diff --git a/CHANGELOG.md b/CHANGELOG.md index a9bddb35..cce67244 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,7 +51,8 @@ _Enhancements:_ - Added a new logging level (`5`) for benchmarking logs. - Added legacy names of options to the `defaultConfig` and `mapToNewConfig` function in order to support the old, PhantomJS-based structure of options. - Added a new process event handler for the `SIGHUP` signal. -- Added `mapChart` and `ganttChart` constructors in the exporting UI (#503). +- Added `mapChart` and `ganttChart` constructors in the exporting UI [(#503)](https://github.com/highcharts/node-export-server/issues/503). +- Added the series-on-point module [(#532)](https://github.com/highcharts/node-export-server/issues/532). - Reordered the `error` and `info` arguments in the callback of the `startExport` function. - Updates were made to the `config.js` file. - Updated the `killPool` function. @@ -70,8 +71,8 @@ _Enhancements:_ _Fixes:_ - Fixed `multer` related error: 'Field value too long'. -- Fixed the SSL handshake error (#307). -- Fixed missing background color transparency (#492). +- Fixed the SSL handshake error [(#307)](https://github.com/highcharts/node-export-server/issues/307). +- Fixed missing background color transparency [(#492)](https://github.com/highcharts/node-export-server/issues/492). - Fixed missing `foreignObject` elements issue. - Fixed type compatibility issues in the `pairArgumentValue` function, arising from CLI string arguments. - Fixed the 'httpsProxyAgent is not a constructor' issue with the `https-proxy-agent` module. @@ -112,8 +113,8 @@ _Fixes:_ # 3.0.5 -- Fixed an issue with transparent backgrounds in PNG exports (#463). -- Fixed an issue with missing `filename` property (https://github.com/highcharts/highcharts/issues/20370). +- Fixed an issue with transparent backgrounds in PNG exports [(#463)](https://github.com/highcharts/node-export-server/issues/463). +- Fixed an issue with missing `filename` property [(#20370)](https://github.com/highcharts/highcharts/issues/20370). # 3.0.4 @@ -121,8 +122,8 @@ _Fixes:_ # 3.0.3 -- Fixed an issue with height and width for CSS (#419). -- Fixed `globalOptions` (#434). +- Fixed an issue with height and width for CSS [(#419)](https://github.com/highcharts/node-export-server/issues/419). +- Fixed `globalOptions` [(#434)](https://github.com/highcharts/node-export-server/issues/434). - Other smaller fixes. # 3.0.2 @@ -246,8 +247,8 @@ _Changelog:_ # 2.0.15 - Added `queueSize` option to `initPool` to set the request overfow queue size. -- Added option to supply `cdnURL` to build script (#133). -- Added `;` between included scripts. Fixes map collections (#128). +- Added option to supply `cdnURL` to build script [(#133)](https://github.com/highcharts/node-export-server/issues/133). +- Added `;` between included scripts. Fixes map collections [(#128)](https://github.com/highcharts/node-export-server/issues/128). - Added `--skipKey` and `--skipToken` CLI options to configure the rate limiter. - Added `--queueSize` switch to the CLI options to set the overflow queue size. - Fixed issue with silent installs and default values. diff --git a/dist/index.cjs b/dist/index.cjs index 59bb8994..46efa902 100644 --- a/dist/index.cjs +++ b/dist/index.cjs @@ -1,2 +1,2 @@ -"use strict";require("colors");var e=require("fs"),t=require("path"),r=require("https-proxy-agent"),o=require("prompts"),i=require("dotenv"),n=require("zod"),s=require("url"),a=require("http"),c=require("https"),l=require("tarn"),p=require("uuid"),u=require("puppeteer"),h=require("jsdom"),d=require("dompurify"),m=require("cors"),g=require("express"),f=require("multer"),v=require("express-rate-limit"),y=require("jsonwebtoken"),b=require("ws"),w="undefined"!=typeof document?document.currentScript:null;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."},browserShellMode:{value:!0,type:"boolean",envLink:"OTHER_BROWSER_SHELL_MODE",description:"Decides if the browser runs in the shell mode."}},debug:{enable:{value:!1,type:"boolean",envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"Enables or disables debug mode for the underlying browser."},headless:{value:!0,type:"boolean",envLink:"DEBUG_HEADLESS",description:"Controls the mode in which the browser is launched when in the debug mode."},devtools:{value:!1,type:"boolean",envLink:"DEBUG_DEVTOOLS",description:"Decides whether to enable DevTools when the browser is in a headful state."},listenToConsole:{value:!1,type:"boolean",envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"Decides whether to enable a listener for console messages sent from the browser."},dumpio:{value:!1,type:"boolean",envLink:"DEBUG_DUMPIO",description:"Redirects browser process stdout and stderr to process.stdout and process.stderr."},slowMo:{value:0,type:"number",envLink:"DEBUG_SLOW_MO",description:"Slows down Puppeteer operations by the specified number of milliseconds."},debuggingPort:{value:9222,type:"number",envLink:"DEBUG_DEBUGGING_PORT",description:"Specifies the debugging port."}},webSocket:{enable:{value:!1,type:"boolean",envLink:"WEB_SOCKET_ENABLE",cliName:"enableWs",description:"Enables or disables the WebSocket connection."},reconnect:{value:!1,type:"boolean",envLink:"WEB_SOCKET_RECONNECT",cliName:"wsReconnect",description:"Controls whether or not to try reconnecting to the WebSocket server in case of a disconnect."},rejectUnauthorized:{value:!1,type:"boolean",envLink:"WEB_SOCKET_REJECT_UNAUTHORIZED",cliName:"wsrejectUnauthorized",description:"Determines whether the client verifies the server's SSL/TLS certificate during the handshake process."},pingTimeout:{value:16e3,type:"number",envLink:"WEB_SOCKET_PING_TIMEOUT",cliName:"wsPingTimeout",description:"The timeout, in milliseconds, for the heartbeat mechanism between the client and server."},reconnectInterval:{value:3e3,type:"number",envLink:"WEB_SOCKET_RECONNECT_INTERVAL",cliName:"wsReconnectInterval",description:"The interval, in milliseconds, for the reconnect attempt."},reconnectAttempts:{value:3,type:"number",envLink:"WEB_SOCKET_RECONNECT_ATTEMPTS",cliName:"wsReconnectAttempts",description:"The number of reconnect attempts before returning a connection error."},messageInterval:{value:3,type:"number",envLink:"WEB_SOCKET_MESSAGE_INTERVAL",cliName:"wsMessageInterval",description:"The interval, in milliseconds, for auto sending the data through a WebSocket connection."},url:{value:!1,type:"string",envLink:"WEB_SOCKET_URL",cliName:"wsUrl",description:"The URL of the WebSocket server."},secret:{value:!1,type:"string",envLink:"WEB_SOCKET_SECRET",cliName:"wsSecret",description:"The secret used to create a JSON Web Token sent to the WebSocket server."}}},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},{type:"toggle",name:"browserShellMode",message:"Decides if the browser runs in the shell mode",initial:T.other.browserShellMode.value}],debug:[{type:"toggle",name:"enable",message:"Enables debug mode for the browser instance",initial:T.debug.enable.value},{type:"toggle",name:"headless",message:"The mode setting for the browser",initial:T.debug.headless.value},{type:"toggle",name:"devtools",message:"The DevTools for the headful browser",initial:T.debug.devtools.value},{type:"toggle",name:"listenToConsole",message:"The event listener for console messages from the browser",initial:T.debug.listenToConsole.value},{type:"toggle",name:"dumpio",message:"Redirects the browser stdout and stderr to NodeJS process",initial:T.debug.dumpio.value},{type:"number",name:"slowMo",message:"Puppeteer operations slow down in milliseconds",initial:T.debug.slowMo.value},{type:"number",name:"debuggingPort",message:"The port number for debugging",initial:T.debug.debuggingPort.value}],webSocket:[{type:"toggle",name:"enable",message:"Enables WebSocket connection",initial:T.webSocket.enable.value},{type:"toggle",name:"reconnect",message:"The reconnect mechanism for WebSocket connection",initial:T.webSocket.reconnect.value},{type:"toggle",name:"rejectUnauthorized",message:"Reject connection if WebSocket is not secured, SSL/TLS",initial:T.webSocket.rejectUnauthorized.value},{type:"number",name:"pingTimeout",message:"Timeout for the hearbeat mechanism",initial:T.webSocket.pingTimeout.value},{type:"number",name:"reconnectInterval",message:"Interval for the reconnect mechanism",initial:T.webSocket.reconnectInterval.value},{type:"number",name:"reconnectAttempts",message:"The number of reconnect attempts",initial:T.webSocket.reconnectAttempts.value},{type:"number",name:"messageInterval",message:"Interval for auto sending the data",initial:T.webSocket.messageInterval.value},{type:"text",name:"url",message:"The URL of the WebSocket server",initial:T.webSocket.url.value},{type:"text",name:"secret",message:"The secret for the JWT to WebSocket server",initial:T.webSocket.secret.value}]},_=["options","globalOptions","themeOptions","resources","payload"],R={},k=(e,t="")=>{Object.keys(e).forEach((r=>{if(!["puppeteer","highcharts"].includes(r)){const o=e[r];void 0===o.value?k(o,`${t}.${r}`):(R[o.cliName||r]=`${t}.${r}`.substring(1),void 0!==o.legacyName&&(R[o.legacyName]=`${t}.${r}`.substring(1)))}}))};k(T),i.config();const x=e=>n.z.string().transform((t=>t.split(",").map((e=>e.trim())).filter((t=>e.includes(t))))).transform((e=>e.length?e:void 0)),O=()=>n.z.enum(["true","false",""]).transform((e=>""!==e?"true"===e:void 0)),L=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)),N=()=>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)),A=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:x(E.core),HIGHCHARTS_MODULE_SCRIPTS:x(E.modules),HIGHCHARTS_INDICATOR_SCRIPTS:x(E.indicators),HIGHCHARTS_FORCE_FETCH:O(),HIGHCHARTS_CACHE_PATH:I(),HIGHCHARTS_ADMIN_TOKEN:I(),EXPORT_TYPE:L(["jpeg","png","pdf","svg"]),EXPORT_CONSTR:L(["chart","stockChart","mapChart","ganttChart"]),EXPORT_DEFAULT_HEIGHT:C(),EXPORT_DEFAULT_WIDTH:C(),EXPORT_DEFAULT_SCALE:C(),EXPORT_RASTERIZATION_TIMEOUT:N(),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:O(),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:O(),SERVER_ENABLE:O(),SERVER_HOST:I(),SERVER_PORT:C(),SERVER_BENCHMARKING:O(),SERVER_PROXY_HOST:I(),SERVER_PROXY_PORT:C(),SERVER_PROXY_TIMEOUT:N(),SERVER_RATE_LIMITING_ENABLE:O(),SERVER_RATE_LIMITING_MAX_REQUESTS:N(),SERVER_RATE_LIMITING_WINDOW:N(),SERVER_RATE_LIMITING_DELAY:N(),SERVER_RATE_LIMITING_TRUST_PROXY:O(),SERVER_RATE_LIMITING_SKIP_KEY:I(),SERVER_RATE_LIMITING_SKIP_TOKEN:I(),SERVER_SSL_ENABLE:O(),SERVER_SSL_FORCE:O(),SERVER_SSL_PORT:C(),SERVER_SSL_CERT_PATH:I(),POOL_MIN_WORKERS:N(),POOL_MAX_WORKERS:N(),POOL_WORK_LIMIT:C(),POOL_ACQUIRE_TIMEOUT:N(),POOL_CREATE_TIMEOUT:N(),POOL_DESTROY_TIMEOUT:N(),POOL_IDLE_TIMEOUT:N(),POOL_CREATE_RETRY_INTERVAL:N(),POOL_REAPER_INTERVAL:N(),POOL_BENCHMARKING:O(),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:O(),UI_ROUTE:I(),OTHER_NODE_ENV:L(["development","production","test"]),OTHER_LISTEN_TO_PROCESS_EXITS:O(),OTHER_NO_LOGO:O(),OTHER_HARD_RESET_PAGE:O(),OTHER_BROWSER_SHELL_MODE:O(),DEBUG_ENABLE:O(),DEBUG_HEADLESS:O(),DEBUG_DEVTOOLS:O(),DEBUG_LISTEN_TO_CONSOLE:O(),DEBUG_DUMPIO:O(),DEBUG_SLOW_MO:N(),DEBUG_DEBUGGING_PORT:C(),WEB_SOCKET_ENABLE:O(),WEB_SOCKET_RECONNECT:O(),WEB_SOCKET_REJECT_UNAUTHORIZED:O(),WEB_SOCKET_PING_TIMEOUT:N(),WEB_SOCKET_RECONNECT_INTERVAL:N(),WEB_SOCKET_RECONNECT_ATTEMPTS:N(),WEB_SOCKET_MESSAGE_INTERVAL:N(),WEB_SOCKET_URL:I(),WEB_SOCKET_SECRET:I()}).partial().parse(process.env),P=["red","yellow","blue","gray","green"];let $={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))$[e]=t.value;const H=(t,r)=>{$.toFile&&($.pathCreated||(!e.existsSync($.dest)&&e.mkdirSync($.dest),$.pathCreated=!0),e.appendFile(`${$.dest}${$.file}`,[r].concat(t).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),$.toFile=!1)})))},U=(...e)=>{const[t,...r]=e,{level:o,levelsDesc:i}=$;if(5!==t&&(0===t||t>o||o>i.length))return;const n=`${(new Date).toString().split("(")[0].trim()} [${i[t-1].title}] -`;$.listeners.forEach((e=>{e(n,r.join(" "))})),$.toConsole&&console.log.apply(void 0,[n.toString()[$.levelsDesc[t-1].color]].concat(r)),H(r,n)},j=(e,t,r)=>{const o=r||t.message,{level:i,levelsDesc:n}=$;if(0===e||e>i||i>n.length)return;const s=`${(new Date).toString().split("(")[0].trim()} [${n[e-1].title}] -`,a=t.message!==t.stackMessage||void 0===t.stackMessage?t.stack:t.stack.split("\n").slice(1).join("\n"),c=[o,"\n",a];$.toConsole&&console.log.apply(void 0,[s.toString()[$.levelsDesc[e-1].color]].concat([o[P[e-1]],"\n",a])),$.listeners.forEach((e=>{e(s,c.join(" "))})),H(c,s)},W=e=>{e>=0&&e<=$.levelsDesc.length&&($.level=e)},D=(e,t)=>{if($={...$,dest:e||$.dest,file:t||$.file,toFile:!0},0===$.dest.length)return U(1,"[logger] File logging initialization: no path supplied.");$.dest.endsWith("/")||($.dest+="/")},G=s.fileURLToPath(new URL("../.","undefined"==typeof document?require("url").pathToFileURL(__filename).href:w&&w.src||new URL("index.cjs",document.baseURI).href)),M=(e,t)=>{const r=["png","jpeg","pdf","svg"];if(t){const o=t.split(".").pop();"jpg"===o?e="jpeg":r.includes(o)&&e!==o&&(e=o)}return{"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"}[e]||r.find((t=>t===e))||"png"},F=(t=!1,r)=>{const o=["js","css","files"];let i=t,n=!1;if(r&&t.endsWith(".json"))try{i=q(e.readFileSync(t,"utf8"))}catch(e){return j(2,e,"[cli] No resources found.")}else i=q(t),i&&!r&&delete i.files;for(const e in i)o.includes(e)?n||(n=!0):delete i[e];return n?(i.files&&(i.files=i.files.map((e=>e.trim())),(!i.files||i.files.length<=0)&&delete i.files),i):U(3,"[cli] No resources found.")};function q(e,t){try{const r=JSON.parse("string"!=typeof e?JSON.stringify(e):e);return"string"!=typeof r&&t?JSON.stringify(r):r}catch{return!1}}const 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 K(){console.log("\nUsage of CLI arguments:".bold,"\n------",`\nFor more detailed information, visit the readme at: ${"https://github.com/highcharts/node-export-server#readme".bold.yellow}.`);const e=t=>{for(const[r,o]of Object.entries(t))if(Object.prototype.hasOwnProperty.call(o,"value")){let e=` --${o.cliName||r} ${("<"+o.type+">").green} `;if(e.length<48)for(let t=e.length;t<48;t++)e+=".";console.log(e,o.description,`[Default: ${o.value.toString().bold}]`.blue)}else e(o)};Object.keys(T).forEach((t=>{["puppeteer","highcharts"].includes(t)||(console.log(`\n${t.toUpperCase()}`.red),e(T[t]))})),console.log("\n")}const z=e=>!["false","undefined","null","NaN","0",""].includes(e)&&!!e,X=(t,r)=>{if(t&&"string"==typeof t)return(t=t.trim()).endsWith(".js")?!!r&&X(e.readFileSync(t,"utf8")):t.startsWith("function()")||t.startsWith("function ()")||t.startsWith("()=>")||t.startsWith("() =>")?`(${t})()`:t.replace(/;$/,"")},J=()=>{const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6};let Y={};const Z=()=>Y,Q=(e,t,r=[])=>{const o=V(e);for(const[e,n]of Object.entries(t))o[e]="object"!=typeof(i=n)||Array.isArray(i)||null===i||r.includes(e)||void 0===o[e]?void 0!==n?n:o[e]:Q(o[e],n,r);var i;return o};function ee(e,t={},r=""){Object.keys(e).forEach((o=>{const i=e[o],n=t&&t[o];void 0===i.value?ee(i,n,`${r}.${o}`):(void 0!==n&&(i.value=n),i.envLink in A&&void 0!==A[i.envLink]&&(i.value=A[i.envLink]))}))}function te(e){let t={};for(const[r,o]of Object.entries(e))t[r]=Object.prototype.hasOwnProperty.call(o,"value")?o.value:te(o);return t}function re(e,t,r){for(;t.length>1;){const o=t.shift();return Object.prototype.hasOwnProperty.call(e,o)||(e[o]={}),e[o]=re(Object.assign({},e[o]),t,r),e}return e[t[0]]=r,e}async function oe(e,t={}){return new Promise(((r,o)=>{const i=(e=>e.startsWith("https")?c:a)(e);i.get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||o("Nothing was fetched from the URL."),e.text=t,r(e)}))})).on("error",(e=>{o(e)}))}))}class ie extends Error{constructor(e){super(),this.message=e,this.stackMessage=e}setError(e){return this.error=e,e.name&&(this.name=e.name),e.statusCode&&(this.statusCode=e.statusCode),e.stack&&(this.stackMessage=e.message,this.stack=e.stack),this}}const ne={cdnURL:"https://code.highcharts.com/",activeManifest:{},sources:"",hcVersion:""},se=e=>e.sources.substring(0,e.sources.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim(),ae=async(e,t,r,o=!1)=>{e.endsWith(".js")&&(e=e.substring(0,e.length-3)),U(4,`[cache] Fetching script - ${e}.js`);const i=await oe(`${e}.js`,t);if(200===i.statusCode&&"string"==typeof i.text){if(r){r[e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")]=1}return i.text}if(o)throw new ie(`Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${i.statusCode}).`).setError(i);return U(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`),""},ce=async(t,o,i)=>{const n=t.version,s="latest"!==n&&n?`${n}/`:"",a=t.cdnURL||ne.cdnURL;U(3,`[cache] Updating cache version to Highcharts: ${s||"latest"}.`);const c={};try{return ne.sources=await(async(e,t,o,i,n)=>{let s;const a=i.host,c=i.port;if(a&&c)try{s=new r.HttpsProxyAgent({host:a,port:c})}catch(e){throw new ie("[cache] Could not create a Proxy Agent.").setError(e)}const l=s?{agent:s,timeout:A.SERVER_PROXY_TIMEOUT}:{},p=[...e.map((e=>ae(`${e}`,l,n,!0))),...t.map((e=>ae(`${e}`,l,n))),...o.map((e=>ae(`${e}`,l)))];return(await Promise.all(p)).join(";\n")})([...t.coreScripts.map((e=>`${a}${s}${e}`))],[...t.moduleScripts.map((e=>"map"===e?`${a}maps/${s}modules/${e}`:`${a}${s}modules/${e}`)),...t.indicatorScripts.map((e=>`${a}stock/${s}indicators/${e}`))],t.customScripts,o,c),ne.hcVersion=se(ne),e.writeFileSync(i,ne.sources),c}catch(e){throw new ie("[cache] Unable to update the local Highcharts cache.").setError(e)}},le=async r=>{const{highcharts:o,server:i}=r,n=t.join(G,o.cachePath);let s;const a=t.join(n,"manifest.json"),c=t.join(n,"sources.js");if(!e.existsSync(n)&&e.mkdirSync(n),!e.existsSync(a)||o.forceFetch)U(3,"[cache] Fetching and caching Highcharts dependencies."),s=await ce(o,i.proxy,c);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:l,indicatorScripts:p}=o,u=n.length+l.length+p.length;r.version!==o.version?(U(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),t=!0):Object.keys(r.modules||{}).length!==u?(U(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),t=!0):t=(l||[]).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 ce(o,i.proxy,c):(U(3,"[cache] Dependency cache is up to date, proceeding."),ne.sources=e.readFileSync(c,"utf8"),s=r.modules,ne.hcVersion=se(ne))}await(async(r,o)=>{const i={version:r.version,modules:o||{}};ne.activeManifest=i,U(3,"[cache] Writing a new manifest.");try{e.writeFileSync(t.join(G,r.cachePath,"manifest.json"),JSON.stringify(i),"utf8")}catch(e){throw new ie("[cache] Error writing the cache manifest.").setError(e)}})(o,s)},pe=()=>t.join(G,Z().highcharts.cachePath),ue=()=>ne.hcVersion;function he(){Highcharts.animObject=function(){return{duration:0}}}async function de(e,t,r){window._displayErrors=r;const{getOptions:o,merge:i,setOptions:n,wrap:s}=Highcharts;Highcharts.setOptionsObj=i(!1,{},o()),t.customLogic.customCode&&new Function(t.customLogic.customCode)();const a={animation:!1};t.export.strInj&&(a.height=e.chart.height,a.width=e.chart.width),window.isRenderComplete=!1,s(Highcharts.Chart.prototype,"init",(function(e,t,r){((t=i(t,{exporting:{enabled:!1},plotOptions:{series:{label:{enabled:!1}}},tooltip:{}})).series||[]).forEach((function(e){e.animation=!1})),window.onHighchartsRender||(window.onHighchartsRender=Highcharts.addEvent(this,"render",(()=>{window.isRenderComplete=!0}))),e.apply(this,[t,r])})),s(Highcharts.Series.prototype,"init",(function(e,t,r){e.apply(this,[t,r])}));const c=t.export.strInj?new Function(`return ${t.export.strInj}`)():e,l=i(!1,JSON.parse(t.export.themeOptions),c,{chart:a}),p=t.customLogic.callback?new Function(`return ${t.customLogic.callback}`)():void 0,u=JSON.parse(t.export.globalOptions);u&&n(u),Highcharts[t.export.constr||"chart"]("container",l,p);const h=o();for(const e in h)"function"!=typeof h[e]&&delete h[e];n(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const me=e.readFileSync(G+"/templates/template.html","utf8");let ge;async function fe(){if(!ge)return!1;const e=await ge.newPage();return await e.setCacheEnabled(!1),await ye(e),function(e){const{debug:t}=Z();t.enable&&t.listenToConsole&&e.on("console",(e=>{console.log(`[debug] ${e.text()}`)}));e.on("pageerror",(async t=>{await e.$eval("#container",((e,t)=>{window._displayErrors&&(e.innerHTML=t)}),`

Chart input data error:

${t.toString()}`)}))}(e),e}async function ve(e,t){for(const e of t)await e.dispose();await e.evaluate((()=>{if("undefined"!=typeof Highcharts){const e=Highcharts.charts;if(Array.isArray(e)&&e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()}const[...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...r]=document.getElementsByTagName("link");for(const o of[...e,...t,...r])o.remove()}))}async function ye(e){await e.setContent(me,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:`${pe()}/sources.js`}),await e.evaluate(he)}const be=async(e,t,r,o)=>e.evaluate(de,t,r,o);var we=async(r,o,i)=>{let n=[];try{U(4,"[export] Determining export path.");const s=i.export,a=s?.options?.chart?.displayErrors&&ne.activeManifest.modules.debugger;let c;if(o.indexOf&&(o.indexOf("=0||o.indexOf("=0)){if(U(4,"[export] Treating as SVG."),"svg"===s.type)return o;c=!0,await r.setContent((e=>`\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`)(o),{waitUntil:"domcontentloaded"})}else U(4,"[export] Treating as config."),s.strInj?await be(r,{chart:{height:s.height,width:s.width}},i,a):(o.chart.height=s.height,o.chart.width=s.width,await be(r,o,i,a));n=await async function(r,o){const i=[],n=o.customLogic.resources;if(n){const s=[];if(n.js&&s.push({content:n.js}),n.files)for(const t of n.files){const r=!t.startsWith("http");s.push(r?{content:e.readFileSync(t,"utf8")}:{url:t})}for(const e of s)try{i.push(await r.addScriptTag(e))}catch(e){j(2,e,"[export] The JS resource cannot be loaded.")}s.length=0;const a=[];if(n.css){let e=n.css.match(/@import\s*([^;]*);/g);if(e)for(let r of e)r&&(r=r.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),r.startsWith("http")?a.push({url:r}):o.customLogic.allowFileResources&&a.push({path:t.join(G,r)}));a.push({content:n.css.replace(/@import\s*([^;]*);/g,"")||" "});for(const e of a)try{i.push(await r.addStyleTag(e))}catch(e){j(2,e,"[export] The CSS resource cannot be loaded.")}a.length=0}}return i}(r,i);const l=c?await r.evaluate((e=>{const t=document.querySelector("#chart-container svg:first-of-type"),r=t.height.baseVal.value*e,o=t.width.baseVal.value*e;return document.body.style.zoom=e,document.body.style.margin="0px",{chartHeight:r,chartWidth:o}}),parseFloat(s.scale)):await r.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return document.body.style.zoom=1,{chartHeight:e,chartWidth:t}})),p=Math.ceil(l.chartHeight||s.height),u=Math.ceil(l.chartWidth||s.width),{x:h,y:d}=await(e=>e.$eval("#chart-container",(e=>{const{x:t,y:r,width:o,height:i}=e.getBoundingClientRect();return{x:t,y:r,width:o,height:Math.trunc(i>1?i:500)}})))(r);let m;if(await r.setViewport({height:p,width:u,deviceScaleFactor:c?1:parseFloat(s.scale)}),"svg"===s.type)m=await(e=>e.$eval("#container svg:first-of-type",(e=>e.outerHTML)))(r);else if(["png","jpeg"].includes(s.type))m=await((e,t,r,o,i)=>Promise.race([e.screenshot({type:t,encoding:r,clip:o,captureBeyondViewport:!0,fullPage:!1,optimizeForSpeed:!0,..."png"!==t?{quality:80}:{},omitBackground:"png"==t}),new Promise(((e,t)=>setTimeout((()=>t(new ie("Rasterization timeout"))),i||1500)))]))(r,s.type,"base64",{width:u,height:p,x:h,y:d},s.rasterizationTimeout);else{if("pdf"!==s.type)throw new ie(`[export] Unsupported output format ${s.type}.`);m=await(async(e,t,r,o,i)=>(await e.emulateMediaType("screen"),Promise.race([e.pdf({height:t+1,width:r,encoding:o}),new Promise(((e,t)=>setTimeout((()=>t(new ie("Rasterization timeout"))),i||1500)))])))(r,p,u,"base64",s.rasterizationTimeout)}return await ve(r,n),m}catch(e){return await ve(r,n),e}};let Ee=!1;const Te={performedExports:0,exportAttempts:0,exportFromSvgAttempts:0,timeSpent:0,droppedExports:0,spentAverage:0};let Se={};const _e={create:async()=>{let e=!1;const t=p.v4(),r=(new Date).getTime();try{if(e=await fe(),!e||e.isClosed())throw new ie("The page is invalid or closed.");U(3,`[pool] Successfully created a worker ${t} - took ${(new Date).getTime()-r} ms.`)}catch(e){throw new ie("Error encountered when creating a new page.").setError(e)}return{id:t,page:e,workCount:Math.round(Math.random()*(Se.workLimit/2))}},validate:async e=>!(Se.workLimit&&++e.workCount>Se.workLimit)||(U(3,`[pool] Worker failed validation: exceeded work limit (limit is ${Se.workLimit}).`),!1),destroy:async e=>{U(3,`[pool] Destroying pool entry ${e.id}.`),e.page&&await e.page.close()}},Re=async e=>{if(Se=e&&e.pool?{...e.pool}:{},await async function(e){const{debug:t,other:r}=Z(),{enable:o,...i}=t,n={headless:!r.browserShellMode||"shell",userDataDir:"./tmp/",args:e,handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...o&&i};if(!ge){let e=0;const t=async()=>{try{U(3,`[browser] Attempting to get a browser instance (try ${++e}).`),ge=await u.launch(n)}catch(r){if(j(1,r,"[browser] Failed to launch a browser instance."),!(e<25))throw r;U(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await t()}};try{await t(),"shell"===n.headless&&U(3,"[browser] Launched browser in shell mode."),o&&U(3,"[browser] Launched browser in debug mode.")}catch(e){throw new ie("[browser] Maximum retries to open a browser instance reached.").setError(e)}if(!ge)throw new ie("[browser] Cannot find a browser to open.")}return ge}(e.puppeteerArgs),U(3,`[pool] Initializing pool with workers: min ${Se.minWorkers}, max ${Se.maxWorkers}.`),Ee)return U(4,"[pool] Already initialized, please kill it before creating a new one.");parseInt(Se.minWorkers)>parseInt(Se.maxWorkers)&&(Se.minWorkers=Se.maxWorkers);try{Ee=new l.Pool({..._e,min:parseInt(Se.minWorkers),max:parseInt(Se.maxWorkers),acquireTimeoutMillis:Se.acquireTimeout,createTimeoutMillis:Se.createTimeout,destroyTimeoutMillis:Se.destroyTimeout,idleTimeoutMillis:Se.idleTimeout,createRetryIntervalMillis:Se.createRetryInterval,reapIntervalMillis:Se.reaperInterval,propagateCreateError:!1}),Ee.on("release",(async e=>{await async function(e,t=!1){try{e.isClosed()||(t?(await e.goto("about:blank",{waitUntil:"domcontentloaded"}),await ye(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}.`)})),Ee.on("destroySuccess",((e,t)=>{U(4,`[pool] Destroyed a worker with ID ${t.id}.`)}));const e=[];for(let t=0;t{Ee.release(e)})),U(3,"[pool] The pool is ready"+(e.length?` with ${e.length} initial resources waiting.`:"."))}catch(e){throw new ie("[pool] Could not create the pool of workers.").setError(e)}};async function ke(){if(U(3,"[pool] Killing pool with all workers and closing browser."),Ee){for(const e of Ee.used)Ee.release(e.resource);Ee.destroyed||(await Ee.destroy(),U(4,"[browser] Destroyed the pool of resources."))}await async function(){ge?.connected&&await ge.close(),U(4,"[browser] Closed the browser.")}()}const xe=async(e,t)=>{let r;try{if(U(4,"[pool] Work received, starting to process."),++Te.exportAttempts,Se.benchmarking&&function(){const{min:e,max:t,all:r,available:o,used:i,pending:n}=Oe();U(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),U(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),U(5,`[pool] The number of all created resources: ${r}.`),U(5,`[pool] The number of available resources: ${o}.`),U(5,`[pool] The number of acquired resources: ${i}.`),U(5,`[pool] The number of resources waiting to be acquired: ${n}.`)}(),!Ee)throw new ie("Work received, but pool has not been started.");const o=J();try{U(4,"[pool] Acquiring a worker handle."),r=await Ee.acquire().promise,t.server.benchmarking&&U(5,t.payload?.requestId?`[benchmark] Request: ${t.payload?.requestId} -`:"[benchmark]",`Acquired a worker handle: ${o()}ms.`)}catch(e){throw new ie((t.payload?.requestId?`Request: ${t.payload?.requestId} - `:"")+`Error encountered when acquiring an available entry: ${o()}ms.`).setError(e)}if(U(4,"[pool] Acquired a worker handle."),!r.page)throw new ie("Resolved worker page is invalid: the pool setup is wonky.");let i=(new Date).getTime();U(4,`[pool] Starting work on pool entry with ID ${r.id}.`);const n=J(),s=await we(r.page,e,t);if(s instanceof Error)throw"Rasterization timeout"===s.message&&(r.page.close(),r.page=await fe()),new ie((t.payload?.requestId?`Request: ${t.payload?.requestId} - `:"")+`Error encountered during export: ${n()}ms.`).setError(s);t.server.benchmarking&&U(5,t.payload?.requestId?`[benchmark] Request: ${t.payload?.requestId} -`:"[benchmark]",`Exported a chart sucessfully: ${n()}ms.`),Ee.release(r);const a=(new Date).getTime()-i;return Te.timeSpent+=a,Te.spentAverage=Te.timeSpent/++Te.performedExports,U(4,`[pool] Work completed in ${a} ms.`),{result:s,options:t}}catch(e){throw++Te.droppedExports,r&&Ee.release(r),new ie(`[pool] In pool.postWork: ${e.message}`).setError(e)}},Oe=()=>({min:Ee.min,max:Ee.max,all:Ee.numFree()+Ee.numUsed(),available:Ee.numFree(),used:Ee.numUsed(),pending:Ee.numPendingAcquires()});function Le(){return Te}let Ie=!1;const Ce=async(t,r)=>{U(4,"[chart] Starting the exporting process.");const o=((e,t={})=>{let r={};return e.svg?(r=V(t),r.export.type=e.type||e.export.type,r.export.scale=e.scale||e.export.scale,r.export.outfile=e.outfile||e.export.outfile,r.payload={svg:e.svg}):r=Q(t,e,_),r.export.outfile=r.export?.outfile||`chart.${r.export?.type||"png"}`,r})(t,Z()),i=o.export;if(o.payload?.svg&&""!==o.payload.svg)try{U(4,"[chart] Attempting to export from a SVG input.");const e=$e(function(e){const t=new h.JSDOM("").window;return d(t).sanitize(e,{ADD_TAGS:["foreignObject"]})}(o.payload.svg),o,r);return++Te.exportFromSvgAttempts,e}catch(e){return r(new ie("[chart] Error loading SVG input.").setError(e))}if(i.infile&&i.infile.length)try{return U(4,"[chart] Attempting to export from an input file."),o.export.instr=e.readFileSync(i.infile,"utf8"),$e(o.export.instr.trim(),o,r)}catch(e){return r(new ie("[chart] Error loading input file.").setError(e))}if(i.instr&&""!==i.instr||i.options&&""!==i.options)try{return U(4,"[chart] Attempting to export from a raw input."),z(o.customLogic?.allowCodeExecution)?Pe(o,r):"string"==typeof i.instr?$e(i.instr.trim(),o,r):Ae(o,i.instr||i.options,r)}catch(e){return r(new ie("[chart] Error loading raw input.").setError(e))}return r(new ie("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'."))},Ne=e=>{const{chart:t,exporting:r}=e.export?.options||q(e.export?.instr),o=q(e.export?.globalOptions);let i=e.export?.scale||r?.scale||o?.exporting?.scale||e.export?.defaultScale||1;i=Math.max(.1,Math.min(i,5)),i=((e,t=1)=>{const r=Math.pow(10,t||0);return Math.round(+e*r)/r})(i,2);const n={height:e.export?.height||r?.sourceHeight||t?.height||o?.exporting?.sourceHeight||o?.chart?.height||e.export?.defaultHeight||400,width:e.export?.width||r?.sourceWidth||t?.width||o?.exporting?.sourceWidth||o?.chart?.width||e.export?.defaultWidth||600,scale:i};for(let[e,t]of Object.entries(n))n[e]="string"==typeof t?+t.replace(/px|%/gi,""):t;return n},Ae=async(t,r,o,i)=>{let{export:n,customLogic:s}=t;const a="boolean"==typeof s.allowCodeExecution?s.allowCodeExecution:Ie;if(s){if(a)if("string"==typeof t.customLogic.resources)t.customLogic.resources=F(t.customLogic.resources,z(t.customLogic.allowFileResources));else if(!t.customLogic.resources)try{const r=e.readFileSync("resources.json","utf8");t.customLogic.resources=F(r,z(t.customLogic.allowFileResources))}catch(e){j(2,e,"[chart] Unable to load the default resources.json file.")}}else s=t.customLogic={};if(!a&&s){if(s.callback||s.resources||s.customCode)return o(new ie("[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server."));s.callback=!1,s.resources=!1,s.customCode=!1}if(r&&(r.chart=r.chart||{},r.exporting=r.exporting||{},r.exporting.enabled=!1),n.constr=n.constr||"chart",n.type=M(n.type,n.outfile),"svg"===n.type&&(n.width=!1),["globalOptions","themeOptions"].forEach((t=>{try{n&&n[t]&&("string"==typeof n[t]&&n[t].endsWith(".json")?n[t]=q(e.readFileSync(n[t],"utf8"),!0):n[t]=q(n[t],!0))}catch(e){n[t]={},j(2,e,`[chart] The '${t}' cannot be loaded.`)}})),s.allowCodeExecution)try{s.customCode=X(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,...Ne(t)};try{return o(!1,await xe(n.strInj||r||i,t))}catch(e){return o(e)}},Pe=(e,t)=>{try{let r,o=e.export.instr||e.export.options;return"string"!=typeof o&&(r=o=B(o,e.customLogic?.allowCodeExecution)),r=o.replaceAll(/\t|\n|\r/g,"").trim(),";"===r[r.length-1]&&(r=r.substring(0,r.length-1)),e.export.strInj=r,Ae(e,!1,t)}catch(r){return t(new ie(`[chart] Malformed input detected for ${e.export?.requestId||"?"}. Please make sure that your JSON/JavaScript options are sent using the "options" attribute, and that if you're using SVG, it is unescaped.`).setError(r))}},$e=(e,t,r)=>{const{allowCodeExecution:o}=t.customLogic;if(e.indexOf("=0||e.indexOf("=0)return U(4,"[chart] Parsing input as SVG."),Ae(t,!1,r,e);try{const o=JSON.parse(e.replaceAll(/\t|\n|\r/g," "));return Ae(t,o,r)}catch(e){return z(o)?Pe(t,r):r(new ie("[chart] Only JSON configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the --allowCodeExecution flag.").setError(e))}},He=[],Ue=e=>{He.push(e)},je=()=>{U(4,"[server] Clearing all registered intervals and timeouts.");for(const e of He)clearInterval(e),clearTimeout(e)},We=(e,t,r,o)=>{j(1,e),"development"!==A.OTHER_NODE_ENV&&delete e.stack,o(e)},De=(e,t,r,o)=>{const{statusCode:i,status:n,message:s,stack:a}=e,c=i||n||500;r.status(c).json({statusCode:c,message:s,stack:a})};var Ge=(e,t)=>{const r="Too many requests, you have been rate limited. Please try again later.",o={max:t.maxRequests||30,window:t.window||1,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||!1,skipToken:t.skipToken||!1};o.trustProxy&&e.enable("trust proxy");const i=v({windowMs:60*o.window*1e3,max:o.max,delayMs:o.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:r})},default:()=>{t.status(429).send(r)}})},skip:e=>!1!==o.skipKey&&!1!==o.skipToken&&e.query.key===o.skipKey&&e.query.access_token===o.skipToken&&(U(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(i),U(3,`[rate limiting] Enabled rate limiting with ${o.max} requests per ${o.window} minute for each IP, trusting proxy: ${o.trustProxy}.`)};const Me=JSON.parse(e.readFileSync(t.join(G,"lib","schemas","telemetry.json"))),Fe={numberOfRequests:0},qe=["series","xAxis","yAxis","zAxis"];function Ve(e,t){const r={};for(const[o,i]of Object.entries(e))if(void 0!==t[o])if(null!==i)if(Array.isArray(t[o]))if(qe.includes(o)){r[o]=[];for(const[e,n]of t[o].entries())r[o][e]=Ve(i,n)}else r[o]=Ve(i,t[o][0]);else r[o]=Ve(i,t[o]);else r[o]=t[o];return r}function Be(e,t){Fe[t]=Ve(Me,e),Fe.numberOfRequests++}const Ke=new Map;let ze,Xe=null;function Je(e){if(ze=Z().webSocket,!0===ze.enable){const t={rejectUnauthorized:ze.rejectUnauthorized,headers:{auth:y.sign({success:"success"},ze.secret,{algorithm:"HS256"}),"X-Server-Address":`${e.protocol}://${["::","0.0.0.0"].includes(e.address)?"localhost":e.address}:${e.port}`}},r={id:p.v4(),reconnect:ze.reconnect,reconnectTry:0,reconnectInterval:null,pingTimeout:null};Ye(ze.url,t,r),function(e){Xe=setInterval((()=>{try{const t=(e?Ke.get(e):Ke.values()).next().value;t&&t.readyState===b.OPEN&&Object.keys(Fe).length>1&&Fe.numberOfRequests>0&&t.send(JSON.stringify(Fe))}catch(e){j(1,"[websocket] Could not send data through WebSocket.")}var e}),e.messageInterval),Ue(Xe)}(ze)}}function Ye(e,t,r){let o=new b(e,t);o.on("open",(()=>{clearInterval(r.reconnectInterval),Ke.set(r.id,o),U(3,`[websocket] WebSocket: ${r.id} - Connected to server: ${e}.`)})),o.on("close",(i=>{U(3,"[websocket]",`WebSocket: ${r.id} - Disconnected from server: ${e} with code: ${i}.`),clearTimeout(r.pingTimeout),Ke.delete(r.id),o=null,r.reconnect&&!r.reconnectInterval&&Ze(e,t,r)})),o.on("error",(e=>{j(1,e,`[websocket] WebSocket: ${r.id} - Error occured.`),e.message.includes("403")?(r.reconnect=!1,r.reconnectTry=ze.reconnectAttempts):r.reconnect=ze.reconnect})),o.on("message",(e=>{U(3,`[websocket] WebSocket: ${r.id} - Data received: ${e}`)})),o.on("ping",(()=>{U(3,`[websocket] WebSocket: ${r.id} - Received PING from server: ${e}.`),clearTimeout(r.pingTimeout),r.pingTimeout=setTimeout((()=>{o.terminate(),r.reconnect&&Ze(e,t,r)}),ze.pingTimeout)}))}function Ze(e,t,r){r.reconnectInterval=setInterval((()=>{r.reconnectTry!!e&&e.post("/version/change/:newVersion",(async(e,t,r)=>{try{const r=A.HIGHCHARTS_ADMIN_TOKEN;if(!r||!r.length)throw new et("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 et("Invalid or missing token: Set the token in the hc-auth header.",401);const i=e.params.newVersion;if(!i)throw new et("No new version supplied.",400);try{await(async e=>{const t=Z();t?.highcharts&&(t.highcharts.version=e),await le(t)})(i)}catch(e){throw new et(`Version change: ${e.message}`,e.statusCode).setError(e)}t.status(200).send({statusCode:200,version:ue(),message:`Successfully updated Highcharts to version: ${i}.`})}catch(e){r(e)}}));const rt={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};let ot=0;const it=[],nt=[],st=(e,t,r,o)=>{let i=!0;const{id:n,uniqueId:s,type:a,body:c}=o;return e.some((e=>{if(e){let o=e(t,r,n,s,a,c);return void 0!==o&&!0!==o&&(i=o),!0}})),i},at=async(e,t,r)=>{try{const r=J(),i=p.v4().replace(/-/g,""),n=Z(),s=e.body,a=++ot;let c=M(s.type);if(!s||"object"==typeof(o=s)&&!Array.isArray(o)&&null!==o&&0===Object.keys(o).length)throw new et("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 l=q(s.infile||s.options||s.data);if(!l&&!s.svg)throw U(2,`The request with ID ${i} from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Payload received: ${JSON.stringify(s)}.`),new et("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=st(it,e,t,{id:a,uniqueId:i,type:c,body:s}),!0!==u)return t.send(u);let h=!1;e.socket.on("close",(()=>{h=!0})),U(4,`[export] Got an incoming HTTP request with ID ${i}.`),s.constr="string"==typeof s.constr&&s.constr||"chart";const d={export:{instr:l,type:c,constr:s.constr[0].toLowerCase()+s.constr.substr(1),height:s.height,width:s.width,scale:s.scale||n.export.scale,globalOptions:q(s.globalOptions,!0),themeOptions:q(s.themeOptions,!0)},customLogic:{allowCodeExecution:Ie,allowFileResources:!1,resources:q(s.resources,!0),callback:s.callback,customCode:s.customCode}};l&&(d.export.instr=B(l,d.customLogic.allowCodeExecution));const m=Q(n,d);if(m.export.options=l,m.payload={svg:s.svg||!1,b64:s.b64||!1,noDownload:s.noDownload||!1,requestId:i},s.svg&&(e=>[/xlink:href="(?:http:\/\/|https:\/\/)?localhost\b/,/xlink:href="(?:http:\/\/|https:\/\/)?10\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?127\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?192\.168\.\d{1,3}\.\d{1,3}\b/].some((t=>t.test(e))))(m.payload.svg))throw new et("SVG potentially contain at least one forbidden URL in xlink:href element. Please review the SVG content and ensure that all referenced URLs comply with security policies.",400);await Ce(m,((o,l)=>{if(e.socket.removeAllListeners("close"),n.server.benchmarking&&U(5,`[benchmark] Request: ${i} - After the whole exporting process: ${r()}ms.`),h)return U(3,"[export] The client closed the connection before the chart finished processing.");if(o)throw o;if(!l||!l.result)throw new et(`Unexpected return from chart generation. Please check your request data. For the request with ID ${i}, the result is ${l.result}.`,400);return c=l.options.export.type,st(nt,e,t,{id:a,body:l.result}),Be(m.export.options,m.payload.requestId),l.result?s.b64?"pdf"===c||"svg"==c?t.send(Buffer.from(l.result,"utf8").toString("base64")):t.send(l.result):(t.header("Content-Type",rt[c]||"image/png"),s.noDownload||t.attachment(`${e.params.filename||e.body.filename||"chart"}.${c||"png"}`),"svg"===c?t.send(l.result):t.send(Buffer.from(l.result,"base64"))):void 0}))}catch(e){r(e)}var o};const ct=JSON.parse(e.readFileSync(t.join(G,"package.json"))),lt=new Date,pt=[];function ut(e){if(!e)return!1;Ue(setInterval((()=>{const e=Le(),t=0===e.exportAttempts?1:e.performedExports/e.exportAttempts*100;pt.push(t),pt.length>30&&pt.shift()}),6e4)),e.get("/health",((e,t)=>{const r=Le(),o=pt.length,i=pt.reduce(((e,t)=>e+t),0)/pt.length;U(4,"[health.js] GET /health [200] - returning server health."),t.send({status:"OK",bootTime:lt,uptime:Math.floor(((new Date).getTime()-lt.getTime())/1e3/60)+" minutes",version:ct.version,highchartsVersion:ue(),averageProcessingTime:r.spentAverage,performedExports:r.performedExports,failedExports:r.droppedExports,exportAttempts:r.exportAttempts,sucessRatio:r.performedExports/r.exportAttempts*100,pool:Oe(),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 ht=new Map,dt=g();dt.disable("x-powered-by"),dt.use(m());const mt=f.memoryStorage(),gt=f({storage:mt,limits:{fieldSize:52428800}});dt.use(g.json({limit:52428800})),dt.use(g.urlencoded({extended:!0,limit:52428800})),dt.use(gt.none());const ft=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}`)}))}))},vt=async r=>{try{if(!r.enable)return!1;if(!r.ssl.force){const e=a.createServer(dt);ft(e),e.listen(r.port,r.host,(()=>{ht.set(r.port,e),U(3,`[server] Started HTTP server on ${r.host}:${r.port}.`),1===ht.size&&Je({...e.address(),protocol:"http"})}))}if(r.ssl.enable){let o,i;try{o=await e.promises.readFile(t.posix.join(r.ssl.certPath,"server.key"),"utf8"),i=await e.promises.readFile(t.posix.join(r.ssl.certPath,"server.crt"),"utf8")}catch(e){U(2,`[server] Unable to load key/certificate from the '${r.ssl.certPath}' path. Could not run secured layer server.`)}if(o&&i){const e=c.createServer({key:o,cert:i},dt);ft(e),e.listen(r.ssl.port,r.host,(()=>{ht.set(r.ssl.port,e),U(3,`[server] Started HTTPS server on ${r.host}:${r.ssl.port}.`),1===ht.size&&Je({...e.address(),protocol:"https"})}))}}r.rateLimiting&&r.rateLimiting.enable&&![0,NaN].includes(r.rateLimiting.maxRequests)&&Ge(dt,r.rateLimiting),dt.use(g.static(t.posix.join(G,"public"))),ut(dt),(e=>{e.post("/",at),e.post("/:filename",at)})(dt),(e=>{!!e&&e.get("/",((e,r)=>{r.sendFile(t.join(G,"public","index.html"))}))})(dt),tt(dt),(e=>{e.use(We),e.use(De)})(dt)}catch(e){throw new ie("[server] Could not configure and start the server.").setError(e)}},yt=()=>{U(4,"[server] Closing all servers.");for(const[e,t]of ht)t.close((()=>{ht.delete(e),U(4,`[server] Closed server on port: ${e}.`)}))};var bt={startServer:vt,closeServers:yt,getServers:()=>ht,enableRateLimiting:e=>Ge(dt,e),getExpress:()=>g,getApp:()=>dt,use:(e,...t)=>{dt.use(e,...t)},get:(e,...t)=>{dt.get(e,...t)},post:(e,...t)=>{dt.post(e,...t)}};const wt=async e=>{await Promise.allSettled([je(),Qe(),yt(),ke()]),process.exit(e)};var Et={server:bt,startServer:vt,initExport:async e=>{var t;return t=e.customLogic&&e.customLogic.allowCodeExecution,Ie=z(t),(e=>{W(e&&parseInt(e.level)),e&&e.dest&&D(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 wt(0)})),process.on("SIGTERM",(async(e,t)=>{U(4,`The ${e} event with code: ${t}.`),await wt(0)})),process.on("SIGHUP",(async(e,t)=>{U(4,`The ${e} event with code: ${t}.`),await wt(0)})),process.on("uncaughtException",(async(e,t)=>{j(1,e,`The ${t} error.`),await wt(1)}))),await le(e),await Re({pool:e.pool||{minWorkers:1,maxWorkers:1},puppeteerArgs:e.puppeteer.args||[]}),e},singleExport:async t=>{t.export.instr=t.export.instr||t.export.options,await Ce(t,(async(t,r)=>{if(t)throw t;const{outfile:o,type:i}=r.options.export;e.writeFileSync(o||`chart.${i}`,"svg"!==i?Buffer.from(r.result,"base64"):r.result),await ke()}))},batchExport:async t=>{const r=[];for(let o of t.export.batch.split(";"))o=o.split("="),2===o.length&&r.push(Ce({...t,export:{...t.export,infile:o[0],outfile:o[1]}},((t,r)=>{if(t)throw t;e.writeFileSync(r.options.export.outfile,"svg"!==r.options.export.type?Buffer.from(r.result,"base64"):r.result)})));try{await Promise.all(r),await ke()}catch(e){throw new ie("[chart] Error encountered during batch export.").setError(e)}},startExport:Ce,initPool:Re,killPool:ke,setOptions:(t,r)=>(r?.length&&(Y=function(t){const r=t.findIndex((e=>"loadConfig"===e.replace(/-/g,"")));if(r>-1&&t[r+1]){const o=t[r+1];try{if(o&&o.endsWith(".json"))return JSON.parse(e.readFileSync(o))}catch(e){j(2,e,`[config] Unable to load the configuration from the ${o} file.`)}}return{}}(r)),ee(T,Y),Y=te(T),t&&(Y=Q(Y,t,_)),r?.length&&(Y=function(e,t,r){let o=!1;for(let i=0;i(s.length-1===r&&(a=e[t].type),e[t])),r),s.reduce(((e,r,c)=>(s.length-1===c&&void 0!==e[r]&&(t[++i]?"boolean"===a?e[r]=z(t[i]):"number"===a?e[r]=+t[i]:a.indexOf("]")>=0?e[r]=t[i].split(","):e[r]=t[i]:(U(2,`[config] Missing value for the '${n}' argument. Using the default value.`),o=!0)),e[r])),e)}o&&K();return e}(Y,r,T)),Y),shutdownCleanUp:wt,log:U,logWithStack:j,setLogLevel:W,enableFileLogging:D,mapToNewConfig:e=>{const t={};for(const[r,o]of Object.entries(e)){const e=R[r]?R[r].split("."):[];e.reduce(((t,r,i)=>t[r]=e.length-1===i?o:t[r]||{}),t)}return t},manualConfig:async t=>{let r={};e.existsSync(t)&&(r=JSON.parse(e.readFileSync(t,"utf8")));const i=Object.keys(S).map((e=>({title:`${e} options`,value:e})));return o({type:"multiselect",name:"category",message:"Which category do you want to configure?",hint:"Space: Select specific, A: Select all, Enter: Confirm.",instructions:"",choices:i},{onSubmit:async(i,n)=>{let s=0,a=[];for(const e of n)S[e]=S[e].map((t=>({...t,section:e}))),a=[...a,...S[e]];return await o(a,{onSubmit:async(o,i)=>{if("moduleScripts"===o.name?(i=i.length?i.map((e=>o.choices[e])):o.choices,r[o.section][o.name]=i):r[o.section]=re(Object.assign({},r[o.section]||{}),o.name.split("."),o.choices?o.choices[i]:i),++s===a.length){try{await e.promises.writeFile(t,JSON.stringify(r,null,2),"utf8")}catch(e){j(1,e,`[config] An error occurred while creating the ${t} file.`)}return!0}}}),!0}})},printLogo:r=>{const o=JSON.parse(e.readFileSync(t.join(G,"package.json"))).version;r?console.log(`Starting Highcharts Export Server v${o}...`):console.log(e.readFileSync(G+"/msg/startup.msg").toString().bold.yellow,`v${o}\n`.bold)},printUsage:K};module.exports=Et; -//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguY2pzIiwic291cmNlcyI6WyIuLi9saWIvc2NoZW1hcy9jb25maWcuanMiLCIuLi9saWIvZW52cy5qcyIsIi4uL2xpYi9sb2dnZXIuanMiLCIuLi9saWIvdXRpbHMuanMiLCIuLi9saWIvY29uZmlnLmpzIiwiLi4vbGliL2ZldGNoLmpzIiwiLi4vbGliL2Vycm9ycy9FeHBvcnRFcnJvci5qcyIsIi4uL2xpYi9jYWNoZS5qcyIsIi4uL2xpYi9oaWdoY2hhcnRzLmpzIiwiLi4vbGliL2Jyb3dzZXIuanMiLCIuLi9saWIvZXhwb3J0LmpzIiwiLi4vdGVtcGxhdGVzL3N2Z19leHBvcnQvc3ZnX2V4cG9ydC5qcyIsIi4uL2xpYi9wb29sLmpzIiwiLi4vbGliL2NoYXJ0LmpzIiwiLi4vbGliL3Nhbml0aXplLmpzIiwiLi4vbGliL3RpbWVycy5qcyIsIi4uL2xpYi9zZXJ2ZXIvZXJyb3IuanMiLCIuLi9saWIvc2VydmVyL3JhdGVfbGltaXQuanMiLCIuLi9saWIvdGVsZW1ldHJ5LmpzIiwiLi4vbGliL3NlcnZlci93ZWJfc29ja2V0LmpzIiwiLi4vbGliL2Vycm9ycy9IdHRwRXJyb3IuanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy9jaGFuZ2VfaGNfdmVyc2lvbi5qcyIsIi4uL2xpYi9zZXJ2ZXIvcm91dGVzL2V4cG9ydC5qcyIsIi4uL2xpYi9zZXJ2ZXIvcm91dGVzL2hlYWx0aC5qcyIsIi4uL2xpYi9zZXJ2ZXIvc2VydmVyLmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvdWkuanMiLCIuLi9saWIvcmVzb3VyY2VfcmVsZWFzZS5qcyIsIi4uL2xpYi9pbmRleC5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8vIFBvc3NpYmxlIG5hbWVzIGZvciBIaWdoY2hhcnRzIHNjcmlwdHNcclxuZXhwb3J0IGNvbnN0IHNjcmlwdHNOYW1lcyA9IHtcclxuICBjb3JlOiBbJ2hpZ2hjaGFydHMnLCAnaGlnaGNoYXJ0cy1tb3JlJywgJ2hpZ2hjaGFydHMtM2QnXSxcclxuICBtb2R1bGVzOiBbXHJcbiAgICAnc3RvY2snLFxyXG4gICAgJ21hcCcsXHJcbiAgICAnZ2FudHQnLFxyXG4gICAgJ2V4cG9ydGluZycsXHJcbiAgICAnZXhwb3J0LWRhdGEnLFxyXG4gICAgJ3BhcmFsbGVsLWNvb3JkaW5hdGVzJyxcclxuICAgICdhY2Nlc3NpYmlsaXR5JyxcclxuICAgIC8vICdhbm5vdGF0aW9ucy1hZHZhbmNlZCcsXHJcbiAgICAnYm9vc3QtY2FudmFzJyxcclxuICAgICdib29zdCcsXHJcbiAgICAnZGF0YScsXHJcbiAgICAnZGF0YS10b29scycsXHJcbiAgICAnZHJhZ2dhYmxlLXBvaW50cycsXHJcbiAgICAnc3RhdGljLXNjYWxlJyxcclxuICAgICdicm9rZW4tYXhpcycsXHJcbiAgICAnaGVhdG1hcCcsXHJcbiAgICAndGlsZW1hcCcsXHJcbiAgICAndGlsZWR3ZWJtYXAnLFxyXG4gICAgJ3RpbWVsaW5lJyxcclxuICAgICd0cmVlbWFwJyxcclxuICAgICd0cmVlZ3JhcGgnLFxyXG4gICAgJ2l0ZW0tc2VyaWVzJyxcclxuICAgICdkcmlsbGRvd24nLFxyXG4gICAgJ2hpc3RvZ3JhbS1iZWxsY3VydmUnLFxyXG4gICAgJ2J1bGxldCcsXHJcbiAgICAnZnVubmVsJyxcclxuICAgICdmdW5uZWwzZCcsXHJcbiAgICAnZ2VvaGVhdG1hcCcsXHJcbiAgICAncHlyYW1pZDNkJyxcclxuICAgICduZXR3b3JrZ3JhcGgnLFxyXG4gICAgJ292ZXJsYXBwaW5nLWRhdGFsYWJlbHMnLFxyXG4gICAgJ3BhcmV0bycsXHJcbiAgICAncGF0dGVybi1maWxsJyxcclxuICAgICdwaWN0b3JpYWwnLFxyXG4gICAgJ3ByaWNlLWluZGljYXRvcicsXHJcbiAgICAnc2Fua2V5JyxcclxuICAgICdhcmMtZGlhZ3JhbScsXHJcbiAgICAnZGVwZW5kZW5jeS13aGVlbCcsXHJcbiAgICAnc2VyaWVzLWxhYmVsJyxcclxuICAgICdzb2xpZC1nYXVnZScsXHJcbiAgICAnc29uaWZpY2F0aW9uJyxcclxuICAgIC8vICdzdG9jay10b29scycsXHJcbiAgICAnc3RyZWFtZ3JhcGgnLFxyXG4gICAgJ3N1bmJ1cnN0JyxcclxuICAgICd2YXJpYWJsZS1waWUnLFxyXG4gICAgJ3Zhcml3aWRlJyxcclxuICAgICd2ZWN0b3InLFxyXG4gICAgJ3Zlbm4nLFxyXG4gICAgJ3dpbmRiYXJiJyxcclxuICAgICd3b3JkY2xvdWQnLFxyXG4gICAgJ3hyYW5nZScsXHJcbiAgICAnbm8tZGF0YS10by1kaXNwbGF5JyxcclxuICAgICdkcmFnLXBhbmVzJyxcclxuICAgICdkZWJ1Z2dlcicsXHJcbiAgICAnZHVtYmJlbGwnLFxyXG4gICAgJ2xvbGxpcG9wJyxcclxuICAgICdjeWxpbmRlcicsXHJcbiAgICAnb3JnYW5pemF0aW9uJyxcclxuICAgICdkb3RwbG90JyxcclxuICAgICdtYXJrZXItY2x1c3RlcnMnLFxyXG4gICAgJ2hvbGxvd2NhbmRsZXN0aWNrJyxcclxuICAgICdoZWlraW5hc2hpJyxcclxuICAgICdmbG93bWFwJ1xyXG4gIF0sXHJcbiAgaW5kaWNhdG9yczogWydpbmRpY2F0b3JzLWFsbCddXHJcbn07XHJcblxyXG4vLyBUaGlzIGlzIHRoZSBjb25maWd1cmF0aW9uIG9iamVjdCB3aXRoIGFsbCBvcHRpb25zIGFuZCB0aGVpciBkZWZhdWx0IHZhbHVlcyxcclxuLy8gYWxzbyBmcm9tIHRoZSAuZW52IGZpbGUgaWYgb25lIGV4aXN0c1xyXG5leHBvcnQgY29uc3QgZGVmYXVsdENvbmZpZyA9IHtcclxuICBwdXBwZXRlZXI6IHtcclxuICAgIGFyZ3M6IHtcclxuICAgICAgdmFsdWU6IFtcclxuICAgICAgICAnLS1hbGxvdy1ydW5uaW5nLWluc2VjdXJlLWNvbnRlbnQnLFxyXG4gICAgICAgICctLWFzaC1uby1udWRnZXMnLFxyXG4gICAgICAgICctLWF1dG9wbGF5LXBvbGljeT11c2VyLWdlc3R1cmUtcmVxdWlyZWQnLFxyXG4gICAgICAgICctLWJsb2NrLW5ldy13ZWItY29udGVudHMnLFxyXG4gICAgICAgICctLWRpc2FibGUtYWNjZWxlcmF0ZWQtMmQtY2FudmFzJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWJhY2tncm91bmQtbmV0d29ya2luZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1iYWNrZ3JvdW5kLXRpbWVyLXRocm90dGxpbmcnLFxyXG4gICAgICAgICctLWRpc2FibGUtYmFja2dyb3VuZGluZy1vY2NsdWRlZC13aW5kb3dzJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWJyZWFrcGFkJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWNoZWNrZXItaW1hZ2luZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1jbGllbnQtc2lkZS1waGlzaGluZy1kZXRlY3Rpb24nLFxyXG4gICAgICAgICctLWRpc2FibGUtY29tcG9uZW50LWV4dGVuc2lvbnMtd2l0aC1iYWNrZ3JvdW5kLXBhZ2VzJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWNvbXBvbmVudC11cGRhdGUnLFxyXG4gICAgICAgICctLWRpc2FibGUtZGVmYXVsdC1hcHBzJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWRldi1zaG0tdXNhZ2UnLFxyXG4gICAgICAgICctLWRpc2FibGUtZG9tYWluLXJlbGlhYmlsaXR5JyxcclxuICAgICAgICAnLS1kaXNhYmxlLWV4dGVuc2lvbnMnLFxyXG4gICAgICAgICctLWRpc2FibGUtZmVhdHVyZXM9Q2FsY3VsYXRlTmF0aXZlV2luT2NjbHVzaW9uLEludGVyZXN0RmVlZENvbnRlbnRTdWdnZXN0aW9ucyxXZWJPVFAnLFxyXG4gICAgICAgICctLWRpc2FibGUtaGFuZy1tb25pdG9yJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWlwYy1mbG9vZGluZy1wcm90ZWN0aW9uJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWxvZ2dpbmcnLFxyXG4gICAgICAgICctLWRpc2FibGUtbm90aWZpY2F0aW9ucycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1vZmZlci1zdG9yZS11bm1hc2tlZC13YWxsZXQtY2FyZHMnLFxyXG4gICAgICAgICctLWRpc2FibGUtcG9wdXAtYmxvY2tpbmcnLFxyXG4gICAgICAgICctLWRpc2FibGUtcHJpbnQtcHJldmlldycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1wcm9tcHQtb24tcmVwb3N0JyxcclxuICAgICAgICAnLS1kaXNhYmxlLXJlbmRlcmVyLWJhY2tncm91bmRpbmcnLFxyXG4gICAgICAgICctLWRpc2FibGUtc2VhcmNoLWVuZ2luZS1jaG9pY2Utc2NyZWVuJyxcclxuICAgICAgICAnLS1kaXNhYmxlLXNlc3Npb24tY3Jhc2hlZC1idWJibGUnLFxyXG4gICAgICAgICctLWRpc2FibGUtc2V0dWlkLXNhbmRib3gnLFxyXG4gICAgICAgICctLWRpc2FibGUtc2l0ZS1pc29sYXRpb24tdHJpYWxzJyxcclxuICAgICAgICAnLS1kaXNhYmxlLXNwZWVjaC1hcGknLFxyXG4gICAgICAgICctLWRpc2FibGUtc3luYycsXHJcbiAgICAgICAgJy0tZW5hYmxlLXVuc2FmZS13ZWJncHUnLFxyXG4gICAgICAgICctLWhpZGUtY3Jhc2gtcmVzdG9yZS1idWJibGUnLFxyXG4gICAgICAgICctLWhpZGUtc2Nyb2xsYmFycycsXHJcbiAgICAgICAgJy0tbWV0cmljcy1yZWNvcmRpbmctb25seScsXHJcbiAgICAgICAgJy0tbXV0ZS1hdWRpbycsXHJcbiAgICAgICAgJy0tbm8tZGVmYXVsdC1icm93c2VyLWNoZWNrJyxcclxuICAgICAgICAnLS1uby1maXJzdC1ydW4nLFxyXG4gICAgICAgICctLW5vLXBpbmdzJyxcclxuICAgICAgICAnLS1uby1zYW5kYm94JyxcclxuICAgICAgICAnLS1uby1zdGFydHVwLXdpbmRvdycsXHJcbiAgICAgICAgJy0tbm8tenlnb3RlJyxcclxuICAgICAgICAnLS1wYXNzd29yZC1zdG9yZT1iYXNpYycsXHJcbiAgICAgICAgJy0tcHJvY2Vzcy1wZXItdGFiJyxcclxuICAgICAgICAnLS11c2UtbW9jay1rZXljaGFpbidcclxuICAgICAgXSxcclxuICAgICAgdHlwZTogJ3N0cmluZ1tdJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdBcmd1bWVudHMgYXJyYXkgdG8gc2VuZCB0byBQdXBwZXRlZXIuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgaGlnaGNoYXJ0czoge1xyXG4gICAgdmVyc2lvbjoge1xyXG4gICAgICB2YWx1ZTogJ2xhdGVzdCcsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19WRVJTSU9OJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgSGlnaGNoYXJ0cyB2ZXJzaW9uIHRvIGJlIHVzZWQuJ1xyXG4gICAgfSxcclxuICAgIGNkblVSTDoge1xyXG4gICAgICB2YWx1ZTogJ2h0dHBzOi8vY29kZS5oaWdoY2hhcnRzLmNvbS8nLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ0ROX1VSTCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIENETiBVUkwgZm9yIEhpZ2hjaGFydHMgc2NyaXB0cyB0byBiZSB1c2VkLidcclxuICAgIH0sXHJcbiAgICBjb3JlU2NyaXB0czoge1xyXG4gICAgICB2YWx1ZTogc2NyaXB0c05hbWVzLmNvcmUsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmdbXScsXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0NPUkVfU0NSSVBUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIGNvcmUgSGlnaGNoYXJ0cyBzY3JpcHRzIHRvIGZldGNoLidcclxuICAgIH0sXHJcbiAgICBtb2R1bGVTY3JpcHRzOiB7XHJcbiAgICAgIHZhbHVlOiBzY3JpcHRzTmFtZXMubW9kdWxlcyxcclxuICAgICAgdHlwZTogJ3N0cmluZ1tdJyxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfTU9EVUxFX1NDUklQVFMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBtb2R1bGVzIG9mIEhpZ2hjaGFydHMgdG8gZmV0Y2guJ1xyXG4gICAgfSxcclxuICAgIGluZGljYXRvclNjcmlwdHM6IHtcclxuICAgICAgdmFsdWU6IHNjcmlwdHNOYW1lcy5pbmRpY2F0b3JzLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19JTkRJQ0FUT1JfU0NSSVBUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIGluZGljYXRvcnMgb2YgSGlnaGNoYXJ0cyB0byBmZXRjaC4nXHJcbiAgICB9LFxyXG4gICAgY3VzdG9tU2NyaXB0czoge1xyXG4gICAgICB2YWx1ZTogW1xyXG4gICAgICAgICdodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9tb21lbnQuanMvMi4yOS40L21vbWVudC5taW4uanMnLFxyXG4gICAgICAgICdodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9tb21lbnQtdGltZXpvbmUvMC41LjM0L21vbWVudC10aW1lem9uZS13aXRoLWRhdGEubWluLmpzJ1xyXG4gICAgICBdLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0FkZGl0aW9uYWwgY3VzdG9tIHNjcmlwdHMgb3IgZGVwZW5kZW5jaWVzIHRvIGZldGNoLidcclxuICAgIH0sXHJcbiAgICBmb3JjZUZldGNoOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19GT1JDRV9GRVRDSCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZmxhZyB0byBkZXRlcm1pbmUgd2hldGhlciB0byByZWZldGNoIGFsbCBzY3JpcHRzIGFmdGVyIGVhY2ggc2VydmVyIHJlcnVuLidcclxuICAgIH0sXHJcbiAgICBjYWNoZVBhdGg6IHtcclxuICAgICAgdmFsdWU6ICcuY2FjaGUnLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ0FDSEVfUEFUSCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgcGF0aCB0byB0aGUgY2FjaGUgZGlyZWN0b3J5LiBJdCBpcyB1c2VkIHRvIHN0b3JlIHRoZSBIaWdoY2hhcnRzIHNjcmlwdHMgYW5kIGN1c3RvbSBzY3JpcHRzLidcclxuICAgIH1cclxuICB9LFxyXG4gIGV4cG9ydDoge1xyXG4gICAgaW5maWxlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgaW5wdXQgZmlsZSBzaG91bGQgaW5jbHVkZSBhIG5hbWUgYW5kIGEgdHlwZSAoanNvbiBvciBzdmcpLiBJdCBtdXN0IGJlIGNvcnJlY3RseSBmb3JtYXR0ZWQgYXMgYSBKU09OIG9yIFNWRyBmaWxlLidcclxuICAgIH0sXHJcbiAgICBpbnN0cjoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSW5wdXQsIHByb3ZpZGVkIGluIHRoZSBmb3JtIG9mIGEgc3RyaW5naWZpZWQgSlNPTiBvciBTVkcgZmlsZSwgd2lsbCBvdmVycmlkZSB0aGUgLS1pbmZpbGUgb3B0aW9uLidcclxuICAgIH0sXHJcbiAgICBvcHRpb25zOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnQW4gYWxpYXMgZm9yIHRoZSAtLWluc3RyIG9wdGlvbi4nXHJcbiAgICB9LFxyXG4gICAgb3V0ZmlsZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIG91dHB1dCBmaWxlbmFtZSBhbG9uZyB3aXRoIGEgdHlwZSAoanBlZywgcG5nLCBwZGYsIG9yIHN2ZykuIFRoaXMgd2lsbCBpZ25vcmUgdGhlIC0tdHlwZSBmbGFnLidcclxuICAgIH0sXHJcbiAgICB0eXBlOiB7XHJcbiAgICAgIHZhbHVlOiAncG5nJyxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfVFlQRScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIGZpbGUgZXhwb3J0IGZvcm1hdC4gSXQgY2FuIGJlIGpwZWcsIHBuZywgcGRmLCBvciBzdmcuJ1xyXG4gICAgfSxcclxuICAgIGNvbnN0cjoge1xyXG4gICAgICB2YWx1ZTogJ2NoYXJ0JyxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfQ09OU1RSJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBjb25zdHJ1Y3RvciB0byB1c2UuIENhbiBiZSBjaGFydCwgc3RvY2tDaGFydCwgbWFwQ2hhcnQsIG9yIGdhbnR0Q2hhcnQuJ1xyXG4gICAgfSxcclxuICAgIGRlZmF1bHRIZWlnaHQ6IHtcclxuICAgICAgdmFsdWU6IDQwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9IRUlHSFQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAndGhlIGRlZmF1bHQgaGVpZ2h0IG9mIHRoZSBleHBvcnRlZCBjaGFydC4gVXNlZCB3aGVuIG5vIHZhbHVlIGlzIHNldC4nXHJcbiAgICB9LFxyXG4gICAgZGVmYXVsdFdpZHRoOiB7XHJcbiAgICAgIHZhbHVlOiA2MDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0RFRkFVTFRfV0lEVEgnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGRlZmF1bHQgd2lkdGggb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LiBVc2VkIHdoZW4gbm8gdmFsdWUgaXMgc2V0LidcclxuICAgIH0sXHJcbiAgICBkZWZhdWx0U2NhbGU6IHtcclxuICAgICAgdmFsdWU6IDEsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0RFRkFVTFRfU0NBTEUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGRlZmF1bHQgc2NhbGUgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LiBVc2VkIHdoZW4gbm8gdmFsdWUgaXMgc2V0LidcclxuICAgIH0sXHJcbiAgICBoZWlnaHQ6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBoZWlnaHQgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LCBvdmVycmlkaW5nIHRoZSBvcHRpb24gaW4gdGhlIGNoYXJ0IHNldHRpbmdzLidcclxuICAgIH0sXHJcbiAgICB3aWR0aDoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIHdpZHRoIG9mIHRoZSBleHBvcnRlZCBjaGFydCwgb3ZlcnJpZGluZyB0aGUgb3B0aW9uIGluIHRoZSBjaGFydCBzZXR0aW5ncy4nXHJcbiAgICB9LFxyXG4gICAgc2NhbGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBzY2FsZSBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQsIG92ZXJyaWRpbmcgdGhlIG9wdGlvbiBpbiB0aGUgY2hhcnQgc2V0dGluZ3MuIFJhbmdlcyBiZXR3ZWVuIDAuMSBhbmQgNS4wLidcclxuICAgIH0sXHJcbiAgICBnbG9iYWxPcHRpb25zOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdFaXRoZXIgYSBzdHJpbmdpZmllZCBKU09OIG9yIGEgZmlsZW5hbWUgY29udGFpbmluZyBvcHRpb25zIHRvIGJlIHBhc3NlZCBpbnRvIHRoZSBIaWdoY2hhcnRzLnNldE9wdGlvbnMuJ1xyXG4gICAgfSxcclxuICAgIHRoZW1lT3B0aW9uczoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnRWl0aGVyIGEgc3RyaW5naWZpZWQgSlNPTiBvciBhIGZpbGVuYW1lIGNvbnRhaW5pbmcgdGhlbWUgb3B0aW9ucyB0byBiZSBwYXNzZWQgaW50byB0aGUgSGlnaGNoYXJ0cy5zZXRPcHRpb25zLidcclxuICAgIH0sXHJcbiAgICBiYXRjaDoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSW5pdGlhdGVzIGEgYmF0Y2ggam9iIHdpdGggYSBzdHJpbmcgY29udGFpbmluZyBpbnB1dC9vdXRwdXQgcGFpcnM6IFwiaW49b3V0O2luPW91dDsuLi5cIi4nXHJcbiAgICB9LFxyXG4gICAgcmFzdGVyaXphdGlvblRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDE1MDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX1JBU1RFUklaQVRJT05fVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24gaW4gbWlsbGlzZWNvbmRzIHRvIHdhaXQgZm9yIHJlbmRlcmluZyBhIHdlYnBhZ2UuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgY3VzdG9tTG9naWM6IHtcclxuICAgIGFsbG93Q29kZUV4ZWN1dGlvbjoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19BTExPV19DT0RFX0VYRUNVVElPTicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdDb250cm9scyB3aGV0aGVyIHRoZSBleGVjdXRpb24gb2YgYXJiaXRyYXJ5IGNvZGUgaXMgYWxsb3dlZCBkdXJpbmcgdGhlIGV4cG9ydGluZyBwcm9jZXNzLidcclxuICAgIH0sXHJcbiAgICBhbGxvd0ZpbGVSZXNvdXJjZXM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdDVVNUT01fTE9HSUNfQUxMT1dfRklMRV9SRVNPVVJDRVMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQ29udHJvbHMgdGhlIGFiaWxpdHkgdG8gaW5qZWN0IHJlc291cmNlcyBmcm9tIHRoZSBmaWxlc3lzdGVtLiBUaGlzIHNldHRpbmcgaGFzIG5vIGVmZmVjdCB3aGVuIHJ1bm5pbmcgYXMgYSBzZXJ2ZXIuJ1xyXG4gICAgfSxcclxuICAgIGN1c3RvbUNvZGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0N1c3RvbSBjb2RlIHRvIGV4ZWN1dGUgYmVmb3JlIGNoYXJ0IGluaXRpYWxpemF0aW9uLiBJdCBjYW4gYmUgYSBmdW5jdGlvbiwgY29kZSB3cmFwcGVkIHdpdGhpbiBhIGZ1bmN0aW9uLCBvciBhIGZpbGVuYW1lIHdpdGggdGhlIC5qcyBleHRlbnNpb24uJ1xyXG4gICAgfSxcclxuICAgIGNhbGxiYWNrOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdKYXZhU2NyaXB0IGNvZGUgdG8gcnVuIGR1cmluZyBjb25zdHJ1Y3Rpb24uIEl0IGNhbiBiZSBhIGZ1bmN0aW9uIG9yIGEgZmlsZW5hbWUgd2l0aCB0aGUgLmpzIGV4dGVuc2lvbi4nXHJcbiAgICB9LFxyXG4gICAgcmVzb3VyY2VzOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdBZGRpdGlvbmFsIHJlc291cmNlIGluIHRoZSBmb3JtIG9mIGEgc3RyaW5naWZpZWQgSlNPTiwgd2hpY2ggbWF5IGNvbnRhaW4gZmlsZXMsIGpzLCBhbmQgY3NzIHNlY3Rpb25zLidcclxuICAgIH0sXHJcbiAgICBsb2FkQ29uZmlnOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGxlZ2FjeU5hbWU6ICdmcm9tRmlsZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnQSBmaWxlIGNvbnRhaW5pbmcgYSBwcmUtZGVmaW5lZCBjb25maWd1cmF0aW9uIHRvIHVzZS4nXHJcbiAgICB9LFxyXG4gICAgY3JlYXRlQ29uZmlnOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdFbmFibGVzIHNldHRpbmcgb3B0aW9ucyB0aHJvdWdoIGEgcHJvbXB0IGFuZCBzYXZpbmcgdGhlbSBpbiBhIHByb3ZpZGVkIGNvbmZpZyBmaWxlLidcclxuICAgIH1cclxuICB9LFxyXG4gIHNlcnZlcjoge1xyXG4gICAgZW5hYmxlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX0VOQUJMRScsXHJcbiAgICAgIGNsaU5hbWU6ICdlbmFibGVTZXJ2ZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnV2hlbiBzZXQgdG8gdHJ1ZSwgdGhlIHNlcnZlciBzdGFydHMgb24gdGhlIGxvY2FsIElQIGFkZHJlc3MgMC4wLjAuMC4nXHJcbiAgICB9LFxyXG4gICAgaG9zdDoge1xyXG4gICAgICB2YWx1ZTogJzAuMC4wLjAnLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ1NFUlZFUl9IT1NUJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBob3N0bmFtZSBvZiB0aGUgc2VydmVyLiBBZGRpdGlvbmFsbHksIGl0IHN0YXJ0cyBhIHNlcnZlciBvbiB0aGUgcHJvdmlkZWQgaG9zdG5hbWUuJ1xyXG4gICAgfSxcclxuICAgIHBvcnQ6IHtcclxuICAgICAgdmFsdWU6IDc4MDEsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX1BPUlQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBzZXJ2ZXIgcG9ydCB3aGVuIGVuYWJsZWQuJ1xyXG4gICAgfSxcclxuICAgIGJlbmNobWFya2luZzoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZW52TGluazogJ1NFUlZFUl9CRU5DSE1BUktJTkcnLFxyXG4gICAgICBjbGlOYW1lOiAnc2VydmVyQmVuY2htYXJraW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0luZGljYXRlcyB3aGV0aGVyIHRvIGRpc3BsYXkgdGhlIGR1cmF0aW9uLCBpbiBtaWxsaXNlY29uZHMsIG9mIHNwZWNpZmljIGFjdGlvbnMgdGhhdCBvY2N1ciBvbiB0aGUgc2VydmVyIHdoaWxlIHNlcnZpbmcgYSByZXF1ZXN0LidcclxuICAgIH0sXHJcbiAgICBwcm94eToge1xyXG4gICAgICBob3N0OiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUFJPWFlfSE9TVCcsXHJcbiAgICAgICAgY2xpTmFtZTogJ3Byb3h5SG9zdCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgaG9zdCBvZiB0aGUgcHJveHkgc2VydmVyIHRvIHVzZSwgaWYgaXQgZXhpc3RzLidcclxuICAgICAgfSxcclxuICAgICAgcG9ydDoge1xyXG4gICAgICAgIHZhbHVlOiA4MDgwLFxyXG4gICAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUFJPWFlfUE9SVCcsXHJcbiAgICAgICAgY2xpTmFtZTogJ3Byb3h5UG9ydCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgcG9ydCBvZiB0aGUgcHJveHkgc2VydmVyIHRvIHVzZSwgaWYgaXQgZXhpc3RzLidcclxuICAgICAgfSxcclxuICAgICAgdGltZW91dDoge1xyXG4gICAgICAgIHZhbHVlOiA1MDAwLFxyXG4gICAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUFJPWFlfVElNRU9VVCcsXHJcbiAgICAgICAgY2xpTmFtZTogJ3Byb3h5VGltZW91dCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgdGltZW91dCBmb3IgdGhlIHByb3h5IHNlcnZlciB0byB1c2UsIGlmIGl0IGV4aXN0cy4nXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICByYXRlTGltaXRpbmc6IHtcclxuICAgICAgZW5hYmxlOiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfRU5BQkxFJyxcclxuICAgICAgICBjbGlOYW1lOiAnZW5hYmxlUmF0ZUxpbWl0aW5nJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgcmF0ZSBsaW1pdGluZyBmb3IgdGhlIHNlcnZlci4nXHJcbiAgICAgIH0sXHJcbiAgICAgIG1heFJlcXVlc3RzOiB7XHJcbiAgICAgICAgdmFsdWU6IDEwLFxyXG4gICAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19NQVhfUkVRVUVTVFMnLFxyXG4gICAgICAgIGxlZ2FjeU5hbWU6ICdyYXRlTGltaXQnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIG1heGltdW0gbnVtYmVyIG9mIHJlcXVlc3RzIGFsbG93ZWQgaW4gb25lIG1pbnV0ZS4nXHJcbiAgICAgIH0sXHJcbiAgICAgIHdpbmRvdzoge1xyXG4gICAgICAgIHZhbHVlOiAxLFxyXG4gICAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19XSU5ET1cnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHRpbWUgd2luZG93LCBpbiBtaW51dGVzLCBmb3IgdGhlIHJhdGUgbGltaXRpbmcuJ1xyXG4gICAgICB9LFxyXG4gICAgICBkZWxheToge1xyXG4gICAgICAgIHZhbHVlOiAwLFxyXG4gICAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19ERUxBWScsXHJcbiAgICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgICAnVGhlIGRlbGF5IGR1cmF0aW9uIGZvciBlYWNoIHN1Y2Nlc3NpdmUgcmVxdWVzdCBiZWZvcmUgcmVhY2hpbmcgdGhlIG1heGltdW0gbGltaXQuJ1xyXG4gICAgICB9LFxyXG4gICAgICB0cnVzdFByb3h5OiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfVFJVU1RfUFJPWFknLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnU2V0IHRoaXMgdG8gdHJ1ZSBpZiB0aGUgc2VydmVyIGlzIGJlaGluZCBhIGxvYWQgYmFsYW5jZXIuJ1xyXG4gICAgICB9LFxyXG4gICAgICBza2lwS2V5OiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX0tFWScsXHJcbiAgICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgICAnQWxsb3dzIGJ5cGFzc2luZyB0aGUgcmF0ZSBsaW1pdGVyIGFuZCBzaG91bGQgYmUgcHJvdmlkZWQgd2l0aCB0aGUgc2tpcFRva2VuIGFyZ3VtZW50LidcclxuICAgICAgfSxcclxuICAgICAgc2tpcFRva2VuOiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX1RPS0VOJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAgICdBbGxvd3MgYnlwYXNzaW5nIHRoZSByYXRlIGxpbWl0ZXIgYW5kIHNob3VsZCBiZSBwcm92aWRlZCB3aXRoIHRoZSBza2lwS2V5IGFyZ3VtZW50LidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHNzbDoge1xyXG4gICAgICBlbmFibGU6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfU1NMX0VOQUJMRScsXHJcbiAgICAgICAgY2xpTmFtZTogJ2VuYWJsZVNzbCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIG9yIGRpc2FibGVzIHRoZSBTU0wgcHJvdG9jb2wuJ1xyXG4gICAgICB9LFxyXG4gICAgICBmb3JjZToge1xyXG4gICAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfRk9SQ0UnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdzc2xGb3JjZScsXHJcbiAgICAgICAgbGVnYWN5TmFtZTogJ3NzbE9ubHknLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICAgJ1doZW4gc2V0IHRvIHRydWUsIHRoZSBzZXJ2ZXIgaXMgZm9yY2VkIHRvIHNlcnZlIG9ubHkgb3ZlciBIVFRQUy4nXHJcbiAgICAgIH0sXHJcbiAgICAgIHBvcnQ6IHtcclxuICAgICAgICB2YWx1ZTogNDQzLFxyXG4gICAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfU1NMX1BPUlQnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdzc2xQb3J0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSBwb3J0IG9uIHdoaWNoIHRvIHJ1biB0aGUgU1NMIHNlcnZlci4nXHJcbiAgICAgIH0sXHJcbiAgICAgIGNlcnRQYXRoOiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfU1NMX0NFUlRfUEFUSCcsXHJcbiAgICAgICAgbGVnYWN5TmFtZTogJ3NzbFBhdGgnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHBhdGggdG8gdGhlIFNTTCBjZXJ0aWZpY2F0ZS9rZXkgZmlsZS4nXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIHBvb2w6IHtcclxuICAgIG1pbldvcmtlcnM6IHtcclxuICAgICAgdmFsdWU6IDQsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9NSU5fV09SS0VSUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIG51bWJlciBvZiBtaW5pbXVtIGFuZCBpbml0aWFsIHBvb2wgd29ya2VycyB0byBzcGF3bi4nXHJcbiAgICB9LFxyXG4gICAgbWF4V29ya2Vyczoge1xyXG4gICAgICB2YWx1ZTogOCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX01BWF9XT1JLRVJTJyxcclxuICAgICAgbGVnYWN5TmFtZTogJ3dvcmtlcnMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBudW1iZXIgb2YgbWF4aW11bSBwb29sIHdvcmtlcnMgdG8gc3Bhd24uJ1xyXG4gICAgfSxcclxuICAgIHdvcmtMaW1pdDoge1xyXG4gICAgICB2YWx1ZTogNDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9XT1JLX0xJTUlUJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBudW1iZXIgb2Ygd29yayBwaWVjZXMgdGhhdCBjYW4gYmUgcGVyZm9ybWVkIGJlZm9yZSByZXN0YXJ0aW5nIHRoZSB3b3JrZXIgcHJvY2Vzcy4nXHJcbiAgICB9LFxyXG4gICAgYWNxdWlyZVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9BQ1FVSVJFX1RJTUVPVVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGR1cmF0aW9uLCBpbiBtaWxsaXNlY29uZHMsIHRvIHdhaXQgZm9yIGFjcXVpcmluZyBhIHJlc291cmNlLidcclxuICAgIH0sXHJcbiAgICBjcmVhdGVUaW1lb3V0OiB7XHJcbiAgICAgIHZhbHVlOiA1MDAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfQ1JFQVRFX1RJTUVPVVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGR1cmF0aW9uLCBpbiBtaWxsaXNlY29uZHMsIHRvIHdhaXQgZm9yIGNyZWF0aW5nIGEgcmVzb3VyY2UuJ1xyXG4gICAgfSxcclxuICAgIGRlc3Ryb3lUaW1lb3V0OiB7XHJcbiAgICAgIHZhbHVlOiA1MDAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfREVTVFJPWV9USU1FT1VUJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCB0byB3YWl0IGZvciBkZXN0cm95aW5nIGEgcmVzb3VyY2UuJ1xyXG4gICAgfSxcclxuICAgIGlkbGVUaW1lb3V0OiB7XHJcbiAgICAgIHZhbHVlOiAzMDAwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX0lETEVfVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgYWZ0ZXIgd2hpY2ggYW4gaWRsZSByZXNvdXJjZSBpcyBkZXN0cm95ZWQuJ1xyXG4gICAgfSxcclxuICAgIGNyZWF0ZVJldHJ5SW50ZXJ2YWw6IHtcclxuICAgICAgdmFsdWU6IDIwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX0NSRUFURV9SRVRSWV9JTlRFUlZBTCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgdG8gd2FpdCBiZWZvcmUgcmV0cnlpbmcgdGhlIGNyZWF0ZSBwcm9jZXNzIGluIGNhc2Ugb2YgYSBmYWlsdXJlLidcclxuICAgIH0sXHJcbiAgICByZWFwZXJJbnRlcnZhbDoge1xyXG4gICAgICB2YWx1ZTogMTAwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX1JFQVBFUl9JTlRFUlZBTCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgYWZ0ZXIgd2hpY2ggdGhlIGNoZWNrIGZvciBpZGxlIHJlc291cmNlcyB0byBkZXN0cm95IGlzIHRyaWdnZXJlZC4nXHJcbiAgICB9LFxyXG4gICAgYmVuY2htYXJraW5nOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9CRU5DSE1BUktJTkcnLFxyXG4gICAgICBjbGlOYW1lOiAncG9vbEJlbmNobWFya2luZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbmRpY2F0ZSB3aGV0aGVyIHRvIHNob3cgc3RhdGlzdGljcyBmb3IgdGhlIHBvb2wgb2YgcmVzb3VyY2VzIG9yIG5vdC4nXHJcbiAgICB9XHJcbiAgfSxcclxuICBsb2dnaW5nOiB7XHJcbiAgICBsZXZlbDoge1xyXG4gICAgICB2YWx1ZTogNCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX0xFVkVMJyxcclxuICAgICAgY2xpTmFtZTogJ2xvZ0xldmVsJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgbG9nZ2luZyBsZXZlbCB0byBiZSB1c2VkLidcclxuICAgIH0sXHJcbiAgICBmaWxlOiB7XHJcbiAgICAgIHZhbHVlOiAnaGlnaGNoYXJ0cy1leHBvcnQtc2VydmVyLmxvZycsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnTE9HR0lOR19GSUxFJyxcclxuICAgICAgY2xpTmFtZTogJ2xvZ0ZpbGUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIG5hbWUgb2YgYSBsb2cgZmlsZS4gVGhlIGxvZ0Rlc3Qgb3B0aW9uIGFsc28gbmVlZHMgdG8gYmUgc2V0IHRvIGVuYWJsZSBmaWxlIGxvZ2dpbmcuJ1xyXG4gICAgfSxcclxuICAgIGRlc3Q6IHtcclxuICAgICAgdmFsdWU6ICdsb2cvJyxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX0RFU1QnLFxyXG4gICAgICBjbGlOYW1lOiAnbG9nRGVzdCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgcGF0aCB0byBzdG9yZSBsb2cgZmlsZXMuIFRoaXMgYWxzbyBlbmFibGVzIGZpbGUgbG9nZ2luZy4nXHJcbiAgICB9XHJcbiAgfSxcclxuICB1aToge1xyXG4gICAgZW5hYmxlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnVUlfRU5BQkxFJyxcclxuICAgICAgY2xpTmFtZTogJ2VuYWJsZVVpJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0VuYWJsZXMgb3IgZGlzYWJsZXMgdGhlIHVzZXIgaW50ZXJmYWNlIChVSSkgZm9yIHRoZSBleHBvcnQgc2VydmVyLidcclxuICAgIH0sXHJcbiAgICByb3V0ZToge1xyXG4gICAgICB2YWx1ZTogJy8nLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ1VJX1JPVVRFJyxcclxuICAgICAgY2xpTmFtZTogJ3VpUm91dGUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGVuZHBvaW50IHJvdXRlIHRvIHdoaWNoIHRoZSB1c2VyIGludGVyZmFjZSAoVUkpIHNob3VsZCBiZSBhdHRhY2hlZC4nXHJcbiAgICB9XHJcbiAgfSxcclxuICBvdGhlcjoge1xyXG4gICAgbm9kZUVudjoge1xyXG4gICAgICB2YWx1ZTogJ3Byb2R1Y3Rpb24nLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ09USEVSX05PREVfRU5WJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgdHlwZSBvZiBOb2RlLmpzIGVudmlyb25tZW50LidcclxuICAgIH0sXHJcbiAgICBsaXN0ZW5Ub1Byb2Nlc3NFeGl0czoge1xyXG4gICAgICB2YWx1ZTogdHJ1ZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfTElTVEVOX1RPX1BST0NFU1NfRVhJVFMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0RlY2lkZXMgd2hldGhlciBvciBub3QgdG8gYXR0YWNoIHByb2Nlc3MuZXhpdCBoYW5kbGVycy4nXHJcbiAgICB9LFxyXG4gICAgbm9Mb2dvOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfTk9fTE9HTycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdTa2lwIHByaW50aW5nIHRoZSBsb2dvIG9uIGEgc3RhcnR1cC4gV2lsbCBiZSByZXBsYWNlZCBieSBhIHNpbXBsZSB0ZXh0LidcclxuICAgIH0sXHJcbiAgICBoYXJkUmVzZXRQYWdlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfSEFSRF9SRVNFVF9QQUdFJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdEZWNpZGVzIGlmIHRoZSBwYWdlIGNvbnRlbnQgc2hvdWxkIGJlIHJlc2V0IGVudGlyZWx5LidcclxuICAgIH0sXHJcbiAgICBicm93c2VyU2hlbGxNb2RlOiB7XHJcbiAgICAgIHZhbHVlOiB0cnVlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9CUk9XU0VSX1NIRUxMX01PREUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0RlY2lkZXMgaWYgdGhlIGJyb3dzZXIgcnVucyBpbiB0aGUgc2hlbGwgbW9kZS4nXHJcbiAgICB9XHJcbiAgfSxcclxuICBkZWJ1Zzoge1xyXG4gICAgZW5hYmxlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfRU5BQkxFJyxcclxuICAgICAgY2xpTmFtZTogJ2VuYWJsZURlYnVnJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIG9yIGRpc2FibGVzIGRlYnVnIG1vZGUgZm9yIHRoZSB1bmRlcmx5aW5nIGJyb3dzZXIuJ1xyXG4gICAgfSxcclxuICAgIGhlYWRsZXNzOiB7XHJcbiAgICAgIHZhbHVlOiB0cnVlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19IRUFETEVTUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdDb250cm9scyB0aGUgbW9kZSBpbiB3aGljaCB0aGUgYnJvd3NlciBpcyBsYXVuY2hlZCB3aGVuIGluIHRoZSBkZWJ1ZyBtb2RlLidcclxuICAgIH0sXHJcbiAgICBkZXZ0b29sczoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZW52TGluazogJ0RFQlVHX0RFVlRPT0xTJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0RlY2lkZXMgd2hldGhlciB0byBlbmFibGUgRGV2VG9vbHMgd2hlbiB0aGUgYnJvd3NlciBpcyBpbiBhIGhlYWRmdWwgc3RhdGUuJ1xyXG4gICAgfSxcclxuICAgIGxpc3RlblRvQ29uc29sZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZW52TGluazogJ0RFQlVHX0xJU1RFTl9UT19DT05TT0xFJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0RlY2lkZXMgd2hldGhlciB0byBlbmFibGUgYSBsaXN0ZW5lciBmb3IgY29uc29sZSBtZXNzYWdlcyBzZW50IGZyb20gdGhlIGJyb3dzZXIuJ1xyXG4gICAgfSxcclxuICAgIGR1bXBpbzoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZW52TGluazogJ0RFQlVHX0RVTVBJTycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdSZWRpcmVjdHMgYnJvd3NlciBwcm9jZXNzIHN0ZG91dCBhbmQgc3RkZXJyIHRvIHByb2Nlc3Muc3Rkb3V0IGFuZCBwcm9jZXNzLnN0ZGVyci4nXHJcbiAgICB9LFxyXG4gICAgc2xvd01vOiB7XHJcbiAgICAgIHZhbHVlOiAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ0RFQlVHX1NMT1dfTU8nLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnU2xvd3MgZG93biBQdXBwZXRlZXIgb3BlcmF0aW9ucyBieSB0aGUgc3BlY2lmaWVkIG51bWJlciBvZiBtaWxsaXNlY29uZHMuJ1xyXG4gICAgfSxcclxuICAgIGRlYnVnZ2luZ1BvcnQ6IHtcclxuICAgICAgdmFsdWU6IDkyMjIsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfREVCVUdHSU5HX1BPUlQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1NwZWNpZmllcyB0aGUgZGVidWdnaW5nIHBvcnQuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgd2ViU29ja2V0OiB7XHJcbiAgICBlbmFibGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdXRUJfU09DS0VUX0VOQUJMRScsXHJcbiAgICAgIGNsaU5hbWU6ICdlbmFibGVXcycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyBvciBkaXNhYmxlcyB0aGUgV2ViU29ja2V0IGNvbm5lY3Rpb24uJ1xyXG4gICAgfSxcclxuICAgIHJlY29ubmVjdDoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZW52TGluazogJ1dFQl9TT0NLRVRfUkVDT05ORUNUJyxcclxuICAgICAgY2xpTmFtZTogJ3dzUmVjb25uZWN0JyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0NvbnRyb2xzIHdoZXRoZXIgb3Igbm90IHRvIHRyeSByZWNvbm5lY3RpbmcgdG8gdGhlIFdlYlNvY2tldCBzZXJ2ZXIgaW4gY2FzZSBvZiBhIGRpc2Nvbm5lY3QuJ1xyXG4gICAgfSxcclxuICAgIHJlamVjdFVuYXV0aG9yaXplZDoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZW52TGluazogJ1dFQl9TT0NLRVRfUkVKRUNUX1VOQVVUSE9SSVpFRCcsXHJcbiAgICAgIGNsaU5hbWU6ICd3c3JlamVjdFVuYXV0aG9yaXplZCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgIFwiRGV0ZXJtaW5lcyB3aGV0aGVyIHRoZSBjbGllbnQgdmVyaWZpZXMgdGhlIHNlcnZlcidzIFNTTC9UTFMgY2VydGlmaWNhdGUgZHVyaW5nIHRoZSBoYW5kc2hha2UgcHJvY2Vzcy5cIlxyXG4gICAgfSxcclxuICAgIHBpbmdUaW1lb3V0OiB7XHJcbiAgICAgIHZhbHVlOiAxNjAwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdXRUJfU09DS0VUX1BJTkdfVElNRU9VVCcsXHJcbiAgICAgIGNsaU5hbWU6ICd3c1BpbmdUaW1lb3V0JyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSB0aW1lb3V0LCBpbiBtaWxsaXNlY29uZHMsIGZvciB0aGUgaGVhcnRiZWF0IG1lY2hhbmlzbSBiZXR3ZWVuIHRoZSBjbGllbnQgYW5kIHNlcnZlci4nXHJcbiAgICB9LFxyXG4gICAgcmVjb25uZWN0SW50ZXJ2YWw6IHtcclxuICAgICAgdmFsdWU6IDMwMDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnV0VCX1NPQ0tFVF9SRUNPTk5FQ1RfSU5URVJWQUwnLFxyXG4gICAgICBjbGlOYW1lOiAnd3NSZWNvbm5lY3RJbnRlcnZhbCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIGludGVydmFsLCBpbiBtaWxsaXNlY29uZHMsIGZvciB0aGUgcmVjb25uZWN0IGF0dGVtcHQuJ1xyXG4gICAgfSxcclxuICAgIHJlY29ubmVjdEF0dGVtcHRzOiB7XHJcbiAgICAgIHZhbHVlOiAzLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1dFQl9TT0NLRVRfUkVDT05ORUNUX0FUVEVNUFRTJyxcclxuICAgICAgY2xpTmFtZTogJ3dzUmVjb25uZWN0QXR0ZW1wdHMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIG51bWJlciBvZiByZWNvbm5lY3QgYXR0ZW1wdHMgYmVmb3JlIHJldHVybmluZyBhIGNvbm5lY3Rpb24gZXJyb3IuJ1xyXG4gICAgfSxcclxuICAgIG1lc3NhZ2VJbnRlcnZhbDoge1xyXG4gICAgICB2YWx1ZTogMyxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdXRUJfU09DS0VUX01FU1NBR0VfSU5URVJWQUwnLFxyXG4gICAgICBjbGlOYW1lOiAnd3NNZXNzYWdlSW50ZXJ2YWwnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGludGVydmFsLCBpbiBtaWxsaXNlY29uZHMsIGZvciBhdXRvIHNlbmRpbmcgdGhlIGRhdGEgdGhyb3VnaCBhIFdlYlNvY2tldCBjb25uZWN0aW9uLidcclxuICAgIH0sXHJcbiAgICB1cmw6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ1dFQl9TT0NLRVRfVVJMJyxcclxuICAgICAgY2xpTmFtZTogJ3dzVXJsJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgVVJMIG9mIHRoZSBXZWJTb2NrZXQgc2VydmVyLidcclxuICAgIH0sXHJcbiAgICBzZWNyZXQ6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ1dFQl9TT0NLRVRfU0VDUkVUJyxcclxuICAgICAgY2xpTmFtZTogJ3dzU2VjcmV0JyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBzZWNyZXQgdXNlZCB0byBjcmVhdGUgYSBKU09OIFdlYiBUb2tlbiBzZW50IHRvIHRoZSBXZWJTb2NrZXQgc2VydmVyLidcclxuICAgIH1cclxuICB9XHJcbn07XHJcblxyXG4vLyBUaGUgY29uZmlnIGRlc2NyaXB0aW9ucyBvYmplY3QgZm9yIHRoZSBwcm9tcHRzIGZ1bmN0aW9uYWxpdHkuIEl0IGNvbnRhaW5zXHJcbi8vIGluZm9ybWF0aW9uIGxpa2U6XHJcbi8vICogVHlwZSBvZiBhIHByb21wdFxyXG4vLyAqIE5hbWUgb2YgYW4gb3B0aW9uXHJcbi8vICogU2hvcnQgZGVzY3JpcHRpb24gb2YgYSBjaG9zZW4gb3B0aW9uXHJcbi8vICogSW5pdGlhbCB2YWx1ZVxyXG5leHBvcnQgY29uc3QgcHJvbXB0c0NvbmZpZyA9IHtcclxuICBwdXBwZXRlZXI6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ2xpc3QnLFxyXG4gICAgICBuYW1lOiAnYXJncycsXHJcbiAgICAgIG1lc3NhZ2U6ICdQdXBwZXRlZXIgYXJndW1lbnRzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wdXBwZXRlZXIuYXJncy52YWx1ZS5qb2luKCcsJyksXHJcbiAgICAgIHNlcGFyYXRvcjogJywnXHJcbiAgICB9XHJcbiAgXSxcclxuICBoaWdoY2hhcnRzOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ3ZlcnNpb24nLFxyXG4gICAgICBtZXNzYWdlOiAnSGlnaGNoYXJ0cyB2ZXJzaW9uJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLnZlcnNpb24udmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ2NkblVSTCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgVVJMIG9mIENETicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5jZG5VUkwudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdtdWx0aXNlbGVjdCcsXHJcbiAgICAgIG5hbWU6ICdjb3JlU2NyaXB0cycsXHJcbiAgICAgIG1lc3NhZ2U6ICdBdmFpbGFibGUgY29yZSBzY3JpcHRzJyxcclxuICAgICAgaW5zdHJ1Y3Rpb25zOiAnU3BhY2U6IFNlbGVjdCBzcGVjaWZpYywgQTogU2VsZWN0IGFsbCwgRW50ZXI6IENvbmZpcm0uJyxcclxuICAgICAgY2hvaWNlczogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLmNvcmVTY3JpcHRzLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbXVsdGlzZWxlY3QnLFxyXG4gICAgICBuYW1lOiAnbW9kdWxlU2NyaXB0cycsXHJcbiAgICAgIG1lc3NhZ2U6ICdBdmFpbGFibGUgbW9kdWxlIHNjcmlwdHMnLFxyXG4gICAgICBpbnN0cnVjdGlvbnM6ICdTcGFjZTogU2VsZWN0IHNwZWNpZmljLCBBOiBTZWxlY3QgYWxsLCBFbnRlcjogQ29uZmlybS4nLFxyXG4gICAgICBjaG9pY2VzOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMubW9kdWxlU2NyaXB0cy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ211bHRpc2VsZWN0JyxcclxuICAgICAgbmFtZTogJ2luZGljYXRvclNjcmlwdHMnLFxyXG4gICAgICBtZXNzYWdlOiAnQXZhaWxhYmxlIGluZGljYXRvciBzY3JpcHRzJyxcclxuICAgICAgaW5zdHJ1Y3Rpb25zOiAnU3BhY2U6IFNlbGVjdCBzcGVjaWZpYywgQTogU2VsZWN0IGFsbCwgRW50ZXI6IENvbmZpcm0uJyxcclxuICAgICAgY2hvaWNlczogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLmluZGljYXRvclNjcmlwdHMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdsaXN0JyxcclxuICAgICAgbmFtZTogJ2N1c3RvbVNjcmlwdHMnLFxyXG4gICAgICBtZXNzYWdlOiAnQ3VzdG9tIHNjcmlwdHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuY3VzdG9tU2NyaXB0cy52YWx1ZS5qb2luKCcsJyksXHJcbiAgICAgIHNlcGFyYXRvcjogJywnXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2ZvcmNlRmV0Y2gnLFxyXG4gICAgICBtZXNzYWdlOiAnRm9yY2UgcmUtZmV0Y2ggdGhlIHNjcmlwdHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuZm9yY2VGZXRjaC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnY2FjaGVQYXRoJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBwYXRoIHRvIHRoZSBjYWNoZSBkaXJlY3RvcnknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuY2FjaGVQYXRoLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBleHBvcnQ6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3NlbGVjdCcsXHJcbiAgICAgIG5hbWU6ICd0eXBlJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBkZWZhdWx0IGV4cG9ydCBmaWxlIHR5cGUnLFxyXG4gICAgICBoaW50OiBgRGVmYXVsdDogJHtkZWZhdWx0Q29uZmlnLmV4cG9ydC50eXBlLnZhbHVlfWAsXHJcbiAgICAgIGluaXRpYWw6IDAsXHJcbiAgICAgIGNob2ljZXM6IFsncG5nJywgJ2pwZWcnLCAncGRmJywgJ3N2ZyddXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnc2VsZWN0JyxcclxuICAgICAgbmFtZTogJ2NvbnN0cicsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgZGVmYXVsdCBjb25zdHJ1Y3RvciBmb3IgSGlnaGNoYXJ0cycsXHJcbiAgICAgIGhpbnQ6IGBEZWZhdWx0OiAke2RlZmF1bHRDb25maWcuZXhwb3J0LmNvbnN0ci52YWx1ZX1gLFxyXG4gICAgICBpbml0aWFsOiAwLFxyXG4gICAgICBjaG9pY2VzOiBbJ2NoYXJ0JywgJ3N0b2NrQ2hhcnQnLCAnbWFwQ2hhcnQnLCAnZ2FudHRDaGFydCddXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2RlZmF1bHRIZWlnaHQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgZmFsbGJhY2sgaGVpZ2h0IG9mIHRoZSBleHBvcnRlZCBjaGFydCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LmRlZmF1bHRIZWlnaHQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnZGVmYXVsdFdpZHRoJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBkZWZhdWx0IGZhbGxiYWNrIHdpZHRoIG9mIHRoZSBleHBvcnRlZCBjaGFydCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LmRlZmF1bHRXaWR0aC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdkZWZhdWx0U2NhbGUnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgZmFsbGJhY2sgc2NhbGUgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5leHBvcnQuZGVmYXVsdFNjYWxlLnZhbHVlLFxyXG4gICAgICBtaW46IDAuMSxcclxuICAgICAgbWF4OiA1XHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3Jhc3Rlcml6YXRpb25UaW1lb3V0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSByZW5kZXJpbmcgd2VicGFnZSB0aW1lb3V0IGluIG1pbGxpc2Vjb25kcycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LnJhc3Rlcml6YXRpb25UaW1lb3V0LnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBjdXN0b21Mb2dpYzogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2FsbG93Q29kZUV4ZWN1dGlvbicsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgZXhlY3V0aW9uIG9mIGN1c3RvbSBjb2RlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5jdXN0b21Mb2dpYy5hbGxvd0NvZGVFeGVjdXRpb24udmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnYWxsb3dGaWxlUmVzb3VyY2VzJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBmaWxlIHJlc291cmNlcycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuY3VzdG9tTG9naWMuYWxsb3dGaWxlUmVzb3VyY2VzLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBzZXJ2ZXI6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdlbmFibGUnLFxyXG4gICAgICBtZXNzYWdlOiAnU3RhcnRzIHRoZSBzZXJ2ZXIgb24gMC4wLjAuMCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLmVuYWJsZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnaG9zdCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdTZXJ2ZXIgaG9zdG5hbWUnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5ob3N0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3BvcnQnLFxyXG4gICAgICBtZXNzYWdlOiAnU2VydmVyIHBvcnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5wb3J0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2JlbmNobWFya2luZycsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgc2VydmVyIGJlbmNobWFya2luZycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLmJlbmNobWFya2luZy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAncHJveHkuaG9zdCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgaG9zdCBvZiB0aGUgcHJveHkgc2VydmVyIHRvIHVzZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnByb3h5Lmhvc3QudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncHJveHkucG9ydCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcG9ydCBvZiB0aGUgcHJveHkgc2VydmVyIHRvIHVzZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnByb3h5LnBvcnQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncHJveHkudGltZW91dCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgdGltZW91dCBmb3IgdGhlIHByb3h5IHNlcnZlciB0byB1c2UnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5wcm94eS50aW1lb3V0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5lbmFibGUnLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIHJhdGUgbGltaXRpbmcnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcuZW5hYmxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5tYXhSZXF1ZXN0cycsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbWF4aW11bSByZXF1ZXN0cyBhbGxvd2VkIHBlciBtaW51dGUnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcubWF4UmVxdWVzdHMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLndpbmRvdycsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcmF0ZS1saW1pdGluZyB0aW1lIHdpbmRvdyBpbiBtaW51dGVzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLndpbmRvdy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcuZGVsYXknLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdUaGUgZGVsYXkgZm9yIGVhY2ggc3VjY2Vzc2l2ZSByZXF1ZXN0IGJlZm9yZSByZWFjaGluZyB0aGUgbWF4aW11bScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy5kZWxheS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcudHJ1c3RQcm94eScsXHJcbiAgICAgIG1lc3NhZ2U6ICdTZXQgdG8gdHJ1ZSBpZiBiZWhpbmQgYSBsb2FkIGJhbGFuY2VyJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLnRydXN0UHJveHkudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5za2lwS2V5JyxcclxuICAgICAgbWVzc2FnZTpcclxuICAgICAgICAnQWxsb3dzIGJ5cGFzc2luZyB0aGUgcmF0ZSBsaW1pdGVyIHdoZW4gcHJvdmlkZWQgd2l0aCB0aGUgc2tpcFRva2VuIGFyZ3VtZW50JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLnNraXBLZXkudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5za2lwVG9rZW4nLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdBbGxvd3MgYnlwYXNzaW5nIHRoZSByYXRlIGxpbWl0ZXIgd2hlbiBwcm92aWRlZCB3aXRoIHRoZSBza2lwS2V5IGFyZ3VtZW50JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLnNraXBUb2tlbi52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdzc2wuZW5hYmxlJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBTU0wgcHJvdG9jb2wnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wuZW5hYmxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ3NzbC5mb3JjZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdGb3JjZSBzZXJ2aW5nIG9ubHkgb3ZlciBIVFRQUycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnNzbC5mb3JjZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdzc2wucG9ydCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdTU0wgc2VydmVyIHBvcnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wucG9ydC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnc3NsLmNlcnRQYXRoJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBwYXRoIHRvIGZpbmQgdGhlIFNTTCBjZXJ0aWZpY2F0ZS9rZXknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wuY2VydFBhdGgudmFsdWVcclxuICAgIH1cclxuICBdLFxyXG4gIHBvb2w6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdtaW5Xb3JrZXJzJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBpbml0aWFsIG51bWJlciBvZiB3b3JrZXJzIHRvIHNwYXduJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLm1pbldvcmtlcnMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnbWF4V29ya2VycycsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbWF4aW11bSBudW1iZXIgb2Ygd29ya2VycyB0byBzcGF3bicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5tYXhXb3JrZXJzLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3dvcmtMaW1pdCcsXHJcbiAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgJ1RoZSBwaWVjZXMgb2Ygd29yayB0aGF0IGNhbiBiZSBwZXJmb3JtZWQgYmVmb3JlIHJlc3RhcnRpbmcgYSBQdXBwZXRlZXIgcHJvY2VzcycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC53b3JrTGltaXQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnYWNxdWlyZVRpbWVvdXQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgYWNxdWlyaW5nIGEgcmVzb3VyY2UnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wuYWNxdWlyZVRpbWVvdXQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnY3JlYXRlVGltZW91dCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcyB0byB3YWl0IGZvciBjcmVhdGluZyBhIHJlc291cmNlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmNyZWF0ZVRpbWVvdXQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnZGVzdHJveVRpbWVvdXQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgZGVzdHJveWluZyBhIHJlc291cmNlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmRlc3Ryb3lUaW1lb3V0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2lkbGVUaW1lb3V0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIGFmdGVyIGFuIGlkbGUgcmVzb3VyY2UgaXMgZGVzdHJveWVkJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmlkbGVUaW1lb3V0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2NyZWF0ZVJldHJ5SW50ZXJ2YWwnLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdUaGUgcmV0cnkgaW50ZXJ2YWwgaW4gbWlsbGlzZWNvbmRzIGFmdGVyIGEgY3JlYXRlIHByb2Nlc3MgZmFpbHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wuY3JlYXRlUmV0cnlJbnRlcnZhbC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdyZWFwZXJJbnRlcnZhbCcsXHJcbiAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgJ1RoZSByZWFwZXIgaW50ZXJ2YWwgaW4gbWlsbGlzZWNvbmRzIGFmdGVyIHRyaWdnZXJpbmcgdGhlIGNoZWNrIGZvciBpZGxlIHJlc291cmNlcyB0byBkZXN0cm95JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLnJlYXBlckludGVydmFsLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2JlbmNobWFya2luZycsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgYmVuY2htYXJraW5nIGZvciBhIHJlc291cmNlIHBvb2wnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wuYmVuY2htYXJraW5nLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBsb2dnaW5nOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnbGV2ZWwnLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdUaGUgbG9nIGxldmVsICgwOiBzaWxlbnQsIDE6IGVycm9yLCAyOiB3YXJuaW5nLCAzOiBub3RpY2UsIDQ6IHZlcmJvc2UsIDU6IGJlbmNobWFyayknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmxvZ2dpbmcubGV2ZWwudmFsdWUsXHJcbiAgICAgIHJvdW5kOiAwLFxyXG4gICAgICBtaW46IDAsXHJcbiAgICAgIG1heDogNVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnZmlsZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdBIGxvZyBmaWxlIG5hbWUuIFNldCB3aXRoIHRoZSAtLWxvZ0Rlc3QgdG8gZW5hYmxlIGZpbGUgbG9nZ2luZycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcubG9nZ2luZy5maWxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdkZXN0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBwYXRoIHRvIGxvZyBmaWxlcy4gRW5hYmxlcyBmaWxlIGxvZ2dpbmcnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmxvZ2dpbmcuZGVzdC52YWx1ZVxyXG4gICAgfVxyXG4gIF0sXHJcbiAgdWk6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdlbmFibGUnLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIFVJIGZvciB0aGUgZXhwb3J0IHNlcnZlcicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcudWkuZW5hYmxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdyb3V0ZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdBIHJvdXRlIHRvIGF0dGFjaCB0aGUgVUknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnVpLnJvdXRlLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBvdGhlcjogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdub2RlRW52JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSB0eXBlIG9mIE5vZGUuanMgZW52aXJvbm1lbnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLm90aGVyLm5vZGVFbnYudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnbGlzdGVuVG9Qcm9jZXNzRXhpdHMnLFxyXG4gICAgICBtZXNzYWdlOiAnU2V0IHRvIGZhbHNlIHRvIHNraXAgYXR0YWNoaW5nIHByb2Nlc3MuZXhpdCBoYW5kbGVycycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcub3RoZXIubGlzdGVuVG9Qcm9jZXNzRXhpdHMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnbm9Mb2dvJyxcclxuICAgICAgbWVzc2FnZTogJ1NraXAgcHJpbnRpbmcgdGhlIGxvZ28gb24gc3RhcnR1cC4gUmVwbGFjZWQgYnkgc2ltcGxlIHRleHQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLm90aGVyLm5vTG9nby52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdoYXJkUmVzZXRQYWdlJyxcclxuICAgICAgbWVzc2FnZTogJ0RlY2lkZXMgaWYgdGhlIHBhZ2UgY29udGVudCBzaG91bGQgYmUgcmVzZXQgZW50aXJlbHknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLm90aGVyLmhhcmRSZXNldFBhZ2UudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnYnJvd3NlclNoZWxsTW9kZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdEZWNpZGVzIGlmIHRoZSBicm93c2VyIHJ1bnMgaW4gdGhlIHNoZWxsIG1vZGUnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLm90aGVyLmJyb3dzZXJTaGVsbE1vZGUudmFsdWVcclxuICAgIH1cclxuICBdLFxyXG4gIGRlYnVnOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnZW5hYmxlJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZXMgZGVidWcgbW9kZSBmb3IgdGhlIGJyb3dzZXIgaW5zdGFuY2UnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmRlYnVnLmVuYWJsZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdoZWFkbGVzcycsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbW9kZSBzZXR0aW5nIGZvciB0aGUgYnJvd3NlcicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZGVidWcuaGVhZGxlc3MudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnZGV2dG9vbHMnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIERldlRvb2xzIGZvciB0aGUgaGVhZGZ1bCBicm93c2VyJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5kZWJ1Zy5kZXZ0b29scy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdsaXN0ZW5Ub0NvbnNvbGUnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIGV2ZW50IGxpc3RlbmVyIGZvciBjb25zb2xlIG1lc3NhZ2VzIGZyb20gdGhlIGJyb3dzZXInLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmRlYnVnLmxpc3RlblRvQ29uc29sZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdkdW1waW8nLFxyXG4gICAgICBtZXNzYWdlOiAnUmVkaXJlY3RzIHRoZSBicm93c2VyIHN0ZG91dCBhbmQgc3RkZXJyIHRvIE5vZGVKUyBwcm9jZXNzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5kZWJ1Zy5kdW1waW8udmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnc2xvd01vJyxcclxuICAgICAgbWVzc2FnZTogJ1B1cHBldGVlciBvcGVyYXRpb25zIHNsb3cgZG93biBpbiBtaWxsaXNlY29uZHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmRlYnVnLnNsb3dNby52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdkZWJ1Z2dpbmdQb3J0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBwb3J0IG51bWJlciBmb3IgZGVidWdnaW5nJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5kZWJ1Zy5kZWJ1Z2dpbmdQb3J0LnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICB3ZWJTb2NrZXQ6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdlbmFibGUnLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlcyBXZWJTb2NrZXQgY29ubmVjdGlvbicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcud2ViU29ja2V0LmVuYWJsZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdyZWNvbm5lY3QnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIHJlY29ubmVjdCBtZWNoYW5pc20gZm9yIFdlYlNvY2tldCBjb25uZWN0aW9uJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy53ZWJTb2NrZXQucmVjb25uZWN0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ3JlamVjdFVuYXV0aG9yaXplZCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdSZWplY3QgY29ubmVjdGlvbiBpZiBXZWJTb2NrZXQgaXMgbm90IHNlY3VyZWQsIFNTTC9UTFMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLndlYlNvY2tldC5yZWplY3RVbmF1dGhvcml6ZWQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncGluZ1RpbWVvdXQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGltZW91dCBmb3IgdGhlIGhlYXJiZWF0IG1lY2hhbmlzbScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcud2ViU29ja2V0LnBpbmdUaW1lb3V0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3JlY29ubmVjdEludGVydmFsJyxcclxuICAgICAgbWVzc2FnZTogJ0ludGVydmFsIGZvciB0aGUgcmVjb25uZWN0IG1lY2hhbmlzbScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcud2ViU29ja2V0LnJlY29ubmVjdEludGVydmFsLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3JlY29ubmVjdEF0dGVtcHRzJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBudW1iZXIgb2YgcmVjb25uZWN0IGF0dGVtcHRzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy53ZWJTb2NrZXQucmVjb25uZWN0QXR0ZW1wdHMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnbWVzc2FnZUludGVydmFsJyxcclxuICAgICAgbWVzc2FnZTogJ0ludGVydmFsIGZvciBhdXRvIHNlbmRpbmcgdGhlIGRhdGEnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLndlYlNvY2tldC5tZXNzYWdlSW50ZXJ2YWwudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ3VybCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgVVJMIG9mIHRoZSBXZWJTb2NrZXQgc2VydmVyJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy53ZWJTb2NrZXQudXJsLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdzZWNyZXQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIHNlY3JldCBmb3IgdGhlIEpXVCB0byBXZWJTb2NrZXQgc2VydmVyJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy53ZWJTb2NrZXQuc2VjcmV0LnZhbHVlXHJcbiAgICB9XHJcbiAgXVxyXG59O1xyXG5cclxuLy8gQWJzb2x1dGUgcHJvcHMgdGhhdCwgaW4gY2FzZSBvZiBtZXJnaW5nIHJlY3Vyc2l2ZWx5LCBuZWVkIHRvIGJlIGZvcmNlIG1lcmdlZFxyXG5leHBvcnQgY29uc3QgYWJzb2x1dGVQcm9wcyA9IFtcclxuICAnb3B0aW9ucycsXHJcbiAgJ2dsb2JhbE9wdGlvbnMnLFxyXG4gICd0aGVtZU9wdGlvbnMnLFxyXG4gICdyZXNvdXJjZXMnLFxyXG4gICdwYXlsb2FkJ1xyXG5dO1xyXG5cclxuLy8gQXJndW1lbnQgbmVzdGluZyBsZXZlbCBvZiBhbGwgZXhwb3J0IHNlcnZlciBvcHRpb25zXHJcbmV4cG9ydCBjb25zdCBuZXN0ZWRBcmdzID0ge307XHJcblxyXG4vKipcclxuICogUmVjdXJzaXZlbHkgY3JlYXRlcyBhIGNoYWluIG9mIG5lc3RlZCBhcmd1bWVudHMgZnJvbSBhbiBvYmplY3QuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvYmogLSBUaGUgb2JqZWN0IGNvbnRhaW5pbmcgbmVzdGVkIGFyZ3VtZW50cy5cclxuICogQHBhcmFtIHtzdHJpbmd9IHByb3BDaGFpbiAtIFRoZSBjdXJyZW50IGNoYWluIG9mIG5lc3RlZCBwcm9wZXJ0aWVzXHJcbiAqICh1c2VkIGludGVybmFsbHkgZHVyaW5nIHJlY3Vyc2lvbikuXHJcbiAqL1xyXG5jb25zdCBjcmVhdGVOZXN0ZWRBcmdzID0gKG9iaiwgcHJvcENoYWluID0gJycpID0+IHtcclxuICBPYmplY3Qua2V5cyhvYmopLmZvckVhY2goKGspID0+IHtcclxuICAgIGlmICghWydwdXBwZXRlZXInLCAnaGlnaGNoYXJ0cyddLmluY2x1ZGVzKGspKSB7XHJcbiAgICAgIGNvbnN0IGVudHJ5ID0gb2JqW2tdO1xyXG4gICAgICBpZiAodHlwZW9mIGVudHJ5LnZhbHVlID09PSAndW5kZWZpbmVkJykge1xyXG4gICAgICAgIC8vIEdvIGRlZXBlciBpbiB0aGUgbmVzdGVkIGFyZ3VtZW50c1xyXG4gICAgICAgIGNyZWF0ZU5lc3RlZEFyZ3MoZW50cnksIGAke3Byb3BDaGFpbn0uJHtrfWApO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIC8vIENyZWF0ZSB0aGUgY2hhaW4gb2YgbmVzdGVkIGFyZ3VtZW50c1xyXG4gICAgICAgIG5lc3RlZEFyZ3NbZW50cnkuY2xpTmFtZSB8fCBrXSA9IGAke3Byb3BDaGFpbn0uJHtrfWAuc3Vic3RyaW5nKDEpO1xyXG5cclxuICAgICAgICAvLyBTdXBwb3J0IGZvciB0aGUgbGVnYWN5LCBQaGFudG9tSlMgcHJvcGVydGllcyBuYW1lc1xyXG4gICAgICAgIGlmIChlbnRyeS5sZWdhY3lOYW1lICE9PSB1bmRlZmluZWQpIHtcclxuICAgICAgICAgIG5lc3RlZEFyZ3NbZW50cnkubGVnYWN5TmFtZV0gPSBgJHtwcm9wQ2hhaW59LiR7a31gLnN1YnN0cmluZygxKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9KTtcclxufTtcclxuXHJcbmNyZWF0ZU5lc3RlZEFyZ3MoZGVmYXVsdENvbmZpZyk7XHJcbiIsIi8qKlxyXG4gKiBAZmlsZW92ZXJ2aWV3XHJcbiAqIFRoaXMgZmlsZSBpcyByZXNwb25zaWJsZSBmb3IgcGFyc2luZyB0aGUgZW52aXJvbm1lbnQgdmFyaWFibGVzIHdpdGggdGhlICd6b2QnXHJcbiAqIGxpYnJhcnkuIFRoZSBwYXJzZWQgZW52aXJvbm1lbnQgdmFyaWFibGVzIGFyZSB0aGVuIGV4cG9ydGVkIHRvIGJlIHVzZWRcclxuICogaW4gdGhlIGFwcGxpY2F0aW9uIGFzIFwiZW52c1wiLiBXZSBzaG91bGQgbm90IHVzZSBwcm9jZXNzLmVudiBkaXJlY3RseVxyXG4gKiBpbiB0aGUgYXBwbGljYXRpb24gYXMgdGhlc2Ugd291bGQgbm90IGJlIHBhcnNlZCBwcm9wZXJseS5cclxuICpcclxuICogVGhlIGVudmlyb25tZW50IHZhcmlhYmxlcyBhcmUgcGFyc2VkIGFuZCB2YWxpZGF0ZWQgb25seSBvbmNlIHdoZW5cclxuICogdGhlIGFwcGxpY2F0aW9uIHN0YXJ0cy4gV2Ugc2hvdWxkIHdyaXRlIGEgY3VzdG9tIHZhbGlkYXRvciBvciBhIHRyYW5zZm9ybWVyXHJcbiAqIGZvciBlYWNoIG9mIHRoZSBvcHRpb25zLlxyXG4gKi9cclxuXHJcbmltcG9ydCBkb3RlbnYgZnJvbSAnZG90ZW52JztcclxuaW1wb3J0IHsgeiB9IGZyb20gJ3pvZCc7XHJcblxyXG5pbXBvcnQgeyBzY3JpcHRzTmFtZXMgfSBmcm9tICcuL3NjaGVtYXMvY29uZmlnLmpzJztcclxuXHJcbi8vIExvYWQgLmVudiBpbnRvIGVudmlyb25tZW50IHZhcmlhYmxlc1xyXG5kb3RlbnYuY29uZmlnKCk7XHJcblxyXG4vLyBPYmplY3Qgd2l0aCBjdXN0b20gdmFsaWRhdG9ycyBhbmQgdHJhbnNmb3JtZXJzLCB0byBhdm9pZCByZXBldGl0aW9uXHJcbi8vIGluIHRoZSBDb25maWcgb2JqZWN0XHJcbmNvbnN0IHYgPSB7XHJcbiAgLy8gU3BsaXRzIHN0cmluZyB2YWx1ZSBpbnRvIGVsZW1lbnRzIGluIGFuIGFycmF5LCB0cmltcyBldmVyeSBlbGVtZW50LCBjaGVja3NcclxuICAvLyBpZiBhbiBhcnJheSBpcyBjb3JyZWN0LCBpZiBpdCBpcyBlbXB0eSwgYW5kIGlmIGl0IGlzLCByZXR1cm5zIHVuZGVmaW5lZFxyXG4gIGFycmF5OiAoZmlsdGVyQXJyYXkpID0+XHJcbiAgICB6XHJcbiAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICB2YWx1ZVxyXG4gICAgICAgICAgLnNwbGl0KCcsJylcclxuICAgICAgICAgIC5tYXAoKHZhbHVlKSA9PiB2YWx1ZS50cmltKCkpXHJcbiAgICAgICAgICAuZmlsdGVyKCh2YWx1ZSkgPT4gZmlsdGVyQXJyYXkuaW5jbHVkZXModmFsdWUpKVxyXG4gICAgICApXHJcbiAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUubGVuZ3RoID8gdmFsdWUgOiB1bmRlZmluZWQpKSxcclxuXHJcbiAgLy8gQWxsb3dzIG9ubHkgdHJ1ZSwgZmFsc2UgYW5kIGNvcnJlY3RseSBwYXJzZSB0aGUgdmFsdWUgdG8gYm9vbGVhblxyXG4gIC8vIG9yIG5vIHZhbHVlIGluIHdoaWNoIGNhc2UgdGhlIHJldHVybmVkIHZhbHVlIHdpbGwgYmUgdW5kZWZpbmVkXHJcbiAgYm9vbGVhbjogKCkgPT5cclxuICAgIHpcclxuICAgICAgLmVudW0oWyd0cnVlJywgJ2ZhbHNlJywgJyddKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHZhbHVlID09PSAndHJ1ZScgOiB1bmRlZmluZWQpKSxcclxuXHJcbiAgLy8gQWxsb3dzIHBhc3NlZCB2YWx1ZXMgb3Igbm8gdmFsdWUgaW4gd2hpY2ggY2FzZSB0aGUgcmV0dXJuZWQgdmFsdWUgd2lsbFxyXG4gIC8vIGJlIHVuZGVmaW5lZFxyXG4gIGVudW06ICh2YWx1ZXMpID0+XHJcbiAgICB6XHJcbiAgICAgIC5lbnVtKFsuLi52YWx1ZXMsICcnXSlcclxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyB2YWx1ZSA6IHVuZGVmaW5lZCkpLFxyXG5cclxuICAvLyBUcmltcyB0aGUgc3RyaW5nIHZhbHVlIGFuZCBjaGVja3MgaWYgaXQgaXMgZW1wdHkgb3IgY29udGFpbnMgc3RyaW5naWZpZWRcclxuICAvLyB2YWx1ZXMgc3VjaCBhcyBmYWxzZSwgdW5kZWZpbmVkLCBudWxsLCBOYU4sIGlmIGl0IGRvZXMsIHJldHVybnMgdW5kZWZpbmVkXHJcbiAgc3RyaW5nOiAoKSA9PlxyXG4gICAgelxyXG4gICAgICAuc3RyaW5nKClcclxuICAgICAgLnRyaW0oKVxyXG4gICAgICAucmVmaW5lKFxyXG4gICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICFbJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJywgJ05hTiddLmluY2x1ZGVzKHZhbHVlKSB8fFxyXG4gICAgICAgICAgdmFsdWUgPT09ICcnLFxyXG4gICAgICAgICh2YWx1ZSkgPT4gKHtcclxuICAgICAgICAgIG1lc3NhZ2U6IGBUaGUgc3RyaW5nIGNvbnRhaW5zIGZvcmJpZGRlbiB2YWx1ZXMsIHJlY2VpdmVkICcke3ZhbHVlfSdgXHJcbiAgICAgICAgfSlcclxuICAgICAgKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHZhbHVlIDogdW5kZWZpbmVkKSksXHJcblxyXG4gIC8vIEFsbG93cyBwb3NpdGl2ZSBudW1iZXJzIG9yIG5vIHZhbHVlIGluIHdoaWNoIGNhc2UgdGhlIHJldHVybmVkIHZhbHVlIHdpbGxcclxuICAvLyBiZSB1bmRlZmluZWRcclxuICBwb3NpdGl2ZU51bTogKCkgPT5cclxuICAgIHpcclxuICAgICAgLnN0cmluZygpXHJcbiAgICAgIC50cmltKClcclxuICAgICAgLnJlZmluZShcclxuICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICB2YWx1ZSA9PT0gJycgfHwgKCFpc05hTihwYXJzZUZsb2F0KHZhbHVlKSkgJiYgcGFyc2VGbG9hdCh2YWx1ZSkgPiAwKSxcclxuICAgICAgICAodmFsdWUpID0+ICh7XHJcbiAgICAgICAgICBtZXNzYWdlOiBgVGhlIHZhbHVlIG11c3QgYmUgbnVtZXJpYyBhbmQgcG9zaXRpdmUsIHJlY2VpdmVkICcke3ZhbHVlfSdgXHJcbiAgICAgICAgfSlcclxuICAgICAgKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHBhcnNlRmxvYXQodmFsdWUpIDogdW5kZWZpbmVkKSksXHJcblxyXG4gIC8vIEFsbG93cyBub24tbmVnYXRpdmUgbnVtYmVycyBvciBubyB2YWx1ZSBpbiB3aGljaCBjYXNlIHRoZSByZXR1cm5lZCB2YWx1ZVxyXG4gIC8vIHdpbGwgYmUgdW5kZWZpbmVkXHJcbiAgbm9uTmVnYXRpdmVOdW06ICgpID0+XHJcbiAgICB6XHJcbiAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAudHJpbSgpXHJcbiAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgdmFsdWUgPT09ICcnIHx8ICghaXNOYU4ocGFyc2VGbG9hdCh2YWx1ZSkpICYmIHBhcnNlRmxvYXQodmFsdWUpID49IDApLFxyXG4gICAgICAgICh2YWx1ZSkgPT4gKHtcclxuICAgICAgICAgIG1lc3NhZ2U6IGBUaGUgdmFsdWUgbXVzdCBiZSBudW1lcmljIGFuZCBub24tbmVnYXRpdmUsIHJlY2VpdmVkICcke3ZhbHVlfSdgXHJcbiAgICAgICAgfSlcclxuICAgICAgKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHBhcnNlRmxvYXQodmFsdWUpIDogdW5kZWZpbmVkKSlcclxufTtcclxuXHJcbmV4cG9ydCBjb25zdCBDb25maWcgPSB6Lm9iamVjdCh7XHJcbiAgLy8gaGlnaGNoYXJ0c1xyXG4gIEhJR0hDSEFSVFNfVkVSU0lPTjogelxyXG4gICAgLnN0cmluZygpXHJcbiAgICAudHJpbSgpXHJcbiAgICAucmVmaW5lKFxyXG4gICAgICAodmFsdWUpID0+IC9eKGxhdGVzdHxcXGQrKFxcLlxcZCspezAsMn0pJC8udGVzdCh2YWx1ZSkgfHwgdmFsdWUgPT09ICcnLFxyXG4gICAgICAodmFsdWUpID0+ICh7XHJcbiAgICAgICAgbWVzc2FnZTogYEhJR0hDSEFSVFNfVkVSU0lPTiBtdXN0IGJlICdsYXRlc3QnLCBhIG1ham9yIHZlcnNpb24sIG9yIGluIHRoZSBmb3JtIFhYLllZLlpaLCByZWNlaXZlZCAnJHt2YWx1ZX0nYFxyXG4gICAgICB9KVxyXG4gICAgKVxyXG4gICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyB2YWx1ZSA6IHVuZGVmaW5lZCkpLFxyXG4gIEhJR0hDSEFSVFNfQ0ROX1VSTDogelxyXG4gICAgLnN0cmluZygpXHJcbiAgICAudHJpbSgpXHJcbiAgICAucmVmaW5lKFxyXG4gICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgdmFsdWUuc3RhcnRzV2l0aCgnaHR0cHM6Ly8nKSB8fFxyXG4gICAgICAgIHZhbHVlLnN0YXJ0c1dpdGgoJ2h0dHA6Ly8nKSB8fFxyXG4gICAgICAgIHZhbHVlID09PSAnJyxcclxuICAgICAgKHZhbHVlKSA9PiAoe1xyXG4gICAgICAgIG1lc3NhZ2U6IGBJbnZhbGlkIHZhbHVlIGZvciBISUdIQ0hBUlRTX0NETl9VUkwuIEl0IHNob3VsZCBzdGFydCB3aXRoIGh0dHA6Ly8gb3IgaHR0cHM6Ly8sIHJlY2VpdmVkICcke3ZhbHVlfSdgXHJcbiAgICAgIH0pXHJcbiAgICApXHJcbiAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHZhbHVlIDogdW5kZWZpbmVkKSksXHJcbiAgSElHSENIQVJUU19DT1JFX1NDUklQVFM6IHYuYXJyYXkoc2NyaXB0c05hbWVzLmNvcmUpLFxyXG4gIEhJR0hDSEFSVFNfTU9EVUxFX1NDUklQVFM6IHYuYXJyYXkoc2NyaXB0c05hbWVzLm1vZHVsZXMpLFxyXG4gIEhJR0hDSEFSVFNfSU5ESUNBVE9SX1NDUklQVFM6IHYuYXJyYXkoc2NyaXB0c05hbWVzLmluZGljYXRvcnMpLFxyXG4gIEhJR0hDSEFSVFNfRk9SQ0VfRkVUQ0g6IHYuYm9vbGVhbigpLFxyXG4gIEhJR0hDSEFSVFNfQ0FDSEVfUEFUSDogdi5zdHJpbmcoKSxcclxuICBISUdIQ0hBUlRTX0FETUlOX1RPS0VOOiB2LnN0cmluZygpLFxyXG5cclxuICAvLyBleHBvcnRcclxuICBFWFBPUlRfVFlQRTogdi5lbnVtKFsnanBlZycsICdwbmcnLCAncGRmJywgJ3N2ZyddKSxcclxuICBFWFBPUlRfQ09OU1RSOiB2LmVudW0oWydjaGFydCcsICdzdG9ja0NoYXJ0JywgJ21hcENoYXJ0JywgJ2dhbnR0Q2hhcnQnXSksXHJcbiAgRVhQT1JUX0RFRkFVTFRfSEVJR0hUOiB2LnBvc2l0aXZlTnVtKCksXHJcbiAgRVhQT1JUX0RFRkFVTFRfV0lEVEg6IHYucG9zaXRpdmVOdW0oKSxcclxuICBFWFBPUlRfREVGQVVMVF9TQ0FMRTogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIEVYUE9SVF9SQVNURVJJWkFUSU9OX1RJTUVPVVQ6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuXHJcbiAgLy8gY3VzdG9tXHJcbiAgQ1VTVE9NX0xPR0lDX0FMTE9XX0NPREVfRVhFQ1VUSU9OOiB2LmJvb2xlYW4oKSxcclxuICBDVVNUT01fTE9HSUNfQUxMT1dfRklMRV9SRVNPVVJDRVM6IHYuYm9vbGVhbigpLFxyXG5cclxuICAvLyBzZXJ2ZXJcclxuICBTRVJWRVJfRU5BQkxFOiB2LmJvb2xlYW4oKSxcclxuICBTRVJWRVJfSE9TVDogdi5zdHJpbmcoKSxcclxuICBTRVJWRVJfUE9SVDogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIFNFUlZFUl9CRU5DSE1BUktJTkc6IHYuYm9vbGVhbigpLFxyXG5cclxuICAvLyBzZXJ2ZXIgcHJveHlcclxuICBTRVJWRVJfUFJPWFlfSE9TVDogdi5zdHJpbmcoKSxcclxuICBTRVJWRVJfUFJPWFlfUE9SVDogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIFNFUlZFUl9QUk9YWV9USU1FT1VUOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcblxyXG4gIC8vIHNlcnZlciByYXRlIGxpbWl0aW5nXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfRU5BQkxFOiB2LmJvb2xlYW4oKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19NQVhfUkVRVUVTVFM6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19XSU5ET1c6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19ERUxBWTogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX1RSVVNUX1BST1hZOiB2LmJvb2xlYW4oKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX0tFWTogdi5zdHJpbmcoKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX1RPS0VOOiB2LnN0cmluZygpLFxyXG5cclxuICAvLyBzZXJ2ZXIgc3NsXHJcbiAgU0VSVkVSX1NTTF9FTkFCTEU6IHYuYm9vbGVhbigpLFxyXG4gIFNFUlZFUl9TU0xfRk9SQ0U6IHYuYm9vbGVhbigpLFxyXG4gIFNFUlZFUl9TU0xfUE9SVDogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIFNFUlZFUl9TU0xfQ0VSVF9QQVRIOiB2LnN0cmluZygpLFxyXG5cclxuICAvLyBwb29sXHJcbiAgUE9PTF9NSU5fV09SS0VSUzogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfTUFYX1dPUktFUlM6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBQT09MX1dPUktfTElNSVQ6IHYucG9zaXRpdmVOdW0oKSxcclxuICBQT09MX0FDUVVJUkVfVElNRU9VVDogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfQ1JFQVRFX1RJTUVPVVQ6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBQT09MX0RFU1RST1lfVElNRU9VVDogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfSURMRV9USU1FT1VUOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcbiAgUE9PTF9DUkVBVEVfUkVUUllfSU5URVJWQUw6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBQT09MX1JFQVBFUl9JTlRFUlZBTDogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfQkVOQ0hNQVJLSU5HOiB2LmJvb2xlYW4oKSxcclxuXHJcbiAgLy8gbG9nZ2VyXHJcbiAgTE9HR0lOR19MRVZFTDogelxyXG4gICAgLnN0cmluZygpXHJcbiAgICAudHJpbSgpXHJcbiAgICAucmVmaW5lKFxyXG4gICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgdmFsdWUgPT09ICcnIHx8XHJcbiAgICAgICAgKCFpc05hTihwYXJzZUZsb2F0KHZhbHVlKSkgJiZcclxuICAgICAgICAgIHBhcnNlRmxvYXQodmFsdWUpID49IDAgJiZcclxuICAgICAgICAgIHBhcnNlRmxvYXQodmFsdWUpIDw9IDUpLFxyXG4gICAgICAodmFsdWUpID0+ICh7XHJcbiAgICAgICAgbWVzc2FnZTogYEludmFsaWQgdmFsdWUgZm9yIExPR0dJTkdfTEVWRUwuIFdlIG9ubHkgYWNjZXB0IHZhbHVlcyBmcm9tIDAgdG8gNSBhcyBsb2dnaW5nIGxldmVscywgcmVjZWl2ZWQgJyR7dmFsdWV9J2BcclxuICAgICAgfSlcclxuICAgIClcclxuICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUgIT09ICcnID8gcGFyc2VGbG9hdCh2YWx1ZSkgOiB1bmRlZmluZWQpKSxcclxuICBMT0dHSU5HX0ZJTEU6IHYuc3RyaW5nKCksXHJcbiAgTE9HR0lOR19ERVNUOiB2LnN0cmluZygpLFxyXG5cclxuICAvLyB1aVxyXG4gIFVJX0VOQUJMRTogdi5ib29sZWFuKCksXHJcbiAgVUlfUk9VVEU6IHYuc3RyaW5nKCksXHJcblxyXG4gIC8vIG90aGVyXHJcbiAgT1RIRVJfTk9ERV9FTlY6IHYuZW51bShbJ2RldmVsb3BtZW50JywgJ3Byb2R1Y3Rpb24nLCAndGVzdCddKSxcclxuICBPVEhFUl9MSVNURU5fVE9fUFJPQ0VTU19FWElUUzogdi5ib29sZWFuKCksXHJcbiAgT1RIRVJfTk9fTE9HTzogdi5ib29sZWFuKCksXHJcbiAgT1RIRVJfSEFSRF9SRVNFVF9QQUdFOiB2LmJvb2xlYW4oKSxcclxuICBPVEhFUl9CUk9XU0VSX1NIRUxMX01PREU6IHYuYm9vbGVhbigpLFxyXG5cclxuICAvLyBkZWJ1Z2dlclxyXG4gIERFQlVHX0VOQUJMRTogdi5ib29sZWFuKCksXHJcbiAgREVCVUdfSEVBRExFU1M6IHYuYm9vbGVhbigpLFxyXG4gIERFQlVHX0RFVlRPT0xTOiB2LmJvb2xlYW4oKSxcclxuICBERUJVR19MSVNURU5fVE9fQ09OU09MRTogdi5ib29sZWFuKCksXHJcbiAgREVCVUdfRFVNUElPOiB2LmJvb2xlYW4oKSxcclxuICBERUJVR19TTE9XX01POiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcbiAgREVCVUdfREVCVUdHSU5HX1BPUlQ6IHYucG9zaXRpdmVOdW0oKSxcclxuXHJcbiAgLy8gd2Vic29ja2V0XHJcbiAgV0VCX1NPQ0tFVF9FTkFCTEU6IHYuYm9vbGVhbigpLFxyXG4gIFdFQl9TT0NLRVRfUkVDT05ORUNUOiB2LmJvb2xlYW4oKSxcclxuICBXRUJfU09DS0VUX1JFSkVDVF9VTkFVVEhPUklaRUQ6IHYuYm9vbGVhbigpLFxyXG4gIFdFQl9TT0NLRVRfUElOR19USU1FT1VUOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcbiAgV0VCX1NPQ0tFVF9SRUNPTk5FQ1RfSU5URVJWQUw6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBXRUJfU09DS0VUX1JFQ09OTkVDVF9BVFRFTVBUUzogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFdFQl9TT0NLRVRfTUVTU0FHRV9JTlRFUlZBTDogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFdFQl9TT0NLRVRfVVJMOiB2LnN0cmluZygpLFxyXG4gIFdFQl9TT0NLRVRfU0VDUkVUOiB2LnN0cmluZygpXHJcbn0pO1xyXG5cclxuZXhwb3J0IGNvbnN0IGVudnMgPSBDb25maWcucGFydGlhbCgpLnBhcnNlKHByb2Nlc3MuZW52KTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyBhcHBlbmRGaWxlLCBleGlzdHNTeW5jLCBta2RpclN5bmMgfSBmcm9tICdmcyc7XHJcblxyXG5pbXBvcnQgeyBkZWZhdWx0Q29uZmlnIH0gZnJvbSAnLi9zY2hlbWFzL2NvbmZpZy5qcyc7XHJcblxyXG4vLyBUaGUgYXZhaWxhYmxlIGNvbG9yc1xyXG5jb25zdCBjb2xvcnMgPSBbJ3JlZCcsICd5ZWxsb3cnLCAnYmx1ZScsICdncmF5JywgJ2dyZWVuJ107XHJcblxyXG4vLyBUaGUgZGVmYXVsdCBsb2dnaW5nIGNvbmZpZ1xyXG5sZXQgbG9nZ2luZyA9IHtcclxuICAvLyBGbGFncyBmb3IgbG9nZ2luZyBzdGF0dXNcclxuICB0b0NvbnNvbGU6IHRydWUsXHJcbiAgdG9GaWxlOiBmYWxzZSxcclxuICBwYXRoQ3JlYXRlZDogZmFsc2UsXHJcbiAgLy8gTG9nIGxldmVsc1xyXG4gIGxldmVsc0Rlc2M6IFtcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICdlcnJvcicsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbMF1cclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHRpdGxlOiAnd2FybmluZycsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbMV1cclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHRpdGxlOiAnbm90aWNlJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1syXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICd2ZXJib3NlJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1szXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICdiZW5jaG1hcmsnLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzRdXHJcbiAgICB9XHJcbiAgXSxcclxuICAvLyBMb2cgbGlzdGVuZXJzXHJcbiAgbGlzdGVuZXJzOiBbXVxyXG59O1xyXG5cclxuLy8gR2F0aGVyIGluaXQgbG9nZ2luZyBvcHRpb25zXHJcbmZvciAoY29uc3QgW2tleSwgb3B0aW9uXSBvZiBPYmplY3QuZW50cmllcyhkZWZhdWx0Q29uZmlnLmxvZ2dpbmcpKSB7XHJcbiAgbG9nZ2luZ1trZXldID0gb3B0aW9uLnZhbHVlO1xyXG59XHJcblxyXG4vKipcclxuICogTG9ncyB0aGUgcHJvdmlkZWQgdGV4dHMgdG8gYSBmaWxlLCBpZiBmaWxlIGxvZ2dpbmcgaXMgZW5hYmxlZC4gSXQgY3JlYXRlc1xyXG4gKiB0aGUgbmVjZXNzYXJ5IGRpcmVjdG9yeSBzdHJ1Y3R1cmUgaWYgbm90IGFscmVhZHkgY3JlYXRlZCBhbmQgYXBwZW5kcyB0aGVcclxuICogY29udGVudCwgaW5jbHVkaW5nIGFuIG9wdGlvbmFsIHByZWZpeCwgdG8gdGhlIHNwZWNpZmllZCBsb2cgZmlsZS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmdbXX0gdGV4dHMgLSBBbiBhcnJheSBvZiB0ZXh0cyB0byBiZSBsb2dnZWQuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwcmVmaXggLSBBbiBvcHRpb25hbCBwcmVmaXggdG8gYmUgYWRkZWQgdG8gZWFjaCBsb2cgZW50cnkuXHJcbiAqL1xyXG5jb25zdCBsb2dUb0ZpbGUgPSAodGV4dHMsIHByZWZpeCkgPT4ge1xyXG4gIGlmIChsb2dnaW5nLnRvRmlsZSkge1xyXG4gICAgaWYgKCFsb2dnaW5nLnBhdGhDcmVhdGVkKSB7XHJcbiAgICAgIC8vIENyZWF0ZSBpZiBkb2VzIG5vdCBleGlzdFxyXG4gICAgICAhZXhpc3RzU3luYyhsb2dnaW5nLmRlc3QpICYmIG1rZGlyU3luYyhsb2dnaW5nLmRlc3QpO1xyXG5cclxuICAgICAgLy8gV2Ugbm93IGFzc3VtZSB0aGUgcGF0aCBpcyBhdmFpbGFibGUsIGUuZy4gaXQncyB0aGUgcmVzcG9uc2liaWxpdHlcclxuICAgICAgLy8gb2YgdGhlIHVzZXIgdG8gY3JlYXRlIHRoZSBwYXRoIHdpdGggdGhlIGNvcnJlY3QgYWNjZXNzIHJpZ2h0cy5cclxuICAgICAgbG9nZ2luZy5wYXRoQ3JlYXRlZCA9IHRydWU7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQWRkIHRoZSBjb250ZW50IHRvIGEgZmlsZVxyXG4gICAgYXBwZW5kRmlsZShcclxuICAgICAgYCR7bG9nZ2luZy5kZXN0fSR7bG9nZ2luZy5maWxlfWAsXHJcbiAgICAgIFtwcmVmaXhdLmNvbmNhdCh0ZXh0cykuam9pbignICcpICsgJ1xcbicsXHJcbiAgICAgIChlcnJvcikgPT4ge1xyXG4gICAgICAgIGlmIChlcnJvcikge1xyXG4gICAgICAgICAgY29uc29sZS5sb2coYFtsb2dnZXJdIFVuYWJsZSB0byB3cml0ZSB0byBsb2cgZmlsZTogJHtlcnJvcn1gKTtcclxuICAgICAgICAgIGxvZ2dpbmcudG9GaWxlID0gZmFsc2U7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICApO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBMb2dzIGEgbWVzc2FnZS4gQWNjZXB0cyBhIHZhcmlhYmxlIGFtb3VudCBvZiBhcmd1bWVudHMuIEFyZ3VtZW50cyBhZnRlclxyXG4gKiBgbGV2ZWxgIHdpbGwgYmUgcGFzc2VkIGRpcmVjdGx5IHRvIGNvbnNvbGUubG9nLCBhbmQvb3Igd2lsbCBiZSBqb2luZWRcclxuICogYW5kIGFwcGVuZGVkIHRvIHRoZSBsb2cgZmlsZS5cclxuICpcclxuICogQHBhcmFtIHthbnl9IGFyZ3MgLSBBbiBhcnJheSBvZiBhcmd1bWVudHMgd2hlcmUgdGhlIGZpcnN0IGlzIHRoZSBsb2cgbGV2ZWxcclxuICogYW5kIHRoZSByZXN0IGFyZSBzdHJpbmdzIHRvIGJ1aWxkIGEgbWVzc2FnZSB3aXRoLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGxvZyA9ICguLi5hcmdzKSA9PiB7XHJcbiAgY29uc3QgW25ld0xldmVsLCAuLi50ZXh0c10gPSBhcmdzO1xyXG5cclxuICAvLyBDdXJyZW50IGxvZ2dpbmcgb3B0aW9uc1xyXG4gIGNvbnN0IHsgbGV2ZWwsIGxldmVsc0Rlc2MgfSA9IGxvZ2dpbmc7XHJcblxyXG4gIC8vIENoZWNrIGlmIGxvZyBsZXZlbCBpcyB3aXRoaW4gYSBjb3JyZWN0IHJhbmdlIG9yIGlzIGEgYmVuY2htYXJrIGxvZ1xyXG4gIGlmIChcclxuICAgIG5ld0xldmVsICE9PSA1ICYmXHJcbiAgICAobmV3TGV2ZWwgPT09IDAgfHwgbmV3TGV2ZWwgPiBsZXZlbCB8fCBsZXZlbCA+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+XHJcbiAgam9pbihfX2Rpcm5hbWUsIGdldE9wdGlvbnMoKS5oaWdoY2hhcnRzLmNhY2hlUGF0aCk7XHJcblxyXG5leHBvcnQgY29uc3QgZ2V0Q2FjaGUgPSAoKSA9PiBjYWNoZTtcclxuXHJcbmV4cG9ydCBjb25zdCBoaWdoY2hhcnRzID0gKCkgPT4gY2FjaGUuc291cmNlcztcclxuXHJcbmV4cG9ydCBjb25zdCB2ZXJzaW9uID0gKCkgPT4gY2FjaGUuaGNWZXJzaW9uO1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGNoZWNrQW5kVXBkYXRlQ2FjaGUsXHJcbiAgZ2V0Q2FjaGVQYXRoLFxyXG4gIHVwZGF0ZVZlcnNpb24sXHJcbiAgZ2V0Q2FjaGUsXHJcbiAgaGlnaGNoYXJ0cyxcclxuICB2ZXJzaW9uXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyogZXNsaW50LWRpc2FibGUgbm8tdW5kZWYgKi9cclxuXHJcbi8qKlxyXG4gKiBTZXR0aW5nIHRoZSBhbmltT2JqZWN0LiBDYWxsZWQgd2hlbiBpbml0aW5nIHRoZSBwYWdlLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHNldHVwSGlnaGNoYXJ0cygpIHtcclxuICBIaWdoY2hhcnRzLmFuaW1PYmplY3QgPSBmdW5jdGlvbiAoKSB7XHJcbiAgICByZXR1cm4geyBkdXJhdGlvbjogMCB9O1xyXG4gIH07XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIHRoZSBhY3R1YWwgY2hhcnQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7b2JqZWN0fSBjaGFydE9wdGlvbnMgLSBUaGUgb3B0aW9ucyBmb3IgdGhlIEhpZ2hjaGFydHMgY2hhcnQuXHJcbiAqIEBwYXJhbSB7b2JqZWN0fSBvcHRpb25zIC0gVGhlIGV4cG9ydCBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGRpc3BsYXlFcnJvcnMgLSBBIGZsYWcgaW5kaWNhdGluZyB3aGV0aGVyIHRvIGRpc3BsYXkgZXJyb3JzLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHRyaWdnZXJFeHBvcnQoY2hhcnRPcHRpb25zLCBvcHRpb25zLCBkaXNwbGF5RXJyb3JzKSB7XHJcbiAgLy8gRGlzcGxheSBlcnJvcnMgZmxhZyB0YWtlbiBmcm9tIGNoYXJ0IG9wdGlvbnMgbmFkIGRlYnVnZ2VyIG1vZHVsZVxyXG4gIHdpbmRvdy5fZGlzcGxheUVycm9ycyA9IGRpc3BsYXlFcnJvcnM7XHJcblxyXG4gIC8vIEdldCByZXF1aXJlZCBmdW5jdGlvbnNcclxuICBjb25zdCB7IGdldE9wdGlvbnMsIG1lcmdlLCBzZXRPcHRpb25zLCB3cmFwIH0gPSBIaWdoY2hhcnRzO1xyXG5cclxuICAvLyBDcmVhdGUgYSBzZXBhcmF0ZSBvYmplY3QgZm9yIGEgcG90ZW50aWFsIHNldE9wdGlvbnMgdXNhZ2VzIGluIG9yZGVyIHRvXHJcbiAgLy8gcHJldmVudCBmcm9tIHBvbGx1dGluZyBvdGhlciBleHBvcnRzIHRoYXQgY2FuIGhhcHBlbiBvbiB0aGUgc2FtZSBwYWdlXHJcbiAgSGlnaGNoYXJ0cy5zZXRPcHRpb25zT2JqID0gbWVyZ2UoZmFsc2UsIHt9LCBnZXRPcHRpb25zKCkpO1xyXG5cclxuICAvLyBUcmlnZ2VyIGN1c3RvbSBjb2RlXHJcbiAgaWYgKG9wdGlvbnMuY3VzdG9tTG9naWMuY3VzdG9tQ29kZSkge1xyXG4gICAgbmV3IEZ1bmN0aW9uKG9wdGlvbnMuY3VzdG9tTG9naWMuY3VzdG9tQ29kZSkoKTtcclxuICB9XHJcblxyXG4gIC8vIEJ5IGRlZmF1bHQgYW5pbWF0aW9uIGlzIGRpc2FibGVkXHJcbiAgY29uc3QgY2hhcnQgPSB7XHJcbiAgICBhbmltYXRpb246IGZhbHNlXHJcbiAgfTtcclxuXHJcbiAgLy8gV2hlbiBzdHJhaWdodCBpbmplY3QsIHRoZSBzaXplIGlzIHNldCB0aHJvdWdoIENTUyBvbmx5XHJcbiAgaWYgKG9wdGlvbnMuZXhwb3J0LnN0ckluaikge1xyXG4gICAgY2hhcnQuaGVpZ2h0ID0gY2hhcnRPcHRpb25zLmNoYXJ0LmhlaWdodDtcclxuICAgIGNoYXJ0LndpZHRoID0gY2hhcnRPcHRpb25zLmNoYXJ0LndpZHRoO1xyXG4gIH1cclxuXHJcbiAgLy8gTk9URTogSXMgdGhpcyB1c2VkIGZvciBhbnl0aGluZyB1c2VmdWw/XHJcbiAgd2luZG93LmlzUmVuZGVyQ29tcGxldGUgPSBmYWxzZTtcclxuICB3cmFwKEhpZ2hjaGFydHMuQ2hhcnQucHJvdG90eXBlLCAnaW5pdCcsIGZ1bmN0aW9uIChwcm9jZWVkLCB1c2VyT3B0aW9ucywgY2IpIHtcclxuICAgIC8vIE92ZXJyaWRlIHVzZXJPcHRpb25zIHdpdGggaW1hZ2UgZnJpZW5kbHkgb3B0aW9uc1xyXG4gICAgdXNlck9wdGlvbnMgPSBtZXJnZSh1c2VyT3B0aW9ucywge1xyXG4gICAgICBleHBvcnRpbmc6IHtcclxuICAgICAgICBlbmFibGVkOiBmYWxzZVxyXG4gICAgICB9LFxyXG4gICAgICBwbG90T3B0aW9uczoge1xyXG4gICAgICAgIHNlcmllczoge1xyXG4gICAgICAgICAgbGFiZWw6IHtcclxuICAgICAgICAgICAgZW5hYmxlZDogZmFsc2VcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIC8qIEV4cGVjdHMgdG9vbHRpcCBpbiB1c2VyT3B0aW9ucyB3aGVuIGZvckV4cG9ydCBpcyB0cnVlLlxyXG4gICAgICAgIGh0dHBzOi8vZ2l0aHViLmNvbS9oaWdoY2hhcnRzL2hpZ2hjaGFydHMvYmxvYi8zYWQ0MzBhMzUzYjgwNTZiOWU3NjRhYTRlNWNkNjgyOGFhNDc5ZGIyL2pzL3BhcnRzL0NoYXJ0LmpzI0wyNDFcclxuICAgICAgICAqL1xyXG4gICAgICB0b29sdGlwOiB7fVxyXG4gICAgfSk7XHJcblxyXG4gICAgKHVzZXJPcHRpb25zLnNlcmllcyB8fCBbXSkuZm9yRWFjaChmdW5jdGlvbiAoc2VyaWVzKSB7XHJcbiAgICAgIHNlcmllcy5hbmltYXRpb24gPSBmYWxzZTtcclxuICAgIH0pO1xyXG5cclxuICAgIC8vIEFkZCBmbGFnIHRvIGtub3cgaWYgY2hhcnQgcmVuZGVyIGhhcyBiZWVuIGNhbGxlZC5cclxuICAgIGlmICghd2luZG93Lm9uSGlnaGNoYXJ0c1JlbmRlcikge1xyXG4gICAgICB3aW5kb3cub25IaWdoY2hhcnRzUmVuZGVyID0gSGlnaGNoYXJ0cy5hZGRFdmVudCh0aGlzLCAncmVuZGVyJywgKCkgPT4ge1xyXG4gICAgICAgIHdpbmRvdy5pc1JlbmRlckNvbXBsZXRlID0gdHJ1ZTtcclxuICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgcHJvY2VlZC5hcHBseSh0aGlzLCBbdXNlck9wdGlvbnMsIGNiXSk7XHJcbiAgfSk7XHJcblxyXG4gIHdyYXAoSGlnaGNoYXJ0cy5TZXJpZXMucHJvdG90eXBlLCAnaW5pdCcsIGZ1bmN0aW9uIChwcm9jZWVkLCBjaGFydCwgb3B0aW9ucykge1xyXG4gICAgcHJvY2VlZC5hcHBseSh0aGlzLCBbY2hhcnQsIG9wdGlvbnNdKTtcclxuICB9KTtcclxuXHJcbiAgLy8gR2V0IHRoZSB1c2VyIG9wdGlvbnNcclxuICBjb25zdCB1c2VyT3B0aW9ucyA9IG9wdGlvbnMuZXhwb3J0LnN0cklualxyXG4gICAgPyBuZXcgRnVuY3Rpb24oYHJldHVybiAke29wdGlvbnMuZXhwb3J0LnN0ckluan1gKSgpXHJcbiAgICA6IGNoYXJ0T3B0aW9ucztcclxuXHJcbiAgLy8gTWVyZ2UgdGhlIGdsb2JhbE9wdGlvbnMsIHRoZW1lT3B0aW9ucywgb3B0aW9ucyBmcm9tIHRoZSB3cmFwcGVkXHJcbiAgLy8gc2V0T3B0aW9ucyBmdW5jdGlvbiBhbmQgdXNlciBvcHRpb25zIHRvIGNyZWF0ZSB0aGUgZmluYWwgb3B0aW9ucyBvYmplY3RcclxuICBjb25zdCBmaW5hbE9wdGlvbnMgPSBtZXJnZShcclxuICAgIGZhbHNlLFxyXG4gICAgSlNPTi5wYXJzZShvcHRpb25zLmV4cG9ydC50aGVtZU9wdGlvbnMpLFxyXG4gICAgdXNlck9wdGlvbnMsXHJcbiAgICAvLyBQbGFjZWQgaXQgaGVyZSBpbnN0ZWFkIGluIHRoZSBpbml0IGJlY2F1c2Ugb2YgdGhlIHNpemUgaXNzdWVzXHJcbiAgICB7IGNoYXJ0IH1cclxuICApO1xyXG5cclxuICBjb25zdCBmaW5hbENhbGxiYWNrID0gb3B0aW9ucy5jdXN0b21Mb2dpYy5jYWxsYmFja1xyXG4gICAgPyBuZXcgRnVuY3Rpb24oYHJldHVybiAke29wdGlvbnMuY3VzdG9tTG9naWMuY2FsbGJhY2t9YCkoKVxyXG4gICAgOiB1bmRlZmluZWQ7XHJcblxyXG4gIC8vIFNldCB0aGUgZ2xvYmFsIG9wdGlvbnMgaWYgZXhpc3RcclxuICBjb25zdCBnbG9iYWxPcHRpb25zID0gSlNPTi5wYXJzZShvcHRpb25zLmV4cG9ydC5nbG9iYWxPcHRpb25zKTtcclxuICBpZiAoZ2xvYmFsT3B0aW9ucykge1xyXG4gICAgc2V0T3B0aW9ucyhnbG9iYWxPcHRpb25zKTtcclxuICB9XHJcblxyXG4gIEhpZ2hjaGFydHNbb3B0aW9ucy5leHBvcnQuY29uc3RyIHx8ICdjaGFydCddKFxyXG4gICAgJ2NvbnRhaW5lcicsXHJcbiAgICBmaW5hbE9wdGlvbnMsXHJcbiAgICBmaW5hbENhbGxiYWNrXHJcbiAgKTtcclxuXHJcbiAgLy8gR2V0IHRoZSBjdXJyZW50IGdsb2JhbCBvcHRpb25zXHJcbiAgY29uc3QgZGVmYXVsdE9wdGlvbnMgPSBnZXRPcHRpb25zKCk7XHJcblxyXG4gIC8vIENsZWFyIGl0IGp1c3QgaW4gY2FzZSAoZS5nLiB0aGUgc2V0T3B0aW9ucyB3YXMgdXNlZCBpbiB0aGUgY3VzdG9tQ29kZSlcclxuICBmb3IgKGNvbnN0IHByb3AgaW4gZGVmYXVsdE9wdGlvbnMpIHtcclxuICAgIGlmICh0eXBlb2YgZGVmYXVsdE9wdGlvbnNbcHJvcF0gIT09ICdmdW5jdGlvbicpIHtcclxuICAgICAgZGVsZXRlIGRlZmF1bHRPcHRpb25zW3Byb3BdO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gU2V0IHRoZSBkZWZhdWx0IG9wdGlvbnMgYmFja1xyXG4gIHNldE9wdGlvbnMoSGlnaGNoYXJ0cy5zZXRPcHRpb25zT2JqKTtcclxuXHJcbiAgLy8gRW1wdHkgdGhlIGN1c3RvbSBnbG9iYWwgb3B0aW9ucyBvYmplY3RcclxuICBIaWdoY2hhcnRzLnNldE9wdGlvbnNPYmogPSB7fTtcclxufVxyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHBhdGggZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgcHVwcGV0ZWVyIGZyb20gJ3B1cHBldGVlcic7XHJcblxyXG5pbXBvcnQgeyBnZXRDYWNoZVBhdGggfSBmcm9tICcuL2NhY2hlLmpzJztcclxuaW1wb3J0IHsgZ2V0T3B0aW9ucyB9IGZyb20gJy4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgc2V0dXBIaWdoY2hhcnRzIH0gZnJvbSAnLi9oaWdoY2hhcnRzLmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IF9fZGlybmFtZSB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8vIEdldCB0aGUgdGVtcGxhdGUgZm9yIHRoZSBwYWdlXHJcbmNvbnN0IHRlbXBsYXRlID0gcmVhZEZpbGVTeW5jKF9fZGlybmFtZSArICcvdGVtcGxhdGVzL3RlbXBsYXRlLmh0bWwnLCAndXRmOCcpO1xyXG5cclxubGV0IGJyb3dzZXI7XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHRoZSBleGlzdGluZyBQdXBwZXRlZXIgYnJvd3NlciBpbnN0YW5jZS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8b2JqZWN0Pn0gQSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgUHVwcGV0ZWVyIGJyb3dzZXJcclxuICogaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgbm8gdmFsaWQgYnJvd3NlciBoYXMgYmVlblxyXG4gKiBjcmVhdGVkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldCgpIHtcclxuICBpZiAoIWJyb3dzZXIpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW2Jyb3dzZXJdIE5vIHZhbGlkIGJyb3dzZXIgaGFzIGJlZW4gY3JlYXRlZC4nKTtcclxuICB9XHJcbiAgcmV0dXJuIGJyb3dzZXI7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgUHVwcGV0ZWVyIGJyb3dzZXIgaW5zdGFuY2Ugd2l0aCB0aGUgc3BlY2lmaWVkIGFyZ3VtZW50cy5cclxuICpcclxuICogQHBhcmFtIHtBcnJheX0gcHVwcGV0ZWVyQXJncyAtIEFkZGl0aW9uYWwgYXJndW1lbnRzIGZvciBQdXBwZXRlZXIgbGF1bmNoLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxvYmplY3Q+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBQdXBwZXRlZXIgYnJvd3NlclxyXG4gKiBpbnN0YW5jZS5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiBtYXggcmV0cmllcyB0byBvcGVuIGEgYnJvd3NlclxyXG4gKiBpbnN0YW5jZSBhcmUgcmVhY2hlZCwgb3IgaWYgbm8gYnJvd3NlciBpbnN0YW5jZSBpcyBmb3VuZCBhZnRlciByZXRyaWVzLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNyZWF0ZShwdXBwZXRlZXJBcmdzKSB7XHJcbiAgLy8gR2V0IGRlYnVnIGFuZCBvdGhlciBvcHRpb25zXHJcbiAgY29uc3QgeyBkZWJ1Zywgb3RoZXIgfSA9IGdldE9wdGlvbnMoKTtcclxuXHJcbiAgLy8gR2V0IHRoZSBkZWJ1ZyBvcHRpb25zXHJcbiAgY29uc3QgeyBlbmFibGU6IGVuYWJsZWREZWJ1ZywgLi4uZGVidWdPcHRpb25zIH0gPSBkZWJ1ZztcclxuXHJcbiAgY29uc3QgbGF1bmNoT3B0aW9ucyA9IHtcclxuICAgIGhlYWRsZXNzOiBvdGhlci5icm93c2VyU2hlbGxNb2RlID8gJ3NoZWxsJyA6IHRydWUsXHJcbiAgICB1c2VyRGF0YURpcjogJy4vdG1wLycsXHJcbiAgICBhcmdzOiBwdXBwZXRlZXJBcmdzLFxyXG4gICAgaGFuZGxlU0lHSU5UOiBmYWxzZSxcclxuICAgIGhhbmRsZVNJR1RFUk06IGZhbHNlLFxyXG4gICAgaGFuZGxlU0lHSFVQOiBmYWxzZSxcclxuICAgIHdhaXRGb3JJbml0aWFsUGFnZTogZmFsc2UsXHJcbiAgICBkZWZhdWx0Vmlld3BvcnQ6IG51bGwsXHJcbiAgICAuLi4oZW5hYmxlZERlYnVnICYmIGRlYnVnT3B0aW9ucylcclxuICB9O1xyXG5cclxuICAvLyBDcmVhdGUgYSBicm93c2VyXHJcbiAgaWYgKCFicm93c2VyKSB7XHJcbiAgICBsZXQgdHJ5Q291bnQgPSAwO1xyXG5cclxuICAgIGNvbnN0IG9wZW4gPSBhc3luYyAoKSA9PiB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbYnJvd3Nlcl0gQXR0ZW1wdGluZyB0byBnZXQgYSBicm93c2VyIGluc3RhbmNlICh0cnkgJHsrK3RyeUNvdW50fSkuYFxyXG4gICAgICAgICk7XHJcbiAgICAgICAgYnJvd3NlciA9IGF3YWl0IHB1cHBldGVlci5sYXVuY2gobGF1bmNoT3B0aW9ucyk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgICAgMSxcclxuICAgICAgICAgIGVycm9yLFxyXG4gICAgICAgICAgJ1ticm93c2VyXSBGYWlsZWQgdG8gbGF1bmNoIGEgYnJvd3NlciBpbnN0YW5jZS4nXHJcbiAgICAgICAgKTtcclxuXHJcbiAgICAgICAgLy8gUmV0cnkgdG8gbGF1bmNoIGJyb3dzZXIgdW50aWwgcmVhY2hpbmcgbWF4IGF0dGVtcHRzXHJcbiAgICAgICAgaWYgKHRyeUNvdW50IDwgMjUpIHtcclxuICAgICAgICAgIGxvZygzLCBgW2Jyb3dzZXJdIFJldHJ5IHRvIG9wZW4gYSBicm93c2VyICgke3RyeUNvdW50fSBvdXQgb2YgMjUpLmApO1xyXG4gICAgICAgICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc3BvbnNlKSA9PiBzZXRUaW1lb3V0KHJlc3BvbnNlLCA0MDAwKSk7XHJcbiAgICAgICAgICBhd2FpdCBvcGVuKCk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIHRocm93IGVycm9yO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfTtcclxuXHJcbiAgICB0cnkge1xyXG4gICAgICBhd2FpdCBvcGVuKCk7XHJcblxyXG4gICAgICAvLyBTaGVsbCBtb2RlIGluZm9ybVxyXG4gICAgICBpZiAobGF1bmNoT3B0aW9ucy5oZWFkbGVzcyA9PT0gJ3NoZWxsJykge1xyXG4gICAgICAgIGxvZygzLCBgW2Jyb3dzZXJdIExhdW5jaGVkIGJyb3dzZXIgaW4gc2hlbGwgbW9kZS5gKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gRGVidWcgbW9kZSBpbmZvcm1cclxuICAgICAgaWYgKGVuYWJsZWREZWJ1Zykge1xyXG4gICAgICAgIGxvZygzLCBgW2Jyb3dzZXJdIExhdW5jaGVkIGJyb3dzZXIgaW4gZGVidWcgbW9kZS5gKTtcclxuICAgICAgfVxyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdbYnJvd3Nlcl0gTWF4aW11bSByZXRyaWVzIHRvIG9wZW4gYSBicm93c2VyIGluc3RhbmNlIHJlYWNoZWQuJ1xyXG4gICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoIWJyb3dzZXIpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbYnJvd3Nlcl0gQ2Fubm90IGZpbmQgYSBicm93c2VyIHRvIG9wZW4uJyk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gYSBicm93c2VyIHByb21pc2VcclxuICByZXR1cm4gYnJvd3NlcjtcclxufVxyXG5cclxuLyoqXHJcbiAqIENsb3NlcyB0aGUgUHVwcGV0ZWVyIGJyb3dzZXIgaW5zdGFuY2UgaWYgaXQgaXMgY29ubmVjdGVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxib29sZWFuPn0gQSBQcm9taXNlIHJlc29sdmluZyB0byB0cnVlIGFmdGVyIHRoZSBicm93c2VyXHJcbiAqIGlzIGNsb3NlZC5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjbG9zZSgpIHtcclxuICAvLyBDbG9zZSB0aGUgYnJvd3NlciB3aGVuIGNvbm5uZWN0ZWRcclxuICBpZiAoYnJvd3Nlcj8uY29ubmVjdGVkKSB7XHJcbiAgICBhd2FpdCBicm93c2VyLmNsb3NlKCk7XHJcbiAgfVxyXG4gIGxvZyg0LCAnW2Jyb3dzZXJdIENsb3NlZCB0aGUgYnJvd3Nlci4nKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYSBuZXcgUHVwcGV0ZWVyIFBhZ2Ugd2l0aGluIGFuIGV4aXN0aW5nIGJyb3dzZXIgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIElmIHRoZSBicm93c2VyIGluc3RhbmNlIGlzIG5vdCBhdmFpbGFibGUsIHJldHVybnMgZmFsc2UuXHJcbiAqXHJcbiAqIFRoZSBmdW5jdGlvbiBjcmVhdGVzIGEgbmV3IHBhZ2UsIGRpc2FibGVzIGNhY2hpbmcsIHNldHMgY29udGVudCB1c2luZ1xyXG4gKiBzZXRQYWdlQ29udGVudCgpLCBhbmQgcmV0dXJucyB0aGUgY3JlYXRlZCBQdXBwZXRlZXIgUGFnZS5cclxuICpcclxuICogQHJldHVybnMgeyhib29sZWFufG9iamVjdCl9IFJldHVybnMgZmFsc2UgaWYgdGhlIGJyb3dzZXIgaW5zdGFuY2UgaXMgbm90XHJcbiAqIGF2YWlsYWJsZSwgb3IgYSBQdXBwZXRlZXIgUGFnZSBvYmplY3QgcmVwcmVzZW50aW5nIHRoZSBuZXdseSBjcmVhdGVkIHBhZ2UuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gbmV3UGFnZSgpIHtcclxuICBpZiAoIWJyb3dzZXIpIHtcclxuICAgIHJldHVybiBmYWxzZTtcclxuICB9XHJcblxyXG4gIC8vIENyZWF0ZSBhIHBhZ2VcclxuICBjb25zdCBwYWdlID0gYXdhaXQgYnJvd3Nlci5uZXdQYWdlKCk7XHJcblxyXG4gIC8vIERpc2FibGUgY2FjaGVcclxuICBhd2FpdCBwYWdlLnNldENhY2hlRW5hYmxlZChmYWxzZSk7XHJcblxyXG4gIC8vIFNldCB0aGUgY29udGVudFxyXG4gIGF3YWl0IHNldFBhZ2VDb250ZW50KHBhZ2UpO1xyXG5cclxuICAvLyBTZXQgcGFnZSBldmVudHNcclxuICBzZXRQYWdlRXZlbnRzKHBhZ2UpO1xyXG5cclxuICByZXR1cm4gcGFnZTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENsZWFycyB0aGUgY29udGVudCBvZiBhIFB1cHBldGVlciBQYWdlIGJhc2VkIG9uIHRoZSBzcGVjaWZpZWQgbW9kZS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IHRvIGJlIGNsZWFyZWQuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gaGFyZFJlc2V0IC0gQSBmbGFnIGluZGljYXRpbmcgdGhlIHR5cGUgb2YgY2xlYXJpbmdcclxuICogdG8gYmUgcGVyZm9ybWVkLiBJZiB0cnVlLCBuYXZpZ2F0ZXMgdG8gJ2Fib3V0OmJsYW5rJyBhbmQgcmVzZXRzIGNvbnRlbnRcclxuICogYW5kIHNjcmlwdHMuIElmIGZhbHNlLCBjbGVhcnMgdGhlIGJvZHkgY29udGVudCBieSBzZXR0aW5nIGEgcHJlZGVmaW5lZCBIVE1MXHJcbiAqIHN0cnVjdHVyZS5cclxuICpcclxuICogQHRocm93cyB7RXJyb3J9IExvZ3MgdGhyb3duIGVycm9yIGlmIGNsZWFyaW5nIHRoZSBwYWdlIGNvbnRlbnQgZmFpbHMuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY2xlYXJQYWdlKHBhZ2UsIGhhcmRSZXNldCA9IGZhbHNlKSB7XHJcbiAgdHJ5IHtcclxuICAgIGlmICghcGFnZS5pc0Nsb3NlZCgpKSB7XHJcbiAgICAgIGlmIChoYXJkUmVzZXQpIHtcclxuICAgICAgICAvLyBOYXZpZ2F0ZSB0byBhYm91dDpibGFua1xyXG4gICAgICAgIGF3YWl0IHBhZ2UuZ290bygnYWJvdXQ6YmxhbmsnLCB7IHdhaXRVbnRpbDogJ2RvbWNvbnRlbnRsb2FkZWQnIH0pO1xyXG5cclxuICAgICAgICAvLyBTZXQgdGhlIGNvbnRlbnQgYW5kIGFuZCBzY3JpcHRzIGFnYWluXHJcbiAgICAgICAgYXdhaXQgc2V0UGFnZUNvbnRlbnQocGFnZSk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgLy8gQ2xlYXIgYm9keSBjb250ZW50XHJcbiAgICAgICAgYXdhaXQgcGFnZS5ldmFsdWF0ZSgoKSA9PiB7XHJcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LmlubmVySFRNTCA9XHJcbiAgICAgICAgICAgICc8ZGl2IGlkPVwiY2hhcnQtY29udGFpbmVyXCI+PGRpdiBpZD1cImNvbnRhaW5lclwiPjwvZGl2PjwvZGl2Pic7XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAyLFxyXG4gICAgICBlcnJvcixcclxuICAgICAgJ1ticm93c2VyXSBDb3VsZCBub3QgY2xlYXIgdGhlIGNvbnRlbnQgb2YgdGhlIHBhZ2UuJ1xyXG4gICAgKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBBZGRzIGN1c3RvbSBKUyBhbmQgQ1NTIHJlc291cmNlcyB0byBhIFB1cHBldGVlciBQYWdlIGJhc2VkIG9uIHRoZSBzcGVjaWZpZWRcclxuICogb3B0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IHRvIHdoaWNoIHJlc291cmNlcyB3aWxsIGJlXHJcbiAqIGFkZGVkLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIEFsbCBvcHRpb25zIGFuZCBjb25maWd1cmF0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxBcnJheTxPYmplY3Q+Pn0gLSBQcm9taXNlIHJlc29sdmluZyB0byBhbiBhcnJheSBvZiBpbmplY3RlZFxyXG4gKiByZXNvdXJjZXMuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gYWRkUGFnZVJlc291cmNlcyhwYWdlLCBvcHRpb25zKSB7XHJcbiAgLy8gSW5qZWN0ZWQgcmVzb3VyY2VzIGFycmF5XHJcbiAgY29uc3QgaW5qZWN0ZWRSZXNvdXJjZXMgPSBbXTtcclxuXHJcbiAgLy8gVXNlIHJlc291cmNlc1xyXG4gIGNvbnN0IHJlc291cmNlcyA9IG9wdGlvbnMuY3VzdG9tTG9naWMucmVzb3VyY2VzO1xyXG4gIGlmIChyZXNvdXJjZXMpIHtcclxuICAgIGNvbnN0IGluamVjdGVkSnMgPSBbXTtcclxuXHJcbiAgICAvLyBMb2FkIGN1c3RvbSBKUyBjb2RlXHJcbiAgICBpZiAocmVzb3VyY2VzLmpzKSB7XHJcbiAgICAgIGluamVjdGVkSnMucHVzaCh7XHJcbiAgICAgICAgY29udGVudDogcmVzb3VyY2VzLmpzXHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIExvYWQgc2NyaXB0cyBmcm9tIGFsbCBjdXN0b20gZmlsZXNcclxuICAgIGlmIChyZXNvdXJjZXMuZmlsZXMpIHtcclxuICAgICAgZm9yIChjb25zdCBmaWxlIG9mIHJlc291cmNlcy5maWxlcykge1xyXG4gICAgICAgIGNvbnN0IGlzTG9jYWwgPSAhZmlsZS5zdGFydHNXaXRoKCdodHRwJykgPyB0cnVlIDogZmFsc2U7XHJcblxyXG4gICAgICAgIC8vIEFkZCBlYWNoIGN1c3RvbSBzY3JpcHQgZnJvbSByZXNvdXJjZXMnIGZpbGVzXHJcbiAgICAgICAgaW5qZWN0ZWRKcy5wdXNoKFxyXG4gICAgICAgICAgaXNMb2NhbFxyXG4gICAgICAgICAgICA/IHtcclxuICAgICAgICAgICAgICAgIGNvbnRlbnQ6IHJlYWRGaWxlU3luYyhmaWxlLCAndXRmOCcpXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICA6IHtcclxuICAgICAgICAgICAgICAgIHVybDogZmlsZVxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgZm9yIChjb25zdCBqc1Jlc291cmNlIG9mIGluamVjdGVkSnMpIHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBpbmplY3RlZFJlc291cmNlcy5wdXNoKGF3YWl0IHBhZ2UuYWRkU2NyaXB0VGFnKGpzUmVzb3VyY2UpKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbZXhwb3J0XSBUaGUgSlMgcmVzb3VyY2UgY2Fubm90IGJlIGxvYWRlZC5gKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gICAgaW5qZWN0ZWRKcy5sZW5ndGggPSAwO1xyXG5cclxuICAgIC8vIExvYWQgQ1NTXHJcbiAgICBjb25zdCBpbmplY3RlZENzcyA9IFtdO1xyXG4gICAgaWYgKHJlc291cmNlcy5jc3MpIHtcclxuICAgICAgbGV0IGNzc0ltcG9ydHMgPSByZXNvdXJjZXMuY3NzLm1hdGNoKC9AaW1wb3J0XFxzKihbXjtdKik7L2cpO1xyXG4gICAgICBpZiAoY3NzSW1wb3J0cykge1xyXG4gICAgICAgIC8vIEhhbmRsZSBjc3Mgc2VjdGlvblxyXG4gICAgICAgIGZvciAobGV0IGNzc0ltcG9ydFBhdGggb2YgY3NzSW1wb3J0cykge1xyXG4gICAgICAgICAgaWYgKGNzc0ltcG9ydFBhdGgpIHtcclxuICAgICAgICAgICAgY3NzSW1wb3J0UGF0aCA9IGNzc0ltcG9ydFBhdGhcclxuICAgICAgICAgICAgICAucmVwbGFjZSgndXJsKCcsICcnKVxyXG4gICAgICAgICAgICAgIC5yZXBsYWNlKCdAaW1wb3J0JywgJycpXHJcbiAgICAgICAgICAgICAgLnJlcGxhY2UoL1wiL2csICcnKVxyXG4gICAgICAgICAgICAgIC5yZXBsYWNlKC8nL2csICcnKVxyXG4gICAgICAgICAgICAgIC5yZXBsYWNlKC87LywgJycpXHJcbiAgICAgICAgICAgICAgLnJlcGxhY2UoL1xcKS9nLCAnJylcclxuICAgICAgICAgICAgICAudHJpbSgpO1xyXG5cclxuICAgICAgICAgICAgLy8gQWRkIGVhY2ggY3VzdG9tIGNzcyBmcm9tIHJlc291cmNlc1xyXG4gICAgICAgICAgICBpZiAoY3NzSW1wb3J0UGF0aC5zdGFydHNXaXRoKCdodHRwJykpIHtcclxuICAgICAgICAgICAgICBpbmplY3RlZENzcy5wdXNoKHtcclxuICAgICAgICAgICAgICAgIHVybDogY3NzSW1wb3J0UGF0aFxyXG4gICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICB9IGVsc2UgaWYgKG9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dGaWxlUmVzb3VyY2VzKSB7XHJcbiAgICAgICAgICAgICAgaW5qZWN0ZWRDc3MucHVzaCh7XHJcbiAgICAgICAgICAgICAgICBwYXRoOiBwYXRoLmpvaW4oX19kaXJuYW1lLCBjc3NJbXBvcnRQYXRoKVxyXG4gICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBUaGUgcmVzdCBvZiB0aGUgQ1NTIHNlY3Rpb24gd2lsbCBiZSBjb250ZW50IGJ5IG5vd1xyXG4gICAgICBpbmplY3RlZENzcy5wdXNoKHtcclxuICAgICAgICBjb250ZW50OiByZXNvdXJjZXMuY3NzLnJlcGxhY2UoL0BpbXBvcnRcXHMqKFteO10qKTsvZywgJycpIHx8ICcgJ1xyXG4gICAgICB9KTtcclxuXHJcbiAgICAgIGZvciAoY29uc3QgY3NzUmVzb3VyY2Ugb2YgaW5qZWN0ZWRDc3MpIHtcclxuICAgICAgICB0cnkge1xyXG4gICAgICAgICAgaW5qZWN0ZWRSZXNvdXJjZXMucHVzaChhd2FpdCBwYWdlLmFkZFN0eWxlVGFnKGNzc1Jlc291cmNlKSk7XHJcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgYFtleHBvcnRdIFRoZSBDU1MgcmVzb3VyY2UgY2Fubm90IGJlIGxvYWRlZC5gKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgICAgaW5qZWN0ZWRDc3MubGVuZ3RoID0gMDtcclxuICAgIH1cclxuICB9XHJcbiAgcmV0dXJuIGluamVjdGVkUmVzb3VyY2VzO1xyXG59XHJcblxyXG4vKipcclxuICogQ2xlYXJzIG91dCBhbGwgc3RhdGUgc2V0IG9uIHRoZSBwYWdlIHdpdGggYWRkU2NyaXB0VGFnL2FkZFN0eWxlVGFnLiBSZW1vdmVzXHJcbiAqIGluamVjdGVkIHJlc291cmNlcyBhbmQgcmVzZXRzIENTUyBhbmQgc2NyaXB0IHRhZ3Mgb24gdGhlIHBhZ2UuIEFkZGl0aW9uYWxseSxcclxuICogaXQgZGVzdHJveXMgcHJldmlvdXNseSBleGlzdGluZyBjaGFydHMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gVGhlIFB1cHBldGVlciBQYWdlIG9iamVjdCBmcm9tIHdoaWNoIHJlc291cmNlcyB3aWxsXHJcbiAqIGJlIGNsZWFyZWQuXHJcbiAqIEBwYXJhbSB7QXJyYXk8T2JqZWN0Pn0gaW5qZWN0ZWRSZXNvdXJjZXMgLSBBcnJheSBvZiBpbmplY3RlZCByZXNvdXJjZXNcclxuICogdG8gYmUgY2xlYXJlZC5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjbGVhclBhZ2VSZXNvdXJjZXMocGFnZSwgaW5qZWN0ZWRSZXNvdXJjZXMpIHtcclxuICBmb3IgKGNvbnN0IHJlc291cmNlIG9mIGluamVjdGVkUmVzb3VyY2VzKSB7XHJcbiAgICBhd2FpdCByZXNvdXJjZS5kaXNwb3NlKCk7XHJcbiAgfVxyXG5cclxuICAvLyBEZXN0cm95IG9sZCBjaGFydHMgYWZ0ZXIgZXhwb3J0IGlzIGRvbmUgYW5kIHJlc2V0IGFsbCBDU1MgYW5kIHNjcmlwdCB0YWdzXHJcbiAgYXdhaXQgcGFnZS5ldmFsdWF0ZSgoKSA9PiB7XHJcbiAgICAvLyBXZSBhcmUgbm90IGd1YXJhbnRlZWQgdGhhdCBIaWdoY2hhcnRzIGlzIGxvYWRlZCwgZSxnLCB3aGVuIGRvaW5nIFNWR1xyXG4gICAgLy8gZXhwb3J0c1xyXG4gICAgaWYgKHR5cGVvZiBIaWdoY2hhcnRzICE9PSAndW5kZWZpbmVkJykge1xyXG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgY29uc3Qgb2xkQ2hhcnRzID0gSGlnaGNoYXJ0cy5jaGFydHM7XHJcblxyXG4gICAgICAvLyBDaGVjayBpbiBhbnkgYWxyZWFkeSBleGlzdGluZyBjaGFydHNcclxuICAgICAgaWYgKEFycmF5LmlzQXJyYXkob2xkQ2hhcnRzKSAmJiBvbGRDaGFydHMubGVuZ3RoKSB7XHJcbiAgICAgICAgLy8gRGVzdHJveSBvbGQgY2hhcnRzXHJcbiAgICAgICAgZm9yIChjb25zdCBvbGRDaGFydCBvZiBvbGRDaGFydHMpIHtcclxuICAgICAgICAgIG9sZENoYXJ0ICYmIG9sZENoYXJ0LmRlc3Ryb3koKTtcclxuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgICAgSGlnaGNoYXJ0cy5jaGFydHMuc2hpZnQoKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgIGNvbnN0IFsuLi5zY3JpcHRzVG9SZW1vdmVdID0gZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ3NjcmlwdCcpO1xyXG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICBjb25zdCBbLCAuLi5zdHlsZXNUb1JlbW92ZV0gPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnc3R5bGUnKTtcclxuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgY29uc3QgWy4uLmxpbmtzVG9SZW1vdmVdID0gZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ2xpbmsnKTtcclxuXHJcbiAgICAvLyBSZW1vdmUgdGFnc1xyXG4gICAgZm9yIChjb25zdCBlbGVtZW50IG9mIFtcclxuICAgICAgLi4uc2NyaXB0c1RvUmVtb3ZlLFxyXG4gICAgICAuLi5zdHlsZXNUb1JlbW92ZSxcclxuICAgICAgLi4ubGlua3NUb1JlbW92ZVxyXG4gICAgXSkge1xyXG4gICAgICBlbGVtZW50LnJlbW92ZSgpO1xyXG4gICAgfVxyXG4gIH0pO1xyXG59XHJcblxyXG4vKipcclxuICogU2V0cyB0aGUgY29udGVudCBmb3IgYSBQdXBwZXRlZXIgUGFnZSB1c2luZyBhIHByZWRlZmluZWQgdGVtcGxhdGVcclxuICogYW5kIGFkZGl0aW9uYWwgc2NyaXB0cy4gQWxzbywgc2V0cyB0aGUgcGFnZWVycm9yIGluIG9yZGVyIHRvIGNhdGNoXHJcbiAqIGFuZCBkaXNwbGF5IGVycm9ycyBmcm9tIHRoZSB3aW5kb3cgY29udGV4dC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IGZvciB3aGljaCB0aGUgY29udGVudFxyXG4gKiBpcyBiZWluZyBzZXQuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBzZXRQYWdlQ29udGVudChwYWdlKSB7XHJcbiAgYXdhaXQgcGFnZS5zZXRDb250ZW50KHRlbXBsYXRlLCB7IHdhaXRVbnRpbDogJ2RvbWNvbnRlbnRsb2FkZWQnIH0pO1xyXG5cclxuICAvLyBBZGQgYWxsIHJlZ2lzdGVyZWQgSGlnY2hhcnRzIHNjcmlwdHMsIHF1aXRlIGRlbWFuZGluZ1xyXG4gIGF3YWl0IHBhZ2UuYWRkU2NyaXB0VGFnKHsgcGF0aDogYCR7Z2V0Q2FjaGVQYXRoKCl9L3NvdXJjZXMuanNgIH0pO1xyXG5cclxuICAvLyBTZXQgdGhlIGluaXRpYWwgYW5pbU9iamVjdFxyXG4gIGF3YWl0IHBhZ2UuZXZhbHVhdGUoc2V0dXBIaWdoY2hhcnRzKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFNldCBldmVudHMgZm9yIGEgUHVwcGV0ZWVyIFBhZ2UuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gVGhlIFB1cHBldGVlciBQYWdlIG9iamVjdCB0byBzZXQgZXZlbnRzIHRvLlxyXG4gKi9cclxuZnVuY3Rpb24gc2V0UGFnZUV2ZW50cyhwYWdlKSB7XHJcbiAgLy8gR2V0IGRlYnVnIG9wdGlvbnNcclxuICBjb25zdCB7IGRlYnVnIH0gPSBnZXRPcHRpb25zKCk7XHJcblxyXG4gIC8vIFNldCB0aGUgY29uc29sZSBsaXN0ZW5lciwgaWYgbmVlZGVkXHJcbiAgaWYgKGRlYnVnLmVuYWJsZSAmJiBkZWJ1Zy5saXN0ZW5Ub0NvbnNvbGUpIHtcclxuICAgIHBhZ2Uub24oJ2NvbnNvbGUnLCAobWVzc2FnZSkgPT4ge1xyXG4gICAgICBjb25zb2xlLmxvZyhgW2RlYnVnXSAke21lc3NhZ2UudGV4dCgpfWApO1xyXG4gICAgfSk7XHJcbiAgfVxyXG5cclxuICAvLyBTZXQgdGhlIHBhZ2VlcnJvciBsaXN0ZW5lclxyXG4gIHBhZ2Uub24oJ3BhZ2VlcnJvcicsIGFzeW5jIChlcnJvcikgPT4ge1xyXG4gICAgLy8gVE9ETzogQ29uc2lkZXIgYWRkaW5nIGEgc3dpdGNoIGhlcmUgdGhhdCB0dXJucyBvbiBsb2coMCkgbG9nZ2luZ1xyXG4gICAgLy8gb24gcGFnZSBlcnJvcnMuXHJcbiAgICBhd2FpdCBwYWdlLiRldmFsKFxyXG4gICAgICAnI2NvbnRhaW5lcicsXHJcbiAgICAgIChlbGVtZW50LCBlcnJvck1lc3NhZ2UpID0+IHtcclxuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICBpZiAod2luZG93Ll9kaXNwbGF5RXJyb3JzKSB7XHJcbiAgICAgICAgICBlbGVtZW50LmlubmVySFRNTCA9IGVycm9yTWVzc2FnZTtcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIGA8aDE+Q2hhcnQgaW5wdXQgZGF0YSBlcnJvcjogPC9oMT4ke2Vycm9yLnRvU3RyaW5nKCl9YFxyXG4gICAgKTtcclxuICB9KTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGdldCxcclxuICBjcmVhdGUsXHJcbiAgY2xvc2UsXHJcbiAgbmV3UGFnZSxcclxuICBjbGVhclBhZ2UsXHJcbiAgYWRkUGFnZVJlc291cmNlcyxcclxuICBjbGVhclBhZ2VSZXNvdXJjZXNcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyBhZGRQYWdlUmVzb3VyY2VzLCBjbGVhclBhZ2VSZXNvdXJjZXMgfSBmcm9tICcuL2Jyb3dzZXIuanMnO1xyXG5pbXBvcnQgeyBnZXRDYWNoZSB9IGZyb20gJy4vY2FjaGUuanMnO1xyXG5pbXBvcnQgeyB0cmlnZ2VyRXhwb3J0IH0gZnJvbSAnLi9oaWdoY2hhcnRzLmpzJztcclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5cclxuaW1wb3J0IHN2Z1RlbXBsYXRlIGZyb20gJy4vLi4vdGVtcGxhdGVzL3N2Z19leHBvcnQvc3ZnX2V4cG9ydC5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyB0aGUgY2xpcHBpbmcgcmVnaW9uIGNvb3JkaW5hdGVzIG9mIHRoZSBzcGVjaWZpZWQgcGFnZSBlbGVtZW50IHdpdGhcclxuICogdGhlIGlkICdjaGFydC1jb250YWluZXInLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gYW4gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogeCwgeSwgd2lkdGgsIGFuZCBoZWlnaHQgcHJvcGVydGllcy5cclxuICovXHJcbmNvbnN0IGdldENsaXBSZWdpb24gPSAocGFnZSkgPT5cclxuICBwYWdlLiRldmFsKCcjY2hhcnQtY29udGFpbmVyJywgKGVsZW1lbnQpID0+IHtcclxuICAgIGNvbnN0IHsgeCwgeSwgd2lkdGgsIGhlaWdodCB9ID0gZWxlbWVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcclxuICAgIHJldHVybiB7XHJcbiAgICAgIHgsXHJcbiAgICAgIHksXHJcbiAgICAgIHdpZHRoLFxyXG4gICAgICBoZWlnaHQ6IE1hdGgudHJ1bmMoaGVpZ2h0ID4gMSA/IGhlaWdodCA6IDUwMClcclxuICAgIH07XHJcbiAgfSk7XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhbiBpbWFnZSB1c2luZyBQdXBwZXRlZXIncyBwYWdlIHNjcmVlbnNob3QgZnVuY3Rpb25hbGl0eSB3aXRoXHJcbiAqIHNwZWNpZmllZCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICogQHBhcmFtIHtzdHJpbmd9IHR5cGUgLSBJbWFnZSB0eXBlLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gZW5jb2RpbmcgLSBJbWFnZSBlbmNvZGluZy5cclxuICogQHBhcmFtIHtPYmplY3R9IGNsaXAgLSBDbGlwcGluZyByZWdpb24gY29vcmRpbmF0ZXMuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSByYXN0ZXJpemF0aW9uVGltZW91dCAtIFRpbWVvdXQgZm9yIHJhc3Rlcml6YXRpb25cclxuICogaW4gbWlsbGlzZWNvbmRzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxCdWZmZXI+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgaW1hZ2UgYnVmZmVyIG9yIHJlamVjdGluZ1xyXG4gKiB3aXRoIGFuIEV4cG9ydEVycm9yIGZvciB0aW1lb3V0LlxyXG4gKi9cclxuY29uc3QgY3JlYXRlSW1hZ2UgPSAocGFnZSwgdHlwZSwgZW5jb2RpbmcsIGNsaXAsIHJhc3Rlcml6YXRpb25UaW1lb3V0KSA9PlxyXG4gIFByb21pc2UucmFjZShbXHJcbiAgICBwYWdlLnNjcmVlbnNob3Qoe1xyXG4gICAgICB0eXBlLFxyXG4gICAgICBlbmNvZGluZyxcclxuICAgICAgY2xpcCxcclxuICAgICAgY2FwdHVyZUJleW9uZFZpZXdwb3J0OiB0cnVlLFxyXG4gICAgICBmdWxsUGFnZTogZmFsc2UsXHJcbiAgICAgIG9wdGltaXplRm9yU3BlZWQ6IHRydWUsXHJcbiAgICAgIC4uLih0eXBlICE9PSAncG5nJyA/IHsgcXVhbGl0eTogODAgfSA6IHt9KSxcclxuXHJcbiAgICAgIC8vICM0NDcsICM0NjMgLSBhbHdheXMgcmVuZGVyIG9uIGEgdHJhbnNwYXJlbnQgcGFnZSBpZiB0aGUgZXhwZWN0ZWQgdHlwZVxyXG4gICAgICAvLyBmb3JtYXQgaXMgUE5HXHJcbiAgICAgIG9taXRCYWNrZ3JvdW5kOiB0eXBlID09ICdwbmcnXHJcbiAgICB9KSxcclxuICAgIG5ldyBQcm9taXNlKChfcmVzb2x2ZSwgcmVqZWN0KSA9PlxyXG4gICAgICBzZXRUaW1lb3V0KFxyXG4gICAgICAgICgpID0+IHJlamVjdChuZXcgRXhwb3J0RXJyb3IoJ1Jhc3Rlcml6YXRpb24gdGltZW91dCcpKSxcclxuICAgICAgICByYXN0ZXJpemF0aW9uVGltZW91dCB8fCAxNTAwXHJcbiAgICAgIClcclxuICAgIClcclxuICBdKTtcclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgUERGIHVzaW5nIFB1cHBldGVlcidzIHBhZ2UgcGRmIGZ1bmN0aW9uYWxpdHkgd2l0aCBzcGVjaWZpZWRcclxuICogb3B0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBoZWlnaHQgLSBQREYgaGVpZ2h0LlxyXG4gKiBAcGFyYW0ge251bWJlcn0gd2lkdGggLSBQREYgd2lkdGguXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBlbmNvZGluZyAtIFBERiBlbmNvZGluZy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8QnVmZmVyPn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIFBERiBidWZmZXIuXHJcbiAqL1xyXG5jb25zdCBjcmVhdGVQREYgPSBhc3luYyAoXHJcbiAgcGFnZSxcclxuICBoZWlnaHQsXHJcbiAgd2lkdGgsXHJcbiAgZW5jb2RpbmcsXHJcbiAgcmFzdGVyaXphdGlvblRpbWVvdXRcclxuKSA9PiB7XHJcbiAgYXdhaXQgcGFnZS5lbXVsYXRlTWVkaWFUeXBlKCdzY3JlZW4nKTtcclxuICByZXR1cm4gUHJvbWlzZS5yYWNlKFtcclxuICAgIHBhZ2UucGRmKHtcclxuICAgICAgLy8gVGhpcyB3aWxsIHJlbW92ZSBhbiBleHRyYSBlbXB0eSBwYWdlIGluIFBERiBleHBvcnRzXHJcbiAgICAgIGhlaWdodDogaGVpZ2h0ICsgMSxcclxuICAgICAgd2lkdGgsXHJcbiAgICAgIGVuY29kaW5nXHJcbiAgICB9KSxcclxuICAgIG5ldyBQcm9taXNlKChfcmVzb2x2ZSwgcmVqZWN0KSA9PlxyXG4gICAgICBzZXRUaW1lb3V0KFxyXG4gICAgICAgICgpID0+IHJlamVjdChuZXcgRXhwb3J0RXJyb3IoJ1Jhc3Rlcml6YXRpb24gdGltZW91dCcpKSxcclxuICAgICAgICByYXN0ZXJpemF0aW9uVGltZW91dCB8fCAxNTAwXHJcbiAgICAgIClcclxuICAgIClcclxuICBdKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGFuIFNWRyBzdHJpbmcgYnkgZXZhbHVhdGluZyB0aGUgb3V0ZXJIVE1MIG9mIHRoZSBmaXJzdCAnc3ZnJyBlbGVtZW50XHJcbiAqIGluc2lkZSBhbiBlbGVtZW50IHdpdGggdGhlIGlkICdjb250YWluZXInLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIFNWRyBzdHJpbmcuXHJcbiAqL1xyXG5jb25zdCBjcmVhdGVTVkcgPSAocGFnZSkgPT5cclxuICBwYWdlLiRldmFsKCcjY29udGFpbmVyIHN2ZzpmaXJzdC1vZi10eXBlJywgKGVsZW1lbnQpID0+IGVsZW1lbnQub3V0ZXJIVE1MKTtcclxuXHJcbi8qKlxyXG4gKiBTZXRzIHRoZSBzcGVjaWZpZWQgY2hhcnQgYW5kIG9wdGlvbnMgYXMgY29uZmlndXJhdGlvbiBpbnRvIHRoZSB0cmlnZ2VyRXhwb3J0XHJcbiAqIGZ1bmN0aW9uIHdpdGhpbiB0aGUgd2luZG93IGNvbnRleHQgdXNpbmcgcGFnZS5ldmFsdWF0ZS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7YW55fSBjaGFydCAtIFRoZSBjaGFydCBvYmplY3QgdG8gYmUgY29uZmlndXJlZC5cclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBDb25maWd1cmF0aW9uIG9wdGlvbnMgZm9yIHRoZSBjaGFydC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IFByb21pc2UgcmVzb2x2aW5nIGFmdGVyIHRoZSBjb25maWd1cmF0aW9uIGlzIHNldC5cclxuICovXHJcbmNvbnN0IHNldEFzQ29uZmlnID0gYXN5bmMgKHBhZ2UsIGNoYXJ0LCBvcHRpb25zLCBkaXNwbGF5RXJyb3JzKSA9PlxyXG4gIHBhZ2UuZXZhbHVhdGUodHJpZ2dlckV4cG9ydCwgY2hhcnQsIG9wdGlvbnMsIGRpc3BsYXlFcnJvcnMpO1xyXG5cclxuLyoqXHJcbiAqIEV4cG9ydHMgdG8gYSBjaGFydCBmcm9tIGEgcGFnZSB1c2luZyBQdXBwZXRlZXIuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge2FueX0gY2hhcnQgLSBUaGUgY2hhcnQgb2JqZWN0IG9yIFNWRyBjb25maWd1cmF0aW9uIHRvIGJlIGV4cG9ydGVkLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIEV4cG9ydCBvcHRpb25zIGFuZCBjb25maWd1cmF0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmcgfCBCdWZmZXIgfCBFeHBvcnRFcnJvcj59IFByb21pc2UgcmVzb2x2aW5nIHRvXHJcbiAqIHRoZSBleHBvcnRlZCBkYXRhIG9yIHJlamVjdGluZyB3aXRoIGFuIEV4cG9ydEVycm9yLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgYXN5bmMgKHBhZ2UsIGNoYXJ0LCBvcHRpb25zKSA9PiB7XHJcbiAgLy8gSW5qZWN0ZWQgcmVzb3VyY2VzIGFycmF5IChhZGRpdGlvbmFsIEpTIGFuZCBDU1MpXHJcbiAgbGV0IGluamVjdGVkUmVzb3VyY2VzID0gW107XHJcblxyXG4gIHRyeSB7XHJcbiAgICBsb2coNCwgJ1tleHBvcnRdIERldGVybWluaW5nIGV4cG9ydCBwYXRoLicpO1xyXG5cclxuICAgIGNvbnN0IGV4cG9ydE9wdGlvbnMgPSBvcHRpb25zLmV4cG9ydDtcclxuXHJcbiAgICAvLyBEZWNpZGUgd2hldGhlciBkaXNwbGF5IGVycm9yIG9yIGRlYmJ1Z2VyIHdyYXBwZXIgYXJvdW5kIGl0XHJcbiAgICBjb25zdCBkaXNwbGF5RXJyb3JzID1cclxuICAgICAgZXhwb3J0T3B0aW9ucz8ub3B0aW9ucz8uY2hhcnQ/LmRpc3BsYXlFcnJvcnMgJiZcclxuICAgICAgZ2V0Q2FjaGUoKS5hY3RpdmVNYW5pZmVzdC5tb2R1bGVzLmRlYnVnZ2VyO1xyXG5cclxuICAgIGxldCBpc1NWRztcclxuICAgIGlmIChcclxuICAgICAgY2hhcnQuaW5kZXhPZiAmJlxyXG4gICAgICAoY2hhcnQuaW5kZXhPZignPHN2ZycpID49IDAgfHwgY2hhcnQuaW5kZXhPZignPD94bWwnKSA+PSAwKVxyXG4gICAgKSB7XHJcbiAgICAgIC8vIFNWRyBpbnB1dCBoYW5kbGluZ1xyXG4gICAgICBsb2coNCwgJ1tleHBvcnRdIFRyZWF0aW5nIGFzIFNWRy4nKTtcclxuXHJcbiAgICAgIC8vIElmIGlucHV0IGlzIGFsc28gU1ZHLCBqdXN0IHJldHVybiBpdFxyXG4gICAgICBpZiAoZXhwb3J0T3B0aW9ucy50eXBlID09PSAnc3ZnJykge1xyXG4gICAgICAgIHJldHVybiBjaGFydDtcclxuICAgICAgfVxyXG5cclxuICAgICAgaXNTVkcgPSB0cnVlO1xyXG4gICAgICBhd2FpdCBwYWdlLnNldENvbnRlbnQoc3ZnVGVtcGxhdGUoY2hhcnQpLCB7XHJcbiAgICAgICAgd2FpdFVudGlsOiAnZG9tY29udGVudGxvYWRlZCdcclxuICAgICAgfSk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBKU09OIGNvbmZpZyBoYW5kbGluZ1xyXG4gICAgICBsb2coNCwgJ1tleHBvcnRdIFRyZWF0aW5nIGFzIGNvbmZpZy4nKTtcclxuXHJcbiAgICAgIC8vIE5lZWQgdG8gcGVyZm9ybSBzdHJhaWdodCBpbmplY3RcclxuICAgICAgaWYgKGV4cG9ydE9wdGlvbnMuc3RySW5qKSB7XHJcbiAgICAgICAgLy8gSW5qZWN0aW9uIGJhc2VkIGNvbmZpZ3VyYXRpb24gZXhwb3J0XHJcbiAgICAgICAgYXdhaXQgc2V0QXNDb25maWcoXHJcbiAgICAgICAgICBwYWdlLFxyXG4gICAgICAgICAge1xyXG4gICAgICAgICAgICBjaGFydDoge1xyXG4gICAgICAgICAgICAgIGhlaWdodDogZXhwb3J0T3B0aW9ucy5oZWlnaHQsXHJcbiAgICAgICAgICAgICAgd2lkdGg6IGV4cG9ydE9wdGlvbnMud2lkdGhcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSxcclxuICAgICAgICAgIG9wdGlvbnMsXHJcbiAgICAgICAgICBkaXNwbGF5RXJyb3JzXHJcbiAgICAgICAgKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICAvLyBCYXNpYyBjb25maWd1cmF0aW9uIGV4cG9ydFxyXG4gICAgICAgIGNoYXJ0LmNoYXJ0LmhlaWdodCA9IGV4cG9ydE9wdGlvbnMuaGVpZ2h0O1xyXG4gICAgICAgIGNoYXJ0LmNoYXJ0LndpZHRoID0gZXhwb3J0T3B0aW9ucy53aWR0aDtcclxuXHJcbiAgICAgICAgYXdhaXQgc2V0QXNDb25maWcocGFnZSwgY2hhcnQsIG9wdGlvbnMsIGRpc3BsYXlFcnJvcnMpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gS2VlcHMgdHJhY2sgb2YgYWxsIHJlc291cmNlcyBhZGRlZCBvbiB0aGUgcGFnZSB3aXRoIGFkZFhYWFRhZy4gZXRjXHJcbiAgICAvLyBJdCdzIFZJVEFMIHRoYXQgYWxsIGFkZGVkIHJlc291cmNlcyBlbmRzIHVwIGhlcmUgc28gd2UgY2FuIGNsZWFyIHRoaW5nc1xyXG4gICAgLy8gb3V0IHdoZW4gZG9pbmcgYSBuZXcgZXhwb3J0IGluIHRoZSBzYW1lIHBhZ2UhXHJcbiAgICBpbmplY3RlZFJlc291cmNlcyA9IGF3YWl0IGFkZFBhZ2VSZXNvdXJjZXMocGFnZSwgb3B0aW9ucyk7XHJcblxyXG4gICAgLy8gR2V0IHRoZSByZWFsIGNoYXJ0IHNpemUgYW5kIHNldCB0aGUgem9vbSBhY2NvcmRpbmdseVxyXG4gICAgY29uc3Qgc2l6ZSA9IGlzU1ZHXHJcbiAgICAgID8gYXdhaXQgcGFnZS5ldmFsdWF0ZSgoc2NhbGUpID0+IHtcclxuICAgICAgICAgIGNvbnN0IHN2Z0VsZW1lbnQgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKFxyXG4gICAgICAgICAgICAnI2NoYXJ0LWNvbnRhaW5lciBzdmc6Zmlyc3Qtb2YtdHlwZSdcclxuICAgICAgICAgICk7XHJcblxyXG4gICAgICAgICAgLy8gR2V0IHRoZSB2YWx1ZXMgY29ycmVjdGx5IHNjYWxlZFxyXG4gICAgICAgICAgY29uc3QgY2hhcnRIZWlnaHQgPSBzdmdFbGVtZW50LmhlaWdodC5iYXNlVmFsLnZhbHVlICogc2NhbGU7XHJcbiAgICAgICAgICBjb25zdCBjaGFydFdpZHRoID0gc3ZnRWxlbWVudC53aWR0aC5iYXNlVmFsLnZhbHVlICogc2NhbGU7XHJcblxyXG4gICAgICAgICAgLy8gSW4gY2FzZSBvZiBTVkcgdGhlIHpvb20gbXVzdCBiZSBzZXQgZGlyZWN0bHkgZm9yIGJvZHlcclxuICAgICAgICAgIC8vIFNldCB0aGUgem9vbSBhcyBzY2FsZVxyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLnpvb20gPSBzY2FsZTtcclxuXHJcbiAgICAgICAgICAvLyBTZXQgdGhlIG1hcmdpbiB0byAwcHhcclxuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgICAgZG9jdW1lbnQuYm9keS5zdHlsZS5tYXJnaW4gPSAnMHB4JztcclxuXHJcbiAgICAgICAgICByZXR1cm4ge1xyXG4gICAgICAgICAgICBjaGFydEhlaWdodCxcclxuICAgICAgICAgICAgY2hhcnRXaWR0aFxyXG4gICAgICAgICAgfTtcclxuICAgICAgICB9LCBwYXJzZUZsb2F0KGV4cG9ydE9wdGlvbnMuc2NhbGUpKVxyXG4gICAgICA6IGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICBjb25zdCB7IGNoYXJ0SGVpZ2h0LCBjaGFydFdpZHRoIH0gPSB3aW5kb3cuSGlnaGNoYXJ0cy5jaGFydHNbMF07XHJcblxyXG4gICAgICAgICAgLy8gTm8gbmVlZCBmb3Igc3VjaCBzY2FsZSBtYW5pcHVsYXRpb24gaW4gY2FzZSBvZiBvdGhlciB0eXBlc1xyXG4gICAgICAgICAgLy8gb2YgZXhwb3J0cy4gUmVzZXQgdGhlIHpvb20gZm9yIG90aGVyIGV4cG9ydHMgdGhhbiB0byBTVkdzXHJcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUuem9vbSA9IDE7XHJcblxyXG4gICAgICAgICAgcmV0dXJuIHtcclxuICAgICAgICAgICAgY2hhcnRIZWlnaHQsXHJcbiAgICAgICAgICAgIGNoYXJ0V2lkdGhcclxuICAgICAgICAgIH07XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgLy8gU2V0IGZpbmFsIGhlaWdodCBhbmQgd2lkdGggZm9yIHZpZXdwb3J0XHJcbiAgICBjb25zdCB2aWV3cG9ydEhlaWdodCA9IE1hdGguY2VpbChzaXplLmNoYXJ0SGVpZ2h0IHx8IGV4cG9ydE9wdGlvbnMuaGVpZ2h0KTtcclxuICAgIGNvbnN0IHZpZXdwb3J0V2lkdGggPSBNYXRoLmNlaWwoc2l6ZS5jaGFydFdpZHRoIHx8IGV4cG9ydE9wdGlvbnMud2lkdGgpO1xyXG5cclxuICAgIC8vIEdldCB0aGUgY2xpcCByZWdpb24gZm9yIHRoZSBwYWdlXHJcbiAgICBjb25zdCB7IHgsIHkgfSA9IGF3YWl0IGdldENsaXBSZWdpb24ocGFnZSk7XHJcblxyXG4gICAgLy8gU2V0IHRoZSBmaW5hbCB2aWV3cG9ydCBub3cgdGhhdCB3ZSBoYXZlIHRoZSByZWFsIGhlaWdodFxyXG4gICAgYXdhaXQgcGFnZS5zZXRWaWV3cG9ydCh7XHJcbiAgICAgIGhlaWdodDogdmlld3BvcnRIZWlnaHQsXHJcbiAgICAgIHdpZHRoOiB2aWV3cG9ydFdpZHRoLFxyXG4gICAgICBkZXZpY2VTY2FsZUZhY3RvcjogaXNTVkcgPyAxIDogcGFyc2VGbG9hdChleHBvcnRPcHRpb25zLnNjYWxlKVxyXG4gICAgfSk7XHJcblxyXG4gICAgbGV0IGRhdGE7XHJcbiAgICAvLyBSYXN0ZXJpemF0aW9uIHByb2Nlc3NcclxuICAgIGlmIChleHBvcnRPcHRpb25zLnR5cGUgPT09ICdzdmcnKSB7XHJcbiAgICAgIC8vIFNWR1xyXG4gICAgICBkYXRhID0gYXdhaXQgY3JlYXRlU1ZHKHBhZ2UpO1xyXG4gICAgfSBlbHNlIGlmIChbJ3BuZycsICdqcGVnJ10uaW5jbHVkZXMoZXhwb3J0T3B0aW9ucy50eXBlKSkge1xyXG4gICAgICAvLyBQTkcgb3IgSlBFR1xyXG4gICAgICBkYXRhID0gYXdhaXQgY3JlYXRlSW1hZ2UoXHJcbiAgICAgICAgcGFnZSxcclxuICAgICAgICBleHBvcnRPcHRpb25zLnR5cGUsXHJcbiAgICAgICAgJ2Jhc2U2NCcsXHJcbiAgICAgICAge1xyXG4gICAgICAgICAgd2lkdGg6IHZpZXdwb3J0V2lkdGgsXHJcbiAgICAgICAgICBoZWlnaHQ6IHZpZXdwb3J0SGVpZ2h0LFxyXG4gICAgICAgICAgeCxcclxuICAgICAgICAgIHlcclxuICAgICAgICB9LFxyXG4gICAgICAgIGV4cG9ydE9wdGlvbnMucmFzdGVyaXphdGlvblRpbWVvdXRcclxuICAgICAgKTtcclxuICAgIH0gZWxzZSBpZiAoZXhwb3J0T3B0aW9ucy50eXBlID09PSAncGRmJykge1xyXG4gICAgICAvLyBQREZcclxuICAgICAgZGF0YSA9IGF3YWl0IGNyZWF0ZVBERihcclxuICAgICAgICBwYWdlLFxyXG4gICAgICAgIHZpZXdwb3J0SGVpZ2h0LFxyXG4gICAgICAgIHZpZXdwb3J0V2lkdGgsXHJcbiAgICAgICAgJ2Jhc2U2NCcsXHJcbiAgICAgICAgZXhwb3J0T3B0aW9ucy5yYXN0ZXJpemF0aW9uVGltZW91dFxyXG4gICAgICApO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgIGBbZXhwb3J0XSBVbnN1cHBvcnRlZCBvdXRwdXQgZm9ybWF0ICR7ZXhwb3J0T3B0aW9ucy50eXBlfS5gXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2xlYXIgcHJldmlvdXNseSBpbmplY3RlZCBKUyBhbmQgQ1NTIHJlc291cmNlc1xyXG4gICAgYXdhaXQgY2xlYXJQYWdlUmVzb3VyY2VzKHBhZ2UsIGluamVjdGVkUmVzb3VyY2VzKTtcclxuICAgIHJldHVybiBkYXRhO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICBhd2FpdCBjbGVhclBhZ2VSZXNvdXJjZXMocGFnZSwgaW5qZWN0ZWRSZXNvdXJjZXMpO1xyXG4gICAgcmV0dXJuIGVycm9yO1xyXG4gIH1cclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgY3NzVGVtcGxhdGUgZnJvbSAnLi9jc3MuanMnO1xyXG5cclxuZXhwb3J0IGRlZmF1bHQgKGNoYXJ0KSA9PiBgXHJcbjwhRE9DVFlQRSBodG1sPlxyXG48aHRtbCBsYW5nPSdlbi1VUyc+XHJcbiAgPGhlYWQ+XHJcbiAgICA8bWV0YSBodHRwLWVxdWl2PVwiQ29udGVudC1UeXBlXCIgY29udGVudD1cInRleHQvaHRtbDsgY2hhcnNldD11dGYtOFwiPlxyXG4gICAgPHRpdGxlPkhpZ2hjaGFydHMgRXhwb3J0PC90aXRsZT5cclxuICA8L2hlYWQ+XHJcbiAgPHN0eWxlPlxyXG4gICAgJHtjc3NUZW1wbGF0ZSgpfVxyXG4gIDwvc3R5bGU+XHJcbiAgPGJvZHk+XHJcbiAgICA8ZGl2IGlkPVwiY2hhcnQtY29udGFpbmVyXCI+XHJcbiAgICAgICR7Y2hhcnR9XHJcbiAgICA8L2Rpdj5cclxuICA8L2JvZHk+XHJcbjwvaHRtbD5cclxuXHJcbmA7XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgUG9vbCB9IGZyb20gJ3Rhcm4nO1xyXG5pbXBvcnQgeyB2NCBhcyB1dWlkIH0gZnJvbSAndXVpZCc7XHJcblxyXG5pbXBvcnQge1xyXG4gIGNyZWF0ZSBhcyBjcmVhdGVCcm93c2VyLFxyXG4gIGNsb3NlIGFzIGNsb3NlQnJvd3NlcixcclxuICBuZXdQYWdlLFxyXG4gIGNsZWFyUGFnZVxyXG59IGZyb20gJy4vYnJvd3Nlci5qcyc7XHJcbmltcG9ydCBwdXBwZXRlZXJFeHBvcnQgZnJvbSAnLi9leHBvcnQuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgbWVhc3VyZVRpbWUgfSBmcm9tICcuL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vLyBUaGUgcG9vbCBpbnN0YW5jZVxyXG5sZXQgcG9vbCA9IGZhbHNlO1xyXG5cclxuLy8gUG9vbCBzdGF0aXN0aWNzXHJcbmV4cG9ydCBjb25zdCBzdGF0cyA9IHtcclxuICBwZXJmb3JtZWRFeHBvcnRzOiAwLFxyXG4gIGV4cG9ydEF0dGVtcHRzOiAwLFxyXG4gIGV4cG9ydEZyb21TdmdBdHRlbXB0czogMCxcclxuICB0aW1lU3BlbnQ6IDAsXHJcbiAgZHJvcHBlZEV4cG9ydHM6IDAsXHJcbiAgc3BlbnRBdmVyYWdlOiAwXHJcbn07XHJcblxyXG5sZXQgcG9vbENvbmZpZyA9IHt9O1xyXG5cclxuY29uc3QgZmFjdG9yeSA9IHtcclxuICAvKipcclxuICAgKiBDcmVhdGVzIGEgbmV3IHdvcmtlciBwYWdlIGZvciB0aGUgZXhwb3J0IHBvb2wuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7T2JqZWN0fSAtIEFuIG9iamVjdCBjb250YWluaW5nIHRoZSB3b3JrZXIgSUQsIGEgcmVmZXJlbmNlIHRvIHRoZVxyXG4gICAqIGJyb3dzZXIgcGFnZSwgYW5kIGluaXRpYWwgd29yayBjb3VudC5cclxuICAgKlxyXG4gICAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSAtIElmIHRoZXJlJ3MgYW4gZXJyb3IgZHVyaW5nIHRoZSBjcmVhdGlvbiBvZiB0aGUgbmV3XHJcbiAgICogcGFnZS5cclxuICAgKi9cclxuICBjcmVhdGU6IGFzeW5jICgpID0+IHtcclxuICAgIGxldCBwYWdlID0gZmFsc2U7XHJcblxyXG4gICAgY29uc3QgaWQgPSB1dWlkKCk7XHJcbiAgICBjb25zdCBzdGFydERhdGUgPSBuZXcgRGF0ZSgpLmdldFRpbWUoKTtcclxuXHJcbiAgICB0cnkge1xyXG4gICAgICBwYWdlID0gYXdhaXQgbmV3UGFnZSgpO1xyXG5cclxuICAgICAgaWYgKCFwYWdlIHx8IHBhZ2UuaXNDbG9zZWQoKSkge1xyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignVGhlIHBhZ2UgaXMgaW52YWxpZCBvciBjbG9zZWQuJyk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGxvZyhcclxuICAgICAgICAzLFxyXG4gICAgICAgIGBbcG9vbF0gU3VjY2Vzc2Z1bGx5IGNyZWF0ZWQgYSB3b3JrZXIgJHtpZH0gLSB0b29rICR7XHJcbiAgICAgICAgICBuZXcgRGF0ZSgpLmdldFRpbWUoKSAtIHN0YXJ0RGF0ZVxyXG4gICAgICAgIH0gbXMuYFxyXG4gICAgICApO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdFcnJvciBlbmNvdW50ZXJlZCB3aGVuIGNyZWF0aW5nIGEgbmV3IHBhZ2UuJ1xyXG4gICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4ge1xyXG4gICAgICBpZCxcclxuICAgICAgcGFnZSxcclxuICAgICAgLy8gVHJ5IHRvIGRpc3RyaWJ1dGUgdGhlIGluaXRpYWwgd29yayBjb3VudFxyXG4gICAgICB3b3JrQ291bnQ6IE1hdGgucm91bmQoTWF0aC5yYW5kb20oKSAqIChwb29sQ29uZmlnLndvcmtMaW1pdCAvIDIpKVxyXG4gICAgfTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBWYWxpZGF0ZXMgYSB3b3JrZXIgcGFnZSBpbiB0aGUgZXhwb3J0IHBvb2wsIGNoZWNraW5nIGlmIGl0IGhhcyBleGNlZWRlZFxyXG4gICAqIHRoZSB3b3JrIGxpbWl0LlxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtPYmplY3R9IHdvcmtlckhhbmRsZSAtIFRoZSBoYW5kbGUgdG8gdGhlIHdvcmtlciwgY29udGFpbmluZyB0aGVcclxuICAgKiB3b3JrZXIncyBJRCwgYSByZWZlcmVuY2UgdG8gdGhlIGJyb3dzZXIgcGFnZSwgYW5kIHdvcmsgY291bnQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBSZXR1cm5zIHRydWUgaWYgdGhlIHdvcmtlciBpcyB2YWxpZCBhbmQgd2l0aGluXHJcbiAgICogdGhlIHdvcmsgbGltaXQ7IG90aGVyd2lzZSwgcmV0dXJucyBmYWxzZS5cclxuICAgKi9cclxuICB2YWxpZGF0ZTogYXN5bmMgKHdvcmtlckhhbmRsZSkgPT4ge1xyXG4gICAgaWYgKFxyXG4gICAgICBwb29sQ29uZmlnLndvcmtMaW1pdCAmJlxyXG4gICAgICArK3dvcmtlckhhbmRsZS53b3JrQ291bnQgPiBwb29sQ29uZmlnLndvcmtMaW1pdFxyXG4gICAgKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICAzLFxyXG4gICAgICAgIGBbcG9vbF0gV29ya2VyIGZhaWxlZCB2YWxpZGF0aW9uOiBleGNlZWRlZCB3b3JrIGxpbWl0IChsaW1pdCBpcyAke3Bvb2xDb25maWcud29ya0xpbWl0fSkuYFxyXG4gICAgICApO1xyXG4gICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gdHJ1ZTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBEZXN0cm95cyBhIHdvcmtlciBlbnRyeSBpbiB0aGUgZXhwb3J0IHBvb2wsIGNsb3NpbmcgaXRzIGFzc29jaWF0ZWQgcGFnZS5cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7T2JqZWN0fSB3b3JrZXJIYW5kbGUgLSBUaGUgaGFuZGxlIHRvIHRoZSB3b3JrZXIsIGNvbnRhaW5pbmdcclxuICAgKiB0aGUgd29ya2VyJ3MgSUQgYW5kIGEgcmVmZXJlbmNlIHRvIHRoZSBicm93c2VyIHBhZ2UuXHJcbiAgICovXHJcbiAgZGVzdHJveTogYXN5bmMgKHdvcmtlckhhbmRsZSkgPT4ge1xyXG4gICAgbG9nKDMsIGBbcG9vbF0gRGVzdHJveWluZyBwb29sIGVudHJ5ICR7d29ya2VySGFuZGxlLmlkfS5gKTtcclxuXHJcbiAgICBpZiAod29ya2VySGFuZGxlLnBhZ2UpIHtcclxuICAgICAgLy8gV2UgZG9uJ3QgcmVhbGx5IG5lZWQgdG8gd2FpdCBhcm91bmQgZm9yIHRoaXNcclxuICAgICAgYXdhaXQgd29ya2VySGFuZGxlLnBhZ2UuY2xvc2UoKTtcclxuICAgIH1cclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgdGhlIGV4cG9ydCBwb29sIHdpdGggdGhlIHByb3ZpZGVkIGNvbmZpZ3VyYXRpb24sIGNyZWF0aW5nXHJcbiAqIGEgYnJvd3NlciBpbnN0YW5jZSBhbmQgc2V0dGluZyB1cCB3b3JrZXIgcmVzb3VyY2VzLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnIC0gQ29uZmlndXJhdGlvbiBvcHRpb25zIGZvciB0aGUgZXhwb3J0IHBvb2wgYWxvbmdcclxuICogd2l0aCBjdXN0b20gcHVwcGV0ZWVyIGFyZ3VtZW50cyBmb3IgdGhlIHB1cHBldGVlci5sYXVuY2ggZnVuY3Rpb24uXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaW5pdFBvb2wgPSBhc3luYyAoY29uZmlnKSA9PiB7XHJcbiAgLy8gRm9yIHRoZSBtb2R1bGUgc2NvcGUgdXNhZ2VcclxuICBwb29sQ29uZmlnID0gY29uZmlnICYmIGNvbmZpZy5wb29sID8geyAuLi5jb25maWcucG9vbCB9IDoge307XHJcblxyXG4gIC8vIENyZWF0ZSBhIGJyb3dzZXIgaW5zdGFuY2Ugd2l0aCB0aGUgcHVwcGV0ZWVyIGFyZ3VtZW50c1xyXG4gIGF3YWl0IGNyZWF0ZUJyb3dzZXIoY29uZmlnLnB1cHBldGVlckFyZ3MpO1xyXG5cclxuICBsb2coXHJcbiAgICAzLFxyXG4gICAgYFtwb29sXSBJbml0aWFsaXppbmcgcG9vbCB3aXRoIHdvcmtlcnM6IG1pbiAke3Bvb2xDb25maWcubWluV29ya2Vyc30sIG1heCAke3Bvb2xDb25maWcubWF4V29ya2Vyc30uYFxyXG4gICk7XHJcblxyXG4gIGlmIChwb29sKSB7XHJcbiAgICByZXR1cm4gbG9nKFxyXG4gICAgICA0LFxyXG4gICAgICAnW3Bvb2xdIEFscmVhZHkgaW5pdGlhbGl6ZWQsIHBsZWFzZSBraWxsIGl0IGJlZm9yZSBjcmVhdGluZyBhIG5ldyBvbmUuJ1xyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIGlmIChwYXJzZUludChwb29sQ29uZmlnLm1pbldvcmtlcnMpID4gcGFyc2VJbnQocG9vbENvbmZpZy5tYXhXb3JrZXJzKSkge1xyXG4gICAgcG9vbENvbmZpZy5taW5Xb3JrZXJzID0gcG9vbENvbmZpZy5tYXhXb3JrZXJzO1xyXG4gIH1cclxuXHJcbiAgdHJ5IHtcclxuICAgIC8vIENyZWF0ZSBhIHBvb2wgYWxvbmcgd2l0aCBhIG1pbmltYWwgbnVtYmVyIG9mIHJlc291cmNlc1xyXG4gICAgcG9vbCA9IG5ldyBQb29sKHtcclxuICAgICAgLy8gR2V0IHRoZSBjcmVhdGUvdmFsaWRhdGUvZGVzdHJveS9sb2cgZnVuY3Rpb25zXHJcbiAgICAgIC4uLmZhY3RvcnksXHJcbiAgICAgIG1pbjogcGFyc2VJbnQocG9vbENvbmZpZy5taW5Xb3JrZXJzKSxcclxuICAgICAgbWF4OiBwYXJzZUludChwb29sQ29uZmlnLm1heFdvcmtlcnMpLFxyXG4gICAgICBhY3F1aXJlVGltZW91dE1pbGxpczogcG9vbENvbmZpZy5hY3F1aXJlVGltZW91dCxcclxuICAgICAgY3JlYXRlVGltZW91dE1pbGxpczogcG9vbENvbmZpZy5jcmVhdGVUaW1lb3V0LFxyXG4gICAgICBkZXN0cm95VGltZW91dE1pbGxpczogcG9vbENvbmZpZy5kZXN0cm95VGltZW91dCxcclxuICAgICAgaWRsZVRpbWVvdXRNaWxsaXM6IHBvb2xDb25maWcuaWRsZVRpbWVvdXQsXHJcbiAgICAgIGNyZWF0ZVJldHJ5SW50ZXJ2YWxNaWxsaXM6IHBvb2xDb25maWcuY3JlYXRlUmV0cnlJbnRlcnZhbCxcclxuICAgICAgcmVhcEludGVydmFsTWlsbGlzOiBwb29sQ29uZmlnLnJlYXBlckludGVydmFsLFxyXG4gICAgICBwcm9wYWdhdGVDcmVhdGVFcnJvcjogZmFsc2VcclxuICAgIH0pO1xyXG5cclxuICAgIC8vIFNldCBldmVudHNcclxuICAgIHBvb2wub24oJ3JlbGVhc2UnLCBhc3luYyAocmVzb3VyY2UpID0+IHtcclxuICAgICAgLy8gQ2xlYXIgcGFnZVxyXG4gICAgICBhd2FpdCBjbGVhclBhZ2UocmVzb3VyY2UucGFnZSwgZmFsc2UpO1xyXG4gICAgICBsb2coNCwgYFtwb29sXSBSZWxlYXNpbmcgYSB3b3JrZXIgd2l0aCBJRCAke3Jlc291cmNlLmlkfS5gKTtcclxuICAgIH0pO1xyXG5cclxuICAgIHBvb2wub24oJ2Rlc3Ryb3lTdWNjZXNzJywgKGV2ZW50SWQsIHJlc291cmNlKSA9PiB7XHJcbiAgICAgIGxvZyg0LCBgW3Bvb2xdIERlc3Ryb3llZCBhIHdvcmtlciB3aXRoIElEICR7cmVzb3VyY2UuaWR9LmApO1xyXG4gICAgfSk7XHJcblxyXG4gICAgY29uc3QgaW5pdGlhbFJlc291cmNlcyA9IFtdO1xyXG4gICAgLy8gQ3JlYXRlIGFuIGluaXRpYWwgbnVtYmVyIG9mIHJlc291cmNlc1xyXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBwb29sQ29uZmlnLm1pbldvcmtlcnM7IGkrKykge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGNvbnN0IHJlc291cmNlID0gYXdhaXQgcG9vbC5hY3F1aXJlKCkucHJvbWlzZTtcclxuICAgICAgICBpbml0aWFsUmVzb3VyY2VzLnB1c2gocmVzb3VyY2UpO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgJ1twb29sXSBDb3VsZCBub3QgY3JlYXRlIGFuIGluaXRpYWwgcmVzb3VyY2UuJyk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBSZWxlYXNlIHRoZSBpbml0aWFsIG51bWJlciBvZiByZXNvdXJjZXMgYmFjayB0byB0aGUgcG9vbFxyXG4gICAgaW5pdGlhbFJlc291cmNlcy5mb3JFYWNoKChyZXNvdXJjZSkgPT4ge1xyXG4gICAgICBwb29sLnJlbGVhc2UocmVzb3VyY2UpO1xyXG4gICAgfSk7XHJcblxyXG4gICAgbG9nKFxyXG4gICAgICAzLFxyXG4gICAgICBgW3Bvb2xdIFRoZSBwb29sIGlzIHJlYWR5JHtpbml0aWFsUmVzb3VyY2VzLmxlbmd0aCA/IGAgd2l0aCAke2luaXRpYWxSZXNvdXJjZXMubGVuZ3RofSBpbml0aWFsIHJlc291cmNlcyB3YWl0aW5nLmAgOiAnLid9YFxyXG4gICAgKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW3Bvb2xdIENvdWxkIG5vdCBjcmVhdGUgdGhlIHBvb2wgb2Ygd29ya2Vycy4nXHJcbiAgICApLnNldEVycm9yKGVycm9yKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogS2lsbHMgYWxsIHdvcmtlcnMgaW4gdGhlIHBvb2wsIGRlc3Ryb3lzIHRoZSBwb29sLCBhbmQgY2xvc2VzIHRoZSBicm93c2VyXHJcbiAqIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgYWZ0ZXIgdGhlIHdvcmtlcnMgYXJlXHJcbiAqIGtpbGxlZCwgdGhlIHBvb2wgaXMgZGVzdHJveWVkLCBhbmQgdGhlIGJyb3dzZXIgaXMgY2xvc2VkLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGtpbGxQb29sKCkge1xyXG4gIGxvZygzLCAnW3Bvb2xdIEtpbGxpbmcgcG9vbCB3aXRoIGFsbCB3b3JrZXJzIGFuZCBjbG9zaW5nIGJyb3dzZXIuJyk7XHJcblxyXG4gIC8vIElmIHN0aWxsIGFsaXZlLCBkZXN0cm95IHRoZSBwb29sIG9mIHBhZ2VzIGJlZm9yZSBjbG9zaW5nIGEgYnJvd3NlclxyXG4gIGlmIChwb29sKSB7XHJcbiAgICAvLyBGcmVlIHVwIG5vdCByZWxlYXNlZCB3b3JrZXJzXHJcbiAgICBmb3IgKGNvbnN0IHdvcmtlciBvZiBwb29sLnVzZWQpIHtcclxuICAgICAgcG9vbC5yZWxlYXNlKHdvcmtlci5yZXNvdXJjZSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRGVzdHJveSB0aGUgcG9vbCBpZiBpdCBpcyBzdGlsbCBhdmFpbGFibGVcclxuICAgIGlmICghcG9vbC5kZXN0cm95ZWQpIHtcclxuICAgICAgYXdhaXQgcG9vbC5kZXN0cm95KCk7XHJcbiAgICAgIGxvZyg0LCAnW2Jyb3dzZXJdIERlc3Ryb3llZCB0aGUgcG9vbCBvZiByZXNvdXJjZXMuJyk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBDbG9zZSB0aGUgYnJvd3NlciBpbnN0YW5jZVxyXG4gIGF3YWl0IGNsb3NlQnJvd3NlcigpO1xyXG59XHJcblxyXG4vKipcclxuICogUHJvY2Vzc2VzIHRoZSBleHBvcnQgd29yayB1c2luZyBhIHdvcmtlciBmcm9tIHRoZSBwb29sLiBBY3F1aXJlcyBhIHdvcmtlclxyXG4gKiBoYW5kbGUgZnJvbSB0aGUgcG9vbCwgcGVyZm9ybXMgdGhlIGV4cG9ydCB1c2luZyBwdXBwZXRlZXIsIGFuZCByZWxlYXNlc1xyXG4gKiB0aGUgd29ya2VyIGhhbmRsZSBiYWNrIHRvIHRoZSBwb29sLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY2hhcnQgLSBUaGUgY2hhcnQgZGF0YSBvciBjb25maWd1cmF0aW9uIHRvIGJlIGV4cG9ydGVkLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIEV4cG9ydCBvcHRpb25zIGFuZCBjb25maWd1cmF0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aXRoIHRoZSBleHBvcnQgcmVzdWx0YW5kXHJcbiAqIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBJZiBhbiBlcnJvciBvY2N1cnMgZHVyaW5nIHRoZSBleHBvcnQgcHJvY2Vzcy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBwb3N0V29yayA9IGFzeW5jIChjaGFydCwgb3B0aW9ucykgPT4ge1xyXG4gIGxldCB3b3JrZXJIYW5kbGU7XHJcblxyXG4gIHRyeSB7XHJcbiAgICBsb2coNCwgJ1twb29sXSBXb3JrIHJlY2VpdmVkLCBzdGFydGluZyB0byBwcm9jZXNzLicpO1xyXG5cclxuICAgICsrc3RhdHMuZXhwb3J0QXR0ZW1wdHM7XHJcbiAgICBpZiAocG9vbENvbmZpZy5iZW5jaG1hcmtpbmcpIHtcclxuICAgICAgZ2V0UG9vbEluZm8oKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoIXBvb2wpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdXb3JrIHJlY2VpdmVkLCBidXQgcG9vbCBoYXMgbm90IGJlZW4gc3RhcnRlZC4nKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBBY3F1aXJlIHRoZSB3b3JrZXIgYWxvbmcgd2l0aCB0aGUgaWQgb2YgcmVzb3VyY2UgYW5kIHdvcmsgY291bnRcclxuICAgIGNvbnN0IGFjcXVpcmVDb3VudGVyID0gbWVhc3VyZVRpbWUoKTtcclxuICAgIHRyeSB7XHJcbiAgICAgIGxvZyg0LCAnW3Bvb2xdIEFjcXVpcmluZyBhIHdvcmtlciBoYW5kbGUuJyk7XHJcbiAgICAgIHdvcmtlckhhbmRsZSA9IGF3YWl0IHBvb2wuYWNxdWlyZSgpLnByb21pc2U7XHJcblxyXG4gICAgICAvLyBDaGVjayB0aGUgcGFnZSBhY3F1aXJlIHRpbWVcclxuICAgICAgaWYgKG9wdGlvbnMuc2VydmVyLmJlbmNobWFya2luZykge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDUsXHJcbiAgICAgICAgICBvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZFxyXG4gICAgICAgICAgICA/IGBbYmVuY2htYXJrXSBSZXF1ZXN0OiAke29wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkfSAtYFxyXG4gICAgICAgICAgICA6ICdbYmVuY2htYXJrXScsXHJcbiAgICAgICAgICBgQWNxdWlyZWQgYSB3b3JrZXIgaGFuZGxlOiAke2FjcXVpcmVDb3VudGVyKCl9bXMuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAob3B0aW9ucy5wYXlsb2FkPy5yZXF1ZXN0SWRcclxuICAgICAgICAgID8gYFJlcXVlc3Q6ICR7b3B0aW9ucy5wYXlsb2FkPy5yZXF1ZXN0SWR9IC0gYFxyXG4gICAgICAgICAgOiAnJykgK1xyXG4gICAgICAgICAgYEVycm9yIGVuY291bnRlcmVkIHdoZW4gYWNxdWlyaW5nIGFuIGF2YWlsYWJsZSBlbnRyeTogJHthY3F1aXJlQ291bnRlcigpfW1zLmBcclxuICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICB9XHJcbiAgICBsb2coNCwgJ1twb29sXSBBY3F1aXJlZCBhIHdvcmtlciBoYW5kbGUuJyk7XHJcblxyXG4gICAgaWYgKCF3b3JrZXJIYW5kbGUucGFnZSkge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ1Jlc29sdmVkIHdvcmtlciBwYWdlIGlzIGludmFsaWQ6IHRoZSBwb29sIHNldHVwIGlzIHdvbmt5LidcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBTYXZlIHRoZSBzdGFydCB0aW1lXHJcbiAgICBsZXQgd29ya1N0YXJ0ID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XHJcblxyXG4gICAgbG9nKDQsIGBbcG9vbF0gU3RhcnRpbmcgd29yayBvbiBwb29sIGVudHJ5IHdpdGggSUQgJHt3b3JrZXJIYW5kbGUuaWR9LmApO1xyXG5cclxuICAgIC8vIFBlcmZvcm0gYW4gZXhwb3J0IG9uIGEgcHVwcGV0ZWVyIGxldmVsXHJcbiAgICBjb25zdCBleHBvcnRDb3VudGVyID0gbWVhc3VyZVRpbWUoKTtcclxuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHB1cHBldGVlckV4cG9ydCh3b3JrZXJIYW5kbGUucGFnZSwgY2hhcnQsIG9wdGlvbnMpO1xyXG5cclxuICAgIC8vIENoZWNrIGlmIGl0J3MgYW4gZXJyb3JcclxuICAgIGlmIChyZXN1bHQgaW5zdGFuY2VvZiBFcnJvcikge1xyXG4gICAgICAvLyBUT0RPOiBJZiB0aGUgZXhwb3J0IGZhaWxlZCBiZWNhdXNlIHB1cHBldGVlciB0aW1lZCBvdXQsIHdlIG5lZWQgdG8gZm9yY2Uga2lsbCB0aGUgd29ya2VyIHNvIHdlIGdldCBhIG5ldyBwYWdlLiBUaGF0IG5lZWRzIHRvIGJlIGhhbmRsZWQgYmV0dGVyIHRoYW4gdGhpcyBoYWNrLlxyXG4gICAgICBpZiAocmVzdWx0Lm1lc3NhZ2UgPT09ICdSYXN0ZXJpemF0aW9uIHRpbWVvdXQnKSB7XHJcbiAgICAgICAgd29ya2VySGFuZGxlLnBhZ2UuY2xvc2UoKTtcclxuICAgICAgICB3b3JrZXJIYW5kbGUucGFnZSA9IGF3YWl0IG5ld1BhZ2UoKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgIChvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZFxyXG4gICAgICAgICAgPyBgUmVxdWVzdDogJHtvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZH0gLSBgXHJcbiAgICAgICAgICA6ICcnKSArIGBFcnJvciBlbmNvdW50ZXJlZCBkdXJpbmcgZXhwb3J0OiAke2V4cG9ydENvdW50ZXIoKX1tcy5gXHJcbiAgICAgICkuc2V0RXJyb3IocmVzdWx0KTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBDaGVjayB0aGUgUHVwcGV0ZWVyIGV4cG9ydCB0aW1lXHJcbiAgICBpZiAob3B0aW9ucy5zZXJ2ZXIuYmVuY2htYXJraW5nKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICA1LFxyXG4gICAgICAgIG9wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkXHJcbiAgICAgICAgICA/IGBbYmVuY2htYXJrXSBSZXF1ZXN0OiAke29wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkfSAtYFxyXG4gICAgICAgICAgOiAnW2JlbmNobWFya10nLFxyXG4gICAgICAgIGBFeHBvcnRlZCBhIGNoYXJ0IHN1Y2Vzc2Z1bGx5OiAke2V4cG9ydENvdW50ZXIoKX1tcy5gXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmVsZWFzZSB0aGUgcmVzb3VyY2UgYmFjayB0byB0aGUgcG9vbFxyXG4gICAgcG9vbC5yZWxlYXNlKHdvcmtlckhhbmRsZSk7XHJcblxyXG4gICAgLy8gVXNlZCBmb3Igc3RhdGlzdGljcyBpbiBhdmVyYWdlVGltZSBhbmQgcHJvY2Vzc2VkV29ya0NvdW50LCB3aGljaFxyXG4gICAgLy8gaW4gdHVybiBpcyB1c2VkIGJ5IHRoZSAvaGVhbHRoIHJvdXRlLlxyXG4gICAgY29uc3Qgd29ya0VuZCA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xyXG4gICAgY29uc3QgZXhwb3J0VGltZSA9IHdvcmtFbmQgLSB3b3JrU3RhcnQ7XHJcbiAgICBzdGF0cy50aW1lU3BlbnQgKz0gZXhwb3J0VGltZTtcclxuICAgIHN0YXRzLnNwZW50QXZlcmFnZSA9IHN0YXRzLnRpbWVTcGVudCAvICsrc3RhdHMucGVyZm9ybWVkRXhwb3J0cztcclxuXHJcbiAgICBsb2coNCwgYFtwb29sXSBXb3JrIGNvbXBsZXRlZCBpbiAke2V4cG9ydFRpbWV9IG1zLmApO1xyXG5cclxuICAgIC8vIE90aGVyd2lzZSByZXR1cm4gdGhlIHJlc3VsdFxyXG4gICAgcmV0dXJuIHtcclxuICAgICAgcmVzdWx0LFxyXG4gICAgICBvcHRpb25zXHJcbiAgICB9O1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICArK3N0YXRzLmRyb3BwZWRFeHBvcnRzO1xyXG5cclxuICAgIGlmICh3b3JrZXJIYW5kbGUpIHtcclxuICAgICAgcG9vbC5yZWxlYXNlKHdvcmtlckhhbmRsZSk7XHJcbiAgICB9XHJcblxyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKGBbcG9vbF0gSW4gcG9vbC5wb3N0V29yazogJHtlcnJvci5tZXNzYWdlfWApLnNldEVycm9yKFxyXG4gICAgICBlcnJvclxyXG4gICAgKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHRoZSBjdXJyZW50IHBvb2wgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R8bnVsbH0gVGhlIGN1cnJlbnQgcG9vbCBpbnN0YW5jZSBpZiBpbml0aWFsaXplZCwgb3IgbnVsbFxyXG4gKiBpZiB0aGUgcG9vbCBoYXMgbm90IGJlZW4gY3JlYXRlZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBnZXRQb29sID0gKCkgPT4gcG9vbDtcclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgcG9vbCBpbmZvcm1hdGlvbiBpbiBKU09OIGZvcm1hdCwgaW5jbHVkaW5nIG1pbmltdW0gYW5kIG1heGltdW1cclxuICogd29ya2VycywgYXZhaWxhYmxlIHdvcmtlcnMsIHdvcmtlcnMgaW4gdXNlLCBhbmQgcGVuZGluZyBhY3F1aXJlIHJlcXVlc3RzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBQb29sIGluZm9ybWF0aW9uIGluIEpTT04gZm9ybWF0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldFBvb2xJbmZvSlNPTiA9ICgpID0+ICh7XHJcbiAgbWluOiBwb29sLm1pbixcclxuICBtYXg6IHBvb2wubWF4LFxyXG4gIGFsbDogcG9vbC5udW1GcmVlKCkgKyBwb29sLm51bVVzZWQoKSxcclxuICBhdmFpbGFibGU6IHBvb2wubnVtRnJlZSgpLFxyXG4gIHVzZWQ6IHBvb2wubnVtVXNlZCgpLFxyXG4gIHBlbmRpbmc6IHBvb2wubnVtUGVuZGluZ0FjcXVpcmVzKClcclxufSk7XHJcblxyXG4vKipcclxuICogTG9ncyBpbmZvcm1hdGlvbiBhYm91dCB0aGUgY3VycmVudCBzdGF0ZSBvZiB0aGUgcG9vbCwgaW5jbHVkaW5nIHRoZSBtaW5pbXVtXHJcbiAqIGFuZCBtYXhpbXVtIHdvcmtlcnMsIGF2YWlsYWJsZSB3b3JrZXJzLCB3b3JrZXJzIGluIHVzZSwgYW5kIHBlbmRpbmcgYWNxdWlyZVxyXG4gKiByZXF1ZXN0cy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRQb29sSW5mbygpIHtcclxuICBjb25zdCB7IG1pbiwgbWF4LCBhbGwsIGF2YWlsYWJsZSwgdXNlZCwgcGVuZGluZyB9ID0gZ2V0UG9vbEluZm9KU09OKCk7XHJcblxyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBtaW5pbXVtIG51bWJlciBvZiByZXNvdXJjZXMgYWxsb3dlZCBieSBwb29sOiAke21pbn0uYCk7XHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG1heGltdW0gbnVtYmVyIG9mIHJlc291cmNlcyBhbGxvd2VkIGJ5IHBvb2w6ICR7bWF4fS5gKTtcclxuICBsb2coNSwgYFtwb29sXSBUaGUgbnVtYmVyIG9mIGFsbCBjcmVhdGVkIHJlc291cmNlczogJHthbGx9LmApO1xyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgYXZhaWxhYmxlIHJlc291cmNlczogJHthdmFpbGFibGV9LmApO1xyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgYWNxdWlyZWQgcmVzb3VyY2VzOiAke3VzZWR9LmApO1xyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgcmVzb3VyY2VzIHdhaXRpbmcgdG8gYmUgYWNxdWlyZWQ6ICR7cGVuZGluZ30uYCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBHZXRzIHRoZSBzdGF0aXN0aWMgb2YgYSBwb29sIGluc3RhY2UgYWJvdXQgZXhwb3J0cy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRTdGF0cygpIHtcclxuICByZXR1cm4gc3RhdHM7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBpbml0UG9vbCxcclxuICBraWxsUG9vbCxcclxuICBwb3N0V29yayxcclxuICBnZXRQb29sLFxyXG4gIGdldFBvb2xJbmZvLFxyXG4gIGdldFBvb2xJbmZvSlNPTixcclxuICBnZXRTdGF0c1xyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYywgd3JpdGVGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuXHJcbmltcG9ydCB7IGdldE9wdGlvbnMsIGluaXRFeHBvcnRTZXR0aW5ncyB9IGZyb20gJy4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IGtpbGxQb29sLCBwb3N0V29yaywgc3RhdHMgfSBmcm9tICcuL3Bvb2wuanMnO1xyXG5pbXBvcnQge1xyXG4gIGZpeFR5cGUsXHJcbiAgaGFuZGxlUmVzb3VyY2VzLFxyXG4gIGlzQ29ycmVjdEpTT04sXHJcbiAgb3B0aW9uc1N0cmluZ2lmeSxcclxuICByb3VuZE51bWJlcixcclxuICB0b0Jvb2xlYW4sXHJcbiAgd3JhcEFyb3VuZFxyXG59IGZyb20gJy4vdXRpbHMuanMnO1xyXG5pbXBvcnQgeyBzYW5pdGl6ZSB9IGZyb20gJy4vc2FuaXRpemUuanMnO1xyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxubGV0IGFsbG93Q29kZUV4ZWN1dGlvbiA9IGZhbHNlO1xyXG5cclxuLyoqXHJcbiAqIFN0YXJ0cyBhbiBleHBvcnQgcHJvY2Vzcy4gVGhlIGBzZXR0aW5nc2AgY29udGFpbnMgZmluYWwgb3B0aW9ucyBnYXRoZXJlZFxyXG4gKiBmcm9tIGFsbCBwb3NzaWJsZSBzb3VyY2VzIChjb25maWcsIGVudiwgY2xpLCBqc29uKS4gVGhlIGBlbmRDYWxsYmFja2AgaXNcclxuICogY2FsbGVkIHdoZW4gdGhlIGV4cG9ydCBpcyBjb21wbGV0ZWQsIHdpdGggYW4gZXJyb3Igb2JqZWN0IGFzIHRoZSBmaXJzdFxyXG4gKiBhcmd1bWVudCBhbmQgdGhlIHNlY29uZCBjb250YWluaW5nIHRoZSBiYXNlNjQgcmVzcHJlc2VudGF0aW9uIG9mIGEgY2hhcnQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBzZXR0aW5ncyAtIFRoZSBzZXR0aW5ncyBvYmplY3QgY29udGFpbmluZyBleHBvcnRcclxuICogY29uZmlndXJhdGlvbi5cclxuICogQHBhcmFtIHtmdW5jdGlvbn0gZW5kQ2FsbGJhY2sgLSBUaGUgY2FsbGJhY2sgZnVuY3Rpb24gdG8gYmUgaW52b2tlZCB1cG9uXHJcbiAqIGZpbmFsaXppbmcgd29yayBvciB1cG9uIGVycm9yIG9jY3VyYW5jZSBvZiB0aGUgZXhwb3J0aW5nIHByb2Nlc3MuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHt2b2lkfSBUaGlzIGZ1bmN0aW9uIGRvZXMgbm90IHJldHVybiBhIHZhbHVlIGRpcmVjdGx5OyBpbnN0ZWFkLFxyXG4gKiBpdCBjb21tdW5pY2F0ZXMgcmVzdWx0cyB2aWEgdGhlIGVuZENhbGxiYWNrLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHN0YXJ0RXhwb3J0ID0gYXN5bmMgKHNldHRpbmdzLCBlbmRDYWxsYmFjaykgPT4ge1xyXG4gIC8vIFN0YXJ0aW5nIGV4cG9ydGluZyBwcm9jZXNzIG1lc3NhZ2VcclxuICBsb2coNCwgJ1tjaGFydF0gU3RhcnRpbmcgdGhlIGV4cG9ydGluZyBwcm9jZXNzLicpO1xyXG5cclxuICAvLyBJbml0aWFsaXplIG9wdGlvbnNcclxuICBjb25zdCBvcHRpb25zID0gaW5pdEV4cG9ydFNldHRpbmdzKHNldHRpbmdzLCBnZXRPcHRpb25zKCkpO1xyXG5cclxuICAvLyBHZXQgdGhlIGV4cG9ydCBvcHRpb25zXHJcbiAgY29uc3QgZXhwb3J0T3B0aW9ucyA9IG9wdGlvbnMuZXhwb3J0O1xyXG5cclxuICAvLyBJZiBTVkcgaXMgYW4gaW5wdXQgKGFyZ3VtZW50IGNhbiBiZSBzZW50IG9ubHkgYnkgdGhlIHJlcXVlc3QpXHJcbiAgaWYgKG9wdGlvbnMucGF5bG9hZD8uc3ZnICYmIG9wdGlvbnMucGF5bG9hZC5zdmcgIT09ICcnKSB7XHJcbiAgICB0cnkge1xyXG4gICAgICBsb2coNCwgJ1tjaGFydF0gQXR0ZW1wdGluZyB0byBleHBvcnQgZnJvbSBhIFNWRyBpbnB1dC4nKTtcclxuXHJcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGV4cG9ydEFzU3RyaW5nKFxyXG4gICAgICAgIHNhbml0aXplKG9wdGlvbnMucGF5bG9hZC5zdmcpLCAvLyAjMjA5XHJcbiAgICAgICAgb3B0aW9ucyxcclxuICAgICAgICBlbmRDYWxsYmFja1xyXG4gICAgICApO1xyXG5cclxuICAgICAgKytzdGF0cy5leHBvcnRGcm9tU3ZnQXR0ZW1wdHM7XHJcbiAgICAgIHJldHVybiByZXN1bHQ7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICAgICAgbmV3IEV4cG9ydEVycm9yKCdbY2hhcnRdIEVycm9yIGxvYWRpbmcgU1ZHIGlucHV0LicpLnNldEVycm9yKGVycm9yKVxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gRXhwb3J0IHVzaW5nIG9wdGlvbnMgZnJvbSB0aGUgZmlsZVxyXG4gIGlmIChleHBvcnRPcHRpb25zLmluZmlsZSAmJiBleHBvcnRPcHRpb25zLmluZmlsZS5sZW5ndGgpIHtcclxuICAgIC8vIFRyeSB0byByZWFkIHRoZSBmaWxlIHRvIGdldCB0aGUgc3RyaW5nIHJlcHJlc2VudGF0aW9uXHJcbiAgICB0cnkge1xyXG4gICAgICBsb2coNCwgJ1tjaGFydF0gQXR0ZW1wdGluZyB0byBleHBvcnQgZnJvbSBhbiBpbnB1dCBmaWxlLicpO1xyXG4gICAgICBvcHRpb25zLmV4cG9ydC5pbnN0ciA9IHJlYWRGaWxlU3luYyhleHBvcnRPcHRpb25zLmluZmlsZSwgJ3V0ZjgnKTtcclxuICAgICAgcmV0dXJuIGV4cG9ydEFzU3RyaW5nKG9wdGlvbnMuZXhwb3J0Lmluc3RyLnRyaW0oKSwgb3B0aW9ucywgZW5kQ2FsbGJhY2spO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKFxyXG4gICAgICAgIG5ldyBFeHBvcnRFcnJvcignW2NoYXJ0XSBFcnJvciBsb2FkaW5nIGlucHV0IGZpbGUuJykuc2V0RXJyb3IoZXJyb3IpXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBFeHBvcnQgd2l0aCBvcHRpb25zIGZyb20gdGhlIHJhdyByZXByZXNlbnRhdGlvblxyXG4gIGlmIChcclxuICAgIChleHBvcnRPcHRpb25zLmluc3RyICYmIGV4cG9ydE9wdGlvbnMuaW5zdHIgIT09ICcnKSB8fFxyXG4gICAgKGV4cG9ydE9wdGlvbnMub3B0aW9ucyAmJiBleHBvcnRPcHRpb25zLm9wdGlvbnMgIT09ICcnKVxyXG4gICkge1xyXG4gICAgdHJ5IHtcclxuICAgICAgbG9nKDQsICdbY2hhcnRdIEF0dGVtcHRpbmcgdG8gZXhwb3J0IGZyb20gYSByYXcgaW5wdXQuJyk7XHJcblxyXG4gICAgICAvLyBQZXJmb3JtIGEgZGlyZWN0IGluamVjdCB3aGVuIGZvcmNlZFxyXG4gICAgICBpZiAodG9Cb29sZWFuKG9wdGlvbnMuY3VzdG9tTG9naWM/LmFsbG93Q29kZUV4ZWN1dGlvbikpIHtcclxuICAgICAgICByZXR1cm4gZG9TdHJhaWdodEluamVjdChvcHRpb25zLCBlbmRDYWxsYmFjayk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIEVpdGhlciB0cnkgdG8gcGFyc2UgdG8gSlNPTiBmaXJzdCBvciBkbyB0aGUgZGlyZWN0IGV4cG9ydFxyXG4gICAgICByZXR1cm4gdHlwZW9mIGV4cG9ydE9wdGlvbnMuaW5zdHIgPT09ICdzdHJpbmcnXHJcbiAgICAgICAgPyBleHBvcnRBc1N0cmluZyhleHBvcnRPcHRpb25zLmluc3RyLnRyaW0oKSwgb3B0aW9ucywgZW5kQ2FsbGJhY2spXHJcbiAgICAgICAgOiBkb0V4cG9ydChcclxuICAgICAgICAgICAgb3B0aW9ucyxcclxuICAgICAgICAgICAgZXhwb3J0T3B0aW9ucy5pbnN0ciB8fCBleHBvcnRPcHRpb25zLm9wdGlvbnMsXHJcbiAgICAgICAgICAgIGVuZENhbGxiYWNrXHJcbiAgICAgICAgICApO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKFxyXG4gICAgICAgIG5ldyBFeHBvcnRFcnJvcignW2NoYXJ0XSBFcnJvciBsb2FkaW5nIHJhdyBpbnB1dC4nKS5zZXRFcnJvcihlcnJvcilcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIE5vIGlucHV0IHNwZWNpZmllZCwgcGFzcyBhbiBlcnJvciBtZXNzYWdlIHRvIHRoZSBjYWxsYmFja1xyXG4gIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgIG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgYFtjaGFydF0gTm8gdmFsaWQgaW5wdXQgc3BlY2lmaWVkLiBDaGVjayBpZiBhdCBsZWFzdCBvbmUgb2YgdGhlIGZvbGxvd2luZyBwYXJhbWV0ZXJzIGlzIGNvcnJlY3RseSBzZXQ6ICdpbmZpbGUnLCAnaW5zdHInLCAnb3B0aW9ucycsIG9yICdzdmcnLmBcclxuICAgIClcclxuICApO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFN0YXJ0cyBhIGJhdGNoIGV4cG9ydCBwcm9jZXNzIGZvciBtdWx0aXBsZSBjaGFydHMgYmFzZWQgb24gdGhlIGluZm9ybWF0aW9uXHJcbiAqIGluIHRoZSBiYXRjaCBvcHRpb24uIFRoZSBiYXRjaCBpcyBhIHN0cmluZyBpbiB0aGUgZm9sbG93aW5nIGZvcm1hdDpcclxuICogXCJpbmZpbGUxLmpzb249b3V0ZmlsZTEucG5nO2luZmlsZTIuanNvbj1vdXRmaWxlMi5wbmc7Li4uXCJcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgb3B0aW9ucyBvYmplY3QgY29udGFpbmluZyBjb25maWd1cmF0aW9uIGZvclxyXG4gKiBhIGJhdGNoIGV4cG9ydC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgdGhlIGJhdGNoIGV4cG9ydFxyXG4gKiBwcm9jZXNzIGlzIGNvbXBsZXRlZC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiBhbiBlcnJvciBvY2N1cnMgZHVyaW5nXHJcbiAqIGFueSBvZiB0aGUgYmF0Y2ggZXhwb3J0IHByb2Nlc3MuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgYmF0Y2hFeHBvcnQgPSBhc3luYyAob3B0aW9ucykgPT4ge1xyXG4gIGNvbnN0IGJhdGNoRnVuY3Rpb25zID0gW107XHJcblxyXG4gIC8vIFNwbGl0IGFuZCBwYWlyIHRoZSAtLWJhdGNoIGFyZ3VtZW50c1xyXG4gIGZvciAobGV0IHBhaXIgb2Ygb3B0aW9ucy5leHBvcnQuYmF0Y2guc3BsaXQoJzsnKSkge1xyXG4gICAgcGFpciA9IHBhaXIuc3BsaXQoJz0nKTtcclxuICAgIGlmIChwYWlyLmxlbmd0aCA9PT0gMikge1xyXG4gICAgICBiYXRjaEZ1bmN0aW9ucy5wdXNoKFxyXG4gICAgICAgIHN0YXJ0RXhwb3J0KFxyXG4gICAgICAgICAge1xyXG4gICAgICAgICAgICAuLi5vcHRpb25zLFxyXG4gICAgICAgICAgICBleHBvcnQ6IHtcclxuICAgICAgICAgICAgICAuLi5vcHRpb25zLmV4cG9ydCxcclxuICAgICAgICAgICAgICBpbmZpbGU6IHBhaXJbMF0sXHJcbiAgICAgICAgICAgICAgb3V0ZmlsZTogcGFpclsxXVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9LFxyXG4gICAgICAgICAgKGVycm9yLCBpbmZvKSA9PiB7XHJcbiAgICAgICAgICAgIC8vIFRocm93IGFuIGVycm9yXHJcbiAgICAgICAgICAgIGlmIChlcnJvcikge1xyXG4gICAgICAgICAgICAgIHRocm93IGVycm9yO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAvLyBTYXZlIHRoZSBiYXNlNjQgZnJvbSBhIGJ1ZmZlciB0byBhIGNvcnJlY3QgaW1hZ2UgZmlsZVxyXG4gICAgICAgICAgICB3cml0ZUZpbGVTeW5jKFxyXG4gICAgICAgICAgICAgIGluZm8ub3B0aW9ucy5leHBvcnQub3V0ZmlsZSxcclxuICAgICAgICAgICAgICBpbmZvLm9wdGlvbnMuZXhwb3J0LnR5cGUgIT09ICdzdmcnXHJcbiAgICAgICAgICAgICAgICA/IEJ1ZmZlci5mcm9tKGluZm8ucmVzdWx0LCAnYmFzZTY0JylcclxuICAgICAgICAgICAgICAgIDogaW5mby5yZXN1bHRcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICApXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICB0cnkge1xyXG4gICAgLy8gQXdhaXQgYWxsIGV4cG9ydHMgYXJlIGRvbmVcclxuICAgIGF3YWl0IFByb21pc2UuYWxsKGJhdGNoRnVuY3Rpb25zKTtcclxuXHJcbiAgICAvLyBLaWxsIHBvb2wgYW5kIGNsb3NlIGJyb3dzZXIgYWZ0ZXIgZmluaXNoaW5nIGJhdGNoIGV4cG9ydFxyXG4gICAgYXdhaXQga2lsbFBvb2woKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW2NoYXJ0XSBFcnJvciBlbmNvdW50ZXJlZCBkdXJpbmcgYmF0Y2ggZXhwb3J0LidcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgYSBzaW5nbGUgZXhwb3J0IHByb2Nlc3MgYmFzZWQgb24gdGhlIHNwZWNpZmllZCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBvcHRpb25zIG9iamVjdCBjb250YWluaW5nIGNvbmZpZ3VyYXRpb24gZm9yXHJcbiAqIGEgc2luZ2xlIGV4cG9ydC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgdGhlIHNpbmdsZSBleHBvcnRcclxuICogcHJvY2VzcyBpcyBjb21wbGV0ZWQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgYW4gZXJyb3Igb2NjdXJzIGR1cmluZ1xyXG4gKiB0aGUgc2luZ2xlIGV4cG9ydCBwcm9jZXNzLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHNpbmdsZUV4cG9ydCA9IGFzeW5jIChvcHRpb25zKSA9PiB7XHJcbiAgLy8gVXNlIGluc3RyIG9yIGl0cyBhbGlhcywgb3B0aW9uc1xyXG4gIG9wdGlvbnMuZXhwb3J0Lmluc3RyID0gb3B0aW9ucy5leHBvcnQuaW5zdHIgfHwgb3B0aW9ucy5leHBvcnQub3B0aW9ucztcclxuXHJcbiAgLy8gUGVyZm9ybSBhbiBleHBvcnRcclxuICBhd2FpdCBzdGFydEV4cG9ydChvcHRpb25zLCBhc3luYyAoZXJyb3IsIGluZm8pID0+IHtcclxuICAgIC8vIEV4aXQgcHJvY2VzcyB3aGVuIGVycm9yXHJcbiAgICBpZiAoZXJyb3IpIHtcclxuICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgeyBvdXRmaWxlLCB0eXBlIH0gPSBpbmZvLm9wdGlvbnMuZXhwb3J0O1xyXG5cclxuICAgIC8vIFNhdmUgdGhlIGJhc2U2NCBmcm9tIGEgYnVmZmVyIHRvIGEgY29ycmVjdCBpbWFnZSBmaWxlXHJcbiAgICB3cml0ZUZpbGVTeW5jKFxyXG4gICAgICBvdXRmaWxlIHx8IGBjaGFydC4ke3R5cGV9YCxcclxuICAgICAgdHlwZSAhPT0gJ3N2ZycgPyBCdWZmZXIuZnJvbShpbmZvLnJlc3VsdCwgJ2Jhc2U2NCcpIDogaW5mby5yZXN1bHRcclxuICAgICk7XHJcblxyXG4gICAgLy8gS2lsbCBwb29sIGFuZCBjbG9zZSBicm93c2VyIGFmdGVyIGZpbmlzaGluZyBzaW5nbGUgZXhwb3J0XHJcbiAgICBhd2FpdCBraWxsUG9vbCgpO1xyXG4gIH0pO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIERldGVybWluZXMgdGhlIHNpemUgYW5kIHNjYWxlIGZvciBjaGFydCBleHBvcnQgYmFzZWQgb24gdGhlIHByb3ZpZGVkIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IGNvbnRhaW5pbmcgY29uZmlndXJhdGlvbiBmb3JcclxuICogY2hhcnQgZXhwb3J0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBBbiBvYmplY3QgY29udGFpbmluZyB0aGUgY2FsY3VsYXRlZCBoZWlnaHQsIHdpZHRoLFxyXG4gKiBhbmQgc2NhbGUgZm9yIHRoZSBjaGFydCBleHBvcnQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZmluZENoYXJ0U2l6ZSA9IChvcHRpb25zKSA9PiB7XHJcbiAgY29uc3QgeyBjaGFydCwgZXhwb3J0aW5nIH0gPVxyXG4gICAgb3B0aW9ucy5leHBvcnQ/Lm9wdGlvbnMgfHwgaXNDb3JyZWN0SlNPTihvcHRpb25zLmV4cG9ydD8uaW5zdHIpO1xyXG5cclxuICAvLyBTZWUgaWYgZ2xvYmFsT3B0aW9ucyBob2xkcyBjaGFydCBvciBleHBvcnRpbmcgc2l6ZVxyXG4gIGNvbnN0IGdsb2JhbE9wdGlvbnMgPSBpc0NvcnJlY3RKU09OKG9wdGlvbnMuZXhwb3J0Py5nbG9iYWxPcHRpb25zKTtcclxuXHJcbiAgLy8gU2VjdXJlIHNjYWxlIHZhbHVlXHJcbiAgbGV0IHNjYWxlID1cclxuICAgIG9wdGlvbnMuZXhwb3J0Py5zY2FsZSB8fFxyXG4gICAgZXhwb3J0aW5nPy5zY2FsZSB8fFxyXG4gICAgZ2xvYmFsT3B0aW9ucz8uZXhwb3J0aW5nPy5zY2FsZSB8fFxyXG4gICAgb3B0aW9ucy5leHBvcnQ/LmRlZmF1bHRTY2FsZSB8fFxyXG4gICAgMTtcclxuXHJcbiAgLy8gdGhlIHNjYWxlIGNhbm5vdCBiZSBsb3dlciB0aGFuIDAuMSBhbmQgY2Fubm90IGJlIGhpZ2hlciB0aGFuIDUuMFxyXG4gIHNjYWxlID0gTWF0aC5tYXgoMC4xLCBNYXRoLm1pbihzY2FsZSwgNS4wKSk7XHJcblxyXG4gIC8vIHdlIHdhbnQgdG8gcm91bmQgdGhlIG51bWJlcnMgbGlrZSAwLjIzMjM0IC0+IDAuMjNcclxuICBzY2FsZSA9IHJvdW5kTnVtYmVyKHNjYWxlLCAyKTtcclxuXHJcbiAgLy8gRmluZCBjaGFydCBzaXplIGFuZCBzY2FsZVxyXG4gIGNvbnN0IHNpemUgPSB7XHJcbiAgICBoZWlnaHQ6XHJcbiAgICAgIG9wdGlvbnMuZXhwb3J0Py5oZWlnaHQgfHxcclxuICAgICAgZXhwb3J0aW5nPy5zb3VyY2VIZWlnaHQgfHxcclxuICAgICAgY2hhcnQ/LmhlaWdodCB8fFxyXG4gICAgICBnbG9iYWxPcHRpb25zPy5leHBvcnRpbmc/LnNvdXJjZUhlaWdodCB8fFxyXG4gICAgICBnbG9iYWxPcHRpb25zPy5jaGFydD8uaGVpZ2h0IHx8XHJcbiAgICAgIG9wdGlvbnMuZXhwb3J0Py5kZWZhdWx0SGVpZ2h0IHx8XHJcbiAgICAgIDQwMCxcclxuICAgIHdpZHRoOlxyXG4gICAgICBvcHRpb25zLmV4cG9ydD8ud2lkdGggfHxcclxuICAgICAgZXhwb3J0aW5nPy5zb3VyY2VXaWR0aCB8fFxyXG4gICAgICBjaGFydD8ud2lkdGggfHxcclxuICAgICAgZ2xvYmFsT3B0aW9ucz8uZXhwb3J0aW5nPy5zb3VyY2VXaWR0aCB8fFxyXG4gICAgICBnbG9iYWxPcHRpb25zPy5jaGFydD8ud2lkdGggfHxcclxuICAgICAgb3B0aW9ucy5leHBvcnQ/LmRlZmF1bHRXaWR0aCB8fFxyXG4gICAgICA2MDAsXHJcbiAgICBzY2FsZVxyXG4gIH07XHJcblxyXG4gIC8vIEdldCByaWQgb2YgcG90ZW50aWFsIHB4IGFuZCAlXHJcbiAgZm9yIChsZXQgW3BhcmFtLCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMoc2l6ZSkpIHtcclxuICAgIHNpemVbcGFyYW1dID1cclxuICAgICAgdHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJyA/ICt2YWx1ZS5yZXBsYWNlKC9weHwlL2dpLCAnJykgOiB2YWx1ZTtcclxuICB9XHJcbiAgcmV0dXJuIHNpemU7XHJcbn07XHJcblxyXG4vKipcclxuICogRnVuY3Rpb24gZm9yIGZpbmFsaXppbmcgb3B0aW9ucyBiZWZvcmUgZXhwb3J0LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBvcHRpb25zIG9iamVjdCBjb250YWluaW5nIGNvbmZpZ3VyYXRpb24gZm9yXHJcbiAqIHRoZSBleHBvcnQgcHJvY2Vzcy5cclxuICogQHBhcmFtIHtPYmplY3R9IGNoYXJ0SnNvbiAtIFRoZSBKU09OIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBjaGFydC5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gZW5kQ2FsbGJhY2sgLSBUaGUgY2FsbGJhY2sgZnVuY3Rpb24gdG8gYmUgY2FsbGVkIHVwb25cclxuICogY29tcGxldGlvbiBvciBlcnJvci5cclxuICogQHBhcmFtIHtzdHJpbmd9IHN2ZyAtIFRoZSBTVkcgcmVwcmVzZW50YXRpb24gb2YgdGhlIGNoYXJ0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgZXhwb3J0IHByb2Nlc3NcclxuICogaXMgY29tcGxldGVkLlxyXG4gKi9cclxuY29uc3QgZG9FeHBvcnQgPSBhc3luYyAob3B0aW9ucywgY2hhcnRKc29uLCBlbmRDYWxsYmFjaywgc3ZnKSA9PiB7XHJcbiAgbGV0IHsgZXhwb3J0OiBleHBvcnRPcHRpb25zLCBjdXN0b21Mb2dpYzogY3VzdG9tTG9naWNPcHRpb25zIH0gPSBvcHRpb25zO1xyXG5cclxuICBjb25zdCBhbGxvd0NvZGVFeGVjdXRpb25TY29wZWQgPVxyXG4gICAgdHlwZW9mIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0NvZGVFeGVjdXRpb24gPT09ICdib29sZWFuJ1xyXG4gICAgICA/IGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0NvZGVFeGVjdXRpb25cclxuICAgICAgOiBhbGxvd0NvZGVFeGVjdXRpb247XHJcblxyXG4gIGlmICghY3VzdG9tTG9naWNPcHRpb25zKSB7XHJcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMgPSBvcHRpb25zLmN1c3RvbUxvZ2ljID0ge307XHJcbiAgfSBlbHNlIGlmIChhbGxvd0NvZGVFeGVjdXRpb25TY29wZWQpIHtcclxuICAgIGlmICh0eXBlb2Ygb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXMgPT09ICdzdHJpbmcnKSB7XHJcbiAgICAgIC8vIFByb2Nlc3MgcmVzb3VyY2VzXHJcbiAgICAgIG9wdGlvbnMuY3VzdG9tTG9naWMucmVzb3VyY2VzID0gaGFuZGxlUmVzb3VyY2VzKFxyXG4gICAgICAgIG9wdGlvbnMuY3VzdG9tTG9naWMucmVzb3VyY2VzLFxyXG4gICAgICAgIHRvQm9vbGVhbihvcHRpb25zLmN1c3RvbUxvZ2ljLmFsbG93RmlsZVJlc291cmNlcylcclxuICAgICAgKTtcclxuICAgIH0gZWxzZSBpZiAoIW9wdGlvbnMuY3VzdG9tTG9naWMucmVzb3VyY2VzKSB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgY29uc3QgcmVzb3VyY2VzID0gcmVhZEZpbGVTeW5jKCdyZXNvdXJjZXMuanNvbicsICd1dGY4Jyk7XHJcbiAgICAgICAgb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXMgPSBoYW5kbGVSZXNvdXJjZXMoXHJcbiAgICAgICAgICByZXNvdXJjZXMsXHJcbiAgICAgICAgICB0b0Jvb2xlYW4ob3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0ZpbGVSZXNvdXJjZXMpXHJcbiAgICAgICAgKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgICAyLFxyXG4gICAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgICBgW2NoYXJ0XSBVbmFibGUgdG8gbG9hZCB0aGUgZGVmYXVsdCByZXNvdXJjZXMuanNvbiBmaWxlLmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBJZiB0aGUgYWxsb3dDb2RlRXhlY3V0aW9uIGZsYWcgaXNuJ3Qgc2V0LCB3ZSBzaG91bGQgcmVmdXNlIHRoZSB1c2FnZVxyXG4gIC8vIG9mIGNhbGxiYWNrLCByZXNvdXJjZXMsIGFuZCBjdXN0b20gY29kZS4gQWRkaXRpb25hbGx5LCB0aGUgd29ya2VyIHdpbGxcclxuICAvLyByZWZ1c2UgdG8gcnVuIGFyYml0cmFyeSBKYXZhU2NyaXB0LiBQcmlvcml0aXplZCBzaG91bGQgYmUgdGhlIHNjb3BlZFxyXG4gIC8vIG9wdGlvbiwgdGhlbiB3ZSBzaG91bGQgdGFrZSBhIGxvb2sgYXQgdGhlIG92ZXJhbGwgcG9vbCBvcHRpb24uXHJcbiAgaWYgKCFhbGxvd0NvZGVFeGVjdXRpb25TY29wZWQgJiYgY3VzdG9tTG9naWNPcHRpb25zKSB7XHJcbiAgICBpZiAoXHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayB8fFxyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzIHx8XHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlXHJcbiAgICApIHtcclxuICAgICAgLy8gU2VuZCBiYWNrIGEgZnJpZW5kbHkgbWVzc2FnZSBzYXlpbmcgdGhhdCB0aGUgZXhwb3J0ZXIgZG9lcyBub3Qgc3VwcG9ydFxyXG4gICAgICAvLyB0aGVzZSBzZXR0aW5ncy5cclxuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKFxyXG4gICAgICAgIG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgIGBbY2hhcnRdIFRoZSAnY2FsbGJhY2snLCAncmVzb3VyY2VzJyBhbmQgJ2N1c3RvbUNvZGUnIG9wdGlvbnMgaGF2ZSBiZWVuIGRpc2FibGVkIGZvciB0aGlzIHNlcnZlci5gXHJcbiAgICAgICAgKVxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFJlc2V0IGFsbCBhZGRpdGlvbmFsIGN1c3RvbSBjb2RlXHJcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSBmYWxzZTtcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXMgPSBmYWxzZTtcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlID0gZmFsc2U7XHJcbiAgfVxyXG5cclxuICAvLyBDbGVhbiBwcm9wZXJ0aWVzIHRvIGtlZXAgaXQgbGVhbiBhbmQgbWVhblxyXG4gIGlmIChjaGFydEpzb24pIHtcclxuICAgIGNoYXJ0SnNvbi5jaGFydCA9IGNoYXJ0SnNvbi5jaGFydCB8fCB7fTtcclxuICAgIGNoYXJ0SnNvbi5leHBvcnRpbmcgPSBjaGFydEpzb24uZXhwb3J0aW5nIHx8IHt9O1xyXG4gICAgY2hhcnRKc29uLmV4cG9ydGluZy5lbmFibGVkID0gZmFsc2U7XHJcbiAgfVxyXG5cclxuICBleHBvcnRPcHRpb25zLmNvbnN0ciA9IGV4cG9ydE9wdGlvbnMuY29uc3RyIHx8ICdjaGFydCc7XHJcbiAgZXhwb3J0T3B0aW9ucy50eXBlID0gZml4VHlwZShleHBvcnRPcHRpb25zLnR5cGUsIGV4cG9ydE9wdGlvbnMub3V0ZmlsZSk7XHJcbiAgaWYgKGV4cG9ydE9wdGlvbnMudHlwZSA9PT0gJ3N2ZycpIHtcclxuICAgIGV4cG9ydE9wdGlvbnMud2lkdGggPSBmYWxzZTtcclxuICB9XHJcblxyXG4gIC8vIFByZXBhcmUgZ2xvYmFsIGFuZCB0aGVtZSBvcHRpb25zXHJcbiAgWydnbG9iYWxPcHRpb25zJywgJ3RoZW1lT3B0aW9ucyddLmZvckVhY2goKG9wdGlvbnNOYW1lKSA9PiB7XHJcbiAgICB0cnkge1xyXG4gICAgICBpZiAoZXhwb3J0T3B0aW9ucyAmJiBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSkge1xyXG4gICAgICAgIGlmIChcclxuICAgICAgICAgIHR5cGVvZiBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9PT0gJ3N0cmluZycgJiZcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdLmVuZHNXaXRoKCcuanNvbicpXHJcbiAgICAgICAgKSB7XHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9IGlzQ29ycmVjdEpTT04oXHJcbiAgICAgICAgICAgIHJlYWRGaWxlU3luYyhleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSwgJ3V0ZjgnKSxcclxuICAgICAgICAgICAgdHJ1ZVxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPSBpc0NvcnJlY3RKU09OKFxyXG4gICAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSxcclxuICAgICAgICAgICAgdHJ1ZVxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID0ge307XHJcbiAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgYFtjaGFydF0gVGhlICcke29wdGlvbnNOYW1lfScgY2Fubm90IGJlIGxvYWRlZC5gKTtcclxuICAgIH1cclxuICB9KTtcclxuXHJcbiAgLy8gUHJlcGFyZSB0aGUgY3VzdG9tQ29kZVxyXG4gIGlmIChjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dDb2RlRXhlY3V0aW9uKSB7XHJcbiAgICB0cnkge1xyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSA9IHdyYXBBcm91bmQoXHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUsXHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmFsbG93RmlsZVJlc291cmNlc1xyXG4gICAgICApO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2NoYXJ0XSBUaGUgJ2N1c3RvbUNvZGUnIGNhbm5vdCBiZSBsb2FkZWQuYCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBHZXQgdGhlIGNhbGxiYWNrXHJcbiAgaWYgKFxyXG4gICAgY3VzdG9tTG9naWNPcHRpb25zICYmXHJcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgJiZcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjaz8uaW5kZXhPZigneycpIDwgMFxyXG4gICkge1xyXG4gICAgLy8gVGhlIGFsbG93RmlsZVJlc291cmNlcyBpcyBhbHdheXMgc2V0IHRvIGZhbHNlIGZvciBIVFRQIHJlcXVlc3RzIHRvIGF2b2lkXHJcbiAgICAvLyBpbmplY3RpbmcgYXJiaXRyYXJ5IGZpbGVzIGZyb20gdGhlIGZzXHJcbiAgICBpZiAoY3VzdG9tTG9naWNPcHRpb25zLmFsbG93RmlsZVJlc291cmNlcykge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IHJlYWRGaWxlU3luYyhcclxuICAgICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayxcclxuICAgICAgICAgICd1dGY4J1xyXG4gICAgICAgICk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrID0gZmFsc2U7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2NoYXJ0XSBUaGUgJ2NhbGxiYWNrJyBjYW5ub3QgYmUgbG9hZGVkLmApO1xyXG4gICAgICB9XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSBmYWxzZTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFNpemUgc2VhcmNoXHJcbiAgb3B0aW9ucy5leHBvcnQgPSB7XHJcbiAgICAuLi5vcHRpb25zLmV4cG9ydCxcclxuICAgIC4uLmZpbmRDaGFydFNpemUob3B0aW9ucylcclxuICB9O1xyXG5cclxuICAvLyBQb3N0IHRoZSB3b3JrIHRvIHRoZSBwb29sXHJcbiAgdHJ5IHtcclxuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHBvc3RXb3JrKFxyXG4gICAgICBleHBvcnRPcHRpb25zLnN0ckluaiB8fCBjaGFydEpzb24gfHwgc3ZnLFxyXG4gICAgICBvcHRpb25zXHJcbiAgICApO1xyXG4gICAgcmV0dXJuIGVuZENhbGxiYWNrKGZhbHNlLCByZXN1bHQpO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICByZXR1cm4gZW5kQ2FsbGJhY2soZXJyb3IpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBQZXJmb3JtcyBhIGRpcmVjdCBpbmplY3Qgb2Ygb3B0aW9ucyBiZWZvcmUgZXhwb3J0LiBUaGUgZnVuY3Rpb24gYXR0ZW1wdHNcclxuICogdG8gc3RyaW5naWZ5IHRoZSBwcm92aWRlZCBvcHRpb25zIGFuZCByZW1vdmVzIHVubmVjZXNzYXJ5IGNoYXJhY3RlcnMsXHJcbiAqIGVuc3VyaW5nIGEgY2xlYW4gYW5kIGZvcm1hdHRlZCBpbnB1dC4gVGhlIHJlc3VsdGluZyBzdHJpbmcgaXMgc2F2ZWQgYXNcclxuICogYSBcInN0cmlnaHQgaW5qZWN0XCIgc3RyaW5nIGluIHRoZSBleHBvcnQgb3B0aW9ucy4gSXQgdGhlbiBpbnZva2VzIHRoZVxyXG4gKiBkb0V4cG9ydCBmdW5jdGlvbiB3aXRoIHRoZSB1cGRhdGVkIG9wdGlvbnMuXHJcbiAqXHJcbiAqIElNUE9SVEFOVDogRGFuZ2Vyb3VzIGFuZCBtdXN0IGJlIHVzZWQgZGVsaWJlcmF0ZWx5IGJ5IHNvbWVvbmUgd2hvIHNldHMgdXBcclxuICogYSBzZXJ2ZXIgKHNlZSB0aGUgIC0tYWxsb3dDb2RlRXhlY3V0aW9uIG9wdGlvbikuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIGV4cG9ydCBvcHRpb25zIGNvbnRhaW5pbmcgdGhlIGlucHV0XHJcbiAqIHRvIGJlIGluamVjdGVkLlxyXG4gKiBAcGFyYW0ge2Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIFRoZSBjYWxsYmFjayBmdW5jdGlvbiB0byBiZSBpbnZva2VkXHJcbiAqIGF0IHRoZSBlbmQgb2YgdGhlIHByb2Nlc3MuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlfSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB3aXRoIHRoZSByZXN1bHQgb2YgdGhlIGV4cG9ydFxyXG4gKiBvcGVyYXRpb24gb3IgcmVqZWN0cyB3aXRoIGFuIGVycm9yIGlmIGFueSBpc3N1ZXMgb2NjdXIgZHVyaW5nIHRoZSBwcm9jZXNzLlxyXG4gKi9cclxuY29uc3QgZG9TdHJhaWdodEluamVjdCA9IChvcHRpb25zLCBlbmRDYWxsYmFjaykgPT4ge1xyXG4gIHRyeSB7XHJcbiAgICBsZXQgc3RySW5qO1xyXG4gICAgbGV0IGluc3RyID0gb3B0aW9ucy5leHBvcnQuaW5zdHIgfHwgb3B0aW9ucy5leHBvcnQub3B0aW9ucztcclxuXHJcbiAgICBpZiAodHlwZW9mIGluc3RyICE9PSAnc3RyaW5nJykge1xyXG4gICAgICAvLyBUcnkgdG8gc3RyaW5naWZ5IG9wdGlvbnNcclxuICAgICAgc3RySW5qID0gaW5zdHIgPSBvcHRpb25zU3RyaW5naWZ5KFxyXG4gICAgICAgIGluc3RyLFxyXG4gICAgICAgIG9wdGlvbnMuY3VzdG9tTG9naWM/LmFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gICAgc3RySW5qID0gaW5zdHIucmVwbGFjZUFsbCgvXFx0fFxcbnxcXHIvZywgJycpLnRyaW0oKTtcclxuXHJcbiAgICAvLyBHZXQgcmlkIG9mIHRoZSA7XHJcbiAgICBpZiAoc3RySW5qW3N0ckluai5sZW5ndGggLSAxXSA9PT0gJzsnKSB7XHJcbiAgICAgIHN0ckluaiA9IHN0ckluai5zdWJzdHJpbmcoMCwgc3RySW5qLmxlbmd0aCAtIDEpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFNhdmUgYXMgc3RyaWdodCBpbmplY3Qgc3RyaW5nXHJcbiAgICBvcHRpb25zLmV4cG9ydC5zdHJJbmogPSBzdHJJbmo7XHJcbiAgICByZXR1cm4gZG9FeHBvcnQob3B0aW9ucywgZmFsc2UsIGVuZENhbGxiYWNrKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgcmV0dXJuIGVuZENhbGxiYWNrKFxyXG4gICAgICBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgYFtjaGFydF0gTWFsZm9ybWVkIGlucHV0IGRldGVjdGVkIGZvciAke29wdGlvbnMuZXhwb3J0Py5yZXF1ZXN0SWQgfHwgJz8nfS4gUGxlYXNlIG1ha2Ugc3VyZSB0aGF0IHlvdXIgSlNPTi9KYXZhU2NyaXB0IG9wdGlvbnMgYXJlIHNlbnQgdXNpbmcgdGhlIFwib3B0aW9uc1wiIGF0dHJpYnV0ZSwgYW5kIHRoYXQgaWYgeW91J3JlIHVzaW5nIFNWRywgaXQgaXMgdW5lc2NhcGVkLmBcclxuICAgICAgKS5zZXRFcnJvcihlcnJvcilcclxuICAgICk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEV4cG9ydHMgYSBzdHJpbmcgYmFzZWQgb24gdGhlIHByb3ZpZGVkIG9wdGlvbnMgYW5kIGludm9rZXMgYW4gZW5kIGNhbGxiYWNrLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gc3RyaW5nVG9FeHBvcnQgLSBUaGUgc3RyaW5nIGNvbnRlbnQgdG8gYmUgZXhwb3J0ZWQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gRXhwb3J0IG9wdGlvbnMsIGluY2x1ZGluZyBjdXN0b21Mb2dpYyB3aXRoXHJcbiAqIGFsbG93Q29kZUV4ZWN1dGlvbiBmbGFnLlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIENhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGludm9rZWQgYXQgdGhlIGVuZFxyXG4gKiBvZiB0aGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHthbnl9IFJlc3VsdCBvZiB0aGUgZXhwb3J0IHByb2Nlc3Mgb3IgYW4gZXJyb3IgaWYgZW5jb3VudGVyZWQuXHJcbiAqL1xyXG5jb25zdCBleHBvcnRBc1N0cmluZyA9IChzdHJpbmdUb0V4cG9ydCwgb3B0aW9ucywgZW5kQ2FsbGJhY2spID0+IHtcclxuICBjb25zdCB7IGFsbG93Q29kZUV4ZWN1dGlvbiB9ID0gb3B0aW9ucy5jdXN0b21Mb2dpYztcclxuXHJcbiAgLy8gQ2hlY2sgaWYgaXQgaXMgU1ZHXHJcbiAgaWYgKFxyXG4gICAgc3RyaW5nVG9FeHBvcnQuaW5kZXhPZignPHN2ZycpID49IDAgfHxcclxuICAgIHN0cmluZ1RvRXhwb3J0LmluZGV4T2YoJzw/eG1sJykgPj0gMFxyXG4gICkge1xyXG4gICAgbG9nKDQsICdbY2hhcnRdIFBhcnNpbmcgaW5wdXQgYXMgU1ZHLicpO1xyXG4gICAgcmV0dXJuIGRvRXhwb3J0KG9wdGlvbnMsIGZhbHNlLCBlbmRDYWxsYmFjaywgc3RyaW5nVG9FeHBvcnQpO1xyXG4gIH1cclxuXHJcbiAgdHJ5IHtcclxuICAgIC8vIFRyeSB0byBwYXJzZSB0byBKU09OIGFuZCBjYWxsIHRoZSBkb0V4cG9ydCBmdW5jdGlvblxyXG4gICAgY29uc3QgY2hhcnRKU09OID0gSlNPTi5wYXJzZShzdHJpbmdUb0V4cG9ydC5yZXBsYWNlQWxsKC9cXHR8XFxufFxcci9nLCAnICcpKTtcclxuXHJcbiAgICAvLyBJZiBhIGNvcnJlY3QgSlNPTiwgZG8gdGhlIGV4cG9ydFxyXG4gICAgcmV0dXJuIGRvRXhwb3J0KG9wdGlvbnMsIGNoYXJ0SlNPTiwgZW5kQ2FsbGJhY2spO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAvLyBOb3QgYSB2YWxpZCBKU09OXHJcbiAgICBpZiAodG9Cb29sZWFuKGFsbG93Q29kZUV4ZWN1dGlvbikpIHtcclxuICAgICAgcmV0dXJuIGRvU3RyYWlnaHRJbmplY3Qob3B0aW9ucywgZW5kQ2FsbGJhY2spO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gRG8gbm90IGFsbG93IHN0cmFpZ2h0IGluamVjdGlvbiB3aXRob3V0IHRoZSBhbGxvd0NvZGVFeGVjdXRpb24gZmxhZ1xyXG4gICAgICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICAgICAgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgJ1tjaGFydF0gT25seSBKU09OIGNvbmZpZ3VyYXRpb25zIGFuZCBTVkcgYXJlIGFsbG93ZWQgZm9yIHRoaXMgc2VydmVyLiBJZiB0aGlzIGlzIHlvdXIgc2VydmVyLCBKYXZhU2NyaXB0IGN1c3RvbSBjb2RlIGNhbiBiZSBlbmFibGVkIGJ5IHN0YXJ0aW5nIHRoZSBzZXJ2ZXIgd2l0aCB0aGUgLS1hbGxvd0NvZGVFeGVjdXRpb24gZmxhZy4nXHJcbiAgICAgICAgKS5zZXRFcnJvcihlcnJvcilcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIGFuZCByZXR1cm5zIHRoZSBjdXJyZW50IHN0YXR1cyBvZiBjb2RlIGV4ZWN1dGlvbiBwZXJtaXNzaW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7YW55fSBUaGUgdmFsdWUgb2YgYWxsb3dDb2RlRXhlY3V0aW9uLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldEFsbG93Q29kZUV4ZWN1dGlvbiA9ICgpID0+IGFsbG93Q29kZUV4ZWN1dGlvbjtcclxuXHJcbi8qKlxyXG4gKiBTZXRzIHRoZSBjb2RlIGV4ZWN1dGlvbiBwZXJtaXNzaW9uIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBib29sZWFuIHZhbHVlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge2FueX0gdmFsdWUgLSBUaGUgdmFsdWUgdG8gYmUgY29udmVydGVkIGFuZCBhc3NpZ25lZFxyXG4gKiB0byBhbGxvd0NvZGVFeGVjdXRpb24uXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2V0QWxsb3dDb2RlRXhlY3V0aW9uID0gKHZhbHVlKSA9PiB7XHJcbiAgYWxsb3dDb2RlRXhlY3V0aW9uID0gdG9Cb29sZWFuKHZhbHVlKTtcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBiYXRjaEV4cG9ydCxcclxuICBzaW5nbGVFeHBvcnQsXHJcbiAgZ2V0QWxsb3dDb2RlRXhlY3V0aW9uLFxyXG4gIHNldEFsbG93Q29kZUV4ZWN1dGlvbixcclxuICBzdGFydEV4cG9ydCxcclxuICBmaW5kQ2hhcnRTaXplXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBVc2VkIHRvIHNhbml0aXplIHRoZSBzdHJpbmdzIGNvbWluZyBmcm9tIHRoZSBleHBvcnRpbmcgbW9kdWxlXHJcbiAqIHRvIHByZXZlbnQgWFNTIGF0dGFja3MgKHdpdGggdGhlIERPTVB1cmlmeSBsaWJyYXJ5KS5cclxuICoqL1xyXG5cclxuaW1wb3J0IHsgSlNET00gfSBmcm9tICdqc2RvbSc7XHJcbmltcG9ydCBET01QdXJpZnkgZnJvbSAnZG9tcHVyaWZ5JztcclxuXHJcbi8qKlxyXG4gKiBTYW5pdGl6ZXMgYSBnaXZlbiBIVE1MIHN0cmluZyBieSByZW1vdmluZyA8c2NyaXB0PiB0YWdzLlxyXG4gKiBUaGlzIGZ1bmN0aW9uIHVzZXMgYSByZWd1bGFyIGV4cHJlc3Npb24gdG8gZmluZCBhbmQgcmVtb3ZlIGFsbFxyXG4gKiBvY2N1cnJlbmNlcyBvZiA8c2NyaXB0Pi4uLjwvc2NyaXB0PiB0YWdzIGFuZCBhbnkgY29udGVudCB3aXRoaW4gdGhlbS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGlucHV0IFRoZSBIVE1MIHN0cmluZyB0byBiZSBzYW5pdGl6ZWQuXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBzYW5pdGl6ZWQgSFRNTCBzdHJpbmcuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gc2FuaXRpemUoaW5wdXQpIHtcclxuICBjb25zdCB3aW5kb3cgPSBuZXcgSlNET00oJycpLndpbmRvdztcclxuICBjb25zdCBwdXJpZnkgPSBET01QdXJpZnkod2luZG93KTtcclxuICByZXR1cm4gcHVyaWZ5LnNhbml0aXplKGlucHV0LCB7IEFERF9UQUdTOiBbJ2ZvcmVpZ25PYmplY3QnXSB9KTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQgc2FuaXRpemU7XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5cclxuLy8gQXJyYXkgdGhhdCBjb250YWlucyBpZHMgb2YgYWxsIG9uZ29pbmcgaW50ZXJ2YWxzIGFuZCB0aW1lb3V0c1xyXG5jb25zdCB0aW1lcklkcyA9IFtdO1xyXG5cclxuLyoqXHJcbiAqIEFkZHMgaWQgb2Ygc2V0SW50ZXJ2YWwgb3Igc2V0VGltZW91dCBhbmQgdG8gdGhlIGludGVydmFsSWRzIGFycmF5LlxyXG4gKlxyXG4gKiBAcGFyYW0ge05vZGVKUy5UaW1lb3V0fSBpZCAtIElkIG9mIGFuIGludGVydmFsL3RpbWVvdXQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgYWRkVGltZXIgPSAoaWQpID0+IHtcclxuICB0aW1lcklkcy5wdXNoKGlkKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBDbGVhcnMgYWxsIG9mIG9uZ29pbmcgaW50ZXJ2YWxzIGFuZCB0aW1lb3V0cyBieSBpZHMgZ2F0aGVyZWQgaW4gdGhlIHRpbWVySWRzXHJcbiAqIGFycmF5LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGNsZWFyQWxsVGltZXJzID0gKCkgPT4ge1xyXG4gIGxvZyg0LCBgW3NlcnZlcl0gQ2xlYXJpbmcgYWxsIHJlZ2lzdGVyZWQgaW50ZXJ2YWxzIGFuZCB0aW1lb3V0cy5gKTtcclxuICBmb3IgKGNvbnN0IGlkIG9mIHRpbWVySWRzKSB7XHJcbiAgICBjbGVhckludGVydmFsKGlkKTtcclxuICAgIGNsZWFyVGltZW91dChpZCk7XHJcbiAgfVxyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGFkZFRpbWVyLFxyXG4gIGNsZWFyQWxsVGltZXJzXHJcbn07XHJcbiIsImltcG9ydCB7IGVudnMgfSBmcm9tICcuLi9lbnZzLmpzJztcclxuaW1wb3J0IHsgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi4vbG9nZ2VyLmpzJztcclxuXHJcbi8qKlxyXG4gKiBNaWRkbGV3YXJlIGZvciBsb2dnaW5nIGVycm9ycyB3aXRoIHN0YWNrIHRyYWNlIGFuZCBoYW5kbGluZyBlcnJvciByZXNwb25zZS5cclxuICpcclxuICogQHBhcmFtIHtFcnJvcn0gZXJyb3IgLSBUaGUgZXJyb3Igb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxIC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBuZXh0IC0gVGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICovXHJcbmNvbnN0IGxvZ0Vycm9yTWlkZGxld2FyZSA9IChlcnJvciwgcmVxLCByZXMsIG5leHQpID0+IHtcclxuICAvLyBEaXNwbGF5IHRoZSBlcnJvciB3aXRoIHN0YWNrIGluIGEgY29ycmVjdCBmb3JtYXRcclxuICBsb2dXaXRoU3RhY2soMSwgZXJyb3IpO1xyXG5cclxuICAvLyBEZWxldGUgdGhlIHN0YWNrIGZvciB0aGUgZW52aXJvbm1lbnQgb3RoZXIgdGhhbiB0aGUgZGV2ZWxvcG1lbnRcclxuICBpZiAoZW52cy5PVEhFUl9OT0RFX0VOViAhPT0gJ2RldmVsb3BtZW50Jykge1xyXG4gICAgZGVsZXRlIGVycm9yLnN0YWNrO1xyXG4gIH1cclxuXHJcbiAgLy8gQ2FsbCB0aGUgcmV0dXJuRXJyb3JNaWRkbGV3YXJlXHJcbiAgbmV4dChlcnJvcik7XHJcbn07XHJcblxyXG4vKipcclxuICogTWlkZGxld2FyZSBmb3IgcmV0dXJuaW5nIGVycm9yIHJlc3BvbnNlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0Vycm9yfSBlcnJvciAtIFRoZSBlcnJvciBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXEgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXMgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IG5leHQgLSBUaGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKi9cclxuY29uc3QgcmV0dXJuRXJyb3JNaWRkbGV3YXJlID0gKGVycm9yLCByZXEsIHJlcywgbmV4dCkgPT4ge1xyXG4gIC8vIEdhdGhlciBhbGwgcmVxdWllZCBpbmZvcm1hdGlvbiBmb3IgdGhlIHJlc3BvbnNlXHJcbiAgY29uc3QgeyBzdGF0dXNDb2RlOiBzdENvZGUsIHN0YXR1cywgbWVzc2FnZSwgc3RhY2sgfSA9IGVycm9yO1xyXG4gIGNvbnN0IHN0YXR1c0NvZGUgPSBzdENvZGUgfHwgc3RhdHVzIHx8IDUwMDtcclxuXHJcbiAgLy8gU2V0IGFuZCByZXR1cm4gcmVzcG9uc2VcclxuICByZXMuc3RhdHVzKHN0YXR1c0NvZGUpLmpzb24oeyBzdGF0dXNDb2RlLCBtZXNzYWdlLCBzdGFjayB9KTtcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IChhcHApID0+IHtcclxuICAvLyBBZGQgbG9nIGVycm9yIG1pZGRsZXdhcmVcclxuICBhcHAudXNlKGxvZ0Vycm9yTWlkZGxld2FyZSk7XHJcblxyXG4gIC8vIEFkZCBzZXQgc3RhdHVzIGFuZCByZXR1cm4gZXJyb3IgbWlkZGxld2FyZVxyXG4gIGFwcC51c2UocmV0dXJuRXJyb3JNaWRkbGV3YXJlKTtcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgcmF0ZUxpbWl0IGZyb20gJ2V4cHJlc3MtcmF0ZS1saW1pdCc7XHJcblxyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuLi9sb2dnZXIuanMnO1xyXG5cclxuLyoqXHJcbiAqIE1pZGRsZXdhcmUgZm9yIGVuYWJsaW5nIHJhdGUgbGltaXRpbmcgb24gdGhlIHNwZWNpZmllZCBFeHByZXNzIGFwcC5cclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzfSBhcHAgLSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBsaW1pdENvbmZpZyAtIENvbmZpZ3VyYXRpb24gb3B0aW9ucyBmb3IgcmF0ZSBsaW1pdGluZy5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IChhcHAsIGxpbWl0Q29uZmlnKSA9PiB7XHJcbiAgY29uc3QgbXNnID1cclxuICAgICdUb28gbWFueSByZXF1ZXN0cywgeW91IGhhdmUgYmVlbiByYXRlIGxpbWl0ZWQuIFBsZWFzZSB0cnkgYWdhaW4gbGF0ZXIuJztcclxuXHJcbiAgLy8gT3B0aW9ucyBmb3IgdGhlIHJhdGUgbGltaXRlclxyXG4gIGNvbnN0IHJhdGVPcHRpb25zID0ge1xyXG4gICAgbWF4OiBsaW1pdENvbmZpZy5tYXhSZXF1ZXN0cyB8fCAzMCxcclxuICAgIHdpbmRvdzogbGltaXRDb25maWcud2luZG93IHx8IDEsXHJcbiAgICBkZWxheTogbGltaXRDb25maWcuZGVsYXkgfHwgMCxcclxuICAgIHRydXN0UHJveHk6IGxpbWl0Q29uZmlnLnRydXN0UHJveHkgfHwgZmFsc2UsXHJcbiAgICBza2lwS2V5OiBsaW1pdENvbmZpZy5za2lwS2V5IHx8IGZhbHNlLFxyXG4gICAgc2tpcFRva2VuOiBsaW1pdENvbmZpZy5za2lwVG9rZW4gfHwgZmFsc2VcclxuICB9O1xyXG5cclxuICAvLyBTZXQgaWYgYmVoaW5kIGEgcHJveHlcclxuICBpZiAocmF0ZU9wdGlvbnMudHJ1c3RQcm94eSkge1xyXG4gICAgYXBwLmVuYWJsZSgndHJ1c3QgcHJveHknKTtcclxuICB9XHJcblxyXG4gIC8vIENyZWF0ZSBhIGxpbWl0ZXJcclxuICBjb25zdCBsaW1pdGVyID0gcmF0ZUxpbWl0KHtcclxuICAgIHdpbmRvd01zOiByYXRlT3B0aW9ucy53aW5kb3cgKiA2MCAqIDEwMDAsXHJcbiAgICAvLyBMaW1pdCBlYWNoIElQIHRvIDEwMCByZXF1ZXN0cyBwZXIgd2luZG93TXNcclxuICAgIG1heDogcmF0ZU9wdGlvbnMubWF4LFxyXG4gICAgLy8gRGlzYWJsZSBkZWxheWluZywgZnVsbCBzcGVlZCB1bnRpbCB0aGUgbWF4IGxpbWl0IGlzIHJlYWNoZWRcclxuICAgIGRlbGF5TXM6IHJhdGVPcHRpb25zLmRlbGF5LFxyXG4gICAgaGFuZGxlcjogKHJlcXVlc3QsIHJlc3BvbnNlKSA9PiB7XHJcbiAgICAgIHJlc3BvbnNlLmZvcm1hdCh7XHJcbiAgICAgICAganNvbjogKCkgPT4ge1xyXG4gICAgICAgICAgcmVzcG9uc2Uuc3RhdHVzKDQyOSkuc2VuZCh7IG1lc3NhZ2U6IG1zZyB9KTtcclxuICAgICAgICB9LFxyXG4gICAgICAgIGRlZmF1bHQ6ICgpID0+IHtcclxuICAgICAgICAgIHJlc3BvbnNlLnN0YXR1cyg0MjkpLnNlbmQobXNnKTtcclxuICAgICAgICB9XHJcbiAgICAgIH0pO1xyXG4gICAgfSxcclxuICAgIHNraXA6IChyZXF1ZXN0KSA9PiB7XHJcbiAgICAgIC8vIEFsbG93IGJ5cGFzc2luZyB0aGUgbGltaXRlciBpZiBhIHZhbGlkIGtleS90b2tlbiBoYXMgYmVlbiBzZW50XHJcbiAgICAgIGlmIChcclxuICAgICAgICByYXRlT3B0aW9ucy5za2lwS2V5ICE9PSBmYWxzZSAmJlxyXG4gICAgICAgIHJhdGVPcHRpb25zLnNraXBUb2tlbiAhPT0gZmFsc2UgJiZcclxuICAgICAgICByZXF1ZXN0LnF1ZXJ5LmtleSA9PT0gcmF0ZU9wdGlvbnMuc2tpcEtleSAmJlxyXG4gICAgICAgIHJlcXVlc3QucXVlcnkuYWNjZXNzX3Rva2VuID09PSByYXRlT3B0aW9ucy5za2lwVG9rZW5cclxuICAgICAgKSB7XHJcbiAgICAgICAgbG9nKDQsICdbcmF0ZSBsaW1pdGluZ10gU2tpcHBpbmcgcmF0ZSBsaW1pdGVyLicpO1xyXG4gICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICB9XHJcbiAgICAgIHJldHVybiBmYWxzZTtcclxuICAgIH1cclxuICB9KTtcclxuXHJcbiAgLy8gVXNlIGEgbGltaXRlciBhcyBhIG1pZGRsZXdhcmVcclxuICBhcHAudXNlKGxpbWl0ZXIpO1xyXG5cclxuICBsb2coXHJcbiAgICAzLFxyXG4gICAgYFtyYXRlIGxpbWl0aW5nXSBFbmFibGVkIHJhdGUgbGltaXRpbmcgd2l0aCAke3JhdGVPcHRpb25zLm1heH0gcmVxdWVzdHMgcGVyICR7cmF0ZU9wdGlvbnMud2luZG93fSBtaW51dGUgZm9yIGVhY2ggSVAsIHRydXN0aW5nIHByb3h5OiAke3JhdGVPcHRpb25zLnRydXN0UHJveHl9LmBcclxuICApO1xyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyMywgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IHsgX19kaXJuYW1lIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG4vLyBHZXQgdGhlIHRlbGVtZXRyeSB0ZW1wbGF0ZVxyXG5jb25zdCB0ZWxlbWV0cnlUZW1wbGF0ZSA9IEpTT04ucGFyc2UoXHJcbiAgcmVhZEZpbGVTeW5jKGpvaW4oX19kaXJuYW1lLCAnbGliJywgJ3NjaGVtYXMnLCAndGVsZW1ldHJ5Lmpzb24nKSlcclxuKTtcclxuXHJcbi8vIFRoZSBvYmplY3Qgd2l0aCB0ZWxlbWV0cnkgZGF0YSBjb2xsZWN0ZWRcclxuZXhwb3J0IGNvbnN0IHRlbGVtZXRyeURhdGEgPSB7XHJcbiAgbnVtYmVyT2ZSZXF1ZXN0czogMFxyXG59O1xyXG5cclxuLy8gUG9zc2libGUgcHJvcGVydGllcyBpbiBhbiBhcnJheVxyXG5jb25zdCBvcHRpb25zSW5BcnJheSA9IFsnc2VyaWVzJywgJ3hBeGlzJywgJ3lBeGlzJywgJ3pBeGlzJ107XHJcblxyXG4vLyBSZWN1cnNpdmUgZnVuY3Rpb24gZm9yIGdldHRpbmcgb25seSB0aGUgcmVxdWlyZWQgb3B0aW9uc1xyXG5mdW5jdGlvbiBmaWx0ZXJEYXRhKHRlbXBsYXRlLCBvcHRpb25zKSB7XHJcbiAgY29uc3QgZmlsdGVyZWRPYmplY3QgPSB7fTtcclxuXHJcbiAgLy8gQ3ljbGUgdGhyb3VnaCBhbGxvd2VkIHByb3BldGllc1xyXG4gIGZvciAoY29uc3QgW3RlbXBsYXRlS2V5LCB0ZW1wbGF0ZVZhbHVlXSBvZiBPYmplY3QuZW50cmllcyh0ZW1wbGF0ZSkpIHtcclxuICAgIC8vIENoZWNrIGlmIHRoZSBzZWN0aW9uIGV4aXN0c1xyXG4gICAgaWYgKG9wdGlvbnNbdGVtcGxhdGVLZXldICE9PSB1bmRlZmluZWQpIHtcclxuICAgICAgLy8gQ2hlY2sgaWYgdGhpcyBpcyB0aGUgZmluYWwgbGV2ZWwgb2YgaW5kZW50IGluIHRoZSB0ZW1wbGF0ZVxyXG4gICAgICBpZiAodGVtcGxhdGVWYWx1ZSAhPT0gbnVsbCkge1xyXG4gICAgICAgIC8vIENoZWNrIGlmIGl0IGlzIGFuIGFycmF5XHJcbiAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkob3B0aW9uc1t0ZW1wbGF0ZUtleV0pKSB7XHJcbiAgICAgICAgICAvLyBBbmQgaWYgaXQgY29udGFpbnMgYWxsb3dlZCBwcm9wZXJ0aWVzXHJcbiAgICAgICAgICBpZiAob3B0aW9uc0luQXJyYXkuaW5jbHVkZXModGVtcGxhdGVLZXkpKSB7XHJcbiAgICAgICAgICAgIC8vIENyZWF0ZSBhbiBhcnJheVxyXG4gICAgICAgICAgICBmaWx0ZXJlZE9iamVjdFt0ZW1wbGF0ZUtleV0gPSBbXTtcclxuICAgICAgICAgICAgLy8gSWYgc28sIGN5Y2xlIHRocm91Z2ggYWxsIG9mIHRoZW1cclxuICAgICAgICAgICAgZm9yIChjb25zdCBbaW5kZXgsIG9wdGlvbnNWYWx1ZV0gb2Ygb3B0aW9uc1tcclxuICAgICAgICAgICAgICB0ZW1wbGF0ZUtleVxyXG4gICAgICAgICAgICBdLmVudHJpZXMoKSkge1xyXG4gICAgICAgICAgICAgIGZpbHRlcmVkT2JqZWN0W3RlbXBsYXRlS2V5XVtpbmRleF0gPSBmaWx0ZXJEYXRhKFxyXG4gICAgICAgICAgICAgICAgdGVtcGxhdGVWYWx1ZSxcclxuICAgICAgICAgICAgICAgIG9wdGlvbnNWYWx1ZVxyXG4gICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIC8vIE90aGVyd2lzZSwgZ2V0IG9ubHkgdGhlIGZpcnN0IGVsZW1lbnRcclxuICAgICAgICAgICAgZmlsdGVyZWRPYmplY3RbdGVtcGxhdGVLZXldID0gZmlsdGVyRGF0YShcclxuICAgICAgICAgICAgICB0ZW1wbGF0ZVZhbHVlLFxyXG4gICAgICAgICAgICAgIG9wdGlvbnNbdGVtcGxhdGVLZXldWzBdXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIGZpbHRlcmVkT2JqZWN0W3RlbXBsYXRlS2V5XSA9IGZpbHRlckRhdGEoXHJcbiAgICAgICAgICAgIHRlbXBsYXRlVmFsdWUsXHJcbiAgICAgICAgICAgIG9wdGlvbnNbdGVtcGxhdGVLZXldXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH1cclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICAvLyBSZXR1cm4gdGhlIG9wdGlvblxyXG4gICAgICAgIGZpbHRlcmVkT2JqZWN0W3RlbXBsYXRlS2V5XSA9IG9wdGlvbnNbdGVtcGxhdGVLZXldO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gdGhlIG9iamVjdFxyXG4gIHJldHVybiBmaWx0ZXJlZE9iamVjdDtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIHByZXBhcmVUZWxlbWV0cnkoY2hhcnRPcHRpb25zLCByZXF1ZXN0SWQpIHtcclxuICAvLyBTYXZlIHRoZSBmaWx0ZXJlZCBvcHRpb25zIHVuZGVyIHRoZSByZXF1ZXN0J3MgaWRcclxuICB0ZWxlbWV0cnlEYXRhW3JlcXVlc3RJZF0gPSBmaWx0ZXJEYXRhKHRlbGVtZXRyeVRlbXBsYXRlLCBjaGFydE9wdGlvbnMpO1xyXG5cclxuICAvLyBJbmNyZW1lbnQgcmVxdWVzdHMgY291bnRlclxyXG4gIHRlbGVtZXRyeURhdGEubnVtYmVyT2ZSZXF1ZXN0cysrO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgdGVsZW1ldHJ5RGF0YSxcclxuICBwcmVwYXJlVGVsZW1ldHJ5XHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDIzLCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5pbXBvcnQgand0IGZyb20gJ2pzb253ZWJ0b2tlbic7XHJcbmltcG9ydCB7IHY0IGFzIHV1aWQgfSBmcm9tICd1dWlkJztcclxuaW1wb3J0IFdlYlNvY2tldCBmcm9tICd3cyc7XHJcblxyXG5pbXBvcnQgeyBnZXRPcHRpb25zIH0gZnJvbSAnLi4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyB0ZWxlbWV0cnlEYXRhIH0gZnJvbSAnLi4vdGVsZW1ldHJ5LmpzJztcclxuaW1wb3J0IHsgYWRkVGltZXIgfSBmcm9tICcuLi90aW1lcnMuanMnO1xyXG5cclxuLy8gV2ViU29ja2V0IGNsaWVudHMgbWFwXHJcbmNvbnN0IHdlYlNvY2tldENsaWVudHMgPSBuZXcgTWFwKCk7XHJcblxyXG4vLyBXZWJTb2NrZXQgb3B0aW9uc1xyXG5sZXQgd2ViU29ja2V0T3B0aW9ucztcclxuXHJcbi8vIFdlYlNvY2tldCBtZXNzYWdlIHNlbmRpbmcgaW50ZXJ2YWxcclxubGV0IG1lc3NhZ2VJbnRlcnZhbCA9IG51bGw7XHJcblxyXG4vKipcclxuICogSW5pdCBXZWJTb2NrZXQgY2xpZW50IGFuZCBjb25uZWN0aW9uIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7b2JqZWN0fSBhZGRyZXNzIC0gT2JqZWN0IHRoYXQgY29udGFpbnMsIGFkZHJlc3MgYW5kIHBvcnQgb2YgZW5hYmxlZFxyXG4gKiBIVFRQIG9yIEhUVFBTIHNlcnZlci5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBpbml0KGFkZHJlc3MpIHtcclxuICB3ZWJTb2NrZXRPcHRpb25zID0gZ2V0T3B0aW9ucygpLndlYlNvY2tldDtcclxuICBpZiAod2ViU29ja2V0T3B0aW9ucy5lbmFibGUgPT09IHRydWUpIHtcclxuICAgIC8vIE9wdGlvbnMgZm9yIHRoZSBXZWJTb2NrZXQgY29ubmVjdGlvblxyXG4gICAgY29uc3QgY29ubmVjdGlvbk9wdGlvbnMgPSB7XHJcbiAgICAgIHJlamVjdFVuYXV0aG9yaXplZDogd2ViU29ja2V0T3B0aW9ucy5yZWplY3RVbmF1dGhvcml6ZWQsXHJcbiAgICAgIGhlYWRlcnM6IHtcclxuICAgICAgICAvLyBTZXQgYW4gYWNjZXNzIHRva2VuIHRoYXQgbGFzdHMgb25seSA1IG1pbnV0ZXNcclxuICAgICAgICBhdXRoOiBqd3Quc2lnbih7IHN1Y2Nlc3M6ICdzdWNjZXNzJyB9LCB3ZWJTb2NrZXRPcHRpb25zLnNlY3JldCwge1xyXG4gICAgICAgICAgYWxnb3JpdGhtOiAnSFMyNTYnXHJcbiAgICAgICAgfSksXHJcbiAgICAgICAgLy8gU2VuZCB0aGUgc2VydmVyIGFkZHJlc3MgaW4gYSBjdXN0b20gaGVhZGVyXHJcbiAgICAgICAgJ1gtU2VydmVyLUFkZHJlc3MnOiBgJHthZGRyZXNzLnByb3RvY29sfTovLyR7XHJcbiAgICAgICAgICBbJzo6JywgJzAuMC4wLjAnXS5pbmNsdWRlcyhhZGRyZXNzLmFkZHJlc3MpXHJcbiAgICAgICAgICAgID8gJ2xvY2FsaG9zdCdcclxuICAgICAgICAgICAgOiBhZGRyZXNzLmFkZHJlc3NcclxuICAgICAgICB9OiR7YWRkcmVzcy5wb3J0fWBcclxuICAgICAgfVxyXG4gICAgfTtcclxuXHJcbiAgICAvLyBPcHRpb25zIGZvciB0aGUgV2ViU29ja2V0IGNsaWVudFxyXG4gICAgY29uc3QgY2xpZW50T3B0aW9ucyA9IHtcclxuICAgICAgaWQ6IHV1aWQoKSxcclxuICAgICAgcmVjb25uZWN0OiB3ZWJTb2NrZXRPcHRpb25zLnJlY29ubmVjdCxcclxuICAgICAgcmVjb25uZWN0VHJ5OiAwLFxyXG4gICAgICByZWNvbm5lY3RJbnRlcnZhbDogbnVsbCxcclxuICAgICAgcGluZ1RpbWVvdXQ6IG51bGxcclxuICAgIH07XHJcblxyXG4gICAgLy8gU3RhcnQgdGhlIFdlYlNvY2tldCBjb25uZWN0aW9uXHJcbiAgICBjb25uZWN0KHdlYlNvY2tldE9wdGlvbnMudXJsLCBjb25uZWN0aW9uT3B0aW9ucywgY2xpZW50T3B0aW9ucyk7XHJcblxyXG4gICAgLy8gU3RhcnQgdGhlIFdlYlNvY2tldCBtZXNzYWdlIHNlbmRpbmcgaW50ZXJ2YWxcclxuICAgIHNlbmRpbmdNZXNzYWdlSW50ZXJ2YWwod2ViU29ja2V0T3B0aW9ucyk7XHJcbiAgfVxyXG59XHJcblxyXG5mdW5jdGlvbiBzZW5kaW5nTWVzc2FnZUludGVydmFsKHdlYlNvY2tldE9wdGlvbnMpIHtcclxuICAvLyBTZXQgdGhlIHNlbmRpbmcgbWVzc2FnZSBpbnRlcnZhbFxyXG4gIG1lc3NhZ2VJbnRlcnZhbCA9IHNldEludGVydmFsKCgpID0+IHtcclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIEdldCB0aGUgZmlyc3QgV2ViU29ja2V0IGNsaWVudFxyXG4gICAgICBjb25zdCB3ZWJTb2NrZXRDbGllbnQgPSBnZXRDbGllbnRzKCkubmV4dCgpLnZhbHVlO1xyXG4gICAgICAvLyBJZiB0aGUgY2xpZW50IGlzIGZvdW5kLCBvcGVuIGFuZCB0aGVyZSBpcyBkYXRhIHRvIHNlbmRcclxuICAgICAgaWYgKFxyXG4gICAgICAgIHdlYlNvY2tldENsaWVudCAmJlxyXG4gICAgICAgIHdlYlNvY2tldENsaWVudC5yZWFkeVN0YXRlID09PSBXZWJTb2NrZXQuT1BFTiAmJlxyXG4gICAgICAgIE9iamVjdC5rZXlzKHRlbGVtZXRyeURhdGEpLmxlbmd0aCA+IDEgJiZcclxuICAgICAgICB0ZWxlbWV0cnlEYXRhLm51bWJlck9mUmVxdWVzdHMgPiAwXHJcbiAgICAgICkge1xyXG4gICAgICAgIC8vIFNlbmQgdGhyb3VnaCB0aGUgV2ViU29ja2V0XHJcbiAgICAgICAgd2ViU29ja2V0Q2xpZW50LnNlbmQoSlNPTi5zdHJpbmdpZnkodGVsZW1ldHJ5RGF0YSkpO1xyXG4gICAgICB9XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBsb2dXaXRoU3RhY2soMSwgYFt3ZWJzb2NrZXRdIENvdWxkIG5vdCBzZW5kIGRhdGEgdGhyb3VnaCBXZWJTb2NrZXQuYCk7XHJcbiAgICB9XHJcbiAgfSwgd2ViU29ja2V0T3B0aW9ucy5tZXNzYWdlSW50ZXJ2YWwpO1xyXG5cclxuICAvLyBSZWdpc3RlciBpbnRlcnZhbCBmb3IgdGhlIGxhdGVyIGNsZWFyaW5nXHJcbiAgYWRkVGltZXIobWVzc2FnZUludGVydmFsKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgV2ViU29ja2V0IGNsaWVudCBhbmQgY29ubmVjdHMgdG8gV2ViU29ja2V0IHNlcnZlciBvbiBhIHByb3ZpZGVkIHVybC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHdlYlNvY2tldFVybCAtIFRoZSBXZWJTb2NrZXQgc2VydmVyJ3MgVVJMLlxyXG4gKiBAcGFyYW0ge29iamVjdH0gY29ubmVjdGlvbk9wdGlvbnMgLSBPcHRpb25zIGZvciBXZWJTb2NrZXQgY29ubmVjdGlvbi5cclxuICogQHBhcmFtIHtvYmplY3R9IGNsaWVudE9wdGlvbnMgLSBPcHRpb25zIGZvciBXZWJTb2NrZXQgY2xpZW50LlxyXG4gKi9cclxuZnVuY3Rpb24gY29ubmVjdCh3ZWJTb2NrZXRVcmwsIGNvbm5lY3Rpb25PcHRpb25zLCBjbGllbnRPcHRpb25zKSB7XHJcbiAgLy8gVHJ5IHRvIGNvbm5lY3QgdG8gaW5kaWNhdGVkIFdlYlNvY2tldCBzZXJ2ZXJcclxuICBsZXQgd2ViU29ja2V0Q2xpZW50ID0gbmV3IFdlYlNvY2tldCh3ZWJTb2NrZXRVcmwsIGNvbm5lY3Rpb25PcHRpb25zKTtcclxuXHJcbiAgLy8gT3BlbiBldmVudFxyXG4gIHdlYlNvY2tldENsaWVudC5vbignb3BlbicsICgpID0+IHtcclxuICAgIC8vIE5vdCBuZWVkIGZvciB0aGUgcmVjb25uZWN0IGludGVydmFsIGFueW1vcmVcclxuICAgIGNsZWFySW50ZXJ2YWwoY2xpZW50T3B0aW9ucy5yZWNvbm5lY3RJbnRlcnZhbCk7XHJcblxyXG4gICAgLy8gU2F2ZSB0aGUgY2xpZW50IHVuZGVyIGl0cyBpZFxyXG4gICAgd2ViU29ja2V0Q2xpZW50cy5zZXQoY2xpZW50T3B0aW9ucy5pZCwgd2ViU29ja2V0Q2xpZW50KTtcclxuXHJcbiAgICAvLyBMb2cgYSBzdWNjZXNzIG1lc3NhZ2VcclxuICAgIGxvZyhcclxuICAgICAgMyxcclxuICAgICAgYFt3ZWJzb2NrZXRdIFdlYlNvY2tldDogJHtjbGllbnRPcHRpb25zLmlkfSAtIENvbm5lY3RlZCB0byBzZXJ2ZXI6ICR7d2ViU29ja2V0VXJsfS5gXHJcbiAgICApO1xyXG4gIH0pO1xyXG5cclxuICAvLyBDbG9zZSBldmVudCB3aGVyZSBwaW5nIHRpbWVvdXQgaXMgY2xlYXJlZFxyXG4gIHdlYlNvY2tldENsaWVudC5vbignY2xvc2UnLCAoY29kZSkgPT4ge1xyXG4gICAgbG9nKFxyXG4gICAgICAzLFxyXG4gICAgICAnW3dlYnNvY2tldF0nLFxyXG4gICAgICBgV2ViU29ja2V0OiAke2NsaWVudE9wdGlvbnMuaWR9IC0gRGlzY29ubmVjdGVkIGZyb20gc2VydmVyOiAke3dlYlNvY2tldFVybH0gd2l0aCBjb2RlOiAke2NvZGV9LmBcclxuICAgICk7XHJcblxyXG4gICAgLy8gU3RvcCB0aGUgaGVhcnRiZWF0IG1lY2hhbmlzbVxyXG4gICAgY2xlYXJUaW1lb3V0KGNsaWVudE9wdGlvbnMucGluZ1RpbWVvdXQpO1xyXG5cclxuICAgIC8vIFJlbW92ZWQgY2xpZW50IGlmIGV4aXN0c1xyXG4gICAgd2ViU29ja2V0Q2xpZW50cy5kZWxldGUoY2xpZW50T3B0aW9ucy5pZCk7XHJcbiAgICB3ZWJTb2NrZXRDbGllbnQgPSBudWxsO1xyXG5cclxuICAgIC8vIFRyeSB0byByZWNvbm5lY3Qgb25seSB3aGVuIGVuYWJsZWQgYW5kIGlmIG5vdCBhbHJlYWR5IGF0dGVtcHRpbmcgdG8gZG8gc29cclxuICAgIGlmIChjbGllbnRPcHRpb25zLnJlY29ubmVjdCAmJiAhY2xpZW50T3B0aW9ucy5yZWNvbm5lY3RJbnRlcnZhbCkge1xyXG4gICAgICByZWNvbm5lY3Qod2ViU29ja2V0VXJsLCBjb25uZWN0aW9uT3B0aW9ucywgY2xpZW50T3B0aW9ucyk7XHJcbiAgICB9XHJcbiAgfSk7XHJcblxyXG4gIC8vIEVycm9yIGV2ZW50XHJcbiAgd2ViU29ja2V0Q2xpZW50Lm9uKCdlcnJvcicsIChlcnJvcikgPT4ge1xyXG4gICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAxLFxyXG4gICAgICBlcnJvcixcclxuICAgICAgYFt3ZWJzb2NrZXRdIFdlYlNvY2tldDogJHtjbGllbnRPcHRpb25zLmlkfSAtIEVycm9yIG9jY3VyZWQuYFxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBCbG9jayB0aGUgcmVjb25uZWN0IG1lY2hhbmlzbSB3aGVuIGdldHRpbmcgNDAzXHJcbiAgICBpZiAoZXJyb3IubWVzc2FnZS5pbmNsdWRlcygnNDAzJykpIHtcclxuICAgICAgY2xpZW50T3B0aW9ucy5yZWNvbm5lY3QgPSBmYWxzZTtcclxuICAgICAgY2xpZW50T3B0aW9ucy5yZWNvbm5lY3RUcnkgPSB3ZWJTb2NrZXRPcHRpb25zLnJlY29ubmVjdEF0dGVtcHRzO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gT3Igc2V0IHRoZSBvcHRpb24gYWNjb3JkaW5nbHlcclxuICAgICAgY2xpZW50T3B0aW9ucy5yZWNvbm5lY3QgPSB3ZWJTb2NrZXRPcHRpb25zLnJlY29ubmVjdDtcclxuICAgIH1cclxuICB9KTtcclxuXHJcbiAgLy8gTWVzc2FnZSBldmVudFxyXG4gIHdlYlNvY2tldENsaWVudC5vbignbWVzc2FnZScsIChtZXNzYWdlKSA9PiB7XHJcbiAgICBsb2coXHJcbiAgICAgIDMsXHJcbiAgICAgIGBbd2Vic29ja2V0XSBXZWJTb2NrZXQ6ICR7Y2xpZW50T3B0aW9ucy5pZH0gLSBEYXRhIHJlY2VpdmVkOiAke21lc3NhZ2V9YFxyXG4gICAgKTtcclxuICB9KTtcclxuXHJcbiAgLy8gVGhlICdwaW5nJyBldmVudCBmcm9tIGEgV2ViU29ja2V0IGNvbm5lY3Rpb24gd2l0aCB0aGUgaGVhbHRoIGNoZWNrXHJcbiAgLy8gYW5kIHRlcm1pbmF0aW9uIGxvZ2ljXHJcbiAgd2ViU29ja2V0Q2xpZW50Lm9uKCdwaW5nJywgKCkgPT4ge1xyXG4gICAgbG9nKFxyXG4gICAgICAzLFxyXG4gICAgICBgW3dlYnNvY2tldF0gV2ViU29ja2V0OiAke2NsaWVudE9wdGlvbnMuaWR9IC0gUmVjZWl2ZWQgUElORyBmcm9tIHNlcnZlcjogJHt3ZWJTb2NrZXRVcmx9LmBcclxuICAgICk7XHJcbiAgICBjbGVhclRpbWVvdXQoY2xpZW50T3B0aW9ucy5waW5nVGltZW91dCk7XHJcbiAgICBjbGllbnRPcHRpb25zLnBpbmdUaW1lb3V0ID0gc2V0VGltZW91dCgoKSA9PiB7XHJcbiAgICAgIC8vIFRlcm1pbmF0ZSB0aGUgY2xpZW50IGNvbm5lY3Rpb25cclxuICAgICAgd2ViU29ja2V0Q2xpZW50LnRlcm1pbmF0ZSgpO1xyXG5cclxuICAgICAgLy8gVHJ5IHRvIHJlY29ubmVjdCBpZiByZXF1aXJlZFxyXG4gICAgICBpZiAoY2xpZW50T3B0aW9ucy5yZWNvbm5lY3QpIHtcclxuICAgICAgICByZWNvbm5lY3Qod2ViU29ja2V0VXJsLCBjb25uZWN0aW9uT3B0aW9ucywgY2xpZW50T3B0aW9ucyk7XHJcbiAgICAgIH1cclxuICAgIH0sIHdlYlNvY2tldE9wdGlvbnMucGluZ1RpbWVvdXQpO1xyXG4gIH0pO1xyXG59XHJcblxyXG4vKipcclxuICogUmVjb25uZWN0cyB0byBXZWJTb2NrZXQgc2VydmVyIG9uIGEgcHJvdmlkZWQgdXJsLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gd2ViU29ja2V0VXJsIC0gVGhlIFdlYlNvY2tldCBzZXJ2ZXIncyBVUkwuXHJcbiAqIEBwYXJhbSB7b2JqZWN0fSBjb25uZWN0aW9uT3B0aW9ucyAtIE9wdGlvbnMgZm9yIFdlYlNvY2tldCBjb25uZWN0aW9uLlxyXG4gKiBAcGFyYW0ge29iamVjdH0gY2xpZW50T3B0aW9ucyAtIE9wdGlvbnMgZm9yIFdlYlNvY2tldCBjbGllbnQuXHJcbiAqL1xyXG5mdW5jdGlvbiByZWNvbm5lY3Qod2ViU29ja2V0VXJsLCBjb25uZWN0aW9uT3B0aW9ucywgY2xpZW50T3B0aW9ucykge1xyXG4gIC8vIFN0YXJ0IHRoZSByZWNvbm5lY3QgaW50ZXJ2YWxcclxuICBjbGllbnRPcHRpb25zLnJlY29ubmVjdEludGVydmFsID0gc2V0SW50ZXJ2YWwoKCkgPT4ge1xyXG4gICAgaWYgKGNsaWVudE9wdGlvbnMucmVjb25uZWN0VHJ5IDwgd2ViU29ja2V0T3B0aW9ucy5yZWNvbm5lY3RBdHRlbXB0cykge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgMyxcclxuICAgICAgICBgW3dlYnNvY2tldF0gV2ViU29ja2V0OiAke2NsaWVudE9wdGlvbnMuaWR9IC0gQXR0ZW1wdCAkeysrY2xpZW50T3B0aW9ucy5yZWNvbm5lY3RUcnl9IG9mICR7d2ViU29ja2V0T3B0aW9ucy5yZWNvbm5lY3RBdHRlbXB0c30gdG8gcmVjb25uZWN0IHRvIHNlcnZlcjogJHt3ZWJTb2NrZXRVcmx9LmBcclxuICAgICAgKTtcclxuXHJcbiAgICAgIGNvbm5lY3Qod2ViU29ja2V0VXJsLCBjb25uZWN0aW9uT3B0aW9ucywgY2xpZW50T3B0aW9ucyk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBjbGllbnRPcHRpb25zLnJlY29ubmVjdCA9IGZhbHNlO1xyXG4gICAgICBjbGVhckludGVydmFsKGNsaWVudE9wdGlvbnMucmVjb25uZWN0SW50ZXJ2YWwpO1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgMixcclxuICAgICAgICBgW3dlYnNvY2tldF0gV2ViU29ja2V0OiAke2NsaWVudE9wdGlvbnMuaWR9IC0gQ291bGQgbm90IHJlY29ubmVjdCB0byBzZXJ2ZXI6ICR7d2ViU29ja2V0VXJsfS5gXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfSwgd2ViU29ja2V0T3B0aW9ucy5yZWNvbm5lY3RJbnRlcnZhbCk7XHJcblxyXG4gIC8vIFJlZ2lzdGVyIGludGVydmFsIGZvciB0aGUgbGF0ZXIgY2xlYXJpbmdcclxuICBhZGRUaW1lcihjbGllbnRPcHRpb25zLnJlY29ubmVjdEludGVydmFsKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEdldHMgbWFwIG9mIGN1cnJlbnQgV2ViU29ja2V0IGNsaWVudHMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBpZCAtIFRoZSB1dWlkIG9mIFdlYlNvY2tldCBjbGllbnQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0Q2xpZW50cyhpZCkge1xyXG4gIHJldHVybiBpZCA/IHdlYlNvY2tldENsaWVudHMuZ2V0KGlkKSA6IHdlYlNvY2tldENsaWVudHMudmFsdWVzKCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBUZXJtaW5hdGVzIGFsbCBXZWJTb2NrZXQgY2xpZW50cyBhbmQgY2xlYXIgdGhlIHdlYlNvY2tldENsaWVudHMgbWFwLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHRlcm1pbmF0ZUNsaWVudHMoKSB7XHJcbiAgZm9yIChjb25zdCBjbGllbnQgb2Ygd2ViU29ja2V0Q2xpZW50cy52YWx1ZXMoKSkge1xyXG4gICAgY2xpZW50LnRlcm1pbmF0ZSgpO1xyXG4gIH1cclxuICB3ZWJTb2NrZXRDbGllbnRzLmNsZWFyKCk7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBpbml0LFxyXG4gIGNvbm5lY3QsXHJcbiAgZ2V0Q2xpZW50c1xyXG59O1xyXG4iLCJpbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG5jbGFzcyBIdHRwRXJyb3IgZXh0ZW5kcyBFeHBvcnRFcnJvciB7XHJcbiAgY29uc3RydWN0b3IobWVzc2FnZSwgc3RhdHVzKSB7XHJcbiAgICBzdXBlcihtZXNzYWdlKTtcclxuICAgIHRoaXMuc3RhdHVzID0gdGhpcy5zdGF0dXNDb2RlID0gc3RhdHVzO1xyXG4gIH1cclxuXHJcbiAgc2V0U3RhdHVzKHN0YXR1cykge1xyXG4gICAgdGhpcy5zdGF0dXMgPSBzdGF0dXM7XHJcbiAgICByZXR1cm4gdGhpcztcclxuICB9XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IEh0dHBFcnJvcjtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyB1cGRhdGVWZXJzaW9uLCB2ZXJzaW9uIH0gZnJvbSAnLi4vLi4vY2FjaGUuanMnO1xyXG5pbXBvcnQgeyBlbnZzIH0gZnJvbSAnLi4vLi4vZW52cy5qcyc7XHJcblxyXG5pbXBvcnQgSHR0cEVycm9yIGZyb20gJy4uLy4uL2Vycm9ycy9IdHRwRXJyb3IuanMnO1xyXG5cclxuLyoqXHJcbiAqIEFkZHMgdGhlIFBPU1QgL2NoYW5nZV9oY192ZXJzaW9uLzpuZXdWZXJzaW9uIHJvdXRlIHRoYXQgY2FuIGJlIHV0aWxpemVkIHRvIG1vZGlmeVxyXG4gKiB0aGUgSGlnaGNoYXJ0cyB2ZXJzaW9uIG9uIHRoZSBzZXJ2ZXIuXHJcbiAqXHJcbiAqIFRPRE86IEFkZCBhdXRoIHRva2VuIGFuZCBjb25uZWN0IHRvIEFQSVxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgKGFwcCkgPT5cclxuICAhYXBwXHJcbiAgICA/IGZhbHNlXHJcbiAgICA6IGFwcC5wb3N0KFxyXG4gICAgICAgICcvdmVyc2lvbi9jaGFuZ2UvOm5ld1ZlcnNpb24nLFxyXG4gICAgICAgIGFzeW5jIChyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkgPT4ge1xyXG4gICAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgY29uc3QgYWRtaW5Ub2tlbiA9IGVudnMuSElHSENIQVJUU19BRE1JTl9UT0tFTjtcclxuXHJcbiAgICAgICAgICAgIC8vIENoZWNrIHRoZSBleGlzdGVuY2Ugb2YgdGhlIHRva2VuXHJcbiAgICAgICAgICAgIGlmICghYWRtaW5Ub2tlbiB8fCAhYWRtaW5Ub2tlbi5sZW5ndGgpIHtcclxuICAgICAgICAgICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgICAgICAgICAgJ1RoZSBzZXJ2ZXIgaXMgbm90IGNvbmZpZ3VyZWQgdG8gcGVyZm9ybSBydW4tdGltZSB2ZXJzaW9uIGNoYW5nZXM6IEhJR0hDSEFSVFNfQURNSU5fVE9LRU4gaXMgbm90IHNldC4nLFxyXG4gICAgICAgICAgICAgICAgNDAxXHJcbiAgICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgLy8gQ2hlY2sgaWYgdGhlIGhjLWF1dGggaGVhZGVyIGNvbnRhaW4gYSBjb3JyZWN0IHRva2VuXHJcbiAgICAgICAgICAgIGNvbnN0IHRva2VuID0gcmVxdWVzdC5nZXQoJ2hjLWF1dGgnKTtcclxuICAgICAgICAgICAgaWYgKCF0b2tlbiB8fCB0b2tlbiAhPT0gYWRtaW5Ub2tlbikge1xyXG4gICAgICAgICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgICAgICAgICAnSW52YWxpZCBvciBtaXNzaW5nIHRva2VuOiBTZXQgdGhlIHRva2VuIGluIHRoZSBoYy1hdXRoIGhlYWRlci4nLFxyXG4gICAgICAgICAgICAgICAgNDAxXHJcbiAgICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgLy8gQ29tcGFyZSB2ZXJzaW9uc1xyXG4gICAgICAgICAgICBjb25zdCBuZXdWZXJzaW9uID0gcmVxdWVzdC5wYXJhbXMubmV3VmVyc2lvbjtcclxuICAgICAgICAgICAgaWYgKG5ld1ZlcnNpb24pIHtcclxuICAgICAgICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGltcG9ydC9uby1uYW1lZC1hcy1kZWZhdWx0LW1lbWJlclxyXG4gICAgICAgICAgICAgICAgYXdhaXQgdXBkYXRlVmVyc2lvbihuZXdWZXJzaW9uKTtcclxuICAgICAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAgICAgICAgICAgYFZlcnNpb24gY2hhbmdlOiAke2Vycm9yLm1lc3NhZ2V9YCxcclxuICAgICAgICAgICAgICAgICAgZXJyb3Iuc3RhdHVzQ29kZVxyXG4gICAgICAgICAgICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAvLyBTdWNjZXNzXHJcbiAgICAgICAgICAgICAgcmVzcG9uc2Uuc3RhdHVzKDIwMCkuc2VuZCh7XHJcbiAgICAgICAgICAgICAgICBzdGF0dXNDb2RlOiAyMDAsXHJcbiAgICAgICAgICAgICAgICB2ZXJzaW9uOiB2ZXJzaW9uKCksXHJcbiAgICAgICAgICAgICAgICBtZXNzYWdlOiBgU3VjY2Vzc2Z1bGx5IHVwZGF0ZWQgSGlnaGNoYXJ0cyB0byB2ZXJzaW9uOiAke25ld1ZlcnNpb259LmBcclxuICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAvLyBObyB2ZXJzaW9uIHNwZWNpZmllZFxyXG4gICAgICAgICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoJ05vIG5ldyB2ZXJzaW9uIHN1cHBsaWVkLicsIDQwMCk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICAgIG5leHQoZXJyb3IpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgKTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyB2NCBhcyB1dWlkIH0gZnJvbSAndXVpZCc7XHJcblxyXG5pbXBvcnQgeyBnZXRBbGxvd0NvZGVFeGVjdXRpb24sIHN0YXJ0RXhwb3J0IH0gZnJvbSAnLi4vLi4vY2hhcnQuanMnO1xyXG5pbXBvcnQgeyBnZXRPcHRpb25zLCBtZXJnZUNvbmZpZ09wdGlvbnMgfSBmcm9tICcuLi8uLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuLi8uLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBwcmVwYXJlVGVsZW1ldHJ5IH0gZnJvbSAnLi4vLi4vdGVsZW1ldHJ5LmpzJztcclxuaW1wb3J0IHtcclxuICBmaXhUeXBlLFxyXG4gIGlzQ29ycmVjdEpTT04sXHJcbiAgaXNPYmplY3RFbXB0eSxcclxuICBpc1ByaXZhdGVSYW5nZVVybEZvdW5kLFxyXG4gIG9wdGlvbnNTdHJpbmdpZnksXHJcbiAgbWVhc3VyZVRpbWVcclxufSBmcm9tICcuLi8uLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgSHR0cEVycm9yIGZyb20gJy4uLy4uL2Vycm9ycy9IdHRwRXJyb3IuanMnO1xyXG5cclxuLy8gUmV2ZXJzZWQgTUlNRSB0eXBlc1xyXG5jb25zdCByZXZlcnNlZE1pbWUgPSB7XHJcbiAgcG5nOiAnaW1hZ2UvcG5nJyxcclxuICBqcGVnOiAnaW1hZ2UvanBlZycsXHJcbiAgZ2lmOiAnaW1hZ2UvZ2lmJyxcclxuICBwZGY6ICdhcHBsaWNhdGlvbi9wZGYnLFxyXG4gIHN2ZzogJ2ltYWdlL3N2Zyt4bWwnXHJcbn07XHJcblxyXG4vLyBUaGUgcmVxdWVzdHMgY291bnRlclxyXG5sZXQgcmVxdWVzdHNDb3VudGVyID0gMDtcclxuXHJcbi8vIFRoZSBhcnJheSBvZiBjYWxsYmFja3MgdG8gY2FsbCBiZWZvcmUgYSByZXF1ZXN0XHJcbmNvbnN0IGJlZm9yZVJlcXVlc3QgPSBbXTtcclxuXHJcbi8vIFRoZSBhcnJheSBvZiBjYWxsYmFja3MgdG8gY2FsbCBhZnRlciBhIHJlcXVlc3RcclxuY29uc3QgYWZ0ZXJSZXF1ZXN0ID0gW107XHJcblxyXG4vKipcclxuICogSW52b2tlcyBhbiBhcnJheSBvZiBjYWxsYmFjayBmdW5jdGlvbnMgd2l0aCBzcGVjaWZpZWQgcGFyYW1ldGVycywgYWxsb3dpbmdcclxuICogY3VzdG9taXphdGlvbiBvZiByZXF1ZXN0IGhhbmRsaW5nLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9uW119IGNhbGxiYWNrcyAtIEFuIGFycmF5IG9mIGNhbGxiYWNrIGZ1bmN0aW9uc1xyXG4gKiB0byBiZSBleGVjdXRlZC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcXVlc3QgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXNwb25zZSAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cclxuICogQHBhcmFtIHtPYmplY3R9IGRhdGEgLSBBbiBvYmplY3QgY29udGFpbmluZyBwYXJhbWV0ZXJzIGxpa2UgaWQsIHVuaXF1ZUlkLFxyXG4gKiB0eXBlLCBhbmQgYm9keS5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IC0gUmV0dXJucyBhIGJvb2xlYW4gaW5kaWNhdGluZyB0aGUgb3ZlcmFsbCByZXN1bHRcclxuICogb2YgdGhlIGNhbGxiYWNrIGludm9jYXRpb25zLlxyXG4gKi9cclxuY29uc3QgZG9DYWxsYmFja3MgPSAoY2FsbGJhY2tzLCByZXF1ZXN0LCByZXNwb25zZSwgZGF0YSkgPT4ge1xyXG4gIGxldCByZXN1bHQgPSB0cnVlO1xyXG4gIGNvbnN0IHsgaWQsIHVuaXF1ZUlkLCB0eXBlLCBib2R5IH0gPSBkYXRhO1xyXG5cclxuICBjYWxsYmFja3Muc29tZSgoY2FsbGJhY2spID0+IHtcclxuICAgIGlmIChjYWxsYmFjaykge1xyXG4gICAgICBsZXQgY2FsbFJlc3BvbnNlID0gY2FsbGJhY2socmVxdWVzdCwgcmVzcG9uc2UsIGlkLCB1bmlxdWVJZCwgdHlwZSwgYm9keSk7XHJcblxyXG4gICAgICBpZiAoY2FsbFJlc3BvbnNlICE9PSB1bmRlZmluZWQgJiYgY2FsbFJlc3BvbnNlICE9PSB0cnVlKSB7XHJcbiAgICAgICAgcmVzdWx0ID0gY2FsbFJlc3BvbnNlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICByZXR1cm4gdHJ1ZTtcclxuICAgIH1cclxuICB9KTtcclxuXHJcbiAgcmV0dXJuIHJlc3VsdDtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBIYW5kbGVzIHRoZSBleHBvcnQgcmVxdWVzdHMgZnJvbSB0aGUgY2xpZW50LlxyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxdWVzdCAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlc3BvbnNlIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBuZXh0IC0gVGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IC0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgZXhwb3J0IHByb2Nlc3NcclxuICogaXMgY29tcGxldGUuXHJcbiAqL1xyXG5jb25zdCBleHBvcnRIYW5kbGVyID0gYXN5bmMgKHJlcXVlc3QsIHJlc3BvbnNlLCBuZXh0KSA9PiB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIFN0YXJ0IGNvdW50aW5nIHRpbWVcclxuICAgIGNvbnN0IHN0b3BDb3VudGVyID0gbWVhc3VyZVRpbWUoKTtcclxuXHJcbiAgICAvLyBDcmVhdGUgYSB1bmlxdWUgSUQgZm9yIGEgcmVxdWVzdFxyXG4gICAgY29uc3QgdW5pcXVlSWQgPSB1dWlkKCkucmVwbGFjZSgvLS9nLCAnJyk7XHJcblxyXG4gICAgLy8gR2V0IHRoZSBjdXJyZW50IHNlcnZlcidzIGdlbmVyYWwgb3B0aW9uc1xyXG4gICAgY29uc3QgZGVmYXVsdE9wdGlvbnMgPSBnZXRPcHRpb25zKCk7XHJcbiAgICBjb25zdCBib2R5ID0gcmVxdWVzdC5ib2R5O1xyXG4gICAgY29uc3QgaWQgPSArK3JlcXVlc3RzQ291bnRlcjtcclxuXHJcbiAgICBsZXQgdHlwZSA9IGZpeFR5cGUoYm9keS50eXBlKTtcclxuXHJcbiAgICAvLyBUaHJvdyAnQmFkIFJlcXVlc3QnIGlmIHRoZXJlJ3Mgbm8gYm9keVxyXG4gICAgaWYgKCFib2R5IHx8IGlzT2JqZWN0RW1wdHkoYm9keSkpIHtcclxuICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAnVGhlIHJlcXVlc3QgYm9keSBpcyByZXF1aXJlZC4gUGxlYXNlIGVuc3VyZSB0aGF0IHlvdXIgQ29udGVudC1UeXBlIGhlYWRlciBpcyBjb3JyZWN0IChhY2NlcHRlZCB0eXBlcyBhcmUgYXBwbGljYXRpb24vanNvbiBhbmQgbXVsdGlwYXJ0L2Zvcm0tZGF0YSkuJyxcclxuICAgICAgICA0MDBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBBbGwgb2YgdGhlIGJlbG93IGNhbiBiZSB1c2VkXHJcbiAgICBsZXQgaW5zdHIgPSBpc0NvcnJlY3RKU09OKGJvZHkuaW5maWxlIHx8IGJvZHkub3B0aW9ucyB8fCBib2R5LmRhdGEpO1xyXG5cclxuICAgIC8vIFRocm93ICdCYWQgUmVxdWVzdCcgaWYgdGhlcmUncyBubyBKU09OIG9yIFNWRyB0byBleHBvcnRcclxuICAgIGlmICghaW5zdHIgJiYgIWJvZHkuc3ZnKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICAyLFxyXG4gICAgICAgIGBUaGUgcmVxdWVzdCB3aXRoIElEICR7dW5pcXVlSWR9IGZyb20gJHtcclxuICAgICAgICAgIHJlcXVlc3QuaGVhZGVyc1sneC1mb3J3YXJkZWQtZm9yJ10gfHwgcmVxdWVzdC5jb25uZWN0aW9uLnJlbW90ZUFkZHJlc3NcclxuICAgICAgICB9IHdhcyBpbmNvcnJlY3QuIFBheWxvYWQgcmVjZWl2ZWQ6ICR7SlNPTi5zdHJpbmdpZnkoYm9keSl9LmBcclxuICAgICAgKTtcclxuXHJcbiAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgXCJObyBjb3JyZWN0IGNoYXJ0IGRhdGEgZm91bmQuIEVuc3VyZSB0aGF0IHlvdSBhcmUgdXNpbmcgZWl0aGVyIGFwcGxpY2F0aW9uL2pzb24gb3IgbXVsdGlwYXJ0L2Zvcm0tZGF0YSBoZWFkZXJzLiBJZiBzZW5kaW5nIEpTT04sIG1ha2Ugc3VyZSB0aGUgY2hhcnQgZGF0YSBpcyBpbiB0aGUgJ2luZmlsZScsICdvcHRpb25zJywgb3IgJ2RhdGEnIGF0dHJpYnV0ZS4gSWYgc2VuZGluZyBTVkcsIGVuc3VyZSBpdCBpcyBpbiB0aGUgJ3N2ZycgYXR0cmlidXRlLlwiLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIGxldCBjYWxsUmVzcG9uc2UgPSBmYWxzZTtcclxuXHJcbiAgICAvLyBDYWxsIHRoZSBiZWZvcmUgcmVxdWVzdCBmdW5jdGlvbnNcclxuICAgIGNhbGxSZXNwb25zZSA9IGRvQ2FsbGJhY2tzKGJlZm9yZVJlcXVlc3QsIHJlcXVlc3QsIHJlc3BvbnNlLCB7XHJcbiAgICAgIGlkLFxyXG4gICAgICB1bmlxdWVJZCxcclxuICAgICAgdHlwZSxcclxuICAgICAgYm9keVxyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gQmxvY2sgdGhlIHJlcXVlc3QgaWYgb25lIG9mIGEgY2FsbGJhY2tzIGZhaWxlZFxyXG4gICAgaWYgKGNhbGxSZXNwb25zZSAhPT0gdHJ1ZSkge1xyXG4gICAgICByZXR1cm4gcmVzcG9uc2Uuc2VuZChjYWxsUmVzcG9uc2UpO1xyXG4gICAgfVxyXG5cclxuICAgIGxldCBjb25uZWN0aW9uQWJvcnRlZCA9IGZhbHNlO1xyXG5cclxuICAgIC8vIEluIGNhc2UgdGhlIGNvbm5lY3Rpb24gaXMgY2xvc2VkLCBmb3JjZSB0byBhYm9ydCBmdXJ0aGVyIGFjdGlvbnNcclxuICAgIHJlcXVlc3Quc29ja2V0Lm9uKCdjbG9zZScsICgpID0+IHtcclxuICAgICAgY29ubmVjdGlvbkFib3J0ZWQgPSB0cnVlO1xyXG4gICAgfSk7XHJcblxyXG4gICAgbG9nKDQsIGBbZXhwb3J0XSBHb3QgYW4gaW5jb21pbmcgSFRUUCByZXF1ZXN0IHdpdGggSUQgJHt1bmlxdWVJZH0uYCk7XHJcblxyXG4gICAgYm9keS5jb25zdHIgPSAodHlwZW9mIGJvZHkuY29uc3RyID09PSAnc3RyaW5nJyAmJiBib2R5LmNvbnN0cikgfHwgJ2NoYXJ0JztcclxuXHJcbiAgICAvLyBHYXRoZXIgYW5kIG9yZ2FuaXplIG9wdGlvbnMgZnJvbSB0aGUgcGF5bG9hZFxyXG4gICAgY29uc3QgcmVxdWVzdE9wdGlvbnMgPSB7XHJcbiAgICAgIGV4cG9ydDoge1xyXG4gICAgICAgIGluc3RyLFxyXG4gICAgICAgIHR5cGUsXHJcbiAgICAgICAgY29uc3RyOiBib2R5LmNvbnN0clswXS50b0xvd2VyQ2FzZSgpICsgYm9keS5jb25zdHIuc3Vic3RyKDEpLFxyXG4gICAgICAgIGhlaWdodDogYm9keS5oZWlnaHQsXHJcbiAgICAgICAgd2lkdGg6IGJvZHkud2lkdGgsXHJcbiAgICAgICAgc2NhbGU6IGJvZHkuc2NhbGUgfHwgZGVmYXVsdE9wdGlvbnMuZXhwb3J0LnNjYWxlLFxyXG4gICAgICAgIGdsb2JhbE9wdGlvbnM6IGlzQ29ycmVjdEpTT04oYm9keS5nbG9iYWxPcHRpb25zLCB0cnVlKSxcclxuICAgICAgICB0aGVtZU9wdGlvbnM6IGlzQ29ycmVjdEpTT04oYm9keS50aGVtZU9wdGlvbnMsIHRydWUpXHJcbiAgICAgIH0sXHJcbiAgICAgIGN1c3RvbUxvZ2ljOiB7XHJcbiAgICAgICAgYWxsb3dDb2RlRXhlY3V0aW9uOiBnZXRBbGxvd0NvZGVFeGVjdXRpb24oKSxcclxuICAgICAgICBhbGxvd0ZpbGVSZXNvdXJjZXM6IGZhbHNlLFxyXG4gICAgICAgIHJlc291cmNlczogaXNDb3JyZWN0SlNPTihib2R5LnJlc291cmNlcywgdHJ1ZSksXHJcbiAgICAgICAgY2FsbGJhY2s6IGJvZHkuY2FsbGJhY2ssXHJcbiAgICAgICAgY3VzdG9tQ29kZTogYm9keS5jdXN0b21Db2RlXHJcbiAgICAgIH1cclxuICAgIH07XHJcblxyXG4gICAgaWYgKGluc3RyKSB7XHJcbiAgICAgIC8vIFN0cmluZ2lmeSBKU09OIHdpdGggb3B0aW9uc1xyXG4gICAgICByZXF1ZXN0T3B0aW9ucy5leHBvcnQuaW5zdHIgPSBvcHRpb25zU3RyaW5naWZ5KFxyXG4gICAgICAgIGluc3RyLFxyXG4gICAgICAgIHJlcXVlc3RPcHRpb25zLmN1c3RvbUxvZ2ljLmFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIE1lcmdlIHRoZSByZXF1ZXN0IG9wdGlvbnMgaW50byBkZWZhdWx0IG9uZXNcclxuICAgIGNvbnN0IG9wdGlvbnMgPSBtZXJnZUNvbmZpZ09wdGlvbnMoZGVmYXVsdE9wdGlvbnMsIHJlcXVlc3RPcHRpb25zKTtcclxuXHJcbiAgICAvLyBTYXZlIHRoZSBKU09OIGlmIGV4aXN0c1xyXG4gICAgb3B0aW9ucy5leHBvcnQub3B0aW9ucyA9IGluc3RyO1xyXG5cclxuICAgIC8vIExhc3RseSwgYWRkIHRoZSBzZXJ2ZXIgc3BlY2lmaWMgYXJndW1lbnRzIGludG8gb3B0aW9ucyBhcyBwYXlsb2FkXHJcbiAgICBvcHRpb25zLnBheWxvYWQgPSB7XHJcbiAgICAgIHN2ZzogYm9keS5zdmcgfHwgZmFsc2UsXHJcbiAgICAgIGI2NDogYm9keS5iNjQgfHwgZmFsc2UsXHJcbiAgICAgIG5vRG93bmxvYWQ6IGJvZHkubm9Eb3dubG9hZCB8fCBmYWxzZSxcclxuICAgICAgcmVxdWVzdElkOiB1bmlxdWVJZFxyXG4gICAgfTtcclxuXHJcbiAgICAvLyBUZXN0IHhsaW5rOmhyZWYgZWxlbWVudHMgZnJvbSBwYXlsb2FkJ3MgU1ZHXHJcbiAgICBpZiAoYm9keS5zdmcgJiYgaXNQcml2YXRlUmFuZ2VVcmxGb3VuZChvcHRpb25zLnBheWxvYWQuc3ZnKSkge1xyXG4gICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgICdTVkcgcG90ZW50aWFsbHkgY29udGFpbiBhdCBsZWFzdCBvbmUgZm9yYmlkZGVuIFVSTCBpbiB4bGluazpocmVmIGVsZW1lbnQuIFBsZWFzZSByZXZpZXcgdGhlIFNWRyBjb250ZW50IGFuZCBlbnN1cmUgdGhhdCBhbGwgcmVmZXJlbmNlZCBVUkxzIGNvbXBseSB3aXRoIHNlY3VyaXR5IHBvbGljaWVzLicsXHJcbiAgICAgICAgNDAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU3RhcnQgdGhlIGV4cG9ydCBwcm9jZXNzXHJcbiAgICBhd2FpdCBzdGFydEV4cG9ydChvcHRpb25zLCAoZXJyb3IsIGluZm8pID0+IHtcclxuICAgICAgLy8gUmVtb3ZlIHRoZSBjbG9zZSBldmVudCBmcm9tIHRoZSBzb2NrZXRcclxuICAgICAgcmVxdWVzdC5zb2NrZXQucmVtb3ZlQWxsTGlzdGVuZXJzKCdjbG9zZScpO1xyXG5cclxuICAgICAgLy8gQWZ0ZXIgdGhlIHdob2xlIGV4cG9ydGluZyBwcm9jZXNzXHJcbiAgICAgIGlmIChkZWZhdWx0T3B0aW9ucy5zZXJ2ZXIuYmVuY2htYXJraW5nKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgNSxcclxuICAgICAgICAgIGBbYmVuY2htYXJrXSBSZXF1ZXN0OiAke3VuaXF1ZUlkfSAtIEFmdGVyIHRoZSB3aG9sZSBleHBvcnRpbmcgcHJvY2VzczogJHtzdG9wQ291bnRlcigpfW1zLmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBJZiB0aGUgY29ubmVjdGlvbiB3YXMgY2xvc2VkLCBkbyBub3RoaW5nXHJcbiAgICAgIGlmIChjb25uZWN0aW9uQWJvcnRlZCkge1xyXG4gICAgICAgIHJldHVybiBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtleHBvcnRdIFRoZSBjbGllbnQgY2xvc2VkIHRoZSBjb25uZWN0aW9uIGJlZm9yZSB0aGUgY2hhcnQgZmluaXNoZWQgcHJvY2Vzc2luZy5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgZXJyb3IsIGxvZyBpdCBhbmQgc2VuZCBpdCB0byB0aGUgZXJyb3IgbWlkZGxld2FyZVxyXG4gICAgICBpZiAoZXJyb3IpIHtcclxuICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgZGF0YSBpcyBtaXNzaW5nLCBsb2cgdGhlIG1lc3NhZ2UgYW5kIHNlbmQgaXQgdG8gdGhlIGVycm9yIG1pZGRsZXdhcmVcclxuICAgICAgaWYgKCFpbmZvIHx8ICFpbmZvLnJlc3VsdCkge1xyXG4gICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgICBgVW5leHBlY3RlZCByZXR1cm4gZnJvbSBjaGFydCBnZW5lcmF0aW9uLiBQbGVhc2UgY2hlY2sgeW91ciByZXF1ZXN0IGRhdGEuIEZvciB0aGUgcmVxdWVzdCB3aXRoIElEICR7dW5pcXVlSWR9LCB0aGUgcmVzdWx0IGlzICR7aW5mby5yZXN1bHR9LmAsXHJcbiAgICAgICAgICA0MDBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBHZXQgdGhlIHR5cGUgZnJvbSBvcHRpb25zXHJcbiAgICAgIHR5cGUgPSBpbmZvLm9wdGlvbnMuZXhwb3J0LnR5cGU7XHJcblxyXG4gICAgICAvLyBUaGUgYWZ0ZXIgcmVxdWVzdCBjYWxsYmFja3NcclxuICAgICAgZG9DYWxsYmFja3MoYWZ0ZXJSZXF1ZXN0LCByZXF1ZXN0LCByZXNwb25zZSwgeyBpZCwgYm9keTogaW5mby5yZXN1bHQgfSk7XHJcblxyXG4gICAgICAvLyBQcmVwYXJlIGFuZCBzZW5kIHRoZSBvcHRpb25zIHRocm91Z2ggdGhlIFdlYlNvY2tldFxyXG4gICAgICBwcmVwYXJlVGVsZW1ldHJ5KG9wdGlvbnMuZXhwb3J0Lm9wdGlvbnMsIG9wdGlvbnMucGF5bG9hZC5yZXF1ZXN0SWQpO1xyXG5cclxuICAgICAgaWYgKGluZm8ucmVzdWx0KSB7XHJcbiAgICAgICAgLy8gSWYgb25seSBiYXNlNjQgaXMgcmVxdWlyZWQsIHJldHVybiBpdFxyXG4gICAgICAgIGlmIChib2R5LmI2NCkge1xyXG4gICAgICAgICAgLy8gU1ZHIEV4Y2VwdGlvbiBmb3IgdGhlIEhpZ2hjaGFydHMgMTEuMy4wIHZlcnNpb25cclxuICAgICAgICAgIGlmICh0eXBlID09PSAncGRmJyB8fCB0eXBlID09ICdzdmcnKSB7XHJcbiAgICAgICAgICAgIHJldHVybiByZXNwb25zZS5zZW5kKFxyXG4gICAgICAgICAgICAgIEJ1ZmZlci5mcm9tKGluZm8ucmVzdWx0LCAndXRmOCcpLnRvU3RyaW5nKCdiYXNlNjQnKVxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgfVxyXG5cclxuICAgICAgICAgIHJldHVybiByZXNwb25zZS5zZW5kKGluZm8ucmVzdWx0KTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIFNldCBjb3JyZWN0IGNvbnRlbnQgdHlwZVxyXG4gICAgICAgIHJlc3BvbnNlLmhlYWRlcignQ29udGVudC1UeXBlJywgcmV2ZXJzZWRNaW1lW3R5cGVdIHx8ICdpbWFnZS9wbmcnKTtcclxuXHJcbiAgICAgICAgLy8gRGVjaWRlIHdoZXRoZXIgdG8gZG93bmxvYWQgb3Igbm90IGNoYXJ0IGZpbGVcclxuICAgICAgICBpZiAoIWJvZHkubm9Eb3dubG9hZCkge1xyXG4gICAgICAgICAgcmVzcG9uc2UuYXR0YWNobWVudChcclxuICAgICAgICAgICAgYCR7cmVxdWVzdC5wYXJhbXMuZmlsZW5hbWUgfHwgcmVxdWVzdC5ib2R5LmZpbGVuYW1lIHx8ICdjaGFydCd9LiR7XHJcbiAgICAgICAgICAgICAgdHlwZSB8fCAncG5nJ1xyXG4gICAgICAgICAgICB9YFxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIElmIFNWRywgcmV0dXJuIHBsYWluIGNvbnRlbnRcclxuICAgICAgICByZXR1cm4gdHlwZSA9PT0gJ3N2ZydcclxuICAgICAgICAgID8gcmVzcG9uc2Uuc2VuZChpbmZvLnJlc3VsdClcclxuICAgICAgICAgIDogcmVzcG9uc2Uuc2VuZChCdWZmZXIuZnJvbShpbmZvLnJlc3VsdCwgJ2Jhc2U2NCcpKTtcclxuICAgICAgfVxyXG4gICAgfSk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIG5leHQoZXJyb3IpO1xyXG4gIH1cclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IChhcHApID0+IHtcclxuICAvKipcclxuICAgKiBBZGRzIHRoZSBQT1NUIC8gYSByb3V0ZSBmb3IgaGFuZGxpbmcgUE9TVCByZXF1ZXN0cyBhdCB0aGUgcm9vdCBlbmRwb2ludC5cclxuICAgKi9cclxuICBhcHAucG9zdCgnLycsIGV4cG9ydEhhbmRsZXIpO1xyXG5cclxuICAvKipcclxuICAgKiBBZGRzIHRoZSBQT1NUIC86ZmlsZW5hbWUgYSByb3V0ZSBmb3IgaGFuZGxpbmcgUE9TVCByZXF1ZXN0cyB3aXRoXHJcbiAgICogYSBzcGVjaWZpZWQgZmlsZW5hbWUgcGFyYW1ldGVyLlxyXG4gICAqL1xyXG4gIGFwcC5wb3N0KCcvOmZpbGVuYW1lJywgZXhwb3J0SGFuZGxlcik7XHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgeyBqb2luIGFzIHBhdGhlciB9IGZyb20gJ3BhdGgnO1xyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuLi8uLi9sb2dnZXIuanMnO1xyXG5cclxuaW1wb3J0IHsgdmVyc2lvbiB9IGZyb20gJy4uLy4uL2NhY2hlLmpzJztcclxuaW1wb3J0IHsgYWRkVGltZXIgfSBmcm9tICcuLi8uLi90aW1lcnMuanMnO1xyXG5pbXBvcnQgeyBnZXRTdGF0cywgZ2V0UG9vbEluZm9KU09OIH0gZnJvbSAnLi4vLi4vcG9vbC5qcyc7XHJcbmltcG9ydCB7IF9fZGlybmFtZSB9IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcclxuXHJcbmNvbnN0IHBrZ0ZpbGUgPSBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhwYXRoZXIoX19kaXJuYW1lLCAncGFja2FnZS5qc29uJykpKTtcclxuXHJcbmNvbnN0IHNlcnZlclN0YXJ0VGltZSA9IG5ldyBEYXRlKCk7XHJcblxyXG5jb25zdCBzdWNjZXNzUmF0ZXMgPSBbXTtcclxuY29uc3QgcmVjb3JkSW50ZXJ2YWwgPSA2MCAqIDEwMDA7IC8vIHJlY29yZCBldmVyeSBtaW51dGVcclxuY29uc3Qgd2luZG93U2l6ZSA9IDMwOyAvLyAzMCBtaW51dGVzXHJcblxyXG4vKipcclxuICogQ2FsY3VsYXRlcyBtb3ZpbmcgYXZlcmFnZSBpbmRpY2F0b3IgYmFzZWQgb24gdGhlIGRhdGEgZnJvbSB0aGUgc3VjY2Vzc1JhdGVzXHJcbiAqIGFycmF5LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7bnVtYmVyfSAtIEEgbW92aW5nIGF2ZXJhZ2UgZm9yIHN1Y2Nlc3MgcmF0aW8gb2YgdGhlIHNlcnZlciBleHBvcnRzLlxyXG4gKi9cclxuZnVuY3Rpb24gY2FsY3VsYXRlTW92aW5nQXZlcmFnZSgpIHtcclxuICBjb25zdCBzdW0gPSBzdWNjZXNzUmF0ZXMucmVkdWNlKChhLCBiKSA9PiBhICsgYiwgMCk7XHJcbiAgcmV0dXJuIHN1bSAvIHN1Y2Nlc3NSYXRlcy5sZW5ndGg7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgdGhlIGludGVydmFsIHJlc3BvbnNpYmxlIGZvciBjYWxjdWxhdGluZyBjdXJyZW50IHN1Y2Nlc3MgcmF0ZSByYXRpb1xyXG4gKiBhbmQgZ2F0aGVyc1xyXG4gKlxyXG4gKiBAcmV0dXJucyB7Tm9kZUpTLlRpbWVvdXR9IGlkIC0gSWQgb2YgYW4gaW50ZXJ2YWwuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc3RhcnRTdWNjZXNzUmF0ZSA9ICgpID0+XHJcbiAgc2V0SW50ZXJ2YWwoKCkgPT4ge1xyXG4gICAgY29uc3Qgc3RhdHMgPSBnZXRTdGF0cygpO1xyXG4gICAgY29uc3Qgc3VjY2Vzc1JhdGlvID1cclxuICAgICAgc3RhdHMuZXhwb3J0QXR0ZW1wdHMgPT09IDBcclxuICAgICAgICA/IDFcclxuICAgICAgICA6IChzdGF0cy5wZXJmb3JtZWRFeHBvcnRzIC8gc3RhdHMuZXhwb3J0QXR0ZW1wdHMpICogMTAwO1xyXG5cclxuICAgIHN1Y2Nlc3NSYXRlcy5wdXNoKHN1Y2Nlc3NSYXRpbyk7XHJcbiAgICBpZiAoc3VjY2Vzc1JhdGVzLmxlbmd0aCA+IHdpbmRvd1NpemUpIHtcclxuICAgICAgc3VjY2Vzc1JhdGVzLnNoaWZ0KCk7XHJcbiAgICB9XHJcbiAgfSwgcmVjb3JkSW50ZXJ2YWwpO1xyXG5cclxuLyoqXHJcbiAqIEFkZHMgdGhlIC9oZWFsdGggYW5kIC9zdWNjZXNzLW1vdmluZy1hdmVyYWdlIHJvdXRlc1xyXG4gKiB3aGljaCBvdXRwdXQgYmFzaWMgc3RhdHMgZm9yIHRoZSBzZXJ2ZXIuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBhZGRIZWFsdGhSb3V0ZXMoYXBwKSB7XHJcbiAgaWYgKCFhcHApIHtcclxuICAgIHJldHVybiBmYWxzZTtcclxuICB9XHJcblxyXG4gIC8vIFN0YXJ0IHByb2Nlc3Npbmcgc3VjY2VzcyByYXRlIHJhdGlvIGludGVydmFsIGFuZCBzYXZlIGl0cyBpZCB0byB0aGUgYXJyYXlcclxuICAvLyBmb3IgdGhlIGdyYWNlZnVsIGNsZWFyaW5nIG9uIHNodXRkb3duIHdpdGggaW5qZWN0ZWQgYWRkSW50ZXJ2YWwgZnVudGlvblxyXG4gIGFkZFRpbWVyKHN0YXJ0U3VjY2Vzc1JhdGUoKSk7XHJcblxyXG4gIGFwcC5nZXQoJy9oZWFsdGgnLCAoXywgcmVzKSA9PiB7XHJcbiAgICBjb25zdCBzdGF0cyA9IGdldFN0YXRzKCk7XHJcbiAgICBjb25zdCBwZXJpb2QgPSBzdWNjZXNzUmF0ZXMubGVuZ3RoO1xyXG4gICAgY29uc3QgbW92aW5nQXZlcmFnZSA9IGNhbGN1bGF0ZU1vdmluZ0F2ZXJhZ2UoKTtcclxuXHJcbiAgICBsb2coNCwgJ1toZWFsdGguanNdIEdFVCAvaGVhbHRoIFsyMDBdIC0gcmV0dXJuaW5nIHNlcnZlciBoZWFsdGguJyk7XHJcblxyXG4gICAgcmVzLnNlbmQoe1xyXG4gICAgICBzdGF0dXM6ICdPSycsXHJcbiAgICAgIGJvb3RUaW1lOiBzZXJ2ZXJTdGFydFRpbWUsXHJcbiAgICAgIHVwdGltZTpcclxuICAgICAgICBNYXRoLmZsb29yKFxyXG4gICAgICAgICAgKG5ldyBEYXRlKCkuZ2V0VGltZSgpIC0gc2VydmVyU3RhcnRUaW1lLmdldFRpbWUoKSkgLyAxMDAwIC8gNjBcclxuICAgICAgICApICsgJyBtaW51dGVzJyxcclxuICAgICAgdmVyc2lvbjogcGtnRmlsZS52ZXJzaW9uLFxyXG4gICAgICBoaWdoY2hhcnRzVmVyc2lvbjogdmVyc2lvbigpLFxyXG4gICAgICBhdmVyYWdlUHJvY2Vzc2luZ1RpbWU6IHN0YXRzLnNwZW50QXZlcmFnZSxcclxuICAgICAgcGVyZm9ybWVkRXhwb3J0czogc3RhdHMucGVyZm9ybWVkRXhwb3J0cyxcclxuICAgICAgZmFpbGVkRXhwb3J0czogc3RhdHMuZHJvcHBlZEV4cG9ydHMsXHJcbiAgICAgIGV4cG9ydEF0dGVtcHRzOiBzdGF0cy5leHBvcnRBdHRlbXB0cyxcclxuICAgICAgc3VjZXNzUmF0aW86IChzdGF0cy5wZXJmb3JtZWRFeHBvcnRzIC8gc3RhdHMuZXhwb3J0QXR0ZW1wdHMpICogMTAwLFxyXG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgaW1wb3J0L25vLW5hbWVkLWFzLWRlZmF1bHQtbWVtYmVyXHJcbiAgICAgIHBvb2w6IGdldFBvb2xJbmZvSlNPTigpLFxyXG5cclxuICAgICAgLy8gTW92aW5nIGF2ZXJhZ2VcclxuICAgICAgcGVyaW9kLFxyXG4gICAgICBtb3ZpbmdBdmVyYWdlLFxyXG4gICAgICBtZXNzYWdlOiBgTGFzdCAke3BlcmlvZH0gbWludXRlcyBoYWQgYSBzdWNjZXNzIHJhdGUgb2YgJHttb3ZpbmdBdmVyYWdlLnRvRml4ZWQoMil9JS5gLFxyXG5cclxuICAgICAgLy8gU1ZHL0pTT04gYXR0ZW1wdHNcclxuICAgICAgc3ZnRXhwb3J0QXR0ZW1wdHM6IHN0YXRzLmV4cG9ydEZyb21TdmdBdHRlbXB0cyxcclxuICAgICAganNvbkV4cG9ydEF0dGVtcHRzOiBzdGF0cy5wZXJmb3JtZWRFeHBvcnRzIC0gc3RhdHMuZXhwb3J0RnJvbVN2Z0F0dGVtcHRzXHJcbiAgICB9KTtcclxuICB9KTtcclxufVxyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IHByb21pc2VzIGFzIGZzUHJvbWlzZXMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IHBvc2l4IH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgY29ycyBmcm9tICdjb3JzJztcclxuaW1wb3J0IGV4cHJlc3MgZnJvbSAnZXhwcmVzcyc7XHJcbmltcG9ydCBodHRwIGZyb20gJ2h0dHAnO1xyXG5pbXBvcnQgaHR0cHMgZnJvbSAnaHR0cHMnO1xyXG5pbXBvcnQgbXVsdGVyIGZyb20gJ211bHRlcic7XHJcblxyXG5pbXBvcnQgZXJyb3JIYW5kbGVyIGZyb20gJy4vZXJyb3IuanMnO1xyXG5pbXBvcnQgcmF0ZUxpbWl0IGZyb20gJy4vcmF0ZV9saW1pdC5qcyc7XHJcbmltcG9ydCB7IGluaXQgYXMgd2ViU29ja2V0SW5pdCB9IGZyb20gJy4vd2ViX3NvY2tldC5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgX19kaXJuYW1lIH0gZnJvbSAnLi4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IHZTd2l0Y2hSb3V0ZSBmcm9tICcuL3JvdXRlcy9jaGFuZ2VfaGNfdmVyc2lvbi5qcyc7XHJcbmltcG9ydCBleHBvcnRSb3V0ZXMgZnJvbSAnLi9yb3V0ZXMvZXhwb3J0LmpzJztcclxuaW1wb3J0IGhlYWx0aFJvdXRlIGZyb20gJy4vcm91dGVzL2hlYWx0aC5qcyc7XHJcbmltcG9ydCB1aVJvdXRlIGZyb20gJy4vcm91dGVzL3VpLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLy8gQXJyYXkgb2YgYW4gYWN0aXZlIHNlcnZlcnNcclxuY29uc3QgYWN0aXZlU2VydmVycyA9IG5ldyBNYXAoKTtcclxuXHJcbi8vIENyZWF0ZSBleHByZXNzIGFwcFxyXG5jb25zdCBhcHAgPSBleHByZXNzKCk7XHJcblxyXG4vLyBEaXNhYmxlIHRoZSBYLVBvd2VyZWQtQnkgaGVhZGVyXHJcbmFwcC5kaXNhYmxlKCd4LXBvd2VyZWQtYnknKTtcclxuXHJcbi8vIEVuYWJsZSBDT1JTIHN1cHBvcnRcclxuYXBwLnVzZShjb3JzKCkpO1xyXG5cclxuLy8gRW5hYmxlIHBhcnNpbmcgb2YgZm9ybSBkYXRhIChmaWxlcykgd2l0aCBNdWx0ZXIgcGFja2FnZVxyXG5jb25zdCBzdG9yYWdlID0gbXVsdGVyLm1lbW9yeVN0b3JhZ2UoKTtcclxuY29uc3QgdXBsb2FkID0gbXVsdGVyKHtcclxuICBzdG9yYWdlLFxyXG4gIGxpbWl0czoge1xyXG4gICAgZmllbGRTaXplOiA1MCAqIDEwMjQgKiAxMDI0XHJcbiAgfVxyXG59KTtcclxuXHJcbi8vIEVuYWJsZSBib2R5IHBhcnNlclxyXG5hcHAudXNlKGV4cHJlc3MuanNvbih7IGxpbWl0OiA1MCAqIDEwMjQgKiAxMDI0IH0pKTtcclxuYXBwLnVzZShleHByZXNzLnVybGVuY29kZWQoeyBleHRlbmRlZDogdHJ1ZSwgbGltaXQ6IDUwICogMTAyNCAqIDEwMjQgfSkpO1xyXG5cclxuLy8gVXNlIG9ubHkgbm9uLWZpbGUgbXVsdGlwYXJ0IGZvcm0gZmllbGRzXHJcbmFwcC51c2UodXBsb2FkLm5vbmUoKSk7XHJcblxyXG4vKipcclxuICogQXR0YWNoIGVycm9yIGhhbmRsZXJzIHRvIHRoZSBzZXJ2ZXIuXHJcbiAqXHJcbiAqIEBwYXJhbSB7aHR0cC5TZXJ2ZXJ9IHNlcnZlciAtIFRoZSBIVFRQL0hUVFBTIHNlcnZlciBpbnN0YW5jZS5cclxuICovXHJcbmNvbnN0IGF0dGFjaFNlcnZlckVycm9ySGFuZGxlcnMgPSAoc2VydmVyKSA9PiB7XHJcbiAgc2VydmVyLm9uKCdjbGllbnRFcnJvcicsIChlcnJvcikgPT4ge1xyXG4gICAgbG9nV2l0aFN0YWNrKDEsIGVycm9yLCBgW3NlcnZlcl0gQ2xpZW50IGVycm9yOiAke2Vycm9yLm1lc3NhZ2V9YCk7XHJcbiAgfSk7XHJcblxyXG4gIHNlcnZlci5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcclxuICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFtzZXJ2ZXJdIFNlcnZlciBlcnJvcjogJHtlcnJvci5tZXNzYWdlfWApO1xyXG4gIH0pO1xyXG5cclxuICBzZXJ2ZXIub24oJ2Nvbm5lY3Rpb24nLCAoc29ja2V0KSA9PiB7XHJcbiAgICBzb2NrZXQub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFtzZXJ2ZXJdIFNvY2tldCBlcnJvcjogJHtlcnJvci5tZXNzYWdlfWApO1xyXG4gICAgfSk7XHJcbiAgfSk7XHJcbn07XHJcblxyXG4vKipcclxuICogU3RhcnRzIGFuIEhUVFAgc2VydmVyIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uLiBUaGUgYHNlcnZlckNvbmZpZ2BcclxuICogb2JqZWN0IGNvbnRhaW5zIGFsbCBzZXJ2ZXIgcmVsYXRlZCBwcm9wZXJ0aWVzIChzZWUgdGhlIGBzZXJ2ZXJgIHNlY3Rpb25cclxuICogaW4gdGhlIGBsaWIvc2NoZW1hcy9jb25maWcuanNgIGZpbGUgZm9yIGEgcmVmZXJlbmNlKS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHNlcnZlckNvbmZpZyAtIFRoZSBzZXJ2ZXIgY29uZmlndXJhdGlvbiBvYmplY3QuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSAtIFRocm93cyBhbiBlcnJvciBpZiB0aGUgc2VydmVyIGNhbm5vdCBiZSBjb25maWd1cmVkXHJcbiAqIGFuZCBzdGFydGVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHN0YXJ0U2VydmVyID0gYXN5bmMgKHNlcnZlckNvbmZpZykgPT4ge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBTdG9wIGlmIG5vdCBlbmFibGVkXHJcbiAgICBpZiAoIXNlcnZlckNvbmZpZy5lbmFibGUpIHtcclxuICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIExpc3RlbiBIVFRQIHNlcnZlclxyXG4gICAgaWYgKCFzZXJ2ZXJDb25maWcuc3NsLmZvcmNlKSB7XHJcbiAgICAgIC8vIE1haW4gc2VydmVyIGluc3RhbmNlIChIVFRQKVxyXG4gICAgICBjb25zdCBodHRwU2VydmVyID0gaHR0cC5jcmVhdGVTZXJ2ZXIoYXBwKTtcclxuXHJcbiAgICAgIC8vIEF0dGFjaCBlcnJvciBoYW5kbGVycyBhbmQgbGlzdGVuIHRvIHRoZSBzZXJ2ZXJcclxuICAgICAgYXR0YWNoU2VydmVyRXJyb3JIYW5kbGVycyhodHRwU2VydmVyKTtcclxuXHJcbiAgICAgIC8vIExpc3RlblxyXG4gICAgICBodHRwU2VydmVyLmxpc3RlbihzZXJ2ZXJDb25maWcucG9ydCwgc2VydmVyQ29uZmlnLmhvc3QsICgpID0+IHtcclxuICAgICAgICAvLyBTYXZlIHRoZSByZWZlcmVuY2UgdG8gSFRUUCBzZXJ2ZXJcclxuICAgICAgICBhY3RpdmVTZXJ2ZXJzLnNldChzZXJ2ZXJDb25maWcucG9ydCwgaHR0cFNlcnZlcik7XHJcblxyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW3NlcnZlcl0gU3RhcnRlZCBIVFRQIHNlcnZlciBvbiAke3NlcnZlckNvbmZpZy5ob3N0fToke3NlcnZlckNvbmZpZy5wb3J0fS5gXHJcbiAgICAgICAgKTtcclxuXHJcbiAgICAgICAgaWYgKGFjdGl2ZVNlcnZlcnMuc2l6ZSA9PT0gMSkge1xyXG4gICAgICAgICAgLy8gU3RhcnQgYSBXZWJTb2NrZXQgY29ubmVjdGlvblxyXG4gICAgICAgICAgd2ViU29ja2V0SW5pdCh7IC4uLmh0dHBTZXJ2ZXIuYWRkcmVzcygpLCBwcm90b2NvbDogJ2h0dHAnIH0pO1xyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTGlzdGVuIEhUVFBTIHNlcnZlclxyXG4gICAgaWYgKHNlcnZlckNvbmZpZy5zc2wuZW5hYmxlKSB7XHJcbiAgICAgIC8vIFNldCB1cCBhbiBTU0wgc2VydmVyIGFsc29cclxuICAgICAgbGV0IGtleSwgY2VydDtcclxuXHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgLy8gR2V0IHRoZSBTU0wga2V5XHJcbiAgICAgICAga2V5ID0gYXdhaXQgZnNQcm9taXNlcy5yZWFkRmlsZShcclxuICAgICAgICAgIHBvc2l4LmpvaW4oc2VydmVyQ29uZmlnLnNzbC5jZXJ0UGF0aCwgJ3NlcnZlci5rZXknKSxcclxuICAgICAgICAgICd1dGY4J1xyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIC8vIEdldCB0aGUgU1NMIGNlcnRpZmljYXRlXHJcbiAgICAgICAgY2VydCA9IGF3YWl0IGZzUHJvbWlzZXMucmVhZEZpbGUoXHJcbiAgICAgICAgICBwb3NpeC5qb2luKHNlcnZlckNvbmZpZy5zc2wuY2VydFBhdGgsICdzZXJ2ZXIuY3J0JyksXHJcbiAgICAgICAgICAndXRmOCdcclxuICAgICAgICApO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDIsXHJcbiAgICAgICAgICBgW3NlcnZlcl0gVW5hYmxlIHRvIGxvYWQga2V5L2NlcnRpZmljYXRlIGZyb20gdGhlICcke3NlcnZlckNvbmZpZy5zc2wuY2VydFBhdGh9JyBwYXRoLiBDb3VsZCBub3QgcnVuIHNlY3VyZWQgbGF5ZXIgc2VydmVyLmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAoa2V5ICYmIGNlcnQpIHtcclxuICAgICAgICAvLyBNYWluIHNlcnZlciBpbnN0YW5jZSAoSFRUUFMpXHJcbiAgICAgICAgY29uc3QgaHR0cHNTZXJ2ZXIgPSBodHRwcy5jcmVhdGVTZXJ2ZXIoeyBrZXksIGNlcnQgfSwgYXBwKTtcclxuXHJcbiAgICAgICAgLy8gQXR0YWNoIGVycm9yIGhhbmRsZXJzIGFuZCBsaXN0ZW4gdG8gdGhlIHNlcnZlclxyXG4gICAgICAgIGF0dGFjaFNlcnZlckVycm9ySGFuZGxlcnMoaHR0cHNTZXJ2ZXIpO1xyXG5cclxuICAgICAgICAvLyBMaXN0ZW5cclxuICAgICAgICBodHRwc1NlcnZlci5saXN0ZW4oc2VydmVyQ29uZmlnLnNzbC5wb3J0LCBzZXJ2ZXJDb25maWcuaG9zdCwgKCkgPT4ge1xyXG4gICAgICAgICAgLy8gU2F2ZSB0aGUgcmVmZXJlbmNlIHRvIEhUVFBTIHNlcnZlclxyXG4gICAgICAgICAgYWN0aXZlU2VydmVycy5zZXQoc2VydmVyQ29uZmlnLnNzbC5wb3J0LCBodHRwc1NlcnZlcik7XHJcblxyXG4gICAgICAgICAgbG9nKFxyXG4gICAgICAgICAgICAzLFxyXG4gICAgICAgICAgICBgW3NlcnZlcl0gU3RhcnRlZCBIVFRQUyBzZXJ2ZXIgb24gJHtzZXJ2ZXJDb25maWcuaG9zdH06JHtzZXJ2ZXJDb25maWcuc3NsLnBvcnR9LmBcclxuICAgICAgICAgICk7XHJcblxyXG4gICAgICAgICAgaWYgKGFjdGl2ZVNlcnZlcnMuc2l6ZSA9PT0gMSkge1xyXG4gICAgICAgICAgICAvLyBTdGFydCBhIFdlYlNvY2tldCBjb25uZWN0aW9uXHJcbiAgICAgICAgICAgIHdlYlNvY2tldEluaXQoeyAuLi5odHRwc1NlcnZlci5hZGRyZXNzKCksIHByb3RvY29sOiAnaHR0cHMnIH0pO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH0pO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRW5hYmxlIHRoZSByYXRlIGxpbWl0ZXIgaWYgY29uZmlnIHNheXMgc29cclxuICAgIGlmIChcclxuICAgICAgc2VydmVyQ29uZmlnLnJhdGVMaW1pdGluZyAmJlxyXG4gICAgICBzZXJ2ZXJDb25maWcucmF0ZUxpbWl0aW5nLmVuYWJsZSAmJlxyXG4gICAgICAhWzAsIE5hTl0uaW5jbHVkZXMoc2VydmVyQ29uZmlnLnJhdGVMaW1pdGluZy5tYXhSZXF1ZXN0cylcclxuICAgICkge1xyXG4gICAgICByYXRlTGltaXQoYXBwLCBzZXJ2ZXJDb25maWcucmF0ZUxpbWl0aW5nKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBTZXQgdXAgc3RhdGljIGZvbGRlcidzIHJvdXRlXHJcbiAgICBhcHAudXNlKGV4cHJlc3Muc3RhdGljKHBvc2l4LmpvaW4oX19kaXJuYW1lLCAncHVibGljJykpKTtcclxuXHJcbiAgICAvLyBTZXQgdXAgcm91dGVzXHJcbiAgICBoZWFsdGhSb3V0ZShhcHApO1xyXG4gICAgZXhwb3J0Um91dGVzKGFwcCk7XHJcbiAgICB1aVJvdXRlKGFwcCk7XHJcbiAgICB2U3dpdGNoUm91dGUoYXBwKTtcclxuXHJcbiAgICAvLyBTZXQgdXAgY2VudHJhbGl6ZWQgZXJyb3IgaGFuZGxlclxyXG4gICAgZXJyb3JIYW5kbGVyKGFwcCk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1tzZXJ2ZXJdIENvdWxkIG5vdCBjb25maWd1cmUgYW5kIHN0YXJ0IHRoZSBzZXJ2ZXIuJ1xyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIENsb3NlcyBhbGwgc2VydmVycyBhc3NvY2lhdGVkIHdpdGggRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgY2xvc2VTZXJ2ZXJzID0gKCkgPT4ge1xyXG4gIGxvZyg0LCBgW3NlcnZlcl0gQ2xvc2luZyBhbGwgc2VydmVycy5gKTtcclxuICBmb3IgKGNvbnN0IFtwb3J0LCBzZXJ2ZXJdIG9mIGFjdGl2ZVNlcnZlcnMpIHtcclxuICAgIHNlcnZlci5jbG9zZSgoKSA9PiB7XHJcbiAgICAgIGFjdGl2ZVNlcnZlcnMuZGVsZXRlKHBvcnQpO1xyXG4gICAgICBsb2coNCwgYFtzZXJ2ZXJdIENsb3NlZCBzZXJ2ZXIgb24gcG9ydDogJHtwb3J0fS5gKTtcclxuICAgIH0pO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBHZXQgYWxsIHNlcnZlcnMgYXNzb2NpYXRlZCB3aXRoIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7QXJyYXl9IC0gU2VydmVycyBhc3NvY2lhdGVkIHdpdGggRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0U2VydmVycyA9ICgpID0+IGFjdGl2ZVNlcnZlcnM7XHJcblxyXG4vKipcclxuICogRW5hYmxlIHJhdGUgbGltaXRpbmcgZm9yIHRoZSBzZXJ2ZXIuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBsaW1pdENvbmZpZyAtIENvbmZpZ3VyYXRpb24gb2JqZWN0IGZvciByYXRlIGxpbWl0aW5nLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGVuYWJsZVJhdGVMaW1pdGluZyA9IChsaW1pdENvbmZpZykgPT4gcmF0ZUxpbWl0KGFwcCwgbGltaXRDb25maWcpO1xyXG5cclxuLyoqXHJcbiAqIEdldCB0aGUgRXhwcmVzcyBpbnN0YW5jZS5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gLSBUaGUgRXhwcmVzcyBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBnZXRFeHByZXNzID0gKCkgPT4gZXhwcmVzcztcclxuXHJcbi8qKlxyXG4gKiBHZXQgdGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSAtIFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBnZXRBcHAgPSAoKSA9PiBhcHA7XHJcblxyXG4vKipcclxuICogQXBwbHkgbWlkZGxld2FyZShzKSB0byBhIHNwZWNpZmljIHBhdGguXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIC0gVGhlIHBhdGggdG8gd2hpY2ggdGhlIG1pZGRsZXdhcmUocykgc2hvdWxkIGJlIGFwcGxpZWQuXHJcbiAqIEBwYXJhbSB7Li4uRnVuY3Rpb259IG1pZGRsZXdhcmVzIC0gVGhlIG1pZGRsZXdhcmUgZnVuY3Rpb25zIHRvIGJlIGFwcGxpZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgdXNlID0gKHBhdGgsIC4uLm1pZGRsZXdhcmVzKSA9PiB7XHJcbiAgYXBwLnVzZShwYXRoLCAuLi5taWRkbGV3YXJlcyk7XHJcbn07XHJcblxyXG4vKipcclxuICogU2V0IHVwIGEgcm91dGUgd2l0aCBHRVQgbWV0aG9kIGFuZCBhcHBseSBtaWRkbGV3YXJlKHMpLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcGF0aCAtIFRoZSByb3V0ZSBwYXRoLlxyXG4gKiBAcGFyYW0gey4uLkZ1bmN0aW9ufSBtaWRkbGV3YXJlcyAtIFRoZSBtaWRkbGV3YXJlIGZ1bmN0aW9ucyB0byBiZSBhcHBsaWVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldCA9IChwYXRoLCAuLi5taWRkbGV3YXJlcykgPT4ge1xyXG4gIGFwcC5nZXQocGF0aCwgLi4ubWlkZGxld2FyZXMpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFNldCB1cCBhIHJvdXRlIHdpdGggUE9TVCBtZXRob2QgYW5kIGFwcGx5IG1pZGRsZXdhcmUocykuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIC0gVGhlIHJvdXRlIHBhdGguXHJcbiAqIEBwYXJhbSB7Li4uRnVuY3Rpb259IG1pZGRsZXdhcmVzIC0gVGhlIG1pZGRsZXdhcmUgZnVuY3Rpb25zIHRvIGJlIGFwcGxpZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgcG9zdCA9IChwYXRoLCAuLi5taWRkbGV3YXJlcykgPT4ge1xyXG4gIGFwcC5wb3N0KHBhdGgsIC4uLm1pZGRsZXdhcmVzKTtcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBzdGFydFNlcnZlcixcclxuICBjbG9zZVNlcnZlcnMsXHJcbiAgZ2V0U2VydmVycyxcclxuICBlbmFibGVSYXRlTGltaXRpbmcsXHJcbiAgZ2V0RXhwcmVzcyxcclxuICBnZXRBcHAsXHJcbiAgdXNlLFxyXG4gIGdldCxcclxuICBwb3N0XHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IHsgX19kaXJuYW1lIH0gZnJvbSAnLi4vLi4vdXRpbHMuanMnO1xyXG5cclxuLyoqXHJcbiAqIEFkZHMgdGhlIEdFVCAvIHJvdXRlIGZvciBhIFVJIHdoZW4gZW5hYmxlZCBvbiB0aGUgZXhwb3J0IHNlcnZlci5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IChhcHApID0+XHJcbiAgIWFwcFxyXG4gICAgPyBmYWxzZVxyXG4gICAgOiBhcHAuZ2V0KCcvJywgKHJlcXVlc3QsIHJlc3BvbnNlKSA9PiB7XHJcbiAgICAgICAgcmVzcG9uc2Uuc2VuZEZpbGUoam9pbihfX2Rpcm5hbWUsICdwdWJsaWMnLCAnaW5kZXguaHRtbCcpKTtcclxuICAgICAgfSk7XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgY2xlYXJBbGxUaW1lcnMgfSBmcm9tICcuL3RpbWVycy5qcyc7XHJcbmltcG9ydCB7IGtpbGxQb29sIH0gZnJvbSAnLi9wb29sLmpzJztcclxuaW1wb3J0IHsgY2xvc2VTZXJ2ZXJzIH0gZnJvbSAnLi9zZXJ2ZXIvc2VydmVyLmpzJztcclxuaW1wb3J0IHsgdGVybWluYXRlQ2xpZW50cyB9IGZyb20gJy4vc2VydmVyL3dlYl9zb2NrZXQuanMnO1xyXG5cclxuLyoqXHJcbiAqIENsZWFuIHVwIGZ1bmN0aW9uIHRvIHRyaWdnZXIgYmVmb3JlIGVuZGluZyBwcm9jZXNzIGZvciB0aGUgZ3JhY2VmdWwgc2h1dGRvd24uXHJcbiAqXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBleGl0Q29kZSAtIEFuIGV4aXQgY29kZSBmb3IgdGhlIHByb2Nlc3MuZXhpdCgpIGZ1bmN0aW9uLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHNodXRkb3duQ2xlYW5VcCA9IGFzeW5jIChleGl0Q29kZSkgPT4ge1xyXG4gIC8vIEF3YWl0IGZyZWVpbmcgYWxsIHJlc291cmNlc1xyXG4gIGF3YWl0IFByb21pc2UuYWxsU2V0dGxlZChbXHJcbiAgICAvLyBDbGVhciBhbGwgb25nb2luZyB0aW1lcnNcclxuICAgIGNsZWFyQWxsVGltZXJzKCksXHJcblxyXG4gICAgLy8gVGVybWluYXRlIGFsbCBjb25uZWN0ZWQgV2ViU29ja2V0IGNsaWVudHNcclxuICAgIHRlcm1pbmF0ZUNsaWVudHMoKSxcclxuXHJcbiAgICAvLyBHZXQgYXZhaWxhYmxlIHNlcnZlciBpbnN0YW5jZXMgKEhUVFAvSFRUUFMpIGFuZCBjbG9zZSB0aGVtXHJcbiAgICBjbG9zZVNlcnZlcnMoKSxcclxuXHJcbiAgICAvLyBDbG9zZSBwb29sIGFsb25nIHdpdGggaXRzIHdvcmtlcnMgYW5kIHRoZSBicm93c2VyIGluc3RhbmNlLCBpZiBleGlzdHNcclxuICAgIGtpbGxQb29sKClcclxuICBdKTtcclxuXHJcbiAgLy8gRXhpdCBwcm9jZXNzIHdpdGggYSBjb3JyZWN0IGNvZGVcclxuICBwcm9jZXNzLmV4aXQoZXhpdENvZGUpO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIHNodXRkb3duQ2xlYW5VcFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCAnY29sb3JzJztcclxuXHJcbmltcG9ydCB7IGNoZWNrQW5kVXBkYXRlQ2FjaGUgfSBmcm9tICcuL2NhY2hlLmpzJztcclxuaW1wb3J0IHtcclxuICBiYXRjaEV4cG9ydCxcclxuICBzZXRBbGxvd0NvZGVFeGVjdXRpb24sXHJcbiAgc2luZ2xlRXhwb3J0LFxyXG4gIHN0YXJ0RXhwb3J0XHJcbn0gZnJvbSAnLi9jaGFydC5qcyc7XHJcbmltcG9ydCB7IG1hcFRvTmV3Q29uZmlnLCBtYW51YWxDb25maWcsIHNldE9wdGlvbnMgfSBmcm9tICcuL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7XHJcbiAgaW5pdExvZ2dpbmcsXHJcbiAgbG9nLFxyXG4gIGxvZ1dpdGhTdGFjayxcclxuICBzZXRMb2dMZXZlbCxcclxuICBlbmFibGVGaWxlTG9nZ2luZ1xyXG59IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgaW5pdFBvb2wsIGtpbGxQb29sIH0gZnJvbSAnLi9wb29sLmpzJztcclxuaW1wb3J0IHsgc2h1dGRvd25DbGVhblVwIH0gZnJvbSAnLi9yZXNvdXJjZV9yZWxlYXNlLmpzJztcclxuaW1wb3J0IHNlcnZlciwgeyBzdGFydFNlcnZlciB9IGZyb20gJy4vc2VydmVyL3NlcnZlci5qcyc7XHJcbmltcG9ydCB7IHByaW50TG9nbywgcHJpbnRVc2FnZSB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxuLyoqXHJcbiAqIEF0dGFjaGVzIGV4aXQgbGlzdGVuZXJzIHRvIHRoZSBwcm9jZXNzLCBlbnN1cmluZyBwcm9wZXIgY2xlYW51cCBvZiByZXNvdXJjZXNcclxuICogYW5kIHRlcm1pbmF0aW9uIG9uIGV4aXQgc2lnbmFscy4gSGFuZGxlcyAnZXhpdCcsICdTSUdJTlQnLCAnU0lHVEVSTScsIGFuZFxyXG4gKiAndW5jYXVnaHRFeGNlcHRpb24nIGV2ZW50cy5cclxuICovXHJcbmNvbnN0IGF0dGFjaFByb2Nlc3NFeGl0TGlzdGVuZXJzID0gKCkgPT4ge1xyXG4gIGxvZygzLCAnW3Byb2Nlc3NdIEF0dGFjaGluZyBleGl0IGxpc3RlbmVycyB0byB0aGUgcHJvY2Vzcy4nKTtcclxuXHJcbiAgLy8gSGFuZGxlciBmb3IgdGhlICdleGl0J1xyXG4gIHByb2Nlc3Mub24oJ2V4aXQnLCAoY29kZSkgPT4ge1xyXG4gICAgbG9nKDQsIGBQcm9jZXNzIGV4aXRlZCB3aXRoIGNvZGUgJHtjb2RlfS5gKTtcclxuICB9KTtcclxuXHJcbiAgLy8gSGFuZGxlciBmb3IgdGhlICdTSUdJTlQnXHJcbiAgcHJvY2Vzcy5vbignU0lHSU5UJywgYXN5bmMgKG5hbWUsIGNvZGUpID0+IHtcclxuICAgIGxvZyg0LCBgVGhlICR7bmFtZX0gZXZlbnQgd2l0aCBjb2RlOiAke2NvZGV9LmApO1xyXG4gICAgYXdhaXQgc2h1dGRvd25DbGVhblVwKDApO1xyXG4gIH0pO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ1NJR1RFUk0nXHJcbiAgcHJvY2Vzcy5vbignU0lHVEVSTScsIGFzeW5jIChuYW1lLCBjb2RlKSA9PiB7XHJcbiAgICBsb2coNCwgYFRoZSAke25hbWV9IGV2ZW50IHdpdGggY29kZTogJHtjb2RlfS5gKTtcclxuICAgIGF3YWl0IHNodXRkb3duQ2xlYW5VcCgwKTtcclxuICB9KTtcclxuXHJcbiAgLy8gSGFuZGxlciBmb3IgdGhlICdTSUdIVVAnXHJcbiAgcHJvY2Vzcy5vbignU0lHSFVQJywgYXN5bmMgKG5hbWUsIGNvZGUpID0+IHtcclxuICAgIGxvZyg0LCBgVGhlICR7bmFtZX0gZXZlbnQgd2l0aCBjb2RlOiAke2NvZGV9LmApO1xyXG4gICAgYXdhaXQgc2h1dGRvd25DbGVhblVwKDApO1xyXG4gIH0pO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ3VuY2F1Z2h0RXhjZXB0aW9uJ1xyXG4gIHByb2Nlc3Mub24oJ3VuY2F1Z2h0RXhjZXB0aW9uJywgYXN5bmMgKGVycm9yLCBuYW1lKSA9PiB7XHJcbiAgICBsb2dXaXRoU3RhY2soMSwgZXJyb3IsIGBUaGUgJHtuYW1lfSBlcnJvci5gKTtcclxuICAgIGF3YWl0IHNodXRkb3duQ2xlYW5VcCgxKTtcclxuICB9KTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyB0aGUgZXhwb3J0IHByb2Nlc3MuIFRhc2tzIHN1Y2ggYXMgY29uZmlndXJpbmcgbG9nZ2luZywgY2hlY2tpbmdcclxuICogY2FjaGUgYW5kIHNvdXJjZXMsIGFuZCBpbml0aWFsaXppbmcgdGhlIHBvb2wgb2YgcmVzb3VyY2VzIGhhcHBlbiBkdXJpbmdcclxuICogdGhpcyBzdGFnZS4gRnVuY3Rpb24gdGhhdCBpcyByZXF1aXJlZCB0byBiZSBjYWxsZWQgYmVmb3JlIHRyeWluZyB0byBleHBvcnQgY2hhcnRzIG9yIHNldHRpbmcgYSBzZXJ2ZXIuIFRoZSBgb3B0aW9uc2AgaXMgYW4gb2JqZWN0IHRoYXQgY29udGFpbnMgYWxsIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gQWxsIGV4cG9ydCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgdXBkYXRlZCBleHBvcnQgb3B0aW9ucy5cclxuICovXHJcbmNvbnN0IGluaXRFeHBvcnQgPSBhc3luYyAob3B0aW9ucykgPT4ge1xyXG4gIC8vIFNldCB0aGUgYWxsb3dDb2RlRXhlY3V0aW9uIHBlciBleHBvcnQgbW9kdWxlIHNjb3BlXHJcbiAgc2V0QWxsb3dDb2RlRXhlY3V0aW9uKFxyXG4gICAgb3B0aW9ucy5jdXN0b21Mb2dpYyAmJiBvcHRpb25zLmN1c3RvbUxvZ2ljLmFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICk7XHJcblxyXG4gIC8vIEluaXQgdGhlIGxvZ2dpbmdcclxuICBpbml0TG9nZ2luZyhvcHRpb25zLmxvZ2dpbmcpO1xyXG5cclxuICAvLyBBdHRhY2ggcHJvY2VzcycgZXhpdCBsaXN0ZW5lcnNcclxuICBpZiAob3B0aW9ucy5vdGhlci5saXN0ZW5Ub1Byb2Nlc3NFeGl0cykge1xyXG4gICAgYXR0YWNoUHJvY2Vzc0V4aXRMaXN0ZW5lcnMoKTtcclxuICB9XHJcblxyXG4gIC8vIENoZWNrIGlmIGNhY2hlIG5lZWRzIHRvIGJlIHVwZGF0ZWRcclxuICBhd2FpdCBjaGVja0FuZFVwZGF0ZUNhY2hlKG9wdGlvbnMpO1xyXG5cclxuICAvLyBJbml0IHRoZSBwb29sXHJcbiAgYXdhaXQgaW5pdFBvb2woe1xyXG4gICAgcG9vbDogb3B0aW9ucy5wb29sIHx8IHtcclxuICAgICAgbWluV29ya2VyczogMSxcclxuICAgICAgbWF4V29ya2VyczogMVxyXG4gICAgfSxcclxuICAgIHB1cHBldGVlckFyZ3M6IG9wdGlvbnMucHVwcGV0ZWVyLmFyZ3MgfHwgW11cclxuICB9KTtcclxuXHJcbiAgLy8gUmV0dXJuIHVwZGF0ZWQgb3B0aW9uc1xyXG4gIHJldHVybiBvcHRpb25zO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIC8vIFNlcnZlclxyXG4gIHNlcnZlcixcclxuICBzdGFydFNlcnZlcixcclxuXHJcbiAgLy8gRXhwb3J0aW5nXHJcbiAgaW5pdEV4cG9ydCxcclxuICBzaW5nbGVFeHBvcnQsXHJcbiAgYmF0Y2hFeHBvcnQsXHJcbiAgc3RhcnRFeHBvcnQsXHJcblxyXG4gIC8vIFBvb2xcclxuICBpbml0UG9vbCxcclxuICBraWxsUG9vbCxcclxuXHJcbiAgLy8gT3RoZXJcclxuICBzZXRPcHRpb25zLFxyXG4gIHNodXRkb3duQ2xlYW5VcCxcclxuXHJcbiAgLy8gTG9nc1xyXG4gIGxvZyxcclxuICBsb2dXaXRoU3RhY2ssXHJcbiAgc2V0TG9nTGV2ZWwsXHJcbiAgZW5hYmxlRmlsZUxvZ2dpbmcsXHJcblxyXG4gIC8vIFV0aWxzXHJcbiAgbWFwVG9OZXdDb25maWcsXHJcbiAgbWFudWFsQ29uZmlnLFxyXG4gIHByaW50TG9nbyxcclxuICBwcmludFVzYWdlXHJcbn07XHJcbiJdLCJuYW1lcyI6WyJzY3JpcHRzTmFtZXMiLCJjb3JlIiwibW9kdWxlcyIsImluZGljYXRvcnMiLCJkZWZhdWx0Q29uZmlnIiwicHVwcGV0ZWVyIiwiYXJncyIsInZhbHVlIiwidHlwZSIsImRlc2NyaXB0aW9uIiwiaGlnaGNoYXJ0cyIsInZlcnNpb24iLCJlbnZMaW5rIiwiY2RuVVJMIiwiY29yZVNjcmlwdHMiLCJtb2R1bGVTY3JpcHRzIiwiaW5kaWNhdG9yU2NyaXB0cyIsImN1c3RvbVNjcmlwdHMiLCJmb3JjZUZldGNoIiwiY2FjaGVQYXRoIiwiZXhwb3J0IiwiaW5maWxlIiwiaW5zdHIiLCJvcHRpb25zIiwib3V0ZmlsZSIsImNvbnN0ciIsImRlZmF1bHRIZWlnaHQiLCJkZWZhdWx0V2lkdGgiLCJkZWZhdWx0U2NhbGUiLCJoZWlnaHQiLCJ3aWR0aCIsInNjYWxlIiwiZ2xvYmFsT3B0aW9ucyIsInRoZW1lT3B0aW9ucyIsImJhdGNoIiwicmFzdGVyaXphdGlvblRpbWVvdXQiLCJjdXN0b21Mb2dpYyIsImFsbG93Q29kZUV4ZWN1dGlvbiIsImFsbG93RmlsZVJlc291cmNlcyIsImN1c3RvbUNvZGUiLCJjYWxsYmFjayIsInJlc291cmNlcyIsImxvYWRDb25maWciLCJsZWdhY3lOYW1lIiwiY3JlYXRlQ29uZmlnIiwic2VydmVyIiwiZW5hYmxlIiwiY2xpTmFtZSIsImhvc3QiLCJwb3J0IiwiYmVuY2htYXJraW5nIiwicHJveHkiLCJ0aW1lb3V0IiwicmF0ZUxpbWl0aW5nIiwibWF4UmVxdWVzdHMiLCJ3aW5kb3ciLCJkZWxheSIsInRydXN0UHJveHkiLCJza2lwS2V5Iiwic2tpcFRva2VuIiwic3NsIiwiZm9yY2UiLCJjZXJ0UGF0aCIsInBvb2wiLCJtaW5Xb3JrZXJzIiwibWF4V29ya2VycyIsIndvcmtMaW1pdCIsImFjcXVpcmVUaW1lb3V0IiwiY3JlYXRlVGltZW91dCIsImRlc3Ryb3lUaW1lb3V0IiwiaWRsZVRpbWVvdXQiLCJjcmVhdGVSZXRyeUludGVydmFsIiwicmVhcGVySW50ZXJ2YWwiLCJsb2dnaW5nIiwibGV2ZWwiLCJmaWxlIiwiZGVzdCIsInVpIiwicm91dGUiLCJvdGhlciIsIm5vZGVFbnYiLCJsaXN0ZW5Ub1Byb2Nlc3NFeGl0cyIsIm5vTG9nbyIsImhhcmRSZXNldFBhZ2UiLCJicm93c2VyU2hlbGxNb2RlIiwiZGVidWciLCJoZWFkbGVzcyIsImRldnRvb2xzIiwibGlzdGVuVG9Db25zb2xlIiwiZHVtcGlvIiwic2xvd01vIiwiZGVidWdnaW5nUG9ydCIsIndlYlNvY2tldCIsInJlY29ubmVjdCIsInJlamVjdFVuYXV0aG9yaXplZCIsInBpbmdUaW1lb3V0IiwicmVjb25uZWN0SW50ZXJ2YWwiLCJyZWNvbm5lY3RBdHRlbXB0cyIsIm1lc3NhZ2VJbnRlcnZhbCIsInVybCIsInNlY3JldCIsInByb21wdHNDb25maWciLCJuYW1lIiwibWVzc2FnZSIsImluaXRpYWwiLCJqb2luIiwic2VwYXJhdG9yIiwiaW5zdHJ1Y3Rpb25zIiwiY2hvaWNlcyIsImhpbnQiLCJtaW4iLCJtYXgiLCJyb3VuZCIsImFic29sdXRlUHJvcHMiLCJuZXN0ZWRBcmdzIiwiY3JlYXRlTmVzdGVkQXJncyIsIm9iaiIsInByb3BDaGFpbiIsIk9iamVjdCIsImtleXMiLCJmb3JFYWNoIiwiayIsImluY2x1ZGVzIiwiZW50cnkiLCJzdWJzdHJpbmciLCJ1bmRlZmluZWQiLCJkb3RlbnYiLCJjb25maWciLCJ2IiwiZmlsdGVyQXJyYXkiLCJ6Iiwic3RyaW5nIiwidHJhbnNmb3JtIiwic3BsaXQiLCJtYXAiLCJ0cmltIiwiZmlsdGVyIiwibGVuZ3RoIiwiZW51bSIsInZhbHVlcyIsInJlZmluZSIsImlzTmFOIiwicGFyc2VGbG9hdCIsImVudnMiLCJvYmplY3QiLCJISUdIQ0hBUlRTX1ZFUlNJT04iLCJ0ZXN0IiwiSElHSENIQVJUU19DRE5fVVJMIiwic3RhcnRzV2l0aCIsIkhJR0hDSEFSVFNfQ09SRV9TQ1JJUFRTIiwiSElHSENIQVJUU19NT0RVTEVfU0NSSVBUUyIsIkhJR0hDSEFSVFNfSU5ESUNBVE9SX1NDUklQVFMiLCJISUdIQ0hBUlRTX0ZPUkNFX0ZFVENIIiwiSElHSENIQVJUU19DQUNIRV9QQVRIIiwiSElHSENIQVJUU19BRE1JTl9UT0tFTiIsIkVYUE9SVF9UWVBFIiwiRVhQT1JUX0NPTlNUUiIsIkVYUE9SVF9ERUZBVUxUX0hFSUdIVCIsIkVYUE9SVF9ERUZBVUxUX1dJRFRIIiwiRVhQT1JUX0RFRkFVTFRfU0NBTEUiLCJFWFBPUlRfUkFTVEVSSVpBVElPTl9USU1FT1VUIiwiQ1VTVE9NX0xPR0lDX0FMTE9XX0NPREVfRVhFQ1VUSU9OIiwiQ1VTVE9NX0xPR0lDX0FMTE9XX0ZJTEVfUkVTT1VSQ0VTIiwiU0VSVkVSX0VOQUJMRSIsIlNFUlZFUl9IT1NUIiwiU0VSVkVSX1BPUlQiLCJTRVJWRVJfQkVOQ0hNQVJLSU5HIiwiU0VSVkVSX1BST1hZX0hPU1QiLCJTRVJWRVJfUFJPWFlfUE9SVCIsIlNFUlZFUl9QUk9YWV9USU1FT1VUIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfRU5BQkxFIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfTUFYX1JFUVVFU1RTIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfV0lORE9XIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfREVMQVkiLCJTRVJWRVJfUkFURV9MSU1JVElOR19UUlVTVF9QUk9YWSIsIlNFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfS0VZIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9UT0tFTiIsIlNFUlZFUl9TU0xfRU5BQkxFIiwiU0VSVkVSX1NTTF9GT1JDRSIsIlNFUlZFUl9TU0xfUE9SVCIsIlNFUlZFUl9TU0xfQ0VSVF9QQVRIIiwiUE9PTF9NSU5fV09SS0VSUyIsIlBPT0xfTUFYX1dPUktFUlMiLCJQT09MX1dPUktfTElNSVQiLCJQT09MX0FDUVVJUkVfVElNRU9VVCIsIlBPT0xfQ1JFQVRFX1RJTUVPVVQiLCJQT09MX0RFU1RST1lfVElNRU9VVCIsIlBPT0xfSURMRV9USU1FT1VUIiwiUE9PTF9DUkVBVEVfUkVUUllfSU5URVJWQUwiLCJQT09MX1JFQVBFUl9JTlRFUlZBTCIsIlBPT0xfQkVOQ0hNQVJLSU5HIiwiTE9HR0lOR19MRVZFTCIsIkxPR0dJTkdfRklMRSIsIkxPR0dJTkdfREVTVCIsIlVJX0VOQUJMRSIsIlVJX1JPVVRFIiwiT1RIRVJfTk9ERV9FTlYiLCJPVEhFUl9MSVNURU5fVE9fUFJPQ0VTU19FWElUUyIsIk9USEVSX05PX0xPR08iLCJPVEhFUl9IQVJEX1JFU0VUX1BBR0UiLCJPVEhFUl9CUk9XU0VSX1NIRUxMX01PREUiLCJERUJVR19FTkFCTEUiLCJERUJVR19IRUFETEVTUyIsIkRFQlVHX0RFVlRPT0xTIiwiREVCVUdfTElTVEVOX1RPX0NPTlNPTEUiLCJERUJVR19EVU1QSU8iLCJERUJVR19TTE9XX01PIiwiREVCVUdfREVCVUdHSU5HX1BPUlQiLCJXRUJfU09DS0VUX0VOQUJMRSIsIldFQl9TT0NLRVRfUkVDT05ORUNUIiwiV0VCX1NPQ0tFVF9SRUpFQ1RfVU5BVVRIT1JJWkVEIiwiV0VCX1NPQ0tFVF9QSU5HX1RJTUVPVVQiLCJXRUJfU09DS0VUX1JFQ09OTkVDVF9JTlRFUlZBTCIsIldFQl9TT0NLRVRfUkVDT05ORUNUX0FUVEVNUFRTIiwiV0VCX1NPQ0tFVF9NRVNTQUdFX0lOVEVSVkFMIiwiV0VCX1NPQ0tFVF9VUkwiLCJXRUJfU09DS0VUX1NFQ1JFVCIsInBhcnRpYWwiLCJwYXJzZSIsInByb2Nlc3MiLCJlbnYiLCJjb2xvcnMiLCJ0b0NvbnNvbGUiLCJ0b0ZpbGUiLCJwYXRoQ3JlYXRlZCIsImxldmVsc0Rlc2MiLCJ0aXRsZSIsImNvbG9yIiwibGlzdGVuZXJzIiwia2V5Iiwib3B0aW9uIiwiZW50cmllcyIsImxvZ1RvRmlsZSIsInRleHRzIiwicHJlZml4IiwiZXhpc3RzU3luYyIsIm1rZGlyU3luYyIsImFwcGVuZEZpbGUiLCJjb25jYXQiLCJlcnJvciIsImNvbnNvbGUiLCJsb2ciLCJuZXdMZXZlbCIsIkRhdGUiLCJ0b1N0cmluZyIsImZuIiwiYXBwbHkiLCJsb2dXaXRoU3RhY2siLCJjdXN0b21NZXNzYWdlIiwibWFpbk1lc3NhZ2UiLCJzdGFja01lc3NhZ2UiLCJzdGFjayIsInNsaWNlIiwic2V0TG9nTGV2ZWwiLCJlbmFibGVGaWxlTG9nZ2luZyIsImxvZ0Rlc3QiLCJsb2dGaWxlIiwiZW5kc1dpdGgiLCJfX2Rpcm5hbWUiLCJmaWxlVVJMVG9QYXRoIiwiVVJMIiwiZG9jdW1lbnQiLCJyZXF1aXJlIiwicGF0aFRvRmlsZVVSTCIsIl9fZmlsZW5hbWUiLCJocmVmIiwiX2RvY3VtZW50Q3VycmVudFNjcmlwdCIsInNyYyIsImJhc2VVUkkiLCJmaXhUeXBlIiwiZm9ybWF0cyIsIm91dFR5cGUiLCJwb3AiLCJmaW5kIiwidCIsImhhbmRsZVJlc291cmNlcyIsImFsbG93ZWRQcm9wcyIsImhhbmRsZWRSZXNvdXJjZXMiLCJjb3JyZWN0UmVzb3VyY2VzIiwiaXNDb3JyZWN0SlNPTiIsInJlYWRGaWxlU3luYyIsImZpbGVzIiwicHJvcE5hbWUiLCJpdGVtIiwiZGF0YSIsInBhcnNlZERhdGEiLCJKU09OIiwic3RyaW5naWZ5IiwiZGVlcENvcHkiLCJjb3B5IiwiQXJyYXkiLCJpc0FycmF5IiwicHJvdG90eXBlIiwiaGFzT3duUHJvcGVydHkiLCJjYWxsIiwib3B0aW9uc1N0cmluZ2lmeSIsImFsbG93RnVuY3Rpb25zIiwicmVwbGFjZUFsbCIsInByaW50VXNhZ2UiLCJib2xkIiwieWVsbG93IiwiY3ljbGVDYXRlZ29yaWVzIiwiZGVzY05hbWUiLCJncmVlbiIsImkiLCJibHVlIiwiY2F0ZWdvcnkiLCJ0b1VwcGVyQ2FzZSIsInJlZCIsInRvQm9vbGVhbiIsIndyYXBBcm91bmQiLCJyZXBsYWNlIiwibWVhc3VyZVRpbWUiLCJzdGFydCIsImhydGltZSIsImJpZ2ludCIsIk51bWJlciIsImdlbmVyYWxPcHRpb25zIiwiZ2V0T3B0aW9ucyIsIm1lcmdlQ29uZmlnT3B0aW9ucyIsIm5ld09wdGlvbnMiLCJtZXJnZWRPcHRpb25zIiwidXBkYXRlRGVmYXVsdENvbmZpZyIsImNvbmZpZ09iaiIsImN1c3RvbU9iaiIsImN1c3RvbVZhbHVlIiwiaW5pdE9wdGlvbnMiLCJpdGVtcyIsInJlY3Vyc2l2ZVByb3BzIiwib2JqZWN0VG9VcGRhdGUiLCJuZXN0ZWROYW1lcyIsInNoaWZ0IiwiYXNzaWduIiwiYXN5bmMiLCJmZXRjaCIsInJlcXVlc3RPcHRpb25zIiwiUHJvbWlzZSIsInJlc29sdmUiLCJyZWplY3QiLCJwcm90b2NvbCIsImh0dHBzIiwiaHR0cCIsImdldFByb3RvY29sIiwiZ2V0IiwicmVzIiwib24iLCJjaHVuayIsInRleHQiLCJFeHBvcnRFcnJvciIsIkVycm9yIiwiY29uc3RydWN0b3IiLCJzdXBlciIsInRoaXMiLCJzZXRFcnJvciIsInN0YXR1c0NvZGUiLCJjYWNoZSIsImFjdGl2ZU1hbmlmZXN0Iiwic291cmNlcyIsImhjVmVyc2lvbiIsImV4dHJhY3RWZXJzaW9uIiwiaW5kZXhPZiIsImZldGNoQW5kUHJvY2Vzc1NjcmlwdCIsInNjcmlwdCIsImZldGNoZWRNb2R1bGVzIiwic2hvdWxkVGhyb3dFcnJvciIsInJlc3BvbnNlIiwidXBkYXRlQ2FjaGUiLCJoaWdoY2hhcnRzT3B0aW9ucyIsInByb3h5T3B0aW9ucyIsInNvdXJjZVBhdGgiLCJwcm94eUFnZW50IiwicHJveHlIb3N0IiwicHJveHlQb3J0IiwiSHR0cHNQcm94eUFnZW50IiwiYWdlbnQiLCJhbGxGZXRjaFByb21pc2VzIiwiYWxsIiwiZmV0Y2hTY3JpcHRzIiwiYyIsIm0iLCJ3cml0ZUZpbGVTeW5jIiwiY2hlY2tBbmRVcGRhdGVDYWNoZSIsIm1hbmlmZXN0UGF0aCIsInJlcXVlc3RVcGRhdGUiLCJtYW5pZmVzdCIsIm1vZHVsZU1hcCIsIm51bWJlck9mTW9kdWxlcyIsInNvbWUiLCJtb2R1bGVOYW1lIiwibmV3TWFuaWZlc3QiLCJzYXZlQ29uZmlnVG9NYW5pZmVzdCIsImdldENhY2hlUGF0aCIsInNldHVwSGlnaGNoYXJ0cyIsIkhpZ2hjaGFydHMiLCJhbmltT2JqZWN0IiwiZHVyYXRpb24iLCJ0cmlnZ2VyRXhwb3J0IiwiY2hhcnRPcHRpb25zIiwiZGlzcGxheUVycm9ycyIsIl9kaXNwbGF5RXJyb3JzIiwibWVyZ2UiLCJzZXRPcHRpb25zIiwid3JhcCIsInNldE9wdGlvbnNPYmoiLCJGdW5jdGlvbiIsImNoYXJ0IiwiYW5pbWF0aW9uIiwic3RySW5qIiwiaXNSZW5kZXJDb21wbGV0ZSIsIkNoYXJ0IiwicHJvY2VlZCIsInVzZXJPcHRpb25zIiwiY2IiLCJleHBvcnRpbmciLCJlbmFibGVkIiwicGxvdE9wdGlvbnMiLCJzZXJpZXMiLCJsYWJlbCIsInRvb2x0aXAiLCJvbkhpZ2hjaGFydHNSZW5kZXIiLCJhZGRFdmVudCIsIlNlcmllcyIsImZpbmFsT3B0aW9ucyIsImZpbmFsQ2FsbGJhY2siLCJkZWZhdWx0T3B0aW9ucyIsInByb3AiLCJ0ZW1wbGF0ZSIsImJyb3dzZXIiLCJuZXdQYWdlIiwicGFnZSIsInNldENhY2hlRW5hYmxlZCIsInNldFBhZ2VDb250ZW50IiwiJGV2YWwiLCJlbGVtZW50IiwiZXJyb3JNZXNzYWdlIiwiaW5uZXJIVE1MIiwic2V0UGFnZUV2ZW50cyIsImNsZWFyUGFnZVJlc291cmNlcyIsImluamVjdGVkUmVzb3VyY2VzIiwicmVzb3VyY2UiLCJkaXNwb3NlIiwiZXZhbHVhdGUiLCJvbGRDaGFydHMiLCJjaGFydHMiLCJvbGRDaGFydCIsImRlc3Ryb3kiLCJzY3JpcHRzVG9SZW1vdmUiLCJnZXRFbGVtZW50c0J5VGFnTmFtZSIsInN0eWxlc1RvUmVtb3ZlIiwibGlua3NUb1JlbW92ZSIsInJlbW92ZSIsInNldENvbnRlbnQiLCJ3YWl0VW50aWwiLCJhZGRTY3JpcHRUYWciLCJwYXRoIiwic2V0QXNDb25maWciLCJwdXBwZXRlZXJFeHBvcnQiLCJleHBvcnRPcHRpb25zIiwiZGVidWdnZXIiLCJpc1NWRyIsInN2Z1RlbXBsYXRlIiwiaW5qZWN0ZWRKcyIsImpzIiwicHVzaCIsImNvbnRlbnQiLCJpc0xvY2FsIiwianNSZXNvdXJjZSIsImluamVjdGVkQ3NzIiwiY3NzIiwiY3NzSW1wb3J0cyIsIm1hdGNoIiwiY3NzSW1wb3J0UGF0aCIsImNzc1Jlc291cmNlIiwiYWRkU3R5bGVUYWciLCJhZGRQYWdlUmVzb3VyY2VzIiwic2l6ZSIsInN2Z0VsZW1lbnQiLCJxdWVyeVNlbGVjdG9yIiwiY2hhcnRIZWlnaHQiLCJiYXNlVmFsIiwiY2hhcnRXaWR0aCIsImJvZHkiLCJzdHlsZSIsInpvb20iLCJtYXJnaW4iLCJ2aWV3cG9ydEhlaWdodCIsIk1hdGgiLCJjZWlsIiwidmlld3BvcnRXaWR0aCIsIngiLCJ5IiwiZ2V0Qm91bmRpbmdDbGllbnRSZWN0IiwidHJ1bmMiLCJnZXRDbGlwUmVnaW9uIiwic2V0Vmlld3BvcnQiLCJkZXZpY2VTY2FsZUZhY3RvciIsIm91dGVySFRNTCIsImNyZWF0ZVNWRyIsImVuY29kaW5nIiwiY2xpcCIsInJhY2UiLCJzY3JlZW5zaG90IiwiY2FwdHVyZUJleW9uZFZpZXdwb3J0IiwiZnVsbFBhZ2UiLCJvcHRpbWl6ZUZvclNwZWVkIiwicXVhbGl0eSIsIm9taXRCYWNrZ3JvdW5kIiwiX3Jlc29sdmUiLCJzZXRUaW1lb3V0IiwiY3JlYXRlSW1hZ2UiLCJlbXVsYXRlTWVkaWFUeXBlIiwicGRmIiwiY3JlYXRlUERGIiwic3RhdHMiLCJwZXJmb3JtZWRFeHBvcnRzIiwiZXhwb3J0QXR0ZW1wdHMiLCJleHBvcnRGcm9tU3ZnQXR0ZW1wdHMiLCJ0aW1lU3BlbnQiLCJkcm9wcGVkRXhwb3J0cyIsInNwZW50QXZlcmFnZSIsInBvb2xDb25maWciLCJmYWN0b3J5IiwiY3JlYXRlIiwiaWQiLCJ1dWlkIiwic3RhcnREYXRlIiwiZ2V0VGltZSIsImlzQ2xvc2VkIiwid29ya0NvdW50IiwicmFuZG9tIiwidmFsaWRhdGUiLCJ3b3JrZXJIYW5kbGUiLCJjbG9zZSIsImluaXRQb29sIiwicHVwcGV0ZWVyQXJncyIsImVuYWJsZWREZWJ1ZyIsImRlYnVnT3B0aW9ucyIsImxhdW5jaE9wdGlvbnMiLCJ1c2VyRGF0YURpciIsImhhbmRsZVNJR0lOVCIsImhhbmRsZVNJR1RFUk0iLCJoYW5kbGVTSUdIVVAiLCJ3YWl0Rm9ySW5pdGlhbFBhZ2UiLCJkZWZhdWx0Vmlld3BvcnQiLCJ0cnlDb3VudCIsIm9wZW4iLCJsYXVuY2giLCJjcmVhdGVCcm93c2VyIiwicGFyc2VJbnQiLCJQb29sIiwiYWNxdWlyZVRpbWVvdXRNaWxsaXMiLCJjcmVhdGVUaW1lb3V0TWlsbGlzIiwiZGVzdHJveVRpbWVvdXRNaWxsaXMiLCJpZGxlVGltZW91dE1pbGxpcyIsImNyZWF0ZVJldHJ5SW50ZXJ2YWxNaWxsaXMiLCJyZWFwSW50ZXJ2YWxNaWxsaXMiLCJwcm9wYWdhdGVDcmVhdGVFcnJvciIsImhhcmRSZXNldCIsImdvdG8iLCJjbGVhclBhZ2UiLCJldmVudElkIiwiaW5pdGlhbFJlc291cmNlcyIsImFjcXVpcmUiLCJwcm9taXNlIiwicmVsZWFzZSIsImtpbGxQb29sIiwid29ya2VyIiwidXNlZCIsImRlc3Ryb3llZCIsImNvbm5lY3RlZCIsImNsb3NlQnJvd3NlciIsInBvc3RXb3JrIiwiYXZhaWxhYmxlIiwicGVuZGluZyIsImdldFBvb2xJbmZvSlNPTiIsImdldFBvb2xJbmZvIiwiYWNxdWlyZUNvdW50ZXIiLCJwYXlsb2FkIiwicmVxdWVzdElkIiwid29ya1N0YXJ0IiwiZXhwb3J0Q291bnRlciIsInJlc3VsdCIsImV4cG9ydFRpbWUiLCJudW1GcmVlIiwibnVtVXNlZCIsIm51bVBlbmRpbmdBY3F1aXJlcyIsImdldFN0YXRzIiwic3RhcnRFeHBvcnQiLCJzZXR0aW5ncyIsImVuZENhbGxiYWNrIiwic3ZnIiwiaW5pdEV4cG9ydFNldHRpbmdzIiwiZXhwb3J0QXNTdHJpbmciLCJpbnB1dCIsIkpTRE9NIiwiRE9NUHVyaWZ5Iiwic2FuaXRpemUiLCJBRERfVEFHUyIsImRvU3RyYWlnaHRJbmplY3QiLCJkb0V4cG9ydCIsImZpbmRDaGFydFNpemUiLCJwcmVjaXNpb24iLCJtdWx0aXBsaWVyIiwicG93Iiwicm91bmROdW1iZXIiLCJzb3VyY2VIZWlnaHQiLCJzb3VyY2VXaWR0aCIsInBhcmFtIiwiY2hhcnRKc29uIiwiY3VzdG9tTG9naWNPcHRpb25zIiwiYWxsb3dDb2RlRXhlY3V0aW9uU2NvcGVkIiwib3B0aW9uc05hbWUiLCJzdHJpbmdUb0V4cG9ydCIsImNoYXJ0SlNPTiIsInRpbWVySWRzIiwiYWRkVGltZXIiLCJjbGVhckFsbFRpbWVycyIsImNsZWFySW50ZXJ2YWwiLCJjbGVhclRpbWVvdXQiLCJsb2dFcnJvck1pZGRsZXdhcmUiLCJyZXEiLCJuZXh0IiwicmV0dXJuRXJyb3JNaWRkbGV3YXJlIiwic3RDb2RlIiwic3RhdHVzIiwianNvbiIsInJhdGVMaW1pdCIsImFwcCIsImxpbWl0Q29uZmlnIiwibXNnIiwicmF0ZU9wdGlvbnMiLCJsaW1pdGVyIiwid2luZG93TXMiLCJkZWxheU1zIiwiaGFuZGxlciIsInJlcXVlc3QiLCJmb3JtYXQiLCJzZW5kIiwiZGVmYXVsdCIsInNraXAiLCJxdWVyeSIsImFjY2Vzc190b2tlbiIsInVzZSIsInRlbGVtZXRyeVRlbXBsYXRlIiwidGVsZW1ldHJ5RGF0YSIsIm51bWJlck9mUmVxdWVzdHMiLCJvcHRpb25zSW5BcnJheSIsImZpbHRlckRhdGEiLCJmaWx0ZXJlZE9iamVjdCIsInRlbXBsYXRlS2V5IiwidGVtcGxhdGVWYWx1ZSIsImluZGV4Iiwib3B0aW9uc1ZhbHVlIiwicHJlcGFyZVRlbGVtZXRyeSIsIndlYlNvY2tldENsaWVudHMiLCJNYXAiLCJ3ZWJTb2NrZXRPcHRpb25zIiwiaW5pdCIsImFkZHJlc3MiLCJjb25uZWN0aW9uT3B0aW9ucyIsImhlYWRlcnMiLCJhdXRoIiwiand0Iiwic2lnbiIsInN1Y2Nlc3MiLCJhbGdvcml0aG0iLCJjbGllbnRPcHRpb25zIiwicmVjb25uZWN0VHJ5IiwiY29ubmVjdCIsInNldEludGVydmFsIiwid2ViU29ja2V0Q2xpZW50IiwicmVhZHlTdGF0ZSIsIldlYlNvY2tldCIsIk9QRU4iLCJzZW5kaW5nTWVzc2FnZUludGVydmFsIiwid2ViU29ja2V0VXJsIiwic2V0IiwiY29kZSIsImRlbGV0ZSIsInRlcm1pbmF0ZSIsInRlcm1pbmF0ZUNsaWVudHMiLCJjbGllbnQiLCJjbGVhciIsIkh0dHBFcnJvciIsInNldFN0YXR1cyIsInZTd2l0Y2hSb3V0ZSIsInBvc3QiLCJhZG1pblRva2VuIiwidG9rZW4iLCJuZXdWZXJzaW9uIiwicGFyYW1zIiwidXBkYXRlVmVyc2lvbiIsInJldmVyc2VkTWltZSIsInBuZyIsImpwZWciLCJnaWYiLCJyZXF1ZXN0c0NvdW50ZXIiLCJiZWZvcmVSZXF1ZXN0IiwiYWZ0ZXJSZXF1ZXN0IiwiZG9DYWxsYmFja3MiLCJjYWxsYmFja3MiLCJ1bmlxdWVJZCIsImNhbGxSZXNwb25zZSIsImV4cG9ydEhhbmRsZXIiLCJzdG9wQ291bnRlciIsImNvbm5lY3Rpb24iLCJyZW1vdGVBZGRyZXNzIiwiY29ubmVjdGlvbkFib3J0ZWQiLCJzb2NrZXQiLCJ0b0xvd2VyQ2FzZSIsInN1YnN0ciIsImI2NCIsIm5vRG93bmxvYWQiLCJwYXR0ZXJuIiwiaXNQcml2YXRlUmFuZ2VVcmxGb3VuZCIsImluZm8iLCJyZW1vdmVBbGxMaXN0ZW5lcnMiLCJCdWZmZXIiLCJmcm9tIiwiaGVhZGVyIiwiYXR0YWNobWVudCIsImZpbGVuYW1lIiwicGtnRmlsZSIsInBhdGhlciIsInNlcnZlclN0YXJ0VGltZSIsInN1Y2Nlc3NSYXRlcyIsImFkZEhlYWx0aFJvdXRlcyIsInN1Y2Nlc3NSYXRpbyIsIl8iLCJwZXJpb2QiLCJtb3ZpbmdBdmVyYWdlIiwicmVkdWNlIiwiYSIsImIiLCJib290VGltZSIsInVwdGltZSIsImZsb29yIiwiaGlnaGNoYXJ0c1ZlcnNpb24iLCJhdmVyYWdlUHJvY2Vzc2luZ1RpbWUiLCJmYWlsZWRFeHBvcnRzIiwic3VjZXNzUmF0aW8iLCJ0b0ZpeGVkIiwic3ZnRXhwb3J0QXR0ZW1wdHMiLCJqc29uRXhwb3J0QXR0ZW1wdHMiLCJhY3RpdmVTZXJ2ZXJzIiwiZXhwcmVzcyIsImRpc2FibGUiLCJjb3JzIiwic3RvcmFnZSIsIm11bHRlciIsIm1lbW9yeVN0b3JhZ2UiLCJ1cGxvYWQiLCJsaW1pdHMiLCJmaWVsZFNpemUiLCJsaW1pdCIsInVybGVuY29kZWQiLCJleHRlbmRlZCIsIm5vbmUiLCJhdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzIiwic3RhcnRTZXJ2ZXIiLCJzZXJ2ZXJDb25maWciLCJodHRwU2VydmVyIiwiY3JlYXRlU2VydmVyIiwibGlzdGVuIiwid2ViU29ja2V0SW5pdCIsImNlcnQiLCJmc1Byb21pc2VzIiwicmVhZEZpbGUiLCJwb3NpeCIsImh0dHBzU2VydmVyIiwiTmFOIiwic3RhdGljIiwiaGVhbHRoUm91dGUiLCJleHBvcnRSb3V0ZXMiLCJzZW5kRmlsZSIsInVpUm91dGUiLCJlcnJvckhhbmRsZXIiLCJjbG9zZVNlcnZlcnMiLCJnZXRTZXJ2ZXJzIiwiZW5hYmxlUmF0ZUxpbWl0aW5nIiwiZ2V0RXhwcmVzcyIsImdldEFwcCIsIm1pZGRsZXdhcmVzIiwic2h1dGRvd25DbGVhblVwIiwiZXhpdENvZGUiLCJhbGxTZXR0bGVkIiwiZXhpdCIsImluaXRFeHBvcnQiLCJpbml0TG9nZ2luZyIsInNpbmdsZUV4cG9ydCIsImJhdGNoRXhwb3J0IiwiYmF0Y2hGdW5jdGlvbnMiLCJwYWlyIiwiY29uZmlnSW5kZXgiLCJmaW5kSW5kZXgiLCJhcmciLCJmaWxlTmFtZSIsImxvYWRDb25maWdGaWxlIiwic2hvd1VzYWdlIiwicHJvcGVydGllc0NoYWluIiwiYXJndW1lbnRUeXBlIiwicGFpckFyZ3VtZW50VmFsdWUiLCJtYXBUb05ld0NvbmZpZyIsIm9sZE9wdGlvbnMiLCJtYW51YWxDb25maWciLCJjb25maWdGaWxlTmFtZSIsImNvbmZpZ0ZpbGUiLCJjaG9pY2UiLCJwcm9tcHRzIiwib25TdWJtaXQiLCJwIiwiY2F0ZWdvcmllcyIsInF1ZXN0aW9uc0NvdW50ZXIiLCJhbGxRdWVzdGlvbnMiLCJzZWN0aW9uIiwicHJvbXB0IiwiYW5zd2VyIiwibW9kdWxlIiwicHJvbWlzZXMiLCJ3cml0ZUZpbGUiLCJwcmludExvZ28iLCJwYWNrYWdlVmVyc2lvbiJdLCJtYXBwaW5ncyI6InlmQWVPLE1BQU1BLEVBQWUsQ0FDMUJDLEtBQU0sQ0FBQyxhQUFjLGtCQUFtQixpQkFDeENDLFFBQVMsQ0FDUCxRQUNBLE1BQ0EsUUFDQSxZQUNBLGNBQ0EsdUJBQ0EsZ0JBRUEsZUFDQSxRQUNBLE9BQ0EsYUFDQSxtQkFDQSxlQUNBLGNBQ0EsVUFDQSxVQUNBLGNBQ0EsV0FDQSxVQUNBLFlBQ0EsY0FDQSxZQUNBLHNCQUNBLFNBQ0EsU0FDQSxXQUNBLGFBQ0EsWUFDQSxlQUNBLHlCQUNBLFNBQ0EsZUFDQSxZQUNBLGtCQUNBLFNBQ0EsY0FDQSxtQkFDQSxlQUNBLGNBQ0EsZUFFQSxjQUNBLFdBQ0EsZUFDQSxXQUNBLFNBQ0EsT0FDQSxXQUNBLFlBQ0EsU0FDQSxxQkFDQSxhQUNBLFdBQ0EsV0FDQSxXQUNBLFdBQ0EsZUFDQSxVQUNBLGtCQUNBLG9CQUNBLGFBQ0EsV0FFRkMsV0FBWSxDQUFDLG1CQUtGQyxFQUFnQixDQUMzQkMsVUFBVyxDQUNUQyxLQUFNLENBQ0pDLE1BQU8sQ0FDTCxtQ0FDQSxrQkFDQSwwQ0FDQSwyQkFDQSxrQ0FDQSxrQ0FDQSx3Q0FDQSwyQ0FDQSxxQkFDQSw0QkFDQSwyQ0FDQSx1REFDQSw2QkFDQSx5QkFDQSwwQkFDQSwrQkFDQSx1QkFDQSx1RkFDQSx5QkFDQSxvQ0FDQSxvQkFDQSwwQkFDQSw4Q0FDQSwyQkFDQSwwQkFDQSw2QkFDQSxtQ0FDQSx3Q0FDQSxtQ0FD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 +"use strict";require("colors");var e=require("fs"),t=require("path"),r=require("https-proxy-agent"),o=require("prompts"),i=require("dotenv"),n=require("zod"),s=require("url"),a=require("http"),c=require("https"),l=require("tarn"),p=require("uuid"),u=require("puppeteer"),h=require("jsdom"),d=require("dompurify"),m=require("cors"),g=require("express"),f=require("multer"),v=require("express-rate-limit"),y=require("jsonwebtoken"),b=require("ws"),w="undefined"!=typeof document?document.currentScript:null;const E={core:["highcharts","highcharts-more","highcharts-3d"],modules:["stock","map","gantt","exporting","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","series-on-point","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","export-data","navigator","textpath"],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."},browserShellMode:{value:!0,type:"boolean",envLink:"OTHER_BROWSER_SHELL_MODE",description:"Decides if the browser runs in the shell mode."}},debug:{enable:{value:!1,type:"boolean",envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"Enables or disables debug mode for the underlying browser."},headless:{value:!0,type:"boolean",envLink:"DEBUG_HEADLESS",description:"Controls the mode in which the browser is launched when in the debug mode."},devtools:{value:!1,type:"boolean",envLink:"DEBUG_DEVTOOLS",description:"Decides whether to enable DevTools when the browser is in a headful state."},listenToConsole:{value:!1,type:"boolean",envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"Decides whether to enable a listener for console messages sent from the browser."},dumpio:{value:!1,type:"boolean",envLink:"DEBUG_DUMPIO",description:"Redirects browser process stdout and stderr to process.stdout and process.stderr."},slowMo:{value:0,type:"number",envLink:"DEBUG_SLOW_MO",description:"Slows down Puppeteer operations by the specified number of milliseconds."},debuggingPort:{value:9222,type:"number",envLink:"DEBUG_DEBUGGING_PORT",description:"Specifies the debugging port."}},webSocket:{enable:{value:!1,type:"boolean",envLink:"WEB_SOCKET_ENABLE",cliName:"enableWs",description:"Enables or disables the WebSocket connection."},reconnect:{value:!1,type:"boolean",envLink:"WEB_SOCKET_RECONNECT",cliName:"wsReconnect",description:"Controls whether or not to try reconnecting to the WebSocket server in case of a disconnect."},rejectUnauthorized:{value:!1,type:"boolean",envLink:"WEB_SOCKET_REJECT_UNAUTHORIZED",cliName:"wsrejectUnauthorized",description:"Determines whether the client verifies the server's SSL/TLS certificate during the handshake process."},pingTimeout:{value:16e3,type:"number",envLink:"WEB_SOCKET_PING_TIMEOUT",cliName:"wsPingTimeout",description:"The timeout, in milliseconds, for the heartbeat mechanism between the client and server."},reconnectInterval:{value:3e3,type:"number",envLink:"WEB_SOCKET_RECONNECT_INTERVAL",cliName:"wsReconnectInterval",description:"The interval, in milliseconds, for the reconnect attempt."},reconnectAttempts:{value:3,type:"number",envLink:"WEB_SOCKET_RECONNECT_ATTEMPTS",cliName:"wsReconnectAttempts",description:"The number of reconnect attempts before returning a connection error."},messageInterval:{value:3,type:"number",envLink:"WEB_SOCKET_MESSAGE_INTERVAL",cliName:"wsMessageInterval",description:"The interval, in milliseconds, for auto sending the data through a WebSocket connection."},url:{value:!1,type:"string",envLink:"WEB_SOCKET_URL",cliName:"wsUrl",description:"The URL of the WebSocket server."},secret:{value:!1,type:"string",envLink:"WEB_SOCKET_SECRET",cliName:"wsSecret",description:"The secret used to create a JSON Web Token sent to the WebSocket server."}}},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},{type:"toggle",name:"browserShellMode",message:"Decides if the browser runs in the shell mode",initial:T.other.browserShellMode.value}],debug:[{type:"toggle",name:"enable",message:"Enables debug mode for the browser instance",initial:T.debug.enable.value},{type:"toggle",name:"headless",message:"The mode setting for the browser",initial:T.debug.headless.value},{type:"toggle",name:"devtools",message:"The DevTools for the headful browser",initial:T.debug.devtools.value},{type:"toggle",name:"listenToConsole",message:"The event listener for console messages from the browser",initial:T.debug.listenToConsole.value},{type:"toggle",name:"dumpio",message:"Redirects the browser stdout and stderr to NodeJS process",initial:T.debug.dumpio.value},{type:"number",name:"slowMo",message:"Puppeteer operations slow down in milliseconds",initial:T.debug.slowMo.value},{type:"number",name:"debuggingPort",message:"The port number for debugging",initial:T.debug.debuggingPort.value}],webSocket:[{type:"toggle",name:"enable",message:"Enables WebSocket connection",initial:T.webSocket.enable.value},{type:"toggle",name:"reconnect",message:"The reconnect mechanism for WebSocket connection",initial:T.webSocket.reconnect.value},{type:"toggle",name:"rejectUnauthorized",message:"Reject connection if WebSocket is not secured, SSL/TLS",initial:T.webSocket.rejectUnauthorized.value},{type:"number",name:"pingTimeout",message:"Timeout for the hearbeat mechanism",initial:T.webSocket.pingTimeout.value},{type:"number",name:"reconnectInterval",message:"Interval for the reconnect mechanism",initial:T.webSocket.reconnectInterval.value},{type:"number",name:"reconnectAttempts",message:"The number of reconnect attempts",initial:T.webSocket.reconnectAttempts.value},{type:"number",name:"messageInterval",message:"Interval for auto sending the data",initial:T.webSocket.messageInterval.value},{type:"text",name:"url",message:"The URL of the WebSocket server",initial:T.webSocket.url.value},{type:"text",name:"secret",message:"The secret for the JWT to WebSocket server",initial:T.webSocket.secret.value}]},_=["options","globalOptions","themeOptions","resources","payload"],R={},k=(e,t="")=>{Object.keys(e).forEach((r=>{if(!["puppeteer","highcharts"].includes(r)){const o=e[r];void 0===o.value?k(o,`${t}.${r}`):(R[o.cliName||r]=`${t}.${r}`.substring(1),void 0!==o.legacyName&&(R[o.legacyName]=`${t}.${r}`.substring(1)))}}))};k(T),i.config();const x=e=>n.z.string().transform((t=>t.split(",").map((e=>e.trim())).filter((t=>e.includes(t))))).transform((e=>e.length?e:void 0)),O=()=>n.z.enum(["true","false",""]).transform((e=>""!==e?"true"===e:void 0)),L=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)),N=()=>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)),A=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:x(E.core),HIGHCHARTS_MODULE_SCRIPTS:x(E.modules),HIGHCHARTS_INDICATOR_SCRIPTS:x(E.indicators),HIGHCHARTS_FORCE_FETCH:O(),HIGHCHARTS_CACHE_PATH:I(),HIGHCHARTS_ADMIN_TOKEN:I(),EXPORT_TYPE:L(["jpeg","png","pdf","svg"]),EXPORT_CONSTR:L(["chart","stockChart","mapChart","ganttChart"]),EXPORT_DEFAULT_HEIGHT:C(),EXPORT_DEFAULT_WIDTH:C(),EXPORT_DEFAULT_SCALE:C(),EXPORT_RASTERIZATION_TIMEOUT:N(),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:O(),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:O(),SERVER_ENABLE:O(),SERVER_HOST:I(),SERVER_PORT:C(),SERVER_BENCHMARKING:O(),SERVER_PROXY_HOST:I(),SERVER_PROXY_PORT:C(),SERVER_PROXY_TIMEOUT:N(),SERVER_RATE_LIMITING_ENABLE:O(),SERVER_RATE_LIMITING_MAX_REQUESTS:N(),SERVER_RATE_LIMITING_WINDOW:N(),SERVER_RATE_LIMITING_DELAY:N(),SERVER_RATE_LIMITING_TRUST_PROXY:O(),SERVER_RATE_LIMITING_SKIP_KEY:I(),SERVER_RATE_LIMITING_SKIP_TOKEN:I(),SERVER_SSL_ENABLE:O(),SERVER_SSL_FORCE:O(),SERVER_SSL_PORT:C(),SERVER_SSL_CERT_PATH:I(),POOL_MIN_WORKERS:N(),POOL_MAX_WORKERS:N(),POOL_WORK_LIMIT:C(),POOL_ACQUIRE_TIMEOUT:N(),POOL_CREATE_TIMEOUT:N(),POOL_DESTROY_TIMEOUT:N(),POOL_IDLE_TIMEOUT:N(),POOL_CREATE_RETRY_INTERVAL:N(),POOL_REAPER_INTERVAL:N(),POOL_BENCHMARKING:O(),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:O(),UI_ROUTE:I(),OTHER_NODE_ENV:L(["development","production","test"]),OTHER_LISTEN_TO_PROCESS_EXITS:O(),OTHER_NO_LOGO:O(),OTHER_HARD_RESET_PAGE:O(),OTHER_BROWSER_SHELL_MODE:O(),DEBUG_ENABLE:O(),DEBUG_HEADLESS:O(),DEBUG_DEVTOOLS:O(),DEBUG_LISTEN_TO_CONSOLE:O(),DEBUG_DUMPIO:O(),DEBUG_SLOW_MO:N(),DEBUG_DEBUGGING_PORT:C(),WEB_SOCKET_ENABLE:O(),WEB_SOCKET_RECONNECT:O(),WEB_SOCKET_REJECT_UNAUTHORIZED:O(),WEB_SOCKET_PING_TIMEOUT:N(),WEB_SOCKET_RECONNECT_INTERVAL:N(),WEB_SOCKET_RECONNECT_ATTEMPTS:N(),WEB_SOCKET_MESSAGE_INTERVAL:N(),WEB_SOCKET_URL:I(),WEB_SOCKET_SECRET:I()}).partial().parse(process.env),P=["red","yellow","blue","gray","green"];let $={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))$[e]=t.value;const H=(t,r)=>{$.toFile&&($.pathCreated||(!e.existsSync($.dest)&&e.mkdirSync($.dest),$.pathCreated=!0),e.appendFile(`${$.dest}${$.file}`,[r].concat(t).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),$.toFile=!1)})))},U=(...e)=>{const[t,...r]=e,{level:o,levelsDesc:i}=$;if(5!==t&&(0===t||t>o||o>i.length))return;const n=`${(new Date).toString().split("(")[0].trim()} [${i[t-1].title}] -`;$.listeners.forEach((e=>{e(n,r.join(" "))})),$.toConsole&&console.log.apply(void 0,[n.toString()[$.levelsDesc[t-1].color]].concat(r)),H(r,n)},j=(e,t,r)=>{const o=r||t.message,{level:i,levelsDesc:n}=$;if(0===e||e>i||i>n.length)return;const s=`${(new Date).toString().split("(")[0].trim()} [${n[e-1].title}] -`,a=t.message!==t.stackMessage||void 0===t.stackMessage?t.stack:t.stack.split("\n").slice(1).join("\n"),c=[o,"\n",a];$.toConsole&&console.log.apply(void 0,[s.toString()[$.levelsDesc[e-1].color]].concat([o[P[e-1]],"\n",a])),$.listeners.forEach((e=>{e(s,c.join(" "))})),H(c,s)},W=e=>{e>=0&&e<=$.levelsDesc.length&&($.level=e)},D=(e,t)=>{if($={...$,dest:e||$.dest,file:t||$.file,toFile:!0},0===$.dest.length)return U(1,"[logger] File logging initialization: no path supplied.");$.dest.endsWith("/")||($.dest+="/")},G=s.fileURLToPath(new URL("../.","undefined"==typeof document?require("url").pathToFileURL(__filename).href:w&&w.src||new URL("index.cjs",document.baseURI).href)),M=(e,t)=>{const r=["png","jpeg","pdf","svg"];if(t){const o=t.split(".").pop();"jpg"===o?e="jpeg":r.includes(o)&&e!==o&&(e=o)}return{"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"}[e]||r.find((t=>t===e))||"png"},F=(t=!1,r)=>{const o=["js","css","files"];let i=t,n=!1;if(r&&t.endsWith(".json"))try{i=q(e.readFileSync(t,"utf8"))}catch(e){return j(2,e,"[cli] No resources found.")}else i=q(t),i&&!r&&delete i.files;for(const e in i)o.includes(e)?n||(n=!0):delete i[e];return n?(i.files&&(i.files=i.files.map((e=>e.trim())),(!i.files||i.files.length<=0)&&delete i.files),i):U(3,"[cli] No resources found.")};function q(e,t){try{const r=JSON.parse("string"!=typeof e?JSON.stringify(e):e);return"string"!=typeof r&&t?JSON.stringify(r):r}catch{return!1}}const 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 K(){console.log("\nUsage of CLI arguments:".bold,"\n------",`\nFor more detailed information, visit the readme at: ${"https://github.com/highcharts/node-export-server#readme".bold.yellow}.`);const e=t=>{for(const[r,o]of Object.entries(t))if(Object.prototype.hasOwnProperty.call(o,"value")){let e=` --${o.cliName||r} ${("<"+o.type+">").green} `;if(e.length<48)for(let t=e.length;t<48;t++)e+=".";console.log(e,o.description,`[Default: ${o.value.toString().bold}]`.blue)}else e(o)};Object.keys(T).forEach((t=>{["puppeteer","highcharts"].includes(t)||(console.log(`\n${t.toUpperCase()}`.red),e(T[t]))})),console.log("\n")}const z=e=>!["false","undefined","null","NaN","0",""].includes(e)&&!!e,X=(t,r)=>{if(t&&"string"==typeof t)return(t=t.trim()).endsWith(".js")?!!r&&X(e.readFileSync(t,"utf8")):t.startsWith("function()")||t.startsWith("function ()")||t.startsWith("()=>")||t.startsWith("() =>")?`(${t})()`:t.replace(/;$/,"")},J=()=>{const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6};let Y={};const Z=()=>Y,Q=(e,t,r=[])=>{const o=V(e);for(const[e,n]of Object.entries(t))o[e]="object"!=typeof(i=n)||Array.isArray(i)||null===i||r.includes(e)||void 0===o[e]?void 0!==n?n:o[e]:Q(o[e],n,r);var i;return o};function ee(e,t={},r=""){Object.keys(e).forEach((o=>{const i=e[o],n=t&&t[o];void 0===i.value?ee(i,n,`${r}.${o}`):(void 0!==n&&(i.value=n),i.envLink in A&&void 0!==A[i.envLink]&&(i.value=A[i.envLink]))}))}function te(e){let t={};for(const[r,o]of Object.entries(e))t[r]=Object.prototype.hasOwnProperty.call(o,"value")?o.value:te(o);return t}function re(e,t,r){for(;t.length>1;){const o=t.shift();return Object.prototype.hasOwnProperty.call(e,o)||(e[o]={}),e[o]=re(Object.assign({},e[o]),t,r),e}return e[t[0]]=r,e}async function oe(e,t={}){return new Promise(((r,o)=>{const i=(e=>e.startsWith("https")?c:a)(e);i.get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||o("Nothing was fetched from the URL."),e.text=t,r(e)}))})).on("error",(e=>{o(e)}))}))}class ie extends Error{constructor(e){super(),this.message=e,this.stackMessage=e}setError(e){return this.error=e,e.name&&(this.name=e.name),e.statusCode&&(this.statusCode=e.statusCode),e.stack&&(this.stackMessage=e.message,this.stack=e.stack),this}}const ne={cdnURL:"https://code.highcharts.com/",activeManifest:{},sources:"",hcVersion:""},se=e=>e.sources.substring(0,e.sources.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim(),ae=async(e,t,r,o=!1)=>{e.endsWith(".js")&&(e=e.substring(0,e.length-3)),U(4,`[cache] Fetching script - ${e}.js`);const i=await oe(`${e}.js`,t);if(200===i.statusCode&&"string"==typeof i.text){if(r){r[e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")]=1}return i.text}if(o)throw new ie(`Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${i.statusCode}).`).setError(i);return U(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`),""},ce=async(t,o,i)=>{const n=t.version,s="latest"!==n&&n?`${n}/`:"",a=t.cdnURL||ne.cdnURL;U(3,`[cache] Updating cache version to Highcharts: ${s||"latest"}.`);const c={};try{return ne.sources=await(async(e,t,o,i,n)=>{let s;const a=i.host,c=i.port;if(a&&c)try{s=new r.HttpsProxyAgent({host:a,port:c})}catch(e){throw new ie("[cache] Could not create a Proxy Agent.").setError(e)}const l=s?{agent:s,timeout:A.SERVER_PROXY_TIMEOUT}:{},p=[...e.map((e=>ae(`${e}`,l,n,!0))),...t.map((e=>ae(`${e}`,l,n))),...o.map((e=>ae(`${e}`,l)))];return(await Promise.all(p)).join(";\n")})([...t.coreScripts.map((e=>`${a}${s}${e}`))],[...t.moduleScripts.map((e=>"map"===e?`${a}maps/${s}modules/${e}`:`${a}${s}modules/${e}`)),...t.indicatorScripts.map((e=>`${a}stock/${s}indicators/${e}`))],t.customScripts,o,c),ne.hcVersion=se(ne),e.writeFileSync(i,ne.sources),c}catch(e){throw new ie("[cache] Unable to update the local Highcharts cache.").setError(e)}},le=async r=>{const{highcharts:o,server:i}=r,n=t.join(G,o.cachePath);let s;const a=t.join(n,"manifest.json"),c=t.join(n,"sources.js");if(!e.existsSync(n)&&e.mkdirSync(n),!e.existsSync(a)||o.forceFetch)U(3,"[cache] Fetching and caching Highcharts dependencies."),s=await ce(o,i.proxy,c);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:l,indicatorScripts:p}=o,u=n.length+l.length+p.length;r.version!==o.version?(U(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),t=!0):Object.keys(r.modules||{}).length!==u?(U(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),t=!0):t=(l||[]).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 ce(o,i.proxy,c):(U(3,"[cache] Dependency cache is up to date, proceeding."),ne.sources=e.readFileSync(c,"utf8"),s=r.modules,ne.hcVersion=se(ne))}await(async(r,o)=>{const i={version:r.version,modules:o||{}};ne.activeManifest=i,U(3,"[cache] Writing a new manifest.");try{e.writeFileSync(t.join(G,r.cachePath,"manifest.json"),JSON.stringify(i),"utf8")}catch(e){throw new ie("[cache] Error writing the cache manifest.").setError(e)}})(o,s)},pe=()=>t.join(G,Z().highcharts.cachePath),ue=()=>ne.hcVersion;function he(){Highcharts.animObject=function(){return{duration:0}}}async function de(e,t,r){window._displayErrors=r;const{getOptions:o,merge:i,setOptions:n,wrap:s}=Highcharts;Highcharts.setOptionsObj=i(!1,{},o()),t.customLogic.customCode&&new Function(t.customLogic.customCode)();const a={animation:!1};t.export.strInj&&(a.height=e.chart.height,a.width=e.chart.width),window.isRenderComplete=!1,s(Highcharts.Chart.prototype,"init",(function(e,t,r){((t=i(t,{exporting:{enabled:!1},plotOptions:{series:{label:{enabled:!1}}},tooltip:{}})).series||[]).forEach((function(e){e.animation=!1})),window.onHighchartsRender||(window.onHighchartsRender=Highcharts.addEvent(this,"render",(()=>{window.isRenderComplete=!0}))),e.apply(this,[t,r])})),s(Highcharts.Series.prototype,"init",(function(e,t,r){e.apply(this,[t,r])}));const c=t.export.strInj?new Function(`return ${t.export.strInj}`)():e,l=i(!1,JSON.parse(t.export.themeOptions),c,{chart:a}),p=t.customLogic.callback?new Function(`return ${t.customLogic.callback}`)():void 0,u=JSON.parse(t.export.globalOptions);u&&n(u),Highcharts[t.export.constr||"chart"]("container",l,p);const h=o();for(const e in h)"function"!=typeof h[e]&&delete h[e];n(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const me=e.readFileSync(G+"/templates/template.html","utf8");let ge;async function fe(){if(!ge)return!1;const e=await ge.newPage();return await e.setCacheEnabled(!1),await ye(e),function(e){const{debug:t}=Z();t.enable&&t.listenToConsole&&e.on("console",(e=>{console.log(`[debug] ${e.text()}`)}));e.on("pageerror",(async t=>{await e.$eval("#container",((e,t)=>{window._displayErrors&&(e.innerHTML=t)}),`

Chart input data error:

${t.toString()}`)}))}(e),e}async function ve(e,t){for(const e of t)await e.dispose();await e.evaluate((()=>{if("undefined"!=typeof Highcharts){const e=Highcharts.charts;if(Array.isArray(e)&&e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()}const[...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...r]=document.getElementsByTagName("link");for(const o of[...e,...t,...r])o.remove()}))}async function ye(e){await e.setContent(me,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:`${pe()}/sources.js`}),await e.evaluate(he)}const be=async(e,t,r,o)=>e.evaluate(de,t,r,o);var we=async(r,o,i)=>{let n=[];try{U(4,"[export] Determining export path.");const s=i.export,a=s?.options?.chart?.displayErrors&&ne.activeManifest.modules.debugger;let c;if(o.indexOf&&(o.indexOf("=0||o.indexOf("=0)){if(U(4,"[export] Treating as SVG."),"svg"===s.type)return o;c=!0,await r.setContent((e=>`\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`)(o),{waitUntil:"domcontentloaded"})}else U(4,"[export] Treating as config."),s.strInj?await be(r,{chart:{height:s.height,width:s.width}},i,a):(o.chart.height=s.height,o.chart.width=s.width,await be(r,o,i,a));n=await async function(r,o){const i=[],n=o.customLogic.resources;if(n){const s=[];if(n.js&&s.push({content:n.js}),n.files)for(const t of n.files){const r=!t.startsWith("http");s.push(r?{content:e.readFileSync(t,"utf8")}:{url:t})}for(const e of s)try{i.push(await r.addScriptTag(e))}catch(e){j(2,e,"[export] The JS resource cannot be loaded.")}s.length=0;const a=[];if(n.css){let e=n.css.match(/@import\s*([^;]*);/g);if(e)for(let r of e)r&&(r=r.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),r.startsWith("http")?a.push({url:r}):o.customLogic.allowFileResources&&a.push({path:t.join(G,r)}));a.push({content:n.css.replace(/@import\s*([^;]*);/g,"")||" "});for(const e of a)try{i.push(await r.addStyleTag(e))}catch(e){j(2,e,"[export] The CSS resource cannot be loaded.")}a.length=0}}return i}(r,i);const l=c?await r.evaluate((e=>{const t=document.querySelector("#chart-container svg:first-of-type"),r=t.height.baseVal.value*e,o=t.width.baseVal.value*e;return document.body.style.zoom=e,document.body.style.margin="0px",{chartHeight:r,chartWidth:o}}),parseFloat(s.scale)):await r.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return document.body.style.zoom=1,{chartHeight:e,chartWidth:t}})),p=Math.ceil(l.chartHeight||s.height),u=Math.ceil(l.chartWidth||s.width),{x:h,y:d}=await(e=>e.$eval("#chart-container",(e=>{const{x:t,y:r,width:o,height:i}=e.getBoundingClientRect();return{x:t,y:r,width:o,height:Math.trunc(i>1?i:500)}})))(r);let m;if(await r.setViewport({height:p,width:u,deviceScaleFactor:c?1:parseFloat(s.scale)}),"svg"===s.type)m=await(e=>e.$eval("#container svg:first-of-type",(e=>e.outerHTML)))(r);else if(["png","jpeg"].includes(s.type))m=await((e,t,r,o,i)=>Promise.race([e.screenshot({type:t,encoding:r,clip:o,captureBeyondViewport:!0,fullPage:!1,optimizeForSpeed:!0,..."png"!==t?{quality:80}:{},omitBackground:"png"==t}),new Promise(((e,t)=>setTimeout((()=>t(new ie("Rasterization timeout"))),i||1500)))]))(r,s.type,"base64",{width:u,height:p,x:h,y:d},s.rasterizationTimeout);else{if("pdf"!==s.type)throw new ie(`[export] Unsupported output format ${s.type}.`);m=await(async(e,t,r,o,i)=>(await e.emulateMediaType("screen"),Promise.race([e.pdf({height:t+1,width:r,encoding:o}),new Promise(((e,t)=>setTimeout((()=>t(new ie("Rasterization timeout"))),i||1500)))])))(r,p,u,"base64",s.rasterizationTimeout)}return await ve(r,n),m}catch(e){return await ve(r,n),e}};let Ee=!1;const Te={performedExports:0,exportAttempts:0,exportFromSvgAttempts:0,timeSpent:0,droppedExports:0,spentAverage:0};let Se={};const _e={create:async()=>{let e=!1;const t=p.v4(),r=(new Date).getTime();try{if(e=await fe(),!e||e.isClosed())throw new ie("The page is invalid or closed.");U(3,`[pool] Successfully created a worker ${t} - took ${(new Date).getTime()-r} ms.`)}catch(e){throw new ie("Error encountered when creating a new page.").setError(e)}return{id:t,page:e,workCount:Math.round(Math.random()*(Se.workLimit/2))}},validate:async e=>!(Se.workLimit&&++e.workCount>Se.workLimit)||(U(3,`[pool] Worker failed validation: exceeded work limit (limit is ${Se.workLimit}).`),!1),destroy:async e=>{U(3,`[pool] Destroying pool entry ${e.id}.`),e.page&&await e.page.close()}},Re=async e=>{if(Se=e&&e.pool?{...e.pool}:{},await async function(e){const{debug:t,other:r}=Z(),{enable:o,...i}=t,n={headless:!r.browserShellMode||"shell",userDataDir:"./tmp/",args:e,handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...o&&i};if(!ge){let e=0;const t=async()=>{try{U(3,`[browser] Attempting to get a browser instance (try ${++e}).`),ge=await u.launch(n)}catch(r){if(j(1,r,"[browser] Failed to launch a browser instance."),!(e<25))throw r;U(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await t()}};try{await t(),"shell"===n.headless&&U(3,"[browser] Launched browser in shell mode."),o&&U(3,"[browser] Launched browser in debug mode.")}catch(e){throw new ie("[browser] Maximum retries to open a browser instance reached.").setError(e)}if(!ge)throw new ie("[browser] Cannot find a browser to open.")}return ge}(e.puppeteerArgs),U(3,`[pool] Initializing pool with workers: min ${Se.minWorkers}, max ${Se.maxWorkers}.`),Ee)return U(4,"[pool] Already initialized, please kill it before creating a new one.");parseInt(Se.minWorkers)>parseInt(Se.maxWorkers)&&(Se.minWorkers=Se.maxWorkers);try{Ee=new l.Pool({..._e,min:parseInt(Se.minWorkers),max:parseInt(Se.maxWorkers),acquireTimeoutMillis:Se.acquireTimeout,createTimeoutMillis:Se.createTimeout,destroyTimeoutMillis:Se.destroyTimeout,idleTimeoutMillis:Se.idleTimeout,createRetryIntervalMillis:Se.createRetryInterval,reapIntervalMillis:Se.reaperInterval,propagateCreateError:!1}),Ee.on("release",(async e=>{await async function(e,t=!1){try{e.isClosed()||(t?(await e.goto("about:blank",{waitUntil:"domcontentloaded"}),await ye(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}.`)})),Ee.on("destroySuccess",((e,t)=>{U(4,`[pool] Destroyed a worker with ID ${t.id}.`)}));const e=[];for(let t=0;t{Ee.release(e)})),U(3,"[pool] The pool is ready"+(e.length?` with ${e.length} initial resources waiting.`:"."))}catch(e){throw new ie("[pool] Could not create the pool of workers.").setError(e)}};async function ke(){if(U(3,"[pool] Killing pool with all workers and closing browser."),Ee){for(const e of Ee.used)Ee.release(e.resource);Ee.destroyed||(await Ee.destroy(),U(4,"[browser] Destroyed the pool of resources."))}await async function(){ge?.connected&&await ge.close(),U(4,"[browser] Closed the browser.")}()}const xe=async(e,t)=>{let r;try{if(U(4,"[pool] Work received, starting to process."),++Te.exportAttempts,Se.benchmarking&&function(){const{min:e,max:t,all:r,available:o,used:i,pending:n}=Oe();U(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),U(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),U(5,`[pool] The number of all created resources: ${r}.`),U(5,`[pool] The number of available resources: ${o}.`),U(5,`[pool] The number of acquired resources: ${i}.`),U(5,`[pool] The number of resources waiting to be acquired: ${n}.`)}(),!Ee)throw new ie("Work received, but pool has not been started.");const o=J();try{U(4,"[pool] Acquiring a worker handle."),r=await Ee.acquire().promise,t.server.benchmarking&&U(5,t.payload?.requestId?`[benchmark] Request: ${t.payload?.requestId} -`:"[benchmark]",`Acquired a worker handle: ${o()}ms.`)}catch(e){throw new ie((t.payload?.requestId?`Request: ${t.payload?.requestId} - `:"")+`Error encountered when acquiring an available entry: ${o()}ms.`).setError(e)}if(U(4,"[pool] Acquired a worker handle."),!r.page)throw new ie("Resolved worker page is invalid: the pool setup is wonky.");let i=(new Date).getTime();U(4,`[pool] Starting work on pool entry with ID ${r.id}.`);const n=J(),s=await we(r.page,e,t);if(s instanceof Error)throw"Rasterization timeout"===s.message&&(r.page.close(),r.page=await fe()),new ie((t.payload?.requestId?`Request: ${t.payload?.requestId} - `:"")+`Error encountered during export: ${n()}ms.`).setError(s);t.server.benchmarking&&U(5,t.payload?.requestId?`[benchmark] Request: ${t.payload?.requestId} -`:"[benchmark]",`Exported a chart sucessfully: ${n()}ms.`),Ee.release(r);const a=(new Date).getTime()-i;return Te.timeSpent+=a,Te.spentAverage=Te.timeSpent/++Te.performedExports,U(4,`[pool] Work completed in ${a} ms.`),{result:s,options:t}}catch(e){throw++Te.droppedExports,r&&Ee.release(r),new ie(`[pool] In pool.postWork: ${e.message}`).setError(e)}},Oe=()=>({min:Ee.min,max:Ee.max,all:Ee.numFree()+Ee.numUsed(),available:Ee.numFree(),used:Ee.numUsed(),pending:Ee.numPendingAcquires()});function Le(){return Te}let Ie=!1;const Ce=async(t,r)=>{U(4,"[chart] Starting the exporting process.");const o=((e,t={})=>{let r={};return e.svg?(r=V(t),r.export.type=e.type||e.export.type,r.export.scale=e.scale||e.export.scale,r.export.outfile=e.outfile||e.export.outfile,r.payload={svg:e.svg}):r=Q(t,e,_),r.export.outfile=r.export?.outfile||`chart.${r.export?.type||"png"}`,r})(t,Z()),i=o.export;if(o.payload?.svg&&""!==o.payload.svg)try{U(4,"[chart] Attempting to export from a SVG input.");const e=$e(function(e){const t=new h.JSDOM("").window;return d(t).sanitize(e,{ADD_TAGS:["foreignObject"]})}(o.payload.svg),o,r);return++Te.exportFromSvgAttempts,e}catch(e){return r(new ie("[chart] Error loading SVG input.").setError(e))}if(i.infile&&i.infile.length)try{return U(4,"[chart] Attempting to export from an input file."),o.export.instr=e.readFileSync(i.infile,"utf8"),$e(o.export.instr.trim(),o,r)}catch(e){return r(new ie("[chart] Error loading input file.").setError(e))}if(i.instr&&""!==i.instr||i.options&&""!==i.options)try{return U(4,"[chart] Attempting to export from a raw input."),z(o.customLogic?.allowCodeExecution)?Pe(o,r):"string"==typeof i.instr?$e(i.instr.trim(),o,r):Ae(o,i.instr||i.options,r)}catch(e){return r(new ie("[chart] Error loading raw input.").setError(e))}return r(new ie("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'."))},Ne=e=>{const{chart:t,exporting:r}=e.export?.options||q(e.export?.instr),o=q(e.export?.globalOptions);let i=e.export?.scale||r?.scale||o?.exporting?.scale||e.export?.defaultScale||1;i=Math.max(.1,Math.min(i,5)),i=((e,t=1)=>{const r=Math.pow(10,t||0);return Math.round(+e*r)/r})(i,2);const n={height:e.export?.height||r?.sourceHeight||t?.height||o?.exporting?.sourceHeight||o?.chart?.height||e.export?.defaultHeight||400,width:e.export?.width||r?.sourceWidth||t?.width||o?.exporting?.sourceWidth||o?.chart?.width||e.export?.defaultWidth||600,scale:i};for(let[e,t]of Object.entries(n))n[e]="string"==typeof t?+t.replace(/px|%/gi,""):t;return n},Ae=async(t,r,o,i)=>{let{export:n,customLogic:s}=t;const a="boolean"==typeof s.allowCodeExecution?s.allowCodeExecution:Ie;if(s){if(a)if("string"==typeof t.customLogic.resources)t.customLogic.resources=F(t.customLogic.resources,z(t.customLogic.allowFileResources));else if(!t.customLogic.resources)try{const r=e.readFileSync("resources.json","utf8");t.customLogic.resources=F(r,z(t.customLogic.allowFileResources))}catch(e){j(2,e,"[chart] Unable to load the default resources.json file.")}}else s=t.customLogic={};if(!a&&s){if(s.callback||s.resources||s.customCode)return o(new ie("[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server."));s.callback=!1,s.resources=!1,s.customCode=!1}if(r&&(r.chart=r.chart||{},r.exporting=r.exporting||{},r.exporting.enabled=!1),n.constr=n.constr||"chart",n.type=M(n.type,n.outfile),"svg"===n.type&&(n.width=!1),["globalOptions","themeOptions"].forEach((t=>{try{n&&n[t]&&("string"==typeof n[t]&&n[t].endsWith(".json")?n[t]=q(e.readFileSync(n[t],"utf8"),!0):n[t]=q(n[t],!0))}catch(e){n[t]={},j(2,e,`[chart] The '${t}' cannot be loaded.`)}})),s.allowCodeExecution)try{s.customCode=X(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,...Ne(t)};try{return o(!1,await xe(n.strInj||r||i,t))}catch(e){return o(e)}},Pe=(e,t)=>{try{let r,o=e.export.instr||e.export.options;return"string"!=typeof o&&(r=o=B(o,e.customLogic?.allowCodeExecution)),r=o.replaceAll(/\t|\n|\r/g,"").trim(),";"===r[r.length-1]&&(r=r.substring(0,r.length-1)),e.export.strInj=r,Ae(e,!1,t)}catch(r){return t(new ie(`[chart] Malformed input detected for ${e.export?.requestId||"?"}. Please make sure that your JSON/JavaScript options are sent using the "options" attribute, and that if you're using SVG, it is unescaped.`).setError(r))}},$e=(e,t,r)=>{const{allowCodeExecution:o}=t.customLogic;if(e.indexOf("=0||e.indexOf("=0)return U(4,"[chart] Parsing input as SVG."),Ae(t,!1,r,e);try{const o=JSON.parse(e.replaceAll(/\t|\n|\r/g," "));return Ae(t,o,r)}catch(e){return z(o)?Pe(t,r):r(new ie("[chart] Only JSON configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the --allowCodeExecution flag.").setError(e))}},He=[],Ue=e=>{He.push(e)},je=()=>{U(4,"[server] Clearing all registered intervals and timeouts.");for(const e of He)clearInterval(e),clearTimeout(e)},We=(e,t,r,o)=>{j(1,e),"development"!==A.OTHER_NODE_ENV&&delete e.stack,o(e)},De=(e,t,r,o)=>{const{statusCode:i,status:n,message:s,stack:a}=e,c=i||n||500;r.status(c).json({statusCode:c,message:s,stack:a})};var Ge=(e,t)=>{const r="Too many requests, you have been rate limited. Please try again later.",o={max:t.maxRequests||30,window:t.window||1,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||!1,skipToken:t.skipToken||!1};o.trustProxy&&e.enable("trust proxy");const i=v({windowMs:60*o.window*1e3,max:o.max,delayMs:o.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:r})},default:()=>{t.status(429).send(r)}})},skip:e=>!1!==o.skipKey&&!1!==o.skipToken&&e.query.key===o.skipKey&&e.query.access_token===o.skipToken&&(U(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(i),U(3,`[rate limiting] Enabled rate limiting with ${o.max} requests per ${o.window} minute for each IP, trusting proxy: ${o.trustProxy}.`)};const Me=JSON.parse(e.readFileSync(t.join(G,"lib","schemas","telemetry.json"))),Fe={numberOfRequests:0},qe=["series","xAxis","yAxis","zAxis"];function Ve(e,t){const r={};for(const[o,i]of Object.entries(e))if(void 0!==t[o])if(null!==i)if(Array.isArray(t[o]))if(qe.includes(o)){r[o]=[];for(const[e,n]of t[o].entries())r[o][e]=Ve(i,n)}else r[o]=Ve(i,t[o][0]);else r[o]=Ve(i,t[o]);else r[o]=t[o];return r}function Be(e,t){Fe[t]=Ve(Me,e),Fe.numberOfRequests++}const Ke=new Map;let ze,Xe=null;function Je(e){if(ze=Z().webSocket,!0===ze.enable){const t={rejectUnauthorized:ze.rejectUnauthorized,headers:{auth:y.sign({success:"success"},ze.secret,{algorithm:"HS256"}),"X-Server-Address":`${e.protocol}://${["::","0.0.0.0"].includes(e.address)?"localhost":e.address}:${e.port}`}},r={id:p.v4(),reconnect:ze.reconnect,reconnectTry:0,reconnectInterval:null,pingTimeout:null};Ye(ze.url,t,r),function(e){Xe=setInterval((()=>{try{const t=(e?Ke.get(e):Ke.values()).next().value;t&&t.readyState===b.OPEN&&Object.keys(Fe).length>1&&Fe.numberOfRequests>0&&t.send(JSON.stringify(Fe))}catch(e){j(1,"[websocket] Could not send data through WebSocket.")}var e}),e.messageInterval),Ue(Xe)}(ze)}}function Ye(e,t,r){let o=new b(e,t);o.on("open",(()=>{clearInterval(r.reconnectInterval),Ke.set(r.id,o),U(3,`[websocket] WebSocket: ${r.id} - Connected to server: ${e}.`)})),o.on("close",(i=>{U(3,"[websocket]",`WebSocket: ${r.id} - Disconnected from server: ${e} with code: ${i}.`),clearTimeout(r.pingTimeout),Ke.delete(r.id),o=null,r.reconnect&&!r.reconnectInterval&&Ze(e,t,r)})),o.on("error",(e=>{j(1,e,`[websocket] WebSocket: ${r.id} - Error occured.`),e.message.includes("403")?(r.reconnect=!1,r.reconnectTry=ze.reconnectAttempts):r.reconnect=ze.reconnect})),o.on("message",(e=>{U(3,`[websocket] WebSocket: ${r.id} - Data received: ${e}`)})),o.on("ping",(()=>{U(3,`[websocket] WebSocket: ${r.id} - Received PING from server: ${e}.`),clearTimeout(r.pingTimeout),r.pingTimeout=setTimeout((()=>{o.terminate(),r.reconnect&&Ze(e,t,r)}),ze.pingTimeout)}))}function Ze(e,t,r){r.reconnectInterval=setInterval((()=>{r.reconnectTry!!e&&e.post("/version/change/:newVersion",(async(e,t,r)=>{try{const r=A.HIGHCHARTS_ADMIN_TOKEN;if(!r||!r.length)throw new et("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 et("Invalid or missing token: Set the token in the hc-auth header.",401);const i=e.params.newVersion;if(!i)throw new et("No new version supplied.",400);try{await(async e=>{const t=Z();t?.highcharts&&(t.highcharts.version=e),await le(t)})(i)}catch(e){throw new et(`Version change: ${e.message}`,e.statusCode).setError(e)}t.status(200).send({statusCode:200,version:ue(),message:`Successfully updated Highcharts to version: ${i}.`})}catch(e){r(e)}}));const rt={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};let ot=0;const it=[],nt=[],st=(e,t,r,o)=>{let i=!0;const{id:n,uniqueId:s,type:a,body:c}=o;return e.some((e=>{if(e){let o=e(t,r,n,s,a,c);return void 0!==o&&!0!==o&&(i=o),!0}})),i},at=async(e,t,r)=>{try{const r=J(),i=p.v4().replace(/-/g,""),n=Z(),s=e.body,a=++ot;let c=M(s.type);if(!s||"object"==typeof(o=s)&&!Array.isArray(o)&&null!==o&&0===Object.keys(o).length)throw new et("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 l=q(s.infile||s.options||s.data);if(!l&&!s.svg)throw U(2,`The request with ID ${i} from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Payload received: ${JSON.stringify(s)}.`),new et("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=st(it,e,t,{id:a,uniqueId:i,type:c,body:s}),!0!==u)return t.send(u);let h=!1;e.socket.on("close",(()=>{h=!0})),U(4,`[export] Got an incoming HTTP request with ID ${i}.`),s.constr="string"==typeof s.constr&&s.constr||"chart";const d={export:{instr:l,type:c,constr:s.constr[0].toLowerCase()+s.constr.substr(1),height:s.height,width:s.width,scale:s.scale||n.export.scale,globalOptions:q(s.globalOptions,!0),themeOptions:q(s.themeOptions,!0)},customLogic:{allowCodeExecution:Ie,allowFileResources:!1,resources:q(s.resources,!0),callback:s.callback,customCode:s.customCode}};l&&(d.export.instr=B(l,d.customLogic.allowCodeExecution));const m=Q(n,d);if(m.export.options=l,m.payload={svg:s.svg||!1,b64:s.b64||!1,noDownload:s.noDownload||!1,requestId:i},s.svg&&(e=>[/xlink:href="(?:http:\/\/|https:\/\/)?localhost\b/,/xlink:href="(?:http:\/\/|https:\/\/)?10\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?127\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?192\.168\.\d{1,3}\.\d{1,3}\b/].some((t=>t.test(e))))(m.payload.svg))throw new et("SVG potentially contain at least one forbidden URL in xlink:href element. Please review the SVG content and ensure that all referenced URLs comply with security policies.",400);await Ce(m,((o,l)=>{if(e.socket.removeAllListeners("close"),n.server.benchmarking&&U(5,`[benchmark] Request: ${i} - After the whole exporting process: ${r()}ms.`),h)return U(3,"[export] The client closed the connection before the chart finished processing.");if(o)throw o;if(!l||!l.result)throw new et(`Unexpected return from chart generation. Please check your request data. For the request with ID ${i}, the result is ${l.result}.`,400);return c=l.options.export.type,st(nt,e,t,{id:a,body:l.result}),Be(m.export.options,m.payload.requestId),l.result?s.b64?"pdf"===c||"svg"==c?t.send(Buffer.from(l.result,"utf8").toString("base64")):t.send(l.result):(t.header("Content-Type",rt[c]||"image/png"),s.noDownload||t.attachment(`${e.params.filename||e.body.filename||"chart"}.${c||"png"}`),"svg"===c?t.send(l.result):t.send(Buffer.from(l.result,"base64"))):void 0}))}catch(e){r(e)}var o};const ct=JSON.parse(e.readFileSync(t.join(G,"package.json"))),lt=new Date,pt=[];function ut(e){if(!e)return!1;Ue(setInterval((()=>{const e=Le(),t=0===e.exportAttempts?1:e.performedExports/e.exportAttempts*100;pt.push(t),pt.length>30&&pt.shift()}),6e4)),e.get("/health",((e,t)=>{const r=Le(),o=pt.length,i=pt.reduce(((e,t)=>e+t),0)/pt.length;U(4,"[health.js] GET /health [200] - returning server health."),t.send({status:"OK",bootTime:lt,uptime:Math.floor(((new Date).getTime()-lt.getTime())/1e3/60)+" minutes",version:ct.version,highchartsVersion:ue(),averageProcessingTime:r.spentAverage,performedExports:r.performedExports,failedExports:r.droppedExports,exportAttempts:r.exportAttempts,sucessRatio:r.performedExports/r.exportAttempts*100,pool:Oe(),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 ht=new Map,dt=g();dt.disable("x-powered-by"),dt.use(m());const mt=f.memoryStorage(),gt=f({storage:mt,limits:{fieldSize:52428800}});dt.use(g.json({limit:52428800})),dt.use(g.urlencoded({extended:!0,limit:52428800})),dt.use(gt.none());const ft=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}`)}))}))},vt=async r=>{try{if(!r.enable)return!1;if(!r.ssl.force){const e=a.createServer(dt);ft(e),e.listen(r.port,r.host,(()=>{ht.set(r.port,e),U(3,`[server] Started HTTP server on ${r.host}:${r.port}.`),1===ht.size&&Je({...e.address(),protocol:"http"})}))}if(r.ssl.enable){let o,i;try{o=await e.promises.readFile(t.posix.join(r.ssl.certPath,"server.key"),"utf8"),i=await e.promises.readFile(t.posix.join(r.ssl.certPath,"server.crt"),"utf8")}catch(e){U(2,`[server] Unable to load key/certificate from the '${r.ssl.certPath}' path. Could not run secured layer server.`)}if(o&&i){const e=c.createServer({key:o,cert:i},dt);ft(e),e.listen(r.ssl.port,r.host,(()=>{ht.set(r.ssl.port,e),U(3,`[server] Started HTTPS server on ${r.host}:${r.ssl.port}.`),1===ht.size&&Je({...e.address(),protocol:"https"})}))}}r.rateLimiting&&r.rateLimiting.enable&&![0,NaN].includes(r.rateLimiting.maxRequests)&&Ge(dt,r.rateLimiting),dt.use(g.static(t.posix.join(G,"public"))),ut(dt),(e=>{e.post("/",at),e.post("/:filename",at)})(dt),(e=>{!!e&&e.get("/",((e,r)=>{r.sendFile(t.join(G,"public","index.html"))}))})(dt),tt(dt),(e=>{e.use(We),e.use(De)})(dt)}catch(e){throw new ie("[server] Could not configure and start the server.").setError(e)}},yt=()=>{U(4,"[server] Closing all servers.");for(const[e,t]of ht)t.close((()=>{ht.delete(e),U(4,`[server] Closed server on port: ${e}.`)}))};var bt={startServer:vt,closeServers:yt,getServers:()=>ht,enableRateLimiting:e=>Ge(dt,e),getExpress:()=>g,getApp:()=>dt,use:(e,...t)=>{dt.use(e,...t)},get:(e,...t)=>{dt.get(e,...t)},post:(e,...t)=>{dt.post(e,...t)}};const wt=async e=>{await Promise.allSettled([je(),Qe(),yt(),ke()]),process.exit(e)};var Et={server:bt,startServer:vt,initExport:async e=>{var t;return t=e.customLogic&&e.customLogic.allowCodeExecution,Ie=z(t),(e=>{W(e&&parseInt(e.level)),e&&e.dest&&D(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 wt(0)})),process.on("SIGTERM",(async(e,t)=>{U(4,`The ${e} event with code: ${t}.`),await wt(0)})),process.on("SIGHUP",(async(e,t)=>{U(4,`The ${e} event with code: ${t}.`),await wt(0)})),process.on("uncaughtException",(async(e,t)=>{j(1,e,`The ${t} error.`),await wt(1)}))),await le(e),await Re({pool:e.pool||{minWorkers:1,maxWorkers:1},puppeteerArgs:e.puppeteer.args||[]}),e},singleExport:async t=>{t.export.instr=t.export.instr||t.export.options,await Ce(t,(async(t,r)=>{if(t)throw t;const{outfile:o,type:i}=r.options.export;e.writeFileSync(o||`chart.${i}`,"svg"!==i?Buffer.from(r.result,"base64"):r.result),await ke()}))},batchExport:async t=>{const r=[];for(let o of t.export.batch.split(";"))o=o.split("="),2===o.length&&r.push(Ce({...t,export:{...t.export,infile:o[0],outfile:o[1]}},((t,r)=>{if(t)throw t;e.writeFileSync(r.options.export.outfile,"svg"!==r.options.export.type?Buffer.from(r.result,"base64"):r.result)})));try{await Promise.all(r),await ke()}catch(e){throw new ie("[chart] Error encountered during batch export.").setError(e)}},startExport:Ce,initPool:Re,killPool:ke,setOptions:(t,r)=>(r?.length&&(Y=function(t){const r=t.findIndex((e=>"loadConfig"===e.replace(/-/g,"")));if(r>-1&&t[r+1]){const o=t[r+1];try{if(o&&o.endsWith(".json"))return JSON.parse(e.readFileSync(o))}catch(e){j(2,e,`[config] Unable to load the configuration from the ${o} file.`)}}return{}}(r)),ee(T,Y),Y=te(T),t&&(Y=Q(Y,t,_)),r?.length&&(Y=function(e,t,r){let o=!1;for(let i=0;i(s.length-1===r&&(a=e[t].type),e[t])),r),s.reduce(((e,r,c)=>(s.length-1===c&&void 0!==e[r]&&(t[++i]?"boolean"===a?e[r]=z(t[i]):"number"===a?e[r]=+t[i]:a.indexOf("]")>=0?e[r]=t[i].split(","):e[r]=t[i]:(U(2,`[config] Missing value for the '${n}' argument. Using the default value.`),o=!0)),e[r])),e)}o&&K();return e}(Y,r,T)),Y),shutdownCleanUp:wt,log:U,logWithStack:j,setLogLevel:W,enableFileLogging:D,mapToNewConfig:e=>{const t={};for(const[r,o]of Object.entries(e)){const e=R[r]?R[r].split("."):[];e.reduce(((t,r,i)=>t[r]=e.length-1===i?o:t[r]||{}),t)}return t},manualConfig:async t=>{let r={};e.existsSync(t)&&(r=JSON.parse(e.readFileSync(t,"utf8")));const i=Object.keys(S).map((e=>({title:`${e} options`,value:e})));return o({type:"multiselect",name:"category",message:"Which category do you want to configure?",hint:"Space: Select specific, A: Select all, Enter: Confirm.",instructions:"",choices:i},{onSubmit:async(i,n)=>{let s=0,a=[];for(const e of n)S[e]=S[e].map((t=>({...t,section:e}))),a=[...a,...S[e]];return await o(a,{onSubmit:async(o,i)=>{if("moduleScripts"===o.name?(i=i.length?i.map((e=>o.choices[e])):o.choices,r[o.section][o.name]=i):r[o.section]=re(Object.assign({},r[o.section]||{}),o.name.split("."),o.choices?o.choices[i]:i),++s===a.length){try{await e.promises.writeFile(t,JSON.stringify(r,null,2),"utf8")}catch(e){j(1,e,`[config] An error occurred while creating the ${t} file.`)}return!0}}}),!0}})},printLogo:r=>{const o=JSON.parse(e.readFileSync(t.join(G,"package.json"))).version;r?console.log(`Starting Highcharts Export Server v${o}...`):console.log(e.readFileSync(G+"/msg/startup.msg").toString().bold.yellow,`v${o}\n`.bold)},printUsage:K};module.exports=Et; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguY2pzIiwic291cmNlcyI6WyIuLi9saWIvc2NoZW1hcy9jb25maWcuanMiLCIuLi9saWIvZW52cy5qcyIsIi4uL2xpYi9sb2dnZXIuanMiLCIuLi9saWIvdXRpbHMuanMiLCIuLi9saWIvY29uZmlnLmpzIiwiLi4vbGliL2ZldGNoLmpzIiwiLi4vbGliL2Vycm9ycy9FeHBvcnRFcnJvci5qcyIsIi4uL2xpYi9jYWNoZS5qcyIsIi4uL2xpYi9oaWdoY2hhcnRzLmpzIiwiLi4vbGliL2Jyb3dzZXIuanMiLCIuLi9saWIvZXhwb3J0LmpzIiwiLi4vdGVtcGxhdGVzL3N2Z19leHBvcnQvc3ZnX2V4cG9ydC5qcyIsIi4uL2xpYi9wb29sLmpzIiwiLi4vbGliL2NoYXJ0LmpzIiwiLi4vbGliL3Nhbml0aXplLmpzIiwiLi4vbGliL3RpbWVycy5qcyIsIi4uL2xpYi9zZXJ2ZXIvZXJyb3IuanMiLCIuLi9saWIvc2VydmVyL3JhdGVfbGltaXQuanMiLCIuLi9saWIvdGVsZW1ldHJ5LmpzIiwiLi4vbGliL3NlcnZlci93ZWJfc29ja2V0LmpzIiwiLi4vbGliL2Vycm9ycy9IdHRwRXJyb3IuanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy9jaGFuZ2VfaGNfdmVyc2lvbi5qcyIsIi4uL2xpYi9zZXJ2ZXIvcm91dGVzL2V4cG9ydC5qcyIsIi4uL2xpYi9zZXJ2ZXIvcm91dGVzL2hlYWx0aC5qcyIsIi4uL2xpYi9zZXJ2ZXIvc2VydmVyLmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvdWkuanMiLCIuLi9saWIvcmVzb3VyY2VfcmVsZWFzZS5qcyIsIi4uL2xpYi9pbmRleC5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8vIFBvc3NpYmxlIG5hbWVzIGZvciBIaWdoY2hhcnRzIHNjcmlwdHNcclxuZXhwb3J0IGNvbnN0IHNjcmlwdHNOYW1lcyA9IHtcclxuICBjb3JlOiBbJ2hpZ2hjaGFydHMnLCAnaGlnaGNoYXJ0cy1tb3JlJywgJ2hpZ2hjaGFydHMtM2QnXSxcclxuICBtb2R1bGVzOiBbXHJcbiAgICAnc3RvY2snLFxyXG4gICAgJ21hcCcsXHJcbiAgICAnZ2FudHQnLFxyXG4gICAgJ2V4cG9ydGluZycsXHJcbiAgICAncGFyYWxsZWwtY29vcmRpbmF0ZXMnLFxyXG4gICAgJ2FjY2Vzc2liaWxpdHknLFxyXG4gICAgLy8gJ2Fubm90YXRpb25zLWFkdmFuY2VkJyxcclxuICAgICdib29zdC1jYW52YXMnLFxyXG4gICAgJ2Jvb3N0JyxcclxuICAgICdkYXRhJyxcclxuICAgICdkYXRhLXRvb2xzJyxcclxuICAgICdkcmFnZ2FibGUtcG9pbnRzJyxcclxuICAgICdzdGF0aWMtc2NhbGUnLFxyXG4gICAgJ2Jyb2tlbi1heGlzJyxcclxuICAgICdoZWF0bWFwJyxcclxuICAgICd0aWxlbWFwJyxcclxuICAgICd0aWxlZHdlYm1hcCcsXHJcbiAgICAndGltZWxpbmUnLFxyXG4gICAgJ3RyZWVtYXAnLFxyXG4gICAgJ3RyZWVncmFwaCcsXHJcbiAgICAnaXRlbS1zZXJpZXMnLFxyXG4gICAgJ2RyaWxsZG93bicsXHJcbiAgICAnaGlzdG9ncmFtLWJlbGxjdXJ2ZScsXHJcbiAgICAnYnVsbGV0JyxcclxuICAgICdmdW5uZWwnLFxyXG4gICAgJ2Z1bm5lbDNkJyxcclxuICAgICdnZW9oZWF0bWFwJyxcclxuICAgICdweXJhbWlkM2QnLFxyXG4gICAgJ25ldHdvcmtncmFwaCcsXHJcbiAgICAnb3ZlcmxhcHBpbmctZGF0YWxhYmVscycsXHJcbiAgICAncGFyZXRvJyxcclxuICAgICdwYXR0ZXJuLWZpbGwnLFxyXG4gICAgJ3BpY3RvcmlhbCcsXHJcbiAgICAncHJpY2UtaW5kaWNhdG9yJyxcclxuICAgICdzYW5rZXknLFxyXG4gICAgJ2FyYy1kaWFncmFtJyxcclxuICAgICdkZXBlbmRlbmN5LXdoZWVsJyxcclxuICAgICdzZXJpZXMtbGFiZWwnLFxyXG4gICAgJ3Nlcmllcy1vbi1wb2ludCcsXHJcbiAgICAnc29saWQtZ2F1Z2UnLFxyXG4gICAgJ3NvbmlmaWNhdGlvbicsXHJcbiAgICAvLyAnc3RvY2stdG9vbHMnLFxyXG4gICAgJ3N0cmVhbWdyYXBoJyxcclxuICAgICdzdW5idXJzdCcsXHJcbiAgICAndmFyaWFibGUtcGllJyxcclxuICAgICd2YXJpd2lkZScsXHJcbiAgICAndmVjdG9yJyxcclxuICAgICd2ZW5uJyxcclxuICAgICd3aW5kYmFyYicsXHJcbiAgICAnd29yZGNsb3VkJyxcclxuICAgICd4cmFuZ2UnLFxyXG4gICAgJ25vLWRhdGEtdG8tZGlzcGxheScsXHJcbiAgICAnZHJhZy1wYW5lcycsXHJcbiAgICAnZGVidWdnZXInLFxyXG4gICAgJ2R1bWJiZWxsJyxcclxuICAgICdsb2xsaXBvcCcsXHJcbiAgICAnY3lsaW5kZXInLFxyXG4gICAgJ29yZ2FuaXphdGlvbicsXHJcbiAgICAnZG90cGxvdCcsXHJcbiAgICAnbWFya2VyLWNsdXN0ZXJzJyxcclxuICAgICdob2xsb3djYW5kbGVzdGljaycsXHJcbiAgICAnaGVpa2luYXNoaScsXHJcbiAgICAnZmxvd21hcCcsXHJcbiAgICAnZXhwb3J0LWRhdGEnLFxyXG4gICAgJ25hdmlnYXRvcicsXHJcbiAgICAndGV4dHBhdGgnXHJcbiAgXSxcclxuICBpbmRpY2F0b3JzOiBbJ2luZGljYXRvcnMtYWxsJ11cclxufTtcclxuXHJcbi8vIFRoaXMgaXMgdGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IHdpdGggYWxsIG9wdGlvbnMgYW5kIHRoZWlyIGRlZmF1bHQgdmFsdWVzLFxyXG4vLyBhbHNvIGZyb20gdGhlIC5lbnYgZmlsZSBpZiBvbmUgZXhpc3RzXHJcbmV4cG9ydCBjb25zdCBkZWZhdWx0Q29uZmlnID0ge1xyXG4gIHB1cHBldGVlcjoge1xyXG4gICAgYXJnczoge1xyXG4gICAgICB2YWx1ZTogW1xyXG4gICAgICAgICctLWFsbG93LXJ1bm5pbmctaW5zZWN1cmUtY29udGVudCcsXHJcbiAgICAgICAgJy0tYXNoLW5vLW51ZGdlcycsXHJcbiAgICAgICAgJy0tYXV0b3BsYXktcG9saWN5PXVzZXItZ2VzdHVyZS1yZXF1aXJlZCcsXHJcbiAgICAgICAgJy0tYmxvY2stbmV3LXdlYi1jb250ZW50cycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1hY2NlbGVyYXRlZC0yZC1jYW52YXMnLFxyXG4gICAgICAgICctLWRpc2FibGUtYmFja2dyb3VuZC1uZXR3b3JraW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWJhY2tncm91bmQtdGltZXItdGhyb3R0bGluZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1iYWNrZ3JvdW5kaW5nLW9jY2x1ZGVkLXdpbmRvd3MnLFxyXG4gICAgICAgICctLWRpc2FibGUtYnJlYWtwYWQnLFxyXG4gICAgICAgICctLWRpc2FibGUtY2hlY2tlci1pbWFnaW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWNsaWVudC1zaWRlLXBoaXNoaW5nLWRldGVjdGlvbicsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1jb21wb25lbnQtZXh0ZW5zaW9ucy13aXRoLWJhY2tncm91bmQtcGFnZXMnLFxyXG4gICAgICAgICctLWRpc2FibGUtY29tcG9uZW50LXVwZGF0ZScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1kZWZhdWx0LWFwcHMnLFxyXG4gICAgICAgICctLWRpc2FibGUtZGV2LXNobS11c2FnZScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1kb21haW4tcmVsaWFiaWxpdHknLFxyXG4gICAgICAgICctLWRpc2FibGUtZXh0ZW5zaW9ucycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1mZWF0dXJlcz1DYWxjdWxhdGVOYXRpdmVXaW5PY2NsdXNpb24sSW50ZXJlc3RGZWVkQ29udGVudFN1Z2dlc3Rpb25zLFdlYk9UUCcsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1oYW5nLW1vbml0b3InLFxyXG4gICAgICAgICctLWRpc2FibGUtaXBjLWZsb29kaW5nLXByb3RlY3Rpb24nLFxyXG4gICAgICAgICctLWRpc2FibGUtbG9nZ2luZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1ub3RpZmljYXRpb25zJyxcclxuICAgICAgICAnLS1kaXNhYmxlLW9mZmVyLXN0b3JlLXVubWFza2VkLXdhbGxldC1jYXJkcycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1wb3B1cC1ibG9ja2luZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1wcmludC1wcmV2aWV3JyxcclxuICAgICAgICAnLS1kaXNhYmxlLXByb21wdC1vbi1yZXBvc3QnLFxyXG4gICAgICAgICctLWRpc2FibGUtcmVuZGVyZXItYmFja2dyb3VuZGluZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zZWFyY2gtZW5naW5lLWNob2ljZS1zY3JlZW4nLFxyXG4gICAgICAgICctLWRpc2FibGUtc2Vzc2lvbi1jcmFzaGVkLWJ1YmJsZScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zZXR1aWQtc2FuZGJveCcsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zaXRlLWlzb2xhdGlvbi10cmlhbHMnLFxyXG4gICAgICAgICctLWRpc2FibGUtc3BlZWNoLWFwaScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zeW5jJyxcclxuICAgICAgICAnLS1lbmFibGUtdW5zYWZlLXdlYmdwdScsXHJcbiAgICAgICAgJy0taGlkZS1jcmFzaC1yZXN0b3JlLWJ1YmJsZScsXHJcbiAgICAgICAgJy0taGlkZS1zY3JvbGxiYXJzJyxcclxuICAgICAgICAnLS1tZXRyaWNzLXJlY29yZGluZy1vbmx5JyxcclxuICAgICAgICAnLS1tdXRlLWF1ZGlvJyxcclxuICAgICAgICAnLS1uby1kZWZhdWx0LWJyb3dzZXItY2hlY2snLFxyXG4gICAgICAgICctLW5vLWZpcnN0LXJ1bicsXHJcbiAgICAgICAgJy0tbm8tcGluZ3MnLFxyXG4gICAgICAgICctLW5vLXNhbmRib3gnLFxyXG4gICAgICAgICctLW5vLXN0YXJ0dXAtd2luZG93JyxcclxuICAgICAgICAnLS1uby16eWdvdGUnLFxyXG4gICAgICAgICctLXBhc3N3b3JkLXN0b3JlPWJhc2ljJyxcclxuICAgICAgICAnLS1wcm9jZXNzLXBlci10YWInLFxyXG4gICAgICAgICctLXVzZS1tb2NrLWtleWNoYWluJ1xyXG4gICAgICBdLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0FyZ3VtZW50cyBhcnJheSB0byBzZW5kIHRvIFB1cHBldGVlci4nXHJcbiAgICB9XHJcbiAgfSxcclxuICBoaWdoY2hhcnRzOiB7XHJcbiAgICB2ZXJzaW9uOiB7XHJcbiAgICAgIHZhbHVlOiAnbGF0ZXN0JyxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX1ZFUlNJT04nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBIaWdoY2hhcnRzIHZlcnNpb24gdG8gYmUgdXNlZC4nXHJcbiAgICB9LFxyXG4gICAgY2RuVVJMOiB7XHJcbiAgICAgIHZhbHVlOiAnaHR0cHM6Ly9jb2RlLmhpZ2hjaGFydHMuY29tLycsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DRE5fVVJMJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgQ0ROIFVSTCBmb3IgSGlnaGNoYXJ0cyBzY3JpcHRzIHRvIGJlIHVzZWQuJ1xyXG4gICAgfSxcclxuICAgIGNvcmVTY3JpcHRzOiB7XHJcbiAgICAgIHZhbHVlOiBzY3JpcHRzTmFtZXMuY29yZSxcclxuICAgICAgdHlwZTogJ3N0cmluZ1tdJyxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ09SRV9TQ1JJUFRTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgY29yZSBIaWdoY2hhcnRzIHNjcmlwdHMgdG8gZmV0Y2guJ1xyXG4gICAgfSxcclxuICAgIG1vZHVsZVNjcmlwdHM6IHtcclxuICAgICAgdmFsdWU6IHNjcmlwdHNOYW1lcy5tb2R1bGVzLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19NT0RVTEVfU0NSSVBUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIG1vZHVsZXMgb2YgSGlnaGNoYXJ0cyB0byBmZXRjaC4nXHJcbiAgICB9LFxyXG4gICAgaW5kaWNhdG9yU2NyaXB0czoge1xyXG4gICAgICB2YWx1ZTogc2NyaXB0c05hbWVzLmluZGljYXRvcnMsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmdbXScsXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0lORElDQVRPUl9TQ1JJUFRTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgaW5kaWNhdG9ycyBvZiBIaWdoY2hhcnRzIHRvIGZldGNoLidcclxuICAgIH0sXHJcbiAgICBjdXN0b21TY3JpcHRzOiB7XHJcbiAgICAgIHZhbHVlOiBbXHJcbiAgICAgICAgJ2h0dHBzOi8vY2RuanMuY2xvdWRmbGFyZS5jb20vYWpheC9saWJzL21vbWVudC5qcy8yLjI5LjQvbW9tZW50Lm1pbi5qcycsXHJcbiAgICAgICAgJ2h0dHBzOi8vY2RuanMuY2xvdWRmbGFyZS5jb20vYWpheC9saWJzL21vbWVudC10aW1lem9uZS8wLjUuMzQvbW9tZW50LXRpbWV6b25lLXdpdGgtZGF0YS5taW4uanMnXHJcbiAgICAgIF0sXHJcbiAgICAgIHR5cGU6ICdzdHJpbmdbXScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnQWRkaXRpb25hbCBjdXN0b20gc2NyaXB0cyBvciBkZXBlbmRlbmNpZXMgdG8gZmV0Y2guJ1xyXG4gICAgfSxcclxuICAgIGZvcmNlRmV0Y2g6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0ZPUkNFX0ZFVENIJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBmbGFnIHRvIGRldGVybWluZSB3aGV0aGVyIHRvIHJlZmV0Y2ggYWxsIHNjcmlwdHMgYWZ0ZXIgZWFjaCBzZXJ2ZXIgcmVydW4uJ1xyXG4gICAgfSxcclxuICAgIGNhY2hlUGF0aDoge1xyXG4gICAgICB2YWx1ZTogJy5jYWNoZScsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DQUNIRV9QQVRIJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBwYXRoIHRvIHRoZSBjYWNoZSBkaXJlY3RvcnkuIEl0IGlzIHVzZWQgdG8gc3RvcmUgdGhlIEhpZ2hjaGFydHMgc2NyaXB0cyBhbmQgY3VzdG9tIHNjcmlwdHMuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgZXhwb3J0OiB7XHJcbiAgICBpbmZpbGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBpbnB1dCBmaWxlIHNob3VsZCBpbmNsdWRlIGEgbmFtZSBhbmQgYSB0eXBlIChqc29uIG9yIHN2ZykuIEl0IG11c3QgYmUgY29ycmVjdGx5IGZvcm1hdHRlZCBhcyBhIEpTT04gb3IgU1ZHIGZpbGUuJ1xyXG4gICAgfSxcclxuICAgIGluc3RyOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbnB1dCwgcHJvdmlkZWQgaW4gdGhlIGZvcm0gb2YgYSBzdHJpbmdpZmllZCBKU09OIG9yIFNWRyBmaWxlLCB3aWxsIG92ZXJyaWRlIHRoZSAtLWluZmlsZSBvcHRpb24uJ1xyXG4gICAgfSxcclxuICAgIG9wdGlvbnM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdBbiBhbGlhcyBmb3IgdGhlIC0taW5zdHIgb3B0aW9uLidcclxuICAgIH0sXHJcbiAgICBvdXRmaWxlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgb3V0cHV0IGZpbGVuYW1lIGFsb25nIHdpdGggYSB0eXBlIChqcGVnLCBwbmcsIHBkZiwgb3Igc3ZnKS4gVGhpcyB3aWxsIGlnbm9yZSB0aGUgLS10eXBlIGZsYWcuJ1xyXG4gICAgfSxcclxuICAgIHR5cGU6IHtcclxuICAgICAgdmFsdWU6ICdwbmcnLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9UWVBFJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgZmlsZSBleHBvcnQgZm9ybWF0LiBJdCBjYW4gYmUganBlZywgcG5nLCBwZGYsIG9yIHN2Zy4nXHJcbiAgICB9LFxyXG4gICAgY29uc3RyOiB7XHJcbiAgICAgIHZhbHVlOiAnY2hhcnQnLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9DT05TVFInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGNvbnN0cnVjdG9yIHRvIHVzZS4gQ2FuIGJlIGNoYXJ0LCBzdG9ja0NoYXJ0LCBtYXBDaGFydCwgb3IgZ2FudHRDaGFydC4nXHJcbiAgICB9LFxyXG4gICAgZGVmYXVsdEhlaWdodDoge1xyXG4gICAgICB2YWx1ZTogNDAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9ERUZBVUxUX0hFSUdIVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICd0aGUgZGVmYXVsdCBoZWlnaHQgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LiBVc2VkIHdoZW4gbm8gdmFsdWUgaXMgc2V0LidcclxuICAgIH0sXHJcbiAgICBkZWZhdWx0V2lkdGg6IHtcclxuICAgICAgdmFsdWU6IDYwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9XSURUSCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZGVmYXVsdCB3aWR0aCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQuIFVzZWQgd2hlbiBubyB2YWx1ZSBpcyBzZXQuJ1xyXG4gICAgfSxcclxuICAgIGRlZmF1bHRTY2FsZToge1xyXG4gICAgICB2YWx1ZTogMSxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9TQ0FMRScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZGVmYXVsdCBzY2FsZSBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQuIFVzZWQgd2hlbiBubyB2YWx1ZSBpcyBzZXQuJ1xyXG4gICAgfSxcclxuICAgIGhlaWdodDoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGhlaWdodCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQsIG92ZXJyaWRpbmcgdGhlIG9wdGlvbiBpbiB0aGUgY2hhcnQgc2V0dGluZ3MuJ1xyXG4gICAgfSxcclxuICAgIHdpZHRoOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgd2lkdGggb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LCBvdmVycmlkaW5nIHRoZSBvcHRpb24gaW4gdGhlIGNoYXJ0IHNldHRpbmdzLidcclxuICAgIH0sXHJcbiAgICBzY2FsZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIHNjYWxlIG9mIHRoZSBleHBvcnRlZCBjaGFydCwgb3ZlcnJpZGluZyB0aGUgb3B0aW9uIGluIHRoZSBjaGFydCBzZXR0aW5ncy4gUmFuZ2VzIGJldHdlZW4gMC4xIGFuZCA1LjAuJ1xyXG4gICAgfSxcclxuICAgIGdsb2JhbE9wdGlvbnM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0VpdGhlciBhIHN0cmluZ2lmaWVkIEpTT04gb3IgYSBmaWxlbmFtZSBjb250YWluaW5nIG9wdGlvbnMgdG8gYmUgcGFzc2VkIGludG8gdGhlIEhpZ2hjaGFydHMuc2V0T3B0aW9ucy4nXHJcbiAgICB9LFxyXG4gICAgdGhlbWVPcHRpb25zOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdFaXRoZXIgYSBzdHJpbmdpZmllZCBKU09OIG9yIGEgZmlsZW5hbWUgY29udGFpbmluZyB0aGVtZSBvcHRpb25zIHRvIGJlIHBhc3NlZCBpbnRvIHRoZSBIaWdoY2hhcnRzLnNldE9wdGlvbnMuJ1xyXG4gICAgfSxcclxuICAgIGJhdGNoOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbml0aWF0ZXMgYSBiYXRjaCBqb2Igd2l0aCBhIHN0cmluZyBjb250YWluaW5nIGlucHV0L291dHB1dCBwYWlyczogXCJpbj1vdXQ7aW49b3V0Oy4uLlwiLidcclxuICAgIH0sXHJcbiAgICByYXN0ZXJpemF0aW9uVGltZW91dDoge1xyXG4gICAgICB2YWx1ZTogMTUwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfUkFTVEVSSVpBVElPTl9USU1FT1VUJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiBpbiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgcmVuZGVyaW5nIGEgd2VicGFnZS4nXHJcbiAgICB9XHJcbiAgfSxcclxuICBjdXN0b21Mb2dpYzoge1xyXG4gICAgYWxsb3dDb2RlRXhlY3V0aW9uOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnQ1VTVE9NX0xPR0lDX0FMTE9XX0NPREVfRVhFQ1VUSU9OJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0NvbnRyb2xzIHdoZXRoZXIgdGhlIGV4ZWN1dGlvbiBvZiBhcmJpdHJhcnkgY29kZSBpcyBhbGxvd2VkIGR1cmluZyB0aGUgZXhwb3J0aW5nIHByb2Nlc3MuJ1xyXG4gICAgfSxcclxuICAgIGFsbG93RmlsZVJlc291cmNlczoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19BTExPV19GSUxFX1JFU09VUkNFUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdDb250cm9scyB0aGUgYWJpbGl0eSB0byBpbmplY3QgcmVzb3VyY2VzIGZyb20gdGhlIGZpbGVzeXN0ZW0uIFRoaXMgc2V0dGluZyBoYXMgbm8gZWZmZWN0IHdoZW4gcnVubmluZyBhcyBhIHNlcnZlci4nXHJcbiAgICB9LFxyXG4gICAgY3VzdG9tQ29kZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQ3VzdG9tIGNvZGUgdG8gZXhlY3V0ZSBiZWZvcmUgY2hhcnQgaW5pdGlhbGl6YXRpb24uIEl0IGNhbiBiZSBhIGZ1bmN0aW9uLCBjb2RlIHdyYXBwZWQgd2l0aGluIGEgZnVuY3Rpb24sIG9yIGEgZmlsZW5hbWUgd2l0aCB0aGUgLmpzIGV4dGVuc2lvbi4nXHJcbiAgICB9LFxyXG4gICAgY2FsbGJhY2s6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0phdmFTY3JpcHQgY29kZSB0byBydW4gZHVyaW5nIGNvbnN0cnVjdGlvbi4gSXQgY2FuIGJlIGEgZnVuY3Rpb24gb3IgYSBmaWxlbmFtZSB3aXRoIHRoZSAuanMgZXh0ZW5zaW9uLidcclxuICAgIH0sXHJcbiAgICByZXNvdXJjZXM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0FkZGl0aW9uYWwgcmVzb3VyY2UgaW4gdGhlIGZvcm0gb2YgYSBzdHJpbmdpZmllZCBKU09OLCB3aGljaCBtYXkgY29udGFpbiBmaWxlcywganMsIGFuZCBjc3Mgc2VjdGlvbnMuJ1xyXG4gICAgfSxcclxuICAgIGxvYWRDb25maWc6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgbGVnYWN5TmFtZTogJ2Zyb21GaWxlJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdBIGZpbGUgY29udGFpbmluZyBhIHByZS1kZWZpbmVkIGNvbmZpZ3VyYXRpb24gdG8gdXNlLidcclxuICAgIH0sXHJcbiAgICBjcmVhdGVDb25maWc6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0VuYWJsZXMgc2V0dGluZyBvcHRpb25zIHRocm91Z2ggYSBwcm9tcHQgYW5kIHNhdmluZyB0aGVtIGluIGEgcHJvdmlkZWQgY29uZmlnIGZpbGUuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgc2VydmVyOiB7XHJcbiAgICBlbmFibGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfRU5BQkxFJyxcclxuICAgICAgY2xpTmFtZTogJ2VuYWJsZVNlcnZlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdXaGVuIHNldCB0byB0cnVlLCB0aGUgc2VydmVyIHN0YXJ0cyBvbiB0aGUgbG9jYWwgSVAgYWRkcmVzcyAwLjAuMC4wLidcclxuICAgIH0sXHJcbiAgICBob3N0OiB7XHJcbiAgICAgIHZhbHVlOiAnMC4wLjAuMCcsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX0hPU1QnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGhvc3RuYW1lIG9mIHRoZSBzZXJ2ZXIuIEFkZGl0aW9uYWxseSwgaXQgc3RhcnRzIGEgc2VydmVyIG9uIHRoZSBwcm92aWRlZCBob3N0bmFtZS4nXHJcbiAgICB9LFxyXG4gICAgcG9ydDoge1xyXG4gICAgICB2YWx1ZTogNzgwMSxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfUE9SVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHNlcnZlciBwb3J0IHdoZW4gZW5hYmxlZC4nXHJcbiAgICB9LFxyXG4gICAgYmVuY2htYXJraW5nOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX0JFTkNITUFSS0lORycsXHJcbiAgICAgIGNsaU5hbWU6ICdzZXJ2ZXJCZW5jaG1hcmtpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSW5kaWNhdGVzIHdoZXRoZXIgdG8gZGlzcGxheSB0aGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgb2Ygc3BlY2lmaWMgYWN0aW9ucyB0aGF0IG9jY3VyIG9uIHRoZSBzZXJ2ZXIgd2hpbGUgc2VydmluZyBhIHJlcXVlc3QuJ1xyXG4gICAgfSxcclxuICAgIHByb3h5OiB7XHJcbiAgICAgIGhvc3Q6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9IT1NUJyxcclxuICAgICAgICBjbGlOYW1lOiAncHJveHlIb3N0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSBob3N0IG9mIHRoZSBwcm94eSBzZXJ2ZXIgdG8gdXNlLCBpZiBpdCBleGlzdHMuJ1xyXG4gICAgICB9LFxyXG4gICAgICBwb3J0OiB7XHJcbiAgICAgICAgdmFsdWU6IDgwODAsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9QT1JUJyxcclxuICAgICAgICBjbGlOYW1lOiAncHJveHlQb3J0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSBwb3J0IG9mIHRoZSBwcm94eSBzZXJ2ZXIgdG8gdXNlLCBpZiBpdCBleGlzdHMuJ1xyXG4gICAgICB9LFxyXG4gICAgICB0aW1lb3V0OiB7XHJcbiAgICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9USU1FT1VUJyxcclxuICAgICAgICBjbGlOYW1lOiAncHJveHlUaW1lb3V0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSB0aW1lb3V0IGZvciB0aGUgcHJveHkgc2VydmVyIHRvIHVzZSwgaWYgaXQgZXhpc3RzLidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHJhdGVMaW1pdGluZzoge1xyXG4gICAgICBlbmFibGU6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19FTkFCTEUnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdlbmFibGVSYXRlTGltaXRpbmcnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyByYXRlIGxpbWl0aW5nIGZvciB0aGUgc2VydmVyLidcclxuICAgICAgfSxcclxuICAgICAgbWF4UmVxdWVzdHM6IHtcclxuICAgICAgICB2YWx1ZTogMTAsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX01BWF9SRVFVRVNUUycsXHJcbiAgICAgICAgbGVnYWN5TmFtZTogJ3JhdGVMaW1pdCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgbWF4aW11bSBudW1iZXIgb2YgcmVxdWVzdHMgYWxsb3dlZCBpbiBvbmUgbWludXRlLidcclxuICAgICAgfSxcclxuICAgICAgd2luZG93OiB7XHJcbiAgICAgICAgdmFsdWU6IDEsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1dJTkRPVycsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgdGltZSB3aW5kb3csIGluIG1pbnV0ZXMsIGZvciB0aGUgcmF0ZSBsaW1pdGluZy4nXHJcbiAgICAgIH0sXHJcbiAgICAgIGRlbGF5OiB7XHJcbiAgICAgICAgdmFsdWU6IDAsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX0RFTEFZJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAgICdUaGUgZGVsYXkgZHVyYXRpb24gZm9yIGVhY2ggc3VjY2Vzc2l2ZSByZXF1ZXN0IGJlZm9yZSByZWFjaGluZyB0aGUgbWF4aW11bSBsaW1pdC4nXHJcbiAgICAgIH0sXHJcbiAgICAgIHRydXN0UHJveHk6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19UUlVTVF9QUk9YWScsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdTZXQgdGhpcyB0byB0cnVlIGlmIHRoZSBzZXJ2ZXIgaXMgYmVoaW5kIGEgbG9hZCBiYWxhbmNlci4nXHJcbiAgICAgIH0sXHJcbiAgICAgIHNraXBLZXk6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfS0VZJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAgICdBbGxvd3MgYnlwYXNzaW5nIHRoZSByYXRlIGxpbWl0ZXIgYW5kIHNob3VsZCBiZSBwcm92aWRlZCB3aXRoIHRoZSBza2lwVG9rZW4gYXJndW1lbnQuJ1xyXG4gICAgICB9LFxyXG4gICAgICBza2lwVG9rZW46IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfVE9LRU4nLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICAgJ0FsbG93cyBieXBhc3NpbmcgdGhlIHJhdGUgbGltaXRlciBhbmQgc2hvdWxkIGJlIHByb3ZpZGVkIHdpdGggdGhlIHNraXBLZXkgYXJndW1lbnQuJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgc3NsOiB7XHJcbiAgICAgIGVuYWJsZToge1xyXG4gICAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfRU5BQkxFJyxcclxuICAgICAgICBjbGlOYW1lOiAnZW5hYmxlU3NsJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgb3IgZGlzYWJsZXMgdGhlIFNTTCBwcm90b2NvbC4nXHJcbiAgICAgIH0sXHJcbiAgICAgIGZvcmNlOiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9GT1JDRScsXHJcbiAgICAgICAgY2xpTmFtZTogJ3NzbEZvcmNlJyxcclxuICAgICAgICBsZWdhY3lOYW1lOiAnc3NsT25seScsXHJcbiAgICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgICAnV2hlbiBzZXQgdG8gdHJ1ZSwgdGhlIHNlcnZlciBpcyBmb3JjZWQgdG8gc2VydmUgb25seSBvdmVyIEhUVFBTLidcclxuICAgICAgfSxcclxuICAgICAgcG9ydDoge1xyXG4gICAgICAgIHZhbHVlOiA0NDMsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfUE9SVCcsXHJcbiAgICAgICAgY2xpTmFtZTogJ3NzbFBvcnQnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHBvcnQgb24gd2hpY2ggdG8gcnVuIHRoZSBTU0wgc2VydmVyLidcclxuICAgICAgfSxcclxuICAgICAgY2VydFBhdGg6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfQ0VSVF9QQVRIJyxcclxuICAgICAgICBsZWdhY3lOYW1lOiAnc3NsUGF0aCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgcGF0aCB0byB0aGUgU1NMIGNlcnRpZmljYXRlL2tleSBmaWxlLidcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0sXHJcbiAgcG9vbDoge1xyXG4gICAgbWluV29ya2Vyczoge1xyXG4gICAgICB2YWx1ZTogNCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX01JTl9XT1JLRVJTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgbnVtYmVyIG9mIG1pbmltdW0gYW5kIGluaXRpYWwgcG9vbCB3b3JrZXJzIHRvIHNwYXduLidcclxuICAgIH0sXHJcbiAgICBtYXhXb3JrZXJzOiB7XHJcbiAgICAgIHZhbHVlOiA4LFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfTUFYX1dPUktFUlMnLFxyXG4gICAgICBsZWdhY3lOYW1lOiAnd29ya2VycycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIG51bWJlciBvZiBtYXhpbXVtIHBvb2wgd29ya2VycyB0byBzcGF3bi4nXHJcbiAgICB9LFxyXG4gICAgd29ya0xpbWl0OiB7XHJcbiAgICAgIHZhbHVlOiA0MCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX1dPUktfTElNSVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIG51bWJlciBvZiB3b3JrIHBpZWNlcyB0aGF0IGNhbiBiZSBwZXJmb3JtZWQgYmVmb3JlIHJlc3RhcnRpbmcgdGhlIHdvcmtlciBwcm9jZXNzLidcclxuICAgIH0sXHJcbiAgICBhY3F1aXJlVGltZW91dDoge1xyXG4gICAgICB2YWx1ZTogNTAwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX0FDUVVJUkVfVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgdG8gd2FpdCBmb3IgYWNxdWlyaW5nIGEgcmVzb3VyY2UuJ1xyXG4gICAgfSxcclxuICAgIGNyZWF0ZVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9DUkVBVEVfVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgdG8gd2FpdCBmb3IgY3JlYXRpbmcgYSByZXNvdXJjZS4nXHJcbiAgICB9LFxyXG4gICAgZGVzdHJveVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9ERVNUUk9ZX1RJTUVPVVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGR1cmF0aW9uLCBpbiBtaWxsaXNlY29uZHMsIHRvIHdhaXQgZm9yIGRlc3Ryb3lpbmcgYSByZXNvdXJjZS4nXHJcbiAgICB9LFxyXG4gICAgaWRsZVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDMwMDAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfSURMRV9USU1FT1VUJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCBhZnRlciB3aGljaCBhbiBpZGxlIHJlc291cmNlIGlzIGRlc3Ryb3llZC4nXHJcbiAgICB9LFxyXG4gICAgY3JlYXRlUmV0cnlJbnRlcnZhbDoge1xyXG4gICAgICB2YWx1ZTogMjAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfQ1JFQVRFX1JFVFJZX0lOVEVSVkFMJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCB0byB3YWl0IGJlZm9yZSByZXRyeWluZyB0aGUgY3JlYXRlIHByb2Nlc3MgaW4gY2FzZSBvZiBhIGZhaWx1cmUuJ1xyXG4gICAgfSxcclxuICAgIHJlYXBlckludGVydmFsOiB7XHJcbiAgICAgIHZhbHVlOiAxMDAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfUkVBUEVSX0lOVEVSVkFMJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCBhZnRlciB3aGljaCB0aGUgY2hlY2sgZm9yIGlkbGUgcmVzb3VyY2VzIHRvIGRlc3Ryb3kgaXMgdHJpZ2dlcmVkLidcclxuICAgIH0sXHJcbiAgICBiZW5jaG1hcmtpbmc6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX0JFTkNITUFSS0lORycsXHJcbiAgICAgIGNsaU5hbWU6ICdwb29sQmVuY2htYXJraW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0luZGljYXRlIHdoZXRoZXIgdG8gc2hvdyBzdGF0aXN0aWNzIGZvciB0aGUgcG9vbCBvZiByZXNvdXJjZXMgb3Igbm90LidcclxuICAgIH1cclxuICB9LFxyXG4gIGxvZ2dpbmc6IHtcclxuICAgIGxldmVsOiB7XHJcbiAgICAgIHZhbHVlOiA0LFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ0xPR0dJTkdfTEVWRUwnLFxyXG4gICAgICBjbGlOYW1lOiAnbG9nTGV2ZWwnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBsb2dnaW5nIGxldmVsIHRvIGJlIHVzZWQuJ1xyXG4gICAgfSxcclxuICAgIGZpbGU6IHtcclxuICAgICAgdmFsdWU6ICdoaWdoY2hhcnRzLWV4cG9ydC1zZXJ2ZXIubG9nJyxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX0ZJTEUnLFxyXG4gICAgICBjbGlOYW1lOiAnbG9nRmlsZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgbmFtZSBvZiBhIGxvZyBmaWxlLiBUaGUgbG9nRGVzdCBvcHRpb24gYWxzbyBuZWVkcyB0byBiZSBzZXQgdG8gZW5hYmxlIGZpbGUgbG9nZ2luZy4nXHJcbiAgICB9LFxyXG4gICAgZGVzdDoge1xyXG4gICAgICB2YWx1ZTogJ2xvZy8nLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ0xPR0dJTkdfREVTVCcsXHJcbiAgICAgIGNsaU5hbWU6ICdsb2dEZXN0JyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBwYXRoIHRvIHN0b3JlIGxvZyBmaWxlcy4gVGhpcyBhbHNvIGVuYWJsZXMgZmlsZSBsb2dnaW5nLidcclxuICAgIH1cclxuICB9LFxyXG4gIHVpOiB7XHJcbiAgICBlbmFibGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdVSV9FTkFCTEUnLFxyXG4gICAgICBjbGlOYW1lOiAnZW5hYmxlVWknLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnRW5hYmxlcyBvciBkaXNhYmxlcyB0aGUgdXNlciBpbnRlcmZhY2UgKFVJKSBmb3IgdGhlIGV4cG9ydCBzZXJ2ZXIuJ1xyXG4gICAgfSxcclxuICAgIHJvdXRlOiB7XHJcbiAgICAgIHZhbHVlOiAnLycsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnVUlfUk9VVEUnLFxyXG4gICAgICBjbGlOYW1lOiAndWlSb3V0ZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZW5kcG9pbnQgcm91dGUgdG8gd2hpY2ggdGhlIHVzZXIgaW50ZXJmYWNlIChVSSkgc2hvdWxkIGJlIGF0dGFjaGVkLidcclxuICAgIH1cclxuICB9LFxyXG4gIG90aGVyOiB7XHJcbiAgICBub2RlRW52OiB7XHJcbiAgICAgIHZhbHVlOiAncHJvZHVjdGlvbicsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfTk9ERV9FTlYnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSB0eXBlIG9mIE5vZGUuanMgZW52aXJvbm1lbnQuJ1xyXG4gICAgfSxcclxuICAgIGxpc3RlblRvUHJvY2Vzc0V4aXRzOiB7XHJcbiAgICAgIHZhbHVlOiB0cnVlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9MSVNURU5fVE9fUFJPQ0VTU19FWElUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRGVjaWRlcyB3aGV0aGVyIG9yIG5vdCB0byBhdHRhY2ggcHJvY2Vzcy5leGl0IGhhbmRsZXJzLidcclxuICAgIH0sXHJcbiAgICBub0xvZ286IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9OT19MT0dPJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1NraXAgcHJpbnRpbmcgdGhlIGxvZ28gb24gYSBzdGFydHVwLiBXaWxsIGJlIHJlcGxhY2VkIGJ5IGEgc2ltcGxlIHRleHQuJ1xyXG4gICAgfSxcclxuICAgIGhhcmRSZXNldFBhZ2U6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9IQVJEX1JFU0VUX1BBR0UnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0RlY2lkZXMgaWYgdGhlIHBhZ2UgY29udGVudCBzaG91bGQgYmUgcmVzZXQgZW50aXJlbHkuJ1xyXG4gICAgfSxcclxuICAgIGJyb3dzZXJTaGVsbE1vZGU6IHtcclxuICAgICAgdmFsdWU6IHRydWUsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZW52TGluazogJ09USEVSX0JST1dTRVJfU0hFTExfTU9ERScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRGVjaWRlcyBpZiB0aGUgYnJvd3NlciBydW5zIGluIHRoZSBzaGVsbCBtb2RlLidcclxuICAgIH1cclxuICB9LFxyXG4gIGRlYnVnOiB7XHJcbiAgICBlbmFibGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19FTkFCTEUnLFxyXG4gICAgICBjbGlOYW1lOiAnZW5hYmxlRGVidWcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgb3IgZGlzYWJsZXMgZGVidWcgbW9kZSBmb3IgdGhlIHVuZGVybHlpbmcgYnJvd3Nlci4nXHJcbiAgICB9LFxyXG4gICAgaGVhZGxlc3M6IHtcclxuICAgICAgdmFsdWU6IHRydWUsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZW52TGluazogJ0RFQlVHX0hFQURMRVNTJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0NvbnRyb2xzIHRoZSBtb2RlIGluIHdoaWNoIHRoZSBicm93c2VyIGlzIGxhdW5jaGVkIHdoZW4gaW4gdGhlIGRlYnVnIG1vZGUuJ1xyXG4gICAgfSxcclxuICAgIGRldnRvb2xzOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfREVWVE9PTFMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnRGVjaWRlcyB3aGV0aGVyIHRvIGVuYWJsZSBEZXZUb29scyB3aGVuIHRoZSBicm93c2VyIGlzIGluIGEgaGVhZGZ1bCBzdGF0ZS4nXHJcbiAgICB9LFxyXG4gICAgbGlzdGVuVG9Db25zb2xlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfTElTVEVOX1RPX0NPTlNPTEUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnRGVjaWRlcyB3aGV0aGVyIHRvIGVuYWJsZSBhIGxpc3RlbmVyIGZvciBjb25zb2xlIG1lc3NhZ2VzIHNlbnQgZnJvbSB0aGUgYnJvd3Nlci4nXHJcbiAgICB9LFxyXG4gICAgZHVtcGlvOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfRFVNUElPJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1JlZGlyZWN0cyBicm93c2VyIHByb2Nlc3Mgc3Rkb3V0IGFuZCBzdGRlcnIgdG8gcHJvY2Vzcy5zdGRvdXQgYW5kIHByb2Nlc3Muc3RkZXJyLidcclxuICAgIH0sXHJcbiAgICBzbG93TW86IHtcclxuICAgICAgdmFsdWU6IDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfU0xPV19NTycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdTbG93cyBkb3duIFB1cHBldGVlciBvcGVyYXRpb25zIGJ5IHRoZSBzcGVjaWZpZWQgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcy4nXHJcbiAgICB9LFxyXG4gICAgZGVidWdnaW5nUG9ydDoge1xyXG4gICAgICB2YWx1ZTogOTIyMixcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19ERUJVR0dJTkdfUE9SVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnU3BlY2lmaWVzIHRoZSBkZWJ1Z2dpbmcgcG9ydC4nXHJcbiAgICB9XHJcbiAgfSxcclxuICB3ZWJTb2NrZXQ6IHtcclxuICAgIGVuYWJsZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZW52TGluazogJ1dFQl9TT0NLRVRfRU5BQkxFJyxcclxuICAgICAgY2xpTmFtZTogJ2VuYWJsZVdzJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIG9yIGRpc2FibGVzIHRoZSBXZWJTb2NrZXQgY29ubmVjdGlvbi4nXHJcbiAgICB9LFxyXG4gICAgcmVjb25uZWN0OiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnV0VCX1NPQ0tFVF9SRUNPTk5FQ1QnLFxyXG4gICAgICBjbGlOYW1lOiAnd3NSZWNvbm5lY3QnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQ29udHJvbHMgd2hldGhlciBvciBub3QgdG8gdHJ5IHJlY29ubmVjdGluZyB0byB0aGUgV2ViU29ja2V0IHNlcnZlciBpbiBjYXNlIG9mIGEgZGlzY29ubmVjdC4nXHJcbiAgICB9LFxyXG4gICAgcmVqZWN0VW5hdXRob3JpemVkOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnV0VCX1NPQ0tFVF9SRUpFQ1RfVU5BVVRIT1JJWkVEJyxcclxuICAgICAgY2xpTmFtZTogJ3dzcmVqZWN0VW5hdXRob3JpemVkJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgXCJEZXRlcm1pbmVzIHdoZXRoZXIgdGhlIGNsaWVudCB2ZXJpZmllcyB0aGUgc2VydmVyJ3MgU1NML1RMUyBjZXJ0aWZpY2F0ZSBkdXJpbmcgdGhlIGhhbmRzaGFrZSBwcm9jZXNzLlwiXHJcbiAgICB9LFxyXG4gICAgcGluZ1RpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDE2MDAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1dFQl9TT0NLRVRfUElOR19USU1FT1VUJyxcclxuICAgICAgY2xpTmFtZTogJ3dzUGluZ1RpbWVvdXQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIHRpbWVvdXQsIGluIG1pbGxpc2Vjb25kcywgZm9yIHRoZSBoZWFydGJlYXQgbWVjaGFuaXNtIGJldHdlZW4gdGhlIGNsaWVudCBhbmQgc2VydmVyLidcclxuICAgIH0sXHJcbiAgICByZWNvbm5lY3RJbnRlcnZhbDoge1xyXG4gICAgICB2YWx1ZTogMzAwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdXRUJfU09DS0VUX1JFQ09OTkVDVF9JTlRFUlZBTCcsXHJcbiAgICAgIGNsaU5hbWU6ICd3c1JlY29ubmVjdEludGVydmFsJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgaW50ZXJ2YWwsIGluIG1pbGxpc2Vjb25kcywgZm9yIHRoZSByZWNvbm5lY3QgYXR0ZW1wdC4nXHJcbiAgICB9LFxyXG4gICAgcmVjb25uZWN0QXR0ZW1wdHM6IHtcclxuICAgICAgdmFsdWU6IDMsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnV0VCX1NPQ0tFVF9SRUNPTk5FQ1RfQVRURU1QVFMnLFxyXG4gICAgICBjbGlOYW1lOiAnd3NSZWNvbm5lY3RBdHRlbXB0cycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgbnVtYmVyIG9mIHJlY29ubmVjdCBhdHRlbXB0cyBiZWZvcmUgcmV0dXJuaW5nIGEgY29ubmVjdGlvbiBlcnJvci4nXHJcbiAgICB9LFxyXG4gICAgbWVzc2FnZUludGVydmFsOiB7XHJcbiAgICAgIHZhbHVlOiAzLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1dFQl9TT0NLRVRfTUVTU0FHRV9JTlRFUlZBTCcsXHJcbiAgICAgIGNsaU5hbWU6ICd3c01lc3NhZ2VJbnRlcnZhbCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgaW50ZXJ2YWwsIGluIG1pbGxpc2Vjb25kcywgZm9yIGF1dG8gc2VuZGluZyB0aGUgZGF0YSB0aHJvdWdoIGEgV2ViU29ja2V0IGNvbm5lY3Rpb24uJ1xyXG4gICAgfSxcclxuICAgIHVybDoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnV0VCX1NPQ0tFVF9VUkwnLFxyXG4gICAgICBjbGlOYW1lOiAnd3NVcmwnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBVUkwgb2YgdGhlIFdlYlNvY2tldCBzZXJ2ZXIuJ1xyXG4gICAgfSxcclxuICAgIHNlY3JldDoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnV0VCX1NPQ0tFVF9TRUNSRVQnLFxyXG4gICAgICBjbGlOYW1lOiAnd3NTZWNyZXQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIHNlY3JldCB1c2VkIHRvIGNyZWF0ZSBhIEpTT04gV2ViIFRva2VuIHNlbnQgdG8gdGhlIFdlYlNvY2tldCBzZXJ2ZXIuJ1xyXG4gICAgfVxyXG4gIH1cclxufTtcclxuXHJcbi8vIFRoZSBjb25maWcgZGVzY3JpcHRpb25zIG9iamVjdCBmb3IgdGhlIHByb21wdHMgZnVuY3Rpb25hbGl0eS4gSXQgY29udGFpbnNcclxuLy8gaW5mb3JtYXRpb24gbGlrZTpcclxuLy8gKiBUeXBlIG9mIGEgcHJvbXB0XHJcbi8vICogTmFtZSBvZiBhbiBvcHRpb25cclxuLy8gKiBTaG9ydCBkZXNjcmlwdGlvbiBvZiBhIGNob3NlbiBvcHRpb25cclxuLy8gKiBJbml0aWFsIHZhbHVlXHJcbmV4cG9ydCBjb25zdCBwcm9tcHRzQ29uZmlnID0ge1xyXG4gIHB1cHBldGVlcjogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbGlzdCcsXHJcbiAgICAgIG5hbWU6ICdhcmdzJyxcclxuICAgICAgbWVzc2FnZTogJ1B1cHBldGVlciBhcmd1bWVudHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnB1cHBldGVlci5hcmdzLnZhbHVlLmpvaW4oJywnKSxcclxuICAgICAgc2VwYXJhdG9yOiAnLCdcclxuICAgIH1cclxuICBdLFxyXG4gIGhpZ2hjaGFydHM6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAndmVyc2lvbicsXHJcbiAgICAgIG1lc3NhZ2U6ICdIaWdoY2hhcnRzIHZlcnNpb24nLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMudmVyc2lvbi52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnY2RuVVJMJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBVUkwgb2YgQ0ROJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLmNkblVSTC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ211bHRpc2VsZWN0JyxcclxuICAgICAgbmFtZTogJ2NvcmVTY3JpcHRzJyxcclxuICAgICAgbWVzc2FnZTogJ0F2YWlsYWJsZSBjb3JlIHNjcmlwdHMnLFxyXG4gICAgICBpbnN0cnVjdGlvbnM6ICdTcGFjZTogU2VsZWN0IHNwZWNpZmljLCBBOiBTZWxlY3QgYWxsLCBFbnRlcjogQ29uZmlybS4nLFxyXG4gICAgICBjaG9pY2VzOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuY29yZVNjcmlwdHMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdtdWx0aXNlbGVjdCcsXHJcbiAgICAgIG5hbWU6ICdtb2R1bGVTY3JpcHRzJyxcclxuICAgICAgbWVzc2FnZTogJ0F2YWlsYWJsZSBtb2R1bGUgc2NyaXB0cycsXHJcbiAgICAgIGluc3RydWN0aW9uczogJ1NwYWNlOiBTZWxlY3Qgc3BlY2lmaWMsIEE6IFNlbGVjdCBhbGwsIEVudGVyOiBDb25maXJtLicsXHJcbiAgICAgIGNob2ljZXM6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5tb2R1bGVTY3JpcHRzLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbXVsdGlzZWxlY3QnLFxyXG4gICAgICBuYW1lOiAnaW5kaWNhdG9yU2NyaXB0cycsXHJcbiAgICAgIG1lc3NhZ2U6ICdBdmFpbGFibGUgaW5kaWNhdG9yIHNjcmlwdHMnLFxyXG4gICAgICBpbnN0cnVjdGlvbnM6ICdTcGFjZTogU2VsZWN0IHNwZWNpZmljLCBBOiBTZWxlY3QgYWxsLCBFbnRlcjogQ29uZmlybS4nLFxyXG4gICAgICBjaG9pY2VzOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuaW5kaWNhdG9yU2NyaXB0cy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ2xpc3QnLFxyXG4gICAgICBuYW1lOiAnY3VzdG9tU2NyaXB0cycsXHJcbiAgICAgIG1lc3NhZ2U6ICdDdXN0b20gc2NyaXB0cycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5jdXN0b21TY3JpcHRzLnZhbHVlLmpvaW4oJywnKSxcclxuICAgICAgc2VwYXJhdG9yOiAnLCdcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnZm9yY2VGZXRjaCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdGb3JjZSByZS1mZXRjaCB0aGUgc2NyaXB0cycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5mb3JjZUZldGNoLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdjYWNoZVBhdGgnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIHBhdGggdG8gdGhlIGNhY2hlIGRpcmVjdG9yeScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5jYWNoZVBhdGgudmFsdWVcclxuICAgIH1cclxuICBdLFxyXG4gIGV4cG9ydDogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAnc2VsZWN0JyxcclxuICAgICAgbmFtZTogJ3R5cGUnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgZXhwb3J0IGZpbGUgdHlwZScsXHJcbiAgICAgIGhpbnQ6IGBEZWZhdWx0OiAke2RlZmF1bHRDb25maWcuZXhwb3J0LnR5cGUudmFsdWV9YCxcclxuICAgICAgaW5pdGlhbDogMCxcclxuICAgICAgY2hvaWNlczogWydwbmcnLCAnanBlZycsICdwZGYnLCAnc3ZnJ11cclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdzZWxlY3QnLFxyXG4gICAgICBuYW1lOiAnY29uc3RyJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBkZWZhdWx0IGNvbnN0cnVjdG9yIGZvciBIaWdoY2hhcnRzJyxcclxuICAgICAgaGludDogYERlZmF1bHQ6ICR7ZGVmYXVsdENvbmZpZy5leHBvcnQuY29uc3RyLnZhbHVlfWAsXHJcbiAgICAgIGluaXRpYWw6IDAsXHJcbiAgICAgIGNob2ljZXM6IFsnY2hhcnQnLCAnc3RvY2tDaGFydCcsICdtYXBDaGFydCcsICdnYW50dENoYXJ0J11cclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnZGVmYXVsdEhlaWdodCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgZGVmYXVsdCBmYWxsYmFjayBoZWlnaHQgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5leHBvcnQuZGVmYXVsdEhlaWdodC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdkZWZhdWx0V2lkdGgnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgZmFsbGJhY2sgd2lkdGggb2YgdGhlIGV4cG9ydGVkIGNoYXJ0JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5leHBvcnQuZGVmYXVsdFdpZHRoLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2RlZmF1bHRTY2FsZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgZGVmYXVsdCBmYWxsYmFjayBzY2FsZSBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmV4cG9ydC5kZWZhdWx0U2NhbGUudmFsdWUsXHJcbiAgICAgIG1pbjogMC4xLFxyXG4gICAgICBtYXg6IDVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncmFzdGVyaXphdGlvblRpbWVvdXQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIHJlbmRlcmluZyB3ZWJwYWdlIHRpbWVvdXQgaW4gbWlsbGlzZWNvbmRzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5leHBvcnQucmFzdGVyaXphdGlvblRpbWVvdXQudmFsdWVcclxuICAgIH1cclxuICBdLFxyXG4gIGN1c3RvbUxvZ2ljOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnYWxsb3dDb2RlRXhlY3V0aW9uJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBleGVjdXRpb24gb2YgY3VzdG9tIGNvZGUnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmN1c3RvbUxvZ2ljLmFsbG93Q29kZUV4ZWN1dGlvbi52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdhbGxvd0ZpbGVSZXNvdXJjZXMnLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIGZpbGUgcmVzb3VyY2VzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5jdXN0b21Mb2dpYy5hbGxvd0ZpbGVSZXNvdXJjZXMudmFsdWVcclxuICAgIH1cclxuICBdLFxyXG4gIHNlcnZlcjogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2VuYWJsZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdTdGFydHMgdGhlIHNlcnZlciBvbiAwLjAuMC4wJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIuZW5hYmxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdob3N0JyxcclxuICAgICAgbWVzc2FnZTogJ1NlcnZlciBob3N0bmFtZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLmhvc3QudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncG9ydCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdTZXJ2ZXIgcG9ydCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnBvcnQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnYmVuY2htYXJraW5nJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBzZXJ2ZXIgYmVuY2htYXJraW5nJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIuYmVuY2htYXJraW5nLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdwcm94eS5ob3N0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBob3N0IG9mIHRoZSBwcm94eSBzZXJ2ZXIgdG8gdXNlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucHJveHkuaG9zdC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdwcm94eS5wb3J0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBwb3J0IG9mIHRoZSBwcm94eSBzZXJ2ZXIgdG8gdXNlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucHJveHkucG9ydC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdwcm94eS50aW1lb3V0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSB0aW1lb3V0IGZvciB0aGUgcHJveHkgc2VydmVyIHRvIHVzZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnByb3h5LnRpbWVvdXQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLmVuYWJsZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgcmF0ZSBsaW1pdGluZycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy5lbmFibGUudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLm1heFJlcXVlc3RzJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBtYXhpbXVtIHJlcXVlc3RzIGFsbG93ZWQgcGVyIG1pbnV0ZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy5tYXhSZXF1ZXN0cy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcud2luZG93JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSByYXRlLWxpbWl0aW5nIHRpbWUgd2luZG93IGluIG1pbnV0ZXMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcud2luZG93LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5kZWxheScsXHJcbiAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgJ1RoZSBkZWxheSBmb3IgZWFjaCBzdWNjZXNzaXZlIHJlcXVlc3QgYmVmb3JlIHJlYWNoaW5nIHRoZSBtYXhpbXVtJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLmRlbGF5LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy50cnVzdFByb3h5JyxcclxuICAgICAgbWVzc2FnZTogJ1NldCB0byB0cnVlIGlmIGJlaGluZCBhIGxvYWQgYmFsYW5jZXInLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcudHJ1c3RQcm94eS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLnNraXBLZXknLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdBbGxvd3MgYnlwYXNzaW5nIHRoZSByYXRlIGxpbWl0ZXIgd2hlbiBwcm92aWRlZCB3aXRoIHRoZSBza2lwVG9rZW4gYXJndW1lbnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcuc2tpcEtleS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLnNraXBUb2tlbicsXHJcbiAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgJ0FsbG93cyBieXBhc3NpbmcgdGhlIHJhdGUgbGltaXRlciB3aGVuIHByb3ZpZGVkIHdpdGggdGhlIHNraXBLZXkgYXJndW1lbnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcuc2tpcFRva2VuLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ3NzbC5lbmFibGUnLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIFNTTCBwcm90b2NvbCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnNzbC5lbmFibGUudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnc3NsLmZvcmNlJyxcclxuICAgICAgbWVzc2FnZTogJ0ZvcmNlIHNlcnZpbmcgb25seSBvdmVyIEhUVFBTJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIuc3NsLmZvcmNlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3NzbC5wb3J0JyxcclxuICAgICAgbWVzc2FnZTogJ1NTTCBzZXJ2ZXIgcG9ydCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnNzbC5wb3J0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdzc2wuY2VydFBhdGgnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIHBhdGggdG8gZmluZCB0aGUgU1NMIGNlcnRpZmljYXRlL2tleScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnNzbC5jZXJ0UGF0aC52YWx1ZVxyXG4gICAgfVxyXG4gIF0sXHJcbiAgcG9vbDogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ21pbldvcmtlcnMnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIGluaXRpYWwgbnVtYmVyIG9mIHdvcmtlcnMgdG8gc3Bhd24nLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wubWluV29ya2Vycy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdtYXhXb3JrZXJzJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBtYXhpbXVtIG51bWJlciBvZiB3b3JrZXJzIHRvIHNwYXduJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLm1heFdvcmtlcnMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnd29ya0xpbWl0JyxcclxuICAgICAgbWVzc2FnZTpcclxuICAgICAgICAnVGhlIHBpZWNlcyBvZiB3b3JrIHRoYXQgY2FuIGJlIHBlcmZvcm1lZCBiZWZvcmUgcmVzdGFydGluZyBhIFB1cHBldGVlciBwcm9jZXNzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLndvcmtMaW1pdC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdhY3F1aXJlVGltZW91dCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcyB0byB3YWl0IGZvciBhY3F1aXJpbmcgYSByZXNvdXJjZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5hY3F1aXJlVGltZW91dC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdjcmVhdGVUaW1lb3V0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIHRvIHdhaXQgZm9yIGNyZWF0aW5nIGEgcmVzb3VyY2UnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wuY3JlYXRlVGltZW91dC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdkZXN0cm95VGltZW91dCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcyB0byB3YWl0IGZvciBkZXN0cm95aW5nIGEgcmVzb3VyY2UnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wuZGVzdHJveVRpbWVvdXQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnaWRsZVRpbWVvdXQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgYWZ0ZXIgYW4gaWRsZSByZXNvdXJjZSBpcyBkZXN0cm95ZWQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wuaWRsZVRpbWVvdXQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnY3JlYXRlUmV0cnlJbnRlcnZhbCcsXHJcbiAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgJ1RoZSByZXRyeSBpbnRlcnZhbCBpbiBtaWxsaXNlY29uZHMgYWZ0ZXIgYSBjcmVhdGUgcHJvY2VzcyBmYWlscycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5jcmVhdGVSZXRyeUludGVydmFsLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3JlYXBlckludGVydmFsJyxcclxuICAgICAgbWVzc2FnZTpcclxuICAgICAgICAnVGhlIHJlYXBlciBpbnRlcnZhbCBpbiBtaWxsaXNlY29uZHMgYWZ0ZXIgdHJpZ2dlcmluZyB0aGUgY2hlY2sgZm9yIGlkbGUgcmVzb3VyY2VzIHRvIGRlc3Ryb3knLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wucmVhcGVySW50ZXJ2YWwudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnYmVuY2htYXJraW5nJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBiZW5jaG1hcmtpbmcgZm9yIGEgcmVzb3VyY2UgcG9vbCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5iZW5jaG1hcmtpbmcudmFsdWVcclxuICAgIH1cclxuICBdLFxyXG4gIGxvZ2dpbmc6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdsZXZlbCcsXHJcbiAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgJ1RoZSBsb2cgbGV2ZWwgKDA6IHNpbGVudCwgMTogZXJyb3IsIDI6IHdhcm5pbmcsIDM6IG5vdGljZSwgNDogdmVyYm9zZSwgNTogYmVuY2htYXJrKScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcubG9nZ2luZy5sZXZlbC52YWx1ZSxcclxuICAgICAgcm91bmQ6IDAsXHJcbiAgICAgIG1pbjogMCxcclxuICAgICAgbWF4OiA1XHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdmaWxlJyxcclxuICAgICAgbWVzc2FnZTogJ0EgbG9nIGZpbGUgbmFtZS4gU2V0IHdpdGggdGhlIC0tbG9nRGVzdCB0byBlbmFibGUgZmlsZSBsb2dnaW5nJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5sb2dnaW5nLmZpbGUudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ2Rlc3QnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIHBhdGggdG8gbG9nIGZpbGVzLiBFbmFibGVzIGZpbGUgbG9nZ2luZycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcubG9nZ2luZy5kZXN0LnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICB1aTogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2VuYWJsZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgVUkgZm9yIHRoZSBleHBvcnQgc2VydmVyJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy51aS5lbmFibGUudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ3JvdXRlJyxcclxuICAgICAgbWVzc2FnZTogJ0Egcm91dGUgdG8gYXR0YWNoIHRoZSBVSScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcudWkucm91dGUudmFsdWVcclxuICAgIH1cclxuICBdLFxyXG4gIG90aGVyOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ25vZGVFbnYnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIHR5cGUgb2YgTm9kZS5qcyBlbnZpcm9ubWVudCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcub3RoZXIubm9kZUVudi52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdsaXN0ZW5Ub1Byb2Nlc3NFeGl0cycsXHJcbiAgICAgIG1lc3NhZ2U6ICdTZXQgdG8gZmFsc2UgdG8gc2tpcCBhdHRhY2hpbmcgcHJvY2Vzcy5leGl0IGhhbmRsZXJzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5vdGhlci5saXN0ZW5Ub1Byb2Nlc3NFeGl0cy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdub0xvZ28nLFxyXG4gICAgICBtZXNzYWdlOiAnU2tpcCBwcmludGluZyB0aGUgbG9nbyBvbiBzdGFydHVwLiBSZXBsYWNlZCBieSBzaW1wbGUgdGV4dCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcub3RoZXIubm9Mb2dvLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2hhcmRSZXNldFBhZ2UnLFxyXG4gICAgICBtZXNzYWdlOiAnRGVjaWRlcyBpZiB0aGUgcGFnZSBjb250ZW50IHNob3VsZCBiZSByZXNldCBlbnRpcmVseScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcub3RoZXIuaGFyZFJlc2V0UGFnZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdicm93c2VyU2hlbGxNb2RlJyxcclxuICAgICAgbWVzc2FnZTogJ0RlY2lkZXMgaWYgdGhlIGJyb3dzZXIgcnVucyBpbiB0aGUgc2hlbGwgbW9kZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcub3RoZXIuYnJvd3NlclNoZWxsTW9kZS52YWx1ZVxyXG4gICAgfVxyXG4gIF0sXHJcbiAgZGVidWc6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdlbmFibGUnLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlcyBkZWJ1ZyBtb2RlIGZvciB0aGUgYnJvd3NlciBpbnN0YW5jZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZGVidWcuZW5hYmxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2hlYWRsZXNzJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBtb2RlIHNldHRpbmcgZm9yIHRoZSBicm93c2VyJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5kZWJ1Zy5oZWFkbGVzcy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdkZXZ0b29scycsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgRGV2VG9vbHMgZm9yIHRoZSBoZWFkZnVsIGJyb3dzZXInLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmRlYnVnLmRldnRvb2xzLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2xpc3RlblRvQ29uc29sZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgZXZlbnQgbGlzdGVuZXIgZm9yIGNvbnNvbGUgbWVzc2FnZXMgZnJvbSB0aGUgYnJvd3NlcicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZGVidWcubGlzdGVuVG9Db25zb2xlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2R1bXBpbycsXHJcbiAgICAgIG1lc3NhZ2U6ICdSZWRpcmVjdHMgdGhlIGJyb3dzZXIgc3Rkb3V0IGFuZCBzdGRlcnIgdG8gTm9kZUpTIHByb2Nlc3MnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmRlYnVnLmR1bXBpby52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdzbG93TW8nLFxyXG4gICAgICBtZXNzYWdlOiAnUHVwcGV0ZWVyIG9wZXJhdGlvbnMgc2xvdyBkb3duIGluIG1pbGxpc2Vjb25kcycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZGVidWcuc2xvd01vLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2RlYnVnZ2luZ1BvcnQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIHBvcnQgbnVtYmVyIGZvciBkZWJ1Z2dpbmcnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmRlYnVnLmRlYnVnZ2luZ1BvcnQudmFsdWVcclxuICAgIH1cclxuICBdLFxyXG4gIHdlYlNvY2tldDogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2VuYWJsZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGVzIFdlYlNvY2tldCBjb25uZWN0aW9uJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy53ZWJTb2NrZXQuZW5hYmxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ3JlY29ubmVjdCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcmVjb25uZWN0IG1lY2hhbmlzbSBmb3IgV2ViU29ja2V0IGNvbm5lY3Rpb24nLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLndlYlNvY2tldC5yZWNvbm5lY3QudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAncmVqZWN0VW5hdXRob3JpemVkJyxcclxuICAgICAgbWVzc2FnZTogJ1JlamVjdCBjb25uZWN0aW9uIGlmIFdlYlNvY2tldCBpcyBub3Qgc2VjdXJlZCwgU1NML1RMUycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcud2ViU29ja2V0LnJlamVjdFVuYXV0aG9yaXplZC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdwaW5nVGltZW91dCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaW1lb3V0IGZvciB0aGUgaGVhcmJlYXQgbWVjaGFuaXNtJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy53ZWJTb2NrZXQucGluZ1RpbWVvdXQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncmVjb25uZWN0SW50ZXJ2YWwnLFxyXG4gICAgICBtZXNzYWdlOiAnSW50ZXJ2YWwgZm9yIHRoZSByZWNvbm5lY3QgbWVjaGFuaXNtJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy53ZWJTb2NrZXQucmVjb25uZWN0SW50ZXJ2YWwudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncmVjb25uZWN0QXR0ZW1wdHMnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIG51bWJlciBvZiByZWNvbm5lY3QgYXR0ZW1wdHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLndlYlNvY2tldC5yZWNvbm5lY3RBdHRlbXB0cy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdtZXNzYWdlSW50ZXJ2YWwnLFxyXG4gICAgICBtZXNzYWdlOiAnSW50ZXJ2YWwgZm9yIGF1dG8gc2VuZGluZyB0aGUgZGF0YScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcud2ViU29ja2V0Lm1lc3NhZ2VJbnRlcnZhbC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAndXJsJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBVUkwgb2YgdGhlIFdlYlNvY2tldCBzZXJ2ZXInLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLndlYlNvY2tldC51cmwudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ3NlY3JldCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgc2VjcmV0IGZvciB0aGUgSldUIHRvIFdlYlNvY2tldCBzZXJ2ZXInLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLndlYlNvY2tldC5zZWNyZXQudmFsdWVcclxuICAgIH1cclxuICBdXHJcbn07XHJcblxyXG4vLyBBYnNvbHV0ZSBwcm9wcyB0aGF0LCBpbiBjYXNlIG9mIG1lcmdpbmcgcmVjdXJzaXZlbHksIG5lZWQgdG8gYmUgZm9yY2UgbWVyZ2VkXHJcbmV4cG9ydCBjb25zdCBhYnNvbHV0ZVByb3BzID0gW1xyXG4gICdvcHRpb25zJyxcclxuICAnZ2xvYmFsT3B0aW9ucycsXHJcbiAgJ3RoZW1lT3B0aW9ucycsXHJcbiAgJ3Jlc291cmNlcycsXHJcbiAgJ3BheWxvYWQnXHJcbl07XHJcblxyXG4vLyBBcmd1bWVudCBuZXN0aW5nIGxldmVsIG9mIGFsbCBleHBvcnQgc2VydmVyIG9wdGlvbnNcclxuZXhwb3J0IGNvbnN0IG5lc3RlZEFyZ3MgPSB7fTtcclxuXHJcbi8qKlxyXG4gKiBSZWN1cnNpdmVseSBjcmVhdGVzIGEgY2hhaW4gb2YgbmVzdGVkIGFyZ3VtZW50cyBmcm9tIGFuIG9iamVjdC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9iaiAtIFRoZSBvYmplY3QgY29udGFpbmluZyBuZXN0ZWQgYXJndW1lbnRzLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcHJvcENoYWluIC0gVGhlIGN1cnJlbnQgY2hhaW4gb2YgbmVzdGVkIHByb3BlcnRpZXNcclxuICogKHVzZWQgaW50ZXJuYWxseSBkdXJpbmcgcmVjdXJzaW9uKS5cclxuICovXHJcbmNvbnN0IGNyZWF0ZU5lc3RlZEFyZ3MgPSAob2JqLCBwcm9wQ2hhaW4gPSAnJykgPT4ge1xyXG4gIE9iamVjdC5rZXlzKG9iaikuZm9yRWFjaCgoaykgPT4ge1xyXG4gICAgaWYgKCFbJ3B1cHBldGVlcicsICdoaWdoY2hhcnRzJ10uaW5jbHVkZXMoaykpIHtcclxuICAgICAgY29uc3QgZW50cnkgPSBvYmpba107XHJcbiAgICAgIGlmICh0eXBlb2YgZW50cnkudmFsdWUgPT09ICd1bmRlZmluZWQnKSB7XHJcbiAgICAgICAgLy8gR28gZGVlcGVyIGluIHRoZSBuZXN0ZWQgYXJndW1lbnRzXHJcbiAgICAgICAgY3JlYXRlTmVzdGVkQXJncyhlbnRyeSwgYCR7cHJvcENoYWlufS4ke2t9YCk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgLy8gQ3JlYXRlIHRoZSBjaGFpbiBvZiBuZXN0ZWQgYXJndW1lbnRzXHJcbiAgICAgICAgbmVzdGVkQXJnc1tlbnRyeS5jbGlOYW1lIHx8IGtdID0gYCR7cHJvcENoYWlufS4ke2t9YC5zdWJzdHJpbmcoMSk7XHJcblxyXG4gICAgICAgIC8vIFN1cHBvcnQgZm9yIHRoZSBsZWdhY3ksIFBoYW50b21KUyBwcm9wZXJ0aWVzIG5hbWVzXHJcbiAgICAgICAgaWYgKGVudHJ5LmxlZ2FjeU5hbWUgIT09IHVuZGVmaW5lZCkge1xyXG4gICAgICAgICAgbmVzdGVkQXJnc1tlbnRyeS5sZWdhY3lOYW1lXSA9IGAke3Byb3BDaGFpbn0uJHtrfWAuc3Vic3RyaW5nKDEpO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0pO1xyXG59O1xyXG5cclxuY3JlYXRlTmVzdGVkQXJncyhkZWZhdWx0Q29uZmlnKTtcclxuIiwiLyoqXHJcbiAqIEBmaWxlb3ZlcnZpZXdcclxuICogVGhpcyBmaWxlIGlzIHJlc3BvbnNpYmxlIGZvciBwYXJzaW5nIHRoZSBlbnZpcm9ubWVudCB2YXJpYWJsZXMgd2l0aCB0aGUgJ3pvZCdcclxuICogbGlicmFyeS4gVGhlIHBhcnNlZCBlbnZpcm9ubWVudCB2YXJpYWJsZXMgYXJlIHRoZW4gZXhwb3J0ZWQgdG8gYmUgdXNlZFxyXG4gKiBpbiB0aGUgYXBwbGljYXRpb24gYXMgXCJlbnZzXCIuIFdlIHNob3VsZCBub3QgdXNlIHByb2Nlc3MuZW52IGRpcmVjdGx5XHJcbiAqIGluIHRoZSBhcHBsaWNhdGlvbiBhcyB0aGVzZSB3b3VsZCBub3QgYmUgcGFyc2VkIHByb3Blcmx5LlxyXG4gKlxyXG4gKiBUaGUgZW52aXJvbm1lbnQgdmFyaWFibGVzIGFyZSBwYXJzZWQgYW5kIHZhbGlkYXRlZCBvbmx5IG9uY2Ugd2hlblxyXG4gKiB0aGUgYXBwbGljYXRpb24gc3RhcnRzLiBXZSBzaG91bGQgd3JpdGUgYSBjdXN0b20gdmFsaWRhdG9yIG9yIGEgdHJhbnNmb3JtZXJcclxuICogZm9yIGVhY2ggb2YgdGhlIG9wdGlvbnMuXHJcbiAqL1xyXG5cclxuaW1wb3J0IGRvdGVudiBmcm9tICdkb3RlbnYnO1xyXG5pbXBvcnQgeyB6IH0gZnJvbSAnem9kJztcclxuXHJcbmltcG9ydCB7IHNjcmlwdHNOYW1lcyB9IGZyb20gJy4vc2NoZW1hcy9jb25maWcuanMnO1xyXG5cclxuLy8gTG9hZCAuZW52IGludG8gZW52aXJvbm1lbnQgdmFyaWFibGVzXHJcbmRvdGVudi5jb25maWcoKTtcclxuXHJcbi8vIE9iamVjdCB3aXRoIGN1c3RvbSB2YWxpZGF0b3JzIGFuZCB0cmFuc2Zvcm1lcnMsIHRvIGF2b2lkIHJlcGV0aXRpb25cclxuLy8gaW4gdGhlIENvbmZpZyBvYmplY3RcclxuY29uc3QgdiA9IHtcclxuICAvLyBTcGxpdHMgc3RyaW5nIHZhbHVlIGludG8gZWxlbWVudHMgaW4gYW4gYXJyYXksIHRyaW1zIGV2ZXJ5IGVsZW1lbnQsIGNoZWNrc1xyXG4gIC8vIGlmIGFuIGFycmF5IGlzIGNvcnJlY3QsIGlmIGl0IGlzIGVtcHR5LCBhbmQgaWYgaXQgaXMsIHJldHVybnMgdW5kZWZpbmVkXHJcbiAgYXJyYXk6IChmaWx0ZXJBcnJheSkgPT5cclxuICAgIHpcclxuICAgICAgLnN0cmluZygpXHJcbiAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgIHZhbHVlXHJcbiAgICAgICAgICAuc3BsaXQoJywnKVxyXG4gICAgICAgICAgLm1hcCgodmFsdWUpID0+IHZhbHVlLnRyaW0oKSlcclxuICAgICAgICAgIC5maWx0ZXIoKHZhbHVlKSA9PiBmaWx0ZXJBcnJheS5pbmNsdWRlcyh2YWx1ZSkpXHJcbiAgICAgIClcclxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZS5sZW5ndGggPyB2YWx1ZSA6IHVuZGVmaW5lZCkpLFxyXG5cclxuICAvLyBBbGxvd3Mgb25seSB0cnVlLCBmYWxzZSBhbmQgY29ycmVjdGx5IHBhcnNlIHRoZSB2YWx1ZSB0byBib29sZWFuXHJcbiAgLy8gb3Igbm8gdmFsdWUgaW4gd2hpY2ggY2FzZSB0aGUgcmV0dXJuZWQgdmFsdWUgd2lsbCBiZSB1bmRlZmluZWRcclxuICBib29sZWFuOiAoKSA9PlxyXG4gICAgelxyXG4gICAgICAuZW51bShbJ3RydWUnLCAnZmFsc2UnLCAnJ10pXHJcbiAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUgIT09ICcnID8gdmFsdWUgPT09ICd0cnVlJyA6IHVuZGVmaW5lZCkpLFxyXG5cclxuICAvLyBBbGxvd3MgcGFzc2VkIHZhbHVlcyBvciBubyB2YWx1ZSBpbiB3aGljaCBjYXNlIHRoZSByZXR1cm5lZCB2YWx1ZSB3aWxsXHJcbiAgLy8gYmUgdW5kZWZpbmVkXHJcbiAgZW51bTogKHZhbHVlcykgPT5cclxuICAgIHpcclxuICAgICAgLmVudW0oWy4uLnZhbHVlcywgJyddKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHZhbHVlIDogdW5kZWZpbmVkKSksXHJcblxyXG4gIC8vIFRyaW1zIHRoZSBzdHJpbmcgdmFsdWUgYW5kIGNoZWNrcyBpZiBpdCBpcyBlbXB0eSBvciBjb250YWlucyBzdHJpbmdpZmllZFxyXG4gIC8vIHZhbHVlcyBzdWNoIGFzIGZhbHNlLCB1bmRlZmluZWQsIG51bGwsIE5hTiwgaWYgaXQgZG9lcywgcmV0dXJucyB1bmRlZmluZWRcclxuICBzdHJpbmc6ICgpID0+XHJcbiAgICB6XHJcbiAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAudHJpbSgpXHJcbiAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgIVsnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCAnTmFOJ10uaW5jbHVkZXModmFsdWUpIHx8XHJcbiAgICAgICAgICB2YWx1ZSA9PT0gJycsXHJcbiAgICAgICAgKHZhbHVlKSA9PiAoe1xyXG4gICAgICAgICAgbWVzc2FnZTogYFRoZSBzdHJpbmcgY29udGFpbnMgZm9yYmlkZGVuIHZhbHVlcywgcmVjZWl2ZWQgJyR7dmFsdWV9J2BcclxuICAgICAgICB9KVxyXG4gICAgICApXHJcbiAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUgIT09ICcnID8gdmFsdWUgOiB1bmRlZmluZWQpKSxcclxuXHJcbiAgLy8gQWxsb3dzIHBvc2l0aXZlIG51bWJlcnMgb3Igbm8gdmFsdWUgaW4gd2hpY2ggY2FzZSB0aGUgcmV0dXJuZWQgdmFsdWUgd2lsbFxyXG4gIC8vIGJlIHVuZGVmaW5lZFxyXG4gIHBvc2l0aXZlTnVtOiAoKSA9PlxyXG4gICAgelxyXG4gICAgICAuc3RyaW5nKClcclxuICAgICAgLnRyaW0oKVxyXG4gICAgICAucmVmaW5lKFxyXG4gICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgIHZhbHVlID09PSAnJyB8fCAoIWlzTmFOKHBhcnNlRmxvYXQodmFsdWUpKSAmJiBwYXJzZUZsb2F0KHZhbHVlKSA+IDApLFxyXG4gICAgICAgICh2YWx1ZSkgPT4gKHtcclxuICAgICAgICAgIG1lc3NhZ2U6IGBUaGUgdmFsdWUgbXVzdCBiZSBudW1lcmljIGFuZCBwb3NpdGl2ZSwgcmVjZWl2ZWQgJyR7dmFsdWV9J2BcclxuICAgICAgICB9KVxyXG4gICAgICApXHJcbiAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUgIT09ICcnID8gcGFyc2VGbG9hdCh2YWx1ZSkgOiB1bmRlZmluZWQpKSxcclxuXHJcbiAgLy8gQWxsb3dzIG5vbi1uZWdhdGl2ZSBudW1iZXJzIG9yIG5vIHZhbHVlIGluIHdoaWNoIGNhc2UgdGhlIHJldHVybmVkIHZhbHVlXHJcbiAgLy8gd2lsbCBiZSB1bmRlZmluZWRcclxuICBub25OZWdhdGl2ZU51bTogKCkgPT5cclxuICAgIHpcclxuICAgICAgLnN0cmluZygpXHJcbiAgICAgIC50cmltKClcclxuICAgICAgLnJlZmluZShcclxuICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICB2YWx1ZSA9PT0gJycgfHwgKCFpc05hTihwYXJzZUZsb2F0KHZhbHVlKSkgJiYgcGFyc2VGbG9hdCh2YWx1ZSkgPj0gMCksXHJcbiAgICAgICAgKHZhbHVlKSA9PiAoe1xyXG4gICAgICAgICAgbWVzc2FnZTogYFRoZSB2YWx1ZSBtdXN0IGJlIG51bWVyaWMgYW5kIG5vbi1uZWdhdGl2ZSwgcmVjZWl2ZWQgJyR7dmFsdWV9J2BcclxuICAgICAgICB9KVxyXG4gICAgICApXHJcbiAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUgIT09ICcnID8gcGFyc2VGbG9hdCh2YWx1ZSkgOiB1bmRlZmluZWQpKVxyXG59O1xyXG5cclxuZXhwb3J0IGNvbnN0IENvbmZpZyA9IHoub2JqZWN0KHtcclxuICAvLyBoaWdoY2hhcnRzXHJcbiAgSElHSENIQVJUU19WRVJTSU9OOiB6XHJcbiAgICAuc3RyaW5nKClcclxuICAgIC50cmltKClcclxuICAgIC5yZWZpbmUoXHJcbiAgICAgICh2YWx1ZSkgPT4gL14obGF0ZXN0fFxcZCsoXFwuXFxkKyl7MCwyfSkkLy50ZXN0KHZhbHVlKSB8fCB2YWx1ZSA9PT0gJycsXHJcbiAgICAgICh2YWx1ZSkgPT4gKHtcclxuICAgICAgICBtZXNzYWdlOiBgSElHSENIQVJUU19WRVJTSU9OIG11c3QgYmUgJ2xhdGVzdCcsIGEgbWFqb3IgdmVyc2lvbiwgb3IgaW4gdGhlIGZvcm0gWFguWVkuWlosIHJlY2VpdmVkICcke3ZhbHVlfSdgXHJcbiAgICAgIH0pXHJcbiAgICApXHJcbiAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHZhbHVlIDogdW5kZWZpbmVkKSksXHJcbiAgSElHSENIQVJUU19DRE5fVVJMOiB6XHJcbiAgICAuc3RyaW5nKClcclxuICAgIC50cmltKClcclxuICAgIC5yZWZpbmUoXHJcbiAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICB2YWx1ZS5zdGFydHNXaXRoKCdodHRwczovLycpIHx8XHJcbiAgICAgICAgdmFsdWUuc3RhcnRzV2l0aCgnaHR0cDovLycpIHx8XHJcbiAgICAgICAgdmFsdWUgPT09ICcnLFxyXG4gICAgICAodmFsdWUpID0+ICh7XHJcbiAgICAgICAgbWVzc2FnZTogYEludmFsaWQgdmFsdWUgZm9yIEhJR0hDSEFSVFNfQ0ROX1VSTC4gSXQgc2hvdWxkIHN0YXJ0IHdpdGggaHR0cDovLyBvciBodHRwczovLywgcmVjZWl2ZWQgJyR7dmFsdWV9J2BcclxuICAgICAgfSlcclxuICAgIClcclxuICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUgIT09ICcnID8gdmFsdWUgOiB1bmRlZmluZWQpKSxcclxuICBISUdIQ0hBUlRTX0NPUkVfU0NSSVBUUzogdi5hcnJheShzY3JpcHRzTmFtZXMuY29yZSksXHJcbiAgSElHSENIQVJUU19NT0RVTEVfU0NSSVBUUzogdi5hcnJheShzY3JpcHRzTmFtZXMubW9kdWxlcyksXHJcbiAgSElHSENIQVJUU19JTkRJQ0FUT1JfU0NSSVBUUzogdi5hcnJheShzY3JpcHRzTmFtZXMuaW5kaWNhdG9ycyksXHJcbiAgSElHSENIQVJUU19GT1JDRV9GRVRDSDogdi5ib29sZWFuKCksXHJcbiAgSElHSENIQVJUU19DQUNIRV9QQVRIOiB2LnN0cmluZygpLFxyXG4gIEhJR0hDSEFSVFNfQURNSU5fVE9LRU46IHYuc3RyaW5nKCksXHJcblxyXG4gIC8vIGV4cG9ydFxyXG4gIEVYUE9SVF9UWVBFOiB2LmVudW0oWydqcGVnJywgJ3BuZycsICdwZGYnLCAnc3ZnJ10pLFxyXG4gIEVYUE9SVF9DT05TVFI6IHYuZW51bShbJ2NoYXJ0JywgJ3N0b2NrQ2hhcnQnLCAnbWFwQ2hhcnQnLCAnZ2FudHRDaGFydCddKSxcclxuICBFWFBPUlRfREVGQVVMVF9IRUlHSFQ6IHYucG9zaXRpdmVOdW0oKSxcclxuICBFWFBPUlRfREVGQVVMVF9XSURUSDogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIEVYUE9SVF9ERUZBVUxUX1NDQUxFOiB2LnBvc2l0aXZlTnVtKCksXHJcbiAgRVhQT1JUX1JBU1RFUklaQVRJT05fVElNRU9VVDogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG5cclxuICAvLyBjdXN0b21cclxuICBDVVNUT01fTE9HSUNfQUxMT1dfQ09ERV9FWEVDVVRJT046IHYuYm9vbGVhbigpLFxyXG4gIENVU1RPTV9MT0dJQ19BTExPV19GSUxFX1JFU09VUkNFUzogdi5ib29sZWFuKCksXHJcblxyXG4gIC8vIHNlcnZlclxyXG4gIFNFUlZFUl9FTkFCTEU6IHYuYm9vbGVhbigpLFxyXG4gIFNFUlZFUl9IT1NUOiB2LnN0cmluZygpLFxyXG4gIFNFUlZFUl9QT1JUOiB2LnBvc2l0aXZlTnVtKCksXHJcbiAgU0VSVkVSX0JFTkNITUFSS0lORzogdi5ib29sZWFuKCksXHJcblxyXG4gIC8vIHNlcnZlciBwcm94eVxyXG4gIFNFUlZFUl9QUk9YWV9IT1NUOiB2LnN0cmluZygpLFxyXG4gIFNFUlZFUl9QUk9YWV9QT1JUOiB2LnBvc2l0aXZlTnVtKCksXHJcbiAgU0VSVkVSX1BST1hZX1RJTUVPVVQ6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuXHJcbiAgLy8gc2VydmVyIHJhdGUgbGltaXRpbmdcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19FTkFCTEU6IHYuYm9vbGVhbigpLFxyXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX01BWF9SRVFVRVNUUzogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX1dJTkRPVzogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX0RFTEFZOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfVFJVU1RfUFJPWFk6IHYuYm9vbGVhbigpLFxyXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfS0VZOiB2LnN0cmluZygpLFxyXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfVE9LRU46IHYuc3RyaW5nKCksXHJcblxyXG4gIC8vIHNlcnZlciBzc2xcclxuICBTRVJWRVJfU1NMX0VOQUJMRTogdi5ib29sZWFuKCksXHJcbiAgU0VSVkVSX1NTTF9GT1JDRTogdi5ib29sZWFuKCksXHJcbiAgU0VSVkVSX1NTTF9QT1JUOiB2LnBvc2l0aXZlTnVtKCksXHJcbiAgU0VSVkVSX1NTTF9DRVJUX1BBVEg6IHYuc3RyaW5nKCksXHJcblxyXG4gIC8vIHBvb2xcclxuICBQT09MX01JTl9XT1JLRVJTOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcbiAgUE9PTF9NQVhfV09SS0VSUzogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfV09SS19MSU1JVDogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIFBPT0xfQUNRVUlSRV9USU1FT1VUOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcbiAgUE9PTF9DUkVBVEVfVElNRU9VVDogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfREVTVFJPWV9USU1FT1VUOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcbiAgUE9PTF9JRExFX1RJTUVPVVQ6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBQT09MX0NSRUFURV9SRVRSWV9JTlRFUlZBTDogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfUkVBUEVSX0lOVEVSVkFMOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcbiAgUE9PTF9CRU5DSE1BUktJTkc6IHYuYm9vbGVhbigpLFxyXG5cclxuICAvLyBsb2dnZXJcclxuICBMT0dHSU5HX0xFVkVMOiB6XHJcbiAgICAuc3RyaW5nKClcclxuICAgIC50cmltKClcclxuICAgIC5yZWZpbmUoXHJcbiAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICB2YWx1ZSA9PT0gJycgfHxcclxuICAgICAgICAoIWlzTmFOKHBhcnNlRmxvYXQodmFsdWUpKSAmJlxyXG4gICAgICAgICAgcGFyc2VGbG9hdCh2YWx1ZSkgPj0gMCAmJlxyXG4gICAgICAgICAgcGFyc2VGbG9hdCh2YWx1ZSkgPD0gNSksXHJcbiAgICAgICh2YWx1ZSkgPT4gKHtcclxuICAgICAgICBtZXNzYWdlOiBgSW52YWxpZCB2YWx1ZSBmb3IgTE9HR0lOR19MRVZFTC4gV2Ugb25seSBhY2NlcHQgdmFsdWVzIGZyb20gMCB0byA1IGFzIGxvZ2dpbmcgbGV2ZWxzLCByZWNlaXZlZCAnJHt2YWx1ZX0nYFxyXG4gICAgICB9KVxyXG4gICAgKVxyXG4gICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyBwYXJzZUZsb2F0KHZhbHVlKSA6IHVuZGVmaW5lZCkpLFxyXG4gIExPR0dJTkdfRklMRTogdi5zdHJpbmcoKSxcclxuICBMT0dHSU5HX0RFU1Q6IHYuc3RyaW5nKCksXHJcblxyXG4gIC8vIHVpXHJcbiAgVUlfRU5BQkxFOiB2LmJvb2xlYW4oKSxcclxuICBVSV9ST1VURTogdi5zdHJpbmcoKSxcclxuXHJcbiAgLy8gb3RoZXJcclxuICBPVEhFUl9OT0RFX0VOVjogdi5lbnVtKFsnZGV2ZWxvcG1lbnQnLCAncHJvZHVjdGlvbicsICd0ZXN0J10pLFxyXG4gIE9USEVSX0xJU1RFTl9UT19QUk9DRVNTX0VYSVRTOiB2LmJvb2xlYW4oKSxcclxuICBPVEhFUl9OT19MT0dPOiB2LmJvb2xlYW4oKSxcclxuICBPVEhFUl9IQVJEX1JFU0VUX1BBR0U6IHYuYm9vbGVhbigpLFxyXG4gIE9USEVSX0JST1dTRVJfU0hFTExfTU9ERTogdi5ib29sZWFuKCksXHJcblxyXG4gIC8vIGRlYnVnZ2VyXHJcbiAgREVCVUdfRU5BQkxFOiB2LmJvb2xlYW4oKSxcclxuICBERUJVR19IRUFETEVTUzogdi5ib29sZWFuKCksXHJcbiAgREVCVUdfREVWVE9PTFM6IHYuYm9vbGVhbigpLFxyXG4gIERFQlVHX0xJU1RFTl9UT19DT05TT0xFOiB2LmJvb2xlYW4oKSxcclxuICBERUJVR19EVU1QSU86IHYuYm9vbGVhbigpLFxyXG4gIERFQlVHX1NMT1dfTU86IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBERUJVR19ERUJVR0dJTkdfUE9SVDogdi5wb3NpdGl2ZU51bSgpLFxyXG5cclxuICAvLyB3ZWJzb2NrZXRcclxuICBXRUJfU09DS0VUX0VOQUJMRTogdi5ib29sZWFuKCksXHJcbiAgV0VCX1NPQ0tFVF9SRUNPTk5FQ1Q6IHYuYm9vbGVhbigpLFxyXG4gIFdFQl9TT0NLRVRfUkVKRUNUX1VOQVVUSE9SSVpFRDogdi5ib29sZWFuKCksXHJcbiAgV0VCX1NPQ0tFVF9QSU5HX1RJTUVPVVQ6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBXRUJfU09DS0VUX1JFQ09OTkVDVF9JTlRFUlZBTDogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFdFQl9TT0NLRVRfUkVDT05ORUNUX0FUVEVNUFRTOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcbiAgV0VCX1NPQ0tFVF9NRVNTQUdFX0lOVEVSVkFMOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcbiAgV0VCX1NPQ0tFVF9VUkw6IHYuc3RyaW5nKCksXHJcbiAgV0VCX1NPQ0tFVF9TRUNSRVQ6IHYuc3RyaW5nKClcclxufSk7XHJcblxyXG5leHBvcnQgY29uc3QgZW52cyA9IENvbmZpZy5wYXJ0aWFsKCkucGFyc2UocHJvY2Vzcy5lbnYpO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IGFwcGVuZEZpbGUsIGV4aXN0c1N5bmMsIG1rZGlyU3luYyB9IGZyb20gJ2ZzJztcclxuXHJcbmltcG9ydCB7IGRlZmF1bHRDb25maWcgfSBmcm9tICcuL3NjaGVtYXMvY29uZmlnLmpzJztcclxuXHJcbi8vIFRoZSBhdmFpbGFibGUgY29sb3JzXHJcbmNvbnN0IGNvbG9ycyA9IFsncmVkJywgJ3llbGxvdycsICdibHVlJywgJ2dyYXknLCAnZ3JlZW4nXTtcclxuXHJcbi8vIFRoZSBkZWZhdWx0IGxvZ2dpbmcgY29uZmlnXHJcbmxldCBsb2dnaW5nID0ge1xyXG4gIC8vIEZsYWdzIGZvciBsb2dnaW5nIHN0YXR1c1xyXG4gIHRvQ29uc29sZTogdHJ1ZSxcclxuICB0b0ZpbGU6IGZhbHNlLFxyXG4gIHBhdGhDcmVhdGVkOiBmYWxzZSxcclxuICAvLyBMb2cgbGV2ZWxzXHJcbiAgbGV2ZWxzRGVzYzogW1xyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ2Vycm9yJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1swXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICd3YXJuaW5nJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1sxXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICdub3RpY2UnLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzJdXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ3ZlcmJvc2UnLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzNdXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ2JlbmNobWFyaycsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbNF1cclxuICAgIH1cclxuICBdLFxyXG4gIC8vIExvZyBsaXN0ZW5lcnNcclxuICBsaXN0ZW5lcnM6IFtdXHJcbn07XHJcblxyXG4vLyBHYXRoZXIgaW5pdCBsb2dnaW5nIG9wdGlvbnNcclxuZm9yIChjb25zdCBba2V5LCBvcHRpb25dIG9mIE9iamVjdC5lbnRyaWVzKGRlZmF1bHRDb25maWcubG9nZ2luZykpIHtcclxuICBsb2dnaW5nW2tleV0gPSBvcHRpb24udmFsdWU7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBMb2dzIHRoZSBwcm92aWRlZCB0ZXh0cyB0byBhIGZpbGUsIGlmIGZpbGUgbG9nZ2luZyBpcyBlbmFibGVkLiBJdCBjcmVhdGVzXHJcbiAqIHRoZSBuZWNlc3NhcnkgZGlyZWN0b3J5IHN0cnVjdHVyZSBpZiBub3QgYWxyZWFkeSBjcmVhdGVkIGFuZCBhcHBlbmRzIHRoZVxyXG4gKiBjb250ZW50LCBpbmNsdWRpbmcgYW4gb3B0aW9uYWwgcHJlZml4LCB0byB0aGUgc3BlY2lmaWVkIGxvZyBmaWxlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ1tdfSB0ZXh0cyAtIEFuIGFycmF5IG9mIHRleHRzIHRvIGJlIGxvZ2dlZC5cclxuICogQHBhcmFtIHtzdHJpbmd9IHByZWZpeCAtIEFuIG9wdGlvbmFsIHByZWZpeCB0byBiZSBhZGRlZCB0byBlYWNoIGxvZyBlbnRyeS5cclxuICovXHJcbmNvbnN0IGxvZ1RvRmlsZSA9ICh0ZXh0cywgcHJlZml4KSA9PiB7XHJcbiAgaWYgKGxvZ2dpbmcudG9GaWxlKSB7XHJcbiAgICBpZiAoIWxvZ2dpbmcucGF0aENyZWF0ZWQpIHtcclxuICAgICAgLy8gQ3JlYXRlIGlmIGRvZXMgbm90IGV4aXN0XHJcbiAgICAgICFleGlzdHNTeW5jKGxvZ2dpbmcuZGVzdCkgJiYgbWtkaXJTeW5jKGxvZ2dpbmcuZGVzdCk7XHJcblxyXG4gICAgICAvLyBXZSBub3cgYXNzdW1lIHRoZSBwYXRoIGlzIGF2YWlsYWJsZSwgZS5nLiBpdCdzIHRoZSByZXNwb25zaWJpbGl0eVxyXG4gICAgICAvLyBvZiB0aGUgdXNlciB0byBjcmVhdGUgdGhlIHBhdGggd2l0aCB0aGUgY29ycmVjdCBhY2Nlc3MgcmlnaHRzLlxyXG4gICAgICBsb2dnaW5nLnBhdGhDcmVhdGVkID0gdHJ1ZTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBBZGQgdGhlIGNvbnRlbnQgdG8gYSBmaWxlXHJcbiAgICBhcHBlbmRGaWxlKFxyXG4gICAgICBgJHtsb2dnaW5nLmRlc3R9JHtsb2dnaW5nLmZpbGV9YCxcclxuICAgICAgW3ByZWZpeF0uY29uY2F0KHRleHRzKS5qb2luKCcgJykgKyAnXFxuJyxcclxuICAgICAgKGVycm9yKSA9PiB7XHJcbiAgICAgICAgaWYgKGVycm9yKSB7XHJcbiAgICAgICAgICBjb25zb2xlLmxvZyhgW2xvZ2dlcl0gVW5hYmxlIHRvIHdyaXRlIHRvIGxvZyBmaWxlOiAke2Vycm9yfWApO1xyXG4gICAgICAgICAgbG9nZ2luZy50b0ZpbGUgPSBmYWxzZTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgICk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIExvZ3MgYSBtZXNzYWdlLiBBY2NlcHRzIGEgdmFyaWFibGUgYW1vdW50IG9mIGFyZ3VtZW50cy4gQXJndW1lbnRzIGFmdGVyXHJcbiAqIGBsZXZlbGAgd2lsbCBiZSBwYXNzZWQgZGlyZWN0bHkgdG8gY29uc29sZS5sb2csIGFuZC9vciB3aWxsIGJlIGpvaW5lZFxyXG4gKiBhbmQgYXBwZW5kZWQgdG8gdGhlIGxvZyBmaWxlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge2FueX0gYXJncyAtIEFuIGFycmF5IG9mIGFyZ3VtZW50cyB3aGVyZSB0aGUgZmlyc3QgaXMgdGhlIGxvZyBsZXZlbFxyXG4gKiBhbmQgdGhlIHJlc3QgYXJlIHN0cmluZ3MgdG8gYnVpbGQgYSBtZXNzYWdlIHdpdGguXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbG9nID0gKC4uLmFyZ3MpID0+IHtcclxuICBjb25zdCBbbmV3TGV2ZWwsIC4uLnRleHRzXSA9IGFyZ3M7XHJcblxyXG4gIC8vIEN1cnJlbnQgbG9nZ2luZyBvcHRpb25zXHJcbiAgY29uc3QgeyBsZXZlbCwgbGV2ZWxzRGVzYyB9ID0gbG9nZ2luZztcclxuXHJcbiAgLy8gQ2hlY2sgaWYgbG9nIGxldmVsIGlzIHdpdGhpbiBhIGNvcnJlY3QgcmFuZ2Ugb3IgaXMgYSBiZW5jaG1hcmsgbG9nXHJcbiAgaWYgKFxyXG4gICAgbmV3TGV2ZWwgIT09IDUgJiZcclxuICAgIChuZXdMZXZlbCA9PT0gMCB8fCBuZXdMZXZlbCA+IGxldmVsIHx8IGxldmVsID4gbGV2ZWxzRGVzYy5sZW5ndGgpXHJcbiAgKSB7XHJcbiAgICByZXR1cm47XHJcbiAgfVxyXG5cclxuICAvLyBHZXQgcmlkIG9mIHRoZSBHTVQgdGV4dCBpbmZvcm1hdGlvblxyXG4gIGNvbnN0IG5ld0RhdGUgPSBuZXcgRGF0ZSgpLnRvU3RyaW5nKCkuc3BsaXQoJygnKVswXS50cmltKCk7XHJcblxyXG4gIC8vIENyZWF0ZSBhIG1lc3NhZ2UncyBwcmVmaXhcclxuICBjb25zdCBwcmVmaXggPSBgJHtuZXdEYXRlfSBbJHtsZXZlbHNEZXNjW25ld0xldmVsIC0gMV0udGl0bGV9XSAtYDtcclxuXHJcbiAgLy8gQ2FsbCBhdmFpbGFibGUgbG9nIGxpc3RlbmVyc1xyXG4gIGxvZ2dpbmcubGlzdGVuZXJzLmZvckVhY2goKGZuKSA9PiB7XHJcbiAgICBmbihwcmVmaXgsIHRleHRzLmpvaW4oJyAnKSk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIExvZyB0byBjb25zb2xlXHJcbiAgaWYgKGxvZ2dpbmcudG9Db25zb2xlKSB7XHJcbiAgICBjb25zb2xlLmxvZy5hcHBseShcclxuICAgICAgdW5kZWZpbmVkLFxyXG4gICAgICBbcHJlZml4LnRvU3RyaW5nKClbbG9nZ2luZy5sZXZlbHNEZXNjW25ld0xldmVsIC0gMV0uY29sb3JdXS5jb25jYXQodGV4dHMpXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgLy8gTG9nIHRvIGZpbGVcclxuICBsb2dUb0ZpbGUodGV4dHMsIHByZWZpeCk7XHJcbn07XHJcblxyXG4vKipcclxuICogTG9ncyBhbiBlcnJvciBtZXNzYWdlIHdpdGggaXRzIHN0YWNrIHRyYWNlLiBPcHRpb25hbGx5LCBhIGN1c3RvbSBtZXNzYWdlXHJcbiAqIGNhbiBiZSBwcm92aWRlZC5cclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IGxldmVsIC0gVGhlIGxvZyBsZXZlbC5cclxuICogQHBhcmFtIHtFcnJvcn0gZXJyb3IgLSBUaGUgZXJyb3Igb2JqZWN0LlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY3VzdG9tTWVzc2FnZSAtIEFuIG9wdGlvbmFsIGN1c3RvbSBtZXNzYWdlIHRvIGJlIGxvZ2dlZCBhbG9uZ1xyXG4gKiB3aXRoIHRoZSBlcnJvci5cclxuICovXHJcbmV4cG9ydCBjb25zdCBsb2dXaXRoU3RhY2sgPSAobmV3TGV2ZWwsIGVycm9yLCBjdXN0b21NZXNzYWdlKSA9PiB7XHJcbiAgLy8gR2V0IHRoZSBtYWluIG1lc3NhZ2VcclxuICBjb25zdCBtYWluTWVzc2FnZSA9IGN1c3RvbU1lc3NhZ2UgfHwgZXJyb3IubWVzc2FnZTtcclxuXHJcbiAgLy8gQ3VycmVudCBsb2dnaW5nIG9wdGlvbnNcclxuICBjb25zdCB7IGxldmVsLCBsZXZlbHNEZXNjIH0gPSBsb2dnaW5nO1xyXG5cclxuICAvLyBDaGVjayBpZiBsb2cgbGV2ZWwgaXMgd2l0aGluIGEgY29ycmVjdCByYW5nZVxyXG4gIGlmIChuZXdMZXZlbCA9PT0gMCB8fCBuZXdMZXZlbCA+IGxldmVsIHx8IGxldmVsID4gbGV2ZWxzRGVzYy5sZW5ndGgpIHtcclxuICAgIHJldHVybjtcclxuICB9XHJcblxyXG4gIC8vIEdldCByaWQgb2YgdGhlIEdNVCB0ZXh0IGluZm9ybWF0aW9uXHJcbiAgY29uc3QgbmV3RGF0ZSA9IG5ldyBEYXRlKCkudG9TdHJpbmcoKS5zcGxpdCgnKCcpWzBdLnRyaW0oKTtcclxuXHJcbiAgLy8gQ3JlYXRlIGEgbWVzc2FnZSdzIHByZWZpeFxyXG4gIGNvbnN0IHByZWZpeCA9IGAke25ld0RhdGV9IFske2xldmVsc0Rlc2NbbmV3TGV2ZWwgLSAxXS50aXRsZX1dIC1gO1xyXG5cclxuICAvLyBJZiB0aGUgY3VzdG9tTWVzc2FnZSBleGlzdHMsIHdlIHdhbnQgdG8gZGlzcGxheSB0aGUgd2hvbGUgc3RhY2sgbWVzc2FnZVxyXG4gIGNvbnN0IHN0YWNrTWVzc2FnZSA9XHJcbiAgICBlcnJvci5tZXNzYWdlICE9PSBlcnJvci5zdGFja01lc3NhZ2UgfHwgZXJyb3Iuc3RhY2tNZXNzYWdlID09PSB1bmRlZmluZWRcclxuICAgICAgPyBlcnJvci5zdGFja1xyXG4gICAgICA6IGVycm9yLnN0YWNrLnNwbGl0KCdcXG4nKS5zbGljZSgxKS5qb2luKCdcXG4nKTtcclxuXHJcbiAgLy8gQ29tYmluZSBjdXN0b20gbWVzc2FnZSBvciBlcnJvciBtZXNzYWdlIHdpdGggZXJyb3Igc3RhY2sgbWVzc2FnZVxyXG4gIGNvbnN0IHRleHRzID0gW21haW5NZXNzYWdlLCAnXFxuJywgc3RhY2tNZXNzYWdlXTtcclxuXHJcbiAgLy8gTG9nIHRvIGNvbnNvbGVcclxuICBpZiAobG9nZ2luZy50b0NvbnNvbGUpIHtcclxuICAgIGNvbnNvbGUubG9nLmFwcGx5KFxyXG4gICAgICB1bmRlZmluZWQsXHJcbiAgICAgIFtwcmVmaXgudG9TdHJpbmcoKVtsb2dnaW5nLmxldmVsc0Rlc2NbbmV3TGV2ZWwgLSAxXS5jb2xvcl1dLmNvbmNhdChbXHJcbiAgICAgICAgbWFpbk1lc3NhZ2VbY29sb3JzW25ld0xldmVsIC0gMV1dLFxyXG4gICAgICAgICdcXG4nLFxyXG4gICAgICAgIHN0YWNrTWVzc2FnZVxyXG4gICAgICBdKVxyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIC8vIENhbGwgYXZhaWxhYmxlIGxvZyBsaXN0ZW5lcnNcclxuICBsb2dnaW5nLmxpc3RlbmVycy5mb3JFYWNoKChmbikgPT4ge1xyXG4gICAgZm4ocHJlZml4LCB0ZXh0cy5qb2luKCcgJykpO1xyXG4gIH0pO1xyXG5cclxuICAvLyBMb2cgdG8gZmlsZVxyXG4gIGxvZ1RvRmlsZSh0ZXh0cywgcHJlZml4KTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBTZXRzIHRoZSBsb2cgbGV2ZWwgdG8gdGhlIHNwZWNpZmllZCB2YWx1ZS4gTG9nIGxldmVscyBhcmUgKDAgPSBubyBsb2dnaW5nLFxyXG4gKiAxID0gZXJyb3IsIDIgPSB3YXJuaW5nLCAzID0gbm90aWNlLCA0ID0gdmVyYm9zZSBvciA1ID0gYmVuY2htYXJrKVxyXG4gKlxyXG4gKiBAcGFyYW0ge251bWJlcn0gbmV3TGV2ZWwgLSBUaGUgbmV3IGxvZyBsZXZlbCB0byBiZSBzZXQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2V0TG9nTGV2ZWwgPSAobmV3TGV2ZWwpID0+IHtcclxuICBpZiAobmV3TGV2ZWwgPj0gMCAmJiBuZXdMZXZlbCA8PSBsb2dnaW5nLmxldmVsc0Rlc2MubGVuZ3RoKSB7XHJcbiAgICBsb2dnaW5nLmxldmVsID0gbmV3TGV2ZWw7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEVuYWJsZXMgZmlsZSBsb2dnaW5nIHdpdGggdGhlIHNwZWNpZmllZCBkZXN0aW5hdGlvbiBhbmQgbG9nIGZpbGUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBsb2dEZXN0IC0gVGhlIGRlc3RpbmF0aW9uIHBhdGggZm9yIGxvZyBmaWxlcy5cclxuICogQHBhcmFtIHtzdHJpbmd9IGxvZ0ZpbGUgLSBUaGUgbG9nIGZpbGUgbmFtZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBlbmFibGVGaWxlTG9nZ2luZyA9IChsb2dEZXN0LCBsb2dGaWxlKSA9PiB7XHJcbiAgLy8gVXBkYXRlIGxvZ2dpbmcgb3B0aW9uc1xyXG4gIGxvZ2dpbmcgPSB7XHJcbiAgICAuLi5sb2dnaW5nLFxyXG4gICAgZGVzdDogbG9nRGVzdCB8fCBsb2dnaW5nLmRlc3QsXHJcbiAgICBmaWxlOiBsb2dGaWxlIHx8IGxvZ2dpbmcuZmlsZSxcclxuICAgIHRvRmlsZTogdHJ1ZVxyXG4gIH07XHJcblxyXG4gIGlmIChsb2dnaW5nLmRlc3QubGVuZ3RoID09PSAwKSB7XHJcbiAgICByZXR1cm4gbG9nKDEsICdbbG9nZ2VyXSBGaWxlIGxvZ2dpbmcgaW5pdGlhbGl6YXRpb246IG5vIHBhdGggc3VwcGxpZWQuJyk7XHJcbiAgfVxyXG5cclxuICBpZiAoIWxvZ2dpbmcuZGVzdC5lbmRzV2l0aCgnLycpKSB7XHJcbiAgICBsb2dnaW5nLmRlc3QgKz0gJy8nO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyBsb2dnaW5nIHdpdGggdGhlIHNwZWNpZmllZCBsb2dnaW5nIGNvbmZpZ3VyYXRpb24uXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBsb2dnaW5nIC0gVGhlIGxvZ2dpbmcgY29uZmlndXJhdGlvbiBvYmplY3QuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaW5pdExvZ2dpbmcgPSAobG9nZ2luZykgPT4ge1xyXG4gIC8vIFNldCB0aGUgbG9nIGxldmVsXHJcbiAgc2V0TG9nTGV2ZWwobG9nZ2luZyAmJiBwYXJzZUludChsb2dnaW5nLmxldmVsKSk7XHJcblxyXG4gIC8vIFNldCB0aGUgbG9nIGZpbGUgcGF0aCBhbmQgbmFtZVxyXG4gIGlmIChsb2dnaW5nICYmIGxvZ2dpbmcuZGVzdCkge1xyXG4gICAgZW5hYmxlRmlsZUxvZ2dpbmcoXHJcbiAgICAgIGxvZ2dpbmcuZGVzdCxcclxuICAgICAgbG9nZ2luZy5maWxlIHx8ICdoaWdoY2hhcnRzLWV4cG9ydC1zZXJ2ZXIubG9nJ1xyXG4gICAgKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogQWRkcyBhIGxpc3RlbmVyIGZ1bmN0aW9uIHRvIHRoZSBsb2dnaW5nIHN5c3RlbS5cclxuICpcclxuICogQHBhcmFtIHtmdW5jdGlvbn0gZm4gLSBUaGUgbGlzdGVuZXIgZnVuY3Rpb24gdG8gYmUgYWRkZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbGlzdGVuID0gKGZuKSA9PiB7XHJcbiAgbG9nZ2luZy5saXN0ZW5lcnMucHVzaChmbik7XHJcbn07XHJcblxyXG4vKipcclxuICogVG9nZ2xlcyB0aGUgc3RhbmRhcmQgb3V0cHV0IChjb25zb2xlKSBsb2dnaW5nLlxyXG4gKlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGVuYWJsZWQgLSBJZiB0cnVlLCBlbmFibGVzIGNvbnNvbGUgbG9nZ2luZzsgaWYgZmFsc2UsXHJcbiAqIGRpc2FibGVzIGl0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHRvZ2dsZVNURE91dCA9IChlbmFibGVkKSA9PiB7XHJcbiAgbG9nZ2luZy50b0NvbnNvbGUgPSBlbmFibGVkO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGxvZyxcclxuICBsb2dXaXRoU3RhY2ssXHJcbiAgc2V0TG9nTGV2ZWwsXHJcbiAgZW5hYmxlRmlsZUxvZ2dpbmcsXHJcbiAgaW5pdExvZ2dpbmcsXHJcbiAgbGlzdGVuLFxyXG4gIHRvZ2dsZVNURE91dFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5pbXBvcnQgeyBmaWxlVVJMVG9QYXRoIH0gZnJvbSAndXJsJztcclxuXHJcbmltcG9ydCB7IGRlZmF1bHRDb25maWcgfSBmcm9tICcuLi9saWIvc2NoZW1hcy9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuXHJcbmNvbnN0IE1BWF9CQUNLT0ZGX0FUVEVNUFRTID0gNjtcclxuXHJcbmV4cG9ydCBjb25zdCBfX2Rpcm5hbWUgPSBmaWxlVVJMVG9QYXRoKG5ldyBVUkwoJy4uLy4nLCBpbXBvcnQubWV0YS51cmwpKTtcclxuXHJcbi8qKlxyXG4gKiBDbGVhcnMgYW5kIHN0YW5kYXJkaXplcyB0ZXh0IGJ5IHJlcGxhY2luZyBtdWx0aXBsZSBjb25zZWN1dGl2ZSB3aGl0ZXNwYWNlXHJcbiAqIGNoYXJhY3RlcnMgd2l0aCBhIHNpbmdsZSBzcGFjZSBhbmQgdHJpbW1pbmcgYW55IGxlYWRpbmcgb3IgdHJhaWxpbmdcclxuICogd2hpdGVzcGFjZS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHRleHQgLSBUaGUgaW5wdXQgdGV4dCB0byBiZSBjbGVhcmVkLlxyXG4gKiBAcGFyYW0ge1JlZ0V4cH0gW3J1bGU9L1xcc1xccysvZ10gLSBUaGUgcmVndWxhciBleHByZXNzaW9uIHJ1bGUgdG8gbWF0Y2hcclxuICogbXVsdGlwbGUgY29uc2VjdXRpdmUgd2hpdGVzcGFjZSBjaGFyYWN0ZXJzLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gW3JlcGxhY2VyPScgJ10gLSBUaGUgc3RyaW5nIHVzZWQgdG8gcmVwbGFjZSBtdWx0aXBsZVxyXG4gKiBjb25zZWN1dGl2ZSB3aGl0ZXNwYWNlIGNoYXJhY3RlcnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IC0gVGhlIGNsZWFyZWQgYW5kIHN0YW5kYXJkaXplZCB0ZXh0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGNsZWFyVGV4dCA9ICh0ZXh0LCBydWxlID0gL1xcc1xccysvZywgcmVwbGFjZXIgPSAnICcpID0+XHJcbiAgdGV4dC5yZXBsYWNlQWxsKHJ1bGUsIHJlcGxhY2VyKS50cmltKCk7XHJcblxyXG4vKipcclxuICogSW1wbGVtZW50cyBhbiBleHBvbmVudGlhbCBiYWNrb2ZmIHN0cmF0ZWd5IGZvciByZXRyeWluZyBhIGZ1bmN0aW9uIHVudGlsXHJcbiAqIGEgY2VydGFpbiBudW1iZXIgb2YgYXR0ZW1wdHMgYXJlIHJlYWNoZWQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGZuIC0gVGhlIGZ1bmN0aW9uIHRvIGJlIHJldHJpZWQuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBbYXR0ZW1wdD0wXSAtIFRoZSBjdXJyZW50IGF0dGVtcHQgbnVtYmVyLlxyXG4gKiBAcGFyYW0gey4uLmFueX0gYXJncyAtIEFyZ3VtZW50cyB0byBiZSBwYXNzZWQgdG8gdGhlIGZ1bmN0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZX0gLSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgcmVzdWx0IG9mIHRoZSBmdW5jdGlvblxyXG4gKiBpZiBzdWNjZXNzZnVsLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFcnJvcn0gLSBUaHJvd3MgYW4gZXJyb3IgaWYgdGhlIG1heGltdW0gbnVtYmVyIG9mIGF0dGVtcHRzXHJcbiAqIGlzIHJlYWNoZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZXhwQmFja29mZiA9IGFzeW5jIChmbiwgYXR0ZW1wdCA9IDAsIC4uLmFyZ3MpID0+IHtcclxuICB0cnkge1xyXG4gICAgLy8gVHJ5IHRvIGNhbGwgdGhlIGZ1bmN0aW9uXHJcbiAgICByZXR1cm4gYXdhaXQgZm4oLi4uYXJncyk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIC8vIENhbGN1bGF0ZSBkZWxheSBpbiBtc1xyXG4gICAgY29uc3QgZGVsYXlJbk1zID0gMiAqKiBhdHRlbXB0ICogMTAwMDtcclxuXHJcbiAgICAvLyBJZiB0aGUgYXR0ZW1wdCBleGNlZWRzIHRoZSBtYXhpbXVtIGF0dGVtcHRzIG9mIHJlYXBlYXQsIHRocm93IGFuIGVycm9yXHJcbiAgICBpZiAoKythdHRlbXB0ID49IE1BWF9CQUNLT0ZGX0FUVEVNUFRTKSB7XHJcbiAgICAgIHRocm93IGVycm9yO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFdhaXQgZ2l2ZW4gYW1vdW50IG9mIHRpbWVcclxuICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNwb25zZSkgPT4gc2V0VGltZW91dChyZXNwb25zZSwgZGVsYXlJbk1zKSk7XHJcbiAgICBsb2coXHJcbiAgICAgIDMsXHJcbiAgICAgIGBbcG9vbF0gV2FpdGVkICR7ZGVsYXlJbk1zfW1zIHVudGlsIG5leHQgY2FsbCBmb3IgdGhlIHJlc291cmNlIGlkOiAke2FyZ3NbMF19LmBcclxuICAgICk7XHJcblxyXG4gICAgLy8gVHJ5IGFnYWluXHJcbiAgICByZXR1cm4gZXhwQmFja29mZihmbiwgYXR0ZW1wdCwgLi4uYXJncyk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEZpeGVzIHRoZSBleHBvcnQgdHlwZSBiYXNlZCBvbiBNSU1FIHR5cGVzIGFuZCBmaWxlIGV4dGVuc2lvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIC0gVGhlIG9yaWdpbmFsIGV4cG9ydCB0eXBlLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gb3V0ZmlsZSAtIFRoZSBmaWxlIHBhdGggb3IgbmFtZS5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gLSBUaGUgY29ycmVjdGVkIGV4cG9ydCB0eXBlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGZpeFR5cGUgPSAodHlwZSwgb3V0ZmlsZSkgPT4ge1xyXG4gIC8vIE1JTUUgdHlwZXNcclxuICBjb25zdCBtaW1lVHlwZXMgPSB7XHJcbiAgICAnaW1hZ2UvcG5nJzogJ3BuZycsXHJcbiAgICAnaW1hZ2UvanBlZyc6ICdqcGVnJyxcclxuICAgICdhcHBsaWNhdGlvbi9wZGYnOiAncGRmJyxcclxuICAgICdpbWFnZS9zdmcreG1sJzogJ3N2ZydcclxuICB9O1xyXG5cclxuICAvLyBGb3JtYXRzXHJcbiAgY29uc3QgZm9ybWF0cyA9IFsncG5nJywgJ2pwZWcnLCAncGRmJywgJ3N2ZyddO1xyXG5cclxuICAvLyBDaGVjayBpZiB0eXBlIGFuZCBvdXRmaWxlJ3MgZXh0ZW5zaW9ucyBhcmUgdGhlIHNhbWVcclxuICBpZiAob3V0ZmlsZSkge1xyXG4gICAgY29uc3Qgb3V0VHlwZSA9IG91dGZpbGUuc3BsaXQoJy4nKS5wb3AoKTtcclxuXHJcbiAgICBpZiAob3V0VHlwZSA9PT0gJ2pwZycpIHtcclxuICAgICAgdHlwZSA9ICdqcGVnJztcclxuICAgIH0gZWxzZSBpZiAoZm9ybWF0cy5pbmNsdWRlcyhvdXRUeXBlKSAmJiB0eXBlICE9PSBvdXRUeXBlKSB7XHJcbiAgICAgIHR5cGUgPSBvdXRUeXBlO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIGEgY29ycmVjdCB0eXBlXHJcbiAgcmV0dXJuIG1pbWVUeXBlc1t0eXBlXSB8fCBmb3JtYXRzLmZpbmQoKHQpID0+IHQgPT09IHR5cGUpIHx8ICdwbmcnO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEhhbmRsZXMgYW5kIHZhbGlkYXRlcyByZXNvdXJjZXMgZm9yIGV4cG9ydC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R8c3RyaW5nfSByZXNvdXJjZXMgLSBUaGUgcmVzb3VyY2VzIHRvIGJlIGhhbmRsZWQuIENhbiBiZSBlaXRoZXJcclxuICogYSBKU09OIG9iamVjdCwgc3RyaW5naWZpZWQgSlNPTiBvciBhIHBhdGggdG8gYSBKU09OIGZpbGUuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gYWxsb3dGaWxlUmVzb3VyY2VzIC0gV2hldGhlciB0byBhbGxvdyBsb2FkaW5nIHJlc291cmNlcyBmcm9tXHJcbiAqIGZpbGVzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fHVuZGVmaW5lZH0gLSBUaGUgaGFuZGxlZCByZXNvdXJjZXMgb3IgdW5kZWZpbmVkIGlmIG5vIHZhbGlkXHJcbiAqIHJlc291cmNlcyBhcmUgZm91bmQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaGFuZGxlUmVzb3VyY2VzID0gKHJlc291cmNlcyA9IGZhbHNlLCBhbGxvd0ZpbGVSZXNvdXJjZXMpID0+IHtcclxuICBjb25zdCBhbGxvd2VkUHJvcHMgPSBbJ2pzJywgJ2NzcycsICdmaWxlcyddO1xyXG5cclxuICBsZXQgaGFuZGxlZFJlc291cmNlcyA9IHJlc291cmNlcztcclxuICBsZXQgY29ycmVjdFJlc291cmNlcyA9IGZhbHNlO1xyXG5cclxuICAvLyBUcnkgdG8gbG9hZCByZXNvdXJjZXMgZnJvbSBhIGZpbGVcclxuICBpZiAoYWxsb3dGaWxlUmVzb3VyY2VzICYmIHJlc291cmNlcy5lbmRzV2l0aCgnLmpzb24nKSkge1xyXG4gICAgdHJ5IHtcclxuICAgICAgaGFuZGxlZFJlc291cmNlcyA9IGlzQ29ycmVjdEpTT04ocmVhZEZpbGVTeW5jKHJlc291cmNlcywgJ3V0ZjgnKSk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICByZXR1cm4gbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2NsaV0gTm8gcmVzb3VyY2VzIGZvdW5kLmApO1xyXG4gICAgfVxyXG4gIH0gZWxzZSB7XHJcbiAgICAvLyBUcnkgdG8gZ2V0IEpTT05cclxuICAgIGhhbmRsZWRSZXNvdXJjZXMgPSBpc0NvcnJlY3RKU09OKHJlc291cmNlcyk7XHJcblxyXG4gICAgLy8gR2V0IHJpZCBvZiB0aGUgZmlsZXMgc2VjdGlvblxyXG4gICAgaWYgKGhhbmRsZWRSZXNvdXJjZXMgJiYgIWFsbG93RmlsZVJlc291cmNlcykge1xyXG4gICAgICBkZWxldGUgaGFuZGxlZFJlc291cmNlcy5maWxlcztcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIEZpbHRlciBmcm9tIHVubmVjZXNzYXJ5IHByb3BlcnRpZXNcclxuICBmb3IgKGNvbnN0IHByb3BOYW1lIGluIGhhbmRsZWRSZXNvdXJjZXMpIHtcclxuICAgIGlmICghYWxsb3dlZFByb3BzLmluY2x1ZGVzKHByb3BOYW1lKSkge1xyXG4gICAgICBkZWxldGUgaGFuZGxlZFJlc291cmNlc1twcm9wTmFtZV07XHJcbiAgICB9IGVsc2UgaWYgKCFjb3JyZWN0UmVzb3VyY2VzKSB7XHJcbiAgICAgIGNvcnJlY3RSZXNvdXJjZXMgPSB0cnVlO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gQ2hlY2sgaWYgYXQgbGVhc3Qgb25lIG9mIGFsbG93ZWQgcHJvcGVydGllcyBpcyBwcmVzZW50XHJcbiAgaWYgKCFjb3JyZWN0UmVzb3VyY2VzKSB7XHJcbiAgICByZXR1cm4gbG9nKDMsIGBbY2xpXSBObyByZXNvdXJjZXMgZm91bmQuYCk7XHJcbiAgfVxyXG5cclxuICAvLyBIYW5kbGUgZmlsZXMgc2VjdGlvblxyXG4gIGlmIChoYW5kbGVkUmVzb3VyY2VzLmZpbGVzKSB7XHJcbiAgICBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzID0gaGFuZGxlZFJlc291cmNlcy5maWxlcy5tYXAoKGl0ZW0pID0+IGl0ZW0udHJpbSgpKTtcclxuICAgIGlmICghaGFuZGxlZFJlc291cmNlcy5maWxlcyB8fCBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzLmxlbmd0aCA8PSAwKSB7XHJcbiAgICAgIGRlbGV0ZSBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIHJlc291cmNlc1xyXG4gIHJldHVybiBoYW5kbGVkUmVzb3VyY2VzO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFZhbGlkYXRlcyBhbmQgcGFyc2VzIEpTT04gZGF0YS4gQ2hlY2tzIGlmIHByb3ZpZGVkIGRhdGEgaXMgb3IgY2FuXHJcbiAqIGJlIGEgY29ycmVjdCBKU09OLiBJZiBhIHByaW1pdGl2ZSBpcyBwcm92aWRlZCwgaXQgaXMgc3RyaW5naWZpZWQgYW5kIHJldHVybmVkLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdHxzdHJpbmd9IGRhdGEgLSBUaGUgSlNPTiBkYXRhIHRvIGJlIHZhbGlkYXRlZCBhbmQgcGFyc2VkLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IHRvU3RyaW5nIC0gV2hldGhlciB0byByZXR1cm4gYSBzdHJpbmdpZmllZCByZXByZXNlbnRhdGlvblxyXG4gKiBvZiB0aGUgcGFyc2VkIEpTT04uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R8c3RyaW5nfGJvb2xlYW59IC0gVGhlIHBhcnNlZCBKU09OIG9iamVjdCwgc3RyaW5naWZpZWQgSlNPTixcclxuICogb3IgZmFsc2UgaWYgdmFsaWRhdGlvbiBmYWlscy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBpc0NvcnJlY3RKU09OKGRhdGEsIHRvU3RyaW5nKSB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIEdldCB0aGUgc3RyaW5nIHJlcHJlc2VudGF0aW9uIGlmIG5vdCBhbHJlYWR5IGJlZm9yZSBwYXJzaW5nXHJcbiAgICBjb25zdCBwYXJzZWREYXRhID0gSlNPTi5wYXJzZShcclxuICAgICAgdHlwZW9mIGRhdGEgIT09ICdzdHJpbmcnID8gSlNPTi5zdHJpbmdpZnkoZGF0YSkgOiBkYXRhXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFJldHVybiBhIHN0cmluZ2lmaWVkIHJlcHJlc2VudGF0aW9uIG9mIGEgSlNPTiBpZiByZXF1aXJlZFxyXG4gICAgaWYgKHR5cGVvZiBwYXJzZWREYXRhICE9PSAnc3RyaW5nJyAmJiB0b1N0cmluZykge1xyXG4gICAgICByZXR1cm4gSlNPTi5zdHJpbmdpZnkocGFyc2VkRGF0YSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmV0dXJuIGEgSlNPTlxyXG4gICAgcmV0dXJuIHBhcnNlZERhdGE7XHJcbiAgfSBjYXRjaCB7XHJcbiAgICByZXR1cm4gZmFsc2U7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogQ2hlY2tzIGlmIHRoZSBnaXZlbiBpdGVtIGlzIGFuIG9iamVjdC5cclxuICpcclxuICogQHBhcmFtIHthbnl9IGl0ZW0gLSBUaGUgaXRlbSB0byBiZSBjaGVja2VkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBUcnVlIGlmIHRoZSBpdGVtIGlzIGFuIG9iamVjdCwgZmFsc2Ugb3RoZXJ3aXNlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGlzT2JqZWN0ID0gKGl0ZW0pID0+XHJcbiAgdHlwZW9mIGl0ZW0gPT09ICdvYmplY3QnICYmICFBcnJheS5pc0FycmF5KGl0ZW0pICYmIGl0ZW0gIT09IG51bGw7XHJcblxyXG4vKipcclxuICogQ2hlY2tzIGlmIHRoZSBnaXZlbiBvYmplY3QgaXMgZW1wdHkuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBpdGVtIC0gVGhlIG9iamVjdCB0byBiZSBjaGVja2VkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBUcnVlIGlmIHRoZSBvYmplY3QgaXMgZW1wdHksIGZhbHNlIG90aGVyd2lzZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBpc09iamVjdEVtcHR5ID0gKGl0ZW0pID0+XHJcbiAgdHlwZW9mIGl0ZW0gPT09ICdvYmplY3QnICYmXHJcbiAgIUFycmF5LmlzQXJyYXkoaXRlbSkgJiZcclxuICBpdGVtICE9PSBudWxsICYmXHJcbiAgT2JqZWN0LmtleXMoaXRlbSkubGVuZ3RoID09PSAwO1xyXG5cclxuLyoqXHJcbiAqIENoZWNrcyBpZiBhIHByaXZhdGUgSVAgcmFuZ2UgVVJMIGlzIGZvdW5kIGluIHRoZSBnaXZlbiBzdHJpbmcuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBpdGVtIC0gVGhlIHN0cmluZyB0byBiZSBjaGVja2VkIGZvciBhIHByaXZhdGUgSVAgcmFuZ2UgVVJMLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBUcnVlIGlmIGEgcHJpdmF0ZSBJUCByYW5nZSBVUkwgaXMgZm91bmQsIGZhbHNlXHJcbiAqIG90aGVyd2lzZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBpc1ByaXZhdGVSYW5nZVVybEZvdW5kID0gKGl0ZW0pID0+IHtcclxuICBjb25zdCByZWdleFBhdHRlcm5zID0gW1xyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pP2xvY2FsaG9zdFxcYi8sXHJcbiAgICAveGxpbms6aHJlZj1cIig/Omh0dHA6XFwvXFwvfGh0dHBzOlxcL1xcLyk/MTBcXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvLFxyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pPzEyN1xcLlxcZHsxLDN9XFwuXFxkezEsM31cXC5cXGR7MSwzfVxcYi8sXHJcbiAgICAveGxpbms6aHJlZj1cIig/Omh0dHA6XFwvXFwvfGh0dHBzOlxcL1xcLyk/MTcyXFwuKDFbNi05XXwyWzAtOV18M1swLTFdKVxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvLFxyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pPzE5MlxcLjE2OFxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvXHJcbiAgXTtcclxuXHJcbiAgcmV0dXJuIHJlZ2V4UGF0dGVybnMuc29tZSgocGF0dGVybikgPT4gcGF0dGVybi50ZXN0KGl0ZW0pKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgZGVlcCBjb3B5IG9mIHRoZSBnaXZlbiBvYmplY3Qgb3IgYXJyYXkuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fEFycmF5fSBvYmogLSBUaGUgb2JqZWN0IG9yIGFycmF5IHRvIGJlIGRlZXBseSBjb3BpZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R8QXJyYXl9IC0gVGhlIGRlZXAgY29weSBvZiB0aGUgcHJvdmlkZWQgb2JqZWN0IG9yIGFycmF5LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGRlZXBDb3B5ID0gKG9iaikgPT4ge1xyXG4gIGlmIChvYmogPT09IG51bGwgfHwgdHlwZW9mIG9iaiAhPT0gJ29iamVjdCcpIHtcclxuICAgIHJldHVybiBvYmo7XHJcbiAgfVxyXG5cclxuICBjb25zdCBjb3B5ID0gQXJyYXkuaXNBcnJheShvYmopID8gW10gOiB7fTtcclxuXHJcbiAgZm9yIChjb25zdCBrZXkgaW4gb2JqKSB7XHJcbiAgICBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9iaiwga2V5KSkge1xyXG4gICAgICBjb3B5W2tleV0gPSBkZWVwQ29weShvYmpba2V5XSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICByZXR1cm4gY29weTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBDb252ZXJ0cyB0aGUgcHJvdmlkZWQgb3B0aW9ucyBvYmplY3QgdG8gYSBKU09OLWZvcm1hdHRlZCBzdHJpbmcgd2l0aCB0aGVcclxuICogb3B0aW9uIHRvIHByZXNlcnZlIGZ1bmN0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgb3B0aW9ucyBvYmplY3QgdG8gYmUgY29udmVydGVkIHRvIGEgc3RyaW5nLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RnVuY3Rpb25zIC0gSWYgc2V0IHRvIHRydWUsIGZ1bmN0aW9ucyBhcmUgcHJlc2VydmVkXHJcbiAqIGluIHRoZSBvdXRwdXQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IC0gVGhlIEpTT04tZm9ybWF0dGVkIHN0cmluZyByZXByZXNlbnRpbmcgdGhlIG9wdGlvbnMuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgb3B0aW9uc1N0cmluZ2lmeSA9IChvcHRpb25zLCBhbGxvd0Z1bmN0aW9ucykgPT4ge1xyXG4gIGNvbnN0IHJlcGxhY2VyQ2FsbGJhY2sgPSAobmFtZSwgdmFsdWUpID0+IHtcclxuICAgIGlmICh0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnKSB7XHJcbiAgICAgIHZhbHVlID0gdmFsdWUudHJpbSgpO1xyXG5cclxuICAgICAgLy8gSWYgYWxsb3dGdW5jdGlvbnMgaXMgc2V0IHRvIHRydWUsIHByZXNlcnZlIGZ1bmN0aW9uc1xyXG4gICAgICBpZiAoXHJcbiAgICAgICAgKHZhbHVlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uKCcpIHx8IHZhbHVlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uICgnKSkgJiZcclxuICAgICAgICB2YWx1ZS5lbmRzV2l0aCgnfScpXHJcbiAgICAgICkge1xyXG4gICAgICAgIHZhbHVlID0gYWxsb3dGdW5jdGlvbnNcclxuICAgICAgICAgID8gYEVYUF9GVU4keyh2YWx1ZSArICcnKS5yZXBsYWNlQWxsKC9cXG58XFx0fFxcci9nLCAnICcpfUVYUF9GVU5gXHJcbiAgICAgICAgICA6IHVuZGVmaW5lZDtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiB0eXBlb2YgdmFsdWUgPT09ICdmdW5jdGlvbidcclxuICAgICAgPyBgRVhQX0ZVTiR7KHZhbHVlICsgJycpLnJlcGxhY2VBbGwoL1xcbnxcXHR8XFxyL2csICcgJyl9RVhQX0ZVTmBcclxuICAgICAgOiB2YWx1ZTtcclxuICB9O1xyXG5cclxuICAvLyBTdHJpbmdpZnkgb3B0aW9ucyBhbmQgaWYgcmVxdWlyZWQsIHJlcGxhY2Ugc3BlY2lhbCBmdW5jdGlvbnMgbWFya3NcclxuICByZXR1cm4gSlNPTi5zdHJpbmdpZnkob3B0aW9ucywgcmVwbGFjZXJDYWxsYmFjaykucmVwbGFjZUFsbChcclxuICAgIC9cIkVYUF9GVU58RVhQX0ZVTlwiL2csXHJcbiAgICAnJ1xyXG4gICk7XHJcbn07XHJcblxyXG4vKipcclxuICogUHJpbnRzIHRoZSBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIgbG9nbyBhbmQgdmVyc2lvbiBpbmZvcm1hdGlvbi5cclxuICpcclxuICogQHBhcmFtIHtib29sZWFufSBub0xvZ28gLSBJZiB0cnVlLCBvbmx5IHByaW50cyB2ZXJzaW9uIGluZm9ybWF0aW9uIHdpdGhvdXRcclxuICogdGhlIGxvZ28uXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgcHJpbnRMb2dvID0gKG5vTG9nbykgPT4ge1xyXG4gIC8vIEdldCBwYWNrYWdlIHZlcnNpb24gZWl0aGVyIGZyb20gZW52IG9yIGZyb20gcGFja2FnZS5qc29uXHJcbiAgY29uc3QgcGFja2FnZVZlcnNpb24gPSBKU09OLnBhcnNlKFxyXG4gICAgcmVhZEZpbGVTeW5jKGpvaW4oX19kaXJuYW1lLCAncGFja2FnZS5qc29uJykpXHJcbiAgKS52ZXJzaW9uO1xyXG5cclxuICAvLyBQcmludCB0ZXh0IG9ubHlcclxuICBpZiAobm9Mb2dvKSB7XHJcbiAgICBjb25zb2xlLmxvZyhgU3RhcnRpbmcgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyIHYke3BhY2thZ2VWZXJzaW9ufS4uLmApO1xyXG4gICAgcmV0dXJuO1xyXG4gIH1cclxuXHJcbiAgLy8gUHJpbnQgdGhlIGxvZ29cclxuICBjb25zb2xlLmxvZyhcclxuICAgIHJlYWRGaWxlU3luYyhfX2Rpcm5hbWUgKyAnL21zZy9zdGFydHVwLm1zZycpLnRvU3RyaW5nKCkuYm9sZC55ZWxsb3csXHJcbiAgICBgdiR7cGFja2FnZVZlcnNpb259XFxuYC5ib2xkXHJcbiAgKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBQcmludHMgdGhlIHVzYWdlIGluZm9ybWF0aW9uIGZvciBDTEkgYXJndW1lbnRzLiBJZiByZXF1aXJlZCwgaXQgY2FuIGxpc3RcclxuICogcHJvcGVydGllcyByZWN1cnNpdmVseVxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHByaW50VXNhZ2UoKSB7XHJcbiAgY29uc3QgcGFkID0gNDg7XHJcbiAgY29uc3QgcmVhZG1lID0gJ2h0dHBzOi8vZ2l0aHViLmNvbS9oaWdoY2hhcnRzL25vZGUtZXhwb3J0LXNlcnZlciNyZWFkbWUnO1xyXG5cclxuICAvLyBEaXNwbGF5IHJlYWRtZSBpbmZvcm1hdGlvblxyXG4gIGNvbnNvbGUubG9nKFxyXG4gICAgJ1xcblVzYWdlIG9mIENMSSBhcmd1bWVudHM6Jy5ib2xkLFxyXG4gICAgJ1xcbi0tLS0tLScsXHJcbiAgICBgXFxuRm9yIG1vcmUgZGV0YWlsZWQgaW5mb3JtYXRpb24sIHZpc2l0IHRoZSByZWFkbWUgYXQ6ICR7cmVhZG1lLmJvbGQueWVsbG93fS5gXHJcbiAgKTtcclxuXHJcbiAgY29uc3QgY3ljbGVDYXRlZ29yaWVzID0gKG9wdGlvbnMpID0+IHtcclxuICAgIGZvciAoY29uc3QgW25hbWUsIG9wdGlvbl0gb2YgT2JqZWN0LmVudHJpZXMob3B0aW9ucykpIHtcclxuICAgICAgLy8gSWYgY2F0ZWdvcnkgaGFzIG1vcmUgbGV2ZWxzLCBnbyBmdXJ0aGVyXHJcbiAgICAgIGlmICghT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9wdGlvbiwgJ3ZhbHVlJykpIHtcclxuICAgICAgICBjeWNsZUNhdGVnb3JpZXMob3B0aW9uKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBsZXQgZGVzY05hbWUgPSBgICAtLSR7b3B0aW9uLmNsaU5hbWUgfHwgbmFtZX0gJHtcclxuICAgICAgICAgICgnPCcgKyBvcHRpb24udHlwZSArICc+JykuZ3JlZW5cclxuICAgICAgICB9IGA7XHJcbiAgICAgICAgaWYgKGRlc2NOYW1lLmxlbmd0aCA8IHBhZCkge1xyXG4gICAgICAgICAgZm9yIChsZXQgaSA9IGRlc2NOYW1lLmxlbmd0aDsgaSA8IHBhZDsgaSsrKSB7XHJcbiAgICAgICAgICAgIGRlc2NOYW1lICs9ICcuJztcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIERpc3BsYXkgY29ycmVjdGx5IGFsaWduZWQgbWVzc2FnZXNcclxuICAgICAgICBjb25zb2xlLmxvZyhcclxuICAgICAgICAgIGRlc2NOYW1lLFxyXG4gICAgICAgICAgb3B0aW9uLmRlc2NyaXB0aW9uLFxyXG4gICAgICAgICAgYFtEZWZhdWx0OiAke29wdGlvbi52YWx1ZS50b1N0cmluZygpLmJvbGR9XWAuYmx1ZVxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9O1xyXG5cclxuICAvLyBDeWNsZSB0aHJvdWdoIG9wdGlvbnMgb2YgZWFjaCBjYXRlZ29yaWVzIGFuZCBkaXNwbGF5IHRoZSB1c2FnZSBpbmZvXHJcbiAgT2JqZWN0LmtleXMoZGVmYXVsdENvbmZpZykuZm9yRWFjaCgoY2F0ZWdvcnkpID0+IHtcclxuICAgIC8vIE9ubHkgcHVwcGV0ZWVyIGFuZCBoaWdoY2hhcnRzIGNhdGVnb3JpZXMgY2Fubm90IGJlIGNvbmZpZ3VyZWQgdGhyb3VnaCBDTElcclxuICAgIGlmICghWydwdXBwZXRlZXInLCAnaGlnaGNoYXJ0cyddLmluY2x1ZGVzKGNhdGVnb3J5KSkge1xyXG4gICAgICBjb25zb2xlLmxvZyhgXFxuJHtjYXRlZ29yeS50b1VwcGVyQ2FzZSgpfWAucmVkKTtcclxuICAgICAgY3ljbGVDYXRlZ29yaWVzKGRlZmF1bHRDb25maWdbY2F0ZWdvcnldKTtcclxuICAgIH1cclxuICB9KTtcclxuICBjb25zb2xlLmxvZygnXFxuJyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSb3VuZHMgYSBudW1iZXIgdG8gdGhlIHNwZWNpZmllZCBwcmVjaXNpb24uXHJcbiAqXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSB2YWx1ZSAtIFRoZSBudW1iZXIgdG8gYmUgcm91bmRlZC5cclxuICogQHBhcmFtIHtudW1iZXJ9IHByZWNpc2lvbiAtIFRoZSBudW1iZXIgb2YgZGVjaW1hbCBwbGFjZXMgdG8gcm91bmQgdG8uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtudW1iZXJ9IC0gVGhlIHJvdW5kZWQgbnVtYmVyLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHJvdW5kTnVtYmVyID0gKHZhbHVlLCBwcmVjaXNpb24gPSAxKSA9PiB7XHJcbiAgY29uc3QgbXVsdGlwbGllciA9IE1hdGgucG93KDEwLCBwcmVjaXNpb24gfHwgMCk7XHJcbiAgcmV0dXJuIE1hdGgucm91bmQoK3ZhbHVlICogbXVsdGlwbGllcikgLyBtdWx0aXBsaWVyO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIENvbnZlcnRzIGEgdmFsdWUgdG8gYSBib29sZWFuLlxyXG4gKlxyXG4gKiBAcGFyYW0ge2FueX0gaXRlbSAtIFRoZSB2YWx1ZSB0byBiZSBjb252ZXJ0ZWQgdG8gYSBib29sZWFuLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBUaGUgYm9vbGVhbiByZXByZXNlbnRhdGlvbiBvZiB0aGUgaW5wdXQgdmFsdWUuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgdG9Cb29sZWFuID0gKGl0ZW0pID0+XHJcbiAgWydmYWxzZScsICd1bmRlZmluZWQnLCAnbnVsbCcsICdOYU4nLCAnMCcsICcnXS5pbmNsdWRlcyhpdGVtKVxyXG4gICAgPyBmYWxzZVxyXG4gICAgOiAhIWl0ZW07XHJcblxyXG4vKipcclxuICogV3JhcHMgY3VzdG9tIGNvZGUgdG8gZXhlY3V0ZSBpdCBzYWZlbHkuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBjdXN0b21Db2RlIC0gVGhlIGN1c3RvbSBjb2RlIHRvIGJlIHdyYXBwZWQuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gYWxsb3dGaWxlUmVzb3VyY2VzIC0gRmxhZyB0byBhbGxvdyBsb2FkaW5nIGNvZGUgZnJvbSBhIGZpbGUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd8Ym9vbGVhbn0gLSBUaGUgd3JhcHBlZCBjdXN0b20gY29kZSBvciBmYWxzZSBpZiB3cmFwcGluZ1xyXG4gKiBmYWlscy5cclxuICovXHJcbmV4cG9ydCBjb25zdCB3cmFwQXJvdW5kID0gKGN1c3RvbUNvZGUsIGFsbG93RmlsZVJlc291cmNlcykgPT4ge1xyXG4gIGlmIChjdXN0b21Db2RlICYmIHR5cGVvZiBjdXN0b21Db2RlID09PSAnc3RyaW5nJykge1xyXG4gICAgY3VzdG9tQ29kZSA9IGN1c3RvbUNvZGUudHJpbSgpO1xyXG5cclxuICAgIGlmIChjdXN0b21Db2RlLmVuZHNXaXRoKCcuanMnKSkge1xyXG4gICAgICByZXR1cm4gYWxsb3dGaWxlUmVzb3VyY2VzXHJcbiAgICAgICAgPyB3cmFwQXJvdW5kKHJlYWRGaWxlU3luYyhjdXN0b21Db2RlLCAndXRmOCcpKVxyXG4gICAgICAgIDogZmFsc2U7XHJcbiAgICB9IGVsc2UgaWYgKFxyXG4gICAgICBjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uKCknKSB8fFxyXG4gICAgICBjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uICgpJykgfHxcclxuICAgICAgY3VzdG9tQ29kZS5zdGFydHNXaXRoKCcoKT0+JykgfHxcclxuICAgICAgY3VzdG9tQ29kZS5zdGFydHNXaXRoKCcoKSA9PicpXHJcbiAgICApIHtcclxuICAgICAgcmV0dXJuIGAoJHtjdXN0b21Db2RlfSkoKWA7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gY3VzdG9tQ29kZS5yZXBsYWNlKC87JC8sICcnKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogVXRpbGl0eSB0byBtZWFzdXJlIGVsYXBzZWQgdGltZSB1c2luZyB0aGUgTm9kZS5qcyBwcm9jZXNzLmhydGltZSgpIG1ldGhvZC5cclxuICpcclxuICogQHJldHVybnMge2Z1bmN0aW9uKCk6IG51bWJlcn0gLSBBIGZ1bmN0aW9uIHRvIGNhbGN1bGF0ZSB0aGUgZWxhcHNlZCB0aW1lXHJcbiAqIGluIG1pbGxpc2Vjb25kcy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBtZWFzdXJlVGltZSA9ICgpID0+IHtcclxuICBjb25zdCBzdGFydCA9IHByb2Nlc3MuaHJ0aW1lLmJpZ2ludCgpO1xyXG4gIHJldHVybiAoKSA9PiBOdW1iZXIocHJvY2Vzcy5ocnRpbWUuYmlnaW50KCkgLSBzdGFydCkgLyAxMDAwMDAwO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIF9fZGlybmFtZSxcclxuICBjbGVhclRleHQsXHJcbiAgZXhwQmFja29mZixcclxuICBmaXhUeXBlLFxyXG4gIGhhbmRsZVJlc291cmNlcyxcclxuICBpc0NvcnJlY3RKU09OLFxyXG4gIGlzT2JqZWN0LFxyXG4gIGlzT2JqZWN0RW1wdHksXHJcbiAgaXNQcml2YXRlUmFuZ2VVcmxGb3VuZCxcclxuICBvcHRpb25zU3RyaW5naWZ5LFxyXG4gIHByaW50TG9nbyxcclxuICBwcmludFVzYWdlLFxyXG4gIHJvdW5kTnVtYmVyLFxyXG4gIHRvQm9vbGVhbixcclxuICB3cmFwQXJvdW5kLFxyXG4gIG1lYXN1cmVUaW1lXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgZXhpc3RzU3luYywgcmVhZEZpbGVTeW5jLCBwcm9taXNlcyBhcyBmc1Byb21pc2VzIH0gZnJvbSAnZnMnO1xyXG5cclxuaW1wb3J0IHByb21wdHMgZnJvbSAncHJvbXB0cyc7XHJcblxyXG5pbXBvcnQge1xyXG4gIGFic29sdXRlUHJvcHMsXHJcbiAgZGVmYXVsdENvbmZpZyxcclxuICBuZXN0ZWRBcmdzLFxyXG4gIHByb21wdHNDb25maWdcclxufSBmcm9tICcuL3NjaGVtYXMvY29uZmlnLmpzJztcclxuaW1wb3J0IHsgZW52cyB9IGZyb20gJy4vZW52cy5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBkZWVwQ29weSwgaXNPYmplY3QsIHByaW50VXNhZ2UsIHRvQm9vbGVhbiB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxubGV0IGdlbmVyYWxPcHRpb25zID0ge307XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIGFuZCByZXR1cm5zIHRoZSBnZW5lcmFsIG9wdGlvbnMgZm9yIHRoZSBleHBvcnQgcHJvY2Vzcy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIGdlbmVyYWwgb3B0aW9ucyBvYmplY3QuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0T3B0aW9ucyA9ICgpID0+IGdlbmVyYWxPcHRpb25zO1xyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIGFuZCBzZXRzIHRoZSBnZW5lcmFsIG9wdGlvbnMgZm9yIHRoZSBzZXJ2ZXIgaW5zdGFjZSwga2VlcGluZ1xyXG4gKiB0aGUgcHJpbmNpcGxlIG9mIHRoZSBvcHRpb25zIGxvYWQgcHJpb3JpdHkuIEl0IGFjY2VwdHMgb3B0aW9uYWwgdXNlck9wdGlvbnNcclxuICogYW5kIGFyZ3MgZnJvbSB0aGUgQ0xJLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gdXNlck9wdGlvbnMgLSBVc2VyLXByb3ZpZGVkIG9wdGlvbnMgZm9yIGN1c3RvbWl6YXRpb24uXHJcbiAqIEBwYXJhbSB7QXJyYXl9IGFyZ3MgLSBDb21tYW5kLWxpbmUgYXJndW1lbnRzIGZvciBhZGRpdGlvbmFsIGNvbmZpZ3VyYXRpb25cclxuICogKENMSSB1c2FnZSkuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSB1cGRhdGVkIGdlbmVyYWwgb3B0aW9ucyBvYmplY3QuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2V0T3B0aW9ucyA9ICh1c2VyT3B0aW9ucywgYXJncykgPT4ge1xyXG4gIC8vIE9ubHkgZm9yIHRoZSBDTEkgdXNhZ2VcclxuICBpZiAoYXJncz8ubGVuZ3RoKSB7XHJcbiAgICAvLyBHZXQgdGhlIGFkZGl0aW9uYWwgb3B0aW9ucyBmcm9tIHRoZSBjdXN0b20gSlNPTiBmaWxlXHJcbiAgICBnZW5lcmFsT3B0aW9ucyA9IGxvYWRDb25maWdGaWxlKGFyZ3MpO1xyXG4gIH1cclxuXHJcbiAgLy8gVXBkYXRlIHRoZSBkZWZhdWx0IGNvbmZpZyB3aXRoIGEgY29ycmVjdCBvcHRpb24gdmFsdWVzXHJcbiAgdXBkYXRlRGVmYXVsdENvbmZpZyhkZWZhdWx0Q29uZmlnLCBnZW5lcmFsT3B0aW9ucyk7XHJcblxyXG4gIC8vIFNldCB2YWx1ZXMgZm9yIHNlcnZlcidzIG9wdGlvbnMgYW5kIHJldHVybnMgdGhlbVxyXG4gIGdlbmVyYWxPcHRpb25zID0gaW5pdE9wdGlvbnMoZGVmYXVsdENvbmZpZyk7XHJcblxyXG4gIC8vIEFwcGx5IHVzZXIgb3B0aW9ucyBpZiB0aGVyZSBhcmUgYW55XHJcbiAgaWYgKHVzZXJPcHRpb25zKSB7XHJcbiAgICAvLyBNZXJnZSB1c2VyIG9wdGlvbnNcclxuICAgIGdlbmVyYWxPcHRpb25zID0gbWVyZ2VDb25maWdPcHRpb25zKFxyXG4gICAgICBnZW5lcmFsT3B0aW9ucyxcclxuICAgICAgdXNlck9wdGlvbnMsXHJcbiAgICAgIGFic29sdXRlUHJvcHNcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICAvLyBPbmx5IGZvciB0aGUgQ0xJIHVzYWdlXHJcbiAgaWYgKGFyZ3M/Lmxlbmd0aCkge1xyXG4gICAgLy8gUGFpciBwcm92aWRlZCBhcmd1bWVudHNcclxuICAgIGdlbmVyYWxPcHRpb25zID0gcGFpckFyZ3VtZW50VmFsdWUoZ2VuZXJhbE9wdGlvbnMsIGFyZ3MsIGRlZmF1bHRDb25maWcpO1xyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIGZpbmFsIGdlbmVyYWwgb3B0aW9uc1xyXG4gIHJldHVybiBnZW5lcmFsT3B0aW9ucztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBBbGxvd3MgbWFudWFsIGNvbmZpZ3VyYXRpb24gYmFzZWQgb24gc3BlY2lmaWVkIHByb21wdHMgYW5kIHNhdmVzXHJcbiAqIHRoZSBjb25maWd1cmF0aW9uIHRvIGEgZmlsZS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGNvbmZpZ0ZpbGVOYW1lIC0gVGhlIG5hbWUgb2YgdGhlIGNvbmZpZ3VyYXRpb24gZmlsZS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8Ym9vbGVhbj59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRydWUgb25jZSB0aGUgbWFudWFsXHJcbiAqIGNvbmZpZ3VyYXRpb24gaXMgY29tcGxldGVkIGFuZCBzYXZlZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBtYW51YWxDb25maWcgPSBhc3luYyAoY29uZmlnRmlsZU5hbWUpID0+IHtcclxuICAvLyBQcmVwYXJlIGEgY29uZmlnIG9iamVjdFxyXG4gIGxldCBjb25maWdGaWxlID0ge307XHJcblxyXG4gIC8vIENoZWNrIGlmIHByb3ZpZGVkIGNvbmZpZyBmaWxlIGV4aXN0c1xyXG4gIGlmIChleGlzdHNTeW5jKGNvbmZpZ0ZpbGVOYW1lKSkge1xyXG4gICAgY29uZmlnRmlsZSA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKGNvbmZpZ0ZpbGVOYW1lLCAndXRmOCcpKTtcclxuICB9XHJcblxyXG4gIC8vIFF1ZXN0aW9uIGFib3V0IGEgY29uZmlndXJhdGlvbiBjYXRlZ29yeVxyXG4gIGNvbnN0IG9uU3VibWl0ID0gYXN5bmMgKHAsIGNhdGVnb3JpZXMpID0+IHtcclxuICAgIGxldCBxdWVzdGlvbnNDb3VudGVyID0gMDtcclxuICAgIGxldCBhbGxRdWVzdGlvbnMgPSBbXTtcclxuXHJcbiAgICAvLyBDcmVhdGUgYSBjb3JyZXNwb25kaW5nIHByb3BlcnR5IGluIHRoZSBtYW51YWxDb25maWcgb2JqZWN0XHJcbiAgICBmb3IgKGNvbnN0IHNlY3Rpb24gb2YgY2F0ZWdvcmllcykge1xyXG4gICAgICAvLyBNYXJrIGVhY2ggb3B0aW9uIHdpdGggYSBzZWN0aW9uXHJcbiAgICAgIHByb21wdHNDb25maWdbc2VjdGlvbl0gPSBwcm9tcHRzQ29uZmlnW3NlY3Rpb25dLm1hcCgob3B0aW9uKSA9PiAoe1xyXG4gICAgICAgIC4uLm9wdGlvbixcclxuICAgICAgICBzZWN0aW9uXHJcbiAgICAgIH0pKTtcclxuXHJcbiAgICAgIC8vIENvbGxlY3QgdGhlIHF1ZXN0aW9uc1xyXG4gICAgICBhbGxRdWVzdGlvbnMgPSBbLi4uYWxsUXVlc3Rpb25zLCAuLi5wcm9tcHRzQ29uZmlnW3NlY3Rpb25dXTtcclxuICAgIH1cclxuXHJcbiAgICBhd2FpdCBwcm9tcHRzKGFsbFF1ZXN0aW9ucywge1xyXG4gICAgICBvblN1Ym1pdDogYXN5bmMgKHByb21wdCwgYW5zd2VyKSA9PiB7XHJcbiAgICAgICAgLy8gR2V0IHRoZSBkZWZhdWx0IG1vZHVsZSBzY3JpcHRzXHJcbiAgICAgICAgaWYgKHByb21wdC5uYW1lID09PSAnbW9kdWxlU2NyaXB0cycpIHtcclxuICAgICAgICAgIGFuc3dlciA9IGFuc3dlci5sZW5ndGhcclxuICAgICAgICAgICAgPyBhbnN3ZXIubWFwKChtb2R1bGUpID0+IHByb21wdC5jaG9pY2VzW21vZHVsZV0pXHJcbiAgICAgICAgICAgIDogcHJvbXB0LmNob2ljZXM7XHJcblxyXG4gICAgICAgICAgY29uZmlnRmlsZVtwcm9tcHQuc2VjdGlvbl1bcHJvbXB0Lm5hbWVdID0gYW5zd2VyO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICBjb25maWdGaWxlW3Byb21wdC5zZWN0aW9uXSA9IHJlY3Vyc2l2ZVByb3BzKFxyXG4gICAgICAgICAgICBPYmplY3QuYXNzaWduKHt9LCBjb25maWdGaWxlW3Byb21wdC5zZWN0aW9uXSB8fCB7fSksXHJcbiAgICAgICAgICAgIHByb21wdC5uYW1lLnNwbGl0KCcuJyksXHJcbiAgICAgICAgICAgIHByb21wdC5jaG9pY2VzID8gcHJvbXB0LmNob2ljZXNbYW5zd2VyXSA6IGFuc3dlclxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGlmICgrK3F1ZXN0aW9uc0NvdW50ZXIgPT09IGFsbFF1ZXN0aW9ucy5sZW5ndGgpIHtcclxuICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgIGF3YWl0IGZzUHJvbWlzZXMud3JpdGVGaWxlKFxyXG4gICAgICAgICAgICAgIGNvbmZpZ0ZpbGVOYW1lLFxyXG4gICAgICAgICAgICAgIEpTT04uc3RyaW5naWZ5KGNvbmZpZ0ZpbGUsIG51bGwsIDIpLFxyXG4gICAgICAgICAgICAgICd1dGY4J1xyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgICAgICAgIDEsXHJcbiAgICAgICAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgICAgICAgYFtjb25maWddIEFuIGVycm9yIG9jY3VycmVkIHdoaWxlIGNyZWF0aW5nIHRoZSAke2NvbmZpZ0ZpbGVOYW1lfSBmaWxlLmBcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfSk7XHJcblxyXG4gICAgcmV0dXJuIHRydWU7XHJcbiAgfTtcclxuXHJcbiAgLy8gRmluZCB0aGUgY2F0ZWdvcmllc1xyXG4gIGNvbnN0IGNob2ljZXMgPSBPYmplY3Qua2V5cyhwcm9tcHRzQ29uZmlnKS5tYXAoKGNob2ljZSkgPT4gKHtcclxuICAgIHRpdGxlOiBgJHtjaG9pY2V9IG9wdGlvbnNgLFxyXG4gICAgdmFsdWU6IGNob2ljZVxyXG4gIH0pKTtcclxuXHJcbiAgLy8gQ2F0ZWdvcnkgcHJvbXB0XHJcbiAgcmV0dXJuIHByb21wdHMoXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdtdWx0aXNlbGVjdCcsXHJcbiAgICAgIG5hbWU6ICdjYXRlZ29yeScsXHJcbiAgICAgIG1lc3NhZ2U6ICdXaGljaCBjYXRlZ29yeSBkbyB5b3Ugd2FudCB0byBjb25maWd1cmU/JyxcclxuICAgICAgaGludDogJ1NwYWNlOiBTZWxlY3Qgc3BlY2lmaWMsIEE6IFNlbGVjdCBhbGwsIEVudGVyOiBDb25maXJtLicsXHJcbiAgICAgIGluc3RydWN0aW9uczogJycsXHJcbiAgICAgIGNob2ljZXNcclxuICAgIH0sXHJcbiAgICB7IG9uU3VibWl0IH1cclxuICApO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIE1hcHMgb2xkLXN0cnVjdHVyZWQgKFBoYW50b21KUykgb3B0aW9ucyB0byBhIG5ldyBjb25maWd1cmF0aW9uIGZvcm1hdFxyXG4gKiAoUHVwcGV0ZWVyKS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9sZE9wdGlvbnMgLSBPbGQtc3RydWN0dXJlZCBvcHRpb25zIHRvIGJlIG1hcHBlZC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gTmV3IG9wdGlvbnMgc3RydWN0dXJlZCBiYXNlZCBvbiB0aGUgZGVmaW5lZCBuZXN0ZWRBcmdzXHJcbiAqIG1hcHBpbmcuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbWFwVG9OZXdDb25maWcgPSAob2xkT3B0aW9ucykgPT4ge1xyXG4gIGNvbnN0IG5ld09wdGlvbnMgPSB7fTtcclxuICAvLyBDeWNsZSB0aHJvdWdoIG9sZC1zdHJ1Y3R1cmVkIG9wdGlvbnNcclxuICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhvbGRPcHRpb25zKSkge1xyXG4gICAgY29uc3QgcHJvcGVydGllc0NoYWluID0gbmVzdGVkQXJnc1trZXldID8gbmVzdGVkQXJnc1trZXldLnNwbGl0KCcuJykgOiBbXTtcclxuXHJcbiAgICAvLyBQb3B1bGF0ZSBvYmplY3QgaW4gY29ycmVjdCBwcm9wZXJ0aWVzIGxldmVsc1xyXG4gICAgcHJvcGVydGllc0NoYWluLnJlZHVjZShcclxuICAgICAgKG9iaiwgcHJvcCwgaW5kZXgpID0+XHJcbiAgICAgICAgKG9ialtwcm9wXSA9XHJcbiAgICAgICAgICBwcm9wZXJ0aWVzQ2hhaW4ubGVuZ3RoIC0gMSA9PT0gaW5kZXggPyB2YWx1ZSA6IG9ialtwcm9wXSB8fCB7fSksXHJcbiAgICAgIG5ld09wdGlvbnNcclxuICAgICk7XHJcbiAgfVxyXG4gIHJldHVybiBuZXdPcHRpb25zO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIE1lcmdlcyB0d28gc2V0cyBvZiBjb25maWd1cmF0aW9uIG9wdGlvbnMsIGNvbnNpZGVyaW5nIGFic29sdXRlIHByb3BlcnRpZXMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gT3JpZ2luYWwgY29uZmlndXJhdGlvbiBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gbmV3T3B0aW9ucyAtIE5ldyBjb25maWd1cmF0aW9uIG9wdGlvbnMgdG8gYmUgbWVyZ2VkLlxyXG4gKiBAcGFyYW0ge0FycmF5fSBhYnNvbHV0ZVByb3BzIC0gTGlzdCBvZiBwcm9wZXJ0aWVzIHRoYXQgc2hvdWxkXHJcbiAqIG5vdCBiZSByZWN1cnNpdmVseSBtZXJnZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IE1lcmdlZCBjb25maWd1cmF0aW9uIG9wdGlvbnMuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbWVyZ2VDb25maWdPcHRpb25zID0gKG9wdGlvbnMsIG5ld09wdGlvbnMsIGFic29sdXRlUHJvcHMgPSBbXSkgPT4ge1xyXG4gIGNvbnN0IG1lcmdlZE9wdGlvbnMgPSBkZWVwQ29weShvcHRpb25zKTtcclxuXHJcbiAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMobmV3T3B0aW9ucykpIHtcclxuICAgIG1lcmdlZE9wdGlvbnNba2V5XSA9XHJcbiAgICAgIGlzT2JqZWN0KHZhbHVlKSAmJlxyXG4gICAgICAhYWJzb2x1dGVQcm9wcy5pbmNsdWRlcyhrZXkpICYmXHJcbiAgICAgIG1lcmdlZE9wdGlvbnNba2V5XSAhPT0gdW5kZWZpbmVkXHJcbiAgICAgICAgPyBtZXJnZUNvbmZpZ09wdGlvbnMobWVyZ2VkT3B0aW9uc1trZXldLCB2YWx1ZSwgYWJzb2x1dGVQcm9wcylcclxuICAgICAgICA6IHZhbHVlICE9PSB1bmRlZmluZWRcclxuICAgICAgICAgID8gdmFsdWVcclxuICAgICAgICAgIDogbWVyZ2VkT3B0aW9uc1trZXldO1xyXG4gIH1cclxuXHJcbiAgcmV0dXJuIG1lcmdlZE9wdGlvbnM7XHJcbn07XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgZXhwb3J0IHNldHRpbmdzIGJhc2VkIG9uIHByb3ZpZGVkIGV4cG9ydE9wdGlvbnNcclxuICogYW5kIGdlbmVyYWxPcHRpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZXhwb3J0T3B0aW9ucyAtIE9wdGlvbnMgc3BlY2lmaWMgdG8gdGhlIGV4cG9ydCBwcm9jZXNzLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZ2VuZXJhbE9wdGlvbnMgLSBHZW5lcmFsIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gSW5pdGlhbGl6ZWQgZXhwb3J0IHNldHRpbmdzLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGluaXRFeHBvcnRTZXR0aW5ncyA9IChleHBvcnRPcHRpb25zLCBnZW5lcmFsT3B0aW9ucyA9IHt9KSA9PiB7XHJcbiAgbGV0IG9wdGlvbnMgPSB7fTtcclxuXHJcbiAgaWYgKGV4cG9ydE9wdGlvbnMuc3ZnKSB7XHJcbiAgICBvcHRpb25zID0gZGVlcENvcHkoZ2VuZXJhbE9wdGlvbnMpO1xyXG4gICAgb3B0aW9ucy5leHBvcnQudHlwZSA9IGV4cG9ydE9wdGlvbnMudHlwZSB8fCBleHBvcnRPcHRpb25zLmV4cG9ydC50eXBlO1xyXG4gICAgb3B0aW9ucy5leHBvcnQuc2NhbGUgPSBleHBvcnRPcHRpb25zLnNjYWxlIHx8IGV4cG9ydE9wdGlvbnMuZXhwb3J0LnNjYWxlO1xyXG4gICAgb3B0aW9ucy5leHBvcnQub3V0ZmlsZSA9XHJcbiAgICAgIGV4cG9ydE9wdGlvbnMub3V0ZmlsZSB8fCBleHBvcnRPcHRpb25zLmV4cG9ydC5vdXRmaWxlO1xyXG4gICAgb3B0aW9ucy5wYXlsb2FkID0ge1xyXG4gICAgICBzdmc6IGV4cG9ydE9wdGlvbnMuc3ZnXHJcbiAgICB9O1xyXG4gIH0gZWxzZSB7XHJcbiAgICBvcHRpb25zID0gbWVyZ2VDb25maWdPcHRpb25zKFxyXG4gICAgICBnZW5lcmFsT3B0aW9ucyxcclxuICAgICAgZXhwb3J0T3B0aW9ucyxcclxuICAgICAgLy8gT21pdCBnb2luZyBkb3duIHJlY3Vyc2l2ZWx5IHdpdGggdGhlIGJlbG93c1xyXG4gICAgICBhYnNvbHV0ZVByb3BzXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgb3B0aW9ucy5leHBvcnQub3V0ZmlsZSA9XHJcbiAgICBvcHRpb25zLmV4cG9ydD8ub3V0ZmlsZSB8fCBgY2hhcnQuJHtvcHRpb25zLmV4cG9ydD8udHlwZSB8fCAncG5nJ31gO1xyXG4gIHJldHVybiBvcHRpb25zO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIExvYWRzIGFkZGl0aW9uYWwgY29uZmlndXJhdGlvbiBmcm9tIGEgc3BlY2lmaWVkIGZpbGUgdXNpbmdcclxuICogdGhlIC0tbG9hZENvbmZpZyBvcHRpb24uXHJcbiAqXHJcbiAqIEBwYXJhbSB7QXJyYXl9IGFyZ3MgLSBDb21tYW5kLWxpbmUgYXJndW1lbnRzIHRvIGNoZWNrIGZvclxyXG4gKiB0aGUgLS1sb2FkQ29uZmlnIG9wdGlvbi5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gQWRkaXRpb25hbCBjb25maWd1cmF0aW9uIGxvYWRlZCBmcm9tIHRoZSBzcGVjaWZpZWQgZmlsZSxcclxuICogb3IgYW4gZW1wdHkgb2JqZWN0IGlmIG5vdCBmb3VuZCBvciBpbnZhbGlkLlxyXG4gKi9cclxuZnVuY3Rpb24gbG9hZENvbmZpZ0ZpbGUoYXJncykge1xyXG4gIC8vIENoZWNrIGlmIHRoZSAtLWxvYWRDb25maWcgb3B0aW9uIHdhcyB1c2VkXHJcbiAgY29uc3QgY29uZmlnSW5kZXggPSBhcmdzLmZpbmRJbmRleChcclxuICAgIChhcmcpID0+IGFyZy5yZXBsYWNlKC8tL2csICcnKSA9PT0gJ2xvYWRDb25maWcnXHJcbiAgKTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgdGhlIC0tbG9hZENvbmZpZyBoYXMgYSB2YWx1ZVxyXG4gIGlmIChjb25maWdJbmRleCA+IC0xICYmIGFyZ3NbY29uZmlnSW5kZXggKyAxXSkge1xyXG4gICAgY29uc3QgZmlsZU5hbWUgPSBhcmdzW2NvbmZpZ0luZGV4ICsgMV07XHJcbiAgICB0cnkge1xyXG4gICAgICAvLyBDaGVjayBpZiBhbiBhZGRpdGlvbmFsIGNvbmZpZyBmaWxlIGlzIGEgY29ycmVjdCBKU09OIGZpbGVcclxuICAgICAgaWYgKGZpbGVOYW1lICYmIGZpbGVOYW1lLmVuZHNXaXRoKCcuanNvbicpKSB7XHJcbiAgICAgICAgLy8gTG9hZCBhbiBvcHRpb25hbCBjdXN0b20gSlNPTiBjb25maWcgZmlsZVxyXG4gICAgICAgIHJldHVybiBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhmaWxlTmFtZSkpO1xyXG4gICAgICB9XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgMixcclxuICAgICAgICBlcnJvcixcclxuICAgICAgICBgW2NvbmZpZ10gVW5hYmxlIHRvIGxvYWQgdGhlIGNvbmZpZ3VyYXRpb24gZnJvbSB0aGUgJHtmaWxlTmFtZX0gZmlsZS5gXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBObyBhZGRpdGlvbmFsIG9wdGlvbnMgdG8gcmV0dXJuXHJcbiAgcmV0dXJuIHt9O1xyXG59XHJcblxyXG4vKipcclxuICogVXBkYXRlcyB0aGUgZGVmYXVsdCBjb25maWd1cmF0aW9uIG9iamVjdCB3aXRoIHZhbHVlcyBmcm9tIGEgY3VzdG9tIG9iamVjdFxyXG4gKiBhbmQgZW52aXJvbm1lbnQgdmFyaWFibGVzLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnT2JqIC0gVGhlIGRlZmF1bHQgY29uZmlndXJhdGlvbiBvYmplY3QuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjdXN0b21PYmogLSBDdXN0b20gY29uZmlndXJhdGlvbiBvYmplY3QgdG8gb3ZlcnJpZGUgZGVmYXVsdHMuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwcm9wQ2hhaW4gLSBQcm9wZXJ0eSBjaGFpbiBmb3IgdHJhY2tpbmcgbmVzdGVkIHByb3BlcnRpZXNcclxuICogZHVyaW5nIHJlY3Vyc2lvbi5cclxuICovXHJcbmZ1bmN0aW9uIHVwZGF0ZURlZmF1bHRDb25maWcoY29uZmlnT2JqLCBjdXN0b21PYmogPSB7fSwgcHJvcENoYWluID0gJycpIHtcclxuICBPYmplY3Qua2V5cyhjb25maWdPYmopLmZvckVhY2goKGtleSkgPT4ge1xyXG4gICAgY29uc3QgZW50cnkgPSBjb25maWdPYmpba2V5XTtcclxuICAgIGNvbnN0IGN1c3RvbVZhbHVlID0gY3VzdG9tT2JqICYmIGN1c3RvbU9ialtrZXldO1xyXG5cclxuICAgIGlmICh0eXBlb2YgZW50cnkudmFsdWUgPT09ICd1bmRlZmluZWQnKSB7XHJcbiAgICAgIHVwZGF0ZURlZmF1bHRDb25maWcoZW50cnksIGN1c3RvbVZhbHVlLCBgJHtwcm9wQ2hhaW59LiR7a2V5fWApO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gSWYgYSB2YWx1ZSBmcm9tIGEgY3VzdG9tIEpTT04gZXhpc3RzLCBpdCB0YWtlIHByZWNlZGVuY2VcclxuICAgICAgaWYgKGN1c3RvbVZhbHVlICE9PSB1bmRlZmluZWQpIHtcclxuICAgICAgICBlbnRyeS52YWx1ZSA9IGN1c3RvbVZhbHVlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBJZiBhIHZhbHVlIGZyb20gYW4gZW52IHZhcmlhYmxlIGV4aXN0cywgaXQgdGFrZSBwcmVjZWRlbmNlXHJcbiAgICAgIGlmIChlbnRyeS5lbnZMaW5rIGluIGVudnMgJiYgZW52c1tlbnRyeS5lbnZMaW5rXSAhPT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgICAgZW50cnkudmFsdWUgPSBlbnZzW2VudHJ5LmVudkxpbmtdO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyBvcHRpb25zIG9iamVjdCBiYXNlZCBvbiBwcm92aWRlZCBpdGVtcywgc2V0dGluZyB2YWx1ZXMgZnJvbVxyXG4gKiBuZXN0ZWQgcHJvcGVydGllcyByZWN1cnNpdmVseS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGl0ZW1zIC0gQ29uZmlndXJhdGlvbiBpdGVtcyB0byBiZSB1c2VkIGZvciBpbml0aWFsaXppbmdcclxuICogb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gSW5pdGlhbGl6ZWQgb3B0aW9ucyBvYmplY3QuXHJcbiAqL1xyXG5mdW5jdGlvbiBpbml0T3B0aW9ucyhpdGVtcykge1xyXG4gIGxldCBvcHRpb25zID0ge307XHJcbiAgZm9yIChjb25zdCBbbmFtZSwgaXRlbV0gb2YgT2JqZWN0LmVudHJpZXMoaXRlbXMpKSB7XHJcbiAgICBvcHRpb25zW25hbWVdID0gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGl0ZW0sICd2YWx1ZScpXHJcbiAgICAgID8gaXRlbS52YWx1ZVxyXG4gICAgICA6IGluaXRPcHRpb25zKGl0ZW0pO1xyXG4gIH1cclxuICByZXR1cm4gb3B0aW9ucztcclxufVxyXG5cclxuLyoqXHJcbiAqIFBhaXJzIGFyZ3VtZW50IHZhbHVlcyB3aXRoIGNvcnJlc3BvbmRpbmcgb3B0aW9ucyBpbiB0aGUgY29uZmlndXJhdGlvbixcclxuICogdXBkYXRpbmcgdGhlIG9wdGlvbnMgb2JqZWN0LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIENvbmZpZ3VyYXRpb24gb3B0aW9ucyBvYmplY3QgdG8gYmUgdXBkYXRlZC5cclxuICogQHBhcmFtIHtBcnJheX0gYXJncyAtIENvbW1hbmQtbGluZSBhcmd1bWVudHMgY29udGFpbmluZyB2YWx1ZXMgZm9yIHNwZWNpZmljXHJcbiAqIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBkZWZhdWx0Q29uZmlnIC0gRGVmYXVsdCBjb25maWd1cmF0aW9uIG9iamVjdCBmb3IgcmVmZXJlbmNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBVcGRhdGVkIG9wdGlvbnMgb2JqZWN0LlxyXG4gKi9cclxuZnVuY3Rpb24gcGFpckFyZ3VtZW50VmFsdWUob3B0aW9ucywgYXJncywgZGVmYXVsdENvbmZpZykge1xyXG4gIGxldCBzaG93VXNhZ2UgPSBmYWxzZTtcclxuICBmb3IgKGxldCBpID0gMDsgaSA8IGFyZ3MubGVuZ3RoOyBpKyspIHtcclxuICAgIGNvbnN0IG9wdGlvbiA9IGFyZ3NbaV0ucmVwbGFjZSgvLS9nLCAnJyk7XHJcblxyXG4gICAgLy8gRmluZCB0aGUgcmlnaHQgcGxhY2UgZm9yIHByb3BlcnR5J3MgdmFsdWVcclxuICAgIGNvbnN0IHByb3BlcnRpZXNDaGFpbiA9IG5lc3RlZEFyZ3Nbb3B0aW9uXVxyXG4gICAgICA/IG5lc3RlZEFyZ3Nbb3B0aW9uXS5zcGxpdCgnLicpXHJcbiAgICAgIDogW107XHJcblxyXG4gICAgLy8gR2V0IHRoZSBjb3JyZWN0IHR5cGUgZm9yIENMSSBhcmdzIHdoaWNoIGFyZSBwYXNzZWQgYXMgc3RyaW5nc1xyXG4gICAgbGV0IGFyZ3VtZW50VHlwZTtcclxuICAgIHByb3BlcnRpZXNDaGFpbi5yZWR1Y2UoKG9iaiwgcHJvcCwgaW5kZXgpID0+IHtcclxuICAgICAgaWYgKHByb3BlcnRpZXNDaGFpbi5sZW5ndGggLSAxID09PSBpbmRleCkge1xyXG4gICAgICAgIGFyZ3VtZW50VHlwZSA9IG9ialtwcm9wXS50eXBlO1xyXG4gICAgICB9XHJcbiAgICAgIHJldHVybiBvYmpbcHJvcF07XHJcbiAgICB9LCBkZWZhdWx0Q29uZmlnKTtcclxuXHJcbiAgICBwcm9wZXJ0aWVzQ2hhaW4ucmVkdWNlKChvYmosIHByb3AsIGluZGV4KSA9PiB7XHJcbiAgICAgIGlmIChwcm9wZXJ0aWVzQ2hhaW4ubGVuZ3RoIC0gMSA9PT0gaW5kZXgpIHtcclxuICAgICAgICAvLyBGaW5kcyBhbiBvcHRpb24gYW5kIHNldCBhIGNvcnJlc3BvbmRpbmcgdmFsdWVcclxuICAgICAgICBpZiAodHlwZW9mIG9ialtwcm9wXSAhPT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgICAgIGlmIChhcmdzWysraV0pIHtcclxuICAgICAgICAgICAgaWYgKGFyZ3VtZW50VHlwZSA9PT0gJ2Jvb2xlYW4nKSB7XHJcbiAgICAgICAgICAgICAgb2JqW3Byb3BdID0gdG9Cb29sZWFuKGFyZ3NbaV0pO1xyXG4gICAgICAgICAgICB9IGVsc2UgaWYgKGFyZ3VtZW50VHlwZSA9PT0gJ251bWJlcicpIHtcclxuICAgICAgICAgICAgICBvYmpbcHJvcF0gPSArYXJnc1tpXTtcclxuICAgICAgICAgICAgfSBlbHNlIGlmIChhcmd1bWVudFR5cGUuaW5kZXhPZignXScpID49IDApIHtcclxuICAgICAgICAgICAgICBvYmpbcHJvcF0gPSBhcmdzW2ldLnNwbGl0KCcsJyk7XHJcbiAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgb2JqW3Byb3BdID0gYXJnc1tpXTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgbG9nKFxyXG4gICAgICAgICAgICAgIDIsXHJcbiAgICAgICAgICAgICAgYFtjb25maWddIE1pc3NpbmcgdmFsdWUgZm9yIHRoZSAnJHtvcHRpb259JyBhcmd1bWVudC4gVXNpbmcgdGhlIGRlZmF1bHQgdmFsdWUuYFxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgICBzaG93VXNhZ2UgPSB0cnVlO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gb2JqW3Byb3BdO1xyXG4gICAgfSwgb3B0aW9ucyk7XHJcbiAgfVxyXG5cclxuICAvLyBEaXNwbGF5IHRoZSB1c2FnZSBmb3IgdGhlIHJlZmVyZW5jZSBpZiBuZWVkZWRcclxuICBpZiAoc2hvd1VzYWdlKSB7XHJcbiAgICBwcmludFVzYWdlKGRlZmF1bHRDb25maWcpO1xyXG4gIH1cclxuXHJcbiAgcmV0dXJuIG9wdGlvbnM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZWN1cnNpdmVseSB1cGRhdGVzIHByb3BlcnRpZXMgaW4gYW4gb2JqZWN0IGJhc2VkIG9uIG5lc3RlZCBuYW1lcyBhbmQgYXNzaWduc1xyXG4gKiB0aGUgZmluYWwgdmFsdWUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvYmplY3RUb1VwZGF0ZSAtIFRoZSBvYmplY3QgdG8gYmUgdXBkYXRlZC5cclxuICogQHBhcmFtIHtBcnJheX0gbmVzdGVkTmFtZXMgLSBBcnJheSBvZiBuZXN0ZWQgcHJvcGVydHkgbmFtZXMuXHJcbiAqIEBwYXJhbSB7YW55fSB2YWx1ZSAtIFRoZSBmaW5hbCB2YWx1ZSB0byBiZSBhc3NpZ25lZC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVXBkYXRlZCBvYmplY3Qgd2l0aCBhc3NpZ25lZCB2YWx1ZXMuXHJcbiAqL1xyXG5mdW5jdGlvbiByZWN1cnNpdmVQcm9wcyhvYmplY3RUb1VwZGF0ZSwgbmVzdGVkTmFtZXMsIHZhbHVlKSB7XHJcbiAgd2hpbGUgKG5lc3RlZE5hbWVzLmxlbmd0aCA+IDEpIHtcclxuICAgIGNvbnN0IHByb3BOYW1lID0gbmVzdGVkTmFtZXMuc2hpZnQoKTtcclxuXHJcbiAgICAvLyBDcmVhdGUgYSBwcm9wZXJ0eSBpbiBvYmplY3QgaWYgaXQgZG9lc24ndCBleGlzdFxyXG4gICAgaWYgKCFPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob2JqZWN0VG9VcGRhdGUsIHByb3BOYW1lKSkge1xyXG4gICAgICBvYmplY3RUb1VwZGF0ZVtwcm9wTmFtZV0gPSB7fTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBDYWxsIGZ1bmN0aW9uIGFnYWluIGlmIHRoZXJlIHN0aWxsIG5hbWVzIHRvIGdvXHJcbiAgICBvYmplY3RUb1VwZGF0ZVtwcm9wTmFtZV0gPSByZWN1cnNpdmVQcm9wcyhcclxuICAgICAgT2JqZWN0LmFzc2lnbih7fSwgb2JqZWN0VG9VcGRhdGVbcHJvcE5hbWVdKSxcclxuICAgICAgbmVzdGVkTmFtZXMsXHJcbiAgICAgIHZhbHVlXHJcbiAgICApO1xyXG5cclxuICAgIHJldHVybiBvYmplY3RUb1VwZGF0ZTtcclxuICB9XHJcblxyXG4gIC8vIEFzc2lnbiB0aGUgZmluYWwgdmFsdWVcclxuICBvYmplY3RUb1VwZGF0ZVtuZXN0ZWROYW1lc1swXV0gPSB2YWx1ZTtcclxuICByZXR1cm4gb2JqZWN0VG9VcGRhdGU7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBnZXRPcHRpb25zLFxyXG4gIHNldE9wdGlvbnMsXHJcbiAgbWFudWFsQ29uZmlnLFxyXG4gIG1hcFRvTmV3Q29uZmlnLFxyXG4gIG1lcmdlQ29uZmlnT3B0aW9ucyxcclxuICBpbml0RXhwb3J0U2V0dGluZ3NcclxufTtcclxuIiwiLyoqXHJcbiAqIFRoaXMgbW9kdWxlIGV4cG9ydHMgdHdvIGZ1bmN0aW9uczogZmV0Y2ggKGZvciBHRVQgcmVxdWVzdHMpIGFuZCBwb3N0IChmb3IgUE9TVCByZXF1ZXN0cykuXHJcbiAqL1xyXG5cclxuaW1wb3J0IGh0dHAgZnJvbSAnaHR0cCc7XHJcbmltcG9ydCBodHRwcyBmcm9tICdodHRwcyc7XHJcblxyXG4vKipcclxuICogUmV0dXJucyB0aGUgSFRUUCBvciBIVFRQUyBwcm90b2NvbCBtb2R1bGUgYmFzZWQgb24gdGhlIHByb3ZpZGVkIFVSTC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHVybCAtIFRoZSBVUkwgdG8gZGV0ZXJtaW5lIHRoZSBwcm90b2NvbC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wgbW9kdWxlIChodHRwIG9yIGh0dHBzKS5cclxuICovXHJcbmNvbnN0IGdldFByb3RvY29sID0gKHVybCkgPT4gKHVybC5zdGFydHNXaXRoKCdodHRwcycpID8gaHR0cHMgOiBodHRwKTtcclxuXHJcbi8qKlxyXG4gKiBGZXRjaGVzIGRhdGEgZnJvbSB0aGUgc3BlY2lmaWVkIFVSTCB1c2luZyBlaXRoZXIgSFRUUCBvciBIVFRQUyBwcm90b2NvbC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHVybCAtIFRoZSBVUkwgdG8gZmV0Y2ggZGF0YSBmcm9tLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcmVxdWVzdE9wdGlvbnMgLSBPcHRpb25zIGZvciB0aGUgSFRUUCByZXF1ZXN0IChvcHRpb25hbCkuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBIVFRQIHJlc3BvbnNlIG9iamVjdFxyXG4gKiB3aXRoIGFkZGVkICd0ZXh0JyBwcm9wZXJ0eSBvciByZWplY3Rpbmcgd2l0aCBhbiBlcnJvci5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIGZldGNoKHVybCwgcmVxdWVzdE9wdGlvbnMgPSB7fSkge1xyXG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XHJcbiAgICBjb25zdCBwcm90b2NvbCA9IGdldFByb3RvY29sKHVybCk7XHJcblxyXG4gICAgcHJvdG9jb2xcclxuICAgICAgLmdldCh1cmwsIHJlcXVlc3RPcHRpb25zLCAocmVzKSA9PiB7XHJcbiAgICAgICAgbGV0IGRhdGEgPSAnJztcclxuXHJcbiAgICAgICAgLy8gQSBjaHVuayBvZiBkYXRhIGhhcyBiZWVuIHJlY2VpdmVkLlxyXG4gICAgICAgIHJlcy5vbignZGF0YScsIChjaHVuaykgPT4ge1xyXG4gICAgICAgICAgZGF0YSArPSBjaHVuaztcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgLy8gVGhlIHdob2xlIHJlc3BvbnNlIGhhcyBiZWVuIHJlY2VpdmVkLlxyXG4gICAgICAgIHJlcy5vbignZW5kJywgKCkgPT4ge1xyXG4gICAgICAgICAgaWYgKCFkYXRhKSB7XHJcbiAgICAgICAgICAgIHJlamVjdCgnTm90aGluZyB3YXMgZmV0Y2hlZCBmcm9tIHRoZSBVUkwuJyk7XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgcmVzLnRleHQgPSBkYXRhO1xyXG4gICAgICAgICAgcmVzb2x2ZShyZXMpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICB9KVxyXG4gICAgICAub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICAgICAgcmVqZWN0KGVycm9yKTtcclxuICAgICAgfSk7XHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZW5kcyBhIFBPU1QgcmVxdWVzdCB0byB0aGUgc3BlY2lmaWVkIFVSTCB3aXRoIHRoZSBwcm92aWRlZCBKU09OIGJvZHkgdXNpbmdcclxuICogZWl0aGVyIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgLSBUaGUgVVJMIHRvIHNlbmQgdGhlIFBPU1QgcmVxdWVzdCB0by5cclxuICogQHBhcmFtIHtPYmplY3R9IGJvZHkgLSBUaGUgSlNPTiBib2R5IHRvIGluY2x1ZGUgaW4gdGhlIFBPU1QgcmVxdWVzdFxyXG4gKiAob3B0aW9uYWwsIGRlZmF1bHQgaXMgYW4gZW1wdHkgb2JqZWN0KS5cclxuICogQHBhcmFtIHtPYmplY3R9IHJlcXVlc3RPcHRpb25zIC0gT3B0aW9ucyBmb3IgdGhlIEhUVFAgcmVxdWVzdCAob3B0aW9uYWwpLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgSFRUUCByZXNwb25zZSBvYmplY3Qgd2l0aFxyXG4gKiBhZGRlZCAndGV4dCcgcHJvcGVydHkgb3IgcmVqZWN0aW5nIHdpdGggYW4gZXJyb3IuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBwb3N0KHVybCwgYm9keSA9IHt9LCByZXF1ZXN0T3B0aW9ucyA9IHt9KSB7XHJcbiAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcclxuICAgIGNvbnN0IHByb3RvY29sID0gZ2V0UHJvdG9jb2wodXJsKTtcclxuICAgIGNvbnN0IGRhdGEgPSBKU09OLnN0cmluZ2lmeShib2R5KTtcclxuXHJcbiAgICAvLyBTZXQgZGVmYXVsdCBoZWFkZXJzIGFuZCBtZXJnZSB3aXRoIHJlcXVlc3RPcHRpb25zXHJcbiAgICBjb25zdCBvcHRpb25zID0gT2JqZWN0LmFzc2lnbihcclxuICAgICAge1xyXG4gICAgICAgIG1ldGhvZDogJ1BPU1QnLFxyXG4gICAgICAgIGhlYWRlcnM6IHtcclxuICAgICAgICAgICdDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbicsXHJcbiAgICAgICAgICAnQ29udGVudC1MZW5ndGgnOiBkYXRhLmxlbmd0aFxyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgcmVxdWVzdE9wdGlvbnNcclxuICAgICk7XHJcblxyXG4gICAgY29uc3QgcmVxID0gcHJvdG9jb2xcclxuICAgICAgLnJlcXVlc3QodXJsLCBvcHRpb25zLCAocmVzKSA9PiB7XHJcbiAgICAgICAgbGV0IHJlc3BvbnNlRGF0YSA9ICcnO1xyXG5cclxuICAgICAgICAvLyBBIGNodW5rIG9mIGRhdGEgaGFzIGJlZW4gcmVjZWl2ZWQuXHJcbiAgICAgICAgcmVzLm9uKCdkYXRhJywgKGNodW5rKSA9PiB7XHJcbiAgICAgICAgICByZXNwb25zZURhdGEgKz0gY2h1bms7XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICAgIC8vIFRoZSB3aG9sZSByZXNwb25zZSBoYXMgYmVlbiByZWNlaXZlZC5cclxuICAgICAgICByZXMub24oJ2VuZCcsICgpID0+IHtcclxuICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgIHJlcy50ZXh0ID0gcmVzcG9uc2VEYXRhO1xyXG4gICAgICAgICAgICByZXNvbHZlKHJlcyk7XHJcbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICByZWplY3QoZXJyb3IpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH0pO1xyXG4gICAgICB9KVxyXG4gICAgICAub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICAgICAgcmVqZWN0KGVycm9yKTtcclxuICAgICAgfSk7XHJcblxyXG4gICAgLy8gV3JpdGUgdGhlIHJlcXVlc3QgYm9keSBhbmQgZW5kIHRoZSByZXF1ZXN0LlxyXG4gICAgcmVxLndyaXRlKGRhdGEpO1xyXG4gICAgcmVxLmVuZCgpO1xyXG4gIH0pO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCBmZXRjaDtcclxuZXhwb3J0IHsgZmV0Y2gsIHBvc3QgfTtcclxuIiwiY2xhc3MgRXhwb3J0RXJyb3IgZXh0ZW5kcyBFcnJvciB7XHJcbiAgY29uc3RydWN0b3IobWVzc2FnZSkge1xyXG4gICAgc3VwZXIoKTtcclxuICAgIHRoaXMubWVzc2FnZSA9IG1lc3NhZ2U7XHJcbiAgICB0aGlzLnN0YWNrTWVzc2FnZSA9IG1lc3NhZ2U7XHJcbiAgfVxyXG5cclxuICBzZXRFcnJvcihlcnJvcikge1xyXG4gICAgdGhpcy5lcnJvciA9IGVycm9yO1xyXG4gICAgaWYgKGVycm9yLm5hbWUpIHtcclxuICAgICAgdGhpcy5uYW1lID0gZXJyb3IubmFtZTtcclxuICAgIH1cclxuICAgIGlmIChlcnJvci5zdGF0dXNDb2RlKSB7XHJcbiAgICAgIHRoaXMuc3RhdHVzQ29kZSA9IGVycm9yLnN0YXR1c0NvZGU7XHJcbiAgICB9XHJcbiAgICBpZiAoZXJyb3Iuc3RhY2spIHtcclxuICAgICAgdGhpcy5zdGFja01lc3NhZ2UgPSBlcnJvci5tZXNzYWdlO1xyXG4gICAgICB0aGlzLnN0YWNrID0gZXJyb3Iuc3RhY2s7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gdGhpcztcclxuICB9XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IEV4cG9ydEVycm9yO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8vIFRoZSBjYWNoZSBtYW5hZ2VyIG1hbmFnZXMgdGhlIEhpZ2hjaGFydHMgbGlicmFyeSBhbmQgaXRzIGRlcGVuZGVuY2llcy5cclxuLy8gVGhlIGNhY2hlIGl0c2VsZiBpcyBzdG9yZWQgaW4gLmNhY2hlLCBhbmQgaXMgY2hlY2tlZCBieSB0aGUgY29uZmlnIHN5c3RlbVxyXG4vLyBiZWZvcmUgc3RhcnRpbmcgdGhlIHNlcnZpY2VcclxuXHJcbmltcG9ydCB7IGV4aXN0c1N5bmMsIG1rZGlyU3luYywgcmVhZEZpbGVTeW5jLCB3cml0ZUZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgeyBIdHRwc1Byb3h5QWdlbnQgfSBmcm9tICdodHRwcy1wcm94eS1hZ2VudCc7XHJcblxyXG5pbXBvcnQgeyBnZXRPcHRpb25zIH0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBlbnZzIH0gZnJvbSAnLi9lbnZzLmpzJztcclxuaW1wb3J0IHsgZmV0Y2ggfSBmcm9tICcuL2ZldGNoLmpzJztcclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBfX2Rpcm5hbWUgfSBmcm9tICcuL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG5jb25zdCBjYWNoZSA9IHtcclxuICBjZG5VUkw6ICdodHRwczovL2NvZGUuaGlnaGNoYXJ0cy5jb20vJyxcclxuICBhY3RpdmVNYW5pZmVzdDoge30sXHJcbiAgc291cmNlczogJycsXHJcbiAgaGNWZXJzaW9uOiAnJ1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEV4dHJhY3RzIGFuZCBjYWNoZXMgdGhlIEhpZ2hjaGFydHMgdmVyc2lvbiBmcm9tIHRoZSBzb3VyY2VzIHN0cmluZy5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIGV4dHJhY3RlZCBIaWdoY2hhcnRzIHZlcnNpb24uXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZXh0cmFjdFZlcnNpb24gPSAoY2FjaGUpID0+IHtcclxuICByZXR1cm4gY2FjaGUuc291cmNlc1xyXG4gICAgLnN1YnN0cmluZygwLCBjYWNoZS5zb3VyY2VzLmluZGV4T2YoJyovJykpXHJcbiAgICAucmVwbGFjZSgnLyonLCAnJylcclxuICAgIC5yZXBsYWNlKCcqLycsICcnKVxyXG4gICAgLnJlcGxhY2UoL1xcbi9nLCAnJylcclxuICAgIC50cmltKCk7XHJcbn07XHJcblxyXG4vKipcclxuICogRXh0cmFjdHMgdGhlIEhpZ2hjaGFydHMgbW9kdWxlIG5hbWUgYmFzZWQgb24gdGhlIHNjcmlwdFBhdGguXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZXh0cmFjdE1vZHVsZU5hbWUgPSAoc2NyaXB0UGF0aCkgPT4ge1xyXG4gIHJldHVybiBzY3JpcHRQYXRoLnJlcGxhY2UoXHJcbiAgICAvKC4qKVxcL3woLiopbW9kdWxlc1xcL3xzdG9ja1xcLyguKilpbmRpY2F0b3JzXFwvfG1hcHNcXC8oLiopbW9kdWxlc1xcLy9naSxcclxuICAgICcnXHJcbiAgKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBTYXZlcyB0aGUgcHJvdmlkZWQgY29uZmlndXJhdGlvbiBhbmQgZmV0Y2hlZCBtb2R1bGVzIHRvIHRoZSBjYWNoZSBtYW5pZmVzdFxyXG4gKiBmaWxlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge29iamVjdH0gY29uZmlnIC0gSGlnaGNoYXJ0cy1yZWxhdGVkIGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxyXG4gKiBAcGFyYW0ge29iamVjdH0gZmV0Y2hlZE1vZHVsZXMgLSBBbiBvYmplY3QgdGhhdCBjb250YWlucyBtYXBwZWQgbmFtZXMgb2ZcclxuICogZmV0Y2hlZCBIaWdoY2hhcnRzIG1vZHVsZXMgdG8gdXNlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIGFuIGVycm9yIG9jY3VycyB3aGlsZSB3cml0aW5nXHJcbiAqIHRoZSBjYWNoZSBtYW5pZmVzdC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBzYXZlQ29uZmlnVG9NYW5pZmVzdCA9IGFzeW5jIChjb25maWcsIGZldGNoZWRNb2R1bGVzKSA9PiB7XHJcbiAgY29uc3QgbmV3TWFuaWZlc3QgPSB7XHJcbiAgICB2ZXJzaW9uOiBjb25maWcudmVyc2lvbixcclxuICAgIG1vZHVsZXM6IGZldGNoZWRNb2R1bGVzIHx8IHt9XHJcbiAgfTtcclxuXHJcbiAgLy8gVXBkYXRlIGNhY2hlIG9iamVjdCB3aXRoIHRoZSBjdXJyZW50IG1vZHVsZXNcclxuICBjYWNoZS5hY3RpdmVNYW5pZmVzdCA9IG5ld01hbmlmZXN0O1xyXG5cclxuICBsb2coMywgJ1tjYWNoZV0gV3JpdGluZyBhIG5ldyBtYW5pZmVzdC4nKTtcclxuICB0cnkge1xyXG4gICAgd3JpdGVGaWxlU3luYyhcclxuICAgICAgam9pbihfX2Rpcm5hbWUsIGNvbmZpZy5jYWNoZVBhdGgsICdtYW5pZmVzdC5qc29uJyksXHJcbiAgICAgIEpTT04uc3RyaW5naWZ5KG5ld01hbmlmZXN0KSxcclxuICAgICAgJ3V0ZjgnXHJcbiAgICApO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1tjYWNoZV0gRXJyb3Igd3JpdGluZyB0aGUgY2FjaGUgbWFuaWZlc3QuJykuc2V0RXJyb3IoXHJcbiAgICAgIGVycm9yXHJcbiAgICApO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBGZXRjaGVzIGEgc2luZ2xlIHNjcmlwdCBhbmQgdXBkYXRlcyB0aGUgZmV0Y2hlZE1vZHVsZXMgYWNjb3JkaW5nbHkuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBzY3JpcHQgLSBBIHBhdGggdG8gc2NyaXB0IHRvIGdldC5cclxuICogQHBhcmFtIHtPYmplY3R9IHJlcXVlc3RPcHRpb25zIC0gQWRkaXRpb25hbCBvcHRpb25zIGZvciB0aGUgcHJveHkgYWdlbnRcclxuICogdG8gdXNlIGZvciBhIHJlcXVlc3QuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBmZXRjaGVkTW9kdWxlcyAtIEFuIG9iamVjdCB3aGljaCB0cmFja3Mgd2hpY2ggSGlnaGNoYXJ0c1xyXG4gKiBtb2R1bGVzIGhhdmUgYmVlbiBmZXRjaGVkLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IHNob3VsZFRocm93RXJyb3IgLSBBIGZsYWcgdG8gaW5kaWNhdGUgaWYgdGhlIGVycm9yIHNob3VsZCBiZVxyXG4gKiB0aHJvd24uIFRoaXMgc2hvdWxkIGJlIHVzZWQgb25seSBmb3IgdGhlIGNvcmUgc2NyaXB0cy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gQSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgdGV4dCByZXByZXNlbnRhdGlvblxyXG4gKiBvZiB0aGUgZmV0Y2hlZCBzY3JpcHQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgdGhlcmUgaXMgYSBwcm9ibGVtIHdpdGhcclxuICogZmV0Y2hpbmcgdGhlIHNjcmlwdC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBmZXRjaEFuZFByb2Nlc3NTY3JpcHQgPSBhc3luYyAoXHJcbiAgc2NyaXB0LFxyXG4gIHJlcXVlc3RPcHRpb25zLFxyXG4gIGZldGNoZWRNb2R1bGVzLFxyXG4gIHNob3VsZFRocm93RXJyb3IgPSBmYWxzZVxyXG4pID0+IHtcclxuICAvLyBHZXQgcmlkIG9mIHRoZSAuanMgZnJvbSB0aGUgY3VzdG9tIHN0cmluZ3NcclxuICBpZiAoc2NyaXB0LmVuZHNXaXRoKCcuanMnKSkge1xyXG4gICAgc2NyaXB0ID0gc2NyaXB0LnN1YnN0cmluZygwLCBzY3JpcHQubGVuZ3RoIC0gMyk7XHJcbiAgfVxyXG5cclxuICBsb2coNCwgYFtjYWNoZV0gRmV0Y2hpbmcgc2NyaXB0IC0gJHtzY3JpcHR9LmpzYCk7XHJcblxyXG4gIC8vIEZldGNoIHRoZSBzY3JpcHRcclxuICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZldGNoKGAke3NjcmlwdH0uanNgLCByZXF1ZXN0T3B0aW9ucyk7XHJcblxyXG4gIC8vIElmIE9LLCByZXR1cm4gaXRzIHRleHQgcmVwcmVzZW50YXRpb25cclxuICBpZiAocmVzcG9uc2Uuc3RhdHVzQ29kZSA9PT0gMjAwICYmIHR5cGVvZiByZXNwb25zZS50ZXh0ID09ICdzdHJpbmcnKSB7XHJcbiAgICBpZiAoZmV0Y2hlZE1vZHVsZXMpIHtcclxuICAgICAgY29uc3QgbW9kdWxlTmFtZSA9IGV4dHJhY3RNb2R1bGVOYW1lKHNjcmlwdCk7XHJcbiAgICAgIGZldGNoZWRNb2R1bGVzW21vZHVsZU5hbWVdID0gMTtcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gcmVzcG9uc2UudGV4dDtcclxuICB9XHJcblxyXG4gIGlmIChzaG91bGRUaHJvd0Vycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgIGBDb3VsZCBub3QgZmV0Y2ggdGhlICR7c2NyaXB0fS5qcy4gVGhlIHNjcmlwdCBtaWdodCBub3QgZXhpc3QgaW4gdGhlIHJlcXVlc3RlZCB2ZXJzaW9uIChzdGF0dXMgY29kZTogJHtyZXNwb25zZS5zdGF0dXNDb2RlfSkuYFxyXG4gICAgKS5zZXRFcnJvcihyZXNwb25zZSk7XHJcbiAgfSBlbHNlIHtcclxuICAgIGxvZyhcclxuICAgICAgMixcclxuICAgICAgYFtjYWNoZV0gQ291bGQgbm90IGZldGNoIHRoZSAke3NjcmlwdH0uanMuIFRoZSBzY3JpcHQgbWlnaHQgbm90IGV4aXN0IGluIHRoZSByZXF1ZXN0ZWQgdmVyc2lvbi5gXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgcmV0dXJuICcnO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEZldGNoZXMgSGlnaGNoYXJ0cyBzY3JpcHRzIGFuZCBjdXN0b21TY3JpcHRzIGZyb20gdGhlIGdpdmVuIENETnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBjb3JlU2NyaXB0cyAtIEFycmF5IG9mIEhpZ2hjaGFydHMgY29yZSBzY3JpcHRzIHRvIGZldGNoLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gbW9kdWxlU2NyaXB0cyAtIEFycmF5IG9mIEhpZ2hjaGFydHMgbW9kdWxlcyB0byBmZXRjaC5cclxuICogQHBhcmFtIHtzdHJpbmd9IGN1c3RvbVNjcmlwdHMgLSBBcnJheSBvZiBjdXN0b20gc2NyaXB0IHBhdGhzIHRvIGZldGNoXHJcbiAqIChmdWxsIFVSTHMpLlxyXG4gKiBAcGFyYW0ge29iamVjdH0gcHJveHlPcHRpb25zIC0gT3B0aW9ucyBmb3IgdGhlIHByb3h5IGFnZW50IHRvIHVzZSBmb3JcclxuICogYSByZXF1ZXN0LlxyXG4gKiBAcGFyYW0ge29iamVjdH0gZmV0Y2hlZE1vZHVsZXMgLSBBbiBvYmplY3Qgd2hpY2ggdHJhY2tzIHdoaWNoIEhpZ2hjaGFydHNcclxuICogbW9kdWxlcyBoYXZlIGJlZW4gZmV0Y2hlZC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gVGhlIGZldGNoZWQgc2NyaXB0cyBjb250ZW50IGpvaW5lZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBmZXRjaFNjcmlwdHMgPSBhc3luYyAoXHJcbiAgY29yZVNjcmlwdHMsXHJcbiAgbW9kdWxlU2NyaXB0cyxcclxuICBjdXN0b21TY3JpcHRzLFxyXG4gIHByb3h5T3B0aW9ucyxcclxuICBmZXRjaGVkTW9kdWxlc1xyXG4pID0+IHtcclxuICAvLyBDb25maWd1cmUgcHJveHkgaWYgZXhpc3RzXHJcbiAgbGV0IHByb3h5QWdlbnQ7XHJcbiAgY29uc3QgcHJveHlIb3N0ID0gcHJveHlPcHRpb25zLmhvc3Q7XHJcbiAgY29uc3QgcHJveHlQb3J0ID0gcHJveHlPcHRpb25zLnBvcnQ7XHJcblxyXG4gIC8vIFRyeSB0byBjcmVhdGUgYSBQcm94eSBBZ2VudFxyXG4gIGlmIChwcm94eUhvc3QgJiYgcHJveHlQb3J0KSB7XHJcbiAgICB0cnkge1xyXG4gICAgICBwcm94eUFnZW50ID0gbmV3IEh0dHBzUHJveHlBZ2VudCh7XHJcbiAgICAgICAgaG9zdDogcHJveHlIb3N0LFxyXG4gICAgICAgIHBvcnQ6IHByb3h5UG9ydFxyXG4gICAgICB9KTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW2NhY2hlXSBDb3VsZCBub3QgY3JlYXRlIGEgUHJveHkgQWdlbnQuJykuc2V0RXJyb3IoXHJcbiAgICAgICAgZXJyb3JcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIElmIGV4aXN0cywgYWRkIHByb3h5IGFnZW50IHRvIHJlcXVlc3Qgb3B0aW9uc1xyXG4gIGNvbnN0IHJlcXVlc3RPcHRpb25zID0gcHJveHlBZ2VudFxyXG4gICAgPyB7XHJcbiAgICAgICAgYWdlbnQ6IHByb3h5QWdlbnQsXHJcbiAgICAgICAgdGltZW91dDogZW52cy5TRVJWRVJfUFJPWFlfVElNRU9VVFxyXG4gICAgICB9XHJcbiAgICA6IHt9O1xyXG5cclxuICBjb25zdCBhbGxGZXRjaFByb21pc2VzID0gW1xyXG4gICAgLi4uY29yZVNjcmlwdHMubWFwKChzY3JpcHQpID0+XHJcbiAgICAgIGZldGNoQW5kUHJvY2Vzc1NjcmlwdChgJHtzY3JpcHR9YCwgcmVxdWVzdE9wdGlvbnMsIGZldGNoZWRNb2R1bGVzLCB0cnVlKVxyXG4gICAgKSxcclxuICAgIC4uLm1vZHVsZVNjcmlwdHMubWFwKChzY3JpcHQpID0+XHJcbiAgICAgIGZldGNoQW5kUHJvY2Vzc1NjcmlwdChgJHtzY3JpcHR9YCwgcmVxdWVzdE9wdGlvbnMsIGZldGNoZWRNb2R1bGVzKVxyXG4gICAgKSxcclxuICAgIC4uLmN1c3RvbVNjcmlwdHMubWFwKChzY3JpcHQpID0+XHJcbiAgICAgIGZldGNoQW5kUHJvY2Vzc1NjcmlwdChgJHtzY3JpcHR9YCwgcmVxdWVzdE9wdGlvbnMpXHJcbiAgICApXHJcbiAgXTtcclxuXHJcbiAgY29uc3QgZmV0Y2hlZFNjcmlwdHMgPSBhd2FpdCBQcm9taXNlLmFsbChhbGxGZXRjaFByb21pc2VzKTtcclxuICByZXR1cm4gZmV0Y2hlZFNjcmlwdHMuam9pbignO1xcbicpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFVwZGF0ZXMgdGhlIGxvY2FsIGNhY2hlIHdpdGggSGlnaGNoYXJ0cyBzY3JpcHRzIGFuZCB0aGVpciB2ZXJzaW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBPYmplY3QgY29udGFpbmluZyBhbGwgb3B0aW9ucy5cclxuICogQHBhcmFtIHtzdHJpbmd9IHNvdXJjZVBhdGggLSBUaGUgcGF0aCB0byB0aGUgc291cmNlIGZpbGUgaW4gdGhlIGNhY2hlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxvYmplY3Q+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIGFuIG9iamVjdCByZXByZXNlbnRpbmdcclxuICogdGhlIGZldGNoZWQgbW9kdWxlcy5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiB0aGVyZSBpcyBhbiBpc3N1ZSB1cGRhdGluZ1xyXG4gKiB0aGUgbG9jYWwgSGlnaGNoYXJ0cyBjYWNoZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCB1cGRhdGVDYWNoZSA9IGFzeW5jIChcclxuICBoaWdoY2hhcnRzT3B0aW9ucyxcclxuICBwcm94eU9wdGlvbnMsXHJcbiAgc291cmNlUGF0aFxyXG4pID0+IHtcclxuICBjb25zdCB2ZXJzaW9uID0gaGlnaGNoYXJ0c09wdGlvbnMudmVyc2lvbjtcclxuICBjb25zdCBoY1ZlcnNpb24gPSB2ZXJzaW9uID09PSAnbGF0ZXN0JyB8fCAhdmVyc2lvbiA/ICcnIDogYCR7dmVyc2lvbn0vYDtcclxuICBjb25zdCBjZG5VUkwgPSBoaWdoY2hhcnRzT3B0aW9ucy5jZG5VUkwgfHwgY2FjaGUuY2RuVVJMO1xyXG5cclxuICBsb2coXHJcbiAgICAzLFxyXG4gICAgYFtjYWNoZV0gVXBkYXRpbmcgY2FjaGUgdmVyc2lvbiB0byBIaWdoY2hhcnRzOiAke2hjVmVyc2lvbiB8fCAnbGF0ZXN0J30uYFxyXG4gICk7XHJcblxyXG4gIGNvbnN0IGZldGNoZWRNb2R1bGVzID0ge307XHJcbiAgdHJ5IHtcclxuICAgIGNhY2hlLnNvdXJjZXMgPSBhd2FpdCBmZXRjaFNjcmlwdHMoXHJcbiAgICAgIFtcclxuICAgICAgICAuLi5oaWdoY2hhcnRzT3B0aW9ucy5jb3JlU2NyaXB0cy5tYXAoKGMpID0+IGAke2NkblVSTH0ke2hjVmVyc2lvbn0ke2N9YClcclxuICAgICAgXSxcclxuICAgICAgW1xyXG4gICAgICAgIC4uLmhpZ2hjaGFydHNPcHRpb25zLm1vZHVsZVNjcmlwdHMubWFwKChtKSA9PlxyXG4gICAgICAgICAgbSA9PT0gJ21hcCdcclxuICAgICAgICAgICAgPyBgJHtjZG5VUkx9bWFwcy8ke2hjVmVyc2lvbn1tb2R1bGVzLyR7bX1gXHJcbiAgICAgICAgICAgIDogYCR7Y2RuVVJMfSR7aGNWZXJzaW9ufW1vZHVsZXMvJHttfWBcclxuICAgICAgICApLFxyXG4gICAgICAgIC4uLmhpZ2hjaGFydHNPcHRpb25zLmluZGljYXRvclNjcmlwdHMubWFwKFxyXG4gICAgICAgICAgKGkpID0+IGAke2NkblVSTH1zdG9jay8ke2hjVmVyc2lvbn1pbmRpY2F0b3JzLyR7aX1gXHJcbiAgICAgICAgKVxyXG4gICAgICBdLFxyXG4gICAgICBoaWdoY2hhcnRzT3B0aW9ucy5jdXN0b21TY3JpcHRzLFxyXG4gICAgICBwcm94eU9wdGlvbnMsXHJcbiAgICAgIGZldGNoZWRNb2R1bGVzXHJcbiAgICApO1xyXG5cclxuICAgIGNhY2hlLmhjVmVyc2lvbiA9IGV4dHJhY3RWZXJzaW9uKGNhY2hlKTtcclxuXHJcbiAgICAvLyBTYXZlIHRoZSBmZXRjaGVkIG1vZHVsZXMgaW50byBjYWNoZXMnIHNvdXJjZSBKU09OXHJcbiAgICB3cml0ZUZpbGVTeW5jKHNvdXJjZVBhdGgsIGNhY2hlLnNvdXJjZXMpO1xyXG4gICAgcmV0dXJuIGZldGNoZWRNb2R1bGVzO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbY2FjaGVdIFVuYWJsZSB0byB1cGRhdGUgdGhlIGxvY2FsIEhpZ2hjaGFydHMgY2FjaGUuJ1xyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIFVwZGF0ZXMgdGhlIEhpZ2hjaGFydHMgdmVyc2lvbiBpbiB0aGUgYXBwbGllZCBjb25maWd1cmF0aW9uIGFuZCBjaGVja3NcclxuICogdGhlIGNhY2hlIGZvciB0aGUgbmV3IHZlcnNpb24uXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBuZXdWZXJzaW9uIC0gVGhlIG5ldyBIaWdoY2hhcnRzIHZlcnNpb24gdG8gYmUgYXBwbGllZC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8KG9iamVjdHxib29sZWFuKT59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIHVwZGF0ZWRcclxuICogY29uZmlndXJhdGlvbiB3aXRoIHRoZSBuZXcgdmVyc2lvbiwgb3IgZmFsc2UgaWYgbm8gYXBwbGllZCBjb25maWd1cmF0aW9uXHJcbiAqIGV4aXN0cy5cclxuICovXHJcbmV4cG9ydCBjb25zdCB1cGRhdGVWZXJzaW9uID0gYXN5bmMgKG5ld1ZlcnNpb24pID0+IHtcclxuICBjb25zdCBvcHRpb25zID0gZ2V0T3B0aW9ucygpO1xyXG4gIGlmIChvcHRpb25zPy5oaWdoY2hhcnRzKSB7XHJcbiAgICBvcHRpb25zLmhpZ2hjaGFydHMudmVyc2lvbiA9IG5ld1ZlcnNpb247XHJcbiAgfVxyXG4gIGF3YWl0IGNoZWNrQW5kVXBkYXRlQ2FjaGUob3B0aW9ucyk7XHJcbn07XHJcblxyXG4vKipcclxuICogQ2hlY2tzIHRoZSBjYWNoZSBmb3IgSGlnaGNoYXJ0cyBkZXBlbmRlbmNpZXMsIHVwZGF0ZXMgdGhlIGNhY2hlIGlmIG5lZWRlZCxcclxuICogYW5kIGxvYWRzIHRoZSBzb3VyY2VzLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIE9iamVjdCBjb250YWluaW5nIGFsbCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgY2FjaGUgaXMgY2hlY2tlZFxyXG4gKiBhbmQgdXBkYXRlZC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiB0aGVyZSBpcyBhbiBpc3N1ZSB1cGRhdGluZ1xyXG4gKiBvciByZWFkaW5nIHRoZSBjYWNoZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBjaGVja0FuZFVwZGF0ZUNhY2hlID0gYXN5bmMgKG9wdGlvbnMpID0+IHtcclxuICBjb25zdCB7IGhpZ2hjaGFydHMsIHNlcnZlciB9ID0gb3B0aW9ucztcclxuICBjb25zdCBjYWNoZVBhdGggPSBqb2luKF9fZGlybmFtZSwgaGlnaGNoYXJ0cy5jYWNoZVBhdGgpO1xyXG5cclxuICBsZXQgZmV0Y2hlZE1vZHVsZXM7XHJcbiAgLy8gUHJlcGFyZSBwYXRocyB0byBtYW5pZmVzdCBhbmQgc291cmNlcyBmcm9tIHRoZSAuY2FjaGUgZm9sZGVyXHJcbiAgY29uc3QgbWFuaWZlc3RQYXRoID0gam9pbihjYWNoZVBhdGgsICdtYW5pZmVzdC5qc29uJyk7XHJcbiAgY29uc3Qgc291cmNlUGF0aCA9IGpvaW4oY2FjaGVQYXRoLCAnc291cmNlcy5qcycpO1xyXG5cclxuICAvLyBDcmVhdGUgdGhlIGNhY2hlIGRlc3RpbmF0aW9uIGlmIGl0IGRvZXNuJ3QgZXhpc3QgYWxyZWFkeVxyXG4gICFleGlzdHNTeW5jKGNhY2hlUGF0aCkgJiYgbWtkaXJTeW5jKGNhY2hlUGF0aCk7XHJcblxyXG4gIC8vIEZldGNoIGFsbCB0aGUgc2NyaXB0cyBlaXRoZXIgaWYgbWFuaWZlc3QuanNvbiBkb2VzIG5vdCBleGlzdFxyXG4gIC8vIG9yIGlmIHRoZSBmb3JjZUZldGNoIG9wdGlvbiBpcyBlbmFibGVkXHJcbiAgaWYgKCFleGlzdHNTeW5jKG1hbmlmZXN0UGF0aCkgfHwgaGlnaGNoYXJ0cy5mb3JjZUZldGNoKSB7XHJcbiAgICBsb2coMywgJ1tjYWNoZV0gRmV0Y2hpbmcgYW5kIGNhY2hpbmcgSGlnaGNoYXJ0cyBkZXBlbmRlbmNpZXMuJyk7XHJcbiAgICBmZXRjaGVkTW9kdWxlcyA9IGF3YWl0IHVwZGF0ZUNhY2hlKGhpZ2hjaGFydHMsIHNlcnZlci5wcm94eSwgc291cmNlUGF0aCk7XHJcbiAgfSBlbHNlIHtcclxuICAgIGxldCByZXF1ZXN0VXBkYXRlID0gZmFsc2U7XHJcblxyXG4gICAgLy8gUmVhZCB0aGUgbWFuaWZlc3QgSlNPTlxyXG4gICAgY29uc3QgbWFuaWZlc3QgPSBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhtYW5pZmVzdFBhdGgpKTtcclxuXHJcbiAgICAvLyBDaGVjayBpZiB0aGUgbW9kdWxlcyBpcyBhbiBhcnJheSwgaWYgc28sIHdlIHJld3JpdGUgaXQgdG8gYSBtYXAgdG8gbWFrZVxyXG4gICAgLy8gaXQgZWFzaWVyIHRvIHJlc29sdmUgbW9kdWxlcy5cclxuICAgIGlmIChtYW5pZmVzdC5tb2R1bGVzICYmIEFycmF5LmlzQXJyYXkobWFuaWZlc3QubW9kdWxlcykpIHtcclxuICAgICAgY29uc3QgbW9kdWxlTWFwID0ge307XHJcbiAgICAgIG1hbmlmZXN0Lm1vZHVsZXMuZm9yRWFjaCgobSkgPT4gKG1vZHVsZU1hcFttXSA9IDEpKTtcclxuICAgICAgbWFuaWZlc3QubW9kdWxlcyA9IG1vZHVsZU1hcDtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCB7IGNvcmVTY3JpcHRzLCBtb2R1bGVTY3JpcHRzLCBpbmRpY2F0b3JTY3JpcHRzIH0gPSBoaWdoY2hhcnRzO1xyXG4gICAgY29uc3QgbnVtYmVyT2ZNb2R1bGVzID1cclxuICAgICAgY29yZVNjcmlwdHMubGVuZ3RoICsgbW9kdWxlU2NyaXB0cy5sZW5ndGggKyBpbmRpY2F0b3JTY3JpcHRzLmxlbmd0aDtcclxuXHJcbiAgICAvLyBDb21wYXJlIHRoZSBsb2FkZWQgaGlnaGNoYXJ0cyBjb25maWcgd2l0aCB0aGUgY29udGVudHMgaW4gY2FjaGUuXHJcbiAgICAvLyBJZiB0aGVyZSBhcmUgY2hhbmdlcywgZmV0Y2ggcmVxdWVzdGVkIG1vZHVsZXMgYW5kIHByb2R1Y3RzLFxyXG4gICAgLy8gYW5kIGJha2UgdGhlbSBpbnRvIGEgZ2lhbnQgYmxvYi4gU2F2ZSB0aGUgYmxvYi5cclxuICAgIGlmIChtYW5pZmVzdC52ZXJzaW9uICE9PSBoaWdoY2hhcnRzLnZlcnNpb24pIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDIsXHJcbiAgICAgICAgJ1tjYWNoZV0gQSBIaWdoY2hhcnRzIHZlcnNpb24gbWlzbWF0Y2ggaW4gdGhlIGNhY2hlLCBuZWVkIHRvIHJlLWZldGNoLidcclxuICAgICAgKTtcclxuICAgICAgcmVxdWVzdFVwZGF0ZSA9IHRydWU7XHJcbiAgICB9IGVsc2UgaWYgKE9iamVjdC5rZXlzKG1hbmlmZXN0Lm1vZHVsZXMgfHwge30pLmxlbmd0aCAhPT0gbnVtYmVyT2ZNb2R1bGVzKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICAyLFxyXG4gICAgICAgICdbY2FjaGVdIFRoZSBjYWNoZSBhbmQgdGhlIHJlcXVlc3RlZCBtb2R1bGVzIGRvIG5vdCBtYXRjaCwgbmVlZCB0byByZS1mZXRjaC4nXHJcbiAgICAgICk7XHJcbiAgICAgIHJlcXVlc3RVcGRhdGUgPSB0cnVlO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gQ2hlY2sgZWFjaCBtb2R1bGUsIGlmIGFueXRoaW5nIGlzIG1pc3NpbmcgcmVmZXRjaCBldmVyeXRoaW5nXHJcbiAgICAgIHJlcXVlc3RVcGRhdGUgPSAobW9kdWxlU2NyaXB0cyB8fCBbXSkuc29tZSgobW9kdWxlTmFtZSkgPT4ge1xyXG4gICAgICAgIGlmICghbWFuaWZlc3QubW9kdWxlc1ttb2R1bGVOYW1lXSkge1xyXG4gICAgICAgICAgbG9nKFxyXG4gICAgICAgICAgICAyLFxyXG4gICAgICAgICAgICBgW2NhY2hlXSBUaGUgJHttb2R1bGVOYW1lfSBpcyBtaXNzaW5nIGluIHRoZSBjYWNoZSwgbmVlZCB0byByZS1mZXRjaC5gXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgICAgfVxyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAocmVxdWVzdFVwZGF0ZSkge1xyXG4gICAgICBmZXRjaGVkTW9kdWxlcyA9IGF3YWl0IHVwZGF0ZUNhY2hlKGhpZ2hjaGFydHMsIHNlcnZlci5wcm94eSwgc291cmNlUGF0aCk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBsb2coMywgJ1tjYWNoZV0gRGVwZW5kZW5jeSBjYWNoZSBpcyB1cCB0byBkYXRlLCBwcm9jZWVkaW5nLicpO1xyXG5cclxuICAgICAgLy8gTG9hZCB0aGUgc291cmNlc1xyXG4gICAgICBjYWNoZS5zb3VyY2VzID0gcmVhZEZpbGVTeW5jKHNvdXJjZVBhdGgsICd1dGY4Jyk7XHJcblxyXG4gICAgICAvLyBHZXQgY3VycmVudCBtb2R1bGVzIG1hcFxyXG4gICAgICBmZXRjaGVkTW9kdWxlcyA9IG1hbmlmZXN0Lm1vZHVsZXM7XHJcblxyXG4gICAgICBjYWNoZS5oY1ZlcnNpb24gPSBleHRyYWN0VmVyc2lvbihjYWNoZSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBGaW5hbGx5LCBzYXZlIHRoZSBuZXcgbWFuaWZlc3QsIHdoaWNoIGlzIGJhc2ljYWxseSBvdXIgY3VycmVudCBjb25maWdcclxuICAvLyBpbiBhIHNsaWdodGx5IGRpZmZlcmVudCBmb3JtYXRcclxuICBhd2FpdCBzYXZlQ29uZmlnVG9NYW5pZmVzdChoaWdoY2hhcnRzLCBmZXRjaGVkTW9kdWxlcyk7XHJcbn07XHJcblxyXG5leHBvcnQgY29uc3QgZ2V0Q2FjaGVQYXRoID0gKCkgPT5cclxuICBqb2luKF9fZGlybmFtZSwgZ2V0T3B0aW9ucygpLmhpZ2hjaGFydHMuY2FjaGVQYXRoKTtcclxuXHJcbmV4cG9ydCBjb25zdCBnZXRDYWNoZSA9ICgpID0+IGNhY2hlO1xyXG5cclxuZXhwb3J0IGNvbnN0IGhpZ2hjaGFydHMgPSAoKSA9PiBjYWNoZS5zb3VyY2VzO1xyXG5cclxuZXhwb3J0IGNvbnN0IHZlcnNpb24gPSAoKSA9PiBjYWNoZS5oY1ZlcnNpb247XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgY2hlY2tBbmRVcGRhdGVDYWNoZSxcclxuICBnZXRDYWNoZVBhdGgsXHJcbiAgdXBkYXRlVmVyc2lvbixcclxuICBnZXRDYWNoZSxcclxuICBoaWdoY2hhcnRzLFxyXG4gIHZlcnNpb25cclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKiBlc2xpbnQtZGlzYWJsZSBuby11bmRlZiAqL1xyXG5cclxuLyoqXHJcbiAqIFNldHRpbmcgdGhlIGFuaW1PYmplY3QuIENhbGxlZCB3aGVuIGluaXRpbmcgdGhlIHBhZ2UuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gc2V0dXBIaWdoY2hhcnRzKCkge1xyXG4gIEhpZ2hjaGFydHMuYW5pbU9iamVjdCA9IGZ1bmN0aW9uICgpIHtcclxuICAgIHJldHVybiB7IGR1cmF0aW9uOiAwIH07XHJcbiAgfTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgdGhlIGFjdHVhbCBjaGFydC5cclxuICpcclxuICogQHBhcmFtIHtvYmplY3R9IGNoYXJ0T3B0aW9ucyAtIFRoZSBvcHRpb25zIGZvciB0aGUgSGlnaGNoYXJ0cyBjaGFydC5cclxuICogQHBhcmFtIHtvYmplY3R9IG9wdGlvbnMgLSBUaGUgZXhwb3J0IG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gZGlzcGxheUVycm9ycyAtIEEgZmxhZyBpbmRpY2F0aW5nIHdoZXRoZXIgdG8gZGlzcGxheSBlcnJvcnMuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gdHJpZ2dlckV4cG9ydChjaGFydE9wdGlvbnMsIG9wdGlvbnMsIGRpc3BsYXlFcnJvcnMpIHtcclxuICAvLyBEaXNwbGF5IGVycm9ycyBmbGFnIHRha2VuIGZyb20gY2hhcnQgb3B0aW9ucyBuYWQgZGVidWdnZXIgbW9kdWxlXHJcbiAgd2luZG93Ll9kaXNwbGF5RXJyb3JzID0gZGlzcGxheUVycm9ycztcclxuXHJcbiAgLy8gR2V0IHJlcXVpcmVkIGZ1bmN0aW9uc1xyXG4gIGNvbnN0IHsgZ2V0T3B0aW9ucywgbWVyZ2UsIHNldE9wdGlvbnMsIHdyYXAgfSA9IEhpZ2hjaGFydHM7XHJcblxyXG4gIC8vIENyZWF0ZSBhIHNlcGFyYXRlIG9iamVjdCBmb3IgYSBwb3RlbnRpYWwgc2V0T3B0aW9ucyB1c2FnZXMgaW4gb3JkZXIgdG9cclxuICAvLyBwcmV2ZW50IGZyb20gcG9sbHV0aW5nIG90aGVyIGV4cG9ydHMgdGhhdCBjYW4gaGFwcGVuIG9uIHRoZSBzYW1lIHBhZ2VcclxuICBIaWdoY2hhcnRzLnNldE9wdGlvbnNPYmogPSBtZXJnZShmYWxzZSwge30sIGdldE9wdGlvbnMoKSk7XHJcblxyXG4gIC8vIFRyaWdnZXIgY3VzdG9tIGNvZGVcclxuICBpZiAob3B0aW9ucy5jdXN0b21Mb2dpYy5jdXN0b21Db2RlKSB7XHJcbiAgICBuZXcgRnVuY3Rpb24ob3B0aW9ucy5jdXN0b21Mb2dpYy5jdXN0b21Db2RlKSgpO1xyXG4gIH1cclxuXHJcbiAgLy8gQnkgZGVmYXVsdCBhbmltYXRpb24gaXMgZGlzYWJsZWRcclxuICBjb25zdCBjaGFydCA9IHtcclxuICAgIGFuaW1hdGlvbjogZmFsc2VcclxuICB9O1xyXG5cclxuICAvLyBXaGVuIHN0cmFpZ2h0IGluamVjdCwgdGhlIHNpemUgaXMgc2V0IHRocm91Z2ggQ1NTIG9ubHlcclxuICBpZiAob3B0aW9ucy5leHBvcnQuc3RySW5qKSB7XHJcbiAgICBjaGFydC5oZWlnaHQgPSBjaGFydE9wdGlvbnMuY2hhcnQuaGVpZ2h0O1xyXG4gICAgY2hhcnQud2lkdGggPSBjaGFydE9wdGlvbnMuY2hhcnQud2lkdGg7XHJcbiAgfVxyXG5cclxuICAvLyBOT1RFOiBJcyB0aGlzIHVzZWQgZm9yIGFueXRoaW5nIHVzZWZ1bD9cclxuICB3aW5kb3cuaXNSZW5kZXJDb21wbGV0ZSA9IGZhbHNlO1xyXG4gIHdyYXAoSGlnaGNoYXJ0cy5DaGFydC5wcm90b3R5cGUsICdpbml0JywgZnVuY3Rpb24gKHByb2NlZWQsIHVzZXJPcHRpb25zLCBjYikge1xyXG4gICAgLy8gT3ZlcnJpZGUgdXNlck9wdGlvbnMgd2l0aCBpbWFnZSBmcmllbmRseSBvcHRpb25zXHJcbiAgICB1c2VyT3B0aW9ucyA9IG1lcmdlKHVzZXJPcHRpb25zLCB7XHJcbiAgICAgIGV4cG9ydGluZzoge1xyXG4gICAgICAgIGVuYWJsZWQ6IGZhbHNlXHJcbiAgICAgIH0sXHJcbiAgICAgIHBsb3RPcHRpb25zOiB7XHJcbiAgICAgICAgc2VyaWVzOiB7XHJcbiAgICAgICAgICBsYWJlbDoge1xyXG4gICAgICAgICAgICBlbmFibGVkOiBmYWxzZVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgLyogRXhwZWN0cyB0b29sdGlwIGluIHVzZXJPcHRpb25zIHdoZW4gZm9yRXhwb3J0IGlzIHRydWUuXHJcbiAgICAgICAgaHR0cHM6Ly9naXRodWIuY29tL2hpZ2hjaGFydHMvaGlnaGNoYXJ0cy9ibG9iLzNhZDQzMGEzNTNiODA1NmI5ZTc2NGFhNGU1Y2Q2ODI4YWE0NzlkYjIvanMvcGFydHMvQ2hhcnQuanMjTDI0MVxyXG4gICAgICAgICovXHJcbiAgICAgIHRvb2x0aXA6IHt9XHJcbiAgICB9KTtcclxuXHJcbiAgICAodXNlck9wdGlvbnMuc2VyaWVzIHx8IFtdKS5mb3JFYWNoKGZ1bmN0aW9uIChzZXJpZXMpIHtcclxuICAgICAgc2VyaWVzLmFuaW1hdGlvbiA9IGZhbHNlO1xyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gQWRkIGZsYWcgdG8ga25vdyBpZiBjaGFydCByZW5kZXIgaGFzIGJlZW4gY2FsbGVkLlxyXG4gICAgaWYgKCF3aW5kb3cub25IaWdoY2hhcnRzUmVuZGVyKSB7XHJcbiAgICAgIHdpbmRvdy5vbkhpZ2hjaGFydHNSZW5kZXIgPSBIaWdoY2hhcnRzLmFkZEV2ZW50KHRoaXMsICdyZW5kZXInLCAoKSA9PiB7XHJcbiAgICAgICAgd2luZG93LmlzUmVuZGVyQ29tcGxldGUgPSB0cnVlO1xyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICBwcm9jZWVkLmFwcGx5KHRoaXMsIFt1c2VyT3B0aW9ucywgY2JdKTtcclxuICB9KTtcclxuXHJcbiAgd3JhcChIaWdoY2hhcnRzLlNlcmllcy5wcm90b3R5cGUsICdpbml0JywgZnVuY3Rpb24gKHByb2NlZWQsIGNoYXJ0LCBvcHRpb25zKSB7XHJcbiAgICBwcm9jZWVkLmFwcGx5KHRoaXMsIFtjaGFydCwgb3B0aW9uc10pO1xyXG4gIH0pO1xyXG5cclxuICAvLyBHZXQgdGhlIHVzZXIgb3B0aW9uc1xyXG4gIGNvbnN0IHVzZXJPcHRpb25zID0gb3B0aW9ucy5leHBvcnQuc3RySW5qXHJcbiAgICA/IG5ldyBGdW5jdGlvbihgcmV0dXJuICR7b3B0aW9ucy5leHBvcnQuc3RySW5qfWApKClcclxuICAgIDogY2hhcnRPcHRpb25zO1xyXG5cclxuICAvLyBNZXJnZSB0aGUgZ2xvYmFsT3B0aW9ucywgdGhlbWVPcHRpb25zLCBvcHRpb25zIGZyb20gdGhlIHdyYXBwZWRcclxuICAvLyBzZXRPcHRpb25zIGZ1bmN0aW9uIGFuZCB1c2VyIG9wdGlvbnMgdG8gY3JlYXRlIHRoZSBmaW5hbCBvcHRpb25zIG9iamVjdFxyXG4gIGNvbnN0IGZpbmFsT3B0aW9ucyA9IG1lcmdlKFxyXG4gICAgZmFsc2UsXHJcbiAgICBKU09OLnBhcnNlKG9wdGlvbnMuZXhwb3J0LnRoZW1lT3B0aW9ucyksXHJcbiAgICB1c2VyT3B0aW9ucyxcclxuICAgIC8vIFBsYWNlZCBpdCBoZXJlIGluc3RlYWQgaW4gdGhlIGluaXQgYmVjYXVzZSBvZiB0aGUgc2l6ZSBpc3N1ZXNcclxuICAgIHsgY2hhcnQgfVxyXG4gICk7XHJcblxyXG4gIGNvbnN0IGZpbmFsQ2FsbGJhY2sgPSBvcHRpb25zLmN1c3RvbUxvZ2ljLmNhbGxiYWNrXHJcbiAgICA/IG5ldyBGdW5jdGlvbihgcmV0dXJuICR7b3B0aW9ucy5jdXN0b21Mb2dpYy5jYWxsYmFja31gKSgpXHJcbiAgICA6IHVuZGVmaW5lZDtcclxuXHJcbiAgLy8gU2V0IHRoZSBnbG9iYWwgb3B0aW9ucyBpZiBleGlzdFxyXG4gIGNvbnN0IGdsb2JhbE9wdGlvbnMgPSBKU09OLnBhcnNlKG9wdGlvbnMuZXhwb3J0Lmdsb2JhbE9wdGlvbnMpO1xyXG4gIGlmIChnbG9iYWxPcHRpb25zKSB7XHJcbiAgICBzZXRPcHRpb25zKGdsb2JhbE9wdGlvbnMpO1xyXG4gIH1cclxuXHJcbiAgSGlnaGNoYXJ0c1tvcHRpb25zLmV4cG9ydC5jb25zdHIgfHwgJ2NoYXJ0J10oXHJcbiAgICAnY29udGFpbmVyJyxcclxuICAgIGZpbmFsT3B0aW9ucyxcclxuICAgIGZpbmFsQ2FsbGJhY2tcclxuICApO1xyXG5cclxuICAvLyBHZXQgdGhlIGN1cnJlbnQgZ2xvYmFsIG9wdGlvbnNcclxuICBjb25zdCBkZWZhdWx0T3B0aW9ucyA9IGdldE9wdGlvbnMoKTtcclxuXHJcbiAgLy8gQ2xlYXIgaXQganVzdCBpbiBjYXNlIChlLmcuIHRoZSBzZXRPcHRpb25zIHdhcyB1c2VkIGluIHRoZSBjdXN0b21Db2RlKVxyXG4gIGZvciAoY29uc3QgcHJvcCBpbiBkZWZhdWx0T3B0aW9ucykge1xyXG4gICAgaWYgKHR5cGVvZiBkZWZhdWx0T3B0aW9uc1twcm9wXSAhPT0gJ2Z1bmN0aW9uJykge1xyXG4gICAgICBkZWxldGUgZGVmYXVsdE9wdGlvbnNbcHJvcF07XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBTZXQgdGhlIGRlZmF1bHQgb3B0aW9ucyBiYWNrXHJcbiAgc2V0T3B0aW9ucyhIaWdoY2hhcnRzLnNldE9wdGlvbnNPYmopO1xyXG5cclxuICAvLyBFbXB0eSB0aGUgY3VzdG9tIGdsb2JhbCBvcHRpb25zIG9iamVjdFxyXG4gIEhpZ2hjaGFydHMuc2V0T3B0aW9uc09iaiA9IHt9O1xyXG59XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgcGF0aCBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCBwdXBwZXRlZXIgZnJvbSAncHVwcGV0ZWVyJztcclxuXHJcbmltcG9ydCB7IGdldENhY2hlUGF0aCB9IGZyb20gJy4vY2FjaGUuanMnO1xyXG5pbXBvcnQgeyBnZXRPcHRpb25zIH0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBzZXR1cEhpZ2hjaGFydHMgfSBmcm9tICcuL2hpZ2hjaGFydHMuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgX19kaXJuYW1lIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLy8gR2V0IHRoZSB0ZW1wbGF0ZSBmb3IgdGhlIHBhZ2VcclxuY29uc3QgdGVtcGxhdGUgPSByZWFkRmlsZVN5bmMoX19kaXJuYW1lICsgJy90ZW1wbGF0ZXMvdGVtcGxhdGUuaHRtbCcsICd1dGY4Jyk7XHJcblxyXG5sZXQgYnJvd3NlcjtcclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgdGhlIGV4aXN0aW5nIFB1cHBldGVlciBicm93c2VyIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxvYmplY3Q+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBQdXBwZXRlZXIgYnJvd3NlclxyXG4gKiBpbnN0YW5jZS5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiBubyB2YWxpZCBicm93c2VyIGhhcyBiZWVuXHJcbiAqIGNyZWF0ZWQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0KCkge1xyXG4gIGlmICghYnJvd3Nlcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbYnJvd3Nlcl0gTm8gdmFsaWQgYnJvd3NlciBoYXMgYmVlbiBjcmVhdGVkLicpO1xyXG4gIH1cclxuICByZXR1cm4gYnJvd3NlcjtcclxufVxyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYSBQdXBwZXRlZXIgYnJvd3NlciBpbnN0YW5jZSB3aXRoIHRoZSBzcGVjaWZpZWQgYXJndW1lbnRzLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0FycmF5fSBwdXBwZXRlZXJBcmdzIC0gQWRkaXRpb25hbCBhcmd1bWVudHMgZm9yIFB1cHBldGVlciBsYXVuY2guXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPG9iamVjdD59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIFB1cHBldGVlciBicm93c2VyXHJcbiAqIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIG1heCByZXRyaWVzIHRvIG9wZW4gYSBicm93c2VyXHJcbiAqIGluc3RhbmNlIGFyZSByZWFjaGVkLCBvciBpZiBubyBicm93c2VyIGluc3RhbmNlIGlzIGZvdW5kIGFmdGVyIHJldHJpZXMuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY3JlYXRlKHB1cHBldGVlckFyZ3MpIHtcclxuICAvLyBHZXQgZGVidWcgYW5kIG90aGVyIG9wdGlvbnNcclxuICBjb25zdCB7IGRlYnVnLCBvdGhlciB9ID0gZ2V0T3B0aW9ucygpO1xyXG5cclxuICAvLyBHZXQgdGhlIGRlYnVnIG9wdGlvbnNcclxuICBjb25zdCB7IGVuYWJsZTogZW5hYmxlZERlYnVnLCAuLi5kZWJ1Z09wdGlvbnMgfSA9IGRlYnVnO1xyXG5cclxuICBjb25zdCBsYXVuY2hPcHRpb25zID0ge1xyXG4gICAgaGVhZGxlc3M6IG90aGVyLmJyb3dzZXJTaGVsbE1vZGUgPyAnc2hlbGwnIDogdHJ1ZSxcclxuICAgIHVzZXJEYXRhRGlyOiAnLi90bXAvJyxcclxuICAgIGFyZ3M6IHB1cHBldGVlckFyZ3MsXHJcbiAgICBoYW5kbGVTSUdJTlQ6IGZhbHNlLFxyXG4gICAgaGFuZGxlU0lHVEVSTTogZmFsc2UsXHJcbiAgICBoYW5kbGVTSUdIVVA6IGZhbHNlLFxyXG4gICAgd2FpdEZvckluaXRpYWxQYWdlOiBmYWxzZSxcclxuICAgIGRlZmF1bHRWaWV3cG9ydDogbnVsbCxcclxuICAgIC4uLihlbmFibGVkRGVidWcgJiYgZGVidWdPcHRpb25zKVxyXG4gIH07XHJcblxyXG4gIC8vIENyZWF0ZSBhIGJyb3dzZXJcclxuICBpZiAoIWJyb3dzZXIpIHtcclxuICAgIGxldCB0cnlDb3VudCA9IDA7XHJcblxyXG4gICAgY29uc3Qgb3BlbiA9IGFzeW5jICgpID0+IHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFticm93c2VyXSBBdHRlbXB0aW5nIHRvIGdldCBhIGJyb3dzZXIgaW5zdGFuY2UgKHRyeSAkeysrdHJ5Q291bnR9KS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgICBicm93c2VyID0gYXdhaXQgcHVwcGV0ZWVyLmxhdW5jaChsYXVuY2hPcHRpb25zKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgICAxLFxyXG4gICAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgICAnW2Jyb3dzZXJdIEZhaWxlZCB0byBsYXVuY2ggYSBicm93c2VyIGluc3RhbmNlLidcclxuICAgICAgICApO1xyXG5cclxuICAgICAgICAvLyBSZXRyeSB0byBsYXVuY2ggYnJvd3NlciB1bnRpbCByZWFjaGluZyBtYXggYXR0ZW1wdHNcclxuICAgICAgICBpZiAodHJ5Q291bnQgPCAyNSkge1xyXG4gICAgICAgICAgbG9nKDMsIGBbYnJvd3Nlcl0gUmV0cnkgdG8gb3BlbiBhIGJyb3dzZXIgKCR7dHJ5Q291bnR9IG91dCBvZiAyNSkuYCk7XHJcbiAgICAgICAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzcG9uc2UpID0+IHNldFRpbWVvdXQocmVzcG9uc2UsIDQwMDApKTtcclxuICAgICAgICAgIGF3YWl0IG9wZW4oKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9O1xyXG5cclxuICAgIHRyeSB7XHJcbiAgICAgIGF3YWl0IG9wZW4oKTtcclxuXHJcbiAgICAgIC8vIFNoZWxsIG1vZGUgaW5mb3JtXHJcbiAgICAgIGlmIChsYXVuY2hPcHRpb25zLmhlYWRsZXNzID09PSAnc2hlbGwnKSB7XHJcbiAgICAgICAgbG9nKDMsIGBbYnJvd3Nlcl0gTGF1bmNoZWQgYnJvd3NlciBpbiBzaGVsbCBtb2RlLmApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBEZWJ1ZyBtb2RlIGluZm9ybVxyXG4gICAgICBpZiAoZW5hYmxlZERlYnVnKSB7XHJcbiAgICAgICAgbG9nKDMsIGBbYnJvd3Nlcl0gTGF1bmNoZWQgYnJvd3NlciBpbiBkZWJ1ZyBtb2RlLmApO1xyXG4gICAgICB9XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ1ticm93c2VyXSBNYXhpbXVtIHJldHJpZXMgdG8gb3BlbiBhIGJyb3dzZXIgaW5zdGFuY2UgcmVhY2hlZC4nXHJcbiAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgfVxyXG5cclxuICAgIGlmICghYnJvd3Nlcikge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1ticm93c2VyXSBDYW5ub3QgZmluZCBhIGJyb3dzZXIgdG8gb3Blbi4nKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiBhIGJyb3dzZXIgcHJvbWlzZVxyXG4gIHJldHVybiBicm93c2VyO1xyXG59XHJcblxyXG4vKipcclxuICogQ2xvc2VzIHRoZSBQdXBwZXRlZXIgYnJvd3NlciBpbnN0YW5jZSBpZiBpdCBpcyBjb25uZWN0ZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPGJvb2xlYW4+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIHRydWUgYWZ0ZXIgdGhlIGJyb3dzZXJcclxuICogaXMgY2xvc2VkLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNsb3NlKCkge1xyXG4gIC8vIENsb3NlIHRoZSBicm93c2VyIHdoZW4gY29ubm5lY3RlZFxyXG4gIGlmIChicm93c2VyPy5jb25uZWN0ZWQpIHtcclxuICAgIGF3YWl0IGJyb3dzZXIuY2xvc2UoKTtcclxuICB9XHJcbiAgbG9nKDQsICdbYnJvd3Nlcl0gQ2xvc2VkIHRoZSBicm93c2VyLicpO1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhIG5ldyBQdXBwZXRlZXIgUGFnZSB3aXRoaW4gYW4gZXhpc3RpbmcgYnJvd3NlciBpbnN0YW5jZS5cclxuICpcclxuICogSWYgdGhlIGJyb3dzZXIgaW5zdGFuY2UgaXMgbm90IGF2YWlsYWJsZSwgcmV0dXJucyBmYWxzZS5cclxuICpcclxuICogVGhlIGZ1bmN0aW9uIGNyZWF0ZXMgYSBuZXcgcGFnZSwgZGlzYWJsZXMgY2FjaGluZywgc2V0cyBjb250ZW50IHVzaW5nXHJcbiAqIHNldFBhZ2VDb250ZW50KCksIGFuZCByZXR1cm5zIHRoZSBjcmVhdGVkIFB1cHBldGVlciBQYWdlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7KGJvb2xlYW58b2JqZWN0KX0gUmV0dXJucyBmYWxzZSBpZiB0aGUgYnJvd3NlciBpbnN0YW5jZSBpcyBub3RcclxuICogYXZhaWxhYmxlLCBvciBhIFB1cHBldGVlciBQYWdlIG9iamVjdCByZXByZXNlbnRpbmcgdGhlIG5ld2x5IGNyZWF0ZWQgcGFnZS5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBuZXdQYWdlKCkge1xyXG4gIGlmICghYnJvd3Nlcikge1xyXG4gICAgcmV0dXJuIGZhbHNlO1xyXG4gIH1cclxuXHJcbiAgLy8gQ3JlYXRlIGEgcGFnZVxyXG4gIGNvbnN0IHBhZ2UgPSBhd2FpdCBicm93c2VyLm5ld1BhZ2UoKTtcclxuXHJcbiAgLy8gRGlzYWJsZSBjYWNoZVxyXG4gIGF3YWl0IHBhZ2Uuc2V0Q2FjaGVFbmFibGVkKGZhbHNlKTtcclxuXHJcbiAgLy8gU2V0IHRoZSBjb250ZW50XHJcbiAgYXdhaXQgc2V0UGFnZUNvbnRlbnQocGFnZSk7XHJcblxyXG4gIC8vIFNldCBwYWdlIGV2ZW50c1xyXG4gIHNldFBhZ2VFdmVudHMocGFnZSk7XHJcblxyXG4gIHJldHVybiBwYWdlO1xyXG59XHJcblxyXG4vKipcclxuICogQ2xlYXJzIHRoZSBjb250ZW50IG9mIGEgUHVwcGV0ZWVyIFBhZ2UgYmFzZWQgb24gdGhlIHNwZWNpZmllZCBtb2RlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFRoZSBQdXBwZXRlZXIgUGFnZSBvYmplY3QgdG8gYmUgY2xlYXJlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBoYXJkUmVzZXQgLSBBIGZsYWcgaW5kaWNhdGluZyB0aGUgdHlwZSBvZiBjbGVhcmluZ1xyXG4gKiB0byBiZSBwZXJmb3JtZWQuIElmIHRydWUsIG5hdmlnYXRlcyB0byAnYWJvdXQ6YmxhbmsnIGFuZCByZXNldHMgY29udGVudFxyXG4gKiBhbmQgc2NyaXB0cy4gSWYgZmFsc2UsIGNsZWFycyB0aGUgYm9keSBjb250ZW50IGJ5IHNldHRpbmcgYSBwcmVkZWZpbmVkIEhUTUxcclxuICogc3RydWN0dXJlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFcnJvcn0gTG9ncyB0aHJvd24gZXJyb3IgaWYgY2xlYXJpbmcgdGhlIHBhZ2UgY29udGVudCBmYWlscy5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjbGVhclBhZ2UocGFnZSwgaGFyZFJlc2V0ID0gZmFsc2UpIHtcclxuICB0cnkge1xyXG4gICAgaWYgKCFwYWdlLmlzQ2xvc2VkKCkpIHtcclxuICAgICAgaWYgKGhhcmRSZXNldCkge1xyXG4gICAgICAgIC8vIE5hdmlnYXRlIHRvIGFib3V0OmJsYW5rXHJcbiAgICAgICAgYXdhaXQgcGFnZS5nb3RvKCdhYm91dDpibGFuaycsIHsgd2FpdFVudGlsOiAnZG9tY29udGVudGxvYWRlZCcgfSk7XHJcblxyXG4gICAgICAgIC8vIFNldCB0aGUgY29udGVudCBhbmQgYW5kIHNjcmlwdHMgYWdhaW5cclxuICAgICAgICBhd2FpdCBzZXRQYWdlQ29udGVudChwYWdlKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICAvLyBDbGVhciBib2R5IGNvbnRlbnRcclxuICAgICAgICBhd2FpdCBwYWdlLmV2YWx1YXRlKCgpID0+IHtcclxuICAgICAgICAgIGRvY3VtZW50LmJvZHkuaW5uZXJIVE1MID1cclxuICAgICAgICAgICAgJzxkaXYgaWQ9XCJjaGFydC1jb250YWluZXJcIj48ZGl2IGlkPVwiY29udGFpbmVyXCI+PC9kaXY+PC9kaXY+JztcclxuICAgICAgICB9KTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgIDIsXHJcbiAgICAgIGVycm9yLFxyXG4gICAgICAnW2Jyb3dzZXJdIENvdWxkIG5vdCBjbGVhciB0aGUgY29udGVudCBvZiB0aGUgcGFnZS4nXHJcbiAgICApO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEFkZHMgY3VzdG9tIEpTIGFuZCBDU1MgcmVzb3VyY2VzIHRvIGEgUHVwcGV0ZWVyIFBhZ2UgYmFzZWQgb24gdGhlIHNwZWNpZmllZFxyXG4gKiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFRoZSBQdXBwZXRlZXIgUGFnZSBvYmplY3QgdG8gd2hpY2ggcmVzb3VyY2VzIHdpbGwgYmVcclxuICogYWRkZWQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gQWxsIG9wdGlvbnMgYW5kIGNvbmZpZ3VyYXRpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPEFycmF5PE9iamVjdD4+fSAtIFByb21pc2UgcmVzb2x2aW5nIHRvIGFuIGFycmF5IG9mIGluamVjdGVkXHJcbiAqIHJlc291cmNlcy5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBhZGRQYWdlUmVzb3VyY2VzKHBhZ2UsIG9wdGlvbnMpIHtcclxuICAvLyBJbmplY3RlZCByZXNvdXJjZXMgYXJyYXlcclxuICBjb25zdCBpbmplY3RlZFJlc291cmNlcyA9IFtdO1xyXG5cclxuICAvLyBVc2UgcmVzb3VyY2VzXHJcbiAgY29uc3QgcmVzb3VyY2VzID0gb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXM7XHJcbiAgaWYgKHJlc291cmNlcykge1xyXG4gICAgY29uc3QgaW5qZWN0ZWRKcyA9IFtdO1xyXG5cclxuICAgIC8vIExvYWQgY3VzdG9tIEpTIGNvZGVcclxuICAgIGlmIChyZXNvdXJjZXMuanMpIHtcclxuICAgICAgaW5qZWN0ZWRKcy5wdXNoKHtcclxuICAgICAgICBjb250ZW50OiByZXNvdXJjZXMuanNcclxuICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTG9hZCBzY3JpcHRzIGZyb20gYWxsIGN1c3RvbSBmaWxlc1xyXG4gICAgaWYgKHJlc291cmNlcy5maWxlcykge1xyXG4gICAgICBmb3IgKGNvbnN0IGZpbGUgb2YgcmVzb3VyY2VzLmZpbGVzKSB7XHJcbiAgICAgICAgY29uc3QgaXNMb2NhbCA9ICFmaWxlLnN0YXJ0c1dpdGgoJ2h0dHAnKSA/IHRydWUgOiBmYWxzZTtcclxuXHJcbiAgICAgICAgLy8gQWRkIGVhY2ggY3VzdG9tIHNjcmlwdCBmcm9tIHJlc291cmNlcycgZmlsZXNcclxuICAgICAgICBpbmplY3RlZEpzLnB1c2goXHJcbiAgICAgICAgICBpc0xvY2FsXHJcbiAgICAgICAgICAgID8ge1xyXG4gICAgICAgICAgICAgICAgY29udGVudDogcmVhZEZpbGVTeW5jKGZpbGUsICd1dGY4JylcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIDoge1xyXG4gICAgICAgICAgICAgICAgdXJsOiBmaWxlXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBmb3IgKGNvbnN0IGpzUmVzb3VyY2Ugb2YgaW5qZWN0ZWRKcykge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGluamVjdGVkUmVzb3VyY2VzLnB1c2goYXdhaXQgcGFnZS5hZGRTY3JpcHRUYWcoanNSZXNvdXJjZSkpO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgYFtleHBvcnRdIFRoZSBKUyByZXNvdXJjZSBjYW5ub3QgYmUgbG9hZGVkLmApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICBpbmplY3RlZEpzLmxlbmd0aCA9IDA7XHJcblxyXG4gICAgLy8gTG9hZCBDU1NcclxuICAgIGNvbnN0IGluamVjdGVkQ3NzID0gW107XHJcbiAgICBpZiAocmVzb3VyY2VzLmNzcykge1xyXG4gICAgICBsZXQgY3NzSW1wb3J0cyA9IHJlc291cmNlcy5jc3MubWF0Y2goL0BpbXBvcnRcXHMqKFteO10qKTsvZyk7XHJcbiAgICAgIGlmIChjc3NJbXBvcnRzKSB7XHJcbiAgICAgICAgLy8gSGFuZGxlIGNzcyBzZWN0aW9uXHJcbiAgICAgICAgZm9yIChsZXQgY3NzSW1wb3J0UGF0aCBvZiBjc3NJbXBvcnRzKSB7XHJcbiAgICAgICAgICBpZiAoY3NzSW1wb3J0UGF0aCkge1xyXG4gICAgICAgICAgICBjc3NJbXBvcnRQYXRoID0gY3NzSW1wb3J0UGF0aFxyXG4gICAgICAgICAgICAgIC5yZXBsYWNlKCd1cmwoJywgJycpXHJcbiAgICAgICAgICAgICAgLnJlcGxhY2UoJ0BpbXBvcnQnLCAnJylcclxuICAgICAgICAgICAgICAucmVwbGFjZSgvXCIvZywgJycpXHJcbiAgICAgICAgICAgICAgLnJlcGxhY2UoLycvZywgJycpXHJcbiAgICAgICAgICAgICAgLnJlcGxhY2UoLzsvLCAnJylcclxuICAgICAgICAgICAgICAucmVwbGFjZSgvXFwpL2csICcnKVxyXG4gICAgICAgICAgICAgIC50cmltKCk7XHJcblxyXG4gICAgICAgICAgICAvLyBBZGQgZWFjaCBjdXN0b20gY3NzIGZyb20gcmVzb3VyY2VzXHJcbiAgICAgICAgICAgIGlmIChjc3NJbXBvcnRQYXRoLnN0YXJ0c1dpdGgoJ2h0dHAnKSkge1xyXG4gICAgICAgICAgICAgIGluamVjdGVkQ3NzLnB1c2goe1xyXG4gICAgICAgICAgICAgICAgdXJsOiBjc3NJbXBvcnRQYXRoXHJcbiAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgIH0gZWxzZSBpZiAob3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0ZpbGVSZXNvdXJjZXMpIHtcclxuICAgICAgICAgICAgICBpbmplY3RlZENzcy5wdXNoKHtcclxuICAgICAgICAgICAgICAgIHBhdGg6IHBhdGguam9pbihfX2Rpcm5hbWUsIGNzc0ltcG9ydFBhdGgpXHJcbiAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIFRoZSByZXN0IG9mIHRoZSBDU1Mgc2VjdGlvbiB3aWxsIGJlIGNvbnRlbnQgYnkgbm93XHJcbiAgICAgIGluamVjdGVkQ3NzLnB1c2goe1xyXG4gICAgICAgIGNvbnRlbnQ6IHJlc291cmNlcy5jc3MucmVwbGFjZSgvQGltcG9ydFxccyooW147XSopOy9nLCAnJykgfHwgJyAnXHJcbiAgICAgIH0pO1xyXG5cclxuICAgICAgZm9yIChjb25zdCBjc3NSZXNvdXJjZSBvZiBpbmplY3RlZENzcykge1xyXG4gICAgICAgIHRyeSB7XHJcbiAgICAgICAgICBpbmplY3RlZFJlc291cmNlcy5wdXNoKGF3YWl0IHBhZ2UuYWRkU3R5bGVUYWcoY3NzUmVzb3VyY2UpKTtcclxuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2V4cG9ydF0gVGhlIENTUyByZXNvdXJjZSBjYW5ub3QgYmUgbG9hZGVkLmApO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgICBpbmplY3RlZENzcy5sZW5ndGggPSAwO1xyXG4gICAgfVxyXG4gIH1cclxuICByZXR1cm4gaW5qZWN0ZWRSZXNvdXJjZXM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDbGVhcnMgb3V0IGFsbCBzdGF0ZSBzZXQgb24gdGhlIHBhZ2Ugd2l0aCBhZGRTY3JpcHRUYWcvYWRkU3R5bGVUYWcuIFJlbW92ZXNcclxuICogaW5qZWN0ZWQgcmVzb3VyY2VzIGFuZCByZXNldHMgQ1NTIGFuZCBzY3JpcHQgdGFncyBvbiB0aGUgcGFnZS4gQWRkaXRpb25hbGx5LFxyXG4gKiBpdCBkZXN0cm95cyBwcmV2aW91c2x5IGV4aXN0aW5nIGNoYXJ0cy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IGZyb20gd2hpY2ggcmVzb3VyY2VzIHdpbGxcclxuICogYmUgY2xlYXJlZC5cclxuICogQHBhcmFtIHtBcnJheTxPYmplY3Q+fSBpbmplY3RlZFJlc291cmNlcyAtIEFycmF5IG9mIGluamVjdGVkIHJlc291cmNlc1xyXG4gKiB0byBiZSBjbGVhcmVkLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNsZWFyUGFnZVJlc291cmNlcyhwYWdlLCBpbmplY3RlZFJlc291cmNlcykge1xyXG4gIGZvciAoY29uc3QgcmVzb3VyY2Ugb2YgaW5qZWN0ZWRSZXNvdXJjZXMpIHtcclxuICAgIGF3YWl0IHJlc291cmNlLmRpc3Bvc2UoKTtcclxuICB9XHJcblxyXG4gIC8vIERlc3Ryb3kgb2xkIGNoYXJ0cyBhZnRlciBleHBvcnQgaXMgZG9uZSBhbmQgcmVzZXQgYWxsIENTUyBhbmQgc2NyaXB0IHRhZ3NcclxuICBhd2FpdCBwYWdlLmV2YWx1YXRlKCgpID0+IHtcclxuICAgIC8vIFdlIGFyZSBub3QgZ3VhcmFudGVlZCB0aGF0IEhpZ2hjaGFydHMgaXMgbG9hZGVkLCBlLGcsIHdoZW4gZG9pbmcgU1ZHXHJcbiAgICAvLyBleHBvcnRzXHJcbiAgICBpZiAodHlwZW9mIEhpZ2hjaGFydHMgIT09ICd1bmRlZmluZWQnKSB7XHJcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICBjb25zdCBvbGRDaGFydHMgPSBIaWdoY2hhcnRzLmNoYXJ0cztcclxuXHJcbiAgICAgIC8vIENoZWNrIGluIGFueSBhbHJlYWR5IGV4aXN0aW5nIGNoYXJ0c1xyXG4gICAgICBpZiAoQXJyYXkuaXNBcnJheShvbGRDaGFydHMpICYmIG9sZENoYXJ0cy5sZW5ndGgpIHtcclxuICAgICAgICAvLyBEZXN0cm95IG9sZCBjaGFydHNcclxuICAgICAgICBmb3IgKGNvbnN0IG9sZENoYXJ0IG9mIG9sZENoYXJ0cykge1xyXG4gICAgICAgICAgb2xkQ2hhcnQgJiYgb2xkQ2hhcnQuZGVzdHJveSgpO1xyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICBIaWdoY2hhcnRzLmNoYXJ0cy5zaGlmdCgpO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgY29uc3QgWy4uLnNjcmlwdHNUb1JlbW92ZV0gPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnc2NyaXB0Jyk7XHJcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgIGNvbnN0IFssIC4uLnN0eWxlc1RvUmVtb3ZlXSA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdzdHlsZScpO1xyXG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICBjb25zdCBbLi4ubGlua3NUb1JlbW92ZV0gPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnbGluaycpO1xyXG5cclxuICAgIC8vIFJlbW92ZSB0YWdzXHJcbiAgICBmb3IgKGNvbnN0IGVsZW1lbnQgb2YgW1xyXG4gICAgICAuLi5zY3JpcHRzVG9SZW1vdmUsXHJcbiAgICAgIC4uLnN0eWxlc1RvUmVtb3ZlLFxyXG4gICAgICAuLi5saW5rc1RvUmVtb3ZlXHJcbiAgICBdKSB7XHJcbiAgICAgIGVsZW1lbnQucmVtb3ZlKCk7XHJcbiAgICB9XHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZXRzIHRoZSBjb250ZW50IGZvciBhIFB1cHBldGVlciBQYWdlIHVzaW5nIGEgcHJlZGVmaW5lZCB0ZW1wbGF0ZVxyXG4gKiBhbmQgYWRkaXRpb25hbCBzY3JpcHRzLiBBbHNvLCBzZXRzIHRoZSBwYWdlZXJyb3IgaW4gb3JkZXIgdG8gY2F0Y2hcclxuICogYW5kIGRpc3BsYXkgZXJyb3JzIGZyb20gdGhlIHdpbmRvdyBjb250ZXh0LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFRoZSBQdXBwZXRlZXIgUGFnZSBvYmplY3QgZm9yIHdoaWNoIHRoZSBjb250ZW50XHJcbiAqIGlzIGJlaW5nIHNldC5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIHNldFBhZ2VDb250ZW50KHBhZ2UpIHtcclxuICBhd2FpdCBwYWdlLnNldENvbnRlbnQodGVtcGxhdGUsIHsgd2FpdFVudGlsOiAnZG9tY29udGVudGxvYWRlZCcgfSk7XHJcblxyXG4gIC8vIEFkZCBhbGwgcmVnaXN0ZXJlZCBIaWdjaGFydHMgc2NyaXB0cywgcXVpdGUgZGVtYW5kaW5nXHJcbiAgYXdhaXQgcGFnZS5hZGRTY3JpcHRUYWcoeyBwYXRoOiBgJHtnZXRDYWNoZVBhdGgoKX0vc291cmNlcy5qc2AgfSk7XHJcblxyXG4gIC8vIFNldCB0aGUgaW5pdGlhbCBhbmltT2JqZWN0XHJcbiAgYXdhaXQgcGFnZS5ldmFsdWF0ZShzZXR1cEhpZ2hjaGFydHMpO1xyXG59XHJcblxyXG4vKipcclxuICogU2V0IGV2ZW50cyBmb3IgYSBQdXBwZXRlZXIgUGFnZS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IHRvIHNldCBldmVudHMgdG8uXHJcbiAqL1xyXG5mdW5jdGlvbiBzZXRQYWdlRXZlbnRzKHBhZ2UpIHtcclxuICAvLyBHZXQgZGVidWcgb3B0aW9uc1xyXG4gIGNvbnN0IHsgZGVidWcgfSA9IGdldE9wdGlvbnMoKTtcclxuXHJcbiAgLy8gU2V0IHRoZSBjb25zb2xlIGxpc3RlbmVyLCBpZiBuZWVkZWRcclxuICBpZiAoZGVidWcuZW5hYmxlICYmIGRlYnVnLmxpc3RlblRvQ29uc29sZSkge1xyXG4gICAgcGFnZS5vbignY29uc29sZScsIChtZXNzYWdlKSA9PiB7XHJcbiAgICAgIGNvbnNvbGUubG9nKGBbZGVidWddICR7bWVzc2FnZS50ZXh0KCl9YCk7XHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIC8vIFNldCB0aGUgcGFnZWVycm9yIGxpc3RlbmVyXHJcbiAgcGFnZS5vbigncGFnZWVycm9yJywgYXN5bmMgKGVycm9yKSA9PiB7XHJcbiAgICAvLyBUT0RPOiBDb25zaWRlciBhZGRpbmcgYSBzd2l0Y2ggaGVyZSB0aGF0IHR1cm5zIG9uIGxvZygwKSBsb2dnaW5nXHJcbiAgICAvLyBvbiBwYWdlIGVycm9ycy5cclxuICAgIGF3YWl0IHBhZ2UuJGV2YWwoXHJcbiAgICAgICcjY29udGFpbmVyJyxcclxuICAgICAgKGVsZW1lbnQsIGVycm9yTWVzc2FnZSkgPT4ge1xyXG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgIGlmICh3aW5kb3cuX2Rpc3BsYXlFcnJvcnMpIHtcclxuICAgICAgICAgIGVsZW1lbnQuaW5uZXJIVE1MID0gZXJyb3JNZXNzYWdlO1xyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgYDxoMT5DaGFydCBpbnB1dCBkYXRhIGVycm9yOiA8L2gxPiR7ZXJyb3IudG9TdHJpbmcoKX1gXHJcbiAgICApO1xyXG4gIH0pO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgZ2V0LFxyXG4gIGNyZWF0ZSxcclxuICBjbG9zZSxcclxuICBuZXdQYWdlLFxyXG4gIGNsZWFyUGFnZSxcclxuICBhZGRQYWdlUmVzb3VyY2VzLFxyXG4gIGNsZWFyUGFnZVJlc291cmNlc1xyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IGFkZFBhZ2VSZXNvdXJjZXMsIGNsZWFyUGFnZVJlc291cmNlcyB9IGZyb20gJy4vYnJvd3Nlci5qcyc7XHJcbmltcG9ydCB7IGdldENhY2hlIH0gZnJvbSAnLi9jYWNoZS5qcyc7XHJcbmltcG9ydCB7IHRyaWdnZXJFeHBvcnQgfSBmcm9tICcuL2hpZ2hjaGFydHMuanMnO1xyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcblxyXG5pbXBvcnQgc3ZnVGVtcGxhdGUgZnJvbSAnLi8uLi90ZW1wbGF0ZXMvc3ZnX2V4cG9ydC9zdmdfZXhwb3J0LmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHRoZSBjbGlwcGluZyByZWdpb24gY29vcmRpbmF0ZXMgb2YgdGhlIHNwZWNpZmllZCBwYWdlIGVsZW1lbnQgd2l0aFxyXG4gKiB0aGUgaWQgJ2NoYXJ0LWNvbnRhaW5lcicuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBQcm9taXNlIHJlc29sdmluZyB0byBhbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiB4LCB5LCB3aWR0aCwgYW5kIGhlaWdodCBwcm9wZXJ0aWVzLlxyXG4gKi9cclxuY29uc3QgZ2V0Q2xpcFJlZ2lvbiA9IChwYWdlKSA9PlxyXG4gIHBhZ2UuJGV2YWwoJyNjaGFydC1jb250YWluZXInLCAoZWxlbWVudCkgPT4ge1xyXG4gICAgY29uc3QgeyB4LCB5LCB3aWR0aCwgaGVpZ2h0IH0gPSBlbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xyXG4gICAgcmV0dXJuIHtcclxuICAgICAgeCxcclxuICAgICAgeSxcclxuICAgICAgd2lkdGgsXHJcbiAgICAgIGhlaWdodDogTWF0aC50cnVuYyhoZWlnaHQgPiAxID8gaGVpZ2h0IDogNTAwKVxyXG4gICAgfTtcclxuICB9KTtcclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGFuIGltYWdlIHVzaW5nIFB1cHBldGVlcidzIHBhZ2Ugc2NyZWVuc2hvdCBmdW5jdGlvbmFsaXR5IHdpdGhcclxuICogc3BlY2lmaWVkIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdHlwZSAtIEltYWdlIHR5cGUuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBlbmNvZGluZyAtIEltYWdlIGVuY29kaW5nLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY2xpcCAtIENsaXBwaW5nIHJlZ2lvbiBjb29yZGluYXRlcy5cclxuICogQHBhcmFtIHtudW1iZXJ9IHJhc3Rlcml6YXRpb25UaW1lb3V0IC0gVGltZW91dCBmb3IgcmFzdGVyaXphdGlvblxyXG4gKiBpbiBtaWxsaXNlY29uZHMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPEJ1ZmZlcj59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBpbWFnZSBidWZmZXIgb3IgcmVqZWN0aW5nXHJcbiAqIHdpdGggYW4gRXhwb3J0RXJyb3IgZm9yIHRpbWVvdXQuXHJcbiAqL1xyXG5jb25zdCBjcmVhdGVJbWFnZSA9IChwYWdlLCB0eXBlLCBlbmNvZGluZywgY2xpcCwgcmFzdGVyaXphdGlvblRpbWVvdXQpID0+XHJcbiAgUHJvbWlzZS5yYWNlKFtcclxuICAgIHBhZ2Uuc2NyZWVuc2hvdCh7XHJcbiAgICAgIHR5cGUsXHJcbiAgICAgIGVuY29kaW5nLFxyXG4gICAgICBjbGlwLFxyXG4gICAgICBjYXB0dXJlQmV5b25kVmlld3BvcnQ6IHRydWUsXHJcbiAgICAgIGZ1bGxQYWdlOiBmYWxzZSxcclxuICAgICAgb3B0aW1pemVGb3JTcGVlZDogdHJ1ZSxcclxuICAgICAgLi4uKHR5cGUgIT09ICdwbmcnID8geyBxdWFsaXR5OiA4MCB9IDoge30pLFxyXG5cclxuICAgICAgLy8gIzQ0NywgIzQ2MyAtIGFsd2F5cyByZW5kZXIgb24gYSB0cmFuc3BhcmVudCBwYWdlIGlmIHRoZSBleHBlY3RlZCB0eXBlXHJcbiAgICAgIC8vIGZvcm1hdCBpcyBQTkdcclxuICAgICAgb21pdEJhY2tncm91bmQ6IHR5cGUgPT0gJ3BuZydcclxuICAgIH0pLFxyXG4gICAgbmV3IFByb21pc2UoKF9yZXNvbHZlLCByZWplY3QpID0+XHJcbiAgICAgIHNldFRpbWVvdXQoXHJcbiAgICAgICAgKCkgPT4gcmVqZWN0KG5ldyBFeHBvcnRFcnJvcignUmFzdGVyaXphdGlvbiB0aW1lb3V0JykpLFxyXG4gICAgICAgIHJhc3Rlcml6YXRpb25UaW1lb3V0IHx8IDE1MDBcclxuICAgICAgKVxyXG4gICAgKVxyXG4gIF0pO1xyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYSBQREYgdXNpbmcgUHVwcGV0ZWVyJ3MgcGFnZSBwZGYgZnVuY3Rpb25hbGl0eSB3aXRoIHNwZWNpZmllZFxyXG4gKiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICogQHBhcmFtIHtudW1iZXJ9IGhlaWdodCAtIFBERiBoZWlnaHQuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSB3aWR0aCAtIFBERiB3aWR0aC5cclxuICogQHBhcmFtIHtzdHJpbmd9IGVuY29kaW5nIC0gUERGIGVuY29kaW5nLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxCdWZmZXI+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgUERGIGJ1ZmZlci5cclxuICovXHJcbmNvbnN0IGNyZWF0ZVBERiA9IGFzeW5jIChcclxuICBwYWdlLFxyXG4gIGhlaWdodCxcclxuICB3aWR0aCxcclxuICBlbmNvZGluZyxcclxuICByYXN0ZXJpemF0aW9uVGltZW91dFxyXG4pID0+IHtcclxuICBhd2FpdCBwYWdlLmVtdWxhdGVNZWRpYVR5cGUoJ3NjcmVlbicpO1xyXG4gIHJldHVybiBQcm9taXNlLnJhY2UoW1xyXG4gICAgcGFnZS5wZGYoe1xyXG4gICAgICAvLyBUaGlzIHdpbGwgcmVtb3ZlIGFuIGV4dHJhIGVtcHR5IHBhZ2UgaW4gUERGIGV4cG9ydHNcclxuICAgICAgaGVpZ2h0OiBoZWlnaHQgKyAxLFxyXG4gICAgICB3aWR0aCxcclxuICAgICAgZW5jb2RpbmdcclxuICAgIH0pLFxyXG4gICAgbmV3IFByb21pc2UoKF9yZXNvbHZlLCByZWplY3QpID0+XHJcbiAgICAgIHNldFRpbWVvdXQoXHJcbiAgICAgICAgKCkgPT4gcmVqZWN0KG5ldyBFeHBvcnRFcnJvcignUmFzdGVyaXphdGlvbiB0aW1lb3V0JykpLFxyXG4gICAgICAgIHJhc3Rlcml6YXRpb25UaW1lb3V0IHx8IDE1MDBcclxuICAgICAgKVxyXG4gICAgKVxyXG4gIF0pO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYW4gU1ZHIHN0cmluZyBieSBldmFsdWF0aW5nIHRoZSBvdXRlckhUTUwgb2YgdGhlIGZpcnN0ICdzdmcnIGVsZW1lbnRcclxuICogaW5zaWRlIGFuIGVsZW1lbnQgd2l0aCB0aGUgaWQgJ2NvbnRhaW5lcicuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgU1ZHIHN0cmluZy5cclxuICovXHJcbmNvbnN0IGNyZWF0ZVNWRyA9IChwYWdlKSA9PlxyXG4gIHBhZ2UuJGV2YWwoJyNjb250YWluZXIgc3ZnOmZpcnN0LW9mLXR5cGUnLCAoZWxlbWVudCkgPT4gZWxlbWVudC5vdXRlckhUTUwpO1xyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIHNwZWNpZmllZCBjaGFydCBhbmQgb3B0aW9ucyBhcyBjb25maWd1cmF0aW9uIGludG8gdGhlIHRyaWdnZXJFeHBvcnRcclxuICogZnVuY3Rpb24gd2l0aGluIHRoZSB3aW5kb3cgY29udGV4dCB1c2luZyBwYWdlLmV2YWx1YXRlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICogQHBhcmFtIHthbnl9IGNoYXJ0IC0gVGhlIGNoYXJ0IG9iamVjdCB0byBiZSBjb25maWd1cmVkLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIENvbmZpZ3VyYXRpb24gb3B0aW9ucyBmb3IgdGhlIGNoYXJ0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gUHJvbWlzZSByZXNvbHZpbmcgYWZ0ZXIgdGhlIGNvbmZpZ3VyYXRpb24gaXMgc2V0LlxyXG4gKi9cclxuY29uc3Qgc2V0QXNDb25maWcgPSBhc3luYyAocGFnZSwgY2hhcnQsIG9wdGlvbnMsIGRpc3BsYXlFcnJvcnMpID0+XHJcbiAgcGFnZS5ldmFsdWF0ZSh0cmlnZ2VyRXhwb3J0LCBjaGFydCwgb3B0aW9ucywgZGlzcGxheUVycm9ycyk7XHJcblxyXG4vKipcclxuICogRXhwb3J0cyB0byBhIGNoYXJ0IGZyb20gYSBwYWdlIHVzaW5nIFB1cHBldGVlci5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7YW55fSBjaGFydCAtIFRoZSBjaGFydCBvYmplY3Qgb3IgU1ZHIGNvbmZpZ3VyYXRpb24gdG8gYmUgZXhwb3J0ZWQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gRXhwb3J0IG9wdGlvbnMgYW5kIGNvbmZpZ3VyYXRpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZyB8IEJ1ZmZlciB8IEV4cG9ydEVycm9yPn0gUHJvbWlzZSByZXNvbHZpbmcgdG9cclxuICogdGhlIGV4cG9ydGVkIGRhdGEgb3IgcmVqZWN0aW5nIHdpdGggYW4gRXhwb3J0RXJyb3IuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCBhc3luYyAocGFnZSwgY2hhcnQsIG9wdGlvbnMpID0+IHtcclxuICAvLyBJbmplY3RlZCByZXNvdXJjZXMgYXJyYXkgKGFkZGl0aW9uYWwgSlMgYW5kIENTUylcclxuICBsZXQgaW5qZWN0ZWRSZXNvdXJjZXMgPSBbXTtcclxuXHJcbiAgdHJ5IHtcclxuICAgIGxvZyg0LCAnW2V4cG9ydF0gRGV0ZXJtaW5pbmcgZXhwb3J0IHBhdGguJyk7XHJcblxyXG4gICAgY29uc3QgZXhwb3J0T3B0aW9ucyA9IG9wdGlvbnMuZXhwb3J0O1xyXG5cclxuICAgIC8vIERlY2lkZSB3aGV0aGVyIGRpc3BsYXkgZXJyb3Igb3IgZGViYnVnZXIgd3JhcHBlciBhcm91bmQgaXRcclxuICAgIGNvbnN0IGRpc3BsYXlFcnJvcnMgPVxyXG4gICAgICBleHBvcnRPcHRpb25zPy5vcHRpb25zPy5jaGFydD8uZGlzcGxheUVycm9ycyAmJlxyXG4gICAgICBnZXRDYWNoZSgpLmFjdGl2ZU1hbmlmZXN0Lm1vZHVsZXMuZGVidWdnZXI7XHJcblxyXG4gICAgbGV0IGlzU1ZHO1xyXG4gICAgaWYgKFxyXG4gICAgICBjaGFydC5pbmRleE9mICYmXHJcbiAgICAgIChjaGFydC5pbmRleE9mKCc8c3ZnJykgPj0gMCB8fCBjaGFydC5pbmRleE9mKCc8P3htbCcpID49IDApXHJcbiAgICApIHtcclxuICAgICAgLy8gU1ZHIGlucHV0IGhhbmRsaW5nXHJcbiAgICAgIGxvZyg0LCAnW2V4cG9ydF0gVHJlYXRpbmcgYXMgU1ZHLicpO1xyXG5cclxuICAgICAgLy8gSWYgaW5wdXQgaXMgYWxzbyBTVkcsIGp1c3QgcmV0dXJuIGl0XHJcbiAgICAgIGlmIChleHBvcnRPcHRpb25zLnR5cGUgPT09ICdzdmcnKSB7XHJcbiAgICAgICAgcmV0dXJuIGNoYXJ0O1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpc1NWRyA9IHRydWU7XHJcbiAgICAgIGF3YWl0IHBhZ2Uuc2V0Q29udGVudChzdmdUZW1wbGF0ZShjaGFydCksIHtcclxuICAgICAgICB3YWl0VW50aWw6ICdkb21jb250ZW50bG9hZGVkJ1xyXG4gICAgICB9KTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIEpTT04gY29uZmlnIGhhbmRsaW5nXHJcbiAgICAgIGxvZyg0LCAnW2V4cG9ydF0gVHJlYXRpbmcgYXMgY29uZmlnLicpO1xyXG5cclxuICAgICAgLy8gTmVlZCB0byBwZXJmb3JtIHN0cmFpZ2h0IGluamVjdFxyXG4gICAgICBpZiAoZXhwb3J0T3B0aW9ucy5zdHJJbmopIHtcclxuICAgICAgICAvLyBJbmplY3Rpb24gYmFzZWQgY29uZmlndXJhdGlvbiBleHBvcnRcclxuICAgICAgICBhd2FpdCBzZXRBc0NvbmZpZyhcclxuICAgICAgICAgIHBhZ2UsXHJcbiAgICAgICAgICB7XHJcbiAgICAgICAgICAgIGNoYXJ0OiB7XHJcbiAgICAgICAgICAgICAgaGVpZ2h0OiBleHBvcnRPcHRpb25zLmhlaWdodCxcclxuICAgICAgICAgICAgICB3aWR0aDogZXhwb3J0T3B0aW9ucy53aWR0aFxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9LFxyXG4gICAgICAgICAgb3B0aW9ucyxcclxuICAgICAgICAgIGRpc3BsYXlFcnJvcnNcclxuICAgICAgICApO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIC8vIEJhc2ljIGNvbmZpZ3VyYXRpb24gZXhwb3J0XHJcbiAgICAgICAgY2hhcnQuY2hhcnQuaGVpZ2h0ID0gZXhwb3J0T3B0aW9ucy5oZWlnaHQ7XHJcbiAgICAgICAgY2hhcnQuY2hhcnQud2lkdGggPSBleHBvcnRPcHRpb25zLndpZHRoO1xyXG5cclxuICAgICAgICBhd2FpdCBzZXRBc0NvbmZpZyhwYWdlLCBjaGFydCwgb3B0aW9ucywgZGlzcGxheUVycm9ycyk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBLZWVwcyB0cmFjayBvZiBhbGwgcmVzb3VyY2VzIGFkZGVkIG9uIHRoZSBwYWdlIHdpdGggYWRkWFhYVGFnLiBldGNcclxuICAgIC8vIEl0J3MgVklUQUwgdGhhdCBhbGwgYWRkZWQgcmVzb3VyY2VzIGVuZHMgdXAgaGVyZSBzbyB3ZSBjYW4gY2xlYXIgdGhpbmdzXHJcbiAgICAvLyBvdXQgd2hlbiBkb2luZyBhIG5ldyBleHBvcnQgaW4gdGhlIHNhbWUgcGFnZSFcclxuICAgIGluamVjdGVkUmVzb3VyY2VzID0gYXdhaXQgYWRkUGFnZVJlc291cmNlcyhwYWdlLCBvcHRpb25zKTtcclxuXHJcbiAgICAvLyBHZXQgdGhlIHJlYWwgY2hhcnQgc2l6ZSBhbmQgc2V0IHRoZSB6b29tIGFjY29yZGluZ2x5XHJcbiAgICBjb25zdCBzaXplID0gaXNTVkdcclxuICAgICAgPyBhd2FpdCBwYWdlLmV2YWx1YXRlKChzY2FsZSkgPT4ge1xyXG4gICAgICAgICAgY29uc3Qgc3ZnRWxlbWVudCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoXHJcbiAgICAgICAgICAgICcjY2hhcnQtY29udGFpbmVyIHN2ZzpmaXJzdC1vZi10eXBlJ1xyXG4gICAgICAgICAgKTtcclxuXHJcbiAgICAgICAgICAvLyBHZXQgdGhlIHZhbHVlcyBjb3JyZWN0bHkgc2NhbGVkXHJcbiAgICAgICAgICBjb25zdCBjaGFydEhlaWdodCA9IHN2Z0VsZW1lbnQuaGVpZ2h0LmJhc2VWYWwudmFsdWUgKiBzY2FsZTtcclxuICAgICAgICAgIGNvbnN0IGNoYXJ0V2lkdGggPSBzdmdFbGVtZW50LndpZHRoLmJhc2VWYWwudmFsdWUgKiBzY2FsZTtcclxuXHJcbiAgICAgICAgICAvLyBJbiBjYXNlIG9mIFNWRyB0aGUgem9vbSBtdXN0IGJlIHNldCBkaXJlY3RseSBmb3IgYm9keVxyXG4gICAgICAgICAgLy8gU2V0IHRoZSB6b29tIGFzIHNjYWxlXHJcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUuem9vbSA9IHNjYWxlO1xyXG5cclxuICAgICAgICAgIC8vIFNldCB0aGUgbWFyZ2luIHRvIDBweFxyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLm1hcmdpbiA9ICcwcHgnO1xyXG5cclxuICAgICAgICAgIHJldHVybiB7XHJcbiAgICAgICAgICAgIGNoYXJ0SGVpZ2h0LFxyXG4gICAgICAgICAgICBjaGFydFdpZHRoXHJcbiAgICAgICAgICB9O1xyXG4gICAgICAgIH0sIHBhcnNlRmxvYXQoZXhwb3J0T3B0aW9ucy5zY2FsZSkpXHJcbiAgICAgIDogYXdhaXQgcGFnZS5ldmFsdWF0ZSgoKSA9PiB7XHJcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgIGNvbnN0IHsgY2hhcnRIZWlnaHQsIGNoYXJ0V2lkdGggfSA9IHdpbmRvdy5IaWdoY2hhcnRzLmNoYXJ0c1swXTtcclxuXHJcbiAgICAgICAgICAvLyBObyBuZWVkIGZvciBzdWNoIHNjYWxlIG1hbmlwdWxhdGlvbiBpbiBjYXNlIG9mIG90aGVyIHR5cGVzXHJcbiAgICAgICAgICAvLyBvZiBleHBvcnRzLiBSZXNldCB0aGUgem9vbSBmb3Igb3RoZXIgZXhwb3J0cyB0aGFuIHRvIFNWR3NcclxuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgICAgZG9jdW1lbnQuYm9keS5zdHlsZS56b29tID0gMTtcclxuXHJcbiAgICAgICAgICByZXR1cm4ge1xyXG4gICAgICAgICAgICBjaGFydEhlaWdodCxcclxuICAgICAgICAgICAgY2hhcnRXaWR0aFxyXG4gICAgICAgICAgfTtcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAvLyBTZXQgZmluYWwgaGVpZ2h0IGFuZCB3aWR0aCBmb3Igdmlld3BvcnRcclxuICAgIGNvbnN0IHZpZXdwb3J0SGVpZ2h0ID0gTWF0aC5jZWlsKHNpemUuY2hhcnRIZWlnaHQgfHwgZXhwb3J0T3B0aW9ucy5oZWlnaHQpO1xyXG4gICAgY29uc3Qgdmlld3BvcnRXaWR0aCA9IE1hdGguY2VpbChzaXplLmNoYXJ0V2lkdGggfHwgZXhwb3J0T3B0aW9ucy53aWR0aCk7XHJcblxyXG4gICAgLy8gR2V0IHRoZSBjbGlwIHJlZ2lvbiBmb3IgdGhlIHBhZ2VcclxuICAgIGNvbnN0IHsgeCwgeSB9ID0gYXdhaXQgZ2V0Q2xpcFJlZ2lvbihwYWdlKTtcclxuXHJcbiAgICAvLyBTZXQgdGhlIGZpbmFsIHZpZXdwb3J0IG5vdyB0aGF0IHdlIGhhdmUgdGhlIHJlYWwgaGVpZ2h0XHJcbiAgICBhd2FpdCBwYWdlLnNldFZpZXdwb3J0KHtcclxuICAgICAgaGVpZ2h0OiB2aWV3cG9ydEhlaWdodCxcclxuICAgICAgd2lkdGg6IHZpZXdwb3J0V2lkdGgsXHJcbiAgICAgIGRldmljZVNjYWxlRmFjdG9yOiBpc1NWRyA/IDEgOiBwYXJzZUZsb2F0KGV4cG9ydE9wdGlvbnMuc2NhbGUpXHJcbiAgICB9KTtcclxuXHJcbiAgICBsZXQgZGF0YTtcclxuICAgIC8vIFJhc3Rlcml6YXRpb24gcHJvY2Vzc1xyXG4gICAgaWYgKGV4cG9ydE9wdGlvbnMudHlwZSA9PT0gJ3N2ZycpIHtcclxuICAgICAgLy8gU1ZHXHJcbiAgICAgIGRhdGEgPSBhd2FpdCBjcmVhdGVTVkcocGFnZSk7XHJcbiAgICB9IGVsc2UgaWYgKFsncG5nJywgJ2pwZWcnXS5pbmNsdWRlcyhleHBvcnRPcHRpb25zLnR5cGUpKSB7XHJcbiAgICAgIC8vIFBORyBvciBKUEVHXHJcbiAgICAgIGRhdGEgPSBhd2FpdCBjcmVhdGVJbWFnZShcclxuICAgICAgICBwYWdlLFxyXG4gICAgICAgIGV4cG9ydE9wdGlvbnMudHlwZSxcclxuICAgICAgICAnYmFzZTY0JyxcclxuICAgICAgICB7XHJcbiAgICAgICAgICB3aWR0aDogdmlld3BvcnRXaWR0aCxcclxuICAgICAgICAgIGhlaWdodDogdmlld3BvcnRIZWlnaHQsXHJcbiAgICAgICAgICB4LFxyXG4gICAgICAgICAgeVxyXG4gICAgICAgIH0sXHJcbiAgICAgICAgZXhwb3J0T3B0aW9ucy5yYXN0ZXJpemF0aW9uVGltZW91dFxyXG4gICAgICApO1xyXG4gICAgfSBlbHNlIGlmIChleHBvcnRPcHRpb25zLnR5cGUgPT09ICdwZGYnKSB7XHJcbiAgICAgIC8vIFBERlxyXG4gICAgICBkYXRhID0gYXdhaXQgY3JlYXRlUERGKFxyXG4gICAgICAgIHBhZ2UsXHJcbiAgICAgICAgdmlld3BvcnRIZWlnaHQsXHJcbiAgICAgICAgdmlld3BvcnRXaWR0aCxcclxuICAgICAgICAnYmFzZTY0JyxcclxuICAgICAgICBleHBvcnRPcHRpb25zLnJhc3Rlcml6YXRpb25UaW1lb3V0XHJcbiAgICAgICk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgYFtleHBvcnRdIFVuc3VwcG9ydGVkIG91dHB1dCBmb3JtYXQgJHtleHBvcnRPcHRpb25zLnR5cGV9LmBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBDbGVhciBwcmV2aW91c2x5IGluamVjdGVkIEpTIGFuZCBDU1MgcmVzb3VyY2VzXHJcbiAgICBhd2FpdCBjbGVhclBhZ2VSZXNvdXJjZXMocGFnZSwgaW5qZWN0ZWRSZXNvdXJjZXMpO1xyXG4gICAgcmV0dXJuIGRhdGE7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIGF3YWl0IGNsZWFyUGFnZVJlc291cmNlcyhwYWdlLCBpbmplY3RlZFJlc291cmNlcyk7XHJcbiAgICByZXR1cm4gZXJyb3I7XHJcbiAgfVxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCBjc3NUZW1wbGF0ZSBmcm9tICcuL2Nzcy5qcyc7XHJcblxyXG5leHBvcnQgZGVmYXVsdCAoY2hhcnQpID0+IGBcclxuPCFET0NUWVBFIGh0bWw+XHJcbjxodG1sIGxhbmc9J2VuLVVTJz5cclxuICA8aGVhZD5cclxuICAgIDxtZXRhIGh0dHAtZXF1aXY9XCJDb250ZW50LVR5cGVcIiBjb250ZW50PVwidGV4dC9odG1sOyBjaGFyc2V0PXV0Zi04XCI+XHJcbiAgICA8dGl0bGU+SGlnaGNoYXJ0cyBFeHBvcnQ8L3RpdGxlPlxyXG4gIDwvaGVhZD5cclxuICA8c3R5bGU+XHJcbiAgICAke2Nzc1RlbXBsYXRlKCl9XHJcbiAgPC9zdHlsZT5cclxuICA8Ym9keT5cclxuICAgIDxkaXYgaWQ9XCJjaGFydC1jb250YWluZXJcIj5cclxuICAgICAgJHtjaGFydH1cclxuICAgIDwvZGl2PlxyXG4gIDwvYm9keT5cclxuPC9odG1sPlxyXG5cclxuYDtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyBQb29sIH0gZnJvbSAndGFybic7XHJcbmltcG9ydCB7IHY0IGFzIHV1aWQgfSBmcm9tICd1dWlkJztcclxuXHJcbmltcG9ydCB7XHJcbiAgY3JlYXRlIGFzIGNyZWF0ZUJyb3dzZXIsXHJcbiAgY2xvc2UgYXMgY2xvc2VCcm93c2VyLFxyXG4gIG5ld1BhZ2UsXHJcbiAgY2xlYXJQYWdlXHJcbn0gZnJvbSAnLi9icm93c2VyLmpzJztcclxuaW1wb3J0IHB1cHBldGVlckV4cG9ydCBmcm9tICcuL2V4cG9ydC5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBtZWFzdXJlVGltZSB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8vIFRoZSBwb29sIGluc3RhbmNlXHJcbmxldCBwb29sID0gZmFsc2U7XHJcblxyXG4vLyBQb29sIHN0YXRpc3RpY3NcclxuZXhwb3J0IGNvbnN0IHN0YXRzID0ge1xyXG4gIHBlcmZvcm1lZEV4cG9ydHM6IDAsXHJcbiAgZXhwb3J0QXR0ZW1wdHM6IDAsXHJcbiAgZXhwb3J0RnJvbVN2Z0F0dGVtcHRzOiAwLFxyXG4gIHRpbWVTcGVudDogMCxcclxuICBkcm9wcGVkRXhwb3J0czogMCxcclxuICBzcGVudEF2ZXJhZ2U6IDBcclxufTtcclxuXHJcbmxldCBwb29sQ29uZmlnID0ge307XHJcblxyXG5jb25zdCBmYWN0b3J5ID0ge1xyXG4gIC8qKlxyXG4gICAqIENyZWF0ZXMgYSBuZXcgd29ya2VyIHBhZ2UgZm9yIHRoZSBleHBvcnQgcG9vbC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHtPYmplY3R9IC0gQW4gb2JqZWN0IGNvbnRhaW5pbmcgdGhlIHdvcmtlciBJRCwgYSByZWZlcmVuY2UgdG8gdGhlXHJcbiAgICogYnJvd3NlciBwYWdlLCBhbmQgaW5pdGlhbCB3b3JrIGNvdW50LlxyXG4gICAqXHJcbiAgICogQHRocm93cyB7RXhwb3J0RXJyb3J9IC0gSWYgdGhlcmUncyBhbiBlcnJvciBkdXJpbmcgdGhlIGNyZWF0aW9uIG9mIHRoZSBuZXdcclxuICAgKiBwYWdlLlxyXG4gICAqL1xyXG4gIGNyZWF0ZTogYXN5bmMgKCkgPT4ge1xyXG4gICAgbGV0IHBhZ2UgPSBmYWxzZTtcclxuXHJcbiAgICBjb25zdCBpZCA9IHV1aWQoKTtcclxuICAgIGNvbnN0IHN0YXJ0RGF0ZSA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xyXG5cclxuICAgIHRyeSB7XHJcbiAgICAgIHBhZ2UgPSBhd2FpdCBuZXdQYWdlKCk7XHJcblxyXG4gICAgICBpZiAoIXBhZ2UgfHwgcGFnZS5pc0Nsb3NlZCgpKSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdUaGUgcGFnZSBpcyBpbnZhbGlkIG9yIGNsb3NlZC4nKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgbG9nKFxyXG4gICAgICAgIDMsXHJcbiAgICAgICAgYFtwb29sXSBTdWNjZXNzZnVsbHkgY3JlYXRlZCBhIHdvcmtlciAke2lkfSAtIHRvb2sgJHtcclxuICAgICAgICAgIG5ldyBEYXRlKCkuZ2V0VGltZSgpIC0gc3RhcnREYXRlXHJcbiAgICAgICAgfSBtcy5gXHJcbiAgICAgICk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ0Vycm9yIGVuY291bnRlcmVkIHdoZW4gY3JlYXRpbmcgYSBuZXcgcGFnZS4nXHJcbiAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiB7XHJcbiAgICAgIGlkLFxyXG4gICAgICBwYWdlLFxyXG4gICAgICAvLyBUcnkgdG8gZGlzdHJpYnV0ZSB0aGUgaW5pdGlhbCB3b3JrIGNvdW50XHJcbiAgICAgIHdvcmtDb3VudDogTWF0aC5yb3VuZChNYXRoLnJhbmRvbSgpICogKHBvb2xDb25maWcud29ya0xpbWl0IC8gMikpXHJcbiAgICB9O1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFZhbGlkYXRlcyBhIHdvcmtlciBwYWdlIGluIHRoZSBleHBvcnQgcG9vbCwgY2hlY2tpbmcgaWYgaXQgaGFzIGV4Y2VlZGVkXHJcbiAgICogdGhlIHdvcmsgbGltaXQuXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge09iamVjdH0gd29ya2VySGFuZGxlIC0gVGhlIGhhbmRsZSB0byB0aGUgd29ya2VyLCBjb250YWluaW5nIHRoZVxyXG4gICAqIHdvcmtlcidzIElELCBhIHJlZmVyZW5jZSB0byB0aGUgYnJvd3NlciBwYWdlLCBhbmQgd29yayBjb3VudC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHtib29sZWFufSAtIFJldHVybnMgdHJ1ZSBpZiB0aGUgd29ya2VyIGlzIHZhbGlkIGFuZCB3aXRoaW5cclxuICAgKiB0aGUgd29yayBsaW1pdDsgb3RoZXJ3aXNlLCByZXR1cm5zIGZhbHNlLlxyXG4gICAqL1xyXG4gIHZhbGlkYXRlOiBhc3luYyAod29ya2VySGFuZGxlKSA9PiB7XHJcbiAgICBpZiAoXHJcbiAgICAgIHBvb2xDb25maWcud29ya0xpbWl0ICYmXHJcbiAgICAgICsrd29ya2VySGFuZGxlLndvcmtDb3VudCA+IHBvb2xDb25maWcud29ya0xpbWl0XHJcbiAgICApIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDMsXHJcbiAgICAgICAgYFtwb29sXSBXb3JrZXIgZmFpbGVkIHZhbGlkYXRpb246IGV4Y2VlZGVkIHdvcmsgbGltaXQgKGxpbWl0IGlzICR7cG9vbENvbmZpZy53b3JrTGltaXR9KS5gXHJcbiAgICAgICk7XHJcbiAgICAgIHJldHVybiBmYWxzZTtcclxuICAgIH1cclxuICAgIHJldHVybiB0cnVlO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIERlc3Ryb3lzIGEgd29ya2VyIGVudHJ5IGluIHRoZSBleHBvcnQgcG9vbCwgY2xvc2luZyBpdHMgYXNzb2NpYXRlZCBwYWdlLlxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtPYmplY3R9IHdvcmtlckhhbmRsZSAtIFRoZSBoYW5kbGUgdG8gdGhlIHdvcmtlciwgY29udGFpbmluZ1xyXG4gICAqIHRoZSB3b3JrZXIncyBJRCBhbmQgYSByZWZlcmVuY2UgdG8gdGhlIGJyb3dzZXIgcGFnZS5cclxuICAgKi9cclxuICBkZXN0cm95OiBhc3luYyAod29ya2VySGFuZGxlKSA9PiB7XHJcbiAgICBsb2coMywgYFtwb29sXSBEZXN0cm95aW5nIHBvb2wgZW50cnkgJHt3b3JrZXJIYW5kbGUuaWR9LmApO1xyXG5cclxuICAgIGlmICh3b3JrZXJIYW5kbGUucGFnZSkge1xyXG4gICAgICAvLyBXZSBkb24ndCByZWFsbHkgbmVlZCB0byB3YWl0IGFyb3VuZCBmb3IgdGhpc1xyXG4gICAgICBhd2FpdCB3b3JrZXJIYW5kbGUucGFnZS5jbG9zZSgpO1xyXG4gICAgfVxyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyB0aGUgZXhwb3J0IHBvb2wgd2l0aCB0aGUgcHJvdmlkZWQgY29uZmlndXJhdGlvbiwgY3JlYXRpbmdcclxuICogYSBicm93c2VyIGluc3RhbmNlIGFuZCBzZXR0aW5nIHVwIHdvcmtlciByZXNvdXJjZXMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjb25maWcgLSBDb25maWd1cmF0aW9uIG9wdGlvbnMgZm9yIHRoZSBleHBvcnQgcG9vbCBhbG9uZ1xyXG4gKiB3aXRoIGN1c3RvbSBwdXBwZXRlZXIgYXJndW1lbnRzIGZvciB0aGUgcHVwcGV0ZWVyLmxhdW5jaCBmdW5jdGlvbi5cclxuICovXHJcbmV4cG9ydCBjb25zdCBpbml0UG9vbCA9IGFzeW5jIChjb25maWcpID0+IHtcclxuICAvLyBGb3IgdGhlIG1vZHVsZSBzY29wZSB1c2FnZVxyXG4gIHBvb2xDb25maWcgPSBjb25maWcgJiYgY29uZmlnLnBvb2wgPyB7IC4uLmNvbmZpZy5wb29sIH0gOiB7fTtcclxuXHJcbiAgLy8gQ3JlYXRlIGEgYnJvd3NlciBpbnN0YW5jZSB3aXRoIHRoZSBwdXBwZXRlZXIgYXJndW1lbnRzXHJcbiAgYXdhaXQgY3JlYXRlQnJvd3Nlcihjb25maWcucHVwcGV0ZWVyQXJncyk7XHJcblxyXG4gIGxvZyhcclxuICAgIDMsXHJcbiAgICBgW3Bvb2xdIEluaXRpYWxpemluZyBwb29sIHdpdGggd29ya2VyczogbWluICR7cG9vbENvbmZpZy5taW5Xb3JrZXJzfSwgbWF4ICR7cG9vbENvbmZpZy5tYXhXb3JrZXJzfS5gXHJcbiAgKTtcclxuXHJcbiAgaWYgKHBvb2wpIHtcclxuICAgIHJldHVybiBsb2coXHJcbiAgICAgIDQsXHJcbiAgICAgICdbcG9vbF0gQWxyZWFkeSBpbml0aWFsaXplZCwgcGxlYXNlIGtpbGwgaXQgYmVmb3JlIGNyZWF0aW5nIGEgbmV3IG9uZS4nXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgaWYgKHBhcnNlSW50KHBvb2xDb25maWcubWluV29ya2VycykgPiBwYXJzZUludChwb29sQ29uZmlnLm1heFdvcmtlcnMpKSB7XHJcbiAgICBwb29sQ29uZmlnLm1pbldvcmtlcnMgPSBwb29sQ29uZmlnLm1heFdvcmtlcnM7XHJcbiAgfVxyXG5cclxuICB0cnkge1xyXG4gICAgLy8gQ3JlYXRlIGEgcG9vbCBhbG9uZyB3aXRoIGEgbWluaW1hbCBudW1iZXIgb2YgcmVzb3VyY2VzXHJcbiAgICBwb29sID0gbmV3IFBvb2woe1xyXG4gICAgICAvLyBHZXQgdGhlIGNyZWF0ZS92YWxpZGF0ZS9kZXN0cm95L2xvZyBmdW5jdGlvbnNcclxuICAgICAgLi4uZmFjdG9yeSxcclxuICAgICAgbWluOiBwYXJzZUludChwb29sQ29uZmlnLm1pbldvcmtlcnMpLFxyXG4gICAgICBtYXg6IHBhcnNlSW50KHBvb2xDb25maWcubWF4V29ya2VycyksXHJcbiAgICAgIGFjcXVpcmVUaW1lb3V0TWlsbGlzOiBwb29sQ29uZmlnLmFjcXVpcmVUaW1lb3V0LFxyXG4gICAgICBjcmVhdGVUaW1lb3V0TWlsbGlzOiBwb29sQ29uZmlnLmNyZWF0ZVRpbWVvdXQsXHJcbiAgICAgIGRlc3Ryb3lUaW1lb3V0TWlsbGlzOiBwb29sQ29uZmlnLmRlc3Ryb3lUaW1lb3V0LFxyXG4gICAgICBpZGxlVGltZW91dE1pbGxpczogcG9vbENvbmZpZy5pZGxlVGltZW91dCxcclxuICAgICAgY3JlYXRlUmV0cnlJbnRlcnZhbE1pbGxpczogcG9vbENvbmZpZy5jcmVhdGVSZXRyeUludGVydmFsLFxyXG4gICAgICByZWFwSW50ZXJ2YWxNaWxsaXM6IHBvb2xDb25maWcucmVhcGVySW50ZXJ2YWwsXHJcbiAgICAgIHByb3BhZ2F0ZUNyZWF0ZUVycm9yOiBmYWxzZVxyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gU2V0IGV2ZW50c1xyXG4gICAgcG9vbC5vbigncmVsZWFzZScsIGFzeW5jIChyZXNvdXJjZSkgPT4ge1xyXG4gICAgICAvLyBDbGVhciBwYWdlXHJcbiAgICAgIGF3YWl0IGNsZWFyUGFnZShyZXNvdXJjZS5wYWdlLCBmYWxzZSk7XHJcbiAgICAgIGxvZyg0LCBgW3Bvb2xdIFJlbGVhc2luZyBhIHdvcmtlciB3aXRoIElEICR7cmVzb3VyY2UuaWR9LmApO1xyXG4gICAgfSk7XHJcblxyXG4gICAgcG9vbC5vbignZGVzdHJveVN1Y2Nlc3MnLCAoZXZlbnRJZCwgcmVzb3VyY2UpID0+IHtcclxuICAgICAgbG9nKDQsIGBbcG9vbF0gRGVzdHJveWVkIGEgd29ya2VyIHdpdGggSUQgJHtyZXNvdXJjZS5pZH0uYCk7XHJcbiAgICB9KTtcclxuXHJcbiAgICBjb25zdCBpbml0aWFsUmVzb3VyY2VzID0gW107XHJcbiAgICAvLyBDcmVhdGUgYW4gaW5pdGlhbCBudW1iZXIgb2YgcmVzb3VyY2VzXHJcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHBvb2xDb25maWcubWluV29ya2VyczsgaSsrKSB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgY29uc3QgcmVzb3VyY2UgPSBhd2FpdCBwb29sLmFjcXVpcmUoKS5wcm9taXNlO1xyXG4gICAgICAgIGluaXRpYWxSZXNvdXJjZXMucHVzaChyZXNvdXJjZSk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCAnW3Bvb2xdIENvdWxkIG5vdCBjcmVhdGUgYW4gaW5pdGlhbCByZXNvdXJjZS4nKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIFJlbGVhc2UgdGhlIGluaXRpYWwgbnVtYmVyIG9mIHJlc291cmNlcyBiYWNrIHRvIHRoZSBwb29sXHJcbiAgICBpbml0aWFsUmVzb3VyY2VzLmZvckVhY2goKHJlc291cmNlKSA9PiB7XHJcbiAgICAgIHBvb2wucmVsZWFzZShyZXNvdXJjZSk7XHJcbiAgICB9KTtcclxuXHJcbiAgICBsb2coXHJcbiAgICAgIDMsXHJcbiAgICAgIGBbcG9vbF0gVGhlIHBvb2wgaXMgcmVhZHkke2luaXRpYWxSZXNvdXJjZXMubGVuZ3RoID8gYCB3aXRoICR7aW5pdGlhbFJlc291cmNlcy5sZW5ndGh9IGluaXRpYWwgcmVzb3VyY2VzIHdhaXRpbmcuYCA6ICcuJ31gXHJcbiAgICApO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbcG9vbF0gQ291bGQgbm90IGNyZWF0ZSB0aGUgcG9vbCBvZiB3b3JrZXJzLidcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBLaWxscyBhbGwgd29ya2VycyBpbiB0aGUgcG9vbCwgZGVzdHJveXMgdGhlIHBvb2wsIGFuZCBjbG9zZXMgdGhlIGJyb3dzZXJcclxuICogaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyBhZnRlciB0aGUgd29ya2VycyBhcmVcclxuICoga2lsbGVkLCB0aGUgcG9vbCBpcyBkZXN0cm95ZWQsIGFuZCB0aGUgYnJvd3NlciBpcyBjbG9zZWQuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24ga2lsbFBvb2woKSB7XHJcbiAgbG9nKDMsICdbcG9vbF0gS2lsbGluZyBwb29sIHdpdGggYWxsIHdvcmtlcnMgYW5kIGNsb3NpbmcgYnJvd3Nlci4nKTtcclxuXHJcbiAgLy8gSWYgc3RpbGwgYWxpdmUsIGRlc3Ryb3kgdGhlIHBvb2wgb2YgcGFnZXMgYmVmb3JlIGNsb3NpbmcgYSBicm93c2VyXHJcbiAgaWYgKHBvb2wpIHtcclxuICAgIC8vIEZyZWUgdXAgbm90IHJlbGVhc2VkIHdvcmtlcnNcclxuICAgIGZvciAoY29uc3Qgd29ya2VyIG9mIHBvb2wudXNlZCkge1xyXG4gICAgICBwb29sLnJlbGVhc2Uod29ya2VyLnJlc291cmNlKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBEZXN0cm95IHRoZSBwb29sIGlmIGl0IGlzIHN0aWxsIGF2YWlsYWJsZVxyXG4gICAgaWYgKCFwb29sLmRlc3Ryb3llZCkge1xyXG4gICAgICBhd2FpdCBwb29sLmRlc3Ryb3koKTtcclxuICAgICAgbG9nKDQsICdbYnJvd3Nlcl0gRGVzdHJveWVkIHRoZSBwb29sIG9mIHJlc291cmNlcy4nKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIENsb3NlIHRoZSBicm93c2VyIGluc3RhbmNlXHJcbiAgYXdhaXQgY2xvc2VCcm93c2VyKCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBQcm9jZXNzZXMgdGhlIGV4cG9ydCB3b3JrIHVzaW5nIGEgd29ya2VyIGZyb20gdGhlIHBvb2wuIEFjcXVpcmVzIGEgd29ya2VyXHJcbiAqIGhhbmRsZSBmcm9tIHRoZSBwb29sLCBwZXJmb3JtcyB0aGUgZXhwb3J0IHVzaW5nIHB1cHBldGVlciwgYW5kIHJlbGVhc2VzXHJcbiAqIHRoZSB3b3JrZXIgaGFuZGxlIGJhY2sgdG8gdGhlIHBvb2wuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBjaGFydCAtIFRoZSBjaGFydCBkYXRhIG9yIGNvbmZpZ3VyYXRpb24gdG8gYmUgZXhwb3J0ZWQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gRXhwb3J0IG9wdGlvbnMgYW5kIGNvbmZpZ3VyYXRpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHdpdGggdGhlIGV4cG9ydCByZXN1bHRhbmRcclxuICogb3B0aW9ucy5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IElmIGFuIGVycm9yIG9jY3VycyBkdXJpbmcgdGhlIGV4cG9ydCBwcm9jZXNzLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHBvc3RXb3JrID0gYXN5bmMgKGNoYXJ0LCBvcHRpb25zKSA9PiB7XHJcbiAgbGV0IHdvcmtlckhhbmRsZTtcclxuXHJcbiAgdHJ5IHtcclxuICAgIGxvZyg0LCAnW3Bvb2xdIFdvcmsgcmVjZWl2ZWQsIHN0YXJ0aW5nIHRvIHByb2Nlc3MuJyk7XHJcblxyXG4gICAgKytzdGF0cy5leHBvcnRBdHRlbXB0cztcclxuICAgIGlmIChwb29sQ29uZmlnLmJlbmNobWFya2luZykge1xyXG4gICAgICBnZXRQb29sSW5mbygpO1xyXG4gICAgfVxyXG5cclxuICAgIGlmICghcG9vbCkge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1dvcmsgcmVjZWl2ZWQsIGJ1dCBwb29sIGhhcyBub3QgYmVlbiBzdGFydGVkLicpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEFjcXVpcmUgdGhlIHdvcmtlciBhbG9uZyB3aXRoIHRoZSBpZCBvZiByZXNvdXJjZSBhbmQgd29yayBjb3VudFxyXG4gICAgY29uc3QgYWNxdWlyZUNvdW50ZXIgPSBtZWFzdXJlVGltZSgpO1xyXG4gICAgdHJ5IHtcclxuICAgICAgbG9nKDQsICdbcG9vbF0gQWNxdWlyaW5nIGEgd29ya2VyIGhhbmRsZS4nKTtcclxuICAgICAgd29ya2VySGFuZGxlID0gYXdhaXQgcG9vbC5hY3F1aXJlKCkucHJvbWlzZTtcclxuXHJcbiAgICAgIC8vIENoZWNrIHRoZSBwYWdlIGFjcXVpcmUgdGltZVxyXG4gICAgICBpZiAob3B0aW9ucy5zZXJ2ZXIuYmVuY2htYXJraW5nKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgNSxcclxuICAgICAgICAgIG9wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkXHJcbiAgICAgICAgICAgID8gYFtiZW5jaG1hcmtdIFJlcXVlc3Q6ICR7b3B0aW9ucy5wYXlsb2FkPy5yZXF1ZXN0SWR9IC1gXHJcbiAgICAgICAgICAgIDogJ1tiZW5jaG1hcmtdJyxcclxuICAgICAgICAgIGBBY3F1aXJlZCBhIHdvcmtlciBoYW5kbGU6ICR7YWNxdWlyZUNvdW50ZXIoKX1tcy5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgIChvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZFxyXG4gICAgICAgICAgPyBgUmVxdWVzdDogJHtvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZH0gLSBgXHJcbiAgICAgICAgICA6ICcnKSArXHJcbiAgICAgICAgICBgRXJyb3IgZW5jb3VudGVyZWQgd2hlbiBhY3F1aXJpbmcgYW4gYXZhaWxhYmxlIGVudHJ5OiAke2FjcXVpcmVDb3VudGVyKCl9bXMuYFxyXG4gICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgIH1cclxuICAgIGxvZyg0LCAnW3Bvb2xdIEFjcXVpcmVkIGEgd29ya2VyIGhhbmRsZS4nKTtcclxuXHJcbiAgICBpZiAoIXdvcmtlckhhbmRsZS5wYWdlKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnUmVzb2x2ZWQgd29ya2VyIHBhZ2UgaXMgaW52YWxpZDogdGhlIHBvb2wgc2V0dXAgaXMgd29ua3kuJ1xyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFNhdmUgdGhlIHN0YXJ0IHRpbWVcclxuICAgIGxldCB3b3JrU3RhcnQgPSBuZXcgRGF0ZSgpLmdldFRpbWUoKTtcclxuXHJcbiAgICBsb2coNCwgYFtwb29sXSBTdGFydGluZyB3b3JrIG9uIHBvb2wgZW50cnkgd2l0aCBJRCAke3dvcmtlckhhbmRsZS5pZH0uYCk7XHJcblxyXG4gICAgLy8gUGVyZm9ybSBhbiBleHBvcnQgb24gYSBwdXBwZXRlZXIgbGV2ZWxcclxuICAgIGNvbnN0IGV4cG9ydENvdW50ZXIgPSBtZWFzdXJlVGltZSgpO1xyXG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcHVwcGV0ZWVyRXhwb3J0KHdvcmtlckhhbmRsZS5wYWdlLCBjaGFydCwgb3B0aW9ucyk7XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgaXQncyBhbiBlcnJvclxyXG4gICAgaWYgKHJlc3VsdCBpbnN0YW5jZW9mIEVycm9yKSB7XHJcbiAgICAgIC8vIFRPRE86IElmIHRoZSBleHBvcnQgZmFpbGVkIGJlY2F1c2UgcHVwcGV0ZWVyIHRpbWVkIG91dCwgd2UgbmVlZCB0byBmb3JjZSBraWxsIHRoZSB3b3JrZXIgc28gd2UgZ2V0IGEgbmV3IHBhZ2UuIFRoYXQgbmVlZHMgdG8gYmUgaGFuZGxlZCBiZXR0ZXIgdGhhbiB0aGlzIGhhY2suXHJcbiAgICAgIGlmIChyZXN1bHQubWVzc2FnZSA9PT0gJ1Jhc3Rlcml6YXRpb24gdGltZW91dCcpIHtcclxuICAgICAgICB3b3JrZXJIYW5kbGUucGFnZS5jbG9zZSgpO1xyXG4gICAgICAgIHdvcmtlckhhbmRsZS5wYWdlID0gYXdhaXQgbmV3UGFnZSgpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgKG9wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkXHJcbiAgICAgICAgICA/IGBSZXF1ZXN0OiAke29wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkfSAtIGBcclxuICAgICAgICAgIDogJycpICsgYEVycm9yIGVuY291bnRlcmVkIGR1cmluZyBleHBvcnQ6ICR7ZXhwb3J0Q291bnRlcigpfW1zLmBcclxuICAgICAgKS5zZXRFcnJvcihyZXN1bHQpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIENoZWNrIHRoZSBQdXBwZXRlZXIgZXhwb3J0IHRpbWVcclxuICAgIGlmIChvcHRpb25zLnNlcnZlci5iZW5jaG1hcmtpbmcpIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDUsXHJcbiAgICAgICAgb3B0aW9ucy5wYXlsb2FkPy5yZXF1ZXN0SWRcclxuICAgICAgICAgID8gYFtiZW5jaG1hcmtdIFJlcXVlc3Q6ICR7b3B0aW9ucy5wYXlsb2FkPy5yZXF1ZXN0SWR9IC1gXHJcbiAgICAgICAgICA6ICdbYmVuY2htYXJrXScsXHJcbiAgICAgICAgYEV4cG9ydGVkIGEgY2hhcnQgc3VjZXNzZnVsbHk6ICR7ZXhwb3J0Q291bnRlcigpfW1zLmBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBSZWxlYXNlIHRoZSByZXNvdXJjZSBiYWNrIHRvIHRoZSBwb29sXHJcbiAgICBwb29sLnJlbGVhc2Uod29ya2VySGFuZGxlKTtcclxuXHJcbiAgICAvLyBVc2VkIGZvciBzdGF0aXN0aWNzIGluIGF2ZXJhZ2VUaW1lIGFuZCBwcm9jZXNzZWRXb3JrQ291bnQsIHdoaWNoXHJcbiAgICAvLyBpbiB0dXJuIGlzIHVzZWQgYnkgdGhlIC9oZWFsdGggcm91dGUuXHJcbiAgICBjb25zdCB3b3JrRW5kID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XHJcbiAgICBjb25zdCBleHBvcnRUaW1lID0gd29ya0VuZCAtIHdvcmtTdGFydDtcclxuICAgIHN0YXRzLnRpbWVTcGVudCArPSBleHBvcnRUaW1lO1xyXG4gICAgc3RhdHMuc3BlbnRBdmVyYWdlID0gc3RhdHMudGltZVNwZW50IC8gKytzdGF0cy5wZXJmb3JtZWRFeHBvcnRzO1xyXG5cclxuICAgIGxvZyg0LCBgW3Bvb2xdIFdvcmsgY29tcGxldGVkIGluICR7ZXhwb3J0VGltZX0gbXMuYCk7XHJcblxyXG4gICAgLy8gT3RoZXJ3aXNlIHJldHVybiB0aGUgcmVzdWx0XHJcbiAgICByZXR1cm4ge1xyXG4gICAgICByZXN1bHQsXHJcbiAgICAgIG9wdGlvbnNcclxuICAgIH07XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICsrc3RhdHMuZHJvcHBlZEV4cG9ydHM7XHJcblxyXG4gICAgaWYgKHdvcmtlckhhbmRsZSkge1xyXG4gICAgICBwb29sLnJlbGVhc2Uod29ya2VySGFuZGxlKTtcclxuICAgIH1cclxuXHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoYFtwb29sXSBJbiBwb29sLnBvc3RXb3JrOiAke2Vycm9yLm1lc3NhZ2V9YCkuc2V0RXJyb3IoXHJcbiAgICAgIGVycm9yXHJcbiAgICApO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgdGhlIGN1cnJlbnQgcG9vbCBpbnN0YW5jZS5cclxuICpcclxuICogQHJldHVybnMge09iamVjdHxudWxsfSBUaGUgY3VycmVudCBwb29sIGluc3RhbmNlIGlmIGluaXRpYWxpemVkLCBvciBudWxsXHJcbiAqIGlmIHRoZSBwb29sIGhhcyBub3QgYmVlbiBjcmVhdGVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldFBvb2wgPSAoKSA9PiBwb29sO1xyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyBwb29sIGluZm9ybWF0aW9uIGluIEpTT04gZm9ybWF0LCBpbmNsdWRpbmcgbWluaW11bSBhbmQgbWF4aW11bVxyXG4gKiB3b3JrZXJzLCBhdmFpbGFibGUgd29ya2Vycywgd29ya2VycyBpbiB1c2UsIGFuZCBwZW5kaW5nIGFjcXVpcmUgcmVxdWVzdHMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFBvb2wgaW5mb3JtYXRpb24gaW4gSlNPTiBmb3JtYXQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0UG9vbEluZm9KU09OID0gKCkgPT4gKHtcclxuICBtaW46IHBvb2wubWluLFxyXG4gIG1heDogcG9vbC5tYXgsXHJcbiAgYWxsOiBwb29sLm51bUZyZWUoKSArIHBvb2wubnVtVXNlZCgpLFxyXG4gIGF2YWlsYWJsZTogcG9vbC5udW1GcmVlKCksXHJcbiAgdXNlZDogcG9vbC5udW1Vc2VkKCksXHJcbiAgcGVuZGluZzogcG9vbC5udW1QZW5kaW5nQWNxdWlyZXMoKVxyXG59KTtcclxuXHJcbi8qKlxyXG4gKiBMb2dzIGluZm9ybWF0aW9uIGFib3V0IHRoZSBjdXJyZW50IHN0YXRlIG9mIHRoZSBwb29sLCBpbmNsdWRpbmcgdGhlIG1pbmltdW1cclxuICogYW5kIG1heGltdW0gd29ya2VycywgYXZhaWxhYmxlIHdvcmtlcnMsIHdvcmtlcnMgaW4gdXNlLCBhbmQgcGVuZGluZyBhY3F1aXJlXHJcbiAqIHJlcXVlc3RzLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldFBvb2xJbmZvKCkge1xyXG4gIGNvbnN0IHsgbWluLCBtYXgsIGFsbCwgYXZhaWxhYmxlLCB1c2VkLCBwZW5kaW5nIH0gPSBnZXRQb29sSW5mb0pTT04oKTtcclxuXHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG1pbmltdW0gbnVtYmVyIG9mIHJlc291cmNlcyBhbGxvd2VkIGJ5IHBvb2w6ICR7bWlufS5gKTtcclxuICBsb2coNSwgYFtwb29sXSBUaGUgbWF4aW11bSBudW1iZXIgb2YgcmVzb3VyY2VzIGFsbG93ZWQgYnkgcG9vbDogJHttYXh9LmApO1xyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgYWxsIGNyZWF0ZWQgcmVzb3VyY2VzOiAke2FsbH0uYCk7XHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG51bWJlciBvZiBhdmFpbGFibGUgcmVzb3VyY2VzOiAke2F2YWlsYWJsZX0uYCk7XHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG51bWJlciBvZiBhY3F1aXJlZCByZXNvdXJjZXM6ICR7dXNlZH0uYCk7XHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG51bWJlciBvZiByZXNvdXJjZXMgd2FpdGluZyB0byBiZSBhY3F1aXJlZDogJHtwZW5kaW5nfS5gKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEdldHMgdGhlIHN0YXRpc3RpYyBvZiBhIHBvb2wgaW5zdGFjZSBhYm91dCBleHBvcnRzLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldFN0YXRzKCkge1xyXG4gIHJldHVybiBzdGF0cztcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGluaXRQb29sLFxyXG4gIGtpbGxQb29sLFxyXG4gIHBvc3RXb3JrLFxyXG4gIGdldFBvb2wsXHJcbiAgZ2V0UG9vbEluZm8sXHJcbiAgZ2V0UG9vbEluZm9KU09OLFxyXG4gIGdldFN0YXRzXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jLCB3cml0ZUZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5cclxuaW1wb3J0IHsgZ2V0T3B0aW9ucywgaW5pdEV4cG9ydFNldHRpbmdzIH0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsga2lsbFBvb2wsIHBvc3RXb3JrLCBzdGF0cyB9IGZyb20gJy4vcG9vbC5qcyc7XHJcbmltcG9ydCB7XHJcbiAgZml4VHlwZSxcclxuICBoYW5kbGVSZXNvdXJjZXMsXHJcbiAgaXNDb3JyZWN0SlNPTixcclxuICBvcHRpb25zU3RyaW5naWZ5LFxyXG4gIHJvdW5kTnVtYmVyLFxyXG4gIHRvQm9vbGVhbixcclxuICB3cmFwQXJvdW5kXHJcbn0gZnJvbSAnLi91dGlscy5qcyc7XHJcbmltcG9ydCB7IHNhbml0aXplIH0gZnJvbSAnLi9zYW5pdGl6ZS5qcyc7XHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG5sZXQgYWxsb3dDb2RlRXhlY3V0aW9uID0gZmFsc2U7XHJcblxyXG4vKipcclxuICogU3RhcnRzIGFuIGV4cG9ydCBwcm9jZXNzLiBUaGUgYHNldHRpbmdzYCBjb250YWlucyBmaW5hbCBvcHRpb25zIGdhdGhlcmVkXHJcbiAqIGZyb20gYWxsIHBvc3NpYmxlIHNvdXJjZXMgKGNvbmZpZywgZW52LCBjbGksIGpzb24pLiBUaGUgYGVuZENhbGxiYWNrYCBpc1xyXG4gKiBjYWxsZWQgd2hlbiB0aGUgZXhwb3J0IGlzIGNvbXBsZXRlZCwgd2l0aCBhbiBlcnJvciBvYmplY3QgYXMgdGhlIGZpcnN0XHJcbiAqIGFyZ3VtZW50IGFuZCB0aGUgc2Vjb25kIGNvbnRhaW5pbmcgdGhlIGJhc2U2NCByZXNwcmVzZW50YXRpb24gb2YgYSBjaGFydC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHNldHRpbmdzIC0gVGhlIHNldHRpbmdzIG9iamVjdCBjb250YWluaW5nIGV4cG9ydFxyXG4gKiBjb25maWd1cmF0aW9uLlxyXG4gKiBAcGFyYW0ge2Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIFRoZSBjYWxsYmFjayBmdW5jdGlvbiB0byBiZSBpbnZva2VkIHVwb25cclxuICogZmluYWxpemluZyB3b3JrIG9yIHVwb24gZXJyb3Igb2NjdXJhbmNlIG9mIHRoZSBleHBvcnRpbmcgcHJvY2Vzcy5cclxuICpcclxuICogQHJldHVybnMge3ZvaWR9IFRoaXMgZnVuY3Rpb24gZG9lcyBub3QgcmV0dXJuIGEgdmFsdWUgZGlyZWN0bHk7IGluc3RlYWQsXHJcbiAqIGl0IGNvbW11bmljYXRlcyByZXN1bHRzIHZpYSB0aGUgZW5kQ2FsbGJhY2suXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc3RhcnRFeHBvcnQgPSBhc3luYyAoc2V0dGluZ3MsIGVuZENhbGxiYWNrKSA9PiB7XHJcbiAgLy8gU3RhcnRpbmcgZXhwb3J0aW5nIHByb2Nlc3MgbWVzc2FnZVxyXG4gIGxvZyg0LCAnW2NoYXJ0XSBTdGFydGluZyB0aGUgZXhwb3J0aW5nIHByb2Nlc3MuJyk7XHJcblxyXG4gIC8vIEluaXRpYWxpemUgb3B0aW9uc1xyXG4gIGNvbnN0IG9wdGlvbnMgPSBpbml0RXhwb3J0U2V0dGluZ3Moc2V0dGluZ3MsIGdldE9wdGlvbnMoKSk7XHJcblxyXG4gIC8vIEdldCB0aGUgZXhwb3J0IG9wdGlvbnNcclxuICBjb25zdCBleHBvcnRPcHRpb25zID0gb3B0aW9ucy5leHBvcnQ7XHJcblxyXG4gIC8vIElmIFNWRyBpcyBhbiBpbnB1dCAoYXJndW1lbnQgY2FuIGJlIHNlbnQgb25seSBieSB0aGUgcmVxdWVzdClcclxuICBpZiAob3B0aW9ucy5wYXlsb2FkPy5zdmcgJiYgb3B0aW9ucy5wYXlsb2FkLnN2ZyAhPT0gJycpIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGxvZyg0LCAnW2NoYXJ0XSBBdHRlbXB0aW5nIHRvIGV4cG9ydCBmcm9tIGEgU1ZHIGlucHV0LicpO1xyXG5cclxuICAgICAgY29uc3QgcmVzdWx0ID0gZXhwb3J0QXNTdHJpbmcoXHJcbiAgICAgICAgc2FuaXRpemUob3B0aW9ucy5wYXlsb2FkLnN2ZyksIC8vICMyMDlcclxuICAgICAgICBvcHRpb25zLFxyXG4gICAgICAgIGVuZENhbGxiYWNrXHJcbiAgICAgICk7XHJcblxyXG4gICAgICArK3N0YXRzLmV4cG9ydEZyb21TdmdBdHRlbXB0cztcclxuICAgICAgcmV0dXJuIHJlc3VsdDtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgICAgICBuZXcgRXhwb3J0RXJyb3IoJ1tjaGFydF0gRXJyb3IgbG9hZGluZyBTVkcgaW5wdXQuJykuc2V0RXJyb3IoZXJyb3IpXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBFeHBvcnQgdXNpbmcgb3B0aW9ucyBmcm9tIHRoZSBmaWxlXHJcbiAgaWYgKGV4cG9ydE9wdGlvbnMuaW5maWxlICYmIGV4cG9ydE9wdGlvbnMuaW5maWxlLmxlbmd0aCkge1xyXG4gICAgLy8gVHJ5IHRvIHJlYWQgdGhlIGZpbGUgdG8gZ2V0IHRoZSBzdHJpbmcgcmVwcmVzZW50YXRpb25cclxuICAgIHRyeSB7XHJcbiAgICAgIGxvZyg0LCAnW2NoYXJ0XSBBdHRlbXB0aW5nIHRvIGV4cG9ydCBmcm9tIGFuIGlucHV0IGZpbGUuJyk7XHJcbiAgICAgIG9wdGlvbnMuZXhwb3J0Lmluc3RyID0gcmVhZEZpbGVTeW5jKGV4cG9ydE9wdGlvbnMuaW5maWxlLCAndXRmOCcpO1xyXG4gICAgICByZXR1cm4gZXhwb3J0QXNTdHJpbmcob3B0aW9ucy5leHBvcnQuaW5zdHIudHJpbSgpLCBvcHRpb25zLCBlbmRDYWxsYmFjayk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICAgICAgbmV3IEV4cG9ydEVycm9yKCdbY2hhcnRdIEVycm9yIGxvYWRpbmcgaW5wdXQgZmlsZS4nKS5zZXRFcnJvcihlcnJvcilcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIEV4cG9ydCB3aXRoIG9wdGlvbnMgZnJvbSB0aGUgcmF3IHJlcHJlc2VudGF0aW9uXHJcbiAgaWYgKFxyXG4gICAgKGV4cG9ydE9wdGlvbnMuaW5zdHIgJiYgZXhwb3J0T3B0aW9ucy5pbnN0ciAhPT0gJycpIHx8XHJcbiAgICAoZXhwb3J0T3B0aW9ucy5vcHRpb25zICYmIGV4cG9ydE9wdGlvbnMub3B0aW9ucyAhPT0gJycpXHJcbiAgKSB7XHJcbiAgICB0cnkge1xyXG4gICAgICBsb2coNCwgJ1tjaGFydF0gQXR0ZW1wdGluZyB0byBleHBvcnQgZnJvbSBhIHJhdyBpbnB1dC4nKTtcclxuXHJcbiAgICAgIC8vIFBlcmZvcm0gYSBkaXJlY3QgaW5qZWN0IHdoZW4gZm9yY2VkXHJcbiAgICAgIGlmICh0b0Jvb2xlYW4ob3B0aW9ucy5jdXN0b21Mb2dpYz8uYWxsb3dDb2RlRXhlY3V0aW9uKSkge1xyXG4gICAgICAgIHJldHVybiBkb1N0cmFpZ2h0SW5qZWN0KG9wdGlvbnMsIGVuZENhbGxiYWNrKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gRWl0aGVyIHRyeSB0byBwYXJzZSB0byBKU09OIGZpcnN0IG9yIGRvIHRoZSBkaXJlY3QgZXhwb3J0XHJcbiAgICAgIHJldHVybiB0eXBlb2YgZXhwb3J0T3B0aW9ucy5pbnN0ciA9PT0gJ3N0cmluZydcclxuICAgICAgICA/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+IHRhZ3MgYW5kIGFueSBjb250ZW50IHdpdGhpbiB0aGVtLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gaW5wdXQgVGhlIEhUTUwgc3RyaW5nIHRvIGJlIHNhbml0aXplZC5cclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIHNhbml0aXplZCBIVE1MIHN0cmluZy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBzYW5pdGl6ZShpbnB1dCkge1xyXG4gIGNvbnN0IHdpbmRvdyA9IG5ldyBKU0RPTSgnJykud2luZG93O1xyXG4gIGNvbnN0IHB1cmlmeSA9IERPTVB1cmlmeSh3aW5kb3cpO1xyXG4gIHJldHVybiBwdXJpZnkuc2FuaXRpemUoaW5wdXQsIHsgQUREX1RBR1M6IFsnZm9yZWlnbk9iamVjdCddIH0pO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCBzYW5pdGl6ZTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcblxyXG4vLyBBcnJheSB0aGF0IGNvbnRhaW5zIGlkcyBvZiBhbGwgb25nb2luZyBpbnRlcnZhbHMgYW5kIHRpbWVvdXRzXHJcbmNvbnN0IHRpbWVySWRzID0gW107XHJcblxyXG4vKipcclxuICogQWRkcyBpZCBvZiBzZXRJbnRlcnZhbCBvciBzZXRUaW1lb3V0IGFuZCB0byB0aGUgaW50ZXJ2YWxJZHMgYXJyYXkuXHJcbiAqXHJcbiAqIEBwYXJhbSB7Tm9kZUpTLlRpbWVvdXR9IGlkIC0gSWQgb2YgYW4gaW50ZXJ2YWwvdGltZW91dC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBhZGRUaW1lciA9IChpZCkgPT4ge1xyXG4gIHRpbWVySWRzLnB1c2goaWQpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIENsZWFycyBhbGwgb2Ygb25nb2luZyBpbnRlcnZhbHMgYW5kIHRpbWVvdXRzIGJ5IGlkcyBnYXRoZXJlZCBpbiB0aGUgdGltZXJJZHNcclxuICogYXJyYXkuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgY2xlYXJBbGxUaW1lcnMgPSAoKSA9PiB7XHJcbiAgbG9nKDQsIGBbc2VydmVyXSBDbGVhcmluZyBhbGwgcmVnaXN0ZXJlZCBpbnRlcnZhbHMgYW5kIHRpbWVvdXRzLmApO1xyXG4gIGZvciAoY29uc3QgaWQgb2YgdGltZXJJZHMpIHtcclxuICAgIGNsZWFySW50ZXJ2YWwoaWQpO1xyXG4gICAgY2xlYXJUaW1lb3V0KGlkKTtcclxuICB9XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgYWRkVGltZXIsXHJcbiAgY2xlYXJBbGxUaW1lcnNcclxufTtcclxuIiwiaW1wb3J0IHsgZW52cyB9IGZyb20gJy4uL2VudnMuanMnO1xyXG5pbXBvcnQgeyBsb2dXaXRoU3RhY2sgfSBmcm9tICcuLi9sb2dnZXIuanMnO1xyXG5cclxuLyoqXHJcbiAqIE1pZGRsZXdhcmUgZm9yIGxvZ2dpbmcgZXJyb3JzIHdpdGggc3RhY2sgdHJhY2UgYW5kIGhhbmRsaW5nIGVycm9yIHJlc3BvbnNlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0Vycm9yfSBlcnJvciAtIFRoZSBlcnJvciBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXEgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXMgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IG5leHQgLSBUaGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKi9cclxuY29uc3QgbG9nRXJyb3JNaWRkbGV3YXJlID0gKGVycm9yLCByZXEsIHJlcywgbmV4dCkgPT4ge1xyXG4gIC8vIERpc3BsYXkgdGhlIGVycm9yIHdpdGggc3RhY2sgaW4gYSBjb3JyZWN0IGZvcm1hdFxyXG4gIGxvZ1dpdGhTdGFjaygxLCBlcnJvcik7XHJcblxyXG4gIC8vIERlbGV0ZSB0aGUgc3RhY2sgZm9yIHRoZSBlbnZpcm9ubWVudCBvdGhlciB0aGFuIHRoZSBkZXZlbG9wbWVudFxyXG4gIGlmIChlbnZzLk9USEVSX05PREVfRU5WICE9PSAnZGV2ZWxvcG1lbnQnKSB7XHJcbiAgICBkZWxldGUgZXJyb3Iuc3RhY2s7XHJcbiAgfVxyXG5cclxuICAvLyBDYWxsIHRoZSByZXR1cm5FcnJvck1pZGRsZXdhcmVcclxuICBuZXh0KGVycm9yKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBNaWRkbGV3YXJlIGZvciByZXR1cm5pbmcgZXJyb3IgcmVzcG9uc2UuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXJyb3J9IGVycm9yIC0gVGhlIGVycm9yIG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcSAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlcyAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gbmV4dCAtIFRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXHJcbiAqL1xyXG5jb25zdCByZXR1cm5FcnJvck1pZGRsZXdhcmUgPSAoZXJyb3IsIHJlcSwgcmVzLCBuZXh0KSA9PiB7XHJcbiAgLy8gR2F0aGVyIGFsbCByZXF1aWVkIGluZm9ybWF0aW9uIGZvciB0aGUgcmVzcG9uc2VcclxuICBjb25zdCB7IHN0YXR1c0NvZGU6IHN0Q29kZSwgc3RhdHVzLCBtZXNzYWdlLCBzdGFjayB9ID0gZXJyb3I7XHJcbiAgY29uc3Qgc3RhdHVzQ29kZSA9IHN0Q29kZSB8fCBzdGF0dXMgfHwgNTAwO1xyXG5cclxuICAvLyBTZXQgYW5kIHJldHVybiByZXNwb25zZVxyXG4gIHJlcy5zdGF0dXMoc3RhdHVzQ29kZSkuanNvbih7IHN0YXR1c0NvZGUsIG1lc3NhZ2UsIHN0YWNrIH0pO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQgKGFwcCkgPT4ge1xyXG4gIC8vIEFkZCBsb2cgZXJyb3IgbWlkZGxld2FyZVxyXG4gIGFwcC51c2UobG9nRXJyb3JNaWRkbGV3YXJlKTtcclxuXHJcbiAgLy8gQWRkIHNldCBzdGF0dXMgYW5kIHJldHVybiBlcnJvciBtaWRkbGV3YXJlXHJcbiAgYXBwLnVzZShyZXR1cm5FcnJvck1pZGRsZXdhcmUpO1xyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCByYXRlTGltaXQgZnJvbSAnZXhwcmVzcy1yYXRlLWxpbWl0JztcclxuXHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4uL2xvZ2dlci5qcyc7XHJcblxyXG4vKipcclxuICogTWlkZGxld2FyZSBmb3IgZW5hYmxpbmcgcmF0ZSBsaW1pdGluZyBvbiB0aGUgc3BlY2lmaWVkIEV4cHJlc3MgYXBwLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3N9IGFwcCAtIFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICogQHBhcmFtIHtPYmplY3R9IGxpbWl0Q29uZmlnIC0gQ29uZmlndXJhdGlvbiBvcHRpb25zIGZvciByYXRlIGxpbWl0aW5nLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgKGFwcCwgbGltaXRDb25maWcpID0+IHtcclxuICBjb25zdCBtc2cgPVxyXG4gICAgJ1RvbyBtYW55IHJlcXVlc3RzLCB5b3UgaGF2ZSBiZWVuIHJhdGUgbGltaXRlZC4gUGxlYXNlIHRyeSBhZ2FpbiBsYXRlci4nO1xyXG5cclxuICAvLyBPcHRpb25zIGZvciB0aGUgcmF0ZSBsaW1pdGVyXHJcbiAgY29uc3QgcmF0ZU9wdGlvbnMgPSB7XHJcbiAgICBtYXg6IGxpbWl0Q29uZmlnLm1heFJlcXVlc3RzIHx8IDMwLFxyXG4gICAgd2luZG93OiBsaW1pdENvbmZpZy53aW5kb3cgfHwgMSxcclxuICAgIGRlbGF5OiBsaW1pdENvbmZpZy5kZWxheSB8fCAwLFxyXG4gICAgdHJ1c3RQcm94eTogbGltaXRDb25maWcudHJ1c3RQcm94eSB8fCBmYWxzZSxcclxuICAgIHNraXBLZXk6IGxpbWl0Q29uZmlnLnNraXBLZXkgfHwgZmFsc2UsXHJcbiAgICBza2lwVG9rZW46IGxpbWl0Q29uZmlnLnNraXBUb2tlbiB8fCBmYWxzZVxyXG4gIH07XHJcblxyXG4gIC8vIFNldCBpZiBiZWhpbmQgYSBwcm94eVxyXG4gIGlmIChyYXRlT3B0aW9ucy50cnVzdFByb3h5KSB7XHJcbiAgICBhcHAuZW5hYmxlKCd0cnVzdCBwcm94eScpO1xyXG4gIH1cclxuXHJcbiAgLy8gQ3JlYXRlIGEgbGltaXRlclxyXG4gIGNvbnN0IGxpbWl0ZXIgPSByYXRlTGltaXQoe1xyXG4gICAgd2luZG93TXM6IHJhdGVPcHRpb25zLndpbmRvdyAqIDYwICogMTAwMCxcclxuICAgIC8vIExpbWl0IGVhY2ggSVAgdG8gMTAwIHJlcXVlc3RzIHBlciB3aW5kb3dNc1xyXG4gICAgbWF4OiByYXRlT3B0aW9ucy5tYXgsXHJcbiAgICAvLyBEaXNhYmxlIGRlbGF5aW5nLCBmdWxsIHNwZWVkIHVudGlsIHRoZSBtYXggbGltaXQgaXMgcmVhY2hlZFxyXG4gICAgZGVsYXlNczogcmF0ZU9wdGlvbnMuZGVsYXksXHJcbiAgICBoYW5kbGVyOiAocmVxdWVzdCwgcmVzcG9uc2UpID0+IHtcclxuICAgICAgcmVzcG9uc2UuZm9ybWF0KHtcclxuICAgICAgICBqc29uOiAoKSA9PiB7XHJcbiAgICAgICAgICByZXNwb25zZS5zdGF0dXMoNDI5KS5zZW5kKHsgbWVzc2FnZTogbXNnIH0pO1xyXG4gICAgICAgIH0sXHJcbiAgICAgICAgZGVmYXVsdDogKCkgPT4ge1xyXG4gICAgICAgICAgcmVzcG9uc2Uuc3RhdHVzKDQyOSkuc2VuZChtc2cpO1xyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcbiAgICB9LFxyXG4gICAgc2tpcDogKHJlcXVlc3QpID0+IHtcclxuICAgICAgLy8gQWxsb3cgYnlwYXNzaW5nIHRoZSBsaW1pdGVyIGlmIGEgdmFsaWQga2V5L3Rva2VuIGhhcyBiZWVuIHNlbnRcclxuICAgICAgaWYgKFxyXG4gICAgICAgIHJhdGVPcHRpb25zLnNraXBLZXkgIT09IGZhbHNlICYmXHJcbiAgICAgICAgcmF0ZU9wdGlvbnMuc2tpcFRva2VuICE9PSBmYWxzZSAmJlxyXG4gICAgICAgIHJlcXVlc3QucXVlcnkua2V5ID09PSByYXRlT3B0aW9ucy5za2lwS2V5ICYmXHJcbiAgICAgICAgcmVxdWVzdC5xdWVyeS5hY2Nlc3NfdG9rZW4gPT09IHJhdGVPcHRpb25zLnNraXBUb2tlblxyXG4gICAgICApIHtcclxuICAgICAgICBsb2coNCwgJ1tyYXRlIGxpbWl0aW5nXSBTa2lwcGluZyByYXRlIGxpbWl0ZXIuJyk7XHJcbiAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICAvLyBVc2UgYSBsaW1pdGVyIGFzIGEgbWlkZGxld2FyZVxyXG4gIGFwcC51c2UobGltaXRlcik7XHJcblxyXG4gIGxvZyhcclxuICAgIDMsXHJcbiAgICBgW3JhdGUgbGltaXRpbmddIEVuYWJsZWQgcmF0ZSBsaW1pdGluZyB3aXRoICR7cmF0ZU9wdGlvbnMubWF4fSByZXF1ZXN0cyBwZXIgJHtyYXRlT3B0aW9ucy53aW5kb3d9IG1pbnV0ZSBmb3IgZWFjaCBJUCwgdHJ1c3RpbmcgcHJveHk6ICR7cmF0ZU9wdGlvbnMudHJ1c3RQcm94eX0uYFxyXG4gICk7XHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDIzLCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgeyBfX2Rpcm5hbWUgfSBmcm9tICcuL3V0aWxzLmpzJztcclxuXHJcbi8vIEdldCB0aGUgdGVsZW1ldHJ5IHRlbXBsYXRlXHJcbmNvbnN0IHRlbGVtZXRyeVRlbXBsYXRlID0gSlNPTi5wYXJzZShcclxuICByZWFkRmlsZVN5bmMoam9pbihfX2Rpcm5hbWUsICdsaWInLCAnc2NoZW1hcycsICd0ZWxlbWV0cnkuanNvbicpKVxyXG4pO1xyXG5cclxuLy8gVGhlIG9iamVjdCB3aXRoIHRlbGVtZXRyeSBkYXRhIGNvbGxlY3RlZFxyXG5leHBvcnQgY29uc3QgdGVsZW1ldHJ5RGF0YSA9IHtcclxuICBudW1iZXJPZlJlcXVlc3RzOiAwXHJcbn07XHJcblxyXG4vLyBQb3NzaWJsZSBwcm9wZXJ0aWVzIGluIGFuIGFycmF5XHJcbmNvbnN0IG9wdGlvbnNJbkFycmF5ID0gWydzZXJpZXMnLCAneEF4aXMnLCAneUF4aXMnLCAnekF4aXMnXTtcclxuXHJcbi8vIFJlY3Vyc2l2ZSBmdW5jdGlvbiBmb3IgZ2V0dGluZyBvbmx5IHRoZSByZXF1aXJlZCBvcHRpb25zXHJcbmZ1bmN0aW9uIGZpbHRlckRhdGEodGVtcGxhdGUsIG9wdGlvbnMpIHtcclxuICBjb25zdCBmaWx0ZXJlZE9iamVjdCA9IHt9O1xyXG5cclxuICAvLyBDeWNsZSB0aHJvdWdoIGFsbG93ZWQgcHJvcGV0aWVzXHJcbiAgZm9yIChjb25zdCBbdGVtcGxhdGVLZXksIHRlbXBsYXRlVmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKHRlbXBsYXRlKSkge1xyXG4gICAgLy8gQ2hlY2sgaWYgdGhlIHNlY3Rpb24gZXhpc3RzXHJcbiAgICBpZiAob3B0aW9uc1t0ZW1wbGF0ZUtleV0gIT09IHVuZGVmaW5lZCkge1xyXG4gICAgICAvLyBDaGVjayBpZiB0aGlzIGlzIHRoZSBmaW5hbCBsZXZlbCBvZiBpbmRlbnQgaW4gdGhlIHRlbXBsYXRlXHJcbiAgICAgIGlmICh0ZW1wbGF0ZVZhbHVlICE9PSBudWxsKSB7XHJcbiAgICAgICAgLy8gQ2hlY2sgaWYgaXQgaXMgYW4gYXJyYXlcclxuICAgICAgICBpZiAoQXJyYXkuaXNBcnJheShvcHRpb25zW3RlbXBsYXRlS2V5XSkpIHtcclxuICAgICAgICAgIC8vIEFuZCBpZiBpdCBjb250YWlucyBhbGxvd2VkIHByb3BlcnRpZXNcclxuICAgICAgICAgIGlmIChvcHRpb25zSW5BcnJheS5pbmNsdWRlcyh0ZW1wbGF0ZUtleSkpIHtcclxuICAgICAgICAgICAgLy8gQ3JlYXRlIGFuIGFycmF5XHJcbiAgICAgICAgICAgIGZpbHRlcmVkT2JqZWN0W3RlbXBsYXRlS2V5XSA9IFtdO1xyXG4gICAgICAgICAgICAvLyBJZiBzbywgY3ljbGUgdGhyb3VnaCBhbGwgb2YgdGhlbVxyXG4gICAgICAgICAgICBmb3IgKGNvbnN0IFtpbmRleCwgb3B0aW9uc1ZhbHVlXSBvZiBvcHRpb25zW1xyXG4gICAgICAgICAgICAgIHRlbXBsYXRlS2V5XHJcbiAgICAgICAgICAgIF0uZW50cmllcygpKSB7XHJcbiAgICAgICAgICAgICAgZmlsdGVyZWRPYmplY3RbdGVtcGxhdGVLZXldW2luZGV4XSA9IGZpbHRlckRhdGEoXHJcbiAgICAgICAgICAgICAgICB0ZW1wbGF0ZVZhbHVlLFxyXG4gICAgICAgICAgICAgICAgb3B0aW9uc1ZhbHVlXHJcbiAgICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgLy8gT3RoZXJ3aXNlLCBnZXQgb25seSB0aGUgZmlyc3QgZWxlbWVudFxyXG4gICAgICAgICAgICBmaWx0ZXJlZE9iamVjdFt0ZW1wbGF0ZUtleV0gPSBmaWx0ZXJEYXRhKFxyXG4gICAgICAgICAgICAgIHRlbXBsYXRlVmFsdWUsXHJcbiAgICAgICAgICAgICAgb3B0aW9uc1t0ZW1wbGF0ZUtleV1bMF1cclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgZmlsdGVyZWRPYmplY3RbdGVtcGxhdGVLZXldID0gZmlsdGVyRGF0YShcclxuICAgICAgICAgICAgdGVtcGxhdGVWYWx1ZSxcclxuICAgICAgICAgICAgb3B0aW9uc1t0ZW1wbGF0ZUtleV1cclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIC8vIFJldHVybiB0aGUgb3B0aW9uXHJcbiAgICAgICAgZmlsdGVyZWRPYmplY3RbdGVtcGxhdGVLZXldID0gb3B0aW9uc1t0ZW1wbGF0ZUtleV07XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiB0aGUgb2JqZWN0XHJcbiAgcmV0dXJuIGZpbHRlcmVkT2JqZWN0O1xyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gcHJlcGFyZVRlbGVtZXRyeShjaGFydE9wdGlvbnMsIHJlcXVlc3RJZCkge1xyXG4gIC8vIFNhdmUgdGhlIGZpbHRlcmVkIG9wdGlvbnMgdW5kZXIgdGhlIHJlcXVlc3QncyBpZFxyXG4gIHRlbGVtZXRyeURhdGFbcmVxdWVzdElkXSA9IGZpbHRlckRhdGEodGVsZW1ldHJ5VGVtcGxhdGUsIGNoYXJ0T3B0aW9ucyk7XHJcblxyXG4gIC8vIEluY3JlbWVudCByZXF1ZXN0cyBjb3VudGVyXHJcbiAgdGVsZW1ldHJ5RGF0YS5udW1iZXJPZlJlcXVlc3RzKys7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICB0ZWxlbWV0cnlEYXRhLFxyXG4gIHByZXBhcmVUZWxlbWV0cnlcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjMsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcbmltcG9ydCBqd3QgZnJvbSAnanNvbndlYnRva2VuJztcclxuaW1wb3J0IHsgdjQgYXMgdXVpZCB9IGZyb20gJ3V1aWQnO1xyXG5pbXBvcnQgV2ViU29ja2V0IGZyb20gJ3dzJztcclxuXHJcbmltcG9ydCB7IGdldE9wdGlvbnMgfSBmcm9tICcuLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4uL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IHRlbGVtZXRyeURhdGEgfSBmcm9tICcuLi90ZWxlbWV0cnkuanMnO1xyXG5pbXBvcnQgeyBhZGRUaW1lciB9IGZyb20gJy4uL3RpbWVycy5qcyc7XHJcblxyXG4vLyBXZWJTb2NrZXQgY2xpZW50cyBtYXBcclxuY29uc3Qgd2ViU29ja2V0Q2xpZW50cyA9IG5ldyBNYXAoKTtcclxuXHJcbi8vIFdlYlNvY2tldCBvcHRpb25zXHJcbmxldCB3ZWJTb2NrZXRPcHRpb25zO1xyXG5cclxuLy8gV2ViU29ja2V0IG1lc3NhZ2Ugc2VuZGluZyBpbnRlcnZhbFxyXG5sZXQgbWVzc2FnZUludGVydmFsID0gbnVsbDtcclxuXHJcbi8qKlxyXG4gKiBJbml0IFdlYlNvY2tldCBjbGllbnQgYW5kIGNvbm5lY3Rpb24gb3B0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtvYmplY3R9IGFkZHJlc3MgLSBPYmplY3QgdGhhdCBjb250YWlucywgYWRkcmVzcyBhbmQgcG9ydCBvZiBlbmFibGVkXHJcbiAqIEhUVFAgb3IgSFRUUFMgc2VydmVyLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGluaXQoYWRkcmVzcykge1xyXG4gIHdlYlNvY2tldE9wdGlvbnMgPSBnZXRPcHRpb25zKCkud2ViU29ja2V0O1xyXG4gIGlmICh3ZWJTb2NrZXRPcHRpb25zLmVuYWJsZSA9PT0gdHJ1ZSkge1xyXG4gICAgLy8gT3B0aW9ucyBmb3IgdGhlIFdlYlNvY2tldCBjb25uZWN0aW9uXHJcbiAgICBjb25zdCBjb25uZWN0aW9uT3B0aW9ucyA9IHtcclxuICAgICAgcmVqZWN0VW5hdXRob3JpemVkOiB3ZWJTb2NrZXRPcHRpb25zLnJlamVjdFVuYXV0aG9yaXplZCxcclxuICAgICAgaGVhZGVyczoge1xyXG4gICAgICAgIC8vIFNldCBhbiBhY2Nlc3MgdG9rZW4gdGhhdCBsYXN0cyBvbmx5IDUgbWludXRlc1xyXG4gICAgICAgIGF1dGg6IGp3dC5zaWduKHsgc3VjY2VzczogJ3N1Y2Nlc3MnIH0sIHdlYlNvY2tldE9wdGlvbnMuc2VjcmV0LCB7XHJcbiAgICAgICAgICBhbGdvcml0aG06ICdIUzI1NidcclxuICAgICAgICB9KSxcclxuICAgICAgICAvLyBTZW5kIHRoZSBzZXJ2ZXIgYWRkcmVzcyBpbiBhIGN1c3RvbSBoZWFkZXJcclxuICAgICAgICAnWC1TZXJ2ZXItQWRkcmVzcyc6IGAke2FkZHJlc3MucHJvdG9jb2x9Oi8vJHtcclxuICAgICAgICAgIFsnOjonLCAnMC4wLjAuMCddLmluY2x1ZGVzKGFkZHJlc3MuYWRkcmVzcylcclxuICAgICAgICAgICAgPyAnbG9jYWxob3N0J1xyXG4gICAgICAgICAgICA6IGFkZHJlc3MuYWRkcmVzc1xyXG4gICAgICAgIH06JHthZGRyZXNzLnBvcnR9YFxyXG4gICAgICB9XHJcbiAgICB9O1xyXG5cclxuICAgIC8vIE9wdGlvbnMgZm9yIHRoZSBXZWJTb2NrZXQgY2xpZW50XHJcbiAgICBjb25zdCBjbGllbnRPcHRpb25zID0ge1xyXG4gICAgICBpZDogdXVpZCgpLFxyXG4gICAgICByZWNvbm5lY3Q6IHdlYlNvY2tldE9wdGlvbnMucmVjb25uZWN0LFxyXG4gICAgICByZWNvbm5lY3RUcnk6IDAsXHJcbiAgICAgIHJlY29ubmVjdEludGVydmFsOiBudWxsLFxyXG4gICAgICBwaW5nVGltZW91dDogbnVsbFxyXG4gICAgfTtcclxuXHJcbiAgICAvLyBTdGFydCB0aGUgV2ViU29ja2V0IGNvbm5lY3Rpb25cclxuICAgIGNvbm5lY3Qod2ViU29ja2V0T3B0aW9ucy51cmwsIGNvbm5lY3Rpb25PcHRpb25zLCBjbGllbnRPcHRpb25zKTtcclxuXHJcbiAgICAvLyBTdGFydCB0aGUgV2ViU29ja2V0IG1lc3NhZ2Ugc2VuZGluZyBpbnRlcnZhbFxyXG4gICAgc2VuZGluZ01lc3NhZ2VJbnRlcnZhbCh3ZWJTb2NrZXRPcHRpb25zKTtcclxuICB9XHJcbn1cclxuXHJcbmZ1bmN0aW9uIHNlbmRpbmdNZXNzYWdlSW50ZXJ2YWwod2ViU29ja2V0T3B0aW9ucykge1xyXG4gIC8vIFNldCB0aGUgc2VuZGluZyBtZXNzYWdlIGludGVydmFsXHJcbiAgbWVzc2FnZUludGVydmFsID0gc2V0SW50ZXJ2YWwoKCkgPT4ge1xyXG4gICAgdHJ5IHtcclxuICAgICAgLy8gR2V0IHRoZSBmaXJzdCBXZWJTb2NrZXQgY2xpZW50XHJcbiAgICAgIGNvbnN0IHdlYlNvY2tldENsaWVudCA9IGdldENsaWVudHMoKS5uZXh0KCkudmFsdWU7XHJcbiAgICAgIC8vIElmIHRoZSBjbGllbnQgaXMgZm91bmQsIG9wZW4gYW5kIHRoZXJlIGlzIGRhdGEgdG8gc2VuZFxyXG4gICAgICBpZiAoXHJcbiAgICAgICAgd2ViU29ja2V0Q2xpZW50ICYmXHJcbiAgICAgICAgd2ViU29ja2V0Q2xpZW50LnJlYWR5U3RhdGUgPT09IFdlYlNvY2tldC5PUEVOICYmXHJcbiAgICAgICAgT2JqZWN0LmtleXModGVsZW1ldHJ5RGF0YSkubGVuZ3RoID4gMSAmJlxyXG4gICAgICAgIHRlbGVtZXRyeURhdGEubnVtYmVyT2ZSZXF1ZXN0cyA+IDBcclxuICAgICAgKSB7XHJcbiAgICAgICAgLy8gU2VuZCB0aHJvdWdoIHRoZSBXZWJTb2NrZXRcclxuICAgICAgICB3ZWJTb2NrZXRDbGllbnQuc2VuZChKU09OLnN0cmluZ2lmeSh0ZWxlbWV0cnlEYXRhKSk7XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGxvZ1dpdGhTdGFjaygxLCBgW3dlYnNvY2tldF0gQ291bGQgbm90IHNlbmQgZGF0YSB0aHJvdWdoIFdlYlNvY2tldC5gKTtcclxuICAgIH1cclxuICB9LCB3ZWJTb2NrZXRPcHRpb25zLm1lc3NhZ2VJbnRlcnZhbCk7XHJcblxyXG4gIC8vIFJlZ2lzdGVyIGludGVydmFsIGZvciB0aGUgbGF0ZXIgY2xlYXJpbmdcclxuICBhZGRUaW1lcihtZXNzYWdlSW50ZXJ2YWwpO1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBXZWJTb2NrZXQgY2xpZW50IGFuZCBjb25uZWN0cyB0byBXZWJTb2NrZXQgc2VydmVyIG9uIGEgcHJvdmlkZWQgdXJsLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gd2ViU29ja2V0VXJsIC0gVGhlIFdlYlNvY2tldCBzZXJ2ZXIncyBVUkwuXHJcbiAqIEBwYXJhbSB7b2JqZWN0fSBjb25uZWN0aW9uT3B0aW9ucyAtIE9wdGlvbnMgZm9yIFdlYlNvY2tldCBjb25uZWN0aW9uLlxyXG4gKiBAcGFyYW0ge29iamVjdH0gY2xpZW50T3B0aW9ucyAtIE9wdGlvbnMgZm9yIFdlYlNvY2tldCBjbGllbnQuXHJcbiAqL1xyXG5mdW5jdGlvbiBjb25uZWN0KHdlYlNvY2tldFVybCwgY29ubmVjdGlvbk9wdGlvbnMsIGNsaWVudE9wdGlvbnMpIHtcclxuICAvLyBUcnkgdG8gY29ubmVjdCB0byBpbmRpY2F0ZWQgV2ViU29ja2V0IHNlcnZlclxyXG4gIGxldCB3ZWJTb2NrZXRDbGllbnQgPSBuZXcgV2ViU29ja2V0KHdlYlNvY2tldFVybCwgY29ubmVjdGlvbk9wdGlvbnMpO1xyXG5cclxuICAvLyBPcGVuIGV2ZW50XHJcbiAgd2ViU29ja2V0Q2xpZW50Lm9uKCdvcGVuJywgKCkgPT4ge1xyXG4gICAgLy8gTm90IG5lZWQgZm9yIHRoZSByZWNvbm5lY3QgaW50ZXJ2YWwgYW55bW9yZVxyXG4gICAgY2xlYXJJbnRlcnZhbChjbGllbnRPcHRpb25zLnJlY29ubmVjdEludGVydmFsKTtcclxuXHJcbiAgICAvLyBTYXZlIHRoZSBjbGllbnQgdW5kZXIgaXRzIGlkXHJcbiAgICB3ZWJTb2NrZXRDbGllbnRzLnNldChjbGllbnRPcHRpb25zLmlkLCB3ZWJTb2NrZXRDbGllbnQpO1xyXG5cclxuICAgIC8vIExvZyBhIHN1Y2Nlc3MgbWVzc2FnZVxyXG4gICAgbG9nKFxyXG4gICAgICAzLFxyXG4gICAgICBgW3dlYnNvY2tldF0gV2ViU29ja2V0OiAke2NsaWVudE9wdGlvbnMuaWR9IC0gQ29ubmVjdGVkIHRvIHNlcnZlcjogJHt3ZWJTb2NrZXRVcmx9LmBcclxuICAgICk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIENsb3NlIGV2ZW50IHdoZXJlIHBpbmcgdGltZW91dCBpcyBjbGVhcmVkXHJcbiAgd2ViU29ja2V0Q2xpZW50Lm9uKCdjbG9zZScsIChjb2RlKSA9PiB7XHJcbiAgICBsb2coXHJcbiAgICAgIDMsXHJcbiAgICAgICdbd2Vic29ja2V0XScsXHJcbiAgICAgIGBXZWJTb2NrZXQ6ICR7Y2xpZW50T3B0aW9ucy5pZH0gLSBEaXNjb25uZWN0ZWQgZnJvbSBzZXJ2ZXI6ICR7d2ViU29ja2V0VXJsfSB3aXRoIGNvZGU6ICR7Y29kZX0uYFxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBTdG9wIHRoZSBoZWFydGJlYXQgbWVjaGFuaXNtXHJcbiAgICBjbGVhclRpbWVvdXQoY2xpZW50T3B0aW9ucy5waW5nVGltZW91dCk7XHJcblxyXG4gICAgLy8gUmVtb3ZlZCBjbGllbnQgaWYgZXhpc3RzXHJcbiAgICB3ZWJTb2NrZXRDbGllbnRzLmRlbGV0ZShjbGllbnRPcHRpb25zLmlkKTtcclxuICAgIHdlYlNvY2tldENsaWVudCA9IG51bGw7XHJcblxyXG4gICAgLy8gVHJ5IHRvIHJlY29ubmVjdCBvbmx5IHdoZW4gZW5hYmxlZCBhbmQgaWYgbm90IGFscmVhZHkgYXR0ZW1wdGluZyB0byBkbyBzb1xyXG4gICAgaWYgKGNsaWVudE9wdGlvbnMucmVjb25uZWN0ICYmICFjbGllbnRPcHRpb25zLnJlY29ubmVjdEludGVydmFsKSB7XHJcbiAgICAgIHJlY29ubmVjdCh3ZWJTb2NrZXRVcmwsIGNvbm5lY3Rpb25PcHRpb25zLCBjbGllbnRPcHRpb25zKTtcclxuICAgIH1cclxuICB9KTtcclxuXHJcbiAgLy8gRXJyb3IgZXZlbnRcclxuICB3ZWJTb2NrZXRDbGllbnQub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgIDEsXHJcbiAgICAgIGVycm9yLFxyXG4gICAgICBgW3dlYnNvY2tldF0gV2ViU29ja2V0OiAke2NsaWVudE9wdGlvbnMuaWR9IC0gRXJyb3Igb2NjdXJlZC5gXHJcbiAgICApO1xyXG5cclxuICAgIC8vIEJsb2NrIHRoZSByZWNvbm5lY3QgbWVjaGFuaXNtIHdoZW4gZ2V0dGluZyA0MDNcclxuICAgIGlmIChlcnJvci5tZXNzYWdlLmluY2x1ZGVzKCc0MDMnKSkge1xyXG4gICAgICBjbGllbnRPcHRpb25zLnJlY29ubmVjdCA9IGZhbHNlO1xyXG4gICAgICBjbGllbnRPcHRpb25zLnJlY29ubmVjdFRyeSA9IHdlYlNvY2tldE9wdGlvbnMucmVjb25uZWN0QXR0ZW1wdHM7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBPciBzZXQgdGhlIG9wdGlvbiBhY2NvcmRpbmdseVxyXG4gICAgICBjbGllbnRPcHRpb25zLnJlY29ubmVjdCA9IHdlYlNvY2tldE9wdGlvbnMucmVjb25uZWN0O1xyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICAvLyBNZXNzYWdlIGV2ZW50XHJcbiAgd2ViU29ja2V0Q2xpZW50Lm9uKCdtZXNzYWdlJywgKG1lc3NhZ2UpID0+IHtcclxuICAgIGxvZyhcclxuICAgICAgMyxcclxuICAgICAgYFt3ZWJzb2NrZXRdIFdlYlNvY2tldDogJHtjbGllbnRPcHRpb25zLmlkfSAtIERhdGEgcmVjZWl2ZWQ6ICR7bWVzc2FnZX1gXHJcbiAgICApO1xyXG4gIH0pO1xyXG5cclxuICAvLyBUaGUgJ3BpbmcnIGV2ZW50IGZyb20gYSBXZWJTb2NrZXQgY29ubmVjdGlvbiB3aXRoIHRoZSBoZWFsdGggY2hlY2tcclxuICAvLyBhbmQgdGVybWluYXRpb24gbG9naWNcclxuICB3ZWJTb2NrZXRDbGllbnQub24oJ3BpbmcnLCAoKSA9PiB7XHJcbiAgICBsb2coXHJcbiAgICAgIDMsXHJcbiAgICAgIGBbd2Vic29ja2V0XSBXZWJTb2NrZXQ6ICR7Y2xpZW50T3B0aW9ucy5pZH0gLSBSZWNlaXZlZCBQSU5HIGZyb20gc2VydmVyOiAke3dlYlNvY2tldFVybH0uYFxyXG4gICAgKTtcclxuICAgIGNsZWFyVGltZW91dChjbGllbnRPcHRpb25zLnBpbmdUaW1lb3V0KTtcclxuICAgIGNsaWVudE9wdGlvbnMucGluZ1RpbWVvdXQgPSBzZXRUaW1lb3V0KCgpID0+IHtcclxuICAgICAgLy8gVGVybWluYXRlIHRoZSBjbGllbnQgY29ubmVjdGlvblxyXG4gICAgICB3ZWJTb2NrZXRDbGllbnQudGVybWluYXRlKCk7XHJcblxyXG4gICAgICAvLyBUcnkgdG8gcmVjb25uZWN0IGlmIHJlcXVpcmVkXHJcbiAgICAgIGlmIChjbGllbnRPcHRpb25zLnJlY29ubmVjdCkge1xyXG4gICAgICAgIHJlY29ubmVjdCh3ZWJTb2NrZXRVcmwsIGNvbm5lY3Rpb25PcHRpb25zLCBjbGllbnRPcHRpb25zKTtcclxuICAgICAgfVxyXG4gICAgfSwgd2ViU29ja2V0T3B0aW9ucy5waW5nVGltZW91dCk7XHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZWNvbm5lY3RzIHRvIFdlYlNvY2tldCBzZXJ2ZXIgb24gYSBwcm92aWRlZCB1cmwuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB3ZWJTb2NrZXRVcmwgLSBUaGUgV2ViU29ja2V0IHNlcnZlcidzIFVSTC5cclxuICogQHBhcmFtIHtvYmplY3R9IGNvbm5lY3Rpb25PcHRpb25zIC0gT3B0aW9ucyBmb3IgV2ViU29ja2V0IGNvbm5lY3Rpb24uXHJcbiAqIEBwYXJhbSB7b2JqZWN0fSBjbGllbnRPcHRpb25zIC0gT3B0aW9ucyBmb3IgV2ViU29ja2V0IGNsaWVudC5cclxuICovXHJcbmZ1bmN0aW9uIHJlY29ubmVjdCh3ZWJTb2NrZXRVcmwsIGNvbm5lY3Rpb25PcHRpb25zLCBjbGllbnRPcHRpb25zKSB7XHJcbiAgLy8gU3RhcnQgdGhlIHJlY29ubmVjdCBpbnRlcnZhbFxyXG4gIGNsaWVudE9wdGlvbnMucmVjb25uZWN0SW50ZXJ2YWwgPSBzZXRJbnRlcnZhbCgoKSA9PiB7XHJcbiAgICBpZiAoY2xpZW50T3B0aW9ucy5yZWNvbm5lY3RUcnkgPCB3ZWJTb2NrZXRPcHRpb25zLnJlY29ubmVjdEF0dGVtcHRzKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICAzLFxyXG4gICAgICAgIGBbd2Vic29ja2V0XSBXZWJTb2NrZXQ6ICR7Y2xpZW50T3B0aW9ucy5pZH0gLSBBdHRlbXB0ICR7KytjbGllbnRPcHRpb25zLnJlY29ubmVjdFRyeX0gb2YgJHt3ZWJTb2NrZXRPcHRpb25zLnJlY29ubmVjdEF0dGVtcHRzfSB0byByZWNvbm5lY3QgdG8gc2VydmVyOiAke3dlYlNvY2tldFVybH0uYFxyXG4gICAgICApO1xyXG5cclxuICAgICAgY29ubmVjdCh3ZWJTb2NrZXRVcmwsIGNvbm5lY3Rpb25PcHRpb25zLCBjbGllbnRPcHRpb25zKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIGNsaWVudE9wdGlvbnMucmVjb25uZWN0ID0gZmFsc2U7XHJcbiAgICAgIGNsZWFySW50ZXJ2YWwoY2xpZW50T3B0aW9ucy5yZWNvbm5lY3RJbnRlcnZhbCk7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICAyLFxyXG4gICAgICAgIGBbd2Vic29ja2V0XSBXZWJTb2NrZXQ6ICR7Y2xpZW50T3B0aW9ucy5pZH0gLSBDb3VsZCBub3QgcmVjb25uZWN0IHRvIHNlcnZlcjogJHt3ZWJTb2NrZXRVcmx9LmBcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9LCB3ZWJTb2NrZXRPcHRpb25zLnJlY29ubmVjdEludGVydmFsKTtcclxuXHJcbiAgLy8gUmVnaXN0ZXIgaW50ZXJ2YWwgZm9yIHRoZSBsYXRlciBjbGVhcmluZ1xyXG4gIGFkZFRpbWVyKGNsaWVudE9wdGlvbnMucmVjb25uZWN0SW50ZXJ2YWwpO1xyXG59XHJcblxyXG4vKipcclxuICogR2V0cyBtYXAgb2YgY3VycmVudCBXZWJTb2NrZXQgY2xpZW50cy5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGlkIC0gVGhlIHV1aWQgb2YgV2ViU29ja2V0IGNsaWVudC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRDbGllbnRzKGlkKSB7XHJcbiAgcmV0dXJuIGlkID8gd2ViU29ja2V0Q2xpZW50cy5nZXQoaWQpIDogd2ViU29ja2V0Q2xpZW50cy52YWx1ZXMoKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFRlcm1pbmF0ZXMgYWxsIFdlYlNvY2tldCBjbGllbnRzIGFuZCBjbGVhciB0aGUgd2ViU29ja2V0Q2xpZW50cyBtYXAuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gdGVybWluYXRlQ2xpZW50cygpIHtcclxuICBmb3IgKGNvbnN0IGNsaWVudCBvZiB3ZWJTb2NrZXRDbGllbnRzLnZhbHVlcygpKSB7XHJcbiAgICBjbGllbnQudGVybWluYXRlKCk7XHJcbiAgfVxyXG4gIHdlYlNvY2tldENsaWVudHMuY2xlYXIoKTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGluaXQsXHJcbiAgY29ubmVjdCxcclxuICBnZXRDbGllbnRzXHJcbn07XHJcbiIsImltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbmNsYXNzIEh0dHBFcnJvciBleHRlbmRzIEV4cG9ydEVycm9yIHtcclxuICBjb25zdHJ1Y3RvcihtZXNzYWdlLCBzdGF0dXMpIHtcclxuICAgIHN1cGVyKG1lc3NhZ2UpO1xyXG4gICAgdGhpcy5zdGF0dXMgPSB0aGlzLnN0YXR1c0NvZGUgPSBzdGF0dXM7XHJcbiAgfVxyXG5cclxuICBzZXRTdGF0dXMoc3RhdHVzKSB7XHJcbiAgICB0aGlzLnN0YXR1cyA9IHN0YXR1cztcclxuICAgIHJldHVybiB0aGlzO1xyXG4gIH1cclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQgSHR0cEVycm9yO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IHVwZGF0ZVZlcnNpb24sIHZlcnNpb24gfSBmcm9tICcuLi8uLi9jYWNoZS5qcyc7XHJcbmltcG9ydCB7IGVudnMgfSBmcm9tICcuLi8uLi9lbnZzLmpzJztcclxuXHJcbmltcG9ydCBIdHRwRXJyb3IgZnJvbSAnLi4vLi4vZXJyb3JzL0h0dHBFcnJvci5qcyc7XHJcblxyXG4vKipcclxuICogQWRkcyB0aGUgUE9TVCAvY2hhbmdlX2hjX3ZlcnNpb24vOm5ld1ZlcnNpb24gcm91dGUgdGhhdCBjYW4gYmUgdXRpbGl6ZWQgdG8gbW9kaWZ5XHJcbiAqIHRoZSBIaWdoY2hhcnRzIHZlcnNpb24gb24gdGhlIHNlcnZlci5cclxuICpcclxuICogVE9ETzogQWRkIGF1dGggdG9rZW4gYW5kIGNvbm5lY3QgdG8gQVBJXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCAoYXBwKSA9PlxyXG4gICFhcHBcclxuICAgID8gZmFsc2VcclxuICAgIDogYXBwLnBvc3QoXHJcbiAgICAgICAgJy92ZXJzaW9uL2NoYW5nZS86bmV3VmVyc2lvbicsXHJcbiAgICAgICAgYXN5bmMgKHJlcXVlc3QsIHJlc3BvbnNlLCBuZXh0KSA9PiB7XHJcbiAgICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICBjb25zdCBhZG1pblRva2VuID0gZW52cy5ISUdIQ0hBUlRTX0FETUlOX1RPS0VOO1xyXG5cclxuICAgICAgICAgICAgLy8gQ2hlY2sgdGhlIGV4aXN0ZW5jZSBvZiB0aGUgdG9rZW5cclxuICAgICAgICAgICAgaWYgKCFhZG1pblRva2VuIHx8ICFhZG1pblRva2VuLmxlbmd0aCkge1xyXG4gICAgICAgICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgICAgICAgICAnVGhlIHNlcnZlciBpcyBub3QgY29uZmlndXJlZCB0byBwZXJmb3JtIHJ1bi10aW1lIHZlcnNpb24gY2hhbmdlczogSElHSENIQVJUU19BRE1JTl9UT0tFTiBpcyBub3Qgc2V0LicsXHJcbiAgICAgICAgICAgICAgICA0MDFcclxuICAgICAgICAgICAgICApO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAvLyBDaGVjayBpZiB0aGUgaGMtYXV0aCBoZWFkZXIgY29udGFpbiBhIGNvcnJlY3QgdG9rZW5cclxuICAgICAgICAgICAgY29uc3QgdG9rZW4gPSByZXF1ZXN0LmdldCgnaGMtYXV0aCcpO1xyXG4gICAgICAgICAgICBpZiAoIXRva2VuIHx8IHRva2VuICE9PSBhZG1pblRva2VuKSB7XHJcbiAgICAgICAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAgICAgICAgICdJbnZhbGlkIG9yIG1pc3NpbmcgdG9rZW46IFNldCB0aGUgdG9rZW4gaW4gdGhlIGhjLWF1dGggaGVhZGVyLicsXHJcbiAgICAgICAgICAgICAgICA0MDFcclxuICAgICAgICAgICAgICApO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAvLyBDb21wYXJlIHZlcnNpb25zXHJcbiAgICAgICAgICAgIGNvbnN0IG5ld1ZlcnNpb24gPSByZXF1ZXN0LnBhcmFtcy5uZXdWZXJzaW9uO1xyXG4gICAgICAgICAgICBpZiAobmV3VmVyc2lvbikge1xyXG4gICAgICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgaW1wb3J0L25vLW5hbWVkLWFzLWRlZmF1bHQtbWVtYmVyXHJcbiAgICAgICAgICAgICAgICBhd2FpdCB1cGRhdGVWZXJzaW9uKG5ld1ZlcnNpb24pO1xyXG4gICAgICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgICAgICAgICAgICBgVmVyc2lvbiBjaGFuZ2U6ICR7ZXJyb3IubWVzc2FnZX1gLFxyXG4gICAgICAgICAgICAgICAgICBlcnJvci5zdGF0dXNDb2RlXHJcbiAgICAgICAgICAgICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgIC8vIFN1Y2Nlc3NcclxuICAgICAgICAgICAgICByZXNwb25zZS5zdGF0dXMoMjAwKS5zZW5kKHtcclxuICAgICAgICAgICAgICAgIHN0YXR1c0NvZGU6IDIwMCxcclxuICAgICAgICAgICAgICAgIHZlcnNpb246IHZlcnNpb24oKSxcclxuICAgICAgICAgICAgICAgIG1lc3NhZ2U6IGBTdWNjZXNzZnVsbHkgdXBkYXRlZCBIaWdoY2hhcnRzIHRvIHZlcnNpb246ICR7bmV3VmVyc2lvbn0uYFxyXG4gICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgIC8vIE5vIHZlcnNpb24gc3BlY2lmaWVkXHJcbiAgICAgICAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcignTm8gbmV3IHZlcnNpb24gc3VwcGxpZWQuJywgNDAwKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgICAgbmV4dChlcnJvcik7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICApO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IHY0IGFzIHV1aWQgfSBmcm9tICd1dWlkJztcclxuXHJcbmltcG9ydCB7IGdldEFsbG93Q29kZUV4ZWN1dGlvbiwgc3RhcnRFeHBvcnQgfSBmcm9tICcuLi8uLi9jaGFydC5qcyc7XHJcbmltcG9ydCB7IGdldE9wdGlvbnMsIG1lcmdlQ29uZmlnT3B0aW9ucyB9IGZyb20gJy4uLy4uL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4uLy4uL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IHByZXBhcmVUZWxlbWV0cnkgfSBmcm9tICcuLi8uLi90ZWxlbWV0cnkuanMnO1xyXG5pbXBvcnQge1xyXG4gIGZpeFR5cGUsXHJcbiAgaXNDb3JyZWN0SlNPTixcclxuICBpc09iamVjdEVtcHR5LFxyXG4gIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmQsXHJcbiAgb3B0aW9uc1N0cmluZ2lmeSxcclxuICBtZWFzdXJlVGltZVxyXG59IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCBIdHRwRXJyb3IgZnJvbSAnLi4vLi4vZXJyb3JzL0h0dHBFcnJvci5qcyc7XHJcblxyXG4vLyBSZXZlcnNlZCBNSU1FIHR5cGVzXHJcbmNvbnN0IHJldmVyc2VkTWltZSA9IHtcclxuICBwbmc6ICdpbWFnZS9wbmcnLFxyXG4gIGpwZWc6ICdpbWFnZS9qcGVnJyxcclxuICBnaWY6ICdpbWFnZS9naWYnLFxyXG4gIHBkZjogJ2FwcGxpY2F0aW9uL3BkZicsXHJcbiAgc3ZnOiAnaW1hZ2Uvc3ZnK3htbCdcclxufTtcclxuXHJcbi8vIFRoZSByZXF1ZXN0cyBjb3VudGVyXHJcbmxldCByZXF1ZXN0c0NvdW50ZXIgPSAwO1xyXG5cclxuLy8gVGhlIGFycmF5IG9mIGNhbGxiYWNrcyB0byBjYWxsIGJlZm9yZSBhIHJlcXVlc3RcclxuY29uc3QgYmVmb3JlUmVxdWVzdCA9IFtdO1xyXG5cclxuLy8gVGhlIGFycmF5IG9mIGNhbGxiYWNrcyB0byBjYWxsIGFmdGVyIGEgcmVxdWVzdFxyXG5jb25zdCBhZnRlclJlcXVlc3QgPSBbXTtcclxuXHJcbi8qKlxyXG4gKiBJbnZva2VzIGFuIGFycmF5IG9mIGNhbGxiYWNrIGZ1bmN0aW9ucyB3aXRoIHNwZWNpZmllZCBwYXJhbWV0ZXJzLCBhbGxvd2luZ1xyXG4gKiBjdXN0b21pemF0aW9uIG9mIHJlcXVlc3QgaGFuZGxpbmcuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb25bXX0gY2FsbGJhY2tzIC0gQW4gYXJyYXkgb2YgY2FsbGJhY2sgZnVuY3Rpb25zXHJcbiAqIHRvIGJlIGV4ZWN1dGVkLlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxdWVzdCAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlc3BvbnNlIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZGF0YSAtIEFuIG9iamVjdCBjb250YWluaW5nIHBhcmFtZXRlcnMgbGlrZSBpZCwgdW5pcXVlSWQsXHJcbiAqIHR5cGUsIGFuZCBib2R5LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBSZXR1cm5zIGEgYm9vbGVhbiBpbmRpY2F0aW5nIHRoZSBvdmVyYWxsIHJlc3VsdFxyXG4gKiBvZiB0aGUgY2FsbGJhY2sgaW52b2NhdGlvbnMuXHJcbiAqL1xyXG5jb25zdCBkb0NhbGxiYWNrcyA9IChjYWxsYmFja3MsIHJlcXVlc3QsIHJlc3BvbnNlLCBkYXRhKSA9PiB7XHJcbiAgbGV0IHJlc3VsdCA9IHRydWU7XHJcbiAgY29uc3QgeyBpZCwgdW5pcXVlSWQsIHR5cGUsIGJvZHkgfSA9IGRhdGE7XHJcblxyXG4gIGNhbGxiYWNrcy5zb21lKChjYWxsYmFjaykgPT4ge1xyXG4gICAgaWYgKGNhbGxiYWNrKSB7XHJcbiAgICAgIGxldCBjYWxsUmVzcG9uc2UgPSBjYWxsYmFjayhyZXF1ZXN0LCByZXNwb25zZSwgaWQsIHVuaXF1ZUlkLCB0eXBlLCBib2R5KTtcclxuXHJcbiAgICAgIGlmIChjYWxsUmVzcG9uc2UgIT09IHVuZGVmaW5lZCAmJiBjYWxsUmVzcG9uc2UgIT09IHRydWUpIHtcclxuICAgICAgICByZXN1bHQgPSBjYWxsUmVzcG9uc2U7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICByZXR1cm4gcmVzdWx0O1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEhhbmRsZXMgdGhlIGV4cG9ydCByZXF1ZXN0cyBmcm9tIHRoZSBjbGllbnQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXF1ZXN0IC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzcG9uc2UgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IG5leHQgLSBUaGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gLSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBleHBvcnQgcHJvY2Vzc1xyXG4gKiBpcyBjb21wbGV0ZS5cclxuICovXHJcbmNvbnN0IGV4cG9ydEhhbmRsZXIgPSBhc3luYyAocmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpID0+IHtcclxuICB0cnkge1xyXG4gICAgLy8gU3RhcnQgY291bnRpbmcgdGltZVxyXG4gICAgY29uc3Qgc3RvcENvdW50ZXIgPSBtZWFzdXJlVGltZSgpO1xyXG5cclxuICAgIC8vIENyZWF0ZSBhIHVuaXF1ZSBJRCBmb3IgYSByZXF1ZXN0XHJcbiAgICBjb25zdCB1bmlxdWVJZCA9IHV1aWQoKS5yZXBsYWNlKC8tL2csICcnKTtcclxuXHJcbiAgICAvLyBHZXQgdGhlIGN1cnJlbnQgc2VydmVyJ3MgZ2VuZXJhbCBvcHRpb25zXHJcbiAgICBjb25zdCBkZWZhdWx0T3B0aW9ucyA9IGdldE9wdGlvbnMoKTtcclxuICAgIGNvbnN0IGJvZHkgPSByZXF1ZXN0LmJvZHk7XHJcbiAgICBjb25zdCBpZCA9ICsrcmVxdWVzdHNDb3VudGVyO1xyXG5cclxuICAgIGxldCB0eXBlID0gZml4VHlwZShib2R5LnR5cGUpO1xyXG5cclxuICAgIC8vIFRocm93ICdCYWQgUmVxdWVzdCcgaWYgdGhlcmUncyBubyBib2R5XHJcbiAgICBpZiAoIWJvZHkgfHwgaXNPYmplY3RFbXB0eShib2R5KSkge1xyXG4gICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgICdUaGUgcmVxdWVzdCBib2R5IGlzIHJlcXVpcmVkLiBQbGVhc2UgZW5zdXJlIHRoYXQgeW91ciBDb250ZW50LVR5cGUgaGVhZGVyIGlzIGNvcnJlY3QgKGFjY2VwdGVkIHR5cGVzIGFyZSBhcHBsaWNhdGlvbi9qc29uIGFuZCBtdWx0aXBhcnQvZm9ybS1kYXRhKS4nLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEFsbCBvZiB0aGUgYmVsb3cgY2FuIGJlIHVzZWRcclxuICAgIGxldCBpbnN0ciA9IGlzQ29ycmVjdEpTT04oYm9keS5pbmZpbGUgfHwgYm9keS5vcHRpb25zIHx8IGJvZHkuZGF0YSk7XHJcblxyXG4gICAgLy8gVGhyb3cgJ0JhZCBSZXF1ZXN0JyBpZiB0aGVyZSdzIG5vIEpTT04gb3IgU1ZHIHRvIGV4cG9ydFxyXG4gICAgaWYgKCFpbnN0ciAmJiAhYm9keS5zdmcpIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDIsXHJcbiAgICAgICAgYFRoZSByZXF1ZXN0IHdpdGggSUQgJHt1bmlxdWVJZH0gZnJvbSAke1xyXG4gICAgICAgICAgcmVxdWVzdC5oZWFkZXJzWyd4LWZvcndhcmRlZC1mb3InXSB8fCByZXF1ZXN0LmNvbm5lY3Rpb24ucmVtb3RlQWRkcmVzc1xyXG4gICAgICAgIH0gd2FzIGluY29ycmVjdC4gUGF5bG9hZCByZWNlaXZlZDogJHtKU09OLnN0cmluZ2lmeShib2R5KX0uYFxyXG4gICAgICApO1xyXG5cclxuICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICBcIk5vIGNvcnJlY3QgY2hhcnQgZGF0YSBmb3VuZC4gRW5zdXJlIHRoYXQgeW91IGFyZSB1c2luZyBlaXRoZXIgYXBwbGljYXRpb24vanNvbiBvciBtdWx0aXBhcnQvZm9ybS1kYXRhIGhlYWRlcnMuIElmIHNlbmRpbmcgSlNPTiwgbWFrZSBzdXJlIHRoZSBjaGFydCBkYXRhIGlzIGluIHRoZSAnaW5maWxlJywgJ29wdGlvbnMnLCBvciAnZGF0YScgYXR0cmlidXRlLiBJZiBzZW5kaW5nIFNWRywgZW5zdXJlIGl0IGlzIGluIHRoZSAnc3ZnJyBhdHRyaWJ1dGUuXCIsXHJcbiAgICAgICAgNDAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgbGV0IGNhbGxSZXNwb25zZSA9IGZhbHNlO1xyXG5cclxuICAgIC8vIENhbGwgdGhlIGJlZm9yZSByZXF1ZXN0IGZ1bmN0aW9uc1xyXG4gICAgY2FsbFJlc3BvbnNlID0gZG9DYWxsYmFja3MoYmVmb3JlUmVxdWVzdCwgcmVxdWVzdCwgcmVzcG9uc2UsIHtcclxuICAgICAgaWQsXHJcbiAgICAgIHVuaXF1ZUlkLFxyXG4gICAgICB0eXBlLFxyXG4gICAgICBib2R5XHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBCbG9jayB0aGUgcmVxdWVzdCBpZiBvbmUgb2YgYSBjYWxsYmFja3MgZmFpbGVkXHJcbiAgICBpZiAoY2FsbFJlc3BvbnNlICE9PSB0cnVlKSB7XHJcbiAgICAgIHJldHVybiByZXNwb25zZS5zZW5kKGNhbGxSZXNwb25zZSk7XHJcbiAgICB9XHJcblxyXG4gICAgbGV0IGNvbm5lY3Rpb25BYm9ydGVkID0gZmFsc2U7XHJcblxyXG4gICAgLy8gSW4gY2FzZSB0aGUgY29ubmVjdGlvbiBpcyBjbG9zZWQsIGZvcmNlIHRvIGFib3J0IGZ1cnRoZXIgYWN0aW9uc1xyXG4gICAgcmVxdWVzdC5zb2NrZXQub24oJ2Nsb3NlJywgKCkgPT4ge1xyXG4gICAgICBjb25uZWN0aW9uQWJvcnRlZCA9IHRydWU7XHJcbiAgICB9KTtcclxuXHJcbiAgICBsb2coNCwgYFtleHBvcnRdIEdvdCBhbiBpbmNvbWluZyBIVFRQIHJlcXVlc3Qgd2l0aCBJRCAke3VuaXF1ZUlkfS5gKTtcclxuXHJcbiAgICBib2R5LmNvbnN0ciA9ICh0eXBlb2YgYm9keS5jb25zdHIgPT09ICdzdHJpbmcnICYmIGJvZHkuY29uc3RyKSB8fCAnY2hhcnQnO1xyXG5cclxuICAgIC8vIEdhdGhlciBhbmQgb3JnYW5pemUgb3B0aW9ucyBmcm9tIHRoZSBwYXlsb2FkXHJcbiAgICBjb25zdCByZXF1ZXN0T3B0aW9ucyA9IHtcclxuICAgICAgZXhwb3J0OiB7XHJcbiAgICAgICAgaW5zdHIsXHJcbiAgICAgICAgdHlwZSxcclxuICAgICAgICBjb25zdHI6IGJvZHkuY29uc3RyWzBdLnRvTG93ZXJDYXNlKCkgKyBib2R5LmNvbnN0ci5zdWJzdHIoMSksXHJcbiAgICAgICAgaGVpZ2h0OiBib2R5LmhlaWdodCxcclxuICAgICAgICB3aWR0aDogYm9keS53aWR0aCxcclxuICAgICAgICBzY2FsZTogYm9keS5zY2FsZSB8fCBkZWZhdWx0T3B0aW9ucy5leHBvcnQuc2NhbGUsXHJcbiAgICAgICAgZ2xvYmFsT3B0aW9uczogaXNDb3JyZWN0SlNPTihib2R5Lmdsb2JhbE9wdGlvbnMsIHRydWUpLFxyXG4gICAgICAgIHRoZW1lT3B0aW9uczogaXNDb3JyZWN0SlNPTihib2R5LnRoZW1lT3B0aW9ucywgdHJ1ZSlcclxuICAgICAgfSxcclxuICAgICAgY3VzdG9tTG9naWM6IHtcclxuICAgICAgICBhbGxvd0NvZGVFeGVjdXRpb246IGdldEFsbG93Q29kZUV4ZWN1dGlvbigpLFxyXG4gICAgICAgIGFsbG93RmlsZVJlc291cmNlczogZmFsc2UsXHJcbiAgICAgICAgcmVzb3VyY2VzOiBpc0NvcnJlY3RKU09OKGJvZHkucmVzb3VyY2VzLCB0cnVlKSxcclxuICAgICAgICBjYWxsYmFjazogYm9keS5jYWxsYmFjayxcclxuICAgICAgICBjdXN0b21Db2RlOiBib2R5LmN1c3RvbUNvZGVcclxuICAgICAgfVxyXG4gICAgfTtcclxuXHJcbiAgICBpZiAoaW5zdHIpIHtcclxuICAgICAgLy8gU3RyaW5naWZ5IEpTT04gd2l0aCBvcHRpb25zXHJcbiAgICAgIHJlcXVlc3RPcHRpb25zLmV4cG9ydC5pbnN0ciA9IG9wdGlvbnNTdHJpbmdpZnkoXHJcbiAgICAgICAgaW5zdHIsXHJcbiAgICAgICAgcmVxdWVzdE9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTWVyZ2UgdGhlIHJlcXVlc3Qgb3B0aW9ucyBpbnRvIGRlZmF1bHQgb25lc1xyXG4gICAgY29uc3Qgb3B0aW9ucyA9IG1lcmdlQ29uZmlnT3B0aW9ucyhkZWZhdWx0T3B0aW9ucywgcmVxdWVzdE9wdGlvbnMpO1xyXG5cclxuICAgIC8vIFNhdmUgdGhlIEpTT04gaWYgZXhpc3RzXHJcbiAgICBvcHRpb25zLmV4cG9ydC5vcHRpb25zID0gaW5zdHI7XHJcblxyXG4gICAgLy8gTGFzdGx5LCBhZGQgdGhlIHNlcnZlciBzcGVjaWZpYyBhcmd1bWVudHMgaW50byBvcHRpb25zIGFzIHBheWxvYWRcclxuICAgIG9wdGlvbnMucGF5bG9hZCA9IHtcclxuICAgICAgc3ZnOiBib2R5LnN2ZyB8fCBmYWxzZSxcclxuICAgICAgYjY0OiBib2R5LmI2NCB8fCBmYWxzZSxcclxuICAgICAgbm9Eb3dubG9hZDogYm9keS5ub0Rvd25sb2FkIHx8IGZhbHNlLFxyXG4gICAgICByZXF1ZXN0SWQ6IHVuaXF1ZUlkXHJcbiAgICB9O1xyXG5cclxuICAgIC8vIFRlc3QgeGxpbms6aHJlZiBlbGVtZW50cyBmcm9tIHBheWxvYWQncyBTVkdcclxuICAgIGlmIChib2R5LnN2ZyAmJiBpc1ByaXZhdGVSYW5nZVVybEZvdW5kKG9wdGlvbnMucGF5bG9hZC5zdmcpKSB7XHJcbiAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgJ1NWRyBwb3RlbnRpYWxseSBjb250YWluIGF0IGxlYXN0IG9uZSBmb3JiaWRkZW4gVVJMIGluIHhsaW5rOmhyZWYgZWxlbWVudC4gUGxlYXNlIHJldmlldyB0aGUgU1ZHIGNvbnRlbnQgYW5kIGVuc3VyZSB0aGF0IGFsbCByZWZlcmVuY2VkIFVSTHMgY29tcGx5IHdpdGggc2VjdXJpdHkgcG9saWNpZXMuJyxcclxuICAgICAgICA0MDBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBTdGFydCB0aGUgZXhwb3J0IHByb2Nlc3NcclxuICAgIGF3YWl0IHN0YXJ0RXhwb3J0KG9wdGlvbnMsIChlcnJvciwgaW5mbykgPT4ge1xyXG4gICAgICAvLyBSZW1vdmUgdGhlIGNsb3NlIGV2ZW50IGZyb20gdGhlIHNvY2tldFxyXG4gICAgICByZXF1ZXN0LnNvY2tldC5yZW1vdmVBbGxMaXN0ZW5lcnMoJ2Nsb3NlJyk7XHJcblxyXG4gICAgICAvLyBBZnRlciB0aGUgd2hvbGUgZXhwb3J0aW5nIHByb2Nlc3NcclxuICAgICAgaWYgKGRlZmF1bHRPcHRpb25zLnNlcnZlci5iZW5jaG1hcmtpbmcpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICA1LFxyXG4gICAgICAgICAgYFtiZW5jaG1hcmtdIFJlcXVlc3Q6ICR7dW5pcXVlSWR9IC0gQWZ0ZXIgdGhlIHdob2xlIGV4cG9ydGluZyBwcm9jZXNzOiAke3N0b3BDb3VudGVyKCl9bXMuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIElmIHRoZSBjb25uZWN0aW9uIHdhcyBjbG9zZWQsIGRvIG5vdGhpbmdcclxuICAgICAgaWYgKGNvbm5lY3Rpb25BYm9ydGVkKSB7XHJcbiAgICAgICAgcmV0dXJuIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW2V4cG9ydF0gVGhlIGNsaWVudCBjbG9zZWQgdGhlIGNvbm5lY3Rpb24gYmVmb3JlIHRoZSBjaGFydCBmaW5pc2hlZCBwcm9jZXNzaW5nLmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBJZiBlcnJvciwgbG9nIGl0IGFuZCBzZW5kIGl0IHRvIHRoZSBlcnJvciBtaWRkbGV3YXJlXHJcbiAgICAgIGlmIChlcnJvcikge1xyXG4gICAgICAgIHRocm93IGVycm9yO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBJZiBkYXRhIGlzIG1pc3NpbmcsIGxvZyB0aGUgbWVzc2FnZSBhbmQgc2VuZCBpdCB0byB0aGUgZXJyb3IgbWlkZGxld2FyZVxyXG4gICAgICBpZiAoIWluZm8gfHwgIWluZm8ucmVzdWx0KSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAgIGBVbmV4cGVjdGVkIHJldHVybiBmcm9tIGNoYXJ0IGdlbmVyYXRpb24uIFBsZWFzZSBjaGVjayB5b3VyIHJlcXVlc3QgZGF0YS4gRm9yIHRoZSByZXF1ZXN0IHdpdGggSUQgJHt1bmlxdWVJZH0sIHRoZSByZXN1bHQgaXMgJHtpbmZvLnJlc3VsdH0uYCxcclxuICAgICAgICAgIDQwMFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIEdldCB0aGUgdHlwZSBmcm9tIG9wdGlvbnNcclxuICAgICAgdHlwZSA9IGluZm8ub3B0aW9ucy5leHBvcnQudHlwZTtcclxuXHJcbiAgICAgIC8vIFRoZSBhZnRlciByZXF1ZXN0IGNhbGxiYWNrc1xyXG4gICAgICBkb0NhbGxiYWNrcyhhZnRlclJlcXVlc3QsIHJlcXVlc3QsIHJlc3BvbnNlLCB7IGlkLCBib2R5OiBpbmZvLnJlc3VsdCB9KTtcclxuXHJcbiAgICAgIC8vIFByZXBhcmUgYW5kIHNlbmQgdGhlIG9wdGlvbnMgdGhyb3VnaCB0aGUgV2ViU29ja2V0XHJcbiAgICAgIHByZXBhcmVUZWxlbWV0cnkob3B0aW9ucy5leHBvcnQub3B0aW9ucywgb3B0aW9ucy5wYXlsb2FkLnJlcXVlc3RJZCk7XHJcblxyXG4gICAgICBpZiAoaW5mby5yZXN1bHQpIHtcclxuICAgICAgICAvLyBJZiBvbmx5IGJhc2U2NCBpcyByZXF1aXJlZCwgcmV0dXJuIGl0XHJcbiAgICAgICAgaWYgKGJvZHkuYjY0KSB7XHJcbiAgICAgICAgICAvLyBTVkcgRXhjZXB0aW9uIGZvciB0aGUgSGlnaGNoYXJ0cyAxMS4zLjAgdmVyc2lvblxyXG4gICAgICAgICAgaWYgKHR5cGUgPT09ICdwZGYnIHx8IHR5cGUgPT0gJ3N2ZycpIHtcclxuICAgICAgICAgICAgcmV0dXJuIHJlc3BvbnNlLnNlbmQoXHJcbiAgICAgICAgICAgICAgQnVmZmVyLmZyb20oaW5mby5yZXN1bHQsICd1dGY4JykudG9TdHJpbmcoJ2Jhc2U2NCcpXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgcmV0dXJuIHJlc3BvbnNlLnNlbmQoaW5mby5yZXN1bHQpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gU2V0IGNvcnJlY3QgY29udGVudCB0eXBlXHJcbiAgICAgICAgcmVzcG9uc2UuaGVhZGVyKCdDb250ZW50LVR5cGUnLCByZXZlcnNlZE1pbWVbdHlwZV0gfHwgJ2ltYWdlL3BuZycpO1xyXG5cclxuICAgICAgICAvLyBEZWNpZGUgd2hldGhlciB0byBkb3dubG9hZCBvciBub3QgY2hhcnQgZmlsZVxyXG4gICAgICAgIGlmICghYm9keS5ub0Rvd25sb2FkKSB7XHJcbiAgICAgICAgICByZXNwb25zZS5hdHRhY2htZW50KFxyXG4gICAgICAgICAgICBgJHtyZXF1ZXN0LnBhcmFtcy5maWxlbmFtZSB8fCByZXF1ZXN0LmJvZHkuZmlsZW5hbWUgfHwgJ2NoYXJ0J30uJHtcclxuICAgICAgICAgICAgICB0eXBlIHx8ICdwbmcnXHJcbiAgICAgICAgICAgIH1gXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gSWYgU1ZHLCByZXR1cm4gcGxhaW4gY29udGVudFxyXG4gICAgICAgIHJldHVybiB0eXBlID09PSAnc3ZnJ1xyXG4gICAgICAgICAgPyByZXNwb25zZS5zZW5kKGluZm8ucmVzdWx0KVxyXG4gICAgICAgICAgOiByZXNwb25zZS5zZW5kKEJ1ZmZlci5mcm9tKGluZm8ucmVzdWx0LCAnYmFzZTY0JykpO1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgbmV4dChlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQgKGFwcCkgPT4ge1xyXG4gIC8qKlxyXG4gICAqIEFkZHMgdGhlIFBPU1QgLyBhIHJvdXRlIGZvciBoYW5kbGluZyBQT1NUIHJlcXVlc3RzIGF0IHRoZSByb290IGVuZHBvaW50LlxyXG4gICAqL1xyXG4gIGFwcC5wb3N0KCcvJywgZXhwb3J0SGFuZGxlcik7XHJcblxyXG4gIC8qKlxyXG4gICAqIEFkZHMgdGhlIFBPU1QgLzpmaWxlbmFtZSBhIHJvdXRlIGZvciBoYW5kbGluZyBQT1NUIHJlcXVlc3RzIHdpdGhcclxuICAgKiBhIHNwZWNpZmllZCBmaWxlbmFtZSBwYXJhbWV0ZXIuXHJcbiAgICovXHJcbiAgYXBwLnBvc3QoJy86ZmlsZW5hbWUnLCBleHBvcnRIYW5kbGVyKTtcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IGpvaW4gYXMgcGF0aGVyIH0gZnJvbSAncGF0aCc7XHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4uLy4uL2xvZ2dlci5qcyc7XHJcblxyXG5pbXBvcnQgeyB2ZXJzaW9uIH0gZnJvbSAnLi4vLi4vY2FjaGUuanMnO1xyXG5pbXBvcnQgeyBhZGRUaW1lciB9IGZyb20gJy4uLy4uL3RpbWVycy5qcyc7XHJcbmltcG9ydCB7IGdldFN0YXRzLCBnZXRQb29sSW5mb0pTT04gfSBmcm9tICcuLi8uLi9wb29sLmpzJztcclxuaW1wb3J0IHsgX19kaXJuYW1lIH0gZnJvbSAnLi4vLi4vdXRpbHMuanMnO1xyXG5cclxuY29uc3QgcGtnRmlsZSA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKHBhdGhlcihfX2Rpcm5hbWUsICdwYWNrYWdlLmpzb24nKSkpO1xyXG5cclxuY29uc3Qgc2VydmVyU3RhcnRUaW1lID0gbmV3IERhdGUoKTtcclxuXHJcbmNvbnN0IHN1Y2Nlc3NSYXRlcyA9IFtdO1xyXG5jb25zdCByZWNvcmRJbnRlcnZhbCA9IDYwICogMTAwMDsgLy8gcmVjb3JkIGV2ZXJ5IG1pbnV0ZVxyXG5jb25zdCB3aW5kb3dTaXplID0gMzA7IC8vIDMwIG1pbnV0ZXNcclxuXHJcbi8qKlxyXG4gKiBDYWxjdWxhdGVzIG1vdmluZyBhdmVyYWdlIGluZGljYXRvciBiYXNlZCBvbiB0aGUgZGF0YSBmcm9tIHRoZSBzdWNjZXNzUmF0ZXNcclxuICogYXJyYXkuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtudW1iZXJ9IC0gQSBtb3ZpbmcgYXZlcmFnZSBmb3Igc3VjY2VzcyByYXRpbyBvZiB0aGUgc2VydmVyIGV4cG9ydHMuXHJcbiAqL1xyXG5mdW5jdGlvbiBjYWxjdWxhdGVNb3ZpbmdBdmVyYWdlKCkge1xyXG4gIGNvbnN0IHN1bSA9IHN1Y2Nlc3NSYXRlcy5yZWR1Y2UoKGEsIGIpID0+IGEgKyBiLCAwKTtcclxuICByZXR1cm4gc3VtIC8gc3VjY2Vzc1JhdGVzLmxlbmd0aDtcclxufVxyXG5cclxuLyoqXHJcbiAqIFN0YXJ0cyB0aGUgaW50ZXJ2YWwgcmVzcG9uc2libGUgZm9yIGNhbGN1bGF0aW5nIGN1cnJlbnQgc3VjY2VzcyByYXRlIHJhdGlvXHJcbiAqIGFuZCBnYXRoZXJzXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtOb2RlSlMuVGltZW91dH0gaWQgLSBJZCBvZiBhbiBpbnRlcnZhbC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBzdGFydFN1Y2Nlc3NSYXRlID0gKCkgPT5cclxuICBzZXRJbnRlcnZhbCgoKSA9PiB7XHJcbiAgICBjb25zdCBzdGF0cyA9IGdldFN0YXRzKCk7XHJcbiAgICBjb25zdCBzdWNjZXNzUmF0aW8gPVxyXG4gICAgICBzdGF0cy5leHBvcnRBdHRlbXB0cyA9PT0gMFxyXG4gICAgICAgID8gMVxyXG4gICAgICAgIDogKHN0YXRzLnBlcmZvcm1lZEV4cG9ydHMgLyBzdGF0cy5leHBvcnRBdHRlbXB0cykgKiAxMDA7XHJcblxyXG4gICAgc3VjY2Vzc1JhdGVzLnB1c2goc3VjY2Vzc1JhdGlvKTtcclxuICAgIGlmIChzdWNjZXNzUmF0ZXMubGVuZ3RoID4gd2luZG93U2l6ZSkge1xyXG4gICAgICBzdWNjZXNzUmF0ZXMuc2hpZnQoKTtcclxuICAgIH1cclxuICB9LCByZWNvcmRJbnRlcnZhbCk7XHJcblxyXG4vKipcclxuICogQWRkcyB0aGUgL2hlYWx0aCBhbmQgL3N1Y2Nlc3MtbW92aW5nLWF2ZXJhZ2Ugcm91dGVzXHJcbiAqIHdoaWNoIG91dHB1dCBiYXNpYyBzdGF0cyBmb3IgdGhlIHNlcnZlci5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIGFkZEhlYWx0aFJvdXRlcyhhcHApIHtcclxuICBpZiAoIWFwcCkge1xyXG4gICAgcmV0dXJuIGZhbHNlO1xyXG4gIH1cclxuXHJcbiAgLy8gU3RhcnQgcHJvY2Vzc2luZyBzdWNjZXNzIHJhdGUgcmF0aW8gaW50ZXJ2YWwgYW5kIHNhdmUgaXRzIGlkIHRvIHRoZSBhcnJheVxyXG4gIC8vIGZvciB0aGUgZ3JhY2VmdWwgY2xlYXJpbmcgb24gc2h1dGRvd24gd2l0aCBpbmplY3RlZCBhZGRJbnRlcnZhbCBmdW50aW9uXHJcbiAgYWRkVGltZXIoc3RhcnRTdWNjZXNzUmF0ZSgpKTtcclxuXHJcbiAgYXBwLmdldCgnL2hlYWx0aCcsIChfLCByZXMpID0+IHtcclxuICAgIGNvbnN0IHN0YXRzID0gZ2V0U3RhdHMoKTtcclxuICAgIGNvbnN0IHBlcmlvZCA9IHN1Y2Nlc3NSYXRlcy5sZW5ndGg7XHJcbiAgICBjb25zdCBtb3ZpbmdBdmVyYWdlID0gY2FsY3VsYXRlTW92aW5nQXZlcmFnZSgpO1xyXG5cclxuICAgIGxvZyg0LCAnW2hlYWx0aC5qc10gR0VUIC9oZWFsdGggWzIwMF0gLSByZXR1cm5pbmcgc2VydmVyIGhlYWx0aC4nKTtcclxuXHJcbiAgICByZXMuc2VuZCh7XHJcbiAgICAgIHN0YXR1czogJ09LJyxcclxuICAgICAgYm9vdFRpbWU6IHNlcnZlclN0YXJ0VGltZSxcclxuICAgICAgdXB0aW1lOlxyXG4gICAgICAgIE1hdGguZmxvb3IoXHJcbiAgICAgICAgICAobmV3IERhdGUoKS5nZXRUaW1lKCkgLSBzZXJ2ZXJTdGFydFRpbWUuZ2V0VGltZSgpKSAvIDEwMDAgLyA2MFxyXG4gICAgICAgICkgKyAnIG1pbnV0ZXMnLFxyXG4gICAgICB2ZXJzaW9uOiBwa2dGaWxlLnZlcnNpb24sXHJcbiAgICAgIGhpZ2hjaGFydHNWZXJzaW9uOiB2ZXJzaW9uKCksXHJcbiAgICAgIGF2ZXJhZ2VQcm9jZXNzaW5nVGltZTogc3RhdHMuc3BlbnRBdmVyYWdlLFxyXG4gICAgICBwZXJmb3JtZWRFeHBvcnRzOiBzdGF0cy5wZXJmb3JtZWRFeHBvcnRzLFxyXG4gICAgICBmYWlsZWRFeHBvcnRzOiBzdGF0cy5kcm9wcGVkRXhwb3J0cyxcclxuICAgICAgZXhwb3J0QXR0ZW1wdHM6IHN0YXRzLmV4cG9ydEF0dGVtcHRzLFxyXG4gICAgICBzdWNlc3NSYXRpbzogKHN0YXRzLnBlcmZvcm1lZEV4cG9ydHMgLyBzdGF0cy5leHBvcnRBdHRlbXB0cykgKiAxMDAsXHJcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBpbXBvcnQvbm8tbmFtZWQtYXMtZGVmYXVsdC1tZW1iZXJcclxuICAgICAgcG9vbDogZ2V0UG9vbEluZm9KU09OKCksXHJcblxyXG4gICAgICAvLyBNb3ZpbmcgYXZlcmFnZVxyXG4gICAgICBwZXJpb2QsXHJcbiAgICAgIG1vdmluZ0F2ZXJhZ2UsXHJcbiAgICAgIG1lc3NhZ2U6IGBMYXN0ICR7cGVyaW9kfSBtaW51dGVzIGhhZCBhIHN1Y2Nlc3MgcmF0ZSBvZiAke21vdmluZ0F2ZXJhZ2UudG9GaXhlZCgyKX0lLmAsXHJcblxyXG4gICAgICAvLyBTVkcvSlNPTiBhdHRlbXB0c1xyXG4gICAgICBzdmdFeHBvcnRBdHRlbXB0czogc3RhdHMuZXhwb3J0RnJvbVN2Z0F0dGVtcHRzLFxyXG4gICAgICBqc29uRXhwb3J0QXR0ZW1wdHM6IHN0YXRzLnBlcmZvcm1lZEV4cG9ydHMgLSBzdGF0cy5leHBvcnRGcm9tU3ZnQXR0ZW1wdHNcclxuICAgIH0pO1xyXG4gIH0pO1xyXG59XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgcHJvbWlzZXMgYXMgZnNQcm9taXNlcyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgcG9zaXggfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCBjb3JzIGZyb20gJ2NvcnMnO1xyXG5pbXBvcnQgZXhwcmVzcyBmcm9tICdleHByZXNzJztcclxuaW1wb3J0IGh0dHAgZnJvbSAnaHR0cCc7XHJcbmltcG9ydCBodHRwcyBmcm9tICdodHRwcyc7XHJcbmltcG9ydCBtdWx0ZXIgZnJvbSAnbXVsdGVyJztcclxuXHJcbmltcG9ydCBlcnJvckhhbmRsZXIgZnJvbSAnLi9lcnJvci5qcyc7XHJcbmltcG9ydCByYXRlTGltaXQgZnJvbSAnLi9yYXRlX2xpbWl0LmpzJztcclxuaW1wb3J0IHsgaW5pdCBhcyB3ZWJTb2NrZXRJbml0IH0gZnJvbSAnLi93ZWJfc29ja2V0LmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBfX2Rpcm5hbWUgfSBmcm9tICcuLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgdlN3aXRjaFJvdXRlIGZyb20gJy4vcm91dGVzL2NoYW5nZV9oY192ZXJzaW9uLmpzJztcclxuaW1wb3J0IGV4cG9ydFJvdXRlcyBmcm9tICcuL3JvdXRlcy9leHBvcnQuanMnO1xyXG5pbXBvcnQgaGVhbHRoUm91dGUgZnJvbSAnLi9yb3V0ZXMvaGVhbHRoLmpzJztcclxuaW1wb3J0IHVpUm91dGUgZnJvbSAnLi9yb3V0ZXMvdWkuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4uL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vLyBBcnJheSBvZiBhbiBhY3RpdmUgc2VydmVyc1xyXG5jb25zdCBhY3RpdmVTZXJ2ZXJzID0gbmV3IE1hcCgpO1xyXG5cclxuLy8gQ3JlYXRlIGV4cHJlc3MgYXBwXHJcbmNvbnN0IGFwcCA9IGV4cHJlc3MoKTtcclxuXHJcbi8vIERpc2FibGUgdGhlIFgtUG93ZXJlZC1CeSBoZWFkZXJcclxuYXBwLmRpc2FibGUoJ3gtcG93ZXJlZC1ieScpO1xyXG5cclxuLy8gRW5hYmxlIENPUlMgc3VwcG9ydFxyXG5hcHAudXNlKGNvcnMoKSk7XHJcblxyXG4vLyBFbmFibGUgcGFyc2luZyBvZiBmb3JtIGRhdGEgKGZpbGVzKSB3aXRoIE11bHRlciBwYWNrYWdlXHJcbmNvbnN0IHN0b3JhZ2UgPSBtdWx0ZXIubWVtb3J5U3RvcmFnZSgpO1xyXG5jb25zdCB1cGxvYWQgPSBtdWx0ZXIoe1xyXG4gIHN0b3JhZ2UsXHJcbiAgbGltaXRzOiB7XHJcbiAgICBmaWVsZFNpemU6IDUwICogMTAyNCAqIDEwMjRcclxuICB9XHJcbn0pO1xyXG5cclxuLy8gRW5hYmxlIGJvZHkgcGFyc2VyXHJcbmFwcC51c2UoZXhwcmVzcy5qc29uKHsgbGltaXQ6IDUwICogMTAyNCAqIDEwMjQgfSkpO1xyXG5hcHAudXNlKGV4cHJlc3MudXJsZW5jb2RlZCh7IGV4dGVuZGVkOiB0cnVlLCBsaW1pdDogNTAgKiAxMDI0ICogMTAyNCB9KSk7XHJcblxyXG4vLyBVc2Ugb25seSBub24tZmlsZSBtdWx0aXBhcnQgZm9ybSBmaWVsZHNcclxuYXBwLnVzZSh1cGxvYWQubm9uZSgpKTtcclxuXHJcbi8qKlxyXG4gKiBBdHRhY2ggZXJyb3IgaGFuZGxlcnMgdG8gdGhlIHNlcnZlci5cclxuICpcclxuICogQHBhcmFtIHtodHRwLlNlcnZlcn0gc2VydmVyIC0gVGhlIEhUVFAvSFRUUFMgc2VydmVyIGluc3RhbmNlLlxyXG4gKi9cclxuY29uc3QgYXR0YWNoU2VydmVyRXJyb3JIYW5kbGVycyA9IChzZXJ2ZXIpID0+IHtcclxuICBzZXJ2ZXIub24oJ2NsaWVudEVycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICBsb2dXaXRoU3RhY2soMSwgZXJyb3IsIGBbc2VydmVyXSBDbGllbnQgZXJyb3I6ICR7ZXJyb3IubWVzc2FnZX1gKTtcclxuICB9KTtcclxuXHJcbiAgc2VydmVyLm9uKCdlcnJvcicsIChlcnJvcikgPT4ge1xyXG4gICAgbG9nV2l0aFN0YWNrKDEsIGVycm9yLCBgW3NlcnZlcl0gU2VydmVyIGVycm9yOiAke2Vycm9yLm1lc3NhZ2V9YCk7XHJcbiAgfSk7XHJcblxyXG4gIHNlcnZlci5vbignY29ubmVjdGlvbicsIChzb2NrZXQpID0+IHtcclxuICAgIHNvY2tldC5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcclxuICAgICAgbG9nV2l0aFN0YWNrKDEsIGVycm9yLCBgW3NlcnZlcl0gU29ja2V0IGVycm9yOiAke2Vycm9yLm1lc3NhZ2V9YCk7XHJcbiAgICB9KTtcclxuICB9KTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgYW4gSFRUUCBzZXJ2ZXIgYmFzZWQgb24gdGhlIHByb3ZpZGVkIGNvbmZpZ3VyYXRpb24uIFRoZSBgc2VydmVyQ29uZmlnYFxyXG4gKiBvYmplY3QgY29udGFpbnMgYWxsIHNlcnZlciByZWxhdGVkIHByb3BlcnRpZXMgKHNlZSB0aGUgYHNlcnZlcmAgc2VjdGlvblxyXG4gKiBpbiB0aGUgYGxpYi9zY2hlbWFzL2NvbmZpZy5qc2AgZmlsZSBmb3IgYSByZWZlcmVuY2UpLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gc2VydmVyQ29uZmlnIC0gVGhlIHNlcnZlciBjb25maWd1cmF0aW9uIG9iamVjdC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IC0gVGhyb3dzIGFuIGVycm9yIGlmIHRoZSBzZXJ2ZXIgY2Fubm90IGJlIGNvbmZpZ3VyZWRcclxuICogYW5kIHN0YXJ0ZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc3RhcnRTZXJ2ZXIgPSBhc3luYyAoc2VydmVyQ29uZmlnKSA9PiB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIFN0b3AgaWYgbm90IGVuYWJsZWRcclxuICAgIGlmICghc2VydmVyQ29uZmlnLmVuYWJsZSkge1xyXG4gICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTGlzdGVuIEhUVFAgc2VydmVyXHJcbiAgICBpZiAoIXNlcnZlckNvbmZpZy5zc2wuZm9yY2UpIHtcclxuICAgICAgLy8gTWFpbiBzZXJ2ZXIgaW5zdGFuY2UgKEhUVFApXHJcbiAgICAgIGNvbnN0IGh0dHBTZXJ2ZXIgPSBodHRwLmNyZWF0ZVNlcnZlcihhcHApO1xyXG5cclxuICAgICAgLy8gQXR0YWNoIGVycm9yIGhhbmRsZXJzIGFuZCBsaXN0ZW4gdG8gdGhlIHNlcnZlclxyXG4gICAgICBhdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzKGh0dHBTZXJ2ZXIpO1xyXG5cclxuICAgICAgLy8gTGlzdGVuXHJcbiAgICAgIGh0dHBTZXJ2ZXIubGlzdGVuKHNlcnZlckNvbmZpZy5wb3J0LCBzZXJ2ZXJDb25maWcuaG9zdCwgKCkgPT4ge1xyXG4gICAgICAgIC8vIFNhdmUgdGhlIHJlZmVyZW5jZSB0byBIVFRQIHNlcnZlclxyXG4gICAgICAgIGFjdGl2ZVNlcnZlcnMuc2V0KHNlcnZlckNvbmZpZy5wb3J0LCBodHRwU2VydmVyKTtcclxuXHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbc2VydmVyXSBTdGFydGVkIEhUVFAgc2VydmVyIG9uICR7c2VydmVyQ29uZmlnLmhvc3R9OiR7c2VydmVyQ29uZmlnLnBvcnR9LmBcclxuICAgICAgICApO1xyXG5cclxuICAgICAgICBpZiAoYWN0aXZlU2VydmVycy5zaXplID09PSAxKSB7XHJcbiAgICAgICAgICAvLyBTdGFydCBhIFdlYlNvY2tldCBjb25uZWN0aW9uXHJcbiAgICAgICAgICB3ZWJTb2NrZXRJbml0KHsgLi4uaHR0cFNlcnZlci5hZGRyZXNzKCksIHByb3RvY29sOiAnaHR0cCcgfSk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBMaXN0ZW4gSFRUUFMgc2VydmVyXHJcbiAgICBpZiAoc2VydmVyQ29uZmlnLnNzbC5lbmFibGUpIHtcclxuICAgICAgLy8gU2V0IHVwIGFuIFNTTCBzZXJ2ZXIgYWxzb1xyXG4gICAgICBsZXQga2V5LCBjZXJ0O1xyXG5cclxuICAgICAgdHJ5IHtcclxuICAgICAgICAvLyBHZXQgdGhlIFNTTCBrZXlcclxuICAgICAgICBrZXkgPSBhd2FpdCBmc1Byb21pc2VzLnJlYWRGaWxlKFxyXG4gICAgICAgICAgcG9zaXguam9pbihzZXJ2ZXJDb25maWcuc3NsLmNlcnRQYXRoLCAnc2VydmVyLmtleScpLFxyXG4gICAgICAgICAgJ3V0ZjgnXHJcbiAgICAgICAgKTtcclxuXHJcbiAgICAgICAgLy8gR2V0IHRoZSBTU0wgY2VydGlmaWNhdGVcclxuICAgICAgICBjZXJ0ID0gYXdhaXQgZnNQcm9taXNlcy5yZWFkRmlsZShcclxuICAgICAgICAgIHBvc2l4LmpvaW4oc2VydmVyQ29uZmlnLnNzbC5jZXJ0UGF0aCwgJ3NlcnZlci5jcnQnKSxcclxuICAgICAgICAgICd1dGY4J1xyXG4gICAgICAgICk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMixcclxuICAgICAgICAgIGBbc2VydmVyXSBVbmFibGUgdG8gbG9hZCBrZXkvY2VydGlmaWNhdGUgZnJvbSB0aGUgJyR7c2VydmVyQ29uZmlnLnNzbC5jZXJ0UGF0aH0nIHBhdGguIENvdWxkIG5vdCBydW4gc2VjdXJlZCBsYXllciBzZXJ2ZXIuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmIChrZXkgJiYgY2VydCkge1xyXG4gICAgICAgIC8vIE1haW4gc2VydmVyIGluc3RhbmNlIChIVFRQUylcclxuICAgICAgICBjb25zdCBodHRwc1NlcnZlciA9IGh0dHBzLmNyZWF0ZVNlcnZlcih7IGtleSwgY2VydCB9LCBhcHApO1xyXG5cclxuICAgICAgICAvLyBBdHRhY2ggZXJyb3IgaGFuZGxlcnMgYW5kIGxpc3RlbiB0byB0aGUgc2VydmVyXHJcbiAgICAgICAgYXR0YWNoU2VydmVyRXJyb3JIYW5kbGVycyhodHRwc1NlcnZlcik7XHJcblxyXG4gICAgICAgIC8vIExpc3RlblxyXG4gICAgICAgIGh0dHBzU2VydmVyLmxpc3RlbihzZXJ2ZXJDb25maWcuc3NsLnBvcnQsIHNlcnZlckNvbmZpZy5ob3N0LCAoKSA9PiB7XHJcbiAgICAgICAgICAvLyBTYXZlIHRoZSByZWZlcmVuY2UgdG8gSFRUUFMgc2VydmVyXHJcbiAgICAgICAgICBhY3RpdmVTZXJ2ZXJzLnNldChzZXJ2ZXJDb25maWcuc3NsLnBvcnQsIGh0dHBzU2VydmVyKTtcclxuXHJcbiAgICAgICAgICBsb2coXHJcbiAgICAgICAgICAgIDMsXHJcbiAgICAgICAgICAgIGBbc2VydmVyXSBTdGFydGVkIEhUVFBTIHNlcnZlciBvbiAke3NlcnZlckNvbmZpZy5ob3N0fToke3NlcnZlckNvbmZpZy5zc2wucG9ydH0uYFxyXG4gICAgICAgICAgKTtcclxuXHJcbiAgICAgICAgICBpZiAoYWN0aXZlU2VydmVycy5zaXplID09PSAxKSB7XHJcbiAgICAgICAgICAgIC8vIFN0YXJ0IGEgV2ViU29ja2V0IGNvbm5lY3Rpb25cclxuICAgICAgICAgICAgd2ViU29ja2V0SW5pdCh7IC4uLmh0dHBzU2VydmVyLmFkZHJlc3MoKSwgcHJvdG9jb2w6ICdodHRwcycgfSk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBFbmFibGUgdGhlIHJhdGUgbGltaXRlciBpZiBjb25maWcgc2F5cyBzb1xyXG4gICAgaWYgKFxyXG4gICAgICBzZXJ2ZXJDb25maWcucmF0ZUxpbWl0aW5nICYmXHJcbiAgICAgIHNlcnZlckNvbmZpZy5yYXRlTGltaXRpbmcuZW5hYmxlICYmXHJcbiAgICAgICFbMCwgTmFOXS5pbmNsdWRlcyhzZXJ2ZXJDb25maWcucmF0ZUxpbWl0aW5nLm1heFJlcXVlc3RzKVxyXG4gICAgKSB7XHJcbiAgICAgIHJhdGVMaW1pdChhcHAsIHNlcnZlckNvbmZpZy5yYXRlTGltaXRpbmcpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFNldCB1cCBzdGF0aWMgZm9sZGVyJ3Mgcm91dGVcclxuICAgIGFwcC51c2UoZXhwcmVzcy5zdGF0aWMocG9zaXguam9pbihfX2Rpcm5hbWUsICdwdWJsaWMnKSkpO1xyXG5cclxuICAgIC8vIFNldCB1cCByb3V0ZXNcclxuICAgIGhlYWx0aFJvdXRlKGFwcCk7XHJcbiAgICBleHBvcnRSb3V0ZXMoYXBwKTtcclxuICAgIHVpUm91dGUoYXBwKTtcclxuICAgIHZTd2l0Y2hSb3V0ZShhcHApO1xyXG5cclxuICAgIC8vIFNldCB1cCBjZW50cmFsaXplZCBlcnJvciBoYW5kbGVyXHJcbiAgICBlcnJvckhhbmRsZXIoYXBwKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW3NlcnZlcl0gQ291bGQgbm90IGNvbmZpZ3VyZSBhbmQgc3RhcnQgdGhlIHNlcnZlci4nXHJcbiAgICApLnNldEVycm9yKGVycm9yKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogQ2xvc2VzIGFsbCBzZXJ2ZXJzIGFzc29jaWF0ZWQgd2l0aCBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBjbG9zZVNlcnZlcnMgPSAoKSA9PiB7XHJcbiAgbG9nKDQsIGBbc2VydmVyXSBDbG9zaW5nIGFsbCBzZXJ2ZXJzLmApO1xyXG4gIGZvciAoY29uc3QgW3BvcnQsIHNlcnZlcl0gb2YgYWN0aXZlU2VydmVycykge1xyXG4gICAgc2VydmVyLmNsb3NlKCgpID0+IHtcclxuICAgICAgYWN0aXZlU2VydmVycy5kZWxldGUocG9ydCk7XHJcbiAgICAgIGxvZyg0LCBgW3NlcnZlcl0gQ2xvc2VkIHNlcnZlciBvbiBwb3J0OiAke3BvcnR9LmApO1xyXG4gICAgfSk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEdldCBhbGwgc2VydmVycyBhc3NvY2lhdGVkIHdpdGggRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtBcnJheX0gLSBTZXJ2ZXJzIGFzc29jaWF0ZWQgd2l0aCBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBnZXRTZXJ2ZXJzID0gKCkgPT4gYWN0aXZlU2VydmVycztcclxuXHJcbi8qKlxyXG4gKiBFbmFibGUgcmF0ZSBsaW1pdGluZyBmb3IgdGhlIHNlcnZlci5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGxpbWl0Q29uZmlnIC0gQ29uZmlndXJhdGlvbiBvYmplY3QgZm9yIHJhdGUgbGltaXRpbmcuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZW5hYmxlUmF0ZUxpbWl0aW5nID0gKGxpbWl0Q29uZmlnKSA9PiByYXRlTGltaXQoYXBwLCBsaW1pdENvbmZpZyk7XHJcblxyXG4vKipcclxuICogR2V0IHRoZSBFeHByZXNzIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSAtIFRoZSBFeHByZXNzIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldEV4cHJlc3MgPSAoKSA9PiBleHByZXNzO1xyXG5cclxuLyoqXHJcbiAqIEdldCB0aGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IC0gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldEFwcCA9ICgpID0+IGFwcDtcclxuXHJcbi8qKlxyXG4gKiBBcHBseSBtaWRkbGV3YXJlKHMpIHRvIGEgc3BlY2lmaWMgcGF0aC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBUaGUgcGF0aCB0byB3aGljaCB0aGUgbWlkZGxld2FyZShzKSBzaG91bGQgYmUgYXBwbGllZC5cclxuICogQHBhcmFtIHsuLi5GdW5jdGlvbn0gbWlkZGxld2FyZXMgLSBUaGUgbWlkZGxld2FyZSBmdW5jdGlvbnMgdG8gYmUgYXBwbGllZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCB1c2UgPSAocGF0aCwgLi4ubWlkZGxld2FyZXMpID0+IHtcclxuICBhcHAudXNlKHBhdGgsIC4uLm1pZGRsZXdhcmVzKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBTZXQgdXAgYSByb3V0ZSB3aXRoIEdFVCBtZXRob2QgYW5kIGFwcGx5IG1pZGRsZXdhcmUocykuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIC0gVGhlIHJvdXRlIHBhdGguXHJcbiAqIEBwYXJhbSB7Li4uRnVuY3Rpb259IG1pZGRsZXdhcmVzIC0gVGhlIG1pZGRsZXdhcmUgZnVuY3Rpb25zIHRvIGJlIGFwcGxpZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0ID0gKHBhdGgsIC4uLm1pZGRsZXdhcmVzKSA9PiB7XHJcbiAgYXBwLmdldChwYXRoLCAuLi5taWRkbGV3YXJlcyk7XHJcbn07XHJcblxyXG4vKipcclxuICogU2V0IHVwIGEgcm91dGUgd2l0aCBQT1NUIG1ldGhvZCBhbmQgYXBwbHkgbWlkZGxld2FyZShzKS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBUaGUgcm91dGUgcGF0aC5cclxuICogQHBhcmFtIHsuLi5GdW5jdGlvbn0gbWlkZGxld2FyZXMgLSBUaGUgbWlkZGxld2FyZSBmdW5jdGlvbnMgdG8gYmUgYXBwbGllZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBwb3N0ID0gKHBhdGgsIC4uLm1pZGRsZXdhcmVzKSA9PiB7XHJcbiAgYXBwLnBvc3QocGF0aCwgLi4ubWlkZGxld2FyZXMpO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIHN0YXJ0U2VydmVyLFxyXG4gIGNsb3NlU2VydmVycyxcclxuICBnZXRTZXJ2ZXJzLFxyXG4gIGVuYWJsZVJhdGVMaW1pdGluZyxcclxuICBnZXRFeHByZXNzLFxyXG4gIGdldEFwcCxcclxuICB1c2UsXHJcbiAgZ2V0LFxyXG4gIHBvc3RcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgeyBfX2Rpcm5hbWUgfSBmcm9tICcuLi8uLi91dGlscy5qcyc7XHJcblxyXG4vKipcclxuICogQWRkcyB0aGUgR0VUIC8gcm91dGUgZm9yIGEgVUkgd2hlbiBlbmFibGVkIG9uIHRoZSBleHBvcnQgc2VydmVyLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgKGFwcCkgPT5cclxuICAhYXBwXHJcbiAgICA/IGZhbHNlXHJcbiAgICA6IGFwcC5nZXQoJy8nLCAocmVxdWVzdCwgcmVzcG9uc2UpID0+IHtcclxuICAgICAgICByZXNwb25zZS5zZW5kRmlsZShqb2luKF9fZGlybmFtZSwgJ3B1YmxpYycsICdpbmRleC5odG1sJykpO1xyXG4gICAgICB9KTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyBjbGVhckFsbFRpbWVycyB9IGZyb20gJy4vdGltZXJzLmpzJztcclxuaW1wb3J0IHsga2lsbFBvb2wgfSBmcm9tICcuL3Bvb2wuanMnO1xyXG5pbXBvcnQgeyBjbG9zZVNlcnZlcnMgfSBmcm9tICcuL3NlcnZlci9zZXJ2ZXIuanMnO1xyXG5pbXBvcnQgeyB0ZXJtaW5hdGVDbGllbnRzIH0gZnJvbSAnLi9zZXJ2ZXIvd2ViX3NvY2tldC5qcyc7XHJcblxyXG4vKipcclxuICogQ2xlYW4gdXAgZnVuY3Rpb24gdG8gdHJpZ2dlciBiZWZvcmUgZW5kaW5nIHByb2Nlc3MgZm9yIHRoZSBncmFjZWZ1bCBzaHV0ZG93bi5cclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IGV4aXRDb2RlIC0gQW4gZXhpdCBjb2RlIGZvciB0aGUgcHJvY2Vzcy5leGl0KCkgZnVuY3Rpb24uXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2h1dGRvd25DbGVhblVwID0gYXN5bmMgKGV4aXRDb2RlKSA9PiB7XHJcbiAgLy8gQXdhaXQgZnJlZWluZyBhbGwgcmVzb3VyY2VzXHJcbiAgYXdhaXQgUHJvbWlzZS5hbGxTZXR0bGVkKFtcclxuICAgIC8vIENsZWFyIGFsbCBvbmdvaW5nIHRpbWVyc1xyXG4gICAgY2xlYXJBbGxUaW1lcnMoKSxcclxuXHJcbiAgICAvLyBUZXJtaW5hdGUgYWxsIGNvbm5lY3RlZCBXZWJTb2NrZXQgY2xpZW50c1xyXG4gICAgdGVybWluYXRlQ2xpZW50cygpLFxyXG5cclxuICAgIC8vIEdldCBhdmFpbGFibGUgc2VydmVyIGluc3RhbmNlcyAoSFRUUC9IVFRQUykgYW5kIGNsb3NlIHRoZW1cclxuICAgIGNsb3NlU2VydmVycygpLFxyXG5cclxuICAgIC8vIENsb3NlIHBvb2wgYWxvbmcgd2l0aCBpdHMgd29ya2VycyBhbmQgdGhlIGJyb3dzZXIgaW5zdGFuY2UsIGlmIGV4aXN0c1xyXG4gICAga2lsbFBvb2woKVxyXG4gIF0pO1xyXG5cclxuICAvLyBFeGl0IHByb2Nlc3Mgd2l0aCBhIGNvcnJlY3QgY29kZVxyXG4gIHByb2Nlc3MuZXhpdChleGl0Q29kZSk7XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgc2h1dGRvd25DbGVhblVwXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0ICdjb2xvcnMnO1xyXG5cclxuaW1wb3J0IHsgY2hlY2tBbmRVcGRhdGVDYWNoZSB9IGZyb20gJy4vY2FjaGUuanMnO1xyXG5pbXBvcnQge1xyXG4gIGJhdGNoRXhwb3J0LFxyXG4gIHNldEFsbG93Q29kZUV4ZWN1dGlvbixcclxuICBzaW5nbGVFeHBvcnQsXHJcbiAgc3RhcnRFeHBvcnRcclxufSBmcm9tICcuL2NoYXJ0LmpzJztcclxuaW1wb3J0IHsgbWFwVG9OZXdDb25maWcsIG1hbnVhbENvbmZpZywgc2V0T3B0aW9ucyB9IGZyb20gJy4vY29uZmlnLmpzJztcclxuaW1wb3J0IHtcclxuICBpbml0TG9nZ2luZyxcclxuICBsb2csXHJcbiAgbG9nV2l0aFN0YWNrLFxyXG4gIHNldExvZ0xldmVsLFxyXG4gIGVuYWJsZUZpbGVMb2dnaW5nXHJcbn0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBpbml0UG9vbCwga2lsbFBvb2wgfSBmcm9tICcuL3Bvb2wuanMnO1xyXG5pbXBvcnQgeyBzaHV0ZG93bkNsZWFuVXAgfSBmcm9tICcuL3Jlc291cmNlX3JlbGVhc2UuanMnO1xyXG5pbXBvcnQgc2VydmVyLCB7IHN0YXJ0U2VydmVyIH0gZnJvbSAnLi9zZXJ2ZXIvc2VydmVyLmpzJztcclxuaW1wb3J0IHsgcHJpbnRMb2dvLCBwcmludFVzYWdlIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG4vKipcclxuICogQXR0YWNoZXMgZXhpdCBsaXN0ZW5lcnMgdG8gdGhlIHByb2Nlc3MsIGVuc3VyaW5nIHByb3BlciBjbGVhbnVwIG9mIHJlc291cmNlc1xyXG4gKiBhbmQgdGVybWluYXRpb24gb24gZXhpdCBzaWduYWxzLiBIYW5kbGVzICdleGl0JywgJ1NJR0lOVCcsICdTSUdURVJNJywgYW5kXHJcbiAqICd1bmNhdWdodEV4Y2VwdGlvbicgZXZlbnRzLlxyXG4gKi9cclxuY29uc3QgYXR0YWNoUHJvY2Vzc0V4aXRMaXN0ZW5lcnMgPSAoKSA9PiB7XHJcbiAgbG9nKDMsICdbcHJvY2Vzc10gQXR0YWNoaW5nIGV4aXQgbGlzdGVuZXJzIHRvIHRoZSBwcm9jZXNzLicpO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ2V4aXQnXHJcbiAgcHJvY2Vzcy5vbignZXhpdCcsIChjb2RlKSA9PiB7XHJcbiAgICBsb2coNCwgYFByb2Nlc3MgZXhpdGVkIHdpdGggY29kZSAke2NvZGV9LmApO1xyXG4gIH0pO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ1NJR0lOVCdcclxuICBwcm9jZXNzLm9uKCdTSUdJTlQnLCBhc3luYyAobmFtZSwgY29kZSkgPT4ge1xyXG4gICAgbG9nKDQsIGBUaGUgJHtuYW1lfSBldmVudCB3aXRoIGNvZGU6ICR7Y29kZX0uYCk7XHJcbiAgICBhd2FpdCBzaHV0ZG93bkNsZWFuVXAoMCk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAnU0lHVEVSTSdcclxuICBwcm9jZXNzLm9uKCdTSUdURVJNJywgYXN5bmMgKG5hbWUsIGNvZGUpID0+IHtcclxuICAgIGxvZyg0LCBgVGhlICR7bmFtZX0gZXZlbnQgd2l0aCBjb2RlOiAke2NvZGV9LmApO1xyXG4gICAgYXdhaXQgc2h1dGRvd25DbGVhblVwKDApO1xyXG4gIH0pO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ1NJR0hVUCdcclxuICBwcm9jZXNzLm9uKCdTSUdIVVAnLCBhc3luYyAobmFtZSwgY29kZSkgPT4ge1xyXG4gICAgbG9nKDQsIGBUaGUgJHtuYW1lfSBldmVudCB3aXRoIGNvZGU6ICR7Y29kZX0uYCk7XHJcbiAgICBhd2FpdCBzaHV0ZG93bkNsZWFuVXAoMCk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAndW5jYXVnaHRFeGNlcHRpb24nXHJcbiAgcHJvY2Vzcy5vbigndW5jYXVnaHRFeGNlcHRpb24nLCBhc3luYyAoZXJyb3IsIG5hbWUpID0+IHtcclxuICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFRoZSAke25hbWV9IGVycm9yLmApO1xyXG4gICAgYXdhaXQgc2h1dGRvd25DbGVhblVwKDEpO1xyXG4gIH0pO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIHRoZSBleHBvcnQgcHJvY2Vzcy4gVGFza3Mgc3VjaCBhcyBjb25maWd1cmluZyBsb2dnaW5nLCBjaGVja2luZ1xyXG4gKiBjYWNoZSBhbmQgc291cmNlcywgYW5kIGluaXRpYWxpemluZyB0aGUgcG9vbCBvZiByZXNvdXJjZXMgaGFwcGVuIGR1cmluZ1xyXG4gKiB0aGlzIHN0YWdlLiBGdW5jdGlvbiB0aGF0IGlzIHJlcXVpcmVkIHRvIGJlIGNhbGxlZCBiZWZvcmUgdHJ5aW5nIHRvIGV4cG9ydCBjaGFydHMgb3Igc2V0dGluZyBhIHNlcnZlci4gVGhlIGBvcHRpb25zYCBpcyBhbiBvYmplY3QgdGhhdCBjb250YWlucyBhbGwgb3B0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBBbGwgZXhwb3J0IG9wdGlvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSB1cGRhdGVkIGV4cG9ydCBvcHRpb25zLlxyXG4gKi9cclxuY29uc3QgaW5pdEV4cG9ydCA9IGFzeW5jIChvcHRpb25zKSA9PiB7XHJcbiAgLy8gU2V0IHRoZSBhbGxvd0NvZGVFeGVjdXRpb24gcGVyIGV4cG9ydCBtb2R1bGUgc2NvcGVcclxuICBzZXRBbGxvd0NvZGVFeGVjdXRpb24oXHJcbiAgICBvcHRpb25zLmN1c3RvbUxvZ2ljICYmIG9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgKTtcclxuXHJcbiAgLy8gSW5pdCB0aGUgbG9nZ2luZ1xyXG4gIGluaXRMb2dnaW5nKG9wdGlvbnMubG9nZ2luZyk7XHJcblxyXG4gIC8vIEF0dGFjaCBwcm9jZXNzJyBleGl0IGxpc3RlbmVyc1xyXG4gIGlmIChvcHRpb25zLm90aGVyLmxpc3RlblRvUHJvY2Vzc0V4aXRzKSB7XHJcbiAgICBhdHRhY2hQcm9jZXNzRXhpdExpc3RlbmVycygpO1xyXG4gIH1cclxuXHJcbiAgLy8gQ2hlY2sgaWYgY2FjaGUgbmVlZHMgdG8gYmUgdXBkYXRlZFxyXG4gIGF3YWl0IGNoZWNrQW5kVXBkYXRlQ2FjaGUob3B0aW9ucyk7XHJcblxyXG4gIC8vIEluaXQgdGhlIHBvb2xcclxuICBhd2FpdCBpbml0UG9vbCh7XHJcbiAgICBwb29sOiBvcHRpb25zLnBvb2wgfHwge1xyXG4gICAgICBtaW5Xb3JrZXJzOiAxLFxyXG4gICAgICBtYXhXb3JrZXJzOiAxXHJcbiAgICB9LFxyXG4gICAgcHVwcGV0ZWVyQXJnczogb3B0aW9ucy5wdXBwZXRlZXIuYXJncyB8fCBbXVxyXG4gIH0pO1xyXG5cclxuICAvLyBSZXR1cm4gdXBkYXRlZCBvcHRpb25zXHJcbiAgcmV0dXJuIG9wdGlvbnM7XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgLy8gU2VydmVyXHJcbiAgc2VydmVyLFxyXG4gIHN0YXJ0U2VydmVyLFxyXG5cclxuICAvLyBFeHBvcnRpbmdcclxuICBpbml0RXhwb3J0LFxyXG4gIHNpbmdsZUV4cG9ydCxcclxuICBiYXRjaEV4cG9ydCxcclxuICBzdGFydEV4cG9ydCxcclxuXHJcbiAgLy8gUG9vbFxyXG4gIGluaXRQb29sLFxyXG4gIGtpbGxQb29sLFxyXG5cclxuICAvLyBPdGhlclxyXG4gIHNldE9wdGlvbnMsXHJcbiAgc2h1dGRvd25DbGVhblVwLFxyXG5cclxuICAvLyBMb2dzXHJcbiAgbG9nLFxyXG4gIGxvZ1dpdGhTdGFjayxcclxuICBzZXRMb2dMZXZlbCxcclxuICBlbmFibGVGaWxlTG9nZ2luZyxcclxuXHJcbiAgLy8gVXRpbHNcclxuICBtYXBUb05ld0NvbmZpZyxcclxuICBtYW51YWxDb25maWcsXHJcbiAgcHJpbnRMb2dvLFxyXG4gIHByaW50VXNhZ2VcclxufTtcclxuIl0sIm5hbWVzIjpbInNjcmlwdHNOYW1lcyIsImNvcmUiLCJtb2R1bGVzIiwiaW5kaWNhdG9ycyIsImRlZmF1bHRDb25maWciLCJwdXBwZXRlZXIiLCJhcmdzIiwidmFsdWUiLCJ0eXBlIiwiZGVzY3JpcHRpb24iLCJoaWdoY2hhcnRzIiwidmVyc2lvbiIsImVudkxpbmsiLCJjZG5VUkwiLCJjb3JlU2NyaXB0cyIsIm1vZHVsZVNjcmlwdHMiLCJpbmRpY2F0b3JTY3JpcHRzIiwiY3VzdG9tU2NyaXB0cyIsImZvcmNlRmV0Y2giLCJjYWNoZVBhdGgiLCJleHBvcnQiLCJpbmZpbGUiLCJpbnN0ciIsIm9wdGlvbnMiLCJvdXRmaWxlIiwiY29uc3RyIiwiZGVmYXVsdEhlaWdodCIsImRlZmF1bHRXaWR0aCIsImRlZmF1bHRTY2FsZSIsImhlaWdodCIsIndpZHRoIiwic2NhbGUiLCJnbG9iYWxPcHRpb25zIiwidGhlbWVPcHRpb25zIiwiYmF0Y2giLCJyYXN0ZXJpemF0aW9uVGltZW91dCIsImN1c3RvbUxvZ2ljIiwiYWxsb3dDb2RlRXhlY3V0aW9uIiwiYWxsb3dGaWxlUmVzb3VyY2VzIiwiY3VzdG9tQ29kZSIsImNhbGxiYWNrIiwicmVzb3VyY2VzIiwibG9hZENvbmZpZyIsImxlZ2FjeU5hbWUiLCJjcmVhdGVDb25maWciLCJzZXJ2ZXIiLCJlbmFibGUiLCJjbGlOYW1lIiwiaG9zdCIsInBvcnQiLCJiZW5jaG1hcmtpbmciLCJwcm94eSIsInRpbWVvdXQiLCJyYXRlTGltaXRpbmciLCJtYXhSZXF1ZXN0cyIsIndpbmRvdyIsImRlbGF5IiwidHJ1c3RQcm94eSIsInNraXBLZXkiLCJza2lwVG9rZW4iLCJzc2wiLCJmb3JjZSIsImNlcnRQYXRoIiwicG9vbCIsIm1pbldvcmtlcnMiLCJtYXhXb3JrZXJzIiwid29ya0xpbWl0IiwiYWNxdWlyZVRpbWVvdXQiLCJjcmVhdGVUaW1lb3V0IiwiZGVzdHJveVRpbWVvdXQiLCJpZGxlVGltZW91dCIsImNyZWF0ZVJldHJ5SW50ZXJ2YWwiLCJyZWFwZXJJbnRlcnZhbCIsImxvZ2dpbmciLCJsZXZlbCIsImZpbGUiLCJkZXN0IiwidWkiLCJyb3V0ZSIsIm90aGVyIiwibm9kZUVudiIsImxpc3RlblRvUHJvY2Vzc0V4aXRzIiwibm9Mb2dvIiwiaGFyZFJlc2V0UGFnZSIsImJyb3dzZXJTaGVsbE1vZGUiLCJkZWJ1ZyIsImhlYWRsZXNzIiwiZGV2dG9vbHMiLCJsaXN0ZW5Ub0NvbnNvbGUiLCJkdW1waW8iLCJzbG93TW8iLCJkZWJ1Z2dpbmdQb3J0Iiwid2ViU29ja2V0IiwicmVjb25uZWN0IiwicmVqZWN0VW5hdXRob3JpemVkIiwicGluZ1RpbWVvdXQiLCJyZWNvbm5lY3RJbnRlcnZhbCIsInJlY29ubmVjdEF0dGVtcHRzIiwibWVzc2FnZUludGVydmFsIiwidXJsIiwic2VjcmV0IiwicHJvbXB0c0NvbmZpZyIsIm5hbWUiLCJtZXNzYWdlIiwiaW5pdGlhbCIsImpvaW4iLCJzZXBhcmF0b3IiLCJpbnN0cnVjdGlvbnMiLCJjaG9pY2VzIiwiaGludCIsIm1pbiIsIm1heCIsInJvdW5kIiwiYWJzb2x1dGVQcm9wcyIsIm5lc3RlZEFyZ3MiLCJjcmVhdGVOZXN0ZWRBcmdzIiwib2JqIiwicHJvcENoYWluIiwiT2JqZWN0Iiwia2V5cyIsImZvckVhY2giLCJrIiwiaW5jbHVkZXMiLCJlbnRyeSIsInN1YnN0cmluZyIsInVuZGVmaW5lZCIsImRvdGVudiIsImNvbmZpZyIsInYiLCJmaWx0ZXJBcnJheSIsInoiLCJzdHJpbmciLCJ0cmFuc2Zvcm0iLCJzcGxpdCIsIm1hcCIsInRyaW0iLCJmaWx0ZXIiLCJsZW5ndGgiLCJlbnVtIiwidmFsdWVzIiwicmVmaW5lIiwiaXNOYU4iLCJwYXJzZUZsb2F0IiwiZW52cyIsIm9iamVjdCIsIkhJR0hDSEFSVFNfVkVSU0lPTiIsInRlc3QiLCJISUdIQ0hBUlRTX0NETl9VUkwiLCJzdGFydHNXaXRoIiwiSElHSENIQVJUU19DT1JFX1NDUklQVFMiLCJISUdIQ0hBUlRTX01PRFVMRV9TQ1JJUFRTIiwiSElHSENIQVJUU19JTkRJQ0FUT1JfU0NSSVBUUyIsIkhJR0hDSEFSVFNfRk9SQ0VfRkVUQ0giLCJISUdIQ0hBUlRTX0NBQ0hFX1BBVEgiLCJISUdIQ0hBUlRTX0FETUlOX1RPS0VOIiwiRVhQT1JUX1RZUEUiLCJFWFBPUlRfQ09OU1RSIiwiRVhQT1JUX0RFRkFVTFRfSEVJR0hUIiwiRVhQT1JUX0RFRkFVTFRfV0lEVEgiLCJFWFBPUlRfREVGQVVMVF9TQ0FMRSIsIkVYUE9SVF9SQVNURVJJWkFUSU9OX1RJTUVPVVQiLCJDVVNUT01fTE9HSUNfQUxMT1dfQ09ERV9FWEVDVVRJT04iLCJDVVNUT01fTE9HSUNfQUxMT1dfRklMRV9SRVNPVVJDRVMiLCJTRVJWRVJfRU5BQkxFIiwiU0VSVkVSX0hPU1QiLCJTRVJWRVJfUE9SVCIsIlNFUlZFUl9CRU5DSE1BUktJTkciLCJTRVJWRVJfUFJPWFlfSE9TVCIsIlNFUlZFUl9QUk9YWV9QT1JUIiwiU0VSVkVSX1BST1hZX1RJTUVPVVQiLCJTRVJWRVJfUkFURV9MSU1JVElOR19FTkFCTEUiLCJTRVJWRVJfUkFURV9MSU1JVElOR19NQVhfUkVRVUVTVFMiLCJTRVJWRVJfUkFURV9MSU1JVElOR19XSU5ET1ciLCJTRVJWRVJfUkFURV9MSU1JVElOR19ERUxBWSIsIlNFUlZFUl9SQVRFX0xJTUlUSU5HX1RSVVNUX1BST1hZIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9LRVkiLCJTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX1RPS0VOIiwiU0VSVkVSX1NTTF9FTkFCTEUiLCJTRVJWRVJfU1NMX0ZPUkNFIiwiU0VSVkVSX1NTTF9QT1JUIiwiU0VSVkVSX1NTTF9DRVJUX1BBVEgiLCJQT09MX01JTl9XT1JLRVJTIiwiUE9PTF9NQVhfV09SS0VSUyIsIlBPT0xfV09SS19MSU1JVCIsIlBPT0xfQUNRVUlSRV9USU1FT1VUIiwiUE9PTF9DUkVBVEVfVElNRU9VVCIsIlBPT0xfREVTVFJPWV9USU1FT1VUIiwiUE9PTF9JRExFX1RJTUVPVVQiLCJQT09MX0NSRUFURV9SRVRSWV9JTlRFUlZBTCIsIlBPT0xfUkVBUEVSX0lOVEVSVkFMIiwiUE9PTF9CRU5DSE1BUktJTkciLCJMT0dHSU5HX0xFVkVMIiwiTE9HR0lOR19GSUxFIiwiTE9HR0lOR19ERVNUIiwiVUlfRU5BQkxFIiwiVUlfUk9VVEUiLCJPVEhFUl9OT0RFX0VOViIsIk9USEVSX0xJU1RFTl9UT19QUk9DRVNTX0VYSVRTIiwiT1RIRVJfTk9fTE9HTyIsIk9USEVSX0hBUkRfUkVTRVRfUEFHRSIsIk9USEVSX0JST1dTRVJfU0hFTExfTU9ERSIsIkRFQlVHX0VOQUJMRSIsIkRFQlVHX0hFQURMRVNTIiwiREVCVUdfREVWVE9PTFMiLCJERUJVR19MSVNURU5fVE9fQ09OU09MRSIsIkRFQlVHX0RVTVBJTyIsIkRFQlVHX1NMT1dfTU8iLCJERUJVR19ERUJVR0dJTkdfUE9SVCIsIldFQl9TT0NLRVRfRU5BQkxFIiwiV0VCX1NPQ0tFVF9SRUNPTk5FQ1QiLCJXRUJfU09DS0VUX1JFSkVDVF9VTkFVVEhPUklaRUQiLCJXRUJfU09DS0VUX1BJTkdfVElNRU9VVCIsIldFQl9TT0NLRVRfUkVDT05ORUNUX0lOVEVSVkFMIiwiV0VCX1NPQ0tFVF9SRUNPTk5FQ1RfQVRURU1QVFMiLCJXRUJfU09DS0VUX01FU1NBR0VfSU5URVJWQUwiLCJXRUJfU09DS0VUX1VSTCIsIldFQl9TT0NLRVRfU0VDUkVUIiwicGFydGlhbCIsInBhcnNlIiwicHJvY2VzcyIsImVudiIsImNvbG9ycyIsInRvQ29uc29sZSIsInRvRmlsZSIsInBhdGhDcmVhdGVkIiwibGV2ZWxzRGVzYyIsInRpdGxlIiwiY29sb3IiLCJsaXN0ZW5lcnMiLCJrZXkiLCJvcHRpb24iLCJlbnRyaWVzIiwibG9nVG9GaWxlIiwidGV4dHMiLCJwcmVmaXgiLCJleGlzdHNTeW5jIiwibWtkaXJTeW5jIiwiYXBwZW5kRmlsZSIsImNvbmNhdCIsImVycm9yIiwiY29uc29sZSIsImxvZyIsIm5ld0xldmVsIiwiRGF0ZSIsInRvU3RyaW5nIiwiZm4iLCJhcHBseSIsImxvZ1dpdGhTdGFjayIsImN1c3RvbU1lc3NhZ2UiLCJtYWluTWVzc2FnZSIsInN0YWNrTWVzc2FnZSIsInN0YWNrIiwic2xpY2UiLCJzZXRMb2dMZXZlbCIsImVuYWJsZUZpbGVMb2dnaW5nIiwibG9nRGVzdCIsImxvZ0ZpbGUiLCJlbmRzV2l0aCIsIl9fZGlybmFtZSIsImZpbGVVUkxUb1BhdGgiLCJVUkwiLCJkb2N1bWVudCIsInJlcXVpcmUiLCJwYXRoVG9GaWxlVVJMIiwiX19maWxlbmFtZSIsImhyZWYiLCJfZG9jdW1lbnRDdXJyZW50U2NyaXB0Iiwic3JjIiwiYmFzZVVSSSIsImZpeFR5cGUiLCJmb3JtYXRzIiwib3V0VHlwZSIsInBvcCIsImZpbmQiLCJ0IiwiaGFuZGxlUmVzb3VyY2VzIiwiYWxsb3dlZFByb3BzIiwiaGFuZGxlZFJlc291cmNlcyIsImNvcnJlY3RSZXNvdXJjZXMiLCJpc0NvcnJlY3RKU09OIiwicmVhZEZpbGVTeW5jIiwiZmlsZXMiLCJwcm9wTmFtZSIsIml0ZW0iLCJkYXRhIiwicGFyc2VkRGF0YSIsIkpTT04iLCJzdHJpbmdpZnkiLCJkZWVwQ29weSIsImNvcHkiLCJBcnJheSIsImlzQXJyYXkiLCJwcm90b3R5cGUiLCJoYXNPd25Qcm9wZXJ0eSIsImNhbGwiLCJvcHRpb25zU3RyaW5naWZ5IiwiYWxsb3dGdW5jdGlvbnMiLCJyZXBsYWNlQWxsIiwicHJpbnRVc2FnZSIsImJvbGQiLCJ5ZWxsb3ciLCJjeWNsZUNhdGVnb3JpZXMiLCJkZXNjTmFtZSIsImdyZWVuIiwiaSIsImJsdWUiLCJjYXRlZ29yeSIsInRvVXBwZXJDYXNlIiwicmVkIiwidG9Cb29sZWFuIiwid3JhcEFyb3VuZCIsInJlcGxhY2UiLCJtZWFzdXJlVGltZSIsInN0YXJ0IiwiaHJ0aW1lIiwiYmlnaW50IiwiTnVtYmVyIiwiZ2VuZXJhbE9wdGlvbnMiLCJnZXRPcHRpb25zIiwibWVyZ2VDb25maWdPcHRpb25zIiwibmV3T3B0aW9ucyIsIm1lcmdlZE9wdGlvbnMiLCJ1cGRhdGVEZWZhdWx0Q29uZmlnIiwiY29uZmlnT2JqIiwiY3VzdG9tT2JqIiwiY3VzdG9tVmFsdWUiLCJpbml0T3B0aW9ucyIsIml0ZW1zIiwicmVjdXJzaXZlUHJvcHMiLCJvYmplY3RUb1VwZGF0ZSIsIm5lc3RlZE5hbWVzIiwic2hpZnQiLCJhc3NpZ24iLCJhc3luYyIsImZldGNoIiwicmVxdWVzdE9wdGlvbnMiLCJQcm9taXNlIiwicmVzb2x2ZSIsInJlamVjdCIsInByb3RvY29sIiwiaHR0cHMiLCJodHRwIiwiZ2V0UHJvdG9jb2wiLCJnZXQiLCJyZXMiLCJvbiIsImNodW5rIiwidGV4dCIsIkV4cG9ydEVycm9yIiwiRXJyb3IiLCJjb25zdHJ1Y3RvciIsInN1cGVyIiwidGhpcyIsInNldEVycm9yIiwic3RhdHVzQ29kZSIsImNhY2hlIiwiYWN0aXZlTWFuaWZlc3QiLCJzb3VyY2VzIiwiaGNWZXJzaW9uIiwiZXh0cmFjdFZlcnNpb24iLCJpbmRleE9mIiwiZmV0Y2hBbmRQcm9jZXNzU2NyaXB0Iiwic2NyaXB0IiwiZmV0Y2hlZE1vZHVsZXMiLCJzaG91bGRUaHJvd0Vycm9yIiwicmVzcG9uc2UiLCJ1cGRhdGVDYWNoZSIsImhpZ2hjaGFydHNPcHRpb25zIiwicHJveHlPcHRpb25zIiwic291cmNlUGF0aCIsInByb3h5QWdlbnQiLCJwcm94eUhvc3QiLCJwcm94eVBvcnQiLCJIdHRwc1Byb3h5QWdlbnQiLCJhZ2VudCIsImFsbEZldGNoUHJvbWlzZXMiLCJhbGwiLCJmZXRjaFNjcmlwdHMiLCJjIiwibSIsIndyaXRlRmlsZVN5bmMiLCJjaGVja0FuZFVwZGF0ZUNhY2hlIiwibWFuaWZlc3RQYXRoIiwicmVxdWVzdFVwZGF0ZSIsIm1hbmlmZXN0IiwibW9kdWxlTWFwIiwibnVtYmVyT2ZNb2R1bGVzIiwic29tZSIsIm1vZHVsZU5hbWUiLCJuZXdNYW5pZmVzdCIsInNhdmVDb25maWdUb01hbmlmZXN0IiwiZ2V0Q2FjaGVQYXRoIiwic2V0dXBIaWdoY2hhcnRzIiwiSGlnaGNoYXJ0cyIsImFuaW1PYmplY3QiLCJkdXJhdGlvbiIsInRyaWdnZXJFeHBvcnQiLCJjaGFydE9wdGlvbnMiLCJkaXNwbGF5RXJyb3JzIiwiX2Rpc3BsYXlFcnJvcnMiLCJtZXJnZSIsInNldE9wdGlvbnMiLCJ3cmFwIiwic2V0T3B0aW9uc09iaiIsIkZ1bmN0aW9uIiwiY2hhcnQiLCJhbmltYXRpb24iLCJzdHJJbmoiLCJpc1JlbmRlckNvbXBsZXRlIiwiQ2hhcnQiLCJwcm9jZWVkIiwidXNlck9wdGlvbnMiLCJjYiIsImV4cG9ydGluZyIsImVuYWJsZWQiLCJwbG90T3B0aW9ucyIsInNlcmllcyIsImxhYmVsIiwidG9vbHRpcCIsIm9uSGlnaGNoYXJ0c1JlbmRlciIsImFkZEV2ZW50IiwiU2VyaWVzIiwiZmluYWxPcHRpb25zIiwiZmluYWxDYWxsYmFjayIsImRlZmF1bHRPcHRpb25zIiwicHJvcCIsInRlbXBsYXRlIiwiYnJvd3NlciIsIm5ld1BhZ2UiLCJwYWdlIiwic2V0Q2FjaGVFbmFibGVkIiwic2V0UGFnZUNvbnRlbnQiLCIkZXZhbCIsImVsZW1lbnQiLCJlcnJvck1lc3NhZ2UiLCJpbm5lckhUTUwiLCJzZXRQYWdlRXZlbnRzIiwiY2xlYXJQYWdlUmVzb3VyY2VzIiwiaW5qZWN0ZWRSZXNvdXJjZXMiLCJyZXNvdXJjZSIsImRpc3Bvc2UiLCJldmFsdWF0ZSIsIm9sZENoYXJ0cyIsImNoYXJ0cyIsIm9sZENoYXJ0IiwiZGVzdHJveSIsInNjcmlwdHNUb1JlbW92ZSIsImdldEVsZW1lbnRzQnlUYWdOYW1lIiwic3R5bGVzVG9SZW1vdmUiLCJsaW5rc1RvUmVtb3ZlIiwicmVtb3ZlIiwic2V0Q29udGVudCIsIndhaXRVbnRpbCIsImFkZFNjcmlwdFRhZyIsInBhdGgiLCJzZXRBc0NvbmZpZyIsInB1cHBldGVlckV4cG9ydCIsImV4cG9ydE9wdGlvbnMiLCJkZWJ1Z2dlciIsImlzU1ZHIiwic3ZnVGVtcGxhdGUiLCJpbmplY3RlZEpzIiwianMiLCJwdXNoIiwiY29udGVudCIsImlzTG9jYWwiLCJqc1Jlc291cmNlIiwiaW5qZWN0ZWRDc3MiLCJjc3MiLCJjc3NJbXBvcnRzIiwibWF0Y2giLCJjc3NJbXBvcnRQYXRoIiwiY3NzUmVzb3VyY2UiLCJhZGRTdHlsZVRhZyIsImFkZFBhZ2VSZXNvdXJjZXMiLCJzaXplIiwic3ZnRWxlbWVudCIsInF1ZXJ5U2VsZWN0b3IiLCJjaGFydEhlaWdodCIsImJhc2VWYWwiLCJjaGFydFdpZHRoIiwiYm9keSIsInN0eWxlIiwiem9vbSIsIm1hcmdpbiIsInZpZXdwb3J0SGVpZ2h0IiwiTWF0aCIsImNlaWwiLCJ2aWV3cG9ydFdpZHRoIiwieCIsInkiLCJnZXRCb3VuZGluZ0NsaWVudFJlY3QiLCJ0cnVuYyIsImdldENsaXBSZWdpb24iLCJzZXRWaWV3cG9ydCIsImRldmljZVNjYWxlRmFjdG9yIiwib3V0ZXJIVE1MIiwiY3JlYXRlU1ZHIiwiZW5jb2RpbmciLCJjbGlwIiwicmFjZSIsInNjcmVlbnNob3QiLCJjYXB0dXJlQmV5b25kVmlld3BvcnQiLCJmdWxsUGFnZSIsIm9wdGltaXplRm9yU3BlZWQiLCJxdWFsaXR5Iiwib21pdEJhY2tncm91bmQiLCJfcmVzb2x2ZSIsInNldFRpbWVvdXQiLCJjcmVhdGVJbWFnZSIsImVtdWxhdGVNZWRpYVR5cGUiLCJwZGYiLCJjcmVhdGVQREYiLCJzdGF0cyIsInBlcmZvcm1lZEV4cG9ydHMiLCJleHBvcnRBdHRlbXB0cyIsImV4cG9ydEZyb21TdmdBdHRlbXB0cyIsInRpbWVTcGVudCIsImRyb3BwZWRFeHBvcnRzIiwic3BlbnRBdmVyYWdlIiwicG9vbENvbmZpZyIsImZhY3RvcnkiLCJjcmVhdGUiLCJpZCIsInV1aWQiLCJzdGFydERhdGUiLCJnZXRUaW1lIiwiaXNDbG9zZWQiLCJ3b3JrQ291bnQiLCJyYW5kb20iLCJ2YWxpZGF0ZSIsIndvcmtlckhhbmRsZSIsImNsb3NlIiwiaW5pdFBvb2wiLCJwdXBwZXRlZXJBcmdzIiwiZW5hYmxlZERlYnVnIiwiZGVidWdPcHRpb25zIiwibGF1bmNoT3B0aW9ucyIsInVzZXJEYXRhRGlyIiwiaGFuZGxlU0lHSU5UIiwiaGFuZGxlU0lHVEVSTSIsImhhbmRsZVNJR0hVUCIsIndhaXRGb3JJbml0aWFsUGFnZSIsImRlZmF1bHRWaWV3cG9ydCIsInRyeUNvdW50Iiwib3BlbiIsImxhdW5jaCIsImNyZWF0ZUJyb3dzZXIiLCJwYXJzZUludCIsIlBvb2wiLCJhY3F1aXJlVGltZW91dE1pbGxpcyIsImNyZWF0ZVRpbWVvdXRNaWxsaXMiLCJkZXN0cm95VGltZW91dE1pbGxpcyIsImlkbGVUaW1lb3V0TWlsbGlzIiwiY3JlYXRlUmV0cnlJbnRlcnZhbE1pbGxpcyIsInJlYXBJbnRlcnZhbE1pbGxpcyIsInByb3BhZ2F0ZUNyZWF0ZUVycm9yIiwiaGFyZFJlc2V0IiwiZ290byIsImNsZWFyUGFnZSIsImV2ZW50SWQiLCJpbml0aWFsUmVzb3VyY2VzIiwiYWNxdWlyZSIsInByb21pc2UiLCJyZWxlYXNlIiwia2lsbFBvb2wiLCJ3b3JrZXIiLCJ1c2VkIiwiZGVzdHJveWVkIiwiY29ubmVjdGVkIiwiY2xvc2VCcm93c2VyIiwicG9zdFdvcmsiLCJhdmFpbGFibGUiLCJwZW5kaW5nIiwiZ2V0UG9vbEluZm9KU09OIiwiZ2V0UG9vbEluZm8iLCJhY3F1aXJlQ291bnRlciIsInBheWxvYWQiLCJyZXF1ZXN0SWQiLCJ3b3JrU3RhcnQiLCJleHBvcnRDb3VudGVyIiwicmVzdWx0IiwiZXhwb3J0VGltZSIsIm51bUZyZWUiLCJudW1Vc2VkIiwibnVtUGVuZGluZ0FjcXVpcmVzIiwiZ2V0U3RhdHMiLCJzdGFydEV4cG9ydCIsInNldHRpbmdzIiwiZW5kQ2FsbGJhY2siLCJzdmciLCJpbml0RXhwb3J0U2V0dGluZ3MiLCJleHBvcnRBc1N0cmluZyIsImlucHV0IiwiSlNET00iLCJET01QdXJpZnkiLCJzYW5pdGl6ZSIsIkFERF9UQUdTIiwiZG9TdHJhaWdodEluamVjdCIsImRvRXhwb3J0IiwiZmluZENoYXJ0U2l6ZSIsInByZWNpc2lvbiIsIm11bHRpcGxpZXIiLCJwb3ciLCJyb3VuZE51bWJlciIsInNvdXJjZUhlaWdodCIsInNvdXJjZVdpZHRoIiwicGFyYW0iLCJjaGFydEpzb24iLCJjdXN0b21Mb2dpY09wdGlvbnMiLCJhbGxvd0NvZGVFeGVjdXRpb25TY29wZWQiLCJvcHRpb25zTmFtZSIsInN0cmluZ1RvRXhwb3J0IiwiY2hhcnRKU09OIiwidGltZXJJZHMiLCJhZGRUaW1lciIsImNsZWFyQWxsVGltZXJzIiwiY2xlYXJJbnRlcnZhbCIsImNsZWFyVGltZW91dCIsImxvZ0Vycm9yTWlkZGxld2FyZSIsInJlcSIsIm5leHQiLCJyZXR1cm5FcnJvck1pZGRsZXdhcmUiLCJzdENvZGUiLCJzdGF0dXMiLCJqc29uIiwicmF0ZUxpbWl0IiwiYXBwIiwibGltaXRDb25maWciLCJtc2ciLCJyYXRlT3B0aW9ucyIsImxpbWl0ZXIiLCJ3aW5kb3dNcyIsImRlbGF5TXMiLCJoYW5kbGVyIiwicmVxdWVzdCIsImZvcm1hdCIsInNlbmQiLCJkZWZhdWx0Iiwic2tpcCIsInF1ZXJ5IiwiYWNjZXNzX3Rva2VuIiwidXNlIiwidGVsZW1ldHJ5VGVtcGxhdGUiLCJ0ZWxlbWV0cnlEYXRhIiwibnVtYmVyT2ZSZXF1ZXN0cyIsIm9wdGlvbnNJbkFycmF5IiwiZmlsdGVyRGF0YSIsImZpbHRlcmVkT2JqZWN0IiwidGVtcGxhdGVLZXkiLCJ0ZW1wbGF0ZVZhbHVlIiwiaW5kZXgiLCJvcHRpb25zVmFsdWUiLCJwcmVwYXJlVGVsZW1ldHJ5Iiwid2ViU29ja2V0Q2xpZW50cyIsIk1hcCIsIndlYlNvY2tldE9wdGlvbnMiLCJpbml0IiwiYWRkcmVzcyIsImNvbm5lY3Rpb25PcHRpb25zIiwiaGVhZGVycyIsImF1dGgiLCJqd3QiLCJzaWduIiwic3VjY2VzcyIsImFsZ29yaXRobSIsImNsaWVudE9wdGlvbnMiLCJyZWNvbm5lY3RUcnkiLCJjb25uZWN0Iiwic2V0SW50ZXJ2YWwiLCJ3ZWJTb2NrZXRDbGllbnQiLCJyZWFkeVN0YXRlIiwiV2ViU29ja2V0IiwiT1BFTiIsInNlbmRpbmdNZXNzYWdlSW50ZXJ2YWwiLCJ3ZWJTb2NrZXRVcmwiLCJzZXQiLCJjb2RlIiwiZGVsZXRlIiwidGVybWluYXRlIiwidGVybWluYXRlQ2xpZW50cyIsImNsaWVudCIsImNsZWFyIiwiSHR0cEVycm9yIiwic2V0U3RhdHVzIiwidlN3aXRjaFJvdXRlIiwicG9zdCIsImFkbWluVG9rZW4iLCJ0b2tlbiIsIm5ld1ZlcnNpb24iLCJwYXJhbXMiLCJ1cGRhdGVWZXJzaW9uIiwicmV2ZXJzZWRNaW1lIiwicG5nIiwianBlZyIsImdpZiIsInJlcXVlc3RzQ291bnRlciIsImJlZm9yZVJlcXVlc3QiLCJhZnRlclJlcXVlc3QiLCJkb0NhbGxiYWNrcyIsImNhbGxiYWNrcyIsInVuaXF1ZUlkIiwiY2FsbFJlc3BvbnNlIiwiZXhwb3J0SGFuZGxlciIsInN0b3BDb3VudGVyIiwiY29ubmVjdGlvbiIsInJlbW90ZUFkZHJlc3MiLCJjb25uZWN0aW9uQWJvcnRlZCIsInNvY2tldCIsInRvTG93ZXJDYXNlIiwic3Vic3RyIiwiYjY0Iiwibm9Eb3dubG9hZCIsInBhdHRlcm4iLCJpc1ByaXZhdGVSYW5nZVVybEZvdW5kIiwiaW5mbyIsInJlbW92ZUFsbExpc3RlbmVycyIsIkJ1ZmZlciIsImZyb20iLCJoZWFkZXIiLCJhdHRhY2htZW50IiwiZmlsZW5hbWUiLCJwa2dGaWxlIiwicGF0aGVyIiwic2VydmVyU3RhcnRUaW1lIiwic3VjY2Vzc1JhdGVzIiwiYWRkSGVhbHRoUm91dGVzIiwic3VjY2Vzc1JhdGlvIiwiXyIsInBlcmlvZCIsIm1vdmluZ0F2ZXJhZ2UiLCJyZWR1Y2UiLCJhIiwiYiIsImJvb3RUaW1lIiwidXB0aW1lIiwiZmxvb3IiLCJoaWdoY2hhcnRzVmVyc2lvbiIsImF2ZXJhZ2VQcm9jZXNzaW5nVGltZSIsImZhaWxlZEV4cG9ydHMiLCJzdWNlc3NSYXRpbyIsInRvRml4ZWQiLCJzdmdFeHBvcnRBdHRlbXB0cyIsImpzb25FeHBvcnRBdHRlbXB0cyIsImFjdGl2ZVNlcnZlcnMiLCJleHByZXNzIiwiZGlzYWJsZSIsImNvcnMiLCJzdG9yYWdlIiwibXVsdGVyIiwibWVtb3J5U3RvcmFnZSIsInVwbG9hZCIsImxpbWl0cyIsImZpZWxkU2l6ZSIsImxpbWl0IiwidXJsZW5jb2RlZCIsImV4dGVuZGVkIiwibm9uZSIsImF0dGFjaFNlcnZlckVycm9ySGFuZGxlcnMiLCJzdGFydFNlcnZlciIsInNlcnZlckNvbmZpZyIsImh0dHBTZXJ2ZXIiLCJjcmVhdGVTZXJ2ZXIiLCJsaXN0ZW4iLCJ3ZWJTb2NrZXRJbml0IiwiY2VydCIsImZzUHJvbWlzZXMiLCJyZWFkRmlsZSIsInBvc2l4IiwiaHR0cHNTZXJ2ZXIiLCJOYU4iLCJzdGF0aWMiLCJoZWFsdGhSb3V0ZSIsImV4cG9ydFJvdXRlcyIsInNlbmRGaWxlIiwidWlSb3V0ZSIsImVycm9ySGFuZGxlciIsImNsb3NlU2VydmVycyIsImdldFNlcnZlcnMiLCJlbmFibGVSYXRlTGltaXRpbmciLCJnZXRFeHByZXNzIiwiZ2V0QXBwIiwibWlkZGxld2FyZXMiLCJzaHV0ZG93bkNsZWFuVXAiLCJleGl0Q29kZSIsImFsbFNldHRsZWQiLCJleGl0IiwiaW5pdEV4cG9ydCIsImluaXRMb2dnaW5nIiwic2luZ2xlRXhwb3J0IiwiYmF0Y2hFeHBvcnQiLCJiYXRjaEZ1bmN0aW9ucyIsInBhaXIiLCJjb25maWdJbmRleCIsImZpbmRJbmRleCIsImFyZyIsImZpbGVOYW1lIiwibG9hZENvbmZpZ0ZpbGUiLCJzaG93VXNhZ2UiLCJwcm9wZXJ0aWVzQ2hhaW4iLCJhcmd1bWVudFR5cGUiLCJwYWlyQXJndW1lbnRWYWx1ZSIsIm1hcFRvTmV3Q29uZmlnIiwib2xkT3B0aW9ucyIsIm1hbnVhbENvbmZpZyIsImNvbmZpZ0ZpbGVOYW1lIiwiY29uZmlnRmlsZSIsImNob2ljZSIsInByb21wdHMiLCJvblN1Ym1pdCIsInAiLCJjYXRlZ29yaWVzIiwicXVlc3Rpb25zQ291bnRlciIsImFsbFF1ZXN0aW9ucyIsInNlY3Rpb24iLCJwcm9tcHQiLCJhbnN3ZXIiLCJtb2R1bGUiLCJwcm9taXNlcyIsIndyaXRlRmlsZSIsInByaW50TG9nbyIsInBhY2thZ2VWZXJzaW9uIl0sIm1hcHBpbmdzIjoieWZBZU8sTUFBTUEsRUFBZSxDQUMxQkMsS0FBTSxDQUFDLGFBQWMsa0JBQW1CLGlCQUN4Q0MsUUFBUyxDQUNQLFFBQ0EsTUFDQSxRQUNBLFlBQ0EsdUJBQ0EsZ0JBRUEsZUFDQSxRQUNBLE9BQ0EsYUFDQSxtQkFDQSxlQUNBLGNBQ0EsVUFDQSxVQUNBLGNBQ0EsV0FDQSxVQUNBLFlBQ0EsY0FDQSxZQUNBLHNCQUNBLFNBQ0EsU0FDQSxXQUNBLGFBQ0EsWUFDQSxlQUNBLHlCQUNBLFNBQ0EsZUFDQSxZQUNBLGtCQUNBLFNBQ0EsY0FDQSxtQkFDQSxlQUNBLGtCQUNBLGNBQ0EsZUFFQSxjQUNBLFdBQ0EsZUFDQSxXQUNBLFNBQ0EsT0FDQSxXQUNBLFlBQ0EsU0FDQSxxQkFDQSxhQUNBLFdBQ0EsV0FDQSxXQUNBLFdBQ0EsZUFDQSxVQUNBLGtCQUNBLG9CQUNBLGFBQ0EsVUFDQSxjQUNBLFlBQ0EsWUFFRkMsV0FBWSxDQUFDLG1CQUtGQyxFQUFnQixDQUMzQkMsVUFBVyxDQUNUQyxLQUFNLENBQ0pDLE1BQU8sQ0FDTCxtQ0FDQSxrQkFDQSwwQ0FDQSwyQkFDQSxrQ0FDQSxrQ0FDQSx3Q0FDQSwyQ0FDQSxxQkFDQSw0QkFDQSwyQ0FDQSx1REFDQSw2QkFDQSx5QkFDQSwwQkFDQSwr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 diff --git a/dist/index.esm.js b/dist/index.esm.js index d6cefc0a..28739cb4 100644 --- a/dist/index.esm.js +++ b/dist/index.esm.js @@ -1,2 +1,2 @@ -import"colors";import{existsSync as e,mkdirSync as t,appendFile as r,readFileSync as o,promises as i,writeFileSync as n}from"fs";import s,{join as a,posix as c}from"path";import{HttpsProxyAgent as l}from"https-proxy-agent";import p from"prompts";import u from"dotenv";import{z as h}from"zod";import{fileURLToPath as d}from"url";import m from"http";import g from"https";import{Pool as f}from"tarn";import{v4 as v}from"uuid";import b from"puppeteer";import{JSDOM as y}from"jsdom";import w from"dompurify";import E from"cors";import T from"express";import S from"multer";import _ from"express-rate-limit";import R from"jsonwebtoken";import k from"ws";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"]},x={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."},browserShellMode:{value:!0,type:"boolean",envLink:"OTHER_BROWSER_SHELL_MODE",description:"Decides if the browser runs in the shell mode."}},debug:{enable:{value:!1,type:"boolean",envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"Enables or disables debug mode for the underlying browser."},headless:{value:!0,type:"boolean",envLink:"DEBUG_HEADLESS",description:"Controls the mode in which the browser is launched when in the debug mode."},devtools:{value:!1,type:"boolean",envLink:"DEBUG_DEVTOOLS",description:"Decides whether to enable DevTools when the browser is in a headful state."},listenToConsole:{value:!1,type:"boolean",envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"Decides whether to enable a listener for console messages sent from the browser."},dumpio:{value:!1,type:"boolean",envLink:"DEBUG_DUMPIO",description:"Redirects browser process stdout and stderr to process.stdout and process.stderr."},slowMo:{value:0,type:"number",envLink:"DEBUG_SLOW_MO",description:"Slows down Puppeteer operations by the specified number of milliseconds."},debuggingPort:{value:9222,type:"number",envLink:"DEBUG_DEBUGGING_PORT",description:"Specifies the debugging port."}},webSocket:{enable:{value:!1,type:"boolean",envLink:"WEB_SOCKET_ENABLE",cliName:"enableWs",description:"Enables or disables the WebSocket connection."},reconnect:{value:!1,type:"boolean",envLink:"WEB_SOCKET_RECONNECT",cliName:"wsReconnect",description:"Controls whether or not to try reconnecting to the WebSocket server in case of a disconnect."},rejectUnauthorized:{value:!1,type:"boolean",envLink:"WEB_SOCKET_REJECT_UNAUTHORIZED",cliName:"wsrejectUnauthorized",description:"Determines whether the client verifies the server's SSL/TLS certificate during the handshake process."},pingTimeout:{value:16e3,type:"number",envLink:"WEB_SOCKET_PING_TIMEOUT",cliName:"wsPingTimeout",description:"The timeout, in milliseconds, for the heartbeat mechanism between the client and server."},reconnectInterval:{value:3e3,type:"number",envLink:"WEB_SOCKET_RECONNECT_INTERVAL",cliName:"wsReconnectInterval",description:"The interval, in milliseconds, for the reconnect attempt."},reconnectAttempts:{value:3,type:"number",envLink:"WEB_SOCKET_RECONNECT_ATTEMPTS",cliName:"wsReconnectAttempts",description:"The number of reconnect attempts before returning a connection error."},messageInterval:{value:3,type:"number",envLink:"WEB_SOCKET_MESSAGE_INTERVAL",cliName:"wsMessageInterval",description:"The interval, in milliseconds, for auto sending the data through a WebSocket connection."},url:{value:!1,type:"string",envLink:"WEB_SOCKET_URL",cliName:"wsUrl",description:"The URL of the WebSocket server."},secret:{value:!1,type:"string",envLink:"WEB_SOCKET_SECRET",cliName:"wsSecret",description:"The secret used to create a JSON Web Token sent to the WebSocket server."}}},L={puppeteer:[{type:"list",name:"args",message:"Puppeteer arguments",initial:x.puppeteer.args.value.join(","),separator:","}],highcharts:[{type:"text",name:"version",message:"Highcharts version",initial:x.highcharts.version.value},{type:"text",name:"cdnURL",message:"The URL of CDN",initial:x.highcharts.cdnURL.value},{type:"multiselect",name:"coreScripts",message:"Available core scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:x.highcharts.coreScripts.value},{type:"multiselect",name:"moduleScripts",message:"Available module scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:x.highcharts.moduleScripts.value},{type:"multiselect",name:"indicatorScripts",message:"Available indicator scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:x.highcharts.indicatorScripts.value},{type:"list",name:"customScripts",message:"Custom scripts",initial:x.highcharts.customScripts.value.join(","),separator:","},{type:"toggle",name:"forceFetch",message:"Force re-fetch the scripts",initial:x.highcharts.forceFetch.value},{type:"text",name:"cachePath",message:"The path to the cache directory",initial:x.highcharts.cachePath.value}],export:[{type:"select",name:"type",message:"The default export file type",hint:`Default: ${x.export.type.value}`,initial:0,choices:["png","jpeg","pdf","svg"]},{type:"select",name:"constr",message:"The default constructor for Highcharts",hint:`Default: ${x.export.constr.value}`,initial:0,choices:["chart","stockChart","mapChart","ganttChart"]},{type:"number",name:"defaultHeight",message:"The default fallback height of the exported chart",initial:x.export.defaultHeight.value},{type:"number",name:"defaultWidth",message:"The default fallback width of the exported chart",initial:x.export.defaultWidth.value},{type:"number",name:"defaultScale",message:"The default fallback scale of the exported chart",initial:x.export.defaultScale.value,min:.1,max:5},{type:"number",name:"rasterizationTimeout",message:"The rendering webpage timeout in milliseconds",initial:x.export.rasterizationTimeout.value}],customLogic:[{type:"toggle",name:"allowCodeExecution",message:"Enable execution of custom code",initial:x.customLogic.allowCodeExecution.value},{type:"toggle",name:"allowFileResources",message:"Enable file resources",initial:x.customLogic.allowFileResources.value}],server:[{type:"toggle",name:"enable",message:"Starts the server on 0.0.0.0",initial:x.server.enable.value},{type:"text",name:"host",message:"Server hostname",initial:x.server.host.value},{type:"number",name:"port",message:"Server port",initial:x.server.port.value},{type:"toggle",name:"benchmarking",message:"Enable server benchmarking",initial:x.server.benchmarking.value},{type:"text",name:"proxy.host",message:"The host of the proxy server to use",initial:x.server.proxy.host.value},{type:"number",name:"proxy.port",message:"The port of the proxy server to use",initial:x.server.proxy.port.value},{type:"number",name:"proxy.timeout",message:"The timeout for the proxy server to use",initial:x.server.proxy.timeout.value},{type:"toggle",name:"rateLimiting.enable",message:"Enable rate limiting",initial:x.server.rateLimiting.enable.value},{type:"number",name:"rateLimiting.maxRequests",message:"The maximum requests allowed per minute",initial:x.server.rateLimiting.maxRequests.value},{type:"number",name:"rateLimiting.window",message:"The rate-limiting time window in minutes",initial:x.server.rateLimiting.window.value},{type:"number",name:"rateLimiting.delay",message:"The delay for each successive request before reaching the maximum",initial:x.server.rateLimiting.delay.value},{type:"toggle",name:"rateLimiting.trustProxy",message:"Set to true if behind a load balancer",initial:x.server.rateLimiting.trustProxy.value},{type:"text",name:"rateLimiting.skipKey",message:"Allows bypassing the rate limiter when provided with the skipToken argument",initial:x.server.rateLimiting.skipKey.value},{type:"text",name:"rateLimiting.skipToken",message:"Allows bypassing the rate limiter when provided with the skipKey argument",initial:x.server.rateLimiting.skipToken.value},{type:"toggle",name:"ssl.enable",message:"Enable SSL protocol",initial:x.server.ssl.enable.value},{type:"toggle",name:"ssl.force",message:"Force serving only over HTTPS",initial:x.server.ssl.force.value},{type:"number",name:"ssl.port",message:"SSL server port",initial:x.server.ssl.port.value},{type:"text",name:"ssl.certPath",message:"The path to find the SSL certificate/key",initial:x.server.ssl.certPath.value}],pool:[{type:"number",name:"minWorkers",message:"The initial number of workers to spawn",initial:x.pool.minWorkers.value},{type:"number",name:"maxWorkers",message:"The maximum number of workers to spawn",initial:x.pool.maxWorkers.value},{type:"number",name:"workLimit",message:"The pieces of work that can be performed before restarting a Puppeteer process",initial:x.pool.workLimit.value},{type:"number",name:"acquireTimeout",message:"The number of milliseconds to wait for acquiring a resource",initial:x.pool.acquireTimeout.value},{type:"number",name:"createTimeout",message:"The number of milliseconds to wait for creating a resource",initial:x.pool.createTimeout.value},{type:"number",name:"destroyTimeout",message:"The number of milliseconds to wait for destroying a resource",initial:x.pool.destroyTimeout.value},{type:"number",name:"idleTimeout",message:"The number of milliseconds after an idle resource is destroyed",initial:x.pool.idleTimeout.value},{type:"number",name:"createRetryInterval",message:"The retry interval in milliseconds after a create process fails",initial:x.pool.createRetryInterval.value},{type:"number",name:"reaperInterval",message:"The reaper interval in milliseconds after triggering the check for idle resources to destroy",initial:x.pool.reaperInterval.value},{type:"toggle",name:"benchmarking",message:"Enable benchmarking for a resource pool",initial:x.pool.benchmarking.value}],logging:[{type:"number",name:"level",message:"The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)",initial:x.logging.level.value,round:0,min:0,max:5},{type:"text",name:"file",message:"A log file name. Set with the --logDest to enable file logging",initial:x.logging.file.value},{type:"text",name:"dest",message:"The path to log files. Enables file logging",initial:x.logging.dest.value}],ui:[{type:"toggle",name:"enable",message:"Enable UI for the export server",initial:x.ui.enable.value},{type:"text",name:"route",message:"A route to attach the UI",initial:x.ui.route.value}],other:[{type:"text",name:"nodeEnv",message:"The type of Node.js environment",initial:x.other.nodeEnv.value},{type:"toggle",name:"listenToProcessExits",message:"Set to false to skip attaching process.exit handlers",initial:x.other.listenToProcessExits.value},{type:"toggle",name:"noLogo",message:"Skip printing the logo on startup. Replaced by simple text",initial:x.other.noLogo.value},{type:"toggle",name:"hardResetPage",message:"Decides if the page content should be reset entirely",initial:x.other.hardResetPage.value},{type:"toggle",name:"browserShellMode",message:"Decides if the browser runs in the shell mode",initial:x.other.browserShellMode.value}],debug:[{type:"toggle",name:"enable",message:"Enables debug mode for the browser instance",initial:x.debug.enable.value},{type:"toggle",name:"headless",message:"The mode setting for the browser",initial:x.debug.headless.value},{type:"toggle",name:"devtools",message:"The DevTools for the headful browser",initial:x.debug.devtools.value},{type:"toggle",name:"listenToConsole",message:"The event listener for console messages from the browser",initial:x.debug.listenToConsole.value},{type:"toggle",name:"dumpio",message:"Redirects the browser stdout and stderr to NodeJS process",initial:x.debug.dumpio.value},{type:"number",name:"slowMo",message:"Puppeteer operations slow down in milliseconds",initial:x.debug.slowMo.value},{type:"number",name:"debuggingPort",message:"The port number for debugging",initial:x.debug.debuggingPort.value}],webSocket:[{type:"toggle",name:"enable",message:"Enables WebSocket connection",initial:x.webSocket.enable.value},{type:"toggle",name:"reconnect",message:"The reconnect mechanism for WebSocket connection",initial:x.webSocket.reconnect.value},{type:"toggle",name:"rejectUnauthorized",message:"Reject connection if WebSocket is not secured, SSL/TLS",initial:x.webSocket.rejectUnauthorized.value},{type:"number",name:"pingTimeout",message:"Timeout for the hearbeat mechanism",initial:x.webSocket.pingTimeout.value},{type:"number",name:"reconnectInterval",message:"Interval for the reconnect mechanism",initial:x.webSocket.reconnectInterval.value},{type:"number",name:"reconnectAttempts",message:"The number of reconnect attempts",initial:x.webSocket.reconnectAttempts.value},{type:"number",name:"messageInterval",message:"Interval for auto sending the data",initial:x.webSocket.messageInterval.value},{type:"text",name:"url",message:"The URL of the WebSocket server",initial:x.webSocket.url.value},{type:"text",name:"secret",message:"The secret for the JWT to WebSocket server",initial:x.webSocket.secret.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(x),u.config();const A=e=>h.string().transform((t=>t.split(",").map((e=>e.trim())).filter((t=>e.includes(t))))).transform((e=>e.length?e:void 0)),P=()=>h.enum(["true","false",""]).transform((e=>""!==e?"true"===e:void 0)),$=e=>h.enum([...e,""]).transform((e=>""!==e?e:void 0)),H=()=>h.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=()=>h.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)),W=()=>h.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=h.object({HIGHCHARTS_VERSION:h.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:h.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:H(),HIGHCHARTS_ADMIN_TOKEN:H(),EXPORT_TYPE:$(["jpeg","png","pdf","svg"]),EXPORT_CONSTR:$(["chart","stockChart","mapChart","ganttChart"]),EXPORT_DEFAULT_HEIGHT:U(),EXPORT_DEFAULT_WIDTH:U(),EXPORT_DEFAULT_SCALE:U(),EXPORT_RASTERIZATION_TIMEOUT:W(),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:P(),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:P(),SERVER_ENABLE:P(),SERVER_HOST:H(),SERVER_PORT:U(),SERVER_BENCHMARKING:P(),SERVER_PROXY_HOST:H(),SERVER_PROXY_PORT:U(),SERVER_PROXY_TIMEOUT:W(),SERVER_RATE_LIMITING_ENABLE:P(),SERVER_RATE_LIMITING_MAX_REQUESTS:W(),SERVER_RATE_LIMITING_WINDOW:W(),SERVER_RATE_LIMITING_DELAY:W(),SERVER_RATE_LIMITING_TRUST_PROXY:P(),SERVER_RATE_LIMITING_SKIP_KEY:H(),SERVER_RATE_LIMITING_SKIP_TOKEN:H(),SERVER_SSL_ENABLE:P(),SERVER_SSL_FORCE:P(),SERVER_SSL_PORT:U(),SERVER_SSL_CERT_PATH:H(),POOL_MIN_WORKERS:W(),POOL_MAX_WORKERS:W(),POOL_WORK_LIMIT:U(),POOL_ACQUIRE_TIMEOUT:W(),POOL_CREATE_TIMEOUT:W(),POOL_DESTROY_TIMEOUT:W(),POOL_IDLE_TIMEOUT:W(),POOL_CREATE_RETRY_INTERVAL:W(),POOL_REAPER_INTERVAL:W(),POOL_BENCHMARKING:P(),LOGGING_LEVEL:h.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:H(),LOGGING_DEST:H(),UI_ENABLE:P(),UI_ROUTE:H(),OTHER_NODE_ENV:$(["development","production","test"]),OTHER_LISTEN_TO_PROCESS_EXITS:P(),OTHER_NO_LOGO:P(),OTHER_HARD_RESET_PAGE:P(),OTHER_BROWSER_SHELL_MODE:P(),DEBUG_ENABLE:P(),DEBUG_HEADLESS:P(),DEBUG_DEVTOOLS:P(),DEBUG_LISTEN_TO_CONSOLE:P(),DEBUG_DUMPIO:P(),DEBUG_SLOW_MO:W(),DEBUG_DEBUGGING_PORT:U(),WEB_SOCKET_ENABLE:P(),WEB_SOCKET_RECONNECT:P(),WEB_SOCKET_REJECT_UNAUTHORIZED:P(),WEB_SOCKET_PING_TIMEOUT:W(),WEB_SOCKET_RECONNECT_INTERVAL:W(),WEB_SOCKET_RECONNECT_ATTEMPTS:W(),WEB_SOCKET_MESSAGE_INTERVAL:W(),WEB_SOCKET_URL:H(),WEB_SOCKET_SECRET:H()}).partial().parse(process.env),G=["red","yellow","blue","gray","green"];let j={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:G[0]},{title:"warning",color:G[1]},{title:"notice",color:G[2]},{title:"verbose",color:G[3]},{title:"benchmark",color:G[4]}],listeners:[]};for(const[e,t]of Object.entries(x.logging))j[e]=t.value;const M=(o,i)=>{j.toFile&&(j.pathCreated||(!e(j.dest)&&t(j.dest),j.pathCreated=!0),r(`${j.dest}${j.file}`,[i].concat(o).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),j.toFile=!1)})))},F=(...e)=>{const[t,...r]=e,{level:o,levelsDesc:i}=j;if(5!==t&&(0===t||t>o||o>i.length))return;const n=`${(new Date).toString().split("(")[0].trim()} [${i[t-1].title}] -`;j.listeners.forEach((e=>{e(n,r.join(" "))})),j.toConsole&&console.log.apply(void 0,[n.toString()[j.levelsDesc[t-1].color]].concat(r)),M(r,n)},V=(e,t,r)=>{const o=r||t.message,{level:i,levelsDesc:n}=j;if(0===e||e>i||i>n.length)return;const s=`${(new Date).toString().split("(")[0].trim()} [${n[e-1].title}] -`,a=t.message!==t.stackMessage||void 0===t.stackMessage?t.stack:t.stack.split("\n").slice(1).join("\n"),c=[o,"\n",a];j.toConsole&&console.log.apply(void 0,[s.toString()[j.levelsDesc[e-1].color]].concat([o[G[e-1]],"\n",a])),j.listeners.forEach((e=>{e(s,c.join(" "))})),M(c,s)},q=e=>{e>=0&&e<=j.levelsDesc.length&&(j.level=e)},B=(e,t)=>{if(j={...j,dest:e||j.dest,file:t||j.file,toFile:!0},0===j.dest.length)return F(1,"[logger] File logging initialization: no path supplied.");j.dest.endsWith("/")||(j.dest+="/")},K=d(new URL("../.",import.meta.url)),X=(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"},z=(e=!1,t)=>{const r=["js","css","files"];let i=e,n=!1;if(t&&e.endsWith(".json"))try{i=J(o(e,"utf8"))}catch(e){return V(2,e,"[cli] No resources found.")}else i=J(e),i&&!t&&delete i.files;for(const e in i)r.includes(e)?n||(n=!0):delete i[e];return n?(i.files&&(i.files=i.files.map((e=>e.trim())),(!i.files||i.files.length<=0)&&delete i.files),i):F(3,"[cli] No resources found.")};function J(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},Z=(e,t)=>JSON.stringify(e,((e,r)=>("string"==typeof r&&((r=r.trim()).startsWith("function(")||r.startsWith("function ("))&&r.endsWith("}")&&(r=t?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:void 0),"function"==typeof r?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:r))).replaceAll(/"EXP_FUN|EXP_FUN"/g,"");function Q(){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(x).forEach((t=>{["puppeteer","highcharts"].includes(t)||(console.log(`\n${t.toUpperCase()}`.red),e(x[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(o(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,ne=(e,t,r=[])=>{const o=Y(e);for(const[e,n]of Object.entries(t))o[e]="object"!=typeof(i=n)||Array.isArray(i)||null===i||r.includes(e)||void 0===o[e]?void 0!==n?n:o[e]:ne(o[e],n,r);var i;return o};function se(e,t={},r=""){Object.keys(e).forEach((o=>{const i=e[o],n=t&&t[o];void 0===i.value?se(i,n,`${r}.${o}`):(void 0!==n&&(i.value=n),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 ce(e,t,r){for(;t.length>1;){const o=t.shift();return Object.prototype.hasOwnProperty.call(e,o)||(e[o]={}),e[o]=ce(Object.assign({},e[o]),t,r),e}return e[t[0]]=r,e}async function le(e,t={}){return new Promise(((r,o)=>{const i=(e=>e.startsWith("https")?g:m)(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 ue={cdnURL:"https://code.highcharts.com/",activeManifest:{},sources:"",hcVersion:""},he=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)),F(4,`[cache] Fetching script - ${e}.js`);const i=await le(`${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 F(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`),""},me=async(e,t,r)=>{const o=e.version,i="latest"!==o&&o?`${o}/`:"",s=e.cdnURL||ue.cdnURL;F(3,`[cache] Updating cache version to Highcharts: ${i||"latest"}.`);const a={};try{return ue.sources=await(async(e,t,r,o,i)=>{let n;const s=o.host,a=o.port;if(s&&a)try{n=new l({host:s,port:a})}catch(e){throw new pe("[cache] Could not create a Proxy Agent.").setError(e)}const c=n?{agent:n,timeout:D.SERVER_PROXY_TIMEOUT}:{},p=[...e.map((e=>de(`${e}`,c,i,!0))),...t.map((e=>de(`${e}`,c,i))),...r.map((e=>de(`${e}`,c)))];return(await Promise.all(p)).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),ue.hcVersion=he(ue),n(r,ue.sources),a}catch(e){throw new pe("[cache] Unable to update the local Highcharts cache.").setError(e)}},ge=async r=>{const{highcharts:i,server:s}=r,c=a(K,i.cachePath);let l;const p=a(c,"manifest.json"),u=a(c,"sources.js");if(!e(c)&&t(c),!e(p)||i.forceFetch)F(3,"[cache] Fetching and caching Highcharts dependencies."),l=await me(i,s.proxy,u);else{let e=!1;const t=JSON.parse(o(p));if(t.modules&&Array.isArray(t.modules)){const e={};t.modules.forEach((t=>e[t]=1)),t.modules=e}const{coreScripts:r,moduleScripts:n,indicatorScripts:a}=i,c=r.length+n.length+a.length;t.version!==i.version?(F(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),e=!0):Object.keys(t.modules||{}).length!==c?(F(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 F(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),e?l=await me(i,s.proxy,u):(F(3,"[cache] Dependency cache is up to date, proceeding."),ue.sources=o(u,"utf8"),l=t.modules,ue.hcVersion=he(ue))}await(async(e,t)=>{const r={version:e.version,modules:t||{}};ue.activeManifest=r,F(3,"[cache] Writing a new manifest.");try{n(a(K,e.cachePath,"manifest.json"),JSON.stringify(r),"utf8")}catch(e){throw new pe("[cache] Error writing the cache manifest.").setError(e)}})(i,l)},fe=()=>a(K,ie().highcharts.cachePath),ve=()=>ue.hcVersion;function be(){Highcharts.animObject=function(){return{duration:0}}}async function ye(e,t,r){window._displayErrors=r;const{getOptions:o,merge:i,setOptions:n,wrap:s}=Highcharts;Highcharts.setOptionsObj=i(!1,{},o()),t.customLogic.customCode&&new Function(t.customLogic.customCode)();const a={animation:!1};t.export.strInj&&(a.height=e.chart.height,a.width=e.chart.width),window.isRenderComplete=!1,s(Highcharts.Chart.prototype,"init",(function(e,t,r){((t=i(t,{exporting:{enabled:!1},plotOptions:{series:{label:{enabled:!1}}},tooltip:{}})).series||[]).forEach((function(e){e.animation=!1})),window.onHighchartsRender||(window.onHighchartsRender=Highcharts.addEvent(this,"render",(()=>{window.isRenderComplete=!0}))),e.apply(this,[t,r])})),s(Highcharts.Series.prototype,"init",(function(e,t,r){e.apply(this,[t,r])}));const c=t.export.strInj?new Function(`return ${t.export.strInj}`)():e,l=i(!1,JSON.parse(t.export.themeOptions),c,{chart:a}),p=t.customLogic.callback?new Function(`return ${t.customLogic.callback}`)():void 0,u=JSON.parse(t.export.globalOptions);u&&n(u),Highcharts[t.export.constr||"chart"]("container",l,p);const h=o();for(const e in h)"function"!=typeof h[e]&&delete h[e];n(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const we=o(K+"/templates/template.html","utf8");let Ee;async function Te(){if(!Ee)return!1;const e=await Ee.newPage();return await e.setCacheEnabled(!1),await _e(e),function(e){const{debug:t}=ie();t.enable&&t.listenToConsole&&e.on("console",(e=>{console.log(`[debug] ${e.text()}`)}));e.on("pageerror",(async t=>{await e.$eval("#container",((e,t)=>{window._displayErrors&&(e.innerHTML=t)}),`

Chart input data error:

${t.toString()}`)}))}(e),e}async function Se(e,t){for(const e of t)await e.dispose();await e.evaluate((()=>{if("undefined"!=typeof Highcharts){const e=Highcharts.charts;if(Array.isArray(e)&&e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()}const[...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...r]=document.getElementsByTagName("link");for(const o of[...e,...t,...r])o.remove()}))}async function _e(e){await e.setContent(we,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:`${fe()}/sources.js`}),await e.evaluate(be)}const Re=async(e,t,r,o)=>e.evaluate(ye,t,r,o);var ke=async(e,t,r)=>{let i=[];try{F(4,"[export] Determining export path.");const n=r.export,a=n?.options?.chart?.displayErrors&&ue.activeManifest.modules.debugger;let c;if(t.indexOf&&(t.indexOf("=0||t.indexOf("=0)){if(F(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 F(4,"[export] Treating as config."),n.strInj?await Re(e,{chart:{height:n.height,width:n.width}},r,a):(t.chart.height=n.height,t.chart.width=n.width,await Re(e,t,r,a));i=await async function(e,t){const r=[],i=t.customLogic.resources;if(i){const n=[];if(i.js&&n.push({content:i.js}),i.files)for(const e of i.files){const t=!e.startsWith("http");n.push(t?{content:o(e,"utf8")}:{url:e})}for(const t of n)try{r.push(await e.addScriptTag(t))}catch(e){V(2,e,"[export] The JS resource cannot be loaded.")}n.length=0;const a=[];if(i.css){let o=i.css.match(/@import\s*([^;]*);/g);if(o)for(let e of o)e&&(e=e.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),e.startsWith("http")?a.push({url:e}):t.customLogic.allowFileResources&&a.push({path:s.join(K,e)}));a.push({content:i.css.replace(/@import\s*([^;]*);/g,"")||" "});for(const t of a)try{r.push(await e.addStyleTag(t))}catch(e){V(2,e,"[export] The CSS resource cannot be loaded.")}a.length=0}}return r}(e,r);const l=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}})),p=Math.ceil(l.chartHeight||n.height),u=Math.ceil(l.chartWidth||n.width),{x:h,y:d}=await(e=>e.$eval("#chart-container",(e=>{const{x:t,y:r,width:o,height:i}=e.getBoundingClientRect();return{x:t,y:r,width:o,height:Math.trunc(i>1?i:500)}})))(e);let m;if(await e.setViewport({height:p,width:u,deviceScaleFactor:c?1:parseFloat(n.scale)}),"svg"===n.type)m=await(e=>e.$eval("#container svg:first-of-type",(e=>e.outerHTML)))(e);else if(["png","jpeg"].includes(n.type))m=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:u,height:p,x:h,y:d},n.rasterizationTimeout);else{if("pdf"!==n.type)throw new pe(`[export] Unsupported output format ${n.type}.`);m=await(async(e,t,r,o,i)=>(await e.emulateMediaType("screen"),Promise.race([e.pdf({height:t+1,width:r,encoding:o}),new Promise(((e,t)=>setTimeout((()=>t(new pe("Rasterization timeout"))),i||1500)))])))(e,p,u,"base64",n.rasterizationTimeout)}return await Se(e,i),m}catch(t){return await Se(e,i),t}};let Oe=!1;const xe={performedExports:0,exportAttempts:0,exportFromSvgAttempts:0,timeSpent:0,droppedExports:0,spentAverage:0};let Le={};const Ie={create:async()=>{let e=!1;const t=v(),r=(new Date).getTime();try{if(e=await Te(),!e||e.isClosed())throw new pe("The page is invalid or closed.");F(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)}return{id:t,page:e,workCount:Math.round(Math.random()*(Le.workLimit/2))}},validate:async e=>!(Le.workLimit&&++e.workCount>Le.workLimit)||(F(3,`[pool] Worker failed validation: exceeded work limit (limit is ${Le.workLimit}).`),!1),destroy:async e=>{F(3,`[pool] Destroying pool entry ${e.id}.`),e.page&&await e.page.close()}},Ce=async e=>{if(Le=e&&e.pool?{...e.pool}:{},await async function(e){const{debug:t,other:r}=ie(),{enable:o,...i}=t,n={headless:!r.browserShellMode||"shell",userDataDir:"./tmp/",args:e,handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...o&&i};if(!Ee){let e=0;const t=async()=>{try{F(3,`[browser] Attempting to get a browser instance (try ${++e}).`),Ee=await b.launch(n)}catch(r){if(V(1,r,"[browser] Failed to launch a browser instance."),!(e<25))throw r;F(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await t()}};try{await t(),"shell"===n.headless&&F(3,"[browser] Launched browser in shell mode."),o&&F(3,"[browser] Launched browser in debug mode.")}catch(e){throw new pe("[browser] Maximum retries to open a browser instance reached.").setError(e)}if(!Ee)throw new pe("[browser] Cannot find a browser to open.")}return Ee}(e.puppeteerArgs),F(3,`[pool] Initializing pool with workers: min ${Le.minWorkers}, max ${Le.maxWorkers}.`),Oe)return F(4,"[pool] Already initialized, please kill it before creating a new one.");parseInt(Le.minWorkers)>parseInt(Le.maxWorkers)&&(Le.minWorkers=Le.maxWorkers);try{Oe=new f({...Ie,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}),Oe.on("release",(async e=>{await async function(e,t=!1){try{e.isClosed()||(t?(await e.goto("about:blank",{waitUntil:"domcontentloaded"}),await _e(e)):await e.evaluate((()=>{document.body.innerHTML='
'})))}catch(e){V(2,e,"[browser] Could not clear the content of the page.")}}(e.page,!1),F(4,`[pool] Releasing a worker with ID ${e.id}.`)})),Oe.on("destroySuccess",((e,t)=>{F(4,`[pool] Destroyed a worker with ID ${t.id}.`)}));const e=[];for(let t=0;t{Oe.release(e)})),F(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 Ne(){if(F(3,"[pool] Killing pool with all workers and closing browser."),Oe){for(const e of Oe.used)Oe.release(e.resource);Oe.destroyed||(await Oe.destroy(),F(4,"[browser] Destroyed the pool of resources."))}await async function(){Ee?.connected&&await Ee.close(),F(4,"[browser] Closed the browser.")}()}const Ae=async(e,t)=>{let r;try{if(F(4,"[pool] Work received, starting to process."),++xe.exportAttempts,Le.benchmarking&&function(){const{min:e,max:t,all:r,available:o,used:i,pending:n}=Pe();F(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),F(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),F(5,`[pool] The number of all created resources: ${r}.`),F(5,`[pool] The number of available resources: ${o}.`),F(5,`[pool] The number of acquired resources: ${i}.`),F(5,`[pool] The number of resources waiting to be acquired: ${n}.`)}(),!Oe)throw new pe("Work received, but pool has not been started.");const o=re();try{F(4,"[pool] Acquiring a worker handle."),r=await Oe.acquire().promise,t.server.benchmarking&&F(5,t.payload?.requestId?`[benchmark] Request: ${t.payload?.requestId} -`:"[benchmark]",`Acquired a worker handle: ${o()}ms.`)}catch(e){throw new pe((t.payload?.requestId?`Request: ${t.payload?.requestId} - `:"")+`Error encountered when acquiring an available entry: ${o()}ms.`).setError(e)}if(F(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();F(4,`[pool] Starting work on pool entry with ID ${r.id}.`);const n=re(),s=await ke(r.page,e,t);if(s instanceof Error)throw"Rasterization timeout"===s.message&&(r.page.close(),r.page=await Te()),new pe((t.payload?.requestId?`Request: ${t.payload?.requestId} - `:"")+`Error encountered during export: ${n()}ms.`).setError(s);t.server.benchmarking&&F(5,t.payload?.requestId?`[benchmark] Request: ${t.payload?.requestId} -`:"[benchmark]",`Exported a chart sucessfully: ${n()}ms.`),Oe.release(r);const a=(new Date).getTime()-i;return xe.timeSpent+=a,xe.spentAverage=xe.timeSpent/++xe.performedExports,F(4,`[pool] Work completed in ${a} ms.`),{result:s,options:t}}catch(e){throw++xe.droppedExports,r&&Oe.release(r),new pe(`[pool] In pool.postWork: ${e.message}`).setError(e)}},Pe=()=>({min:Oe.min,max:Oe.max,all:Oe.numFree()+Oe.numUsed(),available:Oe.numFree(),used:Oe.numUsed(),pending:Oe.numPendingAcquires()});function $e(){return xe}let He=!1;const Ue=async(e,t)=>{F(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=ne(t,e,I),r.export.outfile=r.export?.outfile||`chart.${r.export?.type||"png"}`,r})(e,ie()),i=r.export;if(r.payload?.svg&&""!==r.payload.svg)try{F(4,"[chart] Attempting to export from a SVG input.");const e=je(function(e){const t=new y("").window;return w(t).sanitize(e,{ADD_TAGS:["foreignObject"]})}(r.payload.svg),r,t);return++xe.exportFromSvgAttempts,e}catch(e){return t(new pe("[chart] Error loading SVG input.").setError(e))}if(i.infile&&i.infile.length)try{return F(4,"[chart] Attempting to export from an input file."),r.export.instr=o(i.infile,"utf8"),je(r.export.instr.trim(),r,t)}catch(e){return t(new pe("[chart] Error loading input file.").setError(e))}if(i.instr&&""!==i.instr||i.options&&""!==i.options)try{return F(4,"[chart] Attempting to export from a raw input."),ee(r.customLogic?.allowCodeExecution)?Ge(r,t):"string"==typeof i.instr?je(i.instr.trim(),r,t):De(r,i.instr||i.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||J(e.export?.instr),o=J(e.export?.globalOptions);let i=e.export?.scale||r?.scale||o?.exporting?.scale||e.export?.defaultScale||1;i=Math.max(.1,Math.min(i,5)),i=((e,t=1)=>{const r=Math.pow(10,t||0);return Math.round(+e*r)/r})(i,2);const n={height:e.export?.height||r?.sourceHeight||t?.height||o?.exporting?.sourceHeight||o?.chart?.height||e.export?.defaultHeight||400,width:e.export?.width||r?.sourceWidth||t?.width||o?.exporting?.sourceWidth||o?.chart?.width||e.export?.defaultWidth||600,scale:i};for(let[e,t]of Object.entries(n))n[e]="string"==typeof t?+t.replace(/px|%/gi,""):t;return n},De=async(e,t,r,i)=>{let{export:n,customLogic:s}=e;const a="boolean"==typeof s.allowCodeExecution?s.allowCodeExecution:He;if(s){if(a)if("string"==typeof e.customLogic.resources)e.customLogic.resources=z(e.customLogic.resources,ee(e.customLogic.allowFileResources));else if(!e.customLogic.resources)try{const t=o("resources.json","utf8");e.customLogic.resources=z(t,ee(e.customLogic.allowFileResources))}catch(e){V(2,e,"[chart] Unable to load the default resources.json file.")}}else s=e.customLogic={};if(!a&&s){if(s.callback||s.resources||s.customCode)return r(new pe("[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server."));s.callback=!1,s.resources=!1,s.customCode=!1}if(t&&(t.chart=t.chart||{},t.exporting=t.exporting||{},t.exporting.enabled=!1),n.constr=n.constr||"chart",n.type=X(n.type,n.outfile),"svg"===n.type&&(n.width=!1),["globalOptions","themeOptions"].forEach((e=>{try{n&&n[e]&&("string"==typeof n[e]&&n[e].endsWith(".json")?n[e]=J(o(n[e],"utf8"),!0):n[e]=J(n[e],!0))}catch(t){n[e]={},V(2,t,`[chart] The '${e}' cannot be loaded.`)}})),s.allowCodeExecution)try{s.customCode=te(s.customCode,s.allowFileResources)}catch(e){V(2,e,"[chart] The 'customCode' cannot be loaded.")}if(s&&s.callback&&s.callback?.indexOf("{")<0)if(s.allowFileResources)try{s.callback=o(s.callback,"utf8")}catch(e){s.callback=!1,V(2,e,"[chart] The 'callback' cannot be loaded.")}else s.callback=!1;e.export={...e.export,...We(e)};try{return r(!1,await Ae(n.strInj||t||i,e))}catch(e){return r(e)}},Ge=(e,t)=>{try{let r,o=e.export.instr||e.export.options;return"string"!=typeof o&&(r=o=Z(o,e.customLogic?.allowCodeExecution)),r=o.replaceAll(/\t|\n|\r/g,"").trim(),";"===r[r.length-1]&&(r=r.substring(0,r.length-1)),e.export.strInj=r,De(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))}},je=(e,t,r)=>{const{allowCodeExecution:o}=t.customLogic;if(e.indexOf("=0||e.indexOf("=0)return F(4,"[chart] Parsing input as SVG."),De(t,!1,r,e);try{const o=JSON.parse(e.replaceAll(/\t|\n|\r/g," "));return De(t,o,r)}catch(e){return ee(o)?Ge(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))}},Me=[],Fe=e=>{Me.push(e)},Ve=()=>{F(4,"[server] Clearing all registered intervals and timeouts.");for(const e of Me)clearInterval(e),clearTimeout(e)},qe=(e,t,r,o)=>{V(1,e),"development"!==D.OTHER_NODE_ENV&&delete e.stack,o(e)},Be=(e,t,r,o)=>{const{statusCode:i,status:n,message:s,stack:a}=e,c=i||n||500;r.status(c).json({statusCode:c,message:s,stack:a})};var Ke=(e,t)=>{const r="Too many requests, you have been rate limited. Please try again later.",o={max:t.maxRequests||30,window:t.window||1,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||!1,skipToken:t.skipToken||!1};o.trustProxy&&e.enable("trust proxy");const i=_({windowMs:60*o.window*1e3,max:o.max,delayMs:o.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:r})},default:()=>{t.status(429).send(r)}})},skip:e=>!1!==o.skipKey&&!1!==o.skipToken&&e.query.key===o.skipKey&&e.query.access_token===o.skipToken&&(F(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(i),F(3,`[rate limiting] Enabled rate limiting with ${o.max} requests per ${o.window} minute for each IP, trusting proxy: ${o.trustProxy}.`)};const Xe=JSON.parse(o(a(K,"lib","schemas","telemetry.json"))),ze={numberOfRequests:0},Je=["series","xAxis","yAxis","zAxis"];function Ye(e,t){const r={};for(const[o,i]of Object.entries(e))if(void 0!==t[o])if(null!==i)if(Array.isArray(t[o]))if(Je.includes(o)){r[o]=[];for(const[e,n]of t[o].entries())r[o][e]=Ye(i,n)}else r[o]=Ye(i,t[o][0]);else r[o]=Ye(i,t[o]);else r[o]=t[o];return r}function Ze(e,t){ze[t]=Ye(Xe,e),ze.numberOfRequests++}const Qe=new Map;let et,tt=null;function rt(e){if(et=ie().webSocket,!0===et.enable){const t={rejectUnauthorized:et.rejectUnauthorized,headers:{auth:R.sign({success:"success"},et.secret,{algorithm:"HS256"}),"X-Server-Address":`${e.protocol}://${["::","0.0.0.0"].includes(e.address)?"localhost":e.address}:${e.port}`}},r={id:v(),reconnect:et.reconnect,reconnectTry:0,reconnectInterval:null,pingTimeout:null};ot(et.url,t,r),function(e){tt=setInterval((()=>{try{const t=(e?Qe.get(e):Qe.values()).next().value;t&&t.readyState===k.OPEN&&Object.keys(ze).length>1&&ze.numberOfRequests>0&&t.send(JSON.stringify(ze))}catch(e){V(1,"[websocket] Could not send data through WebSocket.")}var e}),e.messageInterval),Fe(tt)}(et)}}function ot(e,t,r){let o=new k(e,t);o.on("open",(()=>{clearInterval(r.reconnectInterval),Qe.set(r.id,o),F(3,`[websocket] WebSocket: ${r.id} - Connected to server: ${e}.`)})),o.on("close",(i=>{F(3,"[websocket]",`WebSocket: ${r.id} - Disconnected from server: ${e} with code: ${i}.`),clearTimeout(r.pingTimeout),Qe.delete(r.id),o=null,r.reconnect&&!r.reconnectInterval&&it(e,t,r)})),o.on("error",(e=>{V(1,e,`[websocket] WebSocket: ${r.id} - Error occured.`),e.message.includes("403")?(r.reconnect=!1,r.reconnectTry=et.reconnectAttempts):r.reconnect=et.reconnect})),o.on("message",(e=>{F(3,`[websocket] WebSocket: ${r.id} - Data received: ${e}`)})),o.on("ping",(()=>{F(3,`[websocket] WebSocket: ${r.id} - Received PING from server: ${e}.`),clearTimeout(r.pingTimeout),r.pingTimeout=setTimeout((()=>{o.terminate(),r.reconnect&&it(e,t,r)}),et.pingTimeout)}))}function it(e,t,r){r.reconnectInterval=setInterval((()=>{r.reconnectTry!!e&&e.post("/version/change/:newVersion",(async(e,t,r)=>{try{const r=D.HIGHCHARTS_ADMIN_TOKEN;if(!r||!r.length)throw new st("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 st("Invalid or missing token: Set the token in the hc-auth header.",401);const i=e.params.newVersion;if(!i)throw new st("No new version supplied.",400);try{await(async e=>{const t=ie();t?.highcharts&&(t.highcharts.version=e),await ge(t)})(i)}catch(e){throw new st(`Version change: ${e.message}`,e.statusCode).setError(e)}t.status(200).send({statusCode:200,version:ve(),message:`Successfully updated Highcharts to version: ${i}.`})}catch(e){r(e)}}));const ct={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};let lt=0;const pt=[],ut=[],ht=(e,t,r,o)=>{let i=!0;const{id:n,uniqueId:s,type:a,body:c}=o;return e.some((e=>{if(e){let o=e(t,r,n,s,a,c);return void 0!==o&&!0!==o&&(i=o),!0}})),i},dt=async(e,t,r)=>{try{const r=re(),i=v().replace(/-/g,""),n=ie(),s=e.body,a=++lt;let c=X(s.type);if(!s||"object"==typeof(o=s)&&!Array.isArray(o)&&null!==o&&0===Object.keys(o).length)throw new st("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 l=J(s.infile||s.options||s.data);if(!l&&!s.svg)throw F(2,`The request with ID ${i} from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Payload received: ${JSON.stringify(s)}.`),new st("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=ht(pt,e,t,{id:a,uniqueId:i,type:c,body:s}),!0!==p)return t.send(p);let u=!1;e.socket.on("close",(()=>{u=!0})),F(4,`[export] Got an incoming HTTP request with ID ${i}.`),s.constr="string"==typeof s.constr&&s.constr||"chart";const h={export:{instr:l,type:c,constr:s.constr[0].toLowerCase()+s.constr.substr(1),height:s.height,width:s.width,scale:s.scale||n.export.scale,globalOptions:J(s.globalOptions,!0),themeOptions:J(s.themeOptions,!0)},customLogic:{allowCodeExecution:He,allowFileResources:!1,resources:J(s.resources,!0),callback:s.callback,customCode:s.customCode}};l&&(h.export.instr=Z(l,h.customLogic.allowCodeExecution));const d=ne(n,h);if(d.export.options=l,d.payload={svg:s.svg||!1,b64:s.b64||!1,noDownload:s.noDownload||!1,requestId:i},s.svg&&(e=>[/xlink:href="(?:http:\/\/|https:\/\/)?localhost\b/,/xlink:href="(?:http:\/\/|https:\/\/)?10\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?127\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?192\.168\.\d{1,3}\.\d{1,3}\b/].some((t=>t.test(e))))(d.payload.svg))throw new st("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(d,((o,l)=>{if(e.socket.removeAllListeners("close"),n.server.benchmarking&&F(5,`[benchmark] Request: ${i} - After the whole exporting process: ${r()}ms.`),u)return F(3,"[export] The client closed the connection before the chart finished processing.");if(o)throw o;if(!l||!l.result)throw new st(`Unexpected return from chart generation. Please check your request data. For the request with ID ${i}, the result is ${l.result}.`,400);return c=l.options.export.type,ht(ut,e,t,{id:a,body:l.result}),Ze(d.export.options,d.payload.requestId),l.result?s.b64?"pdf"===c||"svg"==c?t.send(Buffer.from(l.result,"utf8").toString("base64")):t.send(l.result):(t.header("Content-Type",ct[c]||"image/png"),s.noDownload||t.attachment(`${e.params.filename||e.body.filename||"chart"}.${c||"png"}`),"svg"===c?t.send(l.result):t.send(Buffer.from(l.result,"base64"))):void 0}))}catch(e){r(e)}var o};const mt=JSON.parse(o(a(K,"package.json"))),gt=new Date,ft=[];function vt(e){if(!e)return!1;Fe(setInterval((()=>{const e=$e(),t=0===e.exportAttempts?1:e.performedExports/e.exportAttempts*100;ft.push(t),ft.length>30&&ft.shift()}),6e4)),e.get("/health",((e,t)=>{const r=$e(),o=ft.length,i=ft.reduce(((e,t)=>e+t),0)/ft.length;F(4,"[health.js] GET /health [200] - returning server health."),t.send({status:"OK",bootTime:gt,uptime:Math.floor(((new Date).getTime()-gt.getTime())/1e3/60)+" minutes",version:mt.version,highchartsVersion:ve(),averageProcessingTime:r.spentAverage,performedExports:r.performedExports,failedExports:r.droppedExports,exportAttempts:r.exportAttempts,sucessRatio:r.performedExports/r.exportAttempts*100,pool:Pe(),period:o,movingAverage:i,message:`Last ${o} minutes had a success rate of ${i.toFixed(2)}%.`,svgExportAttempts:r.exportFromSvgAttempts,jsonExportAttempts:r.performedExports-r.exportFromSvgAttempts})}))}const bt=new Map,yt=T();yt.disable("x-powered-by"),yt.use(E());const wt=S.memoryStorage(),Et=S({storage:wt,limits:{fieldSize:52428800}});yt.use(T.json({limit:52428800})),yt.use(T.urlencoded({extended:!0,limit:52428800})),yt.use(Et.none());const Tt=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}`)}))}))},St=async e=>{try{if(!e.enable)return!1;if(!e.ssl.force){const t=m.createServer(yt);Tt(t),t.listen(e.port,e.host,(()=>{bt.set(e.port,t),F(3,`[server] Started HTTP server on ${e.host}:${e.port}.`),1===bt.size&&rt({...t.address(),protocol:"http"})}))}if(e.ssl.enable){let t,r;try{t=await i.readFile(c.join(e.ssl.certPath,"server.key"),"utf8"),r=await i.readFile(c.join(e.ssl.certPath,"server.crt"),"utf8")}catch(t){F(2,`[server] Unable to load key/certificate from the '${e.ssl.certPath}' path. Could not run secured layer server.`)}if(t&&r){const o=g.createServer({key:t,cert:r},yt);Tt(o),o.listen(e.ssl.port,e.host,(()=>{bt.set(e.ssl.port,o),F(3,`[server] Started HTTPS server on ${e.host}:${e.ssl.port}.`),1===bt.size&&rt({...o.address(),protocol:"https"})}))}}e.rateLimiting&&e.rateLimiting.enable&&![0,NaN].includes(e.rateLimiting.maxRequests)&&Ke(yt,e.rateLimiting),yt.use(T.static(c.join(K,"public"))),vt(yt),(e=>{e.post("/",dt),e.post("/:filename",dt)})(yt),(e=>{!!e&&e.get("/",((e,t)=>{t.sendFile(a(K,"public","index.html"))}))})(yt),at(yt),(e=>{e.use(qe),e.use(Be)})(yt)}catch(e){throw new pe("[server] Could not configure and start the server.").setError(e)}},_t=()=>{F(4,"[server] Closing all servers.");for(const[e,t]of bt)t.close((()=>{bt.delete(e),F(4,`[server] Closed server on port: ${e}.`)}))};var Rt={startServer:St,closeServers:_t,getServers:()=>bt,enableRateLimiting:e=>Ke(yt,e),getExpress:()=>T,getApp:()=>yt,use:(e,...t)=>{yt.use(e,...t)},get:(e,...t)=>{yt.get(e,...t)},post:(e,...t)=>{yt.post(e,...t)}};const kt=async e=>{await Promise.allSettled([Ve(),nt(),_t(),Ne()]),process.exit(e)};var Ot={server:Rt,startServer:St,initExport:async e=>{var t;return t=e.customLogic&&e.customLogic.allowCodeExecution,He=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&&(F(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{F(4,`Process exited with code ${e}.`)})),process.on("SIGINT",(async(e,t)=>{F(4,`The ${e} event with code: ${t}.`),await kt(0)})),process.on("SIGTERM",(async(e,t)=>{F(4,`The ${e} event with code: ${t}.`),await kt(0)})),process.on("SIGHUP",(async(e,t)=>{F(4,`The ${e} event with code: ${t}.`),await kt(0)})),process.on("uncaughtException",(async(e,t)=>{V(1,e,`The ${t} error.`),await kt(1)}))),await ge(e),await Ce({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 Ue(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 Ne()}))},batchExport:async e=>{const t=[];for(let r of e.export.batch.split(";"))r=r.split("="),2===r.length&&t.push(Ue({...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 Ne()}catch(e){throw new pe("[chart] Error encountered during batch export.").setError(e)}},startExport:Ue,initPool:Ce,killPool:Ne,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(o(r))}catch(e){V(2,e,`[config] Unable to load the configuration from the ${r} file.`)}}return{}}(t)),se(x,oe),oe=ae(x),e&&(oe=ne(oe,e,I)),t?.length&&(oe=function(e,t,r){let o=!1;for(let i=0;i(s.length-1===r&&(a=e[t].type),e[t])),r),s.reduce(((e,r,c)=>(s.length-1===c&&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]:(F(2,`[config] Missing value for the '${n}' argument. Using the default value.`),o=!0)),e[r])),e)}o&&Q();return e}(oe,t,x)),oe),shutdownCleanUp:kt,log:F,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 t=>{let r={};e(t)&&(r=JSON.parse(o(t,"utf8")));const n=Object.keys(L).map((e=>({title:`${e} options`,value:e})));return p({type:"multiselect",name:"category",message:"Which category do you want to configure?",hint:"Space: Select specific, A: Select all, Enter: Confirm.",instructions:"",choices:n},{onSubmit:async(e,o)=>{let n=0,s=[];for(const e of o)L[e]=L[e].map((t=>({...t,section:e}))),s=[...s,...L[e]];return await p(s,{onSubmit:async(e,o)=>{if("moduleScripts"===e.name?(o=o.length?o.map((t=>e.choices[t])):e.choices,r[e.section][e.name]=o):r[e.section]=ce(Object.assign({},r[e.section]||{}),e.name.split("."),e.choices?e.choices[o]:o),++n===s.length){try{await i.writeFile(t,JSON.stringify(r,null,2),"utf8")}catch(e){V(1,e,`[config] An error occurred while creating the ${t} file.`)}return!0}}}),!0}})},printLogo:e=>{const t=JSON.parse(o(a(K,"package.json"))).version;e?console.log(`Starting Highcharts Export Server v${t}...`):console.log(o(K+"/msg/startup.msg").toString().bold.yellow,`v${t}\n`.bold)},printUsage:Q};export{Ot as default}; +import"colors";import{existsSync as e,mkdirSync as t,appendFile as r,readFileSync as o,promises as i,writeFileSync as n}from"fs";import s,{join as a,posix as c}from"path";import{HttpsProxyAgent as l}from"https-proxy-agent";import p from"prompts";import u from"dotenv";import{z as h}from"zod";import{fileURLToPath as d}from"url";import m from"http";import g from"https";import{Pool as f}from"tarn";import{v4 as v}from"uuid";import b from"puppeteer";import{JSDOM as y}from"jsdom";import w from"dompurify";import E from"cors";import T from"express";import S from"multer";import _ from"express-rate-limit";import R from"jsonwebtoken";import k from"ws";const O={core:["highcharts","highcharts-more","highcharts-3d"],modules:["stock","map","gantt","exporting","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","series-on-point","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","export-data","navigator","textpath"],indicators:["indicators-all"]},x={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."},browserShellMode:{value:!0,type:"boolean",envLink:"OTHER_BROWSER_SHELL_MODE",description:"Decides if the browser runs in the shell mode."}},debug:{enable:{value:!1,type:"boolean",envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"Enables or disables debug mode for the underlying browser."},headless:{value:!0,type:"boolean",envLink:"DEBUG_HEADLESS",description:"Controls the mode in which the browser is launched when in the debug mode."},devtools:{value:!1,type:"boolean",envLink:"DEBUG_DEVTOOLS",description:"Decides whether to enable DevTools when the browser is in a headful state."},listenToConsole:{value:!1,type:"boolean",envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"Decides whether to enable a listener for console messages sent from the browser."},dumpio:{value:!1,type:"boolean",envLink:"DEBUG_DUMPIO",description:"Redirects browser process stdout and stderr to process.stdout and process.stderr."},slowMo:{value:0,type:"number",envLink:"DEBUG_SLOW_MO",description:"Slows down Puppeteer operations by the specified number of milliseconds."},debuggingPort:{value:9222,type:"number",envLink:"DEBUG_DEBUGGING_PORT",description:"Specifies the debugging port."}},webSocket:{enable:{value:!1,type:"boolean",envLink:"WEB_SOCKET_ENABLE",cliName:"enableWs",description:"Enables or disables the WebSocket connection."},reconnect:{value:!1,type:"boolean",envLink:"WEB_SOCKET_RECONNECT",cliName:"wsReconnect",description:"Controls whether or not to try reconnecting to the WebSocket server in case of a disconnect."},rejectUnauthorized:{value:!1,type:"boolean",envLink:"WEB_SOCKET_REJECT_UNAUTHORIZED",cliName:"wsrejectUnauthorized",description:"Determines whether the client verifies the server's SSL/TLS certificate during the handshake process."},pingTimeout:{value:16e3,type:"number",envLink:"WEB_SOCKET_PING_TIMEOUT",cliName:"wsPingTimeout",description:"The timeout, in milliseconds, for the heartbeat mechanism between the client and server."},reconnectInterval:{value:3e3,type:"number",envLink:"WEB_SOCKET_RECONNECT_INTERVAL",cliName:"wsReconnectInterval",description:"The interval, in milliseconds, for the reconnect attempt."},reconnectAttempts:{value:3,type:"number",envLink:"WEB_SOCKET_RECONNECT_ATTEMPTS",cliName:"wsReconnectAttempts",description:"The number of reconnect attempts before returning a connection error."},messageInterval:{value:3,type:"number",envLink:"WEB_SOCKET_MESSAGE_INTERVAL",cliName:"wsMessageInterval",description:"The interval, in milliseconds, for auto sending the data through a WebSocket connection."},url:{value:!1,type:"string",envLink:"WEB_SOCKET_URL",cliName:"wsUrl",description:"The URL of the WebSocket server."},secret:{value:!1,type:"string",envLink:"WEB_SOCKET_SECRET",cliName:"wsSecret",description:"The secret used to create a JSON Web Token sent to the WebSocket server."}}},L={puppeteer:[{type:"list",name:"args",message:"Puppeteer arguments",initial:x.puppeteer.args.value.join(","),separator:","}],highcharts:[{type:"text",name:"version",message:"Highcharts version",initial:x.highcharts.version.value},{type:"text",name:"cdnURL",message:"The URL of CDN",initial:x.highcharts.cdnURL.value},{type:"multiselect",name:"coreScripts",message:"Available core scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:x.highcharts.coreScripts.value},{type:"multiselect",name:"moduleScripts",message:"Available module scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:x.highcharts.moduleScripts.value},{type:"multiselect",name:"indicatorScripts",message:"Available indicator scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:x.highcharts.indicatorScripts.value},{type:"list",name:"customScripts",message:"Custom scripts",initial:x.highcharts.customScripts.value.join(","),separator:","},{type:"toggle",name:"forceFetch",message:"Force re-fetch the scripts",initial:x.highcharts.forceFetch.value},{type:"text",name:"cachePath",message:"The path to the cache directory",initial:x.highcharts.cachePath.value}],export:[{type:"select",name:"type",message:"The default export file type",hint:`Default: ${x.export.type.value}`,initial:0,choices:["png","jpeg","pdf","svg"]},{type:"select",name:"constr",message:"The default constructor for Highcharts",hint:`Default: ${x.export.constr.value}`,initial:0,choices:["chart","stockChart","mapChart","ganttChart"]},{type:"number",name:"defaultHeight",message:"The default fallback height of the exported chart",initial:x.export.defaultHeight.value},{type:"number",name:"defaultWidth",message:"The default fallback width of the exported chart",initial:x.export.defaultWidth.value},{type:"number",name:"defaultScale",message:"The default fallback scale of the exported chart",initial:x.export.defaultScale.value,min:.1,max:5},{type:"number",name:"rasterizationTimeout",message:"The rendering webpage timeout in milliseconds",initial:x.export.rasterizationTimeout.value}],customLogic:[{type:"toggle",name:"allowCodeExecution",message:"Enable execution of custom code",initial:x.customLogic.allowCodeExecution.value},{type:"toggle",name:"allowFileResources",message:"Enable file resources",initial:x.customLogic.allowFileResources.value}],server:[{type:"toggle",name:"enable",message:"Starts the server on 0.0.0.0",initial:x.server.enable.value},{type:"text",name:"host",message:"Server hostname",initial:x.server.host.value},{type:"number",name:"port",message:"Server port",initial:x.server.port.value},{type:"toggle",name:"benchmarking",message:"Enable server benchmarking",initial:x.server.benchmarking.value},{type:"text",name:"proxy.host",message:"The host of the proxy server to use",initial:x.server.proxy.host.value},{type:"number",name:"proxy.port",message:"The port of the proxy server to use",initial:x.server.proxy.port.value},{type:"number",name:"proxy.timeout",message:"The timeout for the proxy server to use",initial:x.server.proxy.timeout.value},{type:"toggle",name:"rateLimiting.enable",message:"Enable rate limiting",initial:x.server.rateLimiting.enable.value},{type:"number",name:"rateLimiting.maxRequests",message:"The maximum requests allowed per minute",initial:x.server.rateLimiting.maxRequests.value},{type:"number",name:"rateLimiting.window",message:"The rate-limiting time window in minutes",initial:x.server.rateLimiting.window.value},{type:"number",name:"rateLimiting.delay",message:"The delay for each successive request before reaching the maximum",initial:x.server.rateLimiting.delay.value},{type:"toggle",name:"rateLimiting.trustProxy",message:"Set to true if behind a load balancer",initial:x.server.rateLimiting.trustProxy.value},{type:"text",name:"rateLimiting.skipKey",message:"Allows bypassing the rate limiter when provided with the skipToken argument",initial:x.server.rateLimiting.skipKey.value},{type:"text",name:"rateLimiting.skipToken",message:"Allows bypassing the rate limiter when provided with the skipKey argument",initial:x.server.rateLimiting.skipToken.value},{type:"toggle",name:"ssl.enable",message:"Enable SSL protocol",initial:x.server.ssl.enable.value},{type:"toggle",name:"ssl.force",message:"Force serving only over HTTPS",initial:x.server.ssl.force.value},{type:"number",name:"ssl.port",message:"SSL server port",initial:x.server.ssl.port.value},{type:"text",name:"ssl.certPath",message:"The path to find the SSL certificate/key",initial:x.server.ssl.certPath.value}],pool:[{type:"number",name:"minWorkers",message:"The initial number of workers to spawn",initial:x.pool.minWorkers.value},{type:"number",name:"maxWorkers",message:"The maximum number of workers to spawn",initial:x.pool.maxWorkers.value},{type:"number",name:"workLimit",message:"The pieces of work that can be performed before restarting a Puppeteer process",initial:x.pool.workLimit.value},{type:"number",name:"acquireTimeout",message:"The number of milliseconds to wait for acquiring a resource",initial:x.pool.acquireTimeout.value},{type:"number",name:"createTimeout",message:"The number of milliseconds to wait for creating a resource",initial:x.pool.createTimeout.value},{type:"number",name:"destroyTimeout",message:"The number of milliseconds to wait for destroying a resource",initial:x.pool.destroyTimeout.value},{type:"number",name:"idleTimeout",message:"The number of milliseconds after an idle resource is destroyed",initial:x.pool.idleTimeout.value},{type:"number",name:"createRetryInterval",message:"The retry interval in milliseconds after a create process fails",initial:x.pool.createRetryInterval.value},{type:"number",name:"reaperInterval",message:"The reaper interval in milliseconds after triggering the check for idle resources to destroy",initial:x.pool.reaperInterval.value},{type:"toggle",name:"benchmarking",message:"Enable benchmarking for a resource pool",initial:x.pool.benchmarking.value}],logging:[{type:"number",name:"level",message:"The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)",initial:x.logging.level.value,round:0,min:0,max:5},{type:"text",name:"file",message:"A log file name. Set with the --logDest to enable file logging",initial:x.logging.file.value},{type:"text",name:"dest",message:"The path to log files. Enables file logging",initial:x.logging.dest.value}],ui:[{type:"toggle",name:"enable",message:"Enable UI for the export server",initial:x.ui.enable.value},{type:"text",name:"route",message:"A route to attach the UI",initial:x.ui.route.value}],other:[{type:"text",name:"nodeEnv",message:"The type of Node.js environment",initial:x.other.nodeEnv.value},{type:"toggle",name:"listenToProcessExits",message:"Set to false to skip attaching process.exit handlers",initial:x.other.listenToProcessExits.value},{type:"toggle",name:"noLogo",message:"Skip printing the logo on startup. Replaced by simple text",initial:x.other.noLogo.value},{type:"toggle",name:"hardResetPage",message:"Decides if the page content should be reset entirely",initial:x.other.hardResetPage.value},{type:"toggle",name:"browserShellMode",message:"Decides if the browser runs in the shell mode",initial:x.other.browserShellMode.value}],debug:[{type:"toggle",name:"enable",message:"Enables debug mode for the browser instance",initial:x.debug.enable.value},{type:"toggle",name:"headless",message:"The mode setting for the browser",initial:x.debug.headless.value},{type:"toggle",name:"devtools",message:"The DevTools for the headful browser",initial:x.debug.devtools.value},{type:"toggle",name:"listenToConsole",message:"The event listener for console messages from the browser",initial:x.debug.listenToConsole.value},{type:"toggle",name:"dumpio",message:"Redirects the browser stdout and stderr to NodeJS process",initial:x.debug.dumpio.value},{type:"number",name:"slowMo",message:"Puppeteer operations slow down in milliseconds",initial:x.debug.slowMo.value},{type:"number",name:"debuggingPort",message:"The port number for debugging",initial:x.debug.debuggingPort.value}],webSocket:[{type:"toggle",name:"enable",message:"Enables WebSocket connection",initial:x.webSocket.enable.value},{type:"toggle",name:"reconnect",message:"The reconnect mechanism for WebSocket connection",initial:x.webSocket.reconnect.value},{type:"toggle",name:"rejectUnauthorized",message:"Reject connection if WebSocket is not secured, SSL/TLS",initial:x.webSocket.rejectUnauthorized.value},{type:"number",name:"pingTimeout",message:"Timeout for the hearbeat mechanism",initial:x.webSocket.pingTimeout.value},{type:"number",name:"reconnectInterval",message:"Interval for the reconnect mechanism",initial:x.webSocket.reconnectInterval.value},{type:"number",name:"reconnectAttempts",message:"The number of reconnect attempts",initial:x.webSocket.reconnectAttempts.value},{type:"number",name:"messageInterval",message:"Interval for auto sending the data",initial:x.webSocket.messageInterval.value},{type:"text",name:"url",message:"The URL of the WebSocket server",initial:x.webSocket.url.value},{type:"text",name:"secret",message:"The secret for the JWT to WebSocket server",initial:x.webSocket.secret.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(x),u.config();const A=e=>h.string().transform((t=>t.split(",").map((e=>e.trim())).filter((t=>e.includes(t))))).transform((e=>e.length?e:void 0)),P=()=>h.enum(["true","false",""]).transform((e=>""!==e?"true"===e:void 0)),$=e=>h.enum([...e,""]).transform((e=>""!==e?e:void 0)),H=()=>h.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=()=>h.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)),W=()=>h.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=h.object({HIGHCHARTS_VERSION:h.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:h.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:H(),HIGHCHARTS_ADMIN_TOKEN:H(),EXPORT_TYPE:$(["jpeg","png","pdf","svg"]),EXPORT_CONSTR:$(["chart","stockChart","mapChart","ganttChart"]),EXPORT_DEFAULT_HEIGHT:U(),EXPORT_DEFAULT_WIDTH:U(),EXPORT_DEFAULT_SCALE:U(),EXPORT_RASTERIZATION_TIMEOUT:W(),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:P(),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:P(),SERVER_ENABLE:P(),SERVER_HOST:H(),SERVER_PORT:U(),SERVER_BENCHMARKING:P(),SERVER_PROXY_HOST:H(),SERVER_PROXY_PORT:U(),SERVER_PROXY_TIMEOUT:W(),SERVER_RATE_LIMITING_ENABLE:P(),SERVER_RATE_LIMITING_MAX_REQUESTS:W(),SERVER_RATE_LIMITING_WINDOW:W(),SERVER_RATE_LIMITING_DELAY:W(),SERVER_RATE_LIMITING_TRUST_PROXY:P(),SERVER_RATE_LIMITING_SKIP_KEY:H(),SERVER_RATE_LIMITING_SKIP_TOKEN:H(),SERVER_SSL_ENABLE:P(),SERVER_SSL_FORCE:P(),SERVER_SSL_PORT:U(),SERVER_SSL_CERT_PATH:H(),POOL_MIN_WORKERS:W(),POOL_MAX_WORKERS:W(),POOL_WORK_LIMIT:U(),POOL_ACQUIRE_TIMEOUT:W(),POOL_CREATE_TIMEOUT:W(),POOL_DESTROY_TIMEOUT:W(),POOL_IDLE_TIMEOUT:W(),POOL_CREATE_RETRY_INTERVAL:W(),POOL_REAPER_INTERVAL:W(),POOL_BENCHMARKING:P(),LOGGING_LEVEL:h.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:H(),LOGGING_DEST:H(),UI_ENABLE:P(),UI_ROUTE:H(),OTHER_NODE_ENV:$(["development","production","test"]),OTHER_LISTEN_TO_PROCESS_EXITS:P(),OTHER_NO_LOGO:P(),OTHER_HARD_RESET_PAGE:P(),OTHER_BROWSER_SHELL_MODE:P(),DEBUG_ENABLE:P(),DEBUG_HEADLESS:P(),DEBUG_DEVTOOLS:P(),DEBUG_LISTEN_TO_CONSOLE:P(),DEBUG_DUMPIO:P(),DEBUG_SLOW_MO:W(),DEBUG_DEBUGGING_PORT:U(),WEB_SOCKET_ENABLE:P(),WEB_SOCKET_RECONNECT:P(),WEB_SOCKET_REJECT_UNAUTHORIZED:P(),WEB_SOCKET_PING_TIMEOUT:W(),WEB_SOCKET_RECONNECT_INTERVAL:W(),WEB_SOCKET_RECONNECT_ATTEMPTS:W(),WEB_SOCKET_MESSAGE_INTERVAL:W(),WEB_SOCKET_URL:H(),WEB_SOCKET_SECRET:H()}).partial().parse(process.env),G=["red","yellow","blue","gray","green"];let j={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:G[0]},{title:"warning",color:G[1]},{title:"notice",color:G[2]},{title:"verbose",color:G[3]},{title:"benchmark",color:G[4]}],listeners:[]};for(const[e,t]of Object.entries(x.logging))j[e]=t.value;const M=(o,i)=>{j.toFile&&(j.pathCreated||(!e(j.dest)&&t(j.dest),j.pathCreated=!0),r(`${j.dest}${j.file}`,[i].concat(o).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),j.toFile=!1)})))},F=(...e)=>{const[t,...r]=e,{level:o,levelsDesc:i}=j;if(5!==t&&(0===t||t>o||o>i.length))return;const n=`${(new Date).toString().split("(")[0].trim()} [${i[t-1].title}] -`;j.listeners.forEach((e=>{e(n,r.join(" "))})),j.toConsole&&console.log.apply(void 0,[n.toString()[j.levelsDesc[t-1].color]].concat(r)),M(r,n)},V=(e,t,r)=>{const o=r||t.message,{level:i,levelsDesc:n}=j;if(0===e||e>i||i>n.length)return;const s=`${(new Date).toString().split("(")[0].trim()} [${n[e-1].title}] -`,a=t.message!==t.stackMessage||void 0===t.stackMessage?t.stack:t.stack.split("\n").slice(1).join("\n"),c=[o,"\n",a];j.toConsole&&console.log.apply(void 0,[s.toString()[j.levelsDesc[e-1].color]].concat([o[G[e-1]],"\n",a])),j.listeners.forEach((e=>{e(s,c.join(" "))})),M(c,s)},q=e=>{e>=0&&e<=j.levelsDesc.length&&(j.level=e)},B=(e,t)=>{if(j={...j,dest:e||j.dest,file:t||j.file,toFile:!0},0===j.dest.length)return F(1,"[logger] File logging initialization: no path supplied.");j.dest.endsWith("/")||(j.dest+="/")},K=d(new URL("../.",import.meta.url)),X=(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"},z=(e=!1,t)=>{const r=["js","css","files"];let i=e,n=!1;if(t&&e.endsWith(".json"))try{i=J(o(e,"utf8"))}catch(e){return V(2,e,"[cli] No resources found.")}else i=J(e),i&&!t&&delete i.files;for(const e in i)r.includes(e)?n||(n=!0):delete i[e];return n?(i.files&&(i.files=i.files.map((e=>e.trim())),(!i.files||i.files.length<=0)&&delete i.files),i):F(3,"[cli] No resources found.")};function J(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},Z=(e,t)=>JSON.stringify(e,((e,r)=>("string"==typeof r&&((r=r.trim()).startsWith("function(")||r.startsWith("function ("))&&r.endsWith("}")&&(r=t?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:void 0),"function"==typeof r?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:r))).replaceAll(/"EXP_FUN|EXP_FUN"/g,"");function Q(){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(x).forEach((t=>{["puppeteer","highcharts"].includes(t)||(console.log(`\n${t.toUpperCase()}`.red),e(x[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(o(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,ne=(e,t,r=[])=>{const o=Y(e);for(const[e,n]of Object.entries(t))o[e]="object"!=typeof(i=n)||Array.isArray(i)||null===i||r.includes(e)||void 0===o[e]?void 0!==n?n:o[e]:ne(o[e],n,r);var i;return o};function se(e,t={},r=""){Object.keys(e).forEach((o=>{const i=e[o],n=t&&t[o];void 0===i.value?se(i,n,`${r}.${o}`):(void 0!==n&&(i.value=n),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 ce(e,t,r){for(;t.length>1;){const o=t.shift();return Object.prototype.hasOwnProperty.call(e,o)||(e[o]={}),e[o]=ce(Object.assign({},e[o]),t,r),e}return e[t[0]]=r,e}async function le(e,t={}){return new Promise(((r,o)=>{const i=(e=>e.startsWith("https")?g:m)(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 ue={cdnURL:"https://code.highcharts.com/",activeManifest:{},sources:"",hcVersion:""},he=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)),F(4,`[cache] Fetching script - ${e}.js`);const i=await le(`${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 F(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`),""},me=async(e,t,r)=>{const o=e.version,i="latest"!==o&&o?`${o}/`:"",s=e.cdnURL||ue.cdnURL;F(3,`[cache] Updating cache version to Highcharts: ${i||"latest"}.`);const a={};try{return ue.sources=await(async(e,t,r,o,i)=>{let n;const s=o.host,a=o.port;if(s&&a)try{n=new l({host:s,port:a})}catch(e){throw new pe("[cache] Could not create a Proxy Agent.").setError(e)}const c=n?{agent:n,timeout:D.SERVER_PROXY_TIMEOUT}:{},p=[...e.map((e=>de(`${e}`,c,i,!0))),...t.map((e=>de(`${e}`,c,i))),...r.map((e=>de(`${e}`,c)))];return(await Promise.all(p)).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),ue.hcVersion=he(ue),n(r,ue.sources),a}catch(e){throw new pe("[cache] Unable to update the local Highcharts cache.").setError(e)}},ge=async r=>{const{highcharts:i,server:s}=r,c=a(K,i.cachePath);let l;const p=a(c,"manifest.json"),u=a(c,"sources.js");if(!e(c)&&t(c),!e(p)||i.forceFetch)F(3,"[cache] Fetching and caching Highcharts dependencies."),l=await me(i,s.proxy,u);else{let e=!1;const t=JSON.parse(o(p));if(t.modules&&Array.isArray(t.modules)){const e={};t.modules.forEach((t=>e[t]=1)),t.modules=e}const{coreScripts:r,moduleScripts:n,indicatorScripts:a}=i,c=r.length+n.length+a.length;t.version!==i.version?(F(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),e=!0):Object.keys(t.modules||{}).length!==c?(F(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 F(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),e?l=await me(i,s.proxy,u):(F(3,"[cache] Dependency cache is up to date, proceeding."),ue.sources=o(u,"utf8"),l=t.modules,ue.hcVersion=he(ue))}await(async(e,t)=>{const r={version:e.version,modules:t||{}};ue.activeManifest=r,F(3,"[cache] Writing a new manifest.");try{n(a(K,e.cachePath,"manifest.json"),JSON.stringify(r),"utf8")}catch(e){throw new pe("[cache] Error writing the cache manifest.").setError(e)}})(i,l)},fe=()=>a(K,ie().highcharts.cachePath),ve=()=>ue.hcVersion;function be(){Highcharts.animObject=function(){return{duration:0}}}async function ye(e,t,r){window._displayErrors=r;const{getOptions:o,merge:i,setOptions:n,wrap:s}=Highcharts;Highcharts.setOptionsObj=i(!1,{},o()),t.customLogic.customCode&&new Function(t.customLogic.customCode)();const a={animation:!1};t.export.strInj&&(a.height=e.chart.height,a.width=e.chart.width),window.isRenderComplete=!1,s(Highcharts.Chart.prototype,"init",(function(e,t,r){((t=i(t,{exporting:{enabled:!1},plotOptions:{series:{label:{enabled:!1}}},tooltip:{}})).series||[]).forEach((function(e){e.animation=!1})),window.onHighchartsRender||(window.onHighchartsRender=Highcharts.addEvent(this,"render",(()=>{window.isRenderComplete=!0}))),e.apply(this,[t,r])})),s(Highcharts.Series.prototype,"init",(function(e,t,r){e.apply(this,[t,r])}));const c=t.export.strInj?new Function(`return ${t.export.strInj}`)():e,l=i(!1,JSON.parse(t.export.themeOptions),c,{chart:a}),p=t.customLogic.callback?new Function(`return ${t.customLogic.callback}`)():void 0,u=JSON.parse(t.export.globalOptions);u&&n(u),Highcharts[t.export.constr||"chart"]("container",l,p);const h=o();for(const e in h)"function"!=typeof h[e]&&delete h[e];n(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const we=o(K+"/templates/template.html","utf8");let Ee;async function Te(){if(!Ee)return!1;const e=await Ee.newPage();return await e.setCacheEnabled(!1),await _e(e),function(e){const{debug:t}=ie();t.enable&&t.listenToConsole&&e.on("console",(e=>{console.log(`[debug] ${e.text()}`)}));e.on("pageerror",(async t=>{await e.$eval("#container",((e,t)=>{window._displayErrors&&(e.innerHTML=t)}),`

Chart input data error:

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

Chart input data error:

${error.toString()}`\r\n );\r\n });\r\n}\r\n\r\nexport default {\r\n get,\r\n create,\r\n close,\r\n newPage,\r\n clearPage,\r\n addPageResources,\r\n clearPageResources\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { addPageResources, clearPageResources } from './browser.js';\r\nimport { getCache } from './cache.js';\r\nimport { triggerExport } from './highcharts.js';\r\nimport { log } from './logger.js';\r\n\r\nimport svgTemplate from './../templates/svg_export/svg_export.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n/**\r\n * Retrieves the clipping region coordinates of the specified page element with\r\n * the id 'chart-container'.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} Promise resolving to an object containing\r\n * x, y, width, and height properties.\r\n */\r\nconst getClipRegion = (page) =>\r\n page.$eval('#chart-container', (element) => {\r\n const { x, y, width, height } = element.getBoundingClientRect();\r\n return {\r\n x,\r\n y,\r\n width,\r\n height: Math.trunc(height > 1 ? height : 500)\r\n };\r\n });\r\n\r\n/**\r\n * Creates an image using Puppeteer's page screenshot functionality with\r\n * specified options.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {string} type - Image type.\r\n * @param {string} encoding - Image encoding.\r\n * @param {Object} clip - Clipping region coordinates.\r\n * @param {number} rasterizationTimeout - Timeout for rasterization\r\n * in milliseconds.\r\n *\r\n * @returns {Promise} Promise resolving to the image buffer or rejecting\r\n * with an ExportError for timeout.\r\n */\r\nconst createImage = (page, type, encoding, clip, rasterizationTimeout) =>\r\n Promise.race([\r\n page.screenshot({\r\n type,\r\n encoding,\r\n clip,\r\n captureBeyondViewport: true,\r\n fullPage: false,\r\n optimizeForSpeed: true,\r\n ...(type !== 'png' ? { quality: 80 } : {}),\r\n\r\n // #447, #463 - always render on a transparent page if the expected type\r\n // format is PNG\r\n omitBackground: type == 'png'\r\n }),\r\n new Promise((_resolve, reject) =>\r\n setTimeout(\r\n () => reject(new ExportError('Rasterization timeout')),\r\n rasterizationTimeout || 1500\r\n )\r\n )\r\n ]);\r\n\r\n/**\r\n * Creates a PDF using Puppeteer's page pdf functionality with specified\r\n * options.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {number} height - PDF height.\r\n * @param {number} width - PDF width.\r\n * @param {string} encoding - PDF encoding.\r\n *\r\n * @returns {Promise} Promise resolving to the PDF buffer.\r\n */\r\nconst createPDF = async (\r\n page,\r\n height,\r\n width,\r\n encoding,\r\n rasterizationTimeout\r\n) => {\r\n await page.emulateMediaType('screen');\r\n return Promise.race([\r\n page.pdf({\r\n // This will remove an extra empty page in PDF exports\r\n height: height + 1,\r\n width,\r\n encoding\r\n }),\r\n new Promise((_resolve, reject) =>\r\n setTimeout(\r\n () => reject(new ExportError('Rasterization timeout')),\r\n rasterizationTimeout || 1500\r\n )\r\n )\r\n ]);\r\n};\r\n\r\n/**\r\n * Creates an SVG string by evaluating the outerHTML of the first 'svg' element\r\n * inside an element with the id 'container'.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} Promise resolving to the SVG string.\r\n */\r\nconst createSVG = (page) =>\r\n page.$eval('#container svg:first-of-type', (element) => element.outerHTML);\r\n\r\n/**\r\n * Sets the specified chart and options as configuration into the triggerExport\r\n * function within the window context using page.evaluate.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {any} chart - The chart object to be configured.\r\n * @param {Object} options - Configuration options for the chart.\r\n *\r\n * @returns {Promise} Promise resolving after the configuration is set.\r\n */\r\nconst setAsConfig = async (page, chart, options, displayErrors) =>\r\n page.evaluate(triggerExport, chart, options, displayErrors);\r\n\r\n/**\r\n * Exports to a chart from a page using Puppeteer.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {any} chart - The chart object or SVG configuration to be exported.\r\n * @param {Object} options - Export options and configuration.\r\n *\r\n * @returns {Promise} Promise resolving to\r\n * the exported data or rejecting with an ExportError.\r\n */\r\nexport default async (page, chart, options) => {\r\n // Injected resources array (additional JS and CSS)\r\n let injectedResources = [];\r\n\r\n try {\r\n log(4, '[export] Determining export path.');\r\n\r\n const exportOptions = options.export;\r\n\r\n // Decide whether display error or debbuger wrapper around it\r\n const displayErrors =\r\n exportOptions?.options?.chart?.displayErrors &&\r\n getCache().activeManifest.modules.debugger;\r\n\r\n let isSVG;\r\n if (\r\n chart.indexOf &&\r\n (chart.indexOf('= 0 || chart.indexOf('= 0)\r\n ) {\r\n // SVG input handling\r\n log(4, '[export] Treating as SVG.');\r\n\r\n // If input is also SVG, just return it\r\n if (exportOptions.type === 'svg') {\r\n return chart;\r\n }\r\n\r\n isSVG = true;\r\n await page.setContent(svgTemplate(chart), {\r\n waitUntil: 'domcontentloaded'\r\n });\r\n } else {\r\n // JSON config handling\r\n log(4, '[export] Treating as config.');\r\n\r\n // Need to perform straight inject\r\n if (exportOptions.strInj) {\r\n // Injection based configuration export\r\n await setAsConfig(\r\n page,\r\n {\r\n chart: {\r\n height: exportOptions.height,\r\n width: exportOptions.width\r\n }\r\n },\r\n options,\r\n displayErrors\r\n );\r\n } else {\r\n // Basic configuration export\r\n chart.chart.height = exportOptions.height;\r\n chart.chart.width = exportOptions.width;\r\n\r\n await setAsConfig(page, chart, options, displayErrors);\r\n }\r\n }\r\n\r\n // Keeps track of all resources added on the page with addXXXTag. etc\r\n // It's VITAL that all added resources ends up here so we can clear things\r\n // out when doing a new export in the same page!\r\n injectedResources = await addPageResources(page, options);\r\n\r\n // Get the real chart size and set the zoom accordingly\r\n const size = isSVG\r\n ? await page.evaluate((scale) => {\r\n const svgElement = document.querySelector(\r\n '#chart-container svg:first-of-type'\r\n );\r\n\r\n // Get the values correctly scaled\r\n const chartHeight = svgElement.height.baseVal.value * scale;\r\n const chartWidth = svgElement.width.baseVal.value * scale;\r\n\r\n // In case of SVG the zoom must be set directly for body\r\n // Set the zoom as scale\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = scale;\r\n\r\n // Set the margin to 0px\r\n // eslint-disable-next-line no-undef\r\n document.body.style.margin = '0px';\r\n\r\n return {\r\n chartHeight,\r\n chartWidth\r\n };\r\n }, parseFloat(exportOptions.scale))\r\n : await page.evaluate(() => {\r\n // eslint-disable-next-line no-undef\r\n const { chartHeight, chartWidth } = window.Highcharts.charts[0];\r\n\r\n // No need for such scale manipulation in case of other types\r\n // of exports. Reset the zoom for other exports than to SVGs\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = 1;\r\n\r\n return {\r\n chartHeight,\r\n chartWidth\r\n };\r\n });\r\n\r\n // Set final height and width for viewport\r\n const viewportHeight = Math.ceil(size.chartHeight || exportOptions.height);\r\n const viewportWidth = Math.ceil(size.chartWidth || exportOptions.width);\r\n\r\n // Get the clip region for the page\r\n const { x, y } = await getClipRegion(page);\r\n\r\n // Set the final viewport now that we have the real height\r\n await page.setViewport({\r\n height: viewportHeight,\r\n width: viewportWidth,\r\n deviceScaleFactor: isSVG ? 1 : parseFloat(exportOptions.scale)\r\n });\r\n\r\n let data;\r\n // Rasterization process\r\n if (exportOptions.type === 'svg') {\r\n // SVG\r\n data = await createSVG(page);\r\n } else if (['png', 'jpeg'].includes(exportOptions.type)) {\r\n // PNG or JPEG\r\n data = await createImage(\r\n page,\r\n exportOptions.type,\r\n 'base64',\r\n {\r\n width: viewportWidth,\r\n height: viewportHeight,\r\n x,\r\n y\r\n },\r\n exportOptions.rasterizationTimeout\r\n );\r\n } else if (exportOptions.type === 'pdf') {\r\n // PDF\r\n data = await createPDF(\r\n page,\r\n viewportHeight,\r\n viewportWidth,\r\n 'base64',\r\n exportOptions.rasterizationTimeout\r\n );\r\n } else {\r\n throw new ExportError(\r\n `[export] Unsupported output format ${exportOptions.type}.`\r\n );\r\n }\r\n\r\n // Clear previously injected JS and CSS resources\r\n await clearPageResources(page, injectedResources);\r\n return data;\r\n } catch (error) {\r\n await clearPageResources(page, injectedResources);\r\n return error;\r\n }\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport cssTemplate from './css.js';\r\n\r\nexport default (chart) => `\r\n\r\n\r\n \r\n \r\n Highcharts Export\r\n \r\n \r\n \r\n
\r\n ${chart}\r\n
\r\n \r\n\r\n\r\n`;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { Pool } from 'tarn';\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport {\r\n create as createBrowser,\r\n close as closeBrowser,\r\n newPage,\r\n clearPage\r\n} from './browser.js';\r\nimport puppeteerExport from './export.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { measureTime } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// The pool instance\r\nlet pool = false;\r\n\r\n// Pool statistics\r\nexport const stats = {\r\n performedExports: 0,\r\n exportAttempts: 0,\r\n exportFromSvgAttempts: 0,\r\n timeSpent: 0,\r\n droppedExports: 0,\r\n spentAverage: 0\r\n};\r\n\r\nlet poolConfig = {};\r\n\r\nconst factory = {\r\n /**\r\n * Creates a new worker page for the export pool.\r\n *\r\n * @returns {Object} - An object containing the worker ID, a reference to the\r\n * browser page, and initial work count.\r\n *\r\n * @throws {ExportError} - If there's an error during the creation of the new\r\n * page.\r\n */\r\n create: async () => {\r\n let page = false;\r\n\r\n const id = uuid();\r\n const startDate = new Date().getTime();\r\n\r\n try {\r\n page = await newPage();\r\n\r\n if (!page || page.isClosed()) {\r\n throw new ExportError('The page is invalid or closed.');\r\n }\r\n\r\n log(\r\n 3,\r\n `[pool] Successfully created a worker ${id} - took ${\r\n new Date().getTime() - startDate\r\n } ms.`\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n 'Error encountered when creating a new page.'\r\n ).setError(error);\r\n }\r\n\r\n return {\r\n id,\r\n page,\r\n // Try to distribute the initial work count\r\n workCount: Math.round(Math.random() * (poolConfig.workLimit / 2))\r\n };\r\n },\r\n\r\n /**\r\n * Validates a worker page in the export pool, checking if it has exceeded\r\n * the work limit.\r\n *\r\n * @param {Object} workerHandle - The handle to the worker, containing the\r\n * worker's ID, a reference to the browser page, and work count.\r\n *\r\n * @returns {boolean} - Returns true if the worker is valid and within\r\n * the work limit; otherwise, returns false.\r\n */\r\n validate: async (workerHandle) => {\r\n if (\r\n poolConfig.workLimit &&\r\n ++workerHandle.workCount > poolConfig.workLimit\r\n ) {\r\n log(\r\n 3,\r\n `[pool] Worker failed validation: exceeded work limit (limit is ${poolConfig.workLimit}).`\r\n );\r\n return false;\r\n }\r\n return true;\r\n },\r\n\r\n /**\r\n * Destroys a worker entry in the export pool, closing its associated page.\r\n *\r\n * @param {Object} workerHandle - The handle to the worker, containing\r\n * the worker's ID and a reference to the browser page.\r\n */\r\n destroy: async (workerHandle) => {\r\n log(3, `[pool] Destroying pool entry ${workerHandle.id}.`);\r\n\r\n if (workerHandle.page) {\r\n // We don't really need to wait around for this\r\n await workerHandle.page.close();\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Initializes the export pool with the provided configuration, creating\r\n * a browser instance and setting up worker resources.\r\n *\r\n * @param {Object} config - Configuration options for the export pool along\r\n * with custom puppeteer arguments for the puppeteer.launch function.\r\n */\r\nexport const initPool = async (config) => {\r\n // For the module scope usage\r\n poolConfig = config && config.pool ? { ...config.pool } : {};\r\n\r\n // Create a browser instance with the puppeteer arguments\r\n await createBrowser(config.puppeteerArgs);\r\n\r\n log(\r\n 3,\r\n `[pool] Initializing pool with workers: min ${poolConfig.minWorkers}, max ${poolConfig.maxWorkers}.`\r\n );\r\n\r\n if (pool) {\r\n return log(\r\n 4,\r\n '[pool] Already initialized, please kill it before creating a new one.'\r\n );\r\n }\r\n\r\n if (parseInt(poolConfig.minWorkers) > parseInt(poolConfig.maxWorkers)) {\r\n poolConfig.minWorkers = poolConfig.maxWorkers;\r\n }\r\n\r\n try {\r\n // Create a pool along with a minimal number of resources\r\n pool = new Pool({\r\n // Get the create/validate/destroy/log functions\r\n ...factory,\r\n min: parseInt(poolConfig.minWorkers),\r\n max: parseInt(poolConfig.maxWorkers),\r\n acquireTimeoutMillis: poolConfig.acquireTimeout,\r\n createTimeoutMillis: poolConfig.createTimeout,\r\n destroyTimeoutMillis: poolConfig.destroyTimeout,\r\n idleTimeoutMillis: poolConfig.idleTimeout,\r\n createRetryIntervalMillis: poolConfig.createRetryInterval,\r\n reapIntervalMillis: poolConfig.reaperInterval,\r\n propagateCreateError: false\r\n });\r\n\r\n // Set events\r\n pool.on('release', async (resource) => {\r\n // Clear page\r\n await clearPage(resource.page, false);\r\n log(4, `[pool] Releasing a worker with ID ${resource.id}.`);\r\n });\r\n\r\n pool.on('destroySuccess', (eventId, resource) => {\r\n log(4, `[pool] Destroyed a worker with ID ${resource.id}.`);\r\n });\r\n\r\n const initialResources = [];\r\n // Create an initial number of resources\r\n for (let i = 0; i < poolConfig.minWorkers; i++) {\r\n try {\r\n const resource = await pool.acquire().promise;\r\n initialResources.push(resource);\r\n } catch (error) {\r\n logWithStack(2, error, '[pool] Could not create an initial resource.');\r\n }\r\n }\r\n\r\n // Release the initial number of resources back to the pool\r\n initialResources.forEach((resource) => {\r\n pool.release(resource);\r\n });\r\n\r\n log(\r\n 3,\r\n `[pool] The pool is ready${initialResources.length ? ` with ${initialResources.length} initial resources waiting.` : '.'}`\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n '[pool] Could not create the pool of workers.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Kills all workers in the pool, destroys the pool, and closes the browser\r\n * instance.\r\n *\r\n * @returns {Promise} A promise that resolves after the workers are\r\n * killed, the pool is destroyed, and the browser is closed.\r\n */\r\nexport async function killPool() {\r\n log(3, '[pool] Killing pool with all workers and closing browser.');\r\n\r\n // If still alive, destroy the pool of pages before closing a browser\r\n if (pool) {\r\n // Free up not released workers\r\n for (const worker of pool.used) {\r\n pool.release(worker.resource);\r\n }\r\n\r\n // Destroy the pool if it is still available\r\n if (!pool.destroyed) {\r\n await pool.destroy();\r\n log(4, '[browser] Destroyed the pool of resources.');\r\n }\r\n }\r\n\r\n // Close the browser instance\r\n await closeBrowser();\r\n}\r\n\r\n/**\r\n * Processes the export work using a worker from the pool. Acquires a worker\r\n * handle from the pool, performs the export using puppeteer, and releases\r\n * the worker handle back to the pool.\r\n *\r\n * @param {string} chart - The chart data or configuration to be exported.\r\n * @param {Object} options - Export options and configuration.\r\n *\r\n * @returns {Promise} A promise that resolves with the export resultand\r\n * options.\r\n *\r\n * @throws {ExportError} If an error occurs during the export process.\r\n */\r\nexport const postWork = async (chart, options) => {\r\n let workerHandle;\r\n\r\n try {\r\n log(4, '[pool] Work received, starting to process.');\r\n\r\n ++stats.exportAttempts;\r\n if (poolConfig.benchmarking) {\r\n getPoolInfo();\r\n }\r\n\r\n if (!pool) {\r\n throw new ExportError('Work received, but pool has not been started.');\r\n }\r\n\r\n // Acquire the worker along with the id of resource and work count\r\n const acquireCounter = measureTime();\r\n try {\r\n log(4, '[pool] Acquiring a worker handle.');\r\n workerHandle = await pool.acquire().promise;\r\n\r\n // Check the page acquire time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n options.payload?.requestId\r\n ? `[benchmark] Request: ${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 ? `Request: ${options.payload?.requestId} - `\r\n : '') +\r\n `Error encountered when acquiring an available entry: ${acquireCounter()}ms.`\r\n ).setError(error);\r\n }\r\n log(4, '[pool] Acquired a worker handle.');\r\n\r\n if (!workerHandle.page) {\r\n throw new ExportError(\r\n 'Resolved worker page is invalid: the pool setup is wonky.'\r\n );\r\n }\r\n\r\n // Save the start time\r\n let workStart = new Date().getTime();\r\n\r\n log(4, `[pool] Starting work on pool entry with ID ${workerHandle.id}.`);\r\n\r\n // Perform an export on a puppeteer level\r\n const exportCounter = measureTime();\r\n const result = await puppeteerExport(workerHandle.page, chart, options);\r\n\r\n // Check if it's an error\r\n if (result instanceof Error) {\r\n // TODO: If the export failed because puppeteer timed out, we need to force kill the worker so we get a new page. That needs to be handled better than this hack.\r\n if (result.message === 'Rasterization timeout') {\r\n workerHandle.page.close();\r\n workerHandle.page = await newPage();\r\n }\r\n\r\n throw new ExportError(\r\n (options.payload?.requestId\r\n ? `Request: ${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: ${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\n/**\r\n * Gets the statistic of a pool instace about exports.\r\n */\r\nexport function getStats() {\r\n return stats;\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\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 and timeouts\r\nconst timerIds = [];\r\n\r\n/**\r\n * Adds id of setInterval or setTimeout and to the intervalIds array.\r\n *\r\n * @param {NodeJS.Timeout} id - Id of an interval/timeout.\r\n */\r\nexport const addTimer = (id) => {\r\n timerIds.push(id);\r\n};\r\n\r\n/**\r\n * Clears all of ongoing intervals and timeouts by ids gathered in the timerIds\r\n * array.\r\n */\r\nexport const clearAllTimers = () => {\r\n log(4, `[server] Clearing all registered intervals and timeouts.`);\r\n for (const id of timerIds) {\r\n clearInterval(id);\r\n clearTimeout(id);\r\n }\r\n};\r\n\r\nexport default {\r\n addTimer,\r\n clearAllTimers\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","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2023, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid 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\n\r\nimport { __dirname } from './utils.js';\r\n\r\n// Get the telemetry template\r\nconst telemetryTemplate = JSON.parse(\r\n readFileSync(join(__dirname, 'lib', 'schemas', 'telemetry.json'))\r\n);\r\n\r\n// The object with telemetry data collected\r\nexport const telemetryData = {\r\n numberOfRequests: 0\r\n};\r\n\r\n// Possible properties in an array\r\nconst optionsInArray = ['series', 'xAxis', 'yAxis', 'zAxis'];\r\n\r\n// Recursive function for getting only the required options\r\nfunction filterData(template, options) {\r\n const filteredObject = {};\r\n\r\n // Cycle through allowed propeties\r\n for (const [templateKey, templateValue] of Object.entries(template)) {\r\n // Check if the section exists\r\n if (options[templateKey] !== undefined) {\r\n // Check if this is the final level of indent in the template\r\n if (templateValue !== null) {\r\n // Check if it is an array\r\n if (Array.isArray(options[templateKey])) {\r\n // And if it contains allowed properties\r\n if (optionsInArray.includes(templateKey)) {\r\n // Create an array\r\n filteredObject[templateKey] = [];\r\n // If so, cycle through all of them\r\n for (const [index, optionsValue] of options[\r\n templateKey\r\n ].entries()) {\r\n filteredObject[templateKey][index] = filterData(\r\n templateValue,\r\n optionsValue\r\n );\r\n }\r\n } else {\r\n // Otherwise, get only the first element\r\n filteredObject[templateKey] = filterData(\r\n templateValue,\r\n options[templateKey][0]\r\n );\r\n }\r\n } else {\r\n filteredObject[templateKey] = filterData(\r\n templateValue,\r\n options[templateKey]\r\n );\r\n }\r\n } else {\r\n // Return the option\r\n filteredObject[templateKey] = options[templateKey];\r\n }\r\n }\r\n }\r\n\r\n // Return the object\r\n return filteredObject;\r\n}\r\n\r\nexport function prepareTelemetry(chartOptions, requestId) {\r\n // Save the filtered options under the request's id\r\n telemetryData[requestId] = filterData(telemetryTemplate, chartOptions);\r\n\r\n // Increment requests counter\r\n telemetryData.numberOfRequests++;\r\n}\r\n\r\nexport default {\r\n telemetryData,\r\n prepareTelemetry\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2023, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\nimport jwt from 'jsonwebtoken';\r\nimport { v4 as uuid } from 'uuid';\r\nimport WebSocket from 'ws';\r\n\r\nimport { getOptions } from '../config.js';\r\nimport { log, logWithStack } from '../logger.js';\r\nimport { telemetryData } from '../telemetry.js';\r\nimport { addTimer } from '../timers.js';\r\n\r\n// WebSocket clients map\r\nconst webSocketClients = new Map();\r\n\r\n// WebSocket options\r\nlet webSocketOptions;\r\n\r\n// WebSocket message sending interval\r\nlet messageInterval = null;\r\n\r\n/**\r\n * Init WebSocket client and connection options.\r\n *\r\n * @param {object} address - Object that contains, address and port of enabled\r\n * HTTP or HTTPS server.\r\n */\r\nexport function init(address) {\r\n webSocketOptions = getOptions().webSocket;\r\n if (webSocketOptions.enable === true) {\r\n // Options for the WebSocket connection\r\n const connectionOptions = {\r\n rejectUnauthorized: webSocketOptions.rejectUnauthorized,\r\n headers: {\r\n // Set an access token that lasts only 5 minutes\r\n auth: jwt.sign({ success: 'success' }, webSocketOptions.secret, {\r\n algorithm: 'HS256'\r\n }),\r\n // Send the server address in a custom header\r\n 'X-Server-Address': `${address.protocol}://${\r\n ['::', '0.0.0.0'].includes(address.address)\r\n ? 'localhost'\r\n : address.address\r\n }:${address.port}`\r\n }\r\n };\r\n\r\n // Options for the WebSocket client\r\n const clientOptions = {\r\n id: uuid(),\r\n reconnect: webSocketOptions.reconnect,\r\n reconnectTry: 0,\r\n reconnectInterval: null,\r\n pingTimeout: null\r\n };\r\n\r\n // Start the WebSocket connection\r\n connect(webSocketOptions.url, connectionOptions, clientOptions);\r\n\r\n // Start the WebSocket message sending interval\r\n sendingMessageInterval(webSocketOptions);\r\n }\r\n}\r\n\r\nfunction sendingMessageInterval(webSocketOptions) {\r\n // Set the sending message interval\r\n messageInterval = setInterval(() => {\r\n try {\r\n // Get the first WebSocket client\r\n const webSocketClient = getClients().next().value;\r\n // If the client is found, open and there is data to send\r\n if (\r\n webSocketClient &&\r\n webSocketClient.readyState === WebSocket.OPEN &&\r\n Object.keys(telemetryData).length > 1 &&\r\n telemetryData.numberOfRequests > 0\r\n ) {\r\n // Send through the WebSocket\r\n webSocketClient.send(JSON.stringify(telemetryData));\r\n }\r\n } catch (error) {\r\n logWithStack(1, `[websocket] Could not send data through WebSocket.`);\r\n }\r\n }, webSocketOptions.messageInterval);\r\n\r\n // Register interval for the later clearing\r\n addTimer(messageInterval);\r\n}\r\n\r\n/**\r\n * Creates WebSocket client and connects to WebSocket server on a provided url.\r\n *\r\n * @param {string} webSocketUrl - The WebSocket server's URL.\r\n * @param {object} connectionOptions - Options for WebSocket connection.\r\n * @param {object} clientOptions - Options for WebSocket client.\r\n */\r\nfunction connect(webSocketUrl, connectionOptions, clientOptions) {\r\n // Try to connect to indicated WebSocket server\r\n let webSocketClient = new WebSocket(webSocketUrl, connectionOptions);\r\n\r\n // Open event\r\n webSocketClient.on('open', () => {\r\n // Not need for the reconnect interval anymore\r\n clearInterval(clientOptions.reconnectInterval);\r\n\r\n // Save the client under its id\r\n webSocketClients.set(clientOptions.id, webSocketClient);\r\n\r\n // Log a success message\r\n log(\r\n 3,\r\n `[websocket] WebSocket: ${clientOptions.id} - Connected to server: ${webSocketUrl}.`\r\n );\r\n });\r\n\r\n // Close event where ping timeout is cleared\r\n webSocketClient.on('close', (code) => {\r\n log(\r\n 3,\r\n '[websocket]',\r\n `WebSocket: ${clientOptions.id} - Disconnected from server: ${webSocketUrl} with code: ${code}.`\r\n );\r\n\r\n // Stop the heartbeat mechanism\r\n clearTimeout(clientOptions.pingTimeout);\r\n\r\n // Removed client if exists\r\n webSocketClients.delete(clientOptions.id);\r\n webSocketClient = null;\r\n\r\n // Try to reconnect only when enabled and if not already attempting to do so\r\n if (clientOptions.reconnect && !clientOptions.reconnectInterval) {\r\n reconnect(webSocketUrl, connectionOptions, clientOptions);\r\n }\r\n });\r\n\r\n // Error event\r\n webSocketClient.on('error', (error) => {\r\n logWithStack(\r\n 1,\r\n error,\r\n `[websocket] WebSocket: ${clientOptions.id} - Error occured.`\r\n );\r\n\r\n // Block the reconnect mechanism when getting 403\r\n if (error.message.includes('403')) {\r\n clientOptions.reconnect = false;\r\n clientOptions.reconnectTry = webSocketOptions.reconnectAttempts;\r\n } else {\r\n // Or set the option accordingly\r\n clientOptions.reconnect = webSocketOptions.reconnect;\r\n }\r\n });\r\n\r\n // Message event\r\n webSocketClient.on('message', (message) => {\r\n log(\r\n 3,\r\n `[websocket] WebSocket: ${clientOptions.id} - Data received: ${message}`\r\n );\r\n });\r\n\r\n // The 'ping' event from a WebSocket connection with the health check\r\n // and termination logic\r\n webSocketClient.on('ping', () => {\r\n log(\r\n 3,\r\n `[websocket] WebSocket: ${clientOptions.id} - Received PING from server: ${webSocketUrl}.`\r\n );\r\n clearTimeout(clientOptions.pingTimeout);\r\n clientOptions.pingTimeout = setTimeout(() => {\r\n // Terminate the client connection\r\n webSocketClient.terminate();\r\n\r\n // Try to reconnect if required\r\n if (clientOptions.reconnect) {\r\n reconnect(webSocketUrl, connectionOptions, clientOptions);\r\n }\r\n }, webSocketOptions.pingTimeout);\r\n });\r\n}\r\n\r\n/**\r\n * Reconnects to WebSocket server on a provided url.\r\n *\r\n * @param {string} webSocketUrl - The WebSocket server's URL.\r\n * @param {object} connectionOptions - Options for WebSocket connection.\r\n * @param {object} clientOptions - Options for WebSocket client.\r\n */\r\nfunction reconnect(webSocketUrl, connectionOptions, clientOptions) {\r\n // Start the reconnect interval\r\n clientOptions.reconnectInterval = setInterval(() => {\r\n if (clientOptions.reconnectTry < webSocketOptions.reconnectAttempts) {\r\n log(\r\n 3,\r\n `[websocket] WebSocket: ${clientOptions.id} - Attempt ${++clientOptions.reconnectTry} of ${webSocketOptions.reconnectAttempts} to reconnect to server: ${webSocketUrl}.`\r\n );\r\n\r\n connect(webSocketUrl, connectionOptions, clientOptions);\r\n } else {\r\n clientOptions.reconnect = false;\r\n clearInterval(clientOptions.reconnectInterval);\r\n log(\r\n 2,\r\n `[websocket] WebSocket: ${clientOptions.id} - Could not reconnect to server: ${webSocketUrl}.`\r\n );\r\n }\r\n }, webSocketOptions.reconnectInterval);\r\n\r\n // Register interval for the later clearing\r\n addTimer(clientOptions.reconnectInterval);\r\n}\r\n\r\n/**\r\n * Gets map of current WebSocket clients.\r\n *\r\n * @param {string} id - The uuid of WebSocket client.\r\n */\r\nexport function getClients(id) {\r\n return id ? webSocketClients.get(id) : webSocketClients.values();\r\n}\r\n\r\n/**\r\n * Terminates all WebSocket clients and clear the webSocketClients map.\r\n */\r\nexport function terminateClients() {\r\n for (const client of webSocketClients.values()) {\r\n client.terminate();\r\n }\r\n webSocketClients.clear();\r\n}\r\n\r\nexport default {\r\n init,\r\n connect,\r\n getClients\r\n};\r\n","import ExportError from './ExportError.js';\r\n\r\nclass HttpError extends ExportError {\r\n constructor(message, status) {\r\n super(message);\r\n this.status = this.statusCode = status;\r\n }\r\n\r\n setStatus(status) {\r\n this.status = status;\r\n return this;\r\n }\r\n}\r\n\r\nexport default HttpError;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { updateVersion, version } from '../../cache.js';\r\nimport { envs } from '../../envs.js';\r\n\r\nimport HttpError from '../../errors/HttpError.js';\r\n\r\n/**\r\n * Adds the POST /change_hc_version/:newVersion route that can be utilized to modify\r\n * the Highcharts version on the server.\r\n *\r\n * TODO: Add auth token and connect to API\r\n */\r\nexport default (app) =>\r\n !app\r\n ? false\r\n : app.post(\r\n '/version/change/:newVersion',\r\n async (request, response, next) => {\r\n try {\r\n const adminToken = envs.HIGHCHARTS_ADMIN_TOKEN;\r\n\r\n // Check the existence of the token\r\n if (!adminToken || !adminToken.length) {\r\n throw new HttpError(\r\n 'The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.',\r\n 401\r\n );\r\n }\r\n\r\n // Check if the hc-auth header contain a correct token\r\n const token = request.get('hc-auth');\r\n if (!token || token !== adminToken) {\r\n throw new HttpError(\r\n 'Invalid or missing token: Set the token in the hc-auth header.',\r\n 401\r\n );\r\n }\r\n\r\n // Compare versions\r\n const newVersion = request.params.newVersion;\r\n if (newVersion) {\r\n try {\r\n // eslint-disable-next-line import/no-named-as-default-member\r\n await updateVersion(newVersion);\r\n } catch (error) {\r\n throw new HttpError(\r\n `Version change: ${error.message}`,\r\n error.statusCode\r\n ).setError(error);\r\n }\r\n\r\n // Success\r\n response.status(200).send({\r\n statusCode: 200,\r\n version: version(),\r\n message: `Successfully updated Highcharts to version: ${newVersion}.`\r\n });\r\n } else {\r\n // No version specified\r\n throw new HttpError('No new version supplied.', 400);\r\n }\r\n } catch (error) {\r\n next(error);\r\n }\r\n }\r\n );\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport { getAllowCodeExecution, startExport } from '../../chart.js';\r\nimport { getOptions, mergeConfigOptions } from '../../config.js';\r\nimport { log } from '../../logger.js';\r\nimport { prepareTelemetry } from '../../telemetry.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 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: ${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 // Prepare and send the options through the WebSocket\r\n prepareTelemetry(options.export.options, options.payload.requestId);\r\n\r\n if (info.result) {\r\n // If only base64 is required, return it\r\n if (body.b64) {\r\n // SVG Exception for the Highcharts 11.3.0 version\r\n if (type === 'pdf' || type == 'svg') {\r\n return response.send(\r\n Buffer.from(info.result, 'utf8').toString('base64')\r\n );\r\n }\r\n\r\n return response.send(info.result);\r\n }\r\n\r\n // Set correct content type\r\n response.header('Content-Type', reversedMime[type] || 'image/png');\r\n\r\n // Decide whether to download or not chart file\r\n if (!body.noDownload) {\r\n response.attachment(\r\n `${request.params.filename || request.body.filename || 'chart'}.${\r\n type || 'png'\r\n }`\r\n );\r\n }\r\n\r\n // If SVG, return plain content\r\n return type === 'svg'\r\n ? response.send(info.result)\r\n : response.send(Buffer.from(info.result, 'base64'));\r\n }\r\n });\r\n } catch (error) {\r\n next(error);\r\n }\r\n};\r\n\r\nexport default (app) => {\r\n /**\r\n * Adds the POST / a route for handling POST requests at the root endpoint.\r\n */\r\n app.post('/', exportHandler);\r\n\r\n /**\r\n * Adds the POST /:filename a route for handling POST requests with\r\n * a specified filename parameter.\r\n */\r\n app.post('/:filename', exportHandler);\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join as pather } from 'path';\r\nimport { log } from '../../logger.js';\r\n\r\nimport { version } from '../../cache.js';\r\nimport { addTimer } from '../../timers.js';\r\nimport { getStats, getPoolInfoJSON } 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 = 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 addTimer(startSuccessRate());\r\n\r\n app.get('/health', (_, res) => {\r\n const stats = getStats();\r\n const period = successRates.length;\r\n const movingAverage = calculateMovingAverage();\r\n\r\n log(4, '[health.js] GET /health [200] - returning server health.');\r\n\r\n res.send({\r\n status: 'OK',\r\n bootTime: serverStartTime,\r\n uptime:\r\n Math.floor(\r\n (new Date().getTime() - serverStartTime.getTime()) / 1000 / 60\r\n ) + ' minutes',\r\n version: pkgFile.version,\r\n highchartsVersion: version(),\r\n averageProcessingTime: stats.spentAverage,\r\n performedExports: stats.performedExports,\r\n failedExports: stats.droppedExports,\r\n exportAttempts: stats.exportAttempts,\r\n sucessRatio: (stats.performedExports / stats.exportAttempts) * 100,\r\n // eslint-disable-next-line import/no-named-as-default-member\r\n pool: 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 { init as webSocketInit } from './web_socket.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 // 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 if (activeServers.size === 1) {\r\n // Start a WebSocket connection\r\n webSocketInit({ ...httpServer.address(), protocol: 'http' });\r\n }\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 // 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 if (activeServers.size === 1) {\r\n // Start a WebSocket connection\r\n webSocketInit({ ...httpsServer.address(), protocol: 'https' });\r\n }\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 { clearAllTimers } from './timers.js';\r\nimport { killPool } from './pool.js';\r\nimport { closeServers } from './server/server.js';\r\nimport { terminateClients } from './server/web_socket.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 timers\r\n clearAllTimers(),\r\n\r\n // Terminate all connected WebSocket clients\r\n terminateClients(),\r\n\r\n // Get available server instances (HTTP/HTTPS) and close them\r\n closeServers(),\r\n\r\n // Close pool along with its workers and the browser instance, if exists\r\n killPool()\r\n ]);\r\n\r\n // Exit process with a correct code\r\n process.exit(exitCode);\r\n};\r\n\r\nexport default {\r\n shutdownCleanUp\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport 'colors';\r\n\r\nimport { checkAndUpdateCache } from './cache.js';\r\nimport {\r\n batchExport,\r\n setAllowCodeExecution,\r\n singleExport,\r\n startExport\r\n} from './chart.js';\r\nimport { mapToNewConfig, manualConfig, setOptions } from './config.js';\r\nimport {\r\n initLogging,\r\n log,\r\n logWithStack,\r\n setLogLevel,\r\n enableFileLogging\r\n} from './logger.js';\r\nimport { initPool, killPool } from './pool.js';\r\nimport { shutdownCleanUp } from './resource_release.js';\r\nimport server, { startServer } from './server/server.js';\r\nimport { printLogo, printUsage } from './utils.js';\r\n\r\n/**\r\n * Attaches exit listeners to the process, ensuring proper cleanup of resources\r\n * and termination on exit signals. Handles 'exit', 'SIGINT', 'SIGTERM', and\r\n * 'uncaughtException' events.\r\n */\r\nconst attachProcessExitListeners = () => {\r\n log(3, '[process] Attaching exit listeners to the process.');\r\n\r\n // Handler for the 'exit'\r\n process.on('exit', (code) => {\r\n log(4, `Process exited with code ${code}.`);\r\n });\r\n\r\n // Handler for the 'SIGINT'\r\n process.on('SIGINT', async (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'SIGTERM'\r\n process.on('SIGTERM', async (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'SIGHUP'\r\n process.on('SIGHUP', async (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'uncaughtException'\r\n process.on('uncaughtException', async (error, name) => {\r\n logWithStack(1, error, `The ${name} error.`);\r\n await shutdownCleanUp(1);\r\n });\r\n};\r\n\r\n/**\r\n * Initializes the export process. Tasks such as configuring logging, checking\r\n * cache and sources, and initializing the pool of resources happen during\r\n * this stage. Function that is required to be called before trying to export charts or setting a server. The `options` is an object that contains all options.\r\n *\r\n * @param {Object} options - All export options.\r\n *\r\n * @returns {Promise} Promise resolving to the updated export options.\r\n */\r\nconst initExport = async (options) => {\r\n // Set the allowCodeExecution per export module scope\r\n setAllowCodeExecution(\r\n options.customLogic && options.customLogic.allowCodeExecution\r\n );\r\n\r\n // Init the logging\r\n initLogging(options.logging);\r\n\r\n // Attach process' exit listeners\r\n if (options.other.listenToProcessExits) {\r\n attachProcessExitListeners();\r\n }\r\n\r\n // Check if cache needs to be updated\r\n await checkAndUpdateCache(options);\r\n\r\n // Init the pool\r\n await initPool({\r\n pool: options.pool || {\r\n minWorkers: 1,\r\n maxWorkers: 1\r\n },\r\n puppeteerArgs: options.puppeteer.args || []\r\n });\r\n\r\n // Return updated options\r\n return options;\r\n};\r\n\r\nexport default {\r\n // Server\r\n server,\r\n startServer,\r\n\r\n // Exporting\r\n initExport,\r\n singleExport,\r\n batchExport,\r\n startExport,\r\n\r\n // Pool\r\n initPool,\r\n killPool,\r\n\r\n // Other\r\n setOptions,\r\n shutdownCleanUp,\r\n\r\n // Logs\r\n log,\r\n logWithStack,\r\n setLogLevel,\r\n enableFileLogging,\r\n\r\n // Utils\r\n mapToNewConfig,\r\n manualConfig,\r\n printLogo,\r\n printUsage\r\n};\r\n"],"names":["scriptsNames","core","modules","indicators","defaultConfig","puppeteer","args","value","type","description","highcharts","version","envLink","cdnURL","coreScripts","moduleScripts","indicatorScripts","customScripts","forceFetch","cachePath","export","infile","instr","options","outfile","constr","defaultHeight","defaultWidth","defaultScale","height","width","scale","globalOptions","themeOptions","batch","rasterizationTimeout","customLogic","allowCodeExecution","allowFileResources","customCode","callback","resources","loadConfig","legacyName","createConfig","server","enable","cliName","host","port","benchmarking","proxy","timeout","rateLimiting","maxRequests","window","delay","trustProxy","skipKey","skipToken","ssl","force","certPath","pool","minWorkers","maxWorkers","workLimit","acquireTimeout","createTimeout","destroyTimeout","idleTimeout","createRetryInterval","reaperInterval","logging","level","file","dest","ui","route","other","nodeEnv","listenToProcessExits","noLogo","hardResetPage","browserShellMode","debug","headless","devtools","listenToConsole","dumpio","slowMo","debuggingPort","webSocket","reconnect","rejectUnauthorized","pingTimeout","reconnectInterval","reconnectAttempts","messageInterval","url","secret","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","OTHER_BROWSER_SHELL_MODE","DEBUG_ENABLE","DEBUG_HEADLESS","DEBUG_DEVTOOLS","DEBUG_LISTEN_TO_CONSOLE","DEBUG_DUMPIO","DEBUG_SLOW_MO","DEBUG_DEBUGGING_PORT","WEB_SOCKET_ENABLE","WEB_SOCKET_RECONNECT","WEB_SOCKET_REJECT_UNAUTHORIZED","WEB_SOCKET_PING_TIMEOUT","WEB_SOCKET_RECONNECT_INTERVAL","WEB_SOCKET_RECONNECT_ATTEMPTS","WEB_SOCKET_MESSAGE_INTERVAL","WEB_SOCKET_URL","WEB_SOCKET_SECRET","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","fixType","formats","outType","pop","find","t","handleResources","allowedProps","handledResources","correctResources","isCorrectJSON","readFileSync","files","propName","item","data","parsedData","JSON","stringify","deepCopy","copy","Array","isArray","prototype","hasOwnProperty","call","optionsStringify","allowFunctions","replaceAll","printUsage","bold","yellow","cycleCategories","descName","green","i","blue","category","toUpperCase","red","toBoolean","wrapAround","replace","measureTime","start","hrtime","bigint","Number","generalOptions","getOptions","mergeConfigOptions","newOptions","mergedOptions","updateDefaultConfig","configObj","customObj","customValue","initOptions","items","recursiveProps","objectToUpdate","nestedNames","shift","assign","async","fetch","requestOptions","Promise","resolve","reject","protocol","https","http","getProtocol","get","res","on","chunk","text","ExportError","Error","constructor","super","this","setError","statusCode","cache","activeManifest","sources","hcVersion","extractVersion","indexOf","fetchAndProcessScript","script","fetchedModules","shouldThrowError","response","updateCache","highchartsOptions","proxyOptions","sourcePath","proxyAgent","proxyHost","proxyPort","HttpsProxyAgent","agent","allFetchPromises","all","fetchScripts","c","m","writeFileSync","checkAndUpdateCache","manifestPath","requestUpdate","manifest","moduleMap","numberOfModules","some","moduleName","newManifest","saveConfigToManifest","getCachePath","setupHighcharts","Highcharts","animObject","duration","triggerExport","chartOptions","displayErrors","_displayErrors","merge","setOptions","wrap","setOptionsObj","Function","chart","animation","strInj","isRenderComplete","Chart","proceed","userOptions","cb","exporting","enabled","plotOptions","series","label","tooltip","onHighchartsRender","addEvent","Series","finalOptions","finalCallback","defaultOptions","prop","template","browser","newPage","page","setCacheEnabled","setPageContent","$eval","element","errorMessage","innerHTML","setPageEvents","clearPageResources","injectedResources","resource","dispose","evaluate","oldCharts","charts","oldChart","destroy","scriptsToRemove","document","getElementsByTagName","stylesToRemove","linksToRemove","remove","setContent","waitUntil","addScriptTag","path","setAsConfig","puppeteerExport","exportOptions","debugger","isSVG","svgTemplate","injectedJs","js","push","content","isLocal","jsResource","injectedCss","css","cssImports","match","cssImportPath","cssResource","addStyleTag","addPageResources","size","svgElement","querySelector","chartHeight","baseVal","chartWidth","body","style","zoom","margin","viewportHeight","Math","ceil","viewportWidth","x","y","getBoundingClientRect","trunc","getClipRegion","setViewport","deviceScaleFactor","outerHTML","createSVG","encoding","clip","race","screenshot","captureBeyondViewport","fullPage","optimizeForSpeed","quality","omitBackground","_resolve","setTimeout","createImage","emulateMediaType","pdf","createPDF","stats","performedExports","exportAttempts","exportFromSvgAttempts","timeSpent","droppedExports","spentAverage","poolConfig","factory","create","id","uuid","startDate","getTime","isClosed","workCount","random","validate","workerHandle","close","initPool","puppeteerArgs","enabledDebug","debugOptions","launchOptions","userDataDir","handleSIGINT","handleSIGTERM","handleSIGHUP","waitForInitialPage","defaultViewport","tryCount","open","launch","createBrowser","parseInt","Pool","acquireTimeoutMillis","createTimeoutMillis","destroyTimeoutMillis","idleTimeoutMillis","createRetryIntervalMillis","reapIntervalMillis","propagateCreateError","hardReset","goto","clearPage","eventId","initialResources","acquire","promise","release","killPool","worker","used","destroyed","connected","closeBrowser","postWork","available","pending","getPoolInfoJSON","getPoolInfo","acquireCounter","payload","requestId","workStart","exportCounter","result","exportTime","numFree","numUsed","numPendingAcquires","getStats","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","timerIds","addTimer","clearAllTimers","clearInterval","clearTimeout","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","telemetryTemplate","telemetryData","numberOfRequests","optionsInArray","filterData","filteredObject","templateKey","templateValue","index","optionsValue","prepareTelemetry","webSocketClients","Map","webSocketOptions","init","address","connectionOptions","headers","auth","jwt","sign","success","algorithm","clientOptions","reconnectTry","connect","setInterval","webSocketClient","readyState","WebSocket","OPEN","sendingMessageInterval","webSocketUrl","set","code","delete","terminate","terminateClients","client","clear","HttpError","setStatus","vSwitchRoute","post","adminToken","token","newVersion","params","updateVersion","reversedMime","png","jpeg","gif","requestsCounter","beforeRequest","afterRequest","doCallbacks","callbacks","uniqueId","callResponse","exportHandler","stopCounter","connection","remoteAddress","connectionAborted","socket","toLowerCase","substr","b64","noDownload","pattern","isPrivateRangeUrlFound","info","removeAllListeners","Buffer","from","header","attachment","filename","pkgFile","pather","serverStartTime","successRates","addHealthRoutes","successRatio","_","period","movingAverage","reduce","a","b","bootTime","uptime","floor","highchartsVersion","averageProcessingTime","failedExports","sucessRatio","toFixed","svgExportAttempts","jsonExportAttempts","activeServers","express","disable","cors","storage","multer","memoryStorage","upload","limits","fieldSize","limit","urlencoded","extended","none","attachServerErrorHandlers","startServer","serverConfig","httpServer","createServer","listen","webSocketInit","cert","fsPromises","readFile","posix","httpsServer","NaN","static","healthRoute","exportRoutes","sendFile","uiRoute","errorHandler","closeServers","getServers","enableRateLimiting","getExpress","getApp","middlewares","shutdownCleanUp","exitCode","allSettled","exit","initExport","initLogging","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":"woBAeO,MAAMA,EAAe,CAC1BC,KAAM,CAAC,aAAc,kBAAmB,iBACxCC,QAAS,CACP,QACA,MACA,QACA,YACA,cACA,uBACA,gBAEA,eACA,QACA,OACA,aACA,mBACA,eACA,cACA,UACA,UACA,cACA,WACA,UACA,YACA,cACA,YACA,sBACA,SACA,SACA,WACA,aACA,YACA,eACA,yBACA,SACA,eACA,YACA,kBACA,SACA,cACA,mBACA,eACA,cACA,eAEA,cACA,WACA,eACA,WACA,SACA,OACA,WACA,YACA,SACA,qBACA,aACA,WACA,WACA,WACA,WACA,eACA,UACA,kBACA,oBACA,aACA,WAEFC,WAAY,CAAC,mBAKFC,EAAgB,CAC3BC,UAAW,CACTC,KAAM,CACJC,MAAO,CACL,mCACA,kBACA,0CACA,2BACA,kCACA,kCACA,wCACA,2CACA,qBACA,4BACA,2CACA,uDACA,6BACA,yBACA,0BACA,+BACA,uBACA,uFACA,yBACA,oCACA,oBACA,0BACA,8CACA,2BACA,0BACA,6BACA,mCACA,wCACA,mCACA,2BACA,kCACA,uBACA,iBACA,yBACA,8BACA,oBACA,2BACA,eACA,6BACA,iBACA,aACA,eACA,sBACA,cACA,yBACA,oBACA,uBAEFC,KAAM,WACNC,YAAa,0CAGjBC,WAAY,CACVC,QAAS,CACPJ,MAAO,SACPC,KAAM,SACNI,QAAS,qBACTH,YAAa,sCAEfI,OAAQ,CACNN,MAAO,+BACPC,KAAM,SACNI,QAAS,qBACTH,YAAa,kDAEfK,YAAa,CACXP,MAAOP,EAAaC,KACpBO,KAAM,WACNI,QAAS,0BACTH,YAAa,yCAEfM,cAAe,CACbR,MAAOP,EAAaE,QACpBM,KAAM,WACNI,QAAS,4BACTH,YAAa,uCAEfO,iBAAkB,CAChBT,MAAOP,EAAaG,WACpBK,KAAM,WACNI,QAAS,+BACTH,YAAa,0CAEfQ,cAAe,CACbV,MAAO,CACL,wEACA,kGAEFC,KAAM,WACNC,YAAa,uDAEfS,WAAY,CACVX,OAAO,EACPC,KAAM,UACNI,QAAS,yBACTH,YACE,iFAEJU,UAAW,CACTZ,MAAO,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"} \ No newline at end of file +{"version":3,"file":"index.esm.js","sources":["../lib/schemas/config.js","../lib/envs.js","../lib/logger.js","../lib/utils.js","../lib/config.js","../lib/fetch.js","../lib/errors/ExportError.js","../lib/cache.js","../lib/highcharts.js","../lib/browser.js","../lib/export.js","../templates/svg_export/svg_export.js","../lib/pool.js","../lib/chart.js","../lib/sanitize.js","../lib/timers.js","../lib/server/error.js","../lib/server/rate_limit.js","../lib/telemetry.js","../lib/server/web_socket.js","../lib/errors/HttpError.js","../lib/server/routes/change_hc_version.js","../lib/server/routes/export.js","../lib/server/routes/health.js","../lib/server/server.js","../lib/server/routes/ui.js","../lib/resource_release.js","../lib/index.js"],"sourcesContent":["/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n// Possible names for Highcharts scripts\r\nexport const scriptsNames = {\r\n core: ['highcharts', 'highcharts-more', 'highcharts-3d'],\r\n modules: [\r\n 'stock',\r\n 'map',\r\n 'gantt',\r\n 'exporting',\r\n '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 'series-on-point',\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 'export-data',\r\n 'navigator',\r\n 'textpath'\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 browserShellMode: {\r\n value: true,\r\n type: 'boolean',\r\n envLink: 'OTHER_BROWSER_SHELL_MODE',\r\n description: 'Decides if the browser runs in the shell mode.'\r\n }\r\n },\r\n debug: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'DEBUG_ENABLE',\r\n cliName: 'enableDebug',\r\n description: 'Enables or disables debug mode for the underlying browser.'\r\n },\r\n headless: {\r\n value: true,\r\n type: 'boolean',\r\n envLink: 'DEBUG_HEADLESS',\r\n description:\r\n 'Controls the mode in which the browser is launched when in the debug mode.'\r\n },\r\n devtools: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'DEBUG_DEVTOOLS',\r\n description:\r\n 'Decides whether to enable DevTools when the browser is in a headful state.'\r\n },\r\n listenToConsole: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'DEBUG_LISTEN_TO_CONSOLE',\r\n description:\r\n 'Decides whether to enable a listener for console messages sent from the browser.'\r\n },\r\n dumpio: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'DEBUG_DUMPIO',\r\n description:\r\n 'Redirects browser process stdout and stderr to process.stdout and process.stderr.'\r\n },\r\n slowMo: {\r\n value: 0,\r\n type: 'number',\r\n envLink: 'DEBUG_SLOW_MO',\r\n description:\r\n 'Slows down Puppeteer operations by the specified number of milliseconds.'\r\n },\r\n debuggingPort: {\r\n value: 9222,\r\n type: 'number',\r\n envLink: 'DEBUG_DEBUGGING_PORT',\r\n description: 'Specifies the debugging port.'\r\n }\r\n },\r\n webSocket: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'WEB_SOCKET_ENABLE',\r\n cliName: 'enableWs',\r\n description: 'Enables or disables the WebSocket connection.'\r\n },\r\n reconnect: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'WEB_SOCKET_RECONNECT',\r\n cliName: 'wsReconnect',\r\n description:\r\n 'Controls whether or not to try reconnecting to the WebSocket server in case of a disconnect.'\r\n },\r\n rejectUnauthorized: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'WEB_SOCKET_REJECT_UNAUTHORIZED',\r\n cliName: 'wsrejectUnauthorized',\r\n description:\r\n \"Determines whether the client verifies the server's SSL/TLS certificate during the handshake process.\"\r\n },\r\n pingTimeout: {\r\n value: 16000,\r\n type: 'number',\r\n envLink: 'WEB_SOCKET_PING_TIMEOUT',\r\n cliName: 'wsPingTimeout',\r\n description:\r\n 'The timeout, in milliseconds, for the heartbeat mechanism between the client and server.'\r\n },\r\n reconnectInterval: {\r\n value: 3000,\r\n type: 'number',\r\n envLink: 'WEB_SOCKET_RECONNECT_INTERVAL',\r\n cliName: 'wsReconnectInterval',\r\n description: 'The interval, in milliseconds, for the reconnect attempt.'\r\n },\r\n reconnectAttempts: {\r\n value: 3,\r\n type: 'number',\r\n envLink: 'WEB_SOCKET_RECONNECT_ATTEMPTS',\r\n cliName: 'wsReconnectAttempts',\r\n description:\r\n 'The number of reconnect attempts before returning a connection error.'\r\n },\r\n messageInterval: {\r\n value: 3,\r\n type: 'number',\r\n envLink: 'WEB_SOCKET_MESSAGE_INTERVAL',\r\n cliName: 'wsMessageInterval',\r\n description:\r\n 'The interval, in milliseconds, for auto sending the data through a WebSocket connection.'\r\n },\r\n url: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'WEB_SOCKET_URL',\r\n cliName: 'wsUrl',\r\n description: 'The URL of the WebSocket server.'\r\n },\r\n secret: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'WEB_SOCKET_SECRET',\r\n cliName: 'wsSecret',\r\n description:\r\n 'The secret used to create a JSON Web Token sent to the WebSocket server.'\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 type: 'toggle',\r\n name: 'browserShellMode',\r\n message: 'Decides if the browser runs in the shell mode',\r\n initial: defaultConfig.other.browserShellMode.value\r\n }\r\n ],\r\n debug: [\r\n {\r\n type: 'toggle',\r\n name: 'enable',\r\n message: 'Enables debug mode for the browser instance',\r\n initial: defaultConfig.debug.enable.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'headless',\r\n message: 'The mode setting for the browser',\r\n initial: defaultConfig.debug.headless.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'devtools',\r\n message: 'The DevTools for the headful browser',\r\n initial: defaultConfig.debug.devtools.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'listenToConsole',\r\n message: 'The event listener for console messages from the browser',\r\n initial: defaultConfig.debug.listenToConsole.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'dumpio',\r\n message: 'Redirects the browser stdout and stderr to NodeJS process',\r\n initial: defaultConfig.debug.dumpio.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'slowMo',\r\n message: 'Puppeteer operations slow down in milliseconds',\r\n initial: defaultConfig.debug.slowMo.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'debuggingPort',\r\n message: 'The port number for debugging',\r\n initial: defaultConfig.debug.debuggingPort.value\r\n }\r\n ],\r\n webSocket: [\r\n {\r\n type: 'toggle',\r\n name: 'enable',\r\n message: 'Enables WebSocket connection',\r\n initial: defaultConfig.webSocket.enable.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'reconnect',\r\n message: 'The reconnect mechanism for WebSocket connection',\r\n initial: defaultConfig.webSocket.reconnect.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'rejectUnauthorized',\r\n message: 'Reject connection if WebSocket is not secured, SSL/TLS',\r\n initial: defaultConfig.webSocket.rejectUnauthorized.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'pingTimeout',\r\n message: 'Timeout for the hearbeat mechanism',\r\n initial: defaultConfig.webSocket.pingTimeout.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'reconnectInterval',\r\n message: 'Interval for the reconnect mechanism',\r\n initial: defaultConfig.webSocket.reconnectInterval.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'reconnectAttempts',\r\n message: 'The number of reconnect attempts',\r\n initial: defaultConfig.webSocket.reconnectAttempts.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'messageInterval',\r\n message: 'Interval for auto sending the data',\r\n initial: defaultConfig.webSocket.messageInterval.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'url',\r\n message: 'The URL of the WebSocket server',\r\n initial: defaultConfig.webSocket.url.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'secret',\r\n message: 'The secret for the JWT to WebSocket server',\r\n initial: defaultConfig.webSocket.secret.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 OTHER_BROWSER_SHELL_MODE: 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 // websocket\r\n WEB_SOCKET_ENABLE: v.boolean(),\r\n WEB_SOCKET_RECONNECT: v.boolean(),\r\n WEB_SOCKET_REJECT_UNAUTHORIZED: v.boolean(),\r\n WEB_SOCKET_PING_TIMEOUT: v.nonNegativeNum(),\r\n WEB_SOCKET_RECONNECT_INTERVAL: v.nonNegativeNum(),\r\n WEB_SOCKET_RECONNECT_ATTEMPTS: v.nonNegativeNum(),\r\n WEB_SOCKET_MESSAGE_INTERVAL: v.nonNegativeNum(),\r\n WEB_SOCKET_URL: v.string(),\r\n WEB_SOCKET_SECRET: v.string()\r\n});\r\n\r\nexport const envs = Config.partial().parse(process.env);\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { appendFile, existsSync, mkdirSync } from 'fs';\r\n\r\nimport { defaultConfig } from './schemas/config.js';\r\n\r\n// The available colors\r\nconst colors = ['red', 'yellow', 'blue', 'gray', 'green'];\r\n\r\n// The default logging config\r\nlet logging = {\r\n // Flags for logging status\r\n toConsole: true,\r\n toFile: false,\r\n pathCreated: false,\r\n // Log levels\r\n levelsDesc: [\r\n {\r\n title: 'error',\r\n color: colors[0]\r\n },\r\n {\r\n title: 'warning',\r\n color: colors[1]\r\n },\r\n {\r\n title: 'notice',\r\n color: colors[2]\r\n },\r\n {\r\n title: 'verbose',\r\n color: colors[3]\r\n },\r\n {\r\n title: 'benchmark',\r\n color: colors[4]\r\n }\r\n ],\r\n // Log listeners\r\n listeners: []\r\n};\r\n\r\n// Gather init logging options\r\nfor (const [key, option] of Object.entries(defaultConfig.logging)) {\r\n logging[key] = option.value;\r\n}\r\n\r\n/**\r\n * Logs the provided texts to a file, if file logging is enabled. It creates\r\n * the necessary directory structure if not already created and appends the\r\n * content, including an optional prefix, to the specified log file.\r\n *\r\n * @param {string[]} texts - An array of texts to be logged.\r\n * @param {string} prefix - An optional prefix to be added to each log entry.\r\n */\r\nconst logToFile = (texts, prefix) => {\r\n if (logging.toFile) {\r\n if (!logging.pathCreated) {\r\n // Create if does not exist\r\n !existsSync(logging.dest) && mkdirSync(logging.dest);\r\n\r\n // We now assume the path is available, e.g. it's the responsibility\r\n // of the user to create the path with the correct access rights.\r\n logging.pathCreated = true;\r\n }\r\n\r\n // Add the content to a file\r\n appendFile(\r\n `${logging.dest}${logging.file}`,\r\n [prefix].concat(texts).join(' ') + '\\n',\r\n (error) => {\r\n if (error) {\r\n console.log(`[logger] Unable to write to log file: ${error}`);\r\n logging.toFile = false;\r\n }\r\n }\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Logs a message. Accepts a variable amount of arguments. Arguments after\r\n * `level` will be passed directly to console.log, and/or will be joined\r\n * and appended to the log file.\r\n *\r\n * @param {any} args - An array of arguments where the first is the log level\r\n * and the rest are strings to build a message with.\r\n */\r\nexport const log = (...args) => {\r\n const [newLevel, ...texts] = args;\r\n\r\n // Current logging options\r\n const { level, levelsDesc } = logging;\r\n\r\n // Check if log level is within a correct range or is a benchmark log\r\n if (\r\n newLevel !== 5 &&\r\n (newLevel === 0 || newLevel > level || level > levelsDesc.length)\r\n ) {\r\n return;\r\n }\r\n\r\n // Get rid of the GMT text information\r\n const newDate = new Date().toString().split('(')[0].trim();\r\n\r\n // Create a message's prefix\r\n const prefix = `${newDate} [${levelsDesc[newLevel - 1].title}] -`;\r\n\r\n // Call available log listeners\r\n logging.listeners.forEach((fn) => {\r\n fn(prefix, texts.join(' '));\r\n });\r\n\r\n // Log to console\r\n if (logging.toConsole) {\r\n console.log.apply(\r\n undefined,\r\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat(texts)\r\n );\r\n }\r\n\r\n // Log to file\r\n logToFile(texts, prefix);\r\n};\r\n\r\n/**\r\n * Logs an error message with its stack trace. Optionally, a custom message\r\n * can be provided.\r\n *\r\n * @param {number} level - The log level.\r\n * @param {Error} error - The error object.\r\n * @param {string} customMessage - An optional custom message to be logged along\r\n * with the error.\r\n */\r\nexport const logWithStack = (newLevel, error, customMessage) => {\r\n // Get the main message\r\n const mainMessage = customMessage || error.message;\r\n\r\n // Current logging options\r\n const { level, levelsDesc } = logging;\r\n\r\n // Check if log level is within a correct range\r\n if (newLevel === 0 || newLevel > level || level > levelsDesc.length) {\r\n return;\r\n }\r\n\r\n // Get rid of the GMT text information\r\n const newDate = new Date().toString().split('(')[0].trim();\r\n\r\n // Create a message's prefix\r\n const prefix = `${newDate} [${levelsDesc[newLevel - 1].title}] -`;\r\n\r\n // If the customMessage exists, we want to display the whole stack message\r\n const stackMessage =\r\n error.message !== error.stackMessage || error.stackMessage === undefined\r\n ? error.stack\r\n : error.stack.split('\\n').slice(1).join('\\n');\r\n\r\n // Combine custom message or error message with error stack message\r\n const texts = [mainMessage, '\\n', stackMessage];\r\n\r\n // Log to console\r\n if (logging.toConsole) {\r\n console.log.apply(\r\n undefined,\r\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat([\r\n mainMessage[colors[newLevel - 1]],\r\n '\\n',\r\n stackMessage\r\n ])\r\n );\r\n }\r\n\r\n // Call available log listeners\r\n logging.listeners.forEach((fn) => {\r\n fn(prefix, texts.join(' '));\r\n });\r\n\r\n // Log to file\r\n logToFile(texts, prefix);\r\n};\r\n\r\n/**\r\n * Sets the log level to the specified value. Log levels are (0 = no logging,\r\n * 1 = error, 2 = warning, 3 = notice, 4 = verbose or 5 = benchmark)\r\n *\r\n * @param {number} newLevel - The new log level to be set.\r\n */\r\nexport const setLogLevel = (newLevel) => {\r\n if (newLevel >= 0 && newLevel <= logging.levelsDesc.length) {\r\n logging.level = newLevel;\r\n }\r\n};\r\n\r\n/**\r\n * Enables file logging with the specified destination and log file.\r\n *\r\n * @param {string} logDest - The destination path for log files.\r\n * @param {string} logFile - The log file name.\r\n */\r\nexport const enableFileLogging = (logDest, logFile) => {\r\n // Update logging options\r\n logging = {\r\n ...logging,\r\n dest: logDest || logging.dest,\r\n file: logFile || logging.file,\r\n toFile: true\r\n };\r\n\r\n if (logging.dest.length === 0) {\r\n return log(1, '[logger] File logging initialization: no path supplied.');\r\n }\r\n\r\n if (!logging.dest.endsWith('/')) {\r\n logging.dest += '/';\r\n }\r\n};\r\n\r\n/**\r\n * Initializes logging with the specified logging configuration.\r\n *\r\n * @param {Object} logging - The logging configuration object.\r\n */\r\nexport const initLogging = (logging) => {\r\n // Set the log level\r\n setLogLevel(logging && parseInt(logging.level));\r\n\r\n // Set the log file path and name\r\n if (logging && logging.dest) {\r\n enableFileLogging(\r\n logging.dest,\r\n logging.file || 'highcharts-export-server.log'\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Adds a listener function to the logging system.\r\n *\r\n * @param {function} fn - The listener function to be added.\r\n */\r\nexport const listen = (fn) => {\r\n logging.listeners.push(fn);\r\n};\r\n\r\n/**\r\n * Toggles the standard output (console) logging.\r\n *\r\n * @param {boolean} enabled - If true, enables console logging; if false,\r\n * disables it.\r\n */\r\nexport const toggleSTDOut = (enabled) => {\r\n logging.toConsole = enabled;\r\n};\r\n\r\nexport default {\r\n log,\r\n logWithStack,\r\n setLogLevel,\r\n enableFileLogging,\r\n initLogging,\r\n listen,\r\n toggleSTDOut\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\nimport { fileURLToPath } from 'url';\r\n\r\nimport { defaultConfig } from '../lib/schemas/config.js';\r\nimport { log, logWithStack } from './logger.js';\r\n\r\nconst MAX_BACKOFF_ATTEMPTS = 6;\r\n\r\nexport const __dirname = fileURLToPath(new URL('../.', import.meta.url));\r\n\r\n/**\r\n * Clears and standardizes text by replacing multiple consecutive whitespace\r\n * characters with a single space and trimming any leading or trailing\r\n * whitespace.\r\n *\r\n * @param {string} text - The input text to be cleared.\r\n * @param {RegExp} [rule=/\\s\\s+/g] - The regular expression rule to match\r\n * multiple consecutive whitespace characters.\r\n * @param {string} [replacer=' '] - The string used to replace multiple\r\n * consecutive whitespace characters.\r\n *\r\n * @returns {string} - The cleared and standardized text.\r\n */\r\nexport const clearText = (text, rule = /\\s\\s+/g, replacer = ' ') =>\r\n text.replaceAll(rule, replacer).trim();\r\n\r\n/**\r\n * Implements an exponential backoff strategy for retrying a function until\r\n * a certain number of attempts are reached.\r\n *\r\n * @param {Function} fn - The function to be retried.\r\n * @param {number} [attempt=0] - The current attempt number.\r\n * @param {...any} args - Arguments to be passed to the function.\r\n *\r\n * @returns {Promise} - A promise that resolves to the result of the function\r\n * if successful.\r\n *\r\n * @throws {Error} - Throws an error if the maximum number of attempts\r\n * is reached.\r\n */\r\nexport const expBackoff = async (fn, attempt = 0, ...args) => {\r\n try {\r\n // Try to call the function\r\n return await fn(...args);\r\n } catch (error) {\r\n // Calculate delay in ms\r\n const delayInMs = 2 ** attempt * 1000;\r\n\r\n // If the attempt exceeds the maximum attempts of reapeat, throw an error\r\n if (++attempt >= MAX_BACKOFF_ATTEMPTS) {\r\n throw error;\r\n }\r\n\r\n // Wait given amount of time\r\n await new Promise((response) => setTimeout(response, delayInMs));\r\n log(\r\n 3,\r\n `[pool] Waited ${delayInMs}ms until next call for the resource id: ${args[0]}.`\r\n );\r\n\r\n // Try again\r\n return expBackoff(fn, attempt, ...args);\r\n }\r\n};\r\n\r\n/**\r\n * Fixes the export type based on MIME types and file extensions.\r\n *\r\n * @param {string} type - The original export type.\r\n * @param {string} outfile - The file path or name.\r\n *\r\n * @returns {string} - The corrected export type.\r\n */\r\nexport const fixType = (type, outfile) => {\r\n // MIME types\r\n const mimeTypes = {\r\n 'image/png': 'png',\r\n 'image/jpeg': 'jpeg',\r\n 'application/pdf': 'pdf',\r\n 'image/svg+xml': 'svg'\r\n };\r\n\r\n // Formats\r\n const formats = ['png', 'jpeg', 'pdf', 'svg'];\r\n\r\n // Check if type and outfile's extensions are the same\r\n if (outfile) {\r\n const outType = outfile.split('.').pop();\r\n\r\n if (outType === 'jpg') {\r\n type = 'jpeg';\r\n } else if (formats.includes(outType) && type !== outType) {\r\n type = outType;\r\n }\r\n }\r\n\r\n // Return a correct type\r\n return mimeTypes[type] || formats.find((t) => t === type) || 'png';\r\n};\r\n\r\n/**\r\n * Handles and validates resources for export.\r\n *\r\n * @param {Object|string} resources - The resources to be handled. Can be either\r\n * a JSON object, stringified JSON or a path to a JSON file.\r\n * @param {boolean} allowFileResources - Whether to allow loading resources from\r\n * files.\r\n *\r\n * @returns {Object|undefined} - The handled resources or undefined if no valid\r\n * resources are found.\r\n */\r\nexport const handleResources = (resources = false, allowFileResources) => {\r\n const allowedProps = ['js', 'css', 'files'];\r\n\r\n let handledResources = resources;\r\n let correctResources = false;\r\n\r\n // Try to load resources from a file\r\n if (allowFileResources && resources.endsWith('.json')) {\r\n try {\r\n handledResources = isCorrectJSON(readFileSync(resources, 'utf8'));\r\n } catch (error) {\r\n return logWithStack(2, error, `[cli] No resources found.`);\r\n }\r\n } else {\r\n // Try to get JSON\r\n handledResources = isCorrectJSON(resources);\r\n\r\n // Get rid of the files section\r\n if (handledResources && !allowFileResources) {\r\n delete handledResources.files;\r\n }\r\n }\r\n\r\n // Filter from unnecessary properties\r\n for (const propName in handledResources) {\r\n if (!allowedProps.includes(propName)) {\r\n delete handledResources[propName];\r\n } else if (!correctResources) {\r\n correctResources = true;\r\n }\r\n }\r\n\r\n // Check if at least one of allowed properties is present\r\n if (!correctResources) {\r\n return log(3, `[cli] No resources found.`);\r\n }\r\n\r\n // Handle files section\r\n if (handledResources.files) {\r\n handledResources.files = handledResources.files.map((item) => item.trim());\r\n if (!handledResources.files || handledResources.files.length <= 0) {\r\n delete handledResources.files;\r\n }\r\n }\r\n\r\n // Return resources\r\n return handledResources;\r\n};\r\n\r\n/**\r\n * Validates and parses JSON data. Checks if provided data is or can\r\n * be a correct JSON. If a primitive is provided, it is stringified and returned.\r\n *\r\n * @param {Object|string} data - The JSON data to be validated and parsed.\r\n * @param {boolean} toString - Whether to return a stringified representation\r\n * of the parsed JSON.\r\n *\r\n * @returns {Object|string|boolean} - The parsed JSON object, stringified JSON,\r\n * or false if validation fails.\r\n */\r\nexport function isCorrectJSON(data, toString) {\r\n try {\r\n // Get the string representation if not already before parsing\r\n const parsedData = JSON.parse(\r\n typeof data !== 'string' ? JSON.stringify(data) : data\r\n );\r\n\r\n // Return a stringified representation of a JSON if required\r\n if (typeof parsedData !== 'string' && toString) {\r\n return JSON.stringify(parsedData);\r\n }\r\n\r\n // Return a JSON\r\n return parsedData;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Checks if the given item is an object.\r\n *\r\n * @param {any} item - The item to be checked.\r\n *\r\n * @returns {boolean} - True if the item is an object, false otherwise.\r\n */\r\nexport const isObject = (item) =>\r\n typeof item === 'object' && !Array.isArray(item) && item !== null;\r\n\r\n/**\r\n * Checks if the given object is empty.\r\n *\r\n * @param {Object} item - The object to be checked.\r\n *\r\n * @returns {boolean} - True if the object is empty, false otherwise.\r\n */\r\nexport const isObjectEmpty = (item) =>\r\n typeof item === 'object' &&\r\n !Array.isArray(item) &&\r\n item !== null &&\r\n Object.keys(item).length === 0;\r\n\r\n/**\r\n * Checks if a private IP range URL is found in the given string.\r\n *\r\n * @param {string} item - The string to be checked for a private IP range URL.\r\n *\r\n * @returns {boolean} - True if a private IP range URL is found, false\r\n * otherwise.\r\n */\r\nexport const isPrivateRangeUrlFound = (item) => {\r\n const regexPatterns = [\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?localhost\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?172\\.(1[6-9]|2[0-9]|3[0-1])\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?192\\.168\\.\\d{1,3}\\.\\d{1,3}\\b/\r\n ];\r\n\r\n return regexPatterns.some((pattern) => pattern.test(item));\r\n};\r\n\r\n/**\r\n * Creates a deep copy of the given object or array.\r\n *\r\n * @param {Object|Array} obj - The object or array to be deeply copied.\r\n *\r\n * @returns {Object|Array} - The deep copy of the provided object or array.\r\n */\r\nexport const deepCopy = (obj) => {\r\n if (obj === null || typeof obj !== 'object') {\r\n return obj;\r\n }\r\n\r\n const copy = Array.isArray(obj) ? [] : {};\r\n\r\n for (const key in obj) {\r\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\r\n copy[key] = deepCopy(obj[key]);\r\n }\r\n }\r\n\r\n return copy;\r\n};\r\n\r\n/**\r\n * Converts the provided options object to a JSON-formatted string with the\r\n * option to preserve functions.\r\n *\r\n * @param {Object} options - The options object to be converted to a string.\r\n * @param {boolean} allowFunctions - If set to true, functions are preserved\r\n * in the output.\r\n *\r\n * @returns {string} - The JSON-formatted string representing the options.\r\n */\r\nexport const optionsStringify = (options, allowFunctions) => {\r\n const replacerCallback = (name, value) => {\r\n if (typeof value === 'string') {\r\n value = value.trim();\r\n\r\n // If allowFunctions is set to true, preserve functions\r\n if (\r\n (value.startsWith('function(') || value.startsWith('function (')) &&\r\n value.endsWith('}')\r\n ) {\r\n value = allowFunctions\r\n ? `EXP_FUN${(value + '').replaceAll(/\\n|\\t|\\r/g, ' ')}EXP_FUN`\r\n : undefined;\r\n }\r\n }\r\n\r\n return typeof value === 'function'\r\n ? `EXP_FUN${(value + '').replaceAll(/\\n|\\t|\\r/g, ' ')}EXP_FUN`\r\n : value;\r\n };\r\n\r\n // Stringify options and if required, replace special functions marks\r\n return JSON.stringify(options, replacerCallback).replaceAll(\r\n /\"EXP_FUN|EXP_FUN\"/g,\r\n ''\r\n );\r\n};\r\n\r\n/**\r\n * Prints the Highcharts Export Server logo and version information.\r\n *\r\n * @param {boolean} noLogo - If true, only prints version information without\r\n * the logo.\r\n */\r\nexport const printLogo = (noLogo) => {\r\n // Get package version either from env or from package.json\r\n const packageVersion = JSON.parse(\r\n readFileSync(join(__dirname, 'package.json'))\r\n ).version;\r\n\r\n // Print text only\r\n if (noLogo) {\r\n console.log(`Starting Highcharts Export Server v${packageVersion}...`);\r\n return;\r\n }\r\n\r\n // Print the logo\r\n console.log(\r\n readFileSync(__dirname + '/msg/startup.msg').toString().bold.yellow,\r\n `v${packageVersion}\\n`.bold\r\n );\r\n};\r\n\r\n/**\r\n * Prints the usage information for CLI arguments. If required, it can list\r\n * properties recursively\r\n */\r\nexport function printUsage() {\r\n const pad = 48;\r\n const readme = 'https://github.com/highcharts/node-export-server#readme';\r\n\r\n // Display readme information\r\n console.log(\r\n '\\nUsage of CLI arguments:'.bold,\r\n '\\n------',\r\n `\\nFor more detailed information, visit the readme at: ${readme.bold.yellow}.`\r\n );\r\n\r\n const cycleCategories = (options) => {\r\n for (const [name, option] of Object.entries(options)) {\r\n // If category has more levels, go further\r\n if (!Object.prototype.hasOwnProperty.call(option, 'value')) {\r\n cycleCategories(option);\r\n } else {\r\n let descName = ` --${option.cliName || name} ${\r\n ('<' + option.type + '>').green\r\n } `;\r\n if (descName.length < pad) {\r\n for (let i = descName.length; i < pad; i++) {\r\n descName += '.';\r\n }\r\n }\r\n\r\n // Display correctly aligned messages\r\n console.log(\r\n descName,\r\n option.description,\r\n `[Default: ${option.value.toString().bold}]`.blue\r\n );\r\n }\r\n }\r\n };\r\n\r\n // Cycle through options of each categories and display the usage info\r\n Object.keys(defaultConfig).forEach((category) => {\r\n // Only puppeteer and highcharts categories cannot be configured through CLI\r\n if (!['puppeteer', 'highcharts'].includes(category)) {\r\n console.log(`\\n${category.toUpperCase()}`.red);\r\n cycleCategories(defaultConfig[category]);\r\n }\r\n });\r\n console.log('\\n');\r\n}\r\n\r\n/**\r\n * Rounds a number to the specified precision.\r\n *\r\n * @param {number} value - The number to be rounded.\r\n * @param {number} precision - The number of decimal places to round to.\r\n *\r\n * @returns {number} - The rounded number.\r\n */\r\nexport const roundNumber = (value, precision = 1) => {\r\n const multiplier = Math.pow(10, precision || 0);\r\n return Math.round(+value * multiplier) / multiplier;\r\n};\r\n\r\n/**\r\n * Converts a value to a boolean.\r\n *\r\n * @param {any} item - The value to be converted to a boolean.\r\n *\r\n * @returns {boolean} - The boolean representation of the input value.\r\n */\r\nexport const toBoolean = (item) =>\r\n ['false', 'undefined', 'null', 'NaN', '0', ''].includes(item)\r\n ? false\r\n : !!item;\r\n\r\n/**\r\n * Wraps custom code to execute it safely.\r\n *\r\n * @param {string} customCode - The custom code to be wrapped.\r\n * @param {boolean} allowFileResources - Flag to allow loading code from a file.\r\n *\r\n * @returns {string|boolean} - The wrapped custom code or false if wrapping\r\n * fails.\r\n */\r\nexport const wrapAround = (customCode, allowFileResources) => {\r\n if (customCode && typeof customCode === 'string') {\r\n customCode = customCode.trim();\r\n\r\n if (customCode.endsWith('.js')) {\r\n return allowFileResources\r\n ? wrapAround(readFileSync(customCode, 'utf8'))\r\n : false;\r\n } else if (\r\n customCode.startsWith('function()') ||\r\n customCode.startsWith('function ()') ||\r\n customCode.startsWith('()=>') ||\r\n customCode.startsWith('() =>')\r\n ) {\r\n return `(${customCode})()`;\r\n }\r\n return customCode.replace(/;$/, '');\r\n }\r\n};\r\n\r\n/**\r\n * Utility to measure elapsed time using the Node.js process.hrtime() method.\r\n *\r\n * @returns {function(): number} - A function to calculate the elapsed time\r\n * in milliseconds.\r\n */\r\nexport const measureTime = () => {\r\n const start = process.hrtime.bigint();\r\n return () => Number(process.hrtime.bigint() - start) / 1000000;\r\n};\r\n\r\nexport default {\r\n __dirname,\r\n clearText,\r\n expBackoff,\r\n fixType,\r\n handleResources,\r\n isCorrectJSON,\r\n isObject,\r\n isObjectEmpty,\r\n isPrivateRangeUrlFound,\r\n optionsStringify,\r\n printLogo,\r\n printUsage,\r\n roundNumber,\r\n toBoolean,\r\n wrapAround,\r\n measureTime\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { existsSync, readFileSync, promises as fsPromises } from 'fs';\r\n\r\nimport prompts from 'prompts';\r\n\r\nimport {\r\n absoluteProps,\r\n defaultConfig,\r\n nestedArgs,\r\n promptsConfig\r\n} from './schemas/config.js';\r\nimport { envs } from './envs.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { deepCopy, isObject, printUsage, toBoolean } from './utils.js';\r\n\r\nlet generalOptions = {};\r\n\r\n/**\r\n * Retrieves and returns the general options for the export process.\r\n *\r\n * @returns {Object} The general options object.\r\n */\r\nexport const getOptions = () => generalOptions;\r\n\r\n/**\r\n * Initializes and sets the general options for the server instace, keeping\r\n * the principle of the options load priority. It accepts optional userOptions\r\n * and args from the CLI.\r\n *\r\n * @param {Object} userOptions - User-provided options for customization.\r\n * @param {Array} args - Command-line arguments for additional configuration\r\n * (CLI usage).\r\n *\r\n * @returns {Object} The updated general options object.\r\n */\r\nexport const setOptions = (userOptions, args) => {\r\n // Only for the CLI usage\r\n if (args?.length) {\r\n // Get the additional options from the custom JSON file\r\n generalOptions = loadConfigFile(args);\r\n }\r\n\r\n // Update the default config with a correct option values\r\n updateDefaultConfig(defaultConfig, generalOptions);\r\n\r\n // Set values for server's options and returns them\r\n generalOptions = initOptions(defaultConfig);\r\n\r\n // Apply user options if there are any\r\n if (userOptions) {\r\n // Merge user options\r\n generalOptions = mergeConfigOptions(\r\n generalOptions,\r\n userOptions,\r\n absoluteProps\r\n );\r\n }\r\n\r\n // Only for the CLI usage\r\n if (args?.length) {\r\n // Pair provided arguments\r\n generalOptions = pairArgumentValue(generalOptions, args, defaultConfig);\r\n }\r\n\r\n // Return final general options\r\n return generalOptions;\r\n};\r\n\r\n/**\r\n * Allows manual configuration based on specified prompts and saves\r\n * the configuration to a file.\r\n *\r\n * @param {string} configFileName - The name of the configuration file.\r\n *\r\n * @returns {Promise} A Promise that resolves to true once the manual\r\n * configuration is completed and saved.\r\n */\r\nexport const manualConfig = async (configFileName) => {\r\n // Prepare a config object\r\n let configFile = {};\r\n\r\n // Check if provided config file exists\r\n if (existsSync(configFileName)) {\r\n configFile = JSON.parse(readFileSync(configFileName, 'utf8'));\r\n }\r\n\r\n // Question about a configuration category\r\n const onSubmit = async (p, categories) => {\r\n let questionsCounter = 0;\r\n let allQuestions = [];\r\n\r\n // Create a corresponding property in the manualConfig object\r\n for (const section of categories) {\r\n // Mark each option with a section\r\n promptsConfig[section] = promptsConfig[section].map((option) => ({\r\n ...option,\r\n section\r\n }));\r\n\r\n // Collect the questions\r\n allQuestions = [...allQuestions, ...promptsConfig[section]];\r\n }\r\n\r\n await prompts(allQuestions, {\r\n onSubmit: async (prompt, answer) => {\r\n // Get the default module scripts\r\n if (prompt.name === 'moduleScripts') {\r\n answer = answer.length\r\n ? answer.map((module) => prompt.choices[module])\r\n : prompt.choices;\r\n\r\n configFile[prompt.section][prompt.name] = answer;\r\n } else {\r\n configFile[prompt.section] = recursiveProps(\r\n Object.assign({}, configFile[prompt.section] || {}),\r\n prompt.name.split('.'),\r\n prompt.choices ? prompt.choices[answer] : answer\r\n );\r\n }\r\n\r\n if (++questionsCounter === allQuestions.length) {\r\n try {\r\n await fsPromises.writeFile(\r\n configFileName,\r\n JSON.stringify(configFile, null, 2),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n logWithStack(\r\n 1,\r\n error,\r\n `[config] An error occurred while creating the ${configFileName} file.`\r\n );\r\n }\r\n return true;\r\n }\r\n }\r\n });\r\n\r\n return true;\r\n };\r\n\r\n // Find the categories\r\n const choices = Object.keys(promptsConfig).map((choice) => ({\r\n title: `${choice} options`,\r\n value: choice\r\n }));\r\n\r\n // Category prompt\r\n return prompts(\r\n {\r\n type: 'multiselect',\r\n name: 'category',\r\n message: 'Which category do you want to configure?',\r\n hint: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n instructions: '',\r\n choices\r\n },\r\n { onSubmit }\r\n );\r\n};\r\n\r\n/**\r\n * Maps old-structured (PhantomJS) options to a new configuration format\r\n * (Puppeteer).\r\n *\r\n * @param {Object} oldOptions - Old-structured options to be mapped.\r\n *\r\n * @returns {Object} New options structured based on the defined nestedArgs\r\n * mapping.\r\n */\r\nexport const mapToNewConfig = (oldOptions) => {\r\n const newOptions = {};\r\n // Cycle through old-structured options\r\n for (const [key, value] of Object.entries(oldOptions)) {\r\n const propertiesChain = nestedArgs[key] ? nestedArgs[key].split('.') : [];\r\n\r\n // Populate object in correct properties levels\r\n propertiesChain.reduce(\r\n (obj, prop, index) =>\r\n (obj[prop] =\r\n propertiesChain.length - 1 === index ? value : obj[prop] || {}),\r\n newOptions\r\n );\r\n }\r\n return newOptions;\r\n};\r\n\r\n/**\r\n * Merges two sets of configuration options, considering absolute properties.\r\n *\r\n * @param {Object} options - Original configuration options.\r\n * @param {Object} newOptions - New configuration options to be merged.\r\n * @param {Array} absoluteProps - List of properties that should\r\n * not be recursively merged.\r\n *\r\n * @returns {Object} Merged configuration options.\r\n */\r\nexport const mergeConfigOptions = (options, newOptions, absoluteProps = []) => {\r\n const mergedOptions = deepCopy(options);\r\n\r\n for (const [key, value] of Object.entries(newOptions)) {\r\n mergedOptions[key] =\r\n isObject(value) &&\r\n !absoluteProps.includes(key) &&\r\n mergedOptions[key] !== undefined\r\n ? mergeConfigOptions(mergedOptions[key], value, absoluteProps)\r\n : value !== undefined\r\n ? value\r\n : mergedOptions[key];\r\n }\r\n\r\n return mergedOptions;\r\n};\r\n\r\n/**\r\n * Initializes export settings based on provided exportOptions\r\n * and generalOptions.\r\n *\r\n * @param {Object} exportOptions - Options specific to the export process.\r\n * @param {Object} generalOptions - General configuration options.\r\n *\r\n * @returns {Object} Initialized export settings.\r\n */\r\nexport const initExportSettings = (exportOptions, generalOptions = {}) => {\r\n let options = {};\r\n\r\n if (exportOptions.svg) {\r\n options = deepCopy(generalOptions);\r\n options.export.type = exportOptions.type || exportOptions.export.type;\r\n options.export.scale = exportOptions.scale || exportOptions.export.scale;\r\n options.export.outfile =\r\n exportOptions.outfile || exportOptions.export.outfile;\r\n options.payload = {\r\n svg: exportOptions.svg\r\n };\r\n } else {\r\n options = mergeConfigOptions(\r\n generalOptions,\r\n exportOptions,\r\n // Omit going down recursively with the belows\r\n absoluteProps\r\n );\r\n }\r\n\r\n options.export.outfile =\r\n options.export?.outfile || `chart.${options.export?.type || 'png'}`;\r\n return options;\r\n};\r\n\r\n/**\r\n * Loads additional configuration from a specified file using\r\n * the --loadConfig option.\r\n *\r\n * @param {Array} args - Command-line arguments to check for\r\n * the --loadConfig option.\r\n *\r\n * @returns {Object} Additional configuration loaded from the specified file,\r\n * or an empty object if not found or invalid.\r\n */\r\nfunction loadConfigFile(args) {\r\n // Check if the --loadConfig option was used\r\n const configIndex = args.findIndex(\r\n (arg) => arg.replace(/-/g, '') === 'loadConfig'\r\n );\r\n\r\n // Check if the --loadConfig has a value\r\n if (configIndex > -1 && args[configIndex + 1]) {\r\n const fileName = args[configIndex + 1];\r\n try {\r\n // Check if an additional config file is a correct JSON file\r\n if (fileName && fileName.endsWith('.json')) {\r\n // Load an optional custom JSON config file\r\n return JSON.parse(readFileSync(fileName));\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[config] Unable to load the configuration from the ${fileName} file.`\r\n );\r\n }\r\n }\r\n\r\n // No additional options to return\r\n return {};\r\n}\r\n\r\n/**\r\n * Updates the default configuration object with values from a custom object\r\n * and environment variables.\r\n *\r\n * @param {Object} configObj - The default configuration object.\r\n * @param {Object} customObj - Custom configuration object to override defaults.\r\n * @param {string} propChain - Property chain for tracking nested properties\r\n * during recursion.\r\n */\r\nfunction updateDefaultConfig(configObj, customObj = {}, propChain = '') {\r\n Object.keys(configObj).forEach((key) => {\r\n const entry = configObj[key];\r\n const customValue = customObj && customObj[key];\r\n\r\n if (typeof entry.value === 'undefined') {\r\n updateDefaultConfig(entry, customValue, `${propChain}.${key}`);\r\n } else {\r\n // If a value from a custom JSON exists, it take precedence\r\n if (customValue !== undefined) {\r\n entry.value = customValue;\r\n }\r\n\r\n // If a value from an env variable exists, it take precedence\r\n if (entry.envLink in envs && envs[entry.envLink] !== undefined) {\r\n entry.value = envs[entry.envLink];\r\n }\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * Initializes options object based on provided items, setting values from\r\n * nested properties recursively.\r\n *\r\n * @param {Object} items - Configuration items to be used for initializing\r\n * options.\r\n *\r\n * @returns {Object} Initialized options object.\r\n */\r\nfunction initOptions(items) {\r\n let options = {};\r\n for (const [name, item] of Object.entries(items)) {\r\n options[name] = Object.prototype.hasOwnProperty.call(item, 'value')\r\n ? item.value\r\n : initOptions(item);\r\n }\r\n return options;\r\n}\r\n\r\n/**\r\n * Pairs argument values with corresponding options in the configuration,\r\n * updating the options object.\r\n *\r\n * @param {Object} options - Configuration options object to be updated.\r\n * @param {Array} args - Command-line arguments containing values for specific\r\n * options.\r\n * @param {Object} defaultConfig - Default configuration object for reference.\r\n *\r\n * @returns {Object} Updated options object.\r\n */\r\nfunction pairArgumentValue(options, args, defaultConfig) {\r\n let showUsage = false;\r\n for (let i = 0; i < args.length; i++) {\r\n const option = args[i].replace(/-/g, '');\r\n\r\n // Find the right place for property's value\r\n const propertiesChain = nestedArgs[option]\r\n ? nestedArgs[option].split('.')\r\n : [];\r\n\r\n // Get the correct type for CLI args which are passed as strings\r\n let argumentType;\r\n propertiesChain.reduce((obj, prop, index) => {\r\n if (propertiesChain.length - 1 === index) {\r\n argumentType = obj[prop].type;\r\n }\r\n return obj[prop];\r\n }, defaultConfig);\r\n\r\n propertiesChain.reduce((obj, prop, index) => {\r\n if (propertiesChain.length - 1 === index) {\r\n // Finds an option and set a corresponding value\r\n if (typeof obj[prop] !== 'undefined') {\r\n if (args[++i]) {\r\n if (argumentType === 'boolean') {\r\n obj[prop] = toBoolean(args[i]);\r\n } else if (argumentType === 'number') {\r\n obj[prop] = +args[i];\r\n } else if (argumentType.indexOf(']') >= 0) {\r\n obj[prop] = args[i].split(',');\r\n } else {\r\n obj[prop] = args[i];\r\n }\r\n } else {\r\n log(\r\n 2,\r\n `[config] Missing value for the '${option}' argument. Using the default value.`\r\n );\r\n showUsage = true;\r\n }\r\n }\r\n }\r\n return obj[prop];\r\n }, options);\r\n }\r\n\r\n // Display the usage for the reference if needed\r\n if (showUsage) {\r\n printUsage(defaultConfig);\r\n }\r\n\r\n return options;\r\n}\r\n\r\n/**\r\n * Recursively updates properties in an object based on nested names and assigns\r\n * the final value.\r\n *\r\n * @param {Object} objectToUpdate - The object to be updated.\r\n * @param {Array} nestedNames - Array of nested property names.\r\n * @param {any} value - The final value to be assigned.\r\n *\r\n * @returns {Object} Updated object with assigned values.\r\n */\r\nfunction recursiveProps(objectToUpdate, nestedNames, value) {\r\n while (nestedNames.length > 1) {\r\n const propName = nestedNames.shift();\r\n\r\n // Create a property in object if it doesn't exist\r\n if (!Object.prototype.hasOwnProperty.call(objectToUpdate, propName)) {\r\n objectToUpdate[propName] = {};\r\n }\r\n\r\n // Call function again if there still names to go\r\n objectToUpdate[propName] = recursiveProps(\r\n Object.assign({}, objectToUpdate[propName]),\r\n nestedNames,\r\n value\r\n );\r\n\r\n return objectToUpdate;\r\n }\r\n\r\n // Assign the final value\r\n objectToUpdate[nestedNames[0]] = value;\r\n return objectToUpdate;\r\n}\r\n\r\nexport default {\r\n getOptions,\r\n setOptions,\r\n manualConfig,\r\n mapToNewConfig,\r\n mergeConfigOptions,\r\n initExportSettings\r\n};\r\n","/**\r\n * This module exports two functions: fetch (for GET requests) and post (for POST requests).\r\n */\r\n\r\nimport http from 'http';\r\nimport https from 'https';\r\n\r\n/**\r\n * Returns the HTTP or HTTPS protocol module based on the provided URL.\r\n *\r\n * @param {string} url - The URL to determine the protocol.\r\n *\r\n * @returns {Object} The HTTP or HTTPS protocol module (http or https).\r\n */\r\nconst getProtocol = (url) => (url.startsWith('https') ? https : http);\r\n\r\n/**\r\n * Fetches data from the specified URL using either HTTP or HTTPS protocol.\r\n *\r\n * @param {string} url - The URL to fetch data from.\r\n * @param {Object} requestOptions - Options for the HTTP request (optional).\r\n *\r\n * @returns {Promise} Promise resolving to the HTTP response object\r\n * with added 'text' property or rejecting with an error.\r\n */\r\nasync function fetch(url, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n const protocol = getProtocol(url);\r\n\r\n protocol\r\n .get(url, requestOptions, (res) => {\r\n let data = '';\r\n\r\n // A chunk of data has been received.\r\n res.on('data', (chunk) => {\r\n data += chunk;\r\n });\r\n\r\n // The whole response has been received.\r\n res.on('end', () => {\r\n if (!data) {\r\n reject('Nothing was fetched from the URL.');\r\n }\r\n\r\n res.text = data;\r\n resolve(res);\r\n });\r\n })\r\n .on('error', (error) => {\r\n reject(error);\r\n });\r\n });\r\n}\r\n\r\n/**\r\n * Sends a POST request to the specified URL with the provided JSON body using\r\n * either HTTP or HTTPS protocol.\r\n *\r\n * @param {string} url - The URL to send the POST request to.\r\n * @param {Object} body - The JSON body to include in the POST request\r\n * (optional, default is an empty object).\r\n * @param {Object} requestOptions - Options for the HTTP request (optional).\r\n *\r\n * @returns {Promise} Promise resolving to the HTTP response object with\r\n * added 'text' property or rejecting with an error.\r\n */\r\nasync function post(url, body = {}, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n const protocol = getProtocol(url);\r\n const data = JSON.stringify(body);\r\n\r\n // Set default headers and merge with requestOptions\r\n const options = Object.assign(\r\n {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'Content-Length': data.length\r\n }\r\n },\r\n requestOptions\r\n );\r\n\r\n const req = protocol\r\n .request(url, options, (res) => {\r\n let responseData = '';\r\n\r\n // A chunk of data has been received.\r\n res.on('data', (chunk) => {\r\n responseData += chunk;\r\n });\r\n\r\n // The whole response has been received.\r\n res.on('end', () => {\r\n try {\r\n res.text = responseData;\r\n resolve(res);\r\n } catch (error) {\r\n reject(error);\r\n }\r\n });\r\n })\r\n .on('error', (error) => {\r\n reject(error);\r\n });\r\n\r\n // Write the request body and end the request.\r\n req.write(data);\r\n req.end();\r\n });\r\n}\r\n\r\nexport default fetch;\r\nexport { fetch, post };\r\n","class ExportError extends Error {\r\n constructor(message) {\r\n super();\r\n this.message = message;\r\n this.stackMessage = message;\r\n }\r\n\r\n setError(error) {\r\n this.error = error;\r\n if (error.name) {\r\n this.name = error.name;\r\n }\r\n if (error.statusCode) {\r\n this.statusCode = error.statusCode;\r\n }\r\n if (error.stack) {\r\n this.stackMessage = error.message;\r\n this.stack = error.stack;\r\n }\r\n return this;\r\n }\r\n}\r\n\r\nexport default ExportError;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n// The cache manager manages the Highcharts library and its dependencies.\r\n// The cache itself is stored in .cache, and is checked by the config system\r\n// before starting the service\r\n\r\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { HttpsProxyAgent } from 'https-proxy-agent';\r\n\r\nimport { getOptions } from './config.js';\r\nimport { envs } from './envs.js';\r\nimport { fetch } from './fetch.js';\r\nimport { log } from './logger.js';\r\nimport { __dirname } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\nconst cache = {\r\n cdnURL: 'https://code.highcharts.com/',\r\n activeManifest: {},\r\n sources: '',\r\n hcVersion: ''\r\n};\r\n\r\n/**\r\n * Extracts and caches the Highcharts version from the sources string.\r\n *\r\n * @returns {string} The extracted Highcharts version.\r\n */\r\nexport const extractVersion = (cache) => {\r\n return cache.sources\r\n .substring(0, cache.sources.indexOf('*/'))\r\n .replace('/*', '')\r\n .replace('*/', '')\r\n .replace(/\\n/g, '')\r\n .trim();\r\n};\r\n\r\n/**\r\n * Extracts the Highcharts module name based on the scriptPath.\r\n */\r\nexport const extractModuleName = (scriptPath) => {\r\n return scriptPath.replace(\r\n /(.*)\\/|(.*)modules\\/|stock\\/(.*)indicators\\/|maps\\/(.*)modules\\//gi,\r\n ''\r\n );\r\n};\r\n\r\n/**\r\n * Saves the provided configuration and fetched modules to the cache manifest\r\n * file.\r\n *\r\n * @param {object} config - Highcharts-related configuration object.\r\n * @param {object} fetchedModules - An object that contains mapped names of\r\n * fetched Highcharts modules to use.\r\n *\r\n * @throws {ExportError} Throws an ExportError if an error occurs while writing\r\n * the cache manifest.\r\n */\r\nexport const saveConfigToManifest = async (config, fetchedModules) => {\r\n const newManifest = {\r\n version: config.version,\r\n modules: fetchedModules || {}\r\n };\r\n\r\n // Update cache object with the current modules\r\n cache.activeManifest = newManifest;\r\n\r\n log(3, '[cache] Writing a new manifest.');\r\n try {\r\n writeFileSync(\r\n join(__dirname, config.cachePath, 'manifest.json'),\r\n JSON.stringify(newManifest),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n throw new ExportError('[cache] Error writing the cache manifest.').setError(\r\n error\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Fetches a single script and updates the fetchedModules accordingly.\r\n *\r\n * @param {string} script - A path to script to get.\r\n * @param {Object} requestOptions - Additional options for the proxy agent\r\n * to use for a request.\r\n * @param {Object} fetchedModules - An object which tracks which Highcharts\r\n * modules have been fetched.\r\n * @param {boolean} shouldThrowError - A flag to indicate if the error should be\r\n * thrown. This should be used only for the core scripts.\r\n *\r\n * @returns {Promise} A Promise resolving to the text representation\r\n * of the fetched script.\r\n *\r\n * @throws {ExportError} Throws an ExportError if there is a problem with\r\n * fetching the script.\r\n */\r\nexport const fetchAndProcessScript = async (\r\n script,\r\n requestOptions,\r\n fetchedModules,\r\n shouldThrowError = false\r\n) => {\r\n // Get rid of the .js from the custom strings\r\n if (script.endsWith('.js')) {\r\n script = script.substring(0, script.length - 3);\r\n }\r\n\r\n log(4, `[cache] Fetching script - ${script}.js`);\r\n\r\n // Fetch the script\r\n const response = await fetch(`${script}.js`, requestOptions);\r\n\r\n // If OK, return its text representation\r\n if (response.statusCode === 200 && typeof response.text == 'string') {\r\n if (fetchedModules) {\r\n const moduleName = extractModuleName(script);\r\n fetchedModules[moduleName] = 1;\r\n }\r\n\r\n return response.text;\r\n }\r\n\r\n if (shouldThrowError) {\r\n throw new ExportError(\r\n `Could not fetch the ${script}.js. The script might not exist in the requested version (status code: ${response.statusCode}).`\r\n ).setError(response);\r\n } else {\r\n log(\r\n 2,\r\n `[cache] Could not fetch the ${script}.js. The script might not exist in the requested version.`\r\n );\r\n }\r\n\r\n return '';\r\n};\r\n\r\n/**\r\n * Fetches Highcharts scripts and customScripts from the given CDNs.\r\n *\r\n * @param {string} coreScripts - Array of Highcharts core scripts to fetch.\r\n * @param {string} moduleScripts - Array of Highcharts modules to fetch.\r\n * @param {string} customScripts - Array of custom script paths to fetch\r\n * (full URLs).\r\n * @param {object} proxyOptions - Options for the proxy agent to use for\r\n * a request.\r\n * @param {object} fetchedModules - An object which tracks which Highcharts\r\n * modules have been fetched.\r\n *\r\n * @returns {Promise} The fetched scripts content joined.\r\n */\r\nexport const fetchScripts = async (\r\n coreScripts,\r\n moduleScripts,\r\n customScripts,\r\n proxyOptions,\r\n fetchedModules\r\n) => {\r\n // Configure proxy if exists\r\n let proxyAgent;\r\n const proxyHost = proxyOptions.host;\r\n const proxyPort = proxyOptions.port;\r\n\r\n // Try to create a Proxy Agent\r\n if (proxyHost && proxyPort) {\r\n try {\r\n proxyAgent = new HttpsProxyAgent({\r\n host: proxyHost,\r\n port: proxyPort\r\n });\r\n } catch (error) {\r\n throw new ExportError('[cache] Could not create a Proxy Agent.').setError(\r\n error\r\n );\r\n }\r\n }\r\n\r\n // If exists, add proxy agent to request options\r\n const requestOptions = proxyAgent\r\n ? {\r\n agent: proxyAgent,\r\n timeout: envs.SERVER_PROXY_TIMEOUT\r\n }\r\n : {};\r\n\r\n const allFetchPromises = [\r\n ...coreScripts.map((script) =>\r\n fetchAndProcessScript(`${script}`, requestOptions, fetchedModules, true)\r\n ),\r\n ...moduleScripts.map((script) =>\r\n fetchAndProcessScript(`${script}`, requestOptions, fetchedModules)\r\n ),\r\n ...customScripts.map((script) =>\r\n fetchAndProcessScript(`${script}`, requestOptions)\r\n )\r\n ];\r\n\r\n const fetchedScripts = await Promise.all(allFetchPromises);\r\n return fetchedScripts.join(';\\n');\r\n};\r\n\r\n/**\r\n * Updates the local cache with Highcharts scripts and their versions.\r\n *\r\n * @param {Object} options - Object containing all options.\r\n * @param {string} sourcePath - The path to the source file in the cache.\r\n *\r\n * @returns {Promise} A Promise resolving to an object representing\r\n * the fetched modules.\r\n *\r\n * @throws {ExportError} Throws an ExportError if there is an issue updating\r\n * the local Highcharts cache.\r\n */\r\nexport const updateCache = async (\r\n highchartsOptions,\r\n proxyOptions,\r\n sourcePath\r\n) => {\r\n const version = highchartsOptions.version;\r\n const hcVersion = version === 'latest' || !version ? '' : `${version}/`;\r\n const cdnURL = highchartsOptions.cdnURL || cache.cdnURL;\r\n\r\n log(\r\n 3,\r\n `[cache] Updating cache version to Highcharts: ${hcVersion || 'latest'}.`\r\n );\r\n\r\n const fetchedModules = {};\r\n try {\r\n cache.sources = await fetchScripts(\r\n [\r\n ...highchartsOptions.coreScripts.map((c) => `${cdnURL}${hcVersion}${c}`)\r\n ],\r\n [\r\n ...highchartsOptions.moduleScripts.map((m) =>\r\n m === 'map'\r\n ? `${cdnURL}maps/${hcVersion}modules/${m}`\r\n : `${cdnURL}${hcVersion}modules/${m}`\r\n ),\r\n ...highchartsOptions.indicatorScripts.map(\r\n (i) => `${cdnURL}stock/${hcVersion}indicators/${i}`\r\n )\r\n ],\r\n highchartsOptions.customScripts,\r\n proxyOptions,\r\n fetchedModules\r\n );\r\n\r\n cache.hcVersion = extractVersion(cache);\r\n\r\n // Save the fetched modules into caches' source JSON\r\n writeFileSync(sourcePath, cache.sources);\r\n return fetchedModules;\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Unable to update the local Highcharts cache.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Updates the Highcharts version in the applied configuration and checks\r\n * the cache for the new version.\r\n *\r\n * @param {string} newVersion - The new Highcharts version to be applied.\r\n *\r\n * @returns {Promise<(object|boolean)>} A Promise resolving to the updated\r\n * configuration with the new version, or false if no applied configuration\r\n * exists.\r\n */\r\nexport const updateVersion = async (newVersion) => {\r\n const options = getOptions();\r\n if (options?.highcharts) {\r\n options.highcharts.version = newVersion;\r\n }\r\n await checkAndUpdateCache(options);\r\n};\r\n\r\n/**\r\n * Checks the cache for Highcharts dependencies, updates the cache if needed,\r\n * and loads the sources.\r\n *\r\n * @param {Object} options - Object containing all options.\r\n *\r\n * @returns {Promise} A Promise that resolves once the cache is checked\r\n * and updated.\r\n *\r\n * @throws {ExportError} Throws an ExportError if there is an issue updating\r\n * or reading the cache.\r\n */\r\nexport const checkAndUpdateCache = async (options) => {\r\n const { highcharts, server } = options;\r\n const cachePath = join(__dirname, highcharts.cachePath);\r\n\r\n let fetchedModules;\r\n // Prepare paths to manifest and sources from the .cache folder\r\n const manifestPath = join(cachePath, 'manifest.json');\r\n const sourcePath = join(cachePath, 'sources.js');\r\n\r\n // Create the cache destination if it doesn't exist already\r\n !existsSync(cachePath) && mkdirSync(cachePath);\r\n\r\n // Fetch all the scripts either if manifest.json does not exist\r\n // or if the forceFetch option is enabled\r\n if (!existsSync(manifestPath) || highcharts.forceFetch) {\r\n log(3, '[cache] Fetching and caching Highcharts dependencies.');\r\n fetchedModules = await updateCache(highcharts, server.proxy, sourcePath);\r\n } else {\r\n let requestUpdate = false;\r\n\r\n // Read the manifest JSON\r\n const manifest = JSON.parse(readFileSync(manifestPath));\r\n\r\n // Check if the modules is an array, if so, we rewrite it to a map to make\r\n // it easier to resolve modules.\r\n if (manifest.modules && Array.isArray(manifest.modules)) {\r\n const moduleMap = {};\r\n manifest.modules.forEach((m) => (moduleMap[m] = 1));\r\n manifest.modules = moduleMap;\r\n }\r\n\r\n const { coreScripts, moduleScripts, indicatorScripts } = highcharts;\r\n const numberOfModules =\r\n coreScripts.length + moduleScripts.length + indicatorScripts.length;\r\n\r\n // Compare the loaded highcharts config with the contents in cache.\r\n // If there are changes, fetch requested modules and products,\r\n // and bake them into a giant blob. Save the blob.\r\n if (manifest.version !== highcharts.version) {\r\n log(\r\n 2,\r\n '[cache] A Highcharts version mismatch in the cache, need to re-fetch.'\r\n );\r\n requestUpdate = true;\r\n } else if (Object.keys(manifest.modules || {}).length !== numberOfModules) {\r\n log(\r\n 2,\r\n '[cache] The cache and the requested modules do not match, need to re-fetch.'\r\n );\r\n requestUpdate = true;\r\n } else {\r\n // Check each module, if anything is missing refetch everything\r\n requestUpdate = (moduleScripts || []).some((moduleName) => {\r\n if (!manifest.modules[moduleName]) {\r\n log(\r\n 2,\r\n `[cache] The ${moduleName} is missing in the cache, need to re-fetch.`\r\n );\r\n return true;\r\n }\r\n });\r\n }\r\n\r\n if (requestUpdate) {\r\n fetchedModules = await updateCache(highcharts, server.proxy, sourcePath);\r\n } else {\r\n log(3, '[cache] Dependency cache is up to date, proceeding.');\r\n\r\n // Load the sources\r\n cache.sources = readFileSync(sourcePath, 'utf8');\r\n\r\n // Get current modules map\r\n fetchedModules = manifest.modules;\r\n\r\n cache.hcVersion = extractVersion(cache);\r\n }\r\n }\r\n\r\n // Finally, save the new manifest, which is basically our current config\r\n // in a slightly different format\r\n await saveConfigToManifest(highcharts, fetchedModules);\r\n};\r\n\r\nexport const getCachePath = () =>\r\n join(__dirname, getOptions().highcharts.cachePath);\r\n\r\nexport const getCache = () => cache;\r\n\r\nexport const highcharts = () => cache.sources;\r\n\r\nexport const version = () => cache.hcVersion;\r\n\r\nexport default {\r\n checkAndUpdateCache,\r\n getCachePath,\r\n updateVersion,\r\n getCache,\r\n highcharts,\r\n version\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/* eslint-disable no-undef */\r\n\r\n/**\r\n * Setting the animObject. Called when initing the page.\r\n */\r\nexport function setupHighcharts() {\r\n Highcharts.animObject = function () {\r\n return { duration: 0 };\r\n };\r\n}\r\n\r\n/**\r\n * Creates the actual chart.\r\n *\r\n * @param {object} chartOptions - The options for the Highcharts chart.\r\n * @param {object} options - The export options.\r\n * @param {boolean} displayErrors - A flag indicating whether to display errors.\r\n */\r\nexport async function triggerExport(chartOptions, options, displayErrors) {\r\n // Display errors flag taken from chart options nad debugger module\r\n window._displayErrors = displayErrors;\r\n\r\n // Get required functions\r\n const { getOptions, merge, setOptions, wrap } = Highcharts;\r\n\r\n // Create a separate object for a potential setOptions usages in order to\r\n // prevent from polluting other exports that can happen on the same page\r\n Highcharts.setOptionsObj = merge(false, {}, getOptions());\r\n\r\n // Trigger custom code\r\n if (options.customLogic.customCode) {\r\n new Function(options.customLogic.customCode)();\r\n }\r\n\r\n // By default animation is disabled\r\n const chart = {\r\n animation: false\r\n };\r\n\r\n // When straight inject, the size is set through CSS only\r\n if (options.export.strInj) {\r\n chart.height = chartOptions.chart.height;\r\n chart.width = chartOptions.chart.width;\r\n }\r\n\r\n // NOTE: Is this used for anything useful?\r\n window.isRenderComplete = false;\r\n wrap(Highcharts.Chart.prototype, 'init', function (proceed, userOptions, cb) {\r\n // Override userOptions with image friendly options\r\n userOptions = merge(userOptions, {\r\n exporting: {\r\n enabled: false\r\n },\r\n plotOptions: {\r\n series: {\r\n label: {\r\n enabled: false\r\n }\r\n }\r\n },\r\n /* Expects tooltip in userOptions when forExport is true.\r\n https://github.com/highcharts/highcharts/blob/3ad430a353b8056b9e764aa4e5cd6828aa479db2/js/parts/Chart.js#L241\r\n */\r\n tooltip: {}\r\n });\r\n\r\n (userOptions.series || []).forEach(function (series) {\r\n series.animation = false;\r\n });\r\n\r\n // Add flag to know if chart render has been called.\r\n if (!window.onHighchartsRender) {\r\n window.onHighchartsRender = Highcharts.addEvent(this, 'render', () => {\r\n window.isRenderComplete = true;\r\n });\r\n }\r\n\r\n proceed.apply(this, [userOptions, cb]);\r\n });\r\n\r\n wrap(Highcharts.Series.prototype, 'init', function (proceed, chart, options) {\r\n proceed.apply(this, [chart, options]);\r\n });\r\n\r\n // Get the user options\r\n const userOptions = options.export.strInj\r\n ? new Function(`return ${options.export.strInj}`)()\r\n : chartOptions;\r\n\r\n // Merge the globalOptions, themeOptions, options from the wrapped\r\n // setOptions function and user options to create the final options object\r\n const finalOptions = merge(\r\n false,\r\n JSON.parse(options.export.themeOptions),\r\n userOptions,\r\n // Placed it here instead in the init because of the size issues\r\n { chart }\r\n );\r\n\r\n const finalCallback = options.customLogic.callback\r\n ? new Function(`return ${options.customLogic.callback}`)()\r\n : undefined;\r\n\r\n // Set the global options if exist\r\n const globalOptions = JSON.parse(options.export.globalOptions);\r\n if (globalOptions) {\r\n setOptions(globalOptions);\r\n }\r\n\r\n Highcharts[options.export.constr || 'chart'](\r\n 'container',\r\n finalOptions,\r\n finalCallback\r\n );\r\n\r\n // Get the current global options\r\n const defaultOptions = getOptions();\r\n\r\n // Clear it just in case (e.g. the setOptions was used in the customCode)\r\n for (const prop in defaultOptions) {\r\n if (typeof defaultOptions[prop] !== 'function') {\r\n delete defaultOptions[prop];\r\n }\r\n }\r\n\r\n // Set the default options back\r\n setOptions(Highcharts.setOptionsObj);\r\n\r\n // Empty the custom global options object\r\n Highcharts.setOptionsObj = {};\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync } from 'fs';\r\nimport path from 'path';\r\n\r\nimport puppeteer from 'puppeteer';\r\n\r\nimport { getCachePath } from './cache.js';\r\nimport { getOptions } from './config.js';\r\nimport { setupHighcharts } from './highcharts.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { __dirname } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// Get the template for the page\r\nconst template = readFileSync(__dirname + '/templates/template.html', 'utf8');\r\n\r\nlet browser;\r\n\r\n/**\r\n * Retrieves the existing Puppeteer browser instance.\r\n *\r\n * @returns {Promise} A Promise resolving to the Puppeteer browser\r\n * instance.\r\n *\r\n * @throws {ExportError} Throws an ExportError if no valid browser has been\r\n * created.\r\n */\r\nexport function get() {\r\n if (!browser) {\r\n throw new ExportError('[browser] No valid browser has been created.');\r\n }\r\n return browser;\r\n}\r\n\r\n/**\r\n * Creates a Puppeteer browser instance with the specified arguments.\r\n *\r\n * @param {Array} puppeteerArgs - Additional arguments for Puppeteer launch.\r\n *\r\n * @returns {Promise} A Promise resolving to the Puppeteer browser\r\n * instance.\r\n *\r\n * @throws {ExportError} Throws an ExportError if max retries to open a browser\r\n * instance are reached, or if no browser instance is found after retries.\r\n */\r\nexport async function create(puppeteerArgs) {\r\n // Get debug and other options\r\n const { debug, other } = getOptions();\r\n\r\n // Get the debug options\r\n const { enable: enabledDebug, ...debugOptions } = debug;\r\n\r\n const launchOptions = {\r\n headless: other.browserShellMode ? 'shell' : true,\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 && debugOptions)\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\r\n // Shell mode inform\r\n if (launchOptions.headless === 'shell') {\r\n log(3, `[browser] Launched browser in shell mode.`);\r\n }\r\n\r\n // Debug mode inform\r\n if (enabledDebug) {\r\n log(3, `[browser] Launched browser in debug mode.`);\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[browser] Maximum retries to open a browser instance reached.'\r\n ).setError(error);\r\n }\r\n\r\n if (!browser) {\r\n throw new ExportError('[browser] Cannot find a browser to open.');\r\n }\r\n }\r\n\r\n // Return a browser promise\r\n return browser;\r\n}\r\n\r\n/**\r\n * Closes the Puppeteer browser instance if it is connected.\r\n *\r\n * @returns {Promise} A Promise resolving to true after the browser\r\n * is closed.\r\n */\r\nexport async function close() {\r\n // Close the browser when connnected\r\n if (browser?.connected) {\r\n await browser.close();\r\n }\r\n log(4, '[browser] Closed the browser.');\r\n}\r\n\r\n/**\r\n * Creates a new Puppeteer Page within an existing browser instance.\r\n *\r\n * If the browser instance is not available, returns false.\r\n *\r\n * The function creates a new page, disables caching, sets content using\r\n * setPageContent(), and returns the created Puppeteer Page.\r\n *\r\n * @returns {(boolean|object)} Returns false if the browser instance is not\r\n * available, or a Puppeteer Page object representing the newly created page.\r\n */\r\nexport async function newPage() {\r\n if (!browser) {\r\n return false;\r\n }\r\n\r\n // Create a page\r\n const page = await browser.newPage();\r\n\r\n // Disable cache\r\n await page.setCacheEnabled(false);\r\n\r\n // Set the content\r\n await setPageContent(page);\r\n\r\n // Set page events\r\n setPageEvents(page);\r\n\r\n return page;\r\n}\r\n\r\n/**\r\n * Clears the content of a Puppeteer Page based on the specified mode.\r\n *\r\n * @param {Object} page - The Puppeteer Page object to be cleared.\r\n * @param {boolean} hardReset - A flag indicating the type of clearing\r\n * to be performed. If true, navigates to 'about:blank' and resets content\r\n * and scripts. If false, clears the body content by setting a predefined HTML\r\n * structure.\r\n *\r\n * @throws {Error} Logs thrown error if clearing the page content fails.\r\n */\r\nexport async function clearPage(page, hardReset = false) {\r\n try {\r\n if (!page.isClosed()) {\r\n if (hardReset) {\r\n // Navigate to about:blank\r\n await page.goto('about:blank', { waitUntil: 'domcontentloaded' });\r\n\r\n // Set the content and and scripts again\r\n await setPageContent(page);\r\n } else {\r\n // Clear body content\r\n await page.evaluate(() => {\r\n document.body.innerHTML =\r\n '
';\r\n });\r\n }\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n '[browser] Could not clear the content of the page.'\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Adds custom JS and CSS resources to a Puppeteer Page based on the specified\r\n * options.\r\n *\r\n * @param {Object} page - The Puppeteer Page object to which resources will be\r\n * added.\r\n * @param {Object} options - All options and configuration.\r\n *\r\n * @returns {Promise>} - Promise resolving to an array of injected\r\n * resources.\r\n */\r\nexport async function addPageResources(page, options) {\r\n // Injected resources array\r\n const injectedResources = [];\r\n\r\n // Use resources\r\n const resources = options.customLogic.resources;\r\n if (resources) {\r\n const injectedJs = [];\r\n\r\n // Load custom JS code\r\n if (resources.js) {\r\n injectedJs.push({\r\n content: resources.js\r\n });\r\n }\r\n\r\n // Load scripts from all custom files\r\n if (resources.files) {\r\n for (const file of resources.files) {\r\n const isLocal = !file.startsWith('http') ? true : false;\r\n\r\n // Add each custom script from resources' files\r\n injectedJs.push(\r\n isLocal\r\n ? {\r\n content: readFileSync(file, 'utf8')\r\n }\r\n : {\r\n url: file\r\n }\r\n );\r\n }\r\n }\r\n\r\n for (const jsResource of injectedJs) {\r\n try {\r\n injectedResources.push(await page.addScriptTag(jsResource));\r\n } catch (error) {\r\n logWithStack(2, error, `[export] The JS resource cannot be loaded.`);\r\n }\r\n }\r\n injectedJs.length = 0;\r\n\r\n // Load CSS\r\n const injectedCss = [];\r\n if (resources.css) {\r\n let cssImports = resources.css.match(/@import\\s*([^;]*);/g);\r\n if (cssImports) {\r\n // Handle css section\r\n for (let cssImportPath of cssImports) {\r\n if (cssImportPath) {\r\n cssImportPath = cssImportPath\r\n .replace('url(', '')\r\n .replace('@import', '')\r\n .replace(/\"/g, '')\r\n .replace(/'/g, '')\r\n .replace(/;/, '')\r\n .replace(/\\)/g, '')\r\n .trim();\r\n\r\n // Add each custom css from resources\r\n if (cssImportPath.startsWith('http')) {\r\n injectedCss.push({\r\n url: cssImportPath\r\n });\r\n } else if (options.customLogic.allowFileResources) {\r\n injectedCss.push({\r\n path: path.join(__dirname, cssImportPath)\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n // The rest of the CSS section will be content by now\r\n injectedCss.push({\r\n content: resources.css.replace(/@import\\s*([^;]*);/g, '') || ' '\r\n });\r\n\r\n for (const cssResource of injectedCss) {\r\n try {\r\n injectedResources.push(await page.addStyleTag(cssResource));\r\n } catch (error) {\r\n logWithStack(2, error, `[export] The CSS resource cannot be loaded.`);\r\n }\r\n }\r\n injectedCss.length = 0;\r\n }\r\n }\r\n return injectedResources;\r\n}\r\n\r\n/**\r\n * Clears out all state set on the page with addScriptTag/addStyleTag. Removes\r\n * injected resources and resets CSS and script tags on the page. Additionally,\r\n * it destroys previously existing charts.\r\n *\r\n * @param {Object} page - The Puppeteer Page object from which resources will\r\n * be cleared.\r\n * @param {Array} injectedResources - Array of injected resources\r\n * to be cleared.\r\n */\r\nexport async function clearPageResources(page, injectedResources) {\r\n for (const resource of injectedResources) {\r\n await resource.dispose();\r\n }\r\n\r\n // Destroy old charts after export is done and reset all CSS and script tags\r\n await page.evaluate(() => {\r\n // We are not guaranteed that Highcharts is loaded, e,g, when doing SVG\r\n // exports\r\n if (typeof Highcharts !== 'undefined') {\r\n // eslint-disable-next-line no-undef\r\n const oldCharts = Highcharts.charts;\r\n\r\n // Check in any already existing charts\r\n if (Array.isArray(oldCharts) && oldCharts.length) {\r\n // Destroy old charts\r\n for (const oldChart of oldCharts) {\r\n oldChart && oldChart.destroy();\r\n // eslint-disable-next-line no-undef\r\n Highcharts.charts.shift();\r\n }\r\n }\r\n }\r\n\r\n // eslint-disable-next-line no-undef\r\n const [...scriptsToRemove] = document.getElementsByTagName('script');\r\n // eslint-disable-next-line no-undef\r\n const [, ...stylesToRemove] = document.getElementsByTagName('style');\r\n // eslint-disable-next-line no-undef\r\n const [...linksToRemove] = document.getElementsByTagName('link');\r\n\r\n // Remove tags\r\n for (const element of [\r\n ...scriptsToRemove,\r\n ...stylesToRemove,\r\n ...linksToRemove\r\n ]) {\r\n element.remove();\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * Sets the content for a Puppeteer Page using a predefined template\r\n * and additional scripts. Also, sets the pageerror in order to catch\r\n * and display errors from the window context.\r\n *\r\n * @param {Object} page - The Puppeteer Page object for which the content\r\n * is being set.\r\n */\r\nasync function setPageContent(page) {\r\n await page.setContent(template, { waitUntil: 'domcontentloaded' });\r\n\r\n // Add all registered Higcharts scripts, quite demanding\r\n await page.addScriptTag({ path: `${getCachePath()}/sources.js` });\r\n\r\n // Set the initial animObject\r\n await page.evaluate(setupHighcharts);\r\n}\r\n\r\n/**\r\n * Set events for a Puppeteer Page.\r\n *\r\n * @param {Object} page - The Puppeteer Page object to set events to.\r\n */\r\nfunction setPageEvents(page) {\r\n // Get debug options\r\n const { debug } = getOptions();\r\n\r\n // Set the console listener, if needed\r\n if (debug.enable && debug.listenToConsole) {\r\n page.on('console', (message) => {\r\n console.log(`[debug] ${message.text()}`);\r\n });\r\n }\r\n\r\n // Set the pageerror listener\r\n page.on('pageerror', async (error) => {\r\n // TODO: Consider adding a switch here that turns on log(0) logging\r\n // on page errors.\r\n await page.$eval(\r\n '#container',\r\n (element, errorMessage) => {\r\n // eslint-disable-next-line no-undef\r\n if (window._displayErrors) {\r\n element.innerHTML = errorMessage;\r\n }\r\n },\r\n `

Chart input data error:

${error.toString()}`\r\n );\r\n });\r\n}\r\n\r\nexport default {\r\n get,\r\n create,\r\n close,\r\n newPage,\r\n clearPage,\r\n addPageResources,\r\n clearPageResources\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { addPageResources, clearPageResources } from './browser.js';\r\nimport { getCache } from './cache.js';\r\nimport { triggerExport } from './highcharts.js';\r\nimport { log } from './logger.js';\r\n\r\nimport svgTemplate from './../templates/svg_export/svg_export.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n/**\r\n * Retrieves the clipping region coordinates of the specified page element with\r\n * the id 'chart-container'.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} Promise resolving to an object containing\r\n * x, y, width, and height properties.\r\n */\r\nconst getClipRegion = (page) =>\r\n page.$eval('#chart-container', (element) => {\r\n const { x, y, width, height } = element.getBoundingClientRect();\r\n return {\r\n x,\r\n y,\r\n width,\r\n height: Math.trunc(height > 1 ? height : 500)\r\n };\r\n });\r\n\r\n/**\r\n * Creates an image using Puppeteer's page screenshot functionality with\r\n * specified options.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {string} type - Image type.\r\n * @param {string} encoding - Image encoding.\r\n * @param {Object} clip - Clipping region coordinates.\r\n * @param {number} rasterizationTimeout - Timeout for rasterization\r\n * in milliseconds.\r\n *\r\n * @returns {Promise} Promise resolving to the image buffer or rejecting\r\n * with an ExportError for timeout.\r\n */\r\nconst createImage = (page, type, encoding, clip, rasterizationTimeout) =>\r\n Promise.race([\r\n page.screenshot({\r\n type,\r\n encoding,\r\n clip,\r\n captureBeyondViewport: true,\r\n fullPage: false,\r\n optimizeForSpeed: true,\r\n ...(type !== 'png' ? { quality: 80 } : {}),\r\n\r\n // #447, #463 - always render on a transparent page if the expected type\r\n // format is PNG\r\n omitBackground: type == 'png'\r\n }),\r\n new Promise((_resolve, reject) =>\r\n setTimeout(\r\n () => reject(new ExportError('Rasterization timeout')),\r\n rasterizationTimeout || 1500\r\n )\r\n )\r\n ]);\r\n\r\n/**\r\n * Creates a PDF using Puppeteer's page pdf functionality with specified\r\n * options.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {number} height - PDF height.\r\n * @param {number} width - PDF width.\r\n * @param {string} encoding - PDF encoding.\r\n *\r\n * @returns {Promise} Promise resolving to the PDF buffer.\r\n */\r\nconst createPDF = async (\r\n page,\r\n height,\r\n width,\r\n encoding,\r\n rasterizationTimeout\r\n) => {\r\n await page.emulateMediaType('screen');\r\n return Promise.race([\r\n page.pdf({\r\n // This will remove an extra empty page in PDF exports\r\n height: height + 1,\r\n width,\r\n encoding\r\n }),\r\n new Promise((_resolve, reject) =>\r\n setTimeout(\r\n () => reject(new ExportError('Rasterization timeout')),\r\n rasterizationTimeout || 1500\r\n )\r\n )\r\n ]);\r\n};\r\n\r\n/**\r\n * Creates an SVG string by evaluating the outerHTML of the first 'svg' element\r\n * inside an element with the id 'container'.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} Promise resolving to the SVG string.\r\n */\r\nconst createSVG = (page) =>\r\n page.$eval('#container svg:first-of-type', (element) => element.outerHTML);\r\n\r\n/**\r\n * Sets the specified chart and options as configuration into the triggerExport\r\n * function within the window context using page.evaluate.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {any} chart - The chart object to be configured.\r\n * @param {Object} options - Configuration options for the chart.\r\n *\r\n * @returns {Promise} Promise resolving after the configuration is set.\r\n */\r\nconst setAsConfig = async (page, chart, options, displayErrors) =>\r\n page.evaluate(triggerExport, chart, options, displayErrors);\r\n\r\n/**\r\n * Exports to a chart from a page using Puppeteer.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {any} chart - The chart object or SVG configuration to be exported.\r\n * @param {Object} options - Export options and configuration.\r\n *\r\n * @returns {Promise} Promise resolving to\r\n * the exported data or rejecting with an ExportError.\r\n */\r\nexport default async (page, chart, options) => {\r\n // Injected resources array (additional JS and CSS)\r\n let injectedResources = [];\r\n\r\n try {\r\n log(4, '[export] Determining export path.');\r\n\r\n const exportOptions = options.export;\r\n\r\n // Decide whether display error or debbuger wrapper around it\r\n const displayErrors =\r\n exportOptions?.options?.chart?.displayErrors &&\r\n getCache().activeManifest.modules.debugger;\r\n\r\n let isSVG;\r\n if (\r\n chart.indexOf &&\r\n (chart.indexOf('= 0 || chart.indexOf('= 0)\r\n ) {\r\n // SVG input handling\r\n log(4, '[export] Treating as SVG.');\r\n\r\n // If input is also SVG, just return it\r\n if (exportOptions.type === 'svg') {\r\n return chart;\r\n }\r\n\r\n isSVG = true;\r\n await page.setContent(svgTemplate(chart), {\r\n waitUntil: 'domcontentloaded'\r\n });\r\n } else {\r\n // JSON config handling\r\n log(4, '[export] Treating as config.');\r\n\r\n // Need to perform straight inject\r\n if (exportOptions.strInj) {\r\n // Injection based configuration export\r\n await setAsConfig(\r\n page,\r\n {\r\n chart: {\r\n height: exportOptions.height,\r\n width: exportOptions.width\r\n }\r\n },\r\n options,\r\n displayErrors\r\n );\r\n } else {\r\n // Basic configuration export\r\n chart.chart.height = exportOptions.height;\r\n chart.chart.width = exportOptions.width;\r\n\r\n await setAsConfig(page, chart, options, displayErrors);\r\n }\r\n }\r\n\r\n // Keeps track of all resources added on the page with addXXXTag. etc\r\n // It's VITAL that all added resources ends up here so we can clear things\r\n // out when doing a new export in the same page!\r\n injectedResources = await addPageResources(page, options);\r\n\r\n // Get the real chart size and set the zoom accordingly\r\n const size = isSVG\r\n ? await page.evaluate((scale) => {\r\n const svgElement = document.querySelector(\r\n '#chart-container svg:first-of-type'\r\n );\r\n\r\n // Get the values correctly scaled\r\n const chartHeight = svgElement.height.baseVal.value * scale;\r\n const chartWidth = svgElement.width.baseVal.value * scale;\r\n\r\n // In case of SVG the zoom must be set directly for body\r\n // Set the zoom as scale\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = scale;\r\n\r\n // Set the margin to 0px\r\n // eslint-disable-next-line no-undef\r\n document.body.style.margin = '0px';\r\n\r\n return {\r\n chartHeight,\r\n chartWidth\r\n };\r\n }, parseFloat(exportOptions.scale))\r\n : await page.evaluate(() => {\r\n // eslint-disable-next-line no-undef\r\n const { chartHeight, chartWidth } = window.Highcharts.charts[0];\r\n\r\n // No need for such scale manipulation in case of other types\r\n // of exports. Reset the zoom for other exports than to SVGs\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = 1;\r\n\r\n return {\r\n chartHeight,\r\n chartWidth\r\n };\r\n });\r\n\r\n // Set final height and width for viewport\r\n const viewportHeight = Math.ceil(size.chartHeight || exportOptions.height);\r\n const viewportWidth = Math.ceil(size.chartWidth || exportOptions.width);\r\n\r\n // Get the clip region for the page\r\n const { x, y } = await getClipRegion(page);\r\n\r\n // Set the final viewport now that we have the real height\r\n await page.setViewport({\r\n height: viewportHeight,\r\n width: viewportWidth,\r\n deviceScaleFactor: isSVG ? 1 : parseFloat(exportOptions.scale)\r\n });\r\n\r\n let data;\r\n // Rasterization process\r\n if (exportOptions.type === 'svg') {\r\n // SVG\r\n data = await createSVG(page);\r\n } else if (['png', 'jpeg'].includes(exportOptions.type)) {\r\n // PNG or JPEG\r\n data = await createImage(\r\n page,\r\n exportOptions.type,\r\n 'base64',\r\n {\r\n width: viewportWidth,\r\n height: viewportHeight,\r\n x,\r\n y\r\n },\r\n exportOptions.rasterizationTimeout\r\n );\r\n } else if (exportOptions.type === 'pdf') {\r\n // PDF\r\n data = await createPDF(\r\n page,\r\n viewportHeight,\r\n viewportWidth,\r\n 'base64',\r\n exportOptions.rasterizationTimeout\r\n );\r\n } else {\r\n throw new ExportError(\r\n `[export] Unsupported output format ${exportOptions.type}.`\r\n );\r\n }\r\n\r\n // Clear previously injected JS and CSS resources\r\n await clearPageResources(page, injectedResources);\r\n return data;\r\n } catch (error) {\r\n await clearPageResources(page, injectedResources);\r\n return error;\r\n }\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport cssTemplate from './css.js';\r\n\r\nexport default (chart) => `\r\n\r\n\r\n \r\n \r\n Highcharts Export\r\n \r\n \r\n \r\n
\r\n ${chart}\r\n
\r\n \r\n\r\n\r\n`;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { Pool } from 'tarn';\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport {\r\n create as createBrowser,\r\n close as closeBrowser,\r\n newPage,\r\n clearPage\r\n} from './browser.js';\r\nimport puppeteerExport from './export.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { measureTime } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// The pool instance\r\nlet pool = false;\r\n\r\n// Pool statistics\r\nexport const stats = {\r\n performedExports: 0,\r\n exportAttempts: 0,\r\n exportFromSvgAttempts: 0,\r\n timeSpent: 0,\r\n droppedExports: 0,\r\n spentAverage: 0\r\n};\r\n\r\nlet poolConfig = {};\r\n\r\nconst factory = {\r\n /**\r\n * Creates a new worker page for the export pool.\r\n *\r\n * @returns {Object} - An object containing the worker ID, a reference to the\r\n * browser page, and initial work count.\r\n *\r\n * @throws {ExportError} - If there's an error during the creation of the new\r\n * page.\r\n */\r\n create: async () => {\r\n let page = false;\r\n\r\n const id = uuid();\r\n const startDate = new Date().getTime();\r\n\r\n try {\r\n page = await newPage();\r\n\r\n if (!page || page.isClosed()) {\r\n throw new ExportError('The page is invalid or closed.');\r\n }\r\n\r\n log(\r\n 3,\r\n `[pool] Successfully created a worker ${id} - took ${\r\n new Date().getTime() - startDate\r\n } ms.`\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n 'Error encountered when creating a new page.'\r\n ).setError(error);\r\n }\r\n\r\n return {\r\n id,\r\n page,\r\n // Try to distribute the initial work count\r\n workCount: Math.round(Math.random() * (poolConfig.workLimit / 2))\r\n };\r\n },\r\n\r\n /**\r\n * Validates a worker page in the export pool, checking if it has exceeded\r\n * the work limit.\r\n *\r\n * @param {Object} workerHandle - The handle to the worker, containing the\r\n * worker's ID, a reference to the browser page, and work count.\r\n *\r\n * @returns {boolean} - Returns true if the worker is valid and within\r\n * the work limit; otherwise, returns false.\r\n */\r\n validate: async (workerHandle) => {\r\n if (\r\n poolConfig.workLimit &&\r\n ++workerHandle.workCount > poolConfig.workLimit\r\n ) {\r\n log(\r\n 3,\r\n `[pool] Worker failed validation: exceeded work limit (limit is ${poolConfig.workLimit}).`\r\n );\r\n return false;\r\n }\r\n return true;\r\n },\r\n\r\n /**\r\n * Destroys a worker entry in the export pool, closing its associated page.\r\n *\r\n * @param {Object} workerHandle - The handle to the worker, containing\r\n * the worker's ID and a reference to the browser page.\r\n */\r\n destroy: async (workerHandle) => {\r\n log(3, `[pool] Destroying pool entry ${workerHandle.id}.`);\r\n\r\n if (workerHandle.page) {\r\n // We don't really need to wait around for this\r\n await workerHandle.page.close();\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Initializes the export pool with the provided configuration, creating\r\n * a browser instance and setting up worker resources.\r\n *\r\n * @param {Object} config - Configuration options for the export pool along\r\n * with custom puppeteer arguments for the puppeteer.launch function.\r\n */\r\nexport const initPool = async (config) => {\r\n // For the module scope usage\r\n poolConfig = config && config.pool ? { ...config.pool } : {};\r\n\r\n // Create a browser instance with the puppeteer arguments\r\n await createBrowser(config.puppeteerArgs);\r\n\r\n log(\r\n 3,\r\n `[pool] Initializing pool with workers: min ${poolConfig.minWorkers}, max ${poolConfig.maxWorkers}.`\r\n );\r\n\r\n if (pool) {\r\n return log(\r\n 4,\r\n '[pool] Already initialized, please kill it before creating a new one.'\r\n );\r\n }\r\n\r\n if (parseInt(poolConfig.minWorkers) > parseInt(poolConfig.maxWorkers)) {\r\n poolConfig.minWorkers = poolConfig.maxWorkers;\r\n }\r\n\r\n try {\r\n // Create a pool along with a minimal number of resources\r\n pool = new Pool({\r\n // Get the create/validate/destroy/log functions\r\n ...factory,\r\n min: parseInt(poolConfig.minWorkers),\r\n max: parseInt(poolConfig.maxWorkers),\r\n acquireTimeoutMillis: poolConfig.acquireTimeout,\r\n createTimeoutMillis: poolConfig.createTimeout,\r\n destroyTimeoutMillis: poolConfig.destroyTimeout,\r\n idleTimeoutMillis: poolConfig.idleTimeout,\r\n createRetryIntervalMillis: poolConfig.createRetryInterval,\r\n reapIntervalMillis: poolConfig.reaperInterval,\r\n propagateCreateError: false\r\n });\r\n\r\n // Set events\r\n pool.on('release', async (resource) => {\r\n // Clear page\r\n await clearPage(resource.page, false);\r\n log(4, `[pool] Releasing a worker with ID ${resource.id}.`);\r\n });\r\n\r\n pool.on('destroySuccess', (eventId, resource) => {\r\n log(4, `[pool] Destroyed a worker with ID ${resource.id}.`);\r\n });\r\n\r\n const initialResources = [];\r\n // Create an initial number of resources\r\n for (let i = 0; i < poolConfig.minWorkers; i++) {\r\n try {\r\n const resource = await pool.acquire().promise;\r\n initialResources.push(resource);\r\n } catch (error) {\r\n logWithStack(2, error, '[pool] Could not create an initial resource.');\r\n }\r\n }\r\n\r\n // Release the initial number of resources back to the pool\r\n initialResources.forEach((resource) => {\r\n pool.release(resource);\r\n });\r\n\r\n log(\r\n 3,\r\n `[pool] The pool is ready${initialResources.length ? ` with ${initialResources.length} initial resources waiting.` : '.'}`\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n '[pool] Could not create the pool of workers.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Kills all workers in the pool, destroys the pool, and closes the browser\r\n * instance.\r\n *\r\n * @returns {Promise} A promise that resolves after the workers are\r\n * killed, the pool is destroyed, and the browser is closed.\r\n */\r\nexport async function killPool() {\r\n log(3, '[pool] Killing pool with all workers and closing browser.');\r\n\r\n // If still alive, destroy the pool of pages before closing a browser\r\n if (pool) {\r\n // Free up not released workers\r\n for (const worker of pool.used) {\r\n pool.release(worker.resource);\r\n }\r\n\r\n // Destroy the pool if it is still available\r\n if (!pool.destroyed) {\r\n await pool.destroy();\r\n log(4, '[browser] Destroyed the pool of resources.');\r\n }\r\n }\r\n\r\n // Close the browser instance\r\n await closeBrowser();\r\n}\r\n\r\n/**\r\n * Processes the export work using a worker from the pool. Acquires a worker\r\n * handle from the pool, performs the export using puppeteer, and releases\r\n * the worker handle back to the pool.\r\n *\r\n * @param {string} chart - The chart data or configuration to be exported.\r\n * @param {Object} options - Export options and configuration.\r\n *\r\n * @returns {Promise} A promise that resolves with the export resultand\r\n * options.\r\n *\r\n * @throws {ExportError} If an error occurs during the export process.\r\n */\r\nexport const postWork = async (chart, options) => {\r\n let workerHandle;\r\n\r\n try {\r\n log(4, '[pool] Work received, starting to process.');\r\n\r\n ++stats.exportAttempts;\r\n if (poolConfig.benchmarking) {\r\n getPoolInfo();\r\n }\r\n\r\n if (!pool) {\r\n throw new ExportError('Work received, but pool has not been started.');\r\n }\r\n\r\n // Acquire the worker along with the id of resource and work count\r\n const acquireCounter = measureTime();\r\n try {\r\n log(4, '[pool] Acquiring a worker handle.');\r\n workerHandle = await pool.acquire().promise;\r\n\r\n // Check the page acquire time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n options.payload?.requestId\r\n ? `[benchmark] Request: ${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 ? `Request: ${options.payload?.requestId} - `\r\n : '') +\r\n `Error encountered when acquiring an available entry: ${acquireCounter()}ms.`\r\n ).setError(error);\r\n }\r\n log(4, '[pool] Acquired a worker handle.');\r\n\r\n if (!workerHandle.page) {\r\n throw new ExportError(\r\n 'Resolved worker page is invalid: the pool setup is wonky.'\r\n );\r\n }\r\n\r\n // Save the start time\r\n let workStart = new Date().getTime();\r\n\r\n log(4, `[pool] Starting work on pool entry with ID ${workerHandle.id}.`);\r\n\r\n // Perform an export on a puppeteer level\r\n const exportCounter = measureTime();\r\n const result = await puppeteerExport(workerHandle.page, chart, options);\r\n\r\n // Check if it's an error\r\n if (result instanceof Error) {\r\n // TODO: If the export failed because puppeteer timed out, we need to force kill the worker so we get a new page. That needs to be handled better than this hack.\r\n if (result.message === 'Rasterization timeout') {\r\n workerHandle.page.close();\r\n workerHandle.page = await newPage();\r\n }\r\n\r\n throw new ExportError(\r\n (options.payload?.requestId\r\n ? `Request: ${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: ${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\n/**\r\n * Gets the statistic of a pool instace about exports.\r\n */\r\nexport function getStats() {\r\n return stats;\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\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 and timeouts\r\nconst timerIds = [];\r\n\r\n/**\r\n * Adds id of setInterval or setTimeout and to the intervalIds array.\r\n *\r\n * @param {NodeJS.Timeout} id - Id of an interval/timeout.\r\n */\r\nexport const addTimer = (id) => {\r\n timerIds.push(id);\r\n};\r\n\r\n/**\r\n * Clears all of ongoing intervals and timeouts by ids gathered in the timerIds\r\n * array.\r\n */\r\nexport const clearAllTimers = () => {\r\n log(4, `[server] Clearing all registered intervals and timeouts.`);\r\n for (const id of timerIds) {\r\n clearInterval(id);\r\n clearTimeout(id);\r\n }\r\n};\r\n\r\nexport default {\r\n addTimer,\r\n clearAllTimers\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","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2023, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid 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\n\r\nimport { __dirname } from './utils.js';\r\n\r\n// Get the telemetry template\r\nconst telemetryTemplate = JSON.parse(\r\n readFileSync(join(__dirname, 'lib', 'schemas', 'telemetry.json'))\r\n);\r\n\r\n// The object with telemetry data collected\r\nexport const telemetryData = {\r\n numberOfRequests: 0\r\n};\r\n\r\n// Possible properties in an array\r\nconst optionsInArray = ['series', 'xAxis', 'yAxis', 'zAxis'];\r\n\r\n// Recursive function for getting only the required options\r\nfunction filterData(template, options) {\r\n const filteredObject = {};\r\n\r\n // Cycle through allowed propeties\r\n for (const [templateKey, templateValue] of Object.entries(template)) {\r\n // Check if the section exists\r\n if (options[templateKey] !== undefined) {\r\n // Check if this is the final level of indent in the template\r\n if (templateValue !== null) {\r\n // Check if it is an array\r\n if (Array.isArray(options[templateKey])) {\r\n // And if it contains allowed properties\r\n if (optionsInArray.includes(templateKey)) {\r\n // Create an array\r\n filteredObject[templateKey] = [];\r\n // If so, cycle through all of them\r\n for (const [index, optionsValue] of options[\r\n templateKey\r\n ].entries()) {\r\n filteredObject[templateKey][index] = filterData(\r\n templateValue,\r\n optionsValue\r\n );\r\n }\r\n } else {\r\n // Otherwise, get only the first element\r\n filteredObject[templateKey] = filterData(\r\n templateValue,\r\n options[templateKey][0]\r\n );\r\n }\r\n } else {\r\n filteredObject[templateKey] = filterData(\r\n templateValue,\r\n options[templateKey]\r\n );\r\n }\r\n } else {\r\n // Return the option\r\n filteredObject[templateKey] = options[templateKey];\r\n }\r\n }\r\n }\r\n\r\n // Return the object\r\n return filteredObject;\r\n}\r\n\r\nexport function prepareTelemetry(chartOptions, requestId) {\r\n // Save the filtered options under the request's id\r\n telemetryData[requestId] = filterData(telemetryTemplate, chartOptions);\r\n\r\n // Increment requests counter\r\n telemetryData.numberOfRequests++;\r\n}\r\n\r\nexport default {\r\n telemetryData,\r\n prepareTelemetry\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2023, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\nimport jwt from 'jsonwebtoken';\r\nimport { v4 as uuid } from 'uuid';\r\nimport WebSocket from 'ws';\r\n\r\nimport { getOptions } from '../config.js';\r\nimport { log, logWithStack } from '../logger.js';\r\nimport { telemetryData } from '../telemetry.js';\r\nimport { addTimer } from '../timers.js';\r\n\r\n// WebSocket clients map\r\nconst webSocketClients = new Map();\r\n\r\n// WebSocket options\r\nlet webSocketOptions;\r\n\r\n// WebSocket message sending interval\r\nlet messageInterval = null;\r\n\r\n/**\r\n * Init WebSocket client and connection options.\r\n *\r\n * @param {object} address - Object that contains, address and port of enabled\r\n * HTTP or HTTPS server.\r\n */\r\nexport function init(address) {\r\n webSocketOptions = getOptions().webSocket;\r\n if (webSocketOptions.enable === true) {\r\n // Options for the WebSocket connection\r\n const connectionOptions = {\r\n rejectUnauthorized: webSocketOptions.rejectUnauthorized,\r\n headers: {\r\n // Set an access token that lasts only 5 minutes\r\n auth: jwt.sign({ success: 'success' }, webSocketOptions.secret, {\r\n algorithm: 'HS256'\r\n }),\r\n // Send the server address in a custom header\r\n 'X-Server-Address': `${address.protocol}://${\r\n ['::', '0.0.0.0'].includes(address.address)\r\n ? 'localhost'\r\n : address.address\r\n }:${address.port}`\r\n }\r\n };\r\n\r\n // Options for the WebSocket client\r\n const clientOptions = {\r\n id: uuid(),\r\n reconnect: webSocketOptions.reconnect,\r\n reconnectTry: 0,\r\n reconnectInterval: null,\r\n pingTimeout: null\r\n };\r\n\r\n // Start the WebSocket connection\r\n connect(webSocketOptions.url, connectionOptions, clientOptions);\r\n\r\n // Start the WebSocket message sending interval\r\n sendingMessageInterval(webSocketOptions);\r\n }\r\n}\r\n\r\nfunction sendingMessageInterval(webSocketOptions) {\r\n // Set the sending message interval\r\n messageInterval = setInterval(() => {\r\n try {\r\n // Get the first WebSocket client\r\n const webSocketClient = getClients().next().value;\r\n // If the client is found, open and there is data to send\r\n if (\r\n webSocketClient &&\r\n webSocketClient.readyState === WebSocket.OPEN &&\r\n Object.keys(telemetryData).length > 1 &&\r\n telemetryData.numberOfRequests > 0\r\n ) {\r\n // Send through the WebSocket\r\n webSocketClient.send(JSON.stringify(telemetryData));\r\n }\r\n } catch (error) {\r\n logWithStack(1, `[websocket] Could not send data through WebSocket.`);\r\n }\r\n }, webSocketOptions.messageInterval);\r\n\r\n // Register interval for the later clearing\r\n addTimer(messageInterval);\r\n}\r\n\r\n/**\r\n * Creates WebSocket client and connects to WebSocket server on a provided url.\r\n *\r\n * @param {string} webSocketUrl - The WebSocket server's URL.\r\n * @param {object} connectionOptions - Options for WebSocket connection.\r\n * @param {object} clientOptions - Options for WebSocket client.\r\n */\r\nfunction connect(webSocketUrl, connectionOptions, clientOptions) {\r\n // Try to connect to indicated WebSocket server\r\n let webSocketClient = new WebSocket(webSocketUrl, connectionOptions);\r\n\r\n // Open event\r\n webSocketClient.on('open', () => {\r\n // Not need for the reconnect interval anymore\r\n clearInterval(clientOptions.reconnectInterval);\r\n\r\n // Save the client under its id\r\n webSocketClients.set(clientOptions.id, webSocketClient);\r\n\r\n // Log a success message\r\n log(\r\n 3,\r\n `[websocket] WebSocket: ${clientOptions.id} - Connected to server: ${webSocketUrl}.`\r\n );\r\n });\r\n\r\n // Close event where ping timeout is cleared\r\n webSocketClient.on('close', (code) => {\r\n log(\r\n 3,\r\n '[websocket]',\r\n `WebSocket: ${clientOptions.id} - Disconnected from server: ${webSocketUrl} with code: ${code}.`\r\n );\r\n\r\n // Stop the heartbeat mechanism\r\n clearTimeout(clientOptions.pingTimeout);\r\n\r\n // Removed client if exists\r\n webSocketClients.delete(clientOptions.id);\r\n webSocketClient = null;\r\n\r\n // Try to reconnect only when enabled and if not already attempting to do so\r\n if (clientOptions.reconnect && !clientOptions.reconnectInterval) {\r\n reconnect(webSocketUrl, connectionOptions, clientOptions);\r\n }\r\n });\r\n\r\n // Error event\r\n webSocketClient.on('error', (error) => {\r\n logWithStack(\r\n 1,\r\n error,\r\n `[websocket] WebSocket: ${clientOptions.id} - Error occured.`\r\n );\r\n\r\n // Block the reconnect mechanism when getting 403\r\n if (error.message.includes('403')) {\r\n clientOptions.reconnect = false;\r\n clientOptions.reconnectTry = webSocketOptions.reconnectAttempts;\r\n } else {\r\n // Or set the option accordingly\r\n clientOptions.reconnect = webSocketOptions.reconnect;\r\n }\r\n });\r\n\r\n // Message event\r\n webSocketClient.on('message', (message) => {\r\n log(\r\n 3,\r\n `[websocket] WebSocket: ${clientOptions.id} - Data received: ${message}`\r\n );\r\n });\r\n\r\n // The 'ping' event from a WebSocket connection with the health check\r\n // and termination logic\r\n webSocketClient.on('ping', () => {\r\n log(\r\n 3,\r\n `[websocket] WebSocket: ${clientOptions.id} - Received PING from server: ${webSocketUrl}.`\r\n );\r\n clearTimeout(clientOptions.pingTimeout);\r\n clientOptions.pingTimeout = setTimeout(() => {\r\n // Terminate the client connection\r\n webSocketClient.terminate();\r\n\r\n // Try to reconnect if required\r\n if (clientOptions.reconnect) {\r\n reconnect(webSocketUrl, connectionOptions, clientOptions);\r\n }\r\n }, webSocketOptions.pingTimeout);\r\n });\r\n}\r\n\r\n/**\r\n * Reconnects to WebSocket server on a provided url.\r\n *\r\n * @param {string} webSocketUrl - The WebSocket server's URL.\r\n * @param {object} connectionOptions - Options for WebSocket connection.\r\n * @param {object} clientOptions - Options for WebSocket client.\r\n */\r\nfunction reconnect(webSocketUrl, connectionOptions, clientOptions) {\r\n // Start the reconnect interval\r\n clientOptions.reconnectInterval = setInterval(() => {\r\n if (clientOptions.reconnectTry < webSocketOptions.reconnectAttempts) {\r\n log(\r\n 3,\r\n `[websocket] WebSocket: ${clientOptions.id} - Attempt ${++clientOptions.reconnectTry} of ${webSocketOptions.reconnectAttempts} to reconnect to server: ${webSocketUrl}.`\r\n );\r\n\r\n connect(webSocketUrl, connectionOptions, clientOptions);\r\n } else {\r\n clientOptions.reconnect = false;\r\n clearInterval(clientOptions.reconnectInterval);\r\n log(\r\n 2,\r\n `[websocket] WebSocket: ${clientOptions.id} - Could not reconnect to server: ${webSocketUrl}.`\r\n );\r\n }\r\n }, webSocketOptions.reconnectInterval);\r\n\r\n // Register interval for the later clearing\r\n addTimer(clientOptions.reconnectInterval);\r\n}\r\n\r\n/**\r\n * Gets map of current WebSocket clients.\r\n *\r\n * @param {string} id - The uuid of WebSocket client.\r\n */\r\nexport function getClients(id) {\r\n return id ? webSocketClients.get(id) : webSocketClients.values();\r\n}\r\n\r\n/**\r\n * Terminates all WebSocket clients and clear the webSocketClients map.\r\n */\r\nexport function terminateClients() {\r\n for (const client of webSocketClients.values()) {\r\n client.terminate();\r\n }\r\n webSocketClients.clear();\r\n}\r\n\r\nexport default {\r\n init,\r\n connect,\r\n getClients\r\n};\r\n","import ExportError from './ExportError.js';\r\n\r\nclass HttpError extends ExportError {\r\n constructor(message, status) {\r\n super(message);\r\n this.status = this.statusCode = status;\r\n }\r\n\r\n setStatus(status) {\r\n this.status = status;\r\n return this;\r\n }\r\n}\r\n\r\nexport default HttpError;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { updateVersion, version } from '../../cache.js';\r\nimport { envs } from '../../envs.js';\r\n\r\nimport HttpError from '../../errors/HttpError.js';\r\n\r\n/**\r\n * Adds the POST /change_hc_version/:newVersion route that can be utilized to modify\r\n * the Highcharts version on the server.\r\n *\r\n * TODO: Add auth token and connect to API\r\n */\r\nexport default (app) =>\r\n !app\r\n ? false\r\n : app.post(\r\n '/version/change/:newVersion',\r\n async (request, response, next) => {\r\n try {\r\n const adminToken = envs.HIGHCHARTS_ADMIN_TOKEN;\r\n\r\n // Check the existence of the token\r\n if (!adminToken || !adminToken.length) {\r\n throw new HttpError(\r\n 'The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.',\r\n 401\r\n );\r\n }\r\n\r\n // Check if the hc-auth header contain a correct token\r\n const token = request.get('hc-auth');\r\n if (!token || token !== adminToken) {\r\n throw new HttpError(\r\n 'Invalid or missing token: Set the token in the hc-auth header.',\r\n 401\r\n );\r\n }\r\n\r\n // Compare versions\r\n const newVersion = request.params.newVersion;\r\n if (newVersion) {\r\n try {\r\n // eslint-disable-next-line import/no-named-as-default-member\r\n await updateVersion(newVersion);\r\n } catch (error) {\r\n throw new HttpError(\r\n `Version change: ${error.message}`,\r\n error.statusCode\r\n ).setError(error);\r\n }\r\n\r\n // Success\r\n response.status(200).send({\r\n statusCode: 200,\r\n version: version(),\r\n message: `Successfully updated Highcharts to version: ${newVersion}.`\r\n });\r\n } else {\r\n // No version specified\r\n throw new HttpError('No new version supplied.', 400);\r\n }\r\n } catch (error) {\r\n next(error);\r\n }\r\n }\r\n );\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport { getAllowCodeExecution, startExport } from '../../chart.js';\r\nimport { getOptions, mergeConfigOptions } from '../../config.js';\r\nimport { log } from '../../logger.js';\r\nimport { prepareTelemetry } from '../../telemetry.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 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: ${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 // Prepare and send the options through the WebSocket\r\n prepareTelemetry(options.export.options, options.payload.requestId);\r\n\r\n if (info.result) {\r\n // If only base64 is required, return it\r\n if (body.b64) {\r\n // SVG Exception for the Highcharts 11.3.0 version\r\n if (type === 'pdf' || type == 'svg') {\r\n return response.send(\r\n Buffer.from(info.result, 'utf8').toString('base64')\r\n );\r\n }\r\n\r\n return response.send(info.result);\r\n }\r\n\r\n // Set correct content type\r\n response.header('Content-Type', reversedMime[type] || 'image/png');\r\n\r\n // Decide whether to download or not chart file\r\n if (!body.noDownload) {\r\n response.attachment(\r\n `${request.params.filename || request.body.filename || 'chart'}.${\r\n type || 'png'\r\n }`\r\n );\r\n }\r\n\r\n // If SVG, return plain content\r\n return type === 'svg'\r\n ? response.send(info.result)\r\n : response.send(Buffer.from(info.result, 'base64'));\r\n }\r\n });\r\n } catch (error) {\r\n next(error);\r\n }\r\n};\r\n\r\nexport default (app) => {\r\n /**\r\n * Adds the POST / a route for handling POST requests at the root endpoint.\r\n */\r\n app.post('/', exportHandler);\r\n\r\n /**\r\n * Adds the POST /:filename a route for handling POST requests with\r\n * a specified filename parameter.\r\n */\r\n app.post('/:filename', exportHandler);\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join as pather } from 'path';\r\nimport { log } from '../../logger.js';\r\n\r\nimport { version } from '../../cache.js';\r\nimport { addTimer } from '../../timers.js';\r\nimport { getStats, getPoolInfoJSON } 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 = 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 addTimer(startSuccessRate());\r\n\r\n app.get('/health', (_, res) => {\r\n const stats = getStats();\r\n const period = successRates.length;\r\n const movingAverage = calculateMovingAverage();\r\n\r\n log(4, '[health.js] GET /health [200] - returning server health.');\r\n\r\n res.send({\r\n status: 'OK',\r\n bootTime: serverStartTime,\r\n uptime:\r\n Math.floor(\r\n (new Date().getTime() - serverStartTime.getTime()) / 1000 / 60\r\n ) + ' minutes',\r\n version: pkgFile.version,\r\n highchartsVersion: version(),\r\n averageProcessingTime: stats.spentAverage,\r\n performedExports: stats.performedExports,\r\n failedExports: stats.droppedExports,\r\n exportAttempts: stats.exportAttempts,\r\n sucessRatio: (stats.performedExports / stats.exportAttempts) * 100,\r\n // eslint-disable-next-line import/no-named-as-default-member\r\n pool: 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 { init as webSocketInit } from './web_socket.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 // 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 if (activeServers.size === 1) {\r\n // Start a WebSocket connection\r\n webSocketInit({ ...httpServer.address(), protocol: 'http' });\r\n }\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 // 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 if (activeServers.size === 1) {\r\n // Start a WebSocket connection\r\n webSocketInit({ ...httpsServer.address(), protocol: 'https' });\r\n }\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 { clearAllTimers } from './timers.js';\r\nimport { killPool } from './pool.js';\r\nimport { closeServers } from './server/server.js';\r\nimport { terminateClients } from './server/web_socket.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 timers\r\n clearAllTimers(),\r\n\r\n // Terminate all connected WebSocket clients\r\n terminateClients(),\r\n\r\n // Get available server instances (HTTP/HTTPS) and close them\r\n closeServers(),\r\n\r\n // Close pool along with its workers and the browser instance, if exists\r\n killPool()\r\n ]);\r\n\r\n // Exit process with a correct code\r\n process.exit(exitCode);\r\n};\r\n\r\nexport default {\r\n shutdownCleanUp\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport 'colors';\r\n\r\nimport { checkAndUpdateCache } from './cache.js';\r\nimport {\r\n batchExport,\r\n setAllowCodeExecution,\r\n singleExport,\r\n startExport\r\n} from './chart.js';\r\nimport { mapToNewConfig, manualConfig, setOptions } from './config.js';\r\nimport {\r\n initLogging,\r\n log,\r\n logWithStack,\r\n setLogLevel,\r\n enableFileLogging\r\n} from './logger.js';\r\nimport { initPool, killPool } from './pool.js';\r\nimport { shutdownCleanUp } from './resource_release.js';\r\nimport server, { startServer } from './server/server.js';\r\nimport { printLogo, printUsage } from './utils.js';\r\n\r\n/**\r\n * Attaches exit listeners to the process, ensuring proper cleanup of resources\r\n * and termination on exit signals. Handles 'exit', 'SIGINT', 'SIGTERM', and\r\n * 'uncaughtException' events.\r\n */\r\nconst attachProcessExitListeners = () => {\r\n log(3, '[process] Attaching exit listeners to the process.');\r\n\r\n // Handler for the 'exit'\r\n process.on('exit', (code) => {\r\n log(4, `Process exited with code ${code}.`);\r\n });\r\n\r\n // Handler for the 'SIGINT'\r\n process.on('SIGINT', async (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'SIGTERM'\r\n process.on('SIGTERM', async (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'SIGHUP'\r\n process.on('SIGHUP', async (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'uncaughtException'\r\n process.on('uncaughtException', async (error, name) => {\r\n logWithStack(1, error, `The ${name} error.`);\r\n await shutdownCleanUp(1);\r\n });\r\n};\r\n\r\n/**\r\n * Initializes the export process. Tasks such as configuring logging, checking\r\n * cache and sources, and initializing the pool of resources happen during\r\n * this stage. Function that is required to be called before trying to export charts or setting a server. The `options` is an object that contains all options.\r\n *\r\n * @param {Object} options - All export options.\r\n *\r\n * @returns {Promise} Promise resolving to the updated export options.\r\n */\r\nconst initExport = async (options) => {\r\n // Set the allowCodeExecution per export module scope\r\n setAllowCodeExecution(\r\n options.customLogic && options.customLogic.allowCodeExecution\r\n );\r\n\r\n // Init the logging\r\n initLogging(options.logging);\r\n\r\n // Attach process' exit listeners\r\n if (options.other.listenToProcessExits) {\r\n attachProcessExitListeners();\r\n }\r\n\r\n // Check if cache needs to be updated\r\n await checkAndUpdateCache(options);\r\n\r\n // Init the pool\r\n await initPool({\r\n pool: options.pool || {\r\n minWorkers: 1,\r\n maxWorkers: 1\r\n },\r\n puppeteerArgs: options.puppeteer.args || []\r\n });\r\n\r\n // Return updated options\r\n return options;\r\n};\r\n\r\nexport default {\r\n // Server\r\n server,\r\n startServer,\r\n\r\n // Exporting\r\n initExport,\r\n singleExport,\r\n batchExport,\r\n startExport,\r\n\r\n // Pool\r\n initPool,\r\n killPool,\r\n\r\n // Other\r\n setOptions,\r\n shutdownCleanUp,\r\n\r\n // Logs\r\n log,\r\n logWithStack,\r\n setLogLevel,\r\n enableFileLogging,\r\n\r\n // Utils\r\n mapToNewConfig,\r\n manualConfig,\r\n printLogo,\r\n printUsage\r\n};\r\n"],"names":["scriptsNames","core","modules","indicators","defaultConfig","puppeteer","args","value","type","description","highcharts","version","envLink","cdnURL","coreScripts","moduleScripts","indicatorScripts","customScripts","forceFetch","cachePath","export","infile","instr","options","outfile","constr","defaultHeight","defaultWidth","defaultScale","height","width","scale","globalOptions","themeOptions","batch","rasterizationTimeout","customLogic","allowCodeExecution","allowFileResources","customCode","callback","resources","loadConfig","legacyName","createConfig","server","enable","cliName","host","port","benchmarking","proxy","timeout","rateLimiting","maxRequests","window","delay","trustProxy","skipKey","skipToken","ssl","force","certPath","pool","minWorkers","maxWorkers","workLimit","acquireTimeout","createTimeout","destroyTimeout","idleTimeout","createRetryInterval","reaperInterval","logging","level","file","dest","ui","route","other","nodeEnv","listenToProcessExits","noLogo","hardResetPage","browserShellMode","debug","headless","devtools","listenToConsole","dumpio","slowMo","debuggingPort","webSocket","reconnect","rejectUnauthorized","pingTimeout","reconnectInterval","reconnectAttempts","messageInterval","url","secret","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","OTHER_BROWSER_SHELL_MODE","DEBUG_ENABLE","DEBUG_HEADLESS","DEBUG_DEVTOOLS","DEBUG_LISTEN_TO_CONSOLE","DEBUG_DUMPIO","DEBUG_SLOW_MO","DEBUG_DEBUGGING_PORT","WEB_SOCKET_ENABLE","WEB_SOCKET_RECONNECT","WEB_SOCKET_REJECT_UNAUTHORIZED","WEB_SOCKET_PING_TIMEOUT","WEB_SOCKET_RECONNECT_INTERVAL","WEB_SOCKET_RECONNECT_ATTEMPTS","WEB_SOCKET_MESSAGE_INTERVAL","WEB_SOCKET_URL","WEB_SOCKET_SECRET","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","fixType","formats","outType","pop","find","t","handleResources","allowedProps","handledResources","correctResources","isCorrectJSON","readFileSync","files","propName","item","data","parsedData","JSON","stringify","deepCopy","copy","Array","isArray","prototype","hasOwnProperty","call","optionsStringify","allowFunctions","replaceAll","printUsage","bold","yellow","cycleCategories","descName","green","i","blue","category","toUpperCase","red","toBoolean","wrapAround","replace","measureTime","start","hrtime","bigint","Number","generalOptions","getOptions","mergeConfigOptions","newOptions","mergedOptions","updateDefaultConfig","configObj","customObj","customValue","initOptions","items","recursiveProps","objectToUpdate","nestedNames","shift","assign","async","fetch","requestOptions","Promise","resolve","reject","protocol","https","http","getProtocol","get","res","on","chunk","text","ExportError","Error","constructor","super","this","setError","statusCode","cache","activeManifest","sources","hcVersion","extractVersion","indexOf","fetchAndProcessScript","script","fetchedModules","shouldThrowError","response","updateCache","highchartsOptions","proxyOptions","sourcePath","proxyAgent","proxyHost","proxyPort","HttpsProxyAgent","agent","allFetchPromises","all","fetchScripts","c","m","writeFileSync","checkAndUpdateCache","manifestPath","requestUpdate","manifest","moduleMap","numberOfModules","some","moduleName","newManifest","saveConfigToManifest","getCachePath","setupHighcharts","Highcharts","animObject","duration","triggerExport","chartOptions","displayErrors","_displayErrors","merge","setOptions","wrap","setOptionsObj","Function","chart","animation","strInj","isRenderComplete","Chart","proceed","userOptions","cb","exporting","enabled","plotOptions","series","label","tooltip","onHighchartsRender","addEvent","Series","finalOptions","finalCallback","defaultOptions","prop","template","browser","newPage","page","setCacheEnabled","setPageContent","$eval","element","errorMessage","innerHTML","setPageEvents","clearPageResources","injectedResources","resource","dispose","evaluate","oldCharts","charts","oldChart","destroy","scriptsToRemove","document","getElementsByTagName","stylesToRemove","linksToRemove","remove","setContent","waitUntil","addScriptTag","path","setAsConfig","puppeteerExport","exportOptions","debugger","isSVG","svgTemplate","injectedJs","js","push","content","isLocal","jsResource","injectedCss","css","cssImports","match","cssImportPath","cssResource","addStyleTag","addPageResources","size","svgElement","querySelector","chartHeight","baseVal","chartWidth","body","style","zoom","margin","viewportHeight","Math","ceil","viewportWidth","x","y","getBoundingClientRect","trunc","getClipRegion","setViewport","deviceScaleFactor","outerHTML","createSVG","encoding","clip","race","screenshot","captureBeyondViewport","fullPage","optimizeForSpeed","quality","omitBackground","_resolve","setTimeout","createImage","emulateMediaType","pdf","createPDF","stats","performedExports","exportAttempts","exportFromSvgAttempts","timeSpent","droppedExports","spentAverage","poolConfig","factory","create","id","uuid","startDate","getTime","isClosed","workCount","random","validate","workerHandle","close","initPool","puppeteerArgs","enabledDebug","debugOptions","launchOptions","userDataDir","handleSIGINT","handleSIGTERM","handleSIGHUP","waitForInitialPage","defaultViewport","tryCount","open","launch","createBrowser","parseInt","Pool","acquireTimeoutMillis","createTimeoutMillis","destroyTimeoutMillis","idleTimeoutMillis","createRetryIntervalMillis","reapIntervalMillis","propagateCreateError","hardReset","goto","clearPage","eventId","initialResources","acquire","promise","release","killPool","worker","used","destroyed","connected","closeBrowser","postWork","available","pending","getPoolInfoJSON","getPoolInfo","acquireCounter","payload","requestId","workStart","exportCounter","result","exportTime","numFree","numUsed","numPendingAcquires","getStats","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","timerIds","addTimer","clearAllTimers","clearInterval","clearTimeout","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","telemetryTemplate","telemetryData","numberOfRequests","optionsInArray","filterData","filteredObject","templateKey","templateValue","index","optionsValue","prepareTelemetry","webSocketClients","Map","webSocketOptions","init","address","connectionOptions","headers","auth","jwt","sign","success","algorithm","clientOptions","reconnectTry","connect","setInterval","webSocketClient","readyState","WebSocket","OPEN","sendingMessageInterval","webSocketUrl","set","code","delete","terminate","terminateClients","client","clear","HttpError","setStatus","vSwitchRoute","post","adminToken","token","newVersion","params","updateVersion","reversedMime","png","jpeg","gif","requestsCounter","beforeRequest","afterRequest","doCallbacks","callbacks","uniqueId","callResponse","exportHandler","stopCounter","connection","remoteAddress","connectionAborted","socket","toLowerCase","substr","b64","noDownload","pattern","isPrivateRangeUrlFound","info","removeAllListeners","Buffer","from","header","attachment","filename","pkgFile","pather","serverStartTime","successRates","addHealthRoutes","successRatio","_","period","movingAverage","reduce","a","b","bootTime","uptime","floor","highchartsVersion","averageProcessingTime","failedExports","sucessRatio","toFixed","svgExportAttempts","jsonExportAttempts","activeServers","express","disable","cors","storage","multer","memoryStorage","upload","limits","fieldSize","limit","urlencoded","extended","none","attachServerErrorHandlers","startServer","serverConfig","httpServer","createServer","listen","webSocketInit","cert","fsPromises","readFile","posix","httpsServer","NaN","static","healthRoute","exportRoutes","sendFile","uiRoute","errorHandler","closeServers","getServers","enableRateLimiting","getExpress","getApp","middlewares","shutdownCleanUp","exitCode","allSettled","exit","initExport","initLogging","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":"woBAeO,MAAMA,EAAe,CAC1BC,KAAM,CAAC,aAAc,kBAAmB,iBACxCC,QAAS,CACP,QACA,MACA,QACA,YACA,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,kBACA,cACA,eAEA,cACA,WACA,eACA,WACA,SACA,OACA,WACA,YACA,SACA,qBACA,aACA,WACA,WACA,WACA,WACA,eACA,UACA,kBACA,oBACA,aACA,UACA,cACA,YACA,YAEFC,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,SACPC,KAAM,SACNI,QAAS,wBACTH,YACE,oGAGNW,OAAQ,CACNC,OAAQ,CACNd,OAAO,EACPC,KAAM,SACNC,YACE,wHAEJa,MAAO,CACLf,OAAO,EACPC,KAAM,SACNC,YACE,qGAEJc,QAAS,CACPhB,OAAO,EACPC,KAAM,SACNC,YAAa,oCAEfe,QAAS,CACPjB,OAAO,EACPC,KAAM,SACNC,YACE,qGAEJD,KAAM,CACJD,MAAO,MACPC,KAAM,SACNI,QAAS,cACTH,YAAa,6DAEfgB,OAAQ,CACNlB,MAAO,QACPC,KAAM,SACNI,QAAS,gBACTH,YACE,8EAEJiB,cAAe,CACbnB,MAAO,IACPC,KAAM,SACNI,QAAS,wBACTH,YACE,wEAEJkB,aAAc,CACZpB,MAAO,IACPC,KAAM,SACNI,QAAS,uBACTH,YACE,uEAEJmB,aAAc,CACZrB,MAAO,EACPC,KAAM,SACNI,QAAS,uBACTH,YACE,uEAEJoB,OAAQ,CACNtB,OAAO,EACPC,KAAM,SACNC,YACE,kFAEJqB,MAAO,CACLvB,OAAO,EACPC,KAAM,SACNC,YACE,iFAEJsB,MAAO,CACLxB,OAAO,EACPC,KAAM,SACNC,YACE,6GAEJuB,cAAe,CACbzB,OAAO,EACPC,KAAM,SACNC,YACE,2GAEJwB,aAAc,CACZ1B,OAAO,EACPC,KAAM,SACNC,YACE,iHAEJyB,MAAO,CACL3B,OAAO,EACPC,KAAM,SACNC,YACE,2FAEJ0B,qBAAsB,CACpB5B,MAAO,KACPC,KAAM,SACNI,QAAS,+BACTH,YACE,kEAGN2B,YAAa,CACXC,mBAAoB,CAClB9B,OAAO,EACPC,KAAM,UACNI,QAAS,oCACTH,YACE,6FAEJ6B,mBAAoB,CAClB/B,OAAO,EACPC,KAAM,UACNI,QAAS,oCACTH,YACE,sHAEJ8B,WAAY,CACVhC,OAAO,EACPC,KAAM,SACNC,YACE,mJAEJ+B,SAAU,CACRjC,OAAO,EACPC,KAAM,SACNC,YACE,0GAEJgC,UAAW,CACTlC,OAAO,EACPC,KAAM,SACNC,YACE,yGAEJiC,WAAY,CACVnC,OAAO,EACPC,KAAM,SACNmC,WAAY,WACZlC,YAAa,yDAEfmC,aAAc,CACZrC,OAAO,EACPC,KAAM,SACNC,YACE,wFAGNoC,OAAQ,CACNC,OAAQ,CACNvC,OAAO,EACPC,KAAM,UACNI,QAAS,gBACTmC,QAAS,eACTtC,YACE,wEAEJuC,KAAM,CACJzC,MAAO,UACPC,KAAM,SACNI,QAAS,cACTH,YACE,0FAEJwC,KAAM,CACJ1C,MAAO,KACPC,KAAM,SACNI,QAAS,cACTH,YAAa,iCAEfyC,aAAc,CACZ3C,OAAO,EACPC,KAAM,UACNI,QAAS,sBACTmC,QAAS,qBACTtC,YACE,qIAEJ0C,MAAO,CACLH,KAAM,CACJzC,OAAO,EACPC,KAAM,SACNI,QAAS,oBACTmC,QAAS,YACTtC,YAAa,sDAEfwC,KAAM,CACJ1C,MAAO,KACPC,KAAM,SACNI,QAAS,oBACTmC,QAAS,YACTtC,YAAa,sDAEf2C,QAAS,CACP7C,MAAO,IACPC,KAAM,SACNI,QAAS,uBACTmC,QAAS,eACTtC,YAAa,2DAGjB4C,aAAc,CACZP,OAAQ,CACNvC,OAAO,EACPC,KAAM,UACNI,QAAS,8BACTmC,QAAS,qBACTtC,YAAa,yCAEf6C,YAAa,CACX/C,MAAO,GACPC,KAAM,SACNI,QAAS,oCACT+B,WAAY,YACZlC,YAAa,yDAEf8C,OAAQ,CACNhD,MAAO,EACPC,KAAM,SACNI,QAAS,8BACTH,YAAa,uDAEf+C,MAAO,CACLjD,MAAO,EACPC,KAAM,SACNI,QAAS,6BACTH,YACE,qFAEJgD,WAAY,CACVlD,OAAO,EACPC,KAAM,UACNI,QAAS,mCACTH,YAAa,6DAEfiD,QAAS,CACPnD,OAAO,EACPC,KAAM,SACNI,QAAS,gCACTH,YACE,yFAEJkD,UAAW,CACTpD,OAAO,EACPC,KAAM,SACNI,QAAS,kCACTH,YACE,wFAGNmD,IAAK,CACHd,OAAQ,CACNvC,OAAO,EACPC,KAAM,UACNI,QAAS,oBACTmC,QAAS,YACTtC,YAAa,yCAEfoD,MAAO,CACLtD,OAAO,EACPC,KAAM,UACNI,QAAS,mBACTmC,QAAS,WACTJ,WAAY,UACZlC,YACE,oEAEJwC,KAAM,CACJ1C,MAAO,IACPC,KAAM,SACNI,QAAS,kBACTmC,QAAS,UACTtC,YAAa,4CAEfqD,SAAU,CACRvD,OAAO,EACPC,KAAM,SACNI,QAAS,uBACT+B,WAAY,UACZlC,YAAa,+CAInBsD,KAAM,CACJC,WAAY,CACVzD,MAAO,EACPC,KAAM,SACNI,QAAS,mBACTH,YAAa,4DAEfwD,WAAY,CACV1D,MAAO,EACPC,KAAM,SACNI,QAAS,mBACT+B,WAAY,UACZlC,YAAa,gDAEfyD,UAAW,CACT3D,MAAO,GACPC,KAAM,SACNI,QAAS,kBACTH,YACE,yFAEJ0D,eAAgB,CACd5D,MAAO,IACPC,KAAM,SACNI,QAAS,uBACTH,YACE,oEAEJ2D,cAAe,CACb7D,MAAO,IACPC,KAAM,SACNI,QAAS,sBACTH,YACE,mEAEJ4D,eAAgB,CACd9D,MAAO,IACPC,KAAM,SACNI,QAAS,uBACTH,YACE,qEAEJ6D,YAAa,CACX/D,MAAO,IACPC,KAAM,SACNI,QAAS,oBACTH,YACE,6EAEJ8D,oBAAqB,CACnBhE,MAAO,IACPC,KAAM,SACNI,QAAS,6BACTH,YACE,mGAEJ+D,eAAgB,CACdjE,MAAO,IACPC,KAAM,SACNI,QAAS,uBACTH,YACE,oGAEJyC,aAAc,CACZ3C,OAAO,EACPC,KAAM,UACNI,QAAS,oBACTmC,QAAS,mBACTtC,YACE,0EAGNgE,QAAS,CACPC,MAAO,CACLnE,MAAO,EACPC,KAAM,SACNI,QAAS,gBACTmC,QAAS,WACTtC,YAAa,iCAEfkE,KAAM,CACJpE,MAAO,+BACPC,KAAM,SACNI,QAAS,eACTmC,QAAS,UACTtC,YACE,2FAEJmE,KAAM,CACJrE,MAAO,OACPC,KAAM,SACNI,QAAS,eACTmC,QAAS,UACTtC,YACE,iEAGNoE,GAAI,CACF/B,OAAQ,CACNvC,OAAO,EACPC,KAAM,UACNI,QAAS,YACTmC,QAAS,WACTtC,YACE,sEAEJqE,MAAO,CACLvE,MAAO,IACPC,KAAM,SACNI,QAAS,WACTmC,QAAS,UACTtC,YACE,4EAGNsE,MAAO,CACLC,QAAS,CACPzE,MAAO,aACPC,KAAM,SACNI,QAAS,iBACTH,YAAa,oCAEfwE,qBAAsB,CACpB1E,OAAO,EACPC,KAAM,UACNI,QAAS,gCACTH,YAAa,2DAEfyE,OAAQ,CACN3E,OAAO,EACPC,KAAM,UACNI,QAAS,gBACTH,YACE,2EAEJ0E,cAAe,CACb5E,OAAO,EACPC,KAAM,UACNI,QAAS,wBACTH,YAAa,yDAEf2E,iBAAkB,CAChB7E,OAAO,EACPC,KAAM,UACNI,QAAS,2BACTH,YAAa,mDAGjB4E,MAAO,CACLvC,OAAQ,CACNvC,OAAO,EACPC,KAAM,UACNI,QAAS,eACTmC,QAAS,cACTtC,YAAa,8DAEf6E,SAAU,CACR/E,OAAO,EACPC,KAAM,UACNI,QAAS,iBACTH,YACE,8EAEJ8E,SAAU,CACRhF,OAAO,EACPC,KAAM,UACNI,QAAS,iBACTH,YACE,8EAEJ+E,gBAAiB,CACfjF,OAAO,EACPC,KAAM,UACNI,QAAS,0BACTH,YACE,oFAEJgF,OAAQ,CACNlF,OAAO,EACPC,KAAM,UACNI,QAAS,eACTH,YACE,qFAEJiF,OAAQ,CACNnF,MAAO,EACPC,KAAM,SACNI,QAAS,gBACTH,YACE,4EAEJkF,cAAe,CACbpF,MAAO,KACPC,KAAM,SACNI,QAAS,uBACTH,YAAa,kCAGjBmF,UAAW,CACT9C,OAAQ,CACNvC,OAAO,EACPC,KAAM,UACNI,QAAS,oBACTmC,QAAS,WACTtC,YAAa,iDAEfoF,UAAW,CACTtF,OAAO,EACPC,KAAM,UACNI,QAAS,uBACTmC,QAAS,cACTtC,YACE,gGAEJqF,mBAAoB,CAClBvF,OAAO,EACPC,KAAM,UACNI,QAAS,iCACTmC,QAAS,uBACTtC,YACE,yGAEJsF,YAAa,CACXxF,MAAO,KACPC,KAAM,SACNI,QAAS,0BACTmC,QAAS,gBACTtC,YACE,4FAEJuF,kBAAmB,CACjBzF,MAAO,IACPC,KAAM,SACNI,QAAS,gCACTmC,QAAS,sBACTtC,YAAa,6DAEfwF,kBAAmB,CACjB1F,MAAO,EACPC,KAAM,SACNI,QAAS,gCACTmC,QAAS,sBACTtC,YACE,yEAEJyF,gBAAiB,CACf3F,MAAO,EACPC,KAAM,SACNI,QAAS,8BACTmC,QAAS,oBACTtC,YACE,4FAEJ0F,IAAK,CACH5F,OAAO,EACPC,KAAM,SACNI,QAAS,iBACTmC,QAAS,QACTtC,YAAa,oCAEf2F,OAAQ,CACN7F,OAAO,EACPC,KAAM,SACNI,QAAS,oBACTmC,QAAS,WACTtC,YACE,8EAWK4F,EAAgB,CAC3BhG,UAAW,CACT,CACEG,KAAM,OACN8F,KAAM,OACNC,QAAS,sBACTC,QAASpG,EAAcC,UAAUC,KAAKC,MAAMkG,KAAK,KACjDC,UAAW,MAGfhG,WAAY,CACV,CACEF,KAAM,OACN8F,KAAM,UACNC,QAAS,qBACTC,QAASpG,EAAcM,WAAWC,QAAQJ,OAE5C,CACEC,KAAM,OACN8F,KAAM,SACNC,QAAS,iBACTC,QAASpG,EAAcM,WAAWG,OAAON,OAE3C,CACEC,KAAM,cACN8F,KAAM,cACNC,QAAS,yBACTI,aAAc,yDACdC,QAASxG,EAAcM,WAAWI,YAAYP,OAEhD,CACEC,KAAM,cACN8F,KAAM,gBACNC,QAAS,2BACTI,aAAc,yDACdC,QAASxG,EAAcM,WAAWK,cAAcR,OAElD,CACEC,KAAM,cACN8F,KAAM,mBACNC,QAAS,8BACTI,aAAc,yDACdC,QAASxG,EAAcM,WAAWM,iBAAiBT,OAErD,CACEC,KAAM,OACN8F,KAAM,gBACNC,QAAS,iBACTC,QAASpG,EAAcM,WAAWO,cAAcV,MAAMkG,KAAK,KAC3DC,UAAW,KAEb,CACElG,KAAM,SACN8F,KAAM,aACNC,QAAS,6BACTC,QAASpG,EAAcM,WAAWQ,WAAWX,OAE/C,CACEC,KAAM,OACN8F,KAAM,YACNC,QAAS,kCACTC,QAASpG,EAAcM,WAAWS,UAAUZ,QAGhDa,OAAQ,CACN,CACEZ,KAAM,SACN8F,KAAM,OACNC,QAAS,+BACTM,KAAM,YAAYzG,EAAcgB,OAAOZ,KAAKD,QAC5CiG,QAAS,EACTI,QAAS,CAAC,MAAO,OAAQ,MAAO,QAElC,CACEpG,KAAM,SACN8F,KAAM,SACNC,QAAS,yCACTM,KAAM,YAAYzG,EAAcgB,OAAOK,OAAOlB,QAC9CiG,QAAS,EACTI,QAAS,CAAC,QAAS,aAAc,WAAY,eAE/C,CACEpG,KAAM,SACN8F,KAAM,gBACNC,QAAS,oDACTC,QAASpG,EAAcgB,OAAOM,cAAcnB,OAE9C,CACEC,KAAM,SACN8F,KAAM,eACNC,QAAS,mDACTC,QAASpG,EAAcgB,OAAOO,aAAapB,OAE7C,CACEC,KAAM,SACN8F,KAAM,eACNC,QAAS,mDACTC,QAASpG,EAAcgB,OAAOQ,aAAarB,MAC3CuG,IAAK,GACLC,IAAK,GAEP,CACEvG,KAAM,SACN8F,KAAM,uBACNC,QAAS,gDACTC,QAASpG,EAAcgB,OAAOe,qBAAqB5B,QAGvD6B,YAAa,CACX,CACE5B,KAAM,SACN8F,KAAM,qBACNC,QAAS,kCACTC,QAASpG,EAAcgC,YAAYC,mBAAmB9B,OAExD,CACEC,KAAM,SACN8F,KAAM,qBACNC,QAAS,wBACTC,QAASpG,EAAcgC,YAAYE,mBAAmB/B,QAG1DsC,OAAQ,CACN,CACErC,KAAM,SACN8F,KAAM,SACNC,QAAS,+BACTC,QAASpG,EAAcyC,OAAOC,OAAOvC,OAEvC,CACEC,KAAM,OACN8F,KAAM,OACNC,QAAS,kBACTC,QAASpG,EAAcyC,OAAOG,KAAKzC,OAErC,CACEC,KAAM,SACN8F,KAAM,OACNC,QAAS,cACTC,QAASpG,EAAcyC,OAAOI,KAAK1C,OAErC,CACEC,KAAM,SACN8F,KAAM,eACNC,QAAS,6BACTC,QAASpG,EAAcyC,OAAOK,aAAa3C,OAE7C,CACEC,KAAM,OACN8F,KAAM,aACNC,QAAS,sCACTC,QAASpG,EAAcyC,OAAOM,MAAMH,KAAKzC,OAE3C,CACEC,KAAM,SACN8F,KAAM,aACNC,QAAS,sCACTC,QAASpG,EAAcyC,OAAOM,MAAMF,KAAK1C,OAE3C,CACEC,KAAM,SACN8F,KAAM,gBACNC,QAAS,0CACTC,QAASpG,EAAcyC,OAAOM,MAAMC,QAAQ7C,OAE9C,CACEC,KAAM,SACN8F,KAAM,sBACNC,QAAS,uBACTC,QAASpG,EAAcyC,OAAOQ,aAAaP,OAAOvC,OAEpD,CACEC,KAAM,SACN8F,KAAM,2BACNC,QAAS,0CACTC,QAASpG,EAAcyC,OAAOQ,aAAaC,YAAY/C,OAEzD,CACEC,KAAM,SACN8F,KAAM,sBACNC,QAAS,2CACTC,QAASpG,EAAcyC,OAAOQ,aAAaE,OAAOhD,OAEpD,CACEC,KAAM,SACN8F,KAAM,qBACNC,QACE,oEACFC,QAASpG,EAAcyC,OAAOQ,aAAaG,MAAMjD,OAEnD,CACEC,KAAM,SACN8F,KAAM,0BACNC,QAAS,wCACTC,QAASpG,EAAcyC,OAAOQ,aAAaI,WAAWlD,OAExD,CACEC,KAAM,OACN8F,KAAM,uBACNC,QACE,8EACFC,QAASpG,EAAcyC,OAAOQ,aAAaK,QAAQnD,OAErD,CACEC,KAAM,OACN8F,KAAM,yBACNC,QACE,4EACFC,QAASpG,EAAcyC,OAAOQ,aAAaM,UAAUpD,OAEvD,CACEC,KAAM,SACN8F,KAAM,aACNC,QAAS,sBACTC,QAASpG,EAAcyC,OAAOe,IAAId,OAAOvC,OAE3C,CACEC,KAAM,SACN8F,KAAM,YACNC,QAAS,gCACTC,QAASpG,EAAcyC,OAAOe,IAAIC,MAAMtD,OAE1C,CACEC,KAAM,SACN8F,KAAM,WACNC,QAAS,kBACTC,QAASpG,EAAcyC,OAAOe,IAAIX,KAAK1C,OAEzC,CACEC,KAAM,OACN8F,KAAM,eACNC,QAAS,2CACTC,QAASpG,EAAcyC,OAAOe,IAAIE,SAASvD,QAG/CwD,KAAM,CACJ,CACEvD,KAAM,SACN8F,KAAM,aACNC,QAAS,yCACTC,QAASpG,EAAc2D,KAAKC,WAAWzD,OAEzC,CACEC,KAAM,SACN8F,KAAM,aACNC,QAAS,yCACTC,QAASpG,EAAc2D,KAAKE,WAAW1D,OAEzC,CACEC,KAAM,SACN8F,KAAM,YACNC,QACE,iFACFC,QAASpG,EAAc2D,KAAKG,UAAU3D,OAExC,CACEC,KAAM,SACN8F,KAAM,iBACNC,QAAS,8DACTC,QAASpG,EAAc2D,KAAKI,eAAe5D,OAE7C,CACEC,KAAM,SACN8F,KAAM,gBACNC,QAAS,6DACTC,QAASpG,EAAc2D,KAAKK,cAAc7D,OAE5C,CACEC,KAAM,SACN8F,KAAM,iBACNC,QAAS,+DACTC,QAASpG,EAAc2D,KAAKM,eAAe9D,OAE7C,CACEC,KAAM,SACN8F,KAAM,cACNC,QAAS,iEACTC,QAASpG,EAAc2D,KAAKO,YAAY/D,OAE1C,CACEC,KAAM,SACN8F,KAAM,sBACNC,QACE,kEACFC,QAASpG,EAAc2D,KAAKQ,oBAAoBhE,OAElD,CACEC,KAAM,SACN8F,KAAM,iBACNC,QACE,+FACFC,QAASpG,EAAc2D,KAAKS,eAAejE,OAE7C,CACEC,KAAM,SACN8F,KAAM,eACNC,QAAS,0CACTC,QAASpG,EAAc2D,KAAKb,aAAa3C,QAG7CkE,QAAS,CACP,CACEjE,KAAM,SACN8F,KAAM,QACNC,QACE,uFACFC,QAASpG,EAAcqE,QAAQC,MAAMnE,MACrCyG,MAAO,EACPF,IAAK,EACLC,IAAK,GAEP,CACEvG,KAAM,OACN8F,KAAM,OACNC,QAAS,iEACTC,QAASpG,EAAcqE,QAAQE,KAAKpE,OAEtC,CACEC,KAAM,OACN8F,KAAM,OACNC,QAAS,8CACTC,QAASpG,EAAcqE,QAAQG,KAAKrE,QAGxCsE,GAAI,CACF,CACErE,KAAM,SACN8F,KAAM,SACNC,QAAS,kCACTC,QAASpG,EAAcyE,GAAG/B,OAAOvC,OAEnC,CACEC,KAAM,OACN8F,KAAM,QACNC,QAAS,2BACTC,QAASpG,EAAcyE,GAAGC,MAAMvE,QAGpCwE,MAAO,CACL,CACEvE,KAAM,OACN8F,KAAM,UACNC,QAAS,kCACTC,QAASpG,EAAc2E,MAAMC,QAAQzE,OAEvC,CACEC,KAAM,SACN8F,KAAM,uBACNC,QAAS,uDACTC,QAASpG,EAAc2E,MAAME,qBAAqB1E,OAEpD,CACEC,KAAM,SACN8F,KAAM,SACNC,QAAS,6DACTC,QAASpG,EAAc2E,MAAMG,OAAO3E,OAEtC,CACEC,KAAM,SACN8F,KAAM,gBACNC,QAAS,uDACTC,QAASpG,EAAc2E,MAAMI,cAAc5E,OAE7C,CACEC,KAAM,SACN8F,KAAM,mBACNC,QAAS,gDACTC,QAASpG,EAAc2E,MAAMK,iBAAiB7E,QAGlD8E,MAAO,CACL,CACE7E,KAAM,SACN8F,KAAM,SACNC,QAAS,8CACTC,QAASpG,EAAciF,MAAMvC,OAAOvC,OAEtC,CACEC,KAAM,SACN8F,KAAM,WACNC,QAAS,mCACTC,QAASpG,EAAciF,MAAMC,SAAS/E,OAExC,CACEC,KAAM,SACN8F,KAAM,WACNC,QAAS,uCACTC,QAASpG,EAAciF,MAAME,SAAShF,OAExC,CACEC,KAAM,SACN8F,KAAM,kBACNC,QAAS,2DACTC,QAASpG,EAAciF,MAAMG,gBAAgBjF,OAE/C,CACEC,KAAM,SACN8F,KAAM,SACNC,QAAS,4DACTC,QAASpG,EAAciF,MAAMI,OAAOlF,OAEtC,CACEC,KAAM,SACN8F,KAAM,SACNC,QAAS,iDACTC,QAASpG,EAAciF,MAAMK,OAAOnF,OAEtC,CACEC,KAAM,SACN8F,KAAM,gBACNC,QAAS,gCACTC,QAASpG,EAAciF,MAAMM,cAAcpF,QAG/CqF,UAAW,CACT,CACEpF,KAAM,SACN8F,KAAM,SACNC,QAAS,+BACTC,QAASpG,EAAcwF,UAAU9C,OAAOvC,OAE1C,CACEC,KAAM,SACN8F,KAAM,YACNC,QAAS,mDACTC,QAASpG,EAAcwF,UAAUC,UAAUtF,OAE7C,CACEC,KAAM,SACN8F,KAAM,qBACNC,QAAS,yDACTC,QAASpG,EAAcwF,UAAUE,mBAAmBvF,OAEtD,CACEC,KAAM,SACN8F,KAAM,cACNC,QAAS,qCACTC,QAASpG,EAAcwF,UAAUG,YAAYxF,OAE/C,CACEC,KAAM,SACN8F,KAAM,oBACNC,QAAS,uCACTC,QAASpG,EAAcwF,UAAUI,kBAAkBzF,OAErD,CACEC,KAAM,SACN8F,KAAM,oBACNC,QAAS,mCACTC,QAASpG,EAAcwF,UAAUK,kBAAkB1F,OAErD,CACEC,KAAM,SACN8F,KAAM,kBACNC,QAAS,qCACTC,QAASpG,EAAcwF,UAAUM,gBAAgB3F,OAEnD,CACEC,KAAM,OACN8F,KAAM,MACNC,QAAS,kCACTC,QAASpG,EAAcwF,UAAUO,IAAI5F,OAEvC,CACEC,KAAM,OACN8F,KAAM,SACNC,QAAS,6CACTC,QAASpG,EAAcwF,UAAUQ,OAAO7F,SAMjC0G,EAAgB,CAC3B,UACA,gBACA,eACA,YACA,WAIWC,EAAa,CAAA,EASpBC,EAAmB,CAACC,EAAKC,EAAY,MACzCC,OAAOC,KAAKH,GAAKI,SAASC,IACxB,IAAK,CAAC,YAAa,cAAcC,SAASD,GAAI,CAC5C,MAAME,EAAQP,EAAIK,QACS,IAAhBE,EAAMpH,MAEf4G,EAAiBQ,EAAO,GAAGN,KAAaI,MAGxCP,EAAWS,EAAM5E,SAAW0E,GAAK,GAAGJ,KAAaI,IAAIG,UAAU,QAGtCC,IAArBF,EAAMhF,aACRuE,EAAWS,EAAMhF,YAAc,GAAG0E,KAAaI,IAAIG,UAAU,IAGlE,IACD,EAGJT,EAAiB/G,GCruCjB0H,EAAOC,SAIP,MAAMC,EAGIC,GACNC,EACGC,SACAC,WAAW7H,GACVA,EACG8H,MAAM,KACNC,KAAK/H,GAAUA,EAAMgI,SACrBC,QAAQjI,GAAU0H,EAAYP,SAASnH,OAE3C6H,WAAW7H,GAAWA,EAAMkI,OAASlI,OAAQsH,IAZ9CG,EAgBK,IACPE,EACGQ,KAAK,CAAC,OAAQ,QAAS,KACvBN,WAAW7H,GAAqB,KAAVA,EAAyB,SAAVA,OAAmBsH,IAnBzDG,EAuBGW,GACLT,EACGQ,KAAK,IAAIC,EAAQ,KACjBP,WAAW7H,GAAqB,KAAVA,EAAeA,OAAQsH,IA1B9CG,EA8BI,IACNE,EACGC,SACAI,OACAK,QACErI,IACE,CAAC,QAAS,YAAa,OAAQ,OAAOmH,SAASnH,IACtC,KAAVA,IACDA,IAAW,CACVgG,QAAS,mDAAmDhG,SAG/D6H,WAAW7H,GAAqB,KAAVA,EAAeA,OAAQsH,IA1C9CG,EA8CS,IACXE,EACGC,SACAI,OACAK,QACErI,GACW,KAAVA,IAAkBsI,MAAMC,WAAWvI,KAAWuI,WAAWvI,GAAS,IACnEA,IAAW,CACVgG,QAAS,qDAAqDhG,SAGjE6H,WAAW7H,GAAqB,KAAVA,EAAeuI,WAAWvI,QAASsH,IAzD1DG,EA6DY,IACdE,EACGC,SACAI,OACAK,QACErI,GACW,KAAVA,IAAkBsI,MAAMC,WAAWvI,KAAWuI,WAAWvI,IAAU,IACpEA,IAAW,CACVgG,QAAS,yDAAyDhG,SAGrE6H,WAAW7H,GAAqB,KAAVA,EAAeuI,WAAWvI,QAASsH,IAuInDkB,EApISb,EAAEc,OAAO,CAE7BC,mBAAoBf,EACjBC,SACAI,OACAK,QACErI,GAAU,6BAA6B2I,KAAK3I,IAAoB,KAAVA,IACtDA,IAAW,CACVgG,QAAS,4FAA4FhG,SAGxG6H,WAAW7H,GAAqB,KAAVA,EAAeA,OAAQsH,IAChDsB,mBAAoBjB,EACjBC,SACAI,OACAK,QACErI,GACCA,EAAM6I,WAAW,aACjB7I,EAAM6I,WAAW,YACP,KAAV7I,IACDA,IAAW,CACVgG,QAAS,6FAA6FhG,SAGzG6H,WAAW7H,GAAqB,KAAVA,EAAeA,OAAQsH,IAChDwB,wBAAyBrB,EAAQhI,EAAaC,MAC9CqJ,0BAA2BtB,EAAQhI,EAAaE,SAChDqJ,6BAA8BvB,EAAQhI,EAAaG,YACnDqJ,uBAAwBxB,IACxByB,sBAAuBzB,IACvB0B,uBAAwB1B,IAGxB2B,YAAa3B,EAAO,CAAC,OAAQ,MAAO,MAAO,QAC3C4B,cAAe5B,EAAO,CAAC,QAAS,aAAc,WAAY,eAC1D6B,sBAAuB7B,IACvB8B,qBAAsB9B,IACtB+B,qBAAsB/B,IACtBgC,6BAA8BhC,IAG9BiC,kCAAmCjC,IACnCkC,kCAAmClC,IAGnCmC,cAAenC,IACfoC,YAAapC,IACbqC,YAAarC,IACbsC,oBAAqBtC,IAGrBuC,kBAAmBvC,IACnBwC,kBAAmBxC,IACnByC,qBAAsBzC,IAGtB0C,4BAA6B1C,IAC7B2C,kCAAmC3C,IACnC4C,4BAA6B5C,IAC7B6C,2BAA4B7C,IAC5B8C,iCAAkC9C,IAClC+C,8BAA+B/C,IAC/BgD,gCAAiChD,IAGjCiD,kBAAmBjD,IACnBkD,iBAAkBlD,IAClBmD,gBAAiBnD,IACjBoD,qBAAsBpD,IAGtBqD,iBAAkBrD,IAClBsD,iBAAkBtD,IAClBuD,gBAAiBvD,IACjBwD,qBAAsBxD,IACtByD,oBAAqBzD,IACrB0D,qBAAsB1D,IACtB2D,kBAAmB3D,IACnB4D,2BAA4B5D,IAC5B6D,qBAAsB7D,IACtB8D,kBAAmB9D,IAGnB+D,cAAe7D,EACZC,SACAI,OACAK,QACErI,GACW,KAAVA,IACEsI,MAAMC,WAAWvI,KACjBuI,WAAWvI,IAAU,GACrBuI,WAAWvI,IAAU,IACxBA,IAAW,CACVgG,QAAS,mGAAmGhG,SAG/G6H,WAAW7H,GAAqB,KAAVA,EAAeuI,WAAWvI,QAASsH,IAC5DmE,aAAchE,IACdiE,aAAcjE,IAGdkE,UAAWlE,IACXmE,SAAUnE,IAGVoE,eAAgBpE,EAAO,CAAC,cAAe,aAAc,SACrDqE,8BAA+BrE,IAC/BsE,cAAetE,IACfuE,sBAAuBvE,IACvBwE,yBAA0BxE,IAG1ByE,aAAczE,IACd0E,eAAgB1E,IAChB2E,eAAgB3E,IAChB4E,wBAAyB5E,IACzB6E,aAAc7E,IACd8E,cAAe9E,IACf+E,qBAAsB/E,IAGtBgF,kBAAmBhF,IACnBiF,qBAAsBjF,IACtBkF,+BAAgClF,IAChCmF,wBAAyBnF,IACzBoF,8BAA+BpF,IAC/BqF,8BAA+BrF,IAC/BsF,4BAA6BtF,IAC7BuF,eAAgBvF,IAChBwF,kBAAmBxF,MAGMyF,UAAUC,MAAMC,QAAQC,KClN7CC,EAAS,CAAC,MAAO,SAAU,OAAQ,OAAQ,SAGjD,IAAIpJ,EAAU,CAEZqJ,WAAW,EACXC,QAAQ,EACRC,aAAa,EAEbC,WAAY,CACV,CACEC,MAAO,QACPC,MAAON,EAAO,IAEhB,CACEK,MAAO,UACPC,MAAON,EAAO,IAEhB,CACEK,MAAO,SACPC,MAAON,EAAO,IAEhB,CACEK,MAAO,UACPC,MAAON,EAAO,IAEhB,CACEK,MAAO,YACPC,MAAON,EAAO,KAIlBO,UAAW,IAIb,IAAK,MAAOC,EAAKC,KAAWhH,OAAOiH,QAAQnO,EAAcqE,SACvDA,EAAQ4J,GAAOC,EAAO/N,MAWxB,MAAMiO,EAAY,CAACC,EAAOC,KACpBjK,EAAQsJ,SACLtJ,EAAQuJ,eAEVW,EAAWlK,EAAQG,OAASgK,EAAUnK,EAAQG,MAI/CH,EAAQuJ,aAAc,GAIxBa,EACE,GAAGpK,EAAQG,OAAOH,EAAQE,OAC1B,CAAC+J,GAAQI,OAAOL,GAAOhI,KAAK,KAAO,MAClCsI,IACKA,IACFC,QAAQC,IAAI,yCAAyCF,KACrDtK,EAAQsJ,QAAS,EAClB,IAGN,EAWUkB,EAAM,IAAI3O,KACrB,MAAO4O,KAAaT,GAASnO,GAGvBoE,MAAEA,EAAKuJ,WAAEA,GAAexJ,EAG9B,GACe,IAAbyK,IACc,IAAbA,GAAkBA,EAAWxK,GAASA,EAAQuJ,EAAWxF,QAE1D,OAIF,MAGMiG,EAAS,IAHC,IAAIS,MAAOC,WAAW/G,MAAM,KAAK,GAAGE,WAGtB0F,EAAWiB,EAAW,GAAGhB,WAGvDzJ,EAAQ2J,UAAU5G,SAAS6H,IACzBA,EAAGX,EAAQD,EAAMhI,KAAK,KAAK,IAIzBhC,EAAQqJ,WACVkB,QAAQC,IAAIK,WACVzH,EACA,CAAC6G,EAAOU,WAAW3K,EAAQwJ,WAAWiB,EAAW,GAAGf,QAAQW,OAAOL,IAKvED,EAAUC,EAAOC,EAAO,EAYba,EAAe,CAACL,EAAUH,EAAOS,KAE5C,MAAMC,EAAcD,GAAiBT,EAAMxI,SAGrC7B,MAAEA,EAAKuJ,WAAEA,GAAexJ,EAG9B,GAAiB,IAAbyK,GAAkBA,EAAWxK,GAASA,EAAQuJ,EAAWxF,OAC3D,OAIF,MAGMiG,EAAS,IAHC,IAAIS,MAAOC,WAAW/G,MAAM,KAAK,GAAGE,WAGtB0F,EAAWiB,EAAW,GAAGhB,WAGjDwB,EACJX,EAAMxI,UAAYwI,EAAMW,mBAAuC7H,IAAvBkH,EAAMW,aAC1CX,EAAMY,MACNZ,EAAMY,MAAMtH,MAAM,MAAMuH,MAAM,GAAGnJ,KAAK,MAGtCgI,EAAQ,CAACgB,EAAa,KAAMC,GAG9BjL,EAAQqJ,WACVkB,QAAQC,IAAIK,WACVzH,EACA,CAAC6G,EAAOU,WAAW3K,EAAQwJ,WAAWiB,EAAW,GAAGf,QAAQW,OAAO,CACjEW,EAAY5B,EAAOqB,EAAW,IAC9B,KACAQ,KAMNjL,EAAQ2J,UAAU5G,SAAS6H,IACzBA,EAAGX,EAAQD,EAAMhI,KAAK,KAAK,IAI7B+H,EAAUC,EAAOC,EAAO,EASbmB,EAAeX,IACtBA,GAAY,GAAKA,GAAYzK,EAAQwJ,WAAWxF,SAClDhE,EAAQC,MAAQwK,EACjB,EASUY,EAAoB,CAACC,EAASC,KASzC,GAPAvL,EAAU,IACLA,EACHG,KAAMmL,GAAWtL,EAAQG,KACzBD,KAAMqL,GAAWvL,EAAQE,KACzBoJ,QAAQ,GAGkB,IAAxBtJ,EAAQG,KAAK6D,OACf,OAAOwG,EAAI,EAAG,2DAGXxK,EAAQG,KAAKqL,SAAS,OACzBxL,EAAQG,MAAQ,IACjB,EC5MUsL,EAAYC,EAAc,IAAIC,IAAI,mBAAoBjK,MAiEtDkK,EAAU,CAAC7P,EAAMgB,KAE5B,MAQM8O,EAAU,CAAC,MAAO,OAAQ,MAAO,OAGvC,GAAI9O,EAAS,CACX,MAAM+O,EAAU/O,EAAQ6G,MAAM,KAAKmI,MAEnB,QAAZD,EACF/P,EAAO,OACE8P,EAAQ5I,SAAS6I,IAAY/P,IAAS+P,IAC/C/P,EAAO+P,EAEV,CAGD,MAtBkB,CAChB,YAAa,MACb,aAAc,OACd,kBAAmB,MACnB,gBAAiB,OAkBF/P,IAAS8P,EAAQG,MAAMC,GAAMA,IAAMlQ,KAAS,KAAK,EAcvDmQ,EAAkB,CAAClO,GAAY,EAAOH,KACjD,MAAMsO,EAAe,CAAC,KAAM,MAAO,SAEnC,IAAIC,EAAmBpO,EACnBqO,GAAmB,EAGvB,GAAIxO,GAAsBG,EAAUwN,SAAS,SAC3C,IACEY,EAAmBE,EAAcC,EAAavO,EAAW,QAC1D,CAAC,MAAOsM,GACP,OAAOQ,EAAa,EAAGR,EAAO,4BAC/B,MAGD8B,EAAmBE,EAActO,GAG7BoO,IAAqBvO,UAChBuO,EAAiBI,MAK5B,IAAK,MAAMC,KAAYL,EAChBD,EAAalJ,SAASwJ,GAEfJ,IACVA,GAAmB,UAFZD,EAAiBK,GAO5B,OAAKJ,GAKDD,EAAiBI,QACnBJ,EAAiBI,MAAQJ,EAAiBI,MAAM3I,KAAK6I,GAASA,EAAK5I,WAC9DsI,EAAiBI,OAASJ,EAAiBI,MAAMxI,QAAU,WACvDoI,EAAiBI,OAKrBJ,GAZE5B,EAAI,EAAG,4BAYO,EAclB,SAAS8B,EAAcK,EAAMhC,GAClC,IAEE,MAAMiC,EAAaC,KAAK5D,MACN,iBAAT0D,EAAoBE,KAAKC,UAAUH,GAAQA,GAIpD,MAA0B,iBAAfC,GAA2BjC,EAC7BkC,KAAKC,UAAUF,GAIjBA,CACX,CAAI,MACA,OAAO,CACR,CACH,CASO,MA2CMG,EAAYpK,IACvB,GAAY,OAARA,GAA+B,iBAARA,EACzB,OAAOA,EAGT,MAAMqK,EAAOC,MAAMC,QAAQvK,GAAO,GAAK,GAEvC,IAAK,MAAMiH,KAAOjH,EACZE,OAAOsK,UAAUC,eAAeC,KAAK1K,EAAKiH,KAC5CoD,EAAKpD,GAAOmD,EAASpK,EAAIiH,KAI7B,OAAOoD,CAAI,EAaAM,EAAmB,CAACxQ,EAASyQ,IAsBjCV,KAAKC,UAAUhQ,GArBG,CAAC+E,EAAM/F,KACT,iBAAVA,KACTA,EAAQA,EAAMgI,QAILa,WAAW,cAAgB7I,EAAM6I,WAAW,gBACnD7I,EAAM0P,SAAS,OAEf1P,EAAQyR,EACJ,WAAWzR,EAAQ,IAAI0R,WAAW,YAAa,mBAC/CpK,GAIgB,mBAAVtH,EACV,WAAWA,EAAQ,IAAI0R,WAAW,YAAa,cAC/C1R,KAI2C0R,WAC/C,qBACA,IAiCG,SAASC,IAKdlD,QAAQC,IACN,4BAA4BkD,KAC5B,WACA,yDANa,0DAMmDA,KAAKC,WAGvE,MAAMC,EAAmB9Q,IACvB,IAAK,MAAO+E,EAAMgI,KAAWhH,OAAOiH,QAAQhN,GAE1C,GAAK+F,OAAOsK,UAAUC,eAAeC,KAAKxD,EAAQ,SAE3C,CACL,IAAIgE,EAAW,OAAOhE,EAAOvL,SAAWuD,MACrC,IAAMgI,EAAO9N,KAAO,KAAK+R,SAE5B,GAAID,EAAS7J,OAnBP,GAoBJ,IAAK,IAAI+J,EAAIF,EAAS7J,OAAQ+J,EApB1B,GAoBmCA,IACrCF,GAAY,IAKhBtD,QAAQC,IACNqD,EACAhE,EAAO7N,YACP,aAAa6N,EAAO/N,MAAM6O,WAAW+C,QAAQM,KAEhD,MAjBCJ,EAAgB/D,EAkBnB,EAIHhH,OAAOC,KAAKnH,GAAeoH,SAASkL,IAE7B,CAAC,YAAa,cAAchL,SAASgL,KACxC1D,QAAQC,IAAI,KAAKyD,EAASC,gBAAgBC,KAC1CP,EAAgBjS,EAAcsS,IAC/B,IAEH1D,QAAQC,IAAI,KACd,CAUO,MAYM4D,GAAa1B,IACxB,CAAC,QAAS,YAAa,OAAQ,MAAO,IAAK,IAAIzJ,SAASyJ,MAElDA,EAWK2B,GAAa,CAACvQ,EAAYD,KACrC,GAAIC,GAAoC,iBAAfA,EAGvB,OAFAA,EAAaA,EAAWgG,QAET0H,SAAS,SACf3N,GACHwQ,GAAW9B,EAAazO,EAAY,SAGxCA,EAAW6G,WAAW,eACtB7G,EAAW6G,WAAW,gBACtB7G,EAAW6G,WAAW,SACtB7G,EAAW6G,WAAW,SAEf,IAAI7G,OAENA,EAAWwQ,QAAQ,KAAM,GACjC,EASUC,GAAc,KACzB,MAAMC,EAAQtF,QAAQuF,OAAOC,SAC7B,MAAO,IAAMC,OAAOzF,QAAQuF,OAAOC,SAAWF,GAAS,GAAO,ECnahE,IAAII,GAAiB,CAAA,EAOd,MAAMC,GAAa,IAAMD,GAgLnBE,GAAqB,CAAChS,EAASiS,EAAYvM,EAAgB,MACtE,MAAMwM,EAAgBjC,EAASjQ,GAE/B,IAAK,MAAO8M,EAAK9N,KAAU+G,OAAOiH,QAAQiF,GACxCC,EAAcpF,GDFA,iBADO8C,ECIV5Q,IDHgBmR,MAAMC,QAAQR,IAAkB,OAATA,GCI/ClK,EAAcS,SAAS2G,SACDxG,IAAvB4L,EAAcpF,QAEAxG,IAAVtH,EACEA,EACAkT,EAAcpF,GAHhBkF,GAAmBE,EAAcpF,GAAM9N,EAAO0G,GDPhC,IAACkK,ECavB,OAAOsC,CAAa,EAqFtB,SAASC,GAAoBC,EAAWC,EAAY,CAAA,EAAIvM,EAAY,IAClEC,OAAOC,KAAKoM,GAAWnM,SAAS6G,IAC9B,MAAM1G,EAAQgM,EAAUtF,GAClBwF,EAAcD,GAAaA,EAAUvF,QAEhB,IAAhB1G,EAAMpH,MACfmT,GAAoB/L,EAAOkM,EAAa,GAAGxM,KAAagH,WAGpCxG,IAAhBgM,IACFlM,EAAMpH,MAAQsT,GAIZlM,EAAM/G,WAAWmI,QAAgClB,IAAxBkB,EAAKpB,EAAM/G,WACtC+G,EAAMpH,MAAQwI,EAAKpB,EAAM/G,UAE5B,GAEL,CAWA,SAASkT,GAAYC,GACnB,IAAIxS,EAAU,CAAA,EACd,IAAK,MAAO+E,EAAM6K,KAAS7J,OAAOiH,QAAQwF,GACxCxS,EAAQ+E,GAAQgB,OAAOsK,UAAUC,eAAeC,KAAKX,EAAM,SACvDA,EAAK5Q,MACLuT,GAAY3C,GAElB,OAAO5P,CACT,CA6EA,SAASyS,GAAeC,EAAgBC,EAAa3T,GACnD,KAAO2T,EAAYzL,OAAS,GAAG,CAC7B,MAAMyI,EAAWgD,EAAYC,QAc7B,OAXK7M,OAAOsK,UAAUC,eAAeC,KAAKmC,EAAgB/C,KACxD+C,EAAe/C,GAAY,IAI7B+C,EAAe/C,GAAY8C,GACzB1M,OAAO8M,OAAO,CAAA,EAAIH,EAAe/C,IACjCgD,EACA3T,GAGK0T,CACR,CAID,OADAA,EAAeC,EAAY,IAAM3T,EAC1B0T,CACT,CCtaAI,eAAeC,GAAMnO,EAAKoO,EAAiB,IACzC,OAAO,IAAIC,SAAQ,CAACC,EAASC,KAC3B,MAAMC,EAbU,CAACxO,GAASA,EAAIiD,WAAW,SAAWwL,EAAQC,EAa3CC,CAAY3O,GAE7BwO,EACGI,IAAI5O,EAAKoO,GAAiBS,IACzB,IAAI5D,EAAO,GAGX4D,EAAIC,GAAG,QAASC,IACd9D,GAAQ8D,CAAK,IAIfF,EAAIC,GAAG,OAAO,KACP7D,GACHsD,EAAO,qCAGTM,EAAIG,KAAO/D,EACXqD,EAAQO,EAAI,GACZ,IAEHC,GAAG,SAAUlG,IACZ2F,EAAO3F,EAAM,GACb,GAER,CCpDA,MAAMqG,WAAoBC,MACxB,WAAAC,CAAY/O,GACVgP,QACAC,KAAKjP,QAAUA,EACfiP,KAAK9F,aAAenJ,CACrB,CAED,QAAAkP,CAAS1G,GAYP,OAXAyG,KAAKzG,MAAQA,EACTA,EAAMzI,OACRkP,KAAKlP,KAAOyI,EAAMzI,MAEhByI,EAAM2G,aACRF,KAAKE,WAAa3G,EAAM2G,YAEtB3G,EAAMY,QACR6F,KAAK9F,aAAeX,EAAMxI,QAC1BiP,KAAK7F,MAAQZ,EAAMY,OAEd6F,IACR,ECWH,MAAMG,GAAQ,CACZ9U,OAAQ,+BACR+U,eAAgB,CAAE,EAClBC,QAAS,GACTC,UAAW,IAQAC,GAAkBJ,GACtBA,EAAME,QACVjO,UAAU,EAAG+N,EAAME,QAAQG,QAAQ,OACnCjD,QAAQ,KAAM,IACdA,QAAQ,KAAM,IACdA,QAAQ,MAAO,IACfxK,OAgEQ0N,GAAwB5B,MACnC6B,EACA3B,EACA4B,EACAC,GAAmB,KAGfF,EAAOjG,SAAS,SAClBiG,EAASA,EAAOtO,UAAU,EAAGsO,EAAOzN,OAAS,IAG/CwG,EAAI,EAAG,6BAA6BiH,QAGpC,MAAMG,QAAiB/B,GAAM,GAAG4B,OAAa3B,GAG7C,GAA4B,MAAxB8B,EAASX,YAA8C,iBAAjBW,EAASlB,KAAkB,CACnE,GAAIgB,EAAgB,CAElBA,EADqCD,EA5EvBnD,QAChB,qEACA,KA2E+B,CAC9B,CAED,OAAOsD,EAASlB,IACjB,CAED,GAAIiB,EACF,MAAM,IAAIhB,GACR,uBAAuBc,2EAAgFG,EAASX,gBAChHD,SAASY,GAQb,OANEpH,EACE,EACA,+BAA+BiH,8DAI5B,EAAE,EA+EEI,GAAcjC,MACzBkC,EACAC,EACAC,KAEA,MAAM9V,EAAU4V,EAAkB5V,QAC5BmV,EAAwB,WAAZnV,GAAyBA,EAAe,GAAGA,KAAR,GAC/CE,EAAS0V,EAAkB1V,QAAU8U,GAAM9U,OAEjDoO,EACE,EACA,iDAAiD6G,GAAa,aAGhE,MAAMK,EAAiB,CAAA,EACvB,IAwBE,OAvBAR,GAAME,aA9EkBxB,OAC1BvT,EACAC,EACAE,EACAuV,EACAL,KAGA,IAAIO,EACJ,MAAMC,EAAYH,EAAaxT,KACzB4T,EAAYJ,EAAavT,KAG/B,GAAI0T,GAAaC,EACf,IACEF,EAAa,IAAIG,EAAgB,CAC/B7T,KAAM2T,EACN1T,KAAM2T,GAET,CAAC,MAAO7H,GACP,MAAM,IAAIqG,GAAY,2CAA2CK,SAC/D1G,EAEH,CAIH,MAAMwF,EAAiBmC,EACnB,CACEI,MAAOJ,EACPtT,QAAS2F,EAAK0B,sBAEhB,GAEEsM,EAAmB,IACpBjW,EAAYwH,KAAK4N,GAClBD,GAAsB,GAAGC,IAAU3B,EAAgB4B,GAAgB,QAElEpV,EAAcuH,KAAK4N,GACpBD,GAAsB,GAAGC,IAAU3B,EAAgB4B,QAElDlV,EAAcqH,KAAK4N,GACpBD,GAAsB,GAAGC,IAAU3B,MAKvC,aAD6BC,QAAQwC,IAAID,IACnBtQ,KAAK,MAAM,EA+BTwQ,CACpB,IACKV,EAAkBzV,YAAYwH,KAAK4O,GAAM,GAAGrW,IAASiV,IAAYoB,OAEtE,IACKX,EAAkBxV,cAAcuH,KAAK6O,GAChC,QAANA,EACI,GAAGtW,SAAciV,YAAoBqB,IACrC,GAAGtW,IAASiV,YAAoBqB,SAEnCZ,EAAkBvV,iBAAiBsH,KACnCkK,GAAM,GAAG3R,UAAeiV,eAAuBtD,OAGpD+D,EAAkBtV,cAClBuV,EACAL,GAGFR,GAAMG,UAAYC,GAAeJ,IAGjCyB,EAAcX,EAAYd,GAAME,SACzBM,CACR,CAAC,MAAOpH,GACP,MAAM,IAAIqG,GACR,wDACAK,SAAS1G,EACZ,GAiCUsI,GAAsBhD,MAAO9S,IACxC,MAAMb,WAAEA,EAAUmC,OAAEA,GAAWtB,EACzBJ,EAAYsF,EAAKyJ,EAAWxP,EAAWS,WAE7C,IAAIgV,EAEJ,MAAMmB,EAAe7Q,EAAKtF,EAAW,iBAC/BsV,EAAahQ,EAAKtF,EAAW,cAOnC,IAJCwN,EAAWxN,IAAcyN,EAAUzN,IAI/BwN,EAAW2I,IAAiB5W,EAAWQ,WAC1C+N,EAAI,EAAG,yDACPkH,QAAuBG,GAAY5V,EAAYmC,EAAOM,MAAOsT,OACxD,CACL,IAAIc,GAAgB,EAGpB,MAAMC,EAAWlG,KAAK5D,MAAMsD,EAAasG,IAIzC,GAAIE,EAAStX,SAAWwR,MAAMC,QAAQ6F,EAAStX,SAAU,CACvD,MAAMuX,EAAY,CAAA,EAClBD,EAAStX,QAAQsH,SAAS2P,GAAOM,EAAUN,GAAK,IAChDK,EAAStX,QAAUuX,CACpB,CAED,MAAM3W,YAAEA,EAAWC,cAAEA,EAAaC,iBAAEA,GAAqBN,EACnDgX,EACJ5W,EAAY2H,OAAS1H,EAAc0H,OAASzH,EAAiByH,OAK3D+O,EAAS7W,UAAYD,EAAWC,SAClCsO,EACE,EACA,yEAEFsI,GAAgB,GACPjQ,OAAOC,KAAKiQ,EAAStX,SAAW,IAAIuI,SAAWiP,GACxDzI,EACE,EACA,+EAEFsI,GAAgB,GAGhBA,GAAiBxW,GAAiB,IAAI4W,MAAMC,IAC1C,IAAKJ,EAAStX,QAAQ0X,GAKpB,OAJA3I,EACE,EACA,eAAe2I,iDAEV,CACR,IAIDL,EACFpB,QAAuBG,GAAY5V,EAAYmC,EAAOM,MAAOsT,IAE7DxH,EAAI,EAAG,uDAGP0G,GAAME,QAAU7E,EAAayF,EAAY,QAGzCN,EAAiBqB,EAAStX,QAE1ByV,GAAMG,UAAYC,GAAeJ,IAEpC,MArTiCtB,OAAOtM,EAAQoO,KACjD,MAAM0B,EAAc,CAClBlX,QAASoH,EAAOpH,QAChBT,QAASiW,GAAkB,CAAE,GAI/BR,GAAMC,eAAiBiC,EAEvB5I,EAAI,EAAG,mCACP,IACEmI,EACE3Q,EAAKyJ,EAAWnI,EAAO5G,UAAW,iBAClCmQ,KAAKC,UAAUsG,GACf,OAEH,CAAC,MAAO9I,GACP,MAAM,IAAIqG,GAAY,6CAA6CK,SACjE1G,EAEH,GAqSK+I,CAAqBpX,EAAYyV,EAAe,EAG3C4B,GAAe,IAC1BtR,EAAKyJ,EAAWoD,KAAa5S,WAAWS,WAM7BR,GAAU,IAAMgV,GAAMG,UCzX5B,SAASkC,KACdC,WAAWC,WAAa,WACtB,MAAO,CAAEC,SAAU,EACvB,CACA,CASO9D,eAAe+D,GAAcC,EAAc9W,EAAS+W,GAEzD/U,OAAOgV,eAAiBD,EAGxB,MAAMhF,WAAEA,EAAUkF,MAAEA,EAAKC,WAAEA,EAAUC,KAAEA,GAAST,WAIhDA,WAAWU,cAAgBH,GAAM,EAAO,CAAE,EAAElF,KAGxC/R,EAAQa,YAAYG,YACtB,IAAIqW,SAASrX,EAAQa,YAAYG,WAAjC,GAIF,MAAMsW,EAAQ,CACZC,WAAW,GAITvX,EAAQH,OAAO2X,SACjBF,EAAMhX,OAASwW,EAAaQ,MAAMhX,OAClCgX,EAAM/W,MAAQuW,EAAaQ,MAAM/W,OAInCyB,OAAOyV,kBAAmB,EAC1BN,EAAKT,WAAWgB,MAAMrH,UAAW,QAAQ,SAAUsH,EAASC,EAAaC,KAEvED,EAAcX,EAAMW,EAAa,CAC/BE,UAAW,CACTC,SAAS,GAEXC,YAAa,CACXC,OAAQ,CACNC,MAAO,CACLH,SAAS,KAOfI,QAAS,CAAE,KAGAF,QAAU,IAAIhS,SAAQ,SAAUgS,GAC3CA,EAAOV,WAAY,CACzB,IAGSvV,OAAOoW,qBACVpW,OAAOoW,mBAAqB1B,WAAW2B,SAASpE,KAAM,UAAU,KAC9DjS,OAAOyV,kBAAmB,CAAI,KAIlCE,EAAQ5J,MAAMkG,KAAM,CAAC2D,EAAaC,GACtC,IAEEV,EAAKT,WAAW4B,OAAOjI,UAAW,QAAQ,SAAUsH,EAASL,EAAOtX,GAClE2X,EAAQ5J,MAAMkG,KAAM,CAACqD,EAAOtX,GAChC,IAGE,MAAM4X,EAAc5X,EAAQH,OAAO2X,OAC/B,IAAIH,SAAS,UAAUrX,EAAQH,OAAO2X,SAAtC,GACAV,EAIEyB,EAAetB,GACnB,EACAlH,KAAK5D,MAAMnM,EAAQH,OAAOa,cAC1BkX,EAEA,CAAEN,UAGEkB,EAAgBxY,EAAQa,YAAYI,SACtC,IAAIoW,SAAS,UAAUrX,EAAQa,YAAYI,WAA3C,QACAqF,EAGE7F,EAAgBsP,KAAK5D,MAAMnM,EAAQH,OAAOY,eAC5CA,GACFyW,EAAWzW,GAGbiW,WAAW1W,EAAQH,OAAOK,QAAU,SAClC,YACAqY,EACAC,GAIF,MAAMC,EAAiB1G,IAGvB,IAAK,MAAM2G,KAAQD,EACmB,mBAAzBA,EAAeC,WACjBD,EAAeC,GAK1BxB,EAAWR,WAAWU,eAGtBV,WAAWU,cAAgB,EAC7B,CCpHA,MAAMuB,GAAWlJ,EAAad,EAAY,2BAA4B,QAEtE,IAAIiK,GAiIG9F,eAAe+F,KACpB,IAAKD,GACH,OAAO,EAIT,MAAME,QAAaF,GAAQC,UAW3B,aARMC,EAAKC,iBAAgB,SAGrBC,GAAeF,GA+NvB,SAAuBA,GAErB,MAAMhV,MAAEA,GAAUiO,KAGdjO,EAAMvC,QAAUuC,EAAMG,iBACxB6U,EAAKpF,GAAG,WAAY1O,IAClByI,QAAQC,IAAI,WAAW1I,EAAQ4O,SAAS,IAK5CkF,EAAKpF,GAAG,aAAaZ,MAAOtF,UAGpBsL,EAAKG,MACT,cACA,CAACC,EAASC,KAEJnX,OAAOgV,iBACTkC,EAAQE,UAAYD,EACrB,GAEH,oCAAoC3L,EAAMK,aAC3C,GAEL,CAtPEwL,CAAcP,GAEPA,CACT,CAwJOhG,eAAewG,GAAmBR,EAAMS,GAC7C,IAAK,MAAMC,KAAYD,QACfC,EAASC,gBAIXX,EAAKY,UAAS,KAGlB,GAA0B,oBAAfhD,WAA4B,CAErC,MAAMiD,EAAYjD,WAAWkD,OAG7B,GAAIzJ,MAAMC,QAAQuJ,IAAcA,EAAUzS,OAExC,IAAK,MAAM2S,KAAYF,EACrBE,GAAYA,EAASC,UAErBpD,WAAWkD,OAAOhH,OAGvB,CAGD,SAAUmH,GAAmBC,SAASC,qBAAqB,WAErD,IAAMC,GAAkBF,SAASC,qBAAqB,aAElDE,GAAiBH,SAASC,qBAAqB,QAGzD,IAAK,MAAMf,IAAW,IACjBa,KACAG,KACAC,GAEHjB,EAAQkB,QACT,GAEL,CAUAtH,eAAekG,GAAeF,SACtBA,EAAKuB,WAAW1B,GAAU,CAAE2B,UAAW,2BAGvCxB,EAAKyB,aAAa,CAAEC,KAAM,GAAGhE,0BAG7BsC,EAAKY,SAASjD,GACtB,CCnWA,MAwGMgE,GAAc3H,MAAOgG,EAAMxB,EAAOtX,EAAS+W,IAC/C+B,EAAKY,SAAS7C,GAAeS,EAAOtX,EAAS+W,GAY/C,IAAA2D,GAAe5H,MAAOgG,EAAMxB,EAAOtX,KAEjC,IAAIuZ,EAAoB,GAExB,IACE7L,EAAI,EAAG,qCAEP,MAAMiN,EAAgB3a,EAAQH,OAGxBkX,EACJ4D,GAAe3a,SAASsX,OAAOP,eHwOP3C,GGvObC,eAAe1V,QAAQic,SAEpC,IAAIC,EACJ,GACEvD,EAAM7C,UACL6C,EAAM7C,QAAQ,SAAW,GAAK6C,EAAM7C,QAAQ,UAAY,GACzD,CAKA,GAHA/G,EAAI,EAAG,6BAGoB,QAAvBiN,EAAc1b,KAChB,OAAOqY,EAGTuD,GAAQ,QACF/B,EAAKuB,WCjKF,CAAC/C,GAAU,knBAYlBA,wCDqJoBwD,CAAYxD,GAAQ,CACxCgD,UAAW,oBAEnB,MAEM5M,EAAI,EAAG,gCAGHiN,EAAcnD,aAEViD,GACJ3B,EACA,CACExB,MAAO,CACLhX,OAAQqa,EAAcra,OACtBC,MAAOoa,EAAcpa,QAGzBP,EACA+W,IAIFO,EAAMA,MAAMhX,OAASqa,EAAcra,OACnCgX,EAAMA,MAAM/W,MAAQoa,EAAcpa,YAE5Bka,GAAY3B,EAAMxB,EAAOtX,EAAS+W,IAO5CwC,QDiBGzG,eAAgCgG,EAAM9Y,GAE3C,MAAMuZ,EAAoB,GAGpBrY,EAAYlB,EAAQa,YAAYK,UACtC,GAAIA,EAAW,CACb,MAAM6Z,EAAa,GAUnB,GAPI7Z,EAAU8Z,IACZD,EAAWE,KAAK,CACdC,QAASha,EAAU8Z,KAKnB9Z,EAAUwO,MACZ,IAAK,MAAMtM,KAAQlC,EAAUwO,MAAO,CAClC,MAAMyL,GAAW/X,EAAKyE,WAAW,QAGjCkT,EAAWE,KACTE,EACI,CACED,QAASzL,EAAarM,EAAM,SAE9B,CACEwB,IAAKxB,GAGd,CAGH,IAAK,MAAMgY,KAAcL,EACvB,IACExB,EAAkB0B,WAAWnC,EAAKyB,aAAaa,GAChD,CAAC,MAAO5N,GACPQ,EAAa,EAAGR,EAAO,6CACxB,CAEHuN,EAAW7T,OAAS,EAGpB,MAAMmU,EAAc,GACpB,GAAIna,EAAUoa,IAAK,CACjB,IAAIC,EAAara,EAAUoa,IAAIE,MAAM,uBACrC,GAAID,EAEF,IAAK,IAAIE,KAAiBF,EACpBE,IACFA,EAAgBA,EACbjK,QAAQ,OAAQ,IAChBA,QAAQ,UAAW,IACnBA,QAAQ,KAAM,IACdA,QAAQ,KAAM,IACdA,QAAQ,IAAK,IACbA,QAAQ,MAAO,IACfxK,OAGCyU,EAAc5T,WAAW,QAC3BwT,EAAYJ,KAAK,CACfrW,IAAK6W,IAEEzb,EAAQa,YAAYE,oBAC7Bsa,EAAYJ,KAAK,CACfT,KAAMA,EAAKtV,KAAKyJ,EAAW8M,MAQrCJ,EAAYJ,KAAK,CACfC,QAASha,EAAUoa,IAAI9J,QAAQ,sBAAuB,KAAO,MAG/D,IAAK,MAAMkK,KAAeL,EACxB,IACE9B,EAAkB0B,WAAWnC,EAAK6C,YAAYD,GAC/C,CAAC,MAAOlO,GACPQ,EAAa,EAAGR,EAAO,8CACxB,CAEH6N,EAAYnU,OAAS,CACtB,CACF,CACD,OAAOqS,CACT,CC3G8BqC,CAAiB9C,EAAM9Y,GAGjD,MAAM6b,EAAOhB,QACH/B,EAAKY,UAAUlZ,IACnB,MAAMsb,EAAa9B,SAAS+B,cAC1B,sCAIIC,EAAcF,EAAWxb,OAAO2b,QAAQjd,MAAQwB,EAChD0b,EAAaJ,EAAWvb,MAAM0b,QAAQjd,MAAQwB,EAWpD,OANAwZ,SAASmC,KAAKC,MAAMC,KAAO7b,EAI3BwZ,SAASmC,KAAKC,MAAME,OAAS,MAEtB,CACLN,cACAE,aACD,GACA3U,WAAWoT,EAAcna,cACtBsY,EAAKY,UAAS,KAElB,MAAMsC,YAAEA,EAAWE,WAAEA,GAAela,OAAO0U,WAAWkD,OAAO,GAO7D,OAFAI,SAASmC,KAAKC,MAAMC,KAAO,EAEpB,CACLL,cACAE,aACD,IAIDK,EAAiBC,KAAKC,KAAKZ,EAAKG,aAAerB,EAAcra,QAC7Doc,EAAgBF,KAAKC,KAAKZ,EAAKK,YAAcvB,EAAcpa,QAG3Doc,EAAEA,EAACC,EAAEA,QAjOO,CAAC9D,GACrBA,EAAKG,MAAM,oBAAqBC,IAC9B,MAAMyD,EAAEA,EAACC,EAAEA,EAACrc,MAAEA,EAAKD,OAAEA,GAAW4Y,EAAQ2D,wBACxC,MAAO,CACLF,IACAC,IACArc,QACAD,OAAQkc,KAAKM,MAAMxc,EAAS,EAAIA,EAAS,KAC1C,IAyNsByc,CAAcjE,GASrC,IAAIjJ,EAEJ,SARMiJ,EAAKkE,YAAY,CACrB1c,OAAQic,EACRhc,MAAOmc,EACPO,kBAAmBpC,EAAQ,EAAItT,WAAWoT,EAAcna,SAK/B,QAAvBma,EAAc1b,KAEhB4Q,OAnJY,CAACiJ,GACjBA,EAAKG,MAAM,gCAAiCC,GAAYA,EAAQgE,YAkJ/CC,CAAUrE,QAClB,GAAI,CAAC,MAAO,QAAQ3S,SAASwU,EAAc1b,MAEhD4Q,OAxNc,EAACiJ,EAAM7Z,EAAMme,EAAUC,EAAMzc,IAC/CqS,QAAQqK,KAAK,CACXxE,EAAKyE,WAAW,CACdte,OACAme,WACAC,OACAG,uBAAuB,EACvBC,UAAU,EACVC,kBAAkB,KACL,QAATze,EAAiB,CAAE0e,QAAS,IAAO,CAAE,EAIzCC,eAAwB,OAAR3e,IAElB,IAAIgU,SAAQ,CAAC4K,EAAU1K,IACrB2K,YACE,IAAM3K,EAAO,IAAIU,GAAY,2BAC7BjT,GAAwB,UAsMbmd,CACXjF,EACA6B,EAAc1b,KACd,SACA,CACEsB,MAAOmc,EACPpc,OAAQic,EACRI,IACAC,KAEFjC,EAAc/Z,0BAEX,IAA2B,QAAvB+Z,EAAc1b,KAUvB,MAAM,IAAI4U,GACR,sCAAsC8G,EAAc1b,SATtD4Q,OApMYiD,OAChBgG,EACAxY,EACAC,EACA6c,EACAxc,WAEMkY,EAAKkF,iBAAiB,UACrB/K,QAAQqK,KAAK,CAClBxE,EAAKmF,IAAI,CAEP3d,OAAQA,EAAS,EACjBC,QACA6c,aAEF,IAAInK,SAAQ,CAAC4K,EAAU1K,IACrB2K,YACE,IAAM3K,EAAO,IAAIU,GAAY,2BAC7BjT,GAAwB,WAkLbsd,CACXpF,EACAyD,EACAG,EACA,SACA/B,EAAc/Z,qBAMjB,CAID,aADM0Y,GAAmBR,EAAMS,GACxB1J,CACR,CAAC,MAAOrC,GAEP,aADM8L,GAAmBR,EAAMS,GACxB/L,CACR,GEpRH,IAAIhL,IAAO,EAGJ,MAAM2b,GAAQ,CACnBC,iBAAkB,EAClBC,eAAgB,EAChBC,sBAAuB,EACvBC,UAAW,EACXC,eAAgB,EAChBC,aAAc,GAGhB,IAAIC,GAAa,CAAA,EAEjB,MAAMC,GAAU,CAUdC,OAAQ9L,UACN,IAAIgG,GAAO,EAEX,MAAM+F,EAAKC,IACLC,GAAY,IAAInR,MAAOoR,UAE7B,IAGE,GAFAlG,QAAaD,MAERC,GAAQA,EAAKmG,WAChB,MAAM,IAAIpL,GAAY,kCAGxBnG,EACE,EACA,wCAAwCmR,aACtC,IAAIjR,MAAOoR,UAAYD,QAG5B,CAAC,MAAOvR,GACP,MAAM,IAAIqG,GACR,+CACAK,SAAS1G,EACZ,CAED,MAAO,CACLqR,KACA/F,OAEAoG,UAAW1C,KAAK/W,MAAM+W,KAAK2C,UAAYT,GAAW/b,UAAY,IAC/D,EAaHyc,SAAUtM,MAAOuM,KAEbX,GAAW/b,aACT0c,EAAaH,UAAYR,GAAW/b,aAEtC+K,EACE,EACA,kEAAkEgR,GAAW/b,gBAExE,GAWXmX,QAAShH,MAAOuM,IACd3R,EAAI,EAAG,gCAAgC2R,EAAaR,OAEhDQ,EAAavG,YAETuG,EAAavG,KAAKwG,OACzB,GAWQC,GAAWzM,MAAOtM,IAY7B,GAVAkY,GAAalY,GAAUA,EAAOhE,KAAO,IAAKgE,EAAOhE,MAAS,SH7ErDsQ,eAAsB0M,GAE3B,MAAM1b,MAAEA,EAAKN,MAAEA,GAAUuO,MAGjBxQ,OAAQke,KAAiBC,GAAiB5b,EAE5C6b,EAAgB,CACpB5b,UAAUP,EAAMK,kBAAmB,QACnC+b,YAAa,SACb7gB,KAAMygB,EACNK,cAAc,EACdC,eAAe,EACfC,cAAc,EACdC,oBAAoB,EACpBC,gBAAiB,QACbR,GAAgBC,GAItB,IAAK9G,GAAS,CACZ,IAAIsH,EAAW,EAEf,MAAMC,EAAOrN,UACX,IACEpF,EACE,EACA,yDAAyDwS,OAE3DtH,SAAgB9Z,EAAUshB,OAAOT,EAClC,CAAC,MAAOnS,GAQP,GAPAQ,EACE,EACAR,EACA,oDAIE0S,EAAW,IAKb,MAAM1S,EAJNE,EAAI,EAAG,sCAAsCwS,uBACvC,IAAIjN,SAAS6B,GAAagJ,WAAWhJ,EAAU,aAC/CqL,GAIT,GAGH,UACQA,IAGyB,UAA3BR,EAAc5b,UAChB2J,EAAI,EAAG,6CAIL+R,GACF/R,EAAI,EAAG,4CAEV,CAAC,MAAOF,GACP,MAAM,IAAIqG,GACR,iEACAK,SAAS1G,EACZ,CAED,IAAKoL,GACH,MAAM,IAAI/E,GAAY,2CAEzB,CAGD,OAAO+E,EACT,CGOQyH,CAAc7Z,EAAOgZ,eAE3B9R,EACE,EACA,8CAA8CgR,GAAWjc,mBAAmBic,GAAWhc,eAGrFF,GACF,OAAOkL,EACL,EACA,yEAIA4S,SAAS5B,GAAWjc,YAAc6d,SAAS5B,GAAWhc,cACxDgc,GAAWjc,WAAaic,GAAWhc,YAGrC,IAEEF,GAAO,IAAI+d,EAAK,IAEX5B,GACHpZ,IAAK+a,SAAS5B,GAAWjc,YACzB+C,IAAK8a,SAAS5B,GAAWhc,YACzB8d,qBAAsB9B,GAAW9b,eACjC6d,oBAAqB/B,GAAW7b,cAChC6d,qBAAsBhC,GAAW5b,eACjC6d,kBAAmBjC,GAAW3b,YAC9B6d,0BAA2BlC,GAAW1b,oBACtC6d,mBAAoBnC,GAAWzb,eAC/B6d,sBAAsB,IAIxBte,GAAKkR,GAAG,WAAWZ,MAAO0G,UHgBvB1G,eAAyBgG,EAAMiI,GAAY,GAChD,IACOjI,EAAKmG,aACJ8B,SAEIjI,EAAKkI,KAAK,cAAe,CAAE1G,UAAW,2BAGtCtB,GAAeF,UAGfA,EAAKY,UAAS,KAClBM,SAASmC,KAAK/C,UACZ,4DAA4D,IAIrE,CAAC,MAAO5L,GACPQ,EACE,EACAR,EACA,qDAEH,CACH,CGtCYyT,CAAUzH,EAASV,MAAM,GAC/BpL,EAAI,EAAG,qCAAqC8L,EAASqF,MAAM,IAG7Drc,GAAKkR,GAAG,kBAAkB,CAACwN,EAAS1H,KAClC9L,EAAI,EAAG,qCAAqC8L,EAASqF,MAAM,IAG7D,MAAMsC,EAAmB,GAEzB,IAAK,IAAIlQ,EAAI,EAAGA,EAAIyN,GAAWjc,WAAYwO,IACzC,IACE,MAAMuI,QAAiBhX,GAAK4e,UAAUC,QACtCF,EAAiBlG,KAAKzB,EACvB,CAAC,MAAOhM,GACPQ,EAAa,EAAGR,EAAO,+CACxB,CAIH2T,EAAiBlb,SAASuT,IACxBhX,GAAK8e,QAAQ9H,EAAS,IAGxB9L,EACE,EACA,4BAA2ByT,EAAiBja,OAAS,SAASia,EAAiBja,oCAAsC,KAExH,CAAC,MAAOsG,GACP,MAAM,IAAIqG,GACR,gDACAK,SAAS1G,EACZ,GAUIsF,eAAeyO,KAIpB,GAHA7T,EAAI,EAAG,6DAGHlL,GAAM,CAER,IAAK,MAAMgf,KAAUhf,GAAKif,KACxBjf,GAAK8e,QAAQE,EAAOhI,UAIjBhX,GAAKkf,kBACFlf,GAAKsX,UACXpM,EAAI,EAAG,8CAEV,OH7FIoF,iBAED8F,IAAS+I,iBACL/I,GAAQ0G,QAEhB5R,EAAI,EAAG,gCACT,CG0FQkU,EACR,CAeO,MAAMC,GAAW/O,MAAOwE,EAAOtX,KACpC,IAAIqf,EAEJ,IAQE,GAPA3R,EAAI,EAAG,gDAELyQ,GAAME,eACJK,GAAW/c,cAqIZ,WACL,MAAM4D,IAAEA,EAAGC,IAAEA,EAAGiQ,IAAEA,EAAGqM,UAAEA,EAASL,KAAEA,EAAIM,QAAEA,GAAYC,KAEpDtU,EAAI,EAAG,2DAA2DnI,MAClEmI,EAAI,EAAG,2DAA2DlI,MAClEkI,EAAI,EAAG,+CAA+C+H,MACtD/H,EAAI,EAAG,6CAA6CoU,MACpDpU,EAAI,EAAG,4CAA4C+T,MACnD/T,EAAI,EAAG,0DAA0DqU,KACnE,CA7IME,IAGGzf,GACH,MAAM,IAAIqR,GAAY,iDAIxB,MAAMqO,EAAiBzQ,KACvB,IACE/D,EAAI,EAAG,qCACP2R,QAAqB7c,GAAK4e,UAAUC,QAGhCrhB,EAAQsB,OAAOK,cACjB+L,EACE,EACA1N,EAAQmiB,SAASC,UACb,wBAAwBpiB,EAAQmiB,SAASC,cACzC,cACJ,6BAA6BF,SAGlC,CAAC,MAAO1U,GACP,MAAM,IAAIqG,IACP7T,EAAQmiB,SAASC,UACd,YAAYpiB,EAAQmiB,SAASC,eAC7B,IACF,wDAAwDF,UAC1DhO,SAAS1G,EACZ,CAGD,GAFAE,EAAI,EAAG,qCAEF2R,EAAavG,KAChB,MAAM,IAAIjF,GACR,6DAKJ,IAAIwO,GAAY,IAAIzU,MAAOoR,UAE3BtR,EAAI,EAAG,8CAA8C2R,EAAaR,OAGlE,MAAMyD,EAAgB7Q,KAChB8Q,QAAe7H,GAAgB2E,EAAavG,KAAMxB,EAAOtX,GAG/D,GAAIuiB,aAAkBzO,MAOpB,KALuB,0BAAnByO,EAAOvd,UACTqa,EAAavG,KAAKwG,QAClBD,EAAavG,WAAaD,MAGtB,IAAIhF,IACP7T,EAAQmiB,SAASC,UACd,YAAYpiB,EAAQmiB,SAASC,eAC7B,IAAM,oCAAoCE,UAC9CpO,SAASqO,GAITviB,EAAQsB,OAAOK,cACjB+L,EACE,EACA1N,EAAQmiB,SAASC,UACb,wBAAwBpiB,EAAQmiB,SAASC,cACzC,cACJ,iCAAiCE,UAKrC9f,GAAK8e,QAAQjC,GAIb,MACMmD,GADU,IAAI5U,MAAOoR,UACEqD,EAO7B,OANAlE,GAAMI,WAAaiE,EACnBrE,GAAMM,aAAeN,GAAMI,YAAcJ,GAAMC,iBAE/C1Q,EAAI,EAAG,4BAA4B8U,SAG5B,CACLD,SACAviB,UAEH,CAAC,MAAOwN,GAOP,OANE2Q,GAAMK,eAEJa,GACF7c,GAAK8e,QAAQjC,GAGT,IAAIxL,GAAY,4BAA4BrG,EAAMxI,WAAWkP,SACjE1G,EAEH,GAiBUwU,GAAkB,KAAO,CACpCzc,IAAK/C,GAAK+C,IACVC,IAAKhD,GAAKgD,IACViQ,IAAKjT,GAAKigB,UAAYjgB,GAAKkgB,UAC3BZ,UAAWtf,GAAKigB,UAChBhB,KAAMjf,GAAKkgB,UACXX,QAASvf,GAAKmgB,uBAsBT,SAASC,KACd,OAAOzE,EACT,CCzXA,IAAIrd,IAAqB,EAgBlB,MAAM+hB,GAAc/P,MAAOgQ,EAAUC,KAE1CrV,EAAI,EAAG,2CAGP,MAAM1N,ETyL0B,EAAC2a,EAAe7I,EAAiB,MACjE,IAAI9R,EAAU,CAAA,EAsBd,OApBI2a,EAAcqI,KAChBhjB,EAAUiQ,EAAS6B,GACnB9R,EAAQH,OAAOZ,KAAO0b,EAAc1b,MAAQ0b,EAAc9a,OAAOZ,KACjEe,EAAQH,OAAOW,MAAQma,EAAcna,OAASma,EAAc9a,OAAOW,MACnER,EAAQH,OAAOI,QACb0a,EAAc1a,SAAW0a,EAAc9a,OAAOI,QAChDD,EAAQmiB,QAAU,CAChBa,IAAKrI,EAAcqI,MAGrBhjB,EAAUgS,GACRF,EACA6I,EAEAjV,GAIJ1F,EAAQH,OAAOI,QACbD,EAAQH,QAAQI,SAAW,SAASD,EAAQH,QAAQZ,MAAQ,QACvDe,CAAO,EShNEijB,CAAmBH,EAAU/Q,MAGvC4I,EAAgB3a,EAAQH,OAG9B,GAAIG,EAAQmiB,SAASa,KAA+B,KAAxBhjB,EAAQmiB,QAAQa,IAC1C,IACEtV,EAAI,EAAG,kDAEP,MAAM6U,EAASW,GChCd,SAAkBC,GACvB,MAAMnhB,EAAS,IAAIohB,EAAM,IAAIphB,OAE7B,OADeqhB,EAAUrhB,GACXshB,SAASH,EAAO,CAAEI,SAAU,CAAC,kBAC7C,CD6BQD,CAAStjB,EAAQmiB,QAAQa,KACzBhjB,EACA+iB,GAIF,QADE5E,GAAMG,sBACDiE,CACR,CAAC,MAAO/U,GACP,OAAOuV,EACL,IAAIlP,GAAY,oCAAoCK,SAAS1G,GAEhE,CAIH,GAAImN,EAAc7a,QAAU6a,EAAc7a,OAAOoH,OAE/C,IAGE,OAFAwG,EAAI,EAAG,oDACP1N,EAAQH,OAAOE,MAAQ0P,EAAakL,EAAc7a,OAAQ,QACnDojB,GAAeljB,EAAQH,OAAOE,MAAMiH,OAAQhH,EAAS+iB,EAC7D,CAAC,MAAOvV,GACP,OAAOuV,EACL,IAAIlP,GAAY,qCAAqCK,SAAS1G,GAEjE,CAIH,GACGmN,EAAc5a,OAAiC,KAAxB4a,EAAc5a,OACrC4a,EAAc3a,SAAqC,KAA1B2a,EAAc3a,QAExC,IAIE,OAHA0N,EAAI,EAAG,kDAGH4D,GAAUtR,EAAQa,aAAaC,oBAC1B0iB,GAAiBxjB,EAAS+iB,GAIG,iBAAxBpI,EAAc5a,MACxBmjB,GAAevI,EAAc5a,MAAMiH,OAAQhH,EAAS+iB,GACpDU,GACEzjB,EACA2a,EAAc5a,OAAS4a,EAAc3a,QACrC+iB,EAEP,CAAC,MAAOvV,GACP,OAAOuV,EACL,IAAIlP,GAAY,oCAAoCK,SAAS1G,GAEhE,CAIH,OAAOuV,EACL,IAAIlP,GACF,iJAEH,EA+GU6P,GAAiB1jB,IAC5B,MAAMsX,MAAEA,EAAKQ,UAAEA,GACb9X,EAAQH,QAAQG,SAAWwP,EAAcxP,EAAQH,QAAQE,OAGrDU,EAAgB+O,EAAcxP,EAAQH,QAAQY,eAGpD,IAAID,EACFR,EAAQH,QAAQW,OAChBsX,GAAWtX,OACXC,GAAeqX,WAAWtX,OAC1BR,EAAQH,QAAQQ,cAChB,EAGFG,EAAQgc,KAAKhX,IAAI,GAAKgX,KAAKjX,IAAI/E,EAAO,IAGtCA,EV2IyB,EAACxB,EAAO2kB,EAAY,KAC7C,MAAMC,EAAapH,KAAKqH,IAAI,GAAIF,GAAa,GAC7C,OAAOnH,KAAK/W,OAAOzG,EAAQ4kB,GAAcA,CAAU,EU7I3CE,CAAYtjB,EAAO,GAG3B,MAAMqb,EAAO,CACXvb,OACEN,EAAQH,QAAQS,QAChBwX,GAAWiM,cACXzM,GAAOhX,QACPG,GAAeqX,WAAWiM,cAC1BtjB,GAAe6W,OAAOhX,QACtBN,EAAQH,QAAQM,eAChB,IACFI,MACEP,EAAQH,QAAQU,OAChBuX,GAAWkM,aACX1M,GAAO/W,OACPE,GAAeqX,WAAWkM,aAC1BvjB,GAAe6W,OAAO/W,OACtBP,EAAQH,QAAQO,cAChB,IACFI,SAIF,IAAK,IAAKyjB,EAAOjlB,KAAU+G,OAAOiH,QAAQ6O,GACxCA,EAAKoI,GACc,iBAAVjlB,GAAsBA,EAAMwS,QAAQ,SAAU,IAAMxS,EAE/D,OAAO6c,CAAI,EAgBP4H,GAAW3Q,MAAO9S,EAASkkB,EAAWnB,EAAaC,KACvD,IAAMnjB,OAAQ8a,EAAe9Z,YAAasjB,GAAuBnkB,EAEjE,MAAMokB,EAC6C,kBAA1CD,EAAmBrjB,mBACtBqjB,EAAmBrjB,mBACnBA,GAEN,GAAKqjB,GAEE,GAAIC,EACT,GAA6C,iBAAlCpkB,EAAQa,YAAYK,UAE7BlB,EAAQa,YAAYK,UAAYkO,EAC9BpP,EAAQa,YAAYK,UACpBoQ,GAAUtR,EAAQa,YAAYE,0BAE3B,IAAKf,EAAQa,YAAYK,UAC9B,IACE,MAAMA,EAAYuO,EAAa,iBAAkB,QACjDzP,EAAQa,YAAYK,UAAYkO,EAC9BlO,EACAoQ,GAAUtR,EAAQa,YAAYE,oBAEjC,CAAC,MAAOyM,GACPQ,EACE,EACAR,EACA,0DAEH,OArBH2W,EAAqBnkB,EAAQa,YAAc,GA6B7C,IAAKujB,GAA4BD,EAAoB,CACnD,GACEA,EAAmBljB,UACnBkjB,EAAmBjjB,WACnBijB,EAAmBnjB,WAInB,OAAO+hB,EACL,IAAIlP,GACF,qGAMNsQ,EAAmBljB,UAAW,EAC9BkjB,EAAmBjjB,WAAY,EAC/BijB,EAAmBnjB,YAAa,CACjC,CAyCD,GAtCIkjB,IACFA,EAAU5M,MAAQ4M,EAAU5M,OAAS,CAAA,EACrC4M,EAAUpM,UAAYoM,EAAUpM,WAAa,CAAA,EAC7CoM,EAAUpM,UAAUC,SAAU,GAGhC4C,EAAcza,OAASya,EAAcza,QAAU,QAC/Cya,EAAc1b,KAAO6P,EAAQ6L,EAAc1b,KAAM0b,EAAc1a,SACpC,QAAvB0a,EAAc1b,OAChB0b,EAAcpa,OAAQ,GAIxB,CAAC,gBAAiB,gBAAgB0F,SAASoe,IACzC,IACM1J,GAAiBA,EAAc0J,KAEO,iBAA/B1J,EAAc0J,IACrB1J,EAAc0J,GAAa3V,SAAS,SAEpCiM,EAAc0J,GAAe7U,EAC3BC,EAAakL,EAAc0J,GAAc,SACzC,GAGF1J,EAAc0J,GAAe7U,EAC3BmL,EAAc0J,IACd,GAIP,CAAC,MAAO7W,GACPmN,EAAc0J,GAAe,GAC7BrW,EAAa,EAAGR,EAAO,gBAAgB6W,uBACxC,KAICF,EAAmBrjB,mBACrB,IACEqjB,EAAmBnjB,WAAauQ,GAC9B4S,EAAmBnjB,WACnBmjB,EAAmBpjB,mBAEtB,CAAC,MAAOyM,GACPQ,EAAa,EAAGR,EAAO,6CACxB,CAIH,GACE2W,GACAA,EAAmBljB,UACnBkjB,EAAmBljB,UAAUwT,QAAQ,KAAO,EAI5C,GAAI0P,EAAmBpjB,mBACrB,IACEojB,EAAmBljB,SAAWwO,EAC5B0U,EAAmBljB,SACnB,OAEH,CAAC,MAAOuM,GACP2W,EAAmBljB,UAAW,EAC9B+M,EAAa,EAAGR,EAAO,2CACxB,MAED2W,EAAmBljB,UAAW,EAKlCjB,EAAQH,OAAS,IACZG,EAAQH,UACR6jB,GAAc1jB,IAInB,IAKE,OAAO+iB,GAAY,QAJElB,GACnBlH,EAAcnD,QAAU0M,GAAalB,EACrChjB,GAGH,CAAC,MAAOwN,GACP,OAAOuV,EAAYvV,EACpB,GAqBGgW,GAAmB,CAACxjB,EAAS+iB,KACjC,IACE,IAAIvL,EACAzX,EAAQC,EAAQH,OAAOE,OAASC,EAAQH,OAAOG,QAkBnD,MAhBqB,iBAAVD,IAETyX,EAASzX,EAAQyQ,EACfzQ,EACAC,EAAQa,aAAaC,qBAGzB0W,EAASzX,EAAM2Q,WAAW,YAAa,IAAI1J,OAGT,MAA9BwQ,EAAOA,EAAOtQ,OAAS,KACzBsQ,EAASA,EAAOnR,UAAU,EAAGmR,EAAOtQ,OAAS,IAI/ClH,EAAQH,OAAO2X,OAASA,EACjBiM,GAASzjB,GAAS,EAAO+iB,EACjC,CAAC,MAAOvV,GACP,OAAOuV,EACL,IAAIlP,GACF,wCAAwC7T,EAAQH,QAAQuiB,WAAa,kJACrElO,SAAS1G,GAEd,GAcG0V,GAAiB,CAACoB,EAAgBtkB,EAAS+iB,KAC/C,MAAMjiB,mBAAEA,GAAuBd,EAAQa,YAGvC,GACEyjB,EAAe7P,QAAQ,SAAW,GAClC6P,EAAe7P,QAAQ,UAAY,EAGnC,OADA/G,EAAI,EAAG,iCACA+V,GAASzjB,GAAS,EAAO+iB,EAAauB,GAG/C,IAEE,MAAMC,EAAYxU,KAAK5D,MAAMmY,EAAe5T,WAAW,YAAa,MAGpE,OAAO+S,GAASzjB,EAASukB,EAAWxB,EACrC,CAAC,MAAOvV,GAEP,OAAI8D,GAAUxQ,GACL0iB,GAAiBxjB,EAAS+iB,GAG1BA,EACL,IAAIlP,GACF,kMACAK,SAAS1G,GAGhB,GEzgBGgX,GAAW,GAOJC,GAAY5F,IACvB2F,GAASvJ,KAAK4D,EAAG,EAON6F,GAAiB,KAC5BhX,EAAI,EAAG,4DACP,IAAK,MAAMmR,KAAM2F,GACfG,cAAc9F,GACd+F,aAAa/F,EACd,EC1BGgG,GAAqB,CAACrX,EAAOsX,EAAKrR,EAAKsR,KAE3C/W,EAAa,EAAGR,GAGY,gBAAxBhG,EAAKqD,uBACA2C,EAAMY,MAIf2W,EAAKvX,EAAM,EAWPwX,GAAwB,CAACxX,EAAOsX,EAAKrR,EAAKsR,KAE9C,MAAQ5Q,WAAY8Q,EAAMC,OAAEA,EAAMlgB,QAAEA,EAAOoJ,MAAEA,GAAUZ,EACjD2G,EAAa8Q,GAAUC,GAAU,IAGvCzR,EAAIyR,OAAO/Q,GAAYgR,KAAK,CAAEhR,aAAYnP,UAASoJ,SAAQ,EAG7D,ICjBAgX,GAAe,CAACC,EAAKC,KACnB,MAAMC,EACJ,yEAGIC,EAAc,CAClBhgB,IAAK8f,EAAYvjB,aAAe,GAChCC,OAAQsjB,EAAYtjB,QAAU,EAC9BC,MAAOqjB,EAAYrjB,OAAS,EAC5BC,WAAYojB,EAAYpjB,aAAc,EACtCC,QAASmjB,EAAYnjB,UAAW,EAChCC,UAAWkjB,EAAYljB,YAAa,GAIlCojB,EAAYtjB,YACdmjB,EAAI9jB,OAAO,eAIb,MAAMkkB,EAAUL,EAAU,CACxBM,SAA+B,GAArBF,EAAYxjB,OAAc,IAEpCwD,IAAKggB,EAAYhgB,IAEjBmgB,QAASH,EAAYvjB,MACrB2jB,QAAS,CAACC,EAAS/Q,KACjBA,EAASgR,OAAO,CACdX,KAAM,KACJrQ,EAASoQ,OAAO,KAAKa,KAAK,CAAE/gB,QAASugB,GAAM,EAE7CS,QAAS,KACPlR,EAASoQ,OAAO,KAAKa,KAAKR,EAAI,GAEhC,EAEJU,KAAOJ,IAGqB,IAAxBL,EAAYrjB,UACc,IAA1BqjB,EAAYpjB,WACZyjB,EAAQK,MAAMpZ,MAAQ0Y,EAAYrjB,SAClC0jB,EAAQK,MAAMC,eAAiBX,EAAYpjB,YAE3CsL,EAAI,EAAG,2CACA,KAOb2X,EAAIe,IAAIX,GAER/X,EACE,EACA,8CAA8C8X,EAAYhgB,oBAAoBggB,EAAYxjB,8CAA8CwjB,EAAYtjB,cACrJ,EC7DH,MAAMmkB,GAAoBtW,KAAK5D,MAC7BsD,EAAavK,EAAKyJ,EAAW,MAAO,UAAW,oBAIpC2X,GAAgB,CAC3BC,iBAAkB,GAIdC,GAAiB,CAAC,SAAU,QAAS,QAAS,SAGpD,SAASC,GAAW9N,EAAU3Y,GAC5B,MAAM0mB,EAAiB,CAAA,EAGvB,IAAK,MAAOC,EAAaC,KAAkB7gB,OAAOiH,QAAQ2L,GAExD,QAA6BrS,IAAzBtG,EAAQ2mB,GAEV,GAAsB,OAAlBC,EAEF,GAAIzW,MAAMC,QAAQpQ,EAAQ2mB,IAExB,GAAIH,GAAergB,SAASwgB,GAAc,CAExCD,EAAeC,GAAe,GAE9B,IAAK,MAAOE,EAAOC,KAAiB9mB,EAClC2mB,GACA3Z,UACA0Z,EAAeC,GAAaE,GAASJ,GACnCG,EACAE,EAGhB,MAEYJ,EAAeC,GAAeF,GAC5BG,EACA5mB,EAAQ2mB,GAAa,SAIzBD,EAAeC,GAAeF,GAC5BG,EACA5mB,EAAQ2mB,SAKZD,EAAeC,GAAe3mB,EAAQ2mB,GAM5C,OAAOD,CACT,CAEO,SAASK,GAAiBjQ,EAAcsL,GAE7CkE,GAAclE,GAAaqE,GAAWJ,GAAmBvP,GAGzDwP,GAAcC,kBAChB,CChEA,MAAMS,GAAmB,IAAIC,IAG7B,IAAIC,GAGAviB,GAAkB,KAQf,SAASwiB,GAAKC,GAEnB,GADAF,GAAmBnV,KAAa1N,WACA,IAA5B6iB,GAAiB3lB,OAAiB,CAEpC,MAAM8lB,EAAoB,CACxB9iB,mBAAoB2iB,GAAiB3iB,mBACrC+iB,QAAS,CAEPC,KAAMC,EAAIC,KAAK,CAAEC,QAAS,WAAaR,GAAiBriB,OAAQ,CAC9D8iB,UAAW,UAGb,mBAAoB,GAAGP,EAAQhU,cAC7B,CAAC,KAAM,WAAWjN,SAASihB,EAAQA,SAC/B,YACAA,EAAQA,WACVA,EAAQ1lB,SAKVkmB,EAAgB,CACpB/I,GAAIC,IACJxa,UAAW4iB,GAAiB5iB,UAC5BujB,aAAc,EACdpjB,kBAAmB,KACnBD,YAAa,MAIfsjB,GAAQZ,GAAiBtiB,IAAKyiB,EAAmBO,GAOrD,SAAgCV,GAE9BviB,GAAkBojB,aAAY,KAC5B,IAEE,MAAMC,GAsJHnJ,EAAKmI,GAAiBxT,IAAIqL,GAAMmI,GAAiB5f,UAtJf2d,OAAO/lB,MAG1CgpB,GACAA,EAAgBC,aAAeC,EAAUC,MACzCpiB,OAAOC,KAAKsgB,IAAepf,OAAS,GACpCof,GAAcC,iBAAmB,GAGjCyB,EAAgBjC,KAAKhW,KAAKC,UAAUsW,IAEvC,CAAC,MAAO9Y,GACPQ,EAAa,EAAG,qDACjB,CAwIE,IAAoB6Q,CAxItB,GACAqI,EAAiBviB,iBAGpB8f,GAAS9f,GACX,CA3BIyjB,CAAuBlB,GACxB,CACH,CAkCA,SAASY,GAAQO,EAAchB,EAAmBO,GAEhD,IAAII,EAAkB,IAAIE,EAAUG,EAAchB,GAGlDW,EAAgBtU,GAAG,QAAQ,KAEzBiR,cAAciD,EAAcnjB,mBAG5BuiB,GAAiBsB,IAAIV,EAAc/I,GAAImJ,GAGvCta,EACE,EACA,0BAA0Bka,EAAc/I,6BAA6BwJ,KACtE,IAIHL,EAAgBtU,GAAG,SAAU6U,IAC3B7a,EACE,EACA,cACA,cAAcka,EAAc/I,kCAAkCwJ,gBAA2BE,MAI3F3D,aAAagD,EAAcpjB,aAG3BwiB,GAAiBwB,OAAOZ,EAAc/I,IACtCmJ,EAAkB,KAGdJ,EAActjB,YAAcsjB,EAAcnjB,mBAC5CH,GAAU+jB,EAAchB,EAAmBO,EAC5C,IAIHI,EAAgBtU,GAAG,SAAUlG,IAC3BQ,EACE,EACAR,EACA,0BAA0Boa,EAAc/I,uBAItCrR,EAAMxI,QAAQmB,SAAS,QACzByhB,EAActjB,WAAY,EAC1BsjB,EAAcC,aAAeX,GAAiBxiB,mBAG9CkjB,EAActjB,UAAY4iB,GAAiB5iB,SAC5C,IAIH0jB,EAAgBtU,GAAG,WAAY1O,IAC7B0I,EACE,EACA,0BAA0Bka,EAAc/I,uBAAuB7Z,IAChE,IAKHgjB,EAAgBtU,GAAG,QAAQ,KACzBhG,EACE,EACA,0BAA0Bka,EAAc/I,mCAAmCwJ,MAE7EzD,aAAagD,EAAcpjB,aAC3BojB,EAAcpjB,YAAcsZ,YAAW,KAErCkK,EAAgBS,YAGZb,EAActjB,WAChBA,GAAU+jB,EAAchB,EAAmBO,EAC5C,GACAV,GAAiB1iB,YAAY,GAEpC,CASA,SAASF,GAAU+jB,EAAchB,EAAmBO,GAElDA,EAAcnjB,kBAAoBsjB,aAAY,KACxCH,EAAcC,aAAeX,GAAiBxiB,mBAChDgJ,EACE,EACA,0BAA0Bka,EAAc/I,kBAAkB+I,EAAcC,mBAAmBX,GAAiBxiB,6CAA6C2jB,MAG3JP,GAAQO,EAAchB,EAAmBO,KAEzCA,EAActjB,WAAY,EAC1BqgB,cAAciD,EAAcnjB,mBAC5BiJ,EACE,EACA,0BAA0Bka,EAAc/I,uCAAuCwJ,MAElF,GACAnB,GAAiBziB,mBAGpBggB,GAASmD,EAAcnjB,kBACzB,CAcO,SAASikB,KACd,IAAK,MAAMC,KAAU3B,GAAiB5f,SACpCuhB,EAAOF,YAETzB,GAAiB4B,OACnB,CC9OA,MAAMC,WAAkBhV,GACtB,WAAAE,CAAY/O,EAASkgB,GACnBlR,MAAMhP,GACNiP,KAAKiR,OAASjR,KAAKE,WAAa+Q,CACjC,CAED,SAAA4D,CAAU5D,GAER,OADAjR,KAAKiR,OAASA,EACPjR,IACR,ECcH,IAAA8U,GAAgB1D,KACbA,GAEGA,EAAI2D,KACF,+BACAlW,MAAO+S,EAAS/Q,EAAUiQ,KACxB,IACE,MAAMkE,EAAazhB,EAAKW,uBAGxB,IAAK8gB,IAAeA,EAAW/hB,OAC7B,MAAM,IAAI2hB,GACR,uGACA,KAKJ,MAAMK,EAAQrD,EAAQrS,IAAI,WAC1B,IAAK0V,GAASA,IAAUD,EACtB,MAAM,IAAIJ,GACR,iEACA,KAKJ,MAAMM,EAAatD,EAAQuD,OAAOD,WAClC,IAAIA,EAmBF,MAAM,IAAIN,GAAU,2BAA4B,KAlBhD,SdwOe/V,OAAOqW,IAClC,MAAMnpB,EAAU+R,KACZ/R,GAASb,aACXa,EAAQb,WAAWC,QAAU+pB,SAEzBrT,GAAoB9V,EAAQ,Ec3OdqpB,CAAcF,EACrB,CAAC,MAAO3b,GACP,MAAM,IAAIqb,GACR,mBAAmBrb,EAAMxI,UACzBwI,EAAM2G,YACND,SAAS1G,EACZ,CAGDsH,EAASoQ,OAAO,KAAKa,KAAK,CACxB5R,WAAY,IACZ/U,QAASA,KACT4F,QAAS,+CAA+CmkB,MAM7D,CAAC,MAAO3b,GACPuX,EAAKvX,EACN,KC5CX,MAAM8b,GAAe,CACnBC,IAAK,YACLC,KAAM,aACNC,IAAK,YACLxL,IAAK,kBACL+E,IAAK,iBAIP,IAAI0G,GAAkB,EAGtB,MAAMC,GAAgB,GAGhBC,GAAe,GAgBfC,GAAc,CAACC,EAAWjE,EAAS/Q,EAAUjF,KACjD,IAAI0S,GAAS,EACb,MAAM1D,GAAEA,EAAEkL,SAAEA,EAAQ9qB,KAAEA,EAAIkd,KAAEA,GAAStM,EAcrC,OAZAia,EAAU1T,MAAMnV,IACd,GAAIA,EAAU,CACZ,IAAI+oB,EAAe/oB,EAAS4kB,EAAS/Q,EAAU+J,EAAIkL,EAAU9qB,EAAMkd,GAMnE,YAJqB7V,IAAjB0jB,IAA+C,IAAjBA,IAChCzH,EAASyH,IAGJ,CACR,KAGIzH,CAAM,EAaT0H,GAAgBnX,MAAO+S,EAAS/Q,EAAUiQ,KAC9C,IAEE,MAAMmF,EAAczY,KAGdsY,EAAWjL,IAAOtN,QAAQ,KAAM,IAGhCiH,EAAiB1G,KACjBoK,EAAO0J,EAAQ1J,KACf0C,IAAO6K,GAEb,IAAIzqB,EAAO6P,EAAQqN,EAAKld,MAGxB,IAAKkd,GnBmHS,iBADYvM,EmBlHCuM,KnBoH5BhM,MAAMC,QAAQR,IACN,OAATA,GAC6B,IAA7B7J,OAAOC,KAAK4J,GAAM1I,OmBrHd,MAAM,IAAI2hB,GACR,sJACA,KAKJ,IAAI9oB,EAAQyP,EAAc2M,EAAKrc,QAAUqc,EAAKnc,SAAWmc,EAAKtM,MAG9D,IAAK9P,IAAUoc,EAAK6G,IAQlB,MAPAtV,EACE,EACA,uBAAuBqc,UACrBlE,EAAQyB,QAAQ,oBAAsBzB,EAAQsE,WAAWC,kDACtBra,KAAKC,UAAUmM,OAGhD,IAAI0M,GACR,oQACA,KAIJ,IAAImB,GAAe,EAWnB,GARAA,EAAeH,GAAYF,GAAe9D,EAAS/Q,EAAU,CAC3D+J,KACAkL,WACA9qB,OACAkd,UAImB,IAAjB6N,EACF,OAAOlV,EAASiR,KAAKiE,GAGvB,IAAIK,GAAoB,EAGxBxE,EAAQyE,OAAO5W,GAAG,SAAS,KACzB2W,GAAoB,CAAI,IAG1B3c,EAAI,EAAG,iDAAiDqc,MAExD5N,EAAKjc,OAAiC,iBAAhBic,EAAKjc,QAAuBic,EAAKjc,QAAW,QAGlE,MAAM8S,EAAiB,CACrBnT,OAAQ,CACNE,QACAd,OACAiB,OAAQic,EAAKjc,OAAO,GAAGqqB,cAAgBpO,EAAKjc,OAAOsqB,OAAO,GAC1DlqB,OAAQ6b,EAAK7b,OACbC,MAAO4b,EAAK5b,MACZC,MAAO2b,EAAK3b,OAASiY,EAAe5Y,OAAOW,MAC3CC,cAAe+O,EAAc2M,EAAK1b,eAAe,GACjDC,aAAc8O,EAAc2M,EAAKzb,cAAc,IAEjDG,YAAa,CACXC,mBTsXmCA,GSrXnCC,oBAAoB,EACpBG,UAAWsO,EAAc2M,EAAKjb,WAAW,GACzCD,SAAUkb,EAAKlb,SACfD,WAAYmb,EAAKnb,aAIjBjB,IAEFiT,EAAenT,OAAOE,MAAQyQ,EAC5BzQ,EACAiT,EAAenS,YAAYC,qBAK/B,MAAMd,EAAUgS,GAAmByG,EAAgBzF,GAcnD,GAXAhT,EAAQH,OAAOG,QAAUD,EAGzBC,EAAQmiB,QAAU,CAChBa,IAAK7G,EAAK6G,MAAO,EACjByH,IAAKtO,EAAKsO,MAAO,EACjBC,WAAYvO,EAAKuO,aAAc,EAC/BtI,UAAW2H,GAIT5N,EAAK6G,KnBiCyB,CAACpT,GACf,CACpB,mDACA,uEACA,wEACA,uFACA,qEAGmBwG,MAAMuU,GAAYA,EAAQhjB,KAAKiI,KmB1ClCgb,CAAuB5qB,EAAQmiB,QAAQa,KACrD,MAAM,IAAI6F,GACR,6KACA,WAKEhG,GAAY7iB,GAAS,CAACwN,EAAOqd,KAajC,GAXAhF,EAAQyE,OAAOQ,mBAAmB,SAG9BrS,EAAenX,OAAOK,cACxB+L,EACE,EACA,wBAAwBqc,0CAAiDG,UAKzEG,EACF,OAAO3c,EACL,EACA,mFAKJ,GAAIF,EACF,MAAMA,EAIR,IAAKqd,IAASA,EAAKtI,OACjB,MAAM,IAAIsG,GACR,oGAAoGkB,oBAA2Bc,EAAKtI,UACpI,KAaJ,OARAtjB,EAAO4rB,EAAK7qB,QAAQH,OAAOZ,KAG3B4qB,GAAYD,GAAc/D,EAAS/Q,EAAU,CAAE+J,KAAI1C,KAAM0O,EAAKtI,SAG9DwE,GAAiB/mB,EAAQH,OAAOG,QAASA,EAAQmiB,QAAQC,WAErDyI,EAAKtI,OAEHpG,EAAKsO,IAEM,QAATxrB,GAA0B,OAARA,EACb6V,EAASiR,KACdgF,OAAOC,KAAKH,EAAKtI,OAAQ,QAAQ1U,SAAS,WAIvCiH,EAASiR,KAAK8E,EAAKtI,SAI5BzN,EAASmW,OAAO,eAAgB3B,GAAarqB,IAAS,aAGjDkd,EAAKuO,YACR5V,EAASoW,WACP,GAAGrF,EAAQuD,OAAO+B,UAAYtF,EAAQ1J,KAAKgP,UAAY,WACrDlsB,GAAQ,SAME,QAATA,EACH6V,EAASiR,KAAK8E,EAAKtI,QACnBzN,EAASiR,KAAKgF,OAAOC,KAAKH,EAAKtI,OAAQ,iBA5B7C,CA6BC,GAEJ,CAAC,MAAO/U,GACPuX,EAAKvX,EACN,CnBhE0B,IAACoC,CmBgE3B,ECvQH,MAAMwb,GAAUrb,KAAK5D,MAAMsD,EAAa4b,EAAO1c,EAAW,kBAEpD2c,GAAkB,IAAI1d,KAEtB2d,GAAe,GAuCN,SAASC,GAAgBnG,GACtC,IAAKA,EACH,OAAO,EAKTZ,GAxBAsD,aAAY,KACV,MAAM5J,EAAQyE,KACR6I,EACqB,IAAzBtN,EAAME,eACF,EACCF,EAAMC,iBAAmBD,EAAME,eAAkB,IAExDkN,GAAatQ,KAAKwQ,GACdF,GAAarkB,OA5BF,IA6BbqkB,GAAa3Y,OACd,GA/BkB,MA+CrByS,EAAI7R,IAAI,WAAW,CAACkY,EAAGjY,KACrB,MAAM0K,EAAQyE,KACR+I,EAASJ,GAAarkB,OACtB0kB,EAxCIL,GAAaM,QAAO,CAACC,EAAGC,IAAMD,EAAIC,GAAG,GACpCR,GAAarkB,OAyCxBwG,EAAI,EAAG,4DAEP+F,EAAIsS,KAAK,CACPb,OAAQ,KACR8G,SAAUV,GACVW,OACEzP,KAAK0P,QACF,IAAIte,MAAOoR,UAAYsM,GAAgBtM,WAAa,IAAO,IAC1D,WACN5f,QAASgsB,GAAQhsB,QACjB+sB,kBAAmB/sB,KACnBgtB,sBAAuBjO,EAAMM,aAC7BL,iBAAkBD,EAAMC,iBACxBiO,cAAelO,EAAMK,eACrBH,eAAgBF,EAAME,eACtBiO,YAAcnO,EAAMC,iBAAmBD,EAAME,eAAkB,IAE/D7b,KAAMwf,KAGN2J,SACAC,gBACA5mB,QAAS,QAAQ2mB,mCAAwCC,EAAcW,QAAQ,OAG/EC,kBAAmBrO,EAAMG,sBACzBmO,mBAAoBtO,EAAMC,iBAAmBD,EAAMG,uBACnD,GAEN,CCxEA,MAAMoO,GAAgB,IAAIzF,IAGpB5B,GAAMsH,IAGZtH,GAAIuH,QAAQ,gBAGZvH,GAAIe,IAAIyG,KAGR,MAAMC,GAAUC,EAAOC,gBACjBC,GAASF,EAAO,CACpBD,WACAI,OAAQ,CACNC,UAAW,YAKf9H,GAAIe,IAAIuG,EAAQxH,KAAK,CAAEiI,MAAO,YAC9B/H,GAAIe,IAAIuG,EAAQU,WAAW,CAAEC,UAAU,EAAMF,MAAO,YAGpD/H,GAAIe,IAAI6G,GAAOM,QAOf,MAAMC,GAA6BlsB,IACjCA,EAAOoS,GAAG,eAAgBlG,IACxBQ,EAAa,EAAGR,EAAO,0BAA0BA,EAAMxI,UAAU,IAGnE1D,EAAOoS,GAAG,SAAUlG,IAClBQ,EAAa,EAAGR,EAAO,0BAA0BA,EAAMxI,UAAU,IAGnE1D,EAAOoS,GAAG,cAAe4W,IACvBA,EAAO5W,GAAG,SAAUlG,IAClBQ,EAAa,EAAGR,EAAO,0BAA0BA,EAAMxI,UAAU,GACjE,GACF,EAaSyoB,GAAc3a,MAAO4a,IAChC,IAEE,IAAKA,EAAansB,OAChB,OAAO,EAIT,IAAKmsB,EAAarrB,IAAIC,MAAO,CAE3B,MAAMqrB,EAAara,EAAKsa,aAAavI,IAGrCmI,GAA0BG,GAG1BA,EAAWE,OAAOH,EAAahsB,KAAMgsB,EAAajsB,MAAM,KAEtDirB,GAAcpE,IAAIoF,EAAahsB,KAAMisB,GAErCjgB,EACE,EACA,mCAAmCggB,EAAajsB,QAAQisB,EAAahsB,SAG5C,IAAvBgrB,GAAc7Q,MAEhBiS,GAAc,IAAKH,EAAWvG,UAAWhU,SAAU,QACpD,GAEJ,CAGD,GAAIsa,EAAarrB,IAAId,OAAQ,CAE3B,IAAIuL,EAAKihB,EAET,IAEEjhB,QAAYkhB,EAAWC,SACrBC,EAAMhpB,KAAKwoB,EAAarrB,IAAIE,SAAU,cACtC,QAIFwrB,QAAaC,EAAWC,SACtBC,EAAMhpB,KAAKwoB,EAAarrB,IAAIE,SAAU,cACtC,OAEH,CAAC,MAAOiL,GACPE,EACE,EACA,qDAAqDggB,EAAarrB,IAAIE,sDAEzE,CAED,GAAIuK,GAAOihB,EAAM,CAEf,MAAMI,EAAc9a,EAAMua,aAAa,CAAE9gB,MAAKihB,QAAQ1I,IAGtDmI,GAA0BW,GAG1BA,EAAYN,OAAOH,EAAarrB,IAAIX,KAAMgsB,EAAajsB,MAAM,KAE3DirB,GAAcpE,IAAIoF,EAAarrB,IAAIX,KAAMysB,GAEzCzgB,EACE,EACA,oCAAoCggB,EAAajsB,QAAQisB,EAAarrB,IAAIX,SAGjD,IAAvBgrB,GAAc7Q,MAEhBiS,GAAc,IAAKK,EAAY/G,UAAWhU,SAAU,SACrD,GAEJ,CACF,CAICsa,EAAa5rB,cACb4rB,EAAa5rB,aAAaP,SACzB,CAAC,EAAG6sB,KAAKjoB,SAASunB,EAAa5rB,aAAaC,cAE7CqjB,GAAUC,GAAKqI,EAAa5rB,cAI9BujB,GAAIe,IAAIuG,EAAQ0B,OAAOH,EAAMhpB,KAAKyJ,EAAW,YAG7C2f,GAAYjJ,IFoGD,CAACA,IAIdA,EAAI2D,KAAK,IAAKiB,IAMd5E,EAAI2D,KAAK,aAAciB,GAAc,EE7GnCsE,CAAalJ,ICzKF,CAACA,MACbA,GAEGA,EAAI7R,IAAI,KAAK,CAACqS,EAAS/Q,KACrBA,EAAS0Z,SAAStpB,EAAKyJ,EAAW,SAAU,cAAc,GAC1D,EDqKJ8f,CAAQpJ,IACR0D,GAAa1D,IRvJF,CAACA,IAEdA,EAAIe,IAAIvB,IAGRQ,EAAIe,IAAIpB,GAAsB,EQqJ5B0J,CAAarJ,GACd,CAAC,MAAO7X,GACP,MAAM,IAAIqG,GACR,sDACAK,SAAS1G,EACZ,GAMUmhB,GAAe,KAC1BjhB,EAAI,EAAG,iCACP,IAAK,MAAOhM,EAAMJ,KAAWorB,GAC3BprB,EAAOge,OAAM,KACXoN,GAAclE,OAAO9mB,GACrBgM,EAAI,EAAG,mCAAmChM,KAAQ,GAErD,EA6DH,IAAeJ,GAAA,CACbmsB,eACAkB,gBACAC,WAxDwB,IAAMlC,GAyD9BmC,mBAlDiCvJ,GAAgBF,GAAUC,GAAKC,GAmDhEwJ,WA5CwB,IAAMnC,EA6C9BoC,OAtCoB,IAAM1J,GAuC1Be,IA/BiB,CAAC5L,KAASwU,KAC3B3J,GAAIe,IAAI5L,KAASwU,EAAY,EA+B7Bxb,IAtBiB,CAACgH,KAASwU,KAC3B3J,GAAI7R,IAAIgH,KAASwU,EAAY,EAsB7BhG,KAbkB,CAACxO,KAASwU,KAC5B3J,GAAI2D,KAAKxO,KAASwU,EAAY,GEvPzB,MAAMC,GAAkBnc,MAAOoc,UAE9Bjc,QAAQkc,WAAW,CAEvBzK,KAGAgE,KAGAiG,KAGApN,OAIFnV,QAAQgjB,KAAKF,EAAS,ECwExB,IAAerI,GAAA,CAEbvlB,UACAmsB,eAGA4B,WApCiBvc,MAAO9S,IdudW,IAAChB,Ec5bpC,Od4boCA,EcpdlCgB,EAAQa,aAAeb,EAAQa,YAAYC,mBdqd7CA,GAAqBwQ,GAAUtS,GXhUN,CAACkE,IAE1BoL,EAAYpL,GAAWod,SAASpd,EAAQC,QAGpCD,GAAWA,EAAQG,MACrBkL,EACErL,EAAQG,KACRH,EAAQE,MAAQ,+BAEnB,EyB3JDksB,CAAYtvB,EAAQkD,SAGhBlD,EAAQwD,MAAME,uBAnDlBgK,EAAI,EAAG,sDAGPtB,QAAQsH,GAAG,QAAS6U,IAClB7a,EAAI,EAAG,4BAA4B6a,KAAQ,IAI7Cnc,QAAQsH,GAAG,UAAUZ,MAAO/N,EAAMwjB,KAChC7a,EAAI,EAAG,OAAO3I,sBAAyBwjB,YACjC0G,GAAgB,EAAE,IAI1B7iB,QAAQsH,GAAG,WAAWZ,MAAO/N,EAAMwjB,KACjC7a,EAAI,EAAG,OAAO3I,sBAAyBwjB,YACjC0G,GAAgB,EAAE,IAI1B7iB,QAAQsH,GAAG,UAAUZ,MAAO/N,EAAMwjB,KAChC7a,EAAI,EAAG,OAAO3I,sBAAyBwjB,YACjC0G,GAAgB,EAAE,IAI1B7iB,QAAQsH,GAAG,qBAAqBZ,MAAOtF,EAAOzI,KAC5CiJ,EAAa,EAAGR,EAAO,OAAOzI,kBACxBkqB,GAAgB,EAAE,WA4BpBnZ,GAAoB9V,SAGpBuf,GAAS,CACb/c,KAAMxC,EAAQwC,MAAQ,CACpBC,WAAY,EACZC,WAAY,GAEd8c,cAAexf,EAAQlB,UAAUC,MAAQ,KAIpCiB,CAAO,EAUduvB,adkF0Bzc,MAAO9S,IAEjCA,EAAQH,OAAOE,MAAQC,EAAQH,OAAOE,OAASC,EAAQH,OAAOG,cAGxD6iB,GAAY7iB,GAAS8S,MAAOtF,EAAOqd,KAEvC,GAAIrd,EACF,MAAMA,EAGR,MAAMvN,QAAEA,EAAOhB,KAAEA,GAAS4rB,EAAK7qB,QAAQH,OAGvCgW,EACE5V,GAAW,SAAShB,IACX,QAATA,EAAiB8rB,OAAOC,KAAKH,EAAKtI,OAAQ,UAAYsI,EAAKtI,cAIvDhB,IAAU,GAChB,EctGFiO,YdoByB1c,MAAO9S,IAChC,MAAMyvB,EAAiB,GAGvB,IAAK,IAAIC,KAAQ1vB,EAAQH,OAAOc,MAAMmG,MAAM,KAC1C4oB,EAAOA,EAAK5oB,MAAM,KACE,IAAhB4oB,EAAKxoB,QACPuoB,EAAexU,KACb4H,GACE,IACK7iB,EACHH,OAAQ,IACHG,EAAQH,OACXC,OAAQ4vB,EAAK,GACbzvB,QAASyvB,EAAK,MAGlB,CAACliB,EAAOqd,KAEN,GAAIrd,EACF,MAAMA,EAIRqI,EACEgV,EAAK7qB,QAAQH,OAAOI,QACS,QAA7B4qB,EAAK7qB,QAAQH,OAAOZ,KAChB8rB,OAAOC,KAAKH,EAAKtI,OAAQ,UACzBsI,EAAKtI,OACV,KAOX,UAEQtP,QAAQwC,IAAIga,SAGZlO,IACP,CAAC,MAAO/T,GACP,MAAM,IAAIqG,GACR,kDACAK,SAAS1G,EACZ,GcjEDqV,eAGAtD,YACAgC,YAGArK,WvBjFwB,CAACU,EAAa7Y,KAElCA,GAAMmI,SAER4K,GA6NJ,SAAwB/S,GAEtB,MAAM4wB,EAAc5wB,EAAK6wB,WACtBC,GAAkC,eAA1BA,EAAIre,QAAQ,KAAM,MAI7B,GAAIme,GAAe,GAAK5wB,EAAK4wB,EAAc,GAAI,CAC7C,MAAMG,EAAW/wB,EAAK4wB,EAAc,GACpC,IAEE,GAAIG,GAAYA,EAASphB,SAAS,SAEhC,OAAOqB,KAAK5D,MAAMsD,EAAaqgB,GAElC,CAAC,MAAOtiB,GACPQ,EACE,EACAR,EACA,sDAAsDsiB,UAEzD,CACF,CAGD,MAAO,EACT,CAvPqBC,CAAehxB,IAIlCoT,GAAoBtT,EAAeiT,IAGnCA,GAAiBS,GAAY1T,GAGzB+Y,IAEF9F,GAAiBE,GACfF,GACA8F,EACAlS,IAKA3G,GAAMmI,SAER4K,GA+RJ,SAA2B9R,EAASjB,EAAMF,GACxC,IAAImxB,GAAY,EAChB,IAAK,IAAI/e,EAAI,EAAGA,EAAIlS,EAAKmI,OAAQ+J,IAAK,CACpC,MAAMlE,EAAShO,EAAKkS,GAAGO,QAAQ,KAAM,IAG/Bye,EAAkBtqB,EAAWoH,GAC/BpH,EAAWoH,GAAQjG,MAAM,KACzB,GAGJ,IAAIopB,EACJD,EAAgBpE,QAAO,CAAChmB,EAAK6S,EAAMmO,KAC7BoJ,EAAgB/oB,OAAS,IAAM2f,IACjCqJ,EAAerqB,EAAI6S,GAAMzZ,MAEpB4G,EAAI6S,KACV7Z,GAEHoxB,EAAgBpE,QAAO,CAAChmB,EAAK6S,EAAMmO,KAC7BoJ,EAAgB/oB,OAAS,IAAM2f,QAER,IAAdhhB,EAAI6S,KACT3Z,IAAOkS,GACY,YAAjBif,EACFrqB,EAAI6S,GAAQpH,GAAUvS,EAAKkS,IACD,WAAjBif,EACTrqB,EAAI6S,IAAS3Z,EAAKkS,GACTif,EAAazb,QAAQ,MAAQ,EACtC5O,EAAI6S,GAAQ3Z,EAAKkS,GAAGnK,MAAM,KAE1BjB,EAAI6S,GAAQ3Z,EAAKkS,IAGnBvD,EACE,EACA,mCAAmCX,yCAErCijB,GAAY,IAIXnqB,EAAI6S,KACV1Y,EACJ,CAGGgwB,GACFrf,IAGF,OAAO3Q,CACT,CAnVqBmwB,CAAkBre,GAAgB/S,EAAMF,IAIpDiT,IuBoDPmd,mBAGAvhB,MACAM,eACAM,cACAC,oBAGA6hB,evB6C6BC,IAC7B,MAAMpe,EAAa,CAAA,EAEnB,IAAK,MAAOnF,EAAK9N,KAAU+G,OAAOiH,QAAQqjB,GAAa,CACrD,MAAMJ,EAAkBtqB,EAAWmH,GAAOnH,EAAWmH,GAAKhG,MAAM,KAAO,GAGvEmpB,EAAgBpE,QACd,CAAChmB,EAAK6S,EAAMmO,IACThhB,EAAI6S,GACHuX,EAAgB/oB,OAAS,IAAM2f,EAAQ7nB,EAAQ6G,EAAI6S,IAAS,IAChEzG,EAEH,CACD,OAAOA,CAAU,EuB1DjBqe,avBlD0Bxd,MAAOyd,IAEjC,IAAIC,EAAa,CAAA,EAGbpjB,EAAWmjB,KACbC,EAAazgB,KAAK5D,MAAMsD,EAAa8gB,EAAgB,UAIvD,MAwDMlrB,EAAUU,OAAOC,KAAKlB,GAAeiC,KAAK0pB,IAAY,CAC1D9jB,MAAO,GAAG8jB,YACVzxB,MAAOyxB,MAIT,OAAOC,EACL,CACEzxB,KAAM,cACN8F,KAAM,WACNC,QAAS,2CACTM,KAAM,yDACNF,aAAc,GACdC,WAEF,CAAEsrB,SAvEa7d,MAAO8d,EAAGC,KACzB,IAAIC,EAAmB,EACnBC,EAAe,GAGnB,IAAK,MAAMC,KAAWH,EAEpB/rB,EAAcksB,GAAWlsB,EAAcksB,GAASjqB,KAAKgG,IAAY,IAC5DA,EACHikB,cAIFD,EAAe,IAAIA,KAAiBjsB,EAAcksB,IAuCpD,aApCMN,EAAQK,EAAc,CAC1BJ,SAAU7d,MAAOme,EAAQC,KAgBvB,GAdoB,kBAAhBD,EAAOlsB,MACTmsB,EAASA,EAAOhqB,OACZgqB,EAAOnqB,KAAKoqB,GAAWF,EAAO5rB,QAAQ8rB,KACtCF,EAAO5rB,QAEXmrB,EAAWS,EAAOD,SAASC,EAAOlsB,MAAQmsB,GAE1CV,EAAWS,EAAOD,SAAWve,GAC3B1M,OAAO8M,OAAO,GAAI2d,EAAWS,EAAOD,UAAY,IAChDC,EAAOlsB,KAAK+B,MAAM,KAClBmqB,EAAO5rB,QAAU4rB,EAAO5rB,QAAQ6rB,GAAUA,KAIxCJ,IAAqBC,EAAa7pB,OAAQ,CAC9C,UACQ8mB,EAAWoD,UACfb,EACAxgB,KAAKC,UAAUwgB,EAAY,KAAM,GACjC,OAEH,CAAC,MAAOhjB,GACPQ,EACE,EACAR,EACA,iDAAiD+iB,UAEpD,CACD,OAAO,CACR,MAIE,CAAI,GAoBZ,EuB/BDc,UxB8KwB1tB,IAExB,MAAM2tB,EAAiBvhB,KAAK5D,MAC1BsD,EAAavK,EAAKyJ,EAAW,kBAC7BvP,QAGEuE,EACF8J,QAAQC,IAAI,sCAAsC4jB,QAKpD7jB,QAAQC,IACN+B,EAAad,EAAY,oBAAoBd,WAAW+C,KAAKC,OAC7D,IAAIygB,MAAmB1gB,KACxB,EwB7LDD"} \ No newline at end of file diff --git a/lib/schemas/config.js b/lib/schemas/config.js index 22fa8b51..b8ce634f 100644 --- a/lib/schemas/config.js +++ b/lib/schemas/config.js @@ -20,7 +20,6 @@ export const scriptsNames = { 'map', 'gantt', 'exporting', - 'export-data', 'parallel-coordinates', 'accessibility', // 'annotations-advanced', @@ -55,6 +54,7 @@ export const scriptsNames = { 'arc-diagram', 'dependency-wheel', 'series-label', + 'series-on-point', 'solid-gauge', 'sonification', // 'stock-tools', @@ -78,7 +78,10 @@ export const scriptsNames = { 'marker-clusters', 'hollowcandlestick', 'heikinashi', - 'flowmap' + 'flowmap', + 'export-data', + 'navigator', + 'textpath' ], indicators: ['indicators-all'] }; diff --git a/package-lock.json b/package-lock.json index bb006ac2..a50e1235 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,12 +16,12 @@ "dotenv": "^16.4.5", "express": "^4.19.2", "express-rate-limit": "^7.3.1", - "https-proxy-agent": "^7.0.4", + "https-proxy-agent": "^7.0.5", "jsdom": "^24.1.0", "jsonwebtoken": "^9.0.2", "multer": "^1.4.5-lts.1", "prompts": "^2.4.2", - "puppeteer": "^22.12.0", + "puppeteer": "^22.12.1", "tarn": "^3.0.2", "uuid": "^10.0.0", "ws": "^8.17.1", @@ -678,9 +678,9 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.1.tgz", - "integrity": "sha512-Zm2NGpWELsQAD1xsJzGQpYfvICSsFkEpU0jxBjfdC6uNEWXcHnfs9hScFWtXVDVl+rBQJGrl4g1vcKIejpH9dA==", + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", + "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", "dev": true, "license": "MIT", "engines": { @@ -1739,9 +1739,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "20.14.8", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.8.tgz", - "integrity": "sha512-DO+2/jZinXfROG7j7WKFn/3C6nFwxy2lLpgLjEXJz+0XKphZlTLJ14mo8Vfg8X5BWN6XjyESXq+LcYdT7tR3bA==", + "version": "20.14.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.9.tgz", + "integrity": "sha512-06OCtnTXtWOZBJlRApleWndH4JsRVs1pDCc8dLSQp+7PpUpX3ePdHyeNSFTeSe7FtKyQkrlPvHwJOW3SLd8Oyg==", "devOptional": true, "license": "MIT", "dependencies": { @@ -1803,9 +1803,9 @@ } }, "node_modules/acorn": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.0.tgz", - "integrity": "sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==", + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", "dev": true, "license": "MIT", "bin": { @@ -2517,9 +2517,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001636", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001636.tgz", - "integrity": "sha512-bMg2vmr8XBsbL6Lr0UHXy/21m84FTxDLWn2FSqMd5PrlbMxwJlQnC2YWYxVgp66PZE+BBNF2jYQUBKCo1FDeZg==", + "version": "1.0.30001640", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001640.tgz", + "integrity": "sha512-lA4VMpW0PSUrFnkmVuEKBUovSWKhj7puyCg8StBChgu298N1AtuF1sKWEvfDuimSEDbhlb/KqPKC3fs1HbuQUA==", "dev": true, "funding": [ { @@ -3252,9 +3252,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.4.810", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.810.tgz", - "integrity": "sha512-Kaxhu4T7SJGpRQx99tq216gCq2nMxJo+uuT6uzz9l8TVN2stL7M06MIIXAtr9jsrLs2Glflgf2vMQRepxawOdQ==", + "version": "1.4.816", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.816.tgz", + "integrity": "sha512-EKH5X5oqC6hLmiS7/vYtZHZFTNdhsYG5NVPRN6Yn0kQHNBlT59+xSM8HBy66P5fxWpKgZbPqb+diC64ng295Jw==", "dev": true, "license": "ISC" }, @@ -4606,9 +4606,9 @@ } }, "node_modules/https-proxy-agent": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", - "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", "license": "MIT", "dependencies": { "agent-base": "^7.0.2", @@ -5153,9 +5153,9 @@ } }, "node_modules/istanbul-lib-instrument": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.2.tgz", - "integrity": "sha512-1WUsZ9R1lA0HtBSohTkm39WTPlNKSJ5iFk7UwqXkBLoHQT+hfqPsfsTDVuZdKGaBwn7din9bS7SsnoAr943hvw==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -6978,9 +6978,9 @@ } }, "node_modules/pac-proxy-agent": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.1.tgz", - "integrity": "sha512-ASV8yU4LLKBAjqIPMbrgtaKIvxQri/yh2OpI+S6hVa9JRkUI3Y3NPFbfngDtY7oFtSMD3w31Xns89mDa3Feo5A==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.2.tgz", + "integrity": "sha512-BFi3vZnO9X5Qt6NRz7ZOaPja3ic0PhlsmCRYLOpN11+mWBCR6XJDqW5RF3j8jm4WGGQZtBA+bTfxYzeKW73eHg==", "license": "MIT", "dependencies": { "@tootallnate/quickjs-emscripten": "^0.23.0", @@ -6988,9 +6988,9 @@ "debug": "^4.3.4", "get-uri": "^6.0.1", "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.2", - "pac-resolver": "^7.0.0", - "socks-proxy-agent": "^8.0.2" + "https-proxy-agent": "^7.0.5", + "pac-resolver": "^7.0.1", + "socks-proxy-agent": "^8.0.4" }, "engines": { "node": ">= 14" @@ -7405,16 +7405,16 @@ } }, "node_modules/puppeteer": { - "version": "22.12.0", - "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-22.12.0.tgz", - "integrity": "sha512-kyUYI12SyJIjf9UGTnHfhNMYv4oVK321Jb9QZDBiGVNx5453SplvbdKI7UrF+S//3RtCneuUFCyHxnvQXQjpxg==", + "version": "22.12.1", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-22.12.1.tgz", + "integrity": "sha512-1GxY8dnEnHr1SLzdSDr0FCjM6JQfAh2E2I/EqzeF8a58DbGVk9oVjj4lFdqNoVbpgFSpAbz7VER9St7S1wDpNg==", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { "@puppeteer/browsers": "2.2.3", - "cosmiconfig": "9.0.0", + "cosmiconfig": "^9.0.0", "devtools-protocol": "0.0.1299070", - "puppeteer-core": "22.12.0" + "puppeteer-core": "22.12.1" }, "bin": { "puppeteer": "lib/esm/puppeteer/node/cli.js" @@ -7424,16 +7424,16 @@ } }, "node_modules/puppeteer-core": { - "version": "22.12.0", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-22.12.0.tgz", - "integrity": "sha512-9gY+JwBW/Fp3/x9+cOGK7ZcwqjvtvY2xjqRqsAA0B3ZFMzBauVTSZ26iWTmvOQX2sk78TN/rd5rnetxVxmK5CQ==", + "version": "22.12.1", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-22.12.1.tgz", + "integrity": "sha512-XmqeDPVdC5/3nGJys1jbgeoZ02wP0WV1GBlPtr/ULRbGXJFuqgXMcKQ3eeNtFpBzGRbpeoCGWHge1ZWKWl0Exw==", "license": "Apache-2.0", "dependencies": { "@puppeteer/browsers": "2.2.3", "chromium-bidi": "0.5.24", - "debug": "4.3.5", + "debug": "^4.3.5", "devtools-protocol": "0.0.1299070", - "ws": "8.17.1" + "ws": "^8.17.1" }, "engines": { "node": ">=18" @@ -8144,14 +8144,14 @@ } }, "node_modules/socks-proxy-agent": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.3.tgz", - "integrity": "sha512-VNegTZKhuGq5vSD6XNKlbqWhyt/40CgoEw8XxD6dhnm8Jq9IEa3nIa4HwnM8XOqU0CdB0BwWVXusqiFXfHB3+A==", + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.4.tgz", + "integrity": "sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==", "license": "MIT", "dependencies": { "agent-base": "^7.1.1", "debug": "^4.3.4", - "socks": "^2.7.1" + "socks": "^2.8.3" }, "engines": { "node": ">= 14" @@ -8278,9 +8278,9 @@ } }, "node_modules/string-width": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.1.0.tgz", - "integrity": "sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, "license": "MIT", "dependencies": { @@ -8896,9 +8896,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz", - "integrity": "sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", + "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", "dev": true, "funding": [ { @@ -9225,9 +9225,9 @@ } }, "node_modules/ws": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", - "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", "license": "MIT", "engines": { "node": ">=10.0.0" diff --git a/package.json b/package.json index 55d2bf34..69c6a97d 100644 --- a/package.json +++ b/package.json @@ -47,12 +47,12 @@ "dotenv": "^16.4.5", "express": "^4.19.2", "express-rate-limit": "^7.3.1", - "https-proxy-agent": "^7.0.4", + "https-proxy-agent": "^7.0.5", "jsdom": "^24.1.0", "jsonwebtoken": "^9.0.2", "multer": "^1.4.5-lts.1", "prompts": "^2.4.2", - "puppeteer": "^22.12.0", + "puppeteer": "^22.12.1", "tarn": "^3.0.2", "uuid": "^10.0.0", "ws": "^8.17.1",