From 5dc2690adc444f60462772f33f835bd86748bf31 Mon Sep 17 00:00:00 2001 From: jakubSzuminski Date: Mon, 25 Mar 2024 15:59:39 +0100 Subject: [PATCH 1/7] Fixed #492, the .jpg files will not be properly converted to .jpeg instead of 'png'. --- lib/export.js | 2 +- lib/utils.js | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/export.js b/lib/export.js index b4b6f351..5c09c4c1 100644 --- a/lib/export.js +++ b/lib/export.js @@ -382,7 +382,7 @@ export default async (page, chart, options) => { if (exportOptions.type === 'svg') { // SVG data = await createSVG(page); - } else if (exportOptions.type === 'png' || exportOptions.type === 'jpeg') { + } else if (['png', 'jpeg'].includes(exportOptions.type)) { // PNG or JPEG data = await createImage( page, diff --git a/lib/utils.js b/lib/utils.js index 6250c712..1f3745da 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -102,8 +102,9 @@ export const fixType = (type, outfile) => { if (outfile) { const outType = outfile.split('.').pop(); - // Check if extension has a correct type - if (formats.includes(outType) && type !== outType) { + if (outType === 'jpg') { + type = 'jpeg'; + } else if (formats.includes(outType) && type !== outType) { type = outType; } } From df5e306df67a55266e25e80f29e33991aad4a7e9 Mon Sep 17 00:00:00 2001 From: jakubSzuminski Date: Mon, 25 Mar 2024 16:20:46 +0100 Subject: [PATCH 2/7] Fixed #307, ssl now works, we pass key and cert to the https. --- lib/server/server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/server/server.js b/lib/server/server.js index 11c4e784..ebda9564 100644 --- a/lib/server/server.js +++ b/lib/server/server.js @@ -137,7 +137,7 @@ export const startServer = async (serverConfig) => { if (key && cert) { // Main server instance (HTTPS) - const httpsServer = https.createServer(app); + const httpsServer = https.createServer({ key, cert }, app); // Attach error handlers and listen to the server attachErrorHandlers(httpsServer); From 6add5edb1935e79c2edc445272d53de0328bc4e4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 29 Mar 2024 19:55:39 +0000 Subject: [PATCH 3/7] Bump express from 4.18.3 to 4.19.2 Bumps [express](https://github.com/expressjs/express) from 4.18.3 to 4.19.2. - [Release notes](https://github.com/expressjs/express/releases) - [Changelog](https://github.com/expressjs/express/blob/master/History.md) - [Commits](https://github.com/expressjs/express/compare/4.18.3...4.19.2) --- updated-dependencies: - dependency-name: express dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- package-lock.json | 16 ++++++++-------- package.json | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3aefe2b0..a763ec3f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,7 @@ "colors": "1.4.0", "cors": "^2.8.5", "dotenv": "^16.4.5", - "express": "^4.18.3", + "express": "^4.19.2", "express-rate-limit": "^7.2.0", "https-proxy-agent": "^7.0.4", "multer": "^1.4.5-lts.1", @@ -1366,9 +1366,9 @@ } }, "node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", "engines": { "node": ">= 0.6" } @@ -2101,16 +2101,16 @@ } }, "node_modules/express": { - "version": "4.18.3", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.3.tgz", - "integrity": "sha512-6VyCijWQ+9O7WuVMTRBTl+cjNNIzD5cY5mQ1WM8r/LEkI2u8EYpOotESNwzNlyCn3g+dmjKYI6BmNneSr/FSRw==", + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", "body-parser": "1.20.2", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.5.0", + "cookie": "0.6.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", diff --git a/package.json b/package.json index 7da7a279..85669a32 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "colors": "1.4.0", "cors": "^2.8.5", "dotenv": "^16.4.5", - "express": "^4.18.3", + "express": "^4.19.2", "express-rate-limit": "^7.2.0", "https-proxy-agent": "^7.0.4", "multer": "^1.4.5-lts.1", From d786361a0dd2c0521d9038fb313e4bd1a6893d3f Mon Sep 17 00:00:00 2001 From: jakubSzuminski Date: Tue, 2 Apr 2024 15:24:34 +0200 Subject: [PATCH 4/7] Added mapChart, ganttChart constructors to the exporting UI. --- public/index.html | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/public/index.html b/public/index.html index 480b9eaf..84579894 100644 --- a/public/index.html +++ b/public/index.html @@ -102,11 +102,13 @@

Highcharts Export Server

- Either Chart or StockChart depending on what product you use. + Either a chart, stockChart, mapChart, or a ganttChart (depending on what product you use).
From 0207598479db4e8d7a5814fa5178c61a0f6d3c48 Mon Sep 17 00:00:00 2001 From: PaulDalek Date: Wed, 3 Apr 2024 16:12:18 +0200 Subject: [PATCH 5/7] The package.json scripts, bumped versions and .env load changes. --- .env.sample | 1 + dist/index.cjs | 4 +- dist/index.esm.js | 2 +- dist/index.esm.js.map | 2 +- lib/cache.js | 4 - lib/index.js | 4 + lib/schemas/config.js | 5 - nodemon.json | 7 + package-lock.json | 524 +++++++++++++++++++++++++++++++----------- package.json | 26 ++- 10 files changed, 418 insertions(+), 161 deletions(-) create mode 100644 nodemon.json diff --git a/.env.sample b/.env.sample index 7f6657d2..bcd1dd18 100644 --- a/.env.sample +++ b/.env.sample @@ -8,6 +8,7 @@ HIGHCHARTS_CORE_SCRIPTS = HIGHCHARTS_MODULES = HIGHCHARTS_INDICATORS = HIGHCHARTS_FORCE_FETCH = false +HIGHCHARTS_CACHE_PATH = HIGHCHARTS_ADMIN_TOKEN = # EXPORT CONFIG diff --git a/dist/index.cjs b/dist/index.cjs index e93bdf58..fa0ef02f 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("dotenv"),i=require("https-proxy-agent"),o=require("http"),n=require("https"),s=require("url"),a=require("prompts"),l=require("tarn"),c=require("uuid"),p=require("node:path"),u=require("puppeteer"),h=require("node:crypto"),d=require("cors"),g=require("express"),m=require("multer"),f=require("express-rate-limit"),y="undefined"!=typeof document?document.currentScript:null;function v(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=v(s);async function b(e,t={}){return new Promise(((r,i)=>{const s=(e=>e.startsWith("https")?n:o)(e);s.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)}))}))}r.config();const T={puppeteer:{args:{value:[],type:"string[]",description:"Arguments array to send to Puppeteer."}},highcharts:{version:{value:"latest",envLink:"HIGHCHARTS_VERSION",type:"string",description:"The Highcharts version to be used."},cdnURL:{value:"https://code.highcharts.com/",envLink:"HIGHCHARTS_CDN_URL",type:"string",description:"The CDN URL for Highcharts scripts to be used."},coreScripts:{envLink:"HIGHCHARTS_CORE_SCRIPTS",value:["highcharts","highcharts-more","highcharts-3d"],type:"string[]",description:"The core Highcharts scripts to fetch."},modules:{envLink:"HIGHCHARTS_MODULES",value:["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"],type:"string[]",description:"The modules of Highcharts to fetch."},indicators:{envLink:"HIGHCHARTS_INDICATORS",value:["indicators-all"],type:"string[]",description:"The indicators of Highcharts to fetch."},scripts:{value:["https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js","https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.34/moment-timezone-with-data.min.js"],type:"string[]",description:"Additional optional scripts or dependencies to fetch."},forceFetch:{envLink:"HIGHCHARTS_FORCE_FETCH",value:!1,type:"boolean",description:"The flag to determine whether to refetch all scripts after each server rerun."},cachePath:{envLink:"HIGHCHARTS_CACHE_PATH",value:".cache",type:"string",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:{envLink:"EXPORT_TYPE",value:"png",type:"string",description:"The file export format. It can be jpeg, png, pdf, or svg."},constr:{envLink:"EXPORT_CONSTR",value:"chart",type:"string",description:"The constructor to use. Can be chart, stockChart, mapChart, or ganttChart."},defaultHeight:{envLink:"EXPORT_DEFAULT_HEIGHT",value:400,type:"number",description:"the default height of the exported chart. Used when no value is set."},defaultWidth:{envLink:"EXPORT_DEFAULT_WIDTH",value:600,type:"number",description:"The default width of the exported chart. Used when no value is set."},defaultScale:{envLink:"EXPORT_DEFAULT_SCALE",value:1,type:"number",description:"The default scale of the exported chart. Used when no value is set."},height:{type:"number",value:!1,description:"The height of the exported chart, overriding the option in the chart settings."},width:{type:"number",value:!1,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:{envLink:"EXPORT_RASTERIZATION_TIMEOUT",value:1500,type:"number",description:"The duration in milliseconds to wait for rendering a webpage."}},customLogic:{allowCodeExecution:{envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",value:!1,type:"boolean",description:"Controls whether the execution of arbitrary code is allowed during the exporting process."},allowFileResources:{envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",value:!1,type:"boolean",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:{envLink:"SERVER_ENABLE",value:!1,type:"boolean",cliName:"enableServer",description:"When set to true, the server starts on the local IP address 0.0.0.0."},host:{envLink:"SERVER_HOST",value:"0.0.0.0",type:"string",description:"The hostname of the server. Additionally, it starts a server on the provided hostname."},port:{envLink:"SERVER_PORT",value:7801,type:"number",description:"The server port when enabled."},benchmarking:{envLink:"SERVER_BENCHMARKING",value:!1,type:"boolean",cliName:"serverBenchmarking",description:"Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request."},ssl:{enable:{envLink:"SERVER_SSL_ENABLE",value:!1,type:"boolean",cliName:"enableSsl",description:"Enables or disables the SSL protocol."},force:{envLink:"SERVER_SSL_FORCE",value:!1,type:"boolean",cliName:"sslForced",legacyName:"sslOnly",description:"When set to true, the server is forced to serve only over HTTPS."},port:{envLink:"SERVER_SSL_PORT",value:443,type:"number",cliName:"sslPort",description:"The port on which to run the SSL server."},certPath:{envLink:"SERVER_SSL_CERT_PATH",value:"",type:"string",legacyName:"sslPath",description:"The path to the SSL certificate/key file."}},rateLimiting:{enable:{envLink:"SERVER_RATE_LIMITING_ENABLE",value:!1,type:"boolean",cliName:"enableRateLimiting",description:"Enables rate limiting for the server."},maxRequests:{envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",value:10,type:"number",legacyName:"rateLimit",description:"The maximum number of requests allowed in one minute."},window:{envLink:"SERVER_RATE_LIMITING_WINDOW",value:1,type:"number",description:"The time window, in minutes, for the rate limiting."},delay:{envLink:"SERVER_RATE_LIMITING_DELAY",value:0,type:"number",description:"The delay duration for each successive request before reaching the maximum limit."},trustProxy:{envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",value:!1,type:"boolean",description:"Set this to true if the server is behind a load balancer."},skipKey:{envLink:"SERVER_RATE_LIMITING_SKIP_KEY",value:"",type:"string",description:"Allows bypassing the rate limiter and should be provided with the skipToken argument."},skipToken:{envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",value:"",type:"string",description:"Allows bypassing the rate limiter and should be provided with the skipKey argument."}}},pool:{minWorkers:{envLink:"POOL_MIN_WORKERS",value:4,type:"number",description:"The number of minimum and initial pool workers to spawn."},maxWorkers:{envLink:"POOL_MAX_WORKERS",value:8,type:"number",legacyName:"workers",description:"The number of maximum pool workers to spawn."},workLimit:{envLink:"POOL_WORK_LIMIT",value:40,type:"number",description:"The number of work pieces that can be performed before restarting the worker process."},acquireTimeout:{envLink:"POOL_ACQUIRE_TIMEOUT",value:5e3,type:"number",description:"The duration, in milliseconds, to wait for acquiring a resource."},createTimeout:{envLink:"POOL_CREATE_TIMEOUT",value:5e3,type:"number",description:"The duration, in milliseconds, to wait for creating a resource."},destroyTimeout:{envLink:"POOL_DESTROY_TIMEOUT",value:5e3,type:"number",description:"The duration, in milliseconds, to wait for destroying a resource."},idleTimeout:{envLink:"POOL_IDLE_TIMEOUT",value:3e4,type:"number",description:"The duration, in milliseconds, after which an idle resource is destroyed."},createRetryInterval:{envLink:"POOL_CREATE_RETRY_INTERVAL",value:200,type:"number",description:"The duration, in milliseconds, to wait before retrying the create process in case of a failure."},reaperInterval:{envLink:"POOL_REAPER_INTERVAL",value:1e3,type:"number",description:"The duration, in milliseconds, after which the check for idle resources to destroy is triggered."},benchmarking:{envLink:"POOL_BENCHMARKING",value:!1,type:"boolean",cliName:"poolBenchmarking",description:"Indicate whether to show statistics for the pool of resources or not."},listenToProcessExits:{envLink:"POOL_LISTEN_TO_PROCESS_EXITS",value:!0,type:"boolean",description:"Decides whether or not to attach process.exit handlers."}},logging:{level:{envLink:"LOGGING_LEVEL",value:4,type:"number",cliName:"logLevel",description:"The logging level to be used."},file:{envLink:"LOGGING_FILE",value:"highcharts-export-server.log",type:"string",cliName:"logFile",description:"The name of a log file. The logDest option also needs to be set to enable file logging."},dest:{envLink:"LOGGING_DEST",value:"log/",type:"string",cliName:"logDest",description:"The path to store log files. This also enables file logging."}},ui:{enable:{envLink:"UI_ENABLE",value:!1,type:"boolean",cliName:"enableUi",description:"Enables or disables the user interface (UI) for the export server."},route:{envLink:"UI_ROUTE",value:"/",type:"string",cliName:"uiRoute",description:"The endpoint route to which the user interface (UI) should be attached."}},other:{noLogo:{envLink:"OTHER_NO_LOGO",value:!1,type:"boolean",description:"Skip printing the logo on a startup. Will be replaced by a simple text."}}},x={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:"modules",message:"Available modules",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:T.highcharts.modules.value},{type:"list",name:"scripts",message:"Custom scripts",initial:T.highcharts.scripts.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:"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},{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}],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},{type:"toggle",name:"listenToProcessExits",message:"Set to false to skip attaching process.exit handlers",initial:T.pool.listenToProcessExits.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:"toggle",name:"noLogo",message:"Skip printing the logo on startup. Replaced by simple text",initial:T.other.noLogo.value}]},k=["options","globalOptions","themeOptions","resources","payload"],E={},S=(e,t="")=>{Object.keys(e).forEach((r=>{if(!["puppeteer","highcharts"].includes(r)){const i=e[r];void 0===i.value?S(i,`${t}.${r}`):(E[i.cliName||r]=`${t}.${r}`.substring(1),void 0!==i.legacyName&&(E[i.legacyName]=`${t}.${r}`.substring(1)))}}))};S(T);const L=["red","yellow","blue","gray","green"];let R={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:L[0]},{title:"warning",color:L[1]},{title:"notice",color:L[2]},{title:"verbose",color:L[3]},{title:"benchmark",color:L[4]}],listeners:[]};for(const[e,t]of Object.entries(T.logging))R[e]=t.value;const O=(t,r)=>{R.toFile&&(R.pathCreated||(!e.existsSync(R.dest)&&e.mkdirSync(R.dest),R.pathCreated=!0),e.appendFile(`${R.dest}${R.file}`,[r].concat(t).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),R.toFile=!1)})))},I=(...e)=>{const[t,...r]=e,{level:i,levelsDesc:o}=R;if(5!==t&&(0===t||t>i||i>o.length))return;const n=`${(new Date).toString().split("(")[0].trim()} [${o[t-1].title}] -`;R.listeners.forEach((e=>{e(n,r.join(" "))})),R.toConsole&&console.log.apply(void 0,[n.toString()[R.levelsDesc[t-1].color]].concat(r)),O(r,n)},_=(e,t,r)=>{const i=r||t.message,{level:o,levelsDesc:n}=R;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];R.toConsole&&console.log.apply(void 0,[s.toString()[R.levelsDesc[e-1].color]].concat([i[L[e-1]],"\n",a])),R.listeners.forEach((e=>{e(s,l.join(" "))})),O(l,s)},C=e=>{e>=0&&e<=R.levelsDesc.length&&(R.level=e)},$=(e,t)=>{if(R={...R,dest:e||R.dest,file:t||R.file,toFile:!0},0===R.dest.length)return I(1,"[logger] File logging initialization: no path supplied.");R.dest.endsWith("/")||(R.dest+="/")},P=s.fileURLToPath(new URL("../.","undefined"==typeof document?require("url").pathToFileURL(__filename).href:y&&y.src||new URL("index.cjs",document.baseURI).href)),N=(e,t)=>{const r=["png","jpeg","pdf","svg"];if(t){const i=t.split(".").pop();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"},j=(t=!1,r)=>{const i=["js","css","files"];let o=t,n=!1;if(r&&t.endsWith(".json"))try{o=A(e.readFileSync(t,"utf8"))}catch(e){return _(2,e,"[cli] No resources found.")}else o=A(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):I(3,"[cli] No resources found.")};function A(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 H=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]=H(e[r]));return t},F=(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 U(){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 q=e=>!["false","undefined","null","NaN","0",""].includes(e)&&!!e,W=(t,r)=>{if(t&&"string"==typeof t)return(t=t.trim()).endsWith(".js")?!!r&&W(e.readFileSync(t,"utf8")):t.startsWith("function()")||t.startsWith("function ()")||t.startsWith("()=>")||t.startsWith("() =>")?`(${t})()`:t.replace(/;$/,"")},D=()=>{const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6};class M 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}}r.config();const G={cdnURL:"https://code.highcharts.com/",activeManifest:{},sources:"",hcVersion:""};let V=!1;const J=()=>G.hcVersion=G.sources.substring(0,G.sources.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim(),K=async(e,t,r,i=!1)=>{e.endsWith(".js")&&(e=e.substring(0,e.length-3)),I(4,`[cache] Fetching script - ${e}.js`);const o=t?{agent:t,timeout:+process.env.PROXY_SERVER_TIMEOUT||5e3}:{},n=await b(`${e}.js`,o);if(200===n.statusCode&&"string"==typeof n.text){if(r){r[e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")]=1}return n.text}if(i)throw new M(`Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${n.statusCode}).`).setError(n);return I(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`),""},z=async(t,r)=>{const{coreScripts:o,modules:n,indicators:s,scripts:a}=t,l="latest"!==t.version&&t.version?`${t.version}/`:"";let c;I(3,`[cache] Updating cache version to Highcharts: ${l||"latest"}.`);const p=process.env.PROXY_SERVER_HOST,u=process.env.PROXY_SERVER_PORT;if(p&&u)try{c=new i.HttpsProxyAgent({host:p,port:+u})}catch(e){throw new M("[cache] Could not create a Proxy Agent.").setError(e)}const h={};try{return G.sources=await(async(e,t,r,i,o,n)=>{const s=[...e.map((e=>K(`${i}${e}`,o,n,!0))),...t.map((e=>K(`${i}${e}`,o,n))),...r.map((e=>K(`${e}`,o)))];return(await Promise.all(s)).join(";\n")})([...o.map((e=>`${l}${e}`))],[...n.map((e=>"map"===e?`maps/${l}modules/${e}`:`${l}modules/${e}`)),...s.map((e=>`stock/${l}indicators/${e}`))],a,t.cdnURL||G.cdnURL,c,h),J(),e.writeFileSync(r,G.sources),h}catch(e){throw new M("[cache] Unable to update the local Highcharts cache.").setError(e)}},X=async r=>{const i=t.join(P,r.cachePath);let o;const n=t.join(i,"manifest.json"),s=t.join(i,"sources.js");if(V=r,!e.existsSync(i)&&e.mkdirSync(i),!e.existsSync(n)||r.forceFetch)I(3,"[cache] Fetching and caching Highcharts dependencies."),o=await z(r,s);else{let t=!1;const i=JSON.parse(e.readFileSync(n));if(i.modules&&Array.isArray(i.modules)){const e={};i.modules.forEach((t=>e[t]=1)),i.modules=e}const{modules:a,coreScripts:l,indicators:c}=r,p=a.length+l.length+c.length;i.version!==r.version?(I(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),t=!0):Object.keys(i.modules||{}).length!==p?(I(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),t=!0):t=(r.modules||[]).some((e=>{if(!i.modules[e])return I(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),t?o=await z(r,s):(I(3,"[cache] Dependency cache is up to date, proceeding."),G.sources=e.readFileSync(s,"utf8"),o=i.modules,J())}await(async(r,i)=>{const o={version:r.version,modules:i||{}};G.activeManifest=o,I(3,"[cache] Writing a new manifest.");try{e.writeFileSync(t.join(P,r.cachePath,"manifest.json"),JSON.stringify(o),"utf8")}catch(e){throw new M("[cache] Error writing the cache manifest.").setError(e)}})(r,o)},B=()=>t.join(P,V.cachePath);var Y=async e=>!!V&&await X(Object.assign(V,{version:e})),Q=()=>G,Z=()=>G.hcVersion;let ee={};const te=()=>ee,re=(e,t,r=[])=>{const i=H(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]:re(i[e],n,r);var o;return i};function ie(e,t={},r=""){Object.keys(e).forEach((i=>{const o=e[i],n=t&&t[i];let s;void 0===o.value?ie(o,n,`${r}.${i}`):(void 0!==n&&(o.value=n),o.envLink&&("boolean"===o.type?o.value=q([process.env[o.envLink],o.value].find((e=>e||"false"===e))):"number"===o.type?(s=+process.env[o.envLink],o.value=s>=0?s:o.value):o.type.indexOf("]")>=0&&process.env[o.envLink]?o.value=process.env[o.envLink].split(","):o.value=process.env[o.envLink]||o.value))}))}function oe(e){let t={};for(const[r,i]of Object.entries(e))t[r]=Object.prototype.hasOwnProperty.call(i,"value")?i.value:oe(i);return t}function ne(e,t,r){for(;t.length>1;){const i=t.shift();return Object.prototype.hasOwnProperty.call(e,i)||(e[i]={}),e[i]=ne(Object.assign({},e[i]),t,r),e}return e[t[0]]=r,e}const se=h.randomBytes(64).toString("base64url"),ae=p.join("tmp",`puppeteer-${se}`),le=[`--user-data-dir=${p.join(ae,"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"],ce=w.fileURLToPath(new URL(".","undefined"==typeof document?require("url").pathToFileURL(__filename).href:y&&y.src||new URL("index.cjs",document.baseURI).href)),pe=e.readFileSync(ce+"/../templates/template.html","utf8");let ue;const he=async e=>{await e.setContent(pe),await e.addScriptTag({path:`${B()}/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()}`)}))},de=async(e,t=!1)=>{try{t?(await e.goto("about:blank"),await he(e)):await e.evaluate((()=>{document.body.innerHTML='
'}))}catch(e){_(2,e,"[browser] Could not clear the content of the page.")}},ge=async()=>{if(!ue)return!1;const e=await ue.newPage();return await e.setCacheEnabled(!1),await he(e),e},me=async()=>(ue?.isConnected()&&(await ue.close(),I(4,"[browser] Closed the browser.")),!0);const fe=w.fileURLToPath(new URL(".","undefined"==typeof document?require("url").pathToFileURL(__filename).href:y&&y.src||new URL("index.cjs",document.baseURI).href)),ye=(e,t,r)=>e.evaluate(((e,t)=>window.triggerExport(e,t)),t,r);var ve=async(r,i,o)=>{const n=[],s=async e=>{for(const e of n)await e.dispose();await e.evaluate((()=>{const[,...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...r]=document.getElementsByTagName("link");for(const i of[...e,...t,...r])i.remove()}))};try{I(4,"[export] Determining export path.");const a=o.export;await r.evaluate((()=>requestAnimationFrame((()=>{}))));const l=a?.options?.chart?.displayErrors&&Q().activeManifest.modules.debugger;let c;if(await r.evaluate((e=>window._displayErrors=e),l),i.indexOf&&(i.indexOf("=0||i.indexOf("=0)){if(I(4,"[export] Treating as SVG."),"svg"===a.type)return i;c=!0,await r.setContent((e=>`\n\n\n \n \n Highcarts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`)(i))}else I(4,"[export] Treating as config."),a.strInj?await ye(r,{chart:{height:a.height,width:a.width}},o):(i.chart.height=a.height,i.chart.width=a.width,await ye(r,i,o));const p=o.customLogic.resources;if(p){if(p.js&&n.push(await r.addScriptTag({content:p.js})),p.files)for(const t of p.files)try{const i=!t.startsWith("http");n.push(await r.addScriptTag(i?{content:e.readFileSync(t,"utf8")}:{url:t}))}catch(e){_(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")?n.push(await r.addStyleTag({url:i})):o.customLogic.allowFileResources&&n.push(await r.addStyleTag({path:t.join(fe,i)})));n.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:y,y:v}=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"===a.type||"jpeg"===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 M("Rasterization timeout"))),o||1500)))]))(r,a.type,"base64",{width:d,height:h,x:y,y:v},a.rasterizationTimeout);else{if("pdf"!==a.type)throw new M(`[export] Unsupported output format ${a.type}.`);w=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 s(r),w}catch(e){return await s(r),e}};let we,be=0,Te=0,xe=0,ke=0,Ee=0,Se={},Le=!1;const Re={create:async()=>{let e=!1;const t=c.v4(),r=(new Date).getTime();try{if(e=await ge(),!e||e.isClosed())throw new M("The page is invalid or closed.");I(3,`[pool] Successfully created a worker ${t} - took ${(new Date).getTime()-r} ms.`)}catch(e){throw new M("Error encountered when creating a new page.").setError(e)}return{id:t,page:e,workCount:Math.round(Math.random()*(Se.workLimit/2))}},validate:async e=>Se.workLimit&&++e.workCount>Se.workLimit?(I(3,`[pool] Worker failed validation: exceeded work limit (limit is ${Se.workLimit}).`),!1):(await de(e.page,!0),!0),destroy:e=>{I(3,`[pool] Destroying pool entry ${e.id}.`),e.page&&e.page.close()}},Oe=async e=>{if(Se=e&&e.pool?{...e.pool}:{},Se.listenToProcessExits&&(I(3,"[pool] Attaching exit listeners to the process."),process.on("exit",(async e=>{I(4,`Process exited with code ${e}.`),await Ie()})),process.on("SIGINT",((e,t)=>{I(4,`The ${e} event with code: ${t}.`),process.exit(1)})),process.on("SIGTERM",((e,t)=>{I(4,`The ${e} event with code: ${t}.`),process.exit(1)})),process.on("uncaughtException",(async(e,t)=>{_(1,e,`The ${t} error.`),await Ie(),process.exit(1)}))),we=e.puppeteerArgs,await(async e=>{const t=[...le,...e||[]];if(!ue){let e=0;const r=async()=>{try{I(3,`[browser] Attempting to get a browser instance (try ${++e}).`),ue=await u.launch({headless:"new",args:t,userDataDir:"./tmp/"})}catch(t){if(_(1,t,"[browser] Failed to launch a browser instance."),!(e<25))throw t;I(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 M("[browser] Maximum retries to open a browser instance reached.").setError(e)}if(!ue)throw new M("[browser] Cannot find a browser to open.")}return ue})(we),I(3,`[pool] Initializing pool with workers: min ${Se.minWorkers}, max ${Se.maxWorkers}.`),Le)return I(4,"[pool] Already initialized, please kill it before creating a new one.");parseInt(Se.minWorkers)>parseInt(Se.maxWorkers)&&(Se.minWorkers=Se.maxWorkers);try{Le=new l.Pool({...Re,min:parseInt(Se.minWorkers),max:parseInt(Se.maxWorkers),acquireTimeoutMillis:Se.acquireTimeout,createTimeoutMillis:Se.createTimeout,destroyTimeoutMillis:Se.destroyTimeout,idleTimeoutMillis:Se.idleTimeout,createRetryIntervalMillis:Se.createRetryInterval,reapIntervalMillis:Se.reaperInterval,propagateCreateError:!1}),Le.on("release",(async e=>{await de(e.page,!1),I(4,`[pool] Releasing a worker with ID ${e.id}.`)})),Le.on("destroySuccess",((e,t)=>{I(4,`[pool] Destroyed a worker with ID ${t.id}.`)}));const e=[];for(let t=0;t{Le.release(e)})),I(3,"[pool] The pool is ready"+(e.length?` with ${e.length} initial resources waiting.`:"."))}catch(e){throw await me(),new M("[pool] Could not create the pool of workers.").setError(e)}};async function Ie(){return I(3,"[pool] Killing all pool workers and browser, if any exist."),Le?.destroyed||Le&&(await Le.destroy(),I(4,"[browser] Destroyed the pool of resources.")),me()}const _e=async(e,t)=>{let r;try{if(I(4,"[pool] Work received, starting to process."),++Te,Se.benchmarking&&Ce(),!Le)throw new M("Work received, but pool has not been started.");try{I(4,"[pool] Acquiring a worker handle.");const e=D();r=await Le.acquire().promise,t.server.benchmarking&&I(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Acquired a worker handle: ${e()}ms.`)}catch(e){throw new M("Error encountered when acquiring an available entry.").setError(e)}if(I(4,"[pool] Acquired a worker handle."),!r.page)throw new M("Resolved worker page is invalid: the pool setup is wonky.");let i=(new Date).getTime();I(4,`[pool] Starting work on pool entry with ID ${r.id}.`);const o=D(),n=await ve(r.page,e,t);if(n instanceof Error)throw"Rasterization timeout"===n.message&&(r.page.close(),r.page=await ge()),new M("Error encountered during export.").setError(n);t.server.benchmarking&&I(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Exported a chart sucessfully: ${o()}ms.`),Le.release(r);const s=(new Date).getTime()-i;return xe+=s,Ee=xe/++be,I(4,`[pool] Work completed in ${s} ms.`),{result:n,options:t}}catch(e){throw++ke,r&&Le.release(r),new M(`[pool] In pool.postWork: ${e.message}`).setError(e)}};function Ce(){const{min:e,max:t}=Le;I(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),I(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),I(5,`[pool] The number of resources that are currently available: ${Le.numFree()}.`),I(5,`[pool] The number of resources that are currently acquired: ${Le.numUsed()}.`),I(5,`[pool] The number of callers waiting to acquire a resource: ${Le.numPendingAcquires()}.`)}var $e=()=>({min:Le.min,max:Le.max,available:Le.numFree(),inUse:Le.numUsed(),pendingAcquire:Le.numPendingAcquires()}),Pe=()=>Te,Ne=()=>ke,je=()=>Ee,Ae=()=>be;let He=!1;const Fe=async(t,r)=>{I(4,"[chart] Starting the exporting process.");const i=((e,t={})=>{let r={};return e.svg?(r=H(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=re(t,e,k),r.export.outfile=r.export?.outfile||`chart.${r.export?.type||"png"}`,r})(t,te()),o=i.export;if(i.payload?.svg&&""!==i.payload.svg)try{return I(4,"[chart] Attempting to export from a SVG input."),De(i.payload.svg.trim(),i,r)}catch(e){return r(new M("[chart] Error loading SVG input.").setError(e))}if(o.infile&&o.infile.length)try{return I(4,"[chart] Attempting to export from an input file."),i.export.instr=e.readFileSync(o.infile,"utf8"),De(i.export.instr.trim(),i,r)}catch(e){return r(new M("[chart] Error loading input file.").setError(e))}if(o.instr&&""!==o.instr||o.options&&""!==o.options)try{return I(4,"[chart] Attempting to export from a raw input."),q(i.customLogic?.allowCodeExecution)?We(i,r):"string"==typeof o.instr?De(o.instr.trim(),i,r):qe(i,o.instr||o.options,r)}catch(e){return r(new M("[chart] Error loading raw input.").setError(e))}return r(new M("[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||A(e.export?.instr),i=A(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},qe=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=j(t.customLogic.resources,q(t.customLogic.allowFileResources));else if(!t.customLogic.resources)try{const r=e.readFileSync("resources.json","utf8");t.customLogic.resources=j(r,q(t.customLogic.allowFileResources))}catch(e){_(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 M("[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=N(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]=A(e.readFileSync(n[t],"utf8"),!0):n[t]=A(n[t],!0))}catch(e){n[t]={},_(2,e,`[chart] The '${t}' cannot be loaded.`)}})),s.allowCodeExecution)try{s.customCode=W(s.customCode,s.allowFileResources)}catch(e){_(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,_(2,e,"[chart] The 'callback' cannot be loaded.")}else s.callback=!1;t.export={...t.export,...Ue(t)};try{return i(!1,await _e(n.strInj||r||o,t))}catch(e){return i(e)}},We=(e,t)=>{try{let r,i=e.export.instr||e.export.options;return"string"!=typeof i&&(r=i=F(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 M(`[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))}},De=(e,t,r)=>{const{allowCodeExecution:i}=t.customLogic;if(e.indexOf("=0||e.indexOf("=0)return I(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 q(i)?We(t,r):r(new M("[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=(e,t,r,i)=>{_(1,e),"development"!==process.env.NODE_ENV&&delete e.stack,i(e)},Ge=(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=f({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&&(I(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(o),I(3,`[rate limiting] Enabled rate limiting with ${i.max} requests per ${i.window} minute for each IP, trusting proxy: ${i.trustProxy}.`)};class Je extends M{constructor(e,t){super(e),this.status=this.statusCode=t}setStatus(e){return this.status=e,this}}const Ke={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};let ze=0;const Xe=[],Be=[],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=D(),o=c.v4().replace(/-/g,""),n=te(),s=e.body,a=++ze;let l=N(s.type);if(!s||"object"==typeof(i=s)&&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 p=A(s.infile||s.options||s.data);if(!p&&!s.svg)throw I(2,`The request with ID ${o} from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Payload received: ${JSON.stringify(s)}.`),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=Ye(Xe,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})),I(4,`[export] Got an incoming HTTP request with ID ${o}.`),s.constr="string"==typeof s.constr&&s.constr||"chart";const d={export:{instr:p,type:l,constr:s.constr[0].toLowerCase()+s.constr.substr(1),height:s.height,width:s.width,scale:s.scale||n.export.scale,globalOptions:A(s.globalOptions,!0),themeOptions:A(s.themeOptions,!0)},customLogic:{allowCodeExecution:He,allowFileResources:!1,resources:A(s.resources,!0),callback:s.callback,customCode:s.customCode}};p&&(d.export.instr=F(p,d.customLogic.allowCodeExecution));const g=re(n,d);if(g.export.options=p,g.payload={svg:s.svg||!1,b64:s.b64||!1,noDownload:s.noDownload||!1,requestId:o},s.svg&&(e=>["localhost","(10).(.*).(.*).(.*)","(127).(.*).(.*).(.*)","(172).(1[6-9]|2[0-9]|3[0-1]).(.*).(.*)","(192).(168).(.*).(.*)"].some((t=>e.match(`xlink:href="(?:(http://|https://))?${t}`))))(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"),n.server.benchmarking&&I(5,`[benchmark] Request with ID ${o} - After the whole exporting process: ${r()}ms.`),h)return I(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,Ye(Be,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",Ke[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(P,"package.json"))),et=new Date;const tt=g();tt.disable("x-powered-by"),tt.use(d());const rt=m.memoryStorage(),it=m({storage:rt,limits:{fieldSize:52428800}});tt.use(g.json({limit:52428800})),tt.use(g.urlencoded({extended:!0,limit:52428800})),tt.use(it.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}`)}))}))},nt=async r=>{try{if(!r.enable)return!1;if(!r.ssl.force){const e=o.createServer(tt);ot(e),e.listen(r.port,r.host),I(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){I(2,`[server] Unable to load key/certificate from the '${r.ssl.certPath}' path. Could not run secured layer server.`)}if(i&&o){const e=n.createServer(tt);ot(e),e.listen(r.ssl.port,r.host),I(3,`[server] Started HTTPS server on ${r.host}:${r.ssl.port}.`)}}r.rateLimiting&&r.rateLimiting.enable&&![0,NaN].includes(r.rateLimiting.maxRequests)&&Ve(tt,r.rateLimiting),tt.use(g.static(t.posix.join(P,"public"))),(e=>{!!e&&e.get("/health",((e,t)=>{t.send({status:"OK",bootTime:et,uptime:Math.floor(((new Date).getTime()-et.getTime())/1e3/60)+" minutes",version:Ze.version,highchartsVersion:Z(),averageProcessingTime:je(),performedExports:Ae(),failedExports:Ne(),exportAttempts:Pe(),sucessRatio:Ae()/Pe()*100,pool:$e()})}))})(tt),(e=>{e.post("/",Qe),e.post("/:filename",Qe)})(tt),(e=>{!!e&&e.get("/",((e,r)=>{r.sendFile(t.join(P,"public","index.html"))}))})(tt),(e=>{!!e&&e.post("/version/change/:newVersion",(async(e,t,r)=>{try{const r=process.env.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 Y(o)}catch(e){throw new Je(`Version change: ${e.message}`,e.statusCode).setError(e)}t.status(200).send({statusCode:200,version:Z(),message:`Successfully updated Highcharts to version: ${o}.`})}catch(e){r(e)}}))})(tt),(e=>{e.use(Me),e.use(Ge)})(tt)}catch(e){throw new M("[server] Could not configure and start the server.").setError(e)}};var st={startServer:nt,enableRateLimiting:e=>Ve(tt,e),getExpress:()=>g,getApp:()=>tt,use:(e,...t)=>{tt.use(e,...t)},get:(e,...t)=>{tt.get(e,...t)},post:(e,...t)=>{tt.post(e,...t)}};var at={server:st,startServer:nt,setOptions:(t,r)=>(r?.length&&(ee=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){_(2,e,`[config] Unable to load the configuration from the ${i} file.`)}}return{}}(r)),ie(T,ee),ee=oe(T),t&&(ee=re(ee,t,k)),r?.length&&(ee=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]=q(t[o]):"number"===a?e[r]=+t[o]:a.indexOf("]")>=0?e[r]=t[o].split(","):e[r]=t[o]:(I(2,`[config] Missing value for the '${n}' argument. Using the default value.`),i=!0)),e[r])),e)}i&&U();return e}(ee,r,T)),ee),initExport:async e=>{var t;return t=e.customLogic&&e.customLogic.allowCodeExecution,He=q(t),(e=>{C(e&&parseInt(e.level)),e&&e.dest&&$(e.dest,e.file||"highcharts-export-server.log")})(e.logging),await X(e.highcharts||{version:"latest"}),await Oe({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 Ie()}))},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,Buffer.from(r.result,"base64"))})));try{await Promise.all(r),await Ie()}catch(e){throw new M("[chart] Error encountered during batch export.").setError(e)}},startExport:Fe,killPool:Ie,log:I,logWithStack:_,setLogLevel:C,enableFileLogging:$,mapToNewConfig:e=>{const t={};for(const[r,i]of Object.entries(e)){const e=E[r]?E[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 i=Object.keys(x).map((e=>({title:`${e} options`,value:e})));return a({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,o)=>{let n=0,s=[];for(const e of o)x[e]=x[e].map((t=>({...t,section:e}))),s=[...s,...x[e]];return await a(s,{onSubmit:async(i,o)=>{if("modules"===i.name?(o=o.length?o.map((e=>i.choices[e])):i.choices,r[i.section][i.name]=o):r[i.section]=ne(Object.assign({},r[i.section]||{}),i.name.split("."),i.choices?i.choices[o]:o),++n===s.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 i=JSON.parse(e.readFileSync(t.join(P,"package.json"))).version;r?console.log(`Starting Highcharts Export Server v${i}...`):console.log(e.readFileSync(P+"/msg/startup.msg").toString().bold.yellow,`v${i}`)},printUsage:U};module.exports=at; -//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguY2pzIiwic291cmNlcyI6WyIuLi9saWIvZmV0Y2guanMiLCIuLi9saWIvc2NoZW1hcy9jb25maWcuanMiLCIuLi9saWIvbG9nZ2VyLmpzIiwiLi4vbGliL3V0aWxzLmpzIiwiLi4vbGliL2Vycm9ycy9FeHBvcnRFcnJvci5qcyIsIi4uL2xpYi9jYWNoZS5qcyIsIi4uL2xpYi9jb25maWcuanMiLCIuLi9saWIvYnJvd3Nlci5qcyIsIi4uL2xpYi9leHBvcnQuanMiLCIuLi90ZW1wbGF0ZXMvc3ZnX2V4cG9ydC9zdmdfZXhwb3J0LmpzIiwiLi4vbGliL3Bvb2wuanMiLCIuLi9saWIvY2hhcnQuanMiLCIuLi9saWIvc2VydmVyL2Vycm9yLmpzIiwiLi4vbGliL3NlcnZlci9yYXRlX2xpbWl0LmpzIiwiLi4vbGliL2Vycm9ycy9IdHRwRXJyb3IuanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy9leHBvcnQuanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy9oZWFsdGguanMiLCIuLi9saWIvc2VydmVyL3NlcnZlci5qcyIsIi4uL2xpYi9zZXJ2ZXIvcm91dGVzL3VpLmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvY2hhbmdlX2hjX3ZlcnNpb24uanMiLCIuLi9saWIvaW5kZXguanMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqXHJcbiAqIFRoaXMgbW9kdWxlIGV4cG9ydHMgdHdvIGZ1bmN0aW9uczogZmV0Y2ggKGZvciBHRVQgcmVxdWVzdHMpIGFuZCBwb3N0IChmb3IgUE9TVCByZXF1ZXN0cykuXHJcbiAqL1xyXG5cclxuaW1wb3J0IGh0dHAgZnJvbSAnaHR0cCc7XHJcbmltcG9ydCBodHRwcyBmcm9tICdodHRwcyc7XHJcblxyXG4vKipcclxuICogUmV0dXJucyB0aGUgSFRUUCBvciBIVFRQUyBwcm90b2NvbCBtb2R1bGUgYmFzZWQgb24gdGhlIHByb3ZpZGVkIFVSTC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHVybCAtIFRoZSBVUkwgdG8gZGV0ZXJtaW5lIHRoZSBwcm90b2NvbC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wgbW9kdWxlIChodHRwIG9yIGh0dHBzKS5cclxuICovXHJcbmNvbnN0IGdldFByb3RvY29sID0gKHVybCkgPT4gKHVybC5zdGFydHNXaXRoKCdodHRwcycpID8gaHR0cHMgOiBodHRwKTtcclxuXHJcbi8qKlxyXG4gKiBGZXRjaGVzIGRhdGEgZnJvbSB0aGUgc3BlY2lmaWVkIFVSTCB1c2luZyBlaXRoZXIgSFRUUCBvciBIVFRQUyBwcm90b2NvbC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHVybCAtIFRoZSBVUkwgdG8gZmV0Y2ggZGF0YSBmcm9tLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcmVxdWVzdE9wdGlvbnMgLSBPcHRpb25zIGZvciB0aGUgSFRUUCByZXF1ZXN0IChvcHRpb25hbCkuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBIVFRQIHJlc3BvbnNlIG9iamVjdFxyXG4gKiB3aXRoIGFkZGVkICd0ZXh0JyBwcm9wZXJ0eSBvciByZWplY3Rpbmcgd2l0aCBhbiBlcnJvci5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIGZldGNoKHVybCwgcmVxdWVzdE9wdGlvbnMgPSB7fSkge1xyXG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XHJcbiAgICBjb25zdCBwcm90b2NvbCA9IGdldFByb3RvY29sKHVybCk7XHJcblxyXG4gICAgcHJvdG9jb2xcclxuICAgICAgLmdldCh1cmwsIHJlcXVlc3RPcHRpb25zLCAocmVzKSA9PiB7XHJcbiAgICAgICAgbGV0IGRhdGEgPSAnJztcclxuXHJcbiAgICAgICAgLy8gQSBjaHVuayBvZiBkYXRhIGhhcyBiZWVuIHJlY2VpdmVkLlxyXG4gICAgICAgIHJlcy5vbignZGF0YScsIChjaHVuaykgPT4ge1xyXG4gICAgICAgICAgZGF0YSArPSBjaHVuaztcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgLy8gVGhlIHdob2xlIHJlc3BvbnNlIGhhcyBiZWVuIHJlY2VpdmVkLlxyXG4gICAgICAgIHJlcy5vbignZW5kJywgKCkgPT4ge1xyXG4gICAgICAgICAgaWYgKCFkYXRhKSB7XHJcbiAgICAgICAgICAgIHJlamVjdCgnTm90aGluZyB3YXMgZmV0Y2hlZCBmcm9tIHRoZSBVUkwuJyk7XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgcmVzLnRleHQgPSBkYXRhO1xyXG4gICAgICAgICAgcmVzb2x2ZShyZXMpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICB9KVxyXG4gICAgICAub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICAgICAgcmVqZWN0KGVycm9yKTtcclxuICAgICAgfSk7XHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZW5kcyBhIFBPU1QgcmVxdWVzdCB0byB0aGUgc3BlY2lmaWVkIFVSTCB3aXRoIHRoZSBwcm92aWRlZCBKU09OIGJvZHkgdXNpbmdcclxuICogZWl0aGVyIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgLSBUaGUgVVJMIHRvIHNlbmQgdGhlIFBPU1QgcmVxdWVzdCB0by5cclxuICogQHBhcmFtIHtPYmplY3R9IGJvZHkgLSBUaGUgSlNPTiBib2R5IHRvIGluY2x1ZGUgaW4gdGhlIFBPU1QgcmVxdWVzdFxyXG4gKiAob3B0aW9uYWwsIGRlZmF1bHQgaXMgYW4gZW1wdHkgb2JqZWN0KS5cclxuICogQHBhcmFtIHtPYmplY3R9IHJlcXVlc3RPcHRpb25zIC0gT3B0aW9ucyBmb3IgdGhlIEhUVFAgcmVxdWVzdCAob3B0aW9uYWwpLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgSFRUUCByZXNwb25zZSBvYmplY3Qgd2l0aFxyXG4gKiBhZGRlZCAndGV4dCcgcHJvcGVydHkgb3IgcmVqZWN0aW5nIHdpdGggYW4gZXJyb3IuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBwb3N0KHVybCwgYm9keSA9IHt9LCByZXF1ZXN0T3B0aW9ucyA9IHt9KSB7XHJcbiAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcclxuICAgIGNvbnN0IHByb3RvY29sID0gZ2V0UHJvdG9jb2wodXJsKTtcclxuICAgIGNvbnN0IGRhdGEgPSBKU09OLnN0cmluZ2lmeShib2R5KTtcclxuXHJcbiAgICAvLyBTZXQgZGVmYXVsdCBoZWFkZXJzIGFuZCBtZXJnZSB3aXRoIHJlcXVlc3RPcHRpb25zXHJcbiAgICBjb25zdCBvcHRpb25zID0gT2JqZWN0LmFzc2lnbihcclxuICAgICAge1xyXG4gICAgICAgIG1ldGhvZDogJ1BPU1QnLFxyXG4gICAgICAgIGhlYWRlcnM6IHtcclxuICAgICAgICAgICdDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbicsXHJcbiAgICAgICAgICAnQ29udGVudC1MZW5ndGgnOiBkYXRhLmxlbmd0aFxyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgcmVxdWVzdE9wdGlvbnNcclxuICAgICk7XHJcblxyXG4gICAgY29uc3QgcmVxID0gcHJvdG9jb2xcclxuICAgICAgLnJlcXVlc3QodXJsLCBvcHRpb25zLCAocmVzKSA9PiB7XHJcbiAgICAgICAgbGV0IHJlc3BvbnNlRGF0YSA9ICcnO1xyXG5cclxuICAgICAgICAvLyBBIGNodW5rIG9mIGRhdGEgaGFzIGJlZW4gcmVjZWl2ZWQuXHJcbiAgICAgICAgcmVzLm9uKCdkYXRhJywgKGNodW5rKSA9PiB7XHJcbiAgICAgICAgICByZXNwb25zZURhdGEgKz0gY2h1bms7XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICAgIC8vIFRoZSB3aG9sZSByZXNwb25zZSBoYXMgYmVlbiByZWNlaXZlZC5cclxuICAgICAgICByZXMub24oJ2VuZCcsICgpID0+IHtcclxuICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgIHJlcy50ZXh0ID0gcmVzcG9uc2VEYXRhO1xyXG4gICAgICAgICAgICByZXNvbHZlKHJlcyk7XHJcbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICByZWplY3QoZXJyb3IpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH0pO1xyXG4gICAgICB9KVxyXG4gICAgICAub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICAgICAgcmVqZWN0KGVycm9yKTtcclxuICAgICAgfSk7XHJcblxyXG4gICAgLy8gV3JpdGUgdGhlIHJlcXVlc3QgYm9keSBhbmQgZW5kIHRoZSByZXF1ZXN0LlxyXG4gICAgcmVxLndyaXRlKGRhdGEpO1xyXG4gICAgcmVxLmVuZCgpO1xyXG4gIH0pO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCBmZXRjaDtcclxuZXhwb3J0IHsgZmV0Y2gsIHBvc3QgfTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vLyBMb2FkIC5lbnYgaW50byBlbnZpcm9ubWVudCB2YXJpYWJsZXNcclxuaW1wb3J0IGRvdGVudiBmcm9tICdkb3RlbnYnO1xyXG5cclxuZG90ZW52LmNvbmZpZygpO1xyXG5cclxuLy8gVGhpcyBpcyB0aGUgY29uZmlndXJhdGlvbiBvYmplY3Qgd2l0aCBhbGwgb3B0aW9ucyBhbmQgdGhlaXIgZGVmYXVsdCB2YWx1ZXMsXHJcbi8vIGFsc28gZnJvbSB0aGUgLmVudiBmaWxlIGlmIG9uZSBleGlzdHNcclxuZXhwb3J0IGNvbnN0IGRlZmF1bHRDb25maWcgPSB7XHJcbiAgcHVwcGV0ZWVyOiB7XHJcbiAgICBhcmdzOiB7XHJcbiAgICAgIHZhbHVlOiBbXSxcclxuICAgICAgdHlwZTogJ3N0cmluZ1tdJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdBcmd1bWVudHMgYXJyYXkgdG8gc2VuZCB0byBQdXBwZXRlZXIuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgaGlnaGNoYXJ0czoge1xyXG4gICAgdmVyc2lvbjoge1xyXG4gICAgICB2YWx1ZTogJ2xhdGVzdCcsXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX1ZFUlNJT04nLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgSGlnaGNoYXJ0cyB2ZXJzaW9uIHRvIGJlIHVzZWQuJ1xyXG4gICAgfSxcclxuICAgIGNkblVSTDoge1xyXG4gICAgICB2YWx1ZTogJ2h0dHBzOi8vY29kZS5oaWdoY2hhcnRzLmNvbS8nLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DRE5fVVJMJyxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIENETiBVUkwgZm9yIEhpZ2hjaGFydHMgc2NyaXB0cyB0byBiZSB1c2VkLidcclxuICAgIH0sXHJcbiAgICBjb3JlU2NyaXB0czoge1xyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DT1JFX1NDUklQVFMnLFxyXG4gICAgICB2YWx1ZTogWydoaWdoY2hhcnRzJywgJ2hpZ2hjaGFydHMtbW9yZScsICdoaWdoY2hhcnRzLTNkJ10sXHJcbiAgICAgIHR5cGU6ICdzdHJpbmdbXScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIGNvcmUgSGlnaGNoYXJ0cyBzY3JpcHRzIHRvIGZldGNoLidcclxuICAgIH0sXHJcbiAgICBtb2R1bGVzOiB7XHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX01PRFVMRVMnLFxyXG4gICAgICB2YWx1ZTogW1xyXG4gICAgICAgICdzdG9jaycsXHJcbiAgICAgICAgJ21hcCcsXHJcbiAgICAgICAgJ2dhbnR0JyxcclxuICAgICAgICAnZXhwb3J0aW5nJyxcclxuICAgICAgICAnZXhwb3J0LWRhdGEnLFxyXG4gICAgICAgICdwYXJhbGxlbC1jb29yZGluYXRlcycsXHJcbiAgICAgICAgJ2FjY2Vzc2liaWxpdHknLFxyXG4gICAgICAgICdhbm5vdGF0aW9ucy1hZHZhbmNlZCcsXHJcbiAgICAgICAgJ2Jvb3N0LWNhbnZhcycsXHJcbiAgICAgICAgJ2Jvb3N0JyxcclxuICAgICAgICAnZGF0YScsXHJcbiAgICAgICAgJ2RhdGEtdG9vbHMnLFxyXG4gICAgICAgICdkcmFnZ2FibGUtcG9pbnRzJyxcclxuICAgICAgICAnc3RhdGljLXNjYWxlJyxcclxuICAgICAgICAnYnJva2VuLWF4aXMnLFxyXG4gICAgICAgICdoZWF0bWFwJyxcclxuICAgICAgICAndGlsZW1hcCcsXHJcbiAgICAgICAgJ3RpbGVkd2VibWFwJyxcclxuICAgICAgICAndGltZWxpbmUnLFxyXG4gICAgICAgICd0cmVlbWFwJyxcclxuICAgICAgICAndHJlZWdyYXBoJyxcclxuICAgICAgICAnaXRlbS1zZXJpZXMnLFxyXG4gICAgICAgICdkcmlsbGRvd24nLFxyXG4gICAgICAgICdoaXN0b2dyYW0tYmVsbGN1cnZlJyxcclxuICAgICAgICAnYnVsbGV0JyxcclxuICAgICAgICAnZnVubmVsJyxcclxuICAgICAgICAnZnVubmVsM2QnLFxyXG4gICAgICAgICdnZW9oZWF0bWFwJyxcclxuICAgICAgICAncHlyYW1pZDNkJyxcclxuICAgICAgICAnbmV0d29ya2dyYXBoJyxcclxuICAgICAgICAnb3ZlcmxhcHBpbmctZGF0YWxhYmVscycsXHJcbiAgICAgICAgJ3BhcmV0bycsXHJcbiAgICAgICAgJ3BhdHRlcm4tZmlsbCcsXHJcbiAgICAgICAgJ3BpY3RvcmlhbCcsXHJcbiAgICAgICAgJ3ByaWNlLWluZGljYXRvcicsXHJcbiAgICAgICAgJ3NhbmtleScsXHJcbiAgICAgICAgJ2FyYy1kaWFncmFtJyxcclxuICAgICAgICAnZGVwZW5kZW5jeS13aGVlbCcsXHJcbiAgICAgICAgJ3Nlcmllcy1sYWJlbCcsXHJcbiAgICAgICAgJ3NvbGlkLWdhdWdlJyxcclxuICAgICAgICAnc29uaWZpY2F0aW9uJyxcclxuICAgICAgICAnc3RvY2stdG9vbHMnLFxyXG4gICAgICAgICdzdHJlYW1ncmFwaCcsXHJcbiAgICAgICAgJ3N1bmJ1cnN0JyxcclxuICAgICAgICAndmFyaWFibGUtcGllJyxcclxuICAgICAgICAndmFyaXdpZGUnLFxyXG4gICAgICAgICd2ZWN0b3InLFxyXG4gICAgICAgICd2ZW5uJyxcclxuICAgICAgICAnd2luZGJhcmInLFxyXG4gICAgICAgICd3b3JkY2xvdWQnLFxyXG4gICAgICAgICd4cmFuZ2UnLFxyXG4gICAgICAgICduby1kYXRhLXRvLWRpc3BsYXknLFxyXG4gICAgICAgICdkcmFnLXBhbmVzJyxcclxuICAgICAgICAnZGVidWdnZXInLFxyXG4gICAgICAgICdkdW1iYmVsbCcsXHJcbiAgICAgICAgJ2xvbGxpcG9wJyxcclxuICAgICAgICAnY3lsaW5kZXInLFxyXG4gICAgICAgICdvcmdhbml6YXRpb24nLFxyXG4gICAgICAgICdkb3RwbG90JyxcclxuICAgICAgICAnbWFya2VyLWNsdXN0ZXJzJyxcclxuICAgICAgICAnaG9sbG93Y2FuZGxlc3RpY2snLFxyXG4gICAgICAgICdoZWlraW5hc2hpJyxcclxuICAgICAgICAnZmxvd21hcCdcclxuICAgICAgXSxcclxuICAgICAgdHlwZTogJ3N0cmluZ1tdJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgbW9kdWxlcyBvZiBIaWdoY2hhcnRzIHRvIGZldGNoLidcclxuICAgIH0sXHJcbiAgICBpbmRpY2F0b3JzOiB7XHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0lORElDQVRPUlMnLFxyXG4gICAgICB2YWx1ZTogWydpbmRpY2F0b3JzLWFsbCddLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBpbmRpY2F0b3JzIG9mIEhpZ2hjaGFydHMgdG8gZmV0Y2guJ1xyXG4gICAgfSxcclxuICAgIHNjcmlwdHM6IHtcclxuICAgICAgdmFsdWU6IFtcclxuICAgICAgICAnaHR0cHM6Ly9jZG5qcy5jbG91ZGZsYXJlLmNvbS9hamF4L2xpYnMvbW9tZW50LmpzLzIuMjkuNC9tb21lbnQubWluLmpzJyxcclxuICAgICAgICAnaHR0cHM6Ly9jZG5qcy5jbG91ZGZsYXJlLmNvbS9hamF4L2xpYnMvbW9tZW50LXRpbWV6b25lLzAuNS4zNC9tb21lbnQtdGltZXpvbmUtd2l0aC1kYXRhLm1pbi5qcydcclxuICAgICAgXSxcclxuICAgICAgdHlwZTogJ3N0cmluZ1tdJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdBZGRpdGlvbmFsIG9wdGlvbmFsIHNjcmlwdHMgb3IgZGVwZW5kZW5jaWVzIHRvIGZldGNoLidcclxuICAgIH0sXHJcbiAgICBmb3JjZUZldGNoOiB7XHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0ZPUkNFX0ZFVENIJyxcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZmxhZyB0byBkZXRlcm1pbmUgd2hldGhlciB0byByZWZldGNoIGFsbCBzY3JpcHRzIGFmdGVyIGVhY2ggc2VydmVyIHJlcnVuLidcclxuICAgIH0sXHJcbiAgICBjYWNoZVBhdGg6IHtcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ0FDSEVfUEFUSCcsXHJcbiAgICAgIHZhbHVlOiAnLmNhY2hlJyxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgcGF0aCB0byB0aGUgY2FjaGUgZGlyZWN0b3J5LiBJdCBpcyB1c2VkIHRvIHN0b3JlIHRoZSBIaWdoY2hhcnRzIHNjcmlwdHMgYW5kIGN1c3RvbSBzY3JpcHRzLidcclxuICAgIH1cclxuICB9LFxyXG4gIGV4cG9ydDoge1xyXG4gICAgaW5maWxlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgaW5wdXQgZmlsZSBzaG91bGQgaW5jbHVkZSBhIG5hbWUgYW5kIGEgdHlwZSAoanNvbiBvciBzdmcpLiBJdCBtdXN0IGJlIGNvcnJlY3RseSBmb3JtYXR0ZWQgYXMgYSBKU09OIG9yIFNWRyBmaWxlLidcclxuICAgIH0sXHJcbiAgICBpbnN0cjoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSW5wdXQsIHByb3ZpZGVkIGluIHRoZSBmb3JtIG9mIGEgc3RyaW5naWZpZWQgSlNPTiBvciBTVkcgZmlsZSwgd2lsbCBvdmVycmlkZSB0aGUgLS1pbmZpbGUgb3B0aW9uLidcclxuICAgIH0sXHJcbiAgICBvcHRpb25zOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnQW4gYWxpYXMgZm9yIHRoZSAtLWluc3RyIG9wdGlvbi4nXHJcbiAgICB9LFxyXG4gICAgb3V0ZmlsZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIG91dHB1dCBmaWxlbmFtZSBhbG9uZyB3aXRoIGEgdHlwZSAoanBlZywgcG5nLCBwZGYsIG9yIHN2ZykuIFRoaXMgd2lsbCBpZ25vcmUgdGhlIC0tdHlwZSBmbGFnLidcclxuICAgIH0sXHJcbiAgICB0eXBlOiB7XHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfVFlQRScsXHJcbiAgICAgIHZhbHVlOiAncG5nJyxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIGZpbGUgZXhwb3J0IGZvcm1hdC4gSXQgY2FuIGJlIGpwZWcsIHBuZywgcGRmLCBvciBzdmcuJ1xyXG4gICAgfSxcclxuICAgIGNvbnN0cjoge1xyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0NPTlNUUicsXHJcbiAgICAgIHZhbHVlOiAnY2hhcnQnLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBjb25zdHJ1Y3RvciB0byB1c2UuIENhbiBiZSBjaGFydCwgc3RvY2tDaGFydCwgbWFwQ2hhcnQsIG9yIGdhbnR0Q2hhcnQuJ1xyXG4gICAgfSxcclxuICAgIGRlZmF1bHRIZWlnaHQ6IHtcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9ERUZBVUxUX0hFSUdIVCcsXHJcbiAgICAgIHZhbHVlOiA0MDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAndGhlIGRlZmF1bHQgaGVpZ2h0IG9mIHRoZSBleHBvcnRlZCBjaGFydC4gVXNlZCB3aGVuIG5vIHZhbHVlIGlzIHNldC4nXHJcbiAgICB9LFxyXG4gICAgZGVmYXVsdFdpZHRoOiB7XHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9XSURUSCcsXHJcbiAgICAgIHZhbHVlOiA2MDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGRlZmF1bHQgd2lkdGggb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LiBVc2VkIHdoZW4gbm8gdmFsdWUgaXMgc2V0LidcclxuICAgIH0sXHJcbiAgICBkZWZhdWx0U2NhbGU6IHtcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9ERUZBVUxUX1NDQUxFJyxcclxuICAgICAgdmFsdWU6IDEsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGRlZmF1bHQgc2NhbGUgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LiBVc2VkIHdoZW4gbm8gdmFsdWUgaXMgc2V0LidcclxuICAgIH0sXHJcbiAgICBoZWlnaHQ6IHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBoZWlnaHQgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LCBvdmVycmlkaW5nIHRoZSBvcHRpb24gaW4gdGhlIGNoYXJ0IHNldHRpbmdzLidcclxuICAgIH0sXHJcbiAgICB3aWR0aDoge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIHdpZHRoIG9mIHRoZSBleHBvcnRlZCBjaGFydCwgb3ZlcnJpZGluZyB0aGUgb3B0aW9uIGluIHRoZSBjaGFydCBzZXR0aW5ncy4nXHJcbiAgICB9LFxyXG4gICAgc2NhbGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBzY2FsZSBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQsIG92ZXJyaWRpbmcgdGhlIG9wdGlvbiBpbiB0aGUgY2hhcnQgc2V0dGluZ3MuIFJhbmdlcyBiZXR3ZWVuIDAuMSBhbmQgNS4wLidcclxuICAgIH0sXHJcbiAgICBnbG9iYWxPcHRpb25zOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdFaXRoZXIgYSBzdHJpbmdpZmllZCBKU09OIG9yIGEgZmlsZW5hbWUgY29udGFpbmluZyBvcHRpb25zIHRvIGJlIHBhc3NlZCBpbnRvIHRoZSBIaWdoY2hhcnRzLnNldE9wdGlvbnMuJ1xyXG4gICAgfSxcclxuICAgIHRoZW1lT3B0aW9uczoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnRWl0aGVyIGEgc3RyaW5naWZpZWQgSlNPTiBvciBhIGZpbGVuYW1lIGNvbnRhaW5pbmcgdGhlbWUgb3B0aW9ucyB0byBiZSBwYXNzZWQgaW50byB0aGUgSGlnaGNoYXJ0cy5zZXRPcHRpb25zLidcclxuICAgIH0sXHJcbiAgICBiYXRjaDoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSW5pdGlhdGVzIGEgYmF0Y2ggam9iIHdpdGggYSBzdHJpbmcgY29udGFpbmluZyBpbnB1dC9vdXRwdXQgcGFpcnM6IFwiaW49b3V0O2luPW91dDsuLi5cIi4nXHJcbiAgICB9LFxyXG4gICAgcmFzdGVyaXphdGlvblRpbWVvdXQ6IHtcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9SQVNURVJJWkFUSU9OX1RJTUVPVVQnLFxyXG4gICAgICB2YWx1ZTogMTUwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24gaW4gbWlsbGlzZWNvbmRzIHRvIHdhaXQgZm9yIHJlbmRlcmluZyBhIHdlYnBhZ2UuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgY3VzdG9tTG9naWM6IHtcclxuICAgIGFsbG93Q29kZUV4ZWN1dGlvbjoge1xyXG4gICAgICBlbnZMaW5rOiAnQ1VTVE9NX0xPR0lDX0FMTE9XX0NPREVfRVhFQ1VUSU9OJyxcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdDb250cm9scyB3aGV0aGVyIHRoZSBleGVjdXRpb24gb2YgYXJiaXRyYXJ5IGNvZGUgaXMgYWxsb3dlZCBkdXJpbmcgdGhlIGV4cG9ydGluZyBwcm9jZXNzLidcclxuICAgIH0sXHJcbiAgICBhbGxvd0ZpbGVSZXNvdXJjZXM6IHtcclxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19BTExPV19GSUxFX1JFU09VUkNFUycsXHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQ29udHJvbHMgdGhlIGFiaWxpdHkgdG8gaW5qZWN0IHJlc291cmNlcyBmcm9tIHRoZSBmaWxlc3lzdGVtLiBUaGlzIHNldHRpbmcgaGFzIG5vIGVmZmVjdCB3aGVuIHJ1bm5pbmcgYXMgYSBzZXJ2ZXIuJ1xyXG4gICAgfSxcclxuICAgIGN1c3RvbUNvZGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0N1c3RvbSBjb2RlIHRvIGV4ZWN1dGUgYmVmb3JlIGNoYXJ0IGluaXRpYWxpemF0aW9uLiBJdCBjYW4gYmUgYSBmdW5jdGlvbiwgY29kZSB3cmFwcGVkIHdpdGhpbiBhIGZ1bmN0aW9uLCBvciBhIGZpbGVuYW1lIHdpdGggdGhlIC5qcyBleHRlbnNpb24uJ1xyXG4gICAgfSxcclxuICAgIGNhbGxiYWNrOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdKYXZhU2NyaXB0IGNvZGUgdG8gcnVuIGR1cmluZyBjb25zdHJ1Y3Rpb24uIEl0IGNhbiBiZSBhIGZ1bmN0aW9uIG9yIGEgZmlsZW5hbWUgd2l0aCB0aGUgLmpzIGV4dGVuc2lvbi4nXHJcbiAgICB9LFxyXG4gICAgcmVzb3VyY2VzOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdBZGRpdGlvbmFsIHJlc291cmNlIGluIHRoZSBmb3JtIG9mIGEgc3RyaW5naWZpZWQgSlNPTiwgd2hpY2ggbWF5IGNvbnRhaW4gZmlsZXMsIGpzLCBhbmQgY3NzIHNlY3Rpb25zLidcclxuICAgIH0sXHJcbiAgICBsb2FkQ29uZmlnOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGxlZ2FjeU5hbWU6ICdmcm9tRmlsZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnQSBmaWxlIGNvbnRhaW5pbmcgYSBwcmUtZGVmaW5lZCBjb25maWd1cmF0aW9uIHRvIHVzZS4nXHJcbiAgICB9LFxyXG4gICAgY3JlYXRlQ29uZmlnOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdFbmFibGVzIHNldHRpbmcgb3B0aW9ucyB0aHJvdWdoIGEgcHJvbXB0IGFuZCBzYXZpbmcgdGhlbSBpbiBhIHByb3ZpZGVkIGNvbmZpZyBmaWxlLidcclxuICAgIH1cclxuICB9LFxyXG4gIHNlcnZlcjoge1xyXG4gICAgZW5hYmxlOiB7XHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfRU5BQkxFJyxcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGNsaU5hbWU6ICdlbmFibGVTZXJ2ZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnV2hlbiBzZXQgdG8gdHJ1ZSwgdGhlIHNlcnZlciBzdGFydHMgb24gdGhlIGxvY2FsIElQIGFkZHJlc3MgMC4wLjAuMC4nXHJcbiAgICB9LFxyXG4gICAgaG9zdDoge1xyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX0hPU1QnLFxyXG4gICAgICB2YWx1ZTogJzAuMC4wLjAnLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBob3N0bmFtZSBvZiB0aGUgc2VydmVyLiBBZGRpdGlvbmFsbHksIGl0IHN0YXJ0cyBhIHNlcnZlciBvbiB0aGUgcHJvdmlkZWQgaG9zdG5hbWUuJ1xyXG4gICAgfSxcclxuICAgIHBvcnQ6IHtcclxuICAgICAgZW52TGluazogJ1NFUlZFUl9QT1JUJyxcclxuICAgICAgdmFsdWU6IDc4MDEsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBzZXJ2ZXIgcG9ydCB3aGVuIGVuYWJsZWQuJ1xyXG4gICAgfSxcclxuICAgIGJlbmNobWFya2luZzoge1xyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX0JFTkNITUFSS0lORycsXHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBjbGlOYW1lOiAnc2VydmVyQmVuY2htYXJraW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0luZGljYXRlcyB3aGV0aGVyIHRvIGRpc3BsYXkgdGhlIGR1cmF0aW9uLCBpbiBtaWxsaXNlY29uZHMsIG9mIHNwZWNpZmljIGFjdGlvbnMgdGhhdCBvY2N1ciBvbiB0aGUgc2VydmVyIHdoaWxlIHNlcnZpbmcgYSByZXF1ZXN0LidcclxuICAgIH0sXHJcbiAgICBzc2w6IHtcclxuICAgICAgZW5hYmxlOiB7XHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfRU5BQkxFJyxcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICAgIGNsaU5hbWU6ICdlbmFibGVTc2wnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyBvciBkaXNhYmxlcyB0aGUgU1NMIHByb3RvY29sLidcclxuICAgICAgfSxcclxuICAgICAgZm9yY2U6IHtcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9GT1JDRScsXHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgICBjbGlOYW1lOiAnc3NsRm9yY2VkJyxcclxuICAgICAgICBsZWdhY3lOYW1lOiAnc3NsT25seScsXHJcbiAgICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgICAnV2hlbiBzZXQgdG8gdHJ1ZSwgdGhlIHNlcnZlciBpcyBmb3JjZWQgdG8gc2VydmUgb25seSBvdmVyIEhUVFBTLidcclxuICAgICAgfSxcclxuICAgICAgcG9ydDoge1xyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfU1NMX1BPUlQnLFxyXG4gICAgICAgIHZhbHVlOiA0NDMsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgY2xpTmFtZTogJ3NzbFBvcnQnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHBvcnQgb24gd2hpY2ggdG8gcnVuIHRoZSBTU0wgc2VydmVyLidcclxuICAgICAgfSxcclxuICAgICAgY2VydFBhdGg6IHtcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9DRVJUX1BBVEgnLFxyXG4gICAgICAgIHZhbHVlOiAnJyxcclxuICAgICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgICBsZWdhY3lOYW1lOiAnc3NsUGF0aCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgcGF0aCB0byB0aGUgU1NMIGNlcnRpZmljYXRlL2tleSBmaWxlLidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHJhdGVMaW1pdGluZzoge1xyXG4gICAgICBlbmFibGU6IHtcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfRU5BQkxFJyxcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICAgIGNsaU5hbWU6ICdlbmFibGVSYXRlTGltaXRpbmcnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyByYXRlIGxpbWl0aW5nIGZvciB0aGUgc2VydmVyLidcclxuICAgICAgfSxcclxuICAgICAgbWF4UmVxdWVzdHM6IHtcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfTUFYX1JFUVVFU1RTJyxcclxuICAgICAgICB2YWx1ZTogMTAsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgbGVnYWN5TmFtZTogJ3JhdGVMaW1pdCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgbWF4aW11bSBudW1iZXIgb2YgcmVxdWVzdHMgYWxsb3dlZCBpbiBvbmUgbWludXRlLidcclxuICAgICAgfSxcclxuICAgICAgd2luZG93OiB7XHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1dJTkRPVycsXHJcbiAgICAgICAgdmFsdWU6IDEsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgdGltZSB3aW5kb3csIGluIG1pbnV0ZXMsIGZvciB0aGUgcmF0ZSBsaW1pdGluZy4nXHJcbiAgICAgIH0sXHJcbiAgICAgIGRlbGF5OiB7XHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX0RFTEFZJyxcclxuICAgICAgICB2YWx1ZTogMCxcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAgICdUaGUgZGVsYXkgZHVyYXRpb24gZm9yIGVhY2ggc3VjY2Vzc2l2ZSByZXF1ZXN0IGJlZm9yZSByZWFjaGluZyB0aGUgbWF4aW11bSBsaW1pdC4nXHJcbiAgICAgIH0sXHJcbiAgICAgIHRydXN0UHJveHk6IHtcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfVFJVU1RfUFJPWFknLFxyXG4gICAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdTZXQgdGhpcyB0byB0cnVlIGlmIHRoZSBzZXJ2ZXIgaXMgYmVoaW5kIGEgbG9hZCBiYWxhbmNlci4nXHJcbiAgICAgIH0sXHJcbiAgICAgIHNraXBLZXk6IHtcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9LRVknLFxyXG4gICAgICAgIHZhbHVlOiAnJyxcclxuICAgICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAgICdBbGxvd3MgYnlwYXNzaW5nIHRoZSByYXRlIGxpbWl0ZXIgYW5kIHNob3VsZCBiZSBwcm92aWRlZCB3aXRoIHRoZSBza2lwVG9rZW4gYXJndW1lbnQuJ1xyXG4gICAgICB9LFxyXG4gICAgICBza2lwVG9rZW46IHtcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9UT0tFTicsXHJcbiAgICAgICAgdmFsdWU6ICcnLFxyXG4gICAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICAgJ0FsbG93cyBieXBhc3NpbmcgdGhlIHJhdGUgbGltaXRlciBhbmQgc2hvdWxkIGJlIHByb3ZpZGVkIHdpdGggdGhlIHNraXBLZXkgYXJndW1lbnQuJ1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSxcclxuICBwb29sOiB7XHJcbiAgICBtaW5Xb3JrZXJzOiB7XHJcbiAgICAgIGVudkxpbms6ICdQT09MX01JTl9XT1JLRVJTJyxcclxuICAgICAgdmFsdWU6IDQsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBudW1iZXIgb2YgbWluaW11bSBhbmQgaW5pdGlhbCBwb29sIHdvcmtlcnMgdG8gc3Bhd24uJ1xyXG4gICAgfSxcclxuICAgIG1heFdvcmtlcnM6IHtcclxuICAgICAgZW52TGluazogJ1BPT0xfTUFYX1dPUktFUlMnLFxyXG4gICAgICB2YWx1ZTogOCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGxlZ2FjeU5hbWU6ICd3b3JrZXJzJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgbnVtYmVyIG9mIG1heGltdW0gcG9vbCB3b3JrZXJzIHRvIHNwYXduLidcclxuICAgIH0sXHJcbiAgICB3b3JrTGltaXQ6IHtcclxuICAgICAgZW52TGluazogJ1BPT0xfV09SS19MSU1JVCcsXHJcbiAgICAgIHZhbHVlOiA0MCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgbnVtYmVyIG9mIHdvcmsgcGllY2VzIHRoYXQgY2FuIGJlIHBlcmZvcm1lZCBiZWZvcmUgcmVzdGFydGluZyB0aGUgd29ya2VyIHByb2Nlc3MuJ1xyXG4gICAgfSxcclxuICAgIGFjcXVpcmVUaW1lb3V0OiB7XHJcbiAgICAgIGVudkxpbms6ICdQT09MX0FDUVVJUkVfVElNRU9VVCcsXHJcbiAgICAgIHZhbHVlOiA1MDAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCB0byB3YWl0IGZvciBhY3F1aXJpbmcgYSByZXNvdXJjZS4nXHJcbiAgICB9LFxyXG4gICAgY3JlYXRlVGltZW91dDoge1xyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9DUkVBVEVfVElNRU9VVCcsXHJcbiAgICAgIHZhbHVlOiA1MDAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCB0byB3YWl0IGZvciBjcmVhdGluZyBhIHJlc291cmNlLidcclxuICAgIH0sXHJcbiAgICBkZXN0cm95VGltZW91dDoge1xyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9ERVNUUk9ZX1RJTUVPVVQnLFxyXG4gICAgICB2YWx1ZTogNTAwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgdG8gd2FpdCBmb3IgZGVzdHJveWluZyBhIHJlc291cmNlLidcclxuICAgIH0sXHJcbiAgICBpZGxlVGltZW91dDoge1xyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9JRExFX1RJTUVPVVQnLFxyXG4gICAgICB2YWx1ZTogMzAwMDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGR1cmF0aW9uLCBpbiBtaWxsaXNlY29uZHMsIGFmdGVyIHdoaWNoIGFuIGlkbGUgcmVzb3VyY2UgaXMgZGVzdHJveWVkLidcclxuICAgIH0sXHJcbiAgICBjcmVhdGVSZXRyeUludGVydmFsOiB7XHJcbiAgICAgIGVudkxpbms6ICdQT09MX0NSRUFURV9SRVRSWV9JTlRFUlZBTCcsXHJcbiAgICAgIHZhbHVlOiAyMDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGR1cmF0aW9uLCBpbiBtaWxsaXNlY29uZHMsIHRvIHdhaXQgYmVmb3JlIHJldHJ5aW5nIHRoZSBjcmVhdGUgcHJvY2VzcyBpbiBjYXNlIG9mIGEgZmFpbHVyZS4nXHJcbiAgICB9LFxyXG4gICAgcmVhcGVySW50ZXJ2YWw6IHtcclxuICAgICAgZW52TGluazogJ1BPT0xfUkVBUEVSX0lOVEVSVkFMJyxcclxuICAgICAgdmFsdWU6IDEwMDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGR1cmF0aW9uLCBpbiBtaWxsaXNlY29uZHMsIGFmdGVyIHdoaWNoIHRoZSBjaGVjayBmb3IgaWRsZSByZXNvdXJjZXMgdG8gZGVzdHJveSBpcyB0cmlnZ2VyZWQuJ1xyXG4gICAgfSxcclxuICAgIGJlbmNobWFya2luZzoge1xyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9CRU5DSE1BUktJTkcnLFxyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgY2xpTmFtZTogJ3Bvb2xCZW5jaG1hcmtpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSW5kaWNhdGUgd2hldGhlciB0byBzaG93IHN0YXRpc3RpY3MgZm9yIHRoZSBwb29sIG9mIHJlc291cmNlcyBvciBub3QuJ1xyXG4gICAgfSxcclxuICAgIGxpc3RlblRvUHJvY2Vzc0V4aXRzOiB7XHJcbiAgICAgIGVudkxpbms6ICdQT09MX0xJU1RFTl9UT19QUk9DRVNTX0VYSVRTJyxcclxuICAgICAgdmFsdWU6IHRydWUsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdEZWNpZGVzIHdoZXRoZXIgb3Igbm90IHRvIGF0dGFjaCBwcm9jZXNzLmV4aXQgaGFuZGxlcnMuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgbG9nZ2luZzoge1xyXG4gICAgbGV2ZWw6IHtcclxuICAgICAgZW52TGluazogJ0xPR0dJTkdfTEVWRUwnLFxyXG4gICAgICB2YWx1ZTogNCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGNsaU5hbWU6ICdsb2dMZXZlbCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIGxvZ2dpbmcgbGV2ZWwgdG8gYmUgdXNlZC4nXHJcbiAgICB9LFxyXG4gICAgZmlsZToge1xyXG4gICAgICBlbnZMaW5rOiAnTE9HR0lOR19GSUxFJyxcclxuICAgICAgdmFsdWU6ICdoaWdoY2hhcnRzLWV4cG9ydC1zZXJ2ZXIubG9nJyxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGNsaU5hbWU6ICdsb2dGaWxlJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBuYW1lIG9mIGEgbG9nIGZpbGUuIFRoZSBsb2dEZXN0IG9wdGlvbiBhbHNvIG5lZWRzIHRvIGJlIHNldCB0byBlbmFibGUgZmlsZSBsb2dnaW5nLidcclxuICAgIH0sXHJcbiAgICBkZXN0OiB7XHJcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX0RFU1QnLFxyXG4gICAgICB2YWx1ZTogJ2xvZy8nLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgY2xpTmFtZTogJ2xvZ0Rlc3QnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIHBhdGggdG8gc3RvcmUgbG9nIGZpbGVzLiBUaGlzIGFsc28gZW5hYmxlcyBmaWxlIGxvZ2dpbmcuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgdWk6IHtcclxuICAgIGVuYWJsZToge1xyXG4gICAgICBlbnZMaW5rOiAnVUlfRU5BQkxFJyxcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGNsaU5hbWU6ICdlbmFibGVVaScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdFbmFibGVzIG9yIGRpc2FibGVzIHRoZSB1c2VyIGludGVyZmFjZSAoVUkpIGZvciB0aGUgZXhwb3J0IHNlcnZlci4nXHJcbiAgICB9LFxyXG4gICAgcm91dGU6IHtcclxuICAgICAgZW52TGluazogJ1VJX1JPVVRFJyxcclxuICAgICAgdmFsdWU6ICcvJyxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGNsaU5hbWU6ICd1aVJvdXRlJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBlbmRwb2ludCByb3V0ZSB0byB3aGljaCB0aGUgdXNlciBpbnRlcmZhY2UgKFVJKSBzaG91bGQgYmUgYXR0YWNoZWQuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgb3RoZXI6IHtcclxuICAgIG5vTG9nbzoge1xyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfTk9fTE9HTycsXHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnU2tpcCBwcmludGluZyB0aGUgbG9nbyBvbiBhIHN0YXJ0dXAuIFdpbGwgYmUgcmVwbGFjZWQgYnkgYSBzaW1wbGUgdGV4dC4nXHJcbiAgICB9XHJcbiAgfVxyXG59O1xyXG5cclxuLy8gVGhlIGNvbmZpZyBkZXNjcmlwdGlvbnMgb2JqZWN0IGZvciB0aGUgcHJvbXB0cyBmdW5jdGlvbmFsaXR5LiBJdCBjb250YWluc1xyXG4vLyBpbmZvcm1hdGlvbiBsaWtlOlxyXG4vLyAqIFR5cGUgb2YgYSBwcm9tcHRcclxuLy8gKiBOYW1lIG9mIGFuIG9wdGlvblxyXG4vLyAqIFNob3J0IGRlc2NyaXB0aW9uIG9mIGEgY2hvc2VuIG9wdGlvblxyXG4vLyAqIEluaXRpYWwgdmFsdWVcclxuZXhwb3J0IGNvbnN0IHByb21wdHNDb25maWcgPSB7XHJcbiAgcHVwcGV0ZWVyOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdsaXN0JyxcclxuICAgICAgbmFtZTogJ2FyZ3MnLFxyXG4gICAgICBtZXNzYWdlOiAnUHVwcGV0ZWVyIGFyZ3VtZW50cycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucHVwcGV0ZWVyLmFyZ3MudmFsdWUuam9pbignLCcpLFxyXG4gICAgICBzZXBhcmF0b3I6ICcsJ1xyXG4gICAgfVxyXG4gIF0sXHJcbiAgaGlnaGNoYXJ0czogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICd2ZXJzaW9uJyxcclxuICAgICAgbWVzc2FnZTogJ0hpZ2hjaGFydHMgdmVyc2lvbicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy52ZXJzaW9uLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdjZG5VUkwnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIFVSTCBvZiBDRE4nLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuY2RuVVJMLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbXVsdGlzZWxlY3QnLFxyXG4gICAgICBuYW1lOiAnbW9kdWxlcycsXHJcbiAgICAgIG1lc3NhZ2U6ICdBdmFpbGFibGUgbW9kdWxlcycsXHJcbiAgICAgIGluc3RydWN0aW9uczogJ1NwYWNlOiBTZWxlY3Qgc3BlY2lmaWMsIEE6IFNlbGVjdCBhbGwsIEVudGVyOiBDb25maXJtLicsXHJcbiAgICAgIGNob2ljZXM6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5tb2R1bGVzLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbGlzdCcsXHJcbiAgICAgIG5hbWU6ICdzY3JpcHRzJyxcclxuICAgICAgbWVzc2FnZTogJ0N1c3RvbSBzY3JpcHRzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLnNjcmlwdHMudmFsdWUuam9pbignLCcpLFxyXG4gICAgICBzZXBhcmF0b3I6ICcsJ1xyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdmb3JjZUZldGNoJyxcclxuICAgICAgbWVzc2FnZTogJ0ZvcmNlIHJlLWZldGNoIHRoZSBzY3JpcHRzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLmZvcmNlRmV0Y2gudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ2NhY2hlUGF0aCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcGF0aCB0byB0aGUgY2FjaGUgZGlyZWN0b3J5JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLmNhY2hlUGF0aC52YWx1ZVxyXG4gICAgfVxyXG4gIF0sXHJcbiAgZXhwb3J0OiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdzZWxlY3QnLFxyXG4gICAgICBuYW1lOiAndHlwZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgZGVmYXVsdCBleHBvcnQgZmlsZSB0eXBlJyxcclxuICAgICAgaGludDogYERlZmF1bHQ6ICR7ZGVmYXVsdENvbmZpZy5leHBvcnQudHlwZS52YWx1ZX1gLFxyXG4gICAgICBpbml0aWFsOiAwLFxyXG4gICAgICBjaG9pY2VzOiBbJ3BuZycsICdqcGVnJywgJ3BkZicsICdzdmcnXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3NlbGVjdCcsXHJcbiAgICAgIG5hbWU6ICdjb25zdHInLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgY29uc3RydWN0b3IgZm9yIEhpZ2hjaGFydHMnLFxyXG4gICAgICBoaW50OiBgRGVmYXVsdDogJHtkZWZhdWx0Q29uZmlnLmV4cG9ydC5jb25zdHIudmFsdWV9YCxcclxuICAgICAgaW5pdGlhbDogMCxcclxuICAgICAgY2hvaWNlczogWydjaGFydCcsICdzdG9ja0NoYXJ0JywgJ21hcENoYXJ0JywgJ2dhbnR0Q2hhcnQnXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdkZWZhdWx0SGVpZ2h0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBkZWZhdWx0IGZhbGxiYWNrIGhlaWdodCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmV4cG9ydC5kZWZhdWx0SGVpZ2h0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2RlZmF1bHRXaWR0aCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgZGVmYXVsdCBmYWxsYmFjayB3aWR0aCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmV4cG9ydC5kZWZhdWx0V2lkdGgudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnZGVmYXVsdFNjYWxlJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBkZWZhdWx0IGZhbGxiYWNrIHNjYWxlIG9mIHRoZSBleHBvcnRlZCBjaGFydCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LmRlZmF1bHRTY2FsZS52YWx1ZSxcclxuICAgICAgbWluOiAwLjEsXHJcbiAgICAgIG1heDogNVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdyYXN0ZXJpemF0aW9uVGltZW91dCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcmVuZGVyaW5nIHdlYnBhZ2UgdGltZW91dCBpbiBtaWxsaXNlY29uZHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmV4cG9ydC5yYXN0ZXJpemF0aW9uVGltZW91dC52YWx1ZVxyXG4gICAgfVxyXG4gIF0sXHJcbiAgY3VzdG9tTG9naWM6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdhbGxvd0NvZGVFeGVjdXRpb24nLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIGV4ZWN1dGlvbiBvZiBjdXN0b20gY29kZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuY3VzdG9tTG9naWMuYWxsb3dDb2RlRXhlY3V0aW9uLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2FsbG93RmlsZVJlc291cmNlcycsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgZmlsZSByZXNvdXJjZXMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmN1c3RvbUxvZ2ljLmFsbG93RmlsZVJlc291cmNlcy52YWx1ZVxyXG4gICAgfVxyXG4gIF0sXHJcbiAgc2VydmVyOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnZW5hYmxlJyxcclxuICAgICAgbWVzc2FnZTogJ1N0YXJ0cyB0aGUgc2VydmVyIG9uIDAuMC4wLjAnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5lbmFibGUudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ2hvc3QnLFxyXG4gICAgICBtZXNzYWdlOiAnU2VydmVyIGhvc3RuYW1lJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIuaG9zdC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdwb3J0JyxcclxuICAgICAgbWVzc2FnZTogJ1NlcnZlciBwb3J0JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucG9ydC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdiZW5jaG1hcmtpbmcnLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIHNlcnZlciBiZW5jaG1hcmtpbmcnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5iZW5jaG1hcmtpbmcudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnc3NsLmVuYWJsZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgU1NMIHByb3RvY29sJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIuc3NsLmVuYWJsZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdzc2wuZm9yY2UnLFxyXG4gICAgICBtZXNzYWdlOiAnRm9yY2Ugc2VydmluZyBvbmx5IG92ZXIgSFRUUFMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wuZm9yY2UudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnc3NsLnBvcnQnLFxyXG4gICAgICBtZXNzYWdlOiAnU1NMIHNlcnZlciBwb3J0JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIuc3NsLnBvcnQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ3NzbC5jZXJ0UGF0aCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcGF0aCB0byBmaW5kIHRoZSBTU0wgY2VydGlmaWNhdGUva2V5JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIuc3NsLmNlcnRQYXRoLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5lbmFibGUnLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIHJhdGUgbGltaXRpbmcnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcuZW5hYmxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5tYXhSZXF1ZXN0cycsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbWF4aW11bSByZXF1ZXN0cyBhbGxvd2VkIHBlciBtaW51dGUnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcubWF4UmVxdWVzdHMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLndpbmRvdycsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcmF0ZS1saW1pdGluZyB0aW1lIHdpbmRvdyBpbiBtaW51dGVzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLndpbmRvdy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcuZGVsYXknLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdUaGUgZGVsYXkgZm9yIGVhY2ggc3VjY2Vzc2l2ZSByZXF1ZXN0IGJlZm9yZSByZWFjaGluZyB0aGUgbWF4aW11bScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy5kZWxheS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcudHJ1c3RQcm94eScsXHJcbiAgICAgIG1lc3NhZ2U6ICdTZXQgdG8gdHJ1ZSBpZiBiZWhpbmQgYSBsb2FkIGJhbGFuY2VyJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLnRydXN0UHJveHkudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5za2lwS2V5JyxcclxuICAgICAgbWVzc2FnZTpcclxuICAgICAgICAnQWxsb3dzIGJ5cGFzc2luZyB0aGUgcmF0ZSBsaW1pdGVyIHdoZW4gcHJvdmlkZWQgd2l0aCB0aGUgc2tpcFRva2VuIGFyZ3VtZW50JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLnNraXBLZXkudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5za2lwVG9rZW4nLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdBbGxvd3MgYnlwYXNzaW5nIHRoZSByYXRlIGxpbWl0ZXIgd2hlbiBwcm92aWRlZCB3aXRoIHRoZSBza2lwS2V5IGFyZ3VtZW50JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLnNraXBUb2tlbi52YWx1ZVxyXG4gICAgfVxyXG4gIF0sXHJcbiAgcG9vbDogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ21pbldvcmtlcnMnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIGluaXRpYWwgbnVtYmVyIG9mIHdvcmtlcnMgdG8gc3Bhd24nLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wubWluV29ya2Vycy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdtYXhXb3JrZXJzJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBtYXhpbXVtIG51bWJlciBvZiB3b3JrZXJzIHRvIHNwYXduJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLm1heFdvcmtlcnMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnd29ya0xpbWl0JyxcclxuICAgICAgbWVzc2FnZTpcclxuICAgICAgICAnVGhlIHBpZWNlcyBvZiB3b3JrIHRoYXQgY2FuIGJlIHBlcmZvcm1lZCBiZWZvcmUgcmVzdGFydGluZyBhIFB1cHBldGVlciBwcm9jZXNzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLndvcmtMaW1pdC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdhY3F1aXJlVGltZW91dCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcyB0byB3YWl0IGZvciBhY3F1aXJpbmcgYSByZXNvdXJjZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5hY3F1aXJlVGltZW91dC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdjcmVhdGVUaW1lb3V0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIHRvIHdhaXQgZm9yIGNyZWF0aW5nIGEgcmVzb3VyY2UnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wuY3JlYXRlVGltZW91dC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdkZXN0cm95VGltZW91dCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcyB0byB3YWl0IGZvciBkZXN0cm95aW5nIGEgcmVzb3VyY2UnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wuZGVzdHJveVRpbWVvdXQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnaWRsZVRpbWVvdXQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgYWZ0ZXIgYW4gaWRsZSByZXNvdXJjZSBpcyBkZXN0cm95ZWQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wuaWRsZVRpbWVvdXQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnY3JlYXRlUmV0cnlJbnRlcnZhbCcsXHJcbiAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgJ1RoZSByZXRyeSBpbnRlcnZhbCBpbiBtaWxsaXNlY29uZHMgYWZ0ZXIgYSBjcmVhdGUgcHJvY2VzcyBmYWlscycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5jcmVhdGVSZXRyeUludGVydmFsLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3JlYXBlckludGVydmFsJyxcclxuICAgICAgbWVzc2FnZTpcclxuICAgICAgICAnVGhlIHJlYXBlciBpbnRlcnZhbCBpbiBtaWxsaXNlY29uZHMgYWZ0ZXIgdHJpZ2dlcmluZyB0aGUgY2hlY2sgZm9yIGlkbGUgcmVzb3VyY2VzIHRvIGRlc3Ryb3knLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wucmVhcGVySW50ZXJ2YWwudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnYmVuY2htYXJraW5nJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBiZW5jaG1hcmtpbmcgZm9yIGEgcmVzb3VyY2UgcG9vbCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5iZW5jaG1hcmtpbmcudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnbGlzdGVuVG9Qcm9jZXNzRXhpdHMnLFxyXG4gICAgICBtZXNzYWdlOiAnU2V0IHRvIGZhbHNlIHRvIHNraXAgYXR0YWNoaW5nIHByb2Nlc3MuZXhpdCBoYW5kbGVycycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5saXN0ZW5Ub1Byb2Nlc3NFeGl0cy52YWx1ZVxyXG4gICAgfVxyXG4gIF0sXHJcbiAgbG9nZ2luZzogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2xldmVsJyxcclxuICAgICAgbWVzc2FnZTpcclxuICAgICAgICAnVGhlIGxvZyBsZXZlbCAoMDogc2lsZW50LCAxOiBlcnJvciwgMjogd2FybmluZywgMzogbm90aWNlLCA0OiB2ZXJib3NlLCA1OiBiZW5jaG1hcmspJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5sb2dnaW5nLmxldmVsLnZhbHVlLFxyXG4gICAgICByb3VuZDogMCxcclxuICAgICAgbWluOiAwLFxyXG4gICAgICBtYXg6IDVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ2ZpbGUnLFxyXG4gICAgICBtZXNzYWdlOiAnQSBsb2cgZmlsZSBuYW1lLiBTZXQgd2l0aCB0aGUgLS1sb2dEZXN0IHRvIGVuYWJsZSBmaWxlIGxvZ2dpbmcnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmxvZ2dpbmcuZmlsZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnZGVzdCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcGF0aCB0byBsb2cgZmlsZXMuIEVuYWJsZXMgZmlsZSBsb2dnaW5nJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5sb2dnaW5nLmRlc3QudmFsdWVcclxuICAgIH1cclxuICBdLFxyXG4gIHVpOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnZW5hYmxlJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBVSSBmb3IgdGhlIGV4cG9ydCBzZXJ2ZXInLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnVpLmVuYWJsZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAncm91dGUnLFxyXG4gICAgICBtZXNzYWdlOiAnQSByb3V0ZSB0byBhdHRhY2ggdGhlIFVJJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy51aS5yb3V0ZS52YWx1ZVxyXG4gICAgfVxyXG4gIF0sXHJcbiAgb3RoZXI6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdub0xvZ28nLFxyXG4gICAgICBtZXNzYWdlOiAnU2tpcCBwcmludGluZyB0aGUgbG9nbyBvbiBzdGFydHVwLiBSZXBsYWNlZCBieSBzaW1wbGUgdGV4dCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcub3RoZXIubm9Mb2dvLnZhbHVlXHJcbiAgICB9XHJcbiAgXVxyXG59O1xyXG5cclxuLy8gQWJzb2x1dGUgcHJvcHMgdGhhdCwgaW4gY2FzZSBvZiBtZXJnaW5nIHJlY3Vyc2l2ZWx5LCBuZWVkIHRvIGJlIGZvcmNlIG1lcmdlZFxyXG5leHBvcnQgY29uc3QgYWJzb2x1dGVQcm9wcyA9IFtcclxuICAnb3B0aW9ucycsXHJcbiAgJ2dsb2JhbE9wdGlvbnMnLFxyXG4gICd0aGVtZU9wdGlvbnMnLFxyXG4gICdyZXNvdXJjZXMnLFxyXG4gICdwYXlsb2FkJ1xyXG5dO1xyXG5cclxuLy8gQXJndW1lbnQgbmVzdGluZyBsZXZlbCBvZiBhbGwgZXhwb3J0IHNlcnZlciBvcHRpb25zXHJcbmV4cG9ydCBjb25zdCBuZXN0ZWRBcmdzID0ge307XHJcblxyXG4vKipcclxuICogUmVjdXJzaXZlbHkgY3JlYXRlcyBhIGNoYWluIG9mIG5lc3RlZCBhcmd1bWVudHMgZnJvbSBhbiBvYmplY3QuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvYmogLSBUaGUgb2JqZWN0IGNvbnRhaW5pbmcgbmVzdGVkIGFyZ3VtZW50cy5cclxuICogQHBhcmFtIHtzdHJpbmd9IHByb3BDaGFpbiAtIFRoZSBjdXJyZW50IGNoYWluIG9mIG5lc3RlZCBwcm9wZXJ0aWVzXHJcbiAqICh1c2VkIGludGVybmFsbHkgZHVyaW5nIHJlY3Vyc2lvbikuXHJcbiAqL1xyXG5jb25zdCBjcmVhdGVOZXN0ZWRBcmdzID0gKG9iaiwgcHJvcENoYWluID0gJycpID0+IHtcclxuICBPYmplY3Qua2V5cyhvYmopLmZvckVhY2goKGspID0+IHtcclxuICAgIGlmICghWydwdXBwZXRlZXInLCAnaGlnaGNoYXJ0cyddLmluY2x1ZGVzKGspKSB7XHJcbiAgICAgIGNvbnN0IGVudHJ5ID0gb2JqW2tdO1xyXG4gICAgICBpZiAodHlwZW9mIGVudHJ5LnZhbHVlID09PSAndW5kZWZpbmVkJykge1xyXG4gICAgICAgIC8vIEdvIGRlZXBlciBpbiB0aGUgbmVzdGVkIGFyZ3VtZW50c1xyXG4gICAgICAgIGNyZWF0ZU5lc3RlZEFyZ3MoZW50cnksIGAke3Byb3BDaGFpbn0uJHtrfWApO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIC8vIENyZWF0ZSB0aGUgY2hhaW4gb2YgbmVzdGVkIGFyZ3VtZW50c1xyXG4gICAgICAgIG5lc3RlZEFyZ3NbZW50cnkuY2xpTmFtZSB8fCBrXSA9IGAke3Byb3BDaGFpbn0uJHtrfWAuc3Vic3RyaW5nKDEpO1xyXG5cclxuICAgICAgICAvLyBTdXBwb3J0IGZvciB0aGUgbGVnYWN5LCBQaGFudG9tSlMgcHJvcGVydGllcyBuYW1lc1xyXG4gICAgICAgIGlmIChlbnRyeS5sZWdhY3lOYW1lICE9PSB1bmRlZmluZWQpIHtcclxuICAgICAgICAgIG5lc3RlZEFyZ3NbZW50cnkubGVnYWN5TmFtZV0gPSBgJHtwcm9wQ2hhaW59LiR7a31gLnN1YnN0cmluZygxKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9KTtcclxufTtcclxuXHJcbmNyZWF0ZU5lc3RlZEFyZ3MoZGVmYXVsdENvbmZpZyk7XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgYXBwZW5kRmlsZSwgZXhpc3RzU3luYywgbWtkaXJTeW5jIH0gZnJvbSAnZnMnO1xyXG5cclxuaW1wb3J0IHsgZGVmYXVsdENvbmZpZyB9IGZyb20gJy4vc2NoZW1hcy9jb25maWcuanMnO1xyXG5cclxuLy8gVGhlIGF2YWlsYWJsZSBjb2xvcnNcclxuY29uc3QgY29sb3JzID0gWydyZWQnLCAneWVsbG93JywgJ2JsdWUnLCAnZ3JheScsICdncmVlbiddO1xyXG5cclxuLy8gVGhlIGRlZmF1bHQgbG9nZ2luZyBjb25maWdcclxubGV0IGxvZ2dpbmcgPSB7XHJcbiAgLy8gRmxhZ3MgZm9yIGxvZ2dpbmcgc3RhdHVzXHJcbiAgdG9Db25zb2xlOiB0cnVlLFxyXG4gIHRvRmlsZTogZmFsc2UsXHJcbiAgcGF0aENyZWF0ZWQ6IGZhbHNlLFxyXG4gIC8vIExvZyBsZXZlbHNcclxuICBsZXZlbHNEZXNjOiBbXHJcbiAgICB7XHJcbiAgICAgIHRpdGxlOiAnZXJyb3InLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzBdXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ3dhcm5pbmcnLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzFdXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ25vdGljZScsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbMl1cclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHRpdGxlOiAndmVyYm9zZScsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbM11cclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHRpdGxlOiAnYmVuY2htYXJrJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1s0XVxyXG4gICAgfVxyXG4gIF0sXHJcbiAgLy8gTG9nIGxpc3RlbmVyc1xyXG4gIGxpc3RlbmVyczogW11cclxufTtcclxuXHJcbi8vIEdhdGhlciBpbml0IGxvZ2dpbmcgb3B0aW9uc1xyXG5mb3IgKGNvbnN0IFtrZXksIG9wdGlvbl0gb2YgT2JqZWN0LmVudHJpZXMoZGVmYXVsdENvbmZpZy5sb2dnaW5nKSkge1xyXG4gIGxvZ2dpbmdba2V5XSA9IG9wdGlvbi52YWx1ZTtcclxufVxyXG5cclxuLyoqXHJcbiAqIExvZ3MgdGhlIHByb3ZpZGVkIHRleHRzIHRvIGEgZmlsZSwgaWYgZmlsZSBsb2dnaW5nIGlzIGVuYWJsZWQuIEl0IGNyZWF0ZXNcclxuICogdGhlIG5lY2Vzc2FyeSBkaXJlY3Rvcnkgc3RydWN0dXJlIGlmIG5vdCBhbHJlYWR5IGNyZWF0ZWQgYW5kIGFwcGVuZHMgdGhlXHJcbiAqIGNvbnRlbnQsIGluY2x1ZGluZyBhbiBvcHRpb25hbCBwcmVmaXgsIHRvIHRoZSBzcGVjaWZpZWQgbG9nIGZpbGUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nW119IHRleHRzIC0gQW4gYXJyYXkgb2YgdGV4dHMgdG8gYmUgbG9nZ2VkLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcHJlZml4IC0gQW4gb3B0aW9uYWwgcHJlZml4IHRvIGJlIGFkZGVkIHRvIGVhY2ggbG9nIGVudHJ5LlxyXG4gKi9cclxuY29uc3QgbG9nVG9GaWxlID0gKHRleHRzLCBwcmVmaXgpID0+IHtcclxuICBpZiAobG9nZ2luZy50b0ZpbGUpIHtcclxuICAgIGlmICghbG9nZ2luZy5wYXRoQ3JlYXRlZCkge1xyXG4gICAgICAvLyBDcmVhdGUgaWYgZG9lcyBub3QgZXhpc3RcclxuICAgICAgIWV4aXN0c1N5bmMobG9nZ2luZy5kZXN0KSAmJiBta2RpclN5bmMobG9nZ2luZy5kZXN0KTtcclxuXHJcbiAgICAgIC8vIFdlIG5vdyBhc3N1bWUgdGhlIHBhdGggaXMgYXZhaWxhYmxlLCBlLmcuIGl0J3MgdGhlIHJlc3BvbnNpYmlsaXR5XHJcbiAgICAgIC8vIG9mIHRoZSB1c2VyIHRvIGNyZWF0ZSB0aGUgcGF0aCB3aXRoIHRoZSBjb3JyZWN0IGFjY2VzcyByaWdodHMuXHJcbiAgICAgIGxvZ2dpbmcucGF0aENyZWF0ZWQgPSB0cnVlO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEFkZCB0aGUgY29udGVudCB0byBhIGZpbGVcclxuICAgIGFwcGVuZEZpbGUoXHJcbiAgICAgIGAke2xvZ2dpbmcuZGVzdH0ke2xvZ2dpbmcuZmlsZX1gLFxyXG4gICAgICBbcHJlZml4XS5jb25jYXQodGV4dHMpLmpvaW4oJyAnKSArICdcXG4nLFxyXG4gICAgICAoZXJyb3IpID0+IHtcclxuICAgICAgICBpZiAoZXJyb3IpIHtcclxuICAgICAgICAgIGNvbnNvbGUubG9nKGBbbG9nZ2VyXSBVbmFibGUgdG8gd3JpdGUgdG8gbG9nIGZpbGU6ICR7ZXJyb3J9YCk7XHJcbiAgICAgICAgICBsb2dnaW5nLnRvRmlsZSA9IGZhbHNlO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogTG9ncyBhIG1lc3NhZ2UuIEFjY2VwdHMgYSB2YXJpYWJsZSBhbW91bnQgb2YgYXJndW1lbnRzLiBBcmd1bWVudHMgYWZ0ZXJcclxuICogYGxldmVsYCB3aWxsIGJlIHBhc3NlZCBkaXJlY3RseSB0byBjb25zb2xlLmxvZywgYW5kL29yIHdpbGwgYmUgam9pbmVkXHJcbiAqIGFuZCBhcHBlbmRlZCB0byB0aGUgbG9nIGZpbGUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7YW55fSBhcmdzIC0gQW4gYXJyYXkgb2YgYXJndW1lbnRzIHdoZXJlIHRoZSBmaXJzdCBpcyB0aGUgbG9nIGxldmVsXHJcbiAqIGFuZCB0aGUgcmVzdCBhcmUgc3RyaW5ncyB0byBidWlsZCBhIG1lc3NhZ2Ugd2l0aC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBsb2cgPSAoLi4uYXJncykgPT4ge1xyXG4gIGNvbnN0IFtuZXdMZXZlbCwgLi4udGV4dHNdID0gYXJncztcclxuXHJcbiAgLy8gQ3VycmVudCBsb2dnaW5nIG9wdGlvbnNcclxuICBjb25zdCB7IGxldmVsLCBsZXZlbHNEZXNjIH0gPSBsb2dnaW5nO1xyXG5cclxuICAvLyBDaGVjayBpZiBsb2cgbGV2ZWwgaXMgd2l0aGluIGEgY29ycmVjdCByYW5nZSBvciBpcyBhIGJlbmNobWFyayBsb2dcclxuICBpZiAoXHJcbiAgICBuZXdMZXZlbCAhPT0gNSAmJlxyXG4gICAgKG5ld0xldmVsID09PSAwIHx8IG5ld0xldmVsID4gbGV2ZWwgfHwgbGV2ZWwgPiBsZXZlbHNEZXNjLmxlbmd0aClcclxuICApIHtcclxuICAgIHJldHVybjtcclxuICB9XHJcblxyXG4gIC8vIEdldCByaWQgb2YgdGhlIEdNVCB0ZXh0IGluZm9ybWF0aW9uXHJcbiAgY29uc3QgbmV3RGF0ZSA9IG5ldyBEYXRlKCkudG9TdHJpbmcoKS5zcGxpdCgnKCcpWzBdLnRyaW0oKTtcclxuXHJcbiAgLy8gQ3JlYXRlIGEgbWVzc2FnZSdzIHByZWZpeFxyXG4gIGNvbnN0IHByZWZpeCA9IGAke25ld0RhdGV9IFske2xldmVsc0Rlc2NbbmV3TGV2ZWwgLSAxXS50aXRsZX1dIC1gO1xyXG5cclxuICAvLyBDYWxsIGF2YWlsYWJsZSBsb2cgbGlzdGVuZXJzXHJcbiAgbG9nZ2luZy5saXN0ZW5lcnMuZm9yRWFjaCgoZm4pID0+IHtcclxuICAgIGZuKHByZWZpeCwgdGV4dHMuam9pbignICcpKTtcclxuICB9KTtcclxuXHJcbiAgLy8gTG9nIHRvIGNvbnNvbGVcclxuICBpZiAobG9nZ2luZy50b0NvbnNvbGUpIHtcclxuICAgIGNvbnNvbGUubG9nLmFwcGx5KFxyXG4gICAgICB1bmRlZmluZWQsXHJcbiAgICAgIFtwcmVmaXgudG9TdHJpbmcoKVtsb2dnaW5nLmxldmVsc0Rlc2NbbmV3TGV2ZWwgLSAxXS5jb2xvcl1dLmNvbmNhdCh0ZXh0cylcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICAvLyBMb2cgdG8gZmlsZVxyXG4gIGxvZ1RvRmlsZSh0ZXh0cywgcHJlZml4KTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBMb2dzIGFuIGVycm9yIG1lc3NhZ2Ugd2l0aCBpdHMgc3RhY2sgdHJhY2UuIE9wdGlvbmFsbHksIGEgY3VzdG9tIG1lc3NhZ2VcclxuICogY2FuIGJlIHByb3ZpZGVkLlxyXG4gKlxyXG4gKiBAcGFyYW0ge251bWJlcn0gbGV2ZWwgLSBUaGUgbG9nIGxldmVsLlxyXG4gKiBAcGFyYW0ge0Vycm9yfSBlcnJvciAtIFRoZSBlcnJvciBvYmplY3QuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBjdXN0b21NZXNzYWdlIC0gQW4gb3B0aW9uYWwgY3VzdG9tIG1lc3NhZ2UgdG8gYmUgbG9nZ2VkIGFsb25nXHJcbiAqIHdpdGggdGhlIGVycm9yLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGxvZ1dpdGhTdGFjayA9IChuZXdMZXZlbCwgZXJyb3IsIGN1c3RvbU1lc3NhZ2UpID0+IHtcclxuICAvLyBHZXQgdGhlIG1haW4gbWVzc2FnZVxyXG4gIGNvbnN0IG1haW5NZXNzYWdlID0gY3VzdG9tTWVzc2FnZSB8fCBlcnJvci5tZXNzYWdlO1xyXG5cclxuICAvLyBDdXJyZW50IGxvZ2dpbmcgb3B0aW9uc1xyXG4gIGNvbnN0IHsgbGV2ZWwsIGxldmVsc0Rlc2MgfSA9IGxvZ2dpbmc7XHJcblxyXG4gIC8vIENoZWNrIGlmIGxvZyBsZXZlbCBpcyB3aXRoaW4gYSBjb3JyZWN0IHJhbmdlXHJcbiAgaWYgKG5ld0xldmVsID09PSAwIHx8IG5ld0xldmVsID4gbGV2ZWwgfHwgbGV2ZWwgPiBsZXZlbHNEZXNjLmxlbmd0aCkge1xyXG4gICAgcmV0dXJuO1xyXG4gIH1cclxuXHJcbiAgLy8gR2V0IHJpZCBvZiB0aGUgR01UIHRleHQgaW5mb3JtYXRpb25cclxuICBjb25zdCBuZXdEYXRlID0gbmV3IERhdGUoKS50b1N0cmluZygpLnNwbGl0KCcoJylbMF0udHJpbSgpO1xyXG5cclxuICAvLyBDcmVhdGUgYSBtZXNzYWdlJ3MgcHJlZml4XHJcbiAgY29uc3QgcHJlZml4ID0gYCR7bmV3RGF0ZX0gWyR7bGV2ZWxzRGVzY1tuZXdMZXZlbCAtIDFdLnRpdGxlfV0gLWA7XHJcblxyXG4gIC8vIElmIHRoZSBjdXN0b21NZXNzYWdlIGV4aXN0cywgd2Ugd2FudCB0byBkaXNwbGF5IHRoZSB3aG9sZSBzdGFjayBtZXNzYWdlXHJcbiAgY29uc3Qgc3RhY2tNZXNzYWdlID1cclxuICAgIGVycm9yLm1lc3NhZ2UgIT09IGVycm9yLnN0YWNrTWVzc2FnZSB8fCBlcnJvci5zdGFja01lc3NhZ2UgPT09IHVuZGVmaW5lZFxyXG4gICAgICA/IGVycm9yLnN0YWNrXHJcbiAgICAgIDogZXJyb3Iuc3RhY2suc3BsaXQoJ1xcbicpLnNsaWNlKDEpLmpvaW4oJ1xcbicpO1xyXG5cclxuICAvLyBDb21iaW5lIGN1c3RvbSBtZXNzYWdlIG9yIGVycm9yIG1lc3NhZ2Ugd2l0aCBlcnJvciBzdGFjayBtZXNzYWdlXHJcbiAgY29uc3QgdGV4dHMgPSBbbWFpbk1lc3NhZ2UsICdcXG4nLCBzdGFja01lc3NhZ2VdO1xyXG5cclxuICAvLyBMb2cgdG8gY29uc29sZVxyXG4gIGlmIChsb2dnaW5nLnRvQ29uc29sZSkge1xyXG4gICAgY29uc29sZS5sb2cuYXBwbHkoXHJcbiAgICAgIHVuZGVmaW5lZCxcclxuICAgICAgW3ByZWZpeC50b1N0cmluZygpW2xvZ2dpbmcubGV2ZWxzRGVzY1tuZXdMZXZlbCAtIDFdLmNvbG9yXV0uY29uY2F0KFtcclxuICAgICAgICBtYWluTWVzc2FnZVtjb2xvcnNbbmV3TGV2ZWwgLSAxXV0sXHJcbiAgICAgICAgJ1xcbicsXHJcbiAgICAgICAgc3RhY2tNZXNzYWdlXHJcbiAgICAgIF0pXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgLy8gQ2FsbCBhdmFpbGFibGUgbG9nIGxpc3RlbmVyc1xyXG4gIGxvZ2dpbmcubGlzdGVuZXJzLmZvckVhY2goKGZuKSA9PiB7XHJcbiAgICBmbihwcmVmaXgsIHRleHRzLmpvaW4oJyAnKSk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIExvZyB0byBmaWxlXHJcbiAgbG9nVG9GaWxlKHRleHRzLCBwcmVmaXgpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIGxvZyBsZXZlbCB0byB0aGUgc3BlY2lmaWVkIHZhbHVlLiBMb2cgbGV2ZWxzIGFyZSAoMCA9IG5vIGxvZ2dpbmcsXHJcbiAqIDEgPSBlcnJvciwgMiA9IHdhcm5pbmcsIDMgPSBub3RpY2UsIDQgPSB2ZXJib3NlIG9yIDUgPSBiZW5jaG1hcmspXHJcbiAqXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBuZXdMZXZlbCAtIFRoZSBuZXcgbG9nIGxldmVsIHRvIGJlIHNldC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBzZXRMb2dMZXZlbCA9IChuZXdMZXZlbCkgPT4ge1xyXG4gIGlmIChuZXdMZXZlbCA+PSAwICYmIG5ld0xldmVsIDw9IGxvZ2dpbmcubGV2ZWxzRGVzYy5sZW5ndGgpIHtcclxuICAgIGxvZ2dpbmcubGV2ZWwgPSBuZXdMZXZlbDtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogRW5hYmxlcyBmaWxlIGxvZ2dpbmcgd2l0aCB0aGUgc3BlY2lmaWVkIGRlc3RpbmF0aW9uIGFuZCBsb2cgZmlsZS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGxvZ0Rlc3QgLSBUaGUgZGVzdGluYXRpb24gcGF0aCBmb3IgbG9nIGZpbGVzLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gbG9nRmlsZSAtIFRoZSBsb2cgZmlsZSBuYW1lLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGVuYWJsZUZpbGVMb2dnaW5nID0gKGxvZ0Rlc3QsIGxvZ0ZpbGUpID0+IHtcclxuICAvLyBVcGRhdGUgbG9nZ2luZyBvcHRpb25zXHJcbiAgbG9nZ2luZyA9IHtcclxuICAgIC4uLmxvZ2dpbmcsXHJcbiAgICBkZXN0OiBsb2dEZXN0IHx8IGxvZ2dpbmcuZGVzdCxcclxuICAgIGZpbGU6IGxvZ0ZpbGUgfHwgbG9nZ2luZy5maWxlLFxyXG4gICAgdG9GaWxlOiB0cnVlXHJcbiAgfTtcclxuXHJcbiAgaWYgKGxvZ2dpbmcuZGVzdC5sZW5ndGggPT09IDApIHtcclxuICAgIHJldHVybiBsb2coMSwgJ1tsb2dnZXJdIEZpbGUgbG9nZ2luZyBpbml0aWFsaXphdGlvbjogbm8gcGF0aCBzdXBwbGllZC4nKTtcclxuICB9XHJcblxyXG4gIGlmICghbG9nZ2luZy5kZXN0LmVuZHNXaXRoKCcvJykpIHtcclxuICAgIGxvZ2dpbmcuZGVzdCArPSAnLyc7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIGxvZ2dpbmcgd2l0aCB0aGUgc3BlY2lmaWVkIGxvZ2dpbmcgY29uZmlndXJhdGlvbi5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGxvZ2dpbmcgLSBUaGUgbG9nZ2luZyBjb25maWd1cmF0aW9uIG9iamVjdC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBpbml0TG9nZ2luZyA9IChsb2dnaW5nKSA9PiB7XHJcbiAgLy8gU2V0IHRoZSBsb2cgbGV2ZWxcclxuICBzZXRMb2dMZXZlbChsb2dnaW5nICYmIHBhcnNlSW50KGxvZ2dpbmcubGV2ZWwpKTtcclxuXHJcbiAgLy8gU2V0IHRoZSBsb2cgZmlsZSBwYXRoIGFuZCBuYW1lXHJcbiAgaWYgKGxvZ2dpbmcgJiYgbG9nZ2luZy5kZXN0KSB7XHJcbiAgICBlbmFibGVGaWxlTG9nZ2luZyhcclxuICAgICAgbG9nZ2luZy5kZXN0LFxyXG4gICAgICBsb2dnaW5nLmZpbGUgfHwgJ2hpZ2hjaGFydHMtZXhwb3J0LXNlcnZlci5sb2cnXHJcbiAgICApO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBBZGRzIGEgbGlzdGVuZXIgZnVuY3Rpb24gdG8gdGhlIGxvZ2dpbmcgc3lzdGVtLlxyXG4gKlxyXG4gKiBAcGFyYW0ge2Z1bmN0aW9ufSBmbiAtIFRoZSBsaXN0ZW5lciBmdW5jdGlvbiB0byBiZSBhZGRlZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBsaXN0ZW4gPSAoZm4pID0+IHtcclxuICBsb2dnaW5nLmxpc3RlbmVycy5wdXNoKGZuKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBUb2dnbGVzIHRoZSBzdGFuZGFyZCBvdXRwdXQgKGNvbnNvbGUpIGxvZ2dpbmcuXHJcbiAqXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gZW5hYmxlZCAtIElmIHRydWUsIGVuYWJsZXMgY29uc29sZSBsb2dnaW5nOyBpZiBmYWxzZSxcclxuICogZGlzYWJsZXMgaXQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgdG9nZ2xlU1RET3V0ID0gKGVuYWJsZWQpID0+IHtcclxuICBsb2dnaW5nLnRvQ29uc29sZSA9IGVuYWJsZWQ7XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgbG9nLFxyXG4gIGxvZ1dpdGhTdGFjayxcclxuICBzZXRMb2dMZXZlbCxcclxuICBlbmFibGVGaWxlTG9nZ2luZyxcclxuICBpbml0TG9nZ2luZyxcclxuICBsaXN0ZW4sXHJcbiAgdG9nZ2xlU1RET3V0XHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XHJcbmltcG9ydCB7IGZpbGVVUkxUb1BhdGggfSBmcm9tICd1cmwnO1xyXG5cclxuaW1wb3J0IHsgZGVmYXVsdENvbmZpZyB9IGZyb20gJy4uL2xpYi9zY2hlbWFzL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5cclxuY29uc3QgTUFYX0JBQ0tPRkZfQVRURU1QVFMgPSA2O1xyXG5cclxuZXhwb3J0IGNvbnN0IF9fZGlybmFtZSA9IGZpbGVVUkxUb1BhdGgobmV3IFVSTCgnLi4vLicsIGltcG9ydC5tZXRhLnVybCkpO1xyXG5cclxuLyoqXHJcbiAqIENsZWFycyBhbmQgc3RhbmRhcmRpemVzIHRleHQgYnkgcmVwbGFjaW5nIG11bHRpcGxlIGNvbnNlY3V0aXZlIHdoaXRlc3BhY2VcclxuICogY2hhcmFjdGVycyB3aXRoIGEgc2luZ2xlIHNwYWNlIGFuZCB0cmltbWluZyBhbnkgbGVhZGluZyBvciB0cmFpbGluZ1xyXG4gKiB3aGl0ZXNwYWNlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdGV4dCAtIFRoZSBpbnB1dCB0ZXh0IHRvIGJlIGNsZWFyZWQuXHJcbiAqIEBwYXJhbSB7UmVnRXhwfSBbcnVsZT0vXFxzXFxzKy9nXSAtIFRoZSByZWd1bGFyIGV4cHJlc3Npb24gcnVsZSB0byBtYXRjaFxyXG4gKiBtdWx0aXBsZSBjb25zZWN1dGl2ZSB3aGl0ZXNwYWNlIGNoYXJhY3RlcnMuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBbcmVwbGFjZXI9JyAnXSAtIFRoZSBzdHJpbmcgdXNlZCB0byByZXBsYWNlIG11bHRpcGxlXHJcbiAqIGNvbnNlY3V0aXZlIHdoaXRlc3BhY2UgY2hhcmFjdGVycy5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gLSBUaGUgY2xlYXJlZCBhbmQgc3RhbmRhcmRpemVkIHRleHQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgY2xlYXJUZXh0ID0gKHRleHQsIHJ1bGUgPSAvXFxzXFxzKy9nLCByZXBsYWNlciA9ICcgJykgPT5cclxuICB0ZXh0LnJlcGxhY2VBbGwocnVsZSwgcmVwbGFjZXIpLnRyaW0oKTtcclxuXHJcbi8qKlxyXG4gKiBJbXBsZW1lbnRzIGFuIGV4cG9uZW50aWFsIGJhY2tvZmYgc3RyYXRlZ3kgZm9yIHJldHJ5aW5nIGEgZnVuY3Rpb24gdW50aWxcclxuICogYSBjZXJ0YWluIG51bWJlciBvZiBhdHRlbXB0cyBhcmUgcmVhY2hlZC5cclxuICpcclxuICogQHBhcmFtIHtGdW5jdGlvbn0gZm4gLSBUaGUgZnVuY3Rpb24gdG8gYmUgcmV0cmllZC5cclxuICogQHBhcmFtIHtudW1iZXJ9IFthdHRlbXB0PTBdIC0gVGhlIGN1cnJlbnQgYXR0ZW1wdCBudW1iZXIuXHJcbiAqIEBwYXJhbSB7Li4uYW55fSBhcmdzIC0gQXJndW1lbnRzIHRvIGJlIHBhc3NlZCB0byB0aGUgZnVuY3Rpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlfSAtIEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSByZXN1bHQgb2YgdGhlIGZ1bmN0aW9uXHJcbiAqIGlmIHN1Y2Nlc3NmdWwuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0Vycm9yfSAtIFRocm93cyBhbiBlcnJvciBpZiB0aGUgbWF4aW11bSBudW1iZXIgb2YgYXR0ZW1wdHNcclxuICogaXMgcmVhY2hlZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBleHBCYWNrb2ZmID0gYXN5bmMgKGZuLCBhdHRlbXB0ID0gMCwgLi4uYXJncykgPT4ge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBUcnkgdG8gY2FsbCB0aGUgZnVuY3Rpb25cclxuICAgIHJldHVybiBhd2FpdCBmbiguLi5hcmdzKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgLy8gQ2FsY3VsYXRlIGRlbGF5IGluIG1zXHJcbiAgICBjb25zdCBkZWxheUluTXMgPSAyICoqIGF0dGVtcHQgKiAxMDAwO1xyXG5cclxuICAgIC8vIElmIHRoZSBhdHRlbXB0IGV4Y2VlZHMgdGhlIG1heGltdW0gYXR0ZW1wdHMgb2YgcmVhcGVhdCwgdGhyb3cgYW4gZXJyb3JcclxuICAgIGlmICgrK2F0dGVtcHQgPj0gTUFYX0JBQ0tPRkZfQVRURU1QVFMpIHtcclxuICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gV2FpdCBnaXZlbiBhbW91bnQgb2YgdGltZVxyXG4gICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc3BvbnNlKSA9PiBzZXRUaW1lb3V0KHJlc3BvbnNlLCBkZWxheUluTXMpKTtcclxuICAgIGxvZyhcclxuICAgICAgMyxcclxuICAgICAgYFtwb29sXSBXYWl0ZWQgJHtkZWxheUluTXN9bXMgdW50aWwgbmV4dCBjYWxsIGZvciB0aGUgcmVzb3VyY2UgaWQ6ICR7YXJnc1swXX0uYFxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBUcnkgYWdhaW5cclxuICAgIHJldHVybiBleHBCYWNrb2ZmKGZuLCBhdHRlbXB0LCAuLi5hcmdzKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogRml4ZXMgdGhlIGV4cG9ydCB0eXBlIGJhc2VkIG9uIE1JTUUgdHlwZXMgYW5kIGZpbGUgZXh0ZW5zaW9ucy5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHR5cGUgLSBUaGUgb3JpZ2luYWwgZXhwb3J0IHR5cGUuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBvdXRmaWxlIC0gVGhlIGZpbGUgcGF0aCBvciBuYW1lLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSAtIFRoZSBjb3JyZWN0ZWQgZXhwb3J0IHR5cGUuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZml4VHlwZSA9ICh0eXBlLCBvdXRmaWxlKSA9PiB7XHJcbiAgLy8gTUlNRSB0eXBlc1xyXG4gIGNvbnN0IG1pbWVUeXBlcyA9IHtcclxuICAgICdpbWFnZS9wbmcnOiAncG5nJyxcclxuICAgICdpbWFnZS9qcGVnJzogJ2pwZWcnLFxyXG4gICAgJ2FwcGxpY2F0aW9uL3BkZic6ICdwZGYnLFxyXG4gICAgJ2ltYWdlL3N2Zyt4bWwnOiAnc3ZnJ1xyXG4gIH07XHJcblxyXG4gIC8vIEZvcm1hdHNcclxuICBjb25zdCBmb3JtYXRzID0gWydwbmcnLCAnanBlZycsICdwZGYnLCAnc3ZnJ107XHJcblxyXG4gIC8vIENoZWNrIGlmIHR5cGUgYW5kIG91dGZpbGUncyBleHRlbnNpb25zIGFyZSB0aGUgc2FtZVxyXG4gIGlmIChvdXRmaWxlKSB7XHJcbiAgICBjb25zdCBvdXRUeXBlID0gb3V0ZmlsZS5zcGxpdCgnLicpLnBvcCgpO1xyXG5cclxuICAgIC8vIENoZWNrIGlmIGV4dGVuc2lvbiBoYXMgYSBjb3JyZWN0IHR5cGVcclxuICAgIGlmIChmb3JtYXRzLmluY2x1ZGVzKG91dFR5cGUpICYmIHR5cGUgIT09IG91dFR5cGUpIHtcclxuICAgICAgdHlwZSA9IG91dFR5cGU7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gYSBjb3JyZWN0IHR5cGVcclxuICByZXR1cm4gbWltZVR5cGVzW3R5cGVdIHx8IGZvcm1hdHMuZmluZCgodCkgPT4gdCA9PT0gdHlwZSkgfHwgJ3BuZyc7XHJcbn07XHJcblxyXG4vKipcclxuICogSGFuZGxlcyBhbmQgdmFsaWRhdGVzIHJlc291cmNlcyBmb3IgZXhwb3J0LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdHxzdHJpbmd9IHJlc291cmNlcyAtIFRoZSByZXNvdXJjZXMgdG8gYmUgaGFuZGxlZC4gQ2FuIGJlIGVpdGhlclxyXG4gKiBhIEpTT04gb2JqZWN0LCBzdHJpbmdpZmllZCBKU09OIG9yIGEgcGF0aCB0byBhIEpTT04gZmlsZS5cclxuICogQHBhcmFtIHtib29sZWFufSBhbGxvd0ZpbGVSZXNvdXJjZXMgLSBXaGV0aGVyIHRvIGFsbG93IGxvYWRpbmcgcmVzb3VyY2VzIGZyb21cclxuICogZmlsZXMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R8dW5kZWZpbmVkfSAtIFRoZSBoYW5kbGVkIHJlc291cmNlcyBvciB1bmRlZmluZWQgaWYgbm8gdmFsaWRcclxuICogcmVzb3VyY2VzIGFyZSBmb3VuZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBoYW5kbGVSZXNvdXJjZXMgPSAocmVzb3VyY2VzID0gZmFsc2UsIGFsbG93RmlsZVJlc291cmNlcykgPT4ge1xyXG4gIGNvbnN0IGFsbG93ZWRQcm9wcyA9IFsnanMnLCAnY3NzJywgJ2ZpbGVzJ107XHJcblxyXG4gIGxldCBoYW5kbGVkUmVzb3VyY2VzID0gcmVzb3VyY2VzO1xyXG4gIGxldCBjb3JyZWN0UmVzb3VyY2VzID0gZmFsc2U7XHJcblxyXG4gIC8vIFRyeSB0byBsb2FkIHJlc291cmNlcyBmcm9tIGEgZmlsZVxyXG4gIGlmIChhbGxvd0ZpbGVSZXNvdXJjZXMgJiYgcmVzb3VyY2VzLmVuZHNXaXRoKCcuanNvbicpKSB7XHJcbiAgICB0cnkge1xyXG4gICAgICBoYW5kbGVkUmVzb3VyY2VzID0gaXNDb3JyZWN0SlNPTihyZWFkRmlsZVN5bmMocmVzb3VyY2VzLCAndXRmOCcpKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHJldHVybiBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbY2xpXSBObyByZXNvdXJjZXMgZm91bmQuYCk7XHJcbiAgICB9XHJcbiAgfSBlbHNlIHtcclxuICAgIC8vIFRyeSB0byBnZXQgSlNPTlxyXG4gICAgaGFuZGxlZFJlc291cmNlcyA9IGlzQ29ycmVjdEpTT04ocmVzb3VyY2VzKTtcclxuXHJcbiAgICAvLyBHZXQgcmlkIG9mIHRoZSBmaWxlcyBzZWN0aW9uXHJcbiAgICBpZiAoaGFuZGxlZFJlc291cmNlcyAmJiAhYWxsb3dGaWxlUmVzb3VyY2VzKSB7XHJcbiAgICAgIGRlbGV0ZSBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gRmlsdGVyIGZyb20gdW5uZWNlc3NhcnkgcHJvcGVydGllc1xyXG4gIGZvciAoY29uc3QgcHJvcE5hbWUgaW4gaGFuZGxlZFJlc291cmNlcykge1xyXG4gICAgaWYgKCFhbGxvd2VkUHJvcHMuaW5jbHVkZXMocHJvcE5hbWUpKSB7XHJcbiAgICAgIGRlbGV0ZSBoYW5kbGVkUmVzb3VyY2VzW3Byb3BOYW1lXTtcclxuICAgIH0gZWxzZSBpZiAoIWNvcnJlY3RSZXNvdXJjZXMpIHtcclxuICAgICAgY29ycmVjdFJlc291cmNlcyA9IHRydWU7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBDaGVjayBpZiBhdCBsZWFzdCBvbmUgb2YgYWxsb3dlZCBwcm9wZXJ0aWVzIGlzIHByZXNlbnRcclxuICBpZiAoIWNvcnJlY3RSZXNvdXJjZXMpIHtcclxuICAgIHJldHVybiBsb2coMywgYFtjbGldIE5vIHJlc291cmNlcyBmb3VuZC5gKTtcclxuICB9XHJcblxyXG4gIC8vIEhhbmRsZSBmaWxlcyBzZWN0aW9uXHJcbiAgaWYgKGhhbmRsZWRSZXNvdXJjZXMuZmlsZXMpIHtcclxuICAgIGhhbmRsZWRSZXNvdXJjZXMuZmlsZXMgPSBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzLm1hcCgoaXRlbSkgPT4gaXRlbS50cmltKCkpO1xyXG4gICAgaWYgKCFoYW5kbGVkUmVzb3VyY2VzLmZpbGVzIHx8IGhhbmRsZWRSZXNvdXJjZXMuZmlsZXMubGVuZ3RoIDw9IDApIHtcclxuICAgICAgZGVsZXRlIGhhbmRsZWRSZXNvdXJjZXMuZmlsZXM7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gcmVzb3VyY2VzXHJcbiAgcmV0dXJuIGhhbmRsZWRSZXNvdXJjZXM7XHJcbn07XHJcblxyXG4vKipcclxuICogVmFsaWRhdGVzIGFuZCBwYXJzZXMgSlNPTiBkYXRhLiBDaGVja3MgaWYgcHJvdmlkZWQgZGF0YSBpcyBvciBjYW5cclxuICogYmUgYSBjb3JyZWN0IEpTT04uXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fHN0cmluZ30gZGF0YSAtIFRoZSBKU09OIGRhdGEgdG8gYmUgdmFsaWRhdGVkIGFuZCBwYXJzZWQuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gdG9TdHJpbmcgLSBXaGV0aGVyIHRvIHJldHVybiBhIHN0cmluZ2lmaWVkIHJlcHJlc2VudGF0aW9uXHJcbiAqIG9mIHRoZSBwYXJzZWQgSlNPTi5cclxuICpcclxuICogQHJldHVybnMge09iamVjdHxzdHJpbmd8Ym9vbGVhbn0gLSBUaGUgcGFyc2VkIEpTT04gb2JqZWN0LCBzdHJpbmdpZmllZCBKU09OLFxyXG4gKiBvciBmYWxzZSBpZiB2YWxpZGF0aW9uIGZhaWxzLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGlzQ29ycmVjdEpTT04oZGF0YSwgdG9TdHJpbmcpIHtcclxuICB0cnkge1xyXG4gICAgLy8gR2V0IHRoZSBzdHJpbmcgcmVwcmVzZW50YXRpb24gaWYgbm90IGFscmVhZHkgYmVmb3JlIHBhcnNpbmdcclxuICAgIGNvbnN0IHBhcnNlZERhdGEgPSBKU09OLnBhcnNlKFxyXG4gICAgICB0eXBlb2YgZGF0YSAhPT0gJ3N0cmluZycgPyBKU09OLnN0cmluZ2lmeShkYXRhKSA6IGRhdGFcclxuICAgICk7XHJcblxyXG4gICAgLy8gUmV0dXJuIGEgc3RyaW5naWZpZWQgcmVwcmVzZW50YXRpb24gb2YgYSBKU09OIGlmIHJlcXVpcmVkXHJcbiAgICBpZiAodHlwZW9mIHBhcnNlZERhdGEgIT09ICdzdHJpbmcnICYmIHRvU3RyaW5nKSB7XHJcbiAgICAgIHJldHVybiBKU09OLnN0cmluZ2lmeShwYXJzZWREYXRhKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBSZXR1cm4gYSBKU09OXHJcbiAgICByZXR1cm4gcGFyc2VkRGF0YTtcclxuICB9IGNhdGNoIHtcclxuICAgIHJldHVybiBmYWxzZTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDaGVja3MgaWYgdGhlIGdpdmVuIGl0ZW0gaXMgYW4gb2JqZWN0LlxyXG4gKlxyXG4gKiBAcGFyYW0ge2FueX0gaXRlbSAtIFRoZSBpdGVtIHRvIGJlIGNoZWNrZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtib29sZWFufSAtIFRydWUgaWYgdGhlIGl0ZW0gaXMgYW4gb2JqZWN0LCBmYWxzZSBvdGhlcndpc2UuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaXNPYmplY3QgPSAoaXRlbSkgPT5cclxuICB0eXBlb2YgaXRlbSA9PT0gJ29iamVjdCcgJiYgIUFycmF5LmlzQXJyYXkoaXRlbSkgJiYgaXRlbSAhPT0gbnVsbDtcclxuXHJcbi8qKlxyXG4gKiBDaGVja3MgaWYgdGhlIGdpdmVuIG9iamVjdCBpcyBlbXB0eS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGl0ZW0gLSBUaGUgb2JqZWN0IHRvIGJlIGNoZWNrZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtib29sZWFufSAtIFRydWUgaWYgdGhlIG9iamVjdCBpcyBlbXB0eSwgZmFsc2Ugb3RoZXJ3aXNlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGlzT2JqZWN0RW1wdHkgPSAoaXRlbSkgPT5cclxuICB0eXBlb2YgaXRlbSA9PT0gJ29iamVjdCcgJiYgaXRlbSAhPT0gbnVsbCAmJiBPYmplY3Qua2V5cyhpdGVtKS5sZW5ndGggPT09IDA7XHJcblxyXG4vKipcclxuICogQ2hlY2tzIGlmIGEgcHJpdmF0ZSBJUCByYW5nZSBVUkwgaXMgZm91bmQgaW4gdGhlIGdpdmVuIHN0cmluZy5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGl0ZW0gLSBUaGUgc3RyaW5nIHRvIGJlIGNoZWNrZWQgZm9yIGEgcHJpdmF0ZSBJUCByYW5nZSBVUkwuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtib29sZWFufSAtIFRydWUgaWYgYSBwcml2YXRlIElQIHJhbmdlIFVSTCBpcyBmb3VuZCwgZmFsc2VcclxuICogb3RoZXJ3aXNlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGlzUHJpdmF0ZVJhbmdlVXJsRm91bmQgPSAoaXRlbSkgPT4ge1xyXG4gIHJldHVybiBbXHJcbiAgICAnbG9jYWxob3N0JyxcclxuICAgICcoMTApLiguKikuKC4qKS4oLiopJyxcclxuICAgICcoMTI3KS4oLiopLiguKikuKC4qKScsXHJcbiAgICAnKDE3MikuKDFbNi05XXwyWzAtOV18M1swLTFdKS4oLiopLiguKiknLFxyXG4gICAgJygxOTIpLigxNjgpLiguKikuKC4qKSdcclxuICBdLnNvbWUoKGlwUmVnRXgpID0+XHJcbiAgICBpdGVtLm1hdGNoKGB4bGluazpocmVmPVwiKD86KGh0dHA6Ly98aHR0cHM6Ly8pKT8ke2lwUmVnRXh9YClcclxuICApO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYSBkZWVwIGNvcHkgb2YgdGhlIGdpdmVuIG9iamVjdCBvciBhcnJheS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R8QXJyYXl9IG9iaiAtIFRoZSBvYmplY3Qgb3IgYXJyYXkgdG8gYmUgZGVlcGx5IGNvcGllZC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdHxBcnJheX0gLSBUaGUgZGVlcCBjb3B5IG9mIHRoZSBwcm92aWRlZCBvYmplY3Qgb3IgYXJyYXkuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZGVlcENvcHkgPSAob2JqKSA9PiB7XHJcbiAgaWYgKG9iaiA9PT0gbnVsbCB8fCB0eXBlb2Ygb2JqICE9PSAnb2JqZWN0Jykge1xyXG4gICAgcmV0dXJuIG9iajtcclxuICB9XHJcblxyXG4gIGNvbnN0IGNvcHkgPSBBcnJheS5pc0FycmF5KG9iaikgPyBbXSA6IHt9O1xyXG5cclxuICBmb3IgKGNvbnN0IGtleSBpbiBvYmopIHtcclxuICAgIGlmIChPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob2JqLCBrZXkpKSB7XHJcbiAgICAgIGNvcHlba2V5XSA9IGRlZXBDb3B5KG9ialtrZXldKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHJldHVybiBjb3B5O1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIENvbnZlcnRzIHRoZSBwcm92aWRlZCBvcHRpb25zIG9iamVjdCB0byBhIEpTT04tZm9ybWF0dGVkIHN0cmluZyB3aXRoIHRoZVxyXG4gKiBvcHRpb24gdG8gcHJlc2VydmUgZnVuY3Rpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBvcHRpb25zIG9iamVjdCB0byBiZSBjb252ZXJ0ZWQgdG8gYSBzdHJpbmcuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gYWxsb3dGdW5jdGlvbnMgLSBJZiBzZXQgdG8gdHJ1ZSwgZnVuY3Rpb25zIGFyZSBwcmVzZXJ2ZWRcclxuICogaW4gdGhlIG91dHB1dC5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gLSBUaGUgSlNPTi1mb3JtYXR0ZWQgc3RyaW5nIHJlcHJlc2VudGluZyB0aGUgb3B0aW9ucy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBvcHRpb25zU3RyaW5naWZ5ID0gKG9wdGlvbnMsIGFsbG93RnVuY3Rpb25zKSA9PiB7XHJcbiAgY29uc3QgcmVwbGFjZXJDYWxsYmFjayA9IChuYW1lLCB2YWx1ZSkgPT4ge1xyXG4gICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycpIHtcclxuICAgICAgdmFsdWUgPSB2YWx1ZS50cmltKCk7XHJcblxyXG4gICAgICAvLyBJZiBhbGxvd0Z1bmN0aW9ucyBpcyBzZXQgdG8gdHJ1ZSwgcHJlc2VydmUgZnVuY3Rpb25zXHJcbiAgICAgIGlmIChcclxuICAgICAgICAodmFsdWUuc3RhcnRzV2l0aCgnZnVuY3Rpb24oJykgfHwgdmFsdWUuc3RhcnRzV2l0aCgnZnVuY3Rpb24gKCcpKSAmJlxyXG4gICAgICAgIHZhbHVlLmVuZHNXaXRoKCd9JylcclxuICAgICAgKSB7XHJcbiAgICAgICAgdmFsdWUgPSBhbGxvd0Z1bmN0aW9uc1xyXG4gICAgICAgICAgPyBgRVhQX0ZVTiR7KHZhbHVlICsgJycpLnJlcGxhY2VBbGwoL1xcbnxcXHR8XFxyL2csICcgJyl9RVhQX0ZVTmBcclxuICAgICAgICAgIDogdW5kZWZpbmVkO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIHR5cGVvZiB2YWx1ZSA9PT0gJ2Z1bmN0aW9uJ1xyXG4gICAgICA/IGBFWFBfRlVOJHsodmFsdWUgKyAnJykucmVwbGFjZUFsbCgvXFxufFxcdHxcXHIvZywgJyAnKX1FWFBfRlVOYFxyXG4gICAgICA6IHZhbHVlO1xyXG4gIH07XHJcblxyXG4gIC8vIFN0cmluZ2lmeSBvcHRpb25zIGFuZCBpZiByZXF1aXJlZCwgcmVwbGFjZSBzcGVjaWFsIGZ1bmN0aW9ucyBtYXJrc1xyXG4gIHJldHVybiBKU09OLnN0cmluZ2lmeShvcHRpb25zLCByZXBsYWNlckNhbGxiYWNrKS5yZXBsYWNlQWxsKFxyXG4gICAgL1wiRVhQX0ZVTnxFWFBfRlVOXCIvZyxcclxuICAgICcnXHJcbiAgKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBQcmludHMgdGhlIEhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlciBsb2dvIGFuZCB2ZXJzaW9uIGluZm9ybWF0aW9uLlxyXG4gKlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IG5vTG9nbyAtIElmIHRydWUsIG9ubHkgcHJpbnRzIHZlcnNpb24gaW5mb3JtYXRpb24gd2l0aG91dFxyXG4gKiB0aGUgbG9nby5cclxuICovXHJcbmV4cG9ydCBjb25zdCBwcmludExvZ28gPSAobm9Mb2dvKSA9PiB7XHJcbiAgLy8gR2V0IHBhY2thZ2UgdmVyc2lvbiBlaXRoZXIgZnJvbSBlbnYgb3IgZnJvbSBwYWNrYWdlLmpzb25cclxuICBjb25zdCBwYWNrYWdlVmVyc2lvbiA9IEpTT04ucGFyc2UoXHJcbiAgICByZWFkRmlsZVN5bmMoam9pbihfX2Rpcm5hbWUsICdwYWNrYWdlLmpzb24nKSlcclxuICApLnZlcnNpb247XHJcblxyXG4gIC8vIFByaW50IHRleHQgb25seVxyXG4gIGlmIChub0xvZ28pIHtcclxuICAgIGNvbnNvbGUubG9nKGBTdGFydGluZyBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIgdiR7cGFja2FnZVZlcnNpb259Li4uYCk7XHJcbiAgICByZXR1cm47XHJcbiAgfVxyXG5cclxuICAvLyBQcmludCB0aGUgbG9nb1xyXG4gIGNvbnNvbGUubG9nKFxyXG4gICAgcmVhZEZpbGVTeW5jKF9fZGlybmFtZSArICcvbXNnL3N0YXJ0dXAubXNnJykudG9TdHJpbmcoKS5ib2xkLnllbGxvdyxcclxuICAgIGB2JHtwYWNrYWdlVmVyc2lvbn1gXHJcbiAgKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBQcmludHMgdGhlIHVzYWdlIGluZm9ybWF0aW9uIGZvciBDTEkgYXJndW1lbnRzLiBJZiByZXF1aXJlZCwgaXQgY2FuIGxpc3RcclxuICogcHJvcGVydGllcyByZWN1cnNpdmVseVxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHByaW50VXNhZ2UoKSB7XHJcbiAgY29uc3QgcGFkID0gNDg7XHJcbiAgY29uc3QgcmVhZG1lID0gJ2h0dHBzOi8vZ2l0aHViLmNvbS9oaWdoY2hhcnRzL25vZGUtZXhwb3J0LXNlcnZlciNyZWFkbWUnO1xyXG5cclxuICAvLyBEaXNwbGF5IHJlYWRtZSBpbmZvcm1hdGlvblxyXG4gIGNvbnNvbGUubG9nKFxyXG4gICAgJ1xcblVzYWdlIG9mIENMSSBhcmd1bWVudHM6Jy5ib2xkLFxyXG4gICAgJ1xcbi0tLS0tLScsXHJcbiAgICBgXFxuRm9yIG1vcmUgZGV0YWlsZWQgaW5mb3JtYXRpb24sIHZpc2l0IHRoZSByZWFkbWUgYXQ6ICR7cmVhZG1lLmJvbGQueWVsbG93fS5gXHJcbiAgKTtcclxuXHJcbiAgY29uc3QgY3ljbGVDYXRlZ29yaWVzID0gKG9wdGlvbnMpID0+IHtcclxuICAgIGZvciAoY29uc3QgW25hbWUsIG9wdGlvbl0gb2YgT2JqZWN0LmVudHJpZXMob3B0aW9ucykpIHtcclxuICAgICAgLy8gSWYgY2F0ZWdvcnkgaGFzIG1vcmUgbGV2ZWxzLCBnbyBmdXJ0aGVyXHJcbiAgICAgIGlmICghT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9wdGlvbiwgJ3ZhbHVlJykpIHtcclxuICAgICAgICBjeWNsZUNhdGVnb3JpZXMob3B0aW9uKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBsZXQgZGVzY05hbWUgPSBgICAtLSR7b3B0aW9uLmNsaU5hbWUgfHwgbmFtZX0gJHtcclxuICAgICAgICAgICgnPCcgKyBvcHRpb24udHlwZSArICc+JykuZ3JlZW5cclxuICAgICAgICB9IGA7XHJcbiAgICAgICAgaWYgKGRlc2NOYW1lLmxlbmd0aCA8IHBhZCkge1xyXG4gICAgICAgICAgZm9yIChsZXQgaSA9IGRlc2NOYW1lLmxlbmd0aDsgaSA8IHBhZDsgaSsrKSB7XHJcbiAgICAgICAgICAgIGRlc2NOYW1lICs9ICcuJztcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIERpc3BsYXkgY29ycmVjdGx5IGFsaWduZWQgbWVzc2FnZXNcclxuICAgICAgICBjb25zb2xlLmxvZyhcclxuICAgICAgICAgIGRlc2NOYW1lLFxyXG4gICAgICAgICAgb3B0aW9uLmRlc2NyaXB0aW9uLFxyXG4gICAgICAgICAgYFtEZWZhdWx0OiAke29wdGlvbi52YWx1ZS50b1N0cmluZygpLmJvbGR9XWAuYmx1ZVxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9O1xyXG5cclxuICAvLyBDeWNsZSB0aHJvdWdoIG9wdGlvbnMgb2YgZWFjaCBjYXRlZ29yaWVzIGFuZCBkaXNwbGF5IHRoZSB1c2FnZSBpbmZvXHJcbiAgT2JqZWN0LmtleXMoZGVmYXVsdENvbmZpZykuZm9yRWFjaCgoY2F0ZWdvcnkpID0+IHtcclxuICAgIC8vIE9ubHkgcHVwcGV0ZWVyIGFuZCBoaWdoY2hhcnRzIGNhdGVnb3JpZXMgY2Fubm90IGJlIGNvbmZpZ3VyZWQgdGhyb3VnaCBDTElcclxuICAgIGlmICghWydwdXBwZXRlZXInLCAnaGlnaGNoYXJ0cyddLmluY2x1ZGVzKGNhdGVnb3J5KSkge1xyXG4gICAgICBjb25zb2xlLmxvZyhgXFxuJHtjYXRlZ29yeS50b1VwcGVyQ2FzZSgpfWAucmVkKTtcclxuICAgICAgY3ljbGVDYXRlZ29yaWVzKGRlZmF1bHRDb25maWdbY2F0ZWdvcnldKTtcclxuICAgIH1cclxuICB9KTtcclxuICBjb25zb2xlLmxvZygnXFxuJyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSb3VuZHMgYSBudW1iZXIgdG8gdGhlIHNwZWNpZmllZCBwcmVjaXNpb24uXHJcbiAqXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSB2YWx1ZSAtIFRoZSBudW1iZXIgdG8gYmUgcm91bmRlZC5cclxuICogQHBhcmFtIHtudW1iZXJ9IHByZWNpc2lvbiAtIFRoZSBudW1iZXIgb2YgZGVjaW1hbCBwbGFjZXMgdG8gcm91bmQgdG8uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtudW1iZXJ9IC0gVGhlIHJvdW5kZWQgbnVtYmVyLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHJvdW5kTnVtYmVyID0gKHZhbHVlLCBwcmVjaXNpb24gPSAxKSA9PiB7XHJcbiAgY29uc3QgbXVsdGlwbGllciA9IE1hdGgucG93KDEwLCBwcmVjaXNpb24gfHwgMCk7XHJcbiAgcmV0dXJuIE1hdGgucm91bmQoK3ZhbHVlICogbXVsdGlwbGllcikgLyBtdWx0aXBsaWVyO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIENvbnZlcnRzIGEgdmFsdWUgdG8gYSBib29sZWFuLlxyXG4gKlxyXG4gKiBAcGFyYW0ge2FueX0gaXRlbSAtIFRoZSB2YWx1ZSB0byBiZSBjb252ZXJ0ZWQgdG8gYSBib29sZWFuLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBUaGUgYm9vbGVhbiByZXByZXNlbnRhdGlvbiBvZiB0aGUgaW5wdXQgdmFsdWUuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgdG9Cb29sZWFuID0gKGl0ZW0pID0+XHJcbiAgWydmYWxzZScsICd1bmRlZmluZWQnLCAnbnVsbCcsICdOYU4nLCAnMCcsICcnXS5pbmNsdWRlcyhpdGVtKVxyXG4gICAgPyBmYWxzZVxyXG4gICAgOiAhIWl0ZW07XHJcblxyXG4vKipcclxuICogV3JhcHMgY3VzdG9tIGNvZGUgdG8gZXhlY3V0ZSBpdCBzYWZlbHkuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBjdXN0b21Db2RlIC0gVGhlIGN1c3RvbSBjb2RlIHRvIGJlIHdyYXBwZWQuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gYWxsb3dGaWxlUmVzb3VyY2VzIC0gRmxhZyB0byBhbGxvdyBsb2FkaW5nIGNvZGUgZnJvbSBhIGZpbGUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd8Ym9vbGVhbn0gLSBUaGUgd3JhcHBlZCBjdXN0b20gY29kZSBvciBmYWxzZSBpZiB3cmFwcGluZ1xyXG4gKiBmYWlscy5cclxuICovXHJcbmV4cG9ydCBjb25zdCB3cmFwQXJvdW5kID0gKGN1c3RvbUNvZGUsIGFsbG93RmlsZVJlc291cmNlcykgPT4ge1xyXG4gIGlmIChjdXN0b21Db2RlICYmIHR5cGVvZiBjdXN0b21Db2RlID09PSAnc3RyaW5nJykge1xyXG4gICAgY3VzdG9tQ29kZSA9IGN1c3RvbUNvZGUudHJpbSgpO1xyXG5cclxuICAgIGlmIChjdXN0b21Db2RlLmVuZHNXaXRoKCcuanMnKSkge1xyXG4gICAgICByZXR1cm4gYWxsb3dGaWxlUmVzb3VyY2VzXHJcbiAgICAgICAgPyB3cmFwQXJvdW5kKHJlYWRGaWxlU3luYyhjdXN0b21Db2RlLCAndXRmOCcpKVxyXG4gICAgICAgIDogZmFsc2U7XHJcbiAgICB9IGVsc2UgaWYgKFxyXG4gICAgICBjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uKCknKSB8fFxyXG4gICAgICBjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uICgpJykgfHxcclxuICAgICAgY3VzdG9tQ29kZS5zdGFydHNXaXRoKCcoKT0+JykgfHxcclxuICAgICAgY3VzdG9tQ29kZS5zdGFydHNXaXRoKCcoKSA9PicpXHJcbiAgICApIHtcclxuICAgICAgcmV0dXJuIGAoJHtjdXN0b21Db2RlfSkoKWA7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gY3VzdG9tQ29kZS5yZXBsYWNlKC87JC8sICcnKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogVXRpbGl0eSB0byBtZWFzdXJlIGVsYXBzZWQgdGltZSB1c2luZyB0aGUgTm9kZS5qcyBwcm9jZXNzLmhydGltZSgpIG1ldGhvZC5cclxuICpcclxuICogQHJldHVybnMge2Z1bmN0aW9uKCk6IG51bWJlcn0gLSBBIGZ1bmN0aW9uIHRvIGNhbGN1bGF0ZSB0aGUgZWxhcHNlZCB0aW1lXHJcbiAqIGluIG1pbGxpc2Vjb25kcy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBtZWFzdXJlVGltZSA9ICgpID0+IHtcclxuICBjb25zdCBzdGFydCA9IHByb2Nlc3MuaHJ0aW1lLmJpZ2ludCgpO1xyXG4gIHJldHVybiAoKSA9PiBOdW1iZXIocHJvY2Vzcy5ocnRpbWUuYmlnaW50KCkgLSBzdGFydCkgLyAxMDAwMDAwO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIF9fZGlybmFtZSxcclxuICBjbGVhclRleHQsXHJcbiAgZXhwQmFja29mZixcclxuICBmaXhUeXBlLFxyXG4gIGhhbmRsZVJlc291cmNlcyxcclxuICBpc0NvcnJlY3RKU09OLFxyXG4gIGlzT2JqZWN0LFxyXG4gIGlzT2JqZWN0RW1wdHksXHJcbiAgaXNQcml2YXRlUmFuZ2VVcmxGb3VuZCxcclxuICBvcHRpb25zU3RyaW5naWZ5LFxyXG4gIHByaW50TG9nbyxcclxuICBwcmludFVzYWdlLFxyXG4gIHJvdW5kTnVtYmVyLFxyXG4gIHRvQm9vbGVhbixcclxuICB3cmFwQXJvdW5kLFxyXG4gIG1lYXN1cmVUaW1lXHJcbn07XHJcbiIsImNsYXNzIEV4cG9ydEVycm9yIGV4dGVuZHMgRXJyb3Ige1xyXG4gIGNvbnN0cnVjdG9yKG1lc3NhZ2UpIHtcclxuICAgIHN1cGVyKCk7XHJcbiAgICB0aGlzLm1lc3NhZ2UgPSBtZXNzYWdlO1xyXG4gICAgdGhpcy5zdGFja01lc3NhZ2UgPSBtZXNzYWdlO1xyXG4gIH1cclxuXHJcbiAgc2V0RXJyb3IoZXJyb3IpIHtcclxuICAgIHRoaXMuZXJyb3IgPSBlcnJvcjtcclxuICAgIGlmIChlcnJvci5uYW1lKSB7XHJcbiAgICAgIHRoaXMubmFtZSA9IGVycm9yLm5hbWU7XHJcbiAgICB9XHJcbiAgICBpZiAoZXJyb3Iuc3RhdHVzQ29kZSkge1xyXG4gICAgICB0aGlzLnN0YXR1c0NvZGUgPSBlcnJvci5zdGF0dXNDb2RlO1xyXG4gICAgfVxyXG4gICAgaWYgKGVycm9yLnN0YWNrKSB7XHJcbiAgICAgIHRoaXMuc3RhY2tNZXNzYWdlID0gZXJyb3IubWVzc2FnZTtcclxuICAgICAgdGhpcy5zdGFjayA9IGVycm9yLnN0YWNrO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIHRoaXM7XHJcbiAgfVxyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCBFeHBvcnRFcnJvcjtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vLyBUaGUgY2FjaGUgbWFuYWdlciBtYW5hZ2VzIHRoZSBIaWdoY2hhcnRzIGxpYnJhcnkgYW5kIGl0cyBkZXBlbmRlbmNpZXMuXHJcbi8vIFRoZSBjYWNoZSBpdHNlbGYgaXMgc3RvcmVkIGluIC5jYWNoZSwgYW5kIGlzIGNoZWNrZWQgYnkgdGhlIGNvbmZpZyBzeXN0ZW1cclxuLy8gYmVmb3JlIHN0YXJ0aW5nIHRoZSBzZXJ2aWNlXHJcblxyXG5pbXBvcnQgeyBleGlzdHNTeW5jLCBta2RpclN5bmMsIHJlYWRGaWxlU3luYywgd3JpdGVGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IGRvdGVudiBmcm9tICdkb3RlbnYnO1xyXG5pbXBvcnQgeyBIdHRwc1Byb3h5QWdlbnQgfSBmcm9tICdodHRwcy1wcm94eS1hZ2VudCc7XHJcblxyXG5pbXBvcnQgeyBmZXRjaCB9IGZyb20gJy4vZmV0Y2guanMnO1xyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IF9fZGlybmFtZSB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbmRvdGVudi5jb25maWcoKTtcclxuXHJcbmNvbnN0IGNhY2hlID0ge1xyXG4gIGNkblVSTDogJ2h0dHBzOi8vY29kZS5oaWdoY2hhcnRzLmNvbS8nLFxyXG4gIGFjdGl2ZU1hbmlmZXN0OiB7fSxcclxuICBzb3VyY2VzOiAnJyxcclxuICBoY1ZlcnNpb246ICcnXHJcbn07XHJcblxyXG4vLyBUT0RPOiBUaGUgY29uZmlnIHNob3VsZCBiZSBhY2Nlc3NzaWJsZSBnbG9iYWxseSBzbyB3ZSBkb24ndCBoYXZlIHRvIGRvIHRoaXMgc29ydCBvZiB0aGluZy4uXHJcbmxldCBhcHBsaWVkQ29uZmlnID0gZmFsc2U7XHJcblxyXG4vKipcclxuICogRXh0cmFjdHMgYW5kIGNhY2hlcyB0aGUgSGlnaGNoYXJ0cyB2ZXJzaW9uIGZyb20gdGhlIHNvdXJjZXMgc3RyaW5nLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgZXh0cmFjdGVkIEhpZ2hjaGFydHMgdmVyc2lvbi5cclxuICovXHJcbmNvbnN0IGV4dHJhY3RWZXJzaW9uID0gKCkgPT5cclxuICAoY2FjaGUuaGNWZXJzaW9uID0gY2FjaGUuc291cmNlc1xyXG4gICAgLnN1YnN0cmluZygwLCBjYWNoZS5zb3VyY2VzLmluZGV4T2YoJyovJykpXHJcbiAgICAucmVwbGFjZSgnLyonLCAnJylcclxuICAgIC5yZXBsYWNlKCcqLycsICcnKVxyXG4gICAgLnJlcGxhY2UoL1xcbi9nLCAnJylcclxuICAgIC50cmltKCkpO1xyXG5cclxuXHJcbi8qKlxyXG4gKiBFeHRyYWN0cyB0aGUgSGlnaGNoYXJ0cyBtb2R1bGUgbmFtZSBiYXNlZCBvbiB0aGUgc2NyaXB0UGF0aC5cclxuICovXHJcbmNvbnN0IGV4dHJhY3RNb2R1bGVOYW1lID0gKHNjcmlwdFBhdGgpID0+IHtcclxuICByZXR1cm4gc2NyaXB0UGF0aC5yZXBsYWNlKFxyXG4gICAgLyguKilcXC98KC4qKW1vZHVsZXNcXC98c3RvY2tcXC8oLiopaW5kaWNhdG9yc1xcL3xtYXBzXFwvKC4qKW1vZHVsZXNcXC8vZ2ksXHJcbiAgICAnJ1xyXG4gICk7XHJcbn07XHJcblxyXG4vKipcclxuICogU2F2ZXMgdGhlIHByb3ZpZGVkIGNvbmZpZ3VyYXRpb24gYW5kIGZldGNoZWQgbW9kdWxlcyB0byB0aGUgY2FjaGUgbWFuaWZlc3RcclxuICogZmlsZS5cclxuICpcclxuICogQHBhcmFtIHtvYmplY3R9IGNvbmZpZyAtIEhpZ2hjaGFydHMtcmVsYXRlZCBjb25maWd1cmF0aW9uIG9iamVjdC5cclxuICogQHBhcmFtIHtvYmplY3R9IGZldGNoZWRNb2R1bGVzIC0gQW4gb2JqZWN0IHRoYXQgY29udGFpbnMgbWFwcGVkIG5hbWVzIG9mXHJcbiAqIGZldGNoZWQgSGlnaGNoYXJ0cyBtb2R1bGVzIHRvIHVzZS5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiBhbiBlcnJvciBvY2N1cnMgd2hpbGUgd3JpdGluZ1xyXG4gKiB0aGUgY2FjaGUgbWFuaWZlc3QuXHJcbiAqL1xyXG5jb25zdCBzYXZlQ29uZmlnVG9NYW5pZmVzdCA9IGFzeW5jIChjb25maWcsIGZldGNoZWRNb2R1bGVzKSA9PiB7XHJcbiAgY29uc3QgbmV3TWFuaWZlc3QgPSB7XHJcbiAgICB2ZXJzaW9uOiBjb25maWcudmVyc2lvbixcclxuICAgIG1vZHVsZXM6IGZldGNoZWRNb2R1bGVzIHx8IHt9XHJcbiAgfTtcclxuXHJcbiAgLy8gVXBkYXRlIGNhY2hlIG9iamVjdCB3aXRoIHRoZSBjdXJyZW50IG1vZHVsZXNcclxuICBjYWNoZS5hY3RpdmVNYW5pZmVzdCA9IG5ld01hbmlmZXN0O1xyXG5cclxuICBsb2coMywgJ1tjYWNoZV0gV3JpdGluZyBhIG5ldyBtYW5pZmVzdC4nKTtcclxuICB0cnkge1xyXG4gICAgd3JpdGVGaWxlU3luYyhcclxuICAgICAgam9pbihfX2Rpcm5hbWUsIGNvbmZpZy5jYWNoZVBhdGgsICdtYW5pZmVzdC5qc29uJyksXHJcbiAgICAgIEpTT04uc3RyaW5naWZ5KG5ld01hbmlmZXN0KSxcclxuICAgICAgJ3V0ZjgnXHJcbiAgICApO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1tjYWNoZV0gRXJyb3Igd3JpdGluZyB0aGUgY2FjaGUgbWFuaWZlc3QuJykuc2V0RXJyb3IoXHJcbiAgICAgIGVycm9yXHJcbiAgICApO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBGZXRjaGVzIGEgc2luZ2xlIHNjcmlwdCBhbmQgdXBkYXRlcyB0aGUgZmV0Y2hlZE1vZHVsZXMgYWNjb3JkaW5nbHkuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBzY3JpcHQgLSBBIHBhdGggdG8gc2NyaXB0IHRvIGdldC5cclxuICogQHBhcmFtIHtPYmplY3R9IHByb3h5QWdlbnQgLSBUaGUgcHJveHkgYWdlbnQgdG8gdXNlIGZvciBhIHJlcXVlc3QuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBmZXRjaGVkTW9kdWxlcyAtIEFuIG9iamVjdCB3aGljaCB0cmFja3Mgd2hpY2ggSGlnaGNoYXJ0cyBtb2R1bGVzIGhhdmUgYmVlbiBmZXRjaGVkLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IHNob3VsZFRocm93RXJyb3IgLSBBIGZsYWcgdG8gaW5kaWNhdGUgaWYgdGhlIGVycm9yIHNob3VsZCBiZSB0aHJvd24uIFRoaXMgc2hvdWxkIGJlIHVzZWQgb25seSBmb3IgdGhlIGNvcmUgc2NyaXB0cy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gQSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgdGV4dCByZXByZXNlbnRhdGlvblxyXG4gKiBvZiB0aGUgZmV0Y2hlZCBzY3JpcHQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgdGhlcmUgaXMgYSBwcm9ibGVtIHdpdGhcclxuICogZmV0Y2hpbmcgdGhlIHNjcmlwdC5cclxuICovXHJcbmNvbnN0IGZldGNoQW5kUHJvY2Vzc1NjcmlwdCA9IGFzeW5jIChcclxuICBzY3JpcHQsXHJcbiAgcHJveHlBZ2VudCxcclxuICBmZXRjaGVkTW9kdWxlcyxcclxuICBzaG91bGRUaHJvd0Vycm9yID0gZmFsc2VcclxuKSA9PiB7XHJcbiAgLy8gR2V0IHJpZCBvZiB0aGUgLmpzIGZyb20gdGhlIGN1c3RvbSBzdHJpbmdzXHJcbiAgaWYgKHNjcmlwdC5lbmRzV2l0aCgnLmpzJykpIHtcclxuICAgIHNjcmlwdCA9IHNjcmlwdC5zdWJzdHJpbmcoMCwgc2NyaXB0Lmxlbmd0aCAtIDMpO1xyXG4gIH1cclxuXHJcbiAgbG9nKDQsIGBbY2FjaGVdIEZldGNoaW5nIHNjcmlwdCAtICR7c2NyaXB0fS5qc2ApO1xyXG5cclxuICAvLyBJZiBleGlzdHMsIGFkZCBwcm94eSBhZ2VudCB0byByZXF1ZXN0IG9wdGlvbnNcclxuICBjb25zdCByZXF1ZXN0T3B0aW9ucyA9IHByb3h5QWdlbnRcclxuICAgID8ge1xyXG4gICAgICAgIGFnZW50OiBwcm94eUFnZW50LFxyXG4gICAgICAgIHRpbWVvdXQ6ICtwcm9jZXNzLmVudlsnUFJPWFlfU0VSVkVSX1RJTUVPVVQnXSB8fCA1MDAwXHJcbiAgICAgIH1cclxuICAgIDoge307XHJcblxyXG4gIC8vIEZldGNoIHRoZSBzY3JpcHRcclxuICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZldGNoKGAke3NjcmlwdH0uanNgLCByZXF1ZXN0T3B0aW9ucyk7XHJcblxyXG4gIC8vIElmIE9LLCByZXR1cm4gaXRzIHRleHQgcmVwcmVzZW50YXRpb25cclxuICBpZiAocmVzcG9uc2Uuc3RhdHVzQ29kZSA9PT0gMjAwICYmIHR5cGVvZiByZXNwb25zZS50ZXh0ID09ICdzdHJpbmcnKSB7XHJcbiAgICBpZiAoZmV0Y2hlZE1vZHVsZXMpIHtcclxuICAgICAgY29uc3QgbW9kdWxlTmFtZSA9IGV4dHJhY3RNb2R1bGVOYW1lKHNjcmlwdCk7XHJcbiAgICAgIGZldGNoZWRNb2R1bGVzW21vZHVsZU5hbWVdID0gMTtcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gcmVzcG9uc2UudGV4dDtcclxuICB9XHJcblxyXG4gIGlmIChzaG91bGRUaHJvd0Vycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgIGBDb3VsZCBub3QgZmV0Y2ggdGhlICR7c2NyaXB0fS5qcy4gVGhlIHNjcmlwdCBtaWdodCBub3QgZXhpc3QgaW4gdGhlIHJlcXVlc3RlZCB2ZXJzaW9uIChzdGF0dXMgY29kZTogJHtyZXNwb25zZS5zdGF0dXNDb2RlfSkuYFxyXG4gICAgKS5zZXRFcnJvcihyZXNwb25zZSk7XHJcbiAgfSBlbHNlIHtcclxuICAgIGxvZyhcclxuICAgICAgMixcclxuICAgICAgYFtjYWNoZV0gQ291bGQgbm90IGZldGNoIHRoZSAke3NjcmlwdH0uanMuIFRoZSBzY3JpcHQgbWlnaHQgbm90IGV4aXN0IGluIHRoZSByZXF1ZXN0ZWQgdmVyc2lvbi5gXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgcmV0dXJuICcnO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEZldGNoZXMgSGlnaGNoYXJ0cyBzY3JpcHRzIGFuZCBjdXN0b21TY3JpcHRzIGZyb20gdGhlIGdpdmVuIENETnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBzY3JpcHRzIC0gQXJyYXkgb2YgSGlnaGNoYXJ0cyBtb2R1bGVzIHRvIGZldGNoLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY3VzdG9tU2NyaXB0cyAtIEFycmF5IG9mIGN1c3RvbSBzY3JpcHQgcGF0aHMgdG8gZmV0Y2ggKGZ1bGwgVVJMcykuXHJcbiAqIEBwYXJhbSB7b2JqZWN0fSBwcm94eUFnZW50IC0gVGhlIHByb3h5IGFnZW50IHRvIHVzZSBmb3IgYSByZXF1ZXN0LlxyXG4gKiBAcGFyYW0ge29iamVjdH0gZmV0Y2hlZE1vZHVsZXMgLSBBbiBvYmplY3Qgd2hpY2ggdHJhY2tzIHdoaWNoIEhpZ2hjaGFydHMgbW9kdWxlcyBoYXZlIGJlZW4gZmV0Y2hlZC5cclxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gVGhlIGZldGNoZWQgc2NyaXB0cyBjb250ZW50IGpvaW5lZC5cclxuICovXHJcbmNvbnN0IGZldGNoU2NyaXB0cyA9IGFzeW5jIChcclxuICBjb3JlU2NyaXB0cyxcclxuICBtb2R1bGVTY3JpcHRzLFxyXG4gIGN1c3RvbVNjcmlwdHMsXHJcbiAgY2RuVVJMLFxyXG4gIHByb3h5QWdlbnQsXHJcbiAgZmV0Y2hlZE1vZHVsZXNcclxuKSA9PiB7XHJcbiAgY29uc3QgYWxsRmV0Y2hQcm9taXNlcyA9IFtcclxuICAgIC4uLmNvcmVTY3JpcHRzLm1hcCgoc2NyaXB0KSA9PlxyXG4gICAgICBmZXRjaEFuZFByb2Nlc3NTY3JpcHQoXHJcbiAgICAgICAgYCR7Y2RuVVJMfSR7c2NyaXB0fWAsXHJcbiAgICAgICAgcHJveHlBZ2VudCxcclxuICAgICAgICBmZXRjaGVkTW9kdWxlcyxcclxuICAgICAgICB0cnVlXHJcbiAgICAgIClcclxuICAgICksXHJcbiAgICAuLi5tb2R1bGVTY3JpcHRzLm1hcCgoc2NyaXB0KSA9PlxyXG4gICAgICBmZXRjaEFuZFByb2Nlc3NTY3JpcHQoYCR7Y2RuVVJMfSR7c2NyaXB0fWAsIHByb3h5QWdlbnQsIGZldGNoZWRNb2R1bGVzKVxyXG4gICAgKSxcclxuICAgIC4uLmN1c3RvbVNjcmlwdHMubWFwKChzY3JpcHQpID0+XHJcbiAgICAgIGZldGNoQW5kUHJvY2Vzc1NjcmlwdChgJHtzY3JpcHR9YCwgcHJveHlBZ2VudClcclxuICAgIClcclxuICBdO1xyXG5cclxuICBjb25zdCBmZXRjaGVkU2NyaXB0cyA9IGF3YWl0IFByb21pc2UuYWxsKGFsbEZldGNoUHJvbWlzZXMpO1xyXG4gIHJldHVybiBmZXRjaGVkU2NyaXB0cy5qb2luKCc7XFxuJyk7XHJcbn07XHJcblxyXG4vKipcclxuICogVXBkYXRlcyB0aGUgbG9jYWwgY2FjaGUgd2l0aCBIaWdoY2hhcnRzIHNjcmlwdHMgYW5kIHRoZWlyIHZlcnNpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmcgaW5mb3JtYXRpb25cclxuICogYWJvdXQgc2NyaXB0cyBhbmQgbW9kdWxlcy5cclxuICogQHBhcmFtIHtzdHJpbmd9IHNvdXJjZVBhdGggLSBUaGUgcGF0aCB0byB0aGUgc291cmNlIGZpbGUgaW4gdGhlIGNhY2hlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxvYmplY3Q+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIGFuIG9iamVjdCByZXByZXNlbnRpbmdcclxuICogdGhlIGZldGNoZWQgbW9kdWxlcy5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiB0aGVyZSBpcyBhbiBpc3N1ZSB1cGRhdGluZ1xyXG4gKiB0aGUgbG9jYWwgSGlnaGNoYXJ0cyBjYWNoZS5cclxuICovXHJcbmNvbnN0IHVwZGF0ZUNhY2hlID0gYXN5bmMgKGNvbmZpZywgc291cmNlUGF0aCkgPT4ge1xyXG4gIGNvbnN0IHsgY29yZVNjcmlwdHMsIG1vZHVsZXMsIGluZGljYXRvcnMsIHNjcmlwdHM6IGN1c3RvbVNjcmlwdHMgfSA9IGNvbmZpZztcclxuICBjb25zdCBoY1ZlcnNpb24gPVxyXG4gICAgY29uZmlnLnZlcnNpb24gPT09ICdsYXRlc3QnIHx8ICFjb25maWcudmVyc2lvbiA/ICcnIDogYCR7Y29uZmlnLnZlcnNpb259L2A7XHJcblxyXG4gIGxvZyhcclxuICAgIDMsXHJcbiAgICBgW2NhY2hlXSBVcGRhdGluZyBjYWNoZSB2ZXJzaW9uIHRvIEhpZ2hjaGFydHM6ICR7aGNWZXJzaW9uIHx8ICdsYXRlc3QnfS5gXHJcbiAgKTtcclxuXHJcbiAgLy8gQ29uZmlndXJlIHByb3h5IGlmIGV4aXN0c1xyXG4gIGxldCBwcm94eUFnZW50O1xyXG4gIGNvbnN0IHByb3h5SG9zdCA9IHByb2Nlc3MuZW52WydQUk9YWV9TRVJWRVJfSE9TVCddO1xyXG4gIGNvbnN0IHByb3h5UG9ydCA9IHByb2Nlc3MuZW52WydQUk9YWV9TRVJWRVJfUE9SVCddO1xyXG5cclxuICAvLyBUcnkgdG8gY3JlYXRlIGEgUHJveHkgQWdlbnRcclxuICBpZiAocHJveHlIb3N0ICYmIHByb3h5UG9ydCkge1xyXG4gICAgdHJ5IHtcclxuICAgICAgcHJveHlBZ2VudCA9IG5ldyBIdHRwc1Byb3h5QWdlbnQoe1xyXG4gICAgICAgIGhvc3Q6IHByb3h5SG9zdCxcclxuICAgICAgICBwb3J0OiArcHJveHlQb3J0XHJcbiAgICAgIH0pO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbY2FjaGVdIENvdWxkIG5vdCBjcmVhdGUgYSBQcm94eSBBZ2VudC4nKS5zZXRFcnJvcihcclxuICAgICAgICBlcnJvclxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgY29uc3QgZmV0Y2hlZE1vZHVsZXMgPSB7fTtcclxuICB0cnkge1xyXG4gICAgY2FjaGUuc291cmNlcyA9IGF3YWl0IGZldGNoU2NyaXB0cyhcclxuICAgICAgWy4uLmNvcmVTY3JpcHRzLm1hcCgoYykgPT4gYCR7aGNWZXJzaW9ufSR7Y31gKV0sXHJcbiAgICAgIFtcclxuICAgICAgICAuLi5tb2R1bGVzLm1hcCgobSkgPT5cclxuICAgICAgICAgIG0gPT09ICdtYXAnXHJcbiAgICAgICAgICAgID8gYG1hcHMvJHtoY1ZlcnNpb259bW9kdWxlcy8ke219YFxyXG4gICAgICAgICAgICA6IGAke2hjVmVyc2lvbn1tb2R1bGVzLyR7bX1gXHJcbiAgICAgICAgKSxcclxuICAgICAgICAuLi5pbmRpY2F0b3JzLm1hcCgoaSkgPT4gYHN0b2NrLyR7aGNWZXJzaW9ufWluZGljYXRvcnMvJHtpfWApXHJcbiAgICAgIF0sXHJcbiAgICAgIGN1c3RvbVNjcmlwdHMsXHJcbiAgICAgIGNvbmZpZy5jZG5VUkwgfHwgY2FjaGUuY2RuVVJMLFxyXG4gICAgICBwcm94eUFnZW50LFxyXG4gICAgICBmZXRjaGVkTW9kdWxlc1xyXG4gICAgKTtcclxuICAgIGV4dHJhY3RWZXJzaW9uKCk7XHJcblxyXG4gICAgLy8gU2F2ZSB0aGUgZmV0Y2hlZCBtb2R1bGVzIGludG8gY2FjaGVzJyBzb3VyY2UgSlNPTlxyXG4gICAgd3JpdGVGaWxlU3luYyhzb3VyY2VQYXRoLCBjYWNoZS5zb3VyY2VzKTtcclxuICAgIHJldHVybiBmZXRjaGVkTW9kdWxlcztcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW2NhY2hlXSBVbmFibGUgdG8gdXBkYXRlIHRoZSBsb2NhbCBIaWdoY2hhcnRzIGNhY2hlLidcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBVcGRhdGVzIHRoZSBIaWdoY2hhcnRzIHZlcnNpb24gaW4gdGhlIGFwcGxpZWQgY29uZmlndXJhdGlvbiBhbmQgY2hlY2tzXHJcbiAqIHRoZSBjYWNoZSBmb3IgdGhlIG5ldyB2ZXJzaW9uLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gbmV3VmVyc2lvbiAtIFRoZSBuZXcgSGlnaGNoYXJ0cyB2ZXJzaW9uIHRvIGJlIGFwcGxpZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPChvYmplY3R8Ym9vbGVhbik+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSB1cGRhdGVkXHJcbiAqIGNvbmZpZ3VyYXRpb24gd2l0aCB0aGUgbmV3IHZlcnNpb24sIG9yIGZhbHNlIGlmIG5vIGFwcGxpZWQgY29uZmlndXJhdGlvblxyXG4gKiBleGlzdHMuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgdXBkYXRlVmVyc2lvbiA9IGFzeW5jIChuZXdWZXJzaW9uKSA9PlxyXG4gIGFwcGxpZWRDb25maWdcclxuICAgID8gYXdhaXQgY2hlY2tBbmRVcGRhdGVDYWNoZShcclxuICAgICAgICBPYmplY3QuYXNzaWduKGFwcGxpZWRDb25maWcsIHtcclxuICAgICAgICAgIHZlcnNpb246IG5ld1ZlcnNpb25cclxuICAgICAgICB9KVxyXG4gICAgICApXHJcbiAgICA6IGZhbHNlO1xyXG5cclxuLyoqXHJcbiAqIENoZWNrcyB0aGUgY2FjaGUgZm9yIEhpZ2hjaGFydHMgZGVwZW5kZW5jaWVzLCB1cGRhdGVzIHRoZSBjYWNoZSBpZiBuZWVkZWQsXHJcbiAqIGFuZCBsb2FkcyB0aGUgc291cmNlcy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZyAtIEhpZ2hjaGFydHMtcmVsYXRlZCBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nIGluZm9ybWF0aW9uXHJcbiAqIGFib3V0IHNjcmlwdHMgYW5kIG1vZHVsZXMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBjYWNoZSBpcyBjaGVja2VkXHJcbiAqIGFuZCB1cGRhdGVkLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIHRoZXJlIGlzIGFuIGlzc3VlIHVwZGF0aW5nXHJcbiAqIG9yIHJlYWRpbmcgdGhlIGNhY2hlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGNoZWNrQW5kVXBkYXRlQ2FjaGUgPSBhc3luYyAoY29uZmlnKSA9PiB7XHJcbiAgY29uc3QgY2FjaGVQYXRoID0gam9pbihfX2Rpcm5hbWUsIGNvbmZpZy5jYWNoZVBhdGgpO1xyXG5cclxuICBsZXQgZmV0Y2hlZE1vZHVsZXM7XHJcbiAgLy8gUHJlcGFyZSBwYXRocyB0byBtYW5pZmVzdCBhbmQgc291cmNlcyBmcm9tIHRoZSAuY2FjaGUgZm9sZGVyXHJcbiAgY29uc3QgbWFuaWZlc3RQYXRoID0gam9pbihjYWNoZVBhdGgsICdtYW5pZmVzdC5qc29uJyk7XHJcbiAgY29uc3Qgc291cmNlUGF0aCA9IGpvaW4oY2FjaGVQYXRoLCAnc291cmNlcy5qcycpO1xyXG5cclxuICAvLyBUT0RPOiBkZWFsIHdpdGggdHJ5aW5nIHRvIHN3aXRjaCB0byB0aGUgcnVubmluZyB2ZXJzaW9uXHJcbiAgLy8gY29uc3QgYWN0aXZlVmVyc2lvbiA9IGFwcGxpZWRDb25maWcgPyBhcHBsaWVkQ29uZmlnLnZlcnNpb24gOiBmYWxzZTtcclxuXHJcbiAgYXBwbGllZENvbmZpZyA9IGNvbmZpZztcclxuXHJcbiAgLy8gQ3JlYXRlIHRoZSBjYWNoZSBkZXN0aW5hdGlvbiBpZiBpdCBkb2Vzbid0IGV4aXN0IGFscmVhZHlcclxuICAhZXhpc3RzU3luYyhjYWNoZVBhdGgpICYmIG1rZGlyU3luYyhjYWNoZVBhdGgpO1xyXG5cclxuICAvLyBGZXRjaCBhbGwgdGhlIHNjcmlwdHMgZWl0aGVyIGlmIG1hbmlmZXN0Lmpzb24gZG9lcyBub3QgZXhpc3RcclxuICAvLyBvciBpZiB0aGUgZm9yY2VGZXRjaCBvcHRpb24gaXMgZW5hYmxlZFxyXG4gIGlmICghZXhpc3RzU3luYyhtYW5pZmVzdFBhdGgpIHx8IGNvbmZpZy5mb3JjZUZldGNoKSB7XHJcbiAgICBsb2coMywgJ1tjYWNoZV0gRmV0Y2hpbmcgYW5kIGNhY2hpbmcgSGlnaGNoYXJ0cyBkZXBlbmRlbmNpZXMuJyk7XHJcbiAgICBmZXRjaGVkTW9kdWxlcyA9IGF3YWl0IHVwZGF0ZUNhY2hlKGNvbmZpZywgc291cmNlUGF0aCk7XHJcbiAgfSBlbHNlIHtcclxuICAgIGxldCByZXF1ZXN0VXBkYXRlID0gZmFsc2U7XHJcblxyXG4gICAgLy8gUmVhZCB0aGUgbWFuaWZlc3QgSlNPTlxyXG4gICAgY29uc3QgbWFuaWZlc3QgPSBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhtYW5pZmVzdFBhdGgpKTtcclxuXHJcbiAgICAvLyBDaGVjayBpZiB0aGUgbW9kdWxlcyBpcyBhbiBhcnJheSwgaWYgc28sIHdlIHJld3JpdGUgaXQgdG8gYSBtYXAgdG8gbWFrZVxyXG4gICAgLy8gaXQgZWFzaWVyIHRvIHJlc29sdmUgbW9kdWxlcy5cclxuICAgIGlmIChtYW5pZmVzdC5tb2R1bGVzICYmIEFycmF5LmlzQXJyYXkobWFuaWZlc3QubW9kdWxlcykpIHtcclxuICAgICAgY29uc3QgbW9kdWxlTWFwID0ge307XHJcbiAgICAgIG1hbmlmZXN0Lm1vZHVsZXMuZm9yRWFjaCgobSkgPT4gKG1vZHVsZU1hcFttXSA9IDEpKTtcclxuICAgICAgbWFuaWZlc3QubW9kdWxlcyA9IG1vZHVsZU1hcDtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCB7IG1vZHVsZXMsIGNvcmVTY3JpcHRzLCBpbmRpY2F0b3JzIH0gPSBjb25maWc7XHJcbiAgICBjb25zdCBudW1iZXJPZk1vZHVsZXMgPVxyXG4gICAgICBtb2R1bGVzLmxlbmd0aCArIGNvcmVTY3JpcHRzLmxlbmd0aCArIGluZGljYXRvcnMubGVuZ3RoO1xyXG5cclxuICAgIC8vIENvbXBhcmUgdGhlIGxvYWRlZCBjb25maWcgd2l0aCB0aGUgY29udGVudHMgaW4gY2FjaGUuXHJcbiAgICAvLyBJZiB0aGVyZSBhcmUgY2hhbmdlcywgZmV0Y2ggcmVxdWVzdGVkIG1vZHVsZXMgYW5kIHByb2R1Y3RzLFxyXG4gICAgLy8gYW5kIGJha2UgdGhlbSBpbnRvIGEgZ2lhbnQgYmxvYi4gU2F2ZSB0aGUgYmxvYi5cclxuICAgIGlmIChtYW5pZmVzdC52ZXJzaW9uICE9PSBjb25maWcudmVyc2lvbikge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgMixcclxuICAgICAgICAnW2NhY2hlXSBBIEhpZ2hjaGFydHMgdmVyc2lvbiBtaXNtYXRjaCBpbiB0aGUgY2FjaGUsIG5lZWQgdG8gcmUtZmV0Y2guJ1xyXG4gICAgICApO1xyXG4gICAgICByZXF1ZXN0VXBkYXRlID0gdHJ1ZTtcclxuICAgIH0gZWxzZSBpZiAoT2JqZWN0LmtleXMobWFuaWZlc3QubW9kdWxlcyB8fCB7fSkubGVuZ3RoICE9PSBudW1iZXJPZk1vZHVsZXMpIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDIsXHJcbiAgICAgICAgJ1tjYWNoZV0gVGhlIGNhY2hlIGFuZCB0aGUgcmVxdWVzdGVkIG1vZHVsZXMgZG8gbm90IG1hdGNoLCBuZWVkIHRvIHJlLWZldGNoLidcclxuICAgICAgKTtcclxuICAgICAgcmVxdWVzdFVwZGF0ZSA9IHRydWU7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBDaGVjayBlYWNoIG1vZHVsZSwgaWYgYW55dGhpbmcgaXMgbWlzc2luZyByZWZldGNoIGV2ZXJ5dGhpbmdcclxuICAgICAgcmVxdWVzdFVwZGF0ZSA9IChjb25maWcubW9kdWxlcyB8fCBbXSkuc29tZSgobW9kdWxlTmFtZSkgPT4ge1xyXG4gICAgICAgIGlmICghbWFuaWZlc3QubW9kdWxlc1ttb2R1bGVOYW1lXSkge1xyXG4gICAgICAgICAgbG9nKFxyXG4gICAgICAgICAgICAyLFxyXG4gICAgICAgICAgICBgW2NhY2hlXSBUaGUgJHttb2R1bGVOYW1lfSBpcyBtaXNzaW5nIGluIHRoZSBjYWNoZSwgbmVlZCB0byByZS1mZXRjaC5gXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgICAgfVxyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAocmVxdWVzdFVwZGF0ZSkge1xyXG4gICAgICBmZXRjaGVkTW9kdWxlcyA9IGF3YWl0IHVwZGF0ZUNhY2hlKGNvbmZpZywgc291cmNlUGF0aCk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBsb2coMywgJ1tjYWNoZV0gRGVwZW5kZW5jeSBjYWNoZSBpcyB1cCB0byBkYXRlLCBwcm9jZWVkaW5nLicpO1xyXG5cclxuICAgICAgLy8gTG9hZCB0aGUgc291cmNlc1xyXG4gICAgICBjYWNoZS5zb3VyY2VzID0gcmVhZEZpbGVTeW5jKHNvdXJjZVBhdGgsICd1dGY4Jyk7XHJcblxyXG4gICAgICAvLyBHZXQgY3VycmVudCBtb2R1bGVzIG1hcFxyXG4gICAgICBmZXRjaGVkTW9kdWxlcyA9IG1hbmlmZXN0Lm1vZHVsZXM7XHJcbiAgICAgIGV4dHJhY3RWZXJzaW9uKCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBGaW5hbGx5LCBzYXZlIHRoZSBuZXcgbWFuaWZlc3QsIHdoaWNoIGlzIGJhc2ljYWxseSBvdXIgY3VycmVudCBjb25maWdcclxuICAvLyBpbiBhIHNsaWdodGx5IGRpZmZlcmVudCBmb3JtYXRcclxuICBhd2FpdCBzYXZlQ29uZmlnVG9NYW5pZmVzdChjb25maWcsIGZldGNoZWRNb2R1bGVzKTtcclxufTtcclxuXHJcbmV4cG9ydCBjb25zdCBnZXRDYWNoZVBhdGggPSAoKSA9PiB7XHJcbiAgcmV0dXJuIGpvaW4oX19kaXJuYW1lLCBhcHBsaWVkQ29uZmlnLmNhY2hlUGF0aCk7XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgY2hlY2tBbmRVcGRhdGVDYWNoZSxcclxuICBnZXRDYWNoZVBhdGgsXHJcbiAgdXBkYXRlVmVyc2lvbixcclxuICBnZXRDYWNoZTogKCkgPT4gY2FjaGUsXHJcbiAgaGlnaGNoYXJ0czogKCkgPT4gY2FjaGUuc291cmNlcyxcclxuICB2ZXJzaW9uOiAoKSA9PiBjYWNoZS5oY1ZlcnNpb25cclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyBleGlzdHNTeW5jLCByZWFkRmlsZVN5bmMsIHByb21pc2VzIGFzIGZzUHJvbWlzZXMgfSBmcm9tICdmcyc7XHJcblxyXG5pbXBvcnQgcHJvbXB0cyBmcm9tICdwcm9tcHRzJztcclxuXHJcbmltcG9ydCB7XHJcbiAgYWJzb2x1dGVQcm9wcyxcclxuICBkZWZhdWx0Q29uZmlnLFxyXG4gIG5lc3RlZEFyZ3MsXHJcbiAgcHJvbXB0c0NvbmZpZ1xyXG59IGZyb20gJy4vc2NoZW1hcy9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgZGVlcENvcHksIGlzT2JqZWN0LCBwcmludFVzYWdlLCB0b0Jvb2xlYW4gfSBmcm9tICcuL3V0aWxzLmpzJztcclxuXHJcbmxldCBnZW5lcmFsT3B0aW9ucyA9IHt9O1xyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyBhbmQgcmV0dXJucyB0aGUgZ2VuZXJhbCBvcHRpb25zIGZvciB0aGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBnZW5lcmFsIG9wdGlvbnMgb2JqZWN0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldE9wdGlvbnMgPSAoKSA9PiBnZW5lcmFsT3B0aW9ucztcclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyBhbmQgc2V0cyB0aGUgZ2VuZXJhbCBvcHRpb25zIGZvciB0aGUgc2VydmVyIGluc3RhY2UsIGtlZXBpbmdcclxuICogdGhlIHByaW5jaXBsZSBvZiB0aGUgb3B0aW9ucyBsb2FkIHByaW9yaXR5LiBJdCBhY2NlcHRzIG9wdGlvbmFsIHVzZXJPcHRpb25zXHJcbiAqIGFuZCBhcmdzIGZyb20gdGhlIENMSS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHVzZXJPcHRpb25zIC0gVXNlci1wcm92aWRlZCBvcHRpb25zIGZvciBjdXN0b21pemF0aW9uLlxyXG4gKiBAcGFyYW0ge0FycmF5fSBhcmdzIC0gQ29tbWFuZC1saW5lIGFyZ3VtZW50cyBmb3IgYWRkaXRpb25hbCBjb25maWd1cmF0aW9uXHJcbiAqIChDTEkgdXNhZ2UpLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgdXBkYXRlZCBnZW5lcmFsIG9wdGlvbnMgb2JqZWN0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHNldE9wdGlvbnMgPSAodXNlck9wdGlvbnMsIGFyZ3MpID0+IHtcclxuICAvLyBPbmx5IGZvciB0aGUgQ0xJIHVzYWdlXHJcbiAgaWYgKGFyZ3M/Lmxlbmd0aCkge1xyXG4gICAgLy8gR2V0IHRoZSBhZGRpdGlvbmFsIG9wdGlvbnMgZnJvbSB0aGUgY3VzdG9tIEpTT04gZmlsZVxyXG4gICAgZ2VuZXJhbE9wdGlvbnMgPSBsb2FkQ29uZmlnRmlsZShhcmdzKTtcclxuICB9XHJcblxyXG4gIC8vIFVwZGF0ZSB0aGUgZGVmYXVsdCBjb25maWcgd2l0aCBhIGNvcnJlY3Qgb3B0aW9uIHZhbHVlc1xyXG4gIHVwZGF0ZURlZmF1bHRDb25maWcoZGVmYXVsdENvbmZpZywgZ2VuZXJhbE9wdGlvbnMpO1xyXG5cclxuICAvLyBTZXQgdmFsdWVzIGZvciBzZXJ2ZXIncyBvcHRpb25zIGFuZCByZXR1cm5zIHRoZW1cclxuICBnZW5lcmFsT3B0aW9ucyA9IGluaXRPcHRpb25zKGRlZmF1bHRDb25maWcpO1xyXG5cclxuICAvLyBBcHBseSB1c2VyIG9wdGlvbnMgaWYgdGhlcmUgYXJlIGFueVxyXG4gIGlmICh1c2VyT3B0aW9ucykge1xyXG4gICAgLy8gTWVyZ2UgdXNlciBvcHRpb25zXHJcbiAgICBnZW5lcmFsT3B0aW9ucyA9IG1lcmdlQ29uZmlnT3B0aW9ucyhcclxuICAgICAgZ2VuZXJhbE9wdGlvbnMsXHJcbiAgICAgIHVzZXJPcHRpb25zLFxyXG4gICAgICBhYnNvbHV0ZVByb3BzXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgLy8gT25seSBmb3IgdGhlIENMSSB1c2FnZVxyXG4gIGlmIChhcmdzPy5sZW5ndGgpIHtcclxuICAgIC8vIFBhaXIgcHJvdmlkZWQgYXJndW1lbnRzXHJcbiAgICBnZW5lcmFsT3B0aW9ucyA9IHBhaXJBcmd1bWVudFZhbHVlKGdlbmVyYWxPcHRpb25zLCBhcmdzLCBkZWZhdWx0Q29uZmlnKTtcclxuICB9XHJcblxyXG4gIC8vIFJldHVybiBmaW5hbCBnZW5lcmFsIG9wdGlvbnNcclxuICByZXR1cm4gZ2VuZXJhbE9wdGlvbnM7XHJcbn07XHJcblxyXG4vKipcclxuICogQWxsb3dzIG1hbnVhbCBjb25maWd1cmF0aW9uIGJhc2VkIG9uIHNwZWNpZmllZCBwcm9tcHRzIGFuZCBzYXZlc1xyXG4gKiB0aGUgY29uZmlndXJhdGlvbiB0byBhIGZpbGUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBjb25maWdGaWxlTmFtZSAtIFRoZSBuYW1lIG9mIHRoZSBjb25maWd1cmF0aW9uIGZpbGUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPGJvb2xlYW4+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0cnVlIG9uY2UgdGhlIG1hbnVhbFxyXG4gKiBjb25maWd1cmF0aW9uIGlzIGNvbXBsZXRlZCBhbmQgc2F2ZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbWFudWFsQ29uZmlnID0gYXN5bmMgKGNvbmZpZ0ZpbGVOYW1lKSA9PiB7XHJcbiAgLy8gUHJlcGFyZSBhIGNvbmZpZyBvYmplY3RcclxuICBsZXQgY29uZmlnRmlsZSA9IHt9O1xyXG5cclxuICAvLyBDaGVjayBpZiBwcm92aWRlZCBjb25maWcgZmlsZSBleGlzdHNcclxuICBpZiAoZXhpc3RzU3luYyhjb25maWdGaWxlTmFtZSkpIHtcclxuICAgIGNvbmZpZ0ZpbGUgPSBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhjb25maWdGaWxlTmFtZSwgJ3V0ZjgnKSk7XHJcbiAgfVxyXG5cclxuICAvLyBRdWVzdGlvbiBhYm91dCBhIGNvbmZpZ3VyYXRpb24gY2F0ZWdvcnlcclxuICBjb25zdCBvblN1Ym1pdCA9IGFzeW5jIChwLCBjYXRlZ29yaWVzKSA9PiB7XHJcbiAgICBsZXQgcXVlc3Rpb25zQ291bnRlciA9IDA7XHJcbiAgICBsZXQgYWxsUXVlc3Rpb25zID0gW107XHJcblxyXG4gICAgLy8gQ3JlYXRlIGEgY29ycmVzcG9uZGluZyBwcm9wZXJ0eSBpbiB0aGUgbWFudWFsQ29uZmlnIG9iamVjdFxyXG4gICAgZm9yIChjb25zdCBzZWN0aW9uIG9mIGNhdGVnb3JpZXMpIHtcclxuICAgICAgLy8gTWFyayBlYWNoIG9wdGlvbiB3aXRoIGEgc2VjdGlvblxyXG4gICAgICBwcm9tcHRzQ29uZmlnW3NlY3Rpb25dID0gcHJvbXB0c0NvbmZpZ1tzZWN0aW9uXS5tYXAoKG9wdGlvbikgPT4gKHtcclxuICAgICAgICAuLi5vcHRpb24sXHJcbiAgICAgICAgc2VjdGlvblxyXG4gICAgICB9KSk7XHJcblxyXG4gICAgICAvLyBDb2xsZWN0IHRoZSBxdWVzdGlvbnNcclxuICAgICAgYWxsUXVlc3Rpb25zID0gWy4uLmFsbFF1ZXN0aW9ucywgLi4ucHJvbXB0c0NvbmZpZ1tzZWN0aW9uXV07XHJcbiAgICB9XHJcblxyXG4gICAgYXdhaXQgcHJvbXB0cyhhbGxRdWVzdGlvbnMsIHtcclxuICAgICAgb25TdWJtaXQ6IGFzeW5jIChwcm9tcHQsIGFuc3dlcikgPT4ge1xyXG4gICAgICAgIC8vIEdldCB0aGUgZGVmYXVsdCBtb2R1bGVzXHJcbiAgICAgICAgaWYgKHByb21wdC5uYW1lID09PSAnbW9kdWxlcycpIHtcclxuICAgICAgICAgIGFuc3dlciA9IGFuc3dlci5sZW5ndGhcclxuICAgICAgICAgICAgPyBhbnN3ZXIubWFwKChtb2R1bGUpID0+IHByb21wdC5jaG9pY2VzW21vZHVsZV0pXHJcbiAgICAgICAgICAgIDogcHJvbXB0LmNob2ljZXM7XHJcblxyXG4gICAgICAgICAgY29uZmlnRmlsZVtwcm9tcHQuc2VjdGlvbl1bcHJvbXB0Lm5hbWVdID0gYW5zd2VyO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICBjb25maWdGaWxlW3Byb21wdC5zZWN0aW9uXSA9IHJlY3Vyc2l2ZVByb3BzKFxyXG4gICAgICAgICAgICBPYmplY3QuYXNzaWduKHt9LCBjb25maWdGaWxlW3Byb21wdC5zZWN0aW9uXSB8fCB7fSksXHJcbiAgICAgICAgICAgIHByb21wdC5uYW1lLnNwbGl0KCcuJyksXHJcbiAgICAgICAgICAgIHByb21wdC5jaG9pY2VzID8gcHJvbXB0LmNob2ljZXNbYW5zd2VyXSA6IGFuc3dlclxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGlmICgrK3F1ZXN0aW9uc0NvdW50ZXIgPT09IGFsbFF1ZXN0aW9ucy5sZW5ndGgpIHtcclxuICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgIGF3YWl0IGZzUHJvbWlzZXMud3JpdGVGaWxlKFxyXG4gICAgICAgICAgICAgIGNvbmZpZ0ZpbGVOYW1lLFxyXG4gICAgICAgICAgICAgIEpTT04uc3RyaW5naWZ5KGNvbmZpZ0ZpbGUsIG51bGwsIDIpLFxyXG4gICAgICAgICAgICAgICd1dGY4J1xyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgICAgICAgIDEsXHJcbiAgICAgICAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgICAgICAgYFtjb25maWddIEFuIGVycm9yIG9jY3VycmVkIHdoaWxlIGNyZWF0aW5nIHRoZSAke2NvbmZpZ0ZpbGVOYW1lfSBmaWxlLmBcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfSk7XHJcblxyXG4gICAgcmV0dXJuIHRydWU7XHJcbiAgfTtcclxuXHJcbiAgLy8gRmluZCB0aGUgY2F0ZWdvcmllc1xyXG4gIGNvbnN0IGNob2ljZXMgPSBPYmplY3Qua2V5cyhwcm9tcHRzQ29uZmlnKS5tYXAoKGNob2ljZSkgPT4gKHtcclxuICAgIHRpdGxlOiBgJHtjaG9pY2V9IG9wdGlvbnNgLFxyXG4gICAgdmFsdWU6IGNob2ljZVxyXG4gIH0pKTtcclxuXHJcbiAgLy8gQ2F0ZWdvcnkgcHJvbXB0XHJcbiAgcmV0dXJuIHByb21wdHMoXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdtdWx0aXNlbGVjdCcsXHJcbiAgICAgIG5hbWU6ICdjYXRlZ29yeScsXHJcbiAgICAgIG1lc3NhZ2U6ICdXaGljaCBjYXRlZ29yeSBkbyB5b3Ugd2FudCB0byBjb25maWd1cmU/JyxcclxuICAgICAgaGludDogJ1NwYWNlOiBTZWxlY3Qgc3BlY2lmaWMsIEE6IFNlbGVjdCBhbGwsIEVudGVyOiBDb25maXJtLicsXHJcbiAgICAgIGluc3RydWN0aW9uczogJycsXHJcbiAgICAgIGNob2ljZXNcclxuICAgIH0sXHJcbiAgICB7IG9uU3VibWl0IH1cclxuICApO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIE1hcHMgb2xkLXN0cnVjdHVyZWQgKFBoYW50b21KUykgb3B0aW9ucyB0byBhIG5ldyBjb25maWd1cmF0aW9uIGZvcm1hdFxyXG4gKiAoUHVwcGV0ZWVyKS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9sZE9wdGlvbnMgLSBPbGQtc3RydWN0dXJlZCBvcHRpb25zIHRvIGJlIG1hcHBlZC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gTmV3IG9wdGlvbnMgc3RydWN0dXJlZCBiYXNlZCBvbiB0aGUgZGVmaW5lZCBuZXN0ZWRBcmdzXHJcbiAqIG1hcHBpbmcuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbWFwVG9OZXdDb25maWcgPSAob2xkT3B0aW9ucykgPT4ge1xyXG4gIGNvbnN0IG5ld09wdGlvbnMgPSB7fTtcclxuICAvLyBDeWNsZSB0aHJvdWdoIG9sZC1zdHJ1Y3R1cmVkIG9wdGlvbnNcclxuICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhvbGRPcHRpb25zKSkge1xyXG4gICAgY29uc3QgcHJvcGVydGllc0NoYWluID0gbmVzdGVkQXJnc1trZXldID8gbmVzdGVkQXJnc1trZXldLnNwbGl0KCcuJykgOiBbXTtcclxuXHJcbiAgICAvLyBQb3B1bGF0ZSBvYmplY3QgaW4gY29ycmVjdCBwcm9wZXJ0aWVzIGxldmVsc1xyXG4gICAgcHJvcGVydGllc0NoYWluLnJlZHVjZShcclxuICAgICAgKG9iaiwgcHJvcCwgaW5kZXgpID0+XHJcbiAgICAgICAgKG9ialtwcm9wXSA9XHJcbiAgICAgICAgICBwcm9wZXJ0aWVzQ2hhaW4ubGVuZ3RoIC0gMSA9PT0gaW5kZXggPyB2YWx1ZSA6IG9ialtwcm9wXSB8fCB7fSksXHJcbiAgICAgIG5ld09wdGlvbnNcclxuICAgICk7XHJcbiAgfVxyXG4gIHJldHVybiBuZXdPcHRpb25zO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIE1lcmdlcyB0d28gc2V0cyBvZiBjb25maWd1cmF0aW9uIG9wdGlvbnMsIGNvbnNpZGVyaW5nIGFic29sdXRlIHByb3BlcnRpZXMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gT3JpZ2luYWwgY29uZmlndXJhdGlvbiBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gbmV3T3B0aW9ucyAtIE5ldyBjb25maWd1cmF0aW9uIG9wdGlvbnMgdG8gYmUgbWVyZ2VkLlxyXG4gKiBAcGFyYW0ge0FycmF5fSBhYnNvbHV0ZVByb3BzIC0gTGlzdCBvZiBwcm9wZXJ0aWVzIHRoYXQgc2hvdWxkXHJcbiAqIG5vdCBiZSByZWN1cnNpdmVseSBtZXJnZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IE1lcmdlZCBjb25maWd1cmF0aW9uIG9wdGlvbnMuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbWVyZ2VDb25maWdPcHRpb25zID0gKG9wdGlvbnMsIG5ld09wdGlvbnMsIGFic29sdXRlUHJvcHMgPSBbXSkgPT4ge1xyXG4gIGNvbnN0IG1lcmdlZE9wdGlvbnMgPSBkZWVwQ29weShvcHRpb25zKTtcclxuXHJcbiAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMobmV3T3B0aW9ucykpIHtcclxuICAgIG1lcmdlZE9wdGlvbnNba2V5XSA9XHJcbiAgICAgIGlzT2JqZWN0KHZhbHVlKSAmJlxyXG4gICAgICAhYWJzb2x1dGVQcm9wcy5pbmNsdWRlcyhrZXkpICYmXHJcbiAgICAgIG1lcmdlZE9wdGlvbnNba2V5XSAhPT0gdW5kZWZpbmVkXHJcbiAgICAgICAgPyBtZXJnZUNvbmZpZ09wdGlvbnMobWVyZ2VkT3B0aW9uc1trZXldLCB2YWx1ZSwgYWJzb2x1dGVQcm9wcylcclxuICAgICAgICA6IHZhbHVlICE9PSB1bmRlZmluZWRcclxuICAgICAgICAgID8gdmFsdWVcclxuICAgICAgICAgIDogbWVyZ2VkT3B0aW9uc1trZXldO1xyXG4gIH1cclxuXHJcbiAgcmV0dXJuIG1lcmdlZE9wdGlvbnM7XHJcbn07XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgZXhwb3J0IHNldHRpbmdzIGJhc2VkIG9uIHByb3ZpZGVkIGV4cG9ydE9wdGlvbnNcclxuICogYW5kIGdlbmVyYWxPcHRpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZXhwb3J0T3B0aW9ucyAtIE9wdGlvbnMgc3BlY2lmaWMgdG8gdGhlIGV4cG9ydCBwcm9jZXNzLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZ2VuZXJhbE9wdGlvbnMgLSBHZW5lcmFsIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gSW5pdGlhbGl6ZWQgZXhwb3J0IHNldHRpbmdzLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGluaXRFeHBvcnRTZXR0aW5ncyA9IChleHBvcnRPcHRpb25zLCBnZW5lcmFsT3B0aW9ucyA9IHt9KSA9PiB7XHJcbiAgbGV0IG9wdGlvbnMgPSB7fTtcclxuXHJcbiAgaWYgKGV4cG9ydE9wdGlvbnMuc3ZnKSB7XHJcbiAgICBvcHRpb25zID0gZGVlcENvcHkoZ2VuZXJhbE9wdGlvbnMpO1xyXG4gICAgb3B0aW9ucy5leHBvcnQudHlwZSA9IGV4cG9ydE9wdGlvbnMudHlwZSB8fCBleHBvcnRPcHRpb25zLmV4cG9ydC50eXBlO1xyXG4gICAgb3B0aW9ucy5leHBvcnQuc2NhbGUgPSBleHBvcnRPcHRpb25zLnNjYWxlIHx8IGV4cG9ydE9wdGlvbnMuZXhwb3J0LnNjYWxlO1xyXG4gICAgb3B0aW9ucy5leHBvcnQub3V0ZmlsZSA9XHJcbiAgICAgIGV4cG9ydE9wdGlvbnMub3V0ZmlsZSB8fCBleHBvcnRPcHRpb25zLmV4cG9ydC5vdXRmaWxlO1xyXG4gICAgb3B0aW9ucy5wYXlsb2FkID0ge1xyXG4gICAgICBzdmc6IGV4cG9ydE9wdGlvbnMuc3ZnXHJcbiAgICB9O1xyXG4gIH0gZWxzZSB7XHJcbiAgICBvcHRpb25zID0gbWVyZ2VDb25maWdPcHRpb25zKFxyXG4gICAgICBnZW5lcmFsT3B0aW9ucyxcclxuICAgICAgZXhwb3J0T3B0aW9ucyxcclxuICAgICAgLy8gT21pdCBnb2luZyBkb3duIHJlY3Vyc2l2ZWx5IHdpdGggdGhlIGJlbG93c1xyXG4gICAgICBhYnNvbHV0ZVByb3BzXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgb3B0aW9ucy5leHBvcnQub3V0ZmlsZSA9XHJcbiAgICBvcHRpb25zLmV4cG9ydD8ub3V0ZmlsZSB8fCBgY2hhcnQuJHtvcHRpb25zLmV4cG9ydD8udHlwZSB8fCAncG5nJ31gO1xyXG4gIHJldHVybiBvcHRpb25zO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIExvYWRzIGFkZGl0aW9uYWwgY29uZmlndXJhdGlvbiBmcm9tIGEgc3BlY2lmaWVkIGZpbGUgdXNpbmdcclxuICogdGhlIC0tbG9hZENvbmZpZyBvcHRpb24uXHJcbiAqXHJcbiAqIEBwYXJhbSB7QXJyYXl9IGFyZ3MgLSBDb21tYW5kLWxpbmUgYXJndW1lbnRzIHRvIGNoZWNrIGZvclxyXG4gKiB0aGUgLS1sb2FkQ29uZmlnIG9wdGlvbi5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gQWRkaXRpb25hbCBjb25maWd1cmF0aW9uIGxvYWRlZCBmcm9tIHRoZSBzcGVjaWZpZWQgZmlsZSxcclxuICogb3IgYW4gZW1wdHkgb2JqZWN0IGlmIG5vdCBmb3VuZCBvciBpbnZhbGlkLlxyXG4gKi9cclxuZnVuY3Rpb24gbG9hZENvbmZpZ0ZpbGUoYXJncykge1xyXG4gIC8vIENoZWNrIGlmIHRoZSAtLWxvYWRDb25maWcgb3B0aW9uIHdhcyB1c2VkXHJcbiAgY29uc3QgY29uZmlnSW5kZXggPSBhcmdzLmZpbmRJbmRleChcclxuICAgIChhcmcpID0+IGFyZy5yZXBsYWNlKC8tL2csICcnKSA9PT0gJ2xvYWRDb25maWcnXHJcbiAgKTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgdGhlIC0tbG9hZENvbmZpZyBoYXMgYSB2YWx1ZVxyXG4gIGlmIChjb25maWdJbmRleCA+IC0xICYmIGFyZ3NbY29uZmlnSW5kZXggKyAxXSkge1xyXG4gICAgY29uc3QgZmlsZU5hbWUgPSBhcmdzW2NvbmZpZ0luZGV4ICsgMV07XHJcbiAgICB0cnkge1xyXG4gICAgICAvLyBDaGVjayBpZiBhbiBhZGRpdGlvbmFsIGNvbmZpZyBmaWxlIGlzIGEgY29ycmVjdCBKU09OIGZpbGVcclxuICAgICAgaWYgKGZpbGVOYW1lICYmIGZpbGVOYW1lLmVuZHNXaXRoKCcuanNvbicpKSB7XHJcbiAgICAgICAgLy8gTG9hZCBhbiBvcHRpb25hbCBjdXN0b20gSlNPTiBjb25maWcgZmlsZVxyXG4gICAgICAgIHJldHVybiBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhmaWxlTmFtZSkpO1xyXG4gICAgICB9XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgMixcclxuICAgICAgICBlcnJvcixcclxuICAgICAgICBgW2NvbmZpZ10gVW5hYmxlIHRvIGxvYWQgdGhlIGNvbmZpZ3VyYXRpb24gZnJvbSB0aGUgJHtmaWxlTmFtZX0gZmlsZS5gXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBObyBhZGRpdGlvbmFsIG9wdGlvbnMgdG8gcmV0dXJuXHJcbiAgcmV0dXJuIHt9O1xyXG59XHJcblxyXG4vKipcclxuICogVXBkYXRlcyB0aGUgZGVmYXVsdCBjb25maWd1cmF0aW9uIG9iamVjdCB3aXRoIHZhbHVlcyBmcm9tIGEgY3VzdG9tIG9iamVjdFxyXG4gKiBhbmQgZW52aXJvbm1lbnQgdmFyaWFibGVzLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnT2JqIC0gVGhlIGRlZmF1bHQgY29uZmlndXJhdGlvbiBvYmplY3QuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjdXN0b21PYmogLSBDdXN0b20gY29uZmlndXJhdGlvbiBvYmplY3QgdG8gb3ZlcnJpZGUgZGVmYXVsdHMuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwcm9wQ2hhaW4gLSBQcm9wZXJ0eSBjaGFpbiBmb3IgdHJhY2tpbmcgbmVzdGVkIHByb3BlcnRpZXNcclxuICogZHVyaW5nIHJlY3Vyc2lvbi5cclxuICovXHJcbmZ1bmN0aW9uIHVwZGF0ZURlZmF1bHRDb25maWcoY29uZmlnT2JqLCBjdXN0b21PYmogPSB7fSwgcHJvcENoYWluID0gJycpIHtcclxuICBPYmplY3Qua2V5cyhjb25maWdPYmopLmZvckVhY2goKGtleSkgPT4ge1xyXG4gICAgY29uc3QgZW50cnkgPSBjb25maWdPYmpba2V5XTtcclxuICAgIGNvbnN0IGN1c3RvbVZhbHVlID0gY3VzdG9tT2JqICYmIGN1c3RvbU9ialtrZXldO1xyXG4gICAgbGV0IG51bUVudlZhbDtcclxuXHJcbiAgICBpZiAodHlwZW9mIGVudHJ5LnZhbHVlID09PSAndW5kZWZpbmVkJykge1xyXG4gICAgICB1cGRhdGVEZWZhdWx0Q29uZmlnKGVudHJ5LCBjdXN0b21WYWx1ZSwgYCR7cHJvcENoYWlufS4ke2tleX1gKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIElmIGEgdmFsdWUgZnJvbSBhIGN1c3RvbSBKU09OIGV4aXN0cywgaXQgdGFrZSBwcmVjZWRlbmNlXHJcbiAgICAgIGlmIChjdXN0b21WYWx1ZSAhPT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgICAgZW50cnkudmFsdWUgPSBjdXN0b21WYWx1ZTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgYSB2YWx1ZSBmcm9tIGFuIGVudiB2YXJpYWJsZSBleGlzdHMsIGl0IHRha2UgcHJlY2VkZW5jZVxyXG4gICAgICBpZiAoZW50cnkuZW52TGluaykge1xyXG4gICAgICAgIC8vIExvYWQgdGhlIGVudiB2YXJcclxuICAgICAgICBpZiAoZW50cnkudHlwZSA9PT0gJ2Jvb2xlYW4nKSB7XHJcbiAgICAgICAgICBlbnRyeS52YWx1ZSA9IHRvQm9vbGVhbihcclxuICAgICAgICAgICAgW3Byb2Nlc3MuZW52W2VudHJ5LmVudkxpbmtdLCBlbnRyeS52YWx1ZV0uZmluZChcclxuICAgICAgICAgICAgICAoZWwpID0+IGVsIHx8IGVsID09PSAnZmFsc2UnXHJcbiAgICAgICAgICAgIClcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfSBlbHNlIGlmIChlbnRyeS50eXBlID09PSAnbnVtYmVyJykge1xyXG4gICAgICAgICAgbnVtRW52VmFsID0gK3Byb2Nlc3MuZW52W2VudHJ5LmVudkxpbmtdO1xyXG4gICAgICAgICAgZW50cnkudmFsdWUgPSBudW1FbnZWYWwgPj0gMCA/IG51bUVudlZhbCA6IGVudHJ5LnZhbHVlO1xyXG4gICAgICAgIH0gZWxzZSBpZiAoZW50cnkudHlwZS5pbmRleE9mKCddJykgPj0gMCAmJiBwcm9jZXNzLmVudltlbnRyeS5lbnZMaW5rXSkge1xyXG4gICAgICAgICAgZW50cnkudmFsdWUgPSBwcm9jZXNzLmVudltlbnRyeS5lbnZMaW5rXS5zcGxpdCgnLCcpO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICBlbnRyeS52YWx1ZSA9IHByb2Nlc3MuZW52W2VudHJ5LmVudkxpbmtdIHx8IGVudHJ5LnZhbHVlO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0pO1xyXG59XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgb3B0aW9ucyBvYmplY3QgYmFzZWQgb24gcHJvdmlkZWQgaXRlbXMsIHNldHRpbmcgdmFsdWVzIGZyb21cclxuICogbmVzdGVkIHByb3BlcnRpZXMgcmVjdXJzaXZlbHkuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBpdGVtcyAtIENvbmZpZ3VyYXRpb24gaXRlbXMgdG8gYmUgdXNlZCBmb3IgaW5pdGlhbGl6aW5nXHJcbiAqIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IEluaXRpYWxpemVkIG9wdGlvbnMgb2JqZWN0LlxyXG4gKi9cclxuZnVuY3Rpb24gaW5pdE9wdGlvbnMoaXRlbXMpIHtcclxuICBsZXQgb3B0aW9ucyA9IHt9O1xyXG4gIGZvciAoY29uc3QgW25hbWUsIGl0ZW1dIG9mIE9iamVjdC5lbnRyaWVzKGl0ZW1zKSkge1xyXG4gICAgb3B0aW9uc1tuYW1lXSA9IE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChpdGVtLCAndmFsdWUnKVxyXG4gICAgICA/IGl0ZW0udmFsdWVcclxuICAgICAgOiBpbml0T3B0aW9ucyhpdGVtKTtcclxuICB9XHJcbiAgcmV0dXJuIG9wdGlvbnM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBQYWlycyBhcmd1bWVudCB2YWx1ZXMgd2l0aCBjb3JyZXNwb25kaW5nIG9wdGlvbnMgaW4gdGhlIGNvbmZpZ3VyYXRpb24sXHJcbiAqIHVwZGF0aW5nIHRoZSBvcHRpb25zIG9iamVjdC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBDb25maWd1cmF0aW9uIG9wdGlvbnMgb2JqZWN0IHRvIGJlIHVwZGF0ZWQuXHJcbiAqIEBwYXJhbSB7QXJyYXl9IGFyZ3MgLSBDb21tYW5kLWxpbmUgYXJndW1lbnRzIGNvbnRhaW5pbmcgdmFsdWVzIGZvciBzcGVjaWZpY1xyXG4gKiBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZGVmYXVsdENvbmZpZyAtIERlZmF1bHQgY29uZmlndXJhdGlvbiBvYmplY3QgZm9yIHJlZmVyZW5jZS5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVXBkYXRlZCBvcHRpb25zIG9iamVjdC5cclxuICovXHJcbmZ1bmN0aW9uIHBhaXJBcmd1bWVudFZhbHVlKG9wdGlvbnMsIGFyZ3MsIGRlZmF1bHRDb25maWcpIHtcclxuICBsZXQgc2hvd1VzYWdlID0gZmFsc2U7XHJcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBhcmdzLmxlbmd0aDsgaSsrKSB7XHJcbiAgICBjb25zdCBvcHRpb24gPSBhcmdzW2ldLnJlcGxhY2UoLy0vZywgJycpO1xyXG5cclxuICAgIC8vIEZpbmQgdGhlIHJpZ2h0IHBsYWNlIGZvciBwcm9wZXJ0eSdzIHZhbHVlXHJcbiAgICBjb25zdCBwcm9wZXJ0aWVzQ2hhaW4gPSBuZXN0ZWRBcmdzW29wdGlvbl1cclxuICAgICAgPyBuZXN0ZWRBcmdzW29wdGlvbl0uc3BsaXQoJy4nKVxyXG4gICAgICA6IFtdO1xyXG5cclxuICAgIC8vIEdldCB0aGUgY29ycmVjdCB0eXBlIGZvciBDTEkgYXJncyB3aGljaCBhcmUgcGFzc2VkIGFzIHN0cmluZ3NcclxuICAgIGxldCBhcmd1bWVudFR5cGU7XHJcbiAgICBwcm9wZXJ0aWVzQ2hhaW4ucmVkdWNlKChvYmosIHByb3AsIGluZGV4KSA9PiB7XHJcbiAgICAgIGlmIChwcm9wZXJ0aWVzQ2hhaW4ubGVuZ3RoIC0gMSA9PT0gaW5kZXgpIHtcclxuICAgICAgICBhcmd1bWVudFR5cGUgPSBvYmpbcHJvcF0udHlwZTtcclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gb2JqW3Byb3BdO1xyXG4gICAgfSwgZGVmYXVsdENvbmZpZyk7XHJcblxyXG4gICAgcHJvcGVydGllc0NoYWluLnJlZHVjZSgob2JqLCBwcm9wLCBpbmRleCkgPT4ge1xyXG4gICAgICBpZiAocHJvcGVydGllc0NoYWluLmxlbmd0aCAtIDEgPT09IGluZGV4KSB7XHJcbiAgICAgICAgLy8gRmluZHMgYW4gb3B0aW9uIGFuZCBzZXQgYSBjb3JyZXNwb25kaW5nIHZhbHVlXHJcbiAgICAgICAgaWYgKHR5cGVvZiBvYmpbcHJvcF0gIT09ICd1bmRlZmluZWQnKSB7XHJcbiAgICAgICAgICBpZiAoYXJnc1srK2ldKSB7XHJcbiAgICAgICAgICAgIGlmIChhcmd1bWVudFR5cGUgPT09ICdib29sZWFuJykge1xyXG4gICAgICAgICAgICAgIG9ialtwcm9wXSA9IHRvQm9vbGVhbihhcmdzW2ldKTtcclxuICAgICAgICAgICAgfSBlbHNlIGlmIChhcmd1bWVudFR5cGUgPT09ICdudW1iZXInKSB7XHJcbiAgICAgICAgICAgICAgb2JqW3Byb3BdID0gK2FyZ3NbaV07XHJcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoYXJndW1lbnRUeXBlLmluZGV4T2YoJ10nKSA+PSAwKSB7XHJcbiAgICAgICAgICAgICAgb2JqW3Byb3BdID0gYXJnc1tpXS5zcGxpdCgnLCcpO1xyXG4gICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgIG9ialtwcm9wXSA9IGFyZ3NbaV07XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIGxvZyhcclxuICAgICAgICAgICAgICAyLFxyXG4gICAgICAgICAgICAgIGBbY29uZmlnXSBNaXNzaW5nIHZhbHVlIGZvciB0aGUgJyR7b3B0aW9ufScgYXJndW1lbnQuIFVzaW5nIHRoZSBkZWZhdWx0IHZhbHVlLmBcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgc2hvd1VzYWdlID0gdHJ1ZTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIG9ialtwcm9wXTtcclxuICAgIH0sIG9wdGlvbnMpO1xyXG4gIH1cclxuXHJcbiAgLy8gRGlzcGxheSB0aGUgdXNhZ2UgZm9yIHRoZSByZWZlcmVuY2UgaWYgbmVlZGVkXHJcbiAgaWYgKHNob3dVc2FnZSkge1xyXG4gICAgcHJpbnRVc2FnZShkZWZhdWx0Q29uZmlnKTtcclxuICB9XHJcblxyXG4gIHJldHVybiBvcHRpb25zO1xyXG59XHJcblxyXG4vKipcclxuICogUmVjdXJzaXZlbHkgdXBkYXRlcyBwcm9wZXJ0aWVzIGluIGFuIG9iamVjdCBiYXNlZCBvbiBuZXN0ZWQgbmFtZXMgYW5kIGFzc2lnbnNcclxuICogdGhlIGZpbmFsIHZhbHVlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb2JqZWN0VG9VcGRhdGUgLSBUaGUgb2JqZWN0IHRvIGJlIHVwZGF0ZWQuXHJcbiAqIEBwYXJhbSB7QXJyYXl9IG5lc3RlZE5hbWVzIC0gQXJyYXkgb2YgbmVzdGVkIHByb3BlcnR5IG5hbWVzLlxyXG4gKiBAcGFyYW0ge2FueX0gdmFsdWUgLSBUaGUgZmluYWwgdmFsdWUgdG8gYmUgYXNzaWduZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFVwZGF0ZWQgb2JqZWN0IHdpdGggYXNzaWduZWQgdmFsdWVzLlxyXG4gKi9cclxuZnVuY3Rpb24gcmVjdXJzaXZlUHJvcHMob2JqZWN0VG9VcGRhdGUsIG5lc3RlZE5hbWVzLCB2YWx1ZSkge1xyXG4gIHdoaWxlIChuZXN0ZWROYW1lcy5sZW5ndGggPiAxKSB7XHJcbiAgICBjb25zdCBwcm9wTmFtZSA9IG5lc3RlZE5hbWVzLnNoaWZ0KCk7XHJcblxyXG4gICAgLy8gQ3JlYXRlIGEgcHJvcGVydHkgaW4gb2JqZWN0IGlmIGl0IGRvZXNuJ3QgZXhpc3RcclxuICAgIGlmICghT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9iamVjdFRvVXBkYXRlLCBwcm9wTmFtZSkpIHtcclxuICAgICAgb2JqZWN0VG9VcGRhdGVbcHJvcE5hbWVdID0ge307XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2FsbCBmdW5jdGlvbiBhZ2FpbiBpZiB0aGVyZSBzdGlsbCBuYW1lcyB0byBnb1xyXG4gICAgb2JqZWN0VG9VcGRhdGVbcHJvcE5hbWVdID0gcmVjdXJzaXZlUHJvcHMoXHJcbiAgICAgIE9iamVjdC5hc3NpZ24oe30sIG9iamVjdFRvVXBkYXRlW3Byb3BOYW1lXSksXHJcbiAgICAgIG5lc3RlZE5hbWVzLFxyXG4gICAgICB2YWx1ZVxyXG4gICAgKTtcclxuXHJcbiAgICByZXR1cm4gb2JqZWN0VG9VcGRhdGU7XHJcbiAgfVxyXG5cclxuICAvLyBBc3NpZ24gdGhlIGZpbmFsIHZhbHVlXHJcbiAgb2JqZWN0VG9VcGRhdGVbbmVzdGVkTmFtZXNbMF1dID0gdmFsdWU7XHJcbiAgcmV0dXJuIG9iamVjdFRvVXBkYXRlO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgZ2V0T3B0aW9ucyxcclxuICBzZXRPcHRpb25zLFxyXG4gIG1hbnVhbENvbmZpZyxcclxuICBtYXBUb05ld0NvbmZpZyxcclxuICBtZXJnZUNvbmZpZ09wdGlvbnMsXHJcbiAgaW5pdEV4cG9ydFNldHRpbmdzXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IGZzIGZyb20gJ2ZzJztcclxuaW1wb3J0ICogYXMgdXJsIGZyb20gJ3VybCc7XHJcbmltcG9ydCBwYXRoIGZyb20gJ25vZGU6cGF0aCc7XHJcblxyXG5pbXBvcnQgcHVwcGV0ZWVyIGZyb20gJ3B1cHBldGVlcic7XHJcblxyXG4vLyBXb3JrYXJvdW5kIGZvciBodHRwczovL2J1Z3MuY2hyb21pdW0ub3JnL3AvY2hyb21pdW0vaXNzdWVzL2RldGFpbD9pZD0xNDYzMzI4XHJcbi8vIE5vdCBpZGVhbCAtIGxlYXZlcyB0cmFzaCBpbiB0aGUgRlNcclxuaW1wb3J0IHsgcmFuZG9tQnl0ZXMgfSBmcm9tICdub2RlOmNyeXB0byc7XHJcblxyXG5pbXBvcnQgeyBnZXRDYWNoZVBhdGggfSBmcm9tICcuL2NhY2hlLmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuY29uc3QgUkFORE9NX1BJRCA9IHJhbmRvbUJ5dGVzKDY0KS50b1N0cmluZygnYmFzZTY0dXJsJyk7XHJcbmNvbnN0IFBVUFBFVEVFUl9ESVIgPSBwYXRoLmpvaW4oJ3RtcCcsIGBwdXBwZXRlZXItJHtSQU5ET01fUElEfWApO1xyXG5jb25zdCBEQVRBX0RJUiA9IHBhdGguam9pbihQVVBQRVRFRVJfRElSLCAncHJvZmlsZScpO1xyXG5cclxuLy8gVGhlIG1pbmltYWwgYXJncyB0byBzcGVlZCB1cCB0aGUgYnJvd3NlclxyXG5jb25zdCBtaW5pbWFsQXJncyA9IFtcclxuICBgLS11c2VyLWRhdGEtZGlyPSR7REFUQV9ESVJ9YCxcclxuICAnLS1hdXRvcGxheS1wb2xpY3k9dXNlci1nZXN0dXJlLXJlcXVpcmVkJyxcclxuICAnLS1kaXNhYmxlLWJhY2tncm91bmQtbmV0d29ya2luZycsXHJcbiAgJy0tZGlzYWJsZS1iYWNrZ3JvdW5kLXRpbWVyLXRocm90dGxpbmcnLFxyXG4gICctLWRpc2FibGUtYmFja2dyb3VuZGluZy1vY2NsdWRlZC13aW5kb3dzJyxcclxuICAnLS1kaXNhYmxlLWJyZWFrcGFkJyxcclxuICAnLS1kaXNhYmxlLWNsaWVudC1zaWRlLXBoaXNoaW5nLWRldGVjdGlvbicsXHJcbiAgJy0tZGlzYWJsZS1jb21wb25lbnQtdXBkYXRlJyxcclxuICAnLS1kaXNhYmxlLWRlZmF1bHQtYXBwcycsXHJcbiAgJy0tZGlzYWJsZS1kZXYtc2htLXVzYWdlJyxcclxuICAnLS1kaXNhYmxlLWRvbWFpbi1yZWxpYWJpbGl0eScsXHJcbiAgJy0tZGlzYWJsZS1leHRlbnNpb25zJyxcclxuICAnLS1kaXNhYmxlLWZlYXR1cmVzPUF1ZGlvU2VydmljZU91dE9mUHJvY2VzcycsXHJcbiAgJy0tZGlzYWJsZS1oYW5nLW1vbml0b3InLFxyXG4gICctLWRpc2FibGUtaXBjLWZsb29kaW5nLXByb3RlY3Rpb24nLFxyXG4gICctLWRpc2FibGUtbm90aWZpY2F0aW9ucycsXHJcbiAgJy0tZGlzYWJsZS1vZmZlci1zdG9yZS11bm1hc2tlZC13YWxsZXQtY2FyZHMnLFxyXG4gICctLWRpc2FibGUtcG9wdXAtYmxvY2tpbmcnLFxyXG4gICctLWRpc2FibGUtcHJpbnQtcHJldmlldycsXHJcbiAgJy0tZGlzYWJsZS1wcm9tcHQtb24tcmVwb3N0JyxcclxuICAnLS1kaXNhYmxlLXJlbmRlcmVyLWJhY2tncm91bmRpbmcnLFxyXG4gICctLWRpc2FibGUtc2Vzc2lvbi1jcmFzaGVkLWJ1YmJsZScsXHJcbiAgJy0tZGlzYWJsZS1zZXR1aWQtc2FuZGJveCcsXHJcbiAgJy0tZGlzYWJsZS1zcGVlY2gtYXBpJyxcclxuICAnLS1kaXNhYmxlLXN5bmMnLFxyXG4gICctLWhpZGUtY3Jhc2gtcmVzdG9yZS1idWJibGUnLFxyXG4gICctLWhpZGUtc2Nyb2xsYmFycycsXHJcbiAgJy0taWdub3JlLWdwdS1ibGFja2xpc3QnLFxyXG4gICctLW1ldHJpY3MtcmVjb3JkaW5nLW9ubHknLFxyXG4gICctLW11dGUtYXVkaW8nLFxyXG4gICctLW5vLWRlZmF1bHQtYnJvd3Nlci1jaGVjaycsXHJcbiAgJy0tbm8tZmlyc3QtcnVuJyxcclxuICAnLS1uby1waW5ncycsXHJcbiAgJy0tbm8tc2FuZGJveCcsXHJcbiAgJy0tbm8tenlnb3RlJyxcclxuICAnLS1wYXNzd29yZC1zdG9yZT1iYXNpYycsXHJcbiAgJy0tdXNlLW1vY2sta2V5Y2hhaW4nXHJcbl07XHJcblxyXG5jb25zdCBfX2Rpcm5hbWUgPSB1cmwuZmlsZVVSTFRvUGF0aChuZXcgVVJMKCcuJywgaW1wb3J0Lm1ldGEudXJsKSk7XHJcblxyXG5jb25zdCB0ZW1wbGF0ZSA9IGZzLnJlYWRGaWxlU3luYyhcclxuICBfX2Rpcm5hbWUgKyAnLy4uL3RlbXBsYXRlcy90ZW1wbGF0ZS5odG1sJyxcclxuICAndXRmOCdcclxuKTtcclxuXHJcbmxldCBicm93c2VyO1xyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIGNvbnRlbnQgZm9yIGEgUHVwcGV0ZWVyIFBhZ2UgdXNpbmcgYSBwcmVkZWZpbmVkIHRlbXBsYXRlXHJcbiAqIGFuZCBhZGRpdGlvbmFsIHNjcmlwdHMuIEFsc28sIHNldHMgdGhlIHBhZ2VlcnJvciBpbiBvcmRlciB0byBjYXRjaFxyXG4gKiBhbmQgZGlzcGxheSBlcnJvcnMgZnJvbSB0aGUgd2luZG93IGNvbnRleHQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gVGhlIFB1cHBldGVlciBQYWdlIG9iamVjdCBmb3Igd2hpY2ggdGhlIGNvbnRlbnRcclxuICogaXMgYmVpbmcgc2V0LlxyXG4gKi9cclxuY29uc3Qgc2V0UGFnZUNvbnRlbnQgPSBhc3luYyAocGFnZSkgPT4ge1xyXG4gIGF3YWl0IHBhZ2Uuc2V0Q29udGVudCh0ZW1wbGF0ZSk7XHJcbiAgYXdhaXQgcGFnZS5hZGRTY3JpcHRUYWcoeyBwYXRoOiBgJHtnZXRDYWNoZVBhdGgoKX0vc291cmNlcy5qc2AgfSk7XHJcbiAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgYXdhaXQgcGFnZS5ldmFsdWF0ZSgoKSA9PiB3aW5kb3cuc2V0dXBIaWdoY2hhcnRzKCkpO1xyXG5cclxuICBwYWdlLm9uKCdwYWdlZXJyb3InLCBhc3luYyAoZXJyb3IpID0+IHtcclxuICAgIC8vIFRPRE86IENvbnNpZGVyIGFkZGluZyBhIHN3aXRjaCBoZXJlIHRoYXQgdHVybnMgb24gbG9nKDApIGxvZ2dpbmdcclxuICAgIC8vIG9uIHBhZ2UgZXJyb3JzLlxyXG4gICAgYXdhaXQgcGFnZS4kZXZhbChcclxuICAgICAgJyNjb250YWluZXInLFxyXG4gICAgICAoZWxlbWVudCwgZXJyb3JNZXNzYWdlKSA9PiB7XHJcbiAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgaWYgKHdpbmRvdy5fZGlzcGxheUVycm9ycykge1xyXG4gICAgICAgICAgZWxlbWVudC5pbm5lckhUTUwgPSBlcnJvck1lc3NhZ2U7XHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICBgPGgxPkNoYXJ0IGlucHV0IGRhdGEgZXJyb3I8L2gxPiR7ZXJyb3IudG9TdHJpbmcoKX1gXHJcbiAgICApO1xyXG4gIH0pO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIENsZWFycyB0aGUgY29udGVudCBvZiBhIFB1cHBldGVlciBQYWdlIGJhc2VkIG9uIHRoZSBzcGVjaWZpZWQgbW9kZS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IHRvIGJlIGNsZWFyZWQuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gaGFyZFJlc2V0IC0gQSBmbGFnIGluZGljYXRpbmcgdGhlIHR5cGUgb2YgY2xlYXJpbmdcclxuICogdG8gYmUgcGVyZm9ybWVkLiBJZiB0cnVlLCBuYXZpZ2F0ZXMgdG8gJ2Fib3V0OmJsYW5rJyBhbmQgcmVzZXRzIGNvbnRlbnRcclxuICogYW5kIHNjcmlwdHMuIElmIGZhbHNlLCBjbGVhcnMgdGhlIGJvZHkgY29udGVudCBieSBzZXR0aW5nIGEgcHJlZGVmaW5lZCBIVE1MXHJcbiAqIHN0cnVjdHVyZS5cclxuICpcclxuICogQHRocm93cyB7RXJyb3J9IExvZ3MgdGhyb3duIGVycm9yIGlmIGNsZWFyaW5nIHRoZSBwYWdlIGNvbnRlbnQgZmFpbHMuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgY2xlYXJQYWdlID0gYXN5bmMgKHBhZ2UsIGhhcmRSZXNldCA9IGZhbHNlKSA9PiB7XHJcbiAgdHJ5IHtcclxuICAgIGlmIChoYXJkUmVzZXQpIHtcclxuICAgICAgLy8gTmF2aWdhdGUgdG8gYWJvdXQ6YmxhbmtcclxuICAgICAgYXdhaXQgcGFnZS5nb3RvKCdhYm91dDpibGFuaycpO1xyXG5cclxuICAgICAgLy8gU2V0IHRoZSBjb250ZW50IGFuZCBhbmQgc2NyaXB0cyBhZ2FpblxyXG4gICAgICBhd2FpdCBzZXRQYWdlQ29udGVudChwYWdlKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIENsZWFyIGJvZHkgY29udGVudFxyXG4gICAgICBhd2FpdCBwYWdlLmV2YWx1YXRlKCgpID0+IHtcclxuICAgICAgICBkb2N1bWVudC5ib2R5LmlubmVySFRNTCA9XHJcbiAgICAgICAgICAnPGRpdiBpZD1cImNoYXJ0LWNvbnRhaW5lclwiPjxkaXYgaWQ9XCJjb250YWluZXJcIj48L2Rpdj48L2Rpdj4nO1xyXG4gICAgICB9KTtcclxuICAgIH1cclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAyLFxyXG4gICAgICBlcnJvcixcclxuICAgICAgJ1ticm93c2VyXSBDb3VsZCBub3QgY2xlYXIgdGhlIGNvbnRlbnQgb2YgdGhlIHBhZ2UuJ1xyXG4gICAgKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhIG5ldyBQdXBwZXRlZXIgUGFnZSB3aXRoaW4gYW4gZXhpc3RpbmcgYnJvd3NlciBpbnN0YW5jZS5cclxuICpcclxuICogSWYgdGhlIGJyb3dzZXIgaW5zdGFuY2UgaXMgbm90IGF2YWlsYWJsZSwgcmV0dXJucyBmYWxzZS5cclxuICpcclxuICogVGhlIGZ1bmN0aW9uIGNyZWF0ZXMgYSBuZXcgcGFnZSwgZGlzYWJsZXMgY2FjaGluZywgc2V0cyBjb250ZW50IHVzaW5nXHJcbiAqIHNldFBhZ2VDb250ZW50KCksIGFuZCByZXR1cm5zIHRoZSBjcmVhdGVkIFB1cHBldGVlciBQYWdlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7KGJvb2xlYW58b2JqZWN0KX0gUmV0dXJucyBmYWxzZSBpZiB0aGUgYnJvd3NlciBpbnN0YW5jZSBpcyBub3RcclxuICogYXZhaWxhYmxlLCBvciBhIFB1cHBldGVlciBQYWdlIG9iamVjdCByZXByZXNlbnRpbmcgdGhlIG5ld2x5IGNyZWF0ZWQgcGFnZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBuZXdQYWdlID0gYXN5bmMgKCkgPT4ge1xyXG4gIGlmICghYnJvd3Nlcikge1xyXG4gICAgcmV0dXJuIGZhbHNlO1xyXG4gIH1cclxuXHJcbiAgY29uc3QgcGFnZSA9IGF3YWl0IGJyb3dzZXIubmV3UGFnZSgpO1xyXG5cclxuICAvLyBEaXNhYmxlIGNhY2hlXHJcbiAgYXdhaXQgcGFnZS5zZXRDYWNoZUVuYWJsZWQoZmFsc2UpO1xyXG5cclxuICAvLyBTZXQgdGhlIGNvbnRlbnRcclxuICBhd2FpdCBzZXRQYWdlQ29udGVudChwYWdlKTtcclxuICByZXR1cm4gcGFnZTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgUHVwcGV0ZWVyIGJyb3dzZXIgaW5zdGFuY2Ugd2l0aCB0aGUgc3BlY2lmaWVkIGFyZ3VtZW50cy5cclxuICpcclxuICogQHBhcmFtIHtBcnJheX0gcHVwcGV0ZWVyQXJncyAtIEFkZGl0aW9uYWwgYXJndW1lbnRzIGZvciBQdXBwZXRlZXIgbGF1bmNoLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxvYmplY3Q+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBQdXBwZXRlZXIgYnJvd3NlclxyXG4gKiBpbnN0YW5jZS5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiBtYXggcmV0cmllcyB0byBvcGVuIGEgYnJvd3NlclxyXG4gKiBpbnN0YW5jZSBhcmUgcmVhY2hlZCwgb3IgaWYgbm8gYnJvd3NlciBpbnN0YW5jZSBpcyBmb3VuZCBhZnRlciByZXRyaWVzLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGNyZWF0ZSA9IGFzeW5jIChwdXBwZXRlZXJBcmdzKSA9PiB7XHJcbiAgY29uc3QgYWxsQXJncyA9IFsuLi5taW5pbWFsQXJncywgLi4uKHB1cHBldGVlckFyZ3MgfHwgW10pXTtcclxuXHJcbiAgLy8gQ3JlYXRlIGEgYnJvd3NlclxyXG4gIGlmICghYnJvd3Nlcikge1xyXG4gICAgbGV0IHRyeUNvdW50ID0gMDtcclxuXHJcbiAgICBjb25zdCBvcGVuID0gYXN5bmMgKCkgPT4ge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW2Jyb3dzZXJdIEF0dGVtcHRpbmcgdG8gZ2V0IGEgYnJvd3NlciBpbnN0YW5jZSAodHJ5ICR7Kyt0cnlDb3VudH0pLmBcclxuICAgICAgICApO1xyXG4gICAgICAgIGJyb3dzZXIgPSBhd2FpdCBwdXBwZXRlZXIubGF1bmNoKHtcclxuICAgICAgICAgIGhlYWRsZXNzOiAnbmV3JyxcclxuICAgICAgICAgIGFyZ3M6IGFsbEFyZ3MsXHJcbiAgICAgICAgICB1c2VyRGF0YURpcjogJy4vdG1wLydcclxuICAgICAgICB9KTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgICAxLFxyXG4gICAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgICAnW2Jyb3dzZXJdIEZhaWxlZCB0byBsYXVuY2ggYSBicm93c2VyIGluc3RhbmNlLidcclxuICAgICAgICApO1xyXG5cclxuICAgICAgICAvLyBSZXRyeSB0byBsYXVuY2ggYnJvd3NlciB1bnRpbCByZWFjaGluZyBtYXggYXR0ZW1wdHNcclxuICAgICAgICBpZiAodHJ5Q291bnQgPCAyNSkge1xyXG4gICAgICAgICAgbG9nKDMsIGBbYnJvd3Nlcl0gUmV0cnkgdG8gb3BlbiBhIGJyb3dzZXIgKCR7dHJ5Q291bnR9IG91dCBvZiAyNSkuYCk7XHJcbiAgICAgICAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzcG9uc2UpID0+IHNldFRpbWVvdXQocmVzcG9uc2UsIDQwMDApKTtcclxuICAgICAgICAgIGF3YWl0IG9wZW4oKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9O1xyXG5cclxuICAgIHRyeSB7XHJcbiAgICAgIGF3YWl0IG9wZW4oKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnW2Jyb3dzZXJdIE1heGltdW0gcmV0cmllcyB0byBvcGVuIGEgYnJvd3NlciBpbnN0YW5jZSByZWFjaGVkLidcclxuICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKCFicm93c2VyKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW2Jyb3dzZXJdIENhbm5vdCBmaW5kIGEgYnJvd3NlciB0byBvcGVuLicpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIGEgYnJvd3NlciBwcm9taXNlXHJcbiAgcmV0dXJuIGJyb3dzZXI7XHJcbn07XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHRoZSBleGlzdGluZyBQdXBwZXRlZXIgYnJvd3NlciBpbnN0YW5jZS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8b2JqZWN0Pn0gQSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgUHVwcGV0ZWVyIGJyb3dzZXJcclxuICogaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgbm8gdmFsaWQgYnJvd3NlciBoYXMgYmVlblxyXG4gKiBjcmVhdGVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldCA9IGFzeW5jICgpID0+IHtcclxuICBpZiAoIWJyb3dzZXIpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW2Jyb3dzZXJdIE5vIHZhbGlkIGJyb3dzZXIgaGFzIGJlZW4gY3JlYXRlZC4nKTtcclxuICB9XHJcblxyXG4gIHJldHVybiBicm93c2VyO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIENsb3NlcyB0aGUgUHVwcGV0ZWVyIGJyb3dzZXIgaW5zdGFuY2UgaWYgaXQgaXMgY29ubmVjdGVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxib29sZWFuPn0gQSBQcm9taXNlIHJlc29sdmluZyB0byB0cnVlIGFmdGVyIHRoZSBicm93c2VyXHJcbiAqIGlzIGNsb3NlZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBjbG9zZSA9IGFzeW5jICgpID0+IHtcclxuICAvLyBDbG9zZSB0aGUgYnJvd3NlciB3aGVuIGNvbm5uZWN0ZWRcclxuICBpZiAoYnJvd3Nlcj8uaXNDb25uZWN0ZWQoKSkge1xyXG4gICAgYXdhaXQgYnJvd3Nlci5jbG9zZSgpO1xyXG4gICAgbG9nKDQsICdbYnJvd3Nlcl0gQ2xvc2VkIHRoZSBicm93c2VyLicpO1xyXG4gIH1cclxuICByZXR1cm4gdHJ1ZTtcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBuZXdQYWdlLFxyXG4gIGNsZWFyUGFnZSxcclxuICBnZXQsXHJcbiAgY2xvc2VcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCBwYXRoIGZyb20gJ3BhdGgnO1xyXG5pbXBvcnQgKiBhcyB1cmwgZnJvbSAndXJsJztcclxuXHJcbmltcG9ydCBjYWNoZSBmcm9tICcuL2NhY2hlLmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCBzdmdUZW1wbGF0ZSBmcm9tICcuLy4uL3RlbXBsYXRlcy9zdmdfZXhwb3J0L3N2Z19leHBvcnQuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbmNvbnN0IF9fYmFzZWRpciA9IHVybC5maWxlVVJMVG9QYXRoKG5ldyBVUkwoJy4nLCBpbXBvcnQubWV0YS51cmwpKTtcclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgdGhlIGNsaXBwaW5nIHJlZ2lvbiBjb29yZGluYXRlcyBvZiB0aGUgc3BlY2lmaWVkIHBhZ2UgZWxlbWVudCB3aXRoXHJcbiAqIHRoZSBpZCAnY2hhcnQtY29udGFpbmVyJy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IFByb21pc2UgcmVzb2x2aW5nIHRvIGFuIG9iamVjdCBjb250YWluaW5nXHJcbiAqIHgsIHksIHdpZHRoLCBhbmQgaGVpZ2h0IHByb3BlcnRpZXMuXHJcbiAqL1xyXG5jb25zdCBnZXRDbGlwUmVnaW9uID0gKHBhZ2UpID0+XHJcbiAgcGFnZS4kZXZhbCgnI2NoYXJ0LWNvbnRhaW5lcicsIChlbGVtZW50KSA9PiB7XHJcbiAgICBjb25zdCB7IHgsIHksIHdpZHRoLCBoZWlnaHQgfSA9IGVsZW1lbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XHJcbiAgICByZXR1cm4ge1xyXG4gICAgICB4LFxyXG4gICAgICB5LFxyXG4gICAgICB3aWR0aCxcclxuICAgICAgaGVpZ2h0OiBNYXRoLnRydW5jKGhlaWdodCA+IDEgPyBoZWlnaHQgOiA1MDApXHJcbiAgICB9O1xyXG4gIH0pO1xyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYW4gaW1hZ2UgdXNpbmcgUHVwcGV0ZWVyJ3MgcGFnZSBzY3JlZW5zaG90IGZ1bmN0aW9uYWxpdHkgd2l0aFxyXG4gKiBzcGVjaWZpZWQgb3B0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIC0gSW1hZ2UgdHlwZS5cclxuICogQHBhcmFtIHtzdHJpbmd9IGVuY29kaW5nIC0gSW1hZ2UgZW5jb2RpbmcuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjbGlwIC0gQ2xpcHBpbmcgcmVnaW9uIGNvb3JkaW5hdGVzLlxyXG4gKiBAcGFyYW0ge251bWJlcn0gcmFzdGVyaXphdGlvblRpbWVvdXQgLSBUaW1lb3V0IGZvciByYXN0ZXJpemF0aW9uXHJcbiAqIGluIG1pbGxpc2Vjb25kcy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8QnVmZmVyPn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIGltYWdlIGJ1ZmZlciBvciByZWplY3RpbmdcclxuICogd2l0aCBhbiBFeHBvcnRFcnJvciBmb3IgdGltZW91dC5cclxuICovXHJcbmNvbnN0IGNyZWF0ZUltYWdlID0gKHBhZ2UsIHR5cGUsIGVuY29kaW5nLCBjbGlwLCByYXN0ZXJpemF0aW9uVGltZW91dCkgPT5cclxuICBQcm9taXNlLnJhY2UoW1xyXG4gICAgcGFnZS5zY3JlZW5zaG90KHtcclxuICAgICAgdHlwZSxcclxuICAgICAgZW5jb2RpbmcsXHJcbiAgICAgIGNsaXAsXHJcblxyXG4gICAgICAvLyAjNDQ3LCAjNDYzIC0gYWx3YXlzIHJlbmRlciBvbiBhIHRyYW5zcGFyZW50IHBhZ2UgaWYgdGhlIGV4cGVjdGVkIHR5cGVcclxuICAgICAgLy8gZm9ybWF0IGlzIFBOR1xyXG4gICAgICBvbWl0QmFja2dyb3VuZDogdHlwZSA9PSAncG5nJ1xyXG4gICAgfSksXHJcbiAgICBuZXcgUHJvbWlzZSgoX3Jlc29sdmUsIHJlamVjdCkgPT5cclxuICAgICAgc2V0VGltZW91dChcclxuICAgICAgICAoKSA9PiByZWplY3QobmV3IEV4cG9ydEVycm9yKCdSYXN0ZXJpemF0aW9uIHRpbWVvdXQnKSksXHJcbiAgICAgICAgcmFzdGVyaXphdGlvblRpbWVvdXQgfHwgMTUwMFxyXG4gICAgICApXHJcbiAgICApXHJcbiAgXSk7XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhIFBERiB1c2luZyBQdXBwZXRlZXIncyBwYWdlIHBkZiBmdW5jdGlvbmFsaXR5IHdpdGggc3BlY2lmaWVkXHJcbiAqIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge251bWJlcn0gaGVpZ2h0IC0gUERGIGhlaWdodC5cclxuICogQHBhcmFtIHtudW1iZXJ9IHdpZHRoIC0gUERGIHdpZHRoLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gZW5jb2RpbmcgLSBQREYgZW5jb2RpbmcuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPEJ1ZmZlcj59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBQREYgYnVmZmVyLlxyXG4gKi9cclxuY29uc3QgY3JlYXRlUERGID0gKHBhZ2UsIGhlaWdodCwgd2lkdGgsIGVuY29kaW5nKSA9PlxyXG4gIHBhZ2UucGRmKHtcclxuICAgIC8vIFRoaXMgd2lsbCByZW1vdmUgYW4gZXh0cmEgZW1wdHkgcGFnZSBpbiBQREYgZXhwb3J0c1xyXG4gICAgaGVpZ2h0OiBoZWlnaHQgKyAxLFxyXG4gICAgd2lkdGgsXHJcbiAgICBlbmNvZGluZ1xyXG4gIH0pO1xyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYW4gU1ZHIHN0cmluZyBieSBldmFsdWF0aW5nIHRoZSBvdXRlckhUTUwgb2YgdGhlIGZpcnN0ICdzdmcnIGVsZW1lbnRcclxuICogaW5zaWRlIGFuIGVsZW1lbnQgd2l0aCB0aGUgaWQgJ2NvbnRhaW5lcicuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgU1ZHIHN0cmluZy5cclxuICovXHJcbmNvbnN0IGNyZWF0ZVNWRyA9IChwYWdlKSA9PlxyXG4gIHBhZ2UuJGV2YWwoJyNjb250YWluZXIgc3ZnOmZpcnN0LW9mLXR5cGUnLCAoZWxlbWVudCkgPT4gZWxlbWVudC5vdXRlckhUTUwpO1xyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIHNwZWNpZmllZCBjaGFydCBhbmQgb3B0aW9ucyBhcyBjb25maWd1cmF0aW9uIGludG8gdGhlIHRyaWdnZXJFeHBvcnRcclxuICogZnVuY3Rpb24gd2l0aGluIHRoZSB3aW5kb3cgY29udGV4dCB1c2luZyBwYWdlLmV2YWx1YXRlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICogQHBhcmFtIHthbnl9IGNoYXJ0IC0gVGhlIGNoYXJ0IG9iamVjdCB0byBiZSBjb25maWd1cmVkLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIENvbmZpZ3VyYXRpb24gb3B0aW9ucyBmb3IgdGhlIGNoYXJ0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gUHJvbWlzZSByZXNvbHZpbmcgYWZ0ZXIgdGhlIGNvbmZpZ3VyYXRpb24gaXMgc2V0LlxyXG4gKi9cclxuY29uc3Qgc2V0QXNDb25maWcgPSAocGFnZSwgY2hhcnQsIG9wdGlvbnMpID0+XHJcbiAgcGFnZS5ldmFsdWF0ZShcclxuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgKGNoYXJ0LCBvcHRpb25zKSA9PiB3aW5kb3cudHJpZ2dlckV4cG9ydChjaGFydCwgb3B0aW9ucyksXHJcbiAgICBjaGFydCxcclxuICAgIG9wdGlvbnNcclxuICApO1xyXG5cclxuLyoqXHJcbiAqIEV4cG9ydHMgdG8gYSBjaGFydCBmcm9tIGEgcGFnZSB1c2luZyBQdXBwZXRlZXIuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge2FueX0gY2hhcnQgLSBUaGUgY2hhcnQgb2JqZWN0IG9yIFNWRyBjb25maWd1cmF0aW9uIHRvIGJlIGV4cG9ydGVkLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIEV4cG9ydCBvcHRpb25zIGFuZCBjb25maWd1cmF0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmcgfCBCdWZmZXIgfCBFeHBvcnRFcnJvcj59IFByb21pc2UgcmVzb2x2aW5nIHRvXHJcbiAqIHRoZSBleHBvcnRlZCBkYXRhIG9yIHJlamVjdGluZyB3aXRoIGFuIEV4cG9ydEVycm9yLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgYXN5bmMgKHBhZ2UsIGNoYXJ0LCBvcHRpb25zKSA9PiB7XHJcbiAgLyoqXHJcbiAgICogS2VlcHMgdHJhY2sgb2YgYWxsIHJlc291cmNlcyBhZGRlZCBvbiB0aGUgcGFnZSB3aXRoIGFkZFhYWFRhZy4gZXRjXHJcbiAgICogSXQncyBWSVRBTCB0aGF0IGFsbCBhZGRlZCByZXNvdXJjZXMgZW5kcyB1cCBoZXJlIHNvIHdlIGNhbiBjbGVhciB0aGluZ3NcclxuICAgKiBvdXQgd2hlbiBkb2luZyBhIG5ldyBleHBvcnQgaW4gdGhlIHNhbWUgcGFnZSFcclxuICAgKi9cclxuICBjb25zdCBpbmplY3RlZFJlc291cmNlcyA9IFtdO1xyXG5cclxuICAvKiogQ2xlYXIgb3V0IGFsbCBzdGF0ZSBzZXQgb24gdGhlIHBhZ2Ugd2l0aCBhZGRTY3JpcHRUYWcvYWRkU3R5bGVUYWcuICovXHJcbiAgY29uc3QgY2xlYXJJbmplY3RlZCA9IGFzeW5jIChwYWdlKSA9PiB7XHJcbiAgICBmb3IgKGNvbnN0IHJlcyBvZiBpbmplY3RlZFJlc291cmNlcykge1xyXG4gICAgICBhd2FpdCByZXMuZGlzcG9zZSgpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFJlc2V0IGFsbCBDU1MgYW5kIHNjcmlwdCB0YWdzXHJcbiAgICBhd2FpdCBwYWdlLmV2YWx1YXRlKCgpID0+IHtcclxuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgIGNvbnN0IFssIC4uLnNjcmlwdHNUb1JlbW92ZV0gPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnc2NyaXB0Jyk7XHJcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICBjb25zdCBbLCAuLi5zdHlsZXNUb1JlbW92ZV0gPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnc3R5bGUnKTtcclxuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgIGNvbnN0IFsuLi5saW5rc1RvUmVtb3ZlXSA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdsaW5rJyk7XHJcblxyXG4gICAgICAvLyBSZW1vdmUgdGFnc1xyXG4gICAgICBmb3IgKGNvbnN0IGVsZW1lbnQgb2YgW1xyXG4gICAgICAgIC4uLnNjcmlwdHNUb1JlbW92ZSxcclxuICAgICAgICAuLi5zdHlsZXNUb1JlbW92ZSxcclxuICAgICAgICAuLi5saW5rc1RvUmVtb3ZlXHJcbiAgICAgIF0pIHtcclxuICAgICAgICBlbGVtZW50LnJlbW92ZSgpO1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuICB9O1xyXG5cclxuICB0cnkge1xyXG4gICAgbG9nKDQsICdbZXhwb3J0XSBEZXRlcm1pbmluZyBleHBvcnQgcGF0aC4nKTtcclxuXHJcbiAgICBjb25zdCBleHBvcnRPcHRpb25zID0gb3B0aW9ucy5leHBvcnQ7XHJcblxyXG4gICAgLy8gRm9yY2UgYSByQUZcclxuICAgIC8vIFNlZSBodHRwczovL2dpdGh1Yi5jb20vcHVwcGV0ZWVyL3B1cHBldGVlci9pc3N1ZXMvNzUwN1xyXG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICBhd2FpdCBwYWdlLmV2YWx1YXRlKCgpID0+IHJlcXVlc3RBbmltYXRpb25GcmFtZSgoKSA9PiB7fSkpO1xyXG5cclxuICAgIC8vIERlY2lkZSB3aGV0aGVyIGRpc3BsYXkgZXJyb3Igb3IgZGViYnVnZXIgd3JhcHBlciBhcm91bmQgaXRcclxuICAgIGNvbnN0IGRpc3BsYXlFcnJvcnMgPVxyXG4gICAgICBleHBvcnRPcHRpb25zPy5vcHRpb25zPy5jaGFydD8uZGlzcGxheUVycm9ycyAmJlxyXG4gICAgICBjYWNoZS5nZXRDYWNoZSgpLmFjdGl2ZU1hbmlmZXN0Lm1vZHVsZXMuZGVidWdnZXI7XHJcblxyXG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICBhd2FpdCBwYWdlLmV2YWx1YXRlKChkKSA9PiAod2luZG93Ll9kaXNwbGF5RXJyb3JzID0gZCksIGRpc3BsYXlFcnJvcnMpO1xyXG5cclxuICAgIGxldCBpc1NWRztcclxuICAgIGlmIChcclxuICAgICAgY2hhcnQuaW5kZXhPZiAmJlxyXG4gICAgICAoY2hhcnQuaW5kZXhPZignPHN2ZycpID49IDAgfHwgY2hhcnQuaW5kZXhPZignPD94bWwnKSA+PSAwKVxyXG4gICAgKSB7XHJcbiAgICAgIC8vIFNWRyBpbnB1dCBoYW5kbGluZ1xyXG4gICAgICBsb2coNCwgJ1tleHBvcnRdIFRyZWF0aW5nIGFzIFNWRy4nKTtcclxuXHJcbiAgICAgIC8vIElmIGlucHV0IGlzIGFsc28gU1ZHLCBqdXN0IHJldHVybiBpdFxyXG4gICAgICBpZiAoZXhwb3J0T3B0aW9ucy50eXBlID09PSAnc3ZnJykge1xyXG4gICAgICAgIHJldHVybiBjaGFydDtcclxuICAgICAgfVxyXG5cclxuICAgICAgaXNTVkcgPSB0cnVlO1xyXG4gICAgICBhd2FpdCBwYWdlLnNldENvbnRlbnQoc3ZnVGVtcGxhdGUoY2hhcnQpKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIEpTT04gY29uZmlnIGhhbmRsaW5nXHJcbiAgICAgIGxvZyg0LCAnW2V4cG9ydF0gVHJlYXRpbmcgYXMgY29uZmlnLicpO1xyXG5cclxuICAgICAgLy8gTmVlZCB0byBwZXJmb3JtIHN0cmFpZ2h0IGluamVjdFxyXG4gICAgICBpZiAoZXhwb3J0T3B0aW9ucy5zdHJJbmopIHtcclxuICAgICAgICAvLyBJbmplY3Rpb24gYmFzZWQgY29uZmlndXJhdGlvbiBleHBvcnRcclxuICAgICAgICBhd2FpdCBzZXRBc0NvbmZpZyhcclxuICAgICAgICAgIHBhZ2UsXHJcbiAgICAgICAgICB7XHJcbiAgICAgICAgICAgIGNoYXJ0OiB7XHJcbiAgICAgICAgICAgICAgaGVpZ2h0OiBleHBvcnRPcHRpb25zLmhlaWdodCxcclxuICAgICAgICAgICAgICB3aWR0aDogZXhwb3J0T3B0aW9ucy53aWR0aFxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9LFxyXG4gICAgICAgICAgb3B0aW9uc1xyXG4gICAgICAgICk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgLy8gQmFzaWMgY29uZmlndXJhdGlvbiBleHBvcnRcclxuICAgICAgICBjaGFydC5jaGFydC5oZWlnaHQgPSBleHBvcnRPcHRpb25zLmhlaWdodDtcclxuICAgICAgICBjaGFydC5jaGFydC53aWR0aCA9IGV4cG9ydE9wdGlvbnMud2lkdGg7XHJcblxyXG4gICAgICAgIGF3YWl0IHNldEFzQ29uZmlnKHBhZ2UsIGNoYXJ0LCBvcHRpb25zKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIFVzZSByZXNvdXJjZXNcclxuICAgIGNvbnN0IHJlc291cmNlcyA9IG9wdGlvbnMuY3VzdG9tTG9naWMucmVzb3VyY2VzO1xyXG4gICAgaWYgKHJlc291cmNlcykge1xyXG4gICAgICAvLyBMb2FkIGN1c3RvbSBKUyBjb2RlXHJcbiAgICAgIGlmIChyZXNvdXJjZXMuanMpIHtcclxuICAgICAgICBpbmplY3RlZFJlc291cmNlcy5wdXNoKFxyXG4gICAgICAgICAgYXdhaXQgcGFnZS5hZGRTY3JpcHRUYWcoe1xyXG4gICAgICAgICAgICBjb250ZW50OiByZXNvdXJjZXMuanNcclxuICAgICAgICAgIH0pXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gTG9hZCBzY3JpcHRzIGZyb20gYWxsIGN1c3RvbSBmaWxlc1xyXG4gICAgICBpZiAocmVzb3VyY2VzLmZpbGVzKSB7XHJcbiAgICAgICAgZm9yIChjb25zdCBmaWxlIG9mIHJlc291cmNlcy5maWxlcykge1xyXG4gICAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgY29uc3QgaXNMb2NhbCA9ICFmaWxlLnN0YXJ0c1dpdGgoJ2h0dHAnKSA/IHRydWUgOiBmYWxzZTtcclxuXHJcbiAgICAgICAgICAgIC8vIEFkZCBlYWNoIGN1c3RvbSBzY3JpcHQgZnJvbSByZXNvdXJjZXMnIGZpbGVzXHJcbiAgICAgICAgICAgIGluamVjdGVkUmVzb3VyY2VzLnB1c2goXHJcbiAgICAgICAgICAgICAgYXdhaXQgcGFnZS5hZGRTY3JpcHRUYWcoXHJcbiAgICAgICAgICAgICAgICBpc0xvY2FsXHJcbiAgICAgICAgICAgICAgICAgID8ge1xyXG4gICAgICAgICAgICAgICAgICAgICAgY29udGVudDogcmVhZEZpbGVTeW5jKGZpbGUsICd1dGY4JylcclxuICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgIDoge1xyXG4gICAgICAgICAgICAgICAgICAgICAgdXJsOiBmaWxlXHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgIClcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAgICAgICAyLFxyXG4gICAgICAgICAgICAgIGVycm9yLFxyXG4gICAgICAgICAgICAgIGBbZXhwb3J0XSBUaGUgSlMgZmlsZSAke2ZpbGV9IGNhbm5vdCBiZSBsb2FkZWQuYFxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gTG9hZCBDU1NcclxuICAgICAgaWYgKHJlc291cmNlcy5jc3MpIHtcclxuICAgICAgICBsZXQgY3NzSW1wb3J0cyA9IHJlc291cmNlcy5jc3MubWF0Y2goL0BpbXBvcnRcXHMqKFteO10qKTsvZyk7XHJcbiAgICAgICAgaWYgKGNzc0ltcG9ydHMpIHtcclxuICAgICAgICAgIC8vIEhhbmRsZSBjc3Mgc2VjdGlvblxyXG4gICAgICAgICAgZm9yIChsZXQgY3NzSW1wb3J0UGF0aCBvZiBjc3NJbXBvcnRzKSB7XHJcbiAgICAgICAgICAgIGlmIChjc3NJbXBvcnRQYXRoKSB7XHJcbiAgICAgICAgICAgICAgY3NzSW1wb3J0UGF0aCA9IGNzc0ltcG9ydFBhdGhcclxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKCd1cmwoJywgJycpXHJcbiAgICAgICAgICAgICAgICAucmVwbGFjZSgnQGltcG9ydCcsICcnKVxyXG4gICAgICAgICAgICAgICAgLnJlcGxhY2UoL1wiL2csICcnKVxyXG4gICAgICAgICAgICAgICAgLnJlcGxhY2UoLycvZywgJycpXHJcbiAgICAgICAgICAgICAgICAucmVwbGFjZSgvOy8sICcnKVxyXG4gICAgICAgICAgICAgICAgLnJlcGxhY2UoL1xcKS9nLCAnJylcclxuICAgICAgICAgICAgICAgIC50cmltKCk7XHJcblxyXG4gICAgICAgICAgICAgIC8vIEFkZCBlYWNoIGN1c3RvbSBjc3MgZnJvbSByZXNvdXJjZXNcclxuICAgICAgICAgICAgICBpZiAoY3NzSW1wb3J0UGF0aC5zdGFydHNXaXRoKCdodHRwJykpIHtcclxuICAgICAgICAgICAgICAgIGluamVjdGVkUmVzb3VyY2VzLnB1c2goXHJcbiAgICAgICAgICAgICAgICAgIGF3YWl0IHBhZ2UuYWRkU3R5bGVUYWcoe1xyXG4gICAgICAgICAgICAgICAgICAgIHVybDogY3NzSW1wb3J0UGF0aFxyXG4gICAgICAgICAgICAgICAgICB9KVxyXG4gICAgICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgICB9IGVsc2UgaWYgKG9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dGaWxlUmVzb3VyY2VzKSB7XHJcbiAgICAgICAgICAgICAgICBpbmplY3RlZFJlc291cmNlcy5wdXNoKFxyXG4gICAgICAgICAgICAgICAgICBhd2FpdCBwYWdlLmFkZFN0eWxlVGFnKHtcclxuICAgICAgICAgICAgICAgICAgICBwYXRoOiBwYXRoLmpvaW4oX19iYXNlZGlyLCBjc3NJbXBvcnRQYXRoKVxyXG4gICAgICAgICAgICAgICAgICB9KVxyXG4gICAgICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIFRoZSByZXN0IG9mIHRoZSBDU1Mgc2VjdGlvbiB3aWxsIGJlIGNvbnRlbnQgYnkgbm93XHJcbiAgICAgICAgaW5qZWN0ZWRSZXNvdXJjZXMucHVzaChcclxuICAgICAgICAgIGF3YWl0IHBhZ2UuYWRkU3R5bGVUYWcoe1xyXG4gICAgICAgICAgICBjb250ZW50OiByZXNvdXJjZXMuY3NzLnJlcGxhY2UoL0BpbXBvcnRcXHMqKFteO10qKTsvZywgJycpIHx8ICcgJ1xyXG4gICAgICAgICAgfSlcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gR2V0IHRoZSByZWFsIGNoYXJ0IHNpemVcclxuICAgIGNvbnN0IHNpemUgPSBpc1NWR1xyXG4gICAgICA/IGF3YWl0IHBhZ2UuJGV2YWwoXHJcbiAgICAgICAgICAnI2NoYXJ0LWNvbnRhaW5lciBzdmc6Zmlyc3Qtb2YtdHlwZScsXHJcbiAgICAgICAgICAoZWxlbWVudCwgc2NhbGUpID0+ICh7XHJcbiAgICAgICAgICAgIGNoYXJ0SGVpZ2h0OiBlbGVtZW50LmhlaWdodC5iYXNlVmFsLnZhbHVlICogc2NhbGUsXHJcbiAgICAgICAgICAgIGNoYXJ0V2lkdGg6IGVsZW1lbnQud2lkdGguYmFzZVZhbC52YWx1ZSAqIHNjYWxlXHJcbiAgICAgICAgICB9KSxcclxuICAgICAgICAgIHBhcnNlRmxvYXQoZXhwb3J0T3B0aW9ucy5zY2FsZSlcclxuICAgICAgICApXHJcbiAgICAgIDogYXdhaXQgcGFnZS5ldmFsdWF0ZSgoKSA9PiB7XHJcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgIGNvbnN0IHsgY2hhcnRIZWlnaHQsIGNoYXJ0V2lkdGggfSA9IHdpbmRvdy5IaWdoY2hhcnRzLmNoYXJ0c1swXTtcclxuICAgICAgICAgIHJldHVybiB7XHJcbiAgICAgICAgICAgIGNoYXJ0SGVpZ2h0LFxyXG4gICAgICAgICAgICBjaGFydFdpZHRoXHJcbiAgICAgICAgICB9O1xyXG4gICAgICAgIH0pO1xyXG5cclxuICAgIC8vIFNldCBmaW5hbCBoZWlnaHQgYW5kIHdpZHRoIGZvciB2aWV3cG9ydFxyXG4gICAgY29uc3Qgdmlld3BvcnRIZWlnaHQgPSBNYXRoLmNlaWwoc2l6ZT8uY2hhcnRIZWlnaHQgfHwgZXhwb3J0T3B0aW9ucy5oZWlnaHQpO1xyXG4gICAgY29uc3Qgdmlld3BvcnRXaWR0aCA9IE1hdGguY2VpbChzaXplPy5jaGFydFdpZHRoIHx8IGV4cG9ydE9wdGlvbnMud2lkdGgpO1xyXG5cclxuICAgIC8vIFNldCB0aGUgdmlld3BvcnQgZm9yIHRoZSBmaXJzdCB0aW1lXHJcbiAgICAvLyBOT1RFOiB0aGUgY2FsbCB0byBzZXRWaWV3cG9ydCBpcyBleHBlbnNpdmUgLSBjYW4gd2UgZ2V0IGF3YXkgd2l0aCBvbmx5XHJcbiAgICAvLyBjYWxsaW5nIGl0IG9uY2UsIGUuZy4gbW92aW5nIHRoaXMgb25lIGludG8gdGhlIGlzU1ZHIGNvbmRpdGlvbiBiZWxvdz9cclxuICAgIGF3YWl0IHBhZ2Uuc2V0Vmlld3BvcnQoe1xyXG4gICAgICBoZWlnaHQ6IHZpZXdwb3J0SGVpZ2h0LFxyXG4gICAgICB3aWR0aDogdmlld3BvcnRXaWR0aCxcclxuICAgICAgZGV2aWNlU2NhbGVGYWN0b3I6IGlzU1ZHID8gMSA6IHBhcnNlRmxvYXQoZXhwb3J0T3B0aW9ucy5zY2FsZSlcclxuICAgIH0pO1xyXG5cclxuICAgIC8vIFByZXBhcmUgYSB6b29tIGNhbGxiYWNrIGZvciB0aGUgbmV4dCBldmFsdWF0ZSBjYWxsXHJcbiAgICBjb25zdCB6b29tQ2FsbGJhY2sgPSBpc1NWR1xyXG4gICAgICA/IC8vIEluIGNhc2Ugb2YgU1ZHIHRoZSB6b29tIG11c3QgYmUgc2V0IGRpcmVjdGx5IGZvciBib2R5XHJcbiAgICAgICAgKHNjYWxlKSA9PiB7XHJcbiAgICAgICAgICAvLyBTZXQgdGhlIHpvb20gYXMgc2NhbGVcclxuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgICAgZG9jdW1lbnQuYm9keS5zdHlsZS56b29tID0gc2NhbGU7XHJcblxyXG4gICAgICAgICAgLy8gU2V0IHRoZSBtYXJnaW4gdG8gMHB4XHJcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUubWFyZ2luID0gJzBweCc7XHJcbiAgICAgICAgfVxyXG4gICAgICA6IC8vIE5vIG5lZWQgZm9yIHN1Y2ggc2NhbGUgbWFuaXB1bGF0aW9uIGluIGNhc2Ugb2Ygb3RoZXIgdHlwZXMgb2YgZXhwb3J0c1xyXG4gICAgICAgICgpID0+IHtcclxuICAgICAgICAgIC8vIFJlc2V0IHRoZSB6b29tIGZvciBvdGhlciBleHBvcnRzIHRoYW4gdG8gU1ZHc1xyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLnpvb20gPSAxO1xyXG4gICAgICAgIH07XHJcblxyXG4gICAgLy8gU2V0IHRoZSB6b29tIGFjY29yZGluZ2x5XHJcbiAgICBhd2FpdCBwYWdlLmV2YWx1YXRlKHpvb21DYWxsYmFjaywgcGFyc2VGbG9hdChleHBvcnRPcHRpb25zLnNjYWxlKSk7XHJcblxyXG4gICAgLy8gR2V0IHRoZSBjbGlwIHJlZ2lvbiBmb3IgdGhlIHBhZ2VcclxuICAgIGNvbnN0IHsgaGVpZ2h0LCB3aWR0aCwgeCwgeSB9ID0gYXdhaXQgZ2V0Q2xpcFJlZ2lvbihwYWdlKTtcclxuXHJcbiAgICBpZiAoIWlzU1ZHKSB7XHJcbiAgICAgIC8vIFNldCB0aGUgZmluYWwgdmlld3BvcnQgbm93IHRoYXQgd2UgaGF2ZSB0aGUgcmVhbCBoZWlnaHRcclxuICAgICAgYXdhaXQgcGFnZS5zZXRWaWV3cG9ydCh7XHJcbiAgICAgICAgd2lkdGg6IE1hdGgucm91bmQod2lkdGgpLFxyXG4gICAgICAgIGhlaWdodDogTWF0aC5yb3VuZChoZWlnaHQpLFxyXG4gICAgICAgIGRldmljZVNjYWxlRmFjdG9yOiBwYXJzZUZsb2F0KGV4cG9ydE9wdGlvbnMuc2NhbGUpXHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIGxldCBkYXRhO1xyXG4gICAgLy8gUkFTVEVSSVpBVElPTlxyXG4gICAgaWYgKGV4cG9ydE9wdGlvbnMudHlwZSA9PT0gJ3N2ZycpIHtcclxuICAgICAgLy8gU1ZHXHJcbiAgICAgIGRhdGEgPSBhd2FpdCBjcmVhdGVTVkcocGFnZSk7XHJcbiAgICB9IGVsc2UgaWYgKGV4cG9ydE9wdGlvbnMudHlwZSA9PT0gJ3BuZycgfHwgZXhwb3J0T3B0aW9ucy50eXBlID09PSAnanBlZycpIHtcclxuICAgICAgLy8gUE5HIG9yIEpQRUdcclxuICAgICAgZGF0YSA9IGF3YWl0IGNyZWF0ZUltYWdlKFxyXG4gICAgICAgIHBhZ2UsXHJcbiAgICAgICAgZXhwb3J0T3B0aW9ucy50eXBlLFxyXG4gICAgICAgICdiYXNlNjQnLFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIHdpZHRoOiB2aWV3cG9ydFdpZHRoLFxyXG4gICAgICAgICAgaGVpZ2h0OiB2aWV3cG9ydEhlaWdodCxcclxuICAgICAgICAgIHgsXHJcbiAgICAgICAgICB5XHJcbiAgICAgICAgfSxcclxuICAgICAgICBleHBvcnRPcHRpb25zLnJhc3Rlcml6YXRpb25UaW1lb3V0XHJcbiAgICAgICk7XHJcbiAgICB9IGVsc2UgaWYgKGV4cG9ydE9wdGlvbnMudHlwZSA9PT0gJ3BkZicpIHtcclxuICAgICAgLy8gUERGXHJcbiAgICAgIGRhdGEgPSBhd2FpdCBjcmVhdGVQREYocGFnZSwgdmlld3BvcnRIZWlnaHQsIHZpZXdwb3J0V2lkdGgsICdiYXNlNjQnKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICBgW2V4cG9ydF0gVW5zdXBwb3J0ZWQgb3V0cHV0IGZvcm1hdCAke2V4cG9ydE9wdGlvbnMudHlwZX0uYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIERlc3Ryb3kgb2xkIGNoYXJ0cyBhZnRlciB0aGUgZXhwb3J0IGlzIGRvbmVcclxuICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xyXG4gICAgICAvLyBXZSBhcmUgbm90IGd1YXJhbnRlZWQgdGhhdCBIaWdoY2hhcnRzIGlzIGxvYWRlZCwgZSxnLCB3aGVuIGRvaW5nIFNWR1xyXG4gICAgICAvLyBleHBvcnRzXHJcbiAgICAgIGlmICh0eXBlb2YgSGlnaGNoYXJ0cyAhPT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICBjb25zdCBvbGRDaGFydHMgPSBIaWdoY2hhcnRzLmNoYXJ0cztcclxuXHJcbiAgICAgICAgLy8gQ2hlY2sgaW4gYW55IGFscmVhZHkgZXhpc3RpbmcgY2hhcnRzXHJcbiAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkob2xkQ2hhcnRzKSAmJiBvbGRDaGFydHMubGVuZ3RoKSB7XHJcbiAgICAgICAgICAvLyBEZXN0cm95IG9sZCBjaGFydHNcclxuICAgICAgICAgIGZvciAoY29uc3Qgb2xkQ2hhcnQgb2Ygb2xkQ2hhcnRzKSB7XHJcbiAgICAgICAgICAgIG9sZENoYXJ0ICYmIG9sZENoYXJ0LmRlc3Ryb3koKTtcclxuICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICAgIEhpZ2hjaGFydHMuY2hhcnRzLnNoaWZ0KCk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9KTtcclxuXHJcbiAgICBhd2FpdCBjbGVhckluamVjdGVkKHBhZ2UpO1xyXG4gICAgcmV0dXJuIGRhdGE7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIGF3YWl0IGNsZWFySW5qZWN0ZWQocGFnZSk7XHJcbiAgICByZXR1cm4gZXJyb3I7XHJcbiAgfVxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCBjc3NUZW1wbGF0ZSBmcm9tICcuL2Nzcy5qcyc7XHJcblxyXG5leHBvcnQgZGVmYXVsdCAoY2hhcnQpID0+IGBcclxuPCFET0NUWVBFIGh0bWw+XHJcbjxodG1sIGxhbmc9J2VuLVVTJz5cclxuICA8aGVhZD5cclxuICAgIDxtZXRhIGh0dHAtZXF1aXY9XCJDb250ZW50LVR5cGVcIiBjb250ZW50PVwidGV4dC9odG1sOyBjaGFyc2V0PXV0Zi04XCI+XHJcbiAgICA8dGl0bGU+SGlnaGNhcnRzIEV4cG9ydDwvdGl0bGU+XHJcbiAgPC9oZWFkPlxyXG4gIDxzdHlsZT5cclxuICAgICR7Y3NzVGVtcGxhdGUoKX1cclxuICA8L3N0eWxlPlxyXG4gIDxib2R5PlxyXG4gICAgPGRpdiBpZD1cImNoYXJ0LWNvbnRhaW5lclwiPlxyXG4gICAgICAke2NoYXJ0fVxyXG4gICAgPC9kaXY+XHJcbiAgPC9ib2R5PlxyXG48L2h0bWw+XHJcblxyXG5gO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IFBvb2wgfSBmcm9tICd0YXJuJztcclxuaW1wb3J0IHsgdjQgYXMgdXVpZCB9IGZyb20gJ3V1aWQnO1xyXG5cclxuaW1wb3J0IHtcclxuICBjbG9zZSBhcyBicm93c2VyQ2xvc2UsXHJcbiAgY3JlYXRlIGFzIGNyZWF0ZUJyb3dzZXIsXHJcbiAgbmV3UGFnZSBhcyBicm93c2VyTmV3UGFnZSxcclxuICBjbGVhclBhZ2VcclxufSBmcm9tICcuL2Jyb3dzZXIuanMnO1xyXG5pbXBvcnQgcHVwcGV0ZWVyRXhwb3J0IGZyb20gJy4vZXhwb3J0LmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IG1lYXN1cmVUaW1lIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxubGV0IHBlcmZvcm1lZEV4cG9ydHMgPSAwO1xyXG5sZXQgZXhwb3J0QXR0ZW1wdHMgPSAwO1xyXG5sZXQgdGltZVNwZW50ID0gMDtcclxubGV0IGRyb3BwZWRFeHBvcnRzID0gMDtcclxubGV0IHNwZW50QXZlcmFnZSA9IDA7XHJcbmxldCBwb29sQ29uZmlnID0ge307XHJcblxyXG4vLyBUaGUgcG9vbCBpbnN0YW5jZVxyXG5sZXQgcG9vbCA9IGZhbHNlO1xyXG5cclxuLy8gQ3VzdG9tIHB1cHBldGVlciBhcmd1bWVudHNcclxubGV0IHB1cHBldGVlckFyZ3M7XHJcblxyXG5jb25zdCBmYWN0b3J5ID0ge1xyXG4gIC8qKlxyXG4gICAqIENyZWF0ZXMgYSBuZXcgd29ya2VyIHBhZ2UgZm9yIHRoZSBleHBvcnQgcG9vbC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHtPYmplY3R9IC0gQW4gb2JqZWN0IGNvbnRhaW5pbmcgdGhlIHdvcmtlciBJRCwgYSByZWZlcmVuY2UgdG8gdGhlXHJcbiAgICogYnJvd3NlciBwYWdlLCBhbmQgaW5pdGlhbCB3b3JrIGNvdW50LlxyXG4gICAqXHJcbiAgICogQHRocm93cyB7RXhwb3J0RXJyb3J9IC0gSWYgdGhlcmUncyBhbiBlcnJvciBkdXJpbmcgdGhlIGNyZWF0aW9uIG9mIHRoZSBuZXdcclxuICAgKiBwYWdlLlxyXG4gICAqL1xyXG4gIGNyZWF0ZTogYXN5bmMgKCkgPT4ge1xyXG4gICAgbGV0IHBhZ2UgPSBmYWxzZTtcclxuXHJcbiAgICBjb25zdCBpZCA9IHV1aWQoKTtcclxuICAgIGNvbnN0IHN0YXJ0RGF0ZSA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xyXG5cclxuICAgIHRyeSB7XHJcbiAgICAgIHBhZ2UgPSBhd2FpdCBicm93c2VyTmV3UGFnZSgpO1xyXG5cclxuICAgICAgaWYgKCFwYWdlIHx8IHBhZ2UuaXNDbG9zZWQoKSkge1xyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignVGhlIHBhZ2UgaXMgaW52YWxpZCBvciBjbG9zZWQuJyk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGxvZyhcclxuICAgICAgICAzLFxyXG4gICAgICAgIGBbcG9vbF0gU3VjY2Vzc2Z1bGx5IGNyZWF0ZWQgYSB3b3JrZXIgJHtpZH0gLSB0b29rICR7XHJcbiAgICAgICAgICBuZXcgRGF0ZSgpLmdldFRpbWUoKSAtIHN0YXJ0RGF0ZVxyXG4gICAgICAgIH0gbXMuYFxyXG4gICAgICApO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdFcnJvciBlbmNvdW50ZXJlZCB3aGVuIGNyZWF0aW5nIGEgbmV3IHBhZ2UuJ1xyXG4gICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4ge1xyXG4gICAgICBpZCxcclxuICAgICAgcGFnZSxcclxuICAgICAgLy8gVHJ5IHRvIGRpc3RyaWJ1dGUgdGhlIGluaXRpYWwgd29yayBjb3VudFxyXG4gICAgICB3b3JrQ291bnQ6IE1hdGgucm91bmQoTWF0aC5yYW5kb20oKSAqIChwb29sQ29uZmlnLndvcmtMaW1pdCAvIDIpKVxyXG4gICAgfTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBWYWxpZGF0ZXMgYSB3b3JrZXIgcGFnZSBpbiB0aGUgZXhwb3J0IHBvb2wsIGNoZWNraW5nIGlmIGl0IGhhcyBleGNlZWRlZFxyXG4gICAqIHRoZSB3b3JrIGxpbWl0LlxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtPYmplY3R9IHdvcmtlckhhbmRsZSAtIFRoZSBoYW5kbGUgdG8gdGhlIHdvcmtlciwgY29udGFpbmluZyB0aGVcclxuICAgKiB3b3JrZXIncyBJRCwgYSByZWZlcmVuY2UgdG8gdGhlIGJyb3dzZXIgcGFnZSwgYW5kIHdvcmsgY291bnQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBSZXR1cm5zIHRydWUgaWYgdGhlIHdvcmtlciBpcyB2YWxpZCBhbmQgd2l0aGluXHJcbiAgICogdGhlIHdvcmsgbGltaXQ7IG90aGVyd2lzZSwgcmV0dXJucyBmYWxzZS5cclxuICAgKi9cclxuICB2YWxpZGF0ZTogYXN5bmMgKHdvcmtlckhhbmRsZSkgPT4ge1xyXG4gICAgaWYgKFxyXG4gICAgICBwb29sQ29uZmlnLndvcmtMaW1pdCAmJlxyXG4gICAgICArK3dvcmtlckhhbmRsZS53b3JrQ291bnQgPiBwb29sQ29uZmlnLndvcmtMaW1pdFxyXG4gICAgKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICAzLFxyXG4gICAgICAgIGBbcG9vbF0gV29ya2VyIGZhaWxlZCB2YWxpZGF0aW9uOiBleGNlZWRlZCB3b3JrIGxpbWl0IChsaW1pdCBpcyAke3Bvb2xDb25maWcud29ya0xpbWl0fSkuYFxyXG4gICAgICApO1xyXG4gICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2xlYXIgcGFnZVxyXG4gICAgYXdhaXQgY2xlYXJQYWdlKHdvcmtlckhhbmRsZS5wYWdlLCB0cnVlKTtcclxuICAgIHJldHVybiB0cnVlO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIERlc3Ryb3lzIGEgd29ya2VyIGVudHJ5IGluIHRoZSBleHBvcnQgcG9vbCwgY2xvc2luZyBpdHMgYXNzb2NpYXRlZCBwYWdlLlxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtPYmplY3R9IHdvcmtlckhhbmRsZSAtIFRoZSBoYW5kbGUgdG8gdGhlIHdvcmtlciwgY29udGFpbmluZ1xyXG4gICAqIHRoZSB3b3JrZXIncyBJRCBhbmQgYSByZWZlcmVuY2UgdG8gdGhlIGJyb3dzZXIgcGFnZS5cclxuICAgKi9cclxuICBkZXN0cm95OiAod29ya2VySGFuZGxlKSA9PiB7XHJcbiAgICBsb2coMywgYFtwb29sXSBEZXN0cm95aW5nIHBvb2wgZW50cnkgJHt3b3JrZXJIYW5kbGUuaWR9LmApO1xyXG5cclxuICAgIGlmICh3b3JrZXJIYW5kbGUucGFnZSkge1xyXG4gICAgICAvLyBXZSBkb24ndCByZWFsbHkgbmVlZCB0byB3YWl0IGFyb3VuZCBmb3IgdGhpcy5cclxuICAgICAgd29ya2VySGFuZGxlLnBhZ2UuY2xvc2UoKTtcclxuICAgIH1cclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgdGhlIGV4cG9ydCBwb29sIHdpdGggdGhlIHByb3ZpZGVkIGNvbmZpZ3VyYXRpb24sIGNyZWF0aW5nXHJcbiAqIGEgYnJvd3NlciBpbnN0YW5jZSBhbmQgc2V0dGluZyB1cCB3b3JrZXIgcmVzb3VyY2VzLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnIC0gQ29uZmlndXJhdGlvbiBvcHRpb25zIGZvciB0aGUgZXhwb3J0IHBvb2wgYWxvbmdcclxuICogd2l0aCBjdXN0b20gcHVwcGV0ZWVyIGFyZ3VtZW50cyBmb3IgdGhlIHB1cHBldGVlci5sYXVuY2ggZnVuY3Rpb24uXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaW5pdFBvb2wgPSBhc3luYyAoY29uZmlnKSA9PiB7XHJcbiAgLy8gRm9yIHRoZSBtb2R1bGUgc2NvcGUgdXNhZ2VcclxuICBwb29sQ29uZmlnID0gY29uZmlnICYmIGNvbmZpZy5wb29sID8geyAuLi5jb25maWcucG9vbCB9IDoge307XHJcblxyXG4gIC8vIEF0dGFjaCBwcm9jZXNzJyBleGl0IGxpc3RlbmVyc1xyXG4gIGlmIChwb29sQ29uZmlnLmxpc3RlblRvUHJvY2Vzc0V4aXRzKSB7XHJcbiAgICBhdHRhY2hQcm9jZXNzRXhpdExpc3RlbmVycygpO1xyXG4gIH1cclxuXHJcbiAgLy8gVGhlIG5ld2VzdCBwdXBwZXRlZXIgYXJndW1lbnRzIGZvciB0aGUgYnJvd3NlciBjcmVhdGlvblxyXG4gIHB1cHBldGVlckFyZ3MgPSBjb25maWcucHVwcGV0ZWVyQXJncztcclxuXHJcbiAgLy8gQ3JlYXRlIGEgYnJvd3NlciBpbnN0YW5jZVxyXG4gIGF3YWl0IGNyZWF0ZUJyb3dzZXIocHVwcGV0ZWVyQXJncyk7XHJcblxyXG4gIGxvZyhcclxuICAgIDMsXHJcbiAgICBgW3Bvb2xdIEluaXRpYWxpemluZyBwb29sIHdpdGggd29ya2VyczogbWluICR7cG9vbENvbmZpZy5taW5Xb3JrZXJzfSwgbWF4ICR7cG9vbENvbmZpZy5tYXhXb3JrZXJzfS5gXHJcbiAgKTtcclxuXHJcbiAgaWYgKHBvb2wpIHtcclxuICAgIHJldHVybiBsb2coXHJcbiAgICAgIDQsXHJcbiAgICAgICdbcG9vbF0gQWxyZWFkeSBpbml0aWFsaXplZCwgcGxlYXNlIGtpbGwgaXQgYmVmb3JlIGNyZWF0aW5nIGEgbmV3IG9uZS4nXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgaWYgKHBhcnNlSW50KHBvb2xDb25maWcubWluV29ya2VycykgPiBwYXJzZUludChwb29sQ29uZmlnLm1heFdvcmtlcnMpKSB7XHJcbiAgICBwb29sQ29uZmlnLm1pbldvcmtlcnMgPSBwb29sQ29uZmlnLm1heFdvcmtlcnM7XHJcbiAgfVxyXG5cclxuICB0cnkge1xyXG4gICAgLy8gQ3JlYXRlIGEgcG9vbCBhbG9uZyB3aXRoIGEgbWluaW1hbCBudW1iZXIgb2YgcmVzb3VyY2VzXHJcbiAgICBwb29sID0gbmV3IFBvb2woe1xyXG4gICAgICAvLyBHZXQgdGhlIGNyZWF0ZS92YWxpZGF0ZS9kZXN0cm95L2xvZyBmdW5jdGlvbnNcclxuICAgICAgLi4uZmFjdG9yeSxcclxuICAgICAgbWluOiBwYXJzZUludChwb29sQ29uZmlnLm1pbldvcmtlcnMpLFxyXG4gICAgICBtYXg6IHBhcnNlSW50KHBvb2xDb25maWcubWF4V29ya2VycyksXHJcbiAgICAgIGFjcXVpcmVUaW1lb3V0TWlsbGlzOiBwb29sQ29uZmlnLmFjcXVpcmVUaW1lb3V0LFxyXG4gICAgICBjcmVhdGVUaW1lb3V0TWlsbGlzOiBwb29sQ29uZmlnLmNyZWF0ZVRpbWVvdXQsXHJcbiAgICAgIGRlc3Ryb3lUaW1lb3V0TWlsbGlzOiBwb29sQ29uZmlnLmRlc3Ryb3lUaW1lb3V0LFxyXG4gICAgICBpZGxlVGltZW91dE1pbGxpczogcG9vbENvbmZpZy5pZGxlVGltZW91dCxcclxuICAgICAgY3JlYXRlUmV0cnlJbnRlcnZhbE1pbGxpczogcG9vbENvbmZpZy5jcmVhdGVSZXRyeUludGVydmFsLFxyXG4gICAgICByZWFwSW50ZXJ2YWxNaWxsaXM6IHBvb2xDb25maWcucmVhcGVySW50ZXJ2YWwsXHJcbiAgICAgIHByb3BhZ2F0ZUNyZWF0ZUVycm9yOiBmYWxzZVxyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gU2V0IGV2ZW50c1xyXG4gICAgcG9vbC5vbigncmVsZWFzZScsIGFzeW5jIChyZXNvdXJjZSkgPT4ge1xyXG4gICAgICAvLyBDbGVhciBwYWdlXHJcbiAgICAgIGF3YWl0IGNsZWFyUGFnZShyZXNvdXJjZS5wYWdlLCBmYWxzZSk7XHJcbiAgICAgIGxvZyg0LCBgW3Bvb2xdIFJlbGVhc2luZyBhIHdvcmtlciB3aXRoIElEICR7cmVzb3VyY2UuaWR9LmApO1xyXG4gICAgfSk7XHJcblxyXG4gICAgcG9vbC5vbignZGVzdHJveVN1Y2Nlc3MnLCAoZXZlbnRJZCwgcmVzb3VyY2UpID0+IHtcclxuICAgICAgbG9nKDQsIGBbcG9vbF0gRGVzdHJveWVkIGEgd29ya2VyIHdpdGggSUQgJHtyZXNvdXJjZS5pZH0uYCk7XHJcbiAgICB9KTtcclxuXHJcbiAgICBjb25zdCBpbml0aWFsUmVzb3VyY2VzID0gW107XHJcbiAgICAvLyBDcmVhdGUgYW4gaW5pdGlhbCBudW1iZXIgb2YgcmVzb3VyY2VzXHJcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHBvb2xDb25maWcubWluV29ya2VyczsgaSsrKSB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgY29uc3QgcmVzb3VyY2UgPSBhd2FpdCBwb29sLmFjcXVpcmUoKS5wcm9taXNlO1xyXG4gICAgICAgIGluaXRpYWxSZXNvdXJjZXMucHVzaChyZXNvdXJjZSk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCAnW3Bvb2xdIENvdWxkIG5vdCBjcmVhdGUgYW4gaW5pdGlhbCByZXNvdXJjZS4nKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIFJlbGVhc2UgdGhlIGluaXRpYWwgbnVtYmVyIG9mIHJlc291cmNlcyBiYWNrIHRvIHRoZSBwb29sXHJcbiAgICBpbml0aWFsUmVzb3VyY2VzLmZvckVhY2goKHJlc291cmNlKSA9PiB7XHJcbiAgICAgIHBvb2wucmVsZWFzZShyZXNvdXJjZSk7XHJcbiAgICB9KTtcclxuXHJcbiAgICBsb2coXHJcbiAgICAgIDMsXHJcbiAgICAgIGBbcG9vbF0gVGhlIHBvb2wgaXMgcmVhZHkke2luaXRpYWxSZXNvdXJjZXMubGVuZ3RoID8gYCB3aXRoICR7aW5pdGlhbFJlc291cmNlcy5sZW5ndGh9IGluaXRpYWwgcmVzb3VyY2VzIHdhaXRpbmcuYCA6ICcuJ31gXHJcbiAgICApO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAvLyBDbG9zZSBicm93c2VyIGlmIGZvciBzb21lIHJlYXNvbiBjYW5ub3QgZXN0YWJsaXNoIHRoZSBwb29sXHJcbiAgICBhd2FpdCBicm93c2VyQ2xvc2UoKTtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1twb29sXSBDb3VsZCBub3QgY3JlYXRlIHRoZSBwb29sIG9mIHdvcmtlcnMuJ1xyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEF0dGFjaGVzIGV4aXQgbGlzdGVuZXJzIHRvIHRoZSBwcm9jZXNzLCBlbnN1cmluZyBwcm9wZXIgY2xlYW51cCBvZiByZXNvdXJjZXNcclxuICogYW5kIHRlcm1pbmF0aW9uIG9uIGV4aXQgc2lnbmFscy4gSGFuZGxlcyAnZXhpdCcsICdTSUdJTlQnLCAnU0lHVEVSTScsIGFuZFxyXG4gKiAndW5jYXVnaHRFeGNlcHRpb24nIGV2ZW50cy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBhdHRhY2hQcm9jZXNzRXhpdExpc3RlbmVycygpIHtcclxuICBsb2coMywgJ1twb29sXSBBdHRhY2hpbmcgZXhpdCBsaXN0ZW5lcnMgdG8gdGhlIHByb2Nlc3MuJyk7XHJcblxyXG4gIC8vIEtpbGwgYWxsIHBvb2wgcmVzb3VyY2VzIG9uIGV4aXRcclxuICBwcm9jZXNzLm9uKCdleGl0JywgYXN5bmMgKGNvZGUpID0+IHtcclxuICAgIGxvZyg0LCBgUHJvY2VzcyBleGl0ZWQgd2l0aCBjb2RlICR7Y29kZX0uYCk7XHJcbiAgICBhd2FpdCBraWxsUG9vbCgpO1xyXG4gIH0pO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgU0lHSU5UXHJcbiAgcHJvY2Vzcy5vbignU0lHSU5UJywgKG5hbWUsIGNvZGUpID0+IHtcclxuICAgIGxvZyg0LCBgVGhlICR7bmFtZX0gZXZlbnQgd2l0aCBjb2RlOiAke2NvZGV9LmApO1xyXG4gICAgcHJvY2Vzcy5leGl0KDEpO1xyXG4gIH0pO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgU0lHVEVSTVxyXG4gIHByb2Nlc3Mub24oJ1NJR1RFUk0nLCAobmFtZSwgY29kZSkgPT4ge1xyXG4gICAgbG9nKDQsIGBUaGUgJHtuYW1lfSBldmVudCB3aXRoIGNvZGU6ICR7Y29kZX0uYCk7XHJcbiAgICBwcm9jZXNzLmV4aXQoMSk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSB1bmNhdWdodEV4Y2VwdGlvblxyXG4gIHByb2Nlc3Mub24oJ3VuY2F1Z2h0RXhjZXB0aW9uJywgYXN5bmMgKGVycm9yLCBuYW1lKSA9PiB7XHJcbiAgICBsb2dXaXRoU3RhY2soMSwgZXJyb3IsIGBUaGUgJHtuYW1lfSBlcnJvci5gKTtcclxuICAgIGF3YWl0IGtpbGxQb29sKCk7XHJcbiAgICBwcm9jZXNzLmV4aXQoMSk7XHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBLaWxscyBhbGwgd29ya2VycyBpbiB0aGUgcG9vbCwgZGVzdHJveXMgdGhlIHBvb2wsIGFuZCBjbG9zZXMgdGhlIGJyb3dzZXJcclxuICogaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyBhZnRlciB0aGUgd29ya2VycyBhcmVcclxuICoga2lsbGVkLCB0aGUgcG9vbCBpcyBkZXN0cm95ZWQsIGFuZCB0aGUgYnJvd3NlciBpcyBjbG9zZWQuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24ga2lsbFBvb2woKSB7XHJcbiAgbG9nKDMsICdbcG9vbF0gS2lsbGluZyBhbGwgcG9vbCB3b3JrZXJzIGFuZCBicm93c2VyLCBpZiBhbnkgZXhpc3QuJyk7XHJcblxyXG4gIC8vIFJldHVybiB0cnVlIHdoZW4gdGhlIHBvb2wgaXMgYWxyZWFkeSBkZXN0cm95ZWRcclxuICBpZiAocG9vbD8uZGVzdHJveWVkKSB7XHJcbiAgICAvLyBDbG9zZSB0aGUgYnJvd3NlciBpbnN0YW5jZSBpZiBzdGlsbCBjb25uZWN0ZWRcclxuICAgIHJldHVybiBicm93c2VyQ2xvc2UoKTtcclxuICB9XHJcblxyXG4gIC8vIElmIHN0aWxsIGFsaXZlLCBkZXN0cm95IHRoZSBwb29sIG9mIHBhZ2VzIGJlZm9yZSBjbG9zaW5nIGEgYnJvd3NlclxyXG4gIGlmIChwb29sKSB7XHJcbiAgICBhd2FpdCBwb29sLmRlc3Ryb3koKTtcclxuICAgIGxvZyg0LCAnW2Jyb3dzZXJdIERlc3Ryb3llZCB0aGUgcG9vbCBvZiByZXNvdXJjZXMuJyk7XHJcbiAgfVxyXG5cclxuICAvLyBDbG9zZSB0aGUgYnJvd3NlciBpbnN0YW5jZVxyXG4gIHJldHVybiBicm93c2VyQ2xvc2UoKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFByb2Nlc3NlcyB0aGUgZXhwb3J0IHdvcmsgdXNpbmcgYSB3b3JrZXIgZnJvbSB0aGUgcG9vbC4gQWNxdWlyZXMgYSB3b3JrZXJcclxuICogaGFuZGxlIGZyb20gdGhlIHBvb2wsIHBlcmZvcm1zIHRoZSBleHBvcnQgdXNpbmcgcHVwcGV0ZWVyLCBhbmQgcmVsZWFzZXNcclxuICogdGhlIHdvcmtlciBoYW5kbGUgYmFjayB0byB0aGUgcG9vbC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGNoYXJ0IC0gVGhlIGNoYXJ0IGRhdGEgb3IgY29uZmlndXJhdGlvbiB0byBiZSBleHBvcnRlZC5cclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBFeHBvcnQgb3B0aW9ucyBhbmQgY29uZmlndXJhdGlvbi5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2l0aCB0aGUgZXhwb3J0IHJlc3VsdGFuZFxyXG4gKiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gSWYgYW4gZXJyb3Igb2NjdXJzIGR1cmluZyB0aGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgcG9zdFdvcmsgPSBhc3luYyAoY2hhcnQsIG9wdGlvbnMpID0+IHtcclxuICBsZXQgd29ya2VySGFuZGxlO1xyXG5cclxuICB0cnkge1xyXG4gICAgbG9nKDQsICdbcG9vbF0gV29yayByZWNlaXZlZCwgc3RhcnRpbmcgdG8gcHJvY2Vzcy4nKTtcclxuXHJcbiAgICArK2V4cG9ydEF0dGVtcHRzO1xyXG4gICAgaWYgKHBvb2xDb25maWcuYmVuY2htYXJraW5nKSB7XHJcbiAgICAgIGdldFBvb2xJbmZvKCk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKCFwb29sKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignV29yayByZWNlaXZlZCwgYnV0IHBvb2wgaGFzIG5vdCBiZWVuIHN0YXJ0ZWQuJyk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQWNxdWlyZSB0aGUgd29ya2VyIGFsb25nIHdpdGggdGhlIGlkIG9mIHJlc291cmNlIGFuZCB3b3JrIGNvdW50XHJcbiAgICB0cnkge1xyXG4gICAgICBsb2coNCwgJ1twb29sXSBBY3F1aXJpbmcgYSB3b3JrZXIgaGFuZGxlLicpO1xyXG4gICAgICBjb25zdCBhY3F1aXJlQ291bnRlciA9IG1lYXN1cmVUaW1lKCk7XHJcbiAgICAgIHdvcmtlckhhbmRsZSA9IGF3YWl0IHBvb2wuYWNxdWlyZSgpLnByb21pc2U7XHJcblxyXG4gICAgICAvLyBDaGVjayB0aGUgcGFnZSBhY3F1aXJlIHRpbWVcclxuICAgICAgaWYgKG9wdGlvbnMuc2VydmVyLmJlbmNobWFya2luZykge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDUsXHJcbiAgICAgICAgICBvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZFxyXG4gICAgICAgICAgICA/IGBbYmVuY2htYXJrXSBSZXF1ZXN0IHdpdGggSUQgJHtvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZH0gLWBcclxuICAgICAgICAgICAgOiAnW2JlbmNobWFya10nLFxyXG4gICAgICAgICAgYEFjcXVpcmVkIGEgd29ya2VyIGhhbmRsZTogJHthY3F1aXJlQ291bnRlcigpfW1zLmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ0Vycm9yIGVuY291bnRlcmVkIHdoZW4gYWNxdWlyaW5nIGFuIGF2YWlsYWJsZSBlbnRyeS4nXHJcbiAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgfVxyXG4gICAgbG9nKDQsICdbcG9vbF0gQWNxdWlyZWQgYSB3b3JrZXIgaGFuZGxlLicpO1xyXG5cclxuICAgIGlmICghd29ya2VySGFuZGxlLnBhZ2UpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdSZXNvbHZlZCB3b3JrZXIgcGFnZSBpcyBpbnZhbGlkOiB0aGUgcG9vbCBzZXR1cCBpcyB3b25reS4nXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU2F2ZSB0aGUgc3RhcnQgdGltZVxyXG4gICAgbGV0IHdvcmtTdGFydCA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xyXG5cclxuICAgIGxvZyg0LCBgW3Bvb2xdIFN0YXJ0aW5nIHdvcmsgb24gcG9vbCBlbnRyeSB3aXRoIElEICR7d29ya2VySGFuZGxlLmlkfS5gKTtcclxuXHJcbiAgICAvLyBQZXJmb3JtIGFuIGV4cG9ydCBvbiBhIHB1cHBldGVlciBsZXZlbFxyXG4gICAgY29uc3QgZXhwb3J0Q291bnRlciA9IG1lYXN1cmVUaW1lKCk7XHJcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBwdXBwZXRlZXJFeHBvcnQod29ya2VySGFuZGxlLnBhZ2UsIGNoYXJ0LCBvcHRpb25zKTtcclxuXHJcbiAgICAvLyBDaGVjayBpZiBpdCdzIGFuIGVycm9yXHJcbiAgICBpZiAocmVzdWx0IGluc3RhbmNlb2YgRXJyb3IpIHtcclxuICAgICAgLy8gVE9ETzogSWYgdGhlIGV4cG9ydCBmYWlsZWQgYmVjYXVzZSBwdXBwZXRlZXIgdGltZWQgb3V0LCB3ZSBuZWVkIHRvIGZvcmNlIGtpbGwgdGhlIHdvcmtlciBzbyB3ZSBnZXQgYSBuZXcgcGFnZS4gVGhhdCBuZWVkcyB0byBiZSBoYW5kbGVkIGJldHRlciB0aGFuIHRoaXMgaGFjay5cclxuICAgICAgaWYgKHJlc3VsdC5tZXNzYWdlID09PSAnUmFzdGVyaXphdGlvbiB0aW1lb3V0Jykge1xyXG4gICAgICAgIHdvcmtlckhhbmRsZS5wYWdlLmNsb3NlKCk7XHJcbiAgICAgICAgd29ya2VySGFuZGxlLnBhZ2UgPSBhd2FpdCBicm93c2VyTmV3UGFnZSgpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ0Vycm9yIGVuY291bnRlcmVkIGR1cmluZyBleHBvcnQuJykuc2V0RXJyb3IoXHJcbiAgICAgICAgcmVzdWx0XHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2hlY2sgdGhlIFB1cHBldGVlciBleHBvcnQgdGltZVxyXG4gICAgaWYgKG9wdGlvbnMuc2VydmVyLmJlbmNobWFya2luZykge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgNSxcclxuICAgICAgICBvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZFxyXG4gICAgICAgICAgPyBgW2JlbmNobWFya10gUmVxdWVzdCB3aXRoIElEICR7b3B0aW9ucy5wYXlsb2FkPy5yZXF1ZXN0SWR9IC1gXHJcbiAgICAgICAgICA6ICdbYmVuY2htYXJrXScsXHJcbiAgICAgICAgYEV4cG9ydGVkIGEgY2hhcnQgc3VjZXNzZnVsbHk6ICR7ZXhwb3J0Q291bnRlcigpfW1zLmBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBSZWxlYXNlIHRoZSByZXNvdXJjZSBiYWNrIHRvIHRoZSBwb29sXHJcbiAgICBwb29sLnJlbGVhc2Uod29ya2VySGFuZGxlKTtcclxuXHJcbiAgICAvLyBVc2VkIGZvciBzdGF0aXN0aWNzIGluIGF2ZXJhZ2VUaW1lIGFuZCBwcm9jZXNzZWRXb3JrQ291bnQsIHdoaWNoXHJcbiAgICAvLyBpbiB0dXJuIGlzIHVzZWQgYnkgdGhlIC9oZWFsdGggcm91dGUuXHJcbiAgICBjb25zdCB3b3JrRW5kID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XHJcbiAgICBjb25zdCBleHBvcnRUaW1lID0gd29ya0VuZCAtIHdvcmtTdGFydDtcclxuICAgIHRpbWVTcGVudCArPSBleHBvcnRUaW1lO1xyXG4gICAgc3BlbnRBdmVyYWdlID0gdGltZVNwZW50IC8gKytwZXJmb3JtZWRFeHBvcnRzO1xyXG5cclxuICAgIGxvZyg0LCBgW3Bvb2xdIFdvcmsgY29tcGxldGVkIGluICR7ZXhwb3J0VGltZX0gbXMuYCk7XHJcblxyXG4gICAgLy8gT3RoZXJ3aXNlIHJldHVybiB0aGUgcmVzdWx0XHJcbiAgICByZXR1cm4ge1xyXG4gICAgICByZXN1bHQsXHJcbiAgICAgIG9wdGlvbnNcclxuICAgIH07XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICsrZHJvcHBlZEV4cG9ydHM7XHJcblxyXG4gICAgaWYgKHdvcmtlckhhbmRsZSkge1xyXG4gICAgICBwb29sLnJlbGVhc2Uod29ya2VySGFuZGxlKTtcclxuICAgIH1cclxuXHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoYFtwb29sXSBJbiBwb29sLnBvc3RXb3JrOiAke2Vycm9yLm1lc3NhZ2V9YCkuc2V0RXJyb3IoXHJcbiAgICAgIGVycm9yXHJcbiAgICApO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgdGhlIGN1cnJlbnQgcG9vbCBpbnN0YW5jZS5cclxuICpcclxuICogQHJldHVybnMge09iamVjdHxudWxsfSBUaGUgY3VycmVudCBwb29sIGluc3RhbmNlIGlmIGluaXRpYWxpemVkLCBvciBudWxsXHJcbiAqIGlmIHRoZSBwb29sIGhhcyBub3QgYmVlbiBjcmVhdGVkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldFBvb2woKSB7XHJcbiAgcmV0dXJuIHBvb2w7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgcG9vbCBpbmZvcm1hdGlvbiBpbiBKU09OIGZvcm1hdCwgaW5jbHVkaW5nIG1pbmltdW0gYW5kIG1heGltdW1cclxuICogd29ya2VycywgYXZhaWxhYmxlIHdvcmtlcnMsIHdvcmtlcnMgaW4gdXNlLCBhbmQgcGVuZGluZyBhY3F1aXJlIHJlcXVlc3RzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBQb29sIGluZm9ybWF0aW9uIGluIEpTT04gZm9ybWF0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldFBvb2xJbmZvSlNPTiA9ICgpID0+ICh7XHJcbiAgbWluOiBwb29sLm1pbixcclxuICBtYXg6IHBvb2wubWF4LFxyXG4gIGF2YWlsYWJsZTogcG9vbC5udW1GcmVlKCksXHJcbiAgaW5Vc2U6IHBvb2wubnVtVXNlZCgpLFxyXG4gIHBlbmRpbmdBY3F1aXJlOiBwb29sLm51bVBlbmRpbmdBY3F1aXJlcygpXHJcbn0pO1xyXG5cclxuLyoqXHJcbiAqIExvZ3MgaW5mb3JtYXRpb24gYWJvdXQgdGhlIGN1cnJlbnQgc3RhdGUgb2YgdGhlIHBvb2wsIGluY2x1ZGluZyB0aGUgbWluaW11bVxyXG4gKiBhbmQgbWF4aW11bSB3b3JrZXJzLCBhdmFpbGFibGUgd29ya2Vycywgd29ya2VycyBpbiB1c2UsIGFuZCBwZW5kaW5nIGFjcXVpcmVcclxuICogcmVxdWVzdHMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0UG9vbEluZm8oKSB7XHJcbiAgY29uc3QgeyBtaW4sIG1heCB9ID0gcG9vbDtcclxuXHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG1pbmltdW0gbnVtYmVyIG9mIHJlc291cmNlcyBhbGxvd2VkIGJ5IHBvb2w6ICR7bWlufS5gKTtcclxuICBsb2coNSwgYFtwb29sXSBUaGUgbWF4aW11bSBudW1iZXIgb2YgcmVzb3VyY2VzIGFsbG93ZWQgYnkgcG9vbDogJHttYXh9LmApO1xyXG4gIGxvZyhcclxuICAgIDUsXHJcbiAgICBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgcmVzb3VyY2VzIHRoYXQgYXJlIGN1cnJlbnRseSBhdmFpbGFibGU6ICR7cG9vbC5udW1GcmVlKCl9LmBcclxuICApO1xyXG4gIGxvZyhcclxuICAgIDUsXHJcbiAgICBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgcmVzb3VyY2VzIHRoYXQgYXJlIGN1cnJlbnRseSBhY3F1aXJlZDogJHtwb29sLm51bVVzZWQoKX0uYFxyXG4gICk7XHJcbiAgbG9nKFxyXG4gICAgNSxcclxuICAgIGBbcG9vbF0gVGhlIG51bWJlciBvZiBjYWxsZXJzIHdhaXRpbmcgdG8gYWNxdWlyZSBhIHJlc291cmNlOiAke3Bvb2wubnVtUGVuZGluZ0FjcXVpcmVzKCl9LmBcclxuICApO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgaW5pdFBvb2wsXHJcbiAga2lsbFBvb2wsXHJcbiAgcG9zdFdvcmssXHJcbiAgZ2V0UG9vbCxcclxuICBnZXRQb29sSW5mbyxcclxuICBnZXRQb29sSW5mb0pTT04sXHJcbiAgd29ya0F0dGVtcHRzOiAoKSA9PiBleHBvcnRBdHRlbXB0cyxcclxuICBkcm9wcGVkV29yazogKCkgPT4gZHJvcHBlZEV4cG9ydHMsXHJcbiAgYXZlcmFnZVRpbWU6ICgpID0+IHNwZW50QXZlcmFnZSxcclxuICBwcm9jZXNzZWRXb3JrQ291bnQ6ICgpID0+IHBlcmZvcm1lZEV4cG9ydHNcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMsIHdyaXRlRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcblxyXG5pbXBvcnQgeyBnZXRPcHRpb25zLCBpbml0RXhwb3J0U2V0dGluZ3MgfSBmcm9tICcuL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBraWxsUG9vbCwgcG9zdFdvcmsgfSBmcm9tICcuL3Bvb2wuanMnO1xyXG5pbXBvcnQge1xyXG4gIGZpeFR5cGUsXHJcbiAgaGFuZGxlUmVzb3VyY2VzLFxyXG4gIGlzQ29ycmVjdEpTT04sXHJcbiAgb3B0aW9uc1N0cmluZ2lmeSxcclxuICByb3VuZE51bWJlcixcclxuICB0b0Jvb2xlYW4sXHJcbiAgd3JhcEFyb3VuZFxyXG59IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbmxldCBhbGxvd0NvZGVFeGVjdXRpb24gPSBmYWxzZTtcclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgYW4gZXhwb3J0IHByb2Nlc3MuIFRoZSBgc2V0dGluZ3NgIGNvbnRhaW5zIGZpbmFsIG9wdGlvbnMgZ2F0aGVyZWRcclxuICogZnJvbSBhbGwgcG9zc2libGUgc291cmNlcyAoY29uZmlnLCBlbnYsIGNsaSwganNvbikuIFRoZSBgZW5kQ2FsbGJhY2tgIGlzXHJcbiAqIGNhbGxlZCB3aGVuIHRoZSBleHBvcnQgaXMgY29tcGxldGVkLCB3aXRoIGFuIGVycm9yIG9iamVjdCBhcyB0aGUgZmlyc3RcclxuICogYXJndW1lbnQgYW5kIHRoZSBzZWNvbmQgY29udGFpbmluZyB0aGUgYmFzZTY0IHJlc3ByZXNlbnRhdGlvbiBvZiBhIGNoYXJ0LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gc2V0dGluZ3MgLSBUaGUgc2V0dGluZ3Mgb2JqZWN0IGNvbnRhaW5pbmcgZXhwb3J0XHJcbiAqIGNvbmZpZ3VyYXRpb24uXHJcbiAqIEBwYXJhbSB7ZnVuY3Rpb259IGVuZENhbGxiYWNrIC0gVGhlIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGludm9rZWQgdXBvblxyXG4gKiBmaW5hbGl6aW5nIHdvcmsgb3IgdXBvbiBlcnJvciBvY2N1cmFuY2Ugb2YgdGhlIGV4cG9ydGluZyBwcm9jZXNzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7dm9pZH0gVGhpcyBmdW5jdGlvbiBkb2VzIG5vdCByZXR1cm4gYSB2YWx1ZSBkaXJlY3RseTsgaW5zdGVhZCxcclxuICogaXQgY29tbXVuaWNhdGVzIHJlc3VsdHMgdmlhIHRoZSBlbmRDYWxsYmFjay5cclxuICovXHJcbmV4cG9ydCBjb25zdCBzdGFydEV4cG9ydCA9IGFzeW5jIChzZXR0aW5ncywgZW5kQ2FsbGJhY2spID0+IHtcclxuICAvLyBTdGFydGluZyBleHBvcnRpbmcgcHJvY2VzcyBtZXNzYWdlXHJcbiAgbG9nKDQsICdbY2hhcnRdIFN0YXJ0aW5nIHRoZSBleHBvcnRpbmcgcHJvY2Vzcy4nKTtcclxuXHJcbiAgLy8gSW5pdGlhbGl6ZSBvcHRpb25zXHJcbiAgY29uc3Qgb3B0aW9ucyA9IGluaXRFeHBvcnRTZXR0aW5ncyhzZXR0aW5ncywgZ2V0T3B0aW9ucygpKTtcclxuXHJcbiAgLy8gR2V0IHRoZSBleHBvcnQgb3B0aW9uc1xyXG4gIGNvbnN0IGV4cG9ydE9wdGlvbnMgPSBvcHRpb25zLmV4cG9ydDtcclxuXHJcbiAgLy8gSWYgU1ZHIGlzIGFuIGlucHV0IChhcmd1bWVudCBjYW4gYmUgc2VudCBvbmx5IGJ5IHRoZSByZXF1ZXN0KVxyXG4gIGlmIChvcHRpb25zLnBheWxvYWQ/LnN2ZyAmJiBvcHRpb25zLnBheWxvYWQuc3ZnICE9PSAnJykge1xyXG4gICAgdHJ5IHtcclxuICAgICAgbG9nKDQsICdbY2hhcnRdIEF0dGVtcHRpbmcgdG8gZXhwb3J0IGZyb20gYSBTVkcgaW5wdXQuJyk7XHJcbiAgICAgIHJldHVybiBleHBvcnRBc1N0cmluZyhvcHRpb25zLnBheWxvYWQuc3ZnLnRyaW0oKSwgb3B0aW9ucywgZW5kQ2FsbGJhY2spO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKFxyXG4gICAgICAgIG5ldyBFeHBvcnRFcnJvcignW2NoYXJ0XSBFcnJvciBsb2FkaW5nIFNWRyBpbnB1dC4nKS5zZXRFcnJvcihlcnJvcilcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIEV4cG9ydCB1c2luZyBvcHRpb25zIGZyb20gdGhlIGZpbGVcclxuICBpZiAoZXhwb3J0T3B0aW9ucy5pbmZpbGUgJiYgZXhwb3J0T3B0aW9ucy5pbmZpbGUubGVuZ3RoKSB7XHJcbiAgICAvLyBUcnkgdG8gcmVhZCB0aGUgZmlsZSB0byBnZXQgdGhlIHN0cmluZyByZXByZXNlbnRhdGlvblxyXG4gICAgdHJ5IHtcclxuICAgICAgbG9nKDQsICdbY2hhcnRdIEF0dGVtcHRpbmcgdG8gZXhwb3J0IGZyb20gYW4gaW5wdXQgZmlsZS4nKTtcclxuICAgICAgb3B0aW9ucy5leHBvcnQuaW5zdHIgPSByZWFkRmlsZVN5bmMoZXhwb3J0T3B0aW9ucy5pbmZpbGUsICd1dGY4Jyk7XHJcbiAgICAgIHJldHVybiBleHBvcnRBc1N0cmluZyhvcHRpb25zLmV4cG9ydC5pbnN0ci50cmltKCksIG9wdGlvbnMsIGVuZENhbGxiYWNrKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgICAgICBuZXcgRXhwb3J0RXJyb3IoJ1tjaGFydF0gRXJyb3IgbG9hZGluZyBpbnB1dCBmaWxlLicpLnNldEVycm9yKGVycm9yKVxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gRXhwb3J0IHdpdGggb3B0aW9ucyBmcm9tIHRoZSByYXcgcmVwcmVzZW50YXRpb25cclxuICBpZiAoXHJcbiAgICAoZXhwb3J0T3B0aW9ucy5pbnN0ciAmJiBleHBvcnRPcHRpb25zLmluc3RyICE9PSAnJykgfHxcclxuICAgIChleHBvcnRPcHRpb25zLm9wdGlvbnMgJiYgZXhwb3J0T3B0aW9ucy5vcHRpb25zICE9PSAnJylcclxuICApIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGxvZyg0LCAnW2NoYXJ0XSBBdHRlbXB0aW5nIHRvIGV4cG9ydCBmcm9tIGEgcmF3IGlucHV0LicpO1xyXG5cclxuICAgICAgLy8gUGVyZm9ybSBhIGRpcmVjdCBpbmplY3Qgd2hlbiBmb3JjZWRcclxuICAgICAgaWYgKHRvQm9vbGVhbihvcHRpb25zLmN1c3RvbUxvZ2ljPy5hbGxvd0NvZGVFeGVjdXRpb24pKSB7XHJcbiAgICAgICAgcmV0dXJuIGRvU3RyYWlnaHRJbmplY3Qob3B0aW9ucywgZW5kQ2FsbGJhY2spO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBFaXRoZXIgdHJ5IHRvIHBhcnNlIHRvIEpTT04gZmlyc3Qgb3IgZG8gdGhlIGRpcmVjdCBleHBvcnRcclxuICAgICAgcmV0dXJuIHR5cGVvZiBleHBvcnRPcHRpb25zLmluc3RyID09PSAnc3RyaW5nJ1xyXG4gICAgICAgID8gZXhwb3J0QXNTdHJpbmcoZXhwb3J0T3B0aW9ucy5pbnN0ci50cmltKCksIG9wdGlvbnMsIGVuZENhbGxiYWNrKVxyXG4gICAgICAgIDogZG9FeHBvcnQoXHJcbiAgICAgICAgICAgIG9wdGlvbnMsXHJcbiAgICAgICAgICAgIGV4cG9ydE9wdGlvbnMuaW5zdHIgfHwgZXhwb3J0T3B0aW9ucy5vcHRpb25zLFxyXG4gICAgICAgICAgICBlbmRDYWxsYmFja1xyXG4gICAgICAgICAgKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgICAgICBuZXcgRXhwb3J0RXJyb3IoJ1tjaGFydF0gRXJyb3IgbG9hZGluZyByYXcgaW5wdXQuJykuc2V0RXJyb3IoZXJyb3IpXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBObyBpbnB1dCBzcGVjaWZpZWQsIHBhc3MgYW4gZXJyb3IgbWVzc2FnZSB0byB0aGUgY2FsbGJhY2tcclxuICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgIGBbY2hhcnRdIE5vIHZhbGlkIGlucHV0IHNwZWNpZmllZC4gQ2hlY2sgaWYgYXQgbGVhc3Qgb25lIG9mIHRoZSBmb2xsb3dpbmcgcGFyYW1ldGVycyBpcyBjb3JyZWN0bHkgc2V0OiAnaW5maWxlJywgJ2luc3RyJywgJ29wdGlvbnMnLCBvciAnc3ZnJy5gXHJcbiAgICApXHJcbiAgKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgYSBiYXRjaCBleHBvcnQgcHJvY2VzcyBmb3IgbXVsdGlwbGUgY2hhcnRzIGJhc2VkIG9uIHRoZSBpbmZvcm1hdGlvblxyXG4gKiBpbiB0aGUgYmF0Y2ggb3B0aW9uLiBUaGUgYmF0Y2ggaXMgYSBzdHJpbmcgaW4gdGhlIGZvbGxvd2luZyBmb3JtYXQ6XHJcbiAqIFwiaW5maWxlMS5qc29uPW91dGZpbGUxLnBuZztpbmZpbGUyLmpzb249b3V0ZmlsZTIucG5nOy4uLlwiXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IGNvbnRhaW5pbmcgY29uZmlndXJhdGlvbiBmb3JcclxuICogYSBiYXRjaCBleHBvcnQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBiYXRjaCBleHBvcnRcclxuICogcHJvY2VzcyBpcyBjb21wbGV0ZWQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgYW4gZXJyb3Igb2NjdXJzIGR1cmluZ1xyXG4gKiBhbnkgb2YgdGhlIGJhdGNoIGV4cG9ydCBwcm9jZXNzLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGJhdGNoRXhwb3J0ID0gYXN5bmMgKG9wdGlvbnMpID0+IHtcclxuICBjb25zdCBiYXRjaEZ1bmN0aW9ucyA9IFtdO1xyXG5cclxuICAvLyBTcGxpdCBhbmQgcGFpciB0aGUgLS1iYXRjaCBhcmd1bWVudHNcclxuICBmb3IgKGxldCBwYWlyIG9mIG9wdGlvbnMuZXhwb3J0LmJhdGNoLnNwbGl0KCc7JykpIHtcclxuICAgIHBhaXIgPSBwYWlyLnNwbGl0KCc9Jyk7XHJcbiAgICBpZiAocGFpci5sZW5ndGggPT09IDIpIHtcclxuICAgICAgYmF0Y2hGdW5jdGlvbnMucHVzaChcclxuICAgICAgICBzdGFydEV4cG9ydChcclxuICAgICAgICAgIHtcclxuICAgICAgICAgICAgLi4ub3B0aW9ucyxcclxuICAgICAgICAgICAgZXhwb3J0OiB7XHJcbiAgICAgICAgICAgICAgLi4ub3B0aW9ucy5leHBvcnQsXHJcbiAgICAgICAgICAgICAgaW5maWxlOiBwYWlyWzBdLFxyXG4gICAgICAgICAgICAgIG91dGZpbGU6IHBhaXJbMV1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSxcclxuICAgICAgICAgIChlcnJvciwgaW5mbykgPT4ge1xyXG4gICAgICAgICAgICAvLyBUaHJvdyBhbiBlcnJvclxyXG4gICAgICAgICAgICBpZiAoZXJyb3IpIHtcclxuICAgICAgICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgLy8gU2F2ZSB0aGUgYmFzZTY0IGZyb20gYSBidWZmZXIgdG8gYSBjb3JyZWN0IGltYWdlIGZpbGVcclxuICAgICAgICAgICAgd3JpdGVGaWxlU3luYyhcclxuICAgICAgICAgICAgICBpbmZvLm9wdGlvbnMuZXhwb3J0Lm91dGZpbGUsXHJcbiAgICAgICAgICAgICAgQnVmZmVyLmZyb20oaW5mby5yZXN1bHQsICdiYXNlNjQnKVxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIClcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHRyeSB7XHJcbiAgICAvLyBBd2FpdCBhbGwgZXhwb3J0cyBhcmUgZG9uZVxyXG4gICAgYXdhaXQgUHJvbWlzZS5hbGwoYmF0Y2hGdW5jdGlvbnMpO1xyXG5cclxuICAgIC8vIEtpbGwgcG9vbCBhbmQgY2xvc2UgYnJvd3NlciBhZnRlciBmaW5pc2hpbmcgYmF0Y2ggZXhwb3J0XHJcbiAgICBhd2FpdCBraWxsUG9vbCgpO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbY2hhcnRdIEVycm9yIGVuY291bnRlcmVkIGR1cmluZyBiYXRjaCBleHBvcnQuJ1xyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIFN0YXJ0cyBhIHNpbmdsZSBleHBvcnQgcHJvY2VzcyBiYXNlZCBvbiB0aGUgc3BlY2lmaWVkIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IGNvbnRhaW5pbmcgY29uZmlndXJhdGlvbiBmb3JcclxuICogYSBzaW5nbGUgZXhwb3J0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgc2luZ2xlIGV4cG9ydFxyXG4gKiBwcm9jZXNzIGlzIGNvbXBsZXRlZC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiBhbiBlcnJvciBvY2N1cnMgZHVyaW5nXHJcbiAqIHRoZSBzaW5nbGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2luZ2xlRXhwb3J0ID0gYXN5bmMgKG9wdGlvbnMpID0+IHtcclxuICAvLyBVc2UgaW5zdHIgb3IgaXRzIGFsaWFzLCBvcHRpb25zXHJcbiAgb3B0aW9ucy5leHBvcnQuaW5zdHIgPSBvcHRpb25zLmV4cG9ydC5pbnN0ciB8fCBvcHRpb25zLmV4cG9ydC5vcHRpb25zO1xyXG5cclxuICAvLyBQZXJmb3JtIGFuIGV4cG9ydFxyXG4gIGF3YWl0IHN0YXJ0RXhwb3J0KG9wdGlvbnMsIGFzeW5jIChlcnJvciwgaW5mbykgPT4ge1xyXG4gICAgLy8gRXhpdCBwcm9jZXNzIHdoZW4gZXJyb3JcclxuICAgIGlmIChlcnJvcikge1xyXG4gICAgICB0aHJvdyBlcnJvcjtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCB7IG91dGZpbGUsIHR5cGUgfSA9IGluZm8ub3B0aW9ucy5leHBvcnQ7XHJcblxyXG4gICAgLy8gU2F2ZSB0aGUgYmFzZTY0IGZyb20gYSBidWZmZXIgdG8gYSBjb3JyZWN0IGltYWdlIGZpbGVcclxuICAgIHdyaXRlRmlsZVN5bmMoXHJcbiAgICAgIG91dGZpbGUgfHwgYGNoYXJ0LiR7dHlwZX1gLFxyXG4gICAgICB0eXBlICE9PSAnc3ZnJyA/IEJ1ZmZlci5mcm9tKGluZm8ucmVzdWx0LCAnYmFzZTY0JykgOiBpbmZvLnJlc3VsdFxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBLaWxsIHRoZSBwb29sXHJcbiAgICBhd2FpdCBraWxsUG9vbCgpO1xyXG4gIH0pO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIERldGVybWluZXMgdGhlIHNpemUgYW5kIHNjYWxlIGZvciBjaGFydCBleHBvcnQgYmFzZWQgb24gdGhlIHByb3ZpZGVkIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IGNvbnRhaW5pbmcgY29uZmlndXJhdGlvbiBmb3JcclxuICogY2hhcnQgZXhwb3J0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBBbiBvYmplY3QgY29udGFpbmluZyB0aGUgY2FsY3VsYXRlZCBoZWlnaHQsIHdpZHRoLFxyXG4gKiBhbmQgc2NhbGUgZm9yIHRoZSBjaGFydCBleHBvcnQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZmluZENoYXJ0U2l6ZSA9IChvcHRpb25zKSA9PiB7XHJcbiAgY29uc3QgeyBjaGFydCwgZXhwb3J0aW5nIH0gPVxyXG4gICAgb3B0aW9ucy5leHBvcnQ/Lm9wdGlvbnMgfHwgaXNDb3JyZWN0SlNPTihvcHRpb25zLmV4cG9ydD8uaW5zdHIpO1xyXG5cclxuICAvLyBTZWUgaWYgZ2xvYmFsT3B0aW9ucyBob2xkcyBjaGFydCBvciBleHBvcnRpbmcgc2l6ZVxyXG4gIGNvbnN0IGdsb2JhbE9wdGlvbnMgPSBpc0NvcnJlY3RKU09OKG9wdGlvbnMuZXhwb3J0Py5nbG9iYWxPcHRpb25zKTtcclxuXHJcbiAgLy8gU2VjdXJlIHNjYWxlIHZhbHVlXHJcbiAgbGV0IHNjYWxlID1cclxuICAgIG9wdGlvbnMuZXhwb3J0Py5zY2FsZSB8fFxyXG4gICAgZXhwb3J0aW5nPy5zY2FsZSB8fFxyXG4gICAgZ2xvYmFsT3B0aW9ucz8uZXhwb3J0aW5nPy5zY2FsZSB8fFxyXG4gICAgb3B0aW9ucy5leHBvcnQ/LmRlZmF1bHRTY2FsZSB8fFxyXG4gICAgMTtcclxuXHJcbiAgLy8gdGhlIHNjYWxlIGNhbm5vdCBiZSBsb3dlciB0aGFuIDAuMSBhbmQgY2Fubm90IGJlIGhpZ2hlciB0aGFuIDUuMFxyXG4gIHNjYWxlID0gTWF0aC5tYXgoMC4xLCBNYXRoLm1pbihzY2FsZSwgNS4wKSk7XHJcblxyXG4gIC8vIHdlIHdhbnQgdG8gcm91bmQgdGhlIG51bWJlcnMgbGlrZSAwLjIzMjM0IC0+IDAuMjNcclxuICBzY2FsZSA9IHJvdW5kTnVtYmVyKHNjYWxlLCAyKTtcclxuXHJcbiAgLy8gRmluZCBjaGFydCBzaXplIGFuZCBzY2FsZVxyXG4gIGNvbnN0IHNpemUgPSB7XHJcbiAgICBoZWlnaHQ6XHJcbiAgICAgIG9wdGlvbnMuZXhwb3J0Py5oZWlnaHQgfHxcclxuICAgICAgZXhwb3J0aW5nPy5zb3VyY2VIZWlnaHQgfHxcclxuICAgICAgY2hhcnQ/LmhlaWdodCB8fFxyXG4gICAgICBnbG9iYWxPcHRpb25zPy5leHBvcnRpbmc/LnNvdXJjZUhlaWdodCB8fFxyXG4gICAgICBnbG9iYWxPcHRpb25zPy5jaGFydD8uaGVpZ2h0IHx8XHJcbiAgICAgIG9wdGlvbnMuZXhwb3J0Py5kZWZhdWx0SGVpZ2h0IHx8XHJcbiAgICAgIDQwMCxcclxuICAgIHdpZHRoOlxyXG4gICAgICBvcHRpb25zLmV4cG9ydD8ud2lkdGggfHxcclxuICAgICAgZXhwb3J0aW5nPy5zb3VyY2VXaWR0aCB8fFxyXG4gICAgICBjaGFydD8ud2lkdGggfHxcclxuICAgICAgZ2xvYmFsT3B0aW9ucz8uZXhwb3J0aW5nPy5zb3VyY2VXaWR0aCB8fFxyXG4gICAgICBnbG9iYWxPcHRpb25zPy5jaGFydD8ud2lkdGggfHxcclxuICAgICAgb3B0aW9ucy5leHBvcnQ/LmRlZmF1bHRXaWR0aCB8fFxyXG4gICAgICA2MDAsXHJcbiAgICBzY2FsZVxyXG4gIH07XHJcblxyXG4gIC8vIEdldCByaWQgb2YgcG90ZW50aWFsIHB4IGFuZCAlXHJcbiAgZm9yIChsZXQgW3BhcmFtLCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMoc2l6ZSkpIHtcclxuICAgIHNpemVbcGFyYW1dID1cclxuICAgICAgdHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJyA/ICt2YWx1ZS5yZXBsYWNlKC9weHwlL2dpLCAnJykgOiB2YWx1ZTtcclxuICB9XHJcbiAgcmV0dXJuIHNpemU7XHJcbn07XHJcblxyXG4vKipcclxuICogRnVuY3Rpb24gZm9yIGZpbmFsaXppbmcgb3B0aW9ucyBiZWZvcmUgZXhwb3J0LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBvcHRpb25zIG9iamVjdCBjb250YWluaW5nIGNvbmZpZ3VyYXRpb24gZm9yXHJcbiAqIHRoZSBleHBvcnQgcHJvY2Vzcy5cclxuICogQHBhcmFtIHtPYmplY3R9IGNoYXJ0SnNvbiAtIFRoZSBKU09OIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBjaGFydC5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gZW5kQ2FsbGJhY2sgLSBUaGUgY2FsbGJhY2sgZnVuY3Rpb24gdG8gYmUgY2FsbGVkIHVwb25cclxuICogY29tcGxldGlvbiBvciBlcnJvci5cclxuICogQHBhcmFtIHtzdHJpbmd9IHN2ZyAtIFRoZSBTVkcgcmVwcmVzZW50YXRpb24gb2YgdGhlIGNoYXJ0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgZXhwb3J0IHByb2Nlc3NcclxuICogaXMgY29tcGxldGVkLlxyXG4gKi9cclxuY29uc3QgZG9FeHBvcnQgPSBhc3luYyAob3B0aW9ucywgY2hhcnRKc29uLCBlbmRDYWxsYmFjaywgc3ZnKSA9PiB7XHJcbiAgbGV0IHsgZXhwb3J0OiBleHBvcnRPcHRpb25zLCBjdXN0b21Mb2dpYzogY3VzdG9tTG9naWNPcHRpb25zIH0gPSBvcHRpb25zO1xyXG5cclxuICBjb25zdCBhbGxvd0NvZGVFeGVjdXRpb25TY29wZWQgPVxyXG4gICAgdHlwZW9mIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0NvZGVFeGVjdXRpb24gPT09ICdib29sZWFuJ1xyXG4gICAgICA/IGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0NvZGVFeGVjdXRpb25cclxuICAgICAgOiBhbGxvd0NvZGVFeGVjdXRpb247XHJcblxyXG4gIGlmICghY3VzdG9tTG9naWNPcHRpb25zKSB7XHJcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMgPSBvcHRpb25zLmN1c3RvbUxvZ2ljID0ge307XHJcbiAgfSBlbHNlIGlmIChhbGxvd0NvZGVFeGVjdXRpb25TY29wZWQpIHtcclxuICAgIGlmICh0eXBlb2Ygb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXMgPT09ICdzdHJpbmcnKSB7XHJcbiAgICAgIC8vIFByb2Nlc3MgcmVzb3VyY2VzXHJcbiAgICAgIG9wdGlvbnMuY3VzdG9tTG9naWMucmVzb3VyY2VzID0gaGFuZGxlUmVzb3VyY2VzKFxyXG4gICAgICAgIG9wdGlvbnMuY3VzdG9tTG9naWMucmVzb3VyY2VzLFxyXG4gICAgICAgIHRvQm9vbGVhbihvcHRpb25zLmN1c3RvbUxvZ2ljLmFsbG93RmlsZVJlc291cmNlcylcclxuICAgICAgKTtcclxuICAgIH0gZWxzZSBpZiAoIW9wdGlvbnMuY3VzdG9tTG9naWMucmVzb3VyY2VzKSB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgY29uc3QgcmVzb3VyY2VzID0gcmVhZEZpbGVTeW5jKCdyZXNvdXJjZXMuanNvbicsICd1dGY4Jyk7XHJcbiAgICAgICAgb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXMgPSBoYW5kbGVSZXNvdXJjZXMoXHJcbiAgICAgICAgICByZXNvdXJjZXMsXHJcbiAgICAgICAgICB0b0Jvb2xlYW4ob3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0ZpbGVSZXNvdXJjZXMpXHJcbiAgICAgICAgKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgICAyLFxyXG4gICAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgICBgW2NoYXJ0XSBVbmFibGUgdG8gbG9hZCB0aGUgZGVmYXVsdCByZXNvdXJjZXMuanNvbiBmaWxlLmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBJZiB0aGUgYWxsb3dDb2RlRXhlY3V0aW9uIGZsYWcgaXNuJ3Qgc2V0LCB3ZSBzaG91bGQgcmVmdXNlIHRoZSB1c2FnZVxyXG4gIC8vIG9mIGNhbGxiYWNrLCByZXNvdXJjZXMsIGFuZCBjdXN0b20gY29kZS4gQWRkaXRpb25hbGx5LCB0aGUgd29ya2VyIHdpbGxcclxuICAvLyByZWZ1c2UgdG8gcnVuIGFyYml0cmFyeSBKYXZhU2NyaXB0LiBQcmlvcml0aXplZCBzaG91bGQgYmUgdGhlIHNjb3BlZFxyXG4gIC8vIG9wdGlvbiwgdGhlbiB3ZSBzaG91bGQgdGFrZSBhIGxvb2sgYXQgdGhlIG92ZXJhbGwgcG9vbCBvcHRpb24uXHJcbiAgaWYgKCFhbGxvd0NvZGVFeGVjdXRpb25TY29wZWQgJiYgY3VzdG9tTG9naWNPcHRpb25zKSB7XHJcbiAgICBpZiAoXHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayB8fFxyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzIHx8XHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlXHJcbiAgICApIHtcclxuICAgICAgLy8gU2VuZCBiYWNrIGEgZnJpZW5kbHkgbWVzc2FnZSBzYXlpbmcgdGhhdCB0aGUgZXhwb3J0ZXIgZG9lcyBub3Qgc3VwcG9ydFxyXG4gICAgICAvLyB0aGVzZSBzZXR0aW5ncy5cclxuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKFxyXG4gICAgICAgIG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgIGBbY2hhcnRdIFRoZSAnY2FsbGJhY2snLCAncmVzb3VyY2VzJyBhbmQgJ2N1c3RvbUNvZGUnIG9wdGlvbnMgaGF2ZSBiZWVuIGRpc2FibGVkIGZvciB0aGlzIHNlcnZlci5gXHJcbiAgICAgICAgKVxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFJlc2V0IGFsbCBhZGRpdGlvbmFsIGN1c3RvbSBjb2RlXHJcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSBmYWxzZTtcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXMgPSBmYWxzZTtcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlID0gZmFsc2U7XHJcbiAgfVxyXG5cclxuICAvLyBDbGVhbiBwcm9wZXJ0aWVzIHRvIGtlZXAgaXQgbGVhbiBhbmQgbWVhblxyXG4gIGlmIChjaGFydEpzb24pIHtcclxuICAgIGNoYXJ0SnNvbi5jaGFydCA9IGNoYXJ0SnNvbi5jaGFydCB8fCB7fTtcclxuICAgIGNoYXJ0SnNvbi5leHBvcnRpbmcgPSBjaGFydEpzb24uZXhwb3J0aW5nIHx8IHt9O1xyXG4gICAgY2hhcnRKc29uLmV4cG9ydGluZy5lbmFibGVkID0gZmFsc2U7XHJcbiAgfVxyXG5cclxuICBleHBvcnRPcHRpb25zLmNvbnN0ciA9IGV4cG9ydE9wdGlvbnMuY29uc3RyIHx8ICdjaGFydCc7XHJcbiAgZXhwb3J0T3B0aW9ucy50eXBlID0gZml4VHlwZShleHBvcnRPcHRpb25zLnR5cGUsIGV4cG9ydE9wdGlvbnMub3V0ZmlsZSk7XHJcbiAgaWYgKGV4cG9ydE9wdGlvbnMudHlwZSA9PT0gJ3N2ZycpIHtcclxuICAgIGV4cG9ydE9wdGlvbnMud2lkdGggPSBmYWxzZTtcclxuICB9XHJcblxyXG4gIC8vIFByZXBhcmUgZ2xvYmFsIGFuZCB0aGVtZSBvcHRpb25zXHJcbiAgWydnbG9iYWxPcHRpb25zJywgJ3RoZW1lT3B0aW9ucyddLmZvckVhY2goKG9wdGlvbnNOYW1lKSA9PiB7XHJcbiAgICB0cnkge1xyXG4gICAgICBpZiAoZXhwb3J0T3B0aW9ucyAmJiBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSkge1xyXG4gICAgICAgIGlmIChcclxuICAgICAgICAgIHR5cGVvZiBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9PT0gJ3N0cmluZycgJiZcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdLmVuZHNXaXRoKCcuanNvbicpXHJcbiAgICAgICAgKSB7XHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9IGlzQ29ycmVjdEpTT04oXHJcbiAgICAgICAgICAgIHJlYWRGaWxlU3luYyhleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSwgJ3V0ZjgnKSxcclxuICAgICAgICAgICAgdHJ1ZVxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPSBpc0NvcnJlY3RKU09OKFxyXG4gICAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSxcclxuICAgICAgICAgICAgdHJ1ZVxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID0ge307XHJcbiAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgYFtjaGFydF0gVGhlICcke29wdGlvbnNOYW1lfScgY2Fubm90IGJlIGxvYWRlZC5gKTtcclxuICAgIH1cclxuICB9KTtcclxuXHJcbiAgLy8gUHJlcGFyZSB0aGUgY3VzdG9tQ29kZVxyXG4gIGlmIChjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dDb2RlRXhlY3V0aW9uKSB7XHJcbiAgICB0cnkge1xyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSA9IHdyYXBBcm91bmQoXHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUsXHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmFsbG93RmlsZVJlc291cmNlc1xyXG4gICAgICApO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2NoYXJ0XSBUaGUgJ2N1c3RvbUNvZGUnIGNhbm5vdCBiZSBsb2FkZWQuYCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBHZXQgdGhlIGNhbGxiYWNrXHJcbiAgaWYgKFxyXG4gICAgY3VzdG9tTG9naWNPcHRpb25zICYmXHJcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgJiZcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjaz8uaW5kZXhPZigneycpIDwgMFxyXG4gICkge1xyXG4gICAgLy8gVGhlIGFsbG93RmlsZVJlc291cmNlcyBpcyBhbHdheXMgc2V0IHRvIGZhbHNlIGZvciBIVFRQIHJlcXVlc3RzIHRvIGF2b2lkXHJcbiAgICAvLyBpbmplY3RpbmcgYXJiaXRyYXJ5IGZpbGVzIGZyb20gdGhlIGZzXHJcbiAgICBpZiAoY3VzdG9tTG9naWNPcHRpb25zLmFsbG93RmlsZVJlc291cmNlcykge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IHJlYWRGaWxlU3luYyhcclxuICAgICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayxcclxuICAgICAgICAgICd1dGY4J1xyXG4gICAgICAgICk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrID0gZmFsc2U7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2NoYXJ0XSBUaGUgJ2NhbGxiYWNrJyBjYW5ub3QgYmUgbG9hZGVkLmApO1xyXG4gICAgICB9XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSBmYWxzZTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFNpemUgc2VhcmNoXHJcbiAgb3B0aW9ucy5leHBvcnQgPSB7XHJcbiAgICAuLi5vcHRpb25zLmV4cG9ydCxcclxuICAgIC4uLmZpbmRDaGFydFNpemUob3B0aW9ucylcclxuICB9O1xyXG5cclxuICAvLyBQb3N0IHRoZSB3b3JrIHRvIHRoZSBwb29sXHJcbiAgdHJ5IHtcclxuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHBvc3RXb3JrKFxyXG4gICAgICBleHBvcnRPcHRpb25zLnN0ckluaiB8fCBjaGFydEpzb24gfHwgc3ZnLFxyXG4gICAgICBvcHRpb25zXHJcbiAgICApO1xyXG4gICAgcmV0dXJuIGVuZENhbGxiYWNrKGZhbHNlLCByZXN1bHQpO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICByZXR1cm4gZW5kQ2FsbGJhY2soZXJyb3IpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBQZXJmb3JtcyBhIGRpcmVjdCBpbmplY3Qgb2Ygb3B0aW9ucyBiZWZvcmUgZXhwb3J0LiBUaGUgZnVuY3Rpb24gYXR0ZW1wdHNcclxuICogdG8gc3RyaW5naWZ5IHRoZSBwcm92aWRlZCBvcHRpb25zIGFuZCByZW1vdmVzIHVubmVjZXNzYXJ5IGNoYXJhY3RlcnMsXHJcbiAqIGVuc3VyaW5nIGEgY2xlYW4gYW5kIGZvcm1hdHRlZCBpbnB1dC4gVGhlIHJlc3VsdGluZyBzdHJpbmcgaXMgc2F2ZWQgYXNcclxuICogYSBcInN0cmlnaHQgaW5qZWN0XCIgc3RyaW5nIGluIHRoZSBleHBvcnQgb3B0aW9ucy4gSXQgdGhlbiBpbnZva2VzIHRoZVxyXG4gKiBkb0V4cG9ydCBmdW5jdGlvbiB3aXRoIHRoZSB1cGRhdGVkIG9wdGlvbnMuXHJcbiAqXHJcbiAqIElNUE9SVEFOVDogRGFuZ2Vyb3VzIGFuZCBtdXN0IGJlIHVzZWQgZGVsaWJlcmF0ZWx5IGJ5IHNvbWVvbmUgd2hvIHNldHMgdXBcclxuICogYSBzZXJ2ZXIgKHNlZSB0aGUgIC0tYWxsb3dDb2RlRXhlY3V0aW9uIG9wdGlvbikuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIGV4cG9ydCBvcHRpb25zIGNvbnRhaW5pbmcgdGhlIGlucHV0XHJcbiAqIHRvIGJlIGluamVjdGVkLlxyXG4gKiBAcGFyYW0ge2Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIFRoZSBjYWxsYmFjayBmdW5jdGlvbiB0byBiZSBpbnZva2VkXHJcbiAqIGF0IHRoZSBlbmQgb2YgdGhlIHByb2Nlc3MuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlfSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB3aXRoIHRoZSByZXN1bHQgb2YgdGhlIGV4cG9ydFxyXG4gKiBvcGVyYXRpb24gb3IgcmVqZWN0cyB3aXRoIGFuIGVycm9yIGlmIGFueSBpc3N1ZXMgb2NjdXIgZHVyaW5nIHRoZSBwcm9jZXNzLlxyXG4gKi9cclxuY29uc3QgZG9TdHJhaWdodEluamVjdCA9IChvcHRpb25zLCBlbmRDYWxsYmFjaykgPT4ge1xyXG4gIHRyeSB7XHJcbiAgICBsZXQgc3RySW5qO1xyXG4gICAgbGV0IGluc3RyID0gb3B0aW9ucy5leHBvcnQuaW5zdHIgfHwgb3B0aW9ucy5leHBvcnQub3B0aW9ucztcclxuXHJcbiAgICBpZiAodHlwZW9mIGluc3RyICE9PSAnc3RyaW5nJykge1xyXG4gICAgICAvLyBUcnkgdG8gc3RyaW5naWZ5IG9wdGlvbnNcclxuICAgICAgc3RySW5qID0gaW5zdHIgPSBvcHRpb25zU3RyaW5naWZ5KFxyXG4gICAgICAgIGluc3RyLFxyXG4gICAgICAgIG9wdGlvbnMuY3VzdG9tTG9naWM/LmFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gICAgc3RySW5qID0gaW5zdHIucmVwbGFjZUFsbCgvXFx0fFxcbnxcXHIvZywgJycpLnRyaW0oKTtcclxuXHJcbiAgICAvLyBHZXQgcmlkIG9mIHRoZSA7XHJcbiAgICBpZiAoc3RySW5qW3N0ckluai5sZW5ndGggLSAxXSA9PT0gJzsnKSB7XHJcbiAgICAgIHN0ckluaiA9IHN0ckluai5zdWJzdHJpbmcoMCwgc3RySW5qLmxlbmd0aCAtIDEpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFNhdmUgYXMgc3RyaWdodCBpbmplY3Qgc3RyaW5nXHJcbiAgICBvcHRpb25zLmV4cG9ydC5zdHJJbmogPSBzdHJJbmo7XHJcbiAgICByZXR1cm4gZG9FeHBvcnQob3B0aW9ucywgZmFsc2UsIGVuZENhbGxiYWNrKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgcmV0dXJuIGVuZENhbGxiYWNrKFxyXG4gICAgICBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgYFtjaGFydF0gTWFsZm9ybWVkIGlucHV0IGRldGVjdGVkIGZvciAke29wdGlvbnMuZXhwb3J0Py5yZXF1ZXN0SWQgfHwgJz8nfS4gUGxlYXNlIG1ha2Ugc3VyZSB0aGF0IHlvdXIgSlNPTi9KYXZhU2NyaXB0IG9wdGlvbnMgYXJlIHNlbnQgdXNpbmcgdGhlIFwib3B0aW9uc1wiIGF0dHJpYnV0ZSwgYW5kIHRoYXQgaWYgeW91J3JlIHVzaW5nIFNWRywgaXQgaXMgdW5lc2NhcGVkLmBcclxuICAgICAgKS5zZXRFcnJvcihlcnJvcilcclxuICAgICk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEV4cG9ydHMgYSBzdHJpbmcgYmFzZWQgb24gdGhlIHByb3ZpZGVkIG9wdGlvbnMgYW5kIGludm9rZXMgYW4gZW5kIGNhbGxiYWNrLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gc3RyaW5nVG9FeHBvcnQgLSBUaGUgc3RyaW5nIGNvbnRlbnQgdG8gYmUgZXhwb3J0ZWQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gRXhwb3J0IG9wdGlvbnMsIGluY2x1ZGluZyBjdXN0b21Mb2dpYyB3aXRoXHJcbiAqIGFsbG93Q29kZUV4ZWN1dGlvbiBmbGFnLlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIENhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGludm9rZWQgYXQgdGhlIGVuZFxyXG4gKiBvZiB0aGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHthbnl9IFJlc3VsdCBvZiB0aGUgZXhwb3J0IHByb2Nlc3Mgb3IgYW4gZXJyb3IgaWYgZW5jb3VudGVyZWQuXHJcbiAqL1xyXG5jb25zdCBleHBvcnRBc1N0cmluZyA9IChzdHJpbmdUb0V4cG9ydCwgb3B0aW9ucywgZW5kQ2FsbGJhY2spID0+IHtcclxuICBjb25zdCB7IGFsbG93Q29kZUV4ZWN1dGlvbiB9ID0gb3B0aW9ucy5jdXN0b21Mb2dpYztcclxuXHJcbiAgLy8gQ2hlY2sgaWYgaXQgaXMgU1ZHXHJcbiAgaWYgKFxyXG4gICAgc3RyaW5nVG9FeHBvcnQuaW5kZXhPZignPHN2ZycpID49IDAgfHxcclxuICAgIHN0cmluZ1RvRXhwb3J0LmluZGV4T2YoJzw/eG1sJykgPj0gMFxyXG4gICkge1xyXG4gICAgbG9nKDQsICdbY2hhcnRdIFBhcnNpbmcgaW5wdXQgYXMgU1ZHLicpO1xyXG4gICAgcmV0dXJuIGRvRXhwb3J0KG9wdGlvbnMsIGZhbHNlLCBlbmRDYWxsYmFjaywgc3RyaW5nVG9FeHBvcnQpO1xyXG4gIH1cclxuXHJcbiAgdHJ5IHtcclxuICAgIC8vIFRyeSB0byBwYXJzZSB0byBKU09OIGFuZCBjYWxsIHRoZSBkb0V4cG9ydCBmdW5jdGlvblxyXG4gICAgY29uc3QgY2hhcnRKU09OID0gSlNPTi5wYXJzZShzdHJpbmdUb0V4cG9ydC5yZXBsYWNlQWxsKC9cXHR8XFxufFxcci9nLCAnICcpKTtcclxuXHJcbiAgICAvLyBJZiBhIGNvcnJlY3QgSlNPTiwgZG8gdGhlIGV4cG9ydFxyXG4gICAgcmV0dXJuIGRvRXhwb3J0KG9wdGlvbnMsIGNoYXJ0SlNPTiwgZW5kQ2FsbGJhY2spO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAvLyBOb3QgYSB2YWxpZCBKU09OXHJcbiAgICBpZiAodG9Cb29sZWFuKGFsbG93Q29kZUV4ZWN1dGlvbikpIHtcclxuICAgICAgcmV0dXJuIGRvU3RyYWlnaHRJbmplY3Qob3B0aW9ucywgZW5kQ2FsbGJhY2spO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gRG8gbm90IGFsbG93IHN0cmFpZ2h0IGluamVjdGlvbiB3aXRob3V0IHRoZSBhbGxvd0NvZGVFeGVjdXRpb24gZmxhZ1xyXG4gICAgICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICAgICAgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgJ1tjaGFydF0gT25seSBKU09OIGNvbmZpZ3VyYXRpb25zIGFuZCBTVkcgYXJlIGFsbG93ZWQgZm9yIHRoaXMgc2VydmVyLiBJZiB0aGlzIGlzIHlvdXIgc2VydmVyLCBKYXZhU2NyaXB0IGN1c3RvbSBjb2RlIGNhbiBiZSBlbmFibGVkIGJ5IHN0YXJ0aW5nIHRoZSBzZXJ2ZXIgd2l0aCB0aGUgLS1hbGxvd0NvZGVFeGVjdXRpb24gZmxhZy4nXHJcbiAgICAgICAgKS5zZXRFcnJvcihlcnJvcilcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIGFuZCByZXR1cm5zIHRoZSBjdXJyZW50IHN0YXR1cyBvZiBjb2RlIGV4ZWN1dGlvbiBwZXJtaXNzaW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7YW55fSBUaGUgdmFsdWUgb2YgYWxsb3dDb2RlRXhlY3V0aW9uLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldEFsbG93Q29kZUV4ZWN1dGlvbiA9ICgpID0+IGFsbG93Q29kZUV4ZWN1dGlvbjtcclxuXHJcbi8qKlxyXG4gKiBTZXRzIHRoZSBjb2RlIGV4ZWN1dGlvbiBwZXJtaXNzaW9uIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBib29sZWFuIHZhbHVlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge2FueX0gdmFsdWUgLSBUaGUgdmFsdWUgdG8gYmUgY29udmVydGVkIGFuZCBhc3NpZ25lZFxyXG4gKiB0byBhbGxvd0NvZGVFeGVjdXRpb24uXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2V0QWxsb3dDb2RlRXhlY3V0aW9uID0gKHZhbHVlKSA9PiB7XHJcbiAgYWxsb3dDb2RlRXhlY3V0aW9uID0gdG9Cb29sZWFuKHZhbHVlKTtcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBiYXRjaEV4cG9ydCxcclxuICBzaW5nbGVFeHBvcnQsXHJcbiAgZ2V0QWxsb3dDb2RlRXhlY3V0aW9uLFxyXG4gIHNldEFsbG93Q29kZUV4ZWN1dGlvbixcclxuICBzdGFydEV4cG9ydCxcclxuICBmaW5kQ2hhcnRTaXplXHJcbn07XHJcbiIsImltcG9ydCB7IGxvZ1dpdGhTdGFjayB9IGZyb20gJy4uL2xvZ2dlci5qcyc7XHJcblxyXG4vKipcclxuICogTWlkZGxld2FyZSBmb3IgbG9nZ2luZyBlcnJvcnMgd2l0aCBzdGFjayB0cmFjZSBhbmQgaGFuZGxpbmcgZXJyb3IgcmVzcG9uc2UuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXJyb3J9IGVycm9yIC0gVGhlIGVycm9yIG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcSAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlcyAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gbmV4dCAtIFRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXHJcbiAqL1xyXG5jb25zdCBsb2dFcnJvck1pZGRsZXdhcmUgPSAoZXJyb3IsIHJlcSwgcmVzLCBuZXh0KSA9PiB7XHJcbiAgLy8gRGlzcGxheSB0aGUgZXJyb3Igd2l0aCBzdGFjayBpbiBhIGNvcnJlY3QgZm9ybWF0XHJcbiAgbG9nV2l0aFN0YWNrKDEsIGVycm9yKTtcclxuXHJcbiAgLy8gRGVsZXRlIHRoZSBzdGFjayBmb3IgdGhlIGVudmlyb25tZW50IG90aGVyIHRoYW4gdGhlIGRldmVsb3BtZW50XHJcbiAgaWYgKHByb2Nlc3MuZW52Lk5PREVfRU5WICE9PSAnZGV2ZWxvcG1lbnQnKSB7XHJcbiAgICBkZWxldGUgZXJyb3Iuc3RhY2s7XHJcbiAgfVxyXG5cclxuICAvLyBDYWxsIHRoZSByZXR1cm5FcnJvck1pZGRsZXdhcmVcclxuICBuZXh0KGVycm9yKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBNaWRkbGV3YXJlIGZvciByZXR1cm5pbmcgZXJyb3IgcmVzcG9uc2UuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXJyb3J9IGVycm9yIC0gVGhlIGVycm9yIG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcSAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlcyAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gbmV4dCAtIFRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXHJcbiAqL1xyXG5jb25zdCByZXR1cm5FcnJvck1pZGRsZXdhcmUgPSAoZXJyb3IsIHJlcSwgcmVzLCBuZXh0KSA9PiB7XHJcbiAgLy8gR2F0aGVyIGFsbCByZXF1aWVkIGluZm9ybWF0aW9uIGZvciB0aGUgcmVzcG9uc2VcclxuICBjb25zdCB7IHN0YXR1c0NvZGU6IHN0Q29kZSwgc3RhdHVzLCBtZXNzYWdlLCBzdGFjayB9ID0gZXJyb3I7XHJcbiAgY29uc3Qgc3RhdHVzQ29kZSA9IHN0Q29kZSB8fCBzdGF0dXMgfHwgNTAwO1xyXG5cclxuICAvLyBTZXQgYW5kIHJldHVybiByZXNwb25zZVxyXG4gIHJlcy5zdGF0dXMoc3RhdHVzQ29kZSkuanNvbih7IHN0YXR1c0NvZGUsIG1lc3NhZ2UsIHN0YWNrIH0pO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQgKGFwcCkgPT4ge1xyXG4gIC8vIEFkZCBsb2cgZXJyb3IgbWlkZGxld2FyZVxyXG4gIGFwcC51c2UobG9nRXJyb3JNaWRkbGV3YXJlKTtcclxuXHJcbiAgLy8gQWRkIHNldCBzdGF0dXMgYW5kIHJldHVybiBlcnJvciBtaWRkbGV3YXJlXHJcbiAgYXBwLnVzZShyZXR1cm5FcnJvck1pZGRsZXdhcmUpO1xyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCByYXRlTGltaXQgZnJvbSAnZXhwcmVzcy1yYXRlLWxpbWl0JztcclxuXHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4uL2xvZ2dlci5qcyc7XHJcblxyXG4vKipcclxuICogTWlkZGxld2FyZSBmb3IgZW5hYmxpbmcgcmF0ZSBsaW1pdGluZyBvbiB0aGUgc3BlY2lmaWVkIEV4cHJlc3MgYXBwLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3N9IGFwcCAtIFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICogQHBhcmFtIHtPYmplY3R9IGxpbWl0Q29uZmlnIC0gQ29uZmlndXJhdGlvbiBvcHRpb25zIGZvciByYXRlIGxpbWl0aW5nLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgKGFwcCwgbGltaXRDb25maWcpID0+IHtcclxuICBjb25zdCBtc2cgPVxyXG4gICAgJ1RvbyBtYW55IHJlcXVlc3RzLCB5b3UgaGF2ZSBiZWVuIHJhdGUgbGltaXRlZC4gUGxlYXNlIHRyeSBhZ2FpbiBsYXRlci4nO1xyXG5cclxuICAvLyBPcHRpb25zIGZvciB0aGUgcmF0ZSBsaW1pdGVyXHJcbiAgY29uc3QgcmF0ZU9wdGlvbnMgPSB7XHJcbiAgICBtYXg6IGxpbWl0Q29uZmlnLm1heFJlcXVlc3RzIHx8IDMwLFxyXG4gICAgd2luZG93OiBsaW1pdENvbmZpZy53aW5kb3cgfHwgMSxcclxuICAgIGRlbGF5OiBsaW1pdENvbmZpZy5kZWxheSB8fCAwLFxyXG4gICAgdHJ1c3RQcm94eTogbGltaXRDb25maWcudHJ1c3RQcm94eSB8fCBmYWxzZSxcclxuICAgIHNraXBLZXk6IGxpbWl0Q29uZmlnLnNraXBLZXkgfHwgZmFsc2UsXHJcbiAgICBza2lwVG9rZW46IGxpbWl0Q29uZmlnLnNraXBUb2tlbiB8fCBmYWxzZVxyXG4gIH07XHJcblxyXG4gIC8vIFNldCBpZiBiZWhpbmQgYSBwcm94eVxyXG4gIGlmIChyYXRlT3B0aW9ucy50cnVzdFByb3h5KSB7XHJcbiAgICBhcHAuZW5hYmxlKCd0cnVzdCBwcm94eScpO1xyXG4gIH1cclxuXHJcbiAgLy8gQ3JlYXRlIGEgbGltaXRlclxyXG4gIGNvbnN0IGxpbWl0ZXIgPSByYXRlTGltaXQoe1xyXG4gICAgd2luZG93TXM6IHJhdGVPcHRpb25zLndpbmRvdyAqIDYwICogMTAwMCxcclxuICAgIC8vIExpbWl0IGVhY2ggSVAgdG8gMTAwIHJlcXVlc3RzIHBlciB3aW5kb3dNc1xyXG4gICAgbWF4OiByYXRlT3B0aW9ucy5tYXgsXHJcbiAgICAvLyBEaXNhYmxlIGRlbGF5aW5nLCBmdWxsIHNwZWVkIHVudGlsIHRoZSBtYXggbGltaXQgaXMgcmVhY2hlZFxyXG4gICAgZGVsYXlNczogcmF0ZU9wdGlvbnMuZGVsYXksXHJcbiAgICBoYW5kbGVyOiAocmVxdWVzdCwgcmVzcG9uc2UpID0+IHtcclxuICAgICAgcmVzcG9uc2UuZm9ybWF0KHtcclxuICAgICAgICBqc29uOiAoKSA9PiB7XHJcbiAgICAgICAgICByZXNwb25zZS5zdGF0dXMoNDI5KS5zZW5kKHsgbWVzc2FnZTogbXNnIH0pO1xyXG4gICAgICAgIH0sXHJcbiAgICAgICAgZGVmYXVsdDogKCkgPT4ge1xyXG4gICAgICAgICAgcmVzcG9uc2Uuc3RhdHVzKDQyOSkuc2VuZChtc2cpO1xyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcbiAgICB9LFxyXG4gICAgc2tpcDogKHJlcXVlc3QpID0+IHtcclxuICAgICAgLy8gQWxsb3cgYnlwYXNzaW5nIHRoZSBsaW1pdGVyIGlmIGEgdmFsaWQga2V5L3Rva2VuIGhhcyBiZWVuIHNlbnRcclxuICAgICAgaWYgKFxyXG4gICAgICAgIHJhdGVPcHRpb25zLnNraXBLZXkgIT09IGZhbHNlICYmXHJcbiAgICAgICAgcmF0ZU9wdGlvbnMuc2tpcFRva2VuICE9PSBmYWxzZSAmJlxyXG4gICAgICAgIHJlcXVlc3QucXVlcnkua2V5ID09PSByYXRlT3B0aW9ucy5za2lwS2V5ICYmXHJcbiAgICAgICAgcmVxdWVzdC5xdWVyeS5hY2Nlc3NfdG9rZW4gPT09IHJhdGVPcHRpb25zLnNraXBUb2tlblxyXG4gICAgICApIHtcclxuICAgICAgICBsb2coNCwgJ1tyYXRlIGxpbWl0aW5nXSBTa2lwcGluZyByYXRlIGxpbWl0ZXIuJyk7XHJcbiAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICAvLyBVc2UgYSBsaW1pdGVyIGFzIGEgbWlkZGxld2FyZVxyXG4gIGFwcC51c2UobGltaXRlcik7XHJcblxyXG4gIGxvZyhcclxuICAgIDMsXHJcbiAgICBgW3JhdGUgbGltaXRpbmddIEVuYWJsZWQgcmF0ZSBsaW1pdGluZyB3aXRoICR7cmF0ZU9wdGlvbnMubWF4fSByZXF1ZXN0cyBwZXIgJHtyYXRlT3B0aW9ucy53aW5kb3d9IG1pbnV0ZSBmb3IgZWFjaCBJUCwgdHJ1c3RpbmcgcHJveHk6ICR7cmF0ZU9wdGlvbnMudHJ1c3RQcm94eX0uYFxyXG4gICk7XHJcbn07XHJcbiIsImltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbmNsYXNzIEh0dHBFcnJvciBleHRlbmRzIEV4cG9ydEVycm9yIHtcclxuICBjb25zdHJ1Y3RvcihtZXNzYWdlLCBzdGF0dXMpIHtcclxuICAgIHN1cGVyKG1lc3NhZ2UpO1xyXG4gICAgdGhpcy5zdGF0dXMgPSB0aGlzLnN0YXR1c0NvZGUgPSBzdGF0dXM7XHJcbiAgfVxyXG5cclxuICBzZXRTdGF0dXMoc3RhdHVzKSB7XHJcbiAgICB0aGlzLnN0YXR1cyA9IHN0YXR1cztcclxuICAgIHJldHVybiB0aGlzO1xyXG4gIH1cclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQgSHR0cEVycm9yO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IHY0IGFzIHV1aWQgfSBmcm9tICd1dWlkJztcclxuXHJcbmltcG9ydCB7IGdldEFsbG93Q29kZUV4ZWN1dGlvbiwgc3RhcnRFeHBvcnQgfSBmcm9tICcuLi8uLi9jaGFydC5qcyc7XHJcbmltcG9ydCB7IGdldE9wdGlvbnMsIG1lcmdlQ29uZmlnT3B0aW9ucyB9IGZyb20gJy4uLy4uL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4uLy4uL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7XHJcbiAgZml4VHlwZSxcclxuICBpc0NvcnJlY3RKU09OLFxyXG4gIGlzT2JqZWN0RW1wdHksXHJcbiAgaXNQcml2YXRlUmFuZ2VVcmxGb3VuZCxcclxuICBvcHRpb25zU3RyaW5naWZ5LFxyXG4gIG1lYXN1cmVUaW1lXHJcbn0gZnJvbSAnLi4vLi4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IEh0dHBFcnJvciBmcm9tICcuLi8uLi9lcnJvcnMvSHR0cEVycm9yLmpzJztcclxuXHJcbi8vIFJldmVyc2VkIE1JTUUgdHlwZXNcclxuY29uc3QgcmV2ZXJzZWRNaW1lID0ge1xyXG4gIHBuZzogJ2ltYWdlL3BuZycsXHJcbiAganBlZzogJ2ltYWdlL2pwZWcnLFxyXG4gIGdpZjogJ2ltYWdlL2dpZicsXHJcbiAgcGRmOiAnYXBwbGljYXRpb24vcGRmJyxcclxuICBzdmc6ICdpbWFnZS9zdmcreG1sJ1xyXG59O1xyXG5cclxuLy8gVGhlIHJlcXVlc3RzIGNvdW50ZXJcclxubGV0IHJlcXVlc3RzQ291bnRlciA9IDA7XHJcblxyXG4vLyBUaGUgYXJyYXkgb2YgY2FsbGJhY2tzIHRvIGNhbGwgYmVmb3JlIGEgcmVxdWVzdFxyXG5jb25zdCBiZWZvcmVSZXF1ZXN0ID0gW107XHJcblxyXG4vLyBUaGUgYXJyYXkgb2YgY2FsbGJhY2tzIHRvIGNhbGwgYWZ0ZXIgYSByZXF1ZXN0XHJcbmNvbnN0IGFmdGVyUmVxdWVzdCA9IFtdO1xyXG5cclxuLyoqXHJcbiAqIEludm9rZXMgYW4gYXJyYXkgb2YgY2FsbGJhY2sgZnVuY3Rpb25zIHdpdGggc3BlY2lmaWVkIHBhcmFtZXRlcnMsIGFsbG93aW5nXHJcbiAqIGN1c3RvbWl6YXRpb24gb2YgcmVxdWVzdCBoYW5kbGluZy5cclxuICpcclxuICogQHBhcmFtIHtGdW5jdGlvbltdfSBjYWxsYmFja3MgLSBBbiBhcnJheSBvZiBjYWxsYmFjayBmdW5jdGlvbnNcclxuICogdG8gYmUgZXhlY3V0ZWQuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXF1ZXN0IC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzcG9uc2UgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBkYXRhIC0gQW4gb2JqZWN0IGNvbnRhaW5pbmcgcGFyYW1ldGVycyBsaWtlIGlkLCB1bmlxdWVJZCxcclxuICogdHlwZSwgYW5kIGJvZHkuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtib29sZWFufSAtIFJldHVybnMgYSBib29sZWFuIGluZGljYXRpbmcgdGhlIG92ZXJhbGwgcmVzdWx0XHJcbiAqIG9mIHRoZSBjYWxsYmFjayBpbnZvY2F0aW9ucy5cclxuICovXHJcbmNvbnN0IGRvQ2FsbGJhY2tzID0gKGNhbGxiYWNrcywgcmVxdWVzdCwgcmVzcG9uc2UsIGRhdGEpID0+IHtcclxuICBsZXQgcmVzdWx0ID0gdHJ1ZTtcclxuICBjb25zdCB7IGlkLCB1bmlxdWVJZCwgdHlwZSwgYm9keSB9ID0gZGF0YTtcclxuXHJcbiAgY2FsbGJhY2tzLnNvbWUoKGNhbGxiYWNrKSA9PiB7XHJcbiAgICBpZiAoY2FsbGJhY2spIHtcclxuICAgICAgbGV0IGNhbGxSZXNwb25zZSA9IGNhbGxiYWNrKHJlcXVlc3QsIHJlc3BvbnNlLCBpZCwgdW5pcXVlSWQsIHR5cGUsIGJvZHkpO1xyXG5cclxuICAgICAgaWYgKGNhbGxSZXNwb25zZSAhPT0gdW5kZWZpbmVkICYmIGNhbGxSZXNwb25zZSAhPT0gdHJ1ZSkge1xyXG4gICAgICAgIHJlc3VsdCA9IGNhbGxSZXNwb25zZTtcclxuICAgICAgfVxyXG5cclxuICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICB9XHJcbiAgfSk7XHJcblxyXG4gIHJldHVybiByZXN1bHQ7XHJcbn07XHJcblxyXG4vKipcclxuICogSGFuZGxlcyB0aGUgZXhwb3J0IHJlcXVlc3RzIGZyb20gdGhlIGNsaWVudC5cclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcXVlc3QgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXNwb25zZSAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gbmV4dCAtIFRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgdGhlIGV4cG9ydCBwcm9jZXNzXHJcbiAqIGlzIGNvbXBsZXRlLlxyXG4gKi9cclxuY29uc3QgZXhwb3J0SGFuZGxlciA9IGFzeW5jIChyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkgPT4ge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBTdGFydCBjb3VudGluZyB0aW1lXHJcbiAgICBjb25zdCBzdG9wQ291bnRlciA9IG1lYXN1cmVUaW1lKCk7XHJcblxyXG4gICAgLy8gQ3JlYXRlIGEgdW5pcXVlIElEIGZvciBhIHJlcXVlc3RcclxuICAgIGNvbnN0IHVuaXF1ZUlkID0gdXVpZCgpLnJlcGxhY2UoLy0vZywgJycpO1xyXG5cclxuICAgIC8vIEdldCB0aGUgY3VycmVudCBzZXJ2ZXIncyBnZW5lcmFsIG9wdGlvbnNcclxuICAgIGNvbnN0IGRlZmF1bHRPcHRpb25zID0gZ2V0T3B0aW9ucygpO1xyXG5cclxuICAgIGNvbnN0IGJvZHkgPSByZXF1ZXN0LmJvZHk7XHJcbiAgICBjb25zdCBpZCA9ICsrcmVxdWVzdHNDb3VudGVyO1xyXG5cclxuICAgIGxldCB0eXBlID0gZml4VHlwZShib2R5LnR5cGUpO1xyXG5cclxuICAgIC8vIFRocm93ICdCYWQgUmVxdWVzdCcgaWYgdGhlcmUncyBubyBib2R5XHJcbiAgICBpZiAoIWJvZHkgfHwgaXNPYmplY3RFbXB0eShib2R5KSkge1xyXG4gICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgICdUaGUgcmVxdWVzdCBib2R5IGlzIHJlcXVpcmVkLiBQbGVhc2UgZW5zdXJlIHRoYXQgeW91ciBDb250ZW50LVR5cGUgaGVhZGVyIGlzIGNvcnJlY3QgKGFjY2VwdGVkIHR5cGVzIGFyZSBhcHBsaWNhdGlvbi9qc29uIGFuZCBtdWx0aXBhcnQvZm9ybS1kYXRhKS4nLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEFsbCBvZiB0aGUgYmVsb3cgY2FuIGJlIHVzZWRcclxuICAgIGxldCBpbnN0ciA9IGlzQ29ycmVjdEpTT04oYm9keS5pbmZpbGUgfHwgYm9keS5vcHRpb25zIHx8IGJvZHkuZGF0YSk7XHJcblxyXG4gICAgLy8gVGhyb3cgJ0JhZCBSZXF1ZXN0JyBpZiB0aGVyZSdzIG5vIEpTT04gb3IgU1ZHIHRvIGV4cG9ydFxyXG4gICAgaWYgKCFpbnN0ciAmJiAhYm9keS5zdmcpIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDIsXHJcbiAgICAgICAgYFRoZSByZXF1ZXN0IHdpdGggSUQgJHt1bmlxdWVJZH0gZnJvbSAke1xyXG4gICAgICAgICAgcmVxdWVzdC5oZWFkZXJzWyd4LWZvcndhcmRlZC1mb3InXSB8fCByZXF1ZXN0LmNvbm5lY3Rpb24ucmVtb3RlQWRkcmVzc1xyXG4gICAgICAgIH0gd2FzIGluY29ycmVjdC4gUGF5bG9hZCByZWNlaXZlZDogJHtKU09OLnN0cmluZ2lmeShib2R5KX0uYFxyXG4gICAgICApO1xyXG5cclxuICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICBcIk5vIGNvcnJlY3QgY2hhcnQgZGF0YSBmb3VuZC4gRW5zdXJlIHRoYXQgeW91IGFyZSB1c2luZyBlaXRoZXIgYXBwbGljYXRpb24vanNvbiBvciBtdWx0aXBhcnQvZm9ybS1kYXRhIGhlYWRlcnMuIElmIHNlbmRpbmcgSlNPTiwgbWFrZSBzdXJlIHRoZSBjaGFydCBkYXRhIGlzIGluIHRoZSAnaW5maWxlJywgJ29wdGlvbnMnLCBvciAnZGF0YScgYXR0cmlidXRlLiBJZiBzZW5kaW5nIFNWRywgZW5zdXJlIGl0IGlzIGluIHRoZSAnc3ZnJyBhdHRyaWJ1dGUuXCIsXHJcbiAgICAgICAgNDAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgbGV0IGNhbGxSZXNwb25zZSA9IGZhbHNlO1xyXG5cclxuICAgIC8vIENhbGwgdGhlIGJlZm9yZSByZXF1ZXN0IGZ1bmN0aW9uc1xyXG4gICAgY2FsbFJlc3BvbnNlID0gZG9DYWxsYmFja3MoYmVmb3JlUmVxdWVzdCwgcmVxdWVzdCwgcmVzcG9uc2UsIHtcclxuICAgICAgaWQsXHJcbiAgICAgIHVuaXF1ZUlkLFxyXG4gICAgICB0eXBlLFxyXG4gICAgICBib2R5XHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBCbG9jayB0aGUgcmVxdWVzdCBpZiBvbmUgb2YgYSBjYWxsYmFja3MgZmFpbGVkXHJcbiAgICBpZiAoY2FsbFJlc3BvbnNlICE9PSB0cnVlKSB7XHJcbiAgICAgIHJldHVybiByZXNwb25zZS5zZW5kKGNhbGxSZXNwb25zZSk7XHJcbiAgICB9XHJcblxyXG4gICAgbGV0IGNvbm5lY3Rpb25BYm9ydGVkID0gZmFsc2U7XHJcblxyXG4gICAgLy8gSW4gY2FzZSB0aGUgY29ubmVjdGlvbiBpcyBjbG9zZWQsIGZvcmNlIHRvIGFib3J0IGZ1cnRoZXIgYWN0aW9uc1xyXG4gICAgcmVxdWVzdC5zb2NrZXQub24oJ2Nsb3NlJywgKCkgPT4ge1xyXG4gICAgICBjb25uZWN0aW9uQWJvcnRlZCA9IHRydWU7XHJcbiAgICB9KTtcclxuXHJcbiAgICBsb2coNCwgYFtleHBvcnRdIEdvdCBhbiBpbmNvbWluZyBIVFRQIHJlcXVlc3Qgd2l0aCBJRCAke3VuaXF1ZUlkfS5gKTtcclxuXHJcbiAgICBib2R5LmNvbnN0ciA9ICh0eXBlb2YgYm9keS5jb25zdHIgPT09ICdzdHJpbmcnICYmIGJvZHkuY29uc3RyKSB8fCAnY2hhcnQnO1xyXG5cclxuICAgIC8vIEdhdGhlciBhbmQgb3JnYW5pemUgb3B0aW9ucyBmcm9tIHRoZSBwYXlsb2FkXHJcbiAgICBjb25zdCByZXF1ZXN0T3B0aW9ucyA9IHtcclxuICAgICAgZXhwb3J0OiB7XHJcbiAgICAgICAgaW5zdHIsXHJcbiAgICAgICAgdHlwZSxcclxuICAgICAgICBjb25zdHI6IGJvZHkuY29uc3RyWzBdLnRvTG93ZXJDYXNlKCkgKyBib2R5LmNvbnN0ci5zdWJzdHIoMSksXHJcbiAgICAgICAgaGVpZ2h0OiBib2R5LmhlaWdodCxcclxuICAgICAgICB3aWR0aDogYm9keS53aWR0aCxcclxuICAgICAgICBzY2FsZTogYm9keS5zY2FsZSB8fCBkZWZhdWx0T3B0aW9ucy5leHBvcnQuc2NhbGUsXHJcbiAgICAgICAgZ2xvYmFsT3B0aW9uczogaXNDb3JyZWN0SlNPTihib2R5Lmdsb2JhbE9wdGlvbnMsIHRydWUpLFxyXG4gICAgICAgIHRoZW1lT3B0aW9uczogaXNDb3JyZWN0SlNPTihib2R5LnRoZW1lT3B0aW9ucywgdHJ1ZSlcclxuICAgICAgfSxcclxuICAgICAgY3VzdG9tTG9naWM6IHtcclxuICAgICAgICBhbGxvd0NvZGVFeGVjdXRpb246IGdldEFsbG93Q29kZUV4ZWN1dGlvbigpLFxyXG4gICAgICAgIGFsbG93RmlsZVJlc291cmNlczogZmFsc2UsXHJcbiAgICAgICAgcmVzb3VyY2VzOiBpc0NvcnJlY3RKU09OKGJvZHkucmVzb3VyY2VzLCB0cnVlKSxcclxuICAgICAgICBjYWxsYmFjazogYm9keS5jYWxsYmFjayxcclxuICAgICAgICBjdXN0b21Db2RlOiBib2R5LmN1c3RvbUNvZGVcclxuICAgICAgfVxyXG4gICAgfTtcclxuXHJcbiAgICBpZiAoaW5zdHIpIHtcclxuICAgICAgLy8gU3RyaW5naWZ5IEpTT04gd2l0aCBvcHRpb25zXHJcbiAgICAgIHJlcXVlc3RPcHRpb25zLmV4cG9ydC5pbnN0ciA9IG9wdGlvbnNTdHJpbmdpZnkoXHJcbiAgICAgICAgaW5zdHIsXHJcbiAgICAgICAgcmVxdWVzdE9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTWVyZ2UgdGhlIHJlcXVlc3Qgb3B0aW9ucyBpbnRvIGRlZmF1bHQgb25lc1xyXG4gICAgY29uc3Qgb3B0aW9ucyA9IG1lcmdlQ29uZmlnT3B0aW9ucyhkZWZhdWx0T3B0aW9ucywgcmVxdWVzdE9wdGlvbnMpO1xyXG5cclxuICAgIC8vIFNhdmUgdGhlIEpTT04gaWYgZXhpc3RzXHJcbiAgICBvcHRpb25zLmV4cG9ydC5vcHRpb25zID0gaW5zdHI7XHJcblxyXG4gICAgLy8gTGFzdGx5LCBhZGQgdGhlIHNlcnZlciBzcGVjaWZpYyBhcmd1bWVudHMgaW50byBvcHRpb25zIGFzIHBheWxvYWRcclxuICAgIG9wdGlvbnMucGF5bG9hZCA9IHtcclxuICAgICAgc3ZnOiBib2R5LnN2ZyB8fCBmYWxzZSxcclxuICAgICAgYjY0OiBib2R5LmI2NCB8fCBmYWxzZSxcclxuICAgICAgbm9Eb3dubG9hZDogYm9keS5ub0Rvd25sb2FkIHx8IGZhbHNlLFxyXG4gICAgICByZXF1ZXN0SWQ6IHVuaXF1ZUlkXHJcbiAgICB9O1xyXG5cclxuICAgIC8vIFRlc3QgeGxpbms6aHJlZiBlbGVtZW50cyBmcm9tIHBheWxvYWQncyBTVkdcclxuICAgIGlmIChib2R5LnN2ZyAmJiBpc1ByaXZhdGVSYW5nZVVybEZvdW5kKG9wdGlvbnMucGF5bG9hZC5zdmcpKSB7XHJcbiAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgJ1NWRyBwb3RlbnRpYWxseSBjb250YWluIGF0IGxlYXN0IG9uZSBmb3JiaWRkZW4gVVJMIGluIHhsaW5rOmhyZWYgZWxlbWVudC4gUGxlYXNlIHJldmlldyB0aGUgU1ZHIGNvbnRlbnQgYW5kIGVuc3VyZSB0aGF0IGFsbCByZWZlcmVuY2VkIFVSTHMgY29tcGx5IHdpdGggc2VjdXJpdHkgcG9saWNpZXMuJyxcclxuICAgICAgICA0MDBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBTdGFydCB0aGUgZXhwb3J0IHByb2Nlc3NcclxuICAgIGF3YWl0IHN0YXJ0RXhwb3J0KG9wdGlvbnMsIChlcnJvciwgaW5mbykgPT4ge1xyXG4gICAgICAvLyBSZW1vdmUgdGhlIGNsb3NlIGV2ZW50IGZyb20gdGhlIHNvY2tldFxyXG4gICAgICByZXF1ZXN0LnNvY2tldC5yZW1vdmVBbGxMaXN0ZW5lcnMoJ2Nsb3NlJyk7XHJcblxyXG4gICAgICAvLyBBZnRlciB0aGUgd2hvbGUgZXhwb3J0aW5nIHByb2Nlc3NcclxuICAgICAgaWYgKGRlZmF1bHRPcHRpb25zLnNlcnZlci5iZW5jaG1hcmtpbmcpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICA1LFxyXG4gICAgICAgICAgYFtiZW5jaG1hcmtdIFJlcXVlc3Qgd2l0aCBJRCAke3VuaXF1ZUlkfSAtIEFmdGVyIHRoZSB3aG9sZSBleHBvcnRpbmcgcHJvY2VzczogJHtzdG9wQ291bnRlcigpfW1zLmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBJZiB0aGUgY29ubmVjdGlvbiB3YXMgY2xvc2VkLCBkbyBub3RoaW5nXHJcbiAgICAgIGlmIChjb25uZWN0aW9uQWJvcnRlZCkge1xyXG4gICAgICAgIHJldHVybiBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtleHBvcnRdIFRoZSBjbGllbnQgY2xvc2VkIHRoZSBjb25uZWN0aW9uIGJlZm9yZSB0aGUgY2hhcnQgZmluaXNoZWQgcHJvY2Vzc2luZy5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgZXJyb3IsIGxvZyBpdCBhbmQgc2VuZCBpdCB0byB0aGUgZXJyb3IgbWlkZGxld2FyZVxyXG4gICAgICBpZiAoZXJyb3IpIHtcclxuICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgZGF0YSBpcyBtaXNzaW5nLCBsb2cgdGhlIG1lc3NhZ2UgYW5kIHNlbmQgaXQgdG8gdGhlIGVycm9yIG1pZGRsZXdhcmVcclxuICAgICAgaWYgKCFpbmZvIHx8ICFpbmZvLnJlc3VsdCkge1xyXG4gICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgICBgVW5leHBlY3RlZCByZXR1cm4gZnJvbSBjaGFydCBnZW5lcmF0aW9uLiBQbGVhc2UgY2hlY2sgeW91ciByZXF1ZXN0IGRhdGEuIEZvciB0aGUgcmVxdWVzdCB3aXRoIElEICR7dW5pcXVlSWR9LCB0aGUgcmVzdWx0IGlzICR7aW5mby5yZXN1bHR9LmAsXHJcbiAgICAgICAgICA0MDBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBHZXQgdGhlIHR5cGUgZnJvbSBvcHRpb25zXHJcbiAgICAgIHR5cGUgPSBpbmZvLm9wdGlvbnMuZXhwb3J0LnR5cGU7XHJcblxyXG4gICAgICAvLyBUaGUgYWZ0ZXIgcmVxdWVzdCBjYWxsYmFja3NcclxuICAgICAgZG9DYWxsYmFja3MoYWZ0ZXJSZXF1ZXN0LCByZXF1ZXN0LCByZXNwb25zZSwgeyBpZCwgYm9keTogaW5mby5yZXN1bHQgfSk7XHJcblxyXG4gICAgICBpZiAoaW5mby5yZXN1bHQpIHtcclxuICAgICAgICAvLyBJZiBvbmx5IGJhc2U2NCBpcyByZXF1aXJlZCwgcmV0dXJuIGl0XHJcbiAgICAgICAgaWYgKGJvZHkuYjY0KSB7XHJcbiAgICAgICAgICAvLyBTVkcgRXhjZXB0aW9uIGZvciB0aGUgSGlnaGNoYXJ0cyAxMS4zLjAgdmVyc2lvblxyXG4gICAgICAgICAgaWYgKHR5cGUgPT09ICdwZGYnIHx8IHR5cGUgPT0gJ3N2ZycpIHtcclxuICAgICAgICAgICAgcmV0dXJuIHJlc3BvbnNlLnNlbmQoXHJcbiAgICAgICAgICAgICAgQnVmZmVyLmZyb20oaW5mby5yZXN1bHQsICd1dGY4JykudG9TdHJpbmcoJ2Jhc2U2NCcpXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgcmV0dXJuIHJlc3BvbnNlLnNlbmQoaW5mby5yZXN1bHQpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gU2V0IGNvcnJlY3QgY29udGVudCB0eXBlXHJcbiAgICAgICAgcmVzcG9uc2UuaGVhZGVyKCdDb250ZW50LVR5cGUnLCByZXZlcnNlZE1pbWVbdHlwZV0gfHwgJ2ltYWdlL3BuZycpO1xyXG5cclxuICAgICAgICAvLyBEZWNpZGUgd2hldGhlciB0byBkb3dubG9hZCBvciBub3QgY2hhcnQgZmlsZVxyXG4gICAgICAgIGlmICghYm9keS5ub0Rvd25sb2FkKSB7XHJcbiAgICAgICAgICByZXNwb25zZS5hdHRhY2htZW50KFxyXG4gICAgICAgICAgICBgJHtyZXF1ZXN0LnBhcmFtcy5maWxlbmFtZSB8fCByZXF1ZXN0LmJvZHkuZmlsZW5hbWUgfHwgJ2NoYXJ0J30uJHtcclxuICAgICAgICAgICAgICB0eXBlIHx8ICdwbmcnXHJcbiAgICAgICAgICAgIH1gXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gSWYgU1ZHLCByZXR1cm4gcGxhaW4gY29udGVudFxyXG4gICAgICAgIHJldHVybiB0eXBlID09PSAnc3ZnJ1xyXG4gICAgICAgICAgPyByZXNwb25zZS5zZW5kKGluZm8ucmVzdWx0KVxyXG4gICAgICAgICAgOiByZXNwb25zZS5zZW5kKEJ1ZmZlci5mcm9tKGluZm8ucmVzdWx0LCAnYmFzZTY0JykpO1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgbmV4dChlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQgKGFwcCkgPT4ge1xyXG4gIC8qKlxyXG4gICAqIEFkZHMgdGhlIFBPU1QgLyBhIHJvdXRlIGZvciBoYW5kbGluZyBQT1NUIHJlcXVlc3RzIGF0IHRoZSByb290IGVuZHBvaW50LlxyXG4gICAqL1xyXG4gIGFwcC5wb3N0KCcvJywgZXhwb3J0SGFuZGxlcik7XHJcblxyXG4gIC8qKlxyXG4gICAqIEFkZHMgdGhlIFBPU1QgLzpmaWxlbmFtZSBhIHJvdXRlIGZvciBoYW5kbGluZyBQT1NUIHJlcXVlc3RzIHdpdGhcclxuICAgKiBhIHNwZWNpZmllZCBmaWxlbmFtZSBwYXJhbWV0ZXIuXHJcbiAgICovXHJcbiAgYXBwLnBvc3QoJy86ZmlsZW5hbWUnLCBleHBvcnRIYW5kbGVyKTtcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IGpvaW4gYXMgcGF0aGVyIH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgY2FjaGUgZnJvbSAnLi4vLi4vY2FjaGUuanMnO1xyXG5pbXBvcnQgcG9vbCBmcm9tICcuLi8uLi9wb29sLmpzJztcclxuaW1wb3J0IHsgX19kaXJuYW1lIH0gZnJvbSAnLi4vLi4vdXRpbHMuanMnO1xyXG5cclxuY29uc3QgcGtnRmlsZSA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKHBhdGhlcihfX2Rpcm5hbWUsICdwYWNrYWdlLmpzb24nKSkpO1xyXG5cclxuY29uc3Qgc2VydmVyU3RhcnRUaW1lID0gbmV3IERhdGUoKTtcclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSBHRVQgL2hlYWx0aCByb3V0ZSwgd2hpY2ggb3V0cHV0cyBiYXNpYyBzdGF0cyBmb3IgdGhlIHNlcnZlci5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IChhcHApID0+XHJcbiAgIWFwcFxyXG4gICAgPyBmYWxzZVxyXG4gICAgOiBhcHAuZ2V0KCcvaGVhbHRoJywgKHJlcXVlc3QsIHJlc3BvbnNlKSA9PiB7XHJcbiAgICAgICAgcmVzcG9uc2Uuc2VuZCh7XHJcbiAgICAgICAgICBzdGF0dXM6ICdPSycsXHJcbiAgICAgICAgICBib290VGltZTogc2VydmVyU3RhcnRUaW1lLFxyXG4gICAgICAgICAgdXB0aW1lOlxyXG4gICAgICAgICAgICBNYXRoLmZsb29yKFxyXG4gICAgICAgICAgICAgIChuZXcgRGF0ZSgpLmdldFRpbWUoKSAtIHNlcnZlclN0YXJ0VGltZS5nZXRUaW1lKCkpIC8gMTAwMCAvIDYwXHJcbiAgICAgICAgICAgICkgKyAnIG1pbnV0ZXMnLFxyXG4gICAgICAgICAgdmVyc2lvbjogcGtnRmlsZS52ZXJzaW9uLFxyXG4gICAgICAgICAgaGlnaGNoYXJ0c1ZlcnNpb246IGNhY2hlLnZlcnNpb24oKSxcclxuICAgICAgICAgIGF2ZXJhZ2VQcm9jZXNzaW5nVGltZTogcG9vbC5hdmVyYWdlVGltZSgpLFxyXG4gICAgICAgICAgcGVyZm9ybWVkRXhwb3J0czogcG9vbC5wcm9jZXNzZWRXb3JrQ291bnQoKSxcclxuICAgICAgICAgIGZhaWxlZEV4cG9ydHM6IHBvb2wuZHJvcHBlZFdvcmsoKSxcclxuICAgICAgICAgIGV4cG9ydEF0dGVtcHRzOiBwb29sLndvcmtBdHRlbXB0cygpLFxyXG4gICAgICAgICAgc3VjZXNzUmF0aW86IChwb29sLnByb2Nlc3NlZFdvcmtDb3VudCgpIC8gcG9vbC53b3JrQXR0ZW1wdHMoKSkgKiAxMDAsXHJcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgaW1wb3J0L25vLW5hbWVkLWFzLWRlZmF1bHQtbWVtYmVyXHJcbiAgICAgICAgICBwb29sOiBwb29sLmdldFBvb2xJbmZvSlNPTigpXHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH0pO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IHByb21pc2VzIGFzIGZzUHJvbWlzZXMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IHBvc2l4IH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgY29ycyBmcm9tICdjb3JzJztcclxuaW1wb3J0IGV4cHJlc3MgZnJvbSAnZXhwcmVzcyc7XHJcbmltcG9ydCBodHRwIGZyb20gJ2h0dHAnO1xyXG5pbXBvcnQgaHR0cHMgZnJvbSAnaHR0cHMnO1xyXG5pbXBvcnQgbXVsdGVyIGZyb20gJ211bHRlcic7XHJcblxyXG5pbXBvcnQgZXJyb3JIYW5kbGVyIGZyb20gJy4vZXJyb3IuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4uL2xvZ2dlci5qcyc7XHJcbmltcG9ydCByYXRlTGltaXQgZnJvbSAnLi9yYXRlX2xpbWl0LmpzJztcclxuaW1wb3J0IHsgX19kaXJuYW1lIH0gZnJvbSAnLi4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IHZTd2l0Y2hSb3V0ZSBmcm9tICcuL3JvdXRlcy9jaGFuZ2VfaGNfdmVyc2lvbi5qcyc7XHJcbmltcG9ydCBleHBvcnRSb3V0ZXMgZnJvbSAnLi9yb3V0ZXMvZXhwb3J0LmpzJztcclxuaW1wb3J0IGhlYWx0aFJvdXRlIGZyb20gJy4vcm91dGVzL2hlYWx0aC5qcyc7XHJcbmltcG9ydCB1aVJvdXRlIGZyb20gJy4vcm91dGVzL3VpLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLy8gQ3JlYXRlIGV4cHJlc3MgYXBwXHJcbmNvbnN0IGFwcCA9IGV4cHJlc3MoKTtcclxuXHJcbi8vIERpc2FibGUgdGhlIFgtUG93ZXJlZC1CeSBoZWFkZXJcclxuYXBwLmRpc2FibGUoJ3gtcG93ZXJlZC1ieScpO1xyXG5cclxuLy8gRW5hYmxlIENPUlMgc3VwcG9ydFxyXG5hcHAudXNlKGNvcnMoKSk7XHJcblxyXG4vLyBFbmFibGUgcGFyc2luZyBvZiBmb3JtIGRhdGEgKGZpbGVzKSB3aXRoIE11bHRlciBwYWNrYWdlXHJcbmNvbnN0IHN0b3JhZ2UgPSBtdWx0ZXIubWVtb3J5U3RvcmFnZSgpO1xyXG5jb25zdCB1cGxvYWQgPSBtdWx0ZXIoe1xyXG4gIHN0b3JhZ2UsXHJcbiAgbGltaXRzOiB7XHJcbiAgICBmaWVsZFNpemU6IDUwICogMTAyNCAqIDEwMjRcclxuICB9XHJcbn0pO1xyXG5cclxuLy8gRW5hYmxlIGJvZHkgcGFyc2VyXHJcbmFwcC51c2UoZXhwcmVzcy5qc29uKHsgbGltaXQ6IDUwICogMTAyNCAqIDEwMjQgfSkpO1xyXG5hcHAudXNlKGV4cHJlc3MudXJsZW5jb2RlZCh7IGV4dGVuZGVkOiB0cnVlLCBsaW1pdDogNTAgKiAxMDI0ICogMTAyNCB9KSk7XHJcblxyXG4vLyBVc2Ugb25seSBub24tZmlsZSBtdWx0aXBhcnQgZm9ybSBmaWVsZHNcclxuYXBwLnVzZSh1cGxvYWQubm9uZSgpKTtcclxuXHJcbi8qKlxyXG4gKiBBdHRhY2ggZXJyb3IgaGFuZGxlcnMgdG8gdGhlIHNlcnZlci5cclxuICpcclxuICogQHBhcmFtIHtodHRwLlNlcnZlcn0gc2VydmVyIC0gVGhlIEhUVFAvSFRUUFMgc2VydmVyIGluc3RhbmNlLlxyXG4gKi9cclxuY29uc3QgYXR0YWNoRXJyb3JIYW5kbGVycyA9IChzZXJ2ZXIpID0+IHtcclxuICBzZXJ2ZXIub24oJ2NsaWVudEVycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICBsb2dXaXRoU3RhY2soMSwgZXJyb3IsIGBbc2VydmVyXSBDbGllbnQgZXJyb3I6ICR7ZXJyb3IubWVzc2FnZX1gKTtcclxuICB9KTtcclxuICBzZXJ2ZXIub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICBsb2dXaXRoU3RhY2soMSwgZXJyb3IsIGBbc2VydmVyXSBTZXJ2ZXIgZXJyb3I6ICR7ZXJyb3IubWVzc2FnZX1gKTtcclxuICB9KTtcclxuICBzZXJ2ZXIub24oJ2Nvbm5lY3Rpb24nLCAoc29ja2V0KSA9PiB7XHJcbiAgICBzb2NrZXQub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFtzZXJ2ZXJdIFNvY2tldCBlcnJvcjogJHtlcnJvci5tZXNzYWdlfWApO1xyXG4gICAgfSk7XHJcbiAgfSk7XHJcbn07XHJcblxyXG4vKipcclxuICogU3RhcnRzIGFuIEhUVFAgc2VydmVyIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uLiBUaGUgYHNlcnZlckNvbmZpZ2BcclxuICogb2JqZWN0IGNvbnRhaW5zIGFsbCBzZXJ2ZXIgcmVsYXRlZCBwcm9wZXJ0aWVzIChzZWUgdGhlIGBzZXJ2ZXJgIHNlY3Rpb25cclxuICogaW4gdGhlIGBsaWIvc2NoZW1hcy9jb25maWcuanNgIGZpbGUgZm9yIGEgcmVmZXJlbmNlKS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHNlcnZlckNvbmZpZyAtIFRoZSBzZXJ2ZXIgY29uZmlndXJhdGlvbiBvYmplY3QuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSAtIFRocm93cyBhbiBlcnJvciBpZiB0aGUgc2VydmVyIGNhbm5vdCBiZSBjb25maWd1cmVkXHJcbiAqIGFuZCBzdGFydGVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHN0YXJ0U2VydmVyID0gYXN5bmMgKHNlcnZlckNvbmZpZykgPT4ge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBTdG9wIGlmIG5vdCBlbmFibGVkXHJcbiAgICBpZiAoIXNlcnZlckNvbmZpZy5lbmFibGUpIHtcclxuICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIExpc3RlbiBIVFRQIHNlcnZlclxyXG4gICAgaWYgKCFzZXJ2ZXJDb25maWcuc3NsLmZvcmNlKSB7XHJcbiAgICAgIC8vIE1haW4gc2VydmVyIGluc3RhbmNlIChIVFRQKVxyXG4gICAgICBjb25zdCBodHRwU2VydmVyID0gaHR0cC5jcmVhdGVTZXJ2ZXIoYXBwKTtcclxuXHJcbiAgICAgIC8vIEF0dGFjaCBlcnJvciBoYW5kbGVycyBhbmQgbGlzdGVuIHRvIHRoZSBzZXJ2ZXJcclxuICAgICAgYXR0YWNoRXJyb3JIYW5kbGVycyhodHRwU2VydmVyKTtcclxuXHJcbiAgICAgIC8vIExpc3RlblxyXG4gICAgICBodHRwU2VydmVyLmxpc3RlbihzZXJ2ZXJDb25maWcucG9ydCwgc2VydmVyQ29uZmlnLmhvc3QpO1xyXG5cclxuICAgICAgbG9nKFxyXG4gICAgICAgIDMsXHJcbiAgICAgICAgYFtzZXJ2ZXJdIFN0YXJ0ZWQgSFRUUCBzZXJ2ZXIgb24gJHtzZXJ2ZXJDb25maWcuaG9zdH06JHtzZXJ2ZXJDb25maWcucG9ydH0uYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIExpc3RlbiBIVFRQUyBzZXJ2ZXJcclxuICAgIGlmIChzZXJ2ZXJDb25maWcuc3NsLmVuYWJsZSkge1xyXG4gICAgICAvLyBTZXQgdXAgYW4gU1NMIHNlcnZlciBhbHNvXHJcbiAgICAgIGxldCBrZXksIGNlcnQ7XHJcblxyXG4gICAgICB0cnkge1xyXG4gICAgICAgIC8vIEdldCB0aGUgU1NMIGtleVxyXG4gICAgICAgIGtleSA9IGF3YWl0IGZzUHJvbWlzZXMucmVhZEZpbGUoXHJcbiAgICAgICAgICBwb3NpeC5qb2luKHNlcnZlckNvbmZpZy5zc2wuY2VydFBhdGgsICdzZXJ2ZXIua2V5JyksXHJcbiAgICAgICAgICAndXRmOCdcclxuICAgICAgICApO1xyXG5cclxuICAgICAgICAvLyBHZXQgdGhlIFNTTCBjZXJ0aWZpY2F0ZVxyXG4gICAgICAgIGNlcnQgPSBhd2FpdCBmc1Byb21pc2VzLnJlYWRGaWxlKFxyXG4gICAgICAgICAgcG9zaXguam9pbihzZXJ2ZXJDb25maWcuc3NsLmNlcnRQYXRoLCAnc2VydmVyLmNydCcpLFxyXG4gICAgICAgICAgJ3V0ZjgnXHJcbiAgICAgICAgKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAyLFxyXG4gICAgICAgICAgYFtzZXJ2ZXJdIFVuYWJsZSB0byBsb2FkIGtleS9jZXJ0aWZpY2F0ZSBmcm9tIHRoZSAnJHtzZXJ2ZXJDb25maWcuc3NsLmNlcnRQYXRofScgcGF0aC4gQ291bGQgbm90IHJ1biBzZWN1cmVkIGxheWVyIHNlcnZlci5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKGtleSAmJiBjZXJ0KSB7XHJcbiAgICAgICAgLy8gTWFpbiBzZXJ2ZXIgaW5zdGFuY2UgKEhUVFBTKVxyXG4gICAgICAgIGNvbnN0IGh0dHBzU2VydmVyID0gaHR0cHMuY3JlYXRlU2VydmVyKGFwcCk7XHJcblxyXG4gICAgICAgIC8vIEF0dGFjaCBlcnJvciBoYW5kbGVycyBhbmQgbGlzdGVuIHRvIHRoZSBzZXJ2ZXJcclxuICAgICAgICBhdHRhY2hFcnJvckhhbmRsZXJzKGh0dHBzU2VydmVyKTtcclxuXHJcbiAgICAgICAgLy8gTGlzdGVuXHJcbiAgICAgICAgaHR0cHNTZXJ2ZXIubGlzdGVuKHNlcnZlckNvbmZpZy5zc2wucG9ydCwgc2VydmVyQ29uZmlnLmhvc3QpO1xyXG5cclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtzZXJ2ZXJdIFN0YXJ0ZWQgSFRUUFMgc2VydmVyIG9uICR7c2VydmVyQ29uZmlnLmhvc3R9OiR7c2VydmVyQ29uZmlnLnNzbC5wb3J0fS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIEVuYWJsZSB0aGUgcmF0ZSBsaW1pdGVyIGlmIGNvbmZpZyBzYXlzIHNvXHJcbiAgICBpZiAoXHJcbiAgICAgIHNlcnZlckNvbmZpZy5yYXRlTGltaXRpbmcgJiZcclxuICAgICAgc2VydmVyQ29uZmlnLnJhdGVMaW1pdGluZy5lbmFibGUgJiZcclxuICAgICAgIVswLCBOYU5dLmluY2x1ZGVzKHNlcnZlckNvbmZpZy5yYXRlTGltaXRpbmcubWF4UmVxdWVzdHMpXHJcbiAgICApIHtcclxuICAgICAgcmF0ZUxpbWl0KGFwcCwgc2VydmVyQ29uZmlnLnJhdGVMaW1pdGluZyk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU2V0IHVwIHN0YXRpYyBmb2xkZXIncyByb3V0ZVxyXG4gICAgYXBwLnVzZShleHByZXNzLnN0YXRpYyhwb3NpeC5qb2luKF9fZGlybmFtZSwgJ3B1YmxpYycpKSk7XHJcblxyXG4gICAgLy8gU2V0IHVwIHJvdXRlc1xyXG4gICAgaGVhbHRoUm91dGUoYXBwKTtcclxuICAgIGV4cG9ydFJvdXRlcyhhcHApO1xyXG4gICAgdWlSb3V0ZShhcHApO1xyXG4gICAgdlN3aXRjaFJvdXRlKGFwcCk7XHJcblxyXG4gICAgLy8gU2V0IHVwIGNlbnRyYWxpemVkIGVycm9yIGhhbmRsZXJcclxuICAgIGVycm9ySGFuZGxlcihhcHApO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbc2VydmVyXSBDb3VsZCBub3QgY29uZmlndXJlIGFuZCBzdGFydCB0aGUgc2VydmVyLidcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBFbmFibGUgcmF0ZSBsaW1pdGluZyBmb3IgdGhlIHNlcnZlci5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGxpbWl0Q29uZmlnIC0gQ29uZmlndXJhdGlvbiBvYmplY3QgZm9yIHJhdGUgbGltaXRpbmcuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZW5hYmxlUmF0ZUxpbWl0aW5nID0gKGxpbWl0Q29uZmlnKSA9PiByYXRlTGltaXQoYXBwLCBsaW1pdENvbmZpZyk7XHJcblxyXG4vKipcclxuICogR2V0IHRoZSBFeHByZXNzIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSAtIFRoZSBFeHByZXNzIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldEV4cHJlc3MgPSAoKSA9PiBleHByZXNzO1xyXG5cclxuLyoqXHJcbiAqIEdldCB0aGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IC0gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldEFwcCA9ICgpID0+IGFwcDtcclxuXHJcbi8qKlxyXG4gKiBBcHBseSBtaWRkbGV3YXJlKHMpIHRvIGEgc3BlY2lmaWMgcGF0aC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBUaGUgcGF0aCB0byB3aGljaCB0aGUgbWlkZGxld2FyZShzKSBzaG91bGQgYmUgYXBwbGllZC5cclxuICogQHBhcmFtIHsuLi5GdW5jdGlvbn0gbWlkZGxld2FyZXMgLSBUaGUgbWlkZGxld2FyZSBmdW5jdGlvbnMgdG8gYmUgYXBwbGllZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCB1c2UgPSAocGF0aCwgLi4ubWlkZGxld2FyZXMpID0+IHtcclxuICBhcHAudXNlKHBhdGgsIC4uLm1pZGRsZXdhcmVzKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBTZXQgdXAgYSByb3V0ZSB3aXRoIEdFVCBtZXRob2QgYW5kIGFwcGx5IG1pZGRsZXdhcmUocykuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIC0gVGhlIHJvdXRlIHBhdGguXHJcbiAqIEBwYXJhbSB7Li4uRnVuY3Rpb259IG1pZGRsZXdhcmVzIC0gVGhlIG1pZGRsZXdhcmUgZnVuY3Rpb25zIHRvIGJlIGFwcGxpZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0ID0gKHBhdGgsIC4uLm1pZGRsZXdhcmVzKSA9PiB7XHJcbiAgYXBwLmdldChwYXRoLCAuLi5taWRkbGV3YXJlcyk7XHJcbn07XHJcblxyXG4vKipcclxuICogU2V0IHVwIGEgcm91dGUgd2l0aCBQT1NUIG1ldGhvZCBhbmQgYXBwbHkgbWlkZGxld2FyZShzKS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBUaGUgcm91dGUgcGF0aC5cclxuICogQHBhcmFtIHsuLi5GdW5jdGlvbn0gbWlkZGxld2FyZXMgLSBUaGUgbWlkZGxld2FyZSBmdW5jdGlvbnMgdG8gYmUgYXBwbGllZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBwb3N0ID0gKHBhdGgsIC4uLm1pZGRsZXdhcmVzKSA9PiB7XHJcbiAgYXBwLnBvc3QocGF0aCwgLi4ubWlkZGxld2FyZXMpO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIHN0YXJ0U2VydmVyLFxyXG4gIGVuYWJsZVJhdGVMaW1pdGluZyxcclxuICBnZXRFeHByZXNzLFxyXG4gIGdldEFwcCxcclxuICB1c2UsXHJcbiAgZ2V0LFxyXG4gIHBvc3RcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgeyBfX2Rpcm5hbWUgfSBmcm9tICcuLi8uLi91dGlscy5qcyc7XHJcblxyXG4vKipcclxuICogQWRkcyB0aGUgR0VUIC8gcm91dGUgZm9yIGEgVUkgd2hlbiBlbmFibGVkIG9uIHRoZSBleHBvcnQgc2VydmVyLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgKGFwcCkgPT5cclxuICAhYXBwXHJcbiAgICA/IGZhbHNlXHJcbiAgICA6IGFwcC5nZXQoJy8nLCAocmVxdWVzdCwgcmVzcG9uc2UpID0+IHtcclxuICAgICAgICByZXNwb25zZS5zZW5kRmlsZShqb2luKF9fZGlybmFtZSwgJ3B1YmxpYycsICdpbmRleC5odG1sJykpO1xyXG4gICAgICB9KTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgY2FjaGUgZnJvbSAnLi4vLi4vY2FjaGUuanMnO1xyXG5cclxuaW1wb3J0IEh0dHBFcnJvciBmcm9tICcuLi8uLi9lcnJvcnMvSHR0cEVycm9yLmpzJztcclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSBQT1NUIC9jaGFuZ2VfaGNfdmVyc2lvbi86bmV3VmVyc2lvbiByb3V0ZSB0aGF0IGNhbiBiZSB1dGlsaXplZCB0byBtb2RpZnlcclxuICogdGhlIEhpZ2hjaGFydHMgdmVyc2lvbiBvbiB0aGUgc2VydmVyLlxyXG4gKlxyXG4gKiBUT0RPOiBBZGQgYXV0aCB0b2tlbiBhbmQgY29ubmVjdCB0byBBUElcclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IChhcHApID0+XHJcbiAgIWFwcFxyXG4gICAgPyBmYWxzZVxyXG4gICAgOiBhcHAucG9zdChcclxuICAgICAgICAnL3ZlcnNpb24vY2hhbmdlLzpuZXdWZXJzaW9uJyxcclxuICAgICAgICBhc3luYyAocmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpID0+IHtcclxuICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgIGNvbnN0IGFkbWluVG9rZW4gPSBwcm9jZXNzLmVudi5ISUdIQ0hBUlRTX0FETUlOX1RPS0VOO1xyXG5cclxuICAgICAgICAgICAgLy8gQ2hlY2sgdGhlIGV4aXN0ZW5jZSBvZiB0aGUgdG9rZW5cclxuICAgICAgICAgICAgaWYgKCFhZG1pblRva2VuIHx8ICFhZG1pblRva2VuLmxlbmd0aCkge1xyXG4gICAgICAgICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgICAgICAgICAnVGhlIHNlcnZlciBpcyBub3QgY29uZmlndXJlZCB0byBwZXJmb3JtIHJ1bi10aW1lIHZlcnNpb24gY2hhbmdlczogSElHSENIQVJUU19BRE1JTl9UT0tFTiBpcyBub3Qgc2V0LicsXHJcbiAgICAgICAgICAgICAgICA0MDFcclxuICAgICAgICAgICAgICApO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAvLyBDaGVjayBpZiB0aGUgaGMtYXV0aCBoZWFkZXIgY29udGFpbiBhIGNvcnJlY3QgdG9rZW5cclxuICAgICAgICAgICAgY29uc3QgdG9rZW4gPSByZXF1ZXN0LmdldCgnaGMtYXV0aCcpO1xyXG4gICAgICAgICAgICBpZiAoIXRva2VuIHx8IHRva2VuICE9PSBhZG1pblRva2VuKSB7XHJcbiAgICAgICAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAgICAgICAgICdJbnZhbGlkIG9yIG1pc3NpbmcgdG9rZW46IFNldCB0aGUgdG9rZW4gaW4gdGhlIGhjLWF1dGggaGVhZGVyLicsXHJcbiAgICAgICAgICAgICAgICA0MDFcclxuICAgICAgICAgICAgICApO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAvLyBDb21wYXJlIHZlcnNpb25zXHJcbiAgICAgICAgICAgIGNvbnN0IG5ld1ZlcnNpb24gPSByZXF1ZXN0LnBhcmFtcy5uZXdWZXJzaW9uO1xyXG4gICAgICAgICAgICBpZiAobmV3VmVyc2lvbikge1xyXG4gICAgICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgaW1wb3J0L25vLW5hbWVkLWFzLWRlZmF1bHQtbWVtYmVyXHJcbiAgICAgICAgICAgICAgICBhd2FpdCBjYWNoZS51cGRhdGVWZXJzaW9uKG5ld1ZlcnNpb24pO1xyXG4gICAgICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgICAgICAgICAgICBgVmVyc2lvbiBjaGFuZ2U6ICR7ZXJyb3IubWVzc2FnZX1gLFxyXG4gICAgICAgICAgICAgICAgICBlcnJvci5zdGF0dXNDb2RlXHJcbiAgICAgICAgICAgICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgIC8vIFN1Y2Nlc3NcclxuICAgICAgICAgICAgICByZXNwb25zZS5zdGF0dXMoMjAwKS5zZW5kKHtcclxuICAgICAgICAgICAgICAgIHN0YXR1c0NvZGU6IDIwMCxcclxuICAgICAgICAgICAgICAgIHZlcnNpb246IGNhY2hlLnZlcnNpb24oKSxcclxuICAgICAgICAgICAgICAgIG1lc3NhZ2U6IGBTdWNjZXNzZnVsbHkgdXBkYXRlZCBIaWdoY2hhcnRzIHRvIHZlcnNpb246ICR7bmV3VmVyc2lvbn0uYFxyXG4gICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgIC8vIE5vIHZlcnNpb24gc3BlY2lmaWVkXHJcbiAgICAgICAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcignTm8gbmV3IHZlcnNpb24gc3VwcGxpZWQuJywgNDAwKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgICAgbmV4dChlcnJvcik7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICApO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCAnY29sb3JzJztcclxuXHJcbmltcG9ydCB7IGNoZWNrQW5kVXBkYXRlQ2FjaGUgfSBmcm9tICcuL2NhY2hlLmpzJztcclxuaW1wb3J0IHtcclxuICBiYXRjaEV4cG9ydCxcclxuICBzZXRBbGxvd0NvZGVFeGVjdXRpb24sXHJcbiAgc2luZ2xlRXhwb3J0LFxyXG4gIHN0YXJ0RXhwb3J0XHJcbn0gZnJvbSAnLi9jaGFydC5qcyc7XHJcbmltcG9ydCB7IG1hcFRvTmV3Q29uZmlnLCBtYW51YWxDb25maWcsIHNldE9wdGlvbnMgfSBmcm9tICcuL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7XHJcbiAgaW5pdExvZ2dpbmcsXHJcbiAgbG9nLFxyXG4gIGxvZ1dpdGhTdGFjayxcclxuICBzZXRMb2dMZXZlbCxcclxuICBlbmFibGVGaWxlTG9nZ2luZ1xyXG59IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgaW5pdFBvb2wsIGtpbGxQb29sIH0gZnJvbSAnLi9wb29sLmpzJztcclxuaW1wb3J0IHNlcnZlciwgeyBzdGFydFNlcnZlciB9IGZyb20gJy4vc2VydmVyL3NlcnZlci5qcyc7XHJcbmltcG9ydCB7IHByaW50TG9nbywgcHJpbnRVc2FnZSB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIHRoZSBleHBvcnQgcHJvY2Vzcy4gVGFza3Mgc3VjaCBhcyBjb25maWd1cmluZyBsb2dnaW5nLCBjaGVja2luZ1xyXG4gKiBjYWNoZSBhbmQgc291cmNlcywgYW5kIGluaXRpYWxpemluZyB0aGUgcG9vbCBvZiByZXNvdXJjZXMgaGFwcGVuIGR1cmluZ1xyXG4gKiB0aGlzIHN0YWdlLiBGdW5jdGlvbiB0aGF0IGlzIHJlcXVpcmVkIHRvIGJlIGNhbGxlZCBiZWZvcmUgdHJ5aW5nIHRvIGV4cG9ydCBjaGFydHMgb3Igc2V0dGluZyBhIHNlcnZlci4gVGhlIGBvcHRpb25zYCBpcyBhbiBvYmplY3QgdGhhdCBjb250YWlucyBhbGwgb3B0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBBbGwgZXhwb3J0IG9wdGlvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSB1cGRhdGVkIGV4cG9ydCBvcHRpb25zLlxyXG4gKi9cclxuY29uc3QgaW5pdEV4cG9ydCA9IGFzeW5jIChvcHRpb25zKSA9PiB7XHJcbiAgLy8gU2V0IHRoZSBhbGxvd0NvZGVFeGVjdXRpb24gcGVyIGV4cG9ydCBtb2R1bGUgc2NvcGVcclxuICBzZXRBbGxvd0NvZGVFeGVjdXRpb24oXHJcbiAgICBvcHRpb25zLmN1c3RvbUxvZ2ljICYmIG9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgKTtcclxuXHJcbiAgLy8gSW5pdCB0aGUgbG9nZ2luZ1xyXG4gIGluaXRMb2dnaW5nKG9wdGlvbnMubG9nZ2luZyk7XHJcblxyXG4gIC8vIENoZWNrIGlmIGNhY2hlIG5lZWRzIHRvIGJlIHVwZGF0ZWRcclxuICBhd2FpdCBjaGVja0FuZFVwZGF0ZUNhY2hlKG9wdGlvbnMuaGlnaGNoYXJ0cyB8fCB7IHZlcnNpb246ICdsYXRlc3QnIH0pO1xyXG5cclxuICAvLyBJbml0IHRoZSBwb29sXHJcbiAgYXdhaXQgaW5pdFBvb2woe1xyXG4gICAgcG9vbDogb3B0aW9ucy5wb29sIHx8IHtcclxuICAgICAgbWluV29ya2VyczogMSxcclxuICAgICAgbWF4V29ya2VyczogMVxyXG4gICAgfSxcclxuICAgIHB1cHBldGVlckFyZ3M6IG9wdGlvbnMucHVwcGV0ZWVyPy5hcmdzIHx8IFtdXHJcbiAgfSk7XHJcblxyXG4gIC8vIFJldHVybiB1cGRhdGVkIG9wdGlvbnNcclxuICByZXR1cm4gb3B0aW9ucztcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICAvLyBTZXJ2ZXJcclxuICBzZXJ2ZXIsXHJcbiAgc3RhcnRTZXJ2ZXIsXHJcbiAgc2V0T3B0aW9ucyxcclxuXHJcbiAgLy8gRXhwb3J0aW5nXHJcbiAgaW5pdEV4cG9ydCxcclxuICBzaW5nbGVFeHBvcnQsXHJcbiAgYmF0Y2hFeHBvcnQsXHJcbiAgc3RhcnRFeHBvcnQsXHJcbiAga2lsbFBvb2wsXHJcblxyXG4gIC8vIExvZ3NcclxuICBsb2csXHJcbiAgbG9nV2l0aFN0YWNrLFxyXG4gIHNldExvZ0xldmVsLFxyXG4gIGVuYWJsZUZpbGVMb2dnaW5nLFxyXG5cclxuICAvLyBVdGlsc1xyXG4gIG1hcFRvTmV3Q29uZmlnLFxyXG4gIG1hbnVhbENvbmZpZyxcclxuICBwcmludExvZ28sXHJcbiAgcHJpbnRVc2FnZVxyXG59O1xyXG4iXSwibmFtZXMiOlsiYXN5bmMiLCJmZXRjaCIsInVybCIsInJlcXVlc3RPcHRpb25zIiwiUHJvbWlzZSIsInJlc29sdmUiLCJyZWplY3QiLCJwcm90b2NvbCIsInN0YXJ0c1dpdGgiLCJodHRwcyIsImh0dHAiLCJnZXRQcm90b2NvbCIsImdldCIsInJlcyIsImRhdGEiLCJvbiIsImNodW5rIiwidGV4dCIsImVycm9yIiwiZG90ZW52IiwiY29uZmlnIiwiZGVmYXVsdENvbmZpZyIsInB1cHBldGVlciIsImFyZ3MiLCJ2YWx1ZSIsInR5cGUiLCJkZXNjcmlwdGlvbiIsImhpZ2hjaGFydHMiLCJ2ZXJzaW9uIiwiZW52TGluayIsImNkblVSTCIsImNvcmVTY3JpcHRzIiwibW9kdWxlcyIsImluZGljYXRvcnMiLCJzY3JpcHRzIiwiZm9yY2VGZXRjaCIsImNhY2hlUGF0aCIsImV4cG9ydCIsImluZmlsZSIsImluc3RyIiwib3B0aW9ucyIsIm91dGZpbGUiLCJjb25zdHIiLCJkZWZhdWx0SGVpZ2h0IiwiZGVmYXVsdFdpZHRoIiwiZGVmYXVsdFNjYWxlIiwiaGVpZ2h0Iiwid2lkdGgiLCJzY2FsZSIsImdsb2JhbE9wdGlvbnMiLCJ0aGVtZU9wdGlvbnMiLCJiYXRjaCIsInJhc3Rlcml6YXRpb25UaW1lb3V0IiwiY3VzdG9tTG9naWMiLCJhbGxvd0NvZGVFeGVjdXRpb24iLCJhbGxvd0ZpbGVSZXNvdXJjZXMiLCJjdXN0b21Db2RlIiwiY2FsbGJhY2siLCJyZXNvdXJjZXMiLCJsb2FkQ29uZmlnIiwibGVnYWN5TmFtZSIsImNyZWF0ZUNvbmZpZyIsInNlcnZlciIsImVuYWJsZSIsImNsaU5hbWUiLCJob3N0IiwicG9ydCIsImJlbmNobWFya2luZyIsInNzbCIsImZvcmNlIiwiY2VydFBhdGgiLCJyYXRlTGltaXRpbmciLCJtYXhSZXF1ZXN0cyIsIndpbmRvdyIsImRlbGF5IiwidHJ1c3RQcm94eSIsInNraXBLZXkiLCJza2lwVG9rZW4iLCJwb29sIiwibWluV29ya2VycyIsIm1heFdvcmtlcnMiLCJ3b3JrTGltaXQiLCJhY3F1aXJlVGltZW91dCIsImNyZWF0ZVRpbWVvdXQiLCJkZXN0cm95VGltZW91dCIsImlkbGVUaW1lb3V0IiwiY3JlYXRlUmV0cnlJbnRlcnZhbCIsInJlYXBlckludGVydmFsIiwibGlzdGVuVG9Qcm9jZXNzRXhpdHMiLCJsb2dnaW5nIiwibGV2ZWwiLCJmaWxlIiwiZGVzdCIsInVpIiwicm91dGUiLCJvdGhlciIsIm5vTG9nbyIsInByb21wdHNDb25maWciLCJuYW1lIiwibWVzc2FnZSIsImluaXRpYWwiLCJqb2luIiwic2VwYXJhdG9yIiwiaW5zdHJ1Y3Rpb25zIiwiY2hvaWNlcyIsImhpbnQiLCJtaW4iLCJtYXgiLCJyb3VuZCIsImFic29sdXRlUHJvcHMiLCJuZXN0ZWRBcmdzIiwiY3JlYXRlTmVzdGVkQXJncyIsIm9iaiIsInByb3BDaGFpbiIsIk9iamVjdCIsImtleXMiLCJmb3JFYWNoIiwiayIsImluY2x1ZGVzIiwiZW50cnkiLCJzdWJzdHJpbmciLCJ1bmRlZmluZWQiLCJjb2xvcnMiLCJ0b0NvbnNvbGUiLCJ0b0ZpbGUiLCJwYXRoQ3JlYXRlZCIsImxldmVsc0Rlc2MiLCJ0aXRsZSIsImNvbG9yIiwibGlzdGVuZXJzIiwia2V5Iiwib3B0aW9uIiwiZW50cmllcyIsImxvZ1RvRmlsZSIsInRleHRzIiwicHJlZml4IiwiZXhpc3RzU3luYyIsIm1rZGlyU3luYyIsImFwcGVuZEZpbGUiLCJjb25jYXQiLCJjb25zb2xlIiwibG9nIiwibmV3TGV2ZWwiLCJsZW5ndGgiLCJEYXRlIiwidG9TdHJpbmciLCJzcGxpdCIsInRyaW0iLCJmbiIsImFwcGx5IiwibG9nV2l0aFN0YWNrIiwiY3VzdG9tTWVzc2FnZSIsIm1haW5NZXNzYWdlIiwic3RhY2tNZXNzYWdlIiwic3RhY2siLCJzbGljZSIsInNldExvZ0xldmVsIiwiZW5hYmxlRmlsZUxvZ2dpbmciLCJsb2dEZXN0IiwibG9nRmlsZSIsImVuZHNXaXRoIiwiX19kaXJuYW1lIiwiZmlsZVVSTFRvUGF0aCIsIlVSTCIsImRvY3VtZW50IiwicmVxdWlyZSIsInBhdGhUb0ZpbGVVUkwiLCJfX2ZpbGVuYW1lIiwiaHJlZiIsIl9kb2N1bWVudEN1cnJlbnRTY3JpcHQiLCJzcmMiLCJiYXNlVVJJIiwiZml4VHlwZSIsImZvcm1hdHMiLCJvdXRUeXBlIiwicG9wIiwiZmluZCIsInQiLCJoYW5kbGVSZXNvdXJjZXMiLCJhbGxvd2VkUHJvcHMiLCJoYW5kbGVkUmVzb3VyY2VzIiwiY29ycmVjdFJlc291cmNlcyIsImlzQ29ycmVjdEpTT04iLCJyZWFkRmlsZVN5bmMiLCJmaWxlcyIsInByb3BOYW1lIiwibWFwIiwiaXRlbSIsInBhcnNlZERhdGEiLCJKU09OIiwicGFyc2UiLCJzdHJpbmdpZnkiLCJkZWVwQ29weSIsImNvcHkiLCJBcnJheSIsImlzQXJyYXkiLCJwcm90b3R5cGUiLCJoYXNPd25Qcm9wZXJ0eSIsImNhbGwiLCJvcHRpb25zU3RyaW5naWZ5IiwiYWxsb3dGdW5jdGlvbnMiLCJyZXBsYWNlQWxsIiwicHJpbnRVc2FnZSIsImJvbGQiLCJ5ZWxsb3ciLCJjeWNsZUNhdGVnb3JpZXMiLCJkZXNjTmFtZSIsImdyZWVuIiwiaSIsImJsdWUiLCJjYXRlZ29yeSIsInRvVXBwZXJDYXNlIiwicmVkIiwidG9Cb29sZWFuIiwid3JhcEFyb3VuZCIsInJlcGxhY2UiLCJtZWFzdXJlVGltZSIsInN0YXJ0IiwicHJvY2VzcyIsImhydGltZSIsImJpZ2ludCIsIk51bWJlciIsIkV4cG9ydEVycm9yIiwiRXJyb3IiLCJjb25zdHJ1Y3RvciIsInN1cGVyIiwidGhpcyIsInNldEVycm9yIiwic3RhdHVzQ29kZSIsImNhY2hlIiwiYWN0aXZlTWFuaWZlc3QiLCJzb3VyY2VzIiwiaGNWZXJzaW9uIiwiYXBwbGllZENvbmZpZyIsImV4dHJhY3RWZXJzaW9uIiwiaW5kZXhPZiIsImZldGNoQW5kUHJvY2Vzc1NjcmlwdCIsInNjcmlwdCIsInByb3h5QWdlbnQiLCJmZXRjaGVkTW9kdWxlcyIsInNob3VsZFRocm93RXJyb3IiLCJhZ2VudCIsInRpbWVvdXQiLCJlbnYiLCJyZXNwb25zZSIsInVwZGF0ZUNhY2hlIiwic291cmNlUGF0aCIsImN1c3RvbVNjcmlwdHMiLCJwcm94eUhvc3QiLCJwcm94eVBvcnQiLCJIdHRwc1Byb3h5QWdlbnQiLCJtb2R1bGVTY3JpcHRzIiwiYWxsRmV0Y2hQcm9taXNlcyIsImFsbCIsImZldGNoU2NyaXB0cyIsImMiLCJtIiwid3JpdGVGaWxlU3luYyIsImNoZWNrQW5kVXBkYXRlQ2FjaGUiLCJtYW5pZmVzdFBhdGgiLCJyZXF1ZXN0VXBkYXRlIiwibWFuaWZlc3QiLCJtb2R1bGVNYXAiLCJudW1iZXJPZk1vZHVsZXMiLCJzb21lIiwibW9kdWxlTmFtZSIsIm5ld01hbmlmZXN0Iiwic2F2ZUNvbmZpZ1RvTWFuaWZlc3QiLCJnZXRDYWNoZVBhdGgiLCJjYWNoZSQxIiwibmV3VmVyc2lvbiIsImFzc2lnbiIsImdlbmVyYWxPcHRpb25zIiwiZ2V0T3B0aW9ucyIsIm1lcmdlQ29uZmlnT3B0aW9ucyIsIm5ld09wdGlvbnMiLCJtZXJnZWRPcHRpb25zIiwidXBkYXRlRGVmYXVsdENvbmZpZyIsImNvbmZpZ09iaiIsImN1c3RvbU9iaiIsImN1c3RvbVZhbHVlIiwibnVtRW52VmFsIiwiZWwiLCJpbml0T3B0aW9ucyIsIml0ZW1zIiwicmVjdXJzaXZlUHJvcHMiLCJvYmplY3RUb1VwZGF0ZSIsIm5lc3RlZE5hbWVzIiwic2hpZnQiLCJSQU5ET01fUElEIiwicmFuZG9tQnl0ZXMiLCJQVVBQRVRFRVJfRElSIiwicGF0aCIsIm1pbmltYWxBcmdzIiwidGVtcGxhdGUiLCJmcyIsImJyb3dzZXIiLCJzZXRQYWdlQ29udGVudCIsInBhZ2UiLCJzZXRDb250ZW50IiwiYWRkU2NyaXB0VGFnIiwiZXZhbHVhdGUiLCJzZXR1cEhpZ2hjaGFydHMiLCIkZXZhbCIsImVsZW1lbnQiLCJlcnJvck1lc3NhZ2UiLCJfZGlzcGxheUVycm9ycyIsImlubmVySFRNTCIsImNsZWFyUGFnZSIsImhhcmRSZXNldCIsImdvdG8iLCJib2R5IiwibmV3UGFnZSIsInNldENhY2hlRW5hYmxlZCIsImNsb3NlIiwiaXNDb25uZWN0ZWQiLCJfX2Jhc2VkaXIiLCJzZXRBc0NvbmZpZyIsImNoYXJ0IiwidHJpZ2dlckV4cG9ydCIsInB1cHBldGVlckV4cG9ydCIsImluamVjdGVkUmVzb3VyY2VzIiwiY2xlYXJJbmplY3RlZCIsImRpc3Bvc2UiLCJzY3JpcHRzVG9SZW1vdmUiLCJnZXRFbGVtZW50c0J5VGFnTmFtZSIsInN0eWxlc1RvUmVtb3ZlIiwibGlua3NUb1JlbW92ZSIsInJlbW92ZSIsImV4cG9ydE9wdGlvbnMiLCJyZXF1ZXN0QW5pbWF0aW9uRnJhbWUiLCJkaXNwbGF5RXJyb3JzIiwiZGVidWdnZXIiLCJpc1NWRyIsImQiLCJzdmdUZW1wbGF0ZSIsInN0ckluaiIsImpzIiwicHVzaCIsImNvbnRlbnQiLCJpc0xvY2FsIiwiY3NzIiwiY3NzSW1wb3J0cyIsIm1hdGNoIiwiY3NzSW1wb3J0UGF0aCIsImFkZFN0eWxlVGFnIiwic2l6ZSIsImNoYXJ0SGVpZ2h0IiwiYmFzZVZhbCIsImNoYXJ0V2lkdGgiLCJwYXJzZUZsb2F0IiwiSGlnaGNoYXJ0cyIsImNoYXJ0cyIsInZpZXdwb3J0SGVpZ2h0IiwiTWF0aCIsImNlaWwiLCJ2aWV3cG9ydFdpZHRoIiwic2V0Vmlld3BvcnQiLCJkZXZpY2VTY2FsZUZhY3RvciIsInpvb21DYWxsYmFjayIsInN0eWxlIiwiem9vbSIsIm1hcmdpbiIsIngiLCJ5IiwiZ2V0Qm91bmRpbmdDbGllbnRSZWN0IiwidHJ1bmMiLCJnZXRDbGlwUmVnaW9uIiwib3V0ZXJIVE1MIiwiY3JlYXRlU1ZHIiwiZW5jb2RpbmciLCJjbGlwIiwicmFjZSIsInNjcmVlbnNob3QiLCJvbWl0QmFja2dyb3VuZCIsIl9yZXNvbHZlIiwic2V0VGltZW91dCIsImNyZWF0ZUltYWdlIiwicGRmIiwiY3JlYXRlUERGIiwib2xkQ2hhcnRzIiwib2xkQ2hhcnQiLCJkZXN0cm95IiwicHVwcGV0ZWVyQXJncyIsInBlcmZvcm1lZEV4cG9ydHMiLCJleHBvcnRBdHRlbXB0cyIsInRpbWVTcGVudCIsImRyb3BwZWRFeHBvcnRzIiwic3BlbnRBdmVyYWdlIiwicG9vbENvbmZpZyIsImZhY3RvcnkiLCJjcmVhdGUiLCJpZCIsInV1aWQiLCJzdGFydERhdGUiLCJnZXRUaW1lIiwiYnJvd3Nlck5ld1BhZ2UiLCJpc0Nsb3NlZCIsIndvcmtDb3VudCIsInJhbmRvbSIsInZhbGlkYXRlIiwid29ya2VySGFuZGxlIiwiaW5pdFBvb2wiLCJjb2RlIiwia2lsbFBvb2wiLCJleGl0IiwiYWxsQXJncyIsInRyeUNvdW50Iiwib3BlbiIsImxhdW5jaCIsImhlYWRsZXNzIiwidXNlckRhdGFEaXIiLCJjcmVhdGVCcm93c2VyIiwicGFyc2VJbnQiLCJQb29sIiwiYWNxdWlyZVRpbWVvdXRNaWxsaXMiLCJjcmVhdGVUaW1lb3V0TWlsbGlzIiwiZGVzdHJveVRpbWVvdXRNaWxsaXMiLCJpZGxlVGltZW91dE1pbGxpcyIsImNyZWF0ZVJldHJ5SW50ZXJ2YWxNaWxsaXMiLCJyZWFwSW50ZXJ2YWxNaWxsaXMiLCJwcm9wYWdhdGVDcmVhdGVFcnJvciIsInJlc291cmNlIiwiZXZlbnRJZCIsImluaXRpYWxSZXNvdXJjZXMiLCJhY3F1aXJlIiwicHJvbWlzZSIsInJlbGVhc2UiLCJicm93c2VyQ2xvc2UiLCJkZXN0cm95ZWQiLCJwb3N0V29yayIsImdldFBvb2xJbmZvIiwiYWNxdWlyZUNvdW50ZXIiLCJwYXlsb2FkIiwicmVxdWVzdElkIiwid29ya1N0YXJ0IiwiZXhwb3J0Q291bnRlciIsInJlc3VsdCIsImV4cG9ydFRpbWUiLCJudW1GcmVlIiwibnVtVXNlZCIsIm51bVBlbmRpbmdBY3F1aXJlcyIsInBvb2wkMSIsImF2YWlsYWJsZSIsImluVXNlIiwicGVuZGluZ0FjcXVpcmUiLCJzdGFydEV4cG9ydCIsInNldHRpbmdzIiwiZW5kQ2FsbGJhY2siLCJzdmciLCJpbml0RXhwb3J0U2V0dGluZ3MiLCJleHBvcnRBc1N0cmluZyIsImRvU3RyYWlnaHRJbmplY3QiLCJkb0V4cG9ydCIsImZpbmRDaGFydFNpemUiLCJleHBvcnRpbmciLCJwcmVjaXNpb24iLCJtdWx0aXBsaWVyIiwicG93Iiwicm91bmROdW1iZXIiLCJzb3VyY2VIZWlnaHQiLCJzb3VyY2VXaWR0aCIsInBhcmFtIiwiY2hhcnRKc29uIiwiY3VzdG9tTG9naWNPcHRpb25zIiwiYWxsb3dDb2RlRXhlY3V0aW9uU2NvcGVkIiwiZW5hYmxlZCIsIm9wdGlvbnNOYW1lIiwic3RyaW5nVG9FeHBvcnQiLCJjaGFydEpTT04iLCJsb2dFcnJvck1pZGRsZXdhcmUiLCJyZXEiLCJuZXh0IiwiTk9ERV9FTlYiLCJyZXR1cm5FcnJvck1pZGRsZXdhcmUiLCJzdENvZGUiLCJzdGF0dXMiLCJqc29uIiwicmF0ZUxpbWl0IiwiYXBwIiwibGltaXRDb25maWciLCJtc2ciLCJyYXRlT3B0aW9ucyIsImxpbWl0ZXIiLCJ3aW5kb3dNcyIsImRlbGF5TXMiLCJoYW5kbGVyIiwicmVxdWVzdCIsImZvcm1hdCIsInNlbmQiLCJkZWZhdWx0Iiwic2tpcCIsInF1ZXJ5IiwiYWNjZXNzX3Rva2VuIiwidXNlIiwiSHR0cEVycm9yIiwic2V0U3RhdHVzIiwicmV2ZXJzZWRNaW1lIiwicG5nIiwianBlZyIsImdpZiIsInJlcXVlc3RzQ291bnRlciIsImJlZm9yZVJlcXVlc3QiLCJhZnRlclJlcXVlc3QiLCJkb0NhbGxiYWNrcyIsImNhbGxiYWNrcyIsInVuaXF1ZUlkIiwiY2FsbFJlc3BvbnNlIiwiZXhwb3J0SGFuZGxlciIsInN0b3BDb3VudGVyIiwiZGVmYXVsdE9wdGlvbnMiLCJoZWFkZXJzIiwiY29ubmVjdGlvbiIsInJlbW90ZUFkZHJlc3MiLCJjb25uZWN0aW9uQWJvcnRlZCIsInNvY2tldCIsInRvTG93ZXJDYXNlIiwic3Vic3RyIiwiYjY0Iiwibm9Eb3dubG9hZCIsImlwUmVnRXgiLCJpc1ByaXZhdGVSYW5nZVVybEZvdW5kIiwiaW5mbyIsInJlbW92ZUFsbExpc3RlbmVycyIsIkJ1ZmZlciIsImZyb20iLCJoZWFkZXIiLCJhdHRhY2htZW50IiwicGFyYW1zIiwiZmlsZW5hbWUiLCJwa2dGaWxlIiwicGF0aGVyIiwic2VydmVyU3RhcnRUaW1lIiwiZXhwcmVzcyIsImRpc2FibGUiLCJjb3JzIiwic3RvcmFnZSIsIm11bHRlciIsIm1lbW9yeVN0b3JhZ2UiLCJ1cGxvYWQiLCJsaW1pdHMiLCJmaWVsZFNpemUiLCJsaW1pdCIsInVybGVuY29kZWQiLCJleHRlbmRlZCIsIm5vbmUiLCJhdHRhY2hFcnJvckhhbmRsZXJzIiwic3RhcnRTZXJ2ZXIiLCJzZXJ2ZXJDb25maWciLCJodHRwU2VydmVyIiwiY3JlYXRlU2VydmVyIiwibGlzdGVuIiwiY2VydCIsImZzUHJvbWlzZXMiLCJyZWFkRmlsZSIsInBvc2l4IiwiaHR0cHNTZXJ2ZXIiLCJOYU4iLCJzdGF0aWMiLCJib290VGltZSIsInVwdGltZSIsImZsb29yIiwiaGlnaGNoYXJ0c1ZlcnNpb24iLCJhdmVyYWdlUHJvY2Vzc2luZ1RpbWUiLCJmYWlsZWRFeHBvcnRzIiwic3VjZXNzUmF0aW8iLCJoZWFsdGhSb3V0ZSIsInBvc3QiLCJleHBvcnRSb3V0ZXMiLCJzZW5kRmlsZSIsInVpUm91dGUiLCJhZG1pblRva2VuIiwiSElHSENIQVJUU19BRE1JTl9UT0tFTiIsInRva2VuIiwidlN3aXRjaFJvdXRlIiwiZXJyb3JIYW5kbGVyIiwiZW5hYmxlUmF0ZUxpbWl0aW5nIiwiZ2V0RXhwcmVzcyIsImdldEFwcCIsIm1pZGRsZXdhcmVzIiwiaW5kZXgiLCJzZXRPcHRpb25zIiwidXNlck9wdGlvbnMiLCJjb25maWdJbmRleCIsImZpbmRJbmRleCIsImFyZyIsImZpbGVOYW1lIiwibG9hZENvbmZpZ0ZpbGUiLCJzaG93VXNhZ2UiLCJwcm9wZXJ0aWVzQ2hhaW4iLCJhcmd1bWVudFR5cGUiLCJyZWR1Y2UiLCJwcm9wIiwicGFpckFyZ3VtZW50VmFsdWUiLCJpbml0RXhwb3J0IiwiaW5pdExvZ2dpbmciLCJzaW5nbGVFeHBvcnQiLCJiYXRjaEV4cG9ydCIsImJhdGNoRnVuY3Rpb25zIiwicGFpciIsIm1hcFRvTmV3Q29uZmlnIiwib2xkT3B0aW9ucyIsIm1hbnVhbENvbmZpZyIsImNvbmZpZ0ZpbGVOYW1lIiwiY29uZmlnRmlsZSIsImNob2ljZSIsInByb21wdHMiLCJvblN1Ym1pdCIsInAiLCJjYXRlZ29yaWVzIiwicXVlc3Rpb25zQ291bnRlciIsImFsbFF1ZXN0aW9ucyIsInNlY3Rpb24iLCJwcm9tcHQiLCJhbnN3ZXIiLCJtb2R1bGUiLCJwcm9taXNlcyIsIndyaXRlRmlsZSIsInByaW50TG9nbyIsInBhY2thZ2VWZXJzaW9uIl0sIm1hcHBpbmdzIjoia3RCQXlCQUEsZUFBZUMsRUFBTUMsRUFBS0MsRUFBaUIsSUFDekMsT0FBTyxJQUFJQyxTQUFRLENBQUNDLEVBQVNDLEtBQzNCLE1BQU1DLEVBYlUsQ0FBQ0wsR0FBU0EsRUFBSU0sV0FBVyxTQUFXQyxFQUFRQyxFQWEzQ0MsQ0FBWVQsR0FFN0JLLEVBQ0dLLElBQUlWLEVBQUtDLEdBQWlCVSxJQUN6QixJQUFJQyxFQUFPLEdBR1hELEVBQUlFLEdBQUcsUUFBU0MsSUFDZEYsR0FBUUUsQ0FBSyxJQUlmSCxFQUFJRSxHQUFHLE9BQU8sS0FDUEQsR0FDSFIsRUFBTyxxQ0FHVE8sRUFBSUksS0FBT0gsRUFDWFQsRUFBUVEsRUFBSSxHQUNaLElBRUhFLEdBQUcsU0FBVUcsSUFDWlosRUFBT1ksRUFBTSxHQUNiLEdBRVIsQ0NuQ0FDLEVBQU9DLFNBSUEsTUFBTUMsRUFBZ0IsQ0FDM0JDLFVBQVcsQ0FDVEMsS0FBTSxDQUNKQyxNQUFPLEdBQ1BDLEtBQU0sV0FDTkMsWUFBYSwwQ0FHakJDLFdBQVksQ0FDVkMsUUFBUyxDQUNQSixNQUFPLFNBQ1BLLFFBQVMscUJBQ1RKLEtBQU0sU0FDTkMsWUFBYSxzQ0FFZkksT0FBUSxDQUNOTixNQUFPLCtCQUNQSyxRQUFTLHFCQUNUSixLQUFNLFNBQ05DLFlBQWEsa0RBRWZLLFlBQWEsQ0FDWEYsUUFBUywwQkFDVEwsTUFBTyxDQUFDLGFBQWMsa0JBQW1CLGlCQUN6Q0MsS0FBTSxXQUNOQyxZQUFhLHlDQUVmTSxRQUFTLENBQ1BILFFBQVMscUJBQ1RMLE1BQU8sQ0FDTCxRQUNBLE1BQ0EsUUFDQSxZQUNBLGNBQ0EsdUJBQ0EsZ0JBQ0EsdUJBQ0EsZUFDQSxRQUNBLE9B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 +"use strict";require("colors");var e=require("dotenv"),t=require("fs"),r=require("path"),i=require("https-proxy-agent"),o=require("http"),n=require("https"),s=require("url"),a=require("prompts"),l=require("tarn"),c=require("uuid"),p=require("node:path"),u=require("puppeteer"),h=require("node:crypto"),d=require("cors"),g=require("express"),m=require("multer"),f=require("express-rate-limit"),y="undefined"!=typeof document?document.currentScript:null;function v(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=v(s);async function b(e,t={}){return new Promise(((r,i)=>{const s=(e=>e.startsWith("https")?n:o)(e);s.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)}))}))}const T={puppeteer:{args:{value:[],type:"string[]",description:"Arguments array to send to Puppeteer."}},highcharts:{version:{value:"latest",envLink:"HIGHCHARTS_VERSION",type:"string",description:"The Highcharts version to be used."},cdnURL:{value:"https://code.highcharts.com/",envLink:"HIGHCHARTS_CDN_URL",type:"string",description:"The CDN URL for Highcharts scripts to be used."},coreScripts:{envLink:"HIGHCHARTS_CORE_SCRIPTS",value:["highcharts","highcharts-more","highcharts-3d"],type:"string[]",description:"The core Highcharts scripts to fetch."},modules:{envLink:"HIGHCHARTS_MODULES",value:["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"],type:"string[]",description:"The modules of Highcharts to fetch."},indicators:{envLink:"HIGHCHARTS_INDICATORS",value:["indicators-all"],type:"string[]",description:"The indicators of Highcharts to fetch."},scripts:{value:["https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js","https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.34/moment-timezone-with-data.min.js"],type:"string[]",description:"Additional optional scripts or dependencies to fetch."},forceFetch:{envLink:"HIGHCHARTS_FORCE_FETCH",value:!1,type:"boolean",description:"The flag to determine whether to refetch all scripts after each server rerun."},cachePath:{envLink:"HIGHCHARTS_CACHE_PATH",value:".cache",type:"string",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:{envLink:"EXPORT_TYPE",value:"png",type:"string",description:"The file export format. It can be jpeg, png, pdf, or svg."},constr:{envLink:"EXPORT_CONSTR",value:"chart",type:"string",description:"The constructor to use. Can be chart, stockChart, mapChart, or ganttChart."},defaultHeight:{envLink:"EXPORT_DEFAULT_HEIGHT",value:400,type:"number",description:"the default height of the exported chart. Used when no value is set."},defaultWidth:{envLink:"EXPORT_DEFAULT_WIDTH",value:600,type:"number",description:"The default width of the exported chart. Used when no value is set."},defaultScale:{envLink:"EXPORT_DEFAULT_SCALE",value:1,type:"number",description:"The default scale of the exported chart. Used when no value is set."},height:{type:"number",value:!1,description:"The height of the exported chart, overriding the option in the chart settings."},width:{type:"number",value:!1,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:{envLink:"EXPORT_RASTERIZATION_TIMEOUT",value:1500,type:"number",description:"The duration in milliseconds to wait for rendering a webpage."}},customLogic:{allowCodeExecution:{envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",value:!1,type:"boolean",description:"Controls whether the execution of arbitrary code is allowed during the exporting process."},allowFileResources:{envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",value:!1,type:"boolean",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:{envLink:"SERVER_ENABLE",value:!1,type:"boolean",cliName:"enableServer",description:"When set to true, the server starts on the local IP address 0.0.0.0."},host:{envLink:"SERVER_HOST",value:"0.0.0.0",type:"string",description:"The hostname of the server. Additionally, it starts a server on the provided hostname."},port:{envLink:"SERVER_PORT",value:7801,type:"number",description:"The server port when enabled."},benchmarking:{envLink:"SERVER_BENCHMARKING",value:!1,type:"boolean",cliName:"serverBenchmarking",description:"Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request."},ssl:{enable:{envLink:"SERVER_SSL_ENABLE",value:!1,type:"boolean",cliName:"enableSsl",description:"Enables or disables the SSL protocol."},force:{envLink:"SERVER_SSL_FORCE",value:!1,type:"boolean",cliName:"sslForced",legacyName:"sslOnly",description:"When set to true, the server is forced to serve only over HTTPS."},port:{envLink:"SERVER_SSL_PORT",value:443,type:"number",cliName:"sslPort",description:"The port on which to run the SSL server."},certPath:{envLink:"SERVER_SSL_CERT_PATH",value:"",type:"string",legacyName:"sslPath",description:"The path to the SSL certificate/key file."}},rateLimiting:{enable:{envLink:"SERVER_RATE_LIMITING_ENABLE",value:!1,type:"boolean",cliName:"enableRateLimiting",description:"Enables rate limiting for the server."},maxRequests:{envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",value:10,type:"number",legacyName:"rateLimit",description:"The maximum number of requests allowed in one minute."},window:{envLink:"SERVER_RATE_LIMITING_WINDOW",value:1,type:"number",description:"The time window, in minutes, for the rate limiting."},delay:{envLink:"SERVER_RATE_LIMITING_DELAY",value:0,type:"number",description:"The delay duration for each successive request before reaching the maximum limit."},trustProxy:{envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",value:!1,type:"boolean",description:"Set this to true if the server is behind a load balancer."},skipKey:{envLink:"SERVER_RATE_LIMITING_SKIP_KEY",value:"",type:"string",description:"Allows bypassing the rate limiter and should be provided with the skipToken argument."},skipToken:{envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",value:"",type:"string",description:"Allows bypassing the rate limiter and should be provided with the skipKey argument."}}},pool:{minWorkers:{envLink:"POOL_MIN_WORKERS",value:4,type:"number",description:"The number of minimum and initial pool workers to spawn."},maxWorkers:{envLink:"POOL_MAX_WORKERS",value:8,type:"number",legacyName:"workers",description:"The number of maximum pool workers to spawn."},workLimit:{envLink:"POOL_WORK_LIMIT",value:40,type:"number",description:"The number of work pieces that can be performed before restarting the worker process."},acquireTimeout:{envLink:"POOL_ACQUIRE_TIMEOUT",value:5e3,type:"number",description:"The duration, in milliseconds, to wait for acquiring a resource."},createTimeout:{envLink:"POOL_CREATE_TIMEOUT",value:5e3,type:"number",description:"The duration, in milliseconds, to wait for creating a resource."},destroyTimeout:{envLink:"POOL_DESTROY_TIMEOUT",value:5e3,type:"number",description:"The duration, in milliseconds, to wait for destroying a resource."},idleTimeout:{envLink:"POOL_IDLE_TIMEOUT",value:3e4,type:"number",description:"The duration, in milliseconds, after which an idle resource is destroyed."},createRetryInterval:{envLink:"POOL_CREATE_RETRY_INTERVAL",value:200,type:"number",description:"The duration, in milliseconds, to wait before retrying the create process in case of a failure."},reaperInterval:{envLink:"POOL_REAPER_INTERVAL",value:1e3,type:"number",description:"The duration, in milliseconds, after which the check for idle resources to destroy is triggered."},benchmarking:{envLink:"POOL_BENCHMARKING",value:!1,type:"boolean",cliName:"poolBenchmarking",description:"Indicate whether to show statistics for the pool of resources or not."},listenToProcessExits:{envLink:"POOL_LISTEN_TO_PROCESS_EXITS",value:!0,type:"boolean",description:"Decides whether or not to attach process.exit handlers."}},logging:{level:{envLink:"LOGGING_LEVEL",value:4,type:"number",cliName:"logLevel",description:"The logging level to be used."},file:{envLink:"LOGGING_FILE",value:"highcharts-export-server.log",type:"string",cliName:"logFile",description:"The name of a log file. The logDest option also needs to be set to enable file logging."},dest:{envLink:"LOGGING_DEST",value:"log/",type:"string",cliName:"logDest",description:"The path to store log files. This also enables file logging."}},ui:{enable:{envLink:"UI_ENABLE",value:!1,type:"boolean",cliName:"enableUi",description:"Enables or disables the user interface (UI) for the export server."},route:{envLink:"UI_ROUTE",value:"/",type:"string",cliName:"uiRoute",description:"The endpoint route to which the user interface (UI) should be attached."}},other:{noLogo:{envLink:"OTHER_NO_LOGO",value:!1,type:"boolean",description:"Skip printing the logo on a startup. Will be replaced by a simple text."}}},x={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:"modules",message:"Available modules",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:T.highcharts.modules.value},{type:"list",name:"scripts",message:"Custom scripts",initial:T.highcharts.scripts.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:"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},{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}],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},{type:"toggle",name:"listenToProcessExits",message:"Set to false to skip attaching process.exit handlers",initial:T.pool.listenToProcessExits.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:"toggle",name:"noLogo",message:"Skip printing the logo on startup. Replaced by simple text",initial:T.other.noLogo.value}]},k=["options","globalOptions","themeOptions","resources","payload"],E={},S=(e,t="")=>{Object.keys(e).forEach((r=>{if(!["puppeteer","highcharts"].includes(r)){const i=e[r];void 0===i.value?S(i,`${t}.${r}`):(E[i.cliName||r]=`${t}.${r}`.substring(1),void 0!==i.legacyName&&(E[i.legacyName]=`${t}.${r}`.substring(1)))}}))};S(T);const L=["red","yellow","blue","gray","green"];let R={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:L[0]},{title:"warning",color:L[1]},{title:"notice",color:L[2]},{title:"verbose",color:L[3]},{title:"benchmark",color:L[4]}],listeners:[]};for(const[e,t]of Object.entries(T.logging))R[e]=t.value;const O=(e,r)=>{R.toFile&&(R.pathCreated||(!t.existsSync(R.dest)&&t.mkdirSync(R.dest),R.pathCreated=!0),t.appendFile(`${R.dest}${R.file}`,[r].concat(e).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),R.toFile=!1)})))},I=(...e)=>{const[t,...r]=e,{level:i,levelsDesc:o}=R;if(5!==t&&(0===t||t>i||i>o.length))return;const n=`${(new Date).toString().split("(")[0].trim()} [${o[t-1].title}] -`;R.listeners.forEach((e=>{e(n,r.join(" "))})),R.toConsole&&console.log.apply(void 0,[n.toString()[R.levelsDesc[t-1].color]].concat(r)),O(r,n)},_=(e,t,r)=>{const i=r||t.message,{level:o,levelsDesc:n}=R;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];R.toConsole&&console.log.apply(void 0,[s.toString()[R.levelsDesc[e-1].color]].concat([i[L[e-1]],"\n",a])),R.listeners.forEach((e=>{e(s,l.join(" "))})),O(l,s)},C=e=>{e>=0&&e<=R.levelsDesc.length&&(R.level=e)},$=(e,t)=>{if(R={...R,dest:e||R.dest,file:t||R.file,toFile:!0},0===R.dest.length)return I(1,"[logger] File logging initialization: no path supplied.");R.dest.endsWith("/")||(R.dest+="/")},P=s.fileURLToPath(new URL("../.","undefined"==typeof document?require("url").pathToFileURL(__filename).href:y&&y.src||new URL("index.cjs",document.baseURI).href)),N=(e,t)=>{const r=["png","jpeg","pdf","svg"];if(t){const i=t.split(".").pop();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"},j=(e=!1,r)=>{const i=["js","css","files"];let o=e,n=!1;if(r&&e.endsWith(".json"))try{o=A(t.readFileSync(e,"utf8"))}catch(e){return _(2,e,"[cli] No resources found.")}else o=A(e),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):I(3,"[cli] No resources found.")};function A(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 H=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]=H(e[r]));return t},F=(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 U(){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 q=e=>!["false","undefined","null","NaN","0",""].includes(e)&&!!e,W=(e,r)=>{if(e&&"string"==typeof e)return(e=e.trim()).endsWith(".js")?!!r&&W(t.readFileSync(e,"utf8")):e.startsWith("function()")||e.startsWith("function ()")||e.startsWith("()=>")||e.startsWith("() =>")?`(${e})()`:e.replace(/;$/,"")},D=()=>{const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6};class M 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 G={cdnURL:"https://code.highcharts.com/",activeManifest:{},sources:"",hcVersion:""};let V=!1;const J=()=>G.hcVersion=G.sources.substring(0,G.sources.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim(),K=async(e,t,r,i=!1)=>{e.endsWith(".js")&&(e=e.substring(0,e.length-3)),I(4,`[cache] Fetching script - ${e}.js`);const o=t?{agent:t,timeout:+process.env.PROXY_SERVER_TIMEOUT||5e3}:{},n=await b(`${e}.js`,o);if(200===n.statusCode&&"string"==typeof n.text){if(r){r[e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")]=1}return n.text}if(i)throw new M(`Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${n.statusCode}).`).setError(n);return I(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`),""},z=async(e,r)=>{const{coreScripts:o,modules:n,indicators:s,scripts:a}=e,l="latest"!==e.version&&e.version?`${e.version}/`:"";let c;I(3,`[cache] Updating cache version to Highcharts: ${l||"latest"}.`);const p=process.env.PROXY_SERVER_HOST,u=process.env.PROXY_SERVER_PORT;if(p&&u)try{c=new i.HttpsProxyAgent({host:p,port:+u})}catch(e){throw new M("[cache] Could not create a Proxy Agent.").setError(e)}const h={};try{return G.sources=await(async(e,t,r,i,o,n)=>{const s=[...e.map((e=>K(`${i}${e}`,o,n,!0))),...t.map((e=>K(`${i}${e}`,o,n))),...r.map((e=>K(`${e}`,o)))];return(await Promise.all(s)).join(";\n")})([...o.map((e=>`${l}${e}`))],[...n.map((e=>"map"===e?`maps/${l}modules/${e}`:`${l}modules/${e}`)),...s.map((e=>`stock/${l}indicators/${e}`))],a,e.cdnURL||G.cdnURL,c,h),J(),t.writeFileSync(r,G.sources),h}catch(e){throw new M("[cache] Unable to update the local Highcharts cache.").setError(e)}},X=async e=>{const i=r.join(P,e.cachePath);let o;const n=r.join(i,"manifest.json"),s=r.join(i,"sources.js");if(V=e,!t.existsSync(i)&&t.mkdirSync(i),!t.existsSync(n)||e.forceFetch)I(3,"[cache] Fetching and caching Highcharts dependencies."),o=await z(e,s);else{let r=!1;const i=JSON.parse(t.readFileSync(n));if(i.modules&&Array.isArray(i.modules)){const e={};i.modules.forEach((t=>e[t]=1)),i.modules=e}const{modules:a,coreScripts:l,indicators:c}=e,p=a.length+l.length+c.length;i.version!==e.version?(I(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),r=!0):Object.keys(i.modules||{}).length!==p?(I(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),r=!0):r=(e.modules||[]).some((e=>{if(!i.modules[e])return I(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),r?o=await z(e,s):(I(3,"[cache] Dependency cache is up to date, proceeding."),G.sources=t.readFileSync(s,"utf8"),o=i.modules,J())}await(async(e,i)=>{const o={version:e.version,modules:i||{}};G.activeManifest=o,I(3,"[cache] Writing a new manifest.");try{t.writeFileSync(r.join(P,e.cachePath,"manifest.json"),JSON.stringify(o),"utf8")}catch(e){throw new M("[cache] Error writing the cache manifest.").setError(e)}})(e,o)},B=()=>r.join(P,V.cachePath);var Y=async e=>!!V&&await X(Object.assign(V,{version:e})),Q=()=>G,Z=()=>G.hcVersion;let ee={};const te=()=>ee,re=(e,t,r=[])=>{const i=H(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]:re(i[e],n,r);var o;return i};function ie(e,t={},r=""){Object.keys(e).forEach((i=>{const o=e[i],n=t&&t[i];let s;void 0===o.value?ie(o,n,`${r}.${i}`):(void 0!==n&&(o.value=n),o.envLink&&("boolean"===o.type?o.value=q([process.env[o.envLink],o.value].find((e=>e||"false"===e))):"number"===o.type?(s=+process.env[o.envLink],o.value=s>=0?s:o.value):o.type.indexOf("]")>=0&&process.env[o.envLink]?o.value=process.env[o.envLink].split(","):o.value=process.env[o.envLink]||o.value))}))}function oe(e){let t={};for(const[r,i]of Object.entries(e))t[r]=Object.prototype.hasOwnProperty.call(i,"value")?i.value:oe(i);return t}function ne(e,t,r){for(;t.length>1;){const i=t.shift();return Object.prototype.hasOwnProperty.call(e,i)||(e[i]={}),e[i]=ne(Object.assign({},e[i]),t,r),e}return e[t[0]]=r,e}const se=h.randomBytes(64).toString("base64url"),ae=p.join("tmp",`puppeteer-${se}`),le=[`--user-data-dir=${p.join(ae,"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"],ce=w.fileURLToPath(new URL(".","undefined"==typeof document?require("url").pathToFileURL(__filename).href:y&&y.src||new URL("index.cjs",document.baseURI).href)),pe=t.readFileSync(ce+"/../templates/template.html","utf8");let ue;const he=async e=>{await e.setContent(pe),await e.addScriptTag({path:`${B()}/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()}`)}))},de=async(e,t=!1)=>{try{t?(await e.goto("about:blank"),await he(e)):await e.evaluate((()=>{document.body.innerHTML='
'}))}catch(e){_(2,e,"[browser] Could not clear the content of the page.")}},ge=async()=>{if(!ue)return!1;const e=await ue.newPage();return await e.setCacheEnabled(!1),await he(e),e},me=async()=>(ue?.isConnected()&&(await ue.close(),I(4,"[browser] Closed the browser.")),!0);const fe=w.fileURLToPath(new URL(".","undefined"==typeof document?require("url").pathToFileURL(__filename).href:y&&y.src||new URL("index.cjs",document.baseURI).href)),ye=(e,t,r)=>e.evaluate(((e,t)=>window.triggerExport(e,t)),t,r);var ve=async(e,i,o)=>{const n=[],s=async e=>{for(const e of n)await e.dispose();await e.evaluate((()=>{const[,...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...r]=document.getElementsByTagName("link");for(const i of[...e,...t,...r])i.remove()}))};try{I(4,"[export] Determining export path.");const a=o.export;await e.evaluate((()=>requestAnimationFrame((()=>{}))));const l=a?.options?.chart?.displayErrors&&Q().activeManifest.modules.debugger;let c;if(await e.evaluate((e=>window._displayErrors=e),l),i.indexOf&&(i.indexOf("=0||i.indexOf("=0)){if(I(4,"[export] Treating as SVG."),"svg"===a.type)return i;c=!0,await e.setContent((e=>`\n\n\n \n \n Highcarts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`)(i))}else I(4,"[export] Treating as config."),a.strInj?await ye(e,{chart:{height:a.height,width:a.width}},o):(i.chart.height=a.height,i.chart.width=a.width,await ye(e,i,o));const p=o.customLogic.resources;if(p){if(p.js&&n.push(await e.addScriptTag({content:p.js})),p.files)for(const r of p.files)try{const i=!r.startsWith("http");n.push(await e.addScriptTag(i?{content:t.readFileSync(r,"utf8")}:{url:r}))}catch(e){_(2,e,`[export] The JS file ${r} 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")?n.push(await e.addStyleTag({url:i})):o.customLogic.allowFileResources&&n.push(await e.addStyleTag({path:r.join(fe,i)})));n.push(await e.addStyleTag({content:p.css.replace(/@import\s*([^;]*);/g,"")||" "}))}}const u=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(a.scale)):await e.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 e.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 e.evaluate(g,parseFloat(a.scale));const{height:m,width:f,x:y,y:v}=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)}})))(e);let w;if(c||await e.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)))(e);else if("png"===a.type||"jpeg"===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 M("Rasterization timeout"))),o||1500)))]))(e,a.type,"base64",{width:d,height:h,x:y,y:v},a.rasterizationTimeout);else{if("pdf"!==a.type)throw new M(`[export] Unsupported output format ${a.type}.`);w=await((e,t,r,i)=>e.pdf({height:t+1,width:r,encoding:i}))(e,h,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}};let we,be=0,Te=0,xe=0,ke=0,Ee=0,Se={},Le=!1;const Re={create:async()=>{let e=!1;const t=c.v4(),r=(new Date).getTime();try{if(e=await ge(),!e||e.isClosed())throw new M("The page is invalid or closed.");I(3,`[pool] Successfully created a worker ${t} - took ${(new Date).getTime()-r} ms.`)}catch(e){throw new M("Error encountered when creating a new page.").setError(e)}return{id:t,page:e,workCount:Math.round(Math.random()*(Se.workLimit/2))}},validate:async e=>Se.workLimit&&++e.workCount>Se.workLimit?(I(3,`[pool] Worker failed validation: exceeded work limit (limit is ${Se.workLimit}).`),!1):(await de(e.page,!0),!0),destroy:e=>{I(3,`[pool] Destroying pool entry ${e.id}.`),e.page&&e.page.close()}},Oe=async e=>{if(Se=e&&e.pool?{...e.pool}:{},Se.listenToProcessExits&&(I(3,"[pool] Attaching exit listeners to the process."),process.on("exit",(async e=>{I(4,`Process exited with code ${e}.`),await Ie()})),process.on("SIGINT",((e,t)=>{I(4,`The ${e} event with code: ${t}.`),process.exit(1)})),process.on("SIGTERM",((e,t)=>{I(4,`The ${e} event with code: ${t}.`),process.exit(1)})),process.on("uncaughtException",(async(e,t)=>{_(1,e,`The ${t} error.`),await Ie(),process.exit(1)}))),we=e.puppeteerArgs,await(async e=>{const t=[...le,...e||[]];if(!ue){let e=0;const r=async()=>{try{I(3,`[browser] Attempting to get a browser instance (try ${++e}).`),ue=await u.launch({headless:"new",args:t,userDataDir:"./tmp/"})}catch(t){if(_(1,t,"[browser] Failed to launch a browser instance."),!(e<25))throw t;I(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 M("[browser] Maximum retries to open a browser instance reached.").setError(e)}if(!ue)throw new M("[browser] Cannot find a browser to open.")}return ue})(we),I(3,`[pool] Initializing pool with workers: min ${Se.minWorkers}, max ${Se.maxWorkers}.`),Le)return I(4,"[pool] Already initialized, please kill it before creating a new one.");parseInt(Se.minWorkers)>parseInt(Se.maxWorkers)&&(Se.minWorkers=Se.maxWorkers);try{Le=new l.Pool({...Re,min:parseInt(Se.minWorkers),max:parseInt(Se.maxWorkers),acquireTimeoutMillis:Se.acquireTimeout,createTimeoutMillis:Se.createTimeout,destroyTimeoutMillis:Se.destroyTimeout,idleTimeoutMillis:Se.idleTimeout,createRetryIntervalMillis:Se.createRetryInterval,reapIntervalMillis:Se.reaperInterval,propagateCreateError:!1}),Le.on("release",(async e=>{await de(e.page,!1),I(4,`[pool] Releasing a worker with ID ${e.id}.`)})),Le.on("destroySuccess",((e,t)=>{I(4,`[pool] Destroyed a worker with ID ${t.id}.`)}));const e=[];for(let t=0;t{Le.release(e)})),I(3,"[pool] The pool is ready"+(e.length?` with ${e.length} initial resources waiting.`:"."))}catch(e){throw await me(),new M("[pool] Could not create the pool of workers.").setError(e)}};async function Ie(){return I(3,"[pool] Killing all pool workers and browser, if any exist."),Le?.destroyed||Le&&(await Le.destroy(),I(4,"[browser] Destroyed the pool of resources.")),me()}const _e=async(e,t)=>{let r;try{if(I(4,"[pool] Work received, starting to process."),++Te,Se.benchmarking&&Ce(),!Le)throw new M("Work received, but pool has not been started.");try{I(4,"[pool] Acquiring a worker handle.");const e=D();r=await Le.acquire().promise,t.server.benchmarking&&I(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Acquired a worker handle: ${e()}ms.`)}catch(e){throw new M("Error encountered when acquiring an available entry.").setError(e)}if(I(4,"[pool] Acquired a worker handle."),!r.page)throw new M("Resolved worker page is invalid: the pool setup is wonky.");let i=(new Date).getTime();I(4,`[pool] Starting work on pool entry with ID ${r.id}.`);const o=D(),n=await ve(r.page,e,t);if(n instanceof Error)throw"Rasterization timeout"===n.message&&(r.page.close(),r.page=await ge()),new M("Error encountered during export.").setError(n);t.server.benchmarking&&I(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Exported a chart sucessfully: ${o()}ms.`),Le.release(r);const s=(new Date).getTime()-i;return xe+=s,Ee=xe/++be,I(4,`[pool] Work completed in ${s} ms.`),{result:n,options:t}}catch(e){throw++ke,r&&Le.release(r),new M(`[pool] In pool.postWork: ${e.message}`).setError(e)}};function Ce(){const{min:e,max:t}=Le;I(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),I(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),I(5,`[pool] The number of resources that are currently available: ${Le.numFree()}.`),I(5,`[pool] The number of resources that are currently acquired: ${Le.numUsed()}.`),I(5,`[pool] The number of callers waiting to acquire a resource: ${Le.numPendingAcquires()}.`)}var $e=()=>({min:Le.min,max:Le.max,available:Le.numFree(),inUse:Le.numUsed(),pendingAcquire:Le.numPendingAcquires()}),Pe=()=>Te,Ne=()=>ke,je=()=>Ee,Ae=()=>be;let He=!1;const Fe=async(e,r)=>{I(4,"[chart] Starting the exporting process.");const i=((e,t={})=>{let r={};return e.svg?(r=H(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=re(t,e,k),r.export.outfile=r.export?.outfile||`chart.${r.export?.type||"png"}`,r})(e,te()),o=i.export;if(i.payload?.svg&&""!==i.payload.svg)try{return I(4,"[chart] Attempting to export from a SVG input."),De(i.payload.svg.trim(),i,r)}catch(e){return r(new M("[chart] Error loading SVG input.").setError(e))}if(o.infile&&o.infile.length)try{return I(4,"[chart] Attempting to export from an input file."),i.export.instr=t.readFileSync(o.infile,"utf8"),De(i.export.instr.trim(),i,r)}catch(e){return r(new M("[chart] Error loading input file.").setError(e))}if(o.instr&&""!==o.instr||o.options&&""!==o.options)try{return I(4,"[chart] Attempting to export from a raw input."),q(i.customLogic?.allowCodeExecution)?We(i,r):"string"==typeof o.instr?De(o.instr.trim(),i,r):qe(i,o.instr||o.options,r)}catch(e){return r(new M("[chart] Error loading raw input.").setError(e))}return r(new M("[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||A(e.export?.instr),i=A(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},qe=async(e,r,i,o)=>{let{export:n,customLogic:s}=e;const a="boolean"==typeof s.allowCodeExecution?s.allowCodeExecution:He;if(s){if(a)if("string"==typeof e.customLogic.resources)e.customLogic.resources=j(e.customLogic.resources,q(e.customLogic.allowFileResources));else if(!e.customLogic.resources)try{const r=t.readFileSync("resources.json","utf8");e.customLogic.resources=j(r,q(e.customLogic.allowFileResources))}catch(e){_(2,e,"[chart] Unable to load the default resources.json file.")}}else s=e.customLogic={};if(!a&&s){if(s.callback||s.resources||s.customCode)return i(new M("[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=N(n.type,n.outfile),"svg"===n.type&&(n.width=!1),["globalOptions","themeOptions"].forEach((e=>{try{n&&n[e]&&("string"==typeof n[e]&&n[e].endsWith(".json")?n[e]=A(t.readFileSync(n[e],"utf8"),!0):n[e]=A(n[e],!0))}catch(t){n[e]={},_(2,t,`[chart] The '${e}' cannot be loaded.`)}})),s.allowCodeExecution)try{s.customCode=W(s.customCode,s.allowFileResources)}catch(e){_(2,e,"[chart] The 'customCode' cannot be loaded.")}if(s&&s.callback&&s.callback?.indexOf("{")<0)if(s.allowFileResources)try{s.callback=t.readFileSync(s.callback,"utf8")}catch(e){s.callback=!1,_(2,e,"[chart] The 'callback' cannot be loaded.")}else s.callback=!1;e.export={...e.export,...Ue(e)};try{return i(!1,await _e(n.strInj||r||o,e))}catch(e){return i(e)}},We=(e,t)=>{try{let r,i=e.export.instr||e.export.options;return"string"!=typeof i&&(r=i=F(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 M(`[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))}},De=(e,t,r)=>{const{allowCodeExecution:i}=t.customLogic;if(e.indexOf("=0||e.indexOf("=0)return I(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 q(i)?We(t,r):r(new M("[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=(e,t,r,i)=>{_(1,e),"development"!==process.env.NODE_ENV&&delete e.stack,i(e)},Ge=(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=f({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&&(I(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(o),I(3,`[rate limiting] Enabled rate limiting with ${i.max} requests per ${i.window} minute for each IP, trusting proxy: ${i.trustProxy}.`)};class Je extends M{constructor(e,t){super(e),this.status=this.statusCode=t}setStatus(e){return this.status=e,this}}const Ke={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};let ze=0;const Xe=[],Be=[],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=D(),o=c.v4().replace(/-/g,""),n=te(),s=e.body,a=++ze;let l=N(s.type);if(!s||"object"==typeof(i=s)&&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 p=A(s.infile||s.options||s.data);if(!p&&!s.svg)throw I(2,`The request with ID ${o} from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Payload received: ${JSON.stringify(s)}.`),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=Ye(Xe,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})),I(4,`[export] Got an incoming HTTP request with ID ${o}.`),s.constr="string"==typeof s.constr&&s.constr||"chart";const d={export:{instr:p,type:l,constr:s.constr[0].toLowerCase()+s.constr.substr(1),height:s.height,width:s.width,scale:s.scale||n.export.scale,globalOptions:A(s.globalOptions,!0),themeOptions:A(s.themeOptions,!0)},customLogic:{allowCodeExecution:He,allowFileResources:!1,resources:A(s.resources,!0),callback:s.callback,customCode:s.customCode}};p&&(d.export.instr=F(p,d.customLogic.allowCodeExecution));const g=re(n,d);if(g.export.options=p,g.payload={svg:s.svg||!1,b64:s.b64||!1,noDownload:s.noDownload||!1,requestId:o},s.svg&&(e=>["localhost","(10).(.*).(.*).(.*)","(127).(.*).(.*).(.*)","(172).(1[6-9]|2[0-9]|3[0-1]).(.*).(.*)","(192).(168).(.*).(.*)"].some((t=>e.match(`xlink:href="(?:(http://|https://))?${t}`))))(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"),n.server.benchmarking&&I(5,`[benchmark] Request with ID ${o} - After the whole exporting process: ${r()}ms.`),h)return I(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,Ye(Be,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",Ke[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(t.readFileSync(r.join(P,"package.json"))),et=new Date;const tt=g();tt.disable("x-powered-by"),tt.use(d());const rt=m.memoryStorage(),it=m({storage:rt,limits:{fieldSize:52428800}});tt.use(g.json({limit:52428800})),tt.use(g.urlencoded({extended:!0,limit:52428800})),tt.use(it.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}`)}))}))},nt=async e=>{try{if(!e.enable)return!1;if(!e.ssl.force){const t=o.createServer(tt);ot(t),t.listen(e.port,e.host),I(3,`[server] Started HTTP server on ${e.host}:${e.port}.`)}if(e.ssl.enable){let i,o;try{i=await t.promises.readFile(r.posix.join(e.ssl.certPath,"server.key"),"utf8"),o=await t.promises.readFile(r.posix.join(e.ssl.certPath,"server.crt"),"utf8")}catch(t){I(2,`[server] Unable to load key/certificate from the '${e.ssl.certPath}' path. Could not run secured layer server.`)}if(i&&o){const t=n.createServer(tt);ot(t),t.listen(e.ssl.port,e.host),I(3,`[server] Started HTTPS server on ${e.host}:${e.ssl.port}.`)}}e.rateLimiting&&e.rateLimiting.enable&&![0,NaN].includes(e.rateLimiting.maxRequests)&&Ve(tt,e.rateLimiting),tt.use(g.static(r.posix.join(P,"public"))),(e=>{!!e&&e.get("/health",((e,t)=>{t.send({status:"OK",bootTime:et,uptime:Math.floor(((new Date).getTime()-et.getTime())/1e3/60)+" minutes",version:Ze.version,highchartsVersion:Z(),averageProcessingTime:je(),performedExports:Ae(),failedExports:Ne(),exportAttempts:Pe(),sucessRatio:Ae()/Pe()*100,pool:$e()})}))})(tt),(e=>{e.post("/",Qe),e.post("/:filename",Qe)})(tt),(e=>{!!e&&e.get("/",((e,t)=>{t.sendFile(r.join(P,"public","index.html"))}))})(tt),(e=>{!!e&&e.post("/version/change/:newVersion",(async(e,t,r)=>{try{const r=process.env.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 Y(o)}catch(e){throw new Je(`Version change: ${e.message}`,e.statusCode).setError(e)}t.status(200).send({statusCode:200,version:Z(),message:`Successfully updated Highcharts to version: ${o}.`})}catch(e){r(e)}}))})(tt),(e=>{e.use(Me),e.use(Ge)})(tt)}catch(e){throw new M("[server] Could not configure and start the server.").setError(e)}};var st={startServer:nt,enableRateLimiting:e=>Ve(tt,e),getExpress:()=>g,getApp:()=>tt,use:(e,...t)=>{tt.use(e,...t)},get:(e,...t)=>{tt.get(e,...t)},post:(e,...t)=>{tt.post(e,...t)}};e.config();var at={server:st,startServer:nt,setOptions:(e,r)=>(r?.length&&(ee=function(e){const r=e.findIndex((e=>"loadConfig"===e.replace(/-/g,"")));if(r>-1&&e[r+1]){const i=e[r+1];try{if(i&&i.endsWith(".json"))return JSON.parse(t.readFileSync(i))}catch(e){_(2,e,`[config] Unable to load the configuration from the ${i} file.`)}}return{}}(r)),ie(T,ee),ee=oe(T),e&&(ee=re(ee,e,k)),r?.length&&(ee=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]=q(t[o]):"number"===a?e[r]=+t[o]:a.indexOf("]")>=0?e[r]=t[o].split(","):e[r]=t[o]:(I(2,`[config] Missing value for the '${n}' argument. Using the default value.`),i=!0)),e[r])),e)}i&&U();return e}(ee,r,T)),ee),initExport:async e=>{var t;return t=e.customLogic&&e.customLogic.allowCodeExecution,He=q(t),(e=>{C(e&&parseInt(e.level)),e&&e.dest&&$(e.dest,e.file||"highcharts-export-server.log")})(e.logging),await X(e.highcharts||{version:"latest"}),await Oe({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,r)=>{if(e)throw e;const{outfile:i,type:o}=r.options.export;t.writeFileSync(i||`chart.${o}`,"svg"!==o?Buffer.from(r.result,"base64"):r.result),await Ie()}))},batchExport:async e=>{const r=[];for(let i of e.export.batch.split(";"))i=i.split("="),2===i.length&&r.push(Fe({...e,export:{...e.export,infile:i[0],outfile:i[1]}},((e,r)=>{if(e)throw e;t.writeFileSync(r.options.export.outfile,Buffer.from(r.result,"base64"))})));try{await Promise.all(r),await Ie()}catch(e){throw new M("[chart] Error encountered during batch export.").setError(e)}},startExport:Fe,killPool:Ie,log:I,logWithStack:_,setLogLevel:C,enableFileLogging:$,mapToNewConfig:e=>{const t={};for(const[r,i]of Object.entries(e)){const e=E[r]?E[r].split("."):[];e.reduce(((t,r,o)=>t[r]=e.length-1===o?i:t[r]||{}),t)}return t},manualConfig:async e=>{let r={};t.existsSync(e)&&(r=JSON.parse(t.readFileSync(e,"utf8")));const i=Object.keys(x).map((e=>({title:`${e} options`,value:e})));return a({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,o)=>{let n=0,s=[];for(const e of o)x[e]=x[e].map((t=>({...t,section:e}))),s=[...s,...x[e]];return await a(s,{onSubmit:async(i,o)=>{if("modules"===i.name?(o=o.length?o.map((e=>i.choices[e])):i.choices,r[i.section][i.name]=o):r[i.section]=ne(Object.assign({},r[i.section]||{}),i.name.split("."),i.choices?i.choices[o]:o),++n===s.length){try{await t.promises.writeFile(e,JSON.stringify(r,null,2),"utf8")}catch(t){_(1,t,`[config] An error occurred while creating the ${e} file.`)}return!0}}}),!0}})},printLogo:e=>{const i=JSON.parse(t.readFileSync(r.join(P,"package.json"))).version;e?console.log(`Starting Highcharts Export Server v${i}...`):console.log(t.readFileSync(P+"/msg/startup.msg").toString().bold.yellow,`v${i}`)},printUsage:U};module.exports=at; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguY2pzIiwic291cmNlcyI6WyIuLi9saWIvZmV0Y2guanMiLCIuLi9saWIvc2NoZW1hcy9jb25maWcuanMiLCIuLi9saWIvbG9nZ2VyLmpzIiwiLi4vbGliL3V0aWxzLmpzIiwiLi4vbGliL2Vycm9ycy9FeHBvcnRFcnJvci5qcyIsIi4uL2xpYi9jYWNoZS5qcyIsIi4uL2xpYi9jb25maWcuanMiLCIuLi9saWIvYnJvd3Nlci5qcyIsIi4uL2xpYi9leHBvcnQuanMiLCIuLi90ZW1wbGF0ZXMvc3ZnX2V4cG9ydC9zdmdfZXhwb3J0LmpzIiwiLi4vbGliL3Bvb2wuanMiLCIuLi9saWIvY2hhcnQuanMiLCIuLi9saWIvc2VydmVyL2Vycm9yLmpzIiwiLi4vbGliL3NlcnZlci9yYXRlX2xpbWl0LmpzIiwiLi4vbGliL2Vycm9ycy9IdHRwRXJyb3IuanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy9leHBvcnQuanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy9oZWFsdGguanMiLCIuLi9saWIvc2VydmVyL3NlcnZlci5qcyIsIi4uL2xpYi9zZXJ2ZXIvcm91dGVzL3VpLmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvY2hhbmdlX2hjX3ZlcnNpb24uanMiLCIuLi9saWIvaW5kZXguanMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqXHJcbiAqIFRoaXMgbW9kdWxlIGV4cG9ydHMgdHdvIGZ1bmN0aW9uczogZmV0Y2ggKGZvciBHRVQgcmVxdWVzdHMpIGFuZCBwb3N0IChmb3IgUE9TVCByZXF1ZXN0cykuXHJcbiAqL1xyXG5cclxuaW1wb3J0IGh0dHAgZnJvbSAnaHR0cCc7XHJcbmltcG9ydCBodHRwcyBmcm9tICdodHRwcyc7XHJcblxyXG4vKipcclxuICogUmV0dXJucyB0aGUgSFRUUCBvciBIVFRQUyBwcm90b2NvbCBtb2R1bGUgYmFzZWQgb24gdGhlIHByb3ZpZGVkIFVSTC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHVybCAtIFRoZSBVUkwgdG8gZGV0ZXJtaW5lIHRoZSBwcm90b2NvbC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wgbW9kdWxlIChodHRwIG9yIGh0dHBzKS5cclxuICovXHJcbmNvbnN0IGdldFByb3RvY29sID0gKHVybCkgPT4gKHVybC5zdGFydHNXaXRoKCdodHRwcycpID8gaHR0cHMgOiBodHRwKTtcclxuXHJcbi8qKlxyXG4gKiBGZXRjaGVzIGRhdGEgZnJvbSB0aGUgc3BlY2lmaWVkIFVSTCB1c2luZyBlaXRoZXIgSFRUUCBvciBIVFRQUyBwcm90b2NvbC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHVybCAtIFRoZSBVUkwgdG8gZmV0Y2ggZGF0YSBmcm9tLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcmVxdWVzdE9wdGlvbnMgLSBPcHRpb25zIGZvciB0aGUgSFRUUCByZXF1ZXN0IChvcHRpb25hbCkuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBIVFRQIHJlc3BvbnNlIG9iamVjdFxyXG4gKiB3aXRoIGFkZGVkICd0ZXh0JyBwcm9wZXJ0eSBvciByZWplY3Rpbmcgd2l0aCBhbiBlcnJvci5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIGZldGNoKHVybCwgcmVxdWVzdE9wdGlvbnMgPSB7fSkge1xyXG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XHJcbiAgICBjb25zdCBwcm90b2NvbCA9IGdldFByb3RvY29sKHVybCk7XHJcblxyXG4gICAgcHJvdG9jb2xcclxuICAgICAgLmdldCh1cmwsIHJlcXVlc3RPcHRpb25zLCAocmVzKSA9PiB7XHJcbiAgICAgICAgbGV0IGRhdGEgPSAnJztcclxuXHJcbiAgICAgICAgLy8gQSBjaHVuayBvZiBkYXRhIGhhcyBiZWVuIHJlY2VpdmVkLlxyXG4gICAgICAgIHJlcy5vbignZGF0YScsIChjaHVuaykgPT4ge1xyXG4gICAgICAgICAgZGF0YSArPSBjaHVuaztcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgLy8gVGhlIHdob2xlIHJlc3BvbnNlIGhhcyBiZWVuIHJlY2VpdmVkLlxyXG4gICAgICAgIHJlcy5vbignZW5kJywgKCkgPT4ge1xyXG4gICAgICAgICAgaWYgKCFkYXRhKSB7XHJcbiAgICAgICAgICAgIHJlamVjdCgnTm90aGluZyB3YXMgZmV0Y2hlZCBmcm9tIHRoZSBVUkwuJyk7XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgcmVzLnRleHQgPSBkYXRhO1xyXG4gICAgICAgICAgcmVzb2x2ZShyZXMpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICB9KVxyXG4gICAgICAub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICAgICAgcmVqZWN0KGVycm9yKTtcclxuICAgICAgfSk7XHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZW5kcyBhIFBPU1QgcmVxdWVzdCB0byB0aGUgc3BlY2lmaWVkIFVSTCB3aXRoIHRoZSBwcm92aWRlZCBKU09OIGJvZHkgdXNpbmdcclxuICogZWl0aGVyIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgLSBUaGUgVVJMIHRvIHNlbmQgdGhlIFBPU1QgcmVxdWVzdCB0by5cclxuICogQHBhcmFtIHtPYmplY3R9IGJvZHkgLSBUaGUgSlNPTiBib2R5IHRvIGluY2x1ZGUgaW4gdGhlIFBPU1QgcmVxdWVzdFxyXG4gKiAob3B0aW9uYWwsIGRlZmF1bHQgaXMgYW4gZW1wdHkgb2JqZWN0KS5cclxuICogQHBhcmFtIHtPYmplY3R9IHJlcXVlc3RPcHRpb25zIC0gT3B0aW9ucyBmb3IgdGhlIEhUVFAgcmVxdWVzdCAob3B0aW9uYWwpLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgSFRUUCByZXNwb25zZSBvYmplY3Qgd2l0aFxyXG4gKiBhZGRlZCAndGV4dCcgcHJvcGVydHkgb3IgcmVqZWN0aW5nIHdpdGggYW4gZXJyb3IuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBwb3N0KHVybCwgYm9keSA9IHt9LCByZXF1ZXN0T3B0aW9ucyA9IHt9KSB7XHJcbiAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcclxuICAgIGNvbnN0IHByb3RvY29sID0gZ2V0UHJvdG9jb2wodXJsKTtcclxuICAgIGNvbnN0IGRhdGEgPSBKU09OLnN0cmluZ2lmeShib2R5KTtcclxuXHJcbiAgICAvLyBTZXQgZGVmYXVsdCBoZWFkZXJzIGFuZCBtZXJnZSB3aXRoIHJlcXVlc3RPcHRpb25zXHJcbiAgICBjb25zdCBvcHRpb25zID0gT2JqZWN0LmFzc2lnbihcclxuICAgICAge1xyXG4gICAgICAgIG1ldGhvZDogJ1BPU1QnLFxyXG4gICAgICAgIGhlYWRlcnM6IHtcclxuICAgICAgICAgICdDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbicsXHJcbiAgICAgICAgICAnQ29udGVudC1MZW5ndGgnOiBkYXRhLmxlbmd0aFxyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgcmVxdWVzdE9wdGlvbnNcclxuICAgICk7XHJcblxyXG4gICAgY29uc3QgcmVxID0gcHJvdG9jb2xcclxuICAgICAgLnJlcXVlc3QodXJsLCBvcHRpb25zLCAocmVzKSA9PiB7XHJcbiAgICAgICAgbGV0IHJlc3BvbnNlRGF0YSA9ICcnO1xyXG5cclxuICAgICAgICAvLyBBIGNodW5rIG9mIGRhdGEgaGFzIGJlZW4gcmVjZWl2ZWQuXHJcbiAgICAgICAgcmVzLm9uKCdkYXRhJywgKGNodW5rKSA9PiB7XHJcbiAgICAgICAgICByZXNwb25zZURhdGEgKz0gY2h1bms7XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICAgIC8vIFRoZSB3aG9sZSByZXNwb25zZSBoYXMgYmVlbiByZWNlaXZlZC5cclxuICAgICAgICByZXMub24oJ2VuZCcsICgpID0+IHtcclxuICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgIHJlcy50ZXh0ID0gcmVzcG9uc2VEYXRhO1xyXG4gICAgICAgICAgICByZXNvbHZlKHJlcyk7XHJcbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICByZWplY3QoZXJyb3IpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH0pO1xyXG4gICAgICB9KVxyXG4gICAgICAub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICAgICAgcmVqZWN0KGVycm9yKTtcclxuICAgICAgfSk7XHJcblxyXG4gICAgLy8gV3JpdGUgdGhlIHJlcXVlc3QgYm9keSBhbmQgZW5kIHRoZSByZXF1ZXN0LlxyXG4gICAgcmVxLndyaXRlKGRhdGEpO1xyXG4gICAgcmVxLmVuZCgpO1xyXG4gIH0pO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCBmZXRjaDtcclxuZXhwb3J0IHsgZmV0Y2gsIHBvc3QgfTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vLyBUaGlzIGlzIHRoZSBjb25maWd1cmF0aW9uIG9iamVjdCB3aXRoIGFsbCBvcHRpb25zIGFuZCB0aGVpciBkZWZhdWx0IHZhbHVlcyxcclxuLy8gYWxzbyBmcm9tIHRoZSAuZW52IGZpbGUgaWYgb25lIGV4aXN0c1xyXG5leHBvcnQgY29uc3QgZGVmYXVsdENvbmZpZyA9IHtcclxuICBwdXBwZXRlZXI6IHtcclxuICAgIGFyZ3M6IHtcclxuICAgICAgdmFsdWU6IFtdLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0FyZ3VtZW50cyBhcnJheSB0byBzZW5kIHRvIFB1cHBldGVlci4nXHJcbiAgICB9XHJcbiAgfSxcclxuICBoaWdoY2hhcnRzOiB7XHJcbiAgICB2ZXJzaW9uOiB7XHJcbiAgICAgIHZhbHVlOiAnbGF0ZXN0JyxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfVkVSU0lPTicsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBIaWdoY2hhcnRzIHZlcnNpb24gdG8gYmUgdXNlZC4nXHJcbiAgICB9LFxyXG4gICAgY2RuVVJMOiB7XHJcbiAgICAgIHZhbHVlOiAnaHR0cHM6Ly9jb2RlLmhpZ2hjaGFydHMuY29tLycsXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0NETl9VUkwnLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgQ0ROIFVSTCBmb3IgSGlnaGNoYXJ0cyBzY3JpcHRzIHRvIGJlIHVzZWQuJ1xyXG4gICAgfSxcclxuICAgIGNvcmVTY3JpcHRzOiB7XHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0NPUkVfU0NSSVBUUycsXHJcbiAgICAgIHZhbHVlOiBbJ2hpZ2hjaGFydHMnLCAnaGlnaGNoYXJ0cy1tb3JlJywgJ2hpZ2hjaGFydHMtM2QnXSxcclxuICAgICAgdHlwZTogJ3N0cmluZ1tdJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgY29yZSBIaWdoY2hhcnRzIHNjcmlwdHMgdG8gZmV0Y2guJ1xyXG4gICAgfSxcclxuICAgIG1vZHVsZXM6IHtcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfTU9EVUxFUycsXHJcbiAgICAgIHZhbHVlOiBbXHJcbiAgICAgICAgJ3N0b2NrJyxcclxuICAgICAgICAnbWFwJyxcclxuICAgICAgICAnZ2FudHQnLFxyXG4gICAgICAgICdleHBvcnRpbmcnLFxyXG4gICAgICAgICdleHBvcnQtZGF0YScsXHJcbiAgICAgICAgJ3BhcmFsbGVsLWNvb3JkaW5hdGVzJyxcclxuICAgICAgICAnYWNjZXNzaWJpbGl0eScsXHJcbiAgICAgICAgJ2Fubm90YXRpb25zLWFkdmFuY2VkJyxcclxuICAgICAgICAnYm9vc3QtY2FudmFzJyxcclxuICAgICAgICAnYm9vc3QnLFxyXG4gICAgICAgICdkYXRhJyxcclxuICAgICAgICAnZGF0YS10b29scycsXHJcbiAgICAgICAgJ2RyYWdnYWJsZS1wb2ludHMnLFxyXG4gICAgICAgICdzdGF0aWMtc2NhbGUnLFxyXG4gICAgICAgICdicm9rZW4tYXhpcycsXHJcbiAgICAgICAgJ2hlYXRtYXAnLFxyXG4gICAgICAgICd0aWxlbWFwJyxcclxuICAgICAgICAndGlsZWR3ZWJtYXAnLFxyXG4gICAgICAgICd0aW1lbGluZScsXHJcbiAgICAgICAgJ3RyZWVtYXAnLFxyXG4gICAgICAgICd0cmVlZ3JhcGgnLFxyXG4gICAgICAgICdpdGVtLXNlcmllcycsXHJcbiAgICAgICAgJ2RyaWxsZG93bicsXHJcbiAgICAgICAgJ2hpc3RvZ3JhbS1iZWxsY3VydmUnLFxyXG4gICAgICAgICdidWxsZXQnLFxyXG4gICAgICAgICdmdW5uZWwnLFxyXG4gICAgICAgICdmdW5uZWwzZCcsXHJcbiAgICAgICAgJ2dlb2hlYXRtYXAnLFxyXG4gICAgICAgICdweXJhbWlkM2QnLFxyXG4gICAgICAgICduZXR3b3JrZ3JhcGgnLFxyXG4gICAgICAgICdvdmVybGFwcGluZy1kYXRhbGFiZWxzJyxcclxuICAgICAgICAncGFyZXRvJyxcclxuICAgICAgICAncGF0dGVybi1maWxsJyxcclxuICAgICAgICAncGljdG9yaWFsJyxcclxuICAgICAgICAncHJpY2UtaW5kaWNhdG9yJyxcclxuICAgICAgICAnc2Fua2V5JyxcclxuICAgICAgICAnYXJjLWRpYWdyYW0nLFxyXG4gICAgICAgICdkZXBlbmRlbmN5LXdoZWVsJyxcclxuICAgICAgICAnc2VyaWVzLWxhYmVsJyxcclxuICAgICAgICAnc29saWQtZ2F1Z2UnLFxyXG4gICAgICAgICdzb25pZmljYXRpb24nLFxyXG4gICAgICAgICdzdG9jay10b29scycsXHJcbiAgICAgICAgJ3N0cmVhbWdyYXBoJyxcclxuICAgICAgICAnc3VuYnVyc3QnLFxyXG4gICAgICAgICd2YXJpYWJsZS1waWUnLFxyXG4gICAgICAgICd2YXJpd2lkZScsXHJcbiAgICAgICAgJ3ZlY3RvcicsXHJcbiAgICAgICAgJ3Zlbm4nLFxyXG4gICAgICAgICd3aW5kYmFyYicsXHJcbiAgICAgICAgJ3dvcmRjbG91ZCcsXHJcbiAgICAgICAgJ3hyYW5nZScsXHJcbiAgICAgICAgJ25vLWRhdGEtdG8tZGlzcGxheScsXHJcbiAgICAgICAgJ2RyYWctcGFuZXMnLFxyXG4gICAgICAgICdkZWJ1Z2dlcicsXHJcbiAgICAgICAgJ2R1bWJiZWxsJyxcclxuICAgICAgICAnbG9sbGlwb3AnLFxyXG4gICAgICAgICdjeWxpbmRlcicsXHJcbiAgICAgICAgJ29yZ2FuaXphdGlvbicsXHJcbiAgICAgICAgJ2RvdHBsb3QnLFxyXG4gICAgICAgICdtYXJrZXItY2x1c3RlcnMnLFxyXG4gICAgICAgICdob2xsb3djYW5kbGVzdGljaycsXHJcbiAgICAgICAgJ2hlaWtpbmFzaGknLFxyXG4gICAgICAgICdmbG93bWFwJ1xyXG4gICAgICBdLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBtb2R1bGVzIG9mIEhpZ2hjaGFydHMgdG8gZmV0Y2guJ1xyXG4gICAgfSxcclxuICAgIGluZGljYXRvcnM6IHtcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfSU5ESUNBVE9SUycsXHJcbiAgICAgIHZhbHVlOiBbJ2luZGljYXRvcnMtYWxsJ10sXHJcbiAgICAgIHR5cGU6ICdzdHJpbmdbXScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIGluZGljYXRvcnMgb2YgSGlnaGNoYXJ0cyB0byBmZXRjaC4nXHJcbiAgICB9LFxyXG4gICAgc2NyaXB0czoge1xyXG4gICAgICB2YWx1ZTogW1xyXG4gICAgICAgICdodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9tb21lbnQuanMvMi4yOS40L21vbWVudC5taW4uanMnLFxyXG4gICAgICAgICdodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9tb21lbnQtdGltZXpvbmUvMC41LjM0L21vbWVudC10aW1lem9uZS13aXRoLWRhdGEubWluLmpzJ1xyXG4gICAgICBdLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0FkZGl0aW9uYWwgb3B0aW9uYWwgc2NyaXB0cyBvciBkZXBlbmRlbmNpZXMgdG8gZmV0Y2guJ1xyXG4gICAgfSxcclxuICAgIGZvcmNlRmV0Y2g6IHtcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfRk9SQ0VfRkVUQ0gnLFxyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBmbGFnIHRvIGRldGVybWluZSB3aGV0aGVyIHRvIHJlZmV0Y2ggYWxsIHNjcmlwdHMgYWZ0ZXIgZWFjaCBzZXJ2ZXIgcmVydW4uJ1xyXG4gICAgfSxcclxuICAgIGNhY2hlUGF0aDoge1xyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DQUNIRV9QQVRIJyxcclxuICAgICAgdmFsdWU6ICcuY2FjaGUnLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBwYXRoIHRvIHRoZSBjYWNoZSBkaXJlY3RvcnkuIEl0IGlzIHVzZWQgdG8gc3RvcmUgdGhlIEhpZ2hjaGFydHMgc2NyaXB0cyBhbmQgY3VzdG9tIHNjcmlwdHMuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgZXhwb3J0OiB7XHJcbiAgICBpbmZpbGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBpbnB1dCBmaWxlIHNob3VsZCBpbmNsdWRlIGEgbmFtZSBhbmQgYSB0eXBlIChqc29uIG9yIHN2ZykuIEl0IG11c3QgYmUgY29ycmVjdGx5IGZvcm1hdHRlZCBhcyBhIEpTT04gb3IgU1ZHIGZpbGUuJ1xyXG4gICAgfSxcclxuICAgIGluc3RyOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbnB1dCwgcHJvdmlkZWQgaW4gdGhlIGZvcm0gb2YgYSBzdHJpbmdpZmllZCBKU09OIG9yIFNWRyBmaWxlLCB3aWxsIG92ZXJyaWRlIHRoZSAtLWluZmlsZSBvcHRpb24uJ1xyXG4gICAgfSxcclxuICAgIG9wdGlvbnM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdBbiBhbGlhcyBmb3IgdGhlIC0taW5zdHIgb3B0aW9uLidcclxuICAgIH0sXHJcbiAgICBvdXRmaWxlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgb3V0cHV0IGZpbGVuYW1lIGFsb25nIHdpdGggYSB0eXBlIChqcGVnLCBwbmcsIHBkZiwgb3Igc3ZnKS4gVGhpcyB3aWxsIGlnbm9yZSB0aGUgLS10eXBlIGZsYWcuJ1xyXG4gICAgfSxcclxuICAgIHR5cGU6IHtcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9UWVBFJyxcclxuICAgICAgdmFsdWU6ICdwbmcnLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgZmlsZSBleHBvcnQgZm9ybWF0LiBJdCBjYW4gYmUganBlZywgcG5nLCBwZGYsIG9yIHN2Zy4nXHJcbiAgICB9LFxyXG4gICAgY29uc3RyOiB7XHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfQ09OU1RSJyxcclxuICAgICAgdmFsdWU6ICdjaGFydCcsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGNvbnN0cnVjdG9yIHRvIHVzZS4gQ2FuIGJlIGNoYXJ0LCBzdG9ja0NoYXJ0LCBtYXBDaGFydCwgb3IgZ2FudHRDaGFydC4nXHJcbiAgICB9LFxyXG4gICAgZGVmYXVsdEhlaWdodDoge1xyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0RFRkFVTFRfSEVJR0hUJyxcclxuICAgICAgdmFsdWU6IDQwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICd0aGUgZGVmYXVsdCBoZWlnaHQgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LiBVc2VkIHdoZW4gbm8gdmFsdWUgaXMgc2V0LidcclxuICAgIH0sXHJcbiAgICBkZWZhdWx0V2lkdGg6IHtcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9ERUZBVUxUX1dJRFRIJyxcclxuICAgICAgdmFsdWU6IDYwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZGVmYXVsdCB3aWR0aCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQuIFVzZWQgd2hlbiBubyB2YWx1ZSBpcyBzZXQuJ1xyXG4gICAgfSxcclxuICAgIGRlZmF1bHRTY2FsZToge1xyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0RFRkFVTFRfU0NBTEUnLFxyXG4gICAgICB2YWx1ZTogMSxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZGVmYXVsdCBzY2FsZSBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQuIFVzZWQgd2hlbiBubyB2YWx1ZSBpcyBzZXQuJ1xyXG4gICAgfSxcclxuICAgIGhlaWdodDoge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGhlaWdodCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQsIG92ZXJyaWRpbmcgdGhlIG9wdGlvbiBpbiB0aGUgY2hhcnQgc2V0dGluZ3MuJ1xyXG4gICAgfSxcclxuICAgIHdpZHRoOiB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgd2lkdGggb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LCBvdmVycmlkaW5nIHRoZSBvcHRpb24gaW4gdGhlIGNoYXJ0IHNldHRpbmdzLidcclxuICAgIH0sXHJcbiAgICBzY2FsZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIHNjYWxlIG9mIHRoZSBleHBvcnRlZCBjaGFydCwgb3ZlcnJpZGluZyB0aGUgb3B0aW9uIGluIHRoZSBjaGFydCBzZXR0aW5ncy4gUmFuZ2VzIGJldHdlZW4gMC4xIGFuZCA1LjAuJ1xyXG4gICAgfSxcclxuICAgIGdsb2JhbE9wdGlvbnM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0VpdGhlciBhIHN0cmluZ2lmaWVkIEpTT04gb3IgYSBmaWxlbmFtZSBjb250YWluaW5nIG9wdGlvbnMgdG8gYmUgcGFzc2VkIGludG8gdGhlIEhpZ2hjaGFydHMuc2V0T3B0aW9ucy4nXHJcbiAgICB9LFxyXG4gICAgdGhlbWVPcHRpb25zOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdFaXRoZXIgYSBzdHJpbmdpZmllZCBKU09OIG9yIGEgZmlsZW5hbWUgY29udGFpbmluZyB0aGVtZSBvcHRpb25zIHRvIGJlIHBhc3NlZCBpbnRvIHRoZSBIaWdoY2hhcnRzLnNldE9wdGlvbnMuJ1xyXG4gICAgfSxcclxuICAgIGJhdGNoOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbml0aWF0ZXMgYSBiYXRjaCBqb2Igd2l0aCBhIHN0cmluZyBjb250YWluaW5nIGlucHV0L291dHB1dCBwYWlyczogXCJpbj1vdXQ7aW49b3V0Oy4uLlwiLidcclxuICAgIH0sXHJcbiAgICByYXN0ZXJpemF0aW9uVGltZW91dDoge1xyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX1JBU1RFUklaQVRJT05fVElNRU9VVCcsXHJcbiAgICAgIHZhbHVlOiAxNTAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiBpbiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgcmVuZGVyaW5nIGEgd2VicGFnZS4nXHJcbiAgICB9XHJcbiAgfSxcclxuICBjdXN0b21Mb2dpYzoge1xyXG4gICAgYWxsb3dDb2RlRXhlY3V0aW9uOiB7XHJcbiAgICAgIGVudkxpbms6ICdDVVNUT01fTE9HSUNfQUxMT1dfQ09ERV9FWEVDVVRJT04nLFxyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0NvbnRyb2xzIHdoZXRoZXIgdGhlIGV4ZWN1dGlvbiBvZiBhcmJpdHJhcnkgY29kZSBpcyBhbGxvd2VkIGR1cmluZyB0aGUgZXhwb3J0aW5nIHByb2Nlc3MuJ1xyXG4gICAgfSxcclxuICAgIGFsbG93RmlsZVJlc291cmNlczoge1xyXG4gICAgICBlbnZMaW5rOiAnQ1VTVE9NX0xPR0lDX0FMTE9XX0ZJTEVfUkVTT1VSQ0VTJyxcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdDb250cm9scyB0aGUgYWJpbGl0eSB0byBpbmplY3QgcmVzb3VyY2VzIGZyb20gdGhlIGZpbGVzeXN0ZW0uIFRoaXMgc2V0dGluZyBoYXMgbm8gZWZmZWN0IHdoZW4gcnVubmluZyBhcyBhIHNlcnZlci4nXHJcbiAgICB9LFxyXG4gICAgY3VzdG9tQ29kZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQ3VzdG9tIGNvZGUgdG8gZXhlY3V0ZSBiZWZvcmUgY2hhcnQgaW5pdGlhbGl6YXRpb24uIEl0IGNhbiBiZSBhIGZ1bmN0aW9uLCBjb2RlIHdyYXBwZWQgd2l0aGluIGEgZnVuY3Rpb24sIG9yIGEgZmlsZW5hbWUgd2l0aCB0aGUgLmpzIGV4dGVuc2lvbi4nXHJcbiAgICB9LFxyXG4gICAgY2FsbGJhY2s6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0phdmFTY3JpcHQgY29kZSB0byBydW4gZHVyaW5nIGNvbnN0cnVjdGlvbi4gSXQgY2FuIGJlIGEgZnVuY3Rpb24gb3IgYSBmaWxlbmFtZSB3aXRoIHRoZSAuanMgZXh0ZW5zaW9uLidcclxuICAgIH0sXHJcbiAgICByZXNvdXJjZXM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0FkZGl0aW9uYWwgcmVzb3VyY2UgaW4gdGhlIGZvcm0gb2YgYSBzdHJpbmdpZmllZCBKU09OLCB3aGljaCBtYXkgY29udGFpbiBmaWxlcywganMsIGFuZCBjc3Mgc2VjdGlvbnMuJ1xyXG4gICAgfSxcclxuICAgIGxvYWRDb25maWc6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgbGVnYWN5TmFtZTogJ2Zyb21GaWxlJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdBIGZpbGUgY29udGFpbmluZyBhIHByZS1kZWZpbmVkIGNvbmZpZ3VyYXRpb24gdG8gdXNlLidcclxuICAgIH0sXHJcbiAgICBjcmVhdGVDb25maWc6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0VuYWJsZXMgc2V0dGluZyBvcHRpb25zIHRocm91Z2ggYSBwcm9tcHQgYW5kIHNhdmluZyB0aGVtIGluIGEgcHJvdmlkZWQgY29uZmlnIGZpbGUuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgc2VydmVyOiB7XHJcbiAgICBlbmFibGU6IHtcclxuICAgICAgZW52TGluazogJ1NFUlZFUl9FTkFCTEUnLFxyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgY2xpTmFtZTogJ2VuYWJsZVNlcnZlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdXaGVuIHNldCB0byB0cnVlLCB0aGUgc2VydmVyIHN0YXJ0cyBvbiB0aGUgbG9jYWwgSVAgYWRkcmVzcyAwLjAuMC4wLidcclxuICAgIH0sXHJcbiAgICBob3N0OiB7XHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfSE9TVCcsXHJcbiAgICAgIHZhbHVlOiAnMC4wLjAuMCcsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGhvc3RuYW1lIG9mIHRoZSBzZXJ2ZXIuIEFkZGl0aW9uYWxseSwgaXQgc3RhcnRzIGEgc2VydmVyIG9uIHRoZSBwcm92aWRlZCBob3N0bmFtZS4nXHJcbiAgICB9LFxyXG4gICAgcG9ydDoge1xyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX1BPUlQnLFxyXG4gICAgICB2YWx1ZTogNzgwMSxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHNlcnZlciBwb3J0IHdoZW4gZW5hYmxlZC4nXHJcbiAgICB9LFxyXG4gICAgYmVuY2htYXJraW5nOiB7XHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfQkVOQ0hNQVJLSU5HJyxcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGNsaU5hbWU6ICdzZXJ2ZXJCZW5jaG1hcmtpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSW5kaWNhdGVzIHdoZXRoZXIgdG8gZGlzcGxheSB0aGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgb2Ygc3BlY2lmaWMgYWN0aW9ucyB0aGF0IG9jY3VyIG9uIHRoZSBzZXJ2ZXIgd2hpbGUgc2VydmluZyBhIHJlcXVlc3QuJ1xyXG4gICAgfSxcclxuICAgIHNzbDoge1xyXG4gICAgICBlbmFibGU6IHtcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9FTkFCTEUnLFxyXG4gICAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgICAgY2xpTmFtZTogJ2VuYWJsZVNzbCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIG9yIGRpc2FibGVzIHRoZSBTU0wgcHJvdG9jb2wuJ1xyXG4gICAgICB9LFxyXG4gICAgICBmb3JjZToge1xyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfU1NMX0ZPUkNFJyxcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICAgIGNsaU5hbWU6ICdzc2xGb3JjZWQnLFxyXG4gICAgICAgIGxlZ2FjeU5hbWU6ICdzc2xPbmx5JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAgICdXaGVuIHNldCB0byB0cnVlLCB0aGUgc2VydmVyIGlzIGZvcmNlZCB0byBzZXJ2ZSBvbmx5IG92ZXIgSFRUUFMuJ1xyXG4gICAgICB9LFxyXG4gICAgICBwb3J0OiB7XHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfUE9SVCcsXHJcbiAgICAgICAgdmFsdWU6IDQ0MyxcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgICBjbGlOYW1lOiAnc3NsUG9ydCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgcG9ydCBvbiB3aGljaCB0byBydW4gdGhlIFNTTCBzZXJ2ZXIuJ1xyXG4gICAgICB9LFxyXG4gICAgICBjZXJ0UGF0aDoge1xyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfU1NMX0NFUlRfUEFUSCcsXHJcbiAgICAgICAgdmFsdWU6ICcnLFxyXG4gICAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICAgIGxlZ2FjeU5hbWU6ICdzc2xQYXRoJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSBwYXRoIHRvIHRoZSBTU0wgY2VydGlmaWNhdGUva2V5IGZpbGUuJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgcmF0ZUxpbWl0aW5nOiB7XHJcbiAgICAgIGVuYWJsZToge1xyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19FTkFCTEUnLFxyXG4gICAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgICAgY2xpTmFtZTogJ2VuYWJsZVJhdGVMaW1pdGluZycsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIHJhdGUgbGltaXRpbmcgZm9yIHRoZSBzZXJ2ZXIuJ1xyXG4gICAgICB9LFxyXG4gICAgICBtYXhSZXF1ZXN0czoge1xyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19NQVhfUkVRVUVTVFMnLFxyXG4gICAgICAgIHZhbHVlOiAxMCxcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgICBsZWdhY3lOYW1lOiAncmF0ZUxpbWl0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSBtYXhpbXVtIG51bWJlciBvZiByZXF1ZXN0cyBhbGxvd2VkIGluIG9uZSBtaW51dGUuJ1xyXG4gICAgICB9LFxyXG4gICAgICB3aW5kb3c6IHtcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfV0lORE9XJyxcclxuICAgICAgICB2YWx1ZTogMSxcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSB0aW1lIHdpbmRvdywgaW4gbWludXRlcywgZm9yIHRoZSByYXRlIGxpbWl0aW5nLidcclxuICAgICAgfSxcclxuICAgICAgZGVsYXk6IHtcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfREVMQVknLFxyXG4gICAgICAgIHZhbHVlOiAwLFxyXG4gICAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICAgJ1RoZSBkZWxheSBkdXJhdGlvbiBmb3IgZWFjaCBzdWNjZXNzaXZlIHJlcXVlc3QgYmVmb3JlIHJlYWNoaW5nIHRoZSBtYXhpbXVtIGxpbWl0LidcclxuICAgICAgfSxcclxuICAgICAgdHJ1c3RQcm94eToge1xyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19UUlVTVF9QUk9YWScsXHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1NldCB0aGlzIHRvIHRydWUgaWYgdGhlIHNlcnZlciBpcyBiZWhpbmQgYSBsb2FkIGJhbGFuY2VyLidcclxuICAgICAgfSxcclxuICAgICAgc2tpcEtleToge1xyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX0tFWScsXHJcbiAgICAgICAgdmFsdWU6ICcnLFxyXG4gICAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICAgJ0FsbG93cyBieXBhc3NpbmcgdGhlIHJhdGUgbGltaXRlciBhbmQgc2hvdWxkIGJlIHByb3ZpZGVkIHdpdGggdGhlIHNraXBUb2tlbiBhcmd1bWVudC4nXHJcbiAgICAgIH0sXHJcbiAgICAgIHNraXBUb2tlbjoge1xyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX1RPS0VOJyxcclxuICAgICAgICB2YWx1ZTogJycsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgICAnQWxsb3dzIGJ5cGFzc2luZyB0aGUgcmF0ZSBsaW1pdGVyIGFuZCBzaG91bGQgYmUgcHJvdmlkZWQgd2l0aCB0aGUgc2tpcEtleSBhcmd1bWVudC4nXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIHBvb2w6IHtcclxuICAgIG1pbldvcmtlcnM6IHtcclxuICAgICAgZW52TGluazogJ1BPT0xfTUlOX1dPUktFUlMnLFxyXG4gICAgICB2YWx1ZTogNCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIG51bWJlciBvZiBtaW5pbXVtIGFuZCBpbml0aWFsIHBvb2wgd29ya2VycyB0byBzcGF3bi4nXHJcbiAgICB9LFxyXG4gICAgbWF4V29ya2Vyczoge1xyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9NQVhfV09SS0VSUycsXHJcbiAgICAgIHZhbHVlOiA4LFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbGVnYWN5TmFtZTogJ3dvcmtlcnMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBudW1iZXIgb2YgbWF4aW11bSBwb29sIHdvcmtlcnMgdG8gc3Bhd24uJ1xyXG4gICAgfSxcclxuICAgIHdvcmtMaW1pdDoge1xyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9XT1JLX0xJTUlUJyxcclxuICAgICAgdmFsdWU6IDQwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBudW1iZXIgb2Ygd29yayBwaWVjZXMgdGhhdCBjYW4gYmUgcGVyZm9ybWVkIGJlZm9yZSByZXN0YXJ0aW5nIHRoZSB3b3JrZXIgcHJvY2Vzcy4nXHJcbiAgICB9LFxyXG4gICAgYWNxdWlyZVRpbWVvdXQ6IHtcclxuICAgICAgZW52TGluazogJ1BPT0xfQUNRVUlSRV9USU1FT1VUJyxcclxuICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGR1cmF0aW9uLCBpbiBtaWxsaXNlY29uZHMsIHRvIHdhaXQgZm9yIGFjcXVpcmluZyBhIHJlc291cmNlLidcclxuICAgIH0sXHJcbiAgICBjcmVhdGVUaW1lb3V0OiB7XHJcbiAgICAgIGVudkxpbms6ICdQT09MX0NSRUFURV9USU1FT1VUJyxcclxuICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGR1cmF0aW9uLCBpbiBtaWxsaXNlY29uZHMsIHRvIHdhaXQgZm9yIGNyZWF0aW5nIGEgcmVzb3VyY2UuJ1xyXG4gICAgfSxcclxuICAgIGRlc3Ryb3lUaW1lb3V0OiB7XHJcbiAgICAgIGVudkxpbms6ICdQT09MX0RFU1RST1lfVElNRU9VVCcsXHJcbiAgICAgIHZhbHVlOiA1MDAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCB0byB3YWl0IGZvciBkZXN0cm95aW5nIGEgcmVzb3VyY2UuJ1xyXG4gICAgfSxcclxuICAgIGlkbGVUaW1lb3V0OiB7XHJcbiAgICAgIGVudkxpbms6ICdQT09MX0lETEVfVElNRU9VVCcsXHJcbiAgICAgIHZhbHVlOiAzMDAwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgYWZ0ZXIgd2hpY2ggYW4gaWRsZSByZXNvdXJjZSBpcyBkZXN0cm95ZWQuJ1xyXG4gICAgfSxcclxuICAgIGNyZWF0ZVJldHJ5SW50ZXJ2YWw6IHtcclxuICAgICAgZW52TGluazogJ1BPT0xfQ1JFQVRFX1JFVFJZX0lOVEVSVkFMJyxcclxuICAgICAgdmFsdWU6IDIwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgdG8gd2FpdCBiZWZvcmUgcmV0cnlpbmcgdGhlIGNyZWF0ZSBwcm9jZXNzIGluIGNhc2Ugb2YgYSBmYWlsdXJlLidcclxuICAgIH0sXHJcbiAgICByZWFwZXJJbnRlcnZhbDoge1xyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9SRUFQRVJfSU5URVJWQUwnLFxyXG4gICAgICB2YWx1ZTogMTAwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgYWZ0ZXIgd2hpY2ggdGhlIGNoZWNrIGZvciBpZGxlIHJlc291cmNlcyB0byBkZXN0cm95IGlzIHRyaWdnZXJlZC4nXHJcbiAgICB9LFxyXG4gICAgYmVuY2htYXJraW5nOiB7XHJcbiAgICAgIGVudkxpbms6ICdQT09MX0JFTkNITUFSS0lORycsXHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBjbGlOYW1lOiAncG9vbEJlbmNobWFya2luZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbmRpY2F0ZSB3aGV0aGVyIHRvIHNob3cgc3RhdGlzdGljcyBmb3IgdGhlIHBvb2wgb2YgcmVzb3VyY2VzIG9yIG5vdC4nXHJcbiAgICB9LFxyXG4gICAgbGlzdGVuVG9Qcm9jZXNzRXhpdHM6IHtcclxuICAgICAgZW52TGluazogJ1BPT0xfTElTVEVOX1RPX1BST0NFU1NfRVhJVFMnLFxyXG4gICAgICB2YWx1ZTogdHJ1ZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0RlY2lkZXMgd2hldGhlciBvciBub3QgdG8gYXR0YWNoIHByb2Nlc3MuZXhpdCBoYW5kbGVycy4nXHJcbiAgICB9XHJcbiAgfSxcclxuICBsb2dnaW5nOiB7XHJcbiAgICBsZXZlbDoge1xyXG4gICAgICBlbnZMaW5rOiAnTE9HR0lOR19MRVZFTCcsXHJcbiAgICAgIHZhbHVlOiA0LFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgY2xpTmFtZTogJ2xvZ0xldmVsJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgbG9nZ2luZyBsZXZlbCB0byBiZSB1c2VkLidcclxuICAgIH0sXHJcbiAgICBmaWxlOiB7XHJcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX0ZJTEUnLFxyXG4gICAgICB2YWx1ZTogJ2hpZ2hjaGFydHMtZXhwb3J0LXNlcnZlci5sb2cnLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgY2xpTmFtZTogJ2xvZ0ZpbGUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIG5hbWUgb2YgYSBsb2cgZmlsZS4gVGhlIGxvZ0Rlc3Qgb3B0aW9uIGFsc28gbmVlZHMgdG8gYmUgc2V0IHRvIGVuYWJsZSBmaWxlIGxvZ2dpbmcuJ1xyXG4gICAgfSxcclxuICAgIGRlc3Q6IHtcclxuICAgICAgZW52TGluazogJ0xPR0dJTkdfREVTVCcsXHJcbiAgICAgIHZhbHVlOiAnbG9nLycsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBjbGlOYW1lOiAnbG9nRGVzdCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgcGF0aCB0byBzdG9yZSBsb2cgZmlsZXMuIFRoaXMgYWxzbyBlbmFibGVzIGZpbGUgbG9nZ2luZy4nXHJcbiAgICB9XHJcbiAgfSxcclxuICB1aToge1xyXG4gICAgZW5hYmxlOiB7XHJcbiAgICAgIGVudkxpbms6ICdVSV9FTkFCTEUnLFxyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgY2xpTmFtZTogJ2VuYWJsZVVpJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0VuYWJsZXMgb3IgZGlzYWJsZXMgdGhlIHVzZXIgaW50ZXJmYWNlIChVSSkgZm9yIHRoZSBleHBvcnQgc2VydmVyLidcclxuICAgIH0sXHJcbiAgICByb3V0ZToge1xyXG4gICAgICBlbnZMaW5rOiAnVUlfUk9VVEUnLFxyXG4gICAgICB2YWx1ZTogJy8nLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgY2xpTmFtZTogJ3VpUm91dGUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGVuZHBvaW50IHJvdXRlIHRvIHdoaWNoIHRoZSB1c2VyIGludGVyZmFjZSAoVUkpIHNob3VsZCBiZSBhdHRhY2hlZC4nXHJcbiAgICB9XHJcbiAgfSxcclxuICBvdGhlcjoge1xyXG4gICAgbm9Mb2dvOiB7XHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9OT19MT0dPJyxcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdTa2lwIHByaW50aW5nIHRoZSBsb2dvIG9uIGEgc3RhcnR1cC4gV2lsbCBiZSByZXBsYWNlZCBieSBhIHNpbXBsZSB0ZXh0LidcclxuICAgIH1cclxuICB9XHJcbn07XHJcblxyXG4vLyBUaGUgY29uZmlnIGRlc2NyaXB0aW9ucyBvYmplY3QgZm9yIHRoZSBwcm9tcHRzIGZ1bmN0aW9uYWxpdHkuIEl0IGNvbnRhaW5zXHJcbi8vIGluZm9ybWF0aW9uIGxpa2U6XHJcbi8vICogVHlwZSBvZiBhIHByb21wdFxyXG4vLyAqIE5hbWUgb2YgYW4gb3B0aW9uXHJcbi8vICogU2hvcnQgZGVzY3JpcHRpb24gb2YgYSBjaG9zZW4gb3B0aW9uXHJcbi8vICogSW5pdGlhbCB2YWx1ZVxyXG5leHBvcnQgY29uc3QgcHJvbXB0c0NvbmZpZyA9IHtcclxuICBwdXBwZXRlZXI6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ2xpc3QnLFxyXG4gICAgICBuYW1lOiAnYXJncycsXHJcbiAgICAgIG1lc3NhZ2U6ICdQdXBwZXRlZXIgYXJndW1lbnRzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wdXBwZXRlZXIuYXJncy52YWx1ZS5qb2luKCcsJyksXHJcbiAgICAgIHNlcGFyYXRvcjogJywnXHJcbiAgICB9XHJcbiAgXSxcclxuICBoaWdoY2hhcnRzOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ3ZlcnNpb24nLFxyXG4gICAgICBtZXNzYWdlOiAnSGlnaGNoYXJ0cyB2ZXJzaW9uJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLnZlcnNpb24udmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ2NkblVSTCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgVVJMIG9mIENETicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5jZG5VUkwudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdtdWx0aXNlbGVjdCcsXHJcbiAgICAgIG5hbWU6ICdtb2R1bGVzJyxcclxuICAgICAgbWVzc2FnZTogJ0F2YWlsYWJsZSBtb2R1bGVzJyxcclxuICAgICAgaW5zdHJ1Y3Rpb25zOiAnU3BhY2U6IFNlbGVjdCBzcGVjaWZpYywgQTogU2VsZWN0IGFsbCwgRW50ZXI6IENvbmZpcm0uJyxcclxuICAgICAgY2hvaWNlczogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLm1vZHVsZXMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdsaXN0JyxcclxuICAgICAgbmFtZTogJ3NjcmlwdHMnLFxyXG4gICAgICBtZXNzYWdlOiAnQ3VzdG9tIHNjcmlwdHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuc2NyaXB0cy52YWx1ZS5qb2luKCcsJyksXHJcbiAgICAgIHNlcGFyYXRvcjogJywnXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2ZvcmNlRmV0Y2gnLFxyXG4gICAgICBtZXNzYWdlOiAnRm9yY2UgcmUtZmV0Y2ggdGhlIHNjcmlwdHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuZm9yY2VGZXRjaC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnY2FjaGVQYXRoJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBwYXRoIHRvIHRoZSBjYWNoZSBkaXJlY3RvcnknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuY2FjaGVQYXRoLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBleHBvcnQ6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3NlbGVjdCcsXHJcbiAgICAgIG5hbWU6ICd0eXBlJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBkZWZhdWx0IGV4cG9ydCBmaWxlIHR5cGUnLFxyXG4gICAgICBoaW50OiBgRGVmYXVsdDogJHtkZWZhdWx0Q29uZmlnLmV4cG9ydC50eXBlLnZhbHVlfWAsXHJcbiAgICAgIGluaXRpYWw6IDAsXHJcbiAgICAgIGNob2ljZXM6IFsncG5nJywgJ2pwZWcnLCAncGRmJywgJ3N2ZyddXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnc2VsZWN0JyxcclxuICAgICAgbmFtZTogJ2NvbnN0cicsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgZGVmYXVsdCBjb25zdHJ1Y3RvciBmb3IgSGlnaGNoYXJ0cycsXHJcbiAgICAgIGhpbnQ6IGBEZWZhdWx0OiAke2RlZmF1bHRDb25maWcuZXhwb3J0LmNvbnN0ci52YWx1ZX1gLFxyXG4gICAgICBpbml0aWFsOiAwLFxyXG4gICAgICBjaG9pY2VzOiBbJ2NoYXJ0JywgJ3N0b2NrQ2hhcnQnLCAnbWFwQ2hhcnQnLCAnZ2FudHRDaGFydCddXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2RlZmF1bHRIZWlnaHQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgZmFsbGJhY2sgaGVpZ2h0IG9mIHRoZSBleHBvcnRlZCBjaGFydCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LmRlZmF1bHRIZWlnaHQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnZGVmYXVsdFdpZHRoJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBkZWZhdWx0IGZhbGxiYWNrIHdpZHRoIG9mIHRoZSBleHBvcnRlZCBjaGFydCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LmRlZmF1bHRXaWR0aC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdkZWZhdWx0U2NhbGUnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgZmFsbGJhY2sgc2NhbGUgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5leHBvcnQuZGVmYXVsdFNjYWxlLnZhbHVlLFxyXG4gICAgICBtaW46IDAuMSxcclxuICAgICAgbWF4OiA1XHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3Jhc3Rlcml6YXRpb25UaW1lb3V0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSByZW5kZXJpbmcgd2VicGFnZSB0aW1lb3V0IGluIG1pbGxpc2Vjb25kcycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LnJhc3Rlcml6YXRpb25UaW1lb3V0LnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBjdXN0b21Mb2dpYzogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2FsbG93Q29kZUV4ZWN1dGlvbicsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgZXhlY3V0aW9uIG9mIGN1c3RvbSBjb2RlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5jdXN0b21Mb2dpYy5hbGxvd0NvZGVFeGVjdXRpb24udmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnYWxsb3dGaWxlUmVzb3VyY2VzJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBmaWxlIHJlc291cmNlcycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuY3VzdG9tTG9naWMuYWxsb3dGaWxlUmVzb3VyY2VzLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBzZXJ2ZXI6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdlbmFibGUnLFxyXG4gICAgICBtZXNzYWdlOiAnU3RhcnRzIHRoZSBzZXJ2ZXIgb24gMC4wLjAuMCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLmVuYWJsZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnaG9zdCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdTZXJ2ZXIgaG9zdG5hbWUnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5ob3N0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3BvcnQnLFxyXG4gICAgICBtZXNzYWdlOiAnU2VydmVyIHBvcnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5wb3J0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2JlbmNobWFya2luZycsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgc2VydmVyIGJlbmNobWFya2luZycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLmJlbmNobWFya2luZy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdzc2wuZW5hYmxlJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBTU0wgcHJvdG9jb2wnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wuZW5hYmxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ3NzbC5mb3JjZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdGb3JjZSBzZXJ2aW5nIG9ubHkgb3ZlciBIVFRQUycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnNzbC5mb3JjZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdzc2wucG9ydCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdTU0wgc2VydmVyIHBvcnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wucG9ydC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnc3NsLmNlcnRQYXRoJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBwYXRoIHRvIGZpbmQgdGhlIFNTTCBjZXJ0aWZpY2F0ZS9rZXknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wuY2VydFBhdGgudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLmVuYWJsZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgcmF0ZSBsaW1pdGluZycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy5lbmFibGUudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLm1heFJlcXVlc3RzJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBtYXhpbXVtIHJlcXVlc3RzIGFsbG93ZWQgcGVyIG1pbnV0ZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy5tYXhSZXF1ZXN0cy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcud2luZG93JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSByYXRlLWxpbWl0aW5nIHRpbWUgd2luZG93IGluIG1pbnV0ZXMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcud2luZG93LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5kZWxheScsXHJcbiAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgJ1RoZSBkZWxheSBmb3IgZWFjaCBzdWNjZXNzaXZlIHJlcXVlc3QgYmVmb3JlIHJlYWNoaW5nIHRoZSBtYXhpbXVtJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLmRlbGF5LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy50cnVzdFByb3h5JyxcclxuICAgICAgbWVzc2FnZTogJ1NldCB0byB0cnVlIGlmIGJlaGluZCBhIGxvYWQgYmFsYW5jZXInLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcudHJ1c3RQcm94eS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLnNraXBLZXknLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdBbGxvd3MgYnlwYXNzaW5nIHRoZSByYXRlIGxpbWl0ZXIgd2hlbiBwcm92aWRlZCB3aXRoIHRoZSBza2lwVG9rZW4gYXJndW1lbnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcuc2tpcEtleS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLnNraXBUb2tlbicsXHJcbiAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgJ0FsbG93cyBieXBhc3NpbmcgdGhlIHJhdGUgbGltaXRlciB3aGVuIHByb3ZpZGVkIHdpdGggdGhlIHNraXBLZXkgYXJndW1lbnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcuc2tpcFRva2VuLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBwb29sOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnbWluV29ya2VycycsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgaW5pdGlhbCBudW1iZXIgb2Ygd29ya2VycyB0byBzcGF3bicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5taW5Xb3JrZXJzLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ21heFdvcmtlcnMnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIG1heGltdW0gbnVtYmVyIG9mIHdvcmtlcnMgdG8gc3Bhd24nLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wubWF4V29ya2Vycy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICd3b3JrTGltaXQnLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdUaGUgcGllY2VzIG9mIHdvcmsgdGhhdCBjYW4gYmUgcGVyZm9ybWVkIGJlZm9yZSByZXN0YXJ0aW5nIGEgUHVwcGV0ZWVyIHByb2Nlc3MnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wud29ya0xpbWl0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2FjcXVpcmVUaW1lb3V0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIHRvIHdhaXQgZm9yIGFjcXVpcmluZyBhIHJlc291cmNlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmFjcXVpcmVUaW1lb3V0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2NyZWF0ZVRpbWVvdXQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgY3JlYXRpbmcgYSByZXNvdXJjZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5jcmVhdGVUaW1lb3V0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2Rlc3Ryb3lUaW1lb3V0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIHRvIHdhaXQgZm9yIGRlc3Ryb3lpbmcgYSByZXNvdXJjZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5kZXN0cm95VGltZW91dC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdpZGxlVGltZW91dCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcyBhZnRlciBhbiBpZGxlIHJlc291cmNlIGlzIGRlc3Ryb3llZCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5pZGxlVGltZW91dC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdjcmVhdGVSZXRyeUludGVydmFsJyxcclxuICAgICAgbWVzc2FnZTpcclxuICAgICAgICAnVGhlIHJldHJ5IGludGVydmFsIGluIG1pbGxpc2Vjb25kcyBhZnRlciBhIGNyZWF0ZSBwcm9jZXNzIGZhaWxzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmNyZWF0ZVJldHJ5SW50ZXJ2YWwudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncmVhcGVySW50ZXJ2YWwnLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdUaGUgcmVhcGVyIGludGVydmFsIGluIG1pbGxpc2Vjb25kcyBhZnRlciB0cmlnZ2VyaW5nIHRoZSBjaGVjayBmb3IgaWRsZSByZXNvdXJjZXMgdG8gZGVzdHJveScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5yZWFwZXJJbnRlcnZhbC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdiZW5jaG1hcmtpbmcnLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIGJlbmNobWFya2luZyBmb3IgYSByZXNvdXJjZSBwb29sJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmJlbmNobWFya2luZy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdsaXN0ZW5Ub1Byb2Nlc3NFeGl0cycsXHJcbiAgICAgIG1lc3NhZ2U6ICdTZXQgdG8gZmFsc2UgdG8gc2tpcCBhdHRhY2hpbmcgcHJvY2Vzcy5leGl0IGhhbmRsZXJzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmxpc3RlblRvUHJvY2Vzc0V4aXRzLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBsb2dnaW5nOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnbGV2ZWwnLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdUaGUgbG9nIGxldmVsICgwOiBzaWxlbnQsIDE6IGVycm9yLCAyOiB3YXJuaW5nLCAzOiBub3RpY2UsIDQ6IHZlcmJvc2UsIDU6IGJlbmNobWFyayknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmxvZ2dpbmcubGV2ZWwudmFsdWUsXHJcbiAgICAgIHJvdW5kOiAwLFxyXG4gICAgICBtaW46IDAsXHJcbiAgICAgIG1heDogNVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnZmlsZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdBIGxvZyBmaWxlIG5hbWUuIFNldCB3aXRoIHRoZSAtLWxvZ0Rlc3QgdG8gZW5hYmxlIGZpbGUgbG9nZ2luZycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcubG9nZ2luZy5maWxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdkZXN0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBwYXRoIHRvIGxvZyBmaWxlcy4gRW5hYmxlcyBmaWxlIGxvZ2dpbmcnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmxvZ2dpbmcuZGVzdC52YWx1ZVxyXG4gICAgfVxyXG4gIF0sXHJcbiAgdWk6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdlbmFibGUnLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIFVJIGZvciB0aGUgZXhwb3J0IHNlcnZlcicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcudWkuZW5hYmxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdyb3V0ZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdBIHJvdXRlIHRvIGF0dGFjaCB0aGUgVUknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnVpLnJvdXRlLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBvdGhlcjogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ25vTG9nbycsXHJcbiAgICAgIG1lc3NhZ2U6ICdTa2lwIHByaW50aW5nIHRoZSBsb2dvIG9uIHN0YXJ0dXAuIFJlcGxhY2VkIGJ5IHNpbXBsZSB0ZXh0JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5vdGhlci5ub0xvZ28udmFsdWVcclxuICAgIH1cclxuICBdXHJcbn07XHJcblxyXG4vLyBBYnNvbHV0ZSBwcm9wcyB0aGF0LCBpbiBjYXNlIG9mIG1lcmdpbmcgcmVjdXJzaXZlbHksIG5lZWQgdG8gYmUgZm9yY2UgbWVyZ2VkXHJcbmV4cG9ydCBjb25zdCBhYnNvbHV0ZVByb3BzID0gW1xyXG4gICdvcHRpb25zJyxcclxuICAnZ2xvYmFsT3B0aW9ucycsXHJcbiAgJ3RoZW1lT3B0aW9ucycsXHJcbiAgJ3Jlc291cmNlcycsXHJcbiAgJ3BheWxvYWQnXHJcbl07XHJcblxyXG4vLyBBcmd1bWVudCBuZXN0aW5nIGxldmVsIG9mIGFsbCBleHBvcnQgc2VydmVyIG9wdGlvbnNcclxuZXhwb3J0IGNvbnN0IG5lc3RlZEFyZ3MgPSB7fTtcclxuXHJcbi8qKlxyXG4gKiBSZWN1cnNpdmVseSBjcmVhdGVzIGEgY2hhaW4gb2YgbmVzdGVkIGFyZ3VtZW50cyBmcm9tIGFuIG9iamVjdC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9iaiAtIFRoZSBvYmplY3QgY29udGFpbmluZyBuZXN0ZWQgYXJndW1lbnRzLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcHJvcENoYWluIC0gVGhlIGN1cnJlbnQgY2hhaW4gb2YgbmVzdGVkIHByb3BlcnRpZXNcclxuICogKHVzZWQgaW50ZXJuYWxseSBkdXJpbmcgcmVjdXJzaW9uKS5cclxuICovXHJcbmNvbnN0IGNyZWF0ZU5lc3RlZEFyZ3MgPSAob2JqLCBwcm9wQ2hhaW4gPSAnJykgPT4ge1xyXG4gIE9iamVjdC5rZXlzKG9iaikuZm9yRWFjaCgoaykgPT4ge1xyXG4gICAgaWYgKCFbJ3B1cHBldGVlcicsICdoaWdoY2hhcnRzJ10uaW5jbHVkZXMoaykpIHtcclxuICAgICAgY29uc3QgZW50cnkgPSBvYmpba107XHJcbiAgICAgIGlmICh0eXBlb2YgZW50cnkudmFsdWUgPT09ICd1bmRlZmluZWQnKSB7XHJcbiAgICAgICAgLy8gR28gZGVlcGVyIGluIHRoZSBuZXN0ZWQgYXJndW1lbnRzXHJcbiAgICAgICAgY3JlYXRlTmVzdGVkQXJncyhlbnRyeSwgYCR7cHJvcENoYWlufS4ke2t9YCk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgLy8gQ3JlYXRlIHRoZSBjaGFpbiBvZiBuZXN0ZWQgYXJndW1lbnRzXHJcbiAgICAgICAgbmVzdGVkQXJnc1tlbnRyeS5jbGlOYW1lIHx8IGtdID0gYCR7cHJvcENoYWlufS4ke2t9YC5zdWJzdHJpbmcoMSk7XHJcblxyXG4gICAgICAgIC8vIFN1cHBvcnQgZm9yIHRoZSBsZWdhY3ksIFBoYW50b21KUyBwcm9wZXJ0aWVzIG5hbWVzXHJcbiAgICAgICAgaWYgKGVudHJ5LmxlZ2FjeU5hbWUgIT09IHVuZGVmaW5lZCkge1xyXG4gICAgICAgICAgbmVzdGVkQXJnc1tlbnRyeS5sZWdhY3lOYW1lXSA9IGAke3Byb3BDaGFpbn0uJHtrfWAuc3Vic3RyaW5nKDEpO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0pO1xyXG59O1xyXG5cclxuY3JlYXRlTmVzdGVkQXJncyhkZWZhdWx0Q29uZmlnKTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyBhcHBlbmRGaWxlLCBleGlzdHNTeW5jLCBta2RpclN5bmMgfSBmcm9tICdmcyc7XHJcblxyXG5pbXBvcnQgeyBkZWZhdWx0Q29uZmlnIH0gZnJvbSAnLi9zY2hlbWFzL2NvbmZpZy5qcyc7XHJcblxyXG4vLyBUaGUgYXZhaWxhYmxlIGNvbG9yc1xyXG5jb25zdCBjb2xvcnMgPSBbJ3JlZCcsICd5ZWxsb3cnLCAnYmx1ZScsICdncmF5JywgJ2dyZWVuJ107XHJcblxyXG4vLyBUaGUgZGVmYXVsdCBsb2dnaW5nIGNvbmZpZ1xyXG5sZXQgbG9nZ2luZyA9IHtcclxuICAvLyBGbGFncyBmb3IgbG9nZ2luZyBzdGF0dXNcclxuICB0b0NvbnNvbGU6IHRydWUsXHJcbiAgdG9GaWxlOiBmYWxzZSxcclxuICBwYXRoQ3JlYXRlZDogZmFsc2UsXHJcbiAgLy8gTG9nIGxldmVsc1xyXG4gIGxldmVsc0Rlc2M6IFtcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICdlcnJvcicsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbMF1cclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHRpdGxlOiAnd2FybmluZycsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbMV1cclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHRpdGxlOiAnbm90aWNlJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1syXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICd2ZXJib3NlJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1szXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICdiZW5jaG1hcmsnLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzRdXHJcbiAgICB9XHJcbiAgXSxcclxuICAvLyBMb2cgbGlzdGVuZXJzXHJcbiAgbGlzdGVuZXJzOiBbXVxyXG59O1xyXG5cclxuLy8gR2F0aGVyIGluaXQgbG9nZ2luZyBvcHRpb25zXHJcbmZvciAoY29uc3QgW2tleSwgb3B0aW9uXSBvZiBPYmplY3QuZW50cmllcyhkZWZhdWx0Q29uZmlnLmxvZ2dpbmcpKSB7XHJcbiAgbG9nZ2luZ1trZXldID0gb3B0aW9uLnZhbHVlO1xyXG59XHJcblxyXG4vKipcclxuICogTG9ncyB0aGUgcHJvdmlkZWQgdGV4dHMgdG8gYSBmaWxlLCBpZiBmaWxlIGxvZ2dpbmcgaXMgZW5hYmxlZC4gSXQgY3JlYXRlc1xyXG4gKiB0aGUgbmVjZXNzYXJ5IGRpcmVjdG9yeSBzdHJ1Y3R1cmUgaWYgbm90IGFscmVhZHkgY3JlYXRlZCBhbmQgYXBwZW5kcyB0aGVcclxuICogY29udGVudCwgaW5jbHVkaW5nIGFuIG9wdGlvbmFsIHByZWZpeCwgdG8gdGhlIHNwZWNpZmllZCBsb2cgZmlsZS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmdbXX0gdGV4dHMgLSBBbiBhcnJheSBvZiB0ZXh0cyB0byBiZSBsb2dnZWQuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwcmVmaXggLSBBbiBvcHRpb25hbCBwcmVmaXggdG8gYmUgYWRkZWQgdG8gZWFjaCBsb2cgZW50cnkuXHJcbiAqL1xyXG5jb25zdCBsb2dUb0ZpbGUgPSAodGV4dHMsIHByZWZpeCkgPT4ge1xyXG4gIGlmIChsb2dnaW5nLnRvRmlsZSkge1xyXG4gICAgaWYgKCFsb2dnaW5nLnBhdGhDcmVhdGVkKSB7XHJcbiAgICAgIC8vIENyZWF0ZSBpZiBkb2VzIG5vdCBleGlzdFxyXG4gICAgICAhZXhpc3RzU3luYyhsb2dnaW5nLmRlc3QpICYmIG1rZGlyU3luYyhsb2dnaW5nLmRlc3QpO1xyXG5cclxuICAgICAgLy8gV2Ugbm93IGFzc3VtZSB0aGUgcGF0aCBpcyBhdmFpbGFibGUsIGUuZy4gaXQncyB0aGUgcmVzcG9uc2liaWxpdHlcclxuICAgICAgLy8gb2YgdGhlIHVzZXIgdG8gY3JlYXRlIHRoZSBwYXRoIHdpdGggdGhlIGNvcnJlY3QgYWNjZXNzIHJpZ2h0cy5cclxuICAgICAgbG9nZ2luZy5wYXRoQ3JlYXRlZCA9IHRydWU7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQWRkIHRoZSBjb250ZW50IHRvIGEgZmlsZVxyXG4gICAgYXBwZW5kRmlsZShcclxuICAgICAgYCR7bG9nZ2luZy5kZXN0fSR7bG9nZ2luZy5maWxlfWAsXHJcbiAgICAgIFtwcmVmaXhdLmNvbmNhdCh0ZXh0cykuam9pbignICcpICsgJ1xcbicsXHJcbiAgICAgIChlcnJvcikgPT4ge1xyXG4gICAgICAgIGlmIChlcnJvcikge1xyXG4gICAgICAgICAgY29uc29sZS5sb2coYFtsb2dnZXJdIFVuYWJsZSB0byB3cml0ZSB0byBsb2cgZmlsZTogJHtlcnJvcn1gKTtcclxuICAgICAgICAgIGxvZ2dpbmcudG9GaWxlID0gZmFsc2U7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICApO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBMb2dzIGEgbWVzc2FnZS4gQWNjZXB0cyBhIHZhcmlhYmxlIGFtb3VudCBvZiBhcmd1bWVudHMuIEFyZ3VtZW50cyBhZnRlclxyXG4gKiBgbGV2ZWxgIHdpbGwgYmUgcGFzc2VkIGRpcmVjdGx5IHRvIGNvbnNvbGUubG9nLCBhbmQvb3Igd2lsbCBiZSBqb2luZWRcclxuICogYW5kIGFwcGVuZGVkIHRvIHRoZSBsb2cgZmlsZS5cclxuICpcclxuICogQHBhcmFtIHthbnl9IGFyZ3MgLSBBbiBhcnJheSBvZiBhcmd1bWVudHMgd2hlcmUgdGhlIGZpcnN0IGlzIHRoZSBsb2cgbGV2ZWxcclxuICogYW5kIHRoZSByZXN0IGFyZSBzdHJpbmdzIHRvIGJ1aWxkIGEgbWVzc2FnZSB3aXRoLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGxvZyA9ICguLi5hcmdzKSA9PiB7XHJcbiAgY29uc3QgW25ld0xldmVsLCAuLi50ZXh0c10gPSBhcmdzO1xyXG5cclxuICAvLyBDdXJyZW50IGxvZ2dpbmcgb3B0aW9uc1xyXG4gIGNvbnN0IHsgbGV2ZWwsIGxldmVsc0Rlc2MgfSA9IGxvZ2dpbmc7XHJcblxyXG4gIC8vIENoZWNrIGlmIGxvZyBsZXZlbCBpcyB3aXRoaW4gYSBjb3JyZWN0IHJhbmdlIG9yIGlzIGEgYmVuY2htYXJrIGxvZ1xyXG4gIGlmIChcclxuICAgIG5ld0xldmVsICE9PSA1ICYmXHJcbiAgICAobmV3TGV2ZWwgPT09IDAgfHwgbmV3TGV2ZWwgPiBsZXZlbCB8fCBsZXZlbCA+IGxldmVsc0Rlc2MubGVuZ3RoKVxyXG4gICkge1xyXG4gICAgcmV0dXJuO1xyXG4gIH1cclxuXHJcbiAgLy8gR2V0IHJpZCBvZiB0aGUgR01UIHRleHQgaW5mb3JtYXRpb25cclxuICBjb25zdCBuZXdEYXRlID0gbmV3IERhdGUoKS50b1N0cmluZygpLnNwbGl0KCcoJylbMF0udHJpbSgpO1xyXG5cclxuICAvLyBDcmVhdGUgYSBtZXNzYWdlJ3MgcHJlZml4XHJcbiAgY29uc3QgcHJlZml4ID0gYCR7bmV3RGF0ZX0gWyR7bGV2ZWxzRGVzY1tuZXdMZXZlbCAtIDFdLnRpdGxlfV0gLWA7XHJcblxyXG4gIC8vIENhbGwgYXZhaWxhYmxlIGxvZyBsaXN0ZW5lcnNcclxuICBsb2dnaW5nLmxpc3RlbmVycy5mb3JFYWNoKChmbikgPT4ge1xyXG4gICAgZm4ocHJlZml4LCB0ZXh0cy5qb2luKCcgJykpO1xyXG4gIH0pO1xyXG5cclxuICAvLyBMb2cgdG8gY29uc29sZVxyXG4gIGlmIChsb2dnaW5nLnRvQ29uc29sZSkge1xyXG4gICAgY29uc29sZS5sb2cuYXBwbHkoXHJcbiAgICAgIHVuZGVmaW5lZCxcclxuICAgICAgW3ByZWZpeC50b1N0cmluZygpW2xvZ2dpbmcubGV2ZWxzRGVzY1tuZXdMZXZlbCAtIDFdLmNvbG9yXV0uY29uY2F0KHRleHRzKVxyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIC8vIExvZyB0byBmaWxlXHJcbiAgbG9nVG9GaWxlKHRleHRzLCBwcmVmaXgpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIExvZ3MgYW4gZXJyb3IgbWVzc2FnZSB3aXRoIGl0cyBzdGFjayB0cmFjZS4gT3B0aW9uYWxseSwgYSBjdXN0b20gbWVzc2FnZVxyXG4gKiBjYW4gYmUgcHJvdmlkZWQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBsZXZlbCAtIFRoZSBsb2cgbGV2ZWwuXHJcbiAqIEBwYXJhbSB7RXJyb3J9IGVycm9yIC0gVGhlIGVycm9yIG9iamVjdC5cclxuICogQHBhcmFtIHtzdHJpbmd9IGN1c3RvbU1lc3NhZ2UgLSBBbiBvcHRpb25hbCBjdXN0b20gbWVzc2FnZSB0byBiZSBsb2dnZWQgYWxvbmdcclxuICogd2l0aCB0aGUgZXJyb3IuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbG9nV2l0aFN0YWNrID0gKG5ld0xldmVsLCBlcnJvciwgY3VzdG9tTWVzc2FnZSkgPT4ge1xyXG4gIC8vIEdldCB0aGUgbWFpbiBtZXNzYWdlXHJcbiAgY29uc3QgbWFpbk1lc3NhZ2UgPSBjdXN0b21NZXNzYWdlIHx8IGVycm9yLm1lc3NhZ2U7XHJcblxyXG4gIC8vIEN1cnJlbnQgbG9nZ2luZyBvcHRpb25zXHJcbiAgY29uc3QgeyBsZXZlbCwgbGV2ZWxzRGVzYyB9ID0gbG9nZ2luZztcclxuXHJcbiAgLy8gQ2hlY2sgaWYgbG9nIGxldmVsIGlzIHdpdGhpbiBhIGNvcnJlY3QgcmFuZ2VcclxuICBpZiAobmV3TGV2ZWwgPT09IDAgfHwgbmV3TGV2ZWwgPiBsZXZlbCB8fCBsZXZlbCA+IGxldmVsc0Rlc2MubGVuZ3RoKSB7XHJcbiAgICByZXR1cm47XHJcbiAgfVxyXG5cclxuICAvLyBHZXQgcmlkIG9mIHRoZSBHTVQgdGV4dCBpbmZvcm1hdGlvblxyXG4gIGNvbnN0IG5ld0RhdGUgPSBuZXcgRGF0ZSgpLnRvU3RyaW5nKCkuc3BsaXQoJygnKVswXS50cmltKCk7XHJcblxyXG4gIC8vIENyZWF0ZSBhIG1lc3NhZ2UncyBwcmVmaXhcclxuICBjb25zdCBwcmVmaXggPSBgJHtuZXdEYXRlfSBbJHtsZXZlbHNEZXNjW25ld0xldmVsIC0gMV0udGl0bGV9XSAtYDtcclxuXHJcbiAgLy8gSWYgdGhlIGN1c3RvbU1lc3NhZ2UgZXhpc3RzLCB3ZSB3YW50IHRvIGRpc3BsYXkgdGhlIHdob2xlIHN0YWNrIG1lc3NhZ2VcclxuICBjb25zdCBzdGFja01lc3NhZ2UgPVxyXG4gICAgZXJyb3IubWVzc2FnZSAhPT0gZXJyb3Iuc3RhY2tNZXNzYWdlIHx8IGVycm9yLnN0YWNrTWVzc2FnZSA9PT0gdW5kZWZpbmVkXHJcbiAgICAgID8gZXJyb3Iuc3RhY2tcclxuICAgICAgOiBlcnJvci5zdGFjay5zcGxpdCgnXFxuJykuc2xpY2UoMSkuam9pbignXFxuJyk7XHJcblxyXG4gIC8vIENvbWJpbmUgY3VzdG9tIG1lc3NhZ2Ugb3IgZXJyb3IgbWVzc2FnZSB3aXRoIGVycm9yIHN0YWNrIG1lc3NhZ2VcclxuICBjb25zdCB0ZXh0cyA9IFttYWluTWVzc2FnZSwgJ1xcbicsIHN0YWNrTWVzc2FnZV07XHJcblxyXG4gIC8vIExvZyB0byBjb25zb2xlXHJcbiAgaWYgKGxvZ2dpbmcudG9Db25zb2xlKSB7XHJcbiAgICBjb25zb2xlLmxvZy5hcHBseShcclxuICAgICAgdW5kZWZpbmVkLFxyXG4gICAgICBbcHJlZml4LnRvU3RyaW5nKClbbG9nZ2luZy5sZXZlbHNEZXNjW25ld0xldmVsIC0gMV0uY29sb3JdXS5jb25jYXQoW1xyXG4gICAgICAgIG1haW5NZXNzYWdlW2NvbG9yc1tuZXdMZXZlbCAtIDFdXSxcclxuICAgICAgICAnXFxuJyxcclxuICAgICAgICBzdGFja01lc3NhZ2VcclxuICAgICAgXSlcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICAvLyBDYWxsIGF2YWlsYWJsZSBsb2cgbGlzdGVuZXJzXHJcbiAgbG9nZ2luZy5saXN0ZW5lcnMuZm9yRWFjaCgoZm4pID0+IHtcclxuICAgIGZuKHByZWZpeCwgdGV4dHMuam9pbignICcpKTtcclxuICB9KTtcclxuXHJcbiAgLy8gTG9nIHRvIGZpbGVcclxuICBsb2dUb0ZpbGUodGV4dHMsIHByZWZpeCk7XHJcbn07XHJcblxyXG4vKipcclxuICogU2V0cyB0aGUgbG9nIGxldmVsIHRvIHRoZSBzcGVjaWZpZWQgdmFsdWUuIExvZyBsZXZlbHMgYXJlICgwID0gbm8gbG9nZ2luZyxcclxuICogMSA9IGVycm9yLCAyID0gd2FybmluZywgMyA9IG5vdGljZSwgNCA9IHZlcmJvc2Ugb3IgNSA9IGJlbmNobWFyaylcclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IG5ld0xldmVsIC0gVGhlIG5ldyBsb2cgbGV2ZWwgdG8gYmUgc2V0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHNldExvZ0xldmVsID0gKG5ld0xldmVsKSA9PiB7XHJcbiAgaWYgKG5ld0xldmVsID49IDAgJiYgbmV3TGV2ZWwgPD0gbG9nZ2luZy5sZXZlbHNEZXNjLmxlbmd0aCkge1xyXG4gICAgbG9nZ2luZy5sZXZlbCA9IG5ld0xldmVsO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBFbmFibGVzIGZpbGUgbG9nZ2luZyB3aXRoIHRoZSBzcGVjaWZpZWQgZGVzdGluYXRpb24gYW5kIGxvZyBmaWxlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gbG9nRGVzdCAtIFRoZSBkZXN0aW5hdGlvbiBwYXRoIGZvciBsb2cgZmlsZXMuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBsb2dGaWxlIC0gVGhlIGxvZyBmaWxlIG5hbWUuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZW5hYmxlRmlsZUxvZ2dpbmcgPSAobG9nRGVzdCwgbG9nRmlsZSkgPT4ge1xyXG4gIC8vIFVwZGF0ZSBsb2dnaW5nIG9wdGlvbnNcclxuICBsb2dnaW5nID0ge1xyXG4gICAgLi4ubG9nZ2luZyxcclxuICAgIGRlc3Q6IGxvZ0Rlc3QgfHwgbG9nZ2luZy5kZXN0LFxyXG4gICAgZmlsZTogbG9nRmlsZSB8fCBsb2dnaW5nLmZpbGUsXHJcbiAgICB0b0ZpbGU6IHRydWVcclxuICB9O1xyXG5cclxuICBpZiAobG9nZ2luZy5kZXN0Lmxlbmd0aCA9PT0gMCkge1xyXG4gICAgcmV0dXJuIGxvZygxLCAnW2xvZ2dlcl0gRmlsZSBsb2dnaW5nIGluaXRpYWxpemF0aW9uOiBubyBwYXRoIHN1cHBsaWVkLicpO1xyXG4gIH1cclxuXHJcbiAgaWYgKCFsb2dnaW5nLmRlc3QuZW5kc1dpdGgoJy8nKSkge1xyXG4gICAgbG9nZ2luZy5kZXN0ICs9ICcvJztcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgbG9nZ2luZyB3aXRoIHRoZSBzcGVjaWZpZWQgbG9nZ2luZyBjb25maWd1cmF0aW9uLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gbG9nZ2luZyAtIFRoZSBsb2dnaW5nIGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGluaXRMb2dnaW5nID0gKGxvZ2dpbmcpID0+IHtcclxuICAvLyBTZXQgdGhlIGxvZyBsZXZlbFxyXG4gIHNldExvZ0xldmVsKGxvZ2dpbmcgJiYgcGFyc2VJbnQobG9nZ2luZy5sZXZlbCkpO1xyXG5cclxuICAvLyBTZXQgdGhlIGxvZyBmaWxlIHBhdGggYW5kIG5hbWVcclxuICBpZiAobG9nZ2luZyAmJiBsb2dnaW5nLmRlc3QpIHtcclxuICAgIGVuYWJsZUZpbGVMb2dnaW5nKFxyXG4gICAgICBsb2dnaW5nLmRlc3QsXHJcbiAgICAgIGxvZ2dpbmcuZmlsZSB8fCAnaGlnaGNoYXJ0cy1leHBvcnQtc2VydmVyLmxvZydcclxuICAgICk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEFkZHMgYSBsaXN0ZW5lciBmdW5jdGlvbiB0byB0aGUgbG9nZ2luZyBzeXN0ZW0uXHJcbiAqXHJcbiAqIEBwYXJhbSB7ZnVuY3Rpb259IGZuIC0gVGhlIGxpc3RlbmVyIGZ1bmN0aW9uIHRvIGJlIGFkZGVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGxpc3RlbiA9IChmbikgPT4ge1xyXG4gIGxvZ2dpbmcubGlzdGVuZXJzLnB1c2goZm4pO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFRvZ2dsZXMgdGhlIHN0YW5kYXJkIG91dHB1dCAoY29uc29sZSkgbG9nZ2luZy5cclxuICpcclxuICogQHBhcmFtIHtib29sZWFufSBlbmFibGVkIC0gSWYgdHJ1ZSwgZW5hYmxlcyBjb25zb2xlIGxvZ2dpbmc7IGlmIGZhbHNlLFxyXG4gKiBkaXNhYmxlcyBpdC5cclxuICovXHJcbmV4cG9ydCBjb25zdCB0b2dnbGVTVERPdXQgPSAoZW5hYmxlZCkgPT4ge1xyXG4gIGxvZ2dpbmcudG9Db25zb2xlID0gZW5hYmxlZDtcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBsb2csXHJcbiAgbG9nV2l0aFN0YWNrLFxyXG4gIHNldExvZ0xldmVsLFxyXG4gIGVuYWJsZUZpbGVMb2dnaW5nLFxyXG4gIGluaXRMb2dnaW5nLFxyXG4gIGxpc3RlbixcclxuICB0b2dnbGVTVERPdXRcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuaW1wb3J0IHsgZmlsZVVSTFRvUGF0aCB9IGZyb20gJ3VybCc7XHJcblxyXG5pbXBvcnQgeyBkZWZhdWx0Q29uZmlnIH0gZnJvbSAnLi4vbGliL3NjaGVtYXMvY29uZmlnLmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcblxyXG5jb25zdCBNQVhfQkFDS09GRl9BVFRFTVBUUyA9IDY7XHJcblxyXG5leHBvcnQgY29uc3QgX19kaXJuYW1lID0gZmlsZVVSTFRvUGF0aChuZXcgVVJMKCcuLi8uJywgaW1wb3J0Lm1ldGEudXJsKSk7XHJcblxyXG4vKipcclxuICogQ2xlYXJzIGFuZCBzdGFuZGFyZGl6ZXMgdGV4dCBieSByZXBsYWNpbmcgbXVsdGlwbGUgY29uc2VjdXRpdmUgd2hpdGVzcGFjZVxyXG4gKiBjaGFyYWN0ZXJzIHdpdGggYSBzaW5nbGUgc3BhY2UgYW5kIHRyaW1taW5nIGFueSBsZWFkaW5nIG9yIHRyYWlsaW5nXHJcbiAqIHdoaXRlc3BhY2UuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0ZXh0IC0gVGhlIGlucHV0IHRleHQgdG8gYmUgY2xlYXJlZC5cclxuICogQHBhcmFtIHtSZWdFeHB9IFtydWxlPS9cXHNcXHMrL2ddIC0gVGhlIHJlZ3VsYXIgZXhwcmVzc2lvbiBydWxlIHRvIG1hdGNoXHJcbiAqIG11bHRpcGxlIGNvbnNlY3V0aXZlIHdoaXRlc3BhY2UgY2hhcmFjdGVycy5cclxuICogQHBhcmFtIHtzdHJpbmd9IFtyZXBsYWNlcj0nICddIC0gVGhlIHN0cmluZyB1c2VkIHRvIHJlcGxhY2UgbXVsdGlwbGVcclxuICogY29uc2VjdXRpdmUgd2hpdGVzcGFjZSBjaGFyYWN0ZXJzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSAtIFRoZSBjbGVhcmVkIGFuZCBzdGFuZGFyZGl6ZWQgdGV4dC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBjbGVhclRleHQgPSAodGV4dCwgcnVsZSA9IC9cXHNcXHMrL2csIHJlcGxhY2VyID0gJyAnKSA9PlxyXG4gIHRleHQucmVwbGFjZUFsbChydWxlLCByZXBsYWNlcikudHJpbSgpO1xyXG5cclxuLyoqXHJcbiAqIEltcGxlbWVudHMgYW4gZXhwb25lbnRpYWwgYmFja29mZiBzdHJhdGVneSBmb3IgcmV0cnlpbmcgYSBmdW5jdGlvbiB1bnRpbFxyXG4gKiBhIGNlcnRhaW4gbnVtYmVyIG9mIGF0dGVtcHRzIGFyZSByZWFjaGVkLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBmbiAtIFRoZSBmdW5jdGlvbiB0byBiZSByZXRyaWVkLlxyXG4gKiBAcGFyYW0ge251bWJlcn0gW2F0dGVtcHQ9MF0gLSBUaGUgY3VycmVudCBhdHRlbXB0IG51bWJlci5cclxuICogQHBhcmFtIHsuLi5hbnl9IGFyZ3MgLSBBcmd1bWVudHMgdG8gYmUgcGFzc2VkIHRvIHRoZSBmdW5jdGlvbi5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2V9IC0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIHJlc3VsdCBvZiB0aGUgZnVuY3Rpb25cclxuICogaWYgc3VjY2Vzc2Z1bC5cclxuICpcclxuICogQHRocm93cyB7RXJyb3J9IC0gVGhyb3dzIGFuIGVycm9yIGlmIHRoZSBtYXhpbXVtIG51bWJlciBvZiBhdHRlbXB0c1xyXG4gKiBpcyByZWFjaGVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGV4cEJhY2tvZmYgPSBhc3luYyAoZm4sIGF0dGVtcHQgPSAwLCAuLi5hcmdzKSA9PiB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIFRyeSB0byBjYWxsIHRoZSBmdW5jdGlvblxyXG4gICAgcmV0dXJuIGF3YWl0IGZuKC4uLmFyZ3MpO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAvLyBDYWxjdWxhdGUgZGVsYXkgaW4gbXNcclxuICAgIGNvbnN0IGRlbGF5SW5NcyA9IDIgKiogYXR0ZW1wdCAqIDEwMDA7XHJcblxyXG4gICAgLy8gSWYgdGhlIGF0dGVtcHQgZXhjZWVkcyB0aGUgbWF4aW11bSBhdHRlbXB0cyBvZiByZWFwZWF0LCB0aHJvdyBhbiBlcnJvclxyXG4gICAgaWYgKCsrYXR0ZW1wdCA+PSBNQVhfQkFDS09GRl9BVFRFTVBUUykge1xyXG4gICAgICB0aHJvdyBlcnJvcjtcclxuICAgIH1cclxuXHJcbiAgICAvLyBXYWl0IGdpdmVuIGFtb3VudCBvZiB0aW1lXHJcbiAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzcG9uc2UpID0+IHNldFRpbWVvdXQocmVzcG9uc2UsIGRlbGF5SW5NcykpO1xyXG4gICAgbG9nKFxyXG4gICAgICAzLFxyXG4gICAgICBgW3Bvb2xdIFdhaXRlZCAke2RlbGF5SW5Nc31tcyB1bnRpbCBuZXh0IGNhbGwgZm9yIHRoZSByZXNvdXJjZSBpZDogJHthcmdzWzBdfS5gXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFRyeSBhZ2FpblxyXG4gICAgcmV0dXJuIGV4cEJhY2tvZmYoZm4sIGF0dGVtcHQsIC4uLmFyZ3MpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBGaXhlcyB0aGUgZXhwb3J0IHR5cGUgYmFzZWQgb24gTUlNRSB0eXBlcyBhbmQgZmlsZSBleHRlbnNpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdHlwZSAtIFRoZSBvcmlnaW5hbCBleHBvcnQgdHlwZS5cclxuICogQHBhcmFtIHtzdHJpbmd9IG91dGZpbGUgLSBUaGUgZmlsZSBwYXRoIG9yIG5hbWUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IC0gVGhlIGNvcnJlY3RlZCBleHBvcnQgdHlwZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBmaXhUeXBlID0gKHR5cGUsIG91dGZpbGUpID0+IHtcclxuICAvLyBNSU1FIHR5cGVzXHJcbiAgY29uc3QgbWltZVR5cGVzID0ge1xyXG4gICAgJ2ltYWdlL3BuZyc6ICdwbmcnLFxyXG4gICAgJ2ltYWdlL2pwZWcnOiAnanBlZycsXHJcbiAgICAnYXBwbGljYXRpb24vcGRmJzogJ3BkZicsXHJcbiAgICAnaW1hZ2Uvc3ZnK3htbCc6ICdzdmcnXHJcbiAgfTtcclxuXHJcbiAgLy8gRm9ybWF0c1xyXG4gIGNvbnN0IGZvcm1hdHMgPSBbJ3BuZycsICdqcGVnJywgJ3BkZicsICdzdmcnXTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgdHlwZSBhbmQgb3V0ZmlsZSdzIGV4dGVuc2lvbnMgYXJlIHRoZSBzYW1lXHJcbiAgaWYgKG91dGZpbGUpIHtcclxuICAgIGNvbnN0IG91dFR5cGUgPSBvdXRmaWxlLnNwbGl0KCcuJykucG9wKCk7XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgZXh0ZW5zaW9uIGhhcyBhIGNvcnJlY3QgdHlwZVxyXG4gICAgaWYgKGZvcm1hdHMuaW5jbHVkZXMob3V0VHlwZSkgJiYgdHlwZSAhPT0gb3V0VHlwZSkge1xyXG4gICAgICB0eXBlID0gb3V0VHlwZTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiBhIGNvcnJlY3QgdHlwZVxyXG4gIHJldHVybiBtaW1lVHlwZXNbdHlwZV0gfHwgZm9ybWF0cy5maW5kKCh0KSA9PiB0ID09PSB0eXBlKSB8fCAncG5nJztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBIYW5kbGVzIGFuZCB2YWxpZGF0ZXMgcmVzb3VyY2VzIGZvciBleHBvcnQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fHN0cmluZ30gcmVzb3VyY2VzIC0gVGhlIHJlc291cmNlcyB0byBiZSBoYW5kbGVkLiBDYW4gYmUgZWl0aGVyXHJcbiAqIGEgSlNPTiBvYmplY3QsIHN0cmluZ2lmaWVkIEpTT04gb3IgYSBwYXRoIHRvIGEgSlNPTiBmaWxlLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RmlsZVJlc291cmNlcyAtIFdoZXRoZXIgdG8gYWxsb3cgbG9hZGluZyByZXNvdXJjZXMgZnJvbVxyXG4gKiBmaWxlcy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdHx1bmRlZmluZWR9IC0gVGhlIGhhbmRsZWQgcmVzb3VyY2VzIG9yIHVuZGVmaW5lZCBpZiBubyB2YWxpZFxyXG4gKiByZXNvdXJjZXMgYXJlIGZvdW5kLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGhhbmRsZVJlc291cmNlcyA9IChyZXNvdXJjZXMgPSBmYWxzZSwgYWxsb3dGaWxlUmVzb3VyY2VzKSA9PiB7XHJcbiAgY29uc3QgYWxsb3dlZFByb3BzID0gWydqcycsICdjc3MnLCAnZmlsZXMnXTtcclxuXHJcbiAgbGV0IGhhbmRsZWRSZXNvdXJjZXMgPSByZXNvdXJjZXM7XHJcbiAgbGV0IGNvcnJlY3RSZXNvdXJjZXMgPSBmYWxzZTtcclxuXHJcbiAgLy8gVHJ5IHRvIGxvYWQgcmVzb3VyY2VzIGZyb20gYSBmaWxlXHJcbiAgaWYgKGFsbG93RmlsZVJlc291cmNlcyAmJiByZXNvdXJjZXMuZW5kc1dpdGgoJy5qc29uJykpIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGhhbmRsZWRSZXNvdXJjZXMgPSBpc0NvcnJlY3RKU09OKHJlYWRGaWxlU3luYyhyZXNvdXJjZXMsICd1dGY4JykpO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgcmV0dXJuIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgYFtjbGldIE5vIHJlc291cmNlcyBmb3VuZC5gKTtcclxuICAgIH1cclxuICB9IGVsc2Uge1xyXG4gICAgLy8gVHJ5IHRvIGdldCBKU09OXHJcbiAgICBoYW5kbGVkUmVzb3VyY2VzID0gaXNDb3JyZWN0SlNPTihyZXNvdXJjZXMpO1xyXG5cclxuICAgIC8vIEdldCByaWQgb2YgdGhlIGZpbGVzIHNlY3Rpb25cclxuICAgIGlmIChoYW5kbGVkUmVzb3VyY2VzICYmICFhbGxvd0ZpbGVSZXNvdXJjZXMpIHtcclxuICAgICAgZGVsZXRlIGhhbmRsZWRSZXNvdXJjZXMuZmlsZXM7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBGaWx0ZXIgZnJvbSB1bm5lY2Vzc2FyeSBwcm9wZXJ0aWVzXHJcbiAgZm9yIChjb25zdCBwcm9wTmFtZSBpbiBoYW5kbGVkUmVzb3VyY2VzKSB7XHJcbiAgICBpZiAoIWFsbG93ZWRQcm9wcy5pbmNsdWRlcyhwcm9wTmFtZSkpIHtcclxuICAgICAgZGVsZXRlIGhhbmRsZWRSZXNvdXJjZXNbcHJvcE5hbWVdO1xyXG4gICAgfSBlbHNlIGlmICghY29ycmVjdFJlc291cmNlcykge1xyXG4gICAgICBjb3JyZWN0UmVzb3VyY2VzID0gdHJ1ZTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIENoZWNrIGlmIGF0IGxlYXN0IG9uZSBvZiBhbGxvd2VkIHByb3BlcnRpZXMgaXMgcHJlc2VudFxyXG4gIGlmICghY29ycmVjdFJlc291cmNlcykge1xyXG4gICAgcmV0dXJuIGxvZygzLCBgW2NsaV0gTm8gcmVzb3VyY2VzIGZvdW5kLmApO1xyXG4gIH1cclxuXHJcbiAgLy8gSGFuZGxlIGZpbGVzIHNlY3Rpb25cclxuICBpZiAoaGFuZGxlZFJlc291cmNlcy5maWxlcykge1xyXG4gICAgaGFuZGxlZFJlc291cmNlcy5maWxlcyA9IGhhbmRsZWRSZXNvdXJjZXMuZmlsZXMubWFwKChpdGVtKSA9PiBpdGVtLnRyaW0oKSk7XHJcbiAgICBpZiAoIWhhbmRsZWRSZXNvdXJjZXMuZmlsZXMgfHwgaGFuZGxlZFJlc291cmNlcy5maWxlcy5sZW5ndGggPD0gMCkge1xyXG4gICAgICBkZWxldGUgaGFuZGxlZFJlc291cmNlcy5maWxlcztcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiByZXNvdXJjZXNcclxuICByZXR1cm4gaGFuZGxlZFJlc291cmNlcztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBWYWxpZGF0ZXMgYW5kIHBhcnNlcyBKU09OIGRhdGEuIENoZWNrcyBpZiBwcm92aWRlZCBkYXRhIGlzIG9yIGNhblxyXG4gKiBiZSBhIGNvcnJlY3QgSlNPTi5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R8c3RyaW5nfSBkYXRhIC0gVGhlIEpTT04gZGF0YSB0byBiZSB2YWxpZGF0ZWQgYW5kIHBhcnNlZC5cclxuICogQHBhcmFtIHtib29sZWFufSB0b1N0cmluZyAtIFdoZXRoZXIgdG8gcmV0dXJuIGEgc3RyaW5naWZpZWQgcmVwcmVzZW50YXRpb25cclxuICogb2YgdGhlIHBhcnNlZCBKU09OLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fHN0cmluZ3xib29sZWFufSAtIFRoZSBwYXJzZWQgSlNPTiBvYmplY3QsIHN0cmluZ2lmaWVkIEpTT04sXHJcbiAqIG9yIGZhbHNlIGlmIHZhbGlkYXRpb24gZmFpbHMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gaXNDb3JyZWN0SlNPTihkYXRhLCB0b1N0cmluZykge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBHZXQgdGhlIHN0cmluZyByZXByZXNlbnRhdGlvbiBpZiBub3QgYWxyZWFkeSBiZWZvcmUgcGFyc2luZ1xyXG4gICAgY29uc3QgcGFyc2VkRGF0YSA9IEpTT04ucGFyc2UoXHJcbiAgICAgIHR5cGVvZiBkYXRhICE9PSAnc3RyaW5nJyA/IEpTT04uc3RyaW5naWZ5KGRhdGEpIDogZGF0YVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBSZXR1cm4gYSBzdHJpbmdpZmllZCByZXByZXNlbnRhdGlvbiBvZiBhIEpTT04gaWYgcmVxdWlyZWRcclxuICAgIGlmICh0eXBlb2YgcGFyc2VkRGF0YSAhPT0gJ3N0cmluZycgJiYgdG9TdHJpbmcpIHtcclxuICAgICAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KHBhcnNlZERhdGEpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFJldHVybiBhIEpTT05cclxuICAgIHJldHVybiBwYXJzZWREYXRhO1xyXG4gIH0gY2F0Y2gge1xyXG4gICAgcmV0dXJuIGZhbHNlO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gaXRlbSBpcyBhbiBvYmplY3QuXHJcbiAqXHJcbiAqIEBwYXJhbSB7YW55fSBpdGVtIC0gVGhlIGl0ZW0gdG8gYmUgY2hlY2tlZC5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IC0gVHJ1ZSBpZiB0aGUgaXRlbSBpcyBhbiBvYmplY3QsIGZhbHNlIG90aGVyd2lzZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBpc09iamVjdCA9IChpdGVtKSA9PlxyXG4gIHR5cGVvZiBpdGVtID09PSAnb2JqZWN0JyAmJiAhQXJyYXkuaXNBcnJheShpdGVtKSAmJiBpdGVtICE9PSBudWxsO1xyXG5cclxuLyoqXHJcbiAqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gb2JqZWN0IGlzIGVtcHR5LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gaXRlbSAtIFRoZSBvYmplY3QgdG8gYmUgY2hlY2tlZC5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IC0gVHJ1ZSBpZiB0aGUgb2JqZWN0IGlzIGVtcHR5LCBmYWxzZSBvdGhlcndpc2UuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaXNPYmplY3RFbXB0eSA9IChpdGVtKSA9PlxyXG4gIHR5cGVvZiBpdGVtID09PSAnb2JqZWN0JyAmJiBpdGVtICE9PSBudWxsICYmIE9iamVjdC5rZXlzKGl0ZW0pLmxlbmd0aCA9PT0gMDtcclxuXHJcbi8qKlxyXG4gKiBDaGVja3MgaWYgYSBwcml2YXRlIElQIHJhbmdlIFVSTCBpcyBmb3VuZCBpbiB0aGUgZ2l2ZW4gc3RyaW5nLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gaXRlbSAtIFRoZSBzdHJpbmcgdG8gYmUgY2hlY2tlZCBmb3IgYSBwcml2YXRlIElQIHJhbmdlIFVSTC5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IC0gVHJ1ZSBpZiBhIHByaXZhdGUgSVAgcmFuZ2UgVVJMIGlzIGZvdW5kLCBmYWxzZVxyXG4gKiBvdGhlcndpc2UuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaXNQcml2YXRlUmFuZ2VVcmxGb3VuZCA9IChpdGVtKSA9PiB7XHJcbiAgcmV0dXJuIFtcclxuICAgICdsb2NhbGhvc3QnLFxyXG4gICAgJygxMCkuKC4qKS4oLiopLiguKiknLFxyXG4gICAgJygxMjcpLiguKikuKC4qKS4oLiopJyxcclxuICAgICcoMTcyKS4oMVs2LTldfDJbMC05XXwzWzAtMV0pLiguKikuKC4qKScsXHJcbiAgICAnKDE5MikuKDE2OCkuKC4qKS4oLiopJ1xyXG4gIF0uc29tZSgoaXBSZWdFeCkgPT5cclxuICAgIGl0ZW0ubWF0Y2goYHhsaW5rOmhyZWY9XCIoPzooaHR0cDovL3xodHRwczovLykpPyR7aXBSZWdFeH1gKVxyXG4gICk7XHJcbn07XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhIGRlZXAgY29weSBvZiB0aGUgZ2l2ZW4gb2JqZWN0IG9yIGFycmF5LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdHxBcnJheX0gb2JqIC0gVGhlIG9iamVjdCBvciBhcnJheSB0byBiZSBkZWVwbHkgY29waWVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fEFycmF5fSAtIFRoZSBkZWVwIGNvcHkgb2YgdGhlIHByb3ZpZGVkIG9iamVjdCBvciBhcnJheS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBkZWVwQ29weSA9IChvYmopID0+IHtcclxuICBpZiAob2JqID09PSBudWxsIHx8IHR5cGVvZiBvYmogIT09ICdvYmplY3QnKSB7XHJcbiAgICByZXR1cm4gb2JqO1xyXG4gIH1cclxuXHJcbiAgY29uc3QgY29weSA9IEFycmF5LmlzQXJyYXkob2JqKSA/IFtdIDoge307XHJcblxyXG4gIGZvciAoY29uc3Qga2V5IGluIG9iaikge1xyXG4gICAgaWYgKE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChvYmosIGtleSkpIHtcclxuICAgICAgY29weVtrZXldID0gZGVlcENvcHkob2JqW2tleV0pO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcmV0dXJuIGNvcHk7XHJcbn07XHJcblxyXG4vKipcclxuICogQ29udmVydHMgdGhlIHByb3ZpZGVkIG9wdGlvbnMgb2JqZWN0IHRvIGEgSlNPTi1mb3JtYXR0ZWQgc3RyaW5nIHdpdGggdGhlXHJcbiAqIG9wdGlvbiB0byBwcmVzZXJ2ZSBmdW5jdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IHRvIGJlIGNvbnZlcnRlZCB0byBhIHN0cmluZy5cclxuICogQHBhcmFtIHtib29sZWFufSBhbGxvd0Z1bmN0aW9ucyAtIElmIHNldCB0byB0cnVlLCBmdW5jdGlvbnMgYXJlIHByZXNlcnZlZFxyXG4gKiBpbiB0aGUgb3V0cHV0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSAtIFRoZSBKU09OLWZvcm1hdHRlZCBzdHJpbmcgcmVwcmVzZW50aW5nIHRoZSBvcHRpb25zLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IG9wdGlvbnNTdHJpbmdpZnkgPSAob3B0aW9ucywgYWxsb3dGdW5jdGlvbnMpID0+IHtcclxuICBjb25zdCByZXBsYWNlckNhbGxiYWNrID0gKG5hbWUsIHZhbHVlKSA9PiB7XHJcbiAgICBpZiAodHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJykge1xyXG4gICAgICB2YWx1ZSA9IHZhbHVlLnRyaW0oKTtcclxuXHJcbiAgICAgIC8vIElmIGFsbG93RnVuY3Rpb25zIGlzIHNldCB0byB0cnVlLCBwcmVzZXJ2ZSBmdW5jdGlvbnNcclxuICAgICAgaWYgKFxyXG4gICAgICAgICh2YWx1ZS5zdGFydHNXaXRoKCdmdW5jdGlvbignKSB8fCB2YWx1ZS5zdGFydHNXaXRoKCdmdW5jdGlvbiAoJykpICYmXHJcbiAgICAgICAgdmFsdWUuZW5kc1dpdGgoJ30nKVxyXG4gICAgICApIHtcclxuICAgICAgICB2YWx1ZSA9IGFsbG93RnVuY3Rpb25zXHJcbiAgICAgICAgICA/IGBFWFBfRlVOJHsodmFsdWUgKyAnJykucmVwbGFjZUFsbCgvXFxufFxcdHxcXHIvZywgJyAnKX1FWFBfRlVOYFxyXG4gICAgICAgICAgOiB1bmRlZmluZWQ7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gdHlwZW9mIHZhbHVlID09PSAnZnVuY3Rpb24nXHJcbiAgICAgID8gYEVYUF9GVU4keyh2YWx1ZSArICcnKS5yZXBsYWNlQWxsKC9cXG58XFx0fFxcci9nLCAnICcpfUVYUF9GVU5gXHJcbiAgICAgIDogdmFsdWU7XHJcbiAgfTtcclxuXHJcbiAgLy8gU3RyaW5naWZ5IG9wdGlvbnMgYW5kIGlmIHJlcXVpcmVkLCByZXBsYWNlIHNwZWNpYWwgZnVuY3Rpb25zIG1hcmtzXHJcbiAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KG9wdGlvbnMsIHJlcGxhY2VyQ2FsbGJhY2spLnJlcGxhY2VBbGwoXHJcbiAgICAvXCJFWFBfRlVOfEVYUF9GVU5cIi9nLFxyXG4gICAgJydcclxuICApO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFByaW50cyB0aGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyIGxvZ28gYW5kIHZlcnNpb24gaW5mb3JtYXRpb24uXHJcbiAqXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gbm9Mb2dvIC0gSWYgdHJ1ZSwgb25seSBwcmludHMgdmVyc2lvbiBpbmZvcm1hdGlvbiB3aXRob3V0XHJcbiAqIHRoZSBsb2dvLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHByaW50TG9nbyA9IChub0xvZ28pID0+IHtcclxuICAvLyBHZXQgcGFja2FnZSB2ZXJzaW9uIGVpdGhlciBmcm9tIGVudiBvciBmcm9tIHBhY2thZ2UuanNvblxyXG4gIGNvbnN0IHBhY2thZ2VWZXJzaW9uID0gSlNPTi5wYXJzZShcclxuICAgIHJlYWRGaWxlU3luYyhqb2luKF9fZGlybmFtZSwgJ3BhY2thZ2UuanNvbicpKVxyXG4gICkudmVyc2lvbjtcclxuXHJcbiAgLy8gUHJpbnQgdGV4dCBvbmx5XHJcbiAgaWYgKG5vTG9nbykge1xyXG4gICAgY29uc29sZS5sb2coYFN0YXJ0aW5nIEhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlciB2JHtwYWNrYWdlVmVyc2lvbn0uLi5gKTtcclxuICAgIHJldHVybjtcclxuICB9XHJcblxyXG4gIC8vIFByaW50IHRoZSBsb2dvXHJcbiAgY29uc29sZS5sb2coXHJcbiAgICByZWFkRmlsZVN5bmMoX19kaXJuYW1lICsgJy9tc2cvc3RhcnR1cC5tc2cnKS50b1N0cmluZygpLmJvbGQueWVsbG93LFxyXG4gICAgYHYke3BhY2thZ2VWZXJzaW9ufWBcclxuICApO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFByaW50cyB0aGUgdXNhZ2UgaW5mb3JtYXRpb24gZm9yIENMSSBhcmd1bWVudHMuIElmIHJlcXVpcmVkLCBpdCBjYW4gbGlzdFxyXG4gKiBwcm9wZXJ0aWVzIHJlY3Vyc2l2ZWx5XHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gcHJpbnRVc2FnZSgpIHtcclxuICBjb25zdCBwYWQgPSA0ODtcclxuICBjb25zdCByZWFkbWUgPSAnaHR0cHM6Ly9naXRodWIuY29tL2hpZ2hjaGFydHMvbm9kZS1leHBvcnQtc2VydmVyI3JlYWRtZSc7XHJcblxyXG4gIC8vIERpc3BsYXkgcmVhZG1lIGluZm9ybWF0aW9uXHJcbiAgY29uc29sZS5sb2coXHJcbiAgICAnXFxuVXNhZ2Ugb2YgQ0xJIGFyZ3VtZW50czonLmJvbGQsXHJcbiAgICAnXFxuLS0tLS0tJyxcclxuICAgIGBcXG5Gb3IgbW9yZSBkZXRhaWxlZCBpbmZvcm1hdGlvbiwgdmlzaXQgdGhlIHJlYWRtZSBhdDogJHtyZWFkbWUuYm9sZC55ZWxsb3d9LmBcclxuICApO1xyXG5cclxuICBjb25zdCBjeWNsZUNhdGVnb3JpZXMgPSAob3B0aW9ucykgPT4ge1xyXG4gICAgZm9yIChjb25zdCBbbmFtZSwgb3B0aW9uXSBvZiBPYmplY3QuZW50cmllcyhvcHRpb25zKSkge1xyXG4gICAgICAvLyBJZiBjYXRlZ29yeSBoYXMgbW9yZSBsZXZlbHMsIGdvIGZ1cnRoZXJcclxuICAgICAgaWYgKCFPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob3B0aW9uLCAndmFsdWUnKSkge1xyXG4gICAgICAgIGN5Y2xlQ2F0ZWdvcmllcyhvcHRpb24pO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIGxldCBkZXNjTmFtZSA9IGAgIC0tJHtvcHRpb24uY2xpTmFtZSB8fCBuYW1lfSAke1xyXG4gICAgICAgICAgKCc8JyArIG9wdGlvbi50eXBlICsgJz4nKS5ncmVlblxyXG4gICAgICAgIH0gYDtcclxuICAgICAgICBpZiAoZGVzY05hbWUubGVuZ3RoIDwgcGFkKSB7XHJcbiAgICAgICAgICBmb3IgKGxldCBpID0gZGVzY05hbWUubGVuZ3RoOyBpIDwgcGFkOyBpKyspIHtcclxuICAgICAgICAgICAgZGVzY05hbWUgKz0gJy4nO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gRGlzcGxheSBjb3JyZWN0bHkgYWxpZ25lZCBtZXNzYWdlc1xyXG4gICAgICAgIGNvbnNvbGUubG9nKFxyXG4gICAgICAgICAgZGVzY05hbWUsXHJcbiAgICAgICAgICBvcHRpb24uZGVzY3JpcHRpb24sXHJcbiAgICAgICAgICBgW0RlZmF1bHQ6ICR7b3B0aW9uLnZhbHVlLnRvU3RyaW5nKCkuYm9sZH1dYC5ibHVlXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH07XHJcblxyXG4gIC8vIEN5Y2xlIHRocm91Z2ggb3B0aW9ucyBvZiBlYWNoIGNhdGVnb3JpZXMgYW5kIGRpc3BsYXkgdGhlIHVzYWdlIGluZm9cclxuICBPYmplY3Qua2V5cyhkZWZhdWx0Q29uZmlnKS5mb3JFYWNoKChjYXRlZ29yeSkgPT4ge1xyXG4gICAgLy8gT25seSBwdXBwZXRlZXIgYW5kIGhpZ2hjaGFydHMgY2F0ZWdvcmllcyBjYW5ub3QgYmUgY29uZmlndXJlZCB0aHJvdWdoIENMSVxyXG4gICAgaWYgKCFbJ3B1cHBldGVlcicsICdoaWdoY2hhcnRzJ10uaW5jbHVkZXMoY2F0ZWdvcnkpKSB7XHJcbiAgICAgIGNvbnNvbGUubG9nKGBcXG4ke2NhdGVnb3J5LnRvVXBwZXJDYXNlKCl9YC5yZWQpO1xyXG4gICAgICBjeWNsZUNhdGVnb3JpZXMoZGVmYXVsdENvbmZpZ1tjYXRlZ29yeV0pO1xyXG4gICAgfVxyXG4gIH0pO1xyXG4gIGNvbnNvbGUubG9nKCdcXG4nKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFJvdW5kcyBhIG51bWJlciB0byB0aGUgc3BlY2lmaWVkIHByZWNpc2lvbi5cclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IHZhbHVlIC0gVGhlIG51bWJlciB0byBiZSByb3VuZGVkLlxyXG4gKiBAcGFyYW0ge251bWJlcn0gcHJlY2lzaW9uIC0gVGhlIG51bWJlciBvZiBkZWNpbWFsIHBsYWNlcyB0byByb3VuZCB0by5cclxuICpcclxuICogQHJldHVybnMge251bWJlcn0gLSBUaGUgcm91bmRlZCBudW1iZXIuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgcm91bmROdW1iZXIgPSAodmFsdWUsIHByZWNpc2lvbiA9IDEpID0+IHtcclxuICBjb25zdCBtdWx0aXBsaWVyID0gTWF0aC5wb3coMTAsIHByZWNpc2lvbiB8fCAwKTtcclxuICByZXR1cm4gTWF0aC5yb3VuZCgrdmFsdWUgKiBtdWx0aXBsaWVyKSAvIG11bHRpcGxpZXI7XHJcbn07XHJcblxyXG4vKipcclxuICogQ29udmVydHMgYSB2YWx1ZSB0byBhIGJvb2xlYW4uXHJcbiAqXHJcbiAqIEBwYXJhbSB7YW55fSBpdGVtIC0gVGhlIHZhbHVlIHRvIGJlIGNvbnZlcnRlZCB0byBhIGJvb2xlYW4uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtib29sZWFufSAtIFRoZSBib29sZWFuIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBpbnB1dCB2YWx1ZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCB0b0Jvb2xlYW4gPSAoaXRlbSkgPT5cclxuICBbJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJywgJ05hTicsICcwJywgJyddLmluY2x1ZGVzKGl0ZW0pXHJcbiAgICA/IGZhbHNlXHJcbiAgICA6ICEhaXRlbTtcclxuXHJcbi8qKlxyXG4gKiBXcmFwcyBjdXN0b20gY29kZSB0byBleGVjdXRlIGl0IHNhZmVseS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGN1c3RvbUNvZGUgLSBUaGUgY3VzdG9tIGNvZGUgdG8gYmUgd3JhcHBlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBhbGxvd0ZpbGVSZXNvdXJjZXMgLSBGbGFnIHRvIGFsbG93IGxvYWRpbmcgY29kZSBmcm9tIGEgZmlsZS5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ3xib29sZWFufSAtIFRoZSB3cmFwcGVkIGN1c3RvbSBjb2RlIG9yIGZhbHNlIGlmIHdyYXBwaW5nXHJcbiAqIGZhaWxzLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHdyYXBBcm91bmQgPSAoY3VzdG9tQ29kZSwgYWxsb3dGaWxlUmVzb3VyY2VzKSA9PiB7XHJcbiAgaWYgKGN1c3RvbUNvZGUgJiYgdHlwZW9mIGN1c3RvbUNvZGUgPT09ICdzdHJpbmcnKSB7XHJcbiAgICBjdXN0b21Db2RlID0gY3VzdG9tQ29kZS50cmltKCk7XHJcblxyXG4gICAgaWYgKGN1c3RvbUNvZGUuZW5kc1dpdGgoJy5qcycpKSB7XHJcbiAgICAgIHJldHVybiBhbGxvd0ZpbGVSZXNvdXJjZXNcclxuICAgICAgICA/IHdyYXBBcm91bmQocmVhZEZpbGVTeW5jKGN1c3RvbUNvZGUsICd1dGY4JykpXHJcbiAgICAgICAgOiBmYWxzZTtcclxuICAgIH0gZWxzZSBpZiAoXHJcbiAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnZnVuY3Rpb24oKScpIHx8XHJcbiAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnZnVuY3Rpb24gKCknKSB8fFxyXG4gICAgICBjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJygpPT4nKSB8fFxyXG4gICAgICBjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJygpID0+JylcclxuICAgICkge1xyXG4gICAgICByZXR1cm4gYCgke2N1c3RvbUNvZGV9KSgpYDtcclxuICAgIH1cclxuICAgIHJldHVybiBjdXN0b21Db2RlLnJlcGxhY2UoLzskLywgJycpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBVdGlsaXR5IHRvIG1lYXN1cmUgZWxhcHNlZCB0aW1lIHVzaW5nIHRoZSBOb2RlLmpzIHByb2Nlc3MuaHJ0aW1lKCkgbWV0aG9kLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7ZnVuY3Rpb24oKTogbnVtYmVyfSAtIEEgZnVuY3Rpb24gdG8gY2FsY3VsYXRlIHRoZSBlbGFwc2VkIHRpbWVcclxuICogaW4gbWlsbGlzZWNvbmRzLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IG1lYXN1cmVUaW1lID0gKCkgPT4ge1xyXG4gIGNvbnN0IHN0YXJ0ID0gcHJvY2Vzcy5ocnRpbWUuYmlnaW50KCk7XHJcbiAgcmV0dXJuICgpID0+IE51bWJlcihwcm9jZXNzLmhydGltZS5iaWdpbnQoKSAtIHN0YXJ0KSAvIDEwMDAwMDA7XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgX19kaXJuYW1lLFxyXG4gIGNsZWFyVGV4dCxcclxuICBleHBCYWNrb2ZmLFxyXG4gIGZpeFR5cGUsXHJcbiAgaGFuZGxlUmVzb3VyY2VzLFxyXG4gIGlzQ29ycmVjdEpTT04sXHJcbiAgaXNPYmplY3QsXHJcbiAgaXNPYmplY3RFbXB0eSxcclxuICBpc1ByaXZhdGVSYW5nZVVybEZvdW5kLFxyXG4gIG9wdGlvbnNTdHJpbmdpZnksXHJcbiAgcHJpbnRMb2dvLFxyXG4gIHByaW50VXNhZ2UsXHJcbiAgcm91bmROdW1iZXIsXHJcbiAgdG9Cb29sZWFuLFxyXG4gIHdyYXBBcm91bmQsXHJcbiAgbWVhc3VyZVRpbWVcclxufTtcclxuIiwiY2xhc3MgRXhwb3J0RXJyb3IgZXh0ZW5kcyBFcnJvciB7XHJcbiAgY29uc3RydWN0b3IobWVzc2FnZSkge1xyXG4gICAgc3VwZXIoKTtcclxuICAgIHRoaXMubWVzc2FnZSA9IG1lc3NhZ2U7XHJcbiAgICB0aGlzLnN0YWNrTWVzc2FnZSA9IG1lc3NhZ2U7XHJcbiAgfVxyXG5cclxuICBzZXRFcnJvcihlcnJvcikge1xyXG4gICAgdGhpcy5lcnJvciA9IGVycm9yO1xyXG4gICAgaWYgKGVycm9yLm5hbWUpIHtcclxuICAgICAgdGhpcy5uYW1lID0gZXJyb3IubmFtZTtcclxuICAgIH1cclxuICAgIGlmIChlcnJvci5zdGF0dXNDb2RlKSB7XHJcbiAgICAgIHRoaXMuc3RhdHVzQ29kZSA9IGVycm9yLnN0YXR1c0NvZGU7XHJcbiAgICB9XHJcbiAgICBpZiAoZXJyb3Iuc3RhY2spIHtcclxuICAgICAgdGhpcy5zdGFja01lc3NhZ2UgPSBlcnJvci5tZXNzYWdlO1xyXG4gICAgICB0aGlzLnN0YWNrID0gZXJyb3Iuc3RhY2s7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gdGhpcztcclxuICB9XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IEV4cG9ydEVycm9yO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8vIFRoZSBjYWNoZSBtYW5hZ2VyIG1hbmFnZXMgdGhlIEhpZ2hjaGFydHMgbGlicmFyeSBhbmQgaXRzIGRlcGVuZGVuY2llcy5cclxuLy8gVGhlIGNhY2hlIGl0c2VsZiBpcyBzdG9yZWQgaW4gLmNhY2hlLCBhbmQgaXMgY2hlY2tlZCBieSB0aGUgY29uZmlnIHN5c3RlbVxyXG4vLyBiZWZvcmUgc3RhcnRpbmcgdGhlIHNlcnZpY2VcclxuXHJcbmltcG9ydCB7IGV4aXN0c1N5bmMsIG1rZGlyU3luYywgcmVhZEZpbGVTeW5jLCB3cml0ZUZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgeyBIdHRwc1Byb3h5QWdlbnQgfSBmcm9tICdodHRwcy1wcm94eS1hZ2VudCc7XHJcblxyXG5pbXBvcnQgeyBmZXRjaCB9IGZyb20gJy4vZmV0Y2guanMnO1xyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IF9fZGlybmFtZSB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbmNvbnN0IGNhY2hlID0ge1xyXG4gIGNkblVSTDogJ2h0dHBzOi8vY29kZS5oaWdoY2hhcnRzLmNvbS8nLFxyXG4gIGFjdGl2ZU1hbmlmZXN0OiB7fSxcclxuICBzb3VyY2VzOiAnJyxcclxuICBoY1ZlcnNpb246ICcnXHJcbn07XHJcblxyXG4vLyBUT0RPOiBUaGUgY29uZmlnIHNob3VsZCBiZSBhY2Nlc3NzaWJsZSBnbG9iYWxseSBzbyB3ZSBkb24ndCBoYXZlIHRvIGRvIHRoaXMgc29ydCBvZiB0aGluZy4uXHJcbmxldCBhcHBsaWVkQ29uZmlnID0gZmFsc2U7XHJcblxyXG4vKipcclxuICogRXh0cmFjdHMgYW5kIGNhY2hlcyB0aGUgSGlnaGNoYXJ0cyB2ZXJzaW9uIGZyb20gdGhlIHNvdXJjZXMgc3RyaW5nLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgZXh0cmFjdGVkIEhpZ2hjaGFydHMgdmVyc2lvbi5cclxuICovXHJcbmNvbnN0IGV4dHJhY3RWZXJzaW9uID0gKCkgPT5cclxuICAoY2FjaGUuaGNWZXJzaW9uID0gY2FjaGUuc291cmNlc1xyXG4gICAgLnN1YnN0cmluZygwLCBjYWNoZS5zb3VyY2VzLmluZGV4T2YoJyovJykpXHJcbiAgICAucmVwbGFjZSgnLyonLCAnJylcclxuICAgIC5yZXBsYWNlKCcqLycsICcnKVxyXG4gICAgLnJlcGxhY2UoL1xcbi9nLCAnJylcclxuICAgIC50cmltKCkpO1xyXG5cclxuLyoqXHJcbiAqIEV4dHJhY3RzIHRoZSBIaWdoY2hhcnRzIG1vZHVsZSBuYW1lIGJhc2VkIG9uIHRoZSBzY3JpcHRQYXRoLlxyXG4gKi9cclxuY29uc3QgZXh0cmFjdE1vZHVsZU5hbWUgPSAoc2NyaXB0UGF0aCkgPT4ge1xyXG4gIHJldHVybiBzY3JpcHRQYXRoLnJlcGxhY2UoXHJcbiAgICAvKC4qKVxcL3woLiopbW9kdWxlc1xcL3xzdG9ja1xcLyguKilpbmRpY2F0b3JzXFwvfG1hcHNcXC8oLiopbW9kdWxlc1xcLy9naSxcclxuICAgICcnXHJcbiAgKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBTYXZlcyB0aGUgcHJvdmlkZWQgY29uZmlndXJhdGlvbiBhbmQgZmV0Y2hlZCBtb2R1bGVzIHRvIHRoZSBjYWNoZSBtYW5pZmVzdFxyXG4gKiBmaWxlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge29iamVjdH0gY29uZmlnIC0gSGlnaGNoYXJ0cy1yZWxhdGVkIGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxyXG4gKiBAcGFyYW0ge29iamVjdH0gZmV0Y2hlZE1vZHVsZXMgLSBBbiBvYmplY3QgdGhhdCBjb250YWlucyBtYXBwZWQgbmFtZXMgb2ZcclxuICogZmV0Y2hlZCBIaWdoY2hhcnRzIG1vZHVsZXMgdG8gdXNlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIGFuIGVycm9yIG9jY3VycyB3aGlsZSB3cml0aW5nXHJcbiAqIHRoZSBjYWNoZSBtYW5pZmVzdC5cclxuICovXHJcbmNvbnN0IHNhdmVDb25maWdUb01hbmlmZXN0ID0gYXN5bmMgKGNvbmZpZywgZmV0Y2hlZE1vZHVsZXMpID0+IHtcclxuICBjb25zdCBuZXdNYW5pZmVzdCA9IHtcclxuICAgIHZlcnNpb246IGNvbmZpZy52ZXJzaW9uLFxyXG4gICAgbW9kdWxlczogZmV0Y2hlZE1vZHVsZXMgfHwge31cclxuICB9O1xyXG5cclxuICAvLyBVcGRhdGUgY2FjaGUgb2JqZWN0IHdpdGggdGhlIGN1cnJlbnQgbW9kdWxlc1xyXG4gIGNhY2hlLmFjdGl2ZU1hbmlmZXN0ID0gbmV3TWFuaWZlc3Q7XHJcblxyXG4gIGxvZygzLCAnW2NhY2hlXSBXcml0aW5nIGEgbmV3IG1hbmlmZXN0LicpO1xyXG4gIHRyeSB7XHJcbiAgICB3cml0ZUZpbGVTeW5jKFxyXG4gICAgICBqb2luKF9fZGlybmFtZSwgY29uZmlnLmNhY2hlUGF0aCwgJ21hbmlmZXN0Lmpzb24nKSxcclxuICAgICAgSlNPTi5zdHJpbmdpZnkobmV3TWFuaWZlc3QpLFxyXG4gICAgICAndXRmOCdcclxuICAgICk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW2NhY2hlXSBFcnJvciB3cml0aW5nIHRoZSBjYWNoZSBtYW5pZmVzdC4nKS5zZXRFcnJvcihcclxuICAgICAgZXJyb3JcclxuICAgICk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEZldGNoZXMgYSBzaW5nbGUgc2NyaXB0IGFuZCB1cGRhdGVzIHRoZSBmZXRjaGVkTW9kdWxlcyBhY2NvcmRpbmdseS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHNjcmlwdCAtIEEgcGF0aCB0byBzY3JpcHQgdG8gZ2V0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcHJveHlBZ2VudCAtIFRoZSBwcm94eSBhZ2VudCB0byB1c2UgZm9yIGEgcmVxdWVzdC5cclxuICogQHBhcmFtIHtPYmplY3R9IGZldGNoZWRNb2R1bGVzIC0gQW4gb2JqZWN0IHdoaWNoIHRyYWNrcyB3aGljaCBIaWdoY2hhcnRzIG1vZHVsZXMgaGF2ZSBiZWVuIGZldGNoZWQuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gc2hvdWxkVGhyb3dFcnJvciAtIEEgZmxhZyB0byBpbmRpY2F0ZSBpZiB0aGUgZXJyb3Igc2hvdWxkIGJlIHRocm93bi4gVGhpcyBzaG91bGQgYmUgdXNlZCBvbmx5IGZvciB0aGUgY29yZSBzY3JpcHRzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSB0ZXh0IHJlcHJlc2VudGF0aW9uXHJcbiAqIG9mIHRoZSBmZXRjaGVkIHNjcmlwdC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiB0aGVyZSBpcyBhIHByb2JsZW0gd2l0aFxyXG4gKiBmZXRjaGluZyB0aGUgc2NyaXB0LlxyXG4gKi9cclxuY29uc3QgZmV0Y2hBbmRQcm9jZXNzU2NyaXB0ID0gYXN5bmMgKFxyXG4gIHNjcmlwdCxcclxuICBwcm94eUFnZW50LFxyXG4gIGZldGNoZWRNb2R1bGVzLFxyXG4gIHNob3VsZFRocm93RXJyb3IgPSBmYWxzZVxyXG4pID0+IHtcclxuICAvLyBHZXQgcmlkIG9mIHRoZSAuanMgZnJvbSB0aGUgY3VzdG9tIHN0cmluZ3NcclxuICBpZiAoc2NyaXB0LmVuZHNXaXRoKCcuanMnKSkge1xyXG4gICAgc2NyaXB0ID0gc2NyaXB0LnN1YnN0cmluZygwLCBzY3JpcHQubGVuZ3RoIC0gMyk7XHJcbiAgfVxyXG5cclxuICBsb2coNCwgYFtjYWNoZV0gRmV0Y2hpbmcgc2NyaXB0IC0gJHtzY3JpcHR9LmpzYCk7XHJcblxyXG4gIC8vIElmIGV4aXN0cywgYWRkIHByb3h5IGFnZW50IHRvIHJlcXVlc3Qgb3B0aW9uc1xyXG4gIGNvbnN0IHJlcXVlc3RPcHRpb25zID0gcHJveHlBZ2VudFxyXG4gICAgPyB7XHJcbiAgICAgICAgYWdlbnQ6IHByb3h5QWdlbnQsXHJcbiAgICAgICAgdGltZW91dDogK3Byb2Nlc3MuZW52WydQUk9YWV9TRVJWRVJfVElNRU9VVCddIHx8IDUwMDBcclxuICAgICAgfVxyXG4gICAgOiB7fTtcclxuXHJcbiAgLy8gRmV0Y2ggdGhlIHNjcmlwdFxyXG4gIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2goYCR7c2NyaXB0fS5qc2AsIHJlcXVlc3RPcHRpb25zKTtcclxuXHJcbiAgLy8gSWYgT0ssIHJldHVybiBpdHMgdGV4dCByZXByZXNlbnRhdGlvblxyXG4gIGlmIChyZXNwb25zZS5zdGF0dXNDb2RlID09PSAyMDAgJiYgdHlwZW9mIHJlc3BvbnNlLnRleHQgPT0gJ3N0cmluZycpIHtcclxuICAgIGlmIChmZXRjaGVkTW9kdWxlcykge1xyXG4gICAgICBjb25zdCBtb2R1bGVOYW1lID0gZXh0cmFjdE1vZHVsZU5hbWUoc2NyaXB0KTtcclxuICAgICAgZmV0Y2hlZE1vZHVsZXNbbW9kdWxlTmFtZV0gPSAxO1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiByZXNwb25zZS50ZXh0O1xyXG4gIH1cclxuXHJcbiAgaWYgKHNob3VsZFRocm93RXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgYENvdWxkIG5vdCBmZXRjaCB0aGUgJHtzY3JpcHR9LmpzLiBUaGUgc2NyaXB0IG1pZ2h0IG5vdCBleGlzdCBpbiB0aGUgcmVxdWVzdGVkIHZlcnNpb24gKHN0YXR1cyBjb2RlOiAke3Jlc3BvbnNlLnN0YXR1c0NvZGV9KS5gXHJcbiAgICApLnNldEVycm9yKHJlc3BvbnNlKTtcclxuICB9IGVsc2Uge1xyXG4gICAgbG9nKFxyXG4gICAgICAyLFxyXG4gICAgICBgW2NhY2hlXSBDb3VsZCBub3QgZmV0Y2ggdGhlICR7c2NyaXB0fS5qcy4gVGhlIHNjcmlwdCBtaWdodCBub3QgZXhpc3QgaW4gdGhlIHJlcXVlc3RlZCB2ZXJzaW9uLmBcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICByZXR1cm4gJyc7XHJcbn07XHJcblxyXG4vKipcclxuICogRmV0Y2hlcyBIaWdoY2hhcnRzIHNjcmlwdHMgYW5kIGN1c3RvbVNjcmlwdHMgZnJvbSB0aGUgZ2l2ZW4gQ0ROcy5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHNjcmlwdHMgLSBBcnJheSBvZiBIaWdoY2hhcnRzIG1vZHVsZXMgdG8gZmV0Y2guXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBjdXN0b21TY3JpcHRzIC0gQXJyYXkgb2YgY3VzdG9tIHNjcmlwdCBwYXRocyB0byBmZXRjaCAoZnVsbCBVUkxzKS5cclxuICogQHBhcmFtIHtvYmplY3R9IHByb3h5QWdlbnQgLSBUaGUgcHJveHkgYWdlbnQgdG8gdXNlIGZvciBhIHJlcXVlc3QuXHJcbiAqIEBwYXJhbSB7b2JqZWN0fSBmZXRjaGVkTW9kdWxlcyAtIEFuIG9iamVjdCB3aGljaCB0cmFja3Mgd2hpY2ggSGlnaGNoYXJ0cyBtb2R1bGVzIGhhdmUgYmVlbiBmZXRjaGVkLlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSBUaGUgZmV0Y2hlZCBzY3JpcHRzIGNvbnRlbnQgam9pbmVkLlxyXG4gKi9cclxuY29uc3QgZmV0Y2hTY3JpcHRzID0gYXN5bmMgKFxyXG4gIGNvcmVTY3JpcHRzLFxyXG4gIG1vZHVsZVNjcmlwdHMsXHJcbiAgY3VzdG9tU2NyaXB0cyxcclxuICBjZG5VUkwsXHJcbiAgcHJveHlBZ2VudCxcclxuICBmZXRjaGVkTW9kdWxlc1xyXG4pID0+IHtcclxuICBjb25zdCBhbGxGZXRjaFByb21pc2VzID0gW1xyXG4gICAgLi4uY29yZVNjcmlwdHMubWFwKChzY3JpcHQpID0+XHJcbiAgICAgIGZldGNoQW5kUHJvY2Vzc1NjcmlwdChcclxuICAgICAgICBgJHtjZG5VUkx9JHtzY3JpcHR9YCxcclxuICAgICAgICBwcm94eUFnZW50LFxyXG4gICAgICAgIGZldGNoZWRNb2R1bGVzLFxyXG4gICAgICAgIHRydWVcclxuICAgICAgKVxyXG4gICAgKSxcclxuICAgIC4uLm1vZHVsZVNjcmlwdHMubWFwKChzY3JpcHQpID0+XHJcbiAgICAgIGZldGNoQW5kUHJvY2Vzc1NjcmlwdChgJHtjZG5VUkx9JHtzY3JpcHR9YCwgcHJveHlBZ2VudCwgZmV0Y2hlZE1vZHVsZXMpXHJcbiAgICApLFxyXG4gICAgLi4uY3VzdG9tU2NyaXB0cy5tYXAoKHNjcmlwdCkgPT5cclxuICAgICAgZmV0Y2hBbmRQcm9jZXNzU2NyaXB0KGAke3NjcmlwdH1gLCBwcm94eUFnZW50KVxyXG4gICAgKVxyXG4gIF07XHJcblxyXG4gIGNvbnN0IGZldGNoZWRTY3JpcHRzID0gYXdhaXQgUHJvbWlzZS5hbGwoYWxsRmV0Y2hQcm9taXNlcyk7XHJcbiAgcmV0dXJuIGZldGNoZWRTY3JpcHRzLmpvaW4oJztcXG4nKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBVcGRhdGVzIHRoZSBsb2NhbCBjYWNoZSB3aXRoIEhpZ2hjaGFydHMgc2NyaXB0cyBhbmQgdGhlaXIgdmVyc2lvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjb25maWcgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZyBpbmZvcm1hdGlvblxyXG4gKiBhYm91dCBzY3JpcHRzIGFuZCBtb2R1bGVzLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gc291cmNlUGF0aCAtIFRoZSBwYXRoIHRvIHRoZSBzb3VyY2UgZmlsZSBpbiB0aGUgY2FjaGUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPG9iamVjdD59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gYW4gb2JqZWN0IHJlcHJlc2VudGluZ1xyXG4gKiB0aGUgZmV0Y2hlZCBtb2R1bGVzLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIHRoZXJlIGlzIGFuIGlzc3VlIHVwZGF0aW5nXHJcbiAqIHRoZSBsb2NhbCBIaWdoY2hhcnRzIGNhY2hlLlxyXG4gKi9cclxuY29uc3QgdXBkYXRlQ2FjaGUgPSBhc3luYyAoY29uZmlnLCBzb3VyY2VQYXRoKSA9PiB7XHJcbiAgY29uc3QgeyBjb3JlU2NyaXB0cywgbW9kdWxlcywgaW5kaWNhdG9ycywgc2NyaXB0czogY3VzdG9tU2NyaXB0cyB9ID0gY29uZmlnO1xyXG4gIGNvbnN0IGhjVmVyc2lvbiA9XHJcbiAgICBjb25maWcudmVyc2lvbiA9PT0gJ2xhdGVzdCcgfHwgIWNvbmZpZy52ZXJzaW9uID8gJycgOiBgJHtjb25maWcudmVyc2lvbn0vYDtcclxuXHJcbiAgbG9nKFxyXG4gICAgMyxcclxuICAgIGBbY2FjaGVdIFVwZGF0aW5nIGNhY2hlIHZlcnNpb24gdG8gSGlnaGNoYXJ0czogJHtoY1ZlcnNpb24gfHwgJ2xhdGVzdCd9LmBcclxuICApO1xyXG5cclxuICAvLyBDb25maWd1cmUgcHJveHkgaWYgZXhpc3RzXHJcbiAgbGV0IHByb3h5QWdlbnQ7XHJcbiAgY29uc3QgcHJveHlIb3N0ID0gcHJvY2Vzcy5lbnZbJ1BST1hZX1NFUlZFUl9IT1NUJ107XHJcbiAgY29uc3QgcHJveHlQb3J0ID0gcHJvY2Vzcy5lbnZbJ1BST1hZX1NFUlZFUl9QT1JUJ107XHJcblxyXG4gIC8vIFRyeSB0byBjcmVhdGUgYSBQcm94eSBBZ2VudFxyXG4gIGlmIChwcm94eUhvc3QgJiYgcHJveHlQb3J0KSB7XHJcbiAgICB0cnkge1xyXG4gICAgICBwcm94eUFnZW50ID0gbmV3IEh0dHBzUHJveHlBZ2VudCh7XHJcbiAgICAgICAgaG9zdDogcHJveHlIb3N0LFxyXG4gICAgICAgIHBvcnQ6ICtwcm94eVBvcnRcclxuICAgICAgfSk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1tjYWNoZV0gQ291bGQgbm90IGNyZWF0ZSBhIFByb3h5IEFnZW50LicpLnNldEVycm9yKFxyXG4gICAgICAgIGVycm9yXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBjb25zdCBmZXRjaGVkTW9kdWxlcyA9IHt9O1xyXG4gIHRyeSB7XHJcbiAgICBjYWNoZS5zb3VyY2VzID0gYXdhaXQgZmV0Y2hTY3JpcHRzKFxyXG4gICAgICBbLi4uY29yZVNjcmlwdHMubWFwKChjKSA9PiBgJHtoY1ZlcnNpb259JHtjfWApXSxcclxuICAgICAgW1xyXG4gICAgICAgIC4uLm1vZHVsZXMubWFwKChtKSA9PlxyXG4gICAgICAgICAgbSA9PT0gJ21hcCdcclxuICAgICAgICAgICAgPyBgbWFwcy8ke2hjVmVyc2lvbn1tb2R1bGVzLyR7bX1gXHJcbiAgICAgICAgICAgIDogYCR7aGNWZXJzaW9ufW1vZHVsZXMvJHttfWBcclxuICAgICAgICApLFxyXG4gICAgICAgIC4uLmluZGljYXRvcnMubWFwKChpKSA9PiBgc3RvY2svJHtoY1ZlcnNpb259aW5kaWNhdG9ycy8ke2l9YClcclxuICAgICAgXSxcclxuICAgICAgY3VzdG9tU2NyaXB0cyxcclxuICAgICAgY29uZmlnLmNkblVSTCB8fCBjYWNoZS5jZG5VUkwsXHJcbiAgICAgIHByb3h5QWdlbnQsXHJcbiAgICAgIGZldGNoZWRNb2R1bGVzXHJcbiAgICApO1xyXG4gICAgZXh0cmFjdFZlcnNpb24oKTtcclxuXHJcbiAgICAvLyBTYXZlIHRoZSBmZXRjaGVkIG1vZHVsZXMgaW50byBjYWNoZXMnIHNvdXJjZSBKU09OXHJcbiAgICB3cml0ZUZpbGVTeW5jKHNvdXJjZVBhdGgsIGNhY2hlLnNvdXJjZXMpO1xyXG4gICAgcmV0dXJuIGZldGNoZWRNb2R1bGVzO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbY2FjaGVdIFVuYWJsZSB0byB1cGRhdGUgdGhlIGxvY2FsIEhpZ2hjaGFydHMgY2FjaGUuJ1xyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIFVwZGF0ZXMgdGhlIEhpZ2hjaGFydHMgdmVyc2lvbiBpbiB0aGUgYXBwbGllZCBjb25maWd1cmF0aW9uIGFuZCBjaGVja3NcclxuICogdGhlIGNhY2hlIGZvciB0aGUgbmV3IHZlcnNpb24uXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBuZXdWZXJzaW9uIC0gVGhlIG5ldyBIaWdoY2hhcnRzIHZlcnNpb24gdG8gYmUgYXBwbGllZC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8KG9iamVjdHxib29sZWFuKT59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIHVwZGF0ZWRcclxuICogY29uZmlndXJhdGlvbiB3aXRoIHRoZSBuZXcgdmVyc2lvbiwgb3IgZmFsc2UgaWYgbm8gYXBwbGllZCBjb25maWd1cmF0aW9uXHJcbiAqIGV4aXN0cy5cclxuICovXHJcbmV4cG9ydCBjb25zdCB1cGRhdGVWZXJzaW9uID0gYXN5bmMgKG5ld1ZlcnNpb24pID0+XHJcbiAgYXBwbGllZENvbmZpZ1xyXG4gICAgPyBhd2FpdCBjaGVja0FuZFVwZGF0ZUNhY2hlKFxyXG4gICAgICAgIE9iamVjdC5hc3NpZ24oYXBwbGllZENvbmZpZywge1xyXG4gICAgICAgICAgdmVyc2lvbjogbmV3VmVyc2lvblxyXG4gICAgICAgIH0pXHJcbiAgICAgIClcclxuICAgIDogZmFsc2U7XHJcblxyXG4vKipcclxuICogQ2hlY2tzIHRoZSBjYWNoZSBmb3IgSGlnaGNoYXJ0cyBkZXBlbmRlbmNpZXMsIHVwZGF0ZXMgdGhlIGNhY2hlIGlmIG5lZWRlZCxcclxuICogYW5kIGxvYWRzIHRoZSBzb3VyY2VzLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnIC0gSGlnaGNoYXJ0cy1yZWxhdGVkIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmcgaW5mb3JtYXRpb25cclxuICogYWJvdXQgc2NyaXB0cyBhbmQgbW9kdWxlcy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgdGhlIGNhY2hlIGlzIGNoZWNrZWRcclxuICogYW5kIHVwZGF0ZWQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgdGhlcmUgaXMgYW4gaXNzdWUgdXBkYXRpbmdcclxuICogb3IgcmVhZGluZyB0aGUgY2FjaGUuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgY2hlY2tBbmRVcGRhdGVDYWNoZSA9IGFzeW5jIChjb25maWcpID0+IHtcclxuICBjb25zdCBjYWNoZVBhdGggPSBqb2luKF9fZGlybmFtZSwgY29uZmlnLmNhY2hlUGF0aCk7XHJcblxyXG4gIGxldCBmZXRjaGVkTW9kdWxlcztcclxuICAvLyBQcmVwYXJlIHBhdGhzIHRvIG1hbmlmZXN0IGFuZCBzb3VyY2VzIGZyb20gdGhlIC5jYWNoZSBmb2xkZXJcclxuICBjb25zdCBtYW5pZmVzdFBhdGggPSBqb2luKGNhY2hlUGF0aCwgJ21hbmlmZXN0Lmpzb24nKTtcclxuICBjb25zdCBzb3VyY2VQYXRoID0gam9pbihjYWNoZVBhdGgsICdzb3VyY2VzLmpzJyk7XHJcblxyXG4gIC8vIFRPRE86IGRlYWwgd2l0aCB0cnlpbmcgdG8gc3dpdGNoIHRvIHRoZSBydW5uaW5nIHZlcnNpb25cclxuICAvLyBjb25zdCBhY3RpdmVWZXJzaW9uID0gYXBwbGllZENvbmZpZyA/IGFwcGxpZWRDb25maWcudmVyc2lvbiA6IGZhbHNlO1xyXG5cclxuICBhcHBsaWVkQ29uZmlnID0gY29uZmlnO1xyXG5cclxuICAvLyBDcmVhdGUgdGhlIGNhY2hlIGRlc3RpbmF0aW9uIGlmIGl0IGRvZXNuJ3QgZXhpc3QgYWxyZWFkeVxyXG4gICFleGlzdHNTeW5jKGNhY2hlUGF0aCkgJiYgbWtkaXJTeW5jKGNhY2hlUGF0aCk7XHJcblxyXG4gIC8vIEZldGNoIGFsbCB0aGUgc2NyaXB0cyBlaXRoZXIgaWYgbWFuaWZlc3QuanNvbiBkb2VzIG5vdCBleGlzdFxyXG4gIC8vIG9yIGlmIHRoZSBmb3JjZUZldGNoIG9wdGlvbiBpcyBlbmFibGVkXHJcbiAgaWYgKCFleGlzdHNTeW5jKG1hbmlmZXN0UGF0aCkgfHwgY29uZmlnLmZvcmNlRmV0Y2gpIHtcclxuICAgIGxvZygzLCAnW2NhY2hlXSBGZXRjaGluZyBhbmQgY2FjaGluZyBIaWdoY2hhcnRzIGRlcGVuZGVuY2llcy4nKTtcclxuICAgIGZldGNoZWRNb2R1bGVzID0gYXdhaXQgdXBkYXRlQ2FjaGUoY29uZmlnLCBzb3VyY2VQYXRoKTtcclxuICB9IGVsc2Uge1xyXG4gICAgbGV0IHJlcXVlc3RVcGRhdGUgPSBmYWxzZTtcclxuXHJcbiAgICAvLyBSZWFkIHRoZSBtYW5pZmVzdCBKU09OXHJcbiAgICBjb25zdCBtYW5pZmVzdCA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKG1hbmlmZXN0UGF0aCkpO1xyXG5cclxuICAgIC8vIENoZWNrIGlmIHRoZSBtb2R1bGVzIGlzIGFuIGFycmF5LCBpZiBzbywgd2UgcmV3cml0ZSBpdCB0byBhIG1hcCB0byBtYWtlXHJcbiAgICAvLyBpdCBlYXNpZXIgdG8gcmVzb2x2ZSBtb2R1bGVzLlxyXG4gICAgaWYgKG1hbmlmZXN0Lm1vZHVsZXMgJiYgQXJyYXkuaXNBcnJheShtYW5pZmVzdC5tb2R1bGVzKSkge1xyXG4gICAgICBjb25zdCBtb2R1bGVNYXAgPSB7fTtcclxuICAgICAgbWFuaWZlc3QubW9kdWxlcy5mb3JFYWNoKChtKSA9PiAobW9kdWxlTWFwW21dID0gMSkpO1xyXG4gICAgICBtYW5pZmVzdC5tb2R1bGVzID0gbW9kdWxlTWFwO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IHsgbW9kdWxlcywgY29yZVNjcmlwdHMsIGluZGljYXRvcnMgfSA9IGNvbmZpZztcclxuICAgIGNvbnN0IG51bWJlck9mTW9kdWxlcyA9XHJcbiAgICAgIG1vZHVsZXMubGVuZ3RoICsgY29yZVNjcmlwdHMubGVuZ3RoICsgaW5kaWNhdG9ycy5sZW5ndGg7XHJcblxyXG4gICAgLy8gQ29tcGFyZSB0aGUgbG9hZGVkIGNvbmZpZyB3aXRoIHRoZSBjb250ZW50cyBpbiBjYWNoZS5cclxuICAgIC8vIElmIHRoZXJlIGFyZSBjaGFuZ2VzLCBmZXRjaCByZXF1ZXN0ZWQgbW9kdWxlcyBhbmQgcHJvZHVjdHMsXHJcbiAgICAvLyBhbmQgYmFrZSB0aGVtIGludG8gYSBnaWFudCBibG9iLiBTYXZlIHRoZSBibG9iLlxyXG4gICAgaWYgKG1hbmlmZXN0LnZlcnNpb24gIT09IGNvbmZpZy52ZXJzaW9uKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICAyLFxyXG4gICAgICAgICdbY2FjaGVdIEEgSGlnaGNoYXJ0cyB2ZXJzaW9uIG1pc21hdGNoIGluIHRoZSBjYWNoZSwgbmVlZCB0byByZS1mZXRjaC4nXHJcbiAgICAgICk7XHJcbiAgICAgIHJlcXVlc3RVcGRhdGUgPSB0cnVlO1xyXG4gICAgfSBlbHNlIGlmIChPYmplY3Qua2V5cyhtYW5pZmVzdC5tb2R1bGVzIHx8IHt9KS5sZW5ndGggIT09IG51bWJlck9mTW9kdWxlcykge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgMixcclxuICAgICAgICAnW2NhY2hlXSBUaGUgY2FjaGUgYW5kIHRoZSByZXF1ZXN0ZWQgbW9kdWxlcyBkbyBub3QgbWF0Y2gsIG5lZWQgdG8gcmUtZmV0Y2guJ1xyXG4gICAgICApO1xyXG4gICAgICByZXF1ZXN0VXBkYXRlID0gdHJ1ZTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIENoZWNrIGVhY2ggbW9kdWxlLCBpZiBhbnl0aGluZyBpcyBtaXNzaW5nIHJlZmV0Y2ggZXZlcnl0aGluZ1xyXG4gICAgICByZXF1ZXN0VXBkYXRlID0gKGNvbmZpZy5tb2R1bGVzIHx8IFtdKS5zb21lKChtb2R1bGVOYW1lKSA9PiB7XHJcbiAgICAgICAgaWYgKCFtYW5pZmVzdC5tb2R1bGVzW21vZHVsZU5hbWVdKSB7XHJcbiAgICAgICAgICBsb2coXHJcbiAgICAgICAgICAgIDIsXHJcbiAgICAgICAgICAgIGBbY2FjaGVdIFRoZSAke21vZHVsZU5hbWV9IGlzIG1pc3NpbmcgaW4gdGhlIGNhY2hlLCBuZWVkIHRvIHJlLWZldGNoLmBcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgICB9XHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChyZXF1ZXN0VXBkYXRlKSB7XHJcbiAgICAgIGZldGNoZWRNb2R1bGVzID0gYXdhaXQgdXBkYXRlQ2FjaGUoY29uZmlnLCBzb3VyY2VQYXRoKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIGxvZygzLCAnW2NhY2hlXSBEZXBlbmRlbmN5IGNhY2hlIGlzIHVwIHRvIGRhdGUsIHByb2NlZWRpbmcuJyk7XHJcblxyXG4gICAgICAvLyBMb2FkIHRoZSBzb3VyY2VzXHJcbiAgICAgIGNhY2hlLnNvdXJjZXMgPSByZWFkRmlsZVN5bmMoc291cmNlUGF0aCwgJ3V0ZjgnKTtcclxuXHJcbiAgICAgIC8vIEdldCBjdXJyZW50IG1vZHVsZXMgbWFwXHJcbiAgICAgIGZldGNoZWRNb2R1bGVzID0gbWFuaWZlc3QubW9kdWxlcztcclxuICAgICAgZXh0cmFjdFZlcnNpb24oKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIEZpbmFsbHksIHNhdmUgdGhlIG5ldyBtYW5pZmVzdCwgd2hpY2ggaXMgYmFzaWNhbGx5IG91ciBjdXJyZW50IGNvbmZpZ1xyXG4gIC8vIGluIGEgc2xpZ2h0bHkgZGlmZmVyZW50IGZvcm1hdFxyXG4gIGF3YWl0IHNhdmVDb25maWdUb01hbmlmZXN0KGNvbmZpZywgZmV0Y2hlZE1vZHVsZXMpO1xyXG59O1xyXG5cclxuZXhwb3J0IGNvbnN0IGdldENhY2hlUGF0aCA9ICgpID0+IHtcclxuICByZXR1cm4gam9pbihfX2Rpcm5hbWUsIGFwcGxpZWRDb25maWcuY2FjaGVQYXRoKTtcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBjaGVja0FuZFVwZGF0ZUNhY2hlLFxyXG4gIGdldENhY2hlUGF0aCxcclxuICB1cGRhdGVWZXJzaW9uLFxyXG4gIGdldENhY2hlOiAoKSA9PiBjYWNoZSxcclxuICBoaWdoY2hhcnRzOiAoKSA9PiBjYWNoZS5zb3VyY2VzLFxyXG4gIHZlcnNpb246ICgpID0+IGNhY2hlLmhjVmVyc2lvblxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IGV4aXN0c1N5bmMsIHJlYWRGaWxlU3luYywgcHJvbWlzZXMgYXMgZnNQcm9taXNlcyB9IGZyb20gJ2ZzJztcclxuXHJcbmltcG9ydCBwcm9tcHRzIGZyb20gJ3Byb21wdHMnO1xyXG5cclxuaW1wb3J0IHtcclxuICBhYnNvbHV0ZVByb3BzLFxyXG4gIGRlZmF1bHRDb25maWcsXHJcbiAgbmVzdGVkQXJncyxcclxuICBwcm9tcHRzQ29uZmlnXHJcbn0gZnJvbSAnLi9zY2hlbWFzL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBkZWVwQ29weSwgaXNPYmplY3QsIHByaW50VXNhZ2UsIHRvQm9vbGVhbiB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxubGV0IGdlbmVyYWxPcHRpb25zID0ge307XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIGFuZCByZXR1cm5zIHRoZSBnZW5lcmFsIG9wdGlvbnMgZm9yIHRoZSBleHBvcnQgcHJvY2Vzcy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIGdlbmVyYWwgb3B0aW9ucyBvYmplY3QuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0T3B0aW9ucyA9ICgpID0+IGdlbmVyYWxPcHRpb25zO1xyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIGFuZCBzZXRzIHRoZSBnZW5lcmFsIG9wdGlvbnMgZm9yIHRoZSBzZXJ2ZXIgaW5zdGFjZSwga2VlcGluZ1xyXG4gKiB0aGUgcHJpbmNpcGxlIG9mIHRoZSBvcHRpb25zIGxvYWQgcHJpb3JpdHkuIEl0IGFjY2VwdHMgb3B0aW9uYWwgdXNlck9wdGlvbnNcclxuICogYW5kIGFyZ3MgZnJvbSB0aGUgQ0xJLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gdXNlck9wdGlvbnMgLSBVc2VyLXByb3ZpZGVkIG9wdGlvbnMgZm9yIGN1c3RvbWl6YXRpb24uXHJcbiAqIEBwYXJhbSB7QXJyYXl9IGFyZ3MgLSBDb21tYW5kLWxpbmUgYXJndW1lbnRzIGZvciBhZGRpdGlvbmFsIGNvbmZpZ3VyYXRpb25cclxuICogKENMSSB1c2FnZSkuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSB1cGRhdGVkIGdlbmVyYWwgb3B0aW9ucyBvYmplY3QuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2V0T3B0aW9ucyA9ICh1c2VyT3B0aW9ucywgYXJncykgPT4ge1xyXG4gIC8vIE9ubHkgZm9yIHRoZSBDTEkgdXNhZ2VcclxuICBpZiAoYXJncz8ubGVuZ3RoKSB7XHJcbiAgICAvLyBHZXQgdGhlIGFkZGl0aW9uYWwgb3B0aW9ucyBmcm9tIHRoZSBjdXN0b20gSlNPTiBmaWxlXHJcbiAgICBnZW5lcmFsT3B0aW9ucyA9IGxvYWRDb25maWdGaWxlKGFyZ3MpO1xyXG4gIH1cclxuXHJcbiAgLy8gVXBkYXRlIHRoZSBkZWZhdWx0IGNvbmZpZyB3aXRoIGEgY29ycmVjdCBvcHRpb24gdmFsdWVzXHJcbiAgdXBkYXRlRGVmYXVsdENvbmZpZyhkZWZhdWx0Q29uZmlnLCBnZW5lcmFsT3B0aW9ucyk7XHJcblxyXG4gIC8vIFNldCB2YWx1ZXMgZm9yIHNlcnZlcidzIG9wdGlvbnMgYW5kIHJldHVybnMgdGhlbVxyXG4gIGdlbmVyYWxPcHRpb25zID0gaW5pdE9wdGlvbnMoZGVmYXVsdENvbmZpZyk7XHJcblxyXG4gIC8vIEFwcGx5IHVzZXIgb3B0aW9ucyBpZiB0aGVyZSBhcmUgYW55XHJcbiAgaWYgKHVzZXJPcHRpb25zKSB7XHJcbiAgICAvLyBNZXJnZSB1c2VyIG9wdGlvbnNcclxuICAgIGdlbmVyYWxPcHRpb25zID0gbWVyZ2VDb25maWdPcHRpb25zKFxyXG4gICAgICBnZW5lcmFsT3B0aW9ucyxcclxuICAgICAgdXNlck9wdGlvbnMsXHJcbiAgICAgIGFic29sdXRlUHJvcHNcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICAvLyBPbmx5IGZvciB0aGUgQ0xJIHVzYWdlXHJcbiAgaWYgKGFyZ3M/Lmxlbmd0aCkge1xyXG4gICAgLy8gUGFpciBwcm92aWRlZCBhcmd1bWVudHNcclxuICAgIGdlbmVyYWxPcHRpb25zID0gcGFpckFyZ3VtZW50VmFsdWUoZ2VuZXJhbE9wdGlvbnMsIGFyZ3MsIGRlZmF1bHRDb25maWcpO1xyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIGZpbmFsIGdlbmVyYWwgb3B0aW9uc1xyXG4gIHJldHVybiBnZW5lcmFsT3B0aW9ucztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBBbGxvd3MgbWFudWFsIGNvbmZpZ3VyYXRpb24gYmFzZWQgb24gc3BlY2lmaWVkIHByb21wdHMgYW5kIHNhdmVzXHJcbiAqIHRoZSBjb25maWd1cmF0aW9uIHRvIGEgZmlsZS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGNvbmZpZ0ZpbGVOYW1lIC0gVGhlIG5hbWUgb2YgdGhlIGNvbmZpZ3VyYXRpb24gZmlsZS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8Ym9vbGVhbj59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRydWUgb25jZSB0aGUgbWFudWFsXHJcbiAqIGNvbmZpZ3VyYXRpb24gaXMgY29tcGxldGVkIGFuZCBzYXZlZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBtYW51YWxDb25maWcgPSBhc3luYyAoY29uZmlnRmlsZU5hbWUpID0+IHtcclxuICAvLyBQcmVwYXJlIGEgY29uZmlnIG9iamVjdFxyXG4gIGxldCBjb25maWdGaWxlID0ge307XHJcblxyXG4gIC8vIENoZWNrIGlmIHByb3ZpZGVkIGNvbmZpZyBmaWxlIGV4aXN0c1xyXG4gIGlmIChleGlzdHNTeW5jKGNvbmZpZ0ZpbGVOYW1lKSkge1xyXG4gICAgY29uZmlnRmlsZSA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKGNvbmZpZ0ZpbGVOYW1lLCAndXRmOCcpKTtcclxuICB9XHJcblxyXG4gIC8vIFF1ZXN0aW9uIGFib3V0IGEgY29uZmlndXJhdGlvbiBjYXRlZ29yeVxyXG4gIGNvbnN0IG9uU3VibWl0ID0gYXN5bmMgKHAsIGNhdGVnb3JpZXMpID0+IHtcclxuICAgIGxldCBxdWVzdGlvbnNDb3VudGVyID0gMDtcclxuICAgIGxldCBhbGxRdWVzdGlvbnMgPSBbXTtcclxuXHJcbiAgICAvLyBDcmVhdGUgYSBjb3JyZXNwb25kaW5nIHByb3BlcnR5IGluIHRoZSBtYW51YWxDb25maWcgb2JqZWN0XHJcbiAgICBmb3IgKGNvbnN0IHNlY3Rpb24gb2YgY2F0ZWdvcmllcykge1xyXG4gICAgICAvLyBNYXJrIGVhY2ggb3B0aW9uIHdpdGggYSBzZWN0aW9uXHJcbiAgICAgIHByb21wdHNDb25maWdbc2VjdGlvbl0gPSBwcm9tcHRzQ29uZmlnW3NlY3Rpb25dLm1hcCgob3B0aW9uKSA9PiAoe1xyXG4gICAgICAgIC4uLm9wdGlvbixcclxuICAgICAgICBzZWN0aW9uXHJcbiAgICAgIH0pKTtcclxuXHJcbiAgICAgIC8vIENvbGxlY3QgdGhlIHF1ZXN0aW9uc1xyXG4gICAgICBhbGxRdWVzdGlvbnMgPSBbLi4uYWxsUXVlc3Rpb25zLCAuLi5wcm9tcHRzQ29uZmlnW3NlY3Rpb25dXTtcclxuICAgIH1cclxuXHJcbiAgICBhd2FpdCBwcm9tcHRzKGFsbFF1ZXN0aW9ucywge1xyXG4gICAgICBvblN1Ym1pdDogYXN5bmMgKHByb21wdCwgYW5zd2VyKSA9PiB7XHJcbiAgICAgICAgLy8gR2V0IHRoZSBkZWZhdWx0IG1vZHVsZXNcclxuICAgICAgICBpZiAocHJvbXB0Lm5hbWUgPT09ICdtb2R1bGVzJykge1xyXG4gICAgICAgICAgYW5zd2VyID0gYW5zd2VyLmxlbmd0aFxyXG4gICAgICAgICAgICA/IGFuc3dlci5tYXAoKG1vZHVsZSkgPT4gcHJvbXB0LmNob2ljZXNbbW9kdWxlXSlcclxuICAgICAgICAgICAgOiBwcm9tcHQuY2hvaWNlcztcclxuXHJcbiAgICAgICAgICBjb25maWdGaWxlW3Byb21wdC5zZWN0aW9uXVtwcm9tcHQubmFtZV0gPSBhbnN3ZXI7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIGNvbmZpZ0ZpbGVbcHJvbXB0LnNlY3Rpb25dID0gcmVjdXJzaXZlUHJvcHMoXHJcbiAgICAgICAgICAgIE9iamVjdC5hc3NpZ24oe30sIGNvbmZpZ0ZpbGVbcHJvbXB0LnNlY3Rpb25dIHx8IHt9KSxcclxuICAgICAgICAgICAgcHJvbXB0Lm5hbWUuc3BsaXQoJy4nKSxcclxuICAgICAgICAgICAgcHJvbXB0LmNob2ljZXMgPyBwcm9tcHQuY2hvaWNlc1thbnN3ZXJdIDogYW5zd2VyXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgaWYgKCsrcXVlc3Rpb25zQ291bnRlciA9PT0gYWxsUXVlc3Rpb25zLmxlbmd0aCkge1xyXG4gICAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgYXdhaXQgZnNQcm9taXNlcy53cml0ZUZpbGUoXHJcbiAgICAgICAgICAgICAgY29uZmlnRmlsZU5hbWUsXHJcbiAgICAgICAgICAgICAgSlNPTi5zdHJpbmdpZnkoY29uZmlnRmlsZSwgbnVsbCwgMiksXHJcbiAgICAgICAgICAgICAgJ3V0ZjgnXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgICAgICAgMSxcclxuICAgICAgICAgICAgICBlcnJvcixcclxuICAgICAgICAgICAgICBgW2NvbmZpZ10gQW4gZXJyb3Igb2NjdXJyZWQgd2hpbGUgY3JlYXRpbmcgdGhlICR7Y29uZmlnRmlsZU5hbWV9IGZpbGUuYFxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9KTtcclxuXHJcbiAgICByZXR1cm4gdHJ1ZTtcclxuICB9O1xyXG5cclxuICAvLyBGaW5kIHRoZSBjYXRlZ29yaWVzXHJcbiAgY29uc3QgY2hvaWNlcyA9IE9iamVjdC5rZXlzKHByb21wdHNDb25maWcpLm1hcCgoY2hvaWNlKSA9PiAoe1xyXG4gICAgdGl0bGU6IGAke2Nob2ljZX0gb3B0aW9uc2AsXHJcbiAgICB2YWx1ZTogY2hvaWNlXHJcbiAgfSkpO1xyXG5cclxuICAvLyBDYXRlZ29yeSBwcm9tcHRcclxuICByZXR1cm4gcHJvbXB0cyhcclxuICAgIHtcclxuICAgICAgdHlwZTogJ211bHRpc2VsZWN0JyxcclxuICAgICAgbmFtZTogJ2NhdGVnb3J5JyxcclxuICAgICAgbWVzc2FnZTogJ1doaWNoIGNhdGVnb3J5IGRvIHlvdSB3YW50IHRvIGNvbmZpZ3VyZT8nLFxyXG4gICAgICBoaW50OiAnU3BhY2U6IFNlbGVjdCBzcGVjaWZpYywgQTogU2VsZWN0IGFsbCwgRW50ZXI6IENvbmZpcm0uJyxcclxuICAgICAgaW5zdHJ1Y3Rpb25zOiAnJyxcclxuICAgICAgY2hvaWNlc1xyXG4gICAgfSxcclxuICAgIHsgb25TdWJtaXQgfVxyXG4gICk7XHJcbn07XHJcblxyXG4vKipcclxuICogTWFwcyBvbGQtc3RydWN0dXJlZCAoUGhhbnRvbUpTKSBvcHRpb25zIHRvIGEgbmV3IGNvbmZpZ3VyYXRpb24gZm9ybWF0XHJcbiAqIChQdXBwZXRlZXIpLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb2xkT3B0aW9ucyAtIE9sZC1zdHJ1Y3R1cmVkIG9wdGlvbnMgdG8gYmUgbWFwcGVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBOZXcgb3B0aW9ucyBzdHJ1Y3R1cmVkIGJhc2VkIG9uIHRoZSBkZWZpbmVkIG5lc3RlZEFyZ3NcclxuICogbWFwcGluZy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBtYXBUb05ld0NvbmZpZyA9IChvbGRPcHRpb25zKSA9PiB7XHJcbiAgY29uc3QgbmV3T3B0aW9ucyA9IHt9O1xyXG4gIC8vIEN5Y2xlIHRocm91Z2ggb2xkLXN0cnVjdHVyZWQgb3B0aW9uc1xyXG4gIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKG9sZE9wdGlvbnMpKSB7XHJcbiAgICBjb25zdCBwcm9wZXJ0aWVzQ2hhaW4gPSBuZXN0ZWRBcmdzW2tleV0gPyBuZXN0ZWRBcmdzW2tleV0uc3BsaXQoJy4nKSA6IFtdO1xyXG5cclxuICAgIC8vIFBvcHVsYXRlIG9iamVjdCBpbiBjb3JyZWN0IHByb3BlcnRpZXMgbGV2ZWxzXHJcbiAgICBwcm9wZXJ0aWVzQ2hhaW4ucmVkdWNlKFxyXG4gICAgICAob2JqLCBwcm9wLCBpbmRleCkgPT5cclxuICAgICAgICAob2JqW3Byb3BdID1cclxuICAgICAgICAgIHByb3BlcnRpZXNDaGFpbi5sZW5ndGggLSAxID09PSBpbmRleCA/IHZhbHVlIDogb2JqW3Byb3BdIHx8IHt9KSxcclxuICAgICAgbmV3T3B0aW9uc1xyXG4gICAgKTtcclxuICB9XHJcbiAgcmV0dXJuIG5ld09wdGlvbnM7XHJcbn07XHJcblxyXG4vKipcclxuICogTWVyZ2VzIHR3byBzZXRzIG9mIGNvbmZpZ3VyYXRpb24gb3B0aW9ucywgY29uc2lkZXJpbmcgYWJzb2x1dGUgcHJvcGVydGllcy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBPcmlnaW5hbCBjb25maWd1cmF0aW9uIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBuZXdPcHRpb25zIC0gTmV3IGNvbmZpZ3VyYXRpb24gb3B0aW9ucyB0byBiZSBtZXJnZWQuXHJcbiAqIEBwYXJhbSB7QXJyYXl9IGFic29sdXRlUHJvcHMgLSBMaXN0IG9mIHByb3BlcnRpZXMgdGhhdCBzaG91bGRcclxuICogbm90IGJlIHJlY3Vyc2l2ZWx5IG1lcmdlZC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gTWVyZ2VkIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBtZXJnZUNvbmZpZ09wdGlvbnMgPSAob3B0aW9ucywgbmV3T3B0aW9ucywgYWJzb2x1dGVQcm9wcyA9IFtdKSA9PiB7XHJcbiAgY29uc3QgbWVyZ2VkT3B0aW9ucyA9IGRlZXBDb3B5KG9wdGlvbnMpO1xyXG5cclxuICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhuZXdPcHRpb25zKSkge1xyXG4gICAgbWVyZ2VkT3B0aW9uc1trZXldID1cclxuICAgICAgaXNPYmplY3QodmFsdWUpICYmXHJcbiAgICAgICFhYnNvbHV0ZVByb3BzLmluY2x1ZGVzKGtleSkgJiZcclxuICAgICAgbWVyZ2VkT3B0aW9uc1trZXldICE9PSB1bmRlZmluZWRcclxuICAgICAgICA/IG1lcmdlQ29uZmlnT3B0aW9ucyhtZXJnZWRPcHRpb25zW2tleV0sIHZhbHVlLCBhYnNvbHV0ZVByb3BzKVxyXG4gICAgICAgIDogdmFsdWUgIT09IHVuZGVmaW5lZFxyXG4gICAgICAgICAgPyB2YWx1ZVxyXG4gICAgICAgICAgOiBtZXJnZWRPcHRpb25zW2tleV07XHJcbiAgfVxyXG5cclxuICByZXR1cm4gbWVyZ2VkT3B0aW9ucztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyBleHBvcnQgc2V0dGluZ3MgYmFzZWQgb24gcHJvdmlkZWQgZXhwb3J0T3B0aW9uc1xyXG4gKiBhbmQgZ2VuZXJhbE9wdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBleHBvcnRPcHRpb25zIC0gT3B0aW9ucyBzcGVjaWZpYyB0byB0aGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBnZW5lcmFsT3B0aW9ucyAtIEdlbmVyYWwgY29uZmlndXJhdGlvbiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBJbml0aWFsaXplZCBleHBvcnQgc2V0dGluZ3MuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaW5pdEV4cG9ydFNldHRpbmdzID0gKGV4cG9ydE9wdGlvbnMsIGdlbmVyYWxPcHRpb25zID0ge30pID0+IHtcclxuICBsZXQgb3B0aW9ucyA9IHt9O1xyXG5cclxuICBpZiAoZXhwb3J0T3B0aW9ucy5zdmcpIHtcclxuICAgIG9wdGlvbnMgPSBkZWVwQ29weShnZW5lcmFsT3B0aW9ucyk7XHJcbiAgICBvcHRpb25zLmV4cG9ydC50eXBlID0gZXhwb3J0T3B0aW9ucy50eXBlIHx8IGV4cG9ydE9wdGlvbnMuZXhwb3J0LnR5cGU7XHJcbiAgICBvcHRpb25zLmV4cG9ydC5zY2FsZSA9IGV4cG9ydE9wdGlvbnMuc2NhbGUgfHwgZXhwb3J0T3B0aW9ucy5leHBvcnQuc2NhbGU7XHJcbiAgICBvcHRpb25zLmV4cG9ydC5vdXRmaWxlID1cclxuICAgICAgZXhwb3J0T3B0aW9ucy5vdXRmaWxlIHx8IGV4cG9ydE9wdGlvbnMuZXhwb3J0Lm91dGZpbGU7XHJcbiAgICBvcHRpb25zLnBheWxvYWQgPSB7XHJcbiAgICAgIHN2ZzogZXhwb3J0T3B0aW9ucy5zdmdcclxuICAgIH07XHJcbiAgfSBlbHNlIHtcclxuICAgIG9wdGlvbnMgPSBtZXJnZUNvbmZpZ09wdGlvbnMoXHJcbiAgICAgIGdlbmVyYWxPcHRpb25zLFxyXG4gICAgICBleHBvcnRPcHRpb25zLFxyXG4gICAgICAvLyBPbWl0IGdvaW5nIGRvd24gcmVjdXJzaXZlbHkgd2l0aCB0aGUgYmVsb3dzXHJcbiAgICAgIGFic29sdXRlUHJvcHNcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICBvcHRpb25zLmV4cG9ydC5vdXRmaWxlID1cclxuICAgIG9wdGlvbnMuZXhwb3J0Py5vdXRmaWxlIHx8IGBjaGFydC4ke29wdGlvbnMuZXhwb3J0Py50eXBlIHx8ICdwbmcnfWA7XHJcbiAgcmV0dXJuIG9wdGlvbnM7XHJcbn07XHJcblxyXG4vKipcclxuICogTG9hZHMgYWRkaXRpb25hbCBjb25maWd1cmF0aW9uIGZyb20gYSBzcGVjaWZpZWQgZmlsZSB1c2luZ1xyXG4gKiB0aGUgLS1sb2FkQ29uZmlnIG9wdGlvbi5cclxuICpcclxuICogQHBhcmFtIHtBcnJheX0gYXJncyAtIENvbW1hbmQtbGluZSBhcmd1bWVudHMgdG8gY2hlY2sgZm9yXHJcbiAqIHRoZSAtLWxvYWRDb25maWcgb3B0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBBZGRpdGlvbmFsIGNvbmZpZ3VyYXRpb24gbG9hZGVkIGZyb20gdGhlIHNwZWNpZmllZCBmaWxlLFxyXG4gKiBvciBhbiBlbXB0eSBvYmplY3QgaWYgbm90IGZvdW5kIG9yIGludmFsaWQuXHJcbiAqL1xyXG5mdW5jdGlvbiBsb2FkQ29uZmlnRmlsZShhcmdzKSB7XHJcbiAgLy8gQ2hlY2sgaWYgdGhlIC0tbG9hZENvbmZpZyBvcHRpb24gd2FzIHVzZWRcclxuICBjb25zdCBjb25maWdJbmRleCA9IGFyZ3MuZmluZEluZGV4KFxyXG4gICAgKGFyZykgPT4gYXJnLnJlcGxhY2UoLy0vZywgJycpID09PSAnbG9hZENvbmZpZydcclxuICApO1xyXG5cclxuICAvLyBDaGVjayBpZiB0aGUgLS1sb2FkQ29uZmlnIGhhcyBhIHZhbHVlXHJcbiAgaWYgKGNvbmZpZ0luZGV4ID4gLTEgJiYgYXJnc1tjb25maWdJbmRleCArIDFdKSB7XHJcbiAgICBjb25zdCBmaWxlTmFtZSA9IGFyZ3NbY29uZmlnSW5kZXggKyAxXTtcclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIENoZWNrIGlmIGFuIGFkZGl0aW9uYWwgY29uZmlnIGZpbGUgaXMgYSBjb3JyZWN0IEpTT04gZmlsZVxyXG4gICAgICBpZiAoZmlsZU5hbWUgJiYgZmlsZU5hbWUuZW5kc1dpdGgoJy5qc29uJykpIHtcclxuICAgICAgICAvLyBMb2FkIGFuIG9wdGlvbmFsIGN1c3RvbSBKU09OIGNvbmZpZyBmaWxlXHJcbiAgICAgICAgcmV0dXJuIEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKGZpbGVOYW1lKSk7XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAyLFxyXG4gICAgICAgIGVycm9yLFxyXG4gICAgICAgIGBbY29uZmlnXSBVbmFibGUgdG8gbG9hZCB0aGUgY29uZmlndXJhdGlvbiBmcm9tIHRoZSAke2ZpbGVOYW1lfSBmaWxlLmBcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIE5vIGFkZGl0aW9uYWwgb3B0aW9ucyB0byByZXR1cm5cclxuICByZXR1cm4ge307XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBVcGRhdGVzIHRoZSBkZWZhdWx0IGNvbmZpZ3VyYXRpb24gb2JqZWN0IHdpdGggdmFsdWVzIGZyb20gYSBjdXN0b20gb2JqZWN0XHJcbiAqIGFuZCBlbnZpcm9ubWVudCB2YXJpYWJsZXMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjb25maWdPYmogLSBUaGUgZGVmYXVsdCBjb25maWd1cmF0aW9uIG9iamVjdC5cclxuICogQHBhcmFtIHtPYmplY3R9IGN1c3RvbU9iaiAtIEN1c3RvbSBjb25maWd1cmF0aW9uIG9iamVjdCB0byBvdmVycmlkZSBkZWZhdWx0cy5cclxuICogQHBhcmFtIHtzdHJpbmd9IHByb3BDaGFpbiAtIFByb3BlcnR5IGNoYWluIGZvciB0cmFja2luZyBuZXN0ZWQgcHJvcGVydGllc1xyXG4gKiBkdXJpbmcgcmVjdXJzaW9uLlxyXG4gKi9cclxuZnVuY3Rpb24gdXBkYXRlRGVmYXVsdENvbmZpZyhjb25maWdPYmosIGN1c3RvbU9iaiA9IHt9LCBwcm9wQ2hhaW4gPSAnJykge1xyXG4gIE9iamVjdC5rZXlzKGNvbmZpZ09iaikuZm9yRWFjaCgoa2V5KSA9PiB7XHJcbiAgICBjb25zdCBlbnRyeSA9IGNvbmZpZ09ialtrZXldO1xyXG4gICAgY29uc3QgY3VzdG9tVmFsdWUgPSBjdXN0b21PYmogJiYgY3VzdG9tT2JqW2tleV07XHJcbiAgICBsZXQgbnVtRW52VmFsO1xyXG5cclxuICAgIGlmICh0eXBlb2YgZW50cnkudmFsdWUgPT09ICd1bmRlZmluZWQnKSB7XHJcbiAgICAgIHVwZGF0ZURlZmF1bHRDb25maWcoZW50cnksIGN1c3RvbVZhbHVlLCBgJHtwcm9wQ2hhaW59LiR7a2V5fWApO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gSWYgYSB2YWx1ZSBmcm9tIGEgY3VzdG9tIEpTT04gZXhpc3RzLCBpdCB0YWtlIHByZWNlZGVuY2VcclxuICAgICAgaWYgKGN1c3RvbVZhbHVlICE9PSB1bmRlZmluZWQpIHtcclxuICAgICAgICBlbnRyeS52YWx1ZSA9IGN1c3RvbVZhbHVlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBJZiBhIHZhbHVlIGZyb20gYW4gZW52IHZhcmlhYmxlIGV4aXN0cywgaXQgdGFrZSBwcmVjZWRlbmNlXHJcbiAgICAgIGlmIChlbnRyeS5lbnZMaW5rKSB7XHJcbiAgICAgICAgLy8gTG9hZCB0aGUgZW52IHZhclxyXG4gICAgICAgIGlmIChlbnRyeS50eXBlID09PSAnYm9vbGVhbicpIHtcclxuICAgICAgICAgIGVudHJ5LnZhbHVlID0gdG9Cb29sZWFuKFxyXG4gICAgICAgICAgICBbcHJvY2Vzcy5lbnZbZW50cnkuZW52TGlua10sIGVudHJ5LnZhbHVlXS5maW5kKFxyXG4gICAgICAgICAgICAgIChlbCkgPT4gZWwgfHwgZWwgPT09ICdmYWxzZSdcclxuICAgICAgICAgICAgKVxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9IGVsc2UgaWYgKGVudHJ5LnR5cGUgPT09ICdudW1iZXInKSB7XHJcbiAgICAgICAgICBudW1FbnZWYWwgPSArcHJvY2Vzcy5lbnZbZW50cnkuZW52TGlua107XHJcbiAgICAgICAgICBlbnRyeS52YWx1ZSA9IG51bUVudlZhbCA+PSAwID8gbnVtRW52VmFsIDogZW50cnkudmFsdWU7XHJcbiAgICAgICAgfSBlbHNlIGlmIChlbnRyeS50eXBlLmluZGV4T2YoJ10nKSA+PSAwICYmIHByb2Nlc3MuZW52W2VudHJ5LmVudkxpbmtdKSB7XHJcbiAgICAgICAgICBlbnRyeS52YWx1ZSA9IHByb2Nlc3MuZW52W2VudHJ5LmVudkxpbmtdLnNwbGl0KCcsJyk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIGVudHJ5LnZhbHVlID0gcHJvY2Vzcy5lbnZbZW50cnkuZW52TGlua10gfHwgZW50cnkudmFsdWU7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyBvcHRpb25zIG9iamVjdCBiYXNlZCBvbiBwcm92aWRlZCBpdGVtcywgc2V0dGluZyB2YWx1ZXMgZnJvbVxyXG4gKiBuZXN0ZWQgcHJvcGVydGllcyByZWN1cnNpdmVseS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGl0ZW1zIC0gQ29uZmlndXJhdGlvbiBpdGVtcyB0byBiZSB1c2VkIGZvciBpbml0aWFsaXppbmdcclxuICogb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gSW5pdGlhbGl6ZWQgb3B0aW9ucyBvYmplY3QuXHJcbiAqL1xyXG5mdW5jdGlvbiBpbml0T3B0aW9ucyhpdGVtcykge1xyXG4gIGxldCBvcHRpb25zID0ge307XHJcbiAgZm9yIChjb25zdCBbbmFtZSwgaXRlbV0gb2YgT2JqZWN0LmVudHJpZXMoaXRlbXMpKSB7XHJcbiAgICBvcHRpb25zW25hbWVdID0gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGl0ZW0sICd2YWx1ZScpXHJcbiAgICAgID8gaXRlbS52YWx1ZVxyXG4gICAgICA6IGluaXRPcHRpb25zKGl0ZW0pO1xyXG4gIH1cclxuICByZXR1cm4gb3B0aW9ucztcclxufVxyXG5cclxuLyoqXHJcbiAqIFBhaXJzIGFyZ3VtZW50IHZhbHVlcyB3aXRoIGNvcnJlc3BvbmRpbmcgb3B0aW9ucyBpbiB0aGUgY29uZmlndXJhdGlvbixcclxuICogdXBkYXRpbmcgdGhlIG9wdGlvbnMgb2JqZWN0LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIENvbmZpZ3VyYXRpb24gb3B0aW9ucyBvYmplY3QgdG8gYmUgdXBkYXRlZC5cclxuICogQHBhcmFtIHtBcnJheX0gYXJncyAtIENvbW1hbmQtbGluZSBhcmd1bWVudHMgY29udGFpbmluZyB2YWx1ZXMgZm9yIHNwZWNpZmljXHJcbiAqIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBkZWZhdWx0Q29uZmlnIC0gRGVmYXVsdCBjb25maWd1cmF0aW9uIG9iamVjdCBmb3IgcmVmZXJlbmNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBVcGRhdGVkIG9wdGlvbnMgb2JqZWN0LlxyXG4gKi9cclxuZnVuY3Rpb24gcGFpckFyZ3VtZW50VmFsdWUob3B0aW9ucywgYXJncywgZGVmYXVsdENvbmZpZykge1xyXG4gIGxldCBzaG93VXNhZ2UgPSBmYWxzZTtcclxuICBmb3IgKGxldCBpID0gMDsgaSA8IGFyZ3MubGVuZ3RoOyBpKyspIHtcclxuICAgIGNvbnN0IG9wdGlvbiA9IGFyZ3NbaV0ucmVwbGFjZSgvLS9nLCAnJyk7XHJcblxyXG4gICAgLy8gRmluZCB0aGUgcmlnaHQgcGxhY2UgZm9yIHByb3BlcnR5J3MgdmFsdWVcclxuICAgIGNvbnN0IHByb3BlcnRpZXNDaGFpbiA9IG5lc3RlZEFyZ3Nbb3B0aW9uXVxyXG4gICAgICA/IG5lc3RlZEFyZ3Nbb3B0aW9uXS5zcGxpdCgnLicpXHJcbiAgICAgIDogW107XHJcblxyXG4gICAgLy8gR2V0IHRoZSBjb3JyZWN0IHR5cGUgZm9yIENMSSBhcmdzIHdoaWNoIGFyZSBwYXNzZWQgYXMgc3RyaW5nc1xyXG4gICAgbGV0IGFyZ3VtZW50VHlwZTtcclxuICAgIHByb3BlcnRpZXNDaGFpbi5yZWR1Y2UoKG9iaiwgcHJvcCwgaW5kZXgpID0+IHtcclxuICAgICAgaWYgKHByb3BlcnRpZXNDaGFpbi5sZW5ndGggLSAxID09PSBpbmRleCkge1xyXG4gICAgICAgIGFyZ3VtZW50VHlwZSA9IG9ialtwcm9wXS50eXBlO1xyXG4gICAgICB9XHJcbiAgICAgIHJldHVybiBvYmpbcHJvcF07XHJcbiAgICB9LCBkZWZhdWx0Q29uZmlnKTtcclxuXHJcbiAgICBwcm9wZXJ0aWVzQ2hhaW4ucmVkdWNlKChvYmosIHByb3AsIGluZGV4KSA9PiB7XHJcbiAgICAgIGlmIChwcm9wZXJ0aWVzQ2hhaW4ubGVuZ3RoIC0gMSA9PT0gaW5kZXgpIHtcclxuICAgICAgICAvLyBGaW5kcyBhbiBvcHRpb24gYW5kIHNldCBhIGNvcnJlc3BvbmRpbmcgdmFsdWVcclxuICAgICAgICBpZiAodHlwZW9mIG9ialtwcm9wXSAhPT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgICAgIGlmIChhcmdzWysraV0pIHtcclxuICAgICAgICAgICAgaWYgKGFyZ3VtZW50VHlwZSA9PT0gJ2Jvb2xlYW4nKSB7XHJcbiAgICAgICAgICAgICAgb2JqW3Byb3BdID0gdG9Cb29sZWFuKGFyZ3NbaV0pO1xyXG4gICAgICAgICAgICB9IGVsc2UgaWYgKGFyZ3VtZW50VHlwZSA9PT0gJ251bWJlcicpIHtcclxuICAgICAgICAgICAgICBvYmpbcHJvcF0gPSArYXJnc1tpXTtcclxuICAgICAgICAgICAgfSBlbHNlIGlmIChhcmd1bWVudFR5cGUuaW5kZXhPZignXScpID49IDApIHtcclxuICAgICAgICAgICAgICBvYmpbcHJvcF0gPSBhcmdzW2ldLnNwbGl0KCcsJyk7XHJcbiAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgb2JqW3Byb3BdID0gYXJnc1tpXTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgbG9nKFxyXG4gICAgICAgICAgICAgIDIsXHJcbiAgICAgICAgICAgICAgYFtjb25maWddIE1pc3NpbmcgdmFsdWUgZm9yIHRoZSAnJHtvcHRpb259JyBhcmd1bWVudC4gVXNpbmcgdGhlIGRlZmF1bHQgdmFsdWUuYFxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgICBzaG93VXNhZ2UgPSB0cnVlO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gb2JqW3Byb3BdO1xyXG4gICAgfSwgb3B0aW9ucyk7XHJcbiAgfVxyXG5cclxuICAvLyBEaXNwbGF5IHRoZSB1c2FnZSBmb3IgdGhlIHJlZmVyZW5jZSBpZiBuZWVkZWRcclxuICBpZiAoc2hvd1VzYWdlKSB7XHJcbiAgICBwcmludFVzYWdlKGRlZmF1bHRDb25maWcpO1xyXG4gIH1cclxuXHJcbiAgcmV0dXJuIG9wdGlvbnM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZWN1cnNpdmVseSB1cGRhdGVzIHByb3BlcnRpZXMgaW4gYW4gb2JqZWN0IGJhc2VkIG9uIG5lc3RlZCBuYW1lcyBhbmQgYXNzaWduc1xyXG4gKiB0aGUgZmluYWwgdmFsdWUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvYmplY3RUb1VwZGF0ZSAtIFRoZSBvYmplY3QgdG8gYmUgdXBkYXRlZC5cclxuICogQHBhcmFtIHtBcnJheX0gbmVzdGVkTmFtZXMgLSBBcnJheSBvZiBuZXN0ZWQgcHJvcGVydHkgbmFtZXMuXHJcbiAqIEBwYXJhbSB7YW55fSB2YWx1ZSAtIFRoZSBmaW5hbCB2YWx1ZSB0byBiZSBhc3NpZ25lZC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVXBkYXRlZCBvYmplY3Qgd2l0aCBhc3NpZ25lZCB2YWx1ZXMuXHJcbiAqL1xyXG5mdW5jdGlvbiByZWN1cnNpdmVQcm9wcyhvYmplY3RUb1VwZGF0ZSwgbmVzdGVkTmFtZXMsIHZhbHVlKSB7XHJcbiAgd2hpbGUgKG5lc3RlZE5hbWVzLmxlbmd0aCA+IDEpIHtcclxuICAgIGNvbnN0IHByb3BOYW1lID0gbmVzdGVkTmFtZXMuc2hpZnQoKTtcclxuXHJcbiAgICAvLyBDcmVhdGUgYSBwcm9wZXJ0eSBpbiBvYmplY3QgaWYgaXQgZG9lc24ndCBleGlzdFxyXG4gICAgaWYgKCFPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob2JqZWN0VG9VcGRhdGUsIHByb3BOYW1lKSkge1xyXG4gICAgICBvYmplY3RUb1VwZGF0ZVtwcm9wTmFtZV0gPSB7fTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBDYWxsIGZ1bmN0aW9uIGFnYWluIGlmIHRoZXJlIHN0aWxsIG5hbWVzIHRvIGdvXHJcbiAgICBvYmplY3RUb1VwZGF0ZVtwcm9wTmFtZV0gPSByZWN1cnNpdmVQcm9wcyhcclxuICAgICAgT2JqZWN0LmFzc2lnbih7fSwgb2JqZWN0VG9VcGRhdGVbcHJvcE5hbWVdKSxcclxuICAgICAgbmVzdGVkTmFtZXMsXHJcbiAgICAgIHZhbHVlXHJcbiAgICApO1xyXG5cclxuICAgIHJldHVybiBvYmplY3RUb1VwZGF0ZTtcclxuICB9XHJcblxyXG4gIC8vIEFzc2lnbiB0aGUgZmluYWwgdmFsdWVcclxuICBvYmplY3RUb1VwZGF0ZVtuZXN0ZWROYW1lc1swXV0gPSB2YWx1ZTtcclxuICByZXR1cm4gb2JqZWN0VG9VcGRhdGU7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBnZXRPcHRpb25zLFxyXG4gIHNldE9wdGlvbnMsXHJcbiAgbWFudWFsQ29uZmlnLFxyXG4gIG1hcFRvTmV3Q29uZmlnLFxyXG4gIG1lcmdlQ29uZmlnT3B0aW9ucyxcclxuICBpbml0RXhwb3J0U2V0dGluZ3NcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgZnMgZnJvbSAnZnMnO1xyXG5pbXBvcnQgKiBhcyB1cmwgZnJvbSAndXJsJztcclxuaW1wb3J0IHBhdGggZnJvbSAnbm9kZTpwYXRoJztcclxuXHJcbmltcG9ydCBwdXBwZXRlZXIgZnJvbSAncHVwcGV0ZWVyJztcclxuXHJcbi8vIFdvcmthcm91bmQgZm9yIGh0dHBzOi8vYnVncy5jaHJvbWl1bS5vcmcvcC9jaHJvbWl1bS9pc3N1ZXMvZGV0YWlsP2lkPTE0NjMzMjhcclxuLy8gTm90IGlkZWFsIC0gbGVhdmVzIHRyYXNoIGluIHRoZSBGU1xyXG5pbXBvcnQgeyByYW5kb21CeXRlcyB9IGZyb20gJ25vZGU6Y3J5cHRvJztcclxuXHJcbmltcG9ydCB7IGdldENhY2hlUGF0aCB9IGZyb20gJy4vY2FjaGUuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG5jb25zdCBSQU5ET01fUElEID0gcmFuZG9tQnl0ZXMoNjQpLnRvU3RyaW5nKCdiYXNlNjR1cmwnKTtcclxuY29uc3QgUFVQUEVURUVSX0RJUiA9IHBhdGguam9pbigndG1wJywgYHB1cHBldGVlci0ke1JBTkRPTV9QSUR9YCk7XHJcbmNvbnN0IERBVEFfRElSID0gcGF0aC5qb2luKFBVUFBFVEVFUl9ESVIsICdwcm9maWxlJyk7XHJcblxyXG4vLyBUaGUgbWluaW1hbCBhcmdzIHRvIHNwZWVkIHVwIHRoZSBicm93c2VyXHJcbmNvbnN0IG1pbmltYWxBcmdzID0gW1xyXG4gIGAtLXVzZXItZGF0YS1kaXI9JHtEQVRBX0RJUn1gLFxyXG4gICctLWF1dG9wbGF5LXBvbGljeT11c2VyLWdlc3R1cmUtcmVxdWlyZWQnLFxyXG4gICctLWRpc2FibGUtYmFja2dyb3VuZC1uZXR3b3JraW5nJyxcclxuICAnLS1kaXNhYmxlLWJhY2tncm91bmQtdGltZXItdGhyb3R0bGluZycsXHJcbiAgJy0tZGlzYWJsZS1iYWNrZ3JvdW5kaW5nLW9jY2x1ZGVkLXdpbmRvd3MnLFxyXG4gICctLWRpc2FibGUtYnJlYWtwYWQnLFxyXG4gICctLWRpc2FibGUtY2xpZW50LXNpZGUtcGhpc2hpbmctZGV0ZWN0aW9uJyxcclxuICAnLS1kaXNhYmxlLWNvbXBvbmVudC11cGRhdGUnLFxyXG4gICctLWRpc2FibGUtZGVmYXVsdC1hcHBzJyxcclxuICAnLS1kaXNhYmxlLWRldi1zaG0tdXNhZ2UnLFxyXG4gICctLWRpc2FibGUtZG9tYWluLXJlbGlhYmlsaXR5JyxcclxuICAnLS1kaXNhYmxlLWV4dGVuc2lvbnMnLFxyXG4gICctLWRpc2FibGUtZmVhdHVyZXM9QXVkaW9TZXJ2aWNlT3V0T2ZQcm9jZXNzJyxcclxuICAnLS1kaXNhYmxlLWhhbmctbW9uaXRvcicsXHJcbiAgJy0tZGlzYWJsZS1pcGMtZmxvb2RpbmctcHJvdGVjdGlvbicsXHJcbiAgJy0tZGlzYWJsZS1ub3RpZmljYXRpb25zJyxcclxuICAnLS1kaXNhYmxlLW9mZmVyLXN0b3JlLXVubWFza2VkLXdhbGxldC1jYXJkcycsXHJcbiAgJy0tZGlzYWJsZS1wb3B1cC1ibG9ja2luZycsXHJcbiAgJy0tZGlzYWJsZS1wcmludC1wcmV2aWV3JyxcclxuICAnLS1kaXNhYmxlLXByb21wdC1vbi1yZXBvc3QnLFxyXG4gICctLWRpc2FibGUtcmVuZGVyZXItYmFja2dyb3VuZGluZycsXHJcbiAgJy0tZGlzYWJsZS1zZXNzaW9uLWNyYXNoZWQtYnViYmxlJyxcclxuICAnLS1kaXNhYmxlLXNldHVpZC1zYW5kYm94JyxcclxuICAnLS1kaXNhYmxlLXNwZWVjaC1hcGknLFxyXG4gICctLWRpc2FibGUtc3luYycsXHJcbiAgJy0taGlkZS1jcmFzaC1yZXN0b3JlLWJ1YmJsZScsXHJcbiAgJy0taGlkZS1zY3JvbGxiYXJzJyxcclxuICAnLS1pZ25vcmUtZ3B1LWJsYWNrbGlzdCcsXHJcbiAgJy0tbWV0cmljcy1yZWNvcmRpbmctb25seScsXHJcbiAgJy0tbXV0ZS1hdWRpbycsXHJcbiAgJy0tbm8tZGVmYXVsdC1icm93c2VyLWNoZWNrJyxcclxuICAnLS1uby1maXJzdC1ydW4nLFxyXG4gICctLW5vLXBpbmdzJyxcclxuICAnLS1uby1zYW5kYm94JyxcclxuICAnLS1uby16eWdvdGUnLFxyXG4gICctLXBhc3N3b3JkLXN0b3JlPWJhc2ljJyxcclxuICAnLS11c2UtbW9jay1rZXljaGFpbidcclxuXTtcclxuXHJcbmNvbnN0IF9fZGlybmFtZSA9IHVybC5maWxlVVJMVG9QYXRoKG5ldyBVUkwoJy4nLCBpbXBvcnQubWV0YS51cmwpKTtcclxuXHJcbmNvbnN0IHRlbXBsYXRlID0gZnMucmVhZEZpbGVTeW5jKFxyXG4gIF9fZGlybmFtZSArICcvLi4vdGVtcGxhdGVzL3RlbXBsYXRlLmh0bWwnLFxyXG4gICd1dGY4J1xyXG4pO1xyXG5cclxubGV0IGJyb3dzZXI7XHJcblxyXG4vKipcclxuICogU2V0cyB0aGUgY29udGVudCBmb3IgYSBQdXBwZXRlZXIgUGFnZSB1c2luZyBhIHByZWRlZmluZWQgdGVtcGxhdGVcclxuICogYW5kIGFkZGl0aW9uYWwgc2NyaXB0cy4gQWxzbywgc2V0cyB0aGUgcGFnZWVycm9yIGluIG9yZGVyIHRvIGNhdGNoXHJcbiAqIGFuZCBkaXNwbGF5IGVycm9ycyBmcm9tIHRoZSB3aW5kb3cgY29udGV4dC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IGZvciB3aGljaCB0aGUgY29udGVudFxyXG4gKiBpcyBiZWluZyBzZXQuXHJcbiAqL1xyXG5jb25zdCBzZXRQYWdlQ29udGVudCA9IGFzeW5jIChwYWdlKSA9PiB7XHJcbiAgYXdhaXQgcGFnZS5zZXRDb250ZW50KHRlbXBsYXRlKTtcclxuICBhd2FpdCBwYWdlLmFkZFNjcmlwdFRhZyh7IHBhdGg6IGAke2dldENhY2hlUGF0aCgpfS9zb3VyY2VzLmpzYCB9KTtcclxuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICBhd2FpdCBwYWdlLmV2YWx1YXRlKCgpID0+IHdpbmRvdy5zZXR1cEhpZ2hjaGFydHMoKSk7XHJcblxyXG4gIHBhZ2Uub24oJ3BhZ2VlcnJvcicsIGFzeW5jIChlcnJvcikgPT4ge1xyXG4gICAgLy8gVE9ETzogQ29uc2lkZXIgYWRkaW5nIGEgc3dpdGNoIGhlcmUgdGhhdCB0dXJucyBvbiBsb2coMCkgbG9nZ2luZ1xyXG4gICAgLy8gb24gcGFnZSBlcnJvcnMuXHJcbiAgICBhd2FpdCBwYWdlLiRldmFsKFxyXG4gICAgICAnI2NvbnRhaW5lcicsXHJcbiAgICAgIChlbGVtZW50LCBlcnJvck1lc3NhZ2UpID0+IHtcclxuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICBpZiAod2luZG93Ll9kaXNwbGF5RXJyb3JzKSB7XHJcbiAgICAgICAgICBlbGVtZW50LmlubmVySFRNTCA9IGVycm9yTWVzc2FnZTtcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIGA8aDE+Q2hhcnQgaW5wdXQgZGF0YSBlcnJvcjwvaDE+JHtlcnJvci50b1N0cmluZygpfWBcclxuICAgICk7XHJcbiAgfSk7XHJcbn07XHJcblxyXG4vKipcclxuICogQ2xlYXJzIHRoZSBjb250ZW50IG9mIGEgUHVwcGV0ZWVyIFBhZ2UgYmFzZWQgb24gdGhlIHNwZWNpZmllZCBtb2RlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFRoZSBQdXBwZXRlZXIgUGFnZSBvYmplY3QgdG8gYmUgY2xlYXJlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBoYXJkUmVzZXQgLSBBIGZsYWcgaW5kaWNhdGluZyB0aGUgdHlwZSBvZiBjbGVhcmluZ1xyXG4gKiB0byBiZSBwZXJmb3JtZWQuIElmIHRydWUsIG5hdmlnYXRlcyB0byAnYWJvdXQ6YmxhbmsnIGFuZCByZXNldHMgY29udGVudFxyXG4gKiBhbmQgc2NyaXB0cy4gSWYgZmFsc2UsIGNsZWFycyB0aGUgYm9keSBjb250ZW50IGJ5IHNldHRpbmcgYSBwcmVkZWZpbmVkIEhUTUxcclxuICogc3RydWN0dXJlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFcnJvcn0gTG9ncyB0aHJvd24gZXJyb3IgaWYgY2xlYXJpbmcgdGhlIHBhZ2UgY29udGVudCBmYWlscy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBjbGVhclBhZ2UgPSBhc3luYyAocGFnZSwgaGFyZFJlc2V0ID0gZmFsc2UpID0+IHtcclxuICB0cnkge1xyXG4gICAgaWYgKGhhcmRSZXNldCkge1xyXG4gICAgICAvLyBOYXZpZ2F0ZSB0byBhYm91dDpibGFua1xyXG4gICAgICBhd2FpdCBwYWdlLmdvdG8oJ2Fib3V0OmJsYW5rJyk7XHJcblxyXG4gICAgICAvLyBTZXQgdGhlIGNvbnRlbnQgYW5kIGFuZCBzY3JpcHRzIGFnYWluXHJcbiAgICAgIGF3YWl0IHNldFBhZ2VDb250ZW50KHBhZ2UpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gQ2xlYXIgYm9keSBjb250ZW50XHJcbiAgICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xyXG4gICAgICAgIGRvY3VtZW50LmJvZHkuaW5uZXJIVE1MID1cclxuICAgICAgICAgICc8ZGl2IGlkPVwiY2hhcnQtY29udGFpbmVyXCI+PGRpdiBpZD1cImNvbnRhaW5lclwiPjwvZGl2PjwvZGl2Pic7XHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgIDIsXHJcbiAgICAgIGVycm9yLFxyXG4gICAgICAnW2Jyb3dzZXJdIENvdWxkIG5vdCBjbGVhciB0aGUgY29udGVudCBvZiB0aGUgcGFnZS4nXHJcbiAgICApO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgbmV3IFB1cHBldGVlciBQYWdlIHdpdGhpbiBhbiBleGlzdGluZyBicm93c2VyIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBJZiB0aGUgYnJvd3NlciBpbnN0YW5jZSBpcyBub3QgYXZhaWxhYmxlLCByZXR1cm5zIGZhbHNlLlxyXG4gKlxyXG4gKiBUaGUgZnVuY3Rpb24gY3JlYXRlcyBhIG5ldyBwYWdlLCBkaXNhYmxlcyBjYWNoaW5nLCBzZXRzIGNvbnRlbnQgdXNpbmdcclxuICogc2V0UGFnZUNvbnRlbnQoKSwgYW5kIHJldHVybnMgdGhlIGNyZWF0ZWQgUHVwcGV0ZWVyIFBhZ2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHsoYm9vbGVhbnxvYmplY3QpfSBSZXR1cm5zIGZhbHNlIGlmIHRoZSBicm93c2VyIGluc3RhbmNlIGlzIG5vdFxyXG4gKiBhdmFpbGFibGUsIG9yIGEgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IHJlcHJlc2VudGluZyB0aGUgbmV3bHkgY3JlYXRlZCBwYWdlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IG5ld1BhZ2UgPSBhc3luYyAoKSA9PiB7XHJcbiAgaWYgKCFicm93c2VyKSB7XHJcbiAgICByZXR1cm4gZmFsc2U7XHJcbiAgfVxyXG5cclxuICBjb25zdCBwYWdlID0gYXdhaXQgYnJvd3Nlci5uZXdQYWdlKCk7XHJcblxyXG4gIC8vIERpc2FibGUgY2FjaGVcclxuICBhd2FpdCBwYWdlLnNldENhY2hlRW5hYmxlZChmYWxzZSk7XHJcblxyXG4gIC8vIFNldCB0aGUgY29udGVudFxyXG4gIGF3YWl0IHNldFBhZ2VDb250ZW50KHBhZ2UpO1xyXG4gIHJldHVybiBwYWdlO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYSBQdXBwZXRlZXIgYnJvd3NlciBpbnN0YW5jZSB3aXRoIHRoZSBzcGVjaWZpZWQgYXJndW1lbnRzLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0FycmF5fSBwdXBwZXRlZXJBcmdzIC0gQWRkaXRpb25hbCBhcmd1bWVudHMgZm9yIFB1cHBldGVlciBsYXVuY2guXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPG9iamVjdD59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIFB1cHBldGVlciBicm93c2VyXHJcbiAqIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIG1heCByZXRyaWVzIHRvIG9wZW4gYSBicm93c2VyXHJcbiAqIGluc3RhbmNlIGFyZSByZWFjaGVkLCBvciBpZiBubyBicm93c2VyIGluc3RhbmNlIGlzIGZvdW5kIGFmdGVyIHJldHJpZXMuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgY3JlYXRlID0gYXN5bmMgKHB1cHBldGVlckFyZ3MpID0+IHtcclxuICBjb25zdCBhbGxBcmdzID0gWy4uLm1pbmltYWxBcmdzLCAuLi4ocHVwcGV0ZWVyQXJncyB8fCBbXSldO1xyXG5cclxuICAvLyBDcmVhdGUgYSBicm93c2VyXHJcbiAgaWYgKCFicm93c2VyKSB7XHJcbiAgICBsZXQgdHJ5Q291bnQgPSAwO1xyXG5cclxuICAgIGNvbnN0IG9wZW4gPSBhc3luYyAoKSA9PiB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbYnJvd3Nlcl0gQXR0ZW1wdGluZyB0byBnZXQgYSBicm93c2VyIGluc3RhbmNlICh0cnkgJHsrK3RyeUNvdW50fSkuYFxyXG4gICAgICAgICk7XHJcbiAgICAgICAgYnJvd3NlciA9IGF3YWl0IHB1cHBldGVlci5sYXVuY2goe1xyXG4gICAgICAgICAgaGVhZGxlc3M6ICduZXcnLFxyXG4gICAgICAgICAgYXJnczogYWxsQXJncyxcclxuICAgICAgICAgIHVzZXJEYXRhRGlyOiAnLi90bXAvJ1xyXG4gICAgICAgIH0pO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAgIDEsXHJcbiAgICAgICAgICBlcnJvcixcclxuICAgICAgICAgICdbYnJvd3Nlcl0gRmFpbGVkIHRvIGxhdW5jaCBhIGJyb3dzZXIgaW5zdGFuY2UuJ1xyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIC8vIFJldHJ5IHRvIGxhdW5jaCBicm93c2VyIHVudGlsIHJlYWNoaW5nIG1heCBhdHRlbXB0c1xyXG4gICAgICAgIGlmICh0cnlDb3VudCA8IDI1KSB7XHJcbiAgICAgICAgICBsb2coMywgYFticm93c2VyXSBSZXRyeSB0byBvcGVuIGEgYnJvd3NlciAoJHt0cnlDb3VudH0gb3V0IG9mIDI1KS5gKTtcclxuICAgICAgICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNwb25zZSkgPT4gc2V0VGltZW91dChyZXNwb25zZSwgNDAwMCkpO1xyXG4gICAgICAgICAgYXdhaXQgb3BlbigpO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH07XHJcblxyXG4gICAgdHJ5IHtcclxuICAgICAgYXdhaXQgb3BlbigpO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdbYnJvd3Nlcl0gTWF4aW11bSByZXRyaWVzIHRvIG9wZW4gYSBicm93c2VyIGluc3RhbmNlIHJlYWNoZWQuJ1xyXG4gICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoIWJyb3dzZXIpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbYnJvd3Nlcl0gQ2Fubm90IGZpbmQgYSBicm93c2VyIHRvIG9wZW4uJyk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gYSBicm93c2VyIHByb21pc2VcclxuICByZXR1cm4gYnJvd3NlcjtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgdGhlIGV4aXN0aW5nIFB1cHBldGVlciBicm93c2VyIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxvYmplY3Q+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBQdXBwZXRlZXIgYnJvd3NlclxyXG4gKiBpbnN0YW5jZS5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiBubyB2YWxpZCBicm93c2VyIGhhcyBiZWVuXHJcbiAqIGNyZWF0ZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0ID0gYXN5bmMgKCkgPT4ge1xyXG4gIGlmICghYnJvd3Nlcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbYnJvd3Nlcl0gTm8gdmFsaWQgYnJvd3NlciBoYXMgYmVlbiBjcmVhdGVkLicpO1xyXG4gIH1cclxuXHJcbiAgcmV0dXJuIGJyb3dzZXI7XHJcbn07XHJcblxyXG4vKipcclxuICogQ2xvc2VzIHRoZSBQdXBwZXRlZXIgYnJvd3NlciBpbnN0YW5jZSBpZiBpdCBpcyBjb25uZWN0ZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPGJvb2xlYW4+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIHRydWUgYWZ0ZXIgdGhlIGJyb3dzZXJcclxuICogaXMgY2xvc2VkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGNsb3NlID0gYXN5bmMgKCkgPT4ge1xyXG4gIC8vIENsb3NlIHRoZSBicm93c2VyIHdoZW4gY29ubm5lY3RlZFxyXG4gIGlmIChicm93c2VyPy5pc0Nvbm5lY3RlZCgpKSB7XHJcbiAgICBhd2FpdCBicm93c2VyLmNsb3NlKCk7XHJcbiAgICBsb2coNCwgJ1ticm93c2VyXSBDbG9zZWQgdGhlIGJyb3dzZXIuJyk7XHJcbiAgfVxyXG4gIHJldHVybiB0cnVlO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIG5ld1BhZ2UsXHJcbiAgY2xlYXJQYWdlLFxyXG4gIGdldCxcclxuICBjbG9zZVxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHBhdGggZnJvbSAncGF0aCc7XHJcbmltcG9ydCAqIGFzIHVybCBmcm9tICd1cmwnO1xyXG5cclxuaW1wb3J0IGNhY2hlIGZyb20gJy4vY2FjaGUuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHN2Z1RlbXBsYXRlIGZyb20gJy4vLi4vdGVtcGxhdGVzL3N2Z19leHBvcnQvc3ZnX2V4cG9ydC5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuY29uc3QgX19iYXNlZGlyID0gdXJsLmZpbGVVUkxUb1BhdGgobmV3IFVSTCgnLicsIGltcG9ydC5tZXRhLnVybCkpO1xyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyB0aGUgY2xpcHBpbmcgcmVnaW9uIGNvb3JkaW5hdGVzIG9mIHRoZSBzcGVjaWZpZWQgcGFnZSBlbGVtZW50IHdpdGhcclxuICogdGhlIGlkICdjaGFydC1jb250YWluZXInLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gYW4gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogeCwgeSwgd2lkdGgsIGFuZCBoZWlnaHQgcHJvcGVydGllcy5cclxuICovXHJcbmNvbnN0IGdldENsaXBSZWdpb24gPSAocGFnZSkgPT5cclxuICBwYWdlLiRldmFsKCcjY2hhcnQtY29udGFpbmVyJywgKGVsZW1lbnQpID0+IHtcclxuICAgIGNvbnN0IHsgeCwgeSwgd2lkdGgsIGhlaWdodCB9ID0gZWxlbWVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcclxuICAgIHJldHVybiB7XHJcbiAgICAgIHgsXHJcbiAgICAgIHksXHJcbiAgICAgIHdpZHRoLFxyXG4gICAgICBoZWlnaHQ6IE1hdGgudHJ1bmMoaGVpZ2h0ID4gMSA/IGhlaWdodCA6IDUwMClcclxuICAgIH07XHJcbiAgfSk7XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhbiBpbWFnZSB1c2luZyBQdXBwZXRlZXIncyBwYWdlIHNjcmVlbnNob3QgZnVuY3Rpb25hbGl0eSB3aXRoXHJcbiAqIHNwZWNpZmllZCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICogQHBhcmFtIHtzdHJpbmd9IHR5cGUgLSBJbWFnZSB0eXBlLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gZW5jb2RpbmcgLSBJbWFnZSBlbmNvZGluZy5cclxuICogQHBhcmFtIHtPYmplY3R9IGNsaXAgLSBDbGlwcGluZyByZWdpb24gY29vcmRpbmF0ZXMuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSByYXN0ZXJpemF0aW9uVGltZW91dCAtIFRpbWVvdXQgZm9yIHJhc3Rlcml6YXRpb25cclxuICogaW4gbWlsbGlzZWNvbmRzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxCdWZmZXI+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgaW1hZ2UgYnVmZmVyIG9yIHJlamVjdGluZ1xyXG4gKiB3aXRoIGFuIEV4cG9ydEVycm9yIGZvciB0aW1lb3V0LlxyXG4gKi9cclxuY29uc3QgY3JlYXRlSW1hZ2UgPSAocGFnZSwgdHlwZSwgZW5jb2RpbmcsIGNsaXAsIHJhc3Rlcml6YXRpb25UaW1lb3V0KSA9PlxyXG4gIFByb21pc2UucmFjZShbXHJcbiAgICBwYWdlLnNjcmVlbnNob3Qoe1xyXG4gICAgICB0eXBlLFxyXG4gICAgICBlbmNvZGluZyxcclxuICAgICAgY2xpcCxcclxuXHJcbiAgICAgIC8vICM0NDcsICM0NjMgLSBhbHdheXMgcmVuZGVyIG9uIGEgdHJhbnNwYXJlbnQgcGFnZSBpZiB0aGUgZXhwZWN0ZWQgdHlwZVxyXG4gICAgICAvLyBmb3JtYXQgaXMgUE5HXHJcbiAgICAgIG9taXRCYWNrZ3JvdW5kOiB0eXBlID09ICdwbmcnXHJcbiAgICB9KSxcclxuICAgIG5ldyBQcm9taXNlKChfcmVzb2x2ZSwgcmVqZWN0KSA9PlxyXG4gICAgICBzZXRUaW1lb3V0KFxyXG4gICAgICAgICgpID0+IHJlamVjdChuZXcgRXhwb3J0RXJyb3IoJ1Jhc3Rlcml6YXRpb24gdGltZW91dCcpKSxcclxuICAgICAgICByYXN0ZXJpemF0aW9uVGltZW91dCB8fCAxNTAwXHJcbiAgICAgIClcclxuICAgIClcclxuICBdKTtcclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgUERGIHVzaW5nIFB1cHBldGVlcidzIHBhZ2UgcGRmIGZ1bmN0aW9uYWxpdHkgd2l0aCBzcGVjaWZpZWRcclxuICogb3B0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBoZWlnaHQgLSBQREYgaGVpZ2h0LlxyXG4gKiBAcGFyYW0ge251bWJlcn0gd2lkdGggLSBQREYgd2lkdGguXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBlbmNvZGluZyAtIFBERiBlbmNvZGluZy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8QnVmZmVyPn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIFBERiBidWZmZXIuXHJcbiAqL1xyXG5jb25zdCBjcmVhdGVQREYgPSAocGFnZSwgaGVpZ2h0LCB3aWR0aCwgZW5jb2RpbmcpID0+XHJcbiAgcGFnZS5wZGYoe1xyXG4gICAgLy8gVGhpcyB3aWxsIHJlbW92ZSBhbiBleHRyYSBlbXB0eSBwYWdlIGluIFBERiBleHBvcnRzXHJcbiAgICBoZWlnaHQ6IGhlaWdodCArIDEsXHJcbiAgICB3aWR0aCxcclxuICAgIGVuY29kaW5nXHJcbiAgfSk7XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhbiBTVkcgc3RyaW5nIGJ5IGV2YWx1YXRpbmcgdGhlIG91dGVySFRNTCBvZiB0aGUgZmlyc3QgJ3N2ZycgZWxlbWVudFxyXG4gKiBpbnNpZGUgYW4gZWxlbWVudCB3aXRoIHRoZSBpZCAnY29udGFpbmVyJy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZz59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBTVkcgc3RyaW5nLlxyXG4gKi9cclxuY29uc3QgY3JlYXRlU1ZHID0gKHBhZ2UpID0+XHJcbiAgcGFnZS4kZXZhbCgnI2NvbnRhaW5lciBzdmc6Zmlyc3Qtb2YtdHlwZScsIChlbGVtZW50KSA9PiBlbGVtZW50Lm91dGVySFRNTCk7XHJcblxyXG4vKipcclxuICogU2V0cyB0aGUgc3BlY2lmaWVkIGNoYXJ0IGFuZCBvcHRpb25zIGFzIGNvbmZpZ3VyYXRpb24gaW50byB0aGUgdHJpZ2dlckV4cG9ydFxyXG4gKiBmdW5jdGlvbiB3aXRoaW4gdGhlIHdpbmRvdyBjb250ZXh0IHVzaW5nIHBhZ2UuZXZhbHVhdGUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge2FueX0gY2hhcnQgLSBUaGUgY2hhcnQgb2JqZWN0IHRvIGJlIGNvbmZpZ3VyZWQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gQ29uZmlndXJhdGlvbiBvcHRpb25zIGZvciB0aGUgY2hhcnQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBQcm9taXNlIHJlc29sdmluZyBhZnRlciB0aGUgY29uZmlndXJhdGlvbiBpcyBzZXQuXHJcbiAqL1xyXG5jb25zdCBzZXRBc0NvbmZpZyA9IChwYWdlLCBjaGFydCwgb3B0aW9ucykgPT5cclxuICBwYWdlLmV2YWx1YXRlKFxyXG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAoY2hhcnQsIG9wdGlvbnMpID0+IHdpbmRvdy50cmlnZ2VyRXhwb3J0KGNoYXJ0LCBvcHRpb25zKSxcclxuICAgIGNoYXJ0LFxyXG4gICAgb3B0aW9uc1xyXG4gICk7XHJcblxyXG4vKipcclxuICogRXhwb3J0cyB0byBhIGNoYXJ0IGZyb20gYSBwYWdlIHVzaW5nIFB1cHBldGVlci5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7YW55fSBjaGFydCAtIFRoZSBjaGFydCBvYmplY3Qgb3IgU1ZHIGNvbmZpZ3VyYXRpb24gdG8gYmUgZXhwb3J0ZWQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gRXhwb3J0IG9wdGlvbnMgYW5kIGNvbmZpZ3VyYXRpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZyB8IEJ1ZmZlciB8IEV4cG9ydEVycm9yPn0gUHJvbWlzZSByZXNvbHZpbmcgdG9cclxuICogdGhlIGV4cG9ydGVkIGRhdGEgb3IgcmVqZWN0aW5nIHdpdGggYW4gRXhwb3J0RXJyb3IuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCBhc3luYyAocGFnZSwgY2hhcnQsIG9wdGlvbnMpID0+IHtcclxuICAvKipcclxuICAgKiBLZWVwcyB0cmFjayBvZiBhbGwgcmVzb3VyY2VzIGFkZGVkIG9uIHRoZSBwYWdlIHdpdGggYWRkWFhYVGFnLiBldGNcclxuICAgKiBJdCdzIFZJVEFMIHRoYXQgYWxsIGFkZGVkIHJlc291cmNlcyBlbmRzIHVwIGhlcmUgc28gd2UgY2FuIGNsZWFyIHRoaW5nc1xyXG4gICAqIG91dCB3aGVuIGRvaW5nIGEgbmV3IGV4cG9ydCBpbiB0aGUgc2FtZSBwYWdlIVxyXG4gICAqL1xyXG4gIGNvbnN0IGluamVjdGVkUmVzb3VyY2VzID0gW107XHJcblxyXG4gIC8qKiBDbGVhciBvdXQgYWxsIHN0YXRlIHNldCBvbiB0aGUgcGFnZSB3aXRoIGFkZFNjcmlwdFRhZy9hZGRTdHlsZVRhZy4gKi9cclxuICBjb25zdCBjbGVhckluamVjdGVkID0gYXN5bmMgKHBhZ2UpID0+IHtcclxuICAgIGZvciAoY29uc3QgcmVzIG9mIGluamVjdGVkUmVzb3VyY2VzKSB7XHJcbiAgICAgIGF3YWl0IHJlcy5kaXNwb3NlKCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmVzZXQgYWxsIENTUyBhbmQgc2NyaXB0IHRhZ3NcclxuICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xyXG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgY29uc3QgWywgLi4uc2NyaXB0c1RvUmVtb3ZlXSA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdzY3JpcHQnKTtcclxuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgIGNvbnN0IFssIC4uLnN0eWxlc1RvUmVtb3ZlXSA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdzdHlsZScpO1xyXG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgY29uc3QgWy4uLmxpbmtzVG9SZW1vdmVdID0gZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ2xpbmsnKTtcclxuXHJcbiAgICAgIC8vIFJlbW92ZSB0YWdzXHJcbiAgICAgIGZvciAoY29uc3QgZWxlbWVudCBvZiBbXHJcbiAgICAgICAgLi4uc2NyaXB0c1RvUmVtb3ZlLFxyXG4gICAgICAgIC4uLnN0eWxlc1RvUmVtb3ZlLFxyXG4gICAgICAgIC4uLmxpbmtzVG9SZW1vdmVcclxuICAgICAgXSkge1xyXG4gICAgICAgIGVsZW1lbnQucmVtb3ZlKCk7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG4gIH07XHJcblxyXG4gIHRyeSB7XHJcbiAgICBsb2coNCwgJ1tleHBvcnRdIERldGVybWluaW5nIGV4cG9ydCBwYXRoLicpO1xyXG5cclxuICAgIGNvbnN0IGV4cG9ydE9wdGlvbnMgPSBvcHRpb25zLmV4cG9ydDtcclxuXHJcbiAgICAvLyBGb3JjZSBhIHJBRlxyXG4gICAgLy8gU2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9wdXBwZXRlZXIvcHVwcGV0ZWVyL2lzc3Vlcy83NTA3XHJcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4gcmVxdWVzdEFuaW1hdGlvbkZyYW1lKCgpID0+IHt9KSk7XHJcblxyXG4gICAgLy8gRGVjaWRlIHdoZXRoZXIgZGlzcGxheSBlcnJvciBvciBkZWJidWdlciB3cmFwcGVyIGFyb3VuZCBpdFxyXG4gICAgY29uc3QgZGlzcGxheUVycm9ycyA9XHJcbiAgICAgIGV4cG9ydE9wdGlvbnM/Lm9wdGlvbnM/LmNoYXJ0Py5kaXNwbGF5RXJyb3JzICYmXHJcbiAgICAgIGNhY2hlLmdldENhY2hlKCkuYWN0aXZlTWFuaWZlc3QubW9kdWxlcy5kZWJ1Z2dlcjtcclxuXHJcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoKGQpID0+ICh3aW5kb3cuX2Rpc3BsYXlFcnJvcnMgPSBkKSwgZGlzcGxheUVycm9ycyk7XHJcblxyXG4gICAgbGV0IGlzU1ZHO1xyXG4gICAgaWYgKFxyXG4gICAgICBjaGFydC5pbmRleE9mICYmXHJcbiAgICAgIChjaGFydC5pbmRleE9mKCc8c3ZnJykgPj0gMCB8fCBjaGFydC5pbmRleE9mKCc8P3htbCcpID49IDApXHJcbiAgICApIHtcclxuICAgICAgLy8gU1ZHIGlucHV0IGhhbmRsaW5nXHJcbiAgICAgIGxvZyg0LCAnW2V4cG9ydF0gVHJlYXRpbmcgYXMgU1ZHLicpO1xyXG5cclxuICAgICAgLy8gSWYgaW5wdXQgaXMgYWxzbyBTVkcsIGp1c3QgcmV0dXJuIGl0XHJcbiAgICAgIGlmIChleHBvcnRPcHRpb25zLnR5cGUgPT09ICdzdmcnKSB7XHJcbiAgICAgICAgcmV0dXJuIGNoYXJ0O1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpc1NWRyA9IHRydWU7XHJcbiAgICAgIGF3YWl0IHBhZ2Uuc2V0Q29udGVudChzdmdUZW1wbGF0ZShjaGFydCkpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gSlNPTiBjb25maWcgaGFuZGxpbmdcclxuICAgICAgbG9nKDQsICdbZXhwb3J0XSBUcmVhdGluZyBhcyBjb25maWcuJyk7XHJcblxyXG4gICAgICAvLyBOZWVkIHRvIHBlcmZvcm0gc3RyYWlnaHQgaW5qZWN0XHJcbiAgICAgIGlmIChleHBvcnRPcHRpb25zLnN0ckluaikge1xyXG4gICAgICAgIC8vIEluamVjdGlvbiBiYXNlZCBjb25maWd1cmF0aW9uIGV4cG9ydFxyXG4gICAgICAgIGF3YWl0IHNldEFzQ29uZmlnKFxyXG4gICAgICAgICAgcGFnZSxcclxuICAgICAgICAgIHtcclxuICAgICAgICAgICAgY2hhcnQ6IHtcclxuICAgICAgICAgICAgICBoZWlnaHQ6IGV4cG9ydE9wdGlvbnMuaGVpZ2h0LFxyXG4gICAgICAgICAgICAgIHdpZHRoOiBleHBvcnRPcHRpb25zLndpZHRoXHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0sXHJcbiAgICAgICAgICBvcHRpb25zXHJcbiAgICAgICAgKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICAvLyBCYXNpYyBjb25maWd1cmF0aW9uIGV4cG9ydFxyXG4gICAgICAgIGNoYXJ0LmNoYXJ0LmhlaWdodCA9IGV4cG9ydE9wdGlvbnMuaGVpZ2h0O1xyXG4gICAgICAgIGNoYXJ0LmNoYXJ0LndpZHRoID0gZXhwb3J0T3B0aW9ucy53aWR0aDtcclxuXHJcbiAgICAgICAgYXdhaXQgc2V0QXNDb25maWcocGFnZSwgY2hhcnQsIG9wdGlvbnMpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gVXNlIHJlc291cmNlc1xyXG4gICAgY29uc3QgcmVzb3VyY2VzID0gb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXM7XHJcbiAgICBpZiAocmVzb3VyY2VzKSB7XHJcbiAgICAgIC8vIExvYWQgY3VzdG9tIEpTIGNvZGVcclxuICAgICAgaWYgKHJlc291cmNlcy5qcykge1xyXG4gICAgICAgIGluamVjdGVkUmVzb3VyY2VzLnB1c2goXHJcbiAgICAgICAgICBhd2FpdCBwYWdlLmFkZFNjcmlwdFRhZyh7XHJcbiAgICAgICAgICAgIGNvbnRlbnQ6IHJlc291cmNlcy5qc1xyXG4gICAgICAgICAgfSlcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBMb2FkIHNjcmlwdHMgZnJvbSBhbGwgY3VzdG9tIGZpbGVzXHJcbiAgICAgIGlmIChyZXNvdXJjZXMuZmlsZXMpIHtcclxuICAgICAgICBmb3IgKGNvbnN0IGZpbGUgb2YgcmVzb3VyY2VzLmZpbGVzKSB7XHJcbiAgICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICBjb25zdCBpc0xvY2FsID0gIWZpbGUuc3RhcnRzV2l0aCgnaHR0cCcpID8gdHJ1ZSA6IGZhbHNlO1xyXG5cclxuICAgICAgICAgICAgLy8gQWRkIGVhY2ggY3VzdG9tIHNjcmlwdCBmcm9tIHJlc291cmNlcycgZmlsZXNcclxuICAgICAgICAgICAgaW5qZWN0ZWRSZXNvdXJjZXMucHVzaChcclxuICAgICAgICAgICAgICBhd2FpdCBwYWdlLmFkZFNjcmlwdFRhZyhcclxuICAgICAgICAgICAgICAgIGlzTG9jYWxcclxuICAgICAgICAgICAgICAgICAgPyB7XHJcbiAgICAgICAgICAgICAgICAgICAgICBjb250ZW50OiByZWFkRmlsZVN5bmMoZmlsZSwgJ3V0ZjgnKVxyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgOiB7XHJcbiAgICAgICAgICAgICAgICAgICAgICB1cmw6IGZpbGVcclxuICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgKVxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgICAgICAgIDIsXHJcbiAgICAgICAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgICAgICAgYFtleHBvcnRdIFRoZSBKUyBmaWxlICR7ZmlsZX0gY2Fubm90IGJlIGxvYWRlZC5gXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBMb2FkIENTU1xyXG4gICAgICBpZiAocmVzb3VyY2VzLmNzcykge1xyXG4gICAgICAgIGxldCBjc3NJbXBvcnRzID0gcmVzb3VyY2VzLmNzcy5tYXRjaCgvQGltcG9ydFxccyooW147XSopOy9nKTtcclxuICAgICAgICBpZiAoY3NzSW1wb3J0cykge1xyXG4gICAgICAgICAgLy8gSGFuZGxlIGNzcyBzZWN0aW9uXHJcbiAgICAgICAgICBmb3IgKGxldCBjc3NJbXBvcnRQYXRoIG9mIGNzc0ltcG9ydHMpIHtcclxuICAgICAgICAgICAgaWYgKGNzc0ltcG9ydFBhdGgpIHtcclxuICAgICAgICAgICAgICBjc3NJbXBvcnRQYXRoID0gY3NzSW1wb3J0UGF0aFxyXG4gICAgICAgICAgICAgICAgLnJlcGxhY2UoJ3VybCgnLCAnJylcclxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKCdAaW1wb3J0JywgJycpXHJcbiAgICAgICAgICAgICAgICAucmVwbGFjZSgvXCIvZywgJycpXHJcbiAgICAgICAgICAgICAgICAucmVwbGFjZSgvJy9nLCAnJylcclxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKC87LywgJycpXHJcbiAgICAgICAgICAgICAgICAucmVwbGFjZSgvXFwpL2csICcnKVxyXG4gICAgICAgICAgICAgICAgLnRyaW0oKTtcclxuXHJcbiAgICAgICAgICAgICAgLy8gQWRkIGVhY2ggY3VzdG9tIGNzcyBmcm9tIHJlc291cmNlc1xyXG4gICAgICAgICAgICAgIGlmIChjc3NJbXBvcnRQYXRoLnN0YXJ0c1dpdGgoJ2h0dHAnKSkge1xyXG4gICAgICAgICAgICAgICAgaW5qZWN0ZWRSZXNvdXJjZXMucHVzaChcclxuICAgICAgICAgICAgICAgICAgYXdhaXQgcGFnZS5hZGRTdHlsZVRhZyh7XHJcbiAgICAgICAgICAgICAgICAgICAgdXJsOiBjc3NJbXBvcnRQYXRoXHJcbiAgICAgICAgICAgICAgICAgIH0pXHJcbiAgICAgICAgICAgICAgICApO1xyXG4gICAgICAgICAgICAgIH0gZWxzZSBpZiAob3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0ZpbGVSZXNvdXJjZXMpIHtcclxuICAgICAgICAgICAgICAgIGluamVjdGVkUmVzb3VyY2VzLnB1c2goXHJcbiAgICAgICAgICAgICAgICAgIGF3YWl0IHBhZ2UuYWRkU3R5bGVUYWcoe1xyXG4gICAgICAgICAgICAgICAgICAgIHBhdGg6IHBhdGguam9pbihfX2Jhc2VkaXIsIGNzc0ltcG9ydFBhdGgpXHJcbiAgICAgICAgICAgICAgICAgIH0pXHJcbiAgICAgICAgICAgICAgICApO1xyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gVGhlIHJlc3Qgb2YgdGhlIENTUyBzZWN0aW9uIHdpbGwgYmUgY29udGVudCBieSBub3dcclxuICAgICAgICBpbmplY3RlZFJlc291cmNlcy5wdXNoKFxyXG4gICAgICAgICAgYXdhaXQgcGFnZS5hZGRTdHlsZVRhZyh7XHJcbiAgICAgICAgICAgIGNvbnRlbnQ6IHJlc291cmNlcy5jc3MucmVwbGFjZSgvQGltcG9ydFxccyooW147XSopOy9nLCAnJykgfHwgJyAnXHJcbiAgICAgICAgICB9KVxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBHZXQgdGhlIHJlYWwgY2hhcnQgc2l6ZVxyXG4gICAgY29uc3Qgc2l6ZSA9IGlzU1ZHXHJcbiAgICAgID8gYXdhaXQgcGFnZS4kZXZhbChcclxuICAgICAgICAgICcjY2hhcnQtY29udGFpbmVyIHN2ZzpmaXJzdC1vZi10eXBlJyxcclxuICAgICAgICAgIChlbGVtZW50LCBzY2FsZSkgPT4gKHtcclxuICAgICAgICAgICAgY2hhcnRIZWlnaHQ6IGVsZW1lbnQuaGVpZ2h0LmJhc2VWYWwudmFsdWUgKiBzY2FsZSxcclxuICAgICAgICAgICAgY2hhcnRXaWR0aDogZWxlbWVudC53aWR0aC5iYXNlVmFsLnZhbHVlICogc2NhbGVcclxuICAgICAgICAgIH0pLFxyXG4gICAgICAgICAgcGFyc2VGbG9hdChleHBvcnRPcHRpb25zLnNjYWxlKVxyXG4gICAgICAgIClcclxuICAgICAgOiBhd2FpdCBwYWdlLmV2YWx1YXRlKCgpID0+IHtcclxuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgICAgY29uc3QgeyBjaGFydEhlaWdodCwgY2hhcnRXaWR0aCB9ID0gd2luZG93LkhpZ2hjaGFydHMuY2hhcnRzWzBdO1xyXG4gICAgICAgICAgcmV0dXJuIHtcclxuICAgICAgICAgICAgY2hhcnRIZWlnaHQsXHJcbiAgICAgICAgICAgIGNoYXJ0V2lkdGhcclxuICAgICAgICAgIH07XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgLy8gU2V0IGZpbmFsIGhlaWdodCBhbmQgd2lkdGggZm9yIHZpZXdwb3J0XHJcbiAgICBjb25zdCB2aWV3cG9ydEhlaWdodCA9IE1hdGguY2VpbChzaXplPy5jaGFydEhlaWdodCB8fCBleHBvcnRPcHRpb25zLmhlaWdodCk7XHJcbiAgICBjb25zdCB2aWV3cG9ydFdpZHRoID0gTWF0aC5jZWlsKHNpemU/LmNoYXJ0V2lkdGggfHwgZXhwb3J0T3B0aW9ucy53aWR0aCk7XHJcblxyXG4gICAgLy8gU2V0IHRoZSB2aWV3cG9ydCBmb3IgdGhlIGZpcnN0IHRpbWVcclxuICAgIC8vIE5PVEU6IHRoZSBjYWxsIHRvIHNldFZpZXdwb3J0IGlzIGV4cGVuc2l2ZSAtIGNhbiB3ZSBnZXQgYXdheSB3aXRoIG9ubHlcclxuICAgIC8vIGNhbGxpbmcgaXQgb25jZSwgZS5nLiBtb3ZpbmcgdGhpcyBvbmUgaW50byB0aGUgaXNTVkcgY29uZGl0aW9uIGJlbG93P1xyXG4gICAgYXdhaXQgcGFnZS5zZXRWaWV3cG9ydCh7XHJcbiAgICAgIGhlaWdodDogdmlld3BvcnRIZWlnaHQsXHJcbiAgICAgIHdpZHRoOiB2aWV3cG9ydFdpZHRoLFxyXG4gICAgICBkZXZpY2VTY2FsZUZhY3RvcjogaXNTVkcgPyAxIDogcGFyc2VGbG9hdChleHBvcnRPcHRpb25zLnNjYWxlKVxyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gUHJlcGFyZSBhIHpvb20gY2FsbGJhY2sgZm9yIHRoZSBuZXh0IGV2YWx1YXRlIGNhbGxcclxuICAgIGNvbnN0IHpvb21DYWxsYmFjayA9IGlzU1ZHXHJcbiAgICAgID8gLy8gSW4gY2FzZSBvZiBTVkcgdGhlIHpvb20gbXVzdCBiZSBzZXQgZGlyZWN0bHkgZm9yIGJvZHlcclxuICAgICAgICAoc2NhbGUpID0+IHtcclxuICAgICAgICAgIC8vIFNldCB0aGUgem9vbSBhcyBzY2FsZVxyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLnpvb20gPSBzY2FsZTtcclxuXHJcbiAgICAgICAgICAvLyBTZXQgdGhlIG1hcmdpbiB0byAwcHhcclxuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgICAgZG9jdW1lbnQuYm9keS5zdHlsZS5tYXJnaW4gPSAnMHB4JztcclxuICAgICAgICB9XHJcbiAgICAgIDogLy8gTm8gbmVlZCBmb3Igc3VjaCBzY2FsZSBtYW5pcHVsYXRpb24gaW4gY2FzZSBvZiBvdGhlciB0eXBlcyBvZiBleHBvcnRzXHJcbiAgICAgICAgKCkgPT4ge1xyXG4gICAgICAgICAgLy8gUmVzZXQgdGhlIHpvb20gZm9yIG90aGVyIGV4cG9ydHMgdGhhbiB0byBTVkdzXHJcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUuem9vbSA9IDE7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAvLyBTZXQgdGhlIHpvb20gYWNjb3JkaW5nbHlcclxuICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoem9vbUNhbGxiYWNrLCBwYXJzZUZsb2F0KGV4cG9ydE9wdGlvbnMuc2NhbGUpKTtcclxuXHJcbiAgICAvLyBHZXQgdGhlIGNsaXAgcmVnaW9uIGZvciB0aGUgcGFnZVxyXG4gICAgY29uc3QgeyBoZWlnaHQsIHdpZHRoLCB4LCB5IH0gPSBhd2FpdCBnZXRDbGlwUmVnaW9uKHBhZ2UpO1xyXG5cclxuICAgIGlmICghaXNTVkcpIHtcclxuICAgICAgLy8gU2V0IHRoZSBmaW5hbCB2aWV3cG9ydCBub3cgdGhhdCB3ZSBoYXZlIHRoZSByZWFsIGhlaWdodFxyXG4gICAgICBhd2FpdCBwYWdlLnNldFZpZXdwb3J0KHtcclxuICAgICAgICB3aWR0aDogTWF0aC5yb3VuZCh3aWR0aCksXHJcbiAgICAgICAgaGVpZ2h0OiBNYXRoLnJvdW5kKGhlaWdodCksXHJcbiAgICAgICAgZGV2aWNlU2NhbGVGYWN0b3I6IHBhcnNlRmxvYXQoZXhwb3J0T3B0aW9ucy5zY2FsZSlcclxuICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgbGV0IGRhdGE7XHJcbiAgICAvLyBSQVNURVJJWkFUSU9OXHJcbiAgICBpZiAoZXhwb3J0T3B0aW9ucy50eXBlID09PSAnc3ZnJykge1xyXG4gICAgICAvLyBTVkdcclxuICAgICAgZGF0YSA9IGF3YWl0IGNyZWF0ZVNWRyhwYWdlKTtcclxuICAgIH0gZWxzZSBpZiAoZXhwb3J0T3B0aW9ucy50eXBlID09PSAncG5nJyB8fCBleHBvcnRPcHRpb25zLnR5cGUgPT09ICdqcGVnJykge1xyXG4gICAgICAvLyBQTkcgb3IgSlBFR1xyXG4gICAgICBkYXRhID0gYXdhaXQgY3JlYXRlSW1hZ2UoXHJcbiAgICAgICAgcGFnZSxcclxuICAgICAgICBleHBvcnRPcHRpb25zLnR5cGUsXHJcbiAgICAgICAgJ2Jhc2U2NCcsXHJcbiAgICAgICAge1xyXG4gICAgICAgICAgd2lkdGg6IHZpZXdwb3J0V2lkdGgsXHJcbiAgICAgICAgICBoZWlnaHQ6IHZpZXdwb3J0SGVpZ2h0LFxyXG4gICAgICAgICAgeCxcclxuICAgICAgICAgIHlcclxuICAgICAgICB9LFxyXG4gICAgICAgIGV4cG9ydE9wdGlvbnMucmFzdGVyaXphdGlvblRpbWVvdXRcclxuICAgICAgKTtcclxuICAgIH0gZWxzZSBpZiAoZXhwb3J0T3B0aW9ucy50eXBlID09PSAncGRmJykge1xyXG4gICAgICAvLyBQREZcclxuICAgICAgZGF0YSA9IGF3YWl0IGNyZWF0ZVBERihwYWdlLCB2aWV3cG9ydEhlaWdodCwgdmlld3BvcnRXaWR0aCwgJ2Jhc2U2NCcpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgIGBbZXhwb3J0XSBVbnN1cHBvcnRlZCBvdXRwdXQgZm9ybWF0ICR7ZXhwb3J0T3B0aW9ucy50eXBlfS5gXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRGVzdHJveSBvbGQgY2hhcnRzIGFmdGVyIHRoZSBleHBvcnQgaXMgZG9uZVxyXG4gICAgYXdhaXQgcGFnZS5ldmFsdWF0ZSgoKSA9PiB7XHJcbiAgICAgIC8vIFdlIGFyZSBub3QgZ3VhcmFudGVlZCB0aGF0IEhpZ2hjaGFydHMgaXMgbG9hZGVkLCBlLGcsIHdoZW4gZG9pbmcgU1ZHXHJcbiAgICAgIC8vIGV4cG9ydHNcclxuICAgICAgaWYgKHR5cGVvZiBIaWdoY2hhcnRzICE9PSAndW5kZWZpbmVkJykge1xyXG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgIGNvbnN0IG9sZENoYXJ0cyA9IEhpZ2hjaGFydHMuY2hhcnRzO1xyXG5cclxuICAgICAgICAvLyBDaGVjayBpbiBhbnkgYWxyZWFkeSBleGlzdGluZyBjaGFydHNcclxuICAgICAgICBpZiAoQXJyYXkuaXNBcnJheShvbGRDaGFydHMpICYmIG9sZENoYXJ0cy5sZW5ndGgpIHtcclxuICAgICAgICAgIC8vIERlc3Ryb3kgb2xkIGNoYXJ0c1xyXG4gICAgICAgICAgZm9yIChjb25zdCBvbGRDaGFydCBvZiBvbGRDaGFydHMpIHtcclxuICAgICAgICAgICAgb2xkQ2hhcnQgJiYgb2xkQ2hhcnQuZGVzdHJveSgpO1xyXG4gICAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgICAgSGlnaGNoYXJ0cy5jaGFydHMuc2hpZnQoKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG5cclxuICAgIGF3YWl0IGNsZWFySW5qZWN0ZWQocGFnZSk7XHJcbiAgICByZXR1cm4gZGF0YTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgYXdhaXQgY2xlYXJJbmplY3RlZChwYWdlKTtcclxuICAgIHJldHVybiBlcnJvcjtcclxuICB9XHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IGNzc1RlbXBsYXRlIGZyb20gJy4vY3NzLmpzJztcclxuXHJcbmV4cG9ydCBkZWZhdWx0IChjaGFydCkgPT4gYFxyXG48IURPQ1RZUEUgaHRtbD5cclxuPGh0bWwgbGFuZz0nZW4tVVMnPlxyXG4gIDxoZWFkPlxyXG4gICAgPG1ldGEgaHR0cC1lcXVpdj1cIkNvbnRlbnQtVHlwZVwiIGNvbnRlbnQ9XCJ0ZXh0L2h0bWw7IGNoYXJzZXQ9dXRmLThcIj5cclxuICAgIDx0aXRsZT5IaWdoY2FydHMgRXhwb3J0PC90aXRsZT5cclxuICA8L2hlYWQ+XHJcbiAgPHN0eWxlPlxyXG4gICAgJHtjc3NUZW1wbGF0ZSgpfVxyXG4gIDwvc3R5bGU+XHJcbiAgPGJvZHk+XHJcbiAgICA8ZGl2IGlkPVwiY2hhcnQtY29udGFpbmVyXCI+XHJcbiAgICAgICR7Y2hhcnR9XHJcbiAgICA8L2Rpdj5cclxuICA8L2JvZHk+XHJcbjwvaHRtbD5cclxuXHJcbmA7XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgUG9vbCB9IGZyb20gJ3Rhcm4nO1xyXG5pbXBvcnQgeyB2NCBhcyB1dWlkIH0gZnJvbSAndXVpZCc7XHJcblxyXG5pbXBvcnQge1xyXG4gIGNsb3NlIGFzIGJyb3dzZXJDbG9zZSxcclxuICBjcmVhdGUgYXMgY3JlYXRlQnJvd3NlcixcclxuICBuZXdQYWdlIGFzIGJyb3dzZXJOZXdQYWdlLFxyXG4gIGNsZWFyUGFnZVxyXG59IGZyb20gJy4vYnJvd3Nlci5qcyc7XHJcbmltcG9ydCBwdXBwZXRlZXJFeHBvcnQgZnJvbSAnLi9leHBvcnQuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgbWVhc3VyZVRpbWUgfSBmcm9tICcuL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG5sZXQgcGVyZm9ybWVkRXhwb3J0cyA9IDA7XHJcbmxldCBleHBvcnRBdHRlbXB0cyA9IDA7XHJcbmxldCB0aW1lU3BlbnQgPSAwO1xyXG5sZXQgZHJvcHBlZEV4cG9ydHMgPSAwO1xyXG5sZXQgc3BlbnRBdmVyYWdlID0gMDtcclxubGV0IHBvb2xDb25maWcgPSB7fTtcclxuXHJcbi8vIFRoZSBwb29sIGluc3RhbmNlXHJcbmxldCBwb29sID0gZmFsc2U7XHJcblxyXG4vLyBDdXN0b20gcHVwcGV0ZWVyIGFyZ3VtZW50c1xyXG5sZXQgcHVwcGV0ZWVyQXJncztcclxuXHJcbmNvbnN0IGZhY3RvcnkgPSB7XHJcbiAgLyoqXHJcbiAgICogQ3JlYXRlcyBhIG5ldyB3b3JrZXIgcGFnZSBmb3IgdGhlIGV4cG9ydCBwb29sLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge09iamVjdH0gLSBBbiBvYmplY3QgY29udGFpbmluZyB0aGUgd29ya2VyIElELCBhIHJlZmVyZW5jZSB0byB0aGVcclxuICAgKiBicm93c2VyIHBhZ2UsIGFuZCBpbml0aWFsIHdvcmsgY291bnQuXHJcbiAgICpcclxuICAgKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gLSBJZiB0aGVyZSdzIGFuIGVycm9yIGR1cmluZyB0aGUgY3JlYXRpb24gb2YgdGhlIG5ld1xyXG4gICAqIHBhZ2UuXHJcbiAgICovXHJcbiAgY3JlYXRlOiBhc3luYyAoKSA9PiB7XHJcbiAgICBsZXQgcGFnZSA9IGZhbHNlO1xyXG5cclxuICAgIGNvbnN0IGlkID0gdXVpZCgpO1xyXG4gICAgY29uc3Qgc3RhcnREYXRlID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XHJcblxyXG4gICAgdHJ5IHtcclxuICAgICAgcGFnZSA9IGF3YWl0IGJyb3dzZXJOZXdQYWdlKCk7XHJcblxyXG4gICAgICBpZiAoIXBhZ2UgfHwgcGFnZS5pc0Nsb3NlZCgpKSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdUaGUgcGFnZSBpcyBpbnZhbGlkIG9yIGNsb3NlZC4nKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgbG9nKFxyXG4gICAgICAgIDMsXHJcbiAgICAgICAgYFtwb29sXSBTdWNjZXNzZnVsbHkgY3JlYXRlZCBhIHdvcmtlciAke2lkfSAtIHRvb2sgJHtcclxuICAgICAgICAgIG5ldyBEYXRlKCkuZ2V0VGltZSgpIC0gc3RhcnREYXRlXHJcbiAgICAgICAgfSBtcy5gXHJcbiAgICAgICk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ0Vycm9yIGVuY291bnRlcmVkIHdoZW4gY3JlYXRpbmcgYSBuZXcgcGFnZS4nXHJcbiAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiB7XHJcbiAgICAgIGlkLFxyXG4gICAgICBwYWdlLFxyXG4gICAgICAvLyBUcnkgdG8gZGlzdHJpYnV0ZSB0aGUgaW5pdGlhbCB3b3JrIGNvdW50XHJcbiAgICAgIHdvcmtDb3VudDogTWF0aC5yb3VuZChNYXRoLnJhbmRvbSgpICogKHBvb2xDb25maWcud29ya0xpbWl0IC8gMikpXHJcbiAgICB9O1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFZhbGlkYXRlcyBhIHdvcmtlciBwYWdlIGluIHRoZSBleHBvcnQgcG9vbCwgY2hlY2tpbmcgaWYgaXQgaGFzIGV4Y2VlZGVkXHJcbiAgICogdGhlIHdvcmsgbGltaXQuXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge09iamVjdH0gd29ya2VySGFuZGxlIC0gVGhlIGhhbmRsZSB0byB0aGUgd29ya2VyLCBjb250YWluaW5nIHRoZVxyXG4gICAqIHdvcmtlcidzIElELCBhIHJlZmVyZW5jZSB0byB0aGUgYnJvd3NlciBwYWdlLCBhbmQgd29yayBjb3VudC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHtib29sZWFufSAtIFJldHVybnMgdHJ1ZSBpZiB0aGUgd29ya2VyIGlzIHZhbGlkIGFuZCB3aXRoaW5cclxuICAgKiB0aGUgd29yayBsaW1pdDsgb3RoZXJ3aXNlLCByZXR1cm5zIGZhbHNlLlxyXG4gICAqL1xyXG4gIHZhbGlkYXRlOiBhc3luYyAod29ya2VySGFuZGxlKSA9PiB7XHJcbiAgICBpZiAoXHJcbiAgICAgIHBvb2xDb25maWcud29ya0xpbWl0ICYmXHJcbiAgICAgICsrd29ya2VySGFuZGxlLndvcmtDb3VudCA+IHBvb2xDb25maWcud29ya0xpbWl0XHJcbiAgICApIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDMsXHJcbiAgICAgICAgYFtwb29sXSBXb3JrZXIgZmFpbGVkIHZhbGlkYXRpb246IGV4Y2VlZGVkIHdvcmsgbGltaXQgKGxpbWl0IGlzICR7cG9vbENvbmZpZy53b3JrTGltaXR9KS5gXHJcbiAgICAgICk7XHJcbiAgICAgIHJldHVybiBmYWxzZTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBDbGVhciBwYWdlXHJcbiAgICBhd2FpdCBjbGVhclBhZ2Uod29ya2VySGFuZGxlLnBhZ2UsIHRydWUpO1xyXG4gICAgcmV0dXJuIHRydWU7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogRGVzdHJveXMgYSB3b3JrZXIgZW50cnkgaW4gdGhlIGV4cG9ydCBwb29sLCBjbG9zaW5nIGl0cyBhc3NvY2lhdGVkIHBhZ2UuXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge09iamVjdH0gd29ya2VySGFuZGxlIC0gVGhlIGhhbmRsZSB0byB0aGUgd29ya2VyLCBjb250YWluaW5nXHJcbiAgICogdGhlIHdvcmtlcidzIElEIGFuZCBhIHJlZmVyZW5jZSB0byB0aGUgYnJvd3NlciBwYWdlLlxyXG4gICAqL1xyXG4gIGRlc3Ryb3k6ICh3b3JrZXJIYW5kbGUpID0+IHtcclxuICAgIGxvZygzLCBgW3Bvb2xdIERlc3Ryb3lpbmcgcG9vbCBlbnRyeSAke3dvcmtlckhhbmRsZS5pZH0uYCk7XHJcblxyXG4gICAgaWYgKHdvcmtlckhhbmRsZS5wYWdlKSB7XHJcbiAgICAgIC8vIFdlIGRvbid0IHJlYWxseSBuZWVkIHRvIHdhaXQgYXJvdW5kIGZvciB0aGlzLlxyXG4gICAgICB3b3JrZXJIYW5kbGUucGFnZS5jbG9zZSgpO1xyXG4gICAgfVxyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyB0aGUgZXhwb3J0IHBvb2wgd2l0aCB0aGUgcHJvdmlkZWQgY29uZmlndXJhdGlvbiwgY3JlYXRpbmdcclxuICogYSBicm93c2VyIGluc3RhbmNlIGFuZCBzZXR0aW5nIHVwIHdvcmtlciByZXNvdXJjZXMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjb25maWcgLSBDb25maWd1cmF0aW9uIG9wdGlvbnMgZm9yIHRoZSBleHBvcnQgcG9vbCBhbG9uZ1xyXG4gKiB3aXRoIGN1c3RvbSBwdXBwZXRlZXIgYXJndW1lbnRzIGZvciB0aGUgcHVwcGV0ZWVyLmxhdW5jaCBmdW5jdGlvbi5cclxuICovXHJcbmV4cG9ydCBjb25zdCBpbml0UG9vbCA9IGFzeW5jIChjb25maWcpID0+IHtcclxuICAvLyBGb3IgdGhlIG1vZHVsZSBzY29wZSB1c2FnZVxyXG4gIHBvb2xDb25maWcgPSBjb25maWcgJiYgY29uZmlnLnBvb2wgPyB7IC4uLmNvbmZpZy5wb29sIH0gOiB7fTtcclxuXHJcbiAgLy8gQXR0YWNoIHByb2Nlc3MnIGV4aXQgbGlzdGVuZXJzXHJcbiAgaWYgKHBvb2xDb25maWcubGlzdGVuVG9Qcm9jZXNzRXhpdHMpIHtcclxuICAgIGF0dGFjaFByb2Nlc3NFeGl0TGlzdGVuZXJzKCk7XHJcbiAgfVxyXG5cclxuICAvLyBUaGUgbmV3ZXN0IHB1cHBldGVlciBhcmd1bWVudHMgZm9yIHRoZSBicm93c2VyIGNyZWF0aW9uXHJcbiAgcHVwcGV0ZWVyQXJncyA9IGNvbmZpZy5wdXBwZXRlZXJBcmdzO1xyXG5cclxuICAvLyBDcmVhdGUgYSBicm93c2VyIGluc3RhbmNlXHJcbiAgYXdhaXQgY3JlYXRlQnJvd3NlcihwdXBwZXRlZXJBcmdzKTtcclxuXHJcbiAgbG9nKFxyXG4gICAgMyxcclxuICAgIGBbcG9vbF0gSW5pdGlhbGl6aW5nIHBvb2wgd2l0aCB3b3JrZXJzOiBtaW4gJHtwb29sQ29uZmlnLm1pbldvcmtlcnN9LCBtYXggJHtwb29sQ29uZmlnLm1heFdvcmtlcnN9LmBcclxuICApO1xyXG5cclxuICBpZiAocG9vbCkge1xyXG4gICAgcmV0dXJuIGxvZyhcclxuICAgICAgNCxcclxuICAgICAgJ1twb29sXSBBbHJlYWR5IGluaXRpYWxpemVkLCBwbGVhc2Uga2lsbCBpdCBiZWZvcmUgY3JlYXRpbmcgYSBuZXcgb25lLidcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICBpZiAocGFyc2VJbnQocG9vbENvbmZpZy5taW5Xb3JrZXJzKSA+IHBhcnNlSW50KHBvb2xDb25maWcubWF4V29ya2VycykpIHtcclxuICAgIHBvb2xDb25maWcubWluV29ya2VycyA9IHBvb2xDb25maWcubWF4V29ya2VycztcclxuICB9XHJcblxyXG4gIHRyeSB7XHJcbiAgICAvLyBDcmVhdGUgYSBwb29sIGFsb25nIHdpdGggYSBtaW5pbWFsIG51bWJlciBvZiByZXNvdXJjZXNcclxuICAgIHBvb2wgPSBuZXcgUG9vbCh7XHJcbiAgICAgIC8vIEdldCB0aGUgY3JlYXRlL3ZhbGlkYXRlL2Rlc3Ryb3kvbG9nIGZ1bmN0aW9uc1xyXG4gICAgICAuLi5mYWN0b3J5LFxyXG4gICAgICBtaW46IHBhcnNlSW50KHBvb2xDb25maWcubWluV29ya2VycyksXHJcbiAgICAgIG1heDogcGFyc2VJbnQocG9vbENvbmZpZy5tYXhXb3JrZXJzKSxcclxuICAgICAgYWNxdWlyZVRpbWVvdXRNaWxsaXM6IHBvb2xDb25maWcuYWNxdWlyZVRpbWVvdXQsXHJcbiAgICAgIGNyZWF0ZVRpbWVvdXRNaWxsaXM6IHBvb2xDb25maWcuY3JlYXRlVGltZW91dCxcclxuICAgICAgZGVzdHJveVRpbWVvdXRNaWxsaXM6IHBvb2xDb25maWcuZGVzdHJveVRpbWVvdXQsXHJcbiAgICAgIGlkbGVUaW1lb3V0TWlsbGlzOiBwb29sQ29uZmlnLmlkbGVUaW1lb3V0LFxyXG4gICAgICBjcmVhdGVSZXRyeUludGVydmFsTWlsbGlzOiBwb29sQ29uZmlnLmNyZWF0ZVJldHJ5SW50ZXJ2YWwsXHJcbiAgICAgIHJlYXBJbnRlcnZhbE1pbGxpczogcG9vbENvbmZpZy5yZWFwZXJJbnRlcnZhbCxcclxuICAgICAgcHJvcGFnYXRlQ3JlYXRlRXJyb3I6IGZhbHNlXHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBTZXQgZXZlbnRzXHJcbiAgICBwb29sLm9uKCdyZWxlYXNlJywgYXN5bmMgKHJlc291cmNlKSA9PiB7XHJcbiAgICAgIC8vIENsZWFyIHBhZ2VcclxuICAgICAgYXdhaXQgY2xlYXJQYWdlKHJlc291cmNlLnBhZ2UsIGZhbHNlKTtcclxuICAgICAgbG9nKDQsIGBbcG9vbF0gUmVsZWFzaW5nIGEgd29ya2VyIHdpdGggSUQgJHtyZXNvdXJjZS5pZH0uYCk7XHJcbiAgICB9KTtcclxuXHJcbiAgICBwb29sLm9uKCdkZXN0cm95U3VjY2VzcycsIChldmVudElkLCByZXNvdXJjZSkgPT4ge1xyXG4gICAgICBsb2coNCwgYFtwb29sXSBEZXN0cm95ZWQgYSB3b3JrZXIgd2l0aCBJRCAke3Jlc291cmNlLmlkfS5gKTtcclxuICAgIH0pO1xyXG5cclxuICAgIGNvbnN0IGluaXRpYWxSZXNvdXJjZXMgPSBbXTtcclxuICAgIC8vIENyZWF0ZSBhbiBpbml0aWFsIG51bWJlciBvZiByZXNvdXJjZXNcclxuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgcG9vbENvbmZpZy5taW5Xb3JrZXJzOyBpKyspIHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBjb25zdCByZXNvdXJjZSA9IGF3YWl0IHBvb2wuYWNxdWlyZSgpLnByb21pc2U7XHJcbiAgICAgICAgaW5pdGlhbFJlc291cmNlcy5wdXNoKHJlc291cmNlKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsICdbcG9vbF0gQ291bGQgbm90IGNyZWF0ZSBhbiBpbml0aWFsIHJlc291cmNlLicpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmVsZWFzZSB0aGUgaW5pdGlhbCBudW1iZXIgb2YgcmVzb3VyY2VzIGJhY2sgdG8gdGhlIHBvb2xcclxuICAgIGluaXRpYWxSZXNvdXJjZXMuZm9yRWFjaCgocmVzb3VyY2UpID0+IHtcclxuICAgICAgcG9vbC5yZWxlYXNlKHJlc291cmNlKTtcclxuICAgIH0pO1xyXG5cclxuICAgIGxvZyhcclxuICAgICAgMyxcclxuICAgICAgYFtwb29sXSBUaGUgcG9vbCBpcyByZWFkeSR7aW5pdGlhbFJlc291cmNlcy5sZW5ndGggPyBgIHdpdGggJHtpbml0aWFsUmVzb3VyY2VzLmxlbmd0aH0gaW5pdGlhbCByZXNvdXJjZXMgd2FpdGluZy5gIDogJy4nfWBcclxuICAgICk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIC8vIENsb3NlIGJyb3dzZXIgaWYgZm9yIHNvbWUgcmVhc29uIGNhbm5vdCBlc3RhYmxpc2ggdGhlIHBvb2xcclxuICAgIGF3YWl0IGJyb3dzZXJDbG9zZSgpO1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW3Bvb2xdIENvdWxkIG5vdCBjcmVhdGUgdGhlIHBvb2wgb2Ygd29ya2Vycy4nXHJcbiAgICApLnNldEVycm9yKGVycm9yKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogQXR0YWNoZXMgZXhpdCBsaXN0ZW5lcnMgdG8gdGhlIHByb2Nlc3MsIGVuc3VyaW5nIHByb3BlciBjbGVhbnVwIG9mIHJlc291cmNlc1xyXG4gKiBhbmQgdGVybWluYXRpb24gb24gZXhpdCBzaWduYWxzLiBIYW5kbGVzICdleGl0JywgJ1NJR0lOVCcsICdTSUdURVJNJywgYW5kXHJcbiAqICd1bmNhdWdodEV4Y2VwdGlvbicgZXZlbnRzLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGF0dGFjaFByb2Nlc3NFeGl0TGlzdGVuZXJzKCkge1xyXG4gIGxvZygzLCAnW3Bvb2xdIEF0dGFjaGluZyBleGl0IGxpc3RlbmVycyB0byB0aGUgcHJvY2Vzcy4nKTtcclxuXHJcbiAgLy8gS2lsbCBhbGwgcG9vbCByZXNvdXJjZXMgb24gZXhpdFxyXG4gIHByb2Nlc3Mub24oJ2V4aXQnLCBhc3luYyAoY29kZSkgPT4ge1xyXG4gICAgbG9nKDQsIGBQcm9jZXNzIGV4aXRlZCB3aXRoIGNvZGUgJHtjb2RlfS5gKTtcclxuICAgIGF3YWl0IGtpbGxQb29sKCk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSBTSUdJTlRcclxuICBwcm9jZXNzLm9uKCdTSUdJTlQnLCAobmFtZSwgY29kZSkgPT4ge1xyXG4gICAgbG9nKDQsIGBUaGUgJHtuYW1lfSBldmVudCB3aXRoIGNvZGU6ICR7Y29kZX0uYCk7XHJcbiAgICBwcm9jZXNzLmV4aXQoMSk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSBTSUdURVJNXHJcbiAgcHJvY2Vzcy5vbignU0lHVEVSTScsIChuYW1lLCBjb2RlKSA9PiB7XHJcbiAgICBsb2coNCwgYFRoZSAke25hbWV9IGV2ZW50IHdpdGggY29kZTogJHtjb2RlfS5gKTtcclxuICAgIHByb2Nlc3MuZXhpdCgxKTtcclxuICB9KTtcclxuXHJcbiAgLy8gSGFuZGxlciBmb3IgdGhlIHVuY2F1Z2h0RXhjZXB0aW9uXHJcbiAgcHJvY2Vzcy5vbigndW5jYXVnaHRFeGNlcHRpb24nLCBhc3luYyAoZXJyb3IsIG5hbWUpID0+IHtcclxuICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFRoZSAke25hbWV9IGVycm9yLmApO1xyXG4gICAgYXdhaXQga2lsbFBvb2woKTtcclxuICAgIHByb2Nlc3MuZXhpdCgxKTtcclxuICB9KTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEtpbGxzIGFsbCB3b3JrZXJzIGluIHRoZSBwb29sLCBkZXN0cm95cyB0aGUgcG9vbCwgYW5kIGNsb3NlcyB0aGUgYnJvd3NlclxyXG4gKiBpbnN0YW5jZS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIGFmdGVyIHRoZSB3b3JrZXJzIGFyZVxyXG4gKiBraWxsZWQsIHRoZSBwb29sIGlzIGRlc3Ryb3llZCwgYW5kIHRoZSBicm93c2VyIGlzIGNsb3NlZC5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBraWxsUG9vbCgpIHtcclxuICBsb2coMywgJ1twb29sXSBLaWxsaW5nIGFsbCBwb29sIHdvcmtlcnMgYW5kIGJyb3dzZXIsIGlmIGFueSBleGlzdC4nKTtcclxuXHJcbiAgLy8gUmV0dXJuIHRydWUgd2hlbiB0aGUgcG9vbCBpcyBhbHJlYWR5IGRlc3Ryb3llZFxyXG4gIGlmIChwb29sPy5kZXN0cm95ZWQpIHtcclxuICAgIC8vIENsb3NlIHRoZSBicm93c2VyIGluc3RhbmNlIGlmIHN0aWxsIGNvbm5lY3RlZFxyXG4gICAgcmV0dXJuIGJyb3dzZXJDbG9zZSgpO1xyXG4gIH1cclxuXHJcbiAgLy8gSWYgc3RpbGwgYWxpdmUsIGRlc3Ryb3kgdGhlIHBvb2wgb2YgcGFnZXMgYmVmb3JlIGNsb3NpbmcgYSBicm93c2VyXHJcbiAgaWYgKHBvb2wpIHtcclxuICAgIGF3YWl0IHBvb2wuZGVzdHJveSgpO1xyXG4gICAgbG9nKDQsICdbYnJvd3Nlcl0gRGVzdHJveWVkIHRoZSBwb29sIG9mIHJlc291cmNlcy4nKTtcclxuICB9XHJcblxyXG4gIC8vIENsb3NlIHRoZSBicm93c2VyIGluc3RhbmNlXHJcbiAgcmV0dXJuIGJyb3dzZXJDbG9zZSgpO1xyXG59XHJcblxyXG4vKipcclxuICogUHJvY2Vzc2VzIHRoZSBleHBvcnQgd29yayB1c2luZyBhIHdvcmtlciBmcm9tIHRoZSBwb29sLiBBY3F1aXJlcyBhIHdvcmtlclxyXG4gKiBoYW5kbGUgZnJvbSB0aGUgcG9vbCwgcGVyZm9ybXMgdGhlIGV4cG9ydCB1c2luZyBwdXBwZXRlZXIsIGFuZCByZWxlYXNlc1xyXG4gKiB0aGUgd29ya2VyIGhhbmRsZSBiYWNrIHRvIHRoZSBwb29sLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY2hhcnQgLSBUaGUgY2hhcnQgZGF0YSBvciBjb25maWd1cmF0aW9uIHRvIGJlIGV4cG9ydGVkLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIEV4cG9ydCBvcHRpb25zIGFuZCBjb25maWd1cmF0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aXRoIHRoZSBleHBvcnQgcmVzdWx0YW5kXHJcbiAqIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBJZiBhbiBlcnJvciBvY2N1cnMgZHVyaW5nIHRoZSBleHBvcnQgcHJvY2Vzcy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBwb3N0V29yayA9IGFzeW5jIChjaGFydCwgb3B0aW9ucykgPT4ge1xyXG4gIGxldCB3b3JrZXJIYW5kbGU7XHJcblxyXG4gIHRyeSB7XHJcbiAgICBsb2coNCwgJ1twb29sXSBXb3JrIHJlY2VpdmVkLCBzdGFydGluZyB0byBwcm9jZXNzLicpO1xyXG5cclxuICAgICsrZXhwb3J0QXR0ZW1wdHM7XHJcbiAgICBpZiAocG9vbENvbmZpZy5iZW5jaG1hcmtpbmcpIHtcclxuICAgICAgZ2V0UG9vbEluZm8oKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoIXBvb2wpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdXb3JrIHJlY2VpdmVkLCBidXQgcG9vbCBoYXMgbm90IGJlZW4gc3RhcnRlZC4nKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBBY3F1aXJlIHRoZSB3b3JrZXIgYWxvbmcgd2l0aCB0aGUgaWQgb2YgcmVzb3VyY2UgYW5kIHdvcmsgY291bnRcclxuICAgIHRyeSB7XHJcbiAgICAgIGxvZyg0LCAnW3Bvb2xdIEFjcXVpcmluZyBhIHdvcmtlciBoYW5kbGUuJyk7XHJcbiAgICAgIGNvbnN0IGFjcXVpcmVDb3VudGVyID0gbWVhc3VyZVRpbWUoKTtcclxuICAgICAgd29ya2VySGFuZGxlID0gYXdhaXQgcG9vbC5hY3F1aXJlKCkucHJvbWlzZTtcclxuXHJcbiAgICAgIC8vIENoZWNrIHRoZSBwYWdlIGFjcXVpcmUgdGltZVxyXG4gICAgICBpZiAob3B0aW9ucy5zZXJ2ZXIuYmVuY2htYXJraW5nKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgNSxcclxuICAgICAgICAgIG9wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkXHJcbiAgICAgICAgICAgID8gYFtiZW5jaG1hcmtdIFJlcXVlc3Qgd2l0aCBJRCAke29wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkfSAtYFxyXG4gICAgICAgICAgICA6ICdbYmVuY2htYXJrXScsXHJcbiAgICAgICAgICBgQWNxdWlyZWQgYSB3b3JrZXIgaGFuZGxlOiAke2FjcXVpcmVDb3VudGVyKCl9bXMuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnRXJyb3IgZW5jb3VudGVyZWQgd2hlbiBhY3F1aXJpbmcgYW4gYXZhaWxhYmxlIGVudHJ5LidcclxuICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICB9XHJcbiAgICBsb2coNCwgJ1twb29sXSBBY3F1aXJlZCBhIHdvcmtlciBoYW5kbGUuJyk7XHJcblxyXG4gICAgaWYgKCF3b3JrZXJIYW5kbGUucGFnZSkge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ1Jlc29sdmVkIHdvcmtlciBwYWdlIGlzIGludmFsaWQ6IHRoZSBwb29sIHNldHVwIGlzIHdvbmt5LidcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBTYXZlIHRoZSBzdGFydCB0aW1lXHJcbiAgICBsZXQgd29ya1N0YXJ0ID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XHJcblxyXG4gICAgbG9nKDQsIGBbcG9vbF0gU3RhcnRpbmcgd29yayBvbiBwb29sIGVudHJ5IHdpdGggSUQgJHt3b3JrZXJIYW5kbGUuaWR9LmApO1xyXG5cclxuICAgIC8vIFBlcmZvcm0gYW4gZXhwb3J0IG9uIGEgcHVwcGV0ZWVyIGxldmVsXHJcbiAgICBjb25zdCBleHBvcnRDb3VudGVyID0gbWVhc3VyZVRpbWUoKTtcclxuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHB1cHBldGVlckV4cG9ydCh3b3JrZXJIYW5kbGUucGFnZSwgY2hhcnQsIG9wdGlvbnMpO1xyXG5cclxuICAgIC8vIENoZWNrIGlmIGl0J3MgYW4gZXJyb3JcclxuICAgIGlmIChyZXN1bHQgaW5zdGFuY2VvZiBFcnJvcikge1xyXG4gICAgICAvLyBUT0RPOiBJZiB0aGUgZXhwb3J0IGZhaWxlZCBiZWNhdXNlIHB1cHBldGVlciB0aW1lZCBvdXQsIHdlIG5lZWQgdG8gZm9yY2Uga2lsbCB0aGUgd29ya2VyIHNvIHdlIGdldCBhIG5ldyBwYWdlLiBUaGF0IG5lZWRzIHRvIGJlIGhhbmRsZWQgYmV0dGVyIHRoYW4gdGhpcyBoYWNrLlxyXG4gICAgICBpZiAocmVzdWx0Lm1lc3NhZ2UgPT09ICdSYXN0ZXJpemF0aW9uIHRpbWVvdXQnKSB7XHJcbiAgICAgICAgd29ya2VySGFuZGxlLnBhZ2UuY2xvc2UoKTtcclxuICAgICAgICB3b3JrZXJIYW5kbGUucGFnZSA9IGF3YWl0IGJyb3dzZXJOZXdQYWdlKCk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignRXJyb3IgZW5jb3VudGVyZWQgZHVyaW5nIGV4cG9ydC4nKS5zZXRFcnJvcihcclxuICAgICAgICByZXN1bHRcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBDaGVjayB0aGUgUHVwcGV0ZWVyIGV4cG9ydCB0aW1lXHJcbiAgICBpZiAob3B0aW9ucy5zZXJ2ZXIuYmVuY2htYXJraW5nKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICA1LFxyXG4gICAgICAgIG9wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkXHJcbiAgICAgICAgICA/IGBbYmVuY2htYXJrXSBSZXF1ZXN0IHdpdGggSUQgJHtvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZH0gLWBcclxuICAgICAgICAgIDogJ1tiZW5jaG1hcmtdJyxcclxuICAgICAgICBgRXhwb3J0ZWQgYSBjaGFydCBzdWNlc3NmdWxseTogJHtleHBvcnRDb3VudGVyKCl9bXMuYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFJlbGVhc2UgdGhlIHJlc291cmNlIGJhY2sgdG8gdGhlIHBvb2xcclxuICAgIHBvb2wucmVsZWFzZSh3b3JrZXJIYW5kbGUpO1xyXG5cclxuICAgIC8vIFVzZWQgZm9yIHN0YXRpc3RpY3MgaW4gYXZlcmFnZVRpbWUgYW5kIHByb2Nlc3NlZFdvcmtDb3VudCwgd2hpY2hcclxuICAgIC8vIGluIHR1cm4gaXMgdXNlZCBieSB0aGUgL2hlYWx0aCByb3V0ZS5cclxuICAgIGNvbnN0IHdvcmtFbmQgPSBuZXcgRGF0ZSgpLmdldFRpbWUoKTtcclxuICAgIGNvbnN0IGV4cG9ydFRpbWUgPSB3b3JrRW5kIC0gd29ya1N0YXJ0O1xyXG4gICAgdGltZVNwZW50ICs9IGV4cG9ydFRpbWU7XHJcbiAgICBzcGVudEF2ZXJhZ2UgPSB0aW1lU3BlbnQgLyArK3BlcmZvcm1lZEV4cG9ydHM7XHJcblxyXG4gICAgbG9nKDQsIGBbcG9vbF0gV29yayBjb21wbGV0ZWQgaW4gJHtleHBvcnRUaW1lfSBtcy5gKTtcclxuXHJcbiAgICAvLyBPdGhlcndpc2UgcmV0dXJuIHRoZSByZXN1bHRcclxuICAgIHJldHVybiB7XHJcbiAgICAgIHJlc3VsdCxcclxuICAgICAgb3B0aW9uc1xyXG4gICAgfTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgKytkcm9wcGVkRXhwb3J0cztcclxuXHJcbiAgICBpZiAod29ya2VySGFuZGxlKSB7XHJcbiAgICAgIHBvb2wucmVsZWFzZSh3b3JrZXJIYW5kbGUpO1xyXG4gICAgfVxyXG5cclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihgW3Bvb2xdIEluIHBvb2wucG9zdFdvcms6ICR7ZXJyb3IubWVzc2FnZX1gKS5zZXRFcnJvcihcclxuICAgICAgZXJyb3JcclxuICAgICk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyB0aGUgY3VycmVudCBwb29sIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fG51bGx9IFRoZSBjdXJyZW50IHBvb2wgaW5zdGFuY2UgaWYgaW5pdGlhbGl6ZWQsIG9yIG51bGxcclxuICogaWYgdGhlIHBvb2wgaGFzIG5vdCBiZWVuIGNyZWF0ZWQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0UG9vbCgpIHtcclxuICByZXR1cm4gcG9vbDtcclxufVxyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyBwb29sIGluZm9ybWF0aW9uIGluIEpTT04gZm9ybWF0LCBpbmNsdWRpbmcgbWluaW11bSBhbmQgbWF4aW11bVxyXG4gKiB3b3JrZXJzLCBhdmFpbGFibGUgd29ya2Vycywgd29ya2VycyBpbiB1c2UsIGFuZCBwZW5kaW5nIGFjcXVpcmUgcmVxdWVzdHMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFBvb2wgaW5mb3JtYXRpb24gaW4gSlNPTiBmb3JtYXQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0UG9vbEluZm9KU09OID0gKCkgPT4gKHtcclxuICBtaW46IHBvb2wubWluLFxyXG4gIG1heDogcG9vbC5tYXgsXHJcbiAgYXZhaWxhYmxlOiBwb29sLm51bUZyZWUoKSxcclxuICBpblVzZTogcG9vbC5udW1Vc2VkKCksXHJcbiAgcGVuZGluZ0FjcXVpcmU6IHBvb2wubnVtUGVuZGluZ0FjcXVpcmVzKClcclxufSk7XHJcblxyXG4vKipcclxuICogTG9ncyBpbmZvcm1hdGlvbiBhYm91dCB0aGUgY3VycmVudCBzdGF0ZSBvZiB0aGUgcG9vbCwgaW5jbHVkaW5nIHRoZSBtaW5pbXVtXHJcbiAqIGFuZCBtYXhpbXVtIHdvcmtlcnMsIGF2YWlsYWJsZSB3b3JrZXJzLCB3b3JrZXJzIGluIHVzZSwgYW5kIHBlbmRpbmcgYWNxdWlyZVxyXG4gKiByZXF1ZXN0cy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRQb29sSW5mbygpIHtcclxuICBjb25zdCB7IG1pbiwgbWF4IH0gPSBwb29sO1xyXG5cclxuICBsb2coNSwgYFtwb29sXSBUaGUgbWluaW11bSBudW1iZXIgb2YgcmVzb3VyY2VzIGFsbG93ZWQgYnkgcG9vbDogJHttaW59LmApO1xyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBtYXhpbXVtIG51bWJlciBvZiByZXNvdXJjZXMgYWxsb3dlZCBieSBwb29sOiAke21heH0uYCk7XHJcbiAgbG9nKFxyXG4gICAgNSxcclxuICAgIGBbcG9vbF0gVGhlIG51bWJlciBvZiByZXNvdXJjZXMgdGhhdCBhcmUgY3VycmVudGx5IGF2YWlsYWJsZTogJHtwb29sLm51bUZyZWUoKX0uYFxyXG4gICk7XHJcbiAgbG9nKFxyXG4gICAgNSxcclxuICAgIGBbcG9vbF0gVGhlIG51bWJlciBvZiByZXNvdXJjZXMgdGhhdCBhcmUgY3VycmVudGx5IGFjcXVpcmVkOiAke3Bvb2wubnVtVXNlZCgpfS5gXHJcbiAgKTtcclxuICBsb2coXHJcbiAgICA1LFxyXG4gICAgYFtwb29sXSBUaGUgbnVtYmVyIG9mIGNhbGxlcnMgd2FpdGluZyB0byBhY3F1aXJlIGEgcmVzb3VyY2U6ICR7cG9vbC5udW1QZW5kaW5nQWNxdWlyZXMoKX0uYFxyXG4gICk7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBpbml0UG9vbCxcclxuICBraWxsUG9vbCxcclxuICBwb3N0V29yayxcclxuICBnZXRQb29sLFxyXG4gIGdldFBvb2xJbmZvLFxyXG4gIGdldFBvb2xJbmZvSlNPTixcclxuICB3b3JrQXR0ZW1wdHM6ICgpID0+IGV4cG9ydEF0dGVtcHRzLFxyXG4gIGRyb3BwZWRXb3JrOiAoKSA9PiBkcm9wcGVkRXhwb3J0cyxcclxuICBhdmVyYWdlVGltZTogKCkgPT4gc3BlbnRBdmVyYWdlLFxyXG4gIHByb2Nlc3NlZFdvcmtDb3VudDogKCkgPT4gcGVyZm9ybWVkRXhwb3J0c1xyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYywgd3JpdGVGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuXHJcbmltcG9ydCB7IGdldE9wdGlvbnMsIGluaXRFeHBvcnRTZXR0aW5ncyB9IGZyb20gJy4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IGtpbGxQb29sLCBwb3N0V29yayB9IGZyb20gJy4vcG9vbC5qcyc7XHJcbmltcG9ydCB7XHJcbiAgZml4VHlwZSxcclxuICBoYW5kbGVSZXNvdXJjZXMsXHJcbiAgaXNDb3JyZWN0SlNPTixcclxuICBvcHRpb25zU3RyaW5naWZ5LFxyXG4gIHJvdW5kTnVtYmVyLFxyXG4gIHRvQm9vbGVhbixcclxuICB3cmFwQXJvdW5kXHJcbn0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxubGV0IGFsbG93Q29kZUV4ZWN1dGlvbiA9IGZhbHNlO1xyXG5cclxuLyoqXHJcbiAqIFN0YXJ0cyBhbiBleHBvcnQgcHJvY2Vzcy4gVGhlIGBzZXR0aW5nc2AgY29udGFpbnMgZmluYWwgb3B0aW9ucyBnYXRoZXJlZFxyXG4gKiBmcm9tIGFsbCBwb3NzaWJsZSBzb3VyY2VzIChjb25maWcsIGVudiwgY2xpLCBqc29uKS4gVGhlIGBlbmRDYWxsYmFja2AgaXNcclxuICogY2FsbGVkIHdoZW4gdGhlIGV4cG9ydCBpcyBjb21wbGV0ZWQsIHdpdGggYW4gZXJyb3Igb2JqZWN0IGFzIHRoZSBmaXJzdFxyXG4gKiBhcmd1bWVudCBhbmQgdGhlIHNlY29uZCBjb250YWluaW5nIHRoZSBiYXNlNjQgcmVzcHJlc2VudGF0aW9uIG9mIGEgY2hhcnQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBzZXR0aW5ncyAtIFRoZSBzZXR0aW5ncyBvYmplY3QgY29udGFpbmluZyBleHBvcnRcclxuICogY29uZmlndXJhdGlvbi5cclxuICogQHBhcmFtIHtmdW5jdGlvbn0gZW5kQ2FsbGJhY2sgLSBUaGUgY2FsbGJhY2sgZnVuY3Rpb24gdG8gYmUgaW52b2tlZCB1cG9uXHJcbiAqIGZpbmFsaXppbmcgd29yayBvciB1cG9uIGVycm9yIG9jY3VyYW5jZSBvZiB0aGUgZXhwb3J0aW5nIHByb2Nlc3MuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHt2b2lkfSBUaGlzIGZ1bmN0aW9uIGRvZXMgbm90IHJldHVybiBhIHZhbHVlIGRpcmVjdGx5OyBpbnN0ZWFkLFxyXG4gKiBpdCBjb21tdW5pY2F0ZXMgcmVzdWx0cyB2aWEgdGhlIGVuZENhbGxiYWNrLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHN0YXJ0RXhwb3J0ID0gYXN5bmMgKHNldHRpbmdzLCBlbmRDYWxsYmFjaykgPT4ge1xyXG4gIC8vIFN0YXJ0aW5nIGV4cG9ydGluZyBwcm9jZXNzIG1lc3NhZ2VcclxuICBsb2coNCwgJ1tjaGFydF0gU3RhcnRpbmcgdGhlIGV4cG9ydGluZyBwcm9jZXNzLicpO1xyXG5cclxuICAvLyBJbml0aWFsaXplIG9wdGlvbnNcclxuICBjb25zdCBvcHRpb25zID0gaW5pdEV4cG9ydFNldHRpbmdzKHNldHRpbmdzLCBnZXRPcHRpb25zKCkpO1xyXG5cclxuICAvLyBHZXQgdGhlIGV4cG9ydCBvcHRpb25zXHJcbiAgY29uc3QgZXhwb3J0T3B0aW9ucyA9IG9wdGlvbnMuZXhwb3J0O1xyXG5cclxuICAvLyBJZiBTVkcgaXMgYW4gaW5wdXQgKGFyZ3VtZW50IGNhbiBiZSBzZW50IG9ubHkgYnkgdGhlIHJlcXVlc3QpXHJcbiAgaWYgKG9wdGlvbnMucGF5bG9hZD8uc3ZnICYmIG9wdGlvbnMucGF5bG9hZC5zdmcgIT09ICcnKSB7XHJcbiAgICB0cnkge1xyXG4gICAgICBsb2coNCwgJ1tjaGFydF0gQXR0ZW1wdGluZyB0byBleHBvcnQgZnJvbSBhIFNWRyBpbnB1dC4nKTtcclxuICAgICAgcmV0dXJuIGV4cG9ydEFzU3RyaW5nKG9wdGlvbnMucGF5bG9hZC5zdmcudHJpbSgpLCBvcHRpb25zLCBlbmRDYWxsYmFjayk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICAgICAgbmV3IEV4cG9ydEVycm9yKCdbY2hhcnRdIEVycm9yIGxvYWRpbmcgU1ZHIGlucHV0LicpLnNldEVycm9yKGVycm9yKVxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gRXhwb3J0IHVzaW5nIG9wdGlvbnMgZnJvbSB0aGUgZmlsZVxyXG4gIGlmIChleHBvcnRPcHRpb25zLmluZmlsZSAmJiBleHBvcnRPcHRpb25zLmluZmlsZS5sZW5ndGgpIHtcclxuICAgIC8vIFRyeSB0byByZWFkIHRoZSBmaWxlIHRvIGdldCB0aGUgc3RyaW5nIHJlcHJlc2VudGF0aW9uXHJcbiAgICB0cnkge1xyXG4gICAgICBsb2coNCwgJ1tjaGFydF0gQXR0ZW1wdGluZyB0byBleHBvcnQgZnJvbSBhbiBpbnB1dCBmaWxlLicpO1xyXG4gICAgICBvcHRpb25zLmV4cG9ydC5pbnN0ciA9IHJlYWRGaWxlU3luYyhleHBvcnRPcHRpb25zLmluZmlsZSwgJ3V0ZjgnKTtcclxuICAgICAgcmV0dXJuIGV4cG9ydEFzU3RyaW5nKG9wdGlvbnMuZXhwb3J0Lmluc3RyLnRyaW0oKSwgb3B0aW9ucywgZW5kQ2FsbGJhY2spO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKFxyXG4gICAgICAgIG5ldyBFeHBvcnRFcnJvcignW2NoYXJ0XSBFcnJvciBsb2FkaW5nIGlucHV0IGZpbGUuJykuc2V0RXJyb3IoZXJyb3IpXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBFeHBvcnQgd2l0aCBvcHRpb25zIGZyb20gdGhlIHJhdyByZXByZXNlbnRhdGlvblxyXG4gIGlmIChcclxuICAgIChleHBvcnRPcHRpb25zLmluc3RyICYmIGV4cG9ydE9wdGlvbnMuaW5zdHIgIT09ICcnKSB8fFxyXG4gICAgKGV4cG9ydE9wdGlvbnMub3B0aW9ucyAmJiBleHBvcnRPcHRpb25zLm9wdGlvbnMgIT09ICcnKVxyXG4gICkge1xyXG4gICAgdHJ5IHtcclxuICAgICAgbG9nKDQsICdbY2hhcnRdIEF0dGVtcHRpbmcgdG8gZXhwb3J0IGZyb20gYSByYXcgaW5wdXQuJyk7XHJcblxyXG4gICAgICAvLyBQZXJmb3JtIGEgZGlyZWN0IGluamVjdCB3aGVuIGZvcmNlZFxyXG4gICAgICBpZiAodG9Cb29sZWFuKG9wdGlvbnMuY3VzdG9tTG9naWM/LmFsbG93Q29kZUV4ZWN1dGlvbikpIHtcclxuICAgICAgICByZXR1cm4gZG9TdHJhaWdodEluamVjdChvcHRpb25zLCBlbmRDYWxsYmFjayk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIEVpdGhlciB0cnkgdG8gcGFyc2UgdG8gSlNPTiBmaXJzdCBvciBkbyB0aGUgZGlyZWN0IGV4cG9ydFxyXG4gICAgICByZXR1cm4gdHlwZW9mIGV4cG9ydE9wdGlvbnMuaW5zdHIgPT09ICdzdHJpbmcnXHJcbiAgICAgICAgPyBleHBvcnRBc1N0cmluZyhleHBvcnRPcHRpb25zLmluc3RyLnRyaW0oKSwgb3B0aW9ucywgZW5kQ2FsbGJhY2spXHJcbiAgICAgICAgOiBkb0V4cG9ydChcclxuICAgICAgICAgICAgb3B0aW9ucyxcclxuICAgICAgICAgICAgZXhwb3J0T3B0aW9ucy5pbnN0ciB8fCBleHBvcnRPcHRpb25zLm9wdGlvbnMsXHJcbiAgICAgICAgICAgIGVuZENhbGxiYWNrXHJcbiAgICAgICAgICApO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKFxyXG4gICAgICAgIG5ldyBFeHBvcnRFcnJvcignW2NoYXJ0XSBFcnJvciBsb2FkaW5nIHJhdyBpbnB1dC4nKS5zZXRFcnJvcihlcnJvcilcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIE5vIGlucHV0IHNwZWNpZmllZCwgcGFzcyBhbiBlcnJvciBtZXNzYWdlIHRvIHRoZSBjYWxsYmFja1xyXG4gIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgIG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgYFtjaGFydF0gTm8gdmFsaWQgaW5wdXQgc3BlY2lmaWVkLiBDaGVjayBpZiBhdCBsZWFzdCBvbmUgb2YgdGhlIGZvbGxvd2luZyBwYXJhbWV0ZXJzIGlzIGNvcnJlY3RseSBzZXQ6ICdpbmZpbGUnLCAnaW5zdHInLCAnb3B0aW9ucycsIG9yICdzdmcnLmBcclxuICAgIClcclxuICApO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFN0YXJ0cyBhIGJhdGNoIGV4cG9ydCBwcm9jZXNzIGZvciBtdWx0aXBsZSBjaGFydHMgYmFzZWQgb24gdGhlIGluZm9ybWF0aW9uXHJcbiAqIGluIHRoZSBiYXRjaCBvcHRpb24uIFRoZSBiYXRjaCBpcyBhIHN0cmluZyBpbiB0aGUgZm9sbG93aW5nIGZvcm1hdDpcclxuICogXCJpbmZpbGUxLmpzb249b3V0ZmlsZTEucG5nO2luZmlsZTIuanNvbj1vdXRmaWxlMi5wbmc7Li4uXCJcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgb3B0aW9ucyBvYmplY3QgY29udGFpbmluZyBjb25maWd1cmF0aW9uIGZvclxyXG4gKiBhIGJhdGNoIGV4cG9ydC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgdGhlIGJhdGNoIGV4cG9ydFxyXG4gKiBwcm9jZXNzIGlzIGNvbXBsZXRlZC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiBhbiBlcnJvciBvY2N1cnMgZHVyaW5nXHJcbiAqIGFueSBvZiB0aGUgYmF0Y2ggZXhwb3J0IHByb2Nlc3MuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgYmF0Y2hFeHBvcnQgPSBhc3luYyAob3B0aW9ucykgPT4ge1xyXG4gIGNvbnN0IGJhdGNoRnVuY3Rpb25zID0gW107XHJcblxyXG4gIC8vIFNwbGl0IGFuZCBwYWlyIHRoZSAtLWJhdGNoIGFyZ3VtZW50c1xyXG4gIGZvciAobGV0IHBhaXIgb2Ygb3B0aW9ucy5leHBvcnQuYmF0Y2guc3BsaXQoJzsnKSkge1xyXG4gICAgcGFpciA9IHBhaXIuc3BsaXQoJz0nKTtcclxuICAgIGlmIChwYWlyLmxlbmd0aCA9PT0gMikge1xyXG4gICAgICBiYXRjaEZ1bmN0aW9ucy5wdXNoKFxyXG4gICAgICAgIHN0YXJ0RXhwb3J0KFxyXG4gICAgICAgICAge1xyXG4gICAgICAgICAgICAuLi5vcHRpb25zLFxyXG4gICAgICAgICAgICBleHBvcnQ6IHtcclxuICAgICAgICAgICAgICAuLi5vcHRpb25zLmV4cG9ydCxcclxuICAgICAgICAgICAgICBpbmZpbGU6IHBhaXJbMF0sXHJcbiAgICAgICAgICAgICAgb3V0ZmlsZTogcGFpclsxXVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9LFxyXG4gICAgICAgICAgKGVycm9yLCBpbmZvKSA9PiB7XHJcbiAgICAgICAgICAgIC8vIFRocm93IGFuIGVycm9yXHJcbiAgICAgICAgICAgIGlmIChlcnJvcikge1xyXG4gICAgICAgICAgICAgIHRocm93IGVycm9yO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAvLyBTYXZlIHRoZSBiYXNlNjQgZnJvbSBhIGJ1ZmZlciB0byBhIGNvcnJlY3QgaW1hZ2UgZmlsZVxyXG4gICAgICAgICAgICB3cml0ZUZpbGVTeW5jKFxyXG4gICAgICAgICAgICAgIGluZm8ub3B0aW9ucy5leHBvcnQub3V0ZmlsZSxcclxuICAgICAgICAgICAgICBCdWZmZXIuZnJvbShpbmZvLnJlc3VsdCwgJ2Jhc2U2NCcpXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgKVxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgdHJ5IHtcclxuICAgIC8vIEF3YWl0IGFsbCBleHBvcnRzIGFyZSBkb25lXHJcbiAgICBhd2FpdCBQcm9taXNlLmFsbChiYXRjaEZ1bmN0aW9ucyk7XHJcblxyXG4gICAgLy8gS2lsbCBwb29sIGFuZCBjbG9zZSBicm93c2VyIGFmdGVyIGZpbmlzaGluZyBiYXRjaCBleHBvcnRcclxuICAgIGF3YWl0IGtpbGxQb29sKCk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1tjaGFydF0gRXJyb3IgZW5jb3VudGVyZWQgZHVyaW5nIGJhdGNoIGV4cG9ydC4nXHJcbiAgICApLnNldEVycm9yKGVycm9yKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogU3RhcnRzIGEgc2luZ2xlIGV4cG9ydCBwcm9jZXNzIGJhc2VkIG9uIHRoZSBzcGVjaWZpZWQgb3B0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgb3B0aW9ucyBvYmplY3QgY29udGFpbmluZyBjb25maWd1cmF0aW9uIGZvclxyXG4gKiBhIHNpbmdsZSBleHBvcnQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBzaW5nbGUgZXhwb3J0XHJcbiAqIHByb2Nlc3MgaXMgY29tcGxldGVkLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIGFuIGVycm9yIG9jY3VycyBkdXJpbmdcclxuICogdGhlIHNpbmdsZSBleHBvcnQgcHJvY2Vzcy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBzaW5nbGVFeHBvcnQgPSBhc3luYyAob3B0aW9ucykgPT4ge1xyXG4gIC8vIFVzZSBpbnN0ciBvciBpdHMgYWxpYXMsIG9wdGlvbnNcclxuICBvcHRpb25zLmV4cG9ydC5pbnN0ciA9IG9wdGlvbnMuZXhwb3J0Lmluc3RyIHx8IG9wdGlvbnMuZXhwb3J0Lm9wdGlvbnM7XHJcblxyXG4gIC8vIFBlcmZvcm0gYW4gZXhwb3J0XHJcbiAgYXdhaXQgc3RhcnRFeHBvcnQob3B0aW9ucywgYXN5bmMgKGVycm9yLCBpbmZvKSA9PiB7XHJcbiAgICAvLyBFeGl0IHByb2Nlc3Mgd2hlbiBlcnJvclxyXG4gICAgaWYgKGVycm9yKSB7XHJcbiAgICAgIHRocm93IGVycm9yO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IHsgb3V0ZmlsZSwgdHlwZSB9ID0gaW5mby5vcHRpb25zLmV4cG9ydDtcclxuXHJcbiAgICAvLyBTYXZlIHRoZSBiYXNlNjQgZnJvbSBhIGJ1ZmZlciB0byBhIGNvcnJlY3QgaW1hZ2UgZmlsZVxyXG4gICAgd3JpdGVGaWxlU3luYyhcclxuICAgICAgb3V0ZmlsZSB8fCBgY2hhcnQuJHt0eXBlfWAsXHJcbiAgICAgIHR5cGUgIT09ICdzdmcnID8gQnVmZmVyLmZyb20oaW5mby5yZXN1bHQsICdiYXNlNjQnKSA6IGluZm8ucmVzdWx0XHJcbiAgICApO1xyXG5cclxuICAgIC8vIEtpbGwgdGhlIHBvb2xcclxuICAgIGF3YWl0IGtpbGxQb29sKCk7XHJcbiAgfSk7XHJcbn07XHJcblxyXG4vKipcclxuICogRGV0ZXJtaW5lcyB0aGUgc2l6ZSBhbmQgc2NhbGUgZm9yIGNoYXJ0IGV4cG9ydCBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgb3B0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgb3B0aW9ucyBvYmplY3QgY29udGFpbmluZyBjb25maWd1cmF0aW9uIGZvclxyXG4gKiBjaGFydCBleHBvcnQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IEFuIG9iamVjdCBjb250YWluaW5nIHRoZSBjYWxjdWxhdGVkIGhlaWdodCwgd2lkdGgsXHJcbiAqIGFuZCBzY2FsZSBmb3IgdGhlIGNoYXJ0IGV4cG9ydC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBmaW5kQ2hhcnRTaXplID0gKG9wdGlvbnMpID0+IHtcclxuICBjb25zdCB7IGNoYXJ0LCBleHBvcnRpbmcgfSA9XHJcbiAgICBvcHRpb25zLmV4cG9ydD8ub3B0aW9ucyB8fCBpc0NvcnJlY3RKU09OKG9wdGlvbnMuZXhwb3J0Py5pbnN0cik7XHJcblxyXG4gIC8vIFNlZSBpZiBnbG9iYWxPcHRpb25zIGhvbGRzIGNoYXJ0IG9yIGV4cG9ydGluZyBzaXplXHJcbiAgY29uc3QgZ2xvYmFsT3B0aW9ucyA9IGlzQ29ycmVjdEpTT04ob3B0aW9ucy5leHBvcnQ/Lmdsb2JhbE9wdGlvbnMpO1xyXG5cclxuICAvLyBTZWN1cmUgc2NhbGUgdmFsdWVcclxuICBsZXQgc2NhbGUgPVxyXG4gICAgb3B0aW9ucy5leHBvcnQ/LnNjYWxlIHx8XHJcbiAgICBleHBvcnRpbmc/LnNjYWxlIHx8XHJcbiAgICBnbG9iYWxPcHRpb25zPy5leHBvcnRpbmc/LnNjYWxlIHx8XHJcbiAgICBvcHRpb25zLmV4cG9ydD8uZGVmYXVsdFNjYWxlIHx8XHJcbiAgICAxO1xyXG5cclxuICAvLyB0aGUgc2NhbGUgY2Fubm90IGJlIGxvd2VyIHRoYW4gMC4xIGFuZCBjYW5ub3QgYmUgaGlnaGVyIHRoYW4gNS4wXHJcbiAgc2NhbGUgPSBNYXRoLm1heCgwLjEsIE1hdGgubWluKHNjYWxlLCA1LjApKTtcclxuXHJcbiAgLy8gd2Ugd2FudCB0byByb3VuZCB0aGUgbnVtYmVycyBsaWtlIDAuMjMyMzQgLT4gMC4yM1xyXG4gIHNjYWxlID0gcm91bmROdW1iZXIoc2NhbGUsIDIpO1xyXG5cclxuICAvLyBGaW5kIGNoYXJ0IHNpemUgYW5kIHNjYWxlXHJcbiAgY29uc3Qgc2l6ZSA9IHtcclxuICAgIGhlaWdodDpcclxuICAgICAgb3B0aW9ucy5leHBvcnQ/LmhlaWdodCB8fFxyXG4gICAgICBleHBvcnRpbmc/LnNvdXJjZUhlaWdodCB8fFxyXG4gICAgICBjaGFydD8uaGVpZ2h0IHx8XHJcbiAgICAgIGdsb2JhbE9wdGlvbnM/LmV4cG9ydGluZz8uc291cmNlSGVpZ2h0IHx8XHJcbiAgICAgIGdsb2JhbE9wdGlvbnM/LmNoYXJ0Py5oZWlnaHQgfHxcclxuICAgICAgb3B0aW9ucy5leHBvcnQ/LmRlZmF1bHRIZWlnaHQgfHxcclxuICAgICAgNDAwLFxyXG4gICAgd2lkdGg6XHJcbiAgICAgIG9wdGlvbnMuZXhwb3J0Py53aWR0aCB8fFxyXG4gICAgICBleHBvcnRpbmc/LnNvdXJjZVdpZHRoIHx8XHJcbiAgICAgIGNoYXJ0Py53aWR0aCB8fFxyXG4gICAgICBnbG9iYWxPcHRpb25zPy5leHBvcnRpbmc/LnNvdXJjZVdpZHRoIHx8XHJcbiAgICAgIGdsb2JhbE9wdGlvbnM/LmNoYXJ0Py53aWR0aCB8fFxyXG4gICAgICBvcHRpb25zLmV4cG9ydD8uZGVmYXVsdFdpZHRoIHx8XHJcbiAgICAgIDYwMCxcclxuICAgIHNjYWxlXHJcbiAgfTtcclxuXHJcbiAgLy8gR2V0IHJpZCBvZiBwb3RlbnRpYWwgcHggYW5kICVcclxuICBmb3IgKGxldCBbcGFyYW0sIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhzaXplKSkge1xyXG4gICAgc2l6ZVtwYXJhbV0gPVxyXG4gICAgICB0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnID8gK3ZhbHVlLnJlcGxhY2UoL3B4fCUvZ2ksICcnKSA6IHZhbHVlO1xyXG4gIH1cclxuICByZXR1cm4gc2l6ZTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBGdW5jdGlvbiBmb3IgZmluYWxpemluZyBvcHRpb25zIGJlZm9yZSBleHBvcnQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IGNvbnRhaW5pbmcgY29uZmlndXJhdGlvbiBmb3JcclxuICogdGhlIGV4cG9ydCBwcm9jZXNzLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY2hhcnRKc29uIC0gVGhlIEpTT04gcmVwcmVzZW50YXRpb24gb2YgdGhlIGNoYXJ0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIFRoZSBjYWxsYmFjayBmdW5jdGlvbiB0byBiZSBjYWxsZWQgdXBvblxyXG4gKiBjb21wbGV0aW9uIG9yIGVycm9yLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gc3ZnIC0gVGhlIFNWRyByZXByZXNlbnRhdGlvbiBvZiB0aGUgY2hhcnQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBleHBvcnQgcHJvY2Vzc1xyXG4gKiBpcyBjb21wbGV0ZWQuXHJcbiAqL1xyXG5jb25zdCBkb0V4cG9ydCA9IGFzeW5jIChvcHRpb25zLCBjaGFydEpzb24sIGVuZENhbGxiYWNrLCBzdmcpID0+IHtcclxuICBsZXQgeyBleHBvcnQ6IGV4cG9ydE9wdGlvbnMsIGN1c3RvbUxvZ2ljOiBjdXN0b21Mb2dpY09wdGlvbnMgfSA9IG9wdGlvbnM7XHJcblxyXG4gIGNvbnN0IGFsbG93Q29kZUV4ZWN1dGlvblNjb3BlZCA9XHJcbiAgICB0eXBlb2YgY3VzdG9tTG9naWNPcHRpb25zLmFsbG93Q29kZUV4ZWN1dGlvbiA9PT0gJ2Jvb2xlYW4nXHJcbiAgICAgID8gY3VzdG9tTG9naWNPcHRpb25zLmFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgICA6IGFsbG93Q29kZUV4ZWN1dGlvbjtcclxuXHJcbiAgaWYgKCFjdXN0b21Mb2dpY09wdGlvbnMpIHtcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucyA9IG9wdGlvbnMuY3VzdG9tTG9naWMgPSB7fTtcclxuICB9IGVsc2UgaWYgKGFsbG93Q29kZUV4ZWN1dGlvblNjb3BlZCkge1xyXG4gICAgaWYgKHR5cGVvZiBvcHRpb25zLmN1c3RvbUxvZ2ljLnJlc291cmNlcyA9PT0gJ3N0cmluZycpIHtcclxuICAgICAgLy8gUHJvY2VzcyByZXNvdXJjZXNcclxuICAgICAgb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXMgPSBoYW5kbGVSZXNvdXJjZXMoXHJcbiAgICAgICAgb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXMsXHJcbiAgICAgICAgdG9Cb29sZWFuKG9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dGaWxlUmVzb3VyY2VzKVxyXG4gICAgICApO1xyXG4gICAgfSBlbHNlIGlmICghb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXMpIHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBjb25zdCByZXNvdXJjZXMgPSByZWFkRmlsZVN5bmMoJ3Jlc291cmNlcy5qc29uJywgJ3V0ZjgnKTtcclxuICAgICAgICBvcHRpb25zLmN1c3RvbUxvZ2ljLnJlc291cmNlcyA9IGhhbmRsZVJlc291cmNlcyhcclxuICAgICAgICAgIHJlc291cmNlcyxcclxuICAgICAgICAgIHRvQm9vbGVhbihvcHRpb25zLmN1c3RvbUxvZ2ljLmFsbG93RmlsZVJlc291cmNlcylcclxuICAgICAgICApO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAgIDIsXHJcbiAgICAgICAgICBlcnJvcixcclxuICAgICAgICAgIGBbY2hhcnRdIFVuYWJsZSB0byBsb2FkIHRoZSBkZWZhdWx0IHJlc291cmNlcy5qc29uIGZpbGUuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIElmIHRoZSBhbGxvd0NvZGVFeGVjdXRpb24gZmxhZyBpc24ndCBzZXQsIHdlIHNob3VsZCByZWZ1c2UgdGhlIHVzYWdlXHJcbiAgLy8gb2YgY2FsbGJhY2ssIHJlc291cmNlcywgYW5kIGN1c3RvbSBjb2RlLiBBZGRpdGlvbmFsbHksIHRoZSB3b3JrZXIgd2lsbFxyXG4gIC8vIHJlZnVzZSB0byBydW4gYXJiaXRyYXJ5IEphdmFTY3JpcHQuIFByaW9yaXRpemVkIHNob3VsZCBiZSB0aGUgc2NvcGVkXHJcbiAgLy8gb3B0aW9uLCB0aGVuIHdlIHNob3VsZCB0YWtlIGEgbG9vayBhdCB0aGUgb3ZlcmFsbCBwb29sIG9wdGlvbi5cclxuICBpZiAoIWFsbG93Q29kZUV4ZWN1dGlvblNjb3BlZCAmJiBjdXN0b21Mb2dpY09wdGlvbnMpIHtcclxuICAgIGlmIChcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrIHx8XHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXMgfHxcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGVcclxuICAgICkge1xyXG4gICAgICAvLyBTZW5kIGJhY2sgYSBmcmllbmRseSBtZXNzYWdlIHNheWluZyB0aGF0IHRoZSBleHBvcnRlciBkb2VzIG5vdCBzdXBwb3J0XHJcbiAgICAgIC8vIHRoZXNlIHNldHRpbmdzLlxyXG4gICAgICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICAgICAgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgYFtjaGFydF0gVGhlICdjYWxsYmFjaycsICdyZXNvdXJjZXMnIGFuZCAnY3VzdG9tQ29kZScgb3B0aW9ucyBoYXZlIGJlZW4gZGlzYWJsZWQgZm9yIHRoaXMgc2VydmVyLmBcclxuICAgICAgICApXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmVzZXQgYWxsIGFkZGl0aW9uYWwgY3VzdG9tIGNvZGVcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IGZhbHNlO1xyXG4gICAgY3VzdG9tTG9naWNPcHRpb25zLnJlc291cmNlcyA9IGZhbHNlO1xyXG4gICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUgPSBmYWxzZTtcclxuICB9XHJcblxyXG4gIC8vIENsZWFuIHByb3BlcnRpZXMgdG8ga2VlcCBpdCBsZWFuIGFuZCBtZWFuXHJcbiAgaWYgKGNoYXJ0SnNvbikge1xyXG4gICAgY2hhcnRKc29uLmNoYXJ0ID0gY2hhcnRKc29uLmNoYXJ0IHx8IHt9O1xyXG4gICAgY2hhcnRKc29uLmV4cG9ydGluZyA9IGNoYXJ0SnNvbi5leHBvcnRpbmcgfHwge307XHJcbiAgICBjaGFydEpzb24uZXhwb3J0aW5nLmVuYWJsZWQgPSBmYWxzZTtcclxuICB9XHJcblxyXG4gIGV4cG9ydE9wdGlvbnMuY29uc3RyID0gZXhwb3J0T3B0aW9ucy5jb25zdHIgfHwgJ2NoYXJ0JztcclxuICBleHBvcnRPcHRpb25zLnR5cGUgPSBmaXhUeXBlKGV4cG9ydE9wdGlvbnMudHlwZSwgZXhwb3J0T3B0aW9ucy5vdXRmaWxlKTtcclxuICBpZiAoZXhwb3J0T3B0aW9ucy50eXBlID09PSAnc3ZnJykge1xyXG4gICAgZXhwb3J0T3B0aW9ucy53aWR0aCA9IGZhbHNlO1xyXG4gIH1cclxuXHJcbiAgLy8gUHJlcGFyZSBnbG9iYWwgYW5kIHRoZW1lIG9wdGlvbnNcclxuICBbJ2dsb2JhbE9wdGlvbnMnLCAndGhlbWVPcHRpb25zJ10uZm9yRWFjaCgob3B0aW9uc05hbWUpID0+IHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGlmIChleHBvcnRPcHRpb25zICYmIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdKSB7XHJcbiAgICAgICAgaWYgKFxyXG4gICAgICAgICAgdHlwZW9mIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID09PSAnc3RyaW5nJyAmJlxyXG4gICAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0uZW5kc1dpdGgoJy5qc29uJylcclxuICAgICAgICApIHtcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID0gaXNDb3JyZWN0SlNPTihcclxuICAgICAgICAgICAgcmVhZEZpbGVTeW5jKGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdLCAndXRmOCcpLFxyXG4gICAgICAgICAgICB0cnVlXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9IGlzQ29ycmVjdEpTT04oXHJcbiAgICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdLFxyXG4gICAgICAgICAgICB0cnVlXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPSB7fTtcclxuICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2NoYXJ0XSBUaGUgJyR7b3B0aW9uc05hbWV9JyBjYW5ub3QgYmUgbG9hZGVkLmApO1xyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICAvLyBQcmVwYXJlIHRoZSBjdXN0b21Db2RlXHJcbiAgaWYgKGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0NvZGVFeGVjdXRpb24pIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlID0gd3JhcEFyb3VuZChcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSxcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dGaWxlUmVzb3VyY2VzXHJcbiAgICAgICk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbY2hhcnRdIFRoZSAnY3VzdG9tQ29kZScgY2Fubm90IGJlIGxvYWRlZC5gKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIEdldCB0aGUgY2FsbGJhY2tcclxuICBpZiAoXHJcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMgJiZcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayAmJlxyXG4gICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrPy5pbmRleE9mKCd7JykgPCAwXHJcbiAgKSB7XHJcbiAgICAvLyBUaGUgYWxsb3dGaWxlUmVzb3VyY2VzIGlzIGFsd2F5cyBzZXQgdG8gZmFsc2UgZm9yIEhUVFAgcmVxdWVzdHMgdG8gYXZvaWRcclxuICAgIC8vIGluamVjdGluZyBhcmJpdHJhcnkgZmlsZXMgZnJvbSB0aGUgZnNcclxuICAgIGlmIChjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dGaWxlUmVzb3VyY2VzKSB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrID0gcmVhZEZpbGVTeW5jKFxyXG4gICAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrLFxyXG4gICAgICAgICAgJ3V0ZjgnXHJcbiAgICAgICAgKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSBmYWxzZTtcclxuICAgICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbY2hhcnRdIFRoZSAnY2FsbGJhY2snIGNhbm5vdCBiZSBsb2FkZWQuYCk7XHJcbiAgICAgIH1cclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IGZhbHNlO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gU2l6ZSBzZWFyY2hcclxuICBvcHRpb25zLmV4cG9ydCA9IHtcclxuICAgIC4uLm9wdGlvbnMuZXhwb3J0LFxyXG4gICAgLi4uZmluZENoYXJ0U2l6ZShvcHRpb25zKVxyXG4gIH07XHJcblxyXG4gIC8vIFBvc3QgdGhlIHdvcmsgdG8gdGhlIHBvb2xcclxuICB0cnkge1xyXG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcG9zdFdvcmsoXHJcbiAgICAgIGV4cG9ydE9wdGlvbnMuc3RySW5qIHx8IGNoYXJ0SnNvbiB8fCBzdmcsXHJcbiAgICAgIG9wdGlvbnNcclxuICAgICk7XHJcbiAgICByZXR1cm4gZW5kQ2FsbGJhY2soZmFsc2UsIHJlc3VsdCk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHJldHVybiBlbmRDYWxsYmFjayhlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIFBlcmZvcm1zIGEgZGlyZWN0IGluamVjdCBvZiBvcHRpb25zIGJlZm9yZSBleHBvcnQuIFRoZSBmdW5jdGlvbiBhdHRlbXB0c1xyXG4gKiB0byBzdHJpbmdpZnkgdGhlIHByb3ZpZGVkIG9wdGlvbnMgYW5kIHJlbW92ZXMgdW5uZWNlc3NhcnkgY2hhcmFjdGVycyxcclxuICogZW5zdXJpbmcgYSBjbGVhbiBhbmQgZm9ybWF0dGVkIGlucHV0LiBUaGUgcmVzdWx0aW5nIHN0cmluZyBpcyBzYXZlZCBhc1xyXG4gKiBhIFwic3RyaWdodCBpbmplY3RcIiBzdHJpbmcgaW4gdGhlIGV4cG9ydCBvcHRpb25zLiBJdCB0aGVuIGludm9rZXMgdGhlXHJcbiAqIGRvRXhwb3J0IGZ1bmN0aW9uIHdpdGggdGhlIHVwZGF0ZWQgb3B0aW9ucy5cclxuICpcclxuICogSU1QT1JUQU5UOiBEYW5nZXJvdXMgYW5kIG11c3QgYmUgdXNlZCBkZWxpYmVyYXRlbHkgYnkgc29tZW9uZSB3aG8gc2V0cyB1cFxyXG4gKiBhIHNlcnZlciAoc2VlIHRoZSAgLS1hbGxvd0NvZGVFeGVjdXRpb24gb3B0aW9uKS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgZXhwb3J0IG9wdGlvbnMgY29udGFpbmluZyB0aGUgaW5wdXRcclxuICogdG8gYmUgaW5qZWN0ZWQuXHJcbiAqIEBwYXJhbSB7ZnVuY3Rpb259IGVuZENhbGxiYWNrIC0gVGhlIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGludm9rZWRcclxuICogYXQgdGhlIGVuZCBvZiB0aGUgcHJvY2Vzcy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2V9IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHdpdGggdGhlIHJlc3VsdCBvZiB0aGUgZXhwb3J0XHJcbiAqIG9wZXJhdGlvbiBvciByZWplY3RzIHdpdGggYW4gZXJyb3IgaWYgYW55IGlzc3VlcyBvY2N1ciBkdXJpbmcgdGhlIHByb2Nlc3MuXHJcbiAqL1xyXG5jb25zdCBkb1N0cmFpZ2h0SW5qZWN0ID0gKG9wdGlvbnMsIGVuZENhbGxiYWNrKSA9PiB7XHJcbiAgdHJ5IHtcclxuICAgIGxldCBzdHJJbmo7XHJcbiAgICBsZXQgaW5zdHIgPSBvcHRpb25zLmV4cG9ydC5pbnN0ciB8fCBvcHRpb25zLmV4cG9ydC5vcHRpb25zO1xyXG5cclxuICAgIGlmICh0eXBlb2YgaW5zdHIgIT09ICdzdHJpbmcnKSB7XHJcbiAgICAgIC8vIFRyeSB0byBzdHJpbmdpZnkgb3B0aW9uc1xyXG4gICAgICBzdHJJbmogPSBpbnN0ciA9IG9wdGlvbnNTdHJpbmdpZnkoXHJcbiAgICAgICAgaW5zdHIsXHJcbiAgICAgICAgb3B0aW9ucy5jdXN0b21Mb2dpYz8uYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgICBzdHJJbmogPSBpbnN0ci5yZXBsYWNlQWxsKC9cXHR8XFxufFxcci9nLCAnJykudHJpbSgpO1xyXG5cclxuICAgIC8vIEdldCByaWQgb2YgdGhlIDtcclxuICAgIGlmIChzdHJJbmpbc3RySW5qLmxlbmd0aCAtIDFdID09PSAnOycpIHtcclxuICAgICAgc3RySW5qID0gc3RySW5qLnN1YnN0cmluZygwLCBzdHJJbmoubGVuZ3RoIC0gMSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU2F2ZSBhcyBzdHJpZ2h0IGluamVjdCBzdHJpbmdcclxuICAgIG9wdGlvbnMuZXhwb3J0LnN0ckluaiA9IHN0ckluajtcclxuICAgIHJldHVybiBkb0V4cG9ydChvcHRpb25zLCBmYWxzZSwgZW5kQ2FsbGJhY2spO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICAgIG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICBgW2NoYXJ0XSBNYWxmb3JtZWQgaW5wdXQgZGV0ZWN0ZWQgZm9yICR7b3B0aW9ucy5leHBvcnQ/LnJlcXVlc3RJZCB8fCAnPyd9LiBQbGVhc2UgbWFrZSBzdXJlIHRoYXQgeW91ciBKU09OL0phdmFTY3JpcHQgb3B0aW9ucyBhcmUgc2VudCB1c2luZyB0aGUgXCJvcHRpb25zXCIgYXR0cmlidXRlLCBhbmQgdGhhdCBpZiB5b3UncmUgdXNpbmcgU1ZHLCBpdCBpcyB1bmVzY2FwZWQuYFxyXG4gICAgICApLnNldEVycm9yKGVycm9yKVxyXG4gICAgKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogRXhwb3J0cyBhIHN0cmluZyBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgb3B0aW9ucyBhbmQgaW52b2tlcyBhbiBlbmQgY2FsbGJhY2suXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBzdHJpbmdUb0V4cG9ydCAtIFRoZSBzdHJpbmcgY29udGVudCB0byBiZSBleHBvcnRlZC5cclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBFeHBvcnQgb3B0aW9ucywgaW5jbHVkaW5nIGN1c3RvbUxvZ2ljIHdpdGhcclxuICogYWxsb3dDb2RlRXhlY3V0aW9uIGZsYWcuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGVuZENhbGxiYWNrIC0gQ2FsbGJhY2sgZnVuY3Rpb24gdG8gYmUgaW52b2tlZCBhdCB0aGUgZW5kXHJcbiAqIG9mIHRoZSBleHBvcnQgcHJvY2Vzcy5cclxuICpcclxuICogQHJldHVybnMge2FueX0gUmVzdWx0IG9mIHRoZSBleHBvcnQgcHJvY2VzcyBvciBhbiBlcnJvciBpZiBlbmNvdW50ZXJlZC5cclxuICovXHJcbmNvbnN0IGV4cG9ydEFzU3RyaW5nID0gKHN0cmluZ1RvRXhwb3J0LCBvcHRpb25zLCBlbmRDYWxsYmFjaykgPT4ge1xyXG4gIGNvbnN0IHsgYWxsb3dDb2RlRXhlY3V0aW9uIH0gPSBvcHRpb25zLmN1c3RvbUxvZ2ljO1xyXG5cclxuICAvLyBDaGVjayBpZiBpdCBpcyBTVkdcclxuICBpZiAoXHJcbiAgICBzdHJpbmdUb0V4cG9ydC5pbmRleE9mKCc8c3ZnJykgPj0gMCB8fFxyXG4gICAgc3RyaW5nVG9FeHBvcnQuaW5kZXhPZignPD94bWwnKSA+PSAwXHJcbiAgKSB7XHJcbiAgICBsb2coNCwgJ1tjaGFydF0gUGFyc2luZyBpbnB1dCBhcyBTVkcuJyk7XHJcbiAgICByZXR1cm4gZG9FeHBvcnQob3B0aW9ucywgZmFsc2UsIGVuZENhbGxiYWNrLCBzdHJpbmdUb0V4cG9ydCk7XHJcbiAgfVxyXG5cclxuICB0cnkge1xyXG4gICAgLy8gVHJ5IHRvIHBhcnNlIHRvIEpTT04gYW5kIGNhbGwgdGhlIGRvRXhwb3J0IGZ1bmN0aW9uXHJcbiAgICBjb25zdCBjaGFydEpTT04gPSBKU09OLnBhcnNlKHN0cmluZ1RvRXhwb3J0LnJlcGxhY2VBbGwoL1xcdHxcXG58XFxyL2csICcgJykpO1xyXG5cclxuICAgIC8vIElmIGEgY29ycmVjdCBKU09OLCBkbyB0aGUgZXhwb3J0XHJcbiAgICByZXR1cm4gZG9FeHBvcnQob3B0aW9ucywgY2hhcnRKU09OLCBlbmRDYWxsYmFjayk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIC8vIE5vdCBhIHZhbGlkIEpTT05cclxuICAgIGlmICh0b0Jvb2xlYW4oYWxsb3dDb2RlRXhlY3V0aW9uKSkge1xyXG4gICAgICByZXR1cm4gZG9TdHJhaWdodEluamVjdChvcHRpb25zLCBlbmRDYWxsYmFjayk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBEbyBub3QgYWxsb3cgc3RyYWlnaHQgaW5qZWN0aW9uIHdpdGhvdXQgdGhlIGFsbG93Q29kZUV4ZWN1dGlvbiBmbGFnXHJcbiAgICAgIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgICAgICBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgICAnW2NoYXJ0XSBPbmx5IEpTT04gY29uZmlndXJhdGlvbnMgYW5kIFNWRyBhcmUgYWxsb3dlZCBmb3IgdGhpcyBzZXJ2ZXIuIElmIHRoaXMgaXMgeW91ciBzZXJ2ZXIsIEphdmFTY3JpcHQgY3VzdG9tIGNvZGUgY2FuIGJlIGVuYWJsZWQgYnkgc3RhcnRpbmcgdGhlIHNlcnZlciB3aXRoIHRoZSAtLWFsbG93Q29kZUV4ZWN1dGlvbiBmbGFnLidcclxuICAgICAgICApLnNldEVycm9yKGVycm9yKVxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgYW5kIHJldHVybnMgdGhlIGN1cnJlbnQgc3RhdHVzIG9mIGNvZGUgZXhlY3V0aW9uIHBlcm1pc3Npb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHthbnl9IFRoZSB2YWx1ZSBvZiBhbGxvd0NvZGVFeGVjdXRpb24uXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0QWxsb3dDb2RlRXhlY3V0aW9uID0gKCkgPT4gYWxsb3dDb2RlRXhlY3V0aW9uO1xyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIGNvZGUgZXhlY3V0aW9uIHBlcm1pc3Npb24gYmFzZWQgb24gdGhlIHByb3ZpZGVkIGJvb2xlYW4gdmFsdWUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7YW55fSB2YWx1ZSAtIFRoZSB2YWx1ZSB0byBiZSBjb252ZXJ0ZWQgYW5kIGFzc2lnbmVkXHJcbiAqIHRvIGFsbG93Q29kZUV4ZWN1dGlvbi5cclxuICovXHJcbmV4cG9ydCBjb25zdCBzZXRBbGxvd0NvZGVFeGVjdXRpb24gPSAodmFsdWUpID0+IHtcclxuICBhbGxvd0NvZGVFeGVjdXRpb24gPSB0b0Jvb2xlYW4odmFsdWUpO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGJhdGNoRXhwb3J0LFxyXG4gIHNpbmdsZUV4cG9ydCxcclxuICBnZXRBbGxvd0NvZGVFeGVjdXRpb24sXHJcbiAgc2V0QWxsb3dDb2RlRXhlY3V0aW9uLFxyXG4gIHN0YXJ0RXhwb3J0LFxyXG4gIGZpbmRDaGFydFNpemVcclxufTtcclxuIiwiaW1wb3J0IHsgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi4vbG9nZ2VyLmpzJztcclxuXHJcbi8qKlxyXG4gKiBNaWRkbGV3YXJlIGZvciBsb2dnaW5nIGVycm9ycyB3aXRoIHN0YWNrIHRyYWNlIGFuZCBoYW5kbGluZyBlcnJvciByZXNwb25zZS5cclxuICpcclxuICogQHBhcmFtIHtFcnJvcn0gZXJyb3IgLSBUaGUgZXJyb3Igb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxIC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBuZXh0IC0gVGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICovXHJcbmNvbnN0IGxvZ0Vycm9yTWlkZGxld2FyZSA9IChlcnJvciwgcmVxLCByZXMsIG5leHQpID0+IHtcclxuICAvLyBEaXNwbGF5IHRoZSBlcnJvciB3aXRoIHN0YWNrIGluIGEgY29ycmVjdCBmb3JtYXRcclxuICBsb2dXaXRoU3RhY2soMSwgZXJyb3IpO1xyXG5cclxuICAvLyBEZWxldGUgdGhlIHN0YWNrIGZvciB0aGUgZW52aXJvbm1lbnQgb3RoZXIgdGhhbiB0aGUgZGV2ZWxvcG1lbnRcclxuICBpZiAocHJvY2Vzcy5lbnYuTk9ERV9FTlYgIT09ICdkZXZlbG9wbWVudCcpIHtcclxuICAgIGRlbGV0ZSBlcnJvci5zdGFjaztcclxuICB9XHJcblxyXG4gIC8vIENhbGwgdGhlIHJldHVybkVycm9yTWlkZGxld2FyZVxyXG4gIG5leHQoZXJyb3IpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIE1pZGRsZXdhcmUgZm9yIHJldHVybmluZyBlcnJvciByZXNwb25zZS5cclxuICpcclxuICogQHBhcmFtIHtFcnJvcn0gZXJyb3IgLSBUaGUgZXJyb3Igb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxIC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBuZXh0IC0gVGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICovXHJcbmNvbnN0IHJldHVybkVycm9yTWlkZGxld2FyZSA9IChlcnJvciwgcmVxLCByZXMsIG5leHQpID0+IHtcclxuICAvLyBHYXRoZXIgYWxsIHJlcXVpZWQgaW5mb3JtYXRpb24gZm9yIHRoZSByZXNwb25zZVxyXG4gIGNvbnN0IHsgc3RhdHVzQ29kZTogc3RDb2RlLCBzdGF0dXMsIG1lc3NhZ2UsIHN0YWNrIH0gPSBlcnJvcjtcclxuICBjb25zdCBzdGF0dXNDb2RlID0gc3RDb2RlIHx8IHN0YXR1cyB8fCA1MDA7XHJcblxyXG4gIC8vIFNldCBhbmQgcmV0dXJuIHJlc3BvbnNlXHJcbiAgcmVzLnN0YXR1cyhzdGF0dXNDb2RlKS5qc29uKHsgc3RhdHVzQ29kZSwgbWVzc2FnZSwgc3RhY2sgfSk7XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCAoYXBwKSA9PiB7XHJcbiAgLy8gQWRkIGxvZyBlcnJvciBtaWRkbGV3YXJlXHJcbiAgYXBwLnVzZShsb2dFcnJvck1pZGRsZXdhcmUpO1xyXG5cclxuICAvLyBBZGQgc2V0IHN0YXR1cyBhbmQgcmV0dXJuIGVycm9yIG1pZGRsZXdhcmVcclxuICBhcHAudXNlKHJldHVybkVycm9yTWlkZGxld2FyZSk7XHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHJhdGVMaW1pdCBmcm9tICdleHByZXNzLXJhdGUtbGltaXQnO1xyXG5cclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi4vbG9nZ2VyLmpzJztcclxuXHJcbi8qKlxyXG4gKiBNaWRkbGV3YXJlIGZvciBlbmFibGluZyByYXRlIGxpbWl0aW5nIG9uIHRoZSBzcGVjaWZpZWQgRXhwcmVzcyBhcHAuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzc30gYXBwIC0gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gbGltaXRDb25maWcgLSBDb25maWd1cmF0aW9uIG9wdGlvbnMgZm9yIHJhdGUgbGltaXRpbmcuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCAoYXBwLCBsaW1pdENvbmZpZykgPT4ge1xyXG4gIGNvbnN0IG1zZyA9XHJcbiAgICAnVG9vIG1hbnkgcmVxdWVzdHMsIHlvdSBoYXZlIGJlZW4gcmF0ZSBsaW1pdGVkLiBQbGVhc2UgdHJ5IGFnYWluIGxhdGVyLic7XHJcblxyXG4gIC8vIE9wdGlvbnMgZm9yIHRoZSByYXRlIGxpbWl0ZXJcclxuICBjb25zdCByYXRlT3B0aW9ucyA9IHtcclxuICAgIG1heDogbGltaXRDb25maWcubWF4UmVxdWVzdHMgfHwgMzAsXHJcbiAgICB3aW5kb3c6IGxpbWl0Q29uZmlnLndpbmRvdyB8fCAxLFxyXG4gICAgZGVsYXk6IGxpbWl0Q29uZmlnLmRlbGF5IHx8IDAsXHJcbiAgICB0cnVzdFByb3h5OiBsaW1pdENvbmZpZy50cnVzdFByb3h5IHx8IGZhbHNlLFxyXG4gICAgc2tpcEtleTogbGltaXRDb25maWcuc2tpcEtleSB8fCBmYWxzZSxcclxuICAgIHNraXBUb2tlbjogbGltaXRDb25maWcuc2tpcFRva2VuIHx8IGZhbHNlXHJcbiAgfTtcclxuXHJcbiAgLy8gU2V0IGlmIGJlaGluZCBhIHByb3h5XHJcbiAgaWYgKHJhdGVPcHRpb25zLnRydXN0UHJveHkpIHtcclxuICAgIGFwcC5lbmFibGUoJ3RydXN0IHByb3h5Jyk7XHJcbiAgfVxyXG5cclxuICAvLyBDcmVhdGUgYSBsaW1pdGVyXHJcbiAgY29uc3QgbGltaXRlciA9IHJhdGVMaW1pdCh7XHJcbiAgICB3aW5kb3dNczogcmF0ZU9wdGlvbnMud2luZG93ICogNjAgKiAxMDAwLFxyXG4gICAgLy8gTGltaXQgZWFjaCBJUCB0byAxMDAgcmVxdWVzdHMgcGVyIHdpbmRvd01zXHJcbiAgICBtYXg6IHJhdGVPcHRpb25zLm1heCxcclxuICAgIC8vIERpc2FibGUgZGVsYXlpbmcsIGZ1bGwgc3BlZWQgdW50aWwgdGhlIG1heCBsaW1pdCBpcyByZWFjaGVkXHJcbiAgICBkZWxheU1zOiByYXRlT3B0aW9ucy5kZWxheSxcclxuICAgIGhhbmRsZXI6IChyZXF1ZXN0LCByZXNwb25zZSkgPT4ge1xyXG4gICAgICByZXNwb25zZS5mb3JtYXQoe1xyXG4gICAgICAgIGpzb246ICgpID0+IHtcclxuICAgICAgICAgIHJlc3BvbnNlLnN0YXR1cyg0MjkpLnNlbmQoeyBtZXNzYWdlOiBtc2cgfSk7XHJcbiAgICAgICAgfSxcclxuICAgICAgICBkZWZhdWx0OiAoKSA9PiB7XHJcbiAgICAgICAgICByZXNwb25zZS5zdGF0dXMoNDI5KS5zZW5kKG1zZyk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9KTtcclxuICAgIH0sXHJcbiAgICBza2lwOiAocmVxdWVzdCkgPT4ge1xyXG4gICAgICAvLyBBbGxvdyBieXBhc3NpbmcgdGhlIGxpbWl0ZXIgaWYgYSB2YWxpZCBrZXkvdG9rZW4gaGFzIGJlZW4gc2VudFxyXG4gICAgICBpZiAoXHJcbiAgICAgICAgcmF0ZU9wdGlvbnMuc2tpcEtleSAhPT0gZmFsc2UgJiZcclxuICAgICAgICByYXRlT3B0aW9ucy5za2lwVG9rZW4gIT09IGZhbHNlICYmXHJcbiAgICAgICAgcmVxdWVzdC5xdWVyeS5rZXkgPT09IHJhdGVPcHRpb25zLnNraXBLZXkgJiZcclxuICAgICAgICByZXF1ZXN0LnF1ZXJ5LmFjY2Vzc190b2tlbiA9PT0gcmF0ZU9wdGlvbnMuc2tpcFRva2VuXHJcbiAgICAgICkge1xyXG4gICAgICAgIGxvZyg0LCAnW3JhdGUgbGltaXRpbmddIFNraXBwaW5nIHJhdGUgbGltaXRlci4nKTtcclxuICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICB9XHJcbiAgfSk7XHJcblxyXG4gIC8vIFVzZSBhIGxpbWl0ZXIgYXMgYSBtaWRkbGV3YXJlXHJcbiAgYXBwLnVzZShsaW1pdGVyKTtcclxuXHJcbiAgbG9nKFxyXG4gICAgMyxcclxuICAgIGBbcmF0ZSBsaW1pdGluZ10gRW5hYmxlZCByYXRlIGxpbWl0aW5nIHdpdGggJHtyYXRlT3B0aW9ucy5tYXh9IHJlcXVlc3RzIHBlciAke3JhdGVPcHRpb25zLndpbmRvd30gbWludXRlIGZvciBlYWNoIElQLCB0cnVzdGluZyBwcm94eTogJHtyYXRlT3B0aW9ucy50cnVzdFByb3h5fS5gXHJcbiAgKTtcclxufTtcclxuIiwiaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuY2xhc3MgSHR0cEVycm9yIGV4dGVuZHMgRXhwb3J0RXJyb3Ige1xyXG4gIGNvbnN0cnVjdG9yKG1lc3NhZ2UsIHN0YXR1cykge1xyXG4gICAgc3VwZXIobWVzc2FnZSk7XHJcbiAgICB0aGlzLnN0YXR1cyA9IHRoaXMuc3RhdHVzQ29kZSA9IHN0YXR1cztcclxuICB9XHJcblxyXG4gIHNldFN0YXR1cyhzdGF0dXMpIHtcclxuICAgIHRoaXMuc3RhdHVzID0gc3RhdHVzO1xyXG4gICAgcmV0dXJuIHRoaXM7XHJcbiAgfVxyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCBIdHRwRXJyb3I7XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgdjQgYXMgdXVpZCB9IGZyb20gJ3V1aWQnO1xyXG5cclxuaW1wb3J0IHsgZ2V0QWxsb3dDb2RlRXhlY3V0aW9uLCBzdGFydEV4cG9ydCB9IGZyb20gJy4uLy4uL2NoYXJ0LmpzJztcclxuaW1wb3J0IHsgZ2V0T3B0aW9ucywgbWVyZ2VDb25maWdPcHRpb25zIH0gZnJvbSAnLi4vLi4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi4vLi4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHtcclxuICBmaXhUeXBlLFxyXG4gIGlzQ29ycmVjdEpTT04sXHJcbiAgaXNPYmplY3RFbXB0eSxcclxuICBpc1ByaXZhdGVSYW5nZVVybEZvdW5kLFxyXG4gIG9wdGlvbnNTdHJpbmdpZnksXHJcbiAgbWVhc3VyZVRpbWVcclxufSBmcm9tICcuLi8uLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgSHR0cEVycm9yIGZyb20gJy4uLy4uL2Vycm9ycy9IdHRwRXJyb3IuanMnO1xyXG5cclxuLy8gUmV2ZXJzZWQgTUlNRSB0eXBlc1xyXG5jb25zdCByZXZlcnNlZE1pbWUgPSB7XHJcbiAgcG5nOiAnaW1hZ2UvcG5nJyxcclxuICBqcGVnOiAnaW1hZ2UvanBlZycsXHJcbiAgZ2lmOiAnaW1hZ2UvZ2lmJyxcclxuICBwZGY6ICdhcHBsaWNhdGlvbi9wZGYnLFxyXG4gIHN2ZzogJ2ltYWdlL3N2Zyt4bWwnXHJcbn07XHJcblxyXG4vLyBUaGUgcmVxdWVzdHMgY291bnRlclxyXG5sZXQgcmVxdWVzdHNDb3VudGVyID0gMDtcclxuXHJcbi8vIFRoZSBhcnJheSBvZiBjYWxsYmFja3MgdG8gY2FsbCBiZWZvcmUgYSByZXF1ZXN0XHJcbmNvbnN0IGJlZm9yZVJlcXVlc3QgPSBbXTtcclxuXHJcbi8vIFRoZSBhcnJheSBvZiBjYWxsYmFja3MgdG8gY2FsbCBhZnRlciBhIHJlcXVlc3RcclxuY29uc3QgYWZ0ZXJSZXF1ZXN0ID0gW107XHJcblxyXG4vKipcclxuICogSW52b2tlcyBhbiBhcnJheSBvZiBjYWxsYmFjayBmdW5jdGlvbnMgd2l0aCBzcGVjaWZpZWQgcGFyYW1ldGVycywgYWxsb3dpbmdcclxuICogY3VzdG9taXphdGlvbiBvZiByZXF1ZXN0IGhhbmRsaW5nLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9uW119IGNhbGxiYWNrcyAtIEFuIGFycmF5IG9mIGNhbGxiYWNrIGZ1bmN0aW9uc1xyXG4gKiB0byBiZSBleGVjdXRlZC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcXVlc3QgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXNwb25zZSAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cclxuICogQHBhcmFtIHtPYmplY3R9IGRhdGEgLSBBbiBvYmplY3QgY29udGFpbmluZyBwYXJhbWV0ZXJzIGxpa2UgaWQsIHVuaXF1ZUlkLFxyXG4gKiB0eXBlLCBhbmQgYm9keS5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IC0gUmV0dXJucyBhIGJvb2xlYW4gaW5kaWNhdGluZyB0aGUgb3ZlcmFsbCByZXN1bHRcclxuICogb2YgdGhlIGNhbGxiYWNrIGludm9jYXRpb25zLlxyXG4gKi9cclxuY29uc3QgZG9DYWxsYmFja3MgPSAoY2FsbGJhY2tzLCByZXF1ZXN0LCByZXNwb25zZSwgZGF0YSkgPT4ge1xyXG4gIGxldCByZXN1bHQgPSB0cnVlO1xyXG4gIGNvbnN0IHsgaWQsIHVuaXF1ZUlkLCB0eXBlLCBib2R5IH0gPSBkYXRhO1xyXG5cclxuICBjYWxsYmFja3Muc29tZSgoY2FsbGJhY2spID0+IHtcclxuICAgIGlmIChjYWxsYmFjaykge1xyXG4gICAgICBsZXQgY2FsbFJlc3BvbnNlID0gY2FsbGJhY2socmVxdWVzdCwgcmVzcG9uc2UsIGlkLCB1bmlxdWVJZCwgdHlwZSwgYm9keSk7XHJcblxyXG4gICAgICBpZiAoY2FsbFJlc3BvbnNlICE9PSB1bmRlZmluZWQgJiYgY2FsbFJlc3BvbnNlICE9PSB0cnVlKSB7XHJcbiAgICAgICAgcmVzdWx0ID0gY2FsbFJlc3BvbnNlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICByZXR1cm4gdHJ1ZTtcclxuICAgIH1cclxuICB9KTtcclxuXHJcbiAgcmV0dXJuIHJlc3VsdDtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBIYW5kbGVzIHRoZSBleHBvcnQgcmVxdWVzdHMgZnJvbSB0aGUgY2xpZW50LlxyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxdWVzdCAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlc3BvbnNlIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBuZXh0IC0gVGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IC0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgZXhwb3J0IHByb2Nlc3NcclxuICogaXMgY29tcGxldGUuXHJcbiAqL1xyXG5jb25zdCBleHBvcnRIYW5kbGVyID0gYXN5bmMgKHJlcXVlc3QsIHJlc3BvbnNlLCBuZXh0KSA9PiB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIFN0YXJ0IGNvdW50aW5nIHRpbWVcclxuICAgIGNvbnN0IHN0b3BDb3VudGVyID0gbWVhc3VyZVRpbWUoKTtcclxuXHJcbiAgICAvLyBDcmVhdGUgYSB1bmlxdWUgSUQgZm9yIGEgcmVxdWVzdFxyXG4gICAgY29uc3QgdW5pcXVlSWQgPSB1dWlkKCkucmVwbGFjZSgvLS9nLCAnJyk7XHJcblxyXG4gICAgLy8gR2V0IHRoZSBjdXJyZW50IHNlcnZlcidzIGdlbmVyYWwgb3B0aW9uc1xyXG4gICAgY29uc3QgZGVmYXVsdE9wdGlvbnMgPSBnZXRPcHRpb25zKCk7XHJcblxyXG4gICAgY29uc3QgYm9keSA9IHJlcXVlc3QuYm9keTtcclxuICAgIGNvbnN0IGlkID0gKytyZXF1ZXN0c0NvdW50ZXI7XHJcblxyXG4gICAgbGV0IHR5cGUgPSBmaXhUeXBlKGJvZHkudHlwZSk7XHJcblxyXG4gICAgLy8gVGhyb3cgJ0JhZCBSZXF1ZXN0JyBpZiB0aGVyZSdzIG5vIGJvZHlcclxuICAgIGlmICghYm9keSB8fCBpc09iamVjdEVtcHR5KGJvZHkpKSB7XHJcbiAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgJ1RoZSByZXF1ZXN0IGJvZHkgaXMgcmVxdWlyZWQuIFBsZWFzZSBlbnN1cmUgdGhhdCB5b3VyIENvbnRlbnQtVHlwZSBoZWFkZXIgaXMgY29ycmVjdCAoYWNjZXB0ZWQgdHlwZXMgYXJlIGFwcGxpY2F0aW9uL2pzb24gYW5kIG11bHRpcGFydC9mb3JtLWRhdGEpLicsXHJcbiAgICAgICAgNDAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQWxsIG9mIHRoZSBiZWxvdyBjYW4gYmUgdXNlZFxyXG4gICAgbGV0IGluc3RyID0gaXNDb3JyZWN0SlNPTihib2R5LmluZmlsZSB8fCBib2R5Lm9wdGlvbnMgfHwgYm9keS5kYXRhKTtcclxuXHJcbiAgICAvLyBUaHJvdyAnQmFkIFJlcXVlc3QnIGlmIHRoZXJlJ3Mgbm8gSlNPTiBvciBTVkcgdG8gZXhwb3J0XHJcbiAgICBpZiAoIWluc3RyICYmICFib2R5LnN2Zykge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgMixcclxuICAgICAgICBgVGhlIHJlcXVlc3Qgd2l0aCBJRCAke3VuaXF1ZUlkfSBmcm9tICR7XHJcbiAgICAgICAgICByZXF1ZXN0LmhlYWRlcnNbJ3gtZm9yd2FyZGVkLWZvciddIHx8IHJlcXVlc3QuY29ubmVjdGlvbi5yZW1vdGVBZGRyZXNzXHJcbiAgICAgICAgfSB3YXMgaW5jb3JyZWN0LiBQYXlsb2FkIHJlY2VpdmVkOiAke0pTT04uc3RyaW5naWZ5KGJvZHkpfS5gXHJcbiAgICAgICk7XHJcblxyXG4gICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgIFwiTm8gY29ycmVjdCBjaGFydCBkYXRhIGZvdW5kLiBFbnN1cmUgdGhhdCB5b3UgYXJlIHVzaW5nIGVpdGhlciBhcHBsaWNhdGlvbi9qc29uIG9yIG11bHRpcGFydC9mb3JtLWRhdGEgaGVhZGVycy4gSWYgc2VuZGluZyBKU09OLCBtYWtlIHN1cmUgdGhlIGNoYXJ0IGRhdGEgaXMgaW4gdGhlICdpbmZpbGUnLCAnb3B0aW9ucycsIG9yICdkYXRhJyBhdHRyaWJ1dGUuIElmIHNlbmRpbmcgU1ZHLCBlbnN1cmUgaXQgaXMgaW4gdGhlICdzdmcnIGF0dHJpYnV0ZS5cIixcclxuICAgICAgICA0MDBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICBsZXQgY2FsbFJlc3BvbnNlID0gZmFsc2U7XHJcblxyXG4gICAgLy8gQ2FsbCB0aGUgYmVmb3JlIHJlcXVlc3QgZnVuY3Rpb25zXHJcbiAgICBjYWxsUmVzcG9uc2UgPSBkb0NhbGxiYWNrcyhiZWZvcmVSZXF1ZXN0LCByZXF1ZXN0LCByZXNwb25zZSwge1xyXG4gICAgICBpZCxcclxuICAgICAgdW5pcXVlSWQsXHJcbiAgICAgIHR5cGUsXHJcbiAgICAgIGJvZHlcclxuICAgIH0pO1xyXG5cclxuICAgIC8vIEJsb2NrIHRoZSByZXF1ZXN0IGlmIG9uZSBvZiBhIGNhbGxiYWNrcyBmYWlsZWRcclxuICAgIGlmIChjYWxsUmVzcG9uc2UgIT09IHRydWUpIHtcclxuICAgICAgcmV0dXJuIHJlc3BvbnNlLnNlbmQoY2FsbFJlc3BvbnNlKTtcclxuICAgIH1cclxuXHJcbiAgICBsZXQgY29ubmVjdGlvbkFib3J0ZWQgPSBmYWxzZTtcclxuXHJcbiAgICAvLyBJbiBjYXNlIHRoZSBjb25uZWN0aW9uIGlzIGNsb3NlZCwgZm9yY2UgdG8gYWJvcnQgZnVydGhlciBhY3Rpb25zXHJcbiAgICByZXF1ZXN0LnNvY2tldC5vbignY2xvc2UnLCAoKSA9PiB7XHJcbiAgICAgIGNvbm5lY3Rpb25BYm9ydGVkID0gdHJ1ZTtcclxuICAgIH0pO1xyXG5cclxuICAgIGxvZyg0LCBgW2V4cG9ydF0gR290IGFuIGluY29taW5nIEhUVFAgcmVxdWVzdCB3aXRoIElEICR7dW5pcXVlSWR9LmApO1xyXG5cclxuICAgIGJvZHkuY29uc3RyID0gKHR5cGVvZiBib2R5LmNvbnN0ciA9PT0gJ3N0cmluZycgJiYgYm9keS5jb25zdHIpIHx8ICdjaGFydCc7XHJcblxyXG4gICAgLy8gR2F0aGVyIGFuZCBvcmdhbml6ZSBvcHRpb25zIGZyb20gdGhlIHBheWxvYWRcclxuICAgIGNvbnN0IHJlcXVlc3RPcHRpb25zID0ge1xyXG4gICAgICBleHBvcnQ6IHtcclxuICAgICAgICBpbnN0cixcclxuICAgICAgICB0eXBlLFxyXG4gICAgICAgIGNvbnN0cjogYm9keS5jb25zdHJbMF0udG9Mb3dlckNhc2UoKSArIGJvZHkuY29uc3RyLnN1YnN0cigxKSxcclxuICAgICAgICBoZWlnaHQ6IGJvZHkuaGVpZ2h0LFxyXG4gICAgICAgIHdpZHRoOiBib2R5LndpZHRoLFxyXG4gICAgICAgIHNjYWxlOiBib2R5LnNjYWxlIHx8IGRlZmF1bHRPcHRpb25zLmV4cG9ydC5zY2FsZSxcclxuICAgICAgICBnbG9iYWxPcHRpb25zOiBpc0NvcnJlY3RKU09OKGJvZHkuZ2xvYmFsT3B0aW9ucywgdHJ1ZSksXHJcbiAgICAgICAgdGhlbWVPcHRpb25zOiBpc0NvcnJlY3RKU09OKGJvZHkudGhlbWVPcHRpb25zLCB0cnVlKVxyXG4gICAgICB9LFxyXG4gICAgICBjdXN0b21Mb2dpYzoge1xyXG4gICAgICAgIGFsbG93Q29kZUV4ZWN1dGlvbjogZ2V0QWxsb3dDb2RlRXhlY3V0aW9uKCksXHJcbiAgICAgICAgYWxsb3dGaWxlUmVzb3VyY2VzOiBmYWxzZSxcclxuICAgICAgICByZXNvdXJjZXM6IGlzQ29ycmVjdEpTT04oYm9keS5yZXNvdXJjZXMsIHRydWUpLFxyXG4gICAgICAgIGNhbGxiYWNrOiBib2R5LmNhbGxiYWNrLFxyXG4gICAgICAgIGN1c3RvbUNvZGU6IGJvZHkuY3VzdG9tQ29kZVxyXG4gICAgICB9XHJcbiAgICB9O1xyXG5cclxuICAgIGlmIChpbnN0cikge1xyXG4gICAgICAvLyBTdHJpbmdpZnkgSlNPTiB3aXRoIG9wdGlvbnNcclxuICAgICAgcmVxdWVzdE9wdGlvbnMuZXhwb3J0Lmluc3RyID0gb3B0aW9uc1N0cmluZ2lmeShcclxuICAgICAgICBpbnN0cixcclxuICAgICAgICByZXF1ZXN0T3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0NvZGVFeGVjdXRpb25cclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBNZXJnZSB0aGUgcmVxdWVzdCBvcHRpb25zIGludG8gZGVmYXVsdCBvbmVzXHJcbiAgICBjb25zdCBvcHRpb25zID0gbWVyZ2VDb25maWdPcHRpb25zKGRlZmF1bHRPcHRpb25zLCByZXF1ZXN0T3B0aW9ucyk7XHJcblxyXG4gICAgLy8gU2F2ZSB0aGUgSlNPTiBpZiBleGlzdHNcclxuICAgIG9wdGlvbnMuZXhwb3J0Lm9wdGlvbnMgPSBpbnN0cjtcclxuXHJcbiAgICAvLyBMYXN0bHksIGFkZCB0aGUgc2VydmVyIHNwZWNpZmljIGFyZ3VtZW50cyBpbnRvIG9wdGlvbnMgYXMgcGF5bG9hZFxyXG4gICAgb3B0aW9ucy5wYXlsb2FkID0ge1xyXG4gICAgICBzdmc6IGJvZHkuc3ZnIHx8IGZhbHNlLFxyXG4gICAgICBiNjQ6IGJvZHkuYjY0IHx8IGZhbHNlLFxyXG4gICAgICBub0Rvd25sb2FkOiBib2R5Lm5vRG93bmxvYWQgfHwgZmFsc2UsXHJcbiAgICAgIHJlcXVlc3RJZDogdW5pcXVlSWRcclxuICAgIH07XHJcblxyXG4gICAgLy8gVGVzdCB4bGluazpocmVmIGVsZW1lbnRzIGZyb20gcGF5bG9hZCdzIFNWR1xyXG4gICAgaWYgKGJvZHkuc3ZnICYmIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmQob3B0aW9ucy5wYXlsb2FkLnN2ZykpIHtcclxuICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAnU1ZHIHBvdGVudGlhbGx5IGNvbnRhaW4gYXQgbGVhc3Qgb25lIGZvcmJpZGRlbiBVUkwgaW4geGxpbms6aHJlZiBlbGVtZW50LiBQbGVhc2UgcmV2aWV3IHRoZSBTVkcgY29udGVudCBhbmQgZW5zdXJlIHRoYXQgYWxsIHJlZmVyZW5jZWQgVVJMcyBjb21wbHkgd2l0aCBzZWN1cml0eSBwb2xpY2llcy4nLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFN0YXJ0IHRoZSBleHBvcnQgcHJvY2Vzc1xyXG4gICAgYXdhaXQgc3RhcnRFeHBvcnQob3B0aW9ucywgKGVycm9yLCBpbmZvKSA9PiB7XHJcbiAgICAgIC8vIFJlbW92ZSB0aGUgY2xvc2UgZXZlbnQgZnJvbSB0aGUgc29ja2V0XHJcbiAgICAgIHJlcXVlc3Quc29ja2V0LnJlbW92ZUFsbExpc3RlbmVycygnY2xvc2UnKTtcclxuXHJcbiAgICAgIC8vIEFmdGVyIHRoZSB3aG9sZSBleHBvcnRpbmcgcHJvY2Vzc1xyXG4gICAgICBpZiAoZGVmYXVsdE9wdGlvbnMuc2VydmVyLmJlbmNobWFya2luZykge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDUsXHJcbiAgICAgICAgICBgW2JlbmNobWFya10gUmVxdWVzdCB3aXRoIElEICR7dW5pcXVlSWR9IC0gQWZ0ZXIgdGhlIHdob2xlIGV4cG9ydGluZyBwcm9jZXNzOiAke3N0b3BDb3VudGVyKCl9bXMuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIElmIHRoZSBjb25uZWN0aW9uIHdhcyBjbG9zZWQsIGRvIG5vdGhpbmdcclxuICAgICAgaWYgKGNvbm5lY3Rpb25BYm9ydGVkKSB7XHJcbiAgICAgICAgcmV0dXJuIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW2V4cG9ydF0gVGhlIGNsaWVudCBjbG9zZWQgdGhlIGNvbm5lY3Rpb24gYmVmb3JlIHRoZSBjaGFydCBmaW5pc2hlZCBwcm9jZXNzaW5nLmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBJZiBlcnJvciwgbG9nIGl0IGFuZCBzZW5kIGl0IHRvIHRoZSBlcnJvciBtaWRkbGV3YXJlXHJcbiAgICAgIGlmIChlcnJvcikge1xyXG4gICAgICAgIHRocm93IGVycm9yO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBJZiBkYXRhIGlzIG1pc3NpbmcsIGxvZyB0aGUgbWVzc2FnZSBhbmQgc2VuZCBpdCB0byB0aGUgZXJyb3IgbWlkZGxld2FyZVxyXG4gICAgICBpZiAoIWluZm8gfHwgIWluZm8ucmVzdWx0KSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAgIGBVbmV4cGVjdGVkIHJldHVybiBmcm9tIGNoYXJ0IGdlbmVyYXRpb24uIFBsZWFzZSBjaGVjayB5b3VyIHJlcXVlc3QgZGF0YS4gRm9yIHRoZSByZXF1ZXN0IHdpdGggSUQgJHt1bmlxdWVJZH0sIHRoZSByZXN1bHQgaXMgJHtpbmZvLnJlc3VsdH0uYCxcclxuICAgICAgICAgIDQwMFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIEdldCB0aGUgdHlwZSBmcm9tIG9wdGlvbnNcclxuICAgICAgdHlwZSA9IGluZm8ub3B0aW9ucy5leHBvcnQudHlwZTtcclxuXHJcbiAgICAgIC8vIFRoZSBhZnRlciByZXF1ZXN0IGNhbGxiYWNrc1xyXG4gICAgICBkb0NhbGxiYWNrcyhhZnRlclJlcXVlc3QsIHJlcXVlc3QsIHJlc3BvbnNlLCB7IGlkLCBib2R5OiBpbmZvLnJlc3VsdCB9KTtcclxuXHJcbiAgICAgIGlmIChpbmZvLnJlc3VsdCkge1xyXG4gICAgICAgIC8vIElmIG9ubHkgYmFzZTY0IGlzIHJlcXVpcmVkLCByZXR1cm4gaXRcclxuICAgICAgICBpZiAoYm9keS5iNjQpIHtcclxuICAgICAgICAgIC8vIFNWRyBFeGNlcHRpb24gZm9yIHRoZSBIaWdoY2hhcnRzIDExLjMuMCB2ZXJzaW9uXHJcbiAgICAgICAgICBpZiAodHlwZSA9PT0gJ3BkZicgfHwgdHlwZSA9PSAnc3ZnJykge1xyXG4gICAgICAgICAgICByZXR1cm4gcmVzcG9uc2Uuc2VuZChcclxuICAgICAgICAgICAgICBCdWZmZXIuZnJvbShpbmZvLnJlc3VsdCwgJ3V0ZjgnKS50b1N0cmluZygnYmFzZTY0JylcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICByZXR1cm4gcmVzcG9uc2Uuc2VuZChpbmZvLnJlc3VsdCk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBTZXQgY29ycmVjdCBjb250ZW50IHR5cGVcclxuICAgICAgICByZXNwb25zZS5oZWFkZXIoJ0NvbnRlbnQtVHlwZScsIHJldmVyc2VkTWltZVt0eXBlXSB8fCAnaW1hZ2UvcG5nJyk7XHJcblxyXG4gICAgICAgIC8vIERlY2lkZSB3aGV0aGVyIHRvIGRvd25sb2FkIG9yIG5vdCBjaGFydCBmaWxlXHJcbiAgICAgICAgaWYgKCFib2R5Lm5vRG93bmxvYWQpIHtcclxuICAgICAgICAgIHJlc3BvbnNlLmF0dGFjaG1lbnQoXHJcbiAgICAgICAgICAgIGAke3JlcXVlc3QucGFyYW1zLmZpbGVuYW1lIHx8IHJlcXVlc3QuYm9keS5maWxlbmFtZSB8fCAnY2hhcnQnfS4ke1xyXG4gICAgICAgICAgICAgIHR5cGUgfHwgJ3BuZydcclxuICAgICAgICAgICAgfWBcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBJZiBTVkcsIHJldHVybiBwbGFpbiBjb250ZW50XHJcbiAgICAgICAgcmV0dXJuIHR5cGUgPT09ICdzdmcnXHJcbiAgICAgICAgICA/IHJlc3BvbnNlLnNlbmQoaW5mby5yZXN1bHQpXHJcbiAgICAgICAgICA6IHJlc3BvbnNlLnNlbmQoQnVmZmVyLmZyb20oaW5mby5yZXN1bHQsICdiYXNlNjQnKSk7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICBuZXh0KGVycm9yKTtcclxuICB9XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCAoYXBwKSA9PiB7XHJcbiAgLyoqXHJcbiAgICogQWRkcyB0aGUgUE9TVCAvIGEgcm91dGUgZm9yIGhhbmRsaW5nIFBPU1QgcmVxdWVzdHMgYXQgdGhlIHJvb3QgZW5kcG9pbnQuXHJcbiAgICovXHJcbiAgYXBwLnBvc3QoJy8nLCBleHBvcnRIYW5kbGVyKTtcclxuXHJcbiAgLyoqXHJcbiAgICogQWRkcyB0aGUgUE9TVCAvOmZpbGVuYW1lIGEgcm91dGUgZm9yIGhhbmRsaW5nIFBPU1QgcmVxdWVzdHMgd2l0aFxyXG4gICAqIGEgc3BlY2lmaWVkIGZpbGVuYW1lIHBhcmFtZXRlci5cclxuICAgKi9cclxuICBhcHAucG9zdCgnLzpmaWxlbmFtZScsIGV4cG9ydEhhbmRsZXIpO1xyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiBhcyBwYXRoZXIgfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCBjYWNoZSBmcm9tICcuLi8uLi9jYWNoZS5qcyc7XHJcbmltcG9ydCBwb29sIGZyb20gJy4uLy4uL3Bvb2wuanMnO1xyXG5pbXBvcnQgeyBfX2Rpcm5hbWUgfSBmcm9tICcuLi8uLi91dGlscy5qcyc7XHJcblxyXG5jb25zdCBwa2dGaWxlID0gSlNPTi5wYXJzZShyZWFkRmlsZVN5bmMocGF0aGVyKF9fZGlybmFtZSwgJ3BhY2thZ2UuanNvbicpKSk7XHJcblxyXG5jb25zdCBzZXJ2ZXJTdGFydFRpbWUgPSBuZXcgRGF0ZSgpO1xyXG5cclxuLyoqXHJcbiAqIEFkZHMgdGhlIEdFVCAvaGVhbHRoIHJvdXRlLCB3aGljaCBvdXRwdXRzIGJhc2ljIHN0YXRzIGZvciB0aGUgc2VydmVyLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgKGFwcCkgPT5cclxuICAhYXBwXHJcbiAgICA/IGZhbHNlXHJcbiAgICA6IGFwcC5nZXQoJy9oZWFsdGgnLCAocmVxdWVzdCwgcmVzcG9uc2UpID0+IHtcclxuICAgICAgICByZXNwb25zZS5zZW5kKHtcclxuICAgICAgICAgIHN0YXR1czogJ09LJyxcclxuICAgICAgICAgIGJvb3RUaW1lOiBzZXJ2ZXJTdGFydFRpbWUsXHJcbiAgICAgICAgICB1cHRpbWU6XHJcbiAgICAgICAgICAgIE1hdGguZmxvb3IoXHJcbiAgICAgICAgICAgICAgKG5ldyBEYXRlKCkuZ2V0VGltZSgpIC0gc2VydmVyU3RhcnRUaW1lLmdldFRpbWUoKSkgLyAxMDAwIC8gNjBcclxuICAgICAgICAgICAgKSArICcgbWludXRlcycsXHJcbiAgICAgICAgICB2ZXJzaW9uOiBwa2dGaWxlLnZlcnNpb24sXHJcbiAgICAgICAgICBoaWdoY2hhcnRzVmVyc2lvbjogY2FjaGUudmVyc2lvbigpLFxyXG4gICAgICAgICAgYXZlcmFnZVByb2Nlc3NpbmdUaW1lOiBwb29sLmF2ZXJhZ2VUaW1lKCksXHJcbiAgICAgICAgICBwZXJmb3JtZWRFeHBvcnRzOiBwb29sLnByb2Nlc3NlZFdvcmtDb3VudCgpLFxyXG4gICAgICAgICAgZmFpbGVkRXhwb3J0czogcG9vbC5kcm9wcGVkV29yaygpLFxyXG4gICAgICAgICAgZXhwb3J0QXR0ZW1wdHM6IHBvb2wud29ya0F0dGVtcHRzKCksXHJcbiAgICAgICAgICBzdWNlc3NSYXRpbzogKHBvb2wucHJvY2Vzc2VkV29ya0NvdW50KCkgLyBwb29sLndvcmtBdHRlbXB0cygpKSAqIDEwMCxcclxuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBpbXBvcnQvbm8tbmFtZWQtYXMtZGVmYXVsdC1tZW1iZXJcclxuICAgICAgICAgIHBvb2w6IHBvb2wuZ2V0UG9vbEluZm9KU09OKClcclxuICAgICAgICB9KTtcclxuICAgICAgfSk7XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgcHJvbWlzZXMgYXMgZnNQcm9taXNlcyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgcG9zaXggfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCBjb3JzIGZyb20gJ2NvcnMnO1xyXG5pbXBvcnQgZXhwcmVzcyBmcm9tICdleHByZXNzJztcclxuaW1wb3J0IGh0dHAgZnJvbSAnaHR0cCc7XHJcbmltcG9ydCBodHRwcyBmcm9tICdodHRwcyc7XHJcbmltcG9ydCBtdWx0ZXIgZnJvbSAnbXVsdGVyJztcclxuXHJcbmltcG9ydCBlcnJvckhhbmRsZXIgZnJvbSAnLi9lcnJvci5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHJhdGVMaW1pdCBmcm9tICcuL3JhdGVfbGltaXQuanMnO1xyXG5pbXBvcnQgeyBfX2Rpcm5hbWUgfSBmcm9tICcuLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgdlN3aXRjaFJvdXRlIGZyb20gJy4vcm91dGVzL2NoYW5nZV9oY192ZXJzaW9uLmpzJztcclxuaW1wb3J0IGV4cG9ydFJvdXRlcyBmcm9tICcuL3JvdXRlcy9leHBvcnQuanMnO1xyXG5pbXBvcnQgaGVhbHRoUm91dGUgZnJvbSAnLi9yb3V0ZXMvaGVhbHRoLmpzJztcclxuaW1wb3J0IHVpUm91dGUgZnJvbSAnLi9yb3V0ZXMvdWkuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4uL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vLyBDcmVhdGUgZXhwcmVzcyBhcHBcclxuY29uc3QgYXBwID0gZXhwcmVzcygpO1xyXG5cclxuLy8gRGlzYWJsZSB0aGUgWC1Qb3dlcmVkLUJ5IGhlYWRlclxyXG5hcHAuZGlzYWJsZSgneC1wb3dlcmVkLWJ5Jyk7XHJcblxyXG4vLyBFbmFibGUgQ09SUyBzdXBwb3J0XHJcbmFwcC51c2UoY29ycygpKTtcclxuXHJcbi8vIEVuYWJsZSBwYXJzaW5nIG9mIGZvcm0gZGF0YSAoZmlsZXMpIHdpdGggTXVsdGVyIHBhY2thZ2VcclxuY29uc3Qgc3RvcmFnZSA9IG11bHRlci5tZW1vcnlTdG9yYWdlKCk7XHJcbmNvbnN0IHVwbG9hZCA9IG11bHRlcih7XHJcbiAgc3RvcmFnZSxcclxuICBsaW1pdHM6IHtcclxuICAgIGZpZWxkU2l6ZTogNTAgKiAxMDI0ICogMTAyNFxyXG4gIH1cclxufSk7XHJcblxyXG4vLyBFbmFibGUgYm9keSBwYXJzZXJcclxuYXBwLnVzZShleHByZXNzLmpzb24oeyBsaW1pdDogNTAgKiAxMDI0ICogMTAyNCB9KSk7XHJcbmFwcC51c2UoZXhwcmVzcy51cmxlbmNvZGVkKHsgZXh0ZW5kZWQ6IHRydWUsIGxpbWl0OiA1MCAqIDEwMjQgKiAxMDI0IH0pKTtcclxuXHJcbi8vIFVzZSBvbmx5IG5vbi1maWxlIG11bHRpcGFydCBmb3JtIGZpZWxkc1xyXG5hcHAudXNlKHVwbG9hZC5ub25lKCkpO1xyXG5cclxuLyoqXHJcbiAqIEF0dGFjaCBlcnJvciBoYW5kbGVycyB0byB0aGUgc2VydmVyLlxyXG4gKlxyXG4gKiBAcGFyYW0ge2h0dHAuU2VydmVyfSBzZXJ2ZXIgLSBUaGUgSFRUUC9IVFRQUyBzZXJ2ZXIgaW5zdGFuY2UuXHJcbiAqL1xyXG5jb25zdCBhdHRhY2hFcnJvckhhbmRsZXJzID0gKHNlcnZlcikgPT4ge1xyXG4gIHNlcnZlci5vbignY2xpZW50RXJyb3InLCAoZXJyb3IpID0+IHtcclxuICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFtzZXJ2ZXJdIENsaWVudCBlcnJvcjogJHtlcnJvci5tZXNzYWdlfWApO1xyXG4gIH0pO1xyXG4gIHNlcnZlci5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcclxuICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFtzZXJ2ZXJdIFNlcnZlciBlcnJvcjogJHtlcnJvci5tZXNzYWdlfWApO1xyXG4gIH0pO1xyXG4gIHNlcnZlci5vbignY29ubmVjdGlvbicsIChzb2NrZXQpID0+IHtcclxuICAgIHNvY2tldC5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcclxuICAgICAgbG9nV2l0aFN0YWNrKDEsIGVycm9yLCBgW3NlcnZlcl0gU29ja2V0IGVycm9yOiAke2Vycm9yLm1lc3NhZ2V9YCk7XHJcbiAgICB9KTtcclxuICB9KTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgYW4gSFRUUCBzZXJ2ZXIgYmFzZWQgb24gdGhlIHByb3ZpZGVkIGNvbmZpZ3VyYXRpb24uIFRoZSBgc2VydmVyQ29uZmlnYFxyXG4gKiBvYmplY3QgY29udGFpbnMgYWxsIHNlcnZlciByZWxhdGVkIHByb3BlcnRpZXMgKHNlZSB0aGUgYHNlcnZlcmAgc2VjdGlvblxyXG4gKiBpbiB0aGUgYGxpYi9zY2hlbWFzL2NvbmZpZy5qc2AgZmlsZSBmb3IgYSByZWZlcmVuY2UpLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gc2VydmVyQ29uZmlnIC0gVGhlIHNlcnZlciBjb25maWd1cmF0aW9uIG9iamVjdC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IC0gVGhyb3dzIGFuIGVycm9yIGlmIHRoZSBzZXJ2ZXIgY2Fubm90IGJlIGNvbmZpZ3VyZWRcclxuICogYW5kIHN0YXJ0ZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc3RhcnRTZXJ2ZXIgPSBhc3luYyAoc2VydmVyQ29uZmlnKSA9PiB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIFN0b3AgaWYgbm90IGVuYWJsZWRcclxuICAgIGlmICghc2VydmVyQ29uZmlnLmVuYWJsZSkge1xyXG4gICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTGlzdGVuIEhUVFAgc2VydmVyXHJcbiAgICBpZiAoIXNlcnZlckNvbmZpZy5zc2wuZm9yY2UpIHtcclxuICAgICAgLy8gTWFpbiBzZXJ2ZXIgaW5zdGFuY2UgKEhUVFApXHJcbiAgICAgIGNvbnN0IGh0dHBTZXJ2ZXIgPSBodHRwLmNyZWF0ZVNlcnZlcihhcHApO1xyXG5cclxuICAgICAgLy8gQXR0YWNoIGVycm9yIGhhbmRsZXJzIGFuZCBsaXN0ZW4gdG8gdGhlIHNlcnZlclxyXG4gICAgICBhdHRhY2hFcnJvckhhbmRsZXJzKGh0dHBTZXJ2ZXIpO1xyXG5cclxuICAgICAgLy8gTGlzdGVuXHJcbiAgICAgIGh0dHBTZXJ2ZXIubGlzdGVuKHNlcnZlckNvbmZpZy5wb3J0LCBzZXJ2ZXJDb25maWcuaG9zdCk7XHJcblxyXG4gICAgICBsb2coXHJcbiAgICAgICAgMyxcclxuICAgICAgICBgW3NlcnZlcl0gU3RhcnRlZCBIVFRQIHNlcnZlciBvbiAke3NlcnZlckNvbmZpZy5ob3N0fToke3NlcnZlckNvbmZpZy5wb3J0fS5gXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTGlzdGVuIEhUVFBTIHNlcnZlclxyXG4gICAgaWYgKHNlcnZlckNvbmZpZy5zc2wuZW5hYmxlKSB7XHJcbiAgICAgIC8vIFNldCB1cCBhbiBTU0wgc2VydmVyIGFsc29cclxuICAgICAgbGV0IGtleSwgY2VydDtcclxuXHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgLy8gR2V0IHRoZSBTU0wga2V5XHJcbiAgICAgICAga2V5ID0gYXdhaXQgZnNQcm9taXNlcy5yZWFkRmlsZShcclxuICAgICAgICAgIHBvc2l4LmpvaW4oc2VydmVyQ29uZmlnLnNzbC5jZXJ0UGF0aCwgJ3NlcnZlci5rZXknKSxcclxuICAgICAgICAgICd1dGY4J1xyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIC8vIEdldCB0aGUgU1NMIGNlcnRpZmljYXRlXHJcbiAgICAgICAgY2VydCA9IGF3YWl0IGZzUHJvbWlzZXMucmVhZEZpbGUoXHJcbiAgICAgICAgICBwb3NpeC5qb2luKHNlcnZlckNvbmZpZy5zc2wuY2VydFBhdGgsICdzZXJ2ZXIuY3J0JyksXHJcbiAgICAgICAgICAndXRmOCdcclxuICAgICAgICApO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDIsXHJcbiAgICAgICAgICBgW3NlcnZlcl0gVW5hYmxlIHRvIGxvYWQga2V5L2NlcnRpZmljYXRlIGZyb20gdGhlICcke3NlcnZlckNvbmZpZy5zc2wuY2VydFBhdGh9JyBwYXRoLiBDb3VsZCBub3QgcnVuIHNlY3VyZWQgbGF5ZXIgc2VydmVyLmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAoa2V5ICYmIGNlcnQpIHtcclxuICAgICAgICAvLyBNYWluIHNlcnZlciBpbnN0YW5jZSAoSFRUUFMpXHJcbiAgICAgICAgY29uc3QgaHR0cHNTZXJ2ZXIgPSBodHRwcy5jcmVhdGVTZXJ2ZXIoYXBwKTtcclxuXHJcbiAgICAgICAgLy8gQXR0YWNoIGVycm9yIGhhbmRsZXJzIGFuZCBsaXN0ZW4gdG8gdGhlIHNlcnZlclxyXG4gICAgICAgIGF0dGFjaEVycm9ySGFuZGxlcnMoaHR0cHNTZXJ2ZXIpO1xyXG5cclxuICAgICAgICAvLyBMaXN0ZW5cclxuICAgICAgICBodHRwc1NlcnZlci5saXN0ZW4oc2VydmVyQ29uZmlnLnNzbC5wb3J0LCBzZXJ2ZXJDb25maWcuaG9zdCk7XHJcblxyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW3NlcnZlcl0gU3RhcnRlZCBIVFRQUyBzZXJ2ZXIgb24gJHtzZXJ2ZXJDb25maWcuaG9zdH06JHtzZXJ2ZXJDb25maWcuc3NsLnBvcnR9LmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRW5hYmxlIHRoZSByYXRlIGxpbWl0ZXIgaWYgY29uZmlnIHNheXMgc29cclxuICAgIGlmIChcclxuICAgICAgc2VydmVyQ29uZmlnLnJhdGVMaW1pdGluZyAmJlxyXG4gICAgICBzZXJ2ZXJDb25maWcucmF0ZUxpbWl0aW5nLmVuYWJsZSAmJlxyXG4gICAgICAhWzAsIE5hTl0uaW5jbHVkZXMoc2VydmVyQ29uZmlnLnJhdGVMaW1pdGluZy5tYXhSZXF1ZXN0cylcclxuICAgICkge1xyXG4gICAgICByYXRlTGltaXQoYXBwLCBzZXJ2ZXJDb25maWcucmF0ZUxpbWl0aW5nKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBTZXQgdXAgc3RhdGljIGZvbGRlcidzIHJvdXRlXHJcbiAgICBhcHAudXNlKGV4cHJlc3Muc3RhdGljKHBvc2l4LmpvaW4oX19kaXJuYW1lLCAncHVibGljJykpKTtcclxuXHJcbiAgICAvLyBTZXQgdXAgcm91dGVzXHJcbiAgICBoZWFsdGhSb3V0ZShhcHApO1xyXG4gICAgZXhwb3J0Um91dGVzKGFwcCk7XHJcbiAgICB1aVJvdXRlKGFwcCk7XHJcbiAgICB2U3dpdGNoUm91dGUoYXBwKTtcclxuXHJcbiAgICAvLyBTZXQgdXAgY2VudHJhbGl6ZWQgZXJyb3IgaGFuZGxlclxyXG4gICAgZXJyb3JIYW5kbGVyKGFwcCk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1tzZXJ2ZXJdIENvdWxkIG5vdCBjb25maWd1cmUgYW5kIHN0YXJ0IHRoZSBzZXJ2ZXIuJ1xyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEVuYWJsZSByYXRlIGxpbWl0aW5nIGZvciB0aGUgc2VydmVyLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gbGltaXRDb25maWcgLSBDb25maWd1cmF0aW9uIG9iamVjdCBmb3IgcmF0ZSBsaW1pdGluZy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBlbmFibGVSYXRlTGltaXRpbmcgPSAobGltaXRDb25maWcpID0+IHJhdGVMaW1pdChhcHAsIGxpbWl0Q29uZmlnKTtcclxuXHJcbi8qKlxyXG4gKiBHZXQgdGhlIEV4cHJlc3MgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IC0gVGhlIEV4cHJlc3MgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0RXhwcmVzcyA9ICgpID0+IGV4cHJlc3M7XHJcblxyXG4vKipcclxuICogR2V0IHRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gLSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0QXBwID0gKCkgPT4gYXBwO1xyXG5cclxuLyoqXHJcbiAqIEFwcGx5IG1pZGRsZXdhcmUocykgdG8gYSBzcGVjaWZpYyBwYXRoLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcGF0aCAtIFRoZSBwYXRoIHRvIHdoaWNoIHRoZSBtaWRkbGV3YXJlKHMpIHNob3VsZCBiZSBhcHBsaWVkLlxyXG4gKiBAcGFyYW0gey4uLkZ1bmN0aW9ufSBtaWRkbGV3YXJlcyAtIFRoZSBtaWRkbGV3YXJlIGZ1bmN0aW9ucyB0byBiZSBhcHBsaWVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHVzZSA9IChwYXRoLCAuLi5taWRkbGV3YXJlcykgPT4ge1xyXG4gIGFwcC51c2UocGF0aCwgLi4ubWlkZGxld2FyZXMpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFNldCB1cCBhIHJvdXRlIHdpdGggR0VUIG1ldGhvZCBhbmQgYXBwbHkgbWlkZGxld2FyZShzKS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBUaGUgcm91dGUgcGF0aC5cclxuICogQHBhcmFtIHsuLi5GdW5jdGlvbn0gbWlkZGxld2FyZXMgLSBUaGUgbWlkZGxld2FyZSBmdW5jdGlvbnMgdG8gYmUgYXBwbGllZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBnZXQgPSAocGF0aCwgLi4ubWlkZGxld2FyZXMpID0+IHtcclxuICBhcHAuZ2V0KHBhdGgsIC4uLm1pZGRsZXdhcmVzKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBTZXQgdXAgYSByb3V0ZSB3aXRoIFBPU1QgbWV0aG9kIGFuZCBhcHBseSBtaWRkbGV3YXJlKHMpLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcGF0aCAtIFRoZSByb3V0ZSBwYXRoLlxyXG4gKiBAcGFyYW0gey4uLkZ1bmN0aW9ufSBtaWRkbGV3YXJlcyAtIFRoZSBtaWRkbGV3YXJlIGZ1bmN0aW9ucyB0byBiZSBhcHBsaWVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHBvc3QgPSAocGF0aCwgLi4ubWlkZGxld2FyZXMpID0+IHtcclxuICBhcHAucG9zdChwYXRoLCAuLi5taWRkbGV3YXJlcyk7XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgc3RhcnRTZXJ2ZXIsXHJcbiAgZW5hYmxlUmF0ZUxpbWl0aW5nLFxyXG4gIGdldEV4cHJlc3MsXHJcbiAgZ2V0QXBwLFxyXG4gIHVzZSxcclxuICBnZXQsXHJcbiAgcG9zdFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCB7IF9fZGlybmFtZSB9IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSBHRVQgLyByb3V0ZSBmb3IgYSBVSSB3aGVuIGVuYWJsZWQgb24gdGhlIGV4cG9ydCBzZXJ2ZXIuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCAoYXBwKSA9PlxyXG4gICFhcHBcclxuICAgID8gZmFsc2VcclxuICAgIDogYXBwLmdldCgnLycsIChyZXF1ZXN0LCByZXNwb25zZSkgPT4ge1xyXG4gICAgICAgIHJlc3BvbnNlLnNlbmRGaWxlKGpvaW4oX19kaXJuYW1lLCAncHVibGljJywgJ2luZGV4Lmh0bWwnKSk7XHJcbiAgICAgIH0pO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCBjYWNoZSBmcm9tICcuLi8uLi9jYWNoZS5qcyc7XHJcblxyXG5pbXBvcnQgSHR0cEVycm9yIGZyb20gJy4uLy4uL2Vycm9ycy9IdHRwRXJyb3IuanMnO1xyXG5cclxuLyoqXHJcbiAqIEFkZHMgdGhlIFBPU1QgL2NoYW5nZV9oY192ZXJzaW9uLzpuZXdWZXJzaW9uIHJvdXRlIHRoYXQgY2FuIGJlIHV0aWxpemVkIHRvIG1vZGlmeVxyXG4gKiB0aGUgSGlnaGNoYXJ0cyB2ZXJzaW9uIG9uIHRoZSBzZXJ2ZXIuXHJcbiAqXHJcbiAqIFRPRE86IEFkZCBhdXRoIHRva2VuIGFuZCBjb25uZWN0IHRvIEFQSVxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgKGFwcCkgPT5cclxuICAhYXBwXHJcbiAgICA/IGZhbHNlXHJcbiAgICA6IGFwcC5wb3N0KFxyXG4gICAgICAgICcvdmVyc2lvbi9jaGFuZ2UvOm5ld1ZlcnNpb24nLFxyXG4gICAgICAgIGFzeW5jIChyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkgPT4ge1xyXG4gICAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgY29uc3QgYWRtaW5Ub2tlbiA9IHByb2Nlc3MuZW52LkhJR0hDSEFSVFNfQURNSU5fVE9LRU47XHJcblxyXG4gICAgICAgICAgICAvLyBDaGVjayB0aGUgZXhpc3RlbmNlIG9mIHRoZSB0b2tlblxyXG4gICAgICAgICAgICBpZiAoIWFkbWluVG9rZW4gfHwgIWFkbWluVG9rZW4ubGVuZ3RoKSB7XHJcbiAgICAgICAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAgICAgICAgICdUaGUgc2VydmVyIGlzIG5vdCBjb25maWd1cmVkIHRvIHBlcmZvcm0gcnVuLXRpbWUgdmVyc2lvbiBjaGFuZ2VzOiBISUdIQ0hBUlRTX0FETUlOX1RPS0VOIGlzIG5vdCBzZXQuJyxcclxuICAgICAgICAgICAgICAgIDQwMVxyXG4gICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIC8vIENoZWNrIGlmIHRoZSBoYy1hdXRoIGhlYWRlciBjb250YWluIGEgY29ycmVjdCB0b2tlblxyXG4gICAgICAgICAgICBjb25zdCB0b2tlbiA9IHJlcXVlc3QuZ2V0KCdoYy1hdXRoJyk7XHJcbiAgICAgICAgICAgIGlmICghdG9rZW4gfHwgdG9rZW4gIT09IGFkbWluVG9rZW4pIHtcclxuICAgICAgICAgICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgICAgICAgICAgJ0ludmFsaWQgb3IgbWlzc2luZyB0b2tlbjogU2V0IHRoZSB0b2tlbiBpbiB0aGUgaGMtYXV0aCBoZWFkZXIuJyxcclxuICAgICAgICAgICAgICAgIDQwMVxyXG4gICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIC8vIENvbXBhcmUgdmVyc2lvbnNcclxuICAgICAgICAgICAgY29uc3QgbmV3VmVyc2lvbiA9IHJlcXVlc3QucGFyYW1zLm5ld1ZlcnNpb247XHJcbiAgICAgICAgICAgIGlmIChuZXdWZXJzaW9uKSB7XHJcbiAgICAgICAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBpbXBvcnQvbm8tbmFtZWQtYXMtZGVmYXVsdC1tZW1iZXJcclxuICAgICAgICAgICAgICAgIGF3YWl0IGNhY2hlLnVwZGF0ZVZlcnNpb24obmV3VmVyc2lvbik7XHJcbiAgICAgICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgICAgICAgICAgIGBWZXJzaW9uIGNoYW5nZTogJHtlcnJvci5tZXNzYWdlfWAsXHJcbiAgICAgICAgICAgICAgICAgIGVycm9yLnN0YXR1c0NvZGVcclxuICAgICAgICAgICAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgLy8gU3VjY2Vzc1xyXG4gICAgICAgICAgICAgIHJlc3BvbnNlLnN0YXR1cygyMDApLnNlbmQoe1xyXG4gICAgICAgICAgICAgICAgc3RhdHVzQ29kZTogMjAwLFxyXG4gICAgICAgICAgICAgICAgdmVyc2lvbjogY2FjaGUudmVyc2lvbigpLFxyXG4gICAgICAgICAgICAgICAgbWVzc2FnZTogYFN1Y2Nlc3NmdWxseSB1cGRhdGVkIEhpZ2hjaGFydHMgdG8gdmVyc2lvbjogJHtuZXdWZXJzaW9ufS5gXHJcbiAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgLy8gTm8gdmVyc2lvbiBzcGVjaWZpZWRcclxuICAgICAgICAgICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKCdObyBuZXcgdmVyc2lvbiBzdXBwbGllZC4nLCA0MDApO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICBuZXh0KGVycm9yKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICk7XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0ICdjb2xvcnMnO1xyXG5pbXBvcnQgZG90ZW52IGZyb20gJ2RvdGVudic7XHJcblxyXG5pbXBvcnQgeyBjaGVja0FuZFVwZGF0ZUNhY2hlIH0gZnJvbSAnLi9jYWNoZS5qcyc7XHJcbmltcG9ydCB7XHJcbiAgYmF0Y2hFeHBvcnQsXHJcbiAgc2V0QWxsb3dDb2RlRXhlY3V0aW9uLFxyXG4gIHNpbmdsZUV4cG9ydCxcclxuICBzdGFydEV4cG9ydFxyXG59IGZyb20gJy4vY2hhcnQuanMnO1xyXG5pbXBvcnQgeyBtYXBUb05ld0NvbmZpZywgbWFudWFsQ29uZmlnLCBzZXRPcHRpb25zIH0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQge1xyXG4gIGluaXRMb2dnaW5nLFxyXG4gIGxvZyxcclxuICBsb2dXaXRoU3RhY2ssXHJcbiAgc2V0TG9nTGV2ZWwsXHJcbiAgZW5hYmxlRmlsZUxvZ2dpbmdcclxufSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IGluaXRQb29sLCBraWxsUG9vbCB9IGZyb20gJy4vcG9vbC5qcyc7XHJcbmltcG9ydCBzZXJ2ZXIsIHsgc3RhcnRTZXJ2ZXIgfSBmcm9tICcuL3NlcnZlci9zZXJ2ZXIuanMnO1xyXG5pbXBvcnQgeyBwcmludExvZ28sIHByaW50VXNhZ2UgfSBmcm9tICcuL3V0aWxzLmpzJztcclxuXHJcbi8vIExvYWQgLmVudiBpbnRvIGVudmlyb25tZW50IHZhcmlhYmxlc1xyXG5kb3RlbnYuY29uZmlnKCk7XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgdGhlIGV4cG9ydCBwcm9jZXNzLiBUYXNrcyBzdWNoIGFzIGNvbmZpZ3VyaW5nIGxvZ2dpbmcsIGNoZWNraW5nXHJcbiAqIGNhY2hlIGFuZCBzb3VyY2VzLCBhbmQgaW5pdGlhbGl6aW5nIHRoZSBwb29sIG9mIHJlc291cmNlcyBoYXBwZW4gZHVyaW5nXHJcbiAqIHRoaXMgc3RhZ2UuIEZ1bmN0aW9uIHRoYXQgaXMgcmVxdWlyZWQgdG8gYmUgY2FsbGVkIGJlZm9yZSB0cnlpbmcgdG8gZXhwb3J0IGNoYXJ0cyBvciBzZXR0aW5nIGEgc2VydmVyLiBUaGUgYG9wdGlvbnNgIGlzIGFuIG9iamVjdCB0aGF0IGNvbnRhaW5zIGFsbCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIEFsbCBleHBvcnQgb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIHVwZGF0ZWQgZXhwb3J0IG9wdGlvbnMuXHJcbiAqL1xyXG5jb25zdCBpbml0RXhwb3J0ID0gYXN5bmMgKG9wdGlvbnMpID0+IHtcclxuICAvLyBTZXQgdGhlIGFsbG93Q29kZUV4ZWN1dGlvbiBwZXIgZXhwb3J0IG1vZHVsZSBzY29wZVxyXG4gIHNldEFsbG93Q29kZUV4ZWN1dGlvbihcclxuICAgIG9wdGlvbnMuY3VzdG9tTG9naWMgJiYgb3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0NvZGVFeGVjdXRpb25cclxuICApO1xyXG5cclxuICAvLyBJbml0IHRoZSBsb2dnaW5nXHJcbiAgaW5pdExvZ2dpbmcob3B0aW9ucy5sb2dnaW5nKTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgY2FjaGUgbmVlZHMgdG8gYmUgdXBkYXRlZFxyXG4gIGF3YWl0IGNoZWNrQW5kVXBkYXRlQ2FjaGUob3B0aW9ucy5oaWdoY2hhcnRzIHx8IHsgdmVyc2lvbjogJ2xhdGVzdCcgfSk7XHJcblxyXG4gIC8vIEluaXQgdGhlIHBvb2xcclxuICBhd2FpdCBpbml0UG9vbCh7XHJcbiAgICBwb29sOiBvcHRpb25zLnBvb2wgfHwge1xyXG4gICAgICBtaW5Xb3JrZXJzOiAxLFxyXG4gICAgICBtYXhXb3JrZXJzOiAxXHJcbiAgICB9LFxyXG4gICAgcHVwcGV0ZWVyQXJnczogb3B0aW9ucy5wdXBwZXRlZXI/LmFyZ3MgfHwgW11cclxuICB9KTtcclxuXHJcbiAgLy8gUmV0dXJuIHVwZGF0ZWQgb3B0aW9uc1xyXG4gIHJldHVybiBvcHRpb25zO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIC8vIFNlcnZlclxyXG4gIHNlcnZlcixcclxuICBzdGFydFNlcnZlcixcclxuICBzZXRPcHRpb25zLFxyXG5cclxuICAvLyBFeHBvcnRpbmdcclxuICBpbml0RXhwb3J0LFxyXG4gIHNpbmdsZUV4cG9ydCxcclxuICBiYXRjaEV4cG9ydCxcclxuICBzdGFydEV4cG9ydCxcclxuICBraWxsUG9vbCxcclxuXHJcbiAgLy8gTG9nc1xyXG4gIGxvZyxcclxuICBsb2dXaXRoU3RhY2ssXHJcbiAgc2V0TG9nTGV2ZWwsXHJcbiAgZW5hYmxlRmlsZUxvZ2dpbmcsXHJcblxyXG4gIC8vIFV0aWxzXHJcbiAgbWFwVG9OZXdDb25maWcsXHJcbiAgbWFudWFsQ29uZmlnLFxyXG4gIHByaW50TG9nbyxcclxuICBwcmludFVzYWdlXHJcbn07XHJcbiJdLCJuYW1lcyI6WyJhc3luYyIsImZldGNoIiwidXJsIiwicmVxdWVzdE9wdGlvbnMiLCJQcm9taXNlIiwicmVzb2x2ZSIsInJlamVjdCIsInByb3RvY29sIiwic3RhcnRzV2l0aCIsImh0dHBzIiwiaHR0cCIsImdldFByb3RvY29sIiwiZ2V0IiwicmVzIiwiZGF0YSIsIm9uIiwiY2h1bmsiLCJ0ZXh0IiwiZXJyb3IiLCJkZWZhdWx0Q29uZmlnIiwicHVwcGV0ZWVyIiwiYXJncyIsInZhbHVlIiwidHlwZSIsImRlc2NyaXB0aW9uIiwiaGlnaGNoYXJ0cyIsInZlcnNpb24iLCJlbnZMaW5rIiwiY2RuVVJMIiwiY29yZVNjcmlwdHMiLCJtb2R1bGVzIiwiaW5kaWNhdG9ycyIsInNjcmlwdHMiLCJmb3JjZUZldGNoIiwiY2FjaGVQYXRoIiwiZXhwb3J0IiwiaW5maWxlIiwiaW5zdHIiLCJvcHRpb25zIiwib3V0ZmlsZSIsImNvbnN0ciIsImRlZmF1bHRIZWlnaHQiLCJkZWZhdWx0V2lkdGgiLCJkZWZhdWx0U2NhbGUiLCJoZWlnaHQiLCJ3aWR0aCIsInNjYWxlIiwiZ2xvYmFsT3B0aW9ucyIsInRoZW1lT3B0aW9ucyIsImJhdGNoIiwicmFzdGVyaXphdGlvblRpbWVvdXQiLCJjdXN0b21Mb2dpYyIsImFsbG93Q29kZUV4ZWN1dGlvbiIsImFsbG93RmlsZVJlc291cmNlcyIsImN1c3RvbUNvZGUiLCJjYWxsYmFjayIsInJlc291cmNlcyIsImxvYWRDb25maWciLCJsZWdhY3lOYW1lIiwiY3JlYXRlQ29uZmlnIiwic2VydmVyIiwiZW5hYmxlIiwiY2xpTmFtZSIsImhvc3QiLCJwb3J0IiwiYmVuY2htYXJraW5nIiwic3NsIiwiZm9yY2UiLCJjZXJ0UGF0aCIsInJhdGVMaW1pdGluZyIsIm1heFJlcXVlc3RzIiwid2luZG93IiwiZGVsYXkiLCJ0cnVzdFByb3h5Iiwic2tpcEtleSIsInNraXBUb2tlbiIsInBvb2wiLCJtaW5Xb3JrZXJzIiwibWF4V29ya2VycyIsIndvcmtMaW1pdCIsImFjcXVpcmVUaW1lb3V0IiwiY3JlYXRlVGltZW91dCIsImRlc3Ryb3lUaW1lb3V0IiwiaWRsZVRpbWVvdXQiLCJjcmVhdGVSZXRyeUludGVydmFsIiwicmVhcGVySW50ZXJ2YWwiLCJsaXN0ZW5Ub1Byb2Nlc3NFeGl0cyIsImxvZ2dpbmciLCJsZXZlbCIsImZpbGUiLCJkZXN0IiwidWkiLCJyb3V0ZSIsIm90aGVyIiwibm9Mb2dvIiwicHJvbXB0c0NvbmZpZyIsIm5hbWUiLCJtZXNzYWdlIiwiaW5pdGlhbCIsImpvaW4iLCJzZXBhcmF0b3IiLCJpbnN0cnVjdGlvbnMiLCJjaG9pY2VzIiwiaGludCIsIm1pbiIsIm1heCIsInJvdW5kIiwiYWJzb2x1dGVQcm9wcyIsIm5lc3RlZEFyZ3MiLCJjcmVhdGVOZXN0ZWRBcmdzIiwib2JqIiwicHJvcENoYWluIiwiT2JqZWN0Iiwia2V5cyIsImZvckVhY2giLCJrIiwiaW5jbHVkZXMiLCJlbnRyeSIsInN1YnN0cmluZyIsInVuZGVmaW5lZCIsImNvbG9ycyIsInRvQ29uc29sZSIsInRvRmlsZSIsInBhdGhDcmVhdGVkIiwibGV2ZWxzRGVzYyIsInRpdGxlIiwiY29sb3IiLCJsaXN0ZW5lcnMiLCJrZXkiLCJvcHRpb24iLCJlbnRyaWVzIiwibG9nVG9GaWxlIiwidGV4dHMiLCJwcmVmaXgiLCJleGlzdHNTeW5jIiwibWtkaXJTeW5jIiwiYXBwZW5kRmlsZSIsImNvbmNhdCIsImNvbnNvbGUiLCJsb2ciLCJuZXdMZXZlbCIsImxlbmd0aCIsIkRhdGUiLCJ0b1N0cmluZyIsInNwbGl0IiwidHJpbSIsImZuIiwiYXBwbHkiLCJsb2dXaXRoU3RhY2siLCJjdXN0b21NZXNzYWdlIiwibWFpbk1lc3NhZ2UiLCJzdGFja01lc3NhZ2UiLCJzdGFjayIsInNsaWNlIiwic2V0TG9nTGV2ZWwiLCJlbmFibGVGaWxlTG9nZ2luZyIsImxvZ0Rlc3QiLCJsb2dGaWxlIiwiZW5kc1dpdGgiLCJfX2Rpcm5hbWUiLCJmaWxlVVJMVG9QYXRoIiwiVVJMIiwiZG9jdW1lbnQiLCJyZXF1aXJlIiwicGF0aFRvRmlsZVVSTCIsIl9fZmlsZW5hbWUiLCJocmVmIiwiX2RvY3VtZW50Q3VycmVudFNjcmlwdCIsInNyYyIsImJhc2VVUkkiLCJmaXhUeXBlIiwiZm9ybWF0cyIsIm91dFR5cGUiLCJwb3AiLCJmaW5kIiwidCIsImhhbmRsZVJlc291cmNlcyIsImFsbG93ZWRQcm9wcyIsImhhbmRsZWRSZXNvdXJjZXMiLCJjb3JyZWN0UmVzb3VyY2VzIiwiaXNDb3JyZWN0SlNPTiIsInJlYWRGaWxlU3luYyIsImZpbGVzIiwicHJvcE5hbWUiLCJtYXAiLCJpdGVtIiwicGFyc2VkRGF0YSIsIkpTT04iLCJwYXJzZSIsInN0cmluZ2lmeSIsImRlZXBDb3B5IiwiY29weSIsIkFycmF5IiwiaXNBcnJheSIsInByb3RvdHlwZSIsImhhc093blByb3BlcnR5IiwiY2FsbCIsIm9wdGlvbnNTdHJpbmdpZnkiLCJhbGxvd0Z1bmN0aW9ucyIsInJlcGxhY2VBbGwiLCJwcmludFVzYWdlIiwiYm9sZCIsInllbGxvdyIsImN5Y2xlQ2F0ZWdvcmllcyIsImRlc2NOYW1lIiwiZ3JlZW4iLCJpIiwiYmx1ZSIsImNhdGVnb3J5IiwidG9VcHBlckNhc2UiLCJyZWQiLCJ0b0Jvb2xlYW4iLCJ3cmFwQXJvdW5kIiwicmVwbGFjZSIsIm1lYXN1cmVUaW1lIiwic3RhcnQiLCJwcm9jZXNzIiwiaHJ0aW1lIiwiYmlnaW50IiwiTnVtYmVyIiwiRXhwb3J0RXJyb3IiLCJFcnJvciIsImNvbnN0cnVjdG9yIiwic3VwZXIiLCJ0aGlzIiwic2V0RXJyb3IiLCJzdGF0dXNDb2RlIiwiY2FjaGUiLCJhY3RpdmVNYW5pZmVzdCIsInNvdXJjZXMiLCJoY1ZlcnNpb24iLCJhcHBsaWVkQ29uZmlnIiwiZXh0cmFjdFZlcnNpb24iLCJpbmRleE9mIiwiZmV0Y2hBbmRQcm9jZXNzU2NyaXB0Iiwic2NyaXB0IiwicHJveHlBZ2VudCIsImZldGNoZWRNb2R1bGVzIiwic2hvdWxkVGhyb3dFcnJvciIsImFnZW50IiwidGltZW91dCIsImVudiIsInJlc3BvbnNlIiwidXBkYXRlQ2FjaGUiLCJjb25maWciLCJzb3VyY2VQYXRoIiwiY3VzdG9tU2NyaXB0cyIsInByb3h5SG9zdCIsInByb3h5UG9ydCIsIkh0dHBzUHJveHlBZ2VudCIsIm1vZHVsZVNjcmlwdHMiLCJhbGxGZXRjaFByb21pc2VzIiwiYWxsIiwiZmV0Y2hTY3JpcHRzIiwiYyIsIm0iLCJ3cml0ZUZpbGVTeW5jIiwiY2hlY2tBbmRVcGRhdGVDYWNoZSIsIm1hbmlmZXN0UGF0aCIsInJlcXVlc3RVcGRhdGUiLCJtYW5pZmVzdCIsIm1vZHVsZU1hcCIsIm51bWJlck9mTW9kdWxlcyIsInNvbWUiLCJtb2R1bGVOYW1lIiwibmV3TWFuaWZlc3QiLCJzYXZlQ29uZmlnVG9NYW5pZmVzdCIsImdldENhY2hlUGF0aCIsImNhY2hlJDEiLCJuZXdWZXJzaW9uIiwiYXNzaWduIiwiZ2VuZXJhbE9wdGlvbnMiLCJnZXRPcHRpb25zIiwibWVyZ2VDb25maWdPcHRpb25zIiwibmV3T3B0aW9ucyIsIm1lcmdlZE9wdGlvbnMiLCJ1cGRhdGVEZWZhdWx0Q29uZmlnIiwiY29uZmlnT2JqIiwiY3VzdG9tT2JqIiwiY3VzdG9tVmFsdWUiLCJudW1FbnZWYWwiLCJlbCIsImluaXRPcHRpb25zIiwiaXRlbXMiLCJyZWN1cnNpdmVQcm9wcyIsIm9iamVjdFRvVXBkYXRlIiwibmVzdGVkTmFtZXMiLCJzaGlmdCIsIlJBTkRPTV9QSUQiLCJyYW5kb21CeXRlcyIsIlBVUFBFVEVFUl9ESVIiLCJwYXRoIiwibWluaW1hbEFyZ3MiLCJ0ZW1wbGF0ZSIsImZzIiwiYnJvd3NlciIsInNldFBhZ2VDb250ZW50IiwicGFnZSIsInNldENvbnRlbnQiLCJhZGRTY3JpcHRUYWciLCJldmFsdWF0ZSIsInNldHVwSGlnaGNoYXJ0cyIsIiRldmFsIiwiZWxlbWVudCIsImVycm9yTWVzc2FnZSIsIl9kaXNwbGF5RXJyb3JzIiwiaW5uZXJIVE1MIiwiY2xlYXJQYWdlIiwiaGFyZFJlc2V0IiwiZ290byIsImJvZHkiLCJuZXdQYWdlIiwic2V0Q2FjaGVFbmFibGVkIiwiY2xvc2UiLCJpc0Nvbm5lY3RlZCIsIl9fYmFzZWRpciIsInNldEFzQ29uZmlnIiwiY2hhcnQiLCJ0cmlnZ2VyRXhwb3J0IiwicHVwcGV0ZWVyRXhwb3J0IiwiaW5qZWN0ZWRSZXNvdXJjZXMiLCJjbGVhckluamVjdGVkIiwiZGlzcG9zZSIsInNjcmlwdHNUb1JlbW92ZSIsImdldEVsZW1lbnRzQnlUYWdOYW1lIiwic3R5bGVzVG9SZW1vdmUiLCJsaW5rc1RvUmVtb3ZlIiwicmVtb3ZlIiwiZXhwb3J0T3B0aW9ucyIsInJlcXVlc3RBbmltYXRpb25GcmFtZSIsImRpc3BsYXlFcnJvcnMiLCJkZWJ1Z2dlciIsImlzU1ZHIiwiZCIsInN2Z1RlbXBsYXRlIiwic3RySW5qIiwianMiLCJwdXNoIiwiY29udGVudCIsImlzTG9jYWwiLCJjc3MiLCJjc3NJbXBvcnRzIiwibWF0Y2giLCJjc3NJbXBvcnRQYXRoIiwiYWRkU3R5bGVUYWciLCJzaXplIiwiY2hhcnRIZWlnaHQiLCJiYXNlVmFsIiwiY2hhcnRXaWR0aCIsInBhcnNlRmxvYXQiLCJIaWdoY2hhcnRzIiwiY2hhcnRzIiwidmlld3BvcnRIZWlnaHQiLCJNYXRoIiwiY2VpbCIsInZpZXdwb3J0V2lkdGgiLCJzZXRWaWV3cG9ydCIsImRldmljZVNjYWxlRmFjdG9yIiwiem9vbUNhbGxiYWNrIiwic3R5bGUiLCJ6b29tIiwibWFyZ2luIiwieCIsInkiLCJnZXRCb3VuZGluZ0NsaWVudFJlY3QiLCJ0cnVuYyIsImdldENsaXBSZWdpb24iLCJvdXRlckhUTUwiLCJjcmVhdGVTVkciLCJlbmNvZGluZyIsImNsaXAiLCJyYWNlIiwic2NyZWVuc2hvdCIsIm9taXRCYWNrZ3JvdW5kIiwiX3Jlc29sdmUiLCJzZXRUaW1lb3V0IiwiY3JlYXRlSW1hZ2UiLCJwZGYiLCJjcmVhdGVQREYiLCJvbGRDaGFydHMiLCJvbGRDaGFydCIsImRlc3Ryb3kiLCJwdXBwZXRlZXJBcmdzIiwicGVyZm9ybWVkRXhwb3J0cyIsImV4cG9ydEF0dGVtcHRzIiwidGltZVNwZW50IiwiZHJvcHBlZEV4cG9ydHMiLCJzcGVudEF2ZXJhZ2UiLCJwb29sQ29uZmlnIiwiZmFjdG9yeSIsImNyZWF0ZSIsImlkIiwidXVpZCIsInN0YXJ0RGF0ZSIsImdldFRpbWUiLCJicm93c2VyTmV3UGFnZSIsImlzQ2xvc2VkIiwid29ya0NvdW50IiwicmFuZG9tIiwidmFsaWRhdGUiLCJ3b3JrZXJIYW5kbGUiLCJpbml0UG9vbCIsImNvZGUiLCJraWxsUG9vbCIsImV4aXQiLCJhbGxBcmdzIiwidHJ5Q291bnQiLCJvcGVuIiwibGF1bmNoIiwiaGVhZGxlc3MiLCJ1c2VyRGF0YURpciIsImNyZWF0ZUJyb3dzZXIiLCJwYXJzZUludCIsIlBvb2wiLCJhY3F1aXJlVGltZW91dE1pbGxpcyIsImNyZWF0ZVRpbWVvdXRNaWxsaXMiLCJkZXN0cm95VGltZW91dE1pbGxpcyIsImlkbGVUaW1lb3V0TWlsbGlzIiwiY3JlYXRlUmV0cnlJbnRlcnZhbE1pbGxpcyIsInJlYXBJbnRlcnZhbE1pbGxpcyIsInByb3BhZ2F0ZUNyZWF0ZUVycm9yIiwicmVzb3VyY2UiLCJldmVudElkIiwiaW5pdGlhbFJlc291cmNlcyIsImFjcXVpcmUiLCJwcm9taXNlIiwicmVsZWFzZSIsImJyb3dzZXJDbG9zZSIsImRlc3Ryb3llZCIsInBvc3RXb3JrIiwiZ2V0UG9vbEluZm8iLCJhY3F1aXJlQ291bnRlciIsInBheWxvYWQiLCJyZXF1ZXN0SWQiLCJ3b3JrU3RhcnQiLCJleHBvcnRDb3VudGVyIiwicmVzdWx0IiwiZXhwb3J0VGltZSIsIm51bUZyZWUiLCJudW1Vc2VkIiwibnVtUGVuZGluZ0FjcXVpcmVzIiwicG9vbCQxIiwiYXZhaWxhYmxlIiwiaW5Vc2UiLCJwZW5kaW5nQWNxdWlyZSIsInN0YXJ0RXhwb3J0Iiwic2V0dGluZ3MiLCJlbmRDYWxsYmFjayIsInN2ZyIsImluaXRFeHBvcnRTZXR0aW5ncyIsImV4cG9ydEFzU3RyaW5nIiwiZG9TdHJhaWdodEluamVjdCIsImRvRXhwb3J0IiwiZmluZENoYXJ0U2l6ZSIsImV4cG9ydGluZyIsInByZWNpc2lvbiIsIm11bHRpcGxpZXIiLCJwb3ciLCJyb3VuZE51bWJlciIsInNvdXJjZUhlaWdodCIsInNvdXJjZVdpZHRoIiwicGFyYW0iLCJjaGFydEpzb24iLCJjdXN0b21Mb2dpY09wdGlvbnMiLCJhbGxvd0NvZGVFeGVjdXRpb25TY29wZWQiLCJlbmFibGVkIiwib3B0aW9uc05hbWUiLCJzdHJpbmdUb0V4cG9ydCIsImNoYXJ0SlNPTiIsImxvZ0Vycm9yTWlkZGxld2FyZSIsInJlcSIsIm5leHQiLCJOT0RFX0VOViIsInJldHVybkVycm9yTWlkZGxld2FyZSIsInN0Q29kZSIsInN0YXR1cyIsImpzb24iLCJyYXRlTGltaXQiLCJhcHAiLCJsaW1pdENvbmZpZyIsIm1zZyIsInJhdGVPcHRpb25zIiwibGltaXRlciIsIndpbmRvd01zIiwiZGVsYXlNcyIsImhhbmRsZXIiLCJyZXF1ZXN0IiwiZm9ybWF0Iiwic2VuZCIsImRlZmF1bHQiLCJza2lwIiwicXVlcnkiLCJhY2Nlc3NfdG9rZW4iLCJ1c2UiLCJIdHRwRXJyb3IiLCJzZXRTdGF0dXMiLCJyZXZlcnNlZE1pbWUiLCJwbmciLCJqcGVnIiwiZ2lmIiwicmVxdWVzdHNDb3VudGVyIiwiYmVmb3JlUmVxdWVzdCIsImFmdGVyUmVxdWVzdCIsImRvQ2FsbGJhY2tzIiwiY2FsbGJhY2tzIiwidW5pcXVlSWQiLCJjYWxsUmVzcG9uc2UiLCJleHBvcnRIYW5kbGVyIiwic3RvcENvdW50ZXIiLCJkZWZhdWx0T3B0aW9ucyIsImhlYWRlcnMiLCJjb25uZWN0aW9uIiwicmVtb3RlQWRkcmVzcyIsImNvbm5lY3Rpb25BYm9ydGVkIiwic29ja2V0IiwidG9Mb3dlckNhc2UiLCJzdWJzdHIiLCJiNjQiLCJub0Rvd25sb2FkIiwiaXBSZWdFeCIsImlzUHJpdmF0ZVJhbmdlVXJsRm91bmQiLCJpbmZvIiwicmVtb3ZlQWxsTGlzdGVuZXJzIiwiQnVmZmVyIiwiZnJvbSIsImhlYWRlciIsImF0dGFjaG1lbnQiLCJwYXJhbXMiLCJmaWxlbmFtZSIsInBrZ0ZpbGUiLCJwYXRoZXIiLCJzZXJ2ZXJTdGFydFRpbWUiLCJleHByZXNzIiwiZGlzYWJsZSIsImNvcnMiLCJzdG9yYWdlIiwibXVsdGVyIiwibWVtb3J5U3RvcmFnZSIsInVwbG9hZCIsImxpbWl0cyIsImZpZWxkU2l6ZSIsImxpbWl0IiwidXJsZW5jb2RlZCIsImV4dGVuZGVkIiwibm9uZSIsImF0dGFjaEVycm9ySGFuZGxlcnMiLCJzdGFydFNlcnZlciIsInNlcnZlckNvbmZpZyIsImh0dHBTZXJ2ZXIiLCJjcmVhdGVTZXJ2ZXIiLCJsaXN0ZW4iLCJjZXJ0IiwiZnNQcm9taXNlcyIsInJlYWRGaWxlIiwicG9zaXgiLCJodHRwc1NlcnZlciIsIk5hTiIsInN0YXRpYyIsImJvb3RUaW1lIiwidXB0aW1lIiwiZmxvb3IiLCJoaWdoY2hhcnRzVmVyc2lvbiIsImF2ZXJhZ2VQcm9jZXNzaW5nVGltZSIsImZhaWxlZEV4cG9ydHMiLCJzdWNlc3NSYXRpbyIsImhlYWx0aFJvdXRlIiwicG9zdCIsImV4cG9ydFJvdXRlcyIsInNlbmRGaWxlIiwidWlSb3V0ZSIsImFkbWluVG9rZW4iLCJISUdIQ0hBUlRTX0FETUlOX1RPS0VOIiwidG9rZW4iLCJ2U3dpdGNoUm91dGUiLCJlcnJvckhhbmRsZXIiLCJlbmFibGVSYXRlTGltaXRpbmciLCJnZXRFeHByZXNzIiwiZ2V0QXBwIiwibWlkZGxld2FyZXMiLCJkb3RlbnYiLCJpbmRleCIsInNldE9wdGlvbnMiLCJ1c2VyT3B0aW9ucyIsImNvbmZpZ0luZGV4IiwiZmluZEluZGV4IiwiYXJnIiwiZmlsZU5hbWUiLCJsb2FkQ29uZmlnRmlsZSIsInNob3dVc2FnZSIsInByb3BlcnRpZXNDaGFpbiIsImFyZ3VtZW50VHlwZSIsInJlZHVjZSIsInByb3AiLCJwYWlyQXJndW1lbnRWYWx1ZSIsImluaXRFeHBvcnQiLCJpbml0TG9nZ2luZyIsInNpbmdsZUV4cG9ydCIsImJhdGNoRXhwb3J0IiwiYmF0Y2hGdW5jdGlvbnMiLCJwYWlyIiwibWFwVG9OZXdDb25maWciLCJvbGRPcHRpb25zIiwibWFudWFsQ29uZmlnIiwiY29uZmlnRmlsZU5hbWUiLCJjb25maWdGaWxlIiwiY2hvaWNlIiwicHJvbXB0cyIsIm9uU3VibWl0IiwicCIsImNhdGVnb3JpZXMiLCJxdWVzdGlvbnNDb3VudGVyIiwiYWxsUXVlc3Rpb25zIiwic2VjdGlvbiIsInByb21wdCIsImFuc3dlciIsIm1vZHVsZSIsInByb21pc2VzIiwid3JpdGVGaWxlIiwicHJpbnRMb2dvIiwicGFja2FnZVZlcnNpb24iXSwibWFwcGluZ3MiOiJrdEJBeUJBQSxlQUFlQyxFQUFNQyxFQUFLQyxFQUFpQixJQUN6QyxPQUFPLElBQUlDLFNBQVEsQ0FBQ0MsRUFBU0MsS0FDM0IsTUFBTUMsRUFiVSxDQUFDTCxHQUFTQSxFQUFJTSxXQUFXLFNBQVdDLEVBQVFDLEVBYTNDQyxDQUFZVCxHQUU3QkssRUFDR0ssSUFBSVYsRUFBS0MsR0FBaUJVLElBQ3pCLElBQUlDLEVBQU8sR0FHWEQsRUFBSUUsR0FBRyxRQUFTQyxJQUNkRixHQUFRRSxDQUFLLElBSWZILEVBQUlFLEdBQUcsT0FBTyxLQUNQRCxHQUNIUixFQUFPLHFDQUdUTyxFQUFJSSxLQUFPSCxFQUNYVCxFQUFRUSxFQUFJLEdBQ1osSUFFSEUsR0FBRyxTQUFVRyxJQUNaWixFQUFPWSxFQUFNLEdBQ2IsR0FFUixDQ3BDTyxNQUFNQyxFQUFnQixDQUMzQkMsVUFBVyxDQUNUQyxLQUFNLENBQ0pDLE1BQU8sR0FDUEMsS0FBTSxXQUNOQyxZQUFhLDBDQUdqQkMsV0FBWSxDQUNWQyxRQUFTLENBQ1BKLE1BQU8sU0FDUEssUUFBUyxxQkFDVEosS0FBTSxTQUNOQyxZQUFhLHNDQUVmSSxPQUFRLENBQ05OLE1BQU8sK0JBQ1BLLFFBQVMscUJBQ1RKLEtBQU0sU0FDTkMsWUFBYSxrREFFZkssWUFBYSxDQUNYRixRQUFTLDBCQUNUTCxNQUFPLENBQUMsYUFBYyxrQkFBbUIsaUJBQ3pDQyxLQUFNLFdBQ05DLFlBQWEseUNBRWZNLFFBQVMsQ0FDUEgsUUFBUyxxQkFDVEwsTUFBTyxDQUNMLFFBQ0EsTUFDQSxRQUNBLFlBQ0EsY0FDQSx1QkFDQSxnQkFDQSx1QkFDQSxlQUNBLFFBQ0EsT0FDQSxhQUNBLG1CQUNBLGVBQ0EsY0FDQSxVQUNBLFVBQ0EsY0FDQSxXQUNBLFVBQ0EsWUFDQSxjQUNBLFlBQ0Esc0JBQ0EsU0FDQSxT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 diff --git a/dist/index.esm.js b/dist/index.esm.js index bc6ef3c7..f0007d84 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 i,readFileSync as o,writeFileSync as n,promises as s}from"fs";import a,{join as l,posix as c}from"path";import p from"dotenv";import{HttpsProxyAgent as h}from"https-proxy-agent";import u from"http";import d from"https";import*as g from"url";import{fileURLToPath as m}from"url";import f from"prompts";import{Pool as v}from"tarn";import{v4 as y}from"uuid";import w from"node:path";import b from"puppeteer";import{randomBytes as T}from"node:crypto";import k from"cors";import x from"express";import E from"multer";import L from"express-rate-limit";async function S(e,t={}){return new Promise(((r,i)=>{const o=(e=>e.startsWith("https")?d:u)(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)}))}))}p.config();const O={puppeteer:{args:{value:[],type:"string[]",description:"Arguments array to send to Puppeteer."}},highcharts:{version:{value:"latest",envLink:"HIGHCHARTS_VERSION",type:"string",description:"The Highcharts version to be used."},cdnURL:{value:"https://code.highcharts.com/",envLink:"HIGHCHARTS_CDN_URL",type:"string",description:"The CDN URL for Highcharts scripts to be used."},coreScripts:{envLink:"HIGHCHARTS_CORE_SCRIPTS",value:["highcharts","highcharts-more","highcharts-3d"],type:"string[]",description:"The core Highcharts scripts to fetch."},modules:{envLink:"HIGHCHARTS_MODULES",value:["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"],type:"string[]",description:"The modules of Highcharts to fetch."},indicators:{envLink:"HIGHCHARTS_INDICATORS",value:["indicators-all"],type:"string[]",description:"The indicators of Highcharts to fetch."},scripts:{value:["https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js","https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.34/moment-timezone-with-data.min.js"],type:"string[]",description:"Additional optional scripts or dependencies to fetch."},forceFetch:{envLink:"HIGHCHARTS_FORCE_FETCH",value:!1,type:"boolean",description:"The flag to determine whether to refetch all scripts after each server rerun."},cachePath:{envLink:"HIGHCHARTS_CACHE_PATH",value:".cache",type:"string",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:{envLink:"EXPORT_TYPE",value:"png",type:"string",description:"The file export format. It can be jpeg, png, pdf, or svg."},constr:{envLink:"EXPORT_CONSTR",value:"chart",type:"string",description:"The constructor to use. Can be chart, stockChart, mapChart, or ganttChart."},defaultHeight:{envLink:"EXPORT_DEFAULT_HEIGHT",value:400,type:"number",description:"the default height of the exported chart. Used when no value is set."},defaultWidth:{envLink:"EXPORT_DEFAULT_WIDTH",value:600,type:"number",description:"The default width of the exported chart. Used when no value is set."},defaultScale:{envLink:"EXPORT_DEFAULT_SCALE",value:1,type:"number",description:"The default scale of the exported chart. Used when no value is set."},height:{type:"number",value:!1,description:"The height of the exported chart, overriding the option in the chart settings."},width:{type:"number",value:!1,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:{envLink:"EXPORT_RASTERIZATION_TIMEOUT",value:1500,type:"number",description:"The duration in milliseconds to wait for rendering a webpage."}},customLogic:{allowCodeExecution:{envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",value:!1,type:"boolean",description:"Controls whether the execution of arbitrary code is allowed during the exporting process."},allowFileResources:{envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",value:!1,type:"boolean",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:{envLink:"SERVER_ENABLE",value:!1,type:"boolean",cliName:"enableServer",description:"When set to true, the server starts on the local IP address 0.0.0.0."},host:{envLink:"SERVER_HOST",value:"0.0.0.0",type:"string",description:"The hostname of the server. Additionally, it starts a server on the provided hostname."},port:{envLink:"SERVER_PORT",value:7801,type:"number",description:"The server port when enabled."},benchmarking:{envLink:"SERVER_BENCHMARKING",value:!1,type:"boolean",cliName:"serverBenchmarking",description:"Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request."},ssl:{enable:{envLink:"SERVER_SSL_ENABLE",value:!1,type:"boolean",cliName:"enableSsl",description:"Enables or disables the SSL protocol."},force:{envLink:"SERVER_SSL_FORCE",value:!1,type:"boolean",cliName:"sslForced",legacyName:"sslOnly",description:"When set to true, the server is forced to serve only over HTTPS."},port:{envLink:"SERVER_SSL_PORT",value:443,type:"number",cliName:"sslPort",description:"The port on which to run the SSL server."},certPath:{envLink:"SERVER_SSL_CERT_PATH",value:"",type:"string",legacyName:"sslPath",description:"The path to the SSL certificate/key file."}},rateLimiting:{enable:{envLink:"SERVER_RATE_LIMITING_ENABLE",value:!1,type:"boolean",cliName:"enableRateLimiting",description:"Enables rate limiting for the server."},maxRequests:{envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",value:10,type:"number",legacyName:"rateLimit",description:"The maximum number of requests allowed in one minute."},window:{envLink:"SERVER_RATE_LIMITING_WINDOW",value:1,type:"number",description:"The time window, in minutes, for the rate limiting."},delay:{envLink:"SERVER_RATE_LIMITING_DELAY",value:0,type:"number",description:"The delay duration for each successive request before reaching the maximum limit."},trustProxy:{envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",value:!1,type:"boolean",description:"Set this to true if the server is behind a load balancer."},skipKey:{envLink:"SERVER_RATE_LIMITING_SKIP_KEY",value:"",type:"string",description:"Allows bypassing the rate limiter and should be provided with the skipToken argument."},skipToken:{envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",value:"",type:"string",description:"Allows bypassing the rate limiter and should be provided with the skipKey argument."}}},pool:{minWorkers:{envLink:"POOL_MIN_WORKERS",value:4,type:"number",description:"The number of minimum and initial pool workers to spawn."},maxWorkers:{envLink:"POOL_MAX_WORKERS",value:8,type:"number",legacyName:"workers",description:"The number of maximum pool workers to spawn."},workLimit:{envLink:"POOL_WORK_LIMIT",value:40,type:"number",description:"The number of work pieces that can be performed before restarting the worker process."},acquireTimeout:{envLink:"POOL_ACQUIRE_TIMEOUT",value:5e3,type:"number",description:"The duration, in milliseconds, to wait for acquiring a resource."},createTimeout:{envLink:"POOL_CREATE_TIMEOUT",value:5e3,type:"number",description:"The duration, in milliseconds, to wait for creating a resource."},destroyTimeout:{envLink:"POOL_DESTROY_TIMEOUT",value:5e3,type:"number",description:"The duration, in milliseconds, to wait for destroying a resource."},idleTimeout:{envLink:"POOL_IDLE_TIMEOUT",value:3e4,type:"number",description:"The duration, in milliseconds, after which an idle resource is destroyed."},createRetryInterval:{envLink:"POOL_CREATE_RETRY_INTERVAL",value:200,type:"number",description:"The duration, in milliseconds, to wait before retrying the create process in case of a failure."},reaperInterval:{envLink:"POOL_REAPER_INTERVAL",value:1e3,type:"number",description:"The duration, in milliseconds, after which the check for idle resources to destroy is triggered."},benchmarking:{envLink:"POOL_BENCHMARKING",value:!1,type:"boolean",cliName:"poolBenchmarking",description:"Indicate whether to show statistics for the pool of resources or not."},listenToProcessExits:{envLink:"POOL_LISTEN_TO_PROCESS_EXITS",value:!0,type:"boolean",description:"Decides whether or not to attach process.exit handlers."}},logging:{level:{envLink:"LOGGING_LEVEL",value:4,type:"number",cliName:"logLevel",description:"The logging level to be used."},file:{envLink:"LOGGING_FILE",value:"highcharts-export-server.log",type:"string",cliName:"logFile",description:"The name of a log file. The logDest option also needs to be set to enable file logging."},dest:{envLink:"LOGGING_DEST",value:"log/",type:"string",cliName:"logDest",description:"The path to store log files. This also enables file logging."}},ui:{enable:{envLink:"UI_ENABLE",value:!1,type:"boolean",cliName:"enableUi",description:"Enables or disables the user interface (UI) for the export server."},route:{envLink:"UI_ROUTE",value:"/",type:"string",cliName:"uiRoute",description:"The endpoint route to which the user interface (UI) should be attached."}},other:{noLogo:{envLink:"OTHER_NO_LOGO",value:!1,type:"boolean",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:O.puppeteer.args.value.join(","),separator:","}],highcharts:[{type:"text",name:"version",message:"Highcharts version",initial:O.highcharts.version.value},{type:"text",name:"cdnURL",message:"The URL of CDN",initial:O.highcharts.cdnURL.value},{type:"multiselect",name:"modules",message:"Available modules",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:O.highcharts.modules.value},{type:"list",name:"scripts",message:"Custom scripts",initial:O.highcharts.scripts.value.join(","),separator:","},{type:"toggle",name:"forceFetch",message:"Force re-fetch the scripts",initial:O.highcharts.forceFetch.value},{type:"text",name:"cachePath",message:"The path to the cache directory",initial:O.highcharts.cachePath.value}],export:[{type:"select",name:"type",message:"The default export file type",hint:`Default: ${O.export.type.value}`,initial:0,choices:["png","jpeg","pdf","svg"]},{type:"select",name:"constr",message:"The default constructor for Highcharts",hint:`Default: ${O.export.constr.value}`,initial:0,choices:["chart","stockChart","mapChart","ganttChart"]},{type:"number",name:"defaultHeight",message:"The default fallback height of the exported chart",initial:O.export.defaultHeight.value},{type:"number",name:"defaultWidth",message:"The default fallback width of the exported chart",initial:O.export.defaultWidth.value},{type:"number",name:"defaultScale",message:"The default fallback scale of the exported chart",initial:O.export.defaultScale.value,min:.1,max:5},{type:"number",name:"rasterizationTimeout",message:"The rendering webpage timeout in milliseconds",initial:O.export.rasterizationTimeout.value}],customLogic:[{type:"toggle",name:"allowCodeExecution",message:"Enable execution of custom code",initial:O.customLogic.allowCodeExecution.value},{type:"toggle",name:"allowFileResources",message:"Enable file resources",initial:O.customLogic.allowFileResources.value}],server:[{type:"toggle",name:"enable",message:"Starts the server on 0.0.0.0",initial:O.server.enable.value},{type:"text",name:"host",message:"Server hostname",initial:O.server.host.value},{type:"number",name:"port",message:"Server port",initial:O.server.port.value},{type:"toggle",name:"benchmarking",message:"Enable server benchmarking",initial:O.server.benchmarking.value},{type:"toggle",name:"ssl.enable",message:"Enable SSL protocol",initial:O.server.ssl.enable.value},{type:"toggle",name:"ssl.force",message:"Force serving only over HTTPS",initial:O.server.ssl.force.value},{type:"number",name:"ssl.port",message:"SSL server port",initial:O.server.ssl.port.value},{type:"text",name:"ssl.certPath",message:"The path to find the SSL certificate/key",initial:O.server.ssl.certPath.value},{type:"toggle",name:"rateLimiting.enable",message:"Enable rate limiting",initial:O.server.rateLimiting.enable.value},{type:"number",name:"rateLimiting.maxRequests",message:"The maximum requests allowed per minute",initial:O.server.rateLimiting.maxRequests.value},{type:"number",name:"rateLimiting.window",message:"The rate-limiting time window in minutes",initial:O.server.rateLimiting.window.value},{type:"number",name:"rateLimiting.delay",message:"The delay for each successive request before reaching the maximum",initial:O.server.rateLimiting.delay.value},{type:"toggle",name:"rateLimiting.trustProxy",message:"Set to true if behind a load balancer",initial:O.server.rateLimiting.trustProxy.value},{type:"text",name:"rateLimiting.skipKey",message:"Allows bypassing the rate limiter when provided with the skipToken argument",initial:O.server.rateLimiting.skipKey.value},{type:"text",name:"rateLimiting.skipToken",message:"Allows bypassing the rate limiter when provided with the skipKey argument",initial:O.server.rateLimiting.skipToken.value}],pool:[{type:"number",name:"minWorkers",message:"The initial number of workers to spawn",initial:O.pool.minWorkers.value},{type:"number",name:"maxWorkers",message:"The maximum number of workers to spawn",initial:O.pool.maxWorkers.value},{type:"number",name:"workLimit",message:"The pieces of work that can be performed before restarting a Puppeteer process",initial:O.pool.workLimit.value},{type:"number",name:"acquireTimeout",message:"The number of milliseconds to wait for acquiring a resource",initial:O.pool.acquireTimeout.value},{type:"number",name:"createTimeout",message:"The number of milliseconds to wait for creating a resource",initial:O.pool.createTimeout.value},{type:"number",name:"destroyTimeout",message:"The number of milliseconds to wait for destroying a resource",initial:O.pool.destroyTimeout.value},{type:"number",name:"idleTimeout",message:"The number of milliseconds after an idle resource is destroyed",initial:O.pool.idleTimeout.value},{type:"number",name:"createRetryInterval",message:"The retry interval in milliseconds after a create process fails",initial:O.pool.createRetryInterval.value},{type:"number",name:"reaperInterval",message:"The reaper interval in milliseconds after triggering the check for idle resources to destroy",initial:O.pool.reaperInterval.value},{type:"toggle",name:"benchmarking",message:"Enable benchmarking for a resource pool",initial:O.pool.benchmarking.value},{type:"toggle",name:"listenToProcessExits",message:"Set to false to skip attaching process.exit handlers",initial:O.pool.listenToProcessExits.value}],logging:[{type:"number",name:"level",message:"The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)",initial:O.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:O.logging.file.value},{type:"text",name:"dest",message:"The path to log files. Enables file logging",initial:O.logging.dest.value}],ui:[{type:"toggle",name:"enable",message:"Enable UI for the export server",initial:O.ui.enable.value},{type:"text",name:"route",message:"A route to attach the UI",initial:O.ui.route.value}],other:[{type:"toggle",name:"noLogo",message:"Skip printing the logo on startup. Replaced by simple text",initial:O.other.noLogo.value}]},I=["options","globalOptions","themeOptions","resources","payload"],C={},$=(e,t="")=>{Object.keys(e).forEach((r=>{if(!["puppeteer","highcharts"].includes(r)){const i=e[r];void 0===i.value?$(i,`${t}.${r}`):(C[i.cliName||r]=`${t}.${r}`.substring(1),void 0!==i.legacyName&&(C[i.legacyName]=`${t}.${r}`.substring(1)))}}))};$(O);const _=["red","yellow","blue","gray","green"];let N={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:_[0]},{title:"warning",color:_[1]},{title:"notice",color:_[2]},{title:"verbose",color:_[3]},{title:"benchmark",color:_[4]}],listeners:[]};for(const[e,t]of Object.entries(O.logging))N[e]=t.value;const P=(e,o)=>{N.toFile&&(N.pathCreated||(!t(N.dest)&&r(N.dest),N.pathCreated=!0),i(`${N.dest}${N.file}`,[o].concat(e).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),N.toFile=!1)})))},A=(...e)=>{const[t,...r]=e,{level:i,levelsDesc:o}=N;if(5!==t&&(0===t||t>i||i>o.length))return;const n=`${(new Date).toString().split("(")[0].trim()} [${o[t-1].title}] -`;N.listeners.forEach((e=>{e(n,r.join(" "))})),N.toConsole&&console.log.apply(void 0,[n.toString()[N.levelsDesc[t-1].color]].concat(r)),P(r,n)},j=(e,t,r)=>{const i=r||t.message,{level:o,levelsDesc:n}=N;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];N.toConsole&&console.log.apply(void 0,[s.toString()[N.levelsDesc[e-1].color]].concat([i[_[e-1]],"\n",a])),N.listeners.forEach((e=>{e(s,l.join(" "))})),P(l,s)},H=e=>{e>=0&&e<=N.levelsDesc.length&&(N.level=e)},U=(e,t)=>{if(N={...N,dest:e||N.dest,file:t||N.file,toFile:!0},0===N.dest.length)return A(1,"[logger] File logging initialization: no path supplied.");N.dest.endsWith("/")||(N.dest+="/")},W=m(new URL("../.",import.meta.url)),D=(e,t)=>{const r=["png","jpeg","pdf","svg"];if(t){const i=t.split(".").pop();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"},M=(e=!1,t)=>{const r=["js","css","files"];let i=e,n=!1;if(t&&e.endsWith(".json"))try{i=F(o(e,"utf8"))}catch(e){return j(2,e,"[cli] No resources found.")}else i=F(e),i&&!t&&delete i.files;for(const e in i)r.includes(e)?n||(n=!0):delete i[e];return n?(i.files&&(i.files=i.files.map((e=>e.trim())),(!i.files||i.files.length<=0)&&delete i.files),i):A(3,"[cli] No resources found.")};function F(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},G=(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,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(O).forEach((t=>{["puppeteer","highcharts"].includes(t)||(console.log(`\n${t.toUpperCase()}`.red),e(O[t]))})),console.log("\n")}const J=e=>!["false","undefined","null","NaN","0",""].includes(e)&&!!e,K=(e,t)=>{if(e&&"string"==typeof e)return(e=e.trim()).endsWith(".js")?!!t&&K(o(e,"utf8")):e.startsWith("function()")||e.startsWith("function ()")||e.startsWith("()=>")||e.startsWith("() =>")?`(${e})()`:e.replace(/;$/,"")},z=()=>{const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6};class X 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}}p.config();const B={cdnURL:"https://code.highcharts.com/",activeManifest:{},sources:"",hcVersion:""};let Y=!1;const Q=()=>B.hcVersion=B.sources.substring(0,B.sources.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim(),Z=async(e,t,r,i=!1)=>{e.endsWith(".js")&&(e=e.substring(0,e.length-3)),A(4,`[cache] Fetching script - ${e}.js`);const o=t?{agent:t,timeout:+process.env.PROXY_SERVER_TIMEOUT||5e3}:{},n=await S(`${e}.js`,o);if(200===n.statusCode&&"string"==typeof n.text){if(r){r[e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")]=1}return n.text}if(i)throw new X(`Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${n.statusCode}).`).setError(n);return A(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`),""},ee=async(e,t)=>{const{coreScripts:r,modules:i,indicators:o,scripts:s}=e,a="latest"!==e.version&&e.version?`${e.version}/`:"";let l;A(3,`[cache] Updating cache version to Highcharts: ${a||"latest"}.`);const c=process.env.PROXY_SERVER_HOST,p=process.env.PROXY_SERVER_PORT;if(c&&p)try{l=new h({host:c,port:+p})}catch(e){throw new X("[cache] Could not create a Proxy Agent.").setError(e)}const u={};try{return B.sources=await(async(e,t,r,i,o,n)=>{const s=[...e.map((e=>Z(`${i}${e}`,o,n,!0))),...t.map((e=>Z(`${i}${e}`,o,n))),...r.map((e=>Z(`${e}`,o)))];return(await Promise.all(s)).join(";\n")})([...r.map((e=>`${a}${e}`))],[...i.map((e=>"map"===e?`maps/${a}modules/${e}`:`${a}modules/${e}`)),...o.map((e=>`stock/${a}indicators/${e}`))],s,e.cdnURL||B.cdnURL,l,u),Q(),n(t,B.sources),u}catch(e){throw new X("[cache] Unable to update the local Highcharts cache.").setError(e)}},te=async e=>{const i=l(W,e.cachePath);let s;const a=l(i,"manifest.json"),c=l(i,"sources.js");if(Y=e,!t(i)&&r(i),!t(a)||e.forceFetch)A(3,"[cache] Fetching and caching Highcharts dependencies."),s=await ee(e,c);else{let t=!1;const r=JSON.parse(o(a));if(r.modules&&Array.isArray(r.modules)){const e={};r.modules.forEach((t=>e[t]=1)),r.modules=e}const{modules:i,coreScripts:n,indicators:l}=e,p=i.length+n.length+l.length;r.version!==e.version?(A(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),t=!0):Object.keys(r.modules||{}).length!==p?(A(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),t=!0):t=(e.modules||[]).some((e=>{if(!r.modules[e])return A(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),t?s=await ee(e,c):(A(3,"[cache] Dependency cache is up to date, proceeding."),B.sources=o(c,"utf8"),s=r.modules,Q())}await(async(e,t)=>{const r={version:e.version,modules:t||{}};B.activeManifest=r,A(3,"[cache] Writing a new manifest.");try{n(l(W,e.cachePath,"manifest.json"),JSON.stringify(r),"utf8")}catch(e){throw new X("[cache] Error writing the cache manifest.").setError(e)}})(e,s)},re=()=>l(W,Y.cachePath);var ie=async e=>!!Y&&await te(Object.assign(Y,{version:e})),oe=()=>B,ne=()=>B.hcVersion;let se={};const ae=()=>se,le=(e,t,r=[])=>{const i=q(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]:le(i[e],n,r);var o;return i};function ce(e,t={},r=""){Object.keys(e).forEach((i=>{const o=e[i],n=t&&t[i];let s;void 0===o.value?ce(o,n,`${r}.${i}`):(void 0!==n&&(o.value=n),o.envLink&&("boolean"===o.type?o.value=J([process.env[o.envLink],o.value].find((e=>e||"false"===e))):"number"===o.type?(s=+process.env[o.envLink],o.value=s>=0?s:o.value):o.type.indexOf("]")>=0&&process.env[o.envLink]?o.value=process.env[o.envLink].split(","):o.value=process.env[o.envLink]||o.value))}))}function pe(e){let t={};for(const[r,i]of Object.entries(e))t[r]=Object.prototype.hasOwnProperty.call(i,"value")?i.value:pe(i);return t}function he(e,t,r){for(;t.length>1;){const i=t.shift();return Object.prototype.hasOwnProperty.call(e,i)||(e[i]={}),e[i]=he(Object.assign({},e[i]),t,r),e}return e[t[0]]=r,e}const ue=T(64).toString("base64url"),de=w.join("tmp",`puppeteer-${ue}`),ge=[`--user-data-dir=${w.join(de,"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"],me=g.fileURLToPath(new URL(".",import.meta.url)),fe=e.readFileSync(me+"/../templates/template.html","utf8");let ve;const ye=async e=>{await e.setContent(fe),await e.addScriptTag({path:`${re()}/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()}`)}))},we=async(e,t=!1)=>{try{t?(await e.goto("about:blank"),await ye(e)):await e.evaluate((()=>{document.body.innerHTML='
'}))}catch(e){j(2,e,"[browser] Could not clear the content of the page.")}},be=async()=>{if(!ve)return!1;const e=await ve.newPage();return await e.setCacheEnabled(!1),await ye(e),e},Te=async()=>(ve?.isConnected()&&(await ve.close(),A(4,"[browser] Closed the browser.")),!0);const ke=g.fileURLToPath(new URL(".",import.meta.url)),xe=(e,t,r)=>e.evaluate(((e,t)=>window.triggerExport(e,t)),t,r);var Ee=async(e,t,r)=>{const i=[],n=async e=>{for(const e of i)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{A(4,"[export] Determining export path.");const s=r.export;await e.evaluate((()=>requestAnimationFrame((()=>{}))));const l=s?.options?.chart?.displayErrors&&oe().activeManifest.modules.debugger;let c;if(await e.evaluate((e=>window._displayErrors=e),l),t.indexOf&&(t.indexOf("=0||t.indexOf("=0)){if(A(4,"[export] Treating as SVG."),"svg"===s.type)return t;c=!0,await e.setContent((e=>`\n\n\n \n \n Highcarts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`)(t))}else A(4,"[export] Treating as config."),s.strInj?await xe(e,{chart:{height:s.height,width:s.width}},r):(t.chart.height=s.height,t.chart.width=s.width,await xe(e,t,r));const p=r.customLogic.resources;if(p){if(p.js&&i.push(await e.addScriptTag({content:p.js})),p.files)for(const t of p.files)try{const r=!t.startsWith("http");i.push(await e.addScriptTag(r?{content:o(t,"utf8")}:{url:t}))}catch(e){j(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 o of t)o&&(o=o.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),o.startsWith("http")?i.push(await e.addStyleTag({url:o})):r.customLogic.allowFileResources&&i.push(await e.addStyleTag({path:a.join(ke,o)})));i.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(s.scale)):await e.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return{chartHeight:e,chartWidth:t}})),u=Math.ceil(h?.chartHeight||s.height),d=Math.ceil(h?.chartWidth||s.width);await e.setViewport({height:u,width:d,deviceScaleFactor:c?1:parseFloat(s.scale)});const g=c?e=>{document.body.style.zoom=e,document.body.style.margin="0px"}:()=>{document.body.style.zoom=1};await e.evaluate(g,parseFloat(s.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)}})))(e);let w;if(c||await e.setViewport({width:Math.round(f),height:Math.round(m),deviceScaleFactor:parseFloat(s.scale)}),"svg"===s.type)w=await(e=>e.$eval("#container svg:first-of-type",(e=>e.outerHTML)))(e);else if("png"===s.type||"jpeg"===s.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 X("Rasterization timeout"))),o||1500)))]))(e,s.type,"base64",{width:d,height:u,x:v,y:y},s.rasterizationTimeout);else{if("pdf"!==s.type)throw new X(`[export] Unsupported output format ${s.type}.`);w=await((e,t,r,i)=>e.pdf({height:t+1,width:r,encoding:i}))(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 n(e),w}catch(t){return await n(e),t}};let Le,Se=0,Oe=0,Re=0,Ie=0,Ce=0,$e={},_e=!1;const Ne={create:async()=>{let e=!1;const t=y(),r=(new Date).getTime();try{if(e=await be(),!e||e.isClosed())throw new X("The page is invalid or closed.");A(3,`[pool] Successfully created a worker ${t} - took ${(new Date).getTime()-r} ms.`)}catch(e){throw new X("Error encountered when creating a new page.").setError(e)}return{id:t,page:e,workCount:Math.round(Math.random()*($e.workLimit/2))}},validate:async e=>$e.workLimit&&++e.workCount>$e.workLimit?(A(3,`[pool] Worker failed validation: exceeded work limit (limit is ${$e.workLimit}).`),!1):(await we(e.page,!0),!0),destroy:e=>{A(3,`[pool] Destroying pool entry ${e.id}.`),e.page&&e.page.close()}},Pe=async e=>{if($e=e&&e.pool?{...e.pool}:{},$e.listenToProcessExits&&(A(3,"[pool] Attaching exit listeners to the process."),process.on("exit",(async e=>{A(4,`Process exited with code ${e}.`),await Ae()})),process.on("SIGINT",((e,t)=>{A(4,`The ${e} event with code: ${t}.`),process.exit(1)})),process.on("SIGTERM",((e,t)=>{A(4,`The ${e} event with code: ${t}.`),process.exit(1)})),process.on("uncaughtException",(async(e,t)=>{j(1,e,`The ${t} error.`),await Ae(),process.exit(1)}))),Le=e.puppeteerArgs,await(async e=>{const t=[...ge,...e||[]];if(!ve){let e=0;const r=async()=>{try{A(3,`[browser] Attempting to get a browser instance (try ${++e}).`),ve=await b.launch({headless:"new",args:t,userDataDir:"./tmp/"})}catch(t){if(j(1,t,"[browser] Failed to launch a browser instance."),!(e<25))throw t;A(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 X("[browser] Maximum retries to open a browser instance reached.").setError(e)}if(!ve)throw new X("[browser] Cannot find a browser to open.")}return ve})(Le),A(3,`[pool] Initializing pool with workers: min ${$e.minWorkers}, max ${$e.maxWorkers}.`),_e)return A(4,"[pool] Already initialized, please kill it before creating a new one.");parseInt($e.minWorkers)>parseInt($e.maxWorkers)&&($e.minWorkers=$e.maxWorkers);try{_e=new v({...Ne,min:parseInt($e.minWorkers),max:parseInt($e.maxWorkers),acquireTimeoutMillis:$e.acquireTimeout,createTimeoutMillis:$e.createTimeout,destroyTimeoutMillis:$e.destroyTimeout,idleTimeoutMillis:$e.idleTimeout,createRetryIntervalMillis:$e.createRetryInterval,reapIntervalMillis:$e.reaperInterval,propagateCreateError:!1}),_e.on("release",(async e=>{await we(e.page,!1),A(4,`[pool] Releasing a worker with ID ${e.id}.`)})),_e.on("destroySuccess",((e,t)=>{A(4,`[pool] Destroyed a worker with ID ${t.id}.`)}));const e=[];for(let t=0;t<$e.minWorkers;t++)try{const t=await _e.acquire().promise;e.push(t)}catch(e){j(2,e,"[pool] Could not create an initial resource.")}e.forEach((e=>{_e.release(e)})),A(3,"[pool] The pool is ready"+(e.length?` with ${e.length} initial resources waiting.`:"."))}catch(e){throw await Te(),new X("[pool] Could not create the pool of workers.").setError(e)}};async function Ae(){return A(3,"[pool] Killing all pool workers and browser, if any exist."),_e?.destroyed||_e&&(await _e.destroy(),A(4,"[browser] Destroyed the pool of resources.")),Te()}const je=async(e,t)=>{let r;try{if(A(4,"[pool] Work received, starting to process."),++Oe,$e.benchmarking&&He(),!_e)throw new X("Work received, but pool has not been started.");try{A(4,"[pool] Acquiring a worker handle.");const e=z();r=await _e.acquire().promise,t.server.benchmarking&&A(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Acquired a worker handle: ${e()}ms.`)}catch(e){throw new X("Error encountered when acquiring an available entry.").setError(e)}if(A(4,"[pool] Acquired a worker handle."),!r.page)throw new X("Resolved worker page is invalid: the pool setup is wonky.");let i=(new Date).getTime();A(4,`[pool] Starting work on pool entry with ID ${r.id}.`);const o=z(),n=await Ee(r.page,e,t);if(n instanceof Error)throw"Rasterization timeout"===n.message&&(r.page.close(),r.page=await be()),new X("Error encountered during export.").setError(n);t.server.benchmarking&&A(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Exported a chart sucessfully: ${o()}ms.`),_e.release(r);const s=(new Date).getTime()-i;return Re+=s,Ce=Re/++Se,A(4,`[pool] Work completed in ${s} ms.`),{result:n,options:t}}catch(e){throw++Ie,r&&_e.release(r),new X(`[pool] In pool.postWork: ${e.message}`).setError(e)}};function He(){const{min:e,max:t}=_e;A(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),A(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),A(5,`[pool] The number of resources that are currently available: ${_e.numFree()}.`),A(5,`[pool] The number of resources that are currently acquired: ${_e.numUsed()}.`),A(5,`[pool] The number of callers waiting to acquire a resource: ${_e.numPendingAcquires()}.`)}var Ue=()=>({min:_e.min,max:_e.max,available:_e.numFree(),inUse:_e.numUsed(),pendingAcquire:_e.numPendingAcquires()}),We=()=>Oe,De=()=>Ie,Me=()=>Ce,Fe=()=>Se;let qe=!1;const Ge=async(e,t)=>{A(4,"[chart] Starting the exporting process.");const r=((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=le(t,e,I),r.export.outfile=r.export?.outfile||`chart.${r.export?.type||"png"}`,r})(e,ae()),i=r.export;if(r.payload?.svg&&""!==r.payload.svg)try{return A(4,"[chart] Attempting to export from a SVG input."),ze(r.payload.svg.trim(),r,t)}catch(e){return t(new X("[chart] Error loading SVG input.").setError(e))}if(i.infile&&i.infile.length)try{return A(4,"[chart] Attempting to export from an input file."),r.export.instr=o(i.infile,"utf8"),ze(r.export.instr.trim(),r,t)}catch(e){return t(new X("[chart] Error loading input file.").setError(e))}if(i.instr&&""!==i.instr||i.options&&""!==i.options)try{return A(4,"[chart] Attempting to export from a raw input."),J(r.customLogic?.allowCodeExecution)?Ke(r,t):"string"==typeof i.instr?ze(i.instr.trim(),r,t):Je(r,i.instr||i.options,t)}catch(e){return t(new X("[chart] Error loading raw input.").setError(e))}return t(new X("[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||F(e.export?.instr),i=F(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(e,t,r,i)=>{let{export:n,customLogic:s}=e;const a="boolean"==typeof s.allowCodeExecution?s.allowCodeExecution:qe;if(s){if(a)if("string"==typeof e.customLogic.resources)e.customLogic.resources=M(e.customLogic.resources,J(e.customLogic.allowFileResources));else if(!e.customLogic.resources)try{const t=o("resources.json","utf8");e.customLogic.resources=M(t,J(e.customLogic.allowFileResources))}catch(e){j(2,e,"[chart] Unable to load the default resources.json file.")}}else s=e.customLogic={};if(!a&&s){if(s.callback||s.resources||s.customCode)return r(new X("[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server."));s.callback=!1,s.resources=!1,s.customCode=!1}if(t&&(t.chart=t.chart||{},t.exporting=t.exporting||{},t.exporting.enabled=!1),n.constr=n.constr||"chart",n.type=D(n.type,n.outfile),"svg"===n.type&&(n.width=!1),["globalOptions","themeOptions"].forEach((e=>{try{n&&n[e]&&("string"==typeof n[e]&&n[e].endsWith(".json")?n[e]=F(o(n[e],"utf8"),!0):n[e]=F(n[e],!0))}catch(t){n[e]={},j(2,t,`[chart] The '${e}' 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=o(s.callback,"utf8")}catch(e){s.callback=!1,j(2,e,"[chart] The 'callback' cannot be loaded.")}else s.callback=!1;e.export={...e.export,...Ve(e)};try{return r(!1,await je(n.strInj||t||i,e))}catch(e){return r(e)}},Ke=(e,t)=>{try{let r,i=e.export.instr||e.export.options;return"string"!=typeof i&&(r=i=G(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 X(`[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:i}=t.customLogic;if(e.indexOf("=0||e.indexOf("=0)return A(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 J(i)?Ke(t,r):r(new X("[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=(e,t,r,i)=>{j(1,e),"development"!==process.env.NODE_ENV&&delete e.stack,i(e)},Be=(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 Ye=(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=L({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&&(A(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(o),A(3,`[rate limiting] Enabled rate limiting with ${i.max} requests per ${i.window} minute for each IP, trusting proxy: ${i.trustProxy}.`)};class Qe extends X{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=[],it=(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},ot=async(e,t,r)=>{try{const r=z(),o=y().replace(/-/g,""),n=ae(),s=e.body,a=++et;let l=D(s.type);if(!s||"object"==typeof(i=s)&&null!==i&&0===Object.keys(i).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=F(s.infile||s.options||s.data);if(!c&&!s.svg)throw A(2,`The request with ID ${o} from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Payload received: ${JSON.stringify(s)}.`),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=it(tt,e,t,{id:a,uniqueId:o,type:l,body:s}),!0!==p)return t.send(p);let h=!1;e.socket.on("close",(()=>{h=!0})),A(4,`[export] Got an incoming HTTP request with ID ${o}.`),s.constr="string"==typeof s.constr&&s.constr||"chart";const u={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:F(s.globalOptions,!0),themeOptions:F(s.themeOptions,!0)},customLogic:{allowCodeExecution:qe,allowFileResources:!1,resources:F(s.resources,!0),callback:s.callback,customCode:s.customCode}};c&&(u.export.instr=G(c,u.customLogic.allowCodeExecution));const d=le(n,u);if(d.export.options=c,d.payload={svg:s.svg||!1,b64:s.b64||!1,noDownload:s.noDownload||!1,requestId:o},s.svg&&(e=>["localhost","(10).(.*).(.*).(.*)","(127).(.*).(.*).(.*)","(172).(1[6-9]|2[0-9]|3[0-1]).(.*).(.*)","(192).(168).(.*).(.*)"].some((t=>e.match(`xlink:href="(?:(http://|https://))?${t}`))))(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 Ge(d,((i,c)=>{if(e.socket.removeAllListeners("close"),n.server.benchmarking&&A(5,`[benchmark] Request with ID ${o} - After the whole exporting process: ${r()}ms.`),h)return A(3,"[export] The client closed the connection before the chart finished processing.");if(i)throw i;if(!c||!c.result)throw new Qe(`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,it(rt,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 nt=JSON.parse(o(l(W,"package.json"))),st=new Date;const at=x();at.disable("x-powered-by"),at.use(k());const lt=E.memoryStorage(),ct=E({storage:lt,limits:{fieldSize:52428800}});at.use(x.json({limit:52428800})),at.use(x.urlencoded({extended:!0,limit:52428800})),at.use(ct.none());const pt=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}`)}))}))},ht=async e=>{try{if(!e.enable)return!1;if(!e.ssl.force){const t=u.createServer(at);pt(t),t.listen(e.port,e.host),A(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){A(2,`[server] Unable to load key/certificate from the '${e.ssl.certPath}' path. Could not run secured layer server.`)}if(t&&r){const t=d.createServer(at);pt(t),t.listen(e.ssl.port,e.host),A(3,`[server] Started HTTPS server on ${e.host}:${e.ssl.port}.`)}}e.rateLimiting&&e.rateLimiting.enable&&![0,NaN].includes(e.rateLimiting.maxRequests)&&Ye(at,e.rateLimiting),at.use(x.static(c.join(W,"public"))),(e=>{!!e&&e.get("/health",((e,t)=>{t.send({status:"OK",bootTime:st,uptime:Math.floor(((new Date).getTime()-st.getTime())/1e3/60)+" minutes",version:nt.version,highchartsVersion:ne(),averageProcessingTime:Me(),performedExports:Fe(),failedExports:De(),exportAttempts:We(),sucessRatio:Fe()/We()*100,pool:Ue()})}))})(at),(e=>{e.post("/",ot),e.post("/:filename",ot)})(at),(e=>{!!e&&e.get("/",((e,t)=>{t.sendFile(l(W,"public","index.html"))}))})(at),(e=>{!!e&&e.post("/version/change/:newVersion",(async(e,t,r)=>{try{const r=process.env.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 i=e.get("hc-auth");if(!i||i!==r)throw new Qe("Invalid or missing token: Set the token in the hc-auth header.",401);const o=e.params.newVersion;if(!o)throw new Qe("No new version supplied.",400);try{await ie(o)}catch(e){throw new Qe(`Version change: ${e.message}`,e.statusCode).setError(e)}t.status(200).send({statusCode:200,version:ne(),message:`Successfully updated Highcharts to version: ${o}.`})}catch(e){r(e)}}))})(at),(e=>{e.use(Xe),e.use(Be)})(at)}catch(e){throw new X("[server] Could not configure and start the server.").setError(e)}};var ut={startServer:ht,enableRateLimiting:e=>Ye(at,e),getExpress:()=>x,getApp:()=>at,use:(e,...t)=>{at.use(e,...t)},get:(e,...t)=>{at.get(e,...t)},post:(e,...t)=>{at.post(e,...t)}};var dt={server:ut,startServer:ht,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(o(r))}catch(e){j(2,e,`[config] Unable to load the configuration from the ${r} file.`)}}return{}}(t)),ce(O,se),se=pe(O),e&&(se=le(se,e,I)),t?.length&&(se=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]=J(t[o]):"number"===a?e[r]=+t[o]:a.indexOf("]")>=0?e[r]=t[o].split(","):e[r]=t[o]:(A(2,`[config] Missing value for the '${n}' argument. Using the default value.`),i=!0)),e[r])),e)}i&&V();return e}(se,t,O)),se),initExport:async e=>{var t;return t=e.customLogic&&e.customLogic.allowCodeExecution,qe=J(t),(e=>{H(e&&parseInt(e.level)),e&&e.dest&&U(e.dest,e.file||"highcharts-export-server.log")})(e.logging),await te(e.highcharts||{version:"latest"}),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 Ge(e,(async(e,t)=>{if(e)throw e;const{outfile:r,type:i}=t.options.export;n(r||`chart.${i}`,"svg"!==i?Buffer.from(t.result,"base64"):t.result),await Ae()}))},batchExport:async e=>{const t=[];for(let r of e.export.batch.split(";"))r=r.split("="),2===r.length&&t.push(Ge({...e,export:{...e.export,infile:r[0],outfile:r[1]}},((e,t)=>{if(e)throw e;n(t.options.export.outfile,Buffer.from(t.result,"base64"))})));try{await Promise.all(t),await Ae()}catch(e){throw new X("[chart] Error encountered during batch export.").setError(e)}},startExport:Ge,killPool:Ae,log:A,logWithStack:j,setLogLevel:H,enableFileLogging:U,mapToNewConfig:e=>{const t={};for(const[r,i]of Object.entries(e)){const e=C[r]?C[r].split("."):[];e.reduce(((t,r,o)=>t[r]=e.length-1===o?i:t[r]||{}),t)}return t},manualConfig:async e=>{let r={};t(e)&&(r=JSON.parse(o(e,"utf8")));const i=Object.keys(R).map((e=>({title:`${e} options`,value:e})));return f({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(t,i)=>{let o=0,n=[];for(const e of i)R[e]=R[e].map((t=>({...t,section:e}))),n=[...n,...R[e]];return await f(n,{onSubmit:async(t,i)=>{if("modules"===t.name?(i=i.length?i.map((e=>t.choices[e])):t.choices,r[t.section][t.name]=i):r[t.section]=he(Object.assign({},r[t.section]||{}),t.name.split("."),t.choices?t.choices[i]:i),++o===n.length){try{await s.writeFile(e,JSON.stringify(r,null,2),"utf8")}catch(t){j(1,t,`[config] An error occurred while creating the ${e} file.`)}return!0}}}),!0}})},printLogo:e=>{const t=JSON.parse(o(l(W,"package.json"))).version;e?console.log(`Starting Highcharts Export Server v${t}...`):console.log(o(W+"/msg/startup.msg").toString().bold.yellow,`v${t}`)},printUsage:V};export{dt as default}; +import"colors";import e from"dotenv";import t,{existsSync as r,mkdirSync as i,appendFile as o,readFileSync as n,writeFileSync as s,promises as a}from"fs";import l,{join as c,posix as p}from"path";import{HttpsProxyAgent as h}from"https-proxy-agent";import u from"http";import d from"https";import*as g from"url";import{fileURLToPath as m}from"url";import f from"prompts";import{Pool as v}from"tarn";import{v4 as y}from"uuid";import w from"node:path";import b from"puppeteer";import{randomBytes as T}from"node:crypto";import k from"cors";import x from"express";import E from"multer";import L from"express-rate-limit";async function S(e,t={}){return new Promise(((r,i)=>{const o=(e=>e.startsWith("https")?d:u)(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)}))}))}const O={puppeteer:{args:{value:[],type:"string[]",description:"Arguments array to send to Puppeteer."}},highcharts:{version:{value:"latest",envLink:"HIGHCHARTS_VERSION",type:"string",description:"The Highcharts version to be used."},cdnURL:{value:"https://code.highcharts.com/",envLink:"HIGHCHARTS_CDN_URL",type:"string",description:"The CDN URL for Highcharts scripts to be used."},coreScripts:{envLink:"HIGHCHARTS_CORE_SCRIPTS",value:["highcharts","highcharts-more","highcharts-3d"],type:"string[]",description:"The core Highcharts scripts to fetch."},modules:{envLink:"HIGHCHARTS_MODULES",value:["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"],type:"string[]",description:"The modules of Highcharts to fetch."},indicators:{envLink:"HIGHCHARTS_INDICATORS",value:["indicators-all"],type:"string[]",description:"The indicators of Highcharts to fetch."},scripts:{value:["https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js","https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.34/moment-timezone-with-data.min.js"],type:"string[]",description:"Additional optional scripts or dependencies to fetch."},forceFetch:{envLink:"HIGHCHARTS_FORCE_FETCH",value:!1,type:"boolean",description:"The flag to determine whether to refetch all scripts after each server rerun."},cachePath:{envLink:"HIGHCHARTS_CACHE_PATH",value:".cache",type:"string",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:{envLink:"EXPORT_TYPE",value:"png",type:"string",description:"The file export format. It can be jpeg, png, pdf, or svg."},constr:{envLink:"EXPORT_CONSTR",value:"chart",type:"string",description:"The constructor to use. Can be chart, stockChart, mapChart, or ganttChart."},defaultHeight:{envLink:"EXPORT_DEFAULT_HEIGHT",value:400,type:"number",description:"the default height of the exported chart. Used when no value is set."},defaultWidth:{envLink:"EXPORT_DEFAULT_WIDTH",value:600,type:"number",description:"The default width of the exported chart. Used when no value is set."},defaultScale:{envLink:"EXPORT_DEFAULT_SCALE",value:1,type:"number",description:"The default scale of the exported chart. Used when no value is set."},height:{type:"number",value:!1,description:"The height of the exported chart, overriding the option in the chart settings."},width:{type:"number",value:!1,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:{envLink:"EXPORT_RASTERIZATION_TIMEOUT",value:1500,type:"number",description:"The duration in milliseconds to wait for rendering a webpage."}},customLogic:{allowCodeExecution:{envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",value:!1,type:"boolean",description:"Controls whether the execution of arbitrary code is allowed during the exporting process."},allowFileResources:{envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",value:!1,type:"boolean",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:{envLink:"SERVER_ENABLE",value:!1,type:"boolean",cliName:"enableServer",description:"When set to true, the server starts on the local IP address 0.0.0.0."},host:{envLink:"SERVER_HOST",value:"0.0.0.0",type:"string",description:"The hostname of the server. Additionally, it starts a server on the provided hostname."},port:{envLink:"SERVER_PORT",value:7801,type:"number",description:"The server port when enabled."},benchmarking:{envLink:"SERVER_BENCHMARKING",value:!1,type:"boolean",cliName:"serverBenchmarking",description:"Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request."},ssl:{enable:{envLink:"SERVER_SSL_ENABLE",value:!1,type:"boolean",cliName:"enableSsl",description:"Enables or disables the SSL protocol."},force:{envLink:"SERVER_SSL_FORCE",value:!1,type:"boolean",cliName:"sslForced",legacyName:"sslOnly",description:"When set to true, the server is forced to serve only over HTTPS."},port:{envLink:"SERVER_SSL_PORT",value:443,type:"number",cliName:"sslPort",description:"The port on which to run the SSL server."},certPath:{envLink:"SERVER_SSL_CERT_PATH",value:"",type:"string",legacyName:"sslPath",description:"The path to the SSL certificate/key file."}},rateLimiting:{enable:{envLink:"SERVER_RATE_LIMITING_ENABLE",value:!1,type:"boolean",cliName:"enableRateLimiting",description:"Enables rate limiting for the server."},maxRequests:{envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",value:10,type:"number",legacyName:"rateLimit",description:"The maximum number of requests allowed in one minute."},window:{envLink:"SERVER_RATE_LIMITING_WINDOW",value:1,type:"number",description:"The time window, in minutes, for the rate limiting."},delay:{envLink:"SERVER_RATE_LIMITING_DELAY",value:0,type:"number",description:"The delay duration for each successive request before reaching the maximum limit."},trustProxy:{envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",value:!1,type:"boolean",description:"Set this to true if the server is behind a load balancer."},skipKey:{envLink:"SERVER_RATE_LIMITING_SKIP_KEY",value:"",type:"string",description:"Allows bypassing the rate limiter and should be provided with the skipToken argument."},skipToken:{envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",value:"",type:"string",description:"Allows bypassing the rate limiter and should be provided with the skipKey argument."}}},pool:{minWorkers:{envLink:"POOL_MIN_WORKERS",value:4,type:"number",description:"The number of minimum and initial pool workers to spawn."},maxWorkers:{envLink:"POOL_MAX_WORKERS",value:8,type:"number",legacyName:"workers",description:"The number of maximum pool workers to spawn."},workLimit:{envLink:"POOL_WORK_LIMIT",value:40,type:"number",description:"The number of work pieces that can be performed before restarting the worker process."},acquireTimeout:{envLink:"POOL_ACQUIRE_TIMEOUT",value:5e3,type:"number",description:"The duration, in milliseconds, to wait for acquiring a resource."},createTimeout:{envLink:"POOL_CREATE_TIMEOUT",value:5e3,type:"number",description:"The duration, in milliseconds, to wait for creating a resource."},destroyTimeout:{envLink:"POOL_DESTROY_TIMEOUT",value:5e3,type:"number",description:"The duration, in milliseconds, to wait for destroying a resource."},idleTimeout:{envLink:"POOL_IDLE_TIMEOUT",value:3e4,type:"number",description:"The duration, in milliseconds, after which an idle resource is destroyed."},createRetryInterval:{envLink:"POOL_CREATE_RETRY_INTERVAL",value:200,type:"number",description:"The duration, in milliseconds, to wait before retrying the create process in case of a failure."},reaperInterval:{envLink:"POOL_REAPER_INTERVAL",value:1e3,type:"number",description:"The duration, in milliseconds, after which the check for idle resources to destroy is triggered."},benchmarking:{envLink:"POOL_BENCHMARKING",value:!1,type:"boolean",cliName:"poolBenchmarking",description:"Indicate whether to show statistics for the pool of resources or not."},listenToProcessExits:{envLink:"POOL_LISTEN_TO_PROCESS_EXITS",value:!0,type:"boolean",description:"Decides whether or not to attach process.exit handlers."}},logging:{level:{envLink:"LOGGING_LEVEL",value:4,type:"number",cliName:"logLevel",description:"The logging level to be used."},file:{envLink:"LOGGING_FILE",value:"highcharts-export-server.log",type:"string",cliName:"logFile",description:"The name of a log file. The logDest option also needs to be set to enable file logging."},dest:{envLink:"LOGGING_DEST",value:"log/",type:"string",cliName:"logDest",description:"The path to store log files. This also enables file logging."}},ui:{enable:{envLink:"UI_ENABLE",value:!1,type:"boolean",cliName:"enableUi",description:"Enables or disables the user interface (UI) for the export server."},route:{envLink:"UI_ROUTE",value:"/",type:"string",cliName:"uiRoute",description:"The endpoint route to which the user interface (UI) should be attached."}},other:{noLogo:{envLink:"OTHER_NO_LOGO",value:!1,type:"boolean",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:O.puppeteer.args.value.join(","),separator:","}],highcharts:[{type:"text",name:"version",message:"Highcharts version",initial:O.highcharts.version.value},{type:"text",name:"cdnURL",message:"The URL of CDN",initial:O.highcharts.cdnURL.value},{type:"multiselect",name:"modules",message:"Available modules",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:O.highcharts.modules.value},{type:"list",name:"scripts",message:"Custom scripts",initial:O.highcharts.scripts.value.join(","),separator:","},{type:"toggle",name:"forceFetch",message:"Force re-fetch the scripts",initial:O.highcharts.forceFetch.value},{type:"text",name:"cachePath",message:"The path to the cache directory",initial:O.highcharts.cachePath.value}],export:[{type:"select",name:"type",message:"The default export file type",hint:`Default: ${O.export.type.value}`,initial:0,choices:["png","jpeg","pdf","svg"]},{type:"select",name:"constr",message:"The default constructor for Highcharts",hint:`Default: ${O.export.constr.value}`,initial:0,choices:["chart","stockChart","mapChart","ganttChart"]},{type:"number",name:"defaultHeight",message:"The default fallback height of the exported chart",initial:O.export.defaultHeight.value},{type:"number",name:"defaultWidth",message:"The default fallback width of the exported chart",initial:O.export.defaultWidth.value},{type:"number",name:"defaultScale",message:"The default fallback scale of the exported chart",initial:O.export.defaultScale.value,min:.1,max:5},{type:"number",name:"rasterizationTimeout",message:"The rendering webpage timeout in milliseconds",initial:O.export.rasterizationTimeout.value}],customLogic:[{type:"toggle",name:"allowCodeExecution",message:"Enable execution of custom code",initial:O.customLogic.allowCodeExecution.value},{type:"toggle",name:"allowFileResources",message:"Enable file resources",initial:O.customLogic.allowFileResources.value}],server:[{type:"toggle",name:"enable",message:"Starts the server on 0.0.0.0",initial:O.server.enable.value},{type:"text",name:"host",message:"Server hostname",initial:O.server.host.value},{type:"number",name:"port",message:"Server port",initial:O.server.port.value},{type:"toggle",name:"benchmarking",message:"Enable server benchmarking",initial:O.server.benchmarking.value},{type:"toggle",name:"ssl.enable",message:"Enable SSL protocol",initial:O.server.ssl.enable.value},{type:"toggle",name:"ssl.force",message:"Force serving only over HTTPS",initial:O.server.ssl.force.value},{type:"number",name:"ssl.port",message:"SSL server port",initial:O.server.ssl.port.value},{type:"text",name:"ssl.certPath",message:"The path to find the SSL certificate/key",initial:O.server.ssl.certPath.value},{type:"toggle",name:"rateLimiting.enable",message:"Enable rate limiting",initial:O.server.rateLimiting.enable.value},{type:"number",name:"rateLimiting.maxRequests",message:"The maximum requests allowed per minute",initial:O.server.rateLimiting.maxRequests.value},{type:"number",name:"rateLimiting.window",message:"The rate-limiting time window in minutes",initial:O.server.rateLimiting.window.value},{type:"number",name:"rateLimiting.delay",message:"The delay for each successive request before reaching the maximum",initial:O.server.rateLimiting.delay.value},{type:"toggle",name:"rateLimiting.trustProxy",message:"Set to true if behind a load balancer",initial:O.server.rateLimiting.trustProxy.value},{type:"text",name:"rateLimiting.skipKey",message:"Allows bypassing the rate limiter when provided with the skipToken argument",initial:O.server.rateLimiting.skipKey.value},{type:"text",name:"rateLimiting.skipToken",message:"Allows bypassing the rate limiter when provided with the skipKey argument",initial:O.server.rateLimiting.skipToken.value}],pool:[{type:"number",name:"minWorkers",message:"The initial number of workers to spawn",initial:O.pool.minWorkers.value},{type:"number",name:"maxWorkers",message:"The maximum number of workers to spawn",initial:O.pool.maxWorkers.value},{type:"number",name:"workLimit",message:"The pieces of work that can be performed before restarting a Puppeteer process",initial:O.pool.workLimit.value},{type:"number",name:"acquireTimeout",message:"The number of milliseconds to wait for acquiring a resource",initial:O.pool.acquireTimeout.value},{type:"number",name:"createTimeout",message:"The number of milliseconds to wait for creating a resource",initial:O.pool.createTimeout.value},{type:"number",name:"destroyTimeout",message:"The number of milliseconds to wait for destroying a resource",initial:O.pool.destroyTimeout.value},{type:"number",name:"idleTimeout",message:"The number of milliseconds after an idle resource is destroyed",initial:O.pool.idleTimeout.value},{type:"number",name:"createRetryInterval",message:"The retry interval in milliseconds after a create process fails",initial:O.pool.createRetryInterval.value},{type:"number",name:"reaperInterval",message:"The reaper interval in milliseconds after triggering the check for idle resources to destroy",initial:O.pool.reaperInterval.value},{type:"toggle",name:"benchmarking",message:"Enable benchmarking for a resource pool",initial:O.pool.benchmarking.value},{type:"toggle",name:"listenToProcessExits",message:"Set to false to skip attaching process.exit handlers",initial:O.pool.listenToProcessExits.value}],logging:[{type:"number",name:"level",message:"The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)",initial:O.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:O.logging.file.value},{type:"text",name:"dest",message:"The path to log files. Enables file logging",initial:O.logging.dest.value}],ui:[{type:"toggle",name:"enable",message:"Enable UI for the export server",initial:O.ui.enable.value},{type:"text",name:"route",message:"A route to attach the UI",initial:O.ui.route.value}],other:[{type:"toggle",name:"noLogo",message:"Skip printing the logo on startup. Replaced by simple text",initial:O.other.noLogo.value}]},I=["options","globalOptions","themeOptions","resources","payload"],C={},$=(e,t="")=>{Object.keys(e).forEach((r=>{if(!["puppeteer","highcharts"].includes(r)){const i=e[r];void 0===i.value?$(i,`${t}.${r}`):(C[i.cliName||r]=`${t}.${r}`.substring(1),void 0!==i.legacyName&&(C[i.legacyName]=`${t}.${r}`.substring(1)))}}))};$(O);const _=["red","yellow","blue","gray","green"];let N={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:_[0]},{title:"warning",color:_[1]},{title:"notice",color:_[2]},{title:"verbose",color:_[3]},{title:"benchmark",color:_[4]}],listeners:[]};for(const[e,t]of Object.entries(O.logging))N[e]=t.value;const P=(e,t)=>{N.toFile&&(N.pathCreated||(!r(N.dest)&&i(N.dest),N.pathCreated=!0),o(`${N.dest}${N.file}`,[t].concat(e).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),N.toFile=!1)})))},A=(...e)=>{const[t,...r]=e,{level:i,levelsDesc:o}=N;if(5!==t&&(0===t||t>i||i>o.length))return;const n=`${(new Date).toString().split("(")[0].trim()} [${o[t-1].title}] -`;N.listeners.forEach((e=>{e(n,r.join(" "))})),N.toConsole&&console.log.apply(void 0,[n.toString()[N.levelsDesc[t-1].color]].concat(r)),P(r,n)},j=(e,t,r)=>{const i=r||t.message,{level:o,levelsDesc:n}=N;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];N.toConsole&&console.log.apply(void 0,[s.toString()[N.levelsDesc[e-1].color]].concat([i[_[e-1]],"\n",a])),N.listeners.forEach((e=>{e(s,l.join(" "))})),P(l,s)},H=e=>{e>=0&&e<=N.levelsDesc.length&&(N.level=e)},U=(e,t)=>{if(N={...N,dest:e||N.dest,file:t||N.file,toFile:!0},0===N.dest.length)return A(1,"[logger] File logging initialization: no path supplied.");N.dest.endsWith("/")||(N.dest+="/")},W=m(new URL("../.",import.meta.url)),D=(e,t)=>{const r=["png","jpeg","pdf","svg"];if(t){const i=t.split(".").pop();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"},M=(e=!1,t)=>{const r=["js","css","files"];let i=e,o=!1;if(t&&e.endsWith(".json"))try{i=F(n(e,"utf8"))}catch(e){return j(2,e,"[cli] No resources found.")}else i=F(e),i&&!t&&delete i.files;for(const e in i)r.includes(e)?o||(o=!0):delete i[e];return o?(i.files&&(i.files=i.files.map((e=>e.trim())),(!i.files||i.files.length<=0)&&delete i.files),i):A(3,"[cli] No resources found.")};function F(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},G=(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,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(O).forEach((t=>{["puppeteer","highcharts"].includes(t)||(console.log(`\n${t.toUpperCase()}`.red),e(O[t]))})),console.log("\n")}const J=e=>!["false","undefined","null","NaN","0",""].includes(e)&&!!e,K=(e,t)=>{if(e&&"string"==typeof e)return(e=e.trim()).endsWith(".js")?!!t&&K(n(e,"utf8")):e.startsWith("function()")||e.startsWith("function ()")||e.startsWith("()=>")||e.startsWith("() =>")?`(${e})()`:e.replace(/;$/,"")},z=()=>{const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6};class X 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 B={cdnURL:"https://code.highcharts.com/",activeManifest:{},sources:"",hcVersion:""};let Y=!1;const Q=()=>B.hcVersion=B.sources.substring(0,B.sources.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim(),Z=async(e,t,r,i=!1)=>{e.endsWith(".js")&&(e=e.substring(0,e.length-3)),A(4,`[cache] Fetching script - ${e}.js`);const o=t?{agent:t,timeout:+process.env.PROXY_SERVER_TIMEOUT||5e3}:{},n=await S(`${e}.js`,o);if(200===n.statusCode&&"string"==typeof n.text){if(r){r[e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")]=1}return n.text}if(i)throw new X(`Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${n.statusCode}).`).setError(n);return A(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`),""},ee=async(e,t)=>{const{coreScripts:r,modules:i,indicators:o,scripts:n}=e,a="latest"!==e.version&&e.version?`${e.version}/`:"";let l;A(3,`[cache] Updating cache version to Highcharts: ${a||"latest"}.`);const c=process.env.PROXY_SERVER_HOST,p=process.env.PROXY_SERVER_PORT;if(c&&p)try{l=new h({host:c,port:+p})}catch(e){throw new X("[cache] Could not create a Proxy Agent.").setError(e)}const u={};try{return B.sources=await(async(e,t,r,i,o,n)=>{const s=[...e.map((e=>Z(`${i}${e}`,o,n,!0))),...t.map((e=>Z(`${i}${e}`,o,n))),...r.map((e=>Z(`${e}`,o)))];return(await Promise.all(s)).join(";\n")})([...r.map((e=>`${a}${e}`))],[...i.map((e=>"map"===e?`maps/${a}modules/${e}`:`${a}modules/${e}`)),...o.map((e=>`stock/${a}indicators/${e}`))],n,e.cdnURL||B.cdnURL,l,u),Q(),s(t,B.sources),u}catch(e){throw new X("[cache] Unable to update the local Highcharts cache.").setError(e)}},te=async e=>{const t=c(W,e.cachePath);let o;const a=c(t,"manifest.json"),l=c(t,"sources.js");if(Y=e,!r(t)&&i(t),!r(a)||e.forceFetch)A(3,"[cache] Fetching and caching Highcharts dependencies."),o=await ee(e,l);else{let t=!1;const r=JSON.parse(n(a));if(r.modules&&Array.isArray(r.modules)){const e={};r.modules.forEach((t=>e[t]=1)),r.modules=e}const{modules:i,coreScripts:s,indicators:c}=e,p=i.length+s.length+c.length;r.version!==e.version?(A(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),t=!0):Object.keys(r.modules||{}).length!==p?(A(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),t=!0):t=(e.modules||[]).some((e=>{if(!r.modules[e])return A(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),t?o=await ee(e,l):(A(3,"[cache] Dependency cache is up to date, proceeding."),B.sources=n(l,"utf8"),o=r.modules,Q())}await(async(e,t)=>{const r={version:e.version,modules:t||{}};B.activeManifest=r,A(3,"[cache] Writing a new manifest.");try{s(c(W,e.cachePath,"manifest.json"),JSON.stringify(r),"utf8")}catch(e){throw new X("[cache] Error writing the cache manifest.").setError(e)}})(e,o)},re=()=>c(W,Y.cachePath);var ie=async e=>!!Y&&await te(Object.assign(Y,{version:e})),oe=()=>B,ne=()=>B.hcVersion;let se={};const ae=()=>se,le=(e,t,r=[])=>{const i=q(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]:le(i[e],n,r);var o;return i};function ce(e,t={},r=""){Object.keys(e).forEach((i=>{const o=e[i],n=t&&t[i];let s;void 0===o.value?ce(o,n,`${r}.${i}`):(void 0!==n&&(o.value=n),o.envLink&&("boolean"===o.type?o.value=J([process.env[o.envLink],o.value].find((e=>e||"false"===e))):"number"===o.type?(s=+process.env[o.envLink],o.value=s>=0?s:o.value):o.type.indexOf("]")>=0&&process.env[o.envLink]?o.value=process.env[o.envLink].split(","):o.value=process.env[o.envLink]||o.value))}))}function pe(e){let t={};for(const[r,i]of Object.entries(e))t[r]=Object.prototype.hasOwnProperty.call(i,"value")?i.value:pe(i);return t}function he(e,t,r){for(;t.length>1;){const i=t.shift();return Object.prototype.hasOwnProperty.call(e,i)||(e[i]={}),e[i]=he(Object.assign({},e[i]),t,r),e}return e[t[0]]=r,e}const ue=T(64).toString("base64url"),de=w.join("tmp",`puppeteer-${ue}`),ge=[`--user-data-dir=${w.join(de,"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"],me=g.fileURLToPath(new URL(".",import.meta.url)),fe=t.readFileSync(me+"/../templates/template.html","utf8");let ve;const ye=async e=>{await e.setContent(fe),await e.addScriptTag({path:`${re()}/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()}`)}))},we=async(e,t=!1)=>{try{t?(await e.goto("about:blank"),await ye(e)):await e.evaluate((()=>{document.body.innerHTML='
'}))}catch(e){j(2,e,"[browser] Could not clear the content of the page.")}},be=async()=>{if(!ve)return!1;const e=await ve.newPage();return await e.setCacheEnabled(!1),await ye(e),e},Te=async()=>(ve?.isConnected()&&(await ve.close(),A(4,"[browser] Closed the browser.")),!0);const ke=g.fileURLToPath(new URL(".",import.meta.url)),xe=(e,t,r)=>e.evaluate(((e,t)=>window.triggerExport(e,t)),t,r);var Ee=async(e,t,r)=>{const i=[],o=async e=>{for(const e of i)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{A(4,"[export] Determining export path.");const s=r.export;await e.evaluate((()=>requestAnimationFrame((()=>{}))));const a=s?.options?.chart?.displayErrors&&oe().activeManifest.modules.debugger;let c;if(await e.evaluate((e=>window._displayErrors=e),a),t.indexOf&&(t.indexOf("=0||t.indexOf("=0)){if(A(4,"[export] Treating as SVG."),"svg"===s.type)return t;c=!0,await e.setContent((e=>`\n\n\n \n \n Highcarts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`)(t))}else A(4,"[export] Treating as config."),s.strInj?await xe(e,{chart:{height:s.height,width:s.width}},r):(t.chart.height=s.height,t.chart.width=s.width,await xe(e,t,r));const p=r.customLogic.resources;if(p){if(p.js&&i.push(await e.addScriptTag({content:p.js})),p.files)for(const t of p.files)try{const r=!t.startsWith("http");i.push(await e.addScriptTag(r?{content:n(t,"utf8")}:{url:t}))}catch(e){j(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 o of t)o&&(o=o.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),o.startsWith("http")?i.push(await e.addStyleTag({url:o})):r.customLogic.allowFileResources&&i.push(await e.addStyleTag({path:l.join(ke,o)})));i.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(s.scale)):await e.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return{chartHeight:e,chartWidth:t}})),u=Math.ceil(h?.chartHeight||s.height),d=Math.ceil(h?.chartWidth||s.width);await e.setViewport({height:u,width:d,deviceScaleFactor:c?1:parseFloat(s.scale)});const g=c?e=>{document.body.style.zoom=e,document.body.style.margin="0px"}:()=>{document.body.style.zoom=1};await e.evaluate(g,parseFloat(s.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)}})))(e);let w;if(c||await e.setViewport({width:Math.round(f),height:Math.round(m),deviceScaleFactor:parseFloat(s.scale)}),"svg"===s.type)w=await(e=>e.$eval("#container svg:first-of-type",(e=>e.outerHTML)))(e);else if("png"===s.type||"jpeg"===s.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 X("Rasterization timeout"))),o||1500)))]))(e,s.type,"base64",{width:d,height:u,x:v,y:y},s.rasterizationTimeout);else{if("pdf"!==s.type)throw new X(`[export] Unsupported output format ${s.type}.`);w=await((e,t,r,i)=>e.pdf({height:t+1,width:r,encoding:i}))(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 o(e),w}catch(t){return await o(e),t}};let Le,Se=0,Oe=0,Re=0,Ie=0,Ce=0,$e={},_e=!1;const Ne={create:async()=>{let e=!1;const t=y(),r=(new Date).getTime();try{if(e=await be(),!e||e.isClosed())throw new X("The page is invalid or closed.");A(3,`[pool] Successfully created a worker ${t} - took ${(new Date).getTime()-r} ms.`)}catch(e){throw new X("Error encountered when creating a new page.").setError(e)}return{id:t,page:e,workCount:Math.round(Math.random()*($e.workLimit/2))}},validate:async e=>$e.workLimit&&++e.workCount>$e.workLimit?(A(3,`[pool] Worker failed validation: exceeded work limit (limit is ${$e.workLimit}).`),!1):(await we(e.page,!0),!0),destroy:e=>{A(3,`[pool] Destroying pool entry ${e.id}.`),e.page&&e.page.close()}},Pe=async e=>{if($e=e&&e.pool?{...e.pool}:{},$e.listenToProcessExits&&(A(3,"[pool] Attaching exit listeners to the process."),process.on("exit",(async e=>{A(4,`Process exited with code ${e}.`),await Ae()})),process.on("SIGINT",((e,t)=>{A(4,`The ${e} event with code: ${t}.`),process.exit(1)})),process.on("SIGTERM",((e,t)=>{A(4,`The ${e} event with code: ${t}.`),process.exit(1)})),process.on("uncaughtException",(async(e,t)=>{j(1,e,`The ${t} error.`),await Ae(),process.exit(1)}))),Le=e.puppeteerArgs,await(async e=>{const t=[...ge,...e||[]];if(!ve){let e=0;const r=async()=>{try{A(3,`[browser] Attempting to get a browser instance (try ${++e}).`),ve=await b.launch({headless:"new",args:t,userDataDir:"./tmp/"})}catch(t){if(j(1,t,"[browser] Failed to launch a browser instance."),!(e<25))throw t;A(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 X("[browser] Maximum retries to open a browser instance reached.").setError(e)}if(!ve)throw new X("[browser] Cannot find a browser to open.")}return ve})(Le),A(3,`[pool] Initializing pool with workers: min ${$e.minWorkers}, max ${$e.maxWorkers}.`),_e)return A(4,"[pool] Already initialized, please kill it before creating a new one.");parseInt($e.minWorkers)>parseInt($e.maxWorkers)&&($e.minWorkers=$e.maxWorkers);try{_e=new v({...Ne,min:parseInt($e.minWorkers),max:parseInt($e.maxWorkers),acquireTimeoutMillis:$e.acquireTimeout,createTimeoutMillis:$e.createTimeout,destroyTimeoutMillis:$e.destroyTimeout,idleTimeoutMillis:$e.idleTimeout,createRetryIntervalMillis:$e.createRetryInterval,reapIntervalMillis:$e.reaperInterval,propagateCreateError:!1}),_e.on("release",(async e=>{await we(e.page,!1),A(4,`[pool] Releasing a worker with ID ${e.id}.`)})),_e.on("destroySuccess",((e,t)=>{A(4,`[pool] Destroyed a worker with ID ${t.id}.`)}));const e=[];for(let t=0;t<$e.minWorkers;t++)try{const t=await _e.acquire().promise;e.push(t)}catch(e){j(2,e,"[pool] Could not create an initial resource.")}e.forEach((e=>{_e.release(e)})),A(3,"[pool] The pool is ready"+(e.length?` with ${e.length} initial resources waiting.`:"."))}catch(e){throw await Te(),new X("[pool] Could not create the pool of workers.").setError(e)}};async function Ae(){return A(3,"[pool] Killing all pool workers and browser, if any exist."),_e?.destroyed||_e&&(await _e.destroy(),A(4,"[browser] Destroyed the pool of resources.")),Te()}const je=async(e,t)=>{let r;try{if(A(4,"[pool] Work received, starting to process."),++Oe,$e.benchmarking&&He(),!_e)throw new X("Work received, but pool has not been started.");try{A(4,"[pool] Acquiring a worker handle.");const e=z();r=await _e.acquire().promise,t.server.benchmarking&&A(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Acquired a worker handle: ${e()}ms.`)}catch(e){throw new X("Error encountered when acquiring an available entry.").setError(e)}if(A(4,"[pool] Acquired a worker handle."),!r.page)throw new X("Resolved worker page is invalid: the pool setup is wonky.");let i=(new Date).getTime();A(4,`[pool] Starting work on pool entry with ID ${r.id}.`);const o=z(),n=await Ee(r.page,e,t);if(n instanceof Error)throw"Rasterization timeout"===n.message&&(r.page.close(),r.page=await be()),new X("Error encountered during export.").setError(n);t.server.benchmarking&&A(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Exported a chart sucessfully: ${o()}ms.`),_e.release(r);const s=(new Date).getTime()-i;return Re+=s,Ce=Re/++Se,A(4,`[pool] Work completed in ${s} ms.`),{result:n,options:t}}catch(e){throw++Ie,r&&_e.release(r),new X(`[pool] In pool.postWork: ${e.message}`).setError(e)}};function He(){const{min:e,max:t}=_e;A(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),A(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),A(5,`[pool] The number of resources that are currently available: ${_e.numFree()}.`),A(5,`[pool] The number of resources that are currently acquired: ${_e.numUsed()}.`),A(5,`[pool] The number of callers waiting to acquire a resource: ${_e.numPendingAcquires()}.`)}var Ue=()=>({min:_e.min,max:_e.max,available:_e.numFree(),inUse:_e.numUsed(),pendingAcquire:_e.numPendingAcquires()}),We=()=>Oe,De=()=>Ie,Me=()=>Ce,Fe=()=>Se;let qe=!1;const Ge=async(e,t)=>{A(4,"[chart] Starting the exporting process.");const r=((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=le(t,e,I),r.export.outfile=r.export?.outfile||`chart.${r.export?.type||"png"}`,r})(e,ae()),i=r.export;if(r.payload?.svg&&""!==r.payload.svg)try{return A(4,"[chart] Attempting to export from a SVG input."),ze(r.payload.svg.trim(),r,t)}catch(e){return t(new X("[chart] Error loading SVG input.").setError(e))}if(i.infile&&i.infile.length)try{return A(4,"[chart] Attempting to export from an input file."),r.export.instr=n(i.infile,"utf8"),ze(r.export.instr.trim(),r,t)}catch(e){return t(new X("[chart] Error loading input file.").setError(e))}if(i.instr&&""!==i.instr||i.options&&""!==i.options)try{return A(4,"[chart] Attempting to export from a raw input."),J(r.customLogic?.allowCodeExecution)?Ke(r,t):"string"==typeof i.instr?ze(i.instr.trim(),r,t):Je(r,i.instr||i.options,t)}catch(e){return t(new X("[chart] Error loading raw input.").setError(e))}return t(new X("[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||F(e.export?.instr),i=F(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(e,t,r,i)=>{let{export:o,customLogic:s}=e;const a="boolean"==typeof s.allowCodeExecution?s.allowCodeExecution:qe;if(s){if(a)if("string"==typeof e.customLogic.resources)e.customLogic.resources=M(e.customLogic.resources,J(e.customLogic.allowFileResources));else if(!e.customLogic.resources)try{const t=n("resources.json","utf8");e.customLogic.resources=M(t,J(e.customLogic.allowFileResources))}catch(e){j(2,e,"[chart] Unable to load the default resources.json file.")}}else s=e.customLogic={};if(!a&&s){if(s.callback||s.resources||s.customCode)return r(new X("[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server."));s.callback=!1,s.resources=!1,s.customCode=!1}if(t&&(t.chart=t.chart||{},t.exporting=t.exporting||{},t.exporting.enabled=!1),o.constr=o.constr||"chart",o.type=D(o.type,o.outfile),"svg"===o.type&&(o.width=!1),["globalOptions","themeOptions"].forEach((e=>{try{o&&o[e]&&("string"==typeof o[e]&&o[e].endsWith(".json")?o[e]=F(n(o[e],"utf8"),!0):o[e]=F(o[e],!0))}catch(t){o[e]={},j(2,t,`[chart] The '${e}' 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=n(s.callback,"utf8")}catch(e){s.callback=!1,j(2,e,"[chart] The 'callback' cannot be loaded.")}else s.callback=!1;e.export={...e.export,...Ve(e)};try{return r(!1,await je(o.strInj||t||i,e))}catch(e){return r(e)}},Ke=(e,t)=>{try{let r,i=e.export.instr||e.export.options;return"string"!=typeof i&&(r=i=G(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 X(`[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:i}=t.customLogic;if(e.indexOf("=0||e.indexOf("=0)return A(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 J(i)?Ke(t,r):r(new X("[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=(e,t,r,i)=>{j(1,e),"development"!==process.env.NODE_ENV&&delete e.stack,i(e)},Be=(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 Ye=(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=L({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&&(A(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(o),A(3,`[rate limiting] Enabled rate limiting with ${i.max} requests per ${i.window} minute for each IP, trusting proxy: ${i.trustProxy}.`)};class Qe extends X{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=[],it=(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},ot=async(e,t,r)=>{try{const r=z(),o=y().replace(/-/g,""),n=ae(),s=e.body,a=++et;let l=D(s.type);if(!s||"object"==typeof(i=s)&&null!==i&&0===Object.keys(i).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=F(s.infile||s.options||s.data);if(!c&&!s.svg)throw A(2,`The request with ID ${o} from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Payload received: ${JSON.stringify(s)}.`),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=it(tt,e,t,{id:a,uniqueId:o,type:l,body:s}),!0!==p)return t.send(p);let h=!1;e.socket.on("close",(()=>{h=!0})),A(4,`[export] Got an incoming HTTP request with ID ${o}.`),s.constr="string"==typeof s.constr&&s.constr||"chart";const u={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:F(s.globalOptions,!0),themeOptions:F(s.themeOptions,!0)},customLogic:{allowCodeExecution:qe,allowFileResources:!1,resources:F(s.resources,!0),callback:s.callback,customCode:s.customCode}};c&&(u.export.instr=G(c,u.customLogic.allowCodeExecution));const d=le(n,u);if(d.export.options=c,d.payload={svg:s.svg||!1,b64:s.b64||!1,noDownload:s.noDownload||!1,requestId:o},s.svg&&(e=>["localhost","(10).(.*).(.*).(.*)","(127).(.*).(.*).(.*)","(172).(1[6-9]|2[0-9]|3[0-1]).(.*).(.*)","(192).(168).(.*).(.*)"].some((t=>e.match(`xlink:href="(?:(http://|https://))?${t}`))))(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 Ge(d,((i,c)=>{if(e.socket.removeAllListeners("close"),n.server.benchmarking&&A(5,`[benchmark] Request with ID ${o} - After the whole exporting process: ${r()}ms.`),h)return A(3,"[export] The client closed the connection before the chart finished processing.");if(i)throw i;if(!c||!c.result)throw new Qe(`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,it(rt,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 nt=JSON.parse(n(c(W,"package.json"))),st=new Date;const at=x();at.disable("x-powered-by"),at.use(k());const lt=E.memoryStorage(),ct=E({storage:lt,limits:{fieldSize:52428800}});at.use(x.json({limit:52428800})),at.use(x.urlencoded({extended:!0,limit:52428800})),at.use(ct.none());const pt=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}`)}))}))},ht=async e=>{try{if(!e.enable)return!1;if(!e.ssl.force){const t=u.createServer(at);pt(t),t.listen(e.port,e.host),A(3,`[server] Started HTTP server on ${e.host}:${e.port}.`)}if(e.ssl.enable){let t,r;try{t=await a.readFile(p.join(e.ssl.certPath,"server.key"),"utf8"),r=await a.readFile(p.join(e.ssl.certPath,"server.crt"),"utf8")}catch(t){A(2,`[server] Unable to load key/certificate from the '${e.ssl.certPath}' path. Could not run secured layer server.`)}if(t&&r){const t=d.createServer(at);pt(t),t.listen(e.ssl.port,e.host),A(3,`[server] Started HTTPS server on ${e.host}:${e.ssl.port}.`)}}e.rateLimiting&&e.rateLimiting.enable&&![0,NaN].includes(e.rateLimiting.maxRequests)&&Ye(at,e.rateLimiting),at.use(x.static(p.join(W,"public"))),(e=>{!!e&&e.get("/health",((e,t)=>{t.send({status:"OK",bootTime:st,uptime:Math.floor(((new Date).getTime()-st.getTime())/1e3/60)+" minutes",version:nt.version,highchartsVersion:ne(),averageProcessingTime:Me(),performedExports:Fe(),failedExports:De(),exportAttempts:We(),sucessRatio:Fe()/We()*100,pool:Ue()})}))})(at),(e=>{e.post("/",ot),e.post("/:filename",ot)})(at),(e=>{!!e&&e.get("/",((e,t)=>{t.sendFile(c(W,"public","index.html"))}))})(at),(e=>{!!e&&e.post("/version/change/:newVersion",(async(e,t,r)=>{try{const r=process.env.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 i=e.get("hc-auth");if(!i||i!==r)throw new Qe("Invalid or missing token: Set the token in the hc-auth header.",401);const o=e.params.newVersion;if(!o)throw new Qe("No new version supplied.",400);try{await ie(o)}catch(e){throw new Qe(`Version change: ${e.message}`,e.statusCode).setError(e)}t.status(200).send({statusCode:200,version:ne(),message:`Successfully updated Highcharts to version: ${o}.`})}catch(e){r(e)}}))})(at),(e=>{e.use(Xe),e.use(Be)})(at)}catch(e){throw new X("[server] Could not configure and start the server.").setError(e)}};var ut={startServer:ht,enableRateLimiting:e=>Ye(at,e),getExpress:()=>x,getApp:()=>at,use:(e,...t)=>{at.use(e,...t)},get:(e,...t)=>{at.get(e,...t)},post:(e,...t)=>{at.post(e,...t)}};e.config();var dt={server:ut,startServer:ht,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(n(r))}catch(e){j(2,e,`[config] Unable to load the configuration from the ${r} file.`)}}return{}}(t)),ce(O,se),se=pe(O),e&&(se=le(se,e,I)),t?.length&&(se=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]=J(t[o]):"number"===a?e[r]=+t[o]:a.indexOf("]")>=0?e[r]=t[o].split(","):e[r]=t[o]:(A(2,`[config] Missing value for the '${n}' argument. Using the default value.`),i=!0)),e[r])),e)}i&&V();return e}(se,t,O)),se),initExport:async e=>{var t;return t=e.customLogic&&e.customLogic.allowCodeExecution,qe=J(t),(e=>{H(e&&parseInt(e.level)),e&&e.dest&&U(e.dest,e.file||"highcharts-export-server.log")})(e.logging),await te(e.highcharts||{version:"latest"}),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 Ge(e,(async(e,t)=>{if(e)throw e;const{outfile:r,type:i}=t.options.export;s(r||`chart.${i}`,"svg"!==i?Buffer.from(t.result,"base64"):t.result),await Ae()}))},batchExport:async e=>{const t=[];for(let r of e.export.batch.split(";"))r=r.split("="),2===r.length&&t.push(Ge({...e,export:{...e.export,infile:r[0],outfile:r[1]}},((e,t)=>{if(e)throw e;s(t.options.export.outfile,Buffer.from(t.result,"base64"))})));try{await Promise.all(t),await Ae()}catch(e){throw new X("[chart] Error encountered during batch export.").setError(e)}},startExport:Ge,killPool:Ae,log:A,logWithStack:j,setLogLevel:H,enableFileLogging:U,mapToNewConfig:e=>{const t={};for(const[r,i]of Object.entries(e)){const e=C[r]?C[r].split("."):[];e.reduce(((t,r,o)=>t[r]=e.length-1===o?i:t[r]||{}),t)}return t},manualConfig:async e=>{let t={};r(e)&&(t=JSON.parse(n(e,"utf8")));const i=Object.keys(R).map((e=>({title:`${e} options`,value:e})));return f({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(r,i)=>{let o=0,n=[];for(const e of i)R[e]=R[e].map((t=>({...t,section:e}))),n=[...n,...R[e]];return await f(n,{onSubmit:async(r,i)=>{if("modules"===r.name?(i=i.length?i.map((e=>r.choices[e])):r.choices,t[r.section][r.name]=i):t[r.section]=he(Object.assign({},t[r.section]||{}),r.name.split("."),r.choices?r.choices[i]:i),++o===n.length){try{await a.writeFile(e,JSON.stringify(t,null,2),"utf8")}catch(t){j(1,t,`[config] An error occurred while creating the ${e} file.`)}return!0}}}),!0}})},printLogo:e=>{const t=JSON.parse(n(c(W,"package.json"))).version;e?console.log(`Starting Highcharts Export Server v${t}...`):console.log(n(W+"/msg/startup.msg").toString().bold.yellow,`v${t}`)},printUsage:V};export{dt as default}; //# sourceMappingURL=index.esm.js.map diff --git a/dist/index.esm.js.map b/dist/index.esm.js.map index 42a55bb9..645bd873 100644 --- a/dist/index.esm.js.map +++ b/dist/index.esm.js.map @@ -1 +1 @@ -{"version":3,"file":"index.esm.js","sources":["../lib/fetch.js","../lib/schemas/config.js","../lib/logger.js","../lib/utils.js","../lib/errors/ExportError.js","../lib/cache.js","../lib/config.js","../lib/browser.js","../lib/export.js","../templates/svg_export/svg_export.js","../lib/pool.js","../lib/chart.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/index.js"],"sourcesContent":["/**\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","/*******************************************************************************\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// Load .env into environment variables\r\nimport dotenv from 'dotenv';\r\n\r\ndotenv.config();\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 envLink: 'HIGHCHARTS_VERSION',\r\n type: 'string',\r\n description: 'The Highcharts version to be used.'\r\n },\r\n cdnURL: {\r\n value: 'https://code.highcharts.com/',\r\n envLink: 'HIGHCHARTS_CDN_URL',\r\n type: 'string',\r\n description: 'The CDN URL for Highcharts scripts to be used.'\r\n },\r\n coreScripts: {\r\n envLink: 'HIGHCHARTS_CORE_SCRIPTS',\r\n value: ['highcharts', 'highcharts-more', 'highcharts-3d'],\r\n type: 'string[]',\r\n description: 'The core Highcharts scripts to fetch.'\r\n },\r\n modules: {\r\n envLink: 'HIGHCHARTS_MODULES',\r\n value: [\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 type: 'string[]',\r\n description: 'The modules of Highcharts to fetch.'\r\n },\r\n indicators: {\r\n envLink: 'HIGHCHARTS_INDICATORS',\r\n value: ['indicators-all'],\r\n type: 'string[]',\r\n description: 'The indicators of Highcharts to fetch.'\r\n },\r\n scripts: {\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 optional scripts or dependencies to fetch.'\r\n },\r\n forceFetch: {\r\n envLink: 'HIGHCHARTS_FORCE_FETCH',\r\n value: false,\r\n type: 'boolean',\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 envLink: 'HIGHCHARTS_CACHE_PATH',\r\n value: '.cache',\r\n type: 'string',\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 envLink: 'EXPORT_TYPE',\r\n value: 'png',\r\n type: 'string',\r\n description: 'The file export format. It can be jpeg, png, pdf, or svg.'\r\n },\r\n constr: {\r\n envLink: 'EXPORT_CONSTR',\r\n value: 'chart',\r\n type: 'string',\r\n description:\r\n 'The constructor to use. Can be chart, stockChart, mapChart, or ganttChart.'\r\n },\r\n defaultHeight: {\r\n envLink: 'EXPORT_DEFAULT_HEIGHT',\r\n value: 400,\r\n type: 'number',\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 envLink: 'EXPORT_DEFAULT_WIDTH',\r\n value: 600,\r\n type: 'number',\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 envLink: 'EXPORT_DEFAULT_SCALE',\r\n value: 1,\r\n type: 'number',\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 type: 'number',\r\n value: false,\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 type: 'number',\r\n value: false,\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 envLink: 'EXPORT_RASTERIZATION_TIMEOUT',\r\n value: 1500,\r\n type: 'number',\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 envLink: 'CUSTOM_LOGIC_ALLOW_CODE_EXECUTION',\r\n value: false,\r\n type: 'boolean',\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 envLink: 'CUSTOM_LOGIC_ALLOW_FILE_RESOURCES',\r\n value: false,\r\n type: 'boolean',\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 envLink: 'SERVER_ENABLE',\r\n value: false,\r\n type: 'boolean',\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 envLink: 'SERVER_HOST',\r\n value: '0.0.0.0',\r\n type: 'string',\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 envLink: 'SERVER_PORT',\r\n value: 7801,\r\n type: 'number',\r\n description: 'The server port when enabled.'\r\n },\r\n benchmarking: {\r\n envLink: 'SERVER_BENCHMARKING',\r\n value: false,\r\n type: 'boolean',\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 ssl: {\r\n enable: {\r\n envLink: 'SERVER_SSL_ENABLE',\r\n value: false,\r\n type: 'boolean',\r\n cliName: 'enableSsl',\r\n description: 'Enables or disables the SSL protocol.'\r\n },\r\n force: {\r\n envLink: 'SERVER_SSL_FORCE',\r\n value: false,\r\n type: 'boolean',\r\n cliName: 'sslForced',\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 envLink: 'SERVER_SSL_PORT',\r\n value: 443,\r\n type: 'number',\r\n cliName: 'sslPort',\r\n description: 'The port on which to run the SSL server.'\r\n },\r\n certPath: {\r\n envLink: 'SERVER_SSL_CERT_PATH',\r\n value: '',\r\n type: 'string',\r\n legacyName: 'sslPath',\r\n description: 'The path to the SSL certificate/key file.'\r\n }\r\n },\r\n rateLimiting: {\r\n enable: {\r\n envLink: 'SERVER_RATE_LIMITING_ENABLE',\r\n value: false,\r\n type: 'boolean',\r\n cliName: 'enableRateLimiting',\r\n description: 'Enables rate limiting for the server.'\r\n },\r\n maxRequests: {\r\n envLink: 'SERVER_RATE_LIMITING_MAX_REQUESTS',\r\n value: 10,\r\n type: 'number',\r\n legacyName: 'rateLimit',\r\n description: 'The maximum number of requests allowed in one minute.'\r\n },\r\n window: {\r\n envLink: 'SERVER_RATE_LIMITING_WINDOW',\r\n value: 1,\r\n type: 'number',\r\n description: 'The time window, in minutes, for the rate limiting.'\r\n },\r\n delay: {\r\n envLink: 'SERVER_RATE_LIMITING_DELAY',\r\n value: 0,\r\n type: 'number',\r\n description:\r\n 'The delay duration for each successive request before reaching the maximum limit.'\r\n },\r\n trustProxy: {\r\n envLink: 'SERVER_RATE_LIMITING_TRUST_PROXY',\r\n value: false,\r\n type: 'boolean',\r\n description: 'Set this to true if the server is behind a load balancer.'\r\n },\r\n skipKey: {\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_KEY',\r\n value: '',\r\n type: 'string',\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 envLink: 'SERVER_RATE_LIMITING_SKIP_TOKEN',\r\n value: '',\r\n type: 'string',\r\n description:\r\n 'Allows bypassing the rate limiter and should be provided with the skipKey argument.'\r\n }\r\n }\r\n },\r\n pool: {\r\n minWorkers: {\r\n envLink: 'POOL_MIN_WORKERS',\r\n value: 4,\r\n type: 'number',\r\n description: 'The number of minimum and initial pool workers to spawn.'\r\n },\r\n maxWorkers: {\r\n envLink: 'POOL_MAX_WORKERS',\r\n value: 8,\r\n type: 'number',\r\n legacyName: 'workers',\r\n description: 'The number of maximum pool workers to spawn.'\r\n },\r\n workLimit: {\r\n envLink: 'POOL_WORK_LIMIT',\r\n value: 40,\r\n type: 'number',\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 envLink: 'POOL_ACQUIRE_TIMEOUT',\r\n value: 5000,\r\n type: 'number',\r\n description:\r\n 'The duration, in milliseconds, to wait for acquiring a resource.'\r\n },\r\n createTimeout: {\r\n envLink: 'POOL_CREATE_TIMEOUT',\r\n value: 5000,\r\n type: 'number',\r\n description:\r\n 'The duration, in milliseconds, to wait for creating a resource.'\r\n },\r\n destroyTimeout: {\r\n envLink: 'POOL_DESTROY_TIMEOUT',\r\n value: 5000,\r\n type: 'number',\r\n description:\r\n 'The duration, in milliseconds, to wait for destroying a resource.'\r\n },\r\n idleTimeout: {\r\n envLink: 'POOL_IDLE_TIMEOUT',\r\n value: 30000,\r\n type: 'number',\r\n description:\r\n 'The duration, in milliseconds, after which an idle resource is destroyed.'\r\n },\r\n createRetryInterval: {\r\n envLink: 'POOL_CREATE_RETRY_INTERVAL',\r\n value: 200,\r\n type: 'number',\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 envLink: 'POOL_REAPER_INTERVAL',\r\n value: 1000,\r\n type: 'number',\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 envLink: 'POOL_BENCHMARKING',\r\n value: false,\r\n type: 'boolean',\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 listenToProcessExits: {\r\n envLink: 'POOL_LISTEN_TO_PROCESS_EXITS',\r\n value: true,\r\n type: 'boolean',\r\n description: 'Decides whether or not to attach process.exit handlers.'\r\n }\r\n },\r\n logging: {\r\n level: {\r\n envLink: 'LOGGING_LEVEL',\r\n value: 4,\r\n type: 'number',\r\n cliName: 'logLevel',\r\n description: 'The logging level to be used.'\r\n },\r\n file: {\r\n envLink: 'LOGGING_FILE',\r\n value: 'highcharts-export-server.log',\r\n type: 'string',\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 envLink: 'LOGGING_DEST',\r\n value: 'log/',\r\n type: 'string',\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 envLink: 'UI_ENABLE',\r\n value: false,\r\n type: 'boolean',\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 envLink: 'UI_ROUTE',\r\n value: '/',\r\n type: 'string',\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 noLogo: {\r\n envLink: 'OTHER_NO_LOGO',\r\n value: false,\r\n type: 'boolean',\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: 'modules',\r\n message: 'Available modules',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n choices: defaultConfig.highcharts.modules.value\r\n },\r\n {\r\n type: 'list',\r\n name: 'scripts',\r\n message: 'Custom scripts',\r\n initial: defaultConfig.highcharts.scripts.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: '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 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 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 type: 'toggle',\r\n name: 'listenToProcessExits',\r\n message: 'Set to false to skip attaching process.exit handlers',\r\n initial: defaultConfig.pool.listenToProcessExits.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: '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\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 // Check if extension has a correct type\r\n 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.\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' && item !== null && 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 return [\r\n 'localhost',\r\n '(10).(.*).(.*).(.*)',\r\n '(127).(.*).(.*).(.*)',\r\n '(172).(1[6-9]|2[0-9]|3[0-1]).(.*).(.*)',\r\n '(192).(168).(.*).(.*)'\r\n ].some((ipRegEx) =>\r\n item.match(`xlink:href=\"(?:(http://|https://))?${ipRegEx}`)\r\n );\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","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 dotenv from 'dotenv';\r\nimport { HttpsProxyAgent } from 'https-proxy-agent';\r\n\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\ndotenv.config();\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// TODO: The config should be accesssible globally so we don't have to do this sort of thing..\r\nlet appliedConfig = false;\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\nconst extractVersion = () =>\r\n (cache.hcVersion = 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\nconst 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\nconst 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} proxyAgent - The proxy agent to use for a request.\r\n * @param {Object} fetchedModules - An object which tracks which Highcharts modules have been fetched.\r\n * @param {boolean} shouldThrowError - A flag to indicate if the error should be 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\nconst fetchAndProcessScript = async (\r\n script,\r\n proxyAgent,\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 // If exists, add proxy agent to request options\r\n const requestOptions = proxyAgent\r\n ? {\r\n agent: proxyAgent,\r\n timeout: +process.env['PROXY_SERVER_TIMEOUT'] || 5000\r\n }\r\n : {};\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} scripts - Array of Highcharts modules to fetch.\r\n * @param {string} customScripts - Array of custom script paths to fetch (full URLs).\r\n * @param {object} proxyAgent - The proxy agent to use for a request.\r\n * @param {object} fetchedModules - An object which tracks which Highcharts modules have been fetched.\r\n * @returns {Promise} The fetched scripts content joined.\r\n */\r\nconst fetchScripts = async (\r\n coreScripts,\r\n moduleScripts,\r\n customScripts,\r\n cdnURL,\r\n proxyAgent,\r\n fetchedModules\r\n) => {\r\n const allFetchPromises = [\r\n ...coreScripts.map((script) =>\r\n fetchAndProcessScript(\r\n `${cdnURL}${script}`,\r\n proxyAgent,\r\n fetchedModules,\r\n true\r\n )\r\n ),\r\n ...moduleScripts.map((script) =>\r\n fetchAndProcessScript(`${cdnURL}${script}`, proxyAgent, fetchedModules)\r\n ),\r\n ...customScripts.map((script) =>\r\n fetchAndProcessScript(`${script}`, proxyAgent)\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} config - The configuration object containing information\r\n * about scripts and modules.\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\nconst updateCache = async (config, sourcePath) => {\r\n const { coreScripts, modules, indicators, scripts: customScripts } = config;\r\n const hcVersion =\r\n config.version === 'latest' || !config.version ? '' : `${config.version}/`;\r\n\r\n log(\r\n 3,\r\n `[cache] Updating cache version to Highcharts: ${hcVersion || 'latest'}.`\r\n );\r\n\r\n // Configure proxy if exists\r\n let proxyAgent;\r\n const proxyHost = process.env['PROXY_SERVER_HOST'];\r\n const proxyPort = process.env['PROXY_SERVER_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 const fetchedModules = {};\r\n try {\r\n cache.sources = await fetchScripts(\r\n [...coreScripts.map((c) => `${hcVersion}${c}`)],\r\n [\r\n ...modules.map((m) =>\r\n m === 'map'\r\n ? `maps/${hcVersion}modules/${m}`\r\n : `${hcVersion}modules/${m}`\r\n ),\r\n ...indicators.map((i) => `stock/${hcVersion}indicators/${i}`)\r\n ],\r\n customScripts,\r\n config.cdnURL || cache.cdnURL,\r\n proxyAgent,\r\n fetchedModules\r\n );\r\n extractVersion();\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 appliedConfig\r\n ? await checkAndUpdateCache(\r\n Object.assign(appliedConfig, {\r\n version: newVersion\r\n })\r\n )\r\n : false;\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} config - Highcharts-related configuration object containing information\r\n * about scripts and modules.\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 (config) => {\r\n const cachePath = join(__dirname, config.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 // TODO: deal with trying to switch to the running version\r\n // const activeVersion = appliedConfig ? appliedConfig.version : false;\r\n\r\n appliedConfig = config;\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) || config.forceFetch) {\r\n log(3, '[cache] Fetching and caching Highcharts dependencies.');\r\n fetchedModules = await updateCache(config, 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 { modules, coreScripts, indicators } = config;\r\n const numberOfModules =\r\n modules.length + coreScripts.length + indicators.length;\r\n\r\n // Compare the loaded 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 !== config.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 = (config.modules || []).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(config, 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 extractVersion();\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(config, fetchedModules);\r\n};\r\n\r\nexport const getCachePath = () => {\r\n return join(__dirname, appliedConfig.cachePath);\r\n};\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 { 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 { 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 modules\r\n if (prompt.name === 'modules') {\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 let numEnvVal;\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) {\r\n // Load the env var\r\n if (entry.type === 'boolean') {\r\n entry.value = toBoolean(\r\n [process.env[entry.envLink], entry.value].find(\r\n (el) => el || el === 'false'\r\n )\r\n );\r\n } else if (entry.type === 'number') {\r\n numEnvVal = +process.env[entry.envLink];\r\n entry.value = numEnvVal >= 0 ? numEnvVal : entry.value;\r\n } else if (entry.type.indexOf(']') >= 0 && process.env[entry.envLink]) {\r\n entry.value = process.env[entry.envLink].split(',');\r\n } else {\r\n entry.value = process.env[entry.envLink] || entry.value;\r\n }\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\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 });\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 log(4, '[browser] Closed the browser.');\r\n }\r\n return true;\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 (exportOptions.type === 'png' || exportOptions.type === 'jpeg') {\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 Highcarts 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\nlet performedExports = 0;\r\nlet exportAttempts = 0;\r\nlet timeSpent = 0;\r\nlet droppedExports = 0;\r\nlet spentAverage = 0;\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 // Attach process' exit listeners\r\n if (poolConfig.listenToProcessExits) {\r\n attachProcessExitListeners();\r\n }\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 // Close browser if for some reason cannot establish the pool\r\n await browserClose();\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 * 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\nexport function attachProcessExitListeners() {\r\n log(3, '[pool] Attaching exit listeners to the process.');\r\n\r\n // Kill all pool resources on exit\r\n process.on('exit', async (code) => {\r\n log(4, `Process exited with code ${code}.`);\r\n await killPool();\r\n });\r\n\r\n // Handler for the SIGINT\r\n process.on('SIGINT', (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n process.exit(1);\r\n });\r\n\r\n // Handler for the SIGTERM\r\n process.on('SIGTERM', (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n process.exit(1);\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 killPool();\r\n process.exit(1);\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 all pool workers and browser, if any exist.');\r\n\r\n // Return true when the pool is already destroyed\r\n if (pool?.destroyed) {\r\n // Close the browser instance if still connected\r\n return browserClose();\r\n }\r\n\r\n // If still alive, destroy the pool of pages before closing a browser\r\n if (pool) {\r\n await pool.destroy();\r\n log(4, '[browser] Destroyed the pool of resources.');\r\n }\r\n\r\n // Close the browser instance\r\n return 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 ++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 timeSpent += exportTime;\r\n spentAverage = timeSpent / ++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 ++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 function getPool() {\r\n return pool;\r\n}\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 workAttempts: () => exportAttempts,\r\n droppedWork: () => droppedExports,\r\n averageTime: () => spentAverage,\r\n processedWorkCount: () => performedExports\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 } 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\n\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 return exportAsString(options.payload.svg.trim(), options, endCallback);\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 Buffer.from(info.result, 'base64')\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 the pool\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","import { 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 (process.env.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\n\r\nimport cache from '../../cache.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\n/**\r\n * Adds the GET /health route, which outputs basic stats for the server.\r\n */\r\nexport default (app) =>\r\n !app\r\n ? false\r\n : app.get('/health', (request, response) => {\r\n response.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: pool.averageTime(),\r\n performedExports: pool.processedWorkCount(),\r\n failedExports: pool.droppedWork(),\r\n exportAttempts: pool.workAttempts(),\r\n sucessRatio: (pool.processedWorkCount() / pool.workAttempts()) * 100,\r\n // eslint-disable-next-line import/no-named-as-default-member\r\n pool: pool.getPoolInfoJSON()\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 { log, logWithStack } from '../logger.js';\r\nimport rateLimit from './rate_limit.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// 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 attachErrorHandlers = (server) => {\r\n server.on('clientError', (error) => {\r\n logWithStack(1, error, `[server] Client error: ${error.message}`);\r\n });\r\n server.on('error', (error) => {\r\n logWithStack(1, error, `[server] Server error: ${error.message}`);\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 attachErrorHandlers(httpServer);\r\n\r\n // Listen\r\n httpServer.listen(serverConfig.port, serverConfig.host);\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(app);\r\n\r\n // Attach error handlers and listen to the server\r\n attachErrorHandlers(httpsServer);\r\n\r\n // Listen\r\n httpsServer.listen(serverConfig.ssl.port, serverConfig.host);\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 * 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 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\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 = process.env.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 '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 server, { startServer } from './server/server.js';\r\nimport { printLogo, printUsage } from './utils.js';\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 // Check if cache needs to be updated\r\n await checkAndUpdateCache(options.highcharts || { version: 'latest' });\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 setOptions,\r\n\r\n // Exporting\r\n initExport,\r\n singleExport,\r\n batchExport,\r\n startExport,\r\n killPool,\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":["async","fetch","url","requestOptions","Promise","resolve","reject","protocol","startsWith","https","http","getProtocol","get","res","data","on","chunk","text","error","dotenv","config","defaultConfig","puppeteer","args","value","type","description","highcharts","version","envLink","cdnURL","coreScripts","modules","indicators","scripts","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","ssl","force","certPath","rateLimiting","maxRequests","window","delay","trustProxy","skipKey","skipToken","pool","minWorkers","maxWorkers","workLimit","acquireTimeout","createTimeout","destroyTimeout","idleTimeout","createRetryInterval","reaperInterval","listenToProcessExits","logging","level","file","dest","ui","route","other","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","colors","toConsole","toFile","pathCreated","levelsDesc","title","color","listeners","key","option","entries","logToFile","texts","prefix","existsSync","mkdirSync","appendFile","concat","console","log","newLevel","length","Date","toString","split","trim","fn","apply","logWithStack","customMessage","mainMessage","stackMessage","stack","slice","setLogLevel","enableFileLogging","logDest","logFile","endsWith","__dirname","fileURLToPath","URL","fixType","formats","outType","pop","find","t","handleResources","allowedProps","handledResources","correctResources","isCorrectJSON","readFileSync","files","propName","map","item","parsedData","JSON","parse","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","process","hrtime","bigint","Number","ExportError","Error","constructor","super","this","setError","statusCode","cache","activeManifest","sources","hcVersion","appliedConfig","extractVersion","indexOf","fetchAndProcessScript","script","proxyAgent","fetchedModules","shouldThrowError","agent","timeout","env","response","updateCache","sourcePath","customScripts","proxyHost","proxyPort","HttpsProxyAgent","moduleScripts","allFetchPromises","all","fetchScripts","c","m","writeFileSync","checkAndUpdateCache","manifestPath","requestUpdate","manifest","moduleMap","numberOfModules","some","moduleName","newManifest","saveConfigToManifest","getCachePath","cache$1","newVersion","assign","generalOptions","getOptions","mergeConfigOptions","newOptions","mergedOptions","updateDefaultConfig","configObj","customObj","customValue","numEnvVal","el","initOptions","items","recursiveProps","objectToUpdate","nestedNames","shift","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","close","isConnected","__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","parseFloat","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","puppeteerArgs","performedExports","exportAttempts","timeSpent","droppedExports","spentAverage","poolConfig","factory","create","id","uuid","startDate","getTime","browserNewPage","isClosed","workCount","random","validate","workerHandle","initPool","code","killPool","exit","allArgs","tryCount","open","launch","headless","userDataDir","createBrowser","parseInt","Pool","acquireTimeoutMillis","createTimeoutMillis","destroyTimeoutMillis","idleTimeoutMillis","createRetryIntervalMillis","reapIntervalMillis","propagateCreateError","resource","eventId","initialResources","acquire","promise","release","browserClose","destroyed","postWork","getPoolInfo","acquireCounter","payload","requestId","workStart","exportCounter","result","exportTime","numFree","numUsed","numPendingAcquires","pool$1","available","inUse","pendingAcquire","startExport","settings","endCallback","svg","initExportSettings","exportAsString","doStraightInject","doExport","findChartSize","exporting","precision","multiplier","pow","roundNumber","sourceHeight","sourceWidth","param","chartJson","customLogicOptions","allowCodeExecutionScoped","enabled","optionsName","stringToExport","chartJSON","logErrorMiddleware","req","next","NODE_ENV","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","ipRegEx","isPrivateRangeUrlFound","info","removeAllListeners","Buffer","from","header","attachment","params","filename","pkgFile","pather","serverStartTime","express","disable","cors","storage","multer","memoryStorage","upload","limits","fieldSize","limit","urlencoded","extended","none","attachErrorHandlers","startServer","serverConfig","httpServer","createServer","listen","cert","fsPromises","readFile","posix","httpsServer","NaN","static","bootTime","uptime","floor","highchartsVersion","averageProcessingTime","failedExports","sucessRatio","healthRoute","post","exportRoutes","sendFile","uiRoute","adminToken","HIGHCHARTS_ADMIN_TOKEN","token","vSwitchRoute","errorHandler","enableRateLimiting","getExpress","getApp","middlewares","index","setOptions","userOptions","configIndex","findIndex","arg","fileName","loadConfigFile","showUsage","propertiesChain","argumentType","reduce","prop","pairArgumentValue","initExport","initLogging","singleExport","batchExport","batchFunctions","pair","mapToNewConfig","oldOptions","manualConfig","configFileName","configFile","choice","prompts","onSubmit","p","categories","questionsCounter","allQuestions","section","prompt","answer","module","writeFile","printLogo","packageVersion"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.esm.js","sources":["../lib/fetch.js","../lib/schemas/config.js","../lib/logger.js","../lib/utils.js","../lib/errors/ExportError.js","../lib/cache.js","../lib/config.js","../lib/browser.js","../lib/export.js","../templates/svg_export/svg_export.js","../lib/pool.js","../lib/chart.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/index.js"],"sourcesContent":["/**\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","/*******************************************************************************\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// 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 envLink: 'HIGHCHARTS_VERSION',\r\n type: 'string',\r\n description: 'The Highcharts version to be used.'\r\n },\r\n cdnURL: {\r\n value: 'https://code.highcharts.com/',\r\n envLink: 'HIGHCHARTS_CDN_URL',\r\n type: 'string',\r\n description: 'The CDN URL for Highcharts scripts to be used.'\r\n },\r\n coreScripts: {\r\n envLink: 'HIGHCHARTS_CORE_SCRIPTS',\r\n value: ['highcharts', 'highcharts-more', 'highcharts-3d'],\r\n type: 'string[]',\r\n description: 'The core Highcharts scripts to fetch.'\r\n },\r\n modules: {\r\n envLink: 'HIGHCHARTS_MODULES',\r\n value: [\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 type: 'string[]',\r\n description: 'The modules of Highcharts to fetch.'\r\n },\r\n indicators: {\r\n envLink: 'HIGHCHARTS_INDICATORS',\r\n value: ['indicators-all'],\r\n type: 'string[]',\r\n description: 'The indicators of Highcharts to fetch.'\r\n },\r\n scripts: {\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 optional scripts or dependencies to fetch.'\r\n },\r\n forceFetch: {\r\n envLink: 'HIGHCHARTS_FORCE_FETCH',\r\n value: false,\r\n type: 'boolean',\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 envLink: 'HIGHCHARTS_CACHE_PATH',\r\n value: '.cache',\r\n type: 'string',\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 envLink: 'EXPORT_TYPE',\r\n value: 'png',\r\n type: 'string',\r\n description: 'The file export format. It can be jpeg, png, pdf, or svg.'\r\n },\r\n constr: {\r\n envLink: 'EXPORT_CONSTR',\r\n value: 'chart',\r\n type: 'string',\r\n description:\r\n 'The constructor to use. Can be chart, stockChart, mapChart, or ganttChart.'\r\n },\r\n defaultHeight: {\r\n envLink: 'EXPORT_DEFAULT_HEIGHT',\r\n value: 400,\r\n type: 'number',\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 envLink: 'EXPORT_DEFAULT_WIDTH',\r\n value: 600,\r\n type: 'number',\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 envLink: 'EXPORT_DEFAULT_SCALE',\r\n value: 1,\r\n type: 'number',\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 type: 'number',\r\n value: false,\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 type: 'number',\r\n value: false,\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 envLink: 'EXPORT_RASTERIZATION_TIMEOUT',\r\n value: 1500,\r\n type: 'number',\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 envLink: 'CUSTOM_LOGIC_ALLOW_CODE_EXECUTION',\r\n value: false,\r\n type: 'boolean',\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 envLink: 'CUSTOM_LOGIC_ALLOW_FILE_RESOURCES',\r\n value: false,\r\n type: 'boolean',\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 envLink: 'SERVER_ENABLE',\r\n value: false,\r\n type: 'boolean',\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 envLink: 'SERVER_HOST',\r\n value: '0.0.0.0',\r\n type: 'string',\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 envLink: 'SERVER_PORT',\r\n value: 7801,\r\n type: 'number',\r\n description: 'The server port when enabled.'\r\n },\r\n benchmarking: {\r\n envLink: 'SERVER_BENCHMARKING',\r\n value: false,\r\n type: 'boolean',\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 ssl: {\r\n enable: {\r\n envLink: 'SERVER_SSL_ENABLE',\r\n value: false,\r\n type: 'boolean',\r\n cliName: 'enableSsl',\r\n description: 'Enables or disables the SSL protocol.'\r\n },\r\n force: {\r\n envLink: 'SERVER_SSL_FORCE',\r\n value: false,\r\n type: 'boolean',\r\n cliName: 'sslForced',\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 envLink: 'SERVER_SSL_PORT',\r\n value: 443,\r\n type: 'number',\r\n cliName: 'sslPort',\r\n description: 'The port on which to run the SSL server.'\r\n },\r\n certPath: {\r\n envLink: 'SERVER_SSL_CERT_PATH',\r\n value: '',\r\n type: 'string',\r\n legacyName: 'sslPath',\r\n description: 'The path to the SSL certificate/key file.'\r\n }\r\n },\r\n rateLimiting: {\r\n enable: {\r\n envLink: 'SERVER_RATE_LIMITING_ENABLE',\r\n value: false,\r\n type: 'boolean',\r\n cliName: 'enableRateLimiting',\r\n description: 'Enables rate limiting for the server.'\r\n },\r\n maxRequests: {\r\n envLink: 'SERVER_RATE_LIMITING_MAX_REQUESTS',\r\n value: 10,\r\n type: 'number',\r\n legacyName: 'rateLimit',\r\n description: 'The maximum number of requests allowed in one minute.'\r\n },\r\n window: {\r\n envLink: 'SERVER_RATE_LIMITING_WINDOW',\r\n value: 1,\r\n type: 'number',\r\n description: 'The time window, in minutes, for the rate limiting.'\r\n },\r\n delay: {\r\n envLink: 'SERVER_RATE_LIMITING_DELAY',\r\n value: 0,\r\n type: 'number',\r\n description:\r\n 'The delay duration for each successive request before reaching the maximum limit.'\r\n },\r\n trustProxy: {\r\n envLink: 'SERVER_RATE_LIMITING_TRUST_PROXY',\r\n value: false,\r\n type: 'boolean',\r\n description: 'Set this to true if the server is behind a load balancer.'\r\n },\r\n skipKey: {\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_KEY',\r\n value: '',\r\n type: 'string',\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 envLink: 'SERVER_RATE_LIMITING_SKIP_TOKEN',\r\n value: '',\r\n type: 'string',\r\n description:\r\n 'Allows bypassing the rate limiter and should be provided with the skipKey argument.'\r\n }\r\n }\r\n },\r\n pool: {\r\n minWorkers: {\r\n envLink: 'POOL_MIN_WORKERS',\r\n value: 4,\r\n type: 'number',\r\n description: 'The number of minimum and initial pool workers to spawn.'\r\n },\r\n maxWorkers: {\r\n envLink: 'POOL_MAX_WORKERS',\r\n value: 8,\r\n type: 'number',\r\n legacyName: 'workers',\r\n description: 'The number of maximum pool workers to spawn.'\r\n },\r\n workLimit: {\r\n envLink: 'POOL_WORK_LIMIT',\r\n value: 40,\r\n type: 'number',\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 envLink: 'POOL_ACQUIRE_TIMEOUT',\r\n value: 5000,\r\n type: 'number',\r\n description:\r\n 'The duration, in milliseconds, to wait for acquiring a resource.'\r\n },\r\n createTimeout: {\r\n envLink: 'POOL_CREATE_TIMEOUT',\r\n value: 5000,\r\n type: 'number',\r\n description:\r\n 'The duration, in milliseconds, to wait for creating a resource.'\r\n },\r\n destroyTimeout: {\r\n envLink: 'POOL_DESTROY_TIMEOUT',\r\n value: 5000,\r\n type: 'number',\r\n description:\r\n 'The duration, in milliseconds, to wait for destroying a resource.'\r\n },\r\n idleTimeout: {\r\n envLink: 'POOL_IDLE_TIMEOUT',\r\n value: 30000,\r\n type: 'number',\r\n description:\r\n 'The duration, in milliseconds, after which an idle resource is destroyed.'\r\n },\r\n createRetryInterval: {\r\n envLink: 'POOL_CREATE_RETRY_INTERVAL',\r\n value: 200,\r\n type: 'number',\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 envLink: 'POOL_REAPER_INTERVAL',\r\n value: 1000,\r\n type: 'number',\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 envLink: 'POOL_BENCHMARKING',\r\n value: false,\r\n type: 'boolean',\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 listenToProcessExits: {\r\n envLink: 'POOL_LISTEN_TO_PROCESS_EXITS',\r\n value: true,\r\n type: 'boolean',\r\n description: 'Decides whether or not to attach process.exit handlers.'\r\n }\r\n },\r\n logging: {\r\n level: {\r\n envLink: 'LOGGING_LEVEL',\r\n value: 4,\r\n type: 'number',\r\n cliName: 'logLevel',\r\n description: 'The logging level to be used.'\r\n },\r\n file: {\r\n envLink: 'LOGGING_FILE',\r\n value: 'highcharts-export-server.log',\r\n type: 'string',\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 envLink: 'LOGGING_DEST',\r\n value: 'log/',\r\n type: 'string',\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 envLink: 'UI_ENABLE',\r\n value: false,\r\n type: 'boolean',\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 envLink: 'UI_ROUTE',\r\n value: '/',\r\n type: 'string',\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 noLogo: {\r\n envLink: 'OTHER_NO_LOGO',\r\n value: false,\r\n type: 'boolean',\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: 'modules',\r\n message: 'Available modules',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n choices: defaultConfig.highcharts.modules.value\r\n },\r\n {\r\n type: 'list',\r\n name: 'scripts',\r\n message: 'Custom scripts',\r\n initial: defaultConfig.highcharts.scripts.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: '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 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 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 type: 'toggle',\r\n name: 'listenToProcessExits',\r\n message: 'Set to false to skip attaching process.exit handlers',\r\n initial: defaultConfig.pool.listenToProcessExits.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: '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\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 // Check if extension has a correct type\r\n 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.\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' && item !== null && 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 return [\r\n 'localhost',\r\n '(10).(.*).(.*).(.*)',\r\n '(127).(.*).(.*).(.*)',\r\n '(172).(1[6-9]|2[0-9]|3[0-1]).(.*).(.*)',\r\n '(192).(168).(.*).(.*)'\r\n ].some((ipRegEx) =>\r\n item.match(`xlink:href=\"(?:(http://|https://))?${ipRegEx}`)\r\n );\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","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 { 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// TODO: The config should be accesssible globally so we don't have to do this sort of thing..\r\nlet appliedConfig = false;\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\nconst extractVersion = () =>\r\n (cache.hcVersion = 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 * Extracts the Highcharts module name based on the scriptPath.\r\n */\r\nconst 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\nconst 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} proxyAgent - The proxy agent to use for a request.\r\n * @param {Object} fetchedModules - An object which tracks which Highcharts modules have been fetched.\r\n * @param {boolean} shouldThrowError - A flag to indicate if the error should be 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\nconst fetchAndProcessScript = async (\r\n script,\r\n proxyAgent,\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 // If exists, add proxy agent to request options\r\n const requestOptions = proxyAgent\r\n ? {\r\n agent: proxyAgent,\r\n timeout: +process.env['PROXY_SERVER_TIMEOUT'] || 5000\r\n }\r\n : {};\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} scripts - Array of Highcharts modules to fetch.\r\n * @param {string} customScripts - Array of custom script paths to fetch (full URLs).\r\n * @param {object} proxyAgent - The proxy agent to use for a request.\r\n * @param {object} fetchedModules - An object which tracks which Highcharts modules have been fetched.\r\n * @returns {Promise} The fetched scripts content joined.\r\n */\r\nconst fetchScripts = async (\r\n coreScripts,\r\n moduleScripts,\r\n customScripts,\r\n cdnURL,\r\n proxyAgent,\r\n fetchedModules\r\n) => {\r\n const allFetchPromises = [\r\n ...coreScripts.map((script) =>\r\n fetchAndProcessScript(\r\n `${cdnURL}${script}`,\r\n proxyAgent,\r\n fetchedModules,\r\n true\r\n )\r\n ),\r\n ...moduleScripts.map((script) =>\r\n fetchAndProcessScript(`${cdnURL}${script}`, proxyAgent, fetchedModules)\r\n ),\r\n ...customScripts.map((script) =>\r\n fetchAndProcessScript(`${script}`, proxyAgent)\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} config - The configuration object containing information\r\n * about scripts and modules.\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\nconst updateCache = async (config, sourcePath) => {\r\n const { coreScripts, modules, indicators, scripts: customScripts } = config;\r\n const hcVersion =\r\n config.version === 'latest' || !config.version ? '' : `${config.version}/`;\r\n\r\n log(\r\n 3,\r\n `[cache] Updating cache version to Highcharts: ${hcVersion || 'latest'}.`\r\n );\r\n\r\n // Configure proxy if exists\r\n let proxyAgent;\r\n const proxyHost = process.env['PROXY_SERVER_HOST'];\r\n const proxyPort = process.env['PROXY_SERVER_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 const fetchedModules = {};\r\n try {\r\n cache.sources = await fetchScripts(\r\n [...coreScripts.map((c) => `${hcVersion}${c}`)],\r\n [\r\n ...modules.map((m) =>\r\n m === 'map'\r\n ? `maps/${hcVersion}modules/${m}`\r\n : `${hcVersion}modules/${m}`\r\n ),\r\n ...indicators.map((i) => `stock/${hcVersion}indicators/${i}`)\r\n ],\r\n customScripts,\r\n config.cdnURL || cache.cdnURL,\r\n proxyAgent,\r\n fetchedModules\r\n );\r\n extractVersion();\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 appliedConfig\r\n ? await checkAndUpdateCache(\r\n Object.assign(appliedConfig, {\r\n version: newVersion\r\n })\r\n )\r\n : false;\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} config - Highcharts-related configuration object containing information\r\n * about scripts and modules.\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 (config) => {\r\n const cachePath = join(__dirname, config.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 // TODO: deal with trying to switch to the running version\r\n // const activeVersion = appliedConfig ? appliedConfig.version : false;\r\n\r\n appliedConfig = config;\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) || config.forceFetch) {\r\n log(3, '[cache] Fetching and caching Highcharts dependencies.');\r\n fetchedModules = await updateCache(config, 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 { modules, coreScripts, indicators } = config;\r\n const numberOfModules =\r\n modules.length + coreScripts.length + indicators.length;\r\n\r\n // Compare the loaded 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 !== config.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 = (config.modules || []).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(config, 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 extractVersion();\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(config, fetchedModules);\r\n};\r\n\r\nexport const getCachePath = () => {\r\n return join(__dirname, appliedConfig.cachePath);\r\n};\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 { 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 { 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 modules\r\n if (prompt.name === 'modules') {\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 let numEnvVal;\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) {\r\n // Load the env var\r\n if (entry.type === 'boolean') {\r\n entry.value = toBoolean(\r\n [process.env[entry.envLink], entry.value].find(\r\n (el) => el || el === 'false'\r\n )\r\n );\r\n } else if (entry.type === 'number') {\r\n numEnvVal = +process.env[entry.envLink];\r\n entry.value = numEnvVal >= 0 ? numEnvVal : entry.value;\r\n } else if (entry.type.indexOf(']') >= 0 && process.env[entry.envLink]) {\r\n entry.value = process.env[entry.envLink].split(',');\r\n } else {\r\n entry.value = process.env[entry.envLink] || entry.value;\r\n }\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\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 });\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 log(4, '[browser] Closed the browser.');\r\n }\r\n return true;\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 (exportOptions.type === 'png' || exportOptions.type === 'jpeg') {\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 Highcarts 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\nlet performedExports = 0;\r\nlet exportAttempts = 0;\r\nlet timeSpent = 0;\r\nlet droppedExports = 0;\r\nlet spentAverage = 0;\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 // Attach process' exit listeners\r\n if (poolConfig.listenToProcessExits) {\r\n attachProcessExitListeners();\r\n }\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 // Close browser if for some reason cannot establish the pool\r\n await browserClose();\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 * 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\nexport function attachProcessExitListeners() {\r\n log(3, '[pool] Attaching exit listeners to the process.');\r\n\r\n // Kill all pool resources on exit\r\n process.on('exit', async (code) => {\r\n log(4, `Process exited with code ${code}.`);\r\n await killPool();\r\n });\r\n\r\n // Handler for the SIGINT\r\n process.on('SIGINT', (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n process.exit(1);\r\n });\r\n\r\n // Handler for the SIGTERM\r\n process.on('SIGTERM', (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n process.exit(1);\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 killPool();\r\n process.exit(1);\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 all pool workers and browser, if any exist.');\r\n\r\n // Return true when the pool is already destroyed\r\n if (pool?.destroyed) {\r\n // Close the browser instance if still connected\r\n return browserClose();\r\n }\r\n\r\n // If still alive, destroy the pool of pages before closing a browser\r\n if (pool) {\r\n await pool.destroy();\r\n log(4, '[browser] Destroyed the pool of resources.');\r\n }\r\n\r\n // Close the browser instance\r\n return 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 ++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 timeSpent += exportTime;\r\n spentAverage = timeSpent / ++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 ++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 function getPool() {\r\n return pool;\r\n}\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 workAttempts: () => exportAttempts,\r\n droppedWork: () => droppedExports,\r\n averageTime: () => spentAverage,\r\n processedWorkCount: () => performedExports\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 } 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\n\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 return exportAsString(options.payload.svg.trim(), options, endCallback);\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 Buffer.from(info.result, 'base64')\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 the pool\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","import { 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 (process.env.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\n\r\nimport cache from '../../cache.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\n/**\r\n * Adds the GET /health route, which outputs basic stats for the server.\r\n */\r\nexport default (app) =>\r\n !app\r\n ? false\r\n : app.get('/health', (request, response) => {\r\n response.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: pool.averageTime(),\r\n performedExports: pool.processedWorkCount(),\r\n failedExports: pool.droppedWork(),\r\n exportAttempts: pool.workAttempts(),\r\n sucessRatio: (pool.processedWorkCount() / pool.workAttempts()) * 100,\r\n // eslint-disable-next-line import/no-named-as-default-member\r\n pool: pool.getPoolInfoJSON()\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 { log, logWithStack } from '../logger.js';\r\nimport rateLimit from './rate_limit.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// 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 attachErrorHandlers = (server) => {\r\n server.on('clientError', (error) => {\r\n logWithStack(1, error, `[server] Client error: ${error.message}`);\r\n });\r\n server.on('error', (error) => {\r\n logWithStack(1, error, `[server] Server error: ${error.message}`);\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 attachErrorHandlers(httpServer);\r\n\r\n // Listen\r\n httpServer.listen(serverConfig.port, serverConfig.host);\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(app);\r\n\r\n // Attach error handlers and listen to the server\r\n attachErrorHandlers(httpsServer);\r\n\r\n // Listen\r\n httpsServer.listen(serverConfig.ssl.port, serverConfig.host);\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 * 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 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\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 = process.env.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 'colors';\r\nimport dotenv from 'dotenv';\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 server, { startServer } from './server/server.js';\r\nimport { printLogo, printUsage } from './utils.js';\r\n\r\n// Load .env into environment variables\r\ndotenv.config();\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 // Check if cache needs to be updated\r\n await checkAndUpdateCache(options.highcharts || { version: 'latest' });\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 setOptions,\r\n\r\n // Exporting\r\n initExport,\r\n singleExport,\r\n batchExport,\r\n startExport,\r\n killPool,\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":["async","fetch","url","requestOptions","Promise","resolve","reject","protocol","startsWith","https","http","getProtocol","get","res","data","on","chunk","text","error","defaultConfig","puppeteer","args","value","type","description","highcharts","version","envLink","cdnURL","coreScripts","modules","indicators","scripts","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","ssl","force","certPath","rateLimiting","maxRequests","window","delay","trustProxy","skipKey","skipToken","pool","minWorkers","maxWorkers","workLimit","acquireTimeout","createTimeout","destroyTimeout","idleTimeout","createRetryInterval","reaperInterval","listenToProcessExits","logging","level","file","dest","ui","route","other","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","colors","toConsole","toFile","pathCreated","levelsDesc","title","color","listeners","key","option","entries","logToFile","texts","prefix","existsSync","mkdirSync","appendFile","concat","console","log","newLevel","length","Date","toString","split","trim","fn","apply","logWithStack","customMessage","mainMessage","stackMessage","stack","slice","setLogLevel","enableFileLogging","logDest","logFile","endsWith","__dirname","fileURLToPath","URL","fixType","formats","outType","pop","find","t","handleResources","allowedProps","handledResources","correctResources","isCorrectJSON","readFileSync","files","propName","map","item","parsedData","JSON","parse","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","process","hrtime","bigint","Number","ExportError","Error","constructor","super","this","setError","statusCode","cache","activeManifest","sources","hcVersion","appliedConfig","extractVersion","indexOf","fetchAndProcessScript","script","proxyAgent","fetchedModules","shouldThrowError","agent","timeout","env","response","updateCache","config","sourcePath","customScripts","proxyHost","proxyPort","HttpsProxyAgent","moduleScripts","allFetchPromises","all","fetchScripts","c","m","writeFileSync","checkAndUpdateCache","manifestPath","requestUpdate","manifest","moduleMap","numberOfModules","some","moduleName","newManifest","saveConfigToManifest","getCachePath","cache$1","newVersion","assign","generalOptions","getOptions","mergeConfigOptions","newOptions","mergedOptions","updateDefaultConfig","configObj","customObj","customValue","numEnvVal","el","initOptions","items","recursiveProps","objectToUpdate","nestedNames","shift","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","close","isConnected","__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","parseFloat","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","puppeteerArgs","performedExports","exportAttempts","timeSpent","droppedExports","spentAverage","poolConfig","factory","create","id","uuid","startDate","getTime","browserNewPage","isClosed","workCount","random","validate","workerHandle","initPool","code","killPool","exit","allArgs","tryCount","open","launch","headless","userDataDir","createBrowser","parseInt","Pool","acquireTimeoutMillis","createTimeoutMillis","destroyTimeoutMillis","idleTimeoutMillis","createRetryIntervalMillis","reapIntervalMillis","propagateCreateError","resource","eventId","initialResources","acquire","promise","release","browserClose","destroyed","postWork","getPoolInfo","acquireCounter","payload","requestId","workStart","exportCounter","result","exportTime","numFree","numUsed","numPendingAcquires","pool$1","available","inUse","pendingAcquire","startExport","settings","endCallback","svg","initExportSettings","exportAsString","doStraightInject","doExport","findChartSize","exporting","precision","multiplier","pow","roundNumber","sourceHeight","sourceWidth","param","chartJson","customLogicOptions","allowCodeExecutionScoped","enabled","optionsName","stringToExport","chartJSON","logErrorMiddleware","req","next","NODE_ENV","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","ipRegEx","isPrivateRangeUrlFound","info","removeAllListeners","Buffer","from","header","attachment","params","filename","pkgFile","pather","serverStartTime","express","disable","cors","storage","multer","memoryStorage","upload","limits","fieldSize","limit","urlencoded","extended","none","attachErrorHandlers","startServer","serverConfig","httpServer","createServer","listen","cert","fsPromises","readFile","posix","httpsServer","NaN","static","bootTime","uptime","floor","highchartsVersion","averageProcessingTime","failedExports","sucessRatio","healthRoute","post","exportRoutes","sendFile","uiRoute","adminToken","HIGHCHARTS_ADMIN_TOKEN","token","vSwitchRoute","errorHandler","enableRateLimiting","getExpress","getApp","middlewares","dotenv","index","setOptions","userOptions","configIndex","findIndex","arg","fileName","loadConfigFile","showUsage","propertiesChain","argumentType","reduce","prop","pairArgumentValue","initExport","initLogging","singleExport","batchExport","batchFunctions","pair","mapToNewConfig","oldOptions","manualConfig","configFileName","configFile","choice","prompts","onSubmit","p","categories","questionsCounter","allQuestions","section","prompt","answer","module","writeFile","printLogo","packageVersion"],"mappings":"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"} \ No newline at end of file diff --git a/lib/cache.js b/lib/cache.js index e1e24093..c6b803c2 100644 --- a/lib/cache.js +++ b/lib/cache.js @@ -19,7 +19,6 @@ See LICENSE file in root for details. import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs'; import { join } from 'path'; -import dotenv from 'dotenv'; import { HttpsProxyAgent } from 'https-proxy-agent'; import { fetch } from './fetch.js'; @@ -28,8 +27,6 @@ import { __dirname } from './utils.js'; import ExportError from './errors/ExportError.js'; -dotenv.config(); - const cache = { cdnURL: 'https://code.highcharts.com/', activeManifest: {}, @@ -53,7 +50,6 @@ const extractVersion = () => .replace(/\n/g, '') .trim()); - /** * Extracts the Highcharts module name based on the scriptPath. */ diff --git a/lib/index.js b/lib/index.js index 51bfe8c6..fb4cb82c 100644 --- a/lib/index.js +++ b/lib/index.js @@ -13,6 +13,7 @@ See LICENSE file in root for details. *******************************************************************************/ import 'colors'; +import dotenv from 'dotenv'; import { checkAndUpdateCache } from './cache.js'; import { @@ -33,6 +34,9 @@ import { initPool, killPool } from './pool.js'; import server, { startServer } from './server/server.js'; import { printLogo, printUsage } from './utils.js'; +// Load .env into environment variables +dotenv.config(); + /** * Initializes the export process. Tasks such as configuring logging, checking * cache and sources, and initializing the pool of resources happen during diff --git a/lib/schemas/config.js b/lib/schemas/config.js index 113f5c37..535d2b8f 100644 --- a/lib/schemas/config.js +++ b/lib/schemas/config.js @@ -12,11 +12,6 @@ See LICENSE file in root for details. *******************************************************************************/ -// Load .env into environment variables -import dotenv from 'dotenv'; - -dotenv.config(); - // This is the configuration object with all options and their default values, // also from the .env file if one exists export const defaultConfig = { diff --git a/nodemon.json b/nodemon.json new file mode 100644 index 00000000..bb40e239 --- /dev/null +++ b/nodemon.json @@ -0,0 +1,7 @@ +{ + "verbose": true, + "restartable": "rs", + "ext": ".ts,.js,.json", + "watch": ["bin/", "lib/"], + "ignore": ["node_modules/**/node_modules"] +} diff --git a/package-lock.json b/package-lock.json index a763ec3f..1e67b5c1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,7 +18,7 @@ "https-proxy-agent": "^7.0.4", "multer": "^1.4.5-lts.1", "prompts": "^2.4.2", - "puppeteer": "^22.4.0", + "puppeteer": "^22.6.2", "tarn": "^3.0.2", "uuid": "^9.0.1" }, @@ -33,8 +33,9 @@ "eslint-plugin-prettier": "^5.1.3", "husky": "^9.0.11", "lint-staged": "^15.2.2", + "nodemon": "^3.1.0", "prettier": "^3.2.5", - "rollup": "^4.12.1" + "rollup": "^4.14.0" }, "engines": { "node": ">=16.14.0" @@ -405,9 +406,9 @@ } }, "node_modules/@puppeteer/browsers": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.1.0.tgz", - "integrity": "sha512-xloWvocjvryHdUjDam/ZuGMh7zn4Sn3ZAaV4Ah2e2EwEt90N3XphZlSsU3n0VDc1F7kggCjMuH0UuxfPQ5mD9w==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.2.0.tgz", + "integrity": "sha512-MC7LxpcBtdfTbzwARXIkqGZ1Osn3nnZJlm+i0+VqHl72t//Xwl9wICrXT8BwtgC6s1xJNHsxOpvzISUqe92+sw==", "dependencies": { "debug": "4.3.4", "extract-zip": "2.0.1", @@ -473,9 +474,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.12.1.tgz", - "integrity": "sha512-iU2Sya8hNn1LhsYyf0N+L4Gf9Qc+9eBTJJJsaOGUp+7x4n2M9dxTt8UvhJl3oeftSjblSlpCfvjA/IfP3g5VjQ==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.14.0.tgz", + "integrity": "sha512-jwXtxYbRt1V+CdQSy6Z+uZti7JF5irRKF8hlKfEnF/xJpcNGuuiZMBvuoYM+x9sr9iWGnzrlM0+9hvQ1kgkf1w==", "cpu": [ "arm" ], @@ -486,9 +487,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.12.1.tgz", - "integrity": "sha512-wlzcWiH2Ir7rdMELxFE5vuM7D6TsOcJ2Yw0c3vaBR3VOsJFVTx9xvwnAvhgU5Ii8Gd6+I11qNHwndDscIm0HXg==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.14.0.tgz", + "integrity": "sha512-fI9nduZhCccjzlsA/OuAwtFGWocxA4gqXGTLvOyiF8d+8o0fZUeSztixkYjcGq1fGZY3Tkq4yRvHPFxU+jdZ9Q==", "cpu": [ "arm64" ], @@ -499,9 +500,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.12.1.tgz", - "integrity": "sha512-YRXa1+aZIFN5BaImK+84B3uNK8C6+ynKLPgvn29X9s0LTVCByp54TB7tdSMHDR7GTV39bz1lOmlLDuedgTwwHg==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.14.0.tgz", + "integrity": "sha512-BcnSPRM76/cD2gQC+rQNGBN6GStBs2pl/FpweW8JYuz5J/IEa0Fr4AtrPv766DB/6b2MZ/AfSIOSGw3nEIP8SA==", "cpu": [ "arm64" ], @@ -512,9 +513,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.12.1.tgz", - "integrity": "sha512-opjWJ4MevxeA8FhlngQWPBOvVWYNPFkq6/25rGgG+KOy0r8clYwL1CFd+PGwRqqMFVQ4/Qd3sQu5t7ucP7C/Uw==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.14.0.tgz", + "integrity": "sha512-LDyFB9GRolGN7XI6955aFeI3wCdCUszFWumWU0deHA8VpR3nWRrjG6GtGjBrQxQKFevnUTHKCfPR4IvrW3kCgQ==", "cpu": [ "x64" ], @@ -525,9 +526,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.12.1.tgz", - "integrity": "sha512-uBkwaI+gBUlIe+EfbNnY5xNyXuhZbDSx2nzzW8tRMjUmpScd6lCQYKY2V9BATHtv5Ef2OBq6SChEP8h+/cxifQ==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.14.0.tgz", + "integrity": "sha512-ygrGVhQP47mRh0AAD0zl6QqCbNsf0eTo+vgwkY6LunBcg0f2Jv365GXlDUECIyoXp1kKwL5WW6rsO429DBY/bA==", "cpu": [ "arm" ], @@ -538,9 +539,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.12.1.tgz", - "integrity": "sha512-0bK9aG1kIg0Su7OcFTlexkVeNZ5IzEsnz1ept87a0TUgZ6HplSgkJAnFpEVRW7GRcikT4GlPV0pbtVedOaXHQQ==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.14.0.tgz", + "integrity": "sha512-x+uJ6MAYRlHGe9wi4HQjxpaKHPM3d3JjqqCkeC5gpnnI6OWovLdXTpfa8trjxPLnWKyBsSi5kne+146GAxFt4A==", "cpu": [ "arm64" ], @@ -551,9 +552,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.12.1.tgz", - "integrity": "sha512-qB6AFRXuP8bdkBI4D7UPUbE7OQf7u5OL+R94JE42Z2Qjmyj74FtDdLGeriRyBDhm4rQSvqAGCGC01b8Fu2LthQ==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.14.0.tgz", + "integrity": "sha512-nrRw8ZTQKg6+Lttwqo6a2VxR9tOroa2m91XbdQ2sUUzHoedXlsyvY1fN4xWdqz8PKmf4orDwejxXHjh7YBGUCA==", "cpu": [ "arm64" ], @@ -563,10 +564,23 @@ "linux" ] }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.14.0.tgz", + "integrity": "sha512-xV0d5jDb4aFu84XKr+lcUJ9y3qpIWhttO3Qev97z8DKLXR62LC3cXT/bMZXrjLF9X+P5oSmJTzAhqwUbY96PnA==", + "cpu": [ + "ppc64le" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.12.1.tgz", - "integrity": "sha512-sHig3LaGlpNgDj5o8uPEoGs98RII8HpNIqFtAI8/pYABO8i0nb1QzT0JDoXF/pxzqO+FkxvwkHZo9k0NJYDedg==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.14.0.tgz", + "integrity": "sha512-SDDhBQwZX6LPRoPYjAZWyL27LbcBo7WdBFWJi5PI9RPCzU8ijzkQn7tt8NXiXRiFMJCVpkuMkBf4OxSxVMizAw==", "cpu": [ "riscv64" ], @@ -576,10 +590,23 @@ "linux" ] }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.14.0.tgz", + "integrity": "sha512-RxB/qez8zIDshNJDufYlTT0ZTVut5eCpAZ3bdXDU9yTxBzui3KhbGjROK2OYTTor7alM7XBhssgoO3CZ0XD3qA==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.12.1.tgz", - "integrity": "sha512-nD3YcUv6jBJbBNFvSbp0IV66+ba/1teuBcu+fBBPZ33sidxitc6ErhON3JNavaH8HlswhWMC3s5rgZpM4MtPqQ==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.14.0.tgz", + "integrity": "sha512-C6y6z2eCNCfhZxT9u+jAM2Fup89ZjiG5pIzZIDycs1IwESviLxwkQcFRGLjnDrP+PT+v5i4YFvlcfAs+LnreXg==", "cpu": [ "x64" ], @@ -590,9 +617,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.12.1.tgz", - "integrity": "sha512-7/XVZqgBby2qp/cO0TQ8uJK+9xnSdJ9ct6gSDdEr4MfABrjTyrW6Bau7HQ73a2a5tPB7hno49A0y1jhWGDN9OQ==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.14.0.tgz", + "integrity": "sha512-i0QwbHYfnOMYsBEyjxcwGu5SMIi9sImDVjDg087hpzXqhBSosxkE7gyIYFHgfFl4mr7RrXksIBZ4DoLoP4FhJg==", "cpu": [ "x64" ], @@ -603,9 +630,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.12.1.tgz", - "integrity": "sha512-CYc64bnICG42UPL7TrhIwsJW4QcKkIt9gGlj21gq3VV0LL6XNb1yAdHVp1pIi9gkts9gGcT3OfUYHjGP7ETAiw==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.14.0.tgz", + "integrity": "sha512-Fq52EYb0riNHLBTAcL0cun+rRwyZ10S9vKzhGKKgeD+XbwunszSY0rVMco5KbOsTlwovP2rTOkiII/fQ4ih/zQ==", "cpu": [ "arm64" ], @@ -616,9 +643,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.12.1.tgz", - "integrity": "sha512-LN+vnlZ9g0qlHGlS920GR4zFCqAwbv2lULrR29yGaWP9u7wF5L7GqWu9Ah6/kFZPXPUkpdZwd//TNR+9XC9hvA==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.14.0.tgz", + "integrity": "sha512-e/PBHxPdJ00O9p5Ui43+vixSgVf4NlLsmV6QneGERJ3lnjIua/kim6PRFe3iDueT1rQcgSkYP8ZBBXa/h4iPvw==", "cpu": [ "ia32" ], @@ -629,9 +656,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.12.1.tgz", - "integrity": "sha512-n+vkrSyphvmU0qkQ6QBNXCGr2mKjhP08mPRM/Xp5Ck2FV4NrHU+y6axzDeixUrCBHVUS51TZhjqrKBBsHLKb2Q==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.14.0.tgz", + "integrity": "sha512-aGg7iToJjdklmxlUlJh/PaPNa4PmqHfyRMLunbL3eaMO0gp656+q1zOKkpJ/CVe9CryJv6tAN1HDoR8cNGzkag==", "cpu": [ "x64" ], @@ -659,9 +686,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.11.25", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.25.tgz", - "integrity": "sha512-TBHyJxk2b7HceLVGFcpAUjsa5zIdsPWlR6XHfyGzd0SFu+/NFgQgMAl96MSDZgQDvJAvV6BKsFOrt6zIL09JDw==", + "version": "20.12.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.2.tgz", + "integrity": "sha512-zQ0NYO87hyN6Xrclcqp7f8ZbXNbRfoGWNcMvHTPQp9UUrwI0mI7XBz+cu7/W6/VClYo2g63B0cjull/srU7LgQ==", "optional": true, "dependencies": { "undici-types": "~5.26.4" @@ -682,6 +709,12 @@ "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", @@ -716,9 +749,9 @@ } }, "node_modules/agent-base": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", - "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", "dependencies": { "debug": "^4.3.4" }, @@ -791,6 +824,19 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/append-field": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", @@ -975,15 +1021,15 @@ "dev": true }, "node_modules/bare-events": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.2.1.tgz", - "integrity": "sha512-9GYPpsPFvrWBkelIhOhTWtkeZxVxZOdb3VnFTCzlOo3OjvmTvzLoZFUT8kNFACx0vJej6QPney1Cf9BvzCNE/A==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.2.2.tgz", + "integrity": "sha512-h7z00dWdG0PYOQEvChhOSWvOfkIKsdZGkWr083FgN/HyoQuebSew/cgirYqh9SCuy/hRvxc5Vy6Fw8xAmYHLkQ==", "optional": true }, "node_modules/bare-fs": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-2.2.1.tgz", - "integrity": "sha512-+CjmZANQDFZWy4PGbVdmALIwmt33aJg8qTkVjClU6X4WmZkTPBDxRHiBn7fpqEWEfF3AC2io++erpViAIQbSjg==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-2.2.2.tgz", + "integrity": "sha512-X9IqgvyB0/VA5OZJyb5ZstoN62AzD7YxVGog13kkfYWYqJYcK0kcqLZ6TrmH5qr4/8//ejVcX4x/a0UvaogXmA==", "optional": true, "dependencies": { "bare-events": "^2.0.0", @@ -993,9 +1039,9 @@ } }, "node_modules/bare-os": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-2.2.0.tgz", - "integrity": "sha512-hD0rOPfYWOMpVirTACt4/nK8mC55La12K5fY1ij8HAdfQakD62M+H4o4tpfKzVGLgRDTuk3vjA4GqGXXCeFbag==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-2.2.1.tgz", + "integrity": "sha512-OwPyHgBBMkhC29Hl3O4/YfxW9n7mdTr2+SsO29XBWKKJsbgj3mnorDB80r5TiCQgQstgE5ga1qNYrpes6NvX2w==", "optional": true }, "node_modules/bare-path": { @@ -1034,6 +1080,18 @@ "node": ">=10.0.0" } }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/body-parser": { "version": "1.20.2", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", @@ -1189,13 +1247,50 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/chromium-bidi": { - "version": "0.5.12", - "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.5.12.tgz", - "integrity": "sha512-sZMgEBWKbupD0Q7lyFu8AWkrE+rs5ycE12jFkGwIgD/VS8lDPtelPlXM7LYaq4zrkZ/O2L3f4afHUHL0ICdKog==", + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.5.16.tgz", + "integrity": "sha512-IT5lnR44h/qZQ4GaCHvBxYIl4cQL2i9UvFyYeRyVdcpY04hx5H720HQfe/7Oz7ndxaYVLQFGpCO71J4X2Ye/Gw==", "dependencies": { "mitt": "3.0.1", - "urlpattern-polyfill": "10.0.0" + "urlpattern-polyfill": "10.0.0", + "zod": "3.22.4" }, "peerDependencies": { "devtools-protocol": "*" @@ -1420,14 +1515,6 @@ } } }, - "node_modules/cross-fetch": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", - "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", - "dependencies": { - "node-fetch": "^2.6.12" - } - }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -1536,9 +1623,9 @@ } }, "node_modules/devtools-protocol": { - "version": "0.0.1249869", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1249869.tgz", - "integrity": "sha512-Ctp4hInA0BEavlUoRy9mhGq0i+JSo/AwVyX2EFgZmV1kYB+Zq+EMBAn52QWu6FbRr10hRb6pBl420upbp4++vg==" + "version": "0.0.1262051", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1262051.tgz", + "integrity": "sha512-YJe4CT5SA8on3Spa+UDtNhEqtuV6Epwz3OZ4HQVLhlRccpZ9/PAYk0/cy/oKxFKRrZPBUPyxympQci4yWNWZ9g==" }, "node_modules/doctrine": { "version": "3.0.0", @@ -2774,6 +2861,12 @@ "node": ">= 4" } }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -2880,6 +2973,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/is-boolean-object": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", @@ -3568,23 +3673,104 @@ "node": ">= 0.4.0" } }, - "node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "node_modules/nodemon": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.0.tgz", + "integrity": "sha512-xqlktYlDMCepBJd43ZQhjWwMw2obW/JRvkrLxq5RCNcuDDX1DbcPT+qT1IlIIdf+DhnWs90JpTMe+Y5KxOchvA==", + "dev": true, "dependencies": { - "whatwg-url": "^5.0.0" + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" }, "engines": { - "node": "4.x || >=6.0.0" + "node": ">=10" }, - "peerDependencies": { - "encoding": "^0.1.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nodemon/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "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" }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } + "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==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/nodemon/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "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", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" } }, "node_modules/npm-run-path": { @@ -4023,6 +4209,12 @@ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true + }, "node_modules/pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -4042,14 +4234,15 @@ } }, "node_modules/puppeteer": { - "version": "22.4.0", - "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-22.4.0.tgz", - "integrity": "sha512-tR+JsDbA2qD1DqRX4F9k9SxQhk6UzcaCN+Qux7+WrDceS7wcR7tlFmMNB8+g8zE4Fmr/iRTOtf5wNnTW9cGUFQ==", + "version": "22.6.2", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-22.6.2.tgz", + "integrity": "sha512-3GMAJ9adPUSdIHGuYV1b1RqRB6D2UScjnq779uZsvpAP6HOWw2+9ezZiUZaAXVST+Ku7KWsxOjkctEvRasJClA==", "hasInstallScript": true, "dependencies": { - "@puppeteer/browsers": "2.1.0", + "@puppeteer/browsers": "2.2.0", "cosmiconfig": "9.0.0", - "puppeteer-core": "22.4.0" + "devtools-protocol": "0.0.1262051", + "puppeteer-core": "22.6.2" }, "bin": { "puppeteer": "lib/esm/puppeteer/node/cli.js" @@ -4059,15 +4252,14 @@ } }, "node_modules/puppeteer-core": { - "version": "22.4.0", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-22.4.0.tgz", - "integrity": "sha512-MZttAbttrxi6O/B//rY6zQihjFe/vXeCLb5YvKH2xG6yrcVESo0Hc5/Cv49omwZyZzAJ1BK8BnDeatDsj+3hMw==", + "version": "22.6.2", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-22.6.2.tgz", + "integrity": "sha512-Sws/9V2/7nFrn3MSsRPHn1pXJMIFn6FWHhoMFMUBXQwVvcBstRIa9yW8sFfxePzb56W1xNfSYzPRnyAd0+qRVQ==", "dependencies": { - "@puppeteer/browsers": "2.1.0", - "chromium-bidi": "0.5.12", - "cross-fetch": "4.0.0", + "@puppeteer/browsers": "2.2.0", + "chromium-bidi": "0.5.16", "debug": "4.3.4", - "devtools-protocol": "0.0.1249869", + "devtools-protocol": "0.0.1262051", "ws": "8.16.0" }, "engines": { @@ -4163,6 +4355,18 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, "node_modules/regexp.prototype.flags": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", @@ -4292,9 +4496,9 @@ } }, "node_modules/rollup": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.12.1.tgz", - "integrity": "sha512-ggqQKvx/PsB0FaWXhIvVkSWh7a/PCLQAsMjBc+nA2M8Rv2/HG0X6zvixAB7KyZBRtifBUhy5k8voQX/mRnABPg==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.14.0.tgz", + "integrity": "sha512-Qe7w62TyawbDzB4yt32R0+AbIo6m1/sqO7UPzFS8Z/ksL5mrfhA0v4CavfdmFav3D+ub4QeAgsGEe84DoWe/nQ==", "dev": true, "dependencies": { "@types/estree": "1.0.5" @@ -4307,19 +4511,21 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.12.1", - "@rollup/rollup-android-arm64": "4.12.1", - "@rollup/rollup-darwin-arm64": "4.12.1", - "@rollup/rollup-darwin-x64": "4.12.1", - "@rollup/rollup-linux-arm-gnueabihf": "4.12.1", - "@rollup/rollup-linux-arm64-gnu": "4.12.1", - "@rollup/rollup-linux-arm64-musl": "4.12.1", - "@rollup/rollup-linux-riscv64-gnu": "4.12.1", - "@rollup/rollup-linux-x64-gnu": "4.12.1", - "@rollup/rollup-linux-x64-musl": "4.12.1", - "@rollup/rollup-win32-arm64-msvc": "4.12.1", - "@rollup/rollup-win32-ia32-msvc": "4.12.1", - "@rollup/rollup-win32-x64-msvc": "4.12.1", + "@rollup/rollup-android-arm-eabi": "4.14.0", + "@rollup/rollup-android-arm64": "4.14.0", + "@rollup/rollup-darwin-arm64": "4.14.0", + "@rollup/rollup-darwin-x64": "4.14.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.14.0", + "@rollup/rollup-linux-arm64-gnu": "4.14.0", + "@rollup/rollup-linux-arm64-musl": "4.14.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.14.0", + "@rollup/rollup-linux-riscv64-gnu": "4.14.0", + "@rollup/rollup-linux-s390x-gnu": "4.14.0", + "@rollup/rollup-linux-x64-gnu": "4.14.0", + "@rollup/rollup-linux-x64-musl": "4.14.0", + "@rollup/rollup-win32-arm64-msvc": "4.14.0", + "@rollup/rollup-win32-ia32-msvc": "4.14.0", + "@rollup/rollup-win32-x64-msvc": "4.14.0", "fsevents": "~2.3.2" } }, @@ -4570,6 +4776,45 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "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==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", @@ -4632,11 +4877,11 @@ } }, "node_modules/socks-proxy-agent": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.2.tgz", - "integrity": "sha512-8zuqoLv1aP/66PHF5TqwJ7Czm3Yv32urJQHrVyhD7mmA6d61Zv8cIXQYPTWwmg6qlupnPvs/QKDmfa4P/qct2g==", + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.3.tgz", + "integrity": "sha512-VNegTZKhuGq5vSD6XNKlbqWhyt/40CgoEw8XxD6dhnm8Jq9IEa3nIa4HwnM8XOqU0CdB0BwWVXusqiFXfHB3+A==", "dependencies": { - "agent-base": "^7.0.2", + "agent-base": "^7.1.1", "debug": "^4.3.4", "socks": "^2.7.1" }, @@ -4977,10 +5222,17 @@ "node": ">=0.6" } }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + "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==", + "dev": true, + "dependencies": { + "nopt": "~1.0.10" + }, + "bin": { + "nodetouch": "bin/nodetouch.js" + } }, "node_modules/tsconfig-paths": { "version": "3.15.0", @@ -5136,6 +5388,12 @@ "through": "^2.3.8" } }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true + }, "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", @@ -5205,20 +5463,6 @@ "node": ">= 0.8" } }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -5451,6 +5695,14 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zod": { + "version": "3.22.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz", + "integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } } } } diff --git a/package.json b/package.json index 85669a32..33277459 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "license": "MIT", "type": "module", "version": "4.0.0", - "main": "dist/index.esm.js", + "main": "./dist/index.esm.js", "exports": { ".": { "import": "./dist/index.esm.js", @@ -19,16 +19,17 @@ "highcharts-export-server": "./bin/cli.js" }, "scripts": { - "install": "node install.js", - "prestart": "rm -rf tmp && node node_modules/puppeteer/install.mjs", - "start": "node bin/cli.js --enableServer 1 --logLevel 2", + "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", "lint": "eslint ./ --fix", - "cli-tests": "node tests/cli/cli_test_runner.js", - "cli-tests-single": "node tests/cli/cli_test_runner_single.js", - "http-tests": "node tests/http/http_test_runner.js", - "http-tests-single": "node tests/http/http_test_runner_single.js", - "node-tests": "node tests/node/node_test_runner.js", - "node-tests-single": "node tests/node/node_test_runner_single.js", + "cli-tests": "node ./tests/cli/cli_test_runner.js", + "cli-tests-single": "node ./tests/cli/cli_test_runner_single.js", + "http-tests": "node ./tests/http/http_test_runner.js", + "http-tests-single": "node ./tests/http/http_test_runner_single.js", + "node-tests": "node ./tests/node/node_test_runner.js", + "node-tests-single": "node ./tests/node/node_test_runner_single.js", "prepare": "husky install || true", "build": "rollup -c" }, @@ -40,8 +41,9 @@ "eslint-plugin-prettier": "^5.1.3", "husky": "^9.0.11", "lint-staged": "^15.2.2", + "nodemon": "^3.1.0", "prettier": "^3.2.5", - "rollup": "^4.12.1" + "rollup": "^4.14.0" }, "dependencies": { "colors": "1.4.0", @@ -52,7 +54,7 @@ "https-proxy-agent": "^7.0.4", "multer": "^1.4.5-lts.1", "prompts": "^2.4.2", - "puppeteer": "^22.4.0", + "puppeteer": "^22.6.2", "tarn": "^3.0.2", "uuid": "^9.0.1" }, From 8dd0d9c10f90302c5dd03ad466d01bba0058a8fc Mon Sep 17 00:00:00 2001 From: PaulDalek Date: Wed, 3 Apr 2024 16:52:13 +0200 Subject: [PATCH 6/7] Corrected information about required NodeJS version. --- README.md | 4 +- package-lock.json | 525 +++++++++++++++++++++++----------------------- package.json | 6 +- 3 files changed, 266 insertions(+), 269 deletions(-) diff --git a/README.md b/README.md index 08d9aa4a..9ecc0bda 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ In most cases, v3 should serve as a drop-in replacement for v2. However, due to Significant changes have been made to the API for using the server as a Node.js module. While a compatibility layer has been created to address this, it is recommended to transition to the new API described below. It is worth noting that the compatibility layer may be deprecated at some point in the future. -An important note is that the Export Server now requires `Node.js v16.14.0` or a higher version. +An important note is that the Export Server now requires `Node.js v18.12.0` or a higher version. ## Changelog @@ -42,7 +42,7 @@ For systems that generate automatic reports, using the Export Server as a Node.j # Install -First, make sure you have Node.js installed. If not, visit [nodejs.org](https://nodejs.org/en/download/), download and install Node.js for your platform. +First, make sure you have Node.js installed. If not, visit [nodejs.org](https://nodejs.org/en/download/), download and install Node.js for your platform. For compatibility reasons, version `18.12.0` or higher is required. Once Node.js is installed, proceed to install the Export Server by opening a terminal and typing: diff --git a/package-lock.json b/package-lock.json index 1e67b5c1..7dd27bf0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -38,7 +38,7 @@ "rollup": "^4.14.0" }, "engines": { - "node": ">=16.14.0" + "node": ">=18.12.0" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -51,81 +51,17 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", - "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", + "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", "dependencies": { - "@babel/highlight": "^7.23.4", - "chalk": "^2.4.2" + "@babel/highlight": "^7.24.2", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/code-frame/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/code-frame/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/code-frame/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "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", @@ -135,13 +71,14 @@ } }, "node_modules/@babel/highlight": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", - "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz", + "integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==", "dependencies": { "@babel/helper-validator-identifier": "^7.22.20", "chalk": "^2.4.2", - "js-tokens": "^4.0.0" + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" @@ -295,20 +232,20 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", - "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", "dev": true }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "dev": true, "dependencies": { - "@jridgewell/set-array": "^1.0.1", + "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" @@ -324,22 +261,22 @@ } }, "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "dev": true, "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/source-map": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", - "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", "dev": true, "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" } }, "node_modules/@jridgewell/sourcemap-codec": { @@ -349,9 +286,9 @@ "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.22", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz", - "integrity": "sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -686,9 +623,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.12.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.2.tgz", - "integrity": "sha512-zQ0NYO87hyN6Xrclcqp7f8ZbXNbRfoGWNcMvHTPQp9UUrwI0mI7XBz+cu7/W6/VClYo2g63B0cjull/srU7LgQ==", + "version": "20.12.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.3.tgz", + "integrity": "sha512-sD+ia2ubTeWrOu+YMF+MTAB7E+O7qsMqAbMfW7DG3K1URwhZ5hN1pLlRVGbf4wDFzSfikL05M17EyorS86jShw==", "optional": true, "dependencies": { "undici-types": "~5.26.4" @@ -776,24 +713,9 @@ } }, "node_modules/ansi-escapes": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.0.tgz", - "integrity": "sha512-kzRaCqXnpzWs+3z5ABPQiVke+iq0KXkHo8xiWV4RPTi5Yli0l97BEQuhXV1s7+aSU/fu1kUuxgS4MsQ0fRuygw==", - "dev": true, - "dependencies": { - "type-fest": "^3.0.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-escapes/node_modules/type-fest": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.13.1.tgz", - "integrity": "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.1.tgz", + "integrity": "sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==", "dev": true, "engines": { "node": ">=14.16" @@ -869,34 +791,16 @@ "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, "node_modules/array-includes": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz", - "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==", + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", + "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", - "is-string": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.filter": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array.prototype.filter/-/array.prototype.filter-1.0.3.tgz", - "integrity": "sha512-VizNcj/RGJiUyQBgzwxzE5oHdeuXY5hSbbmKMlphj1cy1Vl7Pn2asCGbSrru6hSQjmCzqTBPVWAF/whmEOVHbw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-array-method-boxes-properly": "^1.0.0", + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", "is-string": "^1.0.7" }, "engines": { @@ -907,15 +811,16 @@ } }, "node_modules/array.prototype.findlastindex": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.4.tgz", - "integrity": "sha512-hzvSHUshSpCflDR1QMUBLHGHP1VIEBegT4pix9H/Z92Xw3ySoy6c2qh7lJWTJnRJ8JCZ9bJNCgTyYaJGcJu6xQ==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", + "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.5", + "call-bind": "^1.0.7", "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", + "es-abstract": "^1.23.2", "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", "es-shim-unscopables": "^1.0.2" }, "engines": { @@ -1537,6 +1442,57 @@ "node": ">= 14" } }, + "node_modules/data-view-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", + "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", + "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", + "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -1694,18 +1650,22 @@ } }, "node_modules/es-abstract": { - "version": "1.22.4", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.4.tgz", - "integrity": "sha512-vZYJlk2u6qHYxBOTjAeg7qUxHdNfih64Uu2J8QqWgXZ2cri0ZpJAkzDUK/q593+mvKwlxyaxr6F1Q+3LKoQRgg==", + "version": "1.23.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", + "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", "dev": true, "dependencies": { "array-buffer-byte-length": "^1.0.1", "arraybuffer.prototype.slice": "^1.0.3", - "available-typed-arrays": "^1.0.6", + "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.7", + "data-view-buffer": "^1.0.1", + "data-view-byte-length": "^1.0.1", + "data-view-byte-offset": "^1.0.0", "es-define-property": "^1.0.0", "es-errors": "^1.3.0", - "es-set-tostringtag": "^2.0.2", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.0.3", "es-to-primitive": "^1.2.1", "function.prototype.name": "^1.1.6", "get-intrinsic": "^1.2.4", @@ -1713,15 +1673,16 @@ "globalthis": "^1.0.3", "gopd": "^1.0.1", "has-property-descriptors": "^1.0.2", - "has-proto": "^1.0.1", + "has-proto": "^1.0.3", "has-symbols": "^1.0.3", - "hasown": "^2.0.1", + "hasown": "^2.0.2", "internal-slot": "^1.0.7", "is-array-buffer": "^3.0.4", "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", + "is-data-view": "^1.0.1", + "is-negative-zero": "^2.0.3", "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", + "is-shared-array-buffer": "^1.0.3", "is-string": "^1.0.7", "is-typed-array": "^1.1.13", "is-weakref": "^1.0.2", @@ -1729,17 +1690,17 @@ "object-keys": "^1.1.1", "object.assign": "^4.1.5", "regexp.prototype.flags": "^1.5.2", - "safe-array-concat": "^1.1.0", + "safe-array-concat": "^1.1.2", "safe-regex-test": "^1.0.3", - "string.prototype.trim": "^1.2.8", - "string.prototype.trimend": "^1.0.7", - "string.prototype.trimstart": "^1.0.7", - "typed-array-buffer": "^1.0.1", - "typed-array-byte-length": "^1.0.0", - "typed-array-byte-offset": "^1.0.0", - "typed-array-length": "^1.0.4", + "string.prototype.trim": "^1.2.9", + "string.prototype.trimend": "^1.0.8", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.2", + "typed-array-byte-length": "^1.0.1", + "typed-array-byte-offset": "^1.0.2", + "typed-array-length": "^1.0.6", "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.14" + "which-typed-array": "^1.1.15" }, "engines": { "node": ">= 0.4" @@ -1748,12 +1709,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/es-array-method-boxes-properly": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", - "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", - "dev": true - }, "node_modules/es-define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", @@ -1773,15 +1728,27 @@ "node": ">= 0.4" } }, + "node_modules/es-object-atoms": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", + "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-set-tostringtag": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz", - "integrity": "sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", + "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", "dev": true, "dependencies": { - "get-intrinsic": "^1.2.2", - "has-tostringtag": "^1.0.0", - "hasown": "^2.0.0" + "get-intrinsic": "^1.2.4", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.1" }, "engines": { "node": ">= 0.4" @@ -1946,9 +1913,9 @@ } }, "node_modules/eslint-module-utils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", - "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz", + "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==", "dev": true, "dependencies": { "debug": "^3.2.7" @@ -2419,9 +2386,9 @@ } }, "node_modules/flatted": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.0.tgz", - "integrity": "sha512-noqGuLw158+DuD9UPRKHpJ2hGxpFyDlYYrfM0mWt4XhT4n0lwzTLh70Tkdyy4kyTmyTT9Bv7bWAJqw7cgkEXDg==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", "dev": true }, "node_modules/for-each": { @@ -2749,9 +2716,9 @@ } }, "node_modules/hasown": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.1.tgz", - "integrity": "sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dependencies": { "function-bind": "^1.1.2" }, @@ -3025,6 +2992,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-data-view": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", + "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", + "dev": true, + "dependencies": { + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-date-object": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", @@ -3135,12 +3117,15 @@ } }, "node_modules/is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", + "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", "dev": true, "dependencies": { - "call-bind": "^1.0.2" + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -3774,9 +3759,9 @@ } }, "node_modules/npm-run-path": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.2.0.tgz", - "integrity": "sha512-W4/tgAXFqFA0iL7fk0+uQ3g7wkL8xJmx3XdK0VGb4cHW//eZTtKGvFBBoRKVTpY7n6ze4NL9ly7rgXcHufqXKg==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", "dev": true, "dependencies": { "path-key": "^4.0.0" @@ -3844,14 +3829,15 @@ } }, "node_modules/object.fromentries": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz", - "integrity": "sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==", + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -3861,27 +3847,28 @@ } }, "node_modules/object.groupby": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.2.tgz", - "integrity": "sha512-bzBq58S+x+uo0VjurFT0UktpKHOZmv4/xePiOA1nbB9pMqpGK7rUPNgf+1YC+7mE+0HzhTMqNUuCqvKhj6FnBw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", "dev": true, "dependencies": { - "array.prototype.filter": "^1.0.3", - "call-bind": "^1.0.5", + "call-bind": "^1.0.7", "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.0.0" + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" } }, "node_modules/object.values": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz", - "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", + "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -4080,6 +4067,11 @@ "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", "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==" + }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", @@ -4553,13 +4545,13 @@ } }, "node_modules/safe-array-concat": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.0.tgz", - "integrity": "sha512-ZdQ0Jeb9Ofti4hbt5lX3T2JcAamT9hfzYU1MNB+z/jaEbB6wfFfPIR/zEORmZqobkCCJhSjodobH6WHNmJ97dg==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", + "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", "dev": true, "dependencies": { - "call-bind": "^1.0.5", - "get-intrinsic": "^1.2.2", + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4", "has-symbols": "^1.0.3", "isarray": "^2.0.5" }, @@ -4691,16 +4683,16 @@ } }, "node_modules/set-function-length": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.1.tgz", - "integrity": "sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", "dependencies": { - "define-data-property": "^1.1.2", + "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.3", + "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.1" + "has-property-descriptors": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -4748,11 +4740,11 @@ } }, "node_modules/side-channel": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.5.tgz", - "integrity": "sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", "dependencies": { - "call-bind": "^1.0.6", + "call-bind": "^1.0.7", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.4", "object-inspect": "^1.13.1" @@ -4858,9 +4850,9 @@ } }, "node_modules/smob": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/smob/-/smob-1.4.1.tgz", - "integrity": "sha512-9LK+E7Hv5R9u4g4C3p+jjLstaLe11MDsL21UpYaCNmapvMkYhqCV4A/f/3gyH8QjMyh6l68q9xC85vihY9ahMQ==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/smob/-/smob-1.5.0.tgz", + "integrity": "sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==", "dev": true }, "node_modules/socks": { @@ -5008,14 +5000,15 @@ } }, "node_modules/string.prototype.trim": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", - "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", + "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-object-atoms": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -5025,28 +5018,31 @@ } }, "node_modules/string.prototype.trimend": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", - "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", + "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/string.prototype.trimstart": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", - "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -5168,9 +5164,9 @@ } }, "node_modules/terser": { - "version": "5.27.2", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.27.2.tgz", - "integrity": "sha512-sHXmLSkImesJ4p5apTeT63DsV4Obe1s37qT8qvwHRmVxKTBH7Rv9Wr26VcAMmLbmk9UliiwK8z+657NyJHHy/w==", + "version": "5.30.3", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.30.3.tgz", + "integrity": "sha512-STdUgOUx8rLbMGO9IOwHLpCqolkDITFFQSMYYwKE1N2lY6MVSaeoi10z/EhWxRc6ybqoVmKSkhKYH/XUpl7vSA==", "dev": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", @@ -5302,15 +5298,16 @@ } }, "node_modules/typed-array-byte-length": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", - "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", + "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", + "call-bind": "^1.0.7", "for-each": "^0.3.3", - "has-proto": "^1.0.1", - "is-typed-array": "^1.1.10" + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" }, "engines": { "node": ">= 0.4" @@ -5340,9 +5337,9 @@ } }, "node_modules/typed-array-length": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.5.tgz", - "integrity": "sha512-yMi0PlwuznKHxKmcpoOdeLwxBoVPkqZxd7q2FgMkmD3bNwvF5VW0+UlUQ1k1vmktTu4Yu13Q0RIxEP8+B+wloA==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", + "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", "dev": true, "dependencies": { "call-bind": "^1.0.7", @@ -5495,16 +5492,16 @@ } }, "node_modules/which-typed-array": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.14.tgz", - "integrity": "sha512-VnXFiIW8yNn9kIHN88xvZ4yOWchftKDsRJ8fEPacX/wl1lOvBrhsJ/OeJCXq7B0AaijRuqgzSKalJoPk+D8MPg==", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", "dev": true, "dependencies": { - "available-typed-arrays": "^1.0.6", - "call-bind": "^1.0.5", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", "for-each": "^0.3.3", "gopd": "^1.0.1", - "has-tostringtag": "^1.0.1" + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" diff --git a/package.json b/package.json index 33277459..b86cb637 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,9 @@ "type": "module", "version": "4.0.0", "main": "./dist/index.esm.js", + "engines": { + "node": ">=18.12.0" + }, "exports": { ".": { "import": "./dist/index.esm.js", @@ -58,9 +61,6 @@ "tarn": "^3.0.2", "uuid": "^9.0.1" }, - "engines": { - "node": ">=16.14.0" - }, "lint-staged": { "*.js": "npx eslint --cache --fix", "*.{js,css,md}": "npx prettier --write" From 7df30ddb40653c14e0bdf827aa6cdd46b104fd14 Mon Sep 17 00:00:00 2001 From: PaulDalek Date: Wed, 3 Apr 2024 18:32:05 +0200 Subject: [PATCH 7/7] Updated CHNAGELOG.md file and made a rebuilt. --- CHANGELOG.md | 3 +++ dist/index.cjs | 4 ++-- dist/index.esm.js | 2 +- dist/index.esm.js.map | 2 +- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 17e6d923..60a9ee69 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ _Enhancements:_ - Corrected samples, test scenarios, and test runners. - Removed unnecessary separate `body-parser` package (already implemented in Express v4.16+). - Bumped versions of most packages, with an update for the deprecated `Puppeteer` v21.1.1. +- Added `mapChart` and `ganttChart` constructors in the exporting UI (#503). - Added missing Highcharts modules to stay up-to-date with the latest updates. - Added missing JSDoc descriptions. - Revamped all log messages, error messages, prompt messages, and info for improved clarity of information. @@ -35,6 +36,8 @@ _Enhancements:_ _Fixes:_ - Fixed `multer` related error: 'Field value too long'. +- Fixed the SSL handshake error (#307). +- Fixed missing background color transparency (#492). - Fixed type compatibility issues in the `pairArgumentValue` function, arising from CLI string arguments. - Fixed the 'httpsProxyAgent is not a constructor' issue with the `https-proxy-agent` module. - Fixed the issue of being unable to run both HTTP and HTTPS servers simultaneously. diff --git a/dist/index.cjs b/dist/index.cjs index fa0ef02f..0595621b 100644 --- a/dist/index.cjs +++ b/dist/index.cjs @@ -1,2 +1,2 @@ -"use strict";require("colors");var e=require("dotenv"),t=require("fs"),r=require("path"),i=require("https-proxy-agent"),o=require("http"),n=require("https"),s=require("url"),a=require("prompts"),l=require("tarn"),c=require("uuid"),p=require("node:path"),u=require("puppeteer"),h=require("node:crypto"),d=require("cors"),g=require("express"),m=require("multer"),f=require("express-rate-limit"),y="undefined"!=typeof document?document.currentScript:null;function v(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=v(s);async function b(e,t={}){return new Promise(((r,i)=>{const s=(e=>e.startsWith("https")?n:o)(e);s.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)}))}))}const T={puppeteer:{args:{value:[],type:"string[]",description:"Arguments array to send to Puppeteer."}},highcharts:{version:{value:"latest",envLink:"HIGHCHARTS_VERSION",type:"string",description:"The Highcharts version to be used."},cdnURL:{value:"https://code.highcharts.com/",envLink:"HIGHCHARTS_CDN_URL",type:"string",description:"The CDN URL for Highcharts scripts to be used."},coreScripts:{envLink:"HIGHCHARTS_CORE_SCRIPTS",value:["highcharts","highcharts-more","highcharts-3d"],type:"string[]",description:"The core Highcharts scripts to fetch."},modules:{envLink:"HIGHCHARTS_MODULES",value:["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"],type:"string[]",description:"The modules of Highcharts to fetch."},indicators:{envLink:"HIGHCHARTS_INDICATORS",value:["indicators-all"],type:"string[]",description:"The indicators of Highcharts to fetch."},scripts:{value:["https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js","https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.34/moment-timezone-with-data.min.js"],type:"string[]",description:"Additional optional scripts or dependencies to fetch."},forceFetch:{envLink:"HIGHCHARTS_FORCE_FETCH",value:!1,type:"boolean",description:"The flag to determine whether to refetch all scripts after each server rerun."},cachePath:{envLink:"HIGHCHARTS_CACHE_PATH",value:".cache",type:"string",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:{envLink:"EXPORT_TYPE",value:"png",type:"string",description:"The file export format. It can be jpeg, png, pdf, or svg."},constr:{envLink:"EXPORT_CONSTR",value:"chart",type:"string",description:"The constructor to use. Can be chart, stockChart, mapChart, or ganttChart."},defaultHeight:{envLink:"EXPORT_DEFAULT_HEIGHT",value:400,type:"number",description:"the default height of the exported chart. Used when no value is set."},defaultWidth:{envLink:"EXPORT_DEFAULT_WIDTH",value:600,type:"number",description:"The default width of the exported chart. Used when no value is set."},defaultScale:{envLink:"EXPORT_DEFAULT_SCALE",value:1,type:"number",description:"The default scale of the exported chart. Used when no value is set."},height:{type:"number",value:!1,description:"The height of the exported chart, overriding the option in the chart settings."},width:{type:"number",value:!1,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:{envLink:"EXPORT_RASTERIZATION_TIMEOUT",value:1500,type:"number",description:"The duration in milliseconds to wait for rendering a webpage."}},customLogic:{allowCodeExecution:{envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",value:!1,type:"boolean",description:"Controls whether the execution of arbitrary code is allowed during the exporting process."},allowFileResources:{envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",value:!1,type:"boolean",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:{envLink:"SERVER_ENABLE",value:!1,type:"boolean",cliName:"enableServer",description:"When set to true, the server starts on the local IP address 0.0.0.0."},host:{envLink:"SERVER_HOST",value:"0.0.0.0",type:"string",description:"The hostname of the server. Additionally, it starts a server on the provided hostname."},port:{envLink:"SERVER_PORT",value:7801,type:"number",description:"The server port when enabled."},benchmarking:{envLink:"SERVER_BENCHMARKING",value:!1,type:"boolean",cliName:"serverBenchmarking",description:"Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request."},ssl:{enable:{envLink:"SERVER_SSL_ENABLE",value:!1,type:"boolean",cliName:"enableSsl",description:"Enables or disables the SSL protocol."},force:{envLink:"SERVER_SSL_FORCE",value:!1,type:"boolean",cliName:"sslForced",legacyName:"sslOnly",description:"When set to true, the server is forced to serve only over HTTPS."},port:{envLink:"SERVER_SSL_PORT",value:443,type:"number",cliName:"sslPort",description:"The port on which to run the SSL server."},certPath:{envLink:"SERVER_SSL_CERT_PATH",value:"",type:"string",legacyName:"sslPath",description:"The path to the SSL certificate/key file."}},rateLimiting:{enable:{envLink:"SERVER_RATE_LIMITING_ENABLE",value:!1,type:"boolean",cliName:"enableRateLimiting",description:"Enables rate limiting for the server."},maxRequests:{envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",value:10,type:"number",legacyName:"rateLimit",description:"The maximum number of requests allowed in one minute."},window:{envLink:"SERVER_RATE_LIMITING_WINDOW",value:1,type:"number",description:"The time window, in minutes, for the rate limiting."},delay:{envLink:"SERVER_RATE_LIMITING_DELAY",value:0,type:"number",description:"The delay duration for each successive request before reaching the maximum limit."},trustProxy:{envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",value:!1,type:"boolean",description:"Set this to true if the server is behind a load balancer."},skipKey:{envLink:"SERVER_RATE_LIMITING_SKIP_KEY",value:"",type:"string",description:"Allows bypassing the rate limiter and should be provided with the skipToken argument."},skipToken:{envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",value:"",type:"string",description:"Allows bypassing the rate limiter and should be provided with the skipKey argument."}}},pool:{minWorkers:{envLink:"POOL_MIN_WORKERS",value:4,type:"number",description:"The number of minimum and initial pool workers to spawn."},maxWorkers:{envLink:"POOL_MAX_WORKERS",value:8,type:"number",legacyName:"workers",description:"The number of maximum pool workers to spawn."},workLimit:{envLink:"POOL_WORK_LIMIT",value:40,type:"number",description:"The number of work pieces that can be performed before restarting the worker process."},acquireTimeout:{envLink:"POOL_ACQUIRE_TIMEOUT",value:5e3,type:"number",description:"The duration, in milliseconds, to wait for acquiring a resource."},createTimeout:{envLink:"POOL_CREATE_TIMEOUT",value:5e3,type:"number",description:"The duration, in milliseconds, to wait for creating a resource."},destroyTimeout:{envLink:"POOL_DESTROY_TIMEOUT",value:5e3,type:"number",description:"The duration, in milliseconds, to wait for destroying a resource."},idleTimeout:{envLink:"POOL_IDLE_TIMEOUT",value:3e4,type:"number",description:"The duration, in milliseconds, after which an idle resource is destroyed."},createRetryInterval:{envLink:"POOL_CREATE_RETRY_INTERVAL",value:200,type:"number",description:"The duration, in milliseconds, to wait before retrying the create process in case of a failure."},reaperInterval:{envLink:"POOL_REAPER_INTERVAL",value:1e3,type:"number",description:"The duration, in milliseconds, after which the check for idle resources to destroy is triggered."},benchmarking:{envLink:"POOL_BENCHMARKING",value:!1,type:"boolean",cliName:"poolBenchmarking",description:"Indicate whether to show statistics for the pool of resources or not."},listenToProcessExits:{envLink:"POOL_LISTEN_TO_PROCESS_EXITS",value:!0,type:"boolean",description:"Decides whether or not to attach process.exit handlers."}},logging:{level:{envLink:"LOGGING_LEVEL",value:4,type:"number",cliName:"logLevel",description:"The logging level to be used."},file:{envLink:"LOGGING_FILE",value:"highcharts-export-server.log",type:"string",cliName:"logFile",description:"The name of a log file. The logDest option also needs to be set to enable file logging."},dest:{envLink:"LOGGING_DEST",value:"log/",type:"string",cliName:"logDest",description:"The path to store log files. This also enables file logging."}},ui:{enable:{envLink:"UI_ENABLE",value:!1,type:"boolean",cliName:"enableUi",description:"Enables or disables the user interface (UI) for the export server."},route:{envLink:"UI_ROUTE",value:"/",type:"string",cliName:"uiRoute",description:"The endpoint route to which the user interface (UI) should be attached."}},other:{noLogo:{envLink:"OTHER_NO_LOGO",value:!1,type:"boolean",description:"Skip printing the logo on a startup. Will be replaced by a simple text."}}},x={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:"modules",message:"Available modules",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:T.highcharts.modules.value},{type:"list",name:"scripts",message:"Custom scripts",initial:T.highcharts.scripts.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:"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},{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}],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},{type:"toggle",name:"listenToProcessExits",message:"Set to false to skip attaching process.exit handlers",initial:T.pool.listenToProcessExits.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:"toggle",name:"noLogo",message:"Skip printing the logo on startup. Replaced by simple text",initial:T.other.noLogo.value}]},k=["options","globalOptions","themeOptions","resources","payload"],E={},S=(e,t="")=>{Object.keys(e).forEach((r=>{if(!["puppeteer","highcharts"].includes(r)){const i=e[r];void 0===i.value?S(i,`${t}.${r}`):(E[i.cliName||r]=`${t}.${r}`.substring(1),void 0!==i.legacyName&&(E[i.legacyName]=`${t}.${r}`.substring(1)))}}))};S(T);const L=["red","yellow","blue","gray","green"];let R={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:L[0]},{title:"warning",color:L[1]},{title:"notice",color:L[2]},{title:"verbose",color:L[3]},{title:"benchmark",color:L[4]}],listeners:[]};for(const[e,t]of Object.entries(T.logging))R[e]=t.value;const O=(e,r)=>{R.toFile&&(R.pathCreated||(!t.existsSync(R.dest)&&t.mkdirSync(R.dest),R.pathCreated=!0),t.appendFile(`${R.dest}${R.file}`,[r].concat(e).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),R.toFile=!1)})))},I=(...e)=>{const[t,...r]=e,{level:i,levelsDesc:o}=R;if(5!==t&&(0===t||t>i||i>o.length))return;const n=`${(new Date).toString().split("(")[0].trim()} [${o[t-1].title}] -`;R.listeners.forEach((e=>{e(n,r.join(" "))})),R.toConsole&&console.log.apply(void 0,[n.toString()[R.levelsDesc[t-1].color]].concat(r)),O(r,n)},_=(e,t,r)=>{const i=r||t.message,{level:o,levelsDesc:n}=R;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];R.toConsole&&console.log.apply(void 0,[s.toString()[R.levelsDesc[e-1].color]].concat([i[L[e-1]],"\n",a])),R.listeners.forEach((e=>{e(s,l.join(" "))})),O(l,s)},C=e=>{e>=0&&e<=R.levelsDesc.length&&(R.level=e)},$=(e,t)=>{if(R={...R,dest:e||R.dest,file:t||R.file,toFile:!0},0===R.dest.length)return I(1,"[logger] File logging initialization: no path supplied.");R.dest.endsWith("/")||(R.dest+="/")},P=s.fileURLToPath(new URL("../.","undefined"==typeof document?require("url").pathToFileURL(__filename).href:y&&y.src||new URL("index.cjs",document.baseURI).href)),N=(e,t)=>{const r=["png","jpeg","pdf","svg"];if(t){const i=t.split(".").pop();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"},j=(e=!1,r)=>{const i=["js","css","files"];let o=e,n=!1;if(r&&e.endsWith(".json"))try{o=A(t.readFileSync(e,"utf8"))}catch(e){return _(2,e,"[cli] No resources found.")}else o=A(e),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):I(3,"[cli] No resources found.")};function A(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 H=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]=H(e[r]));return t},F=(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 U(){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 q=e=>!["false","undefined","null","NaN","0",""].includes(e)&&!!e,W=(e,r)=>{if(e&&"string"==typeof e)return(e=e.trim()).endsWith(".js")?!!r&&W(t.readFileSync(e,"utf8")):e.startsWith("function()")||e.startsWith("function ()")||e.startsWith("()=>")||e.startsWith("() =>")?`(${e})()`:e.replace(/;$/,"")},D=()=>{const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6};class M 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 G={cdnURL:"https://code.highcharts.com/",activeManifest:{},sources:"",hcVersion:""};let V=!1;const J=()=>G.hcVersion=G.sources.substring(0,G.sources.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim(),K=async(e,t,r,i=!1)=>{e.endsWith(".js")&&(e=e.substring(0,e.length-3)),I(4,`[cache] Fetching script - ${e}.js`);const o=t?{agent:t,timeout:+process.env.PROXY_SERVER_TIMEOUT||5e3}:{},n=await b(`${e}.js`,o);if(200===n.statusCode&&"string"==typeof n.text){if(r){r[e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")]=1}return n.text}if(i)throw new M(`Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${n.statusCode}).`).setError(n);return I(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`),""},z=async(e,r)=>{const{coreScripts:o,modules:n,indicators:s,scripts:a}=e,l="latest"!==e.version&&e.version?`${e.version}/`:"";let c;I(3,`[cache] Updating cache version to Highcharts: ${l||"latest"}.`);const p=process.env.PROXY_SERVER_HOST,u=process.env.PROXY_SERVER_PORT;if(p&&u)try{c=new i.HttpsProxyAgent({host:p,port:+u})}catch(e){throw new M("[cache] Could not create a Proxy Agent.").setError(e)}const h={};try{return G.sources=await(async(e,t,r,i,o,n)=>{const s=[...e.map((e=>K(`${i}${e}`,o,n,!0))),...t.map((e=>K(`${i}${e}`,o,n))),...r.map((e=>K(`${e}`,o)))];return(await Promise.all(s)).join(";\n")})([...o.map((e=>`${l}${e}`))],[...n.map((e=>"map"===e?`maps/${l}modules/${e}`:`${l}modules/${e}`)),...s.map((e=>`stock/${l}indicators/${e}`))],a,e.cdnURL||G.cdnURL,c,h),J(),t.writeFileSync(r,G.sources),h}catch(e){throw new M("[cache] Unable to update the local Highcharts cache.").setError(e)}},X=async e=>{const i=r.join(P,e.cachePath);let o;const n=r.join(i,"manifest.json"),s=r.join(i,"sources.js");if(V=e,!t.existsSync(i)&&t.mkdirSync(i),!t.existsSync(n)||e.forceFetch)I(3,"[cache] Fetching and caching Highcharts dependencies."),o=await z(e,s);else{let r=!1;const i=JSON.parse(t.readFileSync(n));if(i.modules&&Array.isArray(i.modules)){const e={};i.modules.forEach((t=>e[t]=1)),i.modules=e}const{modules:a,coreScripts:l,indicators:c}=e,p=a.length+l.length+c.length;i.version!==e.version?(I(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),r=!0):Object.keys(i.modules||{}).length!==p?(I(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),r=!0):r=(e.modules||[]).some((e=>{if(!i.modules[e])return I(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),r?o=await z(e,s):(I(3,"[cache] Dependency cache is up to date, proceeding."),G.sources=t.readFileSync(s,"utf8"),o=i.modules,J())}await(async(e,i)=>{const o={version:e.version,modules:i||{}};G.activeManifest=o,I(3,"[cache] Writing a new manifest.");try{t.writeFileSync(r.join(P,e.cachePath,"manifest.json"),JSON.stringify(o),"utf8")}catch(e){throw new M("[cache] Error writing the cache manifest.").setError(e)}})(e,o)},B=()=>r.join(P,V.cachePath);var Y=async e=>!!V&&await X(Object.assign(V,{version:e})),Q=()=>G,Z=()=>G.hcVersion;let ee={};const te=()=>ee,re=(e,t,r=[])=>{const i=H(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]:re(i[e],n,r);var o;return i};function ie(e,t={},r=""){Object.keys(e).forEach((i=>{const o=e[i],n=t&&t[i];let s;void 0===o.value?ie(o,n,`${r}.${i}`):(void 0!==n&&(o.value=n),o.envLink&&("boolean"===o.type?o.value=q([process.env[o.envLink],o.value].find((e=>e||"false"===e))):"number"===o.type?(s=+process.env[o.envLink],o.value=s>=0?s:o.value):o.type.indexOf("]")>=0&&process.env[o.envLink]?o.value=process.env[o.envLink].split(","):o.value=process.env[o.envLink]||o.value))}))}function oe(e){let t={};for(const[r,i]of Object.entries(e))t[r]=Object.prototype.hasOwnProperty.call(i,"value")?i.value:oe(i);return t}function ne(e,t,r){for(;t.length>1;){const i=t.shift();return Object.prototype.hasOwnProperty.call(e,i)||(e[i]={}),e[i]=ne(Object.assign({},e[i]),t,r),e}return e[t[0]]=r,e}const se=h.randomBytes(64).toString("base64url"),ae=p.join("tmp",`puppeteer-${se}`),le=[`--user-data-dir=${p.join(ae,"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"],ce=w.fileURLToPath(new URL(".","undefined"==typeof document?require("url").pathToFileURL(__filename).href:y&&y.src||new URL("index.cjs",document.baseURI).href)),pe=t.readFileSync(ce+"/../templates/template.html","utf8");let ue;const he=async e=>{await e.setContent(pe),await e.addScriptTag({path:`${B()}/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()}`)}))},de=async(e,t=!1)=>{try{t?(await e.goto("about:blank"),await he(e)):await e.evaluate((()=>{document.body.innerHTML='
'}))}catch(e){_(2,e,"[browser] Could not clear the content of the page.")}},ge=async()=>{if(!ue)return!1;const e=await ue.newPage();return await e.setCacheEnabled(!1),await he(e),e},me=async()=>(ue?.isConnected()&&(await ue.close(),I(4,"[browser] Closed the browser.")),!0);const fe=w.fileURLToPath(new URL(".","undefined"==typeof document?require("url").pathToFileURL(__filename).href:y&&y.src||new URL("index.cjs",document.baseURI).href)),ye=(e,t,r)=>e.evaluate(((e,t)=>window.triggerExport(e,t)),t,r);var ve=async(e,i,o)=>{const n=[],s=async e=>{for(const e of n)await e.dispose();await e.evaluate((()=>{const[,...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...r]=document.getElementsByTagName("link");for(const i of[...e,...t,...r])i.remove()}))};try{I(4,"[export] Determining export path.");const a=o.export;await e.evaluate((()=>requestAnimationFrame((()=>{}))));const l=a?.options?.chart?.displayErrors&&Q().activeManifest.modules.debugger;let c;if(await e.evaluate((e=>window._displayErrors=e),l),i.indexOf&&(i.indexOf("=0||i.indexOf("=0)){if(I(4,"[export] Treating as SVG."),"svg"===a.type)return i;c=!0,await e.setContent((e=>`\n\n\n \n \n Highcarts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`)(i))}else I(4,"[export] Treating as config."),a.strInj?await ye(e,{chart:{height:a.height,width:a.width}},o):(i.chart.height=a.height,i.chart.width=a.width,await ye(e,i,o));const p=o.customLogic.resources;if(p){if(p.js&&n.push(await e.addScriptTag({content:p.js})),p.files)for(const r of p.files)try{const i=!r.startsWith("http");n.push(await e.addScriptTag(i?{content:t.readFileSync(r,"utf8")}:{url:r}))}catch(e){_(2,e,`[export] The JS file ${r} 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")?n.push(await e.addStyleTag({url:i})):o.customLogic.allowFileResources&&n.push(await e.addStyleTag({path:r.join(fe,i)})));n.push(await e.addStyleTag({content:p.css.replace(/@import\s*([^;]*);/g,"")||" "}))}}const u=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(a.scale)):await e.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 e.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 e.evaluate(g,parseFloat(a.scale));const{height:m,width:f,x:y,y:v}=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)}})))(e);let w;if(c||await e.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)))(e);else if("png"===a.type||"jpeg"===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 M("Rasterization timeout"))),o||1500)))]))(e,a.type,"base64",{width:d,height:h,x:y,y:v},a.rasterizationTimeout);else{if("pdf"!==a.type)throw new M(`[export] Unsupported output format ${a.type}.`);w=await((e,t,r,i)=>e.pdf({height:t+1,width:r,encoding:i}))(e,h,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}};let we,be=0,Te=0,xe=0,ke=0,Ee=0,Se={},Le=!1;const Re={create:async()=>{let e=!1;const t=c.v4(),r=(new Date).getTime();try{if(e=await ge(),!e||e.isClosed())throw new M("The page is invalid or closed.");I(3,`[pool] Successfully created a worker ${t} - took ${(new Date).getTime()-r} ms.`)}catch(e){throw new M("Error encountered when creating a new page.").setError(e)}return{id:t,page:e,workCount:Math.round(Math.random()*(Se.workLimit/2))}},validate:async e=>Se.workLimit&&++e.workCount>Se.workLimit?(I(3,`[pool] Worker failed validation: exceeded work limit (limit is ${Se.workLimit}).`),!1):(await de(e.page,!0),!0),destroy:e=>{I(3,`[pool] Destroying pool entry ${e.id}.`),e.page&&e.page.close()}},Oe=async e=>{if(Se=e&&e.pool?{...e.pool}:{},Se.listenToProcessExits&&(I(3,"[pool] Attaching exit listeners to the process."),process.on("exit",(async e=>{I(4,`Process exited with code ${e}.`),await Ie()})),process.on("SIGINT",((e,t)=>{I(4,`The ${e} event with code: ${t}.`),process.exit(1)})),process.on("SIGTERM",((e,t)=>{I(4,`The ${e} event with code: ${t}.`),process.exit(1)})),process.on("uncaughtException",(async(e,t)=>{_(1,e,`The ${t} error.`),await Ie(),process.exit(1)}))),we=e.puppeteerArgs,await(async e=>{const t=[...le,...e||[]];if(!ue){let e=0;const r=async()=>{try{I(3,`[browser] Attempting to get a browser instance (try ${++e}).`),ue=await u.launch({headless:"new",args:t,userDataDir:"./tmp/"})}catch(t){if(_(1,t,"[browser] Failed to launch a browser instance."),!(e<25))throw t;I(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 M("[browser] Maximum retries to open a browser instance reached.").setError(e)}if(!ue)throw new M("[browser] Cannot find a browser to open.")}return ue})(we),I(3,`[pool] Initializing pool with workers: min ${Se.minWorkers}, max ${Se.maxWorkers}.`),Le)return I(4,"[pool] Already initialized, please kill it before creating a new one.");parseInt(Se.minWorkers)>parseInt(Se.maxWorkers)&&(Se.minWorkers=Se.maxWorkers);try{Le=new l.Pool({...Re,min:parseInt(Se.minWorkers),max:parseInt(Se.maxWorkers),acquireTimeoutMillis:Se.acquireTimeout,createTimeoutMillis:Se.createTimeout,destroyTimeoutMillis:Se.destroyTimeout,idleTimeoutMillis:Se.idleTimeout,createRetryIntervalMillis:Se.createRetryInterval,reapIntervalMillis:Se.reaperInterval,propagateCreateError:!1}),Le.on("release",(async e=>{await de(e.page,!1),I(4,`[pool] Releasing a worker with ID ${e.id}.`)})),Le.on("destroySuccess",((e,t)=>{I(4,`[pool] Destroyed a worker with ID ${t.id}.`)}));const e=[];for(let t=0;t{Le.release(e)})),I(3,"[pool] The pool is ready"+(e.length?` with ${e.length} initial resources waiting.`:"."))}catch(e){throw await me(),new M("[pool] Could not create the pool of workers.").setError(e)}};async function Ie(){return I(3,"[pool] Killing all pool workers and browser, if any exist."),Le?.destroyed||Le&&(await Le.destroy(),I(4,"[browser] Destroyed the pool of resources.")),me()}const _e=async(e,t)=>{let r;try{if(I(4,"[pool] Work received, starting to process."),++Te,Se.benchmarking&&Ce(),!Le)throw new M("Work received, but pool has not been started.");try{I(4,"[pool] Acquiring a worker handle.");const e=D();r=await Le.acquire().promise,t.server.benchmarking&&I(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Acquired a worker handle: ${e()}ms.`)}catch(e){throw new M("Error encountered when acquiring an available entry.").setError(e)}if(I(4,"[pool] Acquired a worker handle."),!r.page)throw new M("Resolved worker page is invalid: the pool setup is wonky.");let i=(new Date).getTime();I(4,`[pool] Starting work on pool entry with ID ${r.id}.`);const o=D(),n=await ve(r.page,e,t);if(n instanceof Error)throw"Rasterization timeout"===n.message&&(r.page.close(),r.page=await ge()),new M("Error encountered during export.").setError(n);t.server.benchmarking&&I(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Exported a chart sucessfully: ${o()}ms.`),Le.release(r);const s=(new Date).getTime()-i;return xe+=s,Ee=xe/++be,I(4,`[pool] Work completed in ${s} ms.`),{result:n,options:t}}catch(e){throw++ke,r&&Le.release(r),new M(`[pool] In pool.postWork: ${e.message}`).setError(e)}};function Ce(){const{min:e,max:t}=Le;I(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),I(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),I(5,`[pool] The number of resources that are currently available: ${Le.numFree()}.`),I(5,`[pool] The number of resources that are currently acquired: ${Le.numUsed()}.`),I(5,`[pool] The number of callers waiting to acquire a resource: ${Le.numPendingAcquires()}.`)}var $e=()=>({min:Le.min,max:Le.max,available:Le.numFree(),inUse:Le.numUsed(),pendingAcquire:Le.numPendingAcquires()}),Pe=()=>Te,Ne=()=>ke,je=()=>Ee,Ae=()=>be;let He=!1;const Fe=async(e,r)=>{I(4,"[chart] Starting the exporting process.");const i=((e,t={})=>{let r={};return e.svg?(r=H(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=re(t,e,k),r.export.outfile=r.export?.outfile||`chart.${r.export?.type||"png"}`,r})(e,te()),o=i.export;if(i.payload?.svg&&""!==i.payload.svg)try{return I(4,"[chart] Attempting to export from a SVG input."),De(i.payload.svg.trim(),i,r)}catch(e){return r(new M("[chart] Error loading SVG input.").setError(e))}if(o.infile&&o.infile.length)try{return I(4,"[chart] Attempting to export from an input file."),i.export.instr=t.readFileSync(o.infile,"utf8"),De(i.export.instr.trim(),i,r)}catch(e){return r(new M("[chart] Error loading input file.").setError(e))}if(o.instr&&""!==o.instr||o.options&&""!==o.options)try{return I(4,"[chart] Attempting to export from a raw input."),q(i.customLogic?.allowCodeExecution)?We(i,r):"string"==typeof o.instr?De(o.instr.trim(),i,r):qe(i,o.instr||o.options,r)}catch(e){return r(new M("[chart] Error loading raw input.").setError(e))}return r(new M("[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||A(e.export?.instr),i=A(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},qe=async(e,r,i,o)=>{let{export:n,customLogic:s}=e;const a="boolean"==typeof s.allowCodeExecution?s.allowCodeExecution:He;if(s){if(a)if("string"==typeof e.customLogic.resources)e.customLogic.resources=j(e.customLogic.resources,q(e.customLogic.allowFileResources));else if(!e.customLogic.resources)try{const r=t.readFileSync("resources.json","utf8");e.customLogic.resources=j(r,q(e.customLogic.allowFileResources))}catch(e){_(2,e,"[chart] Unable to load the default resources.json file.")}}else s=e.customLogic={};if(!a&&s){if(s.callback||s.resources||s.customCode)return i(new M("[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=N(n.type,n.outfile),"svg"===n.type&&(n.width=!1),["globalOptions","themeOptions"].forEach((e=>{try{n&&n[e]&&("string"==typeof n[e]&&n[e].endsWith(".json")?n[e]=A(t.readFileSync(n[e],"utf8"),!0):n[e]=A(n[e],!0))}catch(t){n[e]={},_(2,t,`[chart] The '${e}' cannot be loaded.`)}})),s.allowCodeExecution)try{s.customCode=W(s.customCode,s.allowFileResources)}catch(e){_(2,e,"[chart] The 'customCode' cannot be loaded.")}if(s&&s.callback&&s.callback?.indexOf("{")<0)if(s.allowFileResources)try{s.callback=t.readFileSync(s.callback,"utf8")}catch(e){s.callback=!1,_(2,e,"[chart] The 'callback' cannot be loaded.")}else s.callback=!1;e.export={...e.export,...Ue(e)};try{return i(!1,await _e(n.strInj||r||o,e))}catch(e){return i(e)}},We=(e,t)=>{try{let r,i=e.export.instr||e.export.options;return"string"!=typeof i&&(r=i=F(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 M(`[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))}},De=(e,t,r)=>{const{allowCodeExecution:i}=t.customLogic;if(e.indexOf("=0||e.indexOf("=0)return I(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 q(i)?We(t,r):r(new M("[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=(e,t,r,i)=>{_(1,e),"development"!==process.env.NODE_ENV&&delete e.stack,i(e)},Ge=(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=f({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&&(I(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(o),I(3,`[rate limiting] Enabled rate limiting with ${i.max} requests per ${i.window} minute for each IP, trusting proxy: ${i.trustProxy}.`)};class Je extends M{constructor(e,t){super(e),this.status=this.statusCode=t}setStatus(e){return this.status=e,this}}const Ke={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};let ze=0;const Xe=[],Be=[],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=D(),o=c.v4().replace(/-/g,""),n=te(),s=e.body,a=++ze;let l=N(s.type);if(!s||"object"==typeof(i=s)&&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 p=A(s.infile||s.options||s.data);if(!p&&!s.svg)throw I(2,`The request with ID ${o} from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Payload received: ${JSON.stringify(s)}.`),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=Ye(Xe,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})),I(4,`[export] Got an incoming HTTP request with ID ${o}.`),s.constr="string"==typeof s.constr&&s.constr||"chart";const d={export:{instr:p,type:l,constr:s.constr[0].toLowerCase()+s.constr.substr(1),height:s.height,width:s.width,scale:s.scale||n.export.scale,globalOptions:A(s.globalOptions,!0),themeOptions:A(s.themeOptions,!0)},customLogic:{allowCodeExecution:He,allowFileResources:!1,resources:A(s.resources,!0),callback:s.callback,customCode:s.customCode}};p&&(d.export.instr=F(p,d.customLogic.allowCodeExecution));const g=re(n,d);if(g.export.options=p,g.payload={svg:s.svg||!1,b64:s.b64||!1,noDownload:s.noDownload||!1,requestId:o},s.svg&&(e=>["localhost","(10).(.*).(.*).(.*)","(127).(.*).(.*).(.*)","(172).(1[6-9]|2[0-9]|3[0-1]).(.*).(.*)","(192).(168).(.*).(.*)"].some((t=>e.match(`xlink:href="(?:(http://|https://))?${t}`))))(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"),n.server.benchmarking&&I(5,`[benchmark] Request with ID ${o} - After the whole exporting process: ${r()}ms.`),h)return I(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,Ye(Be,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",Ke[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(t.readFileSync(r.join(P,"package.json"))),et=new Date;const tt=g();tt.disable("x-powered-by"),tt.use(d());const rt=m.memoryStorage(),it=m({storage:rt,limits:{fieldSize:52428800}});tt.use(g.json({limit:52428800})),tt.use(g.urlencoded({extended:!0,limit:52428800})),tt.use(it.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}`)}))}))},nt=async e=>{try{if(!e.enable)return!1;if(!e.ssl.force){const t=o.createServer(tt);ot(t),t.listen(e.port,e.host),I(3,`[server] Started HTTP server on ${e.host}:${e.port}.`)}if(e.ssl.enable){let i,o;try{i=await t.promises.readFile(r.posix.join(e.ssl.certPath,"server.key"),"utf8"),o=await t.promises.readFile(r.posix.join(e.ssl.certPath,"server.crt"),"utf8")}catch(t){I(2,`[server] Unable to load key/certificate from the '${e.ssl.certPath}' path. Could not run secured layer server.`)}if(i&&o){const t=n.createServer(tt);ot(t),t.listen(e.ssl.port,e.host),I(3,`[server] Started HTTPS server on ${e.host}:${e.ssl.port}.`)}}e.rateLimiting&&e.rateLimiting.enable&&![0,NaN].includes(e.rateLimiting.maxRequests)&&Ve(tt,e.rateLimiting),tt.use(g.static(r.posix.join(P,"public"))),(e=>{!!e&&e.get("/health",((e,t)=>{t.send({status:"OK",bootTime:et,uptime:Math.floor(((new Date).getTime()-et.getTime())/1e3/60)+" minutes",version:Ze.version,highchartsVersion:Z(),averageProcessingTime:je(),performedExports:Ae(),failedExports:Ne(),exportAttempts:Pe(),sucessRatio:Ae()/Pe()*100,pool:$e()})}))})(tt),(e=>{e.post("/",Qe),e.post("/:filename",Qe)})(tt),(e=>{!!e&&e.get("/",((e,t)=>{t.sendFile(r.join(P,"public","index.html"))}))})(tt),(e=>{!!e&&e.post("/version/change/:newVersion",(async(e,t,r)=>{try{const r=process.env.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 Y(o)}catch(e){throw new Je(`Version change: ${e.message}`,e.statusCode).setError(e)}t.status(200).send({statusCode:200,version:Z(),message:`Successfully updated Highcharts to version: ${o}.`})}catch(e){r(e)}}))})(tt),(e=>{e.use(Me),e.use(Ge)})(tt)}catch(e){throw new M("[server] Could not configure and start the server.").setError(e)}};var st={startServer:nt,enableRateLimiting:e=>Ve(tt,e),getExpress:()=>g,getApp:()=>tt,use:(e,...t)=>{tt.use(e,...t)},get:(e,...t)=>{tt.get(e,...t)},post:(e,...t)=>{tt.post(e,...t)}};e.config();var at={server:st,startServer:nt,setOptions:(e,r)=>(r?.length&&(ee=function(e){const r=e.findIndex((e=>"loadConfig"===e.replace(/-/g,"")));if(r>-1&&e[r+1]){const i=e[r+1];try{if(i&&i.endsWith(".json"))return JSON.parse(t.readFileSync(i))}catch(e){_(2,e,`[config] Unable to load the configuration from the ${i} file.`)}}return{}}(r)),ie(T,ee),ee=oe(T),e&&(ee=re(ee,e,k)),r?.length&&(ee=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]=q(t[o]):"number"===a?e[r]=+t[o]:a.indexOf("]")>=0?e[r]=t[o].split(","):e[r]=t[o]:(I(2,`[config] Missing value for the '${n}' argument. Using the default value.`),i=!0)),e[r])),e)}i&&U();return e}(ee,r,T)),ee),initExport:async e=>{var t;return t=e.customLogic&&e.customLogic.allowCodeExecution,He=q(t),(e=>{C(e&&parseInt(e.level)),e&&e.dest&&$(e.dest,e.file||"highcharts-export-server.log")})(e.logging),await X(e.highcharts||{version:"latest"}),await Oe({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,r)=>{if(e)throw e;const{outfile:i,type:o}=r.options.export;t.writeFileSync(i||`chart.${o}`,"svg"!==o?Buffer.from(r.result,"base64"):r.result),await Ie()}))},batchExport:async e=>{const r=[];for(let i of e.export.batch.split(";"))i=i.split("="),2===i.length&&r.push(Fe({...e,export:{...e.export,infile:i[0],outfile:i[1]}},((e,r)=>{if(e)throw e;t.writeFileSync(r.options.export.outfile,Buffer.from(r.result,"base64"))})));try{await Promise.all(r),await Ie()}catch(e){throw new M("[chart] Error encountered during batch export.").setError(e)}},startExport:Fe,killPool:Ie,log:I,logWithStack:_,setLogLevel:C,enableFileLogging:$,mapToNewConfig:e=>{const t={};for(const[r,i]of Object.entries(e)){const e=E[r]?E[r].split("."):[];e.reduce(((t,r,o)=>t[r]=e.length-1===o?i:t[r]||{}),t)}return t},manualConfig:async e=>{let r={};t.existsSync(e)&&(r=JSON.parse(t.readFileSync(e,"utf8")));const i=Object.keys(x).map((e=>({title:`${e} options`,value:e})));return a({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,o)=>{let n=0,s=[];for(const e of o)x[e]=x[e].map((t=>({...t,section:e}))),s=[...s,...x[e]];return await a(s,{onSubmit:async(i,o)=>{if("modules"===i.name?(o=o.length?o.map((e=>i.choices[e])):i.choices,r[i.section][i.name]=o):r[i.section]=ne(Object.assign({},r[i.section]||{}),i.name.split("."),i.choices?i.choices[o]:o),++n===s.length){try{await t.promises.writeFile(e,JSON.stringify(r,null,2),"utf8")}catch(t){_(1,t,`[config] An error occurred while creating the ${e} file.`)}return!0}}}),!0}})},printLogo:e=>{const i=JSON.parse(t.readFileSync(r.join(P,"package.json"))).version;e?console.log(`Starting Highcharts Export Server v${i}...`):console.log(t.readFileSync(P+"/msg/startup.msg").toString().bold.yellow,`v${i}`)},printUsage:U};module.exports=at; -//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguY2pzIiwic291cmNlcyI6WyIuLi9saWIvZmV0Y2guanMiLCIuLi9saWIvc2NoZW1hcy9jb25maWcuanMiLCIuLi9saWIvbG9nZ2VyLmpzIiwiLi4vbGliL3V0aWxzLmpzIiwiLi4vbGliL2Vycm9ycy9FeHBvcnRFcnJvci5qcyIsIi4uL2xpYi9jYWNoZS5qcyIsIi4uL2xpYi9jb25maWcuanMiLCIuLi9saWIvYnJvd3Nlci5qcyIsIi4uL2xpYi9leHBvcnQuanMiLCIuLi90ZW1wbGF0ZXMvc3ZnX2V4cG9ydC9zdmdfZXhwb3J0LmpzIiwiLi4vbGliL3Bvb2wuanMiLCIuLi9saWIvY2hhcnQuanMiLCIuLi9saWIvc2VydmVyL2Vycm9yLmpzIiwiLi4vbGliL3NlcnZlci9yYXRlX2xpbWl0LmpzIiwiLi4vbGliL2Vycm9ycy9IdHRwRXJyb3IuanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy9leHBvcnQuanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy9oZWFsdGguanMiLCIuLi9saWIvc2VydmVyL3NlcnZlci5qcyIsIi4uL2xpYi9zZXJ2ZXIvcm91dGVzL3VpLmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvY2hhbmdlX2hjX3ZlcnNpb24uanMiLCIuLi9saWIvaW5kZXguanMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqXHJcbiAqIFRoaXMgbW9kdWxlIGV4cG9ydHMgdHdvIGZ1bmN0aW9uczogZmV0Y2ggKGZvciBHRVQgcmVxdWVzdHMpIGFuZCBwb3N0IChmb3IgUE9TVCByZXF1ZXN0cykuXHJcbiAqL1xyXG5cclxuaW1wb3J0IGh0dHAgZnJvbSAnaHR0cCc7XHJcbmltcG9ydCBodHRwcyBmcm9tICdodHRwcyc7XHJcblxyXG4vKipcclxuICogUmV0dXJucyB0aGUgSFRUUCBvciBIVFRQUyBwcm90b2NvbCBtb2R1bGUgYmFzZWQgb24gdGhlIHByb3ZpZGVkIFVSTC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHVybCAtIFRoZSBVUkwgdG8gZGV0ZXJtaW5lIHRoZSBwcm90b2NvbC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wgbW9kdWxlIChodHRwIG9yIGh0dHBzKS5cclxuICovXHJcbmNvbnN0IGdldFByb3RvY29sID0gKHVybCkgPT4gKHVybC5zdGFydHNXaXRoKCdodHRwcycpID8gaHR0cHMgOiBodHRwKTtcclxuXHJcbi8qKlxyXG4gKiBGZXRjaGVzIGRhdGEgZnJvbSB0aGUgc3BlY2lmaWVkIFVSTCB1c2luZyBlaXRoZXIgSFRUUCBvciBIVFRQUyBwcm90b2NvbC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHVybCAtIFRoZSBVUkwgdG8gZmV0Y2ggZGF0YSBmcm9tLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcmVxdWVzdE9wdGlvbnMgLSBPcHRpb25zIGZvciB0aGUgSFRUUCByZXF1ZXN0IChvcHRpb25hbCkuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBIVFRQIHJlc3BvbnNlIG9iamVjdFxyXG4gKiB3aXRoIGFkZGVkICd0ZXh0JyBwcm9wZXJ0eSBvciByZWplY3Rpbmcgd2l0aCBhbiBlcnJvci5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIGZldGNoKHVybCwgcmVxdWVzdE9wdGlvbnMgPSB7fSkge1xyXG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XHJcbiAgICBjb25zdCBwcm90b2NvbCA9IGdldFByb3RvY29sKHVybCk7XHJcblxyXG4gICAgcHJvdG9jb2xcclxuICAgICAgLmdldCh1cmwsIHJlcXVlc3RPcHRpb25zLCAocmVzKSA9PiB7XHJcbiAgICAgICAgbGV0IGRhdGEgPSAnJztcclxuXHJcbiAgICAgICAgLy8gQSBjaHVuayBvZiBkYXRhIGhhcyBiZWVuIHJlY2VpdmVkLlxyXG4gICAgICAgIHJlcy5vbignZGF0YScsIChjaHVuaykgPT4ge1xyXG4gICAgICAgICAgZGF0YSArPSBjaHVuaztcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgLy8gVGhlIHdob2xlIHJlc3BvbnNlIGhhcyBiZWVuIHJlY2VpdmVkLlxyXG4gICAgICAgIHJlcy5vbignZW5kJywgKCkgPT4ge1xyXG4gICAgICAgICAgaWYgKCFkYXRhKSB7XHJcbiAgICAgICAgICAgIHJlamVjdCgnTm90aGluZyB3YXMgZmV0Y2hlZCBmcm9tIHRoZSBVUkwuJyk7XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgcmVzLnRleHQgPSBkYXRhO1xyXG4gICAgICAgICAgcmVzb2x2ZShyZXMpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICB9KVxyXG4gICAgICAub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICAgICAgcmVqZWN0KGVycm9yKTtcclxuICAgICAgfSk7XHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZW5kcyBhIFBPU1QgcmVxdWVzdCB0byB0aGUgc3BlY2lmaWVkIFVSTCB3aXRoIHRoZSBwcm92aWRlZCBKU09OIGJvZHkgdXNpbmdcclxuICogZWl0aGVyIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgLSBUaGUgVVJMIHRvIHNlbmQgdGhlIFBPU1QgcmVxdWVzdCB0by5cclxuICogQHBhcmFtIHtPYmplY3R9IGJvZHkgLSBUaGUgSlNPTiBib2R5IHRvIGluY2x1ZGUgaW4gdGhlIFBPU1QgcmVxdWVzdFxyXG4gKiAob3B0aW9uYWwsIGRlZmF1bHQgaXMgYW4gZW1wdHkgb2JqZWN0KS5cclxuICogQHBhcmFtIHtPYmplY3R9IHJlcXVlc3RPcHRpb25zIC0gT3B0aW9ucyBmb3IgdGhlIEhUVFAgcmVxdWVzdCAob3B0aW9uYWwpLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgSFRUUCByZXNwb25zZSBvYmplY3Qgd2l0aFxyXG4gKiBhZGRlZCAndGV4dCcgcHJvcGVydHkgb3IgcmVqZWN0aW5nIHdpdGggYW4gZXJyb3IuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBwb3N0KHVybCwgYm9keSA9IHt9LCByZXF1ZXN0T3B0aW9ucyA9IHt9KSB7XHJcbiAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcclxuICAgIGNvbnN0IHByb3RvY29sID0gZ2V0UHJvdG9jb2wodXJsKTtcclxuICAgIGNvbnN0IGRhdGEgPSBKU09OLnN0cmluZ2lmeShib2R5KTtcclxuXHJcbiAgICAvLyBTZXQgZGVmYXVsdCBoZWFkZXJzIGFuZCBtZXJnZSB3aXRoIHJlcXVlc3RPcHRpb25zXHJcbiAgICBjb25zdCBvcHRpb25zID0gT2JqZWN0LmFzc2lnbihcclxuICAgICAge1xyXG4gICAgICAgIG1ldGhvZDogJ1BPU1QnLFxyXG4gICAgICAgIGhlYWRlcnM6IHtcclxuICAgICAgICAgICdDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbicsXHJcbiAgICAgICAgICAnQ29udGVudC1MZW5ndGgnOiBkYXRhLmxlbmd0aFxyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgcmVxdWVzdE9wdGlvbnNcclxuICAgICk7XHJcblxyXG4gICAgY29uc3QgcmVxID0gcHJvdG9jb2xcclxuICAgICAgLnJlcXVlc3QodXJsLCBvcHRpb25zLCAocmVzKSA9PiB7XHJcbiAgICAgICAgbGV0IHJlc3BvbnNlRGF0YSA9ICcnO1xyXG5cclxuICAgICAgICAvLyBBIGNodW5rIG9mIGRhdGEgaGFzIGJlZW4gcmVjZWl2ZWQuXHJcbiAgICAgICAgcmVzLm9uKCdkYXRhJywgKGNodW5rKSA9PiB7XHJcbiAgICAgICAgICByZXNwb25zZURhdGEgKz0gY2h1bms7XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICAgIC8vIFRoZSB3aG9sZSByZXNwb25zZSBoYXMgYmVlbiByZWNlaXZlZC5cclxuICAgICAgICByZXMub24oJ2VuZCcsICgpID0+IHtcclxuICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgIHJlcy50ZXh0ID0gcmVzcG9uc2VEYXRhO1xyXG4gICAgICAgICAgICByZXNvbHZlKHJlcyk7XHJcbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICByZWplY3QoZXJyb3IpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH0pO1xyXG4gICAgICB9KVxyXG4gICAgICAub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICAgICAgcmVqZWN0KGVycm9yKTtcclxuICAgICAgfSk7XHJcblxyXG4gICAgLy8gV3JpdGUgdGhlIHJlcXVlc3QgYm9keSBhbmQgZW5kIHRoZSByZXF1ZXN0LlxyXG4gICAgcmVxLndyaXRlKGRhdGEpO1xyXG4gICAgcmVxLmVuZCgpO1xyXG4gIH0pO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCBmZXRjaDtcclxuZXhwb3J0IHsgZmV0Y2gsIHBvc3QgfTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vLyBUaGlzIGlzIHRoZSBjb25maWd1cmF0aW9uIG9iamVjdCB3aXRoIGFsbCBvcHRpb25zIGFuZCB0aGVpciBkZWZhdWx0IHZhbHVlcyxcclxuLy8gYWxzbyBmcm9tIHRoZSAuZW52IGZpbGUgaWYgb25lIGV4aXN0c1xyXG5leHBvcnQgY29uc3QgZGVmYXVsdENvbmZpZyA9IHtcclxuICBwdXBwZXRlZXI6IHtcclxuICAgIGFyZ3M6IHtcclxuICAgICAgdmFsdWU6IFtdLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0FyZ3VtZW50cyBhcnJheSB0byBzZW5kIHRvIFB1cHBldGVlci4nXHJcbiAgICB9XHJcbiAgfSxcclxuICBoaWdoY2hhcnRzOiB7XHJcbiAgICB2ZXJzaW9uOiB7XHJcbiAgICAgIHZhbHVlOiAnbGF0ZXN0JyxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfVkVSU0lPTicsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBIaWdoY2hhcnRzIHZlcnNpb24gdG8gYmUgdXNlZC4nXHJcbiAgICB9LFxyXG4gICAgY2RuVVJMOiB7XHJcbiAgICAgIHZhbHVlOiAnaHR0cHM6Ly9jb2RlLmhpZ2hjaGFydHMuY29tLycsXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0NETl9VUkwnLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgQ0ROIFVSTCBmb3IgSGlnaGNoYXJ0cyBzY3JpcHRzIHRvIGJlIHVzZWQuJ1xyXG4gICAgfSxcclxuICAgIGNvcmVTY3JpcHRzOiB7XHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0NPUkVfU0NSSVBUUycsXHJcbiAgICAgIHZhbHVlOiBbJ2hpZ2hjaGFydHMnLCAnaGlnaGNoYXJ0cy1tb3JlJywgJ2hpZ2hjaGFydHMtM2QnXSxcclxuICAgICAgdHlwZTogJ3N0cmluZ1tdJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgY29yZSBIaWdoY2hhcnRzIHNjcmlwdHMgdG8gZmV0Y2guJ1xyXG4gICAgfSxcclxuICAgIG1vZHVsZXM6IHtcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfTU9EVUxFUycsXHJcbiAgICAgIHZhbHVlOiBbXHJcbiAgICAgICAgJ3N0b2NrJyxcclxuICAgICAgICAnbWFwJyxcclxuICAgICAgICAnZ2FudHQnLFxyXG4gICAgICAgICdleHBvcnRpbmcnLFxyXG4gICAgICAgICdleHBvcnQtZGF0YScsXHJcbiAgICAgICAgJ3BhcmFsbGVsLWNvb3JkaW5hdGVzJyxcclxuICAgICAgICAnYWNjZXNzaWJpbGl0eScsXHJcbiAgICAgICAgJ2Fubm90YXRpb25zLWFkdmFuY2VkJyxcclxuICAgICAgICAnYm9vc3QtY2FudmFzJyxcclxuICAgICAgICAnYm9vc3QnLFxyXG4gICAgICAgICdkYXRhJyxcclxuICAgICAgICAnZGF0YS10b29scycsXHJcbiAgICAgICAgJ2RyYWdnYWJsZS1wb2ludHMnLFxyXG4gICAgICAgICdzdGF0aWMtc2NhbGUnLFxyXG4gICAgICAgICdicm9rZW4tYXhpcycsXHJcbiAgICAgICAgJ2hlYXRtYXAnLFxyXG4gICAgICAgICd0aWxlbWFwJyxcclxuICAgICAgICAndGlsZWR3ZWJtYXAnLFxyXG4gICAgICAgICd0aW1lbGluZScsXHJcbiAgICAgICAgJ3RyZWVtYXAnLFxyXG4gICAgICAgICd0cmVlZ3JhcGgnLFxyXG4gICAgICAgICdpdGVtLXNlcmllcycsXHJcbiAgICAgICAgJ2RyaWxsZG93bicsXHJcbiAgICAgICAgJ2hpc3RvZ3JhbS1iZWxsY3VydmUnLFxyXG4gICAgICAgICdidWxsZXQnLFxyXG4gICAgICAgICdmdW5uZWwnLFxyXG4gICAgICAgICdmdW5uZWwzZCcsXHJcbiAgICAgICAgJ2dlb2hlYXRtYXAnLFxyXG4gICAgICAgICdweXJhbWlkM2QnLFxyXG4gICAgICAgICduZXR3b3JrZ3JhcGgnLFxyXG4gICAgICAgICdvdmVybGFwcGluZy1kYXRhbGFiZWxzJyxcclxuICAgICAgICAncGFyZXRvJyxcclxuICAgICAgICAncGF0dGVybi1maWxsJyxcclxuICAgICAgICAncGljdG9yaWFsJyxcclxuICAgICAgICAncHJpY2UtaW5kaWNhdG9yJyxcclxuICAgICAgICAnc2Fua2V5JyxcclxuICAgICAgICAnYXJjLWRpYWdyYW0nLFxyXG4gICAgICAgICdkZXBlbmRlbmN5LXdoZWVsJyxcclxuICAgICAgICAnc2VyaWVzLWxhYmVsJyxcclxuICAgICAgICAnc29saWQtZ2F1Z2UnLFxyXG4gICAgICAgICdzb25pZmljYXRpb24nLFxyXG4gICAgICAgICdzdG9jay10b29scycsXHJcbiAgICAgICAgJ3N0cmVhbWdyYXBoJyxcclxuICAgICAgICAnc3VuYnVyc3QnLFxyXG4gICAgICAgICd2YXJpYWJsZS1waWUnLFxyXG4gICAgICAgICd2YXJpd2lkZScsXHJcbiAgICAgICAgJ3ZlY3RvcicsXHJcbiAgICAgICAgJ3Zlbm4nLFxyXG4gICAgICAgICd3aW5kYmFyYicsXHJcbiAgICAgICAgJ3dvcmRjbG91ZCcsXHJcbiAgICAgICAgJ3hyYW5nZScsXHJcbiAgICAgICAgJ25vLWRhdGEtdG8tZGlzcGxheScsXHJcbiAgICAgICAgJ2RyYWctcGFuZXMnLFxyXG4gICAgICAgICdkZWJ1Z2dlcicsXHJcbiAgICAgICAgJ2R1bWJiZWxsJyxcclxuICAgICAgICAnbG9sbGlwb3AnLFxyXG4gICAgICAgICdjeWxpbmRlcicsXHJcbiAgICAgICAgJ29yZ2FuaXphdGlvbicsXHJcbiAgICAgICAgJ2RvdHBsb3QnLFxyXG4gICAgICAgICdtYXJrZXItY2x1c3RlcnMnLFxyXG4gICAgICAgICdob2xsb3djYW5kbGVzdGljaycsXHJcbiAgICAgICAgJ2hlaWtpbmFzaGknLFxyXG4gICAgICAgICdmbG93bWFwJ1xyXG4gICAgICBdLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBtb2R1bGVzIG9mIEhpZ2hjaGFydHMgdG8gZmV0Y2guJ1xyXG4gICAgfSxcclxuICAgIGluZGljYXRvcnM6IHtcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfSU5ESUNBVE9SUycsXHJcbiAgICAgIHZhbHVlOiBbJ2luZGljYXRvcnMtYWxsJ10sXHJcbiAgICAgIHR5cGU6ICdzdHJpbmdbXScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIGluZGljYXRvcnMgb2YgSGlnaGNoYXJ0cyB0byBmZXRjaC4nXHJcbiAgICB9LFxyXG4gICAgc2NyaXB0czoge1xyXG4gICAgICB2YWx1ZTogW1xyXG4gICAgICAgICdodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9tb21lbnQuanMvMi4yOS40L21vbWVudC5taW4uanMnLFxyXG4gICAgICAgICdodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9tb21lbnQtdGltZXpvbmUvMC41LjM0L21vbWVudC10aW1lem9uZS13aXRoLWRhdGEubWluLmpzJ1xyXG4gICAgICBdLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0FkZGl0aW9uYWwgb3B0aW9uYWwgc2NyaXB0cyBvciBkZXBlbmRlbmNpZXMgdG8gZmV0Y2guJ1xyXG4gICAgfSxcclxuICAgIGZvcmNlRmV0Y2g6IHtcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfRk9SQ0VfRkVUQ0gnLFxyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBmbGFnIHRvIGRldGVybWluZSB3aGV0aGVyIHRvIHJlZmV0Y2ggYWxsIHNjcmlwdHMgYWZ0ZXIgZWFjaCBzZXJ2ZXIgcmVydW4uJ1xyXG4gICAgfSxcclxuICAgIGNhY2hlUGF0aDoge1xyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DQUNIRV9QQVRIJyxcclxuICAgICAgdmFsdWU6ICcuY2FjaGUnLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBwYXRoIHRvIHRoZSBjYWNoZSBkaXJlY3RvcnkuIEl0IGlzIHVzZWQgdG8gc3RvcmUgdGhlIEhpZ2hjaGFydHMgc2NyaXB0cyBhbmQgY3VzdG9tIHNjcmlwdHMuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgZXhwb3J0OiB7XHJcbiAgICBpbmZpbGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBpbnB1dCBmaWxlIHNob3VsZCBpbmNsdWRlIGEgbmFtZSBhbmQgYSB0eXBlIChqc29uIG9yIHN2ZykuIEl0IG11c3QgYmUgY29ycmVjdGx5IGZvcm1hdHRlZCBhcyBhIEpTT04gb3IgU1ZHIGZpbGUuJ1xyXG4gICAgfSxcclxuICAgIGluc3RyOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbnB1dCwgcHJvdmlkZWQgaW4gdGhlIGZvcm0gb2YgYSBzdHJpbmdpZmllZCBKU09OIG9yIFNWRyBmaWxlLCB3aWxsIG92ZXJyaWRlIHRoZSAtLWluZmlsZSBvcHRpb24uJ1xyXG4gICAgfSxcclxuICAgIG9wdGlvbnM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdBbiBhbGlhcyBmb3IgdGhlIC0taW5zdHIgb3B0aW9uLidcclxuICAgIH0sXHJcbiAgICBvdXRmaWxlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgb3V0cHV0IGZpbGVuYW1lIGFsb25nIHdpdGggYSB0eXBlIChqcGVnLCBwbmcsIHBkZiwgb3Igc3ZnKS4gVGhpcyB3aWxsIGlnbm9yZSB0aGUgLS10eXBlIGZsYWcuJ1xyXG4gICAgfSxcclxuICAgIHR5cGU6IHtcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9UWVBFJyxcclxuICAgICAgdmFsdWU6ICdwbmcnLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgZmlsZSBleHBvcnQgZm9ybWF0LiBJdCBjYW4gYmUganBlZywgcG5nLCBwZGYsIG9yIHN2Zy4nXHJcbiAgICB9LFxyXG4gICAgY29uc3RyOiB7XHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfQ09OU1RSJyxcclxuICAgICAgdmFsdWU6ICdjaGFydCcsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGNvbnN0cnVjdG9yIHRvIHVzZS4gQ2FuIGJlIGNoYXJ0LCBzdG9ja0NoYXJ0LCBtYXBDaGFydCwgb3IgZ2FudHRDaGFydC4nXHJcbiAgICB9LFxyXG4gICAgZGVmYXVsdEhlaWdodDoge1xyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0RFRkFVTFRfSEVJR0hUJyxcclxuICAgICAgdmFsdWU6IDQwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICd0aGUgZGVmYXVsdCBoZWlnaHQgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LiBVc2VkIHdoZW4gbm8gdmFsdWUgaXMgc2V0LidcclxuICAgIH0sXHJcbiAgICBkZWZhdWx0V2lkdGg6IHtcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9ERUZBVUxUX1dJRFRIJyxcclxuICAgICAgdmFsdWU6IDYwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZGVmYXVsdCB3aWR0aCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQuIFVzZWQgd2hlbiBubyB2YWx1ZSBpcyBzZXQuJ1xyXG4gICAgfSxcclxuICAgIGRlZmF1bHRTY2FsZToge1xyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0RFRkFVTFRfU0NBTEUnLFxyXG4gICAgICB2YWx1ZTogMSxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZGVmYXVsdCBzY2FsZSBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQuIFVzZWQgd2hlbiBubyB2YWx1ZSBpcyBzZXQuJ1xyXG4gICAgfSxcclxuICAgIGhlaWdodDoge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGhlaWdodCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQsIG92ZXJyaWRpbmcgdGhlIG9wdGlvbiBpbiB0aGUgY2hhcnQgc2V0dGluZ3MuJ1xyXG4gICAgfSxcclxuICAgIHdpZHRoOiB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgd2lkdGggb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LCBvdmVycmlkaW5nIHRoZSBvcHRpb24gaW4gdGhlIGNoYXJ0IHNldHRpbmdzLidcclxuICAgIH0sXHJcbiAgICBzY2FsZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIHNjYWxlIG9mIHRoZSBleHBvcnRlZCBjaGFydCwgb3ZlcnJpZGluZyB0aGUgb3B0aW9uIGluIHRoZSBjaGFydCBzZXR0aW5ncy4gUmFuZ2VzIGJldHdlZW4gMC4xIGFuZCA1LjAuJ1xyXG4gICAgfSxcclxuICAgIGdsb2JhbE9wdGlvbnM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0VpdGhlciBhIHN0cmluZ2lmaWVkIEpTT04gb3IgYSBmaWxlbmFtZSBjb250YWluaW5nIG9wdGlvbnMgdG8gYmUgcGFzc2VkIGludG8gdGhlIEhpZ2hjaGFydHMuc2V0T3B0aW9ucy4nXHJcbiAgICB9LFxyXG4gICAgdGhlbWVPcHRpb25zOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdFaXRoZXIgYSBzdHJpbmdpZmllZCBKU09OIG9yIGEgZmlsZW5hbWUgY29udGFpbmluZyB0aGVtZSBvcHRpb25zIHRvIGJlIHBhc3NlZCBpbnRvIHRoZSBIaWdoY2hhcnRzLnNldE9wdGlvbnMuJ1xyXG4gICAgfSxcclxuICAgIGJhdGNoOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbml0aWF0ZXMgYSBiYXRjaCBqb2Igd2l0aCBhIHN0cmluZyBjb250YWluaW5nIGlucHV0L291dHB1dCBwYWlyczogXCJpbj1vdXQ7aW49b3V0Oy4uLlwiLidcclxuICAgIH0sXHJcbiAgICByYXN0ZXJpemF0aW9uVGltZW91dDoge1xyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX1JBU1RFUklaQVRJT05fVElNRU9VVCcsXHJcbiAgICAgIHZhbHVlOiAxNTAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiBpbiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgcmVuZGVyaW5nIGEgd2VicGFnZS4nXHJcbiAgICB9XHJcbiAgfSxcclxuICBjdXN0b21Mb2dpYzoge1xyXG4gICAgYWxsb3dDb2RlRXhlY3V0aW9uOiB7XHJcbiAgICAgIGVudkxpbms6ICdDVVNUT01fTE9HSUNfQUxMT1dfQ09ERV9FWEVDVVRJT04nLFxyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0NvbnRyb2xzIHdoZXRoZXIgdGhlIGV4ZWN1dGlvbiBvZiBhcmJpdHJhcnkgY29kZSBpcyBhbGxvd2VkIGR1cmluZyB0aGUgZXhwb3J0aW5nIHByb2Nlc3MuJ1xyXG4gICAgfSxcclxuICAgIGFsbG93RmlsZVJlc291cmNlczoge1xyXG4gICAgICBlbnZMaW5rOiAnQ1VTVE9NX0xPR0lDX0FMTE9XX0ZJTEVfUkVTT1VSQ0VTJyxcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdDb250cm9scyB0aGUgYWJpbGl0eSB0byBpbmplY3QgcmVzb3VyY2VzIGZyb20gdGhlIGZpbGVzeXN0ZW0uIFRoaXMgc2V0dGluZyBoYXMgbm8gZWZmZWN0IHdoZW4gcnVubmluZyBhcyBhIHNlcnZlci4nXHJcbiAgICB9LFxyXG4gICAgY3VzdG9tQ29kZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQ3VzdG9tIGNvZGUgdG8gZXhlY3V0ZSBiZWZvcmUgY2hhcnQgaW5pdGlhbGl6YXRpb24uIEl0IGNhbiBiZSBhIGZ1bmN0aW9uLCBjb2RlIHdyYXBwZWQgd2l0aGluIGEgZnVuY3Rpb24sIG9yIGEgZmlsZW5hbWUgd2l0aCB0aGUgLmpzIGV4dGVuc2lvbi4nXHJcbiAgICB9LFxyXG4gICAgY2FsbGJhY2s6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0phdmFTY3JpcHQgY29kZSB0byBydW4gZHVyaW5nIGNvbnN0cnVjdGlvbi4gSXQgY2FuIGJlIGEgZnVuY3Rpb24gb3IgYSBmaWxlbmFtZSB3aXRoIHRoZSAuanMgZXh0ZW5zaW9uLidcclxuICAgIH0sXHJcbiAgICByZXNvdXJjZXM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0FkZGl0aW9uYWwgcmVzb3VyY2UgaW4gdGhlIGZvcm0gb2YgYSBzdHJpbmdpZmllZCBKU09OLCB3aGljaCBtYXkgY29udGFpbiBmaWxlcywganMsIGFuZCBjc3Mgc2VjdGlvbnMuJ1xyXG4gICAgfSxcclxuICAgIGxvYWRDb25maWc6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgbGVnYWN5TmFtZTogJ2Zyb21GaWxlJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdBIGZpbGUgY29udGFpbmluZyBhIHByZS1kZWZpbmVkIGNvbmZpZ3VyYXRpb24gdG8gdXNlLidcclxuICAgIH0sXHJcbiAgICBjcmVhdGVDb25maWc6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0VuYWJsZXMgc2V0dGluZyBvcHRpb25zIHRocm91Z2ggYSBwcm9tcHQgYW5kIHNhdmluZyB0aGVtIGluIGEgcHJvdmlkZWQgY29uZmlnIGZpbGUuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgc2VydmVyOiB7XHJcbiAgICBlbmFibGU6IHtcclxuICAgICAgZW52TGluazogJ1NFUlZFUl9FTkFCTEUnLFxyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgY2xpTmFtZTogJ2VuYWJsZVNlcnZlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdXaGVuIHNldCB0byB0cnVlLCB0aGUgc2VydmVyIHN0YXJ0cyBvbiB0aGUgbG9jYWwgSVAgYWRkcmVzcyAwLjAuMC4wLidcclxuICAgIH0sXHJcbiAgICBob3N0OiB7XHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfSE9TVCcsXHJcbiAgICAgIHZhbHVlOiAnMC4wLjAuMCcsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGhvc3RuYW1lIG9mIHRoZSBzZXJ2ZXIuIEFkZGl0aW9uYWxseSwgaXQgc3RhcnRzIGEgc2VydmVyIG9uIHRoZSBwcm92aWRlZCBob3N0bmFtZS4nXHJcbiAgICB9LFxyXG4gICAgcG9ydDoge1xyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX1BPUlQnLFxyXG4gICAgICB2YWx1ZTogNzgwMSxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHNlcnZlciBwb3J0IHdoZW4gZW5hYmxlZC4nXHJcbiAgICB9LFxyXG4gICAgYmVuY2htYXJraW5nOiB7XHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfQkVOQ0hNQVJLSU5HJyxcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGNsaU5hbWU6ICdzZXJ2ZXJCZW5jaG1hcmtpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSW5kaWNhdGVzIHdoZXRoZXIgdG8gZGlzcGxheSB0aGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgb2Ygc3BlY2lmaWMgYWN0aW9ucyB0aGF0IG9jY3VyIG9uIHRoZSBzZXJ2ZXIgd2hpbGUgc2VydmluZyBhIHJlcXVlc3QuJ1xyXG4gICAgfSxcclxuICAgIHNzbDoge1xyXG4gICAgICBlbmFibGU6IHtcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9FTkFCTEUnLFxyXG4gICAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgICAgY2xpTmFtZTogJ2VuYWJsZVNzbCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIG9yIGRpc2FibGVzIHRoZSBTU0wgcHJvdG9jb2wuJ1xyXG4gICAgICB9LFxyXG4gICAgICBmb3JjZToge1xyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfU1NMX0ZPUkNFJyxcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICAgIGNsaU5hbWU6ICdzc2xGb3JjZWQnLFxyXG4gICAgICAgIGxlZ2FjeU5hbWU6ICdzc2xPbmx5JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAgICdXaGVuIHNldCB0byB0cnVlLCB0aGUgc2VydmVyIGlzIGZvcmNlZCB0byBzZXJ2ZSBvbmx5IG92ZXIgSFRUUFMuJ1xyXG4gICAgICB9LFxyXG4gICAgICBwb3J0OiB7XHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfUE9SVCcsXHJcbiAgICAgICAgdmFsdWU6IDQ0MyxcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgICBjbGlOYW1lOiAnc3NsUG9ydCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgcG9ydCBvbiB3aGljaCB0byBydW4gdGhlIFNTTCBzZXJ2ZXIuJ1xyXG4gICAgICB9LFxyXG4gICAgICBjZXJ0UGF0aDoge1xyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfU1NMX0NFUlRfUEFUSCcsXHJcbiAgICAgICAgdmFsdWU6ICcnLFxyXG4gICAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICAgIGxlZ2FjeU5hbWU6ICdzc2xQYXRoJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSBwYXRoIHRvIHRoZSBTU0wgY2VydGlmaWNhdGUva2V5IGZpbGUuJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgcmF0ZUxpbWl0aW5nOiB7XHJcbiAgICAgIGVuYWJsZToge1xyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19FTkFCTEUnLFxyXG4gICAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgICAgY2xpTmFtZTogJ2VuYWJsZVJhdGVMaW1pdGluZycsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIHJhdGUgbGltaXRpbmcgZm9yIHRoZSBzZXJ2ZXIuJ1xyXG4gICAgICB9LFxyXG4gICAgICBtYXhSZXF1ZXN0czoge1xyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19NQVhfUkVRVUVTVFMnLFxyXG4gICAgICAgIHZhbHVlOiAxMCxcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgICBsZWdhY3lOYW1lOiAncmF0ZUxpbWl0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSBtYXhpbXVtIG51bWJlciBvZiByZXF1ZXN0cyBhbGxvd2VkIGluIG9uZSBtaW51dGUuJ1xyXG4gICAgICB9LFxyXG4gICAgICB3aW5kb3c6IHtcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfV0lORE9XJyxcclxuICAgICAgICB2YWx1ZTogMSxcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSB0aW1lIHdpbmRvdywgaW4gbWludXRlcywgZm9yIHRoZSByYXRlIGxpbWl0aW5nLidcclxuICAgICAgfSxcclxuICAgICAgZGVsYXk6IHtcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfREVMQVknLFxyXG4gICAgICAgIHZhbHVlOiAwLFxyXG4gICAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICAgJ1RoZSBkZWxheSBkdXJhdGlvbiBmb3IgZWFjaCBzdWNjZXNzaXZlIHJlcXVlc3QgYmVmb3JlIHJlYWNoaW5nIHRoZSBtYXhpbXVtIGxpbWl0LidcclxuICAgICAgfSxcclxuICAgICAgdHJ1c3RQcm94eToge1xyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19UUlVTVF9QUk9YWScsXHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1NldCB0aGlzIHRvIHRydWUgaWYgdGhlIHNlcnZlciBpcyBiZWhpbmQgYSBsb2FkIGJhbGFuY2VyLidcclxuICAgICAgfSxcclxuICAgICAgc2tpcEtleToge1xyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX0tFWScsXHJcbiAgICAgICAgdmFsdWU6ICcnLFxyXG4gICAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICAgJ0FsbG93cyBieXBhc3NpbmcgdGhlIHJhdGUgbGltaXRlciBhbmQgc2hvdWxkIGJlIHByb3ZpZGVkIHdpdGggdGhlIHNraXBUb2tlbiBhcmd1bWVudC4nXHJcbiAgICAgIH0sXHJcbiAgICAgIHNraXBUb2tlbjoge1xyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX1RPS0VOJyxcclxuICAgICAgICB2YWx1ZTogJycsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgICAnQWxsb3dzIGJ5cGFzc2luZyB0aGUgcmF0ZSBsaW1pdGVyIGFuZCBzaG91bGQgYmUgcHJvdmlkZWQgd2l0aCB0aGUgc2tpcEtleSBhcmd1bWVudC4nXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIHBvb2w6IHtcclxuICAgIG1pbldvcmtlcnM6IHtcclxuICAgICAgZW52TGluazogJ1BPT0xfTUlOX1dPUktFUlMnLFxyXG4gICAgICB2YWx1ZTogNCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIG51bWJlciBvZiBtaW5pbXVtIGFuZCBpbml0aWFsIHBvb2wgd29ya2VycyB0byBzcGF3bi4nXHJcbiAgICB9LFxyXG4gICAgbWF4V29ya2Vyczoge1xyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9NQVhfV09SS0VSUycsXHJcbiAgICAgIHZhbHVlOiA4LFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbGVnYWN5TmFtZTogJ3dvcmtlcnMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBudW1iZXIgb2YgbWF4aW11bSBwb29sIHdvcmtlcnMgdG8gc3Bhd24uJ1xyXG4gICAgfSxcclxuICAgIHdvcmtMaW1pdDoge1xyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9XT1JLX0xJTUlUJyxcclxuICAgICAgdmFsdWU6IDQwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBudW1iZXIgb2Ygd29yayBwaWVjZXMgdGhhdCBjYW4gYmUgcGVyZm9ybWVkIGJlZm9yZSByZXN0YXJ0aW5nIHRoZSB3b3JrZXIgcHJvY2Vzcy4nXHJcbiAgICB9LFxyXG4gICAgYWNxdWlyZVRpbWVvdXQ6IHtcclxuICAgICAgZW52TGluazogJ1BPT0xfQUNRVUlSRV9USU1FT1VUJyxcclxuICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGR1cmF0aW9uLCBpbiBtaWxsaXNlY29uZHMsIHRvIHdhaXQgZm9yIGFjcXVpcmluZyBhIHJlc291cmNlLidcclxuICAgIH0sXHJcbiAgICBjcmVhdGVUaW1lb3V0OiB7XHJcbiAgICAgIGVudkxpbms6ICdQT09MX0NSRUFURV9USU1FT1VUJyxcclxuICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGR1cmF0aW9uLCBpbiBtaWxsaXNlY29uZHMsIHRvIHdhaXQgZm9yIGNyZWF0aW5nIGEgcmVzb3VyY2UuJ1xyXG4gICAgfSxcclxuICAgIGRlc3Ryb3lUaW1lb3V0OiB7XHJcbiAgICAgIGVudkxpbms6ICdQT09MX0RFU1RST1lfVElNRU9VVCcsXHJcbiAgICAgIHZhbHVlOiA1MDAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCB0byB3YWl0IGZvciBkZXN0cm95aW5nIGEgcmVzb3VyY2UuJ1xyXG4gICAgfSxcclxuICAgIGlkbGVUaW1lb3V0OiB7XHJcbiAgICAgIGVudkxpbms6ICdQT09MX0lETEVfVElNRU9VVCcsXHJcbiAgICAgIHZhbHVlOiAzMDAwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgYWZ0ZXIgd2hpY2ggYW4gaWRsZSByZXNvdXJjZSBpcyBkZXN0cm95ZWQuJ1xyXG4gICAgfSxcclxuICAgIGNyZWF0ZVJldHJ5SW50ZXJ2YWw6IHtcclxuICAgICAgZW52TGluazogJ1BPT0xfQ1JFQVRFX1JFVFJZX0lOVEVSVkFMJyxcclxuICAgICAgdmFsdWU6IDIwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgdG8gd2FpdCBiZWZvcmUgcmV0cnlpbmcgdGhlIGNyZWF0ZSBwcm9jZXNzIGluIGNhc2Ugb2YgYSBmYWlsdXJlLidcclxuICAgIH0sXHJcbiAgICByZWFwZXJJbnRlcnZhbDoge1xyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9SRUFQRVJfSU5URVJWQUwnLFxyXG4gICAgICB2YWx1ZTogMTAwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgYWZ0ZXIgd2hpY2ggdGhlIGNoZWNrIGZvciBpZGxlIHJlc291cmNlcyB0byBkZXN0cm95IGlzIHRyaWdnZXJlZC4nXHJcbiAgICB9LFxyXG4gICAgYmVuY2htYXJraW5nOiB7XHJcbiAgICAgIGVudkxpbms6ICdQT09MX0JFTkNITUFSS0lORycsXHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBjbGlOYW1lOiAncG9vbEJlbmNobWFya2luZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbmRpY2F0ZSB3aGV0aGVyIHRvIHNob3cgc3RhdGlzdGljcyBmb3IgdGhlIHBvb2wgb2YgcmVzb3VyY2VzIG9yIG5vdC4nXHJcbiAgICB9LFxyXG4gICAgbGlzdGVuVG9Qcm9jZXNzRXhpdHM6IHtcclxuICAgICAgZW52TGluazogJ1BPT0xfTElTVEVOX1RPX1BST0NFU1NfRVhJVFMnLFxyXG4gICAgICB2YWx1ZTogdHJ1ZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0RlY2lkZXMgd2hldGhlciBvciBub3QgdG8gYXR0YWNoIHByb2Nlc3MuZXhpdCBoYW5kbGVycy4nXHJcbiAgICB9XHJcbiAgfSxcclxuICBsb2dnaW5nOiB7XHJcbiAgICBsZXZlbDoge1xyXG4gICAgICBlbnZMaW5rOiAnTE9HR0lOR19MRVZFTCcsXHJcbiAgICAgIHZhbHVlOiA0LFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgY2xpTmFtZTogJ2xvZ0xldmVsJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgbG9nZ2luZyBsZXZlbCB0byBiZSB1c2VkLidcclxuICAgIH0sXHJcbiAgICBmaWxlOiB7XHJcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX0ZJTEUnLFxyXG4gICAgICB2YWx1ZTogJ2hpZ2hjaGFydHMtZXhwb3J0LXNlcnZlci5sb2cnLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgY2xpTmFtZTogJ2xvZ0ZpbGUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIG5hbWUgb2YgYSBsb2cgZmlsZS4gVGhlIGxvZ0Rlc3Qgb3B0aW9uIGFsc28gbmVlZHMgdG8gYmUgc2V0IHRvIGVuYWJsZSBmaWxlIGxvZ2dpbmcuJ1xyXG4gICAgfSxcclxuICAgIGRlc3Q6IHtcclxuICAgICAgZW52TGluazogJ0xPR0dJTkdfREVTVCcsXHJcbiAgICAgIHZhbHVlOiAnbG9nLycsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBjbGlOYW1lOiAnbG9nRGVzdCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgcGF0aCB0byBzdG9yZSBsb2cgZmlsZXMuIFRoaXMgYWxzbyBlbmFibGVzIGZpbGUgbG9nZ2luZy4nXHJcbiAgICB9XHJcbiAgfSxcclxuICB1aToge1xyXG4gICAgZW5hYmxlOiB7XHJcbiAgICAgIGVudkxpbms6ICdVSV9FTkFCTEUnLFxyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgY2xpTmFtZTogJ2VuYWJsZVVpJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0VuYWJsZXMgb3IgZGlzYWJsZXMgdGhlIHVzZXIgaW50ZXJmYWNlIChVSSkgZm9yIHRoZSBleHBvcnQgc2VydmVyLidcclxuICAgIH0sXHJcbiAgICByb3V0ZToge1xyXG4gICAgICBlbnZMaW5rOiAnVUlfUk9VVEUnLFxyXG4gICAgICB2YWx1ZTogJy8nLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgY2xpTmFtZTogJ3VpUm91dGUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGVuZHBvaW50IHJvdXRlIHRvIHdoaWNoIHRoZSB1c2VyIGludGVyZmFjZSAoVUkpIHNob3VsZCBiZSBhdHRhY2hlZC4nXHJcbiAgICB9XHJcbiAgfSxcclxuICBvdGhlcjoge1xyXG4gICAgbm9Mb2dvOiB7XHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9OT19MT0dPJyxcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdTa2lwIHByaW50aW5nIHRoZSBsb2dvIG9uIGEgc3RhcnR1cC4gV2lsbCBiZSByZXBsYWNlZCBieSBhIHNpbXBsZSB0ZXh0LidcclxuICAgIH1cclxuICB9XHJcbn07XHJcblxyXG4vLyBUaGUgY29uZmlnIGRlc2NyaXB0aW9ucyBvYmplY3QgZm9yIHRoZSBwcm9tcHRzIGZ1bmN0aW9uYWxpdHkuIEl0IGNvbnRhaW5zXHJcbi8vIGluZm9ybWF0aW9uIGxpa2U6XHJcbi8vICogVHlwZSBvZiBhIHByb21wdFxyXG4vLyAqIE5hbWUgb2YgYW4gb3B0aW9uXHJcbi8vICogU2hvcnQgZGVzY3JpcHRpb24gb2YgYSBjaG9zZW4gb3B0aW9uXHJcbi8vICogSW5pdGlhbCB2YWx1ZVxyXG5leHBvcnQgY29uc3QgcHJvbXB0c0NvbmZpZyA9IHtcclxuICBwdXBwZXRlZXI6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ2xpc3QnLFxyXG4gICAgICBuYW1lOiAnYXJncycsXHJcbiAgICAgIG1lc3NhZ2U6ICdQdXBwZXRlZXIgYXJndW1lbnRzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wdXBwZXRlZXIuYXJncy52YWx1ZS5qb2luKCcsJyksXHJcbiAgICAgIHNlcGFyYXRvcjogJywnXHJcbiAgICB9XHJcbiAgXSxcclxuICBoaWdoY2hhcnRzOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ3ZlcnNpb24nLFxyXG4gICAgICBtZXNzYWdlOiAnSGlnaGNoYXJ0cyB2ZXJzaW9uJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLnZlcnNpb24udmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ2NkblVSTCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgVVJMIG9mIENETicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5jZG5VUkwudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdtdWx0aXNlbGVjdCcsXHJcbiAgICAgIG5hbWU6ICdtb2R1bGVzJyxcclxuICAgICAgbWVzc2FnZTogJ0F2YWlsYWJsZSBtb2R1bGVzJyxcclxuICAgICAgaW5zdHJ1Y3Rpb25zOiAnU3BhY2U6IFNlbGVjdCBzcGVjaWZpYywgQTogU2VsZWN0IGFsbCwgRW50ZXI6IENvbmZpcm0uJyxcclxuICAgICAgY2hvaWNlczogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLm1vZHVsZXMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdsaXN0JyxcclxuICAgICAgbmFtZTogJ3NjcmlwdHMnLFxyXG4gICAgICBtZXNzYWdlOiAnQ3VzdG9tIHNjcmlwdHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuc2NyaXB0cy52YWx1ZS5qb2luKCcsJyksXHJcbiAgICAgIHNlcGFyYXRvcjogJywnXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2ZvcmNlRmV0Y2gnLFxyXG4gICAgICBtZXNzYWdlOiAnRm9yY2UgcmUtZmV0Y2ggdGhlIHNjcmlwdHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuZm9yY2VGZXRjaC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnY2FjaGVQYXRoJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBwYXRoIHRvIHRoZSBjYWNoZSBkaXJlY3RvcnknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuY2FjaGVQYXRoLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBleHBvcnQ6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3NlbGVjdCcsXHJcbiAgICAgIG5hbWU6ICd0eXBlJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBkZWZhdWx0IGV4cG9ydCBmaWxlIHR5cGUnLFxyXG4gICAgICBoaW50OiBgRGVmYXVsdDogJHtkZWZhdWx0Q29uZmlnLmV4cG9ydC50eXBlLnZhbHVlfWAsXHJcbiAgICAgIGluaXRpYWw6IDAsXHJcbiAgICAgIGNob2ljZXM6IFsncG5nJywgJ2pwZWcnLCAncGRmJywgJ3N2ZyddXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnc2VsZWN0JyxcclxuICAgICAgbmFtZTogJ2NvbnN0cicsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgZGVmYXVsdCBjb25zdHJ1Y3RvciBmb3IgSGlnaGNoYXJ0cycsXHJcbiAgICAgIGhpbnQ6IGBEZWZhdWx0OiAke2RlZmF1bHRDb25maWcuZXhwb3J0LmNvbnN0ci52YWx1ZX1gLFxyXG4gICAgICBpbml0aWFsOiAwLFxyXG4gICAgICBjaG9pY2VzOiBbJ2NoYXJ0JywgJ3N0b2NrQ2hhcnQnLCAnbWFwQ2hhcnQnLCAnZ2FudHRDaGFydCddXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2RlZmF1bHRIZWlnaHQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgZmFsbGJhY2sgaGVpZ2h0IG9mIHRoZSBleHBvcnRlZCBjaGFydCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LmRlZmF1bHRIZWlnaHQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnZGVmYXVsdFdpZHRoJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBkZWZhdWx0IGZhbGxiYWNrIHdpZHRoIG9mIHRoZSBleHBvcnRlZCBjaGFydCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LmRlZmF1bHRXaWR0aC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdkZWZhdWx0U2NhbGUnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgZmFsbGJhY2sgc2NhbGUgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5leHBvcnQuZGVmYXVsdFNjYWxlLnZhbHVlLFxyXG4gICAgICBtaW46IDAuMSxcclxuICAgICAgbWF4OiA1XHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3Jhc3Rlcml6YXRpb25UaW1lb3V0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSByZW5kZXJpbmcgd2VicGFnZSB0aW1lb3V0IGluIG1pbGxpc2Vjb25kcycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LnJhc3Rlcml6YXRpb25UaW1lb3V0LnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBjdXN0b21Mb2dpYzogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2FsbG93Q29kZUV4ZWN1dGlvbicsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgZXhlY3V0aW9uIG9mIGN1c3RvbSBjb2RlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5jdXN0b21Mb2dpYy5hbGxvd0NvZGVFeGVjdXRpb24udmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnYWxsb3dGaWxlUmVzb3VyY2VzJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBmaWxlIHJlc291cmNlcycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuY3VzdG9tTG9naWMuYWxsb3dGaWxlUmVzb3VyY2VzLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBzZXJ2ZXI6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdlbmFibGUnLFxyXG4gICAgICBtZXNzYWdlOiAnU3RhcnRzIHRoZSBzZXJ2ZXIgb24gMC4wLjAuMCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLmVuYWJsZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnaG9zdCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdTZXJ2ZXIgaG9zdG5hbWUnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5ob3N0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3BvcnQnLFxyXG4gICAgICBtZXNzYWdlOiAnU2VydmVyIHBvcnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5wb3J0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2JlbmNobWFya2luZycsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgc2VydmVyIGJlbmNobWFya2luZycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLmJlbmNobWFya2luZy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdzc2wuZW5hYmxlJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBTU0wgcHJvdG9jb2wnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wuZW5hYmxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ3NzbC5mb3JjZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdGb3JjZSBzZXJ2aW5nIG9ubHkgb3ZlciBIVFRQUycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnNzbC5mb3JjZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdzc2wucG9ydCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdTU0wgc2VydmVyIHBvcnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wucG9ydC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnc3NsLmNlcnRQYXRoJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBwYXRoIHRvIGZpbmQgdGhlIFNTTCBjZXJ0aWZpY2F0ZS9rZXknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wuY2VydFBhdGgudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLmVuYWJsZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgcmF0ZSBsaW1pdGluZycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy5lbmFibGUudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLm1heFJlcXVlc3RzJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBtYXhpbXVtIHJlcXVlc3RzIGFsbG93ZWQgcGVyIG1pbnV0ZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy5tYXhSZXF1ZXN0cy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcud2luZG93JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSByYXRlLWxpbWl0aW5nIHRpbWUgd2luZG93IGluIG1pbnV0ZXMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcud2luZG93LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5kZWxheScsXHJcbiAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgJ1RoZSBkZWxheSBmb3IgZWFjaCBzdWNjZXNzaXZlIHJlcXVlc3QgYmVmb3JlIHJlYWNoaW5nIHRoZSBtYXhpbXVtJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLmRlbGF5LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy50cnVzdFByb3h5JyxcclxuICAgICAgbWVzc2FnZTogJ1NldCB0byB0cnVlIGlmIGJlaGluZCBhIGxvYWQgYmFsYW5jZXInLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcudHJ1c3RQcm94eS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLnNraXBLZXknLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdBbGxvd3MgYnlwYXNzaW5nIHRoZSByYXRlIGxpbWl0ZXIgd2hlbiBwcm92aWRlZCB3aXRoIHRoZSBza2lwVG9rZW4gYXJndW1lbnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcuc2tpcEtleS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLnNraXBUb2tlbicsXHJcbiAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgJ0FsbG93cyBieXBhc3NpbmcgdGhlIHJhdGUgbGltaXRlciB3aGVuIHByb3ZpZGVkIHdpdGggdGhlIHNraXBLZXkgYXJndW1lbnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcuc2tpcFRva2VuLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBwb29sOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnbWluV29ya2VycycsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgaW5pdGlhbCBudW1iZXIgb2Ygd29ya2VycyB0byBzcGF3bicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5taW5Xb3JrZXJzLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ21heFdvcmtlcnMnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIG1heGltdW0gbnVtYmVyIG9mIHdvcmtlcnMgdG8gc3Bhd24nLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wubWF4V29ya2Vycy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICd3b3JrTGltaXQnLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdUaGUgcGllY2VzIG9mIHdvcmsgdGhhdCBjYW4gYmUgcGVyZm9ybWVkIGJlZm9yZSByZXN0YXJ0aW5nIGEgUHVwcGV0ZWVyIHByb2Nlc3MnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wud29ya0xpbWl0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2FjcXVpcmVUaW1lb3V0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIHRvIHdhaXQgZm9yIGFjcXVpcmluZyBhIHJlc291cmNlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmFjcXVpcmVUaW1lb3V0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2NyZWF0ZVRpbWVvdXQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgY3JlYXRpbmcgYSByZXNvdXJjZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5jcmVhdGVUaW1lb3V0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2Rlc3Ryb3lUaW1lb3V0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIHRvIHdhaXQgZm9yIGRlc3Ryb3lpbmcgYSByZXNvdXJjZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5kZXN0cm95VGltZW91dC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdpZGxlVGltZW91dCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcyBhZnRlciBhbiBpZGxlIHJlc291cmNlIGlzIGRlc3Ryb3llZCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5pZGxlVGltZW91dC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdjcmVhdGVSZXRyeUludGVydmFsJyxcclxuICAgICAgbWVzc2FnZTpcclxuICAgICAgICAnVGhlIHJldHJ5IGludGVydmFsIGluIG1pbGxpc2Vjb25kcyBhZnRlciBhIGNyZWF0ZSBwcm9jZXNzIGZhaWxzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmNyZWF0ZVJldHJ5SW50ZXJ2YWwudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncmVhcGVySW50ZXJ2YWwnLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdUaGUgcmVhcGVyIGludGVydmFsIGluIG1pbGxpc2Vjb25kcyBhZnRlciB0cmlnZ2VyaW5nIHRoZSBjaGVjayBmb3IgaWRsZSByZXNvdXJjZXMgdG8gZGVzdHJveScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5yZWFwZXJJbnRlcnZhbC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdiZW5jaG1hcmtpbmcnLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIGJlbmNobWFya2luZyBmb3IgYSByZXNvdXJjZSBwb29sJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmJlbmNobWFya2luZy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdsaXN0ZW5Ub1Byb2Nlc3NFeGl0cycsXHJcbiAgICAgIG1lc3NhZ2U6ICdTZXQgdG8gZmFsc2UgdG8gc2tpcCBhdHRhY2hpbmcgcHJvY2Vzcy5leGl0IGhhbmRsZXJzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmxpc3RlblRvUHJvY2Vzc0V4aXRzLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBsb2dnaW5nOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnbGV2ZWwnLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdUaGUgbG9nIGxldmVsICgwOiBzaWxlbnQsIDE6IGVycm9yLCAyOiB3YXJuaW5nLCAzOiBub3RpY2UsIDQ6IHZlcmJvc2UsIDU6IGJlbmNobWFyayknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmxvZ2dpbmcubGV2ZWwudmFsdWUsXHJcbiAgICAgIHJvdW5kOiAwLFxyXG4gICAgICBtaW46IDAsXHJcbiAgICAgIG1heDogNVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnZmlsZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdBIGxvZyBmaWxlIG5hbWUuIFNldCB3aXRoIHRoZSAtLWxvZ0Rlc3QgdG8gZW5hYmxlIGZpbGUgbG9nZ2luZycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcubG9nZ2luZy5maWxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdkZXN0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBwYXRoIHRvIGxvZyBmaWxlcy4gRW5hYmxlcyBmaWxlIGxvZ2dpbmcnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmxvZ2dpbmcuZGVzdC52YWx1ZVxyXG4gICAgfVxyXG4gIF0sXHJcbiAgdWk6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdlbmFibGUnLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIFVJIGZvciB0aGUgZXhwb3J0IHNlcnZlcicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcudWkuZW5hYmxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdyb3V0ZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdBIHJvdXRlIHRvIGF0dGFjaCB0aGUgVUknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnVpLnJvdXRlLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBvdGhlcjogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ25vTG9nbycsXHJcbiAgICAgIG1lc3NhZ2U6ICdTa2lwIHByaW50aW5nIHRoZSBsb2dvIG9uIHN0YXJ0dXAuIFJlcGxhY2VkIGJ5IHNpbXBsZSB0ZXh0JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5vdGhlci5ub0xvZ28udmFsdWVcclxuICAgIH1cclxuICBdXHJcbn07XHJcblxyXG4vLyBBYnNvbHV0ZSBwcm9wcyB0aGF0LCBpbiBjYXNlIG9mIG1lcmdpbmcgcmVjdXJzaXZlbHksIG5lZWQgdG8gYmUgZm9yY2UgbWVyZ2VkXHJcbmV4cG9ydCBjb25zdCBhYnNvbHV0ZVByb3BzID0gW1xyXG4gICdvcHRpb25zJyxcclxuICAnZ2xvYmFsT3B0aW9ucycsXHJcbiAgJ3RoZW1lT3B0aW9ucycsXHJcbiAgJ3Jlc291cmNlcycsXHJcbiAgJ3BheWxvYWQnXHJcbl07XHJcblxyXG4vLyBBcmd1bWVudCBuZXN0aW5nIGxldmVsIG9mIGFsbCBleHBvcnQgc2VydmVyIG9wdGlvbnNcclxuZXhwb3J0IGNvbnN0IG5lc3RlZEFyZ3MgPSB7fTtcclxuXHJcbi8qKlxyXG4gKiBSZWN1cnNpdmVseSBjcmVhdGVzIGEgY2hhaW4gb2YgbmVzdGVkIGFyZ3VtZW50cyBmcm9tIGFuIG9iamVjdC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9iaiAtIFRoZSBvYmplY3QgY29udGFpbmluZyBuZXN0ZWQgYXJndW1lbnRzLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcHJvcENoYWluIC0gVGhlIGN1cnJlbnQgY2hhaW4gb2YgbmVzdGVkIHByb3BlcnRpZXNcclxuICogKHVzZWQgaW50ZXJuYWxseSBkdXJpbmcgcmVjdXJzaW9uKS5cclxuICovXHJcbmNvbnN0IGNyZWF0ZU5lc3RlZEFyZ3MgPSAob2JqLCBwcm9wQ2hhaW4gPSAnJykgPT4ge1xyXG4gIE9iamVjdC5rZXlzKG9iaikuZm9yRWFjaCgoaykgPT4ge1xyXG4gICAgaWYgKCFbJ3B1cHBldGVlcicsICdoaWdoY2hhcnRzJ10uaW5jbHVkZXMoaykpIHtcclxuICAgICAgY29uc3QgZW50cnkgPSBvYmpba107XHJcbiAgICAgIGlmICh0eXBlb2YgZW50cnkudmFsdWUgPT09ICd1bmRlZmluZWQnKSB7XHJcbiAgICAgICAgLy8gR28gZGVlcGVyIGluIHRoZSBuZXN0ZWQgYXJndW1lbnRzXHJcbiAgICAgICAgY3JlYXRlTmVzdGVkQXJncyhlbnRyeSwgYCR7cHJvcENoYWlufS4ke2t9YCk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgLy8gQ3JlYXRlIHRoZSBjaGFpbiBvZiBuZXN0ZWQgYXJndW1lbnRzXHJcbiAgICAgICAgbmVzdGVkQXJnc1tlbnRyeS5jbGlOYW1lIHx8IGtdID0gYCR7cHJvcENoYWlufS4ke2t9YC5zdWJzdHJpbmcoMSk7XHJcblxyXG4gICAgICAgIC8vIFN1cHBvcnQgZm9yIHRoZSBsZWdhY3ksIFBoYW50b21KUyBwcm9wZXJ0aWVzIG5hbWVzXHJcbiAgICAgICAgaWYgKGVudHJ5LmxlZ2FjeU5hbWUgIT09IHVuZGVmaW5lZCkge1xyXG4gICAgICAgICAgbmVzdGVkQXJnc1tlbnRyeS5sZWdhY3lOYW1lXSA9IGAke3Byb3BDaGFpbn0uJHtrfWAuc3Vic3RyaW5nKDEpO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0pO1xyXG59O1xyXG5cclxuY3JlYXRlTmVzdGVkQXJncyhkZWZhdWx0Q29uZmlnKTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyBhcHBlbmRGaWxlLCBleGlzdHNTeW5jLCBta2RpclN5bmMgfSBmcm9tICdmcyc7XHJcblxyXG5pbXBvcnQgeyBkZWZhdWx0Q29uZmlnIH0gZnJvbSAnLi9zY2hlbWFzL2NvbmZpZy5qcyc7XHJcblxyXG4vLyBUaGUgYXZhaWxhYmxlIGNvbG9yc1xyXG5jb25zdCBjb2xvcnMgPSBbJ3JlZCcsICd5ZWxsb3cnLCAnYmx1ZScsICdncmF5JywgJ2dyZWVuJ107XHJcblxyXG4vLyBUaGUgZGVmYXVsdCBsb2dnaW5nIGNvbmZpZ1xyXG5sZXQgbG9nZ2luZyA9IHtcclxuICAvLyBGbGFncyBmb3IgbG9nZ2luZyBzdGF0dXNcclxuICB0b0NvbnNvbGU6IHRydWUsXHJcbiAgdG9GaWxlOiBmYWxzZSxcclxuICBwYXRoQ3JlYXRlZDogZmFsc2UsXHJcbiAgLy8gTG9nIGxldmVsc1xyXG4gIGxldmVsc0Rlc2M6IFtcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICdlcnJvcicsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbMF1cclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHRpdGxlOiAnd2FybmluZycsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbMV1cclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHRpdGxlOiAnbm90aWNlJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1syXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICd2ZXJib3NlJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1szXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICdiZW5jaG1hcmsnLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzRdXHJcbiAgICB9XHJcbiAgXSxcclxuICAvLyBMb2cgbGlzdGVuZXJzXHJcbiAgbGlzdGVuZXJzOiBbXVxyXG59O1xyXG5cclxuLy8gR2F0aGVyIGluaXQgbG9nZ2luZyBvcHRpb25zXHJcbmZvciAoY29uc3QgW2tleSwgb3B0aW9uXSBvZiBPYmplY3QuZW50cmllcyhkZWZhdWx0Q29uZmlnLmxvZ2dpbmcpKSB7XHJcbiAgbG9nZ2luZ1trZXldID0gb3B0aW9uLnZhbHVlO1xyXG59XHJcblxyXG4vKipcclxuICogTG9ncyB0aGUgcHJvdmlkZWQgdGV4dHMgdG8gYSBmaWxlLCBpZiBmaWxlIGxvZ2dpbmcgaXMgZW5hYmxlZC4gSXQgY3JlYXRlc1xyXG4gKiB0aGUgbmVjZXNzYXJ5IGRpcmVjdG9yeSBzdHJ1Y3R1cmUgaWYgbm90IGFscmVhZHkgY3JlYXRlZCBhbmQgYXBwZW5kcyB0aGVcclxuICogY29udGVudCwgaW5jbHVkaW5nIGFuIG9wdGlvbmFsIHByZWZpeCwgdG8gdGhlIHNwZWNpZmllZCBsb2cgZmlsZS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmdbXX0gdGV4dHMgLSBBbiBhcnJheSBvZiB0ZXh0cyB0byBiZSBsb2dnZWQuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwcmVmaXggLSBBbiBvcHRpb25hbCBwcmVmaXggdG8gYmUgYWRkZWQgdG8gZWFjaCBsb2cgZW50cnkuXHJcbiAqL1xyXG5jb25zdCBsb2dUb0ZpbGUgPSAodGV4dHMsIHByZWZpeCkgPT4ge1xyXG4gIGlmIChsb2dnaW5nLnRvRmlsZSkge1xyXG4gICAgaWYgKCFsb2dnaW5nLnBhdGhDcmVhdGVkKSB7XHJcbiAgICAgIC8vIENyZWF0ZSBpZiBkb2VzIG5vdCBleGlzdFxyXG4gICAgICAhZXhpc3RzU3luYyhsb2dnaW5nLmRlc3QpICYmIG1rZGlyU3luYyhsb2dnaW5nLmRlc3QpO1xyXG5cclxuICAgICAgLy8gV2Ugbm93IGFzc3VtZSB0aGUgcGF0aCBpcyBhdmFpbGFibGUsIGUuZy4gaXQncyB0aGUgcmVzcG9uc2liaWxpdHlcclxuICAgICAgLy8gb2YgdGhlIHVzZXIgdG8gY3JlYXRlIHRoZSBwYXRoIHdpdGggdGhlIGNvcnJlY3QgYWNjZXNzIHJpZ2h0cy5cclxuICAgICAgbG9nZ2luZy5wYXRoQ3JlYXRlZCA9IHRydWU7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQWRkIHRoZSBjb250ZW50IHRvIGEgZmlsZVxyXG4gICAgYXBwZW5kRmlsZShcclxuICAgICAgYCR7bG9nZ2luZy5kZXN0fSR7bG9nZ2luZy5maWxlfWAsXHJcbiAgICAgIFtwcmVmaXhdLmNvbmNhdCh0ZXh0cykuam9pbignICcpICsgJ1xcbicsXHJcbiAgICAgIChlcnJvcikgPT4ge1xyXG4gICAgICAgIGlmIChlcnJvcikge1xyXG4gICAgICAgICAgY29uc29sZS5sb2coYFtsb2dnZXJdIFVuYWJsZSB0byB3cml0ZSB0byBsb2cgZmlsZTogJHtlcnJvcn1gKTtcclxuICAgICAgICAgIGxvZ2dpbmcudG9GaWxlID0gZmFsc2U7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICApO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBMb2dzIGEgbWVzc2FnZS4gQWNjZXB0cyBhIHZhcmlhYmxlIGFtb3VudCBvZiBhcmd1bWVudHMuIEFyZ3VtZW50cyBhZnRlclxyXG4gKiBgbGV2ZWxgIHdpbGwgYmUgcGFzc2VkIGRpcmVjdGx5IHRvIGNvbnNvbGUubG9nLCBhbmQvb3Igd2lsbCBiZSBqb2luZWRcclxuICogYW5kIGFwcGVuZGVkIHRvIHRoZSBsb2cgZmlsZS5cclxuICpcclxuICogQHBhcmFtIHthbnl9IGFyZ3MgLSBBbiBhcnJheSBvZiBhcmd1bWVudHMgd2hlcmUgdGhlIGZpcnN0IGlzIHRoZSBsb2cgbGV2ZWxcclxuICogYW5kIHRoZSByZXN0IGFyZSBzdHJpbmdzIHRvIGJ1aWxkIGEgbWVzc2FnZSB3aXRoLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGxvZyA9ICguLi5hcmdzKSA9PiB7XHJcbiAgY29uc3QgW25ld0xldmVsLCAuLi50ZXh0c10gPSBhcmdzO1xyXG5cclxuICAvLyBDdXJyZW50IGxvZ2dpbmcgb3B0aW9uc1xyXG4gIGNvbnN0IHsgbGV2ZWwsIGxldmVsc0Rlc2MgfSA9IGxvZ2dpbmc7XHJcblxyXG4gIC8vIENoZWNrIGlmIGxvZyBsZXZlbCBpcyB3aXRoaW4gYSBjb3JyZWN0IHJhbmdlIG9yIGlzIGEgYmVuY2htYXJrIGxvZ1xyXG4gIGlmIChcclxuICAgIG5ld0xldmVsICE9PSA1ICYmXHJcbiAgICAobmV3TGV2ZWwgPT09IDAgfHwgbmV3TGV2ZWwgPiBsZXZlbCB8fCBsZXZlbCA+IGxldmVsc0Rlc2MubGVuZ3RoKVxyXG4gICkge1xyXG4gICAgcmV0dXJuO1xyXG4gIH1cclxuXHJcbiAgLy8gR2V0IHJpZCBvZiB0aGUgR01UIHRleHQgaW5mb3JtYXRpb25cclxuICBjb25zdCBuZXdEYXRlID0gbmV3IERhdGUoKS50b1N0cmluZygpLnNwbGl0KCcoJylbMF0udHJpbSgpO1xyXG5cclxuICAvLyBDcmVhdGUgYSBtZXNzYWdlJ3MgcHJlZml4XHJcbiAgY29uc3QgcHJlZml4ID0gYCR7bmV3RGF0ZX0gWyR7bGV2ZWxzRGVzY1tuZXdMZXZlbCAtIDFdLnRpdGxlfV0gLWA7XHJcblxyXG4gIC8vIENhbGwgYXZhaWxhYmxlIGxvZyBsaXN0ZW5lcnNcclxuICBsb2dnaW5nLmxpc3RlbmVycy5mb3JFYWNoKChmbikgPT4ge1xyXG4gICAgZm4ocHJlZml4LCB0ZXh0cy5qb2luKCcgJykpO1xyXG4gIH0pO1xyXG5cclxuICAvLyBMb2cgdG8gY29uc29sZVxyXG4gIGlmIChsb2dnaW5nLnRvQ29uc29sZSkge1xyXG4gICAgY29uc29sZS5sb2cuYXBwbHkoXHJcbiAgICAgIHVuZGVmaW5lZCxcclxuICAgICAgW3ByZWZpeC50b1N0cmluZygpW2xvZ2dpbmcubGV2ZWxzRGVzY1tuZXdMZXZlbCAtIDFdLmNvbG9yXV0uY29uY2F0KHRleHRzKVxyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIC8vIExvZyB0byBmaWxlXHJcbiAgbG9nVG9GaWxlKHRleHRzLCBwcmVmaXgpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIExvZ3MgYW4gZXJyb3IgbWVzc2FnZSB3aXRoIGl0cyBzdGFjayB0cmFjZS4gT3B0aW9uYWxseSwgYSBjdXN0b20gbWVzc2FnZVxyXG4gKiBjYW4gYmUgcHJvdmlkZWQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBsZXZlbCAtIFRoZSBsb2cgbGV2ZWwuXHJcbiAqIEBwYXJhbSB7RXJyb3J9IGVycm9yIC0gVGhlIGVycm9yIG9iamVjdC5cclxuICogQHBhcmFtIHtzdHJpbmd9IGN1c3RvbU1lc3NhZ2UgLSBBbiBvcHRpb25hbCBjdXN0b20gbWVzc2FnZSB0byBiZSBsb2dnZWQgYWxvbmdcclxuICogd2l0aCB0aGUgZXJyb3IuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbG9nV2l0aFN0YWNrID0gKG5ld0xldmVsLCBlcnJvciwgY3VzdG9tTWVzc2FnZSkgPT4ge1xyXG4gIC8vIEdldCB0aGUgbWFpbiBtZXNzYWdlXHJcbiAgY29uc3QgbWFpbk1lc3NhZ2UgPSBjdXN0b21NZXNzYWdlIHx8IGVycm9yLm1lc3NhZ2U7XHJcblxyXG4gIC8vIEN1cnJlbnQgbG9nZ2luZyBvcHRpb25zXHJcbiAgY29uc3QgeyBsZXZlbCwgbGV2ZWxzRGVzYyB9ID0gbG9nZ2luZztcclxuXHJcbiAgLy8gQ2hlY2sgaWYgbG9nIGxldmVsIGlzIHdpdGhpbiBhIGNvcnJlY3QgcmFuZ2VcclxuICBpZiAobmV3TGV2ZWwgPT09IDAgfHwgbmV3TGV2ZWwgPiBsZXZlbCB8fCBsZXZlbCA+IGxldmVsc0Rlc2MubGVuZ3RoKSB7XHJcbiAgICByZXR1cm47XHJcbiAgfVxyXG5cclxuICAvLyBHZXQgcmlkIG9mIHRoZSBHTVQgdGV4dCBpbmZvcm1hdGlvblxyXG4gIGNvbnN0IG5ld0RhdGUgPSBuZXcgRGF0ZSgpLnRvU3RyaW5nKCkuc3BsaXQoJygnKVswXS50cmltKCk7XHJcblxyXG4gIC8vIENyZWF0ZSBhIG1lc3NhZ2UncyBwcmVmaXhcclxuICBjb25zdCBwcmVmaXggPSBgJHtuZXdEYXRlfSBbJHtsZXZlbHNEZXNjW25ld0xldmVsIC0gMV0udGl0bGV9XSAtYDtcclxuXHJcbiAgLy8gSWYgdGhlIGN1c3RvbU1lc3NhZ2UgZXhpc3RzLCB3ZSB3YW50IHRvIGRpc3BsYXkgdGhlIHdob2xlIHN0YWNrIG1lc3NhZ2VcclxuICBjb25zdCBzdGFja01lc3NhZ2UgPVxyXG4gICAgZXJyb3IubWVzc2FnZSAhPT0gZXJyb3Iuc3RhY2tNZXNzYWdlIHx8IGVycm9yLnN0YWNrTWVzc2FnZSA9PT0gdW5kZWZpbmVkXHJcbiAgICAgID8gZXJyb3Iuc3RhY2tcclxuICAgICAgOiBlcnJvci5zdGFjay5zcGxpdCgnXFxuJykuc2xpY2UoMSkuam9pbignXFxuJyk7XHJcblxyXG4gIC8vIENvbWJpbmUgY3VzdG9tIG1lc3NhZ2Ugb3IgZXJyb3IgbWVzc2FnZSB3aXRoIGVycm9yIHN0YWNrIG1lc3NhZ2VcclxuICBjb25zdCB0ZXh0cyA9IFttYWluTWVzc2FnZSwgJ1xcbicsIHN0YWNrTWVzc2FnZV07XHJcblxyXG4gIC8vIExvZyB0byBjb25zb2xlXHJcbiAgaWYgKGxvZ2dpbmcudG9Db25zb2xlKSB7XHJcbiAgICBjb25zb2xlLmxvZy5hcHBseShcclxuICAgICAgdW5kZWZpbmVkLFxyXG4gICAgICBbcHJlZml4LnRvU3RyaW5nKClbbG9nZ2luZy5sZXZlbHNEZXNjW25ld0xldmVsIC0gMV0uY29sb3JdXS5jb25jYXQoW1xyXG4gICAgICAgIG1haW5NZXNzYWdlW2NvbG9yc1tuZXdMZXZlbCAtIDFdXSxcclxuICAgICAgICAnXFxuJyxcclxuICAgICAgICBzdGFja01lc3NhZ2VcclxuICAgICAgXSlcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICAvLyBDYWxsIGF2YWlsYWJsZSBsb2cgbGlzdGVuZXJzXHJcbiAgbG9nZ2luZy5saXN0ZW5lcnMuZm9yRWFjaCgoZm4pID0+IHtcclxuICAgIGZuKHByZWZpeCwgdGV4dHMuam9pbignICcpKTtcclxuICB9KTtcclxuXHJcbiAgLy8gTG9nIHRvIGZpbGVcclxuICBsb2dUb0ZpbGUodGV4dHMsIHByZWZpeCk7XHJcbn07XHJcblxyXG4vKipcclxuICogU2V0cyB0aGUgbG9nIGxldmVsIHRvIHRoZSBzcGVjaWZpZWQgdmFsdWUuIExvZyBsZXZlbHMgYXJlICgwID0gbm8gbG9nZ2luZyxcclxuICogMSA9IGVycm9yLCAyID0gd2FybmluZywgMyA9IG5vdGljZSwgNCA9IHZlcmJvc2Ugb3IgNSA9IGJlbmNobWFyaylcclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IG5ld0xldmVsIC0gVGhlIG5ldyBsb2cgbGV2ZWwgdG8gYmUgc2V0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHNldExvZ0xldmVsID0gKG5ld0xldmVsKSA9PiB7XHJcbiAgaWYgKG5ld0xldmVsID49IDAgJiYgbmV3TGV2ZWwgPD0gbG9nZ2luZy5sZXZlbHNEZXNjLmxlbmd0aCkge1xyXG4gICAgbG9nZ2luZy5sZXZlbCA9IG5ld0xldmVsO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBFbmFibGVzIGZpbGUgbG9nZ2luZyB3aXRoIHRoZSBzcGVjaWZpZWQgZGVzdGluYXRpb24gYW5kIGxvZyBmaWxlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gbG9nRGVzdCAtIFRoZSBkZXN0aW5hdGlvbiBwYXRoIGZvciBsb2cgZmlsZXMuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBsb2dGaWxlIC0gVGhlIGxvZyBmaWxlIG5hbWUuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZW5hYmxlRmlsZUxvZ2dpbmcgPSAobG9nRGVzdCwgbG9nRmlsZSkgPT4ge1xyXG4gIC8vIFVwZGF0ZSBsb2dnaW5nIG9wdGlvbnNcclxuICBsb2dnaW5nID0ge1xyXG4gICAgLi4ubG9nZ2luZyxcclxuICAgIGRlc3Q6IGxvZ0Rlc3QgfHwgbG9nZ2luZy5kZXN0LFxyXG4gICAgZmlsZTogbG9nRmlsZSB8fCBsb2dnaW5nLmZpbGUsXHJcbiAgICB0b0ZpbGU6IHRydWVcclxuICB9O1xyXG5cclxuICBpZiAobG9nZ2luZy5kZXN0Lmxlbmd0aCA9PT0gMCkge1xyXG4gICAgcmV0dXJuIGxvZygxLCAnW2xvZ2dlcl0gRmlsZSBsb2dnaW5nIGluaXRpYWxpemF0aW9uOiBubyBwYXRoIHN1cHBsaWVkLicpO1xyXG4gIH1cclxuXHJcbiAgaWYgKCFsb2dnaW5nLmRlc3QuZW5kc1dpdGgoJy8nKSkge1xyXG4gICAgbG9nZ2luZy5kZXN0ICs9ICcvJztcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgbG9nZ2luZyB3aXRoIHRoZSBzcGVjaWZpZWQgbG9nZ2luZyBjb25maWd1cmF0aW9uLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gbG9nZ2luZyAtIFRoZSBsb2dnaW5nIGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGluaXRMb2dnaW5nID0gKGxvZ2dpbmcpID0+IHtcclxuICAvLyBTZXQgdGhlIGxvZyBsZXZlbFxyXG4gIHNldExvZ0xldmVsKGxvZ2dpbmcgJiYgcGFyc2VJbnQobG9nZ2luZy5sZXZlbCkpO1xyXG5cclxuICAvLyBTZXQgdGhlIGxvZyBmaWxlIHBhdGggYW5kIG5hbWVcclxuICBpZiAobG9nZ2luZyAmJiBsb2dnaW5nLmRlc3QpIHtcclxuICAgIGVuYWJsZUZpbGVMb2dnaW5nKFxyXG4gICAgICBsb2dnaW5nLmRlc3QsXHJcbiAgICAgIGxvZ2dpbmcuZmlsZSB8fCAnaGlnaGNoYXJ0cy1leHBvcnQtc2VydmVyLmxvZydcclxuICAgICk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEFkZHMgYSBsaXN0ZW5lciBmdW5jdGlvbiB0byB0aGUgbG9nZ2luZyBzeXN0ZW0uXHJcbiAqXHJcbiAqIEBwYXJhbSB7ZnVuY3Rpb259IGZuIC0gVGhlIGxpc3RlbmVyIGZ1bmN0aW9uIHRvIGJlIGFkZGVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGxpc3RlbiA9IChmbikgPT4ge1xyXG4gIGxvZ2dpbmcubGlzdGVuZXJzLnB1c2goZm4pO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFRvZ2dsZXMgdGhlIHN0YW5kYXJkIG91dHB1dCAoY29uc29sZSkgbG9nZ2luZy5cclxuICpcclxuICogQHBhcmFtIHtib29sZWFufSBlbmFibGVkIC0gSWYgdHJ1ZSwgZW5hYmxlcyBjb25zb2xlIGxvZ2dpbmc7IGlmIGZhbHNlLFxyXG4gKiBkaXNhYmxlcyBpdC5cclxuICovXHJcbmV4cG9ydCBjb25zdCB0b2dnbGVTVERPdXQgPSAoZW5hYmxlZCkgPT4ge1xyXG4gIGxvZ2dpbmcudG9Db25zb2xlID0gZW5hYmxlZDtcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBsb2csXHJcbiAgbG9nV2l0aFN0YWNrLFxyXG4gIHNldExvZ0xldmVsLFxyXG4gIGVuYWJsZUZpbGVMb2dnaW5nLFxyXG4gIGluaXRMb2dnaW5nLFxyXG4gIGxpc3RlbixcclxuICB0b2dnbGVTVERPdXRcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuaW1wb3J0IHsgZmlsZVVSTFRvUGF0aCB9IGZyb20gJ3VybCc7XHJcblxyXG5pbXBvcnQgeyBkZWZhdWx0Q29uZmlnIH0gZnJvbSAnLi4vbGliL3NjaGVtYXMvY29uZmlnLmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcblxyXG5jb25zdCBNQVhfQkFDS09GRl9BVFRFTVBUUyA9IDY7XHJcblxyXG5leHBvcnQgY29uc3QgX19kaXJuYW1lID0gZmlsZVVSTFRvUGF0aChuZXcgVVJMKCcuLi8uJywgaW1wb3J0Lm1ldGEudXJsKSk7XHJcblxyXG4vKipcclxuICogQ2xlYXJzIGFuZCBzdGFuZGFyZGl6ZXMgdGV4dCBieSByZXBsYWNpbmcgbXVsdGlwbGUgY29uc2VjdXRpdmUgd2hpdGVzcGFjZVxyXG4gKiBjaGFyYWN0ZXJzIHdpdGggYSBzaW5nbGUgc3BhY2UgYW5kIHRyaW1taW5nIGFueSBsZWFkaW5nIG9yIHRyYWlsaW5nXHJcbiAqIHdoaXRlc3BhY2UuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0ZXh0IC0gVGhlIGlucHV0IHRleHQgdG8gYmUgY2xlYXJlZC5cclxuICogQHBhcmFtIHtSZWdFeHB9IFtydWxlPS9cXHNcXHMrL2ddIC0gVGhlIHJlZ3VsYXIgZXhwcmVzc2lvbiBydWxlIHRvIG1hdGNoXHJcbiAqIG11bHRpcGxlIGNvbnNlY3V0aXZlIHdoaXRlc3BhY2UgY2hhcmFjdGVycy5cclxuICogQHBhcmFtIHtzdHJpbmd9IFtyZXBsYWNlcj0nICddIC0gVGhlIHN0cmluZyB1c2VkIHRvIHJlcGxhY2UgbXVsdGlwbGVcclxuICogY29uc2VjdXRpdmUgd2hpdGVzcGFjZSBjaGFyYWN0ZXJzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSAtIFRoZSBjbGVhcmVkIGFuZCBzdGFuZGFyZGl6ZWQgdGV4dC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBjbGVhclRleHQgPSAodGV4dCwgcnVsZSA9IC9cXHNcXHMrL2csIHJlcGxhY2VyID0gJyAnKSA9PlxyXG4gIHRleHQucmVwbGFjZUFsbChydWxlLCByZXBsYWNlcikudHJpbSgpO1xyXG5cclxuLyoqXHJcbiAqIEltcGxlbWVudHMgYW4gZXhwb25lbnRpYWwgYmFja29mZiBzdHJhdGVneSBmb3IgcmV0cnlpbmcgYSBmdW5jdGlvbiB1bnRpbFxyXG4gKiBhIGNlcnRhaW4gbnVtYmVyIG9mIGF0dGVtcHRzIGFyZSByZWFjaGVkLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBmbiAtIFRoZSBmdW5jdGlvbiB0byBiZSByZXRyaWVkLlxyXG4gKiBAcGFyYW0ge251bWJlcn0gW2F0dGVtcHQ9MF0gLSBUaGUgY3VycmVudCBhdHRlbXB0IG51bWJlci5cclxuICogQHBhcmFtIHsuLi5hbnl9IGFyZ3MgLSBBcmd1bWVudHMgdG8gYmUgcGFzc2VkIHRvIHRoZSBmdW5jdGlvbi5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2V9IC0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIHJlc3VsdCBvZiB0aGUgZnVuY3Rpb25cclxuICogaWYgc3VjY2Vzc2Z1bC5cclxuICpcclxuICogQHRocm93cyB7RXJyb3J9IC0gVGhyb3dzIGFuIGVycm9yIGlmIHRoZSBtYXhpbXVtIG51bWJlciBvZiBhdHRlbXB0c1xyXG4gKiBpcyByZWFjaGVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGV4cEJhY2tvZmYgPSBhc3luYyAoZm4sIGF0dGVtcHQgPSAwLCAuLi5hcmdzKSA9PiB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIFRyeSB0byBjYWxsIHRoZSBmdW5jdGlvblxyXG4gICAgcmV0dXJuIGF3YWl0IGZuKC4uLmFyZ3MpO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAvLyBDYWxjdWxhdGUgZGVsYXkgaW4gbXNcclxuICAgIGNvbnN0IGRlbGF5SW5NcyA9IDIgKiogYXR0ZW1wdCAqIDEwMDA7XHJcblxyXG4gICAgLy8gSWYgdGhlIGF0dGVtcHQgZXhjZWVkcyB0aGUgbWF4aW11bSBhdHRlbXB0cyBvZiByZWFwZWF0LCB0aHJvdyBhbiBlcnJvclxyXG4gICAgaWYgKCsrYXR0ZW1wdCA+PSBNQVhfQkFDS09GRl9BVFRFTVBUUykge1xyXG4gICAgICB0aHJvdyBlcnJvcjtcclxuICAgIH1cclxuXHJcbiAgICAvLyBXYWl0IGdpdmVuIGFtb3VudCBvZiB0aW1lXHJcbiAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzcG9uc2UpID0+IHNldFRpbWVvdXQocmVzcG9uc2UsIGRlbGF5SW5NcykpO1xyXG4gICAgbG9nKFxyXG4gICAgICAzLFxyXG4gICAgICBgW3Bvb2xdIFdhaXRlZCAke2RlbGF5SW5Nc31tcyB1bnRpbCBuZXh0IGNhbGwgZm9yIHRoZSByZXNvdXJjZSBpZDogJHthcmdzWzBdfS5gXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFRyeSBhZ2FpblxyXG4gICAgcmV0dXJuIGV4cEJhY2tvZmYoZm4sIGF0dGVtcHQsIC4uLmFyZ3MpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBGaXhlcyB0aGUgZXhwb3J0IHR5cGUgYmFzZWQgb24gTUlNRSB0eXBlcyBhbmQgZmlsZSBleHRlbnNpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdHlwZSAtIFRoZSBvcmlnaW5hbCBleHBvcnQgdHlwZS5cclxuICogQHBhcmFtIHtzdHJpbmd9IG91dGZpbGUgLSBUaGUgZmlsZSBwYXRoIG9yIG5hbWUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IC0gVGhlIGNvcnJlY3RlZCBleHBvcnQgdHlwZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBmaXhUeXBlID0gKHR5cGUsIG91dGZpbGUpID0+IHtcclxuICAvLyBNSU1FIHR5cGVzXHJcbiAgY29uc3QgbWltZVR5cGVzID0ge1xyXG4gICAgJ2ltYWdlL3BuZyc6ICdwbmcnLFxyXG4gICAgJ2ltYWdlL2pwZWcnOiAnanBlZycsXHJcbiAgICAnYXBwbGljYXRpb24vcGRmJzogJ3BkZicsXHJcbiAgICAnaW1hZ2Uvc3ZnK3htbCc6ICdzdmcnXHJcbiAgfTtcclxuXHJcbiAgLy8gRm9ybWF0c1xyXG4gIGNvbnN0IGZvcm1hdHMgPSBbJ3BuZycsICdqcGVnJywgJ3BkZicsICdzdmcnXTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgdHlwZSBhbmQgb3V0ZmlsZSdzIGV4dGVuc2lvbnMgYXJlIHRoZSBzYW1lXHJcbiAgaWYgKG91dGZpbGUpIHtcclxuICAgIGNvbnN0IG91dFR5cGUgPSBvdXRmaWxlLnNwbGl0KCcuJykucG9wKCk7XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgZXh0ZW5zaW9uIGhhcyBhIGNvcnJlY3QgdHlwZVxyXG4gICAgaWYgKGZvcm1hdHMuaW5jbHVkZXMob3V0VHlwZSkgJiYgdHlwZSAhPT0gb3V0VHlwZSkge1xyXG4gICAgICB0eXBlID0gb3V0VHlwZTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiBhIGNvcnJlY3QgdHlwZVxyXG4gIHJldHVybiBtaW1lVHlwZXNbdHlwZV0gfHwgZm9ybWF0cy5maW5kKCh0KSA9PiB0ID09PSB0eXBlKSB8fCAncG5nJztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBIYW5kbGVzIGFuZCB2YWxpZGF0ZXMgcmVzb3VyY2VzIGZvciBleHBvcnQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fHN0cmluZ30gcmVzb3VyY2VzIC0gVGhlIHJlc291cmNlcyB0byBiZSBoYW5kbGVkLiBDYW4gYmUgZWl0aGVyXHJcbiAqIGEgSlNPTiBvYmplY3QsIHN0cmluZ2lmaWVkIEpTT04gb3IgYSBwYXRoIHRvIGEgSlNPTiBmaWxlLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RmlsZVJlc291cmNlcyAtIFdoZXRoZXIgdG8gYWxsb3cgbG9hZGluZyByZXNvdXJjZXMgZnJvbVxyXG4gKiBmaWxlcy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdHx1bmRlZmluZWR9IC0gVGhlIGhhbmRsZWQgcmVzb3VyY2VzIG9yIHVuZGVmaW5lZCBpZiBubyB2YWxpZFxyXG4gKiByZXNvdXJjZXMgYXJlIGZvdW5kLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGhhbmRsZVJlc291cmNlcyA9IChyZXNvdXJjZXMgPSBmYWxzZSwgYWxsb3dGaWxlUmVzb3VyY2VzKSA9PiB7XHJcbiAgY29uc3QgYWxsb3dlZFByb3BzID0gWydqcycsICdjc3MnLCAnZmlsZXMnXTtcclxuXHJcbiAgbGV0IGhhbmRsZWRSZXNvdXJjZXMgPSByZXNvdXJjZXM7XHJcbiAgbGV0IGNvcnJlY3RSZXNvdXJjZXMgPSBmYWxzZTtcclxuXHJcbiAgLy8gVHJ5IHRvIGxvYWQgcmVzb3VyY2VzIGZyb20gYSBmaWxlXHJcbiAgaWYgKGFsbG93RmlsZVJlc291cmNlcyAmJiByZXNvdXJjZXMuZW5kc1dpdGgoJy5qc29uJykpIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGhhbmRsZWRSZXNvdXJjZXMgPSBpc0NvcnJlY3RKU09OKHJlYWRGaWxlU3luYyhyZXNvdXJjZXMsICd1dGY4JykpO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgcmV0dXJuIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgYFtjbGldIE5vIHJlc291cmNlcyBmb3VuZC5gKTtcclxuICAgIH1cclxuICB9IGVsc2Uge1xyXG4gICAgLy8gVHJ5IHRvIGdldCBKU09OXHJcbiAgICBoYW5kbGVkUmVzb3VyY2VzID0gaXNDb3JyZWN0SlNPTihyZXNvdXJjZXMpO1xyXG5cclxuICAgIC8vIEdldCByaWQgb2YgdGhlIGZpbGVzIHNlY3Rpb25cclxuICAgIGlmIChoYW5kbGVkUmVzb3VyY2VzICYmICFhbGxvd0ZpbGVSZXNvdXJjZXMpIHtcclxuICAgICAgZGVsZXRlIGhhbmRsZWRSZXNvdXJjZXMuZmlsZXM7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBGaWx0ZXIgZnJvbSB1bm5lY2Vzc2FyeSBwcm9wZXJ0aWVzXHJcbiAgZm9yIChjb25zdCBwcm9wTmFtZSBpbiBoYW5kbGVkUmVzb3VyY2VzKSB7XHJcbiAgICBpZiAoIWFsbG93ZWRQcm9wcy5pbmNsdWRlcyhwcm9wTmFtZSkpIHtcclxuICAgICAgZGVsZXRlIGhhbmRsZWRSZXNvdXJjZXNbcHJvcE5hbWVdO1xyXG4gICAgfSBlbHNlIGlmICghY29ycmVjdFJlc291cmNlcykge1xyXG4gICAgICBjb3JyZWN0UmVzb3VyY2VzID0gdHJ1ZTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIENoZWNrIGlmIGF0IGxlYXN0IG9uZSBvZiBhbGxvd2VkIHByb3BlcnRpZXMgaXMgcHJlc2VudFxyXG4gIGlmICghY29ycmVjdFJlc291cmNlcykge1xyXG4gICAgcmV0dXJuIGxvZygzLCBgW2NsaV0gTm8gcmVzb3VyY2VzIGZvdW5kLmApO1xyXG4gIH1cclxuXHJcbiAgLy8gSGFuZGxlIGZpbGVzIHNlY3Rpb25cclxuICBpZiAoaGFuZGxlZFJlc291cmNlcy5maWxlcykge1xyXG4gICAgaGFuZGxlZFJlc291cmNlcy5maWxlcyA9IGhhbmRsZWRSZXNvdXJjZXMuZmlsZXMubWFwKChpdGVtKSA9PiBpdGVtLnRyaW0oKSk7XHJcbiAgICBpZiAoIWhhbmRsZWRSZXNvdXJjZXMuZmlsZXMgfHwgaGFuZGxlZFJlc291cmNlcy5maWxlcy5sZW5ndGggPD0gMCkge1xyXG4gICAgICBkZWxldGUgaGFuZGxlZFJlc291cmNlcy5maWxlcztcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiByZXNvdXJjZXNcclxuICByZXR1cm4gaGFuZGxlZFJlc291cmNlcztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBWYWxpZGF0ZXMgYW5kIHBhcnNlcyBKU09OIGRhdGEuIENoZWNrcyBpZiBwcm92aWRlZCBkYXRhIGlzIG9yIGNhblxyXG4gKiBiZSBhIGNvcnJlY3QgSlNPTi5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R8c3RyaW5nfSBkYXRhIC0gVGhlIEpTT04gZGF0YSB0byBiZSB2YWxpZGF0ZWQgYW5kIHBhcnNlZC5cclxuICogQHBhcmFtIHtib29sZWFufSB0b1N0cmluZyAtIFdoZXRoZXIgdG8gcmV0dXJuIGEgc3RyaW5naWZpZWQgcmVwcmVzZW50YXRpb25cclxuICogb2YgdGhlIHBhcnNlZCBKU09OLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fHN0cmluZ3xib29sZWFufSAtIFRoZSBwYXJzZWQgSlNPTiBvYmplY3QsIHN0cmluZ2lmaWVkIEpTT04sXHJcbiAqIG9yIGZhbHNlIGlmIHZhbGlkYXRpb24gZmFpbHMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gaXNDb3JyZWN0SlNPTihkYXRhLCB0b1N0cmluZykge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBHZXQgdGhlIHN0cmluZyByZXByZXNlbnRhdGlvbiBpZiBub3QgYWxyZWFkeSBiZWZvcmUgcGFyc2luZ1xyXG4gICAgY29uc3QgcGFyc2VkRGF0YSA9IEpTT04ucGFyc2UoXHJcbiAgICAgIHR5cGVvZiBkYXRhICE9PSAnc3RyaW5nJyA/IEpTT04uc3RyaW5naWZ5KGRhdGEpIDogZGF0YVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBSZXR1cm4gYSBzdHJpbmdpZmllZCByZXByZXNlbnRhdGlvbiBvZiBhIEpTT04gaWYgcmVxdWlyZWRcclxuICAgIGlmICh0eXBlb2YgcGFyc2VkRGF0YSAhPT0gJ3N0cmluZycgJiYgdG9TdHJpbmcpIHtcclxuICAgICAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KHBhcnNlZERhdGEpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFJldHVybiBhIEpTT05cclxuICAgIHJldHVybiBwYXJzZWREYXRhO1xyXG4gIH0gY2F0Y2gge1xyXG4gICAgcmV0dXJuIGZhbHNlO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gaXRlbSBpcyBhbiBvYmplY3QuXHJcbiAqXHJcbiAqIEBwYXJhbSB7YW55fSBpdGVtIC0gVGhlIGl0ZW0gdG8gYmUgY2hlY2tlZC5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IC0gVHJ1ZSBpZiB0aGUgaXRlbSBpcyBhbiBvYmplY3QsIGZhbHNlIG90aGVyd2lzZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBpc09iamVjdCA9IChpdGVtKSA9PlxyXG4gIHR5cGVvZiBpdGVtID09PSAnb2JqZWN0JyAmJiAhQXJyYXkuaXNBcnJheShpdGVtKSAmJiBpdGVtICE9PSBudWxsO1xyXG5cclxuLyoqXHJcbiAqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gb2JqZWN0IGlzIGVtcHR5LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gaXRlbSAtIFRoZSBvYmplY3QgdG8gYmUgY2hlY2tlZC5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IC0gVHJ1ZSBpZiB0aGUgb2JqZWN0IGlzIGVtcHR5LCBmYWxzZSBvdGhlcndpc2UuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaXNPYmplY3RFbXB0eSA9IChpdGVtKSA9PlxyXG4gIHR5cGVvZiBpdGVtID09PSAnb2JqZWN0JyAmJiBpdGVtICE9PSBudWxsICYmIE9iamVjdC5rZXlzKGl0ZW0pLmxlbmd0aCA9PT0gMDtcclxuXHJcbi8qKlxyXG4gKiBDaGVja3MgaWYgYSBwcml2YXRlIElQIHJhbmdlIFVSTCBpcyBmb3VuZCBpbiB0aGUgZ2l2ZW4gc3RyaW5nLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gaXRlbSAtIFRoZSBzdHJpbmcgdG8gYmUgY2hlY2tlZCBmb3IgYSBwcml2YXRlIElQIHJhbmdlIFVSTC5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IC0gVHJ1ZSBpZiBhIHByaXZhdGUgSVAgcmFuZ2UgVVJMIGlzIGZvdW5kLCBmYWxzZVxyXG4gKiBvdGhlcndpc2UuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaXNQcml2YXRlUmFuZ2VVcmxGb3VuZCA9IChpdGVtKSA9PiB7XHJcbiAgcmV0dXJuIFtcclxuICAgICdsb2NhbGhvc3QnLFxyXG4gICAgJygxMCkuKC4qKS4oLiopLiguKiknLFxyXG4gICAgJygxMjcpLiguKikuKC4qKS4oLiopJyxcclxuICAgICcoMTcyKS4oMVs2LTldfDJbMC05XXwzWzAtMV0pLiguKikuKC4qKScsXHJcbiAgICAnKDE5MikuKDE2OCkuKC4qKS4oLiopJ1xyXG4gIF0uc29tZSgoaXBSZWdFeCkgPT5cclxuICAgIGl0ZW0ubWF0Y2goYHhsaW5rOmhyZWY9XCIoPzooaHR0cDovL3xodHRwczovLykpPyR7aXBSZWdFeH1gKVxyXG4gICk7XHJcbn07XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhIGRlZXAgY29weSBvZiB0aGUgZ2l2ZW4gb2JqZWN0IG9yIGFycmF5LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdHxBcnJheX0gb2JqIC0gVGhlIG9iamVjdCBvciBhcnJheSB0byBiZSBkZWVwbHkgY29waWVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fEFycmF5fSAtIFRoZSBkZWVwIGNvcHkgb2YgdGhlIHByb3ZpZGVkIG9iamVjdCBvciBhcnJheS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBkZWVwQ29weSA9IChvYmopID0+IHtcclxuICBpZiAob2JqID09PSBudWxsIHx8IHR5cGVvZiBvYmogIT09ICdvYmplY3QnKSB7XHJcbiAgICByZXR1cm4gb2JqO1xyXG4gIH1cclxuXHJcbiAgY29uc3QgY29weSA9IEFycmF5LmlzQXJyYXkob2JqKSA/IFtdIDoge307XHJcblxyXG4gIGZvciAoY29uc3Qga2V5IGluIG9iaikge1xyXG4gICAgaWYgKE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChvYmosIGtleSkpIHtcclxuICAgICAgY29weVtrZXldID0gZGVlcENvcHkob2JqW2tleV0pO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcmV0dXJuIGNvcHk7XHJcbn07XHJcblxyXG4vKipcclxuICogQ29udmVydHMgdGhlIHByb3ZpZGVkIG9wdGlvbnMgb2JqZWN0IHRvIGEgSlNPTi1mb3JtYXR0ZWQgc3RyaW5nIHdpdGggdGhlXHJcbiAqIG9wdGlvbiB0byBwcmVzZXJ2ZSBmdW5jdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IHRvIGJlIGNvbnZlcnRlZCB0byBhIHN0cmluZy5cclxuICogQHBhcmFtIHtib29sZWFufSBhbGxvd0Z1bmN0aW9ucyAtIElmIHNldCB0byB0cnVlLCBmdW5jdGlvbnMgYXJlIHByZXNlcnZlZFxyXG4gKiBpbiB0aGUgb3V0cHV0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSAtIFRoZSBKU09OLWZvcm1hdHRlZCBzdHJpbmcgcmVwcmVzZW50aW5nIHRoZSBvcHRpb25zLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IG9wdGlvbnNTdHJpbmdpZnkgPSAob3B0aW9ucywgYWxsb3dGdW5jdGlvbnMpID0+IHtcclxuICBjb25zdCByZXBsYWNlckNhbGxiYWNrID0gKG5hbWUsIHZhbHVlKSA9PiB7XHJcbiAgICBpZiAodHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJykge1xyXG4gICAgICB2YWx1ZSA9IHZhbHVlLnRyaW0oKTtcclxuXHJcbiAgICAgIC8vIElmIGFsbG93RnVuY3Rpb25zIGlzIHNldCB0byB0cnVlLCBwcmVzZXJ2ZSBmdW5jdGlvbnNcclxuICAgICAgaWYgKFxyXG4gICAgICAgICh2YWx1ZS5zdGFydHNXaXRoKCdmdW5jdGlvbignKSB8fCB2YWx1ZS5zdGFydHNXaXRoKCdmdW5jdGlvbiAoJykpICYmXHJcbiAgICAgICAgdmFsdWUuZW5kc1dpdGgoJ30nKVxyXG4gICAgICApIHtcclxuICAgICAgICB2YWx1ZSA9IGFsbG93RnVuY3Rpb25zXHJcbiAgICAgICAgICA/IGBFWFBfRlVOJHsodmFsdWUgKyAnJykucmVwbGFjZUFsbCgvXFxufFxcdHxcXHIvZywgJyAnKX1FWFBfRlVOYFxyXG4gICAgICAgICAgOiB1bmRlZmluZWQ7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gdHlwZW9mIHZhbHVlID09PSAnZnVuY3Rpb24nXHJcbiAgICAgID8gYEVYUF9GVU4keyh2YWx1ZSArICcnKS5yZXBsYWNlQWxsKC9cXG58XFx0fFxcci9nLCAnICcpfUVYUF9GVU5gXHJcbiAgICAgIDogdmFsdWU7XHJcbiAgfTtcclxuXHJcbiAgLy8gU3RyaW5naWZ5IG9wdGlvbnMgYW5kIGlmIHJlcXVpcmVkLCByZXBsYWNlIHNwZWNpYWwgZnVuY3Rpb25zIG1hcmtzXHJcbiAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KG9wdGlvbnMsIHJlcGxhY2VyQ2FsbGJhY2spLnJlcGxhY2VBbGwoXHJcbiAgICAvXCJFWFBfRlVOfEVYUF9GVU5cIi9nLFxyXG4gICAgJydcclxuICApO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFByaW50cyB0aGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyIGxvZ28gYW5kIHZlcnNpb24gaW5mb3JtYXRpb24uXHJcbiAqXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gbm9Mb2dvIC0gSWYgdHJ1ZSwgb25seSBwcmludHMgdmVyc2lvbiBpbmZvcm1hdGlvbiB3aXRob3V0XHJcbiAqIHRoZSBsb2dvLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHByaW50TG9nbyA9IChub0xvZ28pID0+IHtcclxuICAvLyBHZXQgcGFja2FnZSB2ZXJzaW9uIGVpdGhlciBmcm9tIGVudiBvciBmcm9tIHBhY2thZ2UuanNvblxyXG4gIGNvbnN0IHBhY2thZ2VWZXJzaW9uID0gSlNPTi5wYXJzZShcclxuICAgIHJlYWRGaWxlU3luYyhqb2luKF9fZGlybmFtZSwgJ3BhY2thZ2UuanNvbicpKVxyXG4gICkudmVyc2lvbjtcclxuXHJcbiAgLy8gUHJpbnQgdGV4dCBvbmx5XHJcbiAgaWYgKG5vTG9nbykge1xyXG4gICAgY29uc29sZS5sb2coYFN0YXJ0aW5nIEhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlciB2JHtwYWNrYWdlVmVyc2lvbn0uLi5gKTtcclxuICAgIHJldHVybjtcclxuICB9XHJcblxyXG4gIC8vIFByaW50IHRoZSBsb2dvXHJcbiAgY29uc29sZS5sb2coXHJcbiAgICByZWFkRmlsZVN5bmMoX19kaXJuYW1lICsgJy9tc2cvc3RhcnR1cC5tc2cnKS50b1N0cmluZygpLmJvbGQueWVsbG93LFxyXG4gICAgYHYke3BhY2thZ2VWZXJzaW9ufWBcclxuICApO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFByaW50cyB0aGUgdXNhZ2UgaW5mb3JtYXRpb24gZm9yIENMSSBhcmd1bWVudHMuIElmIHJlcXVpcmVkLCBpdCBjYW4gbGlzdFxyXG4gKiBwcm9wZXJ0aWVzIHJlY3Vyc2l2ZWx5XHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gcHJpbnRVc2FnZSgpIHtcclxuICBjb25zdCBwYWQgPSA0ODtcclxuICBjb25zdCByZWFkbWUgPSAnaHR0cHM6Ly9naXRodWIuY29tL2hpZ2hjaGFydHMvbm9kZS1leHBvcnQtc2VydmVyI3JlYWRtZSc7XHJcblxyXG4gIC8vIERpc3BsYXkgcmVhZG1lIGluZm9ybWF0aW9uXHJcbiAgY29uc29sZS5sb2coXHJcbiAgICAnXFxuVXNhZ2Ugb2YgQ0xJIGFyZ3VtZW50czonLmJvbGQsXHJcbiAgICAnXFxuLS0tLS0tJyxcclxuICAgIGBcXG5Gb3IgbW9yZSBkZXRhaWxlZCBpbmZvcm1hdGlvbiwgdmlzaXQgdGhlIHJlYWRtZSBhdDogJHtyZWFkbWUuYm9sZC55ZWxsb3d9LmBcclxuICApO1xyXG5cclxuICBjb25zdCBjeWNsZUNhdGVnb3JpZXMgPSAob3B0aW9ucykgPT4ge1xyXG4gICAgZm9yIChjb25zdCBbbmFtZSwgb3B0aW9uXSBvZiBPYmplY3QuZW50cmllcyhvcHRpb25zKSkge1xyXG4gICAgICAvLyBJZiBjYXRlZ29yeSBoYXMgbW9yZSBsZXZlbHMsIGdvIGZ1cnRoZXJcclxuICAgICAgaWYgKCFPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob3B0aW9uLCAndmFsdWUnKSkge1xyXG4gICAgICAgIGN5Y2xlQ2F0ZWdvcmllcyhvcHRpb24pO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIGxldCBkZXNjTmFtZSA9IGAgIC0tJHtvcHRpb24uY2xpTmFtZSB8fCBuYW1lfSAke1xyXG4gICAgICAgICAgKCc8JyArIG9wdGlvbi50eXBlICsgJz4nKS5ncmVlblxyXG4gICAgICAgIH0gYDtcclxuICAgICAgICBpZiAoZGVzY05hbWUubGVuZ3RoIDwgcGFkKSB7XHJcbiAgICAgICAgICBmb3IgKGxldCBpID0gZGVzY05hbWUubGVuZ3RoOyBpIDwgcGFkOyBpKyspIHtcclxuICAgICAgICAgICAgZGVzY05hbWUgKz0gJy4nO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gRGlzcGxheSBjb3JyZWN0bHkgYWxpZ25lZCBtZXNzYWdlc1xyXG4gICAgICAgIGNvbnNvbGUubG9nKFxyXG4gICAgICAgICAgZGVzY05hbWUsXHJcbiAgICAgICAgICBvcHRpb24uZGVzY3JpcHRpb24sXHJcbiAgICAgICAgICBgW0RlZmF1bHQ6ICR7b3B0aW9uLnZhbHVlLnRvU3RyaW5nKCkuYm9sZH1dYC5ibHVlXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH07XHJcblxyXG4gIC8vIEN5Y2xlIHRocm91Z2ggb3B0aW9ucyBvZiBlYWNoIGNhdGVnb3JpZXMgYW5kIGRpc3BsYXkgdGhlIHVzYWdlIGluZm9cclxuICBPYmplY3Qua2V5cyhkZWZhdWx0Q29uZmlnKS5mb3JFYWNoKChjYXRlZ29yeSkgPT4ge1xyXG4gICAgLy8gT25seSBwdXBwZXRlZXIgYW5kIGhpZ2hjaGFydHMgY2F0ZWdvcmllcyBjYW5ub3QgYmUgY29uZmlndXJlZCB0aHJvdWdoIENMSVxyXG4gICAgaWYgKCFbJ3B1cHBldGVlcicsICdoaWdoY2hhcnRzJ10uaW5jbHVkZXMoY2F0ZWdvcnkpKSB7XHJcbiAgICAgIGNvbnNvbGUubG9nKGBcXG4ke2NhdGVnb3J5LnRvVXBwZXJDYXNlKCl9YC5yZWQpO1xyXG4gICAgICBjeWNsZUNhdGVnb3JpZXMoZGVmYXVsdENvbmZpZ1tjYXRlZ29yeV0pO1xyXG4gICAgfVxyXG4gIH0pO1xyXG4gIGNvbnNvbGUubG9nKCdcXG4nKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFJvdW5kcyBhIG51bWJlciB0byB0aGUgc3BlY2lmaWVkIHByZWNpc2lvbi5cclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IHZhbHVlIC0gVGhlIG51bWJlciB0byBiZSByb3VuZGVkLlxyXG4gKiBAcGFyYW0ge251bWJlcn0gcHJlY2lzaW9uIC0gVGhlIG51bWJlciBvZiBkZWNpbWFsIHBsYWNlcyB0byByb3VuZCB0by5cclxuICpcclxuICogQHJldHVybnMge251bWJlcn0gLSBUaGUgcm91bmRlZCBudW1iZXIuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgcm91bmROdW1iZXIgPSAodmFsdWUsIHByZWNpc2lvbiA9IDEpID0+IHtcclxuICBjb25zdCBtdWx0aXBsaWVyID0gTWF0aC5wb3coMTAsIHByZWNpc2lvbiB8fCAwKTtcclxuICByZXR1cm4gTWF0aC5yb3VuZCgrdmFsdWUgKiBtdWx0aXBsaWVyKSAvIG11bHRpcGxpZXI7XHJcbn07XHJcblxyXG4vKipcclxuICogQ29udmVydHMgYSB2YWx1ZSB0byBhIGJvb2xlYW4uXHJcbiAqXHJcbiAqIEBwYXJhbSB7YW55fSBpdGVtIC0gVGhlIHZhbHVlIHRvIGJlIGNvbnZlcnRlZCB0byBhIGJvb2xlYW4uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtib29sZWFufSAtIFRoZSBib29sZWFuIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBpbnB1dCB2YWx1ZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCB0b0Jvb2xlYW4gPSAoaXRlbSkgPT5cclxuICBbJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJywgJ05hTicsICcwJywgJyddLmluY2x1ZGVzKGl0ZW0pXHJcbiAgICA/IGZhbHNlXHJcbiAgICA6ICEhaXRlbTtcclxuXHJcbi8qKlxyXG4gKiBXcmFwcyBjdXN0b20gY29kZSB0byBleGVjdXRlIGl0IHNhZmVseS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGN1c3RvbUNvZGUgLSBUaGUgY3VzdG9tIGNvZGUgdG8gYmUgd3JhcHBlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBhbGxvd0ZpbGVSZXNvdXJjZXMgLSBGbGFnIHRvIGFsbG93IGxvYWRpbmcgY29kZSBmcm9tIGEgZmlsZS5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ3xib29sZWFufSAtIFRoZSB3cmFwcGVkIGN1c3RvbSBjb2RlIG9yIGZhbHNlIGlmIHdyYXBwaW5nXHJcbiAqIGZhaWxzLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHdyYXBBcm91bmQgPSAoY3VzdG9tQ29kZSwgYWxsb3dGaWxlUmVzb3VyY2VzKSA9PiB7XHJcbiAgaWYgKGN1c3RvbUNvZGUgJiYgdHlwZW9mIGN1c3RvbUNvZGUgPT09ICdzdHJpbmcnKSB7XHJcbiAgICBjdXN0b21Db2RlID0gY3VzdG9tQ29kZS50cmltKCk7XHJcblxyXG4gICAgaWYgKGN1c3RvbUNvZGUuZW5kc1dpdGgoJy5qcycpKSB7XHJcbiAgICAgIHJldHVybiBhbGxvd0ZpbGVSZXNvdXJjZXNcclxuICAgICAgICA/IHdyYXBBcm91bmQocmVhZEZpbGVTeW5jKGN1c3RvbUNvZGUsICd1dGY4JykpXHJcbiAgICAgICAgOiBmYWxzZTtcclxuICAgIH0gZWxzZSBpZiAoXHJcbiAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnZnVuY3Rpb24oKScpIHx8XHJcbiAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnZnVuY3Rpb24gKCknKSB8fFxyXG4gICAgICBjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJygpPT4nKSB8fFxyXG4gICAgICBjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJygpID0+JylcclxuICAgICkge1xyXG4gICAgICByZXR1cm4gYCgke2N1c3RvbUNvZGV9KSgpYDtcclxuICAgIH1cclxuICAgIHJldHVybiBjdXN0b21Db2RlLnJlcGxhY2UoLzskLywgJycpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBVdGlsaXR5IHRvIG1lYXN1cmUgZWxhcHNlZCB0aW1lIHVzaW5nIHRoZSBOb2RlLmpzIHByb2Nlc3MuaHJ0aW1lKCkgbWV0aG9kLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7ZnVuY3Rpb24oKTogbnVtYmVyfSAtIEEgZnVuY3Rpb24gdG8gY2FsY3VsYXRlIHRoZSBlbGFwc2VkIHRpbWVcclxuICogaW4gbWlsbGlzZWNvbmRzLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IG1lYXN1cmVUaW1lID0gKCkgPT4ge1xyXG4gIGNvbnN0IHN0YXJ0ID0gcHJvY2Vzcy5ocnRpbWUuYmlnaW50KCk7XHJcbiAgcmV0dXJuICgpID0+IE51bWJlcihwcm9jZXNzLmhydGltZS5iaWdpbnQoKSAtIHN0YXJ0KSAvIDEwMDAwMDA7XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgX19kaXJuYW1lLFxyXG4gIGNsZWFyVGV4dCxcclxuICBleHBCYWNrb2ZmLFxyXG4gIGZpeFR5cGUsXHJcbiAgaGFuZGxlUmVzb3VyY2VzLFxyXG4gIGlzQ29ycmVjdEpTT04sXHJcbiAgaXNPYmplY3QsXHJcbiAgaXNPYmplY3RFbXB0eSxcclxuICBpc1ByaXZhdGVSYW5nZVVybEZvdW5kLFxyXG4gIG9wdGlvbnNTdHJpbmdpZnksXHJcbiAgcHJpbnRMb2dvLFxyXG4gIHByaW50VXNhZ2UsXHJcbiAgcm91bmROdW1iZXIsXHJcbiAgdG9Cb29sZWFuLFxyXG4gIHdyYXBBcm91bmQsXHJcbiAgbWVhc3VyZVRpbWVcclxufTtcclxuIiwiY2xhc3MgRXhwb3J0RXJyb3IgZXh0ZW5kcyBFcnJvciB7XHJcbiAgY29uc3RydWN0b3IobWVzc2FnZSkge1xyXG4gICAgc3VwZXIoKTtcclxuICAgIHRoaXMubWVzc2FnZSA9IG1lc3NhZ2U7XHJcbiAgICB0aGlzLnN0YWNrTWVzc2FnZSA9IG1lc3NhZ2U7XHJcbiAgfVxyXG5cclxuICBzZXRFcnJvcihlcnJvcikge1xyXG4gICAgdGhpcy5lcnJvciA9IGVycm9yO1xyXG4gICAgaWYgKGVycm9yLm5hbWUpIHtcclxuICAgICAgdGhpcy5uYW1lID0gZXJyb3IubmFtZTtcclxuICAgIH1cclxuICAgIGlmIChlcnJvci5zdGF0dXNDb2RlKSB7XHJcbiAgICAgIHRoaXMuc3RhdHVzQ29kZSA9IGVycm9yLnN0YXR1c0NvZGU7XHJcbiAgICB9XHJcbiAgICBpZiAoZXJyb3Iuc3RhY2spIHtcclxuICAgICAgdGhpcy5zdGFja01lc3NhZ2UgPSBlcnJvci5tZXNzYWdlO1xyXG4gICAgICB0aGlzLnN0YWNrID0gZXJyb3Iuc3RhY2s7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gdGhpcztcclxuICB9XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IEV4cG9ydEVycm9yO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8vIFRoZSBjYWNoZSBtYW5hZ2VyIG1hbmFnZXMgdGhlIEhpZ2hjaGFydHMgbGlicmFyeSBhbmQgaXRzIGRlcGVuZGVuY2llcy5cclxuLy8gVGhlIGNhY2hlIGl0c2VsZiBpcyBzdG9yZWQgaW4gLmNhY2hlLCBhbmQgaXMgY2hlY2tlZCBieSB0aGUgY29uZmlnIHN5c3RlbVxyXG4vLyBiZWZvcmUgc3RhcnRpbmcgdGhlIHNlcnZpY2VcclxuXHJcbmltcG9ydCB7IGV4aXN0c1N5bmMsIG1rZGlyU3luYywgcmVhZEZpbGVTeW5jLCB3cml0ZUZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgeyBIdHRwc1Byb3h5QWdlbnQgfSBmcm9tICdodHRwcy1wcm94eS1hZ2VudCc7XHJcblxyXG5pbXBvcnQgeyBmZXRjaCB9IGZyb20gJy4vZmV0Y2guanMnO1xyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IF9fZGlybmFtZSB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbmNvbnN0IGNhY2hlID0ge1xyXG4gIGNkblVSTDogJ2h0dHBzOi8vY29kZS5oaWdoY2hhcnRzLmNvbS8nLFxyXG4gIGFjdGl2ZU1hbmlmZXN0OiB7fSxcclxuICBzb3VyY2VzOiAnJyxcclxuICBoY1ZlcnNpb246ICcnXHJcbn07XHJcblxyXG4vLyBUT0RPOiBUaGUgY29uZmlnIHNob3VsZCBiZSBhY2Nlc3NzaWJsZSBnbG9iYWxseSBzbyB3ZSBkb24ndCBoYXZlIHRvIGRvIHRoaXMgc29ydCBvZiB0aGluZy4uXHJcbmxldCBhcHBsaWVkQ29uZmlnID0gZmFsc2U7XHJcblxyXG4vKipcclxuICogRXh0cmFjdHMgYW5kIGNhY2hlcyB0aGUgSGlnaGNoYXJ0cyB2ZXJzaW9uIGZyb20gdGhlIHNvdXJjZXMgc3RyaW5nLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgZXh0cmFjdGVkIEhpZ2hjaGFydHMgdmVyc2lvbi5cclxuICovXHJcbmNvbnN0IGV4dHJhY3RWZXJzaW9uID0gKCkgPT5cclxuICAoY2FjaGUuaGNWZXJzaW9uID0gY2FjaGUuc291cmNlc1xyXG4gICAgLnN1YnN0cmluZygwLCBjYWNoZS5zb3VyY2VzLmluZGV4T2YoJyovJykpXHJcbiAgICAucmVwbGFjZSgnLyonLCAnJylcclxuICAgIC5yZXBsYWNlKCcqLycsICcnKVxyXG4gICAgLnJlcGxhY2UoL1xcbi9nLCAnJylcclxuICAgIC50cmltKCkpO1xyXG5cclxuLyoqXHJcbiAqIEV4dHJhY3RzIHRoZSBIaWdoY2hhcnRzIG1vZHVsZSBuYW1lIGJhc2VkIG9uIHRoZSBzY3JpcHRQYXRoLlxyXG4gKi9cclxuY29uc3QgZXh0cmFjdE1vZHVsZU5hbWUgPSAoc2NyaXB0UGF0aCkgPT4ge1xyXG4gIHJldHVybiBzY3JpcHRQYXRoLnJlcGxhY2UoXHJcbiAgICAvKC4qKVxcL3woLiopbW9kdWxlc1xcL3xzdG9ja1xcLyguKilpbmRpY2F0b3JzXFwvfG1hcHNcXC8oLiopbW9kdWxlc1xcLy9naSxcclxuICAgICcnXHJcbiAgKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBTYXZlcyB0aGUgcHJvdmlkZWQgY29uZmlndXJhdGlvbiBhbmQgZmV0Y2hlZCBtb2R1bGVzIHRvIHRoZSBjYWNoZSBtYW5pZmVzdFxyXG4gKiBmaWxlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge29iamVjdH0gY29uZmlnIC0gSGlnaGNoYXJ0cy1yZWxhdGVkIGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxyXG4gKiBAcGFyYW0ge29iamVjdH0gZmV0Y2hlZE1vZHVsZXMgLSBBbiBvYmplY3QgdGhhdCBjb250YWlucyBtYXBwZWQgbmFtZXMgb2ZcclxuICogZmV0Y2hlZCBIaWdoY2hhcnRzIG1vZHVsZXMgdG8gdXNlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIGFuIGVycm9yIG9jY3VycyB3aGlsZSB3cml0aW5nXHJcbiAqIHRoZSBjYWNoZSBtYW5pZmVzdC5cclxuICovXHJcbmNvbnN0IHNhdmVDb25maWdUb01hbmlmZXN0ID0gYXN5bmMgKGNvbmZpZywgZmV0Y2hlZE1vZHVsZXMpID0+IHtcclxuICBjb25zdCBuZXdNYW5pZmVzdCA9IHtcclxuICAgIHZlcnNpb246IGNvbmZpZy52ZXJzaW9uLFxyXG4gICAgbW9kdWxlczogZmV0Y2hlZE1vZHVsZXMgfHwge31cclxuICB9O1xyXG5cclxuICAvLyBVcGRhdGUgY2FjaGUgb2JqZWN0IHdpdGggdGhlIGN1cnJlbnQgbW9kdWxlc1xyXG4gIGNhY2hlLmFjdGl2ZU1hbmlmZXN0ID0gbmV3TWFuaWZlc3Q7XHJcblxyXG4gIGxvZygzLCAnW2NhY2hlXSBXcml0aW5nIGEgbmV3IG1hbmlmZXN0LicpO1xyXG4gIHRyeSB7XHJcbiAgICB3cml0ZUZpbGVTeW5jKFxyXG4gICAgICBqb2luKF9fZGlybmFtZSwgY29uZmlnLmNhY2hlUGF0aCwgJ21hbmlmZXN0Lmpzb24nKSxcclxuICAgICAgSlNPTi5zdHJpbmdpZnkobmV3TWFuaWZlc3QpLFxyXG4gICAgICAndXRmOCdcclxuICAgICk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW2NhY2hlXSBFcnJvciB3cml0aW5nIHRoZSBjYWNoZSBtYW5pZmVzdC4nKS5zZXRFcnJvcihcclxuICAgICAgZXJyb3JcclxuICAgICk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEZldGNoZXMgYSBzaW5nbGUgc2NyaXB0IGFuZCB1cGRhdGVzIHRoZSBmZXRjaGVkTW9kdWxlcyBhY2NvcmRpbmdseS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHNjcmlwdCAtIEEgcGF0aCB0byBzY3JpcHQgdG8gZ2V0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcHJveHlBZ2VudCAtIFRoZSBwcm94eSBhZ2VudCB0byB1c2UgZm9yIGEgcmVxdWVzdC5cclxuICogQHBhcmFtIHtPYmplY3R9IGZldGNoZWRNb2R1bGVzIC0gQW4gb2JqZWN0IHdoaWNoIHRyYWNrcyB3aGljaCBIaWdoY2hhcnRzIG1vZHVsZXMgaGF2ZSBiZWVuIGZldGNoZWQuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gc2hvdWxkVGhyb3dFcnJvciAtIEEgZmxhZyB0byBpbmRpY2F0ZSBpZiB0aGUgZXJyb3Igc2hvdWxkIGJlIHRocm93bi4gVGhpcyBzaG91bGQgYmUgdXNlZCBvbmx5IGZvciB0aGUgY29yZSBzY3JpcHRzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSB0ZXh0IHJlcHJlc2VudGF0aW9uXHJcbiAqIG9mIHRoZSBmZXRjaGVkIHNjcmlwdC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiB0aGVyZSBpcyBhIHByb2JsZW0gd2l0aFxyXG4gKiBmZXRjaGluZyB0aGUgc2NyaXB0LlxyXG4gKi9cclxuY29uc3QgZmV0Y2hBbmRQcm9jZXNzU2NyaXB0ID0gYXN5bmMgKFxyXG4gIHNjcmlwdCxcclxuICBwcm94eUFnZW50LFxyXG4gIGZldGNoZWRNb2R1bGVzLFxyXG4gIHNob3VsZFRocm93RXJyb3IgPSBmYWxzZVxyXG4pID0+IHtcclxuICAvLyBHZXQgcmlkIG9mIHRoZSAuanMgZnJvbSB0aGUgY3VzdG9tIHN0cmluZ3NcclxuICBpZiAoc2NyaXB0LmVuZHNXaXRoKCcuanMnKSkge1xyXG4gICAgc2NyaXB0ID0gc2NyaXB0LnN1YnN0cmluZygwLCBzY3JpcHQubGVuZ3RoIC0gMyk7XHJcbiAgfVxyXG5cclxuICBsb2coNCwgYFtjYWNoZV0gRmV0Y2hpbmcgc2NyaXB0IC0gJHtzY3JpcHR9LmpzYCk7XHJcblxyXG4gIC8vIElmIGV4aXN0cywgYWRkIHByb3h5IGFnZW50IHRvIHJlcXVlc3Qgb3B0aW9uc1xyXG4gIGNvbnN0IHJlcXVlc3RPcHRpb25zID0gcHJveHlBZ2VudFxyXG4gICAgPyB7XHJcbiAgICAgICAgYWdlbnQ6IHByb3h5QWdlbnQsXHJcbiAgICAgICAgdGltZW91dDogK3Byb2Nlc3MuZW52WydQUk9YWV9TRVJWRVJfVElNRU9VVCddIHx8IDUwMDBcclxuICAgICAgfVxyXG4gICAgOiB7fTtcclxuXHJcbiAgLy8gRmV0Y2ggdGhlIHNjcmlwdFxyXG4gIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2goYCR7c2NyaXB0fS5qc2AsIHJlcXVlc3RPcHRpb25zKTtcclxuXHJcbiAgLy8gSWYgT0ssIHJldHVybiBpdHMgdGV4dCByZXByZXNlbnRhdGlvblxyXG4gIGlmIChyZXNwb25zZS5zdGF0dXNDb2RlID09PSAyMDAgJiYgdHlwZW9mIHJlc3BvbnNlLnRleHQgPT0gJ3N0cmluZycpIHtcclxuICAgIGlmIChmZXRjaGVkTW9kdWxlcykge1xyXG4gICAgICBjb25zdCBtb2R1bGVOYW1lID0gZXh0cmFjdE1vZHVsZU5hbWUoc2NyaXB0KTtcclxuICAgICAgZmV0Y2hlZE1vZHVsZXNbbW9kdWxlTmFtZV0gPSAxO1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiByZXNwb25zZS50ZXh0O1xyXG4gIH1cclxuXHJcbiAgaWYgKHNob3VsZFRocm93RXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgYENvdWxkIG5vdCBmZXRjaCB0aGUgJHtzY3JpcHR9LmpzLiBUaGUgc2NyaXB0IG1pZ2h0IG5vdCBleGlzdCBpbiB0aGUgcmVxdWVzdGVkIHZlcnNpb24gKHN0YXR1cyBjb2RlOiAke3Jlc3BvbnNlLnN0YXR1c0NvZGV9KS5gXHJcbiAgICApLnNldEVycm9yKHJlc3BvbnNlKTtcclxuICB9IGVsc2Uge1xyXG4gICAgbG9nKFxyXG4gICAgICAyLFxyXG4gICAgICBgW2NhY2hlXSBDb3VsZCBub3QgZmV0Y2ggdGhlICR7c2NyaXB0fS5qcy4gVGhlIHNjcmlwdCBtaWdodCBub3QgZXhpc3QgaW4gdGhlIHJlcXVlc3RlZCB2ZXJzaW9uLmBcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICByZXR1cm4gJyc7XHJcbn07XHJcblxyXG4vKipcclxuICogRmV0Y2hlcyBIaWdoY2hhcnRzIHNjcmlwdHMgYW5kIGN1c3RvbVNjcmlwdHMgZnJvbSB0aGUgZ2l2ZW4gQ0ROcy5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHNjcmlwdHMgLSBBcnJheSBvZiBIaWdoY2hhcnRzIG1vZHVsZXMgdG8gZmV0Y2guXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBjdXN0b21TY3JpcHRzIC0gQXJyYXkgb2YgY3VzdG9tIHNjcmlwdCBwYXRocyB0byBmZXRjaCAoZnVsbCBVUkxzKS5cclxuICogQHBhcmFtIHtvYmplY3R9IHByb3h5QWdlbnQgLSBUaGUgcHJveHkgYWdlbnQgdG8gdXNlIGZvciBhIHJlcXVlc3QuXHJcbiAqIEBwYXJhbSB7b2JqZWN0fSBmZXRjaGVkTW9kdWxlcyAtIEFuIG9iamVjdCB3aGljaCB0cmFja3Mgd2hpY2ggSGlnaGNoYXJ0cyBtb2R1bGVzIGhhdmUgYmVlbiBmZXRjaGVkLlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSBUaGUgZmV0Y2hlZCBzY3JpcHRzIGNvbnRlbnQgam9pbmVkLlxyXG4gKi9cclxuY29uc3QgZmV0Y2hTY3JpcHRzID0gYXN5bmMgKFxyXG4gIGNvcmVTY3JpcHRzLFxyXG4gIG1vZHVsZVNjcmlwdHMsXHJcbiAgY3VzdG9tU2NyaXB0cyxcclxuICBjZG5VUkwsXHJcbiAgcHJveHlBZ2VudCxcclxuICBmZXRjaGVkTW9kdWxlc1xyXG4pID0+IHtcclxuICBjb25zdCBhbGxGZXRjaFByb21pc2VzID0gW1xyXG4gICAgLi4uY29yZVNjcmlwdHMubWFwKChzY3JpcHQpID0+XHJcbiAgICAgIGZldGNoQW5kUHJvY2Vzc1NjcmlwdChcclxuICAgICAgICBgJHtjZG5VUkx9JHtzY3JpcHR9YCxcclxuICAgICAgICBwcm94eUFnZW50LFxyXG4gICAgICAgIGZldGNoZWRNb2R1bGVzLFxyXG4gICAgICAgIHRydWVcclxuICAgICAgKVxyXG4gICAgKSxcclxuICAgIC4uLm1vZHVsZVNjcmlwdHMubWFwKChzY3JpcHQpID0+XHJcbiAgICAgIGZldGNoQW5kUHJvY2Vzc1NjcmlwdChgJHtjZG5VUkx9JHtzY3JpcHR9YCwgcHJveHlBZ2VudCwgZmV0Y2hlZE1vZHVsZXMpXHJcbiAgICApLFxyXG4gICAgLi4uY3VzdG9tU2NyaXB0cy5tYXAoKHNjcmlwdCkgPT5cclxuICAgICAgZmV0Y2hBbmRQcm9jZXNzU2NyaXB0KGAke3NjcmlwdH1gLCBwcm94eUFnZW50KVxyXG4gICAgKVxyXG4gIF07XHJcblxyXG4gIGNvbnN0IGZldGNoZWRTY3JpcHRzID0gYXdhaXQgUHJvbWlzZS5hbGwoYWxsRmV0Y2hQcm9taXNlcyk7XHJcbiAgcmV0dXJuIGZldGNoZWRTY3JpcHRzLmpvaW4oJztcXG4nKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBVcGRhdGVzIHRoZSBsb2NhbCBjYWNoZSB3aXRoIEhpZ2hjaGFydHMgc2NyaXB0cyBhbmQgdGhlaXIgdmVyc2lvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjb25maWcgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZyBpbmZvcm1hdGlvblxyXG4gKiBhYm91dCBzY3JpcHRzIGFuZCBtb2R1bGVzLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gc291cmNlUGF0aCAtIFRoZSBwYXRoIHRvIHRoZSBzb3VyY2UgZmlsZSBpbiB0aGUgY2FjaGUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPG9iamVjdD59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gYW4gb2JqZWN0IHJlcHJlc2VudGluZ1xyXG4gKiB0aGUgZmV0Y2hlZCBtb2R1bGVzLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIHRoZXJlIGlzIGFuIGlzc3VlIHVwZGF0aW5nXHJcbiAqIHRoZSBsb2NhbCBIaWdoY2hhcnRzIGNhY2hlLlxyXG4gKi9cclxuY29uc3QgdXBkYXRlQ2FjaGUgPSBhc3luYyAoY29uZmlnLCBzb3VyY2VQYXRoKSA9PiB7XHJcbiAgY29uc3QgeyBjb3JlU2NyaXB0cywgbW9kdWxlcywgaW5kaWNhdG9ycywgc2NyaXB0czogY3VzdG9tU2NyaXB0cyB9ID0gY29uZmlnO1xyXG4gIGNvbnN0IGhjVmVyc2lvbiA9XHJcbiAgICBjb25maWcudmVyc2lvbiA9PT0gJ2xhdGVzdCcgfHwgIWNvbmZpZy52ZXJzaW9uID8gJycgOiBgJHtjb25maWcudmVyc2lvbn0vYDtcclxuXHJcbiAgbG9nKFxyXG4gICAgMyxcclxuICAgIGBbY2FjaGVdIFVwZGF0aW5nIGNhY2hlIHZlcnNpb24gdG8gSGlnaGNoYXJ0czogJHtoY1ZlcnNpb24gfHwgJ2xhdGVzdCd9LmBcclxuICApO1xyXG5cclxuICAvLyBDb25maWd1cmUgcHJveHkgaWYgZXhpc3RzXHJcbiAgbGV0IHByb3h5QWdlbnQ7XHJcbiAgY29uc3QgcHJveHlIb3N0ID0gcHJvY2Vzcy5lbnZbJ1BST1hZX1NFUlZFUl9IT1NUJ107XHJcbiAgY29uc3QgcHJveHlQb3J0ID0gcHJvY2Vzcy5lbnZbJ1BST1hZX1NFUlZFUl9QT1JUJ107XHJcblxyXG4gIC8vIFRyeSB0byBjcmVhdGUgYSBQcm94eSBBZ2VudFxyXG4gIGlmIChwcm94eUhvc3QgJiYgcHJveHlQb3J0KSB7XHJcbiAgICB0cnkge1xyXG4gICAgICBwcm94eUFnZW50ID0gbmV3IEh0dHBzUHJveHlBZ2VudCh7XHJcbiAgICAgICAgaG9zdDogcHJveHlIb3N0LFxyXG4gICAgICAgIHBvcnQ6ICtwcm94eVBvcnRcclxuICAgICAgfSk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1tjYWNoZV0gQ291bGQgbm90IGNyZWF0ZSBhIFByb3h5IEFnZW50LicpLnNldEVycm9yKFxyXG4gICAgICAgIGVycm9yXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBjb25zdCBmZXRjaGVkTW9kdWxlcyA9IHt9O1xyXG4gIHRyeSB7XHJcbiAgICBjYWNoZS5zb3VyY2VzID0gYXdhaXQgZmV0Y2hTY3JpcHRzKFxyXG4gICAgICBbLi4uY29yZVNjcmlwdHMubWFwKChjKSA9PiBgJHtoY1ZlcnNpb259JHtjfWApXSxcclxuICAgICAgW1xyXG4gICAgICAgIC4uLm1vZHVsZXMubWFwKChtKSA9PlxyXG4gICAgICAgICAgbSA9PT0gJ21hcCdcclxuICAgICAgICAgICAgPyBgbWFwcy8ke2hjVmVyc2lvbn1tb2R1bGVzLyR7bX1gXHJcbiAgICAgICAgICAgIDogYCR7aGNWZXJzaW9ufW1vZHVsZXMvJHttfWBcclxuICAgICAgICApLFxyXG4gICAgICAgIC4uLmluZGljYXRvcnMubWFwKChpKSA9PiBgc3RvY2svJHtoY1ZlcnNpb259aW5kaWNhdG9ycy8ke2l9YClcclxuICAgICAgXSxcclxuICAgICAgY3VzdG9tU2NyaXB0cyxcclxuICAgICAgY29uZmlnLmNkblVSTCB8fCBjYWNoZS5jZG5VUkwsXHJcbiAgICAgIHByb3h5QWdlbnQsXHJcbiAgICAgIGZldGNoZWRNb2R1bGVzXHJcbiAgICApO1xyXG4gICAgZXh0cmFjdFZlcnNpb24oKTtcclxuXHJcbiAgICAvLyBTYXZlIHRoZSBmZXRjaGVkIG1vZHVsZXMgaW50byBjYWNoZXMnIHNvdXJjZSBKU09OXHJcbiAgICB3cml0ZUZpbGVTeW5jKHNvdXJjZVBhdGgsIGNhY2hlLnNvdXJjZXMpO1xyXG4gICAgcmV0dXJuIGZldGNoZWRNb2R1bGVzO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbY2FjaGVdIFVuYWJsZSB0byB1cGRhdGUgdGhlIGxvY2FsIEhpZ2hjaGFydHMgY2FjaGUuJ1xyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIFVwZGF0ZXMgdGhlIEhpZ2hjaGFydHMgdmVyc2lvbiBpbiB0aGUgYXBwbGllZCBjb25maWd1cmF0aW9uIGFuZCBjaGVja3NcclxuICogdGhlIGNhY2hlIGZvciB0aGUgbmV3IHZlcnNpb24uXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBuZXdWZXJzaW9uIC0gVGhlIG5ldyBIaWdoY2hhcnRzIHZlcnNpb24gdG8gYmUgYXBwbGllZC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8KG9iamVjdHxib29sZWFuKT59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIHVwZGF0ZWRcclxuICogY29uZmlndXJhdGlvbiB3aXRoIHRoZSBuZXcgdmVyc2lvbiwgb3IgZmFsc2UgaWYgbm8gYXBwbGllZCBjb25maWd1cmF0aW9uXHJcbiAqIGV4aXN0cy5cclxuICovXHJcbmV4cG9ydCBjb25zdCB1cGRhdGVWZXJzaW9uID0gYXN5bmMgKG5ld1ZlcnNpb24pID0+XHJcbiAgYXBwbGllZENvbmZpZ1xyXG4gICAgPyBhd2FpdCBjaGVja0FuZFVwZGF0ZUNhY2hlKFxyXG4gICAgICAgIE9iamVjdC5hc3NpZ24oYXBwbGllZENvbmZpZywge1xyXG4gICAgICAgICAgdmVyc2lvbjogbmV3VmVyc2lvblxyXG4gICAgICAgIH0pXHJcbiAgICAgIClcclxuICAgIDogZmFsc2U7XHJcblxyXG4vKipcclxuICogQ2hlY2tzIHRoZSBjYWNoZSBmb3IgSGlnaGNoYXJ0cyBkZXBlbmRlbmNpZXMsIHVwZGF0ZXMgdGhlIGNhY2hlIGlmIG5lZWRlZCxcclxuICogYW5kIGxvYWRzIHRoZSBzb3VyY2VzLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnIC0gSGlnaGNoYXJ0cy1yZWxhdGVkIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmcgaW5mb3JtYXRpb25cclxuICogYWJvdXQgc2NyaXB0cyBhbmQgbW9kdWxlcy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgdGhlIGNhY2hlIGlzIGNoZWNrZWRcclxuICogYW5kIHVwZGF0ZWQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgdGhlcmUgaXMgYW4gaXNzdWUgdXBkYXRpbmdcclxuICogb3IgcmVhZGluZyB0aGUgY2FjaGUuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgY2hlY2tBbmRVcGRhdGVDYWNoZSA9IGFzeW5jIChjb25maWcpID0+IHtcclxuICBjb25zdCBjYWNoZVBhdGggPSBqb2luKF9fZGlybmFtZSwgY29uZmlnLmNhY2hlUGF0aCk7XHJcblxyXG4gIGxldCBmZXRjaGVkTW9kdWxlcztcclxuICAvLyBQcmVwYXJlIHBhdGhzIHRvIG1hbmlmZXN0IGFuZCBzb3VyY2VzIGZyb20gdGhlIC5jYWNoZSBmb2xkZXJcclxuICBjb25zdCBtYW5pZmVzdFBhdGggPSBqb2luKGNhY2hlUGF0aCwgJ21hbmlmZXN0Lmpzb24nKTtcclxuICBjb25zdCBzb3VyY2VQYXRoID0gam9pbihjYWNoZVBhdGgsICdzb3VyY2VzLmpzJyk7XHJcblxyXG4gIC8vIFRPRE86IGRlYWwgd2l0aCB0cnlpbmcgdG8gc3dpdGNoIHRvIHRoZSBydW5uaW5nIHZlcnNpb25cclxuICAvLyBjb25zdCBhY3RpdmVWZXJzaW9uID0gYXBwbGllZENvbmZpZyA/IGFwcGxpZWRDb25maWcudmVyc2lvbiA6IGZhbHNlO1xyXG5cclxuICBhcHBsaWVkQ29uZmlnID0gY29uZmlnO1xyXG5cclxuICAvLyBDcmVhdGUgdGhlIGNhY2hlIGRlc3RpbmF0aW9uIGlmIGl0IGRvZXNuJ3QgZXhpc3QgYWxyZWFkeVxyXG4gICFleGlzdHNTeW5jKGNhY2hlUGF0aCkgJiYgbWtkaXJTeW5jKGNhY2hlUGF0aCk7XHJcblxyXG4gIC8vIEZldGNoIGFsbCB0aGUgc2NyaXB0cyBlaXRoZXIgaWYgbWFuaWZlc3QuanNvbiBkb2VzIG5vdCBleGlzdFxyXG4gIC8vIG9yIGlmIHRoZSBmb3JjZUZldGNoIG9wdGlvbiBpcyBlbmFibGVkXHJcbiAgaWYgKCFleGlzdHNTeW5jKG1hbmlmZXN0UGF0aCkgfHwgY29uZmlnLmZvcmNlRmV0Y2gpIHtcclxuICAgIGxvZygzLCAnW2NhY2hlXSBGZXRjaGluZyBhbmQgY2FjaGluZyBIaWdoY2hhcnRzIGRlcGVuZGVuY2llcy4nKTtcclxuICAgIGZldGNoZWRNb2R1bGVzID0gYXdhaXQgdXBkYXRlQ2FjaGUoY29uZmlnLCBzb3VyY2VQYXRoKTtcclxuICB9IGVsc2Uge1xyXG4gICAgbGV0IHJlcXVlc3RVcGRhdGUgPSBmYWxzZTtcclxuXHJcbiAgICAvLyBSZWFkIHRoZSBtYW5pZmVzdCBKU09OXHJcbiAgICBjb25zdCBtYW5pZmVzdCA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKG1hbmlmZXN0UGF0aCkpO1xyXG5cclxuICAgIC8vIENoZWNrIGlmIHRoZSBtb2R1bGVzIGlzIGFuIGFycmF5LCBpZiBzbywgd2UgcmV3cml0ZSBpdCB0byBhIG1hcCB0byBtYWtlXHJcbiAgICAvLyBpdCBlYXNpZXIgdG8gcmVzb2x2ZSBtb2R1bGVzLlxyXG4gICAgaWYgKG1hbmlmZXN0Lm1vZHVsZXMgJiYgQXJyYXkuaXNBcnJheShtYW5pZmVzdC5tb2R1bGVzKSkge1xyXG4gICAgICBjb25zdCBtb2R1bGVNYXAgPSB7fTtcclxuICAgICAgbWFuaWZlc3QubW9kdWxlcy5mb3JFYWNoKChtKSA9PiAobW9kdWxlTWFwW21dID0gMSkpO1xyXG4gICAgICBtYW5pZmVzdC5tb2R1bGVzID0gbW9kdWxlTWFwO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IHsgbW9kdWxlcywgY29yZVNjcmlwdHMsIGluZGljYXRvcnMgfSA9IGNvbmZpZztcclxuICAgIGNvbnN0IG51bWJlck9mTW9kdWxlcyA9XHJcbiAgICAgIG1vZHVsZXMubGVuZ3RoICsgY29yZVNjcmlwdHMubGVuZ3RoICsgaW5kaWNhdG9ycy5sZW5ndGg7XHJcblxyXG4gICAgLy8gQ29tcGFyZSB0aGUgbG9hZGVkIGNvbmZpZyB3aXRoIHRoZSBjb250ZW50cyBpbiBjYWNoZS5cclxuICAgIC8vIElmIHRoZXJlIGFyZSBjaGFuZ2VzLCBmZXRjaCByZXF1ZXN0ZWQgbW9kdWxlcyBhbmQgcHJvZHVjdHMsXHJcbiAgICAvLyBhbmQgYmFrZSB0aGVtIGludG8gYSBnaWFudCBibG9iLiBTYXZlIHRoZSBibG9iLlxyXG4gICAgaWYgKG1hbmlmZXN0LnZlcnNpb24gIT09IGNvbmZpZy52ZXJzaW9uKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICAyLFxyXG4gICAgICAgICdbY2FjaGVdIEEgSGlnaGNoYXJ0cyB2ZXJzaW9uIG1pc21hdGNoIGluIHRoZSBjYWNoZSwgbmVlZCB0byByZS1mZXRjaC4nXHJcbiAgICAgICk7XHJcbiAgICAgIHJlcXVlc3RVcGRhdGUgPSB0cnVlO1xyXG4gICAgfSBlbHNlIGlmIChPYmplY3Qua2V5cyhtYW5pZmVzdC5tb2R1bGVzIHx8IHt9KS5sZW5ndGggIT09IG51bWJlck9mTW9kdWxlcykge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgMixcclxuICAgICAgICAnW2NhY2hlXSBUaGUgY2FjaGUgYW5kIHRoZSByZXF1ZXN0ZWQgbW9kdWxlcyBkbyBub3QgbWF0Y2gsIG5lZWQgdG8gcmUtZmV0Y2guJ1xyXG4gICAgICApO1xyXG4gICAgICByZXF1ZXN0VXBkYXRlID0gdHJ1ZTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIENoZWNrIGVhY2ggbW9kdWxlLCBpZiBhbnl0aGluZyBpcyBtaXNzaW5nIHJlZmV0Y2ggZXZlcnl0aGluZ1xyXG4gICAgICByZXF1ZXN0VXBkYXRlID0gKGNvbmZpZy5tb2R1bGVzIHx8IFtdKS5zb21lKChtb2R1bGVOYW1lKSA9PiB7XHJcbiAgICAgICAgaWYgKCFtYW5pZmVzdC5tb2R1bGVzW21vZHVsZU5hbWVdKSB7XHJcbiAgICAgICAgICBsb2coXHJcbiAgICAgICAgICAgIDIsXHJcbiAgICAgICAgICAgIGBbY2FjaGVdIFRoZSAke21vZHVsZU5hbWV9IGlzIG1pc3NpbmcgaW4gdGhlIGNhY2hlLCBuZWVkIHRvIHJlLWZldGNoLmBcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgICB9XHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChyZXF1ZXN0VXBkYXRlKSB7XHJcbiAgICAgIGZldGNoZWRNb2R1bGVzID0gYXdhaXQgdXBkYXRlQ2FjaGUoY29uZmlnLCBzb3VyY2VQYXRoKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIGxvZygzLCAnW2NhY2hlXSBEZXBlbmRlbmN5IGNhY2hlIGlzIHVwIHRvIGRhdGUsIHByb2NlZWRpbmcuJyk7XHJcblxyXG4gICAgICAvLyBMb2FkIHRoZSBzb3VyY2VzXHJcbiAgICAgIGNhY2hlLnNvdXJjZXMgPSByZWFkRmlsZVN5bmMoc291cmNlUGF0aCwgJ3V0ZjgnKTtcclxuXHJcbiAgICAgIC8vIEdldCBjdXJyZW50IG1vZHVsZXMgbWFwXHJcbiAgICAgIGZldGNoZWRNb2R1bGVzID0gbWFuaWZlc3QubW9kdWxlcztcclxuICAgICAgZXh0cmFjdFZlcnNpb24oKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIEZpbmFsbHksIHNhdmUgdGhlIG5ldyBtYW5pZmVzdCwgd2hpY2ggaXMgYmFzaWNhbGx5IG91ciBjdXJyZW50IGNvbmZpZ1xyXG4gIC8vIGluIGEgc2xpZ2h0bHkgZGlmZmVyZW50IGZvcm1hdFxyXG4gIGF3YWl0IHNhdmVDb25maWdUb01hbmlmZXN0KGNvbmZpZywgZmV0Y2hlZE1vZHVsZXMpO1xyXG59O1xyXG5cclxuZXhwb3J0IGNvbnN0IGdldENhY2hlUGF0aCA9ICgpID0+IHtcclxuICByZXR1cm4gam9pbihfX2Rpcm5hbWUsIGFwcGxpZWRDb25maWcuY2FjaGVQYXRoKTtcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBjaGVja0FuZFVwZGF0ZUNhY2hlLFxyXG4gIGdldENhY2hlUGF0aCxcclxuICB1cGRhdGVWZXJzaW9uLFxyXG4gIGdldENhY2hlOiAoKSA9PiBjYWNoZSxcclxuICBoaWdoY2hhcnRzOiAoKSA9PiBjYWNoZS5zb3VyY2VzLFxyXG4gIHZlcnNpb246ICgpID0+IGNhY2hlLmhjVmVyc2lvblxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IGV4aXN0c1N5bmMsIHJlYWRGaWxlU3luYywgcHJvbWlzZXMgYXMgZnNQcm9taXNlcyB9IGZyb20gJ2ZzJztcclxuXHJcbmltcG9ydCBwcm9tcHRzIGZyb20gJ3Byb21wdHMnO1xyXG5cclxuaW1wb3J0IHtcclxuICBhYnNvbHV0ZVByb3BzLFxyXG4gIGRlZmF1bHRDb25maWcsXHJcbiAgbmVzdGVkQXJncyxcclxuICBwcm9tcHRzQ29uZmlnXHJcbn0gZnJvbSAnLi9zY2hlbWFzL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBkZWVwQ29weSwgaXNPYmplY3QsIHByaW50VXNhZ2UsIHRvQm9vbGVhbiB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxubGV0IGdlbmVyYWxPcHRpb25zID0ge307XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIGFuZCByZXR1cm5zIHRoZSBnZW5lcmFsIG9wdGlvbnMgZm9yIHRoZSBleHBvcnQgcHJvY2Vzcy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIGdlbmVyYWwgb3B0aW9ucyBvYmplY3QuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0T3B0aW9ucyA9ICgpID0+IGdlbmVyYWxPcHRpb25zO1xyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIGFuZCBzZXRzIHRoZSBnZW5lcmFsIG9wdGlvbnMgZm9yIHRoZSBzZXJ2ZXIgaW5zdGFjZSwga2VlcGluZ1xyXG4gKiB0aGUgcHJpbmNpcGxlIG9mIHRoZSBvcHRpb25zIGxvYWQgcHJpb3JpdHkuIEl0IGFjY2VwdHMgb3B0aW9uYWwgdXNlck9wdGlvbnNcclxuICogYW5kIGFyZ3MgZnJvbSB0aGUgQ0xJLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gdXNlck9wdGlvbnMgLSBVc2VyLXByb3ZpZGVkIG9wdGlvbnMgZm9yIGN1c3RvbWl6YXRpb24uXHJcbiAqIEBwYXJhbSB7QXJyYXl9IGFyZ3MgLSBDb21tYW5kLWxpbmUgYXJndW1lbnRzIGZvciBhZGRpdGlvbmFsIGNvbmZpZ3VyYXRpb25cclxuICogKENMSSB1c2FnZSkuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSB1cGRhdGVkIGdlbmVyYWwgb3B0aW9ucyBvYmplY3QuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2V0T3B0aW9ucyA9ICh1c2VyT3B0aW9ucywgYXJncykgPT4ge1xyXG4gIC8vIE9ubHkgZm9yIHRoZSBDTEkgdXNhZ2VcclxuICBpZiAoYXJncz8ubGVuZ3RoKSB7XHJcbiAgICAvLyBHZXQgdGhlIGFkZGl0aW9uYWwgb3B0aW9ucyBmcm9tIHRoZSBjdXN0b20gSlNPTiBmaWxlXHJcbiAgICBnZW5lcmFsT3B0aW9ucyA9IGxvYWRDb25maWdGaWxlKGFyZ3MpO1xyXG4gIH1cclxuXHJcbiAgLy8gVXBkYXRlIHRoZSBkZWZhdWx0IGNvbmZpZyB3aXRoIGEgY29ycmVjdCBvcHRpb24gdmFsdWVzXHJcbiAgdXBkYXRlRGVmYXVsdENvbmZpZyhkZWZhdWx0Q29uZmlnLCBnZW5lcmFsT3B0aW9ucyk7XHJcblxyXG4gIC8vIFNldCB2YWx1ZXMgZm9yIHNlcnZlcidzIG9wdGlvbnMgYW5kIHJldHVybnMgdGhlbVxyXG4gIGdlbmVyYWxPcHRpb25zID0gaW5pdE9wdGlvbnMoZGVmYXVsdENvbmZpZyk7XHJcblxyXG4gIC8vIEFwcGx5IHVzZXIgb3B0aW9ucyBpZiB0aGVyZSBhcmUgYW55XHJcbiAgaWYgKHVzZXJPcHRpb25zKSB7XHJcbiAgICAvLyBNZXJnZSB1c2VyIG9wdGlvbnNcclxuICAgIGdlbmVyYWxPcHRpb25zID0gbWVyZ2VDb25maWdPcHRpb25zKFxyXG4gICAgICBnZW5lcmFsT3B0aW9ucyxcclxuICAgICAgdXNlck9wdGlvbnMsXHJcbiAgICAgIGFic29sdXRlUHJvcHNcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICAvLyBPbmx5IGZvciB0aGUgQ0xJIHVzYWdlXHJcbiAgaWYgKGFyZ3M/Lmxlbmd0aCkge1xyXG4gICAgLy8gUGFpciBwcm92aWRlZCBhcmd1bWVudHNcclxuICAgIGdlbmVyYWxPcHRpb25zID0gcGFpckFyZ3VtZW50VmFsdWUoZ2VuZXJhbE9wdGlvbnMsIGFyZ3MsIGRlZmF1bHRDb25maWcpO1xyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIGZpbmFsIGdlbmVyYWwgb3B0aW9uc1xyXG4gIHJldHVybiBnZW5lcmFsT3B0aW9ucztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBBbGxvd3MgbWFudWFsIGNvbmZpZ3VyYXRpb24gYmFzZWQgb24gc3BlY2lmaWVkIHByb21wdHMgYW5kIHNhdmVzXHJcbiAqIHRoZSBjb25maWd1cmF0aW9uIHRvIGEgZmlsZS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGNvbmZpZ0ZpbGVOYW1lIC0gVGhlIG5hbWUgb2YgdGhlIGNvbmZpZ3VyYXRpb24gZmlsZS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8Ym9vbGVhbj59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRydWUgb25jZSB0aGUgbWFudWFsXHJcbiAqIGNvbmZpZ3VyYXRpb24gaXMgY29tcGxldGVkIGFuZCBzYXZlZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBtYW51YWxDb25maWcgPSBhc3luYyAoY29uZmlnRmlsZU5hbWUpID0+IHtcclxuICAvLyBQcmVwYXJlIGEgY29uZmlnIG9iamVjdFxyXG4gIGxldCBjb25maWdGaWxlID0ge307XHJcblxyXG4gIC8vIENoZWNrIGlmIHByb3ZpZGVkIGNvbmZpZyBmaWxlIGV4aXN0c1xyXG4gIGlmIChleGlzdHNTeW5jKGNvbmZpZ0ZpbGVOYW1lKSkge1xyXG4gICAgY29uZmlnRmlsZSA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKGNvbmZpZ0ZpbGVOYW1lLCAndXRmOCcpKTtcclxuICB9XHJcblxyXG4gIC8vIFF1ZXN0aW9uIGFib3V0IGEgY29uZmlndXJhdGlvbiBjYXRlZ29yeVxyXG4gIGNvbnN0IG9uU3VibWl0ID0gYXN5bmMgKHAsIGNhdGVnb3JpZXMpID0+IHtcclxuICAgIGxldCBxdWVzdGlvbnNDb3VudGVyID0gMDtcclxuICAgIGxldCBhbGxRdWVzdGlvbnMgPSBbXTtcclxuXHJcbiAgICAvLyBDcmVhdGUgYSBjb3JyZXNwb25kaW5nIHByb3BlcnR5IGluIHRoZSBtYW51YWxDb25maWcgb2JqZWN0XHJcbiAgICBmb3IgKGNvbnN0IHNlY3Rpb24gb2YgY2F0ZWdvcmllcykge1xyXG4gICAgICAvLyBNYXJrIGVhY2ggb3B0aW9uIHdpdGggYSBzZWN0aW9uXHJcbiAgICAgIHByb21wdHNDb25maWdbc2VjdGlvbl0gPSBwcm9tcHRzQ29uZmlnW3NlY3Rpb25dLm1hcCgob3B0aW9uKSA9PiAoe1xyXG4gICAgICAgIC4uLm9wdGlvbixcclxuICAgICAgICBzZWN0aW9uXHJcbiAgICAgIH0pKTtcclxuXHJcbiAgICAgIC8vIENvbGxlY3QgdGhlIHF1ZXN0aW9uc1xyXG4gICAgICBhbGxRdWVzdGlvbnMgPSBbLi4uYWxsUXVlc3Rpb25zLCAuLi5wcm9tcHRzQ29uZmlnW3NlY3Rpb25dXTtcclxuICAgIH1cclxuXHJcbiAgICBhd2FpdCBwcm9tcHRzKGFsbFF1ZXN0aW9ucywge1xyXG4gICAgICBvblN1Ym1pdDogYXN5bmMgKHByb21wdCwgYW5zd2VyKSA9PiB7XHJcbiAgICAgICAgLy8gR2V0IHRoZSBkZWZhdWx0IG1vZHVsZXNcclxuICAgICAgICBpZiAocHJvbXB0Lm5hbWUgPT09ICdtb2R1bGVzJykge1xyXG4gICAgICAgICAgYW5zd2VyID0gYW5zd2VyLmxlbmd0aFxyXG4gICAgICAgICAgICA/IGFuc3dlci5tYXAoKG1vZHVsZSkgPT4gcHJvbXB0LmNob2ljZXNbbW9kdWxlXSlcclxuICAgICAgICAgICAgOiBwcm9tcHQuY2hvaWNlcztcclxuXHJcbiAgICAgICAgICBjb25maWdGaWxlW3Byb21wdC5zZWN0aW9uXVtwcm9tcHQubmFtZV0gPSBhbnN3ZXI7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIGNvbmZpZ0ZpbGVbcHJvbXB0LnNlY3Rpb25dID0gcmVjdXJzaXZlUHJvcHMoXHJcbiAgICAgICAgICAgIE9iamVjdC5hc3NpZ24oe30sIGNvbmZpZ0ZpbGVbcHJvbXB0LnNlY3Rpb25dIHx8IHt9KSxcclxuICAgICAgICAgICAgcHJvbXB0Lm5hbWUuc3BsaXQoJy4nKSxcclxuICAgICAgICAgICAgcHJvbXB0LmNob2ljZXMgPyBwcm9tcHQuY2hvaWNlc1thbnN3ZXJdIDogYW5zd2VyXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgaWYgKCsrcXVlc3Rpb25zQ291bnRlciA9PT0gYWxsUXVlc3Rpb25zLmxlbmd0aCkge1xyXG4gICAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgYXdhaXQgZnNQcm9taXNlcy53cml0ZUZpbGUoXHJcbiAgICAgICAgICAgICAgY29uZmlnRmlsZU5hbWUsXHJcbiAgICAgICAgICAgICAgSlNPTi5zdHJpbmdpZnkoY29uZmlnRmlsZSwgbnVsbCwgMiksXHJcbiAgICAgICAgICAgICAgJ3V0ZjgnXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgICAgICAgMSxcclxuICAgICAgICAgICAgICBlcnJvcixcclxuICAgICAgICAgICAgICBgW2NvbmZpZ10gQW4gZXJyb3Igb2NjdXJyZWQgd2hpbGUgY3JlYXRpbmcgdGhlICR7Y29uZmlnRmlsZU5hbWV9IGZpbGUuYFxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9KTtcclxuXHJcbiAgICByZXR1cm4gdHJ1ZTtcclxuICB9O1xyXG5cclxuICAvLyBGaW5kIHRoZSBjYXRlZ29yaWVzXHJcbiAgY29uc3QgY2hvaWNlcyA9IE9iamVjdC5rZXlzKHByb21wdHNDb25maWcpLm1hcCgoY2hvaWNlKSA9PiAoe1xyXG4gICAgdGl0bGU6IGAke2Nob2ljZX0gb3B0aW9uc2AsXHJcbiAgICB2YWx1ZTogY2hvaWNlXHJcbiAgfSkpO1xyXG5cclxuICAvLyBDYXRlZ29yeSBwcm9tcHRcclxuICByZXR1cm4gcHJvbXB0cyhcclxuICAgIHtcclxuICAgICAgdHlwZTogJ211bHRpc2VsZWN0JyxcclxuICAgICAgbmFtZTogJ2NhdGVnb3J5JyxcclxuICAgICAgbWVzc2FnZTogJ1doaWNoIGNhdGVnb3J5IGRvIHlvdSB3YW50IHRvIGNvbmZpZ3VyZT8nLFxyXG4gICAgICBoaW50OiAnU3BhY2U6IFNlbGVjdCBzcGVjaWZpYywgQTogU2VsZWN0IGFsbCwgRW50ZXI6IENvbmZpcm0uJyxcclxuICAgICAgaW5zdHJ1Y3Rpb25zOiAnJyxcclxuICAgICAgY2hvaWNlc1xyXG4gICAgfSxcclxuICAgIHsgb25TdWJtaXQgfVxyXG4gICk7XHJcbn07XHJcblxyXG4vKipcclxuICogTWFwcyBvbGQtc3RydWN0dXJlZCAoUGhhbnRvbUpTKSBvcHRpb25zIHRvIGEgbmV3IGNvbmZpZ3VyYXRpb24gZm9ybWF0XHJcbiAqIChQdXBwZXRlZXIpLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb2xkT3B0aW9ucyAtIE9sZC1zdHJ1Y3R1cmVkIG9wdGlvbnMgdG8gYmUgbWFwcGVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBOZXcgb3B0aW9ucyBzdHJ1Y3R1cmVkIGJhc2VkIG9uIHRoZSBkZWZpbmVkIG5lc3RlZEFyZ3NcclxuICogbWFwcGluZy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBtYXBUb05ld0NvbmZpZyA9IChvbGRPcHRpb25zKSA9PiB7XHJcbiAgY29uc3QgbmV3T3B0aW9ucyA9IHt9O1xyXG4gIC8vIEN5Y2xlIHRocm91Z2ggb2xkLXN0cnVjdHVyZWQgb3B0aW9uc1xyXG4gIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKG9sZE9wdGlvbnMpKSB7XHJcbiAgICBjb25zdCBwcm9wZXJ0aWVzQ2hhaW4gPSBuZXN0ZWRBcmdzW2tleV0gPyBuZXN0ZWRBcmdzW2tleV0uc3BsaXQoJy4nKSA6IFtdO1xyXG5cclxuICAgIC8vIFBvcHVsYXRlIG9iamVjdCBpbiBjb3JyZWN0IHByb3BlcnRpZXMgbGV2ZWxzXHJcbiAgICBwcm9wZXJ0aWVzQ2hhaW4ucmVkdWNlKFxyXG4gICAgICAob2JqLCBwcm9wLCBpbmRleCkgPT5cclxuICAgICAgICAob2JqW3Byb3BdID1cclxuICAgICAgICAgIHByb3BlcnRpZXNDaGFpbi5sZW5ndGggLSAxID09PSBpbmRleCA/IHZhbHVlIDogb2JqW3Byb3BdIHx8IHt9KSxcclxuICAgICAgbmV3T3B0aW9uc1xyXG4gICAgKTtcclxuICB9XHJcbiAgcmV0dXJuIG5ld09wdGlvbnM7XHJcbn07XHJcblxyXG4vKipcclxuICogTWVyZ2VzIHR3byBzZXRzIG9mIGNvbmZpZ3VyYXRpb24gb3B0aW9ucywgY29uc2lkZXJpbmcgYWJzb2x1dGUgcHJvcGVydGllcy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBPcmlnaW5hbCBjb25maWd1cmF0aW9uIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBuZXdPcHRpb25zIC0gTmV3IGNvbmZpZ3VyYXRpb24gb3B0aW9ucyB0byBiZSBtZXJnZWQuXHJcbiAqIEBwYXJhbSB7QXJyYXl9IGFic29sdXRlUHJvcHMgLSBMaXN0IG9mIHByb3BlcnRpZXMgdGhhdCBzaG91bGRcclxuICogbm90IGJlIHJlY3Vyc2l2ZWx5IG1lcmdlZC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gTWVyZ2VkIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBtZXJnZUNvbmZpZ09wdGlvbnMgPSAob3B0aW9ucywgbmV3T3B0aW9ucywgYWJzb2x1dGVQcm9wcyA9IFtdKSA9PiB7XHJcbiAgY29uc3QgbWVyZ2VkT3B0aW9ucyA9IGRlZXBDb3B5KG9wdGlvbnMpO1xyXG5cclxuICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhuZXdPcHRpb25zKSkge1xyXG4gICAgbWVyZ2VkT3B0aW9uc1trZXldID1cclxuICAgICAgaXNPYmplY3QodmFsdWUpICYmXHJcbiAgICAgICFhYnNvbHV0ZVByb3BzLmluY2x1ZGVzKGtleSkgJiZcclxuICAgICAgbWVyZ2VkT3B0aW9uc1trZXldICE9PSB1bmRlZmluZWRcclxuICAgICAgICA/IG1lcmdlQ29uZmlnT3B0aW9ucyhtZXJnZWRPcHRpb25zW2tleV0sIHZhbHVlLCBhYnNvbHV0ZVByb3BzKVxyXG4gICAgICAgIDogdmFsdWUgIT09IHVuZGVmaW5lZFxyXG4gICAgICAgICAgPyB2YWx1ZVxyXG4gICAgICAgICAgOiBtZXJnZWRPcHRpb25zW2tleV07XHJcbiAgfVxyXG5cclxuICByZXR1cm4gbWVyZ2VkT3B0aW9ucztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyBleHBvcnQgc2V0dGluZ3MgYmFzZWQgb24gcHJvdmlkZWQgZXhwb3J0T3B0aW9uc1xyXG4gKiBhbmQgZ2VuZXJhbE9wdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBleHBvcnRPcHRpb25zIC0gT3B0aW9ucyBzcGVjaWZpYyB0byB0aGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBnZW5lcmFsT3B0aW9ucyAtIEdlbmVyYWwgY29uZmlndXJhdGlvbiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBJbml0aWFsaXplZCBleHBvcnQgc2V0dGluZ3MuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaW5pdEV4cG9ydFNldHRpbmdzID0gKGV4cG9ydE9wdGlvbnMsIGdlbmVyYWxPcHRpb25zID0ge30pID0+IHtcclxuICBsZXQgb3B0aW9ucyA9IHt9O1xyXG5cclxuICBpZiAoZXhwb3J0T3B0aW9ucy5zdmcpIHtcclxuICAgIG9wdGlvbnMgPSBkZWVwQ29weShnZW5lcmFsT3B0aW9ucyk7XHJcbiAgICBvcHRpb25zLmV4cG9ydC50eXBlID0gZXhwb3J0T3B0aW9ucy50eXBlIHx8IGV4cG9ydE9wdGlvbnMuZXhwb3J0LnR5cGU7XHJcbiAgICBvcHRpb25zLmV4cG9ydC5zY2FsZSA9IGV4cG9ydE9wdGlvbnMuc2NhbGUgfHwgZXhwb3J0T3B0aW9ucy5leHBvcnQuc2NhbGU7XHJcbiAgICBvcHRpb25zLmV4cG9ydC5vdXRmaWxlID1cclxuICAgICAgZXhwb3J0T3B0aW9ucy5vdXRmaWxlIHx8IGV4cG9ydE9wdGlvbnMuZXhwb3J0Lm91dGZpbGU7XHJcbiAgICBvcHRpb25zLnBheWxvYWQgPSB7XHJcbiAgICAgIHN2ZzogZXhwb3J0T3B0aW9ucy5zdmdcclxuICAgIH07XHJcbiAgfSBlbHNlIHtcclxuICAgIG9wdGlvbnMgPSBtZXJnZUNvbmZpZ09wdGlvbnMoXHJcbiAgICAgIGdlbmVyYWxPcHRpb25zLFxyXG4gICAgICBleHBvcnRPcHRpb25zLFxyXG4gICAgICAvLyBPbWl0IGdvaW5nIGRvd24gcmVjdXJzaXZlbHkgd2l0aCB0aGUgYmVsb3dzXHJcbiAgICAgIGFic29sdXRlUHJvcHNcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICBvcHRpb25zLmV4cG9ydC5vdXRmaWxlID1cclxuICAgIG9wdGlvbnMuZXhwb3J0Py5vdXRmaWxlIHx8IGBjaGFydC4ke29wdGlvbnMuZXhwb3J0Py50eXBlIHx8ICdwbmcnfWA7XHJcbiAgcmV0dXJuIG9wdGlvbnM7XHJcbn07XHJcblxyXG4vKipcclxuICogTG9hZHMgYWRkaXRpb25hbCBjb25maWd1cmF0aW9uIGZyb20gYSBzcGVjaWZpZWQgZmlsZSB1c2luZ1xyXG4gKiB0aGUgLS1sb2FkQ29uZmlnIG9wdGlvbi5cclxuICpcclxuICogQHBhcmFtIHtBcnJheX0gYXJncyAtIENvbW1hbmQtbGluZSBhcmd1bWVudHMgdG8gY2hlY2sgZm9yXHJcbiAqIHRoZSAtLWxvYWRDb25maWcgb3B0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBBZGRpdGlvbmFsIGNvbmZpZ3VyYXRpb24gbG9hZGVkIGZyb20gdGhlIHNwZWNpZmllZCBmaWxlLFxyXG4gKiBvciBhbiBlbXB0eSBvYmplY3QgaWYgbm90IGZvdW5kIG9yIGludmFsaWQuXHJcbiAqL1xyXG5mdW5jdGlvbiBsb2FkQ29uZmlnRmlsZShhcmdzKSB7XHJcbiAgLy8gQ2hlY2sgaWYgdGhlIC0tbG9hZENvbmZpZyBvcHRpb24gd2FzIHVzZWRcclxuICBjb25zdCBjb25maWdJbmRleCA9IGFyZ3MuZmluZEluZGV4KFxyXG4gICAgKGFyZykgPT4gYXJnLnJlcGxhY2UoLy0vZywgJycpID09PSAnbG9hZENvbmZpZydcclxuICApO1xyXG5cclxuICAvLyBDaGVjayBpZiB0aGUgLS1sb2FkQ29uZmlnIGhhcyBhIHZhbHVlXHJcbiAgaWYgKGNvbmZpZ0luZGV4ID4gLTEgJiYgYXJnc1tjb25maWdJbmRleCArIDFdKSB7XHJcbiAgICBjb25zdCBmaWxlTmFtZSA9IGFyZ3NbY29uZmlnSW5kZXggKyAxXTtcclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIENoZWNrIGlmIGFuIGFkZGl0aW9uYWwgY29uZmlnIGZpbGUgaXMgYSBjb3JyZWN0IEpTT04gZmlsZVxyXG4gICAgICBpZiAoZmlsZU5hbWUgJiYgZmlsZU5hbWUuZW5kc1dpdGgoJy5qc29uJykpIHtcclxuICAgICAgICAvLyBMb2FkIGFuIG9wdGlvbmFsIGN1c3RvbSBKU09OIGNvbmZpZyBmaWxlXHJcbiAgICAgICAgcmV0dXJuIEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKGZpbGVOYW1lKSk7XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAyLFxyXG4gICAgICAgIGVycm9yLFxyXG4gICAgICAgIGBbY29uZmlnXSBVbmFibGUgdG8gbG9hZCB0aGUgY29uZmlndXJhdGlvbiBmcm9tIHRoZSAke2ZpbGVOYW1lfSBmaWxlLmBcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIE5vIGFkZGl0aW9uYWwgb3B0aW9ucyB0byByZXR1cm5cclxuICByZXR1cm4ge307XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBVcGRhdGVzIHRoZSBkZWZhdWx0IGNvbmZpZ3VyYXRpb24gb2JqZWN0IHdpdGggdmFsdWVzIGZyb20gYSBjdXN0b20gb2JqZWN0XHJcbiAqIGFuZCBlbnZpcm9ubWVudCB2YXJpYWJsZXMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjb25maWdPYmogLSBUaGUgZGVmYXVsdCBjb25maWd1cmF0aW9uIG9iamVjdC5cclxuICogQHBhcmFtIHtPYmplY3R9IGN1c3RvbU9iaiAtIEN1c3RvbSBjb25maWd1cmF0aW9uIG9iamVjdCB0byBvdmVycmlkZSBkZWZhdWx0cy5cclxuICogQHBhcmFtIHtzdHJpbmd9IHByb3BDaGFpbiAtIFByb3BlcnR5IGNoYWluIGZvciB0cmFja2luZyBuZXN0ZWQgcHJvcGVydGllc1xyXG4gKiBkdXJpbmcgcmVjdXJzaW9uLlxyXG4gKi9cclxuZnVuY3Rpb24gdXBkYXRlRGVmYXVsdENvbmZpZyhjb25maWdPYmosIGN1c3RvbU9iaiA9IHt9LCBwcm9wQ2hhaW4gPSAnJykge1xyXG4gIE9iamVjdC5rZXlzKGNvbmZpZ09iaikuZm9yRWFjaCgoa2V5KSA9PiB7XHJcbiAgICBjb25zdCBlbnRyeSA9IGNvbmZpZ09ialtrZXldO1xyXG4gICAgY29uc3QgY3VzdG9tVmFsdWUgPSBjdXN0b21PYmogJiYgY3VzdG9tT2JqW2tleV07XHJcbiAgICBsZXQgbnVtRW52VmFsO1xyXG5cclxuICAgIGlmICh0eXBlb2YgZW50cnkudmFsdWUgPT09ICd1bmRlZmluZWQnKSB7XHJcbiAgICAgIHVwZGF0ZURlZmF1bHRDb25maWcoZW50cnksIGN1c3RvbVZhbHVlLCBgJHtwcm9wQ2hhaW59LiR7a2V5fWApO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gSWYgYSB2YWx1ZSBmcm9tIGEgY3VzdG9tIEpTT04gZXhpc3RzLCBpdCB0YWtlIHByZWNlZGVuY2VcclxuICAgICAgaWYgKGN1c3RvbVZhbHVlICE9PSB1bmRlZmluZWQpIHtcclxuICAgICAgICBlbnRyeS52YWx1ZSA9IGN1c3RvbVZhbHVlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBJZiBhIHZhbHVlIGZyb20gYW4gZW52IHZhcmlhYmxlIGV4aXN0cywgaXQgdGFrZSBwcmVjZWRlbmNlXHJcbiAgICAgIGlmIChlbnRyeS5lbnZMaW5rKSB7XHJcbiAgICAgICAgLy8gTG9hZCB0aGUgZW52IHZhclxyXG4gICAgICAgIGlmIChlbnRyeS50eXBlID09PSAnYm9vbGVhbicpIHtcclxuICAgICAgICAgIGVudHJ5LnZhbHVlID0gdG9Cb29sZWFuKFxyXG4gICAgICAgICAgICBbcHJvY2Vzcy5lbnZbZW50cnkuZW52TGlua10sIGVudHJ5LnZhbHVlXS5maW5kKFxyXG4gICAgICAgICAgICAgIChlbCkgPT4gZWwgfHwgZWwgPT09ICdmYWxzZSdcclxuICAgICAgICAgICAgKVxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9IGVsc2UgaWYgKGVudHJ5LnR5cGUgPT09ICdudW1iZXInKSB7XHJcbiAgICAgICAgICBudW1FbnZWYWwgPSArcHJvY2Vzcy5lbnZbZW50cnkuZW52TGlua107XHJcbiAgICAgICAgICBlbnRyeS52YWx1ZSA9IG51bUVudlZhbCA+PSAwID8gbnVtRW52VmFsIDogZW50cnkudmFsdWU7XHJcbiAgICAgICAgfSBlbHNlIGlmIChlbnRyeS50eXBlLmluZGV4T2YoJ10nKSA+PSAwICYmIHByb2Nlc3MuZW52W2VudHJ5LmVudkxpbmtdKSB7XHJcbiAgICAgICAgICBlbnRyeS52YWx1ZSA9IHByb2Nlc3MuZW52W2VudHJ5LmVudkxpbmtdLnNwbGl0KCcsJyk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIGVudHJ5LnZhbHVlID0gcHJvY2Vzcy5lbnZbZW50cnkuZW52TGlua10gfHwgZW50cnkudmFsdWU7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyBvcHRpb25zIG9iamVjdCBiYXNlZCBvbiBwcm92aWRlZCBpdGVtcywgc2V0dGluZyB2YWx1ZXMgZnJvbVxyXG4gKiBuZXN0ZWQgcHJvcGVydGllcyByZWN1cnNpdmVseS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGl0ZW1zIC0gQ29uZmlndXJhdGlvbiBpdGVtcyB0byBiZSB1c2VkIGZvciBpbml0aWFsaXppbmdcclxuICogb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gSW5pdGlhbGl6ZWQgb3B0aW9ucyBvYmplY3QuXHJcbiAqL1xyXG5mdW5jdGlvbiBpbml0T3B0aW9ucyhpdGVtcykge1xyXG4gIGxldCBvcHRpb25zID0ge307XHJcbiAgZm9yIChjb25zdCBbbmFtZSwgaXRlbV0gb2YgT2JqZWN0LmVudHJpZXMoaXRlbXMpKSB7XHJcbiAgICBvcHRpb25zW25hbWVdID0gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGl0ZW0sICd2YWx1ZScpXHJcbiAgICAgID8gaXRlbS52YWx1ZVxyXG4gICAgICA6IGluaXRPcHRpb25zKGl0ZW0pO1xyXG4gIH1cclxuICByZXR1cm4gb3B0aW9ucztcclxufVxyXG5cclxuLyoqXHJcbiAqIFBhaXJzIGFyZ3VtZW50IHZhbHVlcyB3aXRoIGNvcnJlc3BvbmRpbmcgb3B0aW9ucyBpbiB0aGUgY29uZmlndXJhdGlvbixcclxuICogdXBkYXRpbmcgdGhlIG9wdGlvbnMgb2JqZWN0LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIENvbmZpZ3VyYXRpb24gb3B0aW9ucyBvYmplY3QgdG8gYmUgdXBkYXRlZC5cclxuICogQHBhcmFtIHtBcnJheX0gYXJncyAtIENvbW1hbmQtbGluZSBhcmd1bWVudHMgY29udGFpbmluZyB2YWx1ZXMgZm9yIHNwZWNpZmljXHJcbiAqIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBkZWZhdWx0Q29uZmlnIC0gRGVmYXVsdCBjb25maWd1cmF0aW9uIG9iamVjdCBmb3IgcmVmZXJlbmNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBVcGRhdGVkIG9wdGlvbnMgb2JqZWN0LlxyXG4gKi9cclxuZnVuY3Rpb24gcGFpckFyZ3VtZW50VmFsdWUob3B0aW9ucywgYXJncywgZGVmYXVsdENvbmZpZykge1xyXG4gIGxldCBzaG93VXNhZ2UgPSBmYWxzZTtcclxuICBmb3IgKGxldCBpID0gMDsgaSA8IGFyZ3MubGVuZ3RoOyBpKyspIHtcclxuICAgIGNvbnN0IG9wdGlvbiA9IGFyZ3NbaV0ucmVwbGFjZSgvLS9nLCAnJyk7XHJcblxyXG4gICAgLy8gRmluZCB0aGUgcmlnaHQgcGxhY2UgZm9yIHByb3BlcnR5J3MgdmFsdWVcclxuICAgIGNvbnN0IHByb3BlcnRpZXNDaGFpbiA9IG5lc3RlZEFyZ3Nbb3B0aW9uXVxyXG4gICAgICA/IG5lc3RlZEFyZ3Nbb3B0aW9uXS5zcGxpdCgnLicpXHJcbiAgICAgIDogW107XHJcblxyXG4gICAgLy8gR2V0IHRoZSBjb3JyZWN0IHR5cGUgZm9yIENMSSBhcmdzIHdoaWNoIGFyZSBwYXNzZWQgYXMgc3RyaW5nc1xyXG4gICAgbGV0IGFyZ3VtZW50VHlwZTtcclxuICAgIHByb3BlcnRpZXNDaGFpbi5yZWR1Y2UoKG9iaiwgcHJvcCwgaW5kZXgpID0+IHtcclxuICAgICAgaWYgKHByb3BlcnRpZXNDaGFpbi5sZW5ndGggLSAxID09PSBpbmRleCkge1xyXG4gICAgICAgIGFyZ3VtZW50VHlwZSA9IG9ialtwcm9wXS50eXBlO1xyXG4gICAgICB9XHJcbiAgICAgIHJldHVybiBvYmpbcHJvcF07XHJcbiAgICB9LCBkZWZhdWx0Q29uZmlnKTtcclxuXHJcbiAgICBwcm9wZXJ0aWVzQ2hhaW4ucmVkdWNlKChvYmosIHByb3AsIGluZGV4KSA9PiB7XHJcbiAgICAgIGlmIChwcm9wZXJ0aWVzQ2hhaW4ubGVuZ3RoIC0gMSA9PT0gaW5kZXgpIHtcclxuICAgICAgICAvLyBGaW5kcyBhbiBvcHRpb24gYW5kIHNldCBhIGNvcnJlc3BvbmRpbmcgdmFsdWVcclxuICAgICAgICBpZiAodHlwZW9mIG9ialtwcm9wXSAhPT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgICAgIGlmIChhcmdzWysraV0pIHtcclxuICAgICAgICAgICAgaWYgKGFyZ3VtZW50VHlwZSA9PT0gJ2Jvb2xlYW4nKSB7XHJcbiAgICAgICAgICAgICAgb2JqW3Byb3BdID0gdG9Cb29sZWFuKGFyZ3NbaV0pO1xyXG4gICAgICAgICAgICB9IGVsc2UgaWYgKGFyZ3VtZW50VHlwZSA9PT0gJ251bWJlcicpIHtcclxuICAgICAgICAgICAgICBvYmpbcHJvcF0gPSArYXJnc1tpXTtcclxuICAgICAgICAgICAgfSBlbHNlIGlmIChhcmd1bWVudFR5cGUuaW5kZXhPZignXScpID49IDApIHtcclxuICAgICAgICAgICAgICBvYmpbcHJvcF0gPSBhcmdzW2ldLnNwbGl0KCcsJyk7XHJcbiAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgb2JqW3Byb3BdID0gYXJnc1tpXTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgbG9nKFxyXG4gICAgICAgICAgICAgIDIsXHJcbiAgICAgICAgICAgICAgYFtjb25maWddIE1pc3NpbmcgdmFsdWUgZm9yIHRoZSAnJHtvcHRpb259JyBhcmd1bWVudC4gVXNpbmcgdGhlIGRlZmF1bHQgdmFsdWUuYFxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgICBzaG93VXNhZ2UgPSB0cnVlO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gb2JqW3Byb3BdO1xyXG4gICAgfSwgb3B0aW9ucyk7XHJcbiAgfVxyXG5cclxuICAvLyBEaXNwbGF5IHRoZSB1c2FnZSBmb3IgdGhlIHJlZmVyZW5jZSBpZiBuZWVkZWRcclxuICBpZiAoc2hvd1VzYWdlKSB7XHJcbiAgICBwcmludFVzYWdlKGRlZmF1bHRDb25maWcpO1xyXG4gIH1cclxuXHJcbiAgcmV0dXJuIG9wdGlvbnM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZWN1cnNpdmVseSB1cGRhdGVzIHByb3BlcnRpZXMgaW4gYW4gb2JqZWN0IGJhc2VkIG9uIG5lc3RlZCBuYW1lcyBhbmQgYXNzaWduc1xyXG4gKiB0aGUgZmluYWwgdmFsdWUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvYmplY3RUb1VwZGF0ZSAtIFRoZSBvYmplY3QgdG8gYmUgdXBkYXRlZC5cclxuICogQHBhcmFtIHtBcnJheX0gbmVzdGVkTmFtZXMgLSBBcnJheSBvZiBuZXN0ZWQgcHJvcGVydHkgbmFtZXMuXHJcbiAqIEBwYXJhbSB7YW55fSB2YWx1ZSAtIFRoZSBmaW5hbCB2YWx1ZSB0byBiZSBhc3NpZ25lZC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVXBkYXRlZCBvYmplY3Qgd2l0aCBhc3NpZ25lZCB2YWx1ZXMuXHJcbiAqL1xyXG5mdW5jdGlvbiByZWN1cnNpdmVQcm9wcyhvYmplY3RUb1VwZGF0ZSwgbmVzdGVkTmFtZXMsIHZhbHVlKSB7XHJcbiAgd2hpbGUgKG5lc3RlZE5hbWVzLmxlbmd0aCA+IDEpIHtcclxuICAgIGNvbnN0IHByb3BOYW1lID0gbmVzdGVkTmFtZXMuc2hpZnQoKTtcclxuXHJcbiAgICAvLyBDcmVhdGUgYSBwcm9wZXJ0eSBpbiBvYmplY3QgaWYgaXQgZG9lc24ndCBleGlzdFxyXG4gICAgaWYgKCFPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob2JqZWN0VG9VcGRhdGUsIHByb3BOYW1lKSkge1xyXG4gICAgICBvYmplY3RUb1VwZGF0ZVtwcm9wTmFtZV0gPSB7fTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBDYWxsIGZ1bmN0aW9uIGFnYWluIGlmIHRoZXJlIHN0aWxsIG5hbWVzIHRvIGdvXHJcbiAgICBvYmplY3RUb1VwZGF0ZVtwcm9wTmFtZV0gPSByZWN1cnNpdmVQcm9wcyhcclxuICAgICAgT2JqZWN0LmFzc2lnbih7fSwgb2JqZWN0VG9VcGRhdGVbcHJvcE5hbWVdKSxcclxuICAgICAgbmVzdGVkTmFtZXMsXHJcbiAgICAgIHZhbHVlXHJcbiAgICApO1xyXG5cclxuICAgIHJldHVybiBvYmplY3RUb1VwZGF0ZTtcclxuICB9XHJcblxyXG4gIC8vIEFzc2lnbiB0aGUgZmluYWwgdmFsdWVcclxuICBvYmplY3RUb1VwZGF0ZVtuZXN0ZWROYW1lc1swXV0gPSB2YWx1ZTtcclxuICByZXR1cm4gb2JqZWN0VG9VcGRhdGU7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBnZXRPcHRpb25zLFxyXG4gIHNldE9wdGlvbnMsXHJcbiAgbWFudWFsQ29uZmlnLFxyXG4gIG1hcFRvTmV3Q29uZmlnLFxyXG4gIG1lcmdlQ29uZmlnT3B0aW9ucyxcclxuICBpbml0RXhwb3J0U2V0dGluZ3NcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgZnMgZnJvbSAnZnMnO1xyXG5pbXBvcnQgKiBhcyB1cmwgZnJvbSAndXJsJztcclxuaW1wb3J0IHBhdGggZnJvbSAnbm9kZTpwYXRoJztcclxuXHJcbmltcG9ydCBwdXBwZXRlZXIgZnJvbSAncHVwcGV0ZWVyJztcclxuXHJcbi8vIFdvcmthcm91bmQgZm9yIGh0dHBzOi8vYnVncy5jaHJvbWl1bS5vcmcvcC9jaHJvbWl1bS9pc3N1ZXMvZGV0YWlsP2lkPTE0NjMzMjhcclxuLy8gTm90IGlkZWFsIC0gbGVhdmVzIHRyYXNoIGluIHRoZSBGU1xyXG5pbXBvcnQgeyByYW5kb21CeXRlcyB9IGZyb20gJ25vZGU6Y3J5cHRvJztcclxuXHJcbmltcG9ydCB7IGdldENhY2hlUGF0aCB9IGZyb20gJy4vY2FjaGUuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG5jb25zdCBSQU5ET01fUElEID0gcmFuZG9tQnl0ZXMoNjQpLnRvU3RyaW5nKCdiYXNlNjR1cmwnKTtcclxuY29uc3QgUFVQUEVURUVSX0RJUiA9IHBhdGguam9pbigndG1wJywgYHB1cHBldGVlci0ke1JBTkRPTV9QSUR9YCk7XHJcbmNvbnN0IERBVEFfRElSID0gcGF0aC5qb2luKFBVUFBFVEVFUl9ESVIsICdwcm9maWxlJyk7XHJcblxyXG4vLyBUaGUgbWluaW1hbCBhcmdzIHRvIHNwZWVkIHVwIHRoZSBicm93c2VyXHJcbmNvbnN0IG1pbmltYWxBcmdzID0gW1xyXG4gIGAtLXVzZXItZGF0YS1kaXI9JHtEQVRBX0RJUn1gLFxyXG4gICctLWF1dG9wbGF5LXBvbGljeT11c2VyLWdlc3R1cmUtcmVxdWlyZWQnLFxyXG4gICctLWRpc2FibGUtYmFja2dyb3VuZC1uZXR3b3JraW5nJyxcclxuICAnLS1kaXNhYmxlLWJhY2tncm91bmQtdGltZXItdGhyb3R0bGluZycsXHJcbiAgJy0tZGlzYWJsZS1iYWNrZ3JvdW5kaW5nLW9jY2x1ZGVkLXdpbmRvd3MnLFxyXG4gICctLWRpc2FibGUtYnJlYWtwYWQnLFxyXG4gICctLWRpc2FibGUtY2xpZW50LXNpZGUtcGhpc2hpbmctZGV0ZWN0aW9uJyxcclxuICAnLS1kaXNhYmxlLWNvbXBvbmVudC11cGRhdGUnLFxyXG4gICctLWRpc2FibGUtZGVmYXVsdC1hcHBzJyxcclxuICAnLS1kaXNhYmxlLWRldi1zaG0tdXNhZ2UnLFxyXG4gICctLWRpc2FibGUtZG9tYWluLXJlbGlhYmlsaXR5JyxcclxuICAnLS1kaXNhYmxlLWV4dGVuc2lvbnMnLFxyXG4gICctLWRpc2FibGUtZmVhdHVyZXM9QXVkaW9TZXJ2aWNlT3V0T2ZQcm9jZXNzJyxcclxuICAnLS1kaXNhYmxlLWhhbmctbW9uaXRvcicsXHJcbiAgJy0tZGlzYWJsZS1pcGMtZmxvb2RpbmctcHJvdGVjdGlvbicsXHJcbiAgJy0tZGlzYWJsZS1ub3RpZmljYXRpb25zJyxcclxuICAnLS1kaXNhYmxlLW9mZmVyLXN0b3JlLXVubWFza2VkLXdhbGxldC1jYXJkcycsXHJcbiAgJy0tZGlzYWJsZS1wb3B1cC1ibG9ja2luZycsXHJcbiAgJy0tZGlzYWJsZS1wcmludC1wcmV2aWV3JyxcclxuICAnLS1kaXNhYmxlLXByb21wdC1vbi1yZXBvc3QnLFxyXG4gICctLWRpc2FibGUtcmVuZGVyZXItYmFja2dyb3VuZGluZycsXHJcbiAgJy0tZGlzYWJsZS1zZXNzaW9uLWNyYXNoZWQtYnViYmxlJyxcclxuICAnLS1kaXNhYmxlLXNldHVpZC1zYW5kYm94JyxcclxuICAnLS1kaXNhYmxlLXNwZWVjaC1hcGknLFxyXG4gICctLWRpc2FibGUtc3luYycsXHJcbiAgJy0taGlkZS1jcmFzaC1yZXN0b3JlLWJ1YmJsZScsXHJcbiAgJy0taGlkZS1zY3JvbGxiYXJzJyxcclxuICAnLS1pZ25vcmUtZ3B1LWJsYWNrbGlzdCcsXHJcbiAgJy0tbWV0cmljcy1yZWNvcmRpbmctb25seScsXHJcbiAgJy0tbXV0ZS1hdWRpbycsXHJcbiAgJy0tbm8tZGVmYXVsdC1icm93c2VyLWNoZWNrJyxcclxuICAnLS1uby1maXJzdC1ydW4nLFxyXG4gICctLW5vLXBpbmdzJyxcclxuICAnLS1uby1zYW5kYm94JyxcclxuICAnLS1uby16eWdvdGUnLFxyXG4gICctLXBhc3N3b3JkLXN0b3JlPWJhc2ljJyxcclxuICAnLS11c2UtbW9jay1rZXljaGFpbidcclxuXTtcclxuXHJcbmNvbnN0IF9fZGlybmFtZSA9IHVybC5maWxlVVJMVG9QYXRoKG5ldyBVUkwoJy4nLCBpbXBvcnQubWV0YS51cmwpKTtcclxuXHJcbmNvbnN0IHRlbXBsYXRlID0gZnMucmVhZEZpbGVTeW5jKFxyXG4gIF9fZGlybmFtZSArICcvLi4vdGVtcGxhdGVzL3RlbXBsYXRlLmh0bWwnLFxyXG4gICd1dGY4J1xyXG4pO1xyXG5cclxubGV0IGJyb3dzZXI7XHJcblxyXG4vKipcclxuICogU2V0cyB0aGUgY29udGVudCBmb3IgYSBQdXBwZXRlZXIgUGFnZSB1c2luZyBhIHByZWRlZmluZWQgdGVtcGxhdGVcclxuICogYW5kIGFkZGl0aW9uYWwgc2NyaXB0cy4gQWxzbywgc2V0cyB0aGUgcGFnZWVycm9yIGluIG9yZGVyIHRvIGNhdGNoXHJcbiAqIGFuZCBkaXNwbGF5IGVycm9ycyBmcm9tIHRoZSB3aW5kb3cgY29udGV4dC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IGZvciB3aGljaCB0aGUgY29udGVudFxyXG4gKiBpcyBiZWluZyBzZXQuXHJcbiAqL1xyXG5jb25zdCBzZXRQYWdlQ29udGVudCA9IGFzeW5jIChwYWdlKSA9PiB7XHJcbiAgYXdhaXQgcGFnZS5zZXRDb250ZW50KHRlbXBsYXRlKTtcclxuICBhd2FpdCBwYWdlLmFkZFNjcmlwdFRhZyh7IHBhdGg6IGAke2dldENhY2hlUGF0aCgpfS9zb3VyY2VzLmpzYCB9KTtcclxuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICBhd2FpdCBwYWdlLmV2YWx1YXRlKCgpID0+IHdpbmRvdy5zZXR1cEhpZ2hjaGFydHMoKSk7XHJcblxyXG4gIHBhZ2Uub24oJ3BhZ2VlcnJvcicsIGFzeW5jIChlcnJvcikgPT4ge1xyXG4gICAgLy8gVE9ETzogQ29uc2lkZXIgYWRkaW5nIGEgc3dpdGNoIGhlcmUgdGhhdCB0dXJucyBvbiBsb2coMCkgbG9nZ2luZ1xyXG4gICAgLy8gb24gcGFnZSBlcnJvcnMuXHJcbiAgICBhd2FpdCBwYWdlLiRldmFsKFxyXG4gICAgICAnI2NvbnRhaW5lcicsXHJcbiAgICAgIChlbGVtZW50LCBlcnJvck1lc3NhZ2UpID0+IHtcclxuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICBpZiAod2luZG93Ll9kaXNwbGF5RXJyb3JzKSB7XHJcbiAgICAgICAgICBlbGVtZW50LmlubmVySFRNTCA9IGVycm9yTWVzc2FnZTtcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIGA8aDE+Q2hhcnQgaW5wdXQgZGF0YSBlcnJvcjwvaDE+JHtlcnJvci50b1N0cmluZygpfWBcclxuICAgICk7XHJcbiAgfSk7XHJcbn07XHJcblxyXG4vKipcclxuICogQ2xlYXJzIHRoZSBjb250ZW50IG9mIGEgUHVwcGV0ZWVyIFBhZ2UgYmFzZWQgb24gdGhlIHNwZWNpZmllZCBtb2RlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFRoZSBQdXBwZXRlZXIgUGFnZSBvYmplY3QgdG8gYmUgY2xlYXJlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBoYXJkUmVzZXQgLSBBIGZsYWcgaW5kaWNhdGluZyB0aGUgdHlwZSBvZiBjbGVhcmluZ1xyXG4gKiB0byBiZSBwZXJmb3JtZWQuIElmIHRydWUsIG5hdmlnYXRlcyB0byAnYWJvdXQ6YmxhbmsnIGFuZCByZXNldHMgY29udGVudFxyXG4gKiBhbmQgc2NyaXB0cy4gSWYgZmFsc2UsIGNsZWFycyB0aGUgYm9keSBjb250ZW50IGJ5IHNldHRpbmcgYSBwcmVkZWZpbmVkIEhUTUxcclxuICogc3RydWN0dXJlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFcnJvcn0gTG9ncyB0aHJvd24gZXJyb3IgaWYgY2xlYXJpbmcgdGhlIHBhZ2UgY29udGVudCBmYWlscy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBjbGVhclBhZ2UgPSBhc3luYyAocGFnZSwgaGFyZFJlc2V0ID0gZmFsc2UpID0+IHtcclxuICB0cnkge1xyXG4gICAgaWYgKGhhcmRSZXNldCkge1xyXG4gICAgICAvLyBOYXZpZ2F0ZSB0byBhYm91dDpibGFua1xyXG4gICAgICBhd2FpdCBwYWdlLmdvdG8oJ2Fib3V0OmJsYW5rJyk7XHJcblxyXG4gICAgICAvLyBTZXQgdGhlIGNvbnRlbnQgYW5kIGFuZCBzY3JpcHRzIGFnYWluXHJcbiAgICAgIGF3YWl0IHNldFBhZ2VDb250ZW50KHBhZ2UpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gQ2xlYXIgYm9keSBjb250ZW50XHJcbiAgICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xyXG4gICAgICAgIGRvY3VtZW50LmJvZHkuaW5uZXJIVE1MID1cclxuICAgICAgICAgICc8ZGl2IGlkPVwiY2hhcnQtY29udGFpbmVyXCI+PGRpdiBpZD1cImNvbnRhaW5lclwiPjwvZGl2PjwvZGl2Pic7XHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgIDIsXHJcbiAgICAgIGVycm9yLFxyXG4gICAgICAnW2Jyb3dzZXJdIENvdWxkIG5vdCBjbGVhciB0aGUgY29udGVudCBvZiB0aGUgcGFnZS4nXHJcbiAgICApO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgbmV3IFB1cHBldGVlciBQYWdlIHdpdGhpbiBhbiBleGlzdGluZyBicm93c2VyIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBJZiB0aGUgYnJvd3NlciBpbnN0YW5jZSBpcyBub3QgYXZhaWxhYmxlLCByZXR1cm5zIGZhbHNlLlxyXG4gKlxyXG4gKiBUaGUgZnVuY3Rpb24gY3JlYXRlcyBhIG5ldyBwYWdlLCBkaXNhYmxlcyBjYWNoaW5nLCBzZXRzIGNvbnRlbnQgdXNpbmdcclxuICogc2V0UGFnZUNvbnRlbnQoKSwgYW5kIHJldHVybnMgdGhlIGNyZWF0ZWQgUHVwcGV0ZWVyIFBhZ2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHsoYm9vbGVhbnxvYmplY3QpfSBSZXR1cm5zIGZhbHNlIGlmIHRoZSBicm93c2VyIGluc3RhbmNlIGlzIG5vdFxyXG4gKiBhdmFpbGFibGUsIG9yIGEgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IHJlcHJlc2VudGluZyB0aGUgbmV3bHkgY3JlYXRlZCBwYWdlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IG5ld1BhZ2UgPSBhc3luYyAoKSA9PiB7XHJcbiAgaWYgKCFicm93c2VyKSB7XHJcbiAgICByZXR1cm4gZmFsc2U7XHJcbiAgfVxyXG5cclxuICBjb25zdCBwYWdlID0gYXdhaXQgYnJvd3Nlci5uZXdQYWdlKCk7XHJcblxyXG4gIC8vIERpc2FibGUgY2FjaGVcclxuICBhd2FpdCBwYWdlLnNldENhY2hlRW5hYmxlZChmYWxzZSk7XHJcblxyXG4gIC8vIFNldCB0aGUgY29udGVudFxyXG4gIGF3YWl0IHNldFBhZ2VDb250ZW50KHBhZ2UpO1xyXG4gIHJldHVybiBwYWdlO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYSBQdXBwZXRlZXIgYnJvd3NlciBpbnN0YW5jZSB3aXRoIHRoZSBzcGVjaWZpZWQgYXJndW1lbnRzLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0FycmF5fSBwdXBwZXRlZXJBcmdzIC0gQWRkaXRpb25hbCBhcmd1bWVudHMgZm9yIFB1cHBldGVlciBsYXVuY2guXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPG9iamVjdD59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIFB1cHBldGVlciBicm93c2VyXHJcbiAqIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIG1heCByZXRyaWVzIHRvIG9wZW4gYSBicm93c2VyXHJcbiAqIGluc3RhbmNlIGFyZSByZWFjaGVkLCBvciBpZiBubyBicm93c2VyIGluc3RhbmNlIGlzIGZvdW5kIGFmdGVyIHJldHJpZXMuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgY3JlYXRlID0gYXN5bmMgKHB1cHBldGVlckFyZ3MpID0+IHtcclxuICBjb25zdCBhbGxBcmdzID0gWy4uLm1pbmltYWxBcmdzLCAuLi4ocHVwcGV0ZWVyQXJncyB8fCBbXSldO1xyXG5cclxuICAvLyBDcmVhdGUgYSBicm93c2VyXHJcbiAgaWYgKCFicm93c2VyKSB7XHJcbiAgICBsZXQgdHJ5Q291bnQgPSAwO1xyXG5cclxuICAgIGNvbnN0IG9wZW4gPSBhc3luYyAoKSA9PiB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbYnJvd3Nlcl0gQXR0ZW1wdGluZyB0byBnZXQgYSBicm93c2VyIGluc3RhbmNlICh0cnkgJHsrK3RyeUNvdW50fSkuYFxyXG4gICAgICAgICk7XHJcbiAgICAgICAgYnJvd3NlciA9IGF3YWl0IHB1cHBldGVlci5sYXVuY2goe1xyXG4gICAgICAgICAgaGVhZGxlc3M6ICduZXcnLFxyXG4gICAgICAgICAgYXJnczogYWxsQXJncyxcclxuICAgICAgICAgIHVzZXJEYXRhRGlyOiAnLi90bXAvJ1xyXG4gICAgICAgIH0pO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAgIDEsXHJcbiAgICAgICAgICBlcnJvcixcclxuICAgICAgICAgICdbYnJvd3Nlcl0gRmFpbGVkIHRvIGxhdW5jaCBhIGJyb3dzZXIgaW5zdGFuY2UuJ1xyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIC8vIFJldHJ5IHRvIGxhdW5jaCBicm93c2VyIHVudGlsIHJlYWNoaW5nIG1heCBhdHRlbXB0c1xyXG4gICAgICAgIGlmICh0cnlDb3VudCA8IDI1KSB7XHJcbiAgICAgICAgICBsb2coMywgYFticm93c2VyXSBSZXRyeSB0byBvcGVuIGEgYnJvd3NlciAoJHt0cnlDb3VudH0gb3V0IG9mIDI1KS5gKTtcclxuICAgICAgICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNwb25zZSkgPT4gc2V0VGltZW91dChyZXNwb25zZSwgNDAwMCkpO1xyXG4gICAgICAgICAgYXdhaXQgb3BlbigpO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH07XHJcblxyXG4gICAgdHJ5IHtcclxuICAgICAgYXdhaXQgb3BlbigpO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdbYnJvd3Nlcl0gTWF4aW11bSByZXRyaWVzIHRvIG9wZW4gYSBicm93c2VyIGluc3RhbmNlIHJlYWNoZWQuJ1xyXG4gICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoIWJyb3dzZXIpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbYnJvd3Nlcl0gQ2Fubm90IGZpbmQgYSBicm93c2VyIHRvIG9wZW4uJyk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gYSBicm93c2VyIHByb21pc2VcclxuICByZXR1cm4gYnJvd3NlcjtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgdGhlIGV4aXN0aW5nIFB1cHBldGVlciBicm93c2VyIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxvYmplY3Q+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBQdXBwZXRlZXIgYnJvd3NlclxyXG4gKiBpbnN0YW5jZS5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiBubyB2YWxpZCBicm93c2VyIGhhcyBiZWVuXHJcbiAqIGNyZWF0ZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0ID0gYXN5bmMgKCkgPT4ge1xyXG4gIGlmICghYnJvd3Nlcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbYnJvd3Nlcl0gTm8gdmFsaWQgYnJvd3NlciBoYXMgYmVlbiBjcmVhdGVkLicpO1xyXG4gIH1cclxuXHJcbiAgcmV0dXJuIGJyb3dzZXI7XHJcbn07XHJcblxyXG4vKipcclxuICogQ2xvc2VzIHRoZSBQdXBwZXRlZXIgYnJvd3NlciBpbnN0YW5jZSBpZiBpdCBpcyBjb25uZWN0ZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPGJvb2xlYW4+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIHRydWUgYWZ0ZXIgdGhlIGJyb3dzZXJcclxuICogaXMgY2xvc2VkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGNsb3NlID0gYXN5bmMgKCkgPT4ge1xyXG4gIC8vIENsb3NlIHRoZSBicm93c2VyIHdoZW4gY29ubm5lY3RlZFxyXG4gIGlmIChicm93c2VyPy5pc0Nvbm5lY3RlZCgpKSB7XHJcbiAgICBhd2FpdCBicm93c2VyLmNsb3NlKCk7XHJcbiAgICBsb2coNCwgJ1ticm93c2VyXSBDbG9zZWQgdGhlIGJyb3dzZXIuJyk7XHJcbiAgfVxyXG4gIHJldHVybiB0cnVlO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIG5ld1BhZ2UsXHJcbiAgY2xlYXJQYWdlLFxyXG4gIGdldCxcclxuICBjbG9zZVxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHBhdGggZnJvbSAncGF0aCc7XHJcbmltcG9ydCAqIGFzIHVybCBmcm9tICd1cmwnO1xyXG5cclxuaW1wb3J0IGNhY2hlIGZyb20gJy4vY2FjaGUuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHN2Z1RlbXBsYXRlIGZyb20gJy4vLi4vdGVtcGxhdGVzL3N2Z19leHBvcnQvc3ZnX2V4cG9ydC5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuY29uc3QgX19iYXNlZGlyID0gdXJsLmZpbGVVUkxUb1BhdGgobmV3IFVSTCgnLicsIGltcG9ydC5tZXRhLnVybCkpO1xyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyB0aGUgY2xpcHBpbmcgcmVnaW9uIGNvb3JkaW5hdGVzIG9mIHRoZSBzcGVjaWZpZWQgcGFnZSBlbGVtZW50IHdpdGhcclxuICogdGhlIGlkICdjaGFydC1jb250YWluZXInLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gYW4gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogeCwgeSwgd2lkdGgsIGFuZCBoZWlnaHQgcHJvcGVydGllcy5cclxuICovXHJcbmNvbnN0IGdldENsaXBSZWdpb24gPSAocGFnZSkgPT5cclxuICBwYWdlLiRldmFsKCcjY2hhcnQtY29udGFpbmVyJywgKGVsZW1lbnQpID0+IHtcclxuICAgIGNvbnN0IHsgeCwgeSwgd2lkdGgsIGhlaWdodCB9ID0gZWxlbWVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcclxuICAgIHJldHVybiB7XHJcbiAgICAgIHgsXHJcbiAgICAgIHksXHJcbiAgICAgIHdpZHRoLFxyXG4gICAgICBoZWlnaHQ6IE1hdGgudHJ1bmMoaGVpZ2h0ID4gMSA/IGhlaWdodCA6IDUwMClcclxuICAgIH07XHJcbiAgfSk7XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhbiBpbWFnZSB1c2luZyBQdXBwZXRlZXIncyBwYWdlIHNjcmVlbnNob3QgZnVuY3Rpb25hbGl0eSB3aXRoXHJcbiAqIHNwZWNpZmllZCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICogQHBhcmFtIHtzdHJpbmd9IHR5cGUgLSBJbWFnZSB0eXBlLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gZW5jb2RpbmcgLSBJbWFnZSBlbmNvZGluZy5cclxuICogQHBhcmFtIHtPYmplY3R9IGNsaXAgLSBDbGlwcGluZyByZWdpb24gY29vcmRpbmF0ZXMuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSByYXN0ZXJpemF0aW9uVGltZW91dCAtIFRpbWVvdXQgZm9yIHJhc3Rlcml6YXRpb25cclxuICogaW4gbWlsbGlzZWNvbmRzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxCdWZmZXI+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgaW1hZ2UgYnVmZmVyIG9yIHJlamVjdGluZ1xyXG4gKiB3aXRoIGFuIEV4cG9ydEVycm9yIGZvciB0aW1lb3V0LlxyXG4gKi9cclxuY29uc3QgY3JlYXRlSW1hZ2UgPSAocGFnZSwgdHlwZSwgZW5jb2RpbmcsIGNsaXAsIHJhc3Rlcml6YXRpb25UaW1lb3V0KSA9PlxyXG4gIFByb21pc2UucmFjZShbXHJcbiAgICBwYWdlLnNjcmVlbnNob3Qoe1xyXG4gICAgICB0eXBlLFxyXG4gICAgICBlbmNvZGluZyxcclxuICAgICAgY2xpcCxcclxuXHJcbiAgICAgIC8vICM0NDcsICM0NjMgLSBhbHdheXMgcmVuZGVyIG9uIGEgdHJhbnNwYXJlbnQgcGFnZSBpZiB0aGUgZXhwZWN0ZWQgdHlwZVxyXG4gICAgICAvLyBmb3JtYXQgaXMgUE5HXHJcbiAgICAgIG9taXRCYWNrZ3JvdW5kOiB0eXBlID09ICdwbmcnXHJcbiAgICB9KSxcclxuICAgIG5ldyBQcm9taXNlKChfcmVzb2x2ZSwgcmVqZWN0KSA9PlxyXG4gICAgICBzZXRUaW1lb3V0KFxyXG4gICAgICAgICgpID0+IHJlamVjdChuZXcgRXhwb3J0RXJyb3IoJ1Jhc3Rlcml6YXRpb24gdGltZW91dCcpKSxcclxuICAgICAgICByYXN0ZXJpemF0aW9uVGltZW91dCB8fCAxNTAwXHJcbiAgICAgIClcclxuICAgIClcclxuICBdKTtcclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgUERGIHVzaW5nIFB1cHBldGVlcidzIHBhZ2UgcGRmIGZ1bmN0aW9uYWxpdHkgd2l0aCBzcGVjaWZpZWRcclxuICogb3B0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBoZWlnaHQgLSBQREYgaGVpZ2h0LlxyXG4gKiBAcGFyYW0ge251bWJlcn0gd2lkdGggLSBQREYgd2lkdGguXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBlbmNvZGluZyAtIFBERiBlbmNvZGluZy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8QnVmZmVyPn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIFBERiBidWZmZXIuXHJcbiAqL1xyXG5jb25zdCBjcmVhdGVQREYgPSAocGFnZSwgaGVpZ2h0LCB3aWR0aCwgZW5jb2RpbmcpID0+XHJcbiAgcGFnZS5wZGYoe1xyXG4gICAgLy8gVGhpcyB3aWxsIHJlbW92ZSBhbiBleHRyYSBlbXB0eSBwYWdlIGluIFBERiBleHBvcnRzXHJcbiAgICBoZWlnaHQ6IGhlaWdodCArIDEsXHJcbiAgICB3aWR0aCxcclxuICAgIGVuY29kaW5nXHJcbiAgfSk7XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhbiBTVkcgc3RyaW5nIGJ5IGV2YWx1YXRpbmcgdGhlIG91dGVySFRNTCBvZiB0aGUgZmlyc3QgJ3N2ZycgZWxlbWVudFxyXG4gKiBpbnNpZGUgYW4gZWxlbWVudCB3aXRoIHRoZSBpZCAnY29udGFpbmVyJy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZz59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBTVkcgc3RyaW5nLlxyXG4gKi9cclxuY29uc3QgY3JlYXRlU1ZHID0gKHBhZ2UpID0+XHJcbiAgcGFnZS4kZXZhbCgnI2NvbnRhaW5lciBzdmc6Zmlyc3Qtb2YtdHlwZScsIChlbGVtZW50KSA9PiBlbGVtZW50Lm91dGVySFRNTCk7XHJcblxyXG4vKipcclxuICogU2V0cyB0aGUgc3BlY2lmaWVkIGNoYXJ0IGFuZCBvcHRpb25zIGFzIGNvbmZpZ3VyYXRpb24gaW50byB0aGUgdHJpZ2dlckV4cG9ydFxyXG4gKiBmdW5jdGlvbiB3aXRoaW4gdGhlIHdpbmRvdyBjb250ZXh0IHVzaW5nIHBhZ2UuZXZhbHVhdGUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge2FueX0gY2hhcnQgLSBUaGUgY2hhcnQgb2JqZWN0IHRvIGJlIGNvbmZpZ3VyZWQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gQ29uZmlndXJhdGlvbiBvcHRpb25zIGZvciB0aGUgY2hhcnQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBQcm9taXNlIHJlc29sdmluZyBhZnRlciB0aGUgY29uZmlndXJhdGlvbiBpcyBzZXQuXHJcbiAqL1xyXG5jb25zdCBzZXRBc0NvbmZpZyA9IChwYWdlLCBjaGFydCwgb3B0aW9ucykgPT5cclxuICBwYWdlLmV2YWx1YXRlKFxyXG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAoY2hhcnQsIG9wdGlvbnMpID0+IHdpbmRvdy50cmlnZ2VyRXhwb3J0KGNoYXJ0LCBvcHRpb25zKSxcclxuICAgIGNoYXJ0LFxyXG4gICAgb3B0aW9uc1xyXG4gICk7XHJcblxyXG4vKipcclxuICogRXhwb3J0cyB0byBhIGNoYXJ0IGZyb20gYSBwYWdlIHVzaW5nIFB1cHBldGVlci5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7YW55fSBjaGFydCAtIFRoZSBjaGFydCBvYmplY3Qgb3IgU1ZHIGNvbmZpZ3VyYXRpb24gdG8gYmUgZXhwb3J0ZWQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gRXhwb3J0IG9wdGlvbnMgYW5kIGNvbmZpZ3VyYXRpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZyB8IEJ1ZmZlciB8IEV4cG9ydEVycm9yPn0gUHJvbWlzZSByZXNvbHZpbmcgdG9cclxuICogdGhlIGV4cG9ydGVkIGRhdGEgb3IgcmVqZWN0aW5nIHdpdGggYW4gRXhwb3J0RXJyb3IuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCBhc3luYyAocGFnZSwgY2hhcnQsIG9wdGlvbnMpID0+IHtcclxuICAvKipcclxuICAgKiBLZWVwcyB0cmFjayBvZiBhbGwgcmVzb3VyY2VzIGFkZGVkIG9uIHRoZSBwYWdlIHdpdGggYWRkWFhYVGFnLiBldGNcclxuICAgKiBJdCdzIFZJVEFMIHRoYXQgYWxsIGFkZGVkIHJlc291cmNlcyBlbmRzIHVwIGhlcmUgc28gd2UgY2FuIGNsZWFyIHRoaW5nc1xyXG4gICAqIG91dCB3aGVuIGRvaW5nIGEgbmV3IGV4cG9ydCBpbiB0aGUgc2FtZSBwYWdlIVxyXG4gICAqL1xyXG4gIGNvbnN0IGluamVjdGVkUmVzb3VyY2VzID0gW107XHJcblxyXG4gIC8qKiBDbGVhciBvdXQgYWxsIHN0YXRlIHNldCBvbiB0aGUgcGFnZSB3aXRoIGFkZFNjcmlwdFRhZy9hZGRTdHlsZVRhZy4gKi9cclxuICBjb25zdCBjbGVhckluamVjdGVkID0gYXN5bmMgKHBhZ2UpID0+IHtcclxuICAgIGZvciAoY29uc3QgcmVzIG9mIGluamVjdGVkUmVzb3VyY2VzKSB7XHJcbiAgICAgIGF3YWl0IHJlcy5kaXNwb3NlKCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmVzZXQgYWxsIENTUyBhbmQgc2NyaXB0IHRhZ3NcclxuICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xyXG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgY29uc3QgWywgLi4uc2NyaXB0c1RvUmVtb3ZlXSA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdzY3JpcHQnKTtcclxuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgIGNvbnN0IFssIC4uLnN0eWxlc1RvUmVtb3ZlXSA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdzdHlsZScpO1xyXG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgY29uc3QgWy4uLmxpbmtzVG9SZW1vdmVdID0gZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ2xpbmsnKTtcclxuXHJcbiAgICAgIC8vIFJlbW92ZSB0YWdzXHJcbiAgICAgIGZvciAoY29uc3QgZWxlbWVudCBvZiBbXHJcbiAgICAgICAgLi4uc2NyaXB0c1RvUmVtb3ZlLFxyXG4gICAgICAgIC4uLnN0eWxlc1RvUmVtb3ZlLFxyXG4gICAgICAgIC4uLmxpbmtzVG9SZW1vdmVcclxuICAgICAgXSkge1xyXG4gICAgICAgIGVsZW1lbnQucmVtb3ZlKCk7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG4gIH07XHJcblxyXG4gIHRyeSB7XHJcbiAgICBsb2coNCwgJ1tleHBvcnRdIERldGVybWluaW5nIGV4cG9ydCBwYXRoLicpO1xyXG5cclxuICAgIGNvbnN0IGV4cG9ydE9wdGlvbnMgPSBvcHRpb25zLmV4cG9ydDtcclxuXHJcbiAgICAvLyBGb3JjZSBhIHJBRlxyXG4gICAgLy8gU2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9wdXBwZXRlZXIvcHVwcGV0ZWVyL2lzc3Vlcy83NTA3XHJcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4gcmVxdWVzdEFuaW1hdGlvbkZyYW1lKCgpID0+IHt9KSk7XHJcblxyXG4gICAgLy8gRGVjaWRlIHdoZXRoZXIgZGlzcGxheSBlcnJvciBvciBkZWJidWdlciB3cmFwcGVyIGFyb3VuZCBpdFxyXG4gICAgY29uc3QgZGlzcGxheUVycm9ycyA9XHJcbiAgICAgIGV4cG9ydE9wdGlvbnM/Lm9wdGlvbnM/LmNoYXJ0Py5kaXNwbGF5RXJyb3JzICYmXHJcbiAgICAgIGNhY2hlLmdldENhY2hlKCkuYWN0aXZlTWFuaWZlc3QubW9kdWxlcy5kZWJ1Z2dlcjtcclxuXHJcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoKGQpID0+ICh3aW5kb3cuX2Rpc3BsYXlFcnJvcnMgPSBkKSwgZGlzcGxheUVycm9ycyk7XHJcblxyXG4gICAgbGV0IGlzU1ZHO1xyXG4gICAgaWYgKFxyXG4gICAgICBjaGFydC5pbmRleE9mICYmXHJcbiAgICAgIChjaGFydC5pbmRleE9mKCc8c3ZnJykgPj0gMCB8fCBjaGFydC5pbmRleE9mKCc8P3htbCcpID49IDApXHJcbiAgICApIHtcclxuICAgICAgLy8gU1ZHIGlucHV0IGhhbmRsaW5nXHJcbiAgICAgIGxvZyg0LCAnW2V4cG9ydF0gVHJlYXRpbmcgYXMgU1ZHLicpO1xyXG5cclxuICAgICAgLy8gSWYgaW5wdXQgaXMgYWxzbyBTVkcsIGp1c3QgcmV0dXJuIGl0XHJcbiAgICAgIGlmIChleHBvcnRPcHRpb25zLnR5cGUgPT09ICdzdmcnKSB7XHJcbiAgICAgICAgcmV0dXJuIGNoYXJ0O1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpc1NWRyA9IHRydWU7XHJcbiAgICAgIGF3YWl0IHBhZ2Uuc2V0Q29udGVudChzdmdUZW1wbGF0ZShjaGFydCkpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gSlNPTiBjb25maWcgaGFuZGxpbmdcclxuICAgICAgbG9nKDQsICdbZXhwb3J0XSBUcmVhdGluZyBhcyBjb25maWcuJyk7XHJcblxyXG4gICAgICAvLyBOZWVkIHRvIHBlcmZvcm0gc3RyYWlnaHQgaW5qZWN0XHJcbiAgICAgIGlmIChleHBvcnRPcHRpb25zLnN0ckluaikge1xyXG4gICAgICAgIC8vIEluamVjdGlvbiBiYXNlZCBjb25maWd1cmF0aW9uIGV4cG9ydFxyXG4gICAgICAgIGF3YWl0IHNldEFzQ29uZmlnKFxyXG4gICAgICAgICAgcGFnZSxcclxuICAgICAgICAgIHtcclxuICAgICAgICAgICAgY2hhcnQ6IHtcclxuICAgICAgICAgICAgICBoZWlnaHQ6IGV4cG9ydE9wdGlvbnMuaGVpZ2h0LFxyXG4gICAgICAgICAgICAgIHdpZHRoOiBleHBvcnRPcHRpb25zLndpZHRoXHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0sXHJcbiAgICAgICAgICBvcHRpb25zXHJcbiAgICAgICAgKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICAvLyBCYXNpYyBjb25maWd1cmF0aW9uIGV4cG9ydFxyXG4gICAgICAgIGNoYXJ0LmNoYXJ0LmhlaWdodCA9IGV4cG9ydE9wdGlvbnMuaGVpZ2h0O1xyXG4gICAgICAgIGNoYXJ0LmNoYXJ0LndpZHRoID0gZXhwb3J0T3B0aW9ucy53aWR0aDtcclxuXHJcbiAgICAgICAgYXdhaXQgc2V0QXNDb25maWcocGFnZSwgY2hhcnQsIG9wdGlvbnMpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gVXNlIHJlc291cmNlc1xyXG4gICAgY29uc3QgcmVzb3VyY2VzID0gb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXM7XHJcbiAgICBpZiAocmVzb3VyY2VzKSB7XHJcbiAgICAgIC8vIExvYWQgY3VzdG9tIEpTIGNvZGVcclxuICAgICAgaWYgKHJlc291cmNlcy5qcykge1xyXG4gICAgICAgIGluamVjdGVkUmVzb3VyY2VzLnB1c2goXHJcbiAgICAgICAgICBhd2FpdCBwYWdlLmFkZFNjcmlwdFRhZyh7XHJcbiAgICAgICAgICAgIGNvbnRlbnQ6IHJlc291cmNlcy5qc1xyXG4gICAgICAgICAgfSlcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBMb2FkIHNjcmlwdHMgZnJvbSBhbGwgY3VzdG9tIGZpbGVzXHJcbiAgICAgIGlmIChyZXNvdXJjZXMuZmlsZXMpIHtcclxuICAgICAgICBmb3IgKGNvbnN0IGZpbGUgb2YgcmVzb3VyY2VzLmZpbGVzKSB7XHJcbiAgICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICBjb25zdCBpc0xvY2FsID0gIWZpbGUuc3RhcnRzV2l0aCgnaHR0cCcpID8gdHJ1ZSA6IGZhbHNlO1xyXG5cclxuICAgICAgICAgICAgLy8gQWRkIGVhY2ggY3VzdG9tIHNjcmlwdCBmcm9tIHJlc291cmNlcycgZmlsZXNcclxuICAgICAgICAgICAgaW5qZWN0ZWRSZXNvdXJjZXMucHVzaChcclxuICAgICAgICAgICAgICBhd2FpdCBwYWdlLmFkZFNjcmlwdFRhZyhcclxuICAgICAgICAgICAgICAgIGlzTG9jYWxcclxuICAgICAgICAgICAgICAgICAgPyB7XHJcbiAgICAgICAgICAgICAgICAgICAgICBjb250ZW50OiByZWFkRmlsZVN5bmMoZmlsZSwgJ3V0ZjgnKVxyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgOiB7XHJcbiAgICAgICAgICAgICAgICAgICAgICB1cmw6IGZpbGVcclxuICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgKVxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgICAgICAgIDIsXHJcbiAgICAgICAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgICAgICAgYFtleHBvcnRdIFRoZSBKUyBmaWxlICR7ZmlsZX0gY2Fubm90IGJlIGxvYWRlZC5gXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBMb2FkIENTU1xyXG4gICAgICBpZiAocmVzb3VyY2VzLmNzcykge1xyXG4gICAgICAgIGxldCBjc3NJbXBvcnRzID0gcmVzb3VyY2VzLmNzcy5tYXRjaCgvQGltcG9ydFxccyooW147XSopOy9nKTtcclxuICAgICAgICBpZiAoY3NzSW1wb3J0cykge1xyXG4gICAgICAgICAgLy8gSGFuZGxlIGNzcyBzZWN0aW9uXHJcbiAgICAgICAgICBmb3IgKGxldCBjc3NJbXBvcnRQYXRoIG9mIGNzc0ltcG9ydHMpIHtcclxuICAgICAgICAgICAgaWYgKGNzc0ltcG9ydFBhdGgpIHtcclxuICAgICAgICAgICAgICBjc3NJbXBvcnRQYXRoID0gY3NzSW1wb3J0UGF0aFxyXG4gICAgICAgICAgICAgICAgLnJlcGxhY2UoJ3VybCgnLCAnJylcclxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKCdAaW1wb3J0JywgJycpXHJcbiAgICAgICAgICAgICAgICAucmVwbGFjZSgvXCIvZywgJycpXHJcbiAgICAgICAgICAgICAgICAucmVwbGFjZSgvJy9nLCAnJylcclxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKC87LywgJycpXHJcbiAgICAgICAgICAgICAgICAucmVwbGFjZSgvXFwpL2csICcnKVxyXG4gICAgICAgICAgICAgICAgLnRyaW0oKTtcclxuXHJcbiAgICAgICAgICAgICAgLy8gQWRkIGVhY2ggY3VzdG9tIGNzcyBmcm9tIHJlc291cmNlc1xyXG4gICAgICAgICAgICAgIGlmIChjc3NJbXBvcnRQYXRoLnN0YXJ0c1dpdGgoJ2h0dHAnKSkge1xyXG4gICAgICAgICAgICAgICAgaW5qZWN0ZWRSZXNvdXJjZXMucHVzaChcclxuICAgICAgICAgICAgICAgICAgYXdhaXQgcGFnZS5hZGRTdHlsZVRhZyh7XHJcbiAgICAgICAgICAgICAgICAgICAgdXJsOiBjc3NJbXBvcnRQYXRoXHJcbiAgICAgICAgICAgICAgICAgIH0pXHJcbiAgICAgICAgICAgICAgICApO1xyXG4gICAgICAgICAgICAgIH0gZWxzZSBpZiAob3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0ZpbGVSZXNvdXJjZXMpIHtcclxuICAgICAgICAgICAgICAgIGluamVjdGVkUmVzb3VyY2VzLnB1c2goXHJcbiAgICAgICAgICAgICAgICAgIGF3YWl0IHBhZ2UuYWRkU3R5bGVUYWcoe1xyXG4gICAgICAgICAgICAgICAgICAgIHBhdGg6IHBhdGguam9pbihfX2Jhc2VkaXIsIGNzc0ltcG9ydFBhdGgpXHJcbiAgICAgICAgICAgICAgICAgIH0pXHJcbiAgICAgICAgICAgICAgICApO1xyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gVGhlIHJlc3Qgb2YgdGhlIENTUyBzZWN0aW9uIHdpbGwgYmUgY29udGVudCBieSBub3dcclxuICAgICAgICBpbmplY3RlZFJlc291cmNlcy5wdXNoKFxyXG4gICAgICAgICAgYXdhaXQgcGFnZS5hZGRTdHlsZVRhZyh7XHJcbiAgICAgICAgICAgIGNvbnRlbnQ6IHJlc291cmNlcy5jc3MucmVwbGFjZSgvQGltcG9ydFxccyooW147XSopOy9nLCAnJykgfHwgJyAnXHJcbiAgICAgICAgICB9KVxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBHZXQgdGhlIHJlYWwgY2hhcnQgc2l6ZVxyXG4gICAgY29uc3Qgc2l6ZSA9IGlzU1ZHXHJcbiAgICAgID8gYXdhaXQgcGFnZS4kZXZhbChcclxuICAgICAgICAgICcjY2hhcnQtY29udGFpbmVyIHN2ZzpmaXJzdC1vZi10eXBlJyxcclxuICAgICAgICAgIChlbGVtZW50LCBzY2FsZSkgPT4gKHtcclxuICAgICAgICAgICAgY2hhcnRIZWlnaHQ6IGVsZW1lbnQuaGVpZ2h0LmJhc2VWYWwudmFsdWUgKiBzY2FsZSxcclxuICAgICAgICAgICAgY2hhcnRXaWR0aDogZWxlbWVudC53aWR0aC5iYXNlVmFsLnZhbHVlICogc2NhbGVcclxuICAgICAgICAgIH0pLFxyXG4gICAgICAgICAgcGFyc2VGbG9hdChleHBvcnRPcHRpb25zLnNjYWxlKVxyXG4gICAgICAgIClcclxuICAgICAgOiBhd2FpdCBwYWdlLmV2YWx1YXRlKCgpID0+IHtcclxuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgICAgY29uc3QgeyBjaGFydEhlaWdodCwgY2hhcnRXaWR0aCB9ID0gd2luZG93LkhpZ2hjaGFydHMuY2hhcnRzWzBdO1xyXG4gICAgICAgICAgcmV0dXJuIHtcclxuICAgICAgICAgICAgY2hhcnRIZWlnaHQsXHJcbiAgICAgICAgICAgIGNoYXJ0V2lkdGhcclxuICAgICAgICAgIH07XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgLy8gU2V0IGZpbmFsIGhlaWdodCBhbmQgd2lkdGggZm9yIHZpZXdwb3J0XHJcbiAgICBjb25zdCB2aWV3cG9ydEhlaWdodCA9IE1hdGguY2VpbChzaXplPy5jaGFydEhlaWdodCB8fCBleHBvcnRPcHRpb25zLmhlaWdodCk7XHJcbiAgICBjb25zdCB2aWV3cG9ydFdpZHRoID0gTWF0aC5jZWlsKHNpemU/LmNoYXJ0V2lkdGggfHwgZXhwb3J0T3B0aW9ucy53aWR0aCk7XHJcblxyXG4gICAgLy8gU2V0IHRoZSB2aWV3cG9ydCBmb3IgdGhlIGZpcnN0IHRpbWVcclxuICAgIC8vIE5PVEU6IHRoZSBjYWxsIHRvIHNldFZpZXdwb3J0IGlzIGV4cGVuc2l2ZSAtIGNhbiB3ZSBnZXQgYXdheSB3aXRoIG9ubHlcclxuICAgIC8vIGNhbGxpbmcgaXQgb25jZSwgZS5nLiBtb3ZpbmcgdGhpcyBvbmUgaW50byB0aGUgaXNTVkcgY29uZGl0aW9uIGJlbG93P1xyXG4gICAgYXdhaXQgcGFnZS5zZXRWaWV3cG9ydCh7XHJcbiAgICAgIGhlaWdodDogdmlld3BvcnRIZWlnaHQsXHJcbiAgICAgIHdpZHRoOiB2aWV3cG9ydFdpZHRoLFxyXG4gICAgICBkZXZpY2VTY2FsZUZhY3RvcjogaXNTVkcgPyAxIDogcGFyc2VGbG9hdChleHBvcnRPcHRpb25zLnNjYWxlKVxyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gUHJlcGFyZSBhIHpvb20gY2FsbGJhY2sgZm9yIHRoZSBuZXh0IGV2YWx1YXRlIGNhbGxcclxuICAgIGNvbnN0IHpvb21DYWxsYmFjayA9IGlzU1ZHXHJcbiAgICAgID8gLy8gSW4gY2FzZSBvZiBTVkcgdGhlIHpvb20gbXVzdCBiZSBzZXQgZGlyZWN0bHkgZm9yIGJvZHlcclxuICAgICAgICAoc2NhbGUpID0+IHtcclxuICAgICAgICAgIC8vIFNldCB0aGUgem9vbSBhcyBzY2FsZVxyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLnpvb20gPSBzY2FsZTtcclxuXHJcbiAgICAgICAgICAvLyBTZXQgdGhlIG1hcmdpbiB0byAwcHhcclxuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgICAgZG9jdW1lbnQuYm9keS5zdHlsZS5tYXJnaW4gPSAnMHB4JztcclxuICAgICAgICB9XHJcbiAgICAgIDogLy8gTm8gbmVlZCBmb3Igc3VjaCBzY2FsZSBtYW5pcHVsYXRpb24gaW4gY2FzZSBvZiBvdGhlciB0eXBlcyBvZiBleHBvcnRzXHJcbiAgICAgICAgKCkgPT4ge1xyXG4gICAgICAgICAgLy8gUmVzZXQgdGhlIHpvb20gZm9yIG90aGVyIGV4cG9ydHMgdGhhbiB0byBTVkdzXHJcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUuem9vbSA9IDE7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAvLyBTZXQgdGhlIHpvb20gYWNjb3JkaW5nbHlcclxuICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoem9vbUNhbGxiYWNrLCBwYXJzZUZsb2F0KGV4cG9ydE9wdGlvbnMuc2NhbGUpKTtcclxuXHJcbiAgICAvLyBHZXQgdGhlIGNsaXAgcmVnaW9uIGZvciB0aGUgcGFnZVxyXG4gICAgY29uc3QgeyBoZWlnaHQsIHdpZHRoLCB4LCB5IH0gPSBhd2FpdCBnZXRDbGlwUmVnaW9uKHBhZ2UpO1xyXG5cclxuICAgIGlmICghaXNTVkcpIHtcclxuICAgICAgLy8gU2V0IHRoZSBmaW5hbCB2aWV3cG9ydCBub3cgdGhhdCB3ZSBoYXZlIHRoZSByZWFsIGhlaWdodFxyXG4gICAgICBhd2FpdCBwYWdlLnNldFZpZXdwb3J0KHtcclxuICAgICAgICB3aWR0aDogTWF0aC5yb3VuZCh3aWR0aCksXHJcbiAgICAgICAgaGVpZ2h0OiBNYXRoLnJvdW5kKGhlaWdodCksXHJcbiAgICAgICAgZGV2aWNlU2NhbGVGYWN0b3I6IHBhcnNlRmxvYXQoZXhwb3J0T3B0aW9ucy5zY2FsZSlcclxuICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgbGV0IGRhdGE7XHJcbiAgICAvLyBSQVNURVJJWkFUSU9OXHJcbiAgICBpZiAoZXhwb3J0T3B0aW9ucy50eXBlID09PSAnc3ZnJykge1xyXG4gICAgICAvLyBTVkdcclxuICAgICAgZGF0YSA9IGF3YWl0IGNyZWF0ZVNWRyhwYWdlKTtcclxuICAgIH0gZWxzZSBpZiAoZXhwb3J0T3B0aW9ucy50eXBlID09PSAncG5nJyB8fCBleHBvcnRPcHRpb25zLnR5cGUgPT09ICdqcGVnJykge1xyXG4gICAgICAvLyBQTkcgb3IgSlBFR1xyXG4gICAgICBkYXRhID0gYXdhaXQgY3JlYXRlSW1hZ2UoXHJcbiAgICAgICAgcGFnZSxcclxuICAgICAgICBleHBvcnRPcHRpb25zLnR5cGUsXHJcbiAgICAgICAgJ2Jhc2U2NCcsXHJcbiAgICAgICAge1xyXG4gICAgICAgICAgd2lkdGg6IHZpZXdwb3J0V2lkdGgsXHJcbiAgICAgICAgICBoZWlnaHQ6IHZpZXdwb3J0SGVpZ2h0LFxyXG4gICAgICAgICAgeCxcclxuICAgICAgICAgIHlcclxuICAgICAgICB9LFxyXG4gICAgICAgIGV4cG9ydE9wdGlvbnMucmFzdGVyaXphdGlvblRpbWVvdXRcclxuICAgICAgKTtcclxuICAgIH0gZWxzZSBpZiAoZXhwb3J0T3B0aW9ucy50eXBlID09PSAncGRmJykge1xyXG4gICAgICAvLyBQREZcclxuICAgICAgZGF0YSA9IGF3YWl0IGNyZWF0ZVBERihwYWdlLCB2aWV3cG9ydEhlaWdodCwgdmlld3BvcnRXaWR0aCwgJ2Jhc2U2NCcpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgIGBbZXhwb3J0XSBVbnN1cHBvcnRlZCBvdXRwdXQgZm9ybWF0ICR7ZXhwb3J0T3B0aW9ucy50eXBlfS5gXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRGVzdHJveSBvbGQgY2hhcnRzIGFmdGVyIHRoZSBleHBvcnQgaXMgZG9uZVxyXG4gICAgYXdhaXQgcGFnZS5ldmFsdWF0ZSgoKSA9PiB7XHJcbiAgICAgIC8vIFdlIGFyZSBub3QgZ3VhcmFudGVlZCB0aGF0IEhpZ2hjaGFydHMgaXMgbG9hZGVkLCBlLGcsIHdoZW4gZG9pbmcgU1ZHXHJcbiAgICAgIC8vIGV4cG9ydHNcclxuICAgICAgaWYgKHR5cGVvZiBIaWdoY2hhcnRzICE9PSAndW5kZWZpbmVkJykge1xyXG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgIGNvbnN0IG9sZENoYXJ0cyA9IEhpZ2hjaGFydHMuY2hhcnRzO1xyXG5cclxuICAgICAgICAvLyBDaGVjayBpbiBhbnkgYWxyZWFkeSBleGlzdGluZyBjaGFydHNcclxuICAgICAgICBpZiAoQXJyYXkuaXNBcnJheShvbGRDaGFydHMpICYmIG9sZENoYXJ0cy5sZW5ndGgpIHtcclxuICAgICAgICAgIC8vIERlc3Ryb3kgb2xkIGNoYXJ0c1xyXG4gICAgICAgICAgZm9yIChjb25zdCBvbGRDaGFydCBvZiBvbGRDaGFydHMpIHtcclxuICAgICAgICAgICAgb2xkQ2hhcnQgJiYgb2xkQ2hhcnQuZGVzdHJveSgpO1xyXG4gICAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgICAgSGlnaGNoYXJ0cy5jaGFydHMuc2hpZnQoKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG5cclxuICAgIGF3YWl0IGNsZWFySW5qZWN0ZWQocGFnZSk7XHJcbiAgICByZXR1cm4gZGF0YTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgYXdhaXQgY2xlYXJJbmplY3RlZChwYWdlKTtcclxuICAgIHJldHVybiBlcnJvcjtcclxuICB9XHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IGNzc1RlbXBsYXRlIGZyb20gJy4vY3NzLmpzJztcclxuXHJcbmV4cG9ydCBkZWZhdWx0IChjaGFydCkgPT4gYFxyXG48IURPQ1RZUEUgaHRtbD5cclxuPGh0bWwgbGFuZz0nZW4tVVMnPlxyXG4gIDxoZWFkPlxyXG4gICAgPG1ldGEgaHR0cC1lcXVpdj1cIkNvbnRlbnQtVHlwZVwiIGNvbnRlbnQ9XCJ0ZXh0L2h0bWw7IGNoYXJzZXQ9dXRmLThcIj5cclxuICAgIDx0aXRsZT5IaWdoY2FydHMgRXhwb3J0PC90aXRsZT5cclxuICA8L2hlYWQ+XHJcbiAgPHN0eWxlPlxyXG4gICAgJHtjc3NUZW1wbGF0ZSgpfVxyXG4gIDwvc3R5bGU+XHJcbiAgPGJvZHk+XHJcbiAgICA8ZGl2IGlkPVwiY2hhcnQtY29udGFpbmVyXCI+XHJcbiAgICAgICR7Y2hhcnR9XHJcbiAgICA8L2Rpdj5cclxuICA8L2JvZHk+XHJcbjwvaHRtbD5cclxuXHJcbmA7XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgUG9vbCB9IGZyb20gJ3Rhcm4nO1xyXG5pbXBvcnQgeyB2NCBhcyB1dWlkIH0gZnJvbSAndXVpZCc7XHJcblxyXG5pbXBvcnQge1xyXG4gIGNsb3NlIGFzIGJyb3dzZXJDbG9zZSxcclxuICBjcmVhdGUgYXMgY3JlYXRlQnJvd3NlcixcclxuICBuZXdQYWdlIGFzIGJyb3dzZXJOZXdQYWdlLFxyXG4gIGNsZWFyUGFnZVxyXG59IGZyb20gJy4vYnJvd3Nlci5qcyc7XHJcbmltcG9ydCBwdXBwZXRlZXJFeHBvcnQgZnJvbSAnLi9leHBvcnQuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgbWVhc3VyZVRpbWUgfSBmcm9tICcuL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG5sZXQgcGVyZm9ybWVkRXhwb3J0cyA9IDA7XHJcbmxldCBleHBvcnRBdHRlbXB0cyA9IDA7XHJcbmxldCB0aW1lU3BlbnQgPSAwO1xyXG5sZXQgZHJvcHBlZEV4cG9ydHMgPSAwO1xyXG5sZXQgc3BlbnRBdmVyYWdlID0gMDtcclxubGV0IHBvb2xDb25maWcgPSB7fTtcclxuXHJcbi8vIFRoZSBwb29sIGluc3RhbmNlXHJcbmxldCBwb29sID0gZmFsc2U7XHJcblxyXG4vLyBDdXN0b20gcHVwcGV0ZWVyIGFyZ3VtZW50c1xyXG5sZXQgcHVwcGV0ZWVyQXJncztcclxuXHJcbmNvbnN0IGZhY3RvcnkgPSB7XHJcbiAgLyoqXHJcbiAgICogQ3JlYXRlcyBhIG5ldyB3b3JrZXIgcGFnZSBmb3IgdGhlIGV4cG9ydCBwb29sLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge09iamVjdH0gLSBBbiBvYmplY3QgY29udGFpbmluZyB0aGUgd29ya2VyIElELCBhIHJlZmVyZW5jZSB0byB0aGVcclxuICAgKiBicm93c2VyIHBhZ2UsIGFuZCBpbml0aWFsIHdvcmsgY291bnQuXHJcbiAgICpcclxuICAgKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gLSBJZiB0aGVyZSdzIGFuIGVycm9yIGR1cmluZyB0aGUgY3JlYXRpb24gb2YgdGhlIG5ld1xyXG4gICAqIHBhZ2UuXHJcbiAgICovXHJcbiAgY3JlYXRlOiBhc3luYyAoKSA9PiB7XHJcbiAgICBsZXQgcGFnZSA9IGZhbHNlO1xyXG5cclxuICAgIGNvbnN0IGlkID0gdXVpZCgpO1xyXG4gICAgY29uc3Qgc3RhcnREYXRlID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XHJcblxyXG4gICAgdHJ5IHtcclxuICAgICAgcGFnZSA9IGF3YWl0IGJyb3dzZXJOZXdQYWdlKCk7XHJcblxyXG4gICAgICBpZiAoIXBhZ2UgfHwgcGFnZS5pc0Nsb3NlZCgpKSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdUaGUgcGFnZSBpcyBpbnZhbGlkIG9yIGNsb3NlZC4nKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgbG9nKFxyXG4gICAgICAgIDMsXHJcbiAgICAgICAgYFtwb29sXSBTdWNjZXNzZnVsbHkgY3JlYXRlZCBhIHdvcmtlciAke2lkfSAtIHRvb2sgJHtcclxuICAgICAgICAgIG5ldyBEYXRlKCkuZ2V0VGltZSgpIC0gc3RhcnREYXRlXHJcbiAgICAgICAgfSBtcy5gXHJcbiAgICAgICk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ0Vycm9yIGVuY291bnRlcmVkIHdoZW4gY3JlYXRpbmcgYSBuZXcgcGFnZS4nXHJcbiAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiB7XHJcbiAgICAgIGlkLFxyXG4gICAgICBwYWdlLFxyXG4gICAgICAvLyBUcnkgdG8gZGlzdHJpYnV0ZSB0aGUgaW5pdGlhbCB3b3JrIGNvdW50XHJcbiAgICAgIHdvcmtDb3VudDogTWF0aC5yb3VuZChNYXRoLnJhbmRvbSgpICogKHBvb2xDb25maWcud29ya0xpbWl0IC8gMikpXHJcbiAgICB9O1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFZhbGlkYXRlcyBhIHdvcmtlciBwYWdlIGluIHRoZSBleHBvcnQgcG9vbCwgY2hlY2tpbmcgaWYgaXQgaGFzIGV4Y2VlZGVkXHJcbiAgICogdGhlIHdvcmsgbGltaXQuXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge09iamVjdH0gd29ya2VySGFuZGxlIC0gVGhlIGhhbmRsZSB0byB0aGUgd29ya2VyLCBjb250YWluaW5nIHRoZVxyXG4gICAqIHdvcmtlcidzIElELCBhIHJlZmVyZW5jZSB0byB0aGUgYnJvd3NlciBwYWdlLCBhbmQgd29yayBjb3VudC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHtib29sZWFufSAtIFJldHVybnMgdHJ1ZSBpZiB0aGUgd29ya2VyIGlzIHZhbGlkIGFuZCB3aXRoaW5cclxuICAgKiB0aGUgd29yayBsaW1pdDsgb3RoZXJ3aXNlLCByZXR1cm5zIGZhbHNlLlxyXG4gICAqL1xyXG4gIHZhbGlkYXRlOiBhc3luYyAod29ya2VySGFuZGxlKSA9PiB7XHJcbiAgICBpZiAoXHJcbiAgICAgIHBvb2xDb25maWcud29ya0xpbWl0ICYmXHJcbiAgICAgICsrd29ya2VySGFuZGxlLndvcmtDb3VudCA+IHBvb2xDb25maWcud29ya0xpbWl0XHJcbiAgICApIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDMsXHJcbiAgICAgICAgYFtwb29sXSBXb3JrZXIgZmFpbGVkIHZhbGlkYXRpb246IGV4Y2VlZGVkIHdvcmsgbGltaXQgKGxpbWl0IGlzICR7cG9vbENvbmZpZy53b3JrTGltaXR9KS5gXHJcbiAgICAgICk7XHJcbiAgICAgIHJldHVybiBmYWxzZTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBDbGVhciBwYWdlXHJcbiAgICBhd2FpdCBjbGVhclBhZ2Uod29ya2VySGFuZGxlLnBhZ2UsIHRydWUpO1xyXG4gICAgcmV0dXJuIHRydWU7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogRGVzdHJveXMgYSB3b3JrZXIgZW50cnkgaW4gdGhlIGV4cG9ydCBwb29sLCBjbG9zaW5nIGl0cyBhc3NvY2lhdGVkIHBhZ2UuXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge09iamVjdH0gd29ya2VySGFuZGxlIC0gVGhlIGhhbmRsZSB0byB0aGUgd29ya2VyLCBjb250YWluaW5nXHJcbiAgICogdGhlIHdvcmtlcidzIElEIGFuZCBhIHJlZmVyZW5jZSB0byB0aGUgYnJvd3NlciBwYWdlLlxyXG4gICAqL1xyXG4gIGRlc3Ryb3k6ICh3b3JrZXJIYW5kbGUpID0+IHtcclxuICAgIGxvZygzLCBgW3Bvb2xdIERlc3Ryb3lpbmcgcG9vbCBlbnRyeSAke3dvcmtlckhhbmRsZS5pZH0uYCk7XHJcblxyXG4gICAgaWYgKHdvcmtlckhhbmRsZS5wYWdlKSB7XHJcbiAgICAgIC8vIFdlIGRvbid0IHJlYWxseSBuZWVkIHRvIHdhaXQgYXJvdW5kIGZvciB0aGlzLlxyXG4gICAgICB3b3JrZXJIYW5kbGUucGFnZS5jbG9zZSgpO1xyXG4gICAgfVxyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyB0aGUgZXhwb3J0IHBvb2wgd2l0aCB0aGUgcHJvdmlkZWQgY29uZmlndXJhdGlvbiwgY3JlYXRpbmdcclxuICogYSBicm93c2VyIGluc3RhbmNlIGFuZCBzZXR0aW5nIHVwIHdvcmtlciByZXNvdXJjZXMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjb25maWcgLSBDb25maWd1cmF0aW9uIG9wdGlvbnMgZm9yIHRoZSBleHBvcnQgcG9vbCBhbG9uZ1xyXG4gKiB3aXRoIGN1c3RvbSBwdXBwZXRlZXIgYXJndW1lbnRzIGZvciB0aGUgcHVwcGV0ZWVyLmxhdW5jaCBmdW5jdGlvbi5cclxuICovXHJcbmV4cG9ydCBjb25zdCBpbml0UG9vbCA9IGFzeW5jIChjb25maWcpID0+IHtcclxuICAvLyBGb3IgdGhlIG1vZHVsZSBzY29wZSB1c2FnZVxyXG4gIHBvb2xDb25maWcgPSBjb25maWcgJiYgY29uZmlnLnBvb2wgPyB7IC4uLmNvbmZpZy5wb29sIH0gOiB7fTtcclxuXHJcbiAgLy8gQXR0YWNoIHByb2Nlc3MnIGV4aXQgbGlzdGVuZXJzXHJcbiAgaWYgKHBvb2xDb25maWcubGlzdGVuVG9Qcm9jZXNzRXhpdHMpIHtcclxuICAgIGF0dGFjaFByb2Nlc3NFeGl0TGlzdGVuZXJzKCk7XHJcbiAgfVxyXG5cclxuICAvLyBUaGUgbmV3ZXN0IHB1cHBldGVlciBhcmd1bWVudHMgZm9yIHRoZSBicm93c2VyIGNyZWF0aW9uXHJcbiAgcHVwcGV0ZWVyQXJncyA9IGNvbmZpZy5wdXBwZXRlZXJBcmdzO1xyXG5cclxuICAvLyBDcmVhdGUgYSBicm93c2VyIGluc3RhbmNlXHJcbiAgYXdhaXQgY3JlYXRlQnJvd3NlcihwdXBwZXRlZXJBcmdzKTtcclxuXHJcbiAgbG9nKFxyXG4gICAgMyxcclxuICAgIGBbcG9vbF0gSW5pdGlhbGl6aW5nIHBvb2wgd2l0aCB3b3JrZXJzOiBtaW4gJHtwb29sQ29uZmlnLm1pbldvcmtlcnN9LCBtYXggJHtwb29sQ29uZmlnLm1heFdvcmtlcnN9LmBcclxuICApO1xyXG5cclxuICBpZiAocG9vbCkge1xyXG4gICAgcmV0dXJuIGxvZyhcclxuICAgICAgNCxcclxuICAgICAgJ1twb29sXSBBbHJlYWR5IGluaXRpYWxpemVkLCBwbGVhc2Uga2lsbCBpdCBiZWZvcmUgY3JlYXRpbmcgYSBuZXcgb25lLidcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICBpZiAocGFyc2VJbnQocG9vbENvbmZpZy5taW5Xb3JrZXJzKSA+IHBhcnNlSW50KHBvb2xDb25maWcubWF4V29ya2VycykpIHtcclxuICAgIHBvb2xDb25maWcubWluV29ya2VycyA9IHBvb2xDb25maWcubWF4V29ya2VycztcclxuICB9XHJcblxyXG4gIHRyeSB7XHJcbiAgICAvLyBDcmVhdGUgYSBwb29sIGFsb25nIHdpdGggYSBtaW5pbWFsIG51bWJlciBvZiByZXNvdXJjZXNcclxuICAgIHBvb2wgPSBuZXcgUG9vbCh7XHJcbiAgICAgIC8vIEdldCB0aGUgY3JlYXRlL3ZhbGlkYXRlL2Rlc3Ryb3kvbG9nIGZ1bmN0aW9uc1xyXG4gICAgICAuLi5mYWN0b3J5LFxyXG4gICAgICBtaW46IHBhcnNlSW50KHBvb2xDb25maWcubWluV29ya2VycyksXHJcbiAgICAgIG1heDogcGFyc2VJbnQocG9vbENvbmZpZy5tYXhXb3JrZXJzKSxcclxuICAgICAgYWNxdWlyZVRpbWVvdXRNaWxsaXM6IHBvb2xDb25maWcuYWNxdWlyZVRpbWVvdXQsXHJcbiAgICAgIGNyZWF0ZVRpbWVvdXRNaWxsaXM6IHBvb2xDb25maWcuY3JlYXRlVGltZW91dCxcclxuICAgICAgZGVzdHJveVRpbWVvdXRNaWxsaXM6IHBvb2xDb25maWcuZGVzdHJveVRpbWVvdXQsXHJcbiAgICAgIGlkbGVUaW1lb3V0TWlsbGlzOiBwb29sQ29uZmlnLmlkbGVUaW1lb3V0LFxyXG4gICAgICBjcmVhdGVSZXRyeUludGVydmFsTWlsbGlzOiBwb29sQ29uZmlnLmNyZWF0ZVJldHJ5SW50ZXJ2YWwsXHJcbiAgICAgIHJlYXBJbnRlcnZhbE1pbGxpczogcG9vbENvbmZpZy5yZWFwZXJJbnRlcnZhbCxcclxuICAgICAgcHJvcGFnYXRlQ3JlYXRlRXJyb3I6IGZhbHNlXHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBTZXQgZXZlbnRzXHJcbiAgICBwb29sLm9uKCdyZWxlYXNlJywgYXN5bmMgKHJlc291cmNlKSA9PiB7XHJcbiAgICAgIC8vIENsZWFyIHBhZ2VcclxuICAgICAgYXdhaXQgY2xlYXJQYWdlKHJlc291cmNlLnBhZ2UsIGZhbHNlKTtcclxuICAgICAgbG9nKDQsIGBbcG9vbF0gUmVsZWFzaW5nIGEgd29ya2VyIHdpdGggSUQgJHtyZXNvdXJjZS5pZH0uYCk7XHJcbiAgICB9KTtcclxuXHJcbiAgICBwb29sLm9uKCdkZXN0cm95U3VjY2VzcycsIChldmVudElkLCByZXNvdXJjZSkgPT4ge1xyXG4gICAgICBsb2coNCwgYFtwb29sXSBEZXN0cm95ZWQgYSB3b3JrZXIgd2l0aCBJRCAke3Jlc291cmNlLmlkfS5gKTtcclxuICAgIH0pO1xyXG5cclxuICAgIGNvbnN0IGluaXRpYWxSZXNvdXJjZXMgPSBbXTtcclxuICAgIC8vIENyZWF0ZSBhbiBpbml0aWFsIG51bWJlciBvZiByZXNvdXJjZXNcclxuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgcG9vbENvbmZpZy5taW5Xb3JrZXJzOyBpKyspIHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBjb25zdCByZXNvdXJjZSA9IGF3YWl0IHBvb2wuYWNxdWlyZSgpLnByb21pc2U7XHJcbiAgICAgICAgaW5pdGlhbFJlc291cmNlcy5wdXNoKHJlc291cmNlKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsICdbcG9vbF0gQ291bGQgbm90IGNyZWF0ZSBhbiBpbml0aWFsIHJlc291cmNlLicpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmVsZWFzZSB0aGUgaW5pdGlhbCBudW1iZXIgb2YgcmVzb3VyY2VzIGJhY2sgdG8gdGhlIHBvb2xcclxuICAgIGluaXRpYWxSZXNvdXJjZXMuZm9yRWFjaCgocmVzb3VyY2UpID0+IHtcclxuICAgICAgcG9vbC5yZWxlYXNlKHJlc291cmNlKTtcclxuICAgIH0pO1xyXG5cclxuICAgIGxvZyhcclxuICAgICAgMyxcclxuICAgICAgYFtwb29sXSBUaGUgcG9vbCBpcyByZWFkeSR7aW5pdGlhbFJlc291cmNlcy5sZW5ndGggPyBgIHdpdGggJHtpbml0aWFsUmVzb3VyY2VzLmxlbmd0aH0gaW5pdGlhbCByZXNvdXJjZXMgd2FpdGluZy5gIDogJy4nfWBcclxuICAgICk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIC8vIENsb3NlIGJyb3dzZXIgaWYgZm9yIHNvbWUgcmVhc29uIGNhbm5vdCBlc3RhYmxpc2ggdGhlIHBvb2xcclxuICAgIGF3YWl0IGJyb3dzZXJDbG9zZSgpO1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW3Bvb2xdIENvdWxkIG5vdCBjcmVhdGUgdGhlIHBvb2wgb2Ygd29ya2Vycy4nXHJcbiAgICApLnNldEVycm9yKGVycm9yKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogQXR0YWNoZXMgZXhpdCBsaXN0ZW5lcnMgdG8gdGhlIHByb2Nlc3MsIGVuc3VyaW5nIHByb3BlciBjbGVhbnVwIG9mIHJlc291cmNlc1xyXG4gKiBhbmQgdGVybWluYXRpb24gb24gZXhpdCBzaWduYWxzLiBIYW5kbGVzICdleGl0JywgJ1NJR0lOVCcsICdTSUdURVJNJywgYW5kXHJcbiAqICd1bmNhdWdodEV4Y2VwdGlvbicgZXZlbnRzLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGF0dGFjaFByb2Nlc3NFeGl0TGlzdGVuZXJzKCkge1xyXG4gIGxvZygzLCAnW3Bvb2xdIEF0dGFjaGluZyBleGl0IGxpc3RlbmVycyB0byB0aGUgcHJvY2Vzcy4nKTtcclxuXHJcbiAgLy8gS2lsbCBhbGwgcG9vbCByZXNvdXJjZXMgb24gZXhpdFxyXG4gIHByb2Nlc3Mub24oJ2V4aXQnLCBhc3luYyAoY29kZSkgPT4ge1xyXG4gICAgbG9nKDQsIGBQcm9jZXNzIGV4aXRlZCB3aXRoIGNvZGUgJHtjb2RlfS5gKTtcclxuICAgIGF3YWl0IGtpbGxQb29sKCk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSBTSUdJTlRcclxuICBwcm9jZXNzLm9uKCdTSUdJTlQnLCAobmFtZSwgY29kZSkgPT4ge1xyXG4gICAgbG9nKDQsIGBUaGUgJHtuYW1lfSBldmVudCB3aXRoIGNvZGU6ICR7Y29kZX0uYCk7XHJcbiAgICBwcm9jZXNzLmV4aXQoMSk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSBTSUdURVJNXHJcbiAgcHJvY2Vzcy5vbignU0lHVEVSTScsIChuYW1lLCBjb2RlKSA9PiB7XHJcbiAgICBsb2coNCwgYFRoZSAke25hbWV9IGV2ZW50IHdpdGggY29kZTogJHtjb2RlfS5gKTtcclxuICAgIHByb2Nlc3MuZXhpdCgxKTtcclxuICB9KTtcclxuXHJcbiAgLy8gSGFuZGxlciBmb3IgdGhlIHVuY2F1Z2h0RXhjZXB0aW9uXHJcbiAgcHJvY2Vzcy5vbigndW5jYXVnaHRFeGNlcHRpb24nLCBhc3luYyAoZXJyb3IsIG5hbWUpID0+IHtcclxuICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFRoZSAke25hbWV9IGVycm9yLmApO1xyXG4gICAgYXdhaXQga2lsbFBvb2woKTtcclxuICAgIHByb2Nlc3MuZXhpdCgxKTtcclxuICB9KTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEtpbGxzIGFsbCB3b3JrZXJzIGluIHRoZSBwb29sLCBkZXN0cm95cyB0aGUgcG9vbCwgYW5kIGNsb3NlcyB0aGUgYnJvd3NlclxyXG4gKiBpbnN0YW5jZS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIGFmdGVyIHRoZSB3b3JrZXJzIGFyZVxyXG4gKiBraWxsZWQsIHRoZSBwb29sIGlzIGRlc3Ryb3llZCwgYW5kIHRoZSBicm93c2VyIGlzIGNsb3NlZC5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBraWxsUG9vbCgpIHtcclxuICBsb2coMywgJ1twb29sXSBLaWxsaW5nIGFsbCBwb29sIHdvcmtlcnMgYW5kIGJyb3dzZXIsIGlmIGFueSBleGlzdC4nKTtcclxuXHJcbiAgLy8gUmV0dXJuIHRydWUgd2hlbiB0aGUgcG9vbCBpcyBhbHJlYWR5IGRlc3Ryb3llZFxyXG4gIGlmIChwb29sPy5kZXN0cm95ZWQpIHtcclxuICAgIC8vIENsb3NlIHRoZSBicm93c2VyIGluc3RhbmNlIGlmIHN0aWxsIGNvbm5lY3RlZFxyXG4gICAgcmV0dXJuIGJyb3dzZXJDbG9zZSgpO1xyXG4gIH1cclxuXHJcbiAgLy8gSWYgc3RpbGwgYWxpdmUsIGRlc3Ryb3kgdGhlIHBvb2wgb2YgcGFnZXMgYmVmb3JlIGNsb3NpbmcgYSBicm93c2VyXHJcbiAgaWYgKHBvb2wpIHtcclxuICAgIGF3YWl0IHBvb2wuZGVzdHJveSgpO1xyXG4gICAgbG9nKDQsICdbYnJvd3Nlcl0gRGVzdHJveWVkIHRoZSBwb29sIG9mIHJlc291cmNlcy4nKTtcclxuICB9XHJcblxyXG4gIC8vIENsb3NlIHRoZSBicm93c2VyIGluc3RhbmNlXHJcbiAgcmV0dXJuIGJyb3dzZXJDbG9zZSgpO1xyXG59XHJcblxyXG4vKipcclxuICogUHJvY2Vzc2VzIHRoZSBleHBvcnQgd29yayB1c2luZyBhIHdvcmtlciBmcm9tIHRoZSBwb29sLiBBY3F1aXJlcyBhIHdvcmtlclxyXG4gKiBoYW5kbGUgZnJvbSB0aGUgcG9vbCwgcGVyZm9ybXMgdGhlIGV4cG9ydCB1c2luZyBwdXBwZXRlZXIsIGFuZCByZWxlYXNlc1xyXG4gKiB0aGUgd29ya2VyIGhhbmRsZSBiYWNrIHRvIHRoZSBwb29sLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY2hhcnQgLSBUaGUgY2hhcnQgZGF0YSBvciBjb25maWd1cmF0aW9uIHRvIGJlIGV4cG9ydGVkLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIEV4cG9ydCBvcHRpb25zIGFuZCBjb25maWd1cmF0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aXRoIHRoZSBleHBvcnQgcmVzdWx0YW5kXHJcbiAqIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBJZiBhbiBlcnJvciBvY2N1cnMgZHVyaW5nIHRoZSBleHBvcnQgcHJvY2Vzcy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBwb3N0V29yayA9IGFzeW5jIChjaGFydCwgb3B0aW9ucykgPT4ge1xyXG4gIGxldCB3b3JrZXJIYW5kbGU7XHJcblxyXG4gIHRyeSB7XHJcbiAgICBsb2coNCwgJ1twb29sXSBXb3JrIHJlY2VpdmVkLCBzdGFydGluZyB0byBwcm9jZXNzLicpO1xyXG5cclxuICAgICsrZXhwb3J0QXR0ZW1wdHM7XHJcbiAgICBpZiAocG9vbENvbmZpZy5iZW5jaG1hcmtpbmcpIHtcclxuICAgICAgZ2V0UG9vbEluZm8oKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoIXBvb2wpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdXb3JrIHJlY2VpdmVkLCBidXQgcG9vbCBoYXMgbm90IGJlZW4gc3RhcnRlZC4nKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBBY3F1aXJlIHRoZSB3b3JrZXIgYWxvbmcgd2l0aCB0aGUgaWQgb2YgcmVzb3VyY2UgYW5kIHdvcmsgY291bnRcclxuICAgIHRyeSB7XHJcbiAgICAgIGxvZyg0LCAnW3Bvb2xdIEFjcXVpcmluZyBhIHdvcmtlciBoYW5kbGUuJyk7XHJcbiAgICAgIGNvbnN0IGFjcXVpcmVDb3VudGVyID0gbWVhc3VyZVRpbWUoKTtcclxuICAgICAgd29ya2VySGFuZGxlID0gYXdhaXQgcG9vbC5hY3F1aXJlKCkucHJvbWlzZTtcclxuXHJcbiAgICAgIC8vIENoZWNrIHRoZSBwYWdlIGFjcXVpcmUgdGltZVxyXG4gICAgICBpZiAob3B0aW9ucy5zZXJ2ZXIuYmVuY2htYXJraW5nKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgNSxcclxuICAgICAgICAgIG9wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkXHJcbiAgICAgICAgICAgID8gYFtiZW5jaG1hcmtdIFJlcXVlc3Qgd2l0aCBJRCAke29wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkfSAtYFxyXG4gICAgICAgICAgICA6ICdbYmVuY2htYXJrXScsXHJcbiAgICAgICAgICBgQWNxdWlyZWQgYSB3b3JrZXIgaGFuZGxlOiAke2FjcXVpcmVDb3VudGVyKCl9bXMuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnRXJyb3IgZW5jb3VudGVyZWQgd2hlbiBhY3F1aXJpbmcgYW4gYXZhaWxhYmxlIGVudHJ5LidcclxuICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICB9XHJcbiAgICBsb2coNCwgJ1twb29sXSBBY3F1aXJlZCBhIHdvcmtlciBoYW5kbGUuJyk7XHJcblxyXG4gICAgaWYgKCF3b3JrZXJIYW5kbGUucGFnZSkge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ1Jlc29sdmVkIHdvcmtlciBwYWdlIGlzIGludmFsaWQ6IHRoZSBwb29sIHNldHVwIGlzIHdvbmt5LidcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBTYXZlIHRoZSBzdGFydCB0aW1lXHJcbiAgICBsZXQgd29ya1N0YXJ0ID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XHJcblxyXG4gICAgbG9nKDQsIGBbcG9vbF0gU3RhcnRpbmcgd29yayBvbiBwb29sIGVudHJ5IHdpdGggSUQgJHt3b3JrZXJIYW5kbGUuaWR9LmApO1xyXG5cclxuICAgIC8vIFBlcmZvcm0gYW4gZXhwb3J0IG9uIGEgcHVwcGV0ZWVyIGxldmVsXHJcbiAgICBjb25zdCBleHBvcnRDb3VudGVyID0gbWVhc3VyZVRpbWUoKTtcclxuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHB1cHBldGVlckV4cG9ydCh3b3JrZXJIYW5kbGUucGFnZSwgY2hhcnQsIG9wdGlvbnMpO1xyXG5cclxuICAgIC8vIENoZWNrIGlmIGl0J3MgYW4gZXJyb3JcclxuICAgIGlmIChyZXN1bHQgaW5zdGFuY2VvZiBFcnJvcikge1xyXG4gICAgICAvLyBUT0RPOiBJZiB0aGUgZXhwb3J0IGZhaWxlZCBiZWNhdXNlIHB1cHBldGVlciB0aW1lZCBvdXQsIHdlIG5lZWQgdG8gZm9yY2Uga2lsbCB0aGUgd29ya2VyIHNvIHdlIGdldCBhIG5ldyBwYWdlLiBUaGF0IG5lZWRzIHRvIGJlIGhhbmRsZWQgYmV0dGVyIHRoYW4gdGhpcyBoYWNrLlxyXG4gICAgICBpZiAocmVzdWx0Lm1lc3NhZ2UgPT09ICdSYXN0ZXJpemF0aW9uIHRpbWVvdXQnKSB7XHJcbiAgICAgICAgd29ya2VySGFuZGxlLnBhZ2UuY2xvc2UoKTtcclxuICAgICAgICB3b3JrZXJIYW5kbGUucGFnZSA9IGF3YWl0IGJyb3dzZXJOZXdQYWdlKCk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignRXJyb3IgZW5jb3VudGVyZWQgZHVyaW5nIGV4cG9ydC4nKS5zZXRFcnJvcihcclxuICAgICAgICByZXN1bHRcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBDaGVjayB0aGUgUHVwcGV0ZWVyIGV4cG9ydCB0aW1lXHJcbiAgICBpZiAob3B0aW9ucy5zZXJ2ZXIuYmVuY2htYXJraW5nKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICA1LFxyXG4gICAgICAgIG9wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkXHJcbiAgICAgICAgICA/IGBbYmVuY2htYXJrXSBSZXF1ZXN0IHdpdGggSUQgJHtvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZH0gLWBcclxuICAgICAgICAgIDogJ1tiZW5jaG1hcmtdJyxcclxuICAgICAgICBgRXhwb3J0ZWQgYSBjaGFydCBzdWNlc3NmdWxseTogJHtleHBvcnRDb3VudGVyKCl9bXMuYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFJlbGVhc2UgdGhlIHJlc291cmNlIGJhY2sgdG8gdGhlIHBvb2xcclxuICAgIHBvb2wucmVsZWFzZSh3b3JrZXJIYW5kbGUpO1xyXG5cclxuICAgIC8vIFVzZWQgZm9yIHN0YXRpc3RpY3MgaW4gYXZlcmFnZVRpbWUgYW5kIHByb2Nlc3NlZFdvcmtDb3VudCwgd2hpY2hcclxuICAgIC8vIGluIHR1cm4gaXMgdXNlZCBieSB0aGUgL2hlYWx0aCByb3V0ZS5cclxuICAgIGNvbnN0IHdvcmtFbmQgPSBuZXcgRGF0ZSgpLmdldFRpbWUoKTtcclxuICAgIGNvbnN0IGV4cG9ydFRpbWUgPSB3b3JrRW5kIC0gd29ya1N0YXJ0O1xyXG4gICAgdGltZVNwZW50ICs9IGV4cG9ydFRpbWU7XHJcbiAgICBzcGVudEF2ZXJhZ2UgPSB0aW1lU3BlbnQgLyArK3BlcmZvcm1lZEV4cG9ydHM7XHJcblxyXG4gICAgbG9nKDQsIGBbcG9vbF0gV29yayBjb21wbGV0ZWQgaW4gJHtleHBvcnRUaW1lfSBtcy5gKTtcclxuXHJcbiAgICAvLyBPdGhlcndpc2UgcmV0dXJuIHRoZSByZXN1bHRcclxuICAgIHJldHVybiB7XHJcbiAgICAgIHJlc3VsdCxcclxuICAgICAgb3B0aW9uc1xyXG4gICAgfTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgKytkcm9wcGVkRXhwb3J0cztcclxuXHJcbiAgICBpZiAod29ya2VySGFuZGxlKSB7XHJcbiAgICAgIHBvb2wucmVsZWFzZSh3b3JrZXJIYW5kbGUpO1xyXG4gICAgfVxyXG5cclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihgW3Bvb2xdIEluIHBvb2wucG9zdFdvcms6ICR7ZXJyb3IubWVzc2FnZX1gKS5zZXRFcnJvcihcclxuICAgICAgZXJyb3JcclxuICAgICk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyB0aGUgY3VycmVudCBwb29sIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fG51bGx9IFRoZSBjdXJyZW50IHBvb2wgaW5zdGFuY2UgaWYgaW5pdGlhbGl6ZWQsIG9yIG51bGxcclxuICogaWYgdGhlIHBvb2wgaGFzIG5vdCBiZWVuIGNyZWF0ZWQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0UG9vbCgpIHtcclxuICByZXR1cm4gcG9vbDtcclxufVxyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyBwb29sIGluZm9ybWF0aW9uIGluIEpTT04gZm9ybWF0LCBpbmNsdWRpbmcgbWluaW11bSBhbmQgbWF4aW11bVxyXG4gKiB3b3JrZXJzLCBhdmFpbGFibGUgd29ya2Vycywgd29ya2VycyBpbiB1c2UsIGFuZCBwZW5kaW5nIGFjcXVpcmUgcmVxdWVzdHMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFBvb2wgaW5mb3JtYXRpb24gaW4gSlNPTiBmb3JtYXQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0UG9vbEluZm9KU09OID0gKCkgPT4gKHtcclxuICBtaW46IHBvb2wubWluLFxyXG4gIG1heDogcG9vbC5tYXgsXHJcbiAgYXZhaWxhYmxlOiBwb29sLm51bUZyZWUoKSxcclxuICBpblVzZTogcG9vbC5udW1Vc2VkKCksXHJcbiAgcGVuZGluZ0FjcXVpcmU6IHBvb2wubnVtUGVuZGluZ0FjcXVpcmVzKClcclxufSk7XHJcblxyXG4vKipcclxuICogTG9ncyBpbmZvcm1hdGlvbiBhYm91dCB0aGUgY3VycmVudCBzdGF0ZSBvZiB0aGUgcG9vbCwgaW5jbHVkaW5nIHRoZSBtaW5pbXVtXHJcbiAqIGFuZCBtYXhpbXVtIHdvcmtlcnMsIGF2YWlsYWJsZSB3b3JrZXJzLCB3b3JrZXJzIGluIHVzZSwgYW5kIHBlbmRpbmcgYWNxdWlyZVxyXG4gKiByZXF1ZXN0cy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRQb29sSW5mbygpIHtcclxuICBjb25zdCB7IG1pbiwgbWF4IH0gPSBwb29sO1xyXG5cclxuICBsb2coNSwgYFtwb29sXSBUaGUgbWluaW11bSBudW1iZXIgb2YgcmVzb3VyY2VzIGFsbG93ZWQgYnkgcG9vbDogJHttaW59LmApO1xyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBtYXhpbXVtIG51bWJlciBvZiByZXNvdXJjZXMgYWxsb3dlZCBieSBwb29sOiAke21heH0uYCk7XHJcbiAgbG9nKFxyXG4gICAgNSxcclxuICAgIGBbcG9vbF0gVGhlIG51bWJlciBvZiByZXNvdXJjZXMgdGhhdCBhcmUgY3VycmVudGx5IGF2YWlsYWJsZTogJHtwb29sLm51bUZyZWUoKX0uYFxyXG4gICk7XHJcbiAgbG9nKFxyXG4gICAgNSxcclxuICAgIGBbcG9vbF0gVGhlIG51bWJlciBvZiByZXNvdXJjZXMgdGhhdCBhcmUgY3VycmVudGx5IGFjcXVpcmVkOiAke3Bvb2wubnVtVXNlZCgpfS5gXHJcbiAgKTtcclxuICBsb2coXHJcbiAgICA1LFxyXG4gICAgYFtwb29sXSBUaGUgbnVtYmVyIG9mIGNhbGxlcnMgd2FpdGluZyB0byBhY3F1aXJlIGEgcmVzb3VyY2U6ICR7cG9vbC5udW1QZW5kaW5nQWNxdWlyZXMoKX0uYFxyXG4gICk7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBpbml0UG9vbCxcclxuICBraWxsUG9vbCxcclxuICBwb3N0V29yayxcclxuICBnZXRQb29sLFxyXG4gIGdldFBvb2xJbmZvLFxyXG4gIGdldFBvb2xJbmZvSlNPTixcclxuICB3b3JrQXR0ZW1wdHM6ICgpID0+IGV4cG9ydEF0dGVtcHRzLFxyXG4gIGRyb3BwZWRXb3JrOiAoKSA9PiBkcm9wcGVkRXhwb3J0cyxcclxuICBhdmVyYWdlVGltZTogKCkgPT4gc3BlbnRBdmVyYWdlLFxyXG4gIHByb2Nlc3NlZFdvcmtDb3VudDogKCkgPT4gcGVyZm9ybWVkRXhwb3J0c1xyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYywgd3JpdGVGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuXHJcbmltcG9ydCB7IGdldE9wdGlvbnMsIGluaXRFeHBvcnRTZXR0aW5ncyB9IGZyb20gJy4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IGtpbGxQb29sLCBwb3N0V29yayB9IGZyb20gJy4vcG9vbC5qcyc7XHJcbmltcG9ydCB7XHJcbiAgZml4VHlwZSxcclxuICBoYW5kbGVSZXNvdXJjZXMsXHJcbiAgaXNDb3JyZWN0SlNPTixcclxuICBvcHRpb25zU3RyaW5naWZ5LFxyXG4gIHJvdW5kTnVtYmVyLFxyXG4gIHRvQm9vbGVhbixcclxuICB3cmFwQXJvdW5kXHJcbn0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxubGV0IGFsbG93Q29kZUV4ZWN1dGlvbiA9IGZhbHNlO1xyXG5cclxuLyoqXHJcbiAqIFN0YXJ0cyBhbiBleHBvcnQgcHJvY2Vzcy4gVGhlIGBzZXR0aW5nc2AgY29udGFpbnMgZmluYWwgb3B0aW9ucyBnYXRoZXJlZFxyXG4gKiBmcm9tIGFsbCBwb3NzaWJsZSBzb3VyY2VzIChjb25maWcsIGVudiwgY2xpLCBqc29uKS4gVGhlIGBlbmRDYWxsYmFja2AgaXNcclxuICogY2FsbGVkIHdoZW4gdGhlIGV4cG9ydCBpcyBjb21wbGV0ZWQsIHdpdGggYW4gZXJyb3Igb2JqZWN0IGFzIHRoZSBmaXJzdFxyXG4gKiBhcmd1bWVudCBhbmQgdGhlIHNlY29uZCBjb250YWluaW5nIHRoZSBiYXNlNjQgcmVzcHJlc2VudGF0aW9uIG9mIGEgY2hhcnQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBzZXR0aW5ncyAtIFRoZSBzZXR0aW5ncyBvYmplY3QgY29udGFpbmluZyBleHBvcnRcclxuICogY29uZmlndXJhdGlvbi5cclxuICogQHBhcmFtIHtmdW5jdGlvbn0gZW5kQ2FsbGJhY2sgLSBUaGUgY2FsbGJhY2sgZnVuY3Rpb24gdG8gYmUgaW52b2tlZCB1cG9uXHJcbiAqIGZpbmFsaXppbmcgd29yayBvciB1cG9uIGVycm9yIG9jY3VyYW5jZSBvZiB0aGUgZXhwb3J0aW5nIHByb2Nlc3MuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHt2b2lkfSBUaGlzIGZ1bmN0aW9uIGRvZXMgbm90IHJldHVybiBhIHZhbHVlIGRpcmVjdGx5OyBpbnN0ZWFkLFxyXG4gKiBpdCBjb21tdW5pY2F0ZXMgcmVzdWx0cyB2aWEgdGhlIGVuZENhbGxiYWNrLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHN0YXJ0RXhwb3J0ID0gYXN5bmMgKHNldHRpbmdzLCBlbmRDYWxsYmFjaykgPT4ge1xyXG4gIC8vIFN0YXJ0aW5nIGV4cG9ydGluZyBwcm9jZXNzIG1lc3NhZ2VcclxuICBsb2coNCwgJ1tjaGFydF0gU3RhcnRpbmcgdGhlIGV4cG9ydGluZyBwcm9jZXNzLicpO1xyXG5cclxuICAvLyBJbml0aWFsaXplIG9wdGlvbnNcclxuICBjb25zdCBvcHRpb25zID0gaW5pdEV4cG9ydFNldHRpbmdzKHNldHRpbmdzLCBnZXRPcHRpb25zKCkpO1xyXG5cclxuICAvLyBHZXQgdGhlIGV4cG9ydCBvcHRpb25zXHJcbiAgY29uc3QgZXhwb3J0T3B0aW9ucyA9IG9wdGlvbnMuZXhwb3J0O1xyXG5cclxuICAvLyBJZiBTVkcgaXMgYW4gaW5wdXQgKGFyZ3VtZW50IGNhbiBiZSBzZW50IG9ubHkgYnkgdGhlIHJlcXVlc3QpXHJcbiAgaWYgKG9wdGlvbnMucGF5bG9hZD8uc3ZnICYmIG9wdGlvbnMucGF5bG9hZC5zdmcgIT09ICcnKSB7XHJcbiAgICB0cnkge1xyXG4gICAgICBsb2coNCwgJ1tjaGFydF0gQXR0ZW1wdGluZyB0byBleHBvcnQgZnJvbSBhIFNWRyBpbnB1dC4nKTtcclxuICAgICAgcmV0dXJuIGV4cG9ydEFzU3RyaW5nKG9wdGlvbnMucGF5bG9hZC5zdmcudHJpbSgpLCBvcHRpb25zLCBlbmRDYWxsYmFjayk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICAgICAgbmV3IEV4cG9ydEVycm9yKCdbY2hhcnRdIEVycm9yIGxvYWRpbmcgU1ZHIGlucHV0LicpLnNldEVycm9yKGVycm9yKVxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gRXhwb3J0IHVzaW5nIG9wdGlvbnMgZnJvbSB0aGUgZmlsZVxyXG4gIGlmIChleHBvcnRPcHRpb25zLmluZmlsZSAmJiBleHBvcnRPcHRpb25zLmluZmlsZS5sZW5ndGgpIHtcclxuICAgIC8vIFRyeSB0byByZWFkIHRoZSBmaWxlIHRvIGdldCB0aGUgc3RyaW5nIHJlcHJlc2VudGF0aW9uXHJcbiAgICB0cnkge1xyXG4gICAgICBsb2coNCwgJ1tjaGFydF0gQXR0ZW1wdGluZyB0byBleHBvcnQgZnJvbSBhbiBpbnB1dCBmaWxlLicpO1xyXG4gICAgICBvcHRpb25zLmV4cG9ydC5pbnN0ciA9IHJlYWRGaWxlU3luYyhleHBvcnRPcHRpb25zLmluZmlsZSwgJ3V0ZjgnKTtcclxuICAgICAgcmV0dXJuIGV4cG9ydEFzU3RyaW5nKG9wdGlvbnMuZXhwb3J0Lmluc3RyLnRyaW0oKSwgb3B0aW9ucywgZW5kQ2FsbGJhY2spO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKFxyXG4gICAgICAgIG5ldyBFeHBvcnRFcnJvcignW2NoYXJ0XSBFcnJvciBsb2FkaW5nIGlucHV0IGZpbGUuJykuc2V0RXJyb3IoZXJyb3IpXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBFeHBvcnQgd2l0aCBvcHRpb25zIGZyb20gdGhlIHJhdyByZXByZXNlbnRhdGlvblxyXG4gIGlmIChcclxuICAgIChleHBvcnRPcHRpb25zLmluc3RyICYmIGV4cG9ydE9wdGlvbnMuaW5zdHIgIT09ICcnKSB8fFxyXG4gICAgKGV4cG9ydE9wdGlvbnMub3B0aW9ucyAmJiBleHBvcnRPcHRpb25zLm9wdGlvbnMgIT09ICcnKVxyXG4gICkge1xyXG4gICAgdHJ5IHtcclxuICAgICAgbG9nKDQsICdbY2hhcnRdIEF0dGVtcHRpbmcgdG8gZXhwb3J0IGZyb20gYSByYXcgaW5wdXQuJyk7XHJcblxyXG4gICAgICAvLyBQZXJmb3JtIGEgZGlyZWN0IGluamVjdCB3aGVuIGZvcmNlZFxyXG4gICAgICBpZiAodG9Cb29sZWFuKG9wdGlvbnMuY3VzdG9tTG9naWM/LmFsbG93Q29kZUV4ZWN1dGlvbikpIHtcclxuICAgICAgICByZXR1cm4gZG9TdHJhaWdodEluamVjdChvcHRpb25zLCBlbmRDYWxsYmFjayk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIEVpdGhlciB0cnkgdG8gcGFyc2UgdG8gSlNPTiBmaXJzdCBvciBkbyB0aGUgZGlyZWN0IGV4cG9ydFxyXG4gICAgICByZXR1cm4gdHlwZW9mIGV4cG9ydE9wdGlvbnMuaW5zdHIgPT09ICdzdHJpbmcnXHJcbiAgICAgICAgPyBleHBvcnRBc1N0cmluZyhleHBvcnRPcHRpb25zLmluc3RyLnRyaW0oKSwgb3B0aW9ucywgZW5kQ2FsbGJhY2spXHJcbiAgICAgICAgOiBkb0V4cG9ydChcclxuICAgICAgICAgICAgb3B0aW9ucyxcclxuICAgICAgICAgICAgZXhwb3J0T3B0aW9ucy5pbnN0ciB8fCBleHBvcnRPcHRpb25zLm9wdGlvbnMsXHJcbiAgICAgICAgICAgIGVuZENhbGxiYWNrXHJcbiAgICAgICAgICApO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKFxyXG4gICAgICAgIG5ldyBFeHBvcnRFcnJvcignW2NoYXJ0XSBFcnJvciBsb2FkaW5nIHJhdyBpbnB1dC4nKS5zZXRFcnJvcihlcnJvcilcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIE5vIGlucHV0IHNwZWNpZmllZCwgcGFzcyBhbiBlcnJvciBtZXNzYWdlIHRvIHRoZSBjYWxsYmFja1xyXG4gIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgIG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgYFtjaGFydF0gTm8gdmFsaWQgaW5wdXQgc3BlY2lmaWVkLiBDaGVjayBpZiBhdCBsZWFzdCBvbmUgb2YgdGhlIGZvbGxvd2luZyBwYXJhbWV0ZXJzIGlzIGNvcnJlY3RseSBzZXQ6ICdpbmZpbGUnLCAnaW5zdHInLCAnb3B0aW9ucycsIG9yICdzdmcnLmBcclxuICAgIClcclxuICApO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFN0YXJ0cyBhIGJhdGNoIGV4cG9ydCBwcm9jZXNzIGZvciBtdWx0aXBsZSBjaGFydHMgYmFzZWQgb24gdGhlIGluZm9ybWF0aW9uXHJcbiAqIGluIHRoZSBiYXRjaCBvcHRpb24uIFRoZSBiYXRjaCBpcyBhIHN0cmluZyBpbiB0aGUgZm9sbG93aW5nIGZvcm1hdDpcclxuICogXCJpbmZpbGUxLmpzb249b3V0ZmlsZTEucG5nO2luZmlsZTIuanNvbj1vdXRmaWxlMi5wbmc7Li4uXCJcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgb3B0aW9ucyBvYmplY3QgY29udGFpbmluZyBjb25maWd1cmF0aW9uIGZvclxyXG4gKiBhIGJhdGNoIGV4cG9ydC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgdGhlIGJhdGNoIGV4cG9ydFxyXG4gKiBwcm9jZXNzIGlzIGNvbXBsZXRlZC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiBhbiBlcnJvciBvY2N1cnMgZHVyaW5nXHJcbiAqIGFueSBvZiB0aGUgYmF0Y2ggZXhwb3J0IHByb2Nlc3MuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgYmF0Y2hFeHBvcnQgPSBhc3luYyAob3B0aW9ucykgPT4ge1xyXG4gIGNvbnN0IGJhdGNoRnVuY3Rpb25zID0gW107XHJcblxyXG4gIC8vIFNwbGl0IGFuZCBwYWlyIHRoZSAtLWJhdGNoIGFyZ3VtZW50c1xyXG4gIGZvciAobGV0IHBhaXIgb2Ygb3B0aW9ucy5leHBvcnQuYmF0Y2guc3BsaXQoJzsnKSkge1xyXG4gICAgcGFpciA9IHBhaXIuc3BsaXQoJz0nKTtcclxuICAgIGlmIChwYWlyLmxlbmd0aCA9PT0gMikge1xyXG4gICAgICBiYXRjaEZ1bmN0aW9ucy5wdXNoKFxyXG4gICAgICAgIHN0YXJ0RXhwb3J0KFxyXG4gICAgICAgICAge1xyXG4gICAgICAgICAgICAuLi5vcHRpb25zLFxyXG4gICAgICAgICAgICBleHBvcnQ6IHtcclxuICAgICAgICAgICAgICAuLi5vcHRpb25zLmV4cG9ydCxcclxuICAgICAgICAgICAgICBpbmZpbGU6IHBhaXJbMF0sXHJcbiAgICAgICAgICAgICAgb3V0ZmlsZTogcGFpclsxXVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9LFxyXG4gICAgICAgICAgKGVycm9yLCBpbmZvKSA9PiB7XHJcbiAgICAgICAgICAgIC8vIFRocm93IGFuIGVycm9yXHJcbiAgICAgICAgICAgIGlmIChlcnJvcikge1xyXG4gICAgICAgICAgICAgIHRocm93IGVycm9yO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAvLyBTYXZlIHRoZSBiYXNlNjQgZnJvbSBhIGJ1ZmZlciB0byBhIGNvcnJlY3QgaW1hZ2UgZmlsZVxyXG4gICAgICAgICAgICB3cml0ZUZpbGVTeW5jKFxyXG4gICAgICAgICAgICAgIGluZm8ub3B0aW9ucy5leHBvcnQub3V0ZmlsZSxcclxuICAgICAgICAgICAgICBCdWZmZXIuZnJvbShpbmZvLnJlc3VsdCwgJ2Jhc2U2NCcpXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgKVxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgdHJ5IHtcclxuICAgIC8vIEF3YWl0IGFsbCBleHBvcnRzIGFyZSBkb25lXHJcbiAgICBhd2FpdCBQcm9taXNlLmFsbChiYXRjaEZ1bmN0aW9ucyk7XHJcblxyXG4gICAgLy8gS2lsbCBwb29sIGFuZCBjbG9zZSBicm93c2VyIGFmdGVyIGZpbmlzaGluZyBiYXRjaCBleHBvcnRcclxuICAgIGF3YWl0IGtpbGxQb29sKCk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1tjaGFydF0gRXJyb3IgZW5jb3VudGVyZWQgZHVyaW5nIGJhdGNoIGV4cG9ydC4nXHJcbiAgICApLnNldEVycm9yKGVycm9yKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogU3RhcnRzIGEgc2luZ2xlIGV4cG9ydCBwcm9jZXNzIGJhc2VkIG9uIHRoZSBzcGVjaWZpZWQgb3B0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgb3B0aW9ucyBvYmplY3QgY29udGFpbmluZyBjb25maWd1cmF0aW9uIGZvclxyXG4gKiBhIHNpbmdsZSBleHBvcnQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBzaW5nbGUgZXhwb3J0XHJcbiAqIHByb2Nlc3MgaXMgY29tcGxldGVkLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIGFuIGVycm9yIG9jY3VycyBkdXJpbmdcclxuICogdGhlIHNpbmdsZSBleHBvcnQgcHJvY2Vzcy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBzaW5nbGVFeHBvcnQgPSBhc3luYyAob3B0aW9ucykgPT4ge1xyXG4gIC8vIFVzZSBpbnN0ciBvciBpdHMgYWxpYXMsIG9wdGlvbnNcclxuICBvcHRpb25zLmV4cG9ydC5pbnN0ciA9IG9wdGlvbnMuZXhwb3J0Lmluc3RyIHx8IG9wdGlvbnMuZXhwb3J0Lm9wdGlvbnM7XHJcblxyXG4gIC8vIFBlcmZvcm0gYW4gZXhwb3J0XHJcbiAgYXdhaXQgc3RhcnRFeHBvcnQob3B0aW9ucywgYXN5bmMgKGVycm9yLCBpbmZvKSA9PiB7XHJcbiAgICAvLyBFeGl0IHByb2Nlc3Mgd2hlbiBlcnJvclxyXG4gICAgaWYgKGVycm9yKSB7XHJcbiAgICAgIHRocm93IGVycm9yO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IHsgb3V0ZmlsZSwgdHlwZSB9ID0gaW5mby5vcHRpb25zLmV4cG9ydDtcclxuXHJcbiAgICAvLyBTYXZlIHRoZSBiYXNlNjQgZnJvbSBhIGJ1ZmZlciB0byBhIGNvcnJlY3QgaW1hZ2UgZmlsZVxyXG4gICAgd3JpdGVGaWxlU3luYyhcclxuICAgICAgb3V0ZmlsZSB8fCBgY2hhcnQuJHt0eXBlfWAsXHJcbiAgICAgIHR5cGUgIT09ICdzdmcnID8gQnVmZmVyLmZyb20oaW5mby5yZXN1bHQsICdiYXNlNjQnKSA6IGluZm8ucmVzdWx0XHJcbiAgICApO1xyXG5cclxuICAgIC8vIEtpbGwgdGhlIHBvb2xcclxuICAgIGF3YWl0IGtpbGxQb29sKCk7XHJcbiAgfSk7XHJcbn07XHJcblxyXG4vKipcclxuICogRGV0ZXJtaW5lcyB0aGUgc2l6ZSBhbmQgc2NhbGUgZm9yIGNoYXJ0IGV4cG9ydCBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgb3B0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgb3B0aW9ucyBvYmplY3QgY29udGFpbmluZyBjb25maWd1cmF0aW9uIGZvclxyXG4gKiBjaGFydCBleHBvcnQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IEFuIG9iamVjdCBjb250YWluaW5nIHRoZSBjYWxjdWxhdGVkIGhlaWdodCwgd2lkdGgsXHJcbiAqIGFuZCBzY2FsZSBmb3IgdGhlIGNoYXJ0IGV4cG9ydC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBmaW5kQ2hhcnRTaXplID0gKG9wdGlvbnMpID0+IHtcclxuICBjb25zdCB7IGNoYXJ0LCBleHBvcnRpbmcgfSA9XHJcbiAgICBvcHRpb25zLmV4cG9ydD8ub3B0aW9ucyB8fCBpc0NvcnJlY3RKU09OKG9wdGlvbnMuZXhwb3J0Py5pbnN0cik7XHJcblxyXG4gIC8vIFNlZSBpZiBnbG9iYWxPcHRpb25zIGhvbGRzIGNoYXJ0IG9yIGV4cG9ydGluZyBzaXplXHJcbiAgY29uc3QgZ2xvYmFsT3B0aW9ucyA9IGlzQ29ycmVjdEpTT04ob3B0aW9ucy5leHBvcnQ/Lmdsb2JhbE9wdGlvbnMpO1xyXG5cclxuICAvLyBTZWN1cmUgc2NhbGUgdmFsdWVcclxuICBsZXQgc2NhbGUgPVxyXG4gICAgb3B0aW9ucy5leHBvcnQ/LnNjYWxlIHx8XHJcbiAgICBleHBvcnRpbmc/LnNjYWxlIHx8XHJcbiAgICBnbG9iYWxPcHRpb25zPy5leHBvcnRpbmc/LnNjYWxlIHx8XHJcbiAgICBvcHRpb25zLmV4cG9ydD8uZGVmYXVsdFNjYWxlIHx8XHJcbiAgICAxO1xyXG5cclxuICAvLyB0aGUgc2NhbGUgY2Fubm90IGJlIGxvd2VyIHRoYW4gMC4xIGFuZCBjYW5ub3QgYmUgaGlnaGVyIHRoYW4gNS4wXHJcbiAgc2NhbGUgPSBNYXRoLm1heCgwLjEsIE1hdGgubWluKHNjYWxlLCA1LjApKTtcclxuXHJcbiAgLy8gd2Ugd2FudCB0byByb3VuZCB0aGUgbnVtYmVycyBsaWtlIDAuMjMyMzQgLT4gMC4yM1xyXG4gIHNjYWxlID0gcm91bmROdW1iZXIoc2NhbGUsIDIpO1xyXG5cclxuICAvLyBGaW5kIGNoYXJ0IHNpemUgYW5kIHNjYWxlXHJcbiAgY29uc3Qgc2l6ZSA9IHtcclxuICAgIGhlaWdodDpcclxuICAgICAgb3B0aW9ucy5leHBvcnQ/LmhlaWdodCB8fFxyXG4gICAgICBleHBvcnRpbmc/LnNvdXJjZUhlaWdodCB8fFxyXG4gICAgICBjaGFydD8uaGVpZ2h0IHx8XHJcbiAgICAgIGdsb2JhbE9wdGlvbnM/LmV4cG9ydGluZz8uc291cmNlSGVpZ2h0IHx8XHJcbiAgICAgIGdsb2JhbE9wdGlvbnM/LmNoYXJ0Py5oZWlnaHQgfHxcclxuICAgICAgb3B0aW9ucy5leHBvcnQ/LmRlZmF1bHRIZWlnaHQgfHxcclxuICAgICAgNDAwLFxyXG4gICAgd2lkdGg6XHJcbiAgICAgIG9wdGlvbnMuZXhwb3J0Py53aWR0aCB8fFxyXG4gICAgICBleHBvcnRpbmc/LnNvdXJjZVdpZHRoIHx8XHJcbiAgICAgIGNoYXJ0Py53aWR0aCB8fFxyXG4gICAgICBnbG9iYWxPcHRpb25zPy5leHBvcnRpbmc/LnNvdXJjZVdpZHRoIHx8XHJcbiAgICAgIGdsb2JhbE9wdGlvbnM/LmNoYXJ0Py53aWR0aCB8fFxyXG4gICAgICBvcHRpb25zLmV4cG9ydD8uZGVmYXVsdFdpZHRoIHx8XHJcbiAgICAgIDYwMCxcclxuICAgIHNjYWxlXHJcbiAgfTtcclxuXHJcbiAgLy8gR2V0IHJpZCBvZiBwb3RlbnRpYWwgcHggYW5kICVcclxuICBmb3IgKGxldCBbcGFyYW0sIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhzaXplKSkge1xyXG4gICAgc2l6ZVtwYXJhbV0gPVxyXG4gICAgICB0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnID8gK3ZhbHVlLnJlcGxhY2UoL3B4fCUvZ2ksICcnKSA6IHZhbHVlO1xyXG4gIH1cclxuICByZXR1cm4gc2l6ZTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBGdW5jdGlvbiBmb3IgZmluYWxpemluZyBvcHRpb25zIGJlZm9yZSBleHBvcnQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IGNvbnRhaW5pbmcgY29uZmlndXJhdGlvbiBmb3JcclxuICogdGhlIGV4cG9ydCBwcm9jZXNzLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY2hhcnRKc29uIC0gVGhlIEpTT04gcmVwcmVzZW50YXRpb24gb2YgdGhlIGNoYXJ0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIFRoZSBjYWxsYmFjayBmdW5jdGlvbiB0byBiZSBjYWxsZWQgdXBvblxyXG4gKiBjb21wbGV0aW9uIG9yIGVycm9yLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gc3ZnIC0gVGhlIFNWRyByZXByZXNlbnRhdGlvbiBvZiB0aGUgY2hhcnQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBleHBvcnQgcHJvY2Vzc1xyXG4gKiBpcyBjb21wbGV0ZWQuXHJcbiAqL1xyXG5jb25zdCBkb0V4cG9ydCA9IGFzeW5jIChvcHRpb25zLCBjaGFydEpzb24sIGVuZENhbGxiYWNrLCBzdmcpID0+IHtcclxuICBsZXQgeyBleHBvcnQ6IGV4cG9ydE9wdGlvbnMsIGN1c3RvbUxvZ2ljOiBjdXN0b21Mb2dpY09wdGlvbnMgfSA9IG9wdGlvbnM7XHJcblxyXG4gIGNvbnN0IGFsbG93Q29kZUV4ZWN1dGlvblNjb3BlZCA9XHJcbiAgICB0eXBlb2YgY3VzdG9tTG9naWNPcHRpb25zLmFsbG93Q29kZUV4ZWN1dGlvbiA9PT0gJ2Jvb2xlYW4nXHJcbiAgICAgID8gY3VzdG9tTG9naWNPcHRpb25zLmFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgICA6IGFsbG93Q29kZUV4ZWN1dGlvbjtcclxuXHJcbiAgaWYgKCFjdXN0b21Mb2dpY09wdGlvbnMpIHtcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucyA9IG9wdGlvbnMuY3VzdG9tTG9naWMgPSB7fTtcclxuICB9IGVsc2UgaWYgKGFsbG93Q29kZUV4ZWN1dGlvblNjb3BlZCkge1xyXG4gICAgaWYgKHR5cGVvZiBvcHRpb25zLmN1c3RvbUxvZ2ljLnJlc291cmNlcyA9PT0gJ3N0cmluZycpIHtcclxuICAgICAgLy8gUHJvY2VzcyByZXNvdXJjZXNcclxuICAgICAgb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXMgPSBoYW5kbGVSZXNvdXJjZXMoXHJcbiAgICAgICAgb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXMsXHJcbiAgICAgICAgdG9Cb29sZWFuKG9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dGaWxlUmVzb3VyY2VzKVxyXG4gICAgICApO1xyXG4gICAgfSBlbHNlIGlmICghb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXMpIHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBjb25zdCByZXNvdXJjZXMgPSByZWFkRmlsZVN5bmMoJ3Jlc291cmNlcy5qc29uJywgJ3V0ZjgnKTtcclxuICAgICAgICBvcHRpb25zLmN1c3RvbUxvZ2ljLnJlc291cmNlcyA9IGhhbmRsZVJlc291cmNlcyhcclxuICAgICAgICAgIHJlc291cmNlcyxcclxuICAgICAgICAgIHRvQm9vbGVhbihvcHRpb25zLmN1c3RvbUxvZ2ljLmFsbG93RmlsZVJlc291cmNlcylcclxuICAgICAgICApO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAgIDIsXHJcbiAgICAgICAgICBlcnJvcixcclxuICAgICAgICAgIGBbY2hhcnRdIFVuYWJsZSB0byBsb2FkIHRoZSBkZWZhdWx0IHJlc291cmNlcy5qc29uIGZpbGUuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIElmIHRoZSBhbGxvd0NvZGVFeGVjdXRpb24gZmxhZyBpc24ndCBzZXQsIHdlIHNob3VsZCByZWZ1c2UgdGhlIHVzYWdlXHJcbiAgLy8gb2YgY2FsbGJhY2ssIHJlc291cmNlcywgYW5kIGN1c3RvbSBjb2RlLiBBZGRpdGlvbmFsbHksIHRoZSB3b3JrZXIgd2lsbFxyXG4gIC8vIHJlZnVzZSB0byBydW4gYXJiaXRyYXJ5IEphdmFTY3JpcHQuIFByaW9yaXRpemVkIHNob3VsZCBiZSB0aGUgc2NvcGVkXHJcbiAgLy8gb3B0aW9uLCB0aGVuIHdlIHNob3VsZCB0YWtlIGEgbG9vayBhdCB0aGUgb3ZlcmFsbCBwb29sIG9wdGlvbi5cclxuICBpZiAoIWFsbG93Q29kZUV4ZWN1dGlvblNjb3BlZCAmJiBjdXN0b21Mb2dpY09wdGlvbnMpIHtcclxuICAgIGlmIChcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrIHx8XHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXMgfHxcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGVcclxuICAgICkge1xyXG4gICAgICAvLyBTZW5kIGJhY2sgYSBmcmllbmRseSBtZXNzYWdlIHNheWluZyB0aGF0IHRoZSBleHBvcnRlciBkb2VzIG5vdCBzdXBwb3J0XHJcbiAgICAgIC8vIHRoZXNlIHNldHRpbmdzLlxyXG4gICAgICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICAgICAgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgYFtjaGFydF0gVGhlICdjYWxsYmFjaycsICdyZXNvdXJjZXMnIGFuZCAnY3VzdG9tQ29kZScgb3B0aW9ucyBoYXZlIGJlZW4gZGlzYWJsZWQgZm9yIHRoaXMgc2VydmVyLmBcclxuICAgICAgICApXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmVzZXQgYWxsIGFkZGl0aW9uYWwgY3VzdG9tIGNvZGVcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IGZhbHNlO1xyXG4gICAgY3VzdG9tTG9naWNPcHRpb25zLnJlc291cmNlcyA9IGZhbHNlO1xyXG4gICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUgPSBmYWxzZTtcclxuICB9XHJcblxyXG4gIC8vIENsZWFuIHByb3BlcnRpZXMgdG8ga2VlcCBpdCBsZWFuIGFuZCBtZWFuXHJcbiAgaWYgKGNoYXJ0SnNvbikge1xyXG4gICAgY2hhcnRKc29uLmNoYXJ0ID0gY2hhcnRKc29uLmNoYXJ0IHx8IHt9O1xyXG4gICAgY2hhcnRKc29uLmV4cG9ydGluZyA9IGNoYXJ0SnNvbi5leHBvcnRpbmcgfHwge307XHJcbiAgICBjaGFydEpzb24uZXhwb3J0aW5nLmVuYWJsZWQgPSBmYWxzZTtcclxuICB9XHJcblxyXG4gIGV4cG9ydE9wdGlvbnMuY29uc3RyID0gZXhwb3J0T3B0aW9ucy5jb25zdHIgfHwgJ2NoYXJ0JztcclxuICBleHBvcnRPcHRpb25zLnR5cGUgPSBmaXhUeXBlKGV4cG9ydE9wdGlvbnMudHlwZSwgZXhwb3J0T3B0aW9ucy5vdXRmaWxlKTtcclxuICBpZiAoZXhwb3J0T3B0aW9ucy50eXBlID09PSAnc3ZnJykge1xyXG4gICAgZXhwb3J0T3B0aW9ucy53aWR0aCA9IGZhbHNlO1xyXG4gIH1cclxuXHJcbiAgLy8gUHJlcGFyZSBnbG9iYWwgYW5kIHRoZW1lIG9wdGlvbnNcclxuICBbJ2dsb2JhbE9wdGlvbnMnLCAndGhlbWVPcHRpb25zJ10uZm9yRWFjaCgob3B0aW9uc05hbWUpID0+IHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGlmIChleHBvcnRPcHRpb25zICYmIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdKSB7XHJcbiAgICAgICAgaWYgKFxyXG4gICAgICAgICAgdHlwZW9mIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID09PSAnc3RyaW5nJyAmJlxyXG4gICAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0uZW5kc1dpdGgoJy5qc29uJylcclxuICAgICAgICApIHtcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID0gaXNDb3JyZWN0SlNPTihcclxuICAgICAgICAgICAgcmVhZEZpbGVTeW5jKGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdLCAndXRmOCcpLFxyXG4gICAgICAgICAgICB0cnVlXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9IGlzQ29ycmVjdEpTT04oXHJcbiAgICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdLFxyXG4gICAgICAgICAgICB0cnVlXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPSB7fTtcclxuICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2NoYXJ0XSBUaGUgJyR7b3B0aW9uc05hbWV9JyBjYW5ub3QgYmUgbG9hZGVkLmApO1xyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICAvLyBQcmVwYXJlIHRoZSBjdXN0b21Db2RlXHJcbiAgaWYgKGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0NvZGVFeGVjdXRpb24pIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlID0gd3JhcEFyb3VuZChcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSxcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dGaWxlUmVzb3VyY2VzXHJcbiAgICAgICk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbY2hhcnRdIFRoZSAnY3VzdG9tQ29kZScgY2Fubm90IGJlIGxvYWRlZC5gKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIEdldCB0aGUgY2FsbGJhY2tcclxuICBpZiAoXHJcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMgJiZcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayAmJlxyXG4gICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrPy5pbmRleE9mKCd7JykgPCAwXHJcbiAgKSB7XHJcbiAgICAvLyBUaGUgYWxsb3dGaWxlUmVzb3VyY2VzIGlzIGFsd2F5cyBzZXQgdG8gZmFsc2UgZm9yIEhUVFAgcmVxdWVzdHMgdG8gYXZvaWRcclxuICAgIC8vIGluamVjdGluZyBhcmJpdHJhcnkgZmlsZXMgZnJvbSB0aGUgZnNcclxuICAgIGlmIChjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dGaWxlUmVzb3VyY2VzKSB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrID0gcmVhZEZpbGVTeW5jKFxyXG4gICAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrLFxyXG4gICAgICAgICAgJ3V0ZjgnXHJcbiAgICAgICAgKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSBmYWxzZTtcclxuICAgICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbY2hhcnRdIFRoZSAnY2FsbGJhY2snIGNhbm5vdCBiZSBsb2FkZWQuYCk7XHJcbiAgICAgIH1cclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IGZhbHNlO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gU2l6ZSBzZWFyY2hcclxuICBvcHRpb25zLmV4cG9ydCA9IHtcclxuICAgIC4uLm9wdGlvbnMuZXhwb3J0LFxyXG4gICAgLi4uZmluZENoYXJ0U2l6ZShvcHRpb25zKVxyXG4gIH07XHJcblxyXG4gIC8vIFBvc3QgdGhlIHdvcmsgdG8gdGhlIHBvb2xcclxuICB0cnkge1xyXG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcG9zdFdvcmsoXHJcbiAgICAgIGV4cG9ydE9wdGlvbnMuc3RySW5qIHx8IGNoYXJ0SnNvbiB8fCBzdmcsXHJcbiAgICAgIG9wdGlvbnNcclxuICAgICk7XHJcbiAgICByZXR1cm4gZW5kQ2FsbGJhY2soZmFsc2UsIHJlc3VsdCk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHJldHVybiBlbmRDYWxsYmFjayhlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIFBlcmZvcm1zIGEgZGlyZWN0IGluamVjdCBvZiBvcHRpb25zIGJlZm9yZSBleHBvcnQuIFRoZSBmdW5jdGlvbiBhdHRlbXB0c1xyXG4gKiB0byBzdHJpbmdpZnkgdGhlIHByb3ZpZGVkIG9wdGlvbnMgYW5kIHJlbW92ZXMgdW5uZWNlc3NhcnkgY2hhcmFjdGVycyxcclxuICogZW5zdXJpbmcgYSBjbGVhbiBhbmQgZm9ybWF0dGVkIGlucHV0LiBUaGUgcmVzdWx0aW5nIHN0cmluZyBpcyBzYXZlZCBhc1xyXG4gKiBhIFwic3RyaWdodCBpbmplY3RcIiBzdHJpbmcgaW4gdGhlIGV4cG9ydCBvcHRpb25zLiBJdCB0aGVuIGludm9rZXMgdGhlXHJcbiAqIGRvRXhwb3J0IGZ1bmN0aW9uIHdpdGggdGhlIHVwZGF0ZWQgb3B0aW9ucy5cclxuICpcclxuICogSU1QT1JUQU5UOiBEYW5nZXJvdXMgYW5kIG11c3QgYmUgdXNlZCBkZWxpYmVyYXRlbHkgYnkgc29tZW9uZSB3aG8gc2V0cyB1cFxyXG4gKiBhIHNlcnZlciAoc2VlIHRoZSAgLS1hbGxvd0NvZGVFeGVjdXRpb24gb3B0aW9uKS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgZXhwb3J0IG9wdGlvbnMgY29udGFpbmluZyB0aGUgaW5wdXRcclxuICogdG8gYmUgaW5qZWN0ZWQuXHJcbiAqIEBwYXJhbSB7ZnVuY3Rpb259IGVuZENhbGxiYWNrIC0gVGhlIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGludm9rZWRcclxuICogYXQgdGhlIGVuZCBvZiB0aGUgcHJvY2Vzcy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2V9IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHdpdGggdGhlIHJlc3VsdCBvZiB0aGUgZXhwb3J0XHJcbiAqIG9wZXJhdGlvbiBvciByZWplY3RzIHdpdGggYW4gZXJyb3IgaWYgYW55IGlzc3VlcyBvY2N1ciBkdXJpbmcgdGhlIHByb2Nlc3MuXHJcbiAqL1xyXG5jb25zdCBkb1N0cmFpZ2h0SW5qZWN0ID0gKG9wdGlvbnMsIGVuZENhbGxiYWNrKSA9PiB7XHJcbiAgdHJ5IHtcclxuICAgIGxldCBzdHJJbmo7XHJcbiAgICBsZXQgaW5zdHIgPSBvcHRpb25zLmV4cG9ydC5pbnN0ciB8fCBvcHRpb25zLmV4cG9ydC5vcHRpb25zO1xyXG5cclxuICAgIGlmICh0eXBlb2YgaW5zdHIgIT09ICdzdHJpbmcnKSB7XHJcbiAgICAgIC8vIFRyeSB0byBzdHJpbmdpZnkgb3B0aW9uc1xyXG4gICAgICBzdHJJbmogPSBpbnN0ciA9IG9wdGlvbnNTdHJpbmdpZnkoXHJcbiAgICAgICAgaW5zdHIsXHJcbiAgICAgICAgb3B0aW9ucy5jdXN0b21Mb2dpYz8uYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgICBzdHJJbmogPSBpbnN0ci5yZXBsYWNlQWxsKC9cXHR8XFxufFxcci9nLCAnJykudHJpbSgpO1xyXG5cclxuICAgIC8vIEdldCByaWQgb2YgdGhlIDtcclxuICAgIGlmIChzdHJJbmpbc3RySW5qLmxlbmd0aCAtIDFdID09PSAnOycpIHtcclxuICAgICAgc3RySW5qID0gc3RySW5qLnN1YnN0cmluZygwLCBzdHJJbmoubGVuZ3RoIC0gMSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU2F2ZSBhcyBzdHJpZ2h0IGluamVjdCBzdHJpbmdcclxuICAgIG9wdGlvbnMuZXhwb3J0LnN0ckluaiA9IHN0ckluajtcclxuICAgIHJldHVybiBkb0V4cG9ydChvcHRpb25zLCBmYWxzZSwgZW5kQ2FsbGJhY2spO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICAgIG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICBgW2NoYXJ0XSBNYWxmb3JtZWQgaW5wdXQgZGV0ZWN0ZWQgZm9yICR7b3B0aW9ucy5leHBvcnQ/LnJlcXVlc3RJZCB8fCAnPyd9LiBQbGVhc2UgbWFrZSBzdXJlIHRoYXQgeW91ciBKU09OL0phdmFTY3JpcHQgb3B0aW9ucyBhcmUgc2VudCB1c2luZyB0aGUgXCJvcHRpb25zXCIgYXR0cmlidXRlLCBhbmQgdGhhdCBpZiB5b3UncmUgdXNpbmcgU1ZHLCBpdCBpcyB1bmVzY2FwZWQuYFxyXG4gICAgICApLnNldEVycm9yKGVycm9yKVxyXG4gICAgKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogRXhwb3J0cyBhIHN0cmluZyBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgb3B0aW9ucyBhbmQgaW52b2tlcyBhbiBlbmQgY2FsbGJhY2suXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBzdHJpbmdUb0V4cG9ydCAtIFRoZSBzdHJpbmcgY29udGVudCB0byBiZSBleHBvcnRlZC5cclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBFeHBvcnQgb3B0aW9ucywgaW5jbHVkaW5nIGN1c3RvbUxvZ2ljIHdpdGhcclxuICogYWxsb3dDb2RlRXhlY3V0aW9uIGZsYWcuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGVuZENhbGxiYWNrIC0gQ2FsbGJhY2sgZnVuY3Rpb24gdG8gYmUgaW52b2tlZCBhdCB0aGUgZW5kXHJcbiAqIG9mIHRoZSBleHBvcnQgcHJvY2Vzcy5cclxuICpcclxuICogQHJldHVybnMge2FueX0gUmVzdWx0IG9mIHRoZSBleHBvcnQgcHJvY2VzcyBvciBhbiBlcnJvciBpZiBlbmNvdW50ZXJlZC5cclxuICovXHJcbmNvbnN0IGV4cG9ydEFzU3RyaW5nID0gKHN0cmluZ1RvRXhwb3J0LCBvcHRpb25zLCBlbmRDYWxsYmFjaykgPT4ge1xyXG4gIGNvbnN0IHsgYWxsb3dDb2RlRXhlY3V0aW9uIH0gPSBvcHRpb25zLmN1c3RvbUxvZ2ljO1xyXG5cclxuICAvLyBDaGVjayBpZiBpdCBpcyBTVkdcclxuICBpZiAoXHJcbiAgICBzdHJpbmdUb0V4cG9ydC5pbmRleE9mKCc8c3ZnJykgPj0gMCB8fFxyXG4gICAgc3RyaW5nVG9FeHBvcnQuaW5kZXhPZignPD94bWwnKSA+PSAwXHJcbiAgKSB7XHJcbiAgICBsb2coNCwgJ1tjaGFydF0gUGFyc2luZyBpbnB1dCBhcyBTVkcuJyk7XHJcbiAgICByZXR1cm4gZG9FeHBvcnQob3B0aW9ucywgZmFsc2UsIGVuZENhbGxiYWNrLCBzdHJpbmdUb0V4cG9ydCk7XHJcbiAgfVxyXG5cclxuICB0cnkge1xyXG4gICAgLy8gVHJ5IHRvIHBhcnNlIHRvIEpTT04gYW5kIGNhbGwgdGhlIGRvRXhwb3J0IGZ1bmN0aW9uXHJcbiAgICBjb25zdCBjaGFydEpTT04gPSBKU09OLnBhcnNlKHN0cmluZ1RvRXhwb3J0LnJlcGxhY2VBbGwoL1xcdHxcXG58XFxyL2csICcgJykpO1xyXG5cclxuICAgIC8vIElmIGEgY29ycmVjdCBKU09OLCBkbyB0aGUgZXhwb3J0XHJcbiAgICByZXR1cm4gZG9FeHBvcnQob3B0aW9ucywgY2hhcnRKU09OLCBlbmRDYWxsYmFjayk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIC8vIE5vdCBhIHZhbGlkIEpTT05cclxuICAgIGlmICh0b0Jvb2xlYW4oYWxsb3dDb2RlRXhlY3V0aW9uKSkge1xyXG4gICAgICByZXR1cm4gZG9TdHJhaWdodEluamVjdChvcHRpb25zLCBlbmRDYWxsYmFjayk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBEbyBub3QgYWxsb3cgc3RyYWlnaHQgaW5qZWN0aW9uIHdpdGhvdXQgdGhlIGFsbG93Q29kZUV4ZWN1dGlvbiBmbGFnXHJcbiAgICAgIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgICAgICBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgICAnW2NoYXJ0XSBPbmx5IEpTT04gY29uZmlndXJhdGlvbnMgYW5kIFNWRyBhcmUgYWxsb3dlZCBmb3IgdGhpcyBzZXJ2ZXIuIElmIHRoaXMgaXMgeW91ciBzZXJ2ZXIsIEphdmFTY3JpcHQgY3VzdG9tIGNvZGUgY2FuIGJlIGVuYWJsZWQgYnkgc3RhcnRpbmcgdGhlIHNlcnZlciB3aXRoIHRoZSAtLWFsbG93Q29kZUV4ZWN1dGlvbiBmbGFnLidcclxuICAgICAgICApLnNldEVycm9yKGVycm9yKVxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgYW5kIHJldHVybnMgdGhlIGN1cnJlbnQgc3RhdHVzIG9mIGNvZGUgZXhlY3V0aW9uIHBlcm1pc3Npb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHthbnl9IFRoZSB2YWx1ZSBvZiBhbGxvd0NvZGVFeGVjdXRpb24uXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0QWxsb3dDb2RlRXhlY3V0aW9uID0gKCkgPT4gYWxsb3dDb2RlRXhlY3V0aW9uO1xyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIGNvZGUgZXhlY3V0aW9uIHBlcm1pc3Npb24gYmFzZWQgb24gdGhlIHByb3ZpZGVkIGJvb2xlYW4gdmFsdWUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7YW55fSB2YWx1ZSAtIFRoZSB2YWx1ZSB0byBiZSBjb252ZXJ0ZWQgYW5kIGFzc2lnbmVkXHJcbiAqIHRvIGFsbG93Q29kZUV4ZWN1dGlvbi5cclxuICovXHJcbmV4cG9ydCBjb25zdCBzZXRBbGxvd0NvZGVFeGVjdXRpb24gPSAodmFsdWUpID0+IHtcclxuICBhbGxvd0NvZGVFeGVjdXRpb24gPSB0b0Jvb2xlYW4odmFsdWUpO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGJhdGNoRXhwb3J0LFxyXG4gIHNpbmdsZUV4cG9ydCxcclxuICBnZXRBbGxvd0NvZGVFeGVjdXRpb24sXHJcbiAgc2V0QWxsb3dDb2RlRXhlY3V0aW9uLFxyXG4gIHN0YXJ0RXhwb3J0LFxyXG4gIGZpbmRDaGFydFNpemVcclxufTtcclxuIiwiaW1wb3J0IHsgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi4vbG9nZ2VyLmpzJztcclxuXHJcbi8qKlxyXG4gKiBNaWRkbGV3YXJlIGZvciBsb2dnaW5nIGVycm9ycyB3aXRoIHN0YWNrIHRyYWNlIGFuZCBoYW5kbGluZyBlcnJvciByZXNwb25zZS5cclxuICpcclxuICogQHBhcmFtIHtFcnJvcn0gZXJyb3IgLSBUaGUgZXJyb3Igb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxIC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBuZXh0IC0gVGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICovXHJcbmNvbnN0IGxvZ0Vycm9yTWlkZGxld2FyZSA9IChlcnJvciwgcmVxLCByZXMsIG5leHQpID0+IHtcclxuICAvLyBEaXNwbGF5IHRoZSBlcnJvciB3aXRoIHN0YWNrIGluIGEgY29ycmVjdCBmb3JtYXRcclxuICBsb2dXaXRoU3RhY2soMSwgZXJyb3IpO1xyXG5cclxuICAvLyBEZWxldGUgdGhlIHN0YWNrIGZvciB0aGUgZW52aXJvbm1lbnQgb3RoZXIgdGhhbiB0aGUgZGV2ZWxvcG1lbnRcclxuICBpZiAocHJvY2Vzcy5lbnYuTk9ERV9FTlYgIT09ICdkZXZlbG9wbWVudCcpIHtcclxuICAgIGRlbGV0ZSBlcnJvci5zdGFjaztcclxuICB9XHJcblxyXG4gIC8vIENhbGwgdGhlIHJldHVybkVycm9yTWlkZGxld2FyZVxyXG4gIG5leHQoZXJyb3IpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIE1pZGRsZXdhcmUgZm9yIHJldHVybmluZyBlcnJvciByZXNwb25zZS5cclxuICpcclxuICogQHBhcmFtIHtFcnJvcn0gZXJyb3IgLSBUaGUgZXJyb3Igb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxIC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBuZXh0IC0gVGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICovXHJcbmNvbnN0IHJldHVybkVycm9yTWlkZGxld2FyZSA9IChlcnJvciwgcmVxLCByZXMsIG5leHQpID0+IHtcclxuICAvLyBHYXRoZXIgYWxsIHJlcXVpZWQgaW5mb3JtYXRpb24gZm9yIHRoZSByZXNwb25zZVxyXG4gIGNvbnN0IHsgc3RhdHVzQ29kZTogc3RDb2RlLCBzdGF0dXMsIG1lc3NhZ2UsIHN0YWNrIH0gPSBlcnJvcjtcclxuICBjb25zdCBzdGF0dXNDb2RlID0gc3RDb2RlIHx8IHN0YXR1cyB8fCA1MDA7XHJcblxyXG4gIC8vIFNldCBhbmQgcmV0dXJuIHJlc3BvbnNlXHJcbiAgcmVzLnN0YXR1cyhzdGF0dXNDb2RlKS5qc29uKHsgc3RhdHVzQ29kZSwgbWVzc2FnZSwgc3RhY2sgfSk7XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCAoYXBwKSA9PiB7XHJcbiAgLy8gQWRkIGxvZyBlcnJvciBtaWRkbGV3YXJlXHJcbiAgYXBwLnVzZShsb2dFcnJvck1pZGRsZXdhcmUpO1xyXG5cclxuICAvLyBBZGQgc2V0IHN0YXR1cyBhbmQgcmV0dXJuIGVycm9yIG1pZGRsZXdhcmVcclxuICBhcHAudXNlKHJldHVybkVycm9yTWlkZGxld2FyZSk7XHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHJhdGVMaW1pdCBmcm9tICdleHByZXNzLXJhdGUtbGltaXQnO1xyXG5cclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi4vbG9nZ2VyLmpzJztcclxuXHJcbi8qKlxyXG4gKiBNaWRkbGV3YXJlIGZvciBlbmFibGluZyByYXRlIGxpbWl0aW5nIG9uIHRoZSBzcGVjaWZpZWQgRXhwcmVzcyBhcHAuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzc30gYXBwIC0gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gbGltaXRDb25maWcgLSBDb25maWd1cmF0aW9uIG9wdGlvbnMgZm9yIHJhdGUgbGltaXRpbmcuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCAoYXBwLCBsaW1pdENvbmZpZykgPT4ge1xyXG4gIGNvbnN0IG1zZyA9XHJcbiAgICAnVG9vIG1hbnkgcmVxdWVzdHMsIHlvdSBoYXZlIGJlZW4gcmF0ZSBsaW1pdGVkLiBQbGVhc2UgdHJ5IGFnYWluIGxhdGVyLic7XHJcblxyXG4gIC8vIE9wdGlvbnMgZm9yIHRoZSByYXRlIGxpbWl0ZXJcclxuICBjb25zdCByYXRlT3B0aW9ucyA9IHtcclxuICAgIG1heDogbGltaXRDb25maWcubWF4UmVxdWVzdHMgfHwgMzAsXHJcbiAgICB3aW5kb3c6IGxpbWl0Q29uZmlnLndpbmRvdyB8fCAxLFxyXG4gICAgZGVsYXk6IGxpbWl0Q29uZmlnLmRlbGF5IHx8IDAsXHJcbiAgICB0cnVzdFByb3h5OiBsaW1pdENvbmZpZy50cnVzdFByb3h5IHx8IGZhbHNlLFxyXG4gICAgc2tpcEtleTogbGltaXRDb25maWcuc2tpcEtleSB8fCBmYWxzZSxcclxuICAgIHNraXBUb2tlbjogbGltaXRDb25maWcuc2tpcFRva2VuIHx8IGZhbHNlXHJcbiAgfTtcclxuXHJcbiAgLy8gU2V0IGlmIGJlaGluZCBhIHByb3h5XHJcbiAgaWYgKHJhdGVPcHRpb25zLnRydXN0UHJveHkpIHtcclxuICAgIGFwcC5lbmFibGUoJ3RydXN0IHByb3h5Jyk7XHJcbiAgfVxyXG5cclxuICAvLyBDcmVhdGUgYSBsaW1pdGVyXHJcbiAgY29uc3QgbGltaXRlciA9IHJhdGVMaW1pdCh7XHJcbiAgICB3aW5kb3dNczogcmF0ZU9wdGlvbnMud2luZG93ICogNjAgKiAxMDAwLFxyXG4gICAgLy8gTGltaXQgZWFjaCBJUCB0byAxMDAgcmVxdWVzdHMgcGVyIHdpbmRvd01zXHJcbiAgICBtYXg6IHJhdGVPcHRpb25zLm1heCxcclxuICAgIC8vIERpc2FibGUgZGVsYXlpbmcsIGZ1bGwgc3BlZWQgdW50aWwgdGhlIG1heCBsaW1pdCBpcyByZWFjaGVkXHJcbiAgICBkZWxheU1zOiByYXRlT3B0aW9ucy5kZWxheSxcclxuICAgIGhhbmRsZXI6IChyZXF1ZXN0LCByZXNwb25zZSkgPT4ge1xyXG4gICAgICByZXNwb25zZS5mb3JtYXQoe1xyXG4gICAgICAgIGpzb246ICgpID0+IHtcclxuICAgICAgICAgIHJlc3BvbnNlLnN0YXR1cyg0MjkpLnNlbmQoeyBtZXNzYWdlOiBtc2cgfSk7XHJcbiAgICAgICAgfSxcclxuICAgICAgICBkZWZhdWx0OiAoKSA9PiB7XHJcbiAgICAgICAgICByZXNwb25zZS5zdGF0dXMoNDI5KS5zZW5kKG1zZyk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9KTtcclxuICAgIH0sXHJcbiAgICBza2lwOiAocmVxdWVzdCkgPT4ge1xyXG4gICAgICAvLyBBbGxvdyBieXBhc3NpbmcgdGhlIGxpbWl0ZXIgaWYgYSB2YWxpZCBrZXkvdG9rZW4gaGFzIGJlZW4gc2VudFxyXG4gICAgICBpZiAoXHJcbiAgICAgICAgcmF0ZU9wdGlvbnMuc2tpcEtleSAhPT0gZmFsc2UgJiZcclxuICAgICAgICByYXRlT3B0aW9ucy5za2lwVG9rZW4gIT09IGZhbHNlICYmXHJcbiAgICAgICAgcmVxdWVzdC5xdWVyeS5rZXkgPT09IHJhdGVPcHRpb25zLnNraXBLZXkgJiZcclxuICAgICAgICByZXF1ZXN0LnF1ZXJ5LmFjY2Vzc190b2tlbiA9PT0gcmF0ZU9wdGlvbnMuc2tpcFRva2VuXHJcbiAgICAgICkge1xyXG4gICAgICAgIGxvZyg0LCAnW3JhdGUgbGltaXRpbmddIFNraXBwaW5nIHJhdGUgbGltaXRlci4nKTtcclxuICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICB9XHJcbiAgfSk7XHJcblxyXG4gIC8vIFVzZSBhIGxpbWl0ZXIgYXMgYSBtaWRkbGV3YXJlXHJcbiAgYXBwLnVzZShsaW1pdGVyKTtcclxuXHJcbiAgbG9nKFxyXG4gICAgMyxcclxuICAgIGBbcmF0ZSBsaW1pdGluZ10gRW5hYmxlZCByYXRlIGxpbWl0aW5nIHdpdGggJHtyYXRlT3B0aW9ucy5tYXh9IHJlcXVlc3RzIHBlciAke3JhdGVPcHRpb25zLndpbmRvd30gbWludXRlIGZvciBlYWNoIElQLCB0cnVzdGluZyBwcm94eTogJHtyYXRlT3B0aW9ucy50cnVzdFByb3h5fS5gXHJcbiAgKTtcclxufTtcclxuIiwiaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuY2xhc3MgSHR0cEVycm9yIGV4dGVuZHMgRXhwb3J0RXJyb3Ige1xyXG4gIGNvbnN0cnVjdG9yKG1lc3NhZ2UsIHN0YXR1cykge1xyXG4gICAgc3VwZXIobWVzc2FnZSk7XHJcbiAgICB0aGlzLnN0YXR1cyA9IHRoaXMuc3RhdHVzQ29kZSA9IHN0YXR1cztcclxuICB9XHJcblxyXG4gIHNldFN0YXR1cyhzdGF0dXMpIHtcclxuICAgIHRoaXMuc3RhdHVzID0gc3RhdHVzO1xyXG4gICAgcmV0dXJuIHRoaXM7XHJcbiAgfVxyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCBIdHRwRXJyb3I7XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgdjQgYXMgdXVpZCB9IGZyb20gJ3V1aWQnO1xyXG5cclxuaW1wb3J0IHsgZ2V0QWxsb3dDb2RlRXhlY3V0aW9uLCBzdGFydEV4cG9ydCB9IGZyb20gJy4uLy4uL2NoYXJ0LmpzJztcclxuaW1wb3J0IHsgZ2V0T3B0aW9ucywgbWVyZ2VDb25maWdPcHRpb25zIH0gZnJvbSAnLi4vLi4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi4vLi4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHtcclxuICBmaXhUeXBlLFxyXG4gIGlzQ29ycmVjdEpTT04sXHJcbiAgaXNPYmplY3RFbXB0eSxcclxuICBpc1ByaXZhdGVSYW5nZVVybEZvdW5kLFxyXG4gIG9wdGlvbnNTdHJpbmdpZnksXHJcbiAgbWVhc3VyZVRpbWVcclxufSBmcm9tICcuLi8uLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgSHR0cEVycm9yIGZyb20gJy4uLy4uL2Vycm9ycy9IdHRwRXJyb3IuanMnO1xyXG5cclxuLy8gUmV2ZXJzZWQgTUlNRSB0eXBlc1xyXG5jb25zdCByZXZlcnNlZE1pbWUgPSB7XHJcbiAgcG5nOiAnaW1hZ2UvcG5nJyxcclxuICBqcGVnOiAnaW1hZ2UvanBlZycsXHJcbiAgZ2lmOiAnaW1hZ2UvZ2lmJyxcclxuICBwZGY6ICdhcHBsaWNhdGlvbi9wZGYnLFxyXG4gIHN2ZzogJ2ltYWdlL3N2Zyt4bWwnXHJcbn07XHJcblxyXG4vLyBUaGUgcmVxdWVzdHMgY291bnRlclxyXG5sZXQgcmVxdWVzdHNDb3VudGVyID0gMDtcclxuXHJcbi8vIFRoZSBhcnJheSBvZiBjYWxsYmFja3MgdG8gY2FsbCBiZWZvcmUgYSByZXF1ZXN0XHJcbmNvbnN0IGJlZm9yZVJlcXVlc3QgPSBbXTtcclxuXHJcbi8vIFRoZSBhcnJheSBvZiBjYWxsYmFja3MgdG8gY2FsbCBhZnRlciBhIHJlcXVlc3RcclxuY29uc3QgYWZ0ZXJSZXF1ZXN0ID0gW107XHJcblxyXG4vKipcclxuICogSW52b2tlcyBhbiBhcnJheSBvZiBjYWxsYmFjayBmdW5jdGlvbnMgd2l0aCBzcGVjaWZpZWQgcGFyYW1ldGVycywgYWxsb3dpbmdcclxuICogY3VzdG9taXphdGlvbiBvZiByZXF1ZXN0IGhhbmRsaW5nLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9uW119IGNhbGxiYWNrcyAtIEFuIGFycmF5IG9mIGNhbGxiYWNrIGZ1bmN0aW9uc1xyXG4gKiB0byBiZSBleGVjdXRlZC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcXVlc3QgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXNwb25zZSAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cclxuICogQHBhcmFtIHtPYmplY3R9IGRhdGEgLSBBbiBvYmplY3QgY29udGFpbmluZyBwYXJhbWV0ZXJzIGxpa2UgaWQsIHVuaXF1ZUlkLFxyXG4gKiB0eXBlLCBhbmQgYm9keS5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IC0gUmV0dXJucyBhIGJvb2xlYW4gaW5kaWNhdGluZyB0aGUgb3ZlcmFsbCByZXN1bHRcclxuICogb2YgdGhlIGNhbGxiYWNrIGludm9jYXRpb25zLlxyXG4gKi9cclxuY29uc3QgZG9DYWxsYmFja3MgPSAoY2FsbGJhY2tzLCByZXF1ZXN0LCByZXNwb25zZSwgZGF0YSkgPT4ge1xyXG4gIGxldCByZXN1bHQgPSB0cnVlO1xyXG4gIGNvbnN0IHsgaWQsIHVuaXF1ZUlkLCB0eXBlLCBib2R5IH0gPSBkYXRhO1xyXG5cclxuICBjYWxsYmFja3Muc29tZSgoY2FsbGJhY2spID0+IHtcclxuICAgIGlmIChjYWxsYmFjaykge1xyXG4gICAgICBsZXQgY2FsbFJlc3BvbnNlID0gY2FsbGJhY2socmVxdWVzdCwgcmVzcG9uc2UsIGlkLCB1bmlxdWVJZCwgdHlwZSwgYm9keSk7XHJcblxyXG4gICAgICBpZiAoY2FsbFJlc3BvbnNlICE9PSB1bmRlZmluZWQgJiYgY2FsbFJlc3BvbnNlICE9PSB0cnVlKSB7XHJcbiAgICAgICAgcmVzdWx0ID0gY2FsbFJlc3BvbnNlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICByZXR1cm4gdHJ1ZTtcclxuICAgIH1cclxuICB9KTtcclxuXHJcbiAgcmV0dXJuIHJlc3VsdDtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBIYW5kbGVzIHRoZSBleHBvcnQgcmVxdWVzdHMgZnJvbSB0aGUgY2xpZW50LlxyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxdWVzdCAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlc3BvbnNlIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBuZXh0IC0gVGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IC0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgZXhwb3J0IHByb2Nlc3NcclxuICogaXMgY29tcGxldGUuXHJcbiAqL1xyXG5jb25zdCBleHBvcnRIYW5kbGVyID0gYXN5bmMgKHJlcXVlc3QsIHJlc3BvbnNlLCBuZXh0KSA9PiB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIFN0YXJ0IGNvdW50aW5nIHRpbWVcclxuICAgIGNvbnN0IHN0b3BDb3VudGVyID0gbWVhc3VyZVRpbWUoKTtcclxuXHJcbiAgICAvLyBDcmVhdGUgYSB1bmlxdWUgSUQgZm9yIGEgcmVxdWVzdFxyXG4gICAgY29uc3QgdW5pcXVlSWQgPSB1dWlkKCkucmVwbGFjZSgvLS9nLCAnJyk7XHJcblxyXG4gICAgLy8gR2V0IHRoZSBjdXJyZW50IHNlcnZlcidzIGdlbmVyYWwgb3B0aW9uc1xyXG4gICAgY29uc3QgZGVmYXVsdE9wdGlvbnMgPSBnZXRPcHRpb25zKCk7XHJcblxyXG4gICAgY29uc3QgYm9keSA9IHJlcXVlc3QuYm9keTtcclxuICAgIGNvbnN0IGlkID0gKytyZXF1ZXN0c0NvdW50ZXI7XHJcblxyXG4gICAgbGV0IHR5cGUgPSBmaXhUeXBlKGJvZHkudHlwZSk7XHJcblxyXG4gICAgLy8gVGhyb3cgJ0JhZCBSZXF1ZXN0JyBpZiB0aGVyZSdzIG5vIGJvZHlcclxuICAgIGlmICghYm9keSB8fCBpc09iamVjdEVtcHR5KGJvZHkpKSB7XHJcbiAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgJ1RoZSByZXF1ZXN0IGJvZHkgaXMgcmVxdWlyZWQuIFBsZWFzZSBlbnN1cmUgdGhhdCB5b3VyIENvbnRlbnQtVHlwZSBoZWFkZXIgaXMgY29ycmVjdCAoYWNjZXB0ZWQgdHlwZXMgYXJlIGFwcGxpY2F0aW9uL2pzb24gYW5kIG11bHRpcGFydC9mb3JtLWRhdGEpLicsXHJcbiAgICAgICAgNDAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQWxsIG9mIHRoZSBiZWxvdyBjYW4gYmUgdXNlZFxyXG4gICAgbGV0IGluc3RyID0gaXNDb3JyZWN0SlNPTihib2R5LmluZmlsZSB8fCBib2R5Lm9wdGlvbnMgfHwgYm9keS5kYXRhKTtcclxuXHJcbiAgICAvLyBUaHJvdyAnQmFkIFJlcXVlc3QnIGlmIHRoZXJlJ3Mgbm8gSlNPTiBvciBTVkcgdG8gZXhwb3J0XHJcbiAgICBpZiAoIWluc3RyICYmICFib2R5LnN2Zykge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgMixcclxuICAgICAgICBgVGhlIHJlcXVlc3Qgd2l0aCBJRCAke3VuaXF1ZUlkfSBmcm9tICR7XHJcbiAgICAgICAgICByZXF1ZXN0LmhlYWRlcnNbJ3gtZm9yd2FyZGVkLWZvciddIHx8IHJlcXVlc3QuY29ubmVjdGlvbi5yZW1vdGVBZGRyZXNzXHJcbiAgICAgICAgfSB3YXMgaW5jb3JyZWN0LiBQYXlsb2FkIHJlY2VpdmVkOiAke0pTT04uc3RyaW5naWZ5KGJvZHkpfS5gXHJcbiAgICAgICk7XHJcblxyXG4gICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgIFwiTm8gY29ycmVjdCBjaGFydCBkYXRhIGZvdW5kLiBFbnN1cmUgdGhhdCB5b3UgYXJlIHVzaW5nIGVpdGhlciBhcHBsaWNhdGlvbi9qc29uIG9yIG11bHRpcGFydC9mb3JtLWRhdGEgaGVhZGVycy4gSWYgc2VuZGluZyBKU09OLCBtYWtlIHN1cmUgdGhlIGNoYXJ0IGRhdGEgaXMgaW4gdGhlICdpbmZpbGUnLCAnb3B0aW9ucycsIG9yICdkYXRhJyBhdHRyaWJ1dGUuIElmIHNlbmRpbmcgU1ZHLCBlbnN1cmUgaXQgaXMgaW4gdGhlICdzdmcnIGF0dHJpYnV0ZS5cIixcclxuICAgICAgICA0MDBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICBsZXQgY2FsbFJlc3BvbnNlID0gZmFsc2U7XHJcblxyXG4gICAgLy8gQ2FsbCB0aGUgYmVmb3JlIHJlcXVlc3QgZnVuY3Rpb25zXHJcbiAgICBjYWxsUmVzcG9uc2UgPSBkb0NhbGxiYWNrcyhiZWZvcmVSZXF1ZXN0LCByZXF1ZXN0LCByZXNwb25zZSwge1xyXG4gICAgICBpZCxcclxuICAgICAgdW5pcXVlSWQsXHJcbiAgICAgIHR5cGUsXHJcbiAgICAgIGJvZHlcclxuICAgIH0pO1xyXG5cclxuICAgIC8vIEJsb2NrIHRoZSByZXF1ZXN0IGlmIG9uZSBvZiBhIGNhbGxiYWNrcyBmYWlsZWRcclxuICAgIGlmIChjYWxsUmVzcG9uc2UgIT09IHRydWUpIHtcclxuICAgICAgcmV0dXJuIHJlc3BvbnNlLnNlbmQoY2FsbFJlc3BvbnNlKTtcclxuICAgIH1cclxuXHJcbiAgICBsZXQgY29ubmVjdGlvbkFib3J0ZWQgPSBmYWxzZTtcclxuXHJcbiAgICAvLyBJbiBjYXNlIHRoZSBjb25uZWN0aW9uIGlzIGNsb3NlZCwgZm9yY2UgdG8gYWJvcnQgZnVydGhlciBhY3Rpb25zXHJcbiAgICByZXF1ZXN0LnNvY2tldC5vbignY2xvc2UnLCAoKSA9PiB7XHJcbiAgICAgIGNvbm5lY3Rpb25BYm9ydGVkID0gdHJ1ZTtcclxuICAgIH0pO1xyXG5cclxuICAgIGxvZyg0LCBgW2V4cG9ydF0gR290IGFuIGluY29taW5nIEhUVFAgcmVxdWVzdCB3aXRoIElEICR7dW5pcXVlSWR9LmApO1xyXG5cclxuICAgIGJvZHkuY29uc3RyID0gKHR5cGVvZiBib2R5LmNvbnN0ciA9PT0gJ3N0cmluZycgJiYgYm9keS5jb25zdHIpIHx8ICdjaGFydCc7XHJcblxyXG4gICAgLy8gR2F0aGVyIGFuZCBvcmdhbml6ZSBvcHRpb25zIGZyb20gdGhlIHBheWxvYWRcclxuICAgIGNvbnN0IHJlcXVlc3RPcHRpb25zID0ge1xyXG4gICAgICBleHBvcnQ6IHtcclxuICAgICAgICBpbnN0cixcclxuICAgICAgICB0eXBlLFxyXG4gICAgICAgIGNvbnN0cjogYm9keS5jb25zdHJbMF0udG9Mb3dlckNhc2UoKSArIGJvZHkuY29uc3RyLnN1YnN0cigxKSxcclxuICAgICAgICBoZWlnaHQ6IGJvZHkuaGVpZ2h0LFxyXG4gICAgICAgIHdpZHRoOiBib2R5LndpZHRoLFxyXG4gICAgICAgIHNjYWxlOiBib2R5LnNjYWxlIHx8IGRlZmF1bHRPcHRpb25zLmV4cG9ydC5zY2FsZSxcclxuICAgICAgICBnbG9iYWxPcHRpb25zOiBpc0NvcnJlY3RKU09OKGJvZHkuZ2xvYmFsT3B0aW9ucywgdHJ1ZSksXHJcbiAgICAgICAgdGhlbWVPcHRpb25zOiBpc0NvcnJlY3RKU09OKGJvZHkudGhlbWVPcHRpb25zLCB0cnVlKVxyXG4gICAgICB9LFxyXG4gICAgICBjdXN0b21Mb2dpYzoge1xyXG4gICAgICAgIGFsbG93Q29kZUV4ZWN1dGlvbjogZ2V0QWxsb3dDb2RlRXhlY3V0aW9uKCksXHJcbiAgICAgICAgYWxsb3dGaWxlUmVzb3VyY2VzOiBmYWxzZSxcclxuICAgICAgICByZXNvdXJjZXM6IGlzQ29ycmVjdEpTT04oYm9keS5yZXNvdXJjZXMsIHRydWUpLFxyXG4gICAgICAgIGNhbGxiYWNrOiBib2R5LmNhbGxiYWNrLFxyXG4gICAgICAgIGN1c3RvbUNvZGU6IGJvZHkuY3VzdG9tQ29kZVxyXG4gICAgICB9XHJcbiAgICB9O1xyXG5cclxuICAgIGlmIChpbnN0cikge1xyXG4gICAgICAvLyBTdHJpbmdpZnkgSlNPTiB3aXRoIG9wdGlvbnNcclxuICAgICAgcmVxdWVzdE9wdGlvbnMuZXhwb3J0Lmluc3RyID0gb3B0aW9uc1N0cmluZ2lmeShcclxuICAgICAgICBpbnN0cixcclxuICAgICAgICByZXF1ZXN0T3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0NvZGVFeGVjdXRpb25cclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBNZXJnZSB0aGUgcmVxdWVzdCBvcHRpb25zIGludG8gZGVmYXVsdCBvbmVzXHJcbiAgICBjb25zdCBvcHRpb25zID0gbWVyZ2VDb25maWdPcHRpb25zKGRlZmF1bHRPcHRpb25zLCByZXF1ZXN0T3B0aW9ucyk7XHJcblxyXG4gICAgLy8gU2F2ZSB0aGUgSlNPTiBpZiBleGlzdHNcclxuICAgIG9wdGlvbnMuZXhwb3J0Lm9wdGlvbnMgPSBpbnN0cjtcclxuXHJcbiAgICAvLyBMYXN0bHksIGFkZCB0aGUgc2VydmVyIHNwZWNpZmljIGFyZ3VtZW50cyBpbnRvIG9wdGlvbnMgYXMgcGF5bG9hZFxyXG4gICAgb3B0aW9ucy5wYXlsb2FkID0ge1xyXG4gICAgICBzdmc6IGJvZHkuc3ZnIHx8IGZhbHNlLFxyXG4gICAgICBiNjQ6IGJvZHkuYjY0IHx8IGZhbHNlLFxyXG4gICAgICBub0Rvd25sb2FkOiBib2R5Lm5vRG93bmxvYWQgfHwgZmFsc2UsXHJcbiAgICAgIHJlcXVlc3RJZDogdW5pcXVlSWRcclxuICAgIH07XHJcblxyXG4gICAgLy8gVGVzdCB4bGluazpocmVmIGVsZW1lbnRzIGZyb20gcGF5bG9hZCdzIFNWR1xyXG4gICAgaWYgKGJvZHkuc3ZnICYmIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmQob3B0aW9ucy5wYXlsb2FkLnN2ZykpIHtcclxuICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAnU1ZHIHBvdGVudGlhbGx5IGNvbnRhaW4gYXQgbGVhc3Qgb25lIGZvcmJpZGRlbiBVUkwgaW4geGxpbms6aHJlZiBlbGVtZW50LiBQbGVhc2UgcmV2aWV3IHRoZSBTVkcgY29udGVudCBhbmQgZW5zdXJlIHRoYXQgYWxsIHJlZmVyZW5jZWQgVVJMcyBjb21wbHkgd2l0aCBzZWN1cml0eSBwb2xpY2llcy4nLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFN0YXJ0IHRoZSBleHBvcnQgcHJvY2Vzc1xyXG4gICAgYXdhaXQgc3RhcnRFeHBvcnQob3B0aW9ucywgKGVycm9yLCBpbmZvKSA9PiB7XHJcbiAgICAgIC8vIFJlbW92ZSB0aGUgY2xvc2UgZXZlbnQgZnJvbSB0aGUgc29ja2V0XHJcbiAgICAgIHJlcXVlc3Quc29ja2V0LnJlbW92ZUFsbExpc3RlbmVycygnY2xvc2UnKTtcclxuXHJcbiAgICAgIC8vIEFmdGVyIHRoZSB3aG9sZSBleHBvcnRpbmcgcHJvY2Vzc1xyXG4gICAgICBpZiAoZGVmYXVsdE9wdGlvbnMuc2VydmVyLmJlbmNobWFya2luZykge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDUsXHJcbiAgICAgICAgICBgW2JlbmNobWFya10gUmVxdWVzdCB3aXRoIElEICR7dW5pcXVlSWR9IC0gQWZ0ZXIgdGhlIHdob2xlIGV4cG9ydGluZyBwcm9jZXNzOiAke3N0b3BDb3VudGVyKCl9bXMuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIElmIHRoZSBjb25uZWN0aW9uIHdhcyBjbG9zZWQsIGRvIG5vdGhpbmdcclxuICAgICAgaWYgKGNvbm5lY3Rpb25BYm9ydGVkKSB7XHJcbiAgICAgICAgcmV0dXJuIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW2V4cG9ydF0gVGhlIGNsaWVudCBjbG9zZWQgdGhlIGNvbm5lY3Rpb24gYmVmb3JlIHRoZSBjaGFydCBmaW5pc2hlZCBwcm9jZXNzaW5nLmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBJZiBlcnJvciwgbG9nIGl0IGFuZCBzZW5kIGl0IHRvIHRoZSBlcnJvciBtaWRkbGV3YXJlXHJcbiAgICAgIGlmIChlcnJvcikge1xyXG4gICAgICAgIHRocm93IGVycm9yO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBJZiBkYXRhIGlzIG1pc3NpbmcsIGxvZyB0aGUgbWVzc2FnZSBhbmQgc2VuZCBpdCB0byB0aGUgZXJyb3IgbWlkZGxld2FyZVxyXG4gICAgICBpZiAoIWluZm8gfHwgIWluZm8ucmVzdWx0KSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAgIGBVbmV4cGVjdGVkIHJldHVybiBmcm9tIGNoYXJ0IGdlbmVyYXRpb24uIFBsZWFzZSBjaGVjayB5b3VyIHJlcXVlc3QgZGF0YS4gRm9yIHRoZSByZXF1ZXN0IHdpdGggSUQgJHt1bmlxdWVJZH0sIHRoZSByZXN1bHQgaXMgJHtpbmZvLnJlc3VsdH0uYCxcclxuICAgICAgICAgIDQwMFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIEdldCB0aGUgdHlwZSBmcm9tIG9wdGlvbnNcclxuICAgICAgdHlwZSA9IGluZm8ub3B0aW9ucy5leHBvcnQudHlwZTtcclxuXHJcbiAgICAgIC8vIFRoZSBhZnRlciByZXF1ZXN0IGNhbGxiYWNrc1xyXG4gICAgICBkb0NhbGxiYWNrcyhhZnRlclJlcXVlc3QsIHJlcXVlc3QsIHJlc3BvbnNlLCB7IGlkLCBib2R5OiBpbmZvLnJlc3VsdCB9KTtcclxuXHJcbiAgICAgIGlmIChpbmZvLnJlc3VsdCkge1xyXG4gICAgICAgIC8vIElmIG9ubHkgYmFzZTY0IGlzIHJlcXVpcmVkLCByZXR1cm4gaXRcclxuICAgICAgICBpZiAoYm9keS5iNjQpIHtcclxuICAgICAgICAgIC8vIFNWRyBFeGNlcHRpb24gZm9yIHRoZSBIaWdoY2hhcnRzIDExLjMuMCB2ZXJzaW9uXHJcbiAgICAgICAgICBpZiAodHlwZSA9PT0gJ3BkZicgfHwgdHlwZSA9PSAnc3ZnJykge1xyXG4gICAgICAgICAgICByZXR1cm4gcmVzcG9uc2Uuc2VuZChcclxuICAgICAgICAgICAgICBCdWZmZXIuZnJvbShpbmZvLnJlc3VsdCwgJ3V0ZjgnKS50b1N0cmluZygnYmFzZTY0JylcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICByZXR1cm4gcmVzcG9uc2Uuc2VuZChpbmZvLnJlc3VsdCk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBTZXQgY29ycmVjdCBjb250ZW50IHR5cGVcclxuICAgICAgICByZXNwb25zZS5oZWFkZXIoJ0NvbnRlbnQtVHlwZScsIHJldmVyc2VkTWltZVt0eXBlXSB8fCAnaW1hZ2UvcG5nJyk7XHJcblxyXG4gICAgICAgIC8vIERlY2lkZSB3aGV0aGVyIHRvIGRvd25sb2FkIG9yIG5vdCBjaGFydCBmaWxlXHJcbiAgICAgICAgaWYgKCFib2R5Lm5vRG93bmxvYWQpIHtcclxuICAgICAgICAgIHJlc3BvbnNlLmF0dGFjaG1lbnQoXHJcbiAgICAgICAgICAgIGAke3JlcXVlc3QucGFyYW1zLmZpbGVuYW1lIHx8IHJlcXVlc3QuYm9keS5maWxlbmFtZSB8fCAnY2hhcnQnfS4ke1xyXG4gICAgICAgICAgICAgIHR5cGUgfHwgJ3BuZydcclxuICAgICAgICAgICAgfWBcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBJZiBTVkcsIHJldHVybiBwbGFpbiBjb250ZW50XHJcbiAgICAgICAgcmV0dXJuIHR5cGUgPT09ICdzdmcnXHJcbiAgICAgICAgICA/IHJlc3BvbnNlLnNlbmQoaW5mby5yZXN1bHQpXHJcbiAgICAgICAgICA6IHJlc3BvbnNlLnNlbmQoQnVmZmVyLmZyb20oaW5mby5yZXN1bHQsICdiYXNlNjQnKSk7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICBuZXh0KGVycm9yKTtcclxuICB9XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCAoYXBwKSA9PiB7XHJcbiAgLyoqXHJcbiAgICogQWRkcyB0aGUgUE9TVCAvIGEgcm91dGUgZm9yIGhhbmRsaW5nIFBPU1QgcmVxdWVzdHMgYXQgdGhlIHJvb3QgZW5kcG9pbnQuXHJcbiAgICovXHJcbiAgYXBwLnBvc3QoJy8nLCBleHBvcnRIYW5kbGVyKTtcclxuXHJcbiAgLyoqXHJcbiAgICogQWRkcyB0aGUgUE9TVCAvOmZpbGVuYW1lIGEgcm91dGUgZm9yIGhhbmRsaW5nIFBPU1QgcmVxdWVzdHMgd2l0aFxyXG4gICAqIGEgc3BlY2lmaWVkIGZpbGVuYW1lIHBhcmFtZXRlci5cclxuICAgKi9cclxuICBhcHAucG9zdCgnLzpmaWxlbmFtZScsIGV4cG9ydEhhbmRsZXIpO1xyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiBhcyBwYXRoZXIgfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCBjYWNoZSBmcm9tICcuLi8uLi9jYWNoZS5qcyc7XHJcbmltcG9ydCBwb29sIGZyb20gJy4uLy4uL3Bvb2wuanMnO1xyXG5pbXBvcnQgeyBfX2Rpcm5hbWUgfSBmcm9tICcuLi8uLi91dGlscy5qcyc7XHJcblxyXG5jb25zdCBwa2dGaWxlID0gSlNPTi5wYXJzZShyZWFkRmlsZVN5bmMocGF0aGVyKF9fZGlybmFtZSwgJ3BhY2thZ2UuanNvbicpKSk7XHJcblxyXG5jb25zdCBzZXJ2ZXJTdGFydFRpbWUgPSBuZXcgRGF0ZSgpO1xyXG5cclxuLyoqXHJcbiAqIEFkZHMgdGhlIEdFVCAvaGVhbHRoIHJvdXRlLCB3aGljaCBvdXRwdXRzIGJhc2ljIHN0YXRzIGZvciB0aGUgc2VydmVyLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgKGFwcCkgPT5cclxuICAhYXBwXHJcbiAgICA/IGZhbHNlXHJcbiAgICA6IGFwcC5nZXQoJy9oZWFsdGgnLCAocmVxdWVzdCwgcmVzcG9uc2UpID0+IHtcclxuICAgICAgICByZXNwb25zZS5zZW5kKHtcclxuICAgICAgICAgIHN0YXR1czogJ09LJyxcclxuICAgICAgICAgIGJvb3RUaW1lOiBzZXJ2ZXJTdGFydFRpbWUsXHJcbiAgICAgICAgICB1cHRpbWU6XHJcbiAgICAgICAgICAgIE1hdGguZmxvb3IoXHJcbiAgICAgICAgICAgICAgKG5ldyBEYXRlKCkuZ2V0VGltZSgpIC0gc2VydmVyU3RhcnRUaW1lLmdldFRpbWUoKSkgLyAxMDAwIC8gNjBcclxuICAgICAgICAgICAgKSArICcgbWludXRlcycsXHJcbiAgICAgICAgICB2ZXJzaW9uOiBwa2dGaWxlLnZlcnNpb24sXHJcbiAgICAgICAgICBoaWdoY2hhcnRzVmVyc2lvbjogY2FjaGUudmVyc2lvbigpLFxyXG4gICAgICAgICAgYXZlcmFnZVByb2Nlc3NpbmdUaW1lOiBwb29sLmF2ZXJhZ2VUaW1lKCksXHJcbiAgICAgICAgICBwZXJmb3JtZWRFeHBvcnRzOiBwb29sLnByb2Nlc3NlZFdvcmtDb3VudCgpLFxyXG4gICAgICAgICAgZmFpbGVkRXhwb3J0czogcG9vbC5kcm9wcGVkV29yaygpLFxyXG4gICAgICAgICAgZXhwb3J0QXR0ZW1wdHM6IHBvb2wud29ya0F0dGVtcHRzKCksXHJcbiAgICAgICAgICBzdWNlc3NSYXRpbzogKHBvb2wucHJvY2Vzc2VkV29ya0NvdW50KCkgLyBwb29sLndvcmtBdHRlbXB0cygpKSAqIDEwMCxcclxuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBpbXBvcnQvbm8tbmFtZWQtYXMtZGVmYXVsdC1tZW1iZXJcclxuICAgICAgICAgIHBvb2w6IHBvb2wuZ2V0UG9vbEluZm9KU09OKClcclxuICAgICAgICB9KTtcclxuICAgICAgfSk7XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgcHJvbWlzZXMgYXMgZnNQcm9taXNlcyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgcG9zaXggfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCBjb3JzIGZyb20gJ2NvcnMnO1xyXG5pbXBvcnQgZXhwcmVzcyBmcm9tICdleHByZXNzJztcclxuaW1wb3J0IGh0dHAgZnJvbSAnaHR0cCc7XHJcbmltcG9ydCBodHRwcyBmcm9tICdodHRwcyc7XHJcbmltcG9ydCBtdWx0ZXIgZnJvbSAnbXVsdGVyJztcclxuXHJcbmltcG9ydCBlcnJvckhhbmRsZXIgZnJvbSAnLi9lcnJvci5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHJhdGVMaW1pdCBmcm9tICcuL3JhdGVfbGltaXQuanMnO1xyXG5pbXBvcnQgeyBfX2Rpcm5hbWUgfSBmcm9tICcuLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgdlN3aXRjaFJvdXRlIGZyb20gJy4vcm91dGVzL2NoYW5nZV9oY192ZXJzaW9uLmpzJztcclxuaW1wb3J0IGV4cG9ydFJvdXRlcyBmcm9tICcuL3JvdXRlcy9leHBvcnQuanMnO1xyXG5pbXBvcnQgaGVhbHRoUm91dGUgZnJvbSAnLi9yb3V0ZXMvaGVhbHRoLmpzJztcclxuaW1wb3J0IHVpUm91dGUgZnJvbSAnLi9yb3V0ZXMvdWkuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4uL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vLyBDcmVhdGUgZXhwcmVzcyBhcHBcclxuY29uc3QgYXBwID0gZXhwcmVzcygpO1xyXG5cclxuLy8gRGlzYWJsZSB0aGUgWC1Qb3dlcmVkLUJ5IGhlYWRlclxyXG5hcHAuZGlzYWJsZSgneC1wb3dlcmVkLWJ5Jyk7XHJcblxyXG4vLyBFbmFibGUgQ09SUyBzdXBwb3J0XHJcbmFwcC51c2UoY29ycygpKTtcclxuXHJcbi8vIEVuYWJsZSBwYXJzaW5nIG9mIGZvcm0gZGF0YSAoZmlsZXMpIHdpdGggTXVsdGVyIHBhY2thZ2VcclxuY29uc3Qgc3RvcmFnZSA9IG11bHRlci5tZW1vcnlTdG9yYWdlKCk7XHJcbmNvbnN0IHVwbG9hZCA9IG11bHRlcih7XHJcbiAgc3RvcmFnZSxcclxuICBsaW1pdHM6IHtcclxuICAgIGZpZWxkU2l6ZTogNTAgKiAxMDI0ICogMTAyNFxyXG4gIH1cclxufSk7XHJcblxyXG4vLyBFbmFibGUgYm9keSBwYXJzZXJcclxuYXBwLnVzZShleHByZXNzLmpzb24oeyBsaW1pdDogNTAgKiAxMDI0ICogMTAyNCB9KSk7XHJcbmFwcC51c2UoZXhwcmVzcy51cmxlbmNvZGVkKHsgZXh0ZW5kZWQ6IHRydWUsIGxpbWl0OiA1MCAqIDEwMjQgKiAxMDI0IH0pKTtcclxuXHJcbi8vIFVzZSBvbmx5IG5vbi1maWxlIG11bHRpcGFydCBmb3JtIGZpZWxkc1xyXG5hcHAudXNlKHVwbG9hZC5ub25lKCkpO1xyXG5cclxuLyoqXHJcbiAqIEF0dGFjaCBlcnJvciBoYW5kbGVycyB0byB0aGUgc2VydmVyLlxyXG4gKlxyXG4gKiBAcGFyYW0ge2h0dHAuU2VydmVyfSBzZXJ2ZXIgLSBUaGUgSFRUUC9IVFRQUyBzZXJ2ZXIgaW5zdGFuY2UuXHJcbiAqL1xyXG5jb25zdCBhdHRhY2hFcnJvckhhbmRsZXJzID0gKHNlcnZlcikgPT4ge1xyXG4gIHNlcnZlci5vbignY2xpZW50RXJyb3InLCAoZXJyb3IpID0+IHtcclxuICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFtzZXJ2ZXJdIENsaWVudCBlcnJvcjogJHtlcnJvci5tZXNzYWdlfWApO1xyXG4gIH0pO1xyXG4gIHNlcnZlci5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcclxuICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFtzZXJ2ZXJdIFNlcnZlciBlcnJvcjogJHtlcnJvci5tZXNzYWdlfWApO1xyXG4gIH0pO1xyXG4gIHNlcnZlci5vbignY29ubmVjdGlvbicsIChzb2NrZXQpID0+IHtcclxuICAgIHNvY2tldC5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcclxuICAgICAgbG9nV2l0aFN0YWNrKDEsIGVycm9yLCBgW3NlcnZlcl0gU29ja2V0IGVycm9yOiAke2Vycm9yLm1lc3NhZ2V9YCk7XHJcbiAgICB9KTtcclxuICB9KTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgYW4gSFRUUCBzZXJ2ZXIgYmFzZWQgb24gdGhlIHByb3ZpZGVkIGNvbmZpZ3VyYXRpb24uIFRoZSBgc2VydmVyQ29uZmlnYFxyXG4gKiBvYmplY3QgY29udGFpbnMgYWxsIHNlcnZlciByZWxhdGVkIHByb3BlcnRpZXMgKHNlZSB0aGUgYHNlcnZlcmAgc2VjdGlvblxyXG4gKiBpbiB0aGUgYGxpYi9zY2hlbWFzL2NvbmZpZy5qc2AgZmlsZSBmb3IgYSByZWZlcmVuY2UpLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gc2VydmVyQ29uZmlnIC0gVGhlIHNlcnZlciBjb25maWd1cmF0aW9uIG9iamVjdC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IC0gVGhyb3dzIGFuIGVycm9yIGlmIHRoZSBzZXJ2ZXIgY2Fubm90IGJlIGNvbmZpZ3VyZWRcclxuICogYW5kIHN0YXJ0ZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc3RhcnRTZXJ2ZXIgPSBhc3luYyAoc2VydmVyQ29uZmlnKSA9PiB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIFN0b3AgaWYgbm90IGVuYWJsZWRcclxuICAgIGlmICghc2VydmVyQ29uZmlnLmVuYWJsZSkge1xyXG4gICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTGlzdGVuIEhUVFAgc2VydmVyXHJcbiAgICBpZiAoIXNlcnZlckNvbmZpZy5zc2wuZm9yY2UpIHtcclxuICAgICAgLy8gTWFpbiBzZXJ2ZXIgaW5zdGFuY2UgKEhUVFApXHJcbiAgICAgIGNvbnN0IGh0dHBTZXJ2ZXIgPSBodHRwLmNyZWF0ZVNlcnZlcihhcHApO1xyXG5cclxuICAgICAgLy8gQXR0YWNoIGVycm9yIGhhbmRsZXJzIGFuZCBsaXN0ZW4gdG8gdGhlIHNlcnZlclxyXG4gICAgICBhdHRhY2hFcnJvckhhbmRsZXJzKGh0dHBTZXJ2ZXIpO1xyXG5cclxuICAgICAgLy8gTGlzdGVuXHJcbiAgICAgIGh0dHBTZXJ2ZXIubGlzdGVuKHNlcnZlckNvbmZpZy5wb3J0LCBzZXJ2ZXJDb25maWcuaG9zdCk7XHJcblxyXG4gICAgICBsb2coXHJcbiAgICAgICAgMyxcclxuICAgICAgICBgW3NlcnZlcl0gU3RhcnRlZCBIVFRQIHNlcnZlciBvbiAke3NlcnZlckNvbmZpZy5ob3N0fToke3NlcnZlckNvbmZpZy5wb3J0fS5gXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTGlzdGVuIEhUVFBTIHNlcnZlclxyXG4gICAgaWYgKHNlcnZlckNvbmZpZy5zc2wuZW5hYmxlKSB7XHJcbiAgICAgIC8vIFNldCB1cCBhbiBTU0wgc2VydmVyIGFsc29cclxuICAgICAgbGV0IGtleSwgY2VydDtcclxuXHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgLy8gR2V0IHRoZSBTU0wga2V5XHJcbiAgICAgICAga2V5ID0gYXdhaXQgZnNQcm9taXNlcy5yZWFkRmlsZShcclxuICAgICAgICAgIHBvc2l4LmpvaW4oc2VydmVyQ29uZmlnLnNzbC5jZXJ0UGF0aCwgJ3NlcnZlci5rZXknKSxcclxuICAgICAgICAgICd1dGY4J1xyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIC8vIEdldCB0aGUgU1NMIGNlcnRpZmljYXRlXHJcbiAgICAgICAgY2VydCA9IGF3YWl0IGZzUHJvbWlzZXMucmVhZEZpbGUoXHJcbiAgICAgICAgICBwb3NpeC5qb2luKHNlcnZlckNvbmZpZy5zc2wuY2VydFBhdGgsICdzZXJ2ZXIuY3J0JyksXHJcbiAgICAgICAgICAndXRmOCdcclxuICAgICAgICApO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDIsXHJcbiAgICAgICAgICBgW3NlcnZlcl0gVW5hYmxlIHRvIGxvYWQga2V5L2NlcnRpZmljYXRlIGZyb20gdGhlICcke3NlcnZlckNvbmZpZy5zc2wuY2VydFBhdGh9JyBwYXRoLiBDb3VsZCBub3QgcnVuIHNlY3VyZWQgbGF5ZXIgc2VydmVyLmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAoa2V5ICYmIGNlcnQpIHtcclxuICAgICAgICAvLyBNYWluIHNlcnZlciBpbnN0YW5jZSAoSFRUUFMpXHJcbiAgICAgICAgY29uc3QgaHR0cHNTZXJ2ZXIgPSBodHRwcy5jcmVhdGVTZXJ2ZXIoYXBwKTtcclxuXHJcbiAgICAgICAgLy8gQXR0YWNoIGVycm9yIGhhbmRsZXJzIGFuZCBsaXN0ZW4gdG8gdGhlIHNlcnZlclxyXG4gICAgICAgIGF0dGFjaEVycm9ySGFuZGxlcnMoaHR0cHNTZXJ2ZXIpO1xyXG5cclxuICAgICAgICAvLyBMaXN0ZW5cclxuICAgICAgICBodHRwc1NlcnZlci5saXN0ZW4oc2VydmVyQ29uZmlnLnNzbC5wb3J0LCBzZXJ2ZXJDb25maWcuaG9zdCk7XHJcblxyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW3NlcnZlcl0gU3RhcnRlZCBIVFRQUyBzZXJ2ZXIgb24gJHtzZXJ2ZXJDb25maWcuaG9zdH06JHtzZXJ2ZXJDb25maWcuc3NsLnBvcnR9LmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRW5hYmxlIHRoZSByYXRlIGxpbWl0ZXIgaWYgY29uZmlnIHNheXMgc29cclxuICAgIGlmIChcclxuICAgICAgc2VydmVyQ29uZmlnLnJhdGVMaW1pdGluZyAmJlxyXG4gICAgICBzZXJ2ZXJDb25maWcucmF0ZUxpbWl0aW5nLmVuYWJsZSAmJlxyXG4gICAgICAhWzAsIE5hTl0uaW5jbHVkZXMoc2VydmVyQ29uZmlnLnJhdGVMaW1pdGluZy5tYXhSZXF1ZXN0cylcclxuICAgICkge1xyXG4gICAgICByYXRlTGltaXQoYXBwLCBzZXJ2ZXJDb25maWcucmF0ZUxpbWl0aW5nKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBTZXQgdXAgc3RhdGljIGZvbGRlcidzIHJvdXRlXHJcbiAgICBhcHAudXNlKGV4cHJlc3Muc3RhdGljKHBvc2l4LmpvaW4oX19kaXJuYW1lLCAncHVibGljJykpKTtcclxuXHJcbiAgICAvLyBTZXQgdXAgcm91dGVzXHJcbiAgICBoZWFsdGhSb3V0ZShhcHApO1xyXG4gICAgZXhwb3J0Um91dGVzKGFwcCk7XHJcbiAgICB1aVJvdXRlKGFwcCk7XHJcbiAgICB2U3dpdGNoUm91dGUoYXBwKTtcclxuXHJcbiAgICAvLyBTZXQgdXAgY2VudHJhbGl6ZWQgZXJyb3IgaGFuZGxlclxyXG4gICAgZXJyb3JIYW5kbGVyKGFwcCk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1tzZXJ2ZXJdIENvdWxkIG5vdCBjb25maWd1cmUgYW5kIHN0YXJ0IHRoZSBzZXJ2ZXIuJ1xyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEVuYWJsZSByYXRlIGxpbWl0aW5nIGZvciB0aGUgc2VydmVyLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gbGltaXRDb25maWcgLSBDb25maWd1cmF0aW9uIG9iamVjdCBmb3IgcmF0ZSBsaW1pdGluZy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBlbmFibGVSYXRlTGltaXRpbmcgPSAobGltaXRDb25maWcpID0+IHJhdGVMaW1pdChhcHAsIGxpbWl0Q29uZmlnKTtcclxuXHJcbi8qKlxyXG4gKiBHZXQgdGhlIEV4cHJlc3MgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IC0gVGhlIEV4cHJlc3MgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0RXhwcmVzcyA9ICgpID0+IGV4cHJlc3M7XHJcblxyXG4vKipcclxuICogR2V0IHRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gLSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0QXBwID0gKCkgPT4gYXBwO1xyXG5cclxuLyoqXHJcbiAqIEFwcGx5IG1pZGRsZXdhcmUocykgdG8gYSBzcGVjaWZpYyBwYXRoLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcGF0aCAtIFRoZSBwYXRoIHRvIHdoaWNoIHRoZSBtaWRkbGV3YXJlKHMpIHNob3VsZCBiZSBhcHBsaWVkLlxyXG4gKiBAcGFyYW0gey4uLkZ1bmN0aW9ufSBtaWRkbGV3YXJlcyAtIFRoZSBtaWRkbGV3YXJlIGZ1bmN0aW9ucyB0byBiZSBhcHBsaWVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHVzZSA9IChwYXRoLCAuLi5taWRkbGV3YXJlcykgPT4ge1xyXG4gIGFwcC51c2UocGF0aCwgLi4ubWlkZGxld2FyZXMpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFNldCB1cCBhIHJvdXRlIHdpdGggR0VUIG1ldGhvZCBhbmQgYXBwbHkgbWlkZGxld2FyZShzKS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBUaGUgcm91dGUgcGF0aC5cclxuICogQHBhcmFtIHsuLi5GdW5jdGlvbn0gbWlkZGxld2FyZXMgLSBUaGUgbWlkZGxld2FyZSBmdW5jdGlvbnMgdG8gYmUgYXBwbGllZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBnZXQgPSAocGF0aCwgLi4ubWlkZGxld2FyZXMpID0+IHtcclxuICBhcHAuZ2V0KHBhdGgsIC4uLm1pZGRsZXdhcmVzKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBTZXQgdXAgYSByb3V0ZSB3aXRoIFBPU1QgbWV0aG9kIGFuZCBhcHBseSBtaWRkbGV3YXJlKHMpLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcGF0aCAtIFRoZSByb3V0ZSBwYXRoLlxyXG4gKiBAcGFyYW0gey4uLkZ1bmN0aW9ufSBtaWRkbGV3YXJlcyAtIFRoZSBtaWRkbGV3YXJlIGZ1bmN0aW9ucyB0byBiZSBhcHBsaWVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHBvc3QgPSAocGF0aCwgLi4ubWlkZGxld2FyZXMpID0+IHtcclxuICBhcHAucG9zdChwYXRoLCAuLi5taWRkbGV3YXJlcyk7XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgc3RhcnRTZXJ2ZXIsXHJcbiAgZW5hYmxlUmF0ZUxpbWl0aW5nLFxyXG4gIGdldEV4cHJlc3MsXHJcbiAgZ2V0QXBwLFxyXG4gIHVzZSxcclxuICBnZXQsXHJcbiAgcG9zdFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCB7IF9fZGlybmFtZSB9IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSBHRVQgLyByb3V0ZSBmb3IgYSBVSSB3aGVuIGVuYWJsZWQgb24gdGhlIGV4cG9ydCBzZXJ2ZXIuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCAoYXBwKSA9PlxyXG4gICFhcHBcclxuICAgID8gZmFsc2VcclxuICAgIDogYXBwLmdldCgnLycsIChyZXF1ZXN0LCByZXNwb25zZSkgPT4ge1xyXG4gICAgICAgIHJlc3BvbnNlLnNlbmRGaWxlKGpvaW4oX19kaXJuYW1lLCAncHVibGljJywgJ2luZGV4Lmh0bWwnKSk7XHJcbiAgICAgIH0pO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCBjYWNoZSBmcm9tICcuLi8uLi9jYWNoZS5qcyc7XHJcblxyXG5pbXBvcnQgSHR0cEVycm9yIGZyb20gJy4uLy4uL2Vycm9ycy9IdHRwRXJyb3IuanMnO1xyXG5cclxuLyoqXHJcbiAqIEFkZHMgdGhlIFBPU1QgL2NoYW5nZV9oY192ZXJzaW9uLzpuZXdWZXJzaW9uIHJvdXRlIHRoYXQgY2FuIGJlIHV0aWxpemVkIHRvIG1vZGlmeVxyXG4gKiB0aGUgSGlnaGNoYXJ0cyB2ZXJzaW9uIG9uIHRoZSBzZXJ2ZXIuXHJcbiAqXHJcbiAqIFRPRE86IEFkZCBhdXRoIHRva2VuIGFuZCBjb25uZWN0IHRvIEFQSVxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgKGFwcCkgPT5cclxuICAhYXBwXHJcbiAgICA/IGZhbHNlXHJcbiAgICA6IGFwcC5wb3N0KFxyXG4gICAgICAgICcvdmVyc2lvbi9jaGFuZ2UvOm5ld1ZlcnNpb24nLFxyXG4gICAgICAgIGFzeW5jIChyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkgPT4ge1xyXG4gICAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgY29uc3QgYWRtaW5Ub2tlbiA9IHByb2Nlc3MuZW52LkhJR0hDSEFSVFNfQURNSU5fVE9LRU47XHJcblxyXG4gICAgICAgICAgICAvLyBDaGVjayB0aGUgZXhpc3RlbmNlIG9mIHRoZSB0b2tlblxyXG4gICAgICAgICAgICBpZiAoIWFkbWluVG9rZW4gfHwgIWFkbWluVG9rZW4ubGVuZ3RoKSB7XHJcbiAgICAgICAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAgICAgICAgICdUaGUgc2VydmVyIGlzIG5vdCBjb25maWd1cmVkIHRvIHBlcmZvcm0gcnVuLXRpbWUgdmVyc2lvbiBjaGFuZ2VzOiBISUdIQ0hBUlRTX0FETUlOX1RPS0VOIGlzIG5vdCBzZXQuJyxcclxuICAgICAgICAgICAgICAgIDQwMVxyXG4gICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIC8vIENoZWNrIGlmIHRoZSBoYy1hdXRoIGhlYWRlciBjb250YWluIGEgY29ycmVjdCB0b2tlblxyXG4gICAgICAgICAgICBjb25zdCB0b2tlbiA9IHJlcXVlc3QuZ2V0KCdoYy1hdXRoJyk7XHJcbiAgICAgICAgICAgIGlmICghdG9rZW4gfHwgdG9rZW4gIT09IGFkbWluVG9rZW4pIHtcclxuICAgICAgICAgICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgICAgICAgICAgJ0ludmFsaWQgb3IgbWlzc2luZyB0b2tlbjogU2V0IHRoZSB0b2tlbiBpbiB0aGUgaGMtYXV0aCBoZWFkZXIuJyxcclxuICAgICAgICAgICAgICAgIDQwMVxyXG4gICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIC8vIENvbXBhcmUgdmVyc2lvbnNcclxuICAgICAgICAgICAgY29uc3QgbmV3VmVyc2lvbiA9IHJlcXVlc3QucGFyYW1zLm5ld1ZlcnNpb247XHJcbiAgICAgICAgICAgIGlmIChuZXdWZXJzaW9uKSB7XHJcbiAgICAgICAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBpbXBvcnQvbm8tbmFtZWQtYXMtZGVmYXVsdC1tZW1iZXJcclxuICAgICAgICAgICAgICAgIGF3YWl0IGNhY2hlLnVwZGF0ZVZlcnNpb24obmV3VmVyc2lvbik7XHJcbiAgICAgICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgICAgICAgICAgIGBWZXJzaW9uIGNoYW5nZTogJHtlcnJvci5tZXNzYWdlfWAsXHJcbiAgICAgICAgICAgICAgICAgIGVycm9yLnN0YXR1c0NvZGVcclxuICAgICAgICAgICAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgLy8gU3VjY2Vzc1xyXG4gICAgICAgICAgICAgIHJlc3BvbnNlLnN0YXR1cygyMDApLnNlbmQoe1xyXG4gICAgICAgICAgICAgICAgc3RhdHVzQ29kZTogMjAwLFxyXG4gICAgICAgICAgICAgICAgdmVyc2lvbjogY2FjaGUudmVyc2lvbigpLFxyXG4gICAgICAgICAgICAgICAgbWVzc2FnZTogYFN1Y2Nlc3NmdWxseSB1cGRhdGVkIEhpZ2hjaGFydHMgdG8gdmVyc2lvbjogJHtuZXdWZXJzaW9ufS5gXHJcbiAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgLy8gTm8gdmVyc2lvbiBzcGVjaWZpZWRcclxuICAgICAgICAgICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKCdObyBuZXcgdmVyc2lvbiBzdXBwbGllZC4nLCA0MDApO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICBuZXh0KGVycm9yKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICk7XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0ICdjb2xvcnMnO1xyXG5pbXBvcnQgZG90ZW52IGZyb20gJ2RvdGVudic7XHJcblxyXG5pbXBvcnQgeyBjaGVja0FuZFVwZGF0ZUNhY2hlIH0gZnJvbSAnLi9jYWNoZS5qcyc7XHJcbmltcG9ydCB7XHJcbiAgYmF0Y2hFeHBvcnQsXHJcbiAgc2V0QWxsb3dDb2RlRXhlY3V0aW9uLFxyXG4gIHNpbmdsZUV4cG9ydCxcclxuICBzdGFydEV4cG9ydFxyXG59IGZyb20gJy4vY2hhcnQuanMnO1xyXG5pbXBvcnQgeyBtYXBUb05ld0NvbmZpZywgbWFudWFsQ29uZmlnLCBzZXRPcHRpb25zIH0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQge1xyXG4gIGluaXRMb2dnaW5nLFxyXG4gIGxvZyxcclxuICBsb2dXaXRoU3RhY2ssXHJcbiAgc2V0TG9nTGV2ZWwsXHJcbiAgZW5hYmxlRmlsZUxvZ2dpbmdcclxufSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IGluaXRQb29sLCBraWxsUG9vbCB9IGZyb20gJy4vcG9vbC5qcyc7XHJcbmltcG9ydCBzZXJ2ZXIsIHsgc3RhcnRTZXJ2ZXIgfSBmcm9tICcuL3NlcnZlci9zZXJ2ZXIuanMnO1xyXG5pbXBvcnQgeyBwcmludExvZ28sIHByaW50VXNhZ2UgfSBmcm9tICcuL3V0aWxzLmpzJztcclxuXHJcbi8vIExvYWQgLmVudiBpbnRvIGVudmlyb25tZW50IHZhcmlhYmxlc1xyXG5kb3RlbnYuY29uZmlnKCk7XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgdGhlIGV4cG9ydCBwcm9jZXNzLiBUYXNrcyBzdWNoIGFzIGNvbmZpZ3VyaW5nIGxvZ2dpbmcsIGNoZWNraW5nXHJcbiAqIGNhY2hlIGFuZCBzb3VyY2VzLCBhbmQgaW5pdGlhbGl6aW5nIHRoZSBwb29sIG9mIHJlc291cmNlcyBoYXBwZW4gZHVyaW5nXHJcbiAqIHRoaXMgc3RhZ2UuIEZ1bmN0aW9uIHRoYXQgaXMgcmVxdWlyZWQgdG8gYmUgY2FsbGVkIGJlZm9yZSB0cnlpbmcgdG8gZXhwb3J0IGNoYXJ0cyBvciBzZXR0aW5nIGEgc2VydmVyLiBUaGUgYG9wdGlvbnNgIGlzIGFuIG9iamVjdCB0aGF0IGNvbnRhaW5zIGFsbCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIEFsbCBleHBvcnQgb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIHVwZGF0ZWQgZXhwb3J0IG9wdGlvbnMuXHJcbiAqL1xyXG5jb25zdCBpbml0RXhwb3J0ID0gYXN5bmMgKG9wdGlvbnMpID0+IHtcclxuICAvLyBTZXQgdGhlIGFsbG93Q29kZUV4ZWN1dGlvbiBwZXIgZXhwb3J0IG1vZHVsZSBzY29wZVxyXG4gIHNldEFsbG93Q29kZUV4ZWN1dGlvbihcclxuICAgIG9wdGlvbnMuY3VzdG9tTG9naWMgJiYgb3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0NvZGVFeGVjdXRpb25cclxuICApO1xyXG5cclxuICAvLyBJbml0IHRoZSBsb2dnaW5nXHJcbiAgaW5pdExvZ2dpbmcob3B0aW9ucy5sb2dnaW5nKTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgY2FjaGUgbmVlZHMgdG8gYmUgdXBkYXRlZFxyXG4gIGF3YWl0IGNoZWNrQW5kVXBkYXRlQ2FjaGUob3B0aW9ucy5oaWdoY2hhcnRzIHx8IHsgdmVyc2lvbjogJ2xhdGVzdCcgfSk7XHJcblxyXG4gIC8vIEluaXQgdGhlIHBvb2xcclxuICBhd2FpdCBpbml0UG9vbCh7XHJcbiAgICBwb29sOiBvcHRpb25zLnBvb2wgfHwge1xyXG4gICAgICBtaW5Xb3JrZXJzOiAxLFxyXG4gICAgICBtYXhXb3JrZXJzOiAxXHJcbiAgICB9LFxyXG4gICAgcHVwcGV0ZWVyQXJnczogb3B0aW9ucy5wdXBwZXRlZXI/LmFyZ3MgfHwgW11cclxuICB9KTtcclxuXHJcbiAgLy8gUmV0dXJuIHVwZGF0ZWQgb3B0aW9uc1xyXG4gIHJldHVybiBvcHRpb25zO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIC8vIFNlcnZlclxyXG4gIHNlcnZlcixcclxuICBzdGFydFNlcnZlcixcclxuICBzZXRPcHRpb25zLFxyXG5cclxuICAvLyBFeHBvcnRpbmdcclxuICBpbml0RXhwb3J0LFxyXG4gIHNpbmdsZUV4cG9ydCxcclxuICBiYXRjaEV4cG9ydCxcclxuICBzdGFydEV4cG9ydCxcclxuICBraWxsUG9vbCxcclxuXHJcbiAgLy8gTG9nc1xyXG4gIGxvZyxcclxuICBsb2dXaXRoU3RhY2ssXHJcbiAgc2V0TG9nTGV2ZWwsXHJcbiAgZW5hYmxlRmlsZUxvZ2dpbmcsXHJcblxyXG4gIC8vIFV0aWxzXHJcbiAgbWFwVG9OZXdDb25maWcsXHJcbiAgbWFudWFsQ29uZmlnLFxyXG4gIHByaW50TG9nbyxcclxuICBwcmludFVzYWdlXHJcbn07XHJcbiJdLCJuYW1lcyI6WyJhc3luYyIsImZldGNoIiwidXJsIiwicmVxdWVzdE9wdGlvbnMiLCJQcm9taXNlIiwicmVzb2x2ZSIsInJlamVjdCIsInByb3RvY29sIiwic3RhcnRzV2l0aCIsImh0dHBzIiwiaHR0cCIsImdldFByb3RvY29sIiwiZ2V0IiwicmVzIiwiZGF0YSIsIm9uIiwiY2h1bmsiLCJ0ZXh0IiwiZXJyb3IiLCJkZWZhdWx0Q29uZmlnIiwicHVwcGV0ZWVyIiwiYXJncyIsInZhbHVlIiwidHlwZSIsImRlc2NyaXB0aW9uIiwiaGlnaGNoYXJ0cyIsInZlcnNpb24iLCJlbnZMaW5rIiwiY2RuVVJMIiwiY29yZVNjcmlwdHMiLCJtb2R1bGVzIiwiaW5kaWNhdG9ycyIsInNjcmlwdHMiLCJmb3JjZUZldGNoIiwiY2FjaGVQYXRoIiwiZXhwb3J0IiwiaW5maWxlIiwiaW5zdHIiLCJvcHRpb25zIiwib3V0ZmlsZSIsImNvbnN0ciIsImRlZmF1bHRIZWlnaHQiLCJkZWZhdWx0V2lkdGgiLCJkZWZhdWx0U2NhbGUiLCJoZWlnaHQiLCJ3aWR0aCIsInNjYWxlIiwiZ2xvYmFsT3B0aW9ucyIsInRoZW1lT3B0aW9ucyIsImJhdGNoIiwicmFzdGVyaXphdGlvblRpbWVvdXQiLCJjdXN0b21Mb2dpYyIsImFsbG93Q29kZUV4ZWN1dGlvbiIsImFsbG93RmlsZVJlc291cmNlcyIsImN1c3RvbUNvZGUiLCJjYWxsYmFjayIsInJlc291cmNlcyIsImxvYWRDb25maWciLCJsZWdhY3lOYW1lIiwiY3JlYXRlQ29uZmlnIiwic2VydmVyIiwiZW5hYmxlIiwiY2xpTmFtZSIsImhvc3QiLCJwb3J0IiwiYmVuY2htYXJraW5nIiwic3NsIiwiZm9yY2UiLCJjZXJ0UGF0aCIsInJhdGVMaW1pdGluZyIsIm1heFJlcXVlc3RzIiwid2luZG93IiwiZGVsYXkiLCJ0cnVzdFByb3h5Iiwic2tpcEtleSIsInNraXBUb2tlbiIsInBvb2wiLCJtaW5Xb3JrZXJzIiwibWF4V29ya2VycyIsIndvcmtMaW1pdCIsImFjcXVpcmVUaW1lb3V0IiwiY3JlYXRlVGltZW91dCIsImRlc3Ryb3lUaW1lb3V0IiwiaWRsZVRpbWVvdXQiLCJjcmVhdGVSZXRyeUludGVydmFsIiwicmVhcGVySW50ZXJ2YWwiLCJsaXN0ZW5Ub1Byb2Nlc3NFeGl0cyIsImxvZ2dpbmciLCJsZXZlbCIsImZpbGUiLCJkZXN0IiwidWkiLCJyb3V0ZSIsIm90aGVyIiwibm9Mb2dvIiwicHJvbXB0c0NvbmZpZyIsIm5hbWUiLCJtZXNzYWdlIiwiaW5pdGlhbCIsImpvaW4iLCJzZXBhcmF0b3IiLCJpbnN0cnVjdGlvbnMiLCJjaG9pY2VzIiwiaGludCIsIm1pbiIsIm1heCIsInJvdW5kIiwiYWJzb2x1dGVQcm9wcyIsIm5lc3RlZEFyZ3MiLCJjcmVhdGVOZXN0ZWRBcmdzIiwib2JqIiwicHJvcENoYWluIiwiT2JqZWN0Iiwia2V5cyIsImZvckVhY2giLCJrIiwiaW5jbHVkZXMiLCJlbnRyeSIsInN1YnN0cmluZyIsInVuZGVmaW5lZCIsImNvbG9ycyIsInRvQ29uc29sZSIsInRvRmlsZSIsInBhdGhDcmVhdGVkIiwibGV2ZWxzRGVzYyIsInRpdGxlIiwiY29sb3IiLCJsaXN0ZW5lcnMiLCJrZXkiLCJvcHRpb24iLCJlbnRyaWVzIiwibG9nVG9GaWxlIiwidGV4dHMiLCJwcmVmaXgiLCJleGlzdHNTeW5jIiwibWtkaXJTeW5jIiwiYXBwZW5kRmlsZSIsImNvbmNhdCIsImNvbnNvbGUiLCJsb2ciLCJuZXdMZXZlbCIsImxlbmd0aCIsIkRhdGUiLCJ0b1N0cmluZyIsInNwbGl0IiwidHJpbSIsImZuIiwiYXBwbHkiLCJsb2dXaXRoU3RhY2siLCJjdXN0b21NZXNzYWdlIiwibWFpbk1lc3NhZ2UiLCJzdGFja01lc3NhZ2UiLCJzdGFjayIsInNsaWNlIiwic2V0TG9nTGV2ZWwiLCJlbmFibGVGaWxlTG9nZ2luZyIsImxvZ0Rlc3QiLCJsb2dGaWxlIiwiZW5kc1dpdGgiLCJfX2Rpcm5hbWUiLCJmaWxlVVJMVG9QYXRoIiwiVVJMIiwiZG9jdW1lbnQiLCJyZXF1aXJlIiwicGF0aFRvRmlsZVVSTCIsIl9fZmlsZW5hbWUiLCJocmVmIiwiX2RvY3VtZW50Q3VycmVudFNjcmlwdCIsInNyYyIsImJhc2VVUkkiLCJmaXhUeXBlIiwiZm9ybWF0cyIsIm91dFR5cGUiLCJwb3AiLCJmaW5kIiwidCIsImhhbmRsZVJlc291cmNlcyIsImFsbG93ZWRQcm9wcyIsImhhbmRsZWRSZXNvdXJjZXMiLCJjb3JyZWN0UmVzb3VyY2VzIiwiaXNDb3JyZWN0SlNPTiIsInJlYWRGaWxlU3luYyIsImZpbGVzIiwicHJvcE5hbWUiLCJtYXAiLCJpdGVtIiwicGFyc2VkRGF0YSIsIkpTT04iLCJwYXJzZSIsInN0cmluZ2lmeSIsImRlZXBDb3B5IiwiY29weSIsIkFycmF5IiwiaXNBcnJheSIsInByb3RvdHlwZSIsImhhc093blByb3BlcnR5IiwiY2FsbCIsIm9wdGlvbnNTdHJpbmdpZnkiLCJhbGxvd0Z1bmN0aW9ucyIsInJlcGxhY2VBbGwiLCJwcmludFVzYWdlIiwiYm9sZCIsInllbGxvdyIsImN5Y2xlQ2F0ZWdvcmllcyIsImRlc2NOYW1lIiwiZ3JlZW4iLCJpIiwiYmx1ZSIsImNhdGVnb3J5IiwidG9VcHBlckNhc2UiLCJyZWQiLCJ0b0Jvb2xlYW4iLCJ3cmFwQXJvdW5kIiwicmVwbGFjZSIsIm1lYXN1cmVUaW1lIiwic3RhcnQiLCJwcm9jZXNzIiwiaHJ0aW1lIiwiYmlnaW50IiwiTnVtYmVyIiwiRXhwb3J0RXJyb3IiLCJFcnJvciIsImNvbnN0cnVjdG9yIiwic3VwZXIiLCJ0aGlzIiwic2V0RXJyb3IiLCJzdGF0dXNDb2RlIiwiY2FjaGUiLCJhY3RpdmVNYW5pZmVzdCIsInNvdXJjZXMiLCJoY1ZlcnNpb24iLCJhcHBsaWVkQ29uZmlnIiwiZXh0cmFjdFZlcnNpb24iLCJpbmRleE9mIiwiZmV0Y2hBbmRQcm9jZXNzU2NyaXB0Iiwic2NyaXB0IiwicHJveHlBZ2VudCIsImZldGNoZWRNb2R1bGVzIiwic2hvdWxkVGhyb3dFcnJvciIsImFnZW50IiwidGltZW91dCIsImVudiIsInJlc3BvbnNlIiwidXBkYXRlQ2FjaGUiLCJjb25maWciLCJzb3VyY2VQYXRoIiwiY3VzdG9tU2NyaXB0cyIsInByb3h5SG9zdCIsInByb3h5UG9ydCIsIkh0dHBzUHJveHlBZ2VudCIsIm1vZHVsZVNjcmlwdHMiLCJhbGxGZXRjaFByb21pc2VzIiwiYWxsIiwiZmV0Y2hTY3JpcHRzIiwiYyIsIm0iLCJ3cml0ZUZpbGVTeW5jIiwiY2hlY2tBbmRVcGRhdGVDYWNoZSIsIm1hbmlmZXN0UGF0aCIsInJlcXVlc3RVcGRhdGUiLCJtYW5pZmVzdCIsIm1vZHVsZU1hcCIsIm51bWJlck9mTW9kdWxlcyIsInNvbWUiLCJtb2R1bGVOYW1lIiwibmV3TWFuaWZlc3QiLCJzYXZlQ29uZmlnVG9NYW5pZmVzdCIsImdldENhY2hlUGF0aCIsImNhY2hlJDEiLCJuZXdWZXJzaW9uIiwiYXNzaWduIiwiZ2VuZXJhbE9wdGlvbnMiLCJnZXRPcHRpb25zIiwibWVyZ2VDb25maWdPcHRpb25zIiwibmV3T3B0aW9ucyIsIm1lcmdlZE9wdGlvbnMiLCJ1cGRhdGVEZWZhdWx0Q29uZmlnIiwiY29uZmlnT2JqIiwiY3VzdG9tT2JqIiwiY3VzdG9tVmFsdWUiLCJudW1FbnZWYWwiLCJlbCIsImluaXRPcHRpb25zIiwiaXRlbXMiLCJyZWN1cnNpdmVQcm9wcyIsIm9iamVjdFRvVXBkYXRlIiwibmVzdGVkTmFtZXMiLCJzaGlmdCIsIlJBTkRPTV9QSUQiLCJyYW5kb21CeXRlcyIsIlBVUFBFVEVFUl9ESVIiLCJwYXRoIiwibWluaW1hbEFyZ3MiLCJ0ZW1wbGF0ZSIsImZzIiwiYnJvd3NlciIsInNldFBhZ2VDb250ZW50IiwicGFnZSIsInNldENvbnRlbnQiLCJhZGRTY3JpcHRUYWciLCJldmFsdWF0ZSIsInNldHVwSGlnaGNoYXJ0cyIsIiRldmFsIiwiZWxlbWVudCIsImVycm9yTWVzc2FnZSIsIl9kaXNwbGF5RXJyb3JzIiwiaW5uZXJIVE1MIiwiY2xlYXJQYWdlIiwiaGFyZFJlc2V0IiwiZ290byIsImJvZHkiLCJuZXdQYWdlIiwic2V0Q2FjaGVFbmFibGVkIiwiY2xvc2UiLCJpc0Nvbm5lY3RlZCIsIl9fYmFzZWRpciIsInNldEFzQ29uZmlnIiwiY2hhcnQiLCJ0cmlnZ2VyRXhwb3J0IiwicHVwcGV0ZWVyRXhwb3J0IiwiaW5qZWN0ZWRSZXNvdXJjZXMiLCJjbGVhckluamVjdGVkIiwiZGlzcG9zZSIsInNjcmlwdHNUb1JlbW92ZSIsImdldEVsZW1lbnRzQnlUYWdOYW1lIiwic3R5bGVzVG9SZW1vdmUiLCJsaW5rc1RvUmVtb3ZlIiwicmVtb3ZlIiwiZXhwb3J0T3B0aW9ucyIsInJlcXVlc3RBbmltYXRpb25GcmFtZSIsImRpc3BsYXlFcnJvcnMiLCJkZWJ1Z2dlciIsImlzU1ZHIiwiZCIsInN2Z1RlbXBsYXRlIiwic3RySW5qIiwianMiLCJwdXNoIiwiY29udGVudCIsImlzTG9jYWwiLCJjc3MiLCJjc3NJbXBvcnRzIiwibWF0Y2giLCJjc3NJbXBvcnRQYXRoIiwiYWRkU3R5bGVUYWciLCJzaXplIiwiY2hhcnRIZWlnaHQiLCJiYXNlVmFsIiwiY2hhcnRXaWR0aCIsInBhcnNlRmxvYXQiLCJIaWdoY2hhcnRzIiwiY2hhcnRzIiwidmlld3BvcnRIZWlnaHQiLCJNYXRoIiwiY2VpbCIsInZpZXdwb3J0V2lkdGgiLCJzZXRWaWV3cG9ydCIsImRldmljZVNjYWxlRmFjdG9yIiwiem9vbUNhbGxiYWNrIiwic3R5bGUiLCJ6b29tIiwibWFyZ2luIiwieCIsInkiLCJnZXRCb3VuZGluZ0NsaWVudFJlY3QiLCJ0cnVuYyIsImdldENsaXBSZWdpb24iLCJvdXRlckhUTUwiLCJjcmVhdGVTVkciLCJlbmNvZGluZyIsImNsaXAiLCJyYWNlIiwic2NyZWVuc2hvdCIsIm9taXRCYWNrZ3JvdW5kIiwiX3Jlc29sdmUiLCJzZXRUaW1lb3V0IiwiY3JlYXRlSW1hZ2UiLCJwZGYiLCJjcmVhdGVQREYiLCJvbGRDaGFydHMiLCJvbGRDaGFydCIsImRlc3Ryb3kiLCJwdXBwZXRlZXJBcmdzIiwicGVyZm9ybWVkRXhwb3J0cyIsImV4cG9ydEF0dGVtcHRzIiwidGltZVNwZW50IiwiZHJvcHBlZEV4cG9ydHMiLCJzcGVudEF2ZXJhZ2UiLCJwb29sQ29uZmlnIiwiZmFjdG9yeSIsImNyZWF0ZSIsImlkIiwidXVpZCIsInN0YXJ0RGF0ZSIsImdldFRpbWUiLCJicm93c2VyTmV3UGFnZSIsImlzQ2xvc2VkIiwid29ya0NvdW50IiwicmFuZG9tIiwidmFsaWRhdGUiLCJ3b3JrZXJIYW5kbGUiLCJpbml0UG9vbCIsImNvZGUiLCJraWxsUG9vbCIsImV4aXQiLCJhbGxBcmdzIiwidHJ5Q291bnQiLCJvcGVuIiwibGF1bmNoIiwiaGVhZGxlc3MiLCJ1c2VyRGF0YURpciIsImNyZWF0ZUJyb3dzZXIiLCJwYXJzZUludCIsIlBvb2wiLCJhY3F1aXJlVGltZW91dE1pbGxpcyIsImNyZWF0ZVRpbWVvdXRNaWxsaXMiLCJkZXN0cm95VGltZW91dE1pbGxpcyIsImlkbGVUaW1lb3V0TWlsbGlzIiwiY3JlYXRlUmV0cnlJbnRlcnZhbE1pbGxpcyIsInJlYXBJbnRlcnZhbE1pbGxpcyIsInByb3BhZ2F0ZUNyZWF0ZUVycm9yIiwicmVzb3VyY2UiLCJldmVudElkIiwiaW5pdGlhbFJlc291cmNlcyIsImFjcXVpcmUiLCJwcm9taXNlIiwicmVsZWFzZSIsImJyb3dzZXJDbG9zZSIsImRlc3Ryb3llZCIsInBvc3RXb3JrIiwiZ2V0UG9vbEluZm8iLCJhY3F1aXJlQ291bnRlciIsInBheWxvYWQiLCJyZXF1ZXN0SWQiLCJ3b3JrU3RhcnQiLCJleHBvcnRDb3VudGVyIiwicmVzdWx0IiwiZXhwb3J0VGltZSIsIm51bUZyZWUiLCJudW1Vc2VkIiwibnVtUGVuZGluZ0FjcXVpcmVzIiwicG9vbCQxIiwiYXZhaWxhYmxlIiwiaW5Vc2UiLCJwZW5kaW5nQWNxdWlyZSIsInN0YXJ0RXhwb3J0Iiwic2V0dGluZ3MiLCJlbmRDYWxsYmFjayIsInN2ZyIsImluaXRFeHBvcnRTZXR0aW5ncyIsImV4cG9ydEFzU3RyaW5nIiwiZG9TdHJhaWdodEluamVjdCIsImRvRXhwb3J0IiwiZmluZENoYXJ0U2l6ZSIsImV4cG9ydGluZyIsInByZWNpc2lvbiIsIm11bHRpcGxpZXIiLCJwb3ciLCJyb3VuZE51bWJlciIsInNvdXJjZUhlaWdodCIsInNvdXJjZVdpZHRoIiwicGFyYW0iLCJjaGFydEpzb24iLCJjdXN0b21Mb2dpY09wdGlvbnMiLCJhbGxvd0NvZGVFeGVjdXRpb25TY29wZWQiLCJlbmFibGVkIiwib3B0aW9uc05hbWUiLCJzdHJpbmdUb0V4cG9ydCIsImNoYXJ0SlNPTiIsImxvZ0Vycm9yTWlkZGxld2FyZSIsInJlcSIsIm5leHQiLCJOT0RFX0VOViIsInJldHVybkVycm9yTWlkZGxld2FyZSIsInN0Q29kZSIsInN0YXR1cyIsImpzb24iLCJyYXRlTGltaXQiLCJhcHAiLCJsaW1pdENvbmZpZyIsIm1zZyIsInJhdGVPcHRpb25zIiwibGltaXRlciIsIndpbmRvd01zIiwiZGVsYXlNcyIsImhhbmRsZXIiLCJyZXF1ZXN0IiwiZm9ybWF0Iiwic2VuZCIsImRlZmF1bHQiLCJza2lwIiwicXVlcnkiLCJhY2Nlc3NfdG9rZW4iLCJ1c2UiLCJIdHRwRXJyb3IiLCJzZXRTdGF0dXMiLCJyZXZlcnNlZE1pbWUiLCJwbmciLCJqcGVnIiwiZ2lmIiwicmVxdWVzdHNDb3VudGVyIiwiYmVmb3JlUmVxdWVzdCIsImFmdGVyUmVxdWVzdCIsImRvQ2FsbGJhY2tzIiwiY2FsbGJhY2tzIiwidW5pcXVlSWQiLCJjYWxsUmVzcG9uc2UiLCJleHBvcnRIYW5kbGVyIiwic3RvcENvdW50ZXIiLCJkZWZhdWx0T3B0aW9ucyIsImhlYWRlcnMiLCJjb25uZWN0aW9uIiwicmVtb3RlQWRkcmVzcyIsImNvbm5lY3Rpb25BYm9ydGVkIiwic29ja2V0IiwidG9Mb3dlckNhc2UiLCJzdWJzdHIiLCJiNjQiLCJub0Rvd25sb2FkIiwiaXBSZWdFeCIsImlzUHJpdmF0ZVJhbmdlVXJsRm91bmQiLCJpbmZvIiwicmVtb3ZlQWxsTGlzdGVuZXJzIiwiQnVmZmVyIiwiZnJvbSIsImhlYWRlciIsImF0dGFjaG1lbnQiLCJwYXJhbXMiLCJmaWxlbmFtZSIsInBrZ0ZpbGUiLCJwYXRoZXIiLCJzZXJ2ZXJTdGFydFRpbWUiLCJleHByZXNzIiwiZGlzYWJsZSIsImNvcnMiLCJzdG9yYWdlIiwibXVsdGVyIiwibWVtb3J5U3RvcmFnZSIsInVwbG9hZCIsImxpbWl0cyIsImZpZWxkU2l6ZSIsImxpbWl0IiwidXJsZW5jb2RlZCIsImV4dGVuZGVkIiwibm9uZSIsImF0dGFjaEVycm9ySGFuZGxlcnMiLCJzdGFydFNlcnZlciIsInNlcnZlckNvbmZpZyIsImh0dHBTZXJ2ZXIiLCJjcmVhdGVTZXJ2ZXIiLCJsaXN0ZW4iLCJjZXJ0IiwiZnNQcm9taXNlcyIsInJlYWRGaWxlIiwicG9zaXgiLCJodHRwc1NlcnZlciIsIk5hTiIsInN0YXRpYyIsImJvb3RUaW1lIiwidXB0aW1lIiwiZmxvb3IiLCJoaWdoY2hhcnRzVmVyc2lvbiIsImF2ZXJhZ2VQcm9jZXNzaW5nVGltZSIsImZhaWxlZEV4cG9ydHMiLCJzdWNlc3NSYXRpbyIsImhlYWx0aFJvdXRlIiwicG9zdCIsImV4cG9ydFJvdXRlcyIsInNlbmRGaWxlIiwidWlSb3V0ZSIsImFkbWluVG9rZW4iLCJISUdIQ0hBUlRTX0FETUlOX1RPS0VOIiwidG9rZW4iLCJ2U3dpdGNoUm91dGUiLCJlcnJvckhhbmRsZXIiLCJlbmFibGVSYXRlTGltaXRpbmciLCJnZXRFeHByZXNzIiwiZ2V0QXBwIiwibWlkZGxld2FyZXMiLCJkb3RlbnYiLCJpbmRleCIsInNldE9wdGlvbnMiLCJ1c2VyT3B0aW9ucyIsImNvbmZpZ0luZGV4IiwiZmluZEluZGV4IiwiYXJnIiwiZmlsZU5hbWUiLCJsb2FkQ29uZmlnRmlsZSIsInNob3dVc2FnZSIsInByb3BlcnRpZXNDaGFpbiIsImFyZ3VtZW50VHlwZSIsInJlZHVjZSIsInByb3AiLCJwYWlyQXJndW1lbnRWYWx1ZSIsImluaXRFeHBvcnQiLCJpbml0TG9nZ2luZyIsInNpbmdsZUV4cG9ydCIsImJhdGNoRXhwb3J0IiwiYmF0Y2hGdW5jdGlvbnMiLCJwYWlyIiwibWFwVG9OZXdDb25maWciLCJvbGRPcHRpb25zIiwibWFudWFsQ29uZmlnIiwiY29uZmlnRmlsZU5hbWUiLCJjb25maWdGaWxlIiwiY2hvaWNlIiwicHJvbXB0cyIsIm9uU3VibWl0IiwicCIsImNhdGVnb3JpZXMiLCJxdWVzdGlvbnNDb3VudGVyIiwiYWxsUXVlc3Rpb25zIiwic2VjdGlvbiIsInByb21wdCIsImFuc3dlciIsIm1vZHVsZSIsInByb21pc2VzIiwid3JpdGVGaWxlIiwicHJpbnRMb2dvIiwicGFja2FnZVZlcnNpb24iXSwibWFwcGluZ3MiOiJrdEJBeUJBQSxlQUFlQyxFQUFNQyxFQUFLQyxFQUFpQixJQUN6QyxPQUFPLElBQUlDLFNBQVEsQ0FBQ0MsRUFBU0MsS0FDM0IsTUFBTUMsRUFiVSxDQUFDTCxHQUFTQSxFQUFJTSxXQUFXLFNBQVdDLEVBQVFDLEVBYTNDQyxDQUFZVCxHQUU3QkssRUFDR0ssSUFBSVYsRUFBS0MsR0FBaUJVLElBQ3pCLElBQUlDLEVBQU8sR0FHWEQsRUFBSUUsR0FBRyxRQUFTQyxJQUNkRixHQUFRRSxDQUFLLElBSWZILEVBQUlFLEdBQUcsT0FBTyxLQUNQRCxHQUNIUixFQUFPLHFDQUdUTyxFQUFJSSxLQUFPSCxFQUNYVCxFQUFRUSxFQUFJLEdBQ1osSUFFSEUsR0FBRyxTQUFVRyxJQUNaWixFQUFPWSxFQUFNLEdBQ2IsR0FFUixDQ3BDTyxNQUFNQyxFQUFnQixDQUMzQkMsVUFBVyxDQUNUQyxLQUFNLENBQ0pDLE1BQU8sR0FDUEMsS0FBTSxXQUNOQyxZQUFhLDBDQUdqQkMsV0FBWSxDQUNWQyxRQUFTLENBQ1BKLE1BQU8sU0FDUEssUUFBUyxxQkFDVEosS0FBTSxTQUNOQyxZQUFhLHNDQUVmSSxPQUFRLENBQ05OLE1BQU8sK0JBQ1BLLFFBQVMscUJBQ1RKLEtBQU0sU0FDTkMsWUFBYSxrREFFZkssWUFBYSxDQUNYRixRQUFTLDBCQUNUTCxNQUFPLENBQUMsYUFBYyxrQkFBbUIsaUJBQ3pDQyxLQUFNLFdBQ05DLFlBQWEseUNBRWZNLFFBQVMsQ0FDUEgsUUFBUyxxQkFDVEwsTUFBTyxDQUNMLFFBQ0EsTUFDQSxRQUNBLFlBQ0EsY0FDQSx1QkFDQSxnQkFDQSx1QkFDQSxlQUNBLFFBQ0EsT0FDQSxhQUNBLG1CQUNBLGVBQ0EsY0FDQSxVQUNBLFVBQ0EsY0FDQSxXQUNBLFVBQ0EsWUFDQSxjQUNBLFlBQ0Esc0JBQ0EsU0FDQSxT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 +"use strict";require("colors");var e=require("dotenv"),t=require("fs"),r=require("path"),i=require("https-proxy-agent"),o=require("http"),n=require("https"),s=require("url"),a=require("prompts"),l=require("tarn"),c=require("uuid"),p=require("node:path"),u=require("puppeteer"),h=require("node:crypto"),d=require("cors"),g=require("express"),m=require("multer"),f=require("express-rate-limit"),y="undefined"!=typeof document?document.currentScript:null;function v(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=v(s);async function b(e,t={}){return new Promise(((r,i)=>{const s=(e=>e.startsWith("https")?n:o)(e);s.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)}))}))}const T={puppeteer:{args:{value:[],type:"string[]",description:"Arguments array to send to Puppeteer."}},highcharts:{version:{value:"latest",envLink:"HIGHCHARTS_VERSION",type:"string",description:"The Highcharts version to be used."},cdnURL:{value:"https://code.highcharts.com/",envLink:"HIGHCHARTS_CDN_URL",type:"string",description:"The CDN URL for Highcharts scripts to be used."},coreScripts:{envLink:"HIGHCHARTS_CORE_SCRIPTS",value:["highcharts","highcharts-more","highcharts-3d"],type:"string[]",description:"The core Highcharts scripts to fetch."},modules:{envLink:"HIGHCHARTS_MODULES",value:["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"],type:"string[]",description:"The modules of Highcharts to fetch."},indicators:{envLink:"HIGHCHARTS_INDICATORS",value:["indicators-all"],type:"string[]",description:"The indicators of Highcharts to fetch."},scripts:{value:["https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js","https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.34/moment-timezone-with-data.min.js"],type:"string[]",description:"Additional optional scripts or dependencies to fetch."},forceFetch:{envLink:"HIGHCHARTS_FORCE_FETCH",value:!1,type:"boolean",description:"The flag to determine whether to refetch all scripts after each server rerun."},cachePath:{envLink:"HIGHCHARTS_CACHE_PATH",value:".cache",type:"string",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:{envLink:"EXPORT_TYPE",value:"png",type:"string",description:"The file export format. It can be jpeg, png, pdf, or svg."},constr:{envLink:"EXPORT_CONSTR",value:"chart",type:"string",description:"The constructor to use. Can be chart, stockChart, mapChart, or ganttChart."},defaultHeight:{envLink:"EXPORT_DEFAULT_HEIGHT",value:400,type:"number",description:"the default height of the exported chart. Used when no value is set."},defaultWidth:{envLink:"EXPORT_DEFAULT_WIDTH",value:600,type:"number",description:"The default width of the exported chart. Used when no value is set."},defaultScale:{envLink:"EXPORT_DEFAULT_SCALE",value:1,type:"number",description:"The default scale of the exported chart. Used when no value is set."},height:{type:"number",value:!1,description:"The height of the exported chart, overriding the option in the chart settings."},width:{type:"number",value:!1,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:{envLink:"EXPORT_RASTERIZATION_TIMEOUT",value:1500,type:"number",description:"The duration in milliseconds to wait for rendering a webpage."}},customLogic:{allowCodeExecution:{envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",value:!1,type:"boolean",description:"Controls whether the execution of arbitrary code is allowed during the exporting process."},allowFileResources:{envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",value:!1,type:"boolean",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:{envLink:"SERVER_ENABLE",value:!1,type:"boolean",cliName:"enableServer",description:"When set to true, the server starts on the local IP address 0.0.0.0."},host:{envLink:"SERVER_HOST",value:"0.0.0.0",type:"string",description:"The hostname of the server. Additionally, it starts a server on the provided hostname."},port:{envLink:"SERVER_PORT",value:7801,type:"number",description:"The server port when enabled."},benchmarking:{envLink:"SERVER_BENCHMARKING",value:!1,type:"boolean",cliName:"serverBenchmarking",description:"Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request."},ssl:{enable:{envLink:"SERVER_SSL_ENABLE",value:!1,type:"boolean",cliName:"enableSsl",description:"Enables or disables the SSL protocol."},force:{envLink:"SERVER_SSL_FORCE",value:!1,type:"boolean",cliName:"sslForced",legacyName:"sslOnly",description:"When set to true, the server is forced to serve only over HTTPS."},port:{envLink:"SERVER_SSL_PORT",value:443,type:"number",cliName:"sslPort",description:"The port on which to run the SSL server."},certPath:{envLink:"SERVER_SSL_CERT_PATH",value:"",type:"string",legacyName:"sslPath",description:"The path to the SSL certificate/key file."}},rateLimiting:{enable:{envLink:"SERVER_RATE_LIMITING_ENABLE",value:!1,type:"boolean",cliName:"enableRateLimiting",description:"Enables rate limiting for the server."},maxRequests:{envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",value:10,type:"number",legacyName:"rateLimit",description:"The maximum number of requests allowed in one minute."},window:{envLink:"SERVER_RATE_LIMITING_WINDOW",value:1,type:"number",description:"The time window, in minutes, for the rate limiting."},delay:{envLink:"SERVER_RATE_LIMITING_DELAY",value:0,type:"number",description:"The delay duration for each successive request before reaching the maximum limit."},trustProxy:{envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",value:!1,type:"boolean",description:"Set this to true if the server is behind a load balancer."},skipKey:{envLink:"SERVER_RATE_LIMITING_SKIP_KEY",value:"",type:"string",description:"Allows bypassing the rate limiter and should be provided with the skipToken argument."},skipToken:{envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",value:"",type:"string",description:"Allows bypassing the rate limiter and should be provided with the skipKey argument."}}},pool:{minWorkers:{envLink:"POOL_MIN_WORKERS",value:4,type:"number",description:"The number of minimum and initial pool workers to spawn."},maxWorkers:{envLink:"POOL_MAX_WORKERS",value:8,type:"number",legacyName:"workers",description:"The number of maximum pool workers to spawn."},workLimit:{envLink:"POOL_WORK_LIMIT",value:40,type:"number",description:"The number of work pieces that can be performed before restarting the worker process."},acquireTimeout:{envLink:"POOL_ACQUIRE_TIMEOUT",value:5e3,type:"number",description:"The duration, in milliseconds, to wait for acquiring a resource."},createTimeout:{envLink:"POOL_CREATE_TIMEOUT",value:5e3,type:"number",description:"The duration, in milliseconds, to wait for creating a resource."},destroyTimeout:{envLink:"POOL_DESTROY_TIMEOUT",value:5e3,type:"number",description:"The duration, in milliseconds, to wait for destroying a resource."},idleTimeout:{envLink:"POOL_IDLE_TIMEOUT",value:3e4,type:"number",description:"The duration, in milliseconds, after which an idle resource is destroyed."},createRetryInterval:{envLink:"POOL_CREATE_RETRY_INTERVAL",value:200,type:"number",description:"The duration, in milliseconds, to wait before retrying the create process in case of a failure."},reaperInterval:{envLink:"POOL_REAPER_INTERVAL",value:1e3,type:"number",description:"The duration, in milliseconds, after which the check for idle resources to destroy is triggered."},benchmarking:{envLink:"POOL_BENCHMARKING",value:!1,type:"boolean",cliName:"poolBenchmarking",description:"Indicate whether to show statistics for the pool of resources or not."},listenToProcessExits:{envLink:"POOL_LISTEN_TO_PROCESS_EXITS",value:!0,type:"boolean",description:"Decides whether or not to attach process.exit handlers."}},logging:{level:{envLink:"LOGGING_LEVEL",value:4,type:"number",cliName:"logLevel",description:"The logging level to be used."},file:{envLink:"LOGGING_FILE",value:"highcharts-export-server.log",type:"string",cliName:"logFile",description:"The name of a log file. The logDest option also needs to be set to enable file logging."},dest:{envLink:"LOGGING_DEST",value:"log/",type:"string",cliName:"logDest",description:"The path to store log files. This also enables file logging."}},ui:{enable:{envLink:"UI_ENABLE",value:!1,type:"boolean",cliName:"enableUi",description:"Enables or disables the user interface (UI) for the export server."},route:{envLink:"UI_ROUTE",value:"/",type:"string",cliName:"uiRoute",description:"The endpoint route to which the user interface (UI) should be attached."}},other:{noLogo:{envLink:"OTHER_NO_LOGO",value:!1,type:"boolean",description:"Skip printing the logo on a startup. Will be replaced by a simple text."}}},x={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:"modules",message:"Available modules",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:T.highcharts.modules.value},{type:"list",name:"scripts",message:"Custom scripts",initial:T.highcharts.scripts.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:"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},{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}],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},{type:"toggle",name:"listenToProcessExits",message:"Set to false to skip attaching process.exit handlers",initial:T.pool.listenToProcessExits.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:"toggle",name:"noLogo",message:"Skip printing the logo on startup. Replaced by simple text",initial:T.other.noLogo.value}]},k=["options","globalOptions","themeOptions","resources","payload"],E={},S=(e,t="")=>{Object.keys(e).forEach((r=>{if(!["puppeteer","highcharts"].includes(r)){const i=e[r];void 0===i.value?S(i,`${t}.${r}`):(E[i.cliName||r]=`${t}.${r}`.substring(1),void 0!==i.legacyName&&(E[i.legacyName]=`${t}.${r}`.substring(1)))}}))};S(T);const L=["red","yellow","blue","gray","green"];let R={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:L[0]},{title:"warning",color:L[1]},{title:"notice",color:L[2]},{title:"verbose",color:L[3]},{title:"benchmark",color:L[4]}],listeners:[]};for(const[e,t]of Object.entries(T.logging))R[e]=t.value;const O=(e,r)=>{R.toFile&&(R.pathCreated||(!t.existsSync(R.dest)&&t.mkdirSync(R.dest),R.pathCreated=!0),t.appendFile(`${R.dest}${R.file}`,[r].concat(e).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),R.toFile=!1)})))},I=(...e)=>{const[t,...r]=e,{level:i,levelsDesc:o}=R;if(5!==t&&(0===t||t>i||i>o.length))return;const n=`${(new Date).toString().split("(")[0].trim()} [${o[t-1].title}] -`;R.listeners.forEach((e=>{e(n,r.join(" "))})),R.toConsole&&console.log.apply(void 0,[n.toString()[R.levelsDesc[t-1].color]].concat(r)),O(r,n)},_=(e,t,r)=>{const i=r||t.message,{level:o,levelsDesc:n}=R;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];R.toConsole&&console.log.apply(void 0,[s.toString()[R.levelsDesc[e-1].color]].concat([i[L[e-1]],"\n",a])),R.listeners.forEach((e=>{e(s,l.join(" "))})),O(l,s)},C=e=>{e>=0&&e<=R.levelsDesc.length&&(R.level=e)},$=(e,t)=>{if(R={...R,dest:e||R.dest,file:t||R.file,toFile:!0},0===R.dest.length)return I(1,"[logger] File logging initialization: no path supplied.");R.dest.endsWith("/")||(R.dest+="/")},P=s.fileURLToPath(new URL("../.","undefined"==typeof document?require("url").pathToFileURL(__filename).href:y&&y.src||new URL("index.cjs",document.baseURI).href)),j=(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"},N=(e=!1,r)=>{const i=["js","css","files"];let o=e,n=!1;if(r&&e.endsWith(".json"))try{o=A(t.readFileSync(e,"utf8"))}catch(e){return _(2,e,"[cli] No resources found.")}else o=A(e),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):I(3,"[cli] No resources found.")};function A(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 H=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]=H(e[r]));return t},F=(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 U(){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 q=e=>!["false","undefined","null","NaN","0",""].includes(e)&&!!e,W=(e,r)=>{if(e&&"string"==typeof e)return(e=e.trim()).endsWith(".js")?!!r&&W(t.readFileSync(e,"utf8")):e.startsWith("function()")||e.startsWith("function ()")||e.startsWith("()=>")||e.startsWith("() =>")?`(${e})()`:e.replace(/;$/,"")},D=()=>{const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6};class M 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 G={cdnURL:"https://code.highcharts.com/",activeManifest:{},sources:"",hcVersion:""};let V=!1;const J=()=>G.hcVersion=G.sources.substring(0,G.sources.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim(),K=async(e,t,r,i=!1)=>{e.endsWith(".js")&&(e=e.substring(0,e.length-3)),I(4,`[cache] Fetching script - ${e}.js`);const o=t?{agent:t,timeout:+process.env.PROXY_SERVER_TIMEOUT||5e3}:{},n=await b(`${e}.js`,o);if(200===n.statusCode&&"string"==typeof n.text){if(r){r[e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")]=1}return n.text}if(i)throw new M(`Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${n.statusCode}).`).setError(n);return I(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`),""},z=async(e,r)=>{const{coreScripts:o,modules:n,indicators:s,scripts:a}=e,l="latest"!==e.version&&e.version?`${e.version}/`:"";let c;I(3,`[cache] Updating cache version to Highcharts: ${l||"latest"}.`);const p=process.env.PROXY_SERVER_HOST,u=process.env.PROXY_SERVER_PORT;if(p&&u)try{c=new i.HttpsProxyAgent({host:p,port:+u})}catch(e){throw new M("[cache] Could not create a Proxy Agent.").setError(e)}const h={};try{return G.sources=await(async(e,t,r,i,o,n)=>{const s=[...e.map((e=>K(`${i}${e}`,o,n,!0))),...t.map((e=>K(`${i}${e}`,o,n))),...r.map((e=>K(`${e}`,o)))];return(await Promise.all(s)).join(";\n")})([...o.map((e=>`${l}${e}`))],[...n.map((e=>"map"===e?`maps/${l}modules/${e}`:`${l}modules/${e}`)),...s.map((e=>`stock/${l}indicators/${e}`))],a,e.cdnURL||G.cdnURL,c,h),J(),t.writeFileSync(r,G.sources),h}catch(e){throw new M("[cache] Unable to update the local Highcharts cache.").setError(e)}},X=async e=>{const i=r.join(P,e.cachePath);let o;const n=r.join(i,"manifest.json"),s=r.join(i,"sources.js");if(V=e,!t.existsSync(i)&&t.mkdirSync(i),!t.existsSync(n)||e.forceFetch)I(3,"[cache] Fetching and caching Highcharts dependencies."),o=await z(e,s);else{let r=!1;const i=JSON.parse(t.readFileSync(n));if(i.modules&&Array.isArray(i.modules)){const e={};i.modules.forEach((t=>e[t]=1)),i.modules=e}const{modules:a,coreScripts:l,indicators:c}=e,p=a.length+l.length+c.length;i.version!==e.version?(I(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),r=!0):Object.keys(i.modules||{}).length!==p?(I(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),r=!0):r=(e.modules||[]).some((e=>{if(!i.modules[e])return I(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),r?o=await z(e,s):(I(3,"[cache] Dependency cache is up to date, proceeding."),G.sources=t.readFileSync(s,"utf8"),o=i.modules,J())}await(async(e,i)=>{const o={version:e.version,modules:i||{}};G.activeManifest=o,I(3,"[cache] Writing a new manifest.");try{t.writeFileSync(r.join(P,e.cachePath,"manifest.json"),JSON.stringify(o),"utf8")}catch(e){throw new M("[cache] Error writing the cache manifest.").setError(e)}})(e,o)},B=()=>r.join(P,V.cachePath);var Y=async e=>!!V&&await X(Object.assign(V,{version:e})),Q=()=>G,Z=()=>G.hcVersion;let ee={};const te=()=>ee,re=(e,t,r=[])=>{const i=H(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]:re(i[e],n,r);var o;return i};function ie(e,t={},r=""){Object.keys(e).forEach((i=>{const o=e[i],n=t&&t[i];let s;void 0===o.value?ie(o,n,`${r}.${i}`):(void 0!==n&&(o.value=n),o.envLink&&("boolean"===o.type?o.value=q([process.env[o.envLink],o.value].find((e=>e||"false"===e))):"number"===o.type?(s=+process.env[o.envLink],o.value=s>=0?s:o.value):o.type.indexOf("]")>=0&&process.env[o.envLink]?o.value=process.env[o.envLink].split(","):o.value=process.env[o.envLink]||o.value))}))}function oe(e){let t={};for(const[r,i]of Object.entries(e))t[r]=Object.prototype.hasOwnProperty.call(i,"value")?i.value:oe(i);return t}function ne(e,t,r){for(;t.length>1;){const i=t.shift();return Object.prototype.hasOwnProperty.call(e,i)||(e[i]={}),e[i]=ne(Object.assign({},e[i]),t,r),e}return e[t[0]]=r,e}const se=h.randomBytes(64).toString("base64url"),ae=p.join("tmp",`puppeteer-${se}`),le=[`--user-data-dir=${p.join(ae,"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"],ce=w.fileURLToPath(new URL(".","undefined"==typeof document?require("url").pathToFileURL(__filename).href:y&&y.src||new URL("index.cjs",document.baseURI).href)),pe=t.readFileSync(ce+"/../templates/template.html","utf8");let ue;const he=async e=>{await e.setContent(pe),await e.addScriptTag({path:`${B()}/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()}`)}))},de=async(e,t=!1)=>{try{t?(await e.goto("about:blank"),await he(e)):await e.evaluate((()=>{document.body.innerHTML='
'}))}catch(e){_(2,e,"[browser] Could not clear the content of the page.")}},ge=async()=>{if(!ue)return!1;const e=await ue.newPage();return await e.setCacheEnabled(!1),await he(e),e},me=async()=>(ue?.isConnected()&&(await ue.close(),I(4,"[browser] Closed the browser.")),!0);const fe=w.fileURLToPath(new URL(".","undefined"==typeof document?require("url").pathToFileURL(__filename).href:y&&y.src||new URL("index.cjs",document.baseURI).href)),ye=(e,t,r)=>e.evaluate(((e,t)=>window.triggerExport(e,t)),t,r);var ve=async(e,i,o)=>{const n=[],s=async e=>{for(const e of n)await e.dispose();await e.evaluate((()=>{const[,...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...r]=document.getElementsByTagName("link");for(const i of[...e,...t,...r])i.remove()}))};try{I(4,"[export] Determining export path.");const a=o.export;await e.evaluate((()=>requestAnimationFrame((()=>{}))));const l=a?.options?.chart?.displayErrors&&Q().activeManifest.modules.debugger;let c;if(await e.evaluate((e=>window._displayErrors=e),l),i.indexOf&&(i.indexOf("=0||i.indexOf("=0)){if(I(4,"[export] Treating as SVG."),"svg"===a.type)return i;c=!0,await e.setContent((e=>`\n\n\n \n \n Highcarts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`)(i))}else I(4,"[export] Treating as config."),a.strInj?await ye(e,{chart:{height:a.height,width:a.width}},o):(i.chart.height=a.height,i.chart.width=a.width,await ye(e,i,o));const p=o.customLogic.resources;if(p){if(p.js&&n.push(await e.addScriptTag({content:p.js})),p.files)for(const r of p.files)try{const i=!r.startsWith("http");n.push(await e.addScriptTag(i?{content:t.readFileSync(r,"utf8")}:{url:r}))}catch(e){_(2,e,`[export] The JS file ${r} 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")?n.push(await e.addStyleTag({url:i})):o.customLogic.allowFileResources&&n.push(await e.addStyleTag({path:r.join(fe,i)})));n.push(await e.addStyleTag({content:p.css.replace(/@import\s*([^;]*);/g,"")||" "}))}}const u=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(a.scale)):await e.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 e.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 e.evaluate(g,parseFloat(a.scale));const{height:m,width:f,x:y,y:v}=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)}})))(e);let w;if(c||await e.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)))(e);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 M("Rasterization timeout"))),o||1500)))]))(e,a.type,"base64",{width:d,height:h,x:y,y:v},a.rasterizationTimeout);else{if("pdf"!==a.type)throw new M(`[export] Unsupported output format ${a.type}.`);w=await((e,t,r,i)=>e.pdf({height:t+1,width:r,encoding:i}))(e,h,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}};let we,be=0,Te=0,xe=0,ke=0,Ee=0,Se={},Le=!1;const Re={create:async()=>{let e=!1;const t=c.v4(),r=(new Date).getTime();try{if(e=await ge(),!e||e.isClosed())throw new M("The page is invalid or closed.");I(3,`[pool] Successfully created a worker ${t} - took ${(new Date).getTime()-r} ms.`)}catch(e){throw new M("Error encountered when creating a new page.").setError(e)}return{id:t,page:e,workCount:Math.round(Math.random()*(Se.workLimit/2))}},validate:async e=>Se.workLimit&&++e.workCount>Se.workLimit?(I(3,`[pool] Worker failed validation: exceeded work limit (limit is ${Se.workLimit}).`),!1):(await de(e.page,!0),!0),destroy:e=>{I(3,`[pool] Destroying pool entry ${e.id}.`),e.page&&e.page.close()}},Oe=async e=>{if(Se=e&&e.pool?{...e.pool}:{},Se.listenToProcessExits&&(I(3,"[pool] Attaching exit listeners to the process."),process.on("exit",(async e=>{I(4,`Process exited with code ${e}.`),await Ie()})),process.on("SIGINT",((e,t)=>{I(4,`The ${e} event with code: ${t}.`),process.exit(1)})),process.on("SIGTERM",((e,t)=>{I(4,`The ${e} event with code: ${t}.`),process.exit(1)})),process.on("uncaughtException",(async(e,t)=>{_(1,e,`The ${t} error.`),await Ie(),process.exit(1)}))),we=e.puppeteerArgs,await(async e=>{const t=[...le,...e||[]];if(!ue){let e=0;const r=async()=>{try{I(3,`[browser] Attempting to get a browser instance (try ${++e}).`),ue=await u.launch({headless:"new",args:t,userDataDir:"./tmp/"})}catch(t){if(_(1,t,"[browser] Failed to launch a browser instance."),!(e<25))throw t;I(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 M("[browser] Maximum retries to open a browser instance reached.").setError(e)}if(!ue)throw new M("[browser] Cannot find a browser to open.")}return ue})(we),I(3,`[pool] Initializing pool with workers: min ${Se.minWorkers}, max ${Se.maxWorkers}.`),Le)return I(4,"[pool] Already initialized, please kill it before creating a new one.");parseInt(Se.minWorkers)>parseInt(Se.maxWorkers)&&(Se.minWorkers=Se.maxWorkers);try{Le=new l.Pool({...Re,min:parseInt(Se.minWorkers),max:parseInt(Se.maxWorkers),acquireTimeoutMillis:Se.acquireTimeout,createTimeoutMillis:Se.createTimeout,destroyTimeoutMillis:Se.destroyTimeout,idleTimeoutMillis:Se.idleTimeout,createRetryIntervalMillis:Se.createRetryInterval,reapIntervalMillis:Se.reaperInterval,propagateCreateError:!1}),Le.on("release",(async e=>{await de(e.page,!1),I(4,`[pool] Releasing a worker with ID ${e.id}.`)})),Le.on("destroySuccess",((e,t)=>{I(4,`[pool] Destroyed a worker with ID ${t.id}.`)}));const e=[];for(let t=0;t{Le.release(e)})),I(3,"[pool] The pool is ready"+(e.length?` with ${e.length} initial resources waiting.`:"."))}catch(e){throw await me(),new M("[pool] Could not create the pool of workers.").setError(e)}};async function Ie(){return I(3,"[pool] Killing all pool workers and browser, if any exist."),Le?.destroyed||Le&&(await Le.destroy(),I(4,"[browser] Destroyed the pool of resources.")),me()}const _e=async(e,t)=>{let r;try{if(I(4,"[pool] Work received, starting to process."),++Te,Se.benchmarking&&Ce(),!Le)throw new M("Work received, but pool has not been started.");try{I(4,"[pool] Acquiring a worker handle.");const e=D();r=await Le.acquire().promise,t.server.benchmarking&&I(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Acquired a worker handle: ${e()}ms.`)}catch(e){throw new M("Error encountered when acquiring an available entry.").setError(e)}if(I(4,"[pool] Acquired a worker handle."),!r.page)throw new M("Resolved worker page is invalid: the pool setup is wonky.");let i=(new Date).getTime();I(4,`[pool] Starting work on pool entry with ID ${r.id}.`);const o=D(),n=await ve(r.page,e,t);if(n instanceof Error)throw"Rasterization timeout"===n.message&&(r.page.close(),r.page=await ge()),new M("Error encountered during export.").setError(n);t.server.benchmarking&&I(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Exported a chart sucessfully: ${o()}ms.`),Le.release(r);const s=(new Date).getTime()-i;return xe+=s,Ee=xe/++be,I(4,`[pool] Work completed in ${s} ms.`),{result:n,options:t}}catch(e){throw++ke,r&&Le.release(r),new M(`[pool] In pool.postWork: ${e.message}`).setError(e)}};function Ce(){const{min:e,max:t}=Le;I(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),I(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),I(5,`[pool] The number of resources that are currently available: ${Le.numFree()}.`),I(5,`[pool] The number of resources that are currently acquired: ${Le.numUsed()}.`),I(5,`[pool] The number of callers waiting to acquire a resource: ${Le.numPendingAcquires()}.`)}var $e=()=>({min:Le.min,max:Le.max,available:Le.numFree(),inUse:Le.numUsed(),pendingAcquire:Le.numPendingAcquires()}),Pe=()=>Te,je=()=>ke,Ne=()=>Ee,Ae=()=>be;let He=!1;const Fe=async(e,r)=>{I(4,"[chart] Starting the exporting process.");const i=((e,t={})=>{let r={};return e.svg?(r=H(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=re(t,e,k),r.export.outfile=r.export?.outfile||`chart.${r.export?.type||"png"}`,r})(e,te()),o=i.export;if(i.payload?.svg&&""!==i.payload.svg)try{return I(4,"[chart] Attempting to export from a SVG input."),De(i.payload.svg.trim(),i,r)}catch(e){return r(new M("[chart] Error loading SVG input.").setError(e))}if(o.infile&&o.infile.length)try{return I(4,"[chart] Attempting to export from an input file."),i.export.instr=t.readFileSync(o.infile,"utf8"),De(i.export.instr.trim(),i,r)}catch(e){return r(new M("[chart] Error loading input file.").setError(e))}if(o.instr&&""!==o.instr||o.options&&""!==o.options)try{return I(4,"[chart] Attempting to export from a raw input."),q(i.customLogic?.allowCodeExecution)?We(i,r):"string"==typeof o.instr?De(o.instr.trim(),i,r):qe(i,o.instr||o.options,r)}catch(e){return r(new M("[chart] Error loading raw input.").setError(e))}return r(new M("[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||A(e.export?.instr),i=A(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},qe=async(e,r,i,o)=>{let{export:n,customLogic:s}=e;const a="boolean"==typeof s.allowCodeExecution?s.allowCodeExecution:He;if(s){if(a)if("string"==typeof e.customLogic.resources)e.customLogic.resources=N(e.customLogic.resources,q(e.customLogic.allowFileResources));else if(!e.customLogic.resources)try{const r=t.readFileSync("resources.json","utf8");e.customLogic.resources=N(r,q(e.customLogic.allowFileResources))}catch(e){_(2,e,"[chart] Unable to load the default resources.json file.")}}else s=e.customLogic={};if(!a&&s){if(s.callback||s.resources||s.customCode)return i(new M("[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=j(n.type,n.outfile),"svg"===n.type&&(n.width=!1),["globalOptions","themeOptions"].forEach((e=>{try{n&&n[e]&&("string"==typeof n[e]&&n[e].endsWith(".json")?n[e]=A(t.readFileSync(n[e],"utf8"),!0):n[e]=A(n[e],!0))}catch(t){n[e]={},_(2,t,`[chart] The '${e}' cannot be loaded.`)}})),s.allowCodeExecution)try{s.customCode=W(s.customCode,s.allowFileResources)}catch(e){_(2,e,"[chart] The 'customCode' cannot be loaded.")}if(s&&s.callback&&s.callback?.indexOf("{")<0)if(s.allowFileResources)try{s.callback=t.readFileSync(s.callback,"utf8")}catch(e){s.callback=!1,_(2,e,"[chart] The 'callback' cannot be loaded.")}else s.callback=!1;e.export={...e.export,...Ue(e)};try{return i(!1,await _e(n.strInj||r||o,e))}catch(e){return i(e)}},We=(e,t)=>{try{let r,i=e.export.instr||e.export.options;return"string"!=typeof i&&(r=i=F(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 M(`[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))}},De=(e,t,r)=>{const{allowCodeExecution:i}=t.customLogic;if(e.indexOf("=0||e.indexOf("=0)return I(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 q(i)?We(t,r):r(new M("[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=(e,t,r,i)=>{_(1,e),"development"!==process.env.NODE_ENV&&delete e.stack,i(e)},Ge=(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=f({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&&(I(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(o),I(3,`[rate limiting] Enabled rate limiting with ${i.max} requests per ${i.window} minute for each IP, trusting proxy: ${i.trustProxy}.`)};class Je extends M{constructor(e,t){super(e),this.status=this.statusCode=t}setStatus(e){return this.status=e,this}}const Ke={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};let ze=0;const Xe=[],Be=[],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=D(),o=c.v4().replace(/-/g,""),n=te(),s=e.body,a=++ze;let l=j(s.type);if(!s||"object"==typeof(i=s)&&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 p=A(s.infile||s.options||s.data);if(!p&&!s.svg)throw I(2,`The request with ID ${o} from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Payload received: ${JSON.stringify(s)}.`),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=Ye(Xe,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})),I(4,`[export] Got an incoming HTTP request with ID ${o}.`),s.constr="string"==typeof s.constr&&s.constr||"chart";const d={export:{instr:p,type:l,constr:s.constr[0].toLowerCase()+s.constr.substr(1),height:s.height,width:s.width,scale:s.scale||n.export.scale,globalOptions:A(s.globalOptions,!0),themeOptions:A(s.themeOptions,!0)},customLogic:{allowCodeExecution:He,allowFileResources:!1,resources:A(s.resources,!0),callback:s.callback,customCode:s.customCode}};p&&(d.export.instr=F(p,d.customLogic.allowCodeExecution));const g=re(n,d);if(g.export.options=p,g.payload={svg:s.svg||!1,b64:s.b64||!1,noDownload:s.noDownload||!1,requestId:o},s.svg&&(e=>["localhost","(10).(.*).(.*).(.*)","(127).(.*).(.*).(.*)","(172).(1[6-9]|2[0-9]|3[0-1]).(.*).(.*)","(192).(168).(.*).(.*)"].some((t=>e.match(`xlink:href="(?:(http://|https://))?${t}`))))(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"),n.server.benchmarking&&I(5,`[benchmark] Request with ID ${o} - After the whole exporting process: ${r()}ms.`),h)return I(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,Ye(Be,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",Ke[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(t.readFileSync(r.join(P,"package.json"))),et=new Date;const tt=g();tt.disable("x-powered-by"),tt.use(d());const rt=m.memoryStorage(),it=m({storage:rt,limits:{fieldSize:52428800}});tt.use(g.json({limit:52428800})),tt.use(g.urlencoded({extended:!0,limit:52428800})),tt.use(it.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}`)}))}))},nt=async e=>{try{if(!e.enable)return!1;if(!e.ssl.force){const t=o.createServer(tt);ot(t),t.listen(e.port,e.host),I(3,`[server] Started HTTP server on ${e.host}:${e.port}.`)}if(e.ssl.enable){let i,o;try{i=await t.promises.readFile(r.posix.join(e.ssl.certPath,"server.key"),"utf8"),o=await t.promises.readFile(r.posix.join(e.ssl.certPath,"server.crt"),"utf8")}catch(t){I(2,`[server] Unable to load key/certificate from the '${e.ssl.certPath}' path. Could not run secured layer server.`)}if(i&&o){const t=n.createServer({key:i,cert:o},tt);ot(t),t.listen(e.ssl.port,e.host),I(3,`[server] Started HTTPS server on ${e.host}:${e.ssl.port}.`)}}e.rateLimiting&&e.rateLimiting.enable&&![0,NaN].includes(e.rateLimiting.maxRequests)&&Ve(tt,e.rateLimiting),tt.use(g.static(r.posix.join(P,"public"))),(e=>{!!e&&e.get("/health",((e,t)=>{t.send({status:"OK",bootTime:et,uptime:Math.floor(((new Date).getTime()-et.getTime())/1e3/60)+" minutes",version:Ze.version,highchartsVersion:Z(),averageProcessingTime:Ne(),performedExports:Ae(),failedExports:je(),exportAttempts:Pe(),sucessRatio:Ae()/Pe()*100,pool:$e()})}))})(tt),(e=>{e.post("/",Qe),e.post("/:filename",Qe)})(tt),(e=>{!!e&&e.get("/",((e,t)=>{t.sendFile(r.join(P,"public","index.html"))}))})(tt),(e=>{!!e&&e.post("/version/change/:newVersion",(async(e,t,r)=>{try{const r=process.env.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 Y(o)}catch(e){throw new Je(`Version change: ${e.message}`,e.statusCode).setError(e)}t.status(200).send({statusCode:200,version:Z(),message:`Successfully updated Highcharts to version: ${o}.`})}catch(e){r(e)}}))})(tt),(e=>{e.use(Me),e.use(Ge)})(tt)}catch(e){throw new M("[server] Could not configure and start the server.").setError(e)}};var st={startServer:nt,enableRateLimiting:e=>Ve(tt,e),getExpress:()=>g,getApp:()=>tt,use:(e,...t)=>{tt.use(e,...t)},get:(e,...t)=>{tt.get(e,...t)},post:(e,...t)=>{tt.post(e,...t)}};e.config();var at={server:st,startServer:nt,setOptions:(e,r)=>(r?.length&&(ee=function(e){const r=e.findIndex((e=>"loadConfig"===e.replace(/-/g,"")));if(r>-1&&e[r+1]){const i=e[r+1];try{if(i&&i.endsWith(".json"))return JSON.parse(t.readFileSync(i))}catch(e){_(2,e,`[config] Unable to load the configuration from the ${i} file.`)}}return{}}(r)),ie(T,ee),ee=oe(T),e&&(ee=re(ee,e,k)),r?.length&&(ee=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]=q(t[o]):"number"===a?e[r]=+t[o]:a.indexOf("]")>=0?e[r]=t[o].split(","):e[r]=t[o]:(I(2,`[config] Missing value for the '${n}' argument. Using the default value.`),i=!0)),e[r])),e)}i&&U();return e}(ee,r,T)),ee),initExport:async e=>{var t;return t=e.customLogic&&e.customLogic.allowCodeExecution,He=q(t),(e=>{C(e&&parseInt(e.level)),e&&e.dest&&$(e.dest,e.file||"highcharts-export-server.log")})(e.logging),await X(e.highcharts||{version:"latest"}),await Oe({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,r)=>{if(e)throw e;const{outfile:i,type:o}=r.options.export;t.writeFileSync(i||`chart.${o}`,"svg"!==o?Buffer.from(r.result,"base64"):r.result),await Ie()}))},batchExport:async e=>{const r=[];for(let i of e.export.batch.split(";"))i=i.split("="),2===i.length&&r.push(Fe({...e,export:{...e.export,infile:i[0],outfile:i[1]}},((e,r)=>{if(e)throw e;t.writeFileSync(r.options.export.outfile,Buffer.from(r.result,"base64"))})));try{await Promise.all(r),await Ie()}catch(e){throw new M("[chart] Error encountered during batch export.").setError(e)}},startExport:Fe,killPool:Ie,log:I,logWithStack:_,setLogLevel:C,enableFileLogging:$,mapToNewConfig:e=>{const t={};for(const[r,i]of Object.entries(e)){const e=E[r]?E[r].split("."):[];e.reduce(((t,r,o)=>t[r]=e.length-1===o?i:t[r]||{}),t)}return t},manualConfig:async e=>{let r={};t.existsSync(e)&&(r=JSON.parse(t.readFileSync(e,"utf8")));const i=Object.keys(x).map((e=>({title:`${e} options`,value:e})));return a({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,o)=>{let n=0,s=[];for(const e of o)x[e]=x[e].map((t=>({...t,section:e}))),s=[...s,...x[e]];return await a(s,{onSubmit:async(i,o)=>{if("modules"===i.name?(o=o.length?o.map((e=>i.choices[e])):i.choices,r[i.section][i.name]=o):r[i.section]=ne(Object.assign({},r[i.section]||{}),i.name.split("."),i.choices?i.choices[o]:o),++n===s.length){try{await t.promises.writeFile(e,JSON.stringify(r,null,2),"utf8")}catch(t){_(1,t,`[config] An error occurred while creating the ${e} file.`)}return!0}}}),!0}})},printLogo:e=>{const i=JSON.parse(t.readFileSync(r.join(P,"package.json"))).version;e?console.log(`Starting Highcharts Export Server v${i}...`):console.log(t.readFileSync(P+"/msg/startup.msg").toString().bold.yellow,`v${i}`)},printUsage:U};module.exports=at; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguY2pzIiwic291cmNlcyI6WyIuLi9saWIvZmV0Y2guanMiLCIuLi9saWIvc2NoZW1hcy9jb25maWcuanMiLCIuLi9saWIvbG9nZ2VyLmpzIiwiLi4vbGliL3V0aWxzLmpzIiwiLi4vbGliL2Vycm9ycy9FeHBvcnRFcnJvci5qcyIsIi4uL2xpYi9jYWNoZS5qcyIsIi4uL2xpYi9jb25maWcuanMiLCIuLi9saWIvYnJvd3Nlci5qcyIsIi4uL2xpYi9leHBvcnQuanMiLCIuLi90ZW1wbGF0ZXMvc3ZnX2V4cG9ydC9zdmdfZXhwb3J0LmpzIiwiLi4vbGliL3Bvb2wuanMiLCIuLi9saWIvY2hhcnQuanMiLCIuLi9saWIvc2VydmVyL2Vycm9yLmpzIiwiLi4vbGliL3NlcnZlci9yYXRlX2xpbWl0LmpzIiwiLi4vbGliL2Vycm9ycy9IdHRwRXJyb3IuanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy9leHBvcnQuanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy9oZWFsdGguanMiLCIuLi9saWIvc2VydmVyL3NlcnZlci5qcyIsIi4uL2xpYi9zZXJ2ZXIvcm91dGVzL3VpLmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvY2hhbmdlX2hjX3ZlcnNpb24uanMiLCIuLi9saWIvaW5kZXguanMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqXHJcbiAqIFRoaXMgbW9kdWxlIGV4cG9ydHMgdHdvIGZ1bmN0aW9uczogZmV0Y2ggKGZvciBHRVQgcmVxdWVzdHMpIGFuZCBwb3N0IChmb3IgUE9TVCByZXF1ZXN0cykuXHJcbiAqL1xyXG5cclxuaW1wb3J0IGh0dHAgZnJvbSAnaHR0cCc7XHJcbmltcG9ydCBodHRwcyBmcm9tICdodHRwcyc7XHJcblxyXG4vKipcclxuICogUmV0dXJucyB0aGUgSFRUUCBvciBIVFRQUyBwcm90b2NvbCBtb2R1bGUgYmFzZWQgb24gdGhlIHByb3ZpZGVkIFVSTC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHVybCAtIFRoZSBVUkwgdG8gZGV0ZXJtaW5lIHRoZSBwcm90b2NvbC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wgbW9kdWxlIChodHRwIG9yIGh0dHBzKS5cclxuICovXHJcbmNvbnN0IGdldFByb3RvY29sID0gKHVybCkgPT4gKHVybC5zdGFydHNXaXRoKCdodHRwcycpID8gaHR0cHMgOiBodHRwKTtcclxuXHJcbi8qKlxyXG4gKiBGZXRjaGVzIGRhdGEgZnJvbSB0aGUgc3BlY2lmaWVkIFVSTCB1c2luZyBlaXRoZXIgSFRUUCBvciBIVFRQUyBwcm90b2NvbC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHVybCAtIFRoZSBVUkwgdG8gZmV0Y2ggZGF0YSBmcm9tLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcmVxdWVzdE9wdGlvbnMgLSBPcHRpb25zIGZvciB0aGUgSFRUUCByZXF1ZXN0IChvcHRpb25hbCkuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBIVFRQIHJlc3BvbnNlIG9iamVjdFxyXG4gKiB3aXRoIGFkZGVkICd0ZXh0JyBwcm9wZXJ0eSBvciByZWplY3Rpbmcgd2l0aCBhbiBlcnJvci5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIGZldGNoKHVybCwgcmVxdWVzdE9wdGlvbnMgPSB7fSkge1xyXG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XHJcbiAgICBjb25zdCBwcm90b2NvbCA9IGdldFByb3RvY29sKHVybCk7XHJcblxyXG4gICAgcHJvdG9jb2xcclxuICAgICAgLmdldCh1cmwsIHJlcXVlc3RPcHRpb25zLCAocmVzKSA9PiB7XHJcbiAgICAgICAgbGV0IGRhdGEgPSAnJztcclxuXHJcbiAgICAgICAgLy8gQSBjaHVuayBvZiBkYXRhIGhhcyBiZWVuIHJlY2VpdmVkLlxyXG4gICAgICAgIHJlcy5vbignZGF0YScsIChjaHVuaykgPT4ge1xyXG4gICAgICAgICAgZGF0YSArPSBjaHVuaztcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgLy8gVGhlIHdob2xlIHJlc3BvbnNlIGhhcyBiZWVuIHJlY2VpdmVkLlxyXG4gICAgICAgIHJlcy5vbignZW5kJywgKCkgPT4ge1xyXG4gICAgICAgICAgaWYgKCFkYXRhKSB7XHJcbiAgICAgICAgICAgIHJlamVjdCgnTm90aGluZyB3YXMgZmV0Y2hlZCBmcm9tIHRoZSBVUkwuJyk7XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgcmVzLnRleHQgPSBkYXRhO1xyXG4gICAgICAgICAgcmVzb2x2ZShyZXMpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICB9KVxyXG4gICAgICAub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICAgICAgcmVqZWN0KGVycm9yKTtcclxuICAgICAgfSk7XHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZW5kcyBhIFBPU1QgcmVxdWVzdCB0byB0aGUgc3BlY2lmaWVkIFVSTCB3aXRoIHRoZSBwcm92aWRlZCBKU09OIGJvZHkgdXNpbmdcclxuICogZWl0aGVyIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgLSBUaGUgVVJMIHRvIHNlbmQgdGhlIFBPU1QgcmVxdWVzdCB0by5cclxuICogQHBhcmFtIHtPYmplY3R9IGJvZHkgLSBUaGUgSlNPTiBib2R5IHRvIGluY2x1ZGUgaW4gdGhlIFBPU1QgcmVxdWVzdFxyXG4gKiAob3B0aW9uYWwsIGRlZmF1bHQgaXMgYW4gZW1wdHkgb2JqZWN0KS5cclxuICogQHBhcmFtIHtPYmplY3R9IHJlcXVlc3RPcHRpb25zIC0gT3B0aW9ucyBmb3IgdGhlIEhUVFAgcmVxdWVzdCAob3B0aW9uYWwpLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgSFRUUCByZXNwb25zZSBvYmplY3Qgd2l0aFxyXG4gKiBhZGRlZCAndGV4dCcgcHJvcGVydHkgb3IgcmVqZWN0aW5nIHdpdGggYW4gZXJyb3IuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBwb3N0KHVybCwgYm9keSA9IHt9LCByZXF1ZXN0T3B0aW9ucyA9IHt9KSB7XHJcbiAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcclxuICAgIGNvbnN0IHByb3RvY29sID0gZ2V0UHJvdG9jb2wodXJsKTtcclxuICAgIGNvbnN0IGRhdGEgPSBKU09OLnN0cmluZ2lmeShib2R5KTtcclxuXHJcbiAgICAvLyBTZXQgZGVmYXVsdCBoZWFkZXJzIGFuZCBtZXJnZSB3aXRoIHJlcXVlc3RPcHRpb25zXHJcbiAgICBjb25zdCBvcHRpb25zID0gT2JqZWN0LmFzc2lnbihcclxuICAgICAge1xyXG4gICAgICAgIG1ldGhvZDogJ1BPU1QnLFxyXG4gICAgICAgIGhlYWRlcnM6IHtcclxuICAgICAgICAgICdDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbicsXHJcbiAgICAgICAgICAnQ29udGVudC1MZW5ndGgnOiBkYXRhLmxlbmd0aFxyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgcmVxdWVzdE9wdGlvbnNcclxuICAgICk7XHJcblxyXG4gICAgY29uc3QgcmVxID0gcHJvdG9jb2xcclxuICAgICAgLnJlcXVlc3QodXJsLCBvcHRpb25zLCAocmVzKSA9PiB7XHJcbiAgICAgICAgbGV0IHJlc3BvbnNlRGF0YSA9ICcnO1xyXG5cclxuICAgICAgICAvLyBBIGNodW5rIG9mIGRhdGEgaGFzIGJlZW4gcmVjZWl2ZWQuXHJcbiAgICAgICAgcmVzLm9uKCdkYXRhJywgKGNodW5rKSA9PiB7XHJcbiAgICAgICAgICByZXNwb25zZURhdGEgKz0gY2h1bms7XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICAgIC8vIFRoZSB3aG9sZSByZXNwb25zZSBoYXMgYmVlbiByZWNlaXZlZC5cclxuICAgICAgICByZXMub24oJ2VuZCcsICgpID0+IHtcclxuICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgIHJlcy50ZXh0ID0gcmVzcG9uc2VEYXRhO1xyXG4gICAgICAgICAgICByZXNvbHZlKHJlcyk7XHJcbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICByZWplY3QoZXJyb3IpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH0pO1xyXG4gICAgICB9KVxyXG4gICAgICAub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICAgICAgcmVqZWN0KGVycm9yKTtcclxuICAgICAgfSk7XHJcblxyXG4gICAgLy8gV3JpdGUgdGhlIHJlcXVlc3QgYm9keSBhbmQgZW5kIHRoZSByZXF1ZXN0LlxyXG4gICAgcmVxLndyaXRlKGRhdGEpO1xyXG4gICAgcmVxLmVuZCgpO1xyXG4gIH0pO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCBmZXRjaDtcclxuZXhwb3J0IHsgZmV0Y2gsIHBvc3QgfTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vLyBUaGlzIGlzIHRoZSBjb25maWd1cmF0aW9uIG9iamVjdCB3aXRoIGFsbCBvcHRpb25zIGFuZCB0aGVpciBkZWZhdWx0IHZhbHVlcyxcclxuLy8gYWxzbyBmcm9tIHRoZSAuZW52IGZpbGUgaWYgb25lIGV4aXN0c1xyXG5leHBvcnQgY29uc3QgZGVmYXVsdENvbmZpZyA9IHtcclxuICBwdXBwZXRlZXI6IHtcclxuICAgIGFyZ3M6IHtcclxuICAgICAgdmFsdWU6IFtdLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0FyZ3VtZW50cyBhcnJheSB0byBzZW5kIHRvIFB1cHBldGVlci4nXHJcbiAgICB9XHJcbiAgfSxcclxuICBoaWdoY2hhcnRzOiB7XHJcbiAgICB2ZXJzaW9uOiB7XHJcbiAgICAgIHZhbHVlOiAnbGF0ZXN0JyxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfVkVSU0lPTicsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBIaWdoY2hhcnRzIHZlcnNpb24gdG8gYmUgdXNlZC4nXHJcbiAgICB9LFxyXG4gICAgY2RuVVJMOiB7XHJcbiAgICAgIHZhbHVlOiAnaHR0cHM6Ly9jb2RlLmhpZ2hjaGFydHMuY29tLycsXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0NETl9VUkwnLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgQ0ROIFVSTCBmb3IgSGlnaGNoYXJ0cyBzY3JpcHRzIHRvIGJlIHVzZWQuJ1xyXG4gICAgfSxcclxuICAgIGNvcmVTY3JpcHRzOiB7XHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0NPUkVfU0NSSVBUUycsXHJcbiAgICAgIHZhbHVlOiBbJ2hpZ2hjaGFydHMnLCAnaGlnaGNoYXJ0cy1tb3JlJywgJ2hpZ2hjaGFydHMtM2QnXSxcclxuICAgICAgdHlwZTogJ3N0cmluZ1tdJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgY29yZSBIaWdoY2hhcnRzIHNjcmlwdHMgdG8gZmV0Y2guJ1xyXG4gICAgfSxcclxuICAgIG1vZHVsZXM6IHtcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfTU9EVUxFUycsXHJcbiAgICAgIHZhbHVlOiBbXHJcbiAgICAgICAgJ3N0b2NrJyxcclxuICAgICAgICAnbWFwJyxcclxuICAgICAgICAnZ2FudHQnLFxyXG4gICAgICAgICdleHBvcnRpbmcnLFxyXG4gICAgICAgICdleHBvcnQtZGF0YScsXHJcbiAgICAgICAgJ3BhcmFsbGVsLWNvb3JkaW5hdGVzJyxcclxuICAgICAgICAnYWNjZXNzaWJpbGl0eScsXHJcbiAgICAgICAgJ2Fubm90YXRpb25zLWFkdmFuY2VkJyxcclxuICAgICAgICAnYm9vc3QtY2FudmFzJyxcclxuICAgICAgICAnYm9vc3QnLFxyXG4gICAgICAgICdkYXRhJyxcclxuICAgICAgICAnZGF0YS10b29scycsXHJcbiAgICAgICAgJ2RyYWdnYWJsZS1wb2ludHMnLFxyXG4gICAgICAgICdzdGF0aWMtc2NhbGUnLFxyXG4gICAgICAgICdicm9rZW4tYXhpcycsXHJcbiAgICAgICAgJ2hlYXRtYXAnLFxyXG4gICAgICAgICd0aWxlbWFwJyxcclxuICAgICAgICAndGlsZWR3ZWJtYXAnLFxyXG4gICAgICAgICd0aW1lbGluZScsXHJcbiAgICAgICAgJ3RyZWVtYXAnLFxyXG4gICAgICAgICd0cmVlZ3JhcGgnLFxyXG4gICAgICAgICdpdGVtLXNlcmllcycsXHJcbiAgICAgICAgJ2RyaWxsZG93bicsXHJcbiAgICAgICAgJ2hpc3RvZ3JhbS1iZWxsY3VydmUnLFxyXG4gICAgICAgICdidWxsZXQnLFxyXG4gICAgICAgICdmdW5uZWwnLFxyXG4gICAgICAgICdmdW5uZWwzZCcsXHJcbiAgICAgICAgJ2dlb2hlYXRtYXAnLFxyXG4gICAgICAgICdweXJhbWlkM2QnLFxyXG4gICAgICAgICduZXR3b3JrZ3JhcGgnLFxyXG4gICAgICAgICdvdmVybGFwcGluZy1kYXRhbGFiZWxzJyxcclxuICAgICAgICAncGFyZXRvJyxcclxuICAgICAgICAncGF0dGVybi1maWxsJyxcclxuICAgICAgICAncGljdG9yaWFsJyxcclxuICAgICAgICAncHJpY2UtaW5kaWNhdG9yJyxcclxuICAgICAgICAnc2Fua2V5JyxcclxuICAgICAgICAnYXJjLWRpYWdyYW0nLFxyXG4gICAgICAgICdkZXBlbmRlbmN5LXdoZWVsJyxcclxuICAgICAgICAnc2VyaWVzLWxhYmVsJyxcclxuICAgICAgICAnc29saWQtZ2F1Z2UnLFxyXG4gICAgICAgICdzb25pZmljYXRpb24nLFxyXG4gICAgICAgICdzdG9jay10b29scycsXHJcbiAgICAgICAgJ3N0cmVhbWdyYXBoJyxcclxuICAgICAgICAnc3VuYnVyc3QnLFxyXG4gICAgICAgICd2YXJpYWJsZS1waWUnLFxyXG4gICAgICAgICd2YXJpd2lkZScsXHJcbiAgICAgICAgJ3ZlY3RvcicsXHJcbiAgICAgICAgJ3Zlbm4nLFxyXG4gICAgICAgICd3aW5kYmFyYicsXHJcbiAgICAgICAgJ3dvcmRjbG91ZCcsXHJcbiAgICAgICAgJ3hyYW5nZScsXHJcbiAgICAgICAgJ25vLWRhdGEtdG8tZGlzcGxheScsXHJcbiAgICAgICAgJ2RyYWctcGFuZXMnLFxyXG4gICAgICAgICdkZWJ1Z2dlcicsXHJcbiAgICAgICAgJ2R1bWJiZWxsJyxcclxuICAgICAgICAnbG9sbGlwb3AnLFxyXG4gICAgICAgICdjeWxpbmRlcicsXHJcbiAgICAgICAgJ29yZ2FuaXphdGlvbicsXHJcbiAgICAgICAgJ2RvdHBsb3QnLFxyXG4gICAgICAgICdtYXJrZXItY2x1c3RlcnMnLFxyXG4gICAgICAgICdob2xsb3djYW5kbGVzdGljaycsXHJcbiAgICAgICAgJ2hlaWtpbmFzaGknLFxyXG4gICAgICAgICdmbG93bWFwJ1xyXG4gICAgICBdLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBtb2R1bGVzIG9mIEhpZ2hjaGFydHMgdG8gZmV0Y2guJ1xyXG4gICAgfSxcclxuICAgIGluZGljYXRvcnM6IHtcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfSU5ESUNBVE9SUycsXHJcbiAgICAgIHZhbHVlOiBbJ2luZGljYXRvcnMtYWxsJ10sXHJcbiAgICAgIHR5cGU6ICdzdHJpbmdbXScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIGluZGljYXRvcnMgb2YgSGlnaGNoYXJ0cyB0byBmZXRjaC4nXHJcbiAgICB9LFxyXG4gICAgc2NyaXB0czoge1xyXG4gICAgICB2YWx1ZTogW1xyXG4gICAgICAgICdodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9tb21lbnQuanMvMi4yOS40L21vbWVudC5taW4uanMnLFxyXG4gICAgICAgICdodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9tb21lbnQtdGltZXpvbmUvMC41LjM0L21vbWVudC10aW1lem9uZS13aXRoLWRhdGEubWluLmpzJ1xyXG4gICAgICBdLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0FkZGl0aW9uYWwgb3B0aW9uYWwgc2NyaXB0cyBvciBkZXBlbmRlbmNpZXMgdG8gZmV0Y2guJ1xyXG4gICAgfSxcclxuICAgIGZvcmNlRmV0Y2g6IHtcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfRk9SQ0VfRkVUQ0gnLFxyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBmbGFnIHRvIGRldGVybWluZSB3aGV0aGVyIHRvIHJlZmV0Y2ggYWxsIHNjcmlwdHMgYWZ0ZXIgZWFjaCBzZXJ2ZXIgcmVydW4uJ1xyXG4gICAgfSxcclxuICAgIGNhY2hlUGF0aDoge1xyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DQUNIRV9QQVRIJyxcclxuICAgICAgdmFsdWU6ICcuY2FjaGUnLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBwYXRoIHRvIHRoZSBjYWNoZSBkaXJlY3RvcnkuIEl0IGlzIHVzZWQgdG8gc3RvcmUgdGhlIEhpZ2hjaGFydHMgc2NyaXB0cyBhbmQgY3VzdG9tIHNjcmlwdHMuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgZXhwb3J0OiB7XHJcbiAgICBpbmZpbGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBpbnB1dCBmaWxlIHNob3VsZCBpbmNsdWRlIGEgbmFtZSBhbmQgYSB0eXBlIChqc29uIG9yIHN2ZykuIEl0IG11c3QgYmUgY29ycmVjdGx5IGZvcm1hdHRlZCBhcyBhIEpTT04gb3IgU1ZHIGZpbGUuJ1xyXG4gICAgfSxcclxuICAgIGluc3RyOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbnB1dCwgcHJvdmlkZWQgaW4gdGhlIGZvcm0gb2YgYSBzdHJpbmdpZmllZCBKU09OIG9yIFNWRyBmaWxlLCB3aWxsIG92ZXJyaWRlIHRoZSAtLWluZmlsZSBvcHRpb24uJ1xyXG4gICAgfSxcclxuICAgIG9wdGlvbnM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdBbiBhbGlhcyBmb3IgdGhlIC0taW5zdHIgb3B0aW9uLidcclxuICAgIH0sXHJcbiAgICBvdXRmaWxlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgb3V0cHV0IGZpbGVuYW1lIGFsb25nIHdpdGggYSB0eXBlIChqcGVnLCBwbmcsIHBkZiwgb3Igc3ZnKS4gVGhpcyB3aWxsIGlnbm9yZSB0aGUgLS10eXBlIGZsYWcuJ1xyXG4gICAgfSxcclxuICAgIHR5cGU6IHtcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9UWVBFJyxcclxuICAgICAgdmFsdWU6ICdwbmcnLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgZmlsZSBleHBvcnQgZm9ybWF0LiBJdCBjYW4gYmUganBlZywgcG5nLCBwZGYsIG9yIHN2Zy4nXHJcbiAgICB9LFxyXG4gICAgY29uc3RyOiB7XHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfQ09OU1RSJyxcclxuICAgICAgdmFsdWU6ICdjaGFydCcsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGNvbnN0cnVjdG9yIHRvIHVzZS4gQ2FuIGJlIGNoYXJ0LCBzdG9ja0NoYXJ0LCBtYXBDaGFydCwgb3IgZ2FudHRDaGFydC4nXHJcbiAgICB9LFxyXG4gICAgZGVmYXVsdEhlaWdodDoge1xyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0RFRkFVTFRfSEVJR0hUJyxcclxuICAgICAgdmFsdWU6IDQwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICd0aGUgZGVmYXVsdCBoZWlnaHQgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LiBVc2VkIHdoZW4gbm8gdmFsdWUgaXMgc2V0LidcclxuICAgIH0sXHJcbiAgICBkZWZhdWx0V2lkdGg6IHtcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9ERUZBVUxUX1dJRFRIJyxcclxuICAgICAgdmFsdWU6IDYwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZGVmYXVsdCB3aWR0aCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQuIFVzZWQgd2hlbiBubyB2YWx1ZSBpcyBzZXQuJ1xyXG4gICAgfSxcclxuICAgIGRlZmF1bHRTY2FsZToge1xyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0RFRkFVTFRfU0NBTEUnLFxyXG4gICAgICB2YWx1ZTogMSxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZGVmYXVsdCBzY2FsZSBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQuIFVzZWQgd2hlbiBubyB2YWx1ZSBpcyBzZXQuJ1xyXG4gICAgfSxcclxuICAgIGhlaWdodDoge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGhlaWdodCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQsIG92ZXJyaWRpbmcgdGhlIG9wdGlvbiBpbiB0aGUgY2hhcnQgc2V0dGluZ3MuJ1xyXG4gICAgfSxcclxuICAgIHdpZHRoOiB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgd2lkdGggb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LCBvdmVycmlkaW5nIHRoZSBvcHRpb24gaW4gdGhlIGNoYXJ0IHNldHRpbmdzLidcclxuICAgIH0sXHJcbiAgICBzY2FsZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIHNjYWxlIG9mIHRoZSBleHBvcnRlZCBjaGFydCwgb3ZlcnJpZGluZyB0aGUgb3B0aW9uIGluIHRoZSBjaGFydCBzZXR0aW5ncy4gUmFuZ2VzIGJldHdlZW4gMC4xIGFuZCA1LjAuJ1xyXG4gICAgfSxcclxuICAgIGdsb2JhbE9wdGlvbnM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0VpdGhlciBhIHN0cmluZ2lmaWVkIEpTT04gb3IgYSBmaWxlbmFtZSBjb250YWluaW5nIG9wdGlvbnMgdG8gYmUgcGFzc2VkIGludG8gdGhlIEhpZ2hjaGFydHMuc2V0T3B0aW9ucy4nXHJcbiAgICB9LFxyXG4gICAgdGhlbWVPcHRpb25zOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdFaXRoZXIgYSBzdHJpbmdpZmllZCBKU09OIG9yIGEgZmlsZW5hbWUgY29udGFpbmluZyB0aGVtZSBvcHRpb25zIHRvIGJlIHBhc3NlZCBpbnRvIHRoZSBIaWdoY2hhcnRzLnNldE9wdGlvbnMuJ1xyXG4gICAgfSxcclxuICAgIGJhdGNoOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbml0aWF0ZXMgYSBiYXRjaCBqb2Igd2l0aCBhIHN0cmluZyBjb250YWluaW5nIGlucHV0L291dHB1dCBwYWlyczogXCJpbj1vdXQ7aW49b3V0Oy4uLlwiLidcclxuICAgIH0sXHJcbiAgICByYXN0ZXJpemF0aW9uVGltZW91dDoge1xyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX1JBU1RFUklaQVRJT05fVElNRU9VVCcsXHJcbiAgICAgIHZhbHVlOiAxNTAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiBpbiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgcmVuZGVyaW5nIGEgd2VicGFnZS4nXHJcbiAgICB9XHJcbiAgfSxcclxuICBjdXN0b21Mb2dpYzoge1xyXG4gICAgYWxsb3dDb2RlRXhlY3V0aW9uOiB7XHJcbiAgICAgIGVudkxpbms6ICdDVVNUT01fTE9HSUNfQUxMT1dfQ09ERV9FWEVDVVRJT04nLFxyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0NvbnRyb2xzIHdoZXRoZXIgdGhlIGV4ZWN1dGlvbiBvZiBhcmJpdHJhcnkgY29kZSBpcyBhbGxvd2VkIGR1cmluZyB0aGUgZXhwb3J0aW5nIHByb2Nlc3MuJ1xyXG4gICAgfSxcclxuICAgIGFsbG93RmlsZVJlc291cmNlczoge1xyXG4gICAgICBlbnZMaW5rOiAnQ1VTVE9NX0xPR0lDX0FMTE9XX0ZJTEVfUkVTT1VSQ0VTJyxcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdDb250cm9scyB0aGUgYWJpbGl0eSB0byBpbmplY3QgcmVzb3VyY2VzIGZyb20gdGhlIGZpbGVzeXN0ZW0uIFRoaXMgc2V0dGluZyBoYXMgbm8gZWZmZWN0IHdoZW4gcnVubmluZyBhcyBhIHNlcnZlci4nXHJcbiAgICB9LFxyXG4gICAgY3VzdG9tQ29kZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQ3VzdG9tIGNvZGUgdG8gZXhlY3V0ZSBiZWZvcmUgY2hhcnQgaW5pdGlhbGl6YXRpb24uIEl0IGNhbiBiZSBhIGZ1bmN0aW9uLCBjb2RlIHdyYXBwZWQgd2l0aGluIGEgZnVuY3Rpb24sIG9yIGEgZmlsZW5hbWUgd2l0aCB0aGUgLmpzIGV4dGVuc2lvbi4nXHJcbiAgICB9LFxyXG4gICAgY2FsbGJhY2s6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0phdmFTY3JpcHQgY29kZSB0byBydW4gZHVyaW5nIGNvbnN0cnVjdGlvbi4gSXQgY2FuIGJlIGEgZnVuY3Rpb24gb3IgYSBmaWxlbmFtZSB3aXRoIHRoZSAuanMgZXh0ZW5zaW9uLidcclxuICAgIH0sXHJcbiAgICByZXNvdXJjZXM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0FkZGl0aW9uYWwgcmVzb3VyY2UgaW4gdGhlIGZvcm0gb2YgYSBzdHJpbmdpZmllZCBKU09OLCB3aGljaCBtYXkgY29udGFpbiBmaWxlcywganMsIGFuZCBjc3Mgc2VjdGlvbnMuJ1xyXG4gICAgfSxcclxuICAgIGxvYWRDb25maWc6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgbGVnYWN5TmFtZTogJ2Zyb21GaWxlJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdBIGZpbGUgY29udGFpbmluZyBhIHByZS1kZWZpbmVkIGNvbmZpZ3VyYXRpb24gdG8gdXNlLidcclxuICAgIH0sXHJcbiAgICBjcmVhdGVDb25maWc6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0VuYWJsZXMgc2V0dGluZyBvcHRpb25zIHRocm91Z2ggYSBwcm9tcHQgYW5kIHNhdmluZyB0aGVtIGluIGEgcHJvdmlkZWQgY29uZmlnIGZpbGUuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgc2VydmVyOiB7XHJcbiAgICBlbmFibGU6IHtcclxuICAgICAgZW52TGluazogJ1NFUlZFUl9FTkFCTEUnLFxyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgY2xpTmFtZTogJ2VuYWJsZVNlcnZlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdXaGVuIHNldCB0byB0cnVlLCB0aGUgc2VydmVyIHN0YXJ0cyBvbiB0aGUgbG9jYWwgSVAgYWRkcmVzcyAwLjAuMC4wLidcclxuICAgIH0sXHJcbiAgICBob3N0OiB7XHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfSE9TVCcsXHJcbiAgICAgIHZhbHVlOiAnMC4wLjAuMCcsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGhvc3RuYW1lIG9mIHRoZSBzZXJ2ZXIuIEFkZGl0aW9uYWxseSwgaXQgc3RhcnRzIGEgc2VydmVyIG9uIHRoZSBwcm92aWRlZCBob3N0bmFtZS4nXHJcbiAgICB9LFxyXG4gICAgcG9ydDoge1xyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX1BPUlQnLFxyXG4gICAgICB2YWx1ZTogNzgwMSxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHNlcnZlciBwb3J0IHdoZW4gZW5hYmxlZC4nXHJcbiAgICB9LFxyXG4gICAgYmVuY2htYXJraW5nOiB7XHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfQkVOQ0hNQVJLSU5HJyxcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGNsaU5hbWU6ICdzZXJ2ZXJCZW5jaG1hcmtpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSW5kaWNhdGVzIHdoZXRoZXIgdG8gZGlzcGxheSB0aGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgb2Ygc3BlY2lmaWMgYWN0aW9ucyB0aGF0IG9jY3VyIG9uIHRoZSBzZXJ2ZXIgd2hpbGUgc2VydmluZyBhIHJlcXVlc3QuJ1xyXG4gICAgfSxcclxuICAgIHNzbDoge1xyXG4gICAgICBlbmFibGU6IHtcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9FTkFCTEUnLFxyXG4gICAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgICAgY2xpTmFtZTogJ2VuYWJsZVNzbCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIG9yIGRpc2FibGVzIHRoZSBTU0wgcHJvdG9jb2wuJ1xyXG4gICAgICB9LFxyXG4gICAgICBmb3JjZToge1xyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfU1NMX0ZPUkNFJyxcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICAgIGNsaU5hbWU6ICdzc2xGb3JjZWQnLFxyXG4gICAgICAgIGxlZ2FjeU5hbWU6ICdzc2xPbmx5JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAgICdXaGVuIHNldCB0byB0cnVlLCB0aGUgc2VydmVyIGlzIGZvcmNlZCB0byBzZXJ2ZSBvbmx5IG92ZXIgSFRUUFMuJ1xyXG4gICAgICB9LFxyXG4gICAgICBwb3J0OiB7XHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfUE9SVCcsXHJcbiAgICAgICAgdmFsdWU6IDQ0MyxcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgICBjbGlOYW1lOiAnc3NsUG9ydCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgcG9ydCBvbiB3aGljaCB0byBydW4gdGhlIFNTTCBzZXJ2ZXIuJ1xyXG4gICAgICB9LFxyXG4gICAgICBjZXJ0UGF0aDoge1xyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfU1NMX0NFUlRfUEFUSCcsXHJcbiAgICAgICAgdmFsdWU6ICcnLFxyXG4gICAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICAgIGxlZ2FjeU5hbWU6ICdzc2xQYXRoJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSBwYXRoIHRvIHRoZSBTU0wgY2VydGlmaWNhdGUva2V5IGZpbGUuJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgcmF0ZUxpbWl0aW5nOiB7XHJcbiAgICAgIGVuYWJsZToge1xyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19FTkFCTEUnLFxyXG4gICAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgICAgY2xpTmFtZTogJ2VuYWJsZVJhdGVMaW1pdGluZycsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIHJhdGUgbGltaXRpbmcgZm9yIHRoZSBzZXJ2ZXIuJ1xyXG4gICAgICB9LFxyXG4gICAgICBtYXhSZXF1ZXN0czoge1xyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19NQVhfUkVRVUVTVFMnLFxyXG4gICAgICAgIHZhbHVlOiAxMCxcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgICBsZWdhY3lOYW1lOiAncmF0ZUxpbWl0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSBtYXhpbXVtIG51bWJlciBvZiByZXF1ZXN0cyBhbGxvd2VkIGluIG9uZSBtaW51dGUuJ1xyXG4gICAgICB9LFxyXG4gICAgICB3aW5kb3c6IHtcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfV0lORE9XJyxcclxuICAgICAgICB2YWx1ZTogMSxcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSB0aW1lIHdpbmRvdywgaW4gbWludXRlcywgZm9yIHRoZSByYXRlIGxpbWl0aW5nLidcclxuICAgICAgfSxcclxuICAgICAgZGVsYXk6IHtcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfREVMQVknLFxyXG4gICAgICAgIHZhbHVlOiAwLFxyXG4gICAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICAgJ1RoZSBkZWxheSBkdXJhdGlvbiBmb3IgZWFjaCBzdWNjZXNzaXZlIHJlcXVlc3QgYmVmb3JlIHJlYWNoaW5nIHRoZSBtYXhpbXVtIGxpbWl0LidcclxuICAgICAgfSxcclxuICAgICAgdHJ1c3RQcm94eToge1xyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19UUlVTVF9QUk9YWScsXHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1NldCB0aGlzIHRvIHRydWUgaWYgdGhlIHNlcnZlciBpcyBiZWhpbmQgYSBsb2FkIGJhbGFuY2VyLidcclxuICAgICAgfSxcclxuICAgICAgc2tpcEtleToge1xyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX0tFWScsXHJcbiAgICAgICAgdmFsdWU6ICcnLFxyXG4gICAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICAgJ0FsbG93cyBieXBhc3NpbmcgdGhlIHJhdGUgbGltaXRlciBhbmQgc2hvdWxkIGJlIHByb3ZpZGVkIHdpdGggdGhlIHNraXBUb2tlbiBhcmd1bWVudC4nXHJcbiAgICAgIH0sXHJcbiAgICAgIHNraXBUb2tlbjoge1xyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX1RPS0VOJyxcclxuICAgICAgICB2YWx1ZTogJycsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgICAnQWxsb3dzIGJ5cGFzc2luZyB0aGUgcmF0ZSBsaW1pdGVyIGFuZCBzaG91bGQgYmUgcHJvdmlkZWQgd2l0aCB0aGUgc2tpcEtleSBhcmd1bWVudC4nXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIHBvb2w6IHtcclxuICAgIG1pbldvcmtlcnM6IHtcclxuICAgICAgZW52TGluazogJ1BPT0xfTUlOX1dPUktFUlMnLFxyXG4gICAgICB2YWx1ZTogNCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIG51bWJlciBvZiBtaW5pbXVtIGFuZCBpbml0aWFsIHBvb2wgd29ya2VycyB0byBzcGF3bi4nXHJcbiAgICB9LFxyXG4gICAgbWF4V29ya2Vyczoge1xyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9NQVhfV09SS0VSUycsXHJcbiAgICAgIHZhbHVlOiA4LFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbGVnYWN5TmFtZTogJ3dvcmtlcnMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBudW1iZXIgb2YgbWF4aW11bSBwb29sIHdvcmtlcnMgdG8gc3Bhd24uJ1xyXG4gICAgfSxcclxuICAgIHdvcmtMaW1pdDoge1xyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9XT1JLX0xJTUlUJyxcclxuICAgICAgdmFsdWU6IDQwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBudW1iZXIgb2Ygd29yayBwaWVjZXMgdGhhdCBjYW4gYmUgcGVyZm9ybWVkIGJlZm9yZSByZXN0YXJ0aW5nIHRoZSB3b3JrZXIgcHJvY2Vzcy4nXHJcbiAgICB9LFxyXG4gICAgYWNxdWlyZVRpbWVvdXQ6IHtcclxuICAgICAgZW52TGluazogJ1BPT0xfQUNRVUlSRV9USU1FT1VUJyxcclxuICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGR1cmF0aW9uLCBpbiBtaWxsaXNlY29uZHMsIHRvIHdhaXQgZm9yIGFjcXVpcmluZyBhIHJlc291cmNlLidcclxuICAgIH0sXHJcbiAgICBjcmVhdGVUaW1lb3V0OiB7XHJcbiAgICAgIGVudkxpbms6ICdQT09MX0NSRUFURV9USU1FT1VUJyxcclxuICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGR1cmF0aW9uLCBpbiBtaWxsaXNlY29uZHMsIHRvIHdhaXQgZm9yIGNyZWF0aW5nIGEgcmVzb3VyY2UuJ1xyXG4gICAgfSxcclxuICAgIGRlc3Ryb3lUaW1lb3V0OiB7XHJcbiAgICAgIGVudkxpbms6ICdQT09MX0RFU1RST1lfVElNRU9VVCcsXHJcbiAgICAgIHZhbHVlOiA1MDAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCB0byB3YWl0IGZvciBkZXN0cm95aW5nIGEgcmVzb3VyY2UuJ1xyXG4gICAgfSxcclxuICAgIGlkbGVUaW1lb3V0OiB7XHJcbiAgICAgIGVudkxpbms6ICdQT09MX0lETEVfVElNRU9VVCcsXHJcbiAgICAgIHZhbHVlOiAzMDAwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgYWZ0ZXIgd2hpY2ggYW4gaWRsZSByZXNvdXJjZSBpcyBkZXN0cm95ZWQuJ1xyXG4gICAgfSxcclxuICAgIGNyZWF0ZVJldHJ5SW50ZXJ2YWw6IHtcclxuICAgICAgZW52TGluazogJ1BPT0xfQ1JFQVRFX1JFVFJZX0lOVEVSVkFMJyxcclxuICAgICAgdmFsdWU6IDIwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgdG8gd2FpdCBiZWZvcmUgcmV0cnlpbmcgdGhlIGNyZWF0ZSBwcm9jZXNzIGluIGNhc2Ugb2YgYSBmYWlsdXJlLidcclxuICAgIH0sXHJcbiAgICByZWFwZXJJbnRlcnZhbDoge1xyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9SRUFQRVJfSU5URVJWQUwnLFxyXG4gICAgICB2YWx1ZTogMTAwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgYWZ0ZXIgd2hpY2ggdGhlIGNoZWNrIGZvciBpZGxlIHJlc291cmNlcyB0byBkZXN0cm95IGlzIHRyaWdnZXJlZC4nXHJcbiAgICB9LFxyXG4gICAgYmVuY2htYXJraW5nOiB7XHJcbiAgICAgIGVudkxpbms6ICdQT09MX0JFTkNITUFSS0lORycsXHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBjbGlOYW1lOiAncG9vbEJlbmNobWFya2luZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbmRpY2F0ZSB3aGV0aGVyIHRvIHNob3cgc3RhdGlzdGljcyBmb3IgdGhlIHBvb2wgb2YgcmVzb3VyY2VzIG9yIG5vdC4nXHJcbiAgICB9LFxyXG4gICAgbGlzdGVuVG9Qcm9jZXNzRXhpdHM6IHtcclxuICAgICAgZW52TGluazogJ1BPT0xfTElTVEVOX1RPX1BST0NFU1NfRVhJVFMnLFxyXG4gICAgICB2YWx1ZTogdHJ1ZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0RlY2lkZXMgd2hldGhlciBvciBub3QgdG8gYXR0YWNoIHByb2Nlc3MuZXhpdCBoYW5kbGVycy4nXHJcbiAgICB9XHJcbiAgfSxcclxuICBsb2dnaW5nOiB7XHJcbiAgICBsZXZlbDoge1xyXG4gICAgICBlbnZMaW5rOiAnTE9HR0lOR19MRVZFTCcsXHJcbiAgICAgIHZhbHVlOiA0LFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgY2xpTmFtZTogJ2xvZ0xldmVsJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgbG9nZ2luZyBsZXZlbCB0byBiZSB1c2VkLidcclxuICAgIH0sXHJcbiAgICBmaWxlOiB7XHJcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX0ZJTEUnLFxyXG4gICAgICB2YWx1ZTogJ2hpZ2hjaGFydHMtZXhwb3J0LXNlcnZlci5sb2cnLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgY2xpTmFtZTogJ2xvZ0ZpbGUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIG5hbWUgb2YgYSBsb2cgZmlsZS4gVGhlIGxvZ0Rlc3Qgb3B0aW9uIGFsc28gbmVlZHMgdG8gYmUgc2V0IHRvIGVuYWJsZSBmaWxlIGxvZ2dpbmcuJ1xyXG4gICAgfSxcclxuICAgIGRlc3Q6IHtcclxuICAgICAgZW52TGluazogJ0xPR0dJTkdfREVTVCcsXHJcbiAgICAgIHZhbHVlOiAnbG9nLycsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBjbGlOYW1lOiAnbG9nRGVzdCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgcGF0aCB0byBzdG9yZSBsb2cgZmlsZXMuIFRoaXMgYWxzbyBlbmFibGVzIGZpbGUgbG9nZ2luZy4nXHJcbiAgICB9XHJcbiAgfSxcclxuICB1aToge1xyXG4gICAgZW5hYmxlOiB7XHJcbiAgICAgIGVudkxpbms6ICdVSV9FTkFCTEUnLFxyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgY2xpTmFtZTogJ2VuYWJsZVVpJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0VuYWJsZXMgb3IgZGlzYWJsZXMgdGhlIHVzZXIgaW50ZXJmYWNlIChVSSkgZm9yIHRoZSBleHBvcnQgc2VydmVyLidcclxuICAgIH0sXHJcbiAgICByb3V0ZToge1xyXG4gICAgICBlbnZMaW5rOiAnVUlfUk9VVEUnLFxyXG4gICAgICB2YWx1ZTogJy8nLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgY2xpTmFtZTogJ3VpUm91dGUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGVuZHBvaW50IHJvdXRlIHRvIHdoaWNoIHRoZSB1c2VyIGludGVyZmFjZSAoVUkpIHNob3VsZCBiZSBhdHRhY2hlZC4nXHJcbiAgICB9XHJcbiAgfSxcclxuICBvdGhlcjoge1xyXG4gICAgbm9Mb2dvOiB7XHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9OT19MT0dPJyxcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdTa2lwIHByaW50aW5nIHRoZSBsb2dvIG9uIGEgc3RhcnR1cC4gV2lsbCBiZSByZXBsYWNlZCBieSBhIHNpbXBsZSB0ZXh0LidcclxuICAgIH1cclxuICB9XHJcbn07XHJcblxyXG4vLyBUaGUgY29uZmlnIGRlc2NyaXB0aW9ucyBvYmplY3QgZm9yIHRoZSBwcm9tcHRzIGZ1bmN0aW9uYWxpdHkuIEl0IGNvbnRhaW5zXHJcbi8vIGluZm9ybWF0aW9uIGxpa2U6XHJcbi8vICogVHlwZSBvZiBhIHByb21wdFxyXG4vLyAqIE5hbWUgb2YgYW4gb3B0aW9uXHJcbi8vICogU2hvcnQgZGVzY3JpcHRpb24gb2YgYSBjaG9zZW4gb3B0aW9uXHJcbi8vICogSW5pdGlhbCB2YWx1ZVxyXG5leHBvcnQgY29uc3QgcHJvbXB0c0NvbmZpZyA9IHtcclxuICBwdXBwZXRlZXI6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ2xpc3QnLFxyXG4gICAgICBuYW1lOiAnYXJncycsXHJcbiAgICAgIG1lc3NhZ2U6ICdQdXBwZXRlZXIgYXJndW1lbnRzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wdXBwZXRlZXIuYXJncy52YWx1ZS5qb2luKCcsJyksXHJcbiAgICAgIHNlcGFyYXRvcjogJywnXHJcbiAgICB9XHJcbiAgXSxcclxuICBoaWdoY2hhcnRzOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ3ZlcnNpb24nLFxyXG4gICAgICBtZXNzYWdlOiAnSGlnaGNoYXJ0cyB2ZXJzaW9uJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLnZlcnNpb24udmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ2NkblVSTCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgVVJMIG9mIENETicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5jZG5VUkwudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdtdWx0aXNlbGVjdCcsXHJcbiAgICAgIG5hbWU6ICdtb2R1bGVzJyxcclxuICAgICAgbWVzc2FnZTogJ0F2YWlsYWJsZSBtb2R1bGVzJyxcclxuICAgICAgaW5zdHJ1Y3Rpb25zOiAnU3BhY2U6IFNlbGVjdCBzcGVjaWZpYywgQTogU2VsZWN0IGFsbCwgRW50ZXI6IENvbmZpcm0uJyxcclxuICAgICAgY2hvaWNlczogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLm1vZHVsZXMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdsaXN0JyxcclxuICAgICAgbmFtZTogJ3NjcmlwdHMnLFxyXG4gICAgICBtZXNzYWdlOiAnQ3VzdG9tIHNjcmlwdHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuc2NyaXB0cy52YWx1ZS5qb2luKCcsJyksXHJcbiAgICAgIHNlcGFyYXRvcjogJywnXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2ZvcmNlRmV0Y2gnLFxyXG4gICAgICBtZXNzYWdlOiAnRm9yY2UgcmUtZmV0Y2ggdGhlIHNjcmlwdHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuZm9yY2VGZXRjaC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnY2FjaGVQYXRoJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBwYXRoIHRvIHRoZSBjYWNoZSBkaXJlY3RvcnknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuY2FjaGVQYXRoLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBleHBvcnQ6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3NlbGVjdCcsXHJcbiAgICAgIG5hbWU6ICd0eXBlJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBkZWZhdWx0IGV4cG9ydCBmaWxlIHR5cGUnLFxyXG4gICAgICBoaW50OiBgRGVmYXVsdDogJHtkZWZhdWx0Q29uZmlnLmV4cG9ydC50eXBlLnZhbHVlfWAsXHJcbiAgICAgIGluaXRpYWw6IDAsXHJcbiAgICAgIGNob2ljZXM6IFsncG5nJywgJ2pwZWcnLCAncGRmJywgJ3N2ZyddXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnc2VsZWN0JyxcclxuICAgICAgbmFtZTogJ2NvbnN0cicsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgZGVmYXVsdCBjb25zdHJ1Y3RvciBmb3IgSGlnaGNoYXJ0cycsXHJcbiAgICAgIGhpbnQ6IGBEZWZhdWx0OiAke2RlZmF1bHRDb25maWcuZXhwb3J0LmNvbnN0ci52YWx1ZX1gLFxyXG4gICAgICBpbml0aWFsOiAwLFxyXG4gICAgICBjaG9pY2VzOiBbJ2NoYXJ0JywgJ3N0b2NrQ2hhcnQnLCAnbWFwQ2hhcnQnLCAnZ2FudHRDaGFydCddXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2RlZmF1bHRIZWlnaHQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgZmFsbGJhY2sgaGVpZ2h0IG9mIHRoZSBleHBvcnRlZCBjaGFydCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LmRlZmF1bHRIZWlnaHQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnZGVmYXVsdFdpZHRoJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBkZWZhdWx0IGZhbGxiYWNrIHdpZHRoIG9mIHRoZSBleHBvcnRlZCBjaGFydCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LmRlZmF1bHRXaWR0aC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdkZWZhdWx0U2NhbGUnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgZmFsbGJhY2sgc2NhbGUgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5leHBvcnQuZGVmYXVsdFNjYWxlLnZhbHVlLFxyXG4gICAgICBtaW46IDAuMSxcclxuICAgICAgbWF4OiA1XHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3Jhc3Rlcml6YXRpb25UaW1lb3V0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSByZW5kZXJpbmcgd2VicGFnZSB0aW1lb3V0IGluIG1pbGxpc2Vjb25kcycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LnJhc3Rlcml6YXRpb25UaW1lb3V0LnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBjdXN0b21Mb2dpYzogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2FsbG93Q29kZUV4ZWN1dGlvbicsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgZXhlY3V0aW9uIG9mIGN1c3RvbSBjb2RlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5jdXN0b21Mb2dpYy5hbGxvd0NvZGVFeGVjdXRpb24udmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnYWxsb3dGaWxlUmVzb3VyY2VzJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBmaWxlIHJlc291cmNlcycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuY3VzdG9tTG9naWMuYWxsb3dGaWxlUmVzb3VyY2VzLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBzZXJ2ZXI6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdlbmFibGUnLFxyXG4gICAgICBtZXNzYWdlOiAnU3RhcnRzIHRoZSBzZXJ2ZXIgb24gMC4wLjAuMCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLmVuYWJsZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnaG9zdCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdTZXJ2ZXIgaG9zdG5hbWUnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5ob3N0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3BvcnQnLFxyXG4gICAgICBtZXNzYWdlOiAnU2VydmVyIHBvcnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5wb3J0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2JlbmNobWFya2luZycsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgc2VydmVyIGJlbmNobWFya2luZycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLmJlbmNobWFya2luZy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdzc2wuZW5hYmxlJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBTU0wgcHJvdG9jb2wnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wuZW5hYmxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ3NzbC5mb3JjZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdGb3JjZSBzZXJ2aW5nIG9ubHkgb3ZlciBIVFRQUycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnNzbC5mb3JjZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdzc2wucG9ydCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdTU0wgc2VydmVyIHBvcnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wucG9ydC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnc3NsLmNlcnRQYXRoJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBwYXRoIHRvIGZpbmQgdGhlIFNTTCBjZXJ0aWZpY2F0ZS9rZXknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wuY2VydFBhdGgudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLmVuYWJsZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgcmF0ZSBsaW1pdGluZycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy5lbmFibGUudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLm1heFJlcXVlc3RzJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBtYXhpbXVtIHJlcXVlc3RzIGFsbG93ZWQgcGVyIG1pbnV0ZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy5tYXhSZXF1ZXN0cy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcud2luZG93JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSByYXRlLWxpbWl0aW5nIHRpbWUgd2luZG93IGluIG1pbnV0ZXMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcud2luZG93LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5kZWxheScsXHJcbiAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgJ1RoZSBkZWxheSBmb3IgZWFjaCBzdWNjZXNzaXZlIHJlcXVlc3QgYmVmb3JlIHJlYWNoaW5nIHRoZSBtYXhpbXVtJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLmRlbGF5LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy50cnVzdFByb3h5JyxcclxuICAgICAgbWVzc2FnZTogJ1NldCB0byB0cnVlIGlmIGJlaGluZCBhIGxvYWQgYmFsYW5jZXInLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcudHJ1c3RQcm94eS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLnNraXBLZXknLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdBbGxvd3MgYnlwYXNzaW5nIHRoZSByYXRlIGxpbWl0ZXIgd2hlbiBwcm92aWRlZCB3aXRoIHRoZSBza2lwVG9rZW4gYXJndW1lbnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcuc2tpcEtleS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLnNraXBUb2tlbicsXHJcbiAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgJ0FsbG93cyBieXBhc3NpbmcgdGhlIHJhdGUgbGltaXRlciB3aGVuIHByb3ZpZGVkIHdpdGggdGhlIHNraXBLZXkgYXJndW1lbnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcuc2tpcFRva2VuLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBwb29sOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnbWluV29ya2VycycsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgaW5pdGlhbCBudW1iZXIgb2Ygd29ya2VycyB0byBzcGF3bicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5taW5Xb3JrZXJzLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ21heFdvcmtlcnMnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIG1heGltdW0gbnVtYmVyIG9mIHdvcmtlcnMgdG8gc3Bhd24nLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wubWF4V29ya2Vycy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICd3b3JrTGltaXQnLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdUaGUgcGllY2VzIG9mIHdvcmsgdGhhdCBjYW4gYmUgcGVyZm9ybWVkIGJlZm9yZSByZXN0YXJ0aW5nIGEgUHVwcGV0ZWVyIHByb2Nlc3MnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wud29ya0xpbWl0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2FjcXVpcmVUaW1lb3V0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIHRvIHdhaXQgZm9yIGFjcXVpcmluZyBhIHJlc291cmNlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmFjcXVpcmVUaW1lb3V0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2NyZWF0ZVRpbWVvdXQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgY3JlYXRpbmcgYSByZXNvdXJjZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5jcmVhdGVUaW1lb3V0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2Rlc3Ryb3lUaW1lb3V0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIHRvIHdhaXQgZm9yIGRlc3Ryb3lpbmcgYSByZXNvdXJjZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5kZXN0cm95VGltZW91dC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdpZGxlVGltZW91dCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcyBhZnRlciBhbiBpZGxlIHJlc291cmNlIGlzIGRlc3Ryb3llZCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5pZGxlVGltZW91dC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdjcmVhdGVSZXRyeUludGVydmFsJyxcclxuICAgICAgbWVzc2FnZTpcclxuICAgICAgICAnVGhlIHJldHJ5IGludGVydmFsIGluIG1pbGxpc2Vjb25kcyBhZnRlciBhIGNyZWF0ZSBwcm9jZXNzIGZhaWxzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmNyZWF0ZVJldHJ5SW50ZXJ2YWwudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncmVhcGVySW50ZXJ2YWwnLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdUaGUgcmVhcGVyIGludGVydmFsIGluIG1pbGxpc2Vjb25kcyBhZnRlciB0cmlnZ2VyaW5nIHRoZSBjaGVjayBmb3IgaWRsZSByZXNvdXJjZXMgdG8gZGVzdHJveScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5yZWFwZXJJbnRlcnZhbC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdiZW5jaG1hcmtpbmcnLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIGJlbmNobWFya2luZyBmb3IgYSByZXNvdXJjZSBwb29sJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmJlbmNobWFya2luZy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdsaXN0ZW5Ub1Byb2Nlc3NFeGl0cycsXHJcbiAgICAgIG1lc3NhZ2U6ICdTZXQgdG8gZmFsc2UgdG8gc2tpcCBhdHRhY2hpbmcgcHJvY2Vzcy5leGl0IGhhbmRsZXJzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmxpc3RlblRvUHJvY2Vzc0V4aXRzLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBsb2dnaW5nOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnbGV2ZWwnLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdUaGUgbG9nIGxldmVsICgwOiBzaWxlbnQsIDE6IGVycm9yLCAyOiB3YXJuaW5nLCAzOiBub3RpY2UsIDQ6IHZlcmJvc2UsIDU6IGJlbmNobWFyayknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmxvZ2dpbmcubGV2ZWwudmFsdWUsXHJcbiAgICAgIHJvdW5kOiAwLFxyXG4gICAgICBtaW46IDAsXHJcbiAgICAgIG1heDogNVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnZmlsZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdBIGxvZyBmaWxlIG5hbWUuIFNldCB3aXRoIHRoZSAtLWxvZ0Rlc3QgdG8gZW5hYmxlIGZpbGUgbG9nZ2luZycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcubG9nZ2luZy5maWxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdkZXN0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBwYXRoIHRvIGxvZyBmaWxlcy4gRW5hYmxlcyBmaWxlIGxvZ2dpbmcnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmxvZ2dpbmcuZGVzdC52YWx1ZVxyXG4gICAgfVxyXG4gIF0sXHJcbiAgdWk6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdlbmFibGUnLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIFVJIGZvciB0aGUgZXhwb3J0IHNlcnZlcicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcudWkuZW5hYmxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdyb3V0ZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdBIHJvdXRlIHRvIGF0dGFjaCB0aGUgVUknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnVpLnJvdXRlLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBvdGhlcjogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ25vTG9nbycsXHJcbiAgICAgIG1lc3NhZ2U6ICdTa2lwIHByaW50aW5nIHRoZSBsb2dvIG9uIHN0YXJ0dXAuIFJlcGxhY2VkIGJ5IHNpbXBsZSB0ZXh0JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5vdGhlci5ub0xvZ28udmFsdWVcclxuICAgIH1cclxuICBdXHJcbn07XHJcblxyXG4vLyBBYnNvbHV0ZSBwcm9wcyB0aGF0LCBpbiBjYXNlIG9mIG1lcmdpbmcgcmVjdXJzaXZlbHksIG5lZWQgdG8gYmUgZm9yY2UgbWVyZ2VkXHJcbmV4cG9ydCBjb25zdCBhYnNvbHV0ZVByb3BzID0gW1xyXG4gICdvcHRpb25zJyxcclxuICAnZ2xvYmFsT3B0aW9ucycsXHJcbiAgJ3RoZW1lT3B0aW9ucycsXHJcbiAgJ3Jlc291cmNlcycsXHJcbiAgJ3BheWxvYWQnXHJcbl07XHJcblxyXG4vLyBBcmd1bWVudCBuZXN0aW5nIGxldmVsIG9mIGFsbCBleHBvcnQgc2VydmVyIG9wdGlvbnNcclxuZXhwb3J0IGNvbnN0IG5lc3RlZEFyZ3MgPSB7fTtcclxuXHJcbi8qKlxyXG4gKiBSZWN1cnNpdmVseSBjcmVhdGVzIGEgY2hhaW4gb2YgbmVzdGVkIGFyZ3VtZW50cyBmcm9tIGFuIG9iamVjdC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9iaiAtIFRoZSBvYmplY3QgY29udGFpbmluZyBuZXN0ZWQgYXJndW1lbnRzLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcHJvcENoYWluIC0gVGhlIGN1cnJlbnQgY2hhaW4gb2YgbmVzdGVkIHByb3BlcnRpZXNcclxuICogKHVzZWQgaW50ZXJuYWxseSBkdXJpbmcgcmVjdXJzaW9uKS5cclxuICovXHJcbmNvbnN0IGNyZWF0ZU5lc3RlZEFyZ3MgPSAob2JqLCBwcm9wQ2hhaW4gPSAnJykgPT4ge1xyXG4gIE9iamVjdC5rZXlzKG9iaikuZm9yRWFjaCgoaykgPT4ge1xyXG4gICAgaWYgKCFbJ3B1cHBldGVlcicsICdoaWdoY2hhcnRzJ10uaW5jbHVkZXMoaykpIHtcclxuICAgICAgY29uc3QgZW50cnkgPSBvYmpba107XHJcbiAgICAgIGlmICh0eXBlb2YgZW50cnkudmFsdWUgPT09ICd1bmRlZmluZWQnKSB7XHJcbiAgICAgICAgLy8gR28gZGVlcGVyIGluIHRoZSBuZXN0ZWQgYXJndW1lbnRzXHJcbiAgICAgICAgY3JlYXRlTmVzdGVkQXJncyhlbnRyeSwgYCR7cHJvcENoYWlufS4ke2t9YCk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgLy8gQ3JlYXRlIHRoZSBjaGFpbiBvZiBuZXN0ZWQgYXJndW1lbnRzXHJcbiAgICAgICAgbmVzdGVkQXJnc1tlbnRyeS5jbGlOYW1lIHx8IGtdID0gYCR7cHJvcENoYWlufS4ke2t9YC5zdWJzdHJpbmcoMSk7XHJcblxyXG4gICAgICAgIC8vIFN1cHBvcnQgZm9yIHRoZSBsZWdhY3ksIFBoYW50b21KUyBwcm9wZXJ0aWVzIG5hbWVzXHJcbiAgICAgICAgaWYgKGVudHJ5LmxlZ2FjeU5hbWUgIT09IHVuZGVmaW5lZCkge1xyXG4gICAgICAgICAgbmVzdGVkQXJnc1tlbnRyeS5sZWdhY3lOYW1lXSA9IGAke3Byb3BDaGFpbn0uJHtrfWAuc3Vic3RyaW5nKDEpO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0pO1xyXG59O1xyXG5cclxuY3JlYXRlTmVzdGVkQXJncyhkZWZhdWx0Q29uZmlnKTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyBhcHBlbmRGaWxlLCBleGlzdHNTeW5jLCBta2RpclN5bmMgfSBmcm9tICdmcyc7XHJcblxyXG5pbXBvcnQgeyBkZWZhdWx0Q29uZmlnIH0gZnJvbSAnLi9zY2hlbWFzL2NvbmZpZy5qcyc7XHJcblxyXG4vLyBUaGUgYXZhaWxhYmxlIGNvbG9yc1xyXG5jb25zdCBjb2xvcnMgPSBbJ3JlZCcsICd5ZWxsb3cnLCAnYmx1ZScsICdncmF5JywgJ2dyZWVuJ107XHJcblxyXG4vLyBUaGUgZGVmYXVsdCBsb2dnaW5nIGNvbmZpZ1xyXG5sZXQgbG9nZ2luZyA9IHtcclxuICAvLyBGbGFncyBmb3IgbG9nZ2luZyBzdGF0dXNcclxuICB0b0NvbnNvbGU6IHRydWUsXHJcbiAgdG9GaWxlOiBmYWxzZSxcclxuICBwYXRoQ3JlYXRlZDogZmFsc2UsXHJcbiAgLy8gTG9nIGxldmVsc1xyXG4gIGxldmVsc0Rlc2M6IFtcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICdlcnJvcicsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbMF1cclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHRpdGxlOiAnd2FybmluZycsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbMV1cclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHRpdGxlOiAnbm90aWNlJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1syXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICd2ZXJib3NlJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1szXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICdiZW5jaG1hcmsnLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzRdXHJcbiAgICB9XHJcbiAgXSxcclxuICAvLyBMb2cgbGlzdGVuZXJzXHJcbiAgbGlzdGVuZXJzOiBbXVxyXG59O1xyXG5cclxuLy8gR2F0aGVyIGluaXQgbG9nZ2luZyBvcHRpb25zXHJcbmZvciAoY29uc3QgW2tleSwgb3B0aW9uXSBvZiBPYmplY3QuZW50cmllcyhkZWZhdWx0Q29uZmlnLmxvZ2dpbmcpKSB7XHJcbiAgbG9nZ2luZ1trZXldID0gb3B0aW9uLnZhbHVlO1xyXG59XHJcblxyXG4vKipcclxuICogTG9ncyB0aGUgcHJvdmlkZWQgdGV4dHMgdG8gYSBmaWxlLCBpZiBmaWxlIGxvZ2dpbmcgaXMgZW5hYmxlZC4gSXQgY3JlYXRlc1xyXG4gKiB0aGUgbmVjZXNzYXJ5IGRpcmVjdG9yeSBzdHJ1Y3R1cmUgaWYgbm90IGFscmVhZHkgY3JlYXRlZCBhbmQgYXBwZW5kcyB0aGVcclxuICogY29udGVudCwgaW5jbHVkaW5nIGFuIG9wdGlvbmFsIHByZWZpeCwgdG8gdGhlIHNwZWNpZmllZCBsb2cgZmlsZS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmdbXX0gdGV4dHMgLSBBbiBhcnJheSBvZiB0ZXh0cyB0byBiZSBsb2dnZWQuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwcmVmaXggLSBBbiBvcHRpb25hbCBwcmVmaXggdG8gYmUgYWRkZWQgdG8gZWFjaCBsb2cgZW50cnkuXHJcbiAqL1xyXG5jb25zdCBsb2dUb0ZpbGUgPSAodGV4dHMsIHByZWZpeCkgPT4ge1xyXG4gIGlmIChsb2dnaW5nLnRvRmlsZSkge1xyXG4gICAgaWYgKCFsb2dnaW5nLnBhdGhDcmVhdGVkKSB7XHJcbiAgICAgIC8vIENyZWF0ZSBpZiBkb2VzIG5vdCBleGlzdFxyXG4gICAgICAhZXhpc3RzU3luYyhsb2dnaW5nLmRlc3QpICYmIG1rZGlyU3luYyhsb2dnaW5nLmRlc3QpO1xyXG5cclxuICAgICAgLy8gV2Ugbm93IGFzc3VtZSB0aGUgcGF0aCBpcyBhdmFpbGFibGUsIGUuZy4gaXQncyB0aGUgcmVzcG9uc2liaWxpdHlcclxuICAgICAgLy8gb2YgdGhlIHVzZXIgdG8gY3JlYXRlIHRoZSBwYXRoIHdpdGggdGhlIGNvcnJlY3QgYWNjZXNzIHJpZ2h0cy5cclxuICAgICAgbG9nZ2luZy5wYXRoQ3JlYXRlZCA9IHRydWU7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQWRkIHRoZSBjb250ZW50IHRvIGEgZmlsZVxyXG4gICAgYXBwZW5kRmlsZShcclxuICAgICAgYCR7bG9nZ2luZy5kZXN0fSR7bG9nZ2luZy5maWxlfWAsXHJcbiAgICAgIFtwcmVmaXhdLmNvbmNhdCh0ZXh0cykuam9pbignICcpICsgJ1xcbicsXHJcbiAgICAgIChlcnJvcikgPT4ge1xyXG4gICAgICAgIGlmIChlcnJvcikge1xyXG4gICAgICAgICAgY29uc29sZS5sb2coYFtsb2dnZXJdIFVuYWJsZSB0byB3cml0ZSB0byBsb2cgZmlsZTogJHtlcnJvcn1gKTtcclxuICAgICAgICAgIGxvZ2dpbmcudG9GaWxlID0gZmFsc2U7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICApO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBMb2dzIGEgbWVzc2FnZS4gQWNjZXB0cyBhIHZhcmlhYmxlIGFtb3VudCBvZiBhcmd1bWVudHMuIEFyZ3VtZW50cyBhZnRlclxyXG4gKiBgbGV2ZWxgIHdpbGwgYmUgcGFzc2VkIGRpcmVjdGx5IHRvIGNvbnNvbGUubG9nLCBhbmQvb3Igd2lsbCBiZSBqb2luZWRcclxuICogYW5kIGFwcGVuZGVkIHRvIHRoZSBsb2cgZmlsZS5cclxuICpcclxuICogQHBhcmFtIHthbnl9IGFyZ3MgLSBBbiBhcnJheSBvZiBhcmd1bWVudHMgd2hlcmUgdGhlIGZpcnN0IGlzIHRoZSBsb2cgbGV2ZWxcclxuICogYW5kIHRoZSByZXN0IGFyZSBzdHJpbmdzIHRvIGJ1aWxkIGEgbWVzc2FnZSB3aXRoLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGxvZyA9ICguLi5hcmdzKSA9PiB7XHJcbiAgY29uc3QgW25ld0xldmVsLCAuLi50ZXh0c10gPSBhcmdzO1xyXG5cclxuICAvLyBDdXJyZW50IGxvZ2dpbmcgb3B0aW9uc1xyXG4gIGNvbnN0IHsgbGV2ZWwsIGxldmVsc0Rlc2MgfSA9IGxvZ2dpbmc7XHJcblxyXG4gIC8vIENoZWNrIGlmIGxvZyBsZXZlbCBpcyB3aXRoaW4gYSBjb3JyZWN0IHJhbmdlIG9yIGlzIGEgYmVuY2htYXJrIGxvZ1xyXG4gIGlmIChcclxuICAgIG5ld0xldmVsICE9PSA1ICYmXHJcbiAgICAobmV3TGV2ZWwgPT09IDAgfHwgbmV3TGV2ZWwgPiBsZXZlbCB8fCBsZXZlbCA+IGxldmVsc0Rlc2MubGVuZ3RoKVxyXG4gICkge1xyXG4gICAgcmV0dXJuO1xyXG4gIH1cclxuXHJcbiAgLy8gR2V0IHJpZCBvZiB0aGUgR01UIHRleHQgaW5mb3JtYXRpb25cclxuICBjb25zdCBuZXdEYXRlID0gbmV3IERhdGUoKS50b1N0cmluZygpLnNwbGl0KCcoJylbMF0udHJpbSgpO1xyXG5cclxuICAvLyBDcmVhdGUgYSBtZXNzYWdlJ3MgcHJlZml4XHJcbiAgY29uc3QgcHJlZml4ID0gYCR7bmV3RGF0ZX0gWyR7bGV2ZWxzRGVzY1tuZXdMZXZlbCAtIDFdLnRpdGxlfV0gLWA7XHJcblxyXG4gIC8vIENhbGwgYXZhaWxhYmxlIGxvZyBsaXN0ZW5lcnNcclxuICBsb2dnaW5nLmxpc3RlbmVycy5mb3JFYWNoKChmbikgPT4ge1xyXG4gICAgZm4ocHJlZml4LCB0ZXh0cy5qb2luKCcgJykpO1xyXG4gIH0pO1xyXG5cclxuICAvLyBMb2cgdG8gY29uc29sZVxyXG4gIGlmIChsb2dnaW5nLnRvQ29uc29sZSkge1xyXG4gICAgY29uc29sZS5sb2cuYXBwbHkoXHJcbiAgICAgIHVuZGVmaW5lZCxcclxuICAgICAgW3ByZWZpeC50b1N0cmluZygpW2xvZ2dpbmcubGV2ZWxzRGVzY1tuZXdMZXZlbCAtIDFdLmNvbG9yXV0uY29uY2F0KHRleHRzKVxyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIC8vIExvZyB0byBmaWxlXHJcbiAgbG9nVG9GaWxlKHRleHRzLCBwcmVmaXgpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIExvZ3MgYW4gZXJyb3IgbWVzc2FnZSB3aXRoIGl0cyBzdGFjayB0cmFjZS4gT3B0aW9uYWxseSwgYSBjdXN0b20gbWVzc2FnZVxyXG4gKiBjYW4gYmUgcHJvdmlkZWQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBsZXZlbCAtIFRoZSBsb2cgbGV2ZWwuXHJcbiAqIEBwYXJhbSB7RXJyb3J9IGVycm9yIC0gVGhlIGVycm9yIG9iamVjdC5cclxuICogQHBhcmFtIHtzdHJpbmd9IGN1c3RvbU1lc3NhZ2UgLSBBbiBvcHRpb25hbCBjdXN0b20gbWVzc2FnZSB0byBiZSBsb2dnZWQgYWxvbmdcclxuICogd2l0aCB0aGUgZXJyb3IuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbG9nV2l0aFN0YWNrID0gKG5ld0xldmVsLCBlcnJvciwgY3VzdG9tTWVzc2FnZSkgPT4ge1xyXG4gIC8vIEdldCB0aGUgbWFpbiBtZXNzYWdlXHJcbiAgY29uc3QgbWFpbk1lc3NhZ2UgPSBjdXN0b21NZXNzYWdlIHx8IGVycm9yLm1lc3NhZ2U7XHJcblxyXG4gIC8vIEN1cnJlbnQgbG9nZ2luZyBvcHRpb25zXHJcbiAgY29uc3QgeyBsZXZlbCwgbGV2ZWxzRGVzYyB9ID0gbG9nZ2luZztcclxuXHJcbiAgLy8gQ2hlY2sgaWYgbG9nIGxldmVsIGlzIHdpdGhpbiBhIGNvcnJlY3QgcmFuZ2VcclxuICBpZiAobmV3TGV2ZWwgPT09IDAgfHwgbmV3TGV2ZWwgPiBsZXZlbCB8fCBsZXZlbCA+IGxldmVsc0Rlc2MubGVuZ3RoKSB7XHJcbiAgICByZXR1cm47XHJcbiAgfVxyXG5cclxuICAvLyBHZXQgcmlkIG9mIHRoZSBHTVQgdGV4dCBpbmZvcm1hdGlvblxyXG4gIGNvbnN0IG5ld0RhdGUgPSBuZXcgRGF0ZSgpLnRvU3RyaW5nKCkuc3BsaXQoJygnKVswXS50cmltKCk7XHJcblxyXG4gIC8vIENyZWF0ZSBhIG1lc3NhZ2UncyBwcmVmaXhcclxuICBjb25zdCBwcmVmaXggPSBgJHtuZXdEYXRlfSBbJHtsZXZlbHNEZXNjW25ld0xldmVsIC0gMV0udGl0bGV9XSAtYDtcclxuXHJcbiAgLy8gSWYgdGhlIGN1c3RvbU1lc3NhZ2UgZXhpc3RzLCB3ZSB3YW50IHRvIGRpc3BsYXkgdGhlIHdob2xlIHN0YWNrIG1lc3NhZ2VcclxuICBjb25zdCBzdGFja01lc3NhZ2UgPVxyXG4gICAgZXJyb3IubWVzc2FnZSAhPT0gZXJyb3Iuc3RhY2tNZXNzYWdlIHx8IGVycm9yLnN0YWNrTWVzc2FnZSA9PT0gdW5kZWZpbmVkXHJcbiAgICAgID8gZXJyb3Iuc3RhY2tcclxuICAgICAgOiBlcnJvci5zdGFjay5zcGxpdCgnXFxuJykuc2xpY2UoMSkuam9pbignXFxuJyk7XHJcblxyXG4gIC8vIENvbWJpbmUgY3VzdG9tIG1lc3NhZ2Ugb3IgZXJyb3IgbWVzc2FnZSB3aXRoIGVycm9yIHN0YWNrIG1lc3NhZ2VcclxuICBjb25zdCB0ZXh0cyA9IFttYWluTWVzc2FnZSwgJ1xcbicsIHN0YWNrTWVzc2FnZV07XHJcblxyXG4gIC8vIExvZyB0byBjb25zb2xlXHJcbiAgaWYgKGxvZ2dpbmcudG9Db25zb2xlKSB7XHJcbiAgICBjb25zb2xlLmxvZy5hcHBseShcclxuICAgICAgdW5kZWZpbmVkLFxyXG4gICAgICBbcHJlZml4LnRvU3RyaW5nKClbbG9nZ2luZy5sZXZlbHNEZXNjW25ld0xldmVsIC0gMV0uY29sb3JdXS5jb25jYXQoW1xyXG4gICAgICAgIG1haW5NZXNzYWdlW2NvbG9yc1tuZXdMZXZlbCAtIDFdXSxcclxuICAgICAgICAnXFxuJyxcclxuICAgICAgICBzdGFja01lc3NhZ2VcclxuICAgICAgXSlcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICAvLyBDYWxsIGF2YWlsYWJsZSBsb2cgbGlzdGVuZXJzXHJcbiAgbG9nZ2luZy5saXN0ZW5lcnMuZm9yRWFjaCgoZm4pID0+IHtcclxuICAgIGZuKHByZWZpeCwgdGV4dHMuam9pbignICcpKTtcclxuICB9KTtcclxuXHJcbiAgLy8gTG9nIHRvIGZpbGVcclxuICBsb2dUb0ZpbGUodGV4dHMsIHByZWZpeCk7XHJcbn07XHJcblxyXG4vKipcclxuICogU2V0cyB0aGUgbG9nIGxldmVsIHRvIHRoZSBzcGVjaWZpZWQgdmFsdWUuIExvZyBsZXZlbHMgYXJlICgwID0gbm8gbG9nZ2luZyxcclxuICogMSA9IGVycm9yLCAyID0gd2FybmluZywgMyA9IG5vdGljZSwgNCA9IHZlcmJvc2Ugb3IgNSA9IGJlbmNobWFyaylcclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IG5ld0xldmVsIC0gVGhlIG5ldyBsb2cgbGV2ZWwgdG8gYmUgc2V0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHNldExvZ0xldmVsID0gKG5ld0xldmVsKSA9PiB7XHJcbiAgaWYgKG5ld0xldmVsID49IDAgJiYgbmV3TGV2ZWwgPD0gbG9nZ2luZy5sZXZlbHNEZXNjLmxlbmd0aCkge1xyXG4gICAgbG9nZ2luZy5sZXZlbCA9IG5ld0xldmVsO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBFbmFibGVzIGZpbGUgbG9nZ2luZyB3aXRoIHRoZSBzcGVjaWZpZWQgZGVzdGluYXRpb24gYW5kIGxvZyBmaWxlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gbG9nRGVzdCAtIFRoZSBkZXN0aW5hdGlvbiBwYXRoIGZvciBsb2cgZmlsZXMuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBsb2dGaWxlIC0gVGhlIGxvZyBmaWxlIG5hbWUuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZW5hYmxlRmlsZUxvZ2dpbmcgPSAobG9nRGVzdCwgbG9nRmlsZSkgPT4ge1xyXG4gIC8vIFVwZGF0ZSBsb2dnaW5nIG9wdGlvbnNcclxuICBsb2dnaW5nID0ge1xyXG4gICAgLi4ubG9nZ2luZyxcclxuICAgIGRlc3Q6IGxvZ0Rlc3QgfHwgbG9nZ2luZy5kZXN0LFxyXG4gICAgZmlsZTogbG9nRmlsZSB8fCBsb2dnaW5nLmZpbGUsXHJcbiAgICB0b0ZpbGU6IHRydWVcclxuICB9O1xyXG5cclxuICBpZiAobG9nZ2luZy5kZXN0Lmxlbmd0aCA9PT0gMCkge1xyXG4gICAgcmV0dXJuIGxvZygxLCAnW2xvZ2dlcl0gRmlsZSBsb2dnaW5nIGluaXRpYWxpemF0aW9uOiBubyBwYXRoIHN1cHBsaWVkLicpO1xyXG4gIH1cclxuXHJcbiAgaWYgKCFsb2dnaW5nLmRlc3QuZW5kc1dpdGgoJy8nKSkge1xyXG4gICAgbG9nZ2luZy5kZXN0ICs9ICcvJztcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgbG9nZ2luZyB3aXRoIHRoZSBzcGVjaWZpZWQgbG9nZ2luZyBjb25maWd1cmF0aW9uLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gbG9nZ2luZyAtIFRoZSBsb2dnaW5nIGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGluaXRMb2dnaW5nID0gKGxvZ2dpbmcpID0+IHtcclxuICAvLyBTZXQgdGhlIGxvZyBsZXZlbFxyXG4gIHNldExvZ0xldmVsKGxvZ2dpbmcgJiYgcGFyc2VJbnQobG9nZ2luZy5sZXZlbCkpO1xyXG5cclxuICAvLyBTZXQgdGhlIGxvZyBmaWxlIHBhdGggYW5kIG5hbWVcclxuICBpZiAobG9nZ2luZyAmJiBsb2dnaW5nLmRlc3QpIHtcclxuICAgIGVuYWJsZUZpbGVMb2dnaW5nKFxyXG4gICAgICBsb2dnaW5nLmRlc3QsXHJcbiAgICAgIGxvZ2dpbmcuZmlsZSB8fCAnaGlnaGNoYXJ0cy1leHBvcnQtc2VydmVyLmxvZydcclxuICAgICk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEFkZHMgYSBsaXN0ZW5lciBmdW5jdGlvbiB0byB0aGUgbG9nZ2luZyBzeXN0ZW0uXHJcbiAqXHJcbiAqIEBwYXJhbSB7ZnVuY3Rpb259IGZuIC0gVGhlIGxpc3RlbmVyIGZ1bmN0aW9uIHRvIGJlIGFkZGVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGxpc3RlbiA9IChmbikgPT4ge1xyXG4gIGxvZ2dpbmcubGlzdGVuZXJzLnB1c2goZm4pO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFRvZ2dsZXMgdGhlIHN0YW5kYXJkIG91dHB1dCAoY29uc29sZSkgbG9nZ2luZy5cclxuICpcclxuICogQHBhcmFtIHtib29sZWFufSBlbmFibGVkIC0gSWYgdHJ1ZSwgZW5hYmxlcyBjb25zb2xlIGxvZ2dpbmc7IGlmIGZhbHNlLFxyXG4gKiBkaXNhYmxlcyBpdC5cclxuICovXHJcbmV4cG9ydCBjb25zdCB0b2dnbGVTVERPdXQgPSAoZW5hYmxlZCkgPT4ge1xyXG4gIGxvZ2dpbmcudG9Db25zb2xlID0gZW5hYmxlZDtcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBsb2csXHJcbiAgbG9nV2l0aFN0YWNrLFxyXG4gIHNldExvZ0xldmVsLFxyXG4gIGVuYWJsZUZpbGVMb2dnaW5nLFxyXG4gIGluaXRMb2dnaW5nLFxyXG4gIGxpc3RlbixcclxuICB0b2dnbGVTVERPdXRcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuaW1wb3J0IHsgZmlsZVVSTFRvUGF0aCB9IGZyb20gJ3VybCc7XHJcblxyXG5pbXBvcnQgeyBkZWZhdWx0Q29uZmlnIH0gZnJvbSAnLi4vbGliL3NjaGVtYXMvY29uZmlnLmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcblxyXG5jb25zdCBNQVhfQkFDS09GRl9BVFRFTVBUUyA9IDY7XHJcblxyXG5leHBvcnQgY29uc3QgX19kaXJuYW1lID0gZmlsZVVSTFRvUGF0aChuZXcgVVJMKCcuLi8uJywgaW1wb3J0Lm1ldGEudXJsKSk7XHJcblxyXG4vKipcclxuICogQ2xlYXJzIGFuZCBzdGFuZGFyZGl6ZXMgdGV4dCBieSByZXBsYWNpbmcgbXVsdGlwbGUgY29uc2VjdXRpdmUgd2hpdGVzcGFjZVxyXG4gKiBjaGFyYWN0ZXJzIHdpdGggYSBzaW5nbGUgc3BhY2UgYW5kIHRyaW1taW5nIGFueSBsZWFkaW5nIG9yIHRyYWlsaW5nXHJcbiAqIHdoaXRlc3BhY2UuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0ZXh0IC0gVGhlIGlucHV0IHRleHQgdG8gYmUgY2xlYXJlZC5cclxuICogQHBhcmFtIHtSZWdFeHB9IFtydWxlPS9cXHNcXHMrL2ddIC0gVGhlIHJlZ3VsYXIgZXhwcmVzc2lvbiBydWxlIHRvIG1hdGNoXHJcbiAqIG11bHRpcGxlIGNvbnNlY3V0aXZlIHdoaXRlc3BhY2UgY2hhcmFjdGVycy5cclxuICogQHBhcmFtIHtzdHJpbmd9IFtyZXBsYWNlcj0nICddIC0gVGhlIHN0cmluZyB1c2VkIHRvIHJlcGxhY2UgbXVsdGlwbGVcclxuICogY29uc2VjdXRpdmUgd2hpdGVzcGFjZSBjaGFyYWN0ZXJzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSAtIFRoZSBjbGVhcmVkIGFuZCBzdGFuZGFyZGl6ZWQgdGV4dC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBjbGVhclRleHQgPSAodGV4dCwgcnVsZSA9IC9cXHNcXHMrL2csIHJlcGxhY2VyID0gJyAnKSA9PlxyXG4gIHRleHQucmVwbGFjZUFsbChydWxlLCByZXBsYWNlcikudHJpbSgpO1xyXG5cclxuLyoqXHJcbiAqIEltcGxlbWVudHMgYW4gZXhwb25lbnRpYWwgYmFja29mZiBzdHJhdGVneSBmb3IgcmV0cnlpbmcgYSBmdW5jdGlvbiB1bnRpbFxyXG4gKiBhIGNlcnRhaW4gbnVtYmVyIG9mIGF0dGVtcHRzIGFyZSByZWFjaGVkLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBmbiAtIFRoZSBmdW5jdGlvbiB0byBiZSByZXRyaWVkLlxyXG4gKiBAcGFyYW0ge251bWJlcn0gW2F0dGVtcHQ9MF0gLSBUaGUgY3VycmVudCBhdHRlbXB0IG51bWJlci5cclxuICogQHBhcmFtIHsuLi5hbnl9IGFyZ3MgLSBBcmd1bWVudHMgdG8gYmUgcGFzc2VkIHRvIHRoZSBmdW5jdGlvbi5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2V9IC0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIHJlc3VsdCBvZiB0aGUgZnVuY3Rpb25cclxuICogaWYgc3VjY2Vzc2Z1bC5cclxuICpcclxuICogQHRocm93cyB7RXJyb3J9IC0gVGhyb3dzIGFuIGVycm9yIGlmIHRoZSBtYXhpbXVtIG51bWJlciBvZiBhdHRlbXB0c1xyXG4gKiBpcyByZWFjaGVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGV4cEJhY2tvZmYgPSBhc3luYyAoZm4sIGF0dGVtcHQgPSAwLCAuLi5hcmdzKSA9PiB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIFRyeSB0byBjYWxsIHRoZSBmdW5jdGlvblxyXG4gICAgcmV0dXJuIGF3YWl0IGZuKC4uLmFyZ3MpO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAvLyBDYWxjdWxhdGUgZGVsYXkgaW4gbXNcclxuICAgIGNvbnN0IGRlbGF5SW5NcyA9IDIgKiogYXR0ZW1wdCAqIDEwMDA7XHJcblxyXG4gICAgLy8gSWYgdGhlIGF0dGVtcHQgZXhjZWVkcyB0aGUgbWF4aW11bSBhdHRlbXB0cyBvZiByZWFwZWF0LCB0aHJvdyBhbiBlcnJvclxyXG4gICAgaWYgKCsrYXR0ZW1wdCA+PSBNQVhfQkFDS09GRl9BVFRFTVBUUykge1xyXG4gICAgICB0aHJvdyBlcnJvcjtcclxuICAgIH1cclxuXHJcbiAgICAvLyBXYWl0IGdpdmVuIGFtb3VudCBvZiB0aW1lXHJcbiAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzcG9uc2UpID0+IHNldFRpbWVvdXQocmVzcG9uc2UsIGRlbGF5SW5NcykpO1xyXG4gICAgbG9nKFxyXG4gICAgICAzLFxyXG4gICAgICBgW3Bvb2xdIFdhaXRlZCAke2RlbGF5SW5Nc31tcyB1bnRpbCBuZXh0IGNhbGwgZm9yIHRoZSByZXNvdXJjZSBpZDogJHthcmdzWzBdfS5gXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFRyeSBhZ2FpblxyXG4gICAgcmV0dXJuIGV4cEJhY2tvZmYoZm4sIGF0dGVtcHQsIC4uLmFyZ3MpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBGaXhlcyB0aGUgZXhwb3J0IHR5cGUgYmFzZWQgb24gTUlNRSB0eXBlcyBhbmQgZmlsZSBleHRlbnNpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdHlwZSAtIFRoZSBvcmlnaW5hbCBleHBvcnQgdHlwZS5cclxuICogQHBhcmFtIHtzdHJpbmd9IG91dGZpbGUgLSBUaGUgZmlsZSBwYXRoIG9yIG5hbWUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IC0gVGhlIGNvcnJlY3RlZCBleHBvcnQgdHlwZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBmaXhUeXBlID0gKHR5cGUsIG91dGZpbGUpID0+IHtcclxuICAvLyBNSU1FIHR5cGVzXHJcbiAgY29uc3QgbWltZVR5cGVzID0ge1xyXG4gICAgJ2ltYWdlL3BuZyc6ICdwbmcnLFxyXG4gICAgJ2ltYWdlL2pwZWcnOiAnanBlZycsXHJcbiAgICAnYXBwbGljYXRpb24vcGRmJzogJ3BkZicsXHJcbiAgICAnaW1hZ2Uvc3ZnK3htbCc6ICdzdmcnXHJcbiAgfTtcclxuXHJcbiAgLy8gRm9ybWF0c1xyXG4gIGNvbnN0IGZvcm1hdHMgPSBbJ3BuZycsICdqcGVnJywgJ3BkZicsICdzdmcnXTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgdHlwZSBhbmQgb3V0ZmlsZSdzIGV4dGVuc2lvbnMgYXJlIHRoZSBzYW1lXHJcbiAgaWYgKG91dGZpbGUpIHtcclxuICAgIGNvbnN0IG91dFR5cGUgPSBvdXRmaWxlLnNwbGl0KCcuJykucG9wKCk7XHJcblxyXG4gICAgaWYgKG91dFR5cGUgPT09ICdqcGcnKSB7XHJcbiAgICAgIHR5cGUgPSAnanBlZyc7XHJcbiAgICB9IGVsc2UgaWYgKGZvcm1hdHMuaW5jbHVkZXMob3V0VHlwZSkgJiYgdHlwZSAhPT0gb3V0VHlwZSkge1xyXG4gICAgICB0eXBlID0gb3V0VHlwZTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiBhIGNvcnJlY3QgdHlwZVxyXG4gIHJldHVybiBtaW1lVHlwZXNbdHlwZV0gfHwgZm9ybWF0cy5maW5kKCh0KSA9PiB0ID09PSB0eXBlKSB8fCAncG5nJztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBIYW5kbGVzIGFuZCB2YWxpZGF0ZXMgcmVzb3VyY2VzIGZvciBleHBvcnQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fHN0cmluZ30gcmVzb3VyY2VzIC0gVGhlIHJlc291cmNlcyB0byBiZSBoYW5kbGVkLiBDYW4gYmUgZWl0aGVyXHJcbiAqIGEgSlNPTiBvYmplY3QsIHN0cmluZ2lmaWVkIEpTT04gb3IgYSBwYXRoIHRvIGEgSlNPTiBmaWxlLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RmlsZVJlc291cmNlcyAtIFdoZXRoZXIgdG8gYWxsb3cgbG9hZGluZyByZXNvdXJjZXMgZnJvbVxyXG4gKiBmaWxlcy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdHx1bmRlZmluZWR9IC0gVGhlIGhhbmRsZWQgcmVzb3VyY2VzIG9yIHVuZGVmaW5lZCBpZiBubyB2YWxpZFxyXG4gKiByZXNvdXJjZXMgYXJlIGZvdW5kLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGhhbmRsZVJlc291cmNlcyA9IChyZXNvdXJjZXMgPSBmYWxzZSwgYWxsb3dGaWxlUmVzb3VyY2VzKSA9PiB7XHJcbiAgY29uc3QgYWxsb3dlZFByb3BzID0gWydqcycsICdjc3MnLCAnZmlsZXMnXTtcclxuXHJcbiAgbGV0IGhhbmRsZWRSZXNvdXJjZXMgPSByZXNvdXJjZXM7XHJcbiAgbGV0IGNvcnJlY3RSZXNvdXJjZXMgPSBmYWxzZTtcclxuXHJcbiAgLy8gVHJ5IHRvIGxvYWQgcmVzb3VyY2VzIGZyb20gYSBmaWxlXHJcbiAgaWYgKGFsbG93RmlsZVJlc291cmNlcyAmJiByZXNvdXJjZXMuZW5kc1dpdGgoJy5qc29uJykpIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGhhbmRsZWRSZXNvdXJjZXMgPSBpc0NvcnJlY3RKU09OKHJlYWRGaWxlU3luYyhyZXNvdXJjZXMsICd1dGY4JykpO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgcmV0dXJuIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgYFtjbGldIE5vIHJlc291cmNlcyBmb3VuZC5gKTtcclxuICAgIH1cclxuICB9IGVsc2Uge1xyXG4gICAgLy8gVHJ5IHRvIGdldCBKU09OXHJcbiAgICBoYW5kbGVkUmVzb3VyY2VzID0gaXNDb3JyZWN0SlNPTihyZXNvdXJjZXMpO1xyXG5cclxuICAgIC8vIEdldCByaWQgb2YgdGhlIGZpbGVzIHNlY3Rpb25cclxuICAgIGlmIChoYW5kbGVkUmVzb3VyY2VzICYmICFhbGxvd0ZpbGVSZXNvdXJjZXMpIHtcclxuICAgICAgZGVsZXRlIGhhbmRsZWRSZXNvdXJjZXMuZmlsZXM7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBGaWx0ZXIgZnJvbSB1bm5lY2Vzc2FyeSBwcm9wZXJ0aWVzXHJcbiAgZm9yIChjb25zdCBwcm9wTmFtZSBpbiBoYW5kbGVkUmVzb3VyY2VzKSB7XHJcbiAgICBpZiAoIWFsbG93ZWRQcm9wcy5pbmNsdWRlcyhwcm9wTmFtZSkpIHtcclxuICAgICAgZGVsZXRlIGhhbmRsZWRSZXNvdXJjZXNbcHJvcE5hbWVdO1xyXG4gICAgfSBlbHNlIGlmICghY29ycmVjdFJlc291cmNlcykge1xyXG4gICAgICBjb3JyZWN0UmVzb3VyY2VzID0gdHJ1ZTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIENoZWNrIGlmIGF0IGxlYXN0IG9uZSBvZiBhbGxvd2VkIHByb3BlcnRpZXMgaXMgcHJlc2VudFxyXG4gIGlmICghY29ycmVjdFJlc291cmNlcykge1xyXG4gICAgcmV0dXJuIGxvZygzLCBgW2NsaV0gTm8gcmVzb3VyY2VzIGZvdW5kLmApO1xyXG4gIH1cclxuXHJcbiAgLy8gSGFuZGxlIGZpbGVzIHNlY3Rpb25cclxuICBpZiAoaGFuZGxlZFJlc291cmNlcy5maWxlcykge1xyXG4gICAgaGFuZGxlZFJlc291cmNlcy5maWxlcyA9IGhhbmRsZWRSZXNvdXJjZXMuZmlsZXMubWFwKChpdGVtKSA9PiBpdGVtLnRyaW0oKSk7XHJcbiAgICBpZiAoIWhhbmRsZWRSZXNvdXJjZXMuZmlsZXMgfHwgaGFuZGxlZFJlc291cmNlcy5maWxlcy5sZW5ndGggPD0gMCkge1xyXG4gICAgICBkZWxldGUgaGFuZGxlZFJlc291cmNlcy5maWxlcztcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiByZXNvdXJjZXNcclxuICByZXR1cm4gaGFuZGxlZFJlc291cmNlcztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBWYWxpZGF0ZXMgYW5kIHBhcnNlcyBKU09OIGRhdGEuIENoZWNrcyBpZiBwcm92aWRlZCBkYXRhIGlzIG9yIGNhblxyXG4gKiBiZSBhIGNvcnJlY3QgSlNPTi5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R8c3RyaW5nfSBkYXRhIC0gVGhlIEpTT04gZGF0YSB0byBiZSB2YWxpZGF0ZWQgYW5kIHBhcnNlZC5cclxuICogQHBhcmFtIHtib29sZWFufSB0b1N0cmluZyAtIFdoZXRoZXIgdG8gcmV0dXJuIGEgc3RyaW5naWZpZWQgcmVwcmVzZW50YXRpb25cclxuICogb2YgdGhlIHBhcnNlZCBKU09OLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fHN0cmluZ3xib29sZWFufSAtIFRoZSBwYXJzZWQgSlNPTiBvYmplY3QsIHN0cmluZ2lmaWVkIEpTT04sXHJcbiAqIG9yIGZhbHNlIGlmIHZhbGlkYXRpb24gZmFpbHMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gaXNDb3JyZWN0SlNPTihkYXRhLCB0b1N0cmluZykge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBHZXQgdGhlIHN0cmluZyByZXByZXNlbnRhdGlvbiBpZiBub3QgYWxyZWFkeSBiZWZvcmUgcGFyc2luZ1xyXG4gICAgY29uc3QgcGFyc2VkRGF0YSA9IEpTT04ucGFyc2UoXHJcbiAgICAgIHR5cGVvZiBkYXRhICE9PSAnc3RyaW5nJyA/IEpTT04uc3RyaW5naWZ5KGRhdGEpIDogZGF0YVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBSZXR1cm4gYSBzdHJpbmdpZmllZCByZXByZXNlbnRhdGlvbiBvZiBhIEpTT04gaWYgcmVxdWlyZWRcclxuICAgIGlmICh0eXBlb2YgcGFyc2VkRGF0YSAhPT0gJ3N0cmluZycgJiYgdG9TdHJpbmcpIHtcclxuICAgICAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KHBhcnNlZERhdGEpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFJldHVybiBhIEpTT05cclxuICAgIHJldHVybiBwYXJzZWREYXRhO1xyXG4gIH0gY2F0Y2gge1xyXG4gICAgcmV0dXJuIGZhbHNlO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gaXRlbSBpcyBhbiBvYmplY3QuXHJcbiAqXHJcbiAqIEBwYXJhbSB7YW55fSBpdGVtIC0gVGhlIGl0ZW0gdG8gYmUgY2hlY2tlZC5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IC0gVHJ1ZSBpZiB0aGUgaXRlbSBpcyBhbiBvYmplY3QsIGZhbHNlIG90aGVyd2lzZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBpc09iamVjdCA9IChpdGVtKSA9PlxyXG4gIHR5cGVvZiBpdGVtID09PSAnb2JqZWN0JyAmJiAhQXJyYXkuaXNBcnJheShpdGVtKSAmJiBpdGVtICE9PSBudWxsO1xyXG5cclxuLyoqXHJcbiAqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gb2JqZWN0IGlzIGVtcHR5LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gaXRlbSAtIFRoZSBvYmplY3QgdG8gYmUgY2hlY2tlZC5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IC0gVHJ1ZSBpZiB0aGUgb2JqZWN0IGlzIGVtcHR5LCBmYWxzZSBvdGhlcndpc2UuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaXNPYmplY3RFbXB0eSA9IChpdGVtKSA9PlxyXG4gIHR5cGVvZiBpdGVtID09PSAnb2JqZWN0JyAmJiBpdGVtICE9PSBudWxsICYmIE9iamVjdC5rZXlzKGl0ZW0pLmxlbmd0aCA9PT0gMDtcclxuXHJcbi8qKlxyXG4gKiBDaGVja3MgaWYgYSBwcml2YXRlIElQIHJhbmdlIFVSTCBpcyBmb3VuZCBpbiB0aGUgZ2l2ZW4gc3RyaW5nLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gaXRlbSAtIFRoZSBzdHJpbmcgdG8gYmUgY2hlY2tlZCBmb3IgYSBwcml2YXRlIElQIHJhbmdlIFVSTC5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IC0gVHJ1ZSBpZiBhIHByaXZhdGUgSVAgcmFuZ2UgVVJMIGlzIGZvdW5kLCBmYWxzZVxyXG4gKiBvdGhlcndpc2UuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaXNQcml2YXRlUmFuZ2VVcmxGb3VuZCA9IChpdGVtKSA9PiB7XHJcbiAgcmV0dXJuIFtcclxuICAgICdsb2NhbGhvc3QnLFxyXG4gICAgJygxMCkuKC4qKS4oLiopLiguKiknLFxyXG4gICAgJygxMjcpLiguKikuKC4qKS4oLiopJyxcclxuICAgICcoMTcyKS4oMVs2LTldfDJbMC05XXwzWzAtMV0pLiguKikuKC4qKScsXHJcbiAgICAnKDE5MikuKDE2OCkuKC4qKS4oLiopJ1xyXG4gIF0uc29tZSgoaXBSZWdFeCkgPT5cclxuICAgIGl0ZW0ubWF0Y2goYHhsaW5rOmhyZWY9XCIoPzooaHR0cDovL3xodHRwczovLykpPyR7aXBSZWdFeH1gKVxyXG4gICk7XHJcbn07XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhIGRlZXAgY29weSBvZiB0aGUgZ2l2ZW4gb2JqZWN0IG9yIGFycmF5LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdHxBcnJheX0gb2JqIC0gVGhlIG9iamVjdCBvciBhcnJheSB0byBiZSBkZWVwbHkgY29waWVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fEFycmF5fSAtIFRoZSBkZWVwIGNvcHkgb2YgdGhlIHByb3ZpZGVkIG9iamVjdCBvciBhcnJheS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBkZWVwQ29weSA9IChvYmopID0+IHtcclxuICBpZiAob2JqID09PSBudWxsIHx8IHR5cGVvZiBvYmogIT09ICdvYmplY3QnKSB7XHJcbiAgICByZXR1cm4gb2JqO1xyXG4gIH1cclxuXHJcbiAgY29uc3QgY29weSA9IEFycmF5LmlzQXJyYXkob2JqKSA/IFtdIDoge307XHJcblxyXG4gIGZvciAoY29uc3Qga2V5IGluIG9iaikge1xyXG4gICAgaWYgKE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChvYmosIGtleSkpIHtcclxuICAgICAgY29weVtrZXldID0gZGVlcENvcHkob2JqW2tleV0pO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcmV0dXJuIGNvcHk7XHJcbn07XHJcblxyXG4vKipcclxuICogQ29udmVydHMgdGhlIHByb3ZpZGVkIG9wdGlvbnMgb2JqZWN0IHRvIGEgSlNPTi1mb3JtYXR0ZWQgc3RyaW5nIHdpdGggdGhlXHJcbiAqIG9wdGlvbiB0byBwcmVzZXJ2ZSBmdW5jdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IHRvIGJlIGNvbnZlcnRlZCB0byBhIHN0cmluZy5cclxuICogQHBhcmFtIHtib29sZWFufSBhbGxvd0Z1bmN0aW9ucyAtIElmIHNldCB0byB0cnVlLCBmdW5jdGlvbnMgYXJlIHByZXNlcnZlZFxyXG4gKiBpbiB0aGUgb3V0cHV0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSAtIFRoZSBKU09OLWZvcm1hdHRlZCBzdHJpbmcgcmVwcmVzZW50aW5nIHRoZSBvcHRpb25zLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IG9wdGlvbnNTdHJpbmdpZnkgPSAob3B0aW9ucywgYWxsb3dGdW5jdGlvbnMpID0+IHtcclxuICBjb25zdCByZXBsYWNlckNhbGxiYWNrID0gKG5hbWUsIHZhbHVlKSA9PiB7XHJcbiAgICBpZiAodHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJykge1xyXG4gICAgICB2YWx1ZSA9IHZhbHVlLnRyaW0oKTtcclxuXHJcbiAgICAgIC8vIElmIGFsbG93RnVuY3Rpb25zIGlzIHNldCB0byB0cnVlLCBwcmVzZXJ2ZSBmdW5jdGlvbnNcclxuICAgICAgaWYgKFxyXG4gICAgICAgICh2YWx1ZS5zdGFydHNXaXRoKCdmdW5jdGlvbignKSB8fCB2YWx1ZS5zdGFydHNXaXRoKCdmdW5jdGlvbiAoJykpICYmXHJcbiAgICAgICAgdmFsdWUuZW5kc1dpdGgoJ30nKVxyXG4gICAgICApIHtcclxuICAgICAgICB2YWx1ZSA9IGFsbG93RnVuY3Rpb25zXHJcbiAgICAgICAgICA/IGBFWFBfRlVOJHsodmFsdWUgKyAnJykucmVwbGFjZUFsbCgvXFxufFxcdHxcXHIvZywgJyAnKX1FWFBfRlVOYFxyXG4gICAgICAgICAgOiB1bmRlZmluZWQ7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gdHlwZW9mIHZhbHVlID09PSAnZnVuY3Rpb24nXHJcbiAgICAgID8gYEVYUF9GVU4keyh2YWx1ZSArICcnKS5yZXBsYWNlQWxsKC9cXG58XFx0fFxcci9nLCAnICcpfUVYUF9GVU5gXHJcbiAgICAgIDogdmFsdWU7XHJcbiAgfTtcclxuXHJcbiAgLy8gU3RyaW5naWZ5IG9wdGlvbnMgYW5kIGlmIHJlcXVpcmVkLCByZXBsYWNlIHNwZWNpYWwgZnVuY3Rpb25zIG1hcmtzXHJcbiAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KG9wdGlvbnMsIHJlcGxhY2VyQ2FsbGJhY2spLnJlcGxhY2VBbGwoXHJcbiAgICAvXCJFWFBfRlVOfEVYUF9GVU5cIi9nLFxyXG4gICAgJydcclxuICApO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFByaW50cyB0aGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyIGxvZ28gYW5kIHZlcnNpb24gaW5mb3JtYXRpb24uXHJcbiAqXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gbm9Mb2dvIC0gSWYgdHJ1ZSwgb25seSBwcmludHMgdmVyc2lvbiBpbmZvcm1hdGlvbiB3aXRob3V0XHJcbiAqIHRoZSBsb2dvLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHByaW50TG9nbyA9IChub0xvZ28pID0+IHtcclxuICAvLyBHZXQgcGFja2FnZSB2ZXJzaW9uIGVpdGhlciBmcm9tIGVudiBvciBmcm9tIHBhY2thZ2UuanNvblxyXG4gIGNvbnN0IHBhY2thZ2VWZXJzaW9uID0gSlNPTi5wYXJzZShcclxuICAgIHJlYWRGaWxlU3luYyhqb2luKF9fZGlybmFtZSwgJ3BhY2thZ2UuanNvbicpKVxyXG4gICkudmVyc2lvbjtcclxuXHJcbiAgLy8gUHJpbnQgdGV4dCBvbmx5XHJcbiAgaWYgKG5vTG9nbykge1xyXG4gICAgY29uc29sZS5sb2coYFN0YXJ0aW5nIEhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlciB2JHtwYWNrYWdlVmVyc2lvbn0uLi5gKTtcclxuICAgIHJldHVybjtcclxuICB9XHJcblxyXG4gIC8vIFByaW50IHRoZSBsb2dvXHJcbiAgY29uc29sZS5sb2coXHJcbiAgICByZWFkRmlsZVN5bmMoX19kaXJuYW1lICsgJy9tc2cvc3RhcnR1cC5tc2cnKS50b1N0cmluZygpLmJvbGQueWVsbG93LFxyXG4gICAgYHYke3BhY2thZ2VWZXJzaW9ufWBcclxuICApO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFByaW50cyB0aGUgdXNhZ2UgaW5mb3JtYXRpb24gZm9yIENMSSBhcmd1bWVudHMuIElmIHJlcXVpcmVkLCBpdCBjYW4gbGlzdFxyXG4gKiBwcm9wZXJ0aWVzIHJlY3Vyc2l2ZWx5XHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gcHJpbnRVc2FnZSgpIHtcclxuICBjb25zdCBwYWQgPSA0ODtcclxuICBjb25zdCByZWFkbWUgPSAnaHR0cHM6Ly9naXRodWIuY29tL2hpZ2hjaGFydHMvbm9kZS1leHBvcnQtc2VydmVyI3JlYWRtZSc7XHJcblxyXG4gIC8vIERpc3BsYXkgcmVhZG1lIGluZm9ybWF0aW9uXHJcbiAgY29uc29sZS5sb2coXHJcbiAgICAnXFxuVXNhZ2Ugb2YgQ0xJIGFyZ3VtZW50czonLmJvbGQsXHJcbiAgICAnXFxuLS0tLS0tJyxcclxuICAgIGBcXG5Gb3IgbW9yZSBkZXRhaWxlZCBpbmZvcm1hdGlvbiwgdmlzaXQgdGhlIHJlYWRtZSBhdDogJHtyZWFkbWUuYm9sZC55ZWxsb3d9LmBcclxuICApO1xyXG5cclxuICBjb25zdCBjeWNsZUNhdGVnb3JpZXMgPSAob3B0aW9ucykgPT4ge1xyXG4gICAgZm9yIChjb25zdCBbbmFtZSwgb3B0aW9uXSBvZiBPYmplY3QuZW50cmllcyhvcHRpb25zKSkge1xyXG4gICAgICAvLyBJZiBjYXRlZ29yeSBoYXMgbW9yZSBsZXZlbHMsIGdvIGZ1cnRoZXJcclxuICAgICAgaWYgKCFPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob3B0aW9uLCAndmFsdWUnKSkge1xyXG4gICAgICAgIGN5Y2xlQ2F0ZWdvcmllcyhvcHRpb24pO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIGxldCBkZXNjTmFtZSA9IGAgIC0tJHtvcHRpb24uY2xpTmFtZSB8fCBuYW1lfSAke1xyXG4gICAgICAgICAgKCc8JyArIG9wdGlvbi50eXBlICsgJz4nKS5ncmVlblxyXG4gICAgICAgIH0gYDtcclxuICAgICAgICBpZiAoZGVzY05hbWUubGVuZ3RoIDwgcGFkKSB7XHJcbiAgICAgICAgICBmb3IgKGxldCBpID0gZGVzY05hbWUubGVuZ3RoOyBpIDwgcGFkOyBpKyspIHtcclxuICAgICAgICAgICAgZGVzY05hbWUgKz0gJy4nO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gRGlzcGxheSBjb3JyZWN0bHkgYWxpZ25lZCBtZXNzYWdlc1xyXG4gICAgICAgIGNvbnNvbGUubG9nKFxyXG4gICAgICAgICAgZGVzY05hbWUsXHJcbiAgICAgICAgICBvcHRpb24uZGVzY3JpcHRpb24sXHJcbiAgICAgICAgICBgW0RlZmF1bHQ6ICR7b3B0aW9uLnZhbHVlLnRvU3RyaW5nKCkuYm9sZH1dYC5ibHVlXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH07XHJcblxyXG4gIC8vIEN5Y2xlIHRocm91Z2ggb3B0aW9ucyBvZiBlYWNoIGNhdGVnb3JpZXMgYW5kIGRpc3BsYXkgdGhlIHVzYWdlIGluZm9cclxuICBPYmplY3Qua2V5cyhkZWZhdWx0Q29uZmlnKS5mb3JFYWNoKChjYXRlZ29yeSkgPT4ge1xyXG4gICAgLy8gT25seSBwdXBwZXRlZXIgYW5kIGhpZ2hjaGFydHMgY2F0ZWdvcmllcyBjYW5ub3QgYmUgY29uZmlndXJlZCB0aHJvdWdoIENMSVxyXG4gICAgaWYgKCFbJ3B1cHBldGVlcicsICdoaWdoY2hhcnRzJ10uaW5jbHVkZXMoY2F0ZWdvcnkpKSB7XHJcbiAgICAgIGNvbnNvbGUubG9nKGBcXG4ke2NhdGVnb3J5LnRvVXBwZXJDYXNlKCl9YC5yZWQpO1xyXG4gICAgICBjeWNsZUNhdGVnb3JpZXMoZGVmYXVsdENvbmZpZ1tjYXRlZ29yeV0pO1xyXG4gICAgfVxyXG4gIH0pO1xyXG4gIGNvbnNvbGUubG9nKCdcXG4nKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFJvdW5kcyBhIG51bWJlciB0byB0aGUgc3BlY2lmaWVkIHByZWNpc2lvbi5cclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IHZhbHVlIC0gVGhlIG51bWJlciB0byBiZSByb3VuZGVkLlxyXG4gKiBAcGFyYW0ge251bWJlcn0gcHJlY2lzaW9uIC0gVGhlIG51bWJlciBvZiBkZWNpbWFsIHBsYWNlcyB0byByb3VuZCB0by5cclxuICpcclxuICogQHJldHVybnMge251bWJlcn0gLSBUaGUgcm91bmRlZCBudW1iZXIuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgcm91bmROdW1iZXIgPSAodmFsdWUsIHByZWNpc2lvbiA9IDEpID0+IHtcclxuICBjb25zdCBtdWx0aXBsaWVyID0gTWF0aC5wb3coMTAsIHByZWNpc2lvbiB8fCAwKTtcclxuICByZXR1cm4gTWF0aC5yb3VuZCgrdmFsdWUgKiBtdWx0aXBsaWVyKSAvIG11bHRpcGxpZXI7XHJcbn07XHJcblxyXG4vKipcclxuICogQ29udmVydHMgYSB2YWx1ZSB0byBhIGJvb2xlYW4uXHJcbiAqXHJcbiAqIEBwYXJhbSB7YW55fSBpdGVtIC0gVGhlIHZhbHVlIHRvIGJlIGNvbnZlcnRlZCB0byBhIGJvb2xlYW4uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtib29sZWFufSAtIFRoZSBib29sZWFuIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBpbnB1dCB2YWx1ZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCB0b0Jvb2xlYW4gPSAoaXRlbSkgPT5cclxuICBbJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJywgJ05hTicsICcwJywgJyddLmluY2x1ZGVzKGl0ZW0pXHJcbiAgICA/IGZhbHNlXHJcbiAgICA6ICEhaXRlbTtcclxuXHJcbi8qKlxyXG4gKiBXcmFwcyBjdXN0b20gY29kZSB0byBleGVjdXRlIGl0IHNhZmVseS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGN1c3RvbUNvZGUgLSBUaGUgY3VzdG9tIGNvZGUgdG8gYmUgd3JhcHBlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBhbGxvd0ZpbGVSZXNvdXJjZXMgLSBGbGFnIHRvIGFsbG93IGxvYWRpbmcgY29kZSBmcm9tIGEgZmlsZS5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ3xib29sZWFufSAtIFRoZSB3cmFwcGVkIGN1c3RvbSBjb2RlIG9yIGZhbHNlIGlmIHdyYXBwaW5nXHJcbiAqIGZhaWxzLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHdyYXBBcm91bmQgPSAoY3VzdG9tQ29kZSwgYWxsb3dGaWxlUmVzb3VyY2VzKSA9PiB7XHJcbiAgaWYgKGN1c3RvbUNvZGUgJiYgdHlwZW9mIGN1c3RvbUNvZGUgPT09ICdzdHJpbmcnKSB7XHJcbiAgICBjdXN0b21Db2RlID0gY3VzdG9tQ29kZS50cmltKCk7XHJcblxyXG4gICAgaWYgKGN1c3RvbUNvZGUuZW5kc1dpdGgoJy5qcycpKSB7XHJcbiAgICAgIHJldHVybiBhbGxvd0ZpbGVSZXNvdXJjZXNcclxuICAgICAgICA/IHdyYXBBcm91bmQocmVhZEZpbGVTeW5jKGN1c3RvbUNvZGUsICd1dGY4JykpXHJcbiAgICAgICAgOiBmYWxzZTtcclxuICAgIH0gZWxzZSBpZiAoXHJcbiAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnZnVuY3Rpb24oKScpIHx8XHJcbiAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnZnVuY3Rpb24gKCknKSB8fFxyXG4gICAgICBjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJygpPT4nKSB8fFxyXG4gICAgICBjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJygpID0+JylcclxuICAgICkge1xyXG4gICAgICByZXR1cm4gYCgke2N1c3RvbUNvZGV9KSgpYDtcclxuICAgIH1cclxuICAgIHJldHVybiBjdXN0b21Db2RlLnJlcGxhY2UoLzskLywgJycpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBVdGlsaXR5IHRvIG1lYXN1cmUgZWxhcHNlZCB0aW1lIHVzaW5nIHRoZSBOb2RlLmpzIHByb2Nlc3MuaHJ0aW1lKCkgbWV0aG9kLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7ZnVuY3Rpb24oKTogbnVtYmVyfSAtIEEgZnVuY3Rpb24gdG8gY2FsY3VsYXRlIHRoZSBlbGFwc2VkIHRpbWVcclxuICogaW4gbWlsbGlzZWNvbmRzLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IG1lYXN1cmVUaW1lID0gKCkgPT4ge1xyXG4gIGNvbnN0IHN0YXJ0ID0gcHJvY2Vzcy5ocnRpbWUuYmlnaW50KCk7XHJcbiAgcmV0dXJuICgpID0+IE51bWJlcihwcm9jZXNzLmhydGltZS5iaWdpbnQoKSAtIHN0YXJ0KSAvIDEwMDAwMDA7XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgX19kaXJuYW1lLFxyXG4gIGNsZWFyVGV4dCxcclxuICBleHBCYWNrb2ZmLFxyXG4gIGZpeFR5cGUsXHJcbiAgaGFuZGxlUmVzb3VyY2VzLFxyXG4gIGlzQ29ycmVjdEpTT04sXHJcbiAgaXNPYmplY3QsXHJcbiAgaXNPYmplY3RFbXB0eSxcclxuICBpc1ByaXZhdGVSYW5nZVVybEZvdW5kLFxyXG4gIG9wdGlvbnNTdHJpbmdpZnksXHJcbiAgcHJpbnRMb2dvLFxyXG4gIHByaW50VXNhZ2UsXHJcbiAgcm91bmROdW1iZXIsXHJcbiAgdG9Cb29sZWFuLFxyXG4gIHdyYXBBcm91bmQsXHJcbiAgbWVhc3VyZVRpbWVcclxufTtcclxuIiwiY2xhc3MgRXhwb3J0RXJyb3IgZXh0ZW5kcyBFcnJvciB7XHJcbiAgY29uc3RydWN0b3IobWVzc2FnZSkge1xyXG4gICAgc3VwZXIoKTtcclxuICAgIHRoaXMubWVzc2FnZSA9IG1lc3NhZ2U7XHJcbiAgICB0aGlzLnN0YWNrTWVzc2FnZSA9IG1lc3NhZ2U7XHJcbiAgfVxyXG5cclxuICBzZXRFcnJvcihlcnJvcikge1xyXG4gICAgdGhpcy5lcnJvciA9IGVycm9yO1xyXG4gICAgaWYgKGVycm9yLm5hbWUpIHtcclxuICAgICAgdGhpcy5uYW1lID0gZXJyb3IubmFtZTtcclxuICAgIH1cclxuICAgIGlmIChlcnJvci5zdGF0dXNDb2RlKSB7XHJcbiAgICAgIHRoaXMuc3RhdHVzQ29kZSA9IGVycm9yLnN0YXR1c0NvZGU7XHJcbiAgICB9XHJcbiAgICBpZiAoZXJyb3Iuc3RhY2spIHtcclxuICAgICAgdGhpcy5zdGFja01lc3NhZ2UgPSBlcnJvci5tZXNzYWdlO1xyXG4gICAgICB0aGlzLnN0YWNrID0gZXJyb3Iuc3RhY2s7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gdGhpcztcclxuICB9XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IEV4cG9ydEVycm9yO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8vIFRoZSBjYWNoZSBtYW5hZ2VyIG1hbmFnZXMgdGhlIEhpZ2hjaGFydHMgbGlicmFyeSBhbmQgaXRzIGRlcGVuZGVuY2llcy5cclxuLy8gVGhlIGNhY2hlIGl0c2VsZiBpcyBzdG9yZWQgaW4gLmNhY2hlLCBhbmQgaXMgY2hlY2tlZCBieSB0aGUgY29uZmlnIHN5c3RlbVxyXG4vLyBiZWZvcmUgc3RhcnRpbmcgdGhlIHNlcnZpY2VcclxuXHJcbmltcG9ydCB7IGV4aXN0c1N5bmMsIG1rZGlyU3luYywgcmVhZEZpbGVTeW5jLCB3cml0ZUZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgeyBIdHRwc1Byb3h5QWdlbnQgfSBmcm9tICdodHRwcy1wcm94eS1hZ2VudCc7XHJcblxyXG5pbXBvcnQgeyBmZXRjaCB9IGZyb20gJy4vZmV0Y2guanMnO1xyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IF9fZGlybmFtZSB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbmNvbnN0IGNhY2hlID0ge1xyXG4gIGNkblVSTDogJ2h0dHBzOi8vY29kZS5oaWdoY2hhcnRzLmNvbS8nLFxyXG4gIGFjdGl2ZU1hbmlmZXN0OiB7fSxcclxuICBzb3VyY2VzOiAnJyxcclxuICBoY1ZlcnNpb246ICcnXHJcbn07XHJcblxyXG4vLyBUT0RPOiBUaGUgY29uZmlnIHNob3VsZCBiZSBhY2Nlc3NzaWJsZSBnbG9iYWxseSBzbyB3ZSBkb24ndCBoYXZlIHRvIGRvIHRoaXMgc29ydCBvZiB0aGluZy4uXHJcbmxldCBhcHBsaWVkQ29uZmlnID0gZmFsc2U7XHJcblxyXG4vKipcclxuICogRXh0cmFjdHMgYW5kIGNhY2hlcyB0aGUgSGlnaGNoYXJ0cyB2ZXJzaW9uIGZyb20gdGhlIHNvdXJjZXMgc3RyaW5nLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgZXh0cmFjdGVkIEhpZ2hjaGFydHMgdmVyc2lvbi5cclxuICovXHJcbmNvbnN0IGV4dHJhY3RWZXJzaW9uID0gKCkgPT5cclxuICAoY2FjaGUuaGNWZXJzaW9uID0gY2FjaGUuc291cmNlc1xyXG4gICAgLnN1YnN0cmluZygwLCBjYWNoZS5zb3VyY2VzLmluZGV4T2YoJyovJykpXHJcbiAgICAucmVwbGFjZSgnLyonLCAnJylcclxuICAgIC5yZXBsYWNlKCcqLycsICcnKVxyXG4gICAgLnJlcGxhY2UoL1xcbi9nLCAnJylcclxuICAgIC50cmltKCkpO1xyXG5cclxuLyoqXHJcbiAqIEV4dHJhY3RzIHRoZSBIaWdoY2hhcnRzIG1vZHVsZSBuYW1lIGJhc2VkIG9uIHRoZSBzY3JpcHRQYXRoLlxyXG4gKi9cclxuY29uc3QgZXh0cmFjdE1vZHVsZU5hbWUgPSAoc2NyaXB0UGF0aCkgPT4ge1xyXG4gIHJldHVybiBzY3JpcHRQYXRoLnJlcGxhY2UoXHJcbiAgICAvKC4qKVxcL3woLiopbW9kdWxlc1xcL3xzdG9ja1xcLyguKilpbmRpY2F0b3JzXFwvfG1hcHNcXC8oLiopbW9kdWxlc1xcLy9naSxcclxuICAgICcnXHJcbiAgKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBTYXZlcyB0aGUgcHJvdmlkZWQgY29uZmlndXJhdGlvbiBhbmQgZmV0Y2hlZCBtb2R1bGVzIHRvIHRoZSBjYWNoZSBtYW5pZmVzdFxyXG4gKiBmaWxlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge29iamVjdH0gY29uZmlnIC0gSGlnaGNoYXJ0cy1yZWxhdGVkIGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxyXG4gKiBAcGFyYW0ge29iamVjdH0gZmV0Y2hlZE1vZHVsZXMgLSBBbiBvYmplY3QgdGhhdCBjb250YWlucyBtYXBwZWQgbmFtZXMgb2ZcclxuICogZmV0Y2hlZCBIaWdoY2hhcnRzIG1vZHVsZXMgdG8gdXNlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIGFuIGVycm9yIG9jY3VycyB3aGlsZSB3cml0aW5nXHJcbiAqIHRoZSBjYWNoZSBtYW5pZmVzdC5cclxuICovXHJcbmNvbnN0IHNhdmVDb25maWdUb01hbmlmZXN0ID0gYXN5bmMgKGNvbmZpZywgZmV0Y2hlZE1vZHVsZXMpID0+IHtcclxuICBjb25zdCBuZXdNYW5pZmVzdCA9IHtcclxuICAgIHZlcnNpb246IGNvbmZpZy52ZXJzaW9uLFxyXG4gICAgbW9kdWxlczogZmV0Y2hlZE1vZHVsZXMgfHwge31cclxuICB9O1xyXG5cclxuICAvLyBVcGRhdGUgY2FjaGUgb2JqZWN0IHdpdGggdGhlIGN1cnJlbnQgbW9kdWxlc1xyXG4gIGNhY2hlLmFjdGl2ZU1hbmlmZXN0ID0gbmV3TWFuaWZlc3Q7XHJcblxyXG4gIGxvZygzLCAnW2NhY2hlXSBXcml0aW5nIGEgbmV3IG1hbmlmZXN0LicpO1xyXG4gIHRyeSB7XHJcbiAgICB3cml0ZUZpbGVTeW5jKFxyXG4gICAgICBqb2luKF9fZGlybmFtZSwgY29uZmlnLmNhY2hlUGF0aCwgJ21hbmlmZXN0Lmpzb24nKSxcclxuICAgICAgSlNPTi5zdHJpbmdpZnkobmV3TWFuaWZlc3QpLFxyXG4gICAgICAndXRmOCdcclxuICAgICk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW2NhY2hlXSBFcnJvciB3cml0aW5nIHRoZSBjYWNoZSBtYW5pZmVzdC4nKS5zZXRFcnJvcihcclxuICAgICAgZXJyb3JcclxuICAgICk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEZldGNoZXMgYSBzaW5nbGUgc2NyaXB0IGFuZCB1cGRhdGVzIHRoZSBmZXRjaGVkTW9kdWxlcyBhY2NvcmRpbmdseS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHNjcmlwdCAtIEEgcGF0aCB0byBzY3JpcHQgdG8gZ2V0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcHJveHlBZ2VudCAtIFRoZSBwcm94eSBhZ2VudCB0byB1c2UgZm9yIGEgcmVxdWVzdC5cclxuICogQHBhcmFtIHtPYmplY3R9IGZldGNoZWRNb2R1bGVzIC0gQW4gb2JqZWN0IHdoaWNoIHRyYWNrcyB3aGljaCBIaWdoY2hhcnRzIG1vZHVsZXMgaGF2ZSBiZWVuIGZldGNoZWQuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gc2hvdWxkVGhyb3dFcnJvciAtIEEgZmxhZyB0byBpbmRpY2F0ZSBpZiB0aGUgZXJyb3Igc2hvdWxkIGJlIHRocm93bi4gVGhpcyBzaG91bGQgYmUgdXNlZCBvbmx5IGZvciB0aGUgY29yZSBzY3JpcHRzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSB0ZXh0IHJlcHJlc2VudGF0aW9uXHJcbiAqIG9mIHRoZSBmZXRjaGVkIHNjcmlwdC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiB0aGVyZSBpcyBhIHByb2JsZW0gd2l0aFxyXG4gKiBmZXRjaGluZyB0aGUgc2NyaXB0LlxyXG4gKi9cclxuY29uc3QgZmV0Y2hBbmRQcm9jZXNzU2NyaXB0ID0gYXN5bmMgKFxyXG4gIHNjcmlwdCxcclxuICBwcm94eUFnZW50LFxyXG4gIGZldGNoZWRNb2R1bGVzLFxyXG4gIHNob3VsZFRocm93RXJyb3IgPSBmYWxzZVxyXG4pID0+IHtcclxuICAvLyBHZXQgcmlkIG9mIHRoZSAuanMgZnJvbSB0aGUgY3VzdG9tIHN0cmluZ3NcclxuICBpZiAoc2NyaXB0LmVuZHNXaXRoKCcuanMnKSkge1xyXG4gICAgc2NyaXB0ID0gc2NyaXB0LnN1YnN0cmluZygwLCBzY3JpcHQubGVuZ3RoIC0gMyk7XHJcbiAgfVxyXG5cclxuICBsb2coNCwgYFtjYWNoZV0gRmV0Y2hpbmcgc2NyaXB0IC0gJHtzY3JpcHR9LmpzYCk7XHJcblxyXG4gIC8vIElmIGV4aXN0cywgYWRkIHByb3h5IGFnZW50IHRvIHJlcXVlc3Qgb3B0aW9uc1xyXG4gIGNvbnN0IHJlcXVlc3RPcHRpb25zID0gcHJveHlBZ2VudFxyXG4gICAgPyB7XHJcbiAgICAgICAgYWdlbnQ6IHByb3h5QWdlbnQsXHJcbiAgICAgICAgdGltZW91dDogK3Byb2Nlc3MuZW52WydQUk9YWV9TRVJWRVJfVElNRU9VVCddIHx8IDUwMDBcclxuICAgICAgfVxyXG4gICAgOiB7fTtcclxuXHJcbiAgLy8gRmV0Y2ggdGhlIHNjcmlwdFxyXG4gIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2goYCR7c2NyaXB0fS5qc2AsIHJlcXVlc3RPcHRpb25zKTtcclxuXHJcbiAgLy8gSWYgT0ssIHJldHVybiBpdHMgdGV4dCByZXByZXNlbnRhdGlvblxyXG4gIGlmIChyZXNwb25zZS5zdGF0dXNDb2RlID09PSAyMDAgJiYgdHlwZW9mIHJlc3BvbnNlLnRleHQgPT0gJ3N0cmluZycpIHtcclxuICAgIGlmIChmZXRjaGVkTW9kdWxlcykge1xyXG4gICAgICBjb25zdCBtb2R1bGVOYW1lID0gZXh0cmFjdE1vZHVsZU5hbWUoc2NyaXB0KTtcclxuICAgICAgZmV0Y2hlZE1vZHVsZXNbbW9kdWxlTmFtZV0gPSAxO1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiByZXNwb25zZS50ZXh0O1xyXG4gIH1cclxuXHJcbiAgaWYgKHNob3VsZFRocm93RXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgYENvdWxkIG5vdCBmZXRjaCB0aGUgJHtzY3JpcHR9LmpzLiBUaGUgc2NyaXB0IG1pZ2h0IG5vdCBleGlzdCBpbiB0aGUgcmVxdWVzdGVkIHZlcnNpb24gKHN0YXR1cyBjb2RlOiAke3Jlc3BvbnNlLnN0YXR1c0NvZGV9KS5gXHJcbiAgICApLnNldEVycm9yKHJlc3BvbnNlKTtcclxuICB9IGVsc2Uge1xyXG4gICAgbG9nKFxyXG4gICAgICAyLFxyXG4gICAgICBgW2NhY2hlXSBDb3VsZCBub3QgZmV0Y2ggdGhlICR7c2NyaXB0fS5qcy4gVGhlIHNjcmlwdCBtaWdodCBub3QgZXhpc3QgaW4gdGhlIHJlcXVlc3RlZCB2ZXJzaW9uLmBcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICByZXR1cm4gJyc7XHJcbn07XHJcblxyXG4vKipcclxuICogRmV0Y2hlcyBIaWdoY2hhcnRzIHNjcmlwdHMgYW5kIGN1c3RvbVNjcmlwdHMgZnJvbSB0aGUgZ2l2ZW4gQ0ROcy5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHNjcmlwdHMgLSBBcnJheSBvZiBIaWdoY2hhcnRzIG1vZHVsZXMgdG8gZmV0Y2guXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBjdXN0b21TY3JpcHRzIC0gQXJyYXkgb2YgY3VzdG9tIHNjcmlwdCBwYXRocyB0byBmZXRjaCAoZnVsbCBVUkxzKS5cclxuICogQHBhcmFtIHtvYmplY3R9IHByb3h5QWdlbnQgLSBUaGUgcHJveHkgYWdlbnQgdG8gdXNlIGZvciBhIHJlcXVlc3QuXHJcbiAqIEBwYXJhbSB7b2JqZWN0fSBmZXRjaGVkTW9kdWxlcyAtIEFuIG9iamVjdCB3aGljaCB0cmFja3Mgd2hpY2ggSGlnaGNoYXJ0cyBtb2R1bGVzIGhhdmUgYmVlbiBmZXRjaGVkLlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSBUaGUgZmV0Y2hlZCBzY3JpcHRzIGNvbnRlbnQgam9pbmVkLlxyXG4gKi9cclxuY29uc3QgZmV0Y2hTY3JpcHRzID0gYXN5bmMgKFxyXG4gIGNvcmVTY3JpcHRzLFxyXG4gIG1vZHVsZVNjcmlwdHMsXHJcbiAgY3VzdG9tU2NyaXB0cyxcclxuICBjZG5VUkwsXHJcbiAgcHJveHlBZ2VudCxcclxuICBmZXRjaGVkTW9kdWxlc1xyXG4pID0+IHtcclxuICBjb25zdCBhbGxGZXRjaFByb21pc2VzID0gW1xyXG4gICAgLi4uY29yZVNjcmlwdHMubWFwKChzY3JpcHQpID0+XHJcbiAgICAgIGZldGNoQW5kUHJvY2Vzc1NjcmlwdChcclxuICAgICAgICBgJHtjZG5VUkx9JHtzY3JpcHR9YCxcclxuICAgICAgICBwcm94eUFnZW50LFxyXG4gICAgICAgIGZldGNoZWRNb2R1bGVzLFxyXG4gICAgICAgIHRydWVcclxuICAgICAgKVxyXG4gICAgKSxcclxuICAgIC4uLm1vZHVsZVNjcmlwdHMubWFwKChzY3JpcHQpID0+XHJcbiAgICAgIGZldGNoQW5kUHJvY2Vzc1NjcmlwdChgJHtjZG5VUkx9JHtzY3JpcHR9YCwgcHJveHlBZ2VudCwgZmV0Y2hlZE1vZHVsZXMpXHJcbiAgICApLFxyXG4gICAgLi4uY3VzdG9tU2NyaXB0cy5tYXAoKHNjcmlwdCkgPT5cclxuICAgICAgZmV0Y2hBbmRQcm9jZXNzU2NyaXB0KGAke3NjcmlwdH1gLCBwcm94eUFnZW50KVxyXG4gICAgKVxyXG4gIF07XHJcblxyXG4gIGNvbnN0IGZldGNoZWRTY3JpcHRzID0gYXdhaXQgUHJvbWlzZS5hbGwoYWxsRmV0Y2hQcm9taXNlcyk7XHJcbiAgcmV0dXJuIGZldGNoZWRTY3JpcHRzLmpvaW4oJztcXG4nKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBVcGRhdGVzIHRoZSBsb2NhbCBjYWNoZSB3aXRoIEhpZ2hjaGFydHMgc2NyaXB0cyBhbmQgdGhlaXIgdmVyc2lvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjb25maWcgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZyBpbmZvcm1hdGlvblxyXG4gKiBhYm91dCBzY3JpcHRzIGFuZCBtb2R1bGVzLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gc291cmNlUGF0aCAtIFRoZSBwYXRoIHRvIHRoZSBzb3VyY2UgZmlsZSBpbiB0aGUgY2FjaGUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPG9iamVjdD59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gYW4gb2JqZWN0IHJlcHJlc2VudGluZ1xyXG4gKiB0aGUgZmV0Y2hlZCBtb2R1bGVzLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIHRoZXJlIGlzIGFuIGlzc3VlIHVwZGF0aW5nXHJcbiAqIHRoZSBsb2NhbCBIaWdoY2hhcnRzIGNhY2hlLlxyXG4gKi9cclxuY29uc3QgdXBkYXRlQ2FjaGUgPSBhc3luYyAoY29uZmlnLCBzb3VyY2VQYXRoKSA9PiB7XHJcbiAgY29uc3QgeyBjb3JlU2NyaXB0cywgbW9kdWxlcywgaW5kaWNhdG9ycywgc2NyaXB0czogY3VzdG9tU2NyaXB0cyB9ID0gY29uZmlnO1xyXG4gIGNvbnN0IGhjVmVyc2lvbiA9XHJcbiAgICBjb25maWcudmVyc2lvbiA9PT0gJ2xhdGVzdCcgfHwgIWNvbmZpZy52ZXJzaW9uID8gJycgOiBgJHtjb25maWcudmVyc2lvbn0vYDtcclxuXHJcbiAgbG9nKFxyXG4gICAgMyxcclxuICAgIGBbY2FjaGVdIFVwZGF0aW5nIGNhY2hlIHZlcnNpb24gdG8gSGlnaGNoYXJ0czogJHtoY1ZlcnNpb24gfHwgJ2xhdGVzdCd9LmBcclxuICApO1xyXG5cclxuICAvLyBDb25maWd1cmUgcHJveHkgaWYgZXhpc3RzXHJcbiAgbGV0IHByb3h5QWdlbnQ7XHJcbiAgY29uc3QgcHJveHlIb3N0ID0gcHJvY2Vzcy5lbnZbJ1BST1hZX1NFUlZFUl9IT1NUJ107XHJcbiAgY29uc3QgcHJveHlQb3J0ID0gcHJvY2Vzcy5lbnZbJ1BST1hZX1NFUlZFUl9QT1JUJ107XHJcblxyXG4gIC8vIFRyeSB0byBjcmVhdGUgYSBQcm94eSBBZ2VudFxyXG4gIGlmIChwcm94eUhvc3QgJiYgcHJveHlQb3J0KSB7XHJcbiAgICB0cnkge1xyXG4gICAgICBwcm94eUFnZW50ID0gbmV3IEh0dHBzUHJveHlBZ2VudCh7XHJcbiAgICAgICAgaG9zdDogcHJveHlIb3N0LFxyXG4gICAgICAgIHBvcnQ6ICtwcm94eVBvcnRcclxuICAgICAgfSk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1tjYWNoZV0gQ291bGQgbm90IGNyZWF0ZSBhIFByb3h5IEFnZW50LicpLnNldEVycm9yKFxyXG4gICAgICAgIGVycm9yXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBjb25zdCBmZXRjaGVkTW9kdWxlcyA9IHt9O1xyXG4gIHRyeSB7XHJcbiAgICBjYWNoZS5zb3VyY2VzID0gYXdhaXQgZmV0Y2hTY3JpcHRzKFxyXG4gICAgICBbLi4uY29yZVNjcmlwdHMubWFwKChjKSA9PiBgJHtoY1ZlcnNpb259JHtjfWApXSxcclxuICAgICAgW1xyXG4gICAgICAgIC4uLm1vZHVsZXMubWFwKChtKSA9PlxyXG4gICAgICAgICAgbSA9PT0gJ21hcCdcclxuICAgICAgICAgICAgPyBgbWFwcy8ke2hjVmVyc2lvbn1tb2R1bGVzLyR7bX1gXHJcbiAgICAgICAgICAgIDogYCR7aGNWZXJzaW9ufW1vZHVsZXMvJHttfWBcclxuICAgICAgICApLFxyXG4gICAgICAgIC4uLmluZGljYXRvcnMubWFwKChpKSA9PiBgc3RvY2svJHtoY1ZlcnNpb259aW5kaWNhdG9ycy8ke2l9YClcclxuICAgICAgXSxcclxuICAgICAgY3VzdG9tU2NyaXB0cyxcclxuICAgICAgY29uZmlnLmNkblVSTCB8fCBjYWNoZS5jZG5VUkwsXHJcbiAgICAgIHByb3h5QWdlbnQsXHJcbiAgICAgIGZldGNoZWRNb2R1bGVzXHJcbiAgICApO1xyXG4gICAgZXh0cmFjdFZlcnNpb24oKTtcclxuXHJcbiAgICAvLyBTYXZlIHRoZSBmZXRjaGVkIG1vZHVsZXMgaW50byBjYWNoZXMnIHNvdXJjZSBKU09OXHJcbiAgICB3cml0ZUZpbGVTeW5jKHNvdXJjZVBhdGgsIGNhY2hlLnNvdXJjZXMpO1xyXG4gICAgcmV0dXJuIGZldGNoZWRNb2R1bGVzO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbY2FjaGVdIFVuYWJsZSB0byB1cGRhdGUgdGhlIGxvY2FsIEhpZ2hjaGFydHMgY2FjaGUuJ1xyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIFVwZGF0ZXMgdGhlIEhpZ2hjaGFydHMgdmVyc2lvbiBpbiB0aGUgYXBwbGllZCBjb25maWd1cmF0aW9uIGFuZCBjaGVja3NcclxuICogdGhlIGNhY2hlIGZvciB0aGUgbmV3IHZlcnNpb24uXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBuZXdWZXJzaW9uIC0gVGhlIG5ldyBIaWdoY2hhcnRzIHZlcnNpb24gdG8gYmUgYXBwbGllZC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8KG9iamVjdHxib29sZWFuKT59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIHVwZGF0ZWRcclxuICogY29uZmlndXJhdGlvbiB3aXRoIHRoZSBuZXcgdmVyc2lvbiwgb3IgZmFsc2UgaWYgbm8gYXBwbGllZCBjb25maWd1cmF0aW9uXHJcbiAqIGV4aXN0cy5cclxuICovXHJcbmV4cG9ydCBjb25zdCB1cGRhdGVWZXJzaW9uID0gYXN5bmMgKG5ld1ZlcnNpb24pID0+XHJcbiAgYXBwbGllZENvbmZpZ1xyXG4gICAgPyBhd2FpdCBjaGVja0FuZFVwZGF0ZUNhY2hlKFxyXG4gICAgICAgIE9iamVjdC5hc3NpZ24oYXBwbGllZENvbmZpZywge1xyXG4gICAgICAgICAgdmVyc2lvbjogbmV3VmVyc2lvblxyXG4gICAgICAgIH0pXHJcbiAgICAgIClcclxuICAgIDogZmFsc2U7XHJcblxyXG4vKipcclxuICogQ2hlY2tzIHRoZSBjYWNoZSBmb3IgSGlnaGNoYXJ0cyBkZXBlbmRlbmNpZXMsIHVwZGF0ZXMgdGhlIGNhY2hlIGlmIG5lZWRlZCxcclxuICogYW5kIGxvYWRzIHRoZSBzb3VyY2VzLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnIC0gSGlnaGNoYXJ0cy1yZWxhdGVkIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmcgaW5mb3JtYXRpb25cclxuICogYWJvdXQgc2NyaXB0cyBhbmQgbW9kdWxlcy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgdGhlIGNhY2hlIGlzIGNoZWNrZWRcclxuICogYW5kIHVwZGF0ZWQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgdGhlcmUgaXMgYW4gaXNzdWUgdXBkYXRpbmdcclxuICogb3IgcmVhZGluZyB0aGUgY2FjaGUuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgY2hlY2tBbmRVcGRhdGVDYWNoZSA9IGFzeW5jIChjb25maWcpID0+IHtcclxuICBjb25zdCBjYWNoZVBhdGggPSBqb2luKF9fZGlybmFtZSwgY29uZmlnLmNhY2hlUGF0aCk7XHJcblxyXG4gIGxldCBmZXRjaGVkTW9kdWxlcztcclxuICAvLyBQcmVwYXJlIHBhdGhzIHRvIG1hbmlmZXN0IGFuZCBzb3VyY2VzIGZyb20gdGhlIC5jYWNoZSBmb2xkZXJcclxuICBjb25zdCBtYW5pZmVzdFBhdGggPSBqb2luKGNhY2hlUGF0aCwgJ21hbmlmZXN0Lmpzb24nKTtcclxuICBjb25zdCBzb3VyY2VQYXRoID0gam9pbihjYWNoZVBhdGgsICdzb3VyY2VzLmpzJyk7XHJcblxyXG4gIC8vIFRPRE86IGRlYWwgd2l0aCB0cnlpbmcgdG8gc3dpdGNoIHRvIHRoZSBydW5uaW5nIHZlcnNpb25cclxuICAvLyBjb25zdCBhY3RpdmVWZXJzaW9uID0gYXBwbGllZENvbmZpZyA/IGFwcGxpZWRDb25maWcudmVyc2lvbiA6IGZhbHNlO1xyXG5cclxuICBhcHBsaWVkQ29uZmlnID0gY29uZmlnO1xyXG5cclxuICAvLyBDcmVhdGUgdGhlIGNhY2hlIGRlc3RpbmF0aW9uIGlmIGl0IGRvZXNuJ3QgZXhpc3QgYWxyZWFkeVxyXG4gICFleGlzdHNTeW5jKGNhY2hlUGF0aCkgJiYgbWtkaXJTeW5jKGNhY2hlUGF0aCk7XHJcblxyXG4gIC8vIEZldGNoIGFsbCB0aGUgc2NyaXB0cyBlaXRoZXIgaWYgbWFuaWZlc3QuanNvbiBkb2VzIG5vdCBleGlzdFxyXG4gIC8vIG9yIGlmIHRoZSBmb3JjZUZldGNoIG9wdGlvbiBpcyBlbmFibGVkXHJcbiAgaWYgKCFleGlzdHNTeW5jKG1hbmlmZXN0UGF0aCkgfHwgY29uZmlnLmZvcmNlRmV0Y2gpIHtcclxuICAgIGxvZygzLCAnW2NhY2hlXSBGZXRjaGluZyBhbmQgY2FjaGluZyBIaWdoY2hhcnRzIGRlcGVuZGVuY2llcy4nKTtcclxuICAgIGZldGNoZWRNb2R1bGVzID0gYXdhaXQgdXBkYXRlQ2FjaGUoY29uZmlnLCBzb3VyY2VQYXRoKTtcclxuICB9IGVsc2Uge1xyXG4gICAgbGV0IHJlcXVlc3RVcGRhdGUgPSBmYWxzZTtcclxuXHJcbiAgICAvLyBSZWFkIHRoZSBtYW5pZmVzdCBKU09OXHJcbiAgICBjb25zdCBtYW5pZmVzdCA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKG1hbmlmZXN0UGF0aCkpO1xyXG5cclxuICAgIC8vIENoZWNrIGlmIHRoZSBtb2R1bGVzIGlzIGFuIGFycmF5LCBpZiBzbywgd2UgcmV3cml0ZSBpdCB0byBhIG1hcCB0byBtYWtlXHJcbiAgICAvLyBpdCBlYXNpZXIgdG8gcmVzb2x2ZSBtb2R1bGVzLlxyXG4gICAgaWYgKG1hbmlmZXN0Lm1vZHVsZXMgJiYgQXJyYXkuaXNBcnJheShtYW5pZmVzdC5tb2R1bGVzKSkge1xyXG4gICAgICBjb25zdCBtb2R1bGVNYXAgPSB7fTtcclxuICAgICAgbWFuaWZlc3QubW9kdWxlcy5mb3JFYWNoKChtKSA9PiAobW9kdWxlTWFwW21dID0gMSkpO1xyXG4gICAgICBtYW5pZmVzdC5tb2R1bGVzID0gbW9kdWxlTWFwO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IHsgbW9kdWxlcywgY29yZVNjcmlwdHMsIGluZGljYXRvcnMgfSA9IGNvbmZpZztcclxuICAgIGNvbnN0IG51bWJlck9mTW9kdWxlcyA9XHJcbiAgICAgIG1vZHVsZXMubGVuZ3RoICsgY29yZVNjcmlwdHMubGVuZ3RoICsgaW5kaWNhdG9ycy5sZW5ndGg7XHJcblxyXG4gICAgLy8gQ29tcGFyZSB0aGUgbG9hZGVkIGNvbmZpZyB3aXRoIHRoZSBjb250ZW50cyBpbiBjYWNoZS5cclxuICAgIC8vIElmIHRoZXJlIGFyZSBjaGFuZ2VzLCBmZXRjaCByZXF1ZXN0ZWQgbW9kdWxlcyBhbmQgcHJvZHVjdHMsXHJcbiAgICAvLyBhbmQgYmFrZSB0aGVtIGludG8gYSBnaWFudCBibG9iLiBTYXZlIHRoZSBibG9iLlxyXG4gICAgaWYgKG1hbmlmZXN0LnZlcnNpb24gIT09IGNvbmZpZy52ZXJzaW9uKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICAyLFxyXG4gICAgICAgICdbY2FjaGVdIEEgSGlnaGNoYXJ0cyB2ZXJzaW9uIG1pc21hdGNoIGluIHRoZSBjYWNoZSwgbmVlZCB0byByZS1mZXRjaC4nXHJcbiAgICAgICk7XHJcbiAgICAgIHJlcXVlc3RVcGRhdGUgPSB0cnVlO1xyXG4gICAgfSBlbHNlIGlmIChPYmplY3Qua2V5cyhtYW5pZmVzdC5tb2R1bGVzIHx8IHt9KS5sZW5ndGggIT09IG51bWJlck9mTW9kdWxlcykge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgMixcclxuICAgICAgICAnW2NhY2hlXSBUaGUgY2FjaGUgYW5kIHRoZSByZXF1ZXN0ZWQgbW9kdWxlcyBkbyBub3QgbWF0Y2gsIG5lZWQgdG8gcmUtZmV0Y2guJ1xyXG4gICAgICApO1xyXG4gICAgICByZXF1ZXN0VXBkYXRlID0gdHJ1ZTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIENoZWNrIGVhY2ggbW9kdWxlLCBpZiBhbnl0aGluZyBpcyBtaXNzaW5nIHJlZmV0Y2ggZXZlcnl0aGluZ1xyXG4gICAgICByZXF1ZXN0VXBkYXRlID0gKGNvbmZpZy5tb2R1bGVzIHx8IFtdKS5zb21lKChtb2R1bGVOYW1lKSA9PiB7XHJcbiAgICAgICAgaWYgKCFtYW5pZmVzdC5tb2R1bGVzW21vZHVsZU5hbWVdKSB7XHJcbiAgICAgICAgICBsb2coXHJcbiAgICAgICAgICAgIDIsXHJcbiAgICAgICAgICAgIGBbY2FjaGVdIFRoZSAke21vZHVsZU5hbWV9IGlzIG1pc3NpbmcgaW4gdGhlIGNhY2hlLCBuZWVkIHRvIHJlLWZldGNoLmBcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgICB9XHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChyZXF1ZXN0VXBkYXRlKSB7XHJcbiAgICAgIGZldGNoZWRNb2R1bGVzID0gYXdhaXQgdXBkYXRlQ2FjaGUoY29uZmlnLCBzb3VyY2VQYXRoKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIGxvZygzLCAnW2NhY2hlXSBEZXBlbmRlbmN5IGNhY2hlIGlzIHVwIHRvIGRhdGUsIHByb2NlZWRpbmcuJyk7XHJcblxyXG4gICAgICAvLyBMb2FkIHRoZSBzb3VyY2VzXHJcbiAgICAgIGNhY2hlLnNvdXJjZXMgPSByZWFkRmlsZVN5bmMoc291cmNlUGF0aCwgJ3V0ZjgnKTtcclxuXHJcbiAgICAgIC8vIEdldCBjdXJyZW50IG1vZHVsZXMgbWFwXHJcbiAgICAgIGZldGNoZWRNb2R1bGVzID0gbWFuaWZlc3QubW9kdWxlcztcclxuICAgICAgZXh0cmFjdFZlcnNpb24oKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIEZpbmFsbHksIHNhdmUgdGhlIG5ldyBtYW5pZmVzdCwgd2hpY2ggaXMgYmFzaWNhbGx5IG91ciBjdXJyZW50IGNvbmZpZ1xyXG4gIC8vIGluIGEgc2xpZ2h0bHkgZGlmZmVyZW50IGZvcm1hdFxyXG4gIGF3YWl0IHNhdmVDb25maWdUb01hbmlmZXN0KGNvbmZpZywgZmV0Y2hlZE1vZHVsZXMpO1xyXG59O1xyXG5cclxuZXhwb3J0IGNvbnN0IGdldENhY2hlUGF0aCA9ICgpID0+IHtcclxuICByZXR1cm4gam9pbihfX2Rpcm5hbWUsIGFwcGxpZWRDb25maWcuY2FjaGVQYXRoKTtcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBjaGVja0FuZFVwZGF0ZUNhY2hlLFxyXG4gIGdldENhY2hlUGF0aCxcclxuICB1cGRhdGVWZXJzaW9uLFxyXG4gIGdldENhY2hlOiAoKSA9PiBjYWNoZSxcclxuICBoaWdoY2hhcnRzOiAoKSA9PiBjYWNoZS5zb3VyY2VzLFxyXG4gIHZlcnNpb246ICgpID0+IGNhY2hlLmhjVmVyc2lvblxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IGV4aXN0c1N5bmMsIHJlYWRGaWxlU3luYywgcHJvbWlzZXMgYXMgZnNQcm9taXNlcyB9IGZyb20gJ2ZzJztcclxuXHJcbmltcG9ydCBwcm9tcHRzIGZyb20gJ3Byb21wdHMnO1xyXG5cclxuaW1wb3J0IHtcclxuICBhYnNvbHV0ZVByb3BzLFxyXG4gIGRlZmF1bHRDb25maWcsXHJcbiAgbmVzdGVkQXJncyxcclxuICBwcm9tcHRzQ29uZmlnXHJcbn0gZnJvbSAnLi9zY2hlbWFzL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBkZWVwQ29weSwgaXNPYmplY3QsIHByaW50VXNhZ2UsIHRvQm9vbGVhbiB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxubGV0IGdlbmVyYWxPcHRpb25zID0ge307XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIGFuZCByZXR1cm5zIHRoZSBnZW5lcmFsIG9wdGlvbnMgZm9yIHRoZSBleHBvcnQgcHJvY2Vzcy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIGdlbmVyYWwgb3B0aW9ucyBvYmplY3QuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0T3B0aW9ucyA9ICgpID0+IGdlbmVyYWxPcHRpb25zO1xyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIGFuZCBzZXRzIHRoZSBnZW5lcmFsIG9wdGlvbnMgZm9yIHRoZSBzZXJ2ZXIgaW5zdGFjZSwga2VlcGluZ1xyXG4gKiB0aGUgcHJpbmNpcGxlIG9mIHRoZSBvcHRpb25zIGxvYWQgcHJpb3JpdHkuIEl0IGFjY2VwdHMgb3B0aW9uYWwgdXNlck9wdGlvbnNcclxuICogYW5kIGFyZ3MgZnJvbSB0aGUgQ0xJLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gdXNlck9wdGlvbnMgLSBVc2VyLXByb3ZpZGVkIG9wdGlvbnMgZm9yIGN1c3RvbWl6YXRpb24uXHJcbiAqIEBwYXJhbSB7QXJyYXl9IGFyZ3MgLSBDb21tYW5kLWxpbmUgYXJndW1lbnRzIGZvciBhZGRpdGlvbmFsIGNvbmZpZ3VyYXRpb25cclxuICogKENMSSB1c2FnZSkuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSB1cGRhdGVkIGdlbmVyYWwgb3B0aW9ucyBvYmplY3QuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2V0T3B0aW9ucyA9ICh1c2VyT3B0aW9ucywgYXJncykgPT4ge1xyXG4gIC8vIE9ubHkgZm9yIHRoZSBDTEkgdXNhZ2VcclxuICBpZiAoYXJncz8ubGVuZ3RoKSB7XHJcbiAgICAvLyBHZXQgdGhlIGFkZGl0aW9uYWwgb3B0aW9ucyBmcm9tIHRoZSBjdXN0b20gSlNPTiBmaWxlXHJcbiAgICBnZW5lcmFsT3B0aW9ucyA9IGxvYWRDb25maWdGaWxlKGFyZ3MpO1xyXG4gIH1cclxuXHJcbiAgLy8gVXBkYXRlIHRoZSBkZWZhdWx0IGNvbmZpZyB3aXRoIGEgY29ycmVjdCBvcHRpb24gdmFsdWVzXHJcbiAgdXBkYXRlRGVmYXVsdENvbmZpZyhkZWZhdWx0Q29uZmlnLCBnZW5lcmFsT3B0aW9ucyk7XHJcblxyXG4gIC8vIFNldCB2YWx1ZXMgZm9yIHNlcnZlcidzIG9wdGlvbnMgYW5kIHJldHVybnMgdGhlbVxyXG4gIGdlbmVyYWxPcHRpb25zID0gaW5pdE9wdGlvbnMoZGVmYXVsdENvbmZpZyk7XHJcblxyXG4gIC8vIEFwcGx5IHVzZXIgb3B0aW9ucyBpZiB0aGVyZSBhcmUgYW55XHJcbiAgaWYgKHVzZXJPcHRpb25zKSB7XHJcbiAgICAvLyBNZXJnZSB1c2VyIG9wdGlvbnNcclxuICAgIGdlbmVyYWxPcHRpb25zID0gbWVyZ2VDb25maWdPcHRpb25zKFxyXG4gICAgICBnZW5lcmFsT3B0aW9ucyxcclxuICAgICAgdXNlck9wdGlvbnMsXHJcbiAgICAgIGFic29sdXRlUHJvcHNcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICAvLyBPbmx5IGZvciB0aGUgQ0xJIHVzYWdlXHJcbiAgaWYgKGFyZ3M/Lmxlbmd0aCkge1xyXG4gICAgLy8gUGFpciBwcm92aWRlZCBhcmd1bWVudHNcclxuICAgIGdlbmVyYWxPcHRpb25zID0gcGFpckFyZ3VtZW50VmFsdWUoZ2VuZXJhbE9wdGlvbnMsIGFyZ3MsIGRlZmF1bHRDb25maWcpO1xyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIGZpbmFsIGdlbmVyYWwgb3B0aW9uc1xyXG4gIHJldHVybiBnZW5lcmFsT3B0aW9ucztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBBbGxvd3MgbWFudWFsIGNvbmZpZ3VyYXRpb24gYmFzZWQgb24gc3BlY2lmaWVkIHByb21wdHMgYW5kIHNhdmVzXHJcbiAqIHRoZSBjb25maWd1cmF0aW9uIHRvIGEgZmlsZS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGNvbmZpZ0ZpbGVOYW1lIC0gVGhlIG5hbWUgb2YgdGhlIGNvbmZpZ3VyYXRpb24gZmlsZS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8Ym9vbGVhbj59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRydWUgb25jZSB0aGUgbWFudWFsXHJcbiAqIGNvbmZpZ3VyYXRpb24gaXMgY29tcGxldGVkIGFuZCBzYXZlZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBtYW51YWxDb25maWcgPSBhc3luYyAoY29uZmlnRmlsZU5hbWUpID0+IHtcclxuICAvLyBQcmVwYXJlIGEgY29uZmlnIG9iamVjdFxyXG4gIGxldCBjb25maWdGaWxlID0ge307XHJcblxyXG4gIC8vIENoZWNrIGlmIHByb3ZpZGVkIGNvbmZpZyBmaWxlIGV4aXN0c1xyXG4gIGlmIChleGlzdHNTeW5jKGNvbmZpZ0ZpbGVOYW1lKSkge1xyXG4gICAgY29uZmlnRmlsZSA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKGNvbmZpZ0ZpbGVOYW1lLCAndXRmOCcpKTtcclxuICB9XHJcblxyXG4gIC8vIFF1ZXN0aW9uIGFib3V0IGEgY29uZmlndXJhdGlvbiBjYXRlZ29yeVxyXG4gIGNvbnN0IG9uU3VibWl0ID0gYXN5bmMgKHAsIGNhdGVnb3JpZXMpID0+IHtcclxuICAgIGxldCBxdWVzdGlvbnNDb3VudGVyID0gMDtcclxuICAgIGxldCBhbGxRdWVzdGlvbnMgPSBbXTtcclxuXHJcbiAgICAvLyBDcmVhdGUgYSBjb3JyZXNwb25kaW5nIHByb3BlcnR5IGluIHRoZSBtYW51YWxDb25maWcgb2JqZWN0XHJcbiAgICBmb3IgKGNvbnN0IHNlY3Rpb24gb2YgY2F0ZWdvcmllcykge1xyXG4gICAgICAvLyBNYXJrIGVhY2ggb3B0aW9uIHdpdGggYSBzZWN0aW9uXHJcbiAgICAgIHByb21wdHNDb25maWdbc2VjdGlvbl0gPSBwcm9tcHRzQ29uZmlnW3NlY3Rpb25dLm1hcCgob3B0aW9uKSA9PiAoe1xyXG4gICAgICAgIC4uLm9wdGlvbixcclxuICAgICAgICBzZWN0aW9uXHJcbiAgICAgIH0pKTtcclxuXHJcbiAgICAgIC8vIENvbGxlY3QgdGhlIHF1ZXN0aW9uc1xyXG4gICAgICBhbGxRdWVzdGlvbnMgPSBbLi4uYWxsUXVlc3Rpb25zLCAuLi5wcm9tcHRzQ29uZmlnW3NlY3Rpb25dXTtcclxuICAgIH1cclxuXHJcbiAgICBhd2FpdCBwcm9tcHRzKGFsbFF1ZXN0aW9ucywge1xyXG4gICAgICBvblN1Ym1pdDogYXN5bmMgKHByb21wdCwgYW5zd2VyKSA9PiB7XHJcbiAgICAgICAgLy8gR2V0IHRoZSBkZWZhdWx0IG1vZHVsZXNcclxuICAgICAgICBpZiAocHJvbXB0Lm5hbWUgPT09ICdtb2R1bGVzJykge1xyXG4gICAgICAgICAgYW5zd2VyID0gYW5zd2VyLmxlbmd0aFxyXG4gICAgICAgICAgICA/IGFuc3dlci5tYXAoKG1vZHVsZSkgPT4gcHJvbXB0LmNob2ljZXNbbW9kdWxlXSlcclxuICAgICAgICAgICAgOiBwcm9tcHQuY2hvaWNlcztcclxuXHJcbiAgICAgICAgICBjb25maWdGaWxlW3Byb21wdC5zZWN0aW9uXVtwcm9tcHQubmFtZV0gPSBhbnN3ZXI7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIGNvbmZpZ0ZpbGVbcHJvbXB0LnNlY3Rpb25dID0gcmVjdXJzaXZlUHJvcHMoXHJcbiAgICAgICAgICAgIE9iamVjdC5hc3NpZ24oe30sIGNvbmZpZ0ZpbGVbcHJvbXB0LnNlY3Rpb25dIHx8IHt9KSxcclxuICAgICAgICAgICAgcHJvbXB0Lm5hbWUuc3BsaXQoJy4nKSxcclxuICAgICAgICAgICAgcHJvbXB0LmNob2ljZXMgPyBwcm9tcHQuY2hvaWNlc1thbnN3ZXJdIDogYW5zd2VyXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgaWYgKCsrcXVlc3Rpb25zQ291bnRlciA9PT0gYWxsUXVlc3Rpb25zLmxlbmd0aCkge1xyXG4gICAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgYXdhaXQgZnNQcm9taXNlcy53cml0ZUZpbGUoXHJcbiAgICAgICAgICAgICAgY29uZmlnRmlsZU5hbWUsXHJcbiAgICAgICAgICAgICAgSlNPTi5zdHJpbmdpZnkoY29uZmlnRmlsZSwgbnVsbCwgMiksXHJcbiAgICAgICAgICAgICAgJ3V0ZjgnXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgICAgICAgMSxcclxuICAgICAgICAgICAgICBlcnJvcixcclxuICAgICAgICAgICAgICBgW2NvbmZpZ10gQW4gZXJyb3Igb2NjdXJyZWQgd2hpbGUgY3JlYXRpbmcgdGhlICR7Y29uZmlnRmlsZU5hbWV9IGZpbGUuYFxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9KTtcclxuXHJcbiAgICByZXR1cm4gdHJ1ZTtcclxuICB9O1xyXG5cclxuICAvLyBGaW5kIHRoZSBjYXRlZ29yaWVzXHJcbiAgY29uc3QgY2hvaWNlcyA9IE9iamVjdC5rZXlzKHByb21wdHNDb25maWcpLm1hcCgoY2hvaWNlKSA9PiAoe1xyXG4gICAgdGl0bGU6IGAke2Nob2ljZX0gb3B0aW9uc2AsXHJcbiAgICB2YWx1ZTogY2hvaWNlXHJcbiAgfSkpO1xyXG5cclxuICAvLyBDYXRlZ29yeSBwcm9tcHRcclxuICByZXR1cm4gcHJvbXB0cyhcclxuICAgIHtcclxuICAgICAgdHlwZTogJ211bHRpc2VsZWN0JyxcclxuICAgICAgbmFtZTogJ2NhdGVnb3J5JyxcclxuICAgICAgbWVzc2FnZTogJ1doaWNoIGNhdGVnb3J5IGRvIHlvdSB3YW50IHRvIGNvbmZpZ3VyZT8nLFxyXG4gICAgICBoaW50OiAnU3BhY2U6IFNlbGVjdCBzcGVjaWZpYywgQTogU2VsZWN0IGFsbCwgRW50ZXI6IENvbmZpcm0uJyxcclxuICAgICAgaW5zdHJ1Y3Rpb25zOiAnJyxcclxuICAgICAgY2hvaWNlc1xyXG4gICAgfSxcclxuICAgIHsgb25TdWJtaXQgfVxyXG4gICk7XHJcbn07XHJcblxyXG4vKipcclxuICogTWFwcyBvbGQtc3RydWN0dXJlZCAoUGhhbnRvbUpTKSBvcHRpb25zIHRvIGEgbmV3IGNvbmZpZ3VyYXRpb24gZm9ybWF0XHJcbiAqIChQdXBwZXRlZXIpLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb2xkT3B0aW9ucyAtIE9sZC1zdHJ1Y3R1cmVkIG9wdGlvbnMgdG8gYmUgbWFwcGVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBOZXcgb3B0aW9ucyBzdHJ1Y3R1cmVkIGJhc2VkIG9uIHRoZSBkZWZpbmVkIG5lc3RlZEFyZ3NcclxuICogbWFwcGluZy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBtYXBUb05ld0NvbmZpZyA9IChvbGRPcHRpb25zKSA9PiB7XHJcbiAgY29uc3QgbmV3T3B0aW9ucyA9IHt9O1xyXG4gIC8vIEN5Y2xlIHRocm91Z2ggb2xkLXN0cnVjdHVyZWQgb3B0aW9uc1xyXG4gIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKG9sZE9wdGlvbnMpKSB7XHJcbiAgICBjb25zdCBwcm9wZXJ0aWVzQ2hhaW4gPSBuZXN0ZWRBcmdzW2tleV0gPyBuZXN0ZWRBcmdzW2tleV0uc3BsaXQoJy4nKSA6IFtdO1xyXG5cclxuICAgIC8vIFBvcHVsYXRlIG9iamVjdCBpbiBjb3JyZWN0IHByb3BlcnRpZXMgbGV2ZWxzXHJcbiAgICBwcm9wZXJ0aWVzQ2hhaW4ucmVkdWNlKFxyXG4gICAgICAob2JqLCBwcm9wLCBpbmRleCkgPT5cclxuICAgICAgICAob2JqW3Byb3BdID1cclxuICAgICAgICAgIHByb3BlcnRpZXNDaGFpbi5sZW5ndGggLSAxID09PSBpbmRleCA/IHZhbHVlIDogb2JqW3Byb3BdIHx8IHt9KSxcclxuICAgICAgbmV3T3B0aW9uc1xyXG4gICAgKTtcclxuICB9XHJcbiAgcmV0dXJuIG5ld09wdGlvbnM7XHJcbn07XHJcblxyXG4vKipcclxuICogTWVyZ2VzIHR3byBzZXRzIG9mIGNvbmZpZ3VyYXRpb24gb3B0aW9ucywgY29uc2lkZXJpbmcgYWJzb2x1dGUgcHJvcGVydGllcy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBPcmlnaW5hbCBjb25maWd1cmF0aW9uIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBuZXdPcHRpb25zIC0gTmV3IGNvbmZpZ3VyYXRpb24gb3B0aW9ucyB0byBiZSBtZXJnZWQuXHJcbiAqIEBwYXJhbSB7QXJyYXl9IGFic29sdXRlUHJvcHMgLSBMaXN0IG9mIHByb3BlcnRpZXMgdGhhdCBzaG91bGRcclxuICogbm90IGJlIHJlY3Vyc2l2ZWx5IG1lcmdlZC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gTWVyZ2VkIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBtZXJnZUNvbmZpZ09wdGlvbnMgPSAob3B0aW9ucywgbmV3T3B0aW9ucywgYWJzb2x1dGVQcm9wcyA9IFtdKSA9PiB7XHJcbiAgY29uc3QgbWVyZ2VkT3B0aW9ucyA9IGRlZXBDb3B5KG9wdGlvbnMpO1xyXG5cclxuICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhuZXdPcHRpb25zKSkge1xyXG4gICAgbWVyZ2VkT3B0aW9uc1trZXldID1cclxuICAgICAgaXNPYmplY3QodmFsdWUpICYmXHJcbiAgICAgICFhYnNvbHV0ZVByb3BzLmluY2x1ZGVzKGtleSkgJiZcclxuICAgICAgbWVyZ2VkT3B0aW9uc1trZXldICE9PSB1bmRlZmluZWRcclxuICAgICAgICA/IG1lcmdlQ29uZmlnT3B0aW9ucyhtZXJnZWRPcHRpb25zW2tleV0sIHZhbHVlLCBhYnNvbHV0ZVByb3BzKVxyXG4gICAgICAgIDogdmFsdWUgIT09IHVuZGVmaW5lZFxyXG4gICAgICAgICAgPyB2YWx1ZVxyXG4gICAgICAgICAgOiBtZXJnZWRPcHRpb25zW2tleV07XHJcbiAgfVxyXG5cclxuICByZXR1cm4gbWVyZ2VkT3B0aW9ucztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyBleHBvcnQgc2V0dGluZ3MgYmFzZWQgb24gcHJvdmlkZWQgZXhwb3J0T3B0aW9uc1xyXG4gKiBhbmQgZ2VuZXJhbE9wdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBleHBvcnRPcHRpb25zIC0gT3B0aW9ucyBzcGVjaWZpYyB0byB0aGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBnZW5lcmFsT3B0aW9ucyAtIEdlbmVyYWwgY29uZmlndXJhdGlvbiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBJbml0aWFsaXplZCBleHBvcnQgc2V0dGluZ3MuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaW5pdEV4cG9ydFNldHRpbmdzID0gKGV4cG9ydE9wdGlvbnMsIGdlbmVyYWxPcHRpb25zID0ge30pID0+IHtcclxuICBsZXQgb3B0aW9ucyA9IHt9O1xyXG5cclxuICBpZiAoZXhwb3J0T3B0aW9ucy5zdmcpIHtcclxuICAgIG9wdGlvbnMgPSBkZWVwQ29weShnZW5lcmFsT3B0aW9ucyk7XHJcbiAgICBvcHRpb25zLmV4cG9ydC50eXBlID0gZXhwb3J0T3B0aW9ucy50eXBlIHx8IGV4cG9ydE9wdGlvbnMuZXhwb3J0LnR5cGU7XHJcbiAgICBvcHRpb25zLmV4cG9ydC5zY2FsZSA9IGV4cG9ydE9wdGlvbnMuc2NhbGUgfHwgZXhwb3J0T3B0aW9ucy5leHBvcnQuc2NhbGU7XHJcbiAgICBvcHRpb25zLmV4cG9ydC5vdXRmaWxlID1cclxuICAgICAgZXhwb3J0T3B0aW9ucy5vdXRmaWxlIHx8IGV4cG9ydE9wdGlvbnMuZXhwb3J0Lm91dGZpbGU7XHJcbiAgICBvcHRpb25zLnBheWxvYWQgPSB7XHJcbiAgICAgIHN2ZzogZXhwb3J0T3B0aW9ucy5zdmdcclxuICAgIH07XHJcbiAgfSBlbHNlIHtcclxuICAgIG9wdGlvbnMgPSBtZXJnZUNvbmZpZ09wdGlvbnMoXHJcbiAgICAgIGdlbmVyYWxPcHRpb25zLFxyXG4gICAgICBleHBvcnRPcHRpb25zLFxyXG4gICAgICAvLyBPbWl0IGdvaW5nIGRvd24gcmVjdXJzaXZlbHkgd2l0aCB0aGUgYmVsb3dzXHJcbiAgICAgIGFic29sdXRlUHJvcHNcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICBvcHRpb25zLmV4cG9ydC5vdXRmaWxlID1cclxuICAgIG9wdGlvbnMuZXhwb3J0Py5vdXRmaWxlIHx8IGBjaGFydC4ke29wdGlvbnMuZXhwb3J0Py50eXBlIHx8ICdwbmcnfWA7XHJcbiAgcmV0dXJuIG9wdGlvbnM7XHJcbn07XHJcblxyXG4vKipcclxuICogTG9hZHMgYWRkaXRpb25hbCBjb25maWd1cmF0aW9uIGZyb20gYSBzcGVjaWZpZWQgZmlsZSB1c2luZ1xyXG4gKiB0aGUgLS1sb2FkQ29uZmlnIG9wdGlvbi5cclxuICpcclxuICogQHBhcmFtIHtBcnJheX0gYXJncyAtIENvbW1hbmQtbGluZSBhcmd1bWVudHMgdG8gY2hlY2sgZm9yXHJcbiAqIHRoZSAtLWxvYWRDb25maWcgb3B0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBBZGRpdGlvbmFsIGNvbmZpZ3VyYXRpb24gbG9hZGVkIGZyb20gdGhlIHNwZWNpZmllZCBmaWxlLFxyXG4gKiBvciBhbiBlbXB0eSBvYmplY3QgaWYgbm90IGZvdW5kIG9yIGludmFsaWQuXHJcbiAqL1xyXG5mdW5jdGlvbiBsb2FkQ29uZmlnRmlsZShhcmdzKSB7XHJcbiAgLy8gQ2hlY2sgaWYgdGhlIC0tbG9hZENvbmZpZyBvcHRpb24gd2FzIHVzZWRcclxuICBjb25zdCBjb25maWdJbmRleCA9IGFyZ3MuZmluZEluZGV4KFxyXG4gICAgKGFyZykgPT4gYXJnLnJlcGxhY2UoLy0vZywgJycpID09PSAnbG9hZENvbmZpZydcclxuICApO1xyXG5cclxuICAvLyBDaGVjayBpZiB0aGUgLS1sb2FkQ29uZmlnIGhhcyBhIHZhbHVlXHJcbiAgaWYgKGNvbmZpZ0luZGV4ID4gLTEgJiYgYXJnc1tjb25maWdJbmRleCArIDFdKSB7XHJcbiAgICBjb25zdCBmaWxlTmFtZSA9IGFyZ3NbY29uZmlnSW5kZXggKyAxXTtcclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIENoZWNrIGlmIGFuIGFkZGl0aW9uYWwgY29uZmlnIGZpbGUgaXMgYSBjb3JyZWN0IEpTT04gZmlsZVxyXG4gICAgICBpZiAoZmlsZU5hbWUgJiYgZmlsZU5hbWUuZW5kc1dpdGgoJy5qc29uJykpIHtcclxuICAgICAgICAvLyBMb2FkIGFuIG9wdGlvbmFsIGN1c3RvbSBKU09OIGNvbmZpZyBmaWxlXHJcbiAgICAgICAgcmV0dXJuIEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKGZpbGVOYW1lKSk7XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAyLFxyXG4gICAgICAgIGVycm9yLFxyXG4gICAgICAgIGBbY29uZmlnXSBVbmFibGUgdG8gbG9hZCB0aGUgY29uZmlndXJhdGlvbiBmcm9tIHRoZSAke2ZpbGVOYW1lfSBmaWxlLmBcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIE5vIGFkZGl0aW9uYWwgb3B0aW9ucyB0byByZXR1cm5cclxuICByZXR1cm4ge307XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBVcGRhdGVzIHRoZSBkZWZhdWx0IGNvbmZpZ3VyYXRpb24gb2JqZWN0IHdpdGggdmFsdWVzIGZyb20gYSBjdXN0b20gb2JqZWN0XHJcbiAqIGFuZCBlbnZpcm9ubWVudCB2YXJpYWJsZXMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjb25maWdPYmogLSBUaGUgZGVmYXVsdCBjb25maWd1cmF0aW9uIG9iamVjdC5cclxuICogQHBhcmFtIHtPYmplY3R9IGN1c3RvbU9iaiAtIEN1c3RvbSBjb25maWd1cmF0aW9uIG9iamVjdCB0byBvdmVycmlkZSBkZWZhdWx0cy5cclxuICogQHBhcmFtIHtzdHJpbmd9IHByb3BDaGFpbiAtIFByb3BlcnR5IGNoYWluIGZvciB0cmFja2luZyBuZXN0ZWQgcHJvcGVydGllc1xyXG4gKiBkdXJpbmcgcmVjdXJzaW9uLlxyXG4gKi9cclxuZnVuY3Rpb24gdXBkYXRlRGVmYXVsdENvbmZpZyhjb25maWdPYmosIGN1c3RvbU9iaiA9IHt9LCBwcm9wQ2hhaW4gPSAnJykge1xyXG4gIE9iamVjdC5rZXlzKGNvbmZpZ09iaikuZm9yRWFjaCgoa2V5KSA9PiB7XHJcbiAgICBjb25zdCBlbnRyeSA9IGNvbmZpZ09ialtrZXldO1xyXG4gICAgY29uc3QgY3VzdG9tVmFsdWUgPSBjdXN0b21PYmogJiYgY3VzdG9tT2JqW2tleV07XHJcbiAgICBsZXQgbnVtRW52VmFsO1xyXG5cclxuICAgIGlmICh0eXBlb2YgZW50cnkudmFsdWUgPT09ICd1bmRlZmluZWQnKSB7XHJcbiAgICAgIHVwZGF0ZURlZmF1bHRDb25maWcoZW50cnksIGN1c3RvbVZhbHVlLCBgJHtwcm9wQ2hhaW59LiR7a2V5fWApO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gSWYgYSB2YWx1ZSBmcm9tIGEgY3VzdG9tIEpTT04gZXhpc3RzLCBpdCB0YWtlIHByZWNlZGVuY2VcclxuICAgICAgaWYgKGN1c3RvbVZhbHVlICE9PSB1bmRlZmluZWQpIHtcclxuICAgICAgICBlbnRyeS52YWx1ZSA9IGN1c3RvbVZhbHVlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBJZiBhIHZhbHVlIGZyb20gYW4gZW52IHZhcmlhYmxlIGV4aXN0cywgaXQgdGFrZSBwcmVjZWRlbmNlXHJcbiAgICAgIGlmIChlbnRyeS5lbnZMaW5rKSB7XHJcbiAgICAgICAgLy8gTG9hZCB0aGUgZW52IHZhclxyXG4gICAgICAgIGlmIChlbnRyeS50eXBlID09PSAnYm9vbGVhbicpIHtcclxuICAgICAgICAgIGVudHJ5LnZhbHVlID0gdG9Cb29sZWFuKFxyXG4gICAgICAgICAgICBbcHJvY2Vzcy5lbnZbZW50cnkuZW52TGlua10sIGVudHJ5LnZhbHVlXS5maW5kKFxyXG4gICAgICAgICAgICAgIChlbCkgPT4gZWwgfHwgZWwgPT09ICdmYWxzZSdcclxuICAgICAgICAgICAgKVxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9IGVsc2UgaWYgKGVudHJ5LnR5cGUgPT09ICdudW1iZXInKSB7XHJcbiAgICAgICAgICBudW1FbnZWYWwgPSArcHJvY2Vzcy5lbnZbZW50cnkuZW52TGlua107XHJcbiAgICAgICAgICBlbnRyeS52YWx1ZSA9IG51bUVudlZhbCA+PSAwID8gbnVtRW52VmFsIDogZW50cnkudmFsdWU7XHJcbiAgICAgICAgfSBlbHNlIGlmIChlbnRyeS50eXBlLmluZGV4T2YoJ10nKSA+PSAwICYmIHByb2Nlc3MuZW52W2VudHJ5LmVudkxpbmtdKSB7XHJcbiAgICAgICAgICBlbnRyeS52YWx1ZSA9IHByb2Nlc3MuZW52W2VudHJ5LmVudkxpbmtdLnNwbGl0KCcsJyk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIGVudHJ5LnZhbHVlID0gcHJvY2Vzcy5lbnZbZW50cnkuZW52TGlua10gfHwgZW50cnkudmFsdWU7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyBvcHRpb25zIG9iamVjdCBiYXNlZCBvbiBwcm92aWRlZCBpdGVtcywgc2V0dGluZyB2YWx1ZXMgZnJvbVxyXG4gKiBuZXN0ZWQgcHJvcGVydGllcyByZWN1cnNpdmVseS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGl0ZW1zIC0gQ29uZmlndXJhdGlvbiBpdGVtcyB0byBiZSB1c2VkIGZvciBpbml0aWFsaXppbmdcclxuICogb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gSW5pdGlhbGl6ZWQgb3B0aW9ucyBvYmplY3QuXHJcbiAqL1xyXG5mdW5jdGlvbiBpbml0T3B0aW9ucyhpdGVtcykge1xyXG4gIGxldCBvcHRpb25zID0ge307XHJcbiAgZm9yIChjb25zdCBbbmFtZSwgaXRlbV0gb2YgT2JqZWN0LmVudHJpZXMoaXRlbXMpKSB7XHJcbiAgICBvcHRpb25zW25hbWVdID0gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGl0ZW0sICd2YWx1ZScpXHJcbiAgICAgID8gaXRlbS52YWx1ZVxyXG4gICAgICA6IGluaXRPcHRpb25zKGl0ZW0pO1xyXG4gIH1cclxuICByZXR1cm4gb3B0aW9ucztcclxufVxyXG5cclxuLyoqXHJcbiAqIFBhaXJzIGFyZ3VtZW50IHZhbHVlcyB3aXRoIGNvcnJlc3BvbmRpbmcgb3B0aW9ucyBpbiB0aGUgY29uZmlndXJhdGlvbixcclxuICogdXBkYXRpbmcgdGhlIG9wdGlvbnMgb2JqZWN0LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIENvbmZpZ3VyYXRpb24gb3B0aW9ucyBvYmplY3QgdG8gYmUgdXBkYXRlZC5cclxuICogQHBhcmFtIHtBcnJheX0gYXJncyAtIENvbW1hbmQtbGluZSBhcmd1bWVudHMgY29udGFpbmluZyB2YWx1ZXMgZm9yIHNwZWNpZmljXHJcbiAqIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBkZWZhdWx0Q29uZmlnIC0gRGVmYXVsdCBjb25maWd1cmF0aW9uIG9iamVjdCBmb3IgcmVmZXJlbmNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBVcGRhdGVkIG9wdGlvbnMgb2JqZWN0LlxyXG4gKi9cclxuZnVuY3Rpb24gcGFpckFyZ3VtZW50VmFsdWUob3B0aW9ucywgYXJncywgZGVmYXVsdENvbmZpZykge1xyXG4gIGxldCBzaG93VXNhZ2UgPSBmYWxzZTtcclxuICBmb3IgKGxldCBpID0gMDsgaSA8IGFyZ3MubGVuZ3RoOyBpKyspIHtcclxuICAgIGNvbnN0IG9wdGlvbiA9IGFyZ3NbaV0ucmVwbGFjZSgvLS9nLCAnJyk7XHJcblxyXG4gICAgLy8gRmluZCB0aGUgcmlnaHQgcGxhY2UgZm9yIHByb3BlcnR5J3MgdmFsdWVcclxuICAgIGNvbnN0IHByb3BlcnRpZXNDaGFpbiA9IG5lc3RlZEFyZ3Nbb3B0aW9uXVxyXG4gICAgICA/IG5lc3RlZEFyZ3Nbb3B0aW9uXS5zcGxpdCgnLicpXHJcbiAgICAgIDogW107XHJcblxyXG4gICAgLy8gR2V0IHRoZSBjb3JyZWN0IHR5cGUgZm9yIENMSSBhcmdzIHdoaWNoIGFyZSBwYXNzZWQgYXMgc3RyaW5nc1xyXG4gICAgbGV0IGFyZ3VtZW50VHlwZTtcclxuICAgIHByb3BlcnRpZXNDaGFpbi5yZWR1Y2UoKG9iaiwgcHJvcCwgaW5kZXgpID0+IHtcclxuICAgICAgaWYgKHByb3BlcnRpZXNDaGFpbi5sZW5ndGggLSAxID09PSBpbmRleCkge1xyXG4gICAgICAgIGFyZ3VtZW50VHlwZSA9IG9ialtwcm9wXS50eXBlO1xyXG4gICAgICB9XHJcbiAgICAgIHJldHVybiBvYmpbcHJvcF07XHJcbiAgICB9LCBkZWZhdWx0Q29uZmlnKTtcclxuXHJcbiAgICBwcm9wZXJ0aWVzQ2hhaW4ucmVkdWNlKChvYmosIHByb3AsIGluZGV4KSA9PiB7XHJcbiAgICAgIGlmIChwcm9wZXJ0aWVzQ2hhaW4ubGVuZ3RoIC0gMSA9PT0gaW5kZXgpIHtcclxuICAgICAgICAvLyBGaW5kcyBhbiBvcHRpb24gYW5kIHNldCBhIGNvcnJlc3BvbmRpbmcgdmFsdWVcclxuICAgICAgICBpZiAodHlwZW9mIG9ialtwcm9wXSAhPT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgICAgIGlmIChhcmdzWysraV0pIHtcclxuICAgICAgICAgICAgaWYgKGFyZ3VtZW50VHlwZSA9PT0gJ2Jvb2xlYW4nKSB7XHJcbiAgICAgICAgICAgICAgb2JqW3Byb3BdID0gdG9Cb29sZWFuKGFyZ3NbaV0pO1xyXG4gICAgICAgICAgICB9IGVsc2UgaWYgKGFyZ3VtZW50VHlwZSA9PT0gJ251bWJlcicpIHtcclxuICAgICAgICAgICAgICBvYmpbcHJvcF0gPSArYXJnc1tpXTtcclxuICAgICAgICAgICAgfSBlbHNlIGlmIChhcmd1bWVudFR5cGUuaW5kZXhPZignXScpID49IDApIHtcclxuICAgICAgICAgICAgICBvYmpbcHJvcF0gPSBhcmdzW2ldLnNwbGl0KCcsJyk7XHJcbiAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgb2JqW3Byb3BdID0gYXJnc1tpXTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgbG9nKFxyXG4gICAgICAgICAgICAgIDIsXHJcbiAgICAgICAgICAgICAgYFtjb25maWddIE1pc3NpbmcgdmFsdWUgZm9yIHRoZSAnJHtvcHRpb259JyBhcmd1bWVudC4gVXNpbmcgdGhlIGRlZmF1bHQgdmFsdWUuYFxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgICBzaG93VXNhZ2UgPSB0cnVlO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gb2JqW3Byb3BdO1xyXG4gICAgfSwgb3B0aW9ucyk7XHJcbiAgfVxyXG5cclxuICAvLyBEaXNwbGF5IHRoZSB1c2FnZSBmb3IgdGhlIHJlZmVyZW5jZSBpZiBuZWVkZWRcclxuICBpZiAoc2hvd1VzYWdlKSB7XHJcbiAgICBwcmludFVzYWdlKGRlZmF1bHRDb25maWcpO1xyXG4gIH1cclxuXHJcbiAgcmV0dXJuIG9wdGlvbnM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZWN1cnNpdmVseSB1cGRhdGVzIHByb3BlcnRpZXMgaW4gYW4gb2JqZWN0IGJhc2VkIG9uIG5lc3RlZCBuYW1lcyBhbmQgYXNzaWduc1xyXG4gKiB0aGUgZmluYWwgdmFsdWUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvYmplY3RUb1VwZGF0ZSAtIFRoZSBvYmplY3QgdG8gYmUgdXBkYXRlZC5cclxuICogQHBhcmFtIHtBcnJheX0gbmVzdGVkTmFtZXMgLSBBcnJheSBvZiBuZXN0ZWQgcHJvcGVydHkgbmFtZXMuXHJcbiAqIEBwYXJhbSB7YW55fSB2YWx1ZSAtIFRoZSBmaW5hbCB2YWx1ZSB0byBiZSBhc3NpZ25lZC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVXBkYXRlZCBvYmplY3Qgd2l0aCBhc3NpZ25lZCB2YWx1ZXMuXHJcbiAqL1xyXG5mdW5jdGlvbiByZWN1cnNpdmVQcm9wcyhvYmplY3RUb1VwZGF0ZSwgbmVzdGVkTmFtZXMsIHZhbHVlKSB7XHJcbiAgd2hpbGUgKG5lc3RlZE5hbWVzLmxlbmd0aCA+IDEpIHtcclxuICAgIGNvbnN0IHByb3BOYW1lID0gbmVzdGVkTmFtZXMuc2hpZnQoKTtcclxuXHJcbiAgICAvLyBDcmVhdGUgYSBwcm9wZXJ0eSBpbiBvYmplY3QgaWYgaXQgZG9lc24ndCBleGlzdFxyXG4gICAgaWYgKCFPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob2JqZWN0VG9VcGRhdGUsIHByb3BOYW1lKSkge1xyXG4gICAgICBvYmplY3RUb1VwZGF0ZVtwcm9wTmFtZV0gPSB7fTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBDYWxsIGZ1bmN0aW9uIGFnYWluIGlmIHRoZXJlIHN0aWxsIG5hbWVzIHRvIGdvXHJcbiAgICBvYmplY3RUb1VwZGF0ZVtwcm9wTmFtZV0gPSByZWN1cnNpdmVQcm9wcyhcclxuICAgICAgT2JqZWN0LmFzc2lnbih7fSwgb2JqZWN0VG9VcGRhdGVbcHJvcE5hbWVdKSxcclxuICAgICAgbmVzdGVkTmFtZXMsXHJcbiAgICAgIHZhbHVlXHJcbiAgICApO1xyXG5cclxuICAgIHJldHVybiBvYmplY3RUb1VwZGF0ZTtcclxuICB9XHJcblxyXG4gIC8vIEFzc2lnbiB0aGUgZmluYWwgdmFsdWVcclxuICBvYmplY3RUb1VwZGF0ZVtuZXN0ZWROYW1lc1swXV0gPSB2YWx1ZTtcclxuICByZXR1cm4gb2JqZWN0VG9VcGRhdGU7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBnZXRPcHRpb25zLFxyXG4gIHNldE9wdGlvbnMsXHJcbiAgbWFudWFsQ29uZmlnLFxyXG4gIG1hcFRvTmV3Q29uZmlnLFxyXG4gIG1lcmdlQ29uZmlnT3B0aW9ucyxcclxuICBpbml0RXhwb3J0U2V0dGluZ3NcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgZnMgZnJvbSAnZnMnO1xyXG5pbXBvcnQgKiBhcyB1cmwgZnJvbSAndXJsJztcclxuaW1wb3J0IHBhdGggZnJvbSAnbm9kZTpwYXRoJztcclxuXHJcbmltcG9ydCBwdXBwZXRlZXIgZnJvbSAncHVwcGV0ZWVyJztcclxuXHJcbi8vIFdvcmthcm91bmQgZm9yIGh0dHBzOi8vYnVncy5jaHJvbWl1bS5vcmcvcC9jaHJvbWl1bS9pc3N1ZXMvZGV0YWlsP2lkPTE0NjMzMjhcclxuLy8gTm90IGlkZWFsIC0gbGVhdmVzIHRyYXNoIGluIHRoZSBGU1xyXG5pbXBvcnQgeyByYW5kb21CeXRlcyB9IGZyb20gJ25vZGU6Y3J5cHRvJztcclxuXHJcbmltcG9ydCB7IGdldENhY2hlUGF0aCB9IGZyb20gJy4vY2FjaGUuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG5jb25zdCBSQU5ET01fUElEID0gcmFuZG9tQnl0ZXMoNjQpLnRvU3RyaW5nKCdiYXNlNjR1cmwnKTtcclxuY29uc3QgUFVQUEVURUVSX0RJUiA9IHBhdGguam9pbigndG1wJywgYHB1cHBldGVlci0ke1JBTkRPTV9QSUR9YCk7XHJcbmNvbnN0IERBVEFfRElSID0gcGF0aC5qb2luKFBVUFBFVEVFUl9ESVIsICdwcm9maWxlJyk7XHJcblxyXG4vLyBUaGUgbWluaW1hbCBhcmdzIHRvIHNwZWVkIHVwIHRoZSBicm93c2VyXHJcbmNvbnN0IG1pbmltYWxBcmdzID0gW1xyXG4gIGAtLXVzZXItZGF0YS1kaXI9JHtEQVRBX0RJUn1gLFxyXG4gICctLWF1dG9wbGF5LXBvbGljeT11c2VyLWdlc3R1cmUtcmVxdWlyZWQnLFxyXG4gICctLWRpc2FibGUtYmFja2dyb3VuZC1uZXR3b3JraW5nJyxcclxuICAnLS1kaXNhYmxlLWJhY2tncm91bmQtdGltZXItdGhyb3R0bGluZycsXHJcbiAgJy0tZGlzYWJsZS1iYWNrZ3JvdW5kaW5nLW9jY2x1ZGVkLXdpbmRvd3MnLFxyXG4gICctLWRpc2FibGUtYnJlYWtwYWQnLFxyXG4gICctLWRpc2FibGUtY2xpZW50LXNpZGUtcGhpc2hpbmctZGV0ZWN0aW9uJyxcclxuICAnLS1kaXNhYmxlLWNvbXBvbmVudC11cGRhdGUnLFxyXG4gICctLWRpc2FibGUtZGVmYXVsdC1hcHBzJyxcclxuICAnLS1kaXNhYmxlLWRldi1zaG0tdXNhZ2UnLFxyXG4gICctLWRpc2FibGUtZG9tYWluLXJlbGlhYmlsaXR5JyxcclxuICAnLS1kaXNhYmxlLWV4dGVuc2lvbnMnLFxyXG4gICctLWRpc2FibGUtZmVhdHVyZXM9QXVkaW9TZXJ2aWNlT3V0T2ZQcm9jZXNzJyxcclxuICAnLS1kaXNhYmxlLWhhbmctbW9uaXRvcicsXHJcbiAgJy0tZGlzYWJsZS1pcGMtZmxvb2RpbmctcHJvdGVjdGlvbicsXHJcbiAgJy0tZGlzYWJsZS1ub3RpZmljYXRpb25zJyxcclxuICAnLS1kaXNhYmxlLW9mZmVyLXN0b3JlLXVubWFza2VkLXdhbGxldC1jYXJkcycsXHJcbiAgJy0tZGlzYWJsZS1wb3B1cC1ibG9ja2luZycsXHJcbiAgJy0tZGlzYWJsZS1wcmludC1wcmV2aWV3JyxcclxuICAnLS1kaXNhYmxlLXByb21wdC1vbi1yZXBvc3QnLFxyXG4gICctLWRpc2FibGUtcmVuZGVyZXItYmFja2dyb3VuZGluZycsXHJcbiAgJy0tZGlzYWJsZS1zZXNzaW9uLWNyYXNoZWQtYnViYmxlJyxcclxuICAnLS1kaXNhYmxlLXNldHVpZC1zYW5kYm94JyxcclxuICAnLS1kaXNhYmxlLXNwZWVjaC1hcGknLFxyXG4gICctLWRpc2FibGUtc3luYycsXHJcbiAgJy0taGlkZS1jcmFzaC1yZXN0b3JlLWJ1YmJsZScsXHJcbiAgJy0taGlkZS1zY3JvbGxiYXJzJyxcclxuICAnLS1pZ25vcmUtZ3B1LWJsYWNrbGlzdCcsXHJcbiAgJy0tbWV0cmljcy1yZWNvcmRpbmctb25seScsXHJcbiAgJy0tbXV0ZS1hdWRpbycsXHJcbiAgJy0tbm8tZGVmYXVsdC1icm93c2VyLWNoZWNrJyxcclxuICAnLS1uby1maXJzdC1ydW4nLFxyXG4gICctLW5vLXBpbmdzJyxcclxuICAnLS1uby1zYW5kYm94JyxcclxuICAnLS1uby16eWdvdGUnLFxyXG4gICctLXBhc3N3b3JkLXN0b3JlPWJhc2ljJyxcclxuICAnLS11c2UtbW9jay1rZXljaGFpbidcclxuXTtcclxuXHJcbmNvbnN0IF9fZGlybmFtZSA9IHVybC5maWxlVVJMVG9QYXRoKG5ldyBVUkwoJy4nLCBpbXBvcnQubWV0YS51cmwpKTtcclxuXHJcbmNvbnN0IHRlbXBsYXRlID0gZnMucmVhZEZpbGVTeW5jKFxyXG4gIF9fZGlybmFtZSArICcvLi4vdGVtcGxhdGVzL3RlbXBsYXRlLmh0bWwnLFxyXG4gICd1dGY4J1xyXG4pO1xyXG5cclxubGV0IGJyb3dzZXI7XHJcblxyXG4vKipcclxuICogU2V0cyB0aGUgY29udGVudCBmb3IgYSBQdXBwZXRlZXIgUGFnZSB1c2luZyBhIHByZWRlZmluZWQgdGVtcGxhdGVcclxuICogYW5kIGFkZGl0aW9uYWwgc2NyaXB0cy4gQWxzbywgc2V0cyB0aGUgcGFnZWVycm9yIGluIG9yZGVyIHRvIGNhdGNoXHJcbiAqIGFuZCBkaXNwbGF5IGVycm9ycyBmcm9tIHRoZSB3aW5kb3cgY29udGV4dC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IGZvciB3aGljaCB0aGUgY29udGVudFxyXG4gKiBpcyBiZWluZyBzZXQuXHJcbiAqL1xyXG5jb25zdCBzZXRQYWdlQ29udGVudCA9IGFzeW5jIChwYWdlKSA9PiB7XHJcbiAgYXdhaXQgcGFnZS5zZXRDb250ZW50KHRlbXBsYXRlKTtcclxuICBhd2FpdCBwYWdlLmFkZFNjcmlwdFRhZyh7IHBhdGg6IGAke2dldENhY2hlUGF0aCgpfS9zb3VyY2VzLmpzYCB9KTtcclxuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICBhd2FpdCBwYWdlLmV2YWx1YXRlKCgpID0+IHdpbmRvdy5zZXR1cEhpZ2hjaGFydHMoKSk7XHJcblxyXG4gIHBhZ2Uub24oJ3BhZ2VlcnJvcicsIGFzeW5jIChlcnJvcikgPT4ge1xyXG4gICAgLy8gVE9ETzogQ29uc2lkZXIgYWRkaW5nIGEgc3dpdGNoIGhlcmUgdGhhdCB0dXJucyBvbiBsb2coMCkgbG9nZ2luZ1xyXG4gICAgLy8gb24gcGFnZSBlcnJvcnMuXHJcbiAgICBhd2FpdCBwYWdlLiRldmFsKFxyXG4gICAgICAnI2NvbnRhaW5lcicsXHJcbiAgICAgIChlbGVtZW50LCBlcnJvck1lc3NhZ2UpID0+IHtcclxuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICBpZiAod2luZG93Ll9kaXNwbGF5RXJyb3JzKSB7XHJcbiAgICAgICAgICBlbGVtZW50LmlubmVySFRNTCA9IGVycm9yTWVzc2FnZTtcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIGA8aDE+Q2hhcnQgaW5wdXQgZGF0YSBlcnJvcjwvaDE+JHtlcnJvci50b1N0cmluZygpfWBcclxuICAgICk7XHJcbiAgfSk7XHJcbn07XHJcblxyXG4vKipcclxuICogQ2xlYXJzIHRoZSBjb250ZW50IG9mIGEgUHVwcGV0ZWVyIFBhZ2UgYmFzZWQgb24gdGhlIHNwZWNpZmllZCBtb2RlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFRoZSBQdXBwZXRlZXIgUGFnZSBvYmplY3QgdG8gYmUgY2xlYXJlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBoYXJkUmVzZXQgLSBBIGZsYWcgaW5kaWNhdGluZyB0aGUgdHlwZSBvZiBjbGVhcmluZ1xyXG4gKiB0byBiZSBwZXJmb3JtZWQuIElmIHRydWUsIG5hdmlnYXRlcyB0byAnYWJvdXQ6YmxhbmsnIGFuZCByZXNldHMgY29udGVudFxyXG4gKiBhbmQgc2NyaXB0cy4gSWYgZmFsc2UsIGNsZWFycyB0aGUgYm9keSBjb250ZW50IGJ5IHNldHRpbmcgYSBwcmVkZWZpbmVkIEhUTUxcclxuICogc3RydWN0dXJlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFcnJvcn0gTG9ncyB0aHJvd24gZXJyb3IgaWYgY2xlYXJpbmcgdGhlIHBhZ2UgY29udGVudCBmYWlscy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBjbGVhclBhZ2UgPSBhc3luYyAocGFnZSwgaGFyZFJlc2V0ID0gZmFsc2UpID0+IHtcclxuICB0cnkge1xyXG4gICAgaWYgKGhhcmRSZXNldCkge1xyXG4gICAgICAvLyBOYXZpZ2F0ZSB0byBhYm91dDpibGFua1xyXG4gICAgICBhd2FpdCBwYWdlLmdvdG8oJ2Fib3V0OmJsYW5rJyk7XHJcblxyXG4gICAgICAvLyBTZXQgdGhlIGNvbnRlbnQgYW5kIGFuZCBzY3JpcHRzIGFnYWluXHJcbiAgICAgIGF3YWl0IHNldFBhZ2VDb250ZW50KHBhZ2UpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gQ2xlYXIgYm9keSBjb250ZW50XHJcbiAgICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xyXG4gICAgICAgIGRvY3VtZW50LmJvZHkuaW5uZXJIVE1MID1cclxuICAgICAgICAgICc8ZGl2IGlkPVwiY2hhcnQtY29udGFpbmVyXCI+PGRpdiBpZD1cImNvbnRhaW5lclwiPjwvZGl2PjwvZGl2Pic7XHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgIDIsXHJcbiAgICAgIGVycm9yLFxyXG4gICAgICAnW2Jyb3dzZXJdIENvdWxkIG5vdCBjbGVhciB0aGUgY29udGVudCBvZiB0aGUgcGFnZS4nXHJcbiAgICApO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgbmV3IFB1cHBldGVlciBQYWdlIHdpdGhpbiBhbiBleGlzdGluZyBicm93c2VyIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBJZiB0aGUgYnJvd3NlciBpbnN0YW5jZSBpcyBub3QgYXZhaWxhYmxlLCByZXR1cm5zIGZhbHNlLlxyXG4gKlxyXG4gKiBUaGUgZnVuY3Rpb24gY3JlYXRlcyBhIG5ldyBwYWdlLCBkaXNhYmxlcyBjYWNoaW5nLCBzZXRzIGNvbnRlbnQgdXNpbmdcclxuICogc2V0UGFnZUNvbnRlbnQoKSwgYW5kIHJldHVybnMgdGhlIGNyZWF0ZWQgUHVwcGV0ZWVyIFBhZ2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHsoYm9vbGVhbnxvYmplY3QpfSBSZXR1cm5zIGZhbHNlIGlmIHRoZSBicm93c2VyIGluc3RhbmNlIGlzIG5vdFxyXG4gKiBhdmFpbGFibGUsIG9yIGEgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IHJlcHJlc2VudGluZyB0aGUgbmV3bHkgY3JlYXRlZCBwYWdlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IG5ld1BhZ2UgPSBhc3luYyAoKSA9PiB7XHJcbiAgaWYgKCFicm93c2VyKSB7XHJcbiAgICByZXR1cm4gZmFsc2U7XHJcbiAgfVxyXG5cclxuICBjb25zdCBwYWdlID0gYXdhaXQgYnJvd3Nlci5uZXdQYWdlKCk7XHJcblxyXG4gIC8vIERpc2FibGUgY2FjaGVcclxuICBhd2FpdCBwYWdlLnNldENhY2hlRW5hYmxlZChmYWxzZSk7XHJcblxyXG4gIC8vIFNldCB0aGUgY29udGVudFxyXG4gIGF3YWl0IHNldFBhZ2VDb250ZW50KHBhZ2UpO1xyXG4gIHJldHVybiBwYWdlO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYSBQdXBwZXRlZXIgYnJvd3NlciBpbnN0YW5jZSB3aXRoIHRoZSBzcGVjaWZpZWQgYXJndW1lbnRzLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0FycmF5fSBwdXBwZXRlZXJBcmdzIC0gQWRkaXRpb25hbCBhcmd1bWVudHMgZm9yIFB1cHBldGVlciBsYXVuY2guXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPG9iamVjdD59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIFB1cHBldGVlciBicm93c2VyXHJcbiAqIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIG1heCByZXRyaWVzIHRvIG9wZW4gYSBicm93c2VyXHJcbiAqIGluc3RhbmNlIGFyZSByZWFjaGVkLCBvciBpZiBubyBicm93c2VyIGluc3RhbmNlIGlzIGZvdW5kIGFmdGVyIHJldHJpZXMuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgY3JlYXRlID0gYXN5bmMgKHB1cHBldGVlckFyZ3MpID0+IHtcclxuICBjb25zdCBhbGxBcmdzID0gWy4uLm1pbmltYWxBcmdzLCAuLi4ocHVwcGV0ZWVyQXJncyB8fCBbXSldO1xyXG5cclxuICAvLyBDcmVhdGUgYSBicm93c2VyXHJcbiAgaWYgKCFicm93c2VyKSB7XHJcbiAgICBsZXQgdHJ5Q291bnQgPSAwO1xyXG5cclxuICAgIGNvbnN0IG9wZW4gPSBhc3luYyAoKSA9PiB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbYnJvd3Nlcl0gQXR0ZW1wdGluZyB0byBnZXQgYSBicm93c2VyIGluc3RhbmNlICh0cnkgJHsrK3RyeUNvdW50fSkuYFxyXG4gICAgICAgICk7XHJcbiAgICAgICAgYnJvd3NlciA9IGF3YWl0IHB1cHBldGVlci5sYXVuY2goe1xyXG4gICAgICAgICAgaGVhZGxlc3M6ICduZXcnLFxyXG4gICAgICAgICAgYXJnczogYWxsQXJncyxcclxuICAgICAgICAgIHVzZXJEYXRhRGlyOiAnLi90bXAvJ1xyXG4gICAgICAgIH0pO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAgIDEsXHJcbiAgICAgICAgICBlcnJvcixcclxuICAgICAgICAgICdbYnJvd3Nlcl0gRmFpbGVkIHRvIGxhdW5jaCBhIGJyb3dzZXIgaW5zdGFuY2UuJ1xyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIC8vIFJldHJ5IHRvIGxhdW5jaCBicm93c2VyIHVudGlsIHJlYWNoaW5nIG1heCBhdHRlbXB0c1xyXG4gICAgICAgIGlmICh0cnlDb3VudCA8IDI1KSB7XHJcbiAgICAgICAgICBsb2coMywgYFticm93c2VyXSBSZXRyeSB0byBvcGVuIGEgYnJvd3NlciAoJHt0cnlDb3VudH0gb3V0IG9mIDI1KS5gKTtcclxuICAgICAgICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNwb25zZSkgPT4gc2V0VGltZW91dChyZXNwb25zZSwgNDAwMCkpO1xyXG4gICAgICAgICAgYXdhaXQgb3BlbigpO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH07XHJcblxyXG4gICAgdHJ5IHtcclxuICAgICAgYXdhaXQgb3BlbigpO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdbYnJvd3Nlcl0gTWF4aW11bSByZXRyaWVzIHRvIG9wZW4gYSBicm93c2VyIGluc3RhbmNlIHJlYWNoZWQuJ1xyXG4gICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoIWJyb3dzZXIpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbYnJvd3Nlcl0gQ2Fubm90IGZpbmQgYSBicm93c2VyIHRvIG9wZW4uJyk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gYSBicm93c2VyIHByb21pc2VcclxuICByZXR1cm4gYnJvd3NlcjtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgdGhlIGV4aXN0aW5nIFB1cHBldGVlciBicm93c2VyIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxvYmplY3Q+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBQdXBwZXRlZXIgYnJvd3NlclxyXG4gKiBpbnN0YW5jZS5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiBubyB2YWxpZCBicm93c2VyIGhhcyBiZWVuXHJcbiAqIGNyZWF0ZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0ID0gYXN5bmMgKCkgPT4ge1xyXG4gIGlmICghYnJvd3Nlcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbYnJvd3Nlcl0gTm8gdmFsaWQgYnJvd3NlciBoYXMgYmVlbiBjcmVhdGVkLicpO1xyXG4gIH1cclxuXHJcbiAgcmV0dXJuIGJyb3dzZXI7XHJcbn07XHJcblxyXG4vKipcclxuICogQ2xvc2VzIHRoZSBQdXBwZXRlZXIgYnJvd3NlciBpbnN0YW5jZSBpZiBpdCBpcyBjb25uZWN0ZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPGJvb2xlYW4+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIHRydWUgYWZ0ZXIgdGhlIGJyb3dzZXJcclxuICogaXMgY2xvc2VkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGNsb3NlID0gYXN5bmMgKCkgPT4ge1xyXG4gIC8vIENsb3NlIHRoZSBicm93c2VyIHdoZW4gY29ubm5lY3RlZFxyXG4gIGlmIChicm93c2VyPy5pc0Nvbm5lY3RlZCgpKSB7XHJcbiAgICBhd2FpdCBicm93c2VyLmNsb3NlKCk7XHJcbiAgICBsb2coNCwgJ1ticm93c2VyXSBDbG9zZWQgdGhlIGJyb3dzZXIuJyk7XHJcbiAgfVxyXG4gIHJldHVybiB0cnVlO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIG5ld1BhZ2UsXHJcbiAgY2xlYXJQYWdlLFxyXG4gIGdldCxcclxuICBjbG9zZVxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHBhdGggZnJvbSAncGF0aCc7XHJcbmltcG9ydCAqIGFzIHVybCBmcm9tICd1cmwnO1xyXG5cclxuaW1wb3J0IGNhY2hlIGZyb20gJy4vY2FjaGUuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHN2Z1RlbXBsYXRlIGZyb20gJy4vLi4vdGVtcGxhdGVzL3N2Z19leHBvcnQvc3ZnX2V4cG9ydC5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuY29uc3QgX19iYXNlZGlyID0gdXJsLmZpbGVVUkxUb1BhdGgobmV3IFVSTCgnLicsIGltcG9ydC5tZXRhLnVybCkpO1xyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyB0aGUgY2xpcHBpbmcgcmVnaW9uIGNvb3JkaW5hdGVzIG9mIHRoZSBzcGVjaWZpZWQgcGFnZSBlbGVtZW50IHdpdGhcclxuICogdGhlIGlkICdjaGFydC1jb250YWluZXInLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gYW4gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogeCwgeSwgd2lkdGgsIGFuZCBoZWlnaHQgcHJvcGVydGllcy5cclxuICovXHJcbmNvbnN0IGdldENsaXBSZWdpb24gPSAocGFnZSkgPT5cclxuICBwYWdlLiRldmFsKCcjY2hhcnQtY29udGFpbmVyJywgKGVsZW1lbnQpID0+IHtcclxuICAgIGNvbnN0IHsgeCwgeSwgd2lkdGgsIGhlaWdodCB9ID0gZWxlbWVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcclxuICAgIHJldHVybiB7XHJcbiAgICAgIHgsXHJcbiAgICAgIHksXHJcbiAgICAgIHdpZHRoLFxyXG4gICAgICBoZWlnaHQ6IE1hdGgudHJ1bmMoaGVpZ2h0ID4gMSA/IGhlaWdodCA6IDUwMClcclxuICAgIH07XHJcbiAgfSk7XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhbiBpbWFnZSB1c2luZyBQdXBwZXRlZXIncyBwYWdlIHNjcmVlbnNob3QgZnVuY3Rpb25hbGl0eSB3aXRoXHJcbiAqIHNwZWNpZmllZCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICogQHBhcmFtIHtzdHJpbmd9IHR5cGUgLSBJbWFnZSB0eXBlLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gZW5jb2RpbmcgLSBJbWFnZSBlbmNvZGluZy5cclxuICogQHBhcmFtIHtPYmplY3R9IGNsaXAgLSBDbGlwcGluZyByZWdpb24gY29vcmRpbmF0ZXMuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSByYXN0ZXJpemF0aW9uVGltZW91dCAtIFRpbWVvdXQgZm9yIHJhc3Rlcml6YXRpb25cclxuICogaW4gbWlsbGlzZWNvbmRzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxCdWZmZXI+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgaW1hZ2UgYnVmZmVyIG9yIHJlamVjdGluZ1xyXG4gKiB3aXRoIGFuIEV4cG9ydEVycm9yIGZvciB0aW1lb3V0LlxyXG4gKi9cclxuY29uc3QgY3JlYXRlSW1hZ2UgPSAocGFnZSwgdHlwZSwgZW5jb2RpbmcsIGNsaXAsIHJhc3Rlcml6YXRpb25UaW1lb3V0KSA9PlxyXG4gIFByb21pc2UucmFjZShbXHJcbiAgICBwYWdlLnNjcmVlbnNob3Qoe1xyXG4gICAgICB0eXBlLFxyXG4gICAgICBlbmNvZGluZyxcclxuICAgICAgY2xpcCxcclxuXHJcbiAgICAgIC8vICM0NDcsICM0NjMgLSBhbHdheXMgcmVuZGVyIG9uIGEgdHJhbnNwYXJlbnQgcGFnZSBpZiB0aGUgZXhwZWN0ZWQgdHlwZVxyXG4gICAgICAvLyBmb3JtYXQgaXMgUE5HXHJcbiAgICAgIG9taXRCYWNrZ3JvdW5kOiB0eXBlID09ICdwbmcnXHJcbiAgICB9KSxcclxuICAgIG5ldyBQcm9taXNlKChfcmVzb2x2ZSwgcmVqZWN0KSA9PlxyXG4gICAgICBzZXRUaW1lb3V0KFxyXG4gICAgICAgICgpID0+IHJlamVjdChuZXcgRXhwb3J0RXJyb3IoJ1Jhc3Rlcml6YXRpb24gdGltZW91dCcpKSxcclxuICAgICAgICByYXN0ZXJpemF0aW9uVGltZW91dCB8fCAxNTAwXHJcbiAgICAgIClcclxuICAgIClcclxuICBdKTtcclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgUERGIHVzaW5nIFB1cHBldGVlcidzIHBhZ2UgcGRmIGZ1bmN0aW9uYWxpdHkgd2l0aCBzcGVjaWZpZWRcclxuICogb3B0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBoZWlnaHQgLSBQREYgaGVpZ2h0LlxyXG4gKiBAcGFyYW0ge251bWJlcn0gd2lkdGggLSBQREYgd2lkdGguXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBlbmNvZGluZyAtIFBERiBlbmNvZGluZy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8QnVmZmVyPn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIFBERiBidWZmZXIuXHJcbiAqL1xyXG5jb25zdCBjcmVhdGVQREYgPSAocGFnZSwgaGVpZ2h0LCB3aWR0aCwgZW5jb2RpbmcpID0+XHJcbiAgcGFnZS5wZGYoe1xyXG4gICAgLy8gVGhpcyB3aWxsIHJlbW92ZSBhbiBleHRyYSBlbXB0eSBwYWdlIGluIFBERiBleHBvcnRzXHJcbiAgICBoZWlnaHQ6IGhlaWdodCArIDEsXHJcbiAgICB3aWR0aCxcclxuICAgIGVuY29kaW5nXHJcbiAgfSk7XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhbiBTVkcgc3RyaW5nIGJ5IGV2YWx1YXRpbmcgdGhlIG91dGVySFRNTCBvZiB0aGUgZmlyc3QgJ3N2ZycgZWxlbWVudFxyXG4gKiBpbnNpZGUgYW4gZWxlbWVudCB3aXRoIHRoZSBpZCAnY29udGFpbmVyJy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZz59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBTVkcgc3RyaW5nLlxyXG4gKi9cclxuY29uc3QgY3JlYXRlU1ZHID0gKHBhZ2UpID0+XHJcbiAgcGFnZS4kZXZhbCgnI2NvbnRhaW5lciBzdmc6Zmlyc3Qtb2YtdHlwZScsIChlbGVtZW50KSA9PiBlbGVtZW50Lm91dGVySFRNTCk7XHJcblxyXG4vKipcclxuICogU2V0cyB0aGUgc3BlY2lmaWVkIGNoYXJ0IGFuZCBvcHRpb25zIGFzIGNvbmZpZ3VyYXRpb24gaW50byB0aGUgdHJpZ2dlckV4cG9ydFxyXG4gKiBmdW5jdGlvbiB3aXRoaW4gdGhlIHdpbmRvdyBjb250ZXh0IHVzaW5nIHBhZ2UuZXZhbHVhdGUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge2FueX0gY2hhcnQgLSBUaGUgY2hhcnQgb2JqZWN0IHRvIGJlIGNvbmZpZ3VyZWQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gQ29uZmlndXJhdGlvbiBvcHRpb25zIGZvciB0aGUgY2hhcnQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBQcm9taXNlIHJlc29sdmluZyBhZnRlciB0aGUgY29uZmlndXJhdGlvbiBpcyBzZXQuXHJcbiAqL1xyXG5jb25zdCBzZXRBc0NvbmZpZyA9IChwYWdlLCBjaGFydCwgb3B0aW9ucykgPT5cclxuICBwYWdlLmV2YWx1YXRlKFxyXG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAoY2hhcnQsIG9wdGlvbnMpID0+IHdpbmRvdy50cmlnZ2VyRXhwb3J0KGNoYXJ0LCBvcHRpb25zKSxcclxuICAgIGNoYXJ0LFxyXG4gICAgb3B0aW9uc1xyXG4gICk7XHJcblxyXG4vKipcclxuICogRXhwb3J0cyB0byBhIGNoYXJ0IGZyb20gYSBwYWdlIHVzaW5nIFB1cHBldGVlci5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7YW55fSBjaGFydCAtIFRoZSBjaGFydCBvYmplY3Qgb3IgU1ZHIGNvbmZpZ3VyYXRpb24gdG8gYmUgZXhwb3J0ZWQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gRXhwb3J0IG9wdGlvbnMgYW5kIGNvbmZpZ3VyYXRpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZyB8IEJ1ZmZlciB8IEV4cG9ydEVycm9yPn0gUHJvbWlzZSByZXNvbHZpbmcgdG9cclxuICogdGhlIGV4cG9ydGVkIGRhdGEgb3IgcmVqZWN0aW5nIHdpdGggYW4gRXhwb3J0RXJyb3IuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCBhc3luYyAocGFnZSwgY2hhcnQsIG9wdGlvbnMpID0+IHtcclxuICAvKipcclxuICAgKiBLZWVwcyB0cmFjayBvZiBhbGwgcmVzb3VyY2VzIGFkZGVkIG9uIHRoZSBwYWdlIHdpdGggYWRkWFhYVGFnLiBldGNcclxuICAgKiBJdCdzIFZJVEFMIHRoYXQgYWxsIGFkZGVkIHJlc291cmNlcyBlbmRzIHVwIGhlcmUgc28gd2UgY2FuIGNsZWFyIHRoaW5nc1xyXG4gICAqIG91dCB3aGVuIGRvaW5nIGEgbmV3IGV4cG9ydCBpbiB0aGUgc2FtZSBwYWdlIVxyXG4gICAqL1xyXG4gIGNvbnN0IGluamVjdGVkUmVzb3VyY2VzID0gW107XHJcblxyXG4gIC8qKiBDbGVhciBvdXQgYWxsIHN0YXRlIHNldCBvbiB0aGUgcGFnZSB3aXRoIGFkZFNjcmlwdFRhZy9hZGRTdHlsZVRhZy4gKi9cclxuICBjb25zdCBjbGVhckluamVjdGVkID0gYXN5bmMgKHBhZ2UpID0+IHtcclxuICAgIGZvciAoY29uc3QgcmVzIG9mIGluamVjdGVkUmVzb3VyY2VzKSB7XHJcbiAgICAgIGF3YWl0IHJlcy5kaXNwb3NlKCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmVzZXQgYWxsIENTUyBhbmQgc2NyaXB0IHRhZ3NcclxuICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xyXG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgY29uc3QgWywgLi4uc2NyaXB0c1RvUmVtb3ZlXSA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdzY3JpcHQnKTtcclxuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgIGNvbnN0IFssIC4uLnN0eWxlc1RvUmVtb3ZlXSA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdzdHlsZScpO1xyXG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgY29uc3QgWy4uLmxpbmtzVG9SZW1vdmVdID0gZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ2xpbmsnKTtcclxuXHJcbiAgICAgIC8vIFJlbW92ZSB0YWdzXHJcbiAgICAgIGZvciAoY29uc3QgZWxlbWVudCBvZiBbXHJcbiAgICAgICAgLi4uc2NyaXB0c1RvUmVtb3ZlLFxyXG4gICAgICAgIC4uLnN0eWxlc1RvUmVtb3ZlLFxyXG4gICAgICAgIC4uLmxpbmtzVG9SZW1vdmVcclxuICAgICAgXSkge1xyXG4gICAgICAgIGVsZW1lbnQucmVtb3ZlKCk7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG4gIH07XHJcblxyXG4gIHRyeSB7XHJcbiAgICBsb2coNCwgJ1tleHBvcnRdIERldGVybWluaW5nIGV4cG9ydCBwYXRoLicpO1xyXG5cclxuICAgIGNvbnN0IGV4cG9ydE9wdGlvbnMgPSBvcHRpb25zLmV4cG9ydDtcclxuXHJcbiAgICAvLyBGb3JjZSBhIHJBRlxyXG4gICAgLy8gU2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9wdXBwZXRlZXIvcHVwcGV0ZWVyL2lzc3Vlcy83NTA3XHJcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4gcmVxdWVzdEFuaW1hdGlvbkZyYW1lKCgpID0+IHt9KSk7XHJcblxyXG4gICAgLy8gRGVjaWRlIHdoZXRoZXIgZGlzcGxheSBlcnJvciBvciBkZWJidWdlciB3cmFwcGVyIGFyb3VuZCBpdFxyXG4gICAgY29uc3QgZGlzcGxheUVycm9ycyA9XHJcbiAgICAgIGV4cG9ydE9wdGlvbnM/Lm9wdGlvbnM/LmNoYXJ0Py5kaXNwbGF5RXJyb3JzICYmXHJcbiAgICAgIGNhY2hlLmdldENhY2hlKCkuYWN0aXZlTWFuaWZlc3QubW9kdWxlcy5kZWJ1Z2dlcjtcclxuXHJcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoKGQpID0+ICh3aW5kb3cuX2Rpc3BsYXlFcnJvcnMgPSBkKSwgZGlzcGxheUVycm9ycyk7XHJcblxyXG4gICAgbGV0IGlzU1ZHO1xyXG4gICAgaWYgKFxyXG4gICAgICBjaGFydC5pbmRleE9mICYmXHJcbiAgICAgIChjaGFydC5pbmRleE9mKCc8c3ZnJykgPj0gMCB8fCBjaGFydC5pbmRleE9mKCc8P3htbCcpID49IDApXHJcbiAgICApIHtcclxuICAgICAgLy8gU1ZHIGlucHV0IGhhbmRsaW5nXHJcbiAgICAgIGxvZyg0LCAnW2V4cG9ydF0gVHJlYXRpbmcgYXMgU1ZHLicpO1xyXG5cclxuICAgICAgLy8gSWYgaW5wdXQgaXMgYWxzbyBTVkcsIGp1c3QgcmV0dXJuIGl0XHJcbiAgICAgIGlmIChleHBvcnRPcHRpb25zLnR5cGUgPT09ICdzdmcnKSB7XHJcbiAgICAgICAgcmV0dXJuIGNoYXJ0O1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpc1NWRyA9IHRydWU7XHJcbiAgICAgIGF3YWl0IHBhZ2Uuc2V0Q29udGVudChzdmdUZW1wbGF0ZShjaGFydCkpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gSlNPTiBjb25maWcgaGFuZGxpbmdcclxuICAgICAgbG9nKDQsICdbZXhwb3J0XSBUcmVhdGluZyBhcyBjb25maWcuJyk7XHJcblxyXG4gICAgICAvLyBOZWVkIHRvIHBlcmZvcm0gc3RyYWlnaHQgaW5qZWN0XHJcbiAgICAgIGlmIChleHBvcnRPcHRpb25zLnN0ckluaikge1xyXG4gICAgICAgIC8vIEluamVjdGlvbiBiYXNlZCBjb25maWd1cmF0aW9uIGV4cG9ydFxyXG4gICAgICAgIGF3YWl0IHNldEFzQ29uZmlnKFxyXG4gICAgICAgICAgcGFnZSxcclxuICAgICAgICAgIHtcclxuICAgICAgICAgICAgY2hhcnQ6IHtcclxuICAgICAgICAgICAgICBoZWlnaHQ6IGV4cG9ydE9wdGlvbnMuaGVpZ2h0LFxyXG4gICAgICAgICAgICAgIHdpZHRoOiBleHBvcnRPcHRpb25zLndpZHRoXHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0sXHJcbiAgICAgICAgICBvcHRpb25zXHJcbiAgICAgICAgKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICAvLyBCYXNpYyBjb25maWd1cmF0aW9uIGV4cG9ydFxyXG4gICAgICAgIGNoYXJ0LmNoYXJ0LmhlaWdodCA9IGV4cG9ydE9wdGlvbnMuaGVpZ2h0O1xyXG4gICAgICAgIGNoYXJ0LmNoYXJ0LndpZHRoID0gZXhwb3J0T3B0aW9ucy53aWR0aDtcclxuXHJcbiAgICAgICAgYXdhaXQgc2V0QXNDb25maWcocGFnZSwgY2hhcnQsIG9wdGlvbnMpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gVXNlIHJlc291cmNlc1xyXG4gICAgY29uc3QgcmVzb3VyY2VzID0gb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXM7XHJcbiAgICBpZiAocmVzb3VyY2VzKSB7XHJcbiAgICAgIC8vIExvYWQgY3VzdG9tIEpTIGNvZGVcclxuICAgICAgaWYgKHJlc291cmNlcy5qcykge1xyXG4gICAgICAgIGluamVjdGVkUmVzb3VyY2VzLnB1c2goXHJcbiAgICAgICAgICBhd2FpdCBwYWdlLmFkZFNjcmlwdFRhZyh7XHJcbiAgICAgICAgICAgIGNvbnRlbnQ6IHJlc291cmNlcy5qc1xyXG4gICAgICAgICAgfSlcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBMb2FkIHNjcmlwdHMgZnJvbSBhbGwgY3VzdG9tIGZpbGVzXHJcbiAgICAgIGlmIChyZXNvdXJjZXMuZmlsZXMpIHtcclxuICAgICAgICBmb3IgKGNvbnN0IGZpbGUgb2YgcmVzb3VyY2VzLmZpbGVzKSB7XHJcbiAgICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICBjb25zdCBpc0xvY2FsID0gIWZpbGUuc3RhcnRzV2l0aCgnaHR0cCcpID8gdHJ1ZSA6IGZhbHNlO1xyXG5cclxuICAgICAgICAgICAgLy8gQWRkIGVhY2ggY3VzdG9tIHNjcmlwdCBmcm9tIHJlc291cmNlcycgZmlsZXNcclxuICAgICAgICAgICAgaW5qZWN0ZWRSZXNvdXJjZXMucHVzaChcclxuICAgICAgICAgICAgICBhd2FpdCBwYWdlLmFkZFNjcmlwdFRhZyhcclxuICAgICAgICAgICAgICAgIGlzTG9jYWxcclxuICAgICAgICAgICAgICAgICAgPyB7XHJcbiAgICAgICAgICAgICAgICAgICAgICBjb250ZW50OiByZWFkRmlsZVN5bmMoZmlsZSwgJ3V0ZjgnKVxyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgOiB7XHJcbiAgICAgICAgICAgICAgICAgICAgICB1cmw6IGZpbGVcclxuICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgKVxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgICAgICAgIDIsXHJcbiAgICAgICAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgICAgICAgYFtleHBvcnRdIFRoZSBKUyBmaWxlICR7ZmlsZX0gY2Fubm90IGJlIGxvYWRlZC5gXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBMb2FkIENTU1xyXG4gICAgICBpZiAocmVzb3VyY2VzLmNzcykge1xyXG4gICAgICAgIGxldCBjc3NJbXBvcnRzID0gcmVzb3VyY2VzLmNzcy5tYXRjaCgvQGltcG9ydFxccyooW147XSopOy9nKTtcclxuICAgICAgICBpZiAoY3NzSW1wb3J0cykge1xyXG4gICAgICAgICAgLy8gSGFuZGxlIGNzcyBzZWN0aW9uXHJcbiAgICAgICAgICBmb3IgKGxldCBjc3NJbXBvcnRQYXRoIG9mIGNzc0ltcG9ydHMpIHtcclxuICAgICAgICAgICAgaWYgKGNzc0ltcG9ydFBhdGgpIHtcclxuICAgICAgICAgICAgICBjc3NJbXBvcnRQYXRoID0gY3NzSW1wb3J0UGF0aFxyXG4gICAgICAgICAgICAgICAgLnJlcGxhY2UoJ3VybCgnLCAnJylcclxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKCdAaW1wb3J0JywgJycpXHJcbiAgICAgICAgICAgICAgICAucmVwbGFjZSgvXCIvZywgJycpXHJcbiAgICAgICAgICAgICAgICAucmVwbGFjZSgvJy9nLCAnJylcclxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKC87LywgJycpXHJcbiAgICAgICAgICAgICAgICAucmVwbGFjZSgvXFwpL2csICcnKVxyXG4gICAgICAgICAgICAgICAgLnRyaW0oKTtcclxuXHJcbiAgICAgICAgICAgICAgLy8gQWRkIGVhY2ggY3VzdG9tIGNzcyBmcm9tIHJlc291cmNlc1xyXG4gICAgICAgICAgICAgIGlmIChjc3NJbXBvcnRQYXRoLnN0YXJ0c1dpdGgoJ2h0dHAnKSkge1xyXG4gICAgICAgICAgICAgICAgaW5qZWN0ZWRSZXNvdXJjZXMucHVzaChcclxuICAgICAgICAgICAgICAgICAgYXdhaXQgcGFnZS5hZGRTdHlsZVRhZyh7XHJcbiAgICAgICAgICAgICAgICAgICAgdXJsOiBjc3NJbXBvcnRQYXRoXHJcbiAgICAgICAgICAgICAgICAgIH0pXHJcbiAgICAgICAgICAgICAgICApO1xyXG4gICAgICAgICAgICAgIH0gZWxzZSBpZiAob3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0ZpbGVSZXNvdXJjZXMpIHtcclxuICAgICAgICAgICAgICAgIGluamVjdGVkUmVzb3VyY2VzLnB1c2goXHJcbiAgICAgICAgICAgICAgICAgIGF3YWl0IHBhZ2UuYWRkU3R5bGVUYWcoe1xyXG4gICAgICAgICAgICAgICAgICAgIHBhdGg6IHBhdGguam9pbihfX2Jhc2VkaXIsIGNzc0ltcG9ydFBhdGgpXHJcbiAgICAgICAgICAgICAgICAgIH0pXHJcbiAgICAgICAgICAgICAgICApO1xyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gVGhlIHJlc3Qgb2YgdGhlIENTUyBzZWN0aW9uIHdpbGwgYmUgY29udGVudCBieSBub3dcclxuICAgICAgICBpbmplY3RlZFJlc291cmNlcy5wdXNoKFxyXG4gICAgICAgICAgYXdhaXQgcGFnZS5hZGRTdHlsZVRhZyh7XHJcbiAgICAgICAgICAgIGNvbnRlbnQ6IHJlc291cmNlcy5jc3MucmVwbGFjZSgvQGltcG9ydFxccyooW147XSopOy9nLCAnJykgfHwgJyAnXHJcbiAgICAgICAgICB9KVxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBHZXQgdGhlIHJlYWwgY2hhcnQgc2l6ZVxyXG4gICAgY29uc3Qgc2l6ZSA9IGlzU1ZHXHJcbiAgICAgID8gYXdhaXQgcGFnZS4kZXZhbChcclxuICAgICAgICAgICcjY2hhcnQtY29udGFpbmVyIHN2ZzpmaXJzdC1vZi10eXBlJyxcclxuICAgICAgICAgIChlbGVtZW50LCBzY2FsZSkgPT4gKHtcclxuICAgICAgICAgICAgY2hhcnRIZWlnaHQ6IGVsZW1lbnQuaGVpZ2h0LmJhc2VWYWwudmFsdWUgKiBzY2FsZSxcclxuICAgICAgICAgICAgY2hhcnRXaWR0aDogZWxlbWVudC53aWR0aC5iYXNlVmFsLnZhbHVlICogc2NhbGVcclxuICAgICAgICAgIH0pLFxyXG4gICAgICAgICAgcGFyc2VGbG9hdChleHBvcnRPcHRpb25zLnNjYWxlKVxyXG4gICAgICAgIClcclxuICAgICAgOiBhd2FpdCBwYWdlLmV2YWx1YXRlKCgpID0+IHtcclxuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgICAgY29uc3QgeyBjaGFydEhlaWdodCwgY2hhcnRXaWR0aCB9ID0gd2luZG93LkhpZ2hjaGFydHMuY2hhcnRzWzBdO1xyXG4gICAgICAgICAgcmV0dXJuIHtcclxuICAgICAgICAgICAgY2hhcnRIZWlnaHQsXHJcbiAgICAgICAgICAgIGNoYXJ0V2lkdGhcclxuICAgICAgICAgIH07XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgLy8gU2V0IGZpbmFsIGhlaWdodCBhbmQgd2lkdGggZm9yIHZpZXdwb3J0XHJcbiAgICBjb25zdCB2aWV3cG9ydEhlaWdodCA9IE1hdGguY2VpbChzaXplPy5jaGFydEhlaWdodCB8fCBleHBvcnRPcHRpb25zLmhlaWdodCk7XHJcbiAgICBjb25zdCB2aWV3cG9ydFdpZHRoID0gTWF0aC5jZWlsKHNpemU/LmNoYXJ0V2lkdGggfHwgZXhwb3J0T3B0aW9ucy53aWR0aCk7XHJcblxyXG4gICAgLy8gU2V0IHRoZSB2aWV3cG9ydCBmb3IgdGhlIGZpcnN0IHRpbWVcclxuICAgIC8vIE5PVEU6IHRoZSBjYWxsIHRvIHNldFZpZXdwb3J0IGlzIGV4cGVuc2l2ZSAtIGNhbiB3ZSBnZXQgYXdheSB3aXRoIG9ubHlcclxuICAgIC8vIGNhbGxpbmcgaXQgb25jZSwgZS5nLiBtb3ZpbmcgdGhpcyBvbmUgaW50byB0aGUgaXNTVkcgY29uZGl0aW9uIGJlbG93P1xyXG4gICAgYXdhaXQgcGFnZS5zZXRWaWV3cG9ydCh7XHJcbiAgICAgIGhlaWdodDogdmlld3BvcnRIZWlnaHQsXHJcbiAgICAgIHdpZHRoOiB2aWV3cG9ydFdpZHRoLFxyXG4gICAgICBkZXZpY2VTY2FsZUZhY3RvcjogaXNTVkcgPyAxIDogcGFyc2VGbG9hdChleHBvcnRPcHRpb25zLnNjYWxlKVxyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gUHJlcGFyZSBhIHpvb20gY2FsbGJhY2sgZm9yIHRoZSBuZXh0IGV2YWx1YXRlIGNhbGxcclxuICAgIGNvbnN0IHpvb21DYWxsYmFjayA9IGlzU1ZHXHJcbiAgICAgID8gLy8gSW4gY2FzZSBvZiBTVkcgdGhlIHpvb20gbXVzdCBiZSBzZXQgZGlyZWN0bHkgZm9yIGJvZHlcclxuICAgICAgICAoc2NhbGUpID0+IHtcclxuICAgICAgICAgIC8vIFNldCB0aGUgem9vbSBhcyBzY2FsZVxyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLnpvb20gPSBzY2FsZTtcclxuXHJcbiAgICAgICAgICAvLyBTZXQgdGhlIG1hcmdpbiB0byAwcHhcclxuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgICAgZG9jdW1lbnQuYm9keS5zdHlsZS5tYXJnaW4gPSAnMHB4JztcclxuICAgICAgICB9XHJcbiAgICAgIDogLy8gTm8gbmVlZCBmb3Igc3VjaCBzY2FsZSBtYW5pcHVsYXRpb24gaW4gY2FzZSBvZiBvdGhlciB0eXBlcyBvZiBleHBvcnRzXHJcbiAgICAgICAgKCkgPT4ge1xyXG4gICAgICAgICAgLy8gUmVzZXQgdGhlIHpvb20gZm9yIG90aGVyIGV4cG9ydHMgdGhhbiB0byBTVkdzXHJcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUuem9vbSA9IDE7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAvLyBTZXQgdGhlIHpvb20gYWNjb3JkaW5nbHlcclxuICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoem9vbUNhbGxiYWNrLCBwYXJzZUZsb2F0KGV4cG9ydE9wdGlvbnMuc2NhbGUpKTtcclxuXHJcbiAgICAvLyBHZXQgdGhlIGNsaXAgcmVnaW9uIGZvciB0aGUgcGFnZVxyXG4gICAgY29uc3QgeyBoZWlnaHQsIHdpZHRoLCB4LCB5IH0gPSBhd2FpdCBnZXRDbGlwUmVnaW9uKHBhZ2UpO1xyXG5cclxuICAgIGlmICghaXNTVkcpIHtcclxuICAgICAgLy8gU2V0IHRoZSBmaW5hbCB2aWV3cG9ydCBub3cgdGhhdCB3ZSBoYXZlIHRoZSByZWFsIGhlaWdodFxyXG4gICAgICBhd2FpdCBwYWdlLnNldFZpZXdwb3J0KHtcclxuICAgICAgICB3aWR0aDogTWF0aC5yb3VuZCh3aWR0aCksXHJcbiAgICAgICAgaGVpZ2h0OiBNYXRoLnJvdW5kKGhlaWdodCksXHJcbiAgICAgICAgZGV2aWNlU2NhbGVGYWN0b3I6IHBhcnNlRmxvYXQoZXhwb3J0T3B0aW9ucy5zY2FsZSlcclxuICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgbGV0IGRhdGE7XHJcbiAgICAvLyBSQVNURVJJWkFUSU9OXHJcbiAgICBpZiAoZXhwb3J0T3B0aW9ucy50eXBlID09PSAnc3ZnJykge1xyXG4gICAgICAvLyBTVkdcclxuICAgICAgZGF0YSA9IGF3YWl0IGNyZWF0ZVNWRyhwYWdlKTtcclxuICAgIH0gZWxzZSBpZiAoWydwbmcnLCAnanBlZyddLmluY2x1ZGVzKGV4cG9ydE9wdGlvbnMudHlwZSkpIHtcclxuICAgICAgLy8gUE5HIG9yIEpQRUdcclxuICAgICAgZGF0YSA9IGF3YWl0IGNyZWF0ZUltYWdlKFxyXG4gICAgICAgIHBhZ2UsXHJcbiAgICAgICAgZXhwb3J0T3B0aW9ucy50eXBlLFxyXG4gICAgICAgICdiYXNlNjQnLFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIHdpZHRoOiB2aWV3cG9ydFdpZHRoLFxyXG4gICAgICAgICAgaGVpZ2h0OiB2aWV3cG9ydEhlaWdodCxcclxuICAgICAgICAgIHgsXHJcbiAgICAgICAgICB5XHJcbiAgICAgICAgfSxcclxuICAgICAgICBleHBvcnRPcHRpb25zLnJhc3Rlcml6YXRpb25UaW1lb3V0XHJcbiAgICAgICk7XHJcbiAgICB9IGVsc2UgaWYgKGV4cG9ydE9wdGlvbnMudHlwZSA9PT0gJ3BkZicpIHtcclxuICAgICAgLy8gUERGXHJcbiAgICAgIGRhdGEgPSBhd2FpdCBjcmVhdGVQREYocGFnZSwgdmlld3BvcnRIZWlnaHQsIHZpZXdwb3J0V2lkdGgsICdiYXNlNjQnKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICBgW2V4cG9ydF0gVW5zdXBwb3J0ZWQgb3V0cHV0IGZvcm1hdCAke2V4cG9ydE9wdGlvbnMudHlwZX0uYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIERlc3Ryb3kgb2xkIGNoYXJ0cyBhZnRlciB0aGUgZXhwb3J0IGlzIGRvbmVcclxuICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xyXG4gICAgICAvLyBXZSBhcmUgbm90IGd1YXJhbnRlZWQgdGhhdCBIaWdoY2hhcnRzIGlzIGxvYWRlZCwgZSxnLCB3aGVuIGRvaW5nIFNWR1xyXG4gICAgICAvLyBleHBvcnRzXHJcbiAgICAgIGlmICh0eXBlb2YgSGlnaGNoYXJ0cyAhPT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICBjb25zdCBvbGRDaGFydHMgPSBIaWdoY2hhcnRzLmNoYXJ0cztcclxuXHJcbiAgICAgICAgLy8gQ2hlY2sgaW4gYW55IGFscmVhZHkgZXhpc3RpbmcgY2hhcnRzXHJcbiAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkob2xkQ2hhcnRzKSAmJiBvbGRDaGFydHMubGVuZ3RoKSB7XHJcbiAgICAgICAgICAvLyBEZXN0cm95IG9sZCBjaGFydHNcclxuICAgICAgICAgIGZvciAoY29uc3Qgb2xkQ2hhcnQgb2Ygb2xkQ2hhcnRzKSB7XHJcbiAgICAgICAgICAgIG9sZENoYXJ0ICYmIG9sZENoYXJ0LmRlc3Ryb3koKTtcclxuICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICAgIEhpZ2hjaGFydHMuY2hhcnRzLnNoaWZ0KCk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9KTtcclxuXHJcbiAgICBhd2FpdCBjbGVhckluamVjdGVkKHBhZ2UpO1xyXG4gICAgcmV0dXJuIGRhdGE7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIGF3YWl0IGNsZWFySW5qZWN0ZWQocGFnZSk7XHJcbiAgICByZXR1cm4gZXJyb3I7XHJcbiAgfVxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCBjc3NUZW1wbGF0ZSBmcm9tICcuL2Nzcy5qcyc7XHJcblxyXG5leHBvcnQgZGVmYXVsdCAoY2hhcnQpID0+IGBcclxuPCFET0NUWVBFIGh0bWw+XHJcbjxodG1sIGxhbmc9J2VuLVVTJz5cclxuICA8aGVhZD5cclxuICAgIDxtZXRhIGh0dHAtZXF1aXY9XCJDb250ZW50LVR5cGVcIiBjb250ZW50PVwidGV4dC9odG1sOyBjaGFyc2V0PXV0Zi04XCI+XHJcbiAgICA8dGl0bGU+SGlnaGNhcnRzIEV4cG9ydDwvdGl0bGU+XHJcbiAgPC9oZWFkPlxyXG4gIDxzdHlsZT5cclxuICAgICR7Y3NzVGVtcGxhdGUoKX1cclxuICA8L3N0eWxlPlxyXG4gIDxib2R5PlxyXG4gICAgPGRpdiBpZD1cImNoYXJ0LWNvbnRhaW5lclwiPlxyXG4gICAgICAke2NoYXJ0fVxyXG4gICAgPC9kaXY+XHJcbiAgPC9ib2R5PlxyXG48L2h0bWw+XHJcblxyXG5gO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IFBvb2wgfSBmcm9tICd0YXJuJztcclxuaW1wb3J0IHsgdjQgYXMgdXVpZCB9IGZyb20gJ3V1aWQnO1xyXG5cclxuaW1wb3J0IHtcclxuICBjbG9zZSBhcyBicm93c2VyQ2xvc2UsXHJcbiAgY3JlYXRlIGFzIGNyZWF0ZUJyb3dzZXIsXHJcbiAgbmV3UGFnZSBhcyBicm93c2VyTmV3UGFnZSxcclxuICBjbGVhclBhZ2VcclxufSBmcm9tICcuL2Jyb3dzZXIuanMnO1xyXG5pbXBvcnQgcHVwcGV0ZWVyRXhwb3J0IGZyb20gJy4vZXhwb3J0LmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IG1lYXN1cmVUaW1lIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxubGV0IHBlcmZvcm1lZEV4cG9ydHMgPSAwO1xyXG5sZXQgZXhwb3J0QXR0ZW1wdHMgPSAwO1xyXG5sZXQgdGltZVNwZW50ID0gMDtcclxubGV0IGRyb3BwZWRFeHBvcnRzID0gMDtcclxubGV0IHNwZW50QXZlcmFnZSA9IDA7XHJcbmxldCBwb29sQ29uZmlnID0ge307XHJcblxyXG4vLyBUaGUgcG9vbCBpbnN0YW5jZVxyXG5sZXQgcG9vbCA9IGZhbHNlO1xyXG5cclxuLy8gQ3VzdG9tIHB1cHBldGVlciBhcmd1bWVudHNcclxubGV0IHB1cHBldGVlckFyZ3M7XHJcblxyXG5jb25zdCBmYWN0b3J5ID0ge1xyXG4gIC8qKlxyXG4gICAqIENyZWF0ZXMgYSBuZXcgd29ya2VyIHBhZ2UgZm9yIHRoZSBleHBvcnQgcG9vbC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHtPYmplY3R9IC0gQW4gb2JqZWN0IGNvbnRhaW5pbmcgdGhlIHdvcmtlciBJRCwgYSByZWZlcmVuY2UgdG8gdGhlXHJcbiAgICogYnJvd3NlciBwYWdlLCBhbmQgaW5pdGlhbCB3b3JrIGNvdW50LlxyXG4gICAqXHJcbiAgICogQHRocm93cyB7RXhwb3J0RXJyb3J9IC0gSWYgdGhlcmUncyBhbiBlcnJvciBkdXJpbmcgdGhlIGNyZWF0aW9uIG9mIHRoZSBuZXdcclxuICAgKiBwYWdlLlxyXG4gICAqL1xyXG4gIGNyZWF0ZTogYXN5bmMgKCkgPT4ge1xyXG4gICAgbGV0IHBhZ2UgPSBmYWxzZTtcclxuXHJcbiAgICBjb25zdCBpZCA9IHV1aWQoKTtcclxuICAgIGNvbnN0IHN0YXJ0RGF0ZSA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xyXG5cclxuICAgIHRyeSB7XHJcbiAgICAgIHBhZ2UgPSBhd2FpdCBicm93c2VyTmV3UGFnZSgpO1xyXG5cclxuICAgICAgaWYgKCFwYWdlIHx8IHBhZ2UuaXNDbG9zZWQoKSkge1xyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignVGhlIHBhZ2UgaXMgaW52YWxpZCBvciBjbG9zZWQuJyk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGxvZyhcclxuICAgICAgICAzLFxyXG4gICAgICAgIGBbcG9vbF0gU3VjY2Vzc2Z1bGx5IGNyZWF0ZWQgYSB3b3JrZXIgJHtpZH0gLSB0b29rICR7XHJcbiAgICAgICAgICBuZXcgRGF0ZSgpLmdldFRpbWUoKSAtIHN0YXJ0RGF0ZVxyXG4gICAgICAgIH0gbXMuYFxyXG4gICAgICApO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdFcnJvciBlbmNvdW50ZXJlZCB3aGVuIGNyZWF0aW5nIGEgbmV3IHBhZ2UuJ1xyXG4gICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4ge1xyXG4gICAgICBpZCxcclxuICAgICAgcGFnZSxcclxuICAgICAgLy8gVHJ5IHRvIGRpc3RyaWJ1dGUgdGhlIGluaXRpYWwgd29yayBjb3VudFxyXG4gICAgICB3b3JrQ291bnQ6IE1hdGgucm91bmQoTWF0aC5yYW5kb20oKSAqIChwb29sQ29uZmlnLndvcmtMaW1pdCAvIDIpKVxyXG4gICAgfTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBWYWxpZGF0ZXMgYSB3b3JrZXIgcGFnZSBpbiB0aGUgZXhwb3J0IHBvb2wsIGNoZWNraW5nIGlmIGl0IGhhcyBleGNlZWRlZFxyXG4gICAqIHRoZSB3b3JrIGxpbWl0LlxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtPYmplY3R9IHdvcmtlckhhbmRsZSAtIFRoZSBoYW5kbGUgdG8gdGhlIHdvcmtlciwgY29udGFpbmluZyB0aGVcclxuICAgKiB3b3JrZXIncyBJRCwgYSByZWZlcmVuY2UgdG8gdGhlIGJyb3dzZXIgcGFnZSwgYW5kIHdvcmsgY291bnQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBSZXR1cm5zIHRydWUgaWYgdGhlIHdvcmtlciBpcyB2YWxpZCBhbmQgd2l0aGluXHJcbiAgICogdGhlIHdvcmsgbGltaXQ7IG90aGVyd2lzZSwgcmV0dXJucyBmYWxzZS5cclxuICAgKi9cclxuICB2YWxpZGF0ZTogYXN5bmMgKHdvcmtlckhhbmRsZSkgPT4ge1xyXG4gICAgaWYgKFxyXG4gICAgICBwb29sQ29uZmlnLndvcmtMaW1pdCAmJlxyXG4gICAgICArK3dvcmtlckhhbmRsZS53b3JrQ291bnQgPiBwb29sQ29uZmlnLndvcmtMaW1pdFxyXG4gICAgKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICAzLFxyXG4gICAgICAgIGBbcG9vbF0gV29ya2VyIGZhaWxlZCB2YWxpZGF0aW9uOiBleGNlZWRlZCB3b3JrIGxpbWl0IChsaW1pdCBpcyAke3Bvb2xDb25maWcud29ya0xpbWl0fSkuYFxyXG4gICAgICApO1xyXG4gICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2xlYXIgcGFnZVxyXG4gICAgYXdhaXQgY2xlYXJQYWdlKHdvcmtlckhhbmRsZS5wYWdlLCB0cnVlKTtcclxuICAgIHJldHVybiB0cnVlO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIERlc3Ryb3lzIGEgd29ya2VyIGVudHJ5IGluIHRoZSBleHBvcnQgcG9vbCwgY2xvc2luZyBpdHMgYXNzb2NpYXRlZCBwYWdlLlxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtPYmplY3R9IHdvcmtlckhhbmRsZSAtIFRoZSBoYW5kbGUgdG8gdGhlIHdvcmtlciwgY29udGFpbmluZ1xyXG4gICAqIHRoZSB3b3JrZXIncyBJRCBhbmQgYSByZWZlcmVuY2UgdG8gdGhlIGJyb3dzZXIgcGFnZS5cclxuICAgKi9cclxuICBkZXN0cm95OiAod29ya2VySGFuZGxlKSA9PiB7XHJcbiAgICBsb2coMywgYFtwb29sXSBEZXN0cm95aW5nIHBvb2wgZW50cnkgJHt3b3JrZXJIYW5kbGUuaWR9LmApO1xyXG5cclxuICAgIGlmICh3b3JrZXJIYW5kbGUucGFnZSkge1xyXG4gICAgICAvLyBXZSBkb24ndCByZWFsbHkgbmVlZCB0byB3YWl0IGFyb3VuZCBmb3IgdGhpcy5cclxuICAgICAgd29ya2VySGFuZGxlLnBhZ2UuY2xvc2UoKTtcclxuICAgIH1cclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgdGhlIGV4cG9ydCBwb29sIHdpdGggdGhlIHByb3ZpZGVkIGNvbmZpZ3VyYXRpb24sIGNyZWF0aW5nXHJcbiAqIGEgYnJvd3NlciBpbnN0YW5jZSBhbmQgc2V0dGluZyB1cCB3b3JrZXIgcmVzb3VyY2VzLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnIC0gQ29uZmlndXJhdGlvbiBvcHRpb25zIGZvciB0aGUgZXhwb3J0IHBvb2wgYWxvbmdcclxuICogd2l0aCBjdXN0b20gcHVwcGV0ZWVyIGFyZ3VtZW50cyBmb3IgdGhlIHB1cHBldGVlci5sYXVuY2ggZnVuY3Rpb24uXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaW5pdFBvb2wgPSBhc3luYyAoY29uZmlnKSA9PiB7XHJcbiAgLy8gRm9yIHRoZSBtb2R1bGUgc2NvcGUgdXNhZ2VcclxuICBwb29sQ29uZmlnID0gY29uZmlnICYmIGNvbmZpZy5wb29sID8geyAuLi5jb25maWcucG9vbCB9IDoge307XHJcblxyXG4gIC8vIEF0dGFjaCBwcm9jZXNzJyBleGl0IGxpc3RlbmVyc1xyXG4gIGlmIChwb29sQ29uZmlnLmxpc3RlblRvUHJvY2Vzc0V4aXRzKSB7XHJcbiAgICBhdHRhY2hQcm9jZXNzRXhpdExpc3RlbmVycygpO1xyXG4gIH1cclxuXHJcbiAgLy8gVGhlIG5ld2VzdCBwdXBwZXRlZXIgYXJndW1lbnRzIGZvciB0aGUgYnJvd3NlciBjcmVhdGlvblxyXG4gIHB1cHBldGVlckFyZ3MgPSBjb25maWcucHVwcGV0ZWVyQXJncztcclxuXHJcbiAgLy8gQ3JlYXRlIGEgYnJvd3NlciBpbnN0YW5jZVxyXG4gIGF3YWl0IGNyZWF0ZUJyb3dzZXIocHVwcGV0ZWVyQXJncyk7XHJcblxyXG4gIGxvZyhcclxuICAgIDMsXHJcbiAgICBgW3Bvb2xdIEluaXRpYWxpemluZyBwb29sIHdpdGggd29ya2VyczogbWluICR7cG9vbENvbmZpZy5taW5Xb3JrZXJzfSwgbWF4ICR7cG9vbENvbmZpZy5tYXhXb3JrZXJzfS5gXHJcbiAgKTtcclxuXHJcbiAgaWYgKHBvb2wpIHtcclxuICAgIHJldHVybiBsb2coXHJcbiAgICAgIDQsXHJcbiAgICAgICdbcG9vbF0gQWxyZWFkeSBpbml0aWFsaXplZCwgcGxlYXNlIGtpbGwgaXQgYmVmb3JlIGNyZWF0aW5nIGEgbmV3IG9uZS4nXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgaWYgKHBhcnNlSW50KHBvb2xDb25maWcubWluV29ya2VycykgPiBwYXJzZUludChwb29sQ29uZmlnLm1heFdvcmtlcnMpKSB7XHJcbiAgICBwb29sQ29uZmlnLm1pbldvcmtlcnMgPSBwb29sQ29uZmlnLm1heFdvcmtlcnM7XHJcbiAgfVxyXG5cclxuICB0cnkge1xyXG4gICAgLy8gQ3JlYXRlIGEgcG9vbCBhbG9uZyB3aXRoIGEgbWluaW1hbCBudW1iZXIgb2YgcmVzb3VyY2VzXHJcbiAgICBwb29sID0gbmV3IFBvb2woe1xyXG4gICAgICAvLyBHZXQgdGhlIGNyZWF0ZS92YWxpZGF0ZS9kZXN0cm95L2xvZyBmdW5jdGlvbnNcclxuICAgICAgLi4uZmFjdG9yeSxcclxuICAgICAgbWluOiBwYXJzZUludChwb29sQ29uZmlnLm1pbldvcmtlcnMpLFxyXG4gICAgICBtYXg6IHBhcnNlSW50KHBvb2xDb25maWcubWF4V29ya2VycyksXHJcbiAgICAgIGFjcXVpcmVUaW1lb3V0TWlsbGlzOiBwb29sQ29uZmlnLmFjcXVpcmVUaW1lb3V0LFxyXG4gICAgICBjcmVhdGVUaW1lb3V0TWlsbGlzOiBwb29sQ29uZmlnLmNyZWF0ZVRpbWVvdXQsXHJcbiAgICAgIGRlc3Ryb3lUaW1lb3V0TWlsbGlzOiBwb29sQ29uZmlnLmRlc3Ryb3lUaW1lb3V0LFxyXG4gICAgICBpZGxlVGltZW91dE1pbGxpczogcG9vbENvbmZpZy5pZGxlVGltZW91dCxcclxuICAgICAgY3JlYXRlUmV0cnlJbnRlcnZhbE1pbGxpczogcG9vbENvbmZpZy5jcmVhdGVSZXRyeUludGVydmFsLFxyXG4gICAgICByZWFwSW50ZXJ2YWxNaWxsaXM6IHBvb2xDb25maWcucmVhcGVySW50ZXJ2YWwsXHJcbiAgICAgIHByb3BhZ2F0ZUNyZWF0ZUVycm9yOiBmYWxzZVxyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gU2V0IGV2ZW50c1xyXG4gICAgcG9vbC5vbigncmVsZWFzZScsIGFzeW5jIChyZXNvdXJjZSkgPT4ge1xyXG4gICAgICAvLyBDbGVhciBwYWdlXHJcbiAgICAgIGF3YWl0IGNsZWFyUGFnZShyZXNvdXJjZS5wYWdlLCBmYWxzZSk7XHJcbiAgICAgIGxvZyg0LCBgW3Bvb2xdIFJlbGVhc2luZyBhIHdvcmtlciB3aXRoIElEICR7cmVzb3VyY2UuaWR9LmApO1xyXG4gICAgfSk7XHJcblxyXG4gICAgcG9vbC5vbignZGVzdHJveVN1Y2Nlc3MnLCAoZXZlbnRJZCwgcmVzb3VyY2UpID0+IHtcclxuICAgICAgbG9nKDQsIGBbcG9vbF0gRGVzdHJveWVkIGEgd29ya2VyIHdpdGggSUQgJHtyZXNvdXJjZS5pZH0uYCk7XHJcbiAgICB9KTtcclxuXHJcbiAgICBjb25zdCBpbml0aWFsUmVzb3VyY2VzID0gW107XHJcbiAgICAvLyBDcmVhdGUgYW4gaW5pdGlhbCBudW1iZXIgb2YgcmVzb3VyY2VzXHJcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHBvb2xDb25maWcubWluV29ya2VyczsgaSsrKSB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgY29uc3QgcmVzb3VyY2UgPSBhd2FpdCBwb29sLmFjcXVpcmUoKS5wcm9taXNlO1xyXG4gICAgICAgIGluaXRpYWxSZXNvdXJjZXMucHVzaChyZXNvdXJjZSk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCAnW3Bvb2xdIENvdWxkIG5vdCBjcmVhdGUgYW4gaW5pdGlhbCByZXNvdXJjZS4nKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIFJlbGVhc2UgdGhlIGluaXRpYWwgbnVtYmVyIG9mIHJlc291cmNlcyBiYWNrIHRvIHRoZSBwb29sXHJcbiAgICBpbml0aWFsUmVzb3VyY2VzLmZvckVhY2goKHJlc291cmNlKSA9PiB7XHJcbiAgICAgIHBvb2wucmVsZWFzZShyZXNvdXJjZSk7XHJcbiAgICB9KTtcclxuXHJcbiAgICBsb2coXHJcbiAgICAgIDMsXHJcbiAgICAgIGBbcG9vbF0gVGhlIHBvb2wgaXMgcmVhZHkke2luaXRpYWxSZXNvdXJjZXMubGVuZ3RoID8gYCB3aXRoICR7aW5pdGlhbFJlc291cmNlcy5sZW5ndGh9IGluaXRpYWwgcmVzb3VyY2VzIHdhaXRpbmcuYCA6ICcuJ31gXHJcbiAgICApO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAvLyBDbG9zZSBicm93c2VyIGlmIGZvciBzb21lIHJlYXNvbiBjYW5ub3QgZXN0YWJsaXNoIHRoZSBwb29sXHJcbiAgICBhd2FpdCBicm93c2VyQ2xvc2UoKTtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1twb29sXSBDb3VsZCBub3QgY3JlYXRlIHRoZSBwb29sIG9mIHdvcmtlcnMuJ1xyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEF0dGFjaGVzIGV4aXQgbGlzdGVuZXJzIHRvIHRoZSBwcm9jZXNzLCBlbnN1cmluZyBwcm9wZXIgY2xlYW51cCBvZiByZXNvdXJjZXNcclxuICogYW5kIHRlcm1pbmF0aW9uIG9uIGV4aXQgc2lnbmFscy4gSGFuZGxlcyAnZXhpdCcsICdTSUdJTlQnLCAnU0lHVEVSTScsIGFuZFxyXG4gKiAndW5jYXVnaHRFeGNlcHRpb24nIGV2ZW50cy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBhdHRhY2hQcm9jZXNzRXhpdExpc3RlbmVycygpIHtcclxuICBsb2coMywgJ1twb29sXSBBdHRhY2hpbmcgZXhpdCBsaXN0ZW5lcnMgdG8gdGhlIHByb2Nlc3MuJyk7XHJcblxyXG4gIC8vIEtpbGwgYWxsIHBvb2wgcmVzb3VyY2VzIG9uIGV4aXRcclxuICBwcm9jZXNzLm9uKCdleGl0JywgYXN5bmMgKGNvZGUpID0+IHtcclxuICAgIGxvZyg0LCBgUHJvY2VzcyBleGl0ZWQgd2l0aCBjb2RlICR7Y29kZX0uYCk7XHJcbiAgICBhd2FpdCBraWxsUG9vbCgpO1xyXG4gIH0pO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgU0lHSU5UXHJcbiAgcHJvY2Vzcy5vbignU0lHSU5UJywgKG5hbWUsIGNvZGUpID0+IHtcclxuICAgIGxvZyg0LCBgVGhlICR7bmFtZX0gZXZlbnQgd2l0aCBjb2RlOiAke2NvZGV9LmApO1xyXG4gICAgcHJvY2Vzcy5leGl0KDEpO1xyXG4gIH0pO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgU0lHVEVSTVxyXG4gIHByb2Nlc3Mub24oJ1NJR1RFUk0nLCAobmFtZSwgY29kZSkgPT4ge1xyXG4gICAgbG9nKDQsIGBUaGUgJHtuYW1lfSBldmVudCB3aXRoIGNvZGU6ICR7Y29kZX0uYCk7XHJcbiAgICBwcm9jZXNzLmV4aXQoMSk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSB1bmNhdWdodEV4Y2VwdGlvblxyXG4gIHByb2Nlc3Mub24oJ3VuY2F1Z2h0RXhjZXB0aW9uJywgYXN5bmMgKGVycm9yLCBuYW1lKSA9PiB7XHJcbiAgICBsb2dXaXRoU3RhY2soMSwgZXJyb3IsIGBUaGUgJHtuYW1lfSBlcnJvci5gKTtcclxuICAgIGF3YWl0IGtpbGxQb29sKCk7XHJcbiAgICBwcm9jZXNzLmV4aXQoMSk7XHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBLaWxscyBhbGwgd29ya2VycyBpbiB0aGUgcG9vbCwgZGVzdHJveXMgdGhlIHBvb2wsIGFuZCBjbG9zZXMgdGhlIGJyb3dzZXJcclxuICogaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyBhZnRlciB0aGUgd29ya2VycyBhcmVcclxuICoga2lsbGVkLCB0aGUgcG9vbCBpcyBkZXN0cm95ZWQsIGFuZCB0aGUgYnJvd3NlciBpcyBjbG9zZWQuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24ga2lsbFBvb2woKSB7XHJcbiAgbG9nKDMsICdbcG9vbF0gS2lsbGluZyBhbGwgcG9vbCB3b3JrZXJzIGFuZCBicm93c2VyLCBpZiBhbnkgZXhpc3QuJyk7XHJcblxyXG4gIC8vIFJldHVybiB0cnVlIHdoZW4gdGhlIHBvb2wgaXMgYWxyZWFkeSBkZXN0cm95ZWRcclxuICBpZiAocG9vbD8uZGVzdHJveWVkKSB7XHJcbiAgICAvLyBDbG9zZSB0aGUgYnJvd3NlciBpbnN0YW5jZSBpZiBzdGlsbCBjb25uZWN0ZWRcclxuICAgIHJldHVybiBicm93c2VyQ2xvc2UoKTtcclxuICB9XHJcblxyXG4gIC8vIElmIHN0aWxsIGFsaXZlLCBkZXN0cm95IHRoZSBwb29sIG9mIHBhZ2VzIGJlZm9yZSBjbG9zaW5nIGEgYnJvd3NlclxyXG4gIGlmIChwb29sKSB7XHJcbiAgICBhd2FpdCBwb29sLmRlc3Ryb3koKTtcclxuICAgIGxvZyg0LCAnW2Jyb3dzZXJdIERlc3Ryb3llZCB0aGUgcG9vbCBvZiByZXNvdXJjZXMuJyk7XHJcbiAgfVxyXG5cclxuICAvLyBDbG9zZSB0aGUgYnJvd3NlciBpbnN0YW5jZVxyXG4gIHJldHVybiBicm93c2VyQ2xvc2UoKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFByb2Nlc3NlcyB0aGUgZXhwb3J0IHdvcmsgdXNpbmcgYSB3b3JrZXIgZnJvbSB0aGUgcG9vbC4gQWNxdWlyZXMgYSB3b3JrZXJcclxuICogaGFuZGxlIGZyb20gdGhlIHBvb2wsIHBlcmZvcm1zIHRoZSBleHBvcnQgdXNpbmcgcHVwcGV0ZWVyLCBhbmQgcmVsZWFzZXNcclxuICogdGhlIHdvcmtlciBoYW5kbGUgYmFjayB0byB0aGUgcG9vbC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGNoYXJ0IC0gVGhlIGNoYXJ0IGRhdGEgb3IgY29uZmlndXJhdGlvbiB0byBiZSBleHBvcnRlZC5cclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBFeHBvcnQgb3B0aW9ucyBhbmQgY29uZmlndXJhdGlvbi5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2l0aCB0aGUgZXhwb3J0IHJlc3VsdGFuZFxyXG4gKiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gSWYgYW4gZXJyb3Igb2NjdXJzIGR1cmluZyB0aGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgcG9zdFdvcmsgPSBhc3luYyAoY2hhcnQsIG9wdGlvbnMpID0+IHtcclxuICBsZXQgd29ya2VySGFuZGxlO1xyXG5cclxuICB0cnkge1xyXG4gICAgbG9nKDQsICdbcG9vbF0gV29yayByZWNlaXZlZCwgc3RhcnRpbmcgdG8gcHJvY2Vzcy4nKTtcclxuXHJcbiAgICArK2V4cG9ydEF0dGVtcHRzO1xyXG4gICAgaWYgKHBvb2xDb25maWcuYmVuY2htYXJraW5nKSB7XHJcbiAgICAgIGdldFBvb2xJbmZvKCk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKCFwb29sKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignV29yayByZWNlaXZlZCwgYnV0IHBvb2wgaGFzIG5vdCBiZWVuIHN0YXJ0ZWQuJyk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQWNxdWlyZSB0aGUgd29ya2VyIGFsb25nIHdpdGggdGhlIGlkIG9mIHJlc291cmNlIGFuZCB3b3JrIGNvdW50XHJcbiAgICB0cnkge1xyXG4gICAgICBsb2coNCwgJ1twb29sXSBBY3F1aXJpbmcgYSB3b3JrZXIgaGFuZGxlLicpO1xyXG4gICAgICBjb25zdCBhY3F1aXJlQ291bnRlciA9IG1lYXN1cmVUaW1lKCk7XHJcbiAgICAgIHdvcmtlckhhbmRsZSA9IGF3YWl0IHBvb2wuYWNxdWlyZSgpLnByb21pc2U7XHJcblxyXG4gICAgICAvLyBDaGVjayB0aGUgcGFnZSBhY3F1aXJlIHRpbWVcclxuICAgICAgaWYgKG9wdGlvbnMuc2VydmVyLmJlbmNobWFya2luZykge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDUsXHJcbiAgICAgICAgICBvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZFxyXG4gICAgICAgICAgICA/IGBbYmVuY2htYXJrXSBSZXF1ZXN0IHdpdGggSUQgJHtvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZH0gLWBcclxuICAgICAgICAgICAgOiAnW2JlbmNobWFya10nLFxyXG4gICAgICAgICAgYEFjcXVpcmVkIGEgd29ya2VyIGhhbmRsZTogJHthY3F1aXJlQ291bnRlcigpfW1zLmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ0Vycm9yIGVuY291bnRlcmVkIHdoZW4gYWNxdWlyaW5nIGFuIGF2YWlsYWJsZSBlbnRyeS4nXHJcbiAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgfVxyXG4gICAgbG9nKDQsICdbcG9vbF0gQWNxdWlyZWQgYSB3b3JrZXIgaGFuZGxlLicpO1xyXG5cclxuICAgIGlmICghd29ya2VySGFuZGxlLnBhZ2UpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdSZXNvbHZlZCB3b3JrZXIgcGFnZSBpcyBpbnZhbGlkOiB0aGUgcG9vbCBzZXR1cCBpcyB3b25reS4nXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU2F2ZSB0aGUgc3RhcnQgdGltZVxyXG4gICAgbGV0IHdvcmtTdGFydCA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xyXG5cclxuICAgIGxvZyg0LCBgW3Bvb2xdIFN0YXJ0aW5nIHdvcmsgb24gcG9vbCBlbnRyeSB3aXRoIElEICR7d29ya2VySGFuZGxlLmlkfS5gKTtcclxuXHJcbiAgICAvLyBQZXJmb3JtIGFuIGV4cG9ydCBvbiBhIHB1cHBldGVlciBsZXZlbFxyXG4gICAgY29uc3QgZXhwb3J0Q291bnRlciA9IG1lYXN1cmVUaW1lKCk7XHJcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBwdXBwZXRlZXJFeHBvcnQod29ya2VySGFuZGxlLnBhZ2UsIGNoYXJ0LCBvcHRpb25zKTtcclxuXHJcbiAgICAvLyBDaGVjayBpZiBpdCdzIGFuIGVycm9yXHJcbiAgICBpZiAocmVzdWx0IGluc3RhbmNlb2YgRXJyb3IpIHtcclxuICAgICAgLy8gVE9ETzogSWYgdGhlIGV4cG9ydCBmYWlsZWQgYmVjYXVzZSBwdXBwZXRlZXIgdGltZWQgb3V0LCB3ZSBuZWVkIHRvIGZvcmNlIGtpbGwgdGhlIHdvcmtlciBzbyB3ZSBnZXQgYSBuZXcgcGFnZS4gVGhhdCBuZWVkcyB0byBiZSBoYW5kbGVkIGJldHRlciB0aGFuIHRoaXMgaGFjay5cclxuICAgICAgaWYgKHJlc3VsdC5tZXNzYWdlID09PSAnUmFzdGVyaXphdGlvbiB0aW1lb3V0Jykge1xyXG4gICAgICAgIHdvcmtlckhhbmRsZS5wYWdlLmNsb3NlKCk7XHJcbiAgICAgICAgd29ya2VySGFuZGxlLnBhZ2UgPSBhd2FpdCBicm93c2VyTmV3UGFnZSgpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ0Vycm9yIGVuY291bnRlcmVkIGR1cmluZyBleHBvcnQuJykuc2V0RXJyb3IoXHJcbiAgICAgICAgcmVzdWx0XHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2hlY2sgdGhlIFB1cHBldGVlciBleHBvcnQgdGltZVxyXG4gICAgaWYgKG9wdGlvbnMuc2VydmVyLmJlbmNobWFya2luZykge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgNSxcclxuICAgICAgICBvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZFxyXG4gICAgICAgICAgPyBgW2JlbmNobWFya10gUmVxdWVzdCB3aXRoIElEICR7b3B0aW9ucy5wYXlsb2FkPy5yZXF1ZXN0SWR9IC1gXHJcbiAgICAgICAgICA6ICdbYmVuY2htYXJrXScsXHJcbiAgICAgICAgYEV4cG9ydGVkIGEgY2hhcnQgc3VjZXNzZnVsbHk6ICR7ZXhwb3J0Q291bnRlcigpfW1zLmBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBSZWxlYXNlIHRoZSByZXNvdXJjZSBiYWNrIHRvIHRoZSBwb29sXHJcbiAgICBwb29sLnJlbGVhc2Uod29ya2VySGFuZGxlKTtcclxuXHJcbiAgICAvLyBVc2VkIGZvciBzdGF0aXN0aWNzIGluIGF2ZXJhZ2VUaW1lIGFuZCBwcm9jZXNzZWRXb3JrQ291bnQsIHdoaWNoXHJcbiAgICAvLyBpbiB0dXJuIGlzIHVzZWQgYnkgdGhlIC9oZWFsdGggcm91dGUuXHJcbiAgICBjb25zdCB3b3JrRW5kID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XHJcbiAgICBjb25zdCBleHBvcnRUaW1lID0gd29ya0VuZCAtIHdvcmtTdGFydDtcclxuICAgIHRpbWVTcGVudCArPSBleHBvcnRUaW1lO1xyXG4gICAgc3BlbnRBdmVyYWdlID0gdGltZVNwZW50IC8gKytwZXJmb3JtZWRFeHBvcnRzO1xyXG5cclxuICAgIGxvZyg0LCBgW3Bvb2xdIFdvcmsgY29tcGxldGVkIGluICR7ZXhwb3J0VGltZX0gbXMuYCk7XHJcblxyXG4gICAgLy8gT3RoZXJ3aXNlIHJldHVybiB0aGUgcmVzdWx0XHJcbiAgICByZXR1cm4ge1xyXG4gICAgICByZXN1bHQsXHJcbiAgICAgIG9wdGlvbnNcclxuICAgIH07XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICsrZHJvcHBlZEV4cG9ydHM7XHJcblxyXG4gICAgaWYgKHdvcmtlckhhbmRsZSkge1xyXG4gICAgICBwb29sLnJlbGVhc2Uod29ya2VySGFuZGxlKTtcclxuICAgIH1cclxuXHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoYFtwb29sXSBJbiBwb29sLnBvc3RXb3JrOiAke2Vycm9yLm1lc3NhZ2V9YCkuc2V0RXJyb3IoXHJcbiAgICAgIGVycm9yXHJcbiAgICApO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgdGhlIGN1cnJlbnQgcG9vbCBpbnN0YW5jZS5cclxuICpcclxuICogQHJldHVybnMge09iamVjdHxudWxsfSBUaGUgY3VycmVudCBwb29sIGluc3RhbmNlIGlmIGluaXRpYWxpemVkLCBvciBudWxsXHJcbiAqIGlmIHRoZSBwb29sIGhhcyBub3QgYmVlbiBjcmVhdGVkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldFBvb2woKSB7XHJcbiAgcmV0dXJuIHBvb2w7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgcG9vbCBpbmZvcm1hdGlvbiBpbiBKU09OIGZvcm1hdCwgaW5jbHVkaW5nIG1pbmltdW0gYW5kIG1heGltdW1cclxuICogd29ya2VycywgYXZhaWxhYmxlIHdvcmtlcnMsIHdvcmtlcnMgaW4gdXNlLCBhbmQgcGVuZGluZyBhY3F1aXJlIHJlcXVlc3RzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBQb29sIGluZm9ybWF0aW9uIGluIEpTT04gZm9ybWF0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldFBvb2xJbmZvSlNPTiA9ICgpID0+ICh7XHJcbiAgbWluOiBwb29sLm1pbixcclxuICBtYXg6IHBvb2wubWF4LFxyXG4gIGF2YWlsYWJsZTogcG9vbC5udW1GcmVlKCksXHJcbiAgaW5Vc2U6IHBvb2wubnVtVXNlZCgpLFxyXG4gIHBlbmRpbmdBY3F1aXJlOiBwb29sLm51bVBlbmRpbmdBY3F1aXJlcygpXHJcbn0pO1xyXG5cclxuLyoqXHJcbiAqIExvZ3MgaW5mb3JtYXRpb24gYWJvdXQgdGhlIGN1cnJlbnQgc3RhdGUgb2YgdGhlIHBvb2wsIGluY2x1ZGluZyB0aGUgbWluaW11bVxyXG4gKiBhbmQgbWF4aW11bSB3b3JrZXJzLCBhdmFpbGFibGUgd29ya2Vycywgd29ya2VycyBpbiB1c2UsIGFuZCBwZW5kaW5nIGFjcXVpcmVcclxuICogcmVxdWVzdHMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0UG9vbEluZm8oKSB7XHJcbiAgY29uc3QgeyBtaW4sIG1heCB9ID0gcG9vbDtcclxuXHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG1pbmltdW0gbnVtYmVyIG9mIHJlc291cmNlcyBhbGxvd2VkIGJ5IHBvb2w6ICR7bWlufS5gKTtcclxuICBsb2coNSwgYFtwb29sXSBUaGUgbWF4aW11bSBudW1iZXIgb2YgcmVzb3VyY2VzIGFsbG93ZWQgYnkgcG9vbDogJHttYXh9LmApO1xyXG4gIGxvZyhcclxuICAgIDUsXHJcbiAgICBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgcmVzb3VyY2VzIHRoYXQgYXJlIGN1cnJlbnRseSBhdmFpbGFibGU6ICR7cG9vbC5udW1GcmVlKCl9LmBcclxuICApO1xyXG4gIGxvZyhcclxuICAgIDUsXHJcbiAgICBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgcmVzb3VyY2VzIHRoYXQgYXJlIGN1cnJlbnRseSBhY3F1aXJlZDogJHtwb29sLm51bVVzZWQoKX0uYFxyXG4gICk7XHJcbiAgbG9nKFxyXG4gICAgNSxcclxuICAgIGBbcG9vbF0gVGhlIG51bWJlciBvZiBjYWxsZXJzIHdhaXRpbmcgdG8gYWNxdWlyZSBhIHJlc291cmNlOiAke3Bvb2wubnVtUGVuZGluZ0FjcXVpcmVzKCl9LmBcclxuICApO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgaW5pdFBvb2wsXHJcbiAga2lsbFBvb2wsXHJcbiAgcG9zdFdvcmssXHJcbiAgZ2V0UG9vbCxcclxuICBnZXRQb29sSW5mbyxcclxuICBnZXRQb29sSW5mb0pTT04sXHJcbiAgd29ya0F0dGVtcHRzOiAoKSA9PiBleHBvcnRBdHRlbXB0cyxcclxuICBkcm9wcGVkV29yazogKCkgPT4gZHJvcHBlZEV4cG9ydHMsXHJcbiAgYXZlcmFnZVRpbWU6ICgpID0+IHNwZW50QXZlcmFnZSxcclxuICBwcm9jZXNzZWRXb3JrQ291bnQ6ICgpID0+IHBlcmZvcm1lZEV4cG9ydHNcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMsIHdyaXRlRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcblxyXG5pbXBvcnQgeyBnZXRPcHRpb25zLCBpbml0RXhwb3J0U2V0dGluZ3MgfSBmcm9tICcuL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBraWxsUG9vbCwgcG9zdFdvcmsgfSBmcm9tICcuL3Bvb2wuanMnO1xyXG5pbXBvcnQge1xyXG4gIGZpeFR5cGUsXHJcbiAgaGFuZGxlUmVzb3VyY2VzLFxyXG4gIGlzQ29ycmVjdEpTT04sXHJcbiAgb3B0aW9uc1N0cmluZ2lmeSxcclxuICByb3VuZE51bWJlcixcclxuICB0b0Jvb2xlYW4sXHJcbiAgd3JhcEFyb3VuZFxyXG59IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbmxldCBhbGxvd0NvZGVFeGVjdXRpb24gPSBmYWxzZTtcclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgYW4gZXhwb3J0IHByb2Nlc3MuIFRoZSBgc2V0dGluZ3NgIGNvbnRhaW5zIGZpbmFsIG9wdGlvbnMgZ2F0aGVyZWRcclxuICogZnJvbSBhbGwgcG9zc2libGUgc291cmNlcyAoY29uZmlnLCBlbnYsIGNsaSwganNvbikuIFRoZSBgZW5kQ2FsbGJhY2tgIGlzXHJcbiAqIGNhbGxlZCB3aGVuIHRoZSBleHBvcnQgaXMgY29tcGxldGVkLCB3aXRoIGFuIGVycm9yIG9iamVjdCBhcyB0aGUgZmlyc3RcclxuICogYXJndW1lbnQgYW5kIHRoZSBzZWNvbmQgY29udGFpbmluZyB0aGUgYmFzZTY0IHJlc3ByZXNlbnRhdGlvbiBvZiBhIGNoYXJ0LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gc2V0dGluZ3MgLSBUaGUgc2V0dGluZ3Mgb2JqZWN0IGNvbnRhaW5pbmcgZXhwb3J0XHJcbiAqIGNvbmZpZ3VyYXRpb24uXHJcbiAqIEBwYXJhbSB7ZnVuY3Rpb259IGVuZENhbGxiYWNrIC0gVGhlIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGludm9rZWQgdXBvblxyXG4gKiBmaW5hbGl6aW5nIHdvcmsgb3IgdXBvbiBlcnJvciBvY2N1cmFuY2Ugb2YgdGhlIGV4cG9ydGluZyBwcm9jZXNzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7dm9pZH0gVGhpcyBmdW5jdGlvbiBkb2VzIG5vdCByZXR1cm4gYSB2YWx1ZSBkaXJlY3RseTsgaW5zdGVhZCxcclxuICogaXQgY29tbXVuaWNhdGVzIHJlc3VsdHMgdmlhIHRoZSBlbmRDYWxsYmFjay5cclxuICovXHJcbmV4cG9ydCBjb25zdCBzdGFydEV4cG9ydCA9IGFzeW5jIChzZXR0aW5ncywgZW5kQ2FsbGJhY2spID0+IHtcclxuICAvLyBTdGFydGluZyBleHBvcnRpbmcgcHJvY2VzcyBtZXNzYWdlXHJcbiAgbG9nKDQsICdbY2hhcnRdIFN0YXJ0aW5nIHRoZSBleHBvcnRpbmcgcHJvY2Vzcy4nKTtcclxuXHJcbiAgLy8gSW5pdGlhbGl6ZSBvcHRpb25zXHJcbiAgY29uc3Qgb3B0aW9ucyA9IGluaXRFeHBvcnRTZXR0aW5ncyhzZXR0aW5ncywgZ2V0T3B0aW9ucygpKTtcclxuXHJcbiAgLy8gR2V0IHRoZSBleHBvcnQgb3B0aW9uc1xyXG4gIGNvbnN0IGV4cG9ydE9wdGlvbnMgPSBvcHRpb25zLmV4cG9ydDtcclxuXHJcbiAgLy8gSWYgU1ZHIGlzIGFuIGlucHV0IChhcmd1bWVudCBjYW4gYmUgc2VudCBvbmx5IGJ5IHRoZSByZXF1ZXN0KVxyXG4gIGlmIChvcHRpb25zLnBheWxvYWQ/LnN2ZyAmJiBvcHRpb25zLnBheWxvYWQuc3ZnICE9PSAnJykge1xyXG4gICAgdHJ5IHtcclxuICAgICAgbG9nKDQsICdbY2hhcnRdIEF0dGVtcHRpbmcgdG8gZXhwb3J0IGZyb20gYSBTVkcgaW5wdXQuJyk7XHJcbiAgICAgIHJldHVybiBleHBvcnRBc1N0cmluZyhvcHRpb25zLnBheWxvYWQuc3ZnLnRyaW0oKSwgb3B0aW9ucywgZW5kQ2FsbGJhY2spO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKFxyXG4gICAgICAgIG5ldyBFeHBvcnRFcnJvcignW2NoYXJ0XSBFcnJvciBsb2FkaW5nIFNWRyBpbnB1dC4nKS5zZXRFcnJvcihlcnJvcilcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIEV4cG9ydCB1c2luZyBvcHRpb25zIGZyb20gdGhlIGZpbGVcclxuICBpZiAoZXhwb3J0T3B0aW9ucy5pbmZpbGUgJiYgZXhwb3J0T3B0aW9ucy5pbmZpbGUubGVuZ3RoKSB7XHJcbiAgICAvLyBUcnkgdG8gcmVhZCB0aGUgZmlsZSB0byBnZXQgdGhlIHN0cmluZyByZXByZXNlbnRhdGlvblxyXG4gICAgdHJ5IHtcclxuICAgICAgbG9nKDQsICdbY2hhcnRdIEF0dGVtcHRpbmcgdG8gZXhwb3J0IGZyb20gYW4gaW5wdXQgZmlsZS4nKTtcclxuICAgICAgb3B0aW9ucy5leHBvcnQuaW5zdHIgPSByZWFkRmlsZVN5bmMoZXhwb3J0T3B0aW9ucy5pbmZpbGUsICd1dGY4Jyk7XHJcbiAgICAgIHJldHVybiBleHBvcnRBc1N0cmluZyhvcHRpb25zLmV4cG9ydC5pbnN0ci50cmltKCksIG9wdGlvbnMsIGVuZENhbGxiYWNrKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgICAgICBuZXcgRXhwb3J0RXJyb3IoJ1tjaGFydF0gRXJyb3IgbG9hZGluZyBpbnB1dCBmaWxlLicpLnNldEVycm9yKGVycm9yKVxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gRXhwb3J0IHdpdGggb3B0aW9ucyBmcm9tIHRoZSByYXcgcmVwcmVzZW50YXRpb25cclxuICBpZiAoXHJcbiAgICAoZXhwb3J0T3B0aW9ucy5pbnN0ciAmJiBleHBvcnRPcHRpb25zLmluc3RyICE9PSAnJykgfHxcclxuICAgIChleHBvcnRPcHRpb25zLm9wdGlvbnMgJiYgZXhwb3J0T3B0aW9ucy5vcHRpb25zICE9PSAnJylcclxuICApIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGxvZyg0LCAnW2NoYXJ0XSBBdHRlbXB0aW5nIHRvIGV4cG9ydCBmcm9tIGEgcmF3IGlucHV0LicpO1xyXG5cclxuICAgICAgLy8gUGVyZm9ybSBhIGRpcmVjdCBpbmplY3Qgd2hlbiBmb3JjZWRcclxuICAgICAgaWYgKHRvQm9vbGVhbihvcHRpb25zLmN1c3RvbUxvZ2ljPy5hbGxvd0NvZGVFeGVjdXRpb24pKSB7XHJcbiAgICAgICAgcmV0dXJuIGRvU3RyYWlnaHRJbmplY3Qob3B0aW9ucywgZW5kQ2FsbGJhY2spO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBFaXRoZXIgdHJ5IHRvIHBhcnNlIHRvIEpTT04gZmlyc3Qgb3IgZG8gdGhlIGRpcmVjdCBleHBvcnRcclxuICAgICAgcmV0dXJuIHR5cGVvZiBleHBvcnRPcHRpb25zLmluc3RyID09PSAnc3RyaW5nJ1xyXG4gICAgICAgID8gZXhwb3J0QXNTdHJpbmcoZXhwb3J0T3B0aW9ucy5pbnN0ci50cmltKCksIG9wdGlvbnMsIGVuZENhbGxiYWNrKVxyXG4gICAgICAgIDogZG9FeHBvcnQoXHJcbiAgICAgICAgICAgIG9wdGlvbnMsXHJcbiAgICAgICAgICAgIGV4cG9ydE9wdGlvbnMuaW5zdHIgfHwgZXhwb3J0T3B0aW9ucy5vcHRpb25zLFxyXG4gICAgICAgICAgICBlbmRDYWxsYmFja1xyXG4gICAgICAgICAgKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgICAgICBuZXcgRXhwb3J0RXJyb3IoJ1tjaGFydF0gRXJyb3IgbG9hZGluZyByYXcgaW5wdXQuJykuc2V0RXJyb3IoZXJyb3IpXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBObyBpbnB1dCBzcGVjaWZpZWQsIHBhc3MgYW4gZXJyb3IgbWVzc2FnZSB0byB0aGUgY2FsbGJhY2tcclxuICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgIGBbY2hhcnRdIE5vIHZhbGlkIGlucHV0IHNwZWNpZmllZC4gQ2hlY2sgaWYgYXQgbGVhc3Qgb25lIG9mIHRoZSBmb2xsb3dpbmcgcGFyYW1ldGVycyBpcyBjb3JyZWN0bHkgc2V0OiAnaW5maWxlJywgJ2luc3RyJywgJ29wdGlvbnMnLCBvciAnc3ZnJy5gXHJcbiAgICApXHJcbiAgKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgYSBiYXRjaCBleHBvcnQgcHJvY2VzcyBmb3IgbXVsdGlwbGUgY2hhcnRzIGJhc2VkIG9uIHRoZSBpbmZvcm1hdGlvblxyXG4gKiBpbiB0aGUgYmF0Y2ggb3B0aW9uLiBUaGUgYmF0Y2ggaXMgYSBzdHJpbmcgaW4gdGhlIGZvbGxvd2luZyBmb3JtYXQ6XHJcbiAqIFwiaW5maWxlMS5qc29uPW91dGZpbGUxLnBuZztpbmZpbGUyLmpzb249b3V0ZmlsZTIucG5nOy4uLlwiXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IGNvbnRhaW5pbmcgY29uZmlndXJhdGlvbiBmb3JcclxuICogYSBiYXRjaCBleHBvcnQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBiYXRjaCBleHBvcnRcclxuICogcHJvY2VzcyBpcyBjb21wbGV0ZWQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgYW4gZXJyb3Igb2NjdXJzIGR1cmluZ1xyXG4gKiBhbnkgb2YgdGhlIGJhdGNoIGV4cG9ydCBwcm9jZXNzLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGJhdGNoRXhwb3J0ID0gYXN5bmMgKG9wdGlvbnMpID0+IHtcclxuICBjb25zdCBiYXRjaEZ1bmN0aW9ucyA9IFtdO1xyXG5cclxuICAvLyBTcGxpdCBhbmQgcGFpciB0aGUgLS1iYXRjaCBhcmd1bWVudHNcclxuICBmb3IgKGxldCBwYWlyIG9mIG9wdGlvbnMuZXhwb3J0LmJhdGNoLnNwbGl0KCc7JykpIHtcclxuICAgIHBhaXIgPSBwYWlyLnNwbGl0KCc9Jyk7XHJcbiAgICBpZiAocGFpci5sZW5ndGggPT09IDIpIHtcclxuICAgICAgYmF0Y2hGdW5jdGlvbnMucHVzaChcclxuICAgICAgICBzdGFydEV4cG9ydChcclxuICAgICAgICAgIHtcclxuICAgICAgICAgICAgLi4ub3B0aW9ucyxcclxuICAgICAgICAgICAgZXhwb3J0OiB7XHJcbiAgICAgICAgICAgICAgLi4ub3B0aW9ucy5leHBvcnQsXHJcbiAgICAgICAgICAgICAgaW5maWxlOiBwYWlyWzBdLFxyXG4gICAgICAgICAgICAgIG91dGZpbGU6IHBhaXJbMV1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSxcclxuICAgICAgICAgIChlcnJvciwgaW5mbykgPT4ge1xyXG4gICAgICAgICAgICAvLyBUaHJvdyBhbiBlcnJvclxyXG4gICAgICAgICAgICBpZiAoZXJyb3IpIHtcclxuICAgICAgICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgLy8gU2F2ZSB0aGUgYmFzZTY0IGZyb20gYSBidWZmZXIgdG8gYSBjb3JyZWN0IGltYWdlIGZpbGVcclxuICAgICAgICAgICAgd3JpdGVGaWxlU3luYyhcclxuICAgICAgICAgICAgICBpbmZvLm9wdGlvbnMuZXhwb3J0Lm91dGZpbGUsXHJcbiAgICAgICAgICAgICAgQnVmZmVyLmZyb20oaW5mby5yZXN1bHQsICdiYXNlNjQnKVxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIClcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHRyeSB7XHJcbiAgICAvLyBBd2FpdCBhbGwgZXhwb3J0cyBhcmUgZG9uZVxyXG4gICAgYXdhaXQgUHJvbWlzZS5hbGwoYmF0Y2hGdW5jdGlvbnMpO1xyXG5cclxuICAgIC8vIEtpbGwgcG9vbCBhbmQgY2xvc2UgYnJvd3NlciBhZnRlciBmaW5pc2hpbmcgYmF0Y2ggZXhwb3J0XHJcbiAgICBhd2FpdCBraWxsUG9vbCgpO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbY2hhcnRdIEVycm9yIGVuY291bnRlcmVkIGR1cmluZyBiYXRjaCBleHBvcnQuJ1xyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIFN0YXJ0cyBhIHNpbmdsZSBleHBvcnQgcHJvY2VzcyBiYXNlZCBvbiB0aGUgc3BlY2lmaWVkIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IGNvbnRhaW5pbmcgY29uZmlndXJhdGlvbiBmb3JcclxuICogYSBzaW5nbGUgZXhwb3J0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgc2luZ2xlIGV4cG9ydFxyXG4gKiBwcm9jZXNzIGlzIGNvbXBsZXRlZC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiBhbiBlcnJvciBvY2N1cnMgZHVyaW5nXHJcbiAqIHRoZSBzaW5nbGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2luZ2xlRXhwb3J0ID0gYXN5bmMgKG9wdGlvbnMpID0+IHtcclxuICAvLyBVc2UgaW5zdHIgb3IgaXRzIGFsaWFzLCBvcHRpb25zXHJcbiAgb3B0aW9ucy5leHBvcnQuaW5zdHIgPSBvcHRpb25zLmV4cG9ydC5pbnN0ciB8fCBvcHRpb25zLmV4cG9ydC5vcHRpb25zO1xyXG5cclxuICAvLyBQZXJmb3JtIGFuIGV4cG9ydFxyXG4gIGF3YWl0IHN0YXJ0RXhwb3J0KG9wdGlvbnMsIGFzeW5jIChlcnJvciwgaW5mbykgPT4ge1xyXG4gICAgLy8gRXhpdCBwcm9jZXNzIHdoZW4gZXJyb3JcclxuICAgIGlmIChlcnJvcikge1xyXG4gICAgICB0aHJvdyBlcnJvcjtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCB7IG91dGZpbGUsIHR5cGUgfSA9IGluZm8ub3B0aW9ucy5leHBvcnQ7XHJcblxyXG4gICAgLy8gU2F2ZSB0aGUgYmFzZTY0IGZyb20gYSBidWZmZXIgdG8gYSBjb3JyZWN0IGltYWdlIGZpbGVcclxuICAgIHdyaXRlRmlsZVN5bmMoXHJcbiAgICAgIG91dGZpbGUgfHwgYGNoYXJ0LiR7dHlwZX1gLFxyXG4gICAgICB0eXBlICE9PSAnc3ZnJyA/IEJ1ZmZlci5mcm9tKGluZm8ucmVzdWx0LCAnYmFzZTY0JykgOiBpbmZvLnJlc3VsdFxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBLaWxsIHRoZSBwb29sXHJcbiAgICBhd2FpdCBraWxsUG9vbCgpO1xyXG4gIH0pO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIERldGVybWluZXMgdGhlIHNpemUgYW5kIHNjYWxlIGZvciBjaGFydCBleHBvcnQgYmFzZWQgb24gdGhlIHByb3ZpZGVkIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IGNvbnRhaW5pbmcgY29uZmlndXJhdGlvbiBmb3JcclxuICogY2hhcnQgZXhwb3J0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBBbiBvYmplY3QgY29udGFpbmluZyB0aGUgY2FsY3VsYXRlZCBoZWlnaHQsIHdpZHRoLFxyXG4gKiBhbmQgc2NhbGUgZm9yIHRoZSBjaGFydCBleHBvcnQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZmluZENoYXJ0U2l6ZSA9IChvcHRpb25zKSA9PiB7XHJcbiAgY29uc3QgeyBjaGFydCwgZXhwb3J0aW5nIH0gPVxyXG4gICAgb3B0aW9ucy5leHBvcnQ/Lm9wdGlvbnMgfHwgaXNDb3JyZWN0SlNPTihvcHRpb25zLmV4cG9ydD8uaW5zdHIpO1xyXG5cclxuICAvLyBTZWUgaWYgZ2xvYmFsT3B0aW9ucyBob2xkcyBjaGFydCBvciBleHBvcnRpbmcgc2l6ZVxyXG4gIGNvbnN0IGdsb2JhbE9wdGlvbnMgPSBpc0NvcnJlY3RKU09OKG9wdGlvbnMuZXhwb3J0Py5nbG9iYWxPcHRpb25zKTtcclxuXHJcbiAgLy8gU2VjdXJlIHNjYWxlIHZhbHVlXHJcbiAgbGV0IHNjYWxlID1cclxuICAgIG9wdGlvbnMuZXhwb3J0Py5zY2FsZSB8fFxyXG4gICAgZXhwb3J0aW5nPy5zY2FsZSB8fFxyXG4gICAgZ2xvYmFsT3B0aW9ucz8uZXhwb3J0aW5nPy5zY2FsZSB8fFxyXG4gICAgb3B0aW9ucy5leHBvcnQ/LmRlZmF1bHRTY2FsZSB8fFxyXG4gICAgMTtcclxuXHJcbiAgLy8gdGhlIHNjYWxlIGNhbm5vdCBiZSBsb3dlciB0aGFuIDAuMSBhbmQgY2Fubm90IGJlIGhpZ2hlciB0aGFuIDUuMFxyXG4gIHNjYWxlID0gTWF0aC5tYXgoMC4xLCBNYXRoLm1pbihzY2FsZSwgNS4wKSk7XHJcblxyXG4gIC8vIHdlIHdhbnQgdG8gcm91bmQgdGhlIG51bWJlcnMgbGlrZSAwLjIzMjM0IC0+IDAuMjNcclxuICBzY2FsZSA9IHJvdW5kTnVtYmVyKHNjYWxlLCAyKTtcclxuXHJcbiAgLy8gRmluZCBjaGFydCBzaXplIGFuZCBzY2FsZVxyXG4gIGNvbnN0IHNpemUgPSB7XHJcbiAgICBoZWlnaHQ6XHJcbiAgICAgIG9wdGlvbnMuZXhwb3J0Py5oZWlnaHQgfHxcclxuICAgICAgZXhwb3J0aW5nPy5zb3VyY2VIZWlnaHQgfHxcclxuICAgICAgY2hhcnQ/LmhlaWdodCB8fFxyXG4gICAgICBnbG9iYWxPcHRpb25zPy5leHBvcnRpbmc/LnNvdXJjZUhlaWdodCB8fFxyXG4gICAgICBnbG9iYWxPcHRpb25zPy5jaGFydD8uaGVpZ2h0IHx8XHJcbiAgICAgIG9wdGlvbnMuZXhwb3J0Py5kZWZhdWx0SGVpZ2h0IHx8XHJcbiAgICAgIDQwMCxcclxuICAgIHdpZHRoOlxyXG4gICAgICBvcHRpb25zLmV4cG9ydD8ud2lkdGggfHxcclxuICAgICAgZXhwb3J0aW5nPy5zb3VyY2VXaWR0aCB8fFxyXG4gICAgICBjaGFydD8ud2lkdGggfHxcclxuICAgICAgZ2xvYmFsT3B0aW9ucz8uZXhwb3J0aW5nPy5zb3VyY2VXaWR0aCB8fFxyXG4gICAgICBnbG9iYWxPcHRpb25zPy5jaGFydD8ud2lkdGggfHxcclxuICAgICAgb3B0aW9ucy5leHBvcnQ/LmRlZmF1bHRXaWR0aCB8fFxyXG4gICAgICA2MDAsXHJcbiAgICBzY2FsZVxyXG4gIH07XHJcblxyXG4gIC8vIEdldCByaWQgb2YgcG90ZW50aWFsIHB4IGFuZCAlXHJcbiAgZm9yIChsZXQgW3BhcmFtLCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMoc2l6ZSkpIHtcclxuICAgIHNpemVbcGFyYW1dID1cclxuICAgICAgdHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJyA/ICt2YWx1ZS5yZXBsYWNlKC9weHwlL2dpLCAnJykgOiB2YWx1ZTtcclxuICB9XHJcbiAgcmV0dXJuIHNpemU7XHJcbn07XHJcblxyXG4vKipcclxuICogRnVuY3Rpb24gZm9yIGZpbmFsaXppbmcgb3B0aW9ucyBiZWZvcmUgZXhwb3J0LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBvcHRpb25zIG9iamVjdCBjb250YWluaW5nIGNvbmZpZ3VyYXRpb24gZm9yXHJcbiAqIHRoZSBleHBvcnQgcHJvY2Vzcy5cclxuICogQHBhcmFtIHtPYmplY3R9IGNoYXJ0SnNvbiAtIFRoZSBKU09OIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBjaGFydC5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gZW5kQ2FsbGJhY2sgLSBUaGUgY2FsbGJhY2sgZnVuY3Rpb24gdG8gYmUgY2FsbGVkIHVwb25cclxuICogY29tcGxldGlvbiBvciBlcnJvci5cclxuICogQHBhcmFtIHtzdHJpbmd9IHN2ZyAtIFRoZSBTVkcgcmVwcmVzZW50YXRpb24gb2YgdGhlIGNoYXJ0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgZXhwb3J0IHByb2Nlc3NcclxuICogaXMgY29tcGxldGVkLlxyXG4gKi9cclxuY29uc3QgZG9FeHBvcnQgPSBhc3luYyAob3B0aW9ucywgY2hhcnRKc29uLCBlbmRDYWxsYmFjaywgc3ZnKSA9PiB7XHJcbiAgbGV0IHsgZXhwb3J0OiBleHBvcnRPcHRpb25zLCBjdXN0b21Mb2dpYzogY3VzdG9tTG9naWNPcHRpb25zIH0gPSBvcHRpb25zO1xyXG5cclxuICBjb25zdCBhbGxvd0NvZGVFeGVjdXRpb25TY29wZWQgPVxyXG4gICAgdHlwZW9mIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0NvZGVFeGVjdXRpb24gPT09ICdib29sZWFuJ1xyXG4gICAgICA/IGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0NvZGVFeGVjdXRpb25cclxuICAgICAgOiBhbGxvd0NvZGVFeGVjdXRpb247XHJcblxyXG4gIGlmICghY3VzdG9tTG9naWNPcHRpb25zKSB7XHJcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMgPSBvcHRpb25zLmN1c3RvbUxvZ2ljID0ge307XHJcbiAgfSBlbHNlIGlmIChhbGxvd0NvZGVFeGVjdXRpb25TY29wZWQpIHtcclxuICAgIGlmICh0eXBlb2Ygb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXMgPT09ICdzdHJpbmcnKSB7XHJcbiAgICAgIC8vIFByb2Nlc3MgcmVzb3VyY2VzXHJcbiAgICAgIG9wdGlvbnMuY3VzdG9tTG9naWMucmVzb3VyY2VzID0gaGFuZGxlUmVzb3VyY2VzKFxyXG4gICAgICAgIG9wdGlvbnMuY3VzdG9tTG9naWMucmVzb3VyY2VzLFxyXG4gICAgICAgIHRvQm9vbGVhbihvcHRpb25zLmN1c3RvbUxvZ2ljLmFsbG93RmlsZVJlc291cmNlcylcclxuICAgICAgKTtcclxuICAgIH0gZWxzZSBpZiAoIW9wdGlvbnMuY3VzdG9tTG9naWMucmVzb3VyY2VzKSB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgY29uc3QgcmVzb3VyY2VzID0gcmVhZEZpbGVTeW5jKCdyZXNvdXJjZXMuanNvbicsICd1dGY4Jyk7XHJcbiAgICAgICAgb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXMgPSBoYW5kbGVSZXNvdXJjZXMoXHJcbiAgICAgICAgICByZXNvdXJjZXMsXHJcbiAgICAgICAgICB0b0Jvb2xlYW4ob3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0ZpbGVSZXNvdXJjZXMpXHJcbiAgICAgICAgKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgICAyLFxyXG4gICAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgICBgW2NoYXJ0XSBVbmFibGUgdG8gbG9hZCB0aGUgZGVmYXVsdCByZXNvdXJjZXMuanNvbiBmaWxlLmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBJZiB0aGUgYWxsb3dDb2RlRXhlY3V0aW9uIGZsYWcgaXNuJ3Qgc2V0LCB3ZSBzaG91bGQgcmVmdXNlIHRoZSB1c2FnZVxyXG4gIC8vIG9mIGNhbGxiYWNrLCByZXNvdXJjZXMsIGFuZCBjdXN0b20gY29kZS4gQWRkaXRpb25hbGx5LCB0aGUgd29ya2VyIHdpbGxcclxuICAvLyByZWZ1c2UgdG8gcnVuIGFyYml0cmFyeSBKYXZhU2NyaXB0LiBQcmlvcml0aXplZCBzaG91bGQgYmUgdGhlIHNjb3BlZFxyXG4gIC8vIG9wdGlvbiwgdGhlbiB3ZSBzaG91bGQgdGFrZSBhIGxvb2sgYXQgdGhlIG92ZXJhbGwgcG9vbCBvcHRpb24uXHJcbiAgaWYgKCFhbGxvd0NvZGVFeGVjdXRpb25TY29wZWQgJiYgY3VzdG9tTG9naWNPcHRpb25zKSB7XHJcbiAgICBpZiAoXHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayB8fFxyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzIHx8XHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlXHJcbiAgICApIHtcclxuICAgICAgLy8gU2VuZCBiYWNrIGEgZnJpZW5kbHkgbWVzc2FnZSBzYXlpbmcgdGhhdCB0aGUgZXhwb3J0ZXIgZG9lcyBub3Qgc3VwcG9ydFxyXG4gICAgICAvLyB0aGVzZSBzZXR0aW5ncy5cclxuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKFxyXG4gICAgICAgIG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgIGBbY2hhcnRdIFRoZSAnY2FsbGJhY2snLCAncmVzb3VyY2VzJyBhbmQgJ2N1c3RvbUNvZGUnIG9wdGlvbnMgaGF2ZSBiZWVuIGRpc2FibGVkIGZvciB0aGlzIHNlcnZlci5gXHJcbiAgICAgICAgKVxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFJlc2V0IGFsbCBhZGRpdGlvbmFsIGN1c3RvbSBjb2RlXHJcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSBmYWxzZTtcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXMgPSBmYWxzZTtcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlID0gZmFsc2U7XHJcbiAgfVxyXG5cclxuICAvLyBDbGVhbiBwcm9wZXJ0aWVzIHRvIGtlZXAgaXQgbGVhbiBhbmQgbWVhblxyXG4gIGlmIChjaGFydEpzb24pIHtcclxuICAgIGNoYXJ0SnNvbi5jaGFydCA9IGNoYXJ0SnNvbi5jaGFydCB8fCB7fTtcclxuICAgIGNoYXJ0SnNvbi5leHBvcnRpbmcgPSBjaGFydEpzb24uZXhwb3J0aW5nIHx8IHt9O1xyXG4gICAgY2hhcnRKc29uLmV4cG9ydGluZy5lbmFibGVkID0gZmFsc2U7XHJcbiAgfVxyXG5cclxuICBleHBvcnRPcHRpb25zLmNvbnN0ciA9IGV4cG9ydE9wdGlvbnMuY29uc3RyIHx8ICdjaGFydCc7XHJcbiAgZXhwb3J0T3B0aW9ucy50eXBlID0gZml4VHlwZShleHBvcnRPcHRpb25zLnR5cGUsIGV4cG9ydE9wdGlvbnMub3V0ZmlsZSk7XHJcbiAgaWYgKGV4cG9ydE9wdGlvbnMudHlwZSA9PT0gJ3N2ZycpIHtcclxuICAgIGV4cG9ydE9wdGlvbnMud2lkdGggPSBmYWxzZTtcclxuICB9XHJcblxyXG4gIC8vIFByZXBhcmUgZ2xvYmFsIGFuZCB0aGVtZSBvcHRpb25zXHJcbiAgWydnbG9iYWxPcHRpb25zJywgJ3RoZW1lT3B0aW9ucyddLmZvckVhY2goKG9wdGlvbnNOYW1lKSA9PiB7XHJcbiAgICB0cnkge1xyXG4gICAgICBpZiAoZXhwb3J0T3B0aW9ucyAmJiBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSkge1xyXG4gICAgICAgIGlmIChcclxuICAgICAgICAgIHR5cGVvZiBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9PT0gJ3N0cmluZycgJiZcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdLmVuZHNXaXRoKCcuanNvbicpXHJcbiAgICAgICAgKSB7XHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9IGlzQ29ycmVjdEpTT04oXHJcbiAgICAgICAgICAgIHJlYWRGaWxlU3luYyhleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSwgJ3V0ZjgnKSxcclxuICAgICAgICAgICAgdHJ1ZVxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPSBpc0NvcnJlY3RKU09OKFxyXG4gICAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSxcclxuICAgICAgICAgICAgdHJ1ZVxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID0ge307XHJcbiAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgYFtjaGFydF0gVGhlICcke29wdGlvbnNOYW1lfScgY2Fubm90IGJlIGxvYWRlZC5gKTtcclxuICAgIH1cclxuICB9KTtcclxuXHJcbiAgLy8gUHJlcGFyZSB0aGUgY3VzdG9tQ29kZVxyXG4gIGlmIChjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dDb2RlRXhlY3V0aW9uKSB7XHJcbiAgICB0cnkge1xyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSA9IHdyYXBBcm91bmQoXHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUsXHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmFsbG93RmlsZVJlc291cmNlc1xyXG4gICAgICApO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2NoYXJ0XSBUaGUgJ2N1c3RvbUNvZGUnIGNhbm5vdCBiZSBsb2FkZWQuYCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBHZXQgdGhlIGNhbGxiYWNrXHJcbiAgaWYgKFxyXG4gICAgY3VzdG9tTG9naWNPcHRpb25zICYmXHJcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgJiZcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjaz8uaW5kZXhPZigneycpIDwgMFxyXG4gICkge1xyXG4gICAgLy8gVGhlIGFsbG93RmlsZVJlc291cmNlcyBpcyBhbHdheXMgc2V0IHRvIGZhbHNlIGZvciBIVFRQIHJlcXVlc3RzIHRvIGF2b2lkXHJcbiAgICAvLyBpbmplY3RpbmcgYXJiaXRyYXJ5IGZpbGVzIGZyb20gdGhlIGZzXHJcbiAgICBpZiAoY3VzdG9tTG9naWNPcHRpb25zLmFsbG93RmlsZVJlc291cmNlcykge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IHJlYWRGaWxlU3luYyhcclxuICAgICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayxcclxuICAgICAgICAgICd1dGY4J1xyXG4gICAgICAgICk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrID0gZmFsc2U7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2NoYXJ0XSBUaGUgJ2NhbGxiYWNrJyBjYW5ub3QgYmUgbG9hZGVkLmApO1xyXG4gICAgICB9XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSBmYWxzZTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFNpemUgc2VhcmNoXHJcbiAgb3B0aW9ucy5leHBvcnQgPSB7XHJcbiAgICAuLi5vcHRpb25zLmV4cG9ydCxcclxuICAgIC4uLmZpbmRDaGFydFNpemUob3B0aW9ucylcclxuICB9O1xyXG5cclxuICAvLyBQb3N0IHRoZSB3b3JrIHRvIHRoZSBwb29sXHJcbiAgdHJ5IHtcclxuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHBvc3RXb3JrKFxyXG4gICAgICBleHBvcnRPcHRpb25zLnN0ckluaiB8fCBjaGFydEpzb24gfHwgc3ZnLFxyXG4gICAgICBvcHRpb25zXHJcbiAgICApO1xyXG4gICAgcmV0dXJuIGVuZENhbGxiYWNrKGZhbHNlLCByZXN1bHQpO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICByZXR1cm4gZW5kQ2FsbGJhY2soZXJyb3IpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBQZXJmb3JtcyBhIGRpcmVjdCBpbmplY3Qgb2Ygb3B0aW9ucyBiZWZvcmUgZXhwb3J0LiBUaGUgZnVuY3Rpb24gYXR0ZW1wdHNcclxuICogdG8gc3RyaW5naWZ5IHRoZSBwcm92aWRlZCBvcHRpb25zIGFuZCByZW1vdmVzIHVubmVjZXNzYXJ5IGNoYXJhY3RlcnMsXHJcbiAqIGVuc3VyaW5nIGEgY2xlYW4gYW5kIGZvcm1hdHRlZCBpbnB1dC4gVGhlIHJlc3VsdGluZyBzdHJpbmcgaXMgc2F2ZWQgYXNcclxuICogYSBcInN0cmlnaHQgaW5qZWN0XCIgc3RyaW5nIGluIHRoZSBleHBvcnQgb3B0aW9ucy4gSXQgdGhlbiBpbnZva2VzIHRoZVxyXG4gKiBkb0V4cG9ydCBmdW5jdGlvbiB3aXRoIHRoZSB1cGRhdGVkIG9wdGlvbnMuXHJcbiAqXHJcbiAqIElNUE9SVEFOVDogRGFuZ2Vyb3VzIGFuZCBtdXN0IGJlIHVzZWQgZGVsaWJlcmF0ZWx5IGJ5IHNvbWVvbmUgd2hvIHNldHMgdXBcclxuICogYSBzZXJ2ZXIgKHNlZSB0aGUgIC0tYWxsb3dDb2RlRXhlY3V0aW9uIG9wdGlvbikuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIGV4cG9ydCBvcHRpb25zIGNvbnRhaW5pbmcgdGhlIGlucHV0XHJcbiAqIHRvIGJlIGluamVjdGVkLlxyXG4gKiBAcGFyYW0ge2Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIFRoZSBjYWxsYmFjayBmdW5jdGlvbiB0byBiZSBpbnZva2VkXHJcbiAqIGF0IHRoZSBlbmQgb2YgdGhlIHByb2Nlc3MuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlfSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB3aXRoIHRoZSByZXN1bHQgb2YgdGhlIGV4cG9ydFxyXG4gKiBvcGVyYXRpb24gb3IgcmVqZWN0cyB3aXRoIGFuIGVycm9yIGlmIGFueSBpc3N1ZXMgb2NjdXIgZHVyaW5nIHRoZSBwcm9jZXNzLlxyXG4gKi9cclxuY29uc3QgZG9TdHJhaWdodEluamVjdCA9IChvcHRpb25zLCBlbmRDYWxsYmFjaykgPT4ge1xyXG4gIHRyeSB7XHJcbiAgICBsZXQgc3RySW5qO1xyXG4gICAgbGV0IGluc3RyID0gb3B0aW9ucy5leHBvcnQuaW5zdHIgfHwgb3B0aW9ucy5leHBvcnQub3B0aW9ucztcclxuXHJcbiAgICBpZiAodHlwZW9mIGluc3RyICE9PSAnc3RyaW5nJykge1xyXG4gICAgICAvLyBUcnkgdG8gc3RyaW5naWZ5IG9wdGlvbnNcclxuICAgICAgc3RySW5qID0gaW5zdHIgPSBvcHRpb25zU3RyaW5naWZ5KFxyXG4gICAgICAgIGluc3RyLFxyXG4gICAgICAgIG9wdGlvbnMuY3VzdG9tTG9naWM/LmFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gICAgc3RySW5qID0gaW5zdHIucmVwbGFjZUFsbCgvXFx0fFxcbnxcXHIvZywgJycpLnRyaW0oKTtcclxuXHJcbiAgICAvLyBHZXQgcmlkIG9mIHRoZSA7XHJcbiAgICBpZiAoc3RySW5qW3N0ckluai5sZW5ndGggLSAxXSA9PT0gJzsnKSB7XHJcbiAgICAgIHN0ckluaiA9IHN0ckluai5zdWJzdHJpbmcoMCwgc3RySW5qLmxlbmd0aCAtIDEpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFNhdmUgYXMgc3RyaWdodCBpbmplY3Qgc3RyaW5nXHJcbiAgICBvcHRpb25zLmV4cG9ydC5zdHJJbmogPSBzdHJJbmo7XHJcbiAgICByZXR1cm4gZG9FeHBvcnQob3B0aW9ucywgZmFsc2UsIGVuZENhbGxiYWNrKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgcmV0dXJuIGVuZENhbGxiYWNrKFxyXG4gICAgICBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgYFtjaGFydF0gTWFsZm9ybWVkIGlucHV0IGRldGVjdGVkIGZvciAke29wdGlvbnMuZXhwb3J0Py5yZXF1ZXN0SWQgfHwgJz8nfS4gUGxlYXNlIG1ha2Ugc3VyZSB0aGF0IHlvdXIgSlNPTi9KYXZhU2NyaXB0IG9wdGlvbnMgYXJlIHNlbnQgdXNpbmcgdGhlIFwib3B0aW9uc1wiIGF0dHJpYnV0ZSwgYW5kIHRoYXQgaWYgeW91J3JlIHVzaW5nIFNWRywgaXQgaXMgdW5lc2NhcGVkLmBcclxuICAgICAgKS5zZXRFcnJvcihlcnJvcilcclxuICAgICk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEV4cG9ydHMgYSBzdHJpbmcgYmFzZWQgb24gdGhlIHByb3ZpZGVkIG9wdGlvbnMgYW5kIGludm9rZXMgYW4gZW5kIGNhbGxiYWNrLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gc3RyaW5nVG9FeHBvcnQgLSBUaGUgc3RyaW5nIGNvbnRlbnQgdG8gYmUgZXhwb3J0ZWQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gRXhwb3J0IG9wdGlvbnMsIGluY2x1ZGluZyBjdXN0b21Mb2dpYyB3aXRoXHJcbiAqIGFsbG93Q29kZUV4ZWN1dGlvbiBmbGFnLlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIENhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGludm9rZWQgYXQgdGhlIGVuZFxyXG4gKiBvZiB0aGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHthbnl9IFJlc3VsdCBvZiB0aGUgZXhwb3J0IHByb2Nlc3Mgb3IgYW4gZXJyb3IgaWYgZW5jb3VudGVyZWQuXHJcbiAqL1xyXG5jb25zdCBleHBvcnRBc1N0cmluZyA9IChzdHJpbmdUb0V4cG9ydCwgb3B0aW9ucywgZW5kQ2FsbGJhY2spID0+IHtcclxuICBjb25zdCB7IGFsbG93Q29kZUV4ZWN1dGlvbiB9ID0gb3B0aW9ucy5jdXN0b21Mb2dpYztcclxuXHJcbiAgLy8gQ2hlY2sgaWYgaXQgaXMgU1ZHXHJcbiAgaWYgKFxyXG4gICAgc3RyaW5nVG9FeHBvcnQuaW5kZXhPZignPHN2ZycpID49IDAgfHxcclxuICAgIHN0cmluZ1RvRXhwb3J0LmluZGV4T2YoJzw/eG1sJykgPj0gMFxyXG4gICkge1xyXG4gICAgbG9nKDQsICdbY2hhcnRdIFBhcnNpbmcgaW5wdXQgYXMgU1ZHLicpO1xyXG4gICAgcmV0dXJuIGRvRXhwb3J0KG9wdGlvbnMsIGZhbHNlLCBlbmRDYWxsYmFjaywgc3RyaW5nVG9FeHBvcnQpO1xyXG4gIH1cclxuXHJcbiAgdHJ5IHtcclxuICAgIC8vIFRyeSB0byBwYXJzZSB0byBKU09OIGFuZCBjYWxsIHRoZSBkb0V4cG9ydCBmdW5jdGlvblxyXG4gICAgY29uc3QgY2hhcnRKU09OID0gSlNPTi5wYXJzZShzdHJpbmdUb0V4cG9ydC5yZXBsYWNlQWxsKC9cXHR8XFxufFxcci9nLCAnICcpKTtcclxuXHJcbiAgICAvLyBJZiBhIGNvcnJlY3QgSlNPTiwgZG8gdGhlIGV4cG9ydFxyXG4gICAgcmV0dXJuIGRvRXhwb3J0KG9wdGlvbnMsIGNoYXJ0SlNPTiwgZW5kQ2FsbGJhY2spO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAvLyBOb3QgYSB2YWxpZCBKU09OXHJcbiAgICBpZiAodG9Cb29sZWFuKGFsbG93Q29kZUV4ZWN1dGlvbikpIHtcclxuICAgICAgcmV0dXJuIGRvU3RyYWlnaHRJbmplY3Qob3B0aW9ucywgZW5kQ2FsbGJhY2spO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gRG8gbm90IGFsbG93IHN0cmFpZ2h0IGluamVjdGlvbiB3aXRob3V0IHRoZSBhbGxvd0NvZGVFeGVjdXRpb24gZmxhZ1xyXG4gICAgICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICAgICAgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgJ1tjaGFydF0gT25seSBKU09OIGNvbmZpZ3VyYXRpb25zIGFuZCBTVkcgYXJlIGFsbG93ZWQgZm9yIHRoaXMgc2VydmVyLiBJZiB0aGlzIGlzIHlvdXIgc2VydmVyLCBKYXZhU2NyaXB0IGN1c3RvbSBjb2RlIGNhbiBiZSBlbmFibGVkIGJ5IHN0YXJ0aW5nIHRoZSBzZXJ2ZXIgd2l0aCB0aGUgLS1hbGxvd0NvZGVFeGVjdXRpb24gZmxhZy4nXHJcbiAgICAgICAgKS5zZXRFcnJvcihlcnJvcilcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIGFuZCByZXR1cm5zIHRoZSBjdXJyZW50IHN0YXR1cyBvZiBjb2RlIGV4ZWN1dGlvbiBwZXJtaXNzaW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7YW55fSBUaGUgdmFsdWUgb2YgYWxsb3dDb2RlRXhlY3V0aW9uLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldEFsbG93Q29kZUV4ZWN1dGlvbiA9ICgpID0+IGFsbG93Q29kZUV4ZWN1dGlvbjtcclxuXHJcbi8qKlxyXG4gKiBTZXRzIHRoZSBjb2RlIGV4ZWN1dGlvbiBwZXJtaXNzaW9uIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBib29sZWFuIHZhbHVlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge2FueX0gdmFsdWUgLSBUaGUgdmFsdWUgdG8gYmUgY29udmVydGVkIGFuZCBhc3NpZ25lZFxyXG4gKiB0byBhbGxvd0NvZGVFeGVjdXRpb24uXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2V0QWxsb3dDb2RlRXhlY3V0aW9uID0gKHZhbHVlKSA9PiB7XHJcbiAgYWxsb3dDb2RlRXhlY3V0aW9uID0gdG9Cb29sZWFuKHZhbHVlKTtcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBiYXRjaEV4cG9ydCxcclxuICBzaW5nbGVFeHBvcnQsXHJcbiAgZ2V0QWxsb3dDb2RlRXhlY3V0aW9uLFxyXG4gIHNldEFsbG93Q29kZUV4ZWN1dGlvbixcclxuICBzdGFydEV4cG9ydCxcclxuICBmaW5kQ2hhcnRTaXplXHJcbn07XHJcbiIsImltcG9ydCB7IGxvZ1dpdGhTdGFjayB9IGZyb20gJy4uL2xvZ2dlci5qcyc7XHJcblxyXG4vKipcclxuICogTWlkZGxld2FyZSBmb3IgbG9nZ2luZyBlcnJvcnMgd2l0aCBzdGFjayB0cmFjZSBhbmQgaGFuZGxpbmcgZXJyb3IgcmVzcG9uc2UuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXJyb3J9IGVycm9yIC0gVGhlIGVycm9yIG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcSAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlcyAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gbmV4dCAtIFRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXHJcbiAqL1xyXG5jb25zdCBsb2dFcnJvck1pZGRsZXdhcmUgPSAoZXJyb3IsIHJlcSwgcmVzLCBuZXh0KSA9PiB7XHJcbiAgLy8gRGlzcGxheSB0aGUgZXJyb3Igd2l0aCBzdGFjayBpbiBhIGNvcnJlY3QgZm9ybWF0XHJcbiAgbG9nV2l0aFN0YWNrKDEsIGVycm9yKTtcclxuXHJcbiAgLy8gRGVsZXRlIHRoZSBzdGFjayBmb3IgdGhlIGVudmlyb25tZW50IG90aGVyIHRoYW4gdGhlIGRldmVsb3BtZW50XHJcbiAgaWYgKHByb2Nlc3MuZW52Lk5PREVfRU5WICE9PSAnZGV2ZWxvcG1lbnQnKSB7XHJcbiAgICBkZWxldGUgZXJyb3Iuc3RhY2s7XHJcbiAgfVxyXG5cclxuICAvLyBDYWxsIHRoZSByZXR1cm5FcnJvck1pZGRsZXdhcmVcclxuICBuZXh0KGVycm9yKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBNaWRkbGV3YXJlIGZvciByZXR1cm5pbmcgZXJyb3IgcmVzcG9uc2UuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXJyb3J9IGVycm9yIC0gVGhlIGVycm9yIG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcSAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlcyAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gbmV4dCAtIFRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXHJcbiAqL1xyXG5jb25zdCByZXR1cm5FcnJvck1pZGRsZXdhcmUgPSAoZXJyb3IsIHJlcSwgcmVzLCBuZXh0KSA9PiB7XHJcbiAgLy8gR2F0aGVyIGFsbCByZXF1aWVkIGluZm9ybWF0aW9uIGZvciB0aGUgcmVzcG9uc2VcclxuICBjb25zdCB7IHN0YXR1c0NvZGU6IHN0Q29kZSwgc3RhdHVzLCBtZXNzYWdlLCBzdGFjayB9ID0gZXJyb3I7XHJcbiAgY29uc3Qgc3RhdHVzQ29kZSA9IHN0Q29kZSB8fCBzdGF0dXMgfHwgNTAwO1xyXG5cclxuICAvLyBTZXQgYW5kIHJldHVybiByZXNwb25zZVxyXG4gIHJlcy5zdGF0dXMoc3RhdHVzQ29kZSkuanNvbih7IHN0YXR1c0NvZGUsIG1lc3NhZ2UsIHN0YWNrIH0pO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQgKGFwcCkgPT4ge1xyXG4gIC8vIEFkZCBsb2cgZXJyb3IgbWlkZGxld2FyZVxyXG4gIGFwcC51c2UobG9nRXJyb3JNaWRkbGV3YXJlKTtcclxuXHJcbiAgLy8gQWRkIHNldCBzdGF0dXMgYW5kIHJldHVybiBlcnJvciBtaWRkbGV3YXJlXHJcbiAgYXBwLnVzZShyZXR1cm5FcnJvck1pZGRsZXdhcmUpO1xyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCByYXRlTGltaXQgZnJvbSAnZXhwcmVzcy1yYXRlLWxpbWl0JztcclxuXHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4uL2xvZ2dlci5qcyc7XHJcblxyXG4vKipcclxuICogTWlkZGxld2FyZSBmb3IgZW5hYmxpbmcgcmF0ZSBsaW1pdGluZyBvbiB0aGUgc3BlY2lmaWVkIEV4cHJlc3MgYXBwLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3N9IGFwcCAtIFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICogQHBhcmFtIHtPYmplY3R9IGxpbWl0Q29uZmlnIC0gQ29uZmlndXJhdGlvbiBvcHRpb25zIGZvciByYXRlIGxpbWl0aW5nLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgKGFwcCwgbGltaXRDb25maWcpID0+IHtcclxuICBjb25zdCBtc2cgPVxyXG4gICAgJ1RvbyBtYW55IHJlcXVlc3RzLCB5b3UgaGF2ZSBiZWVuIHJhdGUgbGltaXRlZC4gUGxlYXNlIHRyeSBhZ2FpbiBsYXRlci4nO1xyXG5cclxuICAvLyBPcHRpb25zIGZvciB0aGUgcmF0ZSBsaW1pdGVyXHJcbiAgY29uc3QgcmF0ZU9wdGlvbnMgPSB7XHJcbiAgICBtYXg6IGxpbWl0Q29uZmlnLm1heFJlcXVlc3RzIHx8IDMwLFxyXG4gICAgd2luZG93OiBsaW1pdENvbmZpZy53aW5kb3cgfHwgMSxcclxuICAgIGRlbGF5OiBsaW1pdENvbmZpZy5kZWxheSB8fCAwLFxyXG4gICAgdHJ1c3RQcm94eTogbGltaXRDb25maWcudHJ1c3RQcm94eSB8fCBmYWxzZSxcclxuICAgIHNraXBLZXk6IGxpbWl0Q29uZmlnLnNraXBLZXkgfHwgZmFsc2UsXHJcbiAgICBza2lwVG9rZW46IGxpbWl0Q29uZmlnLnNraXBUb2tlbiB8fCBmYWxzZVxyXG4gIH07XHJcblxyXG4gIC8vIFNldCBpZiBiZWhpbmQgYSBwcm94eVxyXG4gIGlmIChyYXRlT3B0aW9ucy50cnVzdFByb3h5KSB7XHJcbiAgICBhcHAuZW5hYmxlKCd0cnVzdCBwcm94eScpO1xyXG4gIH1cclxuXHJcbiAgLy8gQ3JlYXRlIGEgbGltaXRlclxyXG4gIGNvbnN0IGxpbWl0ZXIgPSByYXRlTGltaXQoe1xyXG4gICAgd2luZG93TXM6IHJhdGVPcHRpb25zLndpbmRvdyAqIDYwICogMTAwMCxcclxuICAgIC8vIExpbWl0IGVhY2ggSVAgdG8gMTAwIHJlcXVlc3RzIHBlciB3aW5kb3dNc1xyXG4gICAgbWF4OiByYXRlT3B0aW9ucy5tYXgsXHJcbiAgICAvLyBEaXNhYmxlIGRlbGF5aW5nLCBmdWxsIHNwZWVkIHVudGlsIHRoZSBtYXggbGltaXQgaXMgcmVhY2hlZFxyXG4gICAgZGVsYXlNczogcmF0ZU9wdGlvbnMuZGVsYXksXHJcbiAgICBoYW5kbGVyOiAocmVxdWVzdCwgcmVzcG9uc2UpID0+IHtcclxuICAgICAgcmVzcG9uc2UuZm9ybWF0KHtcclxuICAgICAgICBqc29uOiAoKSA9PiB7XHJcbiAgICAgICAgICByZXNwb25zZS5zdGF0dXMoNDI5KS5zZW5kKHsgbWVzc2FnZTogbXNnIH0pO1xyXG4gICAgICAgIH0sXHJcbiAgICAgICAgZGVmYXVsdDogKCkgPT4ge1xyXG4gICAgICAgICAgcmVzcG9uc2Uuc3RhdHVzKDQyOSkuc2VuZChtc2cpO1xyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcbiAgICB9LFxyXG4gICAgc2tpcDogKHJlcXVlc3QpID0+IHtcclxuICAgICAgLy8gQWxsb3cgYnlwYXNzaW5nIHRoZSBsaW1pdGVyIGlmIGEgdmFsaWQga2V5L3Rva2VuIGhhcyBiZWVuIHNlbnRcclxuICAgICAgaWYgKFxyXG4gICAgICAgIHJhdGVPcHRpb25zLnNraXBLZXkgIT09IGZhbHNlICYmXHJcbiAgICAgICAgcmF0ZU9wdGlvbnMuc2tpcFRva2VuICE9PSBmYWxzZSAmJlxyXG4gICAgICAgIHJlcXVlc3QucXVlcnkua2V5ID09PSByYXRlT3B0aW9ucy5za2lwS2V5ICYmXHJcbiAgICAgICAgcmVxdWVzdC5xdWVyeS5hY2Nlc3NfdG9rZW4gPT09IHJhdGVPcHRpb25zLnNraXBUb2tlblxyXG4gICAgICApIHtcclxuICAgICAgICBsb2coNCwgJ1tyYXRlIGxpbWl0aW5nXSBTa2lwcGluZyByYXRlIGxpbWl0ZXIuJyk7XHJcbiAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICAvLyBVc2UgYSBsaW1pdGVyIGFzIGEgbWlkZGxld2FyZVxyXG4gIGFwcC51c2UobGltaXRlcik7XHJcblxyXG4gIGxvZyhcclxuICAgIDMsXHJcbiAgICBgW3JhdGUgbGltaXRpbmddIEVuYWJsZWQgcmF0ZSBsaW1pdGluZyB3aXRoICR7cmF0ZU9wdGlvbnMubWF4fSByZXF1ZXN0cyBwZXIgJHtyYXRlT3B0aW9ucy53aW5kb3d9IG1pbnV0ZSBmb3IgZWFjaCBJUCwgdHJ1c3RpbmcgcHJveHk6ICR7cmF0ZU9wdGlvbnMudHJ1c3RQcm94eX0uYFxyXG4gICk7XHJcbn07XHJcbiIsImltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbmNsYXNzIEh0dHBFcnJvciBleHRlbmRzIEV4cG9ydEVycm9yIHtcclxuICBjb25zdHJ1Y3RvcihtZXNzYWdlLCBzdGF0dXMpIHtcclxuICAgIHN1cGVyKG1lc3NhZ2UpO1xyXG4gICAgdGhpcy5zdGF0dXMgPSB0aGlzLnN0YXR1c0NvZGUgPSBzdGF0dXM7XHJcbiAgfVxyXG5cclxuICBzZXRTdGF0dXMoc3RhdHVzKSB7XHJcbiAgICB0aGlzLnN0YXR1cyA9IHN0YXR1cztcclxuICAgIHJldHVybiB0aGlzO1xyXG4gIH1cclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQgSHR0cEVycm9yO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IHY0IGFzIHV1aWQgfSBmcm9tICd1dWlkJztcclxuXHJcbmltcG9ydCB7IGdldEFsbG93Q29kZUV4ZWN1dGlvbiwgc3RhcnRFeHBvcnQgfSBmcm9tICcuLi8uLi9jaGFydC5qcyc7XHJcbmltcG9ydCB7IGdldE9wdGlvbnMsIG1lcmdlQ29uZmlnT3B0aW9ucyB9IGZyb20gJy4uLy4uL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4uLy4uL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7XHJcbiAgZml4VHlwZSxcclxuICBpc0NvcnJlY3RKU09OLFxyXG4gIGlzT2JqZWN0RW1wdHksXHJcbiAgaXNQcml2YXRlUmFuZ2VVcmxGb3VuZCxcclxuICBvcHRpb25zU3RyaW5naWZ5LFxyXG4gIG1lYXN1cmVUaW1lXHJcbn0gZnJvbSAnLi4vLi4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IEh0dHBFcnJvciBmcm9tICcuLi8uLi9lcnJvcnMvSHR0cEVycm9yLmpzJztcclxuXHJcbi8vIFJldmVyc2VkIE1JTUUgdHlwZXNcclxuY29uc3QgcmV2ZXJzZWRNaW1lID0ge1xyXG4gIHBuZzogJ2ltYWdlL3BuZycsXHJcbiAganBlZzogJ2ltYWdlL2pwZWcnLFxyXG4gIGdpZjogJ2ltYWdlL2dpZicsXHJcbiAgcGRmOiAnYXBwbGljYXRpb24vcGRmJyxcclxuICBzdmc6ICdpbWFnZS9zdmcreG1sJ1xyXG59O1xyXG5cclxuLy8gVGhlIHJlcXVlc3RzIGNvdW50ZXJcclxubGV0IHJlcXVlc3RzQ291bnRlciA9IDA7XHJcblxyXG4vLyBUaGUgYXJyYXkgb2YgY2FsbGJhY2tzIHRvIGNhbGwgYmVmb3JlIGEgcmVxdWVzdFxyXG5jb25zdCBiZWZvcmVSZXF1ZXN0ID0gW107XHJcblxyXG4vLyBUaGUgYXJyYXkgb2YgY2FsbGJhY2tzIHRvIGNhbGwgYWZ0ZXIgYSByZXF1ZXN0XHJcbmNvbnN0IGFmdGVyUmVxdWVzdCA9IFtdO1xyXG5cclxuLyoqXHJcbiAqIEludm9rZXMgYW4gYXJyYXkgb2YgY2FsbGJhY2sgZnVuY3Rpb25zIHdpdGggc3BlY2lmaWVkIHBhcmFtZXRlcnMsIGFsbG93aW5nXHJcbiAqIGN1c3RvbWl6YXRpb24gb2YgcmVxdWVzdCBoYW5kbGluZy5cclxuICpcclxuICogQHBhcmFtIHtGdW5jdGlvbltdfSBjYWxsYmFja3MgLSBBbiBhcnJheSBvZiBjYWxsYmFjayBmdW5jdGlvbnNcclxuICogdG8gYmUgZXhlY3V0ZWQuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXF1ZXN0IC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzcG9uc2UgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBkYXRhIC0gQW4gb2JqZWN0IGNvbnRhaW5pbmcgcGFyYW1ldGVycyBsaWtlIGlkLCB1bmlxdWVJZCxcclxuICogdHlwZSwgYW5kIGJvZHkuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtib29sZWFufSAtIFJldHVybnMgYSBib29sZWFuIGluZGljYXRpbmcgdGhlIG92ZXJhbGwgcmVzdWx0XHJcbiAqIG9mIHRoZSBjYWxsYmFjayBpbnZvY2F0aW9ucy5cclxuICovXHJcbmNvbnN0IGRvQ2FsbGJhY2tzID0gKGNhbGxiYWNrcywgcmVxdWVzdCwgcmVzcG9uc2UsIGRhdGEpID0+IHtcclxuICBsZXQgcmVzdWx0ID0gdHJ1ZTtcclxuICBjb25zdCB7IGlkLCB1bmlxdWVJZCwgdHlwZSwgYm9keSB9ID0gZGF0YTtcclxuXHJcbiAgY2FsbGJhY2tzLnNvbWUoKGNhbGxiYWNrKSA9PiB7XHJcbiAgICBpZiAoY2FsbGJhY2spIHtcclxuICAgICAgbGV0IGNhbGxSZXNwb25zZSA9IGNhbGxiYWNrKHJlcXVlc3QsIHJlc3BvbnNlLCBpZCwgdW5pcXVlSWQsIHR5cGUsIGJvZHkpO1xyXG5cclxuICAgICAgaWYgKGNhbGxSZXNwb25zZSAhPT0gdW5kZWZpbmVkICYmIGNhbGxSZXNwb25zZSAhPT0gdHJ1ZSkge1xyXG4gICAgICAgIHJlc3VsdCA9IGNhbGxSZXNwb25zZTtcclxuICAgICAgfVxyXG5cclxuICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICB9XHJcbiAgfSk7XHJcblxyXG4gIHJldHVybiByZXN1bHQ7XHJcbn07XHJcblxyXG4vKipcclxuICogSGFuZGxlcyB0aGUgZXhwb3J0IHJlcXVlc3RzIGZyb20gdGhlIGNsaWVudC5cclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcXVlc3QgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXNwb25zZSAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gbmV4dCAtIFRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgdGhlIGV4cG9ydCBwcm9jZXNzXHJcbiAqIGlzIGNvbXBsZXRlLlxyXG4gKi9cclxuY29uc3QgZXhwb3J0SGFuZGxlciA9IGFzeW5jIChyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkgPT4ge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBTdGFydCBjb3VudGluZyB0aW1lXHJcbiAgICBjb25zdCBzdG9wQ291bnRlciA9IG1lYXN1cmVUaW1lKCk7XHJcblxyXG4gICAgLy8gQ3JlYXRlIGEgdW5pcXVlIElEIGZvciBhIHJlcXVlc3RcclxuICAgIGNvbnN0IHVuaXF1ZUlkID0gdXVpZCgpLnJlcGxhY2UoLy0vZywgJycpO1xyXG5cclxuICAgIC8vIEdldCB0aGUgY3VycmVudCBzZXJ2ZXIncyBnZW5lcmFsIG9wdGlvbnNcclxuICAgIGNvbnN0IGRlZmF1bHRPcHRpb25zID0gZ2V0T3B0aW9ucygpO1xyXG5cclxuICAgIGNvbnN0IGJvZHkgPSByZXF1ZXN0LmJvZHk7XHJcbiAgICBjb25zdCBpZCA9ICsrcmVxdWVzdHNDb3VudGVyO1xyXG5cclxuICAgIGxldCB0eXBlID0gZml4VHlwZShib2R5LnR5cGUpO1xyXG5cclxuICAgIC8vIFRocm93ICdCYWQgUmVxdWVzdCcgaWYgdGhlcmUncyBubyBib2R5XHJcbiAgICBpZiAoIWJvZHkgfHwgaXNPYmplY3RFbXB0eShib2R5KSkge1xyXG4gICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgICdUaGUgcmVxdWVzdCBib2R5IGlzIHJlcXVpcmVkLiBQbGVhc2UgZW5zdXJlIHRoYXQgeW91ciBDb250ZW50LVR5cGUgaGVhZGVyIGlzIGNvcnJlY3QgKGFjY2VwdGVkIHR5cGVzIGFyZSBhcHBsaWNhdGlvbi9qc29uIGFuZCBtdWx0aXBhcnQvZm9ybS1kYXRhKS4nLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEFsbCBvZiB0aGUgYmVsb3cgY2FuIGJlIHVzZWRcclxuICAgIGxldCBpbnN0ciA9IGlzQ29ycmVjdEpTT04oYm9keS5pbmZpbGUgfHwgYm9keS5vcHRpb25zIHx8IGJvZHkuZGF0YSk7XHJcblxyXG4gICAgLy8gVGhyb3cgJ0JhZCBSZXF1ZXN0JyBpZiB0aGVyZSdzIG5vIEpTT04gb3IgU1ZHIHRvIGV4cG9ydFxyXG4gICAgaWYgKCFpbnN0ciAmJiAhYm9keS5zdmcpIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDIsXHJcbiAgICAgICAgYFRoZSByZXF1ZXN0IHdpdGggSUQgJHt1bmlxdWVJZH0gZnJvbSAke1xyXG4gICAgICAgICAgcmVxdWVzdC5oZWFkZXJzWyd4LWZvcndhcmRlZC1mb3InXSB8fCByZXF1ZXN0LmNvbm5lY3Rpb24ucmVtb3RlQWRkcmVzc1xyXG4gICAgICAgIH0gd2FzIGluY29ycmVjdC4gUGF5bG9hZCByZWNlaXZlZDogJHtKU09OLnN0cmluZ2lmeShib2R5KX0uYFxyXG4gICAgICApO1xyXG5cclxuICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICBcIk5vIGNvcnJlY3QgY2hhcnQgZGF0YSBmb3VuZC4gRW5zdXJlIHRoYXQgeW91IGFyZSB1c2luZyBlaXRoZXIgYXBwbGljYXRpb24vanNvbiBvciBtdWx0aXBhcnQvZm9ybS1kYXRhIGhlYWRlcnMuIElmIHNlbmRpbmcgSlNPTiwgbWFrZSBzdXJlIHRoZSBjaGFydCBkYXRhIGlzIGluIHRoZSAnaW5maWxlJywgJ29wdGlvbnMnLCBvciAnZGF0YScgYXR0cmlidXRlLiBJZiBzZW5kaW5nIFNWRywgZW5zdXJlIGl0IGlzIGluIHRoZSAnc3ZnJyBhdHRyaWJ1dGUuXCIsXHJcbiAgICAgICAgNDAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgbGV0IGNhbGxSZXNwb25zZSA9IGZhbHNlO1xyXG5cclxuICAgIC8vIENhbGwgdGhlIGJlZm9yZSByZXF1ZXN0IGZ1bmN0aW9uc1xyXG4gICAgY2FsbFJlc3BvbnNlID0gZG9DYWxsYmFja3MoYmVmb3JlUmVxdWVzdCwgcmVxdWVzdCwgcmVzcG9uc2UsIHtcclxuICAgICAgaWQsXHJcbiAgICAgIHVuaXF1ZUlkLFxyXG4gICAgICB0eXBlLFxyXG4gICAgICBib2R5XHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBCbG9jayB0aGUgcmVxdWVzdCBpZiBvbmUgb2YgYSBjYWxsYmFja3MgZmFpbGVkXHJcbiAgICBpZiAoY2FsbFJlc3BvbnNlICE9PSB0cnVlKSB7XHJcbiAgICAgIHJldHVybiByZXNwb25zZS5zZW5kKGNhbGxSZXNwb25zZSk7XHJcbiAgICB9XHJcblxyXG4gICAgbGV0IGNvbm5lY3Rpb25BYm9ydGVkID0gZmFsc2U7XHJcblxyXG4gICAgLy8gSW4gY2FzZSB0aGUgY29ubmVjdGlvbiBpcyBjbG9zZWQsIGZvcmNlIHRvIGFib3J0IGZ1cnRoZXIgYWN0aW9uc1xyXG4gICAgcmVxdWVzdC5zb2NrZXQub24oJ2Nsb3NlJywgKCkgPT4ge1xyXG4gICAgICBjb25uZWN0aW9uQWJvcnRlZCA9IHRydWU7XHJcbiAgICB9KTtcclxuXHJcbiAgICBsb2coNCwgYFtleHBvcnRdIEdvdCBhbiBpbmNvbWluZyBIVFRQIHJlcXVlc3Qgd2l0aCBJRCAke3VuaXF1ZUlkfS5gKTtcclxuXHJcbiAgICBib2R5LmNvbnN0ciA9ICh0eXBlb2YgYm9keS5jb25zdHIgPT09ICdzdHJpbmcnICYmIGJvZHkuY29uc3RyKSB8fCAnY2hhcnQnO1xyXG5cclxuICAgIC8vIEdhdGhlciBhbmQgb3JnYW5pemUgb3B0aW9ucyBmcm9tIHRoZSBwYXlsb2FkXHJcbiAgICBjb25zdCByZXF1ZXN0T3B0aW9ucyA9IHtcclxuICAgICAgZXhwb3J0OiB7XHJcbiAgICAgICAgaW5zdHIsXHJcbiAgICAgICAgdHlwZSxcclxuICAgICAgICBjb25zdHI6IGJvZHkuY29uc3RyWzBdLnRvTG93ZXJDYXNlKCkgKyBib2R5LmNvbnN0ci5zdWJzdHIoMSksXHJcbiAgICAgICAgaGVpZ2h0OiBib2R5LmhlaWdodCxcclxuICAgICAgICB3aWR0aDogYm9keS53aWR0aCxcclxuICAgICAgICBzY2FsZTogYm9keS5zY2FsZSB8fCBkZWZhdWx0T3B0aW9ucy5leHBvcnQuc2NhbGUsXHJcbiAgICAgICAgZ2xvYmFsT3B0aW9uczogaXNDb3JyZWN0SlNPTihib2R5Lmdsb2JhbE9wdGlvbnMsIHRydWUpLFxyXG4gICAgICAgIHRoZW1lT3B0aW9uczogaXNDb3JyZWN0SlNPTihib2R5LnRoZW1lT3B0aW9ucywgdHJ1ZSlcclxuICAgICAgfSxcclxuICAgICAgY3VzdG9tTG9naWM6IHtcclxuICAgICAgICBhbGxvd0NvZGVFeGVjdXRpb246IGdldEFsbG93Q29kZUV4ZWN1dGlvbigpLFxyXG4gICAgICAgIGFsbG93RmlsZVJlc291cmNlczogZmFsc2UsXHJcbiAgICAgICAgcmVzb3VyY2VzOiBpc0NvcnJlY3RKU09OKGJvZHkucmVzb3VyY2VzLCB0cnVlKSxcclxuICAgICAgICBjYWxsYmFjazogYm9keS5jYWxsYmFjayxcclxuICAgICAgICBjdXN0b21Db2RlOiBib2R5LmN1c3RvbUNvZGVcclxuICAgICAgfVxyXG4gICAgfTtcclxuXHJcbiAgICBpZiAoaW5zdHIpIHtcclxuICAgICAgLy8gU3RyaW5naWZ5IEpTT04gd2l0aCBvcHRpb25zXHJcbiAgICAgIHJlcXVlc3RPcHRpb25zLmV4cG9ydC5pbnN0ciA9IG9wdGlvbnNTdHJpbmdpZnkoXHJcbiAgICAgICAgaW5zdHIsXHJcbiAgICAgICAgcmVxdWVzdE9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTWVyZ2UgdGhlIHJlcXVlc3Qgb3B0aW9ucyBpbnRvIGRlZmF1bHQgb25lc1xyXG4gICAgY29uc3Qgb3B0aW9ucyA9IG1lcmdlQ29uZmlnT3B0aW9ucyhkZWZhdWx0T3B0aW9ucywgcmVxdWVzdE9wdGlvbnMpO1xyXG5cclxuICAgIC8vIFNhdmUgdGhlIEpTT04gaWYgZXhpc3RzXHJcbiAgICBvcHRpb25zLmV4cG9ydC5vcHRpb25zID0gaW5zdHI7XHJcblxyXG4gICAgLy8gTGFzdGx5LCBhZGQgdGhlIHNlcnZlciBzcGVjaWZpYyBhcmd1bWVudHMgaW50byBvcHRpb25zIGFzIHBheWxvYWRcclxuICAgIG9wdGlvbnMucGF5bG9hZCA9IHtcclxuICAgICAgc3ZnOiBib2R5LnN2ZyB8fCBmYWxzZSxcclxuICAgICAgYjY0OiBib2R5LmI2NCB8fCBmYWxzZSxcclxuICAgICAgbm9Eb3dubG9hZDogYm9keS5ub0Rvd25sb2FkIHx8IGZhbHNlLFxyXG4gICAgICByZXF1ZXN0SWQ6IHVuaXF1ZUlkXHJcbiAgICB9O1xyXG5cclxuICAgIC8vIFRlc3QgeGxpbms6aHJlZiBlbGVtZW50cyBmcm9tIHBheWxvYWQncyBTVkdcclxuICAgIGlmIChib2R5LnN2ZyAmJiBpc1ByaXZhdGVSYW5nZVVybEZvdW5kKG9wdGlvbnMucGF5bG9hZC5zdmcpKSB7XHJcbiAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgJ1NWRyBwb3RlbnRpYWxseSBjb250YWluIGF0IGxlYXN0IG9uZSBmb3JiaWRkZW4gVVJMIGluIHhsaW5rOmhyZWYgZWxlbWVudC4gUGxlYXNlIHJldmlldyB0aGUgU1ZHIGNvbnRlbnQgYW5kIGVuc3VyZSB0aGF0IGFsbCByZWZlcmVuY2VkIFVSTHMgY29tcGx5IHdpdGggc2VjdXJpdHkgcG9saWNpZXMuJyxcclxuICAgICAgICA0MDBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBTdGFydCB0aGUgZXhwb3J0IHByb2Nlc3NcclxuICAgIGF3YWl0IHN0YXJ0RXhwb3J0KG9wdGlvbnMsIChlcnJvciwgaW5mbykgPT4ge1xyXG4gICAgICAvLyBSZW1vdmUgdGhlIGNsb3NlIGV2ZW50IGZyb20gdGhlIHNvY2tldFxyXG4gICAgICByZXF1ZXN0LnNvY2tldC5yZW1vdmVBbGxMaXN0ZW5lcnMoJ2Nsb3NlJyk7XHJcblxyXG4gICAgICAvLyBBZnRlciB0aGUgd2hvbGUgZXhwb3J0aW5nIHByb2Nlc3NcclxuICAgICAgaWYgKGRlZmF1bHRPcHRpb25zLnNlcnZlci5iZW5jaG1hcmtpbmcpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICA1LFxyXG4gICAgICAgICAgYFtiZW5jaG1hcmtdIFJlcXVlc3Qgd2l0aCBJRCAke3VuaXF1ZUlkfSAtIEFmdGVyIHRoZSB3aG9sZSBleHBvcnRpbmcgcHJvY2VzczogJHtzdG9wQ291bnRlcigpfW1zLmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBJZiB0aGUgY29ubmVjdGlvbiB3YXMgY2xvc2VkLCBkbyBub3RoaW5nXHJcbiAgICAgIGlmIChjb25uZWN0aW9uQWJvcnRlZCkge1xyXG4gICAgICAgIHJldHVybiBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtleHBvcnRdIFRoZSBjbGllbnQgY2xvc2VkIHRoZSBjb25uZWN0aW9uIGJlZm9yZSB0aGUgY2hhcnQgZmluaXNoZWQgcHJvY2Vzc2luZy5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgZXJyb3IsIGxvZyBpdCBhbmQgc2VuZCBpdCB0byB0aGUgZXJyb3IgbWlkZGxld2FyZVxyXG4gICAgICBpZiAoZXJyb3IpIHtcclxuICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgZGF0YSBpcyBtaXNzaW5nLCBsb2cgdGhlIG1lc3NhZ2UgYW5kIHNlbmQgaXQgdG8gdGhlIGVycm9yIG1pZGRsZXdhcmVcclxuICAgICAgaWYgKCFpbmZvIHx8ICFpbmZvLnJlc3VsdCkge1xyXG4gICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgICBgVW5leHBlY3RlZCByZXR1cm4gZnJvbSBjaGFydCBnZW5lcmF0aW9uLiBQbGVhc2UgY2hlY2sgeW91ciByZXF1ZXN0IGRhdGEuIEZvciB0aGUgcmVxdWVzdCB3aXRoIElEICR7dW5pcXVlSWR9LCB0aGUgcmVzdWx0IGlzICR7aW5mby5yZXN1bHR9LmAsXHJcbiAgICAgICAgICA0MDBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBHZXQgdGhlIHR5cGUgZnJvbSBvcHRpb25zXHJcbiAgICAgIHR5cGUgPSBpbmZvLm9wdGlvbnMuZXhwb3J0LnR5cGU7XHJcblxyXG4gICAgICAvLyBUaGUgYWZ0ZXIgcmVxdWVzdCBjYWxsYmFja3NcclxuICAgICAgZG9DYWxsYmFja3MoYWZ0ZXJSZXF1ZXN0LCByZXF1ZXN0LCByZXNwb25zZSwgeyBpZCwgYm9keTogaW5mby5yZXN1bHQgfSk7XHJcblxyXG4gICAgICBpZiAoaW5mby5yZXN1bHQpIHtcclxuICAgICAgICAvLyBJZiBvbmx5IGJhc2U2NCBpcyByZXF1aXJlZCwgcmV0dXJuIGl0XHJcbiAgICAgICAgaWYgKGJvZHkuYjY0KSB7XHJcbiAgICAgICAgICAvLyBTVkcgRXhjZXB0aW9uIGZvciB0aGUgSGlnaGNoYXJ0cyAxMS4zLjAgdmVyc2lvblxyXG4gICAgICAgICAgaWYgKHR5cGUgPT09ICdwZGYnIHx8IHR5cGUgPT0gJ3N2ZycpIHtcclxuICAgICAgICAgICAgcmV0dXJuIHJlc3BvbnNlLnNlbmQoXHJcbiAgICAgICAgICAgICAgQnVmZmVyLmZyb20oaW5mby5yZXN1bHQsICd1dGY4JykudG9TdHJpbmcoJ2Jhc2U2NCcpXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgcmV0dXJuIHJlc3BvbnNlLnNlbmQoaW5mby5yZXN1bHQpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gU2V0IGNvcnJlY3QgY29udGVudCB0eXBlXHJcbiAgICAgICAgcmVzcG9uc2UuaGVhZGVyKCdDb250ZW50LVR5cGUnLCByZXZlcnNlZE1pbWVbdHlwZV0gfHwgJ2ltYWdlL3BuZycpO1xyXG5cclxuICAgICAgICAvLyBEZWNpZGUgd2hldGhlciB0byBkb3dubG9hZCBvciBub3QgY2hhcnQgZmlsZVxyXG4gICAgICAgIGlmICghYm9keS5ub0Rvd25sb2FkKSB7XHJcbiAgICAgICAgICByZXNwb25zZS5hdHRhY2htZW50KFxyXG4gICAgICAgICAgICBgJHtyZXF1ZXN0LnBhcmFtcy5maWxlbmFtZSB8fCByZXF1ZXN0LmJvZHkuZmlsZW5hbWUgfHwgJ2NoYXJ0J30uJHtcclxuICAgICAgICAgICAgICB0eXBlIHx8ICdwbmcnXHJcbiAgICAgICAgICAgIH1gXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gSWYgU1ZHLCByZXR1cm4gcGxhaW4gY29udGVudFxyXG4gICAgICAgIHJldHVybiB0eXBlID09PSAnc3ZnJ1xyXG4gICAgICAgICAgPyByZXNwb25zZS5zZW5kKGluZm8ucmVzdWx0KVxyXG4gICAgICAgICAgOiByZXNwb25zZS5zZW5kKEJ1ZmZlci5mcm9tKGluZm8ucmVzdWx0LCAnYmFzZTY0JykpO1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgbmV4dChlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQgKGFwcCkgPT4ge1xyXG4gIC8qKlxyXG4gICAqIEFkZHMgdGhlIFBPU1QgLyBhIHJvdXRlIGZvciBoYW5kbGluZyBQT1NUIHJlcXVlc3RzIGF0IHRoZSByb290IGVuZHBvaW50LlxyXG4gICAqL1xyXG4gIGFwcC5wb3N0KCcvJywgZXhwb3J0SGFuZGxlcik7XHJcblxyXG4gIC8qKlxyXG4gICAqIEFkZHMgdGhlIFBPU1QgLzpmaWxlbmFtZSBhIHJvdXRlIGZvciBoYW5kbGluZyBQT1NUIHJlcXVlc3RzIHdpdGhcclxuICAgKiBhIHNwZWNpZmllZCBmaWxlbmFtZSBwYXJhbWV0ZXIuXHJcbiAgICovXHJcbiAgYXBwLnBvc3QoJy86ZmlsZW5hbWUnLCBleHBvcnRIYW5kbGVyKTtcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IGpvaW4gYXMgcGF0aGVyIH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgY2FjaGUgZnJvbSAnLi4vLi4vY2FjaGUuanMnO1xyXG5pbXBvcnQgcG9vbCBmcm9tICcuLi8uLi9wb29sLmpzJztcclxuaW1wb3J0IHsgX19kaXJuYW1lIH0gZnJvbSAnLi4vLi4vdXRpbHMuanMnO1xyXG5cclxuY29uc3QgcGtnRmlsZSA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKHBhdGhlcihfX2Rpcm5hbWUsICdwYWNrYWdlLmpzb24nKSkpO1xyXG5cclxuY29uc3Qgc2VydmVyU3RhcnRUaW1lID0gbmV3IERhdGUoKTtcclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSBHRVQgL2hlYWx0aCByb3V0ZSwgd2hpY2ggb3V0cHV0cyBiYXNpYyBzdGF0cyBmb3IgdGhlIHNlcnZlci5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IChhcHApID0+XHJcbiAgIWFwcFxyXG4gICAgPyBmYWxzZVxyXG4gICAgOiBhcHAuZ2V0KCcvaGVhbHRoJywgKHJlcXVlc3QsIHJlc3BvbnNlKSA9PiB7XHJcbiAgICAgICAgcmVzcG9uc2Uuc2VuZCh7XHJcbiAgICAgICAgICBzdGF0dXM6ICdPSycsXHJcbiAgICAgICAgICBib290VGltZTogc2VydmVyU3RhcnRUaW1lLFxyXG4gICAgICAgICAgdXB0aW1lOlxyXG4gICAgICAgICAgICBNYXRoLmZsb29yKFxyXG4gICAgICAgICAgICAgIChuZXcgRGF0ZSgpLmdldFRpbWUoKSAtIHNlcnZlclN0YXJ0VGltZS5nZXRUaW1lKCkpIC8gMTAwMCAvIDYwXHJcbiAgICAgICAgICAgICkgKyAnIG1pbnV0ZXMnLFxyXG4gICAgICAgICAgdmVyc2lvbjogcGtnRmlsZS52ZXJzaW9uLFxyXG4gICAgICAgICAgaGlnaGNoYXJ0c1ZlcnNpb246IGNhY2hlLnZlcnNpb24oKSxcclxuICAgICAgICAgIGF2ZXJhZ2VQcm9jZXNzaW5nVGltZTogcG9vbC5hdmVyYWdlVGltZSgpLFxyXG4gICAgICAgICAgcGVyZm9ybWVkRXhwb3J0czogcG9vbC5wcm9jZXNzZWRXb3JrQ291bnQoKSxcclxuICAgICAgICAgIGZhaWxlZEV4cG9ydHM6IHBvb2wuZHJvcHBlZFdvcmsoKSxcclxuICAgICAgICAgIGV4cG9ydEF0dGVtcHRzOiBwb29sLndvcmtBdHRlbXB0cygpLFxyXG4gICAgICAgICAgc3VjZXNzUmF0aW86IChwb29sLnByb2Nlc3NlZFdvcmtDb3VudCgpIC8gcG9vbC53b3JrQXR0ZW1wdHMoKSkgKiAxMDAsXHJcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgaW1wb3J0L25vLW5hbWVkLWFzLWRlZmF1bHQtbWVtYmVyXHJcbiAgICAgICAgICBwb29sOiBwb29sLmdldFBvb2xJbmZvSlNPTigpXHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH0pO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IHByb21pc2VzIGFzIGZzUHJvbWlzZXMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IHBvc2l4IH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgY29ycyBmcm9tICdjb3JzJztcclxuaW1wb3J0IGV4cHJlc3MgZnJvbSAnZXhwcmVzcyc7XHJcbmltcG9ydCBodHRwIGZyb20gJ2h0dHAnO1xyXG5pbXBvcnQgaHR0cHMgZnJvbSAnaHR0cHMnO1xyXG5pbXBvcnQgbXVsdGVyIGZyb20gJ211bHRlcic7XHJcblxyXG5pbXBvcnQgZXJyb3JIYW5kbGVyIGZyb20gJy4vZXJyb3IuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4uL2xvZ2dlci5qcyc7XHJcbmltcG9ydCByYXRlTGltaXQgZnJvbSAnLi9yYXRlX2xpbWl0LmpzJztcclxuaW1wb3J0IHsgX19kaXJuYW1lIH0gZnJvbSAnLi4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IHZTd2l0Y2hSb3V0ZSBmcm9tICcuL3JvdXRlcy9jaGFuZ2VfaGNfdmVyc2lvbi5qcyc7XHJcbmltcG9ydCBleHBvcnRSb3V0ZXMgZnJvbSAnLi9yb3V0ZXMvZXhwb3J0LmpzJztcclxuaW1wb3J0IGhlYWx0aFJvdXRlIGZyb20gJy4vcm91dGVzL2hlYWx0aC5qcyc7XHJcbmltcG9ydCB1aVJvdXRlIGZyb20gJy4vcm91dGVzL3VpLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLy8gQ3JlYXRlIGV4cHJlc3MgYXBwXHJcbmNvbnN0IGFwcCA9IGV4cHJlc3MoKTtcclxuXHJcbi8vIERpc2FibGUgdGhlIFgtUG93ZXJlZC1CeSBoZWFkZXJcclxuYXBwLmRpc2FibGUoJ3gtcG93ZXJlZC1ieScpO1xyXG5cclxuLy8gRW5hYmxlIENPUlMgc3VwcG9ydFxyXG5hcHAudXNlKGNvcnMoKSk7XHJcblxyXG4vLyBFbmFibGUgcGFyc2luZyBvZiBmb3JtIGRhdGEgKGZpbGVzKSB3aXRoIE11bHRlciBwYWNrYWdlXHJcbmNvbnN0IHN0b3JhZ2UgPSBtdWx0ZXIubWVtb3J5U3RvcmFnZSgpO1xyXG5jb25zdCB1cGxvYWQgPSBtdWx0ZXIoe1xyXG4gIHN0b3JhZ2UsXHJcbiAgbGltaXRzOiB7XHJcbiAgICBmaWVsZFNpemU6IDUwICogMTAyNCAqIDEwMjRcclxuICB9XHJcbn0pO1xyXG5cclxuLy8gRW5hYmxlIGJvZHkgcGFyc2VyXHJcbmFwcC51c2UoZXhwcmVzcy5qc29uKHsgbGltaXQ6IDUwICogMTAyNCAqIDEwMjQgfSkpO1xyXG5hcHAudXNlKGV4cHJlc3MudXJsZW5jb2RlZCh7IGV4dGVuZGVkOiB0cnVlLCBsaW1pdDogNTAgKiAxMDI0ICogMTAyNCB9KSk7XHJcblxyXG4vLyBVc2Ugb25seSBub24tZmlsZSBtdWx0aXBhcnQgZm9ybSBmaWVsZHNcclxuYXBwLnVzZSh1cGxvYWQubm9uZSgpKTtcclxuXHJcbi8qKlxyXG4gKiBBdHRhY2ggZXJyb3IgaGFuZGxlcnMgdG8gdGhlIHNlcnZlci5cclxuICpcclxuICogQHBhcmFtIHtodHRwLlNlcnZlcn0gc2VydmVyIC0gVGhlIEhUVFAvSFRUUFMgc2VydmVyIGluc3RhbmNlLlxyXG4gKi9cclxuY29uc3QgYXR0YWNoRXJyb3JIYW5kbGVycyA9IChzZXJ2ZXIpID0+IHtcclxuICBzZXJ2ZXIub24oJ2NsaWVudEVycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICBsb2dXaXRoU3RhY2soMSwgZXJyb3IsIGBbc2VydmVyXSBDbGllbnQgZXJyb3I6ICR7ZXJyb3IubWVzc2FnZX1gKTtcclxuICB9KTtcclxuICBzZXJ2ZXIub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICBsb2dXaXRoU3RhY2soMSwgZXJyb3IsIGBbc2VydmVyXSBTZXJ2ZXIgZXJyb3I6ICR7ZXJyb3IubWVzc2FnZX1gKTtcclxuICB9KTtcclxuICBzZXJ2ZXIub24oJ2Nvbm5lY3Rpb24nLCAoc29ja2V0KSA9PiB7XHJcbiAgICBzb2NrZXQub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFtzZXJ2ZXJdIFNvY2tldCBlcnJvcjogJHtlcnJvci5tZXNzYWdlfWApO1xyXG4gICAgfSk7XHJcbiAgfSk7XHJcbn07XHJcblxyXG4vKipcclxuICogU3RhcnRzIGFuIEhUVFAgc2VydmVyIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uLiBUaGUgYHNlcnZlckNvbmZpZ2BcclxuICogb2JqZWN0IGNvbnRhaW5zIGFsbCBzZXJ2ZXIgcmVsYXRlZCBwcm9wZXJ0aWVzIChzZWUgdGhlIGBzZXJ2ZXJgIHNlY3Rpb25cclxuICogaW4gdGhlIGBsaWIvc2NoZW1hcy9jb25maWcuanNgIGZpbGUgZm9yIGEgcmVmZXJlbmNlKS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHNlcnZlckNvbmZpZyAtIFRoZSBzZXJ2ZXIgY29uZmlndXJhdGlvbiBvYmplY3QuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSAtIFRocm93cyBhbiBlcnJvciBpZiB0aGUgc2VydmVyIGNhbm5vdCBiZSBjb25maWd1cmVkXHJcbiAqIGFuZCBzdGFydGVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHN0YXJ0U2VydmVyID0gYXN5bmMgKHNlcnZlckNvbmZpZykgPT4ge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBTdG9wIGlmIG5vdCBlbmFibGVkXHJcbiAgICBpZiAoIXNlcnZlckNvbmZpZy5lbmFibGUpIHtcclxuICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIExpc3RlbiBIVFRQIHNlcnZlclxyXG4gICAgaWYgKCFzZXJ2ZXJDb25maWcuc3NsLmZvcmNlKSB7XHJcbiAgICAgIC8vIE1haW4gc2VydmVyIGluc3RhbmNlIChIVFRQKVxyXG4gICAgICBjb25zdCBodHRwU2VydmVyID0gaHR0cC5jcmVhdGVTZXJ2ZXIoYXBwKTtcclxuXHJcbiAgICAgIC8vIEF0dGFjaCBlcnJvciBoYW5kbGVycyBhbmQgbGlzdGVuIHRvIHRoZSBzZXJ2ZXJcclxuICAgICAgYXR0YWNoRXJyb3JIYW5kbGVycyhodHRwU2VydmVyKTtcclxuXHJcbiAgICAgIC8vIExpc3RlblxyXG4gICAgICBodHRwU2VydmVyLmxpc3RlbihzZXJ2ZXJDb25maWcucG9ydCwgc2VydmVyQ29uZmlnLmhvc3QpO1xyXG5cclxuICAgICAgbG9nKFxyXG4gICAgICAgIDMsXHJcbiAgICAgICAgYFtzZXJ2ZXJdIFN0YXJ0ZWQgSFRUUCBzZXJ2ZXIgb24gJHtzZXJ2ZXJDb25maWcuaG9zdH06JHtzZXJ2ZXJDb25maWcucG9ydH0uYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIExpc3RlbiBIVFRQUyBzZXJ2ZXJcclxuICAgIGlmIChzZXJ2ZXJDb25maWcuc3NsLmVuYWJsZSkge1xyXG4gICAgICAvLyBTZXQgdXAgYW4gU1NMIHNlcnZlciBhbHNvXHJcbiAgICAgIGxldCBrZXksIGNlcnQ7XHJcblxyXG4gICAgICB0cnkge1xyXG4gICAgICAgIC8vIEdldCB0aGUgU1NMIGtleVxyXG4gICAgICAgIGtleSA9IGF3YWl0IGZzUHJvbWlzZXMucmVhZEZpbGUoXHJcbiAgICAgICAgICBwb3NpeC5qb2luKHNlcnZlckNvbmZpZy5zc2wuY2VydFBhdGgsICdzZXJ2ZXIua2V5JyksXHJcbiAgICAgICAgICAndXRmOCdcclxuICAgICAgICApO1xyXG5cclxuICAgICAgICAvLyBHZXQgdGhlIFNTTCBjZXJ0aWZpY2F0ZVxyXG4gICAgICAgIGNlcnQgPSBhd2FpdCBmc1Byb21pc2VzLnJlYWRGaWxlKFxyXG4gICAgICAgICAgcG9zaXguam9pbihzZXJ2ZXJDb25maWcuc3NsLmNlcnRQYXRoLCAnc2VydmVyLmNydCcpLFxyXG4gICAgICAgICAgJ3V0ZjgnXHJcbiAgICAgICAgKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAyLFxyXG4gICAgICAgICAgYFtzZXJ2ZXJdIFVuYWJsZSB0byBsb2FkIGtleS9jZXJ0aWZpY2F0ZSBmcm9tIHRoZSAnJHtzZXJ2ZXJDb25maWcuc3NsLmNlcnRQYXRofScgcGF0aC4gQ291bGQgbm90IHJ1biBzZWN1cmVkIGxheWVyIHNlcnZlci5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKGtleSAmJiBjZXJ0KSB7XHJcbiAgICAgICAgLy8gTWFpbiBzZXJ2ZXIgaW5zdGFuY2UgKEhUVFBTKVxyXG4gICAgICAgIGNvbnN0IGh0dHBzU2VydmVyID0gaHR0cHMuY3JlYXRlU2VydmVyKHsga2V5LCBjZXJ0IH0sIGFwcCk7XHJcblxyXG4gICAgICAgIC8vIEF0dGFjaCBlcnJvciBoYW5kbGVycyBhbmQgbGlzdGVuIHRvIHRoZSBzZXJ2ZXJcclxuICAgICAgICBhdHRhY2hFcnJvckhhbmRsZXJzKGh0dHBzU2VydmVyKTtcclxuXHJcbiAgICAgICAgLy8gTGlzdGVuXHJcbiAgICAgICAgaHR0cHNTZXJ2ZXIubGlzdGVuKHNlcnZlckNvbmZpZy5zc2wucG9ydCwgc2VydmVyQ29uZmlnLmhvc3QpO1xyXG5cclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtzZXJ2ZXJdIFN0YXJ0ZWQgSFRUUFMgc2VydmVyIG9uICR7c2VydmVyQ29uZmlnLmhvc3R9OiR7c2VydmVyQ29uZmlnLnNzbC5wb3J0fS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIEVuYWJsZSB0aGUgcmF0ZSBsaW1pdGVyIGlmIGNvbmZpZyBzYXlzIHNvXHJcbiAgICBpZiAoXHJcbiAgICAgIHNlcnZlckNvbmZpZy5yYXRlTGltaXRpbmcgJiZcclxuICAgICAgc2VydmVyQ29uZmlnLnJhdGVMaW1pdGluZy5lbmFibGUgJiZcclxuICAgICAgIVswLCBOYU5dLmluY2x1ZGVzKHNlcnZlckNvbmZpZy5yYXRlTGltaXRpbmcubWF4UmVxdWVzdHMpXHJcbiAgICApIHtcclxuICAgICAgcmF0ZUxpbWl0KGFwcCwgc2VydmVyQ29uZmlnLnJhdGVMaW1pdGluZyk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU2V0IHVwIHN0YXRpYyBmb2xkZXIncyByb3V0ZVxyXG4gICAgYXBwLnVzZShleHByZXNzLnN0YXRpYyhwb3NpeC5qb2luKF9fZGlybmFtZSwgJ3B1YmxpYycpKSk7XHJcblxyXG4gICAgLy8gU2V0IHVwIHJvdXRlc1xyXG4gICAgaGVhbHRoUm91dGUoYXBwKTtcclxuICAgIGV4cG9ydFJvdXRlcyhhcHApO1xyXG4gICAgdWlSb3V0ZShhcHApO1xyXG4gICAgdlN3aXRjaFJvdXRlKGFwcCk7XHJcblxyXG4gICAgLy8gU2V0IHVwIGNlbnRyYWxpemVkIGVycm9yIGhhbmRsZXJcclxuICAgIGVycm9ySGFuZGxlcihhcHApO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbc2VydmVyXSBDb3VsZCBub3QgY29uZmlndXJlIGFuZCBzdGFydCB0aGUgc2VydmVyLidcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBFbmFibGUgcmF0ZSBsaW1pdGluZyBmb3IgdGhlIHNlcnZlci5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGxpbWl0Q29uZmlnIC0gQ29uZmlndXJhdGlvbiBvYmplY3QgZm9yIHJhdGUgbGltaXRpbmcuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZW5hYmxlUmF0ZUxpbWl0aW5nID0gKGxpbWl0Q29uZmlnKSA9PiByYXRlTGltaXQoYXBwLCBsaW1pdENvbmZpZyk7XHJcblxyXG4vKipcclxuICogR2V0IHRoZSBFeHByZXNzIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSAtIFRoZSBFeHByZXNzIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldEV4cHJlc3MgPSAoKSA9PiBleHByZXNzO1xyXG5cclxuLyoqXHJcbiAqIEdldCB0aGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IC0gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldEFwcCA9ICgpID0+IGFwcDtcclxuXHJcbi8qKlxyXG4gKiBBcHBseSBtaWRkbGV3YXJlKHMpIHRvIGEgc3BlY2lmaWMgcGF0aC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBUaGUgcGF0aCB0byB3aGljaCB0aGUgbWlkZGxld2FyZShzKSBzaG91bGQgYmUgYXBwbGllZC5cclxuICogQHBhcmFtIHsuLi5GdW5jdGlvbn0gbWlkZGxld2FyZXMgLSBUaGUgbWlkZGxld2FyZSBmdW5jdGlvbnMgdG8gYmUgYXBwbGllZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCB1c2UgPSAocGF0aCwgLi4ubWlkZGxld2FyZXMpID0+IHtcclxuICBhcHAudXNlKHBhdGgsIC4uLm1pZGRsZXdhcmVzKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBTZXQgdXAgYSByb3V0ZSB3aXRoIEdFVCBtZXRob2QgYW5kIGFwcGx5IG1pZGRsZXdhcmUocykuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIC0gVGhlIHJvdXRlIHBhdGguXHJcbiAqIEBwYXJhbSB7Li4uRnVuY3Rpb259IG1pZGRsZXdhcmVzIC0gVGhlIG1pZGRsZXdhcmUgZnVuY3Rpb25zIHRvIGJlIGFwcGxpZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0ID0gKHBhdGgsIC4uLm1pZGRsZXdhcmVzKSA9PiB7XHJcbiAgYXBwLmdldChwYXRoLCAuLi5taWRkbGV3YXJlcyk7XHJcbn07XHJcblxyXG4vKipcclxuICogU2V0IHVwIGEgcm91dGUgd2l0aCBQT1NUIG1ldGhvZCBhbmQgYXBwbHkgbWlkZGxld2FyZShzKS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBUaGUgcm91dGUgcGF0aC5cclxuICogQHBhcmFtIHsuLi5GdW5jdGlvbn0gbWlkZGxld2FyZXMgLSBUaGUgbWlkZGxld2FyZSBmdW5jdGlvbnMgdG8gYmUgYXBwbGllZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBwb3N0ID0gKHBhdGgsIC4uLm1pZGRsZXdhcmVzKSA9PiB7XHJcbiAgYXBwLnBvc3QocGF0aCwgLi4ubWlkZGxld2FyZXMpO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIHN0YXJ0U2VydmVyLFxyXG4gIGVuYWJsZVJhdGVMaW1pdGluZyxcclxuICBnZXRFeHByZXNzLFxyXG4gIGdldEFwcCxcclxuICB1c2UsXHJcbiAgZ2V0LFxyXG4gIHBvc3RcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgeyBfX2Rpcm5hbWUgfSBmcm9tICcuLi8uLi91dGlscy5qcyc7XHJcblxyXG4vKipcclxuICogQWRkcyB0aGUgR0VUIC8gcm91dGUgZm9yIGEgVUkgd2hlbiBlbmFibGVkIG9uIHRoZSBleHBvcnQgc2VydmVyLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgKGFwcCkgPT5cclxuICAhYXBwXHJcbiAgICA/IGZhbHNlXHJcbiAgICA6IGFwcC5nZXQoJy8nLCAocmVxdWVzdCwgcmVzcG9uc2UpID0+IHtcclxuICAgICAgICByZXNwb25zZS5zZW5kRmlsZShqb2luKF9fZGlybmFtZSwgJ3B1YmxpYycsICdpbmRleC5odG1sJykpO1xyXG4gICAgICB9KTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgY2FjaGUgZnJvbSAnLi4vLi4vY2FjaGUuanMnO1xyXG5cclxuaW1wb3J0IEh0dHBFcnJvciBmcm9tICcuLi8uLi9lcnJvcnMvSHR0cEVycm9yLmpzJztcclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSBQT1NUIC9jaGFuZ2VfaGNfdmVyc2lvbi86bmV3VmVyc2lvbiByb3V0ZSB0aGF0IGNhbiBiZSB1dGlsaXplZCB0byBtb2RpZnlcclxuICogdGhlIEhpZ2hjaGFydHMgdmVyc2lvbiBvbiB0aGUgc2VydmVyLlxyXG4gKlxyXG4gKiBUT0RPOiBBZGQgYXV0aCB0b2tlbiBhbmQgY29ubmVjdCB0byBBUElcclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IChhcHApID0+XHJcbiAgIWFwcFxyXG4gICAgPyBmYWxzZVxyXG4gICAgOiBhcHAucG9zdChcclxuICAgICAgICAnL3ZlcnNpb24vY2hhbmdlLzpuZXdWZXJzaW9uJyxcclxuICAgICAgICBhc3luYyAocmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpID0+IHtcclxuICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgIGNvbnN0IGFkbWluVG9rZW4gPSBwcm9jZXNzLmVudi5ISUdIQ0hBUlRTX0FETUlOX1RPS0VOO1xyXG5cclxuICAgICAgICAgICAgLy8gQ2hlY2sgdGhlIGV4aXN0ZW5jZSBvZiB0aGUgdG9rZW5cclxuICAgICAgICAgICAgaWYgKCFhZG1pblRva2VuIHx8ICFhZG1pblRva2VuLmxlbmd0aCkge1xyXG4gICAgICAgICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgICAgICAgICAnVGhlIHNlcnZlciBpcyBub3QgY29uZmlndXJlZCB0byBwZXJmb3JtIHJ1bi10aW1lIHZlcnNpb24gY2hhbmdlczogSElHSENIQVJUU19BRE1JTl9UT0tFTiBpcyBub3Qgc2V0LicsXHJcbiAgICAgICAgICAgICAgICA0MDFcclxuICAgICAgICAgICAgICApO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAvLyBDaGVjayBpZiB0aGUgaGMtYXV0aCBoZWFkZXIgY29udGFpbiBhIGNvcnJlY3QgdG9rZW5cclxuICAgICAgICAgICAgY29uc3QgdG9rZW4gPSByZXF1ZXN0LmdldCgnaGMtYXV0aCcpO1xyXG4gICAgICAgICAgICBpZiAoIXRva2VuIHx8IHRva2VuICE9PSBhZG1pblRva2VuKSB7XHJcbiAgICAgICAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAgICAgICAgICdJbnZhbGlkIG9yIG1pc3NpbmcgdG9rZW46IFNldCB0aGUgdG9rZW4gaW4gdGhlIGhjLWF1dGggaGVhZGVyLicsXHJcbiAgICAgICAgICAgICAgICA0MDFcclxuICAgICAgICAgICAgICApO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAvLyBDb21wYXJlIHZlcnNpb25zXHJcbiAgICAgICAgICAgIGNvbnN0IG5ld1ZlcnNpb24gPSByZXF1ZXN0LnBhcmFtcy5uZXdWZXJzaW9uO1xyXG4gICAgICAgICAgICBpZiAobmV3VmVyc2lvbikge1xyXG4gICAgICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgaW1wb3J0L25vLW5hbWVkLWFzLWRlZmF1bHQtbWVtYmVyXHJcbiAgICAgICAgICAgICAgICBhd2FpdCBjYWNoZS51cGRhdGVWZXJzaW9uKG5ld1ZlcnNpb24pO1xyXG4gICAgICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgICAgICAgICAgICBgVmVyc2lvbiBjaGFuZ2U6ICR7ZXJyb3IubWVzc2FnZX1gLFxyXG4gICAgICAgICAgICAgICAgICBlcnJvci5zdGF0dXNDb2RlXHJcbiAgICAgICAgICAgICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgIC8vIFN1Y2Nlc3NcclxuICAgICAgICAgICAgICByZXNwb25zZS5zdGF0dXMoMjAwKS5zZW5kKHtcclxuICAgICAgICAgICAgICAgIHN0YXR1c0NvZGU6IDIwMCxcclxuICAgICAgICAgICAgICAgIHZlcnNpb246IGNhY2hlLnZlcnNpb24oKSxcclxuICAgICAgICAgICAgICAgIG1lc3NhZ2U6IGBTdWNjZXNzZnVsbHkgdXBkYXRlZCBIaWdoY2hhcnRzIHRvIHZlcnNpb246ICR7bmV3VmVyc2lvbn0uYFxyXG4gICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgIC8vIE5vIHZlcnNpb24gc3BlY2lmaWVkXHJcbiAgICAgICAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcignTm8gbmV3IHZlcnNpb24gc3VwcGxpZWQuJywgNDAwKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgICAgbmV4dChlcnJvcik7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICApO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCAnY29sb3JzJztcclxuaW1wb3J0IGRvdGVudiBmcm9tICdkb3RlbnYnO1xyXG5cclxuaW1wb3J0IHsgY2hlY2tBbmRVcGRhdGVDYWNoZSB9IGZyb20gJy4vY2FjaGUuanMnO1xyXG5pbXBvcnQge1xyXG4gIGJhdGNoRXhwb3J0LFxyXG4gIHNldEFsbG93Q29kZUV4ZWN1dGlvbixcclxuICBzaW5nbGVFeHBvcnQsXHJcbiAgc3RhcnRFeHBvcnRcclxufSBmcm9tICcuL2NoYXJ0LmpzJztcclxuaW1wb3J0IHsgbWFwVG9OZXdDb25maWcsIG1hbnVhbENvbmZpZywgc2V0T3B0aW9ucyB9IGZyb20gJy4vY29uZmlnLmpzJztcclxuaW1wb3J0IHtcclxuICBpbml0TG9nZ2luZyxcclxuICBsb2csXHJcbiAgbG9nV2l0aFN0YWNrLFxyXG4gIHNldExvZ0xldmVsLFxyXG4gIGVuYWJsZUZpbGVMb2dnaW5nXHJcbn0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBpbml0UG9vbCwga2lsbFBvb2wgfSBmcm9tICcuL3Bvb2wuanMnO1xyXG5pbXBvcnQgc2VydmVyLCB7IHN0YXJ0U2VydmVyIH0gZnJvbSAnLi9zZXJ2ZXIvc2VydmVyLmpzJztcclxuaW1wb3J0IHsgcHJpbnRMb2dvLCBwcmludFVzYWdlIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG4vLyBMb2FkIC5lbnYgaW50byBlbnZpcm9ubWVudCB2YXJpYWJsZXNcclxuZG90ZW52LmNvbmZpZygpO1xyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIHRoZSBleHBvcnQgcHJvY2Vzcy4gVGFza3Mgc3VjaCBhcyBjb25maWd1cmluZyBsb2dnaW5nLCBjaGVja2luZ1xyXG4gKiBjYWNoZSBhbmQgc291cmNlcywgYW5kIGluaXRpYWxpemluZyB0aGUgcG9vbCBvZiByZXNvdXJjZXMgaGFwcGVuIGR1cmluZ1xyXG4gKiB0aGlzIHN0YWdlLiBGdW5jdGlvbiB0aGF0IGlzIHJlcXVpcmVkIHRvIGJlIGNhbGxlZCBiZWZvcmUgdHJ5aW5nIHRvIGV4cG9ydCBjaGFydHMgb3Igc2V0dGluZyBhIHNlcnZlci4gVGhlIGBvcHRpb25zYCBpcyBhbiBvYmplY3QgdGhhdCBjb250YWlucyBhbGwgb3B0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBBbGwgZXhwb3J0IG9wdGlvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSB1cGRhdGVkIGV4cG9ydCBvcHRpb25zLlxyXG4gKi9cclxuY29uc3QgaW5pdEV4cG9ydCA9IGFzeW5jIChvcHRpb25zKSA9PiB7XHJcbiAgLy8gU2V0IHRoZSBhbGxvd0NvZGVFeGVjdXRpb24gcGVyIGV4cG9ydCBtb2R1bGUgc2NvcGVcclxuICBzZXRBbGxvd0NvZGVFeGVjdXRpb24oXHJcbiAgICBvcHRpb25zLmN1c3RvbUxvZ2ljICYmIG9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgKTtcclxuXHJcbiAgLy8gSW5pdCB0aGUgbG9nZ2luZ1xyXG4gIGluaXRMb2dnaW5nKG9wdGlvbnMubG9nZ2luZyk7XHJcblxyXG4gIC8vIENoZWNrIGlmIGNhY2hlIG5lZWRzIHRvIGJlIHVwZGF0ZWRcclxuICBhd2FpdCBjaGVja0FuZFVwZGF0ZUNhY2hlKG9wdGlvbnMuaGlnaGNoYXJ0cyB8fCB7IHZlcnNpb246ICdsYXRlc3QnIH0pO1xyXG5cclxuICAvLyBJbml0IHRoZSBwb29sXHJcbiAgYXdhaXQgaW5pdFBvb2woe1xyXG4gICAgcG9vbDogb3B0aW9ucy5wb29sIHx8IHtcclxuICAgICAgbWluV29ya2VyczogMSxcclxuICAgICAgbWF4V29ya2VyczogMVxyXG4gICAgfSxcclxuICAgIHB1cHBldGVlckFyZ3M6IG9wdGlvbnMucHVwcGV0ZWVyPy5hcmdzIHx8IFtdXHJcbiAgfSk7XHJcblxyXG4gIC8vIFJldHVybiB1cGRhdGVkIG9wdGlvbnNcclxuICByZXR1cm4gb3B0aW9ucztcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICAvLyBTZXJ2ZXJcclxuICBzZXJ2ZXIsXHJcbiAgc3RhcnRTZXJ2ZXIsXHJcbiAgc2V0T3B0aW9ucyxcclxuXHJcbiAgLy8gRXhwb3J0aW5nXHJcbiAgaW5pdEV4cG9ydCxcclxuICBzaW5nbGVFeHBvcnQsXHJcbiAgYmF0Y2hFeHBvcnQsXHJcbiAgc3RhcnRFeHBvcnQsXHJcbiAga2lsbFBvb2wsXHJcblxyXG4gIC8vIExvZ3NcclxuICBsb2csXHJcbiAgbG9nV2l0aFN0YWNrLFxyXG4gIHNldExvZ0xldmVsLFxyXG4gIGVuYWJsZUZpbGVMb2dnaW5nLFxyXG5cclxuICAvLyBVdGlsc1xyXG4gIG1hcFRvTmV3Q29uZmlnLFxyXG4gIG1hbnVhbENvbmZpZyxcclxuICBwcmludExvZ28sXHJcbiAgcHJpbnRVc2FnZVxyXG59O1xyXG4iXSwibmFtZXMiOlsiYXN5bmMiLCJmZXRjaCIsInVybCIsInJlcXVlc3RPcHRpb25zIiwiUHJvbWlzZSIsInJlc29sdmUiLCJyZWplY3QiLCJwcm90b2NvbCIsInN0YXJ0c1dpdGgiLCJodHRwcyIsImh0dHAiLCJnZXRQcm90b2NvbCIsImdldCIsInJlcyIsImRhdGEiLCJvbiIsImNodW5rIiwidGV4dCIsImVycm9yIiwiZGVmYXVsdENvbmZpZyIsInB1cHBldGVlciIsImFyZ3MiLCJ2YWx1ZSIsInR5cGUiLCJkZXNjcmlwdGlvbiIsImhpZ2hjaGFydHMiLCJ2ZXJzaW9uIiwiZW52TGluayIsImNkblVSTCIsImNvcmVTY3JpcHRzIiwibW9kdWxlcyIsImluZGljYXRvcnMiLCJzY3JpcHRzIiwiZm9yY2VGZXRjaCIsImNhY2hlUGF0aCIsImV4cG9ydCIsImluZmlsZSIsImluc3RyIiwib3B0aW9ucyIsIm91dGZpbGUiLCJjb25zdHIiLCJkZWZhdWx0SGVpZ2h0IiwiZGVmYXVsdFdpZHRoIiwiZGVmYXVsdFNjYWxlIiwiaGVpZ2h0Iiwid2lkdGgiLCJzY2FsZSIsImdsb2JhbE9wdGlvbnMiLCJ0aGVtZU9wdGlvbnMiLCJiYXRjaCIsInJhc3Rlcml6YXRpb25UaW1lb3V0IiwiY3VzdG9tTG9naWMiLCJhbGxvd0NvZGVFeGVjdXRpb24iLCJhbGxvd0ZpbGVSZXNvdXJjZXMiLCJjdXN0b21Db2RlIiwiY2FsbGJhY2siLCJyZXNvdXJjZXMiLCJsb2FkQ29uZmlnIiwibGVnYWN5TmFtZSIsImNyZWF0ZUNvbmZpZyIsInNlcnZlciIsImVuYWJsZSIsImNsaU5hbWUiLCJob3N0IiwicG9ydCIsImJlbmNobWFya2luZyIsInNzbCIsImZvcmNlIiwiY2VydFBhdGgiLCJyYXRlTGltaXRpbmciLCJtYXhSZXF1ZXN0cyIsIndpbmRvdyIsImRlbGF5IiwidHJ1c3RQcm94eSIsInNraXBLZXkiLCJza2lwVG9rZW4iLCJwb29sIiwibWluV29ya2VycyIsIm1heFdvcmtlcnMiLCJ3b3JrTGltaXQiLCJhY3F1aXJlVGltZW91dCIsImNyZWF0ZVRpbWVvdXQiLCJkZXN0cm95VGltZW91dCIsImlkbGVUaW1lb3V0IiwiY3JlYXRlUmV0cnlJbnRlcnZhbCIsInJlYXBlckludGVydmFsIiwibGlzdGVuVG9Qcm9jZXNzRXhpdHMiLCJsb2dnaW5nIiwibGV2ZWwiLCJmaWxlIiwiZGVzdCIsInVpIiwicm91dGUiLCJvdGhlciIsIm5vTG9nbyIsInByb21wdHNDb25maWciLCJuYW1lIiwibWVzc2FnZSIsImluaXRpYWwiLCJqb2luIiwic2VwYXJhdG9yIiwiaW5zdHJ1Y3Rpb25zIiwiY2hvaWNlcyIsImhpbnQiLCJtaW4iLCJtYXgiLCJyb3VuZCIsImFic29sdXRlUHJvcHMiLCJuZXN0ZWRBcmdzIiwiY3JlYXRlTmVzdGVkQXJncyIsIm9iaiIsInByb3BDaGFpbiIsIk9iamVjdCIsImtleXMiLCJmb3JFYWNoIiwiayIsImluY2x1ZGVzIiwiZW50cnkiLCJzdWJzdHJpbmciLCJ1bmRlZmluZWQiLCJjb2xvcnMiLCJ0b0NvbnNvbGUiLCJ0b0ZpbGUiLCJwYXRoQ3JlYXRlZCIsImxldmVsc0Rlc2MiLCJ0aXRsZSIsImNvbG9yIiwibGlzdGVuZXJzIiwia2V5Iiwib3B0aW9uIiwiZW50cmllcyIsImxvZ1RvRmlsZSIsInRleHRzIiwicHJlZml4IiwiZXhpc3RzU3luYyIsIm1rZGlyU3luYyIsImFwcGVuZEZpbGUiLCJjb25jYXQiLCJjb25zb2xlIiwibG9nIiwibmV3TGV2ZWwiLCJsZW5ndGgiLCJEYXRlIiwidG9TdHJpbmciLCJzcGxpdCIsInRyaW0iLCJmbiIsImFwcGx5IiwibG9nV2l0aFN0YWNrIiwiY3VzdG9tTWVzc2FnZSIsIm1haW5NZXNzYWdlIiwic3RhY2tNZXNzYWdlIiwic3RhY2siLCJzbGljZSIsInNldExvZ0xldmVsIiwiZW5hYmxlRmlsZUxvZ2dpbmciLCJsb2dEZXN0IiwibG9nRmlsZSIsImVuZHNXaXRoIiwiX19kaXJuYW1lIiwiZmlsZVVSTFRvUGF0aCIsIlVSTCIsImRvY3VtZW50IiwicmVxdWlyZSIsInBhdGhUb0ZpbGVVUkwiLCJfX2ZpbGVuYW1lIiwiaHJlZiIsIl9kb2N1bWVudEN1cnJlbnRTY3JpcHQiLCJzcmMiLCJiYXNlVVJJIiwiZml4VHlwZSIsImZvcm1hdHMiLCJvdXRUeXBlIiwicG9wIiwiZmluZCIsInQiLCJoYW5kbGVSZXNvdXJjZXMiLCJhbGxvd2VkUHJvcHMiLCJoYW5kbGVkUmVzb3VyY2VzIiwiY29ycmVjdFJlc291cmNlcyIsImlzQ29ycmVjdEpTT04iLCJyZWFkRmlsZVN5bmMiLCJmaWxlcyIsInByb3BOYW1lIiwibWFwIiwiaXRlbSIsInBhcnNlZERhdGEiLCJKU09OIiwicGFyc2UiLCJzdHJpbmdpZnkiLCJkZWVwQ29weSIsImNvcHkiLCJBcnJheSIsImlzQXJyYXkiLCJwcm90b3R5cGUiLCJoYXNPd25Qcm9wZXJ0eSIsImNhbGwiLCJvcHRpb25zU3RyaW5naWZ5IiwiYWxsb3dGdW5jdGlvbnMiLCJyZXBsYWNlQWxsIiwicHJpbnRVc2FnZSIsImJvbGQiLCJ5ZWxsb3ciLCJjeWNsZUNhdGVnb3JpZXMiLCJkZXNjTmFtZSIsImdyZWVuIiwiaSIsImJsdWUiLCJjYXRlZ29yeSIsInRvVXBwZXJDYXNlIiwicmVkIiwidG9Cb29sZWFuIiwid3JhcEFyb3VuZCIsInJlcGxhY2UiLCJtZWFzdXJlVGltZSIsInN0YXJ0IiwicHJvY2VzcyIsImhydGltZSIsImJpZ2ludCIsIk51bWJlciIsIkV4cG9ydEVycm9yIiwiRXJyb3IiLCJjb25zdHJ1Y3RvciIsInN1cGVyIiwidGhpcyIsInNldEVycm9yIiwic3RhdHVzQ29kZSIsImNhY2hlIiwiYWN0aXZlTWFuaWZlc3QiLCJzb3VyY2VzIiwiaGNWZXJzaW9uIiwiYXBwbGllZENvbmZpZyIsImV4dHJhY3RWZXJzaW9uIiwiaW5kZXhPZiIsImZldGNoQW5kUHJvY2Vzc1NjcmlwdCIsInNjcmlwdCIsInByb3h5QWdlbnQiLCJmZXRjaGVkTW9kdWxlcyIsInNob3VsZFRocm93RXJyb3IiLCJhZ2VudCIsInRpbWVvdXQiLCJlbnYiLCJyZXNwb25zZSIsInVwZGF0ZUNhY2hlIiwiY29uZmlnIiwic291cmNlUGF0aCIsImN1c3RvbVNjcmlwdHMiLCJwcm94eUhvc3QiLCJwcm94eVBvcnQiLCJIdHRwc1Byb3h5QWdlbnQiLCJtb2R1bGVTY3JpcHRzIiwiYWxsRmV0Y2hQcm9taXNlcyIsImFsbCIsImZldGNoU2NyaXB0cyIsImMiLCJtIiwid3JpdGVGaWxlU3luYyIsImNoZWNrQW5kVXBkYXRlQ2FjaGUiLCJtYW5pZmVzdFBhdGgiLCJyZXF1ZXN0VXBkYXRlIiwibWFuaWZlc3QiLCJtb2R1bGVNYXAiLCJudW1iZXJPZk1vZHVsZXMiLCJzb21lIiwibW9kdWxlTmFtZSIsIm5ld01hbmlmZXN0Iiwic2F2ZUNvbmZpZ1RvTWFuaWZlc3QiLCJnZXRDYWNoZVBhdGgiLCJjYWNoZSQxIiwibmV3VmVyc2lvbiIsImFzc2lnbiIsImdlbmVyYWxPcHRpb25zIiwiZ2V0T3B0aW9ucyIsIm1lcmdlQ29uZmlnT3B0aW9ucyIsIm5ld09wdGlvbnMiLCJtZXJnZWRPcHRpb25zIiwidXBkYXRlRGVmYXVsdENvbmZpZyIsImNvbmZpZ09iaiIsImN1c3RvbU9iaiIsImN1c3RvbVZhbHVlIiwibnVtRW52VmFsIiwiZWwiLCJpbml0T3B0aW9ucyIsIml0ZW1zIiwicmVjdXJzaXZlUHJvcHMiLCJvYmplY3RUb1VwZGF0ZSIsIm5lc3RlZE5hbWVzIiwic2hpZnQiLCJSQU5ET01fUElEIiwicmFuZG9tQnl0ZXMiLCJQVVBQRVRFRVJfRElSIiwicGF0aCIsIm1pbmltYWxBcmdzIiwidGVtcGxhdGUiLCJmcyIsImJyb3dzZXIiLCJzZXRQYWdlQ29udGVudCIsInBhZ2UiLCJzZXRDb250ZW50IiwiYWRkU2NyaXB0VGFnIiwiZXZhbHVhdGUiLCJzZXR1cEhpZ2hjaGFydHMiLCIkZXZhbCIsImVsZW1lbnQiLCJlcnJvck1lc3NhZ2UiLCJfZGlzcGxheUVycm9ycyIsImlubmVySFRNTCIsImNsZWFyUGFnZSIsImhhcmRSZXNldCIsImdvdG8iLCJib2R5IiwibmV3UGFnZSIsInNldENhY2hlRW5hYmxlZCIsImNsb3NlIiwiaXNDb25uZWN0ZWQiLCJfX2Jhc2VkaXIiLCJzZXRBc0NvbmZpZyIsImNoYXJ0IiwidHJpZ2dlckV4cG9ydCIsInB1cHBldGVlckV4cG9ydCIsImluamVjdGVkUmVzb3VyY2VzIiwiY2xlYXJJbmplY3RlZCIsImRpc3Bvc2UiLCJzY3JpcHRzVG9SZW1vdmUiLCJnZXRFbGVtZW50c0J5VGFnTmFtZSIsInN0eWxlc1RvUmVtb3ZlIiwibGlua3NUb1JlbW92ZSIsInJlbW92ZSIsImV4cG9ydE9wdGlvbnMiLCJyZXF1ZXN0QW5pbWF0aW9uRnJhbWUiLCJkaXNwbGF5RXJyb3JzIiwiZGVidWdnZXIiLCJpc1NWRyIsImQiLCJzdmdUZW1wbGF0ZSIsInN0ckluaiIsImpzIiwicHVzaCIsImNvbnRlbnQiLCJpc0xvY2FsIiwiY3NzIiwiY3NzSW1wb3J0cyIsIm1hdGNoIiwiY3NzSW1wb3J0UGF0aCIsImFkZFN0eWxlVGFnIiwic2l6ZSIsImNoYXJ0SGVpZ2h0IiwiYmFzZVZhbCIsImNoYXJ0V2lkdGgiLCJwYXJzZUZsb2F0IiwiSGlnaGNoYXJ0cyIsImNoYXJ0cyIsInZpZXdwb3J0SGVpZ2h0IiwiTWF0aCIsImNlaWwiLCJ2aWV3cG9ydFdpZHRoIiwic2V0Vmlld3BvcnQiLCJkZXZpY2VTY2FsZUZhY3RvciIsInpvb21DYWxsYmFjayIsInN0eWxlIiwiem9vbSIsIm1hcmdpbiIsIngiLCJ5IiwiZ2V0Qm91bmRpbmdDbGllbnRSZWN0IiwidHJ1bmMiLCJnZXRDbGlwUmVnaW9uIiwib3V0ZXJIVE1MIiwiY3JlYXRlU1ZHIiwiZW5jb2RpbmciLCJjbGlwIiwicmFjZSIsInNjcmVlbnNob3QiLCJvbWl0QmFja2dyb3VuZCIsIl9yZXNvbHZlIiwic2V0VGltZW91dCIsImNyZWF0ZUltYWdlIiwicGRmIiwiY3JlYXRlUERGIiwib2xkQ2hhcnRzIiwib2xkQ2hhcnQiLCJkZXN0cm95IiwicHVwcGV0ZWVyQXJncyIsInBlcmZvcm1lZEV4cG9ydHMiLCJleHBvcnRBdHRlbXB0cyIsInRpbWVTcGVudCIsImRyb3BwZWRFeHBvcnRzIiwic3BlbnRBdmVyYWdlIiwicG9vbENvbmZpZyIsImZhY3RvcnkiLCJjcmVhdGUiLCJpZCIsInV1aWQiLCJzdGFydERhdGUiLCJnZXRUaW1lIiwiYnJvd3Nlck5ld1BhZ2UiLCJpc0Nsb3NlZCIsIndvcmtDb3VudCIsInJhbmRvbSIsInZhbGlkYXRlIiwid29ya2VySGFuZGxlIiwiaW5pdFBvb2wiLCJjb2RlIiwia2lsbFBvb2wiLCJleGl0IiwiYWxsQXJncyIsInRyeUNvdW50Iiwib3BlbiIsImxhdW5jaCIsImhlYWRsZXNzIiwidXNlckRhdGFEaXIiLCJjcmVhdGVCcm93c2VyIiwicGFyc2VJbnQiLCJQb29sIiwiYWNxdWlyZVRpbWVvdXRNaWxsaXMiLCJjcmVhdGVUaW1lb3V0TWlsbGlzIiwiZGVzdHJveVRpbWVvdXRNaWxsaXMiLCJpZGxlVGltZW91dE1pbGxpcyIsImNyZWF0ZVJldHJ5SW50ZXJ2YWxNaWxsaXMiLCJyZWFwSW50ZXJ2YWxNaWxsaXMiLCJwcm9wYWdhdGVDcmVhdGVFcnJvciIsInJlc291cmNlIiwiZXZlbnRJZCIsImluaXRpYWxSZXNvdXJjZXMiLCJhY3F1aXJlIiwicHJvbWlzZSIsInJlbGVhc2UiLCJicm93c2VyQ2xvc2UiLCJkZXN0cm95ZWQiLCJwb3N0V29yayIsImdldFBvb2xJbmZvIiwiYWNxdWlyZUNvdW50ZXIiLCJwYXlsb2FkIiwicmVxdWVzdElkIiwid29ya1N0YXJ0IiwiZXhwb3J0Q291bnRlciIsInJlc3VsdCIsImV4cG9ydFRpbWUiLCJudW1GcmVlIiwibnVtVXNlZCIsIm51bVBlbmRpbmdBY3F1aXJlcyIsInBvb2wkMSIsImF2YWlsYWJsZSIsImluVXNlIiwicGVuZGluZ0FjcXVpcmUiLCJzdGFydEV4cG9ydCIsInNldHRpbmdzIiwiZW5kQ2FsbGJhY2siLCJzdmciLCJpbml0RXhwb3J0U2V0dGluZ3MiLCJleHBvcnRBc1N0cmluZyIsImRvU3RyYWlnaHRJbmplY3QiLCJkb0V4cG9ydCIsImZpbmRDaGFydFNpemUiLCJleHBvcnRpbmciLCJwcmVjaXNpb24iLCJtdWx0aXBsaWVyIiwicG93Iiwicm91bmROdW1iZXIiLCJzb3VyY2VIZWlnaHQiLCJzb3VyY2VXaWR0aCIsInBhcmFtIiwiY2hhcnRKc29uIiwiY3VzdG9tTG9naWNPcHRpb25zIiwiYWxsb3dDb2RlRXhlY3V0aW9uU2NvcGVkIiwiZW5hYmxlZCIsIm9wdGlvbnNOYW1lIiwic3RyaW5nVG9FeHBvcnQiLCJjaGFydEpTT04iLCJsb2dFcnJvck1pZGRsZXdhcmUiLCJyZXEiLCJuZXh0IiwiTk9ERV9FTlYiLCJyZXR1cm5FcnJvck1pZGRsZXdhcmUiLCJzdENvZGUiLCJzdGF0dXMiLCJqc29uIiwicmF0ZUxpbWl0IiwiYXBwIiwibGltaXRDb25maWciLCJtc2ciLCJyYXRlT3B0aW9ucyIsImxpbWl0ZXIiLCJ3aW5kb3dNcyIsImRlbGF5TXMiLCJoYW5kbGVyIiwicmVxdWVzdCIsImZvcm1hdCIsInNlbmQiLCJkZWZhdWx0Iiwic2tpcCIsInF1ZXJ5IiwiYWNjZXNzX3Rva2VuIiwidXNlIiwiSHR0cEVycm9yIiwic2V0U3RhdHVzIiwicmV2ZXJzZWRNaW1lIiwicG5nIiwianBlZyIsImdpZiIsInJlcXVlc3RzQ291bnRlciIsImJlZm9yZVJlcXVlc3QiLCJhZnRlclJlcXVlc3QiLCJkb0NhbGxiYWNrcyIsImNhbGxiYWNrcyIsInVuaXF1ZUlkIiwiY2FsbFJlc3BvbnNlIiwiZXhwb3J0SGFuZGxlciIsInN0b3BDb3VudGVyIiwiZGVmYXVsdE9wdGlvbnMiLCJoZWFkZXJzIiwiY29ubmVjdGlvbiIsInJlbW90ZUFkZHJlc3MiLCJjb25uZWN0aW9uQWJvcnRlZCIsInNvY2tldCIsInRvTG93ZXJDYXNlIiwic3Vic3RyIiwiYjY0Iiwibm9Eb3dubG9hZCIsImlwUmVnRXgiLCJpc1ByaXZhdGVSYW5nZVVybEZvdW5kIiwiaW5mbyIsInJlbW92ZUFsbExpc3RlbmVycyIsIkJ1ZmZlciIsImZyb20iLCJoZWFkZXIiLCJhdHRhY2htZW50IiwicGFyYW1zIiwiZmlsZW5hbWUiLCJwa2dGaWxlIiwicGF0aGVyIiwic2VydmVyU3RhcnRUaW1lIiwiZXhwcmVzcyIsImRpc2FibGUiLCJjb3JzIiwic3RvcmFnZSIsIm11bHRlciIsIm1lbW9yeVN0b3JhZ2UiLCJ1cGxvYWQiLCJsaW1pdHMiLCJmaWVsZFNpemUiLCJsaW1pdCIsInVybGVuY29kZWQiLCJleHRlbmRlZCIsIm5vbmUiLCJhdHRhY2hFcnJvckhhbmRsZXJzIiwic3RhcnRTZXJ2ZXIiLCJzZXJ2ZXJDb25maWciLCJodHRwU2VydmVyIiwiY3JlYXRlU2VydmVyIiwibGlzdGVuIiwiY2VydCIsImZzUHJvbWlzZXMiLCJyZWFkRmlsZSIsInBvc2l4IiwiaHR0cHNTZXJ2ZXIiLCJOYU4iLCJzdGF0aWMiLCJib290VGltZSIsInVwdGltZSIsImZsb29yIiwiaGlnaGNoYXJ0c1ZlcnNpb24iLCJhdmVyYWdlUHJvY2Vzc2luZ1RpbWUiLCJmYWlsZWRFeHBvcnRzIiwic3VjZXNzUmF0aW8iLCJoZWFsdGhSb3V0ZSIsInBvc3QiLCJleHBvcnRSb3V0ZXMiLCJzZW5kRmlsZSIsInVpUm91dGUiLCJhZG1pblRva2VuIiwiSElHSENIQVJUU19BRE1JTl9UT0tFTiIsInRva2VuIiwidlN3aXRjaFJvdXRlIiwiZXJyb3JIYW5kbGVyIiwiZW5hYmxlUmF0ZUxpbWl0aW5nIiwiZ2V0RXhwcmVzcyIsImdldEFwcCIsIm1pZGRsZXdhcmVzIiwiZG90ZW52IiwiaW5kZXgiLCJzZXRPcHRpb25zIiwidXNlck9wdGlvbnMiLCJjb25maWdJbmRleCIsImZpbmRJbmRleCIsImFyZyIsImZpbGVOYW1lIiwibG9hZENvbmZpZ0ZpbGUiLCJzaG93VXNhZ2UiLCJwcm9wZXJ0aWVzQ2hhaW4iLCJhcmd1bWVudFR5cGUiLCJyZWR1Y2UiLCJwcm9wIiwicGFpckFyZ3VtZW50VmFsdWUiLCJpbml0RXhwb3J0IiwiaW5pdExvZ2dpbmciLCJzaW5nbGVFeHBvcnQiLCJiYXRjaEV4cG9ydCIsImJhdGNoRnVuY3Rpb25zIiwicGFpciIsIm1hcFRvTmV3Q29uZmlnIiwib2xkT3B0aW9ucyIsIm1hbnVhbENvbmZpZyIsImNvbmZpZ0ZpbGVOYW1lIiwiY29uZmlnRmlsZSIsImNob2ljZSIsInByb21wdHMiLCJvblN1Ym1pdCIsInAiLCJjYXRlZ29yaWVzIiwicXVlc3Rpb25zQ291bnRlciIsImFsbFF1ZXN0aW9ucyIsInNlY3Rpb24iLCJwcm9tcHQiLCJhbnN3ZXIiLCJtb2R1bGUiLCJwcm9taXNlcyIsIndyaXRlRmlsZSIsInByaW50TG9nbyIsInBhY2thZ2VWZXJzaW9uIl0sIm1hcHBpbmdzIjoia3RCQXlCQUEsZUFBZUMsRUFBTUMsRUFBS0MsRUFBaUIsSUFDekMsT0FBTyxJQUFJQyxTQUFRLENBQUNDLEVBQVNDLEtBQzNCLE1BQU1DLEVBYlUsQ0FBQ0wsR0FBU0EsRUFBSU0sV0FBVyxTQUFXQyxFQUFRQyxFQWEzQ0MsQ0FBWVQsR0FFN0JLLEVBQ0dLLElBQUlWLEVBQUtDLEdBQWlCVSxJQUN6QixJQUFJQyxFQUFPLEdBR1hELEVBQUlFLEdBQUcsUUFBU0MsSUFDZEYsR0FBUUUsQ0FBSyxJQUlmSCxFQUFJRSxHQUFHLE9BQU8sS0FDUEQsR0FDSFIsRUFBTyxxQ0FHVE8sRUFBSUksS0FBT0gsRUFDWFQsRUFBUVEsRUFBSSxHQUNaLElBRUhFLEdBQUcsU0FBVUcsSUFDWlosRUFBT1ksRUFBTSxHQUNiLEdBRVIsQ0NwQ08sTUFBTUMsRUFBZ0IsQ0FDM0JDLFVBQVcsQ0FDVEMsS0FBTSxDQUNKQyxNQUFPLEdBQ1BDLEtBQU0sV0FDTkMsWUFBYSwwQ0FHakJDLFdBQVksQ0FDVkMsUUFBUyxDQUNQSixNQUFPLFNBQ1BLLFFBQVMscUJBQ1RKLEtBQU0sU0FDTkMsWUFBYSxzQ0FFZkksT0FBUSxDQUNOTixNQUFPLCtCQUNQSyxRQUFTLHFCQUNUSixLQUFNLFNBQ05DLFlBQWEsa0RBRWZLLFlBQWEsQ0FDWEYsUUFBUywwQkFDVEwsTUFBTyxDQUFDLGFBQWMsa0JBQW1CLGlCQUN6Q0MsS0FBTSxXQUNOQyxZQUFhLHlDQUVmTSxRQUFTLENBQ1BILFFBQVMscUJBQ1RMLE1BQU8sQ0FDTCxRQUNBLE1BQ0EsUUFDQSxZQUNBLGNBQ0EsdUJBQ0EsZ0JBQ0EsdUJBQ0EsZUFDQSxRQUNBLE9BQ0EsYUFDQSxtQkFDQSxlQUNBLGNBQ0EsVUFDQSxVQUNBLGNBQ0EsV0FDQSxVQUNBLFlBQ0EsY0FDQSxZQUNB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 diff --git a/dist/index.esm.js b/dist/index.esm.js index f0007d84..489ea041 100644 --- a/dist/index.esm.js +++ b/dist/index.esm.js @@ -1,2 +1,2 @@ -import"colors";import e from"dotenv";import t,{existsSync as r,mkdirSync as i,appendFile as o,readFileSync as n,writeFileSync as s,promises as a}from"fs";import l,{join as c,posix as p}from"path";import{HttpsProxyAgent as h}from"https-proxy-agent";import u from"http";import d from"https";import*as g from"url";import{fileURLToPath as m}from"url";import f from"prompts";import{Pool as v}from"tarn";import{v4 as y}from"uuid";import w from"node:path";import b from"puppeteer";import{randomBytes as T}from"node:crypto";import k from"cors";import x from"express";import E from"multer";import L from"express-rate-limit";async function S(e,t={}){return new Promise(((r,i)=>{const o=(e=>e.startsWith("https")?d:u)(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)}))}))}const O={puppeteer:{args:{value:[],type:"string[]",description:"Arguments array to send to Puppeteer."}},highcharts:{version:{value:"latest",envLink:"HIGHCHARTS_VERSION",type:"string",description:"The Highcharts version to be used."},cdnURL:{value:"https://code.highcharts.com/",envLink:"HIGHCHARTS_CDN_URL",type:"string",description:"The CDN URL for Highcharts scripts to be used."},coreScripts:{envLink:"HIGHCHARTS_CORE_SCRIPTS",value:["highcharts","highcharts-more","highcharts-3d"],type:"string[]",description:"The core Highcharts scripts to fetch."},modules:{envLink:"HIGHCHARTS_MODULES",value:["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"],type:"string[]",description:"The modules of Highcharts to fetch."},indicators:{envLink:"HIGHCHARTS_INDICATORS",value:["indicators-all"],type:"string[]",description:"The indicators of Highcharts to fetch."},scripts:{value:["https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js","https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.34/moment-timezone-with-data.min.js"],type:"string[]",description:"Additional optional scripts or dependencies to fetch."},forceFetch:{envLink:"HIGHCHARTS_FORCE_FETCH",value:!1,type:"boolean",description:"The flag to determine whether to refetch all scripts after each server rerun."},cachePath:{envLink:"HIGHCHARTS_CACHE_PATH",value:".cache",type:"string",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:{envLink:"EXPORT_TYPE",value:"png",type:"string",description:"The file export format. It can be jpeg, png, pdf, or svg."},constr:{envLink:"EXPORT_CONSTR",value:"chart",type:"string",description:"The constructor to use. Can be chart, stockChart, mapChart, or ganttChart."},defaultHeight:{envLink:"EXPORT_DEFAULT_HEIGHT",value:400,type:"number",description:"the default height of the exported chart. Used when no value is set."},defaultWidth:{envLink:"EXPORT_DEFAULT_WIDTH",value:600,type:"number",description:"The default width of the exported chart. Used when no value is set."},defaultScale:{envLink:"EXPORT_DEFAULT_SCALE",value:1,type:"number",description:"The default scale of the exported chart. Used when no value is set."},height:{type:"number",value:!1,description:"The height of the exported chart, overriding the option in the chart settings."},width:{type:"number",value:!1,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:{envLink:"EXPORT_RASTERIZATION_TIMEOUT",value:1500,type:"number",description:"The duration in milliseconds to wait for rendering a webpage."}},customLogic:{allowCodeExecution:{envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",value:!1,type:"boolean",description:"Controls whether the execution of arbitrary code is allowed during the exporting process."},allowFileResources:{envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",value:!1,type:"boolean",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:{envLink:"SERVER_ENABLE",value:!1,type:"boolean",cliName:"enableServer",description:"When set to true, the server starts on the local IP address 0.0.0.0."},host:{envLink:"SERVER_HOST",value:"0.0.0.0",type:"string",description:"The hostname of the server. Additionally, it starts a server on the provided hostname."},port:{envLink:"SERVER_PORT",value:7801,type:"number",description:"The server port when enabled."},benchmarking:{envLink:"SERVER_BENCHMARKING",value:!1,type:"boolean",cliName:"serverBenchmarking",description:"Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request."},ssl:{enable:{envLink:"SERVER_SSL_ENABLE",value:!1,type:"boolean",cliName:"enableSsl",description:"Enables or disables the SSL protocol."},force:{envLink:"SERVER_SSL_FORCE",value:!1,type:"boolean",cliName:"sslForced",legacyName:"sslOnly",description:"When set to true, the server is forced to serve only over HTTPS."},port:{envLink:"SERVER_SSL_PORT",value:443,type:"number",cliName:"sslPort",description:"The port on which to run the SSL server."},certPath:{envLink:"SERVER_SSL_CERT_PATH",value:"",type:"string",legacyName:"sslPath",description:"The path to the SSL certificate/key file."}},rateLimiting:{enable:{envLink:"SERVER_RATE_LIMITING_ENABLE",value:!1,type:"boolean",cliName:"enableRateLimiting",description:"Enables rate limiting for the server."},maxRequests:{envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",value:10,type:"number",legacyName:"rateLimit",description:"The maximum number of requests allowed in one minute."},window:{envLink:"SERVER_RATE_LIMITING_WINDOW",value:1,type:"number",description:"The time window, in minutes, for the rate limiting."},delay:{envLink:"SERVER_RATE_LIMITING_DELAY",value:0,type:"number",description:"The delay duration for each successive request before reaching the maximum limit."},trustProxy:{envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",value:!1,type:"boolean",description:"Set this to true if the server is behind a load balancer."},skipKey:{envLink:"SERVER_RATE_LIMITING_SKIP_KEY",value:"",type:"string",description:"Allows bypassing the rate limiter and should be provided with the skipToken argument."},skipToken:{envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",value:"",type:"string",description:"Allows bypassing the rate limiter and should be provided with the skipKey argument."}}},pool:{minWorkers:{envLink:"POOL_MIN_WORKERS",value:4,type:"number",description:"The number of minimum and initial pool workers to spawn."},maxWorkers:{envLink:"POOL_MAX_WORKERS",value:8,type:"number",legacyName:"workers",description:"The number of maximum pool workers to spawn."},workLimit:{envLink:"POOL_WORK_LIMIT",value:40,type:"number",description:"The number of work pieces that can be performed before restarting the worker process."},acquireTimeout:{envLink:"POOL_ACQUIRE_TIMEOUT",value:5e3,type:"number",description:"The duration, in milliseconds, to wait for acquiring a resource."},createTimeout:{envLink:"POOL_CREATE_TIMEOUT",value:5e3,type:"number",description:"The duration, in milliseconds, to wait for creating a resource."},destroyTimeout:{envLink:"POOL_DESTROY_TIMEOUT",value:5e3,type:"number",description:"The duration, in milliseconds, to wait for destroying a resource."},idleTimeout:{envLink:"POOL_IDLE_TIMEOUT",value:3e4,type:"number",description:"The duration, in milliseconds, after which an idle resource is destroyed."},createRetryInterval:{envLink:"POOL_CREATE_RETRY_INTERVAL",value:200,type:"number",description:"The duration, in milliseconds, to wait before retrying the create process in case of a failure."},reaperInterval:{envLink:"POOL_REAPER_INTERVAL",value:1e3,type:"number",description:"The duration, in milliseconds, after which the check for idle resources to destroy is triggered."},benchmarking:{envLink:"POOL_BENCHMARKING",value:!1,type:"boolean",cliName:"poolBenchmarking",description:"Indicate whether to show statistics for the pool of resources or not."},listenToProcessExits:{envLink:"POOL_LISTEN_TO_PROCESS_EXITS",value:!0,type:"boolean",description:"Decides whether or not to attach process.exit handlers."}},logging:{level:{envLink:"LOGGING_LEVEL",value:4,type:"number",cliName:"logLevel",description:"The logging level to be used."},file:{envLink:"LOGGING_FILE",value:"highcharts-export-server.log",type:"string",cliName:"logFile",description:"The name of a log file. The logDest option also needs to be set to enable file logging."},dest:{envLink:"LOGGING_DEST",value:"log/",type:"string",cliName:"logDest",description:"The path to store log files. This also enables file logging."}},ui:{enable:{envLink:"UI_ENABLE",value:!1,type:"boolean",cliName:"enableUi",description:"Enables or disables the user interface (UI) for the export server."},route:{envLink:"UI_ROUTE",value:"/",type:"string",cliName:"uiRoute",description:"The endpoint route to which the user interface (UI) should be attached."}},other:{noLogo:{envLink:"OTHER_NO_LOGO",value:!1,type:"boolean",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:O.puppeteer.args.value.join(","),separator:","}],highcharts:[{type:"text",name:"version",message:"Highcharts version",initial:O.highcharts.version.value},{type:"text",name:"cdnURL",message:"The URL of CDN",initial:O.highcharts.cdnURL.value},{type:"multiselect",name:"modules",message:"Available modules",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:O.highcharts.modules.value},{type:"list",name:"scripts",message:"Custom scripts",initial:O.highcharts.scripts.value.join(","),separator:","},{type:"toggle",name:"forceFetch",message:"Force re-fetch the scripts",initial:O.highcharts.forceFetch.value},{type:"text",name:"cachePath",message:"The path to the cache directory",initial:O.highcharts.cachePath.value}],export:[{type:"select",name:"type",message:"The default export file type",hint:`Default: ${O.export.type.value}`,initial:0,choices:["png","jpeg","pdf","svg"]},{type:"select",name:"constr",message:"The default constructor for Highcharts",hint:`Default: ${O.export.constr.value}`,initial:0,choices:["chart","stockChart","mapChart","ganttChart"]},{type:"number",name:"defaultHeight",message:"The default fallback height of the exported chart",initial:O.export.defaultHeight.value},{type:"number",name:"defaultWidth",message:"The default fallback width of the exported chart",initial:O.export.defaultWidth.value},{type:"number",name:"defaultScale",message:"The default fallback scale of the exported chart",initial:O.export.defaultScale.value,min:.1,max:5},{type:"number",name:"rasterizationTimeout",message:"The rendering webpage timeout in milliseconds",initial:O.export.rasterizationTimeout.value}],customLogic:[{type:"toggle",name:"allowCodeExecution",message:"Enable execution of custom code",initial:O.customLogic.allowCodeExecution.value},{type:"toggle",name:"allowFileResources",message:"Enable file resources",initial:O.customLogic.allowFileResources.value}],server:[{type:"toggle",name:"enable",message:"Starts the server on 0.0.0.0",initial:O.server.enable.value},{type:"text",name:"host",message:"Server hostname",initial:O.server.host.value},{type:"number",name:"port",message:"Server port",initial:O.server.port.value},{type:"toggle",name:"benchmarking",message:"Enable server benchmarking",initial:O.server.benchmarking.value},{type:"toggle",name:"ssl.enable",message:"Enable SSL protocol",initial:O.server.ssl.enable.value},{type:"toggle",name:"ssl.force",message:"Force serving only over HTTPS",initial:O.server.ssl.force.value},{type:"number",name:"ssl.port",message:"SSL server port",initial:O.server.ssl.port.value},{type:"text",name:"ssl.certPath",message:"The path to find the SSL certificate/key",initial:O.server.ssl.certPath.value},{type:"toggle",name:"rateLimiting.enable",message:"Enable rate limiting",initial:O.server.rateLimiting.enable.value},{type:"number",name:"rateLimiting.maxRequests",message:"The maximum requests allowed per minute",initial:O.server.rateLimiting.maxRequests.value},{type:"number",name:"rateLimiting.window",message:"The rate-limiting time window in minutes",initial:O.server.rateLimiting.window.value},{type:"number",name:"rateLimiting.delay",message:"The delay for each successive request before reaching the maximum",initial:O.server.rateLimiting.delay.value},{type:"toggle",name:"rateLimiting.trustProxy",message:"Set to true if behind a load balancer",initial:O.server.rateLimiting.trustProxy.value},{type:"text",name:"rateLimiting.skipKey",message:"Allows bypassing the rate limiter when provided with the skipToken argument",initial:O.server.rateLimiting.skipKey.value},{type:"text",name:"rateLimiting.skipToken",message:"Allows bypassing the rate limiter when provided with the skipKey argument",initial:O.server.rateLimiting.skipToken.value}],pool:[{type:"number",name:"minWorkers",message:"The initial number of workers to spawn",initial:O.pool.minWorkers.value},{type:"number",name:"maxWorkers",message:"The maximum number of workers to spawn",initial:O.pool.maxWorkers.value},{type:"number",name:"workLimit",message:"The pieces of work that can be performed before restarting a Puppeteer process",initial:O.pool.workLimit.value},{type:"number",name:"acquireTimeout",message:"The number of milliseconds to wait for acquiring a resource",initial:O.pool.acquireTimeout.value},{type:"number",name:"createTimeout",message:"The number of milliseconds to wait for creating a resource",initial:O.pool.createTimeout.value},{type:"number",name:"destroyTimeout",message:"The number of milliseconds to wait for destroying a resource",initial:O.pool.destroyTimeout.value},{type:"number",name:"idleTimeout",message:"The number of milliseconds after an idle resource is destroyed",initial:O.pool.idleTimeout.value},{type:"number",name:"createRetryInterval",message:"The retry interval in milliseconds after a create process fails",initial:O.pool.createRetryInterval.value},{type:"number",name:"reaperInterval",message:"The reaper interval in milliseconds after triggering the check for idle resources to destroy",initial:O.pool.reaperInterval.value},{type:"toggle",name:"benchmarking",message:"Enable benchmarking for a resource pool",initial:O.pool.benchmarking.value},{type:"toggle",name:"listenToProcessExits",message:"Set to false to skip attaching process.exit handlers",initial:O.pool.listenToProcessExits.value}],logging:[{type:"number",name:"level",message:"The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)",initial:O.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:O.logging.file.value},{type:"text",name:"dest",message:"The path to log files. Enables file logging",initial:O.logging.dest.value}],ui:[{type:"toggle",name:"enable",message:"Enable UI for the export server",initial:O.ui.enable.value},{type:"text",name:"route",message:"A route to attach the UI",initial:O.ui.route.value}],other:[{type:"toggle",name:"noLogo",message:"Skip printing the logo on startup. Replaced by simple text",initial:O.other.noLogo.value}]},I=["options","globalOptions","themeOptions","resources","payload"],C={},$=(e,t="")=>{Object.keys(e).forEach((r=>{if(!["puppeteer","highcharts"].includes(r)){const i=e[r];void 0===i.value?$(i,`${t}.${r}`):(C[i.cliName||r]=`${t}.${r}`.substring(1),void 0!==i.legacyName&&(C[i.legacyName]=`${t}.${r}`.substring(1)))}}))};$(O);const _=["red","yellow","blue","gray","green"];let N={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:_[0]},{title:"warning",color:_[1]},{title:"notice",color:_[2]},{title:"verbose",color:_[3]},{title:"benchmark",color:_[4]}],listeners:[]};for(const[e,t]of Object.entries(O.logging))N[e]=t.value;const P=(e,t)=>{N.toFile&&(N.pathCreated||(!r(N.dest)&&i(N.dest),N.pathCreated=!0),o(`${N.dest}${N.file}`,[t].concat(e).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),N.toFile=!1)})))},A=(...e)=>{const[t,...r]=e,{level:i,levelsDesc:o}=N;if(5!==t&&(0===t||t>i||i>o.length))return;const n=`${(new Date).toString().split("(")[0].trim()} [${o[t-1].title}] -`;N.listeners.forEach((e=>{e(n,r.join(" "))})),N.toConsole&&console.log.apply(void 0,[n.toString()[N.levelsDesc[t-1].color]].concat(r)),P(r,n)},j=(e,t,r)=>{const i=r||t.message,{level:o,levelsDesc:n}=N;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];N.toConsole&&console.log.apply(void 0,[s.toString()[N.levelsDesc[e-1].color]].concat([i[_[e-1]],"\n",a])),N.listeners.forEach((e=>{e(s,l.join(" "))})),P(l,s)},H=e=>{e>=0&&e<=N.levelsDesc.length&&(N.level=e)},U=(e,t)=>{if(N={...N,dest:e||N.dest,file:t||N.file,toFile:!0},0===N.dest.length)return A(1,"[logger] File logging initialization: no path supplied.");N.dest.endsWith("/")||(N.dest+="/")},W=m(new URL("../.",import.meta.url)),D=(e,t)=>{const r=["png","jpeg","pdf","svg"];if(t){const i=t.split(".").pop();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"},M=(e=!1,t)=>{const r=["js","css","files"];let i=e,o=!1;if(t&&e.endsWith(".json"))try{i=F(n(e,"utf8"))}catch(e){return j(2,e,"[cli] No resources found.")}else i=F(e),i&&!t&&delete i.files;for(const e in i)r.includes(e)?o||(o=!0):delete i[e];return o?(i.files&&(i.files=i.files.map((e=>e.trim())),(!i.files||i.files.length<=0)&&delete i.files),i):A(3,"[cli] No resources found.")};function F(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},G=(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,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(O).forEach((t=>{["puppeteer","highcharts"].includes(t)||(console.log(`\n${t.toUpperCase()}`.red),e(O[t]))})),console.log("\n")}const J=e=>!["false","undefined","null","NaN","0",""].includes(e)&&!!e,K=(e,t)=>{if(e&&"string"==typeof e)return(e=e.trim()).endsWith(".js")?!!t&&K(n(e,"utf8")):e.startsWith("function()")||e.startsWith("function ()")||e.startsWith("()=>")||e.startsWith("() =>")?`(${e})()`:e.replace(/;$/,"")},z=()=>{const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6};class X 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 B={cdnURL:"https://code.highcharts.com/",activeManifest:{},sources:"",hcVersion:""};let Y=!1;const Q=()=>B.hcVersion=B.sources.substring(0,B.sources.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim(),Z=async(e,t,r,i=!1)=>{e.endsWith(".js")&&(e=e.substring(0,e.length-3)),A(4,`[cache] Fetching script - ${e}.js`);const o=t?{agent:t,timeout:+process.env.PROXY_SERVER_TIMEOUT||5e3}:{},n=await S(`${e}.js`,o);if(200===n.statusCode&&"string"==typeof n.text){if(r){r[e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")]=1}return n.text}if(i)throw new X(`Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${n.statusCode}).`).setError(n);return A(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`),""},ee=async(e,t)=>{const{coreScripts:r,modules:i,indicators:o,scripts:n}=e,a="latest"!==e.version&&e.version?`${e.version}/`:"";let l;A(3,`[cache] Updating cache version to Highcharts: ${a||"latest"}.`);const c=process.env.PROXY_SERVER_HOST,p=process.env.PROXY_SERVER_PORT;if(c&&p)try{l=new h({host:c,port:+p})}catch(e){throw new X("[cache] Could not create a Proxy Agent.").setError(e)}const u={};try{return B.sources=await(async(e,t,r,i,o,n)=>{const s=[...e.map((e=>Z(`${i}${e}`,o,n,!0))),...t.map((e=>Z(`${i}${e}`,o,n))),...r.map((e=>Z(`${e}`,o)))];return(await Promise.all(s)).join(";\n")})([...r.map((e=>`${a}${e}`))],[...i.map((e=>"map"===e?`maps/${a}modules/${e}`:`${a}modules/${e}`)),...o.map((e=>`stock/${a}indicators/${e}`))],n,e.cdnURL||B.cdnURL,l,u),Q(),s(t,B.sources),u}catch(e){throw new X("[cache] Unable to update the local Highcharts cache.").setError(e)}},te=async e=>{const t=c(W,e.cachePath);let o;const a=c(t,"manifest.json"),l=c(t,"sources.js");if(Y=e,!r(t)&&i(t),!r(a)||e.forceFetch)A(3,"[cache] Fetching and caching Highcharts dependencies."),o=await ee(e,l);else{let t=!1;const r=JSON.parse(n(a));if(r.modules&&Array.isArray(r.modules)){const e={};r.modules.forEach((t=>e[t]=1)),r.modules=e}const{modules:i,coreScripts:s,indicators:c}=e,p=i.length+s.length+c.length;r.version!==e.version?(A(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),t=!0):Object.keys(r.modules||{}).length!==p?(A(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),t=!0):t=(e.modules||[]).some((e=>{if(!r.modules[e])return A(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),t?o=await ee(e,l):(A(3,"[cache] Dependency cache is up to date, proceeding."),B.sources=n(l,"utf8"),o=r.modules,Q())}await(async(e,t)=>{const r={version:e.version,modules:t||{}};B.activeManifest=r,A(3,"[cache] Writing a new manifest.");try{s(c(W,e.cachePath,"manifest.json"),JSON.stringify(r),"utf8")}catch(e){throw new X("[cache] Error writing the cache manifest.").setError(e)}})(e,o)},re=()=>c(W,Y.cachePath);var ie=async e=>!!Y&&await te(Object.assign(Y,{version:e})),oe=()=>B,ne=()=>B.hcVersion;let se={};const ae=()=>se,le=(e,t,r=[])=>{const i=q(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]:le(i[e],n,r);var o;return i};function ce(e,t={},r=""){Object.keys(e).forEach((i=>{const o=e[i],n=t&&t[i];let s;void 0===o.value?ce(o,n,`${r}.${i}`):(void 0!==n&&(o.value=n),o.envLink&&("boolean"===o.type?o.value=J([process.env[o.envLink],o.value].find((e=>e||"false"===e))):"number"===o.type?(s=+process.env[o.envLink],o.value=s>=0?s:o.value):o.type.indexOf("]")>=0&&process.env[o.envLink]?o.value=process.env[o.envLink].split(","):o.value=process.env[o.envLink]||o.value))}))}function pe(e){let t={};for(const[r,i]of Object.entries(e))t[r]=Object.prototype.hasOwnProperty.call(i,"value")?i.value:pe(i);return t}function he(e,t,r){for(;t.length>1;){const i=t.shift();return Object.prototype.hasOwnProperty.call(e,i)||(e[i]={}),e[i]=he(Object.assign({},e[i]),t,r),e}return e[t[0]]=r,e}const ue=T(64).toString("base64url"),de=w.join("tmp",`puppeteer-${ue}`),ge=[`--user-data-dir=${w.join(de,"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"],me=g.fileURLToPath(new URL(".",import.meta.url)),fe=t.readFileSync(me+"/../templates/template.html","utf8");let ve;const ye=async e=>{await e.setContent(fe),await e.addScriptTag({path:`${re()}/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()}`)}))},we=async(e,t=!1)=>{try{t?(await e.goto("about:blank"),await ye(e)):await e.evaluate((()=>{document.body.innerHTML='
'}))}catch(e){j(2,e,"[browser] Could not clear the content of the page.")}},be=async()=>{if(!ve)return!1;const e=await ve.newPage();return await e.setCacheEnabled(!1),await ye(e),e},Te=async()=>(ve?.isConnected()&&(await ve.close(),A(4,"[browser] Closed the browser.")),!0);const ke=g.fileURLToPath(new URL(".",import.meta.url)),xe=(e,t,r)=>e.evaluate(((e,t)=>window.triggerExport(e,t)),t,r);var Ee=async(e,t,r)=>{const i=[],o=async e=>{for(const e of i)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{A(4,"[export] Determining export path.");const s=r.export;await e.evaluate((()=>requestAnimationFrame((()=>{}))));const a=s?.options?.chart?.displayErrors&&oe().activeManifest.modules.debugger;let c;if(await e.evaluate((e=>window._displayErrors=e),a),t.indexOf&&(t.indexOf("=0||t.indexOf("=0)){if(A(4,"[export] Treating as SVG."),"svg"===s.type)return t;c=!0,await e.setContent((e=>`\n\n\n \n \n Highcarts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`)(t))}else A(4,"[export] Treating as config."),s.strInj?await xe(e,{chart:{height:s.height,width:s.width}},r):(t.chart.height=s.height,t.chart.width=s.width,await xe(e,t,r));const p=r.customLogic.resources;if(p){if(p.js&&i.push(await e.addScriptTag({content:p.js})),p.files)for(const t of p.files)try{const r=!t.startsWith("http");i.push(await e.addScriptTag(r?{content:n(t,"utf8")}:{url:t}))}catch(e){j(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 o of t)o&&(o=o.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),o.startsWith("http")?i.push(await e.addStyleTag({url:o})):r.customLogic.allowFileResources&&i.push(await e.addStyleTag({path:l.join(ke,o)})));i.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(s.scale)):await e.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return{chartHeight:e,chartWidth:t}})),u=Math.ceil(h?.chartHeight||s.height),d=Math.ceil(h?.chartWidth||s.width);await e.setViewport({height:u,width:d,deviceScaleFactor:c?1:parseFloat(s.scale)});const g=c?e=>{document.body.style.zoom=e,document.body.style.margin="0px"}:()=>{document.body.style.zoom=1};await e.evaluate(g,parseFloat(s.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)}})))(e);let w;if(c||await e.setViewport({width:Math.round(f),height:Math.round(m),deviceScaleFactor:parseFloat(s.scale)}),"svg"===s.type)w=await(e=>e.$eval("#container svg:first-of-type",(e=>e.outerHTML)))(e);else if("png"===s.type||"jpeg"===s.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 X("Rasterization timeout"))),o||1500)))]))(e,s.type,"base64",{width:d,height:u,x:v,y:y},s.rasterizationTimeout);else{if("pdf"!==s.type)throw new X(`[export] Unsupported output format ${s.type}.`);w=await((e,t,r,i)=>e.pdf({height:t+1,width:r,encoding:i}))(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 o(e),w}catch(t){return await o(e),t}};let Le,Se=0,Oe=0,Re=0,Ie=0,Ce=0,$e={},_e=!1;const Ne={create:async()=>{let e=!1;const t=y(),r=(new Date).getTime();try{if(e=await be(),!e||e.isClosed())throw new X("The page is invalid or closed.");A(3,`[pool] Successfully created a worker ${t} - took ${(new Date).getTime()-r} ms.`)}catch(e){throw new X("Error encountered when creating a new page.").setError(e)}return{id:t,page:e,workCount:Math.round(Math.random()*($e.workLimit/2))}},validate:async e=>$e.workLimit&&++e.workCount>$e.workLimit?(A(3,`[pool] Worker failed validation: exceeded work limit (limit is ${$e.workLimit}).`),!1):(await we(e.page,!0),!0),destroy:e=>{A(3,`[pool] Destroying pool entry ${e.id}.`),e.page&&e.page.close()}},Pe=async e=>{if($e=e&&e.pool?{...e.pool}:{},$e.listenToProcessExits&&(A(3,"[pool] Attaching exit listeners to the process."),process.on("exit",(async e=>{A(4,`Process exited with code ${e}.`),await Ae()})),process.on("SIGINT",((e,t)=>{A(4,`The ${e} event with code: ${t}.`),process.exit(1)})),process.on("SIGTERM",((e,t)=>{A(4,`The ${e} event with code: ${t}.`),process.exit(1)})),process.on("uncaughtException",(async(e,t)=>{j(1,e,`The ${t} error.`),await Ae(),process.exit(1)}))),Le=e.puppeteerArgs,await(async e=>{const t=[...ge,...e||[]];if(!ve){let e=0;const r=async()=>{try{A(3,`[browser] Attempting to get a browser instance (try ${++e}).`),ve=await b.launch({headless:"new",args:t,userDataDir:"./tmp/"})}catch(t){if(j(1,t,"[browser] Failed to launch a browser instance."),!(e<25))throw t;A(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 X("[browser] Maximum retries to open a browser instance reached.").setError(e)}if(!ve)throw new X("[browser] Cannot find a browser to open.")}return ve})(Le),A(3,`[pool] Initializing pool with workers: min ${$e.minWorkers}, max ${$e.maxWorkers}.`),_e)return A(4,"[pool] Already initialized, please kill it before creating a new one.");parseInt($e.minWorkers)>parseInt($e.maxWorkers)&&($e.minWorkers=$e.maxWorkers);try{_e=new v({...Ne,min:parseInt($e.minWorkers),max:parseInt($e.maxWorkers),acquireTimeoutMillis:$e.acquireTimeout,createTimeoutMillis:$e.createTimeout,destroyTimeoutMillis:$e.destroyTimeout,idleTimeoutMillis:$e.idleTimeout,createRetryIntervalMillis:$e.createRetryInterval,reapIntervalMillis:$e.reaperInterval,propagateCreateError:!1}),_e.on("release",(async e=>{await we(e.page,!1),A(4,`[pool] Releasing a worker with ID ${e.id}.`)})),_e.on("destroySuccess",((e,t)=>{A(4,`[pool] Destroyed a worker with ID ${t.id}.`)}));const e=[];for(let t=0;t<$e.minWorkers;t++)try{const t=await _e.acquire().promise;e.push(t)}catch(e){j(2,e,"[pool] Could not create an initial resource.")}e.forEach((e=>{_e.release(e)})),A(3,"[pool] The pool is ready"+(e.length?` with ${e.length} initial resources waiting.`:"."))}catch(e){throw await Te(),new X("[pool] Could not create the pool of workers.").setError(e)}};async function Ae(){return A(3,"[pool] Killing all pool workers and browser, if any exist."),_e?.destroyed||_e&&(await _e.destroy(),A(4,"[browser] Destroyed the pool of resources.")),Te()}const je=async(e,t)=>{let r;try{if(A(4,"[pool] Work received, starting to process."),++Oe,$e.benchmarking&&He(),!_e)throw new X("Work received, but pool has not been started.");try{A(4,"[pool] Acquiring a worker handle.");const e=z();r=await _e.acquire().promise,t.server.benchmarking&&A(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Acquired a worker handle: ${e()}ms.`)}catch(e){throw new X("Error encountered when acquiring an available entry.").setError(e)}if(A(4,"[pool] Acquired a worker handle."),!r.page)throw new X("Resolved worker page is invalid: the pool setup is wonky.");let i=(new Date).getTime();A(4,`[pool] Starting work on pool entry with ID ${r.id}.`);const o=z(),n=await Ee(r.page,e,t);if(n instanceof Error)throw"Rasterization timeout"===n.message&&(r.page.close(),r.page=await be()),new X("Error encountered during export.").setError(n);t.server.benchmarking&&A(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Exported a chart sucessfully: ${o()}ms.`),_e.release(r);const s=(new Date).getTime()-i;return Re+=s,Ce=Re/++Se,A(4,`[pool] Work completed in ${s} ms.`),{result:n,options:t}}catch(e){throw++Ie,r&&_e.release(r),new X(`[pool] In pool.postWork: ${e.message}`).setError(e)}};function He(){const{min:e,max:t}=_e;A(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),A(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),A(5,`[pool] The number of resources that are currently available: ${_e.numFree()}.`),A(5,`[pool] The number of resources that are currently acquired: ${_e.numUsed()}.`),A(5,`[pool] The number of callers waiting to acquire a resource: ${_e.numPendingAcquires()}.`)}var Ue=()=>({min:_e.min,max:_e.max,available:_e.numFree(),inUse:_e.numUsed(),pendingAcquire:_e.numPendingAcquires()}),We=()=>Oe,De=()=>Ie,Me=()=>Ce,Fe=()=>Se;let qe=!1;const Ge=async(e,t)=>{A(4,"[chart] Starting the exporting process.");const r=((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=le(t,e,I),r.export.outfile=r.export?.outfile||`chart.${r.export?.type||"png"}`,r})(e,ae()),i=r.export;if(r.payload?.svg&&""!==r.payload.svg)try{return A(4,"[chart] Attempting to export from a SVG input."),ze(r.payload.svg.trim(),r,t)}catch(e){return t(new X("[chart] Error loading SVG input.").setError(e))}if(i.infile&&i.infile.length)try{return A(4,"[chart] Attempting to export from an input file."),r.export.instr=n(i.infile,"utf8"),ze(r.export.instr.trim(),r,t)}catch(e){return t(new X("[chart] Error loading input file.").setError(e))}if(i.instr&&""!==i.instr||i.options&&""!==i.options)try{return A(4,"[chart] Attempting to export from a raw input."),J(r.customLogic?.allowCodeExecution)?Ke(r,t):"string"==typeof i.instr?ze(i.instr.trim(),r,t):Je(r,i.instr||i.options,t)}catch(e){return t(new X("[chart] Error loading raw input.").setError(e))}return t(new X("[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||F(e.export?.instr),i=F(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(e,t,r,i)=>{let{export:o,customLogic:s}=e;const a="boolean"==typeof s.allowCodeExecution?s.allowCodeExecution:qe;if(s){if(a)if("string"==typeof e.customLogic.resources)e.customLogic.resources=M(e.customLogic.resources,J(e.customLogic.allowFileResources));else if(!e.customLogic.resources)try{const t=n("resources.json","utf8");e.customLogic.resources=M(t,J(e.customLogic.allowFileResources))}catch(e){j(2,e,"[chart] Unable to load the default resources.json file.")}}else s=e.customLogic={};if(!a&&s){if(s.callback||s.resources||s.customCode)return r(new X("[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server."));s.callback=!1,s.resources=!1,s.customCode=!1}if(t&&(t.chart=t.chart||{},t.exporting=t.exporting||{},t.exporting.enabled=!1),o.constr=o.constr||"chart",o.type=D(o.type,o.outfile),"svg"===o.type&&(o.width=!1),["globalOptions","themeOptions"].forEach((e=>{try{o&&o[e]&&("string"==typeof o[e]&&o[e].endsWith(".json")?o[e]=F(n(o[e],"utf8"),!0):o[e]=F(o[e],!0))}catch(t){o[e]={},j(2,t,`[chart] The '${e}' 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=n(s.callback,"utf8")}catch(e){s.callback=!1,j(2,e,"[chart] The 'callback' cannot be loaded.")}else s.callback=!1;e.export={...e.export,...Ve(e)};try{return r(!1,await je(o.strInj||t||i,e))}catch(e){return r(e)}},Ke=(e,t)=>{try{let r,i=e.export.instr||e.export.options;return"string"!=typeof i&&(r=i=G(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 X(`[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:i}=t.customLogic;if(e.indexOf("=0||e.indexOf("=0)return A(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 J(i)?Ke(t,r):r(new X("[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=(e,t,r,i)=>{j(1,e),"development"!==process.env.NODE_ENV&&delete e.stack,i(e)},Be=(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 Ye=(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=L({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&&(A(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(o),A(3,`[rate limiting] Enabled rate limiting with ${i.max} requests per ${i.window} minute for each IP, trusting proxy: ${i.trustProxy}.`)};class Qe extends X{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=[],it=(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},ot=async(e,t,r)=>{try{const r=z(),o=y().replace(/-/g,""),n=ae(),s=e.body,a=++et;let l=D(s.type);if(!s||"object"==typeof(i=s)&&null!==i&&0===Object.keys(i).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=F(s.infile||s.options||s.data);if(!c&&!s.svg)throw A(2,`The request with ID ${o} from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Payload received: ${JSON.stringify(s)}.`),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=it(tt,e,t,{id:a,uniqueId:o,type:l,body:s}),!0!==p)return t.send(p);let h=!1;e.socket.on("close",(()=>{h=!0})),A(4,`[export] Got an incoming HTTP request with ID ${o}.`),s.constr="string"==typeof s.constr&&s.constr||"chart";const u={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:F(s.globalOptions,!0),themeOptions:F(s.themeOptions,!0)},customLogic:{allowCodeExecution:qe,allowFileResources:!1,resources:F(s.resources,!0),callback:s.callback,customCode:s.customCode}};c&&(u.export.instr=G(c,u.customLogic.allowCodeExecution));const d=le(n,u);if(d.export.options=c,d.payload={svg:s.svg||!1,b64:s.b64||!1,noDownload:s.noDownload||!1,requestId:o},s.svg&&(e=>["localhost","(10).(.*).(.*).(.*)","(127).(.*).(.*).(.*)","(172).(1[6-9]|2[0-9]|3[0-1]).(.*).(.*)","(192).(168).(.*).(.*)"].some((t=>e.match(`xlink:href="(?:(http://|https://))?${t}`))))(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 Ge(d,((i,c)=>{if(e.socket.removeAllListeners("close"),n.server.benchmarking&&A(5,`[benchmark] Request with ID ${o} - After the whole exporting process: ${r()}ms.`),h)return A(3,"[export] The client closed the connection before the chart finished processing.");if(i)throw i;if(!c||!c.result)throw new Qe(`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,it(rt,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 nt=JSON.parse(n(c(W,"package.json"))),st=new Date;const at=x();at.disable("x-powered-by"),at.use(k());const lt=E.memoryStorage(),ct=E({storage:lt,limits:{fieldSize:52428800}});at.use(x.json({limit:52428800})),at.use(x.urlencoded({extended:!0,limit:52428800})),at.use(ct.none());const pt=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}`)}))}))},ht=async e=>{try{if(!e.enable)return!1;if(!e.ssl.force){const t=u.createServer(at);pt(t),t.listen(e.port,e.host),A(3,`[server] Started HTTP server on ${e.host}:${e.port}.`)}if(e.ssl.enable){let t,r;try{t=await a.readFile(p.join(e.ssl.certPath,"server.key"),"utf8"),r=await a.readFile(p.join(e.ssl.certPath,"server.crt"),"utf8")}catch(t){A(2,`[server] Unable to load key/certificate from the '${e.ssl.certPath}' path. Could not run secured layer server.`)}if(t&&r){const t=d.createServer(at);pt(t),t.listen(e.ssl.port,e.host),A(3,`[server] Started HTTPS server on ${e.host}:${e.ssl.port}.`)}}e.rateLimiting&&e.rateLimiting.enable&&![0,NaN].includes(e.rateLimiting.maxRequests)&&Ye(at,e.rateLimiting),at.use(x.static(p.join(W,"public"))),(e=>{!!e&&e.get("/health",((e,t)=>{t.send({status:"OK",bootTime:st,uptime:Math.floor(((new Date).getTime()-st.getTime())/1e3/60)+" minutes",version:nt.version,highchartsVersion:ne(),averageProcessingTime:Me(),performedExports:Fe(),failedExports:De(),exportAttempts:We(),sucessRatio:Fe()/We()*100,pool:Ue()})}))})(at),(e=>{e.post("/",ot),e.post("/:filename",ot)})(at),(e=>{!!e&&e.get("/",((e,t)=>{t.sendFile(c(W,"public","index.html"))}))})(at),(e=>{!!e&&e.post("/version/change/:newVersion",(async(e,t,r)=>{try{const r=process.env.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 i=e.get("hc-auth");if(!i||i!==r)throw new Qe("Invalid or missing token: Set the token in the hc-auth header.",401);const o=e.params.newVersion;if(!o)throw new Qe("No new version supplied.",400);try{await ie(o)}catch(e){throw new Qe(`Version change: ${e.message}`,e.statusCode).setError(e)}t.status(200).send({statusCode:200,version:ne(),message:`Successfully updated Highcharts to version: ${o}.`})}catch(e){r(e)}}))})(at),(e=>{e.use(Xe),e.use(Be)})(at)}catch(e){throw new X("[server] Could not configure and start the server.").setError(e)}};var ut={startServer:ht,enableRateLimiting:e=>Ye(at,e),getExpress:()=>x,getApp:()=>at,use:(e,...t)=>{at.use(e,...t)},get:(e,...t)=>{at.get(e,...t)},post:(e,...t)=>{at.post(e,...t)}};e.config();var dt={server:ut,startServer:ht,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(n(r))}catch(e){j(2,e,`[config] Unable to load the configuration from the ${r} file.`)}}return{}}(t)),ce(O,se),se=pe(O),e&&(se=le(se,e,I)),t?.length&&(se=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]=J(t[o]):"number"===a?e[r]=+t[o]:a.indexOf("]")>=0?e[r]=t[o].split(","):e[r]=t[o]:(A(2,`[config] Missing value for the '${n}' argument. Using the default value.`),i=!0)),e[r])),e)}i&&V();return e}(se,t,O)),se),initExport:async e=>{var t;return t=e.customLogic&&e.customLogic.allowCodeExecution,qe=J(t),(e=>{H(e&&parseInt(e.level)),e&&e.dest&&U(e.dest,e.file||"highcharts-export-server.log")})(e.logging),await te(e.highcharts||{version:"latest"}),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 Ge(e,(async(e,t)=>{if(e)throw e;const{outfile:r,type:i}=t.options.export;s(r||`chart.${i}`,"svg"!==i?Buffer.from(t.result,"base64"):t.result),await Ae()}))},batchExport:async e=>{const t=[];for(let r of e.export.batch.split(";"))r=r.split("="),2===r.length&&t.push(Ge({...e,export:{...e.export,infile:r[0],outfile:r[1]}},((e,t)=>{if(e)throw e;s(t.options.export.outfile,Buffer.from(t.result,"base64"))})));try{await Promise.all(t),await Ae()}catch(e){throw new X("[chart] Error encountered during batch export.").setError(e)}},startExport:Ge,killPool:Ae,log:A,logWithStack:j,setLogLevel:H,enableFileLogging:U,mapToNewConfig:e=>{const t={};for(const[r,i]of Object.entries(e)){const e=C[r]?C[r].split("."):[];e.reduce(((t,r,o)=>t[r]=e.length-1===o?i:t[r]||{}),t)}return t},manualConfig:async e=>{let t={};r(e)&&(t=JSON.parse(n(e,"utf8")));const i=Object.keys(R).map((e=>({title:`${e} options`,value:e})));return f({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(r,i)=>{let o=0,n=[];for(const e of i)R[e]=R[e].map((t=>({...t,section:e}))),n=[...n,...R[e]];return await f(n,{onSubmit:async(r,i)=>{if("modules"===r.name?(i=i.length?i.map((e=>r.choices[e])):r.choices,t[r.section][r.name]=i):t[r.section]=he(Object.assign({},t[r.section]||{}),r.name.split("."),r.choices?r.choices[i]:i),++o===n.length){try{await a.writeFile(e,JSON.stringify(t,null,2),"utf8")}catch(t){j(1,t,`[config] An error occurred while creating the ${e} file.`)}return!0}}}),!0}})},printLogo:e=>{const t=JSON.parse(n(c(W,"package.json"))).version;e?console.log(`Starting Highcharts Export Server v${t}...`):console.log(n(W+"/msg/startup.msg").toString().bold.yellow,`v${t}`)},printUsage:V};export{dt as default}; +import"colors";import e from"dotenv";import t,{existsSync as r,mkdirSync as i,appendFile as o,readFileSync as n,writeFileSync as s,promises as a}from"fs";import l,{join as c,posix as p}from"path";import{HttpsProxyAgent as h}from"https-proxy-agent";import u from"http";import d from"https";import*as g from"url";import{fileURLToPath as m}from"url";import f from"prompts";import{Pool as v}from"tarn";import{v4 as y}from"uuid";import w from"node:path";import b from"puppeteer";import{randomBytes as T}from"node:crypto";import k from"cors";import x from"express";import E from"multer";import L from"express-rate-limit";async function S(e,t={}){return new Promise(((r,i)=>{const o=(e=>e.startsWith("https")?d:u)(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)}))}))}const O={puppeteer:{args:{value:[],type:"string[]",description:"Arguments array to send to Puppeteer."}},highcharts:{version:{value:"latest",envLink:"HIGHCHARTS_VERSION",type:"string",description:"The Highcharts version to be used."},cdnURL:{value:"https://code.highcharts.com/",envLink:"HIGHCHARTS_CDN_URL",type:"string",description:"The CDN URL for Highcharts scripts to be used."},coreScripts:{envLink:"HIGHCHARTS_CORE_SCRIPTS",value:["highcharts","highcharts-more","highcharts-3d"],type:"string[]",description:"The core Highcharts scripts to fetch."},modules:{envLink:"HIGHCHARTS_MODULES",value:["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"],type:"string[]",description:"The modules of Highcharts to fetch."},indicators:{envLink:"HIGHCHARTS_INDICATORS",value:["indicators-all"],type:"string[]",description:"The indicators of Highcharts to fetch."},scripts:{value:["https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js","https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.34/moment-timezone-with-data.min.js"],type:"string[]",description:"Additional optional scripts or dependencies to fetch."},forceFetch:{envLink:"HIGHCHARTS_FORCE_FETCH",value:!1,type:"boolean",description:"The flag to determine whether to refetch all scripts after each server rerun."},cachePath:{envLink:"HIGHCHARTS_CACHE_PATH",value:".cache",type:"string",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:{envLink:"EXPORT_TYPE",value:"png",type:"string",description:"The file export format. It can be jpeg, png, pdf, or svg."},constr:{envLink:"EXPORT_CONSTR",value:"chart",type:"string",description:"The constructor to use. Can be chart, stockChart, mapChart, or ganttChart."},defaultHeight:{envLink:"EXPORT_DEFAULT_HEIGHT",value:400,type:"number",description:"the default height of the exported chart. Used when no value is set."},defaultWidth:{envLink:"EXPORT_DEFAULT_WIDTH",value:600,type:"number",description:"The default width of the exported chart. Used when no value is set."},defaultScale:{envLink:"EXPORT_DEFAULT_SCALE",value:1,type:"number",description:"The default scale of the exported chart. Used when no value is set."},height:{type:"number",value:!1,description:"The height of the exported chart, overriding the option in the chart settings."},width:{type:"number",value:!1,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:{envLink:"EXPORT_RASTERIZATION_TIMEOUT",value:1500,type:"number",description:"The duration in milliseconds to wait for rendering a webpage."}},customLogic:{allowCodeExecution:{envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",value:!1,type:"boolean",description:"Controls whether the execution of arbitrary code is allowed during the exporting process."},allowFileResources:{envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",value:!1,type:"boolean",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:{envLink:"SERVER_ENABLE",value:!1,type:"boolean",cliName:"enableServer",description:"When set to true, the server starts on the local IP address 0.0.0.0."},host:{envLink:"SERVER_HOST",value:"0.0.0.0",type:"string",description:"The hostname of the server. Additionally, it starts a server on the provided hostname."},port:{envLink:"SERVER_PORT",value:7801,type:"number",description:"The server port when enabled."},benchmarking:{envLink:"SERVER_BENCHMARKING",value:!1,type:"boolean",cliName:"serverBenchmarking",description:"Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request."},ssl:{enable:{envLink:"SERVER_SSL_ENABLE",value:!1,type:"boolean",cliName:"enableSsl",description:"Enables or disables the SSL protocol."},force:{envLink:"SERVER_SSL_FORCE",value:!1,type:"boolean",cliName:"sslForced",legacyName:"sslOnly",description:"When set to true, the server is forced to serve only over HTTPS."},port:{envLink:"SERVER_SSL_PORT",value:443,type:"number",cliName:"sslPort",description:"The port on which to run the SSL server."},certPath:{envLink:"SERVER_SSL_CERT_PATH",value:"",type:"string",legacyName:"sslPath",description:"The path to the SSL certificate/key file."}},rateLimiting:{enable:{envLink:"SERVER_RATE_LIMITING_ENABLE",value:!1,type:"boolean",cliName:"enableRateLimiting",description:"Enables rate limiting for the server."},maxRequests:{envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",value:10,type:"number",legacyName:"rateLimit",description:"The maximum number of requests allowed in one minute."},window:{envLink:"SERVER_RATE_LIMITING_WINDOW",value:1,type:"number",description:"The time window, in minutes, for the rate limiting."},delay:{envLink:"SERVER_RATE_LIMITING_DELAY",value:0,type:"number",description:"The delay duration for each successive request before reaching the maximum limit."},trustProxy:{envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",value:!1,type:"boolean",description:"Set this to true if the server is behind a load balancer."},skipKey:{envLink:"SERVER_RATE_LIMITING_SKIP_KEY",value:"",type:"string",description:"Allows bypassing the rate limiter and should be provided with the skipToken argument."},skipToken:{envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",value:"",type:"string",description:"Allows bypassing the rate limiter and should be provided with the skipKey argument."}}},pool:{minWorkers:{envLink:"POOL_MIN_WORKERS",value:4,type:"number",description:"The number of minimum and initial pool workers to spawn."},maxWorkers:{envLink:"POOL_MAX_WORKERS",value:8,type:"number",legacyName:"workers",description:"The number of maximum pool workers to spawn."},workLimit:{envLink:"POOL_WORK_LIMIT",value:40,type:"number",description:"The number of work pieces that can be performed before restarting the worker process."},acquireTimeout:{envLink:"POOL_ACQUIRE_TIMEOUT",value:5e3,type:"number",description:"The duration, in milliseconds, to wait for acquiring a resource."},createTimeout:{envLink:"POOL_CREATE_TIMEOUT",value:5e3,type:"number",description:"The duration, in milliseconds, to wait for creating a resource."},destroyTimeout:{envLink:"POOL_DESTROY_TIMEOUT",value:5e3,type:"number",description:"The duration, in milliseconds, to wait for destroying a resource."},idleTimeout:{envLink:"POOL_IDLE_TIMEOUT",value:3e4,type:"number",description:"The duration, in milliseconds, after which an idle resource is destroyed."},createRetryInterval:{envLink:"POOL_CREATE_RETRY_INTERVAL",value:200,type:"number",description:"The duration, in milliseconds, to wait before retrying the create process in case of a failure."},reaperInterval:{envLink:"POOL_REAPER_INTERVAL",value:1e3,type:"number",description:"The duration, in milliseconds, after which the check for idle resources to destroy is triggered."},benchmarking:{envLink:"POOL_BENCHMARKING",value:!1,type:"boolean",cliName:"poolBenchmarking",description:"Indicate whether to show statistics for the pool of resources or not."},listenToProcessExits:{envLink:"POOL_LISTEN_TO_PROCESS_EXITS",value:!0,type:"boolean",description:"Decides whether or not to attach process.exit handlers."}},logging:{level:{envLink:"LOGGING_LEVEL",value:4,type:"number",cliName:"logLevel",description:"The logging level to be used."},file:{envLink:"LOGGING_FILE",value:"highcharts-export-server.log",type:"string",cliName:"logFile",description:"The name of a log file. The logDest option also needs to be set to enable file logging."},dest:{envLink:"LOGGING_DEST",value:"log/",type:"string",cliName:"logDest",description:"The path to store log files. This also enables file logging."}},ui:{enable:{envLink:"UI_ENABLE",value:!1,type:"boolean",cliName:"enableUi",description:"Enables or disables the user interface (UI) for the export server."},route:{envLink:"UI_ROUTE",value:"/",type:"string",cliName:"uiRoute",description:"The endpoint route to which the user interface (UI) should be attached."}},other:{noLogo:{envLink:"OTHER_NO_LOGO",value:!1,type:"boolean",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:O.puppeteer.args.value.join(","),separator:","}],highcharts:[{type:"text",name:"version",message:"Highcharts version",initial:O.highcharts.version.value},{type:"text",name:"cdnURL",message:"The URL of CDN",initial:O.highcharts.cdnURL.value},{type:"multiselect",name:"modules",message:"Available modules",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:O.highcharts.modules.value},{type:"list",name:"scripts",message:"Custom scripts",initial:O.highcharts.scripts.value.join(","),separator:","},{type:"toggle",name:"forceFetch",message:"Force re-fetch the scripts",initial:O.highcharts.forceFetch.value},{type:"text",name:"cachePath",message:"The path to the cache directory",initial:O.highcharts.cachePath.value}],export:[{type:"select",name:"type",message:"The default export file type",hint:`Default: ${O.export.type.value}`,initial:0,choices:["png","jpeg","pdf","svg"]},{type:"select",name:"constr",message:"The default constructor for Highcharts",hint:`Default: ${O.export.constr.value}`,initial:0,choices:["chart","stockChart","mapChart","ganttChart"]},{type:"number",name:"defaultHeight",message:"The default fallback height of the exported chart",initial:O.export.defaultHeight.value},{type:"number",name:"defaultWidth",message:"The default fallback width of the exported chart",initial:O.export.defaultWidth.value},{type:"number",name:"defaultScale",message:"The default fallback scale of the exported chart",initial:O.export.defaultScale.value,min:.1,max:5},{type:"number",name:"rasterizationTimeout",message:"The rendering webpage timeout in milliseconds",initial:O.export.rasterizationTimeout.value}],customLogic:[{type:"toggle",name:"allowCodeExecution",message:"Enable execution of custom code",initial:O.customLogic.allowCodeExecution.value},{type:"toggle",name:"allowFileResources",message:"Enable file resources",initial:O.customLogic.allowFileResources.value}],server:[{type:"toggle",name:"enable",message:"Starts the server on 0.0.0.0",initial:O.server.enable.value},{type:"text",name:"host",message:"Server hostname",initial:O.server.host.value},{type:"number",name:"port",message:"Server port",initial:O.server.port.value},{type:"toggle",name:"benchmarking",message:"Enable server benchmarking",initial:O.server.benchmarking.value},{type:"toggle",name:"ssl.enable",message:"Enable SSL protocol",initial:O.server.ssl.enable.value},{type:"toggle",name:"ssl.force",message:"Force serving only over HTTPS",initial:O.server.ssl.force.value},{type:"number",name:"ssl.port",message:"SSL server port",initial:O.server.ssl.port.value},{type:"text",name:"ssl.certPath",message:"The path to find the SSL certificate/key",initial:O.server.ssl.certPath.value},{type:"toggle",name:"rateLimiting.enable",message:"Enable rate limiting",initial:O.server.rateLimiting.enable.value},{type:"number",name:"rateLimiting.maxRequests",message:"The maximum requests allowed per minute",initial:O.server.rateLimiting.maxRequests.value},{type:"number",name:"rateLimiting.window",message:"The rate-limiting time window in minutes",initial:O.server.rateLimiting.window.value},{type:"number",name:"rateLimiting.delay",message:"The delay for each successive request before reaching the maximum",initial:O.server.rateLimiting.delay.value},{type:"toggle",name:"rateLimiting.trustProxy",message:"Set to true if behind a load balancer",initial:O.server.rateLimiting.trustProxy.value},{type:"text",name:"rateLimiting.skipKey",message:"Allows bypassing the rate limiter when provided with the skipToken argument",initial:O.server.rateLimiting.skipKey.value},{type:"text",name:"rateLimiting.skipToken",message:"Allows bypassing the rate limiter when provided with the skipKey argument",initial:O.server.rateLimiting.skipToken.value}],pool:[{type:"number",name:"minWorkers",message:"The initial number of workers to spawn",initial:O.pool.minWorkers.value},{type:"number",name:"maxWorkers",message:"The maximum number of workers to spawn",initial:O.pool.maxWorkers.value},{type:"number",name:"workLimit",message:"The pieces of work that can be performed before restarting a Puppeteer process",initial:O.pool.workLimit.value},{type:"number",name:"acquireTimeout",message:"The number of milliseconds to wait for acquiring a resource",initial:O.pool.acquireTimeout.value},{type:"number",name:"createTimeout",message:"The number of milliseconds to wait for creating a resource",initial:O.pool.createTimeout.value},{type:"number",name:"destroyTimeout",message:"The number of milliseconds to wait for destroying a resource",initial:O.pool.destroyTimeout.value},{type:"number",name:"idleTimeout",message:"The number of milliseconds after an idle resource is destroyed",initial:O.pool.idleTimeout.value},{type:"number",name:"createRetryInterval",message:"The retry interval in milliseconds after a create process fails",initial:O.pool.createRetryInterval.value},{type:"number",name:"reaperInterval",message:"The reaper interval in milliseconds after triggering the check for idle resources to destroy",initial:O.pool.reaperInterval.value},{type:"toggle",name:"benchmarking",message:"Enable benchmarking for a resource pool",initial:O.pool.benchmarking.value},{type:"toggle",name:"listenToProcessExits",message:"Set to false to skip attaching process.exit handlers",initial:O.pool.listenToProcessExits.value}],logging:[{type:"number",name:"level",message:"The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)",initial:O.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:O.logging.file.value},{type:"text",name:"dest",message:"The path to log files. Enables file logging",initial:O.logging.dest.value}],ui:[{type:"toggle",name:"enable",message:"Enable UI for the export server",initial:O.ui.enable.value},{type:"text",name:"route",message:"A route to attach the UI",initial:O.ui.route.value}],other:[{type:"toggle",name:"noLogo",message:"Skip printing the logo on startup. Replaced by simple text",initial:O.other.noLogo.value}]},I=["options","globalOptions","themeOptions","resources","payload"],C={},$=(e,t="")=>{Object.keys(e).forEach((r=>{if(!["puppeteer","highcharts"].includes(r)){const i=e[r];void 0===i.value?$(i,`${t}.${r}`):(C[i.cliName||r]=`${t}.${r}`.substring(1),void 0!==i.legacyName&&(C[i.legacyName]=`${t}.${r}`.substring(1)))}}))};$(O);const _=["red","yellow","blue","gray","green"];let N={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:_[0]},{title:"warning",color:_[1]},{title:"notice",color:_[2]},{title:"verbose",color:_[3]},{title:"benchmark",color:_[4]}],listeners:[]};for(const[e,t]of Object.entries(O.logging))N[e]=t.value;const P=(e,t)=>{N.toFile&&(N.pathCreated||(!r(N.dest)&&i(N.dest),N.pathCreated=!0),o(`${N.dest}${N.file}`,[t].concat(e).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),N.toFile=!1)})))},A=(...e)=>{const[t,...r]=e,{level:i,levelsDesc:o}=N;if(5!==t&&(0===t||t>i||i>o.length))return;const n=`${(new Date).toString().split("(")[0].trim()} [${o[t-1].title}] -`;N.listeners.forEach((e=>{e(n,r.join(" "))})),N.toConsole&&console.log.apply(void 0,[n.toString()[N.levelsDesc[t-1].color]].concat(r)),P(r,n)},j=(e,t,r)=>{const i=r||t.message,{level:o,levelsDesc:n}=N;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];N.toConsole&&console.log.apply(void 0,[s.toString()[N.levelsDesc[e-1].color]].concat([i[_[e-1]],"\n",a])),N.listeners.forEach((e=>{e(s,l.join(" "))})),P(l,s)},H=e=>{e>=0&&e<=N.levelsDesc.length&&(N.level=e)},U=(e,t)=>{if(N={...N,dest:e||N.dest,file:t||N.file,toFile:!0},0===N.dest.length)return A(1,"[logger] File logging initialization: no path supplied.");N.dest.endsWith("/")||(N.dest+="/")},W=m(new URL("../.",import.meta.url)),D=(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"},M=(e=!1,t)=>{const r=["js","css","files"];let i=e,o=!1;if(t&&e.endsWith(".json"))try{i=F(n(e,"utf8"))}catch(e){return j(2,e,"[cli] No resources found.")}else i=F(e),i&&!t&&delete i.files;for(const e in i)r.includes(e)?o||(o=!0):delete i[e];return o?(i.files&&(i.files=i.files.map((e=>e.trim())),(!i.files||i.files.length<=0)&&delete i.files),i):A(3,"[cli] No resources found.")};function F(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},G=(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,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(O).forEach((t=>{["puppeteer","highcharts"].includes(t)||(console.log(`\n${t.toUpperCase()}`.red),e(O[t]))})),console.log("\n")}const J=e=>!["false","undefined","null","NaN","0",""].includes(e)&&!!e,K=(e,t)=>{if(e&&"string"==typeof e)return(e=e.trim()).endsWith(".js")?!!t&&K(n(e,"utf8")):e.startsWith("function()")||e.startsWith("function ()")||e.startsWith("()=>")||e.startsWith("() =>")?`(${e})()`:e.replace(/;$/,"")},z=()=>{const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6};class X 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 B={cdnURL:"https://code.highcharts.com/",activeManifest:{},sources:"",hcVersion:""};let Y=!1;const Q=()=>B.hcVersion=B.sources.substring(0,B.sources.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim(),Z=async(e,t,r,i=!1)=>{e.endsWith(".js")&&(e=e.substring(0,e.length-3)),A(4,`[cache] Fetching script - ${e}.js`);const o=t?{agent:t,timeout:+process.env.PROXY_SERVER_TIMEOUT||5e3}:{},n=await S(`${e}.js`,o);if(200===n.statusCode&&"string"==typeof n.text){if(r){r[e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")]=1}return n.text}if(i)throw new X(`Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${n.statusCode}).`).setError(n);return A(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`),""},ee=async(e,t)=>{const{coreScripts:r,modules:i,indicators:o,scripts:n}=e,a="latest"!==e.version&&e.version?`${e.version}/`:"";let l;A(3,`[cache] Updating cache version to Highcharts: ${a||"latest"}.`);const c=process.env.PROXY_SERVER_HOST,p=process.env.PROXY_SERVER_PORT;if(c&&p)try{l=new h({host:c,port:+p})}catch(e){throw new X("[cache] Could not create a Proxy Agent.").setError(e)}const u={};try{return B.sources=await(async(e,t,r,i,o,n)=>{const s=[...e.map((e=>Z(`${i}${e}`,o,n,!0))),...t.map((e=>Z(`${i}${e}`,o,n))),...r.map((e=>Z(`${e}`,o)))];return(await Promise.all(s)).join(";\n")})([...r.map((e=>`${a}${e}`))],[...i.map((e=>"map"===e?`maps/${a}modules/${e}`:`${a}modules/${e}`)),...o.map((e=>`stock/${a}indicators/${e}`))],n,e.cdnURL||B.cdnURL,l,u),Q(),s(t,B.sources),u}catch(e){throw new X("[cache] Unable to update the local Highcharts cache.").setError(e)}},te=async e=>{const t=c(W,e.cachePath);let o;const a=c(t,"manifest.json"),l=c(t,"sources.js");if(Y=e,!r(t)&&i(t),!r(a)||e.forceFetch)A(3,"[cache] Fetching and caching Highcharts dependencies."),o=await ee(e,l);else{let t=!1;const r=JSON.parse(n(a));if(r.modules&&Array.isArray(r.modules)){const e={};r.modules.forEach((t=>e[t]=1)),r.modules=e}const{modules:i,coreScripts:s,indicators:c}=e,p=i.length+s.length+c.length;r.version!==e.version?(A(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),t=!0):Object.keys(r.modules||{}).length!==p?(A(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),t=!0):t=(e.modules||[]).some((e=>{if(!r.modules[e])return A(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),t?o=await ee(e,l):(A(3,"[cache] Dependency cache is up to date, proceeding."),B.sources=n(l,"utf8"),o=r.modules,Q())}await(async(e,t)=>{const r={version:e.version,modules:t||{}};B.activeManifest=r,A(3,"[cache] Writing a new manifest.");try{s(c(W,e.cachePath,"manifest.json"),JSON.stringify(r),"utf8")}catch(e){throw new X("[cache] Error writing the cache manifest.").setError(e)}})(e,o)},re=()=>c(W,Y.cachePath);var ie=async e=>!!Y&&await te(Object.assign(Y,{version:e})),oe=()=>B,ne=()=>B.hcVersion;let se={};const ae=()=>se,le=(e,t,r=[])=>{const i=q(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]:le(i[e],n,r);var o;return i};function ce(e,t={},r=""){Object.keys(e).forEach((i=>{const o=e[i],n=t&&t[i];let s;void 0===o.value?ce(o,n,`${r}.${i}`):(void 0!==n&&(o.value=n),o.envLink&&("boolean"===o.type?o.value=J([process.env[o.envLink],o.value].find((e=>e||"false"===e))):"number"===o.type?(s=+process.env[o.envLink],o.value=s>=0?s:o.value):o.type.indexOf("]")>=0&&process.env[o.envLink]?o.value=process.env[o.envLink].split(","):o.value=process.env[o.envLink]||o.value))}))}function pe(e){let t={};for(const[r,i]of Object.entries(e))t[r]=Object.prototype.hasOwnProperty.call(i,"value")?i.value:pe(i);return t}function he(e,t,r){for(;t.length>1;){const i=t.shift();return Object.prototype.hasOwnProperty.call(e,i)||(e[i]={}),e[i]=he(Object.assign({},e[i]),t,r),e}return e[t[0]]=r,e}const ue=T(64).toString("base64url"),de=w.join("tmp",`puppeteer-${ue}`),ge=[`--user-data-dir=${w.join(de,"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"],me=g.fileURLToPath(new URL(".",import.meta.url)),fe=t.readFileSync(me+"/../templates/template.html","utf8");let ve;const ye=async e=>{await e.setContent(fe),await e.addScriptTag({path:`${re()}/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()}`)}))},we=async(e,t=!1)=>{try{t?(await e.goto("about:blank"),await ye(e)):await e.evaluate((()=>{document.body.innerHTML='
'}))}catch(e){j(2,e,"[browser] Could not clear the content of the page.")}},be=async()=>{if(!ve)return!1;const e=await ve.newPage();return await e.setCacheEnabled(!1),await ye(e),e},Te=async()=>(ve?.isConnected()&&(await ve.close(),A(4,"[browser] Closed the browser.")),!0);const ke=g.fileURLToPath(new URL(".",import.meta.url)),xe=(e,t,r)=>e.evaluate(((e,t)=>window.triggerExport(e,t)),t,r);var Ee=async(e,t,r)=>{const i=[],o=async e=>{for(const e of i)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{A(4,"[export] Determining export path.");const s=r.export;await e.evaluate((()=>requestAnimationFrame((()=>{}))));const a=s?.options?.chart?.displayErrors&&oe().activeManifest.modules.debugger;let c;if(await e.evaluate((e=>window._displayErrors=e),a),t.indexOf&&(t.indexOf("=0||t.indexOf("=0)){if(A(4,"[export] Treating as SVG."),"svg"===s.type)return t;c=!0,await e.setContent((e=>`\n\n\n \n \n Highcarts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`)(t))}else A(4,"[export] Treating as config."),s.strInj?await xe(e,{chart:{height:s.height,width:s.width}},r):(t.chart.height=s.height,t.chart.width=s.width,await xe(e,t,r));const p=r.customLogic.resources;if(p){if(p.js&&i.push(await e.addScriptTag({content:p.js})),p.files)for(const t of p.files)try{const r=!t.startsWith("http");i.push(await e.addScriptTag(r?{content:n(t,"utf8")}:{url:t}))}catch(e){j(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 o of t)o&&(o=o.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),o.startsWith("http")?i.push(await e.addStyleTag({url:o})):r.customLogic.allowFileResources&&i.push(await e.addStyleTag({path:l.join(ke,o)})));i.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(s.scale)):await e.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return{chartHeight:e,chartWidth:t}})),u=Math.ceil(h?.chartHeight||s.height),d=Math.ceil(h?.chartWidth||s.width);await e.setViewport({height:u,width:d,deviceScaleFactor:c?1:parseFloat(s.scale)});const g=c?e=>{document.body.style.zoom=e,document.body.style.margin="0px"}:()=>{document.body.style.zoom=1};await e.evaluate(g,parseFloat(s.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)}})))(e);let w;if(c||await e.setViewport({width:Math.round(f),height:Math.round(m),deviceScaleFactor:parseFloat(s.scale)}),"svg"===s.type)w=await(e=>e.$eval("#container svg:first-of-type",(e=>e.outerHTML)))(e);else if(["png","jpeg"].includes(s.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 X("Rasterization timeout"))),o||1500)))]))(e,s.type,"base64",{width:d,height:u,x:v,y:y},s.rasterizationTimeout);else{if("pdf"!==s.type)throw new X(`[export] Unsupported output format ${s.type}.`);w=await((e,t,r,i)=>e.pdf({height:t+1,width:r,encoding:i}))(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 o(e),w}catch(t){return await o(e),t}};let Le,Se=0,Oe=0,Re=0,Ie=0,Ce=0,$e={},_e=!1;const Ne={create:async()=>{let e=!1;const t=y(),r=(new Date).getTime();try{if(e=await be(),!e||e.isClosed())throw new X("The page is invalid or closed.");A(3,`[pool] Successfully created a worker ${t} - took ${(new Date).getTime()-r} ms.`)}catch(e){throw new X("Error encountered when creating a new page.").setError(e)}return{id:t,page:e,workCount:Math.round(Math.random()*($e.workLimit/2))}},validate:async e=>$e.workLimit&&++e.workCount>$e.workLimit?(A(3,`[pool] Worker failed validation: exceeded work limit (limit is ${$e.workLimit}).`),!1):(await we(e.page,!0),!0),destroy:e=>{A(3,`[pool] Destroying pool entry ${e.id}.`),e.page&&e.page.close()}},Pe=async e=>{if($e=e&&e.pool?{...e.pool}:{},$e.listenToProcessExits&&(A(3,"[pool] Attaching exit listeners to the process."),process.on("exit",(async e=>{A(4,`Process exited with code ${e}.`),await Ae()})),process.on("SIGINT",((e,t)=>{A(4,`The ${e} event with code: ${t}.`),process.exit(1)})),process.on("SIGTERM",((e,t)=>{A(4,`The ${e} event with code: ${t}.`),process.exit(1)})),process.on("uncaughtException",(async(e,t)=>{j(1,e,`The ${t} error.`),await Ae(),process.exit(1)}))),Le=e.puppeteerArgs,await(async e=>{const t=[...ge,...e||[]];if(!ve){let e=0;const r=async()=>{try{A(3,`[browser] Attempting to get a browser instance (try ${++e}).`),ve=await b.launch({headless:"new",args:t,userDataDir:"./tmp/"})}catch(t){if(j(1,t,"[browser] Failed to launch a browser instance."),!(e<25))throw t;A(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 X("[browser] Maximum retries to open a browser instance reached.").setError(e)}if(!ve)throw new X("[browser] Cannot find a browser to open.")}return ve})(Le),A(3,`[pool] Initializing pool with workers: min ${$e.minWorkers}, max ${$e.maxWorkers}.`),_e)return A(4,"[pool] Already initialized, please kill it before creating a new one.");parseInt($e.minWorkers)>parseInt($e.maxWorkers)&&($e.minWorkers=$e.maxWorkers);try{_e=new v({...Ne,min:parseInt($e.minWorkers),max:parseInt($e.maxWorkers),acquireTimeoutMillis:$e.acquireTimeout,createTimeoutMillis:$e.createTimeout,destroyTimeoutMillis:$e.destroyTimeout,idleTimeoutMillis:$e.idleTimeout,createRetryIntervalMillis:$e.createRetryInterval,reapIntervalMillis:$e.reaperInterval,propagateCreateError:!1}),_e.on("release",(async e=>{await we(e.page,!1),A(4,`[pool] Releasing a worker with ID ${e.id}.`)})),_e.on("destroySuccess",((e,t)=>{A(4,`[pool] Destroyed a worker with ID ${t.id}.`)}));const e=[];for(let t=0;t<$e.minWorkers;t++)try{const t=await _e.acquire().promise;e.push(t)}catch(e){j(2,e,"[pool] Could not create an initial resource.")}e.forEach((e=>{_e.release(e)})),A(3,"[pool] The pool is ready"+(e.length?` with ${e.length} initial resources waiting.`:"."))}catch(e){throw await Te(),new X("[pool] Could not create the pool of workers.").setError(e)}};async function Ae(){return A(3,"[pool] Killing all pool workers and browser, if any exist."),_e?.destroyed||_e&&(await _e.destroy(),A(4,"[browser] Destroyed the pool of resources.")),Te()}const je=async(e,t)=>{let r;try{if(A(4,"[pool] Work received, starting to process."),++Oe,$e.benchmarking&&He(),!_e)throw new X("Work received, but pool has not been started.");try{A(4,"[pool] Acquiring a worker handle.");const e=z();r=await _e.acquire().promise,t.server.benchmarking&&A(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Acquired a worker handle: ${e()}ms.`)}catch(e){throw new X("Error encountered when acquiring an available entry.").setError(e)}if(A(4,"[pool] Acquired a worker handle."),!r.page)throw new X("Resolved worker page is invalid: the pool setup is wonky.");let i=(new Date).getTime();A(4,`[pool] Starting work on pool entry with ID ${r.id}.`);const o=z(),n=await Ee(r.page,e,t);if(n instanceof Error)throw"Rasterization timeout"===n.message&&(r.page.close(),r.page=await be()),new X("Error encountered during export.").setError(n);t.server.benchmarking&&A(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Exported a chart sucessfully: ${o()}ms.`),_e.release(r);const s=(new Date).getTime()-i;return Re+=s,Ce=Re/++Se,A(4,`[pool] Work completed in ${s} ms.`),{result:n,options:t}}catch(e){throw++Ie,r&&_e.release(r),new X(`[pool] In pool.postWork: ${e.message}`).setError(e)}};function He(){const{min:e,max:t}=_e;A(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),A(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),A(5,`[pool] The number of resources that are currently available: ${_e.numFree()}.`),A(5,`[pool] The number of resources that are currently acquired: ${_e.numUsed()}.`),A(5,`[pool] The number of callers waiting to acquire a resource: ${_e.numPendingAcquires()}.`)}var Ue=()=>({min:_e.min,max:_e.max,available:_e.numFree(),inUse:_e.numUsed(),pendingAcquire:_e.numPendingAcquires()}),We=()=>Oe,De=()=>Ie,Me=()=>Ce,Fe=()=>Se;let qe=!1;const Ge=async(e,t)=>{A(4,"[chart] Starting the exporting process.");const r=((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=le(t,e,I),r.export.outfile=r.export?.outfile||`chart.${r.export?.type||"png"}`,r})(e,ae()),i=r.export;if(r.payload?.svg&&""!==r.payload.svg)try{return A(4,"[chart] Attempting to export from a SVG input."),ze(r.payload.svg.trim(),r,t)}catch(e){return t(new X("[chart] Error loading SVG input.").setError(e))}if(i.infile&&i.infile.length)try{return A(4,"[chart] Attempting to export from an input file."),r.export.instr=n(i.infile,"utf8"),ze(r.export.instr.trim(),r,t)}catch(e){return t(new X("[chart] Error loading input file.").setError(e))}if(i.instr&&""!==i.instr||i.options&&""!==i.options)try{return A(4,"[chart] Attempting to export from a raw input."),J(r.customLogic?.allowCodeExecution)?Ke(r,t):"string"==typeof i.instr?ze(i.instr.trim(),r,t):Je(r,i.instr||i.options,t)}catch(e){return t(new X("[chart] Error loading raw input.").setError(e))}return t(new X("[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||F(e.export?.instr),i=F(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(e,t,r,i)=>{let{export:o,customLogic:s}=e;const a="boolean"==typeof s.allowCodeExecution?s.allowCodeExecution:qe;if(s){if(a)if("string"==typeof e.customLogic.resources)e.customLogic.resources=M(e.customLogic.resources,J(e.customLogic.allowFileResources));else if(!e.customLogic.resources)try{const t=n("resources.json","utf8");e.customLogic.resources=M(t,J(e.customLogic.allowFileResources))}catch(e){j(2,e,"[chart] Unable to load the default resources.json file.")}}else s=e.customLogic={};if(!a&&s){if(s.callback||s.resources||s.customCode)return r(new X("[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server."));s.callback=!1,s.resources=!1,s.customCode=!1}if(t&&(t.chart=t.chart||{},t.exporting=t.exporting||{},t.exporting.enabled=!1),o.constr=o.constr||"chart",o.type=D(o.type,o.outfile),"svg"===o.type&&(o.width=!1),["globalOptions","themeOptions"].forEach((e=>{try{o&&o[e]&&("string"==typeof o[e]&&o[e].endsWith(".json")?o[e]=F(n(o[e],"utf8"),!0):o[e]=F(o[e],!0))}catch(t){o[e]={},j(2,t,`[chart] The '${e}' 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=n(s.callback,"utf8")}catch(e){s.callback=!1,j(2,e,"[chart] The 'callback' cannot be loaded.")}else s.callback=!1;e.export={...e.export,...Ve(e)};try{return r(!1,await je(o.strInj||t||i,e))}catch(e){return r(e)}},Ke=(e,t)=>{try{let r,i=e.export.instr||e.export.options;return"string"!=typeof i&&(r=i=G(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 X(`[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:i}=t.customLogic;if(e.indexOf("=0||e.indexOf("=0)return A(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 J(i)?Ke(t,r):r(new X("[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=(e,t,r,i)=>{j(1,e),"development"!==process.env.NODE_ENV&&delete e.stack,i(e)},Be=(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 Ye=(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=L({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&&(A(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(o),A(3,`[rate limiting] Enabled rate limiting with ${i.max} requests per ${i.window} minute for each IP, trusting proxy: ${i.trustProxy}.`)};class Qe extends X{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=[],it=(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},ot=async(e,t,r)=>{try{const r=z(),o=y().replace(/-/g,""),n=ae(),s=e.body,a=++et;let l=D(s.type);if(!s||"object"==typeof(i=s)&&null!==i&&0===Object.keys(i).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=F(s.infile||s.options||s.data);if(!c&&!s.svg)throw A(2,`The request with ID ${o} from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Payload received: ${JSON.stringify(s)}.`),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=it(tt,e,t,{id:a,uniqueId:o,type:l,body:s}),!0!==p)return t.send(p);let h=!1;e.socket.on("close",(()=>{h=!0})),A(4,`[export] Got an incoming HTTP request with ID ${o}.`),s.constr="string"==typeof s.constr&&s.constr||"chart";const u={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:F(s.globalOptions,!0),themeOptions:F(s.themeOptions,!0)},customLogic:{allowCodeExecution:qe,allowFileResources:!1,resources:F(s.resources,!0),callback:s.callback,customCode:s.customCode}};c&&(u.export.instr=G(c,u.customLogic.allowCodeExecution));const d=le(n,u);if(d.export.options=c,d.payload={svg:s.svg||!1,b64:s.b64||!1,noDownload:s.noDownload||!1,requestId:o},s.svg&&(e=>["localhost","(10).(.*).(.*).(.*)","(127).(.*).(.*).(.*)","(172).(1[6-9]|2[0-9]|3[0-1]).(.*).(.*)","(192).(168).(.*).(.*)"].some((t=>e.match(`xlink:href="(?:(http://|https://))?${t}`))))(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 Ge(d,((i,c)=>{if(e.socket.removeAllListeners("close"),n.server.benchmarking&&A(5,`[benchmark] Request with ID ${o} - After the whole exporting process: ${r()}ms.`),h)return A(3,"[export] The client closed the connection before the chart finished processing.");if(i)throw i;if(!c||!c.result)throw new Qe(`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,it(rt,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 nt=JSON.parse(n(c(W,"package.json"))),st=new Date;const at=x();at.disable("x-powered-by"),at.use(k());const lt=E.memoryStorage(),ct=E({storage:lt,limits:{fieldSize:52428800}});at.use(x.json({limit:52428800})),at.use(x.urlencoded({extended:!0,limit:52428800})),at.use(ct.none());const pt=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}`)}))}))},ht=async e=>{try{if(!e.enable)return!1;if(!e.ssl.force){const t=u.createServer(at);pt(t),t.listen(e.port,e.host),A(3,`[server] Started HTTP server on ${e.host}:${e.port}.`)}if(e.ssl.enable){let t,r;try{t=await a.readFile(p.join(e.ssl.certPath,"server.key"),"utf8"),r=await a.readFile(p.join(e.ssl.certPath,"server.crt"),"utf8")}catch(t){A(2,`[server] Unable to load key/certificate from the '${e.ssl.certPath}' path. Could not run secured layer server.`)}if(t&&r){const i=d.createServer({key:t,cert:r},at);pt(i),i.listen(e.ssl.port,e.host),A(3,`[server] Started HTTPS server on ${e.host}:${e.ssl.port}.`)}}e.rateLimiting&&e.rateLimiting.enable&&![0,NaN].includes(e.rateLimiting.maxRequests)&&Ye(at,e.rateLimiting),at.use(x.static(p.join(W,"public"))),(e=>{!!e&&e.get("/health",((e,t)=>{t.send({status:"OK",bootTime:st,uptime:Math.floor(((new Date).getTime()-st.getTime())/1e3/60)+" minutes",version:nt.version,highchartsVersion:ne(),averageProcessingTime:Me(),performedExports:Fe(),failedExports:De(),exportAttempts:We(),sucessRatio:Fe()/We()*100,pool:Ue()})}))})(at),(e=>{e.post("/",ot),e.post("/:filename",ot)})(at),(e=>{!!e&&e.get("/",((e,t)=>{t.sendFile(c(W,"public","index.html"))}))})(at),(e=>{!!e&&e.post("/version/change/:newVersion",(async(e,t,r)=>{try{const r=process.env.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 i=e.get("hc-auth");if(!i||i!==r)throw new Qe("Invalid or missing token: Set the token in the hc-auth header.",401);const o=e.params.newVersion;if(!o)throw new Qe("No new version supplied.",400);try{await ie(o)}catch(e){throw new Qe(`Version change: ${e.message}`,e.statusCode).setError(e)}t.status(200).send({statusCode:200,version:ne(),message:`Successfully updated Highcharts to version: ${o}.`})}catch(e){r(e)}}))})(at),(e=>{e.use(Xe),e.use(Be)})(at)}catch(e){throw new X("[server] Could not configure and start the server.").setError(e)}};var ut={startServer:ht,enableRateLimiting:e=>Ye(at,e),getExpress:()=>x,getApp:()=>at,use:(e,...t)=>{at.use(e,...t)},get:(e,...t)=>{at.get(e,...t)},post:(e,...t)=>{at.post(e,...t)}};e.config();var dt={server:ut,startServer:ht,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(n(r))}catch(e){j(2,e,`[config] Unable to load the configuration from the ${r} file.`)}}return{}}(t)),ce(O,se),se=pe(O),e&&(se=le(se,e,I)),t?.length&&(se=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]=J(t[o]):"number"===a?e[r]=+t[o]:a.indexOf("]")>=0?e[r]=t[o].split(","):e[r]=t[o]:(A(2,`[config] Missing value for the '${n}' argument. Using the default value.`),i=!0)),e[r])),e)}i&&V();return e}(se,t,O)),se),initExport:async e=>{var t;return t=e.customLogic&&e.customLogic.allowCodeExecution,qe=J(t),(e=>{H(e&&parseInt(e.level)),e&&e.dest&&U(e.dest,e.file||"highcharts-export-server.log")})(e.logging),await te(e.highcharts||{version:"latest"}),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 Ge(e,(async(e,t)=>{if(e)throw e;const{outfile:r,type:i}=t.options.export;s(r||`chart.${i}`,"svg"!==i?Buffer.from(t.result,"base64"):t.result),await Ae()}))},batchExport:async e=>{const t=[];for(let r of e.export.batch.split(";"))r=r.split("="),2===r.length&&t.push(Ge({...e,export:{...e.export,infile:r[0],outfile:r[1]}},((e,t)=>{if(e)throw e;s(t.options.export.outfile,Buffer.from(t.result,"base64"))})));try{await Promise.all(t),await Ae()}catch(e){throw new X("[chart] Error encountered during batch export.").setError(e)}},startExport:Ge,killPool:Ae,log:A,logWithStack:j,setLogLevel:H,enableFileLogging:U,mapToNewConfig:e=>{const t={};for(const[r,i]of Object.entries(e)){const e=C[r]?C[r].split("."):[];e.reduce(((t,r,o)=>t[r]=e.length-1===o?i:t[r]||{}),t)}return t},manualConfig:async e=>{let t={};r(e)&&(t=JSON.parse(n(e,"utf8")));const i=Object.keys(R).map((e=>({title:`${e} options`,value:e})));return f({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(r,i)=>{let o=0,n=[];for(const e of i)R[e]=R[e].map((t=>({...t,section:e}))),n=[...n,...R[e]];return await f(n,{onSubmit:async(r,i)=>{if("modules"===r.name?(i=i.length?i.map((e=>r.choices[e])):r.choices,t[r.section][r.name]=i):t[r.section]=he(Object.assign({},t[r.section]||{}),r.name.split("."),r.choices?r.choices[i]:i),++o===n.length){try{await a.writeFile(e,JSON.stringify(t,null,2),"utf8")}catch(t){j(1,t,`[config] An error occurred while creating the ${e} file.`)}return!0}}}),!0}})},printLogo:e=>{const t=JSON.parse(n(c(W,"package.json"))).version;e?console.log(`Starting Highcharts Export Server v${t}...`):console.log(n(W+"/msg/startup.msg").toString().bold.yellow,`v${t}`)},printUsage:V};export{dt as default}; //# sourceMappingURL=index.esm.js.map diff --git a/dist/index.esm.js.map b/dist/index.esm.js.map index 645bd873..1ec4e718 100644 --- a/dist/index.esm.js.map +++ b/dist/index.esm.js.map @@ -1 +1 @@ -{"version":3,"file":"index.esm.js","sources":["../lib/fetch.js","../lib/schemas/config.js","../lib/logger.js","../lib/utils.js","../lib/errors/ExportError.js","../lib/cache.js","../lib/config.js","../lib/browser.js","../lib/export.js","../templates/svg_export/svg_export.js","../lib/pool.js","../lib/chart.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/index.js"],"sourcesContent":["/**\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","/*******************************************************************************\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// 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 envLink: 'HIGHCHARTS_VERSION',\r\n type: 'string',\r\n description: 'The Highcharts version to be used.'\r\n },\r\n cdnURL: {\r\n value: 'https://code.highcharts.com/',\r\n envLink: 'HIGHCHARTS_CDN_URL',\r\n type: 'string',\r\n description: 'The CDN URL for Highcharts scripts to be used.'\r\n },\r\n coreScripts: {\r\n envLink: 'HIGHCHARTS_CORE_SCRIPTS',\r\n value: ['highcharts', 'highcharts-more', 'highcharts-3d'],\r\n type: 'string[]',\r\n description: 'The core Highcharts scripts to fetch.'\r\n },\r\n modules: {\r\n envLink: 'HIGHCHARTS_MODULES',\r\n value: [\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 type: 'string[]',\r\n description: 'The modules of Highcharts to fetch.'\r\n },\r\n indicators: {\r\n envLink: 'HIGHCHARTS_INDICATORS',\r\n value: ['indicators-all'],\r\n type: 'string[]',\r\n description: 'The indicators of Highcharts to fetch.'\r\n },\r\n scripts: {\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 optional scripts or dependencies to fetch.'\r\n },\r\n forceFetch: {\r\n envLink: 'HIGHCHARTS_FORCE_FETCH',\r\n value: false,\r\n type: 'boolean',\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 envLink: 'HIGHCHARTS_CACHE_PATH',\r\n value: '.cache',\r\n type: 'string',\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 envLink: 'EXPORT_TYPE',\r\n value: 'png',\r\n type: 'string',\r\n description: 'The file export format. It can be jpeg, png, pdf, or svg.'\r\n },\r\n constr: {\r\n envLink: 'EXPORT_CONSTR',\r\n value: 'chart',\r\n type: 'string',\r\n description:\r\n 'The constructor to use. Can be chart, stockChart, mapChart, or ganttChart.'\r\n },\r\n defaultHeight: {\r\n envLink: 'EXPORT_DEFAULT_HEIGHT',\r\n value: 400,\r\n type: 'number',\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 envLink: 'EXPORT_DEFAULT_WIDTH',\r\n value: 600,\r\n type: 'number',\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 envLink: 'EXPORT_DEFAULT_SCALE',\r\n value: 1,\r\n type: 'number',\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 type: 'number',\r\n value: false,\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 type: 'number',\r\n value: false,\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 envLink: 'EXPORT_RASTERIZATION_TIMEOUT',\r\n value: 1500,\r\n type: 'number',\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 envLink: 'CUSTOM_LOGIC_ALLOW_CODE_EXECUTION',\r\n value: false,\r\n type: 'boolean',\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 envLink: 'CUSTOM_LOGIC_ALLOW_FILE_RESOURCES',\r\n value: false,\r\n type: 'boolean',\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 envLink: 'SERVER_ENABLE',\r\n value: false,\r\n type: 'boolean',\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 envLink: 'SERVER_HOST',\r\n value: '0.0.0.0',\r\n type: 'string',\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 envLink: 'SERVER_PORT',\r\n value: 7801,\r\n type: 'number',\r\n description: 'The server port when enabled.'\r\n },\r\n benchmarking: {\r\n envLink: 'SERVER_BENCHMARKING',\r\n value: false,\r\n type: 'boolean',\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 ssl: {\r\n enable: {\r\n envLink: 'SERVER_SSL_ENABLE',\r\n value: false,\r\n type: 'boolean',\r\n cliName: 'enableSsl',\r\n description: 'Enables or disables the SSL protocol.'\r\n },\r\n force: {\r\n envLink: 'SERVER_SSL_FORCE',\r\n value: false,\r\n type: 'boolean',\r\n cliName: 'sslForced',\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 envLink: 'SERVER_SSL_PORT',\r\n value: 443,\r\n type: 'number',\r\n cliName: 'sslPort',\r\n description: 'The port on which to run the SSL server.'\r\n },\r\n certPath: {\r\n envLink: 'SERVER_SSL_CERT_PATH',\r\n value: '',\r\n type: 'string',\r\n legacyName: 'sslPath',\r\n description: 'The path to the SSL certificate/key file.'\r\n }\r\n },\r\n rateLimiting: {\r\n enable: {\r\n envLink: 'SERVER_RATE_LIMITING_ENABLE',\r\n value: false,\r\n type: 'boolean',\r\n cliName: 'enableRateLimiting',\r\n description: 'Enables rate limiting for the server.'\r\n },\r\n maxRequests: {\r\n envLink: 'SERVER_RATE_LIMITING_MAX_REQUESTS',\r\n value: 10,\r\n type: 'number',\r\n legacyName: 'rateLimit',\r\n description: 'The maximum number of requests allowed in one minute.'\r\n },\r\n window: {\r\n envLink: 'SERVER_RATE_LIMITING_WINDOW',\r\n value: 1,\r\n type: 'number',\r\n description: 'The time window, in minutes, for the rate limiting.'\r\n },\r\n delay: {\r\n envLink: 'SERVER_RATE_LIMITING_DELAY',\r\n value: 0,\r\n type: 'number',\r\n description:\r\n 'The delay duration for each successive request before reaching the maximum limit.'\r\n },\r\n trustProxy: {\r\n envLink: 'SERVER_RATE_LIMITING_TRUST_PROXY',\r\n value: false,\r\n type: 'boolean',\r\n description: 'Set this to true if the server is behind a load balancer.'\r\n },\r\n skipKey: {\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_KEY',\r\n value: '',\r\n type: 'string',\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 envLink: 'SERVER_RATE_LIMITING_SKIP_TOKEN',\r\n value: '',\r\n type: 'string',\r\n description:\r\n 'Allows bypassing the rate limiter and should be provided with the skipKey argument.'\r\n }\r\n }\r\n },\r\n pool: {\r\n minWorkers: {\r\n envLink: 'POOL_MIN_WORKERS',\r\n value: 4,\r\n type: 'number',\r\n description: 'The number of minimum and initial pool workers to spawn.'\r\n },\r\n maxWorkers: {\r\n envLink: 'POOL_MAX_WORKERS',\r\n value: 8,\r\n type: 'number',\r\n legacyName: 'workers',\r\n description: 'The number of maximum pool workers to spawn.'\r\n },\r\n workLimit: {\r\n envLink: 'POOL_WORK_LIMIT',\r\n value: 40,\r\n type: 'number',\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 envLink: 'POOL_ACQUIRE_TIMEOUT',\r\n value: 5000,\r\n type: 'number',\r\n description:\r\n 'The duration, in milliseconds, to wait for acquiring a resource.'\r\n },\r\n createTimeout: {\r\n envLink: 'POOL_CREATE_TIMEOUT',\r\n value: 5000,\r\n type: 'number',\r\n description:\r\n 'The duration, in milliseconds, to wait for creating a resource.'\r\n },\r\n destroyTimeout: {\r\n envLink: 'POOL_DESTROY_TIMEOUT',\r\n value: 5000,\r\n type: 'number',\r\n description:\r\n 'The duration, in milliseconds, to wait for destroying a resource.'\r\n },\r\n idleTimeout: {\r\n envLink: 'POOL_IDLE_TIMEOUT',\r\n value: 30000,\r\n type: 'number',\r\n description:\r\n 'The duration, in milliseconds, after which an idle resource is destroyed.'\r\n },\r\n createRetryInterval: {\r\n envLink: 'POOL_CREATE_RETRY_INTERVAL',\r\n value: 200,\r\n type: 'number',\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 envLink: 'POOL_REAPER_INTERVAL',\r\n value: 1000,\r\n type: 'number',\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 envLink: 'POOL_BENCHMARKING',\r\n value: false,\r\n type: 'boolean',\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 listenToProcessExits: {\r\n envLink: 'POOL_LISTEN_TO_PROCESS_EXITS',\r\n value: true,\r\n type: 'boolean',\r\n description: 'Decides whether or not to attach process.exit handlers.'\r\n }\r\n },\r\n logging: {\r\n level: {\r\n envLink: 'LOGGING_LEVEL',\r\n value: 4,\r\n type: 'number',\r\n cliName: 'logLevel',\r\n description: 'The logging level to be used.'\r\n },\r\n file: {\r\n envLink: 'LOGGING_FILE',\r\n value: 'highcharts-export-server.log',\r\n type: 'string',\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 envLink: 'LOGGING_DEST',\r\n value: 'log/',\r\n type: 'string',\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 envLink: 'UI_ENABLE',\r\n value: false,\r\n type: 'boolean',\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 envLink: 'UI_ROUTE',\r\n value: '/',\r\n type: 'string',\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 noLogo: {\r\n envLink: 'OTHER_NO_LOGO',\r\n value: false,\r\n type: 'boolean',\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: 'modules',\r\n message: 'Available modules',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n choices: defaultConfig.highcharts.modules.value\r\n },\r\n {\r\n type: 'list',\r\n name: 'scripts',\r\n message: 'Custom scripts',\r\n initial: defaultConfig.highcharts.scripts.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: '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 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 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 type: 'toggle',\r\n name: 'listenToProcessExits',\r\n message: 'Set to false to skip attaching process.exit handlers',\r\n initial: defaultConfig.pool.listenToProcessExits.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: '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\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 // Check if extension has a correct type\r\n 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.\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' && item !== null && 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 return [\r\n 'localhost',\r\n '(10).(.*).(.*).(.*)',\r\n '(127).(.*).(.*).(.*)',\r\n '(172).(1[6-9]|2[0-9]|3[0-1]).(.*).(.*)',\r\n '(192).(168).(.*).(.*)'\r\n ].some((ipRegEx) =>\r\n item.match(`xlink:href=\"(?:(http://|https://))?${ipRegEx}`)\r\n );\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","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 { 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// TODO: The config should be accesssible globally so we don't have to do this sort of thing..\r\nlet appliedConfig = false;\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\nconst extractVersion = () =>\r\n (cache.hcVersion = 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 * Extracts the Highcharts module name based on the scriptPath.\r\n */\r\nconst 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\nconst 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} proxyAgent - The proxy agent to use for a request.\r\n * @param {Object} fetchedModules - An object which tracks which Highcharts modules have been fetched.\r\n * @param {boolean} shouldThrowError - A flag to indicate if the error should be 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\nconst fetchAndProcessScript = async (\r\n script,\r\n proxyAgent,\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 // If exists, add proxy agent to request options\r\n const requestOptions = proxyAgent\r\n ? {\r\n agent: proxyAgent,\r\n timeout: +process.env['PROXY_SERVER_TIMEOUT'] || 5000\r\n }\r\n : {};\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} scripts - Array of Highcharts modules to fetch.\r\n * @param {string} customScripts - Array of custom script paths to fetch (full URLs).\r\n * @param {object} proxyAgent - The proxy agent to use for a request.\r\n * @param {object} fetchedModules - An object which tracks which Highcharts modules have been fetched.\r\n * @returns {Promise} The fetched scripts content joined.\r\n */\r\nconst fetchScripts = async (\r\n coreScripts,\r\n moduleScripts,\r\n customScripts,\r\n cdnURL,\r\n proxyAgent,\r\n fetchedModules\r\n) => {\r\n const allFetchPromises = [\r\n ...coreScripts.map((script) =>\r\n fetchAndProcessScript(\r\n `${cdnURL}${script}`,\r\n proxyAgent,\r\n fetchedModules,\r\n true\r\n )\r\n ),\r\n ...moduleScripts.map((script) =>\r\n fetchAndProcessScript(`${cdnURL}${script}`, proxyAgent, fetchedModules)\r\n ),\r\n ...customScripts.map((script) =>\r\n fetchAndProcessScript(`${script}`, proxyAgent)\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} config - The configuration object containing information\r\n * about scripts and modules.\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\nconst updateCache = async (config, sourcePath) => {\r\n const { coreScripts, modules, indicators, scripts: customScripts } = config;\r\n const hcVersion =\r\n config.version === 'latest' || !config.version ? '' : `${config.version}/`;\r\n\r\n log(\r\n 3,\r\n `[cache] Updating cache version to Highcharts: ${hcVersion || 'latest'}.`\r\n );\r\n\r\n // Configure proxy if exists\r\n let proxyAgent;\r\n const proxyHost = process.env['PROXY_SERVER_HOST'];\r\n const proxyPort = process.env['PROXY_SERVER_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 const fetchedModules = {};\r\n try {\r\n cache.sources = await fetchScripts(\r\n [...coreScripts.map((c) => `${hcVersion}${c}`)],\r\n [\r\n ...modules.map((m) =>\r\n m === 'map'\r\n ? `maps/${hcVersion}modules/${m}`\r\n : `${hcVersion}modules/${m}`\r\n ),\r\n ...indicators.map((i) => `stock/${hcVersion}indicators/${i}`)\r\n ],\r\n customScripts,\r\n config.cdnURL || cache.cdnURL,\r\n proxyAgent,\r\n fetchedModules\r\n );\r\n extractVersion();\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 appliedConfig\r\n ? await checkAndUpdateCache(\r\n Object.assign(appliedConfig, {\r\n version: newVersion\r\n })\r\n )\r\n : false;\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} config - Highcharts-related configuration object containing information\r\n * about scripts and modules.\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 (config) => {\r\n const cachePath = join(__dirname, config.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 // TODO: deal with trying to switch to the running version\r\n // const activeVersion = appliedConfig ? appliedConfig.version : false;\r\n\r\n appliedConfig = config;\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) || config.forceFetch) {\r\n log(3, '[cache] Fetching and caching Highcharts dependencies.');\r\n fetchedModules = await updateCache(config, 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 { modules, coreScripts, indicators } = config;\r\n const numberOfModules =\r\n modules.length + coreScripts.length + indicators.length;\r\n\r\n // Compare the loaded 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 !== config.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 = (config.modules || []).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(config, 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 extractVersion();\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(config, fetchedModules);\r\n};\r\n\r\nexport const getCachePath = () => {\r\n return join(__dirname, appliedConfig.cachePath);\r\n};\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 { 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 { 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 modules\r\n if (prompt.name === 'modules') {\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 let numEnvVal;\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) {\r\n // Load the env var\r\n if (entry.type === 'boolean') {\r\n entry.value = toBoolean(\r\n [process.env[entry.envLink], entry.value].find(\r\n (el) => el || el === 'false'\r\n )\r\n );\r\n } else if (entry.type === 'number') {\r\n numEnvVal = +process.env[entry.envLink];\r\n entry.value = numEnvVal >= 0 ? numEnvVal : entry.value;\r\n } else if (entry.type.indexOf(']') >= 0 && process.env[entry.envLink]) {\r\n entry.value = process.env[entry.envLink].split(',');\r\n } else {\r\n entry.value = process.env[entry.envLink] || entry.value;\r\n }\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\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 });\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 log(4, '[browser] Closed the browser.');\r\n }\r\n return true;\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 (exportOptions.type === 'png' || exportOptions.type === 'jpeg') {\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 Highcarts 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\nlet performedExports = 0;\r\nlet exportAttempts = 0;\r\nlet timeSpent = 0;\r\nlet droppedExports = 0;\r\nlet spentAverage = 0;\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 // Attach process' exit listeners\r\n if (poolConfig.listenToProcessExits) {\r\n attachProcessExitListeners();\r\n }\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 // Close browser if for some reason cannot establish the pool\r\n await browserClose();\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 * 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\nexport function attachProcessExitListeners() {\r\n log(3, '[pool] Attaching exit listeners to the process.');\r\n\r\n // Kill all pool resources on exit\r\n process.on('exit', async (code) => {\r\n log(4, `Process exited with code ${code}.`);\r\n await killPool();\r\n });\r\n\r\n // Handler for the SIGINT\r\n process.on('SIGINT', (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n process.exit(1);\r\n });\r\n\r\n // Handler for the SIGTERM\r\n process.on('SIGTERM', (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n process.exit(1);\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 killPool();\r\n process.exit(1);\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 all pool workers and browser, if any exist.');\r\n\r\n // Return true when the pool is already destroyed\r\n if (pool?.destroyed) {\r\n // Close the browser instance if still connected\r\n return browserClose();\r\n }\r\n\r\n // If still alive, destroy the pool of pages before closing a browser\r\n if (pool) {\r\n await pool.destroy();\r\n log(4, '[browser] Destroyed the pool of resources.');\r\n }\r\n\r\n // Close the browser instance\r\n return 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 ++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 timeSpent += exportTime;\r\n spentAverage = timeSpent / ++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 ++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 function getPool() {\r\n return pool;\r\n}\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 workAttempts: () => exportAttempts,\r\n droppedWork: () => droppedExports,\r\n averageTime: () => spentAverage,\r\n processedWorkCount: () => performedExports\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 } 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\n\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 return exportAsString(options.payload.svg.trim(), options, endCallback);\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 Buffer.from(info.result, 'base64')\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 the pool\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","import { 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 (process.env.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\n\r\nimport cache from '../../cache.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\n/**\r\n * Adds the GET /health route, which outputs basic stats for the server.\r\n */\r\nexport default (app) =>\r\n !app\r\n ? false\r\n : app.get('/health', (request, response) => {\r\n response.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: pool.averageTime(),\r\n performedExports: pool.processedWorkCount(),\r\n failedExports: pool.droppedWork(),\r\n exportAttempts: pool.workAttempts(),\r\n sucessRatio: (pool.processedWorkCount() / pool.workAttempts()) * 100,\r\n // eslint-disable-next-line import/no-named-as-default-member\r\n pool: pool.getPoolInfoJSON()\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 { log, logWithStack } from '../logger.js';\r\nimport rateLimit from './rate_limit.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// 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 attachErrorHandlers = (server) => {\r\n server.on('clientError', (error) => {\r\n logWithStack(1, error, `[server] Client error: ${error.message}`);\r\n });\r\n server.on('error', (error) => {\r\n logWithStack(1, error, `[server] Server error: ${error.message}`);\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 attachErrorHandlers(httpServer);\r\n\r\n // Listen\r\n httpServer.listen(serverConfig.port, serverConfig.host);\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(app);\r\n\r\n // Attach error handlers and listen to the server\r\n attachErrorHandlers(httpsServer);\r\n\r\n // Listen\r\n httpsServer.listen(serverConfig.ssl.port, serverConfig.host);\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 * 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 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\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 = process.env.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 'colors';\r\nimport dotenv from 'dotenv';\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 server, { startServer } from './server/server.js';\r\nimport { printLogo, printUsage } from './utils.js';\r\n\r\n// Load .env into environment variables\r\ndotenv.config();\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 // Check if cache needs to be updated\r\n await checkAndUpdateCache(options.highcharts || { version: 'latest' });\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 setOptions,\r\n\r\n // Exporting\r\n initExport,\r\n singleExport,\r\n batchExport,\r\n startExport,\r\n killPool,\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":["async","fetch","url","requestOptions","Promise","resolve","reject","protocol","startsWith","https","http","getProtocol","get","res","data","on","chunk","text","error","defaultConfig","puppeteer","args","value","type","description","highcharts","version","envLink","cdnURL","coreScripts","modules","indicators","scripts","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","ssl","force","certPath","rateLimiting","maxRequests","window","delay","trustProxy","skipKey","skipToken","pool","minWorkers","maxWorkers","workLimit","acquireTimeout","createTimeout","destroyTimeout","idleTimeout","createRetryInterval","reaperInterval","listenToProcessExits","logging","level","file","dest","ui","route","other","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","colors","toConsole","toFile","pathCreated","levelsDesc","title","color","listeners","key","option","entries","logToFile","texts","prefix","existsSync","mkdirSync","appendFile","concat","console","log","newLevel","length","Date","toString","split","trim","fn","apply","logWithStack","customMessage","mainMessage","stackMessage","stack","slice","setLogLevel","enableFileLogging","logDest","logFile","endsWith","__dirname","fileURLToPath","URL","fixType","formats","outType","pop","find","t","handleResources","allowedProps","handledResources","correctResources","isCorrectJSON","readFileSync","files","propName","map","item","parsedData","JSON","parse","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","process","hrtime","bigint","Number","ExportError","Error","constructor","super","this","setError","statusCode","cache","activeManifest","sources","hcVersion","appliedConfig","extractVersion","indexOf","fetchAndProcessScript","script","proxyAgent","fetchedModules","shouldThrowError","agent","timeout","env","response","updateCache","config","sourcePath","customScripts","proxyHost","proxyPort","HttpsProxyAgent","moduleScripts","allFetchPromises","all","fetchScripts","c","m","writeFileSync","checkAndUpdateCache","manifestPath","requestUpdate","manifest","moduleMap","numberOfModules","some","moduleName","newManifest","saveConfigToManifest","getCachePath","cache$1","newVersion","assign","generalOptions","getOptions","mergeConfigOptions","newOptions","mergedOptions","updateDefaultConfig","configObj","customObj","customValue","numEnvVal","el","initOptions","items","recursiveProps","objectToUpdate","nestedNames","shift","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","close","isConnected","__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","parseFloat","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","puppeteerArgs","performedExports","exportAttempts","timeSpent","droppedExports","spentAverage","poolConfig","factory","create","id","uuid","startDate","getTime","browserNewPage","isClosed","workCount","random","validate","workerHandle","initPool","code","killPool","exit","allArgs","tryCount","open","launch","headless","userDataDir","createBrowser","parseInt","Pool","acquireTimeoutMillis","createTimeoutMillis","destroyTimeoutMillis","idleTimeoutMillis","createRetryIntervalMillis","reapIntervalMillis","propagateCreateError","resource","eventId","initialResources","acquire","promise","release","browserClose","destroyed","postWork","getPoolInfo","acquireCounter","payload","requestId","workStart","exportCounter","result","exportTime","numFree","numUsed","numPendingAcquires","pool$1","available","inUse","pendingAcquire","startExport","settings","endCallback","svg","initExportSettings","exportAsString","doStraightInject","doExport","findChartSize","exporting","precision","multiplier","pow","roundNumber","sourceHeight","sourceWidth","param","chartJson","customLogicOptions","allowCodeExecutionScoped","enabled","optionsName","stringToExport","chartJSON","logErrorMiddleware","req","next","NODE_ENV","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","ipRegEx","isPrivateRangeUrlFound","info","removeAllListeners","Buffer","from","header","attachment","params","filename","pkgFile","pather","serverStartTime","express","disable","cors","storage","multer","memoryStorage","upload","limits","fieldSize","limit","urlencoded","extended","none","attachErrorHandlers","startServer","serverConfig","httpServer","createServer","listen","cert","fsPromises","readFile","posix","httpsServer","NaN","static","bootTime","uptime","floor","highchartsVersion","averageProcessingTime","failedExports","sucessRatio","healthRoute","post","exportRoutes","sendFile","uiRoute","adminToken","HIGHCHARTS_ADMIN_TOKEN","token","vSwitchRoute","errorHandler","enableRateLimiting","getExpress","getApp","middlewares","dotenv","index","setOptions","userOptions","configIndex","findIndex","arg","fileName","loadConfigFile","showUsage","propertiesChain","argumentType","reduce","prop","pairArgumentValue","initExport","initLogging","singleExport","batchExport","batchFunctions","pair","mapToNewConfig","oldOptions","manualConfig","configFileName","configFile","choice","prompts","onSubmit","p","categories","questionsCounter","allQuestions","section","prompt","answer","module","writeFile","printLogo","packageVersion"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.esm.js","sources":["../lib/fetch.js","../lib/schemas/config.js","../lib/logger.js","../lib/utils.js","../lib/errors/ExportError.js","../lib/cache.js","../lib/config.js","../lib/browser.js","../lib/export.js","../templates/svg_export/svg_export.js","../lib/pool.js","../lib/chart.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/index.js"],"sourcesContent":["/**\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","/*******************************************************************************\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// 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 envLink: 'HIGHCHARTS_VERSION',\r\n type: 'string',\r\n description: 'The Highcharts version to be used.'\r\n },\r\n cdnURL: {\r\n value: 'https://code.highcharts.com/',\r\n envLink: 'HIGHCHARTS_CDN_URL',\r\n type: 'string',\r\n description: 'The CDN URL for Highcharts scripts to be used.'\r\n },\r\n coreScripts: {\r\n envLink: 'HIGHCHARTS_CORE_SCRIPTS',\r\n value: ['highcharts', 'highcharts-more', 'highcharts-3d'],\r\n type: 'string[]',\r\n description: 'The core Highcharts scripts to fetch.'\r\n },\r\n modules: {\r\n envLink: 'HIGHCHARTS_MODULES',\r\n value: [\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 type: 'string[]',\r\n description: 'The modules of Highcharts to fetch.'\r\n },\r\n indicators: {\r\n envLink: 'HIGHCHARTS_INDICATORS',\r\n value: ['indicators-all'],\r\n type: 'string[]',\r\n description: 'The indicators of Highcharts to fetch.'\r\n },\r\n scripts: {\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 optional scripts or dependencies to fetch.'\r\n },\r\n forceFetch: {\r\n envLink: 'HIGHCHARTS_FORCE_FETCH',\r\n value: false,\r\n type: 'boolean',\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 envLink: 'HIGHCHARTS_CACHE_PATH',\r\n value: '.cache',\r\n type: 'string',\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 envLink: 'EXPORT_TYPE',\r\n value: 'png',\r\n type: 'string',\r\n description: 'The file export format. It can be jpeg, png, pdf, or svg.'\r\n },\r\n constr: {\r\n envLink: 'EXPORT_CONSTR',\r\n value: 'chart',\r\n type: 'string',\r\n description:\r\n 'The constructor to use. Can be chart, stockChart, mapChart, or ganttChart.'\r\n },\r\n defaultHeight: {\r\n envLink: 'EXPORT_DEFAULT_HEIGHT',\r\n value: 400,\r\n type: 'number',\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 envLink: 'EXPORT_DEFAULT_WIDTH',\r\n value: 600,\r\n type: 'number',\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 envLink: 'EXPORT_DEFAULT_SCALE',\r\n value: 1,\r\n type: 'number',\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 type: 'number',\r\n value: false,\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 type: 'number',\r\n value: false,\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 envLink: 'EXPORT_RASTERIZATION_TIMEOUT',\r\n value: 1500,\r\n type: 'number',\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 envLink: 'CUSTOM_LOGIC_ALLOW_CODE_EXECUTION',\r\n value: false,\r\n type: 'boolean',\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 envLink: 'CUSTOM_LOGIC_ALLOW_FILE_RESOURCES',\r\n value: false,\r\n type: 'boolean',\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 envLink: 'SERVER_ENABLE',\r\n value: false,\r\n type: 'boolean',\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 envLink: 'SERVER_HOST',\r\n value: '0.0.0.0',\r\n type: 'string',\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 envLink: 'SERVER_PORT',\r\n value: 7801,\r\n type: 'number',\r\n description: 'The server port when enabled.'\r\n },\r\n benchmarking: {\r\n envLink: 'SERVER_BENCHMARKING',\r\n value: false,\r\n type: 'boolean',\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 ssl: {\r\n enable: {\r\n envLink: 'SERVER_SSL_ENABLE',\r\n value: false,\r\n type: 'boolean',\r\n cliName: 'enableSsl',\r\n description: 'Enables or disables the SSL protocol.'\r\n },\r\n force: {\r\n envLink: 'SERVER_SSL_FORCE',\r\n value: false,\r\n type: 'boolean',\r\n cliName: 'sslForced',\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 envLink: 'SERVER_SSL_PORT',\r\n value: 443,\r\n type: 'number',\r\n cliName: 'sslPort',\r\n description: 'The port on which to run the SSL server.'\r\n },\r\n certPath: {\r\n envLink: 'SERVER_SSL_CERT_PATH',\r\n value: '',\r\n type: 'string',\r\n legacyName: 'sslPath',\r\n description: 'The path to the SSL certificate/key file.'\r\n }\r\n },\r\n rateLimiting: {\r\n enable: {\r\n envLink: 'SERVER_RATE_LIMITING_ENABLE',\r\n value: false,\r\n type: 'boolean',\r\n cliName: 'enableRateLimiting',\r\n description: 'Enables rate limiting for the server.'\r\n },\r\n maxRequests: {\r\n envLink: 'SERVER_RATE_LIMITING_MAX_REQUESTS',\r\n value: 10,\r\n type: 'number',\r\n legacyName: 'rateLimit',\r\n description: 'The maximum number of requests allowed in one minute.'\r\n },\r\n window: {\r\n envLink: 'SERVER_RATE_LIMITING_WINDOW',\r\n value: 1,\r\n type: 'number',\r\n description: 'The time window, in minutes, for the rate limiting.'\r\n },\r\n delay: {\r\n envLink: 'SERVER_RATE_LIMITING_DELAY',\r\n value: 0,\r\n type: 'number',\r\n description:\r\n 'The delay duration for each successive request before reaching the maximum limit.'\r\n },\r\n trustProxy: {\r\n envLink: 'SERVER_RATE_LIMITING_TRUST_PROXY',\r\n value: false,\r\n type: 'boolean',\r\n description: 'Set this to true if the server is behind a load balancer.'\r\n },\r\n skipKey: {\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_KEY',\r\n value: '',\r\n type: 'string',\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 envLink: 'SERVER_RATE_LIMITING_SKIP_TOKEN',\r\n value: '',\r\n type: 'string',\r\n description:\r\n 'Allows bypassing the rate limiter and should be provided with the skipKey argument.'\r\n }\r\n }\r\n },\r\n pool: {\r\n minWorkers: {\r\n envLink: 'POOL_MIN_WORKERS',\r\n value: 4,\r\n type: 'number',\r\n description: 'The number of minimum and initial pool workers to spawn.'\r\n },\r\n maxWorkers: {\r\n envLink: 'POOL_MAX_WORKERS',\r\n value: 8,\r\n type: 'number',\r\n legacyName: 'workers',\r\n description: 'The number of maximum pool workers to spawn.'\r\n },\r\n workLimit: {\r\n envLink: 'POOL_WORK_LIMIT',\r\n value: 40,\r\n type: 'number',\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 envLink: 'POOL_ACQUIRE_TIMEOUT',\r\n value: 5000,\r\n type: 'number',\r\n description:\r\n 'The duration, in milliseconds, to wait for acquiring a resource.'\r\n },\r\n createTimeout: {\r\n envLink: 'POOL_CREATE_TIMEOUT',\r\n value: 5000,\r\n type: 'number',\r\n description:\r\n 'The duration, in milliseconds, to wait for creating a resource.'\r\n },\r\n destroyTimeout: {\r\n envLink: 'POOL_DESTROY_TIMEOUT',\r\n value: 5000,\r\n type: 'number',\r\n description:\r\n 'The duration, in milliseconds, to wait for destroying a resource.'\r\n },\r\n idleTimeout: {\r\n envLink: 'POOL_IDLE_TIMEOUT',\r\n value: 30000,\r\n type: 'number',\r\n description:\r\n 'The duration, in milliseconds, after which an idle resource is destroyed.'\r\n },\r\n createRetryInterval: {\r\n envLink: 'POOL_CREATE_RETRY_INTERVAL',\r\n value: 200,\r\n type: 'number',\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 envLink: 'POOL_REAPER_INTERVAL',\r\n value: 1000,\r\n type: 'number',\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 envLink: 'POOL_BENCHMARKING',\r\n value: false,\r\n type: 'boolean',\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 listenToProcessExits: {\r\n envLink: 'POOL_LISTEN_TO_PROCESS_EXITS',\r\n value: true,\r\n type: 'boolean',\r\n description: 'Decides whether or not to attach process.exit handlers.'\r\n }\r\n },\r\n logging: {\r\n level: {\r\n envLink: 'LOGGING_LEVEL',\r\n value: 4,\r\n type: 'number',\r\n cliName: 'logLevel',\r\n description: 'The logging level to be used.'\r\n },\r\n file: {\r\n envLink: 'LOGGING_FILE',\r\n value: 'highcharts-export-server.log',\r\n type: 'string',\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 envLink: 'LOGGING_DEST',\r\n value: 'log/',\r\n type: 'string',\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 envLink: 'UI_ENABLE',\r\n value: false,\r\n type: 'boolean',\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 envLink: 'UI_ROUTE',\r\n value: '/',\r\n type: 'string',\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 noLogo: {\r\n envLink: 'OTHER_NO_LOGO',\r\n value: false,\r\n type: 'boolean',\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: 'modules',\r\n message: 'Available modules',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n choices: defaultConfig.highcharts.modules.value\r\n },\r\n {\r\n type: 'list',\r\n name: 'scripts',\r\n message: 'Custom scripts',\r\n initial: defaultConfig.highcharts.scripts.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: '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 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 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 type: 'toggle',\r\n name: 'listenToProcessExits',\r\n message: 'Set to false to skip attaching process.exit handlers',\r\n initial: defaultConfig.pool.listenToProcessExits.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: '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\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.\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' && item !== null && 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 return [\r\n 'localhost',\r\n '(10).(.*).(.*).(.*)',\r\n '(127).(.*).(.*).(.*)',\r\n '(172).(1[6-9]|2[0-9]|3[0-1]).(.*).(.*)',\r\n '(192).(168).(.*).(.*)'\r\n ].some((ipRegEx) =>\r\n item.match(`xlink:href=\"(?:(http://|https://))?${ipRegEx}`)\r\n );\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","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 { 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// TODO: The config should be accesssible globally so we don't have to do this sort of thing..\r\nlet appliedConfig = false;\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\nconst extractVersion = () =>\r\n (cache.hcVersion = 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 * Extracts the Highcharts module name based on the scriptPath.\r\n */\r\nconst 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\nconst 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} proxyAgent - The proxy agent to use for a request.\r\n * @param {Object} fetchedModules - An object which tracks which Highcharts modules have been fetched.\r\n * @param {boolean} shouldThrowError - A flag to indicate if the error should be 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\nconst fetchAndProcessScript = async (\r\n script,\r\n proxyAgent,\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 // If exists, add proxy agent to request options\r\n const requestOptions = proxyAgent\r\n ? {\r\n agent: proxyAgent,\r\n timeout: +process.env['PROXY_SERVER_TIMEOUT'] || 5000\r\n }\r\n : {};\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} scripts - Array of Highcharts modules to fetch.\r\n * @param {string} customScripts - Array of custom script paths to fetch (full URLs).\r\n * @param {object} proxyAgent - The proxy agent to use for a request.\r\n * @param {object} fetchedModules - An object which tracks which Highcharts modules have been fetched.\r\n * @returns {Promise} The fetched scripts content joined.\r\n */\r\nconst fetchScripts = async (\r\n coreScripts,\r\n moduleScripts,\r\n customScripts,\r\n cdnURL,\r\n proxyAgent,\r\n fetchedModules\r\n) => {\r\n const allFetchPromises = [\r\n ...coreScripts.map((script) =>\r\n fetchAndProcessScript(\r\n `${cdnURL}${script}`,\r\n proxyAgent,\r\n fetchedModules,\r\n true\r\n )\r\n ),\r\n ...moduleScripts.map((script) =>\r\n fetchAndProcessScript(`${cdnURL}${script}`, proxyAgent, fetchedModules)\r\n ),\r\n ...customScripts.map((script) =>\r\n fetchAndProcessScript(`${script}`, proxyAgent)\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} config - The configuration object containing information\r\n * about scripts and modules.\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\nconst updateCache = async (config, sourcePath) => {\r\n const { coreScripts, modules, indicators, scripts: customScripts } = config;\r\n const hcVersion =\r\n config.version === 'latest' || !config.version ? '' : `${config.version}/`;\r\n\r\n log(\r\n 3,\r\n `[cache] Updating cache version to Highcharts: ${hcVersion || 'latest'}.`\r\n );\r\n\r\n // Configure proxy if exists\r\n let proxyAgent;\r\n const proxyHost = process.env['PROXY_SERVER_HOST'];\r\n const proxyPort = process.env['PROXY_SERVER_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 const fetchedModules = {};\r\n try {\r\n cache.sources = await fetchScripts(\r\n [...coreScripts.map((c) => `${hcVersion}${c}`)],\r\n [\r\n ...modules.map((m) =>\r\n m === 'map'\r\n ? `maps/${hcVersion}modules/${m}`\r\n : `${hcVersion}modules/${m}`\r\n ),\r\n ...indicators.map((i) => `stock/${hcVersion}indicators/${i}`)\r\n ],\r\n customScripts,\r\n config.cdnURL || cache.cdnURL,\r\n proxyAgent,\r\n fetchedModules\r\n );\r\n extractVersion();\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 appliedConfig\r\n ? await checkAndUpdateCache(\r\n Object.assign(appliedConfig, {\r\n version: newVersion\r\n })\r\n )\r\n : false;\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} config - Highcharts-related configuration object containing information\r\n * about scripts and modules.\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 (config) => {\r\n const cachePath = join(__dirname, config.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 // TODO: deal with trying to switch to the running version\r\n // const activeVersion = appliedConfig ? appliedConfig.version : false;\r\n\r\n appliedConfig = config;\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) || config.forceFetch) {\r\n log(3, '[cache] Fetching and caching Highcharts dependencies.');\r\n fetchedModules = await updateCache(config, 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 { modules, coreScripts, indicators } = config;\r\n const numberOfModules =\r\n modules.length + coreScripts.length + indicators.length;\r\n\r\n // Compare the loaded 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 !== config.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 = (config.modules || []).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(config, 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 extractVersion();\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(config, fetchedModules);\r\n};\r\n\r\nexport const getCachePath = () => {\r\n return join(__dirname, appliedConfig.cachePath);\r\n};\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 { 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 { 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 modules\r\n if (prompt.name === 'modules') {\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 let numEnvVal;\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) {\r\n // Load the env var\r\n if (entry.type === 'boolean') {\r\n entry.value = toBoolean(\r\n [process.env[entry.envLink], entry.value].find(\r\n (el) => el || el === 'false'\r\n )\r\n );\r\n } else if (entry.type === 'number') {\r\n numEnvVal = +process.env[entry.envLink];\r\n entry.value = numEnvVal >= 0 ? numEnvVal : entry.value;\r\n } else if (entry.type.indexOf(']') >= 0 && process.env[entry.envLink]) {\r\n entry.value = process.env[entry.envLink].split(',');\r\n } else {\r\n entry.value = process.env[entry.envLink] || entry.value;\r\n }\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\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 });\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 log(4, '[browser] Closed the browser.');\r\n }\r\n return true;\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 Highcarts 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\nlet performedExports = 0;\r\nlet exportAttempts = 0;\r\nlet timeSpent = 0;\r\nlet droppedExports = 0;\r\nlet spentAverage = 0;\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 // Attach process' exit listeners\r\n if (poolConfig.listenToProcessExits) {\r\n attachProcessExitListeners();\r\n }\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 // Close browser if for some reason cannot establish the pool\r\n await browserClose();\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 * 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\nexport function attachProcessExitListeners() {\r\n log(3, '[pool] Attaching exit listeners to the process.');\r\n\r\n // Kill all pool resources on exit\r\n process.on('exit', async (code) => {\r\n log(4, `Process exited with code ${code}.`);\r\n await killPool();\r\n });\r\n\r\n // Handler for the SIGINT\r\n process.on('SIGINT', (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n process.exit(1);\r\n });\r\n\r\n // Handler for the SIGTERM\r\n process.on('SIGTERM', (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n process.exit(1);\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 killPool();\r\n process.exit(1);\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 all pool workers and browser, if any exist.');\r\n\r\n // Return true when the pool is already destroyed\r\n if (pool?.destroyed) {\r\n // Close the browser instance if still connected\r\n return browserClose();\r\n }\r\n\r\n // If still alive, destroy the pool of pages before closing a browser\r\n if (pool) {\r\n await pool.destroy();\r\n log(4, '[browser] Destroyed the pool of resources.');\r\n }\r\n\r\n // Close the browser instance\r\n return 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 ++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 timeSpent += exportTime;\r\n spentAverage = timeSpent / ++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 ++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 function getPool() {\r\n return pool;\r\n}\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 workAttempts: () => exportAttempts,\r\n droppedWork: () => droppedExports,\r\n averageTime: () => spentAverage,\r\n processedWorkCount: () => performedExports\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 } 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\n\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 return exportAsString(options.payload.svg.trim(), options, endCallback);\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 Buffer.from(info.result, 'base64')\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 the pool\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","import { 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 (process.env.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\n\r\nimport cache from '../../cache.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\n/**\r\n * Adds the GET /health route, which outputs basic stats for the server.\r\n */\r\nexport default (app) =>\r\n !app\r\n ? false\r\n : app.get('/health', (request, response) => {\r\n response.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: pool.averageTime(),\r\n performedExports: pool.processedWorkCount(),\r\n failedExports: pool.droppedWork(),\r\n exportAttempts: pool.workAttempts(),\r\n sucessRatio: (pool.processedWorkCount() / pool.workAttempts()) * 100,\r\n // eslint-disable-next-line import/no-named-as-default-member\r\n pool: pool.getPoolInfoJSON()\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 { log, logWithStack } from '../logger.js';\r\nimport rateLimit from './rate_limit.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// 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 attachErrorHandlers = (server) => {\r\n server.on('clientError', (error) => {\r\n logWithStack(1, error, `[server] Client error: ${error.message}`);\r\n });\r\n server.on('error', (error) => {\r\n logWithStack(1, error, `[server] Server error: ${error.message}`);\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 attachErrorHandlers(httpServer);\r\n\r\n // Listen\r\n httpServer.listen(serverConfig.port, serverConfig.host);\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 attachErrorHandlers(httpsServer);\r\n\r\n // Listen\r\n httpsServer.listen(serverConfig.ssl.port, serverConfig.host);\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 * 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 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\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 = process.env.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 'colors';\r\nimport dotenv from 'dotenv';\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 server, { startServer } from './server/server.js';\r\nimport { printLogo, printUsage } from './utils.js';\r\n\r\n// Load .env into environment variables\r\ndotenv.config();\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 // Check if cache needs to be updated\r\n await checkAndUpdateCache(options.highcharts || { version: 'latest' });\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 setOptions,\r\n\r\n // Exporting\r\n initExport,\r\n singleExport,\r\n batchExport,\r\n startExport,\r\n killPool,\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":["async","fetch","url","requestOptions","Promise","resolve","reject","protocol","startsWith","https","http","getProtocol","get","res","data","on","chunk","text","error","defaultConfig","puppeteer","args","value","type","description","highcharts","version","envLink","cdnURL","coreScripts","modules","indicators","scripts","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","ssl","force","certPath","rateLimiting","maxRequests","window","delay","trustProxy","skipKey","skipToken","pool","minWorkers","maxWorkers","workLimit","acquireTimeout","createTimeout","destroyTimeout","idleTimeout","createRetryInterval","reaperInterval","listenToProcessExits","logging","level","file","dest","ui","route","other","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","colors","toConsole","toFile","pathCreated","levelsDesc","title","color","listeners","key","option","entries","logToFile","texts","prefix","existsSync","mkdirSync","appendFile","concat","console","log","newLevel","length","Date","toString","split","trim","fn","apply","logWithStack","customMessage","mainMessage","stackMessage","stack","slice","setLogLevel","enableFileLogging","logDest","logFile","endsWith","__dirname","fileURLToPath","URL","fixType","formats","outType","pop","find","t","handleResources","allowedProps","handledResources","correctResources","isCorrectJSON","readFileSync","files","propName","map","item","parsedData","JSON","parse","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","process","hrtime","bigint","Number","ExportError","Error","constructor","super","this","setError","statusCode","cache","activeManifest","sources","hcVersion","appliedConfig","extractVersion","indexOf","fetchAndProcessScript","script","proxyAgent","fetchedModules","shouldThrowError","agent","timeout","env","response","updateCache","config","sourcePath","customScripts","proxyHost","proxyPort","HttpsProxyAgent","moduleScripts","allFetchPromises","all","fetchScripts","c","m","writeFileSync","checkAndUpdateCache","manifestPath","requestUpdate","manifest","moduleMap","numberOfModules","some","moduleName","newManifest","saveConfigToManifest","getCachePath","cache$1","newVersion","assign","generalOptions","getOptions","mergeConfigOptions","newOptions","mergedOptions","updateDefaultConfig","configObj","customObj","customValue","numEnvVal","el","initOptions","items","recursiveProps","objectToUpdate","nestedNames","shift","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","close","isConnected","__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","parseFloat","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","puppeteerArgs","performedExports","exportAttempts","timeSpent","droppedExports","spentAverage","poolConfig","factory","create","id","uuid","startDate","getTime","browserNewPage","isClosed","workCount","random","validate","workerHandle","initPool","code","killPool","exit","allArgs","tryCount","open","launch","headless","userDataDir","createBrowser","parseInt","Pool","acquireTimeoutMillis","createTimeoutMillis","destroyTimeoutMillis","idleTimeoutMillis","createRetryIntervalMillis","reapIntervalMillis","propagateCreateError","resource","eventId","initialResources","acquire","promise","release","browserClose","destroyed","postWork","getPoolInfo","acquireCounter","payload","requestId","workStart","exportCounter","result","exportTime","numFree","numUsed","numPendingAcquires","pool$1","available","inUse","pendingAcquire","startExport","settings","endCallback","svg","initExportSettings","exportAsString","doStraightInject","doExport","findChartSize","exporting","precision","multiplier","pow","roundNumber","sourceHeight","sourceWidth","param","chartJson","customLogicOptions","allowCodeExecutionScoped","enabled","optionsName","stringToExport","chartJSON","logErrorMiddleware","req","next","NODE_ENV","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","ipRegEx","isPrivateRangeUrlFound","info","removeAllListeners","Buffer","from","header","attachment","params","filename","pkgFile","pather","serverStartTime","express","disable","cors","storage","multer","memoryStorage","upload","limits","fieldSize","limit","urlencoded","extended","none","attachErrorHandlers","startServer","serverConfig","httpServer","createServer","listen","cert","fsPromises","readFile","posix","httpsServer","NaN","static","bootTime","uptime","floor","highchartsVersion","averageProcessingTime","failedExports","sucessRatio","healthRoute","post","exportRoutes","sendFile","uiRoute","adminToken","HIGHCHARTS_ADMIN_TOKEN","token","vSwitchRoute","errorHandler","enableRateLimiting","getExpress","getApp","middlewares","dotenv","index","setOptions","userOptions","configIndex","findIndex","arg","fileName","loadConfigFile","showUsage","propertiesChain","argumentType","reduce","prop","pairArgumentValue","initExport","initLogging","singleExport","batchExport","batchFunctions","pair","mapToNewConfig","oldOptions","manualConfig","configFileName","configFile","choice","prompts","onSubmit","p","categories","questionsCounter","allQuestions","section","prompt","answer","module","writeFile","printLogo","packageVersion"],"mappings":"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"} \ No newline at end of file