diff --git a/.eslintrc.cjs b/.eslintrc.cjs index d8b1ab80..3b8e2752 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -15,6 +15,14 @@ module.exports = { 'plugin:import/recommended', 'plugin:prettier/recommended' ], + overrides: [ + { + files: ['*.test.js', '*.spec.js'], + env: { + jest: true + } + } + ], rules: { 'no-unused-vars': 0, 'import/no-cycle': 2, diff --git a/.github/workflows/build-and-push.yml b/.github/workflows/build-and-push.yml index 334d06d6..859c4425 100644 --- a/.github/workflows/build-and-push.yml +++ b/.github/workflows/build-and-push.yml @@ -16,7 +16,7 @@ jobs: - name: Set up Node.js uses: actions/setup-node@v4 with: - node-version: '16.4.0' + node-version: '18.x.x' - name: Install Dependencies run: npm ci diff --git a/.github/workflows/eslint-check.yml b/.github/workflows/eslint-check.yml new file mode 100644 index 00000000..62fff57d --- /dev/null +++ b/.github/workflows/eslint-check.yml @@ -0,0 +1,41 @@ +name: ESLint check + +on: [ pull_request ] + +jobs: + eslint: + runs-on: ubuntu-latest + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: '18.x.x' + + - name: Install Dependencies + run: npm install + + - name: Run ESLint + id: eslint + continue-on-error: true + run: | + ESLINT_OUTPUT=$(npx eslint . --ext .js,.jsx,.ts,.tsx) + echo "::set-output name=result::$ESLINT_OUTPUT" + if [ -z "$ESLINT_OUTPUT" ]; then + echo "ESLint found no issues :white_check_mark:" + echo "::set-output name=status::success" + else + echo "$ESLINT_OUTPUT" + echo "::set-output name=status::failure" + exit 1 + fi + + - name: Success Message + if: steps.eslint.outputs.status == 'success' + run: echo "✅ ESLint check passed successfully!" + + - name: Failure Message + if: failure() + run: echo "❌ ESLint check failed. Please fix the issues." diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml new file mode 100644 index 00000000..c23e98f8 --- /dev/null +++ b/.github/workflows/unit-tests.yml @@ -0,0 +1,26 @@ +name: Unit tests + +on: + pull_request: + branches: [ master ] + +jobs: + testing: + runs-on: ubuntu-latest + + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: '18.x.x' + + - name: Install dependencies + run: npm ci + + - name: Run unit tests + run: npm run unit:test + env: + CI: true \ No newline at end of file diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 00000000..6b75e603 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,5 @@ +#!/usr/bin/env sh +. "$(dirname -- "$0")/_/husky.sh" + +npm run lint +npm run unit:test diff --git a/dist/index.cjs b/dist/index.cjs index 0595621b..06100145 100644 --- a/dist/index.cjs +++ b/dist/index.cjs @@ -1,2 +1,2 @@ -"use strict";require("colors");var e=require("dotenv"),t=require("fs"),r=require("path"),i=require("https-proxy-agent"),o=require("http"),n=require("https"),s=require("url"),a=require("prompts"),l=require("tarn"),c=require("uuid"),p=require("node:path"),u=require("puppeteer"),h=require("node:crypto"),d=require("cors"),g=require("express"),m=require("multer"),f=require("express-rate-limit"),y="undefined"!=typeof document?document.currentScript:null;function v(e){var t=Object.create(null);return e&&Object.keys(e).forEach((function(r){if("default"!==r){var i=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,i.get?i:{enumerable:!0,get:function(){return e[r]}})}})),t.default=e,Object.freeze(t)}var w=v(s);async function b(e,t={}){return new Promise(((r,i)=>{const s=(e=>e.startsWith("https")?n:o)(e);s.get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||i("Nothing was fetched from the URL."),e.text=t,r(e)}))})).on("error",(e=>{i(e)}))}))}const T={puppeteer:{args:{value:[],type:"string[]",description:"Arguments array to send to Puppeteer."}},highcharts:{version:{value:"latest",envLink:"HIGHCHARTS_VERSION",type:"string",description:"The Highcharts version to be used."},cdnURL:{value:"https://code.highcharts.com/",envLink:"HIGHCHARTS_CDN_URL",type:"string",description:"The CDN URL for Highcharts scripts to be used."},coreScripts:{envLink:"HIGHCHARTS_CORE_SCRIPTS",value:["highcharts","highcharts-more","highcharts-3d"],type:"string[]",description:"The core Highcharts scripts to fetch."},modules:{envLink:"HIGHCHARTS_MODULES",value:["stock","map","gantt","exporting","export-data","parallel-coordinates","accessibility","annotations-advanced","boost-canvas","boost","data","data-tools","draggable-points","static-scale","broken-axis","heatmap","tilemap","tiledwebmap","timeline","treemap","treegraph","item-series","drilldown","histogram-bellcurve","bullet","funnel","funnel3d","geoheatmap","pyramid3d","networkgraph","overlapping-datalabels","pareto","pattern-fill","pictorial","price-indicator","sankey","arc-diagram","dependency-wheel","series-label","solid-gauge","sonification","stock-tools","streamgraph","sunburst","variable-pie","variwide","vector","venn","windbarb","wordcloud","xrange","no-data-to-display","drag-panes","debugger","dumbbell","lollipop","cylinder","organization","dotplot","marker-clusters","hollowcandlestick","heikinashi","flowmap"],type:"string[]",description:"The modules of Highcharts to fetch."},indicators:{envLink:"HIGHCHARTS_INDICATORS",value:["indicators-all"],type:"string[]",description:"The indicators of Highcharts to fetch."},scripts:{value:["https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js","https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.34/moment-timezone-with-data.min.js"],type:"string[]",description:"Additional optional scripts or dependencies to fetch."},forceFetch:{envLink:"HIGHCHARTS_FORCE_FETCH",value:!1,type:"boolean",description:"The flag to determine whether to refetch all scripts after each server rerun."},cachePath:{envLink:"HIGHCHARTS_CACHE_PATH",value:".cache",type:"string",description:"The path to the cache directory. It is used to store the Highcharts scripts and custom scripts."}},export:{infile:{value:!1,type:"string",description:"The input file should include a name and a type (json or svg). It must be correctly formatted as a JSON or SVG file."},instr:{value:!1,type:"string",description:"Input, provided in the form of a stringified JSON or SVG file, will override the --infile option."},options:{value:!1,type:"string",description:"An alias for the --instr option."},outfile:{value:!1,type:"string",description:"The output filename along with a type (jpeg, png, pdf, or svg). This will ignore the --type flag."},type:{envLink:"EXPORT_TYPE",value:"png",type:"string",description:"The file export format. It can be jpeg, png, pdf, or svg."},constr:{envLink:"EXPORT_CONSTR",value:"chart",type:"string",description:"The constructor to use. Can be chart, stockChart, mapChart, or ganttChart."},defaultHeight:{envLink:"EXPORT_DEFAULT_HEIGHT",value:400,type:"number",description:"the default height of the exported chart. Used when no value is set."},defaultWidth:{envLink:"EXPORT_DEFAULT_WIDTH",value:600,type:"number",description:"The default width of the exported chart. Used when no value is set."},defaultScale:{envLink:"EXPORT_DEFAULT_SCALE",value:1,type:"number",description:"The default scale of the exported chart. Used when no value is set."},height:{type:"number",value:!1,description:"The height of the exported chart, overriding the option in the chart settings."},width:{type:"number",value:!1,description:"The width of the exported chart, overriding the option in the chart settings."},scale:{value:!1,type:"number",description:"The scale of the exported chart, overriding the option in the chart settings. Ranges between 0.1 and 5.0."},globalOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing options to be passed into the Highcharts.setOptions."},themeOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing theme options to be passed into the Highcharts.setOptions."},batch:{value:!1,type:"string",description:'Initiates a batch job with a string containing input/output pairs: "in=out;in=out;...".'},rasterizationTimeout:{envLink:"EXPORT_RASTERIZATION_TIMEOUT",value:1500,type:"number",description:"The duration in milliseconds to wait for rendering a webpage."}},customLogic:{allowCodeExecution:{envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",value:!1,type:"boolean",description:"Controls whether the execution of arbitrary code is allowed during the exporting process."},allowFileResources:{envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",value:!1,type:"boolean",description:"Controls the ability to inject resources from the filesystem. This setting has no effect when running as a server."},customCode:{value:!1,type:"string",description:"Custom code to execute before chart initialization. It can be a function, code wrapped within a function, or a filename with the .js extension."},callback:{value:!1,type:"string",description:"JavaScript code to run during construction. It can be a function or a filename with the .js extension."},resources:{value:!1,type:"string",description:"Additional resource in the form of a stringified JSON, which may contain files, js, and css sections."},loadConfig:{value:!1,type:"string",legacyName:"fromFile",description:"A file containing a pre-defined configuration to use."},createConfig:{value:!1,type:"string",description:"Enables setting options through a prompt and saving them in a provided config file."}},server:{enable:{envLink:"SERVER_ENABLE",value:!1,type:"boolean",cliName:"enableServer",description:"When set to true, the server starts on the local IP address 0.0.0.0."},host:{envLink:"SERVER_HOST",value:"0.0.0.0",type:"string",description:"The hostname of the server. Additionally, it starts a server on the provided hostname."},port:{envLink:"SERVER_PORT",value:7801,type:"number",description:"The server port when enabled."},benchmarking:{envLink:"SERVER_BENCHMARKING",value:!1,type:"boolean",cliName:"serverBenchmarking",description:"Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request."},ssl:{enable:{envLink:"SERVER_SSL_ENABLE",value:!1,type:"boolean",cliName:"enableSsl",description:"Enables or disables the SSL protocol."},force:{envLink:"SERVER_SSL_FORCE",value:!1,type:"boolean",cliName:"sslForced",legacyName:"sslOnly",description:"When set to true, the server is forced to serve only over HTTPS."},port:{envLink:"SERVER_SSL_PORT",value:443,type:"number",cliName:"sslPort",description:"The port on which to run the SSL server."},certPath:{envLink:"SERVER_SSL_CERT_PATH",value:"",type:"string",legacyName:"sslPath",description:"The path to the SSL certificate/key file."}},rateLimiting:{enable:{envLink:"SERVER_RATE_LIMITING_ENABLE",value:!1,type:"boolean",cliName:"enableRateLimiting",description:"Enables rate limiting for the server."},maxRequests:{envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",value:10,type:"number",legacyName:"rateLimit",description:"The maximum number of requests allowed in one minute."},window:{envLink:"SERVER_RATE_LIMITING_WINDOW",value:1,type:"number",description:"The time window, in minutes, for the rate limiting."},delay:{envLink:"SERVER_RATE_LIMITING_DELAY",value:0,type:"number",description:"The delay duration for each successive request before reaching the maximum limit."},trustProxy:{envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",value:!1,type:"boolean",description:"Set this to true if the server is behind a load balancer."},skipKey:{envLink:"SERVER_RATE_LIMITING_SKIP_KEY",value:"",type:"string",description:"Allows bypassing the rate limiter and should be provided with the skipToken argument."},skipToken:{envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",value:"",type:"string",description:"Allows bypassing the rate limiter and should be provided with the skipKey argument."}}},pool:{minWorkers:{envLink:"POOL_MIN_WORKERS",value:4,type:"number",description:"The number of minimum and initial pool workers to spawn."},maxWorkers:{envLink:"POOL_MAX_WORKERS",value:8,type:"number",legacyName:"workers",description:"The number of maximum pool workers to spawn."},workLimit:{envLink:"POOL_WORK_LIMIT",value:40,type:"number",description:"The number of work pieces that can be performed before restarting the worker process."},acquireTimeout:{envLink:"POOL_ACQUIRE_TIMEOUT",value:5e3,type:"number",description:"The duration, in milliseconds, to wait for acquiring a resource."},createTimeout:{envLink:"POOL_CREATE_TIMEOUT",value:5e3,type:"number",description:"The duration, in milliseconds, to wait for creating a resource."},destroyTimeout:{envLink:"POOL_DESTROY_TIMEOUT",value:5e3,type:"number",description:"The duration, in milliseconds, to wait for destroying a resource."},idleTimeout:{envLink:"POOL_IDLE_TIMEOUT",value:3e4,type:"number",description:"The duration, in milliseconds, after which an idle resource is destroyed."},createRetryInterval:{envLink:"POOL_CREATE_RETRY_INTERVAL",value:200,type:"number",description:"The duration, in milliseconds, to wait before retrying the create process in case of a failure."},reaperInterval:{envLink:"POOL_REAPER_INTERVAL",value:1e3,type:"number",description:"The duration, in milliseconds, after which the check for idle resources to destroy is triggered."},benchmarking:{envLink:"POOL_BENCHMARKING",value:!1,type:"boolean",cliName:"poolBenchmarking",description:"Indicate whether to show statistics for the pool of resources or not."},listenToProcessExits:{envLink:"POOL_LISTEN_TO_PROCESS_EXITS",value:!0,type:"boolean",description:"Decides whether or not to attach process.exit handlers."}},logging:{level:{envLink:"LOGGING_LEVEL",value:4,type:"number",cliName:"logLevel",description:"The logging level to be used."},file:{envLink:"LOGGING_FILE",value:"highcharts-export-server.log",type:"string",cliName:"logFile",description:"The name of a log file. The logDest option also needs to be set to enable file logging."},dest:{envLink:"LOGGING_DEST",value:"log/",type:"string",cliName:"logDest",description:"The path to store log files. This also enables file logging."}},ui:{enable:{envLink:"UI_ENABLE",value:!1,type:"boolean",cliName:"enableUi",description:"Enables or disables the user interface (UI) for the export server."},route:{envLink:"UI_ROUTE",value:"/",type:"string",cliName:"uiRoute",description:"The endpoint route to which the user interface (UI) should be attached."}},other:{noLogo:{envLink:"OTHER_NO_LOGO",value:!1,type:"boolean",description:"Skip printing the logo on a startup. Will be replaced by a simple text."}}},x={puppeteer:[{type:"list",name:"args",message:"Puppeteer arguments",initial:T.puppeteer.args.value.join(","),separator:","}],highcharts:[{type:"text",name:"version",message:"Highcharts version",initial:T.highcharts.version.value},{type:"text",name:"cdnURL",message:"The URL of CDN",initial:T.highcharts.cdnURL.value},{type:"multiselect",name:"modules",message:"Available modules",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:T.highcharts.modules.value},{type:"list",name:"scripts",message:"Custom scripts",initial:T.highcharts.scripts.value.join(","),separator:","},{type:"toggle",name:"forceFetch",message:"Force re-fetch the scripts",initial:T.highcharts.forceFetch.value},{type:"text",name:"cachePath",message:"The path to the cache directory",initial:T.highcharts.cachePath.value}],export:[{type:"select",name:"type",message:"The default export file type",hint:`Default: ${T.export.type.value}`,initial:0,choices:["png","jpeg","pdf","svg"]},{type:"select",name:"constr",message:"The default constructor for Highcharts",hint:`Default: ${T.export.constr.value}`,initial:0,choices:["chart","stockChart","mapChart","ganttChart"]},{type:"number",name:"defaultHeight",message:"The default fallback height of the exported chart",initial:T.export.defaultHeight.value},{type:"number",name:"defaultWidth",message:"The default fallback width of the exported chart",initial:T.export.defaultWidth.value},{type:"number",name:"defaultScale",message:"The default fallback scale of the exported chart",initial:T.export.defaultScale.value,min:.1,max:5},{type:"number",name:"rasterizationTimeout",message:"The rendering webpage timeout in milliseconds",initial:T.export.rasterizationTimeout.value}],customLogic:[{type:"toggle",name:"allowCodeExecution",message:"Enable execution of custom code",initial:T.customLogic.allowCodeExecution.value},{type:"toggle",name:"allowFileResources",message:"Enable file resources",initial:T.customLogic.allowFileResources.value}],server:[{type:"toggle",name:"enable",message:"Starts the server on 0.0.0.0",initial:T.server.enable.value},{type:"text",name:"host",message:"Server hostname",initial:T.server.host.value},{type:"number",name:"port",message:"Server port",initial:T.server.port.value},{type:"toggle",name:"benchmarking",message:"Enable server benchmarking",initial:T.server.benchmarking.value},{type:"toggle",name:"ssl.enable",message:"Enable SSL protocol",initial:T.server.ssl.enable.value},{type:"toggle",name:"ssl.force",message:"Force serving only over HTTPS",initial:T.server.ssl.force.value},{type:"number",name:"ssl.port",message:"SSL server port",initial:T.server.ssl.port.value},{type:"text",name:"ssl.certPath",message:"The path to find the SSL certificate/key",initial:T.server.ssl.certPath.value},{type:"toggle",name:"rateLimiting.enable",message:"Enable rate limiting",initial:T.server.rateLimiting.enable.value},{type:"number",name:"rateLimiting.maxRequests",message:"The maximum requests allowed per minute",initial:T.server.rateLimiting.maxRequests.value},{type:"number",name:"rateLimiting.window",message:"The rate-limiting time window in minutes",initial:T.server.rateLimiting.window.value},{type:"number",name:"rateLimiting.delay",message:"The delay for each successive request before reaching the maximum",initial:T.server.rateLimiting.delay.value},{type:"toggle",name:"rateLimiting.trustProxy",message:"Set to true if behind a load balancer",initial:T.server.rateLimiting.trustProxy.value},{type:"text",name:"rateLimiting.skipKey",message:"Allows bypassing the rate limiter when provided with the skipToken argument",initial:T.server.rateLimiting.skipKey.value},{type:"text",name:"rateLimiting.skipToken",message:"Allows bypassing the rate limiter when provided with the skipKey argument",initial:T.server.rateLimiting.skipToken.value}],pool:[{type:"number",name:"minWorkers",message:"The initial number of workers to spawn",initial:T.pool.minWorkers.value},{type:"number",name:"maxWorkers",message:"The maximum number of workers to spawn",initial:T.pool.maxWorkers.value},{type:"number",name:"workLimit",message:"The pieces of work that can be performed before restarting a Puppeteer process",initial:T.pool.workLimit.value},{type:"number",name:"acquireTimeout",message:"The number of milliseconds to wait for acquiring a resource",initial:T.pool.acquireTimeout.value},{type:"number",name:"createTimeout",message:"The number of milliseconds to wait for creating a resource",initial:T.pool.createTimeout.value},{type:"number",name:"destroyTimeout",message:"The number of milliseconds to wait for destroying a resource",initial:T.pool.destroyTimeout.value},{type:"number",name:"idleTimeout",message:"The number of milliseconds after an idle resource is destroyed",initial:T.pool.idleTimeout.value},{type:"number",name:"createRetryInterval",message:"The retry interval in milliseconds after a create process fails",initial:T.pool.createRetryInterval.value},{type:"number",name:"reaperInterval",message:"The reaper interval in milliseconds after triggering the check for idle resources to destroy",initial:T.pool.reaperInterval.value},{type:"toggle",name:"benchmarking",message:"Enable benchmarking for a resource pool",initial:T.pool.benchmarking.value},{type:"toggle",name:"listenToProcessExits",message:"Set to false to skip attaching process.exit handlers",initial:T.pool.listenToProcessExits.value}],logging:[{type:"number",name:"level",message:"The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)",initial:T.logging.level.value,round:0,min:0,max:5},{type:"text",name:"file",message:"A log file name. Set with the --logDest to enable file logging",initial:T.logging.file.value},{type:"text",name:"dest",message:"The path to log files. Enables file logging",initial:T.logging.dest.value}],ui:[{type:"toggle",name:"enable",message:"Enable UI for the export server",initial:T.ui.enable.value},{type:"text",name:"route",message:"A route to attach the UI",initial:T.ui.route.value}],other:[{type:"toggle",name:"noLogo",message:"Skip printing the logo on startup. Replaced by simple text",initial:T.other.noLogo.value}]},k=["options","globalOptions","themeOptions","resources","payload"],E={},S=(e,t="")=>{Object.keys(e).forEach((r=>{if(!["puppeteer","highcharts"].includes(r)){const i=e[r];void 0===i.value?S(i,`${t}.${r}`):(E[i.cliName||r]=`${t}.${r}`.substring(1),void 0!==i.legacyName&&(E[i.legacyName]=`${t}.${r}`.substring(1)))}}))};S(T);const L=["red","yellow","blue","gray","green"];let R={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:L[0]},{title:"warning",color:L[1]},{title:"notice",color:L[2]},{title:"verbose",color:L[3]},{title:"benchmark",color:L[4]}],listeners:[]};for(const[e,t]of Object.entries(T.logging))R[e]=t.value;const O=(e,r)=>{R.toFile&&(R.pathCreated||(!t.existsSync(R.dest)&&t.mkdirSync(R.dest),R.pathCreated=!0),t.appendFile(`${R.dest}${R.file}`,[r].concat(e).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),R.toFile=!1)})))},I=(...e)=>{const[t,...r]=e,{level:i,levelsDesc:o}=R;if(5!==t&&(0===t||t>i||i>o.length))return;const n=`${(new Date).toString().split("(")[0].trim()} [${o[t-1].title}] -`;R.listeners.forEach((e=>{e(n,r.join(" "))})),R.toConsole&&console.log.apply(void 0,[n.toString()[R.levelsDesc[t-1].color]].concat(r)),O(r,n)},_=(e,t,r)=>{const i=r||t.message,{level:o,levelsDesc:n}=R;if(0===e||e>o||o>n.length)return;const s=`${(new Date).toString().split("(")[0].trim()} [${n[e-1].title}] -`,a=t.message!==t.stackMessage||void 0===t.stackMessage?t.stack:t.stack.split("\n").slice(1).join("\n"),l=[i,"\n",a];R.toConsole&&console.log.apply(void 0,[s.toString()[R.levelsDesc[e-1].color]].concat([i[L[e-1]],"\n",a])),R.listeners.forEach((e=>{e(s,l.join(" "))})),O(l,s)},C=e=>{e>=0&&e<=R.levelsDesc.length&&(R.level=e)},$=(e,t)=>{if(R={...R,dest:e||R.dest,file:t||R.file,toFile:!0},0===R.dest.length)return I(1,"[logger] File logging initialization: no path supplied.");R.dest.endsWith("/")||(R.dest+="/")},P=s.fileURLToPath(new URL("../.","undefined"==typeof document?require("url").pathToFileURL(__filename).href:y&&y.src||new URL("index.cjs",document.baseURI).href)),j=(e,t)=>{const r=["png","jpeg","pdf","svg"];if(t){const i=t.split(".").pop();"jpg"===i?e="jpeg":r.includes(i)&&e!==i&&(e=i)}return{"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"}[e]||r.find((t=>t===e))||"png"},N=(e=!1,r)=>{const i=["js","css","files"];let o=e,n=!1;if(r&&e.endsWith(".json"))try{o=A(t.readFileSync(e,"utf8"))}catch(e){return _(2,e,"[cli] No resources found.")}else o=A(e),o&&!r&&delete o.files;for(const e in o)i.includes(e)?n||(n=!0):delete o[e];return n?(o.files&&(o.files=o.files.map((e=>e.trim())),(!o.files||o.files.length<=0)&&delete o.files),o):I(3,"[cli] No resources found.")};function A(e,t){try{const r=JSON.parse("string"!=typeof e?JSON.stringify(e):e);return"string"!=typeof r&&t?JSON.stringify(r):r}catch{return!1}}const H=e=>{if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=H(e[r]));return t},F=(e,t)=>JSON.stringify(e,((e,r)=>("string"==typeof r&&((r=r.trim()).startsWith("function(")||r.startsWith("function ("))&&r.endsWith("}")&&(r=t?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:void 0),"function"==typeof r?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:r))).replaceAll(/"EXP_FUN|EXP_FUN"/g,"");function U(){console.log("\nUsage of CLI arguments:".bold,"\n------",`\nFor more detailed information, visit the readme at: ${"https://github.com/highcharts/node-export-server#readme".bold.yellow}.`);const e=t=>{for(const[r,i]of Object.entries(t))if(Object.prototype.hasOwnProperty.call(i,"value")){let e=` --${i.cliName||r} ${("<"+i.type+">").green} `;if(e.length<48)for(let t=e.length;t<48;t++)e+=".";console.log(e,i.description,`[Default: ${i.value.toString().bold}]`.blue)}else e(i)};Object.keys(T).forEach((t=>{["puppeteer","highcharts"].includes(t)||(console.log(`\n${t.toUpperCase()}`.red),e(T[t]))})),console.log("\n")}const q=e=>!["false","undefined","null","NaN","0",""].includes(e)&&!!e,W=(e,r)=>{if(e&&"string"==typeof e)return(e=e.trim()).endsWith(".js")?!!r&&W(t.readFileSync(e,"utf8")):e.startsWith("function()")||e.startsWith("function ()")||e.startsWith("()=>")||e.startsWith("() =>")?`(${e})()`:e.replace(/;$/,"")},D=()=>{const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6};class M extends Error{constructor(e){super(),this.message=e,this.stackMessage=e}setError(e){return this.error=e,e.name&&(this.name=e.name),e.statusCode&&(this.statusCode=e.statusCode),e.stack&&(this.stackMessage=e.message,this.stack=e.stack),this}}const G={cdnURL:"https://code.highcharts.com/",activeManifest:{},sources:"",hcVersion:""};let V=!1;const J=()=>G.hcVersion=G.sources.substring(0,G.sources.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim(),K=async(e,t,r,i=!1)=>{e.endsWith(".js")&&(e=e.substring(0,e.length-3)),I(4,`[cache] Fetching script - ${e}.js`);const o=t?{agent:t,timeout:+process.env.PROXY_SERVER_TIMEOUT||5e3}:{},n=await b(`${e}.js`,o);if(200===n.statusCode&&"string"==typeof n.text){if(r){r[e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")]=1}return n.text}if(i)throw new M(`Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${n.statusCode}).`).setError(n);return I(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`),""},z=async(e,r)=>{const{coreScripts:o,modules:n,indicators:s,scripts:a}=e,l="latest"!==e.version&&e.version?`${e.version}/`:"";let c;I(3,`[cache] Updating cache version to Highcharts: ${l||"latest"}.`);const p=process.env.PROXY_SERVER_HOST,u=process.env.PROXY_SERVER_PORT;if(p&&u)try{c=new i.HttpsProxyAgent({host:p,port:+u})}catch(e){throw new M("[cache] Could not create a Proxy Agent.").setError(e)}const h={};try{return G.sources=await(async(e,t,r,i,o,n)=>{const s=[...e.map((e=>K(`${i}${e}`,o,n,!0))),...t.map((e=>K(`${i}${e}`,o,n))),...r.map((e=>K(`${e}`,o)))];return(await Promise.all(s)).join(";\n")})([...o.map((e=>`${l}${e}`))],[...n.map((e=>"map"===e?`maps/${l}modules/${e}`:`${l}modules/${e}`)),...s.map((e=>`stock/${l}indicators/${e}`))],a,e.cdnURL||G.cdnURL,c,h),J(),t.writeFileSync(r,G.sources),h}catch(e){throw new M("[cache] Unable to update the local Highcharts cache.").setError(e)}},X=async e=>{const i=r.join(P,e.cachePath);let o;const n=r.join(i,"manifest.json"),s=r.join(i,"sources.js");if(V=e,!t.existsSync(i)&&t.mkdirSync(i),!t.existsSync(n)||e.forceFetch)I(3,"[cache] Fetching and caching Highcharts dependencies."),o=await z(e,s);else{let r=!1;const i=JSON.parse(t.readFileSync(n));if(i.modules&&Array.isArray(i.modules)){const e={};i.modules.forEach((t=>e[t]=1)),i.modules=e}const{modules:a,coreScripts:l,indicators:c}=e,p=a.length+l.length+c.length;i.version!==e.version?(I(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),r=!0):Object.keys(i.modules||{}).length!==p?(I(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),r=!0):r=(e.modules||[]).some((e=>{if(!i.modules[e])return I(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),r?o=await z(e,s):(I(3,"[cache] Dependency cache is up to date, proceeding."),G.sources=t.readFileSync(s,"utf8"),o=i.modules,J())}await(async(e,i)=>{const o={version:e.version,modules:i||{}};G.activeManifest=o,I(3,"[cache] Writing a new manifest.");try{t.writeFileSync(r.join(P,e.cachePath,"manifest.json"),JSON.stringify(o),"utf8")}catch(e){throw new M("[cache] Error writing the cache manifest.").setError(e)}})(e,o)},B=()=>r.join(P,V.cachePath);var Y=async e=>!!V&&await X(Object.assign(V,{version:e})),Q=()=>G,Z=()=>G.hcVersion;let ee={};const te=()=>ee,re=(e,t,r=[])=>{const i=H(e);for(const[e,n]of Object.entries(t))i[e]="object"!=typeof(o=n)||Array.isArray(o)||null===o||r.includes(e)||void 0===i[e]?void 0!==n?n:i[e]:re(i[e],n,r);var o;return i};function ie(e,t={},r=""){Object.keys(e).forEach((i=>{const o=e[i],n=t&&t[i];let s;void 0===o.value?ie(o,n,`${r}.${i}`):(void 0!==n&&(o.value=n),o.envLink&&("boolean"===o.type?o.value=q([process.env[o.envLink],o.value].find((e=>e||"false"===e))):"number"===o.type?(s=+process.env[o.envLink],o.value=s>=0?s:o.value):o.type.indexOf("]")>=0&&process.env[o.envLink]?o.value=process.env[o.envLink].split(","):o.value=process.env[o.envLink]||o.value))}))}function oe(e){let t={};for(const[r,i]of Object.entries(e))t[r]=Object.prototype.hasOwnProperty.call(i,"value")?i.value:oe(i);return t}function ne(e,t,r){for(;t.length>1;){const i=t.shift();return Object.prototype.hasOwnProperty.call(e,i)||(e[i]={}),e[i]=ne(Object.assign({},e[i]),t,r),e}return e[t[0]]=r,e}const se=h.randomBytes(64).toString("base64url"),ae=p.join("tmp",`puppeteer-${se}`),le=[`--user-data-dir=${p.join(ae,"profile")}`,"--autoplay-policy=user-gesture-required","--disable-background-networking","--disable-background-timer-throttling","--disable-backgrounding-occluded-windows","--disable-breakpad","--disable-client-side-phishing-detection","--disable-component-update","--disable-default-apps","--disable-dev-shm-usage","--disable-domain-reliability","--disable-extensions","--disable-features=AudioServiceOutOfProcess","--disable-hang-monitor","--disable-ipc-flooding-protection","--disable-notifications","--disable-offer-store-unmasked-wallet-cards","--disable-popup-blocking","--disable-print-preview","--disable-prompt-on-repost","--disable-renderer-backgrounding","--disable-session-crashed-bubble","--disable-setuid-sandbox","--disable-speech-api","--disable-sync","--hide-crash-restore-bubble","--hide-scrollbars","--ignore-gpu-blacklist","--metrics-recording-only","--mute-audio","--no-default-browser-check","--no-first-run","--no-pings","--no-sandbox","--no-zygote","--password-store=basic","--use-mock-keychain"],ce=w.fileURLToPath(new URL(".","undefined"==typeof document?require("url").pathToFileURL(__filename).href:y&&y.src||new URL("index.cjs",document.baseURI).href)),pe=t.readFileSync(ce+"/../templates/template.html","utf8");let ue;const he=async e=>{await e.setContent(pe),await e.addScriptTag({path:`${B()}/sources.js`}),await e.evaluate((()=>window.setupHighcharts())),e.on("pageerror",(async t=>{await e.$eval("#container",((e,t)=>{window._displayErrors&&(e.innerHTML=t)}),`

Chart input data error

${t.toString()}`)}))},de=async(e,t=!1)=>{try{t?(await e.goto("about:blank"),await he(e)):await e.evaluate((()=>{document.body.innerHTML='
'}))}catch(e){_(2,e,"[browser] Could not clear the content of the page.")}},ge=async()=>{if(!ue)return!1;const e=await ue.newPage();return await e.setCacheEnabled(!1),await he(e),e},me=async()=>(ue?.isConnected()&&(await ue.close(),I(4,"[browser] Closed the browser.")),!0);const fe=w.fileURLToPath(new URL(".","undefined"==typeof document?require("url").pathToFileURL(__filename).href:y&&y.src||new URL("index.cjs",document.baseURI).href)),ye=(e,t,r)=>e.evaluate(((e,t)=>window.triggerExport(e,t)),t,r);var ve=async(e,i,o)=>{const n=[],s=async e=>{for(const e of n)await e.dispose();await e.evaluate((()=>{const[,...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...r]=document.getElementsByTagName("link");for(const i of[...e,...t,...r])i.remove()}))};try{I(4,"[export] Determining export path.");const a=o.export;await e.evaluate((()=>requestAnimationFrame((()=>{}))));const l=a?.options?.chart?.displayErrors&&Q().activeManifest.modules.debugger;let c;if(await e.evaluate((e=>window._displayErrors=e),l),i.indexOf&&(i.indexOf("=0||i.indexOf("=0)){if(I(4,"[export] Treating as SVG."),"svg"===a.type)return i;c=!0,await e.setContent((e=>`\n\n\n \n \n Highcarts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`)(i))}else I(4,"[export] Treating as config."),a.strInj?await ye(e,{chart:{height:a.height,width:a.width}},o):(i.chart.height=a.height,i.chart.width=a.width,await ye(e,i,o));const p=o.customLogic.resources;if(p){if(p.js&&n.push(await e.addScriptTag({content:p.js})),p.files)for(const r of p.files)try{const i=!r.startsWith("http");n.push(await e.addScriptTag(i?{content:t.readFileSync(r,"utf8")}:{url:r}))}catch(e){_(2,e,`[export] The JS file ${r} cannot be loaded.`)}if(p.css){let t=p.css.match(/@import\s*([^;]*);/g);if(t)for(let i of t)i&&(i=i.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),i.startsWith("http")?n.push(await e.addStyleTag({url:i})):o.customLogic.allowFileResources&&n.push(await e.addStyleTag({path:r.join(fe,i)})));n.push(await e.addStyleTag({content:p.css.replace(/@import\s*([^;]*);/g,"")||" "}))}}const u=c?await e.$eval("#chart-container svg:first-of-type",((e,t)=>({chartHeight:e.height.baseVal.value*t,chartWidth:e.width.baseVal.value*t})),parseFloat(a.scale)):await e.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return{chartHeight:e,chartWidth:t}})),h=Math.ceil(u?.chartHeight||a.height),d=Math.ceil(u?.chartWidth||a.width);await e.setViewport({height:h,width:d,deviceScaleFactor:c?1:parseFloat(a.scale)});const g=c?e=>{document.body.style.zoom=e,document.body.style.margin="0px"}:()=>{document.body.style.zoom=1};await e.evaluate(g,parseFloat(a.scale));const{height:m,width:f,x:y,y:v}=await(e=>e.$eval("#chart-container",(e=>{const{x:t,y:r,width:i,height:o}=e.getBoundingClientRect();return{x:t,y:r,width:i,height:Math.trunc(o>1?o:500)}})))(e);let w;if(c||await e.setViewport({width:Math.round(f),height:Math.round(m),deviceScaleFactor:parseFloat(a.scale)}),"svg"===a.type)w=await(e=>e.$eval("#container svg:first-of-type",(e=>e.outerHTML)))(e);else if(["png","jpeg"].includes(a.type))w=await((e,t,r,i,o)=>Promise.race([e.screenshot({type:t,encoding:r,clip:i,omitBackground:"png"==t}),new Promise(((e,t)=>setTimeout((()=>t(new M("Rasterization timeout"))),o||1500)))]))(e,a.type,"base64",{width:d,height:h,x:y,y:v},a.rasterizationTimeout);else{if("pdf"!==a.type)throw new M(`[export] Unsupported output format ${a.type}.`);w=await((e,t,r,i)=>e.pdf({height:t+1,width:r,encoding:i}))(e,h,d,"base64")}return await e.evaluate((()=>{if("undefined"!=typeof Highcharts){const e=Highcharts.charts;if(Array.isArray(e)&&e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()}})),await s(e),w}catch(t){return await s(e),t}};let we,be=0,Te=0,xe=0,ke=0,Ee=0,Se={},Le=!1;const Re={create:async()=>{let e=!1;const t=c.v4(),r=(new Date).getTime();try{if(e=await ge(),!e||e.isClosed())throw new M("The page is invalid or closed.");I(3,`[pool] Successfully created a worker ${t} - took ${(new Date).getTime()-r} ms.`)}catch(e){throw new M("Error encountered when creating a new page.").setError(e)}return{id:t,page:e,workCount:Math.round(Math.random()*(Se.workLimit/2))}},validate:async e=>Se.workLimit&&++e.workCount>Se.workLimit?(I(3,`[pool] Worker failed validation: exceeded work limit (limit is ${Se.workLimit}).`),!1):(await de(e.page,!0),!0),destroy:e=>{I(3,`[pool] Destroying pool entry ${e.id}.`),e.page&&e.page.close()}},Oe=async e=>{if(Se=e&&e.pool?{...e.pool}:{},Se.listenToProcessExits&&(I(3,"[pool] Attaching exit listeners to the process."),process.on("exit",(async e=>{I(4,`Process exited with code ${e}.`),await Ie()})),process.on("SIGINT",((e,t)=>{I(4,`The ${e} event with code: ${t}.`),process.exit(1)})),process.on("SIGTERM",((e,t)=>{I(4,`The ${e} event with code: ${t}.`),process.exit(1)})),process.on("uncaughtException",(async(e,t)=>{_(1,e,`The ${t} error.`),await Ie(),process.exit(1)}))),we=e.puppeteerArgs,await(async e=>{const t=[...le,...e||[]];if(!ue){let e=0;const r=async()=>{try{I(3,`[browser] Attempting to get a browser instance (try ${++e}).`),ue=await u.launch({headless:"new",args:t,userDataDir:"./tmp/"})}catch(t){if(_(1,t,"[browser] Failed to launch a browser instance."),!(e<25))throw t;I(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await r()}};try{await r()}catch(e){throw new M("[browser] Maximum retries to open a browser instance reached.").setError(e)}if(!ue)throw new M("[browser] Cannot find a browser to open.")}return ue})(we),I(3,`[pool] Initializing pool with workers: min ${Se.minWorkers}, max ${Se.maxWorkers}.`),Le)return I(4,"[pool] Already initialized, please kill it before creating a new one.");parseInt(Se.minWorkers)>parseInt(Se.maxWorkers)&&(Se.minWorkers=Se.maxWorkers);try{Le=new l.Pool({...Re,min:parseInt(Se.minWorkers),max:parseInt(Se.maxWorkers),acquireTimeoutMillis:Se.acquireTimeout,createTimeoutMillis:Se.createTimeout,destroyTimeoutMillis:Se.destroyTimeout,idleTimeoutMillis:Se.idleTimeout,createRetryIntervalMillis:Se.createRetryInterval,reapIntervalMillis:Se.reaperInterval,propagateCreateError:!1}),Le.on("release",(async e=>{await de(e.page,!1),I(4,`[pool] Releasing a worker with ID ${e.id}.`)})),Le.on("destroySuccess",((e,t)=>{I(4,`[pool] Destroyed a worker with ID ${t.id}.`)}));const e=[];for(let t=0;t{Le.release(e)})),I(3,"[pool] The pool is ready"+(e.length?` with ${e.length} initial resources waiting.`:"."))}catch(e){throw await me(),new M("[pool] Could not create the pool of workers.").setError(e)}};async function Ie(){return I(3,"[pool] Killing all pool workers and browser, if any exist."),Le?.destroyed||Le&&(await Le.destroy(),I(4,"[browser] Destroyed the pool of resources.")),me()}const _e=async(e,t)=>{let r;try{if(I(4,"[pool] Work received, starting to process."),++Te,Se.benchmarking&&Ce(),!Le)throw new M("Work received, but pool has not been started.");try{I(4,"[pool] Acquiring a worker handle.");const e=D();r=await Le.acquire().promise,t.server.benchmarking&&I(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Acquired a worker handle: ${e()}ms.`)}catch(e){throw new M("Error encountered when acquiring an available entry.").setError(e)}if(I(4,"[pool] Acquired a worker handle."),!r.page)throw new M("Resolved worker page is invalid: the pool setup is wonky.");let i=(new Date).getTime();I(4,`[pool] Starting work on pool entry with ID ${r.id}.`);const o=D(),n=await ve(r.page,e,t);if(n instanceof Error)throw"Rasterization timeout"===n.message&&(r.page.close(),r.page=await ge()),new M("Error encountered during export.").setError(n);t.server.benchmarking&&I(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Exported a chart sucessfully: ${o()}ms.`),Le.release(r);const s=(new Date).getTime()-i;return xe+=s,Ee=xe/++be,I(4,`[pool] Work completed in ${s} ms.`),{result:n,options:t}}catch(e){throw++ke,r&&Le.release(r),new M(`[pool] In pool.postWork: ${e.message}`).setError(e)}};function Ce(){const{min:e,max:t}=Le;I(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),I(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),I(5,`[pool] The number of resources that are currently available: ${Le.numFree()}.`),I(5,`[pool] The number of resources that are currently acquired: ${Le.numUsed()}.`),I(5,`[pool] The number of callers waiting to acquire a resource: ${Le.numPendingAcquires()}.`)}var $e=()=>({min:Le.min,max:Le.max,available:Le.numFree(),inUse:Le.numUsed(),pendingAcquire:Le.numPendingAcquires()}),Pe=()=>Te,je=()=>ke,Ne=()=>Ee,Ae=()=>be;let He=!1;const Fe=async(e,r)=>{I(4,"[chart] Starting the exporting process.");const i=((e,t={})=>{let r={};return e.svg?(r=H(t),r.export.type=e.type||e.export.type,r.export.scale=e.scale||e.export.scale,r.export.outfile=e.outfile||e.export.outfile,r.payload={svg:e.svg}):r=re(t,e,k),r.export.outfile=r.export?.outfile||`chart.${r.export?.type||"png"}`,r})(e,te()),o=i.export;if(i.payload?.svg&&""!==i.payload.svg)try{return I(4,"[chart] Attempting to export from a SVG input."),De(i.payload.svg.trim(),i,r)}catch(e){return r(new M("[chart] Error loading SVG input.").setError(e))}if(o.infile&&o.infile.length)try{return I(4,"[chart] Attempting to export from an input file."),i.export.instr=t.readFileSync(o.infile,"utf8"),De(i.export.instr.trim(),i,r)}catch(e){return r(new M("[chart] Error loading input file.").setError(e))}if(o.instr&&""!==o.instr||o.options&&""!==o.options)try{return I(4,"[chart] Attempting to export from a raw input."),q(i.customLogic?.allowCodeExecution)?We(i,r):"string"==typeof o.instr?De(o.instr.trim(),i,r):qe(i,o.instr||o.options,r)}catch(e){return r(new M("[chart] Error loading raw input.").setError(e))}return r(new M("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'."))},Ue=e=>{const{chart:t,exporting:r}=e.export?.options||A(e.export?.instr),i=A(e.export?.globalOptions);let o=e.export?.scale||r?.scale||i?.exporting?.scale||e.export?.defaultScale||1;o=Math.max(.1,Math.min(o,5)),o=((e,t=1)=>{const r=Math.pow(10,t||0);return Math.round(+e*r)/r})(o,2);const n={height:e.export?.height||r?.sourceHeight||t?.height||i?.exporting?.sourceHeight||i?.chart?.height||e.export?.defaultHeight||400,width:e.export?.width||r?.sourceWidth||t?.width||i?.exporting?.sourceWidth||i?.chart?.width||e.export?.defaultWidth||600,scale:o};for(let[e,t]of Object.entries(n))n[e]="string"==typeof t?+t.replace(/px|%/gi,""):t;return n},qe=async(e,r,i,o)=>{let{export:n,customLogic:s}=e;const a="boolean"==typeof s.allowCodeExecution?s.allowCodeExecution:He;if(s){if(a)if("string"==typeof e.customLogic.resources)e.customLogic.resources=N(e.customLogic.resources,q(e.customLogic.allowFileResources));else if(!e.customLogic.resources)try{const r=t.readFileSync("resources.json","utf8");e.customLogic.resources=N(r,q(e.customLogic.allowFileResources))}catch(e){_(2,e,"[chart] Unable to load the default resources.json file.")}}else s=e.customLogic={};if(!a&&s){if(s.callback||s.resources||s.customCode)return i(new M("[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server."));s.callback=!1,s.resources=!1,s.customCode=!1}if(r&&(r.chart=r.chart||{},r.exporting=r.exporting||{},r.exporting.enabled=!1),n.constr=n.constr||"chart",n.type=j(n.type,n.outfile),"svg"===n.type&&(n.width=!1),["globalOptions","themeOptions"].forEach((e=>{try{n&&n[e]&&("string"==typeof n[e]&&n[e].endsWith(".json")?n[e]=A(t.readFileSync(n[e],"utf8"),!0):n[e]=A(n[e],!0))}catch(t){n[e]={},_(2,t,`[chart] The '${e}' cannot be loaded.`)}})),s.allowCodeExecution)try{s.customCode=W(s.customCode,s.allowFileResources)}catch(e){_(2,e,"[chart] The 'customCode' cannot be loaded.")}if(s&&s.callback&&s.callback?.indexOf("{")<0)if(s.allowFileResources)try{s.callback=t.readFileSync(s.callback,"utf8")}catch(e){s.callback=!1,_(2,e,"[chart] The 'callback' cannot be loaded.")}else s.callback=!1;e.export={...e.export,...Ue(e)};try{return i(!1,await _e(n.strInj||r||o,e))}catch(e){return i(e)}},We=(e,t)=>{try{let r,i=e.export.instr||e.export.options;return"string"!=typeof i&&(r=i=F(i,e.customLogic?.allowCodeExecution)),r=i.replaceAll(/\t|\n|\r/g,"").trim(),";"===r[r.length-1]&&(r=r.substring(0,r.length-1)),e.export.strInj=r,qe(e,!1,t)}catch(r){return t(new M(`[chart] Malformed input detected for ${e.export?.requestId||"?"}. Please make sure that your JSON/JavaScript options are sent using the "options" attribute, and that if you're using SVG, it is unescaped.`).setError(r))}},De=(e,t,r)=>{const{allowCodeExecution:i}=t.customLogic;if(e.indexOf("=0||e.indexOf("=0)return I(4,"[chart] Parsing input as SVG."),qe(t,!1,r,e);try{const i=JSON.parse(e.replaceAll(/\t|\n|\r/g," "));return qe(t,i,r)}catch(e){return q(i)?We(t,r):r(new M("[chart] Only JSON configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the --allowCodeExecution flag.").setError(e))}},Me=(e,t,r,i)=>{_(1,e),"development"!==process.env.NODE_ENV&&delete e.stack,i(e)},Ge=(e,t,r,i)=>{const{statusCode:o,status:n,message:s,stack:a}=e,l=o||n||500;r.status(l).json({statusCode:l,message:s,stack:a})};var Ve=(e,t)=>{const r="Too many requests, you have been rate limited. Please try again later.",i={max:t.maxRequests||30,window:t.window||1,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||!1,skipToken:t.skipToken||!1};i.trustProxy&&e.enable("trust proxy");const o=f({windowMs:60*i.window*1e3,max:i.max,delayMs:i.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:r})},default:()=>{t.status(429).send(r)}})},skip:e=>!1!==i.skipKey&&!1!==i.skipToken&&e.query.key===i.skipKey&&e.query.access_token===i.skipToken&&(I(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(o),I(3,`[rate limiting] Enabled rate limiting with ${i.max} requests per ${i.window} minute for each IP, trusting proxy: ${i.trustProxy}.`)};class Je extends M{constructor(e,t){super(e),this.status=this.statusCode=t}setStatus(e){return this.status=e,this}}const Ke={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};let ze=0;const Xe=[],Be=[],Ye=(e,t,r,i)=>{let o=!0;const{id:n,uniqueId:s,type:a,body:l}=i;return e.some((e=>{if(e){let i=e(t,r,n,s,a,l);return void 0!==i&&!0!==i&&(o=i),!0}})),o},Qe=async(e,t,r)=>{try{const r=D(),o=c.v4().replace(/-/g,""),n=te(),s=e.body,a=++ze;let l=j(s.type);if(!s||"object"==typeof(i=s)&&null!==i&&0===Object.keys(i).length)throw new Je("The request body is required. Please ensure that your Content-Type header is correct (accepted types are application/json and multipart/form-data).",400);let p=A(s.infile||s.options||s.data);if(!p&&!s.svg)throw I(2,`The request with ID ${o} from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Payload received: ${JSON.stringify(s)}.`),new Je("No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.",400);let u=!1;if(u=Ye(Xe,e,t,{id:a,uniqueId:o,type:l,body:s}),!0!==u)return t.send(u);let h=!1;e.socket.on("close",(()=>{h=!0})),I(4,`[export] Got an incoming HTTP request with ID ${o}.`),s.constr="string"==typeof s.constr&&s.constr||"chart";const d={export:{instr:p,type:l,constr:s.constr[0].toLowerCase()+s.constr.substr(1),height:s.height,width:s.width,scale:s.scale||n.export.scale,globalOptions:A(s.globalOptions,!0),themeOptions:A(s.themeOptions,!0)},customLogic:{allowCodeExecution:He,allowFileResources:!1,resources:A(s.resources,!0),callback:s.callback,customCode:s.customCode}};p&&(d.export.instr=F(p,d.customLogic.allowCodeExecution));const g=re(n,d);if(g.export.options=p,g.payload={svg:s.svg||!1,b64:s.b64||!1,noDownload:s.noDownload||!1,requestId:o},s.svg&&(e=>["localhost","(10).(.*).(.*).(.*)","(127).(.*).(.*).(.*)","(172).(1[6-9]|2[0-9]|3[0-1]).(.*).(.*)","(192).(168).(.*).(.*)"].some((t=>e.match(`xlink:href="(?:(http://|https://))?${t}`))))(g.payload.svg))throw new Je("SVG potentially contain at least one forbidden URL in xlink:href element. Please review the SVG content and ensure that all referenced URLs comply with security policies.",400);await Fe(g,((i,c)=>{if(e.socket.removeAllListeners("close"),n.server.benchmarking&&I(5,`[benchmark] Request with ID ${o} - After the whole exporting process: ${r()}ms.`),h)return I(3,"[export] The client closed the connection before the chart finished processing.");if(i)throw i;if(!c||!c.result)throw new Je(`Unexpected return from chart generation. Please check your request data. For the request with ID ${o}, the result is ${c.result}.`,400);return l=c.options.export.type,Ye(Be,e,t,{id:a,body:c.result}),c.result?s.b64?"pdf"===l||"svg"==l?t.send(Buffer.from(c.result,"utf8").toString("base64")):t.send(c.result):(t.header("Content-Type",Ke[l]||"image/png"),s.noDownload||t.attachment(`${e.params.filename||e.body.filename||"chart"}.${l||"png"}`),"svg"===l?t.send(c.result):t.send(Buffer.from(c.result,"base64"))):void 0}))}catch(e){r(e)}var i};const Ze=JSON.parse(t.readFileSync(r.join(P,"package.json"))),et=new Date;const tt=g();tt.disable("x-powered-by"),tt.use(d());const rt=m.memoryStorage(),it=m({storage:rt,limits:{fieldSize:52428800}});tt.use(g.json({limit:52428800})),tt.use(g.urlencoded({extended:!0,limit:52428800})),tt.use(it.none());const ot=e=>{e.on("clientError",(e=>{_(1,e,`[server] Client error: ${e.message}`)})),e.on("error",(e=>{_(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{_(1,e,`[server] Socket error: ${e.message}`)}))}))},nt=async e=>{try{if(!e.enable)return!1;if(!e.ssl.force){const t=o.createServer(tt);ot(t),t.listen(e.port,e.host),I(3,`[server] Started HTTP server on ${e.host}:${e.port}.`)}if(e.ssl.enable){let i,o;try{i=await t.promises.readFile(r.posix.join(e.ssl.certPath,"server.key"),"utf8"),o=await t.promises.readFile(r.posix.join(e.ssl.certPath,"server.crt"),"utf8")}catch(t){I(2,`[server] Unable to load key/certificate from the '${e.ssl.certPath}' path. Could not run secured layer server.`)}if(i&&o){const t=n.createServer({key:i,cert:o},tt);ot(t),t.listen(e.ssl.port,e.host),I(3,`[server] Started HTTPS server on ${e.host}:${e.ssl.port}.`)}}e.rateLimiting&&e.rateLimiting.enable&&![0,NaN].includes(e.rateLimiting.maxRequests)&&Ve(tt,e.rateLimiting),tt.use(g.static(r.posix.join(P,"public"))),(e=>{!!e&&e.get("/health",((e,t)=>{t.send({status:"OK",bootTime:et,uptime:Math.floor(((new Date).getTime()-et.getTime())/1e3/60)+" minutes",version:Ze.version,highchartsVersion:Z(),averageProcessingTime:Ne(),performedExports:Ae(),failedExports:je(),exportAttempts:Pe(),sucessRatio:Ae()/Pe()*100,pool:$e()})}))})(tt),(e=>{e.post("/",Qe),e.post("/:filename",Qe)})(tt),(e=>{!!e&&e.get("/",((e,t)=>{t.sendFile(r.join(P,"public","index.html"))}))})(tt),(e=>{!!e&&e.post("/version/change/:newVersion",(async(e,t,r)=>{try{const r=process.env.HIGHCHARTS_ADMIN_TOKEN;if(!r||!r.length)throw new Je("The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.",401);const i=e.get("hc-auth");if(!i||i!==r)throw new Je("Invalid or missing token: Set the token in the hc-auth header.",401);const o=e.params.newVersion;if(!o)throw new Je("No new version supplied.",400);try{await Y(o)}catch(e){throw new Je(`Version change: ${e.message}`,e.statusCode).setError(e)}t.status(200).send({statusCode:200,version:Z(),message:`Successfully updated Highcharts to version: ${o}.`})}catch(e){r(e)}}))})(tt),(e=>{e.use(Me),e.use(Ge)})(tt)}catch(e){throw new M("[server] Could not configure and start the server.").setError(e)}};var st={startServer:nt,enableRateLimiting:e=>Ve(tt,e),getExpress:()=>g,getApp:()=>tt,use:(e,...t)=>{tt.use(e,...t)},get:(e,...t)=>{tt.get(e,...t)},post:(e,...t)=>{tt.post(e,...t)}};e.config();var at={server:st,startServer:nt,setOptions:(e,r)=>(r?.length&&(ee=function(e){const r=e.findIndex((e=>"loadConfig"===e.replace(/-/g,"")));if(r>-1&&e[r+1]){const i=e[r+1];try{if(i&&i.endsWith(".json"))return JSON.parse(t.readFileSync(i))}catch(e){_(2,e,`[config] Unable to load the configuration from the ${i} file.`)}}return{}}(r)),ie(T,ee),ee=oe(T),e&&(ee=re(ee,e,k)),r?.length&&(ee=function(e,t,r){let i=!1;for(let o=0;o(s.length-1===r&&(a=e[t].type),e[t])),r),s.reduce(((e,r,l)=>(s.length-1===l&&void 0!==e[r]&&(t[++o]?"boolean"===a?e[r]=q(t[o]):"number"===a?e[r]=+t[o]:a.indexOf("]")>=0?e[r]=t[o].split(","):e[r]=t[o]:(I(2,`[config] Missing value for the '${n}' argument. Using the default value.`),i=!0)),e[r])),e)}i&&U();return e}(ee,r,T)),ee),initExport:async e=>{var t;return t=e.customLogic&&e.customLogic.allowCodeExecution,He=q(t),(e=>{C(e&&parseInt(e.level)),e&&e.dest&&$(e.dest,e.file||"highcharts-export-server.log")})(e.logging),await X(e.highcharts||{version:"latest"}),await Oe({pool:e.pool||{minWorkers:1,maxWorkers:1},puppeteerArgs:e.puppeteer?.args||[]}),e},singleExport:async e=>{e.export.instr=e.export.instr||e.export.options,await Fe(e,(async(e,r)=>{if(e)throw e;const{outfile:i,type:o}=r.options.export;t.writeFileSync(i||`chart.${o}`,"svg"!==o?Buffer.from(r.result,"base64"):r.result),await Ie()}))},batchExport:async e=>{const r=[];for(let i of e.export.batch.split(";"))i=i.split("="),2===i.length&&r.push(Fe({...e,export:{...e.export,infile:i[0],outfile:i[1]}},((e,r)=>{if(e)throw e;t.writeFileSync(r.options.export.outfile,Buffer.from(r.result,"base64"))})));try{await Promise.all(r),await Ie()}catch(e){throw new M("[chart] Error encountered during batch export.").setError(e)}},startExport:Fe,killPool:Ie,log:I,logWithStack:_,setLogLevel:C,enableFileLogging:$,mapToNewConfig:e=>{const t={};for(const[r,i]of Object.entries(e)){const e=E[r]?E[r].split("."):[];e.reduce(((t,r,o)=>t[r]=e.length-1===o?i:t[r]||{}),t)}return t},manualConfig:async e=>{let r={};t.existsSync(e)&&(r=JSON.parse(t.readFileSync(e,"utf8")));const i=Object.keys(x).map((e=>({title:`${e} options`,value:e})));return a({type:"multiselect",name:"category",message:"Which category do you want to configure?",hint:"Space: Select specific, A: Select all, Enter: Confirm.",instructions:"",choices:i},{onSubmit:async(i,o)=>{let n=0,s=[];for(const e of o)x[e]=x[e].map((t=>({...t,section:e}))),s=[...s,...x[e]];return await a(s,{onSubmit:async(i,o)=>{if("modules"===i.name?(o=o.length?o.map((e=>i.choices[e])):i.choices,r[i.section][i.name]=o):r[i.section]=ne(Object.assign({},r[i.section]||{}),i.name.split("."),i.choices?i.choices[o]:o),++n===s.length){try{await t.promises.writeFile(e,JSON.stringify(r,null,2),"utf8")}catch(t){_(1,t,`[config] An error occurred while creating the ${e} file.`)}return!0}}}),!0}})},printLogo:e=>{const i=JSON.parse(t.readFileSync(r.join(P,"package.json"))).version;e?console.log(`Starting Highcharts Export Server v${i}...`):console.log(t.readFileSync(P+"/msg/startup.msg").toString().bold.yellow,`v${i}`)},printUsage:U};module.exports=at; -//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguY2pzIiwic291cmNlcyI6WyIuLi9saWIvZmV0Y2guanMiLCIuLi9saWIvc2NoZW1hcy9jb25maWcuanMiLCIuLi9saWIvbG9nZ2VyLmpzIiwiLi4vbGliL3V0aWxzLmpzIiwiLi4vbGliL2Vycm9ycy9FeHBvcnRFcnJvci5qcyIsIi4uL2xpYi9jYWNoZS5qcyIsIi4uL2xpYi9jb25maWcuanMiLCIuLi9saWIvYnJvd3Nlci5qcyIsIi4uL2xpYi9leHBvcnQuanMiLCIuLi90ZW1wbGF0ZXMvc3ZnX2V4cG9ydC9zdmdfZXhwb3J0LmpzIiwiLi4vbGliL3Bvb2wuanMiLCIuLi9saWIvY2hhcnQuanMiLCIuLi9saWIvc2VydmVyL2Vycm9yLmpzIiwiLi4vbGliL3NlcnZlci9yYXRlX2xpbWl0LmpzIiwiLi4vbGliL2Vycm9ycy9IdHRwRXJyb3IuanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy9leHBvcnQuanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy9oZWFsdGguanMiLCIuLi9saWIvc2VydmVyL3NlcnZlci5qcyIsIi4uL2xpYi9zZXJ2ZXIvcm91dGVzL3VpLmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvY2hhbmdlX2hjX3ZlcnNpb24uanMiLCIuLi9saWIvaW5kZXguanMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqXHJcbiAqIFRoaXMgbW9kdWxlIGV4cG9ydHMgdHdvIGZ1bmN0aW9uczogZmV0Y2ggKGZvciBHRVQgcmVxdWVzdHMpIGFuZCBwb3N0IChmb3IgUE9TVCByZXF1ZXN0cykuXHJcbiAqL1xyXG5cclxuaW1wb3J0IGh0dHAgZnJvbSAnaHR0cCc7XHJcbmltcG9ydCBodHRwcyBmcm9tICdodHRwcyc7XHJcblxyXG4vKipcclxuICogUmV0dXJucyB0aGUgSFRUUCBvciBIVFRQUyBwcm90b2NvbCBtb2R1bGUgYmFzZWQgb24gdGhlIHByb3ZpZGVkIFVSTC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHVybCAtIFRoZSBVUkwgdG8gZGV0ZXJtaW5lIHRoZSBwcm90b2NvbC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wgbW9kdWxlIChodHRwIG9yIGh0dHBzKS5cclxuICovXHJcbmNvbnN0IGdldFByb3RvY29sID0gKHVybCkgPT4gKHVybC5zdGFydHNXaXRoKCdodHRwcycpID8gaHR0cHMgOiBodHRwKTtcclxuXHJcbi8qKlxyXG4gKiBGZXRjaGVzIGRhdGEgZnJvbSB0aGUgc3BlY2lmaWVkIFVSTCB1c2luZyBlaXRoZXIgSFRUUCBvciBIVFRQUyBwcm90b2NvbC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHVybCAtIFRoZSBVUkwgdG8gZmV0Y2ggZGF0YSBmcm9tLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcmVxdWVzdE9wdGlvbnMgLSBPcHRpb25zIGZvciB0aGUgSFRUUCByZXF1ZXN0IChvcHRpb25hbCkuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBIVFRQIHJlc3BvbnNlIG9iamVjdFxyXG4gKiB3aXRoIGFkZGVkICd0ZXh0JyBwcm9wZXJ0eSBvciByZWplY3Rpbmcgd2l0aCBhbiBlcnJvci5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIGZldGNoKHVybCwgcmVxdWVzdE9wdGlvbnMgPSB7fSkge1xyXG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XHJcbiAgICBjb25zdCBwcm90b2NvbCA9IGdldFByb3RvY29sKHVybCk7XHJcblxyXG4gICAgcHJvdG9jb2xcclxuICAgICAgLmdldCh1cmwsIHJlcXVlc3RPcHRpb25zLCAocmVzKSA9PiB7XHJcbiAgICAgICAgbGV0IGRhdGEgPSAnJztcclxuXHJcbiAgICAgICAgLy8gQSBjaHVuayBvZiBkYXRhIGhhcyBiZWVuIHJlY2VpdmVkLlxyXG4gICAgICAgIHJlcy5vbignZGF0YScsIChjaHVuaykgPT4ge1xyXG4gICAgICAgICAgZGF0YSArPSBjaHVuaztcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgLy8gVGhlIHdob2xlIHJlc3BvbnNlIGhhcyBiZWVuIHJlY2VpdmVkLlxyXG4gICAgICAgIHJlcy5vbignZW5kJywgKCkgPT4ge1xyXG4gICAgICAgICAgaWYgKCFkYXRhKSB7XHJcbiAgICAgICAgICAgIHJlamVjdCgnTm90aGluZyB3YXMgZmV0Y2hlZCBmcm9tIHRoZSBVUkwuJyk7XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgcmVzLnRleHQgPSBkYXRhO1xyXG4gICAgICAgICAgcmVzb2x2ZShyZXMpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICB9KVxyXG4gICAgICAub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICAgICAgcmVqZWN0KGVycm9yKTtcclxuICAgICAgfSk7XHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZW5kcyBhIFBPU1QgcmVxdWVzdCB0byB0aGUgc3BlY2lmaWVkIFVSTCB3aXRoIHRoZSBwcm92aWRlZCBKU09OIGJvZHkgdXNpbmdcclxuICogZWl0aGVyIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgLSBUaGUgVVJMIHRvIHNlbmQgdGhlIFBPU1QgcmVxdWVzdCB0by5cclxuICogQHBhcmFtIHtPYmplY3R9IGJvZHkgLSBUaGUgSlNPTiBib2R5IHRvIGluY2x1ZGUgaW4gdGhlIFBPU1QgcmVxdWVzdFxyXG4gKiAob3B0aW9uYWwsIGRlZmF1bHQgaXMgYW4gZW1wdHkgb2JqZWN0KS5cclxuICogQHBhcmFtIHtPYmplY3R9IHJlcXVlc3RPcHRpb25zIC0gT3B0aW9ucyBmb3IgdGhlIEhUVFAgcmVxdWVzdCAob3B0aW9uYWwpLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgSFRUUCByZXNwb25zZSBvYmplY3Qgd2l0aFxyXG4gKiBhZGRlZCAndGV4dCcgcHJvcGVydHkgb3IgcmVqZWN0aW5nIHdpdGggYW4gZXJyb3IuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBwb3N0KHVybCwgYm9keSA9IHt9LCByZXF1ZXN0T3B0aW9ucyA9IHt9KSB7XHJcbiAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcclxuICAgIGNvbnN0IHByb3RvY29sID0gZ2V0UHJvdG9jb2wodXJsKTtcclxuICAgIGNvbnN0IGRhdGEgPSBKU09OLnN0cmluZ2lmeShib2R5KTtcclxuXHJcbiAgICAvLyBTZXQgZGVmYXVsdCBoZWFkZXJzIGFuZCBtZXJnZSB3aXRoIHJlcXVlc3RPcHRpb25zXHJcbiAgICBjb25zdCBvcHRpb25zID0gT2JqZWN0LmFzc2lnbihcclxuICAgICAge1xyXG4gICAgICAgIG1ldGhvZDogJ1BPU1QnLFxyXG4gICAgICAgIGhlYWRlcnM6IHtcclxuICAgICAgICAgICdDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbicsXHJcbiAgICAgICAgICAnQ29udGVudC1MZW5ndGgnOiBkYXRhLmxlbmd0aFxyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgcmVxdWVzdE9wdGlvbnNcclxuICAgICk7XHJcblxyXG4gICAgY29uc3QgcmVxID0gcHJvdG9jb2xcclxuICAgICAgLnJlcXVlc3QodXJsLCBvcHRpb25zLCAocmVzKSA9PiB7XHJcbiAgICAgICAgbGV0IHJlc3BvbnNlRGF0YSA9ICcnO1xyXG5cclxuICAgICAgICAvLyBBIGNodW5rIG9mIGRhdGEgaGFzIGJlZW4gcmVjZWl2ZWQuXHJcbiAgICAgICAgcmVzLm9uKCdkYXRhJywgKGNodW5rKSA9PiB7XHJcbiAgICAgICAgICByZXNwb25zZURhdGEgKz0gY2h1bms7XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICAgIC8vIFRoZSB3aG9sZSByZXNwb25zZSBoYXMgYmVlbiByZWNlaXZlZC5cclxuICAgICAgICByZXMub24oJ2VuZCcsICgpID0+IHtcclxuICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgIHJlcy50ZXh0ID0gcmVzcG9uc2VEYXRhO1xyXG4gICAgICAgICAgICByZXNvbHZlKHJlcyk7XHJcbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICByZWplY3QoZXJyb3IpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH0pO1xyXG4gICAgICB9KVxyXG4gICAgICAub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICAgICAgcmVqZWN0KGVycm9yKTtcclxuICAgICAgfSk7XHJcblxyXG4gICAgLy8gV3JpdGUgdGhlIHJlcXVlc3QgYm9keSBhbmQgZW5kIHRoZSByZXF1ZXN0LlxyXG4gICAgcmVxLndyaXRlKGRhdGEpO1xyXG4gICAgcmVxLmVuZCgpO1xyXG4gIH0pO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCBmZXRjaDtcclxuZXhwb3J0IHsgZmV0Y2gsIHBvc3QgfTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vLyBUaGlzIGlzIHRoZSBjb25maWd1cmF0aW9uIG9iamVjdCB3aXRoIGFsbCBvcHRpb25zIGFuZCB0aGVpciBkZWZhdWx0IHZhbHVlcyxcclxuLy8gYWxzbyBmcm9tIHRoZSAuZW52IGZpbGUgaWYgb25lIGV4aXN0c1xyXG5leHBvcnQgY29uc3QgZGVmYXVsdENvbmZpZyA9IHtcclxuICBwdXBwZXRlZXI6IHtcclxuICAgIGFyZ3M6IHtcclxuICAgICAgdmFsdWU6IFtdLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0FyZ3VtZW50cyBhcnJheSB0byBzZW5kIHRvIFB1cHBldGVlci4nXHJcbiAgICB9XHJcbiAgfSxcclxuICBoaWdoY2hhcnRzOiB7XHJcbiAgICB2ZXJzaW9uOiB7XHJcbiAgICAgIHZhbHVlOiAnbGF0ZXN0JyxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfVkVSU0lPTicsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBIaWdoY2hhcnRzIHZlcnNpb24gdG8gYmUgdXNlZC4nXHJcbiAgICB9LFxyXG4gICAgY2RuVVJMOiB7XHJcbiAgICAgIHZhbHVlOiAnaHR0cHM6Ly9jb2RlLmhpZ2hjaGFydHMuY29tLycsXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0NETl9VUkwnLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgQ0ROIFVSTCBmb3IgSGlnaGNoYXJ0cyBzY3JpcHRzIHRvIGJlIHVzZWQuJ1xyXG4gICAgfSxcclxuICAgIGNvcmVTY3JpcHRzOiB7XHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0NPUkVfU0NSSVBUUycsXHJcbiAgICAgIHZhbHVlOiBbJ2hpZ2hjaGFydHMnLCAnaGlnaGNoYXJ0cy1tb3JlJywgJ2hpZ2hjaGFydHMtM2QnXSxcclxuICAgICAgdHlwZTogJ3N0cmluZ1tdJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgY29yZSBIaWdoY2hhcnRzIHNjcmlwdHMgdG8gZmV0Y2guJ1xyXG4gICAgfSxcclxuICAgIG1vZHVsZXM6IHtcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfTU9EVUxFUycsXHJcbiAgICAgIHZhbHVlOiBbXHJcbiAgICAgICAgJ3N0b2NrJyxcclxuICAgICAgICAnbWFwJyxcclxuICAgICAgICAnZ2FudHQnLFxyXG4gICAgICAgICdleHBvcnRpbmcnLFxyXG4gICAgICAgICdleHBvcnQtZGF0YScsXHJcbiAgICAgICAgJ3BhcmFsbGVsLWNvb3JkaW5hdGVzJyxcclxuICAgICAgICAnYWNjZXNzaWJpbGl0eScsXHJcbiAgICAgICAgJ2Fubm90YXRpb25zLWFkdmFuY2VkJyxcclxuICAgICAgICAnYm9vc3QtY2FudmFzJyxcclxuICAgICAgICAnYm9vc3QnLFxyXG4gICAgICAgICdkYXRhJyxcclxuICAgICAgICAnZGF0YS10b29scycsXHJcbiAgICAgICAgJ2RyYWdnYWJsZS1wb2ludHMnLFxyXG4gICAgICAgICdzdGF0aWMtc2NhbGUnLFxyXG4gICAgICAgICdicm9rZW4tYXhpcycsXHJcbiAgICAgICAgJ2hlYXRtYXAnLFxyXG4gICAgICAgICd0aWxlbWFwJyxcclxuICAgICAgICAndGlsZWR3ZWJtYXAnLFxyXG4gICAgICAgICd0aW1lbGluZScsXHJcbiAgICAgICAgJ3RyZWVtYXAnLFxyXG4gICAgICAgICd0cmVlZ3JhcGgnLFxyXG4gICAgICAgICdpdGVtLXNlcmllcycsXHJcbiAgICAgICAgJ2RyaWxsZG93bicsXHJcbiAgICAgICAgJ2hpc3RvZ3JhbS1iZWxsY3VydmUnLFxyXG4gICAgICAgICdidWxsZXQnLFxyXG4gICAgICAgICdmdW5uZWwnLFxyXG4gICAgICAgICdmdW5uZWwzZCcsXHJcbiAgICAgICAgJ2dlb2hlYXRtYXAnLFxyXG4gICAgICAgICdweXJhbWlkM2QnLFxyXG4gICAgICAgICduZXR3b3JrZ3JhcGgnLFxyXG4gICAgICAgICdvdmVybGFwcGluZy1kYXRhbGFiZWxzJyxcclxuICAgICAgICAncGFyZXRvJyxcclxuICAgICAgICAncGF0dGVybi1maWxsJyxcclxuICAgICAgICAncGljdG9yaWFsJyxcclxuICAgICAgICAncHJpY2UtaW5kaWNhdG9yJyxcclxuICAgICAgICAnc2Fua2V5JyxcclxuICAgICAgICAnYXJjLWRpYWdyYW0nLFxyXG4gICAgICAgICdkZXBlbmRlbmN5LXdoZWVsJyxcclxuICAgICAgICAnc2VyaWVzLWxhYmVsJyxcclxuICAgICAgICAnc29saWQtZ2F1Z2UnLFxyXG4gICAgICAgICdzb25pZmljYXRpb24nLFxyXG4gICAgICAgICdzdG9jay10b29scycsXHJcbiAgICAgICAgJ3N0cmVhbWdyYXBoJyxcclxuICAgICAgICAnc3VuYnVyc3QnLFxyXG4gICAgICAgICd2YXJpYWJsZS1waWUnLFxyXG4gICAgICAgICd2YXJpd2lkZScsXHJcbiAgICAgICAgJ3ZlY3RvcicsXHJcbiAgICAgICAgJ3Zlbm4nLFxyXG4gICAgICAgICd3aW5kYmFyYicsXHJcbiAgICAgICAgJ3dvcmRjbG91ZCcsXHJcbiAgICAgICAgJ3hyYW5nZScsXHJcbiAgICAgICAgJ25vLWRhdGEtdG8tZGlzcGxheScsXHJcbiAgICAgICAgJ2RyYWctcGFuZXMnLFxyXG4gICAgICAgICdkZWJ1Z2dlcicsXHJcbiAgICAgICAgJ2R1bWJiZWxsJyxcclxuICAgICAgICAnbG9sbGlwb3AnLFxyXG4gICAgICAgICdjeWxpbmRlcicsXHJcbiAgICAgICAgJ29yZ2FuaXphdGlvbicsXHJcbiAgICAgICAgJ2RvdHBsb3QnLFxyXG4gICAgICAgICdtYXJrZXItY2x1c3RlcnMnLFxyXG4gICAgICAgICdob2xsb3djYW5kbGVzdGljaycsXHJcbiAgICAgICAgJ2hlaWtpbmFzaGknLFxyXG4gICAgICAgICdmbG93bWFwJ1xyXG4gICAgICBdLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBtb2R1bGVzIG9mIEhpZ2hjaGFydHMgdG8gZmV0Y2guJ1xyXG4gICAgfSxcclxuICAgIGluZGljYXRvcnM6IHtcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfSU5ESUNBVE9SUycsXHJcbiAgICAgIHZhbHVlOiBbJ2luZGljYXRvcnMtYWxsJ10sXHJcbiAgICAgIHR5cGU6ICdzdHJpbmdbXScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIGluZGljYXRvcnMgb2YgSGlnaGNoYXJ0cyB0byBmZXRjaC4nXHJcbiAgICB9LFxyXG4gICAgc2NyaXB0czoge1xyXG4gICAgICB2YWx1ZTogW1xyXG4gICAgICAgICdodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9tb21lbnQuanMvMi4yOS40L21vbWVudC5taW4uanMnLFxyXG4gICAgICAgICdodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9tb21lbnQtdGltZXpvbmUvMC41LjM0L21vbWVudC10aW1lem9uZS13aXRoLWRhdGEubWluLmpzJ1xyXG4gICAgICBdLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0FkZGl0aW9uYWwgb3B0aW9uYWwgc2NyaXB0cyBvciBkZXBlbmRlbmNpZXMgdG8gZmV0Y2guJ1xyXG4gICAgfSxcclxuICAgIGZvcmNlRmV0Y2g6IHtcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfRk9SQ0VfRkVUQ0gnLFxyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBmbGFnIHRvIGRldGVybWluZSB3aGV0aGVyIHRvIHJlZmV0Y2ggYWxsIHNjcmlwdHMgYWZ0ZXIgZWFjaCBzZXJ2ZXIgcmVydW4uJ1xyXG4gICAgfSxcclxuICAgIGNhY2hlUGF0aDoge1xyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DQUNIRV9QQVRIJyxcclxuICAgICAgdmFsdWU6ICcuY2FjaGUnLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBwYXRoIHRvIHRoZSBjYWNoZSBkaXJlY3RvcnkuIEl0IGlzIHVzZWQgdG8gc3RvcmUgdGhlIEhpZ2hjaGFydHMgc2NyaXB0cyBhbmQgY3VzdG9tIHNjcmlwdHMuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgZXhwb3J0OiB7XHJcbiAgICBpbmZpbGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBpbnB1dCBmaWxlIHNob3VsZCBpbmNsdWRlIGEgbmFtZSBhbmQgYSB0eXBlIChqc29uIG9yIHN2ZykuIEl0IG11c3QgYmUgY29ycmVjdGx5IGZvcm1hdHRlZCBhcyBhIEpTT04gb3IgU1ZHIGZpbGUuJ1xyXG4gICAgfSxcclxuICAgIGluc3RyOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbnB1dCwgcHJvdmlkZWQgaW4gdGhlIGZvcm0gb2YgYSBzdHJpbmdpZmllZCBKU09OIG9yIFNWRyBmaWxlLCB3aWxsIG92ZXJyaWRlIHRoZSAtLWluZmlsZSBvcHRpb24uJ1xyXG4gICAgfSxcclxuICAgIG9wdGlvbnM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdBbiBhbGlhcyBmb3IgdGhlIC0taW5zdHIgb3B0aW9uLidcclxuICAgIH0sXHJcbiAgICBvdXRmaWxlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgb3V0cHV0IGZpbGVuYW1lIGFsb25nIHdpdGggYSB0eXBlIChqcGVnLCBwbmcsIHBkZiwgb3Igc3ZnKS4gVGhpcyB3aWxsIGlnbm9yZSB0aGUgLS10eXBlIGZsYWcuJ1xyXG4gICAgfSxcclxuICAgIHR5cGU6IHtcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9UWVBFJyxcclxuICAgICAgdmFsdWU6ICdwbmcnLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgZmlsZSBleHBvcnQgZm9ybWF0LiBJdCBjYW4gYmUganBlZywgcG5nLCBwZGYsIG9yIHN2Zy4nXHJcbiAgICB9LFxyXG4gICAgY29uc3RyOiB7XHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfQ09OU1RSJyxcclxuICAgICAgdmFsdWU6ICdjaGFydCcsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGNvbnN0cnVjdG9yIHRvIHVzZS4gQ2FuIGJlIGNoYXJ0LCBzdG9ja0NoYXJ0LCBtYXBDaGFydCwgb3IgZ2FudHRDaGFydC4nXHJcbiAgICB9LFxyXG4gICAgZGVmYXVsdEhlaWdodDoge1xyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0RFRkFVTFRfSEVJR0hUJyxcclxuICAgICAgdmFsdWU6IDQwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICd0aGUgZGVmYXVsdCBoZWlnaHQgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LiBVc2VkIHdoZW4gbm8gdmFsdWUgaXMgc2V0LidcclxuICAgIH0sXHJcbiAgICBkZWZhdWx0V2lkdGg6IHtcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9ERUZBVUxUX1dJRFRIJyxcclxuICAgICAgdmFsdWU6IDYwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZGVmYXVsdCB3aWR0aCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQuIFVzZWQgd2hlbiBubyB2YWx1ZSBpcyBzZXQuJ1xyXG4gICAgfSxcclxuICAgIGRlZmF1bHRTY2FsZToge1xyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0RFRkFVTFRfU0NBTEUnLFxyXG4gICAgICB2YWx1ZTogMSxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZGVmYXVsdCBzY2FsZSBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQuIFVzZWQgd2hlbiBubyB2YWx1ZSBpcyBzZXQuJ1xyXG4gICAgfSxcclxuICAgIGhlaWdodDoge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGhlaWdodCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQsIG92ZXJyaWRpbmcgdGhlIG9wdGlvbiBpbiB0aGUgY2hhcnQgc2V0dGluZ3MuJ1xyXG4gICAgfSxcclxuICAgIHdpZHRoOiB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgd2lkdGggb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LCBvdmVycmlkaW5nIHRoZSBvcHRpb24gaW4gdGhlIGNoYXJ0IHNldHRpbmdzLidcclxuICAgIH0sXHJcbiAgICBzY2FsZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIHNjYWxlIG9mIHRoZSBleHBvcnRlZCBjaGFydCwgb3ZlcnJpZGluZyB0aGUgb3B0aW9uIGluIHRoZSBjaGFydCBzZXR0aW5ncy4gUmFuZ2VzIGJldHdlZW4gMC4xIGFuZCA1LjAuJ1xyXG4gICAgfSxcclxuICAgIGdsb2JhbE9wdGlvbnM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0VpdGhlciBhIHN0cmluZ2lmaWVkIEpTT04gb3IgYSBmaWxlbmFtZSBjb250YWluaW5nIG9wdGlvbnMgdG8gYmUgcGFzc2VkIGludG8gdGhlIEhpZ2hjaGFydHMuc2V0T3B0aW9ucy4nXHJcbiAgICB9LFxyXG4gICAgdGhlbWVPcHRpb25zOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdFaXRoZXIgYSBzdHJpbmdpZmllZCBKU09OIG9yIGEgZmlsZW5hbWUgY29udGFpbmluZyB0aGVtZSBvcHRpb25zIHRvIGJlIHBhc3NlZCBpbnRvIHRoZSBIaWdoY2hhcnRzLnNldE9wdGlvbnMuJ1xyXG4gICAgfSxcclxuICAgIGJhdGNoOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbml0aWF0ZXMgYSBiYXRjaCBqb2Igd2l0aCBhIHN0cmluZyBjb250YWluaW5nIGlucHV0L291dHB1dCBwYWlyczogXCJpbj1vdXQ7aW49b3V0Oy4uLlwiLidcclxuICAgIH0sXHJcbiAgICByYXN0ZXJpemF0aW9uVGltZW91dDoge1xyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX1JBU1RFUklaQVRJT05fVElNRU9VVCcsXHJcbiAgICAgIHZhbHVlOiAxNTAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiBpbiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgcmVuZGVyaW5nIGEgd2VicGFnZS4nXHJcbiAgICB9XHJcbiAgfSxcclxuICBjdXN0b21Mb2dpYzoge1xyXG4gICAgYWxsb3dDb2RlRXhlY3V0aW9uOiB7XHJcbiAgICAgIGVudkxpbms6ICdDVVNUT01fTE9HSUNfQUxMT1dfQ09ERV9FWEVDVVRJT04nLFxyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0NvbnRyb2xzIHdoZXRoZXIgdGhlIGV4ZWN1dGlvbiBvZiBhcmJpdHJhcnkgY29kZSBpcyBhbGxvd2VkIGR1cmluZyB0aGUgZXhwb3J0aW5nIHByb2Nlc3MuJ1xyXG4gICAgfSxcclxuICAgIGFsbG93RmlsZVJlc291cmNlczoge1xyXG4gICAgICBlbnZMaW5rOiAnQ1VTVE9NX0xPR0lDX0FMTE9XX0ZJTEVfUkVTT1VSQ0VTJyxcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdDb250cm9scyB0aGUgYWJpbGl0eSB0byBpbmplY3QgcmVzb3VyY2VzIGZyb20gdGhlIGZpbGVzeXN0ZW0uIFRoaXMgc2V0dGluZyBoYXMgbm8gZWZmZWN0IHdoZW4gcnVubmluZyBhcyBhIHNlcnZlci4nXHJcbiAgICB9LFxyXG4gICAgY3VzdG9tQ29kZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQ3VzdG9tIGNvZGUgdG8gZXhlY3V0ZSBiZWZvcmUgY2hhcnQgaW5pdGlhbGl6YXRpb24uIEl0IGNhbiBiZSBhIGZ1bmN0aW9uLCBjb2RlIHdyYXBwZWQgd2l0aGluIGEgZnVuY3Rpb24sIG9yIGEgZmlsZW5hbWUgd2l0aCB0aGUgLmpzIGV4dGVuc2lvbi4nXHJcbiAgICB9LFxyXG4gICAgY2FsbGJhY2s6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0phdmFTY3JpcHQgY29kZSB0byBydW4gZHVyaW5nIGNvbnN0cnVjdGlvbi4gSXQgY2FuIGJlIGEgZnVuY3Rpb24gb3IgYSBmaWxlbmFtZSB3aXRoIHRoZSAuanMgZXh0ZW5zaW9uLidcclxuICAgIH0sXHJcbiAgICByZXNvdXJjZXM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0FkZGl0aW9uYWwgcmVzb3VyY2UgaW4gdGhlIGZvcm0gb2YgYSBzdHJpbmdpZmllZCBKU09OLCB3aGljaCBtYXkgY29udGFpbiBmaWxlcywganMsIGFuZCBjc3Mgc2VjdGlvbnMuJ1xyXG4gICAgfSxcclxuICAgIGxvYWRDb25maWc6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgbGVnYWN5TmFtZTogJ2Zyb21GaWxlJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdBIGZpbGUgY29udGFpbmluZyBhIHByZS1kZWZpbmVkIGNvbmZpZ3VyYXRpb24gdG8gdXNlLidcclxuICAgIH0sXHJcbiAgICBjcmVhdGVDb25maWc6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0VuYWJsZXMgc2V0dGluZyBvcHRpb25zIHRocm91Z2ggYSBwcm9tcHQgYW5kIHNhdmluZyB0aGVtIGluIGEgcHJvdmlkZWQgY29uZmlnIGZpbGUuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgc2VydmVyOiB7XHJcbiAgICBlbmFibGU6IHtcclxuICAgICAgZW52TGluazogJ1NFUlZFUl9FTkFCTEUnLFxyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgY2xpTmFtZTogJ2VuYWJsZVNlcnZlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdXaGVuIHNldCB0byB0cnVlLCB0aGUgc2VydmVyIHN0YXJ0cyBvbiB0aGUgbG9jYWwgSVAgYWRkcmVzcyAwLjAuMC4wLidcclxuICAgIH0sXHJcbiAgICBob3N0OiB7XHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfSE9TVCcsXHJcbiAgICAgIHZhbHVlOiAnMC4wLjAuMCcsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGhvc3RuYW1lIG9mIHRoZSBzZXJ2ZXIuIEFkZGl0aW9uYWxseSwgaXQgc3RhcnRzIGEgc2VydmVyIG9uIHRoZSBwcm92aWRlZCBob3N0bmFtZS4nXHJcbiAgICB9LFxyXG4gICAgcG9ydDoge1xyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX1BPUlQnLFxyXG4gICAgICB2YWx1ZTogNzgwMSxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHNlcnZlciBwb3J0IHdoZW4gZW5hYmxlZC4nXHJcbiAgICB9LFxyXG4gICAgYmVuY2htYXJraW5nOiB7XHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfQkVOQ0hNQVJLSU5HJyxcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGNsaU5hbWU6ICdzZXJ2ZXJCZW5jaG1hcmtpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSW5kaWNhdGVzIHdoZXRoZXIgdG8gZGlzcGxheSB0aGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgb2Ygc3BlY2lmaWMgYWN0aW9ucyB0aGF0IG9jY3VyIG9uIHRoZSBzZXJ2ZXIgd2hpbGUgc2VydmluZyBhIHJlcXVlc3QuJ1xyXG4gICAgfSxcclxuICAgIHNzbDoge1xyXG4gICAgICBlbmFibGU6IHtcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9FTkFCTEUnLFxyXG4gICAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgICAgY2xpTmFtZTogJ2VuYWJsZVNzbCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIG9yIGRpc2FibGVzIHRoZSBTU0wgcHJvdG9jb2wuJ1xyXG4gICAgICB9LFxyXG4gICAgICBmb3JjZToge1xyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfU1NMX0ZPUkNFJyxcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICAgIGNsaU5hbWU6ICdzc2xGb3JjZWQnLFxyXG4gICAgICAgIGxlZ2FjeU5hbWU6ICdzc2xPbmx5JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAgICdXaGVuIHNldCB0byB0cnVlLCB0aGUgc2VydmVyIGlzIGZvcmNlZCB0byBzZXJ2ZSBvbmx5IG92ZXIgSFRUUFMuJ1xyXG4gICAgICB9LFxyXG4gICAgICBwb3J0OiB7XHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfUE9SVCcsXHJcbiAgICAgICAgdmFsdWU6IDQ0MyxcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgICBjbGlOYW1lOiAnc3NsUG9ydCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgcG9ydCBvbiB3aGljaCB0byBydW4gdGhlIFNTTCBzZXJ2ZXIuJ1xyXG4gICAgICB9LFxyXG4gICAgICBjZXJ0UGF0aDoge1xyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfU1NMX0NFUlRfUEFUSCcsXHJcbiAgICAgICAgdmFsdWU6ICcnLFxyXG4gICAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICAgIGxlZ2FjeU5hbWU6ICdzc2xQYXRoJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSBwYXRoIHRvIHRoZSBTU0wgY2VydGlmaWNhdGUva2V5IGZpbGUuJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgcmF0ZUxpbWl0aW5nOiB7XHJcbiAgICAgIGVuYWJsZToge1xyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19FTkFCTEUnLFxyXG4gICAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgICAgY2xpTmFtZTogJ2VuYWJsZVJhdGVMaW1pdGluZycsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIHJhdGUgbGltaXRpbmcgZm9yIHRoZSBzZXJ2ZXIuJ1xyXG4gICAgICB9LFxyXG4gICAgICBtYXhSZXF1ZXN0czoge1xyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19NQVhfUkVRVUVTVFMnLFxyXG4gICAgICAgIHZhbHVlOiAxMCxcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgICBsZWdhY3lOYW1lOiAncmF0ZUxpbWl0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSBtYXhpbXVtIG51bWJlciBvZiByZXF1ZXN0cyBhbGxvd2VkIGluIG9uZSBtaW51dGUuJ1xyXG4gICAgICB9LFxyXG4gICAgICB3aW5kb3c6IHtcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfV0lORE9XJyxcclxuICAgICAgICB2YWx1ZTogMSxcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSB0aW1lIHdpbmRvdywgaW4gbWludXRlcywgZm9yIHRoZSByYXRlIGxpbWl0aW5nLidcclxuICAgICAgfSxcclxuICAgICAgZGVsYXk6IHtcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfREVMQVknLFxyXG4gICAgICAgIHZhbHVlOiAwLFxyXG4gICAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICAgJ1RoZSBkZWxheSBkdXJhdGlvbiBmb3IgZWFjaCBzdWNjZXNzaXZlIHJlcXVlc3QgYmVmb3JlIHJlYWNoaW5nIHRoZSBtYXhpbXVtIGxpbWl0LidcclxuICAgICAgfSxcclxuICAgICAgdHJ1c3RQcm94eToge1xyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19UUlVTVF9QUk9YWScsXHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1NldCB0aGlzIHRvIHRydWUgaWYgdGhlIHNlcnZlciBpcyBiZWhpbmQgYSBsb2FkIGJhbGFuY2VyLidcclxuICAgICAgfSxcclxuICAgICAgc2tpcEtleToge1xyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX0tFWScsXHJcbiAgICAgICAgdmFsdWU6ICcnLFxyXG4gICAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICAgJ0FsbG93cyBieXBhc3NpbmcgdGhlIHJhdGUgbGltaXRlciBhbmQgc2hvdWxkIGJlIHByb3ZpZGVkIHdpdGggdGhlIHNraXBUb2tlbiBhcmd1bWVudC4nXHJcbiAgICAgIH0sXHJcbiAgICAgIHNraXBUb2tlbjoge1xyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX1RPS0VOJyxcclxuICAgICAgICB2YWx1ZTogJycsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgICAnQWxsb3dzIGJ5cGFzc2luZyB0aGUgcmF0ZSBsaW1pdGVyIGFuZCBzaG91bGQgYmUgcHJvdmlkZWQgd2l0aCB0aGUgc2tpcEtleSBhcmd1bWVudC4nXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIHBvb2w6IHtcclxuICAgIG1pbldvcmtlcnM6IHtcclxuICAgICAgZW52TGluazogJ1BPT0xfTUlOX1dPUktFUlMnLFxyXG4gICAgICB2YWx1ZTogNCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIG51bWJlciBvZiBtaW5pbXVtIGFuZCBpbml0aWFsIHBvb2wgd29ya2VycyB0byBzcGF3bi4nXHJcbiAgICB9LFxyXG4gICAgbWF4V29ya2Vyczoge1xyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9NQVhfV09SS0VSUycsXHJcbiAgICAgIHZhbHVlOiA4LFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbGVnYWN5TmFtZTogJ3dvcmtlcnMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBudW1iZXIgb2YgbWF4aW11bSBwb29sIHdvcmtlcnMgdG8gc3Bhd24uJ1xyXG4gICAgfSxcclxuICAgIHdvcmtMaW1pdDoge1xyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9XT1JLX0xJTUlUJyxcclxuICAgICAgdmFsdWU6IDQwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBudW1iZXIgb2Ygd29yayBwaWVjZXMgdGhhdCBjYW4gYmUgcGVyZm9ybWVkIGJlZm9yZSByZXN0YXJ0aW5nIHRoZSB3b3JrZXIgcHJvY2Vzcy4nXHJcbiAgICB9LFxyXG4gICAgYWNxdWlyZVRpbWVvdXQ6IHtcclxuICAgICAgZW52TGluazogJ1BPT0xfQUNRVUlSRV9USU1FT1VUJyxcclxuICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGR1cmF0aW9uLCBpbiBtaWxsaXNlY29uZHMsIHRvIHdhaXQgZm9yIGFjcXVpcmluZyBhIHJlc291cmNlLidcclxuICAgIH0sXHJcbiAgICBjcmVhdGVUaW1lb3V0OiB7XHJcbiAgICAgIGVudkxpbms6ICdQT09MX0NSRUFURV9USU1FT1VUJyxcclxuICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGR1cmF0aW9uLCBpbiBtaWxsaXNlY29uZHMsIHRvIHdhaXQgZm9yIGNyZWF0aW5nIGEgcmVzb3VyY2UuJ1xyXG4gICAgfSxcclxuICAgIGRlc3Ryb3lUaW1lb3V0OiB7XHJcbiAgICAgIGVudkxpbms6ICdQT09MX0RFU1RST1lfVElNRU9VVCcsXHJcbiAgICAgIHZhbHVlOiA1MDAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCB0byB3YWl0IGZvciBkZXN0cm95aW5nIGEgcmVzb3VyY2UuJ1xyXG4gICAgfSxcclxuICAgIGlkbGVUaW1lb3V0OiB7XHJcbiAgICAgIGVudkxpbms6ICdQT09MX0lETEVfVElNRU9VVCcsXHJcbiAgICAgIHZhbHVlOiAzMDAwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgYWZ0ZXIgd2hpY2ggYW4gaWRsZSByZXNvdXJjZSBpcyBkZXN0cm95ZWQuJ1xyXG4gICAgfSxcclxuICAgIGNyZWF0ZVJldHJ5SW50ZXJ2YWw6IHtcclxuICAgICAgZW52TGluazogJ1BPT0xfQ1JFQVRFX1JFVFJZX0lOVEVSVkFMJyxcclxuICAgICAgdmFsdWU6IDIwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgdG8gd2FpdCBiZWZvcmUgcmV0cnlpbmcgdGhlIGNyZWF0ZSBwcm9jZXNzIGluIGNhc2Ugb2YgYSBmYWlsdXJlLidcclxuICAgIH0sXHJcbiAgICByZWFwZXJJbnRlcnZhbDoge1xyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9SRUFQRVJfSU5URVJWQUwnLFxyXG4gICAgICB2YWx1ZTogMTAwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgYWZ0ZXIgd2hpY2ggdGhlIGNoZWNrIGZvciBpZGxlIHJlc291cmNlcyB0byBkZXN0cm95IGlzIHRyaWdnZXJlZC4nXHJcbiAgICB9LFxyXG4gICAgYmVuY2htYXJraW5nOiB7XHJcbiAgICAgIGVudkxpbms6ICdQT09MX0JFTkNITUFSS0lORycsXHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBjbGlOYW1lOiAncG9vbEJlbmNobWFya2luZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbmRpY2F0ZSB3aGV0aGVyIHRvIHNob3cgc3RhdGlzdGljcyBmb3IgdGhlIHBvb2wgb2YgcmVzb3VyY2VzIG9yIG5vdC4nXHJcbiAgICB9LFxyXG4gICAgbGlzdGVuVG9Qcm9jZXNzRXhpdHM6IHtcclxuICAgICAgZW52TGluazogJ1BPT0xfTElTVEVOX1RPX1BST0NFU1NfRVhJVFMnLFxyXG4gICAgICB2YWx1ZTogdHJ1ZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0RlY2lkZXMgd2hldGhlciBvciBub3QgdG8gYXR0YWNoIHByb2Nlc3MuZXhpdCBoYW5kbGVycy4nXHJcbiAgICB9XHJcbiAgfSxcclxuICBsb2dnaW5nOiB7XHJcbiAgICBsZXZlbDoge1xyXG4gICAgICBlbnZMaW5rOiAnTE9HR0lOR19MRVZFTCcsXHJcbiAgICAgIHZhbHVlOiA0LFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgY2xpTmFtZTogJ2xvZ0xldmVsJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgbG9nZ2luZyBsZXZlbCB0byBiZSB1c2VkLidcclxuICAgIH0sXHJcbiAgICBmaWxlOiB7XHJcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX0ZJTEUnLFxyXG4gICAgICB2YWx1ZTogJ2hpZ2hjaGFydHMtZXhwb3J0LXNlcnZlci5sb2cnLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgY2xpTmFtZTogJ2xvZ0ZpbGUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIG5hbWUgb2YgYSBsb2cgZmlsZS4gVGhlIGxvZ0Rlc3Qgb3B0aW9uIGFsc28gbmVlZHMgdG8gYmUgc2V0IHRvIGVuYWJsZSBmaWxlIGxvZ2dpbmcuJ1xyXG4gICAgfSxcclxuICAgIGRlc3Q6IHtcclxuICAgICAgZW52TGluazogJ0xPR0dJTkdfREVTVCcsXHJcbiAgICAgIHZhbHVlOiAnbG9nLycsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBjbGlOYW1lOiAnbG9nRGVzdCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgcGF0aCB0byBzdG9yZSBsb2cgZmlsZXMuIFRoaXMgYWxzbyBlbmFibGVzIGZpbGUgbG9nZ2luZy4nXHJcbiAgICB9XHJcbiAgfSxcclxuICB1aToge1xyXG4gICAgZW5hYmxlOiB7XHJcbiAgICAgIGVudkxpbms6ICdVSV9FTkFCTEUnLFxyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgY2xpTmFtZTogJ2VuYWJsZVVpJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0VuYWJsZXMgb3IgZGlzYWJsZXMgdGhlIHVzZXIgaW50ZXJmYWNlIChVSSkgZm9yIHRoZSBleHBvcnQgc2VydmVyLidcclxuICAgIH0sXHJcbiAgICByb3V0ZToge1xyXG4gICAgICBlbnZMaW5rOiAnVUlfUk9VVEUnLFxyXG4gICAgICB2YWx1ZTogJy8nLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgY2xpTmFtZTogJ3VpUm91dGUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGVuZHBvaW50IHJvdXRlIHRvIHdoaWNoIHRoZSB1c2VyIGludGVyZmFjZSAoVUkpIHNob3VsZCBiZSBhdHRhY2hlZC4nXHJcbiAgICB9XHJcbiAgfSxcclxuICBvdGhlcjoge1xyXG4gICAgbm9Mb2dvOiB7XHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9OT19MT0dPJyxcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdTa2lwIHByaW50aW5nIHRoZSBsb2dvIG9uIGEgc3RhcnR1cC4gV2lsbCBiZSByZXBsYWNlZCBieSBhIHNpbXBsZSB0ZXh0LidcclxuICAgIH1cclxuICB9XHJcbn07XHJcblxyXG4vLyBUaGUgY29uZmlnIGRlc2NyaXB0aW9ucyBvYmplY3QgZm9yIHRoZSBwcm9tcHRzIGZ1bmN0aW9uYWxpdHkuIEl0IGNvbnRhaW5zXHJcbi8vIGluZm9ybWF0aW9uIGxpa2U6XHJcbi8vICogVHlwZSBvZiBhIHByb21wdFxyXG4vLyAqIE5hbWUgb2YgYW4gb3B0aW9uXHJcbi8vICogU2hvcnQgZGVzY3JpcHRpb24gb2YgYSBjaG9zZW4gb3B0aW9uXHJcbi8vICogSW5pdGlhbCB2YWx1ZVxyXG5leHBvcnQgY29uc3QgcHJvbXB0c0NvbmZpZyA9IHtcclxuICBwdXBwZXRlZXI6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ2xpc3QnLFxyXG4gICAgICBuYW1lOiAnYXJncycsXHJcbiAgICAgIG1lc3NhZ2U6ICdQdXBwZXRlZXIgYXJndW1lbnRzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wdXBwZXRlZXIuYXJncy52YWx1ZS5qb2luKCcsJyksXHJcbiAgICAgIHNlcGFyYXRvcjogJywnXHJcbiAgICB9XHJcbiAgXSxcclxuICBoaWdoY2hhcnRzOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ3ZlcnNpb24nLFxyXG4gICAgICBtZXNzYWdlOiAnSGlnaGNoYXJ0cyB2ZXJzaW9uJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLnZlcnNpb24udmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ2NkblVSTCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgVVJMIG9mIENETicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5jZG5VUkwudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdtdWx0aXNlbGVjdCcsXHJcbiAgICAgIG5hbWU6ICdtb2R1bGVzJyxcclxuICAgICAgbWVzc2FnZTogJ0F2YWlsYWJsZSBtb2R1bGVzJyxcclxuICAgICAgaW5zdHJ1Y3Rpb25zOiAnU3BhY2U6IFNlbGVjdCBzcGVjaWZpYywgQTogU2VsZWN0IGFsbCwgRW50ZXI6IENvbmZpcm0uJyxcclxuICAgICAgY2hvaWNlczogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLm1vZHVsZXMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdsaXN0JyxcclxuICAgICAgbmFtZTogJ3NjcmlwdHMnLFxyXG4gICAgICBtZXNzYWdlOiAnQ3VzdG9tIHNjcmlwdHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuc2NyaXB0cy52YWx1ZS5qb2luKCcsJyksXHJcbiAgICAgIHNlcGFyYXRvcjogJywnXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2ZvcmNlRmV0Y2gnLFxyXG4gICAgICBtZXNzYWdlOiAnRm9yY2UgcmUtZmV0Y2ggdGhlIHNjcmlwdHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuZm9yY2VGZXRjaC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnY2FjaGVQYXRoJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBwYXRoIHRvIHRoZSBjYWNoZSBkaXJlY3RvcnknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuY2FjaGVQYXRoLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBleHBvcnQ6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3NlbGVjdCcsXHJcbiAgICAgIG5hbWU6ICd0eXBlJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBkZWZhdWx0IGV4cG9ydCBmaWxlIHR5cGUnLFxyXG4gICAgICBoaW50OiBgRGVmYXVsdDogJHtkZWZhdWx0Q29uZmlnLmV4cG9ydC50eXBlLnZhbHVlfWAsXHJcbiAgICAgIGluaXRpYWw6IDAsXHJcbiAgICAgIGNob2ljZXM6IFsncG5nJywgJ2pwZWcnLCAncGRmJywgJ3N2ZyddXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnc2VsZWN0JyxcclxuICAgICAgbmFtZTogJ2NvbnN0cicsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgZGVmYXVsdCBjb25zdHJ1Y3RvciBmb3IgSGlnaGNoYXJ0cycsXHJcbiAgICAgIGhpbnQ6IGBEZWZhdWx0OiAke2RlZmF1bHRDb25maWcuZXhwb3J0LmNvbnN0ci52YWx1ZX1gLFxyXG4gICAgICBpbml0aWFsOiAwLFxyXG4gICAgICBjaG9pY2VzOiBbJ2NoYXJ0JywgJ3N0b2NrQ2hhcnQnLCAnbWFwQ2hhcnQnLCAnZ2FudHRDaGFydCddXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2RlZmF1bHRIZWlnaHQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgZmFsbGJhY2sgaGVpZ2h0IG9mIHRoZSBleHBvcnRlZCBjaGFydCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LmRlZmF1bHRIZWlnaHQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnZGVmYXVsdFdpZHRoJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBkZWZhdWx0IGZhbGxiYWNrIHdpZHRoIG9mIHRoZSBleHBvcnRlZCBjaGFydCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LmRlZmF1bHRXaWR0aC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdkZWZhdWx0U2NhbGUnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgZmFsbGJhY2sgc2NhbGUgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5leHBvcnQuZGVmYXVsdFNjYWxlLnZhbHVlLFxyXG4gICAgICBtaW46IDAuMSxcclxuICAgICAgbWF4OiA1XHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3Jhc3Rlcml6YXRpb25UaW1lb3V0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSByZW5kZXJpbmcgd2VicGFnZSB0aW1lb3V0IGluIG1pbGxpc2Vjb25kcycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LnJhc3Rlcml6YXRpb25UaW1lb3V0LnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBjdXN0b21Mb2dpYzogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2FsbG93Q29kZUV4ZWN1dGlvbicsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgZXhlY3V0aW9uIG9mIGN1c3RvbSBjb2RlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5jdXN0b21Mb2dpYy5hbGxvd0NvZGVFeGVjdXRpb24udmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnYWxsb3dGaWxlUmVzb3VyY2VzJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBmaWxlIHJlc291cmNlcycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuY3VzdG9tTG9naWMuYWxsb3dGaWxlUmVzb3VyY2VzLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBzZXJ2ZXI6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdlbmFibGUnLFxyXG4gICAgICBtZXNzYWdlOiAnU3RhcnRzIHRoZSBzZXJ2ZXIgb24gMC4wLjAuMCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLmVuYWJsZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnaG9zdCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdTZXJ2ZXIgaG9zdG5hbWUnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5ob3N0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3BvcnQnLFxyXG4gICAgICBtZXNzYWdlOiAnU2VydmVyIHBvcnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5wb3J0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2JlbmNobWFya2luZycsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgc2VydmVyIGJlbmNobWFya2luZycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLmJlbmNobWFya2luZy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdzc2wuZW5hYmxlJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBTU0wgcHJvdG9jb2wnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wuZW5hYmxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ3NzbC5mb3JjZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdGb3JjZSBzZXJ2aW5nIG9ubHkgb3ZlciBIVFRQUycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnNzbC5mb3JjZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdzc2wucG9ydCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdTU0wgc2VydmVyIHBvcnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wucG9ydC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnc3NsLmNlcnRQYXRoJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBwYXRoIHRvIGZpbmQgdGhlIFNTTCBjZXJ0aWZpY2F0ZS9rZXknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wuY2VydFBhdGgudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLmVuYWJsZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgcmF0ZSBsaW1pdGluZycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy5lbmFibGUudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLm1heFJlcXVlc3RzJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBtYXhpbXVtIHJlcXVlc3RzIGFsbG93ZWQgcGVyIG1pbnV0ZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy5tYXhSZXF1ZXN0cy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcud2luZG93JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSByYXRlLWxpbWl0aW5nIHRpbWUgd2luZG93IGluIG1pbnV0ZXMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcud2luZG93LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5kZWxheScsXHJcbiAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgJ1RoZSBkZWxheSBmb3IgZWFjaCBzdWNjZXNzaXZlIHJlcXVlc3QgYmVmb3JlIHJlYWNoaW5nIHRoZSBtYXhpbXVtJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLmRlbGF5LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy50cnVzdFByb3h5JyxcclxuICAgICAgbWVzc2FnZTogJ1NldCB0byB0cnVlIGlmIGJlaGluZCBhIGxvYWQgYmFsYW5jZXInLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcudHJ1c3RQcm94eS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLnNraXBLZXknLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdBbGxvd3MgYnlwYXNzaW5nIHRoZSByYXRlIGxpbWl0ZXIgd2hlbiBwcm92aWRlZCB3aXRoIHRoZSBza2lwVG9rZW4gYXJndW1lbnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcuc2tpcEtleS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLnNraXBUb2tlbicsXHJcbiAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgJ0FsbG93cyBieXBhc3NpbmcgdGhlIHJhdGUgbGltaXRlciB3aGVuIHByb3ZpZGVkIHdpdGggdGhlIHNraXBLZXkgYXJndW1lbnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcuc2tpcFRva2VuLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBwb29sOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnbWluV29ya2VycycsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgaW5pdGlhbCBudW1iZXIgb2Ygd29ya2VycyB0byBzcGF3bicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5taW5Xb3JrZXJzLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ21heFdvcmtlcnMnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIG1heGltdW0gbnVtYmVyIG9mIHdvcmtlcnMgdG8gc3Bhd24nLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wubWF4V29ya2Vycy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICd3b3JrTGltaXQnLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdUaGUgcGllY2VzIG9mIHdvcmsgdGhhdCBjYW4gYmUgcGVyZm9ybWVkIGJlZm9yZSByZXN0YXJ0aW5nIGEgUHVwcGV0ZWVyIHByb2Nlc3MnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wud29ya0xpbWl0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2FjcXVpcmVUaW1lb3V0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIHRvIHdhaXQgZm9yIGFjcXVpcmluZyBhIHJlc291cmNlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmFjcXVpcmVUaW1lb3V0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2NyZWF0ZVRpbWVvdXQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgY3JlYXRpbmcgYSByZXNvdXJjZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5jcmVhdGVUaW1lb3V0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2Rlc3Ryb3lUaW1lb3V0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIHRvIHdhaXQgZm9yIGRlc3Ryb3lpbmcgYSByZXNvdXJjZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5kZXN0cm95VGltZW91dC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdpZGxlVGltZW91dCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcyBhZnRlciBhbiBpZGxlIHJlc291cmNlIGlzIGRlc3Ryb3llZCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5pZGxlVGltZW91dC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdjcmVhdGVSZXRyeUludGVydmFsJyxcclxuICAgICAgbWVzc2FnZTpcclxuICAgICAgICAnVGhlIHJldHJ5IGludGVydmFsIGluIG1pbGxpc2Vjb25kcyBhZnRlciBhIGNyZWF0ZSBwcm9jZXNzIGZhaWxzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmNyZWF0ZVJldHJ5SW50ZXJ2YWwudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncmVhcGVySW50ZXJ2YWwnLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdUaGUgcmVhcGVyIGludGVydmFsIGluIG1pbGxpc2Vjb25kcyBhZnRlciB0cmlnZ2VyaW5nIHRoZSBjaGVjayBmb3IgaWRsZSByZXNvdXJjZXMgdG8gZGVzdHJveScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5yZWFwZXJJbnRlcnZhbC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdiZW5jaG1hcmtpbmcnLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIGJlbmNobWFya2luZyBmb3IgYSByZXNvdXJjZSBwb29sJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmJlbmNobWFya2luZy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdsaXN0ZW5Ub1Byb2Nlc3NFeGl0cycsXHJcbiAgICAgIG1lc3NhZ2U6ICdTZXQgdG8gZmFsc2UgdG8gc2tpcCBhdHRhY2hpbmcgcHJvY2Vzcy5leGl0IGhhbmRsZXJzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmxpc3RlblRvUHJvY2Vzc0V4aXRzLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBsb2dnaW5nOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnbGV2ZWwnLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdUaGUgbG9nIGxldmVsICgwOiBzaWxlbnQsIDE6IGVycm9yLCAyOiB3YXJuaW5nLCAzOiBub3RpY2UsIDQ6IHZlcmJvc2UsIDU6IGJlbmNobWFyayknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmxvZ2dpbmcubGV2ZWwudmFsdWUsXHJcbiAgICAgIHJvdW5kOiAwLFxyXG4gICAgICBtaW46IDAsXHJcbiAgICAgIG1heDogNVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnZmlsZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdBIGxvZyBmaWxlIG5hbWUuIFNldCB3aXRoIHRoZSAtLWxvZ0Rlc3QgdG8gZW5hYmxlIGZpbGUgbG9nZ2luZycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcubG9nZ2luZy5maWxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdkZXN0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBwYXRoIHRvIGxvZyBmaWxlcy4gRW5hYmxlcyBmaWxlIGxvZ2dpbmcnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmxvZ2dpbmcuZGVzdC52YWx1ZVxyXG4gICAgfVxyXG4gIF0sXHJcbiAgdWk6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdlbmFibGUnLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIFVJIGZvciB0aGUgZXhwb3J0IHNlcnZlcicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcudWkuZW5hYmxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdyb3V0ZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdBIHJvdXRlIHRvIGF0dGFjaCB0aGUgVUknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnVpLnJvdXRlLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBvdGhlcjogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ25vTG9nbycsXHJcbiAgICAgIG1lc3NhZ2U6ICdTa2lwIHByaW50aW5nIHRoZSBsb2dvIG9uIHN0YXJ0dXAuIFJlcGxhY2VkIGJ5IHNpbXBsZSB0ZXh0JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5vdGhlci5ub0xvZ28udmFsdWVcclxuICAgIH1cclxuICBdXHJcbn07XHJcblxyXG4vLyBBYnNvbHV0ZSBwcm9wcyB0aGF0LCBpbiBjYXNlIG9mIG1lcmdpbmcgcmVjdXJzaXZlbHksIG5lZWQgdG8gYmUgZm9yY2UgbWVyZ2VkXHJcbmV4cG9ydCBjb25zdCBhYnNvbHV0ZVByb3BzID0gW1xyXG4gICdvcHRpb25zJyxcclxuICAnZ2xvYmFsT3B0aW9ucycsXHJcbiAgJ3RoZW1lT3B0aW9ucycsXHJcbiAgJ3Jlc291cmNlcycsXHJcbiAgJ3BheWxvYWQnXHJcbl07XHJcblxyXG4vLyBBcmd1bWVudCBuZXN0aW5nIGxldmVsIG9mIGFsbCBleHBvcnQgc2VydmVyIG9wdGlvbnNcclxuZXhwb3J0IGNvbnN0IG5lc3RlZEFyZ3MgPSB7fTtcclxuXHJcbi8qKlxyXG4gKiBSZWN1cnNpdmVseSBjcmVhdGVzIGEgY2hhaW4gb2YgbmVzdGVkIGFyZ3VtZW50cyBmcm9tIGFuIG9iamVjdC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9iaiAtIFRoZSBvYmplY3QgY29udGFpbmluZyBuZXN0ZWQgYXJndW1lbnRzLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcHJvcENoYWluIC0gVGhlIGN1cnJlbnQgY2hhaW4gb2YgbmVzdGVkIHByb3BlcnRpZXNcclxuICogKHVzZWQgaW50ZXJuYWxseSBkdXJpbmcgcmVjdXJzaW9uKS5cclxuICovXHJcbmNvbnN0IGNyZWF0ZU5lc3RlZEFyZ3MgPSAob2JqLCBwcm9wQ2hhaW4gPSAnJykgPT4ge1xyXG4gIE9iamVjdC5rZXlzKG9iaikuZm9yRWFjaCgoaykgPT4ge1xyXG4gICAgaWYgKCFbJ3B1cHBldGVlcicsICdoaWdoY2hhcnRzJ10uaW5jbHVkZXMoaykpIHtcclxuICAgICAgY29uc3QgZW50cnkgPSBvYmpba107XHJcbiAgICAgIGlmICh0eXBlb2YgZW50cnkudmFsdWUgPT09ICd1bmRlZmluZWQnKSB7XHJcbiAgICAgICAgLy8gR28gZGVlcGVyIGluIHRoZSBuZXN0ZWQgYXJndW1lbnRzXHJcbiAgICAgICAgY3JlYXRlTmVzdGVkQXJncyhlbnRyeSwgYCR7cHJvcENoYWlufS4ke2t9YCk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgLy8gQ3JlYXRlIHRoZSBjaGFpbiBvZiBuZXN0ZWQgYXJndW1lbnRzXHJcbiAgICAgICAgbmVzdGVkQXJnc1tlbnRyeS5jbGlOYW1lIHx8IGtdID0gYCR7cHJvcENoYWlufS4ke2t9YC5zdWJzdHJpbmcoMSk7XHJcblxyXG4gICAgICAgIC8vIFN1cHBvcnQgZm9yIHRoZSBsZWdhY3ksIFBoYW50b21KUyBwcm9wZXJ0aWVzIG5hbWVzXHJcbiAgICAgICAgaWYgKGVudHJ5LmxlZ2FjeU5hbWUgIT09IHVuZGVmaW5lZCkge1xyXG4gICAgICAgICAgbmVzdGVkQXJnc1tlbnRyeS5sZWdhY3lOYW1lXSA9IGAke3Byb3BDaGFpbn0uJHtrfWAuc3Vic3RyaW5nKDEpO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0pO1xyXG59O1xyXG5cclxuY3JlYXRlTmVzdGVkQXJncyhkZWZhdWx0Q29uZmlnKTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyBhcHBlbmRGaWxlLCBleGlzdHNTeW5jLCBta2RpclN5bmMgfSBmcm9tICdmcyc7XHJcblxyXG5pbXBvcnQgeyBkZWZhdWx0Q29uZmlnIH0gZnJvbSAnLi9zY2hlbWFzL2NvbmZpZy5qcyc7XHJcblxyXG4vLyBUaGUgYXZhaWxhYmxlIGNvbG9yc1xyXG5jb25zdCBjb2xvcnMgPSBbJ3JlZCcsICd5ZWxsb3cnLCAnYmx1ZScsICdncmF5JywgJ2dyZWVuJ107XHJcblxyXG4vLyBUaGUgZGVmYXVsdCBsb2dnaW5nIGNvbmZpZ1xyXG5sZXQgbG9nZ2luZyA9IHtcclxuICAvLyBGbGFncyBmb3IgbG9nZ2luZyBzdGF0dXNcclxuICB0b0NvbnNvbGU6IHRydWUsXHJcbiAgdG9GaWxlOiBmYWxzZSxcclxuICBwYXRoQ3JlYXRlZDogZmFsc2UsXHJcbiAgLy8gTG9nIGxldmVsc1xyXG4gIGxldmVsc0Rlc2M6IFtcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICdlcnJvcicsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbMF1cclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHRpdGxlOiAnd2FybmluZycsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbMV1cclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHRpdGxlOiAnbm90aWNlJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1syXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICd2ZXJib3NlJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1szXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICdiZW5jaG1hcmsnLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzRdXHJcbiAgICB9XHJcbiAgXSxcclxuICAvLyBMb2cgbGlzdGVuZXJzXHJcbiAgbGlzdGVuZXJzOiBbXVxyXG59O1xyXG5cclxuLy8gR2F0aGVyIGluaXQgbG9nZ2luZyBvcHRpb25zXHJcbmZvciAoY29uc3QgW2tleSwgb3B0aW9uXSBvZiBPYmplY3QuZW50cmllcyhkZWZhdWx0Q29uZmlnLmxvZ2dpbmcpKSB7XHJcbiAgbG9nZ2luZ1trZXldID0gb3B0aW9uLnZhbHVlO1xyXG59XHJcblxyXG4vKipcclxuICogTG9ncyB0aGUgcHJvdmlkZWQgdGV4dHMgdG8gYSBmaWxlLCBpZiBmaWxlIGxvZ2dpbmcgaXMgZW5hYmxlZC4gSXQgY3JlYXRlc1xyXG4gKiB0aGUgbmVjZXNzYXJ5IGRpcmVjdG9yeSBzdHJ1Y3R1cmUgaWYgbm90IGFscmVhZHkgY3JlYXRlZCBhbmQgYXBwZW5kcyB0aGVcclxuICogY29udGVudCwgaW5jbHVkaW5nIGFuIG9wdGlvbmFsIHByZWZpeCwgdG8gdGhlIHNwZWNpZmllZCBsb2cgZmlsZS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmdbXX0gdGV4dHMgLSBBbiBhcnJheSBvZiB0ZXh0cyB0byBiZSBsb2dnZWQuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwcmVmaXggLSBBbiBvcHRpb25hbCBwcmVmaXggdG8gYmUgYWRkZWQgdG8gZWFjaCBsb2cgZW50cnkuXHJcbiAqL1xyXG5jb25zdCBsb2dUb0ZpbGUgPSAodGV4dHMsIHByZWZpeCkgPT4ge1xyXG4gIGlmIChsb2dnaW5nLnRvRmlsZSkge1xyXG4gICAgaWYgKCFsb2dnaW5nLnBhdGhDcmVhdGVkKSB7XHJcbiAgICAgIC8vIENyZWF0ZSBpZiBkb2VzIG5vdCBleGlzdFxyXG4gICAgICAhZXhpc3RzU3luYyhsb2dnaW5nLmRlc3QpICYmIG1rZGlyU3luYyhsb2dnaW5nLmRlc3QpO1xyXG5cclxuICAgICAgLy8gV2Ugbm93IGFzc3VtZSB0aGUgcGF0aCBpcyBhdmFpbGFibGUsIGUuZy4gaXQncyB0aGUgcmVzcG9uc2liaWxpdHlcclxuICAgICAgLy8gb2YgdGhlIHVzZXIgdG8gY3JlYXRlIHRoZSBwYXRoIHdpdGggdGhlIGNvcnJlY3QgYWNjZXNzIHJpZ2h0cy5cclxuICAgICAgbG9nZ2luZy5wYXRoQ3JlYXRlZCA9IHRydWU7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQWRkIHRoZSBjb250ZW50IHRvIGEgZmlsZVxyXG4gICAgYXBwZW5kRmlsZShcclxuICAgICAgYCR7bG9nZ2luZy5kZXN0fSR7bG9nZ2luZy5maWxlfWAsXHJcbiAgICAgIFtwcmVmaXhdLmNvbmNhdCh0ZXh0cykuam9pbignICcpICsgJ1xcbicsXHJcbiAgICAgIChlcnJvcikgPT4ge1xyXG4gICAgICAgIGlmIChlcnJvcikge1xyXG4gICAgICAgICAgY29uc29sZS5sb2coYFtsb2dnZXJdIFVuYWJsZSB0byB3cml0ZSB0byBsb2cgZmlsZTogJHtlcnJvcn1gKTtcclxuICAgICAgICAgIGxvZ2dpbmcudG9GaWxlID0gZmFsc2U7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICApO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBMb2dzIGEgbWVzc2FnZS4gQWNjZXB0cyBhIHZhcmlhYmxlIGFtb3VudCBvZiBhcmd1bWVudHMuIEFyZ3VtZW50cyBhZnRlclxyXG4gKiBgbGV2ZWxgIHdpbGwgYmUgcGFzc2VkIGRpcmVjdGx5IHRvIGNvbnNvbGUubG9nLCBhbmQvb3Igd2lsbCBiZSBqb2luZWRcclxuICogYW5kIGFwcGVuZGVkIHRvIHRoZSBsb2cgZmlsZS5cclxuICpcclxuICogQHBhcmFtIHthbnl9IGFyZ3MgLSBBbiBhcnJheSBvZiBhcmd1bWVudHMgd2hlcmUgdGhlIGZpcnN0IGlzIHRoZSBsb2cgbGV2ZWxcclxuICogYW5kIHRoZSByZXN0IGFyZSBzdHJpbmdzIHRvIGJ1aWxkIGEgbWVzc2FnZSB3aXRoLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGxvZyA9ICguLi5hcmdzKSA9PiB7XHJcbiAgY29uc3QgW25ld0xldmVsLCAuLi50ZXh0c10gPSBhcmdzO1xyXG5cclxuICAvLyBDdXJyZW50IGxvZ2dpbmcgb3B0aW9uc1xyXG4gIGNvbnN0IHsgbGV2ZWwsIGxldmVsc0Rlc2MgfSA9IGxvZ2dpbmc7XHJcblxyXG4gIC8vIENoZWNrIGlmIGxvZyBsZXZlbCBpcyB3aXRoaW4gYSBjb3JyZWN0IHJhbmdlIG9yIGlzIGEgYmVuY2htYXJrIGxvZ1xyXG4gIGlmIChcclxuICAgIG5ld0xldmVsICE9PSA1ICYmXHJcbiAgICAobmV3TGV2ZWwgPT09IDAgfHwgbmV3TGV2ZWwgPiBsZXZlbCB8fCBsZXZlbCA+IGxldmVsc0Rlc2MubGVuZ3RoKVxyXG4gICkge1xyXG4gICAgcmV0dXJuO1xyXG4gIH1cclxuXHJcbiAgLy8gR2V0IHJpZCBvZiB0aGUgR01UIHRleHQgaW5mb3JtYXRpb25cclxuICBjb25zdCBuZXdEYXRlID0gbmV3IERhdGUoKS50b1N0cmluZygpLnNwbGl0KCcoJylbMF0udHJpbSgpO1xyXG5cclxuICAvLyBDcmVhdGUgYSBtZXNzYWdlJ3MgcHJlZml4XHJcbiAgY29uc3QgcHJlZml4ID0gYCR7bmV3RGF0ZX0gWyR7bGV2ZWxzRGVzY1tuZXdMZXZlbCAtIDFdLnRpdGxlfV0gLWA7XHJcblxyXG4gIC8vIENhbGwgYXZhaWxhYmxlIGxvZyBsaXN0ZW5lcnNcclxuICBsb2dnaW5nLmxpc3RlbmVycy5mb3JFYWNoKChmbikgPT4ge1xyXG4gICAgZm4ocHJlZml4LCB0ZXh0cy5qb2luKCcgJykpO1xyXG4gIH0pO1xyXG5cclxuICAvLyBMb2cgdG8gY29uc29sZVxyXG4gIGlmIChsb2dnaW5nLnRvQ29uc29sZSkge1xyXG4gICAgY29uc29sZS5sb2cuYXBwbHkoXHJcbiAgICAgIHVuZGVmaW5lZCxcclxuICAgICAgW3ByZWZpeC50b1N0cmluZygpW2xvZ2dpbmcubGV2ZWxzRGVzY1tuZXdMZXZlbCAtIDFdLmNvbG9yXV0uY29uY2F0KHRleHRzKVxyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIC8vIExvZyB0byBmaWxlXHJcbiAgbG9nVG9GaWxlKHRleHRzLCBwcmVmaXgpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIExvZ3MgYW4gZXJyb3IgbWVzc2FnZSB3aXRoIGl0cyBzdGFjayB0cmFjZS4gT3B0aW9uYWxseSwgYSBjdXN0b20gbWVzc2FnZVxyXG4gKiBjYW4gYmUgcHJvdmlkZWQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBsZXZlbCAtIFRoZSBsb2cgbGV2ZWwuXHJcbiAqIEBwYXJhbSB7RXJyb3J9IGVycm9yIC0gVGhlIGVycm9yIG9iamVjdC5cclxuICogQHBhcmFtIHtzdHJpbmd9IGN1c3RvbU1lc3NhZ2UgLSBBbiBvcHRpb25hbCBjdXN0b20gbWVzc2FnZSB0byBiZSBsb2dnZWQgYWxvbmdcclxuICogd2l0aCB0aGUgZXJyb3IuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbG9nV2l0aFN0YWNrID0gKG5ld0xldmVsLCBlcnJvciwgY3VzdG9tTWVzc2FnZSkgPT4ge1xyXG4gIC8vIEdldCB0aGUgbWFpbiBtZXNzYWdlXHJcbiAgY29uc3QgbWFpbk1lc3NhZ2UgPSBjdXN0b21NZXNzYWdlIHx8IGVycm9yLm1lc3NhZ2U7XHJcblxyXG4gIC8vIEN1cnJlbnQgbG9nZ2luZyBvcHRpb25zXHJcbiAgY29uc3QgeyBsZXZlbCwgbGV2ZWxzRGVzYyB9ID0gbG9nZ2luZztcclxuXHJcbiAgLy8gQ2hlY2sgaWYgbG9nIGxldmVsIGlzIHdpdGhpbiBhIGNvcnJlY3QgcmFuZ2VcclxuICBpZiAobmV3TGV2ZWwgPT09IDAgfHwgbmV3TGV2ZWwgPiBsZXZlbCB8fCBsZXZlbCA+IGxldmVsc0Rlc2MubGVuZ3RoKSB7XHJcbiAgICByZXR1cm47XHJcbiAgfVxyXG5cclxuICAvLyBHZXQgcmlkIG9mIHRoZSBHTVQgdGV4dCBpbmZvcm1hdGlvblxyXG4gIGNvbnN0IG5ld0RhdGUgPSBuZXcgRGF0ZSgpLnRvU3RyaW5nKCkuc3BsaXQoJygnKVswXS50cmltKCk7XHJcblxyXG4gIC8vIENyZWF0ZSBhIG1lc3NhZ2UncyBwcmVmaXhcclxuICBjb25zdCBwcmVmaXggPSBgJHtuZXdEYXRlfSBbJHtsZXZlbHNEZXNjW25ld0xldmVsIC0gMV0udGl0bGV9XSAtYDtcclxuXHJcbiAgLy8gSWYgdGhlIGN1c3RvbU1lc3NhZ2UgZXhpc3RzLCB3ZSB3YW50IHRvIGRpc3BsYXkgdGhlIHdob2xlIHN0YWNrIG1lc3NhZ2VcclxuICBjb25zdCBzdGFja01lc3NhZ2UgPVxyXG4gICAgZXJyb3IubWVzc2FnZSAhPT0gZXJyb3Iuc3RhY2tNZXNzYWdlIHx8IGVycm9yLnN0YWNrTWVzc2FnZSA9PT0gdW5kZWZpbmVkXHJcbiAgICAgID8gZXJyb3Iuc3RhY2tcclxuICAgICAgOiBlcnJvci5zdGFjay5zcGxpdCgnXFxuJykuc2xpY2UoMSkuam9pbignXFxuJyk7XHJcblxyXG4gIC8vIENvbWJpbmUgY3VzdG9tIG1lc3NhZ2Ugb3IgZXJyb3IgbWVzc2FnZSB3aXRoIGVycm9yIHN0YWNrIG1lc3NhZ2VcclxuICBjb25zdCB0ZXh0cyA9IFttYWluTWVzc2FnZSwgJ1xcbicsIHN0YWNrTWVzc2FnZV07XHJcblxyXG4gIC8vIExvZyB0byBjb25zb2xlXHJcbiAgaWYgKGxvZ2dpbmcudG9Db25zb2xlKSB7XHJcbiAgICBjb25zb2xlLmxvZy5hcHBseShcclxuICAgICAgdW5kZWZpbmVkLFxyXG4gICAgICBbcHJlZml4LnRvU3RyaW5nKClbbG9nZ2luZy5sZXZlbHNEZXNjW25ld0xldmVsIC0gMV0uY29sb3JdXS5jb25jYXQoW1xyXG4gICAgICAgIG1haW5NZXNzYWdlW2NvbG9yc1tuZXdMZXZlbCAtIDFdXSxcclxuICAgICAgICAnXFxuJyxcclxuICAgICAgICBzdGFja01lc3NhZ2VcclxuICAgICAgXSlcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICAvLyBDYWxsIGF2YWlsYWJsZSBsb2cgbGlzdGVuZXJzXHJcbiAgbG9nZ2luZy5saXN0ZW5lcnMuZm9yRWFjaCgoZm4pID0+IHtcclxuICAgIGZuKHByZWZpeCwgdGV4dHMuam9pbignICcpKTtcclxuICB9KTtcclxuXHJcbiAgLy8gTG9nIHRvIGZpbGVcclxuICBsb2dUb0ZpbGUodGV4dHMsIHByZWZpeCk7XHJcbn07XHJcblxyXG4vKipcclxuICogU2V0cyB0aGUgbG9nIGxldmVsIHRvIHRoZSBzcGVjaWZpZWQgdmFsdWUuIExvZyBsZXZlbHMgYXJlICgwID0gbm8gbG9nZ2luZyxcclxuICogMSA9IGVycm9yLCAyID0gd2FybmluZywgMyA9IG5vdGljZSwgNCA9IHZlcmJvc2Ugb3IgNSA9IGJlbmNobWFyaylcclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IG5ld0xldmVsIC0gVGhlIG5ldyBsb2cgbGV2ZWwgdG8gYmUgc2V0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHNldExvZ0xldmVsID0gKG5ld0xldmVsKSA9PiB7XHJcbiAgaWYgKG5ld0xldmVsID49IDAgJiYgbmV3TGV2ZWwgPD0gbG9nZ2luZy5sZXZlbHNEZXNjLmxlbmd0aCkge1xyXG4gICAgbG9nZ2luZy5sZXZlbCA9IG5ld0xldmVsO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBFbmFibGVzIGZpbGUgbG9nZ2luZyB3aXRoIHRoZSBzcGVjaWZpZWQgZGVzdGluYXRpb24gYW5kIGxvZyBmaWxlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gbG9nRGVzdCAtIFRoZSBkZXN0aW5hdGlvbiBwYXRoIGZvciBsb2cgZmlsZXMuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBsb2dGaWxlIC0gVGhlIGxvZyBmaWxlIG5hbWUuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZW5hYmxlRmlsZUxvZ2dpbmcgPSAobG9nRGVzdCwgbG9nRmlsZSkgPT4ge1xyXG4gIC8vIFVwZGF0ZSBsb2dnaW5nIG9wdGlvbnNcclxuICBsb2dnaW5nID0ge1xyXG4gICAgLi4ubG9nZ2luZyxcclxuICAgIGRlc3Q6IGxvZ0Rlc3QgfHwgbG9nZ2luZy5kZXN0LFxyXG4gICAgZmlsZTogbG9nRmlsZSB8fCBsb2dnaW5nLmZpbGUsXHJcbiAgICB0b0ZpbGU6IHRydWVcclxuICB9O1xyXG5cclxuICBpZiAobG9nZ2luZy5kZXN0Lmxlbmd0aCA9PT0gMCkge1xyXG4gICAgcmV0dXJuIGxvZygxLCAnW2xvZ2dlcl0gRmlsZSBsb2dnaW5nIGluaXRpYWxpemF0aW9uOiBubyBwYXRoIHN1cHBsaWVkLicpO1xyXG4gIH1cclxuXHJcbiAgaWYgKCFsb2dnaW5nLmRlc3QuZW5kc1dpdGgoJy8nKSkge1xyXG4gICAgbG9nZ2luZy5kZXN0ICs9ICcvJztcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgbG9nZ2luZyB3aXRoIHRoZSBzcGVjaWZpZWQgbG9nZ2luZyBjb25maWd1cmF0aW9uLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gbG9nZ2luZyAtIFRoZSBsb2dnaW5nIGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGluaXRMb2dnaW5nID0gKGxvZ2dpbmcpID0+IHtcclxuICAvLyBTZXQgdGhlIGxvZyBsZXZlbFxyXG4gIHNldExvZ0xldmVsKGxvZ2dpbmcgJiYgcGFyc2VJbnQobG9nZ2luZy5sZXZlbCkpO1xyXG5cclxuICAvLyBTZXQgdGhlIGxvZyBmaWxlIHBhdGggYW5kIG5hbWVcclxuICBpZiAobG9nZ2luZyAmJiBsb2dnaW5nLmRlc3QpIHtcclxuICAgIGVuYWJsZUZpbGVMb2dnaW5nKFxyXG4gICAgICBsb2dnaW5nLmRlc3QsXHJcbiAgICAgIGxvZ2dpbmcuZmlsZSB8fCAnaGlnaGNoYXJ0cy1leHBvcnQtc2VydmVyLmxvZydcclxuICAgICk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEFkZHMgYSBsaXN0ZW5lciBmdW5jdGlvbiB0byB0aGUgbG9nZ2luZyBzeXN0ZW0uXHJcbiAqXHJcbiAqIEBwYXJhbSB7ZnVuY3Rpb259IGZuIC0gVGhlIGxpc3RlbmVyIGZ1bmN0aW9uIHRvIGJlIGFkZGVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGxpc3RlbiA9IChmbikgPT4ge1xyXG4gIGxvZ2dpbmcubGlzdGVuZXJzLnB1c2goZm4pO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFRvZ2dsZXMgdGhlIHN0YW5kYXJkIG91dHB1dCAoY29uc29sZSkgbG9nZ2luZy5cclxuICpcclxuICogQHBhcmFtIHtib29sZWFufSBlbmFibGVkIC0gSWYgdHJ1ZSwgZW5hYmxlcyBjb25zb2xlIGxvZ2dpbmc7IGlmIGZhbHNlLFxyXG4gKiBkaXNhYmxlcyBpdC5cclxuICovXHJcbmV4cG9ydCBjb25zdCB0b2dnbGVTVERPdXQgPSAoZW5hYmxlZCkgPT4ge1xyXG4gIGxvZ2dpbmcudG9Db25zb2xlID0gZW5hYmxlZDtcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBsb2csXHJcbiAgbG9nV2l0aFN0YWNrLFxyXG4gIHNldExvZ0xldmVsLFxyXG4gIGVuYWJsZUZpbGVMb2dnaW5nLFxyXG4gIGluaXRMb2dnaW5nLFxyXG4gIGxpc3RlbixcclxuICB0b2dnbGVTVERPdXRcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuaW1wb3J0IHsgZmlsZVVSTFRvUGF0aCB9IGZyb20gJ3VybCc7XHJcblxyXG5pbXBvcnQgeyBkZWZhdWx0Q29uZmlnIH0gZnJvbSAnLi4vbGliL3NjaGVtYXMvY29uZmlnLmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcblxyXG5jb25zdCBNQVhfQkFDS09GRl9BVFRFTVBUUyA9IDY7XHJcblxyXG5leHBvcnQgY29uc3QgX19kaXJuYW1lID0gZmlsZVVSTFRvUGF0aChuZXcgVVJMKCcuLi8uJywgaW1wb3J0Lm1ldGEudXJsKSk7XHJcblxyXG4vKipcclxuICogQ2xlYXJzIGFuZCBzdGFuZGFyZGl6ZXMgdGV4dCBieSByZXBsYWNpbmcgbXVsdGlwbGUgY29uc2VjdXRpdmUgd2hpdGVzcGFjZVxyXG4gKiBjaGFyYWN0ZXJzIHdpdGggYSBzaW5nbGUgc3BhY2UgYW5kIHRyaW1taW5nIGFueSBsZWFkaW5nIG9yIHRyYWlsaW5nXHJcbiAqIHdoaXRlc3BhY2UuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0ZXh0IC0gVGhlIGlucHV0IHRleHQgdG8gYmUgY2xlYXJlZC5cclxuICogQHBhcmFtIHtSZWdFeHB9IFtydWxlPS9cXHNcXHMrL2ddIC0gVGhlIHJlZ3VsYXIgZXhwcmVzc2lvbiBydWxlIHRvIG1hdGNoXHJcbiAqIG11bHRpcGxlIGNvbnNlY3V0aXZlIHdoaXRlc3BhY2UgY2hhcmFjdGVycy5cclxuICogQHBhcmFtIHtzdHJpbmd9IFtyZXBsYWNlcj0nICddIC0gVGhlIHN0cmluZyB1c2VkIHRvIHJlcGxhY2UgbXVsdGlwbGVcclxuICogY29uc2VjdXRpdmUgd2hpdGVzcGFjZSBjaGFyYWN0ZXJzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSAtIFRoZSBjbGVhcmVkIGFuZCBzdGFuZGFyZGl6ZWQgdGV4dC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBjbGVhclRleHQgPSAodGV4dCwgcnVsZSA9IC9cXHNcXHMrL2csIHJlcGxhY2VyID0gJyAnKSA9PlxyXG4gIHRleHQucmVwbGFjZUFsbChydWxlLCByZXBsYWNlcikudHJpbSgpO1xyXG5cclxuLyoqXHJcbiAqIEltcGxlbWVudHMgYW4gZXhwb25lbnRpYWwgYmFja29mZiBzdHJhdGVneSBmb3IgcmV0cnlpbmcgYSBmdW5jdGlvbiB1bnRpbFxyXG4gKiBhIGNlcnRhaW4gbnVtYmVyIG9mIGF0dGVtcHRzIGFyZSByZWFjaGVkLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBmbiAtIFRoZSBmdW5jdGlvbiB0byBiZSByZXRyaWVkLlxyXG4gKiBAcGFyYW0ge251bWJlcn0gW2F0dGVtcHQ9MF0gLSBUaGUgY3VycmVudCBhdHRlbXB0IG51bWJlci5cclxuICogQHBhcmFtIHsuLi5hbnl9IGFyZ3MgLSBBcmd1bWVudHMgdG8gYmUgcGFzc2VkIHRvIHRoZSBmdW5jdGlvbi5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2V9IC0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIHJlc3VsdCBvZiB0aGUgZnVuY3Rpb25cclxuICogaWYgc3VjY2Vzc2Z1bC5cclxuICpcclxuICogQHRocm93cyB7RXJyb3J9IC0gVGhyb3dzIGFuIGVycm9yIGlmIHRoZSBtYXhpbXVtIG51bWJlciBvZiBhdHRlbXB0c1xyXG4gKiBpcyByZWFjaGVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGV4cEJhY2tvZmYgPSBhc3luYyAoZm4sIGF0dGVtcHQgPSAwLCAuLi5hcmdzKSA9PiB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIFRyeSB0byBjYWxsIHRoZSBmdW5jdGlvblxyXG4gICAgcmV0dXJuIGF3YWl0IGZuKC4uLmFyZ3MpO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAvLyBDYWxjdWxhdGUgZGVsYXkgaW4gbXNcclxuICAgIGNvbnN0IGRlbGF5SW5NcyA9IDIgKiogYXR0ZW1wdCAqIDEwMDA7XHJcblxyXG4gICAgLy8gSWYgdGhlIGF0dGVtcHQgZXhjZWVkcyB0aGUgbWF4aW11bSBhdHRlbXB0cyBvZiByZWFwZWF0LCB0aHJvdyBhbiBlcnJvclxyXG4gICAgaWYgKCsrYXR0ZW1wdCA+PSBNQVhfQkFDS09GRl9BVFRFTVBUUykge1xyXG4gICAgICB0aHJvdyBlcnJvcjtcclxuICAgIH1cclxuXHJcbiAgICAvLyBXYWl0IGdpdmVuIGFtb3VudCBvZiB0aW1lXHJcbiAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzcG9uc2UpID0+IHNldFRpbWVvdXQocmVzcG9uc2UsIGRlbGF5SW5NcykpO1xyXG4gICAgbG9nKFxyXG4gICAgICAzLFxyXG4gICAgICBgW3Bvb2xdIFdhaXRlZCAke2RlbGF5SW5Nc31tcyB1bnRpbCBuZXh0IGNhbGwgZm9yIHRoZSByZXNvdXJjZSBpZDogJHthcmdzWzBdfS5gXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFRyeSBhZ2FpblxyXG4gICAgcmV0dXJuIGV4cEJhY2tvZmYoZm4sIGF0dGVtcHQsIC4uLmFyZ3MpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBGaXhlcyB0aGUgZXhwb3J0IHR5cGUgYmFzZWQgb24gTUlNRSB0eXBlcyBhbmQgZmlsZSBleHRlbnNpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdHlwZSAtIFRoZSBvcmlnaW5hbCBleHBvcnQgdHlwZS5cclxuICogQHBhcmFtIHtzdHJpbmd9IG91dGZpbGUgLSBUaGUgZmlsZSBwYXRoIG9yIG5hbWUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IC0gVGhlIGNvcnJlY3RlZCBleHBvcnQgdHlwZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBmaXhUeXBlID0gKHR5cGUsIG91dGZpbGUpID0+IHtcclxuICAvLyBNSU1FIHR5cGVzXHJcbiAgY29uc3QgbWltZVR5cGVzID0ge1xyXG4gICAgJ2ltYWdlL3BuZyc6ICdwbmcnLFxyXG4gICAgJ2ltYWdlL2pwZWcnOiAnanBlZycsXHJcbiAgICAnYXBwbGljYXRpb24vcGRmJzogJ3BkZicsXHJcbiAgICAnaW1hZ2Uvc3ZnK3htbCc6ICdzdmcnXHJcbiAgfTtcclxuXHJcbiAgLy8gRm9ybWF0c1xyXG4gIGNvbnN0IGZvcm1hdHMgPSBbJ3BuZycsICdqcGVnJywgJ3BkZicsICdzdmcnXTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgdHlwZSBhbmQgb3V0ZmlsZSdzIGV4dGVuc2lvbnMgYXJlIHRoZSBzYW1lXHJcbiAgaWYgKG91dGZpbGUpIHtcclxuICAgIGNvbnN0IG91dFR5cGUgPSBvdXRmaWxlLnNwbGl0KCcuJykucG9wKCk7XHJcblxyXG4gICAgaWYgKG91dFR5cGUgPT09ICdqcGcnKSB7XHJcbiAgICAgIHR5cGUgPSAnanBlZyc7XHJcbiAgICB9IGVsc2UgaWYgKGZvcm1hdHMuaW5jbHVkZXMob3V0VHlwZSkgJiYgdHlwZSAhPT0gb3V0VHlwZSkge1xyXG4gICAgICB0eXBlID0gb3V0VHlwZTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiBhIGNvcnJlY3QgdHlwZVxyXG4gIHJldHVybiBtaW1lVHlwZXNbdHlwZV0gfHwgZm9ybWF0cy5maW5kKCh0KSA9PiB0ID09PSB0eXBlKSB8fCAncG5nJztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBIYW5kbGVzIGFuZCB2YWxpZGF0ZXMgcmVzb3VyY2VzIGZvciBleHBvcnQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fHN0cmluZ30gcmVzb3VyY2VzIC0gVGhlIHJlc291cmNlcyB0byBiZSBoYW5kbGVkLiBDYW4gYmUgZWl0aGVyXHJcbiAqIGEgSlNPTiBvYmplY3QsIHN0cmluZ2lmaWVkIEpTT04gb3IgYSBwYXRoIHRvIGEgSlNPTiBmaWxlLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RmlsZVJlc291cmNlcyAtIFdoZXRoZXIgdG8gYWxsb3cgbG9hZGluZyByZXNvdXJjZXMgZnJvbVxyXG4gKiBmaWxlcy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdHx1bmRlZmluZWR9IC0gVGhlIGhhbmRsZWQgcmVzb3VyY2VzIG9yIHVuZGVmaW5lZCBpZiBubyB2YWxpZFxyXG4gKiByZXNvdXJjZXMgYXJlIGZvdW5kLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGhhbmRsZVJlc291cmNlcyA9IChyZXNvdXJjZXMgPSBmYWxzZSwgYWxsb3dGaWxlUmVzb3VyY2VzKSA9PiB7XHJcbiAgY29uc3QgYWxsb3dlZFByb3BzID0gWydqcycsICdjc3MnLCAnZmlsZXMnXTtcclxuXHJcbiAgbGV0IGhhbmRsZWRSZXNvdXJjZXMgPSByZXNvdXJjZXM7XHJcbiAgbGV0IGNvcnJlY3RSZXNvdXJjZXMgPSBmYWxzZTtcclxuXHJcbiAgLy8gVHJ5IHRvIGxvYWQgcmVzb3VyY2VzIGZyb20gYSBmaWxlXHJcbiAgaWYgKGFsbG93RmlsZVJlc291cmNlcyAmJiByZXNvdXJjZXMuZW5kc1dpdGgoJy5qc29uJykpIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGhhbmRsZWRSZXNvdXJjZXMgPSBpc0NvcnJlY3RKU09OKHJlYWRGaWxlU3luYyhyZXNvdXJjZXMsICd1dGY4JykpO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgcmV0dXJuIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgYFtjbGldIE5vIHJlc291cmNlcyBmb3VuZC5gKTtcclxuICAgIH1cclxuICB9IGVsc2Uge1xyXG4gICAgLy8gVHJ5IHRvIGdldCBKU09OXHJcbiAgICBoYW5kbGVkUmVzb3VyY2VzID0gaXNDb3JyZWN0SlNPTihyZXNvdXJjZXMpO1xyXG5cclxuICAgIC8vIEdldCByaWQgb2YgdGhlIGZpbGVzIHNlY3Rpb25cclxuICAgIGlmIChoYW5kbGVkUmVzb3VyY2VzICYmICFhbGxvd0ZpbGVSZXNvdXJjZXMpIHtcclxuICAgICAgZGVsZXRlIGhhbmRsZWRSZXNvdXJjZXMuZmlsZXM7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBGaWx0ZXIgZnJvbSB1bm5lY2Vzc2FyeSBwcm9wZXJ0aWVzXHJcbiAgZm9yIChjb25zdCBwcm9wTmFtZSBpbiBoYW5kbGVkUmVzb3VyY2VzKSB7XHJcbiAgICBpZiAoIWFsbG93ZWRQcm9wcy5pbmNsdWRlcyhwcm9wTmFtZSkpIHtcclxuICAgICAgZGVsZXRlIGhhbmRsZWRSZXNvdXJjZXNbcHJvcE5hbWVdO1xyXG4gICAgfSBlbHNlIGlmICghY29ycmVjdFJlc291cmNlcykge1xyXG4gICAgICBjb3JyZWN0UmVzb3VyY2VzID0gdHJ1ZTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIENoZWNrIGlmIGF0IGxlYXN0IG9uZSBvZiBhbGxvd2VkIHByb3BlcnRpZXMgaXMgcHJlc2VudFxyXG4gIGlmICghY29ycmVjdFJlc291cmNlcykge1xyXG4gICAgcmV0dXJuIGxvZygzLCBgW2NsaV0gTm8gcmVzb3VyY2VzIGZvdW5kLmApO1xyXG4gIH1cclxuXHJcbiAgLy8gSGFuZGxlIGZpbGVzIHNlY3Rpb25cclxuICBpZiAoaGFuZGxlZFJlc291cmNlcy5maWxlcykge1xyXG4gICAgaGFuZGxlZFJlc291cmNlcy5maWxlcyA9IGhhbmRsZWRSZXNvdXJjZXMuZmlsZXMubWFwKChpdGVtKSA9PiBpdGVtLnRyaW0oKSk7XHJcbiAgICBpZiAoIWhhbmRsZWRSZXNvdXJjZXMuZmlsZXMgfHwgaGFuZGxlZFJlc291cmNlcy5maWxlcy5sZW5ndGggPD0gMCkge1xyXG4gICAgICBkZWxldGUgaGFuZGxlZFJlc291cmNlcy5maWxlcztcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiByZXNvdXJjZXNcclxuICByZXR1cm4gaGFuZGxlZFJlc291cmNlcztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBWYWxpZGF0ZXMgYW5kIHBhcnNlcyBKU09OIGRhdGEuIENoZWNrcyBpZiBwcm92aWRlZCBkYXRhIGlzIG9yIGNhblxyXG4gKiBiZSBhIGNvcnJlY3QgSlNPTi5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R8c3RyaW5nfSBkYXRhIC0gVGhlIEpTT04gZGF0YSB0byBiZSB2YWxpZGF0ZWQgYW5kIHBhcnNlZC5cclxuICogQHBhcmFtIHtib29sZWFufSB0b1N0cmluZyAtIFdoZXRoZXIgdG8gcmV0dXJuIGEgc3RyaW5naWZpZWQgcmVwcmVzZW50YXRpb25cclxuICogb2YgdGhlIHBhcnNlZCBKU09OLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fHN0cmluZ3xib29sZWFufSAtIFRoZSBwYXJzZWQgSlNPTiBvYmplY3QsIHN0cmluZ2lmaWVkIEpTT04sXHJcbiAqIG9yIGZhbHNlIGlmIHZhbGlkYXRpb24gZmFpbHMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gaXNDb3JyZWN0SlNPTihkYXRhLCB0b1N0cmluZykge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBHZXQgdGhlIHN0cmluZyByZXByZXNlbnRhdGlvbiBpZiBub3QgYWxyZWFkeSBiZWZvcmUgcGFyc2luZ1xyXG4gICAgY29uc3QgcGFyc2VkRGF0YSA9IEpTT04ucGFyc2UoXHJcbiAgICAgIHR5cGVvZiBkYXRhICE9PSAnc3RyaW5nJyA/IEpTT04uc3RyaW5naWZ5KGRhdGEpIDogZGF0YVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBSZXR1cm4gYSBzdHJpbmdpZmllZCByZXByZXNlbnRhdGlvbiBvZiBhIEpTT04gaWYgcmVxdWlyZWRcclxuICAgIGlmICh0eXBlb2YgcGFyc2VkRGF0YSAhPT0gJ3N0cmluZycgJiYgdG9TdHJpbmcpIHtcclxuICAgICAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KHBhcnNlZERhdGEpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFJldHVybiBhIEpTT05cclxuICAgIHJldHVybiBwYXJzZWREYXRhO1xyXG4gIH0gY2F0Y2gge1xyXG4gICAgcmV0dXJuIGZhbHNlO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gaXRlbSBpcyBhbiBvYmplY3QuXHJcbiAqXHJcbiAqIEBwYXJhbSB7YW55fSBpdGVtIC0gVGhlIGl0ZW0gdG8gYmUgY2hlY2tlZC5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IC0gVHJ1ZSBpZiB0aGUgaXRlbSBpcyBhbiBvYmplY3QsIGZhbHNlIG90aGVyd2lzZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBpc09iamVjdCA9IChpdGVtKSA9PlxyXG4gIHR5cGVvZiBpdGVtID09PSAnb2JqZWN0JyAmJiAhQXJyYXkuaXNBcnJheShpdGVtKSAmJiBpdGVtICE9PSBudWxsO1xyXG5cclxuLyoqXHJcbiAqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gb2JqZWN0IGlzIGVtcHR5LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gaXRlbSAtIFRoZSBvYmplY3QgdG8gYmUgY2hlY2tlZC5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IC0gVHJ1ZSBpZiB0aGUgb2JqZWN0IGlzIGVtcHR5LCBmYWxzZSBvdGhlcndpc2UuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaXNPYmplY3RFbXB0eSA9IChpdGVtKSA9PlxyXG4gIHR5cGVvZiBpdGVtID09PSAnb2JqZWN0JyAmJiBpdGVtICE9PSBudWxsICYmIE9iamVjdC5rZXlzKGl0ZW0pLmxlbmd0aCA9PT0gMDtcclxuXHJcbi8qKlxyXG4gKiBDaGVja3MgaWYgYSBwcml2YXRlIElQIHJhbmdlIFVSTCBpcyBmb3VuZCBpbiB0aGUgZ2l2ZW4gc3RyaW5nLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gaXRlbSAtIFRoZSBzdHJpbmcgdG8gYmUgY2hlY2tlZCBmb3IgYSBwcml2YXRlIElQIHJhbmdlIFVSTC5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IC0gVHJ1ZSBpZiBhIHByaXZhdGUgSVAgcmFuZ2UgVVJMIGlzIGZvdW5kLCBmYWxzZVxyXG4gKiBvdGhlcndpc2UuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaXNQcml2YXRlUmFuZ2VVcmxGb3VuZCA9IChpdGVtKSA9PiB7XHJcbiAgcmV0dXJuIFtcclxuICAgICdsb2NhbGhvc3QnLFxyXG4gICAgJygxMCkuKC4qKS4oLiopLiguKiknLFxyXG4gICAgJygxMjcpLiguKikuKC4qKS4oLiopJyxcclxuICAgICcoMTcyKS4oMVs2LTldfDJbMC05XXwzWzAtMV0pLiguKikuKC4qKScsXHJcbiAgICAnKDE5MikuKDE2OCkuKC4qKS4oLiopJ1xyXG4gIF0uc29tZSgoaXBSZWdFeCkgPT5cclxuICAgIGl0ZW0ubWF0Y2goYHhsaW5rOmhyZWY9XCIoPzooaHR0cDovL3xodHRwczovLykpPyR7aXBSZWdFeH1gKVxyXG4gICk7XHJcbn07XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhIGRlZXAgY29weSBvZiB0aGUgZ2l2ZW4gb2JqZWN0IG9yIGFycmF5LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdHxBcnJheX0gb2JqIC0gVGhlIG9iamVjdCBvciBhcnJheSB0byBiZSBkZWVwbHkgY29waWVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fEFycmF5fSAtIFRoZSBkZWVwIGNvcHkgb2YgdGhlIHByb3ZpZGVkIG9iamVjdCBvciBhcnJheS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBkZWVwQ29weSA9IChvYmopID0+IHtcclxuICBpZiAob2JqID09PSBudWxsIHx8IHR5cGVvZiBvYmogIT09ICdvYmplY3QnKSB7XHJcbiAgICByZXR1cm4gb2JqO1xyXG4gIH1cclxuXHJcbiAgY29uc3QgY29weSA9IEFycmF5LmlzQXJyYXkob2JqKSA/IFtdIDoge307XHJcblxyXG4gIGZvciAoY29uc3Qga2V5IGluIG9iaikge1xyXG4gICAgaWYgKE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChvYmosIGtleSkpIHtcclxuICAgICAgY29weVtrZXldID0gZGVlcENvcHkob2JqW2tleV0pO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcmV0dXJuIGNvcHk7XHJcbn07XHJcblxyXG4vKipcclxuICogQ29udmVydHMgdGhlIHByb3ZpZGVkIG9wdGlvbnMgb2JqZWN0IHRvIGEgSlNPTi1mb3JtYXR0ZWQgc3RyaW5nIHdpdGggdGhlXHJcbiAqIG9wdGlvbiB0byBwcmVzZXJ2ZSBmdW5jdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IHRvIGJlIGNvbnZlcnRlZCB0byBhIHN0cmluZy5cclxuICogQHBhcmFtIHtib29sZWFufSBhbGxvd0Z1bmN0aW9ucyAtIElmIHNldCB0byB0cnVlLCBmdW5jdGlvbnMgYXJlIHByZXNlcnZlZFxyXG4gKiBpbiB0aGUgb3V0cHV0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSAtIFRoZSBKU09OLWZvcm1hdHRlZCBzdHJpbmcgcmVwcmVzZW50aW5nIHRoZSBvcHRpb25zLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IG9wdGlvbnNTdHJpbmdpZnkgPSAob3B0aW9ucywgYWxsb3dGdW5jdGlvbnMpID0+IHtcclxuICBjb25zdCByZXBsYWNlckNhbGxiYWNrID0gKG5hbWUsIHZhbHVlKSA9PiB7XHJcbiAgICBpZiAodHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJykge1xyXG4gICAgICB2YWx1ZSA9IHZhbHVlLnRyaW0oKTtcclxuXHJcbiAgICAgIC8vIElmIGFsbG93RnVuY3Rpb25zIGlzIHNldCB0byB0cnVlLCBwcmVzZXJ2ZSBmdW5jdGlvbnNcclxuICAgICAgaWYgKFxyXG4gICAgICAgICh2YWx1ZS5zdGFydHNXaXRoKCdmdW5jdGlvbignKSB8fCB2YWx1ZS5zdGFydHNXaXRoKCdmdW5jdGlvbiAoJykpICYmXHJcbiAgICAgICAgdmFsdWUuZW5kc1dpdGgoJ30nKVxyXG4gICAgICApIHtcclxuICAgICAgICB2YWx1ZSA9IGFsbG93RnVuY3Rpb25zXHJcbiAgICAgICAgICA/IGBFWFBfRlVOJHsodmFsdWUgKyAnJykucmVwbGFjZUFsbCgvXFxufFxcdHxcXHIvZywgJyAnKX1FWFBfRlVOYFxyXG4gICAgICAgICAgOiB1bmRlZmluZWQ7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gdHlwZW9mIHZhbHVlID09PSAnZnVuY3Rpb24nXHJcbiAgICAgID8gYEVYUF9GVU4keyh2YWx1ZSArICcnKS5yZXBsYWNlQWxsKC9cXG58XFx0fFxcci9nLCAnICcpfUVYUF9GVU5gXHJcbiAgICAgIDogdmFsdWU7XHJcbiAgfTtcclxuXHJcbiAgLy8gU3RyaW5naWZ5IG9wdGlvbnMgYW5kIGlmIHJlcXVpcmVkLCByZXBsYWNlIHNwZWNpYWwgZnVuY3Rpb25zIG1hcmtzXHJcbiAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KG9wdGlvbnMsIHJlcGxhY2VyQ2FsbGJhY2spLnJlcGxhY2VBbGwoXHJcbiAgICAvXCJFWFBfRlVOfEVYUF9GVU5cIi9nLFxyXG4gICAgJydcclxuICApO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFByaW50cyB0aGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyIGxvZ28gYW5kIHZlcnNpb24gaW5mb3JtYXRpb24uXHJcbiAqXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gbm9Mb2dvIC0gSWYgdHJ1ZSwgb25seSBwcmludHMgdmVyc2lvbiBpbmZvcm1hdGlvbiB3aXRob3V0XHJcbiAqIHRoZSBsb2dvLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHByaW50TG9nbyA9IChub0xvZ28pID0+IHtcclxuICAvLyBHZXQgcGFja2FnZSB2ZXJzaW9uIGVpdGhlciBmcm9tIGVudiBvciBmcm9tIHBhY2thZ2UuanNvblxyXG4gIGNvbnN0IHBhY2thZ2VWZXJzaW9uID0gSlNPTi5wYXJzZShcclxuICAgIHJlYWRGaWxlU3luYyhqb2luKF9fZGlybmFtZSwgJ3BhY2thZ2UuanNvbicpKVxyXG4gICkudmVyc2lvbjtcclxuXHJcbiAgLy8gUHJpbnQgdGV4dCBvbmx5XHJcbiAgaWYgKG5vTG9nbykge1xyXG4gICAgY29uc29sZS5sb2coYFN0YXJ0aW5nIEhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlciB2JHtwYWNrYWdlVmVyc2lvbn0uLi5gKTtcclxuICAgIHJldHVybjtcclxuICB9XHJcblxyXG4gIC8vIFByaW50IHRoZSBsb2dvXHJcbiAgY29uc29sZS5sb2coXHJcbiAgICByZWFkRmlsZVN5bmMoX19kaXJuYW1lICsgJy9tc2cvc3RhcnR1cC5tc2cnKS50b1N0cmluZygpLmJvbGQueWVsbG93LFxyXG4gICAgYHYke3BhY2thZ2VWZXJzaW9ufWBcclxuICApO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFByaW50cyB0aGUgdXNhZ2UgaW5mb3JtYXRpb24gZm9yIENMSSBhcmd1bWVudHMuIElmIHJlcXVpcmVkLCBpdCBjYW4gbGlzdFxyXG4gKiBwcm9wZXJ0aWVzIHJlY3Vyc2l2ZWx5XHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gcHJpbnRVc2FnZSgpIHtcclxuICBjb25zdCBwYWQgPSA0ODtcclxuICBjb25zdCByZWFkbWUgPSAnaHR0cHM6Ly9naXRodWIuY29tL2hpZ2hjaGFydHMvbm9kZS1leHBvcnQtc2VydmVyI3JlYWRtZSc7XHJcblxyXG4gIC8vIERpc3BsYXkgcmVhZG1lIGluZm9ybWF0aW9uXHJcbiAgY29uc29sZS5sb2coXHJcbiAgICAnXFxuVXNhZ2Ugb2YgQ0xJIGFyZ3VtZW50czonLmJvbGQsXHJcbiAgICAnXFxuLS0tLS0tJyxcclxuICAgIGBcXG5Gb3IgbW9yZSBkZXRhaWxlZCBpbmZvcm1hdGlvbiwgdmlzaXQgdGhlIHJlYWRtZSBhdDogJHtyZWFkbWUuYm9sZC55ZWxsb3d9LmBcclxuICApO1xyXG5cclxuICBjb25zdCBjeWNsZUNhdGVnb3JpZXMgPSAob3B0aW9ucykgPT4ge1xyXG4gICAgZm9yIChjb25zdCBbbmFtZSwgb3B0aW9uXSBvZiBPYmplY3QuZW50cmllcyhvcHRpb25zKSkge1xyXG4gICAgICAvLyBJZiBjYXRlZ29yeSBoYXMgbW9yZSBsZXZlbHMsIGdvIGZ1cnRoZXJcclxuICAgICAgaWYgKCFPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob3B0aW9uLCAndmFsdWUnKSkge1xyXG4gICAgICAgIGN5Y2xlQ2F0ZWdvcmllcyhvcHRpb24pO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIGxldCBkZXNjTmFtZSA9IGAgIC0tJHtvcHRpb24uY2xpTmFtZSB8fCBuYW1lfSAke1xyXG4gICAgICAgICAgKCc8JyArIG9wdGlvbi50eXBlICsgJz4nKS5ncmVlblxyXG4gICAgICAgIH0gYDtcclxuICAgICAgICBpZiAoZGVzY05hbWUubGVuZ3RoIDwgcGFkKSB7XHJcbiAgICAgICAgICBmb3IgKGxldCBpID0gZGVzY05hbWUubGVuZ3RoOyBpIDwgcGFkOyBpKyspIHtcclxuICAgICAgICAgICAgZGVzY05hbWUgKz0gJy4nO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gRGlzcGxheSBjb3JyZWN0bHkgYWxpZ25lZCBtZXNzYWdlc1xyXG4gICAgICAgIGNvbnNvbGUubG9nKFxyXG4gICAgICAgICAgZGVzY05hbWUsXHJcbiAgICAgICAgICBvcHRpb24uZGVzY3JpcHRpb24sXHJcbiAgICAgICAgICBgW0RlZmF1bHQ6ICR7b3B0aW9uLnZhbHVlLnRvU3RyaW5nKCkuYm9sZH1dYC5ibHVlXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH07XHJcblxyXG4gIC8vIEN5Y2xlIHRocm91Z2ggb3B0aW9ucyBvZiBlYWNoIGNhdGVnb3JpZXMgYW5kIGRpc3BsYXkgdGhlIHVzYWdlIGluZm9cclxuICBPYmplY3Qua2V5cyhkZWZhdWx0Q29uZmlnKS5mb3JFYWNoKChjYXRlZ29yeSkgPT4ge1xyXG4gICAgLy8gT25seSBwdXBwZXRlZXIgYW5kIGhpZ2hjaGFydHMgY2F0ZWdvcmllcyBjYW5ub3QgYmUgY29uZmlndXJlZCB0aHJvdWdoIENMSVxyXG4gICAgaWYgKCFbJ3B1cHBldGVlcicsICdoaWdoY2hhcnRzJ10uaW5jbHVkZXMoY2F0ZWdvcnkpKSB7XHJcbiAgICAgIGNvbnNvbGUubG9nKGBcXG4ke2NhdGVnb3J5LnRvVXBwZXJDYXNlKCl9YC5yZWQpO1xyXG4gICAgICBjeWNsZUNhdGVnb3JpZXMoZGVmYXVsdENvbmZpZ1tjYXRlZ29yeV0pO1xyXG4gICAgfVxyXG4gIH0pO1xyXG4gIGNvbnNvbGUubG9nKCdcXG4nKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFJvdW5kcyBhIG51bWJlciB0byB0aGUgc3BlY2lmaWVkIHByZWNpc2lvbi5cclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IHZhbHVlIC0gVGhlIG51bWJlciB0byBiZSByb3VuZGVkLlxyXG4gKiBAcGFyYW0ge251bWJlcn0gcHJlY2lzaW9uIC0gVGhlIG51bWJlciBvZiBkZWNpbWFsIHBsYWNlcyB0byByb3VuZCB0by5cclxuICpcclxuICogQHJldHVybnMge251bWJlcn0gLSBUaGUgcm91bmRlZCBudW1iZXIuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgcm91bmROdW1iZXIgPSAodmFsdWUsIHByZWNpc2lvbiA9IDEpID0+IHtcclxuICBjb25zdCBtdWx0aXBsaWVyID0gTWF0aC5wb3coMTAsIHByZWNpc2lvbiB8fCAwKTtcclxuICByZXR1cm4gTWF0aC5yb3VuZCgrdmFsdWUgKiBtdWx0aXBsaWVyKSAvIG11bHRpcGxpZXI7XHJcbn07XHJcblxyXG4vKipcclxuICogQ29udmVydHMgYSB2YWx1ZSB0byBhIGJvb2xlYW4uXHJcbiAqXHJcbiAqIEBwYXJhbSB7YW55fSBpdGVtIC0gVGhlIHZhbHVlIHRvIGJlIGNvbnZlcnRlZCB0byBhIGJvb2xlYW4uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtib29sZWFufSAtIFRoZSBib29sZWFuIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBpbnB1dCB2YWx1ZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCB0b0Jvb2xlYW4gPSAoaXRlbSkgPT5cclxuICBbJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJywgJ05hTicsICcwJywgJyddLmluY2x1ZGVzKGl0ZW0pXHJcbiAgICA/IGZhbHNlXHJcbiAgICA6ICEhaXRlbTtcclxuXHJcbi8qKlxyXG4gKiBXcmFwcyBjdXN0b20gY29kZSB0byBleGVjdXRlIGl0IHNhZmVseS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGN1c3RvbUNvZGUgLSBUaGUgY3VzdG9tIGNvZGUgdG8gYmUgd3JhcHBlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBhbGxvd0ZpbGVSZXNvdXJjZXMgLSBGbGFnIHRvIGFsbG93IGxvYWRpbmcgY29kZSBmcm9tIGEgZmlsZS5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ3xib29sZWFufSAtIFRoZSB3cmFwcGVkIGN1c3RvbSBjb2RlIG9yIGZhbHNlIGlmIHdyYXBwaW5nXHJcbiAqIGZhaWxzLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHdyYXBBcm91bmQgPSAoY3VzdG9tQ29kZSwgYWxsb3dGaWxlUmVzb3VyY2VzKSA9PiB7XHJcbiAgaWYgKGN1c3RvbUNvZGUgJiYgdHlwZW9mIGN1c3RvbUNvZGUgPT09ICdzdHJpbmcnKSB7XHJcbiAgICBjdXN0b21Db2RlID0gY3VzdG9tQ29kZS50cmltKCk7XHJcblxyXG4gICAgaWYgKGN1c3RvbUNvZGUuZW5kc1dpdGgoJy5qcycpKSB7XHJcbiAgICAgIHJldHVybiBhbGxvd0ZpbGVSZXNvdXJjZXNcclxuICAgICAgICA/IHdyYXBBcm91bmQocmVhZEZpbGVTeW5jKGN1c3RvbUNvZGUsICd1dGY4JykpXHJcbiAgICAgICAgOiBmYWxzZTtcclxuICAgIH0gZWxzZSBpZiAoXHJcbiAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnZnVuY3Rpb24oKScpIHx8XHJcbiAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnZnVuY3Rpb24gKCknKSB8fFxyXG4gICAgICBjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJygpPT4nKSB8fFxyXG4gICAgICBjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJygpID0+JylcclxuICAgICkge1xyXG4gICAgICByZXR1cm4gYCgke2N1c3RvbUNvZGV9KSgpYDtcclxuICAgIH1cclxuICAgIHJldHVybiBjdXN0b21Db2RlLnJlcGxhY2UoLzskLywgJycpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBVdGlsaXR5IHRvIG1lYXN1cmUgZWxhcHNlZCB0aW1lIHVzaW5nIHRoZSBOb2RlLmpzIHByb2Nlc3MuaHJ0aW1lKCkgbWV0aG9kLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7ZnVuY3Rpb24oKTogbnVtYmVyfSAtIEEgZnVuY3Rpb24gdG8gY2FsY3VsYXRlIHRoZSBlbGFwc2VkIHRpbWVcclxuICogaW4gbWlsbGlzZWNvbmRzLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IG1lYXN1cmVUaW1lID0gKCkgPT4ge1xyXG4gIGNvbnN0IHN0YXJ0ID0gcHJvY2Vzcy5ocnRpbWUuYmlnaW50KCk7XHJcbiAgcmV0dXJuICgpID0+IE51bWJlcihwcm9jZXNzLmhydGltZS5iaWdpbnQoKSAtIHN0YXJ0KSAvIDEwMDAwMDA7XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgX19kaXJuYW1lLFxyXG4gIGNsZWFyVGV4dCxcclxuICBleHBCYWNrb2ZmLFxyXG4gIGZpeFR5cGUsXHJcbiAgaGFuZGxlUmVzb3VyY2VzLFxyXG4gIGlzQ29ycmVjdEpTT04sXHJcbiAgaXNPYmplY3QsXHJcbiAgaXNPYmplY3RFbXB0eSxcclxuICBpc1ByaXZhdGVSYW5nZVVybEZvdW5kLFxyXG4gIG9wdGlvbnNTdHJpbmdpZnksXHJcbiAgcHJpbnRMb2dvLFxyXG4gIHByaW50VXNhZ2UsXHJcbiAgcm91bmROdW1iZXIsXHJcbiAgdG9Cb29sZWFuLFxyXG4gIHdyYXBBcm91bmQsXHJcbiAgbWVhc3VyZVRpbWVcclxufTtcclxuIiwiY2xhc3MgRXhwb3J0RXJyb3IgZXh0ZW5kcyBFcnJvciB7XHJcbiAgY29uc3RydWN0b3IobWVzc2FnZSkge1xyXG4gICAgc3VwZXIoKTtcclxuICAgIHRoaXMubWVzc2FnZSA9IG1lc3NhZ2U7XHJcbiAgICB0aGlzLnN0YWNrTWVzc2FnZSA9IG1lc3NhZ2U7XHJcbiAgfVxyXG5cclxuICBzZXRFcnJvcihlcnJvcikge1xyXG4gICAgdGhpcy5lcnJvciA9IGVycm9yO1xyXG4gICAgaWYgKGVycm9yLm5hbWUpIHtcclxuICAgICAgdGhpcy5uYW1lID0gZXJyb3IubmFtZTtcclxuICAgIH1cclxuICAgIGlmIChlcnJvci5zdGF0dXNDb2RlKSB7XHJcbiAgICAgIHRoaXMuc3RhdHVzQ29kZSA9IGVycm9yLnN0YXR1c0NvZGU7XHJcbiAgICB9XHJcbiAgICBpZiAoZXJyb3Iuc3RhY2spIHtcclxuICAgICAgdGhpcy5zdGFja01lc3NhZ2UgPSBlcnJvci5tZXNzYWdlO1xyXG4gICAgICB0aGlzLnN0YWNrID0gZXJyb3Iuc3RhY2s7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gdGhpcztcclxuICB9XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IEV4cG9ydEVycm9yO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8vIFRoZSBjYWNoZSBtYW5hZ2VyIG1hbmFnZXMgdGhlIEhpZ2hjaGFydHMgbGlicmFyeSBhbmQgaXRzIGRlcGVuZGVuY2llcy5cclxuLy8gVGhlIGNhY2hlIGl0c2VsZiBpcyBzdG9yZWQgaW4gLmNhY2hlLCBhbmQgaXMgY2hlY2tlZCBieSB0aGUgY29uZmlnIHN5c3RlbVxyXG4vLyBiZWZvcmUgc3RhcnRpbmcgdGhlIHNlcnZpY2VcclxuXHJcbmltcG9ydCB7IGV4aXN0c1N5bmMsIG1rZGlyU3luYywgcmVhZEZpbGVTeW5jLCB3cml0ZUZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgeyBIdHRwc1Byb3h5QWdlbnQgfSBmcm9tICdodHRwcy1wcm94eS1hZ2VudCc7XHJcblxyXG5pbXBvcnQgeyBmZXRjaCB9IGZyb20gJy4vZmV0Y2guanMnO1xyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IF9fZGlybmFtZSB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbmNvbnN0IGNhY2hlID0ge1xyXG4gIGNkblVSTDogJ2h0dHBzOi8vY29kZS5oaWdoY2hhcnRzLmNvbS8nLFxyXG4gIGFjdGl2ZU1hbmlmZXN0OiB7fSxcclxuICBzb3VyY2VzOiAnJyxcclxuICBoY1ZlcnNpb246ICcnXHJcbn07XHJcblxyXG4vLyBUT0RPOiBUaGUgY29uZmlnIHNob3VsZCBiZSBhY2Nlc3NzaWJsZSBnbG9iYWxseSBzbyB3ZSBkb24ndCBoYXZlIHRvIGRvIHRoaXMgc29ydCBvZiB0aGluZy4uXHJcbmxldCBhcHBsaWVkQ29uZmlnID0gZmFsc2U7XHJcblxyXG4vKipcclxuICogRXh0cmFjdHMgYW5kIGNhY2hlcyB0aGUgSGlnaGNoYXJ0cyB2ZXJzaW9uIGZyb20gdGhlIHNvdXJjZXMgc3RyaW5nLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgZXh0cmFjdGVkIEhpZ2hjaGFydHMgdmVyc2lvbi5cclxuICovXHJcbmNvbnN0IGV4dHJhY3RWZXJzaW9uID0gKCkgPT5cclxuICAoY2FjaGUuaGNWZXJzaW9uID0gY2FjaGUuc291cmNlc1xyXG4gICAgLnN1YnN0cmluZygwLCBjYWNoZS5zb3VyY2VzLmluZGV4T2YoJyovJykpXHJcbiAgICAucmVwbGFjZSgnLyonLCAnJylcclxuICAgIC5yZXBsYWNlKCcqLycsICcnKVxyXG4gICAgLnJlcGxhY2UoL1xcbi9nLCAnJylcclxuICAgIC50cmltKCkpO1xyXG5cclxuLyoqXHJcbiAqIEV4dHJhY3RzIHRoZSBIaWdoY2hhcnRzIG1vZHVsZSBuYW1lIGJhc2VkIG9uIHRoZSBzY3JpcHRQYXRoLlxyXG4gKi9cclxuY29uc3QgZXh0cmFjdE1vZHVsZU5hbWUgPSAoc2NyaXB0UGF0aCkgPT4ge1xyXG4gIHJldHVybiBzY3JpcHRQYXRoLnJlcGxhY2UoXHJcbiAgICAvKC4qKVxcL3woLiopbW9kdWxlc1xcL3xzdG9ja1xcLyguKilpbmRpY2F0b3JzXFwvfG1hcHNcXC8oLiopbW9kdWxlc1xcLy9naSxcclxuICAgICcnXHJcbiAgKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBTYXZlcyB0aGUgcHJvdmlkZWQgY29uZmlndXJhdGlvbiBhbmQgZmV0Y2hlZCBtb2R1bGVzIHRvIHRoZSBjYWNoZSBtYW5pZmVzdFxyXG4gKiBmaWxlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge29iamVjdH0gY29uZmlnIC0gSGlnaGNoYXJ0cy1yZWxhdGVkIGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxyXG4gKiBAcGFyYW0ge29iamVjdH0gZmV0Y2hlZE1vZHVsZXMgLSBBbiBvYmplY3QgdGhhdCBjb250YWlucyBtYXBwZWQgbmFtZXMgb2ZcclxuICogZmV0Y2hlZCBIaWdoY2hhcnRzIG1vZHVsZXMgdG8gdXNlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIGFuIGVycm9yIG9jY3VycyB3aGlsZSB3cml0aW5nXHJcbiAqIHRoZSBjYWNoZSBtYW5pZmVzdC5cclxuICovXHJcbmNvbnN0IHNhdmVDb25maWdUb01hbmlmZXN0ID0gYXN5bmMgKGNvbmZpZywgZmV0Y2hlZE1vZHVsZXMpID0+IHtcclxuICBjb25zdCBuZXdNYW5pZmVzdCA9IHtcclxuICAgIHZlcnNpb246IGNvbmZpZy52ZXJzaW9uLFxyXG4gICAgbW9kdWxlczogZmV0Y2hlZE1vZHVsZXMgfHwge31cclxuICB9O1xyXG5cclxuICAvLyBVcGRhdGUgY2FjaGUgb2JqZWN0IHdpdGggdGhlIGN1cnJlbnQgbW9kdWxlc1xyXG4gIGNhY2hlLmFjdGl2ZU1hbmlmZXN0ID0gbmV3TWFuaWZlc3Q7XHJcblxyXG4gIGxvZygzLCAnW2NhY2hlXSBXcml0aW5nIGEgbmV3IG1hbmlmZXN0LicpO1xyXG4gIHRyeSB7XHJcbiAgICB3cml0ZUZpbGVTeW5jKFxyXG4gICAgICBqb2luKF9fZGlybmFtZSwgY29uZmlnLmNhY2hlUGF0aCwgJ21hbmlmZXN0Lmpzb24nKSxcclxuICAgICAgSlNPTi5zdHJpbmdpZnkobmV3TWFuaWZlc3QpLFxyXG4gICAgICAndXRmOCdcclxuICAgICk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW2NhY2hlXSBFcnJvciB3cml0aW5nIHRoZSBjYWNoZSBtYW5pZmVzdC4nKS5zZXRFcnJvcihcclxuICAgICAgZXJyb3JcclxuICAgICk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEZldGNoZXMgYSBzaW5nbGUgc2NyaXB0IGFuZCB1cGRhdGVzIHRoZSBmZXRjaGVkTW9kdWxlcyBhY2NvcmRpbmdseS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHNjcmlwdCAtIEEgcGF0aCB0byBzY3JpcHQgdG8gZ2V0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcHJveHlBZ2VudCAtIFRoZSBwcm94eSBhZ2VudCB0byB1c2UgZm9yIGEgcmVxdWVzdC5cclxuICogQHBhcmFtIHtPYmplY3R9IGZldGNoZWRNb2R1bGVzIC0gQW4gb2JqZWN0IHdoaWNoIHRyYWNrcyB3aGljaCBIaWdoY2hhcnRzIG1vZHVsZXMgaGF2ZSBiZWVuIGZldGNoZWQuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gc2hvdWxkVGhyb3dFcnJvciAtIEEgZmxhZyB0byBpbmRpY2F0ZSBpZiB0aGUgZXJyb3Igc2hvdWxkIGJlIHRocm93bi4gVGhpcyBzaG91bGQgYmUgdXNlZCBvbmx5IGZvciB0aGUgY29yZSBzY3JpcHRzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSB0ZXh0IHJlcHJlc2VudGF0aW9uXHJcbiAqIG9mIHRoZSBmZXRjaGVkIHNjcmlwdC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiB0aGVyZSBpcyBhIHByb2JsZW0gd2l0aFxyXG4gKiBmZXRjaGluZyB0aGUgc2NyaXB0LlxyXG4gKi9cclxuY29uc3QgZmV0Y2hBbmRQcm9jZXNzU2NyaXB0ID0gYXN5bmMgKFxyXG4gIHNjcmlwdCxcclxuICBwcm94eUFnZW50LFxyXG4gIGZldGNoZWRNb2R1bGVzLFxyXG4gIHNob3VsZFRocm93RXJyb3IgPSBmYWxzZVxyXG4pID0+IHtcclxuICAvLyBHZXQgcmlkIG9mIHRoZSAuanMgZnJvbSB0aGUgY3VzdG9tIHN0cmluZ3NcclxuICBpZiAoc2NyaXB0LmVuZHNXaXRoKCcuanMnKSkge1xyXG4gICAgc2NyaXB0ID0gc2NyaXB0LnN1YnN0cmluZygwLCBzY3JpcHQubGVuZ3RoIC0gMyk7XHJcbiAgfVxyXG5cclxuICBsb2coNCwgYFtjYWNoZV0gRmV0Y2hpbmcgc2NyaXB0IC0gJHtzY3JpcHR9LmpzYCk7XHJcblxyXG4gIC8vIElmIGV4aXN0cywgYWRkIHByb3h5IGFnZW50IHRvIHJlcXVlc3Qgb3B0aW9uc1xyXG4gIGNvbnN0IHJlcXVlc3RPcHRpb25zID0gcHJveHlBZ2VudFxyXG4gICAgPyB7XHJcbiAgICAgICAgYWdlbnQ6IHByb3h5QWdlbnQsXHJcbiAgICAgICAgdGltZW91dDogK3Byb2Nlc3MuZW52WydQUk9YWV9TRVJWRVJfVElNRU9VVCddIHx8IDUwMDBcclxuICAgICAgfVxyXG4gICAgOiB7fTtcclxuXHJcbiAgLy8gRmV0Y2ggdGhlIHNjcmlwdFxyXG4gIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2goYCR7c2NyaXB0fS5qc2AsIHJlcXVlc3RPcHRpb25zKTtcclxuXHJcbiAgLy8gSWYgT0ssIHJldHVybiBpdHMgdGV4dCByZXByZXNlbnRhdGlvblxyXG4gIGlmIChyZXNwb25zZS5zdGF0dXNDb2RlID09PSAyMDAgJiYgdHlwZW9mIHJlc3BvbnNlLnRleHQgPT0gJ3N0cmluZycpIHtcclxuICAgIGlmIChmZXRjaGVkTW9kdWxlcykge1xyXG4gICAgICBjb25zdCBtb2R1bGVOYW1lID0gZXh0cmFjdE1vZHVsZU5hbWUoc2NyaXB0KTtcclxuICAgICAgZmV0Y2hlZE1vZHVsZXNbbW9kdWxlTmFtZV0gPSAxO1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiByZXNwb25zZS50ZXh0O1xyXG4gIH1cclxuXHJcbiAgaWYgKHNob3VsZFRocm93RXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgYENvdWxkIG5vdCBmZXRjaCB0aGUgJHtzY3JpcHR9LmpzLiBUaGUgc2NyaXB0IG1pZ2h0IG5vdCBleGlzdCBpbiB0aGUgcmVxdWVzdGVkIHZlcnNpb24gKHN0YXR1cyBjb2RlOiAke3Jlc3BvbnNlLnN0YXR1c0NvZGV9KS5gXHJcbiAgICApLnNldEVycm9yKHJlc3BvbnNlKTtcclxuICB9IGVsc2Uge1xyXG4gICAgbG9nKFxyXG4gICAgICAyLFxyXG4gICAgICBgW2NhY2hlXSBDb3VsZCBub3QgZmV0Y2ggdGhlICR7c2NyaXB0fS5qcy4gVGhlIHNjcmlwdCBtaWdodCBub3QgZXhpc3QgaW4gdGhlIHJlcXVlc3RlZCB2ZXJzaW9uLmBcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICByZXR1cm4gJyc7XHJcbn07XHJcblxyXG4vKipcclxuICogRmV0Y2hlcyBIaWdoY2hhcnRzIHNjcmlwdHMgYW5kIGN1c3RvbVNjcmlwdHMgZnJvbSB0aGUgZ2l2ZW4gQ0ROcy5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHNjcmlwdHMgLSBBcnJheSBvZiBIaWdoY2hhcnRzIG1vZHVsZXMgdG8gZmV0Y2guXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBjdXN0b21TY3JpcHRzIC0gQXJyYXkgb2YgY3VzdG9tIHNjcmlwdCBwYXRocyB0byBmZXRjaCAoZnVsbCBVUkxzKS5cclxuICogQHBhcmFtIHtvYmplY3R9IHByb3h5QWdlbnQgLSBUaGUgcHJveHkgYWdlbnQgdG8gdXNlIGZvciBhIHJlcXVlc3QuXHJcbiAqIEBwYXJhbSB7b2JqZWN0fSBmZXRjaGVkTW9kdWxlcyAtIEFuIG9iamVjdCB3aGljaCB0cmFja3Mgd2hpY2ggSGlnaGNoYXJ0cyBtb2R1bGVzIGhhdmUgYmVlbiBmZXRjaGVkLlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSBUaGUgZmV0Y2hlZCBzY3JpcHRzIGNvbnRlbnQgam9pbmVkLlxyXG4gKi9cclxuY29uc3QgZmV0Y2hTY3JpcHRzID0gYXN5bmMgKFxyXG4gIGNvcmVTY3JpcHRzLFxyXG4gIG1vZHVsZVNjcmlwdHMsXHJcbiAgY3VzdG9tU2NyaXB0cyxcclxuICBjZG5VUkwsXHJcbiAgcHJveHlBZ2VudCxcclxuICBmZXRjaGVkTW9kdWxlc1xyXG4pID0+IHtcclxuICBjb25zdCBhbGxGZXRjaFByb21pc2VzID0gW1xyXG4gICAgLi4uY29yZVNjcmlwdHMubWFwKChzY3JpcHQpID0+XHJcbiAgICAgIGZldGNoQW5kUHJvY2Vzc1NjcmlwdChcclxuICAgICAgICBgJHtjZG5VUkx9JHtzY3JpcHR9YCxcclxuICAgICAgICBwcm94eUFnZW50LFxyXG4gICAgICAgIGZldGNoZWRNb2R1bGVzLFxyXG4gICAgICAgIHRydWVcclxuICAgICAgKVxyXG4gICAgKSxcclxuICAgIC4uLm1vZHVsZVNjcmlwdHMubWFwKChzY3JpcHQpID0+XHJcbiAgICAgIGZldGNoQW5kUHJvY2Vzc1NjcmlwdChgJHtjZG5VUkx9JHtzY3JpcHR9YCwgcHJveHlBZ2VudCwgZmV0Y2hlZE1vZHVsZXMpXHJcbiAgICApLFxyXG4gICAgLi4uY3VzdG9tU2NyaXB0cy5tYXAoKHNjcmlwdCkgPT5cclxuICAgICAgZmV0Y2hBbmRQcm9jZXNzU2NyaXB0KGAke3NjcmlwdH1gLCBwcm94eUFnZW50KVxyXG4gICAgKVxyXG4gIF07XHJcblxyXG4gIGNvbnN0IGZldGNoZWRTY3JpcHRzID0gYXdhaXQgUHJvbWlzZS5hbGwoYWxsRmV0Y2hQcm9taXNlcyk7XHJcbiAgcmV0dXJuIGZldGNoZWRTY3JpcHRzLmpvaW4oJztcXG4nKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBVcGRhdGVzIHRoZSBsb2NhbCBjYWNoZSB3aXRoIEhpZ2hjaGFydHMgc2NyaXB0cyBhbmQgdGhlaXIgdmVyc2lvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjb25maWcgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZyBpbmZvcm1hdGlvblxyXG4gKiBhYm91dCBzY3JpcHRzIGFuZCBtb2R1bGVzLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gc291cmNlUGF0aCAtIFRoZSBwYXRoIHRvIHRoZSBzb3VyY2UgZmlsZSBpbiB0aGUgY2FjaGUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPG9iamVjdD59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gYW4gb2JqZWN0IHJlcHJlc2VudGluZ1xyXG4gKiB0aGUgZmV0Y2hlZCBtb2R1bGVzLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIHRoZXJlIGlzIGFuIGlzc3VlIHVwZGF0aW5nXHJcbiAqIHRoZSBsb2NhbCBIaWdoY2hhcnRzIGNhY2hlLlxyXG4gKi9cclxuY29uc3QgdXBkYXRlQ2FjaGUgPSBhc3luYyAoY29uZmlnLCBzb3VyY2VQYXRoKSA9PiB7XHJcbiAgY29uc3QgeyBjb3JlU2NyaXB0cywgbW9kdWxlcywgaW5kaWNhdG9ycywgc2NyaXB0czogY3VzdG9tU2NyaXB0cyB9ID0gY29uZmlnO1xyXG4gIGNvbnN0IGhjVmVyc2lvbiA9XHJcbiAgICBjb25maWcudmVyc2lvbiA9PT0gJ2xhdGVzdCcgfHwgIWNvbmZpZy52ZXJzaW9uID8gJycgOiBgJHtjb25maWcudmVyc2lvbn0vYDtcclxuXHJcbiAgbG9nKFxyXG4gICAgMyxcclxuICAgIGBbY2FjaGVdIFVwZGF0aW5nIGNhY2hlIHZlcnNpb24gdG8gSGlnaGNoYXJ0czogJHtoY1ZlcnNpb24gfHwgJ2xhdGVzdCd9LmBcclxuICApO1xyXG5cclxuICAvLyBDb25maWd1cmUgcHJveHkgaWYgZXhpc3RzXHJcbiAgbGV0IHByb3h5QWdlbnQ7XHJcbiAgY29uc3QgcHJveHlIb3N0ID0gcHJvY2Vzcy5lbnZbJ1BST1hZX1NFUlZFUl9IT1NUJ107XHJcbiAgY29uc3QgcHJveHlQb3J0ID0gcHJvY2Vzcy5lbnZbJ1BST1hZX1NFUlZFUl9QT1JUJ107XHJcblxyXG4gIC8vIFRyeSB0byBjcmVhdGUgYSBQcm94eSBBZ2VudFxyXG4gIGlmIChwcm94eUhvc3QgJiYgcHJveHlQb3J0KSB7XHJcbiAgICB0cnkge1xyXG4gICAgICBwcm94eUFnZW50ID0gbmV3IEh0dHBzUHJveHlBZ2VudCh7XHJcbiAgICAgICAgaG9zdDogcHJveHlIb3N0LFxyXG4gICAgICAgIHBvcnQ6ICtwcm94eVBvcnRcclxuICAgICAgfSk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1tjYWNoZV0gQ291bGQgbm90IGNyZWF0ZSBhIFByb3h5IEFnZW50LicpLnNldEVycm9yKFxyXG4gICAgICAgIGVycm9yXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBjb25zdCBmZXRjaGVkTW9kdWxlcyA9IHt9O1xyXG4gIHRyeSB7XHJcbiAgICBjYWNoZS5zb3VyY2VzID0gYXdhaXQgZmV0Y2hTY3JpcHRzKFxyXG4gICAgICBbLi4uY29yZVNjcmlwdHMubWFwKChjKSA9PiBgJHtoY1ZlcnNpb259JHtjfWApXSxcclxuICAgICAgW1xyXG4gICAgICAgIC4uLm1vZHVsZXMubWFwKChtKSA9PlxyXG4gICAgICAgICAgbSA9PT0gJ21hcCdcclxuICAgICAgICAgICAgPyBgbWFwcy8ke2hjVmVyc2lvbn1tb2R1bGVzLyR7bX1gXHJcbiAgICAgICAgICAgIDogYCR7aGNWZXJzaW9ufW1vZHVsZXMvJHttfWBcclxuICAgICAgICApLFxyXG4gICAgICAgIC4uLmluZGljYXRvcnMubWFwKChpKSA9PiBgc3RvY2svJHtoY1ZlcnNpb259aW5kaWNhdG9ycy8ke2l9YClcclxuICAgICAgXSxcclxuICAgICAgY3VzdG9tU2NyaXB0cyxcclxuICAgICAgY29uZmlnLmNkblVSTCB8fCBjYWNoZS5jZG5VUkwsXHJcbiAgICAgIHByb3h5QWdlbnQsXHJcbiAgICAgIGZldGNoZWRNb2R1bGVzXHJcbiAgICApO1xyXG4gICAgZXh0cmFjdFZlcnNpb24oKTtcclxuXHJcbiAgICAvLyBTYXZlIHRoZSBmZXRjaGVkIG1vZHVsZXMgaW50byBjYWNoZXMnIHNvdXJjZSBKU09OXHJcbiAgICB3cml0ZUZpbGVTeW5jKHNvdXJjZVBhdGgsIGNhY2hlLnNvdXJjZXMpO1xyXG4gICAgcmV0dXJuIGZldGNoZWRNb2R1bGVzO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbY2FjaGVdIFVuYWJsZSB0byB1cGRhdGUgdGhlIGxvY2FsIEhpZ2hjaGFydHMgY2FjaGUuJ1xyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIFVwZGF0ZXMgdGhlIEhpZ2hjaGFydHMgdmVyc2lvbiBpbiB0aGUgYXBwbGllZCBjb25maWd1cmF0aW9uIGFuZCBjaGVja3NcclxuICogdGhlIGNhY2hlIGZvciB0aGUgbmV3IHZlcnNpb24uXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBuZXdWZXJzaW9uIC0gVGhlIG5ldyBIaWdoY2hhcnRzIHZlcnNpb24gdG8gYmUgYXBwbGllZC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8KG9iamVjdHxib29sZWFuKT59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIHVwZGF0ZWRcclxuICogY29uZmlndXJhdGlvbiB3aXRoIHRoZSBuZXcgdmVyc2lvbiwgb3IgZmFsc2UgaWYgbm8gYXBwbGllZCBjb25maWd1cmF0aW9uXHJcbiAqIGV4aXN0cy5cclxuICovXHJcbmV4cG9ydCBjb25zdCB1cGRhdGVWZXJzaW9uID0gYXN5bmMgKG5ld1ZlcnNpb24pID0+XHJcbiAgYXBwbGllZENvbmZpZ1xyXG4gICAgPyBhd2FpdCBjaGVja0FuZFVwZGF0ZUNhY2hlKFxyXG4gICAgICAgIE9iamVjdC5hc3NpZ24oYXBwbGllZENvbmZpZywge1xyXG4gICAgICAgICAgdmVyc2lvbjogbmV3VmVyc2lvblxyXG4gICAgICAgIH0pXHJcbiAgICAgIClcclxuICAgIDogZmFsc2U7XHJcblxyXG4vKipcclxuICogQ2hlY2tzIHRoZSBjYWNoZSBmb3IgSGlnaGNoYXJ0cyBkZXBlbmRlbmNpZXMsIHVwZGF0ZXMgdGhlIGNhY2hlIGlmIG5lZWRlZCxcclxuICogYW5kIGxvYWRzIHRoZSBzb3VyY2VzLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnIC0gSGlnaGNoYXJ0cy1yZWxhdGVkIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmcgaW5mb3JtYXRpb25cclxuICogYWJvdXQgc2NyaXB0cyBhbmQgbW9kdWxlcy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgdGhlIGNhY2hlIGlzIGNoZWNrZWRcclxuICogYW5kIHVwZGF0ZWQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgdGhlcmUgaXMgYW4gaXNzdWUgdXBkYXRpbmdcclxuICogb3IgcmVhZGluZyB0aGUgY2FjaGUuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgY2hlY2tBbmRVcGRhdGVDYWNoZSA9IGFzeW5jIChjb25maWcpID0+IHtcclxuICBjb25zdCBjYWNoZVBhdGggPSBqb2luKF9fZGlybmFtZSwgY29uZmlnLmNhY2hlUGF0aCk7XHJcblxyXG4gIGxldCBmZXRjaGVkTW9kdWxlcztcclxuICAvLyBQcmVwYXJlIHBhdGhzIHRvIG1hbmlmZXN0IGFuZCBzb3VyY2VzIGZyb20gdGhlIC5jYWNoZSBmb2xkZXJcclxuICBjb25zdCBtYW5pZmVzdFBhdGggPSBqb2luKGNhY2hlUGF0aCwgJ21hbmlmZXN0Lmpzb24nKTtcclxuICBjb25zdCBzb3VyY2VQYXRoID0gam9pbihjYWNoZVBhdGgsICdzb3VyY2VzLmpzJyk7XHJcblxyXG4gIC8vIFRPRE86IGRlYWwgd2l0aCB0cnlpbmcgdG8gc3dpdGNoIHRvIHRoZSBydW5uaW5nIHZlcnNpb25cclxuICAvLyBjb25zdCBhY3RpdmVWZXJzaW9uID0gYXBwbGllZENvbmZpZyA/IGFwcGxpZWRDb25maWcudmVyc2lvbiA6IGZhbHNlO1xyXG5cclxuICBhcHBsaWVkQ29uZmlnID0gY29uZmlnO1xyXG5cclxuICAvLyBDcmVhdGUgdGhlIGNhY2hlIGRlc3RpbmF0aW9uIGlmIGl0IGRvZXNuJ3QgZXhpc3QgYWxyZWFkeVxyXG4gICFleGlzdHNTeW5jKGNhY2hlUGF0aCkgJiYgbWtkaXJTeW5jKGNhY2hlUGF0aCk7XHJcblxyXG4gIC8vIEZldGNoIGFsbCB0aGUgc2NyaXB0cyBlaXRoZXIgaWYgbWFuaWZlc3QuanNvbiBkb2VzIG5vdCBleGlzdFxyXG4gIC8vIG9yIGlmIHRoZSBmb3JjZUZldGNoIG9wdGlvbiBpcyBlbmFibGVkXHJcbiAgaWYgKCFleGlzdHNTeW5jKG1hbmlmZXN0UGF0aCkgfHwgY29uZmlnLmZvcmNlRmV0Y2gpIHtcclxuICAgIGxvZygzLCAnW2NhY2hlXSBGZXRjaGluZyBhbmQgY2FjaGluZyBIaWdoY2hhcnRzIGRlcGVuZGVuY2llcy4nKTtcclxuICAgIGZldGNoZWRNb2R1bGVzID0gYXdhaXQgdXBkYXRlQ2FjaGUoY29uZmlnLCBzb3VyY2VQYXRoKTtcclxuICB9IGVsc2Uge1xyXG4gICAgbGV0IHJlcXVlc3RVcGRhdGUgPSBmYWxzZTtcclxuXHJcbiAgICAvLyBSZWFkIHRoZSBtYW5pZmVzdCBKU09OXHJcbiAgICBjb25zdCBtYW5pZmVzdCA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKG1hbmlmZXN0UGF0aCkpO1xyXG5cclxuICAgIC8vIENoZWNrIGlmIHRoZSBtb2R1bGVzIGlzIGFuIGFycmF5LCBpZiBzbywgd2UgcmV3cml0ZSBpdCB0byBhIG1hcCB0byBtYWtlXHJcbiAgICAvLyBpdCBlYXNpZXIgdG8gcmVzb2x2ZSBtb2R1bGVzLlxyXG4gICAgaWYgKG1hbmlmZXN0Lm1vZHVsZXMgJiYgQXJyYXkuaXNBcnJheShtYW5pZmVzdC5tb2R1bGVzKSkge1xyXG4gICAgICBjb25zdCBtb2R1bGVNYXAgPSB7fTtcclxuICAgICAgbWFuaWZlc3QubW9kdWxlcy5mb3JFYWNoKChtKSA9PiAobW9kdWxlTWFwW21dID0gMSkpO1xyXG4gICAgICBtYW5pZmVzdC5tb2R1bGVzID0gbW9kdWxlTWFwO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IHsgbW9kdWxlcywgY29yZVNjcmlwdHMsIGluZGljYXRvcnMgfSA9IGNvbmZpZztcclxuICAgIGNvbnN0IG51bWJlck9mTW9kdWxlcyA9XHJcbiAgICAgIG1vZHVsZXMubGVuZ3RoICsgY29yZVNjcmlwdHMubGVuZ3RoICsgaW5kaWNhdG9ycy5sZW5ndGg7XHJcblxyXG4gICAgLy8gQ29tcGFyZSB0aGUgbG9hZGVkIGNvbmZpZyB3aXRoIHRoZSBjb250ZW50cyBpbiBjYWNoZS5cclxuICAgIC8vIElmIHRoZXJlIGFyZSBjaGFuZ2VzLCBmZXRjaCByZXF1ZXN0ZWQgbW9kdWxlcyBhbmQgcHJvZHVjdHMsXHJcbiAgICAvLyBhbmQgYmFrZSB0aGVtIGludG8gYSBnaWFudCBibG9iLiBTYXZlIHRoZSBibG9iLlxyXG4gICAgaWYgKG1hbmlmZXN0LnZlcnNpb24gIT09IGNvbmZpZy52ZXJzaW9uKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICAyLFxyXG4gICAgICAgICdbY2FjaGVdIEEgSGlnaGNoYXJ0cyB2ZXJzaW9uIG1pc21hdGNoIGluIHRoZSBjYWNoZSwgbmVlZCB0byByZS1mZXRjaC4nXHJcbiAgICAgICk7XHJcbiAgICAgIHJlcXVlc3RVcGRhdGUgPSB0cnVlO1xyXG4gICAgfSBlbHNlIGlmIChPYmplY3Qua2V5cyhtYW5pZmVzdC5tb2R1bGVzIHx8IHt9KS5sZW5ndGggIT09IG51bWJlck9mTW9kdWxlcykge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgMixcclxuICAgICAgICAnW2NhY2hlXSBUaGUgY2FjaGUgYW5kIHRoZSByZXF1ZXN0ZWQgbW9kdWxlcyBkbyBub3QgbWF0Y2gsIG5lZWQgdG8gcmUtZmV0Y2guJ1xyXG4gICAgICApO1xyXG4gICAgICByZXF1ZXN0VXBkYXRlID0gdHJ1ZTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIENoZWNrIGVhY2ggbW9kdWxlLCBpZiBhbnl0aGluZyBpcyBtaXNzaW5nIHJlZmV0Y2ggZXZlcnl0aGluZ1xyXG4gICAgICByZXF1ZXN0VXBkYXRlID0gKGNvbmZpZy5tb2R1bGVzIHx8IFtdKS5zb21lKChtb2R1bGVOYW1lKSA9PiB7XHJcbiAgICAgICAgaWYgKCFtYW5pZmVzdC5tb2R1bGVzW21vZHVsZU5hbWVdKSB7XHJcbiAgICAgICAgICBsb2coXHJcbiAgICAgICAgICAgIDIsXHJcbiAgICAgICAgICAgIGBbY2FjaGVdIFRoZSAke21vZHVsZU5hbWV9IGlzIG1pc3NpbmcgaW4gdGhlIGNhY2hlLCBuZWVkIHRvIHJlLWZldGNoLmBcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgICB9XHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChyZXF1ZXN0VXBkYXRlKSB7XHJcbiAgICAgIGZldGNoZWRNb2R1bGVzID0gYXdhaXQgdXBkYXRlQ2FjaGUoY29uZmlnLCBzb3VyY2VQYXRoKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIGxvZygzLCAnW2NhY2hlXSBEZXBlbmRlbmN5IGNhY2hlIGlzIHVwIHRvIGRhdGUsIHByb2NlZWRpbmcuJyk7XHJcblxyXG4gICAgICAvLyBMb2FkIHRoZSBzb3VyY2VzXHJcbiAgICAgIGNhY2hlLnNvdXJjZXMgPSByZWFkRmlsZVN5bmMoc291cmNlUGF0aCwgJ3V0ZjgnKTtcclxuXHJcbiAgICAgIC8vIEdldCBjdXJyZW50IG1vZHVsZXMgbWFwXHJcbiAgICAgIGZldGNoZWRNb2R1bGVzID0gbWFuaWZlc3QubW9kdWxlcztcclxuICAgICAgZXh0cmFjdFZlcnNpb24oKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIEZpbmFsbHksIHNhdmUgdGhlIG5ldyBtYW5pZmVzdCwgd2hpY2ggaXMgYmFzaWNhbGx5IG91ciBjdXJyZW50IGNvbmZpZ1xyXG4gIC8vIGluIGEgc2xpZ2h0bHkgZGlmZmVyZW50IGZvcm1hdFxyXG4gIGF3YWl0IHNhdmVDb25maWdUb01hbmlmZXN0KGNvbmZpZywgZmV0Y2hlZE1vZHVsZXMpO1xyXG59O1xyXG5cclxuZXhwb3J0IGNvbnN0IGdldENhY2hlUGF0aCA9ICgpID0+IHtcclxuICByZXR1cm4gam9pbihfX2Rpcm5hbWUsIGFwcGxpZWRDb25maWcuY2FjaGVQYXRoKTtcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBjaGVja0FuZFVwZGF0ZUNhY2hlLFxyXG4gIGdldENhY2hlUGF0aCxcclxuICB1cGRhdGVWZXJzaW9uLFxyXG4gIGdldENhY2hlOiAoKSA9PiBjYWNoZSxcclxuICBoaWdoY2hhcnRzOiAoKSA9PiBjYWNoZS5zb3VyY2VzLFxyXG4gIHZlcnNpb246ICgpID0+IGNhY2hlLmhjVmVyc2lvblxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IGV4aXN0c1N5bmMsIHJlYWRGaWxlU3luYywgcHJvbWlzZXMgYXMgZnNQcm9taXNlcyB9IGZyb20gJ2ZzJztcclxuXHJcbmltcG9ydCBwcm9tcHRzIGZyb20gJ3Byb21wdHMnO1xyXG5cclxuaW1wb3J0IHtcclxuICBhYnNvbHV0ZVByb3BzLFxyXG4gIGRlZmF1bHRDb25maWcsXHJcbiAgbmVzdGVkQXJncyxcclxuICBwcm9tcHRzQ29uZmlnXHJcbn0gZnJvbSAnLi9zY2hlbWFzL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBkZWVwQ29weSwgaXNPYmplY3QsIHByaW50VXNhZ2UsIHRvQm9vbGVhbiB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxubGV0IGdlbmVyYWxPcHRpb25zID0ge307XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIGFuZCByZXR1cm5zIHRoZSBnZW5lcmFsIG9wdGlvbnMgZm9yIHRoZSBleHBvcnQgcHJvY2Vzcy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIGdlbmVyYWwgb3B0aW9ucyBvYmplY3QuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0T3B0aW9ucyA9ICgpID0+IGdlbmVyYWxPcHRpb25zO1xyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIGFuZCBzZXRzIHRoZSBnZW5lcmFsIG9wdGlvbnMgZm9yIHRoZSBzZXJ2ZXIgaW5zdGFjZSwga2VlcGluZ1xyXG4gKiB0aGUgcHJpbmNpcGxlIG9mIHRoZSBvcHRpb25zIGxvYWQgcHJpb3JpdHkuIEl0IGFjY2VwdHMgb3B0aW9uYWwgdXNlck9wdGlvbnNcclxuICogYW5kIGFyZ3MgZnJvbSB0aGUgQ0xJLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gdXNlck9wdGlvbnMgLSBVc2VyLXByb3ZpZGVkIG9wdGlvbnMgZm9yIGN1c3RvbWl6YXRpb24uXHJcbiAqIEBwYXJhbSB7QXJyYXl9IGFyZ3MgLSBDb21tYW5kLWxpbmUgYXJndW1lbnRzIGZvciBhZGRpdGlvbmFsIGNvbmZpZ3VyYXRpb25cclxuICogKENMSSB1c2FnZSkuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSB1cGRhdGVkIGdlbmVyYWwgb3B0aW9ucyBvYmplY3QuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2V0T3B0aW9ucyA9ICh1c2VyT3B0aW9ucywgYXJncykgPT4ge1xyXG4gIC8vIE9ubHkgZm9yIHRoZSBDTEkgdXNhZ2VcclxuICBpZiAoYXJncz8ubGVuZ3RoKSB7XHJcbiAgICAvLyBHZXQgdGhlIGFkZGl0aW9uYWwgb3B0aW9ucyBmcm9tIHRoZSBjdXN0b20gSlNPTiBmaWxlXHJcbiAgICBnZW5lcmFsT3B0aW9ucyA9IGxvYWRDb25maWdGaWxlKGFyZ3MpO1xyXG4gIH1cclxuXHJcbiAgLy8gVXBkYXRlIHRoZSBkZWZhdWx0IGNvbmZpZyB3aXRoIGEgY29ycmVjdCBvcHRpb24gdmFsdWVzXHJcbiAgdXBkYXRlRGVmYXVsdENvbmZpZyhkZWZhdWx0Q29uZmlnLCBnZW5lcmFsT3B0aW9ucyk7XHJcblxyXG4gIC8vIFNldCB2YWx1ZXMgZm9yIHNlcnZlcidzIG9wdGlvbnMgYW5kIHJldHVybnMgdGhlbVxyXG4gIGdlbmVyYWxPcHRpb25zID0gaW5pdE9wdGlvbnMoZGVmYXVsdENvbmZpZyk7XHJcblxyXG4gIC8vIEFwcGx5IHVzZXIgb3B0aW9ucyBpZiB0aGVyZSBhcmUgYW55XHJcbiAgaWYgKHVzZXJPcHRpb25zKSB7XHJcbiAgICAvLyBNZXJnZSB1c2VyIG9wdGlvbnNcclxuICAgIGdlbmVyYWxPcHRpb25zID0gbWVyZ2VDb25maWdPcHRpb25zKFxyXG4gICAgICBnZW5lcmFsT3B0aW9ucyxcclxuICAgICAgdXNlck9wdGlvbnMsXHJcbiAgICAgIGFic29sdXRlUHJvcHNcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICAvLyBPbmx5IGZvciB0aGUgQ0xJIHVzYWdlXHJcbiAgaWYgKGFyZ3M/Lmxlbmd0aCkge1xyXG4gICAgLy8gUGFpciBwcm92aWRlZCBhcmd1bWVudHNcclxuICAgIGdlbmVyYWxPcHRpb25zID0gcGFpckFyZ3VtZW50VmFsdWUoZ2VuZXJhbE9wdGlvbnMsIGFyZ3MsIGRlZmF1bHRDb25maWcpO1xyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIGZpbmFsIGdlbmVyYWwgb3B0aW9uc1xyXG4gIHJldHVybiBnZW5lcmFsT3B0aW9ucztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBBbGxvd3MgbWFudWFsIGNvbmZpZ3VyYXRpb24gYmFzZWQgb24gc3BlY2lmaWVkIHByb21wdHMgYW5kIHNhdmVzXHJcbiAqIHRoZSBjb25maWd1cmF0aW9uIHRvIGEgZmlsZS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGNvbmZpZ0ZpbGVOYW1lIC0gVGhlIG5hbWUgb2YgdGhlIGNvbmZpZ3VyYXRpb24gZmlsZS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8Ym9vbGVhbj59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRydWUgb25jZSB0aGUgbWFudWFsXHJcbiAqIGNvbmZpZ3VyYXRpb24gaXMgY29tcGxldGVkIGFuZCBzYXZlZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBtYW51YWxDb25maWcgPSBhc3luYyAoY29uZmlnRmlsZU5hbWUpID0+IHtcclxuICAvLyBQcmVwYXJlIGEgY29uZmlnIG9iamVjdFxyXG4gIGxldCBjb25maWdGaWxlID0ge307XHJcblxyXG4gIC8vIENoZWNrIGlmIHByb3ZpZGVkIGNvbmZpZyBmaWxlIGV4aXN0c1xyXG4gIGlmIChleGlzdHNTeW5jKGNvbmZpZ0ZpbGVOYW1lKSkge1xyXG4gICAgY29uZmlnRmlsZSA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKGNvbmZpZ0ZpbGVOYW1lLCAndXRmOCcpKTtcclxuICB9XHJcblxyXG4gIC8vIFF1ZXN0aW9uIGFib3V0IGEgY29uZmlndXJhdGlvbiBjYXRlZ29yeVxyXG4gIGNvbnN0IG9uU3VibWl0ID0gYXN5bmMgKHAsIGNhdGVnb3JpZXMpID0+IHtcclxuICAgIGxldCBxdWVzdGlvbnNDb3VudGVyID0gMDtcclxuICAgIGxldCBhbGxRdWVzdGlvbnMgPSBbXTtcclxuXHJcbiAgICAvLyBDcmVhdGUgYSBjb3JyZXNwb25kaW5nIHByb3BlcnR5IGluIHRoZSBtYW51YWxDb25maWcgb2JqZWN0XHJcbiAgICBmb3IgKGNvbnN0IHNlY3Rpb24gb2YgY2F0ZWdvcmllcykge1xyXG4gICAgICAvLyBNYXJrIGVhY2ggb3B0aW9uIHdpdGggYSBzZWN0aW9uXHJcbiAgICAgIHByb21wdHNDb25maWdbc2VjdGlvbl0gPSBwcm9tcHRzQ29uZmlnW3NlY3Rpb25dLm1hcCgob3B0aW9uKSA9PiAoe1xyXG4gICAgICAgIC4uLm9wdGlvbixcclxuICAgICAgICBzZWN0aW9uXHJcbiAgICAgIH0pKTtcclxuXHJcbiAgICAgIC8vIENvbGxlY3QgdGhlIHF1ZXN0aW9uc1xyXG4gICAgICBhbGxRdWVzdGlvbnMgPSBbLi4uYWxsUXVlc3Rpb25zLCAuLi5wcm9tcHRzQ29uZmlnW3NlY3Rpb25dXTtcclxuICAgIH1cclxuXHJcbiAgICBhd2FpdCBwcm9tcHRzKGFsbFF1ZXN0aW9ucywge1xyXG4gICAgICBvblN1Ym1pdDogYXN5bmMgKHByb21wdCwgYW5zd2VyKSA9PiB7XHJcbiAgICAgICAgLy8gR2V0IHRoZSBkZWZhdWx0IG1vZHVsZXNcclxuICAgICAgICBpZiAocHJvbXB0Lm5hbWUgPT09ICdtb2R1bGVzJykge1xyXG4gICAgICAgICAgYW5zd2VyID0gYW5zd2VyLmxlbmd0aFxyXG4gICAgICAgICAgICA/IGFuc3dlci5tYXAoKG1vZHVsZSkgPT4gcHJvbXB0LmNob2ljZXNbbW9kdWxlXSlcclxuICAgICAgICAgICAgOiBwcm9tcHQuY2hvaWNlcztcclxuXHJcbiAgICAgICAgICBjb25maWdGaWxlW3Byb21wdC5zZWN0aW9uXVtwcm9tcHQubmFtZV0gPSBhbnN3ZXI7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIGNvbmZpZ0ZpbGVbcHJvbXB0LnNlY3Rpb25dID0gcmVjdXJzaXZlUHJvcHMoXHJcbiAgICAgICAgICAgIE9iamVjdC5hc3NpZ24oe30sIGNvbmZpZ0ZpbGVbcHJvbXB0LnNlY3Rpb25dIHx8IHt9KSxcclxuICAgICAgICAgICAgcHJvbXB0Lm5hbWUuc3BsaXQoJy4nKSxcclxuICAgICAgICAgICAgcHJvbXB0LmNob2ljZXMgPyBwcm9tcHQuY2hvaWNlc1thbnN3ZXJdIDogYW5zd2VyXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgaWYgKCsrcXVlc3Rpb25zQ291bnRlciA9PT0gYWxsUXVlc3Rpb25zLmxlbmd0aCkge1xyXG4gICAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgYXdhaXQgZnNQcm9taXNlcy53cml0ZUZpbGUoXHJcbiAgICAgICAgICAgICAgY29uZmlnRmlsZU5hbWUsXHJcbiAgICAgICAgICAgICAgSlNPTi5zdHJpbmdpZnkoY29uZmlnRmlsZSwgbnVsbCwgMiksXHJcbiAgICAgICAgICAgICAgJ3V0ZjgnXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgICAgICAgMSxcclxuICAgICAgICAgICAgICBlcnJvcixcclxuICAgICAgICAgICAgICBgW2NvbmZpZ10gQW4gZXJyb3Igb2NjdXJyZWQgd2hpbGUgY3JlYXRpbmcgdGhlICR7Y29uZmlnRmlsZU5hbWV9IGZpbGUuYFxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9KTtcclxuXHJcbiAgICByZXR1cm4gdHJ1ZTtcclxuICB9O1xyXG5cclxuICAvLyBGaW5kIHRoZSBjYXRlZ29yaWVzXHJcbiAgY29uc3QgY2hvaWNlcyA9IE9iamVjdC5rZXlzKHByb21wdHNDb25maWcpLm1hcCgoY2hvaWNlKSA9PiAoe1xyXG4gICAgdGl0bGU6IGAke2Nob2ljZX0gb3B0aW9uc2AsXHJcbiAgICB2YWx1ZTogY2hvaWNlXHJcbiAgfSkpO1xyXG5cclxuICAvLyBDYXRlZ29yeSBwcm9tcHRcclxuICByZXR1cm4gcHJvbXB0cyhcclxuICAgIHtcclxuICAgICAgdHlwZTogJ211bHRpc2VsZWN0JyxcclxuICAgICAgbmFtZTogJ2NhdGVnb3J5JyxcclxuICAgICAgbWVzc2FnZTogJ1doaWNoIGNhdGVnb3J5IGRvIHlvdSB3YW50IHRvIGNvbmZpZ3VyZT8nLFxyXG4gICAgICBoaW50OiAnU3BhY2U6IFNlbGVjdCBzcGVjaWZpYywgQTogU2VsZWN0IGFsbCwgRW50ZXI6IENvbmZpcm0uJyxcclxuICAgICAgaW5zdHJ1Y3Rpb25zOiAnJyxcclxuICAgICAgY2hvaWNlc1xyXG4gICAgfSxcclxuICAgIHsgb25TdWJtaXQgfVxyXG4gICk7XHJcbn07XHJcblxyXG4vKipcclxuICogTWFwcyBvbGQtc3RydWN0dXJlZCAoUGhhbnRvbUpTKSBvcHRpb25zIHRvIGEgbmV3IGNvbmZpZ3VyYXRpb24gZm9ybWF0XHJcbiAqIChQdXBwZXRlZXIpLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb2xkT3B0aW9ucyAtIE9sZC1zdHJ1Y3R1cmVkIG9wdGlvbnMgdG8gYmUgbWFwcGVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBOZXcgb3B0aW9ucyBzdHJ1Y3R1cmVkIGJhc2VkIG9uIHRoZSBkZWZpbmVkIG5lc3RlZEFyZ3NcclxuICogbWFwcGluZy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBtYXBUb05ld0NvbmZpZyA9IChvbGRPcHRpb25zKSA9PiB7XHJcbiAgY29uc3QgbmV3T3B0aW9ucyA9IHt9O1xyXG4gIC8vIEN5Y2xlIHRocm91Z2ggb2xkLXN0cnVjdHVyZWQgb3B0aW9uc1xyXG4gIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKG9sZE9wdGlvbnMpKSB7XHJcbiAgICBjb25zdCBwcm9wZXJ0aWVzQ2hhaW4gPSBuZXN0ZWRBcmdzW2tleV0gPyBuZXN0ZWRBcmdzW2tleV0uc3BsaXQoJy4nKSA6IFtdO1xyXG5cclxuICAgIC8vIFBvcHVsYXRlIG9iamVjdCBpbiBjb3JyZWN0IHByb3BlcnRpZXMgbGV2ZWxzXHJcbiAgICBwcm9wZXJ0aWVzQ2hhaW4ucmVkdWNlKFxyXG4gICAgICAob2JqLCBwcm9wLCBpbmRleCkgPT5cclxuICAgICAgICAob2JqW3Byb3BdID1cclxuICAgICAgICAgIHByb3BlcnRpZXNDaGFpbi5sZW5ndGggLSAxID09PSBpbmRleCA/IHZhbHVlIDogb2JqW3Byb3BdIHx8IHt9KSxcclxuICAgICAgbmV3T3B0aW9uc1xyXG4gICAgKTtcclxuICB9XHJcbiAgcmV0dXJuIG5ld09wdGlvbnM7XHJcbn07XHJcblxyXG4vKipcclxuICogTWVyZ2VzIHR3byBzZXRzIG9mIGNvbmZpZ3VyYXRpb24gb3B0aW9ucywgY29uc2lkZXJpbmcgYWJzb2x1dGUgcHJvcGVydGllcy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBPcmlnaW5hbCBjb25maWd1cmF0aW9uIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBuZXdPcHRpb25zIC0gTmV3IGNvbmZpZ3VyYXRpb24gb3B0aW9ucyB0byBiZSBtZXJnZWQuXHJcbiAqIEBwYXJhbSB7QXJyYXl9IGFic29sdXRlUHJvcHMgLSBMaXN0IG9mIHByb3BlcnRpZXMgdGhhdCBzaG91bGRcclxuICogbm90IGJlIHJlY3Vyc2l2ZWx5IG1lcmdlZC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gTWVyZ2VkIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBtZXJnZUNvbmZpZ09wdGlvbnMgPSAob3B0aW9ucywgbmV3T3B0aW9ucywgYWJzb2x1dGVQcm9wcyA9IFtdKSA9PiB7XHJcbiAgY29uc3QgbWVyZ2VkT3B0aW9ucyA9IGRlZXBDb3B5KG9wdGlvbnMpO1xyXG5cclxuICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhuZXdPcHRpb25zKSkge1xyXG4gICAgbWVyZ2VkT3B0aW9uc1trZXldID1cclxuICAgICAgaXNPYmplY3QodmFsdWUpICYmXHJcbiAgICAgICFhYnNvbHV0ZVByb3BzLmluY2x1ZGVzKGtleSkgJiZcclxuICAgICAgbWVyZ2VkT3B0aW9uc1trZXldICE9PSB1bmRlZmluZWRcclxuICAgICAgICA/IG1lcmdlQ29uZmlnT3B0aW9ucyhtZXJnZWRPcHRpb25zW2tleV0sIHZhbHVlLCBhYnNvbHV0ZVByb3BzKVxyXG4gICAgICAgIDogdmFsdWUgIT09IHVuZGVmaW5lZFxyXG4gICAgICAgICAgPyB2YWx1ZVxyXG4gICAgICAgICAgOiBtZXJnZWRPcHRpb25zW2tleV07XHJcbiAgfVxyXG5cclxuICByZXR1cm4gbWVyZ2VkT3B0aW9ucztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyBleHBvcnQgc2V0dGluZ3MgYmFzZWQgb24gcHJvdmlkZWQgZXhwb3J0T3B0aW9uc1xyXG4gKiBhbmQgZ2VuZXJhbE9wdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBleHBvcnRPcHRpb25zIC0gT3B0aW9ucyBzcGVjaWZpYyB0byB0aGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBnZW5lcmFsT3B0aW9ucyAtIEdlbmVyYWwgY29uZmlndXJhdGlvbiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBJbml0aWFsaXplZCBleHBvcnQgc2V0dGluZ3MuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaW5pdEV4cG9ydFNldHRpbmdzID0gKGV4cG9ydE9wdGlvbnMsIGdlbmVyYWxPcHRpb25zID0ge30pID0+IHtcclxuICBsZXQgb3B0aW9ucyA9IHt9O1xyXG5cclxuICBpZiAoZXhwb3J0T3B0aW9ucy5zdmcpIHtcclxuICAgIG9wdGlvbnMgPSBkZWVwQ29weShnZW5lcmFsT3B0aW9ucyk7XHJcbiAgICBvcHRpb25zLmV4cG9ydC50eXBlID0gZXhwb3J0T3B0aW9ucy50eXBlIHx8IGV4cG9ydE9wdGlvbnMuZXhwb3J0LnR5cGU7XHJcbiAgICBvcHRpb25zLmV4cG9ydC5zY2FsZSA9IGV4cG9ydE9wdGlvbnMuc2NhbGUgfHwgZXhwb3J0T3B0aW9ucy5leHBvcnQuc2NhbGU7XHJcbiAgICBvcHRpb25zLmV4cG9ydC5vdXRmaWxlID1cclxuICAgICAgZXhwb3J0T3B0aW9ucy5vdXRmaWxlIHx8IGV4cG9ydE9wdGlvbnMuZXhwb3J0Lm91dGZpbGU7XHJcbiAgICBvcHRpb25zLnBheWxvYWQgPSB7XHJcbiAgICAgIHN2ZzogZXhwb3J0T3B0aW9ucy5zdmdcclxuICAgIH07XHJcbiAgfSBlbHNlIHtcclxuICAgIG9wdGlvbnMgPSBtZXJnZUNvbmZpZ09wdGlvbnMoXHJcbiAgICAgIGdlbmVyYWxPcHRpb25zLFxyXG4gICAgICBleHBvcnRPcHRpb25zLFxyXG4gICAgICAvLyBPbWl0IGdvaW5nIGRvd24gcmVjdXJzaXZlbHkgd2l0aCB0aGUgYmVsb3dzXHJcbiAgICAgIGFic29sdXRlUHJvcHNcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICBvcHRpb25zLmV4cG9ydC5vdXRmaWxlID1cclxuICAgIG9wdGlvbnMuZXhwb3J0Py5vdXRmaWxlIHx8IGBjaGFydC4ke29wdGlvbnMuZXhwb3J0Py50eXBlIHx8ICdwbmcnfWA7XHJcbiAgcmV0dXJuIG9wdGlvbnM7XHJcbn07XHJcblxyXG4vKipcclxuICogTG9hZHMgYWRkaXRpb25hbCBjb25maWd1cmF0aW9uIGZyb20gYSBzcGVjaWZpZWQgZmlsZSB1c2luZ1xyXG4gKiB0aGUgLS1sb2FkQ29uZmlnIG9wdGlvbi5cclxuICpcclxuICogQHBhcmFtIHtBcnJheX0gYXJncyAtIENvbW1hbmQtbGluZSBhcmd1bWVudHMgdG8gY2hlY2sgZm9yXHJcbiAqIHRoZSAtLWxvYWRDb25maWcgb3B0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBBZGRpdGlvbmFsIGNvbmZpZ3VyYXRpb24gbG9hZGVkIGZyb20gdGhlIHNwZWNpZmllZCBmaWxlLFxyXG4gKiBvciBhbiBlbXB0eSBvYmplY3QgaWYgbm90IGZvdW5kIG9yIGludmFsaWQuXHJcbiAqL1xyXG5mdW5jdGlvbiBsb2FkQ29uZmlnRmlsZShhcmdzKSB7XHJcbiAgLy8gQ2hlY2sgaWYgdGhlIC0tbG9hZENvbmZpZyBvcHRpb24gd2FzIHVzZWRcclxuICBjb25zdCBjb25maWdJbmRleCA9IGFyZ3MuZmluZEluZGV4KFxyXG4gICAgKGFyZykgPT4gYXJnLnJlcGxhY2UoLy0vZywgJycpID09PSAnbG9hZENvbmZpZydcclxuICApO1xyXG5cclxuICAvLyBDaGVjayBpZiB0aGUgLS1sb2FkQ29uZmlnIGhhcyBhIHZhbHVlXHJcbiAgaWYgKGNvbmZpZ0luZGV4ID4gLTEgJiYgYXJnc1tjb25maWdJbmRleCArIDFdKSB7XHJcbiAgICBjb25zdCBmaWxlTmFtZSA9IGFyZ3NbY29uZmlnSW5kZXggKyAxXTtcclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIENoZWNrIGlmIGFuIGFkZGl0aW9uYWwgY29uZmlnIGZpbGUgaXMgYSBjb3JyZWN0IEpTT04gZmlsZVxyXG4gICAgICBpZiAoZmlsZU5hbWUgJiYgZmlsZU5hbWUuZW5kc1dpdGgoJy5qc29uJykpIHtcclxuICAgICAgICAvLyBMb2FkIGFuIG9wdGlvbmFsIGN1c3RvbSBKU09OIGNvbmZpZyBmaWxlXHJcbiAgICAgICAgcmV0dXJuIEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKGZpbGVOYW1lKSk7XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAyLFxyXG4gICAgICAgIGVycm9yLFxyXG4gICAgICAgIGBbY29uZmlnXSBVbmFibGUgdG8gbG9hZCB0aGUgY29uZmlndXJhdGlvbiBmcm9tIHRoZSAke2ZpbGVOYW1lfSBmaWxlLmBcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIE5vIGFkZGl0aW9uYWwgb3B0aW9ucyB0byByZXR1cm5cclxuICByZXR1cm4ge307XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBVcGRhdGVzIHRoZSBkZWZhdWx0IGNvbmZpZ3VyYXRpb24gb2JqZWN0IHdpdGggdmFsdWVzIGZyb20gYSBjdXN0b20gb2JqZWN0XHJcbiAqIGFuZCBlbnZpcm9ubWVudCB2YXJpYWJsZXMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjb25maWdPYmogLSBUaGUgZGVmYXVsdCBjb25maWd1cmF0aW9uIG9iamVjdC5cclxuICogQHBhcmFtIHtPYmplY3R9IGN1c3RvbU9iaiAtIEN1c3RvbSBjb25maWd1cmF0aW9uIG9iamVjdCB0byBvdmVycmlkZSBkZWZhdWx0cy5cclxuICogQHBhcmFtIHtzdHJpbmd9IHByb3BDaGFpbiAtIFByb3BlcnR5IGNoYWluIGZvciB0cmFja2luZyBuZXN0ZWQgcHJvcGVydGllc1xyXG4gKiBkdXJpbmcgcmVjdXJzaW9uLlxyXG4gKi9cclxuZnVuY3Rpb24gdXBkYXRlRGVmYXVsdENvbmZpZyhjb25maWdPYmosIGN1c3RvbU9iaiA9IHt9LCBwcm9wQ2hhaW4gPSAnJykge1xyXG4gIE9iamVjdC5rZXlzKGNvbmZpZ09iaikuZm9yRWFjaCgoa2V5KSA9PiB7XHJcbiAgICBjb25zdCBlbnRyeSA9IGNvbmZpZ09ialtrZXldO1xyXG4gICAgY29uc3QgY3VzdG9tVmFsdWUgPSBjdXN0b21PYmogJiYgY3VzdG9tT2JqW2tleV07XHJcbiAgICBsZXQgbnVtRW52VmFsO1xyXG5cclxuICAgIGlmICh0eXBlb2YgZW50cnkudmFsdWUgPT09ICd1bmRlZmluZWQnKSB7XHJcbiAgICAgIHVwZGF0ZURlZmF1bHRDb25maWcoZW50cnksIGN1c3RvbVZhbHVlLCBgJHtwcm9wQ2hhaW59LiR7a2V5fWApO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gSWYgYSB2YWx1ZSBmcm9tIGEgY3VzdG9tIEpTT04gZXhpc3RzLCBpdCB0YWtlIHByZWNlZGVuY2VcclxuICAgICAgaWYgKGN1c3RvbVZhbHVlICE9PSB1bmRlZmluZWQpIHtcclxuICAgICAgICBlbnRyeS52YWx1ZSA9IGN1c3RvbVZhbHVlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBJZiBhIHZhbHVlIGZyb20gYW4gZW52IHZhcmlhYmxlIGV4aXN0cywgaXQgdGFrZSBwcmVjZWRlbmNlXHJcbiAgICAgIGlmIChlbnRyeS5lbnZMaW5rKSB7XHJcbiAgICAgICAgLy8gTG9hZCB0aGUgZW52IHZhclxyXG4gICAgICAgIGlmIChlbnRyeS50eXBlID09PSAnYm9vbGVhbicpIHtcclxuICAgICAgICAgIGVudHJ5LnZhbHVlID0gdG9Cb29sZWFuKFxyXG4gICAgICAgICAgICBbcHJvY2Vzcy5lbnZbZW50cnkuZW52TGlua10sIGVudHJ5LnZhbHVlXS5maW5kKFxyXG4gICAgICAgICAgICAgIChlbCkgPT4gZWwgfHwgZWwgPT09ICdmYWxzZSdcclxuICAgICAgICAgICAgKVxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9IGVsc2UgaWYgKGVudHJ5LnR5cGUgPT09ICdudW1iZXInKSB7XHJcbiAgICAgICAgICBudW1FbnZWYWwgPSArcHJvY2Vzcy5lbnZbZW50cnkuZW52TGlua107XHJcbiAgICAgICAgICBlbnRyeS52YWx1ZSA9IG51bUVudlZhbCA+PSAwID8gbnVtRW52VmFsIDogZW50cnkudmFsdWU7XHJcbiAgICAgICAgfSBlbHNlIGlmIChlbnRyeS50eXBlLmluZGV4T2YoJ10nKSA+PSAwICYmIHByb2Nlc3MuZW52W2VudHJ5LmVudkxpbmtdKSB7XHJcbiAgICAgICAgICBlbnRyeS52YWx1ZSA9IHByb2Nlc3MuZW52W2VudHJ5LmVudkxpbmtdLnNwbGl0KCcsJyk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIGVudHJ5LnZhbHVlID0gcHJvY2Vzcy5lbnZbZW50cnkuZW52TGlua10gfHwgZW50cnkudmFsdWU7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyBvcHRpb25zIG9iamVjdCBiYXNlZCBvbiBwcm92aWRlZCBpdGVtcywgc2V0dGluZyB2YWx1ZXMgZnJvbVxyXG4gKiBuZXN0ZWQgcHJvcGVydGllcyByZWN1cnNpdmVseS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGl0ZW1zIC0gQ29uZmlndXJhdGlvbiBpdGVtcyB0byBiZSB1c2VkIGZvciBpbml0aWFsaXppbmdcclxuICogb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gSW5pdGlhbGl6ZWQgb3B0aW9ucyBvYmplY3QuXHJcbiAqL1xyXG5mdW5jdGlvbiBpbml0T3B0aW9ucyhpdGVtcykge1xyXG4gIGxldCBvcHRpb25zID0ge307XHJcbiAgZm9yIChjb25zdCBbbmFtZSwgaXRlbV0gb2YgT2JqZWN0LmVudHJpZXMoaXRlbXMpKSB7XHJcbiAgICBvcHRpb25zW25hbWVdID0gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGl0ZW0sICd2YWx1ZScpXHJcbiAgICAgID8gaXRlbS52YWx1ZVxyXG4gICAgICA6IGluaXRPcHRpb25zKGl0ZW0pO1xyXG4gIH1cclxuICByZXR1cm4gb3B0aW9ucztcclxufVxyXG5cclxuLyoqXHJcbiAqIFBhaXJzIGFyZ3VtZW50IHZhbHVlcyB3aXRoIGNvcnJlc3BvbmRpbmcgb3B0aW9ucyBpbiB0aGUgY29uZmlndXJhdGlvbixcclxuICogdXBkYXRpbmcgdGhlIG9wdGlvbnMgb2JqZWN0LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIENvbmZpZ3VyYXRpb24gb3B0aW9ucyBvYmplY3QgdG8gYmUgdXBkYXRlZC5cclxuICogQHBhcmFtIHtBcnJheX0gYXJncyAtIENvbW1hbmQtbGluZSBhcmd1bWVudHMgY29udGFpbmluZyB2YWx1ZXMgZm9yIHNwZWNpZmljXHJcbiAqIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBkZWZhdWx0Q29uZmlnIC0gRGVmYXVsdCBjb25maWd1cmF0aW9uIG9iamVjdCBmb3IgcmVmZXJlbmNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBVcGRhdGVkIG9wdGlvbnMgb2JqZWN0LlxyXG4gKi9cclxuZnVuY3Rpb24gcGFpckFyZ3VtZW50VmFsdWUob3B0aW9ucywgYXJncywgZGVmYXVsdENvbmZpZykge1xyXG4gIGxldCBzaG93VXNhZ2UgPSBmYWxzZTtcclxuICBmb3IgKGxldCBpID0gMDsgaSA8IGFyZ3MubGVuZ3RoOyBpKyspIHtcclxuICAgIGNvbnN0IG9wdGlvbiA9IGFyZ3NbaV0ucmVwbGFjZSgvLS9nLCAnJyk7XHJcblxyXG4gICAgLy8gRmluZCB0aGUgcmlnaHQgcGxhY2UgZm9yIHByb3BlcnR5J3MgdmFsdWVcclxuICAgIGNvbnN0IHByb3BlcnRpZXNDaGFpbiA9IG5lc3RlZEFyZ3Nbb3B0aW9uXVxyXG4gICAgICA/IG5lc3RlZEFyZ3Nbb3B0aW9uXS5zcGxpdCgnLicpXHJcbiAgICAgIDogW107XHJcblxyXG4gICAgLy8gR2V0IHRoZSBjb3JyZWN0IHR5cGUgZm9yIENMSSBhcmdzIHdoaWNoIGFyZSBwYXNzZWQgYXMgc3RyaW5nc1xyXG4gICAgbGV0IGFyZ3VtZW50VHlwZTtcclxuICAgIHByb3BlcnRpZXNDaGFpbi5yZWR1Y2UoKG9iaiwgcHJvcCwgaW5kZXgpID0+IHtcclxuICAgICAgaWYgKHByb3BlcnRpZXNDaGFpbi5sZW5ndGggLSAxID09PSBpbmRleCkge1xyXG4gICAgICAgIGFyZ3VtZW50VHlwZSA9IG9ialtwcm9wXS50eXBlO1xyXG4gICAgICB9XHJcbiAgICAgIHJldHVybiBvYmpbcHJvcF07XHJcbiAgICB9LCBkZWZhdWx0Q29uZmlnKTtcclxuXHJcbiAgICBwcm9wZXJ0aWVzQ2hhaW4ucmVkdWNlKChvYmosIHByb3AsIGluZGV4KSA9PiB7XHJcbiAgICAgIGlmIChwcm9wZXJ0aWVzQ2hhaW4ubGVuZ3RoIC0gMSA9PT0gaW5kZXgpIHtcclxuICAgICAgICAvLyBGaW5kcyBhbiBvcHRpb24gYW5kIHNldCBhIGNvcnJlc3BvbmRpbmcgdmFsdWVcclxuICAgICAgICBpZiAodHlwZW9mIG9ialtwcm9wXSAhPT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgICAgIGlmIChhcmdzWysraV0pIHtcclxuICAgICAgICAgICAgaWYgKGFyZ3VtZW50VHlwZSA9PT0gJ2Jvb2xlYW4nKSB7XHJcbiAgICAgICAgICAgICAgb2JqW3Byb3BdID0gdG9Cb29sZWFuKGFyZ3NbaV0pO1xyXG4gICAgICAgICAgICB9IGVsc2UgaWYgKGFyZ3VtZW50VHlwZSA9PT0gJ251bWJlcicpIHtcclxuICAgICAgICAgICAgICBvYmpbcHJvcF0gPSArYXJnc1tpXTtcclxuICAgICAgICAgICAgfSBlbHNlIGlmIChhcmd1bWVudFR5cGUuaW5kZXhPZignXScpID49IDApIHtcclxuICAgICAgICAgICAgICBvYmpbcHJvcF0gPSBhcmdzW2ldLnNwbGl0KCcsJyk7XHJcbiAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgb2JqW3Byb3BdID0gYXJnc1tpXTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgbG9nKFxyXG4gICAgICAgICAgICAgIDIsXHJcbiAgICAgICAgICAgICAgYFtjb25maWddIE1pc3NpbmcgdmFsdWUgZm9yIHRoZSAnJHtvcHRpb259JyBhcmd1bWVudC4gVXNpbmcgdGhlIGRlZmF1bHQgdmFsdWUuYFxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgICBzaG93VXNhZ2UgPSB0cnVlO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gb2JqW3Byb3BdO1xyXG4gICAgfSwgb3B0aW9ucyk7XHJcbiAgfVxyXG5cclxuICAvLyBEaXNwbGF5IHRoZSB1c2FnZSBmb3IgdGhlIHJlZmVyZW5jZSBpZiBuZWVkZWRcclxuICBpZiAoc2hvd1VzYWdlKSB7XHJcbiAgICBwcmludFVzYWdlKGRlZmF1bHRDb25maWcpO1xyXG4gIH1cclxuXHJcbiAgcmV0dXJuIG9wdGlvbnM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZWN1cnNpdmVseSB1cGRhdGVzIHByb3BlcnRpZXMgaW4gYW4gb2JqZWN0IGJhc2VkIG9uIG5lc3RlZCBuYW1lcyBhbmQgYXNzaWduc1xyXG4gKiB0aGUgZmluYWwgdmFsdWUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvYmplY3RUb1VwZGF0ZSAtIFRoZSBvYmplY3QgdG8gYmUgdXBkYXRlZC5cclxuICogQHBhcmFtIHtBcnJheX0gbmVzdGVkTmFtZXMgLSBBcnJheSBvZiBuZXN0ZWQgcHJvcGVydHkgbmFtZXMuXHJcbiAqIEBwYXJhbSB7YW55fSB2YWx1ZSAtIFRoZSBmaW5hbCB2YWx1ZSB0byBiZSBhc3NpZ25lZC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVXBkYXRlZCBvYmplY3Qgd2l0aCBhc3NpZ25lZCB2YWx1ZXMuXHJcbiAqL1xyXG5mdW5jdGlvbiByZWN1cnNpdmVQcm9wcyhvYmplY3RUb1VwZGF0ZSwgbmVzdGVkTmFtZXMsIHZhbHVlKSB7XHJcbiAgd2hpbGUgKG5lc3RlZE5hbWVzLmxlbmd0aCA+IDEpIHtcclxuICAgIGNvbnN0IHByb3BOYW1lID0gbmVzdGVkTmFtZXMuc2hpZnQoKTtcclxuXHJcbiAgICAvLyBDcmVhdGUgYSBwcm9wZXJ0eSBpbiBvYmplY3QgaWYgaXQgZG9lc24ndCBleGlzdFxyXG4gICAgaWYgKCFPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob2JqZWN0VG9VcGRhdGUsIHByb3BOYW1lKSkge1xyXG4gICAgICBvYmplY3RUb1VwZGF0ZVtwcm9wTmFtZV0gPSB7fTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBDYWxsIGZ1bmN0aW9uIGFnYWluIGlmIHRoZXJlIHN0aWxsIG5hbWVzIHRvIGdvXHJcbiAgICBvYmplY3RUb1VwZGF0ZVtwcm9wTmFtZV0gPSByZWN1cnNpdmVQcm9wcyhcclxuICAgICAgT2JqZWN0LmFzc2lnbih7fSwgb2JqZWN0VG9VcGRhdGVbcHJvcE5hbWVdKSxcclxuICAgICAgbmVzdGVkTmFtZXMsXHJcbiAgICAgIHZhbHVlXHJcbiAgICApO1xyXG5cclxuICAgIHJldHVybiBvYmplY3RUb1VwZGF0ZTtcclxuICB9XHJcblxyXG4gIC8vIEFzc2lnbiB0aGUgZmluYWwgdmFsdWVcclxuICBvYmplY3RUb1VwZGF0ZVtuZXN0ZWROYW1lc1swXV0gPSB2YWx1ZTtcclxuICByZXR1cm4gb2JqZWN0VG9VcGRhdGU7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBnZXRPcHRpb25zLFxyXG4gIHNldE9wdGlvbnMsXHJcbiAgbWFudWFsQ29uZmlnLFxyXG4gIG1hcFRvTmV3Q29uZmlnLFxyXG4gIG1lcmdlQ29uZmlnT3B0aW9ucyxcclxuICBpbml0RXhwb3J0U2V0dGluZ3NcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgZnMgZnJvbSAnZnMnO1xyXG5pbXBvcnQgKiBhcyB1cmwgZnJvbSAndXJsJztcclxuaW1wb3J0IHBhdGggZnJvbSAnbm9kZTpwYXRoJztcclxuXHJcbmltcG9ydCBwdXBwZXRlZXIgZnJvbSAncHVwcGV0ZWVyJztcclxuXHJcbi8vIFdvcmthcm91bmQgZm9yIGh0dHBzOi8vYnVncy5jaHJvbWl1bS5vcmcvcC9jaHJvbWl1bS9pc3N1ZXMvZGV0YWlsP2lkPTE0NjMzMjhcclxuLy8gTm90IGlkZWFsIC0gbGVhdmVzIHRyYXNoIGluIHRoZSBGU1xyXG5pbXBvcnQgeyByYW5kb21CeXRlcyB9IGZyb20gJ25vZGU6Y3J5cHRvJztcclxuXHJcbmltcG9ydCB7IGdldENhY2hlUGF0aCB9IGZyb20gJy4vY2FjaGUuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG5jb25zdCBSQU5ET01fUElEID0gcmFuZG9tQnl0ZXMoNjQpLnRvU3RyaW5nKCdiYXNlNjR1cmwnKTtcclxuY29uc3QgUFVQUEVURUVSX0RJUiA9IHBhdGguam9pbigndG1wJywgYHB1cHBldGVlci0ke1JBTkRPTV9QSUR9YCk7XHJcbmNvbnN0IERBVEFfRElSID0gcGF0aC5qb2luKFBVUFBFVEVFUl9ESVIsICdwcm9maWxlJyk7XHJcblxyXG4vLyBUaGUgbWluaW1hbCBhcmdzIHRvIHNwZWVkIHVwIHRoZSBicm93c2VyXHJcbmNvbnN0IG1pbmltYWxBcmdzID0gW1xyXG4gIGAtLXVzZXItZGF0YS1kaXI9JHtEQVRBX0RJUn1gLFxyXG4gICctLWF1dG9wbGF5LXBvbGljeT11c2VyLWdlc3R1cmUtcmVxdWlyZWQnLFxyXG4gICctLWRpc2FibGUtYmFja2dyb3VuZC1uZXR3b3JraW5nJyxcclxuICAnLS1kaXNhYmxlLWJhY2tncm91bmQtdGltZXItdGhyb3R0bGluZycsXHJcbiAgJy0tZGlzYWJsZS1iYWNrZ3JvdW5kaW5nLW9jY2x1ZGVkLXdpbmRvd3MnLFxyXG4gICctLWRpc2FibGUtYnJlYWtwYWQnLFxyXG4gICctLWRpc2FibGUtY2xpZW50LXNpZGUtcGhpc2hpbmctZGV0ZWN0aW9uJyxcclxuICAnLS1kaXNhYmxlLWNvbXBvbmVudC11cGRhdGUnLFxyXG4gICctLWRpc2FibGUtZGVmYXVsdC1hcHBzJyxcclxuICAnLS1kaXNhYmxlLWRldi1zaG0tdXNhZ2UnLFxyXG4gICctLWRpc2FibGUtZG9tYWluLXJlbGlhYmlsaXR5JyxcclxuICAnLS1kaXNhYmxlLWV4dGVuc2lvbnMnLFxyXG4gICctLWRpc2FibGUtZmVhdHVyZXM9QXVkaW9TZXJ2aWNlT3V0T2ZQcm9jZXNzJyxcclxuICAnLS1kaXNhYmxlLWhhbmctbW9uaXRvcicsXHJcbiAgJy0tZGlzYWJsZS1pcGMtZmxvb2RpbmctcHJvdGVjdGlvbicsXHJcbiAgJy0tZGlzYWJsZS1ub3RpZmljYXRpb25zJyxcclxuICAnLS1kaXNhYmxlLW9mZmVyLXN0b3JlLXVubWFza2VkLXdhbGxldC1jYXJkcycsXHJcbiAgJy0tZGlzYWJsZS1wb3B1cC1ibG9ja2luZycsXHJcbiAgJy0tZGlzYWJsZS1wcmludC1wcmV2aWV3JyxcclxuICAnLS1kaXNhYmxlLXByb21wdC1vbi1yZXBvc3QnLFxyXG4gICctLWRpc2FibGUtcmVuZGVyZXItYmFja2dyb3VuZGluZycsXHJcbiAgJy0tZGlzYWJsZS1zZXNzaW9uLWNyYXNoZWQtYnViYmxlJyxcclxuICAnLS1kaXNhYmxlLXNldHVpZC1zYW5kYm94JyxcclxuICAnLS1kaXNhYmxlLXNwZWVjaC1hcGknLFxyXG4gICctLWRpc2FibGUtc3luYycsXHJcbiAgJy0taGlkZS1jcmFzaC1yZXN0b3JlLWJ1YmJsZScsXHJcbiAgJy0taGlkZS1zY3JvbGxiYXJzJyxcclxuICAnLS1pZ25vcmUtZ3B1LWJsYWNrbGlzdCcsXHJcbiAgJy0tbWV0cmljcy1yZWNvcmRpbmctb25seScsXHJcbiAgJy0tbXV0ZS1hdWRpbycsXHJcbiAgJy0tbm8tZGVmYXVsdC1icm93c2VyLWNoZWNrJyxcclxuICAnLS1uby1maXJzdC1ydW4nLFxyXG4gICctLW5vLXBpbmdzJyxcclxuICAnLS1uby1zYW5kYm94JyxcclxuICAnLS1uby16eWdvdGUnLFxyXG4gICctLXBhc3N3b3JkLXN0b3JlPWJhc2ljJyxcclxuICAnLS11c2UtbW9jay1rZXljaGFpbidcclxuXTtcclxuXHJcbmNvbnN0IF9fZGlybmFtZSA9IHVybC5maWxlVVJMVG9QYXRoKG5ldyBVUkwoJy4nLCBpbXBvcnQubWV0YS51cmwpKTtcclxuXHJcbmNvbnN0IHRlbXBsYXRlID0gZnMucmVhZEZpbGVTeW5jKFxyXG4gIF9fZGlybmFtZSArICcvLi4vdGVtcGxhdGVzL3RlbXBsYXRlLmh0bWwnLFxyXG4gICd1dGY4J1xyXG4pO1xyXG5cclxubGV0IGJyb3dzZXI7XHJcblxyXG4vKipcclxuICogU2V0cyB0aGUgY29udGVudCBmb3IgYSBQdXBwZXRlZXIgUGFnZSB1c2luZyBhIHByZWRlZmluZWQgdGVtcGxhdGVcclxuICogYW5kIGFkZGl0aW9uYWwgc2NyaXB0cy4gQWxzbywgc2V0cyB0aGUgcGFnZWVycm9yIGluIG9yZGVyIHRvIGNhdGNoXHJcbiAqIGFuZCBkaXNwbGF5IGVycm9ycyBmcm9tIHRoZSB3aW5kb3cgY29udGV4dC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IGZvciB3aGljaCB0aGUgY29udGVudFxyXG4gKiBpcyBiZWluZyBzZXQuXHJcbiAqL1xyXG5jb25zdCBzZXRQYWdlQ29udGVudCA9IGFzeW5jIChwYWdlKSA9PiB7XHJcbiAgYXdhaXQgcGFnZS5zZXRDb250ZW50KHRlbXBsYXRlKTtcclxuICBhd2FpdCBwYWdlLmFkZFNjcmlwdFRhZyh7IHBhdGg6IGAke2dldENhY2hlUGF0aCgpfS9zb3VyY2VzLmpzYCB9KTtcclxuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICBhd2FpdCBwYWdlLmV2YWx1YXRlKCgpID0+IHdpbmRvdy5zZXR1cEhpZ2hjaGFydHMoKSk7XHJcblxyXG4gIHBhZ2Uub24oJ3BhZ2VlcnJvcicsIGFzeW5jIChlcnJvcikgPT4ge1xyXG4gICAgLy8gVE9ETzogQ29uc2lkZXIgYWRkaW5nIGEgc3dpdGNoIGhlcmUgdGhhdCB0dXJucyBvbiBsb2coMCkgbG9nZ2luZ1xyXG4gICAgLy8gb24gcGFnZSBlcnJvcnMuXHJcbiAgICBhd2FpdCBwYWdlLiRldmFsKFxyXG4gICAgICAnI2NvbnRhaW5lcicsXHJcbiAgICAgIChlbGVtZW50LCBlcnJvck1lc3NhZ2UpID0+IHtcclxuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICBpZiAod2luZG93Ll9kaXNwbGF5RXJyb3JzKSB7XHJcbiAgICAgICAgICBlbGVtZW50LmlubmVySFRNTCA9IGVycm9yTWVzc2FnZTtcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIGA8aDE+Q2hhcnQgaW5wdXQgZGF0YSBlcnJvcjwvaDE+JHtlcnJvci50b1N0cmluZygpfWBcclxuICAgICk7XHJcbiAgfSk7XHJcbn07XHJcblxyXG4vKipcclxuICogQ2xlYXJzIHRoZSBjb250ZW50IG9mIGEgUHVwcGV0ZWVyIFBhZ2UgYmFzZWQgb24gdGhlIHNwZWNpZmllZCBtb2RlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFRoZSBQdXBwZXRlZXIgUGFnZSBvYmplY3QgdG8gYmUgY2xlYXJlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBoYXJkUmVzZXQgLSBBIGZsYWcgaW5kaWNhdGluZyB0aGUgdHlwZSBvZiBjbGVhcmluZ1xyXG4gKiB0byBiZSBwZXJmb3JtZWQuIElmIHRydWUsIG5hdmlnYXRlcyB0byAnYWJvdXQ6YmxhbmsnIGFuZCByZXNldHMgY29udGVudFxyXG4gKiBhbmQgc2NyaXB0cy4gSWYgZmFsc2UsIGNsZWFycyB0aGUgYm9keSBjb250ZW50IGJ5IHNldHRpbmcgYSBwcmVkZWZpbmVkIEhUTUxcclxuICogc3RydWN0dXJlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFcnJvcn0gTG9ncyB0aHJvd24gZXJyb3IgaWYgY2xlYXJpbmcgdGhlIHBhZ2UgY29udGVudCBmYWlscy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBjbGVhclBhZ2UgPSBhc3luYyAocGFnZSwgaGFyZFJlc2V0ID0gZmFsc2UpID0+IHtcclxuICB0cnkge1xyXG4gICAgaWYgKGhhcmRSZXNldCkge1xyXG4gICAgICAvLyBOYXZpZ2F0ZSB0byBhYm91dDpibGFua1xyXG4gICAgICBhd2FpdCBwYWdlLmdvdG8oJ2Fib3V0OmJsYW5rJyk7XHJcblxyXG4gICAgICAvLyBTZXQgdGhlIGNvbnRlbnQgYW5kIGFuZCBzY3JpcHRzIGFnYWluXHJcbiAgICAgIGF3YWl0IHNldFBhZ2VDb250ZW50KHBhZ2UpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gQ2xlYXIgYm9keSBjb250ZW50XHJcbiAgICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xyXG4gICAgICAgIGRvY3VtZW50LmJvZHkuaW5uZXJIVE1MID1cclxuICAgICAgICAgICc8ZGl2IGlkPVwiY2hhcnQtY29udGFpbmVyXCI+PGRpdiBpZD1cImNvbnRhaW5lclwiPjwvZGl2PjwvZGl2Pic7XHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgIDIsXHJcbiAgICAgIGVycm9yLFxyXG4gICAgICAnW2Jyb3dzZXJdIENvdWxkIG5vdCBjbGVhciB0aGUgY29udGVudCBvZiB0aGUgcGFnZS4nXHJcbiAgICApO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgbmV3IFB1cHBldGVlciBQYWdlIHdpdGhpbiBhbiBleGlzdGluZyBicm93c2VyIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBJZiB0aGUgYnJvd3NlciBpbnN0YW5jZSBpcyBub3QgYXZhaWxhYmxlLCByZXR1cm5zIGZhbHNlLlxyXG4gKlxyXG4gKiBUaGUgZnVuY3Rpb24gY3JlYXRlcyBhIG5ldyBwYWdlLCBkaXNhYmxlcyBjYWNoaW5nLCBzZXRzIGNvbnRlbnQgdXNpbmdcclxuICogc2V0UGFnZUNvbnRlbnQoKSwgYW5kIHJldHVybnMgdGhlIGNyZWF0ZWQgUHVwcGV0ZWVyIFBhZ2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHsoYm9vbGVhbnxvYmplY3QpfSBSZXR1cm5zIGZhbHNlIGlmIHRoZSBicm93c2VyIGluc3RhbmNlIGlzIG5vdFxyXG4gKiBhdmFpbGFibGUsIG9yIGEgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IHJlcHJlc2VudGluZyB0aGUgbmV3bHkgY3JlYXRlZCBwYWdlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IG5ld1BhZ2UgPSBhc3luYyAoKSA9PiB7XHJcbiAgaWYgKCFicm93c2VyKSB7XHJcbiAgICByZXR1cm4gZmFsc2U7XHJcbiAgfVxyXG5cclxuICBjb25zdCBwYWdlID0gYXdhaXQgYnJvd3Nlci5uZXdQYWdlKCk7XHJcblxyXG4gIC8vIERpc2FibGUgY2FjaGVcclxuICBhd2FpdCBwYWdlLnNldENhY2hlRW5hYmxlZChmYWxzZSk7XHJcblxyXG4gIC8vIFNldCB0aGUgY29udGVudFxyXG4gIGF3YWl0IHNldFBhZ2VDb250ZW50KHBhZ2UpO1xyXG4gIHJldHVybiBwYWdlO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYSBQdXBwZXRlZXIgYnJvd3NlciBpbnN0YW5jZSB3aXRoIHRoZSBzcGVjaWZpZWQgYXJndW1lbnRzLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0FycmF5fSBwdXBwZXRlZXJBcmdzIC0gQWRkaXRpb25hbCBhcmd1bWVudHMgZm9yIFB1cHBldGVlciBsYXVuY2guXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPG9iamVjdD59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIFB1cHBldGVlciBicm93c2VyXHJcbiAqIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIG1heCByZXRyaWVzIHRvIG9wZW4gYSBicm93c2VyXHJcbiAqIGluc3RhbmNlIGFyZSByZWFjaGVkLCBvciBpZiBubyBicm93c2VyIGluc3RhbmNlIGlzIGZvdW5kIGFmdGVyIHJldHJpZXMuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgY3JlYXRlID0gYXN5bmMgKHB1cHBldGVlckFyZ3MpID0+IHtcclxuICBjb25zdCBhbGxBcmdzID0gWy4uLm1pbmltYWxBcmdzLCAuLi4ocHVwcGV0ZWVyQXJncyB8fCBbXSldO1xyXG5cclxuICAvLyBDcmVhdGUgYSBicm93c2VyXHJcbiAgaWYgKCFicm93c2VyKSB7XHJcbiAgICBsZXQgdHJ5Q291bnQgPSAwO1xyXG5cclxuICAgIGNvbnN0IG9wZW4gPSBhc3luYyAoKSA9PiB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbYnJvd3Nlcl0gQXR0ZW1wdGluZyB0byBnZXQgYSBicm93c2VyIGluc3RhbmNlICh0cnkgJHsrK3RyeUNvdW50fSkuYFxyXG4gICAgICAgICk7XHJcbiAgICAgICAgYnJvd3NlciA9IGF3YWl0IHB1cHBldGVlci5sYXVuY2goe1xyXG4gICAgICAgICAgaGVhZGxlc3M6ICduZXcnLFxyXG4gICAgICAgICAgYXJnczogYWxsQXJncyxcclxuICAgICAgICAgIHVzZXJEYXRhRGlyOiAnLi90bXAvJ1xyXG4gICAgICAgIH0pO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAgIDEsXHJcbiAgICAgICAgICBlcnJvcixcclxuICAgICAgICAgICdbYnJvd3Nlcl0gRmFpbGVkIHRvIGxhdW5jaCBhIGJyb3dzZXIgaW5zdGFuY2UuJ1xyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIC8vIFJldHJ5IHRvIGxhdW5jaCBicm93c2VyIHVudGlsIHJlYWNoaW5nIG1heCBhdHRlbXB0c1xyXG4gICAgICAgIGlmICh0cnlDb3VudCA8IDI1KSB7XHJcbiAgICAgICAgICBsb2coMywgYFticm93c2VyXSBSZXRyeSB0byBvcGVuIGEgYnJvd3NlciAoJHt0cnlDb3VudH0gb3V0IG9mIDI1KS5gKTtcclxuICAgICAgICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNwb25zZSkgPT4gc2V0VGltZW91dChyZXNwb25zZSwgNDAwMCkpO1xyXG4gICAgICAgICAgYXdhaXQgb3BlbigpO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH07XHJcblxyXG4gICAgdHJ5IHtcclxuICAgICAgYXdhaXQgb3BlbigpO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdbYnJvd3Nlcl0gTWF4aW11bSByZXRyaWVzIHRvIG9wZW4gYSBicm93c2VyIGluc3RhbmNlIHJlYWNoZWQuJ1xyXG4gICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoIWJyb3dzZXIpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbYnJvd3Nlcl0gQ2Fubm90IGZpbmQgYSBicm93c2VyIHRvIG9wZW4uJyk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gYSBicm93c2VyIHByb21pc2VcclxuICByZXR1cm4gYnJvd3NlcjtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgdGhlIGV4aXN0aW5nIFB1cHBldGVlciBicm93c2VyIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxvYmplY3Q+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBQdXBwZXRlZXIgYnJvd3NlclxyXG4gKiBpbnN0YW5jZS5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiBubyB2YWxpZCBicm93c2VyIGhhcyBiZWVuXHJcbiAqIGNyZWF0ZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0ID0gYXN5bmMgKCkgPT4ge1xyXG4gIGlmICghYnJvd3Nlcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbYnJvd3Nlcl0gTm8gdmFsaWQgYnJvd3NlciBoYXMgYmVlbiBjcmVhdGVkLicpO1xyXG4gIH1cclxuXHJcbiAgcmV0dXJuIGJyb3dzZXI7XHJcbn07XHJcblxyXG4vKipcclxuICogQ2xvc2VzIHRoZSBQdXBwZXRlZXIgYnJvd3NlciBpbnN0YW5jZSBpZiBpdCBpcyBjb25uZWN0ZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPGJvb2xlYW4+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIHRydWUgYWZ0ZXIgdGhlIGJyb3dzZXJcclxuICogaXMgY2xvc2VkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGNsb3NlID0gYXN5bmMgKCkgPT4ge1xyXG4gIC8vIENsb3NlIHRoZSBicm93c2VyIHdoZW4gY29ubm5lY3RlZFxyXG4gIGlmIChicm93c2VyPy5pc0Nvbm5lY3RlZCgpKSB7XHJcbiAgICBhd2FpdCBicm93c2VyLmNsb3NlKCk7XHJcbiAgICBsb2coNCwgJ1ticm93c2VyXSBDbG9zZWQgdGhlIGJyb3dzZXIuJyk7XHJcbiAgfVxyXG4gIHJldHVybiB0cnVlO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIG5ld1BhZ2UsXHJcbiAgY2xlYXJQYWdlLFxyXG4gIGdldCxcclxuICBjbG9zZVxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHBhdGggZnJvbSAncGF0aCc7XHJcbmltcG9ydCAqIGFzIHVybCBmcm9tICd1cmwnO1xyXG5cclxuaW1wb3J0IGNhY2hlIGZyb20gJy4vY2FjaGUuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHN2Z1RlbXBsYXRlIGZyb20gJy4vLi4vdGVtcGxhdGVzL3N2Z19leHBvcnQvc3ZnX2V4cG9ydC5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuY29uc3QgX19iYXNlZGlyID0gdXJsLmZpbGVVUkxUb1BhdGgobmV3IFVSTCgnLicsIGltcG9ydC5tZXRhLnVybCkpO1xyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyB0aGUgY2xpcHBpbmcgcmVnaW9uIGNvb3JkaW5hdGVzIG9mIHRoZSBzcGVjaWZpZWQgcGFnZSBlbGVtZW50IHdpdGhcclxuICogdGhlIGlkICdjaGFydC1jb250YWluZXInLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gYW4gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogeCwgeSwgd2lkdGgsIGFuZCBoZWlnaHQgcHJvcGVydGllcy5cclxuICovXHJcbmNvbnN0IGdldENsaXBSZWdpb24gPSAocGFnZSkgPT5cclxuICBwYWdlLiRldmFsKCcjY2hhcnQtY29udGFpbmVyJywgKGVsZW1lbnQpID0+IHtcclxuICAgIGNvbnN0IHsgeCwgeSwgd2lkdGgsIGhlaWdodCB9ID0gZWxlbWVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcclxuICAgIHJldHVybiB7XHJcbiAgICAgIHgsXHJcbiAgICAgIHksXHJcbiAgICAgIHdpZHRoLFxyXG4gICAgICBoZWlnaHQ6IE1hdGgudHJ1bmMoaGVpZ2h0ID4gMSA/IGhlaWdodCA6IDUwMClcclxuICAgIH07XHJcbiAgfSk7XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhbiBpbWFnZSB1c2luZyBQdXBwZXRlZXIncyBwYWdlIHNjcmVlbnNob3QgZnVuY3Rpb25hbGl0eSB3aXRoXHJcbiAqIHNwZWNpZmllZCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICogQHBhcmFtIHtzdHJpbmd9IHR5cGUgLSBJbWFnZSB0eXBlLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gZW5jb2RpbmcgLSBJbWFnZSBlbmNvZGluZy5cclxuICogQHBhcmFtIHtPYmplY3R9IGNsaXAgLSBDbGlwcGluZyByZWdpb24gY29vcmRpbmF0ZXMuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSByYXN0ZXJpemF0aW9uVGltZW91dCAtIFRpbWVvdXQgZm9yIHJhc3Rlcml6YXRpb25cclxuICogaW4gbWlsbGlzZWNvbmRzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxCdWZmZXI+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgaW1hZ2UgYnVmZmVyIG9yIHJlamVjdGluZ1xyXG4gKiB3aXRoIGFuIEV4cG9ydEVycm9yIGZvciB0aW1lb3V0LlxyXG4gKi9cclxuY29uc3QgY3JlYXRlSW1hZ2UgPSAocGFnZSwgdHlwZSwgZW5jb2RpbmcsIGNsaXAsIHJhc3Rlcml6YXRpb25UaW1lb3V0KSA9PlxyXG4gIFByb21pc2UucmFjZShbXHJcbiAgICBwYWdlLnNjcmVlbnNob3Qoe1xyXG4gICAgICB0eXBlLFxyXG4gICAgICBlbmNvZGluZyxcclxuICAgICAgY2xpcCxcclxuXHJcbiAgICAgIC8vICM0NDcsICM0NjMgLSBhbHdheXMgcmVuZGVyIG9uIGEgdHJhbnNwYXJlbnQgcGFnZSBpZiB0aGUgZXhwZWN0ZWQgdHlwZVxyXG4gICAgICAvLyBmb3JtYXQgaXMgUE5HXHJcbiAgICAgIG9taXRCYWNrZ3JvdW5kOiB0eXBlID09ICdwbmcnXHJcbiAgICB9KSxcclxuICAgIG5ldyBQcm9taXNlKChfcmVzb2x2ZSwgcmVqZWN0KSA9PlxyXG4gICAgICBzZXRUaW1lb3V0KFxyXG4gICAgICAgICgpID0+IHJlamVjdChuZXcgRXhwb3J0RXJyb3IoJ1Jhc3Rlcml6YXRpb24gdGltZW91dCcpKSxcclxuICAgICAgICByYXN0ZXJpemF0aW9uVGltZW91dCB8fCAxNTAwXHJcbiAgICAgIClcclxuICAgIClcclxuICBdKTtcclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgUERGIHVzaW5nIFB1cHBldGVlcidzIHBhZ2UgcGRmIGZ1bmN0aW9uYWxpdHkgd2l0aCBzcGVjaWZpZWRcclxuICogb3B0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBoZWlnaHQgLSBQREYgaGVpZ2h0LlxyXG4gKiBAcGFyYW0ge251bWJlcn0gd2lkdGggLSBQREYgd2lkdGguXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBlbmNvZGluZyAtIFBERiBlbmNvZGluZy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8QnVmZmVyPn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIFBERiBidWZmZXIuXHJcbiAqL1xyXG5jb25zdCBjcmVhdGVQREYgPSAocGFnZSwgaGVpZ2h0LCB3aWR0aCwgZW5jb2RpbmcpID0+XHJcbiAgcGFnZS5wZGYoe1xyXG4gICAgLy8gVGhpcyB3aWxsIHJlbW92ZSBhbiBleHRyYSBlbXB0eSBwYWdlIGluIFBERiBleHBvcnRzXHJcbiAgICBoZWlnaHQ6IGhlaWdodCArIDEsXHJcbiAgICB3aWR0aCxcclxuICAgIGVuY29kaW5nXHJcbiAgfSk7XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhbiBTVkcgc3RyaW5nIGJ5IGV2YWx1YXRpbmcgdGhlIG91dGVySFRNTCBvZiB0aGUgZmlyc3QgJ3N2ZycgZWxlbWVudFxyXG4gKiBpbnNpZGUgYW4gZWxlbWVudCB3aXRoIHRoZSBpZCAnY29udGFpbmVyJy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZz59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBTVkcgc3RyaW5nLlxyXG4gKi9cclxuY29uc3QgY3JlYXRlU1ZHID0gKHBhZ2UpID0+XHJcbiAgcGFnZS4kZXZhbCgnI2NvbnRhaW5lciBzdmc6Zmlyc3Qtb2YtdHlwZScsIChlbGVtZW50KSA9PiBlbGVtZW50Lm91dGVySFRNTCk7XHJcblxyXG4vKipcclxuICogU2V0cyB0aGUgc3BlY2lmaWVkIGNoYXJ0IGFuZCBvcHRpb25zIGFzIGNvbmZpZ3VyYXRpb24gaW50byB0aGUgdHJpZ2dlckV4cG9ydFxyXG4gKiBmdW5jdGlvbiB3aXRoaW4gdGhlIHdpbmRvdyBjb250ZXh0IHVzaW5nIHBhZ2UuZXZhbHVhdGUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge2FueX0gY2hhcnQgLSBUaGUgY2hhcnQgb2JqZWN0IHRvIGJlIGNvbmZpZ3VyZWQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gQ29uZmlndXJhdGlvbiBvcHRpb25zIGZvciB0aGUgY2hhcnQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBQcm9taXNlIHJlc29sdmluZyBhZnRlciB0aGUgY29uZmlndXJhdGlvbiBpcyBzZXQuXHJcbiAqL1xyXG5jb25zdCBzZXRBc0NvbmZpZyA9IChwYWdlLCBjaGFydCwgb3B0aW9ucykgPT5cclxuICBwYWdlLmV2YWx1YXRlKFxyXG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAoY2hhcnQsIG9wdGlvbnMpID0+IHdpbmRvdy50cmlnZ2VyRXhwb3J0KGNoYXJ0LCBvcHRpb25zKSxcclxuICAgIGNoYXJ0LFxyXG4gICAgb3B0aW9uc1xyXG4gICk7XHJcblxyXG4vKipcclxuICogRXhwb3J0cyB0byBhIGNoYXJ0IGZyb20gYSBwYWdlIHVzaW5nIFB1cHBldGVlci5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7YW55fSBjaGFydCAtIFRoZSBjaGFydCBvYmplY3Qgb3IgU1ZHIGNvbmZpZ3VyYXRpb24gdG8gYmUgZXhwb3J0ZWQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gRXhwb3J0IG9wdGlvbnMgYW5kIGNvbmZpZ3VyYXRpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZyB8IEJ1ZmZlciB8IEV4cG9ydEVycm9yPn0gUHJvbWlzZSByZXNvbHZpbmcgdG9cclxuICogdGhlIGV4cG9ydGVkIGRhdGEgb3IgcmVqZWN0aW5nIHdpdGggYW4gRXhwb3J0RXJyb3IuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCBhc3luYyAocGFnZSwgY2hhcnQsIG9wdGlvbnMpID0+IHtcclxuICAvKipcclxuICAgKiBLZWVwcyB0cmFjayBvZiBhbGwgcmVzb3VyY2VzIGFkZGVkIG9uIHRoZSBwYWdlIHdpdGggYWRkWFhYVGFnLiBldGNcclxuICAgKiBJdCdzIFZJVEFMIHRoYXQgYWxsIGFkZGVkIHJlc291cmNlcyBlbmRzIHVwIGhlcmUgc28gd2UgY2FuIGNsZWFyIHRoaW5nc1xyXG4gICAqIG91dCB3aGVuIGRvaW5nIGEgbmV3IGV4cG9ydCBpbiB0aGUgc2FtZSBwYWdlIVxyXG4gICAqL1xyXG4gIGNvbnN0IGluamVjdGVkUmVzb3VyY2VzID0gW107XHJcblxyXG4gIC8qKiBDbGVhciBvdXQgYWxsIHN0YXRlIHNldCBvbiB0aGUgcGFnZSB3aXRoIGFkZFNjcmlwdFRhZy9hZGRTdHlsZVRhZy4gKi9cclxuICBjb25zdCBjbGVhckluamVjdGVkID0gYXN5bmMgKHBhZ2UpID0+IHtcclxuICAgIGZvciAoY29uc3QgcmVzIG9mIGluamVjdGVkUmVzb3VyY2VzKSB7XHJcbiAgICAgIGF3YWl0IHJlcy5kaXNwb3NlKCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmVzZXQgYWxsIENTUyBhbmQgc2NyaXB0IHRhZ3NcclxuICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xyXG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgY29uc3QgWywgLi4uc2NyaXB0c1RvUmVtb3ZlXSA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdzY3JpcHQnKTtcclxuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgIGNvbnN0IFssIC4uLnN0eWxlc1RvUmVtb3ZlXSA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdzdHlsZScpO1xyXG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgY29uc3QgWy4uLmxpbmtzVG9SZW1vdmVdID0gZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ2xpbmsnKTtcclxuXHJcbiAgICAgIC8vIFJlbW92ZSB0YWdzXHJcbiAgICAgIGZvciAoY29uc3QgZWxlbWVudCBvZiBbXHJcbiAgICAgICAgLi4uc2NyaXB0c1RvUmVtb3ZlLFxyXG4gICAgICAgIC4uLnN0eWxlc1RvUmVtb3ZlLFxyXG4gICAgICAgIC4uLmxpbmtzVG9SZW1vdmVcclxuICAgICAgXSkge1xyXG4gICAgICAgIGVsZW1lbnQucmVtb3ZlKCk7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG4gIH07XHJcblxyXG4gIHRyeSB7XHJcbiAgICBsb2coNCwgJ1tleHBvcnRdIERldGVybWluaW5nIGV4cG9ydCBwYXRoLicpO1xyXG5cclxuICAgIGNvbnN0IGV4cG9ydE9wdGlvbnMgPSBvcHRpb25zLmV4cG9ydDtcclxuXHJcbiAgICAvLyBGb3JjZSBhIHJBRlxyXG4gICAgLy8gU2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9wdXBwZXRlZXIvcHVwcGV0ZWVyL2lzc3Vlcy83NTA3XHJcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4gcmVxdWVzdEFuaW1hdGlvbkZyYW1lKCgpID0+IHt9KSk7XHJcblxyXG4gICAgLy8gRGVjaWRlIHdoZXRoZXIgZGlzcGxheSBlcnJvciBvciBkZWJidWdlciB3cmFwcGVyIGFyb3VuZCBpdFxyXG4gICAgY29uc3QgZGlzcGxheUVycm9ycyA9XHJcbiAgICAgIGV4cG9ydE9wdGlvbnM/Lm9wdGlvbnM/LmNoYXJ0Py5kaXNwbGF5RXJyb3JzICYmXHJcbiAgICAgIGNhY2hlLmdldENhY2hlKCkuYWN0aXZlTWFuaWZlc3QubW9kdWxlcy5kZWJ1Z2dlcjtcclxuXHJcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoKGQpID0+ICh3aW5kb3cuX2Rpc3BsYXlFcnJvcnMgPSBkKSwgZGlzcGxheUVycm9ycyk7XHJcblxyXG4gICAgbGV0IGlzU1ZHO1xyXG4gICAgaWYgKFxyXG4gICAgICBjaGFydC5pbmRleE9mICYmXHJcbiAgICAgIChjaGFydC5pbmRleE9mKCc8c3ZnJykgPj0gMCB8fCBjaGFydC5pbmRleE9mKCc8P3htbCcpID49IDApXHJcbiAgICApIHtcclxuICAgICAgLy8gU1ZHIGlucHV0IGhhbmRsaW5nXHJcbiAgICAgIGxvZyg0LCAnW2V4cG9ydF0gVHJlYXRpbmcgYXMgU1ZHLicpO1xyXG5cclxuICAgICAgLy8gSWYgaW5wdXQgaXMgYWxzbyBTVkcsIGp1c3QgcmV0dXJuIGl0XHJcbiAgICAgIGlmIChleHBvcnRPcHRpb25zLnR5cGUgPT09ICdzdmcnKSB7XHJcbiAgICAgICAgcmV0dXJuIGNoYXJ0O1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpc1NWRyA9IHRydWU7XHJcbiAgICAgIGF3YWl0IHBhZ2Uuc2V0Q29udGVudChzdmdUZW1wbGF0ZShjaGFydCkpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gSlNPTiBjb25maWcgaGFuZGxpbmdcclxuICAgICAgbG9nKDQsICdbZXhwb3J0XSBUcmVhdGluZyBhcyBjb25maWcuJyk7XHJcblxyXG4gICAgICAvLyBOZWVkIHRvIHBlcmZvcm0gc3RyYWlnaHQgaW5qZWN0XHJcbiAgICAgIGlmIChleHBvcnRPcHRpb25zLnN0ckluaikge1xyXG4gICAgICAgIC8vIEluamVjdGlvbiBiYXNlZCBjb25maWd1cmF0aW9uIGV4cG9ydFxyXG4gICAgICAgIGF3YWl0IHNldEFzQ29uZmlnKFxyXG4gICAgICAgICAgcGFnZSxcclxuICAgICAgICAgIHtcclxuICAgICAgICAgICAgY2hhcnQ6IHtcclxuICAgICAgICAgICAgICBoZWlnaHQ6IGV4cG9ydE9wdGlvbnMuaGVpZ2h0LFxyXG4gICAgICAgICAgICAgIHdpZHRoOiBleHBvcnRPcHRpb25zLndpZHRoXHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0sXHJcbiAgICAgICAgICBvcHRpb25zXHJcbiAgICAgICAgKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICAvLyBCYXNpYyBjb25maWd1cmF0aW9uIGV4cG9ydFxyXG4gICAgICAgIGNoYXJ0LmNoYXJ0LmhlaWdodCA9IGV4cG9ydE9wdGlvbnMuaGVpZ2h0O1xyXG4gICAgICAgIGNoYXJ0LmNoYXJ0LndpZHRoID0gZXhwb3J0T3B0aW9ucy53aWR0aDtcclxuXHJcbiAgICAgICAgYXdhaXQgc2V0QXNDb25maWcocGFnZSwgY2hhcnQsIG9wdGlvbnMpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gVXNlIHJlc291cmNlc1xyXG4gICAgY29uc3QgcmVzb3VyY2VzID0gb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXM7XHJcbiAgICBpZiAocmVzb3VyY2VzKSB7XHJcbiAgICAgIC8vIExvYWQgY3VzdG9tIEpTIGNvZGVcclxuICAgICAgaWYgKHJlc291cmNlcy5qcykge1xyXG4gICAgICAgIGluamVjdGVkUmVzb3VyY2VzLnB1c2goXHJcbiAgICAgICAgICBhd2FpdCBwYWdlLmFkZFNjcmlwdFRhZyh7XHJcbiAgICAgICAgICAgIGNvbnRlbnQ6IHJlc291cmNlcy5qc1xyXG4gICAgICAgICAgfSlcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBMb2FkIHNjcmlwdHMgZnJvbSBhbGwgY3VzdG9tIGZpbGVzXHJcbiAgICAgIGlmIChyZXNvdXJjZXMuZmlsZXMpIHtcclxuICAgICAgICBmb3IgKGNvbnN0IGZpbGUgb2YgcmVzb3VyY2VzLmZpbGVzKSB7XHJcbiAgICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICBjb25zdCBpc0xvY2FsID0gIWZpbGUuc3RhcnRzV2l0aCgnaHR0cCcpID8gdHJ1ZSA6IGZhbHNlO1xyXG5cclxuICAgICAgICAgICAgLy8gQWRkIGVhY2ggY3VzdG9tIHNjcmlwdCBmcm9tIHJlc291cmNlcycgZmlsZXNcclxuICAgICAgICAgICAgaW5qZWN0ZWRSZXNvdXJjZXMucHVzaChcclxuICAgICAgICAgICAgICBhd2FpdCBwYWdlLmFkZFNjcmlwdFRhZyhcclxuICAgICAgICAgICAgICAgIGlzTG9jYWxcclxuICAgICAgICAgICAgICAgICAgPyB7XHJcbiAgICAgICAgICAgICAgICAgICAgICBjb250ZW50OiByZWFkRmlsZVN5bmMoZmlsZSwgJ3V0ZjgnKVxyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgOiB7XHJcbiAgICAgICAgICAgICAgICAgICAgICB1cmw6IGZpbGVcclxuICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgKVxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgICAgICAgIDIsXHJcbiAgICAgICAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgICAgICAgYFtleHBvcnRdIFRoZSBKUyBmaWxlICR7ZmlsZX0gY2Fubm90IGJlIGxvYWRlZC5gXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBMb2FkIENTU1xyXG4gICAgICBpZiAocmVzb3VyY2VzLmNzcykge1xyXG4gICAgICAgIGxldCBjc3NJbXBvcnRzID0gcmVzb3VyY2VzLmNzcy5tYXRjaCgvQGltcG9ydFxccyooW147XSopOy9nKTtcclxuICAgICAgICBpZiAoY3NzSW1wb3J0cykge1xyXG4gICAgICAgICAgLy8gSGFuZGxlIGNzcyBzZWN0aW9uXHJcbiAgICAgICAgICBmb3IgKGxldCBjc3NJbXBvcnRQYXRoIG9mIGNzc0ltcG9ydHMpIHtcclxuICAgICAgICAgICAgaWYgKGNzc0ltcG9ydFBhdGgpIHtcclxuICAgICAgICAgICAgICBjc3NJbXBvcnRQYXRoID0gY3NzSW1wb3J0UGF0aFxyXG4gICAgICAgICAgICAgICAgLnJlcGxhY2UoJ3VybCgnLCAnJylcclxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKCdAaW1wb3J0JywgJycpXHJcbiAgICAgICAgICAgICAgICAucmVwbGFjZSgvXCIvZywgJycpXHJcbiAgICAgICAgICAgICAgICAucmVwbGFjZSgvJy9nLCAnJylcclxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKC87LywgJycpXHJcbiAgICAgICAgICAgICAgICAucmVwbGFjZSgvXFwpL2csICcnKVxyXG4gICAgICAgICAgICAgICAgLnRyaW0oKTtcclxuXHJcbiAgICAgICAgICAgICAgLy8gQWRkIGVhY2ggY3VzdG9tIGNzcyBmcm9tIHJlc291cmNlc1xyXG4gICAgICAgICAgICAgIGlmIChjc3NJbXBvcnRQYXRoLnN0YXJ0c1dpdGgoJ2h0dHAnKSkge1xyXG4gICAgICAgICAgICAgICAgaW5qZWN0ZWRSZXNvdXJjZXMucHVzaChcclxuICAgICAgICAgICAgICAgICAgYXdhaXQgcGFnZS5hZGRTdHlsZVRhZyh7XHJcbiAgICAgICAgICAgICAgICAgICAgdXJsOiBjc3NJbXBvcnRQYXRoXHJcbiAgICAgICAgICAgICAgICAgIH0pXHJcbiAgICAgICAgICAgICAgICApO1xyXG4gICAgICAgICAgICAgIH0gZWxzZSBpZiAob3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0ZpbGVSZXNvdXJjZXMpIHtcclxuICAgICAgICAgICAgICAgIGluamVjdGVkUmVzb3VyY2VzLnB1c2goXHJcbiAgICAgICAgICAgICAgICAgIGF3YWl0IHBhZ2UuYWRkU3R5bGVUYWcoe1xyXG4gICAgICAgICAgICAgICAgICAgIHBhdGg6IHBhdGguam9pbihfX2Jhc2VkaXIsIGNzc0ltcG9ydFBhdGgpXHJcbiAgICAgICAgICAgICAgICAgIH0pXHJcbiAgICAgICAgICAgICAgICApO1xyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gVGhlIHJlc3Qgb2YgdGhlIENTUyBzZWN0aW9uIHdpbGwgYmUgY29udGVudCBieSBub3dcclxuICAgICAgICBpbmplY3RlZFJlc291cmNlcy5wdXNoKFxyXG4gICAgICAgICAgYXdhaXQgcGFnZS5hZGRTdHlsZVRhZyh7XHJcbiAgICAgICAgICAgIGNvbnRlbnQ6IHJlc291cmNlcy5jc3MucmVwbGFjZSgvQGltcG9ydFxccyooW147XSopOy9nLCAnJykgfHwgJyAnXHJcbiAgICAgICAgICB9KVxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBHZXQgdGhlIHJlYWwgY2hhcnQgc2l6ZVxyXG4gICAgY29uc3Qgc2l6ZSA9IGlzU1ZHXHJcbiAgICAgID8gYXdhaXQgcGFnZS4kZXZhbChcclxuICAgICAgICAgICcjY2hhcnQtY29udGFpbmVyIHN2ZzpmaXJzdC1vZi10eXBlJyxcclxuICAgICAgICAgIChlbGVtZW50LCBzY2FsZSkgPT4gKHtcclxuICAgICAgICAgICAgY2hhcnRIZWlnaHQ6IGVsZW1lbnQuaGVpZ2h0LmJhc2VWYWwudmFsdWUgKiBzY2FsZSxcclxuICAgICAgICAgICAgY2hhcnRXaWR0aDogZWxlbWVudC53aWR0aC5iYXNlVmFsLnZhbHVlICogc2NhbGVcclxuICAgICAgICAgIH0pLFxyXG4gICAgICAgICAgcGFyc2VGbG9hdChleHBvcnRPcHRpb25zLnNjYWxlKVxyXG4gICAgICAgIClcclxuICAgICAgOiBhd2FpdCBwYWdlLmV2YWx1YXRlKCgpID0+IHtcclxuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgICAgY29uc3QgeyBjaGFydEhlaWdodCwgY2hhcnRXaWR0aCB9ID0gd2luZG93LkhpZ2hjaGFydHMuY2hhcnRzWzBdO1xyXG4gICAgICAgICAgcmV0dXJuIHtcclxuICAgICAgICAgICAgY2hhcnRIZWlnaHQsXHJcbiAgICAgICAgICAgIGNoYXJ0V2lkdGhcclxuICAgICAgICAgIH07XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgLy8gU2V0IGZpbmFsIGhlaWdodCBhbmQgd2lkdGggZm9yIHZpZXdwb3J0XHJcbiAgICBjb25zdCB2aWV3cG9ydEhlaWdodCA9IE1hdGguY2VpbChzaXplPy5jaGFydEhlaWdodCB8fCBleHBvcnRPcHRpb25zLmhlaWdodCk7XHJcbiAgICBjb25zdCB2aWV3cG9ydFdpZHRoID0gTWF0aC5jZWlsKHNpemU/LmNoYXJ0V2lkdGggfHwgZXhwb3J0T3B0aW9ucy53aWR0aCk7XHJcblxyXG4gICAgLy8gU2V0IHRoZSB2aWV3cG9ydCBmb3IgdGhlIGZpcnN0IHRpbWVcclxuICAgIC8vIE5PVEU6IHRoZSBjYWxsIHRvIHNldFZpZXdwb3J0IGlzIGV4cGVuc2l2ZSAtIGNhbiB3ZSBnZXQgYXdheSB3aXRoIG9ubHlcclxuICAgIC8vIGNhbGxpbmcgaXQgb25jZSwgZS5nLiBtb3ZpbmcgdGhpcyBvbmUgaW50byB0aGUgaXNTVkcgY29uZGl0aW9uIGJlbG93P1xyXG4gICAgYXdhaXQgcGFnZS5zZXRWaWV3cG9ydCh7XHJcbiAgICAgIGhlaWdodDogdmlld3BvcnRIZWlnaHQsXHJcbiAgICAgIHdpZHRoOiB2aWV3cG9ydFdpZHRoLFxyXG4gICAgICBkZXZpY2VTY2FsZUZhY3RvcjogaXNTVkcgPyAxIDogcGFyc2VGbG9hdChleHBvcnRPcHRpb25zLnNjYWxlKVxyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gUHJlcGFyZSBhIHpvb20gY2FsbGJhY2sgZm9yIHRoZSBuZXh0IGV2YWx1YXRlIGNhbGxcclxuICAgIGNvbnN0IHpvb21DYWxsYmFjayA9IGlzU1ZHXHJcbiAgICAgID8gLy8gSW4gY2FzZSBvZiBTVkcgdGhlIHpvb20gbXVzdCBiZSBzZXQgZGlyZWN0bHkgZm9yIGJvZHlcclxuICAgICAgICAoc2NhbGUpID0+IHtcclxuICAgICAgICAgIC8vIFNldCB0aGUgem9vbSBhcyBzY2FsZVxyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLnpvb20gPSBzY2FsZTtcclxuXHJcbiAgICAgICAgICAvLyBTZXQgdGhlIG1hcmdpbiB0byAwcHhcclxuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgICAgZG9jdW1lbnQuYm9keS5zdHlsZS5tYXJnaW4gPSAnMHB4JztcclxuICAgICAgICB9XHJcbiAgICAgIDogLy8gTm8gbmVlZCBmb3Igc3VjaCBzY2FsZSBtYW5pcHVsYXRpb24gaW4gY2FzZSBvZiBvdGhlciB0eXBlcyBvZiBleHBvcnRzXHJcbiAgICAgICAgKCkgPT4ge1xyXG4gICAgICAgICAgLy8gUmVzZXQgdGhlIHpvb20gZm9yIG90aGVyIGV4cG9ydHMgdGhhbiB0byBTVkdzXHJcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUuem9vbSA9IDE7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAvLyBTZXQgdGhlIHpvb20gYWNjb3JkaW5nbHlcclxuICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoem9vbUNhbGxiYWNrLCBwYXJzZUZsb2F0KGV4cG9ydE9wdGlvbnMuc2NhbGUpKTtcclxuXHJcbiAgICAvLyBHZXQgdGhlIGNsaXAgcmVnaW9uIGZvciB0aGUgcGFnZVxyXG4gICAgY29uc3QgeyBoZWlnaHQsIHdpZHRoLCB4LCB5IH0gPSBhd2FpdCBnZXRDbGlwUmVnaW9uKHBhZ2UpO1xyXG5cclxuICAgIGlmICghaXNTVkcpIHtcclxuICAgICAgLy8gU2V0IHRoZSBmaW5hbCB2aWV3cG9ydCBub3cgdGhhdCB3ZSBoYXZlIHRoZSByZWFsIGhlaWdodFxyXG4gICAgICBhd2FpdCBwYWdlLnNldFZpZXdwb3J0KHtcclxuICAgICAgICB3aWR0aDogTWF0aC5yb3VuZCh3aWR0aCksXHJcbiAgICAgICAgaGVpZ2h0OiBNYXRoLnJvdW5kKGhlaWdodCksXHJcbiAgICAgICAgZGV2aWNlU2NhbGVGYWN0b3I6IHBhcnNlRmxvYXQoZXhwb3J0T3B0aW9ucy5zY2FsZSlcclxuICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgbGV0IGRhdGE7XHJcbiAgICAvLyBSQVNURVJJWkFUSU9OXHJcbiAgICBpZiAoZXhwb3J0T3B0aW9ucy50eXBlID09PSAnc3ZnJykge1xyXG4gICAgICAvLyBTVkdcclxuICAgICAgZGF0YSA9IGF3YWl0IGNyZWF0ZVNWRyhwYWdlKTtcclxuICAgIH0gZWxzZSBpZiAoWydwbmcnLCAnanBlZyddLmluY2x1ZGVzKGV4cG9ydE9wdGlvbnMudHlwZSkpIHtcclxuICAgICAgLy8gUE5HIG9yIEpQRUdcclxuICAgICAgZGF0YSA9IGF3YWl0IGNyZWF0ZUltYWdlKFxyXG4gICAgICAgIHBhZ2UsXHJcbiAgICAgICAgZXhwb3J0T3B0aW9ucy50eXBlLFxyXG4gICAgICAgICdiYXNlNjQnLFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIHdpZHRoOiB2aWV3cG9ydFdpZHRoLFxyXG4gICAgICAgICAgaGVpZ2h0OiB2aWV3cG9ydEhlaWdodCxcclxuICAgICAgICAgIHgsXHJcbiAgICAgICAgICB5XHJcbiAgICAgICAgfSxcclxuICAgICAgICBleHBvcnRPcHRpb25zLnJhc3Rlcml6YXRpb25UaW1lb3V0XHJcbiAgICAgICk7XHJcbiAgICB9IGVsc2UgaWYgKGV4cG9ydE9wdGlvbnMudHlwZSA9PT0gJ3BkZicpIHtcclxuICAgICAgLy8gUERGXHJcbiAgICAgIGRhdGEgPSBhd2FpdCBjcmVhdGVQREYocGFnZSwgdmlld3BvcnRIZWlnaHQsIHZpZXdwb3J0V2lkdGgsICdiYXNlNjQnKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICBgW2V4cG9ydF0gVW5zdXBwb3J0ZWQgb3V0cHV0IGZvcm1hdCAke2V4cG9ydE9wdGlvbnMudHlwZX0uYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIERlc3Ryb3kgb2xkIGNoYXJ0cyBhZnRlciB0aGUgZXhwb3J0IGlzIGRvbmVcclxuICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xyXG4gICAgICAvLyBXZSBhcmUgbm90IGd1YXJhbnRlZWQgdGhhdCBIaWdoY2hhcnRzIGlzIGxvYWRlZCwgZSxnLCB3aGVuIGRvaW5nIFNWR1xyXG4gICAgICAvLyBleHBvcnRzXHJcbiAgICAgIGlmICh0eXBlb2YgSGlnaGNoYXJ0cyAhPT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICBjb25zdCBvbGRDaGFydHMgPSBIaWdoY2hhcnRzLmNoYXJ0cztcclxuXHJcbiAgICAgICAgLy8gQ2hlY2sgaW4gYW55IGFscmVhZHkgZXhpc3RpbmcgY2hhcnRzXHJcbiAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkob2xkQ2hhcnRzKSAmJiBvbGRDaGFydHMubGVuZ3RoKSB7XHJcbiAgICAgICAgICAvLyBEZXN0cm95IG9sZCBjaGFydHNcclxuICAgICAgICAgIGZvciAoY29uc3Qgb2xkQ2hhcnQgb2Ygb2xkQ2hhcnRzKSB7XHJcbiAgICAgICAgICAgIG9sZENoYXJ0ICYmIG9sZENoYXJ0LmRlc3Ryb3koKTtcclxuICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICAgIEhpZ2hjaGFydHMuY2hhcnRzLnNoaWZ0KCk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9KTtcclxuXHJcbiAgICBhd2FpdCBjbGVhckluamVjdGVkKHBhZ2UpO1xyXG4gICAgcmV0dXJuIGRhdGE7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIGF3YWl0IGNsZWFySW5qZWN0ZWQocGFnZSk7XHJcbiAgICByZXR1cm4gZXJyb3I7XHJcbiAgfVxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCBjc3NUZW1wbGF0ZSBmcm9tICcuL2Nzcy5qcyc7XHJcblxyXG5leHBvcnQgZGVmYXVsdCAoY2hhcnQpID0+IGBcclxuPCFET0NUWVBFIGh0bWw+XHJcbjxodG1sIGxhbmc9J2VuLVVTJz5cclxuICA8aGVhZD5cclxuICAgIDxtZXRhIGh0dHAtZXF1aXY9XCJDb250ZW50LVR5cGVcIiBjb250ZW50PVwidGV4dC9odG1sOyBjaGFyc2V0PXV0Zi04XCI+XHJcbiAgICA8dGl0bGU+SGlnaGNhcnRzIEV4cG9ydDwvdGl0bGU+XHJcbiAgPC9oZWFkPlxyXG4gIDxzdHlsZT5cclxuICAgICR7Y3NzVGVtcGxhdGUoKX1cclxuICA8L3N0eWxlPlxyXG4gIDxib2R5PlxyXG4gICAgPGRpdiBpZD1cImNoYXJ0LWNvbnRhaW5lclwiPlxyXG4gICAgICAke2NoYXJ0fVxyXG4gICAgPC9kaXY+XHJcbiAgPC9ib2R5PlxyXG48L2h0bWw+XHJcblxyXG5gO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IFBvb2wgfSBmcm9tICd0YXJuJztcclxuaW1wb3J0IHsgdjQgYXMgdXVpZCB9IGZyb20gJ3V1aWQnO1xyXG5cclxuaW1wb3J0IHtcclxuICBjbG9zZSBhcyBicm93c2VyQ2xvc2UsXHJcbiAgY3JlYXRlIGFzIGNyZWF0ZUJyb3dzZXIsXHJcbiAgbmV3UGFnZSBhcyBicm93c2VyTmV3UGFnZSxcclxuICBjbGVhclBhZ2VcclxufSBmcm9tICcuL2Jyb3dzZXIuanMnO1xyXG5pbXBvcnQgcHVwcGV0ZWVyRXhwb3J0IGZyb20gJy4vZXhwb3J0LmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IG1lYXN1cmVUaW1lIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxubGV0IHBlcmZvcm1lZEV4cG9ydHMgPSAwO1xyXG5sZXQgZXhwb3J0QXR0ZW1wdHMgPSAwO1xyXG5sZXQgdGltZVNwZW50ID0gMDtcclxubGV0IGRyb3BwZWRFeHBvcnRzID0gMDtcclxubGV0IHNwZW50QXZlcmFnZSA9IDA7XHJcbmxldCBwb29sQ29uZmlnID0ge307XHJcblxyXG4vLyBUaGUgcG9vbCBpbnN0YW5jZVxyXG5sZXQgcG9vbCA9IGZhbHNlO1xyXG5cclxuLy8gQ3VzdG9tIHB1cHBldGVlciBhcmd1bWVudHNcclxubGV0IHB1cHBldGVlckFyZ3M7XHJcblxyXG5jb25zdCBmYWN0b3J5ID0ge1xyXG4gIC8qKlxyXG4gICAqIENyZWF0ZXMgYSBuZXcgd29ya2VyIHBhZ2UgZm9yIHRoZSBleHBvcnQgcG9vbC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHtPYmplY3R9IC0gQW4gb2JqZWN0IGNvbnRhaW5pbmcgdGhlIHdvcmtlciBJRCwgYSByZWZlcmVuY2UgdG8gdGhlXHJcbiAgICogYnJvd3NlciBwYWdlLCBhbmQgaW5pdGlhbCB3b3JrIGNvdW50LlxyXG4gICAqXHJcbiAgICogQHRocm93cyB7RXhwb3J0RXJyb3J9IC0gSWYgdGhlcmUncyBhbiBlcnJvciBkdXJpbmcgdGhlIGNyZWF0aW9uIG9mIHRoZSBuZXdcclxuICAgKiBwYWdlLlxyXG4gICAqL1xyXG4gIGNyZWF0ZTogYXN5bmMgKCkgPT4ge1xyXG4gICAgbGV0IHBhZ2UgPSBmYWxzZTtcclxuXHJcbiAgICBjb25zdCBpZCA9IHV1aWQoKTtcclxuICAgIGNvbnN0IHN0YXJ0RGF0ZSA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xyXG5cclxuICAgIHRyeSB7XHJcbiAgICAgIHBhZ2UgPSBhd2FpdCBicm93c2VyTmV3UGFnZSgpO1xyXG5cclxuICAgICAgaWYgKCFwYWdlIHx8IHBhZ2UuaXNDbG9zZWQoKSkge1xyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignVGhlIHBhZ2UgaXMgaW52YWxpZCBvciBjbG9zZWQuJyk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGxvZyhcclxuICAgICAgICAzLFxyXG4gICAgICAgIGBbcG9vbF0gU3VjY2Vzc2Z1bGx5IGNyZWF0ZWQgYSB3b3JrZXIgJHtpZH0gLSB0b29rICR7XHJcbiAgICAgICAgICBuZXcgRGF0ZSgpLmdldFRpbWUoKSAtIHN0YXJ0RGF0ZVxyXG4gICAgICAgIH0gbXMuYFxyXG4gICAgICApO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdFcnJvciBlbmNvdW50ZXJlZCB3aGVuIGNyZWF0aW5nIGEgbmV3IHBhZ2UuJ1xyXG4gICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4ge1xyXG4gICAgICBpZCxcclxuICAgICAgcGFnZSxcclxuICAgICAgLy8gVHJ5IHRvIGRpc3RyaWJ1dGUgdGhlIGluaXRpYWwgd29yayBjb3VudFxyXG4gICAgICB3b3JrQ291bnQ6IE1hdGgucm91bmQoTWF0aC5yYW5kb20oKSAqIChwb29sQ29uZmlnLndvcmtMaW1pdCAvIDIpKVxyXG4gICAgfTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBWYWxpZGF0ZXMgYSB3b3JrZXIgcGFnZSBpbiB0aGUgZXhwb3J0IHBvb2wsIGNoZWNraW5nIGlmIGl0IGhhcyBleGNlZWRlZFxyXG4gICAqIHRoZSB3b3JrIGxpbWl0LlxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtPYmplY3R9IHdvcmtlckhhbmRsZSAtIFRoZSBoYW5kbGUgdG8gdGhlIHdvcmtlciwgY29udGFpbmluZyB0aGVcclxuICAgKiB3b3JrZXIncyBJRCwgYSByZWZlcmVuY2UgdG8gdGhlIGJyb3dzZXIgcGFnZSwgYW5kIHdvcmsgY291bnQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBSZXR1cm5zIHRydWUgaWYgdGhlIHdvcmtlciBpcyB2YWxpZCBhbmQgd2l0aGluXHJcbiAgICogdGhlIHdvcmsgbGltaXQ7IG90aGVyd2lzZSwgcmV0dXJucyBmYWxzZS5cclxuICAgKi9cclxuICB2YWxpZGF0ZTogYXN5bmMgKHdvcmtlckhhbmRsZSkgPT4ge1xyXG4gICAgaWYgKFxyXG4gICAgICBwb29sQ29uZmlnLndvcmtMaW1pdCAmJlxyXG4gICAgICArK3dvcmtlckhhbmRsZS53b3JrQ291bnQgPiBwb29sQ29uZmlnLndvcmtMaW1pdFxyXG4gICAgKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICAzLFxyXG4gICAgICAgIGBbcG9vbF0gV29ya2VyIGZhaWxlZCB2YWxpZGF0aW9uOiBleGNlZWRlZCB3b3JrIGxpbWl0IChsaW1pdCBpcyAke3Bvb2xDb25maWcud29ya0xpbWl0fSkuYFxyXG4gICAgICApO1xyXG4gICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2xlYXIgcGFnZVxyXG4gICAgYXdhaXQgY2xlYXJQYWdlKHdvcmtlckhhbmRsZS5wYWdlLCB0cnVlKTtcclxuICAgIHJldHVybiB0cnVlO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIERlc3Ryb3lzIGEgd29ya2VyIGVudHJ5IGluIHRoZSBleHBvcnQgcG9vbCwgY2xvc2luZyBpdHMgYXNzb2NpYXRlZCBwYWdlLlxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtPYmplY3R9IHdvcmtlckhhbmRsZSAtIFRoZSBoYW5kbGUgdG8gdGhlIHdvcmtlciwgY29udGFpbmluZ1xyXG4gICAqIHRoZSB3b3JrZXIncyBJRCBhbmQgYSByZWZlcmVuY2UgdG8gdGhlIGJyb3dzZXIgcGFnZS5cclxuICAgKi9cclxuICBkZXN0cm95OiAod29ya2VySGFuZGxlKSA9PiB7XHJcbiAgICBsb2coMywgYFtwb29sXSBEZXN0cm95aW5nIHBvb2wgZW50cnkgJHt3b3JrZXJIYW5kbGUuaWR9LmApO1xyXG5cclxuICAgIGlmICh3b3JrZXJIYW5kbGUucGFnZSkge1xyXG4gICAgICAvLyBXZSBkb24ndCByZWFsbHkgbmVlZCB0byB3YWl0IGFyb3VuZCBmb3IgdGhpcy5cclxuICAgICAgd29ya2VySGFuZGxlLnBhZ2UuY2xvc2UoKTtcclxuICAgIH1cclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgdGhlIGV4cG9ydCBwb29sIHdpdGggdGhlIHByb3ZpZGVkIGNvbmZpZ3VyYXRpb24sIGNyZWF0aW5nXHJcbiAqIGEgYnJvd3NlciBpbnN0YW5jZSBhbmQgc2V0dGluZyB1cCB3b3JrZXIgcmVzb3VyY2VzLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnIC0gQ29uZmlndXJhdGlvbiBvcHRpb25zIGZvciB0aGUgZXhwb3J0IHBvb2wgYWxvbmdcclxuICogd2l0aCBjdXN0b20gcHVwcGV0ZWVyIGFyZ3VtZW50cyBmb3IgdGhlIHB1cHBldGVlci5sYXVuY2ggZnVuY3Rpb24uXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaW5pdFBvb2wgPSBhc3luYyAoY29uZmlnKSA9PiB7XHJcbiAgLy8gRm9yIHRoZSBtb2R1bGUgc2NvcGUgdXNhZ2VcclxuICBwb29sQ29uZmlnID0gY29uZmlnICYmIGNvbmZpZy5wb29sID8geyAuLi5jb25maWcucG9vbCB9IDoge307XHJcblxyXG4gIC8vIEF0dGFjaCBwcm9jZXNzJyBleGl0IGxpc3RlbmVyc1xyXG4gIGlmIChwb29sQ29uZmlnLmxpc3RlblRvUHJvY2Vzc0V4aXRzKSB7XHJcbiAgICBhdHRhY2hQcm9jZXNzRXhpdExpc3RlbmVycygpO1xyXG4gIH1cclxuXHJcbiAgLy8gVGhlIG5ld2VzdCBwdXBwZXRlZXIgYXJndW1lbnRzIGZvciB0aGUgYnJvd3NlciBjcmVhdGlvblxyXG4gIHB1cHBldGVlckFyZ3MgPSBjb25maWcucHVwcGV0ZWVyQXJncztcclxuXHJcbiAgLy8gQ3JlYXRlIGEgYnJvd3NlciBpbnN0YW5jZVxyXG4gIGF3YWl0IGNyZWF0ZUJyb3dzZXIocHVwcGV0ZWVyQXJncyk7XHJcblxyXG4gIGxvZyhcclxuICAgIDMsXHJcbiAgICBgW3Bvb2xdIEluaXRpYWxpemluZyBwb29sIHdpdGggd29ya2VyczogbWluICR7cG9vbENvbmZpZy5taW5Xb3JrZXJzfSwgbWF4ICR7cG9vbENvbmZpZy5tYXhXb3JrZXJzfS5gXHJcbiAgKTtcclxuXHJcbiAgaWYgKHBvb2wpIHtcclxuICAgIHJldHVybiBsb2coXHJcbiAgICAgIDQsXHJcbiAgICAgICdbcG9vbF0gQWxyZWFkeSBpbml0aWFsaXplZCwgcGxlYXNlIGtpbGwgaXQgYmVmb3JlIGNyZWF0aW5nIGEgbmV3IG9uZS4nXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgaWYgKHBhcnNlSW50KHBvb2xDb25maWcubWluV29ya2VycykgPiBwYXJzZUludChwb29sQ29uZmlnLm1heFdvcmtlcnMpKSB7XHJcbiAgICBwb29sQ29uZmlnLm1pbldvcmtlcnMgPSBwb29sQ29uZmlnLm1heFdvcmtlcnM7XHJcbiAgfVxyXG5cclxuICB0cnkge1xyXG4gICAgLy8gQ3JlYXRlIGEgcG9vbCBhbG9uZyB3aXRoIGEgbWluaW1hbCBudW1iZXIgb2YgcmVzb3VyY2VzXHJcbiAgICBwb29sID0gbmV3IFBvb2woe1xyXG4gICAgICAvLyBHZXQgdGhlIGNyZWF0ZS92YWxpZGF0ZS9kZXN0cm95L2xvZyBmdW5jdGlvbnNcclxuICAgICAgLi4uZmFjdG9yeSxcclxuICAgICAgbWluOiBwYXJzZUludChwb29sQ29uZmlnLm1pbldvcmtlcnMpLFxyXG4gICAgICBtYXg6IHBhcnNlSW50KHBvb2xDb25maWcubWF4V29ya2VycyksXHJcbiAgICAgIGFjcXVpcmVUaW1lb3V0TWlsbGlzOiBwb29sQ29uZmlnLmFjcXVpcmVUaW1lb3V0LFxyXG4gICAgICBjcmVhdGVUaW1lb3V0TWlsbGlzOiBwb29sQ29uZmlnLmNyZWF0ZVRpbWVvdXQsXHJcbiAgICAgIGRlc3Ryb3lUaW1lb3V0TWlsbGlzOiBwb29sQ29uZmlnLmRlc3Ryb3lUaW1lb3V0LFxyXG4gICAgICBpZGxlVGltZW91dE1pbGxpczogcG9vbENvbmZpZy5pZGxlVGltZW91dCxcclxuICAgICAgY3JlYXRlUmV0cnlJbnRlcnZhbE1pbGxpczogcG9vbENvbmZpZy5jcmVhdGVSZXRyeUludGVydmFsLFxyXG4gICAgICByZWFwSW50ZXJ2YWxNaWxsaXM6IHBvb2xDb25maWcucmVhcGVySW50ZXJ2YWwsXHJcbiAgICAgIHByb3BhZ2F0ZUNyZWF0ZUVycm9yOiBmYWxzZVxyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gU2V0IGV2ZW50c1xyXG4gICAgcG9vbC5vbigncmVsZWFzZScsIGFzeW5jIChyZXNvdXJjZSkgPT4ge1xyXG4gICAgICAvLyBDbGVhciBwYWdlXHJcbiAgICAgIGF3YWl0IGNsZWFyUGFnZShyZXNvdXJjZS5wYWdlLCBmYWxzZSk7XHJcbiAgICAgIGxvZyg0LCBgW3Bvb2xdIFJlbGVhc2luZyBhIHdvcmtlciB3aXRoIElEICR7cmVzb3VyY2UuaWR9LmApO1xyXG4gICAgfSk7XHJcblxyXG4gICAgcG9vbC5vbignZGVzdHJveVN1Y2Nlc3MnLCAoZXZlbnRJZCwgcmVzb3VyY2UpID0+IHtcclxuICAgICAgbG9nKDQsIGBbcG9vbF0gRGVzdHJveWVkIGEgd29ya2VyIHdpdGggSUQgJHtyZXNvdXJjZS5pZH0uYCk7XHJcbiAgICB9KTtcclxuXHJcbiAgICBjb25zdCBpbml0aWFsUmVzb3VyY2VzID0gW107XHJcbiAgICAvLyBDcmVhdGUgYW4gaW5pdGlhbCBudW1iZXIgb2YgcmVzb3VyY2VzXHJcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHBvb2xDb25maWcubWluV29ya2VyczsgaSsrKSB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgY29uc3QgcmVzb3VyY2UgPSBhd2FpdCBwb29sLmFjcXVpcmUoKS5wcm9taXNlO1xyXG4gICAgICAgIGluaXRpYWxSZXNvdXJjZXMucHVzaChyZXNvdXJjZSk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCAnW3Bvb2xdIENvdWxkIG5vdCBjcmVhdGUgYW4gaW5pdGlhbCByZXNvdXJjZS4nKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIFJlbGVhc2UgdGhlIGluaXRpYWwgbnVtYmVyIG9mIHJlc291cmNlcyBiYWNrIHRvIHRoZSBwb29sXHJcbiAgICBpbml0aWFsUmVzb3VyY2VzLmZvckVhY2goKHJlc291cmNlKSA9PiB7XHJcbiAgICAgIHBvb2wucmVsZWFzZShyZXNvdXJjZSk7XHJcbiAgICB9KTtcclxuXHJcbiAgICBsb2coXHJcbiAgICAgIDMsXHJcbiAgICAgIGBbcG9vbF0gVGhlIHBvb2wgaXMgcmVhZHkke2luaXRpYWxSZXNvdXJjZXMubGVuZ3RoID8gYCB3aXRoICR7aW5pdGlhbFJlc291cmNlcy5sZW5ndGh9IGluaXRpYWwgcmVzb3VyY2VzIHdhaXRpbmcuYCA6ICcuJ31gXHJcbiAgICApO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAvLyBDbG9zZSBicm93c2VyIGlmIGZvciBzb21lIHJlYXNvbiBjYW5ub3QgZXN0YWJsaXNoIHRoZSBwb29sXHJcbiAgICBhd2FpdCBicm93c2VyQ2xvc2UoKTtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1twb29sXSBDb3VsZCBub3QgY3JlYXRlIHRoZSBwb29sIG9mIHdvcmtlcnMuJ1xyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEF0dGFjaGVzIGV4aXQgbGlzdGVuZXJzIHRvIHRoZSBwcm9jZXNzLCBlbnN1cmluZyBwcm9wZXIgY2xlYW51cCBvZiByZXNvdXJjZXNcclxuICogYW5kIHRlcm1pbmF0aW9uIG9uIGV4aXQgc2lnbmFscy4gSGFuZGxlcyAnZXhpdCcsICdTSUdJTlQnLCAnU0lHVEVSTScsIGFuZFxyXG4gKiAndW5jYXVnaHRFeGNlcHRpb24nIGV2ZW50cy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBhdHRhY2hQcm9jZXNzRXhpdExpc3RlbmVycygpIHtcclxuICBsb2coMywgJ1twb29sXSBBdHRhY2hpbmcgZXhpdCBsaXN0ZW5lcnMgdG8gdGhlIHByb2Nlc3MuJyk7XHJcblxyXG4gIC8vIEtpbGwgYWxsIHBvb2wgcmVzb3VyY2VzIG9uIGV4aXRcclxuICBwcm9jZXNzLm9uKCdleGl0JywgYXN5bmMgKGNvZGUpID0+IHtcclxuICAgIGxvZyg0LCBgUHJvY2VzcyBleGl0ZWQgd2l0aCBjb2RlICR7Y29kZX0uYCk7XHJcbiAgICBhd2FpdCBraWxsUG9vbCgpO1xyXG4gIH0pO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgU0lHSU5UXHJcbiAgcHJvY2Vzcy5vbignU0lHSU5UJywgKG5hbWUsIGNvZGUpID0+IHtcclxuICAgIGxvZyg0LCBgVGhlICR7bmFtZX0gZXZlbnQgd2l0aCBjb2RlOiAke2NvZGV9LmApO1xyXG4gICAgcHJvY2Vzcy5leGl0KDEpO1xyXG4gIH0pO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgU0lHVEVSTVxyXG4gIHByb2Nlc3Mub24oJ1NJR1RFUk0nLCAobmFtZSwgY29kZSkgPT4ge1xyXG4gICAgbG9nKDQsIGBUaGUgJHtuYW1lfSBldmVudCB3aXRoIGNvZGU6ICR7Y29kZX0uYCk7XHJcbiAgICBwcm9jZXNzLmV4aXQoMSk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSB1bmNhdWdodEV4Y2VwdGlvblxyXG4gIHByb2Nlc3Mub24oJ3VuY2F1Z2h0RXhjZXB0aW9uJywgYXN5bmMgKGVycm9yLCBuYW1lKSA9PiB7XHJcbiAgICBsb2dXaXRoU3RhY2soMSwgZXJyb3IsIGBUaGUgJHtuYW1lfSBlcnJvci5gKTtcclxuICAgIGF3YWl0IGtpbGxQb29sKCk7XHJcbiAgICBwcm9jZXNzLmV4aXQoMSk7XHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBLaWxscyBhbGwgd29ya2VycyBpbiB0aGUgcG9vbCwgZGVzdHJveXMgdGhlIHBvb2wsIGFuZCBjbG9zZXMgdGhlIGJyb3dzZXJcclxuICogaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyBhZnRlciB0aGUgd29ya2VycyBhcmVcclxuICoga2lsbGVkLCB0aGUgcG9vbCBpcyBkZXN0cm95ZWQsIGFuZCB0aGUgYnJvd3NlciBpcyBjbG9zZWQuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24ga2lsbFBvb2woKSB7XHJcbiAgbG9nKDMsICdbcG9vbF0gS2lsbGluZyBhbGwgcG9vbCB3b3JrZXJzIGFuZCBicm93c2VyLCBpZiBhbnkgZXhpc3QuJyk7XHJcblxyXG4gIC8vIFJldHVybiB0cnVlIHdoZW4gdGhlIHBvb2wgaXMgYWxyZWFkeSBkZXN0cm95ZWRcclxuICBpZiAocG9vbD8uZGVzdHJveWVkKSB7XHJcbiAgICAvLyBDbG9zZSB0aGUgYnJvd3NlciBpbnN0YW5jZSBpZiBzdGlsbCBjb25uZWN0ZWRcclxuICAgIHJldHVybiBicm93c2VyQ2xvc2UoKTtcclxuICB9XHJcblxyXG4gIC8vIElmIHN0aWxsIGFsaXZlLCBkZXN0cm95IHRoZSBwb29sIG9mIHBhZ2VzIGJlZm9yZSBjbG9zaW5nIGEgYnJvd3NlclxyXG4gIGlmIChwb29sKSB7XHJcbiAgICBhd2FpdCBwb29sLmRlc3Ryb3koKTtcclxuICAgIGxvZyg0LCAnW2Jyb3dzZXJdIERlc3Ryb3llZCB0aGUgcG9vbCBvZiByZXNvdXJjZXMuJyk7XHJcbiAgfVxyXG5cclxuICAvLyBDbG9zZSB0aGUgYnJvd3NlciBpbnN0YW5jZVxyXG4gIHJldHVybiBicm93c2VyQ2xvc2UoKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFByb2Nlc3NlcyB0aGUgZXhwb3J0IHdvcmsgdXNpbmcgYSB3b3JrZXIgZnJvbSB0aGUgcG9vbC4gQWNxdWlyZXMgYSB3b3JrZXJcclxuICogaGFuZGxlIGZyb20gdGhlIHBvb2wsIHBlcmZvcm1zIHRoZSBleHBvcnQgdXNpbmcgcHVwcGV0ZWVyLCBhbmQgcmVsZWFzZXNcclxuICogdGhlIHdvcmtlciBoYW5kbGUgYmFjayB0byB0aGUgcG9vbC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGNoYXJ0IC0gVGhlIGNoYXJ0IGRhdGEgb3IgY29uZmlndXJhdGlvbiB0byBiZSBleHBvcnRlZC5cclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBFeHBvcnQgb3B0aW9ucyBhbmQgY29uZmlndXJhdGlvbi5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2l0aCB0aGUgZXhwb3J0IHJlc3VsdGFuZFxyXG4gKiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gSWYgYW4gZXJyb3Igb2NjdXJzIGR1cmluZyB0aGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgcG9zdFdvcmsgPSBhc3luYyAoY2hhcnQsIG9wdGlvbnMpID0+IHtcclxuICBsZXQgd29ya2VySGFuZGxlO1xyXG5cclxuICB0cnkge1xyXG4gICAgbG9nKDQsICdbcG9vbF0gV29yayByZWNlaXZlZCwgc3RhcnRpbmcgdG8gcHJvY2Vzcy4nKTtcclxuXHJcbiAgICArK2V4cG9ydEF0dGVtcHRzO1xyXG4gICAgaWYgKHBvb2xDb25maWcuYmVuY2htYXJraW5nKSB7XHJcbiAgICAgIGdldFBvb2xJbmZvKCk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKCFwb29sKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignV29yayByZWNlaXZlZCwgYnV0IHBvb2wgaGFzIG5vdCBiZWVuIHN0YXJ0ZWQuJyk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQWNxdWlyZSB0aGUgd29ya2VyIGFsb25nIHdpdGggdGhlIGlkIG9mIHJlc291cmNlIGFuZCB3b3JrIGNvdW50XHJcbiAgICB0cnkge1xyXG4gICAgICBsb2coNCwgJ1twb29sXSBBY3F1aXJpbmcgYSB3b3JrZXIgaGFuZGxlLicpO1xyXG4gICAgICBjb25zdCBhY3F1aXJlQ291bnRlciA9IG1lYXN1cmVUaW1lKCk7XHJcbiAgICAgIHdvcmtlckhhbmRsZSA9IGF3YWl0IHBvb2wuYWNxdWlyZSgpLnByb21pc2U7XHJcblxyXG4gICAgICAvLyBDaGVjayB0aGUgcGFnZSBhY3F1aXJlIHRpbWVcclxuICAgICAgaWYgKG9wdGlvbnMuc2VydmVyLmJlbmNobWFya2luZykge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDUsXHJcbiAgICAgICAgICBvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZFxyXG4gICAgICAgICAgICA/IGBbYmVuY2htYXJrXSBSZXF1ZXN0IHdpdGggSUQgJHtvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZH0gLWBcclxuICAgICAgICAgICAgOiAnW2JlbmNobWFya10nLFxyXG4gICAgICAgICAgYEFjcXVpcmVkIGEgd29ya2VyIGhhbmRsZTogJHthY3F1aXJlQ291bnRlcigpfW1zLmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ0Vycm9yIGVuY291bnRlcmVkIHdoZW4gYWNxdWlyaW5nIGFuIGF2YWlsYWJsZSBlbnRyeS4nXHJcbiAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgfVxyXG4gICAgbG9nKDQsICdbcG9vbF0gQWNxdWlyZWQgYSB3b3JrZXIgaGFuZGxlLicpO1xyXG5cclxuICAgIGlmICghd29ya2VySGFuZGxlLnBhZ2UpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdSZXNvbHZlZCB3b3JrZXIgcGFnZSBpcyBpbnZhbGlkOiB0aGUgcG9vbCBzZXR1cCBpcyB3b25reS4nXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU2F2ZSB0aGUgc3RhcnQgdGltZVxyXG4gICAgbGV0IHdvcmtTdGFydCA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xyXG5cclxuICAgIGxvZyg0LCBgW3Bvb2xdIFN0YXJ0aW5nIHdvcmsgb24gcG9vbCBlbnRyeSB3aXRoIElEICR7d29ya2VySGFuZGxlLmlkfS5gKTtcclxuXHJcbiAgICAvLyBQZXJmb3JtIGFuIGV4cG9ydCBvbiBhIHB1cHBldGVlciBsZXZlbFxyXG4gICAgY29uc3QgZXhwb3J0Q291bnRlciA9IG1lYXN1cmVUaW1lKCk7XHJcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBwdXBwZXRlZXJFeHBvcnQod29ya2VySGFuZGxlLnBhZ2UsIGNoYXJ0LCBvcHRpb25zKTtcclxuXHJcbiAgICAvLyBDaGVjayBpZiBpdCdzIGFuIGVycm9yXHJcbiAgICBpZiAocmVzdWx0IGluc3RhbmNlb2YgRXJyb3IpIHtcclxuICAgICAgLy8gVE9ETzogSWYgdGhlIGV4cG9ydCBmYWlsZWQgYmVjYXVzZSBwdXBwZXRlZXIgdGltZWQgb3V0LCB3ZSBuZWVkIHRvIGZvcmNlIGtpbGwgdGhlIHdvcmtlciBzbyB3ZSBnZXQgYSBuZXcgcGFnZS4gVGhhdCBuZWVkcyB0byBiZSBoYW5kbGVkIGJldHRlciB0aGFuIHRoaXMgaGFjay5cclxuICAgICAgaWYgKHJlc3VsdC5tZXNzYWdlID09PSAnUmFzdGVyaXphdGlvbiB0aW1lb3V0Jykge1xyXG4gICAgICAgIHdvcmtlckhhbmRsZS5wYWdlLmNsb3NlKCk7XHJcbiAgICAgICAgd29ya2VySGFuZGxlLnBhZ2UgPSBhd2FpdCBicm93c2VyTmV3UGFnZSgpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ0Vycm9yIGVuY291bnRlcmVkIGR1cmluZyBleHBvcnQuJykuc2V0RXJyb3IoXHJcbiAgICAgICAgcmVzdWx0XHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2hlY2sgdGhlIFB1cHBldGVlciBleHBvcnQgdGltZVxyXG4gICAgaWYgKG9wdGlvbnMuc2VydmVyLmJlbmNobWFya2luZykge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgNSxcclxuICAgICAgICBvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZFxyXG4gICAgICAgICAgPyBgW2JlbmNobWFya10gUmVxdWVzdCB3aXRoIElEICR7b3B0aW9ucy5wYXlsb2FkPy5yZXF1ZXN0SWR9IC1gXHJcbiAgICAgICAgICA6ICdbYmVuY2htYXJrXScsXHJcbiAgICAgICAgYEV4cG9ydGVkIGEgY2hhcnQgc3VjZXNzZnVsbHk6ICR7ZXhwb3J0Q291bnRlcigpfW1zLmBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBSZWxlYXNlIHRoZSByZXNvdXJjZSBiYWNrIHRvIHRoZSBwb29sXHJcbiAgICBwb29sLnJlbGVhc2Uod29ya2VySGFuZGxlKTtcclxuXHJcbiAgICAvLyBVc2VkIGZvciBzdGF0aXN0aWNzIGluIGF2ZXJhZ2VUaW1lIGFuZCBwcm9jZXNzZWRXb3JrQ291bnQsIHdoaWNoXHJcbiAgICAvLyBpbiB0dXJuIGlzIHVzZWQgYnkgdGhlIC9oZWFsdGggcm91dGUuXHJcbiAgICBjb25zdCB3b3JrRW5kID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XHJcbiAgICBjb25zdCBleHBvcnRUaW1lID0gd29ya0VuZCAtIHdvcmtTdGFydDtcclxuICAgIHRpbWVTcGVudCArPSBleHBvcnRUaW1lO1xyXG4gICAgc3BlbnRBdmVyYWdlID0gdGltZVNwZW50IC8gKytwZXJmb3JtZWRFeHBvcnRzO1xyXG5cclxuICAgIGxvZyg0LCBgW3Bvb2xdIFdvcmsgY29tcGxldGVkIGluICR7ZXhwb3J0VGltZX0gbXMuYCk7XHJcblxyXG4gICAgLy8gT3RoZXJ3aXNlIHJldHVybiB0aGUgcmVzdWx0XHJcbiAgICByZXR1cm4ge1xyXG4gICAgICByZXN1bHQsXHJcbiAgICAgIG9wdGlvbnNcclxuICAgIH07XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICsrZHJvcHBlZEV4cG9ydHM7XHJcblxyXG4gICAgaWYgKHdvcmtlckhhbmRsZSkge1xyXG4gICAgICBwb29sLnJlbGVhc2Uod29ya2VySGFuZGxlKTtcclxuICAgIH1cclxuXHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoYFtwb29sXSBJbiBwb29sLnBvc3RXb3JrOiAke2Vycm9yLm1lc3NhZ2V9YCkuc2V0RXJyb3IoXHJcbiAgICAgIGVycm9yXHJcbiAgICApO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgdGhlIGN1cnJlbnQgcG9vbCBpbnN0YW5jZS5cclxuICpcclxuICogQHJldHVybnMge09iamVjdHxudWxsfSBUaGUgY3VycmVudCBwb29sIGluc3RhbmNlIGlmIGluaXRpYWxpemVkLCBvciBudWxsXHJcbiAqIGlmIHRoZSBwb29sIGhhcyBub3QgYmVlbiBjcmVhdGVkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldFBvb2woKSB7XHJcbiAgcmV0dXJuIHBvb2w7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgcG9vbCBpbmZvcm1hdGlvbiBpbiBKU09OIGZvcm1hdCwgaW5jbHVkaW5nIG1pbmltdW0gYW5kIG1heGltdW1cclxuICogd29ya2VycywgYXZhaWxhYmxlIHdvcmtlcnMsIHdvcmtlcnMgaW4gdXNlLCBhbmQgcGVuZGluZyBhY3F1aXJlIHJlcXVlc3RzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBQb29sIGluZm9ybWF0aW9uIGluIEpTT04gZm9ybWF0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldFBvb2xJbmZvSlNPTiA9ICgpID0+ICh7XHJcbiAgbWluOiBwb29sLm1pbixcclxuICBtYXg6IHBvb2wubWF4LFxyXG4gIGF2YWlsYWJsZTogcG9vbC5udW1GcmVlKCksXHJcbiAgaW5Vc2U6IHBvb2wubnVtVXNlZCgpLFxyXG4gIHBlbmRpbmdBY3F1aXJlOiBwb29sLm51bVBlbmRpbmdBY3F1aXJlcygpXHJcbn0pO1xyXG5cclxuLyoqXHJcbiAqIExvZ3MgaW5mb3JtYXRpb24gYWJvdXQgdGhlIGN1cnJlbnQgc3RhdGUgb2YgdGhlIHBvb2wsIGluY2x1ZGluZyB0aGUgbWluaW11bVxyXG4gKiBhbmQgbWF4aW11bSB3b3JrZXJzLCBhdmFpbGFibGUgd29ya2Vycywgd29ya2VycyBpbiB1c2UsIGFuZCBwZW5kaW5nIGFjcXVpcmVcclxuICogcmVxdWVzdHMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0UG9vbEluZm8oKSB7XHJcbiAgY29uc3QgeyBtaW4sIG1heCB9ID0gcG9vbDtcclxuXHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG1pbmltdW0gbnVtYmVyIG9mIHJlc291cmNlcyBhbGxvd2VkIGJ5IHBvb2w6ICR7bWlufS5gKTtcclxuICBsb2coNSwgYFtwb29sXSBUaGUgbWF4aW11bSBudW1iZXIgb2YgcmVzb3VyY2VzIGFsbG93ZWQgYnkgcG9vbDogJHttYXh9LmApO1xyXG4gIGxvZyhcclxuICAgIDUsXHJcbiAgICBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgcmVzb3VyY2VzIHRoYXQgYXJlIGN1cnJlbnRseSBhdmFpbGFibGU6ICR7cG9vbC5udW1GcmVlKCl9LmBcclxuICApO1xyXG4gIGxvZyhcclxuICAgIDUsXHJcbiAgICBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgcmVzb3VyY2VzIHRoYXQgYXJlIGN1cnJlbnRseSBhY3F1aXJlZDogJHtwb29sLm51bVVzZWQoKX0uYFxyXG4gICk7XHJcbiAgbG9nKFxyXG4gICAgNSxcclxuICAgIGBbcG9vbF0gVGhlIG51bWJlciBvZiBjYWxsZXJzIHdhaXRpbmcgdG8gYWNxdWlyZSBhIHJlc291cmNlOiAke3Bvb2wubnVtUGVuZGluZ0FjcXVpcmVzKCl9LmBcclxuICApO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgaW5pdFBvb2wsXHJcbiAga2lsbFBvb2wsXHJcbiAgcG9zdFdvcmssXHJcbiAgZ2V0UG9vbCxcclxuICBnZXRQb29sSW5mbyxcclxuICBnZXRQb29sSW5mb0pTT04sXHJcbiAgd29ya0F0dGVtcHRzOiAoKSA9PiBleHBvcnRBdHRlbXB0cyxcclxuICBkcm9wcGVkV29yazogKCkgPT4gZHJvcHBlZEV4cG9ydHMsXHJcbiAgYXZlcmFnZVRpbWU6ICgpID0+IHNwZW50QXZlcmFnZSxcclxuICBwcm9jZXNzZWRXb3JrQ291bnQ6ICgpID0+IHBlcmZvcm1lZEV4cG9ydHNcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMsIHdyaXRlRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcblxyXG5pbXBvcnQgeyBnZXRPcHRpb25zLCBpbml0RXhwb3J0U2V0dGluZ3MgfSBmcm9tICcuL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBraWxsUG9vbCwgcG9zdFdvcmsgfSBmcm9tICcuL3Bvb2wuanMnO1xyXG5pbXBvcnQge1xyXG4gIGZpeFR5cGUsXHJcbiAgaGFuZGxlUmVzb3VyY2VzLFxyXG4gIGlzQ29ycmVjdEpTT04sXHJcbiAgb3B0aW9uc1N0cmluZ2lmeSxcclxuICByb3VuZE51bWJlcixcclxuICB0b0Jvb2xlYW4sXHJcbiAgd3JhcEFyb3VuZFxyXG59IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbmxldCBhbGxvd0NvZGVFeGVjdXRpb24gPSBmYWxzZTtcclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgYW4gZXhwb3J0IHByb2Nlc3MuIFRoZSBgc2V0dGluZ3NgIGNvbnRhaW5zIGZpbmFsIG9wdGlvbnMgZ2F0aGVyZWRcclxuICogZnJvbSBhbGwgcG9zc2libGUgc291cmNlcyAoY29uZmlnLCBlbnYsIGNsaSwganNvbikuIFRoZSBgZW5kQ2FsbGJhY2tgIGlzXHJcbiAqIGNhbGxlZCB3aGVuIHRoZSBleHBvcnQgaXMgY29tcGxldGVkLCB3aXRoIGFuIGVycm9yIG9iamVjdCBhcyB0aGUgZmlyc3RcclxuICogYXJndW1lbnQgYW5kIHRoZSBzZWNvbmQgY29udGFpbmluZyB0aGUgYmFzZTY0IHJlc3ByZXNlbnRhdGlvbiBvZiBhIGNoYXJ0LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gc2V0dGluZ3MgLSBUaGUgc2V0dGluZ3Mgb2JqZWN0IGNvbnRhaW5pbmcgZXhwb3J0XHJcbiAqIGNvbmZpZ3VyYXRpb24uXHJcbiAqIEBwYXJhbSB7ZnVuY3Rpb259IGVuZENhbGxiYWNrIC0gVGhlIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGludm9rZWQgdXBvblxyXG4gKiBmaW5hbGl6aW5nIHdvcmsgb3IgdXBvbiBlcnJvciBvY2N1cmFuY2Ugb2YgdGhlIGV4cG9ydGluZyBwcm9jZXNzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7dm9pZH0gVGhpcyBmdW5jdGlvbiBkb2VzIG5vdCByZXR1cm4gYSB2YWx1ZSBkaXJlY3RseTsgaW5zdGVhZCxcclxuICogaXQgY29tbXVuaWNhdGVzIHJlc3VsdHMgdmlhIHRoZSBlbmRDYWxsYmFjay5cclxuICovXHJcbmV4cG9ydCBjb25zdCBzdGFydEV4cG9ydCA9IGFzeW5jIChzZXR0aW5ncywgZW5kQ2FsbGJhY2spID0+IHtcclxuICAvLyBTdGFydGluZyBleHBvcnRpbmcgcHJvY2VzcyBtZXNzYWdlXHJcbiAgbG9nKDQsICdbY2hhcnRdIFN0YXJ0aW5nIHRoZSBleHBvcnRpbmcgcHJvY2Vzcy4nKTtcclxuXHJcbiAgLy8gSW5pdGlhbGl6ZSBvcHRpb25zXHJcbiAgY29uc3Qgb3B0aW9ucyA9IGluaXRFeHBvcnRTZXR0aW5ncyhzZXR0aW5ncywgZ2V0T3B0aW9ucygpKTtcclxuXHJcbiAgLy8gR2V0IHRoZSBleHBvcnQgb3B0aW9uc1xyXG4gIGNvbnN0IGV4cG9ydE9wdGlvbnMgPSBvcHRpb25zLmV4cG9ydDtcclxuXHJcbiAgLy8gSWYgU1ZHIGlzIGFuIGlucHV0IChhcmd1bWVudCBjYW4gYmUgc2VudCBvbmx5IGJ5IHRoZSByZXF1ZXN0KVxyXG4gIGlmIChvcHRpb25zLnBheWxvYWQ/LnN2ZyAmJiBvcHRpb25zLnBheWxvYWQuc3ZnICE9PSAnJykge1xyXG4gICAgdHJ5IHtcclxuICAgICAgbG9nKDQsICdbY2hhcnRdIEF0dGVtcHRpbmcgdG8gZXhwb3J0IGZyb20gYSBTVkcgaW5wdXQuJyk7XHJcbiAgICAgIHJldHVybiBleHBvcnRBc1N0cmluZyhvcHRpb25zLnBheWxvYWQuc3ZnLnRyaW0oKSwgb3B0aW9ucywgZW5kQ2FsbGJhY2spO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKFxyXG4gICAgICAgIG5ldyBFeHBvcnRFcnJvcignW2NoYXJ0XSBFcnJvciBsb2FkaW5nIFNWRyBpbnB1dC4nKS5zZXRFcnJvcihlcnJvcilcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIEV4cG9ydCB1c2luZyBvcHRpb25zIGZyb20gdGhlIGZpbGVcclxuICBpZiAoZXhwb3J0T3B0aW9ucy5pbmZpbGUgJiYgZXhwb3J0T3B0aW9ucy5pbmZpbGUubGVuZ3RoKSB7XHJcbiAgICAvLyBUcnkgdG8gcmVhZCB0aGUgZmlsZSB0byBnZXQgdGhlIHN0cmluZyByZXByZXNlbnRhdGlvblxyXG4gICAgdHJ5IHtcclxuICAgICAgbG9nKDQsICdbY2hhcnRdIEF0dGVtcHRpbmcgdG8gZXhwb3J0IGZyb20gYW4gaW5wdXQgZmlsZS4nKTtcclxuICAgICAgb3B0aW9ucy5leHBvcnQuaW5zdHIgPSByZWFkRmlsZVN5bmMoZXhwb3J0T3B0aW9ucy5pbmZpbGUsICd1dGY4Jyk7XHJcbiAgICAgIHJldHVybiBleHBvcnRBc1N0cmluZyhvcHRpb25zLmV4cG9ydC5pbnN0ci50cmltKCksIG9wdGlvbnMsIGVuZENhbGxiYWNrKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgICAgICBuZXcgRXhwb3J0RXJyb3IoJ1tjaGFydF0gRXJyb3IgbG9hZGluZyBpbnB1dCBmaWxlLicpLnNldEVycm9yKGVycm9yKVxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gRXhwb3J0IHdpdGggb3B0aW9ucyBmcm9tIHRoZSByYXcgcmVwcmVzZW50YXRpb25cclxuICBpZiAoXHJcbiAgICAoZXhwb3J0T3B0aW9ucy5pbnN0ciAmJiBleHBvcnRPcHRpb25zLmluc3RyICE9PSAnJykgfHxcclxuICAgIChleHBvcnRPcHRpb25zLm9wdGlvbnMgJiYgZXhwb3J0T3B0aW9ucy5vcHRpb25zICE9PSAnJylcclxuICApIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGxvZyg0LCAnW2NoYXJ0XSBBdHRlbXB0aW5nIHRvIGV4cG9ydCBmcm9tIGEgcmF3IGlucHV0LicpO1xyXG5cclxuICAgICAgLy8gUGVyZm9ybSBhIGRpcmVjdCBpbmplY3Qgd2hlbiBmb3JjZWRcclxuICAgICAgaWYgKHRvQm9vbGVhbihvcHRpb25zLmN1c3RvbUxvZ2ljPy5hbGxvd0NvZGVFeGVjdXRpb24pKSB7XHJcbiAgICAgICAgcmV0dXJuIGRvU3RyYWlnaHRJbmplY3Qob3B0aW9ucywgZW5kQ2FsbGJhY2spO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBFaXRoZXIgdHJ5IHRvIHBhcnNlIHRvIEpTT04gZmlyc3Qgb3IgZG8gdGhlIGRpcmVjdCBleHBvcnRcclxuICAgICAgcmV0dXJuIHR5cGVvZiBleHBvcnRPcHRpb25zLmluc3RyID09PSAnc3RyaW5nJ1xyXG4gICAgICAgID8gZXhwb3J0QXNTdHJpbmcoZXhwb3J0T3B0aW9ucy5pbnN0ci50cmltKCksIG9wdGlvbnMsIGVuZENhbGxiYWNrKVxyXG4gICAgICAgIDogZG9FeHBvcnQoXHJcbiAgICAgICAgICAgIG9wdGlvbnMsXHJcbiAgICAgICAgICAgIGV4cG9ydE9wdGlvbnMuaW5zdHIgfHwgZXhwb3J0T3B0aW9ucy5vcHRpb25zLFxyXG4gICAgICAgICAgICBlbmRDYWxsYmFja1xyXG4gICAgICAgICAgKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgICAgICBuZXcgRXhwb3J0RXJyb3IoJ1tjaGFydF0gRXJyb3IgbG9hZGluZyByYXcgaW5wdXQuJykuc2V0RXJyb3IoZXJyb3IpXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBObyBpbnB1dCBzcGVjaWZpZWQsIHBhc3MgYW4gZXJyb3IgbWVzc2FnZSB0byB0aGUgY2FsbGJhY2tcclxuICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgIGBbY2hhcnRdIE5vIHZhbGlkIGlucHV0IHNwZWNpZmllZC4gQ2hlY2sgaWYgYXQgbGVhc3Qgb25lIG9mIHRoZSBmb2xsb3dpbmcgcGFyYW1ldGVycyBpcyBjb3JyZWN0bHkgc2V0OiAnaW5maWxlJywgJ2luc3RyJywgJ29wdGlvbnMnLCBvciAnc3ZnJy5gXHJcbiAgICApXHJcbiAgKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgYSBiYXRjaCBleHBvcnQgcHJvY2VzcyBmb3IgbXVsdGlwbGUgY2hhcnRzIGJhc2VkIG9uIHRoZSBpbmZvcm1hdGlvblxyXG4gKiBpbiB0aGUgYmF0Y2ggb3B0aW9uLiBUaGUgYmF0Y2ggaXMgYSBzdHJpbmcgaW4gdGhlIGZvbGxvd2luZyBmb3JtYXQ6XHJcbiAqIFwiaW5maWxlMS5qc29uPW91dGZpbGUxLnBuZztpbmZpbGUyLmpzb249b3V0ZmlsZTIucG5nOy4uLlwiXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IGNvbnRhaW5pbmcgY29uZmlndXJhdGlvbiBmb3JcclxuICogYSBiYXRjaCBleHBvcnQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBiYXRjaCBleHBvcnRcclxuICogcHJvY2VzcyBpcyBjb21wbGV0ZWQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgYW4gZXJyb3Igb2NjdXJzIGR1cmluZ1xyXG4gKiBhbnkgb2YgdGhlIGJhdGNoIGV4cG9ydCBwcm9jZXNzLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGJhdGNoRXhwb3J0ID0gYXN5bmMgKG9wdGlvbnMpID0+IHtcclxuICBjb25zdCBiYXRjaEZ1bmN0aW9ucyA9IFtdO1xyXG5cclxuICAvLyBTcGxpdCBhbmQgcGFpciB0aGUgLS1iYXRjaCBhcmd1bWVudHNcclxuICBmb3IgKGxldCBwYWlyIG9mIG9wdGlvbnMuZXhwb3J0LmJhdGNoLnNwbGl0KCc7JykpIHtcclxuICAgIHBhaXIgPSBwYWlyLnNwbGl0KCc9Jyk7XHJcbiAgICBpZiAocGFpci5sZW5ndGggPT09IDIpIHtcclxuICAgICAgYmF0Y2hGdW5jdGlvbnMucHVzaChcclxuICAgICAgICBzdGFydEV4cG9ydChcclxuICAgICAgICAgIHtcclxuICAgICAgICAgICAgLi4ub3B0aW9ucyxcclxuICAgICAgICAgICAgZXhwb3J0OiB7XHJcbiAgICAgICAgICAgICAgLi4ub3B0aW9ucy5leHBvcnQsXHJcbiAgICAgICAgICAgICAgaW5maWxlOiBwYWlyWzBdLFxyXG4gICAgICAgICAgICAgIG91dGZpbGU6IHBhaXJbMV1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSxcclxuICAgICAgICAgIChlcnJvciwgaW5mbykgPT4ge1xyXG4gICAgICAgICAgICAvLyBUaHJvdyBhbiBlcnJvclxyXG4gICAgICAgICAgICBpZiAoZXJyb3IpIHtcclxuICAgICAgICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgLy8gU2F2ZSB0aGUgYmFzZTY0IGZyb20gYSBidWZmZXIgdG8gYSBjb3JyZWN0IGltYWdlIGZpbGVcclxuICAgICAgICAgICAgd3JpdGVGaWxlU3luYyhcclxuICAgICAgICAgICAgICBpbmZvLm9wdGlvbnMuZXhwb3J0Lm91dGZpbGUsXHJcbiAgICAgICAgICAgICAgQnVmZmVyLmZyb20oaW5mby5yZXN1bHQsICdiYXNlNjQnKVxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIClcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHRyeSB7XHJcbiAgICAvLyBBd2FpdCBhbGwgZXhwb3J0cyBhcmUgZG9uZVxyXG4gICAgYXdhaXQgUHJvbWlzZS5hbGwoYmF0Y2hGdW5jdGlvbnMpO1xyXG5cclxuICAgIC8vIEtpbGwgcG9vbCBhbmQgY2xvc2UgYnJvd3NlciBhZnRlciBmaW5pc2hpbmcgYmF0Y2ggZXhwb3J0XHJcbiAgICBhd2FpdCBraWxsUG9vbCgpO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbY2hhcnRdIEVycm9yIGVuY291bnRlcmVkIGR1cmluZyBiYXRjaCBleHBvcnQuJ1xyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIFN0YXJ0cyBhIHNpbmdsZSBleHBvcnQgcHJvY2VzcyBiYXNlZCBvbiB0aGUgc3BlY2lmaWVkIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IGNvbnRhaW5pbmcgY29uZmlndXJhdGlvbiBmb3JcclxuICogYSBzaW5nbGUgZXhwb3J0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgc2luZ2xlIGV4cG9ydFxyXG4gKiBwcm9jZXNzIGlzIGNvbXBsZXRlZC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiBhbiBlcnJvciBvY2N1cnMgZHVyaW5nXHJcbiAqIHRoZSBzaW5nbGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2luZ2xlRXhwb3J0ID0gYXN5bmMgKG9wdGlvbnMpID0+IHtcclxuICAvLyBVc2UgaW5zdHIgb3IgaXRzIGFsaWFzLCBvcHRpb25zXHJcbiAgb3B0aW9ucy5leHBvcnQuaW5zdHIgPSBvcHRpb25zLmV4cG9ydC5pbnN0ciB8fCBvcHRpb25zLmV4cG9ydC5vcHRpb25zO1xyXG5cclxuICAvLyBQZXJmb3JtIGFuIGV4cG9ydFxyXG4gIGF3YWl0IHN0YXJ0RXhwb3J0KG9wdGlvbnMsIGFzeW5jIChlcnJvciwgaW5mbykgPT4ge1xyXG4gICAgLy8gRXhpdCBwcm9jZXNzIHdoZW4gZXJyb3JcclxuICAgIGlmIChlcnJvcikge1xyXG4gICAgICB0aHJvdyBlcnJvcjtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCB7IG91dGZpbGUsIHR5cGUgfSA9IGluZm8ub3B0aW9ucy5leHBvcnQ7XHJcblxyXG4gICAgLy8gU2F2ZSB0aGUgYmFzZTY0IGZyb20gYSBidWZmZXIgdG8gYSBjb3JyZWN0IGltYWdlIGZpbGVcclxuICAgIHdyaXRlRmlsZVN5bmMoXHJcbiAgICAgIG91dGZpbGUgfHwgYGNoYXJ0LiR7dHlwZX1gLFxyXG4gICAgICB0eXBlICE9PSAnc3ZnJyA/IEJ1ZmZlci5mcm9tKGluZm8ucmVzdWx0LCAnYmFzZTY0JykgOiBpbmZvLnJlc3VsdFxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBLaWxsIHRoZSBwb29sXHJcbiAgICBhd2FpdCBraWxsUG9vbCgpO1xyXG4gIH0pO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIERldGVybWluZXMgdGhlIHNpemUgYW5kIHNjYWxlIGZvciBjaGFydCBleHBvcnQgYmFzZWQgb24gdGhlIHByb3ZpZGVkIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IGNvbnRhaW5pbmcgY29uZmlndXJhdGlvbiBmb3JcclxuICogY2hhcnQgZXhwb3J0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBBbiBvYmplY3QgY29udGFpbmluZyB0aGUgY2FsY3VsYXRlZCBoZWlnaHQsIHdpZHRoLFxyXG4gKiBhbmQgc2NhbGUgZm9yIHRoZSBjaGFydCBleHBvcnQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZmluZENoYXJ0U2l6ZSA9IChvcHRpb25zKSA9PiB7XHJcbiAgY29uc3QgeyBjaGFydCwgZXhwb3J0aW5nIH0gPVxyXG4gICAgb3B0aW9ucy5leHBvcnQ/Lm9wdGlvbnMgfHwgaXNDb3JyZWN0SlNPTihvcHRpb25zLmV4cG9ydD8uaW5zdHIpO1xyXG5cclxuICAvLyBTZWUgaWYgZ2xvYmFsT3B0aW9ucyBob2xkcyBjaGFydCBvciBleHBvcnRpbmcgc2l6ZVxyXG4gIGNvbnN0IGdsb2JhbE9wdGlvbnMgPSBpc0NvcnJlY3RKU09OKG9wdGlvbnMuZXhwb3J0Py5nbG9iYWxPcHRpb25zKTtcclxuXHJcbiAgLy8gU2VjdXJlIHNjYWxlIHZhbHVlXHJcbiAgbGV0IHNjYWxlID1cclxuICAgIG9wdGlvbnMuZXhwb3J0Py5zY2FsZSB8fFxyXG4gICAgZXhwb3J0aW5nPy5zY2FsZSB8fFxyXG4gICAgZ2xvYmFsT3B0aW9ucz8uZXhwb3J0aW5nPy5zY2FsZSB8fFxyXG4gICAgb3B0aW9ucy5leHBvcnQ/LmRlZmF1bHRTY2FsZSB8fFxyXG4gICAgMTtcclxuXHJcbiAgLy8gdGhlIHNjYWxlIGNhbm5vdCBiZSBsb3dlciB0aGFuIDAuMSBhbmQgY2Fubm90IGJlIGhpZ2hlciB0aGFuIDUuMFxyXG4gIHNjYWxlID0gTWF0aC5tYXgoMC4xLCBNYXRoLm1pbihzY2FsZSwgNS4wKSk7XHJcblxyXG4gIC8vIHdlIHdhbnQgdG8gcm91bmQgdGhlIG51bWJlcnMgbGlrZSAwLjIzMjM0IC0+IDAuMjNcclxuICBzY2FsZSA9IHJvdW5kTnVtYmVyKHNjYWxlLCAyKTtcclxuXHJcbiAgLy8gRmluZCBjaGFydCBzaXplIGFuZCBzY2FsZVxyXG4gIGNvbnN0IHNpemUgPSB7XHJcbiAgICBoZWlnaHQ6XHJcbiAgICAgIG9wdGlvbnMuZXhwb3J0Py5oZWlnaHQgfHxcclxuICAgICAgZXhwb3J0aW5nPy5zb3VyY2VIZWlnaHQgfHxcclxuICAgICAgY2hhcnQ/LmhlaWdodCB8fFxyXG4gICAgICBnbG9iYWxPcHRpb25zPy5leHBvcnRpbmc/LnNvdXJjZUhlaWdodCB8fFxyXG4gICAgICBnbG9iYWxPcHRpb25zPy5jaGFydD8uaGVpZ2h0IHx8XHJcbiAgICAgIG9wdGlvbnMuZXhwb3J0Py5kZWZhdWx0SGVpZ2h0IHx8XHJcbiAgICAgIDQwMCxcclxuICAgIHdpZHRoOlxyXG4gICAgICBvcHRpb25zLmV4cG9ydD8ud2lkdGggfHxcclxuICAgICAgZXhwb3J0aW5nPy5zb3VyY2VXaWR0aCB8fFxyXG4gICAgICBjaGFydD8ud2lkdGggfHxcclxuICAgICAgZ2xvYmFsT3B0aW9ucz8uZXhwb3J0aW5nPy5zb3VyY2VXaWR0aCB8fFxyXG4gICAgICBnbG9iYWxPcHRpb25zPy5jaGFydD8ud2lkdGggfHxcclxuICAgICAgb3B0aW9ucy5leHBvcnQ/LmRlZmF1bHRXaWR0aCB8fFxyXG4gICAgICA2MDAsXHJcbiAgICBzY2FsZVxyXG4gIH07XHJcblxyXG4gIC8vIEdldCByaWQgb2YgcG90ZW50aWFsIHB4IGFuZCAlXHJcbiAgZm9yIChsZXQgW3BhcmFtLCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMoc2l6ZSkpIHtcclxuICAgIHNpemVbcGFyYW1dID1cclxuICAgICAgdHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJyA/ICt2YWx1ZS5yZXBsYWNlKC9weHwlL2dpLCAnJykgOiB2YWx1ZTtcclxuICB9XHJcbiAgcmV0dXJuIHNpemU7XHJcbn07XHJcblxyXG4vKipcclxuICogRnVuY3Rpb24gZm9yIGZpbmFsaXppbmcgb3B0aW9ucyBiZWZvcmUgZXhwb3J0LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBvcHRpb25zIG9iamVjdCBjb250YWluaW5nIGNvbmZpZ3VyYXRpb24gZm9yXHJcbiAqIHRoZSBleHBvcnQgcHJvY2Vzcy5cclxuICogQHBhcmFtIHtPYmplY3R9IGNoYXJ0SnNvbiAtIFRoZSBKU09OIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBjaGFydC5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gZW5kQ2FsbGJhY2sgLSBUaGUgY2FsbGJhY2sgZnVuY3Rpb24gdG8gYmUgY2FsbGVkIHVwb25cclxuICogY29tcGxldGlvbiBvciBlcnJvci5cclxuICogQHBhcmFtIHtzdHJpbmd9IHN2ZyAtIFRoZSBTVkcgcmVwcmVzZW50YXRpb24gb2YgdGhlIGNoYXJ0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgZXhwb3J0IHByb2Nlc3NcclxuICogaXMgY29tcGxldGVkLlxyXG4gKi9cclxuY29uc3QgZG9FeHBvcnQgPSBhc3luYyAob3B0aW9ucywgY2hhcnRKc29uLCBlbmRDYWxsYmFjaywgc3ZnKSA9PiB7XHJcbiAgbGV0IHsgZXhwb3J0OiBleHBvcnRPcHRpb25zLCBjdXN0b21Mb2dpYzogY3VzdG9tTG9naWNPcHRpb25zIH0gPSBvcHRpb25zO1xyXG5cclxuICBjb25zdCBhbGxvd0NvZGVFeGVjdXRpb25TY29wZWQgPVxyXG4gICAgdHlwZW9mIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0NvZGVFeGVjdXRpb24gPT09ICdib29sZWFuJ1xyXG4gICAgICA/IGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0NvZGVFeGVjdXRpb25cclxuICAgICAgOiBhbGxvd0NvZGVFeGVjdXRpb247XHJcblxyXG4gIGlmICghY3VzdG9tTG9naWNPcHRpb25zKSB7XHJcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMgPSBvcHRpb25zLmN1c3RvbUxvZ2ljID0ge307XHJcbiAgfSBlbHNlIGlmIChhbGxvd0NvZGVFeGVjdXRpb25TY29wZWQpIHtcclxuICAgIGlmICh0eXBlb2Ygb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXMgPT09ICdzdHJpbmcnKSB7XHJcbiAgICAgIC8vIFByb2Nlc3MgcmVzb3VyY2VzXHJcbiAgICAgIG9wdGlvbnMuY3VzdG9tTG9naWMucmVzb3VyY2VzID0gaGFuZGxlUmVzb3VyY2VzKFxyXG4gICAgICAgIG9wdGlvbnMuY3VzdG9tTG9naWMucmVzb3VyY2VzLFxyXG4gICAgICAgIHRvQm9vbGVhbihvcHRpb25zLmN1c3RvbUxvZ2ljLmFsbG93RmlsZVJlc291cmNlcylcclxuICAgICAgKTtcclxuICAgIH0gZWxzZSBpZiAoIW9wdGlvbnMuY3VzdG9tTG9naWMucmVzb3VyY2VzKSB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgY29uc3QgcmVzb3VyY2VzID0gcmVhZEZpbGVTeW5jKCdyZXNvdXJjZXMuanNvbicsICd1dGY4Jyk7XHJcbiAgICAgICAgb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXMgPSBoYW5kbGVSZXNvdXJjZXMoXHJcbiAgICAgICAgICByZXNvdXJjZXMsXHJcbiAgICAgICAgICB0b0Jvb2xlYW4ob3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0ZpbGVSZXNvdXJjZXMpXHJcbiAgICAgICAgKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgICAyLFxyXG4gICAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgICBgW2NoYXJ0XSBVbmFibGUgdG8gbG9hZCB0aGUgZGVmYXVsdCByZXNvdXJjZXMuanNvbiBmaWxlLmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBJZiB0aGUgYWxsb3dDb2RlRXhlY3V0aW9uIGZsYWcgaXNuJ3Qgc2V0LCB3ZSBzaG91bGQgcmVmdXNlIHRoZSB1c2FnZVxyXG4gIC8vIG9mIGNhbGxiYWNrLCByZXNvdXJjZXMsIGFuZCBjdXN0b20gY29kZS4gQWRkaXRpb25hbGx5LCB0aGUgd29ya2VyIHdpbGxcclxuICAvLyByZWZ1c2UgdG8gcnVuIGFyYml0cmFyeSBKYXZhU2NyaXB0LiBQcmlvcml0aXplZCBzaG91bGQgYmUgdGhlIHNjb3BlZFxyXG4gIC8vIG9wdGlvbiwgdGhlbiB3ZSBzaG91bGQgdGFrZSBhIGxvb2sgYXQgdGhlIG92ZXJhbGwgcG9vbCBvcHRpb24uXHJcbiAgaWYgKCFhbGxvd0NvZGVFeGVjdXRpb25TY29wZWQgJiYgY3VzdG9tTG9naWNPcHRpb25zKSB7XHJcbiAgICBpZiAoXHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayB8fFxyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzIHx8XHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlXHJcbiAgICApIHtcclxuICAgICAgLy8gU2VuZCBiYWNrIGEgZnJpZW5kbHkgbWVzc2FnZSBzYXlpbmcgdGhhdCB0aGUgZXhwb3J0ZXIgZG9lcyBub3Qgc3VwcG9ydFxyXG4gICAgICAvLyB0aGVzZSBzZXR0aW5ncy5cclxuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKFxyXG4gICAgICAgIG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgIGBbY2hhcnRdIFRoZSAnY2FsbGJhY2snLCAncmVzb3VyY2VzJyBhbmQgJ2N1c3RvbUNvZGUnIG9wdGlvbnMgaGF2ZSBiZWVuIGRpc2FibGVkIGZvciB0aGlzIHNlcnZlci5gXHJcbiAgICAgICAgKVxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFJlc2V0IGFsbCBhZGRpdGlvbmFsIGN1c3RvbSBjb2RlXHJcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSBmYWxzZTtcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXMgPSBmYWxzZTtcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlID0gZmFsc2U7XHJcbiAgfVxyXG5cclxuICAvLyBDbGVhbiBwcm9wZXJ0aWVzIHRvIGtlZXAgaXQgbGVhbiBhbmQgbWVhblxyXG4gIGlmIChjaGFydEpzb24pIHtcclxuICAgIGNoYXJ0SnNvbi5jaGFydCA9IGNoYXJ0SnNvbi5jaGFydCB8fCB7fTtcclxuICAgIGNoYXJ0SnNvbi5leHBvcnRpbmcgPSBjaGFydEpzb24uZXhwb3J0aW5nIHx8IHt9O1xyXG4gICAgY2hhcnRKc29uLmV4cG9ydGluZy5lbmFibGVkID0gZmFsc2U7XHJcbiAgfVxyXG5cclxuICBleHBvcnRPcHRpb25zLmNvbnN0ciA9IGV4cG9ydE9wdGlvbnMuY29uc3RyIHx8ICdjaGFydCc7XHJcbiAgZXhwb3J0T3B0aW9ucy50eXBlID0gZml4VHlwZShleHBvcnRPcHRpb25zLnR5cGUsIGV4cG9ydE9wdGlvbnMub3V0ZmlsZSk7XHJcbiAgaWYgKGV4cG9ydE9wdGlvbnMudHlwZSA9PT0gJ3N2ZycpIHtcclxuICAgIGV4cG9ydE9wdGlvbnMud2lkdGggPSBmYWxzZTtcclxuICB9XHJcblxyXG4gIC8vIFByZXBhcmUgZ2xvYmFsIGFuZCB0aGVtZSBvcHRpb25zXHJcbiAgWydnbG9iYWxPcHRpb25zJywgJ3RoZW1lT3B0aW9ucyddLmZvckVhY2goKG9wdGlvbnNOYW1lKSA9PiB7XHJcbiAgICB0cnkge1xyXG4gICAgICBpZiAoZXhwb3J0T3B0aW9ucyAmJiBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSkge1xyXG4gICAgICAgIGlmIChcclxuICAgICAgICAgIHR5cGVvZiBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9PT0gJ3N0cmluZycgJiZcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdLmVuZHNXaXRoKCcuanNvbicpXHJcbiAgICAgICAgKSB7XHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9IGlzQ29ycmVjdEpTT04oXHJcbiAgICAgICAgICAgIHJlYWRGaWxlU3luYyhleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSwgJ3V0ZjgnKSxcclxuICAgICAgICAgICAgdHJ1ZVxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPSBpc0NvcnJlY3RKU09OKFxyXG4gICAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSxcclxuICAgICAgICAgICAgdHJ1ZVxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID0ge307XHJcbiAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgYFtjaGFydF0gVGhlICcke29wdGlvbnNOYW1lfScgY2Fubm90IGJlIGxvYWRlZC5gKTtcclxuICAgIH1cclxuICB9KTtcclxuXHJcbiAgLy8gUHJlcGFyZSB0aGUgY3VzdG9tQ29kZVxyXG4gIGlmIChjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dDb2RlRXhlY3V0aW9uKSB7XHJcbiAgICB0cnkge1xyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSA9IHdyYXBBcm91bmQoXHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUsXHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmFsbG93RmlsZVJlc291cmNlc1xyXG4gICAgICApO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2NoYXJ0XSBUaGUgJ2N1c3RvbUNvZGUnIGNhbm5vdCBiZSBsb2FkZWQuYCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBHZXQgdGhlIGNhbGxiYWNrXHJcbiAgaWYgKFxyXG4gICAgY3VzdG9tTG9naWNPcHRpb25zICYmXHJcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgJiZcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjaz8uaW5kZXhPZigneycpIDwgMFxyXG4gICkge1xyXG4gICAgLy8gVGhlIGFsbG93RmlsZVJlc291cmNlcyBpcyBhbHdheXMgc2V0IHRvIGZhbHNlIGZvciBIVFRQIHJlcXVlc3RzIHRvIGF2b2lkXHJcbiAgICAvLyBpbmplY3RpbmcgYXJiaXRyYXJ5IGZpbGVzIGZyb20gdGhlIGZzXHJcbiAgICBpZiAoY3VzdG9tTG9naWNPcHRpb25zLmFsbG93RmlsZVJlc291cmNlcykge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IHJlYWRGaWxlU3luYyhcclxuICAgICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayxcclxuICAgICAgICAgICd1dGY4J1xyXG4gICAgICAgICk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrID0gZmFsc2U7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2NoYXJ0XSBUaGUgJ2NhbGxiYWNrJyBjYW5ub3QgYmUgbG9hZGVkLmApO1xyXG4gICAgICB9XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSBmYWxzZTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFNpemUgc2VhcmNoXHJcbiAgb3B0aW9ucy5leHBvcnQgPSB7XHJcbiAgICAuLi5vcHRpb25zLmV4cG9ydCxcclxuICAgIC4uLmZpbmRDaGFydFNpemUob3B0aW9ucylcclxuICB9O1xyXG5cclxuICAvLyBQb3N0IHRoZSB3b3JrIHRvIHRoZSBwb29sXHJcbiAgdHJ5IHtcclxuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHBvc3RXb3JrKFxyXG4gICAgICBleHBvcnRPcHRpb25zLnN0ckluaiB8fCBjaGFydEpzb24gfHwgc3ZnLFxyXG4gICAgICBvcHRpb25zXHJcbiAgICApO1xyXG4gICAgcmV0dXJuIGVuZENhbGxiYWNrKGZhbHNlLCByZXN1bHQpO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICByZXR1cm4gZW5kQ2FsbGJhY2soZXJyb3IpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBQZXJmb3JtcyBhIGRpcmVjdCBpbmplY3Qgb2Ygb3B0aW9ucyBiZWZvcmUgZXhwb3J0LiBUaGUgZnVuY3Rpb24gYXR0ZW1wdHNcclxuICogdG8gc3RyaW5naWZ5IHRoZSBwcm92aWRlZCBvcHRpb25zIGFuZCByZW1vdmVzIHVubmVjZXNzYXJ5IGNoYXJhY3RlcnMsXHJcbiAqIGVuc3VyaW5nIGEgY2xlYW4gYW5kIGZvcm1hdHRlZCBpbnB1dC4gVGhlIHJlc3VsdGluZyBzdHJpbmcgaXMgc2F2ZWQgYXNcclxuICogYSBcInN0cmlnaHQgaW5qZWN0XCIgc3RyaW5nIGluIHRoZSBleHBvcnQgb3B0aW9ucy4gSXQgdGhlbiBpbnZva2VzIHRoZVxyXG4gKiBkb0V4cG9ydCBmdW5jdGlvbiB3aXRoIHRoZSB1cGRhdGVkIG9wdGlvbnMuXHJcbiAqXHJcbiAqIElNUE9SVEFOVDogRGFuZ2Vyb3VzIGFuZCBtdXN0IGJlIHVzZWQgZGVsaWJlcmF0ZWx5IGJ5IHNvbWVvbmUgd2hvIHNldHMgdXBcclxuICogYSBzZXJ2ZXIgKHNlZSB0aGUgIC0tYWxsb3dDb2RlRXhlY3V0aW9uIG9wdGlvbikuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIGV4cG9ydCBvcHRpb25zIGNvbnRhaW5pbmcgdGhlIGlucHV0XHJcbiAqIHRvIGJlIGluamVjdGVkLlxyXG4gKiBAcGFyYW0ge2Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIFRoZSBjYWxsYmFjayBmdW5jdGlvbiB0byBiZSBpbnZva2VkXHJcbiAqIGF0IHRoZSBlbmQgb2YgdGhlIHByb2Nlc3MuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlfSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB3aXRoIHRoZSByZXN1bHQgb2YgdGhlIGV4cG9ydFxyXG4gKiBvcGVyYXRpb24gb3IgcmVqZWN0cyB3aXRoIGFuIGVycm9yIGlmIGFueSBpc3N1ZXMgb2NjdXIgZHVyaW5nIHRoZSBwcm9jZXNzLlxyXG4gKi9cclxuY29uc3QgZG9TdHJhaWdodEluamVjdCA9IChvcHRpb25zLCBlbmRDYWxsYmFjaykgPT4ge1xyXG4gIHRyeSB7XHJcbiAgICBsZXQgc3RySW5qO1xyXG4gICAgbGV0IGluc3RyID0gb3B0aW9ucy5leHBvcnQuaW5zdHIgfHwgb3B0aW9ucy5leHBvcnQub3B0aW9ucztcclxuXHJcbiAgICBpZiAodHlwZW9mIGluc3RyICE9PSAnc3RyaW5nJykge1xyXG4gICAgICAvLyBUcnkgdG8gc3RyaW5naWZ5IG9wdGlvbnNcclxuICAgICAgc3RySW5qID0gaW5zdHIgPSBvcHRpb25zU3RyaW5naWZ5KFxyXG4gICAgICAgIGluc3RyLFxyXG4gICAgICAgIG9wdGlvbnMuY3VzdG9tTG9naWM/LmFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gICAgc3RySW5qID0gaW5zdHIucmVwbGFjZUFsbCgvXFx0fFxcbnxcXHIvZywgJycpLnRyaW0oKTtcclxuXHJcbiAgICAvLyBHZXQgcmlkIG9mIHRoZSA7XHJcbiAgICBpZiAoc3RySW5qW3N0ckluai5sZW5ndGggLSAxXSA9PT0gJzsnKSB7XHJcbiAgICAgIHN0ckluaiA9IHN0ckluai5zdWJzdHJpbmcoMCwgc3RySW5qLmxlbmd0aCAtIDEpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFNhdmUgYXMgc3RyaWdodCBpbmplY3Qgc3RyaW5nXHJcbiAgICBvcHRpb25zLmV4cG9ydC5zdHJJbmogPSBzdHJJbmo7XHJcbiAgICByZXR1cm4gZG9FeHBvcnQob3B0aW9ucywgZmFsc2UsIGVuZENhbGxiYWNrKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgcmV0dXJuIGVuZENhbGxiYWNrKFxyXG4gICAgICBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgYFtjaGFydF0gTWFsZm9ybWVkIGlucHV0IGRldGVjdGVkIGZvciAke29wdGlvbnMuZXhwb3J0Py5yZXF1ZXN0SWQgfHwgJz8nfS4gUGxlYXNlIG1ha2Ugc3VyZSB0aGF0IHlvdXIgSlNPTi9KYXZhU2NyaXB0IG9wdGlvbnMgYXJlIHNlbnQgdXNpbmcgdGhlIFwib3B0aW9uc1wiIGF0dHJpYnV0ZSwgYW5kIHRoYXQgaWYgeW91J3JlIHVzaW5nIFNWRywgaXQgaXMgdW5lc2NhcGVkLmBcclxuICAgICAgKS5zZXRFcnJvcihlcnJvcilcclxuICAgICk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEV4cG9ydHMgYSBzdHJpbmcgYmFzZWQgb24gdGhlIHByb3ZpZGVkIG9wdGlvbnMgYW5kIGludm9rZXMgYW4gZW5kIGNhbGxiYWNrLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gc3RyaW5nVG9FeHBvcnQgLSBUaGUgc3RyaW5nIGNvbnRlbnQgdG8gYmUgZXhwb3J0ZWQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gRXhwb3J0IG9wdGlvbnMsIGluY2x1ZGluZyBjdXN0b21Mb2dpYyB3aXRoXHJcbiAqIGFsbG93Q29kZUV4ZWN1dGlvbiBmbGFnLlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIENhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGludm9rZWQgYXQgdGhlIGVuZFxyXG4gKiBvZiB0aGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHthbnl9IFJlc3VsdCBvZiB0aGUgZXhwb3J0IHByb2Nlc3Mgb3IgYW4gZXJyb3IgaWYgZW5jb3VudGVyZWQuXHJcbiAqL1xyXG5jb25zdCBleHBvcnRBc1N0cmluZyA9IChzdHJpbmdUb0V4cG9ydCwgb3B0aW9ucywgZW5kQ2FsbGJhY2spID0+IHtcclxuICBjb25zdCB7IGFsbG93Q29kZUV4ZWN1dGlvbiB9ID0gb3B0aW9ucy5jdXN0b21Mb2dpYztcclxuXHJcbiAgLy8gQ2hlY2sgaWYgaXQgaXMgU1ZHXHJcbiAgaWYgKFxyXG4gICAgc3RyaW5nVG9FeHBvcnQuaW5kZXhPZignPHN2ZycpID49IDAgfHxcclxuICAgIHN0cmluZ1RvRXhwb3J0LmluZGV4T2YoJzw/eG1sJykgPj0gMFxyXG4gICkge1xyXG4gICAgbG9nKDQsICdbY2hhcnRdIFBhcnNpbmcgaW5wdXQgYXMgU1ZHLicpO1xyXG4gICAgcmV0dXJuIGRvRXhwb3J0KG9wdGlvbnMsIGZhbHNlLCBlbmRDYWxsYmFjaywgc3RyaW5nVG9FeHBvcnQpO1xyXG4gIH1cclxuXHJcbiAgdHJ5IHtcclxuICAgIC8vIFRyeSB0byBwYXJzZSB0byBKU09OIGFuZCBjYWxsIHRoZSBkb0V4cG9ydCBmdW5jdGlvblxyXG4gICAgY29uc3QgY2hhcnRKU09OID0gSlNPTi5wYXJzZShzdHJpbmdUb0V4cG9ydC5yZXBsYWNlQWxsKC9cXHR8XFxufFxcci9nLCAnICcpKTtcclxuXHJcbiAgICAvLyBJZiBhIGNvcnJlY3QgSlNPTiwgZG8gdGhlIGV4cG9ydFxyXG4gICAgcmV0dXJuIGRvRXhwb3J0KG9wdGlvbnMsIGNoYXJ0SlNPTiwgZW5kQ2FsbGJhY2spO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAvLyBOb3QgYSB2YWxpZCBKU09OXHJcbiAgICBpZiAodG9Cb29sZWFuKGFsbG93Q29kZUV4ZWN1dGlvbikpIHtcclxuICAgICAgcmV0dXJuIGRvU3RyYWlnaHRJbmplY3Qob3B0aW9ucywgZW5kQ2FsbGJhY2spO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gRG8gbm90IGFsbG93IHN0cmFpZ2h0IGluamVjdGlvbiB3aXRob3V0IHRoZSBhbGxvd0NvZGVFeGVjdXRpb24gZmxhZ1xyXG4gICAgICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICAgICAgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgJ1tjaGFydF0gT25seSBKU09OIGNvbmZpZ3VyYXRpb25zIGFuZCBTVkcgYXJlIGFsbG93ZWQgZm9yIHRoaXMgc2VydmVyLiBJZiB0aGlzIGlzIHlvdXIgc2VydmVyLCBKYXZhU2NyaXB0IGN1c3RvbSBjb2RlIGNhbiBiZSBlbmFibGVkIGJ5IHN0YXJ0aW5nIHRoZSBzZXJ2ZXIgd2l0aCB0aGUgLS1hbGxvd0NvZGVFeGVjdXRpb24gZmxhZy4nXHJcbiAgICAgICAgKS5zZXRFcnJvcihlcnJvcilcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIGFuZCByZXR1cm5zIHRoZSBjdXJyZW50IHN0YXR1cyBvZiBjb2RlIGV4ZWN1dGlvbiBwZXJtaXNzaW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7YW55fSBUaGUgdmFsdWUgb2YgYWxsb3dDb2RlRXhlY3V0aW9uLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldEFsbG93Q29kZUV4ZWN1dGlvbiA9ICgpID0+IGFsbG93Q29kZUV4ZWN1dGlvbjtcclxuXHJcbi8qKlxyXG4gKiBTZXRzIHRoZSBjb2RlIGV4ZWN1dGlvbiBwZXJtaXNzaW9uIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBib29sZWFuIHZhbHVlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge2FueX0gdmFsdWUgLSBUaGUgdmFsdWUgdG8gYmUgY29udmVydGVkIGFuZCBhc3NpZ25lZFxyXG4gKiB0byBhbGxvd0NvZGVFeGVjdXRpb24uXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2V0QWxsb3dDb2RlRXhlY3V0aW9uID0gKHZhbHVlKSA9PiB7XHJcbiAgYWxsb3dDb2RlRXhlY3V0aW9uID0gdG9Cb29sZWFuKHZhbHVlKTtcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBiYXRjaEV4cG9ydCxcclxuICBzaW5nbGVFeHBvcnQsXHJcbiAgZ2V0QWxsb3dDb2RlRXhlY3V0aW9uLFxyXG4gIHNldEFsbG93Q29kZUV4ZWN1dGlvbixcclxuICBzdGFydEV4cG9ydCxcclxuICBmaW5kQ2hhcnRTaXplXHJcbn07XHJcbiIsImltcG9ydCB7IGxvZ1dpdGhTdGFjayB9IGZyb20gJy4uL2xvZ2dlci5qcyc7XHJcblxyXG4vKipcclxuICogTWlkZGxld2FyZSBmb3IgbG9nZ2luZyBlcnJvcnMgd2l0aCBzdGFjayB0cmFjZSBhbmQgaGFuZGxpbmcgZXJyb3IgcmVzcG9uc2UuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXJyb3J9IGVycm9yIC0gVGhlIGVycm9yIG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcSAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlcyAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gbmV4dCAtIFRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXHJcbiAqL1xyXG5jb25zdCBsb2dFcnJvck1pZGRsZXdhcmUgPSAoZXJyb3IsIHJlcSwgcmVzLCBuZXh0KSA9PiB7XHJcbiAgLy8gRGlzcGxheSB0aGUgZXJyb3Igd2l0aCBzdGFjayBpbiBhIGNvcnJlY3QgZm9ybWF0XHJcbiAgbG9nV2l0aFN0YWNrKDEsIGVycm9yKTtcclxuXHJcbiAgLy8gRGVsZXRlIHRoZSBzdGFjayBmb3IgdGhlIGVudmlyb25tZW50IG90aGVyIHRoYW4gdGhlIGRldmVsb3BtZW50XHJcbiAgaWYgKHByb2Nlc3MuZW52Lk5PREVfRU5WICE9PSAnZGV2ZWxvcG1lbnQnKSB7XHJcbiAgICBkZWxldGUgZXJyb3Iuc3RhY2s7XHJcbiAgfVxyXG5cclxuICAvLyBDYWxsIHRoZSByZXR1cm5FcnJvck1pZGRsZXdhcmVcclxuICBuZXh0KGVycm9yKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBNaWRkbGV3YXJlIGZvciByZXR1cm5pbmcgZXJyb3IgcmVzcG9uc2UuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXJyb3J9IGVycm9yIC0gVGhlIGVycm9yIG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcSAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlcyAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gbmV4dCAtIFRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXHJcbiAqL1xyXG5jb25zdCByZXR1cm5FcnJvck1pZGRsZXdhcmUgPSAoZXJyb3IsIHJlcSwgcmVzLCBuZXh0KSA9PiB7XHJcbiAgLy8gR2F0aGVyIGFsbCByZXF1aWVkIGluZm9ybWF0aW9uIGZvciB0aGUgcmVzcG9uc2VcclxuICBjb25zdCB7IHN0YXR1c0NvZGU6IHN0Q29kZSwgc3RhdHVzLCBtZXNzYWdlLCBzdGFjayB9ID0gZXJyb3I7XHJcbiAgY29uc3Qgc3RhdHVzQ29kZSA9IHN0Q29kZSB8fCBzdGF0dXMgfHwgNTAwO1xyXG5cclxuICAvLyBTZXQgYW5kIHJldHVybiByZXNwb25zZVxyXG4gIHJlcy5zdGF0dXMoc3RhdHVzQ29kZSkuanNvbih7IHN0YXR1c0NvZGUsIG1lc3NhZ2UsIHN0YWNrIH0pO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQgKGFwcCkgPT4ge1xyXG4gIC8vIEFkZCBsb2cgZXJyb3IgbWlkZGxld2FyZVxyXG4gIGFwcC51c2UobG9nRXJyb3JNaWRkbGV3YXJlKTtcclxuXHJcbiAgLy8gQWRkIHNldCBzdGF0dXMgYW5kIHJldHVybiBlcnJvciBtaWRkbGV3YXJlXHJcbiAgYXBwLnVzZShyZXR1cm5FcnJvck1pZGRsZXdhcmUpO1xyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCByYXRlTGltaXQgZnJvbSAnZXhwcmVzcy1yYXRlLWxpbWl0JztcclxuXHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4uL2xvZ2dlci5qcyc7XHJcblxyXG4vKipcclxuICogTWlkZGxld2FyZSBmb3IgZW5hYmxpbmcgcmF0ZSBsaW1pdGluZyBvbiB0aGUgc3BlY2lmaWVkIEV4cHJlc3MgYXBwLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3N9IGFwcCAtIFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICogQHBhcmFtIHtPYmplY3R9IGxpbWl0Q29uZmlnIC0gQ29uZmlndXJhdGlvbiBvcHRpb25zIGZvciByYXRlIGxpbWl0aW5nLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgKGFwcCwgbGltaXRDb25maWcpID0+IHtcclxuICBjb25zdCBtc2cgPVxyXG4gICAgJ1RvbyBtYW55IHJlcXVlc3RzLCB5b3UgaGF2ZSBiZWVuIHJhdGUgbGltaXRlZC4gUGxlYXNlIHRyeSBhZ2FpbiBsYXRlci4nO1xyXG5cclxuICAvLyBPcHRpb25zIGZvciB0aGUgcmF0ZSBsaW1pdGVyXHJcbiAgY29uc3QgcmF0ZU9wdGlvbnMgPSB7XHJcbiAgICBtYXg6IGxpbWl0Q29uZmlnLm1heFJlcXVlc3RzIHx8IDMwLFxyXG4gICAgd2luZG93OiBsaW1pdENvbmZpZy53aW5kb3cgfHwgMSxcclxuICAgIGRlbGF5OiBsaW1pdENvbmZpZy5kZWxheSB8fCAwLFxyXG4gICAgdHJ1c3RQcm94eTogbGltaXRDb25maWcudHJ1c3RQcm94eSB8fCBmYWxzZSxcclxuICAgIHNraXBLZXk6IGxpbWl0Q29uZmlnLnNraXBLZXkgfHwgZmFsc2UsXHJcbiAgICBza2lwVG9rZW46IGxpbWl0Q29uZmlnLnNraXBUb2tlbiB8fCBmYWxzZVxyXG4gIH07XHJcblxyXG4gIC8vIFNldCBpZiBiZWhpbmQgYSBwcm94eVxyXG4gIGlmIChyYXRlT3B0aW9ucy50cnVzdFByb3h5KSB7XHJcbiAgICBhcHAuZW5hYmxlKCd0cnVzdCBwcm94eScpO1xyXG4gIH1cclxuXHJcbiAgLy8gQ3JlYXRlIGEgbGltaXRlclxyXG4gIGNvbnN0IGxpbWl0ZXIgPSByYXRlTGltaXQoe1xyXG4gICAgd2luZG93TXM6IHJhdGVPcHRpb25zLndpbmRvdyAqIDYwICogMTAwMCxcclxuICAgIC8vIExpbWl0IGVhY2ggSVAgdG8gMTAwIHJlcXVlc3RzIHBlciB3aW5kb3dNc1xyXG4gICAgbWF4OiByYXRlT3B0aW9ucy5tYXgsXHJcbiAgICAvLyBEaXNhYmxlIGRlbGF5aW5nLCBmdWxsIHNwZWVkIHVudGlsIHRoZSBtYXggbGltaXQgaXMgcmVhY2hlZFxyXG4gICAgZGVsYXlNczogcmF0ZU9wdGlvbnMuZGVsYXksXHJcbiAgICBoYW5kbGVyOiAocmVxdWVzdCwgcmVzcG9uc2UpID0+IHtcclxuICAgICAgcmVzcG9uc2UuZm9ybWF0KHtcclxuICAgICAgICBqc29uOiAoKSA9PiB7XHJcbiAgICAgICAgICByZXNwb25zZS5zdGF0dXMoNDI5KS5zZW5kKHsgbWVzc2FnZTogbXNnIH0pO1xyXG4gICAgICAgIH0sXHJcbiAgICAgICAgZGVmYXVsdDogKCkgPT4ge1xyXG4gICAgICAgICAgcmVzcG9uc2Uuc3RhdHVzKDQyOSkuc2VuZChtc2cpO1xyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcbiAgICB9LFxyXG4gICAgc2tpcDogKHJlcXVlc3QpID0+IHtcclxuICAgICAgLy8gQWxsb3cgYnlwYXNzaW5nIHRoZSBsaW1pdGVyIGlmIGEgdmFsaWQga2V5L3Rva2VuIGhhcyBiZWVuIHNlbnRcclxuICAgICAgaWYgKFxyXG4gICAgICAgIHJhdGVPcHRpb25zLnNraXBLZXkgIT09IGZhbHNlICYmXHJcbiAgICAgICAgcmF0ZU9wdGlvbnMuc2tpcFRva2VuICE9PSBmYWxzZSAmJlxyXG4gICAgICAgIHJlcXVlc3QucXVlcnkua2V5ID09PSByYXRlT3B0aW9ucy5za2lwS2V5ICYmXHJcbiAgICAgICAgcmVxdWVzdC5xdWVyeS5hY2Nlc3NfdG9rZW4gPT09IHJhdGVPcHRpb25zLnNraXBUb2tlblxyXG4gICAgICApIHtcclxuICAgICAgICBsb2coNCwgJ1tyYXRlIGxpbWl0aW5nXSBTa2lwcGluZyByYXRlIGxpbWl0ZXIuJyk7XHJcbiAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICAvLyBVc2UgYSBsaW1pdGVyIGFzIGEgbWlkZGxld2FyZVxyXG4gIGFwcC51c2UobGltaXRlcik7XHJcblxyXG4gIGxvZyhcclxuICAgIDMsXHJcbiAgICBgW3JhdGUgbGltaXRpbmddIEVuYWJsZWQgcmF0ZSBsaW1pdGluZyB3aXRoICR7cmF0ZU9wdGlvbnMubWF4fSByZXF1ZXN0cyBwZXIgJHtyYXRlT3B0aW9ucy53aW5kb3d9IG1pbnV0ZSBmb3IgZWFjaCBJUCwgdHJ1c3RpbmcgcHJveHk6ICR7cmF0ZU9wdGlvbnMudHJ1c3RQcm94eX0uYFxyXG4gICk7XHJcbn07XHJcbiIsImltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbmNsYXNzIEh0dHBFcnJvciBleHRlbmRzIEV4cG9ydEVycm9yIHtcclxuICBjb25zdHJ1Y3RvcihtZXNzYWdlLCBzdGF0dXMpIHtcclxuICAgIHN1cGVyKG1lc3NhZ2UpO1xyXG4gICAgdGhpcy5zdGF0dXMgPSB0aGlzLnN0YXR1c0NvZGUgPSBzdGF0dXM7XHJcbiAgfVxyXG5cclxuICBzZXRTdGF0dXMoc3RhdHVzKSB7XHJcbiAgICB0aGlzLnN0YXR1cyA9IHN0YXR1cztcclxuICAgIHJldHVybiB0aGlzO1xyXG4gIH1cclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQgSHR0cEVycm9yO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IHY0IGFzIHV1aWQgfSBmcm9tICd1dWlkJztcclxuXHJcbmltcG9ydCB7IGdldEFsbG93Q29kZUV4ZWN1dGlvbiwgc3RhcnRFeHBvcnQgfSBmcm9tICcuLi8uLi9jaGFydC5qcyc7XHJcbmltcG9ydCB7IGdldE9wdGlvbnMsIG1lcmdlQ29uZmlnT3B0aW9ucyB9IGZyb20gJy4uLy4uL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4uLy4uL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7XHJcbiAgZml4VHlwZSxcclxuICBpc0NvcnJlY3RKU09OLFxyXG4gIGlzT2JqZWN0RW1wdHksXHJcbiAgaXNQcml2YXRlUmFuZ2VVcmxGb3VuZCxcclxuICBvcHRpb25zU3RyaW5naWZ5LFxyXG4gIG1lYXN1cmVUaW1lXHJcbn0gZnJvbSAnLi4vLi4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IEh0dHBFcnJvciBmcm9tICcuLi8uLi9lcnJvcnMvSHR0cEVycm9yLmpzJztcclxuXHJcbi8vIFJldmVyc2VkIE1JTUUgdHlwZXNcclxuY29uc3QgcmV2ZXJzZWRNaW1lID0ge1xyXG4gIHBuZzogJ2ltYWdlL3BuZycsXHJcbiAganBlZzogJ2ltYWdlL2pwZWcnLFxyXG4gIGdpZjogJ2ltYWdlL2dpZicsXHJcbiAgcGRmOiAnYXBwbGljYXRpb24vcGRmJyxcclxuICBzdmc6ICdpbWFnZS9zdmcreG1sJ1xyXG59O1xyXG5cclxuLy8gVGhlIHJlcXVlc3RzIGNvdW50ZXJcclxubGV0IHJlcXVlc3RzQ291bnRlciA9IDA7XHJcblxyXG4vLyBUaGUgYXJyYXkgb2YgY2FsbGJhY2tzIHRvIGNhbGwgYmVmb3JlIGEgcmVxdWVzdFxyXG5jb25zdCBiZWZvcmVSZXF1ZXN0ID0gW107XHJcblxyXG4vLyBUaGUgYXJyYXkgb2YgY2FsbGJhY2tzIHRvIGNhbGwgYWZ0ZXIgYSByZXF1ZXN0XHJcbmNvbnN0IGFmdGVyUmVxdWVzdCA9IFtdO1xyXG5cclxuLyoqXHJcbiAqIEludm9rZXMgYW4gYXJyYXkgb2YgY2FsbGJhY2sgZnVuY3Rpb25zIHdpdGggc3BlY2lmaWVkIHBhcmFtZXRlcnMsIGFsbG93aW5nXHJcbiAqIGN1c3RvbWl6YXRpb24gb2YgcmVxdWVzdCBoYW5kbGluZy5cclxuICpcclxuICogQHBhcmFtIHtGdW5jdGlvbltdfSBjYWxsYmFja3MgLSBBbiBhcnJheSBvZiBjYWxsYmFjayBmdW5jdGlvbnNcclxuICogdG8gYmUgZXhlY3V0ZWQuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXF1ZXN0IC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzcG9uc2UgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBkYXRhIC0gQW4gb2JqZWN0IGNvbnRhaW5pbmcgcGFyYW1ldGVycyBsaWtlIGlkLCB1bmlxdWVJZCxcclxuICogdHlwZSwgYW5kIGJvZHkuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtib29sZWFufSAtIFJldHVybnMgYSBib29sZWFuIGluZGljYXRpbmcgdGhlIG92ZXJhbGwgcmVzdWx0XHJcbiAqIG9mIHRoZSBjYWxsYmFjayBpbnZvY2F0aW9ucy5cclxuICovXHJcbmNvbnN0IGRvQ2FsbGJhY2tzID0gKGNhbGxiYWNrcywgcmVxdWVzdCwgcmVzcG9uc2UsIGRhdGEpID0+IHtcclxuICBsZXQgcmVzdWx0ID0gdHJ1ZTtcclxuICBjb25zdCB7IGlkLCB1bmlxdWVJZCwgdHlwZSwgYm9keSB9ID0gZGF0YTtcclxuXHJcbiAgY2FsbGJhY2tzLnNvbWUoKGNhbGxiYWNrKSA9PiB7XHJcbiAgICBpZiAoY2FsbGJhY2spIHtcclxuICAgICAgbGV0IGNhbGxSZXNwb25zZSA9IGNhbGxiYWNrKHJlcXVlc3QsIHJlc3BvbnNlLCBpZCwgdW5pcXVlSWQsIHR5cGUsIGJvZHkpO1xyXG5cclxuICAgICAgaWYgKGNhbGxSZXNwb25zZSAhPT0gdW5kZWZpbmVkICYmIGNhbGxSZXNwb25zZSAhPT0gdHJ1ZSkge1xyXG4gICAgICAgIHJlc3VsdCA9IGNhbGxSZXNwb25zZTtcclxuICAgICAgfVxyXG5cclxuICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICB9XHJcbiAgfSk7XHJcblxyXG4gIHJldHVybiByZXN1bHQ7XHJcbn07XHJcblxyXG4vKipcclxuICogSGFuZGxlcyB0aGUgZXhwb3J0IHJlcXVlc3RzIGZyb20gdGhlIGNsaWVudC5cclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcXVlc3QgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXNwb25zZSAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gbmV4dCAtIFRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgdGhlIGV4cG9ydCBwcm9jZXNzXHJcbiAqIGlzIGNvbXBsZXRlLlxyXG4gKi9cclxuY29uc3QgZXhwb3J0SGFuZGxlciA9IGFzeW5jIChyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkgPT4ge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBTdGFydCBjb3VudGluZyB0aW1lXHJcbiAgICBjb25zdCBzdG9wQ291bnRlciA9IG1lYXN1cmVUaW1lKCk7XHJcblxyXG4gICAgLy8gQ3JlYXRlIGEgdW5pcXVlIElEIGZvciBhIHJlcXVlc3RcclxuICAgIGNvbnN0IHVuaXF1ZUlkID0gdXVpZCgpLnJlcGxhY2UoLy0vZywgJycpO1xyXG5cclxuICAgIC8vIEdldCB0aGUgY3VycmVudCBzZXJ2ZXIncyBnZW5lcmFsIG9wdGlvbnNcclxuICAgIGNvbnN0IGRlZmF1bHRPcHRpb25zID0gZ2V0T3B0aW9ucygpO1xyXG5cclxuICAgIGNvbnN0IGJvZHkgPSByZXF1ZXN0LmJvZHk7XHJcbiAgICBjb25zdCBpZCA9ICsrcmVxdWVzdHNDb3VudGVyO1xyXG5cclxuICAgIGxldCB0eXBlID0gZml4VHlwZShib2R5LnR5cGUpO1xyXG5cclxuICAgIC8vIFRocm93ICdCYWQgUmVxdWVzdCcgaWYgdGhlcmUncyBubyBib2R5XHJcbiAgICBpZiAoIWJvZHkgfHwgaXNPYmplY3RFbXB0eShib2R5KSkge1xyXG4gICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgICdUaGUgcmVxdWVzdCBib2R5IGlzIHJlcXVpcmVkLiBQbGVhc2UgZW5zdXJlIHRoYXQgeW91ciBDb250ZW50LVR5cGUgaGVhZGVyIGlzIGNvcnJlY3QgKGFjY2VwdGVkIHR5cGVzIGFyZSBhcHBsaWNhdGlvbi9qc29uIGFuZCBtdWx0aXBhcnQvZm9ybS1kYXRhKS4nLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEFsbCBvZiB0aGUgYmVsb3cgY2FuIGJlIHVzZWRcclxuICAgIGxldCBpbnN0ciA9IGlzQ29ycmVjdEpTT04oYm9keS5pbmZpbGUgfHwgYm9keS5vcHRpb25zIHx8IGJvZHkuZGF0YSk7XHJcblxyXG4gICAgLy8gVGhyb3cgJ0JhZCBSZXF1ZXN0JyBpZiB0aGVyZSdzIG5vIEpTT04gb3IgU1ZHIHRvIGV4cG9ydFxyXG4gICAgaWYgKCFpbnN0ciAmJiAhYm9keS5zdmcpIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDIsXHJcbiAgICAgICAgYFRoZSByZXF1ZXN0IHdpdGggSUQgJHt1bmlxdWVJZH0gZnJvbSAke1xyXG4gICAgICAgICAgcmVxdWVzdC5oZWFkZXJzWyd4LWZvcndhcmRlZC1mb3InXSB8fCByZXF1ZXN0LmNvbm5lY3Rpb24ucmVtb3RlQWRkcmVzc1xyXG4gICAgICAgIH0gd2FzIGluY29ycmVjdC4gUGF5bG9hZCByZWNlaXZlZDogJHtKU09OLnN0cmluZ2lmeShib2R5KX0uYFxyXG4gICAgICApO1xyXG5cclxuICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICBcIk5vIGNvcnJlY3QgY2hhcnQgZGF0YSBmb3VuZC4gRW5zdXJlIHRoYXQgeW91IGFyZSB1c2luZyBlaXRoZXIgYXBwbGljYXRpb24vanNvbiBvciBtdWx0aXBhcnQvZm9ybS1kYXRhIGhlYWRlcnMuIElmIHNlbmRpbmcgSlNPTiwgbWFrZSBzdXJlIHRoZSBjaGFydCBkYXRhIGlzIGluIHRoZSAnaW5maWxlJywgJ29wdGlvbnMnLCBvciAnZGF0YScgYXR0cmlidXRlLiBJZiBzZW5kaW5nIFNWRywgZW5zdXJlIGl0IGlzIGluIHRoZSAnc3ZnJyBhdHRyaWJ1dGUuXCIsXHJcbiAgICAgICAgNDAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgbGV0IGNhbGxSZXNwb25zZSA9IGZhbHNlO1xyXG5cclxuICAgIC8vIENhbGwgdGhlIGJlZm9yZSByZXF1ZXN0IGZ1bmN0aW9uc1xyXG4gICAgY2FsbFJlc3BvbnNlID0gZG9DYWxsYmFja3MoYmVmb3JlUmVxdWVzdCwgcmVxdWVzdCwgcmVzcG9uc2UsIHtcclxuICAgICAgaWQsXHJcbiAgICAgIHVuaXF1ZUlkLFxyXG4gICAgICB0eXBlLFxyXG4gICAgICBib2R5XHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBCbG9jayB0aGUgcmVxdWVzdCBpZiBvbmUgb2YgYSBjYWxsYmFja3MgZmFpbGVkXHJcbiAgICBpZiAoY2FsbFJlc3BvbnNlICE9PSB0cnVlKSB7XHJcbiAgICAgIHJldHVybiByZXNwb25zZS5zZW5kKGNhbGxSZXNwb25zZSk7XHJcbiAgICB9XHJcblxyXG4gICAgbGV0IGNvbm5lY3Rpb25BYm9ydGVkID0gZmFsc2U7XHJcblxyXG4gICAgLy8gSW4gY2FzZSB0aGUgY29ubmVjdGlvbiBpcyBjbG9zZWQsIGZvcmNlIHRvIGFib3J0IGZ1cnRoZXIgYWN0aW9uc1xyXG4gICAgcmVxdWVzdC5zb2NrZXQub24oJ2Nsb3NlJywgKCkgPT4ge1xyXG4gICAgICBjb25uZWN0aW9uQWJvcnRlZCA9IHRydWU7XHJcbiAgICB9KTtcclxuXHJcbiAgICBsb2coNCwgYFtleHBvcnRdIEdvdCBhbiBpbmNvbWluZyBIVFRQIHJlcXVlc3Qgd2l0aCBJRCAke3VuaXF1ZUlkfS5gKTtcclxuXHJcbiAgICBib2R5LmNvbnN0ciA9ICh0eXBlb2YgYm9keS5jb25zdHIgPT09ICdzdHJpbmcnICYmIGJvZHkuY29uc3RyKSB8fCAnY2hhcnQnO1xyXG5cclxuICAgIC8vIEdhdGhlciBhbmQgb3JnYW5pemUgb3B0aW9ucyBmcm9tIHRoZSBwYXlsb2FkXHJcbiAgICBjb25zdCByZXF1ZXN0T3B0aW9ucyA9IHtcclxuICAgICAgZXhwb3J0OiB7XHJcbiAgICAgICAgaW5zdHIsXHJcbiAgICAgICAgdHlwZSxcclxuICAgICAgICBjb25zdHI6IGJvZHkuY29uc3RyWzBdLnRvTG93ZXJDYXNlKCkgKyBib2R5LmNvbnN0ci5zdWJzdHIoMSksXHJcbiAgICAgICAgaGVpZ2h0OiBib2R5LmhlaWdodCxcclxuICAgICAgICB3aWR0aDogYm9keS53aWR0aCxcclxuICAgICAgICBzY2FsZTogYm9keS5zY2FsZSB8fCBkZWZhdWx0T3B0aW9ucy5leHBvcnQuc2NhbGUsXHJcbiAgICAgICAgZ2xvYmFsT3B0aW9uczogaXNDb3JyZWN0SlNPTihib2R5Lmdsb2JhbE9wdGlvbnMsIHRydWUpLFxyXG4gICAgICAgIHRoZW1lT3B0aW9uczogaXNDb3JyZWN0SlNPTihib2R5LnRoZW1lT3B0aW9ucywgdHJ1ZSlcclxuICAgICAgfSxcclxuICAgICAgY3VzdG9tTG9naWM6IHtcclxuICAgICAgICBhbGxvd0NvZGVFeGVjdXRpb246IGdldEFsbG93Q29kZUV4ZWN1dGlvbigpLFxyXG4gICAgICAgIGFsbG93RmlsZVJlc291cmNlczogZmFsc2UsXHJcbiAgICAgICAgcmVzb3VyY2VzOiBpc0NvcnJlY3RKU09OKGJvZHkucmVzb3VyY2VzLCB0cnVlKSxcclxuICAgICAgICBjYWxsYmFjazogYm9keS5jYWxsYmFjayxcclxuICAgICAgICBjdXN0b21Db2RlOiBib2R5LmN1c3RvbUNvZGVcclxuICAgICAgfVxyXG4gICAgfTtcclxuXHJcbiAgICBpZiAoaW5zdHIpIHtcclxuICAgICAgLy8gU3RyaW5naWZ5IEpTT04gd2l0aCBvcHRpb25zXHJcbiAgICAgIHJlcXVlc3RPcHRpb25zLmV4cG9ydC5pbnN0ciA9IG9wdGlvbnNTdHJpbmdpZnkoXHJcbiAgICAgICAgaW5zdHIsXHJcbiAgICAgICAgcmVxdWVzdE9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTWVyZ2UgdGhlIHJlcXVlc3Qgb3B0aW9ucyBpbnRvIGRlZmF1bHQgb25lc1xyXG4gICAgY29uc3Qgb3B0aW9ucyA9IG1lcmdlQ29uZmlnT3B0aW9ucyhkZWZhdWx0T3B0aW9ucywgcmVxdWVzdE9wdGlvbnMpO1xyXG5cclxuICAgIC8vIFNhdmUgdGhlIEpTT04gaWYgZXhpc3RzXHJcbiAgICBvcHRpb25zLmV4cG9ydC5vcHRpb25zID0gaW5zdHI7XHJcblxyXG4gICAgLy8gTGFzdGx5LCBhZGQgdGhlIHNlcnZlciBzcGVjaWZpYyBhcmd1bWVudHMgaW50byBvcHRpb25zIGFzIHBheWxvYWRcclxuICAgIG9wdGlvbnMucGF5bG9hZCA9IHtcclxuICAgICAgc3ZnOiBib2R5LnN2ZyB8fCBmYWxzZSxcclxuICAgICAgYjY0OiBib2R5LmI2NCB8fCBmYWxzZSxcclxuICAgICAgbm9Eb3dubG9hZDogYm9keS5ub0Rvd25sb2FkIHx8IGZhbHNlLFxyXG4gICAgICByZXF1ZXN0SWQ6IHVuaXF1ZUlkXHJcbiAgICB9O1xyXG5cclxuICAgIC8vIFRlc3QgeGxpbms6aHJlZiBlbGVtZW50cyBmcm9tIHBheWxvYWQncyBTVkdcclxuICAgIGlmIChib2R5LnN2ZyAmJiBpc1ByaXZhdGVSYW5nZVVybEZvdW5kKG9wdGlvbnMucGF5bG9hZC5zdmcpKSB7XHJcbiAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgJ1NWRyBwb3RlbnRpYWxseSBjb250YWluIGF0IGxlYXN0IG9uZSBmb3JiaWRkZW4gVVJMIGluIHhsaW5rOmhyZWYgZWxlbWVudC4gUGxlYXNlIHJldmlldyB0aGUgU1ZHIGNvbnRlbnQgYW5kIGVuc3VyZSB0aGF0IGFsbCByZWZlcmVuY2VkIFVSTHMgY29tcGx5IHdpdGggc2VjdXJpdHkgcG9saWNpZXMuJyxcclxuICAgICAgICA0MDBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBTdGFydCB0aGUgZXhwb3J0IHByb2Nlc3NcclxuICAgIGF3YWl0IHN0YXJ0RXhwb3J0KG9wdGlvbnMsIChlcnJvciwgaW5mbykgPT4ge1xyXG4gICAgICAvLyBSZW1vdmUgdGhlIGNsb3NlIGV2ZW50IGZyb20gdGhlIHNvY2tldFxyXG4gICAgICByZXF1ZXN0LnNvY2tldC5yZW1vdmVBbGxMaXN0ZW5lcnMoJ2Nsb3NlJyk7XHJcblxyXG4gICAgICAvLyBBZnRlciB0aGUgd2hvbGUgZXhwb3J0aW5nIHByb2Nlc3NcclxuICAgICAgaWYgKGRlZmF1bHRPcHRpb25zLnNlcnZlci5iZW5jaG1hcmtpbmcpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICA1LFxyXG4gICAgICAgICAgYFtiZW5jaG1hcmtdIFJlcXVlc3Qgd2l0aCBJRCAke3VuaXF1ZUlkfSAtIEFmdGVyIHRoZSB3aG9sZSBleHBvcnRpbmcgcHJvY2VzczogJHtzdG9wQ291bnRlcigpfW1zLmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBJZiB0aGUgY29ubmVjdGlvbiB3YXMgY2xvc2VkLCBkbyBub3RoaW5nXHJcbiAgICAgIGlmIChjb25uZWN0aW9uQWJvcnRlZCkge1xyXG4gICAgICAgIHJldHVybiBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtleHBvcnRdIFRoZSBjbGllbnQgY2xvc2VkIHRoZSBjb25uZWN0aW9uIGJlZm9yZSB0aGUgY2hhcnQgZmluaXNoZWQgcHJvY2Vzc2luZy5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgZXJyb3IsIGxvZyBpdCBhbmQgc2VuZCBpdCB0byB0aGUgZXJyb3IgbWlkZGxld2FyZVxyXG4gICAgICBpZiAoZXJyb3IpIHtcclxuICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgZGF0YSBpcyBtaXNzaW5nLCBsb2cgdGhlIG1lc3NhZ2UgYW5kIHNlbmQgaXQgdG8gdGhlIGVycm9yIG1pZGRsZXdhcmVcclxuICAgICAgaWYgKCFpbmZvIHx8ICFpbmZvLnJlc3VsdCkge1xyXG4gICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgICBgVW5leHBlY3RlZCByZXR1cm4gZnJvbSBjaGFydCBnZW5lcmF0aW9uLiBQbGVhc2UgY2hlY2sgeW91ciByZXF1ZXN0IGRhdGEuIEZvciB0aGUgcmVxdWVzdCB3aXRoIElEICR7dW5pcXVlSWR9LCB0aGUgcmVzdWx0IGlzICR7aW5mby5yZXN1bHR9LmAsXHJcbiAgICAgICAgICA0MDBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBHZXQgdGhlIHR5cGUgZnJvbSBvcHRpb25zXHJcbiAgICAgIHR5cGUgPSBpbmZvLm9wdGlvbnMuZXhwb3J0LnR5cGU7XHJcblxyXG4gICAgICAvLyBUaGUgYWZ0ZXIgcmVxdWVzdCBjYWxsYmFja3NcclxuICAgICAgZG9DYWxsYmFja3MoYWZ0ZXJSZXF1ZXN0LCByZXF1ZXN0LCByZXNwb25zZSwgeyBpZCwgYm9keTogaW5mby5yZXN1bHQgfSk7XHJcblxyXG4gICAgICBpZiAoaW5mby5yZXN1bHQpIHtcclxuICAgICAgICAvLyBJZiBvbmx5IGJhc2U2NCBpcyByZXF1aXJlZCwgcmV0dXJuIGl0XHJcbiAgICAgICAgaWYgKGJvZHkuYjY0KSB7XHJcbiAgICAgICAgICAvLyBTVkcgRXhjZXB0aW9uIGZvciB0aGUgSGlnaGNoYXJ0cyAxMS4zLjAgdmVyc2lvblxyXG4gICAgICAgICAgaWYgKHR5cGUgPT09ICdwZGYnIHx8IHR5cGUgPT0gJ3N2ZycpIHtcclxuICAgICAgICAgICAgcmV0dXJuIHJlc3BvbnNlLnNlbmQoXHJcbiAgICAgICAgICAgICAgQnVmZmVyLmZyb20oaW5mby5yZXN1bHQsICd1dGY4JykudG9TdHJpbmcoJ2Jhc2U2NCcpXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgcmV0dXJuIHJlc3BvbnNlLnNlbmQoaW5mby5yZXN1bHQpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gU2V0IGNvcnJlY3QgY29udGVudCB0eXBlXHJcbiAgICAgICAgcmVzcG9uc2UuaGVhZGVyKCdDb250ZW50LVR5cGUnLCByZXZlcnNlZE1pbWVbdHlwZV0gfHwgJ2ltYWdlL3BuZycpO1xyXG5cclxuICAgICAgICAvLyBEZWNpZGUgd2hldGhlciB0byBkb3dubG9hZCBvciBub3QgY2hhcnQgZmlsZVxyXG4gICAgICAgIGlmICghYm9keS5ub0Rvd25sb2FkKSB7XHJcbiAgICAgICAgICByZXNwb25zZS5hdHRhY2htZW50KFxyXG4gICAgICAgICAgICBgJHtyZXF1ZXN0LnBhcmFtcy5maWxlbmFtZSB8fCByZXF1ZXN0LmJvZHkuZmlsZW5hbWUgfHwgJ2NoYXJ0J30uJHtcclxuICAgICAgICAgICAgICB0eXBlIHx8ICdwbmcnXHJcbiAgICAgICAgICAgIH1gXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gSWYgU1ZHLCByZXR1cm4gcGxhaW4gY29udGVudFxyXG4gICAgICAgIHJldHVybiB0eXBlID09PSAnc3ZnJ1xyXG4gICAgICAgICAgPyByZXNwb25zZS5zZW5kKGluZm8ucmVzdWx0KVxyXG4gICAgICAgICAgOiByZXNwb25zZS5zZW5kKEJ1ZmZlci5mcm9tKGluZm8ucmVzdWx0LCAnYmFzZTY0JykpO1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgbmV4dChlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQgKGFwcCkgPT4ge1xyXG4gIC8qKlxyXG4gICAqIEFkZHMgdGhlIFBPU1QgLyBhIHJvdXRlIGZvciBoYW5kbGluZyBQT1NUIHJlcXVlc3RzIGF0IHRoZSByb290IGVuZHBvaW50LlxyXG4gICAqL1xyXG4gIGFwcC5wb3N0KCcvJywgZXhwb3J0SGFuZGxlcik7XHJcblxyXG4gIC8qKlxyXG4gICAqIEFkZHMgdGhlIFBPU1QgLzpmaWxlbmFtZSBhIHJvdXRlIGZvciBoYW5kbGluZyBQT1NUIHJlcXVlc3RzIHdpdGhcclxuICAgKiBhIHNwZWNpZmllZCBmaWxlbmFtZSBwYXJhbWV0ZXIuXHJcbiAgICovXHJcbiAgYXBwLnBvc3QoJy86ZmlsZW5hbWUnLCBleHBvcnRIYW5kbGVyKTtcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IGpvaW4gYXMgcGF0aGVyIH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgY2FjaGUgZnJvbSAnLi4vLi4vY2FjaGUuanMnO1xyXG5pbXBvcnQgcG9vbCBmcm9tICcuLi8uLi9wb29sLmpzJztcclxuaW1wb3J0IHsgX19kaXJuYW1lIH0gZnJvbSAnLi4vLi4vdXRpbHMuanMnO1xyXG5cclxuY29uc3QgcGtnRmlsZSA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKHBhdGhlcihfX2Rpcm5hbWUsICdwYWNrYWdlLmpzb24nKSkpO1xyXG5cclxuY29uc3Qgc2VydmVyU3RhcnRUaW1lID0gbmV3IERhdGUoKTtcclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSBHRVQgL2hlYWx0aCByb3V0ZSwgd2hpY2ggb3V0cHV0cyBiYXNpYyBzdGF0cyBmb3IgdGhlIHNlcnZlci5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IChhcHApID0+XHJcbiAgIWFwcFxyXG4gICAgPyBmYWxzZVxyXG4gICAgOiBhcHAuZ2V0KCcvaGVhbHRoJywgKHJlcXVlc3QsIHJlc3BvbnNlKSA9PiB7XHJcbiAgICAgICAgcmVzcG9uc2Uuc2VuZCh7XHJcbiAgICAgICAgICBzdGF0dXM6ICdPSycsXHJcbiAgICAgICAgICBib290VGltZTogc2VydmVyU3RhcnRUaW1lLFxyXG4gICAgICAgICAgdXB0aW1lOlxyXG4gICAgICAgICAgICBNYXRoLmZsb29yKFxyXG4gICAgICAgICAgICAgIChuZXcgRGF0ZSgpLmdldFRpbWUoKSAtIHNlcnZlclN0YXJ0VGltZS5nZXRUaW1lKCkpIC8gMTAwMCAvIDYwXHJcbiAgICAgICAgICAgICkgKyAnIG1pbnV0ZXMnLFxyXG4gICAgICAgICAgdmVyc2lvbjogcGtnRmlsZS52ZXJzaW9uLFxyXG4gICAgICAgICAgaGlnaGNoYXJ0c1ZlcnNpb246IGNhY2hlLnZlcnNpb24oKSxcclxuICAgICAgICAgIGF2ZXJhZ2VQcm9jZXNzaW5nVGltZTogcG9vbC5hdmVyYWdlVGltZSgpLFxyXG4gICAgICAgICAgcGVyZm9ybWVkRXhwb3J0czogcG9vbC5wcm9jZXNzZWRXb3JrQ291bnQoKSxcclxuICAgICAgICAgIGZhaWxlZEV4cG9ydHM6IHBvb2wuZHJvcHBlZFdvcmsoKSxcclxuICAgICAgICAgIGV4cG9ydEF0dGVtcHRzOiBwb29sLndvcmtBdHRlbXB0cygpLFxyXG4gICAgICAgICAgc3VjZXNzUmF0aW86IChwb29sLnByb2Nlc3NlZFdvcmtDb3VudCgpIC8gcG9vbC53b3JrQXR0ZW1wdHMoKSkgKiAxMDAsXHJcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgaW1wb3J0L25vLW5hbWVkLWFzLWRlZmF1bHQtbWVtYmVyXHJcbiAgICAgICAgICBwb29sOiBwb29sLmdldFBvb2xJbmZvSlNPTigpXHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH0pO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IHByb21pc2VzIGFzIGZzUHJvbWlzZXMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IHBvc2l4IH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgY29ycyBmcm9tICdjb3JzJztcclxuaW1wb3J0IGV4cHJlc3MgZnJvbSAnZXhwcmVzcyc7XHJcbmltcG9ydCBodHRwIGZyb20gJ2h0dHAnO1xyXG5pbXBvcnQgaHR0cHMgZnJvbSAnaHR0cHMnO1xyXG5pbXBvcnQgbXVsdGVyIGZyb20gJ211bHRlcic7XHJcblxyXG5pbXBvcnQgZXJyb3JIYW5kbGVyIGZyb20gJy4vZXJyb3IuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4uL2xvZ2dlci5qcyc7XHJcbmltcG9ydCByYXRlTGltaXQgZnJvbSAnLi9yYXRlX2xpbWl0LmpzJztcclxuaW1wb3J0IHsgX19kaXJuYW1lIH0gZnJvbSAnLi4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IHZTd2l0Y2hSb3V0ZSBmcm9tICcuL3JvdXRlcy9jaGFuZ2VfaGNfdmVyc2lvbi5qcyc7XHJcbmltcG9ydCBleHBvcnRSb3V0ZXMgZnJvbSAnLi9yb3V0ZXMvZXhwb3J0LmpzJztcclxuaW1wb3J0IGhlYWx0aFJvdXRlIGZyb20gJy4vcm91dGVzL2hlYWx0aC5qcyc7XHJcbmltcG9ydCB1aVJvdXRlIGZyb20gJy4vcm91dGVzL3VpLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLy8gQ3JlYXRlIGV4cHJlc3MgYXBwXHJcbmNvbnN0IGFwcCA9IGV4cHJlc3MoKTtcclxuXHJcbi8vIERpc2FibGUgdGhlIFgtUG93ZXJlZC1CeSBoZWFkZXJcclxuYXBwLmRpc2FibGUoJ3gtcG93ZXJlZC1ieScpO1xyXG5cclxuLy8gRW5hYmxlIENPUlMgc3VwcG9ydFxyXG5hcHAudXNlKGNvcnMoKSk7XHJcblxyXG4vLyBFbmFibGUgcGFyc2luZyBvZiBmb3JtIGRhdGEgKGZpbGVzKSB3aXRoIE11bHRlciBwYWNrYWdlXHJcbmNvbnN0IHN0b3JhZ2UgPSBtdWx0ZXIubWVtb3J5U3RvcmFnZSgpO1xyXG5jb25zdCB1cGxvYWQgPSBtdWx0ZXIoe1xyXG4gIHN0b3JhZ2UsXHJcbiAgbGltaXRzOiB7XHJcbiAgICBmaWVsZFNpemU6IDUwICogMTAyNCAqIDEwMjRcclxuICB9XHJcbn0pO1xyXG5cclxuLy8gRW5hYmxlIGJvZHkgcGFyc2VyXHJcbmFwcC51c2UoZXhwcmVzcy5qc29uKHsgbGltaXQ6IDUwICogMTAyNCAqIDEwMjQgfSkpO1xyXG5hcHAudXNlKGV4cHJlc3MudXJsZW5jb2RlZCh7IGV4dGVuZGVkOiB0cnVlLCBsaW1pdDogNTAgKiAxMDI0ICogMTAyNCB9KSk7XHJcblxyXG4vLyBVc2Ugb25seSBub24tZmlsZSBtdWx0aXBhcnQgZm9ybSBmaWVsZHNcclxuYXBwLnVzZSh1cGxvYWQubm9uZSgpKTtcclxuXHJcbi8qKlxyXG4gKiBBdHRhY2ggZXJyb3IgaGFuZGxlcnMgdG8gdGhlIHNlcnZlci5cclxuICpcclxuICogQHBhcmFtIHtodHRwLlNlcnZlcn0gc2VydmVyIC0gVGhlIEhUVFAvSFRUUFMgc2VydmVyIGluc3RhbmNlLlxyXG4gKi9cclxuY29uc3QgYXR0YWNoRXJyb3JIYW5kbGVycyA9IChzZXJ2ZXIpID0+IHtcclxuICBzZXJ2ZXIub24oJ2NsaWVudEVycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICBsb2dXaXRoU3RhY2soMSwgZXJyb3IsIGBbc2VydmVyXSBDbGllbnQgZXJyb3I6ICR7ZXJyb3IubWVzc2FnZX1gKTtcclxuICB9KTtcclxuICBzZXJ2ZXIub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICBsb2dXaXRoU3RhY2soMSwgZXJyb3IsIGBbc2VydmVyXSBTZXJ2ZXIgZXJyb3I6ICR7ZXJyb3IubWVzc2FnZX1gKTtcclxuICB9KTtcclxuICBzZXJ2ZXIub24oJ2Nvbm5lY3Rpb24nLCAoc29ja2V0KSA9PiB7XHJcbiAgICBzb2NrZXQub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFtzZXJ2ZXJdIFNvY2tldCBlcnJvcjogJHtlcnJvci5tZXNzYWdlfWApO1xyXG4gICAgfSk7XHJcbiAgfSk7XHJcbn07XHJcblxyXG4vKipcclxuICogU3RhcnRzIGFuIEhUVFAgc2VydmVyIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uLiBUaGUgYHNlcnZlckNvbmZpZ2BcclxuICogb2JqZWN0IGNvbnRhaW5zIGFsbCBzZXJ2ZXIgcmVsYXRlZCBwcm9wZXJ0aWVzIChzZWUgdGhlIGBzZXJ2ZXJgIHNlY3Rpb25cclxuICogaW4gdGhlIGBsaWIvc2NoZW1hcy9jb25maWcuanNgIGZpbGUgZm9yIGEgcmVmZXJlbmNlKS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHNlcnZlckNvbmZpZyAtIFRoZSBzZXJ2ZXIgY29uZmlndXJhdGlvbiBvYmplY3QuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSAtIFRocm93cyBhbiBlcnJvciBpZiB0aGUgc2VydmVyIGNhbm5vdCBiZSBjb25maWd1cmVkXHJcbiAqIGFuZCBzdGFydGVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHN0YXJ0U2VydmVyID0gYXN5bmMgKHNlcnZlckNvbmZpZykgPT4ge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBTdG9wIGlmIG5vdCBlbmFibGVkXHJcbiAgICBpZiAoIXNlcnZlckNvbmZpZy5lbmFibGUpIHtcclxuICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIExpc3RlbiBIVFRQIHNlcnZlclxyXG4gICAgaWYgKCFzZXJ2ZXJDb25maWcuc3NsLmZvcmNlKSB7XHJcbiAgICAgIC8vIE1haW4gc2VydmVyIGluc3RhbmNlIChIVFRQKVxyXG4gICAgICBjb25zdCBodHRwU2VydmVyID0gaHR0cC5jcmVhdGVTZXJ2ZXIoYXBwKTtcclxuXHJcbiAgICAgIC8vIEF0dGFjaCBlcnJvciBoYW5kbGVycyBhbmQgbGlzdGVuIHRvIHRoZSBzZXJ2ZXJcclxuICAgICAgYXR0YWNoRXJyb3JIYW5kbGVycyhodHRwU2VydmVyKTtcclxuXHJcbiAgICAgIC8vIExpc3RlblxyXG4gICAgICBodHRwU2VydmVyLmxpc3RlbihzZXJ2ZXJDb25maWcucG9ydCwgc2VydmVyQ29uZmlnLmhvc3QpO1xyXG5cclxuICAgICAgbG9nKFxyXG4gICAgICAgIDMsXHJcbiAgICAgICAgYFtzZXJ2ZXJdIFN0YXJ0ZWQgSFRUUCBzZXJ2ZXIgb24gJHtzZXJ2ZXJDb25maWcuaG9zdH06JHtzZXJ2ZXJDb25maWcucG9ydH0uYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIExpc3RlbiBIVFRQUyBzZXJ2ZXJcclxuICAgIGlmIChzZXJ2ZXJDb25maWcuc3NsLmVuYWJsZSkge1xyXG4gICAgICAvLyBTZXQgdXAgYW4gU1NMIHNlcnZlciBhbHNvXHJcbiAgICAgIGxldCBrZXksIGNlcnQ7XHJcblxyXG4gICAgICB0cnkge1xyXG4gICAgICAgIC8vIEdldCB0aGUgU1NMIGtleVxyXG4gICAgICAgIGtleSA9IGF3YWl0IGZzUHJvbWlzZXMucmVhZEZpbGUoXHJcbiAgICAgICAgICBwb3NpeC5qb2luKHNlcnZlckNvbmZpZy5zc2wuY2VydFBhdGgsICdzZXJ2ZXIua2V5JyksXHJcbiAgICAgICAgICAndXRmOCdcclxuICAgICAgICApO1xyXG5cclxuICAgICAgICAvLyBHZXQgdGhlIFNTTCBjZXJ0aWZpY2F0ZVxyXG4gICAgICAgIGNlcnQgPSBhd2FpdCBmc1Byb21pc2VzLnJlYWRGaWxlKFxyXG4gICAgICAgICAgcG9zaXguam9pbihzZXJ2ZXJDb25maWcuc3NsLmNlcnRQYXRoLCAnc2VydmVyLmNydCcpLFxyXG4gICAgICAgICAgJ3V0ZjgnXHJcbiAgICAgICAgKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAyLFxyXG4gICAgICAgICAgYFtzZXJ2ZXJdIFVuYWJsZSB0byBsb2FkIGtleS9jZXJ0aWZpY2F0ZSBmcm9tIHRoZSAnJHtzZXJ2ZXJDb25maWcuc3NsLmNlcnRQYXRofScgcGF0aC4gQ291bGQgbm90IHJ1biBzZWN1cmVkIGxheWVyIHNlcnZlci5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKGtleSAmJiBjZXJ0KSB7XHJcbiAgICAgICAgLy8gTWFpbiBzZXJ2ZXIgaW5zdGFuY2UgKEhUVFBTKVxyXG4gICAgICAgIGNvbnN0IGh0dHBzU2VydmVyID0gaHR0cHMuY3JlYXRlU2VydmVyKHsga2V5LCBjZXJ0IH0sIGFwcCk7XHJcblxyXG4gICAgICAgIC8vIEF0dGFjaCBlcnJvciBoYW5kbGVycyBhbmQgbGlzdGVuIHRvIHRoZSBzZXJ2ZXJcclxuICAgICAgICBhdHRhY2hFcnJvckhhbmRsZXJzKGh0dHBzU2VydmVyKTtcclxuXHJcbiAgICAgICAgLy8gTGlzdGVuXHJcbiAgICAgICAgaHR0cHNTZXJ2ZXIubGlzdGVuKHNlcnZlckNvbmZpZy5zc2wucG9ydCwgc2VydmVyQ29uZmlnLmhvc3QpO1xyXG5cclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtzZXJ2ZXJdIFN0YXJ0ZWQgSFRUUFMgc2VydmVyIG9uICR7c2VydmVyQ29uZmlnLmhvc3R9OiR7c2VydmVyQ29uZmlnLnNzbC5wb3J0fS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIEVuYWJsZSB0aGUgcmF0ZSBsaW1pdGVyIGlmIGNvbmZpZyBzYXlzIHNvXHJcbiAgICBpZiAoXHJcbiAgICAgIHNlcnZlckNvbmZpZy5yYXRlTGltaXRpbmcgJiZcclxuICAgICAgc2VydmVyQ29uZmlnLnJhdGVMaW1pdGluZy5lbmFibGUgJiZcclxuICAgICAgIVswLCBOYU5dLmluY2x1ZGVzKHNlcnZlckNvbmZpZy5yYXRlTGltaXRpbmcubWF4UmVxdWVzdHMpXHJcbiAgICApIHtcclxuICAgICAgcmF0ZUxpbWl0KGFwcCwgc2VydmVyQ29uZmlnLnJhdGVMaW1pdGluZyk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU2V0IHVwIHN0YXRpYyBmb2xkZXIncyByb3V0ZVxyXG4gICAgYXBwLnVzZShleHByZXNzLnN0YXRpYyhwb3NpeC5qb2luKF9fZGlybmFtZSwgJ3B1YmxpYycpKSk7XHJcblxyXG4gICAgLy8gU2V0IHVwIHJvdXRlc1xyXG4gICAgaGVhbHRoUm91dGUoYXBwKTtcclxuICAgIGV4cG9ydFJvdXRlcyhhcHApO1xyXG4gICAgdWlSb3V0ZShhcHApO1xyXG4gICAgdlN3aXRjaFJvdXRlKGFwcCk7XHJcblxyXG4gICAgLy8gU2V0IHVwIGNlbnRyYWxpemVkIGVycm9yIGhhbmRsZXJcclxuICAgIGVycm9ySGFuZGxlcihhcHApO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbc2VydmVyXSBDb3VsZCBub3QgY29uZmlndXJlIGFuZCBzdGFydCB0aGUgc2VydmVyLidcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBFbmFibGUgcmF0ZSBsaW1pdGluZyBmb3IgdGhlIHNlcnZlci5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGxpbWl0Q29uZmlnIC0gQ29uZmlndXJhdGlvbiBvYmplY3QgZm9yIHJhdGUgbGltaXRpbmcuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZW5hYmxlUmF0ZUxpbWl0aW5nID0gKGxpbWl0Q29uZmlnKSA9PiByYXRlTGltaXQoYXBwLCBsaW1pdENvbmZpZyk7XHJcblxyXG4vKipcclxuICogR2V0IHRoZSBFeHByZXNzIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSAtIFRoZSBFeHByZXNzIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldEV4cHJlc3MgPSAoKSA9PiBleHByZXNzO1xyXG5cclxuLyoqXHJcbiAqIEdldCB0aGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IC0gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldEFwcCA9ICgpID0+IGFwcDtcclxuXHJcbi8qKlxyXG4gKiBBcHBseSBtaWRkbGV3YXJlKHMpIHRvIGEgc3BlY2lmaWMgcGF0aC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBUaGUgcGF0aCB0byB3aGljaCB0aGUgbWlkZGxld2FyZShzKSBzaG91bGQgYmUgYXBwbGllZC5cclxuICogQHBhcmFtIHsuLi5GdW5jdGlvbn0gbWlkZGxld2FyZXMgLSBUaGUgbWlkZGxld2FyZSBmdW5jdGlvbnMgdG8gYmUgYXBwbGllZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCB1c2UgPSAocGF0aCwgLi4ubWlkZGxld2FyZXMpID0+IHtcclxuICBhcHAudXNlKHBhdGgsIC4uLm1pZGRsZXdhcmVzKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBTZXQgdXAgYSByb3V0ZSB3aXRoIEdFVCBtZXRob2QgYW5kIGFwcGx5IG1pZGRsZXdhcmUocykuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIC0gVGhlIHJvdXRlIHBhdGguXHJcbiAqIEBwYXJhbSB7Li4uRnVuY3Rpb259IG1pZGRsZXdhcmVzIC0gVGhlIG1pZGRsZXdhcmUgZnVuY3Rpb25zIHRvIGJlIGFwcGxpZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0ID0gKHBhdGgsIC4uLm1pZGRsZXdhcmVzKSA9PiB7XHJcbiAgYXBwLmdldChwYXRoLCAuLi5taWRkbGV3YXJlcyk7XHJcbn07XHJcblxyXG4vKipcclxuICogU2V0IHVwIGEgcm91dGUgd2l0aCBQT1NUIG1ldGhvZCBhbmQgYXBwbHkgbWlkZGxld2FyZShzKS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBUaGUgcm91dGUgcGF0aC5cclxuICogQHBhcmFtIHsuLi5GdW5jdGlvbn0gbWlkZGxld2FyZXMgLSBUaGUgbWlkZGxld2FyZSBmdW5jdGlvbnMgdG8gYmUgYXBwbGllZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBwb3N0ID0gKHBhdGgsIC4uLm1pZGRsZXdhcmVzKSA9PiB7XHJcbiAgYXBwLnBvc3QocGF0aCwgLi4ubWlkZGxld2FyZXMpO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIHN0YXJ0U2VydmVyLFxyXG4gIGVuYWJsZVJhdGVMaW1pdGluZyxcclxuICBnZXRFeHByZXNzLFxyXG4gIGdldEFwcCxcclxuICB1c2UsXHJcbiAgZ2V0LFxyXG4gIHBvc3RcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgeyBfX2Rpcm5hbWUgfSBmcm9tICcuLi8uLi91dGlscy5qcyc7XHJcblxyXG4vKipcclxuICogQWRkcyB0aGUgR0VUIC8gcm91dGUgZm9yIGEgVUkgd2hlbiBlbmFibGVkIG9uIHRoZSBleHBvcnQgc2VydmVyLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgKGFwcCkgPT5cclxuICAhYXBwXHJcbiAgICA/IGZhbHNlXHJcbiAgICA6IGFwcC5nZXQoJy8nLCAocmVxdWVzdCwgcmVzcG9uc2UpID0+IHtcclxuICAgICAgICByZXNwb25zZS5zZW5kRmlsZShqb2luKF9fZGlybmFtZSwgJ3B1YmxpYycsICdpbmRleC5odG1sJykpO1xyXG4gICAgICB9KTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgY2FjaGUgZnJvbSAnLi4vLi4vY2FjaGUuanMnO1xyXG5cclxuaW1wb3J0IEh0dHBFcnJvciBmcm9tICcuLi8uLi9lcnJvcnMvSHR0cEVycm9yLmpzJztcclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSBQT1NUIC9jaGFuZ2VfaGNfdmVyc2lvbi86bmV3VmVyc2lvbiByb3V0ZSB0aGF0IGNhbiBiZSB1dGlsaXplZCB0byBtb2RpZnlcclxuICogdGhlIEhpZ2hjaGFydHMgdmVyc2lvbiBvbiB0aGUgc2VydmVyLlxyXG4gKlxyXG4gKiBUT0RPOiBBZGQgYXV0aCB0b2tlbiBhbmQgY29ubmVjdCB0byBBUElcclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IChhcHApID0+XHJcbiAgIWFwcFxyXG4gICAgPyBmYWxzZVxyXG4gICAgOiBhcHAucG9zdChcclxuICAgICAgICAnL3ZlcnNpb24vY2hhbmdlLzpuZXdWZXJzaW9uJyxcclxuICAgICAgICBhc3luYyAocmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpID0+IHtcclxuICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgIGNvbnN0IGFkbWluVG9rZW4gPSBwcm9jZXNzLmVudi5ISUdIQ0hBUlRTX0FETUlOX1RPS0VOO1xyXG5cclxuICAgICAgICAgICAgLy8gQ2hlY2sgdGhlIGV4aXN0ZW5jZSBvZiB0aGUgdG9rZW5cclxuICAgICAgICAgICAgaWYgKCFhZG1pblRva2VuIHx8ICFhZG1pblRva2VuLmxlbmd0aCkge1xyXG4gICAgICAgICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgICAgICAgICAnVGhlIHNlcnZlciBpcyBub3QgY29uZmlndXJlZCB0byBwZXJmb3JtIHJ1bi10aW1lIHZlcnNpb24gY2hhbmdlczogSElHSENIQVJUU19BRE1JTl9UT0tFTiBpcyBub3Qgc2V0LicsXHJcbiAgICAgICAgICAgICAgICA0MDFcclxuICAgICAgICAgICAgICApO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAvLyBDaGVjayBpZiB0aGUgaGMtYXV0aCBoZWFkZXIgY29udGFpbiBhIGNvcnJlY3QgdG9rZW5cclxuICAgICAgICAgICAgY29uc3QgdG9rZW4gPSByZXF1ZXN0LmdldCgnaGMtYXV0aCcpO1xyXG4gICAgICAgICAgICBpZiAoIXRva2VuIHx8IHRva2VuICE9PSBhZG1pblRva2VuKSB7XHJcbiAgICAgICAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAgICAgICAgICdJbnZhbGlkIG9yIG1pc3NpbmcgdG9rZW46IFNldCB0aGUgdG9rZW4gaW4gdGhlIGhjLWF1dGggaGVhZGVyLicsXHJcbiAgICAgICAgICAgICAgICA0MDFcclxuICAgICAgICAgICAgICApO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAvLyBDb21wYXJlIHZlcnNpb25zXHJcbiAgICAgICAgICAgIGNvbnN0IG5ld1ZlcnNpb24gPSByZXF1ZXN0LnBhcmFtcy5uZXdWZXJzaW9uO1xyXG4gICAgICAgICAgICBpZiAobmV3VmVyc2lvbikge1xyXG4gICAgICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgaW1wb3J0L25vLW5hbWVkLWFzLWRlZmF1bHQtbWVtYmVyXHJcbiAgICAgICAgICAgICAgICBhd2FpdCBjYWNoZS51cGRhdGVWZXJzaW9uKG5ld1ZlcnNpb24pO1xyXG4gICAgICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgICAgICAgICAgICBgVmVyc2lvbiBjaGFuZ2U6ICR7ZXJyb3IubWVzc2FnZX1gLFxyXG4gICAgICAgICAgICAgICAgICBlcnJvci5zdGF0dXNDb2RlXHJcbiAgICAgICAgICAgICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgIC8vIFN1Y2Nlc3NcclxuICAgICAgICAgICAgICByZXNwb25zZS5zdGF0dXMoMjAwKS5zZW5kKHtcclxuICAgICAgICAgICAgICAgIHN0YXR1c0NvZGU6IDIwMCxcclxuICAgICAgICAgICAgICAgIHZlcnNpb246IGNhY2hlLnZlcnNpb24oKSxcclxuICAgICAgICAgICAgICAgIG1lc3NhZ2U6IGBTdWNjZXNzZnVsbHkgdXBkYXRlZCBIaWdoY2hhcnRzIHRvIHZlcnNpb246ICR7bmV3VmVyc2lvbn0uYFxyXG4gICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgIC8vIE5vIHZlcnNpb24gc3BlY2lmaWVkXHJcbiAgICAgICAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcignTm8gbmV3IHZlcnNpb24gc3VwcGxpZWQuJywgNDAwKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgICAgbmV4dChlcnJvcik7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICApO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCAnY29sb3JzJztcclxuaW1wb3J0IGRvdGVudiBmcm9tICdkb3RlbnYnO1xyXG5cclxuaW1wb3J0IHsgY2hlY2tBbmRVcGRhdGVDYWNoZSB9IGZyb20gJy4vY2FjaGUuanMnO1xyXG5pbXBvcnQge1xyXG4gIGJhdGNoRXhwb3J0LFxyXG4gIHNldEFsbG93Q29kZUV4ZWN1dGlvbixcclxuICBzaW5nbGVFeHBvcnQsXHJcbiAgc3RhcnRFeHBvcnRcclxufSBmcm9tICcuL2NoYXJ0LmpzJztcclxuaW1wb3J0IHsgbWFwVG9OZXdDb25maWcsIG1hbnVhbENvbmZpZywgc2V0T3B0aW9ucyB9IGZyb20gJy4vY29uZmlnLmpzJztcclxuaW1wb3J0IHtcclxuICBpbml0TG9nZ2luZyxcclxuICBsb2csXHJcbiAgbG9nV2l0aFN0YWNrLFxyXG4gIHNldExvZ0xldmVsLFxyXG4gIGVuYWJsZUZpbGVMb2dnaW5nXHJcbn0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBpbml0UG9vbCwga2lsbFBvb2wgfSBmcm9tICcuL3Bvb2wuanMnO1xyXG5pbXBvcnQgc2VydmVyLCB7IHN0YXJ0U2VydmVyIH0gZnJvbSAnLi9zZXJ2ZXIvc2VydmVyLmpzJztcclxuaW1wb3J0IHsgcHJpbnRMb2dvLCBwcmludFVzYWdlIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG4vLyBMb2FkIC5lbnYgaW50byBlbnZpcm9ubWVudCB2YXJpYWJsZXNcclxuZG90ZW52LmNvbmZpZygpO1xyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIHRoZSBleHBvcnQgcHJvY2Vzcy4gVGFza3Mgc3VjaCBhcyBjb25maWd1cmluZyBsb2dnaW5nLCBjaGVja2luZ1xyXG4gKiBjYWNoZSBhbmQgc291cmNlcywgYW5kIGluaXRpYWxpemluZyB0aGUgcG9vbCBvZiByZXNvdXJjZXMgaGFwcGVuIGR1cmluZ1xyXG4gKiB0aGlzIHN0YWdlLiBGdW5jdGlvbiB0aGF0IGlzIHJlcXVpcmVkIHRvIGJlIGNhbGxlZCBiZWZvcmUgdHJ5aW5nIHRvIGV4cG9ydCBjaGFydHMgb3Igc2V0dGluZyBhIHNlcnZlci4gVGhlIGBvcHRpb25zYCBpcyBhbiBvYmplY3QgdGhhdCBjb250YWlucyBhbGwgb3B0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBBbGwgZXhwb3J0IG9wdGlvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSB1cGRhdGVkIGV4cG9ydCBvcHRpb25zLlxyXG4gKi9cclxuY29uc3QgaW5pdEV4cG9ydCA9IGFzeW5jIChvcHRpb25zKSA9PiB7XHJcbiAgLy8gU2V0IHRoZSBhbGxvd0NvZGVFeGVjdXRpb24gcGVyIGV4cG9ydCBtb2R1bGUgc2NvcGVcclxuICBzZXRBbGxvd0NvZGVFeGVjdXRpb24oXHJcbiAgICBvcHRpb25zLmN1c3RvbUxvZ2ljICYmIG9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgKTtcclxuXHJcbiAgLy8gSW5pdCB0aGUgbG9nZ2luZ1xyXG4gIGluaXRMb2dnaW5nKG9wdGlvbnMubG9nZ2luZyk7XHJcblxyXG4gIC8vIENoZWNrIGlmIGNhY2hlIG5lZWRzIHRvIGJlIHVwZGF0ZWRcclxuICBhd2FpdCBjaGVja0FuZFVwZGF0ZUNhY2hlKG9wdGlvbnMuaGlnaGNoYXJ0cyB8fCB7IHZlcnNpb246ICdsYXRlc3QnIH0pO1xyXG5cclxuICAvLyBJbml0IHRoZSBwb29sXHJcbiAgYXdhaXQgaW5pdFBvb2woe1xyXG4gICAgcG9vbDogb3B0aW9ucy5wb29sIHx8IHtcclxuICAgICAgbWluV29ya2VyczogMSxcclxuICAgICAgbWF4V29ya2VyczogMVxyXG4gICAgfSxcclxuICAgIHB1cHBldGVlckFyZ3M6IG9wdGlvbnMucHVwcGV0ZWVyPy5hcmdzIHx8IFtdXHJcbiAgfSk7XHJcblxyXG4gIC8vIFJldHVybiB1cGRhdGVkIG9wdGlvbnNcclxuICByZXR1cm4gb3B0aW9ucztcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICAvLyBTZXJ2ZXJcclxuICBzZXJ2ZXIsXHJcbiAgc3RhcnRTZXJ2ZXIsXHJcbiAgc2V0T3B0aW9ucyxcclxuXHJcbiAgLy8gRXhwb3J0aW5nXHJcbiAgaW5pdEV4cG9ydCxcclxuICBzaW5nbGVFeHBvcnQsXHJcbiAgYmF0Y2hFeHBvcnQsXHJcbiAgc3RhcnRFeHBvcnQsXHJcbiAga2lsbFBvb2wsXHJcblxyXG4gIC8vIExvZ3NcclxuICBsb2csXHJcbiAgbG9nV2l0aFN0YWNrLFxyXG4gIHNldExvZ0xldmVsLFxyXG4gIGVuYWJsZUZpbGVMb2dnaW5nLFxyXG5cclxuICAvLyBVdGlsc1xyXG4gIG1hcFRvTmV3Q29uZmlnLFxyXG4gIG1hbnVhbENvbmZpZyxcclxuICBwcmludExvZ28sXHJcbiAgcHJpbnRVc2FnZVxyXG59O1xyXG4iXSwibmFtZXMiOlsiYXN5bmMiLCJmZXRjaCIsInVybCIsInJlcXVlc3RPcHRpb25zIiwiUHJvbWlzZSIsInJlc29sdmUiLCJyZWplY3QiLCJwcm90b2NvbCIsInN0YXJ0c1dpdGgiLCJodHRwcyIsImh0dHAiLCJnZXRQcm90b2NvbCIsImdldCIsInJlcyIsImRhdGEiLCJvbiIsImNodW5rIiwidGV4dCIsImVycm9yIiwiZGVmYXVsdENvbmZpZyIsInB1cHBldGVlciIsImFyZ3MiLCJ2YWx1ZSIsInR5cGUiLCJkZXNjcmlwdGlvbiIsImhpZ2hjaGFydHMiLCJ2ZXJzaW9uIiwiZW52TGluayIsImNkblVSTCIsImNvcmVTY3JpcHRzIiwibW9kdWxlcyIsImluZGljYXRvcnMiLCJzY3JpcHRzIiwiZm9yY2VGZXRjaCIsImNhY2hlUGF0aCIsImV4cG9ydCIsImluZmlsZSIsImluc3RyIiwib3B0aW9ucyIsIm91dGZpbGUiLCJjb25zdHIiLCJkZWZhdWx0SGVpZ2h0IiwiZGVmYXVsdFdpZHRoIiwiZGVmYXVsdFNjYWxlIiwiaGVpZ2h0Iiwid2lkdGgiLCJzY2FsZSIsImdsb2JhbE9wdGlvbnMiLCJ0aGVtZU9wdGlvbnMiLCJiYXRjaCIsInJhc3Rlcml6YXRpb25UaW1lb3V0IiwiY3VzdG9tTG9naWMiLCJhbGxvd0NvZGVFeGVjdXRpb24iLCJhbGxvd0ZpbGVSZXNvdXJjZXMiLCJjdXN0b21Db2RlIiwiY2FsbGJhY2siLCJyZXNvdXJjZXMiLCJsb2FkQ29uZmlnIiwibGVnYWN5TmFtZSIsImNyZWF0ZUNvbmZpZyIsInNlcnZlciIsImVuYWJsZSIsImNsaU5hbWUiLCJob3N0IiwicG9ydCIsImJlbmNobWFya2luZyIsInNzbCIsImZvcmNlIiwiY2VydFBhdGgiLCJyYXRlTGltaXRpbmciLCJtYXhSZXF1ZXN0cyIsIndpbmRvdyIsImRlbGF5IiwidHJ1c3RQcm94eSIsInNraXBLZXkiLCJza2lwVG9rZW4iLCJwb29sIiwibWluV29ya2VycyIsIm1heFdvcmtlcnMiLCJ3b3JrTGltaXQiLCJhY3F1aXJlVGltZW91dCIsImNyZWF0ZVRpbWVvdXQiLCJkZXN0cm95VGltZW91dCIsImlkbGVUaW1lb3V0IiwiY3JlYXRlUmV0cnlJbnRlcnZhbCIsInJlYXBlckludGVydmFsIiwibGlzdGVuVG9Qcm9jZXNzRXhpdHMiLCJsb2dnaW5nIiwibGV2ZWwiLCJmaWxlIiwiZGVzdCIsInVpIiwicm91dGUiLCJvdGhlciIsIm5vTG9nbyIsInByb21wdHNDb25maWciLCJuYW1lIiwibWVzc2FnZSIsImluaXRpYWwiLCJqb2luIiwic2VwYXJhdG9yIiwiaW5zdHJ1Y3Rpb25zIiwiY2hvaWNlcyIsImhpbnQiLCJtaW4iLCJtYXgiLCJyb3VuZCIsImFic29sdXRlUHJvcHMiLCJuZXN0ZWRBcmdzIiwiY3JlYXRlTmVzdGVkQXJncyIsIm9iaiIsInByb3BDaGFpbiIsIk9iamVjdCIsImtleXMiLCJmb3JFYWNoIiwiayIsImluY2x1ZGVzIiwiZW50cnkiLCJzdWJzdHJpbmciLCJ1bmRlZmluZWQiLCJjb2xvcnMiLCJ0b0NvbnNvbGUiLCJ0b0ZpbGUiLCJwYXRoQ3JlYXRlZCIsImxldmVsc0Rlc2MiLCJ0aXRsZSIsImNvbG9yIiwibGlzdGVuZXJzIiwia2V5Iiwib3B0aW9uIiwiZW50cmllcyIsImxvZ1RvRmlsZSIsInRleHRzIiwicHJlZml4IiwiZXhpc3RzU3luYyIsIm1rZGlyU3luYyIsImFwcGVuZEZpbGUiLCJjb25jYXQiLCJjb25zb2xlIiwibG9nIiwibmV3TGV2ZWwiLCJsZW5ndGgiLCJEYXRlIiwidG9TdHJpbmciLCJzcGxpdCIsInRyaW0iLCJmbiIsImFwcGx5IiwibG9nV2l0aFN0YWNrIiwiY3VzdG9tTWVzc2FnZSIsIm1haW5NZXNzYWdlIiwic3RhY2tNZXNzYWdlIiwic3RhY2siLCJzbGljZSIsInNldExvZ0xldmVsIiwiZW5hYmxlRmlsZUxvZ2dpbmciLCJsb2dEZXN0IiwibG9nRmlsZSIsImVuZHNXaXRoIiwiX19kaXJuYW1lIiwiZmlsZVVSTFRvUGF0aCIsIlVSTCIsImRvY3VtZW50IiwicmVxdWlyZSIsInBhdGhUb0ZpbGVVUkwiLCJfX2ZpbGVuYW1lIiwiaHJlZiIsIl9kb2N1bWVudEN1cnJlbnRTY3JpcHQiLCJzcmMiLCJiYXNlVVJJIiwiZml4VHlwZSIsImZvcm1hdHMiLCJvdXRUeXBlIiwicG9wIiwiZmluZCIsInQiLCJoYW5kbGVSZXNvdXJjZXMiLCJhbGxvd2VkUHJvcHMiLCJoYW5kbGVkUmVzb3VyY2VzIiwiY29ycmVjdFJlc291cmNlcyIsImlzQ29ycmVjdEpTT04iLCJyZWFkRmlsZVN5bmMiLCJmaWxlcyIsInByb3BOYW1lIiwibWFwIiwiaXRlbSIsInBhcnNlZERhdGEiLCJKU09OIiwicGFyc2UiLCJzdHJpbmdpZnkiLCJkZWVwQ29weSIsImNvcHkiLCJBcnJheSIsImlzQXJyYXkiLCJwcm90b3R5cGUiLCJoYXNPd25Qcm9wZXJ0eSIsImNhbGwiLCJvcHRpb25zU3RyaW5naWZ5IiwiYWxsb3dGdW5jdGlvbnMiLCJyZXBsYWNlQWxsIiwicHJpbnRVc2FnZSIsImJvbGQiLCJ5ZWxsb3ciLCJjeWNsZUNhdGVnb3JpZXMiLCJkZXNjTmFtZSIsImdyZWVuIiwiaSIsImJsdWUiLCJjYXRlZ29yeSIsInRvVXBwZXJDYXNlIiwicmVkIiwidG9Cb29sZWFuIiwid3JhcEFyb3VuZCIsInJlcGxhY2UiLCJtZWFzdXJlVGltZSIsInN0YXJ0IiwicHJvY2VzcyIsImhydGltZSIsImJpZ2ludCIsIk51bWJlciIsIkV4cG9ydEVycm9yIiwiRXJyb3IiLCJjb25zdHJ1Y3RvciIsInN1cGVyIiwidGhpcyIsInNldEVycm9yIiwic3RhdHVzQ29kZSIsImNhY2hlIiwiYWN0aXZlTWFuaWZlc3QiLCJzb3VyY2VzIiwiaGNWZXJzaW9uIiwiYXBwbGllZENvbmZpZyIsImV4dHJhY3RWZXJzaW9uIiwiaW5kZXhPZiIsImZldGNoQW5kUHJvY2Vzc1NjcmlwdCIsInNjcmlwdCIsInByb3h5QWdlbnQiLCJmZXRjaGVkTW9kdWxlcyIsInNob3VsZFRocm93RXJyb3IiLCJhZ2VudCIsInRpbWVvdXQiLCJlbnYiLCJyZXNwb25zZSIsInVwZGF0ZUNhY2hlIiwiY29uZmlnIiwic291cmNlUGF0aCIsImN1c3RvbVNjcmlwdHMiLCJwcm94eUhvc3QiLCJwcm94eVBvcnQiLCJIdHRwc1Byb3h5QWdlbnQiLCJtb2R1bGVTY3JpcHRzIiwiYWxsRmV0Y2hQcm9taXNlcyIsImFsbCIsImZldGNoU2NyaXB0cyIsImMiLCJtIiwid3JpdGVGaWxlU3luYyIsImNoZWNrQW5kVXBkYXRlQ2FjaGUiLCJtYW5pZmVzdFBhdGgiLCJyZXF1ZXN0VXBkYXRlIiwibWFuaWZlc3QiLCJtb2R1bGVNYXAiLCJudW1iZXJPZk1vZHVsZXMiLCJzb21lIiwibW9kdWxlTmFtZSIsIm5ld01hbmlmZXN0Iiwic2F2ZUNvbmZpZ1RvTWFuaWZlc3QiLCJnZXRDYWNoZVBhdGgiLCJjYWNoZSQxIiwibmV3VmVyc2lvbiIsImFzc2lnbiIsImdlbmVyYWxPcHRpb25zIiwiZ2V0T3B0aW9ucyIsIm1lcmdlQ29uZmlnT3B0aW9ucyIsIm5ld09wdGlvbnMiLCJtZXJnZWRPcHRpb25zIiwidXBkYXRlRGVmYXVsdENvbmZpZyIsImNvbmZpZ09iaiIsImN1c3RvbU9iaiIsImN1c3RvbVZhbHVlIiwibnVtRW52VmFsIiwiZWwiLCJpbml0T3B0aW9ucyIsIml0ZW1zIiwicmVjdXJzaXZlUHJvcHMiLCJvYmplY3RUb1VwZGF0ZSIsIm5lc3RlZE5hbWVzIiwic2hpZnQiLCJSQU5ET01fUElEIiwicmFuZG9tQnl0ZXMiLCJQVVBQRVRFRVJfRElSIiwicGF0aCIsIm1pbmltYWxBcmdzIiwidGVtcGxhdGUiLCJmcyIsImJyb3dzZXIiLCJzZXRQYWdlQ29udGVudCIsInBhZ2UiLCJzZXRDb250ZW50IiwiYWRkU2NyaXB0VGFnIiwiZXZhbHVhdGUiLCJzZXR1cEhpZ2hjaGFydHMiLCIkZXZhbCIsImVsZW1lbnQiLCJlcnJvck1lc3NhZ2UiLCJfZGlzcGxheUVycm9ycyIsImlubmVySFRNTCIsImNsZWFyUGFnZSIsImhhcmRSZXNldCIsImdvdG8iLCJib2R5IiwibmV3UGFnZSIsInNldENhY2hlRW5hYmxlZCIsImNsb3NlIiwiaXNDb25uZWN0ZWQiLCJfX2Jhc2VkaXIiLCJzZXRBc0NvbmZpZyIsImNoYXJ0IiwidHJpZ2dlckV4cG9ydCIsInB1cHBldGVlckV4cG9ydCIsImluamVjdGVkUmVzb3VyY2VzIiwiY2xlYXJJbmplY3RlZCIsImRpc3Bvc2UiLCJzY3JpcHRzVG9SZW1vdmUiLCJnZXRFbGVtZW50c0J5VGFnTmFtZSIsInN0eWxlc1RvUmVtb3ZlIiwibGlua3NUb1JlbW92ZSIsInJlbW92ZSIsImV4cG9ydE9wdGlvbnMiLCJyZXF1ZXN0QW5pbWF0aW9uRnJhbWUiLCJkaXNwbGF5RXJyb3JzIiwiZGVidWdnZXIiLCJpc1NWRyIsImQiLCJzdmdUZW1wbGF0ZSIsInN0ckluaiIsImpzIiwicHVzaCIsImNvbnRlbnQiLCJpc0xvY2FsIiwiY3NzIiwiY3NzSW1wb3J0cyIsIm1hdGNoIiwiY3NzSW1wb3J0UGF0aCIsImFkZFN0eWxlVGFnIiwic2l6ZSIsImNoYXJ0SGVpZ2h0IiwiYmFzZVZhbCIsImNoYXJ0V2lkdGgiLCJwYXJzZUZsb2F0IiwiSGlnaGNoYXJ0cyIsImNoYXJ0cyIsInZpZXdwb3J0SGVpZ2h0IiwiTWF0aCIsImNlaWwiLCJ2aWV3cG9ydFdpZHRoIiwic2V0Vmlld3BvcnQiLCJkZXZpY2VTY2FsZUZhY3RvciIsInpvb21DYWxsYmFjayIsInN0eWxlIiwiem9vbSIsIm1hcmdpbiIsIngiLCJ5IiwiZ2V0Qm91bmRpbmdDbGllbnRSZWN0IiwidHJ1bmMiLCJnZXRDbGlwUmVnaW9uIiwib3V0ZXJIVE1MIiwiY3JlYXRlU1ZHIiwiZW5jb2RpbmciLCJjbGlwIiwicmFjZSIsInNjcmVlbnNob3QiLCJvbWl0QmFja2dyb3VuZCIsIl9yZXNvbHZlIiwic2V0VGltZW91dCIsImNyZWF0ZUltYWdlIiwicGRmIiwiY3JlYXRlUERGIiwib2xkQ2hhcnRzIiwib2xkQ2hhcnQiLCJkZXN0cm95IiwicHVwcGV0ZWVyQXJncyIsInBlcmZvcm1lZEV4cG9ydHMiLCJleHBvcnRBdHRlbXB0cyIsInRpbWVTcGVudCIsImRyb3BwZWRFeHBvcnRzIiwic3BlbnRBdmVyYWdlIiwicG9vbENvbmZpZyIsImZhY3RvcnkiLCJjcmVhdGUiLCJpZCIsInV1aWQiLCJzdGFydERhdGUiLCJnZXRUaW1lIiwiYnJvd3Nlck5ld1BhZ2UiLCJpc0Nsb3NlZCIsIndvcmtDb3VudCIsInJhbmRvbSIsInZhbGlkYXRlIiwid29ya2VySGFuZGxlIiwiaW5pdFBvb2wiLCJjb2RlIiwia2lsbFBvb2wiLCJleGl0IiwiYWxsQXJncyIsInRyeUNvdW50Iiwib3BlbiIsImxhdW5jaCIsImhlYWRsZXNzIiwidXNlckRhdGFEaXIiLCJjcmVhdGVCcm93c2VyIiwicGFyc2VJbnQiLCJQb29sIiwiYWNxdWlyZVRpbWVvdXRNaWxsaXMiLCJjcmVhdGVUaW1lb3V0TWlsbGlzIiwiZGVzdHJveVRpbWVvdXRNaWxsaXMiLCJpZGxlVGltZW91dE1pbGxpcyIsImNyZWF0ZVJldHJ5SW50ZXJ2YWxNaWxsaXMiLCJyZWFwSW50ZXJ2YWxNaWxsaXMiLCJwcm9wYWdhdGVDcmVhdGVFcnJvciIsInJlc291cmNlIiwiZXZlbnRJZCIsImluaXRpYWxSZXNvdXJjZXMiLCJhY3F1aXJlIiwicHJvbWlzZSIsInJlbGVhc2UiLCJicm93c2VyQ2xvc2UiLCJkZXN0cm95ZWQiLCJwb3N0V29yayIsImdldFBvb2xJbmZvIiwiYWNxdWlyZUNvdW50ZXIiLCJwYXlsb2FkIiwicmVxdWVzdElkIiwid29ya1N0YXJ0IiwiZXhwb3J0Q291bnRlciIsInJlc3VsdCIsImV4cG9ydFRpbWUiLCJudW1GcmVlIiwibnVtVXNlZCIsIm51bVBlbmRpbmdBY3F1aXJlcyIsInBvb2wkMSIsImF2YWlsYWJsZSIsImluVXNlIiwicGVuZGluZ0FjcXVpcmUiLCJzdGFydEV4cG9ydCIsInNldHRpbmdzIiwiZW5kQ2FsbGJhY2siLCJzdmciLCJpbml0RXhwb3J0U2V0dGluZ3MiLCJleHBvcnRBc1N0cmluZyIsImRvU3RyYWlnaHRJbmplY3QiLCJkb0V4cG9ydCIsImZpbmRDaGFydFNpemUiLCJleHBvcnRpbmciLCJwcmVjaXNpb24iLCJtdWx0aXBsaWVyIiwicG93Iiwicm91bmROdW1iZXIiLCJzb3VyY2VIZWlnaHQiLCJzb3VyY2VXaWR0aCIsInBhcmFtIiwiY2hhcnRKc29uIiwiY3VzdG9tTG9naWNPcHRpb25zIiwiYWxsb3dDb2RlRXhlY3V0aW9uU2NvcGVkIiwiZW5hYmxlZCIsIm9wdGlvbnNOYW1lIiwic3RyaW5nVG9FeHBvcnQiLCJjaGFydEpTT04iLCJsb2dFcnJvck1pZGRsZXdhcmUiLCJyZXEiLCJuZXh0IiwiTk9ERV9FTlYiLCJyZXR1cm5FcnJvck1pZGRsZXdhcmUiLCJzdENvZGUiLCJzdGF0dXMiLCJqc29uIiwicmF0ZUxpbWl0IiwiYXBwIiwibGltaXRDb25maWciLCJtc2ciLCJyYXRlT3B0aW9ucyIsImxpbWl0ZXIiLCJ3aW5kb3dNcyIsImRlbGF5TXMiLCJoYW5kbGVyIiwicmVxdWVzdCIsImZvcm1hdCIsInNlbmQiLCJkZWZhdWx0Iiwic2tpcCIsInF1ZXJ5IiwiYWNjZXNzX3Rva2VuIiwidXNlIiwiSHR0cEVycm9yIiwic2V0U3RhdHVzIiwicmV2ZXJzZWRNaW1lIiwicG5nIiwianBlZyIsImdpZiIsInJlcXVlc3RzQ291bnRlciIsImJlZm9yZVJlcXVlc3QiLCJhZnRlclJlcXVlc3QiLCJkb0NhbGxiYWNrcyIsImNhbGxiYWNrcyIsInVuaXF1ZUlkIiwiY2FsbFJlc3BvbnNlIiwiZXhwb3J0SGFuZGxlciIsInN0b3BDb3VudGVyIiwiZGVmYXVsdE9wdGlvbnMiLCJoZWFkZXJzIiwiY29ubmVjdGlvbiIsInJlbW90ZUFkZHJlc3MiLCJjb25uZWN0aW9uQWJvcnRlZCIsInNvY2tldCIsInRvTG93ZXJDYXNlIiwic3Vic3RyIiwiYjY0Iiwibm9Eb3dubG9hZCIsImlwUmVnRXgiLCJpc1ByaXZhdGVSYW5nZVVybEZvdW5kIiwiaW5mbyIsInJlbW92ZUFsbExpc3RlbmVycyIsIkJ1ZmZlciIsImZyb20iLCJoZWFkZXIiLCJhdHRhY2htZW50IiwicGFyYW1zIiwiZmlsZW5hbWUiLCJwa2dGaWxlIiwicGF0aGVyIiwic2VydmVyU3RhcnRUaW1lIiwiZXhwcmVzcyIsImRpc2FibGUiLCJjb3JzIiwic3RvcmFnZSIsIm11bHRlciIsIm1lbW9yeVN0b3JhZ2UiLCJ1cGxvYWQiLCJsaW1pdHMiLCJmaWVsZFNpemUiLCJsaW1pdCIsInVybGVuY29kZWQiLCJleHRlbmRlZCIsIm5vbmUiLCJhdHRhY2hFcnJvckhhbmRsZXJzIiwic3RhcnRTZXJ2ZXIiLCJzZXJ2ZXJDb25maWciLCJodHRwU2VydmVyIiwiY3JlYXRlU2VydmVyIiwibGlzdGVuIiwiY2VydCIsImZzUHJvbWlzZXMiLCJyZWFkRmlsZSIsInBvc2l4IiwiaHR0cHNTZXJ2ZXIiLCJOYU4iLCJzdGF0aWMiLCJib290VGltZSIsInVwdGltZSIsImZsb29yIiwiaGlnaGNoYXJ0c1ZlcnNpb24iLCJhdmVyYWdlUHJvY2Vzc2luZ1RpbWUiLCJmYWlsZWRFeHBvcnRzIiwic3VjZXNzUmF0aW8iLCJoZWFsdGhSb3V0ZSIsInBvc3QiLCJleHBvcnRSb3V0ZXMiLCJzZW5kRmlsZSIsInVpUm91dGUiLCJhZG1pblRva2VuIiwiSElHSENIQVJUU19BRE1JTl9UT0tFTiIsInRva2VuIiwidlN3aXRjaFJvdXRlIiwiZXJyb3JIYW5kbGVyIiwiZW5hYmxlUmF0ZUxpbWl0aW5nIiwiZ2V0RXhwcmVzcyIsImdldEFwcCIsIm1pZGRsZXdhcmVzIiwiZG90ZW52IiwiaW5kZXgiLCJzZXRPcHRpb25zIiwidXNlck9wdGlvbnMiLCJjb25maWdJbmRleCIsImZpbmRJbmRleCIsImFyZyIsImZpbGVOYW1lIiwibG9hZENvbmZpZ0ZpbGUiLCJzaG93VXNhZ2UiLCJwcm9wZXJ0aWVzQ2hhaW4iLCJhcmd1bWVudFR5cGUiLCJyZWR1Y2UiLCJwcm9wIiwicGFpckFyZ3VtZW50VmFsdWUiLCJpbml0RXhwb3J0IiwiaW5pdExvZ2dpbmciLCJzaW5nbGVFeHBvcnQiLCJiYXRjaEV4cG9ydCIsImJhdGNoRnVuY3Rpb25zIiwicGFpciIsIm1hcFRvTmV3Q29uZmlnIiwib2xkT3B0aW9ucyIsIm1hbnVhbENvbmZpZyIsImNvbmZpZ0ZpbGVOYW1lIiwiY29uZmlnRmlsZSIsImNob2ljZSIsInByb21wdHMiLCJvblN1Ym1pdCIsInAiLCJjYXRlZ29yaWVzIiwicXVlc3Rpb25zQ291bnRlciIsImFsbFF1ZXN0aW9ucyIsInNlY3Rpb24iLCJwcm9tcHQiLCJhbnN3ZXIiLCJtb2R1bGUiLCJwcm9taXNlcyIsIndyaXRlRmlsZSIsInByaW50TG9nbyIsInBhY2thZ2VWZXJzaW9uIl0sIm1hcHBpbmdzIjoia3RCQXlCQUEsZUFBZUMsRUFBTUMsRUFBS0MsRUFBaUIsSUFDekMsT0FBTyxJQUFJQyxTQUFRLENBQUNDLEVBQVNDLEtBQzNCLE1BQU1DLEVBYlUsQ0FBQ0wsR0FBU0EsRUFBSU0sV0FBVyxTQUFXQyxFQUFRQyxFQWEzQ0MsQ0FBWVQsR0FFN0JLLEVBQ0dLLElBQUlWLEVBQUtDLEdBQWlCVSxJQUN6QixJQUFJQyxFQUFPLEdBR1hELEVBQUlFLEdBQUcsUUFBU0MsSUFDZEYsR0FBUUUsQ0FBSyxJQUlmSCxFQUFJRSxHQUFHLE9BQU8sS0FDUEQsR0FDSFIsRUFBTyxxQ0FHVE8sRUFBSUksS0FBT0gsRUFDWFQsRUFBUVEsRUFBSSxHQUNaLElBRUhFLEdBQUcsU0FBVUcsSUFDWlosRUFBT1ksRUFBTSxHQUNiLEdBRVIsQ0NwQ08sTUFBTUMsRUFBZ0IsQ0FDM0JDLFVBQVcsQ0FDVEMsS0FBTSxDQUNKQyxNQUFPLEdBQ1BDLEtBQU0sV0FDTkMsWUFBYSwwQ0FHakJDLFdBQVksQ0FDVkMsUUFBUyxDQUNQSixNQUFPLFNBQ1BLLFFBQVMscUJBQ1RKLEtBQU0sU0FDTkMsWUFBYSxzQ0FFZkksT0FBUSxDQUNOTixNQUFPLCtCQUNQSyxRQUFTLHFCQUNUSixLQUFNLFNBQ05DLFlBQWEsa0RBRWZLLFlBQWEsQ0FDWEYsUUFBUywwQkFDVEwsTUFBTyxDQUFDLGFBQWMsa0JBQW1CLGlCQUN6Q0MsS0FBTSxXQUNOQyxZQUFhLHlDQUVmTSxRQUFTLENBQ1BILFFBQVMscUJBQ1RMLE1BQU8sQ0FDTCxRQUNBLE1BQ0EsUUFDQSxZQUNBLGNBQ0EsdUJBQ0EsZ0JBQ0EsdUJBQ0EsZUFDQSxRQUNBLE9BQ0EsYUFDQSxtQkFDQSxlQUNBLGNBQ0EsVUFDQSxVQUNBLGNBQ0EsV0FDQSxVQUNBLFlBQ0EsY0FDQSxZQUNB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 +"use strict";require("colors");var e=require("dotenv"),t=require("fs"),r=require("path"),i=require("https-proxy-agent"),o=require("http"),n=require("https"),a=require("url"),s=require("zod"),l=require("prompts"),c=require("tarn"),p=require("uuid"),u=require("node:path"),h=require("puppeteer"),d=require("node:crypto"),g=require("cors"),m=require("express"),f=require("multer"),y=require("express-rate-limit"),v="undefined"!=typeof document?document.currentScript:null;function b(e){var t=Object.create(null);return e&&Object.keys(e).forEach((function(r){if("default"!==r){var i=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,i.get?i:{enumerable:!0,get:function(){return e[r]}})}})),t.default=e,Object.freeze(t)}var w=b(a);async function E(e,t={}){return new Promise(((r,i)=>{const a=(e=>e.startsWith("https")?n:o)(e);a.get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||i("Nothing was fetched from the URL."),e.text=t,r(e)}))})).on("error",(e=>{i(e)}))}))}const T={puppeteer:{args:{value:[],type:"string[]",description:"Arguments array to send to Puppeteer."}},highcharts:{version:{value:"latest",envLink:"HIGHCHARTS_VERSION",type:"string",description:"The Highcharts version to be used."},cdnURL:{value:"https://code.highcharts.com/",envLink:"HIGHCHARTS_CDN_URL",type:"string",description:"The CDN URL for Highcharts scripts to be used."},coreScripts:{envLink:"HIGHCHARTS_CORE_SCRIPTS",value:["highcharts","highcharts-more","highcharts-3d"],type:"string[]",description:"The core Highcharts scripts to fetch."},modules:{envLink:"HIGHCHARTS_MODULES",value:["stock","map","gantt","exporting","export-data","parallel-coordinates","accessibility","annotations-advanced","boost-canvas","boost","data","data-tools","draggable-points","static-scale","broken-axis","heatmap","tilemap","tiledwebmap","timeline","treemap","treegraph","item-series","drilldown","histogram-bellcurve","bullet","funnel","funnel3d","geoheatmap","pyramid3d","networkgraph","overlapping-datalabels","pareto","pattern-fill","pictorial","price-indicator","sankey","arc-diagram","dependency-wheel","series-label","solid-gauge","sonification","stock-tools","streamgraph","sunburst","variable-pie","variwide","vector","venn","windbarb","wordcloud","xrange","no-data-to-display","drag-panes","debugger","dumbbell","lollipop","cylinder","organization","dotplot","marker-clusters","hollowcandlestick","heikinashi","flowmap"],type:"string[]",description:"The modules of Highcharts to fetch."},indicators:{envLink:"HIGHCHARTS_INDICATORS",value:["indicators-all"],type:"string[]",description:"The indicators of Highcharts to fetch."},scripts:{value:["https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js","https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.34/moment-timezone-with-data.min.js"],type:"string[]",description:"Additional optional scripts or dependencies to fetch."},forceFetch:{envLink:"HIGHCHARTS_FORCE_FETCH",value:!1,type:"boolean",description:"The flag to determine whether to refetch all scripts after each server rerun."},cachePath:{envLink:"HIGHCHARTS_CACHE_PATH",value:".cache",type:"string",description:"The path to the cache directory. It is used to store the Highcharts scripts and custom scripts."}},export:{infile:{value:!1,type:"string",description:"The input file should include a name and a type (json or svg). It must be correctly formatted as a JSON or SVG file."},instr:{value:!1,type:"string",description:"Input, provided in the form of a stringified JSON or SVG file, will override the --infile option."},options:{value:!1,type:"string",description:"An alias for the --instr option."},outfile:{value:!1,type:"string",description:"The output filename along with a type (jpeg, png, pdf, or svg). This will ignore the --type flag."},type:{envLink:"EXPORT_TYPE",value:"png",type:"string",description:"The file export format. It can be jpeg, png, pdf, or svg."},constr:{envLink:"EXPORT_CONSTR",value:"chart",type:"string",description:"The constructor to use. Can be chart, stockChart, mapChart, or ganttChart."},defaultHeight:{envLink:"EXPORT_DEFAULT_HEIGHT",value:400,type:"number",description:"the default height of the exported chart. Used when no value is set."},defaultWidth:{envLink:"EXPORT_DEFAULT_WIDTH",value:600,type:"number",description:"The default width of the exported chart. Used when no value is set."},defaultScale:{envLink:"EXPORT_DEFAULT_SCALE",value:1,type:"number",description:"The default scale of the exported chart. Used when no value is set."},height:{type:"number",value:!1,description:"The height of the exported chart, overriding the option in the chart settings."},width:{type:"number",value:!1,description:"The width of the exported chart, overriding the option in the chart settings."},scale:{value:!1,type:"number",description:"The scale of the exported chart, overriding the option in the chart settings. Ranges between 0.1 and 5.0."},globalOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing options to be passed into the Highcharts.setOptions."},themeOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing theme options to be passed into the Highcharts.setOptions."},batch:{value:!1,type:"string",description:'Initiates a batch job with a string containing input/output pairs: "in=out;in=out;...".'},rasterizationTimeout:{envLink:"EXPORT_RASTERIZATION_TIMEOUT",value:1500,type:"number",description:"The duration in milliseconds to wait for rendering a webpage."}},customLogic:{allowCodeExecution:{envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",value:!1,type:"boolean",description:"Controls whether the execution of arbitrary code is allowed during the exporting process."},allowFileResources:{envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",value:!1,type:"boolean",description:"Controls the ability to inject resources from the filesystem. This setting has no effect when running as a server."},customCode:{value:!1,type:"string",description:"Custom code to execute before chart initialization. It can be a function, code wrapped within a function, or a filename with the .js extension."},callback:{value:!1,type:"string",description:"JavaScript code to run during construction. It can be a function or a filename with the .js extension."},resources:{value:!1,type:"string",description:"Additional resource in the form of a stringified JSON, which may contain files, js, and css sections."},loadConfig:{value:!1,type:"string",legacyName:"fromFile",description:"A file containing a pre-defined configuration to use."},createConfig:{value:!1,type:"string",description:"Enables setting options through a prompt and saving them in a provided config file."}},server:{enable:{envLink:"SERVER_ENABLE",value:!1,type:"boolean",cliName:"enableServer",description:"When set to true, the server starts on the local IP address 0.0.0.0."},host:{envLink:"SERVER_HOST",value:"0.0.0.0",type:"string",description:"The hostname of the server. Additionally, it starts a server on the provided hostname."},port:{envLink:"SERVER_PORT",value:7801,type:"number",description:"The server port when enabled."},benchmarking:{envLink:"SERVER_BENCHMARKING",value:!1,type:"boolean",cliName:"serverBenchmarking",description:"Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request."},ssl:{enable:{envLink:"SERVER_SSL_ENABLE",value:!1,type:"boolean",cliName:"enableSsl",description:"Enables or disables the SSL protocol."},force:{envLink:"SERVER_SSL_FORCE",value:!1,type:"boolean",cliName:"sslForced",legacyName:"sslOnly",description:"When set to true, the server is forced to serve only over HTTPS."},port:{envLink:"SERVER_SSL_PORT",value:443,type:"number",cliName:"sslPort",description:"The port on which to run the SSL server."},certPath:{envLink:"SERVER_SSL_CERT_PATH",value:"",type:"string",legacyName:"sslPath",description:"The path to the SSL certificate/key file."}},rateLimiting:{enable:{envLink:"SERVER_RATE_LIMITING_ENABLE",value:!1,type:"boolean",cliName:"enableRateLimiting",description:"Enables rate limiting for the server."},maxRequests:{envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",value:10,type:"number",legacyName:"rateLimit",description:"The maximum number of requests allowed in one minute."},window:{envLink:"SERVER_RATE_LIMITING_WINDOW",value:1,type:"number",description:"The time window, in minutes, for the rate limiting."},delay:{envLink:"SERVER_RATE_LIMITING_DELAY",value:0,type:"number",description:"The delay duration for each successive request before reaching the maximum limit."},trustProxy:{envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",value:!1,type:"boolean",description:"Set this to true if the server is behind a load balancer."},skipKey:{envLink:"SERVER_RATE_LIMITING_SKIP_KEY",value:"",type:"string",description:"Allows bypassing the rate limiter and should be provided with the skipToken argument."},skipToken:{envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",value:"",type:"string",description:"Allows bypassing the rate limiter and should be provided with the skipKey argument."}}},pool:{minWorkers:{envLink:"POOL_MIN_WORKERS",value:4,type:"number",description:"The number of minimum and initial pool workers to spawn."},maxWorkers:{envLink:"POOL_MAX_WORKERS",value:8,type:"number",legacyName:"workers",description:"The number of maximum pool workers to spawn."},workLimit:{envLink:"POOL_WORK_LIMIT",value:40,type:"number",description:"The number of work pieces that can be performed before restarting the worker process."},acquireTimeout:{envLink:"POOL_ACQUIRE_TIMEOUT",value:5e3,type:"number",description:"The duration, in milliseconds, to wait for acquiring a resource."},createTimeout:{envLink:"POOL_CREATE_TIMEOUT",value:5e3,type:"number",description:"The duration, in milliseconds, to wait for creating a resource."},destroyTimeout:{envLink:"POOL_DESTROY_TIMEOUT",value:5e3,type:"number",description:"The duration, in milliseconds, to wait for destroying a resource."},idleTimeout:{envLink:"POOL_IDLE_TIMEOUT",value:3e4,type:"number",description:"The duration, in milliseconds, after which an idle resource is destroyed."},createRetryInterval:{envLink:"POOL_CREATE_RETRY_INTERVAL",value:200,type:"number",description:"The duration, in milliseconds, to wait before retrying the create process in case of a failure."},reaperInterval:{envLink:"POOL_REAPER_INTERVAL",value:1e3,type:"number",description:"The duration, in milliseconds, after which the check for idle resources to destroy is triggered."},benchmarking:{envLink:"POOL_BENCHMARKING",value:!1,type:"boolean",cliName:"poolBenchmarking",description:"Indicate whether to show statistics for the pool of resources or not."},listenToProcessExits:{envLink:"POOL_LISTEN_TO_PROCESS_EXITS",value:!0,type:"boolean",description:"Decides whether or not to attach process.exit handlers."}},logging:{level:{envLink:"LOGGING_LEVEL",value:4,type:"number",cliName:"logLevel",description:"The logging level to be used."},file:{envLink:"LOGGING_FILE",value:"highcharts-export-server.log",type:"string",cliName:"logFile",description:"The name of a log file. The logDest option also needs to be set to enable file logging."},dest:{envLink:"LOGGING_DEST",value:"log/",type:"string",cliName:"logDest",description:"The path to store log files. This also enables file logging."}},ui:{enable:{envLink:"UI_ENABLE",value:!1,type:"boolean",cliName:"enableUi",description:"Enables or disables the user interface (UI) for the export server."},route:{envLink:"UI_ROUTE",value:"/",type:"string",cliName:"uiRoute",description:"The endpoint route to which the user interface (UI) should be attached."}},other:{noLogo:{envLink:"OTHER_NO_LOGO",value:!1,type:"boolean",description:"Skip printing the logo on a startup. Will be replaced by a simple text."}}},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:"modules",message:"Available modules",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:T.highcharts.modules.value},{type:"list",name:"scripts",message:"Custom scripts",initial:T.highcharts.scripts.value.join(","),separator:","},{type:"toggle",name:"forceFetch",message:"Force re-fetch the scripts",initial:T.highcharts.forceFetch.value},{type:"text",name:"cachePath",message:"The path to the cache directory",initial:T.highcharts.cachePath.value}],export:[{type:"select",name:"type",message:"The default export file type",hint:`Default: ${T.export.type.value}`,initial:0,choices:["png","jpeg","pdf","svg"]},{type:"select",name:"constr",message:"The default constructor for Highcharts",hint:`Default: ${T.export.constr.value}`,initial:0,choices:["chart","stockChart","mapChart","ganttChart"]},{type:"number",name:"defaultHeight",message:"The default fallback height of the exported chart",initial:T.export.defaultHeight.value},{type:"number",name:"defaultWidth",message:"The default fallback width of the exported chart",initial:T.export.defaultWidth.value},{type:"number",name:"defaultScale",message:"The default fallback scale of the exported chart",initial:T.export.defaultScale.value,min:.1,max:5},{type:"number",name:"rasterizationTimeout",message:"The rendering webpage timeout in milliseconds",initial:T.export.rasterizationTimeout.value}],customLogic:[{type:"toggle",name:"allowCodeExecution",message:"Enable execution of custom code",initial:T.customLogic.allowCodeExecution.value},{type:"toggle",name:"allowFileResources",message:"Enable file resources",initial:T.customLogic.allowFileResources.value}],server:[{type:"toggle",name:"enable",message:"Starts the server on 0.0.0.0",initial:T.server.enable.value},{type:"text",name:"host",message:"Server hostname",initial:T.server.host.value},{type:"number",name:"port",message:"Server port",initial:T.server.port.value},{type:"toggle",name:"benchmarking",message:"Enable server benchmarking",initial:T.server.benchmarking.value},{type:"toggle",name:"ssl.enable",message:"Enable SSL protocol",initial:T.server.ssl.enable.value},{type:"toggle",name:"ssl.force",message:"Force serving only over HTTPS",initial:T.server.ssl.force.value},{type:"number",name:"ssl.port",message:"SSL server port",initial:T.server.ssl.port.value},{type:"text",name:"ssl.certPath",message:"The path to find the SSL certificate/key",initial:T.server.ssl.certPath.value},{type:"toggle",name:"rateLimiting.enable",message:"Enable rate limiting",initial:T.server.rateLimiting.enable.value},{type:"number",name:"rateLimiting.maxRequests",message:"The maximum requests allowed per minute",initial:T.server.rateLimiting.maxRequests.value},{type:"number",name:"rateLimiting.window",message:"The rate-limiting time window in minutes",initial:T.server.rateLimiting.window.value},{type:"number",name:"rateLimiting.delay",message:"The delay for each successive request before reaching the maximum",initial:T.server.rateLimiting.delay.value},{type:"toggle",name:"rateLimiting.trustProxy",message:"Set to true if behind a load balancer",initial:T.server.rateLimiting.trustProxy.value},{type:"text",name:"rateLimiting.skipKey",message:"Allows bypassing the rate limiter when provided with the skipToken argument",initial:T.server.rateLimiting.skipKey.value},{type:"text",name:"rateLimiting.skipToken",message:"Allows bypassing the rate limiter when provided with the skipKey argument",initial:T.server.rateLimiting.skipToken.value}],pool:[{type:"number",name:"minWorkers",message:"The initial number of workers to spawn",initial:T.pool.minWorkers.value},{type:"number",name:"maxWorkers",message:"The maximum number of workers to spawn",initial:T.pool.maxWorkers.value},{type:"number",name:"workLimit",message:"The pieces of work that can be performed before restarting a Puppeteer process",initial:T.pool.workLimit.value},{type:"number",name:"acquireTimeout",message:"The number of milliseconds to wait for acquiring a resource",initial:T.pool.acquireTimeout.value},{type:"number",name:"createTimeout",message:"The number of milliseconds to wait for creating a resource",initial:T.pool.createTimeout.value},{type:"number",name:"destroyTimeout",message:"The number of milliseconds to wait for destroying a resource",initial:T.pool.destroyTimeout.value},{type:"number",name:"idleTimeout",message:"The number of milliseconds after an idle resource is destroyed",initial:T.pool.idleTimeout.value},{type:"number",name:"createRetryInterval",message:"The retry interval in milliseconds after a create process fails",initial:T.pool.createRetryInterval.value},{type:"number",name:"reaperInterval",message:"The reaper interval in milliseconds after triggering the check for idle resources to destroy",initial:T.pool.reaperInterval.value},{type:"toggle",name:"benchmarking",message:"Enable benchmarking for a resource pool",initial:T.pool.benchmarking.value},{type:"toggle",name:"listenToProcessExits",message:"Set to false to skip attaching process.exit handlers",initial:T.pool.listenToProcessExits.value}],logging:[{type:"number",name:"level",message:"The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)",initial:T.logging.level.value,round:0,min:0,max:5},{type:"text",name:"file",message:"A log file name. Set with the --logDest to enable file logging",initial:T.logging.file.value},{type:"text",name:"dest",message:"The path to log files. Enables file logging",initial:T.logging.dest.value}],ui:[{type:"toggle",name:"enable",message:"Enable UI for the export server",initial:T.ui.enable.value},{type:"text",name:"route",message:"A route to attach the UI",initial:T.ui.route.value}],other:[{type:"toggle",name:"noLogo",message:"Skip printing the logo on startup. Replaced by simple text",initial:T.other.noLogo.value}]},R=["options","globalOptions","themeOptions","resources","payload"],x={},L=(e,t="")=>{Object.keys(e).forEach((r=>{if(!["puppeteer","highcharts"].includes(r)){const i=e[r];void 0===i.value?L(i,`${t}.${r}`):(x[i.cliName||r]=`${t}.${r}`.substring(1),void 0!==i.legacyName&&(x[i.legacyName]=`${t}.${r}`.substring(1)))}}))};L(T);const k=["red","yellow","blue","gray","green"];let O={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:k[0]},{title:"warning",color:k[1]},{title:"notice",color:k[2]},{title:"verbose",color:k[3]},{title:"benchmark",color:k[4]}],listeners:[]};for(const[e,t]of Object.entries(T.logging))O[e]=t.value;const _=(e,r)=>{O.toFile&&(O.pathCreated||(!t.existsSync(O.dest)&&t.mkdirSync(O.dest),O.pathCreated=!0),t.appendFile(`${O.dest}${O.file}`,[r].concat(e).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),O.toFile=!1)})))},I=(...e)=>{const[t,...r]=e,{level:i,levelsDesc:o}=O;if(5!==t&&(0===t||t>i||i>o.length))return;const n=`${(new Date).toString().split("(")[0].trim()} [${o[t-1].title}] -`;O.listeners.forEach((e=>{e(n,r.join(" "))})),O.toConsole&&console.log.apply(void 0,[n.toString()[O.levelsDesc[t-1].color]].concat(r)),_(r,n)},C=(e,t,r)=>{const i=r||t.message,{level:o,levelsDesc:n}=O;if(0===e||e>o||o>n.length)return;const a=`${(new Date).toString().split("(")[0].trim()} [${n[e-1].title}] -`,s=t.message!==t.stackMessage||void 0===t.stackMessage?t.stack:t.stack.split("\n").slice(1).join("\n"),l=[i,"\n",s];O.toConsole&&console.log.apply(void 0,[a.toString()[O.levelsDesc[e-1].color]].concat([i[k[e-1]],"\n",s])),O.listeners.forEach((e=>{e(a,l.join(" "))})),_(l,a)},A=e=>{e>=0&&e<=O.levelsDesc.length&&(O.level=e)},N=(e,t)=>{if(O={...O,dest:e||O.dest,file:t||O.file,toFile:!0},0===O.dest.length)return I(1,"[logger] File logging initialization: no path supplied.");O.dest.endsWith("/")||(O.dest+="/")},P=a.fileURLToPath(new URL("../.","undefined"==typeof document?require("url").pathToFileURL(__filename).href:v&&v.src||new URL("index.cjs",document.baseURI).href)),H=(e,t)=>{const r=["png","jpeg","pdf","svg"];if(t){const i=t.split(".").pop();"jpg"===i?e="jpeg":r.includes(i)&&e!==i&&(e=i)}return{"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"}[e]||r.find((t=>t===e))||"png"},$=(e=!1,r)=>{const i=["js","css","files"];let o=e,n=!1;if(r&&e.endsWith(".json"))try{o=j(t.readFileSync(e,"utf8"))}catch(e){return C(2,e,"[cli] No resources found.")}else o=j(e),o&&!r&&delete o.files;for(const e in o)i.includes(e)?n||(n=!0):delete o[e];return n?(o.files&&(o.files=o.files.map((e=>e.trim())),(!o.files||o.files.length<=0)&&delete o.files),o):I(3,"[cli] No resources found.")};function 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 U=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]=U(e[r]));return t},F=(e,t)=>JSON.stringify(e,((e,r)=>("string"==typeof r&&((r=r.trim()).startsWith("function(")||r.startsWith("function ("))&&r.endsWith("}")&&(r=t?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:void 0),"function"==typeof r?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:r))).replaceAll(/"EXP_FUN|EXP_FUN"/g,"");function M(){console.log("\nUsage of CLI arguments:".bold,"\n------",`\nFor more detailed information, visit the readme at: ${"https://github.com/highcharts/node-export-server#readme".bold.yellow}.`);const e=t=>{for(const[r,i]of Object.entries(t))if(Object.prototype.hasOwnProperty.call(i,"value")){let e=` --${i.cliName||r} ${("<"+i.type+">").green} `;if(e.length<48)for(let t=e.length;t<48;t++)e+=".";console.log(e,i.description,`[Default: ${i.value.toString().bold}]`.blue)}else e(i)};Object.keys(T).forEach((t=>{["puppeteer","highcharts"].includes(t)||(console.log(`\n${t.toUpperCase()}`.red),e(T[t]))})),console.log("\n")}const G=e=>!["false","undefined","null","NaN","0",""].includes(e)&&!!e,q=(e,r)=>{if(e&&"string"==typeof e)return(e=e.trim()).endsWith(".js")?!!r&&q(t.readFileSync(e,"utf8")):e.startsWith("function()")||e.startsWith("function ()")||e.startsWith("()=>")||e.startsWith("() =>")?`(${e})()`:e.replace(/;$/,"")},D=()=>{const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6};e.config();const W=()=>s.z.enum(["true","false"]).transform((e=>"true"===e)).optional(),V=()=>s.z.string().transform((e=>e.split(",").map((e=>e.trim())))).optional(),z=s.z.object({HIGHCHARTS_VERSION:s.z.string().refine((e=>/^(latest|\d+(\.\d+){0,2})$/.test(e)),{message:"HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ"}).optional(),HIGHCHARTS_CDN_URL:s.z.string().trim().refine((e=>e.startsWith("https://")||e.startsWith("http://")),{message:"Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://."}).optional(),HIGHCHARTS_CORE_SCRIPTS:V(),HIGHCHARTS_MODULES:V(),HIGHCHARTS_INDICATORS:V(),HIGHCHARTS_FORCE_FETCH:W(),HIGHCHARTS_CACHE_PATH:s.z.string().optional(),HIGHCHARTS_ADMIN_TOKEN:s.z.string().optional(),EXPORT_TYPE:s.z.enum(["jpeg","png","pdf","svg"]).optional(),EXPORT_CONSTR:s.z.string().refine((e=>["chart","stockChart","mapChart","ganttChart"].includes(e||"")),{message:"Invalid value for EXPORT_CONSTR. "}).optional(),EXPORT_DEFAULT_HEIGHT:s.z.coerce.number().positive().optional(),EXPORT_DEFAULT_WIDTH:s.z.coerce.number().positive().optional(),EXPORT_DEFAULT_SCALE:s.z.coerce.number().positive().optional(),EXPORT_RASTERIZATION_TIMEOUT:s.z.coerce.number().positive().optional(),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:W(),CUSTOM_LOGIC_ALLOW_FILEL_RESOURCES:W(),SERVER_ENABLE:W(),SERVER_HOST:s.z.string().optional(),SERVER_PORT:s.z.coerce.number().optional(),SERVER_BENCHMARKING:W(),SERVER_SSL_ENABLE:W(),SERVER_SSL_FORCE:W(),SERVER_SSL_PORT:s.z.coerce.number().optional(),SERVER_SSL_CERT_PATH:s.z.string().optional(),SERVER_RATE_LIMITING_ENABLE:W(),SERVER_RATE_LIMITING_MAX_REQUESTS:s.z.coerce.number().optional(),SERVER_RATE_LIMITING_WINDOW:s.z.coerce.number().optional(),SERVER_RATE_LIMITING_DELAY:s.z.coerce.number().optional(),SERVER_RATE_LIMITING_TRUST_PROXY:W(),SERVER_RATE_LIMITING_SKIP_KEY:s.z.string().optional(),SERVER_RATE_LIMITING_SKIP_TOKEN:s.z.string().optional(),POOL_MIN_WORKERS:s.z.coerce.number().optional(),POOL_MAX_WORKERS:s.z.coerce.number().optional(),POOL_WORK_LIMIT:s.z.coerce.number().optional(),POOL_ACQUIRE_TIMEOUT:s.z.coerce.number().optional(),POOL_CREATE_TIMEOUT:s.z.coerce.number().optional(),POOL_DESTROY_TIMEOUT:s.z.coerce.number().optional(),POOL_IDLE_TIMEOUT:s.z.coerce.number().optional(),POOL_CREATE_RETRY_INTERVAL:s.z.coerce.number().optional(),POOL_REAPER_INTERVAL:s.z.coerce.number().optional(),POOL_BENCHMARKING:W(),POOL_LISTEN_TO_PROCESS_EXITS:W(),LOGGING_LEVEL:s.z.coerce.number().optional().refine((e=>(e||4)>=0&&(e||4)<=4),{message:"Invalid value for LOGGING_LEVEL. We only accept 0, 1, 2, 3, 4 as logging levels."}),LOGGING_FILE:s.z.string().optional(),LOGGING_DEST:s.z.string().optional(),UI_ENABLE:W(),UI_ROUTE:s.z.string().optional(),OTHER_NO_LOGO:W(),NODE_ENV:s.z.enum(["development","production","test"]).optional().default("production"),PROXY_SERVER_TIMEOUT:s.z.coerce.number().positive().optional().default(5e3),PROXY_SERVER_HOST:s.z.string().optional().default("localhost"),PROXY_SERVER_PORT:s.z.coerce.number().positive().optional().default(8080)}).parse(process.env);class X extends Error{constructor(e){super(),this.message=e,this.stackMessage=e}setError(e){return this.error=e,e.name&&(this.name=e.name),e.statusCode&&(this.statusCode=e.statusCode),e.stack&&(this.stackMessage=e.message,this.stack=e.stack),this}}const K={cdnURL:"https://code.highcharts.com/",activeManifest:{},sources:"",hcVersion:""};let J=!1;const B=e=>e.sources.substring(0,e.sources.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim(),Y=async(e,t,r,i=!1)=>{e.endsWith(".js")&&(e=e.substring(0,e.length-3)),I(4,`[cache] Fetching script - ${e}.js`);const o=t?{agent:t,timeout:z.PROXY_SERVER_TIMEOUT}:{},n=await E(`${e}.js`,o);if(200===n.statusCode&&"string"==typeof n.text){if(r){r[e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")]=1}return n.text}if(i)throw new X(`Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${n.statusCode}).`).setError(n);return I(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`),""},Q=async(e,r)=>{const{coreScripts:o,modules:n,indicators:a,scripts:s}=e,l="latest"!==e.version&&e.version?`${e.version}/`:"";let c;I(3,`[cache] Updating cache version to Highcharts: ${l||"latest"}.`);const p=process.env.PROXY_SERVER_HOST,u=process.env.PROXY_SERVER_PORT;if(p&&u)try{c=new i.HttpsProxyAgent({host:p,port:+u})}catch(e){throw new X("[cache] Could not create a Proxy Agent.").setError(e)}const h={};try{return K.sources=await(async(e,t,r,i,o,n)=>{const a=[...e.map((e=>Y(`${i}${e}`,o,n,!0))),...t.map((e=>Y(`${i}${e}`,o,n))),...r.map((e=>Y(`${e}`,o)))];return(await Promise.all(a)).join(";\n")})([...o.map((e=>`${l}${e}`))],[...n.map((e=>"map"===e?`maps/${l}modules/${e}`:`${l}modules/${e}`)),...a.map((e=>`stock/${l}indicators/${e}`))],s,e.cdnURL||K.cdnURL,c,h),K.hcVersion=B(K),t.writeFileSync(r,K.sources),h}catch(e){throw new X("[cache] Unable to update the local Highcharts cache.").setError(e)}},Z=async e=>{const i=r.join(P,e.cachePath);let o;const n=r.join(i,"manifest.json"),a=r.join(i,"sources.js");if(J=e,!t.existsSync(i)&&t.mkdirSync(i),!t.existsSync(n)||e.forceFetch)I(3,"[cache] Fetching and caching Highcharts dependencies."),o=await Q(e,a);else{let r=!1;const i=JSON.parse(t.readFileSync(n));if(i.modules&&Array.isArray(i.modules)){const e={};i.modules.forEach((t=>e[t]=1)),i.modules=e}const{modules:s,coreScripts:l,indicators:c}=e,p=s.length+l.length+c.length;i.version!==e.version?(I(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),r=!0):Object.keys(i.modules||{}).length!==p?(I(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),r=!0):r=(e.modules||[]).some((e=>{if(!i.modules[e])return I(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),r?o=await Q(e,a):(I(3,"[cache] Dependency cache is up to date, proceeding."),K.sources=t.readFileSync(a,"utf8"),o=i.modules,K.hcVersion=B(K))}await(async(e,i)=>{const o={version:e.version,modules:i||{}};K.activeManifest=o,I(3,"[cache] Writing a new manifest.");try{t.writeFileSync(r.join(P,e.cachePath,"manifest.json"),JSON.stringify(o),"utf8")}catch(e){throw new X("[cache] Error writing the cache manifest.").setError(e)}})(e,o)},ee=()=>r.join(P,J.cachePath);var te=async e=>!!J&&await Z(Object.assign(J,{version:e})),re=()=>K,ie=()=>K.hcVersion;let oe={};const ne=()=>oe,ae=(e,t,r=[])=>{const i=U(e);for(const[e,n]of Object.entries(t))i[e]="object"!=typeof(o=n)||Array.isArray(o)||null===o||r.includes(e)||void 0===i[e]?void 0!==n?n:i[e]:ae(i[e],n,r);var o;return i};function se(e,t={},r=""){Object.keys(e).forEach((i=>{const o=e[i],n=t&&t[i];void 0===o.value?se(o,n,`${r}.${i}`):(void 0!==n&&(o.value=n),o.envLink in z&&(o.value=z[o.envLink]))}))}function le(e){let t={};for(const[r,i]of Object.entries(e))t[r]=Object.prototype.hasOwnProperty.call(i,"value")?i.value:le(i);return t}function ce(e,t,r){for(;t.length>1;){const i=t.shift();return Object.prototype.hasOwnProperty.call(e,i)||(e[i]={}),e[i]=ce(Object.assign({},e[i]),t,r),e}return e[t[0]]=r,e}const pe=d.randomBytes(64).toString("base64url"),ue=u.join("tmp",`puppeteer-${pe}`),he=[`--user-data-dir=${u.join(ue,"profile")}`,"--autoplay-policy=user-gesture-required","--disable-background-networking","--disable-background-timer-throttling","--disable-backgrounding-occluded-windows","--disable-breakpad","--disable-client-side-phishing-detection","--disable-component-update","--disable-default-apps","--disable-dev-shm-usage","--disable-domain-reliability","--disable-extensions","--disable-features=AudioServiceOutOfProcess","--disable-hang-monitor","--disable-ipc-flooding-protection","--disable-notifications","--disable-offer-store-unmasked-wallet-cards","--disable-popup-blocking","--disable-print-preview","--disable-prompt-on-repost","--disable-renderer-backgrounding","--disable-session-crashed-bubble","--disable-setuid-sandbox","--disable-speech-api","--disable-sync","--hide-crash-restore-bubble","--hide-scrollbars","--ignore-gpu-blacklist","--metrics-recording-only","--mute-audio","--no-default-browser-check","--no-first-run","--no-pings","--no-sandbox","--no-zygote","--password-store=basic","--use-mock-keychain"],de=w.fileURLToPath(new URL(".","undefined"==typeof document?require("url").pathToFileURL(__filename).href:v&&v.src||new URL("index.cjs",document.baseURI).href)),ge=t.readFileSync(de+"/../templates/template.html","utf8");let me;const fe=async e=>{await e.setContent(ge),await e.addScriptTag({path:`${ee()}/sources.js`}),await e.evaluate((()=>window.setupHighcharts())),e.on("pageerror",(async t=>{await e.$eval("#container",((e,t)=>{window._displayErrors&&(e.innerHTML=t)}),`

Chart input data error

${t.toString()}`)}))},ye=async(e,t=!1)=>{try{t?(await e.goto("about:blank"),await fe(e)):await e.evaluate((()=>{document.body.innerHTML='
'}))}catch(e){C(2,e,"[browser] Could not clear the content of the page.")}},ve=async()=>{if(!me)return!1;const e=await me.newPage();return await e.setCacheEnabled(!1),await fe(e),e},be=async()=>(me?.isConnected()&&(await me.close(),I(4,"[browser] Closed the browser.")),!0);const we=w.fileURLToPath(new URL(".","undefined"==typeof document?require("url").pathToFileURL(__filename).href:v&&v.src||new URL("index.cjs",document.baseURI).href)),Ee=(e,t,r)=>e.evaluate(((e,t)=>window.triggerExport(e,t)),t,r);var Te=async(e,i,o)=>{const n=[],a=async e=>{for(const e of n)await e.dispose();await e.evaluate((()=>{const[,...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...r]=document.getElementsByTagName("link");for(const i of[...e,...t,...r])i.remove()}))};try{I(4,"[export] Determining export path.");const s=o.export;await e.evaluate((()=>requestAnimationFrame((()=>{}))));const l=s?.options?.chart?.displayErrors&&re().activeManifest.modules.debugger;let c;if(await e.evaluate((e=>window._displayErrors=e),l),i.indexOf&&(i.indexOf("=0||i.indexOf("=0)){if(I(4,"[export] Treating as SVG."),"svg"===s.type)return i;c=!0,await e.setContent((e=>`\n\n\n \n \n Highcarts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`)(i))}else I(4,"[export] Treating as config."),s.strInj?await Ee(e,{chart:{height:s.height,width:s.width}},o):(i.chart.height=s.height,i.chart.width=s.width,await Ee(e,i,o));const p=o.customLogic.resources;if(p){if(p.js&&n.push(await e.addScriptTag({content:p.js})),p.files)for(const r of p.files)try{const i=!r.startsWith("http");n.push(await e.addScriptTag(i?{content:t.readFileSync(r,"utf8")}:{url:r}))}catch(e){C(2,e,`[export] The JS file ${r} cannot be loaded.`)}if(p.css){let t=p.css.match(/@import\s*([^;]*);/g);if(t)for(let i of t)i&&(i=i.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),i.startsWith("http")?n.push(await e.addStyleTag({url:i})):o.customLogic.allowFileResources&&n.push(await e.addStyleTag({path:r.join(we,i)})));n.push(await e.addStyleTag({content:p.css.replace(/@import\s*([^;]*);/g,"")||" "}))}}const u=c?await e.$eval("#chart-container svg:first-of-type",((e,t)=>({chartHeight:e.height.baseVal.value*t,chartWidth:e.width.baseVal.value*t})),parseFloat(s.scale)):await e.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return{chartHeight:e,chartWidth:t}})),h=Math.ceil(u?.chartHeight||s.height),d=Math.ceil(u?.chartWidth||s.width);await e.setViewport({height:h,width:d,deviceScaleFactor:c?1:parseFloat(s.scale)});const g=c?e=>{document.body.style.zoom=e,document.body.style.margin="0px"}:()=>{document.body.style.zoom=1};await e.evaluate(g,parseFloat(s.scale));const{height:m,width:f,x:y,y:v}=await(e=>e.$eval("#chart-container",(e=>{const{x:t,y:r,width:i,height:o}=e.getBoundingClientRect();return{x:t,y:r,width:i,height:Math.trunc(o>1?o:500)}})))(e);let b;if(c||await e.setViewport({width:Math.round(f),height:Math.round(m),deviceScaleFactor:parseFloat(s.scale)}),"svg"===s.type)b=await(e=>e.$eval("#container svg:first-of-type",(e=>e.outerHTML)))(e);else if(["png","jpeg"].includes(s.type))b=await((e,t,r,i,o)=>Promise.race([e.screenshot({type:t,encoding:r,clip:i,omitBackground:"png"==t}),new Promise(((e,t)=>setTimeout((()=>t(new X("Rasterization timeout"))),o||1500)))]))(e,s.type,"base64",{width:d,height:h,x:y,y:v},s.rasterizationTimeout);else{if("pdf"!==s.type)throw new X(`[export] Unsupported output format ${s.type}.`);b=await((e,t,r,i)=>e.pdf({height:t+1,width:r,encoding:i}))(e,h,d,"base64")}return await e.evaluate((()=>{if("undefined"!=typeof Highcharts){const e=Highcharts.charts;if(Array.isArray(e)&&e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()}})),await a(e),b}catch(t){return await a(e),t}};let Se,Re=0,xe=0,Le=0,ke=0,Oe=0,_e={},Ie=!1;const Ce={create:async()=>{let e=!1;const t=p.v4(),r=(new Date).getTime();try{if(e=await ve(),!e||e.isClosed())throw new X("The page is invalid or closed.");I(3,`[pool] Successfully created a worker ${t} - took ${(new Date).getTime()-r} ms.`)}catch(e){throw new X("Error encountered when creating a new page.").setError(e)}return{id:t,page:e,workCount:Math.round(Math.random()*(_e.workLimit/2))}},validate:async e=>_e.workLimit&&++e.workCount>_e.workLimit?(I(3,`[pool] Worker failed validation: exceeded work limit (limit is ${_e.workLimit}).`),!1):(await ye(e.page,!0),!0),destroy:e=>{I(3,`[pool] Destroying pool entry ${e.id}.`),e.page&&e.page.close()}},Ae=async e=>{if(_e=e&&e.pool?{...e.pool}:{},_e.listenToProcessExits&&(I(3,"[pool] Attaching exit listeners to the process."),process.on("exit",(async e=>{I(4,`Process exited with code ${e}.`),await Ne()})),process.on("SIGINT",((e,t)=>{I(4,`The ${e} event with code: ${t}.`),process.exit(1)})),process.on("SIGTERM",((e,t)=>{I(4,`The ${e} event with code: ${t}.`),process.exit(1)})),process.on("uncaughtException",(async(e,t)=>{C(1,e,`The ${t} error.`),await Ne(),process.exit(1)}))),Se=e.puppeteerArgs,await(async e=>{const t=[...he,...e||[]];if(!me){let e=0;const r=async()=>{try{I(3,`[browser] Attempting to get a browser instance (try ${++e}).`),me=await h.launch({headless:"new",args:t,userDataDir:"./tmp/"})}catch(t){if(C(1,t,"[browser] Failed to launch a browser instance."),!(e<25))throw t;I(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await r()}};try{await r()}catch(e){throw new X("[browser] Maximum retries to open a browser instance reached.").setError(e)}if(!me)throw new X("[browser] Cannot find a browser to open.")}return me})(Se),I(3,`[pool] Initializing pool with workers: min ${_e.minWorkers}, max ${_e.maxWorkers}.`),Ie)return I(4,"[pool] Already initialized, please kill it before creating a new one.");parseInt(_e.minWorkers)>parseInt(_e.maxWorkers)&&(_e.minWorkers=_e.maxWorkers);try{Ie=new c.Pool({...Ce,min:parseInt(_e.minWorkers),max:parseInt(_e.maxWorkers),acquireTimeoutMillis:_e.acquireTimeout,createTimeoutMillis:_e.createTimeout,destroyTimeoutMillis:_e.destroyTimeout,idleTimeoutMillis:_e.idleTimeout,createRetryIntervalMillis:_e.createRetryInterval,reapIntervalMillis:_e.reaperInterval,propagateCreateError:!1}),Ie.on("release",(async e=>{await ye(e.page,!1),I(4,`[pool] Releasing a worker with ID ${e.id}.`)})),Ie.on("destroySuccess",((e,t)=>{I(4,`[pool] Destroyed a worker with ID ${t.id}.`)}));const e=[];for(let t=0;t<_e.minWorkers;t++)try{const t=await Ie.acquire().promise;e.push(t)}catch(e){C(2,e,"[pool] Could not create an initial resource.")}e.forEach((e=>{Ie.release(e)})),I(3,"[pool] The pool is ready"+(e.length?` with ${e.length} initial resources waiting.`:"."))}catch(e){throw await be(),new X("[pool] Could not create the pool of workers.").setError(e)}};async function Ne(){return I(3,"[pool] Killing all pool workers and browser, if any exist."),Ie?.destroyed||Ie&&(await Ie.destroy(),I(4,"[browser] Destroyed the pool of resources.")),be()}const Pe=async(e,t)=>{let r;try{if(I(4,"[pool] Work received, starting to process."),++xe,_e.benchmarking&&He(),!Ie)throw new X("Work received, but pool has not been started.");try{I(4,"[pool] Acquiring a worker handle.");const e=D();r=await Ie.acquire().promise,t.server.benchmarking&&I(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Acquired a worker handle: ${e()}ms.`)}catch(e){throw new X("Error encountered when acquiring an available entry.").setError(e)}if(I(4,"[pool] Acquired a worker handle."),!r.page)throw new X("Resolved worker page is invalid: the pool setup is wonky.");let i=(new Date).getTime();I(4,`[pool] Starting work on pool entry with ID ${r.id}.`);const o=D(),n=await Te(r.page,e,t);if(n instanceof Error)throw"Rasterization timeout"===n.message&&(r.page.close(),r.page=await ve()),new X("Error encountered during export.").setError(n);t.server.benchmarking&&I(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Exported a chart sucessfully: ${o()}ms.`),Ie.release(r);const a=(new Date).getTime()-i;return Le+=a,Oe=Le/++Re,I(4,`[pool] Work completed in ${a} ms.`),{result:n,options:t}}catch(e){throw++ke,r&&Ie.release(r),new X(`[pool] In pool.postWork: ${e.message}`).setError(e)}};function He(){const{min:e,max:t}=Ie;I(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),I(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),I(5,`[pool] The number of resources that are currently available: ${Ie.numFree()}.`),I(5,`[pool] The number of resources that are currently acquired: ${Ie.numUsed()}.`),I(5,`[pool] The number of callers waiting to acquire a resource: ${Ie.numPendingAcquires()}.`)}var $e=()=>({min:Ie.min,max:Ie.max,available:Ie.numFree(),inUse:Ie.numUsed(),pendingAcquire:Ie.numPendingAcquires()}),je=()=>xe,Ue=()=>ke,Fe=()=>Oe,Me=()=>Re;let Ge=!1;const qe=async(e,r)=>{I(4,"[chart] Starting the exporting process.");const i=((e,t={})=>{let r={};return e.svg?(r=U(t),r.export.type=e.type||e.export.type,r.export.scale=e.scale||e.export.scale,r.export.outfile=e.outfile||e.export.outfile,r.payload={svg:e.svg}):r=ae(t,e,R),r.export.outfile=r.export?.outfile||`chart.${r.export?.type||"png"}`,r})(e,ne()),o=i.export;if(i.payload?.svg&&""!==i.payload.svg)try{return I(4,"[chart] Attempting to export from a SVG input."),ze(i.payload.svg.trim(),i,r)}catch(e){return r(new X("[chart] Error loading SVG input.").setError(e))}if(o.infile&&o.infile.length)try{return I(4,"[chart] Attempting to export from an input file."),i.export.instr=t.readFileSync(o.infile,"utf8"),ze(i.export.instr.trim(),i,r)}catch(e){return r(new X("[chart] Error loading input file.").setError(e))}if(o.instr&&""!==o.instr||o.options&&""!==o.options)try{return I(4,"[chart] Attempting to export from a raw input."),G(i.customLogic?.allowCodeExecution)?Ve(i,r):"string"==typeof o.instr?ze(o.instr.trim(),i,r):We(i,o.instr||o.options,r)}catch(e){return r(new X("[chart] Error loading raw input.").setError(e))}return r(new X("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'."))},De=e=>{const{chart:t,exporting:r}=e.export?.options||j(e.export?.instr),i=j(e.export?.globalOptions);let o=e.export?.scale||r?.scale||i?.exporting?.scale||e.export?.defaultScale||1;o=Math.max(.1,Math.min(o,5)),o=((e,t=1)=>{const r=Math.pow(10,t||0);return Math.round(+e*r)/r})(o,2);const n={height:e.export?.height||r?.sourceHeight||t?.height||i?.exporting?.sourceHeight||i?.chart?.height||e.export?.defaultHeight||400,width:e.export?.width||r?.sourceWidth||t?.width||i?.exporting?.sourceWidth||i?.chart?.width||e.export?.defaultWidth||600,scale:o};for(let[e,t]of Object.entries(n))n[e]="string"==typeof t?+t.replace(/px|%/gi,""):t;return n},We=async(e,r,i,o)=>{let{export:n,customLogic:a}=e;const s="boolean"==typeof a.allowCodeExecution?a.allowCodeExecution:Ge;if(a){if(s)if("string"==typeof e.customLogic.resources)e.customLogic.resources=$(e.customLogic.resources,G(e.customLogic.allowFileResources));else if(!e.customLogic.resources)try{const r=t.readFileSync("resources.json","utf8");e.customLogic.resources=$(r,G(e.customLogic.allowFileResources))}catch(e){C(2,e,"[chart] Unable to load the default resources.json file.")}}else a=e.customLogic={};if(!s&&a){if(a.callback||a.resources||a.customCode)return i(new X("[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server."));a.callback=!1,a.resources=!1,a.customCode=!1}if(r&&(r.chart=r.chart||{},r.exporting=r.exporting||{},r.exporting.enabled=!1),n.constr=n.constr||"chart",n.type=H(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(t.readFileSync(n[e],"utf8"),!0):n[e]=j(n[e],!0))}catch(t){n[e]={},C(2,t,`[chart] The '${e}' cannot be loaded.`)}})),a.allowCodeExecution)try{a.customCode=q(a.customCode,a.allowFileResources)}catch(e){C(2,e,"[chart] The 'customCode' cannot be loaded.")}if(a&&a.callback&&a.callback?.indexOf("{")<0)if(a.allowFileResources)try{a.callback=t.readFileSync(a.callback,"utf8")}catch(e){a.callback=!1,C(2,e,"[chart] The 'callback' cannot be loaded.")}else a.callback=!1;e.export={...e.export,...De(e)};try{return i(!1,await Pe(n.strInj||r||o,e))}catch(e){return i(e)}},Ve=(e,t)=>{try{let r,i=e.export.instr||e.export.options;return"string"!=typeof i&&(r=i=F(i,e.customLogic?.allowCodeExecution)),r=i.replaceAll(/\t|\n|\r/g,"").trim(),";"===r[r.length-1]&&(r=r.substring(0,r.length-1)),e.export.strInj=r,We(e,!1,t)}catch(r){return t(new X(`[chart] Malformed input detected for ${e.export?.requestId||"?"}. Please make sure that your JSON/JavaScript options are sent using the "options" attribute, and that if you're using SVG, it is unescaped.`).setError(r))}},ze=(e,t,r)=>{const{allowCodeExecution:i}=t.customLogic;if(e.indexOf("=0||e.indexOf("=0)return I(4,"[chart] Parsing input as SVG."),We(t,!1,r,e);try{const i=JSON.parse(e.replaceAll(/\t|\n|\r/g," "));return We(t,i,r)}catch(e){return G(i)?Ve(t,r):r(new X("[chart] Only JSON configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the --allowCodeExecution flag.").setError(e))}},Xe=(e,t,r,i)=>{C(1,e),"development"!==z.NODE_ENV&&delete e.stack,i(e)},Ke=(e,t,r,i)=>{const{statusCode:o,status:n,message:a,stack:s}=e,l=o||n||500;r.status(l).json({statusCode:l,message:a,stack:s})};var Je=(e,t)=>{const r="Too many requests, you have been rate limited. Please try again later.",i={max:t.maxRequests||30,window:t.window||1,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||!1,skipToken:t.skipToken||!1};i.trustProxy&&e.enable("trust proxy");const o=y({windowMs:60*i.window*1e3,max:i.max,delayMs:i.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:r})},default:()=>{t.status(429).send(r)}})},skip:e=>!1!==i.skipKey&&!1!==i.skipToken&&e.query.key===i.skipKey&&e.query.access_token===i.skipToken&&(I(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(o),I(3,`[rate limiting] Enabled rate limiting with ${i.max} requests per ${i.window} minute for each IP, trusting proxy: ${i.trustProxy}.`)};class Be extends X{constructor(e,t){super(e),this.status=this.statusCode=t}setStatus(e){return this.status=e,this}}const Ye={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};let Qe=0;const Ze=[],et=[],tt=(e,t,r,i)=>{let o=!0;const{id:n,uniqueId:a,type:s,body:l}=i;return e.some((e=>{if(e){let i=e(t,r,n,a,s,l);return void 0!==i&&!0!==i&&(o=i),!0}})),o},rt=async(e,t,r)=>{try{const r=D(),o=p.v4().replace(/-/g,""),n=ne(),a=e.body,s=++Qe;let l=H(a.type);if(!a||"object"==typeof(i=a)&&!Array.isArray(i)&&null!==i&&0===Object.keys(i).length)throw new Be("The request body is required. Please ensure that your Content-Type header is correct (accepted types are application/json and multipart/form-data).",400);let c=j(a.infile||a.options||a.data);if(!c&&!a.svg)throw I(2,`The request with ID ${o} from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Payload received: ${JSON.stringify(a)}.`),new Be("No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.",400);let u=!1;if(u=tt(Ze,e,t,{id:s,uniqueId:o,type:l,body:a}),!0!==u)return t.send(u);let h=!1;e.socket.on("close",(()=>{h=!0})),I(4,`[export] Got an incoming HTTP request with ID ${o}.`),a.constr="string"==typeof a.constr&&a.constr||"chart";const d={export:{instr:c,type:l,constr:a.constr[0].toLowerCase()+a.constr.substr(1),height:a.height,width:a.width,scale:a.scale||n.export.scale,globalOptions:j(a.globalOptions,!0),themeOptions:j(a.themeOptions,!0)},customLogic:{allowCodeExecution:Ge,allowFileResources:!1,resources:j(a.resources,!0),callback:a.callback,customCode:a.customCode}};c&&(d.export.instr=F(c,d.customLogic.allowCodeExecution));const g=ae(n,d);if(g.export.options=c,g.payload={svg:a.svg||!1,b64:a.b64||!1,noDownload:a.noDownload||!1,requestId:o},a.svg&&(e=>[/xlink:href="(?:http:\/\/|https:\/\/)?localhost\b/,/xlink:href="(?:http:\/\/|https:\/\/)?10\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?127\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?192\.168\.\d{1,3}\.\d{1,3}\b/].some((t=>t.test(e))))(g.payload.svg))throw new Be("SVG potentially contain at least one forbidden URL in xlink:href element. Please review the SVG content and ensure that all referenced URLs comply with security policies.",400);await qe(g,((i,c)=>{if(e.socket.removeAllListeners("close"),n.server.benchmarking&&I(5,`[benchmark] Request with ID ${o} - After the whole exporting process: ${r()}ms.`),h)return I(3,"[export] The client closed the connection before the chart finished processing.");if(i)throw i;if(!c||!c.result)throw new Be(`Unexpected return from chart generation. Please check your request data. For the request with ID ${o}, the result is ${c.result}.`,400);return l=c.options.export.type,tt(et,e,t,{id:s,body:c.result}),c.result?a.b64?"pdf"===l||"svg"==l?t.send(Buffer.from(c.result,"utf8").toString("base64")):t.send(c.result):(t.header("Content-Type",Ye[l]||"image/png"),a.noDownload||t.attachment(`${e.params.filename||e.body.filename||"chart"}.${l||"png"}`),"svg"===l?t.send(c.result):t.send(Buffer.from(c.result,"base64"))):void 0}))}catch(e){r(e)}var i};const it=JSON.parse(t.readFileSync(r.join(P,"package.json"))),ot=new Date;const nt=m();nt.disable("x-powered-by"),nt.use(g());const at=f.memoryStorage(),st=f({storage:at,limits:{fieldSize:52428800}});nt.use(m.json({limit:52428800})),nt.use(m.urlencoded({extended:!0,limit:52428800})),nt.use(st.none());const lt=e=>{e.on("clientError",(e=>{C(1,e,`[server] Client error: ${e.message}`)})),e.on("error",(e=>{C(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{C(1,e,`[server] Socket error: ${e.message}`)}))}))},ct=async e=>{try{if(!e.enable)return!1;if(!e.ssl.force){const t=o.createServer(nt);lt(t),t.listen(e.port,e.host),I(3,`[server] Started HTTP server on ${e.host}:${e.port}.`)}if(e.ssl.enable){let i,o;try{i=await t.promises.readFile(r.posix.join(e.ssl.certPath,"server.key"),"utf8"),o=await t.promises.readFile(r.posix.join(e.ssl.certPath,"server.crt"),"utf8")}catch(t){I(2,`[server] Unable to load key/certificate from the '${e.ssl.certPath}' path. Could not run secured layer server.`)}if(i&&o){const t=n.createServer({key:i,cert:o},nt);lt(t),t.listen(e.ssl.port,e.host),I(3,`[server] Started HTTPS server on ${e.host}:${e.ssl.port}.`)}}e.rateLimiting&&e.rateLimiting.enable&&![0,NaN].includes(e.rateLimiting.maxRequests)&&Je(nt,e.rateLimiting),nt.use(m.static(r.posix.join(P,"public"))),(e=>{!!e&&e.get("/health",((e,t)=>{t.send({status:"OK",bootTime:ot,uptime:Math.floor(((new Date).getTime()-ot.getTime())/1e3/60)+" minutes",version:it.version,highchartsVersion:ie(),averageProcessingTime:Fe(),performedExports:Me(),failedExports:Ue(),exportAttempts:je(),sucessRatio:Me()/je()*100,pool:$e()})}))})(nt),(e=>{e.post("/",rt),e.post("/:filename",rt)})(nt),(e=>{!!e&&e.get("/",((e,t)=>{t.sendFile(r.join(P,"public","index.html"))}))})(nt),(e=>{!!e&&e.post("/version/change/:newVersion",(async(e,t,r)=>{try{const r=z.HIGHCHARTS_ADMIN_TOKEN;if(!r||!r.length)throw new Be("The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.",401);const i=e.get("hc-auth");if(!i||i!==r)throw new Be("Invalid or missing token: Set the token in the hc-auth header.",401);const o=e.params.newVersion;if(!o)throw new Be("No new version supplied.",400);try{await te(o)}catch(e){throw new Be(`Version change: ${e.message}`,e.statusCode).setError(e)}t.status(200).send({statusCode:200,version:ie(),message:`Successfully updated Highcharts to version: ${o}.`})}catch(e){r(e)}}))})(nt),(e=>{e.use(Xe),e.use(Ke)})(nt)}catch(e){throw new X("[server] Could not configure and start the server.").setError(e)}};var pt={startServer:ct,enableRateLimiting:e=>Je(nt,e),getExpress:()=>m,getApp:()=>nt,use:(e,...t)=>{nt.use(e,...t)},get:(e,...t)=>{nt.get(e,...t)},post:(e,...t)=>{nt.post(e,...t)}};e.config();var ut={server:pt,startServer:ct,setOptions:(e,r)=>(r?.length&&(oe=function(e){const r=e.findIndex((e=>"loadConfig"===e.replace(/-/g,"")));if(r>-1&&e[r+1]){const i=e[r+1];try{if(i&&i.endsWith(".json"))return JSON.parse(t.readFileSync(i))}catch(e){C(2,e,`[config] Unable to load the configuration from the ${i} file.`)}}return{}}(r)),se(T,oe),oe=le(T),e&&(oe=ae(oe,e,R)),r?.length&&(oe=function(e,t,r){let i=!1;for(let o=0;o(a.length-1===r&&(s=e[t].type),e[t])),r),a.reduce(((e,r,l)=>(a.length-1===l&&void 0!==e[r]&&(t[++o]?"boolean"===s?e[r]=G(t[o]):"number"===s?e[r]=+t[o]:s.indexOf("]")>=0?e[r]=t[o].split(","):e[r]=t[o]:(I(2,`[config] Missing value for the '${n}' argument. Using the default value.`),i=!0)),e[r])),e)}i&&M();return e}(oe,r,T)),oe),initExport:async e=>{var t;return t=e.customLogic&&e.customLogic.allowCodeExecution,Ge=G(t),(e=>{A(e&&parseInt(e.level)),e&&e.dest&&N(e.dest,e.file||"highcharts-export-server.log")})(e.logging),await Z(e.highcharts||{version:"latest"}),await Ae({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 qe(e,(async(e,r)=>{if(e)throw e;const{outfile:i,type:o}=r.options.export;t.writeFileSync(i||`chart.${o}`,"svg"!==o?Buffer.from(r.result,"base64"):r.result),await Ne()}))},batchExport:async e=>{const r=[];for(let i of e.export.batch.split(";"))i=i.split("="),2===i.length&&r.push(qe({...e,export:{...e.export,infile:i[0],outfile:i[1]}},((e,r)=>{if(e)throw e;t.writeFileSync(r.options.export.outfile,Buffer.from(r.result,"base64"))})));try{await Promise.all(r),await Ne()}catch(e){throw new X("[chart] Error encountered during batch export.").setError(e)}},startExport:qe,killPool:Ne,log:I,logWithStack:C,setLogLevel:A,enableFileLogging:N,mapToNewConfig:e=>{const t={};for(const[r,i]of Object.entries(e)){const e=x[r]?x[r].split("."):[];e.reduce(((t,r,o)=>t[r]=e.length-1===o?i:t[r]||{}),t)}return t},manualConfig:async e=>{let r={};t.existsSync(e)&&(r=JSON.parse(t.readFileSync(e,"utf8")));const i=Object.keys(S).map((e=>({title:`${e} options`,value:e})));return l({type:"multiselect",name:"category",message:"Which category do you want to configure?",hint:"Space: Select specific, A: Select all, Enter: Confirm.",instructions:"",choices:i},{onSubmit:async(i,o)=>{let n=0,a=[];for(const e of o)S[e]=S[e].map((t=>({...t,section:e}))),a=[...a,...S[e]];return await l(a,{onSubmit:async(i,o)=>{if("modules"===i.name?(o=o.length?o.map((e=>i.choices[e])):i.choices,r[i.section][i.name]=o):r[i.section]=ce(Object.assign({},r[i.section]||{}),i.name.split("."),i.choices?i.choices[o]:o),++n===a.length){try{await t.promises.writeFile(e,JSON.stringify(r,null,2),"utf8")}catch(t){C(1,t,`[config] An error occurred while creating the ${e} file.`)}return!0}}}),!0}})},printLogo:e=>{const i=JSON.parse(t.readFileSync(r.join(P,"package.json"))).version;e?console.log(`Starting Highcharts Export Server v${i}...`):console.log(t.readFileSync(P+"/msg/startup.msg").toString().bold.yellow,`v${i}`)},printUsage:M};module.exports=ut; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguY2pzIiwic291cmNlcyI6WyIuLi9saWIvZmV0Y2guanMiLCIuLi9saWIvc2NoZW1hcy9jb25maWcuanMiLCIuLi9saWIvbG9nZ2VyLmpzIiwiLi4vbGliL3V0aWxzLmpzIiwiLi4vbGliL2VudnMuanMiLCIuLi9saWIvZXJyb3JzL0V4cG9ydEVycm9yLmpzIiwiLi4vbGliL2NhY2hlLmpzIiwiLi4vbGliL2NvbmZpZy5qcyIsIi4uL2xpYi9icm93c2VyLmpzIiwiLi4vbGliL2V4cG9ydC5qcyIsIi4uL3RlbXBsYXRlcy9zdmdfZXhwb3J0L3N2Z19leHBvcnQuanMiLCIuLi9saWIvcG9vbC5qcyIsIi4uL2xpYi9jaGFydC5qcyIsIi4uL2xpYi9zZXJ2ZXIvZXJyb3IuanMiLCIuLi9saWIvc2VydmVyL3JhdGVfbGltaXQuanMiLCIuLi9saWIvZXJyb3JzL0h0dHBFcnJvci5qcyIsIi4uL2xpYi9zZXJ2ZXIvcm91dGVzL2V4cG9ydC5qcyIsIi4uL2xpYi9zZXJ2ZXIvcm91dGVzL2hlYWx0aC5qcyIsIi4uL2xpYi9zZXJ2ZXIvc2VydmVyLmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvdWkuanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy9jaGFuZ2VfaGNfdmVyc2lvbi5qcyIsIi4uL2xpYi9pbmRleC5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKipcclxuICogVGhpcyBtb2R1bGUgZXhwb3J0cyB0d28gZnVuY3Rpb25zOiBmZXRjaCAoZm9yIEdFVCByZXF1ZXN0cykgYW5kIHBvc3QgKGZvciBQT1NUIHJlcXVlc3RzKS5cclxuICovXHJcblxyXG5pbXBvcnQgaHR0cCBmcm9tICdodHRwJztcclxuaW1wb3J0IGh0dHBzIGZyb20gJ2h0dHBzJztcclxuXHJcbi8qKlxyXG4gKiBSZXR1cm5zIHRoZSBIVFRQIG9yIEhUVFBTIHByb3RvY29sIG1vZHVsZSBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgVVJMLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdXJsIC0gVGhlIFVSTCB0byBkZXRlcm1pbmUgdGhlIHByb3RvY29sLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgSFRUUCBvciBIVFRQUyBwcm90b2NvbCBtb2R1bGUgKGh0dHAgb3IgaHR0cHMpLlxyXG4gKi9cclxuY29uc3QgZ2V0UHJvdG9jb2wgPSAodXJsKSA9PiAodXJsLnN0YXJ0c1dpdGgoJ2h0dHBzJykgPyBodHRwcyA6IGh0dHApO1xyXG5cclxuLyoqXHJcbiAqIEZldGNoZXMgZGF0YSBmcm9tIHRoZSBzcGVjaWZpZWQgVVJMIHVzaW5nIGVpdGhlciBIVFRQIG9yIEhUVFBTIHByb3RvY29sLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdXJsIC0gVGhlIFVSTCB0byBmZXRjaCBkYXRhIGZyb20uXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSByZXF1ZXN0T3B0aW9ucyAtIE9wdGlvbnMgZm9yIHRoZSBIVFRQIHJlcXVlc3QgKG9wdGlvbmFsKS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIEhUVFAgcmVzcG9uc2Ugb2JqZWN0XHJcbiAqIHdpdGggYWRkZWQgJ3RleHQnIHByb3BlcnR5IG9yIHJlamVjdGluZyB3aXRoIGFuIGVycm9yLlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gZmV0Y2godXJsLCByZXF1ZXN0T3B0aW9ucyA9IHt9KSB7XHJcbiAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcclxuICAgIGNvbnN0IHByb3RvY29sID0gZ2V0UHJvdG9jb2wodXJsKTtcclxuXHJcbiAgICBwcm90b2NvbFxyXG4gICAgICAuZ2V0KHVybCwgcmVxdWVzdE9wdGlvbnMsIChyZXMpID0+IHtcclxuICAgICAgICBsZXQgZGF0YSA9ICcnO1xyXG5cclxuICAgICAgICAvLyBBIGNodW5rIG9mIGRhdGEgaGFzIGJlZW4gcmVjZWl2ZWQuXHJcbiAgICAgICAgcmVzLm9uKCdkYXRhJywgKGNodW5rKSA9PiB7XHJcbiAgICAgICAgICBkYXRhICs9IGNodW5rO1xyXG4gICAgICAgIH0pO1xyXG5cclxuICAgICAgICAvLyBUaGUgd2hvbGUgcmVzcG9uc2UgaGFzIGJlZW4gcmVjZWl2ZWQuXHJcbiAgICAgICAgcmVzLm9uKCdlbmQnLCAoKSA9PiB7XHJcbiAgICAgICAgICBpZiAoIWRhdGEpIHtcclxuICAgICAgICAgICAgcmVqZWN0KCdOb3RoaW5nIHdhcyBmZXRjaGVkIGZyb20gdGhlIFVSTC4nKTtcclxuICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICByZXMudGV4dCA9IGRhdGE7XHJcbiAgICAgICAgICByZXNvbHZlKHJlcyk7XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH0pXHJcbiAgICAgIC5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcclxuICAgICAgICByZWplY3QoZXJyb3IpO1xyXG4gICAgICB9KTtcclxuICB9KTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFNlbmRzIGEgUE9TVCByZXF1ZXN0IHRvIHRoZSBzcGVjaWZpZWQgVVJMIHdpdGggdGhlIHByb3ZpZGVkIEpTT04gYm9keSB1c2luZ1xyXG4gKiBlaXRoZXIgSFRUUCBvciBIVFRQUyBwcm90b2NvbC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHVybCAtIFRoZSBVUkwgdG8gc2VuZCB0aGUgUE9TVCByZXF1ZXN0IHRvLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gYm9keSAtIFRoZSBKU09OIGJvZHkgdG8gaW5jbHVkZSBpbiB0aGUgUE9TVCByZXF1ZXN0XHJcbiAqIChvcHRpb25hbCwgZGVmYXVsdCBpcyBhbiBlbXB0eSBvYmplY3QpLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcmVxdWVzdE9wdGlvbnMgLSBPcHRpb25zIGZvciB0aGUgSFRUUCByZXF1ZXN0IChvcHRpb25hbCkuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBIVFRQIHJlc3BvbnNlIG9iamVjdCB3aXRoXHJcbiAqIGFkZGVkICd0ZXh0JyBwcm9wZXJ0eSBvciByZWplY3Rpbmcgd2l0aCBhbiBlcnJvci5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIHBvc3QodXJsLCBib2R5ID0ge30sIHJlcXVlc3RPcHRpb25zID0ge30pIHtcclxuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xyXG4gICAgY29uc3QgcHJvdG9jb2wgPSBnZXRQcm90b2NvbCh1cmwpO1xyXG4gICAgY29uc3QgZGF0YSA9IEpTT04uc3RyaW5naWZ5KGJvZHkpO1xyXG5cclxuICAgIC8vIFNldCBkZWZhdWx0IGhlYWRlcnMgYW5kIG1lcmdlIHdpdGggcmVxdWVzdE9wdGlvbnNcclxuICAgIGNvbnN0IG9wdGlvbnMgPSBPYmplY3QuYXNzaWduKFxyXG4gICAgICB7XHJcbiAgICAgICAgbWV0aG9kOiAnUE9TVCcsXHJcbiAgICAgICAgaGVhZGVyczoge1xyXG4gICAgICAgICAgJ0NvbnRlbnQtVHlwZSc6ICdhcHBsaWNhdGlvbi9qc29uJyxcclxuICAgICAgICAgICdDb250ZW50LUxlbmd0aCc6IGRhdGEubGVuZ3RoXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICByZXF1ZXN0T3B0aW9uc1xyXG4gICAgKTtcclxuXHJcbiAgICBjb25zdCByZXEgPSBwcm90b2NvbFxyXG4gICAgICAucmVxdWVzdCh1cmwsIG9wdGlvbnMsIChyZXMpID0+IHtcclxuICAgICAgICBsZXQgcmVzcG9uc2VEYXRhID0gJyc7XHJcblxyXG4gICAgICAgIC8vIEEgY2h1bmsgb2YgZGF0YSBoYXMgYmVlbiByZWNlaXZlZC5cclxuICAgICAgICByZXMub24oJ2RhdGEnLCAoY2h1bmspID0+IHtcclxuICAgICAgICAgIHJlc3BvbnNlRGF0YSArPSBjaHVuaztcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgLy8gVGhlIHdob2xlIHJlc3BvbnNlIGhhcyBiZWVuIHJlY2VpdmVkLlxyXG4gICAgICAgIHJlcy5vbignZW5kJywgKCkgPT4ge1xyXG4gICAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgcmVzLnRleHQgPSByZXNwb25zZURhdGE7XHJcbiAgICAgICAgICAgIHJlc29sdmUocmVzKTtcclxuICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICAgIHJlamVjdChlcnJvcik7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH0pXHJcbiAgICAgIC5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcclxuICAgICAgICByZWplY3QoZXJyb3IpO1xyXG4gICAgICB9KTtcclxuXHJcbiAgICAvLyBXcml0ZSB0aGUgcmVxdWVzdCBib2R5IGFuZCBlbmQgdGhlIHJlcXVlc3QuXHJcbiAgICByZXEud3JpdGUoZGF0YSk7XHJcbiAgICByZXEuZW5kKCk7XHJcbiAgfSk7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IGZldGNoO1xyXG5leHBvcnQgeyBmZXRjaCwgcG9zdCB9O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8vIFRoaXMgaXMgdGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IHdpdGggYWxsIG9wdGlvbnMgYW5kIHRoZWlyIGRlZmF1bHQgdmFsdWVzLFxyXG4vLyBhbHNvIGZyb20gdGhlIC5lbnYgZmlsZSBpZiBvbmUgZXhpc3RzXHJcbmV4cG9ydCBjb25zdCBkZWZhdWx0Q29uZmlnID0ge1xyXG4gIHB1cHBldGVlcjoge1xyXG4gICAgYXJnczoge1xyXG4gICAgICB2YWx1ZTogW10sXHJcbiAgICAgIHR5cGU6ICdzdHJpbmdbXScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnQXJndW1lbnRzIGFycmF5IHRvIHNlbmQgdG8gUHVwcGV0ZWVyLidcclxuICAgIH1cclxuICB9LFxyXG4gIGhpZ2hjaGFydHM6IHtcclxuICAgIHZlcnNpb246IHtcclxuICAgICAgdmFsdWU6ICdsYXRlc3QnLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19WRVJTSU9OJyxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIEhpZ2hjaGFydHMgdmVyc2lvbiB0byBiZSB1c2VkLidcclxuICAgIH0sXHJcbiAgICBjZG5VUkw6IHtcclxuICAgICAgdmFsdWU6ICdodHRwczovL2NvZGUuaGlnaGNoYXJ0cy5jb20vJyxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ0ROX1VSTCcsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBDRE4gVVJMIGZvciBIaWdoY2hhcnRzIHNjcmlwdHMgdG8gYmUgdXNlZC4nXHJcbiAgICB9LFxyXG4gICAgY29yZVNjcmlwdHM6IHtcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ09SRV9TQ1JJUFRTJyxcclxuICAgICAgdmFsdWU6IFsnaGlnaGNoYXJ0cycsICdoaWdoY2hhcnRzLW1vcmUnLCAnaGlnaGNoYXJ0cy0zZCddLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBjb3JlIEhpZ2hjaGFydHMgc2NyaXB0cyB0byBmZXRjaC4nXHJcbiAgICB9LFxyXG4gICAgbW9kdWxlczoge1xyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19NT0RVTEVTJyxcclxuICAgICAgdmFsdWU6IFtcclxuICAgICAgICAnc3RvY2snLFxyXG4gICAgICAgICdtYXAnLFxyXG4gICAgICAgICdnYW50dCcsXHJcbiAgICAgICAgJ2V4cG9ydGluZycsXHJcbiAgICAgICAgJ2V4cG9ydC1kYXRhJyxcclxuICAgICAgICAncGFyYWxsZWwtY29vcmRpbmF0ZXMnLFxyXG4gICAgICAgICdhY2Nlc3NpYmlsaXR5JyxcclxuICAgICAgICAnYW5ub3RhdGlvbnMtYWR2YW5jZWQnLFxyXG4gICAgICAgICdib29zdC1jYW52YXMnLFxyXG4gICAgICAgICdib29zdCcsXHJcbiAgICAgICAgJ2RhdGEnLFxyXG4gICAgICAgICdkYXRhLXRvb2xzJyxcclxuICAgICAgICAnZHJhZ2dhYmxlLXBvaW50cycsXHJcbiAgICAgICAgJ3N0YXRpYy1zY2FsZScsXHJcbiAgICAgICAgJ2Jyb2tlbi1heGlzJyxcclxuICAgICAgICAnaGVhdG1hcCcsXHJcbiAgICAgICAgJ3RpbGVtYXAnLFxyXG4gICAgICAgICd0aWxlZHdlYm1hcCcsXHJcbiAgICAgICAgJ3RpbWVsaW5lJyxcclxuICAgICAgICAndHJlZW1hcCcsXHJcbiAgICAgICAgJ3RyZWVncmFwaCcsXHJcbiAgICAgICAgJ2l0ZW0tc2VyaWVzJyxcclxuICAgICAgICAnZHJpbGxkb3duJyxcclxuICAgICAgICAnaGlzdG9ncmFtLWJlbGxjdXJ2ZScsXHJcbiAgICAgICAgJ2J1bGxldCcsXHJcbiAgICAgICAgJ2Z1bm5lbCcsXHJcbiAgICAgICAgJ2Z1bm5lbDNkJyxcclxuICAgICAgICAnZ2VvaGVhdG1hcCcsXHJcbiAgICAgICAgJ3B5cmFtaWQzZCcsXHJcbiAgICAgICAgJ25ldHdvcmtncmFwaCcsXHJcbiAgICAgICAgJ292ZXJsYXBwaW5nLWRhdGFsYWJlbHMnLFxyXG4gICAgICAgICdwYXJldG8nLFxyXG4gICAgICAgICdwYXR0ZXJuLWZpbGwnLFxyXG4gICAgICAgICdwaWN0b3JpYWwnLFxyXG4gICAgICAgICdwcmljZS1pbmRpY2F0b3InLFxyXG4gICAgICAgICdzYW5rZXknLFxyXG4gICAgICAgICdhcmMtZGlhZ3JhbScsXHJcbiAgICAgICAgJ2RlcGVuZGVuY3ktd2hlZWwnLFxyXG4gICAgICAgICdzZXJpZXMtbGFiZWwnLFxyXG4gICAgICAgICdzb2xpZC1nYXVnZScsXHJcbiAgICAgICAgJ3NvbmlmaWNhdGlvbicsXHJcbiAgICAgICAgJ3N0b2NrLXRvb2xzJyxcclxuICAgICAgICAnc3RyZWFtZ3JhcGgnLFxyXG4gICAgICAgICdzdW5idXJzdCcsXHJcbiAgICAgICAgJ3ZhcmlhYmxlLXBpZScsXHJcbiAgICAgICAgJ3Zhcml3aWRlJyxcclxuICAgICAgICAndmVjdG9yJyxcclxuICAgICAgICAndmVubicsXHJcbiAgICAgICAgJ3dpbmRiYXJiJyxcclxuICAgICAgICAnd29yZGNsb3VkJyxcclxuICAgICAgICAneHJhbmdlJyxcclxuICAgICAgICAnbm8tZGF0YS10by1kaXNwbGF5JyxcclxuICAgICAgICAnZHJhZy1wYW5lcycsXHJcbiAgICAgICAgJ2RlYnVnZ2VyJyxcclxuICAgICAgICAnZHVtYmJlbGwnLFxyXG4gICAgICAgICdsb2xsaXBvcCcsXHJcbiAgICAgICAgJ2N5bGluZGVyJyxcclxuICAgICAgICAnb3JnYW5pemF0aW9uJyxcclxuICAgICAgICAnZG90cGxvdCcsXHJcbiAgICAgICAgJ21hcmtlci1jbHVzdGVycycsXHJcbiAgICAgICAgJ2hvbGxvd2NhbmRsZXN0aWNrJyxcclxuICAgICAgICAnaGVpa2luYXNoaScsXHJcbiAgICAgICAgJ2Zsb3dtYXAnXHJcbiAgICAgIF0sXHJcbiAgICAgIHR5cGU6ICdzdHJpbmdbXScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIG1vZHVsZXMgb2YgSGlnaGNoYXJ0cyB0byBmZXRjaC4nXHJcbiAgICB9LFxyXG4gICAgaW5kaWNhdG9yczoge1xyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19JTkRJQ0FUT1JTJyxcclxuICAgICAgdmFsdWU6IFsnaW5kaWNhdG9ycy1hbGwnXSxcclxuICAgICAgdHlwZTogJ3N0cmluZ1tdJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgaW5kaWNhdG9ycyBvZiBIaWdoY2hhcnRzIHRvIGZldGNoLidcclxuICAgIH0sXHJcbiAgICBzY3JpcHRzOiB7XHJcbiAgICAgIHZhbHVlOiBbXHJcbiAgICAgICAgJ2h0dHBzOi8vY2RuanMuY2xvdWRmbGFyZS5jb20vYWpheC9saWJzL21vbWVudC5qcy8yLjI5LjQvbW9tZW50Lm1pbi5qcycsXHJcbiAgICAgICAgJ2h0dHBzOi8vY2RuanMuY2xvdWRmbGFyZS5jb20vYWpheC9saWJzL21vbWVudC10aW1lem9uZS8wLjUuMzQvbW9tZW50LXRpbWV6b25lLXdpdGgtZGF0YS5taW4uanMnXHJcbiAgICAgIF0sXHJcbiAgICAgIHR5cGU6ICdzdHJpbmdbXScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnQWRkaXRpb25hbCBvcHRpb25hbCBzY3JpcHRzIG9yIGRlcGVuZGVuY2llcyB0byBmZXRjaC4nXHJcbiAgICB9LFxyXG4gICAgZm9yY2VGZXRjaDoge1xyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19GT1JDRV9GRVRDSCcsXHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGZsYWcgdG8gZGV0ZXJtaW5lIHdoZXRoZXIgdG8gcmVmZXRjaCBhbGwgc2NyaXB0cyBhZnRlciBlYWNoIHNlcnZlciByZXJ1bi4nXHJcbiAgICB9LFxyXG4gICAgY2FjaGVQYXRoOiB7XHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0NBQ0hFX1BBVEgnLFxyXG4gICAgICB2YWx1ZTogJy5jYWNoZScsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIHBhdGggdG8gdGhlIGNhY2hlIGRpcmVjdG9yeS4gSXQgaXMgdXNlZCB0byBzdG9yZSB0aGUgSGlnaGNoYXJ0cyBzY3JpcHRzIGFuZCBjdXN0b20gc2NyaXB0cy4nXHJcbiAgICB9XHJcbiAgfSxcclxuICBleHBvcnQ6IHtcclxuICAgIGluZmlsZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGlucHV0IGZpbGUgc2hvdWxkIGluY2x1ZGUgYSBuYW1lIGFuZCBhIHR5cGUgKGpzb24gb3Igc3ZnKS4gSXQgbXVzdCBiZSBjb3JyZWN0bHkgZm9ybWF0dGVkIGFzIGEgSlNPTiBvciBTVkcgZmlsZS4nXHJcbiAgICB9LFxyXG4gICAgaW5zdHI6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0lucHV0LCBwcm92aWRlZCBpbiB0aGUgZm9ybSBvZiBhIHN0cmluZ2lmaWVkIEpTT04gb3IgU1ZHIGZpbGUsIHdpbGwgb3ZlcnJpZGUgdGhlIC0taW5maWxlIG9wdGlvbi4nXHJcbiAgICB9LFxyXG4gICAgb3B0aW9uczoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0FuIGFsaWFzIGZvciB0aGUgLS1pbnN0ciBvcHRpb24uJ1xyXG4gICAgfSxcclxuICAgIG91dGZpbGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBvdXRwdXQgZmlsZW5hbWUgYWxvbmcgd2l0aCBhIHR5cGUgKGpwZWcsIHBuZywgcGRmLCBvciBzdmcpLiBUaGlzIHdpbGwgaWdub3JlIHRoZSAtLXR5cGUgZmxhZy4nXHJcbiAgICB9LFxyXG4gICAgdHlwZToge1xyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX1RZUEUnLFxyXG4gICAgICB2YWx1ZTogJ3BuZycsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBmaWxlIGV4cG9ydCBmb3JtYXQuIEl0IGNhbiBiZSBqcGVnLCBwbmcsIHBkZiwgb3Igc3ZnLidcclxuICAgIH0sXHJcbiAgICBjb25zdHI6IHtcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9DT05TVFInLFxyXG4gICAgICB2YWx1ZTogJ2NoYXJ0JyxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgY29uc3RydWN0b3IgdG8gdXNlLiBDYW4gYmUgY2hhcnQsIHN0b2NrQ2hhcnQsIG1hcENoYXJ0LCBvciBnYW50dENoYXJ0LidcclxuICAgIH0sXHJcbiAgICBkZWZhdWx0SGVpZ2h0OiB7XHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9IRUlHSFQnLFxyXG4gICAgICB2YWx1ZTogNDAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ3RoZSBkZWZhdWx0IGhlaWdodCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQuIFVzZWQgd2hlbiBubyB2YWx1ZSBpcyBzZXQuJ1xyXG4gICAgfSxcclxuICAgIGRlZmF1bHRXaWR0aDoge1xyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0RFRkFVTFRfV0lEVEgnLFxyXG4gICAgICB2YWx1ZTogNjAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkZWZhdWx0IHdpZHRoIG9mIHRoZSBleHBvcnRlZCBjaGFydC4gVXNlZCB3aGVuIG5vIHZhbHVlIGlzIHNldC4nXHJcbiAgICB9LFxyXG4gICAgZGVmYXVsdFNjYWxlOiB7XHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9TQ0FMRScsXHJcbiAgICAgIHZhbHVlOiAxLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkZWZhdWx0IHNjYWxlIG9mIHRoZSBleHBvcnRlZCBjaGFydC4gVXNlZCB3aGVuIG5vIHZhbHVlIGlzIHNldC4nXHJcbiAgICB9LFxyXG4gICAgaGVpZ2h0OiB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgaGVpZ2h0IG9mIHRoZSBleHBvcnRlZCBjaGFydCwgb3ZlcnJpZGluZyB0aGUgb3B0aW9uIGluIHRoZSBjaGFydCBzZXR0aW5ncy4nXHJcbiAgICB9LFxyXG4gICAgd2lkdGg6IHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSB3aWR0aCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQsIG92ZXJyaWRpbmcgdGhlIG9wdGlvbiBpbiB0aGUgY2hhcnQgc2V0dGluZ3MuJ1xyXG4gICAgfSxcclxuICAgIHNjYWxlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgc2NhbGUgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LCBvdmVycmlkaW5nIHRoZSBvcHRpb24gaW4gdGhlIGNoYXJ0IHNldHRpbmdzLiBSYW5nZXMgYmV0d2VlbiAwLjEgYW5kIDUuMC4nXHJcbiAgICB9LFxyXG4gICAgZ2xvYmFsT3B0aW9uczoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnRWl0aGVyIGEgc3RyaW5naWZpZWQgSlNPTiBvciBhIGZpbGVuYW1lIGNvbnRhaW5pbmcgb3B0aW9ucyB0byBiZSBwYXNzZWQgaW50byB0aGUgSGlnaGNoYXJ0cy5zZXRPcHRpb25zLidcclxuICAgIH0sXHJcbiAgICB0aGVtZU9wdGlvbnM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0VpdGhlciBhIHN0cmluZ2lmaWVkIEpTT04gb3IgYSBmaWxlbmFtZSBjb250YWluaW5nIHRoZW1lIG9wdGlvbnMgdG8gYmUgcGFzc2VkIGludG8gdGhlIEhpZ2hjaGFydHMuc2V0T3B0aW9ucy4nXHJcbiAgICB9LFxyXG4gICAgYmF0Y2g6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0luaXRpYXRlcyBhIGJhdGNoIGpvYiB3aXRoIGEgc3RyaW5nIGNvbnRhaW5pbmcgaW5wdXQvb3V0cHV0IHBhaXJzOiBcImluPW91dDtpbj1vdXQ7Li4uXCIuJ1xyXG4gICAgfSxcclxuICAgIHJhc3Rlcml6YXRpb25UaW1lb3V0OiB7XHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfUkFTVEVSSVpBVElPTl9USU1FT1VUJyxcclxuICAgICAgdmFsdWU6IDE1MDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGR1cmF0aW9uIGluIG1pbGxpc2Vjb25kcyB0byB3YWl0IGZvciByZW5kZXJpbmcgYSB3ZWJwYWdlLidcclxuICAgIH1cclxuICB9LFxyXG4gIGN1c3RvbUxvZ2ljOiB7XHJcbiAgICBhbGxvd0NvZGVFeGVjdXRpb246IHtcclxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19BTExPV19DT0RFX0VYRUNVVElPTicsXHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQ29udHJvbHMgd2hldGhlciB0aGUgZXhlY3V0aW9uIG9mIGFyYml0cmFyeSBjb2RlIGlzIGFsbG93ZWQgZHVyaW5nIHRoZSBleHBvcnRpbmcgcHJvY2Vzcy4nXHJcbiAgICB9LFxyXG4gICAgYWxsb3dGaWxlUmVzb3VyY2VzOiB7XHJcbiAgICAgIGVudkxpbms6ICdDVVNUT01fTE9HSUNfQUxMT1dfRklMRV9SRVNPVVJDRVMnLFxyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0NvbnRyb2xzIHRoZSBhYmlsaXR5IHRvIGluamVjdCByZXNvdXJjZXMgZnJvbSB0aGUgZmlsZXN5c3RlbS4gVGhpcyBzZXR0aW5nIGhhcyBubyBlZmZlY3Qgd2hlbiBydW5uaW5nIGFzIGEgc2VydmVyLidcclxuICAgIH0sXHJcbiAgICBjdXN0b21Db2RlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdDdXN0b20gY29kZSB0byBleGVjdXRlIGJlZm9yZSBjaGFydCBpbml0aWFsaXphdGlvbi4gSXQgY2FuIGJlIGEgZnVuY3Rpb24sIGNvZGUgd3JhcHBlZCB3aXRoaW4gYSBmdW5jdGlvbiwgb3IgYSBmaWxlbmFtZSB3aXRoIHRoZSAuanMgZXh0ZW5zaW9uLidcclxuICAgIH0sXHJcbiAgICBjYWxsYmFjazoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSmF2YVNjcmlwdCBjb2RlIHRvIHJ1biBkdXJpbmcgY29uc3RydWN0aW9uLiBJdCBjYW4gYmUgYSBmdW5jdGlvbiBvciBhIGZpbGVuYW1lIHdpdGggdGhlIC5qcyBleHRlbnNpb24uJ1xyXG4gICAgfSxcclxuICAgIHJlc291cmNlczoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQWRkaXRpb25hbCByZXNvdXJjZSBpbiB0aGUgZm9ybSBvZiBhIHN0cmluZ2lmaWVkIEpTT04sIHdoaWNoIG1heSBjb250YWluIGZpbGVzLCBqcywgYW5kIGNzcyBzZWN0aW9ucy4nXHJcbiAgICB9LFxyXG4gICAgbG9hZENvbmZpZzoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBsZWdhY3lOYW1lOiAnZnJvbUZpbGUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0EgZmlsZSBjb250YWluaW5nIGEgcHJlLWRlZmluZWQgY29uZmlndXJhdGlvbiB0byB1c2UuJ1xyXG4gICAgfSxcclxuICAgIGNyZWF0ZUNvbmZpZzoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnRW5hYmxlcyBzZXR0aW5nIG9wdGlvbnMgdGhyb3VnaCBhIHByb21wdCBhbmQgc2F2aW5nIHRoZW0gaW4gYSBwcm92aWRlZCBjb25maWcgZmlsZS4nXHJcbiAgICB9XHJcbiAgfSxcclxuICBzZXJ2ZXI6IHtcclxuICAgIGVuYWJsZToge1xyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX0VOQUJMRScsXHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBjbGlOYW1lOiAnZW5hYmxlU2VydmVyJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1doZW4gc2V0IHRvIHRydWUsIHRoZSBzZXJ2ZXIgc3RhcnRzIG9uIHRoZSBsb2NhbCBJUCBhZGRyZXNzIDAuMC4wLjAuJ1xyXG4gICAgfSxcclxuICAgIGhvc3Q6IHtcclxuICAgICAgZW52TGluazogJ1NFUlZFUl9IT1NUJyxcclxuICAgICAgdmFsdWU6ICcwLjAuMC4wJyxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgaG9zdG5hbWUgb2YgdGhlIHNlcnZlci4gQWRkaXRpb25hbGx5LCBpdCBzdGFydHMgYSBzZXJ2ZXIgb24gdGhlIHByb3ZpZGVkIGhvc3RuYW1lLidcclxuICAgIH0sXHJcbiAgICBwb3J0OiB7XHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfUE9SVCcsXHJcbiAgICAgIHZhbHVlOiA3ODAxLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgc2VydmVyIHBvcnQgd2hlbiBlbmFibGVkLidcclxuICAgIH0sXHJcbiAgICBiZW5jaG1hcmtpbmc6IHtcclxuICAgICAgZW52TGluazogJ1NFUlZFUl9CRU5DSE1BUktJTkcnLFxyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgY2xpTmFtZTogJ3NlcnZlckJlbmNobWFya2luZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbmRpY2F0ZXMgd2hldGhlciB0byBkaXNwbGF5IHRoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCBvZiBzcGVjaWZpYyBhY3Rpb25zIHRoYXQgb2NjdXIgb24gdGhlIHNlcnZlciB3aGlsZSBzZXJ2aW5nIGEgcmVxdWVzdC4nXHJcbiAgICB9LFxyXG4gICAgc3NsOiB7XHJcbiAgICAgIGVuYWJsZToge1xyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfU1NMX0VOQUJMRScsXHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgICBjbGlOYW1lOiAnZW5hYmxlU3NsJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgb3IgZGlzYWJsZXMgdGhlIFNTTCBwcm90b2NvbC4nXHJcbiAgICAgIH0sXHJcbiAgICAgIGZvcmNlOiB7XHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfRk9SQ0UnLFxyXG4gICAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgICAgY2xpTmFtZTogJ3NzbEZvcmNlZCcsXHJcbiAgICAgICAgbGVnYWN5TmFtZTogJ3NzbE9ubHknLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICAgJ1doZW4gc2V0IHRvIHRydWUsIHRoZSBzZXJ2ZXIgaXMgZm9yY2VkIHRvIHNlcnZlIG9ubHkgb3ZlciBIVFRQUy4nXHJcbiAgICAgIH0sXHJcbiAgICAgIHBvcnQ6IHtcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9QT1JUJyxcclxuICAgICAgICB2YWx1ZTogNDQzLFxyXG4gICAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICAgIGNsaU5hbWU6ICdzc2xQb3J0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSBwb3J0IG9uIHdoaWNoIHRvIHJ1biB0aGUgU1NMIHNlcnZlci4nXHJcbiAgICAgIH0sXHJcbiAgICAgIGNlcnRQYXRoOiB7XHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfQ0VSVF9QQVRIJyxcclxuICAgICAgICB2YWx1ZTogJycsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgbGVnYWN5TmFtZTogJ3NzbFBhdGgnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHBhdGggdG8gdGhlIFNTTCBjZXJ0aWZpY2F0ZS9rZXkgZmlsZS4nXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICByYXRlTGltaXRpbmc6IHtcclxuICAgICAgZW5hYmxlOiB7XHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX0VOQUJMRScsXHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgICBjbGlOYW1lOiAnZW5hYmxlUmF0ZUxpbWl0aW5nJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgcmF0ZSBsaW1pdGluZyBmb3IgdGhlIHNlcnZlci4nXHJcbiAgICAgIH0sXHJcbiAgICAgIG1heFJlcXVlc3RzOiB7XHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX01BWF9SRVFVRVNUUycsXHJcbiAgICAgICAgdmFsdWU6IDEwLFxyXG4gICAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICAgIGxlZ2FjeU5hbWU6ICdyYXRlTGltaXQnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIG1heGltdW0gbnVtYmVyIG9mIHJlcXVlc3RzIGFsbG93ZWQgaW4gb25lIG1pbnV0ZS4nXHJcbiAgICAgIH0sXHJcbiAgICAgIHdpbmRvdzoge1xyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19XSU5ET1cnLFxyXG4gICAgICAgIHZhbHVlOiAxLFxyXG4gICAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHRpbWUgd2luZG93LCBpbiBtaW51dGVzLCBmb3IgdGhlIHJhdGUgbGltaXRpbmcuJ1xyXG4gICAgICB9LFxyXG4gICAgICBkZWxheToge1xyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19ERUxBWScsXHJcbiAgICAgICAgdmFsdWU6IDAsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgICAnVGhlIGRlbGF5IGR1cmF0aW9uIGZvciBlYWNoIHN1Y2Nlc3NpdmUgcmVxdWVzdCBiZWZvcmUgcmVhY2hpbmcgdGhlIG1heGltdW0gbGltaXQuJ1xyXG4gICAgICB9LFxyXG4gICAgICB0cnVzdFByb3h5OiB7XHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1RSVVNUX1BST1hZJyxcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnU2V0IHRoaXMgdG8gdHJ1ZSBpZiB0aGUgc2VydmVyIGlzIGJlaGluZCBhIGxvYWQgYmFsYW5jZXIuJ1xyXG4gICAgICB9LFxyXG4gICAgICBza2lwS2V5OiB7XHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfS0VZJyxcclxuICAgICAgICB2YWx1ZTogJycsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgICAnQWxsb3dzIGJ5cGFzc2luZyB0aGUgcmF0ZSBsaW1pdGVyIGFuZCBzaG91bGQgYmUgcHJvdmlkZWQgd2l0aCB0aGUgc2tpcFRva2VuIGFyZ3VtZW50LidcclxuICAgICAgfSxcclxuICAgICAgc2tpcFRva2VuOiB7XHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfVE9LRU4nLFxyXG4gICAgICAgIHZhbHVlOiAnJyxcclxuICAgICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAgICdBbGxvd3MgYnlwYXNzaW5nIHRoZSByYXRlIGxpbWl0ZXIgYW5kIHNob3VsZCBiZSBwcm92aWRlZCB3aXRoIHRoZSBza2lwS2V5IGFyZ3VtZW50LidcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0sXHJcbiAgcG9vbDoge1xyXG4gICAgbWluV29ya2Vyczoge1xyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9NSU5fV09SS0VSUycsXHJcbiAgICAgIHZhbHVlOiA0LFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgbnVtYmVyIG9mIG1pbmltdW0gYW5kIGluaXRpYWwgcG9vbCB3b3JrZXJzIHRvIHNwYXduLidcclxuICAgIH0sXHJcbiAgICBtYXhXb3JrZXJzOiB7XHJcbiAgICAgIGVudkxpbms6ICdQT09MX01BWF9XT1JLRVJTJyxcclxuICAgICAgdmFsdWU6IDgsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBsZWdhY3lOYW1lOiAnd29ya2VycycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIG51bWJlciBvZiBtYXhpbXVtIHBvb2wgd29ya2VycyB0byBzcGF3bi4nXHJcbiAgICB9LFxyXG4gICAgd29ya0xpbWl0OiB7XHJcbiAgICAgIGVudkxpbms6ICdQT09MX1dPUktfTElNSVQnLFxyXG4gICAgICB2YWx1ZTogNDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIG51bWJlciBvZiB3b3JrIHBpZWNlcyB0aGF0IGNhbiBiZSBwZXJmb3JtZWQgYmVmb3JlIHJlc3RhcnRpbmcgdGhlIHdvcmtlciBwcm9jZXNzLidcclxuICAgIH0sXHJcbiAgICBhY3F1aXJlVGltZW91dDoge1xyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9BQ1FVSVJFX1RJTUVPVVQnLFxyXG4gICAgICB2YWx1ZTogNTAwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgdG8gd2FpdCBmb3IgYWNxdWlyaW5nIGEgcmVzb3VyY2UuJ1xyXG4gICAgfSxcclxuICAgIGNyZWF0ZVRpbWVvdXQ6IHtcclxuICAgICAgZW52TGluazogJ1BPT0xfQ1JFQVRFX1RJTUVPVVQnLFxyXG4gICAgICB2YWx1ZTogNTAwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgdG8gd2FpdCBmb3IgY3JlYXRpbmcgYSByZXNvdXJjZS4nXHJcbiAgICB9LFxyXG4gICAgZGVzdHJveVRpbWVvdXQ6IHtcclxuICAgICAgZW52TGluazogJ1BPT0xfREVTVFJPWV9USU1FT1VUJyxcclxuICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGR1cmF0aW9uLCBpbiBtaWxsaXNlY29uZHMsIHRvIHdhaXQgZm9yIGRlc3Ryb3lpbmcgYSByZXNvdXJjZS4nXHJcbiAgICB9LFxyXG4gICAgaWRsZVRpbWVvdXQ6IHtcclxuICAgICAgZW52TGluazogJ1BPT0xfSURMRV9USU1FT1VUJyxcclxuICAgICAgdmFsdWU6IDMwMDAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCBhZnRlciB3aGljaCBhbiBpZGxlIHJlc291cmNlIGlzIGRlc3Ryb3llZC4nXHJcbiAgICB9LFxyXG4gICAgY3JlYXRlUmV0cnlJbnRlcnZhbDoge1xyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9DUkVBVEVfUkVUUllfSU5URVJWQUwnLFxyXG4gICAgICB2YWx1ZTogMjAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCB0byB3YWl0IGJlZm9yZSByZXRyeWluZyB0aGUgY3JlYXRlIHByb2Nlc3MgaW4gY2FzZSBvZiBhIGZhaWx1cmUuJ1xyXG4gICAgfSxcclxuICAgIHJlYXBlckludGVydmFsOiB7XHJcbiAgICAgIGVudkxpbms6ICdQT09MX1JFQVBFUl9JTlRFUlZBTCcsXHJcbiAgICAgIHZhbHVlOiAxMDAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCBhZnRlciB3aGljaCB0aGUgY2hlY2sgZm9yIGlkbGUgcmVzb3VyY2VzIHRvIGRlc3Ryb3kgaXMgdHJpZ2dlcmVkLidcclxuICAgIH0sXHJcbiAgICBiZW5jaG1hcmtpbmc6IHtcclxuICAgICAgZW52TGluazogJ1BPT0xfQkVOQ0hNQVJLSU5HJyxcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGNsaU5hbWU6ICdwb29sQmVuY2htYXJraW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0luZGljYXRlIHdoZXRoZXIgdG8gc2hvdyBzdGF0aXN0aWNzIGZvciB0aGUgcG9vbCBvZiByZXNvdXJjZXMgb3Igbm90LidcclxuICAgIH0sXHJcbiAgICBsaXN0ZW5Ub1Byb2Nlc3NFeGl0czoge1xyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9MSVNURU5fVE9fUFJPQ0VTU19FWElUUycsXHJcbiAgICAgIHZhbHVlOiB0cnVlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRGVjaWRlcyB3aGV0aGVyIG9yIG5vdCB0byBhdHRhY2ggcHJvY2Vzcy5leGl0IGhhbmRsZXJzLidcclxuICAgIH1cclxuICB9LFxyXG4gIGxvZ2dpbmc6IHtcclxuICAgIGxldmVsOiB7XHJcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX0xFVkVMJyxcclxuICAgICAgdmFsdWU6IDQsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBjbGlOYW1lOiAnbG9nTGV2ZWwnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBsb2dnaW5nIGxldmVsIHRvIGJlIHVzZWQuJ1xyXG4gICAgfSxcclxuICAgIGZpbGU6IHtcclxuICAgICAgZW52TGluazogJ0xPR0dJTkdfRklMRScsXHJcbiAgICAgIHZhbHVlOiAnaGlnaGNoYXJ0cy1leHBvcnQtc2VydmVyLmxvZycsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBjbGlOYW1lOiAnbG9nRmlsZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgbmFtZSBvZiBhIGxvZyBmaWxlLiBUaGUgbG9nRGVzdCBvcHRpb24gYWxzbyBuZWVkcyB0byBiZSBzZXQgdG8gZW5hYmxlIGZpbGUgbG9nZ2luZy4nXHJcbiAgICB9LFxyXG4gICAgZGVzdDoge1xyXG4gICAgICBlbnZMaW5rOiAnTE9HR0lOR19ERVNUJyxcclxuICAgICAgdmFsdWU6ICdsb2cvJyxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGNsaU5hbWU6ICdsb2dEZXN0JyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBwYXRoIHRvIHN0b3JlIGxvZyBmaWxlcy4gVGhpcyBhbHNvIGVuYWJsZXMgZmlsZSBsb2dnaW5nLidcclxuICAgIH1cclxuICB9LFxyXG4gIHVpOiB7XHJcbiAgICBlbmFibGU6IHtcclxuICAgICAgZW52TGluazogJ1VJX0VOQUJMRScsXHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBjbGlOYW1lOiAnZW5hYmxlVWknLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnRW5hYmxlcyBvciBkaXNhYmxlcyB0aGUgdXNlciBpbnRlcmZhY2UgKFVJKSBmb3IgdGhlIGV4cG9ydCBzZXJ2ZXIuJ1xyXG4gICAgfSxcclxuICAgIHJvdXRlOiB7XHJcbiAgICAgIGVudkxpbms6ICdVSV9ST1VURScsXHJcbiAgICAgIHZhbHVlOiAnLycsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBjbGlOYW1lOiAndWlSb3V0ZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZW5kcG9pbnQgcm91dGUgdG8gd2hpY2ggdGhlIHVzZXIgaW50ZXJmYWNlIChVSSkgc2hvdWxkIGJlIGF0dGFjaGVkLidcclxuICAgIH1cclxuICB9LFxyXG4gIG90aGVyOiB7XHJcbiAgICBub0xvZ286IHtcclxuICAgICAgZW52TGluazogJ09USEVSX05PX0xPR08nLFxyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1NraXAgcHJpbnRpbmcgdGhlIGxvZ28gb24gYSBzdGFydHVwLiBXaWxsIGJlIHJlcGxhY2VkIGJ5IGEgc2ltcGxlIHRleHQuJ1xyXG4gICAgfVxyXG4gIH1cclxufTtcclxuXHJcbi8vIFRoZSBjb25maWcgZGVzY3JpcHRpb25zIG9iamVjdCBmb3IgdGhlIHByb21wdHMgZnVuY3Rpb25hbGl0eS4gSXQgY29udGFpbnNcclxuLy8gaW5mb3JtYXRpb24gbGlrZTpcclxuLy8gKiBUeXBlIG9mIGEgcHJvbXB0XHJcbi8vICogTmFtZSBvZiBhbiBvcHRpb25cclxuLy8gKiBTaG9ydCBkZXNjcmlwdGlvbiBvZiBhIGNob3NlbiBvcHRpb25cclxuLy8gKiBJbml0aWFsIHZhbHVlXHJcbmV4cG9ydCBjb25zdCBwcm9tcHRzQ29uZmlnID0ge1xyXG4gIHB1cHBldGVlcjogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbGlzdCcsXHJcbiAgICAgIG5hbWU6ICdhcmdzJyxcclxuICAgICAgbWVzc2FnZTogJ1B1cHBldGVlciBhcmd1bWVudHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnB1cHBldGVlci5hcmdzLnZhbHVlLmpvaW4oJywnKSxcclxuICAgICAgc2VwYXJhdG9yOiAnLCdcclxuICAgIH1cclxuICBdLFxyXG4gIGhpZ2hjaGFydHM6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAndmVyc2lvbicsXHJcbiAgICAgIG1lc3NhZ2U6ICdIaWdoY2hhcnRzIHZlcnNpb24nLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMudmVyc2lvbi52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnY2RuVVJMJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBVUkwgb2YgQ0ROJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLmNkblVSTC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ211bHRpc2VsZWN0JyxcclxuICAgICAgbmFtZTogJ21vZHVsZXMnLFxyXG4gICAgICBtZXNzYWdlOiAnQXZhaWxhYmxlIG1vZHVsZXMnLFxyXG4gICAgICBpbnN0cnVjdGlvbnM6ICdTcGFjZTogU2VsZWN0IHNwZWNpZmljLCBBOiBTZWxlY3QgYWxsLCBFbnRlcjogQ29uZmlybS4nLFxyXG4gICAgICBjaG9pY2VzOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMubW9kdWxlcy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ2xpc3QnLFxyXG4gICAgICBuYW1lOiAnc2NyaXB0cycsXHJcbiAgICAgIG1lc3NhZ2U6ICdDdXN0b20gc2NyaXB0cycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5zY3JpcHRzLnZhbHVlLmpvaW4oJywnKSxcclxuICAgICAgc2VwYXJhdG9yOiAnLCdcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnZm9yY2VGZXRjaCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdGb3JjZSByZS1mZXRjaCB0aGUgc2NyaXB0cycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5mb3JjZUZldGNoLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdjYWNoZVBhdGgnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIHBhdGggdG8gdGhlIGNhY2hlIGRpcmVjdG9yeScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5jYWNoZVBhdGgudmFsdWVcclxuICAgIH1cclxuICBdLFxyXG4gIGV4cG9ydDogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAnc2VsZWN0JyxcclxuICAgICAgbmFtZTogJ3R5cGUnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgZXhwb3J0IGZpbGUgdHlwZScsXHJcbiAgICAgIGhpbnQ6IGBEZWZhdWx0OiAke2RlZmF1bHRDb25maWcuZXhwb3J0LnR5cGUudmFsdWV9YCxcclxuICAgICAgaW5pdGlhbDogMCxcclxuICAgICAgY2hvaWNlczogWydwbmcnLCAnanBlZycsICdwZGYnLCAnc3ZnJ11cclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdzZWxlY3QnLFxyXG4gICAgICBuYW1lOiAnY29uc3RyJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBkZWZhdWx0IGNvbnN0cnVjdG9yIGZvciBIaWdoY2hhcnRzJyxcclxuICAgICAgaGludDogYERlZmF1bHQ6ICR7ZGVmYXVsdENvbmZpZy5leHBvcnQuY29uc3RyLnZhbHVlfWAsXHJcbiAgICAgIGluaXRpYWw6IDAsXHJcbiAgICAgIGNob2ljZXM6IFsnY2hhcnQnLCAnc3RvY2tDaGFydCcsICdtYXBDaGFydCcsICdnYW50dENoYXJ0J11cclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnZGVmYXVsdEhlaWdodCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgZGVmYXVsdCBmYWxsYmFjayBoZWlnaHQgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5leHBvcnQuZGVmYXVsdEhlaWdodC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdkZWZhdWx0V2lkdGgnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgZmFsbGJhY2sgd2lkdGggb2YgdGhlIGV4cG9ydGVkIGNoYXJ0JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5leHBvcnQuZGVmYXVsdFdpZHRoLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2RlZmF1bHRTY2FsZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgZGVmYXVsdCBmYWxsYmFjayBzY2FsZSBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmV4cG9ydC5kZWZhdWx0U2NhbGUudmFsdWUsXHJcbiAgICAgIG1pbjogMC4xLFxyXG4gICAgICBtYXg6IDVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncmFzdGVyaXphdGlvblRpbWVvdXQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIHJlbmRlcmluZyB3ZWJwYWdlIHRpbWVvdXQgaW4gbWlsbGlzZWNvbmRzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5leHBvcnQucmFzdGVyaXphdGlvblRpbWVvdXQudmFsdWVcclxuICAgIH1cclxuICBdLFxyXG4gIGN1c3RvbUxvZ2ljOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnYWxsb3dDb2RlRXhlY3V0aW9uJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBleGVjdXRpb24gb2YgY3VzdG9tIGNvZGUnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmN1c3RvbUxvZ2ljLmFsbG93Q29kZUV4ZWN1dGlvbi52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdhbGxvd0ZpbGVSZXNvdXJjZXMnLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIGZpbGUgcmVzb3VyY2VzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5jdXN0b21Mb2dpYy5hbGxvd0ZpbGVSZXNvdXJjZXMudmFsdWVcclxuICAgIH1cclxuICBdLFxyXG4gIHNlcnZlcjogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2VuYWJsZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdTdGFydHMgdGhlIHNlcnZlciBvbiAwLjAuMC4wJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIuZW5hYmxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdob3N0JyxcclxuICAgICAgbWVzc2FnZTogJ1NlcnZlciBob3N0bmFtZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLmhvc3QudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncG9ydCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdTZXJ2ZXIgcG9ydCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnBvcnQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnYmVuY2htYXJraW5nJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBzZXJ2ZXIgYmVuY2htYXJraW5nJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIuYmVuY2htYXJraW5nLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ3NzbC5lbmFibGUnLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIFNTTCBwcm90b2NvbCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnNzbC5lbmFibGUudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnc3NsLmZvcmNlJyxcclxuICAgICAgbWVzc2FnZTogJ0ZvcmNlIHNlcnZpbmcgb25seSBvdmVyIEhUVFBTJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIuc3NsLmZvcmNlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3NzbC5wb3J0JyxcclxuICAgICAgbWVzc2FnZTogJ1NTTCBzZXJ2ZXIgcG9ydCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnNzbC5wb3J0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdzc2wuY2VydFBhdGgnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIHBhdGggdG8gZmluZCB0aGUgU1NMIGNlcnRpZmljYXRlL2tleScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnNzbC5jZXJ0UGF0aC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcuZW5hYmxlJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSByYXRlIGxpbWl0aW5nJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLmVuYWJsZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcubWF4UmVxdWVzdHMnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIG1heGltdW0gcmVxdWVzdHMgYWxsb3dlZCBwZXIgbWludXRlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLm1heFJlcXVlc3RzLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy53aW5kb3cnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIHJhdGUtbGltaXRpbmcgdGltZSB3aW5kb3cgaW4gbWludXRlcycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy53aW5kb3cudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLmRlbGF5JyxcclxuICAgICAgbWVzc2FnZTpcclxuICAgICAgICAnVGhlIGRlbGF5IGZvciBlYWNoIHN1Y2Nlc3NpdmUgcmVxdWVzdCBiZWZvcmUgcmVhY2hpbmcgdGhlIG1heGltdW0nLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcuZGVsYXkudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLnRydXN0UHJveHknLFxyXG4gICAgICBtZXNzYWdlOiAnU2V0IHRvIHRydWUgaWYgYmVoaW5kIGEgbG9hZCBiYWxhbmNlcicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy50cnVzdFByb3h5LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcuc2tpcEtleScsXHJcbiAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgJ0FsbG93cyBieXBhc3NpbmcgdGhlIHJhdGUgbGltaXRlciB3aGVuIHByb3ZpZGVkIHdpdGggdGhlIHNraXBUb2tlbiBhcmd1bWVudCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy5za2lwS2V5LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcuc2tpcFRva2VuJyxcclxuICAgICAgbWVzc2FnZTpcclxuICAgICAgICAnQWxsb3dzIGJ5cGFzc2luZyB0aGUgcmF0ZSBsaW1pdGVyIHdoZW4gcHJvdmlkZWQgd2l0aCB0aGUgc2tpcEtleSBhcmd1bWVudCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy5za2lwVG9rZW4udmFsdWVcclxuICAgIH1cclxuICBdLFxyXG4gIHBvb2w6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdtaW5Xb3JrZXJzJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBpbml0aWFsIG51bWJlciBvZiB3b3JrZXJzIHRvIHNwYXduJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLm1pbldvcmtlcnMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnbWF4V29ya2VycycsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbWF4aW11bSBudW1iZXIgb2Ygd29ya2VycyB0byBzcGF3bicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5tYXhXb3JrZXJzLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3dvcmtMaW1pdCcsXHJcbiAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgJ1RoZSBwaWVjZXMgb2Ygd29yayB0aGF0IGNhbiBiZSBwZXJmb3JtZWQgYmVmb3JlIHJlc3RhcnRpbmcgYSBQdXBwZXRlZXIgcHJvY2VzcycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC53b3JrTGltaXQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnYWNxdWlyZVRpbWVvdXQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgYWNxdWlyaW5nIGEgcmVzb3VyY2UnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wuYWNxdWlyZVRpbWVvdXQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnY3JlYXRlVGltZW91dCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcyB0byB3YWl0IGZvciBjcmVhdGluZyBhIHJlc291cmNlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmNyZWF0ZVRpbWVvdXQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnZGVzdHJveVRpbWVvdXQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgZGVzdHJveWluZyBhIHJlc291cmNlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmRlc3Ryb3lUaW1lb3V0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2lkbGVUaW1lb3V0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIGFmdGVyIGFuIGlkbGUgcmVzb3VyY2UgaXMgZGVzdHJveWVkJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmlkbGVUaW1lb3V0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2NyZWF0ZVJldHJ5SW50ZXJ2YWwnLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdUaGUgcmV0cnkgaW50ZXJ2YWwgaW4gbWlsbGlzZWNvbmRzIGFmdGVyIGEgY3JlYXRlIHByb2Nlc3MgZmFpbHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wuY3JlYXRlUmV0cnlJbnRlcnZhbC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdyZWFwZXJJbnRlcnZhbCcsXHJcbiAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgJ1RoZSByZWFwZXIgaW50ZXJ2YWwgaW4gbWlsbGlzZWNvbmRzIGFmdGVyIHRyaWdnZXJpbmcgdGhlIGNoZWNrIGZvciBpZGxlIHJlc291cmNlcyB0byBkZXN0cm95JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLnJlYXBlckludGVydmFsLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2JlbmNobWFya2luZycsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgYmVuY2htYXJraW5nIGZvciBhIHJlc291cmNlIHBvb2wnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wuYmVuY2htYXJraW5nLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2xpc3RlblRvUHJvY2Vzc0V4aXRzJyxcclxuICAgICAgbWVzc2FnZTogJ1NldCB0byBmYWxzZSB0byBza2lwIGF0dGFjaGluZyBwcm9jZXNzLmV4aXQgaGFuZGxlcnMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wubGlzdGVuVG9Qcm9jZXNzRXhpdHMudmFsdWVcclxuICAgIH1cclxuICBdLFxyXG4gIGxvZ2dpbmc6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdsZXZlbCcsXHJcbiAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgJ1RoZSBsb2cgbGV2ZWwgKDA6IHNpbGVudCwgMTogZXJyb3IsIDI6IHdhcm5pbmcsIDM6IG5vdGljZSwgNDogdmVyYm9zZSwgNTogYmVuY2htYXJrKScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcubG9nZ2luZy5sZXZlbC52YWx1ZSxcclxuICAgICAgcm91bmQ6IDAsXHJcbiAgICAgIG1pbjogMCxcclxuICAgICAgbWF4OiA1XHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdmaWxlJyxcclxuICAgICAgbWVzc2FnZTogJ0EgbG9nIGZpbGUgbmFtZS4gU2V0IHdpdGggdGhlIC0tbG9nRGVzdCB0byBlbmFibGUgZmlsZSBsb2dnaW5nJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5sb2dnaW5nLmZpbGUudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ2Rlc3QnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIHBhdGggdG8gbG9nIGZpbGVzLiBFbmFibGVzIGZpbGUgbG9nZ2luZycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcubG9nZ2luZy5kZXN0LnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICB1aTogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2VuYWJsZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgVUkgZm9yIHRoZSBleHBvcnQgc2VydmVyJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy51aS5lbmFibGUudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ3JvdXRlJyxcclxuICAgICAgbWVzc2FnZTogJ0Egcm91dGUgdG8gYXR0YWNoIHRoZSBVSScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcudWkucm91dGUudmFsdWVcclxuICAgIH1cclxuICBdLFxyXG4gIG90aGVyOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnbm9Mb2dvJyxcclxuICAgICAgbWVzc2FnZTogJ1NraXAgcHJpbnRpbmcgdGhlIGxvZ28gb24gc3RhcnR1cC4gUmVwbGFjZWQgYnkgc2ltcGxlIHRleHQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLm90aGVyLm5vTG9nby52YWx1ZVxyXG4gICAgfVxyXG4gIF1cclxufTtcclxuXHJcbi8vIEFic29sdXRlIHByb3BzIHRoYXQsIGluIGNhc2Ugb2YgbWVyZ2luZyByZWN1cnNpdmVseSwgbmVlZCB0byBiZSBmb3JjZSBtZXJnZWRcclxuZXhwb3J0IGNvbnN0IGFic29sdXRlUHJvcHMgPSBbXHJcbiAgJ29wdGlvbnMnLFxyXG4gICdnbG9iYWxPcHRpb25zJyxcclxuICAndGhlbWVPcHRpb25zJyxcclxuICAncmVzb3VyY2VzJyxcclxuICAncGF5bG9hZCdcclxuXTtcclxuXHJcbi8vIEFyZ3VtZW50IG5lc3RpbmcgbGV2ZWwgb2YgYWxsIGV4cG9ydCBzZXJ2ZXIgb3B0aW9uc1xyXG5leHBvcnQgY29uc3QgbmVzdGVkQXJncyA9IHt9O1xyXG5cclxuLyoqXHJcbiAqIFJlY3Vyc2l2ZWx5IGNyZWF0ZXMgYSBjaGFpbiBvZiBuZXN0ZWQgYXJndW1lbnRzIGZyb20gYW4gb2JqZWN0LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb2JqIC0gVGhlIG9iamVjdCBjb250YWluaW5nIG5lc3RlZCBhcmd1bWVudHMuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwcm9wQ2hhaW4gLSBUaGUgY3VycmVudCBjaGFpbiBvZiBuZXN0ZWQgcHJvcGVydGllc1xyXG4gKiAodXNlZCBpbnRlcm5hbGx5IGR1cmluZyByZWN1cnNpb24pLlxyXG4gKi9cclxuY29uc3QgY3JlYXRlTmVzdGVkQXJncyA9IChvYmosIHByb3BDaGFpbiA9ICcnKSA9PiB7XHJcbiAgT2JqZWN0LmtleXMob2JqKS5mb3JFYWNoKChrKSA9PiB7XHJcbiAgICBpZiAoIVsncHVwcGV0ZWVyJywgJ2hpZ2hjaGFydHMnXS5pbmNsdWRlcyhrKSkge1xyXG4gICAgICBjb25zdCBlbnRyeSA9IG9ialtrXTtcclxuICAgICAgaWYgKHR5cGVvZiBlbnRyeS52YWx1ZSA9PT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgICAvLyBHbyBkZWVwZXIgaW4gdGhlIG5lc3RlZCBhcmd1bWVudHNcclxuICAgICAgICBjcmVhdGVOZXN0ZWRBcmdzKGVudHJ5LCBgJHtwcm9wQ2hhaW59LiR7a31gKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICAvLyBDcmVhdGUgdGhlIGNoYWluIG9mIG5lc3RlZCBhcmd1bWVudHNcclxuICAgICAgICBuZXN0ZWRBcmdzW2VudHJ5LmNsaU5hbWUgfHwga10gPSBgJHtwcm9wQ2hhaW59LiR7a31gLnN1YnN0cmluZygxKTtcclxuXHJcbiAgICAgICAgLy8gU3VwcG9ydCBmb3IgdGhlIGxlZ2FjeSwgUGhhbnRvbUpTIHByb3BlcnRpZXMgbmFtZXNcclxuICAgICAgICBpZiAoZW50cnkubGVnYWN5TmFtZSAhPT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgICAgICBuZXN0ZWRBcmdzW2VudHJ5LmxlZ2FjeU5hbWVdID0gYCR7cHJvcENoYWlufS4ke2t9YC5zdWJzdHJpbmcoMSk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSk7XHJcbn07XHJcblxyXG5jcmVhdGVOZXN0ZWRBcmdzKGRlZmF1bHRDb25maWcpO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IGFwcGVuZEZpbGUsIGV4aXN0c1N5bmMsIG1rZGlyU3luYyB9IGZyb20gJ2ZzJztcclxuXHJcbmltcG9ydCB7IGRlZmF1bHRDb25maWcgfSBmcm9tICcuL3NjaGVtYXMvY29uZmlnLmpzJztcclxuXHJcbi8vIFRoZSBhdmFpbGFibGUgY29sb3JzXHJcbmNvbnN0IGNvbG9ycyA9IFsncmVkJywgJ3llbGxvdycsICdibHVlJywgJ2dyYXknLCAnZ3JlZW4nXTtcclxuXHJcbi8vIFRoZSBkZWZhdWx0IGxvZ2dpbmcgY29uZmlnXHJcbmxldCBsb2dnaW5nID0ge1xyXG4gIC8vIEZsYWdzIGZvciBsb2dnaW5nIHN0YXR1c1xyXG4gIHRvQ29uc29sZTogdHJ1ZSxcclxuICB0b0ZpbGU6IGZhbHNlLFxyXG4gIHBhdGhDcmVhdGVkOiBmYWxzZSxcclxuICAvLyBMb2cgbGV2ZWxzXHJcbiAgbGV2ZWxzRGVzYzogW1xyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ2Vycm9yJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1swXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICd3YXJuaW5nJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1sxXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICdub3RpY2UnLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzJdXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ3ZlcmJvc2UnLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzNdXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ2JlbmNobWFyaycsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbNF1cclxuICAgIH1cclxuICBdLFxyXG4gIC8vIExvZyBsaXN0ZW5lcnNcclxuICBsaXN0ZW5lcnM6IFtdXHJcbn07XHJcblxyXG4vLyBHYXRoZXIgaW5pdCBsb2dnaW5nIG9wdGlvbnNcclxuZm9yIChjb25zdCBba2V5LCBvcHRpb25dIG9mIE9iamVjdC5lbnRyaWVzKGRlZmF1bHRDb25maWcubG9nZ2luZykpIHtcclxuICBsb2dnaW5nW2tleV0gPSBvcHRpb24udmFsdWU7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBMb2dzIHRoZSBwcm92aWRlZCB0ZXh0cyB0byBhIGZpbGUsIGlmIGZpbGUgbG9nZ2luZyBpcyBlbmFibGVkLiBJdCBjcmVhdGVzXHJcbiAqIHRoZSBuZWNlc3NhcnkgZGlyZWN0b3J5IHN0cnVjdHVyZSBpZiBub3QgYWxyZWFkeSBjcmVhdGVkIGFuZCBhcHBlbmRzIHRoZVxyXG4gKiBjb250ZW50LCBpbmNsdWRpbmcgYW4gb3B0aW9uYWwgcHJlZml4LCB0byB0aGUgc3BlY2lmaWVkIGxvZyBmaWxlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ1tdfSB0ZXh0cyAtIEFuIGFycmF5IG9mIHRleHRzIHRvIGJlIGxvZ2dlZC5cclxuICogQHBhcmFtIHtzdHJpbmd9IHByZWZpeCAtIEFuIG9wdGlvbmFsIHByZWZpeCB0byBiZSBhZGRlZCB0byBlYWNoIGxvZyBlbnRyeS5cclxuICovXHJcbmNvbnN0IGxvZ1RvRmlsZSA9ICh0ZXh0cywgcHJlZml4KSA9PiB7XHJcbiAgaWYgKGxvZ2dpbmcudG9GaWxlKSB7XHJcbiAgICBpZiAoIWxvZ2dpbmcucGF0aENyZWF0ZWQpIHtcclxuICAgICAgLy8gQ3JlYXRlIGlmIGRvZXMgbm90IGV4aXN0XHJcbiAgICAgICFleGlzdHNTeW5jKGxvZ2dpbmcuZGVzdCkgJiYgbWtkaXJTeW5jKGxvZ2dpbmcuZGVzdCk7XHJcblxyXG4gICAgICAvLyBXZSBub3cgYXNzdW1lIHRoZSBwYXRoIGlzIGF2YWlsYWJsZSwgZS5nLiBpdCdzIHRoZSByZXNwb25zaWJpbGl0eVxyXG4gICAgICAvLyBvZiB0aGUgdXNlciB0byBjcmVhdGUgdGhlIHBhdGggd2l0aCB0aGUgY29ycmVjdCBhY2Nlc3MgcmlnaHRzLlxyXG4gICAgICBsb2dnaW5nLnBhdGhDcmVhdGVkID0gdHJ1ZTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBBZGQgdGhlIGNvbnRlbnQgdG8gYSBmaWxlXHJcbiAgICBhcHBlbmRGaWxlKFxyXG4gICAgICBgJHtsb2dnaW5nLmRlc3R9JHtsb2dnaW5nLmZpbGV9YCxcclxuICAgICAgW3ByZWZpeF0uY29uY2F0KHRleHRzKS5qb2luKCcgJykgKyAnXFxuJyxcclxuICAgICAgKGVycm9yKSA9PiB7XHJcbiAgICAgICAgaWYgKGVycm9yKSB7XHJcbiAgICAgICAgICBjb25zb2xlLmxvZyhgW2xvZ2dlcl0gVW5hYmxlIHRvIHdyaXRlIHRvIGxvZyBmaWxlOiAke2Vycm9yfWApO1xyXG4gICAgICAgICAgbG9nZ2luZy50b0ZpbGUgPSBmYWxzZTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgICk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIExvZ3MgYSBtZXNzYWdlLiBBY2NlcHRzIGEgdmFyaWFibGUgYW1vdW50IG9mIGFyZ3VtZW50cy4gQXJndW1lbnRzIGFmdGVyXHJcbiAqIGBsZXZlbGAgd2lsbCBiZSBwYXNzZWQgZGlyZWN0bHkgdG8gY29uc29sZS5sb2csIGFuZC9vciB3aWxsIGJlIGpvaW5lZFxyXG4gKiBhbmQgYXBwZW5kZWQgdG8gdGhlIGxvZyBmaWxlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge2FueX0gYXJncyAtIEFuIGFycmF5IG9mIGFyZ3VtZW50cyB3aGVyZSB0aGUgZmlyc3QgaXMgdGhlIGxvZyBsZXZlbFxyXG4gKiBhbmQgdGhlIHJlc3QgYXJlIHN0cmluZ3MgdG8gYnVpbGQgYSBtZXNzYWdlIHdpdGguXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbG9nID0gKC4uLmFyZ3MpID0+IHtcclxuICBjb25zdCBbbmV3TGV2ZWwsIC4uLnRleHRzXSA9IGFyZ3M7XHJcblxyXG4gIC8vIEN1cnJlbnQgbG9nZ2luZyBvcHRpb25zXHJcbiAgY29uc3QgeyBsZXZlbCwgbGV2ZWxzRGVzYyB9ID0gbG9nZ2luZztcclxuXHJcbiAgLy8gQ2hlY2sgaWYgbG9nIGxldmVsIGlzIHdpdGhpbiBhIGNvcnJlY3QgcmFuZ2Ugb3IgaXMgYSBiZW5jaG1hcmsgbG9nXHJcbiAgaWYgKFxyXG4gICAgbmV3TGV2ZWwgIT09IDUgJiZcclxuICAgIChuZXdMZXZlbCA9PT0gMCB8fCBuZXdMZXZlbCA+IGxldmVsIHx8IGxldmVsID4gbGV2ZWxzRGVzYy5sZW5ndGgpXHJcbiAgKSB7XHJcbiAgICByZXR1cm47XHJcbiAgfVxyXG5cclxuICAvLyBHZXQgcmlkIG9mIHRoZSBHTVQgdGV4dCBpbmZvcm1hdGlvblxyXG4gIGNvbnN0IG5ld0RhdGUgPSBuZXcgRGF0ZSgpLnRvU3RyaW5nKCkuc3BsaXQoJygnKVswXS50cmltKCk7XHJcblxyXG4gIC8vIENyZWF0ZSBhIG1lc3NhZ2UncyBwcmVmaXhcclxuICBjb25zdCBwcmVmaXggPSBgJHtuZXdEYXRlfSBbJHtsZXZlbHNEZXNjW25ld0xldmVsIC0gMV0udGl0bGV9XSAtYDtcclxuXHJcbiAgLy8gQ2FsbCBhdmFpbGFibGUgbG9nIGxpc3RlbmVyc1xyXG4gIGxvZ2dpbmcubGlzdGVuZXJzLmZvckVhY2goKGZuKSA9PiB7XHJcbiAgICBmbihwcmVmaXgsIHRleHRzLmpvaW4oJyAnKSk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIExvZyB0byBjb25zb2xlXHJcbiAgaWYgKGxvZ2dpbmcudG9Db25zb2xlKSB7XHJcbiAgICBjb25zb2xlLmxvZy5hcHBseShcclxuICAgICAgdW5kZWZpbmVkLFxyXG4gICAgICBbcHJlZml4LnRvU3RyaW5nKClbbG9nZ2luZy5sZXZlbHNEZXNjW25ld0xldmVsIC0gMV0uY29sb3JdXS5jb25jYXQodGV4dHMpXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgLy8gTG9nIHRvIGZpbGVcclxuICBsb2dUb0ZpbGUodGV4dHMsIHByZWZpeCk7XHJcbn07XHJcblxyXG4vKipcclxuICogTG9ncyBhbiBlcnJvciBtZXNzYWdlIHdpdGggaXRzIHN0YWNrIHRyYWNlLiBPcHRpb25hbGx5LCBhIGN1c3RvbSBtZXNzYWdlXHJcbiAqIGNhbiBiZSBwcm92aWRlZC5cclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IGxldmVsIC0gVGhlIGxvZyBsZXZlbC5cclxuICogQHBhcmFtIHtFcnJvcn0gZXJyb3IgLSBUaGUgZXJyb3Igb2JqZWN0LlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY3VzdG9tTWVzc2FnZSAtIEFuIG9wdGlvbmFsIGN1c3RvbSBtZXNzYWdlIHRvIGJlIGxvZ2dlZCBhbG9uZ1xyXG4gKiB3aXRoIHRoZSBlcnJvci5cclxuICovXHJcbmV4cG9ydCBjb25zdCBsb2dXaXRoU3RhY2sgPSAobmV3TGV2ZWwsIGVycm9yLCBjdXN0b21NZXNzYWdlKSA9PiB7XHJcbiAgLy8gR2V0IHRoZSBtYWluIG1lc3NhZ2VcclxuICBjb25zdCBtYWluTWVzc2FnZSA9IGN1c3RvbU1lc3NhZ2UgfHwgZXJyb3IubWVzc2FnZTtcclxuXHJcbiAgLy8gQ3VycmVudCBsb2dnaW5nIG9wdGlvbnNcclxuICBjb25zdCB7IGxldmVsLCBsZXZlbHNEZXNjIH0gPSBsb2dnaW5nO1xyXG5cclxuICAvLyBDaGVjayBpZiBsb2cgbGV2ZWwgaXMgd2l0aGluIGEgY29ycmVjdCByYW5nZVxyXG4gIGlmIChuZXdMZXZlbCA9PT0gMCB8fCBuZXdMZXZlbCA+IGxldmVsIHx8IGxldmVsID4gbGV2ZWxzRGVzYy5sZW5ndGgpIHtcclxuICAgIHJldHVybjtcclxuICB9XHJcblxyXG4gIC8vIEdldCByaWQgb2YgdGhlIEdNVCB0ZXh0IGluZm9ybWF0aW9uXHJcbiAgY29uc3QgbmV3RGF0ZSA9IG5ldyBEYXRlKCkudG9TdHJpbmcoKS5zcGxpdCgnKCcpWzBdLnRyaW0oKTtcclxuXHJcbiAgLy8gQ3JlYXRlIGEgbWVzc2FnZSdzIHByZWZpeFxyXG4gIGNvbnN0IHByZWZpeCA9IGAke25ld0RhdGV9IFske2xldmVsc0Rlc2NbbmV3TGV2ZWwgLSAxXS50aXRsZX1dIC1gO1xyXG5cclxuICAvLyBJZiB0aGUgY3VzdG9tTWVzc2FnZSBleGlzdHMsIHdlIHdhbnQgdG8gZGlzcGxheSB0aGUgd2hvbGUgc3RhY2sgbWVzc2FnZVxyXG4gIGNvbnN0IHN0YWNrTWVzc2FnZSA9XHJcbiAgICBlcnJvci5tZXNzYWdlICE9PSBlcnJvci5zdGFja01lc3NhZ2UgfHwgZXJyb3Iuc3RhY2tNZXNzYWdlID09PSB1bmRlZmluZWRcclxuICAgICAgPyBlcnJvci5zdGFja1xyXG4gICAgICA6IGVycm9yLnN0YWNrLnNwbGl0KCdcXG4nKS5zbGljZSgxKS5qb2luKCdcXG4nKTtcclxuXHJcbiAgLy8gQ29tYmluZSBjdXN0b20gbWVzc2FnZSBvciBlcnJvciBtZXNzYWdlIHdpdGggZXJyb3Igc3RhY2sgbWVzc2FnZVxyXG4gIGNvbnN0IHRleHRzID0gW21haW5NZXNzYWdlLCAnXFxuJywgc3RhY2tNZXNzYWdlXTtcclxuXHJcbiAgLy8gTG9nIHRvIGNvbnNvbGVcclxuICBpZiAobG9nZ2luZy50b0NvbnNvbGUpIHtcclxuICAgIGNvbnNvbGUubG9nLmFwcGx5KFxyXG4gICAgICB1bmRlZmluZWQsXHJcbiAgICAgIFtwcmVmaXgudG9TdHJpbmcoKVtsb2dnaW5nLmxldmVsc0Rlc2NbbmV3TGV2ZWwgLSAxXS5jb2xvcl1dLmNvbmNhdChbXHJcbiAgICAgICAgbWFpbk1lc3NhZ2VbY29sb3JzW25ld0xldmVsIC0gMV1dLFxyXG4gICAgICAgICdcXG4nLFxyXG4gICAgICAgIHN0YWNrTWVzc2FnZVxyXG4gICAgICBdKVxyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIC8vIENhbGwgYXZhaWxhYmxlIGxvZyBsaXN0ZW5lcnNcclxuICBsb2dnaW5nLmxpc3RlbmVycy5mb3JFYWNoKChmbikgPT4ge1xyXG4gICAgZm4ocHJlZml4LCB0ZXh0cy5qb2luKCcgJykpO1xyXG4gIH0pO1xyXG5cclxuICAvLyBMb2cgdG8gZmlsZVxyXG4gIGxvZ1RvRmlsZSh0ZXh0cywgcHJlZml4KTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBTZXRzIHRoZSBsb2cgbGV2ZWwgdG8gdGhlIHNwZWNpZmllZCB2YWx1ZS4gTG9nIGxldmVscyBhcmUgKDAgPSBubyBsb2dnaW5nLFxyXG4gKiAxID0gZXJyb3IsIDIgPSB3YXJuaW5nLCAzID0gbm90aWNlLCA0ID0gdmVyYm9zZSBvciA1ID0gYmVuY2htYXJrKVxyXG4gKlxyXG4gKiBAcGFyYW0ge251bWJlcn0gbmV3TGV2ZWwgLSBUaGUgbmV3IGxvZyBsZXZlbCB0byBiZSBzZXQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2V0TG9nTGV2ZWwgPSAobmV3TGV2ZWwpID0+IHtcclxuICBpZiAobmV3TGV2ZWwgPj0gMCAmJiBuZXdMZXZlbCA8PSBsb2dnaW5nLmxldmVsc0Rlc2MubGVuZ3RoKSB7XHJcbiAgICBsb2dnaW5nLmxldmVsID0gbmV3TGV2ZWw7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEVuYWJsZXMgZmlsZSBsb2dnaW5nIHdpdGggdGhlIHNwZWNpZmllZCBkZXN0aW5hdGlvbiBhbmQgbG9nIGZpbGUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBsb2dEZXN0IC0gVGhlIGRlc3RpbmF0aW9uIHBhdGggZm9yIGxvZyBmaWxlcy5cclxuICogQHBhcmFtIHtzdHJpbmd9IGxvZ0ZpbGUgLSBUaGUgbG9nIGZpbGUgbmFtZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBlbmFibGVGaWxlTG9nZ2luZyA9IChsb2dEZXN0LCBsb2dGaWxlKSA9PiB7XHJcbiAgLy8gVXBkYXRlIGxvZ2dpbmcgb3B0aW9uc1xyXG4gIGxvZ2dpbmcgPSB7XHJcbiAgICAuLi5sb2dnaW5nLFxyXG4gICAgZGVzdDogbG9nRGVzdCB8fCBsb2dnaW5nLmRlc3QsXHJcbiAgICBmaWxlOiBsb2dGaWxlIHx8IGxvZ2dpbmcuZmlsZSxcclxuICAgIHRvRmlsZTogdHJ1ZVxyXG4gIH07XHJcblxyXG4gIGlmIChsb2dnaW5nLmRlc3QubGVuZ3RoID09PSAwKSB7XHJcbiAgICByZXR1cm4gbG9nKDEsICdbbG9nZ2VyXSBGaWxlIGxvZ2dpbmcgaW5pdGlhbGl6YXRpb246IG5vIHBhdGggc3VwcGxpZWQuJyk7XHJcbiAgfVxyXG5cclxuICBpZiAoIWxvZ2dpbmcuZGVzdC5lbmRzV2l0aCgnLycpKSB7XHJcbiAgICBsb2dnaW5nLmRlc3QgKz0gJy8nO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyBsb2dnaW5nIHdpdGggdGhlIHNwZWNpZmllZCBsb2dnaW5nIGNvbmZpZ3VyYXRpb24uXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBsb2dnaW5nIC0gVGhlIGxvZ2dpbmcgY29uZmlndXJhdGlvbiBvYmplY3QuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaW5pdExvZ2dpbmcgPSAobG9nZ2luZykgPT4ge1xyXG4gIC8vIFNldCB0aGUgbG9nIGxldmVsXHJcbiAgc2V0TG9nTGV2ZWwobG9nZ2luZyAmJiBwYXJzZUludChsb2dnaW5nLmxldmVsKSk7XHJcblxyXG4gIC8vIFNldCB0aGUgbG9nIGZpbGUgcGF0aCBhbmQgbmFtZVxyXG4gIGlmIChsb2dnaW5nICYmIGxvZ2dpbmcuZGVzdCkge1xyXG4gICAgZW5hYmxlRmlsZUxvZ2dpbmcoXHJcbiAgICAgIGxvZ2dpbmcuZGVzdCxcclxuICAgICAgbG9nZ2luZy5maWxlIHx8ICdoaWdoY2hhcnRzLWV4cG9ydC1zZXJ2ZXIubG9nJ1xyXG4gICAgKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogQWRkcyBhIGxpc3RlbmVyIGZ1bmN0aW9uIHRvIHRoZSBsb2dnaW5nIHN5c3RlbS5cclxuICpcclxuICogQHBhcmFtIHtmdW5jdGlvbn0gZm4gLSBUaGUgbGlzdGVuZXIgZnVuY3Rpb24gdG8gYmUgYWRkZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbGlzdGVuID0gKGZuKSA9PiB7XHJcbiAgbG9nZ2luZy5saXN0ZW5lcnMucHVzaChmbik7XHJcbn07XHJcblxyXG4vKipcclxuICogVG9nZ2xlcyB0aGUgc3RhbmRhcmQgb3V0cHV0IChjb25zb2xlKSBsb2dnaW5nLlxyXG4gKlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGVuYWJsZWQgLSBJZiB0cnVlLCBlbmFibGVzIGNvbnNvbGUgbG9nZ2luZzsgaWYgZmFsc2UsXHJcbiAqIGRpc2FibGVzIGl0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHRvZ2dsZVNURE91dCA9IChlbmFibGVkKSA9PiB7XHJcbiAgbG9nZ2luZy50b0NvbnNvbGUgPSBlbmFibGVkO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGxvZyxcclxuICBsb2dXaXRoU3RhY2ssXHJcbiAgc2V0TG9nTGV2ZWwsXHJcbiAgZW5hYmxlRmlsZUxvZ2dpbmcsXHJcbiAgaW5pdExvZ2dpbmcsXHJcbiAgbGlzdGVuLFxyXG4gIHRvZ2dsZVNURE91dFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5pbXBvcnQgeyBmaWxlVVJMVG9QYXRoIH0gZnJvbSAndXJsJztcclxuXHJcbmltcG9ydCB7IGRlZmF1bHRDb25maWcgfSBmcm9tICcuLi9saWIvc2NoZW1hcy9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuXHJcbmNvbnN0IE1BWF9CQUNLT0ZGX0FUVEVNUFRTID0gNjtcclxuXHJcbmV4cG9ydCBjb25zdCBfX2Rpcm5hbWUgPSBmaWxlVVJMVG9QYXRoKG5ldyBVUkwoJy4uLy4nLCBpbXBvcnQubWV0YS51cmwpKTtcclxuXHJcbi8qKlxyXG4gKiBDbGVhcnMgYW5kIHN0YW5kYXJkaXplcyB0ZXh0IGJ5IHJlcGxhY2luZyBtdWx0aXBsZSBjb25zZWN1dGl2ZSB3aGl0ZXNwYWNlXHJcbiAqIGNoYXJhY3RlcnMgd2l0aCBhIHNpbmdsZSBzcGFjZSBhbmQgdHJpbW1pbmcgYW55IGxlYWRpbmcgb3IgdHJhaWxpbmdcclxuICogd2hpdGVzcGFjZS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHRleHQgLSBUaGUgaW5wdXQgdGV4dCB0byBiZSBjbGVhcmVkLlxyXG4gKiBAcGFyYW0ge1JlZ0V4cH0gW3J1bGU9L1xcc1xccysvZ10gLSBUaGUgcmVndWxhciBleHByZXNzaW9uIHJ1bGUgdG8gbWF0Y2hcclxuICogbXVsdGlwbGUgY29uc2VjdXRpdmUgd2hpdGVzcGFjZSBjaGFyYWN0ZXJzLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gW3JlcGxhY2VyPScgJ10gLSBUaGUgc3RyaW5nIHVzZWQgdG8gcmVwbGFjZSBtdWx0aXBsZVxyXG4gKiBjb25zZWN1dGl2ZSB3aGl0ZXNwYWNlIGNoYXJhY3RlcnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IC0gVGhlIGNsZWFyZWQgYW5kIHN0YW5kYXJkaXplZCB0ZXh0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGNsZWFyVGV4dCA9ICh0ZXh0LCBydWxlID0gL1xcc1xccysvZywgcmVwbGFjZXIgPSAnICcpID0+XHJcbiAgdGV4dC5yZXBsYWNlQWxsKHJ1bGUsIHJlcGxhY2VyKS50cmltKCk7XHJcblxyXG4vKipcclxuICogSW1wbGVtZW50cyBhbiBleHBvbmVudGlhbCBiYWNrb2ZmIHN0cmF0ZWd5IGZvciByZXRyeWluZyBhIGZ1bmN0aW9uIHVudGlsXHJcbiAqIGEgY2VydGFpbiBudW1iZXIgb2YgYXR0ZW1wdHMgYXJlIHJlYWNoZWQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGZuIC0gVGhlIGZ1bmN0aW9uIHRvIGJlIHJldHJpZWQuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBbYXR0ZW1wdD0wXSAtIFRoZSBjdXJyZW50IGF0dGVtcHQgbnVtYmVyLlxyXG4gKiBAcGFyYW0gey4uLmFueX0gYXJncyAtIEFyZ3VtZW50cyB0byBiZSBwYXNzZWQgdG8gdGhlIGZ1bmN0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZX0gLSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgcmVzdWx0IG9mIHRoZSBmdW5jdGlvblxyXG4gKiBpZiBzdWNjZXNzZnVsLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFcnJvcn0gLSBUaHJvd3MgYW4gZXJyb3IgaWYgdGhlIG1heGltdW0gbnVtYmVyIG9mIGF0dGVtcHRzXHJcbiAqIGlzIHJlYWNoZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZXhwQmFja29mZiA9IGFzeW5jIChmbiwgYXR0ZW1wdCA9IDAsIC4uLmFyZ3MpID0+IHtcclxuICB0cnkge1xyXG4gICAgLy8gVHJ5IHRvIGNhbGwgdGhlIGZ1bmN0aW9uXHJcbiAgICByZXR1cm4gYXdhaXQgZm4oLi4uYXJncyk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIC8vIENhbGN1bGF0ZSBkZWxheSBpbiBtc1xyXG4gICAgY29uc3QgZGVsYXlJbk1zID0gMiAqKiBhdHRlbXB0ICogMTAwMDtcclxuXHJcbiAgICAvLyBJZiB0aGUgYXR0ZW1wdCBleGNlZWRzIHRoZSBtYXhpbXVtIGF0dGVtcHRzIG9mIHJlYXBlYXQsIHRocm93IGFuIGVycm9yXHJcbiAgICBpZiAoKythdHRlbXB0ID49IE1BWF9CQUNLT0ZGX0FUVEVNUFRTKSB7XHJcbiAgICAgIHRocm93IGVycm9yO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFdhaXQgZ2l2ZW4gYW1vdW50IG9mIHRpbWVcclxuICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNwb25zZSkgPT4gc2V0VGltZW91dChyZXNwb25zZSwgZGVsYXlJbk1zKSk7XHJcbiAgICBsb2coXHJcbiAgICAgIDMsXHJcbiAgICAgIGBbcG9vbF0gV2FpdGVkICR7ZGVsYXlJbk1zfW1zIHVudGlsIG5leHQgY2FsbCBmb3IgdGhlIHJlc291cmNlIGlkOiAke2FyZ3NbMF19LmBcclxuICAgICk7XHJcblxyXG4gICAgLy8gVHJ5IGFnYWluXHJcbiAgICByZXR1cm4gZXhwQmFja29mZihmbiwgYXR0ZW1wdCwgLi4uYXJncyk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEZpeGVzIHRoZSBleHBvcnQgdHlwZSBiYXNlZCBvbiBNSU1FIHR5cGVzIGFuZCBmaWxlIGV4dGVuc2lvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIC0gVGhlIG9yaWdpbmFsIGV4cG9ydCB0eXBlLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gb3V0ZmlsZSAtIFRoZSBmaWxlIHBhdGggb3IgbmFtZS5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gLSBUaGUgY29ycmVjdGVkIGV4cG9ydCB0eXBlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGZpeFR5cGUgPSAodHlwZSwgb3V0ZmlsZSkgPT4ge1xyXG4gIC8vIE1JTUUgdHlwZXNcclxuICBjb25zdCBtaW1lVHlwZXMgPSB7XHJcbiAgICAnaW1hZ2UvcG5nJzogJ3BuZycsXHJcbiAgICAnaW1hZ2UvanBlZyc6ICdqcGVnJyxcclxuICAgICdhcHBsaWNhdGlvbi9wZGYnOiAncGRmJyxcclxuICAgICdpbWFnZS9zdmcreG1sJzogJ3N2ZydcclxuICB9O1xyXG5cclxuICAvLyBGb3JtYXRzXHJcbiAgY29uc3QgZm9ybWF0cyA9IFsncG5nJywgJ2pwZWcnLCAncGRmJywgJ3N2ZyddO1xyXG5cclxuICAvLyBDaGVjayBpZiB0eXBlIGFuZCBvdXRmaWxlJ3MgZXh0ZW5zaW9ucyBhcmUgdGhlIHNhbWVcclxuICBpZiAob3V0ZmlsZSkge1xyXG4gICAgY29uc3Qgb3V0VHlwZSA9IG91dGZpbGUuc3BsaXQoJy4nKS5wb3AoKTtcclxuXHJcbiAgICBpZiAob3V0VHlwZSA9PT0gJ2pwZycpIHtcclxuICAgICAgdHlwZSA9ICdqcGVnJztcclxuICAgIH0gZWxzZSBpZiAoZm9ybWF0cy5pbmNsdWRlcyhvdXRUeXBlKSAmJiB0eXBlICE9PSBvdXRUeXBlKSB7XHJcbiAgICAgIHR5cGUgPSBvdXRUeXBlO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIGEgY29ycmVjdCB0eXBlXHJcbiAgcmV0dXJuIG1pbWVUeXBlc1t0eXBlXSB8fCBmb3JtYXRzLmZpbmQoKHQpID0+IHQgPT09IHR5cGUpIHx8ICdwbmcnO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEhhbmRsZXMgYW5kIHZhbGlkYXRlcyByZXNvdXJjZXMgZm9yIGV4cG9ydC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R8c3RyaW5nfSByZXNvdXJjZXMgLSBUaGUgcmVzb3VyY2VzIHRvIGJlIGhhbmRsZWQuIENhbiBiZSBlaXRoZXJcclxuICogYSBKU09OIG9iamVjdCwgc3RyaW5naWZpZWQgSlNPTiBvciBhIHBhdGggdG8gYSBKU09OIGZpbGUuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gYWxsb3dGaWxlUmVzb3VyY2VzIC0gV2hldGhlciB0byBhbGxvdyBsb2FkaW5nIHJlc291cmNlcyBmcm9tXHJcbiAqIGZpbGVzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fHVuZGVmaW5lZH0gLSBUaGUgaGFuZGxlZCByZXNvdXJjZXMgb3IgdW5kZWZpbmVkIGlmIG5vIHZhbGlkXHJcbiAqIHJlc291cmNlcyBhcmUgZm91bmQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaGFuZGxlUmVzb3VyY2VzID0gKHJlc291cmNlcyA9IGZhbHNlLCBhbGxvd0ZpbGVSZXNvdXJjZXMpID0+IHtcclxuICBjb25zdCBhbGxvd2VkUHJvcHMgPSBbJ2pzJywgJ2NzcycsICdmaWxlcyddO1xyXG5cclxuICBsZXQgaGFuZGxlZFJlc291cmNlcyA9IHJlc291cmNlcztcclxuICBsZXQgY29ycmVjdFJlc291cmNlcyA9IGZhbHNlO1xyXG5cclxuICAvLyBUcnkgdG8gbG9hZCByZXNvdXJjZXMgZnJvbSBhIGZpbGVcclxuICBpZiAoYWxsb3dGaWxlUmVzb3VyY2VzICYmIHJlc291cmNlcy5lbmRzV2l0aCgnLmpzb24nKSkge1xyXG4gICAgdHJ5IHtcclxuICAgICAgaGFuZGxlZFJlc291cmNlcyA9IGlzQ29ycmVjdEpTT04ocmVhZEZpbGVTeW5jKHJlc291cmNlcywgJ3V0ZjgnKSk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICByZXR1cm4gbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2NsaV0gTm8gcmVzb3VyY2VzIGZvdW5kLmApO1xyXG4gICAgfVxyXG4gIH0gZWxzZSB7XHJcbiAgICAvLyBUcnkgdG8gZ2V0IEpTT05cclxuICAgIGhhbmRsZWRSZXNvdXJjZXMgPSBpc0NvcnJlY3RKU09OKHJlc291cmNlcyk7XHJcblxyXG4gICAgLy8gR2V0IHJpZCBvZiB0aGUgZmlsZXMgc2VjdGlvblxyXG4gICAgaWYgKGhhbmRsZWRSZXNvdXJjZXMgJiYgIWFsbG93RmlsZVJlc291cmNlcykge1xyXG4gICAgICBkZWxldGUgaGFuZGxlZFJlc291cmNlcy5maWxlcztcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIEZpbHRlciBmcm9tIHVubmVjZXNzYXJ5IHByb3BlcnRpZXNcclxuICBmb3IgKGNvbnN0IHByb3BOYW1lIGluIGhhbmRsZWRSZXNvdXJjZXMpIHtcclxuICAgIGlmICghYWxsb3dlZFByb3BzLmluY2x1ZGVzKHByb3BOYW1lKSkge1xyXG4gICAgICBkZWxldGUgaGFuZGxlZFJlc291cmNlc1twcm9wTmFtZV07XHJcbiAgICB9IGVsc2UgaWYgKCFjb3JyZWN0UmVzb3VyY2VzKSB7XHJcbiAgICAgIGNvcnJlY3RSZXNvdXJjZXMgPSB0cnVlO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gQ2hlY2sgaWYgYXQgbGVhc3Qgb25lIG9mIGFsbG93ZWQgcHJvcGVydGllcyBpcyBwcmVzZW50XHJcbiAgaWYgKCFjb3JyZWN0UmVzb3VyY2VzKSB7XHJcbiAgICByZXR1cm4gbG9nKDMsIGBbY2xpXSBObyByZXNvdXJjZXMgZm91bmQuYCk7XHJcbiAgfVxyXG5cclxuICAvLyBIYW5kbGUgZmlsZXMgc2VjdGlvblxyXG4gIGlmIChoYW5kbGVkUmVzb3VyY2VzLmZpbGVzKSB7XHJcbiAgICBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzID0gaGFuZGxlZFJlc291cmNlcy5maWxlcy5tYXAoKGl0ZW0pID0+IGl0ZW0udHJpbSgpKTtcclxuICAgIGlmICghaGFuZGxlZFJlc291cmNlcy5maWxlcyB8fCBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzLmxlbmd0aCA8PSAwKSB7XHJcbiAgICAgIGRlbGV0ZSBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIHJlc291cmNlc1xyXG4gIHJldHVybiBoYW5kbGVkUmVzb3VyY2VzO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFZhbGlkYXRlcyBhbmQgcGFyc2VzIEpTT04gZGF0YS4gQ2hlY2tzIGlmIHByb3ZpZGVkIGRhdGEgaXMgb3IgY2FuXHJcbiAqIGJlIGEgY29ycmVjdCBKU09OLiBJZiBhIHByaW1pdGl2ZSBpcyBwcm92aWRlZCwgaXQgaXMgc3RyaW5naWZpZWQgYW5kIHJldHVybmVkLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdHxzdHJpbmd9IGRhdGEgLSBUaGUgSlNPTiBkYXRhIHRvIGJlIHZhbGlkYXRlZCBhbmQgcGFyc2VkLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IHRvU3RyaW5nIC0gV2hldGhlciB0byByZXR1cm4gYSBzdHJpbmdpZmllZCByZXByZXNlbnRhdGlvblxyXG4gKiBvZiB0aGUgcGFyc2VkIEpTT04uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R8c3RyaW5nfGJvb2xlYW59IC0gVGhlIHBhcnNlZCBKU09OIG9iamVjdCwgc3RyaW5naWZpZWQgSlNPTixcclxuICogb3IgZmFsc2UgaWYgdmFsaWRhdGlvbiBmYWlscy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBpc0NvcnJlY3RKU09OKGRhdGEsIHRvU3RyaW5nKSB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIEdldCB0aGUgc3RyaW5nIHJlcHJlc2VudGF0aW9uIGlmIG5vdCBhbHJlYWR5IGJlZm9yZSBwYXJzaW5nXHJcbiAgICBjb25zdCBwYXJzZWREYXRhID0gSlNPTi5wYXJzZShcclxuICAgICAgdHlwZW9mIGRhdGEgIT09ICdzdHJpbmcnID8gSlNPTi5zdHJpbmdpZnkoZGF0YSkgOiBkYXRhXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFJldHVybiBhIHN0cmluZ2lmaWVkIHJlcHJlc2VudGF0aW9uIG9mIGEgSlNPTiBpZiByZXF1aXJlZFxyXG4gICAgaWYgKHR5cGVvZiBwYXJzZWREYXRhICE9PSAnc3RyaW5nJyAmJiB0b1N0cmluZykge1xyXG4gICAgICByZXR1cm4gSlNPTi5zdHJpbmdpZnkocGFyc2VkRGF0YSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmV0dXJuIGEgSlNPTlxyXG4gICAgcmV0dXJuIHBhcnNlZERhdGE7XHJcbiAgfSBjYXRjaCB7XHJcbiAgICByZXR1cm4gZmFsc2U7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogQ2hlY2tzIGlmIHRoZSBnaXZlbiBpdGVtIGlzIGFuIG9iamVjdC5cclxuICpcclxuICogQHBhcmFtIHthbnl9IGl0ZW0gLSBUaGUgaXRlbSB0byBiZSBjaGVja2VkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBUcnVlIGlmIHRoZSBpdGVtIGlzIGFuIG9iamVjdCwgZmFsc2Ugb3RoZXJ3aXNlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGlzT2JqZWN0ID0gKGl0ZW0pID0+XHJcbiAgdHlwZW9mIGl0ZW0gPT09ICdvYmplY3QnICYmICFBcnJheS5pc0FycmF5KGl0ZW0pICYmIGl0ZW0gIT09IG51bGw7XHJcblxyXG4vKipcclxuICogQ2hlY2tzIGlmIHRoZSBnaXZlbiBvYmplY3QgaXMgZW1wdHkuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBpdGVtIC0gVGhlIG9iamVjdCB0byBiZSBjaGVja2VkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBUcnVlIGlmIHRoZSBvYmplY3QgaXMgZW1wdHksIGZhbHNlIG90aGVyd2lzZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBpc09iamVjdEVtcHR5ID0gKGl0ZW0pID0+XHJcbiAgdHlwZW9mIGl0ZW0gPT09ICdvYmplY3QnICYmXHJcbiAgIUFycmF5LmlzQXJyYXkoaXRlbSkgJiZcclxuICBpdGVtICE9PSBudWxsICYmXHJcbiAgT2JqZWN0LmtleXMoaXRlbSkubGVuZ3RoID09PSAwO1xyXG5cclxuLyoqXHJcbiAqIENoZWNrcyBpZiBhIHByaXZhdGUgSVAgcmFuZ2UgVVJMIGlzIGZvdW5kIGluIHRoZSBnaXZlbiBzdHJpbmcuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBpdGVtIC0gVGhlIHN0cmluZyB0byBiZSBjaGVja2VkIGZvciBhIHByaXZhdGUgSVAgcmFuZ2UgVVJMLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBUcnVlIGlmIGEgcHJpdmF0ZSBJUCByYW5nZSBVUkwgaXMgZm91bmQsIGZhbHNlXHJcbiAqIG90aGVyd2lzZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBpc1ByaXZhdGVSYW5nZVVybEZvdW5kID0gKGl0ZW0pID0+IHtcclxuICBjb25zdCByZWdleFBhdHRlcm5zID0gW1xyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pP2xvY2FsaG9zdFxcYi8sXHJcbiAgICAveGxpbms6aHJlZj1cIig/Omh0dHA6XFwvXFwvfGh0dHBzOlxcL1xcLyk/MTBcXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvLFxyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pPzEyN1xcLlxcZHsxLDN9XFwuXFxkezEsM31cXC5cXGR7MSwzfVxcYi8sXHJcbiAgICAveGxpbms6aHJlZj1cIig/Omh0dHA6XFwvXFwvfGh0dHBzOlxcL1xcLyk/MTcyXFwuKDFbNi05XXwyWzAtOV18M1swLTFdKVxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvLFxyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pPzE5MlxcLjE2OFxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvXHJcbiAgXTtcclxuXHJcbiAgcmV0dXJuIHJlZ2V4UGF0dGVybnMuc29tZSgocGF0dGVybikgPT4gcGF0dGVybi50ZXN0KGl0ZW0pKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgZGVlcCBjb3B5IG9mIHRoZSBnaXZlbiBvYmplY3Qgb3IgYXJyYXkuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fEFycmF5fSBvYmogLSBUaGUgb2JqZWN0IG9yIGFycmF5IHRvIGJlIGRlZXBseSBjb3BpZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R8QXJyYXl9IC0gVGhlIGRlZXAgY29weSBvZiB0aGUgcHJvdmlkZWQgb2JqZWN0IG9yIGFycmF5LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGRlZXBDb3B5ID0gKG9iaikgPT4ge1xyXG4gIGlmIChvYmogPT09IG51bGwgfHwgdHlwZW9mIG9iaiAhPT0gJ29iamVjdCcpIHtcclxuICAgIHJldHVybiBvYmo7XHJcbiAgfVxyXG5cclxuICBjb25zdCBjb3B5ID0gQXJyYXkuaXNBcnJheShvYmopID8gW10gOiB7fTtcclxuXHJcbiAgZm9yIChjb25zdCBrZXkgaW4gb2JqKSB7XHJcbiAgICBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9iaiwga2V5KSkge1xyXG4gICAgICBjb3B5W2tleV0gPSBkZWVwQ29weShvYmpba2V5XSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICByZXR1cm4gY29weTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBDb252ZXJ0cyB0aGUgcHJvdmlkZWQgb3B0aW9ucyBvYmplY3QgdG8gYSBKU09OLWZvcm1hdHRlZCBzdHJpbmcgd2l0aCB0aGVcclxuICogb3B0aW9uIHRvIHByZXNlcnZlIGZ1bmN0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgb3B0aW9ucyBvYmplY3QgdG8gYmUgY29udmVydGVkIHRvIGEgc3RyaW5nLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RnVuY3Rpb25zIC0gSWYgc2V0IHRvIHRydWUsIGZ1bmN0aW9ucyBhcmUgcHJlc2VydmVkXHJcbiAqIGluIHRoZSBvdXRwdXQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IC0gVGhlIEpTT04tZm9ybWF0dGVkIHN0cmluZyByZXByZXNlbnRpbmcgdGhlIG9wdGlvbnMuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgb3B0aW9uc1N0cmluZ2lmeSA9IChvcHRpb25zLCBhbGxvd0Z1bmN0aW9ucykgPT4ge1xyXG4gIGNvbnN0IHJlcGxhY2VyQ2FsbGJhY2sgPSAobmFtZSwgdmFsdWUpID0+IHtcclxuICAgIGlmICh0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnKSB7XHJcbiAgICAgIHZhbHVlID0gdmFsdWUudHJpbSgpO1xyXG5cclxuICAgICAgLy8gSWYgYWxsb3dGdW5jdGlvbnMgaXMgc2V0IHRvIHRydWUsIHByZXNlcnZlIGZ1bmN0aW9uc1xyXG4gICAgICBpZiAoXHJcbiAgICAgICAgKHZhbHVlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uKCcpIHx8IHZhbHVlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uICgnKSkgJiZcclxuICAgICAgICB2YWx1ZS5lbmRzV2l0aCgnfScpXHJcbiAgICAgICkge1xyXG4gICAgICAgIHZhbHVlID0gYWxsb3dGdW5jdGlvbnNcclxuICAgICAgICAgID8gYEVYUF9GVU4keyh2YWx1ZSArICcnKS5yZXBsYWNlQWxsKC9cXG58XFx0fFxcci9nLCAnICcpfUVYUF9GVU5gXHJcbiAgICAgICAgICA6IHVuZGVmaW5lZDtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiB0eXBlb2YgdmFsdWUgPT09ICdmdW5jdGlvbidcclxuICAgICAgPyBgRVhQX0ZVTiR7KHZhbHVlICsgJycpLnJlcGxhY2VBbGwoL1xcbnxcXHR8XFxyL2csICcgJyl9RVhQX0ZVTmBcclxuICAgICAgOiB2YWx1ZTtcclxuICB9O1xyXG5cclxuICAvLyBTdHJpbmdpZnkgb3B0aW9ucyBhbmQgaWYgcmVxdWlyZWQsIHJlcGxhY2Ugc3BlY2lhbCBmdW5jdGlvbnMgbWFya3NcclxuICByZXR1cm4gSlNPTi5zdHJpbmdpZnkob3B0aW9ucywgcmVwbGFjZXJDYWxsYmFjaykucmVwbGFjZUFsbChcclxuICAgIC9cIkVYUF9GVU58RVhQX0ZVTlwiL2csXHJcbiAgICAnJ1xyXG4gICk7XHJcbn07XHJcblxyXG4vKipcclxuICogUHJpbnRzIHRoZSBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIgbG9nbyBhbmQgdmVyc2lvbiBpbmZvcm1hdGlvbi5cclxuICpcclxuICogQHBhcmFtIHtib29sZWFufSBub0xvZ28gLSBJZiB0cnVlLCBvbmx5IHByaW50cyB2ZXJzaW9uIGluZm9ybWF0aW9uIHdpdGhvdXRcclxuICogdGhlIGxvZ28uXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgcHJpbnRMb2dvID0gKG5vTG9nbykgPT4ge1xyXG4gIC8vIEdldCBwYWNrYWdlIHZlcnNpb24gZWl0aGVyIGZyb20gZW52IG9yIGZyb20gcGFja2FnZS5qc29uXHJcbiAgY29uc3QgcGFja2FnZVZlcnNpb24gPSBKU09OLnBhcnNlKFxyXG4gICAgcmVhZEZpbGVTeW5jKGpvaW4oX19kaXJuYW1lLCAncGFja2FnZS5qc29uJykpXHJcbiAgKS52ZXJzaW9uO1xyXG5cclxuICAvLyBQcmludCB0ZXh0IG9ubHlcclxuICBpZiAobm9Mb2dvKSB7XHJcbiAgICBjb25zb2xlLmxvZyhgU3RhcnRpbmcgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyIHYke3BhY2thZ2VWZXJzaW9ufS4uLmApO1xyXG4gICAgcmV0dXJuO1xyXG4gIH1cclxuXHJcbiAgLy8gUHJpbnQgdGhlIGxvZ29cclxuICBjb25zb2xlLmxvZyhcclxuICAgIHJlYWRGaWxlU3luYyhfX2Rpcm5hbWUgKyAnL21zZy9zdGFydHVwLm1zZycpLnRvU3RyaW5nKCkuYm9sZC55ZWxsb3csXHJcbiAgICBgdiR7cGFja2FnZVZlcnNpb259YFxyXG4gICk7XHJcbn07XHJcblxyXG4vKipcclxuICogUHJpbnRzIHRoZSB1c2FnZSBpbmZvcm1hdGlvbiBmb3IgQ0xJIGFyZ3VtZW50cy4gSWYgcmVxdWlyZWQsIGl0IGNhbiBsaXN0XHJcbiAqIHByb3BlcnRpZXMgcmVjdXJzaXZlbHlcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBwcmludFVzYWdlKCkge1xyXG4gIGNvbnN0IHBhZCA9IDQ4O1xyXG4gIGNvbnN0IHJlYWRtZSA9ICdodHRwczovL2dpdGh1Yi5jb20vaGlnaGNoYXJ0cy9ub2RlLWV4cG9ydC1zZXJ2ZXIjcmVhZG1lJztcclxuXHJcbiAgLy8gRGlzcGxheSByZWFkbWUgaW5mb3JtYXRpb25cclxuICBjb25zb2xlLmxvZyhcclxuICAgICdcXG5Vc2FnZSBvZiBDTEkgYXJndW1lbnRzOicuYm9sZCxcclxuICAgICdcXG4tLS0tLS0nLFxyXG4gICAgYFxcbkZvciBtb3JlIGRldGFpbGVkIGluZm9ybWF0aW9uLCB2aXNpdCB0aGUgcmVhZG1lIGF0OiAke3JlYWRtZS5ib2xkLnllbGxvd30uYFxyXG4gICk7XHJcblxyXG4gIGNvbnN0IGN5Y2xlQ2F0ZWdvcmllcyA9IChvcHRpb25zKSA9PiB7XHJcbiAgICBmb3IgKGNvbnN0IFtuYW1lLCBvcHRpb25dIG9mIE9iamVjdC5lbnRyaWVzKG9wdGlvbnMpKSB7XHJcbiAgICAgIC8vIElmIGNhdGVnb3J5IGhhcyBtb3JlIGxldmVscywgZ28gZnVydGhlclxyXG4gICAgICBpZiAoIU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChvcHRpb24sICd2YWx1ZScpKSB7XHJcbiAgICAgICAgY3ljbGVDYXRlZ29yaWVzKG9wdGlvbik7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgbGV0IGRlc2NOYW1lID0gYCAgLS0ke29wdGlvbi5jbGlOYW1lIHx8IG5hbWV9ICR7XHJcbiAgICAgICAgICAoJzwnICsgb3B0aW9uLnR5cGUgKyAnPicpLmdyZWVuXHJcbiAgICAgICAgfSBgO1xyXG4gICAgICAgIGlmIChkZXNjTmFtZS5sZW5ndGggPCBwYWQpIHtcclxuICAgICAgICAgIGZvciAobGV0IGkgPSBkZXNjTmFtZS5sZW5ndGg7IGkgPCBwYWQ7IGkrKykge1xyXG4gICAgICAgICAgICBkZXNjTmFtZSArPSAnLic7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBEaXNwbGF5IGNvcnJlY3RseSBhbGlnbmVkIG1lc3NhZ2VzXHJcbiAgICAgICAgY29uc29sZS5sb2coXHJcbiAgICAgICAgICBkZXNjTmFtZSxcclxuICAgICAgICAgIG9wdGlvbi5kZXNjcmlwdGlvbixcclxuICAgICAgICAgIGBbRGVmYXVsdDogJHtvcHRpb24udmFsdWUudG9TdHJpbmcoKS5ib2xkfV1gLmJsdWVcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfTtcclxuXHJcbiAgLy8gQ3ljbGUgdGhyb3VnaCBvcHRpb25zIG9mIGVhY2ggY2F0ZWdvcmllcyBhbmQgZGlzcGxheSB0aGUgdXNhZ2UgaW5mb1xyXG4gIE9iamVjdC5rZXlzKGRlZmF1bHRDb25maWcpLmZvckVhY2goKGNhdGVnb3J5KSA9PiB7XHJcbiAgICAvLyBPbmx5IHB1cHBldGVlciBhbmQgaGlnaGNoYXJ0cyBjYXRlZ29yaWVzIGNhbm5vdCBiZSBjb25maWd1cmVkIHRocm91Z2ggQ0xJXHJcbiAgICBpZiAoIVsncHVwcGV0ZWVyJywgJ2hpZ2hjaGFydHMnXS5pbmNsdWRlcyhjYXRlZ29yeSkpIHtcclxuICAgICAgY29uc29sZS5sb2coYFxcbiR7Y2F0ZWdvcnkudG9VcHBlckNhc2UoKX1gLnJlZCk7XHJcbiAgICAgIGN5Y2xlQ2F0ZWdvcmllcyhkZWZhdWx0Q29uZmlnW2NhdGVnb3J5XSk7XHJcbiAgICB9XHJcbiAgfSk7XHJcbiAgY29uc29sZS5sb2coJ1xcbicpO1xyXG59XHJcblxyXG4vKipcclxuICogUm91bmRzIGEgbnVtYmVyIHRvIHRoZSBzcGVjaWZpZWQgcHJlY2lzaW9uLlxyXG4gKlxyXG4gKiBAcGFyYW0ge251bWJlcn0gdmFsdWUgLSBUaGUgbnVtYmVyIHRvIGJlIHJvdW5kZWQuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBwcmVjaXNpb24gLSBUaGUgbnVtYmVyIG9mIGRlY2ltYWwgcGxhY2VzIHRvIHJvdW5kIHRvLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7bnVtYmVyfSAtIFRoZSByb3VuZGVkIG51bWJlci5cclxuICovXHJcbmV4cG9ydCBjb25zdCByb3VuZE51bWJlciA9ICh2YWx1ZSwgcHJlY2lzaW9uID0gMSkgPT4ge1xyXG4gIGNvbnN0IG11bHRpcGxpZXIgPSBNYXRoLnBvdygxMCwgcHJlY2lzaW9uIHx8IDApO1xyXG4gIHJldHVybiBNYXRoLnJvdW5kKCt2YWx1ZSAqIG11bHRpcGxpZXIpIC8gbXVsdGlwbGllcjtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBDb252ZXJ0cyBhIHZhbHVlIHRvIGEgYm9vbGVhbi5cclxuICpcclxuICogQHBhcmFtIHthbnl9IGl0ZW0gLSBUaGUgdmFsdWUgdG8gYmUgY29udmVydGVkIHRvIGEgYm9vbGVhbi5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IC0gVGhlIGJvb2xlYW4gcmVwcmVzZW50YXRpb24gb2YgdGhlIGlucHV0IHZhbHVlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHRvQm9vbGVhbiA9IChpdGVtKSA9PlxyXG4gIFsnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCAnTmFOJywgJzAnLCAnJ10uaW5jbHVkZXMoaXRlbSlcclxuICAgID8gZmFsc2VcclxuICAgIDogISFpdGVtO1xyXG5cclxuLyoqXHJcbiAqIFdyYXBzIGN1c3RvbSBjb2RlIHRvIGV4ZWN1dGUgaXQgc2FmZWx5LlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY3VzdG9tQ29kZSAtIFRoZSBjdXN0b20gY29kZSB0byBiZSB3cmFwcGVkLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RmlsZVJlc291cmNlcyAtIEZsYWcgdG8gYWxsb3cgbG9hZGluZyBjb2RlIGZyb20gYSBmaWxlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfGJvb2xlYW59IC0gVGhlIHdyYXBwZWQgY3VzdG9tIGNvZGUgb3IgZmFsc2UgaWYgd3JhcHBpbmdcclxuICogZmFpbHMuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgd3JhcEFyb3VuZCA9IChjdXN0b21Db2RlLCBhbGxvd0ZpbGVSZXNvdXJjZXMpID0+IHtcclxuICBpZiAoY3VzdG9tQ29kZSAmJiB0eXBlb2YgY3VzdG9tQ29kZSA9PT0gJ3N0cmluZycpIHtcclxuICAgIGN1c3RvbUNvZGUgPSBjdXN0b21Db2RlLnRyaW0oKTtcclxuXHJcbiAgICBpZiAoY3VzdG9tQ29kZS5lbmRzV2l0aCgnLmpzJykpIHtcclxuICAgICAgcmV0dXJuIGFsbG93RmlsZVJlc291cmNlc1xyXG4gICAgICAgID8gd3JhcEFyb3VuZChyZWFkRmlsZVN5bmMoY3VzdG9tQ29kZSwgJ3V0ZjgnKSlcclxuICAgICAgICA6IGZhbHNlO1xyXG4gICAgfSBlbHNlIGlmIChcclxuICAgICAgY3VzdG9tQ29kZS5zdGFydHNXaXRoKCdmdW5jdGlvbigpJykgfHxcclxuICAgICAgY3VzdG9tQ29kZS5zdGFydHNXaXRoKCdmdW5jdGlvbiAoKScpIHx8XHJcbiAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnKCk9PicpIHx8XHJcbiAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnKCkgPT4nKVxyXG4gICAgKSB7XHJcbiAgICAgIHJldHVybiBgKCR7Y3VzdG9tQ29kZX0pKClgO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIGN1c3RvbUNvZGUucmVwbGFjZSgvOyQvLCAnJyk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIFV0aWxpdHkgdG8gbWVhc3VyZSBlbGFwc2VkIHRpbWUgdXNpbmcgdGhlIE5vZGUuanMgcHJvY2Vzcy5ocnRpbWUoKSBtZXRob2QuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtmdW5jdGlvbigpOiBudW1iZXJ9IC0gQSBmdW5jdGlvbiB0byBjYWxjdWxhdGUgdGhlIGVsYXBzZWQgdGltZVxyXG4gKiBpbiBtaWxsaXNlY29uZHMuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbWVhc3VyZVRpbWUgPSAoKSA9PiB7XHJcbiAgY29uc3Qgc3RhcnQgPSBwcm9jZXNzLmhydGltZS5iaWdpbnQoKTtcclxuICByZXR1cm4gKCkgPT4gTnVtYmVyKHByb2Nlc3MuaHJ0aW1lLmJpZ2ludCgpIC0gc3RhcnQpIC8gMTAwMDAwMDtcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBfX2Rpcm5hbWUsXHJcbiAgY2xlYXJUZXh0LFxyXG4gIGV4cEJhY2tvZmYsXHJcbiAgZml4VHlwZSxcclxuICBoYW5kbGVSZXNvdXJjZXMsXHJcbiAgaXNDb3JyZWN0SlNPTixcclxuICBpc09iamVjdCxcclxuICBpc09iamVjdEVtcHR5LFxyXG4gIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmQsXHJcbiAgb3B0aW9uc1N0cmluZ2lmeSxcclxuICBwcmludExvZ28sXHJcbiAgcHJpbnRVc2FnZSxcclxuICByb3VuZE51bWJlcixcclxuICB0b0Jvb2xlYW4sXHJcbiAgd3JhcEFyb3VuZCxcclxuICBtZWFzdXJlVGltZVxyXG59O1xyXG4iLCIvKipcclxuICogQGZpbGVvdmVydmlld1xyXG4gKiBUaGlzIGZpbGUgaXMgcmVzcG9uc2libGUgZm9yIHBhcnNpbmcgdGhlIGVudmlyb25tZW50IHZhcmlhYmxlcyB3aXRoIHRoZSAnem9kJyBsaWJyYXJ5LlxyXG4gKiBUaGUgcGFyc2VkIGVudmlyb25tZW50IHZhcmlhYmxlcyBhcmUgdGhlbiBleHBvcnRlZCB0byBiZSB1c2VkIGluIHRoZSBhcHBsaWNhdGlvbiBhcyBcImVudnNcIi5cclxuICogV2Ugc2hvdWxkIG5vdCB1c2UgcHJvY2Vzcy5lbnYgZGlyZWN0bHkgaW4gdGhlIGFwcGxpY2F0aW9uIGFzIHRoZXNlIHdvdWxkIG5vdCBiZSBwYXJzZWQgcHJvcGVybHkuXHJcbiAqXHJcbiAqIFRoZSBlbnZpcm9ubWVudCB2YXJpYWJsZXMgYXJlIHBhcnNlZCBhbmQgdmFsaWRhdGVkIG9ubHkgb25jZSB3aGVuIHRoZSBhcHBsaWNhdGlvbiBzdGFydHMuXHJcbiAqIFdlIHNob3VsZCB3cml0ZSBhIGN1c3RvbSB2YWxpZGF0b3Igb3IgYSB0cmFuc2Zvcm1lciBmb3IgZWFjaCBvZiB0aGUgb3B0aW9ucy5cclxuICpcclxuICogRm9yIGVudnMgbm90IGRlZmluZWQgaW4gY29uZmlnLmpzIHdpdGggZGVmYXVsdHMsIHdlIGFsc28gaW5jbHVkZSBkZWZhdWx0IHZhbHVlcyBoZXJlIChQUk9YWV8uLi4pLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IHogfSBmcm9tICd6b2QnO1xyXG5pbXBvcnQgZG90ZW52IGZyb20gJ2RvdGVudic7XHJcbmRvdGVudi5jb25maWcoKTtcclxuXHJcbi8vIE9iamVjdCB3aXRoIGN1c3RvbSB2YWxpZGF0b3JzIGFuZCB0cmFuc2Zvcm1lcnMsIHRvIGF2b2lkIHJlcGV0aXRpb24gaW4gdGhlIENvbmZpZyBvYmplY3RcclxuY29uc3QgdiA9IHtcclxuICBib29sZWFuOiAoKSA9PlxyXG4gICAgelxyXG4gICAgICAuZW51bShbJ3RydWUnLCAnZmFsc2UnXSlcclxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+IHZhbHVlID09PSAndHJ1ZScpXHJcbiAgICAgIC5vcHRpb25hbCgpLFxyXG4gIGFycmF5OiAoKSA9PlxyXG4gICAgelxyXG4gICAgICAuc3RyaW5nKClcclxuICAgICAgLnRyYW5zZm9ybSgodmFsKSA9PiB2YWwuc3BsaXQoJywnKS5tYXAoKHYpID0+IHYudHJpbSgpKSlcclxuICAgICAgLm9wdGlvbmFsKClcclxufTtcclxuXHJcbmV4cG9ydCBjb25zdCBDb25maWcgPSB6Lm9iamVjdCh7XHJcbiAgLy8gaGlnaGNoYXJ0c1xyXG4gIEhJR0hDSEFSVFNfVkVSU0lPTjogelxyXG4gICAgLnN0cmluZygpXHJcbiAgICAucmVmaW5lKCh2YWx1ZSkgPT4gL14obGF0ZXN0fFxcZCsoXFwuXFxkKyl7MCwyfSkkLy50ZXN0KHZhbHVlKSwge1xyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgIFwiSElHSENIQVJUU19WRVJTSU9OIG11c3QgYmUgJ2xhdGVzdCcsIGEgbWFqb3IgdmVyc2lvbiwgb3IgaW4gdGhlIGZvcm0gWFguWVkuWlpcIlxyXG4gICAgfSlcclxuICAgIC5vcHRpb25hbCgpLCAvLyB0b2RvOiBjcmVhdGUgYW4gYXJyYXkgb2YgYXZhaWxhYmxlIEhpZ2hjaGFydHMgdmVyc2lvbnNcclxuICBISUdIQ0hBUlRTX0NETl9VUkw6IHpcclxuICAgIC5zdHJpbmcoKVxyXG4gICAgLnRyaW0oKVxyXG4gICAgLnJlZmluZSgodmFsKSA9PiB2YWwuc3RhcnRzV2l0aCgnaHR0cHM6Ly8nKSB8fCB2YWwuc3RhcnRzV2l0aCgnaHR0cDovLycpLCB7XHJcbiAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgJ0ludmFsaWQgdmFsdWUgZm9yIEhJR0hDSEFSVFNfQ0ROX1VSTC4gSXQgc2hvdWxkIHN0YXJ0IHdpdGggaHR0cDovLyBvciBodHRwczovLy4nXHJcbiAgICB9KVxyXG4gICAgLm9wdGlvbmFsKCksXHJcbiAgSElHSENIQVJUU19DT1JFX1NDUklQVFM6IHYuYXJyYXkoKSxcclxuICBISUdIQ0hBUlRTX01PRFVMRVM6IHYuYXJyYXkoKSxcclxuICBISUdIQ0hBUlRTX0lORElDQVRPUlM6IHYuYXJyYXkoKSxcclxuICBISUdIQ0hBUlRTX0ZPUkNFX0ZFVENIOiB2LmJvb2xlYW4oKSxcclxuICBISUdIQ0hBUlRTX0NBQ0hFX1BBVEg6IHouc3RyaW5nKCkub3B0aW9uYWwoKSxcclxuICBISUdIQ0hBUlRTX0FETUlOX1RPS0VOOiB6LnN0cmluZygpLm9wdGlvbmFsKCksXHJcblxyXG4gIC8vIGV4cG9ydFxyXG4gIEVYUE9SVF9UWVBFOiB6LmVudW0oWydqcGVnJywgJ3BuZycsICdwZGYnLCAnc3ZnJ10pLm9wdGlvbmFsKCksXHJcbiAgRVhQT1JUX0NPTlNUUjogelxyXG4gICAgLnN0cmluZygpXHJcbiAgICAucmVmaW5lKFxyXG4gICAgICAodmFsKSA9PlxyXG4gICAgICAgIFsnY2hhcnQnLCAnc3RvY2tDaGFydCcsICdtYXBDaGFydCcsICdnYW50dENoYXJ0J10uaW5jbHVkZXModmFsIHx8ICcnKSxcclxuICAgICAgeyBtZXNzYWdlOiAnSW52YWxpZCB2YWx1ZSBmb3IgRVhQT1JUX0NPTlNUUi4gJyB9XHJcbiAgICApXHJcbiAgICAub3B0aW9uYWwoKSxcclxuICBFWFBPUlRfREVGQVVMVF9IRUlHSFQ6IHouY29lcmNlLm51bWJlcigpLnBvc2l0aXZlKCkub3B0aW9uYWwoKSxcclxuICBFWFBPUlRfREVGQVVMVF9XSURUSDogei5jb2VyY2UubnVtYmVyKCkucG9zaXRpdmUoKS5vcHRpb25hbCgpLFxyXG4gIEVYUE9SVF9ERUZBVUxUX1NDQUxFOiB6LmNvZXJjZS5udW1iZXIoKS5wb3NpdGl2ZSgpLm9wdGlvbmFsKCksXHJcbiAgRVhQT1JUX1JBU1RFUklaQVRJT05fVElNRU9VVDogei5jb2VyY2UubnVtYmVyKCkucG9zaXRpdmUoKS5vcHRpb25hbCgpLFxyXG5cclxuICAvLyBjdXN0b21cclxuICBDVVNUT01fTE9HSUNfQUxMT1dfQ09ERV9FWEVDVVRJT046IHYuYm9vbGVhbigpLFxyXG4gIENVU1RPTV9MT0dJQ19BTExPV19GSUxFTF9SRVNPVVJDRVM6IHYuYm9vbGVhbigpLFxyXG5cclxuICAvLyBzZXJ2ZXItcmVsYXRlZFxyXG4gIFNFUlZFUl9FTkFCTEU6IHYuYm9vbGVhbigpLFxyXG4gIFNFUlZFUl9IT1NUOiB6LnN0cmluZygpLm9wdGlvbmFsKCksXHJcbiAgU0VSVkVSX1BPUlQ6IHouY29lcmNlLm51bWJlcigpLm9wdGlvbmFsKCksXHJcbiAgU0VSVkVSX0JFTkNITUFSS0lORzogdi5ib29sZWFuKCksXHJcbiAgU0VSVkVSX1NTTF9FTkFCTEU6IHYuYm9vbGVhbigpLFxyXG4gIFNFUlZFUl9TU0xfRk9SQ0U6IHYuYm9vbGVhbigpLFxyXG4gIFNFUlZFUl9TU0xfUE9SVDogei5jb2VyY2UubnVtYmVyKCkub3B0aW9uYWwoKSxcclxuICBTRVJWRVJfU1NMX0NFUlRfUEFUSDogei5zdHJpbmcoKS5vcHRpb25hbCgpLFxyXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX0VOQUJMRTogdi5ib29sZWFuKCksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfTUFYX1JFUVVFU1RTOiB6LmNvZXJjZS5udW1iZXIoKS5vcHRpb25hbCgpLFxyXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX1dJTkRPVzogei5jb2VyY2UubnVtYmVyKCkub3B0aW9uYWwoKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19ERUxBWTogei5jb2VyY2UubnVtYmVyKCkub3B0aW9uYWwoKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19UUlVTVF9QUk9YWTogdi5ib29sZWFuKCksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9LRVk6IHouc3RyaW5nKCkub3B0aW9uYWwoKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX1RPS0VOOiB6LnN0cmluZygpLm9wdGlvbmFsKCksXHJcblxyXG4gIC8vIHBvb2xcclxuICBQT09MX01JTl9XT1JLRVJTOiB6LmNvZXJjZS5udW1iZXIoKS5vcHRpb25hbCgpLFxyXG4gIFBPT0xfTUFYX1dPUktFUlM6IHouY29lcmNlLm51bWJlcigpLm9wdGlvbmFsKCksXHJcbiAgUE9PTF9XT1JLX0xJTUlUOiB6LmNvZXJjZS5udW1iZXIoKS5vcHRpb25hbCgpLFxyXG4gIFBPT0xfQUNRVUlSRV9USU1FT1VUOiB6LmNvZXJjZS5udW1iZXIoKS5vcHRpb25hbCgpLFxyXG4gIFBPT0xfQ1JFQVRFX1RJTUVPVVQ6IHouY29lcmNlLm51bWJlcigpLm9wdGlvbmFsKCksXHJcbiAgUE9PTF9ERVNUUk9ZX1RJTUVPVVQ6IHouY29lcmNlLm51bWJlcigpLm9wdGlvbmFsKCksXHJcbiAgUE9PTF9JRExFX1RJTUVPVVQ6IHouY29lcmNlLm51bWJlcigpLm9wdGlvbmFsKCksXHJcbiAgUE9PTF9DUkVBVEVfUkVUUllfSU5URVJWQUw6IHouY29lcmNlLm51bWJlcigpLm9wdGlvbmFsKCksXHJcbiAgUE9PTF9SRUFQRVJfSU5URVJWQUw6IHouY29lcmNlLm51bWJlcigpLm9wdGlvbmFsKCksXHJcbiAgUE9PTF9CRU5DSE1BUktJTkc6IHYuYm9vbGVhbigpLFxyXG4gIFBPT0xfTElTVEVOX1RPX1BST0NFU1NfRVhJVFM6IHYuYm9vbGVhbigpLFxyXG5cclxuICAvLyBsb2dnZXJcclxuICBMT0dHSU5HX0xFVkVMOiB6LmNvZXJjZVxyXG4gICAgLm51bWJlcigpXHJcbiAgICAub3B0aW9uYWwoKVxyXG4gICAgLnJlZmluZSgodmFsKSA9PiAodmFsIHx8IDQpID49IDAgJiYgKHZhbCB8fCA0KSA8PSA0LCB7XHJcbiAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgJ0ludmFsaWQgdmFsdWUgZm9yIExPR0dJTkdfTEVWRUwuIFdlIG9ubHkgYWNjZXB0IDAsIDEsIDIsIDMsIDQgYXMgbG9nZ2luZyBsZXZlbHMuJ1xyXG4gICAgfSksXHJcbiAgTE9HR0lOR19GSUxFOiB6LnN0cmluZygpLm9wdGlvbmFsKCksXHJcbiAgTE9HR0lOR19ERVNUOiB6LnN0cmluZygpLm9wdGlvbmFsKCksXHJcblxyXG4gIC8vIHVpXHJcbiAgVUlfRU5BQkxFOiB2LmJvb2xlYW4oKSxcclxuICBVSV9ST1VURTogei5zdHJpbmcoKS5vcHRpb25hbCgpLFxyXG5cclxuICAvLyBvdGhlclxyXG4gIE9USEVSX05PX0xPR086IHYuYm9vbGVhbigpLFxyXG4gIE5PREVfRU5WOiB6XHJcbiAgICAuZW51bShbJ2RldmVsb3BtZW50JywgJ3Byb2R1Y3Rpb24nLCAndGVzdCddKVxyXG4gICAgLm9wdGlvbmFsKClcclxuICAgIC5kZWZhdWx0KCdwcm9kdWN0aW9uJyksXHJcblxyXG4gIC8vIHByb3h5ICghIE5PVCBJTkNMVURFRCBJTiBDT05GSUcuSlMgISlcclxuICBQUk9YWV9TRVJWRVJfVElNRU9VVDogei5jb2VyY2UubnVtYmVyKCkucG9zaXRpdmUoKS5vcHRpb25hbCgpLmRlZmF1bHQoNTAwMCksXHJcbiAgUFJPWFlfU0VSVkVSX0hPU1Q6IHouc3RyaW5nKCkub3B0aW9uYWwoKS5kZWZhdWx0KCdsb2NhbGhvc3QnKSxcclxuICBQUk9YWV9TRVJWRVJfUE9SVDogei5jb2VyY2UubnVtYmVyKCkucG9zaXRpdmUoKS5vcHRpb25hbCgpLmRlZmF1bHQoODA4MClcclxufSk7XHJcblxyXG5leHBvcnQgY29uc3QgZW52cyA9IENvbmZpZy5wYXJzZShwcm9jZXNzLmVudik7XHJcbiIsImNsYXNzIEV4cG9ydEVycm9yIGV4dGVuZHMgRXJyb3Ige1xyXG4gIGNvbnN0cnVjdG9yKG1lc3NhZ2UpIHtcclxuICAgIHN1cGVyKCk7XHJcbiAgICB0aGlzLm1lc3NhZ2UgPSBtZXNzYWdlO1xyXG4gICAgdGhpcy5zdGFja01lc3NhZ2UgPSBtZXNzYWdlO1xyXG4gIH1cclxuXHJcbiAgc2V0RXJyb3IoZXJyb3IpIHtcclxuICAgIHRoaXMuZXJyb3IgPSBlcnJvcjtcclxuICAgIGlmIChlcnJvci5uYW1lKSB7XHJcbiAgICAgIHRoaXMubmFtZSA9IGVycm9yLm5hbWU7XHJcbiAgICB9XHJcbiAgICBpZiAoZXJyb3Iuc3RhdHVzQ29kZSkge1xyXG4gICAgICB0aGlzLnN0YXR1c0NvZGUgPSBlcnJvci5zdGF0dXNDb2RlO1xyXG4gICAgfVxyXG4gICAgaWYgKGVycm9yLnN0YWNrKSB7XHJcbiAgICAgIHRoaXMuc3RhY2tNZXNzYWdlID0gZXJyb3IubWVzc2FnZTtcclxuICAgICAgdGhpcy5zdGFjayA9IGVycm9yLnN0YWNrO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIHRoaXM7XHJcbiAgfVxyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCBFeHBvcnRFcnJvcjtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vLyBUaGUgY2FjaGUgbWFuYWdlciBtYW5hZ2VzIHRoZSBIaWdoY2hhcnRzIGxpYnJhcnkgYW5kIGl0cyBkZXBlbmRlbmNpZXMuXHJcbi8vIFRoZSBjYWNoZSBpdHNlbGYgaXMgc3RvcmVkIGluIC5jYWNoZSwgYW5kIGlzIGNoZWNrZWQgYnkgdGhlIGNvbmZpZyBzeXN0ZW1cclxuLy8gYmVmb3JlIHN0YXJ0aW5nIHRoZSBzZXJ2aWNlXHJcblxyXG5pbXBvcnQgeyBleGlzdHNTeW5jLCBta2RpclN5bmMsIHJlYWRGaWxlU3luYywgd3JpdGVGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IHsgSHR0cHNQcm94eUFnZW50IH0gZnJvbSAnaHR0cHMtcHJveHktYWdlbnQnO1xyXG5cclxuaW1wb3J0IHsgZmV0Y2ggfSBmcm9tICcuL2ZldGNoLmpzJztcclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBfX2Rpcm5hbWUgfSBmcm9tICcuL3V0aWxzLmpzJztcclxuaW1wb3J0IHsgZW52cyB9IGZyb20gJy4vZW52cy5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuY29uc3QgY2FjaGUgPSB7XHJcbiAgY2RuVVJMOiAnaHR0cHM6Ly9jb2RlLmhpZ2hjaGFydHMuY29tLycsXHJcbiAgYWN0aXZlTWFuaWZlc3Q6IHt9LFxyXG4gIHNvdXJjZXM6ICcnLFxyXG4gIGhjVmVyc2lvbjogJydcclxufTtcclxuXHJcbi8vIFRPRE86IFRoZSBjb25maWcgc2hvdWxkIGJlIGFjY2Vzc3NpYmxlIGdsb2JhbGx5IHNvIHdlIGRvbid0IGhhdmUgdG8gZG8gdGhpcyBzb3J0IG9mIHRoaW5nLi5cclxubGV0IGFwcGxpZWRDb25maWcgPSBmYWxzZTtcclxuXHJcbi8qKlxyXG4gKiBFeHRyYWN0cyBhbmQgY2FjaGVzIHRoZSBIaWdoY2hhcnRzIHZlcnNpb24gZnJvbSB0aGUgc291cmNlcyBzdHJpbmcuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBleHRyYWN0ZWQgSGlnaGNoYXJ0cyB2ZXJzaW9uLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGV4dHJhY3RWZXJzaW9uID0gKGNhY2hlKSA9PiB7XHJcbiAgcmV0dXJuIGNhY2hlLnNvdXJjZXNcclxuICAgIC5zdWJzdHJpbmcoMCwgY2FjaGUuc291cmNlcy5pbmRleE9mKCcqLycpKVxyXG4gICAgLnJlcGxhY2UoJy8qJywgJycpXHJcbiAgICAucmVwbGFjZSgnKi8nLCAnJylcclxuICAgIC5yZXBsYWNlKC9cXG4vZywgJycpXHJcbiAgICAudHJpbSgpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEV4dHJhY3RzIHRoZSBIaWdoY2hhcnRzIG1vZHVsZSBuYW1lIGJhc2VkIG9uIHRoZSBzY3JpcHRQYXRoLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGV4dHJhY3RNb2R1bGVOYW1lID0gKHNjcmlwdFBhdGgpID0+IHtcclxuICByZXR1cm4gc2NyaXB0UGF0aC5yZXBsYWNlKFxyXG4gICAgLyguKilcXC98KC4qKW1vZHVsZXNcXC98c3RvY2tcXC8oLiopaW5kaWNhdG9yc1xcL3xtYXBzXFwvKC4qKW1vZHVsZXNcXC8vZ2ksXHJcbiAgICAnJ1xyXG4gICk7XHJcbn07XHJcblxyXG4vKipcclxuICogU2F2ZXMgdGhlIHByb3ZpZGVkIGNvbmZpZ3VyYXRpb24gYW5kIGZldGNoZWQgbW9kdWxlcyB0byB0aGUgY2FjaGUgbWFuaWZlc3RcclxuICogZmlsZS5cclxuICpcclxuICogQHBhcmFtIHtvYmplY3R9IGNvbmZpZyAtIEhpZ2hjaGFydHMtcmVsYXRlZCBjb25maWd1cmF0aW9uIG9iamVjdC5cclxuICogQHBhcmFtIHtvYmplY3R9IGZldGNoZWRNb2R1bGVzIC0gQW4gb2JqZWN0IHRoYXQgY29udGFpbnMgbWFwcGVkIG5hbWVzIG9mXHJcbiAqIGZldGNoZWQgSGlnaGNoYXJ0cyBtb2R1bGVzIHRvIHVzZS5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiBhbiBlcnJvciBvY2N1cnMgd2hpbGUgd3JpdGluZ1xyXG4gKiB0aGUgY2FjaGUgbWFuaWZlc3QuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2F2ZUNvbmZpZ1RvTWFuaWZlc3QgPSBhc3luYyAoY29uZmlnLCBmZXRjaGVkTW9kdWxlcykgPT4ge1xyXG4gIGNvbnN0IG5ld01hbmlmZXN0ID0ge1xyXG4gICAgdmVyc2lvbjogY29uZmlnLnZlcnNpb24sXHJcbiAgICBtb2R1bGVzOiBmZXRjaGVkTW9kdWxlcyB8fCB7fVxyXG4gIH07XHJcblxyXG4gIC8vIFVwZGF0ZSBjYWNoZSBvYmplY3Qgd2l0aCB0aGUgY3VycmVudCBtb2R1bGVzXHJcbiAgY2FjaGUuYWN0aXZlTWFuaWZlc3QgPSBuZXdNYW5pZmVzdDtcclxuXHJcbiAgbG9nKDMsICdbY2FjaGVdIFdyaXRpbmcgYSBuZXcgbWFuaWZlc3QuJyk7XHJcbiAgdHJ5IHtcclxuICAgIHdyaXRlRmlsZVN5bmMoXHJcbiAgICAgIGpvaW4oX19kaXJuYW1lLCBjb25maWcuY2FjaGVQYXRoLCAnbWFuaWZlc3QuanNvbicpLFxyXG4gICAgICBKU09OLnN0cmluZ2lmeShuZXdNYW5pZmVzdCksXHJcbiAgICAgICd1dGY4J1xyXG4gICAgKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbY2FjaGVdIEVycm9yIHdyaXRpbmcgdGhlIGNhY2hlIG1hbmlmZXN0LicpLnNldEVycm9yKFxyXG4gICAgICBlcnJvclxyXG4gICAgKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogRmV0Y2hlcyBhIHNpbmdsZSBzY3JpcHQgYW5kIHVwZGF0ZXMgdGhlIGZldGNoZWRNb2R1bGVzIGFjY29yZGluZ2x5LlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gc2NyaXB0IC0gQSBwYXRoIHRvIHNjcmlwdCB0byBnZXQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwcm94eUFnZW50IC0gVGhlIHByb3h5IGFnZW50IHRvIHVzZSBmb3IgYSByZXF1ZXN0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZmV0Y2hlZE1vZHVsZXMgLSBBbiBvYmplY3Qgd2hpY2ggdHJhY2tzIHdoaWNoIEhpZ2hjaGFydHMgbW9kdWxlcyBoYXZlIGJlZW4gZmV0Y2hlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBzaG91bGRUaHJvd0Vycm9yIC0gQSBmbGFnIHRvIGluZGljYXRlIGlmIHRoZSBlcnJvciBzaG91bGQgYmUgdGhyb3duLiBUaGlzIHNob3VsZCBiZSB1c2VkIG9ubHkgZm9yIHRoZSBjb3JlIHNjcmlwdHMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZz59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIHRleHQgcmVwcmVzZW50YXRpb25cclxuICogb2YgdGhlIGZldGNoZWQgc2NyaXB0LlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIHRoZXJlIGlzIGEgcHJvYmxlbSB3aXRoXHJcbiAqIGZldGNoaW5nIHRoZSBzY3JpcHQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZmV0Y2hBbmRQcm9jZXNzU2NyaXB0ID0gYXN5bmMgKFxyXG4gIHNjcmlwdCxcclxuICBwcm94eUFnZW50LFxyXG4gIGZldGNoZWRNb2R1bGVzLFxyXG4gIHNob3VsZFRocm93RXJyb3IgPSBmYWxzZVxyXG4pID0+IHtcclxuICAvLyBHZXQgcmlkIG9mIHRoZSAuanMgZnJvbSB0aGUgY3VzdG9tIHN0cmluZ3NcclxuICBpZiAoc2NyaXB0LmVuZHNXaXRoKCcuanMnKSkge1xyXG4gICAgc2NyaXB0ID0gc2NyaXB0LnN1YnN0cmluZygwLCBzY3JpcHQubGVuZ3RoIC0gMyk7XHJcbiAgfVxyXG5cclxuICBsb2coNCwgYFtjYWNoZV0gRmV0Y2hpbmcgc2NyaXB0IC0gJHtzY3JpcHR9LmpzYCk7XHJcblxyXG4gIC8vIElmIGV4aXN0cywgYWRkIHByb3h5IGFnZW50IHRvIHJlcXVlc3Qgb3B0aW9uc1xyXG4gIGNvbnN0IHJlcXVlc3RPcHRpb25zID0gcHJveHlBZ2VudFxyXG4gICAgPyB7XHJcbiAgICAgICAgYWdlbnQ6IHByb3h5QWdlbnQsXHJcbiAgICAgICAgdGltZW91dDogZW52cy5QUk9YWV9TRVJWRVJfVElNRU9VVFxyXG4gICAgICB9XHJcbiAgICA6IHt9O1xyXG5cclxuICAvLyBGZXRjaCB0aGUgc2NyaXB0XHJcbiAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaChgJHtzY3JpcHR9LmpzYCwgcmVxdWVzdE9wdGlvbnMpO1xyXG5cclxuICAvLyBJZiBPSywgcmV0dXJuIGl0cyB0ZXh0IHJlcHJlc2VudGF0aW9uXHJcbiAgaWYgKHJlc3BvbnNlLnN0YXR1c0NvZGUgPT09IDIwMCAmJiB0eXBlb2YgcmVzcG9uc2UudGV4dCA9PSAnc3RyaW5nJykge1xyXG4gICAgaWYgKGZldGNoZWRNb2R1bGVzKSB7XHJcbiAgICAgIGNvbnN0IG1vZHVsZU5hbWUgPSBleHRyYWN0TW9kdWxlTmFtZShzY3JpcHQpO1xyXG4gICAgICBmZXRjaGVkTW9kdWxlc1ttb2R1bGVOYW1lXSA9IDE7XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIHJlc3BvbnNlLnRleHQ7XHJcbiAgfVxyXG5cclxuICBpZiAoc2hvdWxkVGhyb3dFcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICBgQ291bGQgbm90IGZldGNoIHRoZSAke3NjcmlwdH0uanMuIFRoZSBzY3JpcHQgbWlnaHQgbm90IGV4aXN0IGluIHRoZSByZXF1ZXN0ZWQgdmVyc2lvbiAoc3RhdHVzIGNvZGU6ICR7cmVzcG9uc2Uuc3RhdHVzQ29kZX0pLmBcclxuICAgICkuc2V0RXJyb3IocmVzcG9uc2UpO1xyXG4gIH0gZWxzZSB7XHJcbiAgICBsb2coXHJcbiAgICAgIDIsXHJcbiAgICAgIGBbY2FjaGVdIENvdWxkIG5vdCBmZXRjaCB0aGUgJHtzY3JpcHR9LmpzLiBUaGUgc2NyaXB0IG1pZ2h0IG5vdCBleGlzdCBpbiB0aGUgcmVxdWVzdGVkIHZlcnNpb24uYFxyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIHJldHVybiAnJztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBGZXRjaGVzIEhpZ2hjaGFydHMgc2NyaXB0cyBhbmQgY3VzdG9tU2NyaXB0cyBmcm9tIHRoZSBnaXZlbiBDRE5zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gc2NyaXB0cyAtIEFycmF5IG9mIEhpZ2hjaGFydHMgbW9kdWxlcyB0byBmZXRjaC5cclxuICogQHBhcmFtIHtzdHJpbmd9IGN1c3RvbVNjcmlwdHMgLSBBcnJheSBvZiBjdXN0b20gc2NyaXB0IHBhdGhzIHRvIGZldGNoIChmdWxsIFVSTHMpLlxyXG4gKiBAcGFyYW0ge29iamVjdH0gcHJveHlBZ2VudCAtIFRoZSBwcm94eSBhZ2VudCB0byB1c2UgZm9yIGEgcmVxdWVzdC5cclxuICogQHBhcmFtIHtvYmplY3R9IGZldGNoZWRNb2R1bGVzIC0gQW4gb2JqZWN0IHdoaWNoIHRyYWNrcyB3aGljaCBIaWdoY2hhcnRzIG1vZHVsZXMgaGF2ZSBiZWVuIGZldGNoZWQuXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZz59IFRoZSBmZXRjaGVkIHNjcmlwdHMgY29udGVudCBqb2luZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZmV0Y2hTY3JpcHRzID0gYXN5bmMgKFxyXG4gIGNvcmVTY3JpcHRzLFxyXG4gIG1vZHVsZVNjcmlwdHMsXHJcbiAgY3VzdG9tU2NyaXB0cyxcclxuICBjZG5VUkwsXHJcbiAgcHJveHlBZ2VudCxcclxuICBmZXRjaGVkTW9kdWxlc1xyXG4pID0+IHtcclxuICBjb25zdCBhbGxGZXRjaFByb21pc2VzID0gW1xyXG4gICAgLi4uY29yZVNjcmlwdHMubWFwKChzY3JpcHQpID0+XHJcbiAgICAgIGZldGNoQW5kUHJvY2Vzc1NjcmlwdChcclxuICAgICAgICBgJHtjZG5VUkx9JHtzY3JpcHR9YCxcclxuICAgICAgICBwcm94eUFnZW50LFxyXG4gICAgICAgIGZldGNoZWRNb2R1bGVzLFxyXG4gICAgICAgIHRydWVcclxuICAgICAgKVxyXG4gICAgKSxcclxuICAgIC4uLm1vZHVsZVNjcmlwdHMubWFwKChzY3JpcHQpID0+XHJcbiAgICAgIGZldGNoQW5kUHJvY2Vzc1NjcmlwdChgJHtjZG5VUkx9JHtzY3JpcHR9YCwgcHJveHlBZ2VudCwgZmV0Y2hlZE1vZHVsZXMpXHJcbiAgICApLFxyXG4gICAgLi4uY3VzdG9tU2NyaXB0cy5tYXAoKHNjcmlwdCkgPT5cclxuICAgICAgZmV0Y2hBbmRQcm9jZXNzU2NyaXB0KGAke3NjcmlwdH1gLCBwcm94eUFnZW50KVxyXG4gICAgKVxyXG4gIF07XHJcblxyXG4gIGNvbnN0IGZldGNoZWRTY3JpcHRzID0gYXdhaXQgUHJvbWlzZS5hbGwoYWxsRmV0Y2hQcm9taXNlcyk7XHJcbiAgcmV0dXJuIGZldGNoZWRTY3JpcHRzLmpvaW4oJztcXG4nKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBVcGRhdGVzIHRoZSBsb2NhbCBjYWNoZSB3aXRoIEhpZ2hjaGFydHMgc2NyaXB0cyBhbmQgdGhlaXIgdmVyc2lvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjb25maWcgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZyBpbmZvcm1hdGlvblxyXG4gKiBhYm91dCBzY3JpcHRzIGFuZCBtb2R1bGVzLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gc291cmNlUGF0aCAtIFRoZSBwYXRoIHRvIHRoZSBzb3VyY2UgZmlsZSBpbiB0aGUgY2FjaGUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPG9iamVjdD59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gYW4gb2JqZWN0IHJlcHJlc2VudGluZ1xyXG4gKiB0aGUgZmV0Y2hlZCBtb2R1bGVzLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIHRoZXJlIGlzIGFuIGlzc3VlIHVwZGF0aW5nXHJcbiAqIHRoZSBsb2NhbCBIaWdoY2hhcnRzIGNhY2hlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHVwZGF0ZUNhY2hlID0gYXN5bmMgKGNvbmZpZywgc291cmNlUGF0aCkgPT4ge1xyXG4gIGNvbnN0IHsgY29yZVNjcmlwdHMsIG1vZHVsZXMsIGluZGljYXRvcnMsIHNjcmlwdHM6IGN1c3RvbVNjcmlwdHMgfSA9IGNvbmZpZztcclxuICBjb25zdCBoY1ZlcnNpb24gPVxyXG4gICAgY29uZmlnLnZlcnNpb24gPT09ICdsYXRlc3QnIHx8ICFjb25maWcudmVyc2lvbiA/ICcnIDogYCR7Y29uZmlnLnZlcnNpb259L2A7XHJcblxyXG4gIGxvZyhcclxuICAgIDMsXHJcbiAgICBgW2NhY2hlXSBVcGRhdGluZyBjYWNoZSB2ZXJzaW9uIHRvIEhpZ2hjaGFydHM6ICR7aGNWZXJzaW9uIHx8ICdsYXRlc3QnfS5gXHJcbiAgKTtcclxuXHJcbiAgLy8gQ29uZmlndXJlIHByb3h5IGlmIGV4aXN0c1xyXG4gIGxldCBwcm94eUFnZW50O1xyXG4gIGNvbnN0IHByb3h5SG9zdCA9IHByb2Nlc3MuZW52WydQUk9YWV9TRVJWRVJfSE9TVCddO1xyXG4gIGNvbnN0IHByb3h5UG9ydCA9IHByb2Nlc3MuZW52WydQUk9YWV9TRVJWRVJfUE9SVCddO1xyXG5cclxuICAvLyBUcnkgdG8gY3JlYXRlIGEgUHJveHkgQWdlbnRcclxuICBpZiAocHJveHlIb3N0ICYmIHByb3h5UG9ydCkge1xyXG4gICAgdHJ5IHtcclxuICAgICAgcHJveHlBZ2VudCA9IG5ldyBIdHRwc1Byb3h5QWdlbnQoe1xyXG4gICAgICAgIGhvc3Q6IHByb3h5SG9zdCxcclxuICAgICAgICBwb3J0OiArcHJveHlQb3J0XHJcbiAgICAgIH0pO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbY2FjaGVdIENvdWxkIG5vdCBjcmVhdGUgYSBQcm94eSBBZ2VudC4nKS5zZXRFcnJvcihcclxuICAgICAgICBlcnJvclxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgY29uc3QgZmV0Y2hlZE1vZHVsZXMgPSB7fTtcclxuICB0cnkge1xyXG4gICAgY2FjaGUuc291cmNlcyA9IGF3YWl0IGZldGNoU2NyaXB0cyhcclxuICAgICAgWy4uLmNvcmVTY3JpcHRzLm1hcCgoYykgPT4gYCR7aGNWZXJzaW9ufSR7Y31gKV0sXHJcbiAgICAgIFtcclxuICAgICAgICAuLi5tb2R1bGVzLm1hcCgobSkgPT5cclxuICAgICAgICAgIG0gPT09ICdtYXAnXHJcbiAgICAgICAgICAgID8gYG1hcHMvJHtoY1ZlcnNpb259bW9kdWxlcy8ke219YFxyXG4gICAgICAgICAgICA6IGAke2hjVmVyc2lvbn1tb2R1bGVzLyR7bX1gXHJcbiAgICAgICAgKSxcclxuICAgICAgICAuLi5pbmRpY2F0b3JzLm1hcCgoaSkgPT4gYHN0b2NrLyR7aGNWZXJzaW9ufWluZGljYXRvcnMvJHtpfWApXHJcbiAgICAgIF0sXHJcbiAgICAgIGN1c3RvbVNjcmlwdHMsXHJcbiAgICAgIGNvbmZpZy5jZG5VUkwgfHwgY2FjaGUuY2RuVVJMLFxyXG4gICAgICBwcm94eUFnZW50LFxyXG4gICAgICBmZXRjaGVkTW9kdWxlc1xyXG4gICAgKTtcclxuXHJcbiAgICBjYWNoZS5oY1ZlcnNpb24gPSBleHRyYWN0VmVyc2lvbihjYWNoZSk7XHJcblxyXG4gICAgLy8gU2F2ZSB0aGUgZmV0Y2hlZCBtb2R1bGVzIGludG8gY2FjaGVzJyBzb3VyY2UgSlNPTlxyXG4gICAgd3JpdGVGaWxlU3luYyhzb3VyY2VQYXRoLCBjYWNoZS5zb3VyY2VzKTtcclxuICAgIHJldHVybiBmZXRjaGVkTW9kdWxlcztcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW2NhY2hlXSBVbmFibGUgdG8gdXBkYXRlIHRoZSBsb2NhbCBIaWdoY2hhcnRzIGNhY2hlLidcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBVcGRhdGVzIHRoZSBIaWdoY2hhcnRzIHZlcnNpb24gaW4gdGhlIGFwcGxpZWQgY29uZmlndXJhdGlvbiBhbmQgY2hlY2tzXHJcbiAqIHRoZSBjYWNoZSBmb3IgdGhlIG5ldyB2ZXJzaW9uLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gbmV3VmVyc2lvbiAtIFRoZSBuZXcgSGlnaGNoYXJ0cyB2ZXJzaW9uIHRvIGJlIGFwcGxpZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPChvYmplY3R8Ym9vbGVhbik+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSB1cGRhdGVkXHJcbiAqIGNvbmZpZ3VyYXRpb24gd2l0aCB0aGUgbmV3IHZlcnNpb24sIG9yIGZhbHNlIGlmIG5vIGFwcGxpZWQgY29uZmlndXJhdGlvblxyXG4gKiBleGlzdHMuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgdXBkYXRlVmVyc2lvbiA9IGFzeW5jIChuZXdWZXJzaW9uKSA9PlxyXG4gIGFwcGxpZWRDb25maWdcclxuICAgID8gYXdhaXQgY2hlY2tBbmRVcGRhdGVDYWNoZShcclxuICAgICAgICBPYmplY3QuYXNzaWduKGFwcGxpZWRDb25maWcsIHtcclxuICAgICAgICAgIHZlcnNpb246IG5ld1ZlcnNpb25cclxuICAgICAgICB9KVxyXG4gICAgICApXHJcbiAgICA6IGZhbHNlO1xyXG5cclxuLyoqXHJcbiAqIENoZWNrcyB0aGUgY2FjaGUgZm9yIEhpZ2hjaGFydHMgZGVwZW5kZW5jaWVzLCB1cGRhdGVzIHRoZSBjYWNoZSBpZiBuZWVkZWQsXHJcbiAqIGFuZCBsb2FkcyB0aGUgc291cmNlcy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZyAtIEhpZ2hjaGFydHMtcmVsYXRlZCBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nIGluZm9ybWF0aW9uXHJcbiAqIGFib3V0IHNjcmlwdHMgYW5kIG1vZHVsZXMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBjYWNoZSBpcyBjaGVja2VkXHJcbiAqIGFuZCB1cGRhdGVkLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIHRoZXJlIGlzIGFuIGlzc3VlIHVwZGF0aW5nXHJcbiAqIG9yIHJlYWRpbmcgdGhlIGNhY2hlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGNoZWNrQW5kVXBkYXRlQ2FjaGUgPSBhc3luYyAoY29uZmlnKSA9PiB7XHJcbiAgY29uc3QgY2FjaGVQYXRoID0gam9pbihfX2Rpcm5hbWUsIGNvbmZpZy5jYWNoZVBhdGgpO1xyXG5cclxuICBsZXQgZmV0Y2hlZE1vZHVsZXM7XHJcbiAgLy8gUHJlcGFyZSBwYXRocyB0byBtYW5pZmVzdCBhbmQgc291cmNlcyBmcm9tIHRoZSAuY2FjaGUgZm9sZGVyXHJcbiAgY29uc3QgbWFuaWZlc3RQYXRoID0gam9pbihjYWNoZVBhdGgsICdtYW5pZmVzdC5qc29uJyk7XHJcbiAgY29uc3Qgc291cmNlUGF0aCA9IGpvaW4oY2FjaGVQYXRoLCAnc291cmNlcy5qcycpO1xyXG5cclxuICAvLyBUT0RPOiBkZWFsIHdpdGggdHJ5aW5nIHRvIHN3aXRjaCB0byB0aGUgcnVubmluZyB2ZXJzaW9uXHJcbiAgLy8gY29uc3QgYWN0aXZlVmVyc2lvbiA9IGFwcGxpZWRDb25maWcgPyBhcHBsaWVkQ29uZmlnLnZlcnNpb24gOiBmYWxzZTtcclxuXHJcbiAgYXBwbGllZENvbmZpZyA9IGNvbmZpZztcclxuXHJcbiAgLy8gQ3JlYXRlIHRoZSBjYWNoZSBkZXN0aW5hdGlvbiBpZiBpdCBkb2Vzbid0IGV4aXN0IGFscmVhZHlcclxuICAhZXhpc3RzU3luYyhjYWNoZVBhdGgpICYmIG1rZGlyU3luYyhjYWNoZVBhdGgpO1xyXG5cclxuICAvLyBGZXRjaCBhbGwgdGhlIHNjcmlwdHMgZWl0aGVyIGlmIG1hbmlmZXN0Lmpzb24gZG9lcyBub3QgZXhpc3RcclxuICAvLyBvciBpZiB0aGUgZm9yY2VGZXRjaCBvcHRpb24gaXMgZW5hYmxlZFxyXG4gIGlmICghZXhpc3RzU3luYyhtYW5pZmVzdFBhdGgpIHx8IGNvbmZpZy5mb3JjZUZldGNoKSB7XHJcbiAgICBsb2coMywgJ1tjYWNoZV0gRmV0Y2hpbmcgYW5kIGNhY2hpbmcgSGlnaGNoYXJ0cyBkZXBlbmRlbmNpZXMuJyk7XHJcbiAgICBmZXRjaGVkTW9kdWxlcyA9IGF3YWl0IHVwZGF0ZUNhY2hlKGNvbmZpZywgc291cmNlUGF0aCk7XHJcbiAgfSBlbHNlIHtcclxuICAgIGxldCByZXF1ZXN0VXBkYXRlID0gZmFsc2U7XHJcblxyXG4gICAgLy8gUmVhZCB0aGUgbWFuaWZlc3QgSlNPTlxyXG4gICAgY29uc3QgbWFuaWZlc3QgPSBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhtYW5pZmVzdFBhdGgpKTtcclxuXHJcbiAgICAvLyBDaGVjayBpZiB0aGUgbW9kdWxlcyBpcyBhbiBhcnJheSwgaWYgc28sIHdlIHJld3JpdGUgaXQgdG8gYSBtYXAgdG8gbWFrZVxyXG4gICAgLy8gaXQgZWFzaWVyIHRvIHJlc29sdmUgbW9kdWxlcy5cclxuICAgIGlmIChtYW5pZmVzdC5tb2R1bGVzICYmIEFycmF5LmlzQXJyYXkobWFuaWZlc3QubW9kdWxlcykpIHtcclxuICAgICAgY29uc3QgbW9kdWxlTWFwID0ge307XHJcbiAgICAgIG1hbmlmZXN0Lm1vZHVsZXMuZm9yRWFjaCgobSkgPT4gKG1vZHVsZU1hcFttXSA9IDEpKTtcclxuICAgICAgbWFuaWZlc3QubW9kdWxlcyA9IG1vZHVsZU1hcDtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCB7IG1vZHVsZXMsIGNvcmVTY3JpcHRzLCBpbmRpY2F0b3JzIH0gPSBjb25maWc7XHJcbiAgICBjb25zdCBudW1iZXJPZk1vZHVsZXMgPVxyXG4gICAgICBtb2R1bGVzLmxlbmd0aCArIGNvcmVTY3JpcHRzLmxlbmd0aCArIGluZGljYXRvcnMubGVuZ3RoO1xyXG5cclxuICAgIC8vIENvbXBhcmUgdGhlIGxvYWRlZCBjb25maWcgd2l0aCB0aGUgY29udGVudHMgaW4gY2FjaGUuXHJcbiAgICAvLyBJZiB0aGVyZSBhcmUgY2hhbmdlcywgZmV0Y2ggcmVxdWVzdGVkIG1vZHVsZXMgYW5kIHByb2R1Y3RzLFxyXG4gICAgLy8gYW5kIGJha2UgdGhlbSBpbnRvIGEgZ2lhbnQgYmxvYi4gU2F2ZSB0aGUgYmxvYi5cclxuICAgIGlmIChtYW5pZmVzdC52ZXJzaW9uICE9PSBjb25maWcudmVyc2lvbikge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgMixcclxuICAgICAgICAnW2NhY2hlXSBBIEhpZ2hjaGFydHMgdmVyc2lvbiBtaXNtYXRjaCBpbiB0aGUgY2FjaGUsIG5lZWQgdG8gcmUtZmV0Y2guJ1xyXG4gICAgICApO1xyXG4gICAgICByZXF1ZXN0VXBkYXRlID0gdHJ1ZTtcclxuICAgIH0gZWxzZSBpZiAoT2JqZWN0LmtleXMobWFuaWZlc3QubW9kdWxlcyB8fCB7fSkubGVuZ3RoICE9PSBudW1iZXJPZk1vZHVsZXMpIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDIsXHJcbiAgICAgICAgJ1tjYWNoZV0gVGhlIGNhY2hlIGFuZCB0aGUgcmVxdWVzdGVkIG1vZHVsZXMgZG8gbm90IG1hdGNoLCBuZWVkIHRvIHJlLWZldGNoLidcclxuICAgICAgKTtcclxuICAgICAgcmVxdWVzdFVwZGF0ZSA9IHRydWU7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBDaGVjayBlYWNoIG1vZHVsZSwgaWYgYW55dGhpbmcgaXMgbWlzc2luZyByZWZldGNoIGV2ZXJ5dGhpbmdcclxuICAgICAgcmVxdWVzdFVwZGF0ZSA9IChjb25maWcubW9kdWxlcyB8fCBbXSkuc29tZSgobW9kdWxlTmFtZSkgPT4ge1xyXG4gICAgICAgIGlmICghbWFuaWZlc3QubW9kdWxlc1ttb2R1bGVOYW1lXSkge1xyXG4gICAgICAgICAgbG9nKFxyXG4gICAgICAgICAgICAyLFxyXG4gICAgICAgICAgICBgW2NhY2hlXSBUaGUgJHttb2R1bGVOYW1lfSBpcyBtaXNzaW5nIGluIHRoZSBjYWNoZSwgbmVlZCB0byByZS1mZXRjaC5gXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgICAgfVxyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAocmVxdWVzdFVwZGF0ZSkge1xyXG4gICAgICBmZXRjaGVkTW9kdWxlcyA9IGF3YWl0IHVwZGF0ZUNhY2hlKGNvbmZpZywgc291cmNlUGF0aCk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBsb2coMywgJ1tjYWNoZV0gRGVwZW5kZW5jeSBjYWNoZSBpcyB1cCB0byBkYXRlLCBwcm9jZWVkaW5nLicpO1xyXG5cclxuICAgICAgLy8gTG9hZCB0aGUgc291cmNlc1xyXG4gICAgICBjYWNoZS5zb3VyY2VzID0gcmVhZEZpbGVTeW5jKHNvdXJjZVBhdGgsICd1dGY4Jyk7XHJcblxyXG4gICAgICAvLyBHZXQgY3VycmVudCBtb2R1bGVzIG1hcFxyXG4gICAgICBmZXRjaGVkTW9kdWxlcyA9IG1hbmlmZXN0Lm1vZHVsZXM7XHJcblxyXG4gICAgICBjYWNoZS5oY1ZlcnNpb24gPSBleHRyYWN0VmVyc2lvbihjYWNoZSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBGaW5hbGx5LCBzYXZlIHRoZSBuZXcgbWFuaWZlc3QsIHdoaWNoIGlzIGJhc2ljYWxseSBvdXIgY3VycmVudCBjb25maWdcclxuICAvLyBpbiBhIHNsaWdodGx5IGRpZmZlcmVudCBmb3JtYXRcclxuICBhd2FpdCBzYXZlQ29uZmlnVG9NYW5pZmVzdChjb25maWcsIGZldGNoZWRNb2R1bGVzKTtcclxufTtcclxuXHJcbmV4cG9ydCBjb25zdCBnZXRDYWNoZVBhdGggPSAoKSA9PiB7XHJcbiAgcmV0dXJuIGpvaW4oX19kaXJuYW1lLCBhcHBsaWVkQ29uZmlnLmNhY2hlUGF0aCk7XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgY2hlY2tBbmRVcGRhdGVDYWNoZSxcclxuICBnZXRDYWNoZVBhdGgsXHJcbiAgdXBkYXRlVmVyc2lvbixcclxuICBnZXRDYWNoZTogKCkgPT4gY2FjaGUsXHJcbiAgaGlnaGNoYXJ0czogKCkgPT4gY2FjaGUuc291cmNlcyxcclxuICB2ZXJzaW9uOiAoKSA9PiBjYWNoZS5oY1ZlcnNpb25cclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyBleGlzdHNTeW5jLCByZWFkRmlsZVN5bmMsIHByb21pc2VzIGFzIGZzUHJvbWlzZXMgfSBmcm9tICdmcyc7XHJcblxyXG5pbXBvcnQgcHJvbXB0cyBmcm9tICdwcm9tcHRzJztcclxuXHJcbmltcG9ydCB7XHJcbiAgYWJzb2x1dGVQcm9wcyxcclxuICBkZWZhdWx0Q29uZmlnLFxyXG4gIG5lc3RlZEFyZ3MsXHJcbiAgcHJvbXB0c0NvbmZpZ1xyXG59IGZyb20gJy4vc2NoZW1hcy9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgZGVlcENvcHksIGlzT2JqZWN0LCBwcmludFVzYWdlLCB0b0Jvb2xlYW4gfSBmcm9tICcuL3V0aWxzLmpzJztcclxuaW1wb3J0IHsgZW52cyB9IGZyb20gJy4vZW52cy5qcyc7XHJcblxyXG5sZXQgZ2VuZXJhbE9wdGlvbnMgPSB7fTtcclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgYW5kIHJldHVybnMgdGhlIGdlbmVyYWwgb3B0aW9ucyBmb3IgdGhlIGV4cG9ydCBwcm9jZXNzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgZ2VuZXJhbCBvcHRpb25zIG9iamVjdC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBnZXRPcHRpb25zID0gKCkgPT4gZ2VuZXJhbE9wdGlvbnM7XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgYW5kIHNldHMgdGhlIGdlbmVyYWwgb3B0aW9ucyBmb3IgdGhlIHNlcnZlciBpbnN0YWNlLCBrZWVwaW5nXHJcbiAqIHRoZSBwcmluY2lwbGUgb2YgdGhlIG9wdGlvbnMgbG9hZCBwcmlvcml0eS4gSXQgYWNjZXB0cyBvcHRpb25hbCB1c2VyT3B0aW9uc1xyXG4gKiBhbmQgYXJncyBmcm9tIHRoZSBDTEkuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSB1c2VyT3B0aW9ucyAtIFVzZXItcHJvdmlkZWQgb3B0aW9ucyBmb3IgY3VzdG9taXphdGlvbi5cclxuICogQHBhcmFtIHtBcnJheX0gYXJncyAtIENvbW1hbmQtbGluZSBhcmd1bWVudHMgZm9yIGFkZGl0aW9uYWwgY29uZmlndXJhdGlvblxyXG4gKiAoQ0xJIHVzYWdlKS5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIHVwZGF0ZWQgZ2VuZXJhbCBvcHRpb25zIG9iamVjdC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBzZXRPcHRpb25zID0gKHVzZXJPcHRpb25zLCBhcmdzKSA9PiB7XHJcbiAgLy8gT25seSBmb3IgdGhlIENMSSB1c2FnZVxyXG4gIGlmIChhcmdzPy5sZW5ndGgpIHtcclxuICAgIC8vIEdldCB0aGUgYWRkaXRpb25hbCBvcHRpb25zIGZyb20gdGhlIGN1c3RvbSBKU09OIGZpbGVcclxuICAgIGdlbmVyYWxPcHRpb25zID0gbG9hZENvbmZpZ0ZpbGUoYXJncyk7XHJcbiAgfVxyXG5cclxuICAvLyBVcGRhdGUgdGhlIGRlZmF1bHQgY29uZmlnIHdpdGggYSBjb3JyZWN0IG9wdGlvbiB2YWx1ZXNcclxuICB1cGRhdGVEZWZhdWx0Q29uZmlnKGRlZmF1bHRDb25maWcsIGdlbmVyYWxPcHRpb25zKTtcclxuXHJcbiAgLy8gU2V0IHZhbHVlcyBmb3Igc2VydmVyJ3Mgb3B0aW9ucyBhbmQgcmV0dXJucyB0aGVtXHJcbiAgZ2VuZXJhbE9wdGlvbnMgPSBpbml0T3B0aW9ucyhkZWZhdWx0Q29uZmlnKTtcclxuXHJcbiAgLy8gQXBwbHkgdXNlciBvcHRpb25zIGlmIHRoZXJlIGFyZSBhbnlcclxuICBpZiAodXNlck9wdGlvbnMpIHtcclxuICAgIC8vIE1lcmdlIHVzZXIgb3B0aW9uc1xyXG4gICAgZ2VuZXJhbE9wdGlvbnMgPSBtZXJnZUNvbmZpZ09wdGlvbnMoXHJcbiAgICAgIGdlbmVyYWxPcHRpb25zLFxyXG4gICAgICB1c2VyT3B0aW9ucyxcclxuICAgICAgYWJzb2x1dGVQcm9wc1xyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIC8vIE9ubHkgZm9yIHRoZSBDTEkgdXNhZ2VcclxuICBpZiAoYXJncz8ubGVuZ3RoKSB7XHJcbiAgICAvLyBQYWlyIHByb3ZpZGVkIGFyZ3VtZW50c1xyXG4gICAgZ2VuZXJhbE9wdGlvbnMgPSBwYWlyQXJndW1lbnRWYWx1ZShnZW5lcmFsT3B0aW9ucywgYXJncywgZGVmYXVsdENvbmZpZyk7XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gZmluYWwgZ2VuZXJhbCBvcHRpb25zXHJcbiAgcmV0dXJuIGdlbmVyYWxPcHRpb25zO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEFsbG93cyBtYW51YWwgY29uZmlndXJhdGlvbiBiYXNlZCBvbiBzcGVjaWZpZWQgcHJvbXB0cyBhbmQgc2F2ZXNcclxuICogdGhlIGNvbmZpZ3VyYXRpb24gdG8gYSBmaWxlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY29uZmlnRmlsZU5hbWUgLSBUaGUgbmFtZSBvZiB0aGUgY29uZmlndXJhdGlvbiBmaWxlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxib29sZWFuPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdHJ1ZSBvbmNlIHRoZSBtYW51YWxcclxuICogY29uZmlndXJhdGlvbiBpcyBjb21wbGV0ZWQgYW5kIHNhdmVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IG1hbnVhbENvbmZpZyA9IGFzeW5jIChjb25maWdGaWxlTmFtZSkgPT4ge1xyXG4gIC8vIFByZXBhcmUgYSBjb25maWcgb2JqZWN0XHJcbiAgbGV0IGNvbmZpZ0ZpbGUgPSB7fTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgcHJvdmlkZWQgY29uZmlnIGZpbGUgZXhpc3RzXHJcbiAgaWYgKGV4aXN0c1N5bmMoY29uZmlnRmlsZU5hbWUpKSB7XHJcbiAgICBjb25maWdGaWxlID0gSlNPTi5wYXJzZShyZWFkRmlsZVN5bmMoY29uZmlnRmlsZU5hbWUsICd1dGY4JykpO1xyXG4gIH1cclxuXHJcbiAgLy8gUXVlc3Rpb24gYWJvdXQgYSBjb25maWd1cmF0aW9uIGNhdGVnb3J5XHJcbiAgY29uc3Qgb25TdWJtaXQgPSBhc3luYyAocCwgY2F0ZWdvcmllcykgPT4ge1xyXG4gICAgbGV0IHF1ZXN0aW9uc0NvdW50ZXIgPSAwO1xyXG4gICAgbGV0IGFsbFF1ZXN0aW9ucyA9IFtdO1xyXG5cclxuICAgIC8vIENyZWF0ZSBhIGNvcnJlc3BvbmRpbmcgcHJvcGVydHkgaW4gdGhlIG1hbnVhbENvbmZpZyBvYmplY3RcclxuICAgIGZvciAoY29uc3Qgc2VjdGlvbiBvZiBjYXRlZ29yaWVzKSB7XHJcbiAgICAgIC8vIE1hcmsgZWFjaCBvcHRpb24gd2l0aCBhIHNlY3Rpb25cclxuICAgICAgcHJvbXB0c0NvbmZpZ1tzZWN0aW9uXSA9IHByb21wdHNDb25maWdbc2VjdGlvbl0ubWFwKChvcHRpb24pID0+ICh7XHJcbiAgICAgICAgLi4ub3B0aW9uLFxyXG4gICAgICAgIHNlY3Rpb25cclxuICAgICAgfSkpO1xyXG5cclxuICAgICAgLy8gQ29sbGVjdCB0aGUgcXVlc3Rpb25zXHJcbiAgICAgIGFsbFF1ZXN0aW9ucyA9IFsuLi5hbGxRdWVzdGlvbnMsIC4uLnByb21wdHNDb25maWdbc2VjdGlvbl1dO1xyXG4gICAgfVxyXG5cclxuICAgIGF3YWl0IHByb21wdHMoYWxsUXVlc3Rpb25zLCB7XHJcbiAgICAgIG9uU3VibWl0OiBhc3luYyAocHJvbXB0LCBhbnN3ZXIpID0+IHtcclxuICAgICAgICAvLyBHZXQgdGhlIGRlZmF1bHQgbW9kdWxlc1xyXG4gICAgICAgIGlmIChwcm9tcHQubmFtZSA9PT0gJ21vZHVsZXMnKSB7XHJcbiAgICAgICAgICBhbnN3ZXIgPSBhbnN3ZXIubGVuZ3RoXHJcbiAgICAgICAgICAgID8gYW5zd2VyLm1hcCgobW9kdWxlKSA9PiBwcm9tcHQuY2hvaWNlc1ttb2R1bGVdKVxyXG4gICAgICAgICAgICA6IHByb21wdC5jaG9pY2VzO1xyXG5cclxuICAgICAgICAgIGNvbmZpZ0ZpbGVbcHJvbXB0LnNlY3Rpb25dW3Byb21wdC5uYW1lXSA9IGFuc3dlcjtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgY29uZmlnRmlsZVtwcm9tcHQuc2VjdGlvbl0gPSByZWN1cnNpdmVQcm9wcyhcclxuICAgICAgICAgICAgT2JqZWN0LmFzc2lnbih7fSwgY29uZmlnRmlsZVtwcm9tcHQuc2VjdGlvbl0gfHwge30pLFxyXG4gICAgICAgICAgICBwcm9tcHQubmFtZS5zcGxpdCgnLicpLFxyXG4gICAgICAgICAgICBwcm9tcHQuY2hvaWNlcyA/IHByb21wdC5jaG9pY2VzW2Fuc3dlcl0gOiBhbnN3ZXJcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBpZiAoKytxdWVzdGlvbnNDb3VudGVyID09PSBhbGxRdWVzdGlvbnMubGVuZ3RoKSB7XHJcbiAgICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICBhd2FpdCBmc1Byb21pc2VzLndyaXRlRmlsZShcclxuICAgICAgICAgICAgICBjb25maWdGaWxlTmFtZSxcclxuICAgICAgICAgICAgICBKU09OLnN0cmluZ2lmeShjb25maWdGaWxlLCBudWxsLCAyKSxcclxuICAgICAgICAgICAgICAndXRmOCdcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAgICAgICAxLFxyXG4gICAgICAgICAgICAgIGVycm9yLFxyXG4gICAgICAgICAgICAgIGBbY29uZmlnXSBBbiBlcnJvciBvY2N1cnJlZCB3aGlsZSBjcmVhdGluZyB0aGUgJHtjb25maWdGaWxlTmFtZX0gZmlsZS5gXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG5cclxuICAgIHJldHVybiB0cnVlO1xyXG4gIH07XHJcblxyXG4gIC8vIEZpbmQgdGhlIGNhdGVnb3JpZXNcclxuICBjb25zdCBjaG9pY2VzID0gT2JqZWN0LmtleXMocHJvbXB0c0NvbmZpZykubWFwKChjaG9pY2UpID0+ICh7XHJcbiAgICB0aXRsZTogYCR7Y2hvaWNlfSBvcHRpb25zYCxcclxuICAgIHZhbHVlOiBjaG9pY2VcclxuICB9KSk7XHJcblxyXG4gIC8vIENhdGVnb3J5IHByb21wdFxyXG4gIHJldHVybiBwcm9tcHRzKFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbXVsdGlzZWxlY3QnLFxyXG4gICAgICBuYW1lOiAnY2F0ZWdvcnknLFxyXG4gICAgICBtZXNzYWdlOiAnV2hpY2ggY2F0ZWdvcnkgZG8geW91IHdhbnQgdG8gY29uZmlndXJlPycsXHJcbiAgICAgIGhpbnQ6ICdTcGFjZTogU2VsZWN0IHNwZWNpZmljLCBBOiBTZWxlY3QgYWxsLCBFbnRlcjogQ29uZmlybS4nLFxyXG4gICAgICBpbnN0cnVjdGlvbnM6ICcnLFxyXG4gICAgICBjaG9pY2VzXHJcbiAgICB9LFxyXG4gICAgeyBvblN1Ym1pdCB9XHJcbiAgKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBNYXBzIG9sZC1zdHJ1Y3R1cmVkIChQaGFudG9tSlMpIG9wdGlvbnMgdG8gYSBuZXcgY29uZmlndXJhdGlvbiBmb3JtYXRcclxuICogKFB1cHBldGVlcikuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvbGRPcHRpb25zIC0gT2xkLXN0cnVjdHVyZWQgb3B0aW9ucyB0byBiZSBtYXBwZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IE5ldyBvcHRpb25zIHN0cnVjdHVyZWQgYmFzZWQgb24gdGhlIGRlZmluZWQgbmVzdGVkQXJnc1xyXG4gKiBtYXBwaW5nLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IG1hcFRvTmV3Q29uZmlnID0gKG9sZE9wdGlvbnMpID0+IHtcclxuICBjb25zdCBuZXdPcHRpb25zID0ge307XHJcbiAgLy8gQ3ljbGUgdGhyb3VnaCBvbGQtc3RydWN0dXJlZCBvcHRpb25zXHJcbiAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMob2xkT3B0aW9ucykpIHtcclxuICAgIGNvbnN0IHByb3BlcnRpZXNDaGFpbiA9IG5lc3RlZEFyZ3Nba2V5XSA/IG5lc3RlZEFyZ3Nba2V5XS5zcGxpdCgnLicpIDogW107XHJcblxyXG4gICAgLy8gUG9wdWxhdGUgb2JqZWN0IGluIGNvcnJlY3QgcHJvcGVydGllcyBsZXZlbHNcclxuICAgIHByb3BlcnRpZXNDaGFpbi5yZWR1Y2UoXHJcbiAgICAgIChvYmosIHByb3AsIGluZGV4KSA9PlxyXG4gICAgICAgIChvYmpbcHJvcF0gPVxyXG4gICAgICAgICAgcHJvcGVydGllc0NoYWluLmxlbmd0aCAtIDEgPT09IGluZGV4ID8gdmFsdWUgOiBvYmpbcHJvcF0gfHwge30pLFxyXG4gICAgICBuZXdPcHRpb25zXHJcbiAgICApO1xyXG4gIH1cclxuICByZXR1cm4gbmV3T3B0aW9ucztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBNZXJnZXMgdHdvIHNldHMgb2YgY29uZmlndXJhdGlvbiBvcHRpb25zLCBjb25zaWRlcmluZyBhYnNvbHV0ZSBwcm9wZXJ0aWVzLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIE9yaWdpbmFsIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cclxuICogQHBhcmFtIHtPYmplY3R9IG5ld09wdGlvbnMgLSBOZXcgY29uZmlndXJhdGlvbiBvcHRpb25zIHRvIGJlIG1lcmdlZC5cclxuICogQHBhcmFtIHtBcnJheX0gYWJzb2x1dGVQcm9wcyAtIExpc3Qgb2YgcHJvcGVydGllcyB0aGF0IHNob3VsZFxyXG4gKiBub3QgYmUgcmVjdXJzaXZlbHkgbWVyZ2VkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBNZXJnZWQgY29uZmlndXJhdGlvbiBvcHRpb25zLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IG1lcmdlQ29uZmlnT3B0aW9ucyA9IChvcHRpb25zLCBuZXdPcHRpb25zLCBhYnNvbHV0ZVByb3BzID0gW10pID0+IHtcclxuICBjb25zdCBtZXJnZWRPcHRpb25zID0gZGVlcENvcHkob3B0aW9ucyk7XHJcblxyXG4gIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKG5ld09wdGlvbnMpKSB7XHJcbiAgICBtZXJnZWRPcHRpb25zW2tleV0gPVxyXG4gICAgICBpc09iamVjdCh2YWx1ZSkgJiZcclxuICAgICAgIWFic29sdXRlUHJvcHMuaW5jbHVkZXMoa2V5KSAmJlxyXG4gICAgICBtZXJnZWRPcHRpb25zW2tleV0gIT09IHVuZGVmaW5lZFxyXG4gICAgICAgID8gbWVyZ2VDb25maWdPcHRpb25zKG1lcmdlZE9wdGlvbnNba2V5XSwgdmFsdWUsIGFic29sdXRlUHJvcHMpXHJcbiAgICAgICAgOiB2YWx1ZSAhPT0gdW5kZWZpbmVkXHJcbiAgICAgICAgICA/IHZhbHVlXHJcbiAgICAgICAgICA6IG1lcmdlZE9wdGlvbnNba2V5XTtcclxuICB9XHJcblxyXG4gIHJldHVybiBtZXJnZWRPcHRpb25zO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIGV4cG9ydCBzZXR0aW5ncyBiYXNlZCBvbiBwcm92aWRlZCBleHBvcnRPcHRpb25zXHJcbiAqIGFuZCBnZW5lcmFsT3B0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGV4cG9ydE9wdGlvbnMgLSBPcHRpb25zIHNwZWNpZmljIHRvIHRoZSBleHBvcnQgcHJvY2Vzcy5cclxuICogQHBhcmFtIHtPYmplY3R9IGdlbmVyYWxPcHRpb25zIC0gR2VuZXJhbCBjb25maWd1cmF0aW9uIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IEluaXRpYWxpemVkIGV4cG9ydCBzZXR0aW5ncy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBpbml0RXhwb3J0U2V0dGluZ3MgPSAoZXhwb3J0T3B0aW9ucywgZ2VuZXJhbE9wdGlvbnMgPSB7fSkgPT4ge1xyXG4gIGxldCBvcHRpb25zID0ge307XHJcblxyXG4gIGlmIChleHBvcnRPcHRpb25zLnN2Zykge1xyXG4gICAgb3B0aW9ucyA9IGRlZXBDb3B5KGdlbmVyYWxPcHRpb25zKTtcclxuICAgIG9wdGlvbnMuZXhwb3J0LnR5cGUgPSBleHBvcnRPcHRpb25zLnR5cGUgfHwgZXhwb3J0T3B0aW9ucy5leHBvcnQudHlwZTtcclxuICAgIG9wdGlvbnMuZXhwb3J0LnNjYWxlID0gZXhwb3J0T3B0aW9ucy5zY2FsZSB8fCBleHBvcnRPcHRpb25zLmV4cG9ydC5zY2FsZTtcclxuICAgIG9wdGlvbnMuZXhwb3J0Lm91dGZpbGUgPVxyXG4gICAgICBleHBvcnRPcHRpb25zLm91dGZpbGUgfHwgZXhwb3J0T3B0aW9ucy5leHBvcnQub3V0ZmlsZTtcclxuICAgIG9wdGlvbnMucGF5bG9hZCA9IHtcclxuICAgICAgc3ZnOiBleHBvcnRPcHRpb25zLnN2Z1xyXG4gICAgfTtcclxuICB9IGVsc2Uge1xyXG4gICAgb3B0aW9ucyA9IG1lcmdlQ29uZmlnT3B0aW9ucyhcclxuICAgICAgZ2VuZXJhbE9wdGlvbnMsXHJcbiAgICAgIGV4cG9ydE9wdGlvbnMsXHJcbiAgICAgIC8vIE9taXQgZ29pbmcgZG93biByZWN1cnNpdmVseSB3aXRoIHRoZSBiZWxvd3NcclxuICAgICAgYWJzb2x1dGVQcm9wc1xyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIG9wdGlvbnMuZXhwb3J0Lm91dGZpbGUgPVxyXG4gICAgb3B0aW9ucy5leHBvcnQ/Lm91dGZpbGUgfHwgYGNoYXJ0LiR7b3B0aW9ucy5leHBvcnQ/LnR5cGUgfHwgJ3BuZyd9YDtcclxuICByZXR1cm4gb3B0aW9ucztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBMb2FkcyBhZGRpdGlvbmFsIGNvbmZpZ3VyYXRpb24gZnJvbSBhIHNwZWNpZmllZCBmaWxlIHVzaW5nXHJcbiAqIHRoZSAtLWxvYWRDb25maWcgb3B0aW9uLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0FycmF5fSBhcmdzIC0gQ29tbWFuZC1saW5lIGFyZ3VtZW50cyB0byBjaGVjayBmb3JcclxuICogdGhlIC0tbG9hZENvbmZpZyBvcHRpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IEFkZGl0aW9uYWwgY29uZmlndXJhdGlvbiBsb2FkZWQgZnJvbSB0aGUgc3BlY2lmaWVkIGZpbGUsXHJcbiAqIG9yIGFuIGVtcHR5IG9iamVjdCBpZiBub3QgZm91bmQgb3IgaW52YWxpZC5cclxuICovXHJcbmZ1bmN0aW9uIGxvYWRDb25maWdGaWxlKGFyZ3MpIHtcclxuICAvLyBDaGVjayBpZiB0aGUgLS1sb2FkQ29uZmlnIG9wdGlvbiB3YXMgdXNlZFxyXG4gIGNvbnN0IGNvbmZpZ0luZGV4ID0gYXJncy5maW5kSW5kZXgoXHJcbiAgICAoYXJnKSA9PiBhcmcucmVwbGFjZSgvLS9nLCAnJykgPT09ICdsb2FkQ29uZmlnJ1xyXG4gICk7XHJcblxyXG4gIC8vIENoZWNrIGlmIHRoZSAtLWxvYWRDb25maWcgaGFzIGEgdmFsdWVcclxuICBpZiAoY29uZmlnSW5kZXggPiAtMSAmJiBhcmdzW2NvbmZpZ0luZGV4ICsgMV0pIHtcclxuICAgIGNvbnN0IGZpbGVOYW1lID0gYXJnc1tjb25maWdJbmRleCArIDFdO1xyXG4gICAgdHJ5IHtcclxuICAgICAgLy8gQ2hlY2sgaWYgYW4gYWRkaXRpb25hbCBjb25maWcgZmlsZSBpcyBhIGNvcnJlY3QgSlNPTiBmaWxlXHJcbiAgICAgIGlmIChmaWxlTmFtZSAmJiBmaWxlTmFtZS5lbmRzV2l0aCgnLmpzb24nKSkge1xyXG4gICAgICAgIC8vIExvYWQgYW4gb3B0aW9uYWwgY3VzdG9tIEpTT04gY29uZmlnIGZpbGVcclxuICAgICAgICByZXR1cm4gSlNPTi5wYXJzZShyZWFkRmlsZVN5bmMoZmlsZU5hbWUpKTtcclxuICAgICAgfVxyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgIDIsXHJcbiAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgYFtjb25maWddIFVuYWJsZSB0byBsb2FkIHRoZSBjb25maWd1cmF0aW9uIGZyb20gdGhlICR7ZmlsZU5hbWV9IGZpbGUuYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gTm8gYWRkaXRpb25hbCBvcHRpb25zIHRvIHJldHVyblxyXG4gIHJldHVybiB7fTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFVwZGF0ZXMgdGhlIGRlZmF1bHQgY29uZmlndXJhdGlvbiBvYmplY3Qgd2l0aCB2YWx1ZXMgZnJvbSBhIGN1c3RvbSBvYmplY3RcclxuICogYW5kIGVudmlyb25tZW50IHZhcmlhYmxlcy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZ09iaiAtIFRoZSBkZWZhdWx0IGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY3VzdG9tT2JqIC0gQ3VzdG9tIGNvbmZpZ3VyYXRpb24gb2JqZWN0IHRvIG92ZXJyaWRlIGRlZmF1bHRzLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcHJvcENoYWluIC0gUHJvcGVydHkgY2hhaW4gZm9yIHRyYWNraW5nIG5lc3RlZCBwcm9wZXJ0aWVzXHJcbiAqIGR1cmluZyByZWN1cnNpb24uXHJcbiAqL1xyXG5mdW5jdGlvbiB1cGRhdGVEZWZhdWx0Q29uZmlnKGNvbmZpZ09iaiwgY3VzdG9tT2JqID0ge30sIHByb3BDaGFpbiA9ICcnKSB7XHJcbiAgT2JqZWN0LmtleXMoY29uZmlnT2JqKS5mb3JFYWNoKChrZXkpID0+IHtcclxuICAgIGNvbnN0IGVudHJ5ID0gY29uZmlnT2JqW2tleV07XHJcbiAgICBjb25zdCBjdXN0b21WYWx1ZSA9IGN1c3RvbU9iaiAmJiBjdXN0b21PYmpba2V5XTtcclxuXHJcbiAgICBpZiAodHlwZW9mIGVudHJ5LnZhbHVlID09PSAndW5kZWZpbmVkJykge1xyXG4gICAgICB1cGRhdGVEZWZhdWx0Q29uZmlnKGVudHJ5LCBjdXN0b21WYWx1ZSwgYCR7cHJvcENoYWlufS4ke2tleX1gKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIElmIGEgdmFsdWUgZnJvbSBhIGN1c3RvbSBKU09OIGV4aXN0cywgaXQgdGFrZSBwcmVjZWRlbmNlXHJcbiAgICAgIGlmIChjdXN0b21WYWx1ZSAhPT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgICAgZW50cnkudmFsdWUgPSBjdXN0b21WYWx1ZTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgYSB2YWx1ZSBmcm9tIGFuIGVudiB2YXJpYWJsZSBleGlzdHMsIGl0IHRha2UgcHJlY2VkZW5jZVxyXG4gICAgICBpZiAoZW50cnkuZW52TGluayBpbiBlbnZzKSB7XHJcbiAgICAgICAgZW50cnkudmFsdWUgPSBlbnZzW2VudHJ5LmVudkxpbmtdO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyBvcHRpb25zIG9iamVjdCBiYXNlZCBvbiBwcm92aWRlZCBpdGVtcywgc2V0dGluZyB2YWx1ZXMgZnJvbVxyXG4gKiBuZXN0ZWQgcHJvcGVydGllcyByZWN1cnNpdmVseS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGl0ZW1zIC0gQ29uZmlndXJhdGlvbiBpdGVtcyB0byBiZSB1c2VkIGZvciBpbml0aWFsaXppbmdcclxuICogb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gSW5pdGlhbGl6ZWQgb3B0aW9ucyBvYmplY3QuXHJcbiAqL1xyXG5mdW5jdGlvbiBpbml0T3B0aW9ucyhpdGVtcykge1xyXG4gIGxldCBvcHRpb25zID0ge307XHJcbiAgZm9yIChjb25zdCBbbmFtZSwgaXRlbV0gb2YgT2JqZWN0LmVudHJpZXMoaXRlbXMpKSB7XHJcbiAgICBvcHRpb25zW25hbWVdID0gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGl0ZW0sICd2YWx1ZScpXHJcbiAgICAgID8gaXRlbS52YWx1ZVxyXG4gICAgICA6IGluaXRPcHRpb25zKGl0ZW0pO1xyXG4gIH1cclxuICByZXR1cm4gb3B0aW9ucztcclxufVxyXG5cclxuLyoqXHJcbiAqIFBhaXJzIGFyZ3VtZW50IHZhbHVlcyB3aXRoIGNvcnJlc3BvbmRpbmcgb3B0aW9ucyBpbiB0aGUgY29uZmlndXJhdGlvbixcclxuICogdXBkYXRpbmcgdGhlIG9wdGlvbnMgb2JqZWN0LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIENvbmZpZ3VyYXRpb24gb3B0aW9ucyBvYmplY3QgdG8gYmUgdXBkYXRlZC5cclxuICogQHBhcmFtIHtBcnJheX0gYXJncyAtIENvbW1hbmQtbGluZSBhcmd1bWVudHMgY29udGFpbmluZyB2YWx1ZXMgZm9yIHNwZWNpZmljXHJcbiAqIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBkZWZhdWx0Q29uZmlnIC0gRGVmYXVsdCBjb25maWd1cmF0aW9uIG9iamVjdCBmb3IgcmVmZXJlbmNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBVcGRhdGVkIG9wdGlvbnMgb2JqZWN0LlxyXG4gKi9cclxuZnVuY3Rpb24gcGFpckFyZ3VtZW50VmFsdWUob3B0aW9ucywgYXJncywgZGVmYXVsdENvbmZpZykge1xyXG4gIGxldCBzaG93VXNhZ2UgPSBmYWxzZTtcclxuICBmb3IgKGxldCBpID0gMDsgaSA8IGFyZ3MubGVuZ3RoOyBpKyspIHtcclxuICAgIGNvbnN0IG9wdGlvbiA9IGFyZ3NbaV0ucmVwbGFjZSgvLS9nLCAnJyk7XHJcblxyXG4gICAgLy8gRmluZCB0aGUgcmlnaHQgcGxhY2UgZm9yIHByb3BlcnR5J3MgdmFsdWVcclxuICAgIGNvbnN0IHByb3BlcnRpZXNDaGFpbiA9IG5lc3RlZEFyZ3Nbb3B0aW9uXVxyXG4gICAgICA/IG5lc3RlZEFyZ3Nbb3B0aW9uXS5zcGxpdCgnLicpXHJcbiAgICAgIDogW107XHJcblxyXG4gICAgLy8gR2V0IHRoZSBjb3JyZWN0IHR5cGUgZm9yIENMSSBhcmdzIHdoaWNoIGFyZSBwYXNzZWQgYXMgc3RyaW5nc1xyXG4gICAgbGV0IGFyZ3VtZW50VHlwZTtcclxuICAgIHByb3BlcnRpZXNDaGFpbi5yZWR1Y2UoKG9iaiwgcHJvcCwgaW5kZXgpID0+IHtcclxuICAgICAgaWYgKHByb3BlcnRpZXNDaGFpbi5sZW5ndGggLSAxID09PSBpbmRleCkge1xyXG4gICAgICAgIGFyZ3VtZW50VHlwZSA9IG9ialtwcm9wXS50eXBlO1xyXG4gICAgICB9XHJcbiAgICAgIHJldHVybiBvYmpbcHJvcF07XHJcbiAgICB9LCBkZWZhdWx0Q29uZmlnKTtcclxuXHJcbiAgICBwcm9wZXJ0aWVzQ2hhaW4ucmVkdWNlKChvYmosIHByb3AsIGluZGV4KSA9PiB7XHJcbiAgICAgIGlmIChwcm9wZXJ0aWVzQ2hhaW4ubGVuZ3RoIC0gMSA9PT0gaW5kZXgpIHtcclxuICAgICAgICAvLyBGaW5kcyBhbiBvcHRpb24gYW5kIHNldCBhIGNvcnJlc3BvbmRpbmcgdmFsdWVcclxuICAgICAgICBpZiAodHlwZW9mIG9ialtwcm9wXSAhPT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgICAgIGlmIChhcmdzWysraV0pIHtcclxuICAgICAgICAgICAgaWYgKGFyZ3VtZW50VHlwZSA9PT0gJ2Jvb2xlYW4nKSB7XHJcbiAgICAgICAgICAgICAgb2JqW3Byb3BdID0gdG9Cb29sZWFuKGFyZ3NbaV0pO1xyXG4gICAgICAgICAgICB9IGVsc2UgaWYgKGFyZ3VtZW50VHlwZSA9PT0gJ251bWJlcicpIHtcclxuICAgICAgICAgICAgICBvYmpbcHJvcF0gPSArYXJnc1tpXTtcclxuICAgICAgICAgICAgfSBlbHNlIGlmIChhcmd1bWVudFR5cGUuaW5kZXhPZignXScpID49IDApIHtcclxuICAgICAgICAgICAgICBvYmpbcHJvcF0gPSBhcmdzW2ldLnNwbGl0KCcsJyk7XHJcbiAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgb2JqW3Byb3BdID0gYXJnc1tpXTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgbG9nKFxyXG4gICAgICAgICAgICAgIDIsXHJcbiAgICAgICAgICAgICAgYFtjb25maWddIE1pc3NpbmcgdmFsdWUgZm9yIHRoZSAnJHtvcHRpb259JyBhcmd1bWVudC4gVXNpbmcgdGhlIGRlZmF1bHQgdmFsdWUuYFxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgICBzaG93VXNhZ2UgPSB0cnVlO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gb2JqW3Byb3BdO1xyXG4gICAgfSwgb3B0aW9ucyk7XHJcbiAgfVxyXG5cclxuICAvLyBEaXNwbGF5IHRoZSB1c2FnZSBmb3IgdGhlIHJlZmVyZW5jZSBpZiBuZWVkZWRcclxuICBpZiAoc2hvd1VzYWdlKSB7XHJcbiAgICBwcmludFVzYWdlKGRlZmF1bHRDb25maWcpO1xyXG4gIH1cclxuXHJcbiAgcmV0dXJuIG9wdGlvbnM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZWN1cnNpdmVseSB1cGRhdGVzIHByb3BlcnRpZXMgaW4gYW4gb2JqZWN0IGJhc2VkIG9uIG5lc3RlZCBuYW1lcyBhbmQgYXNzaWduc1xyXG4gKiB0aGUgZmluYWwgdmFsdWUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvYmplY3RUb1VwZGF0ZSAtIFRoZSBvYmplY3QgdG8gYmUgdXBkYXRlZC5cclxuICogQHBhcmFtIHtBcnJheX0gbmVzdGVkTmFtZXMgLSBBcnJheSBvZiBuZXN0ZWQgcHJvcGVydHkgbmFtZXMuXHJcbiAqIEBwYXJhbSB7YW55fSB2YWx1ZSAtIFRoZSBmaW5hbCB2YWx1ZSB0byBiZSBhc3NpZ25lZC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVXBkYXRlZCBvYmplY3Qgd2l0aCBhc3NpZ25lZCB2YWx1ZXMuXHJcbiAqL1xyXG5mdW5jdGlvbiByZWN1cnNpdmVQcm9wcyhvYmplY3RUb1VwZGF0ZSwgbmVzdGVkTmFtZXMsIHZhbHVlKSB7XHJcbiAgd2hpbGUgKG5lc3RlZE5hbWVzLmxlbmd0aCA+IDEpIHtcclxuICAgIGNvbnN0IHByb3BOYW1lID0gbmVzdGVkTmFtZXMuc2hpZnQoKTtcclxuXHJcbiAgICAvLyBDcmVhdGUgYSBwcm9wZXJ0eSBpbiBvYmplY3QgaWYgaXQgZG9lc24ndCBleGlzdFxyXG4gICAgaWYgKCFPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob2JqZWN0VG9VcGRhdGUsIHByb3BOYW1lKSkge1xyXG4gICAgICBvYmplY3RUb1VwZGF0ZVtwcm9wTmFtZV0gPSB7fTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBDYWxsIGZ1bmN0aW9uIGFnYWluIGlmIHRoZXJlIHN0aWxsIG5hbWVzIHRvIGdvXHJcbiAgICBvYmplY3RUb1VwZGF0ZVtwcm9wTmFtZV0gPSByZWN1cnNpdmVQcm9wcyhcclxuICAgICAgT2JqZWN0LmFzc2lnbih7fSwgb2JqZWN0VG9VcGRhdGVbcHJvcE5hbWVdKSxcclxuICAgICAgbmVzdGVkTmFtZXMsXHJcbiAgICAgIHZhbHVlXHJcbiAgICApO1xyXG5cclxuICAgIHJldHVybiBvYmplY3RUb1VwZGF0ZTtcclxuICB9XHJcblxyXG4gIC8vIEFzc2lnbiB0aGUgZmluYWwgdmFsdWVcclxuICBvYmplY3RUb1VwZGF0ZVtuZXN0ZWROYW1lc1swXV0gPSB2YWx1ZTtcclxuICByZXR1cm4gb2JqZWN0VG9VcGRhdGU7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBnZXRPcHRpb25zLFxyXG4gIHNldE9wdGlvbnMsXHJcbiAgbWFudWFsQ29uZmlnLFxyXG4gIG1hcFRvTmV3Q29uZmlnLFxyXG4gIG1lcmdlQ29uZmlnT3B0aW9ucyxcclxuICBpbml0RXhwb3J0U2V0dGluZ3NcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgZnMgZnJvbSAnZnMnO1xyXG5pbXBvcnQgKiBhcyB1cmwgZnJvbSAndXJsJztcclxuaW1wb3J0IHBhdGggZnJvbSAnbm9kZTpwYXRoJztcclxuXHJcbmltcG9ydCBwdXBwZXRlZXIgZnJvbSAncHVwcGV0ZWVyJztcclxuXHJcbi8vIFdvcmthcm91bmQgZm9yIGh0dHBzOi8vYnVncy5jaHJvbWl1bS5vcmcvcC9jaHJvbWl1bS9pc3N1ZXMvZGV0YWlsP2lkPTE0NjMzMjhcclxuLy8gTm90IGlkZWFsIC0gbGVhdmVzIHRyYXNoIGluIHRoZSBGU1xyXG5pbXBvcnQgeyByYW5kb21CeXRlcyB9IGZyb20gJ25vZGU6Y3J5cHRvJztcclxuXHJcbmltcG9ydCB7IGdldENhY2hlUGF0aCB9IGZyb20gJy4vY2FjaGUuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG5jb25zdCBSQU5ET01fUElEID0gcmFuZG9tQnl0ZXMoNjQpLnRvU3RyaW5nKCdiYXNlNjR1cmwnKTtcclxuY29uc3QgUFVQUEVURUVSX0RJUiA9IHBhdGguam9pbigndG1wJywgYHB1cHBldGVlci0ke1JBTkRPTV9QSUR9YCk7XHJcbmNvbnN0IERBVEFfRElSID0gcGF0aC5qb2luKFBVUFBFVEVFUl9ESVIsICdwcm9maWxlJyk7XHJcblxyXG4vLyBUaGUgbWluaW1hbCBhcmdzIHRvIHNwZWVkIHVwIHRoZSBicm93c2VyXHJcbmNvbnN0IG1pbmltYWxBcmdzID0gW1xyXG4gIGAtLXVzZXItZGF0YS1kaXI9JHtEQVRBX0RJUn1gLFxyXG4gICctLWF1dG9wbGF5LXBvbGljeT11c2VyLWdlc3R1cmUtcmVxdWlyZWQnLFxyXG4gICctLWRpc2FibGUtYmFja2dyb3VuZC1uZXR3b3JraW5nJyxcclxuICAnLS1kaXNhYmxlLWJhY2tncm91bmQtdGltZXItdGhyb3R0bGluZycsXHJcbiAgJy0tZGlzYWJsZS1iYWNrZ3JvdW5kaW5nLW9jY2x1ZGVkLXdpbmRvd3MnLFxyXG4gICctLWRpc2FibGUtYnJlYWtwYWQnLFxyXG4gICctLWRpc2FibGUtY2xpZW50LXNpZGUtcGhpc2hpbmctZGV0ZWN0aW9uJyxcclxuICAnLS1kaXNhYmxlLWNvbXBvbmVudC11cGRhdGUnLFxyXG4gICctLWRpc2FibGUtZGVmYXVsdC1hcHBzJyxcclxuICAnLS1kaXNhYmxlLWRldi1zaG0tdXNhZ2UnLFxyXG4gICctLWRpc2FibGUtZG9tYWluLXJlbGlhYmlsaXR5JyxcclxuICAnLS1kaXNhYmxlLWV4dGVuc2lvbnMnLFxyXG4gICctLWRpc2FibGUtZmVhdHVyZXM9QXVkaW9TZXJ2aWNlT3V0T2ZQcm9jZXNzJyxcclxuICAnLS1kaXNhYmxlLWhhbmctbW9uaXRvcicsXHJcbiAgJy0tZGlzYWJsZS1pcGMtZmxvb2RpbmctcHJvdGVjdGlvbicsXHJcbiAgJy0tZGlzYWJsZS1ub3RpZmljYXRpb25zJyxcclxuICAnLS1kaXNhYmxlLW9mZmVyLXN0b3JlLXVubWFza2VkLXdhbGxldC1jYXJkcycsXHJcbiAgJy0tZGlzYWJsZS1wb3B1cC1ibG9ja2luZycsXHJcbiAgJy0tZGlzYWJsZS1wcmludC1wcmV2aWV3JyxcclxuICAnLS1kaXNhYmxlLXByb21wdC1vbi1yZXBvc3QnLFxyXG4gICctLWRpc2FibGUtcmVuZGVyZXItYmFja2dyb3VuZGluZycsXHJcbiAgJy0tZGlzYWJsZS1zZXNzaW9uLWNyYXNoZWQtYnViYmxlJyxcclxuICAnLS1kaXNhYmxlLXNldHVpZC1zYW5kYm94JyxcclxuICAnLS1kaXNhYmxlLXNwZWVjaC1hcGknLFxyXG4gICctLWRpc2FibGUtc3luYycsXHJcbiAgJy0taGlkZS1jcmFzaC1yZXN0b3JlLWJ1YmJsZScsXHJcbiAgJy0taGlkZS1zY3JvbGxiYXJzJyxcclxuICAnLS1pZ25vcmUtZ3B1LWJsYWNrbGlzdCcsXHJcbiAgJy0tbWV0cmljcy1yZWNvcmRpbmctb25seScsXHJcbiAgJy0tbXV0ZS1hdWRpbycsXHJcbiAgJy0tbm8tZGVmYXVsdC1icm93c2VyLWNoZWNrJyxcclxuICAnLS1uby1maXJzdC1ydW4nLFxyXG4gICctLW5vLXBpbmdzJyxcclxuICAnLS1uby1zYW5kYm94JyxcclxuICAnLS1uby16eWdvdGUnLFxyXG4gICctLXBhc3N3b3JkLXN0b3JlPWJhc2ljJyxcclxuICAnLS11c2UtbW9jay1rZXljaGFpbidcclxuXTtcclxuXHJcbmNvbnN0IF9fZGlybmFtZSA9IHVybC5maWxlVVJMVG9QYXRoKG5ldyBVUkwoJy4nLCBpbXBvcnQubWV0YS51cmwpKTtcclxuXHJcbmNvbnN0IHRlbXBsYXRlID0gZnMucmVhZEZpbGVTeW5jKFxyXG4gIF9fZGlybmFtZSArICcvLi4vdGVtcGxhdGVzL3RlbXBsYXRlLmh0bWwnLFxyXG4gICd1dGY4J1xyXG4pO1xyXG5cclxubGV0IGJyb3dzZXI7XHJcblxyXG4vKipcclxuICogU2V0cyB0aGUgY29udGVudCBmb3IgYSBQdXBwZXRlZXIgUGFnZSB1c2luZyBhIHByZWRlZmluZWQgdGVtcGxhdGVcclxuICogYW5kIGFkZGl0aW9uYWwgc2NyaXB0cy4gQWxzbywgc2V0cyB0aGUgcGFnZWVycm9yIGluIG9yZGVyIHRvIGNhdGNoXHJcbiAqIGFuZCBkaXNwbGF5IGVycm9ycyBmcm9tIHRoZSB3aW5kb3cgY29udGV4dC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IGZvciB3aGljaCB0aGUgY29udGVudFxyXG4gKiBpcyBiZWluZyBzZXQuXHJcbiAqL1xyXG5jb25zdCBzZXRQYWdlQ29udGVudCA9IGFzeW5jIChwYWdlKSA9PiB7XHJcbiAgYXdhaXQgcGFnZS5zZXRDb250ZW50KHRlbXBsYXRlKTtcclxuICBhd2FpdCBwYWdlLmFkZFNjcmlwdFRhZyh7IHBhdGg6IGAke2dldENhY2hlUGF0aCgpfS9zb3VyY2VzLmpzYCB9KTtcclxuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICBhd2FpdCBwYWdlLmV2YWx1YXRlKCgpID0+IHdpbmRvdy5zZXR1cEhpZ2hjaGFydHMoKSk7XHJcblxyXG4gIHBhZ2Uub24oJ3BhZ2VlcnJvcicsIGFzeW5jIChlcnJvcikgPT4ge1xyXG4gICAgLy8gVE9ETzogQ29uc2lkZXIgYWRkaW5nIGEgc3dpdGNoIGhlcmUgdGhhdCB0dXJucyBvbiBsb2coMCkgbG9nZ2luZ1xyXG4gICAgLy8gb24gcGFnZSBlcnJvcnMuXHJcbiAgICBhd2FpdCBwYWdlLiRldmFsKFxyXG4gICAgICAnI2NvbnRhaW5lcicsXHJcbiAgICAgIChlbGVtZW50LCBlcnJvck1lc3NhZ2UpID0+IHtcclxuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICBpZiAod2luZG93Ll9kaXNwbGF5RXJyb3JzKSB7XHJcbiAgICAgICAgICBlbGVtZW50LmlubmVySFRNTCA9IGVycm9yTWVzc2FnZTtcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIGA8aDE+Q2hhcnQgaW5wdXQgZGF0YSBlcnJvcjwvaDE+JHtlcnJvci50b1N0cmluZygpfWBcclxuICAgICk7XHJcbiAgfSk7XHJcbn07XHJcblxyXG4vKipcclxuICogQ2xlYXJzIHRoZSBjb250ZW50IG9mIGEgUHVwcGV0ZWVyIFBhZ2UgYmFzZWQgb24gdGhlIHNwZWNpZmllZCBtb2RlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFRoZSBQdXBwZXRlZXIgUGFnZSBvYmplY3QgdG8gYmUgY2xlYXJlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBoYXJkUmVzZXQgLSBBIGZsYWcgaW5kaWNhdGluZyB0aGUgdHlwZSBvZiBjbGVhcmluZ1xyXG4gKiB0byBiZSBwZXJmb3JtZWQuIElmIHRydWUsIG5hdmlnYXRlcyB0byAnYWJvdXQ6YmxhbmsnIGFuZCByZXNldHMgY29udGVudFxyXG4gKiBhbmQgc2NyaXB0cy4gSWYgZmFsc2UsIGNsZWFycyB0aGUgYm9keSBjb250ZW50IGJ5IHNldHRpbmcgYSBwcmVkZWZpbmVkIEhUTUxcclxuICogc3RydWN0dXJlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFcnJvcn0gTG9ncyB0aHJvd24gZXJyb3IgaWYgY2xlYXJpbmcgdGhlIHBhZ2UgY29udGVudCBmYWlscy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBjbGVhclBhZ2UgPSBhc3luYyAocGFnZSwgaGFyZFJlc2V0ID0gZmFsc2UpID0+IHtcclxuICB0cnkge1xyXG4gICAgaWYgKGhhcmRSZXNldCkge1xyXG4gICAgICAvLyBOYXZpZ2F0ZSB0byBhYm91dDpibGFua1xyXG4gICAgICBhd2FpdCBwYWdlLmdvdG8oJ2Fib3V0OmJsYW5rJyk7XHJcblxyXG4gICAgICAvLyBTZXQgdGhlIGNvbnRlbnQgYW5kIGFuZCBzY3JpcHRzIGFnYWluXHJcbiAgICAgIGF3YWl0IHNldFBhZ2VDb250ZW50KHBhZ2UpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gQ2xlYXIgYm9keSBjb250ZW50XHJcbiAgICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xyXG4gICAgICAgIGRvY3VtZW50LmJvZHkuaW5uZXJIVE1MID1cclxuICAgICAgICAgICc8ZGl2IGlkPVwiY2hhcnQtY29udGFpbmVyXCI+PGRpdiBpZD1cImNvbnRhaW5lclwiPjwvZGl2PjwvZGl2Pic7XHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgIDIsXHJcbiAgICAgIGVycm9yLFxyXG4gICAgICAnW2Jyb3dzZXJdIENvdWxkIG5vdCBjbGVhciB0aGUgY29udGVudCBvZiB0aGUgcGFnZS4nXHJcbiAgICApO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgbmV3IFB1cHBldGVlciBQYWdlIHdpdGhpbiBhbiBleGlzdGluZyBicm93c2VyIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBJZiB0aGUgYnJvd3NlciBpbnN0YW5jZSBpcyBub3QgYXZhaWxhYmxlLCByZXR1cm5zIGZhbHNlLlxyXG4gKlxyXG4gKiBUaGUgZnVuY3Rpb24gY3JlYXRlcyBhIG5ldyBwYWdlLCBkaXNhYmxlcyBjYWNoaW5nLCBzZXRzIGNvbnRlbnQgdXNpbmdcclxuICogc2V0UGFnZUNvbnRlbnQoKSwgYW5kIHJldHVybnMgdGhlIGNyZWF0ZWQgUHVwcGV0ZWVyIFBhZ2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHsoYm9vbGVhbnxvYmplY3QpfSBSZXR1cm5zIGZhbHNlIGlmIHRoZSBicm93c2VyIGluc3RhbmNlIGlzIG5vdFxyXG4gKiBhdmFpbGFibGUsIG9yIGEgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IHJlcHJlc2VudGluZyB0aGUgbmV3bHkgY3JlYXRlZCBwYWdlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IG5ld1BhZ2UgPSBhc3luYyAoKSA9PiB7XHJcbiAgaWYgKCFicm93c2VyKSB7XHJcbiAgICByZXR1cm4gZmFsc2U7XHJcbiAgfVxyXG5cclxuICBjb25zdCBwYWdlID0gYXdhaXQgYnJvd3Nlci5uZXdQYWdlKCk7XHJcblxyXG4gIC8vIERpc2FibGUgY2FjaGVcclxuICBhd2FpdCBwYWdlLnNldENhY2hlRW5hYmxlZChmYWxzZSk7XHJcblxyXG4gIC8vIFNldCB0aGUgY29udGVudFxyXG4gIGF3YWl0IHNldFBhZ2VDb250ZW50KHBhZ2UpO1xyXG4gIHJldHVybiBwYWdlO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYSBQdXBwZXRlZXIgYnJvd3NlciBpbnN0YW5jZSB3aXRoIHRoZSBzcGVjaWZpZWQgYXJndW1lbnRzLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0FycmF5fSBwdXBwZXRlZXJBcmdzIC0gQWRkaXRpb25hbCBhcmd1bWVudHMgZm9yIFB1cHBldGVlciBsYXVuY2guXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPG9iamVjdD59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIFB1cHBldGVlciBicm93c2VyXHJcbiAqIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIG1heCByZXRyaWVzIHRvIG9wZW4gYSBicm93c2VyXHJcbiAqIGluc3RhbmNlIGFyZSByZWFjaGVkLCBvciBpZiBubyBicm93c2VyIGluc3RhbmNlIGlzIGZvdW5kIGFmdGVyIHJldHJpZXMuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgY3JlYXRlID0gYXN5bmMgKHB1cHBldGVlckFyZ3MpID0+IHtcclxuICBjb25zdCBhbGxBcmdzID0gWy4uLm1pbmltYWxBcmdzLCAuLi4ocHVwcGV0ZWVyQXJncyB8fCBbXSldO1xyXG5cclxuICAvLyBDcmVhdGUgYSBicm93c2VyXHJcbiAgaWYgKCFicm93c2VyKSB7XHJcbiAgICBsZXQgdHJ5Q291bnQgPSAwO1xyXG5cclxuICAgIGNvbnN0IG9wZW4gPSBhc3luYyAoKSA9PiB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbYnJvd3Nlcl0gQXR0ZW1wdGluZyB0byBnZXQgYSBicm93c2VyIGluc3RhbmNlICh0cnkgJHsrK3RyeUNvdW50fSkuYFxyXG4gICAgICAgICk7XHJcbiAgICAgICAgYnJvd3NlciA9IGF3YWl0IHB1cHBldGVlci5sYXVuY2goe1xyXG4gICAgICAgICAgaGVhZGxlc3M6ICduZXcnLFxyXG4gICAgICAgICAgYXJnczogYWxsQXJncyxcclxuICAgICAgICAgIHVzZXJEYXRhRGlyOiAnLi90bXAvJ1xyXG4gICAgICAgIH0pO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAgIDEsXHJcbiAgICAgICAgICBlcnJvcixcclxuICAgICAgICAgICdbYnJvd3Nlcl0gRmFpbGVkIHRvIGxhdW5jaCBhIGJyb3dzZXIgaW5zdGFuY2UuJ1xyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIC8vIFJldHJ5IHRvIGxhdW5jaCBicm93c2VyIHVudGlsIHJlYWNoaW5nIG1heCBhdHRlbXB0c1xyXG4gICAgICAgIGlmICh0cnlDb3VudCA8IDI1KSB7XHJcbiAgICAgICAgICBsb2coMywgYFticm93c2VyXSBSZXRyeSB0byBvcGVuIGEgYnJvd3NlciAoJHt0cnlDb3VudH0gb3V0IG9mIDI1KS5gKTtcclxuICAgICAgICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNwb25zZSkgPT4gc2V0VGltZW91dChyZXNwb25zZSwgNDAwMCkpO1xyXG4gICAgICAgICAgYXdhaXQgb3BlbigpO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH07XHJcblxyXG4gICAgdHJ5IHtcclxuICAgICAgYXdhaXQgb3BlbigpO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdbYnJvd3Nlcl0gTWF4aW11bSByZXRyaWVzIHRvIG9wZW4gYSBicm93c2VyIGluc3RhbmNlIHJlYWNoZWQuJ1xyXG4gICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoIWJyb3dzZXIpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbYnJvd3Nlcl0gQ2Fubm90IGZpbmQgYSBicm93c2VyIHRvIG9wZW4uJyk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gYSBicm93c2VyIHByb21pc2VcclxuICByZXR1cm4gYnJvd3NlcjtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgdGhlIGV4aXN0aW5nIFB1cHBldGVlciBicm93c2VyIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxvYmplY3Q+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBQdXBwZXRlZXIgYnJvd3NlclxyXG4gKiBpbnN0YW5jZS5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiBubyB2YWxpZCBicm93c2VyIGhhcyBiZWVuXHJcbiAqIGNyZWF0ZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0ID0gYXN5bmMgKCkgPT4ge1xyXG4gIGlmICghYnJvd3Nlcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbYnJvd3Nlcl0gTm8gdmFsaWQgYnJvd3NlciBoYXMgYmVlbiBjcmVhdGVkLicpO1xyXG4gIH1cclxuXHJcbiAgcmV0dXJuIGJyb3dzZXI7XHJcbn07XHJcblxyXG4vKipcclxuICogQ2xvc2VzIHRoZSBQdXBwZXRlZXIgYnJvd3NlciBpbnN0YW5jZSBpZiBpdCBpcyBjb25uZWN0ZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPGJvb2xlYW4+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIHRydWUgYWZ0ZXIgdGhlIGJyb3dzZXJcclxuICogaXMgY2xvc2VkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGNsb3NlID0gYXN5bmMgKCkgPT4ge1xyXG4gIC8vIENsb3NlIHRoZSBicm93c2VyIHdoZW4gY29ubm5lY3RlZFxyXG4gIGlmIChicm93c2VyPy5pc0Nvbm5lY3RlZCgpKSB7XHJcbiAgICBhd2FpdCBicm93c2VyLmNsb3NlKCk7XHJcbiAgICBsb2coNCwgJ1ticm93c2VyXSBDbG9zZWQgdGhlIGJyb3dzZXIuJyk7XHJcbiAgfVxyXG4gIHJldHVybiB0cnVlO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIG5ld1BhZ2UsXHJcbiAgY2xlYXJQYWdlLFxyXG4gIGdldCxcclxuICBjbG9zZVxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHBhdGggZnJvbSAncGF0aCc7XHJcbmltcG9ydCAqIGFzIHVybCBmcm9tICd1cmwnO1xyXG5cclxuaW1wb3J0IGNhY2hlIGZyb20gJy4vY2FjaGUuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHN2Z1RlbXBsYXRlIGZyb20gJy4vLi4vdGVtcGxhdGVzL3N2Z19leHBvcnQvc3ZnX2V4cG9ydC5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuY29uc3QgX19iYXNlZGlyID0gdXJsLmZpbGVVUkxUb1BhdGgobmV3IFVSTCgnLicsIGltcG9ydC5tZXRhLnVybCkpO1xyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyB0aGUgY2xpcHBpbmcgcmVnaW9uIGNvb3JkaW5hdGVzIG9mIHRoZSBzcGVjaWZpZWQgcGFnZSBlbGVtZW50IHdpdGhcclxuICogdGhlIGlkICdjaGFydC1jb250YWluZXInLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gYW4gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogeCwgeSwgd2lkdGgsIGFuZCBoZWlnaHQgcHJvcGVydGllcy5cclxuICovXHJcbmNvbnN0IGdldENsaXBSZWdpb24gPSAocGFnZSkgPT5cclxuICBwYWdlLiRldmFsKCcjY2hhcnQtY29udGFpbmVyJywgKGVsZW1lbnQpID0+IHtcclxuICAgIGNvbnN0IHsgeCwgeSwgd2lkdGgsIGhlaWdodCB9ID0gZWxlbWVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcclxuICAgIHJldHVybiB7XHJcbiAgICAgIHgsXHJcbiAgICAgIHksXHJcbiAgICAgIHdpZHRoLFxyXG4gICAgICBoZWlnaHQ6IE1hdGgudHJ1bmMoaGVpZ2h0ID4gMSA/IGhlaWdodCA6IDUwMClcclxuICAgIH07XHJcbiAgfSk7XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhbiBpbWFnZSB1c2luZyBQdXBwZXRlZXIncyBwYWdlIHNjcmVlbnNob3QgZnVuY3Rpb25hbGl0eSB3aXRoXHJcbiAqIHNwZWNpZmllZCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICogQHBhcmFtIHtzdHJpbmd9IHR5cGUgLSBJbWFnZSB0eXBlLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gZW5jb2RpbmcgLSBJbWFnZSBlbmNvZGluZy5cclxuICogQHBhcmFtIHtPYmplY3R9IGNsaXAgLSBDbGlwcGluZyByZWdpb24gY29vcmRpbmF0ZXMuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSByYXN0ZXJpemF0aW9uVGltZW91dCAtIFRpbWVvdXQgZm9yIHJhc3Rlcml6YXRpb25cclxuICogaW4gbWlsbGlzZWNvbmRzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxCdWZmZXI+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgaW1hZ2UgYnVmZmVyIG9yIHJlamVjdGluZ1xyXG4gKiB3aXRoIGFuIEV4cG9ydEVycm9yIGZvciB0aW1lb3V0LlxyXG4gKi9cclxuY29uc3QgY3JlYXRlSW1hZ2UgPSAocGFnZSwgdHlwZSwgZW5jb2RpbmcsIGNsaXAsIHJhc3Rlcml6YXRpb25UaW1lb3V0KSA9PlxyXG4gIFByb21pc2UucmFjZShbXHJcbiAgICBwYWdlLnNjcmVlbnNob3Qoe1xyXG4gICAgICB0eXBlLFxyXG4gICAgICBlbmNvZGluZyxcclxuICAgICAgY2xpcCxcclxuXHJcbiAgICAgIC8vICM0NDcsICM0NjMgLSBhbHdheXMgcmVuZGVyIG9uIGEgdHJhbnNwYXJlbnQgcGFnZSBpZiB0aGUgZXhwZWN0ZWQgdHlwZVxyXG4gICAgICAvLyBmb3JtYXQgaXMgUE5HXHJcbiAgICAgIG9taXRCYWNrZ3JvdW5kOiB0eXBlID09ICdwbmcnXHJcbiAgICB9KSxcclxuICAgIG5ldyBQcm9taXNlKChfcmVzb2x2ZSwgcmVqZWN0KSA9PlxyXG4gICAgICBzZXRUaW1lb3V0KFxyXG4gICAgICAgICgpID0+IHJlamVjdChuZXcgRXhwb3J0RXJyb3IoJ1Jhc3Rlcml6YXRpb24gdGltZW91dCcpKSxcclxuICAgICAgICByYXN0ZXJpemF0aW9uVGltZW91dCB8fCAxNTAwXHJcbiAgICAgIClcclxuICAgIClcclxuICBdKTtcclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgUERGIHVzaW5nIFB1cHBldGVlcidzIHBhZ2UgcGRmIGZ1bmN0aW9uYWxpdHkgd2l0aCBzcGVjaWZpZWRcclxuICogb3B0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBoZWlnaHQgLSBQREYgaGVpZ2h0LlxyXG4gKiBAcGFyYW0ge251bWJlcn0gd2lkdGggLSBQREYgd2lkdGguXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBlbmNvZGluZyAtIFBERiBlbmNvZGluZy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8QnVmZmVyPn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIFBERiBidWZmZXIuXHJcbiAqL1xyXG5jb25zdCBjcmVhdGVQREYgPSAocGFnZSwgaGVpZ2h0LCB3aWR0aCwgZW5jb2RpbmcpID0+XHJcbiAgcGFnZS5wZGYoe1xyXG4gICAgLy8gVGhpcyB3aWxsIHJlbW92ZSBhbiBleHRyYSBlbXB0eSBwYWdlIGluIFBERiBleHBvcnRzXHJcbiAgICBoZWlnaHQ6IGhlaWdodCArIDEsXHJcbiAgICB3aWR0aCxcclxuICAgIGVuY29kaW5nXHJcbiAgfSk7XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhbiBTVkcgc3RyaW5nIGJ5IGV2YWx1YXRpbmcgdGhlIG91dGVySFRNTCBvZiB0aGUgZmlyc3QgJ3N2ZycgZWxlbWVudFxyXG4gKiBpbnNpZGUgYW4gZWxlbWVudCB3aXRoIHRoZSBpZCAnY29udGFpbmVyJy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZz59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBTVkcgc3RyaW5nLlxyXG4gKi9cclxuY29uc3QgY3JlYXRlU1ZHID0gKHBhZ2UpID0+XHJcbiAgcGFnZS4kZXZhbCgnI2NvbnRhaW5lciBzdmc6Zmlyc3Qtb2YtdHlwZScsIChlbGVtZW50KSA9PiBlbGVtZW50Lm91dGVySFRNTCk7XHJcblxyXG4vKipcclxuICogU2V0cyB0aGUgc3BlY2lmaWVkIGNoYXJ0IGFuZCBvcHRpb25zIGFzIGNvbmZpZ3VyYXRpb24gaW50byB0aGUgdHJpZ2dlckV4cG9ydFxyXG4gKiBmdW5jdGlvbiB3aXRoaW4gdGhlIHdpbmRvdyBjb250ZXh0IHVzaW5nIHBhZ2UuZXZhbHVhdGUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge2FueX0gY2hhcnQgLSBUaGUgY2hhcnQgb2JqZWN0IHRvIGJlIGNvbmZpZ3VyZWQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gQ29uZmlndXJhdGlvbiBvcHRpb25zIGZvciB0aGUgY2hhcnQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBQcm9taXNlIHJlc29sdmluZyBhZnRlciB0aGUgY29uZmlndXJhdGlvbiBpcyBzZXQuXHJcbiAqL1xyXG5jb25zdCBzZXRBc0NvbmZpZyA9IChwYWdlLCBjaGFydCwgb3B0aW9ucykgPT5cclxuICBwYWdlLmV2YWx1YXRlKFxyXG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAoY2hhcnQsIG9wdGlvbnMpID0+IHdpbmRvdy50cmlnZ2VyRXhwb3J0KGNoYXJ0LCBvcHRpb25zKSxcclxuICAgIGNoYXJ0LFxyXG4gICAgb3B0aW9uc1xyXG4gICk7XHJcblxyXG4vKipcclxuICogRXhwb3J0cyB0byBhIGNoYXJ0IGZyb20gYSBwYWdlIHVzaW5nIFB1cHBldGVlci5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7YW55fSBjaGFydCAtIFRoZSBjaGFydCBvYmplY3Qgb3IgU1ZHIGNvbmZpZ3VyYXRpb24gdG8gYmUgZXhwb3J0ZWQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gRXhwb3J0IG9wdGlvbnMgYW5kIGNvbmZpZ3VyYXRpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZyB8IEJ1ZmZlciB8IEV4cG9ydEVycm9yPn0gUHJvbWlzZSByZXNvbHZpbmcgdG9cclxuICogdGhlIGV4cG9ydGVkIGRhdGEgb3IgcmVqZWN0aW5nIHdpdGggYW4gRXhwb3J0RXJyb3IuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCBhc3luYyAocGFnZSwgY2hhcnQsIG9wdGlvbnMpID0+IHtcclxuICAvKipcclxuICAgKiBLZWVwcyB0cmFjayBvZiBhbGwgcmVzb3VyY2VzIGFkZGVkIG9uIHRoZSBwYWdlIHdpdGggYWRkWFhYVGFnLiBldGNcclxuICAgKiBJdCdzIFZJVEFMIHRoYXQgYWxsIGFkZGVkIHJlc291cmNlcyBlbmRzIHVwIGhlcmUgc28gd2UgY2FuIGNsZWFyIHRoaW5nc1xyXG4gICAqIG91dCB3aGVuIGRvaW5nIGEgbmV3IGV4cG9ydCBpbiB0aGUgc2FtZSBwYWdlIVxyXG4gICAqL1xyXG4gIGNvbnN0IGluamVjdGVkUmVzb3VyY2VzID0gW107XHJcblxyXG4gIC8qKiBDbGVhciBvdXQgYWxsIHN0YXRlIHNldCBvbiB0aGUgcGFnZSB3aXRoIGFkZFNjcmlwdFRhZy9hZGRTdHlsZVRhZy4gKi9cclxuICBjb25zdCBjbGVhckluamVjdGVkID0gYXN5bmMgKHBhZ2UpID0+IHtcclxuICAgIGZvciAoY29uc3QgcmVzIG9mIGluamVjdGVkUmVzb3VyY2VzKSB7XHJcbiAgICAgIGF3YWl0IHJlcy5kaXNwb3NlKCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmVzZXQgYWxsIENTUyBhbmQgc2NyaXB0IHRhZ3NcclxuICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xyXG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgY29uc3QgWywgLi4uc2NyaXB0c1RvUmVtb3ZlXSA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdzY3JpcHQnKTtcclxuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgIGNvbnN0IFssIC4uLnN0eWxlc1RvUmVtb3ZlXSA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdzdHlsZScpO1xyXG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgY29uc3QgWy4uLmxpbmtzVG9SZW1vdmVdID0gZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ2xpbmsnKTtcclxuXHJcbiAgICAgIC8vIFJlbW92ZSB0YWdzXHJcbiAgICAgIGZvciAoY29uc3QgZWxlbWVudCBvZiBbXHJcbiAgICAgICAgLi4uc2NyaXB0c1RvUmVtb3ZlLFxyXG4gICAgICAgIC4uLnN0eWxlc1RvUmVtb3ZlLFxyXG4gICAgICAgIC4uLmxpbmtzVG9SZW1vdmVcclxuICAgICAgXSkge1xyXG4gICAgICAgIGVsZW1lbnQucmVtb3ZlKCk7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG4gIH07XHJcblxyXG4gIHRyeSB7XHJcbiAgICBsb2coNCwgJ1tleHBvcnRdIERldGVybWluaW5nIGV4cG9ydCBwYXRoLicpO1xyXG5cclxuICAgIGNvbnN0IGV4cG9ydE9wdGlvbnMgPSBvcHRpb25zLmV4cG9ydDtcclxuXHJcbiAgICAvLyBGb3JjZSBhIHJBRlxyXG4gICAgLy8gU2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9wdXBwZXRlZXIvcHVwcGV0ZWVyL2lzc3Vlcy83NTA3XHJcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4gcmVxdWVzdEFuaW1hdGlvbkZyYW1lKCgpID0+IHt9KSk7XHJcblxyXG4gICAgLy8gRGVjaWRlIHdoZXRoZXIgZGlzcGxheSBlcnJvciBvciBkZWJidWdlciB3cmFwcGVyIGFyb3VuZCBpdFxyXG4gICAgY29uc3QgZGlzcGxheUVycm9ycyA9XHJcbiAgICAgIGV4cG9ydE9wdGlvbnM/Lm9wdGlvbnM/LmNoYXJ0Py5kaXNwbGF5RXJyb3JzICYmXHJcbiAgICAgIGNhY2hlLmdldENhY2hlKCkuYWN0aXZlTWFuaWZlc3QubW9kdWxlcy5kZWJ1Z2dlcjtcclxuXHJcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoKGQpID0+ICh3aW5kb3cuX2Rpc3BsYXlFcnJvcnMgPSBkKSwgZGlzcGxheUVycm9ycyk7XHJcblxyXG4gICAgbGV0IGlzU1ZHO1xyXG4gICAgaWYgKFxyXG4gICAgICBjaGFydC5pbmRleE9mICYmXHJcbiAgICAgIChjaGFydC5pbmRleE9mKCc8c3ZnJykgPj0gMCB8fCBjaGFydC5pbmRleE9mKCc8P3htbCcpID49IDApXHJcbiAgICApIHtcclxuICAgICAgLy8gU1ZHIGlucHV0IGhhbmRsaW5nXHJcbiAgICAgIGxvZyg0LCAnW2V4cG9ydF0gVHJlYXRpbmcgYXMgU1ZHLicpO1xyXG5cclxuICAgICAgLy8gSWYgaW5wdXQgaXMgYWxzbyBTVkcsIGp1c3QgcmV0dXJuIGl0XHJcbiAgICAgIGlmIChleHBvcnRPcHRpb25zLnR5cGUgPT09ICdzdmcnKSB7XHJcbiAgICAgICAgcmV0dXJuIGNoYXJ0O1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpc1NWRyA9IHRydWU7XHJcbiAgICAgIGF3YWl0IHBhZ2Uuc2V0Q29udGVudChzdmdUZW1wbGF0ZShjaGFydCkpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gSlNPTiBjb25maWcgaGFuZGxpbmdcclxuICAgICAgbG9nKDQsICdbZXhwb3J0XSBUcmVhdGluZyBhcyBjb25maWcuJyk7XHJcblxyXG4gICAgICAvLyBOZWVkIHRvIHBlcmZvcm0gc3RyYWlnaHQgaW5qZWN0XHJcbiAgICAgIGlmIChleHBvcnRPcHRpb25zLnN0ckluaikge1xyXG4gICAgICAgIC8vIEluamVjdGlvbiBiYXNlZCBjb25maWd1cmF0aW9uIGV4cG9ydFxyXG4gICAgICAgIGF3YWl0IHNldEFzQ29uZmlnKFxyXG4gICAgICAgICAgcGFnZSxcclxuICAgICAgICAgIHtcclxuICAgICAgICAgICAgY2hhcnQ6IHtcclxuICAgICAgICAgICAgICBoZWlnaHQ6IGV4cG9ydE9wdGlvbnMuaGVpZ2h0LFxyXG4gICAgICAgICAgICAgIHdpZHRoOiBleHBvcnRPcHRpb25zLndpZHRoXHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0sXHJcbiAgICAgICAgICBvcHRpb25zXHJcbiAgICAgICAgKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICAvLyBCYXNpYyBjb25maWd1cmF0aW9uIGV4cG9ydFxyXG4gICAgICAgIGNoYXJ0LmNoYXJ0LmhlaWdodCA9IGV4cG9ydE9wdGlvbnMuaGVpZ2h0O1xyXG4gICAgICAgIGNoYXJ0LmNoYXJ0LndpZHRoID0gZXhwb3J0T3B0aW9ucy53aWR0aDtcclxuXHJcbiAgICAgICAgYXdhaXQgc2V0QXNDb25maWcocGFnZSwgY2hhcnQsIG9wdGlvbnMpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gVXNlIHJlc291cmNlc1xyXG4gICAgY29uc3QgcmVzb3VyY2VzID0gb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXM7XHJcbiAgICBpZiAocmVzb3VyY2VzKSB7XHJcbiAgICAgIC8vIExvYWQgY3VzdG9tIEpTIGNvZGVcclxuICAgICAgaWYgKHJlc291cmNlcy5qcykge1xyXG4gICAgICAgIGluamVjdGVkUmVzb3VyY2VzLnB1c2goXHJcbiAgICAgICAgICBhd2FpdCBwYWdlLmFkZFNjcmlwdFRhZyh7XHJcbiAgICAgICAgICAgIGNvbnRlbnQ6IHJlc291cmNlcy5qc1xyXG4gICAgICAgICAgfSlcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBMb2FkIHNjcmlwdHMgZnJvbSBhbGwgY3VzdG9tIGZpbGVzXHJcbiAgICAgIGlmIChyZXNvdXJjZXMuZmlsZXMpIHtcclxuICAgICAgICBmb3IgKGNvbnN0IGZpbGUgb2YgcmVzb3VyY2VzLmZpbGVzKSB7XHJcbiAgICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICBjb25zdCBpc0xvY2FsID0gIWZpbGUuc3RhcnRzV2l0aCgnaHR0cCcpID8gdHJ1ZSA6IGZhbHNlO1xyXG5cclxuICAgICAgICAgICAgLy8gQWRkIGVhY2ggY3VzdG9tIHNjcmlwdCBmcm9tIHJlc291cmNlcycgZmlsZXNcclxuICAgICAgICAgICAgaW5qZWN0ZWRSZXNvdXJjZXMucHVzaChcclxuICAgICAgICAgICAgICBhd2FpdCBwYWdlLmFkZFNjcmlwdFRhZyhcclxuICAgICAgICAgICAgICAgIGlzTG9jYWxcclxuICAgICAgICAgICAgICAgICAgPyB7XHJcbiAgICAgICAgICAgICAgICAgICAgICBjb250ZW50OiByZWFkRmlsZVN5bmMoZmlsZSwgJ3V0ZjgnKVxyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgOiB7XHJcbiAgICAgICAgICAgICAgICAgICAgICB1cmw6IGZpbGVcclxuICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgKVxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgICAgICAgIDIsXHJcbiAgICAgICAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgICAgICAgYFtleHBvcnRdIFRoZSBKUyBmaWxlICR7ZmlsZX0gY2Fubm90IGJlIGxvYWRlZC5gXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBMb2FkIENTU1xyXG4gICAgICBpZiAocmVzb3VyY2VzLmNzcykge1xyXG4gICAgICAgIGxldCBjc3NJbXBvcnRzID0gcmVzb3VyY2VzLmNzcy5tYXRjaCgvQGltcG9ydFxccyooW147XSopOy9nKTtcclxuICAgICAgICBpZiAoY3NzSW1wb3J0cykge1xyXG4gICAgICAgICAgLy8gSGFuZGxlIGNzcyBzZWN0aW9uXHJcbiAgICAgICAgICBmb3IgKGxldCBjc3NJbXBvcnRQYXRoIG9mIGNzc0ltcG9ydHMpIHtcclxuICAgICAgICAgICAgaWYgKGNzc0ltcG9ydFBhdGgpIHtcclxuICAgICAgICAgICAgICBjc3NJbXBvcnRQYXRoID0gY3NzSW1wb3J0UGF0aFxyXG4gICAgICAgICAgICAgICAgLnJlcGxhY2UoJ3VybCgnLCAnJylcclxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKCdAaW1wb3J0JywgJycpXHJcbiAgICAgICAgICAgICAgICAucmVwbGFjZSgvXCIvZywgJycpXHJcbiAgICAgICAgICAgICAgICAucmVwbGFjZSgvJy9nLCAnJylcclxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKC87LywgJycpXHJcbiAgICAgICAgICAgICAgICAucmVwbGFjZSgvXFwpL2csICcnKVxyXG4gICAgICAgICAgICAgICAgLnRyaW0oKTtcclxuXHJcbiAgICAgICAgICAgICAgLy8gQWRkIGVhY2ggY3VzdG9tIGNzcyBmcm9tIHJlc291cmNlc1xyXG4gICAgICAgICAgICAgIGlmIChjc3NJbXBvcnRQYXRoLnN0YXJ0c1dpdGgoJ2h0dHAnKSkge1xyXG4gICAgICAgICAgICAgICAgaW5qZWN0ZWRSZXNvdXJjZXMucHVzaChcclxuICAgICAgICAgICAgICAgICAgYXdhaXQgcGFnZS5hZGRTdHlsZVRhZyh7XHJcbiAgICAgICAgICAgICAgICAgICAgdXJsOiBjc3NJbXBvcnRQYXRoXHJcbiAgICAgICAgICAgICAgICAgIH0pXHJcbiAgICAgICAgICAgICAgICApO1xyXG4gICAgICAgICAgICAgIH0gZWxzZSBpZiAob3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0ZpbGVSZXNvdXJjZXMpIHtcclxuICAgICAgICAgICAgICAgIGluamVjdGVkUmVzb3VyY2VzLnB1c2goXHJcbiAgICAgICAgICAgICAgICAgIGF3YWl0IHBhZ2UuYWRkU3R5bGVUYWcoe1xyXG4gICAgICAgICAgICAgICAgICAgIHBhdGg6IHBhdGguam9pbihfX2Jhc2VkaXIsIGNzc0ltcG9ydFBhdGgpXHJcbiAgICAgICAgICAgICAgICAgIH0pXHJcbiAgICAgICAgICAgICAgICApO1xyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gVGhlIHJlc3Qgb2YgdGhlIENTUyBzZWN0aW9uIHdpbGwgYmUgY29udGVudCBieSBub3dcclxuICAgICAgICBpbmplY3RlZFJlc291cmNlcy5wdXNoKFxyXG4gICAgICAgICAgYXdhaXQgcGFnZS5hZGRTdHlsZVRhZyh7XHJcbiAgICAgICAgICAgIGNvbnRlbnQ6IHJlc291cmNlcy5jc3MucmVwbGFjZSgvQGltcG9ydFxccyooW147XSopOy9nLCAnJykgfHwgJyAnXHJcbiAgICAgICAgICB9KVxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBHZXQgdGhlIHJlYWwgY2hhcnQgc2l6ZVxyXG4gICAgY29uc3Qgc2l6ZSA9IGlzU1ZHXHJcbiAgICAgID8gYXdhaXQgcGFnZS4kZXZhbChcclxuICAgICAgICAgICcjY2hhcnQtY29udGFpbmVyIHN2ZzpmaXJzdC1vZi10eXBlJyxcclxuICAgICAgICAgIChlbGVtZW50LCBzY2FsZSkgPT4gKHtcclxuICAgICAgICAgICAgY2hhcnRIZWlnaHQ6IGVsZW1lbnQuaGVpZ2h0LmJhc2VWYWwudmFsdWUgKiBzY2FsZSxcclxuICAgICAgICAgICAgY2hhcnRXaWR0aDogZWxlbWVudC53aWR0aC5iYXNlVmFsLnZhbHVlICogc2NhbGVcclxuICAgICAgICAgIH0pLFxyXG4gICAgICAgICAgcGFyc2VGbG9hdChleHBvcnRPcHRpb25zLnNjYWxlKVxyXG4gICAgICAgIClcclxuICAgICAgOiBhd2FpdCBwYWdlLmV2YWx1YXRlKCgpID0+IHtcclxuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgICAgY29uc3QgeyBjaGFydEhlaWdodCwgY2hhcnRXaWR0aCB9ID0gd2luZG93LkhpZ2hjaGFydHMuY2hhcnRzWzBdO1xyXG4gICAgICAgICAgcmV0dXJuIHtcclxuICAgICAgICAgICAgY2hhcnRIZWlnaHQsXHJcbiAgICAgICAgICAgIGNoYXJ0V2lkdGhcclxuICAgICAgICAgIH07XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgLy8gU2V0IGZpbmFsIGhlaWdodCBhbmQgd2lkdGggZm9yIHZpZXdwb3J0XHJcbiAgICBjb25zdCB2aWV3cG9ydEhlaWdodCA9IE1hdGguY2VpbChzaXplPy5jaGFydEhlaWdodCB8fCBleHBvcnRPcHRpb25zLmhlaWdodCk7XHJcbiAgICBjb25zdCB2aWV3cG9ydFdpZHRoID0gTWF0aC5jZWlsKHNpemU/LmNoYXJ0V2lkdGggfHwgZXhwb3J0T3B0aW9ucy53aWR0aCk7XHJcblxyXG4gICAgLy8gU2V0IHRoZSB2aWV3cG9ydCBmb3IgdGhlIGZpcnN0IHRpbWVcclxuICAgIC8vIE5PVEU6IHRoZSBjYWxsIHRvIHNldFZpZXdwb3J0IGlzIGV4cGVuc2l2ZSAtIGNhbiB3ZSBnZXQgYXdheSB3aXRoIG9ubHlcclxuICAgIC8vIGNhbGxpbmcgaXQgb25jZSwgZS5nLiBtb3ZpbmcgdGhpcyBvbmUgaW50byB0aGUgaXNTVkcgY29uZGl0aW9uIGJlbG93P1xyXG4gICAgYXdhaXQgcGFnZS5zZXRWaWV3cG9ydCh7XHJcbiAgICAgIGhlaWdodDogdmlld3BvcnRIZWlnaHQsXHJcbiAgICAgIHdpZHRoOiB2aWV3cG9ydFdpZHRoLFxyXG4gICAgICBkZXZpY2VTY2FsZUZhY3RvcjogaXNTVkcgPyAxIDogcGFyc2VGbG9hdChleHBvcnRPcHRpb25zLnNjYWxlKVxyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gUHJlcGFyZSBhIHpvb20gY2FsbGJhY2sgZm9yIHRoZSBuZXh0IGV2YWx1YXRlIGNhbGxcclxuICAgIGNvbnN0IHpvb21DYWxsYmFjayA9IGlzU1ZHXHJcbiAgICAgID8gLy8gSW4gY2FzZSBvZiBTVkcgdGhlIHpvb20gbXVzdCBiZSBzZXQgZGlyZWN0bHkgZm9yIGJvZHlcclxuICAgICAgICAoc2NhbGUpID0+IHtcclxuICAgICAgICAgIC8vIFNldCB0aGUgem9vbSBhcyBzY2FsZVxyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLnpvb20gPSBzY2FsZTtcclxuXHJcbiAgICAgICAgICAvLyBTZXQgdGhlIG1hcmdpbiB0byAwcHhcclxuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgICAgZG9jdW1lbnQuYm9keS5zdHlsZS5tYXJnaW4gPSAnMHB4JztcclxuICAgICAgICB9XHJcbiAgICAgIDogLy8gTm8gbmVlZCBmb3Igc3VjaCBzY2FsZSBtYW5pcHVsYXRpb24gaW4gY2FzZSBvZiBvdGhlciB0eXBlcyBvZiBleHBvcnRzXHJcbiAgICAgICAgKCkgPT4ge1xyXG4gICAgICAgICAgLy8gUmVzZXQgdGhlIHpvb20gZm9yIG90aGVyIGV4cG9ydHMgdGhhbiB0byBTVkdzXHJcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUuem9vbSA9IDE7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAvLyBTZXQgdGhlIHpvb20gYWNjb3JkaW5nbHlcclxuICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoem9vbUNhbGxiYWNrLCBwYXJzZUZsb2F0KGV4cG9ydE9wdGlvbnMuc2NhbGUpKTtcclxuXHJcbiAgICAvLyBHZXQgdGhlIGNsaXAgcmVnaW9uIGZvciB0aGUgcGFnZVxyXG4gICAgY29uc3QgeyBoZWlnaHQsIHdpZHRoLCB4LCB5IH0gPSBhd2FpdCBnZXRDbGlwUmVnaW9uKHBhZ2UpO1xyXG5cclxuICAgIGlmICghaXNTVkcpIHtcclxuICAgICAgLy8gU2V0IHRoZSBmaW5hbCB2aWV3cG9ydCBub3cgdGhhdCB3ZSBoYXZlIHRoZSByZWFsIGhlaWdodFxyXG4gICAgICBhd2FpdCBwYWdlLnNldFZpZXdwb3J0KHtcclxuICAgICAgICB3aWR0aDogTWF0aC5yb3VuZCh3aWR0aCksXHJcbiAgICAgICAgaGVpZ2h0OiBNYXRoLnJvdW5kKGhlaWdodCksXHJcbiAgICAgICAgZGV2aWNlU2NhbGVGYWN0b3I6IHBhcnNlRmxvYXQoZXhwb3J0T3B0aW9ucy5zY2FsZSlcclxuICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgbGV0IGRhdGE7XHJcbiAgICAvLyBSQVNURVJJWkFUSU9OXHJcbiAgICBpZiAoZXhwb3J0T3B0aW9ucy50eXBlID09PSAnc3ZnJykge1xyXG4gICAgICAvLyBTVkdcclxuICAgICAgZGF0YSA9IGF3YWl0IGNyZWF0ZVNWRyhwYWdlKTtcclxuICAgIH0gZWxzZSBpZiAoWydwbmcnLCAnanBlZyddLmluY2x1ZGVzKGV4cG9ydE9wdGlvbnMudHlwZSkpIHtcclxuICAgICAgLy8gUE5HIG9yIEpQRUdcclxuICAgICAgZGF0YSA9IGF3YWl0IGNyZWF0ZUltYWdlKFxyXG4gICAgICAgIHBhZ2UsXHJcbiAgICAgICAgZXhwb3J0T3B0aW9ucy50eXBlLFxyXG4gICAgICAgICdiYXNlNjQnLFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIHdpZHRoOiB2aWV3cG9ydFdpZHRoLFxyXG4gICAgICAgICAgaGVpZ2h0OiB2aWV3cG9ydEhlaWdodCxcclxuICAgICAgICAgIHgsXHJcbiAgICAgICAgICB5XHJcbiAgICAgICAgfSxcclxuICAgICAgICBleHBvcnRPcHRpb25zLnJhc3Rlcml6YXRpb25UaW1lb3V0XHJcbiAgICAgICk7XHJcbiAgICB9IGVsc2UgaWYgKGV4cG9ydE9wdGlvbnMudHlwZSA9PT0gJ3BkZicpIHtcclxuICAgICAgLy8gUERGXHJcbiAgICAgIGRhdGEgPSBhd2FpdCBjcmVhdGVQREYocGFnZSwgdmlld3BvcnRIZWlnaHQsIHZpZXdwb3J0V2lkdGgsICdiYXNlNjQnKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICBgW2V4cG9ydF0gVW5zdXBwb3J0ZWQgb3V0cHV0IGZvcm1hdCAke2V4cG9ydE9wdGlvbnMudHlwZX0uYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIERlc3Ryb3kgb2xkIGNoYXJ0cyBhZnRlciB0aGUgZXhwb3J0IGlzIGRvbmVcclxuICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xyXG4gICAgICAvLyBXZSBhcmUgbm90IGd1YXJhbnRlZWQgdGhhdCBIaWdoY2hhcnRzIGlzIGxvYWRlZCwgZSxnLCB3aGVuIGRvaW5nIFNWR1xyXG4gICAgICAvLyBleHBvcnRzXHJcbiAgICAgIGlmICh0eXBlb2YgSGlnaGNoYXJ0cyAhPT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICBjb25zdCBvbGRDaGFydHMgPSBIaWdoY2hhcnRzLmNoYXJ0cztcclxuXHJcbiAgICAgICAgLy8gQ2hlY2sgaW4gYW55IGFscmVhZHkgZXhpc3RpbmcgY2hhcnRzXHJcbiAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkob2xkQ2hhcnRzKSAmJiBvbGRDaGFydHMubGVuZ3RoKSB7XHJcbiAgICAgICAgICAvLyBEZXN0cm95IG9sZCBjaGFydHNcclxuICAgICAgICAgIGZvciAoY29uc3Qgb2xkQ2hhcnQgb2Ygb2xkQ2hhcnRzKSB7XHJcbiAgICAgICAgICAgIG9sZENoYXJ0ICYmIG9sZENoYXJ0LmRlc3Ryb3koKTtcclxuICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICAgIEhpZ2hjaGFydHMuY2hhcnRzLnNoaWZ0KCk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9KTtcclxuXHJcbiAgICBhd2FpdCBjbGVhckluamVjdGVkKHBhZ2UpO1xyXG4gICAgcmV0dXJuIGRhdGE7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIGF3YWl0IGNsZWFySW5qZWN0ZWQocGFnZSk7XHJcbiAgICByZXR1cm4gZXJyb3I7XHJcbiAgfVxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCBjc3NUZW1wbGF0ZSBmcm9tICcuL2Nzcy5qcyc7XHJcblxyXG5leHBvcnQgZGVmYXVsdCAoY2hhcnQpID0+IGBcclxuPCFET0NUWVBFIGh0bWw+XHJcbjxodG1sIGxhbmc9J2VuLVVTJz5cclxuICA8aGVhZD5cclxuICAgIDxtZXRhIGh0dHAtZXF1aXY9XCJDb250ZW50LVR5cGVcIiBjb250ZW50PVwidGV4dC9odG1sOyBjaGFyc2V0PXV0Zi04XCI+XHJcbiAgICA8dGl0bGU+SGlnaGNhcnRzIEV4cG9ydDwvdGl0bGU+XHJcbiAgPC9oZWFkPlxyXG4gIDxzdHlsZT5cclxuICAgICR7Y3NzVGVtcGxhdGUoKX1cclxuICA8L3N0eWxlPlxyXG4gIDxib2R5PlxyXG4gICAgPGRpdiBpZD1cImNoYXJ0LWNvbnRhaW5lclwiPlxyXG4gICAgICAke2NoYXJ0fVxyXG4gICAgPC9kaXY+XHJcbiAgPC9ib2R5PlxyXG48L2h0bWw+XHJcblxyXG5gO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IFBvb2wgfSBmcm9tICd0YXJuJztcclxuaW1wb3J0IHsgdjQgYXMgdXVpZCB9IGZyb20gJ3V1aWQnO1xyXG5cclxuaW1wb3J0IHtcclxuICBjbG9zZSBhcyBicm93c2VyQ2xvc2UsXHJcbiAgY3JlYXRlIGFzIGNyZWF0ZUJyb3dzZXIsXHJcbiAgbmV3UGFnZSBhcyBicm93c2VyTmV3UGFnZSxcclxuICBjbGVhclBhZ2VcclxufSBmcm9tICcuL2Jyb3dzZXIuanMnO1xyXG5pbXBvcnQgcHVwcGV0ZWVyRXhwb3J0IGZyb20gJy4vZXhwb3J0LmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IG1lYXN1cmVUaW1lIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxubGV0IHBlcmZvcm1lZEV4cG9ydHMgPSAwO1xyXG5sZXQgZXhwb3J0QXR0ZW1wdHMgPSAwO1xyXG5sZXQgdGltZVNwZW50ID0gMDtcclxubGV0IGRyb3BwZWRFeHBvcnRzID0gMDtcclxubGV0IHNwZW50QXZlcmFnZSA9IDA7XHJcbmxldCBwb29sQ29uZmlnID0ge307XHJcblxyXG4vLyBUaGUgcG9vbCBpbnN0YW5jZVxyXG5sZXQgcG9vbCA9IGZhbHNlO1xyXG5cclxuLy8gQ3VzdG9tIHB1cHBldGVlciBhcmd1bWVudHNcclxubGV0IHB1cHBldGVlckFyZ3M7XHJcblxyXG5jb25zdCBmYWN0b3J5ID0ge1xyXG4gIC8qKlxyXG4gICAqIENyZWF0ZXMgYSBuZXcgd29ya2VyIHBhZ2UgZm9yIHRoZSBleHBvcnQgcG9vbC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHtPYmplY3R9IC0gQW4gb2JqZWN0IGNvbnRhaW5pbmcgdGhlIHdvcmtlciBJRCwgYSByZWZlcmVuY2UgdG8gdGhlXHJcbiAgICogYnJvd3NlciBwYWdlLCBhbmQgaW5pdGlhbCB3b3JrIGNvdW50LlxyXG4gICAqXHJcbiAgICogQHRocm93cyB7RXhwb3J0RXJyb3J9IC0gSWYgdGhlcmUncyBhbiBlcnJvciBkdXJpbmcgdGhlIGNyZWF0aW9uIG9mIHRoZSBuZXdcclxuICAgKiBwYWdlLlxyXG4gICAqL1xyXG4gIGNyZWF0ZTogYXN5bmMgKCkgPT4ge1xyXG4gICAgbGV0IHBhZ2UgPSBmYWxzZTtcclxuXHJcbiAgICBjb25zdCBpZCA9IHV1aWQoKTtcclxuICAgIGNvbnN0IHN0YXJ0RGF0ZSA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xyXG5cclxuICAgIHRyeSB7XHJcbiAgICAgIHBhZ2UgPSBhd2FpdCBicm93c2VyTmV3UGFnZSgpO1xyXG5cclxuICAgICAgaWYgKCFwYWdlIHx8IHBhZ2UuaXNDbG9zZWQoKSkge1xyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignVGhlIHBhZ2UgaXMgaW52YWxpZCBvciBjbG9zZWQuJyk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGxvZyhcclxuICAgICAgICAzLFxyXG4gICAgICAgIGBbcG9vbF0gU3VjY2Vzc2Z1bGx5IGNyZWF0ZWQgYSB3b3JrZXIgJHtpZH0gLSB0b29rICR7XHJcbiAgICAgICAgICBuZXcgRGF0ZSgpLmdldFRpbWUoKSAtIHN0YXJ0RGF0ZVxyXG4gICAgICAgIH0gbXMuYFxyXG4gICAgICApO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdFcnJvciBlbmNvdW50ZXJlZCB3aGVuIGNyZWF0aW5nIGEgbmV3IHBhZ2UuJ1xyXG4gICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4ge1xyXG4gICAgICBpZCxcclxuICAgICAgcGFnZSxcclxuICAgICAgLy8gVHJ5IHRvIGRpc3RyaWJ1dGUgdGhlIGluaXRpYWwgd29yayBjb3VudFxyXG4gICAgICB3b3JrQ291bnQ6IE1hdGgucm91bmQoTWF0aC5yYW5kb20oKSAqIChwb29sQ29uZmlnLndvcmtMaW1pdCAvIDIpKVxyXG4gICAgfTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBWYWxpZGF0ZXMgYSB3b3JrZXIgcGFnZSBpbiB0aGUgZXhwb3J0IHBvb2wsIGNoZWNraW5nIGlmIGl0IGhhcyBleGNlZWRlZFxyXG4gICAqIHRoZSB3b3JrIGxpbWl0LlxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtPYmplY3R9IHdvcmtlckhhbmRsZSAtIFRoZSBoYW5kbGUgdG8gdGhlIHdvcmtlciwgY29udGFpbmluZyB0aGVcclxuICAgKiB3b3JrZXIncyBJRCwgYSByZWZlcmVuY2UgdG8gdGhlIGJyb3dzZXIgcGFnZSwgYW5kIHdvcmsgY291bnQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBSZXR1cm5zIHRydWUgaWYgdGhlIHdvcmtlciBpcyB2YWxpZCBhbmQgd2l0aGluXHJcbiAgICogdGhlIHdvcmsgbGltaXQ7IG90aGVyd2lzZSwgcmV0dXJucyBmYWxzZS5cclxuICAgKi9cclxuICB2YWxpZGF0ZTogYXN5bmMgKHdvcmtlckhhbmRsZSkgPT4ge1xyXG4gICAgaWYgKFxyXG4gICAgICBwb29sQ29uZmlnLndvcmtMaW1pdCAmJlxyXG4gICAgICArK3dvcmtlckhhbmRsZS53b3JrQ291bnQgPiBwb29sQ29uZmlnLndvcmtMaW1pdFxyXG4gICAgKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICAzLFxyXG4gICAgICAgIGBbcG9vbF0gV29ya2VyIGZhaWxlZCB2YWxpZGF0aW9uOiBleGNlZWRlZCB3b3JrIGxpbWl0IChsaW1pdCBpcyAke3Bvb2xDb25maWcud29ya0xpbWl0fSkuYFxyXG4gICAgICApO1xyXG4gICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2xlYXIgcGFnZVxyXG4gICAgYXdhaXQgY2xlYXJQYWdlKHdvcmtlckhhbmRsZS5wYWdlLCB0cnVlKTtcclxuICAgIHJldHVybiB0cnVlO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIERlc3Ryb3lzIGEgd29ya2VyIGVudHJ5IGluIHRoZSBleHBvcnQgcG9vbCwgY2xvc2luZyBpdHMgYXNzb2NpYXRlZCBwYWdlLlxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtPYmplY3R9IHdvcmtlckhhbmRsZSAtIFRoZSBoYW5kbGUgdG8gdGhlIHdvcmtlciwgY29udGFpbmluZ1xyXG4gICAqIHRoZSB3b3JrZXIncyBJRCBhbmQgYSByZWZlcmVuY2UgdG8gdGhlIGJyb3dzZXIgcGFnZS5cclxuICAgKi9cclxuICBkZXN0cm95OiAod29ya2VySGFuZGxlKSA9PiB7XHJcbiAgICBsb2coMywgYFtwb29sXSBEZXN0cm95aW5nIHBvb2wgZW50cnkgJHt3b3JrZXJIYW5kbGUuaWR9LmApO1xyXG5cclxuICAgIGlmICh3b3JrZXJIYW5kbGUucGFnZSkge1xyXG4gICAgICAvLyBXZSBkb24ndCByZWFsbHkgbmVlZCB0byB3YWl0IGFyb3VuZCBmb3IgdGhpcy5cclxuICAgICAgd29ya2VySGFuZGxlLnBhZ2UuY2xvc2UoKTtcclxuICAgIH1cclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgdGhlIGV4cG9ydCBwb29sIHdpdGggdGhlIHByb3ZpZGVkIGNvbmZpZ3VyYXRpb24sIGNyZWF0aW5nXHJcbiAqIGEgYnJvd3NlciBpbnN0YW5jZSBhbmQgc2V0dGluZyB1cCB3b3JrZXIgcmVzb3VyY2VzLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnIC0gQ29uZmlndXJhdGlvbiBvcHRpb25zIGZvciB0aGUgZXhwb3J0IHBvb2wgYWxvbmdcclxuICogd2l0aCBjdXN0b20gcHVwcGV0ZWVyIGFyZ3VtZW50cyBmb3IgdGhlIHB1cHBldGVlci5sYXVuY2ggZnVuY3Rpb24uXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaW5pdFBvb2wgPSBhc3luYyAoY29uZmlnKSA9PiB7XHJcbiAgLy8gRm9yIHRoZSBtb2R1bGUgc2NvcGUgdXNhZ2VcclxuICBwb29sQ29uZmlnID0gY29uZmlnICYmIGNvbmZpZy5wb29sID8geyAuLi5jb25maWcucG9vbCB9IDoge307XHJcblxyXG4gIC8vIEF0dGFjaCBwcm9jZXNzJyBleGl0IGxpc3RlbmVyc1xyXG4gIGlmIChwb29sQ29uZmlnLmxpc3RlblRvUHJvY2Vzc0V4aXRzKSB7XHJcbiAgICBhdHRhY2hQcm9jZXNzRXhpdExpc3RlbmVycygpO1xyXG4gIH1cclxuXHJcbiAgLy8gVGhlIG5ld2VzdCBwdXBwZXRlZXIgYXJndW1lbnRzIGZvciB0aGUgYnJvd3NlciBjcmVhdGlvblxyXG4gIHB1cHBldGVlckFyZ3MgPSBjb25maWcucHVwcGV0ZWVyQXJncztcclxuXHJcbiAgLy8gQ3JlYXRlIGEgYnJvd3NlciBpbnN0YW5jZVxyXG4gIGF3YWl0IGNyZWF0ZUJyb3dzZXIocHVwcGV0ZWVyQXJncyk7XHJcblxyXG4gIGxvZyhcclxuICAgIDMsXHJcbiAgICBgW3Bvb2xdIEluaXRpYWxpemluZyBwb29sIHdpdGggd29ya2VyczogbWluICR7cG9vbENvbmZpZy5taW5Xb3JrZXJzfSwgbWF4ICR7cG9vbENvbmZpZy5tYXhXb3JrZXJzfS5gXHJcbiAgKTtcclxuXHJcbiAgaWYgKHBvb2wpIHtcclxuICAgIHJldHVybiBsb2coXHJcbiAgICAgIDQsXHJcbiAgICAgICdbcG9vbF0gQWxyZWFkeSBpbml0aWFsaXplZCwgcGxlYXNlIGtpbGwgaXQgYmVmb3JlIGNyZWF0aW5nIGEgbmV3IG9uZS4nXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgaWYgKHBhcnNlSW50KHBvb2xDb25maWcubWluV29ya2VycykgPiBwYXJzZUludChwb29sQ29uZmlnLm1heFdvcmtlcnMpKSB7XHJcbiAgICBwb29sQ29uZmlnLm1pbldvcmtlcnMgPSBwb29sQ29uZmlnLm1heFdvcmtlcnM7XHJcbiAgfVxyXG5cclxuICB0cnkge1xyXG4gICAgLy8gQ3JlYXRlIGEgcG9vbCBhbG9uZyB3aXRoIGEgbWluaW1hbCBudW1iZXIgb2YgcmVzb3VyY2VzXHJcbiAgICBwb29sID0gbmV3IFBvb2woe1xyXG4gICAgICAvLyBHZXQgdGhlIGNyZWF0ZS92YWxpZGF0ZS9kZXN0cm95L2xvZyBmdW5jdGlvbnNcclxuICAgICAgLi4uZmFjdG9yeSxcclxuICAgICAgbWluOiBwYXJzZUludChwb29sQ29uZmlnLm1pbldvcmtlcnMpLFxyXG4gICAgICBtYXg6IHBhcnNlSW50KHBvb2xDb25maWcubWF4V29ya2VycyksXHJcbiAgICAgIGFjcXVpcmVUaW1lb3V0TWlsbGlzOiBwb29sQ29uZmlnLmFjcXVpcmVUaW1lb3V0LFxyXG4gICAgICBjcmVhdGVUaW1lb3V0TWlsbGlzOiBwb29sQ29uZmlnLmNyZWF0ZVRpbWVvdXQsXHJcbiAgICAgIGRlc3Ryb3lUaW1lb3V0TWlsbGlzOiBwb29sQ29uZmlnLmRlc3Ryb3lUaW1lb3V0LFxyXG4gICAgICBpZGxlVGltZW91dE1pbGxpczogcG9vbENvbmZpZy5pZGxlVGltZW91dCxcclxuICAgICAgY3JlYXRlUmV0cnlJbnRlcnZhbE1pbGxpczogcG9vbENvbmZpZy5jcmVhdGVSZXRyeUludGVydmFsLFxyXG4gICAgICByZWFwSW50ZXJ2YWxNaWxsaXM6IHBvb2xDb25maWcucmVhcGVySW50ZXJ2YWwsXHJcbiAgICAgIHByb3BhZ2F0ZUNyZWF0ZUVycm9yOiBmYWxzZVxyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gU2V0IGV2ZW50c1xyXG4gICAgcG9vbC5vbigncmVsZWFzZScsIGFzeW5jIChyZXNvdXJjZSkgPT4ge1xyXG4gICAgICAvLyBDbGVhciBwYWdlXHJcbiAgICAgIGF3YWl0IGNsZWFyUGFnZShyZXNvdXJjZS5wYWdlLCBmYWxzZSk7XHJcbiAgICAgIGxvZyg0LCBgW3Bvb2xdIFJlbGVhc2luZyBhIHdvcmtlciB3aXRoIElEICR7cmVzb3VyY2UuaWR9LmApO1xyXG4gICAgfSk7XHJcblxyXG4gICAgcG9vbC5vbignZGVzdHJveVN1Y2Nlc3MnLCAoZXZlbnRJZCwgcmVzb3VyY2UpID0+IHtcclxuICAgICAgbG9nKDQsIGBbcG9vbF0gRGVzdHJveWVkIGEgd29ya2VyIHdpdGggSUQgJHtyZXNvdXJjZS5pZH0uYCk7XHJcbiAgICB9KTtcclxuXHJcbiAgICBjb25zdCBpbml0aWFsUmVzb3VyY2VzID0gW107XHJcbiAgICAvLyBDcmVhdGUgYW4gaW5pdGlhbCBudW1iZXIgb2YgcmVzb3VyY2VzXHJcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHBvb2xDb25maWcubWluV29ya2VyczsgaSsrKSB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgY29uc3QgcmVzb3VyY2UgPSBhd2FpdCBwb29sLmFjcXVpcmUoKS5wcm9taXNlO1xyXG4gICAgICAgIGluaXRpYWxSZXNvdXJjZXMucHVzaChyZXNvdXJjZSk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCAnW3Bvb2xdIENvdWxkIG5vdCBjcmVhdGUgYW4gaW5pdGlhbCByZXNvdXJjZS4nKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIFJlbGVhc2UgdGhlIGluaXRpYWwgbnVtYmVyIG9mIHJlc291cmNlcyBiYWNrIHRvIHRoZSBwb29sXHJcbiAgICBpbml0aWFsUmVzb3VyY2VzLmZvckVhY2goKHJlc291cmNlKSA9PiB7XHJcbiAgICAgIHBvb2wucmVsZWFzZShyZXNvdXJjZSk7XHJcbiAgICB9KTtcclxuXHJcbiAgICBsb2coXHJcbiAgICAgIDMsXHJcbiAgICAgIGBbcG9vbF0gVGhlIHBvb2wgaXMgcmVhZHkke2luaXRpYWxSZXNvdXJjZXMubGVuZ3RoID8gYCB3aXRoICR7aW5pdGlhbFJlc291cmNlcy5sZW5ndGh9IGluaXRpYWwgcmVzb3VyY2VzIHdhaXRpbmcuYCA6ICcuJ31gXHJcbiAgICApO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAvLyBDbG9zZSBicm93c2VyIGlmIGZvciBzb21lIHJlYXNvbiBjYW5ub3QgZXN0YWJsaXNoIHRoZSBwb29sXHJcbiAgICBhd2FpdCBicm93c2VyQ2xvc2UoKTtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1twb29sXSBDb3VsZCBub3QgY3JlYXRlIHRoZSBwb29sIG9mIHdvcmtlcnMuJ1xyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEF0dGFjaGVzIGV4aXQgbGlzdGVuZXJzIHRvIHRoZSBwcm9jZXNzLCBlbnN1cmluZyBwcm9wZXIgY2xlYW51cCBvZiByZXNvdXJjZXNcclxuICogYW5kIHRlcm1pbmF0aW9uIG9uIGV4aXQgc2lnbmFscy4gSGFuZGxlcyAnZXhpdCcsICdTSUdJTlQnLCAnU0lHVEVSTScsIGFuZFxyXG4gKiAndW5jYXVnaHRFeGNlcHRpb24nIGV2ZW50cy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBhdHRhY2hQcm9jZXNzRXhpdExpc3RlbmVycygpIHtcclxuICBsb2coMywgJ1twb29sXSBBdHRhY2hpbmcgZXhpdCBsaXN0ZW5lcnMgdG8gdGhlIHByb2Nlc3MuJyk7XHJcblxyXG4gIC8vIEtpbGwgYWxsIHBvb2wgcmVzb3VyY2VzIG9uIGV4aXRcclxuICBwcm9jZXNzLm9uKCdleGl0JywgYXN5bmMgKGNvZGUpID0+IHtcclxuICAgIGxvZyg0LCBgUHJvY2VzcyBleGl0ZWQgd2l0aCBjb2RlICR7Y29kZX0uYCk7XHJcbiAgICBhd2FpdCBraWxsUG9vbCgpO1xyXG4gIH0pO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgU0lHSU5UXHJcbiAgcHJvY2Vzcy5vbignU0lHSU5UJywgKG5hbWUsIGNvZGUpID0+IHtcclxuICAgIGxvZyg0LCBgVGhlICR7bmFtZX0gZXZlbnQgd2l0aCBjb2RlOiAke2NvZGV9LmApO1xyXG4gICAgcHJvY2Vzcy5leGl0KDEpO1xyXG4gIH0pO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgU0lHVEVSTVxyXG4gIHByb2Nlc3Mub24oJ1NJR1RFUk0nLCAobmFtZSwgY29kZSkgPT4ge1xyXG4gICAgbG9nKDQsIGBUaGUgJHtuYW1lfSBldmVudCB3aXRoIGNvZGU6ICR7Y29kZX0uYCk7XHJcbiAgICBwcm9jZXNzLmV4aXQoMSk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSB1bmNhdWdodEV4Y2VwdGlvblxyXG4gIHByb2Nlc3Mub24oJ3VuY2F1Z2h0RXhjZXB0aW9uJywgYXN5bmMgKGVycm9yLCBuYW1lKSA9PiB7XHJcbiAgICBsb2dXaXRoU3RhY2soMSwgZXJyb3IsIGBUaGUgJHtuYW1lfSBlcnJvci5gKTtcclxuICAgIGF3YWl0IGtpbGxQb29sKCk7XHJcbiAgICBwcm9jZXNzLmV4aXQoMSk7XHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBLaWxscyBhbGwgd29ya2VycyBpbiB0aGUgcG9vbCwgZGVzdHJveXMgdGhlIHBvb2wsIGFuZCBjbG9zZXMgdGhlIGJyb3dzZXJcclxuICogaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyBhZnRlciB0aGUgd29ya2VycyBhcmVcclxuICoga2lsbGVkLCB0aGUgcG9vbCBpcyBkZXN0cm95ZWQsIGFuZCB0aGUgYnJvd3NlciBpcyBjbG9zZWQuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24ga2lsbFBvb2woKSB7XHJcbiAgbG9nKDMsICdbcG9vbF0gS2lsbGluZyBhbGwgcG9vbCB3b3JrZXJzIGFuZCBicm93c2VyLCBpZiBhbnkgZXhpc3QuJyk7XHJcblxyXG4gIC8vIFJldHVybiB0cnVlIHdoZW4gdGhlIHBvb2wgaXMgYWxyZWFkeSBkZXN0cm95ZWRcclxuICBpZiAocG9vbD8uZGVzdHJveWVkKSB7XHJcbiAgICAvLyBDbG9zZSB0aGUgYnJvd3NlciBpbnN0YW5jZSBpZiBzdGlsbCBjb25uZWN0ZWRcclxuICAgIHJldHVybiBicm93c2VyQ2xvc2UoKTtcclxuICB9XHJcblxyXG4gIC8vIElmIHN0aWxsIGFsaXZlLCBkZXN0cm95IHRoZSBwb29sIG9mIHBhZ2VzIGJlZm9yZSBjbG9zaW5nIGEgYnJvd3NlclxyXG4gIGlmIChwb29sKSB7XHJcbiAgICBhd2FpdCBwb29sLmRlc3Ryb3koKTtcclxuICAgIGxvZyg0LCAnW2Jyb3dzZXJdIERlc3Ryb3llZCB0aGUgcG9vbCBvZiByZXNvdXJjZXMuJyk7XHJcbiAgfVxyXG5cclxuICAvLyBDbG9zZSB0aGUgYnJvd3NlciBpbnN0YW5jZVxyXG4gIHJldHVybiBicm93c2VyQ2xvc2UoKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFByb2Nlc3NlcyB0aGUgZXhwb3J0IHdvcmsgdXNpbmcgYSB3b3JrZXIgZnJvbSB0aGUgcG9vbC4gQWNxdWlyZXMgYSB3b3JrZXJcclxuICogaGFuZGxlIGZyb20gdGhlIHBvb2wsIHBlcmZvcm1zIHRoZSBleHBvcnQgdXNpbmcgcHVwcGV0ZWVyLCBhbmQgcmVsZWFzZXNcclxuICogdGhlIHdvcmtlciBoYW5kbGUgYmFjayB0byB0aGUgcG9vbC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGNoYXJ0IC0gVGhlIGNoYXJ0IGRhdGEgb3IgY29uZmlndXJhdGlvbiB0byBiZSBleHBvcnRlZC5cclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBFeHBvcnQgb3B0aW9ucyBhbmQgY29uZmlndXJhdGlvbi5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2l0aCB0aGUgZXhwb3J0IHJlc3VsdGFuZFxyXG4gKiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gSWYgYW4gZXJyb3Igb2NjdXJzIGR1cmluZyB0aGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgcG9zdFdvcmsgPSBhc3luYyAoY2hhcnQsIG9wdGlvbnMpID0+IHtcclxuICBsZXQgd29ya2VySGFuZGxlO1xyXG5cclxuICB0cnkge1xyXG4gICAgbG9nKDQsICdbcG9vbF0gV29yayByZWNlaXZlZCwgc3RhcnRpbmcgdG8gcHJvY2Vzcy4nKTtcclxuXHJcbiAgICArK2V4cG9ydEF0dGVtcHRzO1xyXG4gICAgaWYgKHBvb2xDb25maWcuYmVuY2htYXJraW5nKSB7XHJcbiAgICAgIGdldFBvb2xJbmZvKCk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKCFwb29sKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignV29yayByZWNlaXZlZCwgYnV0IHBvb2wgaGFzIG5vdCBiZWVuIHN0YXJ0ZWQuJyk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQWNxdWlyZSB0aGUgd29ya2VyIGFsb25nIHdpdGggdGhlIGlkIG9mIHJlc291cmNlIGFuZCB3b3JrIGNvdW50XHJcbiAgICB0cnkge1xyXG4gICAgICBsb2coNCwgJ1twb29sXSBBY3F1aXJpbmcgYSB3b3JrZXIgaGFuZGxlLicpO1xyXG4gICAgICBjb25zdCBhY3F1aXJlQ291bnRlciA9IG1lYXN1cmVUaW1lKCk7XHJcbiAgICAgIHdvcmtlckhhbmRsZSA9IGF3YWl0IHBvb2wuYWNxdWlyZSgpLnByb21pc2U7XHJcblxyXG4gICAgICAvLyBDaGVjayB0aGUgcGFnZSBhY3F1aXJlIHRpbWVcclxuICAgICAgaWYgKG9wdGlvbnMuc2VydmVyLmJlbmNobWFya2luZykge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDUsXHJcbiAgICAgICAgICBvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZFxyXG4gICAgICAgICAgICA/IGBbYmVuY2htYXJrXSBSZXF1ZXN0IHdpdGggSUQgJHtvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZH0gLWBcclxuICAgICAgICAgICAgOiAnW2JlbmNobWFya10nLFxyXG4gICAgICAgICAgYEFjcXVpcmVkIGEgd29ya2VyIGhhbmRsZTogJHthY3F1aXJlQ291bnRlcigpfW1zLmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ0Vycm9yIGVuY291bnRlcmVkIHdoZW4gYWNxdWlyaW5nIGFuIGF2YWlsYWJsZSBlbnRyeS4nXHJcbiAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgfVxyXG4gICAgbG9nKDQsICdbcG9vbF0gQWNxdWlyZWQgYSB3b3JrZXIgaGFuZGxlLicpO1xyXG5cclxuICAgIGlmICghd29ya2VySGFuZGxlLnBhZ2UpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdSZXNvbHZlZCB3b3JrZXIgcGFnZSBpcyBpbnZhbGlkOiB0aGUgcG9vbCBzZXR1cCBpcyB3b25reS4nXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU2F2ZSB0aGUgc3RhcnQgdGltZVxyXG4gICAgbGV0IHdvcmtTdGFydCA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xyXG5cclxuICAgIGxvZyg0LCBgW3Bvb2xdIFN0YXJ0aW5nIHdvcmsgb24gcG9vbCBlbnRyeSB3aXRoIElEICR7d29ya2VySGFuZGxlLmlkfS5gKTtcclxuXHJcbiAgICAvLyBQZXJmb3JtIGFuIGV4cG9ydCBvbiBhIHB1cHBldGVlciBsZXZlbFxyXG4gICAgY29uc3QgZXhwb3J0Q291bnRlciA9IG1lYXN1cmVUaW1lKCk7XHJcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBwdXBwZXRlZXJFeHBvcnQod29ya2VySGFuZGxlLnBhZ2UsIGNoYXJ0LCBvcHRpb25zKTtcclxuXHJcbiAgICAvLyBDaGVjayBpZiBpdCdzIGFuIGVycm9yXHJcbiAgICBpZiAocmVzdWx0IGluc3RhbmNlb2YgRXJyb3IpIHtcclxuICAgICAgLy8gVE9ETzogSWYgdGhlIGV4cG9ydCBmYWlsZWQgYmVjYXVzZSBwdXBwZXRlZXIgdGltZWQgb3V0LCB3ZSBuZWVkIHRvIGZvcmNlIGtpbGwgdGhlIHdvcmtlciBzbyB3ZSBnZXQgYSBuZXcgcGFnZS4gVGhhdCBuZWVkcyB0byBiZSBoYW5kbGVkIGJldHRlciB0aGFuIHRoaXMgaGFjay5cclxuICAgICAgaWYgKHJlc3VsdC5tZXNzYWdlID09PSAnUmFzdGVyaXphdGlvbiB0aW1lb3V0Jykge1xyXG4gICAgICAgIHdvcmtlckhhbmRsZS5wYWdlLmNsb3NlKCk7XHJcbiAgICAgICAgd29ya2VySGFuZGxlLnBhZ2UgPSBhd2FpdCBicm93c2VyTmV3UGFnZSgpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ0Vycm9yIGVuY291bnRlcmVkIGR1cmluZyBleHBvcnQuJykuc2V0RXJyb3IoXHJcbiAgICAgICAgcmVzdWx0XHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2hlY2sgdGhlIFB1cHBldGVlciBleHBvcnQgdGltZVxyXG4gICAgaWYgKG9wdGlvbnMuc2VydmVyLmJlbmNobWFya2luZykge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgNSxcclxuICAgICAgICBvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZFxyXG4gICAgICAgICAgPyBgW2JlbmNobWFya10gUmVxdWVzdCB3aXRoIElEICR7b3B0aW9ucy5wYXlsb2FkPy5yZXF1ZXN0SWR9IC1gXHJcbiAgICAgICAgICA6ICdbYmVuY2htYXJrXScsXHJcbiAgICAgICAgYEV4cG9ydGVkIGEgY2hhcnQgc3VjZXNzZnVsbHk6ICR7ZXhwb3J0Q291bnRlcigpfW1zLmBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBSZWxlYXNlIHRoZSByZXNvdXJjZSBiYWNrIHRvIHRoZSBwb29sXHJcbiAgICBwb29sLnJlbGVhc2Uod29ya2VySGFuZGxlKTtcclxuXHJcbiAgICAvLyBVc2VkIGZvciBzdGF0aXN0aWNzIGluIGF2ZXJhZ2VUaW1lIGFuZCBwcm9jZXNzZWRXb3JrQ291bnQsIHdoaWNoXHJcbiAgICAvLyBpbiB0dXJuIGlzIHVzZWQgYnkgdGhlIC9oZWFsdGggcm91dGUuXHJcbiAgICBjb25zdCB3b3JrRW5kID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XHJcbiAgICBjb25zdCBleHBvcnRUaW1lID0gd29ya0VuZCAtIHdvcmtTdGFydDtcclxuICAgIHRpbWVTcGVudCArPSBleHBvcnRUaW1lO1xyXG4gICAgc3BlbnRBdmVyYWdlID0gdGltZVNwZW50IC8gKytwZXJmb3JtZWRFeHBvcnRzO1xyXG5cclxuICAgIGxvZyg0LCBgW3Bvb2xdIFdvcmsgY29tcGxldGVkIGluICR7ZXhwb3J0VGltZX0gbXMuYCk7XHJcblxyXG4gICAgLy8gT3RoZXJ3aXNlIHJldHVybiB0aGUgcmVzdWx0XHJcbiAgICByZXR1cm4ge1xyXG4gICAgICByZXN1bHQsXHJcbiAgICAgIG9wdGlvbnNcclxuICAgIH07XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICsrZHJvcHBlZEV4cG9ydHM7XHJcblxyXG4gICAgaWYgKHdvcmtlckhhbmRsZSkge1xyXG4gICAgICBwb29sLnJlbGVhc2Uod29ya2VySGFuZGxlKTtcclxuICAgIH1cclxuXHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoYFtwb29sXSBJbiBwb29sLnBvc3RXb3JrOiAke2Vycm9yLm1lc3NhZ2V9YCkuc2V0RXJyb3IoXHJcbiAgICAgIGVycm9yXHJcbiAgICApO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgdGhlIGN1cnJlbnQgcG9vbCBpbnN0YW5jZS5cclxuICpcclxuICogQHJldHVybnMge09iamVjdHxudWxsfSBUaGUgY3VycmVudCBwb29sIGluc3RhbmNlIGlmIGluaXRpYWxpemVkLCBvciBudWxsXHJcbiAqIGlmIHRoZSBwb29sIGhhcyBub3QgYmVlbiBjcmVhdGVkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldFBvb2woKSB7XHJcbiAgcmV0dXJuIHBvb2w7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgcG9vbCBpbmZvcm1hdGlvbiBpbiBKU09OIGZvcm1hdCwgaW5jbHVkaW5nIG1pbmltdW0gYW5kIG1heGltdW1cclxuICogd29ya2VycywgYXZhaWxhYmxlIHdvcmtlcnMsIHdvcmtlcnMgaW4gdXNlLCBhbmQgcGVuZGluZyBhY3F1aXJlIHJlcXVlc3RzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBQb29sIGluZm9ybWF0aW9uIGluIEpTT04gZm9ybWF0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldFBvb2xJbmZvSlNPTiA9ICgpID0+ICh7XHJcbiAgbWluOiBwb29sLm1pbixcclxuICBtYXg6IHBvb2wubWF4LFxyXG4gIGF2YWlsYWJsZTogcG9vbC5udW1GcmVlKCksXHJcbiAgaW5Vc2U6IHBvb2wubnVtVXNlZCgpLFxyXG4gIHBlbmRpbmdBY3F1aXJlOiBwb29sLm51bVBlbmRpbmdBY3F1aXJlcygpXHJcbn0pO1xyXG5cclxuLyoqXHJcbiAqIExvZ3MgaW5mb3JtYXRpb24gYWJvdXQgdGhlIGN1cnJlbnQgc3RhdGUgb2YgdGhlIHBvb2wsIGluY2x1ZGluZyB0aGUgbWluaW11bVxyXG4gKiBhbmQgbWF4aW11bSB3b3JrZXJzLCBhdmFpbGFibGUgd29ya2Vycywgd29ya2VycyBpbiB1c2UsIGFuZCBwZW5kaW5nIGFjcXVpcmVcclxuICogcmVxdWVzdHMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0UG9vbEluZm8oKSB7XHJcbiAgY29uc3QgeyBtaW4sIG1heCB9ID0gcG9vbDtcclxuXHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG1pbmltdW0gbnVtYmVyIG9mIHJlc291cmNlcyBhbGxvd2VkIGJ5IHBvb2w6ICR7bWlufS5gKTtcclxuICBsb2coNSwgYFtwb29sXSBUaGUgbWF4aW11bSBudW1iZXIgb2YgcmVzb3VyY2VzIGFsbG93ZWQgYnkgcG9vbDogJHttYXh9LmApO1xyXG4gIGxvZyhcclxuICAgIDUsXHJcbiAgICBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgcmVzb3VyY2VzIHRoYXQgYXJlIGN1cnJlbnRseSBhdmFpbGFibGU6ICR7cG9vbC5udW1GcmVlKCl9LmBcclxuICApO1xyXG4gIGxvZyhcclxuICAgIDUsXHJcbiAgICBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgcmVzb3VyY2VzIHRoYXQgYXJlIGN1cnJlbnRseSBhY3F1aXJlZDogJHtwb29sLm51bVVzZWQoKX0uYFxyXG4gICk7XHJcbiAgbG9nKFxyXG4gICAgNSxcclxuICAgIGBbcG9vbF0gVGhlIG51bWJlciBvZiBjYWxsZXJzIHdhaXRpbmcgdG8gYWNxdWlyZSBhIHJlc291cmNlOiAke3Bvb2wubnVtUGVuZGluZ0FjcXVpcmVzKCl9LmBcclxuICApO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgaW5pdFBvb2wsXHJcbiAga2lsbFBvb2wsXHJcbiAgcG9zdFdvcmssXHJcbiAgZ2V0UG9vbCxcclxuICBnZXRQb29sSW5mbyxcclxuICBnZXRQb29sSW5mb0pTT04sXHJcbiAgd29ya0F0dGVtcHRzOiAoKSA9PiBleHBvcnRBdHRlbXB0cyxcclxuICBkcm9wcGVkV29yazogKCkgPT4gZHJvcHBlZEV4cG9ydHMsXHJcbiAgYXZlcmFnZVRpbWU6ICgpID0+IHNwZW50QXZlcmFnZSxcclxuICBwcm9jZXNzZWRXb3JrQ291bnQ6ICgpID0+IHBlcmZvcm1lZEV4cG9ydHNcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMsIHdyaXRlRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcblxyXG5pbXBvcnQgeyBnZXRPcHRpb25zLCBpbml0RXhwb3J0U2V0dGluZ3MgfSBmcm9tICcuL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBraWxsUG9vbCwgcG9zdFdvcmsgfSBmcm9tICcuL3Bvb2wuanMnO1xyXG5pbXBvcnQge1xyXG4gIGZpeFR5cGUsXHJcbiAgaGFuZGxlUmVzb3VyY2VzLFxyXG4gIGlzQ29ycmVjdEpTT04sXHJcbiAgb3B0aW9uc1N0cmluZ2lmeSxcclxuICByb3VuZE51bWJlcixcclxuICB0b0Jvb2xlYW4sXHJcbiAgd3JhcEFyb3VuZFxyXG59IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbmxldCBhbGxvd0NvZGVFeGVjdXRpb24gPSBmYWxzZTtcclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgYW4gZXhwb3J0IHByb2Nlc3MuIFRoZSBgc2V0dGluZ3NgIGNvbnRhaW5zIGZpbmFsIG9wdGlvbnMgZ2F0aGVyZWRcclxuICogZnJvbSBhbGwgcG9zc2libGUgc291cmNlcyAoY29uZmlnLCBlbnYsIGNsaSwganNvbikuIFRoZSBgZW5kQ2FsbGJhY2tgIGlzXHJcbiAqIGNhbGxlZCB3aGVuIHRoZSBleHBvcnQgaXMgY29tcGxldGVkLCB3aXRoIGFuIGVycm9yIG9iamVjdCBhcyB0aGUgZmlyc3RcclxuICogYXJndW1lbnQgYW5kIHRoZSBzZWNvbmQgY29udGFpbmluZyB0aGUgYmFzZTY0IHJlc3ByZXNlbnRhdGlvbiBvZiBhIGNoYXJ0LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gc2V0dGluZ3MgLSBUaGUgc2V0dGluZ3Mgb2JqZWN0IGNvbnRhaW5pbmcgZXhwb3J0XHJcbiAqIGNvbmZpZ3VyYXRpb24uXHJcbiAqIEBwYXJhbSB7ZnVuY3Rpb259IGVuZENhbGxiYWNrIC0gVGhlIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGludm9rZWQgdXBvblxyXG4gKiBmaW5hbGl6aW5nIHdvcmsgb3IgdXBvbiBlcnJvciBvY2N1cmFuY2Ugb2YgdGhlIGV4cG9ydGluZyBwcm9jZXNzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7dm9pZH0gVGhpcyBmdW5jdGlvbiBkb2VzIG5vdCByZXR1cm4gYSB2YWx1ZSBkaXJlY3RseTsgaW5zdGVhZCxcclxuICogaXQgY29tbXVuaWNhdGVzIHJlc3VsdHMgdmlhIHRoZSBlbmRDYWxsYmFjay5cclxuICovXHJcbmV4cG9ydCBjb25zdCBzdGFydEV4cG9ydCA9IGFzeW5jIChzZXR0aW5ncywgZW5kQ2FsbGJhY2spID0+IHtcclxuICAvLyBTdGFydGluZyBleHBvcnRpbmcgcHJvY2VzcyBtZXNzYWdlXHJcbiAgbG9nKDQsICdbY2hhcnRdIFN0YXJ0aW5nIHRoZSBleHBvcnRpbmcgcHJvY2Vzcy4nKTtcclxuXHJcbiAgLy8gSW5pdGlhbGl6ZSBvcHRpb25zXHJcbiAgY29uc3Qgb3B0aW9ucyA9IGluaXRFeHBvcnRTZXR0aW5ncyhzZXR0aW5ncywgZ2V0T3B0aW9ucygpKTtcclxuXHJcbiAgLy8gR2V0IHRoZSBleHBvcnQgb3B0aW9uc1xyXG4gIGNvbnN0IGV4cG9ydE9wdGlvbnMgPSBvcHRpb25zLmV4cG9ydDtcclxuXHJcbiAgLy8gSWYgU1ZHIGlzIGFuIGlucHV0IChhcmd1bWVudCBjYW4gYmUgc2VudCBvbmx5IGJ5IHRoZSByZXF1ZXN0KVxyXG4gIGlmIChvcHRpb25zLnBheWxvYWQ/LnN2ZyAmJiBvcHRpb25zLnBheWxvYWQuc3ZnICE9PSAnJykge1xyXG4gICAgdHJ5IHtcclxuICAgICAgbG9nKDQsICdbY2hhcnRdIEF0dGVtcHRpbmcgdG8gZXhwb3J0IGZyb20gYSBTVkcgaW5wdXQuJyk7XHJcbiAgICAgIHJldHVybiBleHBvcnRBc1N0cmluZyhvcHRpb25zLnBheWxvYWQuc3ZnLnRyaW0oKSwgb3B0aW9ucywgZW5kQ2FsbGJhY2spO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKFxyXG4gICAgICAgIG5ldyBFeHBvcnRFcnJvcignW2NoYXJ0XSBFcnJvciBsb2FkaW5nIFNWRyBpbnB1dC4nKS5zZXRFcnJvcihlcnJvcilcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIEV4cG9ydCB1c2luZyBvcHRpb25zIGZyb20gdGhlIGZpbGVcclxuICBpZiAoZXhwb3J0T3B0aW9ucy5pbmZpbGUgJiYgZXhwb3J0T3B0aW9ucy5pbmZpbGUubGVuZ3RoKSB7XHJcbiAgICAvLyBUcnkgdG8gcmVhZCB0aGUgZmlsZSB0byBnZXQgdGhlIHN0cmluZyByZXByZXNlbnRhdGlvblxyXG4gICAgdHJ5IHtcclxuICAgICAgbG9nKDQsICdbY2hhcnRdIEF0dGVtcHRpbmcgdG8gZXhwb3J0IGZyb20gYW4gaW5wdXQgZmlsZS4nKTtcclxuICAgICAgb3B0aW9ucy5leHBvcnQuaW5zdHIgPSByZWFkRmlsZVN5bmMoZXhwb3J0T3B0aW9ucy5pbmZpbGUsICd1dGY4Jyk7XHJcbiAgICAgIHJldHVybiBleHBvcnRBc1N0cmluZyhvcHRpb25zLmV4cG9ydC5pbnN0ci50cmltKCksIG9wdGlvbnMsIGVuZENhbGxiYWNrKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgICAgICBuZXcgRXhwb3J0RXJyb3IoJ1tjaGFydF0gRXJyb3IgbG9hZGluZyBpbnB1dCBmaWxlLicpLnNldEVycm9yKGVycm9yKVxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gRXhwb3J0IHdpdGggb3B0aW9ucyBmcm9tIHRoZSByYXcgcmVwcmVzZW50YXRpb25cclxuICBpZiAoXHJcbiAgICAoZXhwb3J0T3B0aW9ucy5pbnN0ciAmJiBleHBvcnRPcHRpb25zLmluc3RyICE9PSAnJykgfHxcclxuICAgIChleHBvcnRPcHRpb25zLm9wdGlvbnMgJiYgZXhwb3J0T3B0aW9ucy5vcHRpb25zICE9PSAnJylcclxuICApIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGxvZyg0LCAnW2NoYXJ0XSBBdHRlbXB0aW5nIHRvIGV4cG9ydCBmcm9tIGEgcmF3IGlucHV0LicpO1xyXG5cclxuICAgICAgLy8gUGVyZm9ybSBhIGRpcmVjdCBpbmplY3Qgd2hlbiBmb3JjZWRcclxuICAgICAgaWYgKHRvQm9vbGVhbihvcHRpb25zLmN1c3RvbUxvZ2ljPy5hbGxvd0NvZGVFeGVjdXRpb24pKSB7XHJcbiAgICAgICAgcmV0dXJuIGRvU3RyYWlnaHRJbmplY3Qob3B0aW9ucywgZW5kQ2FsbGJhY2spO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBFaXRoZXIgdHJ5IHRvIHBhcnNlIHRvIEpTT04gZmlyc3Qgb3IgZG8gdGhlIGRpcmVjdCBleHBvcnRcclxuICAgICAgcmV0dXJuIHR5cGVvZiBleHBvcnRPcHRpb25zLmluc3RyID09PSAnc3RyaW5nJ1xyXG4gICAgICAgID8gZXhwb3J0QXNTdHJpbmcoZXhwb3J0T3B0aW9ucy5pbnN0ci50cmltKCksIG9wdGlvbnMsIGVuZENhbGxiYWNrKVxyXG4gICAgICAgIDogZG9FeHBvcnQoXHJcbiAgICAgICAgICAgIG9wdGlvbnMsXHJcbiAgICAgICAgICAgIGV4cG9ydE9wdGlvbnMuaW5zdHIgfHwgZXhwb3J0T3B0aW9ucy5vcHRpb25zLFxyXG4gICAgICAgICAgICBlbmRDYWxsYmFja1xyXG4gICAgICAgICAgKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgICAgICBuZXcgRXhwb3J0RXJyb3IoJ1tjaGFydF0gRXJyb3IgbG9hZGluZyByYXcgaW5wdXQuJykuc2V0RXJyb3IoZXJyb3IpXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBObyBpbnB1dCBzcGVjaWZpZWQsIHBhc3MgYW4gZXJyb3IgbWVzc2FnZSB0byB0aGUgY2FsbGJhY2tcclxuICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgIGBbY2hhcnRdIE5vIHZhbGlkIGlucHV0IHNwZWNpZmllZC4gQ2hlY2sgaWYgYXQgbGVhc3Qgb25lIG9mIHRoZSBmb2xsb3dpbmcgcGFyYW1ldGVycyBpcyBjb3JyZWN0bHkgc2V0OiAnaW5maWxlJywgJ2luc3RyJywgJ29wdGlvbnMnLCBvciAnc3ZnJy5gXHJcbiAgICApXHJcbiAgKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgYSBiYXRjaCBleHBvcnQgcHJvY2VzcyBmb3IgbXVsdGlwbGUgY2hhcnRzIGJhc2VkIG9uIHRoZSBpbmZvcm1hdGlvblxyXG4gKiBpbiB0aGUgYmF0Y2ggb3B0aW9uLiBUaGUgYmF0Y2ggaXMgYSBzdHJpbmcgaW4gdGhlIGZvbGxvd2luZyBmb3JtYXQ6XHJcbiAqIFwiaW5maWxlMS5qc29uPW91dGZpbGUxLnBuZztpbmZpbGUyLmpzb249b3V0ZmlsZTIucG5nOy4uLlwiXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IGNvbnRhaW5pbmcgY29uZmlndXJhdGlvbiBmb3JcclxuICogYSBiYXRjaCBleHBvcnQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBiYXRjaCBleHBvcnRcclxuICogcHJvY2VzcyBpcyBjb21wbGV0ZWQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgYW4gZXJyb3Igb2NjdXJzIGR1cmluZ1xyXG4gKiBhbnkgb2YgdGhlIGJhdGNoIGV4cG9ydCBwcm9jZXNzLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGJhdGNoRXhwb3J0ID0gYXN5bmMgKG9wdGlvbnMpID0+IHtcclxuICBjb25zdCBiYXRjaEZ1bmN0aW9ucyA9IFtdO1xyXG5cclxuICAvLyBTcGxpdCBhbmQgcGFpciB0aGUgLS1iYXRjaCBhcmd1bWVudHNcclxuICBmb3IgKGxldCBwYWlyIG9mIG9wdGlvbnMuZXhwb3J0LmJhdGNoLnNwbGl0KCc7JykpIHtcclxuICAgIHBhaXIgPSBwYWlyLnNwbGl0KCc9Jyk7XHJcbiAgICBpZiAocGFpci5sZW5ndGggPT09IDIpIHtcclxuICAgICAgYmF0Y2hGdW5jdGlvbnMucHVzaChcclxuICAgICAgICBzdGFydEV4cG9ydChcclxuICAgICAgICAgIHtcclxuICAgICAgICAgICAgLi4ub3B0aW9ucyxcclxuICAgICAgICAgICAgZXhwb3J0OiB7XHJcbiAgICAgICAgICAgICAgLi4ub3B0aW9ucy5leHBvcnQsXHJcbiAgICAgICAgICAgICAgaW5maWxlOiBwYWlyWzBdLFxyXG4gICAgICAgICAgICAgIG91dGZpbGU6IHBhaXJbMV1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSxcclxuICAgICAgICAgIChlcnJvciwgaW5mbykgPT4ge1xyXG4gICAgICAgICAgICAvLyBUaHJvdyBhbiBlcnJvclxyXG4gICAgICAgICAgICBpZiAoZXJyb3IpIHtcclxuICAgICAgICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgLy8gU2F2ZSB0aGUgYmFzZTY0IGZyb20gYSBidWZmZXIgdG8gYSBjb3JyZWN0IGltYWdlIGZpbGVcclxuICAgICAgICAgICAgd3JpdGVGaWxlU3luYyhcclxuICAgICAgICAgICAgICBpbmZvLm9wdGlvbnMuZXhwb3J0Lm91dGZpbGUsXHJcbiAgICAgICAgICAgICAgQnVmZmVyLmZyb20oaW5mby5yZXN1bHQsICdiYXNlNjQnKVxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIClcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHRyeSB7XHJcbiAgICAvLyBBd2FpdCBhbGwgZXhwb3J0cyBhcmUgZG9uZVxyXG4gICAgYXdhaXQgUHJvbWlzZS5hbGwoYmF0Y2hGdW5jdGlvbnMpO1xyXG5cclxuICAgIC8vIEtpbGwgcG9vbCBhbmQgY2xvc2UgYnJvd3NlciBhZnRlciBmaW5pc2hpbmcgYmF0Y2ggZXhwb3J0XHJcbiAgICBhd2FpdCBraWxsUG9vbCgpO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbY2hhcnRdIEVycm9yIGVuY291bnRlcmVkIGR1cmluZyBiYXRjaCBleHBvcnQuJ1xyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIFN0YXJ0cyBhIHNpbmdsZSBleHBvcnQgcHJvY2VzcyBiYXNlZCBvbiB0aGUgc3BlY2lmaWVkIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IGNvbnRhaW5pbmcgY29uZmlndXJhdGlvbiBmb3JcclxuICogYSBzaW5nbGUgZXhwb3J0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgc2luZ2xlIGV4cG9ydFxyXG4gKiBwcm9jZXNzIGlzIGNvbXBsZXRlZC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiBhbiBlcnJvciBvY2N1cnMgZHVyaW5nXHJcbiAqIHRoZSBzaW5nbGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2luZ2xlRXhwb3J0ID0gYXN5bmMgKG9wdGlvbnMpID0+IHtcclxuICAvLyBVc2UgaW5zdHIgb3IgaXRzIGFsaWFzLCBvcHRpb25zXHJcbiAgb3B0aW9ucy5leHBvcnQuaW5zdHIgPSBvcHRpb25zLmV4cG9ydC5pbnN0ciB8fCBvcHRpb25zLmV4cG9ydC5vcHRpb25zO1xyXG5cclxuICAvLyBQZXJmb3JtIGFuIGV4cG9ydFxyXG4gIGF3YWl0IHN0YXJ0RXhwb3J0KG9wdGlvbnMsIGFzeW5jIChlcnJvciwgaW5mbykgPT4ge1xyXG4gICAgLy8gRXhpdCBwcm9jZXNzIHdoZW4gZXJyb3JcclxuICAgIGlmIChlcnJvcikge1xyXG4gICAgICB0aHJvdyBlcnJvcjtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCB7IG91dGZpbGUsIHR5cGUgfSA9IGluZm8ub3B0aW9ucy5leHBvcnQ7XHJcblxyXG4gICAgLy8gU2F2ZSB0aGUgYmFzZTY0IGZyb20gYSBidWZmZXIgdG8gYSBjb3JyZWN0IGltYWdlIGZpbGVcclxuICAgIHdyaXRlRmlsZVN5bmMoXHJcbiAgICAgIG91dGZpbGUgfHwgYGNoYXJ0LiR7dHlwZX1gLFxyXG4gICAgICB0eXBlICE9PSAnc3ZnJyA/IEJ1ZmZlci5mcm9tKGluZm8ucmVzdWx0LCAnYmFzZTY0JykgOiBpbmZvLnJlc3VsdFxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBLaWxsIHRoZSBwb29sXHJcbiAgICBhd2FpdCBraWxsUG9vbCgpO1xyXG4gIH0pO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIERldGVybWluZXMgdGhlIHNpemUgYW5kIHNjYWxlIGZvciBjaGFydCBleHBvcnQgYmFzZWQgb24gdGhlIHByb3ZpZGVkIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IGNvbnRhaW5pbmcgY29uZmlndXJhdGlvbiBmb3JcclxuICogY2hhcnQgZXhwb3J0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBBbiBvYmplY3QgY29udGFpbmluZyB0aGUgY2FsY3VsYXRlZCBoZWlnaHQsIHdpZHRoLFxyXG4gKiBhbmQgc2NhbGUgZm9yIHRoZSBjaGFydCBleHBvcnQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZmluZENoYXJ0U2l6ZSA9IChvcHRpb25zKSA9PiB7XHJcbiAgY29uc3QgeyBjaGFydCwgZXhwb3J0aW5nIH0gPVxyXG4gICAgb3B0aW9ucy5leHBvcnQ/Lm9wdGlvbnMgfHwgaXNDb3JyZWN0SlNPTihvcHRpb25zLmV4cG9ydD8uaW5zdHIpO1xyXG5cclxuICAvLyBTZWUgaWYgZ2xvYmFsT3B0aW9ucyBob2xkcyBjaGFydCBvciBleHBvcnRpbmcgc2l6ZVxyXG4gIGNvbnN0IGdsb2JhbE9wdGlvbnMgPSBpc0NvcnJlY3RKU09OKG9wdGlvbnMuZXhwb3J0Py5nbG9iYWxPcHRpb25zKTtcclxuXHJcbiAgLy8gU2VjdXJlIHNjYWxlIHZhbHVlXHJcbiAgbGV0IHNjYWxlID1cclxuICAgIG9wdGlvbnMuZXhwb3J0Py5zY2FsZSB8fFxyXG4gICAgZXhwb3J0aW5nPy5zY2FsZSB8fFxyXG4gICAgZ2xvYmFsT3B0aW9ucz8uZXhwb3J0aW5nPy5zY2FsZSB8fFxyXG4gICAgb3B0aW9ucy5leHBvcnQ/LmRlZmF1bHRTY2FsZSB8fFxyXG4gICAgMTtcclxuXHJcbiAgLy8gdGhlIHNjYWxlIGNhbm5vdCBiZSBsb3dlciB0aGFuIDAuMSBhbmQgY2Fubm90IGJlIGhpZ2hlciB0aGFuIDUuMFxyXG4gIHNjYWxlID0gTWF0aC5tYXgoMC4xLCBNYXRoLm1pbihzY2FsZSwgNS4wKSk7XHJcblxyXG4gIC8vIHdlIHdhbnQgdG8gcm91bmQgdGhlIG51bWJlcnMgbGlrZSAwLjIzMjM0IC0+IDAuMjNcclxuICBzY2FsZSA9IHJvdW5kTnVtYmVyKHNjYWxlLCAyKTtcclxuXHJcbiAgLy8gRmluZCBjaGFydCBzaXplIGFuZCBzY2FsZVxyXG4gIGNvbnN0IHNpemUgPSB7XHJcbiAgICBoZWlnaHQ6XHJcbiAgICAgIG9wdGlvbnMuZXhwb3J0Py5oZWlnaHQgfHxcclxuICAgICAgZXhwb3J0aW5nPy5zb3VyY2VIZWlnaHQgfHxcclxuICAgICAgY2hhcnQ/LmhlaWdodCB8fFxyXG4gICAgICBnbG9iYWxPcHRpb25zPy5leHBvcnRpbmc/LnNvdXJjZUhlaWdodCB8fFxyXG4gICAgICBnbG9iYWxPcHRpb25zPy5jaGFydD8uaGVpZ2h0IHx8XHJcbiAgICAgIG9wdGlvbnMuZXhwb3J0Py5kZWZhdWx0SGVpZ2h0IHx8XHJcbiAgICAgIDQwMCxcclxuICAgIHdpZHRoOlxyXG4gICAgICBvcHRpb25zLmV4cG9ydD8ud2lkdGggfHxcclxuICAgICAgZXhwb3J0aW5nPy5zb3VyY2VXaWR0aCB8fFxyXG4gICAgICBjaGFydD8ud2lkdGggfHxcclxuICAgICAgZ2xvYmFsT3B0aW9ucz8uZXhwb3J0aW5nPy5zb3VyY2VXaWR0aCB8fFxyXG4gICAgICBnbG9iYWxPcHRpb25zPy5jaGFydD8ud2lkdGggfHxcclxuICAgICAgb3B0aW9ucy5leHBvcnQ/LmRlZmF1bHRXaWR0aCB8fFxyXG4gICAgICA2MDAsXHJcbiAgICBzY2FsZVxyXG4gIH07XHJcblxyXG4gIC8vIEdldCByaWQgb2YgcG90ZW50aWFsIHB4IGFuZCAlXHJcbiAgZm9yIChsZXQgW3BhcmFtLCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMoc2l6ZSkpIHtcclxuICAgIHNpemVbcGFyYW1dID1cclxuICAgICAgdHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJyA/ICt2YWx1ZS5yZXBsYWNlKC9weHwlL2dpLCAnJykgOiB2YWx1ZTtcclxuICB9XHJcbiAgcmV0dXJuIHNpemU7XHJcbn07XHJcblxyXG4vKipcclxuICogRnVuY3Rpb24gZm9yIGZpbmFsaXppbmcgb3B0aW9ucyBiZWZvcmUgZXhwb3J0LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBvcHRpb25zIG9iamVjdCBjb250YWluaW5nIGNvbmZpZ3VyYXRpb24gZm9yXHJcbiAqIHRoZSBleHBvcnQgcHJvY2Vzcy5cclxuICogQHBhcmFtIHtPYmplY3R9IGNoYXJ0SnNvbiAtIFRoZSBKU09OIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBjaGFydC5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gZW5kQ2FsbGJhY2sgLSBUaGUgY2FsbGJhY2sgZnVuY3Rpb24gdG8gYmUgY2FsbGVkIHVwb25cclxuICogY29tcGxldGlvbiBvciBlcnJvci5cclxuICogQHBhcmFtIHtzdHJpbmd9IHN2ZyAtIFRoZSBTVkcgcmVwcmVzZW50YXRpb24gb2YgdGhlIGNoYXJ0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgZXhwb3J0IHByb2Nlc3NcclxuICogaXMgY29tcGxldGVkLlxyXG4gKi9cclxuY29uc3QgZG9FeHBvcnQgPSBhc3luYyAob3B0aW9ucywgY2hhcnRKc29uLCBlbmRDYWxsYmFjaywgc3ZnKSA9PiB7XHJcbiAgbGV0IHsgZXhwb3J0OiBleHBvcnRPcHRpb25zLCBjdXN0b21Mb2dpYzogY3VzdG9tTG9naWNPcHRpb25zIH0gPSBvcHRpb25zO1xyXG5cclxuICBjb25zdCBhbGxvd0NvZGVFeGVjdXRpb25TY29wZWQgPVxyXG4gICAgdHlwZW9mIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0NvZGVFeGVjdXRpb24gPT09ICdib29sZWFuJ1xyXG4gICAgICA/IGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0NvZGVFeGVjdXRpb25cclxuICAgICAgOiBhbGxvd0NvZGVFeGVjdXRpb247XHJcblxyXG4gIGlmICghY3VzdG9tTG9naWNPcHRpb25zKSB7XHJcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMgPSBvcHRpb25zLmN1c3RvbUxvZ2ljID0ge307XHJcbiAgfSBlbHNlIGlmIChhbGxvd0NvZGVFeGVjdXRpb25TY29wZWQpIHtcclxuICAgIGlmICh0eXBlb2Ygb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXMgPT09ICdzdHJpbmcnKSB7XHJcbiAgICAgIC8vIFByb2Nlc3MgcmVzb3VyY2VzXHJcbiAgICAgIG9wdGlvbnMuY3VzdG9tTG9naWMucmVzb3VyY2VzID0gaGFuZGxlUmVzb3VyY2VzKFxyXG4gICAgICAgIG9wdGlvbnMuY3VzdG9tTG9naWMucmVzb3VyY2VzLFxyXG4gICAgICAgIHRvQm9vbGVhbihvcHRpb25zLmN1c3RvbUxvZ2ljLmFsbG93RmlsZVJlc291cmNlcylcclxuICAgICAgKTtcclxuICAgIH0gZWxzZSBpZiAoIW9wdGlvbnMuY3VzdG9tTG9naWMucmVzb3VyY2VzKSB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgY29uc3QgcmVzb3VyY2VzID0gcmVhZEZpbGVTeW5jKCdyZXNvdXJjZXMuanNvbicsICd1dGY4Jyk7XHJcbiAgICAgICAgb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXMgPSBoYW5kbGVSZXNvdXJjZXMoXHJcbiAgICAgICAgICByZXNvdXJjZXMsXHJcbiAgICAgICAgICB0b0Jvb2xlYW4ob3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0ZpbGVSZXNvdXJjZXMpXHJcbiAgICAgICAgKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgICAyLFxyXG4gICAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgICBgW2NoYXJ0XSBVbmFibGUgdG8gbG9hZCB0aGUgZGVmYXVsdCByZXNvdXJjZXMuanNvbiBmaWxlLmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBJZiB0aGUgYWxsb3dDb2RlRXhlY3V0aW9uIGZsYWcgaXNuJ3Qgc2V0LCB3ZSBzaG91bGQgcmVmdXNlIHRoZSB1c2FnZVxyXG4gIC8vIG9mIGNhbGxiYWNrLCByZXNvdXJjZXMsIGFuZCBjdXN0b20gY29kZS4gQWRkaXRpb25hbGx5LCB0aGUgd29ya2VyIHdpbGxcclxuICAvLyByZWZ1c2UgdG8gcnVuIGFyYml0cmFyeSBKYXZhU2NyaXB0LiBQcmlvcml0aXplZCBzaG91bGQgYmUgdGhlIHNjb3BlZFxyXG4gIC8vIG9wdGlvbiwgdGhlbiB3ZSBzaG91bGQgdGFrZSBhIGxvb2sgYXQgdGhlIG92ZXJhbGwgcG9vbCBvcHRpb24uXHJcbiAgaWYgKCFhbGxvd0NvZGVFeGVjdXRpb25TY29wZWQgJiYgY3VzdG9tTG9naWNPcHRpb25zKSB7XHJcbiAgICBpZiAoXHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayB8fFxyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzIHx8XHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlXHJcbiAgICApIHtcclxuICAgICAgLy8gU2VuZCBiYWNrIGEgZnJpZW5kbHkgbWVzc2FnZSBzYXlpbmcgdGhhdCB0aGUgZXhwb3J0ZXIgZG9lcyBub3Qgc3VwcG9ydFxyXG4gICAgICAvLyB0aGVzZSBzZXR0aW5ncy5cclxuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKFxyXG4gICAgICAgIG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgIGBbY2hhcnRdIFRoZSAnY2FsbGJhY2snLCAncmVzb3VyY2VzJyBhbmQgJ2N1c3RvbUNvZGUnIG9wdGlvbnMgaGF2ZSBiZWVuIGRpc2FibGVkIGZvciB0aGlzIHNlcnZlci5gXHJcbiAgICAgICAgKVxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFJlc2V0IGFsbCBhZGRpdGlvbmFsIGN1c3RvbSBjb2RlXHJcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSBmYWxzZTtcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXMgPSBmYWxzZTtcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlID0gZmFsc2U7XHJcbiAgfVxyXG5cclxuICAvLyBDbGVhbiBwcm9wZXJ0aWVzIHRvIGtlZXAgaXQgbGVhbiBhbmQgbWVhblxyXG4gIGlmIChjaGFydEpzb24pIHtcclxuICAgIGNoYXJ0SnNvbi5jaGFydCA9IGNoYXJ0SnNvbi5jaGFydCB8fCB7fTtcclxuICAgIGNoYXJ0SnNvbi5leHBvcnRpbmcgPSBjaGFydEpzb24uZXhwb3J0aW5nIHx8IHt9O1xyXG4gICAgY2hhcnRKc29uLmV4cG9ydGluZy5lbmFibGVkID0gZmFsc2U7XHJcbiAgfVxyXG5cclxuICBleHBvcnRPcHRpb25zLmNvbnN0ciA9IGV4cG9ydE9wdGlvbnMuY29uc3RyIHx8ICdjaGFydCc7XHJcbiAgZXhwb3J0T3B0aW9ucy50eXBlID0gZml4VHlwZShleHBvcnRPcHRpb25zLnR5cGUsIGV4cG9ydE9wdGlvbnMub3V0ZmlsZSk7XHJcbiAgaWYgKGV4cG9ydE9wdGlvbnMudHlwZSA9PT0gJ3N2ZycpIHtcclxuICAgIGV4cG9ydE9wdGlvbnMud2lkdGggPSBmYWxzZTtcclxuICB9XHJcblxyXG4gIC8vIFByZXBhcmUgZ2xvYmFsIGFuZCB0aGVtZSBvcHRpb25zXHJcbiAgWydnbG9iYWxPcHRpb25zJywgJ3RoZW1lT3B0aW9ucyddLmZvckVhY2goKG9wdGlvbnNOYW1lKSA9PiB7XHJcbiAgICB0cnkge1xyXG4gICAgICBpZiAoZXhwb3J0T3B0aW9ucyAmJiBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSkge1xyXG4gICAgICAgIGlmIChcclxuICAgICAgICAgIHR5cGVvZiBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9PT0gJ3N0cmluZycgJiZcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdLmVuZHNXaXRoKCcuanNvbicpXHJcbiAgICAgICAgKSB7XHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9IGlzQ29ycmVjdEpTT04oXHJcbiAgICAgICAgICAgIHJlYWRGaWxlU3luYyhleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSwgJ3V0ZjgnKSxcclxuICAgICAgICAgICAgdHJ1ZVxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPSBpc0NvcnJlY3RKU09OKFxyXG4gICAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSxcclxuICAgICAgICAgICAgdHJ1ZVxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID0ge307XHJcbiAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgYFtjaGFydF0gVGhlICcke29wdGlvbnNOYW1lfScgY2Fubm90IGJlIGxvYWRlZC5gKTtcclxuICAgIH1cclxuICB9KTtcclxuXHJcbiAgLy8gUHJlcGFyZSB0aGUgY3VzdG9tQ29kZVxyXG4gIGlmIChjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dDb2RlRXhlY3V0aW9uKSB7XHJcbiAgICB0cnkge1xyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSA9IHdyYXBBcm91bmQoXHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUsXHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmFsbG93RmlsZVJlc291cmNlc1xyXG4gICAgICApO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2NoYXJ0XSBUaGUgJ2N1c3RvbUNvZGUnIGNhbm5vdCBiZSBsb2FkZWQuYCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBHZXQgdGhlIGNhbGxiYWNrXHJcbiAgaWYgKFxyXG4gICAgY3VzdG9tTG9naWNPcHRpb25zICYmXHJcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgJiZcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjaz8uaW5kZXhPZigneycpIDwgMFxyXG4gICkge1xyXG4gICAgLy8gVGhlIGFsbG93RmlsZVJlc291cmNlcyBpcyBhbHdheXMgc2V0IHRvIGZhbHNlIGZvciBIVFRQIHJlcXVlc3RzIHRvIGF2b2lkXHJcbiAgICAvLyBpbmplY3RpbmcgYXJiaXRyYXJ5IGZpbGVzIGZyb20gdGhlIGZzXHJcbiAgICBpZiAoY3VzdG9tTG9naWNPcHRpb25zLmFsbG93RmlsZVJlc291cmNlcykge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IHJlYWRGaWxlU3luYyhcclxuICAgICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayxcclxuICAgICAgICAgICd1dGY4J1xyXG4gICAgICAgICk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrID0gZmFsc2U7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2NoYXJ0XSBUaGUgJ2NhbGxiYWNrJyBjYW5ub3QgYmUgbG9hZGVkLmApO1xyXG4gICAgICB9XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSBmYWxzZTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFNpemUgc2VhcmNoXHJcbiAgb3B0aW9ucy5leHBvcnQgPSB7XHJcbiAgICAuLi5vcHRpb25zLmV4cG9ydCxcclxuICAgIC4uLmZpbmRDaGFydFNpemUob3B0aW9ucylcclxuICB9O1xyXG5cclxuICAvLyBQb3N0IHRoZSB3b3JrIHRvIHRoZSBwb29sXHJcbiAgdHJ5IHtcclxuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHBvc3RXb3JrKFxyXG4gICAgICBleHBvcnRPcHRpb25zLnN0ckluaiB8fCBjaGFydEpzb24gfHwgc3ZnLFxyXG4gICAgICBvcHRpb25zXHJcbiAgICApO1xyXG4gICAgcmV0dXJuIGVuZENhbGxiYWNrKGZhbHNlLCByZXN1bHQpO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICByZXR1cm4gZW5kQ2FsbGJhY2soZXJyb3IpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBQZXJmb3JtcyBhIGRpcmVjdCBpbmplY3Qgb2Ygb3B0aW9ucyBiZWZvcmUgZXhwb3J0LiBUaGUgZnVuY3Rpb24gYXR0ZW1wdHNcclxuICogdG8gc3RyaW5naWZ5IHRoZSBwcm92aWRlZCBvcHRpb25zIGFuZCByZW1vdmVzIHVubmVjZXNzYXJ5IGNoYXJhY3RlcnMsXHJcbiAqIGVuc3VyaW5nIGEgY2xlYW4gYW5kIGZvcm1hdHRlZCBpbnB1dC4gVGhlIHJlc3VsdGluZyBzdHJpbmcgaXMgc2F2ZWQgYXNcclxuICogYSBcInN0cmlnaHQgaW5qZWN0XCIgc3RyaW5nIGluIHRoZSBleHBvcnQgb3B0aW9ucy4gSXQgdGhlbiBpbnZva2VzIHRoZVxyXG4gKiBkb0V4cG9ydCBmdW5jdGlvbiB3aXRoIHRoZSB1cGRhdGVkIG9wdGlvbnMuXHJcbiAqXHJcbiAqIElNUE9SVEFOVDogRGFuZ2Vyb3VzIGFuZCBtdXN0IGJlIHVzZWQgZGVsaWJlcmF0ZWx5IGJ5IHNvbWVvbmUgd2hvIHNldHMgdXBcclxuICogYSBzZXJ2ZXIgKHNlZSB0aGUgIC0tYWxsb3dDb2RlRXhlY3V0aW9uIG9wdGlvbikuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIGV4cG9ydCBvcHRpb25zIGNvbnRhaW5pbmcgdGhlIGlucHV0XHJcbiAqIHRvIGJlIGluamVjdGVkLlxyXG4gKiBAcGFyYW0ge2Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIFRoZSBjYWxsYmFjayBmdW5jdGlvbiB0byBiZSBpbnZva2VkXHJcbiAqIGF0IHRoZSBlbmQgb2YgdGhlIHByb2Nlc3MuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlfSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB3aXRoIHRoZSByZXN1bHQgb2YgdGhlIGV4cG9ydFxyXG4gKiBvcGVyYXRpb24gb3IgcmVqZWN0cyB3aXRoIGFuIGVycm9yIGlmIGFueSBpc3N1ZXMgb2NjdXIgZHVyaW5nIHRoZSBwcm9jZXNzLlxyXG4gKi9cclxuY29uc3QgZG9TdHJhaWdodEluamVjdCA9IChvcHRpb25zLCBlbmRDYWxsYmFjaykgPT4ge1xyXG4gIHRyeSB7XHJcbiAgICBsZXQgc3RySW5qO1xyXG4gICAgbGV0IGluc3RyID0gb3B0aW9ucy5leHBvcnQuaW5zdHIgfHwgb3B0aW9ucy5leHBvcnQub3B0aW9ucztcclxuXHJcbiAgICBpZiAodHlwZW9mIGluc3RyICE9PSAnc3RyaW5nJykge1xyXG4gICAgICAvLyBUcnkgdG8gc3RyaW5naWZ5IG9wdGlvbnNcclxuICAgICAgc3RySW5qID0gaW5zdHIgPSBvcHRpb25zU3RyaW5naWZ5KFxyXG4gICAgICAgIGluc3RyLFxyXG4gICAgICAgIG9wdGlvbnMuY3VzdG9tTG9naWM/LmFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gICAgc3RySW5qID0gaW5zdHIucmVwbGFjZUFsbCgvXFx0fFxcbnxcXHIvZywgJycpLnRyaW0oKTtcclxuXHJcbiAgICAvLyBHZXQgcmlkIG9mIHRoZSA7XHJcbiAgICBpZiAoc3RySW5qW3N0ckluai5sZW5ndGggLSAxXSA9PT0gJzsnKSB7XHJcbiAgICAgIHN0ckluaiA9IHN0ckluai5zdWJzdHJpbmcoMCwgc3RySW5qLmxlbmd0aCAtIDEpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFNhdmUgYXMgc3RyaWdodCBpbmplY3Qgc3RyaW5nXHJcbiAgICBvcHRpb25zLmV4cG9ydC5zdHJJbmogPSBzdHJJbmo7XHJcbiAgICByZXR1cm4gZG9FeHBvcnQob3B0aW9ucywgZmFsc2UsIGVuZENhbGxiYWNrKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgcmV0dXJuIGVuZENhbGxiYWNrKFxyXG4gICAgICBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgYFtjaGFydF0gTWFsZm9ybWVkIGlucHV0IGRldGVjdGVkIGZvciAke29wdGlvbnMuZXhwb3J0Py5yZXF1ZXN0SWQgfHwgJz8nfS4gUGxlYXNlIG1ha2Ugc3VyZSB0aGF0IHlvdXIgSlNPTi9KYXZhU2NyaXB0IG9wdGlvbnMgYXJlIHNlbnQgdXNpbmcgdGhlIFwib3B0aW9uc1wiIGF0dHJpYnV0ZSwgYW5kIHRoYXQgaWYgeW91J3JlIHVzaW5nIFNWRywgaXQgaXMgdW5lc2NhcGVkLmBcclxuICAgICAgKS5zZXRFcnJvcihlcnJvcilcclxuICAgICk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEV4cG9ydHMgYSBzdHJpbmcgYmFzZWQgb24gdGhlIHByb3ZpZGVkIG9wdGlvbnMgYW5kIGludm9rZXMgYW4gZW5kIGNhbGxiYWNrLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gc3RyaW5nVG9FeHBvcnQgLSBUaGUgc3RyaW5nIGNvbnRlbnQgdG8gYmUgZXhwb3J0ZWQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gRXhwb3J0IG9wdGlvbnMsIGluY2x1ZGluZyBjdXN0b21Mb2dpYyB3aXRoXHJcbiAqIGFsbG93Q29kZUV4ZWN1dGlvbiBmbGFnLlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIENhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGludm9rZWQgYXQgdGhlIGVuZFxyXG4gKiBvZiB0aGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHthbnl9IFJlc3VsdCBvZiB0aGUgZXhwb3J0IHByb2Nlc3Mgb3IgYW4gZXJyb3IgaWYgZW5jb3VudGVyZWQuXHJcbiAqL1xyXG5jb25zdCBleHBvcnRBc1N0cmluZyA9IChzdHJpbmdUb0V4cG9ydCwgb3B0aW9ucywgZW5kQ2FsbGJhY2spID0+IHtcclxuICBjb25zdCB7IGFsbG93Q29kZUV4ZWN1dGlvbiB9ID0gb3B0aW9ucy5jdXN0b21Mb2dpYztcclxuXHJcbiAgLy8gQ2hlY2sgaWYgaXQgaXMgU1ZHXHJcbiAgaWYgKFxyXG4gICAgc3RyaW5nVG9FeHBvcnQuaW5kZXhPZignPHN2ZycpID49IDAgfHxcclxuICAgIHN0cmluZ1RvRXhwb3J0LmluZGV4T2YoJzw/eG1sJykgPj0gMFxyXG4gICkge1xyXG4gICAgbG9nKDQsICdbY2hhcnRdIFBhcnNpbmcgaW5wdXQgYXMgU1ZHLicpO1xyXG4gICAgcmV0dXJuIGRvRXhwb3J0KG9wdGlvbnMsIGZhbHNlLCBlbmRDYWxsYmFjaywgc3RyaW5nVG9FeHBvcnQpO1xyXG4gIH1cclxuXHJcbiAgdHJ5IHtcclxuICAgIC8vIFRyeSB0byBwYXJzZSB0byBKU09OIGFuZCBjYWxsIHRoZSBkb0V4cG9ydCBmdW5jdGlvblxyXG4gICAgY29uc3QgY2hhcnRKU09OID0gSlNPTi5wYXJzZShzdHJpbmdUb0V4cG9ydC5yZXBsYWNlQWxsKC9cXHR8XFxufFxcci9nLCAnICcpKTtcclxuXHJcbiAgICAvLyBJZiBhIGNvcnJlY3QgSlNPTiwgZG8gdGhlIGV4cG9ydFxyXG4gICAgcmV0dXJuIGRvRXhwb3J0KG9wdGlvbnMsIGNoYXJ0SlNPTiwgZW5kQ2FsbGJhY2spO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAvLyBOb3QgYSB2YWxpZCBKU09OXHJcbiAgICBpZiAodG9Cb29sZWFuKGFsbG93Q29kZUV4ZWN1dGlvbikpIHtcclxuICAgICAgcmV0dXJuIGRvU3RyYWlnaHRJbmplY3Qob3B0aW9ucywgZW5kQ2FsbGJhY2spO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gRG8gbm90IGFsbG93IHN0cmFpZ2h0IGluamVjdGlvbiB3aXRob3V0IHRoZSBhbGxvd0NvZGVFeGVjdXRpb24gZmxhZ1xyXG4gICAgICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICAgICAgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgJ1tjaGFydF0gT25seSBKU09OIGNvbmZpZ3VyYXRpb25zIGFuZCBTVkcgYXJlIGFsbG93ZWQgZm9yIHRoaXMgc2VydmVyLiBJZiB0aGlzIGlzIHlvdXIgc2VydmVyLCBKYXZhU2NyaXB0IGN1c3RvbSBjb2RlIGNhbiBiZSBlbmFibGVkIGJ5IHN0YXJ0aW5nIHRoZSBzZXJ2ZXIgd2l0aCB0aGUgLS1hbGxvd0NvZGVFeGVjdXRpb24gZmxhZy4nXHJcbiAgICAgICAgKS5zZXRFcnJvcihlcnJvcilcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIGFuZCByZXR1cm5zIHRoZSBjdXJyZW50IHN0YXR1cyBvZiBjb2RlIGV4ZWN1dGlvbiBwZXJtaXNzaW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7YW55fSBUaGUgdmFsdWUgb2YgYWxsb3dDb2RlRXhlY3V0aW9uLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldEFsbG93Q29kZUV4ZWN1dGlvbiA9ICgpID0+IGFsbG93Q29kZUV4ZWN1dGlvbjtcclxuXHJcbi8qKlxyXG4gKiBTZXRzIHRoZSBjb2RlIGV4ZWN1dGlvbiBwZXJtaXNzaW9uIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBib29sZWFuIHZhbHVlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge2FueX0gdmFsdWUgLSBUaGUgdmFsdWUgdG8gYmUgY29udmVydGVkIGFuZCBhc3NpZ25lZFxyXG4gKiB0byBhbGxvd0NvZGVFeGVjdXRpb24uXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2V0QWxsb3dDb2RlRXhlY3V0aW9uID0gKHZhbHVlKSA9PiB7XHJcbiAgYWxsb3dDb2RlRXhlY3V0aW9uID0gdG9Cb29sZWFuKHZhbHVlKTtcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBiYXRjaEV4cG9ydCxcclxuICBzaW5nbGVFeHBvcnQsXHJcbiAgZ2V0QWxsb3dDb2RlRXhlY3V0aW9uLFxyXG4gIHNldEFsbG93Q29kZUV4ZWN1dGlvbixcclxuICBzdGFydEV4cG9ydCxcclxuICBmaW5kQ2hhcnRTaXplXHJcbn07XHJcbiIsImltcG9ydCB7IGxvZ1dpdGhTdGFjayB9IGZyb20gJy4uL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IGVudnMgfSBmcm9tICcuLi9lbnZzLmpzJztcclxuXHJcbi8qKlxyXG4gKiBNaWRkbGV3YXJlIGZvciBsb2dnaW5nIGVycm9ycyB3aXRoIHN0YWNrIHRyYWNlIGFuZCBoYW5kbGluZyBlcnJvciByZXNwb25zZS5cclxuICpcclxuICogQHBhcmFtIHtFcnJvcn0gZXJyb3IgLSBUaGUgZXJyb3Igb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxIC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBuZXh0IC0gVGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICovXHJcbmNvbnN0IGxvZ0Vycm9yTWlkZGxld2FyZSA9IChlcnJvciwgcmVxLCByZXMsIG5leHQpID0+IHtcclxuICAvLyBEaXNwbGF5IHRoZSBlcnJvciB3aXRoIHN0YWNrIGluIGEgY29ycmVjdCBmb3JtYXRcclxuICBsb2dXaXRoU3RhY2soMSwgZXJyb3IpO1xyXG5cclxuICAvLyBEZWxldGUgdGhlIHN0YWNrIGZvciB0aGUgZW52aXJvbm1lbnQgb3RoZXIgdGhhbiB0aGUgZGV2ZWxvcG1lbnRcclxuICBpZiAoZW52cy5OT0RFX0VOViAhPT0gJ2RldmVsb3BtZW50Jykge1xyXG4gICAgZGVsZXRlIGVycm9yLnN0YWNrO1xyXG4gIH1cclxuXHJcbiAgLy8gQ2FsbCB0aGUgcmV0dXJuRXJyb3JNaWRkbGV3YXJlXHJcbiAgbmV4dChlcnJvcik7XHJcbn07XHJcblxyXG4vKipcclxuICogTWlkZGxld2FyZSBmb3IgcmV0dXJuaW5nIGVycm9yIHJlc3BvbnNlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0Vycm9yfSBlcnJvciAtIFRoZSBlcnJvciBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXEgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXMgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IG5leHQgLSBUaGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKi9cclxuY29uc3QgcmV0dXJuRXJyb3JNaWRkbGV3YXJlID0gKGVycm9yLCByZXEsIHJlcywgbmV4dCkgPT4ge1xyXG4gIC8vIEdhdGhlciBhbGwgcmVxdWllZCBpbmZvcm1hdGlvbiBmb3IgdGhlIHJlc3BvbnNlXHJcbiAgY29uc3QgeyBzdGF0dXNDb2RlOiBzdENvZGUsIHN0YXR1cywgbWVzc2FnZSwgc3RhY2sgfSA9IGVycm9yO1xyXG4gIGNvbnN0IHN0YXR1c0NvZGUgPSBzdENvZGUgfHwgc3RhdHVzIHx8IDUwMDtcclxuXHJcbiAgLy8gU2V0IGFuZCByZXR1cm4gcmVzcG9uc2VcclxuICByZXMuc3RhdHVzKHN0YXR1c0NvZGUpLmpzb24oeyBzdGF0dXNDb2RlLCBtZXNzYWdlLCBzdGFjayB9KTtcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IChhcHApID0+IHtcclxuICAvLyBBZGQgbG9nIGVycm9yIG1pZGRsZXdhcmVcclxuICBhcHAudXNlKGxvZ0Vycm9yTWlkZGxld2FyZSk7XHJcblxyXG4gIC8vIEFkZCBzZXQgc3RhdHVzIGFuZCByZXR1cm4gZXJyb3IgbWlkZGxld2FyZVxyXG4gIGFwcC51c2UocmV0dXJuRXJyb3JNaWRkbGV3YXJlKTtcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgcmF0ZUxpbWl0IGZyb20gJ2V4cHJlc3MtcmF0ZS1saW1pdCc7XHJcblxyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuLi9sb2dnZXIuanMnO1xyXG5cclxuLyoqXHJcbiAqIE1pZGRsZXdhcmUgZm9yIGVuYWJsaW5nIHJhdGUgbGltaXRpbmcgb24gdGhlIHNwZWNpZmllZCBFeHByZXNzIGFwcC5cclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzfSBhcHAgLSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBsaW1pdENvbmZpZyAtIENvbmZpZ3VyYXRpb24gb3B0aW9ucyBmb3IgcmF0ZSBsaW1pdGluZy5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IChhcHAsIGxpbWl0Q29uZmlnKSA9PiB7XHJcbiAgY29uc3QgbXNnID1cclxuICAgICdUb28gbWFueSByZXF1ZXN0cywgeW91IGhhdmUgYmVlbiByYXRlIGxpbWl0ZWQuIFBsZWFzZSB0cnkgYWdhaW4gbGF0ZXIuJztcclxuXHJcbiAgLy8gT3B0aW9ucyBmb3IgdGhlIHJhdGUgbGltaXRlclxyXG4gIGNvbnN0IHJhdGVPcHRpb25zID0ge1xyXG4gICAgbWF4OiBsaW1pdENvbmZpZy5tYXhSZXF1ZXN0cyB8fCAzMCxcclxuICAgIHdpbmRvdzogbGltaXRDb25maWcud2luZG93IHx8IDEsXHJcbiAgICBkZWxheTogbGltaXRDb25maWcuZGVsYXkgfHwgMCxcclxuICAgIHRydXN0UHJveHk6IGxpbWl0Q29uZmlnLnRydXN0UHJveHkgfHwgZmFsc2UsXHJcbiAgICBza2lwS2V5OiBsaW1pdENvbmZpZy5za2lwS2V5IHx8IGZhbHNlLFxyXG4gICAgc2tpcFRva2VuOiBsaW1pdENvbmZpZy5za2lwVG9rZW4gfHwgZmFsc2VcclxuICB9O1xyXG5cclxuICAvLyBTZXQgaWYgYmVoaW5kIGEgcHJveHlcclxuICBpZiAocmF0ZU9wdGlvbnMudHJ1c3RQcm94eSkge1xyXG4gICAgYXBwLmVuYWJsZSgndHJ1c3QgcHJveHknKTtcclxuICB9XHJcblxyXG4gIC8vIENyZWF0ZSBhIGxpbWl0ZXJcclxuICBjb25zdCBsaW1pdGVyID0gcmF0ZUxpbWl0KHtcclxuICAgIHdpbmRvd01zOiByYXRlT3B0aW9ucy53aW5kb3cgKiA2MCAqIDEwMDAsXHJcbiAgICAvLyBMaW1pdCBlYWNoIElQIHRvIDEwMCByZXF1ZXN0cyBwZXIgd2luZG93TXNcclxuICAgIG1heDogcmF0ZU9wdGlvbnMubWF4LFxyXG4gICAgLy8gRGlzYWJsZSBkZWxheWluZywgZnVsbCBzcGVlZCB1bnRpbCB0aGUgbWF4IGxpbWl0IGlzIHJlYWNoZWRcclxuICAgIGRlbGF5TXM6IHJhdGVPcHRpb25zLmRlbGF5LFxyXG4gICAgaGFuZGxlcjogKHJlcXVlc3QsIHJlc3BvbnNlKSA9PiB7XHJcbiAgICAgIHJlc3BvbnNlLmZvcm1hdCh7XHJcbiAgICAgICAganNvbjogKCkgPT4ge1xyXG4gICAgICAgICAgcmVzcG9uc2Uuc3RhdHVzKDQyOSkuc2VuZCh7IG1lc3NhZ2U6IG1zZyB9KTtcclxuICAgICAgICB9LFxyXG4gICAgICAgIGRlZmF1bHQ6ICgpID0+IHtcclxuICAgICAgICAgIHJlc3BvbnNlLnN0YXR1cyg0MjkpLnNlbmQobXNnKTtcclxuICAgICAgICB9XHJcbiAgICAgIH0pO1xyXG4gICAgfSxcclxuICAgIHNraXA6IChyZXF1ZXN0KSA9PiB7XHJcbiAgICAgIC8vIEFsbG93IGJ5cGFzc2luZyB0aGUgbGltaXRlciBpZiBhIHZhbGlkIGtleS90b2tlbiBoYXMgYmVlbiBzZW50XHJcbiAgICAgIGlmIChcclxuICAgICAgICByYXRlT3B0aW9ucy5za2lwS2V5ICE9PSBmYWxzZSAmJlxyXG4gICAgICAgIHJhdGVPcHRpb25zLnNraXBUb2tlbiAhPT0gZmFsc2UgJiZcclxuICAgICAgICByZXF1ZXN0LnF1ZXJ5LmtleSA9PT0gcmF0ZU9wdGlvbnMuc2tpcEtleSAmJlxyXG4gICAgICAgIHJlcXVlc3QucXVlcnkuYWNjZXNzX3Rva2VuID09PSByYXRlT3B0aW9ucy5za2lwVG9rZW5cclxuICAgICAgKSB7XHJcbiAgICAgICAgbG9nKDQsICdbcmF0ZSBsaW1pdGluZ10gU2tpcHBpbmcgcmF0ZSBsaW1pdGVyLicpO1xyXG4gICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICB9XHJcbiAgICAgIHJldHVybiBmYWxzZTtcclxuICAgIH1cclxuICB9KTtcclxuXHJcbiAgLy8gVXNlIGEgbGltaXRlciBhcyBhIG1pZGRsZXdhcmVcclxuICBhcHAudXNlKGxpbWl0ZXIpO1xyXG5cclxuICBsb2coXHJcbiAgICAzLFxyXG4gICAgYFtyYXRlIGxpbWl0aW5nXSBFbmFibGVkIHJhdGUgbGltaXRpbmcgd2l0aCAke3JhdGVPcHRpb25zLm1heH0gcmVxdWVzdHMgcGVyICR7cmF0ZU9wdGlvbnMud2luZG93fSBtaW51dGUgZm9yIGVhY2ggSVAsIHRydXN0aW5nIHByb3h5OiAke3JhdGVPcHRpb25zLnRydXN0UHJveHl9LmBcclxuICApO1xyXG59O1xyXG4iLCJpbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG5jbGFzcyBIdHRwRXJyb3IgZXh0ZW5kcyBFeHBvcnRFcnJvciB7XHJcbiAgY29uc3RydWN0b3IobWVzc2FnZSwgc3RhdHVzKSB7XHJcbiAgICBzdXBlcihtZXNzYWdlKTtcclxuICAgIHRoaXMuc3RhdHVzID0gdGhpcy5zdGF0dXNDb2RlID0gc3RhdHVzO1xyXG4gIH1cclxuXHJcbiAgc2V0U3RhdHVzKHN0YXR1cykge1xyXG4gICAgdGhpcy5zdGF0dXMgPSBzdGF0dXM7XHJcbiAgICByZXR1cm4gdGhpcztcclxuICB9XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IEh0dHBFcnJvcjtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyB2NCBhcyB1dWlkIH0gZnJvbSAndXVpZCc7XHJcblxyXG5pbXBvcnQgeyBnZXRBbGxvd0NvZGVFeGVjdXRpb24sIHN0YXJ0RXhwb3J0IH0gZnJvbSAnLi4vLi4vY2hhcnQuanMnO1xyXG5pbXBvcnQgeyBnZXRPcHRpb25zLCBtZXJnZUNvbmZpZ09wdGlvbnMgfSBmcm9tICcuLi8uLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuLi8uLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQge1xyXG4gIGZpeFR5cGUsXHJcbiAgaXNDb3JyZWN0SlNPTixcclxuICBpc09iamVjdEVtcHR5LFxyXG4gIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmQsXHJcbiAgb3B0aW9uc1N0cmluZ2lmeSxcclxuICBtZWFzdXJlVGltZVxyXG59IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCBIdHRwRXJyb3IgZnJvbSAnLi4vLi4vZXJyb3JzL0h0dHBFcnJvci5qcyc7XHJcblxyXG4vLyBSZXZlcnNlZCBNSU1FIHR5cGVzXHJcbmNvbnN0IHJldmVyc2VkTWltZSA9IHtcclxuICBwbmc6ICdpbWFnZS9wbmcnLFxyXG4gIGpwZWc6ICdpbWFnZS9qcGVnJyxcclxuICBnaWY6ICdpbWFnZS9naWYnLFxyXG4gIHBkZjogJ2FwcGxpY2F0aW9uL3BkZicsXHJcbiAgc3ZnOiAnaW1hZ2Uvc3ZnK3htbCdcclxufTtcclxuXHJcbi8vIFRoZSByZXF1ZXN0cyBjb3VudGVyXHJcbmxldCByZXF1ZXN0c0NvdW50ZXIgPSAwO1xyXG5cclxuLy8gVGhlIGFycmF5IG9mIGNhbGxiYWNrcyB0byBjYWxsIGJlZm9yZSBhIHJlcXVlc3RcclxuY29uc3QgYmVmb3JlUmVxdWVzdCA9IFtdO1xyXG5cclxuLy8gVGhlIGFycmF5IG9mIGNhbGxiYWNrcyB0byBjYWxsIGFmdGVyIGEgcmVxdWVzdFxyXG5jb25zdCBhZnRlclJlcXVlc3QgPSBbXTtcclxuXHJcbi8qKlxyXG4gKiBJbnZva2VzIGFuIGFycmF5IG9mIGNhbGxiYWNrIGZ1bmN0aW9ucyB3aXRoIHNwZWNpZmllZCBwYXJhbWV0ZXJzLCBhbGxvd2luZ1xyXG4gKiBjdXN0b21pemF0aW9uIG9mIHJlcXVlc3QgaGFuZGxpbmcuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb25bXX0gY2FsbGJhY2tzIC0gQW4gYXJyYXkgb2YgY2FsbGJhY2sgZnVuY3Rpb25zXHJcbiAqIHRvIGJlIGV4ZWN1dGVkLlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxdWVzdCAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlc3BvbnNlIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZGF0YSAtIEFuIG9iamVjdCBjb250YWluaW5nIHBhcmFtZXRlcnMgbGlrZSBpZCwgdW5pcXVlSWQsXHJcbiAqIHR5cGUsIGFuZCBib2R5LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBSZXR1cm5zIGEgYm9vbGVhbiBpbmRpY2F0aW5nIHRoZSBvdmVyYWxsIHJlc3VsdFxyXG4gKiBvZiB0aGUgY2FsbGJhY2sgaW52b2NhdGlvbnMuXHJcbiAqL1xyXG5jb25zdCBkb0NhbGxiYWNrcyA9IChjYWxsYmFja3MsIHJlcXVlc3QsIHJlc3BvbnNlLCBkYXRhKSA9PiB7XHJcbiAgbGV0IHJlc3VsdCA9IHRydWU7XHJcbiAgY29uc3QgeyBpZCwgdW5pcXVlSWQsIHR5cGUsIGJvZHkgfSA9IGRhdGE7XHJcblxyXG4gIGNhbGxiYWNrcy5zb21lKChjYWxsYmFjaykgPT4ge1xyXG4gICAgaWYgKGNhbGxiYWNrKSB7XHJcbiAgICAgIGxldCBjYWxsUmVzcG9uc2UgPSBjYWxsYmFjayhyZXF1ZXN0LCByZXNwb25zZSwgaWQsIHVuaXF1ZUlkLCB0eXBlLCBib2R5KTtcclxuXHJcbiAgICAgIGlmIChjYWxsUmVzcG9uc2UgIT09IHVuZGVmaW5lZCAmJiBjYWxsUmVzcG9uc2UgIT09IHRydWUpIHtcclxuICAgICAgICByZXN1bHQgPSBjYWxsUmVzcG9uc2U7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICByZXR1cm4gcmVzdWx0O1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEhhbmRsZXMgdGhlIGV4cG9ydCByZXF1ZXN0cyBmcm9tIHRoZSBjbGllbnQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXF1ZXN0IC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzcG9uc2UgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IG5leHQgLSBUaGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gLSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBleHBvcnQgcHJvY2Vzc1xyXG4gKiBpcyBjb21wbGV0ZS5cclxuICovXHJcbmNvbnN0IGV4cG9ydEhhbmRsZXIgPSBhc3luYyAocmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpID0+IHtcclxuICB0cnkge1xyXG4gICAgLy8gU3RhcnQgY291bnRpbmcgdGltZVxyXG4gICAgY29uc3Qgc3RvcENvdW50ZXIgPSBtZWFzdXJlVGltZSgpO1xyXG5cclxuICAgIC8vIENyZWF0ZSBhIHVuaXF1ZSBJRCBmb3IgYSByZXF1ZXN0XHJcbiAgICBjb25zdCB1bmlxdWVJZCA9IHV1aWQoKS5yZXBsYWNlKC8tL2csICcnKTtcclxuXHJcbiAgICAvLyBHZXQgdGhlIGN1cnJlbnQgc2VydmVyJ3MgZ2VuZXJhbCBvcHRpb25zXHJcbiAgICBjb25zdCBkZWZhdWx0T3B0aW9ucyA9IGdldE9wdGlvbnMoKTtcclxuXHJcbiAgICBjb25zdCBib2R5ID0gcmVxdWVzdC5ib2R5O1xyXG4gICAgY29uc3QgaWQgPSArK3JlcXVlc3RzQ291bnRlcjtcclxuXHJcbiAgICBsZXQgdHlwZSA9IGZpeFR5cGUoYm9keS50eXBlKTtcclxuXHJcbiAgICAvLyBUaHJvdyAnQmFkIFJlcXVlc3QnIGlmIHRoZXJlJ3Mgbm8gYm9keVxyXG4gICAgaWYgKCFib2R5IHx8IGlzT2JqZWN0RW1wdHkoYm9keSkpIHtcclxuICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAnVGhlIHJlcXVlc3QgYm9keSBpcyByZXF1aXJlZC4gUGxlYXNlIGVuc3VyZSB0aGF0IHlvdXIgQ29udGVudC1UeXBlIGhlYWRlciBpcyBjb3JyZWN0IChhY2NlcHRlZCB0eXBlcyBhcmUgYXBwbGljYXRpb24vanNvbiBhbmQgbXVsdGlwYXJ0L2Zvcm0tZGF0YSkuJyxcclxuICAgICAgICA0MDBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBBbGwgb2YgdGhlIGJlbG93IGNhbiBiZSB1c2VkXHJcbiAgICBsZXQgaW5zdHIgPSBpc0NvcnJlY3RKU09OKGJvZHkuaW5maWxlIHx8IGJvZHkub3B0aW9ucyB8fCBib2R5LmRhdGEpO1xyXG5cclxuICAgIC8vIFRocm93ICdCYWQgUmVxdWVzdCcgaWYgdGhlcmUncyBubyBKU09OIG9yIFNWRyB0byBleHBvcnRcclxuICAgIGlmICghaW5zdHIgJiYgIWJvZHkuc3ZnKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICAyLFxyXG4gICAgICAgIGBUaGUgcmVxdWVzdCB3aXRoIElEICR7dW5pcXVlSWR9IGZyb20gJHtcclxuICAgICAgICAgIHJlcXVlc3QuaGVhZGVyc1sneC1mb3J3YXJkZWQtZm9yJ10gfHwgcmVxdWVzdC5jb25uZWN0aW9uLnJlbW90ZUFkZHJlc3NcclxuICAgICAgICB9IHdhcyBpbmNvcnJlY3QuIFBheWxvYWQgcmVjZWl2ZWQ6ICR7SlNPTi5zdHJpbmdpZnkoYm9keSl9LmBcclxuICAgICAgKTtcclxuXHJcbiAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgXCJObyBjb3JyZWN0IGNoYXJ0IGRhdGEgZm91bmQuIEVuc3VyZSB0aGF0IHlvdSBhcmUgdXNpbmcgZWl0aGVyIGFwcGxpY2F0aW9uL2pzb24gb3IgbXVsdGlwYXJ0L2Zvcm0tZGF0YSBoZWFkZXJzLiBJZiBzZW5kaW5nIEpTT04sIG1ha2Ugc3VyZSB0aGUgY2hhcnQgZGF0YSBpcyBpbiB0aGUgJ2luZmlsZScsICdvcHRpb25zJywgb3IgJ2RhdGEnIGF0dHJpYnV0ZS4gSWYgc2VuZGluZyBTVkcsIGVuc3VyZSBpdCBpcyBpbiB0aGUgJ3N2ZycgYXR0cmlidXRlLlwiLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIGxldCBjYWxsUmVzcG9uc2UgPSBmYWxzZTtcclxuXHJcbiAgICAvLyBDYWxsIHRoZSBiZWZvcmUgcmVxdWVzdCBmdW5jdGlvbnNcclxuICAgIGNhbGxSZXNwb25zZSA9IGRvQ2FsbGJhY2tzKGJlZm9yZVJlcXVlc3QsIHJlcXVlc3QsIHJlc3BvbnNlLCB7XHJcbiAgICAgIGlkLFxyXG4gICAgICB1bmlxdWVJZCxcclxuICAgICAgdHlwZSxcclxuICAgICAgYm9keVxyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gQmxvY2sgdGhlIHJlcXVlc3QgaWYgb25lIG9mIGEgY2FsbGJhY2tzIGZhaWxlZFxyXG4gICAgaWYgKGNhbGxSZXNwb25zZSAhPT0gdHJ1ZSkge1xyXG4gICAgICByZXR1cm4gcmVzcG9uc2Uuc2VuZChjYWxsUmVzcG9uc2UpO1xyXG4gICAgfVxyXG5cclxuICAgIGxldCBjb25uZWN0aW9uQWJvcnRlZCA9IGZhbHNlO1xyXG5cclxuICAgIC8vIEluIGNhc2UgdGhlIGNvbm5lY3Rpb24gaXMgY2xvc2VkLCBmb3JjZSB0byBhYm9ydCBmdXJ0aGVyIGFjdGlvbnNcclxuICAgIHJlcXVlc3Quc29ja2V0Lm9uKCdjbG9zZScsICgpID0+IHtcclxuICAgICAgY29ubmVjdGlvbkFib3J0ZWQgPSB0cnVlO1xyXG4gICAgfSk7XHJcblxyXG4gICAgbG9nKDQsIGBbZXhwb3J0XSBHb3QgYW4gaW5jb21pbmcgSFRUUCByZXF1ZXN0IHdpdGggSUQgJHt1bmlxdWVJZH0uYCk7XHJcblxyXG4gICAgYm9keS5jb25zdHIgPSAodHlwZW9mIGJvZHkuY29uc3RyID09PSAnc3RyaW5nJyAmJiBib2R5LmNvbnN0cikgfHwgJ2NoYXJ0JztcclxuXHJcbiAgICAvLyBHYXRoZXIgYW5kIG9yZ2FuaXplIG9wdGlvbnMgZnJvbSB0aGUgcGF5bG9hZFxyXG4gICAgY29uc3QgcmVxdWVzdE9wdGlvbnMgPSB7XHJcbiAgICAgIGV4cG9ydDoge1xyXG4gICAgICAgIGluc3RyLFxyXG4gICAgICAgIHR5cGUsXHJcbiAgICAgICAgY29uc3RyOiBib2R5LmNvbnN0clswXS50b0xvd2VyQ2FzZSgpICsgYm9keS5jb25zdHIuc3Vic3RyKDEpLFxyXG4gICAgICAgIGhlaWdodDogYm9keS5oZWlnaHQsXHJcbiAgICAgICAgd2lkdGg6IGJvZHkud2lkdGgsXHJcbiAgICAgICAgc2NhbGU6IGJvZHkuc2NhbGUgfHwgZGVmYXVsdE9wdGlvbnMuZXhwb3J0LnNjYWxlLFxyXG4gICAgICAgIGdsb2JhbE9wdGlvbnM6IGlzQ29ycmVjdEpTT04oYm9keS5nbG9iYWxPcHRpb25zLCB0cnVlKSxcclxuICAgICAgICB0aGVtZU9wdGlvbnM6IGlzQ29ycmVjdEpTT04oYm9keS50aGVtZU9wdGlvbnMsIHRydWUpXHJcbiAgICAgIH0sXHJcbiAgICAgIGN1c3RvbUxvZ2ljOiB7XHJcbiAgICAgICAgYWxsb3dDb2RlRXhlY3V0aW9uOiBnZXRBbGxvd0NvZGVFeGVjdXRpb24oKSxcclxuICAgICAgICBhbGxvd0ZpbGVSZXNvdXJjZXM6IGZhbHNlLFxyXG4gICAgICAgIHJlc291cmNlczogaXNDb3JyZWN0SlNPTihib2R5LnJlc291cmNlcywgdHJ1ZSksXHJcbiAgICAgICAgY2FsbGJhY2s6IGJvZHkuY2FsbGJhY2ssXHJcbiAgICAgICAgY3VzdG9tQ29kZTogYm9keS5jdXN0b21Db2RlXHJcbiAgICAgIH1cclxuICAgIH07XHJcblxyXG4gICAgaWYgKGluc3RyKSB7XHJcbiAgICAgIC8vIFN0cmluZ2lmeSBKU09OIHdpdGggb3B0aW9uc1xyXG4gICAgICByZXF1ZXN0T3B0aW9ucy5leHBvcnQuaW5zdHIgPSBvcHRpb25zU3RyaW5naWZ5KFxyXG4gICAgICAgIGluc3RyLFxyXG4gICAgICAgIHJlcXVlc3RPcHRpb25zLmN1c3RvbUxvZ2ljLmFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIE1lcmdlIHRoZSByZXF1ZXN0IG9wdGlvbnMgaW50byBkZWZhdWx0IG9uZXNcclxuICAgIGNvbnN0IG9wdGlvbnMgPSBtZXJnZUNvbmZpZ09wdGlvbnMoZGVmYXVsdE9wdGlvbnMsIHJlcXVlc3RPcHRpb25zKTtcclxuXHJcbiAgICAvLyBTYXZlIHRoZSBKU09OIGlmIGV4aXN0c1xyXG4gICAgb3B0aW9ucy5leHBvcnQub3B0aW9ucyA9IGluc3RyO1xyXG5cclxuICAgIC8vIExhc3RseSwgYWRkIHRoZSBzZXJ2ZXIgc3BlY2lmaWMgYXJndW1lbnRzIGludG8gb3B0aW9ucyBhcyBwYXlsb2FkXHJcbiAgICBvcHRpb25zLnBheWxvYWQgPSB7XHJcbiAgICAgIHN2ZzogYm9keS5zdmcgfHwgZmFsc2UsXHJcbiAgICAgIGI2NDogYm9keS5iNjQgfHwgZmFsc2UsXHJcbiAgICAgIG5vRG93bmxvYWQ6IGJvZHkubm9Eb3dubG9hZCB8fCBmYWxzZSxcclxuICAgICAgcmVxdWVzdElkOiB1bmlxdWVJZFxyXG4gICAgfTtcclxuXHJcbiAgICAvLyBUZXN0IHhsaW5rOmhyZWYgZWxlbWVudHMgZnJvbSBwYXlsb2FkJ3MgU1ZHXHJcbiAgICBpZiAoYm9keS5zdmcgJiYgaXNQcml2YXRlUmFuZ2VVcmxGb3VuZChvcHRpb25zLnBheWxvYWQuc3ZnKSkge1xyXG4gICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgICdTVkcgcG90ZW50aWFsbHkgY29udGFpbiBhdCBsZWFzdCBvbmUgZm9yYmlkZGVuIFVSTCBpbiB4bGluazpocmVmIGVsZW1lbnQuIFBsZWFzZSByZXZpZXcgdGhlIFNWRyBjb250ZW50IGFuZCBlbnN1cmUgdGhhdCBhbGwgcmVmZXJlbmNlZCBVUkxzIGNvbXBseSB3aXRoIHNlY3VyaXR5IHBvbGljaWVzLicsXHJcbiAgICAgICAgNDAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU3RhcnQgdGhlIGV4cG9ydCBwcm9jZXNzXHJcbiAgICBhd2FpdCBzdGFydEV4cG9ydChvcHRpb25zLCAoZXJyb3IsIGluZm8pID0+IHtcclxuICAgICAgLy8gUmVtb3ZlIHRoZSBjbG9zZSBldmVudCBmcm9tIHRoZSBzb2NrZXRcclxuICAgICAgcmVxdWVzdC5zb2NrZXQucmVtb3ZlQWxsTGlzdGVuZXJzKCdjbG9zZScpO1xyXG5cclxuICAgICAgLy8gQWZ0ZXIgdGhlIHdob2xlIGV4cG9ydGluZyBwcm9jZXNzXHJcbiAgICAgIGlmIChkZWZhdWx0T3B0aW9ucy5zZXJ2ZXIuYmVuY2htYXJraW5nKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgNSxcclxuICAgICAgICAgIGBbYmVuY2htYXJrXSBSZXF1ZXN0IHdpdGggSUQgJHt1bmlxdWVJZH0gLSBBZnRlciB0aGUgd2hvbGUgZXhwb3J0aW5nIHByb2Nlc3M6ICR7c3RvcENvdW50ZXIoKX1tcy5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgdGhlIGNvbm5lY3Rpb24gd2FzIGNsb3NlZCwgZG8gbm90aGluZ1xyXG4gICAgICBpZiAoY29ubmVjdGlvbkFib3J0ZWQpIHtcclxuICAgICAgICByZXR1cm4gbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbZXhwb3J0XSBUaGUgY2xpZW50IGNsb3NlZCB0aGUgY29ubmVjdGlvbiBiZWZvcmUgdGhlIGNoYXJ0IGZpbmlzaGVkIHByb2Nlc3NpbmcuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIElmIGVycm9yLCBsb2cgaXQgYW5kIHNlbmQgaXQgdG8gdGhlIGVycm9yIG1pZGRsZXdhcmVcclxuICAgICAgaWYgKGVycm9yKSB7XHJcbiAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIElmIGRhdGEgaXMgbWlzc2luZywgbG9nIHRoZSBtZXNzYWdlIGFuZCBzZW5kIGl0IHRvIHRoZSBlcnJvciBtaWRkbGV3YXJlXHJcbiAgICAgIGlmICghaW5mbyB8fCAhaW5mby5yZXN1bHQpIHtcclxuICAgICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgICAgYFVuZXhwZWN0ZWQgcmV0dXJuIGZyb20gY2hhcnQgZ2VuZXJhdGlvbi4gUGxlYXNlIGNoZWNrIHlvdXIgcmVxdWVzdCBkYXRhLiBGb3IgdGhlIHJlcXVlc3Qgd2l0aCBJRCAke3VuaXF1ZUlkfSwgdGhlIHJlc3VsdCBpcyAke2luZm8ucmVzdWx0fS5gLFxyXG4gICAgICAgICAgNDAwXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gR2V0IHRoZSB0eXBlIGZyb20gb3B0aW9uc1xyXG4gICAgICB0eXBlID0gaW5mby5vcHRpb25zLmV4cG9ydC50eXBlO1xyXG5cclxuICAgICAgLy8gVGhlIGFmdGVyIHJlcXVlc3QgY2FsbGJhY2tzXHJcbiAgICAgIGRvQ2FsbGJhY2tzKGFmdGVyUmVxdWVzdCwgcmVxdWVzdCwgcmVzcG9uc2UsIHsgaWQsIGJvZHk6IGluZm8ucmVzdWx0IH0pO1xyXG5cclxuICAgICAgaWYgKGluZm8ucmVzdWx0KSB7XHJcbiAgICAgICAgLy8gSWYgb25seSBiYXNlNjQgaXMgcmVxdWlyZWQsIHJldHVybiBpdFxyXG4gICAgICAgIGlmIChib2R5LmI2NCkge1xyXG4gICAgICAgICAgLy8gU1ZHIEV4Y2VwdGlvbiBmb3IgdGhlIEhpZ2hjaGFydHMgMTEuMy4wIHZlcnNpb25cclxuICAgICAgICAgIGlmICh0eXBlID09PSAncGRmJyB8fCB0eXBlID09ICdzdmcnKSB7XHJcbiAgICAgICAgICAgIHJldHVybiByZXNwb25zZS5zZW5kKFxyXG4gICAgICAgICAgICAgIEJ1ZmZlci5mcm9tKGluZm8ucmVzdWx0LCAndXRmOCcpLnRvU3RyaW5nKCdiYXNlNjQnKVxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgfVxyXG5cclxuICAgICAgICAgIHJldHVybiByZXNwb25zZS5zZW5kKGluZm8ucmVzdWx0KTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIFNldCBjb3JyZWN0IGNvbnRlbnQgdHlwZVxyXG4gICAgICAgIHJlc3BvbnNlLmhlYWRlcignQ29udGVudC1UeXBlJywgcmV2ZXJzZWRNaW1lW3R5cGVdIHx8ICdpbWFnZS9wbmcnKTtcclxuXHJcbiAgICAgICAgLy8gRGVjaWRlIHdoZXRoZXIgdG8gZG93bmxvYWQgb3Igbm90IGNoYXJ0IGZpbGVcclxuICAgICAgICBpZiAoIWJvZHkubm9Eb3dubG9hZCkge1xyXG4gICAgICAgICAgcmVzcG9uc2UuYXR0YWNobWVudChcclxuICAgICAgICAgICAgYCR7cmVxdWVzdC5wYXJhbXMuZmlsZW5hbWUgfHwgcmVxdWVzdC5ib2R5LmZpbGVuYW1lIHx8ICdjaGFydCd9LiR7XHJcbiAgICAgICAgICAgICAgdHlwZSB8fCAncG5nJ1xyXG4gICAgICAgICAgICB9YFxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIElmIFNWRywgcmV0dXJuIHBsYWluIGNvbnRlbnRcclxuICAgICAgICByZXR1cm4gdHlwZSA9PT0gJ3N2ZydcclxuICAgICAgICAgID8gcmVzcG9uc2Uuc2VuZChpbmZvLnJlc3VsdClcclxuICAgICAgICAgIDogcmVzcG9uc2Uuc2VuZChCdWZmZXIuZnJvbShpbmZvLnJlc3VsdCwgJ2Jhc2U2NCcpKTtcclxuICAgICAgfVxyXG4gICAgfSk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIG5leHQoZXJyb3IpO1xyXG4gIH1cclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IChhcHApID0+IHtcclxuICAvKipcclxuICAgKiBBZGRzIHRoZSBQT1NUIC8gYSByb3V0ZSBmb3IgaGFuZGxpbmcgUE9TVCByZXF1ZXN0cyBhdCB0aGUgcm9vdCBlbmRwb2ludC5cclxuICAgKi9cclxuICBhcHAucG9zdCgnLycsIGV4cG9ydEhhbmRsZXIpO1xyXG5cclxuICAvKipcclxuICAgKiBBZGRzIHRoZSBQT1NUIC86ZmlsZW5hbWUgYSByb3V0ZSBmb3IgaGFuZGxpbmcgUE9TVCByZXF1ZXN0cyB3aXRoXHJcbiAgICogYSBzcGVjaWZpZWQgZmlsZW5hbWUgcGFyYW1ldGVyLlxyXG4gICAqL1xyXG4gIGFwcC5wb3N0KCcvOmZpbGVuYW1lJywgZXhwb3J0SGFuZGxlcik7XHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgeyBqb2luIGFzIHBhdGhlciB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IGNhY2hlIGZyb20gJy4uLy4uL2NhY2hlLmpzJztcclxuaW1wb3J0IHBvb2wgZnJvbSAnLi4vLi4vcG9vbC5qcyc7XHJcbmltcG9ydCB7IF9fZGlybmFtZSB9IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcclxuXHJcbmNvbnN0IHBrZ0ZpbGUgPSBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhwYXRoZXIoX19kaXJuYW1lLCAncGFja2FnZS5qc29uJykpKTtcclxuXHJcbmNvbnN0IHNlcnZlclN0YXJ0VGltZSA9IG5ldyBEYXRlKCk7XHJcblxyXG4vKipcclxuICogQWRkcyB0aGUgR0VUIC9oZWFsdGggcm91dGUsIHdoaWNoIG91dHB1dHMgYmFzaWMgc3RhdHMgZm9yIHRoZSBzZXJ2ZXIuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCAoYXBwKSA9PlxyXG4gICFhcHBcclxuICAgID8gZmFsc2VcclxuICAgIDogYXBwLmdldCgnL2hlYWx0aCcsIChyZXF1ZXN0LCByZXNwb25zZSkgPT4ge1xyXG4gICAgICAgIHJlc3BvbnNlLnNlbmQoe1xyXG4gICAgICAgICAgc3RhdHVzOiAnT0snLFxyXG4gICAgICAgICAgYm9vdFRpbWU6IHNlcnZlclN0YXJ0VGltZSxcclxuICAgICAgICAgIHVwdGltZTpcclxuICAgICAgICAgICAgTWF0aC5mbG9vcihcclxuICAgICAgICAgICAgICAobmV3IERhdGUoKS5nZXRUaW1lKCkgLSBzZXJ2ZXJTdGFydFRpbWUuZ2V0VGltZSgpKSAvIDEwMDAgLyA2MFxyXG4gICAgICAgICAgICApICsgJyBtaW51dGVzJyxcclxuICAgICAgICAgIHZlcnNpb246IHBrZ0ZpbGUudmVyc2lvbixcclxuICAgICAgICAgIGhpZ2hjaGFydHNWZXJzaW9uOiBjYWNoZS52ZXJzaW9uKCksXHJcbiAgICAgICAgICBhdmVyYWdlUHJvY2Vzc2luZ1RpbWU6IHBvb2wuYXZlcmFnZVRpbWUoKSxcclxuICAgICAgICAgIHBlcmZvcm1lZEV4cG9ydHM6IHBvb2wucHJvY2Vzc2VkV29ya0NvdW50KCksXHJcbiAgICAgICAgICBmYWlsZWRFeHBvcnRzOiBwb29sLmRyb3BwZWRXb3JrKCksXHJcbiAgICAgICAgICBleHBvcnRBdHRlbXB0czogcG9vbC53b3JrQXR0ZW1wdHMoKSxcclxuICAgICAgICAgIHN1Y2Vzc1JhdGlvOiAocG9vbC5wcm9jZXNzZWRXb3JrQ291bnQoKSAvIHBvb2wud29ya0F0dGVtcHRzKCkpICogMTAwLFxyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGltcG9ydC9uby1uYW1lZC1hcy1kZWZhdWx0LW1lbWJlclxyXG4gICAgICAgICAgcG9vbDogcG9vbC5nZXRQb29sSW5mb0pTT04oKVxyXG4gICAgICAgIH0pO1xyXG4gICAgICB9KTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyBwcm9taXNlcyBhcyBmc1Byb21pc2VzIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgeyBwb3NpeCB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IGNvcnMgZnJvbSAnY29ycyc7XHJcbmltcG9ydCBleHByZXNzIGZyb20gJ2V4cHJlc3MnO1xyXG5pbXBvcnQgaHR0cCBmcm9tICdodHRwJztcclxuaW1wb3J0IGh0dHBzIGZyb20gJ2h0dHBzJztcclxuaW1wb3J0IG11bHRlciBmcm9tICdtdWx0ZXInO1xyXG5cclxuaW1wb3J0IGVycm9ySGFuZGxlciBmcm9tICcuL2Vycm9yLmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgcmF0ZUxpbWl0IGZyb20gJy4vcmF0ZV9saW1pdC5qcyc7XHJcbmltcG9ydCB7IF9fZGlybmFtZSB9IGZyb20gJy4uL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCB2U3dpdGNoUm91dGUgZnJvbSAnLi9yb3V0ZXMvY2hhbmdlX2hjX3ZlcnNpb24uanMnO1xyXG5pbXBvcnQgZXhwb3J0Um91dGVzIGZyb20gJy4vcm91dGVzL2V4cG9ydC5qcyc7XHJcbmltcG9ydCBoZWFsdGhSb3V0ZSBmcm9tICcuL3JvdXRlcy9oZWFsdGguanMnO1xyXG5pbXBvcnQgdWlSb3V0ZSBmcm9tICcuL3JvdXRlcy91aS5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8vIENyZWF0ZSBleHByZXNzIGFwcFxyXG5jb25zdCBhcHAgPSBleHByZXNzKCk7XHJcblxyXG4vLyBEaXNhYmxlIHRoZSBYLVBvd2VyZWQtQnkgaGVhZGVyXHJcbmFwcC5kaXNhYmxlKCd4LXBvd2VyZWQtYnknKTtcclxuXHJcbi8vIEVuYWJsZSBDT1JTIHN1cHBvcnRcclxuYXBwLnVzZShjb3JzKCkpO1xyXG5cclxuLy8gRW5hYmxlIHBhcnNpbmcgb2YgZm9ybSBkYXRhIChmaWxlcykgd2l0aCBNdWx0ZXIgcGFja2FnZVxyXG5jb25zdCBzdG9yYWdlID0gbXVsdGVyLm1lbW9yeVN0b3JhZ2UoKTtcclxuY29uc3QgdXBsb2FkID0gbXVsdGVyKHtcclxuICBzdG9yYWdlLFxyXG4gIGxpbWl0czoge1xyXG4gICAgZmllbGRTaXplOiA1MCAqIDEwMjQgKiAxMDI0XHJcbiAgfVxyXG59KTtcclxuXHJcbi8vIEVuYWJsZSBib2R5IHBhcnNlclxyXG5hcHAudXNlKGV4cHJlc3MuanNvbih7IGxpbWl0OiA1MCAqIDEwMjQgKiAxMDI0IH0pKTtcclxuYXBwLnVzZShleHByZXNzLnVybGVuY29kZWQoeyBleHRlbmRlZDogdHJ1ZSwgbGltaXQ6IDUwICogMTAyNCAqIDEwMjQgfSkpO1xyXG5cclxuLy8gVXNlIG9ubHkgbm9uLWZpbGUgbXVsdGlwYXJ0IGZvcm0gZmllbGRzXHJcbmFwcC51c2UodXBsb2FkLm5vbmUoKSk7XHJcblxyXG4vKipcclxuICogQXR0YWNoIGVycm9yIGhhbmRsZXJzIHRvIHRoZSBzZXJ2ZXIuXHJcbiAqXHJcbiAqIEBwYXJhbSB7aHR0cC5TZXJ2ZXJ9IHNlcnZlciAtIFRoZSBIVFRQL0hUVFBTIHNlcnZlciBpbnN0YW5jZS5cclxuICovXHJcbmNvbnN0IGF0dGFjaEVycm9ySGFuZGxlcnMgPSAoc2VydmVyKSA9PiB7XHJcbiAgc2VydmVyLm9uKCdjbGllbnRFcnJvcicsIChlcnJvcikgPT4ge1xyXG4gICAgbG9nV2l0aFN0YWNrKDEsIGVycm9yLCBgW3NlcnZlcl0gQ2xpZW50IGVycm9yOiAke2Vycm9yLm1lc3NhZ2V9YCk7XHJcbiAgfSk7XHJcbiAgc2VydmVyLm9uKCdlcnJvcicsIChlcnJvcikgPT4ge1xyXG4gICAgbG9nV2l0aFN0YWNrKDEsIGVycm9yLCBgW3NlcnZlcl0gU2VydmVyIGVycm9yOiAke2Vycm9yLm1lc3NhZ2V9YCk7XHJcbiAgfSk7XHJcbiAgc2VydmVyLm9uKCdjb25uZWN0aW9uJywgKHNvY2tldCkgPT4ge1xyXG4gICAgc29ja2V0Lm9uKCdlcnJvcicsIChlcnJvcikgPT4ge1xyXG4gICAgICBsb2dXaXRoU3RhY2soMSwgZXJyb3IsIGBbc2VydmVyXSBTb2NrZXQgZXJyb3I6ICR7ZXJyb3IubWVzc2FnZX1gKTtcclxuICAgIH0pO1xyXG4gIH0pO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFN0YXJ0cyBhbiBIVFRQIHNlcnZlciBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgY29uZmlndXJhdGlvbi4gVGhlIGBzZXJ2ZXJDb25maWdgXHJcbiAqIG9iamVjdCBjb250YWlucyBhbGwgc2VydmVyIHJlbGF0ZWQgcHJvcGVydGllcyAoc2VlIHRoZSBgc2VydmVyYCBzZWN0aW9uXHJcbiAqIGluIHRoZSBgbGliL3NjaGVtYXMvY29uZmlnLmpzYCBmaWxlIGZvciBhIHJlZmVyZW5jZSkuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBzZXJ2ZXJDb25maWcgLSBUaGUgc2VydmVyIGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gLSBUaHJvd3MgYW4gZXJyb3IgaWYgdGhlIHNlcnZlciBjYW5ub3QgYmUgY29uZmlndXJlZFxyXG4gKiBhbmQgc3RhcnRlZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBzdGFydFNlcnZlciA9IGFzeW5jIChzZXJ2ZXJDb25maWcpID0+IHtcclxuICB0cnkge1xyXG4gICAgLy8gU3RvcCBpZiBub3QgZW5hYmxlZFxyXG4gICAgaWYgKCFzZXJ2ZXJDb25maWcuZW5hYmxlKSB7XHJcbiAgICAgIHJldHVybiBmYWxzZTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBMaXN0ZW4gSFRUUCBzZXJ2ZXJcclxuICAgIGlmICghc2VydmVyQ29uZmlnLnNzbC5mb3JjZSkge1xyXG4gICAgICAvLyBNYWluIHNlcnZlciBpbnN0YW5jZSAoSFRUUClcclxuICAgICAgY29uc3QgaHR0cFNlcnZlciA9IGh0dHAuY3JlYXRlU2VydmVyKGFwcCk7XHJcblxyXG4gICAgICAvLyBBdHRhY2ggZXJyb3IgaGFuZGxlcnMgYW5kIGxpc3RlbiB0byB0aGUgc2VydmVyXHJcbiAgICAgIGF0dGFjaEVycm9ySGFuZGxlcnMoaHR0cFNlcnZlcik7XHJcblxyXG4gICAgICAvLyBMaXN0ZW5cclxuICAgICAgaHR0cFNlcnZlci5saXN0ZW4oc2VydmVyQ29uZmlnLnBvcnQsIHNlcnZlckNvbmZpZy5ob3N0KTtcclxuXHJcbiAgICAgIGxvZyhcclxuICAgICAgICAzLFxyXG4gICAgICAgIGBbc2VydmVyXSBTdGFydGVkIEhUVFAgc2VydmVyIG9uICR7c2VydmVyQ29uZmlnLmhvc3R9OiR7c2VydmVyQ29uZmlnLnBvcnR9LmBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBMaXN0ZW4gSFRUUFMgc2VydmVyXHJcbiAgICBpZiAoc2VydmVyQ29uZmlnLnNzbC5lbmFibGUpIHtcclxuICAgICAgLy8gU2V0IHVwIGFuIFNTTCBzZXJ2ZXIgYWxzb1xyXG4gICAgICBsZXQga2V5LCBjZXJ0O1xyXG5cclxuICAgICAgdHJ5IHtcclxuICAgICAgICAvLyBHZXQgdGhlIFNTTCBrZXlcclxuICAgICAgICBrZXkgPSBhd2FpdCBmc1Byb21pc2VzLnJlYWRGaWxlKFxyXG4gICAgICAgICAgcG9zaXguam9pbihzZXJ2ZXJDb25maWcuc3NsLmNlcnRQYXRoLCAnc2VydmVyLmtleScpLFxyXG4gICAgICAgICAgJ3V0ZjgnXHJcbiAgICAgICAgKTtcclxuXHJcbiAgICAgICAgLy8gR2V0IHRoZSBTU0wgY2VydGlmaWNhdGVcclxuICAgICAgICBjZXJ0ID0gYXdhaXQgZnNQcm9taXNlcy5yZWFkRmlsZShcclxuICAgICAgICAgIHBvc2l4LmpvaW4oc2VydmVyQ29uZmlnLnNzbC5jZXJ0UGF0aCwgJ3NlcnZlci5jcnQnKSxcclxuICAgICAgICAgICd1dGY4J1xyXG4gICAgICAgICk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMixcclxuICAgICAgICAgIGBbc2VydmVyXSBVbmFibGUgdG8gbG9hZCBrZXkvY2VydGlmaWNhdGUgZnJvbSB0aGUgJyR7c2VydmVyQ29uZmlnLnNzbC5jZXJ0UGF0aH0nIHBhdGguIENvdWxkIG5vdCBydW4gc2VjdXJlZCBsYXllciBzZXJ2ZXIuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmIChrZXkgJiYgY2VydCkge1xyXG4gICAgICAgIC8vIE1haW4gc2VydmVyIGluc3RhbmNlIChIVFRQUylcclxuICAgICAgICBjb25zdCBodHRwc1NlcnZlciA9IGh0dHBzLmNyZWF0ZVNlcnZlcih7IGtleSwgY2VydCB9LCBhcHApO1xyXG5cclxuICAgICAgICAvLyBBdHRhY2ggZXJyb3IgaGFuZGxlcnMgYW5kIGxpc3RlbiB0byB0aGUgc2VydmVyXHJcbiAgICAgICAgYXR0YWNoRXJyb3JIYW5kbGVycyhodHRwc1NlcnZlcik7XHJcblxyXG4gICAgICAgIC8vIExpc3RlblxyXG4gICAgICAgIGh0dHBzU2VydmVyLmxpc3RlbihzZXJ2ZXJDb25maWcuc3NsLnBvcnQsIHNlcnZlckNvbmZpZy5ob3N0KTtcclxuXHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbc2VydmVyXSBTdGFydGVkIEhUVFBTIHNlcnZlciBvbiAke3NlcnZlckNvbmZpZy5ob3N0fToke3NlcnZlckNvbmZpZy5zc2wucG9ydH0uYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBFbmFibGUgdGhlIHJhdGUgbGltaXRlciBpZiBjb25maWcgc2F5cyBzb1xyXG4gICAgaWYgKFxyXG4gICAgICBzZXJ2ZXJDb25maWcucmF0ZUxpbWl0aW5nICYmXHJcbiAgICAgIHNlcnZlckNvbmZpZy5yYXRlTGltaXRpbmcuZW5hYmxlICYmXHJcbiAgICAgICFbMCwgTmFOXS5pbmNsdWRlcyhzZXJ2ZXJDb25maWcucmF0ZUxpbWl0aW5nLm1heFJlcXVlc3RzKVxyXG4gICAgKSB7XHJcbiAgICAgIHJhdGVMaW1pdChhcHAsIHNlcnZlckNvbmZpZy5yYXRlTGltaXRpbmcpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFNldCB1cCBzdGF0aWMgZm9sZGVyJ3Mgcm91dGVcclxuICAgIGFwcC51c2UoZXhwcmVzcy5zdGF0aWMocG9zaXguam9pbihfX2Rpcm5hbWUsICdwdWJsaWMnKSkpO1xyXG5cclxuICAgIC8vIFNldCB1cCByb3V0ZXNcclxuICAgIGhlYWx0aFJvdXRlKGFwcCk7XHJcbiAgICBleHBvcnRSb3V0ZXMoYXBwKTtcclxuICAgIHVpUm91dGUoYXBwKTtcclxuICAgIHZTd2l0Y2hSb3V0ZShhcHApO1xyXG5cclxuICAgIC8vIFNldCB1cCBjZW50cmFsaXplZCBlcnJvciBoYW5kbGVyXHJcbiAgICBlcnJvckhhbmRsZXIoYXBwKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW3NlcnZlcl0gQ291bGQgbm90IGNvbmZpZ3VyZSBhbmQgc3RhcnQgdGhlIHNlcnZlci4nXHJcbiAgICApLnNldEVycm9yKGVycm9yKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogRW5hYmxlIHJhdGUgbGltaXRpbmcgZm9yIHRoZSBzZXJ2ZXIuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBsaW1pdENvbmZpZyAtIENvbmZpZ3VyYXRpb24gb2JqZWN0IGZvciByYXRlIGxpbWl0aW5nLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGVuYWJsZVJhdGVMaW1pdGluZyA9IChsaW1pdENvbmZpZykgPT4gcmF0ZUxpbWl0KGFwcCwgbGltaXRDb25maWcpO1xyXG5cclxuLyoqXHJcbiAqIEdldCB0aGUgRXhwcmVzcyBpbnN0YW5jZS5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gLSBUaGUgRXhwcmVzcyBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBnZXRFeHByZXNzID0gKCkgPT4gZXhwcmVzcztcclxuXHJcbi8qKlxyXG4gKiBHZXQgdGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSAtIFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBnZXRBcHAgPSAoKSA9PiBhcHA7XHJcblxyXG4vKipcclxuICogQXBwbHkgbWlkZGxld2FyZShzKSB0byBhIHNwZWNpZmljIHBhdGguXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIC0gVGhlIHBhdGggdG8gd2hpY2ggdGhlIG1pZGRsZXdhcmUocykgc2hvdWxkIGJlIGFwcGxpZWQuXHJcbiAqIEBwYXJhbSB7Li4uRnVuY3Rpb259IG1pZGRsZXdhcmVzIC0gVGhlIG1pZGRsZXdhcmUgZnVuY3Rpb25zIHRvIGJlIGFwcGxpZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgdXNlID0gKHBhdGgsIC4uLm1pZGRsZXdhcmVzKSA9PiB7XHJcbiAgYXBwLnVzZShwYXRoLCAuLi5taWRkbGV3YXJlcyk7XHJcbn07XHJcblxyXG4vKipcclxuICogU2V0IHVwIGEgcm91dGUgd2l0aCBHRVQgbWV0aG9kIGFuZCBhcHBseSBtaWRkbGV3YXJlKHMpLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcGF0aCAtIFRoZSByb3V0ZSBwYXRoLlxyXG4gKiBAcGFyYW0gey4uLkZ1bmN0aW9ufSBtaWRkbGV3YXJlcyAtIFRoZSBtaWRkbGV3YXJlIGZ1bmN0aW9ucyB0byBiZSBhcHBsaWVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldCA9IChwYXRoLCAuLi5taWRkbGV3YXJlcykgPT4ge1xyXG4gIGFwcC5nZXQocGF0aCwgLi4ubWlkZGxld2FyZXMpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFNldCB1cCBhIHJvdXRlIHdpdGggUE9TVCBtZXRob2QgYW5kIGFwcGx5IG1pZGRsZXdhcmUocykuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIC0gVGhlIHJvdXRlIHBhdGguXHJcbiAqIEBwYXJhbSB7Li4uRnVuY3Rpb259IG1pZGRsZXdhcmVzIC0gVGhlIG1pZGRsZXdhcmUgZnVuY3Rpb25zIHRvIGJlIGFwcGxpZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgcG9zdCA9IChwYXRoLCAuLi5taWRkbGV3YXJlcykgPT4ge1xyXG4gIGFwcC5wb3N0KHBhdGgsIC4uLm1pZGRsZXdhcmVzKTtcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBzdGFydFNlcnZlcixcclxuICBlbmFibGVSYXRlTGltaXRpbmcsXHJcbiAgZ2V0RXhwcmVzcyxcclxuICBnZXRBcHAsXHJcbiAgdXNlLFxyXG4gIGdldCxcclxuICBwb3N0XHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IHsgX19kaXJuYW1lIH0gZnJvbSAnLi4vLi4vdXRpbHMuanMnO1xyXG5cclxuLyoqXHJcbiAqIEFkZHMgdGhlIEdFVCAvIHJvdXRlIGZvciBhIFVJIHdoZW4gZW5hYmxlZCBvbiB0aGUgZXhwb3J0IHNlcnZlci5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IChhcHApID0+XHJcbiAgIWFwcFxyXG4gICAgPyBmYWxzZVxyXG4gICAgOiBhcHAuZ2V0KCcvJywgKHJlcXVlc3QsIHJlc3BvbnNlKSA9PiB7XHJcbiAgICAgICAgcmVzcG9uc2Uuc2VuZEZpbGUoam9pbihfX2Rpcm5hbWUsICdwdWJsaWMnLCAnaW5kZXguaHRtbCcpKTtcclxuICAgICAgfSk7XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IGNhY2hlIGZyb20gJy4uLy4uL2NhY2hlLmpzJztcclxuaW1wb3J0IEh0dHBFcnJvciBmcm9tICcuLi8uLi9lcnJvcnMvSHR0cEVycm9yLmpzJztcclxuaW1wb3J0IHsgZW52cyB9IGZyb20gJy4uLy4uL2VudnMuanMnO1xyXG5cclxuLyoqXHJcbiAqIEFkZHMgdGhlIFBPU1QgL2NoYW5nZV9oY192ZXJzaW9uLzpuZXdWZXJzaW9uIHJvdXRlIHRoYXQgY2FuIGJlIHV0aWxpemVkIHRvIG1vZGlmeVxyXG4gKiB0aGUgSGlnaGNoYXJ0cyB2ZXJzaW9uIG9uIHRoZSBzZXJ2ZXIuXHJcbiAqXHJcbiAqIFRPRE86IEFkZCBhdXRoIHRva2VuIGFuZCBjb25uZWN0IHRvIEFQSVxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgKGFwcCkgPT5cclxuICAhYXBwXHJcbiAgICA/IGZhbHNlXHJcbiAgICA6IGFwcC5wb3N0KFxyXG4gICAgICAgICcvdmVyc2lvbi9jaGFuZ2UvOm5ld1ZlcnNpb24nLFxyXG4gICAgICAgIGFzeW5jIChyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkgPT4ge1xyXG4gICAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgY29uc3QgYWRtaW5Ub2tlbiA9IGVudnMuSElHSENIQVJUU19BRE1JTl9UT0tFTjtcclxuXHJcbiAgICAgICAgICAgIC8vIENoZWNrIHRoZSBleGlzdGVuY2Ugb2YgdGhlIHRva2VuXHJcbiAgICAgICAgICAgIGlmICghYWRtaW5Ub2tlbiB8fCAhYWRtaW5Ub2tlbi5sZW5ndGgpIHtcclxuICAgICAgICAgICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgICAgICAgICAgJ1RoZSBzZXJ2ZXIgaXMgbm90IGNvbmZpZ3VyZWQgdG8gcGVyZm9ybSBydW4tdGltZSB2ZXJzaW9uIGNoYW5nZXM6IEhJR0hDSEFSVFNfQURNSU5fVE9LRU4gaXMgbm90IHNldC4nLFxyXG4gICAgICAgICAgICAgICAgNDAxXHJcbiAgICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgLy8gQ2hlY2sgaWYgdGhlIGhjLWF1dGggaGVhZGVyIGNvbnRhaW4gYSBjb3JyZWN0IHRva2VuXHJcbiAgICAgICAgICAgIGNvbnN0IHRva2VuID0gcmVxdWVzdC5nZXQoJ2hjLWF1dGgnKTtcclxuICAgICAgICAgICAgaWYgKCF0b2tlbiB8fCB0b2tlbiAhPT0gYWRtaW5Ub2tlbikge1xyXG4gICAgICAgICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgICAgICAgICAnSW52YWxpZCBvciBtaXNzaW5nIHRva2VuOiBTZXQgdGhlIHRva2VuIGluIHRoZSBoYy1hdXRoIGhlYWRlci4nLFxyXG4gICAgICAgICAgICAgICAgNDAxXHJcbiAgICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgLy8gQ29tcGFyZSB2ZXJzaW9uc1xyXG4gICAgICAgICAgICBjb25zdCBuZXdWZXJzaW9uID0gcmVxdWVzdC5wYXJhbXMubmV3VmVyc2lvbjtcclxuICAgICAgICAgICAgaWYgKG5ld1ZlcnNpb24pIHtcclxuICAgICAgICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGltcG9ydC9uby1uYW1lZC1hcy1kZWZhdWx0LW1lbWJlclxyXG4gICAgICAgICAgICAgICAgYXdhaXQgY2FjaGUudXBkYXRlVmVyc2lvbihuZXdWZXJzaW9uKTtcclxuICAgICAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAgICAgICAgICAgYFZlcnNpb24gY2hhbmdlOiAke2Vycm9yLm1lc3NhZ2V9YCxcclxuICAgICAgICAgICAgICAgICAgZXJyb3Iuc3RhdHVzQ29kZVxyXG4gICAgICAgICAgICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAvLyBTdWNjZXNzXHJcbiAgICAgICAgICAgICAgcmVzcG9uc2Uuc3RhdHVzKDIwMCkuc2VuZCh7XHJcbiAgICAgICAgICAgICAgICBzdGF0dXNDb2RlOiAyMDAsXHJcbiAgICAgICAgICAgICAgICB2ZXJzaW9uOiBjYWNoZS52ZXJzaW9uKCksXHJcbiAgICAgICAgICAgICAgICBtZXNzYWdlOiBgU3VjY2Vzc2Z1bGx5IHVwZGF0ZWQgSGlnaGNoYXJ0cyB0byB2ZXJzaW9uOiAke25ld1ZlcnNpb259LmBcclxuICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAvLyBObyB2ZXJzaW9uIHNwZWNpZmllZFxyXG4gICAgICAgICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoJ05vIG5ldyB2ZXJzaW9uIHN1cHBsaWVkLicsIDQwMCk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICAgIG5leHQoZXJyb3IpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgKTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgJ2NvbG9ycyc7XHJcbmltcG9ydCBkb3RlbnYgZnJvbSAnZG90ZW52JztcclxuXHJcbmltcG9ydCB7IGNoZWNrQW5kVXBkYXRlQ2FjaGUgfSBmcm9tICcuL2NhY2hlLmpzJztcclxuaW1wb3J0IHtcclxuICBiYXRjaEV4cG9ydCxcclxuICBzZXRBbGxvd0NvZGVFeGVjdXRpb24sXHJcbiAgc2luZ2xlRXhwb3J0LFxyXG4gIHN0YXJ0RXhwb3J0XHJcbn0gZnJvbSAnLi9jaGFydC5qcyc7XHJcbmltcG9ydCB7IG1hcFRvTmV3Q29uZmlnLCBtYW51YWxDb25maWcsIHNldE9wdGlvbnMgfSBmcm9tICcuL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7XHJcbiAgaW5pdExvZ2dpbmcsXHJcbiAgbG9nLFxyXG4gIGxvZ1dpdGhTdGFjayxcclxuICBzZXRMb2dMZXZlbCxcclxuICBlbmFibGVGaWxlTG9nZ2luZ1xyXG59IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgaW5pdFBvb2wsIGtpbGxQb29sIH0gZnJvbSAnLi9wb29sLmpzJztcclxuaW1wb3J0IHNlcnZlciwgeyBzdGFydFNlcnZlciB9IGZyb20gJy4vc2VydmVyL3NlcnZlci5qcyc7XHJcbmltcG9ydCB7IHByaW50TG9nbywgcHJpbnRVc2FnZSB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxuLy8gTG9hZCAuZW52IGludG8gZW52aXJvbm1lbnQgdmFyaWFibGVzXHJcbmRvdGVudi5jb25maWcoKTtcclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyB0aGUgZXhwb3J0IHByb2Nlc3MuIFRhc2tzIHN1Y2ggYXMgY29uZmlndXJpbmcgbG9nZ2luZywgY2hlY2tpbmdcclxuICogY2FjaGUgYW5kIHNvdXJjZXMsIGFuZCBpbml0aWFsaXppbmcgdGhlIHBvb2wgb2YgcmVzb3VyY2VzIGhhcHBlbiBkdXJpbmdcclxuICogdGhpcyBzdGFnZS4gRnVuY3Rpb24gdGhhdCBpcyByZXF1aXJlZCB0byBiZSBjYWxsZWQgYmVmb3JlIHRyeWluZyB0byBleHBvcnQgY2hhcnRzIG9yIHNldHRpbmcgYSBzZXJ2ZXIuIFRoZSBgb3B0aW9uc2AgaXMgYW4gb2JqZWN0IHRoYXQgY29udGFpbnMgYWxsIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gQWxsIGV4cG9ydCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgdXBkYXRlZCBleHBvcnQgb3B0aW9ucy5cclxuICovXHJcbmNvbnN0IGluaXRFeHBvcnQgPSBhc3luYyAob3B0aW9ucykgPT4ge1xyXG4gIC8vIFNldCB0aGUgYWxsb3dDb2RlRXhlY3V0aW9uIHBlciBleHBvcnQgbW9kdWxlIHNjb3BlXHJcbiAgc2V0QWxsb3dDb2RlRXhlY3V0aW9uKFxyXG4gICAgb3B0aW9ucy5jdXN0b21Mb2dpYyAmJiBvcHRpb25zLmN1c3RvbUxvZ2ljLmFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICk7XHJcblxyXG4gIC8vIEluaXQgdGhlIGxvZ2dpbmdcclxuICBpbml0TG9nZ2luZyhvcHRpb25zLmxvZ2dpbmcpO1xyXG5cclxuICAvLyBDaGVjayBpZiBjYWNoZSBuZWVkcyB0byBiZSB1cGRhdGVkXHJcbiAgYXdhaXQgY2hlY2tBbmRVcGRhdGVDYWNoZShvcHRpb25zLmhpZ2hjaGFydHMgfHwgeyB2ZXJzaW9uOiAnbGF0ZXN0JyB9KTtcclxuXHJcbiAgLy8gSW5pdCB0aGUgcG9vbFxyXG4gIGF3YWl0IGluaXRQb29sKHtcclxuICAgIHBvb2w6IG9wdGlvbnMucG9vbCB8fCB7XHJcbiAgICAgIG1pbldvcmtlcnM6IDEsXHJcbiAgICAgIG1heFdvcmtlcnM6IDFcclxuICAgIH0sXHJcbiAgICBwdXBwZXRlZXJBcmdzOiBvcHRpb25zLnB1cHBldGVlcj8uYXJncyB8fCBbXVxyXG4gIH0pO1xyXG5cclxuICAvLyBSZXR1cm4gdXBkYXRlZCBvcHRpb25zXHJcbiAgcmV0dXJuIG9wdGlvbnM7XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgLy8gU2VydmVyXHJcbiAgc2VydmVyLFxyXG4gIHN0YXJ0U2VydmVyLFxyXG4gIHNldE9wdGlvbnMsXHJcblxyXG4gIC8vIEV4cG9ydGluZ1xyXG4gIGluaXRFeHBvcnQsXHJcbiAgc2luZ2xlRXhwb3J0LFxyXG4gIGJhdGNoRXhwb3J0LFxyXG4gIHN0YXJ0RXhwb3J0LFxyXG4gIGtpbGxQb29sLFxyXG5cclxuICAvLyBMb2dzXHJcbiAgbG9nLFxyXG4gIGxvZ1dpdGhTdGFjayxcclxuICBzZXRMb2dMZXZlbCxcclxuICBlbmFibGVGaWxlTG9nZ2luZyxcclxuXHJcbiAgLy8gVXRpbHNcclxuICBtYXBUb05ld0NvbmZpZyxcclxuICBtYW51YWxDb25maWcsXHJcbiAgcHJpbnRMb2dvLFxyXG4gIHByaW50VXNhZ2VcclxufTtcclxuIl0sIm5hbWVzIjpbImFzeW5jIiwiZmV0Y2giLCJ1cmwiLCJyZXF1ZXN0T3B0aW9ucyIsIlByb21pc2UiLCJyZXNvbHZlIiwicmVqZWN0IiwicHJvdG9jb2wiLCJzdGFydHNXaXRoIiwiaHR0cHMiLCJodHRwIiwiZ2V0UHJvdG9jb2wiLCJnZXQiLCJyZXMiLCJkYXRhIiwib24iLCJjaHVuayIsInRleHQiLCJlcnJvciIsImRlZmF1bHRDb25maWciLCJwdXBwZXRlZXIiLCJhcmdzIiwidmFsdWUiLCJ0eXBlIiwiZGVzY3JpcHRpb24iLCJoaWdoY2hhcnRzIiwidmVyc2lvbiIsImVudkxpbmsiLCJjZG5VUkwiLCJjb3JlU2NyaXB0cyIsIm1vZHVsZXMiLCJpbmRpY2F0b3JzIiwic2NyaXB0cyIsImZvcmNlRmV0Y2giLCJjYWNoZVBhdGgiLCJleHBvcnQiLCJpbmZpbGUiLCJpbnN0ciIsIm9wdGlvbnMiLCJvdXRmaWxlIiwiY29uc3RyIiwiZGVmYXVsdEhlaWdodCIsImRlZmF1bHRXaWR0aCIsImRlZmF1bHRTY2FsZSIsImhlaWdodCIsIndpZHRoIiwic2NhbGUiLCJnbG9iYWxPcHRpb25zIiwidGhlbWVPcHRpb25zIiwiYmF0Y2giLCJyYXN0ZXJpemF0aW9uVGltZW91dCIsImN1c3RvbUxvZ2ljIiwiYWxsb3dDb2RlRXhlY3V0aW9uIiwiYWxsb3dGaWxlUmVzb3VyY2VzIiwiY3VzdG9tQ29kZSIsImNhbGxiYWNrIiwicmVzb3VyY2VzIiwibG9hZENvbmZpZyIsImxlZ2FjeU5hbWUiLCJjcmVhdGVDb25maWciLCJzZXJ2ZXIiLCJlbmFibGUiLCJjbGlOYW1lIiwiaG9zdCIsInBvcnQiLCJiZW5jaG1hcmtpbmciLCJzc2wiLCJmb3JjZSIsImNlcnRQYXRoIiwicmF0ZUxpbWl0aW5nIiwibWF4UmVxdWVzdHMiLCJ3aW5kb3ciLCJkZWxheSIsInRydXN0UHJveHkiLCJza2lwS2V5Iiwic2tpcFRva2VuIiwicG9vbCIsIm1pbldvcmtlcnMiLCJtYXhXb3JrZXJzIiwid29ya0xpbWl0IiwiYWNxdWlyZVRpbWVvdXQiLCJjcmVhdGVUaW1lb3V0IiwiZGVzdHJveVRpbWVvdXQiLCJpZGxlVGltZW91dCIsImNyZWF0ZVJldHJ5SW50ZXJ2YWwiLCJyZWFwZXJJbnRlcnZhbCIsImxpc3RlblRvUHJvY2Vzc0V4aXRzIiwibG9nZ2luZyIsImxldmVsIiwiZmlsZSIsImRlc3QiLCJ1aSIsInJvdXRlIiwib3RoZXIiLCJub0xvZ28iLCJwcm9tcHRzQ29uZmlnIiwibmFtZSIsIm1lc3NhZ2UiLCJpbml0aWFsIiwiam9pbiIsInNlcGFyYXRvciIsImluc3RydWN0aW9ucyIsImNob2ljZXMiLCJoaW50IiwibWluIiwibWF4Iiwicm91bmQiLCJhYnNvbHV0ZVByb3BzIiwibmVzdGVkQXJncyIsImNyZWF0ZU5lc3RlZEFyZ3MiLCJvYmoiLCJwcm9wQ2hhaW4iLCJPYmplY3QiLCJrZXlzIiwiZm9yRWFjaCIsImsiLCJpbmNsdWRlcyIsImVudHJ5Iiwic3Vic3RyaW5nIiwidW5kZWZpbmVkIiwiY29sb3JzIiwidG9Db25zb2xlIiwidG9GaWxlIiwicGF0aENyZWF0ZWQiLCJsZXZlbHNEZXNjIiwidGl0bGUiLCJjb2xvciIsImxpc3RlbmVycyIsImtleSIsIm9wdGlvbiIsImVudHJpZXMiLCJsb2dUb0ZpbGUiLCJ0ZXh0cyIsInByZWZpeCIsImV4aXN0c1N5bmMiLCJta2RpclN5bmMiLCJhcHBlbmRGaWxlIiwiY29uY2F0IiwiY29uc29sZSIsImxvZyIsIm5ld0xldmVsIiwibGVuZ3RoIiwiRGF0ZSIsInRvU3RyaW5nIiwic3BsaXQiLCJ0cmltIiwiZm4iLCJhcHBseSIsImxvZ1dpdGhTdGFjayIsImN1c3RvbU1lc3NhZ2UiLCJtYWluTWVzc2FnZSIsInN0YWNrTWVzc2FnZSIsInN0YWNrIiwic2xpY2UiLCJzZXRMb2dMZXZlbCIsImVuYWJsZUZpbGVMb2dnaW5nIiwibG9nRGVzdCIsImxvZ0ZpbGUiLCJlbmRzV2l0aCIsIl9fZGlybmFtZSIsImZpbGVVUkxUb1BhdGgiLCJVUkwiLCJkb2N1bWVudCIsInJlcXVpcmUiLCJwYXRoVG9GaWxlVVJMIiwiX19maWxlbmFtZSIsImhyZWYiLCJfZG9jdW1lbnRDdXJyZW50U2NyaXB0Iiwic3JjIiwiYmFzZVVSSSIsImZpeFR5cGUiLCJmb3JtYXRzIiwib3V0VHlwZSIsInBvcCIsImZpbmQiLCJ0IiwiaGFuZGxlUmVzb3VyY2VzIiwiYWxsb3dlZFByb3BzIiwiaGFuZGxlZFJlc291cmNlcyIsImNvcnJlY3RSZXNvdXJjZXMiLCJpc0NvcnJlY3RKU09OIiwicmVhZEZpbGVTeW5jIiwiZmlsZXMiLCJwcm9wTmFtZSIsIm1hcCIsIml0ZW0iLCJwYXJzZWREYXRhIiwiSlNPTiIsInBhcnNlIiwic3RyaW5naWZ5IiwiZGVlcENvcHkiLCJjb3B5IiwiQXJyYXkiLCJpc0FycmF5IiwicHJvdG90eXBlIiwiaGFzT3duUHJvcGVydHkiLCJjYWxsIiwib3B0aW9uc1N0cmluZ2lmeSIsImFsbG93RnVuY3Rpb25zIiwicmVwbGFjZUFsbCIsInByaW50VXNhZ2UiLCJib2xkIiwieWVsbG93IiwiY3ljbGVDYXRlZ29yaWVzIiwiZGVzY05hbWUiLCJncmVlbiIsImkiLCJibHVlIiwiY2F0ZWdvcnkiLCJ0b1VwcGVyQ2FzZSIsInJlZCIsInRvQm9vbGVhbiIsIndyYXBBcm91bmQiLCJyZXBsYWNlIiwibWVhc3VyZVRpbWUiLCJzdGFydCIsInByb2Nlc3MiLCJocnRpbWUiLCJiaWdpbnQiLCJOdW1iZXIiLCJkb3RlbnYiLCJjb25maWciLCJ2IiwieiIsImVudW0iLCJ0cmFuc2Zvcm0iLCJvcHRpb25hbCIsInN0cmluZyIsInZhbCIsImVudnMiLCJvYmplY3QiLCJISUdIQ0hBUlRTX1ZFUlNJT04iLCJyZWZpbmUiLCJ0ZXN0IiwiSElHSENIQVJUU19DRE5fVVJMIiwiSElHSENIQVJUU19DT1JFX1NDUklQVFMiLCJISUdIQ0hBUlRTX01PRFVMRVMiLCJISUdIQ0hBUlRTX0lORElDQVRPUlMiLCJISUdIQ0hBUlRTX0ZPUkNFX0ZFVENIIiwiSElHSENIQVJUU19DQUNIRV9QQVRIIiwiSElHSENIQVJUU19BRE1JTl9UT0tFTiIsIkVYUE9SVF9UWVBFIiwiRVhQT1JUX0NPTlNUUiIsIkVYUE9SVF9ERUZBVUxUX0hFSUdIVCIsImNvZXJjZSIsIm51bWJlciIsInBvc2l0aXZlIiwiRVhQT1JUX0RFRkFVTFRfV0lEVEgiLCJFWFBPUlRfREVGQVVMVF9TQ0FMRSIsIkVYUE9SVF9SQVNURVJJWkFUSU9OX1RJTUVPVVQiLCJDVVNUT01fTE9HSUNfQUxMT1dfQ09ERV9FWEVDVVRJT04iLCJDVVNUT01fTE9HSUNfQUxMT1dfRklMRUxfUkVTT1VSQ0VTIiwiU0VSVkVSX0VOQUJMRSIsIlNFUlZFUl9IT1NUIiwiU0VSVkVSX1BPUlQiLCJTRVJWRVJfQkVOQ0hNQVJLSU5HIiwiU0VSVkVSX1NTTF9FTkFCTEUiLCJTRVJWRVJfU1NMX0ZPUkNFIiwiU0VSVkVSX1NTTF9QT1JUIiwiU0VSVkVSX1NTTF9DRVJUX1BBVEgiLCJTRVJWRVJfUkFURV9MSU1JVElOR19FTkFCTEUiLCJTRVJWRVJfUkFURV9MSU1JVElOR19NQVhfUkVRVUVTVFMiLCJTRVJWRVJfUkFURV9MSU1JVElOR19XSU5ET1ciLCJTRVJWRVJfUkFURV9MSU1JVElOR19ERUxBWSIsIlNFUlZFUl9SQVRFX0xJTUlUSU5HX1RSVVNUX1BST1hZIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9LRVkiLCJTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX1RPS0VOIiwiUE9PTF9NSU5fV09SS0VSUyIsIlBPT0xfTUFYX1dPUktFUlMiLCJQT09MX1dPUktfTElNSVQiLCJQT09MX0FDUVVJUkVfVElNRU9VVCIsIlBPT0xfQ1JFQVRFX1RJTUVPVVQiLCJQT09MX0RFU1RST1lfVElNRU9VVCIsIlBPT0xfSURMRV9USU1FT1VUIiwiUE9PTF9DUkVBVEVfUkVUUllfSU5URVJWQUwiLCJQT09MX1JFQVBFUl9JTlRFUlZBTCIsIlBPT0xfQkVOQ0hNQVJLSU5HIiwiUE9PTF9MSVNURU5fVE9fUFJPQ0VTU19FWElUUyIsIkxPR0dJTkdfTEVWRUwiLCJMT0dHSU5HX0ZJTEUiLCJMT0dHSU5HX0RFU1QiLCJVSV9FTkFCTEUiLCJVSV9ST1VURSIsIk9USEVSX05PX0xPR08iLCJOT0RFX0VOViIsImRlZmF1bHQiLCJQUk9YWV9TRVJWRVJfVElNRU9VVCIsIlBST1hZX1NFUlZFUl9IT1NUIiwiUFJPWFlfU0VSVkVSX1BPUlQiLCJlbnYiLCJFeHBvcnRFcnJvciIsIkVycm9yIiwiY29uc3RydWN0b3IiLCJzdXBlciIsInRoaXMiLCJzZXRFcnJvciIsInN0YXR1c0NvZGUiLCJjYWNoZSIsImFjdGl2ZU1hbmlmZXN0Iiwic291cmNlcyIsImhjVmVyc2lvbiIsImFwcGxpZWRDb25maWciLCJleHRyYWN0VmVyc2lvbiIsImluZGV4T2YiLCJmZXRjaEFuZFByb2Nlc3NTY3JpcHQiLCJzY3JpcHQiLCJwcm94eUFnZW50IiwiZmV0Y2hlZE1vZHVsZXMiLCJzaG91bGRUaHJvd0Vycm9yIiwiYWdlbnQiLCJ0aW1lb3V0IiwicmVzcG9uc2UiLCJ1cGRhdGVDYWNoZSIsInNvdXJjZVBhdGgiLCJjdXN0b21TY3JpcHRzIiwicHJveHlIb3N0IiwicHJveHlQb3J0IiwiSHR0cHNQcm94eUFnZW50IiwibW9kdWxlU2NyaXB0cyIsImFsbEZldGNoUHJvbWlzZXMiLCJhbGwiLCJmZXRjaFNjcmlwdHMiLCJjIiwibSIsIndyaXRlRmlsZVN5bmMiLCJjaGVja0FuZFVwZGF0ZUNhY2hlIiwibWFuaWZlc3RQYXRoIiwicmVxdWVzdFVwZGF0ZSIsIm1hbmlmZXN0IiwibW9kdWxlTWFwIiwibnVtYmVyT2ZNb2R1bGVzIiwic29tZSIsIm1vZHVsZU5hbWUiLCJuZXdNYW5pZmVzdCIsInNhdmVDb25maWdUb01hbmlmZXN0IiwiZ2V0Q2FjaGVQYXRoIiwiY2FjaGUkMSIsIm5ld1ZlcnNpb24iLCJhc3NpZ24iLCJnZW5lcmFsT3B0aW9ucyIsImdldE9wdGlvbnMiLCJtZXJnZUNvbmZpZ09wdGlvbnMiLCJuZXdPcHRpb25zIiwibWVyZ2VkT3B0aW9ucyIsInVwZGF0ZURlZmF1bHRDb25maWciLCJjb25maWdPYmoiLCJjdXN0b21PYmoiLCJjdXN0b21WYWx1ZSIsImluaXRPcHRpb25zIiwiaXRlbXMiLCJyZWN1cnNpdmVQcm9wcyIsIm9iamVjdFRvVXBkYXRlIiwibmVzdGVkTmFtZXMiLCJzaGlmdCIsIlJBTkRPTV9QSUQiLCJyYW5kb21CeXRlcyIsIlBVUFBFVEVFUl9ESVIiLCJwYXRoIiwibWluaW1hbEFyZ3MiLCJ0ZW1wbGF0ZSIsImZzIiwiYnJvd3NlciIsInNldFBhZ2VDb250ZW50IiwicGFnZSIsInNldENvbnRlbnQiLCJhZGRTY3JpcHRUYWciLCJldmFsdWF0ZSIsInNldHVwSGlnaGNoYXJ0cyIsIiRldmFsIiwiZWxlbWVudCIsImVycm9yTWVzc2FnZSIsIl9kaXNwbGF5RXJyb3JzIiwiaW5uZXJIVE1MIiwiY2xlYXJQYWdlIiwiaGFyZFJlc2V0IiwiZ290byIsImJvZHkiLCJuZXdQYWdlIiwic2V0Q2FjaGVFbmFibGVkIiwiY2xvc2UiLCJpc0Nvbm5lY3RlZCIsIl9fYmFzZWRpciIsInNldEFzQ29uZmlnIiwiY2hhcnQiLCJ0cmlnZ2VyRXhwb3J0IiwicHVwcGV0ZWVyRXhwb3J0IiwiaW5qZWN0ZWRSZXNvdXJjZXMiLCJjbGVhckluamVjdGVkIiwiZGlzcG9zZSIsInNjcmlwdHNUb1JlbW92ZSIsImdldEVsZW1lbnRzQnlUYWdOYW1lIiwic3R5bGVzVG9SZW1vdmUiLCJsaW5rc1RvUmVtb3ZlIiwicmVtb3ZlIiwiZXhwb3J0T3B0aW9ucyIsInJlcXVlc3RBbmltYXRpb25GcmFtZSIsImRpc3BsYXlFcnJvcnMiLCJkZWJ1Z2dlciIsImlzU1ZHIiwiZCIsInN2Z1RlbXBsYXRlIiwic3RySW5qIiwianMiLCJwdXNoIiwiY29udGVudCIsImlzTG9jYWwiLCJjc3MiLCJjc3NJbXBvcnRzIiwibWF0Y2giLCJjc3NJbXBvcnRQYXRoIiwiYWRkU3R5bGVUYWciLCJzaXplIiwiY2hhcnRIZWlnaHQiLCJiYXNlVmFsIiwiY2hhcnRXaWR0aCIsInBhcnNlRmxvYXQiLCJIaWdoY2hhcnRzIiwiY2hhcnRzIiwidmlld3BvcnRIZWlnaHQiLCJNYXRoIiwiY2VpbCIsInZpZXdwb3J0V2lkdGgiLCJzZXRWaWV3cG9ydCIsImRldmljZVNjYWxlRmFjdG9yIiwiem9vbUNhbGxiYWNrIiwic3R5bGUiLCJ6b29tIiwibWFyZ2luIiwieCIsInkiLCJnZXRCb3VuZGluZ0NsaWVudFJlY3QiLCJ0cnVuYyIsImdldENsaXBSZWdpb24iLCJvdXRlckhUTUwiLCJjcmVhdGVTVkciLCJlbmNvZGluZyIsImNsaXAiLCJyYWNlIiwic2NyZWVuc2hvdCIsIm9taXRCYWNrZ3JvdW5kIiwiX3Jlc29sdmUiLCJzZXRUaW1lb3V0IiwiY3JlYXRlSW1hZ2UiLCJwZGYiLCJjcmVhdGVQREYiLCJvbGRDaGFydHMiLCJvbGRDaGFydCIsImRlc3Ryb3kiLCJwdXBwZXRlZXJBcmdzIiwicGVyZm9ybWVkRXhwb3J0cyIsImV4cG9ydEF0dGVtcHRzIiwidGltZVNwZW50IiwiZHJvcHBlZEV4cG9ydHMiLCJzcGVudEF2ZXJhZ2UiLCJwb29sQ29uZmlnIiwiZmFjdG9yeSIsImNyZWF0ZSIsImlkIiwidXVpZCIsInN0YXJ0RGF0ZSIsImdldFRpbWUiLCJicm93c2VyTmV3UGFnZSIsImlzQ2xvc2VkIiwid29ya0NvdW50IiwicmFuZG9tIiwidmFsaWRhdGUiLCJ3b3JrZXJIYW5kbGUiLCJpbml0UG9vbCIsImNvZGUiLCJraWxsUG9vbCIsImV4aXQiLCJhbGxBcmdzIiwidHJ5Q291bnQiLCJvcGVuIiwibGF1bmNoIiwiaGVhZGxlc3MiLCJ1c2VyRGF0YURpciIsImNyZWF0ZUJyb3dzZXIiLCJwYXJzZUludCIsIlBvb2wiLCJhY3F1aXJlVGltZW91dE1pbGxpcyIsImNyZWF0ZVRpbWVvdXRNaWxsaXMiLCJkZXN0cm95VGltZW91dE1pbGxpcyIsImlkbGVUaW1lb3V0TWlsbGlzIiwiY3JlYXRlUmV0cnlJbnRlcnZhbE1pbGxpcyIsInJlYXBJbnRlcnZhbE1pbGxpcyIsInByb3BhZ2F0ZUNyZWF0ZUVycm9yIiwicmVzb3VyY2UiLCJldmVudElkIiwiaW5pdGlhbFJlc291cmNlcyIsImFjcXVpcmUiLCJwcm9taXNlIiwicmVsZWFzZSIsImJyb3dzZXJDbG9zZSIsImRlc3Ryb3llZCIsInBvc3RXb3JrIiwiZ2V0UG9vbEluZm8iLCJhY3F1aXJlQ291bnRlciIsInBheWxvYWQiLCJyZXF1ZXN0SWQiLCJ3b3JrU3RhcnQiLCJleHBvcnRDb3VudGVyIiwicmVzdWx0IiwiZXhwb3J0VGltZSIsIm51bUZyZWUiLCJudW1Vc2VkIiwibnVtUGVuZGluZ0FjcXVpcmVzIiwicG9vbCQxIiwiYXZhaWxhYmxlIiwiaW5Vc2UiLCJwZW5kaW5nQWNxdWlyZSIsInN0YXJ0RXhwb3J0Iiwic2V0dGluZ3MiLCJlbmRDYWxsYmFjayIsInN2ZyIsImluaXRFeHBvcnRTZXR0aW5ncyIsImV4cG9ydEFzU3RyaW5nIiwiZG9TdHJhaWdodEluamVjdCIsImRvRXhwb3J0IiwiZmluZENoYXJ0U2l6ZSIsImV4cG9ydGluZyIsInByZWNpc2lvbiIsIm11bHRpcGxpZXIiLCJwb3ciLCJyb3VuZE51bWJlciIsInNvdXJjZUhlaWdodCIsInNvdXJjZVdpZHRoIiwicGFyYW0iLCJjaGFydEpzb24iLCJjdXN0b21Mb2dpY09wdGlvbnMiLCJhbGxvd0NvZGVFeGVjdXRpb25TY29wZWQiLCJlbmFibGVkIiwib3B0aW9uc05hbWUiLCJzdHJpbmdUb0V4cG9ydCIsImNoYXJ0SlNPTiIsImxvZ0Vycm9yTWlkZGxld2FyZSIsInJlcSIsIm5leHQiLCJyZXR1cm5FcnJvck1pZGRsZXdhcmUiLCJzdENvZGUiLCJzdGF0dXMiLCJqc29uIiwicmF0ZUxpbWl0IiwiYXBwIiwibGltaXRDb25maWciLCJtc2ciLCJyYXRlT3B0aW9ucyIsImxpbWl0ZXIiLCJ3aW5kb3dNcyIsImRlbGF5TXMiLCJoYW5kbGVyIiwicmVxdWVzdCIsImZvcm1hdCIsInNlbmQiLCJza2lwIiwicXVlcnkiLCJhY2Nlc3NfdG9rZW4iLCJ1c2UiLCJIdHRwRXJyb3IiLCJzZXRTdGF0dXMiLCJyZXZlcnNlZE1pbWUiLCJwbmciLCJqcGVnIiwiZ2lmIiwicmVxdWVzdHNDb3VudGVyIiwiYmVmb3JlUmVxdWVzdCIsImFmdGVyUmVxdWVzdCIsImRvQ2FsbGJhY2tzIiwiY2FsbGJhY2tzIiwidW5pcXVlSWQiLCJjYWxsUmVzcG9uc2UiLCJleHBvcnRIYW5kbGVyIiwic3RvcENvdW50ZXIiLCJkZWZhdWx0T3B0aW9ucyIsImhlYWRlcnMiLCJjb25uZWN0aW9uIiwicmVtb3RlQWRkcmVzcyIsImNvbm5lY3Rpb25BYm9ydGVkIiwic29ja2V0IiwidG9Mb3dlckNhc2UiLCJzdWJzdHIiLCJiNjQiLCJub0Rvd25sb2FkIiwicGF0dGVybiIsImlzUHJpdmF0ZVJhbmdlVXJsRm91bmQiLCJpbmZvIiwicmVtb3ZlQWxsTGlzdGVuZXJzIiwiQnVmZmVyIiwiZnJvbSIsImhlYWRlciIsImF0dGFjaG1lbnQiLCJwYXJhbXMiLCJmaWxlbmFtZSIsInBrZ0ZpbGUiLCJwYXRoZXIiLCJzZXJ2ZXJTdGFydFRpbWUiLCJleHByZXNzIiwiZGlzYWJsZSIsImNvcnMiLCJzdG9yYWdlIiwibXVsdGVyIiwibWVtb3J5U3RvcmFnZSIsInVwbG9hZCIsImxpbWl0cyIsImZpZWxkU2l6ZSIsImxpbWl0IiwidXJsZW5jb2RlZCIsImV4dGVuZGVkIiwibm9uZSIsImF0dGFjaEVycm9ySGFuZGxlcnMiLCJzdGFydFNlcnZlciIsInNlcnZlckNvbmZpZyIsImh0dHBTZXJ2ZXIiLCJjcmVhdGVTZXJ2ZXIiLCJsaXN0ZW4iLCJjZXJ0IiwiZnNQcm9taXNlcyIsInJlYWRGaWxlIiwicG9zaXgiLCJodHRwc1NlcnZlciIsIk5hTiIsInN0YXRpYyIsImJvb3RUaW1lIiwidXB0aW1lIiwiZmxvb3IiLCJoaWdoY2hhcnRzVmVyc2lvbiIsImF2ZXJhZ2VQcm9jZXNzaW5nVGltZSIsImZhaWxlZEV4cG9ydHMiLCJzdWNlc3NSYXRpbyIsImhlYWx0aFJvdXRlIiwicG9zdCIsImV4cG9ydFJvdXRlcyIsInNlbmRGaWxlIiwidWlSb3V0ZSIsImFkbWluVG9rZW4iLCJ0b2tlbiIsInZTd2l0Y2hSb3V0ZSIsImVycm9ySGFuZGxlciIsImVuYWJsZVJhdGVMaW1pdGluZyIsImdldEV4cHJlc3MiLCJnZXRBcHAiLCJtaWRkbGV3YXJlcyIsImluZGV4Iiwic2V0T3B0aW9ucyIsInVzZXJPcHRpb25zIiwiY29uZmlnSW5kZXgiLCJmaW5kSW5kZXgiLCJhcmciLCJmaWxlTmFtZSIsImxvYWRDb25maWdGaWxlIiwic2hvd1VzYWdlIiwicHJvcGVydGllc0NoYWluIiwiYXJndW1lbnRUeXBlIiwicmVkdWNlIiwicHJvcCIsInBhaXJBcmd1bWVudFZhbHVlIiwiaW5pdEV4cG9ydCIsImluaXRMb2dnaW5nIiwic2luZ2xlRXhwb3J0IiwiYmF0Y2hFeHBvcnQiLCJiYXRjaEZ1bmN0aW9ucyIsInBhaXIiLCJtYXBUb05ld0NvbmZpZyIsIm9sZE9wdGlvbnMiLCJtYW51YWxDb25maWciLCJjb25maWdGaWxlTmFtZSIsImNvbmZpZ0ZpbGUiLCJjaG9pY2UiLCJwcm9tcHRzIiwib25TdWJtaXQiLCJwIiwiY2F0ZWdvcmllcyIsInF1ZXN0aW9uc0NvdW50ZXIiLCJhbGxRdWVzdGlvbnMiLCJzZWN0aW9uIiwicHJvbXB0IiwiYW5zd2VyIiwibW9kdWxlIiwicHJvbWlzZXMiLCJ3cml0ZUZpbGUiLCJwcmludExvZ28iLCJwYWNrYWdlVmVyc2lvbiJdLCJtYXBwaW5ncyI6Im11QkF5QkFBLGVBQWVDLEVBQU1DLEVBQUtDLEVBQWlCLElBQ3pDLE9BQU8sSUFBSUMsU0FBUSxDQUFDQyxFQUFTQyxLQUMzQixNQUFNQyxFQWJVLENBQUNMLEdBQVNBLEVBQUlNLFdBQVcsU0FBV0MsRUFBUUMsRUFhM0NDLENBQVlULEdBRTdCSyxFQUNHSyxJQUFJVixFQUFLQyxHQUFpQlUsSUFDekIsSUFBSUMsRUFBTyxHQUdYRCxFQUFJRSxHQUFHLFFBQVNDLElBQ2RGLEdBQVFFLENBQUssSUFJZkgsRUFBSUUsR0FBRyxPQUFPLEtBQ1BELEdBQ0hSLEVBQU8scUNBR1RPLEVBQUlJLEtBQU9ILEVBQ1hULEVBQVFRLEVBQUksR0FDWixJQUVIRSxHQUFHLFNBQVVHLElBQ1paLEVBQU9ZLEVBQU0sR0FDYixHQUVSLENDcENPLE1BQU1DLEVBQWdCLENBQzNCQyxVQUFXLENBQ1RDLEtBQU0sQ0FDSkMsTUFBTyxHQUNQQyxLQUFNLFdBQ05DLFlBQWEsMENBR2pCQyxXQUFZLENBQ1ZDLFFBQVMsQ0FDUEosTUFBTyxTQUNQSyxRQUFTLHFCQUNUSixLQUFNLFNBQ05DLFlBQWEsc0NBRWZJLE9BQVEsQ0FDTk4sTUFBTywrQkFDUEssUUFBUyxxQkFDVEosS0FBTSxTQUNOQyxZQUFhLGtEQUVmSyxZQUFhLENBQ1hGLFFBQVMsMEJBQ1RMLE1BQU8sQ0FBQyxhQUFjLGtCQUFtQixpQkFDekNDLEtBQU0sV0FDTkMsWUFBYSx5Q0FFZk0sUUFBUyxDQUNQSCxRQUFTLHFCQUNUTCxNQUFPLENBQ0wsUUFDQSxNQUNBLFFBQ0EsWUFDQSxjQUNBLHVCQUNBLGdCQUNBLHVCQUNBLGVBQ0EsUUFDQSxPQUNBLGFBQ0EsbUJBQ0EsZUFDQSxjQUNBLFVBQ0EsVUFDQSxjQUNBLFdBQ0EsVUFDQSxZQUNBLGNBQ0EsWUFDQSxzQkFDQSxTQUNBLFNBQ0EsV0FDQSxhQUNBLFlBQ0EsZUFDQSx5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 diff --git a/dist/index.esm.js b/dist/index.esm.js index 489ea041..4f4416eb 100644 --- a/dist/index.esm.js +++ b/dist/index.esm.js @@ -1,2 +1,2 @@ -import"colors";import e from"dotenv";import t,{existsSync as r,mkdirSync as i,appendFile as o,readFileSync as n,writeFileSync as s,promises as a}from"fs";import l,{join as c,posix as p}from"path";import{HttpsProxyAgent as h}from"https-proxy-agent";import u from"http";import d from"https";import*as g from"url";import{fileURLToPath as m}from"url";import f from"prompts";import{Pool as v}from"tarn";import{v4 as y}from"uuid";import w from"node:path";import b from"puppeteer";import{randomBytes as T}from"node:crypto";import k from"cors";import x from"express";import E from"multer";import L from"express-rate-limit";async function S(e,t={}){return new Promise(((r,i)=>{const o=(e=>e.startsWith("https")?d:u)(e);o.get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||i("Nothing was fetched from the URL."),e.text=t,r(e)}))})).on("error",(e=>{i(e)}))}))}const O={puppeteer:{args:{value:[],type:"string[]",description:"Arguments array to send to Puppeteer."}},highcharts:{version:{value:"latest",envLink:"HIGHCHARTS_VERSION",type:"string",description:"The Highcharts version to be used."},cdnURL:{value:"https://code.highcharts.com/",envLink:"HIGHCHARTS_CDN_URL",type:"string",description:"The CDN URL for Highcharts scripts to be used."},coreScripts:{envLink:"HIGHCHARTS_CORE_SCRIPTS",value:["highcharts","highcharts-more","highcharts-3d"],type:"string[]",description:"The core Highcharts scripts to fetch."},modules:{envLink:"HIGHCHARTS_MODULES",value:["stock","map","gantt","exporting","export-data","parallel-coordinates","accessibility","annotations-advanced","boost-canvas","boost","data","data-tools","draggable-points","static-scale","broken-axis","heatmap","tilemap","tiledwebmap","timeline","treemap","treegraph","item-series","drilldown","histogram-bellcurve","bullet","funnel","funnel3d","geoheatmap","pyramid3d","networkgraph","overlapping-datalabels","pareto","pattern-fill","pictorial","price-indicator","sankey","arc-diagram","dependency-wheel","series-label","solid-gauge","sonification","stock-tools","streamgraph","sunburst","variable-pie","variwide","vector","venn","windbarb","wordcloud","xrange","no-data-to-display","drag-panes","debugger","dumbbell","lollipop","cylinder","organization","dotplot","marker-clusters","hollowcandlestick","heikinashi","flowmap"],type:"string[]",description:"The modules of Highcharts to fetch."},indicators:{envLink:"HIGHCHARTS_INDICATORS",value:["indicators-all"],type:"string[]",description:"The indicators of Highcharts to fetch."},scripts:{value:["https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js","https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.34/moment-timezone-with-data.min.js"],type:"string[]",description:"Additional optional scripts or dependencies to fetch."},forceFetch:{envLink:"HIGHCHARTS_FORCE_FETCH",value:!1,type:"boolean",description:"The flag to determine whether to refetch all scripts after each server rerun."},cachePath:{envLink:"HIGHCHARTS_CACHE_PATH",value:".cache",type:"string",description:"The path to the cache directory. It is used to store the Highcharts scripts and custom scripts."}},export:{infile:{value:!1,type:"string",description:"The input file should include a name and a type (json or svg). It must be correctly formatted as a JSON or SVG file."},instr:{value:!1,type:"string",description:"Input, provided in the form of a stringified JSON or SVG file, will override the --infile option."},options:{value:!1,type:"string",description:"An alias for the --instr option."},outfile:{value:!1,type:"string",description:"The output filename along with a type (jpeg, png, pdf, or svg). This will ignore the --type flag."},type:{envLink:"EXPORT_TYPE",value:"png",type:"string",description:"The file export format. It can be jpeg, png, pdf, or svg."},constr:{envLink:"EXPORT_CONSTR",value:"chart",type:"string",description:"The constructor to use. Can be chart, stockChart, mapChart, or ganttChart."},defaultHeight:{envLink:"EXPORT_DEFAULT_HEIGHT",value:400,type:"number",description:"the default height of the exported chart. Used when no value is set."},defaultWidth:{envLink:"EXPORT_DEFAULT_WIDTH",value:600,type:"number",description:"The default width of the exported chart. Used when no value is set."},defaultScale:{envLink:"EXPORT_DEFAULT_SCALE",value:1,type:"number",description:"The default scale of the exported chart. Used when no value is set."},height:{type:"number",value:!1,description:"The height of the exported chart, overriding the option in the chart settings."},width:{type:"number",value:!1,description:"The width of the exported chart, overriding the option in the chart settings."},scale:{value:!1,type:"number",description:"The scale of the exported chart, overriding the option in the chart settings. Ranges between 0.1 and 5.0."},globalOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing options to be passed into the Highcharts.setOptions."},themeOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing theme options to be passed into the Highcharts.setOptions."},batch:{value:!1,type:"string",description:'Initiates a batch job with a string containing input/output pairs: "in=out;in=out;...".'},rasterizationTimeout:{envLink:"EXPORT_RASTERIZATION_TIMEOUT",value:1500,type:"number",description:"The duration in milliseconds to wait for rendering a webpage."}},customLogic:{allowCodeExecution:{envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",value:!1,type:"boolean",description:"Controls whether the execution of arbitrary code is allowed during the exporting process."},allowFileResources:{envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",value:!1,type:"boolean",description:"Controls the ability to inject resources from the filesystem. This setting has no effect when running as a server."},customCode:{value:!1,type:"string",description:"Custom code to execute before chart initialization. It can be a function, code wrapped within a function, or a filename with the .js extension."},callback:{value:!1,type:"string",description:"JavaScript code to run during construction. It can be a function or a filename with the .js extension."},resources:{value:!1,type:"string",description:"Additional resource in the form of a stringified JSON, which may contain files, js, and css sections."},loadConfig:{value:!1,type:"string",legacyName:"fromFile",description:"A file containing a pre-defined configuration to use."},createConfig:{value:!1,type:"string",description:"Enables setting options through a prompt and saving them in a provided config file."}},server:{enable:{envLink:"SERVER_ENABLE",value:!1,type:"boolean",cliName:"enableServer",description:"When set to true, the server starts on the local IP address 0.0.0.0."},host:{envLink:"SERVER_HOST",value:"0.0.0.0",type:"string",description:"The hostname of the server. Additionally, it starts a server on the provided hostname."},port:{envLink:"SERVER_PORT",value:7801,type:"number",description:"The server port when enabled."},benchmarking:{envLink:"SERVER_BENCHMARKING",value:!1,type:"boolean",cliName:"serverBenchmarking",description:"Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request."},ssl:{enable:{envLink:"SERVER_SSL_ENABLE",value:!1,type:"boolean",cliName:"enableSsl",description:"Enables or disables the SSL protocol."},force:{envLink:"SERVER_SSL_FORCE",value:!1,type:"boolean",cliName:"sslForced",legacyName:"sslOnly",description:"When set to true, the server is forced to serve only over HTTPS."},port:{envLink:"SERVER_SSL_PORT",value:443,type:"number",cliName:"sslPort",description:"The port on which to run the SSL server."},certPath:{envLink:"SERVER_SSL_CERT_PATH",value:"",type:"string",legacyName:"sslPath",description:"The path to the SSL certificate/key file."}},rateLimiting:{enable:{envLink:"SERVER_RATE_LIMITING_ENABLE",value:!1,type:"boolean",cliName:"enableRateLimiting",description:"Enables rate limiting for the server."},maxRequests:{envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",value:10,type:"number",legacyName:"rateLimit",description:"The maximum number of requests allowed in one minute."},window:{envLink:"SERVER_RATE_LIMITING_WINDOW",value:1,type:"number",description:"The time window, in minutes, for the rate limiting."},delay:{envLink:"SERVER_RATE_LIMITING_DELAY",value:0,type:"number",description:"The delay duration for each successive request before reaching the maximum limit."},trustProxy:{envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",value:!1,type:"boolean",description:"Set this to true if the server is behind a load balancer."},skipKey:{envLink:"SERVER_RATE_LIMITING_SKIP_KEY",value:"",type:"string",description:"Allows bypassing the rate limiter and should be provided with the skipToken argument."},skipToken:{envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",value:"",type:"string",description:"Allows bypassing the rate limiter and should be provided with the skipKey argument."}}},pool:{minWorkers:{envLink:"POOL_MIN_WORKERS",value:4,type:"number",description:"The number of minimum and initial pool workers to spawn."},maxWorkers:{envLink:"POOL_MAX_WORKERS",value:8,type:"number",legacyName:"workers",description:"The number of maximum pool workers to spawn."},workLimit:{envLink:"POOL_WORK_LIMIT",value:40,type:"number",description:"The number of work pieces that can be performed before restarting the worker process."},acquireTimeout:{envLink:"POOL_ACQUIRE_TIMEOUT",value:5e3,type:"number",description:"The duration, in milliseconds, to wait for acquiring a resource."},createTimeout:{envLink:"POOL_CREATE_TIMEOUT",value:5e3,type:"number",description:"The duration, in milliseconds, to wait for creating a resource."},destroyTimeout:{envLink:"POOL_DESTROY_TIMEOUT",value:5e3,type:"number",description:"The duration, in milliseconds, to wait for destroying a resource."},idleTimeout:{envLink:"POOL_IDLE_TIMEOUT",value:3e4,type:"number",description:"The duration, in milliseconds, after which an idle resource is destroyed."},createRetryInterval:{envLink:"POOL_CREATE_RETRY_INTERVAL",value:200,type:"number",description:"The duration, in milliseconds, to wait before retrying the create process in case of a failure."},reaperInterval:{envLink:"POOL_REAPER_INTERVAL",value:1e3,type:"number",description:"The duration, in milliseconds, after which the check for idle resources to destroy is triggered."},benchmarking:{envLink:"POOL_BENCHMARKING",value:!1,type:"boolean",cliName:"poolBenchmarking",description:"Indicate whether to show statistics for the pool of resources or not."},listenToProcessExits:{envLink:"POOL_LISTEN_TO_PROCESS_EXITS",value:!0,type:"boolean",description:"Decides whether or not to attach process.exit handlers."}},logging:{level:{envLink:"LOGGING_LEVEL",value:4,type:"number",cliName:"logLevel",description:"The logging level to be used."},file:{envLink:"LOGGING_FILE",value:"highcharts-export-server.log",type:"string",cliName:"logFile",description:"The name of a log file. The logDest option also needs to be set to enable file logging."},dest:{envLink:"LOGGING_DEST",value:"log/",type:"string",cliName:"logDest",description:"The path to store log files. This also enables file logging."}},ui:{enable:{envLink:"UI_ENABLE",value:!1,type:"boolean",cliName:"enableUi",description:"Enables or disables the user interface (UI) for the export server."},route:{envLink:"UI_ROUTE",value:"/",type:"string",cliName:"uiRoute",description:"The endpoint route to which the user interface (UI) should be attached."}},other:{noLogo:{envLink:"OTHER_NO_LOGO",value:!1,type:"boolean",description:"Skip printing the logo on a startup. Will be replaced by a simple text."}}},R={puppeteer:[{type:"list",name:"args",message:"Puppeteer arguments",initial:O.puppeteer.args.value.join(","),separator:","}],highcharts:[{type:"text",name:"version",message:"Highcharts version",initial:O.highcharts.version.value},{type:"text",name:"cdnURL",message:"The URL of CDN",initial:O.highcharts.cdnURL.value},{type:"multiselect",name:"modules",message:"Available modules",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:O.highcharts.modules.value},{type:"list",name:"scripts",message:"Custom scripts",initial:O.highcharts.scripts.value.join(","),separator:","},{type:"toggle",name:"forceFetch",message:"Force re-fetch the scripts",initial:O.highcharts.forceFetch.value},{type:"text",name:"cachePath",message:"The path to the cache directory",initial:O.highcharts.cachePath.value}],export:[{type:"select",name:"type",message:"The default export file type",hint:`Default: ${O.export.type.value}`,initial:0,choices:["png","jpeg","pdf","svg"]},{type:"select",name:"constr",message:"The default constructor for Highcharts",hint:`Default: ${O.export.constr.value}`,initial:0,choices:["chart","stockChart","mapChart","ganttChart"]},{type:"number",name:"defaultHeight",message:"The default fallback height of the exported chart",initial:O.export.defaultHeight.value},{type:"number",name:"defaultWidth",message:"The default fallback width of the exported chart",initial:O.export.defaultWidth.value},{type:"number",name:"defaultScale",message:"The default fallback scale of the exported chart",initial:O.export.defaultScale.value,min:.1,max:5},{type:"number",name:"rasterizationTimeout",message:"The rendering webpage timeout in milliseconds",initial:O.export.rasterizationTimeout.value}],customLogic:[{type:"toggle",name:"allowCodeExecution",message:"Enable execution of custom code",initial:O.customLogic.allowCodeExecution.value},{type:"toggle",name:"allowFileResources",message:"Enable file resources",initial:O.customLogic.allowFileResources.value}],server:[{type:"toggle",name:"enable",message:"Starts the server on 0.0.0.0",initial:O.server.enable.value},{type:"text",name:"host",message:"Server hostname",initial:O.server.host.value},{type:"number",name:"port",message:"Server port",initial:O.server.port.value},{type:"toggle",name:"benchmarking",message:"Enable server benchmarking",initial:O.server.benchmarking.value},{type:"toggle",name:"ssl.enable",message:"Enable SSL protocol",initial:O.server.ssl.enable.value},{type:"toggle",name:"ssl.force",message:"Force serving only over HTTPS",initial:O.server.ssl.force.value},{type:"number",name:"ssl.port",message:"SSL server port",initial:O.server.ssl.port.value},{type:"text",name:"ssl.certPath",message:"The path to find the SSL certificate/key",initial:O.server.ssl.certPath.value},{type:"toggle",name:"rateLimiting.enable",message:"Enable rate limiting",initial:O.server.rateLimiting.enable.value},{type:"number",name:"rateLimiting.maxRequests",message:"The maximum requests allowed per minute",initial:O.server.rateLimiting.maxRequests.value},{type:"number",name:"rateLimiting.window",message:"The rate-limiting time window in minutes",initial:O.server.rateLimiting.window.value},{type:"number",name:"rateLimiting.delay",message:"The delay for each successive request before reaching the maximum",initial:O.server.rateLimiting.delay.value},{type:"toggle",name:"rateLimiting.trustProxy",message:"Set to true if behind a load balancer",initial:O.server.rateLimiting.trustProxy.value},{type:"text",name:"rateLimiting.skipKey",message:"Allows bypassing the rate limiter when provided with the skipToken argument",initial:O.server.rateLimiting.skipKey.value},{type:"text",name:"rateLimiting.skipToken",message:"Allows bypassing the rate limiter when provided with the skipKey argument",initial:O.server.rateLimiting.skipToken.value}],pool:[{type:"number",name:"minWorkers",message:"The initial number of workers to spawn",initial:O.pool.minWorkers.value},{type:"number",name:"maxWorkers",message:"The maximum number of workers to spawn",initial:O.pool.maxWorkers.value},{type:"number",name:"workLimit",message:"The pieces of work that can be performed before restarting a Puppeteer process",initial:O.pool.workLimit.value},{type:"number",name:"acquireTimeout",message:"The number of milliseconds to wait for acquiring a resource",initial:O.pool.acquireTimeout.value},{type:"number",name:"createTimeout",message:"The number of milliseconds to wait for creating a resource",initial:O.pool.createTimeout.value},{type:"number",name:"destroyTimeout",message:"The number of milliseconds to wait for destroying a resource",initial:O.pool.destroyTimeout.value},{type:"number",name:"idleTimeout",message:"The number of milliseconds after an idle resource is destroyed",initial:O.pool.idleTimeout.value},{type:"number",name:"createRetryInterval",message:"The retry interval in milliseconds after a create process fails",initial:O.pool.createRetryInterval.value},{type:"number",name:"reaperInterval",message:"The reaper interval in milliseconds after triggering the check for idle resources to destroy",initial:O.pool.reaperInterval.value},{type:"toggle",name:"benchmarking",message:"Enable benchmarking for a resource pool",initial:O.pool.benchmarking.value},{type:"toggle",name:"listenToProcessExits",message:"Set to false to skip attaching process.exit handlers",initial:O.pool.listenToProcessExits.value}],logging:[{type:"number",name:"level",message:"The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)",initial:O.logging.level.value,round:0,min:0,max:5},{type:"text",name:"file",message:"A log file name. Set with the --logDest to enable file logging",initial:O.logging.file.value},{type:"text",name:"dest",message:"The path to log files. Enables file logging",initial:O.logging.dest.value}],ui:[{type:"toggle",name:"enable",message:"Enable UI for the export server",initial:O.ui.enable.value},{type:"text",name:"route",message:"A route to attach the UI",initial:O.ui.route.value}],other:[{type:"toggle",name:"noLogo",message:"Skip printing the logo on startup. Replaced by simple text",initial:O.other.noLogo.value}]},I=["options","globalOptions","themeOptions","resources","payload"],C={},$=(e,t="")=>{Object.keys(e).forEach((r=>{if(!["puppeteer","highcharts"].includes(r)){const i=e[r];void 0===i.value?$(i,`${t}.${r}`):(C[i.cliName||r]=`${t}.${r}`.substring(1),void 0!==i.legacyName&&(C[i.legacyName]=`${t}.${r}`.substring(1)))}}))};$(O);const _=["red","yellow","blue","gray","green"];let N={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:_[0]},{title:"warning",color:_[1]},{title:"notice",color:_[2]},{title:"verbose",color:_[3]},{title:"benchmark",color:_[4]}],listeners:[]};for(const[e,t]of Object.entries(O.logging))N[e]=t.value;const P=(e,t)=>{N.toFile&&(N.pathCreated||(!r(N.dest)&&i(N.dest),N.pathCreated=!0),o(`${N.dest}${N.file}`,[t].concat(e).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),N.toFile=!1)})))},A=(...e)=>{const[t,...r]=e,{level:i,levelsDesc:o}=N;if(5!==t&&(0===t||t>i||i>o.length))return;const n=`${(new Date).toString().split("(")[0].trim()} [${o[t-1].title}] -`;N.listeners.forEach((e=>{e(n,r.join(" "))})),N.toConsole&&console.log.apply(void 0,[n.toString()[N.levelsDesc[t-1].color]].concat(r)),P(r,n)},j=(e,t,r)=>{const i=r||t.message,{level:o,levelsDesc:n}=N;if(0===e||e>o||o>n.length)return;const s=`${(new Date).toString().split("(")[0].trim()} [${n[e-1].title}] -`,a=t.message!==t.stackMessage||void 0===t.stackMessage?t.stack:t.stack.split("\n").slice(1).join("\n"),l=[i,"\n",a];N.toConsole&&console.log.apply(void 0,[s.toString()[N.levelsDesc[e-1].color]].concat([i[_[e-1]],"\n",a])),N.listeners.forEach((e=>{e(s,l.join(" "))})),P(l,s)},H=e=>{e>=0&&e<=N.levelsDesc.length&&(N.level=e)},U=(e,t)=>{if(N={...N,dest:e||N.dest,file:t||N.file,toFile:!0},0===N.dest.length)return A(1,"[logger] File logging initialization: no path supplied.");N.dest.endsWith("/")||(N.dest+="/")},W=m(new URL("../.",import.meta.url)),D=(e,t)=>{const r=["png","jpeg","pdf","svg"];if(t){const i=t.split(".").pop();"jpg"===i?e="jpeg":r.includes(i)&&e!==i&&(e=i)}return{"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"}[e]||r.find((t=>t===e))||"png"},M=(e=!1,t)=>{const r=["js","css","files"];let i=e,o=!1;if(t&&e.endsWith(".json"))try{i=F(n(e,"utf8"))}catch(e){return j(2,e,"[cli] No resources found.")}else i=F(e),i&&!t&&delete i.files;for(const e in i)r.includes(e)?o||(o=!0):delete i[e];return o?(i.files&&(i.files=i.files.map((e=>e.trim())),(!i.files||i.files.length<=0)&&delete i.files),i):A(3,"[cli] No resources found.")};function F(e,t){try{const r=JSON.parse("string"!=typeof e?JSON.stringify(e):e);return"string"!=typeof r&&t?JSON.stringify(r):r}catch{return!1}}const q=e=>{if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=q(e[r]));return t},G=(e,t)=>JSON.stringify(e,((e,r)=>("string"==typeof r&&((r=r.trim()).startsWith("function(")||r.startsWith("function ("))&&r.endsWith("}")&&(r=t?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:void 0),"function"==typeof r?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:r))).replaceAll(/"EXP_FUN|EXP_FUN"/g,"");function V(){console.log("\nUsage of CLI arguments:".bold,"\n------",`\nFor more detailed information, visit the readme at: ${"https://github.com/highcharts/node-export-server#readme".bold.yellow}.`);const e=t=>{for(const[r,i]of Object.entries(t))if(Object.prototype.hasOwnProperty.call(i,"value")){let e=` --${i.cliName||r} ${("<"+i.type+">").green} `;if(e.length<48)for(let t=e.length;t<48;t++)e+=".";console.log(e,i.description,`[Default: ${i.value.toString().bold}]`.blue)}else e(i)};Object.keys(O).forEach((t=>{["puppeteer","highcharts"].includes(t)||(console.log(`\n${t.toUpperCase()}`.red),e(O[t]))})),console.log("\n")}const J=e=>!["false","undefined","null","NaN","0",""].includes(e)&&!!e,K=(e,t)=>{if(e&&"string"==typeof e)return(e=e.trim()).endsWith(".js")?!!t&&K(n(e,"utf8")):e.startsWith("function()")||e.startsWith("function ()")||e.startsWith("()=>")||e.startsWith("() =>")?`(${e})()`:e.replace(/;$/,"")},z=()=>{const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6};class X extends Error{constructor(e){super(),this.message=e,this.stackMessage=e}setError(e){return this.error=e,e.name&&(this.name=e.name),e.statusCode&&(this.statusCode=e.statusCode),e.stack&&(this.stackMessage=e.message,this.stack=e.stack),this}}const B={cdnURL:"https://code.highcharts.com/",activeManifest:{},sources:"",hcVersion:""};let Y=!1;const Q=()=>B.hcVersion=B.sources.substring(0,B.sources.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim(),Z=async(e,t,r,i=!1)=>{e.endsWith(".js")&&(e=e.substring(0,e.length-3)),A(4,`[cache] Fetching script - ${e}.js`);const o=t?{agent:t,timeout:+process.env.PROXY_SERVER_TIMEOUT||5e3}:{},n=await S(`${e}.js`,o);if(200===n.statusCode&&"string"==typeof n.text){if(r){r[e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")]=1}return n.text}if(i)throw new X(`Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${n.statusCode}).`).setError(n);return A(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`),""},ee=async(e,t)=>{const{coreScripts:r,modules:i,indicators:o,scripts:n}=e,a="latest"!==e.version&&e.version?`${e.version}/`:"";let l;A(3,`[cache] Updating cache version to Highcharts: ${a||"latest"}.`);const c=process.env.PROXY_SERVER_HOST,p=process.env.PROXY_SERVER_PORT;if(c&&p)try{l=new h({host:c,port:+p})}catch(e){throw new X("[cache] Could not create a Proxy Agent.").setError(e)}const u={};try{return B.sources=await(async(e,t,r,i,o,n)=>{const s=[...e.map((e=>Z(`${i}${e}`,o,n,!0))),...t.map((e=>Z(`${i}${e}`,o,n))),...r.map((e=>Z(`${e}`,o)))];return(await Promise.all(s)).join(";\n")})([...r.map((e=>`${a}${e}`))],[...i.map((e=>"map"===e?`maps/${a}modules/${e}`:`${a}modules/${e}`)),...o.map((e=>`stock/${a}indicators/${e}`))],n,e.cdnURL||B.cdnURL,l,u),Q(),s(t,B.sources),u}catch(e){throw new X("[cache] Unable to update the local Highcharts cache.").setError(e)}},te=async e=>{const t=c(W,e.cachePath);let o;const a=c(t,"manifest.json"),l=c(t,"sources.js");if(Y=e,!r(t)&&i(t),!r(a)||e.forceFetch)A(3,"[cache] Fetching and caching Highcharts dependencies."),o=await ee(e,l);else{let t=!1;const r=JSON.parse(n(a));if(r.modules&&Array.isArray(r.modules)){const e={};r.modules.forEach((t=>e[t]=1)),r.modules=e}const{modules:i,coreScripts:s,indicators:c}=e,p=i.length+s.length+c.length;r.version!==e.version?(A(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),t=!0):Object.keys(r.modules||{}).length!==p?(A(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),t=!0):t=(e.modules||[]).some((e=>{if(!r.modules[e])return A(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),t?o=await ee(e,l):(A(3,"[cache] Dependency cache is up to date, proceeding."),B.sources=n(l,"utf8"),o=r.modules,Q())}await(async(e,t)=>{const r={version:e.version,modules:t||{}};B.activeManifest=r,A(3,"[cache] Writing a new manifest.");try{s(c(W,e.cachePath,"manifest.json"),JSON.stringify(r),"utf8")}catch(e){throw new X("[cache] Error writing the cache manifest.").setError(e)}})(e,o)},re=()=>c(W,Y.cachePath);var ie=async e=>!!Y&&await te(Object.assign(Y,{version:e})),oe=()=>B,ne=()=>B.hcVersion;let se={};const ae=()=>se,le=(e,t,r=[])=>{const i=q(e);for(const[e,n]of Object.entries(t))i[e]="object"!=typeof(o=n)||Array.isArray(o)||null===o||r.includes(e)||void 0===i[e]?void 0!==n?n:i[e]:le(i[e],n,r);var o;return i};function ce(e,t={},r=""){Object.keys(e).forEach((i=>{const o=e[i],n=t&&t[i];let s;void 0===o.value?ce(o,n,`${r}.${i}`):(void 0!==n&&(o.value=n),o.envLink&&("boolean"===o.type?o.value=J([process.env[o.envLink],o.value].find((e=>e||"false"===e))):"number"===o.type?(s=+process.env[o.envLink],o.value=s>=0?s:o.value):o.type.indexOf("]")>=0&&process.env[o.envLink]?o.value=process.env[o.envLink].split(","):o.value=process.env[o.envLink]||o.value))}))}function pe(e){let t={};for(const[r,i]of Object.entries(e))t[r]=Object.prototype.hasOwnProperty.call(i,"value")?i.value:pe(i);return t}function he(e,t,r){for(;t.length>1;){const i=t.shift();return Object.prototype.hasOwnProperty.call(e,i)||(e[i]={}),e[i]=he(Object.assign({},e[i]),t,r),e}return e[t[0]]=r,e}const ue=T(64).toString("base64url"),de=w.join("tmp",`puppeteer-${ue}`),ge=[`--user-data-dir=${w.join(de,"profile")}`,"--autoplay-policy=user-gesture-required","--disable-background-networking","--disable-background-timer-throttling","--disable-backgrounding-occluded-windows","--disable-breakpad","--disable-client-side-phishing-detection","--disable-component-update","--disable-default-apps","--disable-dev-shm-usage","--disable-domain-reliability","--disable-extensions","--disable-features=AudioServiceOutOfProcess","--disable-hang-monitor","--disable-ipc-flooding-protection","--disable-notifications","--disable-offer-store-unmasked-wallet-cards","--disable-popup-blocking","--disable-print-preview","--disable-prompt-on-repost","--disable-renderer-backgrounding","--disable-session-crashed-bubble","--disable-setuid-sandbox","--disable-speech-api","--disable-sync","--hide-crash-restore-bubble","--hide-scrollbars","--ignore-gpu-blacklist","--metrics-recording-only","--mute-audio","--no-default-browser-check","--no-first-run","--no-pings","--no-sandbox","--no-zygote","--password-store=basic","--use-mock-keychain"],me=g.fileURLToPath(new URL(".",import.meta.url)),fe=t.readFileSync(me+"/../templates/template.html","utf8");let ve;const ye=async e=>{await e.setContent(fe),await e.addScriptTag({path:`${re()}/sources.js`}),await e.evaluate((()=>window.setupHighcharts())),e.on("pageerror",(async t=>{await e.$eval("#container",((e,t)=>{window._displayErrors&&(e.innerHTML=t)}),`

Chart input data error

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

Chart input data error

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

Chart input data error

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

Chart input data error

${error.toString()}`\r\n );\r\n });\r\n};\r\n\r\n/**\r\n * Clears the content of a Puppeteer Page based on the specified mode.\r\n *\r\n * @param {Object} page - The Puppeteer Page object to be cleared.\r\n * @param {boolean} hardReset - A flag indicating the type of clearing\r\n * to be performed. If true, navigates to 'about:blank' and resets content\r\n * and scripts. If false, clears the body content by setting a predefined HTML\r\n * structure.\r\n *\r\n * @throws {Error} Logs thrown error if clearing the page content fails.\r\n */\r\nexport const clearPage = async (page, hardReset = false) => {\r\n try {\r\n if (hardReset) {\r\n // Navigate to about:blank\r\n await page.goto('about:blank');\r\n\r\n // Set the content and and scripts again\r\n await setPageContent(page);\r\n } else {\r\n // Clear body content\r\n await page.evaluate(() => {\r\n document.body.innerHTML =\r\n '
';\r\n });\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n '[browser] Could not clear the content of the page.'\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Creates a new Puppeteer Page within an existing browser instance.\r\n *\r\n * If the browser instance is not available, returns false.\r\n *\r\n * The function creates a new page, disables caching, sets content using\r\n * setPageContent(), and returns the created Puppeteer Page.\r\n *\r\n * @returns {(boolean|object)} Returns false if the browser instance is not\r\n * available, or a Puppeteer Page object representing the newly created page.\r\n */\r\nexport const newPage = async () => {\r\n if (!browser) {\r\n return false;\r\n }\r\n\r\n const page = await browser.newPage();\r\n\r\n // Disable cache\r\n await page.setCacheEnabled(false);\r\n\r\n // Set the content\r\n await setPageContent(page);\r\n return page;\r\n};\r\n\r\n/**\r\n * Creates a Puppeteer browser instance with the specified arguments.\r\n *\r\n * @param {Array} puppeteerArgs - Additional arguments for Puppeteer launch.\r\n *\r\n * @returns {Promise} A Promise resolving to the Puppeteer browser\r\n * instance.\r\n *\r\n * @throws {ExportError} Throws an ExportError if max retries to open a browser\r\n * instance are reached, or if no browser instance is found after retries.\r\n */\r\nexport const create = async (puppeteerArgs) => {\r\n const allArgs = [...minimalArgs, ...(puppeteerArgs || [])];\r\n\r\n // Create a browser\r\n if (!browser) {\r\n let tryCount = 0;\r\n\r\n const open = async () => {\r\n try {\r\n log(\r\n 3,\r\n `[browser] Attempting to get a browser instance (try ${++tryCount}).`\r\n );\r\n browser = await puppeteer.launch({\r\n headless: 'new',\r\n args: allArgs,\r\n userDataDir: './tmp/'\r\n });\r\n } catch (error) {\r\n logWithStack(\r\n 1,\r\n error,\r\n '[browser] Failed to launch a browser instance.'\r\n );\r\n\r\n // Retry to launch browser until reaching max attempts\r\n if (tryCount < 25) {\r\n log(3, `[browser] Retry to open a browser (${tryCount} out of 25).`);\r\n await new Promise((response) => setTimeout(response, 4000));\r\n await open();\r\n } else {\r\n throw error;\r\n }\r\n }\r\n };\r\n\r\n try {\r\n await open();\r\n } catch (error) {\r\n throw new ExportError(\r\n '[browser] Maximum retries to open a browser instance reached.'\r\n ).setError(error);\r\n }\r\n\r\n if (!browser) {\r\n throw new ExportError('[browser] Cannot find a browser to open.');\r\n }\r\n }\r\n\r\n // Return a browser promise\r\n return browser;\r\n};\r\n\r\n/**\r\n * Retrieves the existing Puppeteer browser instance.\r\n *\r\n * @returns {Promise} A Promise resolving to the Puppeteer browser\r\n * instance.\r\n *\r\n * @throws {ExportError} Throws an ExportError if no valid browser has been\r\n * created.\r\n */\r\nexport const get = async () => {\r\n if (!browser) {\r\n throw new ExportError('[browser] No valid browser has been created.');\r\n }\r\n\r\n return browser;\r\n};\r\n\r\n/**\r\n * Closes the Puppeteer browser instance if it is connected.\r\n *\r\n * @returns {Promise} A Promise resolving to true after the browser\r\n * is closed.\r\n */\r\nexport const close = async () => {\r\n // Close the browser when connnected\r\n if (browser?.isConnected()) {\r\n await browser.close();\r\n log(4, '[browser] Closed the browser.');\r\n }\r\n return true;\r\n};\r\n\r\nexport default {\r\n newPage,\r\n clearPage,\r\n get,\r\n close\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync } from 'fs';\r\nimport path from 'path';\r\nimport * as url from 'url';\r\n\r\nimport cache from './cache.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport svgTemplate from './../templates/svg_export/svg_export.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\nconst __basedir = url.fileURLToPath(new URL('.', import.meta.url));\r\n\r\n/**\r\n * Retrieves the clipping region coordinates of the specified page element with\r\n * the id 'chart-container'.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} Promise resolving to an object containing\r\n * x, y, width, and height properties.\r\n */\r\nconst getClipRegion = (page) =>\r\n page.$eval('#chart-container', (element) => {\r\n const { x, y, width, height } = element.getBoundingClientRect();\r\n return {\r\n x,\r\n y,\r\n width,\r\n height: Math.trunc(height > 1 ? height : 500)\r\n };\r\n });\r\n\r\n/**\r\n * Creates an image using Puppeteer's page screenshot functionality with\r\n * specified options.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {string} type - Image type.\r\n * @param {string} encoding - Image encoding.\r\n * @param {Object} clip - Clipping region coordinates.\r\n * @param {number} rasterizationTimeout - Timeout for rasterization\r\n * in milliseconds.\r\n *\r\n * @returns {Promise} Promise resolving to the image buffer or rejecting\r\n * with an ExportError for timeout.\r\n */\r\nconst createImage = (page, type, encoding, clip, rasterizationTimeout) =>\r\n Promise.race([\r\n page.screenshot({\r\n type,\r\n encoding,\r\n clip,\r\n\r\n // #447, #463 - always render on a transparent page if the expected type\r\n // format is PNG\r\n omitBackground: type == 'png'\r\n }),\r\n new Promise((_resolve, reject) =>\r\n setTimeout(\r\n () => reject(new ExportError('Rasterization timeout')),\r\n rasterizationTimeout || 1500\r\n )\r\n )\r\n ]);\r\n\r\n/**\r\n * Creates a PDF using Puppeteer's page pdf functionality with specified\r\n * options.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {number} height - PDF height.\r\n * @param {number} width - PDF width.\r\n * @param {string} encoding - PDF encoding.\r\n *\r\n * @returns {Promise} Promise resolving to the PDF buffer.\r\n */\r\nconst createPDF = (page, height, width, encoding) =>\r\n page.pdf({\r\n // This will remove an extra empty page in PDF exports\r\n height: height + 1,\r\n width,\r\n encoding\r\n });\r\n\r\n/**\r\n * Creates an SVG string by evaluating the outerHTML of the first 'svg' element\r\n * inside an element with the id 'container'.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} Promise resolving to the SVG string.\r\n */\r\nconst createSVG = (page) =>\r\n page.$eval('#container svg:first-of-type', (element) => element.outerHTML);\r\n\r\n/**\r\n * Sets the specified chart and options as configuration into the triggerExport\r\n * function within the window context using page.evaluate.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {any} chart - The chart object to be configured.\r\n * @param {Object} options - Configuration options for the chart.\r\n *\r\n * @returns {Promise} Promise resolving after the configuration is set.\r\n */\r\nconst setAsConfig = (page, chart, options) =>\r\n page.evaluate(\r\n // eslint-disable-next-line no-undef\r\n (chart, options) => window.triggerExport(chart, options),\r\n chart,\r\n options\r\n );\r\n\r\n/**\r\n * Exports to a chart from a page using Puppeteer.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {any} chart - The chart object or SVG configuration to be exported.\r\n * @param {Object} options - Export options and configuration.\r\n *\r\n * @returns {Promise} Promise resolving to\r\n * the exported data or rejecting with an ExportError.\r\n */\r\nexport default async (page, chart, options) => {\r\n /**\r\n * Keeps track of all resources added on the page with addXXXTag. etc\r\n * It's VITAL that all added resources ends up here so we can clear things\r\n * out when doing a new export in the same page!\r\n */\r\n const injectedResources = [];\r\n\r\n /** Clear out all state set on the page with addScriptTag/addStyleTag. */\r\n const clearInjected = async (page) => {\r\n for (const res of injectedResources) {\r\n await res.dispose();\r\n }\r\n\r\n // Reset all CSS and script tags\r\n await page.evaluate(() => {\r\n // eslint-disable-next-line no-undef\r\n const [, ...scriptsToRemove] = document.getElementsByTagName('script');\r\n // eslint-disable-next-line no-undef\r\n const [, ...stylesToRemove] = document.getElementsByTagName('style');\r\n // eslint-disable-next-line no-undef\r\n const [...linksToRemove] = document.getElementsByTagName('link');\r\n\r\n // Remove tags\r\n for (const element of [\r\n ...scriptsToRemove,\r\n ...stylesToRemove,\r\n ...linksToRemove\r\n ]) {\r\n element.remove();\r\n }\r\n });\r\n };\r\n\r\n try {\r\n log(4, '[export] Determining export path.');\r\n\r\n const exportOptions = options.export;\r\n\r\n // Force a rAF\r\n // See https://github.com/puppeteer/puppeteer/issues/7507\r\n // eslint-disable-next-line no-undef\r\n await page.evaluate(() => requestAnimationFrame(() => {}));\r\n\r\n // Decide whether display error or debbuger wrapper around it\r\n const displayErrors =\r\n exportOptions?.options?.chart?.displayErrors &&\r\n cache.getCache().activeManifest.modules.debugger;\r\n\r\n // eslint-disable-next-line no-undef\r\n await page.evaluate((d) => (window._displayErrors = d), displayErrors);\r\n\r\n let isSVG;\r\n if (\r\n chart.indexOf &&\r\n (chart.indexOf('= 0 || chart.indexOf('= 0)\r\n ) {\r\n // SVG input handling\r\n log(4, '[export] Treating as SVG.');\r\n\r\n // If input is also SVG, just return it\r\n if (exportOptions.type === 'svg') {\r\n return chart;\r\n }\r\n\r\n isSVG = true;\r\n await page.setContent(svgTemplate(chart));\r\n } else {\r\n // JSON config handling\r\n log(4, '[export] Treating as config.');\r\n\r\n // Need to perform straight inject\r\n if (exportOptions.strInj) {\r\n // Injection based configuration export\r\n await setAsConfig(\r\n page,\r\n {\r\n chart: {\r\n height: exportOptions.height,\r\n width: exportOptions.width\r\n }\r\n },\r\n options\r\n );\r\n } else {\r\n // Basic configuration export\r\n chart.chart.height = exportOptions.height;\r\n chart.chart.width = exportOptions.width;\r\n\r\n await setAsConfig(page, chart, options);\r\n }\r\n }\r\n\r\n // Use resources\r\n const resources = options.customLogic.resources;\r\n if (resources) {\r\n // Load custom JS code\r\n if (resources.js) {\r\n injectedResources.push(\r\n await page.addScriptTag({\r\n content: resources.js\r\n })\r\n );\r\n }\r\n\r\n // Load scripts from all custom files\r\n if (resources.files) {\r\n for (const file of resources.files) {\r\n try {\r\n const isLocal = !file.startsWith('http') ? true : false;\r\n\r\n // Add each custom script from resources' files\r\n injectedResources.push(\r\n await page.addScriptTag(\r\n isLocal\r\n ? {\r\n content: readFileSync(file, 'utf8')\r\n }\r\n : {\r\n url: file\r\n }\r\n )\r\n );\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[export] The JS file ${file} cannot be loaded.`\r\n );\r\n }\r\n }\r\n }\r\n\r\n // Load CSS\r\n if (resources.css) {\r\n let cssImports = resources.css.match(/@import\\s*([^;]*);/g);\r\n if (cssImports) {\r\n // Handle css section\r\n for (let cssImportPath of cssImports) {\r\n if (cssImportPath) {\r\n cssImportPath = cssImportPath\r\n .replace('url(', '')\r\n .replace('@import', '')\r\n .replace(/\"/g, '')\r\n .replace(/'/g, '')\r\n .replace(/;/, '')\r\n .replace(/\\)/g, '')\r\n .trim();\r\n\r\n // Add each custom css from resources\r\n if (cssImportPath.startsWith('http')) {\r\n injectedResources.push(\r\n await page.addStyleTag({\r\n url: cssImportPath\r\n })\r\n );\r\n } else if (options.customLogic.allowFileResources) {\r\n injectedResources.push(\r\n await page.addStyleTag({\r\n path: path.join(__basedir, cssImportPath)\r\n })\r\n );\r\n }\r\n }\r\n }\r\n }\r\n\r\n // The rest of the CSS section will be content by now\r\n injectedResources.push(\r\n await page.addStyleTag({\r\n content: resources.css.replace(/@import\\s*([^;]*);/g, '') || ' '\r\n })\r\n );\r\n }\r\n }\r\n\r\n // Get the real chart size\r\n const size = isSVG\r\n ? await page.$eval(\r\n '#chart-container svg:first-of-type',\r\n (element, scale) => ({\r\n chartHeight: element.height.baseVal.value * scale,\r\n chartWidth: element.width.baseVal.value * scale\r\n }),\r\n parseFloat(exportOptions.scale)\r\n )\r\n : await page.evaluate(() => {\r\n // eslint-disable-next-line no-undef\r\n const { chartHeight, chartWidth } = window.Highcharts.charts[0];\r\n return {\r\n chartHeight,\r\n chartWidth\r\n };\r\n });\r\n\r\n // Set final height and width for viewport\r\n const viewportHeight = Math.ceil(size?.chartHeight || exportOptions.height);\r\n const viewportWidth = Math.ceil(size?.chartWidth || exportOptions.width);\r\n\r\n // Set the viewport for the first time\r\n // NOTE: the call to setViewport is expensive - can we get away with only\r\n // calling it once, e.g. moving this one into the isSVG condition below?\r\n await page.setViewport({\r\n height: viewportHeight,\r\n width: viewportWidth,\r\n deviceScaleFactor: isSVG ? 1 : parseFloat(exportOptions.scale)\r\n });\r\n\r\n // Prepare a zoom callback for the next evaluate call\r\n const zoomCallback = isSVG\r\n ? // In case of SVG the zoom must be set directly for body\r\n (scale) => {\r\n // Set the zoom as scale\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = scale;\r\n\r\n // Set the margin to 0px\r\n // eslint-disable-next-line no-undef\r\n document.body.style.margin = '0px';\r\n }\r\n : // No need for such scale manipulation in case of other types of exports\r\n () => {\r\n // Reset the zoom for other exports than to SVGs\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = 1;\r\n };\r\n\r\n // Set the zoom accordingly\r\n await page.evaluate(zoomCallback, parseFloat(exportOptions.scale));\r\n\r\n // Get the clip region for the page\r\n const { height, width, x, y } = await getClipRegion(page);\r\n\r\n if (!isSVG) {\r\n // Set the final viewport now that we have the real height\r\n await page.setViewport({\r\n width: Math.round(width),\r\n height: Math.round(height),\r\n deviceScaleFactor: parseFloat(exportOptions.scale)\r\n });\r\n }\r\n\r\n let data;\r\n // RASTERIZATION\r\n if (exportOptions.type === 'svg') {\r\n // SVG\r\n data = await createSVG(page);\r\n } else if (['png', 'jpeg'].includes(exportOptions.type)) {\r\n // PNG or JPEG\r\n data = await createImage(\r\n page,\r\n exportOptions.type,\r\n 'base64',\r\n {\r\n width: viewportWidth,\r\n height: viewportHeight,\r\n x,\r\n y\r\n },\r\n exportOptions.rasterizationTimeout\r\n );\r\n } else if (exportOptions.type === 'pdf') {\r\n // PDF\r\n data = await createPDF(page, viewportHeight, viewportWidth, 'base64');\r\n } else {\r\n throw new ExportError(\r\n `[export] Unsupported output format ${exportOptions.type}.`\r\n );\r\n }\r\n\r\n // Destroy old charts after the export is done\r\n await page.evaluate(() => {\r\n // We are not guaranteed that Highcharts is loaded, e,g, when doing SVG\r\n // exports\r\n if (typeof Highcharts !== 'undefined') {\r\n // eslint-disable-next-line no-undef\r\n const oldCharts = Highcharts.charts;\r\n\r\n // Check in any already existing charts\r\n if (Array.isArray(oldCharts) && oldCharts.length) {\r\n // Destroy old charts\r\n for (const oldChart of oldCharts) {\r\n oldChart && oldChart.destroy();\r\n // eslint-disable-next-line no-undef\r\n Highcharts.charts.shift();\r\n }\r\n }\r\n }\r\n });\r\n\r\n await clearInjected(page);\r\n return data;\r\n } catch (error) {\r\n await clearInjected(page);\r\n return error;\r\n }\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport cssTemplate from './css.js';\r\n\r\nexport default (chart) => `\r\n\r\n\r\n \r\n \r\n Highcarts Export\r\n \r\n \r\n \r\n
\r\n ${chart}\r\n
\r\n \r\n\r\n\r\n`;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { Pool } from 'tarn';\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport {\r\n close as browserClose,\r\n create as createBrowser,\r\n newPage as browserNewPage,\r\n clearPage\r\n} from './browser.js';\r\nimport puppeteerExport from './export.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { measureTime } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\nlet performedExports = 0;\r\nlet exportAttempts = 0;\r\nlet timeSpent = 0;\r\nlet droppedExports = 0;\r\nlet spentAverage = 0;\r\nlet poolConfig = {};\r\n\r\n// The pool instance\r\nlet pool = false;\r\n\r\n// Custom puppeteer arguments\r\nlet puppeteerArgs;\r\n\r\nconst factory = {\r\n /**\r\n * Creates a new worker page for the export pool.\r\n *\r\n * @returns {Object} - An object containing the worker ID, a reference to the\r\n * browser page, and initial work count.\r\n *\r\n * @throws {ExportError} - If there's an error during the creation of the new\r\n * page.\r\n */\r\n create: async () => {\r\n let page = false;\r\n\r\n const id = uuid();\r\n const startDate = new Date().getTime();\r\n\r\n try {\r\n page = await browserNewPage();\r\n\r\n if (!page || page.isClosed()) {\r\n throw new ExportError('The page is invalid or closed.');\r\n }\r\n\r\n log(\r\n 3,\r\n `[pool] Successfully created a worker ${id} - took ${\r\n new Date().getTime() - startDate\r\n } ms.`\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n 'Error encountered when creating a new page.'\r\n ).setError(error);\r\n }\r\n\r\n return {\r\n id,\r\n page,\r\n // Try to distribute the initial work count\r\n workCount: Math.round(Math.random() * (poolConfig.workLimit / 2))\r\n };\r\n },\r\n\r\n /**\r\n * Validates a worker page in the export pool, checking if it has exceeded\r\n * the work limit.\r\n *\r\n * @param {Object} workerHandle - The handle to the worker, containing the\r\n * worker's ID, a reference to the browser page, and work count.\r\n *\r\n * @returns {boolean} - Returns true if the worker is valid and within\r\n * the work limit; otherwise, returns false.\r\n */\r\n validate: async (workerHandle) => {\r\n if (\r\n poolConfig.workLimit &&\r\n ++workerHandle.workCount > poolConfig.workLimit\r\n ) {\r\n log(\r\n 3,\r\n `[pool] Worker failed validation: exceeded work limit (limit is ${poolConfig.workLimit}).`\r\n );\r\n return false;\r\n }\r\n\r\n // Clear page\r\n await clearPage(workerHandle.page, true);\r\n return true;\r\n },\r\n\r\n /**\r\n * Destroys a worker entry in the export pool, closing its associated page.\r\n *\r\n * @param {Object} workerHandle - The handle to the worker, containing\r\n * the worker's ID and a reference to the browser page.\r\n */\r\n destroy: (workerHandle) => {\r\n log(3, `[pool] Destroying pool entry ${workerHandle.id}.`);\r\n\r\n if (workerHandle.page) {\r\n // We don't really need to wait around for this.\r\n workerHandle.page.close();\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Initializes the export pool with the provided configuration, creating\r\n * a browser instance and setting up worker resources.\r\n *\r\n * @param {Object} config - Configuration options for the export pool along\r\n * with custom puppeteer arguments for the puppeteer.launch function.\r\n */\r\nexport const initPool = async (config) => {\r\n // For the module scope usage\r\n poolConfig = config && config.pool ? { ...config.pool } : {};\r\n\r\n // Attach process' exit listeners\r\n if (poolConfig.listenToProcessExits) {\r\n attachProcessExitListeners();\r\n }\r\n\r\n // The newest puppeteer arguments for the browser creation\r\n puppeteerArgs = config.puppeteerArgs;\r\n\r\n // Create a browser instance\r\n await createBrowser(puppeteerArgs);\r\n\r\n log(\r\n 3,\r\n `[pool] Initializing pool with workers: min ${poolConfig.minWorkers}, max ${poolConfig.maxWorkers}.`\r\n );\r\n\r\n if (pool) {\r\n return log(\r\n 4,\r\n '[pool] Already initialized, please kill it before creating a new one.'\r\n );\r\n }\r\n\r\n if (parseInt(poolConfig.minWorkers) > parseInt(poolConfig.maxWorkers)) {\r\n poolConfig.minWorkers = poolConfig.maxWorkers;\r\n }\r\n\r\n try {\r\n // Create a pool along with a minimal number of resources\r\n pool = new Pool({\r\n // Get the create/validate/destroy/log functions\r\n ...factory,\r\n min: parseInt(poolConfig.minWorkers),\r\n max: parseInt(poolConfig.maxWorkers),\r\n acquireTimeoutMillis: poolConfig.acquireTimeout,\r\n createTimeoutMillis: poolConfig.createTimeout,\r\n destroyTimeoutMillis: poolConfig.destroyTimeout,\r\n idleTimeoutMillis: poolConfig.idleTimeout,\r\n createRetryIntervalMillis: poolConfig.createRetryInterval,\r\n reapIntervalMillis: poolConfig.reaperInterval,\r\n propagateCreateError: false\r\n });\r\n\r\n // Set events\r\n pool.on('release', async (resource) => {\r\n // Clear page\r\n await clearPage(resource.page, false);\r\n log(4, `[pool] Releasing a worker with ID ${resource.id}.`);\r\n });\r\n\r\n pool.on('destroySuccess', (eventId, resource) => {\r\n log(4, `[pool] Destroyed a worker with ID ${resource.id}.`);\r\n });\r\n\r\n const initialResources = [];\r\n // Create an initial number of resources\r\n for (let i = 0; i < poolConfig.minWorkers; i++) {\r\n try {\r\n const resource = await pool.acquire().promise;\r\n initialResources.push(resource);\r\n } catch (error) {\r\n logWithStack(2, error, '[pool] Could not create an initial resource.');\r\n }\r\n }\r\n\r\n // Release the initial number of resources back to the pool\r\n initialResources.forEach((resource) => {\r\n pool.release(resource);\r\n });\r\n\r\n log(\r\n 3,\r\n `[pool] The pool is ready${initialResources.length ? ` with ${initialResources.length} initial resources waiting.` : '.'}`\r\n );\r\n } catch (error) {\r\n // Close browser if for some reason cannot establish the pool\r\n await browserClose();\r\n throw new ExportError(\r\n '[pool] Could not create the pool of workers.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Attaches exit listeners to the process, ensuring proper cleanup of resources\r\n * and termination on exit signals. Handles 'exit', 'SIGINT', 'SIGTERM', and\r\n * 'uncaughtException' events.\r\n */\r\nexport function attachProcessExitListeners() {\r\n log(3, '[pool] Attaching exit listeners to the process.');\r\n\r\n // Kill all pool resources on exit\r\n process.on('exit', async (code) => {\r\n log(4, `Process exited with code ${code}.`);\r\n await killPool();\r\n });\r\n\r\n // Handler for the SIGINT\r\n process.on('SIGINT', (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n process.exit(1);\r\n });\r\n\r\n // Handler for the SIGTERM\r\n process.on('SIGTERM', (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n process.exit(1);\r\n });\r\n\r\n // Handler for the uncaughtException\r\n process.on('uncaughtException', async (error, name) => {\r\n logWithStack(1, error, `The ${name} error.`);\r\n await killPool();\r\n process.exit(1);\r\n });\r\n}\r\n\r\n/**\r\n * Kills all workers in the pool, destroys the pool, and closes the browser\r\n * instance.\r\n *\r\n * @returns {Promise} A promise that resolves after the workers are\r\n * killed, the pool is destroyed, and the browser is closed.\r\n */\r\nexport async function killPool() {\r\n log(3, '[pool] Killing all pool workers and browser, if any exist.');\r\n\r\n // Return true when the pool is already destroyed\r\n if (pool?.destroyed) {\r\n // Close the browser instance if still connected\r\n return browserClose();\r\n }\r\n\r\n // If still alive, destroy the pool of pages before closing a browser\r\n if (pool) {\r\n await pool.destroy();\r\n log(4, '[browser] Destroyed the pool of resources.');\r\n }\r\n\r\n // Close the browser instance\r\n return browserClose();\r\n}\r\n\r\n/**\r\n * Processes the export work using a worker from the pool. Acquires a worker\r\n * handle from the pool, performs the export using puppeteer, and releases\r\n * the worker handle back to the pool.\r\n *\r\n * @param {string} chart - The chart data or configuration to be exported.\r\n * @param {Object} options - Export options and configuration.\r\n *\r\n * @returns {Promise} A promise that resolves with the export resultand\r\n * options.\r\n *\r\n * @throws {ExportError} If an error occurs during the export process.\r\n */\r\nexport const postWork = async (chart, options) => {\r\n let workerHandle;\r\n\r\n try {\r\n log(4, '[pool] Work received, starting to process.');\r\n\r\n ++exportAttempts;\r\n if (poolConfig.benchmarking) {\r\n getPoolInfo();\r\n }\r\n\r\n if (!pool) {\r\n throw new ExportError('Work received, but pool has not been started.');\r\n }\r\n\r\n // Acquire the worker along with the id of resource and work count\r\n try {\r\n log(4, '[pool] Acquiring a worker handle.');\r\n const acquireCounter = measureTime();\r\n workerHandle = await pool.acquire().promise;\r\n\r\n // Check the page acquire time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n options.payload?.requestId\r\n ? `[benchmark] Request with ID ${options.payload?.requestId} -`\r\n : '[benchmark]',\r\n `Acquired a worker handle: ${acquireCounter()}ms.`\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n 'Error encountered when acquiring an available entry.'\r\n ).setError(error);\r\n }\r\n log(4, '[pool] Acquired a worker handle.');\r\n\r\n if (!workerHandle.page) {\r\n throw new ExportError(\r\n 'Resolved worker page is invalid: the pool setup is wonky.'\r\n );\r\n }\r\n\r\n // Save the start time\r\n let workStart = new Date().getTime();\r\n\r\n log(4, `[pool] Starting work on pool entry with ID ${workerHandle.id}.`);\r\n\r\n // Perform an export on a puppeteer level\r\n const exportCounter = measureTime();\r\n const result = await puppeteerExport(workerHandle.page, chart, options);\r\n\r\n // Check if it's an error\r\n if (result instanceof Error) {\r\n // TODO: If the export failed because puppeteer timed out, we need to force kill the worker so we get a new page. That needs to be handled better than this hack.\r\n if (result.message === 'Rasterization timeout') {\r\n workerHandle.page.close();\r\n workerHandle.page = await browserNewPage();\r\n }\r\n\r\n throw new ExportError('Error encountered during export.').setError(\r\n result\r\n );\r\n }\r\n\r\n // Check the Puppeteer export time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n options.payload?.requestId\r\n ? `[benchmark] Request with ID ${options.payload?.requestId} -`\r\n : '[benchmark]',\r\n `Exported a chart sucessfully: ${exportCounter()}ms.`\r\n );\r\n }\r\n\r\n // Release the resource back to the pool\r\n pool.release(workerHandle);\r\n\r\n // Used for statistics in averageTime and processedWorkCount, which\r\n // in turn is used by the /health route.\r\n const workEnd = new Date().getTime();\r\n const exportTime = workEnd - workStart;\r\n timeSpent += exportTime;\r\n spentAverage = timeSpent / ++performedExports;\r\n\r\n log(4, `[pool] Work completed in ${exportTime} ms.`);\r\n\r\n // Otherwise return the result\r\n return {\r\n result,\r\n options\r\n };\r\n } catch (error) {\r\n ++droppedExports;\r\n\r\n if (workerHandle) {\r\n pool.release(workerHandle);\r\n }\r\n\r\n throw new ExportError(`[pool] In pool.postWork: ${error.message}`).setError(\r\n error\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Retrieves the current pool instance.\r\n *\r\n * @returns {Object|null} The current pool instance if initialized, or null\r\n * if the pool has not been created.\r\n */\r\nexport function getPool() {\r\n return pool;\r\n}\r\n\r\n/**\r\n * Retrieves pool information in JSON format, including minimum and maximum\r\n * workers, available workers, workers in use, and pending acquire requests.\r\n *\r\n * @returns {Object} Pool information in JSON format.\r\n */\r\nexport const getPoolInfoJSON = () => ({\r\n min: pool.min,\r\n max: pool.max,\r\n available: pool.numFree(),\r\n inUse: pool.numUsed(),\r\n pendingAcquire: pool.numPendingAcquires()\r\n});\r\n\r\n/**\r\n * Logs information about the current state of the pool, including the minimum\r\n * and maximum workers, available workers, workers in use, and pending acquire\r\n * requests.\r\n */\r\nexport function getPoolInfo() {\r\n const { min, max } = pool;\r\n\r\n log(5, `[pool] The minimum number of resources allowed by pool: ${min}.`);\r\n log(5, `[pool] The maximum number of resources allowed by pool: ${max}.`);\r\n log(\r\n 5,\r\n `[pool] The number of resources that are currently available: ${pool.numFree()}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources that are currently acquired: ${pool.numUsed()}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of callers waiting to acquire a resource: ${pool.numPendingAcquires()}.`\r\n );\r\n}\r\n\r\nexport default {\r\n initPool,\r\n killPool,\r\n postWork,\r\n getPool,\r\n getPoolInfo,\r\n getPoolInfoJSON,\r\n workAttempts: () => exportAttempts,\r\n droppedWork: () => droppedExports,\r\n averageTime: () => spentAverage,\r\n processedWorkCount: () => performedExports\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync, writeFileSync } from 'fs';\r\n\r\nimport { getOptions, initExportSettings } from './config.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { killPool, postWork } from './pool.js';\r\nimport {\r\n fixType,\r\n handleResources,\r\n isCorrectJSON,\r\n optionsStringify,\r\n roundNumber,\r\n toBoolean,\r\n wrapAround\r\n} from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\nlet allowCodeExecution = false;\r\n\r\n/**\r\n * Starts an export process. The `settings` contains final options gathered\r\n * from all possible sources (config, env, cli, json). The `endCallback` is\r\n * called when the export is completed, with an error object as the first\r\n * argument and the second containing the base64 respresentation of a chart.\r\n *\r\n * @param {Object} settings - The settings object containing export\r\n * configuration.\r\n * @param {function} endCallback - The callback function to be invoked upon\r\n * finalizing work or upon error occurance of the exporting process.\r\n *\r\n * @returns {void} This function does not return a value directly; instead,\r\n * it communicates results via the endCallback.\r\n */\r\nexport const startExport = async (settings, endCallback) => {\r\n // Starting exporting process message\r\n log(4, '[chart] Starting the exporting process.');\r\n\r\n // Initialize options\r\n const options = initExportSettings(settings, getOptions());\r\n\r\n // Get the export options\r\n const exportOptions = options.export;\r\n\r\n // If SVG is an input (argument can be sent only by the request)\r\n if (options.payload?.svg && options.payload.svg !== '') {\r\n try {\r\n log(4, '[chart] Attempting to export from a SVG input.');\r\n return exportAsString(options.payload.svg.trim(), options, endCallback);\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError('[chart] Error loading SVG input.').setError(error)\r\n );\r\n }\r\n }\r\n\r\n // Export using options from the file\r\n if (exportOptions.infile && exportOptions.infile.length) {\r\n // Try to read the file to get the string representation\r\n try {\r\n log(4, '[chart] Attempting to export from an input file.');\r\n options.export.instr = readFileSync(exportOptions.infile, 'utf8');\r\n return exportAsString(options.export.instr.trim(), options, endCallback);\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError('[chart] Error loading input file.').setError(error)\r\n );\r\n }\r\n }\r\n\r\n // Export with options from the raw representation\r\n if (\r\n (exportOptions.instr && exportOptions.instr !== '') ||\r\n (exportOptions.options && exportOptions.options !== '')\r\n ) {\r\n try {\r\n log(4, '[chart] Attempting to export from a raw input.');\r\n\r\n // Perform a direct inject when forced\r\n if (toBoolean(options.customLogic?.allowCodeExecution)) {\r\n return doStraightInject(options, endCallback);\r\n }\r\n\r\n // Either try to parse to JSON first or do the direct export\r\n return typeof exportOptions.instr === 'string'\r\n ? exportAsString(exportOptions.instr.trim(), options, endCallback)\r\n : doExport(\r\n options,\r\n exportOptions.instr || exportOptions.options,\r\n endCallback\r\n );\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError('[chart] Error loading raw input.').setError(error)\r\n );\r\n }\r\n }\r\n\r\n // No input specified, pass an error message to the callback\r\n return endCallback(\r\n new ExportError(\r\n `[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.`\r\n )\r\n );\r\n};\r\n\r\n/**\r\n * Starts a batch export process for multiple charts based on the information\r\n * in the batch option. The batch is a string in the following format:\r\n * \"infile1.json=outfile1.png;infile2.json=outfile2.png;...\"\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * a batch export.\r\n *\r\n * @returns {Promise} A Promise that resolves once the batch export\r\n * process is completed.\r\n *\r\n * @throws {ExportError} Throws an ExportError if an error occurs during\r\n * any of the batch export process.\r\n */\r\nexport const batchExport = async (options) => {\r\n const batchFunctions = [];\r\n\r\n // Split and pair the --batch arguments\r\n for (let pair of options.export.batch.split(';')) {\r\n pair = pair.split('=');\r\n if (pair.length === 2) {\r\n batchFunctions.push(\r\n startExport(\r\n {\r\n ...options,\r\n export: {\r\n ...options.export,\r\n infile: pair[0],\r\n outfile: pair[1]\r\n }\r\n },\r\n (error, info) => {\r\n // Throw an error\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // Save the base64 from a buffer to a correct image file\r\n writeFileSync(\r\n info.options.export.outfile,\r\n Buffer.from(info.result, 'base64')\r\n );\r\n }\r\n )\r\n );\r\n }\r\n }\r\n\r\n try {\r\n // Await all exports are done\r\n await Promise.all(batchFunctions);\r\n\r\n // Kill pool and close browser after finishing batch export\r\n await killPool();\r\n } catch (error) {\r\n throw new ExportError(\r\n '[chart] Error encountered during batch export.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Starts a single export process based on the specified options.\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * a single export.\r\n *\r\n * @returns {Promise} A Promise that resolves once the single export\r\n * process is completed.\r\n *\r\n * @throws {ExportError} Throws an ExportError if an error occurs during\r\n * the single export process.\r\n */\r\nexport const singleExport = async (options) => {\r\n // Use instr or its alias, options\r\n options.export.instr = options.export.instr || options.export.options;\r\n\r\n // Perform an export\r\n await startExport(options, async (error, info) => {\r\n // Exit process when error\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n const { outfile, type } = info.options.export;\r\n\r\n // Save the base64 from a buffer to a correct image file\r\n writeFileSync(\r\n outfile || `chart.${type}`,\r\n type !== 'svg' ? Buffer.from(info.result, 'base64') : info.result\r\n );\r\n\r\n // Kill the pool\r\n await killPool();\r\n });\r\n};\r\n\r\n/**\r\n * Determines the size and scale for chart export based on the provided options.\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * chart export.\r\n *\r\n * @returns {Object} An object containing the calculated height, width,\r\n * and scale for the chart export.\r\n */\r\nexport const findChartSize = (options) => {\r\n const { chart, exporting } =\r\n options.export?.options || isCorrectJSON(options.export?.instr);\r\n\r\n // See if globalOptions holds chart or exporting size\r\n const globalOptions = isCorrectJSON(options.export?.globalOptions);\r\n\r\n // Secure scale value\r\n let scale =\r\n options.export?.scale ||\r\n exporting?.scale ||\r\n globalOptions?.exporting?.scale ||\r\n options.export?.defaultScale ||\r\n 1;\r\n\r\n // the scale cannot be lower than 0.1 and cannot be higher than 5.0\r\n scale = Math.max(0.1, Math.min(scale, 5.0));\r\n\r\n // we want to round the numbers like 0.23234 -> 0.23\r\n scale = roundNumber(scale, 2);\r\n\r\n // Find chart size and scale\r\n const size = {\r\n height:\r\n options.export?.height ||\r\n exporting?.sourceHeight ||\r\n chart?.height ||\r\n globalOptions?.exporting?.sourceHeight ||\r\n globalOptions?.chart?.height ||\r\n options.export?.defaultHeight ||\r\n 400,\r\n width:\r\n options.export?.width ||\r\n exporting?.sourceWidth ||\r\n chart?.width ||\r\n globalOptions?.exporting?.sourceWidth ||\r\n globalOptions?.chart?.width ||\r\n options.export?.defaultWidth ||\r\n 600,\r\n scale\r\n };\r\n\r\n // Get rid of potential px and %\r\n for (let [param, value] of Object.entries(size)) {\r\n size[param] =\r\n typeof value === 'string' ? +value.replace(/px|%/gi, '') : value;\r\n }\r\n return size;\r\n};\r\n\r\n/**\r\n * Function for finalizing options before export.\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * the export process.\r\n * @param {Object} chartJson - The JSON representation of the chart.\r\n * @param {Function} endCallback - The callback function to be called upon\r\n * completion or error.\r\n * @param {string} svg - The SVG representation of the chart.\r\n *\r\n * @returns {Promise} A Promise that resolves once the export process\r\n * is completed.\r\n */\r\nconst doExport = async (options, chartJson, endCallback, svg) => {\r\n let { export: exportOptions, customLogic: customLogicOptions } = options;\r\n\r\n const allowCodeExecutionScoped =\r\n typeof customLogicOptions.allowCodeExecution === 'boolean'\r\n ? customLogicOptions.allowCodeExecution\r\n : allowCodeExecution;\r\n\r\n if (!customLogicOptions) {\r\n customLogicOptions = options.customLogic = {};\r\n } else if (allowCodeExecutionScoped) {\r\n if (typeof options.customLogic.resources === 'string') {\r\n // Process resources\r\n options.customLogic.resources = handleResources(\r\n options.customLogic.resources,\r\n toBoolean(options.customLogic.allowFileResources)\r\n );\r\n } else if (!options.customLogic.resources) {\r\n try {\r\n const resources = readFileSync('resources.json', 'utf8');\r\n options.customLogic.resources = handleResources(\r\n resources,\r\n toBoolean(options.customLogic.allowFileResources)\r\n );\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[chart] Unable to load the default resources.json file.`\r\n );\r\n }\r\n }\r\n }\r\n\r\n // If the allowCodeExecution flag isn't set, we should refuse the usage\r\n // of callback, resources, and custom code. Additionally, the worker will\r\n // refuse to run arbitrary JavaScript. Prioritized should be the scoped\r\n // option, then we should take a look at the overall pool option.\r\n if (!allowCodeExecutionScoped && customLogicOptions) {\r\n if (\r\n customLogicOptions.callback ||\r\n customLogicOptions.resources ||\r\n customLogicOptions.customCode\r\n ) {\r\n // Send back a friendly message saying that the exporter does not support\r\n // these settings.\r\n return endCallback(\r\n new ExportError(\r\n `[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server.`\r\n )\r\n );\r\n }\r\n\r\n // Reset all additional custom code\r\n customLogicOptions.callback = false;\r\n customLogicOptions.resources = false;\r\n customLogicOptions.customCode = false;\r\n }\r\n\r\n // Clean properties to keep it lean and mean\r\n if (chartJson) {\r\n chartJson.chart = chartJson.chart || {};\r\n chartJson.exporting = chartJson.exporting || {};\r\n chartJson.exporting.enabled = false;\r\n }\r\n\r\n exportOptions.constr = exportOptions.constr || 'chart';\r\n exportOptions.type = fixType(exportOptions.type, exportOptions.outfile);\r\n if (exportOptions.type === 'svg') {\r\n exportOptions.width = false;\r\n }\r\n\r\n // Prepare global and theme options\r\n ['globalOptions', 'themeOptions'].forEach((optionsName) => {\r\n try {\r\n if (exportOptions && exportOptions[optionsName]) {\r\n if (\r\n typeof exportOptions[optionsName] === 'string' &&\r\n exportOptions[optionsName].endsWith('.json')\r\n ) {\r\n exportOptions[optionsName] = isCorrectJSON(\r\n readFileSync(exportOptions[optionsName], 'utf8'),\r\n true\r\n );\r\n } else {\r\n exportOptions[optionsName] = isCorrectJSON(\r\n exportOptions[optionsName],\r\n true\r\n );\r\n }\r\n }\r\n } catch (error) {\r\n exportOptions[optionsName] = {};\r\n logWithStack(2, error, `[chart] The '${optionsName}' cannot be loaded.`);\r\n }\r\n });\r\n\r\n // Prepare the customCode\r\n if (customLogicOptions.allowCodeExecution) {\r\n try {\r\n customLogicOptions.customCode = wrapAround(\r\n customLogicOptions.customCode,\r\n customLogicOptions.allowFileResources\r\n );\r\n } catch (error) {\r\n logWithStack(2, error, `[chart] The 'customCode' cannot be loaded.`);\r\n }\r\n }\r\n\r\n // Get the callback\r\n if (\r\n customLogicOptions &&\r\n customLogicOptions.callback &&\r\n customLogicOptions.callback?.indexOf('{') < 0\r\n ) {\r\n // The allowFileResources is always set to false for HTTP requests to avoid\r\n // injecting arbitrary files from the fs\r\n if (customLogicOptions.allowFileResources) {\r\n try {\r\n customLogicOptions.callback = readFileSync(\r\n customLogicOptions.callback,\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n customLogicOptions.callback = false;\r\n logWithStack(2, error, `[chart] The 'callback' cannot be loaded.`);\r\n }\r\n } else {\r\n customLogicOptions.callback = false;\r\n }\r\n }\r\n\r\n // Size search\r\n options.export = {\r\n ...options.export,\r\n ...findChartSize(options)\r\n };\r\n\r\n // Post the work to the pool\r\n try {\r\n const result = await postWork(\r\n exportOptions.strInj || chartJson || svg,\r\n options\r\n );\r\n return endCallback(false, result);\r\n } catch (error) {\r\n return endCallback(error);\r\n }\r\n};\r\n\r\n/**\r\n * Performs a direct inject of options before export. The function attempts\r\n * to stringify the provided options and removes unnecessary characters,\r\n * ensuring a clean and formatted input. The resulting string is saved as\r\n * a \"stright inject\" string in the export options. It then invokes the\r\n * doExport function with the updated options.\r\n *\r\n * IMPORTANT: Dangerous and must be used deliberately by someone who sets up\r\n * a server (see the --allowCodeExecution option).\r\n *\r\n * @param {Object} options - The export options containing the input\r\n * to be injected.\r\n * @param {function} endCallback - The callback function to be invoked\r\n * at the end of the process.\r\n *\r\n * @returns {Promise} A Promise that resolves with the result of the export\r\n * operation or rejects with an error if any issues occur during the process.\r\n */\r\nconst doStraightInject = (options, endCallback) => {\r\n try {\r\n let strInj;\r\n let instr = options.export.instr || options.export.options;\r\n\r\n if (typeof instr !== 'string') {\r\n // Try to stringify options\r\n strInj = instr = optionsStringify(\r\n instr,\r\n options.customLogic?.allowCodeExecution\r\n );\r\n }\r\n strInj = instr.replaceAll(/\\t|\\n|\\r/g, '').trim();\r\n\r\n // Get rid of the ;\r\n if (strInj[strInj.length - 1] === ';') {\r\n strInj = strInj.substring(0, strInj.length - 1);\r\n }\r\n\r\n // Save as stright inject string\r\n options.export.strInj = strInj;\r\n return doExport(options, false, endCallback);\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError(\r\n `[chart] Malformed input detected for ${options.export?.requestId || '?'}. Please make sure that your JSON/JavaScript options are sent using the \"options\" attribute, and that if you're using SVG, it is unescaped.`\r\n ).setError(error)\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Exports a string based on the provided options and invokes an end callback.\r\n *\r\n * @param {string} stringToExport - The string content to be exported.\r\n * @param {Object} options - Export options, including customLogic with\r\n * allowCodeExecution flag.\r\n * @param {Function} endCallback - Callback function to be invoked at the end\r\n * of the export process.\r\n *\r\n * @returns {any} Result of the export process or an error if encountered.\r\n */\r\nconst exportAsString = (stringToExport, options, endCallback) => {\r\n const { allowCodeExecution } = options.customLogic;\r\n\r\n // Check if it is SVG\r\n if (\r\n stringToExport.indexOf('= 0 ||\r\n stringToExport.indexOf('= 0\r\n ) {\r\n log(4, '[chart] Parsing input as SVG.');\r\n return doExport(options, false, endCallback, stringToExport);\r\n }\r\n\r\n try {\r\n // Try to parse to JSON and call the doExport function\r\n const chartJSON = JSON.parse(stringToExport.replaceAll(/\\t|\\n|\\r/g, ' '));\r\n\r\n // If a correct JSON, do the export\r\n return doExport(options, chartJSON, endCallback);\r\n } catch (error) {\r\n // Not a valid JSON\r\n if (toBoolean(allowCodeExecution)) {\r\n return doStraightInject(options, endCallback);\r\n } else {\r\n // Do not allow straight injection without the allowCodeExecution flag\r\n return endCallback(\r\n new ExportError(\r\n '[chart] Only JSON configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the --allowCodeExecution flag.'\r\n ).setError(error)\r\n );\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Retrieves and returns the current status of code execution permission.\r\n *\r\n * @returns {any} The value of allowCodeExecution.\r\n */\r\nexport const getAllowCodeExecution = () => allowCodeExecution;\r\n\r\n/**\r\n * Sets the code execution permission based on the provided boolean value.\r\n *\r\n * @param {any} value - The value to be converted and assigned\r\n * to allowCodeExecution.\r\n */\r\nexport const setAllowCodeExecution = (value) => {\r\n allowCodeExecution = toBoolean(value);\r\n};\r\n\r\nexport default {\r\n batchExport,\r\n singleExport,\r\n getAllowCodeExecution,\r\n setAllowCodeExecution,\r\n startExport,\r\n findChartSize\r\n};\r\n","import { logWithStack } from '../logger.js';\r\nimport { envs } from '../envs.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.NODE_ENV !== 'development') {\r\n delete error.stack;\r\n }\r\n\r\n // Call the returnErrorMiddleware\r\n next(error);\r\n};\r\n\r\n/**\r\n * Middleware for returning error response.\r\n *\r\n * @param {Error} error - The error object.\r\n * @param {Express.Request} req - The Express request object.\r\n * @param {Express.Response} res - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n */\r\nconst returnErrorMiddleware = (error, req, res, next) => {\r\n // Gather all requied information for the response\r\n const { statusCode: stCode, status, message, stack } = error;\r\n const statusCode = stCode || status || 500;\r\n\r\n // Set and return response\r\n res.status(statusCode).json({ statusCode, message, stack });\r\n};\r\n\r\nexport default (app) => {\r\n // Add log error middleware\r\n app.use(logErrorMiddleware);\r\n\r\n // Add set status and return error middleware\r\n app.use(returnErrorMiddleware);\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport rateLimit from 'express-rate-limit';\r\n\r\nimport { log } from '../logger.js';\r\n\r\n/**\r\n * Middleware for enabling rate limiting on the specified Express app.\r\n *\r\n * @param {Express} app - The Express app instance.\r\n * @param {Object} limitConfig - Configuration options for rate limiting.\r\n */\r\nexport default (app, limitConfig) => {\r\n const msg =\r\n 'Too many requests, you have been rate limited. Please try again later.';\r\n\r\n // Options for the rate limiter\r\n const rateOptions = {\r\n max: limitConfig.maxRequests || 30,\r\n window: limitConfig.window || 1,\r\n delay: limitConfig.delay || 0,\r\n trustProxy: limitConfig.trustProxy || false,\r\n skipKey: limitConfig.skipKey || false,\r\n skipToken: limitConfig.skipToken || false\r\n };\r\n\r\n // Set if behind a proxy\r\n if (rateOptions.trustProxy) {\r\n app.enable('trust proxy');\r\n }\r\n\r\n // Create a limiter\r\n const limiter = rateLimit({\r\n windowMs: rateOptions.window * 60 * 1000,\r\n // Limit each IP to 100 requests per windowMs\r\n max: rateOptions.max,\r\n // Disable delaying, full speed until the max limit is reached\r\n delayMs: rateOptions.delay,\r\n handler: (request, response) => {\r\n response.format({\r\n json: () => {\r\n response.status(429).send({ message: msg });\r\n },\r\n default: () => {\r\n response.status(429).send(msg);\r\n }\r\n });\r\n },\r\n skip: (request) => {\r\n // Allow bypassing the limiter if a valid key/token has been sent\r\n if (\r\n rateOptions.skipKey !== false &&\r\n rateOptions.skipToken !== false &&\r\n request.query.key === rateOptions.skipKey &&\r\n request.query.access_token === rateOptions.skipToken\r\n ) {\r\n log(4, '[rate limiting] Skipping rate limiter.');\r\n return true;\r\n }\r\n return false;\r\n }\r\n });\r\n\r\n // Use a limiter as a middleware\r\n app.use(limiter);\r\n\r\n log(\r\n 3,\r\n `[rate limiting] Enabled rate limiting with ${rateOptions.max} requests per ${rateOptions.window} minute for each IP, trusting proxy: ${rateOptions.trustProxy}.`\r\n );\r\n};\r\n","import ExportError from './ExportError.js';\r\n\r\nclass HttpError extends ExportError {\r\n constructor(message, status) {\r\n super(message);\r\n this.status = this.statusCode = status;\r\n }\r\n\r\n setStatus(status) {\r\n this.status = status;\r\n return this;\r\n }\r\n}\r\n\r\nexport default HttpError;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport { getAllowCodeExecution, startExport } from '../../chart.js';\r\nimport { getOptions, mergeConfigOptions } from '../../config.js';\r\nimport { log } from '../../logger.js';\r\nimport {\r\n fixType,\r\n isCorrectJSON,\r\n isObjectEmpty,\r\n isPrivateRangeUrlFound,\r\n optionsStringify,\r\n measureTime\r\n} from '../../utils.js';\r\n\r\nimport HttpError from '../../errors/HttpError.js';\r\n\r\n// Reversed MIME types\r\nconst reversedMime = {\r\n png: 'image/png',\r\n jpeg: 'image/jpeg',\r\n gif: 'image/gif',\r\n pdf: 'application/pdf',\r\n svg: 'image/svg+xml'\r\n};\r\n\r\n// The requests counter\r\nlet requestsCounter = 0;\r\n\r\n// The array of callbacks to call before a request\r\nconst beforeRequest = [];\r\n\r\n// The array of callbacks to call after a request\r\nconst afterRequest = [];\r\n\r\n/**\r\n * Invokes an array of callback functions with specified parameters, allowing\r\n * customization of request handling.\r\n *\r\n * @param {Function[]} callbacks - An array of callback functions\r\n * to be executed.\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Object} data - An object containing parameters like id, uniqueId,\r\n * type, and body.\r\n *\r\n * @returns {boolean} - Returns a boolean indicating the overall result\r\n * of the callback invocations.\r\n */\r\nconst doCallbacks = (callbacks, request, response, data) => {\r\n let result = true;\r\n const { id, uniqueId, type, body } = data;\r\n\r\n callbacks.some((callback) => {\r\n if (callback) {\r\n let callResponse = callback(request, response, id, uniqueId, type, body);\r\n\r\n if (callResponse !== undefined && callResponse !== true) {\r\n result = callResponse;\r\n }\r\n\r\n return true;\r\n }\r\n });\r\n\r\n return result;\r\n};\r\n\r\n/**\r\n * Handles the export requests from the client.\r\n *\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {Promise} - A promise that resolves once the export process\r\n * is complete.\r\n */\r\nconst exportHandler = async (request, response, next) => {\r\n try {\r\n // Start counting time\r\n const stopCounter = measureTime();\r\n\r\n // Create a unique ID for a request\r\n const uniqueId = uuid().replace(/-/g, '');\r\n\r\n // Get the current server's general options\r\n const defaultOptions = getOptions();\r\n\r\n const body = request.body;\r\n const id = ++requestsCounter;\r\n\r\n let type = fixType(body.type);\r\n\r\n // Throw 'Bad Request' if there's no body\r\n if (!body || isObjectEmpty(body)) {\r\n throw new HttpError(\r\n 'The request body is required. Please ensure that your Content-Type header is correct (accepted types are application/json and multipart/form-data).',\r\n 400\r\n );\r\n }\r\n\r\n // All of the below can be used\r\n let instr = isCorrectJSON(body.infile || body.options || body.data);\r\n\r\n // Throw 'Bad Request' if there's no JSON or SVG to export\r\n if (!instr && !body.svg) {\r\n log(\r\n 2,\r\n `The request with ID ${uniqueId} from ${\r\n request.headers['x-forwarded-for'] || request.connection.remoteAddress\r\n } was incorrect. Payload received: ${JSON.stringify(body)}.`\r\n );\r\n\r\n throw new HttpError(\r\n \"No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.\",\r\n 400\r\n );\r\n }\r\n\r\n let callResponse = false;\r\n\r\n // Call the before request functions\r\n callResponse = doCallbacks(beforeRequest, request, response, {\r\n id,\r\n uniqueId,\r\n type,\r\n body\r\n });\r\n\r\n // Block the request if one of a callbacks failed\r\n if (callResponse !== true) {\r\n return response.send(callResponse);\r\n }\r\n\r\n let connectionAborted = false;\r\n\r\n // In case the connection is closed, force to abort further actions\r\n request.socket.on('close', () => {\r\n connectionAborted = true;\r\n });\r\n\r\n log(4, `[export] Got an incoming HTTP request with ID ${uniqueId}.`);\r\n\r\n body.constr = (typeof body.constr === 'string' && body.constr) || 'chart';\r\n\r\n // Gather and organize options from the payload\r\n const requestOptions = {\r\n export: {\r\n instr,\r\n type,\r\n constr: body.constr[0].toLowerCase() + body.constr.substr(1),\r\n height: body.height,\r\n width: body.width,\r\n scale: body.scale || defaultOptions.export.scale,\r\n globalOptions: isCorrectJSON(body.globalOptions, true),\r\n themeOptions: isCorrectJSON(body.themeOptions, true)\r\n },\r\n customLogic: {\r\n allowCodeExecution: getAllowCodeExecution(),\r\n allowFileResources: false,\r\n resources: isCorrectJSON(body.resources, true),\r\n callback: body.callback,\r\n customCode: body.customCode\r\n }\r\n };\r\n\r\n if (instr) {\r\n // Stringify JSON with options\r\n requestOptions.export.instr = optionsStringify(\r\n instr,\r\n requestOptions.customLogic.allowCodeExecution\r\n );\r\n }\r\n\r\n // Merge the request options into default ones\r\n const options = mergeConfigOptions(defaultOptions, requestOptions);\r\n\r\n // Save the JSON if exists\r\n options.export.options = instr;\r\n\r\n // Lastly, add the server specific arguments into options as payload\r\n options.payload = {\r\n svg: body.svg || false,\r\n b64: body.b64 || false,\r\n noDownload: body.noDownload || false,\r\n requestId: uniqueId\r\n };\r\n\r\n // Test xlink:href elements from payload's SVG\r\n if (body.svg && isPrivateRangeUrlFound(options.payload.svg)) {\r\n throw new HttpError(\r\n 'SVG potentially contain at least one forbidden URL in xlink:href element. Please review the SVG content and ensure that all referenced URLs comply with security policies.',\r\n 400\r\n );\r\n }\r\n\r\n // Start the export process\r\n await startExport(options, (error, info) => {\r\n // Remove the close event from the socket\r\n request.socket.removeAllListeners('close');\r\n\r\n // After the whole exporting process\r\n if (defaultOptions.server.benchmarking) {\r\n log(\r\n 5,\r\n `[benchmark] Request with ID ${uniqueId} - After the whole exporting process: ${stopCounter()}ms.`\r\n );\r\n }\r\n\r\n // If the connection was closed, do nothing\r\n if (connectionAborted) {\r\n return log(\r\n 3,\r\n `[export] The client closed the connection before the chart finished processing.`\r\n );\r\n }\r\n\r\n // If error, log it and send it to the error middleware\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // If data is missing, log the message and send it to the error middleware\r\n if (!info || !info.result) {\r\n throw new HttpError(\r\n `Unexpected return from chart generation. Please check your request data. For the request with ID ${uniqueId}, the result is ${info.result}.`,\r\n 400\r\n );\r\n }\r\n\r\n // Get the type from options\r\n type = info.options.export.type;\r\n\r\n // The after request callbacks\r\n doCallbacks(afterRequest, request, response, { id, body: info.result });\r\n\r\n if (info.result) {\r\n // If only base64 is required, return it\r\n if (body.b64) {\r\n // SVG Exception for the Highcharts 11.3.0 version\r\n if (type === 'pdf' || type == 'svg') {\r\n return response.send(\r\n Buffer.from(info.result, 'utf8').toString('base64')\r\n );\r\n }\r\n\r\n return response.send(info.result);\r\n }\r\n\r\n // Set correct content type\r\n response.header('Content-Type', reversedMime[type] || 'image/png');\r\n\r\n // Decide whether to download or not chart file\r\n if (!body.noDownload) {\r\n response.attachment(\r\n `${request.params.filename || request.body.filename || 'chart'}.${\r\n type || 'png'\r\n }`\r\n );\r\n }\r\n\r\n // If SVG, return plain content\r\n return type === 'svg'\r\n ? response.send(info.result)\r\n : response.send(Buffer.from(info.result, 'base64'));\r\n }\r\n });\r\n } catch (error) {\r\n next(error);\r\n }\r\n};\r\n\r\nexport default (app) => {\r\n /**\r\n * Adds the POST / a route for handling POST requests at the root endpoint.\r\n */\r\n app.post('/', exportHandler);\r\n\r\n /**\r\n * Adds the POST /:filename a route for handling POST requests with\r\n * a specified filename parameter.\r\n */\r\n app.post('/:filename', exportHandler);\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join as pather } from 'path';\r\n\r\nimport cache from '../../cache.js';\r\nimport pool from '../../pool.js';\r\nimport { __dirname } from '../../utils.js';\r\n\r\nconst pkgFile = JSON.parse(readFileSync(pather(__dirname, 'package.json')));\r\n\r\nconst serverStartTime = new Date();\r\n\r\n/**\r\n * Adds the GET /health route, which outputs basic stats for the server.\r\n */\r\nexport default (app) =>\r\n !app\r\n ? false\r\n : app.get('/health', (request, response) => {\r\n response.send({\r\n status: 'OK',\r\n bootTime: serverStartTime,\r\n uptime:\r\n Math.floor(\r\n (new Date().getTime() - serverStartTime.getTime()) / 1000 / 60\r\n ) + ' minutes',\r\n version: pkgFile.version,\r\n highchartsVersion: cache.version(),\r\n averageProcessingTime: pool.averageTime(),\r\n performedExports: pool.processedWorkCount(),\r\n failedExports: pool.droppedWork(),\r\n exportAttempts: pool.workAttempts(),\r\n sucessRatio: (pool.processedWorkCount() / pool.workAttempts()) * 100,\r\n // eslint-disable-next-line import/no-named-as-default-member\r\n pool: pool.getPoolInfoJSON()\r\n });\r\n });\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { promises as fsPromises } from 'fs';\r\nimport { posix } from 'path';\r\n\r\nimport cors from 'cors';\r\nimport express from 'express';\r\nimport http from 'http';\r\nimport https from 'https';\r\nimport multer from 'multer';\r\n\r\nimport errorHandler from './error.js';\r\nimport { log, logWithStack } from '../logger.js';\r\nimport rateLimit from './rate_limit.js';\r\nimport { __dirname } from '../utils.js';\r\n\r\nimport vSwitchRoute from './routes/change_hc_version.js';\r\nimport exportRoutes from './routes/export.js';\r\nimport healthRoute from './routes/health.js';\r\nimport uiRoute from './routes/ui.js';\r\n\r\nimport ExportError from '../errors/ExportError.js';\r\n\r\n// Create express app\r\nconst app = express();\r\n\r\n// Disable the X-Powered-By header\r\napp.disable('x-powered-by');\r\n\r\n// Enable CORS support\r\napp.use(cors());\r\n\r\n// Enable parsing of form data (files) with Multer package\r\nconst storage = multer.memoryStorage();\r\nconst upload = multer({\r\n storage,\r\n limits: {\r\n fieldSize: 50 * 1024 * 1024\r\n }\r\n});\r\n\r\n// Enable body parser\r\napp.use(express.json({ limit: 50 * 1024 * 1024 }));\r\napp.use(express.urlencoded({ extended: true, limit: 50 * 1024 * 1024 }));\r\n\r\n// Use only non-file multipart form fields\r\napp.use(upload.none());\r\n\r\n/**\r\n * Attach error handlers to the server.\r\n *\r\n * @param {http.Server} server - The HTTP/HTTPS server instance.\r\n */\r\nconst attachErrorHandlers = (server) => {\r\n server.on('clientError', (error) => {\r\n logWithStack(1, error, `[server] Client error: ${error.message}`);\r\n });\r\n server.on('error', (error) => {\r\n logWithStack(1, error, `[server] Server error: ${error.message}`);\r\n });\r\n server.on('connection', (socket) => {\r\n socket.on('error', (error) => {\r\n logWithStack(1, error, `[server] Socket error: ${error.message}`);\r\n });\r\n });\r\n};\r\n\r\n/**\r\n * Starts an HTTP server based on the provided configuration. The `serverConfig`\r\n * object contains all server related properties (see the `server` section\r\n * in the `lib/schemas/config.js` file for a reference).\r\n *\r\n * @param {Object} serverConfig - The server configuration object.\r\n *\r\n * @throws {ExportError} - Throws an error if the server cannot be configured\r\n * and started.\r\n */\r\nexport const startServer = async (serverConfig) => {\r\n try {\r\n // Stop if not enabled\r\n if (!serverConfig.enable) {\r\n return false;\r\n }\r\n\r\n // Listen HTTP server\r\n if (!serverConfig.ssl.force) {\r\n // Main server instance (HTTP)\r\n const httpServer = http.createServer(app);\r\n\r\n // Attach error handlers and listen to the server\r\n attachErrorHandlers(httpServer);\r\n\r\n // Listen\r\n httpServer.listen(serverConfig.port, serverConfig.host);\r\n\r\n log(\r\n 3,\r\n `[server] Started HTTP server on ${serverConfig.host}:${serverConfig.port}.`\r\n );\r\n }\r\n\r\n // Listen HTTPS server\r\n if (serverConfig.ssl.enable) {\r\n // Set up an SSL server also\r\n let key, cert;\r\n\r\n try {\r\n // Get the SSL key\r\n key = await fsPromises.readFile(\r\n posix.join(serverConfig.ssl.certPath, 'server.key'),\r\n 'utf8'\r\n );\r\n\r\n // Get the SSL certificate\r\n cert = await fsPromises.readFile(\r\n posix.join(serverConfig.ssl.certPath, 'server.crt'),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n log(\r\n 2,\r\n `[server] Unable to load key/certificate from the '${serverConfig.ssl.certPath}' path. Could not run secured layer server.`\r\n );\r\n }\r\n\r\n if (key && cert) {\r\n // Main server instance (HTTPS)\r\n const httpsServer = https.createServer({ key, cert }, app);\r\n\r\n // Attach error handlers and listen to the server\r\n attachErrorHandlers(httpsServer);\r\n\r\n // Listen\r\n httpsServer.listen(serverConfig.ssl.port, serverConfig.host);\r\n\r\n log(\r\n 3,\r\n `[server] Started HTTPS server on ${serverConfig.host}:${serverConfig.ssl.port}.`\r\n );\r\n }\r\n }\r\n\r\n // Enable the rate limiter if config says so\r\n if (\r\n serverConfig.rateLimiting &&\r\n serverConfig.rateLimiting.enable &&\r\n ![0, NaN].includes(serverConfig.rateLimiting.maxRequests)\r\n ) {\r\n rateLimit(app, serverConfig.rateLimiting);\r\n }\r\n\r\n // Set up static folder's route\r\n app.use(express.static(posix.join(__dirname, 'public')));\r\n\r\n // Set up routes\r\n healthRoute(app);\r\n exportRoutes(app);\r\n uiRoute(app);\r\n vSwitchRoute(app);\r\n\r\n // Set up centralized error handler\r\n errorHandler(app);\r\n } catch (error) {\r\n throw new ExportError(\r\n '[server] Could not configure and start the server.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Enable rate limiting for the server.\r\n *\r\n * @param {Object} limitConfig - Configuration object for rate limiting.\r\n */\r\nexport const enableRateLimiting = (limitConfig) => rateLimit(app, limitConfig);\r\n\r\n/**\r\n * Get the Express instance.\r\n *\r\n * @returns {Object} - The Express instance.\r\n */\r\nexport const getExpress = () => express;\r\n\r\n/**\r\n * Get the Express app instance.\r\n *\r\n * @returns {Object} - The Express app instance.\r\n */\r\nexport const getApp = () => app;\r\n\r\n/**\r\n * Apply middleware(s) to a specific path.\r\n *\r\n * @param {string} path - The path to which the middleware(s) should be applied.\r\n * @param {...Function} middlewares - The middleware functions to be applied.\r\n */\r\nexport const use = (path, ...middlewares) => {\r\n app.use(path, ...middlewares);\r\n};\r\n\r\n/**\r\n * Set up a route with GET method and apply middleware(s).\r\n *\r\n * @param {string} path - The route path.\r\n * @param {...Function} middlewares - The middleware functions to be applied.\r\n */\r\nexport const get = (path, ...middlewares) => {\r\n app.get(path, ...middlewares);\r\n};\r\n\r\n/**\r\n * Set up a route with POST method and apply middleware(s).\r\n *\r\n * @param {string} path - The route path.\r\n * @param {...Function} middlewares - The middleware functions to be applied.\r\n */\r\nexport const post = (path, ...middlewares) => {\r\n app.post(path, ...middlewares);\r\n};\r\n\r\nexport default {\r\n startServer,\r\n enableRateLimiting,\r\n getExpress,\r\n getApp,\r\n use,\r\n get,\r\n post\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { join } from 'path';\r\n\r\nimport { __dirname } from '../../utils.js';\r\n\r\n/**\r\n * Adds the GET / route for a UI when enabled on the export server.\r\n */\r\nexport default (app) =>\r\n !app\r\n ? false\r\n : app.get('/', (request, response) => {\r\n response.sendFile(join(__dirname, 'public', 'index.html'));\r\n });\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport cache from '../../cache.js';\r\nimport HttpError from '../../errors/HttpError.js';\r\nimport { envs } from '../../envs.js';\r\n\r\n/**\r\n * Adds the POST /change_hc_version/:newVersion route that can be utilized to modify\r\n * the Highcharts version on the server.\r\n *\r\n * TODO: Add auth token and connect to API\r\n */\r\nexport default (app) =>\r\n !app\r\n ? false\r\n : app.post(\r\n '/version/change/:newVersion',\r\n async (request, response, next) => {\r\n try {\r\n const adminToken = envs.HIGHCHARTS_ADMIN_TOKEN;\r\n\r\n // Check the existence of the token\r\n if (!adminToken || !adminToken.length) {\r\n throw new HttpError(\r\n 'The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.',\r\n 401\r\n );\r\n }\r\n\r\n // Check if the hc-auth header contain a correct token\r\n const token = request.get('hc-auth');\r\n if (!token || token !== adminToken) {\r\n throw new HttpError(\r\n 'Invalid or missing token: Set the token in the hc-auth header.',\r\n 401\r\n );\r\n }\r\n\r\n // Compare versions\r\n const newVersion = request.params.newVersion;\r\n if (newVersion) {\r\n try {\r\n // eslint-disable-next-line import/no-named-as-default-member\r\n await cache.updateVersion(newVersion);\r\n } catch (error) {\r\n throw new HttpError(\r\n `Version change: ${error.message}`,\r\n error.statusCode\r\n ).setError(error);\r\n }\r\n\r\n // Success\r\n response.status(200).send({\r\n statusCode: 200,\r\n version: cache.version(),\r\n message: `Successfully updated Highcharts to version: ${newVersion}.`\r\n });\r\n } else {\r\n // No version specified\r\n throw new HttpError('No new version supplied.', 400);\r\n }\r\n } catch (error) {\r\n next(error);\r\n }\r\n }\r\n );\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport 'colors';\r\nimport dotenv from 'dotenv';\r\n\r\nimport { checkAndUpdateCache } from './cache.js';\r\nimport {\r\n batchExport,\r\n setAllowCodeExecution,\r\n singleExport,\r\n startExport\r\n} from './chart.js';\r\nimport { mapToNewConfig, manualConfig, setOptions } from './config.js';\r\nimport {\r\n initLogging,\r\n log,\r\n logWithStack,\r\n setLogLevel,\r\n enableFileLogging\r\n} from './logger.js';\r\nimport { initPool, killPool } from './pool.js';\r\nimport server, { startServer } from './server/server.js';\r\nimport { printLogo, printUsage } from './utils.js';\r\n\r\n// Load .env into environment variables\r\ndotenv.config();\r\n\r\n/**\r\n * Initializes the export process. Tasks such as configuring logging, checking\r\n * cache and sources, and initializing the pool of resources happen during\r\n * this stage. Function that is required to be called before trying to export charts or setting a server. The `options` is an object that contains all options.\r\n *\r\n * @param {Object} options - All export options.\r\n *\r\n * @returns {Promise} Promise resolving to the updated export options.\r\n */\r\nconst initExport = async (options) => {\r\n // Set the allowCodeExecution per export module scope\r\n setAllowCodeExecution(\r\n options.customLogic && options.customLogic.allowCodeExecution\r\n );\r\n\r\n // Init the logging\r\n initLogging(options.logging);\r\n\r\n // Check if cache needs to be updated\r\n await checkAndUpdateCache(options.highcharts || { version: 'latest' });\r\n\r\n // Init the pool\r\n await initPool({\r\n pool: options.pool || {\r\n minWorkers: 1,\r\n maxWorkers: 1\r\n },\r\n puppeteerArgs: options.puppeteer?.args || []\r\n });\r\n\r\n // Return updated options\r\n return options;\r\n};\r\n\r\nexport default {\r\n // Server\r\n server,\r\n startServer,\r\n setOptions,\r\n\r\n // Exporting\r\n initExport,\r\n singleExport,\r\n batchExport,\r\n startExport,\r\n killPool,\r\n\r\n // Logs\r\n log,\r\n logWithStack,\r\n setLogLevel,\r\n enableFileLogging,\r\n\r\n // Utils\r\n mapToNewConfig,\r\n manualConfig,\r\n printLogo,\r\n printUsage\r\n};\r\n"],"names":["async","fetch","url","requestOptions","Promise","resolve","reject","protocol","startsWith","https","http","getProtocol","get","res","data","on","chunk","text","error","defaultConfig","puppeteer","args","value","type","description","highcharts","version","envLink","cdnURL","coreScripts","modules","indicators","scripts","forceFetch","cachePath","export","infile","instr","options","outfile","constr","defaultHeight","defaultWidth","defaultScale","height","width","scale","globalOptions","themeOptions","batch","rasterizationTimeout","customLogic","allowCodeExecution","allowFileResources","customCode","callback","resources","loadConfig","legacyName","createConfig","server","enable","cliName","host","port","benchmarking","ssl","force","certPath","rateLimiting","maxRequests","window","delay","trustProxy","skipKey","skipToken","pool","minWorkers","maxWorkers","workLimit","acquireTimeout","createTimeout","destroyTimeout","idleTimeout","createRetryInterval","reaperInterval","listenToProcessExits","logging","level","file","dest","ui","route","other","noLogo","promptsConfig","name","message","initial","join","separator","instructions","choices","hint","min","max","round","absoluteProps","nestedArgs","createNestedArgs","obj","propChain","Object","keys","forEach","k","includes","entry","substring","undefined","colors","toConsole","toFile","pathCreated","levelsDesc","title","color","listeners","key","option","entries","logToFile","texts","prefix","existsSync","mkdirSync","appendFile","concat","console","log","newLevel","length","Date","toString","split","trim","fn","apply","logWithStack","customMessage","mainMessage","stackMessage","stack","slice","setLogLevel","enableFileLogging","logDest","logFile","endsWith","__dirname","fileURLToPath","URL","fixType","formats","outType","pop","find","t","handleResources","allowedProps","handledResources","correctResources","isCorrectJSON","readFileSync","files","propName","map","item","parsedData","JSON","parse","stringify","deepCopy","copy","Array","isArray","prototype","hasOwnProperty","call","optionsStringify","allowFunctions","replaceAll","printUsage","bold","yellow","cycleCategories","descName","green","i","blue","category","toUpperCase","red","toBoolean","wrapAround","replace","measureTime","start","process","hrtime","bigint","Number","dotenv","config","v","z","enum","transform","optional","string","val","envs","object","HIGHCHARTS_VERSION","refine","test","HIGHCHARTS_CDN_URL","HIGHCHARTS_CORE_SCRIPTS","HIGHCHARTS_MODULES","HIGHCHARTS_INDICATORS","HIGHCHARTS_FORCE_FETCH","HIGHCHARTS_CACHE_PATH","HIGHCHARTS_ADMIN_TOKEN","EXPORT_TYPE","EXPORT_CONSTR","EXPORT_DEFAULT_HEIGHT","coerce","number","positive","EXPORT_DEFAULT_WIDTH","EXPORT_DEFAULT_SCALE","EXPORT_RASTERIZATION_TIMEOUT","CUSTOM_LOGIC_ALLOW_CODE_EXECUTION","CUSTOM_LOGIC_ALLOW_FILEL_RESOURCES","SERVER_ENABLE","SERVER_HOST","SERVER_PORT","SERVER_BENCHMARKING","SERVER_SSL_ENABLE","SERVER_SSL_FORCE","SERVER_SSL_PORT","SERVER_SSL_CERT_PATH","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","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","POOL_LISTEN_TO_PROCESS_EXITS","LOGGING_LEVEL","LOGGING_FILE","LOGGING_DEST","UI_ENABLE","UI_ROUTE","OTHER_NO_LOGO","NODE_ENV","default","PROXY_SERVER_TIMEOUT","PROXY_SERVER_HOST","PROXY_SERVER_PORT","env","ExportError","Error","constructor","super","this","setError","statusCode","cache","activeManifest","sources","hcVersion","appliedConfig","extractVersion","indexOf","fetchAndProcessScript","script","proxyAgent","fetchedModules","shouldThrowError","agent","timeout","response","updateCache","sourcePath","customScripts","proxyHost","proxyPort","HttpsProxyAgent","moduleScripts","allFetchPromises","all","fetchScripts","c","m","writeFileSync","checkAndUpdateCache","manifestPath","requestUpdate","manifest","moduleMap","numberOfModules","some","moduleName","newManifest","saveConfigToManifest","getCachePath","cache$1","newVersion","assign","generalOptions","getOptions","mergeConfigOptions","newOptions","mergedOptions","updateDefaultConfig","configObj","customObj","customValue","initOptions","items","recursiveProps","objectToUpdate","nestedNames","shift","RANDOM_PID","randomBytes","PUPPETEER_DIR","path","minimalArgs","template","fs","browser","setPageContent","page","setContent","addScriptTag","evaluate","setupHighcharts","$eval","element","errorMessage","_displayErrors","innerHTML","clearPage","hardReset","goto","document","body","newPage","setCacheEnabled","close","isConnected","__basedir","setAsConfig","chart","triggerExport","puppeteerExport","injectedResources","clearInjected","dispose","scriptsToRemove","getElementsByTagName","stylesToRemove","linksToRemove","remove","exportOptions","requestAnimationFrame","displayErrors","debugger","isSVG","d","svgTemplate","strInj","js","push","content","isLocal","css","cssImports","match","cssImportPath","addStyleTag","size","chartHeight","baseVal","chartWidth","parseFloat","Highcharts","charts","viewportHeight","Math","ceil","viewportWidth","setViewport","deviceScaleFactor","zoomCallback","style","zoom","margin","x","y","getBoundingClientRect","trunc","getClipRegion","outerHTML","createSVG","encoding","clip","race","screenshot","omitBackground","_resolve","setTimeout","createImage","pdf","createPDF","oldCharts","oldChart","destroy","puppeteerArgs","performedExports","exportAttempts","timeSpent","droppedExports","spentAverage","poolConfig","factory","create","id","uuid","startDate","getTime","browserNewPage","isClosed","workCount","random","validate","workerHandle","initPool","code","killPool","exit","allArgs","tryCount","open","launch","headless","userDataDir","createBrowser","parseInt","Pool","acquireTimeoutMillis","createTimeoutMillis","destroyTimeoutMillis","idleTimeoutMillis","createRetryIntervalMillis","reapIntervalMillis","propagateCreateError","resource","eventId","initialResources","acquire","promise","release","browserClose","destroyed","postWork","getPoolInfo","acquireCounter","payload","requestId","workStart","exportCounter","result","exportTime","numFree","numUsed","numPendingAcquires","pool$1","available","inUse","pendingAcquire","startExport","settings","endCallback","svg","initExportSettings","exportAsString","doStraightInject","doExport","findChartSize","exporting","precision","multiplier","pow","roundNumber","sourceHeight","sourceWidth","param","chartJson","customLogicOptions","allowCodeExecutionScoped","enabled","optionsName","stringToExport","chartJSON","logErrorMiddleware","req","next","returnErrorMiddleware","stCode","status","json","rateLimit","app","limitConfig","msg","rateOptions","limiter","windowMs","delayMs","handler","request","format","send","skip","query","access_token","use","HttpError","setStatus","reversedMime","png","jpeg","gif","requestsCounter","beforeRequest","afterRequest","doCallbacks","callbacks","uniqueId","callResponse","exportHandler","stopCounter","defaultOptions","headers","connection","remoteAddress","connectionAborted","socket","toLowerCase","substr","b64","noDownload","pattern","isPrivateRangeUrlFound","info","removeAllListeners","Buffer","from","header","attachment","params","filename","pkgFile","pather","serverStartTime","express","disable","cors","storage","multer","memoryStorage","upload","limits","fieldSize","limit","urlencoded","extended","none","attachErrorHandlers","startServer","serverConfig","httpServer","createServer","listen","cert","fsPromises","readFile","posix","httpsServer","NaN","static","bootTime","uptime","floor","highchartsVersion","averageProcessingTime","failedExports","sucessRatio","healthRoute","post","exportRoutes","sendFile","uiRoute","adminToken","token","vSwitchRoute","errorHandler","enableRateLimiting","getExpress","getApp","middlewares","index","setOptions","userOptions","configIndex","findIndex","arg","fileName","loadConfigFile","showUsage","propertiesChain","argumentType","reduce","prop","pairArgumentValue","initExport","initLogging","singleExport","batchExport","batchFunctions","pair","mapToNewConfig","oldOptions","manualConfig","configFileName","configFile","choice","prompts","onSubmit","p","categories","questionsCounter","allQuestions","section","prompt","answer","module","writeFile","printLogo","packageVersion"],"mappings":"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"} \ No newline at end of file diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 00000000..f57f9616 --- /dev/null +++ b/jest.config.js @@ -0,0 +1,7 @@ +export default { + testEnvironment: 'jest-environment-node', + testMatch: ['**/tests/unit/**/*.test.js'], + transform: { + // '^.+\\.test.js?$': 'babel-jest' + } +}; diff --git a/lib/cache.js b/lib/cache.js index c6b803c2..820b24e7 100644 --- a/lib/cache.js +++ b/lib/cache.js @@ -24,6 +24,7 @@ import { HttpsProxyAgent } from 'https-proxy-agent'; import { fetch } from './fetch.js'; import { log } from './logger.js'; import { __dirname } from './utils.js'; +import { envs } from './envs.js'; import ExportError from './errors/ExportError.js'; @@ -42,18 +43,19 @@ let appliedConfig = false; * * @returns {string} The extracted Highcharts version. */ -const extractVersion = () => - (cache.hcVersion = cache.sources +export const extractVersion = (cache) => { + return cache.sources .substring(0, cache.sources.indexOf('*/')) .replace('/*', '') .replace('*/', '') .replace(/\n/g, '') - .trim()); + .trim(); +}; /** * Extracts the Highcharts module name based on the scriptPath. */ -const extractModuleName = (scriptPath) => { +export const extractModuleName = (scriptPath) => { return scriptPath.replace( /(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi, '' @@ -71,7 +73,7 @@ const extractModuleName = (scriptPath) => { * @throws {ExportError} Throws an ExportError if an error occurs while writing * the cache manifest. */ -const saveConfigToManifest = async (config, fetchedModules) => { +export const saveConfigToManifest = async (config, fetchedModules) => { const newManifest = { version: config.version, modules: fetchedModules || {} @@ -108,7 +110,7 @@ const saveConfigToManifest = async (config, fetchedModules) => { * @throws {ExportError} Throws an ExportError if there is a problem with * fetching the script. */ -const fetchAndProcessScript = async ( +export const fetchAndProcessScript = async ( script, proxyAgent, fetchedModules, @@ -125,7 +127,7 @@ const fetchAndProcessScript = async ( const requestOptions = proxyAgent ? { agent: proxyAgent, - timeout: +process.env['PROXY_SERVER_TIMEOUT'] || 5000 + timeout: envs.PROXY_SERVER_TIMEOUT } : {}; @@ -165,7 +167,7 @@ const fetchAndProcessScript = async ( * @param {object} fetchedModules - An object which tracks which Highcharts modules have been fetched. * @returns {Promise} The fetched scripts content joined. */ -const fetchScripts = async ( +export const fetchScripts = async ( coreScripts, moduleScripts, customScripts, @@ -207,7 +209,7 @@ const fetchScripts = async ( * @throws {ExportError} Throws an ExportError if there is an issue updating * the local Highcharts cache. */ -const updateCache = async (config, sourcePath) => { +export const updateCache = async (config, sourcePath) => { const { coreScripts, modules, indicators, scripts: customScripts } = config; const hcVersion = config.version === 'latest' || !config.version ? '' : `${config.version}/`; @@ -253,7 +255,8 @@ const updateCache = async (config, sourcePath) => { proxyAgent, fetchedModules ); - extractVersion(); + + cache.hcVersion = extractVersion(cache); // Save the fetched modules into caches' source JSON writeFileSync(sourcePath, cache.sources); @@ -374,7 +377,8 @@ export const checkAndUpdateCache = async (config) => { // Get current modules map fetchedModules = manifest.modules; - extractVersion(); + + cache.hcVersion = extractVersion(cache); } } diff --git a/lib/config.js b/lib/config.js index dc8b0135..f52cf7f9 100644 --- a/lib/config.js +++ b/lib/config.js @@ -24,6 +24,7 @@ import { } from './schemas/config.js'; import { log, logWithStack } from './logger.js'; import { deepCopy, isObject, printUsage, toBoolean } from './utils.js'; +import { envs } from './envs.js'; let generalOptions = {}; @@ -311,7 +312,6 @@ function updateDefaultConfig(configObj, customObj = {}, propChain = '') { Object.keys(configObj).forEach((key) => { const entry = configObj[key]; const customValue = customObj && customObj[key]; - let numEnvVal; if (typeof entry.value === 'undefined') { updateDefaultConfig(entry, customValue, `${propChain}.${key}`); @@ -322,22 +322,8 @@ function updateDefaultConfig(configObj, customObj = {}, propChain = '') { } // If a value from an env variable exists, it take precedence - if (entry.envLink) { - // Load the env var - if (entry.type === 'boolean') { - entry.value = toBoolean( - [process.env[entry.envLink], entry.value].find( - (el) => el || el === 'false' - ) - ); - } else if (entry.type === 'number') { - numEnvVal = +process.env[entry.envLink]; - entry.value = numEnvVal >= 0 ? numEnvVal : entry.value; - } else if (entry.type.indexOf(']') >= 0 && process.env[entry.envLink]) { - entry.value = process.env[entry.envLink].split(','); - } else { - entry.value = process.env[entry.envLink] || entry.value; - } + if (entry.envLink in envs) { + entry.value = envs[entry.envLink]; } } }); diff --git a/lib/envs.js b/lib/envs.js new file mode 100644 index 00000000..1e6c4919 --- /dev/null +++ b/lib/envs.js @@ -0,0 +1,132 @@ +/** + * @fileoverview + * This file is responsible for parsing the environment variables with the 'zod' library. + * The parsed environment variables are then exported to be used in the application as "envs". + * We should not use process.env directly in the application as these would not be parsed properly. + * + * The environment variables are parsed and validated only once when the application starts. + * We should write a custom validator or a transformer for each of the options. + * + * For envs not defined in config.js with defaults, we also include default values here (PROXY_...). + */ + +import { z } from 'zod'; +import dotenv from 'dotenv'; +dotenv.config(); + +// Object with custom validators and transformers, to avoid repetition in the Config object +const v = { + boolean: () => + z + .enum(['true', 'false']) + .transform((value) => value === 'true') + .optional(), + array: () => + z + .string() + .transform((val) => val.split(',').map((v) => v.trim())) + .optional() +}; + +export const Config = z.object({ + // highcharts + HIGHCHARTS_VERSION: z + .string() + .refine((value) => /^(latest|\d+(\.\d+){0,2})$/.test(value), { + message: + "HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ" + }) + .optional(), // todo: create an array of available Highcharts versions + HIGHCHARTS_CDN_URL: z + .string() + .trim() + .refine((val) => val.startsWith('https://') || val.startsWith('http://'), { + message: + 'Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://.' + }) + .optional(), + HIGHCHARTS_CORE_SCRIPTS: v.array(), + HIGHCHARTS_MODULES: v.array(), + HIGHCHARTS_INDICATORS: v.array(), + HIGHCHARTS_FORCE_FETCH: v.boolean(), + HIGHCHARTS_CACHE_PATH: z.string().optional(), + HIGHCHARTS_ADMIN_TOKEN: z.string().optional(), + + // export + EXPORT_TYPE: z.enum(['jpeg', 'png', 'pdf', 'svg']).optional(), + EXPORT_CONSTR: z + .string() + .refine( + (val) => + ['chart', 'stockChart', 'mapChart', 'ganttChart'].includes(val || ''), + { message: 'Invalid value for EXPORT_CONSTR. ' } + ) + .optional(), + EXPORT_DEFAULT_HEIGHT: z.coerce.number().positive().optional(), + EXPORT_DEFAULT_WIDTH: z.coerce.number().positive().optional(), + EXPORT_DEFAULT_SCALE: z.coerce.number().positive().optional(), + EXPORT_RASTERIZATION_TIMEOUT: z.coerce.number().positive().optional(), + + // custom + CUSTOM_LOGIC_ALLOW_CODE_EXECUTION: v.boolean(), + CUSTOM_LOGIC_ALLOW_FILEL_RESOURCES: v.boolean(), + + // server-related + SERVER_ENABLE: v.boolean(), + SERVER_HOST: z.string().optional(), + SERVER_PORT: z.coerce.number().optional(), + SERVER_BENCHMARKING: v.boolean(), + SERVER_SSL_ENABLE: v.boolean(), + SERVER_SSL_FORCE: v.boolean(), + SERVER_SSL_PORT: z.coerce.number().optional(), + SERVER_SSL_CERT_PATH: z.string().optional(), + SERVER_RATE_LIMITING_ENABLE: v.boolean(), + SERVER_RATE_LIMITING_MAX_REQUESTS: z.coerce.number().optional(), + SERVER_RATE_LIMITING_WINDOW: z.coerce.number().optional(), + SERVER_RATE_LIMITING_DELAY: z.coerce.number().optional(), + SERVER_RATE_LIMITING_TRUST_PROXY: v.boolean(), + SERVER_RATE_LIMITING_SKIP_KEY: z.string().optional(), + SERVER_RATE_LIMITING_SKIP_TOKEN: z.string().optional(), + + // pool + POOL_MIN_WORKERS: z.coerce.number().optional(), + POOL_MAX_WORKERS: z.coerce.number().optional(), + POOL_WORK_LIMIT: z.coerce.number().optional(), + POOL_ACQUIRE_TIMEOUT: z.coerce.number().optional(), + POOL_CREATE_TIMEOUT: z.coerce.number().optional(), + POOL_DESTROY_TIMEOUT: z.coerce.number().optional(), + POOL_IDLE_TIMEOUT: z.coerce.number().optional(), + POOL_CREATE_RETRY_INTERVAL: z.coerce.number().optional(), + POOL_REAPER_INTERVAL: z.coerce.number().optional(), + POOL_BENCHMARKING: v.boolean(), + POOL_LISTEN_TO_PROCESS_EXITS: v.boolean(), + + // logger + LOGGING_LEVEL: z.coerce + .number() + .optional() + .refine((val) => (val || 5) >= 0 && (val || 5) <= 5, { + message: + 'Invalid value for LOGGING_LEVEL. We only accept 0, 1, 2, 3, 4, 5 as logging levels.' + }), + LOGGING_FILE: z.string().optional(), + LOGGING_DEST: z.string().optional(), + + // ui + UI_ENABLE: v.boolean(), + UI_ROUTE: z.string().optional(), + + // other + OTHER_NO_LOGO: v.boolean(), + NODE_ENV: z + .enum(['development', 'production', 'test']) + .optional() + .default('production'), + + // proxy (! NOT INCLUDED IN CONFIG.JS !) + PROXY_SERVER_TIMEOUT: z.coerce.number().positive().optional().default(5000), + PROXY_SERVER_HOST: z.string().optional().default('localhost'), + PROXY_SERVER_PORT: z.coerce.number().positive().optional().default(8080) +}); + +export const envs = Config.parse(process.env); diff --git a/lib/server/error.js b/lib/server/error.js index e92fcc77..10b06b2e 100644 --- a/lib/server/error.js +++ b/lib/server/error.js @@ -1,4 +1,5 @@ import { logWithStack } from '../logger.js'; +import { envs } from '../envs.js'; /** * Middleware for logging errors with stack trace and handling error response. @@ -13,7 +14,7 @@ const logErrorMiddleware = (error, req, res, next) => { logWithStack(1, error); // Delete the stack for the environment other than the development - if (process.env.NODE_ENV !== 'development') { + if (envs.NODE_ENV !== 'development') { delete error.stack; } diff --git a/lib/server/routes/change_hc_version.js b/lib/server/routes/change_hc_version.js index aa3db095..54fa8cc3 100644 --- a/lib/server/routes/change_hc_version.js +++ b/lib/server/routes/change_hc_version.js @@ -13,8 +13,8 @@ See LICENSE file in root for details. *******************************************************************************/ import cache from '../../cache.js'; - import HttpError from '../../errors/HttpError.js'; +import { envs } from '../../envs.js'; /** * Adds the POST /change_hc_version/:newVersion route that can be utilized to modify @@ -29,7 +29,7 @@ export default (app) => '/version/change/:newVersion', async (request, response, next) => { try { - const adminToken = process.env.HIGHCHARTS_ADMIN_TOKEN; + const adminToken = envs.HIGHCHARTS_ADMIN_TOKEN; // Check the existence of the token if (!adminToken || !adminToken.length) { diff --git a/lib/utils.js b/lib/utils.js index 1f3745da..945f69f3 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -175,7 +175,7 @@ export const handleResources = (resources = false, allowFileResources) => { /** * Validates and parses JSON data. Checks if provided data is or can - * be a correct JSON. + * be a correct JSON. If a primitive is provided, it is stringified and returned. * * @param {Object|string} data - The JSON data to be validated and parsed. * @param {boolean} toString - Whether to return a stringified representation @@ -221,7 +221,10 @@ export const isObject = (item) => * @returns {boolean} - True if the object is empty, false otherwise. */ export const isObjectEmpty = (item) => - typeof item === 'object' && item !== null && Object.keys(item).length === 0; + typeof item === 'object' && + !Array.isArray(item) && + item !== null && + Object.keys(item).length === 0; /** * Checks if a private IP range URL is found in the given string. @@ -232,15 +235,15 @@ export const isObjectEmpty = (item) => * otherwise. */ export const isPrivateRangeUrlFound = (item) => { - return [ - 'localhost', - '(10).(.*).(.*).(.*)', - '(127).(.*).(.*).(.*)', - '(172).(1[6-9]|2[0-9]|3[0-1]).(.*).(.*)', - '(192).(168).(.*).(.*)' - ].some((ipRegEx) => - item.match(`xlink:href="(?:(http://|https://))?${ipRegEx}`) - ); + const regexPatterns = [ + /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/ + ]; + + return regexPatterns.some((pattern) => pattern.test(item)); }; /** diff --git a/package-lock.json b/package-lock.json index 7dd27bf0..aaf74212 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,7 +20,8 @@ "prompts": "^2.4.2", "puppeteer": "^22.6.2", "tarn": "^3.0.2", - "uuid": "^9.0.1" + "uuid": "^9.0.1", + "zod": "^3.22.4" }, "bin": { "highcharts-export-server": "bin/cli.js" @@ -32,6 +33,7 @@ "eslint-plugin-import": "^2.29.1", "eslint-plugin-prettier": "^5.1.3", "husky": "^9.0.11", + "jest": "^29.7.0", "lint-staged": "^15.2.2", "nodemon": "^3.1.0", "prettier": "^3.2.5", @@ -50,6 +52,19 @@ "node": ">=0.10.0" } }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@babel/code-frame": { "version": "7.24.2", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", @@ -62,6 +77,183 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/compat-data": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.1.tgz", + "integrity": "sha512-Pc65opHDliVpRHuKfzI+gSA4zcgr65O4cl64fFJIWEEh8JoHIHh0Oez1Eo8Arz8zq/JhgKodQaxEwUPRtZylVA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.24.3", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.3.tgz", + "integrity": "sha512-5FcvN1JHw2sHJChotgx8Ek0lyuh4kCKelgMTTqhYJJtloNvUfpAFMeNQUtdlIaktwrSV9LtCdqwk48wL2wBacQ==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.24.2", + "@babel/generator": "^7.24.1", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.24.1", + "@babel/parser": "^7.24.1", + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.1.tgz", + "integrity": "sha512-DfCRfZsBcrPEHUfuBMgbJ1Ut01Y/itOs+hY2nFLgqsqXd52/iSiVq5TITtUasIUgm+IIKdY2/1I7auiQOEeC9A==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.0", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", + "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.23.5", + "@babel/helper-validator-option": "^7.23.5", + "browserslist": "^4.22.2", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "dev": true, + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.24.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz", + "integrity": "sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz", + "integrity": "sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz", + "integrity": "sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-validator-identifier": { "version": "7.22.20", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", @@ -70,6 +262,29 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-validator-option": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.1.tgz", + "integrity": "sha512-BpU09QqEe6ZCHuIHFphEFgvNSrubve1FtyMton26ekZ85gRGi6LrTF7zArARp2YvyFxloeiRmtSCq5sjh1WqIg==", + "dev": true, + "dependencies": { + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/highlight": { "version": "7.24.2", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz", @@ -148,6 +363,259 @@ "node": ">=4" } }, + "node_modules/@babel/parser": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.1.tgz", + "integrity": "sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz", + "integrity": "sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.1.tgz", + "integrity": "sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", + "integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.23.5", + "@babel/parser": "^7.24.0", + "@babel/types": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.1.tgz", + "integrity": "sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.24.1", + "@babel/generator": "^7.24.1", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.24.1", + "@babel/types": "^7.24.0", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/types": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", + "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -237,24 +705,416 @@ "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", "dev": true }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", "dev": true, "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" }, "engines": { - "node": ">=6.0.0" + "node": ">=8" } }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", + "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", + "dev": true, + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/reporters": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.7.0", + "jest-config": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-resolve-dependencies": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "jest-watcher": "^29.7.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "dev": true, + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", + "dev": true, + "dependencies": { + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "dev": true, + "dependencies": { + "jest-get-type": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/types": "^29.6.3", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", + "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", + "dev": true, + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", + "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", + "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", + "dev": true, + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", + "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", + "dev": true, + "dependencies": { + "@jest/test-result": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, "engines": { "node": ">=6.0.0" @@ -388,6 +1248,11 @@ "node": ">=10" } }, + "node_modules/@puppeteer/browsers/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, "node_modules/@rollup/plugin-terser": { "version": "0.4.4", "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz", @@ -605,17 +1470,115 @@ "win32" ] }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, "node_modules/@tootallnate/quickjs-emscripten": { "version": "0.23.0", "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==" }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.8", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", + "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.5.tgz", + "integrity": "sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.7" + } + }, "node_modules/@types/estree": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", "dev": true }, + "node_modules/@types/graceful-fs": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -626,11 +1589,32 @@ "version": "20.12.3", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.3.tgz", "integrity": "sha512-sD+ia2ubTeWrOu+YMF+MTAB7E+O7qsMqAbMfW7DG3K1URwhZ5hN1pLlRVGbf4wDFzSfikL05M17EyorS86jShw==", - "optional": true, + "devOptional": true, "dependencies": { "undici-types": "~5.26.4" } }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true + }, + "node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true + }, "node_modules/@types/yauzl": { "version": "2.10.3", "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", @@ -713,12 +1697,27 @@ } }, "node_modules/ansi-escapes": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.1.tgz", - "integrity": "sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, "engines": { - "node": ">=14.16" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -919,7 +1918,114 @@ "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.6.tgz", "integrity": "sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==" }, - "node_modules/balanced-match": { + "node_modules/babel-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", + "dev": true, + "dependencies": { + "@jest/transform": "^29.7.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.6.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", + "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", + "dev": true, + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-preset-jest": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", + "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", + "dev": true, + "dependencies": { + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", @@ -1055,6 +2161,47 @@ "node": ">=8" } }, + "node_modules/browserslist": { + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", + "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "dependencies": { + "node-int64": "^0.4.0" + } + }, "node_modules/buffer": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", @@ -1136,6 +2283,35 @@ "node": ">=6" } }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001605", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001605.tgz", + "integrity": "sha512-nXwGlFWo34uliI9z3n6Qc0wZaf7zaZWA1CPZ169La5mV3I/gem7bst0vr5XQH5TJXZIMfDeZyOrZnSlVzKxxHQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -1152,6 +2328,15 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", @@ -1201,6 +2386,27 @@ "devtools-protocol": "*" } }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", + "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", + "dev": true + }, "node_modules/cli-cursor": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", @@ -1287,6 +2493,22 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", + "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", + "dev": true + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -1365,6 +2587,12 @@ "node": ">= 0.6" } }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, "node_modules/cookie": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", @@ -1420,6 +2648,27 @@ } } }, + "node_modules/create-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", + "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "prompts": "^2.0.1" + }, + "bin": { + "create-jest": "bin/create-jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -1509,12 +2758,35 @@ } } }, + "node_modules/dedent": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz", + "integrity": "sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==", + "dev": true, + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/define-data-property": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", @@ -1578,11 +2850,29 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/devtools-protocol": { "version": "0.0.1262051", "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1262051.tgz", "integrity": "sha512-YJe4CT5SA8on3Spa+UDtNhEqtuV6Epwz3OZ4HQVLhlRccpZ9/PAYk0/cy/oKxFKRrZPBUPyxympQci4yWNWZ9g==" }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -1611,6 +2901,24 @@ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, + "node_modules/electron-to-chromium": { + "version": "1.4.724", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.724.tgz", + "integrity": "sha512-RTRvkmRkGhNBPPpdrgtDKvmOEYTrPlXDfc0J/Nfq5s29tEahAwhiX4mmhNzj6febWMleulxVYPh7QwCSL/EldA==", + "dev": true + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, "node_modules/emoji-regex": { "version": "10.3.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", @@ -2132,28 +3440,53 @@ "dev": true }, "node_modules/execa": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", - "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, "dependencies": { "cross-spawn": "^7.0.3", - "get-stream": "^8.0.1", - "human-signals": "^5.0.0", - "is-stream": "^3.0.0", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", "merge-stream": "^2.0.0", - "npm-run-path": "^5.1.0", - "onetime": "^6.0.0", - "signal-exit": "^4.1.0", - "strip-final-newline": "^3.0.0" + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" }, "engines": { - "node": ">=16.17" + "node": ">=10" }, "funding": { "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "dev": true, + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, "node_modules/express": { "version": "4.19.2", "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", @@ -2293,6 +3626,15 @@ "reusify": "^1.0.4" } }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "dependencies": { + "bser": "2.1.1" + } + }, "node_modules/fd-slicer": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", @@ -2484,6 +3826,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -2522,13 +3873,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/get-stream": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", - "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true, "engines": { - "node": ">=16" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -2726,6 +4086,12 @@ "node": ">= 0.4" } }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, "node_modules/http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", @@ -2766,12 +4132,12 @@ } }, "node_modules/human-signals": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", - "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true, "engines": { - "node": ">=16.17.0" + "node": ">=10.17.0" } }, "node_modules/husky": { @@ -2849,6 +4215,25 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -3043,6 +4428,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -3132,12 +4526,12 @@ } }, "node_modules/is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -3211,27 +4605,726 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "engines": { + "node": ">=8" + } }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "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==", + "dev": true, "dependencies": { - "argparse": "^2.0.1" + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", + "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", + "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", + "dev": true, + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/types": "^29.6.3", + "import-local": "^3.0.2", + "jest-cli": "^29.7.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", + "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", + "dev": true, + "dependencies": { + "execa": "^5.0.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", + "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^1.0.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.7.0", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.7.0", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-cli": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", + "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", + "dev": true, + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "create-jest": "^29.7.0", + "exit": "^0.1.2", + "import-local": "^3.0.2", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-config": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", + "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-jest": "^29.7.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-docblock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", + "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", + "dev": true, + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", + "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "jest-util": "^29.7.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-leak-detector": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", + "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", + "dev": true, + "dependencies": { + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", + "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", + "dev": true, + "dependencies": { + "jest-regex-util": "^29.6.3", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", + "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", + "dev": true, + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/environment": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-leak-detector": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-resolve": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-util": "^29.7.0", + "jest-watcher": "^29.7.0", + "jest-worker": "^29.7.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", + "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/globals": "^29.7.0", + "@jest/source-map": "^29.6.3", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.7.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-snapshot/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watcher": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", + "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", + "dev": true, + "dependencies": { + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.7.0", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "dev": true, + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==" + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" } }, - "node_modules/jsbn": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", - "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==" - }, "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", @@ -3256,15 +5349,15 @@ "dev": true }, "node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, "bin": { "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" } }, "node_modules/jsonfile": { @@ -3287,78 +5380,221 @@ "json-buffer": "3.0.1" } }, - "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "engines": { + "node": ">=6" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lilconfig": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.0.0.tgz", + "integrity": "sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + }, + "node_modules/lint-staged": { + "version": "15.2.2", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.2.tgz", + "integrity": "sha512-TiTt93OPh1OZOsb5B7k96A/ATl2AjIZo+vnzFZ6oHK5FuTk63ByDtxGQpHm+kFETjEWqgkF95M8FRXKR/LEBcw==", + "dev": true, + "dependencies": { + "chalk": "5.3.0", + "commander": "11.1.0", + "debug": "4.3.4", + "execa": "8.0.1", + "lilconfig": "3.0.0", + "listr2": "8.0.1", + "micromatch": "4.0.5", + "pidtree": "0.6.0", + "string-argv": "0.3.2", + "yaml": "2.3.4" + }, + "bin": { + "lint-staged": "bin/lint-staged.js" + }, + "engines": { + "node": ">=18.12.0" + }, + "funding": { + "url": "https://opencollective.com/lint-staged" + } + }, + "node_modules/lint-staged/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/lint-staged/node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/lint-staged/node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true, + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/lint-staged/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/npm-run-path": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", + "dev": true, + "dependencies": { + "path-key": "^4.0.0" + }, "engines": { - "node": ">=6" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "node_modules/lint-staged/node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", "dev": true, "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" + "mimic-fn": "^4.0.0" }, "engines": { - "node": ">= 0.8.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lilconfig": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.0.0.tgz", - "integrity": "sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==", + "node_modules/lint-staged/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", "dev": true, "engines": { - "node": ">=14" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" - }, - "node_modules/lint-staged": { - "version": "15.2.2", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.2.tgz", - "integrity": "sha512-TiTt93OPh1OZOsb5B7k96A/ATl2AjIZo+vnzFZ6oHK5FuTk63ByDtxGQpHm+kFETjEWqgkF95M8FRXKR/LEBcw==", + "node_modules/lint-staged/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true, - "dependencies": { - "chalk": "5.3.0", - "commander": "11.1.0", - "debug": "4.3.4", - "execa": "8.0.1", - "lilconfig": "3.0.0", - "listr2": "8.0.1", - "micromatch": "4.0.5", - "pidtree": "0.6.0", - "string-argv": "0.3.2", - "yaml": "2.3.4" - }, - "bin": { - "lint-staged": "bin/lint-staged.js" - }, "engines": { - "node": ">=18.12.0" + "node": ">=14" }, "funding": { - "url": "https://opencollective.com/lint-staged" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/lint-staged/node_modules/chalk": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", - "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "node_modules/lint-staged/node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", "dev": true, "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" + "node": ">=12" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/listr2": { @@ -3418,6 +5654,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/log-update/node_modules/ansi-escapes": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.1.tgz", + "integrity": "sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/log-update/node_modules/ansi-regex": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", @@ -3489,11 +5737,69 @@ } }, "node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "dependencies": { + "semver": "^7.5.3" + }, "engines": { - "node": ">=12" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-dir/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "dependencies": { + "tmpl": "1.0.5" } }, "node_modules/media-typer": { @@ -3567,15 +5873,12 @@ } }, "node_modules/mimic-fn": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", - "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=6" } }, "node_modules/minimatch": { @@ -3658,6 +5961,18 @@ "node": ">= 0.4.0" } }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true + }, + "node_modules/node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "dev": true + }, "node_modules/nodemon": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.0.tgz", @@ -3734,6 +6049,12 @@ "node": ">=4" } }, + "node_modules/nodemon/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, "node_modules/nopt": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", @@ -3759,30 +6080,15 @@ } }, "node_modules/npm-run-path": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", - "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, "dependencies": { - "path-key": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "path-key": "^3.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm-run-path/node_modules/path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", - "dev": true, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, "node_modules/object-assign": { @@ -3897,15 +6203,15 @@ } }, "node_modules/onetime": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", - "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "dev": true, "dependencies": { - "mimic-fn": "^4.0.0" + "mimic-fn": "^2.1.0" }, "engines": { - "node": ">=12" + "node": ">=6" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -3958,6 +6264,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/pac-proxy-agent": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.1.tgz", @@ -4078,22 +6393,95 @@ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, "engines": { - "node": ">=8.6" + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", + "dev": true, + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" }, "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/pidtree": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", - "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, - "bin": { - "pidtree": "bin/pidtree.js" + "dependencies": { + "p-limit": "^2.2.0" }, "engines": { - "node": ">=0.10" + "node": ">=8" } }, "node_modules/possible-typed-array-names": { @@ -4141,6 +6529,32 @@ "node": ">=6.0.0" } }, + "node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -4196,6 +6610,14 @@ "node": ">= 14" } }, + "node_modules/proxy-agent/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "engines": { + "node": ">=12" + } + }, "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", @@ -4258,6 +6680,22 @@ "node": ">=18" } }, + "node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ] + }, "node_modules/qs": { "version": "6.11.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", @@ -4328,6 +6766,12 @@ "node": ">= 0.8" } }, + "node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, "node_modules/readable-stream": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", @@ -4402,6 +6846,27 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -4410,6 +6875,15 @@ "node": ">=4" } }, + "node_modules/resolve.exports": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", + "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/restore-cursor": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", @@ -4426,36 +6900,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/restore-cursor/node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/restore-cursor/node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/restore-cursor/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -4757,16 +7201,10 @@ } }, "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true }, "node_modules/simple-update-notifier": { "version": "2.0.0", @@ -4807,11 +7245,26 @@ "node": ">=10" } }, + "node_modules/simple-update-notifier/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, "node_modules/sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/slice-ansi": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", @@ -4891,9 +7344,9 @@ } }, "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", "dev": true, "dependencies": { "buffer-from": "^1.0.0", @@ -4905,6 +7358,27 @@ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==" }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -4955,6 +7429,19 @@ "node": ">=0.6.19" } }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/string-width": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.1.0.tgz", @@ -5060,24 +7547,21 @@ } }, "node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", "dev": true, "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/strip-final-newline": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", - "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", "dev": true, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=6" } }, "node_modules/strip-json-comments": { @@ -5187,6 +7671,30 @@ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true }, + "node_modules/terser/node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -5198,6 +7706,21 @@ "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -5242,6 +7765,27 @@ "strip-bom": "^3.0.0" } }, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/tsconfig-paths/node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/tslib": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", @@ -5259,6 +7803,15 @@ "node": ">= 0.8.0" } }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -5395,7 +7948,7 @@ "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "optional": true + "devOptional": true }, "node_modules/universalify": { "version": "2.0.1", @@ -5413,6 +7966,36 @@ "node": ">= 0.8" } }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -5452,6 +8035,20 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/v8-to-istanbul": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz", + "integrity": "sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -5460,6 +8057,15 @@ "node": ">= 0.8" } }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "dependencies": { + "makeerror": "1.0.12" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -5571,6 +8177,19 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, + "node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, "node_modules/ws": { "version": "8.16.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", @@ -5608,9 +8227,10 @@ } }, "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true }, "node_modules/yaml": { "version": "2.3.4", diff --git a/package.json b/package.json index b86cb637..860c4ee9 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,8 @@ "node-tests": "node ./tests/node/node_test_runner.js", "node-tests-single": "node ./tests/node/node_test_runner_single.js", "prepare": "husky install || true", - "build": "rollup -c" + "build": "rollup -c", + "unit:test": "node --experimental-vm-modules node_modules/jest/bin/jest.js" }, "devDependencies": { "@rollup/plugin-terser": "^0.4.4", @@ -43,6 +44,7 @@ "eslint-plugin-import": "^2.29.1", "eslint-plugin-prettier": "^5.1.3", "husky": "^9.0.11", + "jest": "^29.7.0", "lint-staged": "^15.2.2", "nodemon": "^3.1.0", "prettier": "^3.2.5", @@ -59,7 +61,8 @@ "prompts": "^2.4.2", "puppeteer": "^22.6.2", "tarn": "^3.0.2", - "uuid": "^9.0.1" + "uuid": "^9.0.1", + "zod": "^3.22.4" }, "lint-staged": { "*.js": "npx eslint --cache --fix", diff --git a/tests/unit/cache.test.js b/tests/unit/cache.test.js new file mode 100644 index 00000000..8086706c --- /dev/null +++ b/tests/unit/cache.test.js @@ -0,0 +1,24 @@ +// cacheManager.test.js +import { extractVersion, extractModuleName } from '../../lib/cache'; + +describe('extractVersion', () => { + it('should extract the Highcharts version correctly', () => { + const cache = { sources: '/* Highcharts 9.3.2 */' }; + + const version = extractVersion(cache); + expect(version).toBe('Highcharts 9.3.2'); + }); +}); + +describe('extractModuleName', () => { + it('should extract the module name from a given script path', () => { + const paths = [ + { input: 'modules/exporting', expected: 'exporting' }, + { input: 'maps/modules/map', expected: 'map' } + ]; + + paths.forEach(({ input, expected }) => { + expect(extractModuleName(input)).toBe(expected); + }); + }); +}); diff --git a/tests/unit/envs.test.js b/tests/unit/envs.test.js new file mode 100644 index 00000000..50a5fe61 --- /dev/null +++ b/tests/unit/envs.test.js @@ -0,0 +1,58 @@ +import { Config } from '../../lib/envs'; + +describe('Environment variables should be correctly parsed', () => { + test('HIGHCHARTS_VERSION accepts latests and not unrelated strings', () => { + const env = { HIGHCHARTS_VERSION: 'string-other-than-latest' }; + expect(() => Config.parse(env)).toThrow(); + + env.HIGHCHARTS_VERSION = 'latest'; + expect(Config.parse(env).HIGHCHARTS_VERSION).toEqual('latest'); + }); + + test('HIGHCHARTS_VERSION accepts proper version strings like XX.YY.ZZ', () => { + const env = { HIGHCHARTS_VERSION: '11' }; + expect(Config.parse(env).HIGHCHARTS_VERSION).toEqual('11'); + + env.HIGHCHARTS_VERSION = '11.0.0'; + expect(Config.parse(env).HIGHCHARTS_VERSION).toEqual('11.0.0'); + + env.HIGHCHARTS_VERSION = '9.1'; + expect(Config.parse(env).HIGHCHARTS_VERSION).toEqual('9.1'); + + env.HIGHCHARTS_VERSION = '11a.2.0'; + expect(() => Config.parse(env)).toThrow(); + }); + + test('HIGHCHARTS_CDN_URL should start with http:// or https://', () => { + const env = { HIGHCHARTS_CDN_URL: 'http://example.com' }; + expect(Config.parse(env).HIGHCHARTS_CDN_URL).toEqual('http://example.com'); + + env.HIGHCHARTS_CDN_URL = 'https://example.com'; + expect(Config.parse(env).HIGHCHARTS_CDN_URL).toEqual('https://example.com'); + + env.HIGHCHARTS_CDN_URL = 'example.com'; + expect(() => Config.parse(env)).toThrow(); + }); + + test('CORE_SCRIPTS, MODULES, INDICATORS should be arrays', () => { + const env = { + HIGHCHARTS_CORE_SCRIPTS: 'core1, core2', + HIGHCHARTS_MODULES: 'module1, module2', + HIGHCHARTS_INDICATORS: 'indicator1, indicator2' + }; + + const parsed = Config.parse(env); + + expect(parsed.HIGHCHARTS_CORE_SCRIPTS).toEqual(['core1', 'core2']); + expect(parsed.HIGHCHARTS_MODULES).toEqual(['module1', 'module2']); + expect(parsed.HIGHCHARTS_INDICATORS).toEqual(['indicator1', 'indicator2']); + }); + + test('HIGHCHARTS_FORCE_FETCH should be a boolean', () => { + const env = { HIGHCHARTS_FORCE_FETCH: 'true' }; + expect(Config.parse(env).HIGHCHARTS_FORCE_FETCH).toEqual(true); + + env.HIGHCHARTS_FORCE_FETCH = 'false'; + expect(Config.parse(env).HIGHCHARTS_FORCE_FETCH).toEqual(false); + }); +}); diff --git a/tests/unit/index.test.js b/tests/unit/index.test.js new file mode 100644 index 00000000..85e102db --- /dev/null +++ b/tests/unit/index.test.js @@ -0,0 +1,8 @@ +describe('Simple Variable Comparison', () => { + it('should compare two variables for equality', () => { + const variable1 = 42; + const variable2 = 42; + + expect(variable1).toBe(variable2); + }); +}); diff --git a/tests/unit/utils.test.js b/tests/unit/utils.test.js new file mode 100644 index 00000000..7c89f52d --- /dev/null +++ b/tests/unit/utils.test.js @@ -0,0 +1,168 @@ +import { + clearText, + fixType, + roundNumber, + toBoolean, + isCorrectJSON, + isObject, + isObjectEmpty, + isPrivateRangeUrlFound +} from '../../lib/utils'; + +describe('clearText', () => { + it('replaces multiple spaces with a single space and trims the text', () => { + const input = ' This is a test '; + const expected = 'This is a test'; + expect(clearText(input)).toBe(expected); + }); +}); + +describe('fixType', () => { + it('corrects the export type based on file extension', () => { + expect(fixType('image/jpeg', 'output.png')).toBe('png'); + }); + + it('returns the original type if no outfile is provided', () => { + expect(fixType('pdf')).toBe('pdf'); + }); +}); + +describe('roundNumber', () => { + it('rounds a number to the specified precision', () => { + expect(roundNumber(3.14159, 2)).toBe(3.14); + expect(roundNumber(0.1 + 0.2, 1)).toBe(0.3); + }); +}); + +describe('toBoolean', () => { + it('converts various values to their boolean equivalent', () => { + expect(toBoolean('true')).toBe(true); + expect(toBoolean('')).toBe(false); + expect(toBoolean('false')).toBe(false); + expect(toBoolean(undefined)).toBe(false); + expect(toBoolean('any string')).toBe(true); + }); +}); + +describe('isCorrectJSON', () => { + it('parses valid JSON strings', () => { + const json = '{"key":"value"}'; + expect(isCorrectJSON(json)).toEqual({ key: 'value' }); + }); + + it('returns false for invalid JSON strings', () => { + const json = '{"key":value}'; + expect(isCorrectJSON(json)).toBe(false); + }); + + it('parses JavaScript objects', () => { + const obj = { key: 'value' }; + expect(isCorrectJSON(obj)).toEqual({ key: 'value' }); + }); + + it('returns a stringified version of a valid JSON/object when toString is true', () => { + const obj = { key: 'value' }; + const json = '{"key":"value"}'; + expect(isCorrectJSON(obj, true)).toBe(json); + expect(isCorrectJSON(json, true)).toBe(json); + }); + + it('handles non-JSON strings', () => { + const str = 'Just a string'; + expect(isCorrectJSON(str)).toBe(false); + }); + + it('handles non-object types (e.g., numbers, booleans)', () => { + expect(isCorrectJSON(123)).toBe(123); + expect(isCorrectJSON(true)).toBe(true); + }); + + it('correctly parses and stringifies an array when toString is true', () => { + const arr = [1, 2, 3]; + expect(isCorrectJSON(arr, true)).toBe('[1,2,3]'); + }); +}); + +describe('isObject', () => { + it('returns true for plain objects', () => { + expect(isObject({})).toBe(true); + expect(isObject({ key: 'value' })).toBe(true); + }); + + it('returns false for arrays', () => { + expect(isObject([])).toBe(false); + expect(isObject([1, 2, 3])).toBe(false); + }); + + it('returns false for null', () => { + expect(isObject(null)).toBe(false); + }); + + it('returns false for non-object types', () => { + expect(isObject(123)).toBe(false); + expect(isObject('string')).toBe(false); + expect(isObject(true)).toBe(false); + expect(isObject(undefined)).toBe(false); + expect(isObject(() => {})).toBe(false); + }); +}); + +describe('isObjectEmpty', () => { + it('returns true for an empty object', () => { + expect(isObjectEmpty({})).toBe(true); + }); + + it('returns false for a non-empty object', () => { + expect(isObjectEmpty({ key: 'value' })).toBe(false); + }); + + it('returns false for non-object types, even if "empty"', () => { + expect(isObjectEmpty(null)).toBe(false); // Even though null is technically an "empty" value, it's not an object. + expect(isObjectEmpty([])).toBe(false); // Arrays are objects, but this function specifically checks for plain objects. + expect(isObjectEmpty('')).toBe(false); // A string is not an object. + expect(isObjectEmpty(0)).toBe(false); // A number is not an object. + }); + + it('handles complex objects correctly', () => { + expect(isObjectEmpty({ key: undefined })).toBe(false); // An object with a key undefined is still considered not empty. + expect(isObjectEmpty({ key: null })).toBe(false); // Same for a key with a null value. + }); +}); + +describe('isPrivateRangeUrlFound', () => { + it('returns true for URLs with private IP ranges', () => { + const testCases = [ + 'xlink:href="http://localhost/path/to/resource"', + 'xlink:href="https://127.0.0.1/path/to/resource"', + 'xlink:href="http://10.0.0.1/path/to/resource"', + 'xlink:href="http://172.16.0.1/path/to/resource"', + 'xlink:href="https://192.168.1.1/path/to/resource"' + ]; + testCases.forEach((testCase) => { + expect(isPrivateRangeUrlFound(testCase)).toBe(true); + }); + }); + + it('returns false for URLs with public IP ranges or non-IP strings', () => { + const testCases = [ + 'xlink:href="https://8.8.8.8/path/to/resource"', + 'xlink:href="http://www.example.com/path/to/resource"', + 'Just a regular string without any URL', + 'xlink:href="https://172.32.0.1/path/to/resource"', // IP outside the private range + '' + ]; + testCases.forEach((testCase) => { + expect(isPrivateRangeUrlFound(testCase)).toBe(false); + }); + }); + + it('returns false for malformed URLs', () => { + const testCases = [ + 'xlink:href="http:///malformed.url"', + 'xlink:href="https://:80"' + ]; + testCases.forEach((testCase) => { + expect(isPrivateRangeUrlFound(testCase)).toBe(false); + }); + }); +});