From 067e0266c3d3d24a21fbc15e66d4b8470c143304 Mon Sep 17 00:00:00 2001 From: PaulDalek Date: Mon, 13 May 2024 16:25:35 +0200 Subject: [PATCH] Small performance and other corrections. --- dist/index.cjs | 4 +- dist/index.esm.js | 2 +- dist/index.esm.js.map | 2 +- lib/browser.js | 26 ++-- lib/index.js | 12 +- lib/pool.js | 10 +- lib/sanitize.js | 2 +- lib/schemas/config.js | 2 +- package-lock.json | 239 ++----------------------------- package.json | 8 +- tests/cli/scenarios/constr.json | 2 +- tests/http/scenarios/constr.json | 3 - 12 files changed, 48 insertions(+), 264 deletions(-) diff --git a/dist/index.cjs b/dist/index.cjs index c0050e71..2f726829 100644 --- a/dist/index.cjs +++ b/dist/index.cjs @@ -1,2 +1,2 @@ -"use strict";require("colors");var e=require("fs"),t=require("path"),r=require("https-proxy-agent"),i=require("prompts"),o=require("dotenv"),n=require("zod"),s=require("url"),a=require("http"),l=require("https"),c=require("tarn"),p=require("uuid"),u=require("puppeteer"),h=require("jsdom"),d=require("dompurify"),g=require("cors"),m=require("express"),f=require("multer"),v=require("express-rate-limit"),y="undefined"!=typeof document?document.currentScript:null;function b(e){var t=Object.create(null);return e&&Object.keys(e).forEach((function(r){if("default"!==r){var i=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,i.get?i:{enumerable:!0,get:function(){return e[r]}})}})),t.default=e,Object.freeze(t)}var w=b(s);const E={core:["highcharts","highcharts-more","highcharts-3d"],modules:["stock","map","gantt","exporting","export-data","parallel-coordinates","accessibility","boost-canvas","boost","data","data-tools","draggable-points","static-scale","broken-axis","heatmap","tilemap","tiledwebmap","timeline","treemap","treegraph","item-series","drilldown","histogram-bellcurve","bullet","funnel","funnel3d","geoheatmap","pyramid3d","networkgraph","overlapping-datalabels","pareto","pattern-fill","pictorial","price-indicator","sankey","arc-diagram","dependency-wheel","series-label","solid-gauge","sonification","streamgraph","sunburst","variable-pie","variwide","vector","venn","windbarb","wordcloud","xrange","no-data-to-display","drag-panes","debugger","dumbbell","lollipop","cylinder","organization","dotplot","marker-clusters","hollowcandlestick","heikinashi","flowmap"],indicators:["indicators-all"]},T={puppeteer:{args:{value:["--allow-running-insecure-content","--ash-no-nudges","--autoplay-policy=user-gesture-required","--block-new-web-contents","--disable-accelerated-2d-canvas","--disable-background-networking","--disable-background-timer-throttling","--disable-backgrounding-occluded-windows","--disable-breakpad","--disable-checker-imaging","--disable-client-side-phishing-detection","--disable-component-extensions-with-background-pages","--disable-component-update","--disable-default-apps","--disable-dev-shm-usage","--disable-domain-reliability","--disable-extensions","--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,MediaRouter,Translate,WebOTP","--disable-hang-monitor","--disable-ipc-flooding-protection","--disable-logging","--disable-notifications","--disable-offer-store-unmasked-wallet-cards","--disable-popup-blocking","--disable-print-preview","--disable-prompt-on-repost","--disable-renderer-backgrounding","--disable-search-engine-choice-screen","--disable-session-crashed-bubble","--disable-setuid-sandbox","--disable-site-isolation-trials","--disable-speech-api","--disable-sync","--enable-unsafe-webgpu","--hide-crash-restore-bubble","--hide-scrollbars","--metrics-recording-only","--mute-audio","--no-default-browser-check","--no-first-run","--no-pings","--no-sandbox","--no-startup-window","--no-zygote","--password-store=basic","--process-per-tab","--use-mock-keychain"],type:"string[]",description:"Arguments array to send to Puppeteer."}},highcharts:{version:{value:"latest",type:"string",envLink:"HIGHCHARTS_VERSION",description:"The Highcharts version to be used."},cdnURL:{value:"https://code.highcharts.com/",type:"string",envLink:"HIGHCHARTS_CDN_URL",description:"The CDN URL for Highcharts scripts to be used."},coreScripts:{value:E.core,type:"string[]",envLink:"HIGHCHARTS_CORE_SCRIPTS",description:"The core Highcharts scripts to fetch."},moduleScripts:{value:E.modules,type:"string[]",envLink:"HIGHCHARTS_MODULE_SCRIPTS",description:"The modules of Highcharts to fetch."},indicatorScripts:{value:E.indicators,type:"string[]",envLink:"HIGHCHARTS_INDICATOR_SCRIPTS",description:"The indicators of Highcharts to fetch."},customScripts:{value:["https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js","https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.34/moment-timezone-with-data.min.js"],type:"string[]",description:"Additional custom scripts or dependencies to fetch."},forceFetch:{value:!1,type:"boolean",envLink:"HIGHCHARTS_FORCE_FETCH",description:"The flag to determine whether to refetch all scripts after each server rerun."},cachePath:{value:".cache",type:"string",envLink:"HIGHCHARTS_CACHE_PATH",description:"The path to the cache directory. It is used to store the Highcharts scripts and custom scripts."}},export:{infile:{value:!1,type:"string",description:"The input file should include a name and a type (json or svg). It must be correctly formatted as a JSON or SVG file."},instr:{value:!1,type:"string",description:"Input, provided in the form of a stringified JSON or SVG file, will override the --infile option."},options:{value:!1,type:"string",description:"An alias for the --instr option."},outfile:{value:!1,type:"string",description:"The output filename along with a type (jpeg, png, pdf, or svg). This will ignore the --type flag."},type:{value:"png",type:"string",envLink:"EXPORT_TYPE",description:"The file export format. It can be jpeg, png, pdf, or svg."},constr:{value:"chart",type:"string",envLink:"EXPORT_CONSTR",description:"The constructor to use. Can be chart, stockChart, mapChart, or ganttChart."},defaultHeight:{value:400,type:"number",envLink:"EXPORT_DEFAULT_HEIGHT",description:"the default height of the exported chart. Used when no value is set."},defaultWidth:{value:600,type:"number",envLink:"EXPORT_DEFAULT_WIDTH",description:"The default width of the exported chart. Used when no value is set."},defaultScale:{value:1,type:"number",envLink:"EXPORT_DEFAULT_SCALE",description:"The default scale of the exported chart. Used when no value is set."},height:{value:!1,type:"number",description:"The height of the exported chart, overriding the option in the chart settings."},width:{value:!1,type:"number",description:"The width of the exported chart, overriding the option in the chart settings."},scale:{value:!1,type:"number",description:"The scale of the exported chart, overriding the option in the chart settings. Ranges between 0.1 and 5.0."},globalOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing options to be passed into the Highcharts.setOptions."},themeOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing theme options to be passed into the Highcharts.setOptions."},batch:{value:!1,type:"string",description:'Initiates a batch job with a string containing input/output pairs: "in=out;in=out;...".'},rasterizationTimeout:{value:1500,type:"number",envLink:"EXPORT_RASTERIZATION_TIMEOUT",description:"The duration in milliseconds to wait for rendering a webpage."}},customLogic:{allowCodeExecution:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",description:"Controls whether the execution of arbitrary code is allowed during the exporting process."},allowFileResources:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",description:"Controls the ability to inject resources from the filesystem. This setting has no effect when running as a server."},customCode:{value:!1,type:"string",description:"Custom code to execute before chart initialization. It can be a function, code wrapped within a function, or a filename with the .js extension."},callback:{value:!1,type:"string",description:"JavaScript code to run during construction. It can be a function or a filename with the .js extension."},resources:{value:!1,type:"string",description:"Additional resource in the form of a stringified JSON, which may contain files, js, and css sections."},loadConfig:{value:!1,type:"string",legacyName:"fromFile",description:"A file containing a pre-defined configuration to use."},createConfig:{value:!1,type:"string",description:"Enables setting options through a prompt and saving them in a provided config file."}},server:{enable:{value:!1,type:"boolean",envLink:"SERVER_ENABLE",cliName:"enableServer",description:"When set to true, the server starts on the local IP address 0.0.0.0."},host:{value:"0.0.0.0",type:"string",envLink:"SERVER_HOST",description:"The hostname of the server. Additionally, it starts a server on the provided hostname."},port:{value:7801,type:"number",envLink:"SERVER_PORT",description:"The server port when enabled."},benchmarking:{value:!1,type:"boolean",envLink:"SERVER_BENCHMARKING",cliName:"serverBenchmarking",description:"Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request."},proxy:{host:{value:!1,type:"string",envLink:"SERVER_PROXY_HOST",cliName:"proxyHost",description:"The host of the proxy server to use, if it exists."},port:{value:8080,type:"number",envLink:"SERVER_PROXY_PORT",cliName:"proxyPort",description:"The port of the proxy server to use, if it exists."},timeout:{value:5e3,type:"number",envLink:"SERVER_PROXY_TIMEOUT",cliName:"proxyTimeout",description:"The timeout for the proxy server to use, if it exists."}},rateLimiting:{enable:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_ENABLE",cliName:"enableRateLimiting",description:"Enables rate limiting for the server."},maxRequests:{value:10,type:"number",envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",legacyName:"rateLimit",description:"The maximum number of requests allowed in one minute."},window:{value:1,type:"number",envLink:"SERVER_RATE_LIMITING_WINDOW",description:"The time window, in minutes, for the rate limiting."},delay:{value:0,type:"number",envLink:"SERVER_RATE_LIMITING_DELAY",description:"The delay duration for each successive request before reaching the maximum limit."},trustProxy:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",description:"Set this to true if the server is behind a load balancer."},skipKey:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_KEY",description:"Allows bypassing the rate limiter and should be provided with the skipToken argument."},skipToken:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",description:"Allows bypassing the rate limiter and should be provided with the skipKey argument."}},ssl:{enable:{value:!1,type:"boolean",envLink:"SERVER_SSL_ENABLE",cliName:"enableSsl",description:"Enables or disables the SSL protocol."},force:{value:!1,type:"boolean",envLink:"SERVER_SSL_FORCE",cliName:"sslForce",legacyName:"sslOnly",description:"When set to true, the server is forced to serve only over HTTPS."},port:{value:443,type:"number",envLink:"SERVER_SSL_PORT",cliName:"sslPort",description:"The port on which to run the SSL server."},certPath:{value:!1,type:"string",envLink:"SERVER_SSL_CERT_PATH",legacyName:"sslPath",description:"The path to the SSL certificate/key file."}}},pool:{minWorkers:{value:4,type:"number",envLink:"POOL_MIN_WORKERS",description:"The number of minimum and initial pool workers to spawn."},maxWorkers:{value:8,type:"number",envLink:"POOL_MAX_WORKERS",legacyName:"workers",description:"The number of maximum pool workers to spawn."},workLimit:{value:40,type:"number",envLink:"POOL_WORK_LIMIT",description:"The number of work pieces that can be performed before restarting the worker process."},acquireTimeout:{value:5e3,type:"number",envLink:"POOL_ACQUIRE_TIMEOUT",description:"The duration, in milliseconds, to wait for acquiring a resource."},createTimeout:{value:5e3,type:"number",envLink:"POOL_CREATE_TIMEOUT",description:"The duration, in milliseconds, to wait for creating a resource."},destroyTimeout:{value:5e3,type:"number",envLink:"POOL_DESTROY_TIMEOUT",description:"The duration, in milliseconds, to wait for destroying a resource."},idleTimeout:{value:3e4,type:"number",envLink:"POOL_IDLE_TIMEOUT",description:"The duration, in milliseconds, after which an idle resource is destroyed."},createRetryInterval:{value:200,type:"number",envLink:"POOL_CREATE_RETRY_INTERVAL",description:"The duration, in milliseconds, to wait before retrying the create process in case of a failure."},reaperInterval:{value:1e3,type:"number",envLink:"POOL_REAPER_INTERVAL",description:"The duration, in milliseconds, after which the check for idle resources to destroy is triggered."},benchmarking:{value:!1,type:"boolean",envLink:"POOL_BENCHMARKING",cliName:"poolBenchmarking",description:"Indicate whether to show statistics for the pool of resources or not."}},logging:{level:{value:4,type:"number",envLink:"LOGGING_LEVEL",cliName:"logLevel",description:"The logging level to be used."},file:{value:"highcharts-export-server.log",type:"string",envLink:"LOGGING_FILE",cliName:"logFile",description:"The name of a log file. The logDest option also needs to be set to enable file logging."},dest:{value:"log/",type:"string",envLink:"LOGGING_DEST",cliName:"logDest",description:"The path to store log files. This also enables file logging."}},ui:{enable:{value:!1,type:"boolean",envLink:"UI_ENABLE",cliName:"enableUi",description:"Enables or disables the user interface (UI) for the export server."},route:{value:"/",type:"string",envLink:"UI_ROUTE",cliName:"uiRoute",description:"The endpoint route to which the user interface (UI) should be attached."}},other:{nodeEnv:{value:"production",type:"string",envLink:"OTHER_NODE_ENV",description:"The type of Node.js environment."},listenToProcessExits:{value:!0,type:"boolean",envLink:"OTHER_LISTEN_TO_PROCESS_EXITS",description:"Decides whether or not to attach process.exit handlers."},noLogo:{value:!1,type:"boolean",envLink:"OTHER_NO_LOGO",description:"Skip printing the logo on a startup. Will be replaced by a simple text."},hardResetPage:{value:!1,type:"boolean",envLink:"OTHER_HARD_RESET_PAGE",description:"Decides if the page content should be reset entirely."}},debug:{enable:{value:!1,type:"boolean",envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"."},headless:{value:!0,type:"boolean",envLink:"DEBUG_HEADLESS",description:"."},devtools:{value:!1,type:"boolean",envLink:"DEBUG_DEVTOOLS",description:"."},listenToConsole:{value:!1,type:"boolean",envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"."},dumpio:{value:!1,type:"boolean",envLink:"DEBUG_DUMPIO",description:"."},slowMo:{value:0,type:"number",envLink:"DEBUG_SLOW_MO",description:"."},debuggingPort:{value:9222,type:"number",envLink:"DEBUG_DEBUGGING_PORT",description:"."}}},S={puppeteer:[{type:"list",name:"args",message:"Puppeteer arguments",initial:T.puppeteer.args.value.join(","),separator:","}],highcharts:[{type:"text",name:"version",message:"Highcharts version",initial:T.highcharts.version.value},{type:"text",name:"cdnURL",message:"The URL of CDN",initial:T.highcharts.cdnURL.value},{type:"multiselect",name:"coreScripts",message:"Available core scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:T.highcharts.coreScripts.value},{type:"multiselect",name:"moduleScripts",message:"Available module scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:T.highcharts.moduleScripts.value},{type:"multiselect",name:"indicatorScripts",message:"Available indicator scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:T.highcharts.indicatorScripts.value},{type:"list",name:"customScripts",message:"Custom scripts",initial:T.highcharts.customScripts.value.join(","),separator:","},{type:"toggle",name:"forceFetch",message:"Force re-fetch the scripts",initial:T.highcharts.forceFetch.value},{type:"text",name:"cachePath",message:"The path to the cache directory",initial:T.highcharts.cachePath.value}],export:[{type:"select",name:"type",message:"The default export file type",hint:`Default: ${T.export.type.value}`,initial:0,choices:["png","jpeg","pdf","svg"]},{type:"select",name:"constr",message:"The default constructor for Highcharts",hint:`Default: ${T.export.constr.value}`,initial:0,choices:["chart","stockChart","mapChart","ganttChart"]},{type:"number",name:"defaultHeight",message:"The default fallback height of the exported chart",initial:T.export.defaultHeight.value},{type:"number",name:"defaultWidth",message:"The default fallback width of the exported chart",initial:T.export.defaultWidth.value},{type:"number",name:"defaultScale",message:"The default fallback scale of the exported chart",initial:T.export.defaultScale.value,min:.1,max:5},{type:"number",name:"rasterizationTimeout",message:"The rendering webpage timeout in milliseconds",initial:T.export.rasterizationTimeout.value}],customLogic:[{type:"toggle",name:"allowCodeExecution",message:"Enable execution of custom code",initial:T.customLogic.allowCodeExecution.value},{type:"toggle",name:"allowFileResources",message:"Enable file resources",initial:T.customLogic.allowFileResources.value}],server:[{type:"toggle",name:"enable",message:"Starts the server on 0.0.0.0",initial:T.server.enable.value},{type:"text",name:"host",message:"Server hostname",initial:T.server.host.value},{type:"number",name:"port",message:"Server port",initial:T.server.port.value},{type:"toggle",name:"benchmarking",message:"Enable server benchmarking",initial:T.server.benchmarking.value},{type:"text",name:"proxy.host",message:"The host of the proxy server to use",initial:T.server.proxy.host.value},{type:"number",name:"proxy.port",message:"The port of the proxy server to use",initial:T.server.proxy.port.value},{type:"number",name:"proxy.timeout",message:"The timeout for the proxy server to use",initial:T.server.proxy.timeout.value},{type:"toggle",name:"rateLimiting.enable",message:"Enable rate limiting",initial:T.server.rateLimiting.enable.value},{type:"number",name:"rateLimiting.maxRequests",message:"The maximum requests allowed per minute",initial:T.server.rateLimiting.maxRequests.value},{type:"number",name:"rateLimiting.window",message:"The rate-limiting time window in minutes",initial:T.server.rateLimiting.window.value},{type:"number",name:"rateLimiting.delay",message:"The delay for each successive request before reaching the maximum",initial:T.server.rateLimiting.delay.value},{type:"toggle",name:"rateLimiting.trustProxy",message:"Set to true if behind a load balancer",initial:T.server.rateLimiting.trustProxy.value},{type:"text",name:"rateLimiting.skipKey",message:"Allows bypassing the rate limiter when provided with the skipToken argument",initial:T.server.rateLimiting.skipKey.value},{type:"text",name:"rateLimiting.skipToken",message:"Allows bypassing the rate limiter when provided with the skipKey argument",initial:T.server.rateLimiting.skipToken.value},{type:"toggle",name:"ssl.enable",message:"Enable SSL protocol",initial:T.server.ssl.enable.value},{type:"toggle",name:"ssl.force",message:"Force serving only over HTTPS",initial:T.server.ssl.force.value},{type:"number",name:"ssl.port",message:"SSL server port",initial:T.server.ssl.port.value},{type:"text",name:"ssl.certPath",message:"The path to find the SSL certificate/key",initial:T.server.ssl.certPath.value}],pool:[{type:"number",name:"minWorkers",message:"The initial number of workers to spawn",initial:T.pool.minWorkers.value},{type:"number",name:"maxWorkers",message:"The maximum number of workers to spawn",initial:T.pool.maxWorkers.value},{type:"number",name:"workLimit",message:"The pieces of work that can be performed before restarting a Puppeteer process",initial:T.pool.workLimit.value},{type:"number",name:"acquireTimeout",message:"The number of milliseconds to wait for acquiring a resource",initial:T.pool.acquireTimeout.value},{type:"number",name:"createTimeout",message:"The number of milliseconds to wait for creating a resource",initial:T.pool.createTimeout.value},{type:"number",name:"destroyTimeout",message:"The number of milliseconds to wait for destroying a resource",initial:T.pool.destroyTimeout.value},{type:"number",name:"idleTimeout",message:"The number of milliseconds after an idle resource is destroyed",initial:T.pool.idleTimeout.value},{type:"number",name:"createRetryInterval",message:"The retry interval in milliseconds after a create process fails",initial:T.pool.createRetryInterval.value},{type:"number",name:"reaperInterval",message:"The reaper interval in milliseconds after triggering the check for idle resources to destroy",initial:T.pool.reaperInterval.value},{type:"toggle",name:"benchmarking",message:"Enable benchmarking for a resource pool",initial:T.pool.benchmarking.value}],logging:[{type:"number",name:"level",message:"The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)",initial:T.logging.level.value,round:0,min:0,max:5},{type:"text",name:"file",message:"A log file name. Set with the --logDest to enable file logging",initial:T.logging.file.value},{type:"text",name:"dest",message:"The path to log files. Enables file logging",initial:T.logging.dest.value}],ui:[{type:"toggle",name:"enable",message:"Enable UI for the export server",initial:T.ui.enable.value},{type:"text",name:"route",message:"A route to attach the UI",initial:T.ui.route.value}],other:[{type:"text",name:"nodeEnv",message:"The type of Node.js environment",initial:T.other.nodeEnv.value},{type:"toggle",name:"listenToProcessExits",message:"Set to false to skip attaching process.exit handlers",initial:T.other.listenToProcessExits.value},{type:"toggle",name:"noLogo",message:"Skip printing the logo on startup. Replaced by simple text",initial:T.other.noLogo.value},{type:"toggle",name:"hardResetPage",message:"Decides if the page content should be reset entirely",initial:T.other.hardResetPage.value}],debug:[{type:"toggle",name:"enable",message:"Enable debug mode for the browser instance",initial:T.debug.enable.value},{type:"toggle",name:"headless",message:"",initial:T.debug.headless.value},{type:"toggle",name:"devtools",message:"",initial:T.debug.devtools.value},{type:"toggle",name:"listenToConsole",message:"",initial:T.debug.listenToConsole.value},{type:"toggle",name:"dumpio",message:"",initial:T.debug.dumpio.value},{type:"number",name:"slowMo",message:"",initial:T.debug.slowMo.value},{type:"number",name:"debuggingPort",message:"",initial:T.debug.debuggingPort.value}]},x=["options","globalOptions","themeOptions","resources","payload"],R={},L=(e,t="")=>{Object.keys(e).forEach((r=>{if(!["puppeteer","highcharts"].includes(r)){const i=e[r];void 0===i.value?L(i,`${t}.${r}`):(R[i.cliName||r]=`${t}.${r}`.substring(1),void 0!==i.legacyName&&(R[i.legacyName]=`${t}.${r}`.substring(1)))}}))};L(T),o.config();const O=e=>n.z.string().transform((t=>t.split(",").map((e=>e.trim())).filter((t=>e.includes(t))))).transform((e=>e.length?e:void 0)),_=()=>n.z.enum(["true","false",""]).transform((e=>""!==e?"true"===e:void 0)),k=e=>n.z.enum([...e,""]).transform((e=>""!==e?e:void 0)),I=()=>n.z.string().trim().refine((e=>!["false","undefined","null","NaN"].includes(e)||""===e),(e=>({message:`The string contains forbidden values, received '${e}'`}))).transform((e=>""!==e?e:void 0)),C=()=>n.z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>0),(e=>({message:`The value must be numeric and positive, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),A=()=>n.z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0),(e=>({message:`The value must be numeric and non-negative, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),N=n.z.object({HIGHCHARTS_VERSION:n.z.string().trim().refine((e=>/^(latest|\d+(\.\d+){0,2})$/.test(e)||""===e),(e=>({message:`HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CDN_URL:n.z.string().trim().refine((e=>e.startsWith("https://")||e.startsWith("http://")||""===e),(e=>({message:`Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CORE_SCRIPTS:O(E.core),HIGHCHARTS_MODULE_SCRIPTS:O(E.modules),HIGHCHARTS_INDICATOR_SCRIPTS:O(E.indicators),HIGHCHARTS_FORCE_FETCH:_(),HIGHCHARTS_CACHE_PATH:I(),HIGHCHARTS_ADMIN_TOKEN:I(),EXPORT_TYPE:k(["jpeg","png","pdf","svg"]),EXPORT_CONSTR:k(["chart","stockChart","mapChart","ganttChart"]),EXPORT_DEFAULT_HEIGHT:C(),EXPORT_DEFAULT_WIDTH:C(),EXPORT_DEFAULT_SCALE:C(),EXPORT_RASTERIZATION_TIMEOUT:A(),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:_(),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:_(),SERVER_ENABLE:_(),SERVER_HOST:I(),SERVER_PORT:C(),SERVER_BENCHMARKING:_(),SERVER_PROXY_HOST:I(),SERVER_PROXY_PORT:C(),SERVER_PROXY_TIMEOUT:A(),SERVER_RATE_LIMITING_ENABLE:_(),SERVER_RATE_LIMITING_MAX_REQUESTS:A(),SERVER_RATE_LIMITING_WINDOW:A(),SERVER_RATE_LIMITING_DELAY:A(),SERVER_RATE_LIMITING_TRUST_PROXY:_(),SERVER_RATE_LIMITING_SKIP_KEY:I(),SERVER_RATE_LIMITING_SKIP_TOKEN:I(),SERVER_SSL_ENABLE:_(),SERVER_SSL_FORCE:_(),SERVER_SSL_PORT:C(),SERVER_SSL_CERT_PATH:I(),POOL_MIN_WORKERS:A(),POOL_MAX_WORKERS:A(),POOL_WORK_LIMIT:C(),POOL_ACQUIRE_TIMEOUT:A(),POOL_CREATE_TIMEOUT:A(),POOL_DESTROY_TIMEOUT:A(),POOL_IDLE_TIMEOUT:A(),POOL_CREATE_RETRY_INTERVAL:A(),POOL_REAPER_INTERVAL:A(),POOL_BENCHMARKING:_(),LOGGING_LEVEL:n.z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0&&parseFloat(e)<=5),(e=>({message:`Invalid value for LOGGING_LEVEL. We only accept values from 0 to 5 as logging levels, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),LOGGING_FILE:I(),LOGGING_DEST:I(),UI_ENABLE:_(),UI_ROUTE:I(),OTHER_NODE_ENV:k(["development","production","test"]),OTHER_LISTEN_TO_PROCESS_EXITS:_(),OTHER_NO_LOGO:_(),OTHER_HARD_RESET_PAGE:_(),DEBUG_ENABLE:_(),DEBUG_HEADLESS:_(),DEBUG_DEVTOOLS:_(),DEBUG_LISTEN_TO_CONSOLE:_(),DEBUG_DUMPIO:_(),DEBUG_SLOW_MO:A(),DEBUG_DEBUGGING_PORT:C()}).partial().parse(process.env),P=["red","yellow","blue","gray","green"];let H={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:P[0]},{title:"warning",color:P[1]},{title:"notice",color:P[2]},{title:"verbose",color:P[3]},{title:"benchmark",color:P[4]}],listeners:[]};for(const[e,t]of Object.entries(T.logging))H[e]=t.value;const $=(t,r)=>{H.toFile&&(H.pathCreated||(!e.existsSync(H.dest)&&e.mkdirSync(H.dest),H.pathCreated=!0),e.appendFile(`${H.dest}${H.file}`,[r].concat(t).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),H.toFile=!1)})))},U=(...e)=>{const[t,...r]=e,{level:i,levelsDesc:o}=H;if(5!==t&&(0===t||t>i||i>o.length))return;const n=`${(new Date).toString().split("(")[0].trim()} [${o[t-1].title}] -`;H.listeners.forEach((e=>{e(n,r.join(" "))})),H.toConsole&&console.log.apply(void 0,[n.toString()[H.levelsDesc[t-1].color]].concat(r)),$(r,n)},j=(e,t,r)=>{const i=r||t.message,{level:o,levelsDesc:n}=H;if(0===e||e>o||o>n.length)return;const s=`${(new Date).toString().split("(")[0].trim()} [${n[e-1].title}] -`,a=t.message!==t.stackMessage||void 0===t.stackMessage?t.stack:t.stack.split("\n").slice(1).join("\n"),l=[i,"\n",a];H.toConsole&&console.log.apply(void 0,[s.toString()[H.levelsDesc[e-1].color]].concat([i[P[e-1]],"\n",a])),H.listeners.forEach((e=>{e(s,l.join(" "))})),$(l,s)},D=e=>{e>=0&&e<=H.levelsDesc.length&&(H.level=e)},G=(e,t)=>{if(H={...H,dest:e||H.dest,file:t||H.file,toFile:!0},0===H.dest.length)return U(1,"[logger] File logging initialization: no path supplied.");H.dest.endsWith("/")||(H.dest+="/")},F=s.fileURLToPath(new URL("../.","undefined"==typeof document?require("url").pathToFileURL(__filename).href:y&&y.src||new URL("index.cjs",document.baseURI).href)),M=(e,t)=>{const r=["png","jpeg","pdf","svg"];if(t){const i=t.split(".").pop();"jpg"===i?e="jpeg":r.includes(i)&&e!==i&&(e=i)}return{"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"}[e]||r.find((t=>t===e))||"png"},q=(t=!1,r)=>{const i=["js","css","files"];let o=t,n=!1;if(r&&t.endsWith(".json"))try{o=W(e.readFileSync(t,"utf8"))}catch(e){return j(2,e,"[cli] No resources found.")}else o=W(t),o&&!r&&delete o.files;for(const e in o)i.includes(e)?n||(n=!0):delete o[e];return n?(o.files&&(o.files=o.files.map((e=>e.trim())),(!o.files||o.files.length<=0)&&delete o.files),o):U(3,"[cli] No resources found.")};function W(e,t){try{const r=JSON.parse("string"!=typeof e?JSON.stringify(e):e);return"string"!=typeof r&&t?JSON.stringify(r):r}catch{return!1}}const V=e=>{if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=V(e[r]));return t},B=(e,t)=>JSON.stringify(e,((e,r)=>("string"==typeof r&&((r=r.trim()).startsWith("function(")||r.startsWith("function ("))&&r.endsWith("}")&&(r=t?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:void 0),"function"==typeof r?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:r))).replaceAll(/"EXP_FUN|EXP_FUN"/g,"");function X(){console.log("\nUsage of CLI arguments:".bold,"\n------",`\nFor more detailed information, visit the readme at: ${"https://github.com/highcharts/node-export-server#readme".bold.yellow}.`);const e=t=>{for(const[r,i]of Object.entries(t))if(Object.prototype.hasOwnProperty.call(i,"value")){let e=` --${i.cliName||r} ${("<"+i.type+">").green} `;if(e.length<48)for(let t=e.length;t<48;t++)e+=".";console.log(e,i.description,`[Default: ${i.value.toString().bold}]`.blue)}else e(i)};Object.keys(T).forEach((t=>{["puppeteer","highcharts"].includes(t)||(console.log(`\n${t.toUpperCase()}`.red),e(T[t]))})),console.log("\n")}const z=e=>!["false","undefined","null","NaN","0",""].includes(e)&&!!e,K=(t,r)=>{if(t&&"string"==typeof t)return(t=t.trim()).endsWith(".js")?!!r&&K(e.readFileSync(t,"utf8")):t.startsWith("function()")||t.startsWith("function ()")||t.startsWith("()=>")||t.startsWith("() =>")?`(${t})()`:t.replace(/;$/,"")},J=()=>{const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6};let Y={};const Q=()=>Y,Z=(e,t,r=[])=>{const i=V(e);for(const[e,n]of Object.entries(t))i[e]="object"!=typeof(o=n)||Array.isArray(o)||null===o||r.includes(e)||void 0===i[e]?void 0!==n?n:i[e]:Z(i[e],n,r);var o;return i};function ee(e,t={},r=""){Object.keys(e).forEach((i=>{const o=e[i],n=t&&t[i];void 0===o.value?ee(o,n,`${r}.${i}`):(void 0!==n&&(o.value=n),o.envLink in N&&void 0!==N[o.envLink]&&(o.value=N[o.envLink]))}))}function te(e){let t={};for(const[r,i]of Object.entries(e))t[r]=Object.prototype.hasOwnProperty.call(i,"value")?i.value:te(i);return t}function re(e,t,r){for(;t.length>1;){const i=t.shift();return Object.prototype.hasOwnProperty.call(e,i)||(e[i]={}),e[i]=re(Object.assign({},e[i]),t,r),e}return e[t[0]]=r,e}async function ie(e,t={}){return new Promise(((r,i)=>{const o=(e=>e.startsWith("https")?l:a)(e);o.get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||i("Nothing was fetched from the URL."),e.text=t,r(e)}))})).on("error",(e=>{i(e)}))}))}class oe extends Error{constructor(e){super(),this.message=e,this.stackMessage=e}setError(e){return this.error=e,e.name&&(this.name=e.name),e.statusCode&&(this.statusCode=e.statusCode),e.stack&&(this.stackMessage=e.message,this.stack=e.stack),this}}const ne={cdnURL:"https://code.highcharts.com/",activeManifest:{},sources:"",hcVersion:""},se=e=>e.sources.substring(0,e.sources.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim(),ae=async(e,t,r,i=!1)=>{e.endsWith(".js")&&(e=e.substring(0,e.length-3)),U(4,`[cache] Fetching script - ${e}.js`);const o=await ie(`${e}.js`,t);if(200===o.statusCode&&"string"==typeof o.text){if(r){r[e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")]=1}return o.text}if(i)throw new oe(`Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${o.statusCode}).`).setError(o);return U(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`),""},le=async(t,i,o)=>{const n=t.version,s="latest"!==n&&n?`${n}/`:"",a=t.cdnURL||ne.cdnURL;U(3,`[cache] Updating cache version to Highcharts: ${s||"latest"}.`);const l={};try{return ne.sources=await(async(e,t,i,o,n)=>{let s;const a=o.host,l=o.port;if(a&&l)try{s=new r.HttpsProxyAgent({host:a,port:l})}catch(e){throw new oe("[cache] Could not create a Proxy Agent.").setError(e)}const c=s?{agent:s,timeout:N.SERVER_PROXY_TIMEOUT}:{},p=[...e.map((e=>ae(`${e}`,c,n,!0))),...t.map((e=>ae(`${e}`,c,n))),...i.map((e=>ae(`${e}`,c)))];return(await Promise.all(p)).join(";\n")})([...t.coreScripts.map((e=>`${a}${s}${e}`))],[...t.moduleScripts.map((e=>"map"===e?`${a}maps/${s}modules/${e}`:`${a}${s}modules/${e}`)),...t.indicatorScripts.map((e=>`${a}stock/${s}indicators/${e}`))],t.customScripts,i,l),ne.hcVersion=se(ne),e.writeFileSync(o,ne.sources),l}catch(e){throw new oe("[cache] Unable to update the local Highcharts cache.").setError(e)}},ce=async r=>{const{highcharts:i,server:o}=r,n=t.join(F,i.cachePath);let s;const a=t.join(n,"manifest.json"),l=t.join(n,"sources.js");if(!e.existsSync(n)&&e.mkdirSync(n),!e.existsSync(a)||i.forceFetch)U(3,"[cache] Fetching and caching Highcharts dependencies."),s=await le(i,o.proxy,l);else{let t=!1;const r=JSON.parse(e.readFileSync(a));if(r.modules&&Array.isArray(r.modules)){const e={};r.modules.forEach((t=>e[t]=1)),r.modules=e}const{coreScripts:n,moduleScripts:c,indicatorScripts:p}=i,u=n.length+c.length+p.length;r.version!==i.version?(U(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),t=!0):Object.keys(r.modules||{}).length!==u?(U(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),t=!0):t=(c||[]).some((e=>{if(!r.modules[e])return U(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),t?s=await le(i,o.proxy,l):(U(3,"[cache] Dependency cache is up to date, proceeding."),ne.sources=e.readFileSync(l,"utf8"),s=r.modules,ne.hcVersion=se(ne))}await(async(r,i)=>{const o={version:r.version,modules:i||{}};ne.activeManifest=o,U(3,"[cache] Writing a new manifest.");try{e.writeFileSync(t.join(F,r.cachePath,"manifest.json"),JSON.stringify(o),"utf8")}catch(e){throw new oe("[cache] Error writing the cache manifest.").setError(e)}})(i,s)},pe=()=>t.join(F,Q().highcharts.cachePath);var ue=async e=>{const t=Q();t?.highcharts&&(t.highcharts.version=e),await ce(t)},he=()=>ne,de=()=>ne.hcVersion;function ge(){Highcharts.animObject=function(){return{duration:0}}}function me(e,t,r){window._displayErrors=r;const{getOptions:i,merge:o,setOptions:n,wrap:s}=Highcharts;Highcharts.setOptionsObj=o(!1,{},i()),t.customLogic.customCode&&new Function(t.customLogic.customCode)();const a={animation:!1};t.export.strInj&&(a.height=e.chart.height,a.width=e.chart.width),window.isRenderComplete=!1,s(Highcharts.Chart.prototype,"init",(function(e,t,r){((t=o(t,{exporting:{enabled:!1},plotOptions:{series:{label:{enabled:!1}}},tooltip:{}})).series||[]).forEach((function(e){e.animation=!1})),window.onHighchartsRender||(window.onHighchartsRender=Highcharts.addEvent(this,"render",(()=>{window.isRenderComplete=!0}))),e.apply(this,[t,r])})),s(Highcharts.Series.prototype,"init",(function(e,t,r){e.apply(this,[t,r])}));const l=t.export.strInj?new Function(`return ${t.export.strInj}`)():e,c=o(!1,JSON.parse(t.export.themeOptions),l,{chart:a}),p=t.customLogic.callback?new Function(`return ${t.customLogic.callback}`)():void 0;n(JSON.parse(t.export.globalOptions)),Highcharts[t.export.constr||"chart"]("container",c,p);const u=i();for(const e in u)"function"!=typeof u[e]&&delete u[e];n(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const fe=w.fileURLToPath(new URL(".","undefined"==typeof document?require("url").pathToFileURL(__filename).href:y&&y.src||new URL("index.cjs",document.baseURI).href)),ve=e.readFileSync(fe+"/../templates/template.html","utf8");let ye;async function be(){if(!ye)return!1;const e=await ye.newPage();return await e.setCacheEnabled(!1),await Ee(e),e}async function we(e,t=!1){try{t?(await e.goto("about:blank",{waitUntil:"domcontentloaded"}),await Ee(e)):await e.evaluate((()=>{document.body.innerHTML='
'}))}catch(e){j(2,e,"[browser] Could not clear the content of the page.")}}async function Ee(e){await e.setContent(ve,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:`${pe()}/sources.js`}),await e.evaluate(ge)}const Te=w.fileURLToPath(new URL(".","undefined"==typeof document?require("url").pathToFileURL(__filename).href:y&&y.src||new URL("index.cjs",document.baseURI).href)),Se=(e,t,r,i)=>e.evaluate(me,t,r,i);var xe=async(r,i,o)=>{const n=[],s=async e=>{for(const e of n)await e.dispose();await e.evaluate((()=>{if("undefined"!=typeof Highcharts){const e=Highcharts.charts;if(Array.isArray(e)&&e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()}const[...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...r]=document.getElementsByTagName("link");for(const i of[...e,...t,...r])i.remove()}))};try{U(4,"[export] Determining export path.");const a=o.export,l=a?.options?.chart?.displayErrors&&he().activeManifest.modules.debugger;let c;if(i.indexOf&&(i.indexOf("=0||i.indexOf("=0)){if(U(4,"[export] Treating as SVG."),"svg"===a.type)return i;c=!0,await r.setContent((e=>`\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`)(i),{waitUntil:"domcontentloaded"})}else U(4,"[export] Treating as config."),a.strInj?await Se(r,{chart:{height:a.height,width:a.width}},o,l):(i.chart.height=a.height,i.chart.width=a.width,await Se(r,i,o,l));const p=o.customLogic.resources;if(p){const i=[];if(p.js&&i.push({content:p.js}),p.files)for(const t of p.files){const r=!t.startsWith("http");i.push(r?{content:e.readFileSync(t,"utf8")}:{url:t})}for(const e of i)try{n.push(await r.addScriptTag(e))}catch(e){j(2,e,"[export] The JS resource cannot be loaded.")}i.length=0;const s=[];if(p.css){let e=p.css.match(/@import\s*([^;]*);/g);if(e)for(let r of e)r&&(r=r.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),r.startsWith("http")?s.push({url:r}):o.customLogic.allowFileResources&&s.push({path:t.join(Te,r)}));s.push({content:p.css.replace(/@import\s*([^;]*);/g,"")||" "});for(const e of s)try{n.push(await r.addStyleTag(e))}catch(e){j(2,e,"[export] The CSS resource cannot be loaded.")}s.length=0}}const u=c?await r.evaluate((e=>{const t=document.querySelector("#chart-container svg:first-of-type"),r=t.height.baseVal.value*e,i=t.width.baseVal.value*e;return document.body.style.zoom=e,document.body.style.margin="0px",{chartHeight:r,chartWidth:i}}),parseFloat(a.scale)):await r.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return document.body.style.zoom=1,{chartHeight:e,chartWidth:t}})),h=Math.ceil(u.chartHeight||a.height),d=Math.ceil(u.chartWidth||a.width),{x:g,y:m}=await(e=>e.$eval("#chart-container",(e=>{const{x:t,y:r,width:i,height:o}=e.getBoundingClientRect();return{x:t,y:r,width:i,height:Math.trunc(o>1?o:500)}})))(r);let f;if(await r.setViewport({height:h,width:d,deviceScaleFactor:c?1:parseFloat(a.scale)}),"svg"===a.type)f=await(e=>e.$eval("#container svg:first-of-type",(e=>e.outerHTML)))(r);else if(["png","jpeg"].includes(a.type))f=await((e,t,r,i,o)=>Promise.race([e.screenshot({type:t,encoding:r,clip:i,captureBeyondViewport:!0,fullPage:!1,optimizeForSpeed:!0,..."png"!==t?{quality:80}:{},omitBackground:"png"==t}),new Promise(((e,t)=>setTimeout((()=>t(new oe("Rasterization timeout"))),o||1500)))]))(r,a.type,"base64",{width:d,height:h,x:g,y:m},a.rasterizationTimeout);else{if("pdf"!==a.type)throw new oe(`[export] Unsupported output format ${a.type}.`);f=await(async(e,t,r,i)=>(await e.emulateMediaType("screen"),e.pdf({height:t+1,width:r,encoding:i})))(r,h,d,"base64")}return await s(r),f}catch(e){return await s(r),e}};let Re=!1;const Le={performedExports:0,exportAttempts:0,exportFromSvgAttempts:0,timeSpent:0,droppedExports:0,spentAverage:0};let Oe={};const _e={create:async()=>{let e=!1;const t=p.v4(),r=(new Date).getTime();try{if(e=await be(),!e||e.isClosed())throw new oe("The page is invalid or closed.");U(3,`[pool] Successfully created a worker ${t} - took ${(new Date).getTime()-r} ms.`)}catch(e){throw new oe("Error encountered when creating a new page.").setError(e)}const{debug:i}=Q();return i.enable&&i.listenToConsole&&e.on("console",(e=>{console.log(`[debug] ${e.text()}`)})),e.on("pageerror",(async t=>{await e.$eval("#container",((e,t)=>{window._displayErrors&&(e.innerHTML=t)}),`

Chart input data error:

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

Chart input data error:

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

Chart input data error:

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

Chart input data error:

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

Chart input data error:

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

Chart input data error:

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