@decaf-ts/utils 0.10.3 → 0.11.1-0.experimental.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/utils.cjs +2561 -2
- package/dist/utils.js +2602 -2
- package/lib/assets/slogans.cjs +1 -1
- package/lib/bin/build-scripts.cjs +1 -1
- package/lib/bin/tag-release.cjs +1 -1
- package/lib/cli/command.cjs +1 -1
- package/lib/cli/commands/build-scripts.cjs +74 -14
- package/lib/cli/commands/build-scripts.d.ts +62 -2
- package/lib/cli/commands/index.cjs +1 -1
- package/lib/cli/commands/tag-release.cjs +1 -1
- package/lib/cli/constants.cjs +1 -1
- package/lib/cli/index.cjs +1 -1
- package/lib/cli/types.cjs +1 -1
- package/lib/esm/assets/slogans.js +1 -1
- package/lib/esm/bin/build-scripts.js +1 -1
- package/lib/esm/bin/tag-release.js +1 -1
- package/lib/esm/cli/command.js +1 -1
- package/lib/esm/cli/commands/build-scripts.d.ts +62 -2
- package/lib/esm/cli/commands/build-scripts.js +74 -14
- package/lib/esm/cli/commands/index.js +1 -1
- package/lib/esm/cli/commands/tag-release.js +1 -1
- package/lib/esm/cli/constants.js +1 -1
- package/lib/esm/cli/index.js +1 -1
- package/lib/esm/cli/types.js +1 -1
- package/lib/esm/index.d.ts +1 -1
- package/lib/esm/index.js +2 -2
- package/lib/esm/input/index.js +1 -1
- package/lib/esm/input/input.js +1 -1
- package/lib/esm/input/types.js +1 -1
- package/lib/esm/output/common.js +1 -1
- package/lib/esm/output/index.js +1 -1
- package/lib/esm/tests/Consumer.d.ts +106 -0
- package/lib/esm/tests/Consumer.js +79 -1
- package/lib/esm/tests/ProducerChildProcess.js +1 -1
- package/lib/esm/tests/TestReporter.d.ts +3 -0
- package/lib/esm/tests/TestReporter.js +20 -2
- package/lib/esm/tests/index.d.ts +3 -1
- package/lib/esm/tests/index.js +4 -2
- package/lib/esm/tests/jestPerformanceRunner.d.ts +7 -0
- package/lib/esm/tests/jestPerformanceRunner.js +15 -0
- package/lib/esm/tests/utils.d.ts +5 -0
- package/lib/esm/tests/utils.js +33 -0
- package/lib/esm/utils/constants.js +1 -1
- package/lib/esm/utils/fs.d.ts +1 -1
- package/lib/esm/utils/fs.js +76 -29
- package/lib/esm/utils/http.js +1 -1
- package/lib/esm/utils/index.d.ts +1 -0
- package/lib/esm/utils/index.js +2 -1
- package/lib/esm/utils/md.js +1 -1
- package/lib/esm/utils/performanceRunner.d.ts +126 -0
- package/lib/esm/utils/performanceRunner.js +344 -0
- package/lib/esm/utils/timeout.js +1 -1
- package/lib/esm/utils/types.js +1 -1
- package/lib/esm/utils/utils.js +1 -1
- package/lib/esm/writers/OutputWriter.js +1 -1
- package/lib/esm/writers/RegexpOutputWriter.js +1 -1
- package/lib/esm/writers/StandardOutputWriter.js +11 -4
- package/lib/esm/writers/index.js +1 -1
- package/lib/esm/writers/types.js +1 -1
- package/lib/index.cjs +2 -2
- package/lib/index.d.ts +1 -1
- package/lib/input/index.cjs +1 -1
- package/lib/input/input.cjs +1 -1
- package/lib/input/types.cjs +1 -1
- package/lib/output/common.cjs +1 -1
- package/lib/output/index.cjs +1 -1
- package/lib/tests/Consumer.cjs +79 -1
- package/lib/tests/Consumer.d.ts +106 -0
- package/lib/tests/ProducerChildProcess.cjs +1 -1
- package/lib/tests/TestReporter.cjs +20 -2
- package/lib/tests/TestReporter.d.ts +3 -0
- package/lib/tests/index.cjs +4 -2
- package/lib/tests/index.d.ts +3 -1
- package/lib/tests/jestPerformanceRunner.cjs +19 -0
- package/lib/tests/jestPerformanceRunner.d.ts +7 -0
- package/lib/tests/utils.cjs +36 -0
- package/lib/tests/utils.d.ts +5 -0
- package/lib/utils/constants.cjs +1 -1
- package/lib/utils/fs.cjs +76 -29
- package/lib/utils/fs.d.ts +1 -1
- package/lib/utils/http.cjs +1 -1
- package/lib/utils/index.cjs +2 -1
- package/lib/utils/index.d.ts +1 -0
- package/lib/utils/md.cjs +1 -1
- package/lib/utils/performanceRunner.cjs +384 -0
- package/lib/utils/performanceRunner.d.ts +126 -0
- package/lib/utils/timeout.cjs +1 -1
- package/lib/utils/types.cjs +1 -1
- package/lib/utils/utils.cjs +1 -1
- package/lib/writers/OutputWriter.cjs +1 -1
- package/lib/writers/RegexpOutputWriter.cjs +1 -1
- package/lib/writers/StandardOutputWriter.cjs +11 -4
- package/lib/writers/index.cjs +1 -1
- package/lib/writers/types.cjs +1 -1
- package/package.json +17 -10
- package/workdocs/assets/slogans.json +802 -0
- package/dist/utils.cjs.map +0 -1
- package/dist/utils.js.map +0 -1
- package/lib/assets/slogans.js.map +0 -1
- package/lib/bin/build-scripts.js.map +0 -1
- package/lib/bin/tag-release.js.map +0 -1
- package/lib/cli/command.js.map +0 -1
- package/lib/cli/commands/build-scripts.js.map +0 -1
- package/lib/cli/commands/index.js.map +0 -1
- package/lib/cli/commands/tag-release.js.map +0 -1
- package/lib/cli/constants.js.map +0 -1
- package/lib/cli/index.js.map +0 -1
- package/lib/cli/types.js.map +0 -1
- package/lib/esm/assets/slogans.js.map +0 -1
- package/lib/esm/bin/build-scripts.js.map +0 -1
- package/lib/esm/bin/tag-release.js.map +0 -1
- package/lib/esm/cli/command.js.map +0 -1
- package/lib/esm/cli/commands/build-scripts.js.map +0 -1
- package/lib/esm/cli/commands/index.js.map +0 -1
- package/lib/esm/cli/commands/tag-release.js.map +0 -1
- package/lib/esm/cli/constants.js.map +0 -1
- package/lib/esm/cli/index.js.map +0 -1
- package/lib/esm/cli/types.js.map +0 -1
- package/lib/esm/index.js.map +0 -1
- package/lib/esm/input/index.js.map +0 -1
- package/lib/esm/input/input.js.map +0 -1
- package/lib/esm/input/types.js.map +0 -1
- package/lib/esm/output/common.js.map +0 -1
- package/lib/esm/output/index.js.map +0 -1
- package/lib/esm/tests/Consumer.js.map +0 -1
- package/lib/esm/tests/ProducerChildProcess.js.map +0 -1
- package/lib/esm/tests/TestReporter.js.map +0 -1
- package/lib/esm/tests/index.js.map +0 -1
- package/lib/esm/utils/constants.js.map +0 -1
- package/lib/esm/utils/fs.js.map +0 -1
- package/lib/esm/utils/http.js.map +0 -1
- package/lib/esm/utils/index.js.map +0 -1
- package/lib/esm/utils/md.js.map +0 -1
- package/lib/esm/utils/tests.d.ts +0 -1
- package/lib/esm/utils/tests.js +0 -2
- package/lib/esm/utils/tests.js.map +0 -1
- package/lib/esm/utils/timeout.js.map +0 -1
- package/lib/esm/utils/types.js.map +0 -1
- package/lib/esm/utils/utils.js.map +0 -1
- package/lib/esm/writers/OutputWriter.js.map +0 -1
- package/lib/esm/writers/RegexpOutputWriter.js.map +0 -1
- package/lib/esm/writers/StandardOutputWriter.js.map +0 -1
- package/lib/esm/writers/index.js.map +0 -1
- package/lib/esm/writers/types.js.map +0 -1
- package/lib/index.js.map +0 -1
- package/lib/input/index.js.map +0 -1
- package/lib/input/input.js.map +0 -1
- package/lib/input/types.js.map +0 -1
- package/lib/output/common.js.map +0 -1
- package/lib/output/index.js.map +0 -1
- package/lib/tests/Consumer.js.map +0 -1
- package/lib/tests/ProducerChildProcess.js.map +0 -1
- package/lib/tests/TestReporter.js.map +0 -1
- package/lib/tests/index.js.map +0 -1
- package/lib/utils/constants.js.map +0 -1
- package/lib/utils/fs.js.map +0 -1
- package/lib/utils/http.js.map +0 -1
- package/lib/utils/index.js.map +0 -1
- package/lib/utils/md.js.map +0 -1
- package/lib/utils/tests.cjs +0 -18
- package/lib/utils/tests.d.ts +0 -1
- package/lib/utils/tests.js.map +0 -1
- package/lib/utils/timeout.js.map +0 -1
- package/lib/utils/types.js.map +0 -1
- package/lib/utils/utils.js.map +0 -1
- package/lib/writers/OutputWriter.js.map +0 -1
- package/lib/writers/RegexpOutputWriter.js.map +0 -1
- package/lib/writers/StandardOutputWriter.js.map +0 -1
- package/lib/writers/index.js.map +0 -1
- package/lib/writers/types.js.map +0 -1
package/dist/utils.js
CHANGED
|
@@ -1,2 +1,2602 @@
|
|
|
1
|
-
import e from"prompts";import{parseArgs as t}from"util";import{Logging as o,escapeRegExp as a,LoggedClass as s,LoggedEnvironment as r,LogLevel as n}from"@decaf-ts/logging";import i from"fs";import c from"path";import{spawn as l}from"child_process";import{style as g}from"styled-string-builder";import f from"zlib";import d from"https";import{rollup as h}from"rollup";import u from"@rollup/plugin-typescript";import m from"@rollup/plugin-commonjs";import{nodeResolve as p}from"@rollup/plugin-node-resolve";import S from"@rollup/plugin-json";import{builtinModules as y}from"module";import*as T from"typescript";import{ModuleKind as b}from"typescript";class w{static{this.logger=o.for(w)}constructor(e){this.type="text",this.name=e}setType(e){return w.logger.verbose("Setting type to: "+e),this.type=e,this}setMessage(e){return w.logger.verbose("Setting message to: "+e),this.message=e,this}setInitial(e){return w.logger.verbose("Setting initial value to: "+e),this.initial=e,this}setStyle(e){return w.logger.verbose("Setting style to: "+e),this.style=e,this}setFormat(e){return w.logger.verbose("Setting format function"),this.format=e,this}setValidate(e){return w.logger.verbose("Setting validate function"),this.validate=e,this}setOnState(e){return w.logger.verbose("Setting onState callback"),this.onState=e,this}setMin(e){return w.logger.verbose("Setting min value to: "+e),this.min=e,this}setMax(e){return w.logger.verbose("Setting max value to: "+e),this.max=e,this}setFloat(e){return w.logger.verbose("Setting float to: "+e),this.float=e,this}setRound(e){return w.logger.verbose("Setting round to: "+e),this.round=e,this}setInstructions(e){return w.logger.verbose("Setting instructions to: "+e),this.instructions=e,this}setIncrement(e){return w.logger.verbose("Setting increment to: "+e),this.increment=e,this}setSeparator(e){return w.logger.verbose("Setting separator to: "+e),this.separator=e,this}setActive(e){return w.logger.verbose("Setting active style to: "+e),this.active=e,this}setInactive(e){return w.logger.verbose("Setting inactive style to: "+e),this.inactive=e,this}setChoices(e){return w.logger.verbose("Setting choices: "+JSON.stringify(e)),this.choices=e,this}setHint(e){return w.logger.verbose("Setting hint to: "+e),this.hint=e,this}setWarn(e){return w.logger.verbose("Setting warn to: "+e),this.warn=e,this}setSuggest(e){return w.logger.verbose("Setting suggest function"),this.suggest=e,this}setLimit(e){return w.logger.verbose("Setting limit to: "+e),this.limit=e,this}setMask(e){return w.logger.verbose("Setting mask to: "+e),this.mask=e,this}setStdout(e){return w.logger.verbose("Setting stdout stream"),this.stdout=e,this}setStdin(e){return this.stdin=e,this}async ask(){return(await w.ask(this))[this.name]}static async ask(t){const o=w.logger.for(this.ask);let a;Array.isArray(t)||(t=[t]);try{o.verbose("Asking questions: "+t.map(e=>e.name).join(", ")),a=await e(t),o.verbose("Received answers: "+JSON.stringify(a,null,2))}catch(e){throw Error("Error while getting input: "+e)}return a}static async askNumber(e,t,o,a,s){w.logger.for(this.askNumber).verbose(`Asking number input: undefined, question: ${t}, min: ${o}, max: ${a}, initial: ${s}`);const r=new w(e).setMessage(t).setType("number");return"number"==typeof o&&r.setMin(o),"number"==typeof a&&r.setMax(a),"number"==typeof s&&r.setInitial(s),(await this.ask(r))[e]}static async askText(e,t,o=void 0,a){w.logger.for(this.askText).verbose(`Asking text input: undefined, question: ${t}, mask: ${o}, initial: ${a}`);const s=new w(e).setMessage(t);return o&&s.setMask(o),"string"==typeof a&&s.setInitial(a),(await this.ask(s))[e]}static async askConfirmation(e,t,o){w.logger.for(this.askConfirmation).verbose(`Asking confirmation input: undefined, question: ${t}, initial: ${o}`);const a=new w(e).setMessage(t).setType("confirm");return void 0!==o&&a.setInitial(o),(await this.ask(a))[e]}static async insist(e,t,o,a=1){const s=w.logger.for(this.insist);let r;s.verbose(`Insisting on input: ${e.name}, test: ${t.toString()}, defaultConfirmation: ${o}, limit: ${a}`);let n,i=0;try{do{r=(await w.ask(e))[e.name],t(r)?(n=await w.askConfirmation(e.name+"-confirm",`Is the ${e.type} correct?`,o),n||(r=void 0)):r=void 0}while(void 0===r&&a>1&&i++<a)}catch(e){throw s.error("Error while insisting: "+e),e}return void 0===r&&s.info("no selection..."),r}static async insistForText(e,t,o,a=void 0,s,r=!1,n=-1){w.logger.for(this.insistForText).verbose(`Insisting for text input: undefined, question: ${t}, test: ${o.toString()}, mask: ${a}, initial: ${s}, defaultConfirmation: ${r}, limit: ${n}`);const i=new w(e).setMessage(t);return a&&i.setMask(a),"string"==typeof s&&i.setInitial(s),await this.insist(i,o,r,n)}static async insistForNumber(e,t,o,a,s,r,n=!1,i=-1){w.logger.for(this.insistForNumber).verbose(`Insisting for number input: undefined, question: ${t}, test: ${o.toString()}, min: ${a}, max: ${s}, initial: ${r}, defaultConfirmation: ${n}, limit: ${i}`);const c=new w(e).setMessage(t).setType("number");return"number"==typeof a&&c.setMin(a),"number"==typeof s&&c.setMax(s),"number"==typeof r&&c.setInitial(r),await this.insist(c,o,n,i)}static parseArgs(e){const o=w.logger.for(this.parseArgs),a={args:process.argv.slice(2),options:e};o.debug("Parsing arguments: "+JSON.stringify(a,null,2));try{return t(a)}catch(t){throw o.debug(`Error while parsing arguments:\n${JSON.stringify(a,null,2)}\n | options\n${JSON.stringify(e,null,2)}\n | ${t}`),Error("Error while parsing arguments: "+t)}}}const C={verbose:{type:"boolean",short:"V",default:void 0},version:{type:"boolean",short:"v",default:void 0},help:{type:"boolean",short:"h",default:!1},logLevel:{type:"string",default:"info"},logStyle:{type:"boolean",default:!0},timestamp:{type:"boolean",default:!0},banner:{type:"boolean",default:!0}},D=Object.keys(C).reduce((e,t)=>(e[t]=C[t].default,e),{}),v="utf-8",k=/^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z])))/g;var $;(e=>{e.PATCH="patch",e.MINOR="minor",e.MAJOR="major"})($||($={}));const E="-no-ci",I="postinstall";var F;(e=>{e.GIT=".token",e.NPM=".npmtoken",e.DOCKER=".dockertoken",e.CONFLUENCE=".confluence-token"})(F||(F={}));const N="Aborted";class x{constructor(e,t,...a){this.cmd=e,this.lock=t,this.logger=o.for(this.cmd)}log(e,t){t=Buffer.isBuffer(t)?t.toString(v):t;const o="stderr"===e?g(t).red.text:t;this.logger.info(o)}data(e){this.log("stdout",e+"")}error(e){this.log("stderr",e+"")}errors(e){this.log("stderr","Error executing command exited : "+e)}exit(e,t){this.log("stdout","command exited code : "+(0===e?g(e.toString()).green.text:g(null===e?"null":e.toString()).red.text)),0===e?this.resolve(t.map(e=>e.trim()).join("\n")):this.reject(Error(t.length?t.join("\n"):e.toString()))}parseCommand(e){return e="string"==typeof e?e.split(" "):e,this.cmd=e.join(" "),[e[0],e.slice(1)]}resolve(e){this.log("stdout",`${this.cmd} executed successfully: ${g(e?"ran to completion":e).green}`),this.lock.resolve(e)}reject(e){e instanceof Error||(e=Error("number"==typeof e?"Exit code "+e:e)),this.log("stderr",`${this.cmd} failed to execute: ${g(e.message).red}`),this.lock.reject(e)}}function A(e){let t=Promise.resolve();return(...o)=>{const a=t.then(()=>e(...o));return t=a.catch(()=>{}),a}}function j(e,...t){let o,a;if(e instanceof AbortSignal?(a=new AbortController,o=[e,...t]):(a=e,o=t),a.signal.aborted)return a;const s=()=>a.abort();for(const e of o){if(e.aborted){a.abort();break}e.addEventListener("abort",s,{once:!0,signal:a.signal})}return a}function B(e,t,o,a,s){function r(t,a){const[r,n]=e.parseCommand(t);s.info("Running command: "+r),s.debug("with args: "+n.join(" "));const i=l(r,n,{...o,cwd:o.cwd||process.cwd(),env:Object.assign({},process.env,o.env,{PATH:process.env.PATH}),shell:o.shell||!1,signal:a.signal});return s.verbose("pid : "+i.pid),i}const n=t.match(/[<>$#]/g);if(n)throw Error(`Invalid command: ${t}. contains invalid characters: ${n}`);if(t.includes(" | ")){const e=t.split(" | "),o=[],s=Array(e.length);s[0]=a;for(let t=0;t<e.length;t++)0!==t&&(s[t]=j(s[t-1].signal)),o.push(r(e[t],s[t])),0!==t&&o[t-1].stdout.pipe(o[t].stdin);return o[e.length-1]}return r(t,a)}function M(e,t={},a=x,...s){const r=o.for(M),n=new AbortController,i={abort:n,command:e,logs:[],errs:[]},c=new Promise((o,c)=>{let l;try{l=new a(e,{resolve:o,reject:c},...s),i.cmd=B(l,e,t,n,r)}catch(t){return c(Error(`Error running command ${e}: ${t}`))}i.cmd.stdout.setEncoding("utf8"),i.cmd.stdout.on("data",e=>{e=e.toString(),i.logs.push(e),l.data(e)}),i.cmd.stderr.on("data",e=>{e=e.toString(),i.errs.push(e),l.error(e)}),i.cmd.once("error",e=>{l.exit(e.message,i.errs)}),i.cmd.once("exit",(e=0)=>{n.signal.aborted&&null===e&&(e=N),l.exit(e,0===e?i.logs:i.errs)})});return Object.assign(i,{promise:c,pipe:async t=>{const o=r.for("pipe");try{o.verbose(`Executing pipe function ${e}...`);const a=await c;return o.verbose(`Piping output to ${t.name}: ${a}`),t(a)}catch(e){throw o.error("Error piping command output: "+e),e}}}),i}const P=o.for("fs");function U(e,t,o){const s=P.for(U);if(!i.existsSync(e))throw Error(`File not found at path "${e}".`);let r=O(e);s.verbose(`Patching file "${e}"...`),s.debug("with value: "+JSON.stringify(t));try{r=((e,t,o="g",s)=>(Object.entries(t).forEach(([t,r])=>{const n=RegExp(a(t),o);e=e.replace(n,e=>(!s||s(e),r))}),e))(r,t,"g",o)}catch(e){throw Error("Error patching file: "+e)}L(e,r)}function O(e){const t=P.for(O);try{return t.verbose(`Reading file "${e}"...`),i.readFileSync(e,"utf8")}catch(o){throw t.verbose(`Error reading file "${e}": ${o}`),Error(`Error reading file "${e}": ${o}`)}}function L(e,t){const o=P.for(L);try{o.verbose(`Writing file "${e} with ${t.length} bytes...`),i.writeFileSync(e,t,"utf8")}catch(t){throw o.verbose(`Error writing file "${e}": ${t}`),Error(`Error writing file "${e}": ${t}`)}}function R(e,t){const o=P.for(R),a=[];try{return o.verbose(`Retrieving all files from "${e}"...`),i.readdirSync(e).forEach(t=>{const o=c.join(e,t),s=i.statSync(o);s.isFile()?a.push(o):s.isDirectory()&&a.push(...R(o))}),t?a.filter(t):a}catch(t){throw o.verbose(`Error retrieving files from "${e}": ${t}`),Error(`Error retrieving files from "${e}": ${t}`)}}async function J(e,t){const o=P.for(J);let a,s;try{a=i.statSync(e)}catch(t){throw o.verbose(`Source path "${e}" does not exist: ${t}`),Error(`Source path "${e}" does not exist: ${t}`)}try{s=i.statSync(t)}catch(e){}if(s)throw o.verbose(`Destination path "${t}" already exists`),Error(`Destination path "${t}" already exists`);try{o.verbose(`Renaming ${a.isFile()?"file":"directory"} "${e}" to "${t}...`),i.renameSync(e,t),o.verbose(`Successfully renamed to "${t}"`)}catch(s){throw o.verbose(`Error renaming ${a.isFile()?"file":"directory"} "${e}" to "${t}": ${s}`),Error(`Error renaming ${a.isFile()?"file":"directory"} "${e}" to "${t}": ${s}`)}}function W(e,t){const o=P.for(W);let a,s;try{a=i.statSync(e)}catch(t){throw o.verbose(`Source path "${e}" does not exist: ${t}`),Error(`Source path "${e}" does not exist: ${t}`)}try{s=i.statSync(t)}catch(e){a.isDirectory()&&(o.verbose(`Dest path "${t}" does not exist. creating`),i.mkdirSync(t,{recursive:!0}))}try{o.verbose(`Copying ${a.isFile()?"file":"directory"} "${e}" to "${t}...`),i.cpSync(e,t,{recursive:!0})}catch(s){throw o.verbose(`Error copying ${a.isFile()?"file":"directory"} "${e}" to "${t}: ${s}`),Error(`Error copying ${a.isFile()?"file":"directory"} "${e}" to "${t}: ${s}`)}}function X(e){const t=P.for(X);try{const o=i.statSync(e);o.isFile()?(t.verbose(`Deleting file "${e}...`),i.rmSync(e,{recursive:!0,force:!0})):o.isDirectory()&&i.rmSync(e,{recursive:!0,force:!0})}catch(o){throw t.verbose(`Error Deleting "${e}": ${o}`),Error(`Error Deleting "${e}": ${o}`)}}function V(e=process.cwd(),t){let o;try{o=JSON.parse(O(c.join(e,"package.json")))}catch(e){throw Error('Failed to retrieve package information" '+e)}if(t){if(!(t in o))throw Error(`Property "${t}" not found in package.json`);return o[t]}return o}function G(e,t,o=process.cwd()){const a=V(o);a[e]=t,L(c.join(o,"package.json"),JSON.stringify(a,null,2))}function _(e=process.cwd()){return V(e,"version")}async function H(e=process.cwd()){let t;try{t=JSON.parse(await M("npm ls --json",{cwd:e}).promise)}catch(e){throw Error("Failed to retrieve dependencies: "+e)}const o=(e,t)=>({name:e[0],version:e[1].version});return{prod:Object.entries(t.dependencies||{}).map(o),dev:Object.entries(t.devDependencies||{}).map(o),peer:Object.entries(t.peerDependencies||{}).map(o)}}async function K(){const e=P.for(K);e.info("checking for updates..."),await M("npx npm-check-updates -u").promise,e.info("updating..."),await M("npx npm run do-install").promise}async function z(e,t){if(!t){const e=await H();t={prod:e.prod?.map(e=>e.name)||[],dev:e.dev?.map(e=>e.name)||[],peer:e.peer?.map(e=>e.name)||[]}}const{prod:o,dev:a,peer:s}=t,r=Array.from(new Set([...o||[],...a||[],...s||[]])),n=(e="string"==typeof e?[e]:e).filter(e=>!r.includes(e));return n.length&&await q({dev:n}),t.dev=t.dev||[],t.dev.push(...n),t}async function Y(){const e=P.for(Y),t=await M("git config user.name").promise,o=await M("git config user.email").promise;e.verbose(`cached git id: ${t}/${o}. changing to automation`),await M('git config user.email "automation@decaf.ts"').promise,await M('git config user.name "decaf"').promise,e.info("Pushing changes to git..."),await M("git add .").promise,await M('git commit -m "refs #1 - after repo setup"').promise,await M("git push").promise,await M(`git config user.email "${o}"`).promise,await M(`git config user.name "${t}"`).promise,e.verbose(`reverted to git id: ${t}/${o}`)}async function q(e){const t=P.for(q),o=e.prod||[],a=e.dev||[],s=e.peer||[];o.length&&(t.info(`Installing dependencies ${o.join(", ")}...`),await M("npm install "+o.join(" "),{cwd:process.cwd()}).promise),a.length&&(t.info(`Installing devDependencies ${a.join(", ")}...`),await M("npm install --save-dev "+a.join(" "),{cwd:process.cwd()}).promise),s.length&&(t.info(`Installing peerDependencies ${s.join(", ")}...`),await M("npm install --save-peer "+s.join(" "),{cwd:process.cwd()}).promise)}async function Z(e){return e.then(e=>e.default||e)}async function Q(e){const t=P.for(Q);try{const o=i.readdirSync(e).map(t=>c.join(e,t)).filter(e=>{try{return i.statSync(e).isFile()&&(e.endsWith(".js")||e.endsWith(".cjs")||e.endsWith(".mjs"))}catch{return!1}});if(0===o.length)throw Error("No JS files found in directory "+e);let a=o[0],s=i.statSync(a).size;for(const e of o.slice(1)){const t=i.statSync(e).size;s>t&&(a=e,s=t)}t.verbose(`Selected smallest bundle: ${a} (${s} bytes)`);const r=i.readFileSync(a),n=f.gzipSync(r),l=Number((n.length/1024).toFixed(1));return t.verbose(`Gzipped size: ${n.length} bytes (${l} KB)`),l}catch(o){throw t.verbose(`Failed to compute gzipped size for ${e}: ${o}`),o}}function ee(e=process.cwd(),t){const o=P.for(ee);try{return i.existsSync(e)?i.readdirSync(e,{withFileTypes:!0}).filter(e=>!t||t(e.name,e)).map(e=>e.name):[]}catch(t){return o.verbose(`Failed to list folder ${e}: ${t}`),[]}}function te(e=c.join(process.cwd(),"node_modules")){const t=P.for(te);try{if(!i.existsSync(e))return[];const o=i.readdirSync(e,{withFileTypes:!0}),a=[];for(const s of o)try{if(!s.isDirectory())continue;if(s.name.startsWith("."))continue;if(s.name.startsWith("@")){const o=c.join(e,s.name);try{const e=i.readdirSync(o,{withFileTypes:!0});for(const t of e)t.isDirectory()&&!t.name.startsWith(".")&&a.push(`${s.name}/${t.name}`)}catch(e){t.verbose(`Failed to read scope ${o}: ${e}`)}}else a.push(s.name)}catch(e){t.verbose(`Skipping entry ${s.name} due to error: ${e}`)}return a}catch(o){return t.verbose(`Failed to list node_modules packages at ${e}: ${o}`),[]}}const oe=[{Slogan:"No caffeine, no chaos. Just clean code.",Tags:"Coffee-themed, Calm, Tech"},{Slogan:"Full flavor, no jitters. That's Decaf-TS.",Tags:"Coffee-themed, Cheerful"},{Slogan:"Chill fullstack. Powered by Decaf.",Tags:"Coffee-themed, Fun, Tech"},{Slogan:"Decaf-TS: Brewed for calm code.",Tags:"Coffee-themed, Branding"},{Slogan:"Smooth as your morning Decaf.",Tags:"Coffee-themed, Chill"},{Slogan:"All the kick, none of the crash.",Tags:"Coffee-themed, Energetic"},{Slogan:"Sip back and ship faster.",Tags:"Coffee-themed, Fun"},{Slogan:"Keep calm and code Decaf.",Tags:"Coffee-themed, Playful"},{Slogan:"Code without the caffeine shakes.",Tags:"Coffee-themed, Humorous"},{Slogan:"Your fullstack, decaffeinated.",Tags:"Coffee-themed, Technical"},{Slogan:"No caffeine, no chaos. Just clean code.",Tags:"Coffee-themed, Calm, Tech"},{Slogan:"Full flavor, no jitters. That\u2019s Decaf-TS.",Tags:"Coffee-themed, Cheerful"},{Slogan:"Chill fullstack. Powered by Decaf.",Tags:"Coffee-themed, Fun, Tech"},{Slogan:"Decaf-TS: Brewed for calm code.",Tags:"Coffee-themed, Branding"},{Slogan:"Smooth as your morning Decaf.",Tags:"Coffee-themed, Chill"},{Slogan:"All the kick, none of the crash.",Tags:"Coffee-themed, Energetic"},{Slogan:"Sip back and ship faster.",Tags:"Coffee-themed, Fun"},{Slogan:"Keep calm and code Decaf.",Tags:"Coffee-themed, Playful"},{Slogan:"Code without the caffeine shakes.",Tags:"Coffee-themed, Humorous"},{Slogan:"Your fullstack, decaffeinated.",Tags:"Coffee-themed, Technical"},{Slogan:"No caffeine, no chaos. Just clean code.",Tags:"Coffee-themed, Calm, Tech"},{Slogan:"Full flavor, no jitters. That\u2019s Decaf-TS.",Tags:"Coffee-themed, Cheerful"},{Slogan:"Chill fullstack. Powered by Decaf.",Tags:"Coffee-themed, Fun, Tech"},{Slogan:"Decaf-TS: Brewed for calm code.",Tags:"Coffee-themed, Branding"},{Slogan:"Smooth as your morning Decaf.",Tags:"Coffee-themed, Chill"},{Slogan:"All the kick, none of the crash.",Tags:"Coffee-themed, Energetic"},{Slogan:"Sip back and ship faster.",Tags:"Coffee-themed, Fun"},{Slogan:"Keep calm and code Decaf.",Tags:"Coffee-themed, Playful"},{Slogan:"Code without the caffeine shakes.",Tags:"Coffee-themed, Humorous"},{Slogan:"Your fullstack, decaffeinated.",Tags:"Coffee-themed, Technical"},{Slogan:"No caffeine, no chaos. Just clean code.",Tags:"Coffee-themed, Calm, Tech"},{Slogan:"Full flavor, no jitters. That\u2019s Decaf-TS.",Tags:"Coffee-themed, Cheerful"},{Slogan:"Chill fullstack. Powered by Decaf.",Tags:"Coffee-themed, Fun, Tech"},{Slogan:"Decaf-TS: Brewed for calm code.",Tags:"Coffee-themed, Branding"},{Slogan:"Smooth as your morning Decaf.",Tags:"Coffee-themed, Chill"},{Slogan:"All the kick, none of the crash.",Tags:"Coffee-themed, Energetic"},{Slogan:"Sip back and ship faster.",Tags:"Coffee-themed, Fun"},{Slogan:"Keep calm and code Decaf.",Tags:"Coffee-themed, Playful"},{Slogan:"Code without the caffeine shakes.",Tags:"Coffee-themed, Humorous"},{Slogan:"Your fullstack, decaffeinated.",Tags:"Coffee-themed, Technical"},{Slogan:"No caffeine, no chaos. Just clean code.",Tags:"Coffee-themed, Calm, Tech"},{Slogan:"Full flavor, no jitters. That\u2019s Decaf-TS.",Tags:"Coffee-themed, Cheerful"},{Slogan:"Chill fullstack. Powered by Decaf.",Tags:"Coffee-themed, Fun, Tech"},{Slogan:"Decaf-TS: Brewed for calm code.",Tags:"Coffee-themed, Branding"},{Slogan:"Smooth as your morning Decaf.",Tags:"Coffee-themed, Chill"},{Slogan:"All the kick, none of the crash.",Tags:"Coffee-themed, Energetic"},{Slogan:"Sip back and ship faster.",Tags:"Coffee-themed, Fun"},{Slogan:"Keep calm and code Decaf.",Tags:"Coffee-themed, Playful"},{Slogan:"Code without the caffeine shakes.",Tags:"Coffee-themed, Humorous"},{Slogan:"Your fullstack, decaffeinated.",Tags:"Coffee-themed, Technical"},{Slogan:"No caffeine, no chaos. Just clean code.",Tags:"Coffee-themed, Calm, Tech"},{Slogan:"Full flavor, no jitters. That\u2019s Decaf-TS.",Tags:"Coffee-themed, Cheerful"},{Slogan:"Chill fullstack. Powered by Decaf.",Tags:"Coffee-themed, Fun, Tech"},{Slogan:"Decaf-TS: Brewed for calm code.",Tags:"Coffee-themed, Branding"},{Slogan:"Smooth as your morning Decaf.",Tags:"Coffee-themed, Chill"},{Slogan:"All the kick, none of the crash.",Tags:"Coffee-themed, Energetic"},{Slogan:"Sip back and ship faster.",Tags:"Coffee-themed, Fun"},{Slogan:"Keep calm and code Decaf.",Tags:"Coffee-themed, Playful"},{Slogan:"Code without the caffeine shakes.",Tags:"Coffee-themed, Humorous"},{Slogan:"Your fullstack, decaffeinated.",Tags:"Coffee-themed, Technical"},{Slogan:"No caffeine, no chaos. Just clean code.",Tags:"Coffee-themed, Calm, Tech"},{Slogan:"Full flavor, no jitters. That\u2019s Decaf-TS.",Tags:"Coffee-themed, Cheerful"},{Slogan:"Chill fullstack. Powered by Decaf.",Tags:"Coffee-themed, Fun, Tech"},{Slogan:"Decaf-TS: Brewed for calm code.",Tags:"Coffee-themed, Branding"},{Slogan:"Smooth as your morning Decaf.",Tags:"Coffee-themed, Chill"},{Slogan:"All the kick, none of the crash.",Tags:"Coffee-themed, Energetic"},{Slogan:"Sip back and ship faster.",Tags:"Coffee-themed, Fun"},{Slogan:"Keep calm and code Decaf.",Tags:"Coffee-themed, Playful"},{Slogan:"Code without the caffeine shakes.",Tags:"Coffee-themed, Humorous"},{Slogan:"Your fullstack, decaffeinated.",Tags:"Coffee-themed, Technical"},{Slogan:"No caffeine, no chaos. Just clean code.",Tags:"Coffee-themed, Calm, Tech"},{Slogan:"Full flavor, no jitters. That\u2019s Decaf-TS.",Tags:"Coffee-themed, Cheerful"},{Slogan:"Chill fullstack. Powered by Decaf.",Tags:"Coffee-themed, Fun, Tech"},{Slogan:"Decaf-TS: Brewed for calm code.",Tags:"Coffee-themed, Branding"},{Slogan:"Smooth as your morning Decaf.",Tags:"Coffee-themed, Chill"},{Slogan:"All the kick, none of the crash.",Tags:"Coffee-themed, Energetic"},{Slogan:"Sip back and ship faster.",Tags:"Coffee-themed, Fun"},{Slogan:"Keep calm and code Decaf.",Tags:"Coffee-themed, Playful"},{Slogan:"Code without the caffeine shakes.",Tags:"Coffee-themed, Humorous"},{Slogan:"Your fullstack, decaffeinated.",Tags:"Coffee-themed, Technical"},{Slogan:"No caffeine, no chaos. Just clean code.",Tags:"Coffee-themed, Calm, Tech"},{Slogan:"Full flavor, no jitters. That\u2019s Decaf-TS.",Tags:"Coffee-themed, Cheerful"},{Slogan:"Chill fullstack. Powered by Decaf.",Tags:"Coffee-themed, Fun, Tech"},{Slogan:"Decaf-TS: Brewed for calm code.",Tags:"Coffee-themed, Branding"},{Slogan:"Smooth as your morning Decaf.",Tags:"Coffee-themed, Chill"},{Slogan:"All the kick, none of the crash.",Tags:"Coffee-themed, Energetic"},{Slogan:"Sip back and ship faster.",Tags:"Coffee-themed, Fun"},{Slogan:"Keep calm and code Decaf.",Tags:"Coffee-themed, Playful"},{Slogan:"Code without the caffeine shakes.",Tags:"Coffee-themed, Humorous"},{Slogan:"Your fullstack, decaffeinated.",Tags:"Coffee-themed, Technical"},{Slogan:"No caffeine, no chaos. Just clean code.",Tags:"Coffee-themed, Calm, Tech"},{Slogan:"Full flavor, no jitters. That\u2019s Decaf-TS.",Tags:"Coffee-themed, Cheerful"},{Slogan:"Chill fullstack. Powered by Decaf.",Tags:"Coffee-themed, Fun, Tech"},{Slogan:"Decaf-TS: Brewed for calm code.",Tags:"Coffee-themed, Branding"},{Slogan:"Smooth as your morning Decaf.",Tags:"Coffee-themed, Chill"},{Slogan:"All the kick, none of the crash.",Tags:"Coffee-themed, Energetic"},{Slogan:"Sip back and ship faster.",Tags:"Coffee-themed, Fun"},{Slogan:"Keep calm and code Decaf.",Tags:"Coffee-themed, Playful"},{Slogan:"Code without the caffeine shakes.",Tags:"Coffee-themed, Humorous"},{Slogan:"Your fullstack, decaffeinated.",Tags:"Coffee-themed, Technical"},{Slogan:"Decaf-TS: Where smart contracts meet smart interfaces.",Tags:"Blockchain, Smart Contracts, Tech"},{Slogan:"Ship dApps without the stress.",Tags:"Blockchain, Cheerful, Developer"},{Slogan:"No CRUD, no problem \u2014 Decaf your data.",Tags:"Data, No-CRUD, Chill"},{Slogan:"From DID to UI, without breaking a sweat.",Tags:"DID, SSI, UI, Calm"},{Slogan:"Decaf-TS: Your frontend already understands your smart contract.",Tags:"Smart Contracts, DX, Magic"},{Slogan:"Self-sovereign by design. Productive by default.",Tags:"SSI, Developer, Calm"},{Slogan:"Build once. Deploy everywhere. Decentralized and delightful.",Tags:"Blockchain, Multi-platform, Happy"},{Slogan:"Data that defines its own destiny.",Tags:"SSI, Data-driven, Empowerment"},{Slogan:"Goodbye CRUD, hello intent-based interfaces.",Tags:"No-CRUD, UI, Technical"},{Slogan:"The smoothest path from DID to done.",Tags:"DID, Workflow, Chill"},{Slogan:"Because your dApp deserves more than boilerplate.",Tags:"Blockchain, DevX, Efficiency"},{Slogan:"Own your data. Own your flow.",Tags:"SSI, Control, Ownership"},{Slogan:"Write logic like it belongs with the data \u2014 because it does.",Tags:"Data Logic, Developer, Smart"},{Slogan:"From smart contracts to smarter frontends.",Tags:"Smart Contracts, UI, DX"},{Slogan:"No caffeine. No CRUD. Just the future.",Tags:"No-CRUD, Coffee-themed, Futuristic"},{Slogan:"The future of web3 UX is Decaf.",Tags:"Blockchain, UX, Vision"},{Slogan:"Code with confidence. Govern with clarity.",Tags:"Blockchain, Governance, Calm"},{Slogan:"Interfaces that obey the data, not the other way around.",Tags:"UI, Data Logic, Self-aware"},{Slogan:"Brew business logic right into your bytes.",Tags:"Data Logic, Coffee-themed, Fun"},{Slogan:"DIDs done differently \u2014 and delightfully.",Tags:"DID, Self-Sovereign, Playful"},{Slogan:"Decaf-TS-TS: Where blockchain contracts meet smart interfaces.",Tags:"Blockchain, Smart Contracts, Tech"},{Slogan:"Ship dApps without the stress.",Tags:"Blockchain, Cheerful, Developer"},{Slogan:"No boilerplate, no problem \u2014 Decaf-TS your data.",Tags:"Data, No-CRUD, Chill"},{Slogan:"From DID to UI, without breaking a sweat.",Tags:"DID, SSI, UI, Calm"},{Slogan:"Decaf-TS-TS: Your frontend already understands your blockchain contract.",Tags:"Smart Contracts, DX, Magic"},{Slogan:"Self-sovereign by design. Productive by default.",Tags:"SSI, Developer, Calm"},{Slogan:"Build once. Deploy everywhere. Decentralized and delightful.",Tags:"Blockchain, Multi-platform, Happy"},{Slogan:"Data that defines its own destiny.",Tags:"SSI, Data-driven, Empowerment"},{Slogan:"Goodbye boilerplate, hello intent-based interfaces.",Tags:"No-CRUD, UI, Technical"},{Slogan:"The smoothest path from DID to done.",Tags:"DID, Workflow, Chill"},{Slogan:"Because your dApp deserves more than boilerplate.",Tags:"Blockchain, DevX, Efficiency"},{Slogan:"Own your data. Own your flow.",Tags:"SSI, Control, Ownership"},{Slogan:"Write logic like it belongs with the data \u2014 because it does.",Tags:"Data Logic, Developer, Smart"},{Slogan:"From blockchain contracts to smarter frontends.",Tags:"Smart Contracts, UI, DX"},{Slogan:"No caffeine. No boilerplate. Just the future.",Tags:"No-CRUD, Coffee-themed, Futuristic"},{Slogan:"The future of web3 UX is Decaf-TS.",Tags:"Blockchain, UX, Vision"},{Slogan:"Code with confidence. Govern with clarity.",Tags:"Blockchain, Governance, Calm"},{Slogan:"Interfaces that obey the data, not the other way around.",Tags:"UI, Data Logic, Self-aware"},{Slogan:"Brew business logic right into your bytes.",Tags:"Data Logic, Coffee-themed, Fun"},{Slogan:"DIDs done differently \u2014 and delightfully.",Tags:"DID, Self-Sovereign, Playful"},{Slogan:"Decaf-TS-TS: Where blockchain contracts meet smart interfaces.",Tags:"Blockchain, Smart Contracts, Tech"},{Slogan:"Ship dApps without the stress.",Tags:"Blockchain, Cheerful, Developer"},{Slogan:"No boilerplate, no problem \u2014 Decaf-TS your data.",Tags:"Data, No-CRUD, Chill"},{Slogan:"From DID to UI, without breaking a sweat.",Tags:"DID, SSI, UI, Calm"},{Slogan:"Decaf-TS-TS: Your frontend already understands your blockchain contract.",Tags:"Smart Contracts, DX, Magic"},{Slogan:"Self-sovereign by design. Productive by default.",Tags:"SSI, Developer, Calm"},{Slogan:"Build once. Deploy everywhere. Decentralized and delightful.",Tags:"Blockchain, Multi-platform, Happy"},{Slogan:"Data that defines its own destiny.",Tags:"SSI, Data-driven, Empowerment"},{Slogan:"Goodbye boilerplate, hello intent-based interfaces.",Tags:"No-CRUD, UI, Technical"},{Slogan:"The smoothest path from DID to done.",Tags:"DID, Workflow, Chill"},{Slogan:"Because your dApp deserves more than boilerplate.",Tags:"Blockchain, DevX, Efficiency"},{Slogan:"Own your data. Own your flow.",Tags:"SSI, Control, Ownership"},{Slogan:"Write logic like it belongs with the data \u2014 because it does.",Tags:"Data Logic, Developer, Smart"},{Slogan:"From blockchain contracts to smarter frontends.",Tags:"Smart Contracts, UI, DX"},{Slogan:"No caffeine. No boilerplate. Just the future.",Tags:"No-CRUD, Coffee-themed, Futuristic"},{Slogan:"The future of web3 UX is Decaf-TS.",Tags:"Blockchain, UX, Vision"},{Slogan:"Code with confidence. Govern with clarity.",Tags:"Blockchain, Governance, Calm"},{Slogan:"Interfaces that obey the data, not the other way around.",Tags:"UI, Data Logic, Self-aware"},{Slogan:"Brew business logic right into your bytes.",Tags:"Data Logic, Coffee-themed, Fun"},{Slogan:"DIDs done differently \u2014 and delightfully.",Tags:"DID, Self-Sovereign, Playful"},{Slogan:"Decaf-TS-TS: Where blockchain contracts meet smart interfaces.",Tags:"Blockchain, Smart Contracts, Tech"},{Slogan:"Ship dApps without the stress.",Tags:"Blockchain, Cheerful, Developer"},{Slogan:"No boilerplate, no problem \u2014 Decaf-TS your data.",Tags:"Data, No-CRUD, Chill"},{Slogan:"From DID to UI, without breaking a sweat.",Tags:"DID, SSI, UI, Calm"},{Slogan:"Decaf-TS-TS: Your frontend already understands your blockchain contract.",Tags:"Smart Contracts, DX, Magic"},{Slogan:"Self-sovereign by design. Productive by default.",Tags:"SSI, Developer, Calm"},{Slogan:"Build once. Deploy everywhere. Decentralized and delightful.",Tags:"Blockchain, Multi-platform, Happy"},{Slogan:"Data that defines its own destiny.",Tags:"SSI, Data-driven, Empowerment"},{Slogan:"Goodbye boilerplate, hello intent-based interfaces.",Tags:"No-CRUD, UI, Technical"},{Slogan:"The smoothest path from DID to done.",Tags:"DID, Workflow, Chill"},{Slogan:"Because your dApp deserves more than boilerplate.",Tags:"Blockchain, DevX, Efficiency"},{Slogan:"Own your data. Own your flow.",Tags:"SSI, Control, Ownership"},{Slogan:"Write logic like it belongs with the data \u2014 because it does.",Tags:"Data Logic, Developer, Smart"},{Slogan:"From blockchain contracts to smarter frontends.",Tags:"Smart Contracts, UI, DX"},{Slogan:"No caffeine. No boilerplate. Just the future.",Tags:"No-CRUD, Coffee-themed, Futuristic"},{Slogan:"The future of web3 UX is Decaf-TS.",Tags:"Blockchain, UX, Vision"},{Slogan:"Code with confidence. Govern with clarity.",Tags:"Blockchain, Governance, Calm"},{Slogan:"Interfaces that obey the data, not the other way around.",Tags:"UI, Data Logic, Self-aware"},{Slogan:"Brew business logic right into your bytes.",Tags:"Data Logic, Coffee-themed, Fun"},{Slogan:"DIDs done differently \u2014 and delightfully.",Tags:"DID, Self-Sovereign, Playful"},{Slogan:"Decaf-TS-TS: Where blockchain contracts meet smart interfaces.",Tags:"Blockchain, Smart Contracts, Tech"},{Slogan:"Ship dApps without the stress.",Tags:"Blockchain, Cheerful, Developer"},{Slogan:"No boilerplate, no problem \u2014 Decaf-TS your data.",Tags:"Data, No-CRUD, Chill"},{Slogan:"From DID to UI, without breaking a sweat.",Tags:"DID, SSI, UI, Calm"},{Slogan:"Decaf-TS-TS: Your frontend already understands your blockchain contract.",Tags:"Smart Contracts, DX, Magic"},{Slogan:"Self-sovereign by design. Productive by default.",Tags:"SSI, Developer, Calm"},{Slogan:"Build once. Deploy everywhere. Decentralized and delightful.",Tags:"Blockchain, Multi-platform, Happy"},{Slogan:"Data that defines its own destiny.",Tags:"SSI, Data-driven, Empowerment"},{Slogan:"Goodbye boilerplate, hello intent-based interfaces.",Tags:"No-CRUD, UI, Technical"},{Slogan:"The smoothest path from DID to done.",Tags:"DID, Workflow, Chill"},{Slogan:"Because your dApp deserves more than boilerplate.",Tags:"Blockchain, DevX, Efficiency"},{Slogan:"Own your data. Own your flow.",Tags:"SSI, Control, Ownership"},{Slogan:"Write logic like it belongs with the data \u2014 because it does.",Tags:"Data Logic, Developer, Smart"},{Slogan:"From blockchain contracts to smarter frontends.",Tags:"Smart Contracts, UI, DX"},{Slogan:"No caffeine. No boilerplate. Just the future.",Tags:"No-CRUD, Coffee-themed, Futuristic"},{Slogan:"The future of web3 UX is Decaf-TS.",Tags:"Blockchain, UX, Vision"},{Slogan:"Code with confidence. Govern with clarity.",Tags:"Blockchain, Governance, Calm"},{Slogan:"Interfaces that obey the data, not the other way around.",Tags:"UI, Data Logic, Self-aware"},{Slogan:"Brew business logic right into your bytes.",Tags:"Data Logic, Coffee-themed, Fun"},{Slogan:"DIDs done differently \u2014 and delightfully.",Tags:"DID, Self-Sovereign, Playful"}],ae=["\x1b[38;5;215m","\x1b[38;5;209m","\x1b[38;5;205m","\x1b[38;5;210m","\x1b[38;5;217m","\x1b[38;5;216m","\x1b[38;5;224m","\x1b[38;5;230m","\x1b[38;5;230m"];function se(e){const t=re(),o="# \u2591\u2592\u2593\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2593\u2592\u2591 \u2591\u2592\u2593\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2593\u2592\u2591 \u2591\u2592\u2593\u2588\u2588\u2588\u2588\u2588\u2588\u2593\u2592\u2591 \u2591\u2592\u2593\u2588\u2588\u2588\u2588\u2588\u2588\u2593\u2592\u2591 \u2591\u2592\u2593\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2593\u2592\u2591 \u2591\u2592\u2593\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2593\u2592\u2591 \u2591\u2592\u2593\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2593\u2592\u2591 \n# ( ( \u2591\u2592\u2593\u2588\u2593\u2592\u2591\u2591\u2592\u2593\u2588\u2593\u2592\u2591 \u2591\u2592\u2593\u2588\u2593\u2592\u2591 \u2591\u2592\u2593\u2588\u2593\u2592\u2591\u2591\u2592\u2593\u2588\u2593\u2592\u2591 \u2591\u2592\u2593\u2588\u2593\u2592\u2591\u2591\u2592\u2593\u2588\u2593\u2592\u2591 \u2591\u2592\u2593\u2588\u2593\u2592\u2591 \u2591\u2592\u2593\u2588\u2593\u2592\u2591 \u2591\u2592\u2593\u2588\u2593\u2592\u2591 \n# ) ) \u2591\u2592\u2593\u2588\u2593\u2592\u2591\u2591\u2592\u2593\u2588\u2593\u2592\u2591 \u2591\u2592\u2593\u2588\u2593\u2592\u2591 \u2591\u2592\u2593\u2588\u2593\u2592\u2591 \u2591\u2592\u2593\u2588\u2593\u2592\u2591\u2591\u2592\u2593\u2588\u2593\u2592\u2591 \u2591\u2592\u2593\u2588\u2593\u2592\u2591 \u2591\u2592\u2593\u2588\u2593\u2592\u2591 \u2591\u2592\u2593\u2588\u2593\u2592\u2591 \n# [=======] \u2591\u2592\u2593\u2588\u2593\u2592\u2591\u2591\u2592\u2593\u2588\u2593\u2592\u2591 \u2591\u2592\u2593\u2588\u2588\u2588\u2588\u2588\u2588\u2593\u2592\u2591 \u2591\u2592\u2593\u2588\u2593\u2592\u2591 \u2591\u2592\u2593\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2593\u2592\u2591 \u2591\u2592\u2593\u2588\u2588\u2588\u2588\u2588\u2588\u2593\u2592\u2591 \u2591\u2592\u2593\u2588\u2593\u2592\u2591 \u2591\u2592\u2593\u2588\u2588\u2588\u2588\u2588\u2588\u2593\u2592\u2591 \n# `-----\xb4 \u2591\u2592\u2593\u2588\u2593\u2592\u2591\u2591\u2592\u2593\u2588\u2593\u2592\u2591 \u2591\u2592\u2593\u2588\u2593\u2592\u2591 \u2591\u2592\u2593\u2588\u2593\u2592\u2591 \u2591\u2592\u2593\u2588\u2593\u2592\u2591\u2591\u2592\u2593\u2588\u2593\u2592\u2591 \u2591\u2592\u2593\u2588\u2593\u2592\u2591 \u2591\u2592\u2593\u2588\u2593\u2592\u2591 \u2591\u2592\u2593\u2588\u2593\u2592\u2591 \n# \u2591\u2592\u2593\u2588\u2593\u2592\u2591\u2591\u2592\u2593\u2588\u2593\u2592\u2591 \u2591\u2592\u2593\u2588\u2593\u2592\u2591 \u2591\u2592\u2593\u2588\u2593\u2592\u2591\u2591\u2592\u2593\u2588\u2593\u2592\u2591 \u2591\u2592\u2593\u2588\u2593\u2592\u2591\u2591\u2592\u2593\u2588\u2593\u2592\u2591 \u2591\u2592\u2593\u2588\u2593\u2592\u2591 \u2591\u2592\u2593\u2588\u2593\u2592\u2591 \u2591\u2592\u2593\u2588\u2593\u2592\u2591 \n# \u2591\u2592\u2593\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2593\u2592\u2591 \u2591\u2592\u2593\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2593\u2592\u2591 \u2591\u2592\u2593\u2588\u2588\u2588\u2588\u2588\u2588\u2593\u2592\u2591 \u2591\u2592\u2593\u2588\u2593\u2592\u2591\u2591\u2592\u2593\u2588\u2593\u2592\u2591 \u2591\u2592\u2593\u2588\u2593\u2592\u2591 \u2591\u2592\u2593\u2588\u2593\u2592\u2591 \u2591\u2592\u2593\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2593\u2592\u2591 \n#".split("\n"),a=o.reduce((e,t)=>Math.max(e,t.length),0);o.push("# "+t.padStart(a-3)),o.forEach((t,o)=>{(e?e.info.bind(e):(()=>{}).bind())(g(t||"").raw(ae[o]).text)})}function re(e){try{return e=void 0===e?Math.floor(Math.random()*oe.length):e,oe[e].Slogan}catch(e){throw Error("Failed to retrieve slogans: "+e)}}class ne extends s{constructor(e,t={},a=[]){super(),this.name=e,this.inputs=t,this.requirements=a,ne.log||Object.defineProperty(ne,"log",{writable:!1,value:o.for(ne.name)}),this.inputs=Object.assign({},C,t)}async checkRequirements(){const{prod:e,dev:t,peer:o}=await H(),a=[],s=Array.from(new Set([...e,...t,...o]).values()).map(e=>e.name);for(const e of this.requirements)s.includes(e)||a.push(e);a.length}help(e){return this.log.info("This is help. I'm no use because I should have been overridden.")}async execute(){const e=w.parseArgs(this.inputs),t=r.accumulate(D).accumulate(e.values),{version:o,help:a,banner:s}=t;if(o)return _();if(a)return this.help(e);let n;s&&se(this.log.for(se,{timestamp:!1,style:!1,context:!1,logLevel:!1}));try{n=await this.run(t)}catch(e){throw e}return n}}class ie{static{this.log=o.for(ie)}static async downloadFile(e){return new Promise((t,o)=>{!function e(a){a=encodeURI(a),d.get(a,s=>{if(301===s.statusCode||307===s.statusCode)return e(s.headers.location);if(200!==s.statusCode)return ie.log.error(`Failed to fetch ${a} (status: ${s.statusCode})`),o(Error("Failed to fetch "+a));let r="";s.on("data",e=>{r+=e}),s.on("error",e=>{o(e)}),s.on("end",()=>{t(r)})})}(e)})}}function ce(e){return e?Array.isArray(e)?e.map(e=>(""+e).trim()).filter(Boolean):(""+e).split(",").map(e=>e.trim()).filter(Boolean):[]}function le(e){return e.replace(/^@/,"").split(/[/\-_.]+/).filter(Boolean).map((e,t)=>0===t?e.replace(/[^a-zA-Z0-9]/g,""):`${e.charAt(0).toUpperCase()}${e.slice(1)}`).join("")}function ge(){let e;try{e=V(process.cwd())}catch{e=void 0}try{if(!e||!(Object.keys(e.dependencies||{}).length>0||Object.keys(e.devDependencies||{}).length>0||Object.keys(e.peerDependencies||{}).length>0)){const t=c.resolve(__dirname,"../../..");try{e=V(t)}catch{}}}catch{}const t=Object.keys(e&&e.dependencies||{}),o=Object.keys(e&&e.peerDependencies||{}),a=Object.keys(e&&e.devDependencies||{});return Array.from(new Set([...t,...o,...a]))}const fe="##VERSION##",de="##PACKAGE##",he="##PACKAGE_SIZE##";var ue,me;(e=>{e.CJS="commonjs",e.ESM="es2022"})(ue||(ue={})),(e=>{e.BUILD="build",e.BUNDLE="bundle",e.ALL="all"})(me||(me={}));const pe={prod:{type:"boolean",default:!1},dev:{type:"boolean",default:!1},buildMode:{type:"string",default:me.ALL},includes:{type:"string",default:""},externals:{type:"string",default:""},docs:{type:"boolean",default:!1},commands:{type:"boolean",default:!1},banner:{type:"boolean",default:!1}},Se=(e=".cjs")=>{const t=ye.log.for(Se),o=new Map;return a=>s=>{const r=c.dirname(s.fileName);function n(a){const s=JSON.stringify([r,a]),n=o.get(s);if(null!=n)return n;let l,g=a;try{g=c.resolve(r,g+".ts")}catch(e){throw Error(`Failed to resolve path ${a}: ${e}`)}try{l=i.statSync(g)}catch(e){try{t.verbose(`Testing existence of path ${g} as a folder defaulting to index file`),l=i.statSync(g.replace(/\.ts$/gm,""))}catch(t){throw Error(`Failed to resolve path ${a}: ${e}, ${t}`)}}if(l.isDirectory()&&(g=g.replace(/\.ts$/gm,"/index.ts")),c.isAbsolute(g)){const t=(/\.tsx?$/.exec(c.basename(g))||[])[0]||void 0;g="./"+c.relative(r,c.resolve(c.dirname(g),c.basename(g,t)+e))}return o.set(s,g),g}return T.visitNode(s,function e(t){if((e=>!(!T.isImportDeclaration(e)&&!T.isExportDeclaration(e)||void 0===e.moduleSpecifier||!T.isStringLiteral(e.moduleSpecifier)||!e.moduleSpecifier.text.startsWith("./")&&!e.moduleSpecifier.text.startsWith("../")||""!==c.extname(e.moduleSpecifier.text)))(t)){if(T.isImportDeclaration(t)){const e=n(t.moduleSpecifier.text),o=a.factory.createStringLiteral(e);return a.factory.updateImportDeclaration(t,t.modifiers,t.importClause,o,void 0)}if(T.isExportDeclaration(t)){const e=n(t.moduleSpecifier.text),o=a.factory.createStringLiteral(e);return a.factory.updateExportDeclaration(t,t.modifiers,t.isTypeOnly,t.exportClause,o,void 0)}}return T.visitEachChild(t,e,a)})}};class ye extends ne{constructor(){super("BuildScripts",Object.assign({},C,pe)),this.replacements={};const e=V(),{name:t,version:o}=e;this.pkgName=t.includes("@")?t.split("/")[1]:t,this.pkgVersion=o,this.replacements[fe]=this.pkgVersion,this.replacements[de]=t}patchFiles(e){const t=this.log.for(this.patchFiles),{name:o,version:a}=V();t.info(`Patching ${o} ${a} module in ${e}...`),i.statSync(e).isDirectory()&&i.readdirSync(e,{withFileTypes:!0,recursive:!0}).filter(e=>e.isFile()).forEach(e=>U(c.join(e.parentPath,e.name),Object.entries(this.replacements).reduce((e,[o,a])=>{switch(o){case fe:t.debug("Found VERSION string to replace"),e[`VERSION = "${fe}";`]=`VERSION = "${a}";`;break;case de:t.debug("Found PACKAGE_NAME string to replace"),e[`PACKAGE_NAME = "${de}";`]=`PACKAGE_NAME = "${a}";`;break;default:e[o]=a}return e},{}))),t.verbose(`Module ${o} ${a} patched in ${e}...`)}reportDiagnostics(e,t){const o=this.formatDiagnostics(e);try{this.log[t](o)}catch(e){throw e}return o}formatDiagnostics(e){return e.map(e=>{let t="";if(e.file&&e.start){const{line:o,character:a}=e.file.getLineAndCharacterOfPosition(e.start);t+=`${e.file.fileName} (${o+1},${a+1})`}return t+=": "+T.flattenDiagnosticMessageText(e.messageText,"\n"),t}).join("\n")}readConfigFile(e){const t=i.readFileSync(e).toString(),o=T.parseConfigFileTextToJson(e,t),a=o.config;a||this.reportDiagnostics([o.error],n.error);const s=T.parseJsonConfigFileContent(a,T.sys,c.dirname(e));return s.errors.length>0&&this.reportDiagnostics(s.errors,n.error),s}evalDiagnostics(e){if(e&&e.length>0){const t=e.filter(e=>e.category===T.DiagnosticCategory.Error),o=e.filter(e=>e.category===T.DiagnosticCategory.Warning),a=e.filter(e=>e.category===T.DiagnosticCategory.Suggestion),s=e.filter(e=>e.category===T.DiagnosticCategory.Message);if(o.length&&this.reportDiagnostics(o,n.warn),t.length)throw this.reportDiagnostics(e,n.error),Error(`TypeScript reported ${e.length} diagnostic(s) during check; aborting.`);a.length&&this.reportDiagnostics(a,n.info),s.length&&this.reportDiagnostics(s,n.info)}}preCheckDiagnostics(e){const t=T.getPreEmitDiagnostics(e);this.evalDiagnostics(t)}async checkTsDiagnostics(e,t,o=!1){const a=this.log.for(this.checkTsDiagnostics);let s;try{s=this.readConfigFile("./tsconfig.json")}catch(e){throw Error("Failed to parse tsconfig.json: "+e)}o?(s.options.module=b.AMD,s.options.outDir="dist",s.options.isolatedModules=!1,s.options.outFile=this.pkgName):(s.options.outDir="lib"+(t===ue.ESM?"/esm":""),s.options.module=t===ue.ESM?b.ES2022:b.CommonJS),s.options.inlineSourceMap=!1,s.options.inlineSources=!1,s.options.sourceMap=!0;const r=T.createProgram(s.fileNames,s.options);this.preCheckDiagnostics(r),a.verbose(`TypeScript checks passed (${o?"bundle":"normal"} mode).`)}async buildTs(e,t,o=!1){let a;this.log.for(this.buildTs).info(`Building ${this.pkgName} ${this.pkgVersion} module (${t}) in ${e?"dev":"prod"} mode...`);try{a=this.readConfigFile("./tsconfig.json")}catch(e){throw Error("Failed to parse tsconfig.json: "+e)}o?(a.options.module=b.AMD,a.options.outDir="dist",a.options.isolatedModules=!1,a.options.outFile=this.pkgName):(a.options.outDir="lib"+(t===ue.ESM?"/esm":""),a.options.module=t===ue.ESM?b.ES2022:b.CommonJS),e?(a.options.inlineSourceMap=!0,a.options.inlineSources=!0,a.options.sourceMap=!1):(a.options.inlineSourceMap=!1,a.options.inlineSources=!1,a.options.sourceMap=!0);const s=T.createProgram(a.fileNames,a.options),r={};t===ue.CJS?r.before=[Se(".cjs")]:t===ue.ESM&&(r.before=[Se(".js")]);const n=s.emit(void 0,void 0,void 0,void 0,r),i=T.getPreEmitDiagnostics(s).concat(n.diagnostics);this.evalDiagnostics(i)}async build(e,t,o=!1){const a=this.log.for(this.build);if(await this.buildTs(e,t,o),a.verbose(`Module ${this.pkgName} ${this.pkgVersion} (${t}) built in ${e?"dev":"prod"} mode...`),t===ue.CJS&&!o){const e=R("lib",e=>e.endsWith(".js")&&!e.includes("/esm/"));for(const t of e){a.verbose(`Patching ${t}'s cjs imports...`);const e=t.replace(".js",".cjs");await J(t,e)}}}copyAssets(e){const t=this.log.for(this.copyAssets);let o=!1;try{o=i.statSync("./src/assets").isDirectory()}catch(e){return t.verbose("No assets found in ./src/assets to copy")}o&&W("./src/assets",`./${e===ue.CJS?"lib":"dist"}/assets`)}async bundle(e,t,o,a="src/index.ts",s=this.pkgName,r,n=["prompts","styled-string-builder","typed-object-accumulator","@decaf-ts/logging"]){await this.checkTsDiagnostics(t,e,!0);const i=e===ue.ESM,l=this.pkgName,g=this.log,f=Array.from(new Set([...ce(n)]));let d=ce(r);if(0===d.length){try{d=te(c.join(process.cwd(),"node_modules"))}catch{}d&&0!==d.length||(d=ge())}const T=Array.from(new Set([...(()=>{try{return Array.isArray(y)?y:[]}catch{return["fs","path","process","child_process","util","https","http","os","stream","crypto","zlib","net","tls","url","querystring","assert","events","tty","dns","querystring"]}})(),...d])),b=!t||"inline",w=[u({compilerOptions:{module:"esnext",declaration:!1,outDir:o?"bin":"dist",sourceMap:!t,inlineSourceMap:!!t,inlineSources:!!t},include:["src/**/*.ts"],exclude:["node_modules","**/*.spec.ts"],tsconfig:"./tsconfig.json"}),S()];o&&w.push(m({include:[],exclude:d}),p({resolveOnly:f}));try{const k=await import("@rollup/plugin-terser"),$=k&&k.terser||k.default||k,E={parse:{ecma:2020},compress:!1,mangle:!1,format:{comments:!1,beautify:!0}},I={parse:{ecma:2020},compress:{ecma:2020,passes:5,drop_console:!0,drop_debugger:!0,toplevel:!0,module:i,unsafe:!0,unsafe_arrows:!0,unsafe_comps:!0,collapse_vars:!0,reduce_funcs:!0,reduce_vars:!0},mangle:{toplevel:!0},format:{comments:!1,ascii_only:!0},toplevel:!0};w.push($(t?E:I))}catch{}const C={input:a,plugins:w,external:T,onwarn:void 0,treeshake:!t},D={};T.forEach(e=>{D[e]=le(e)});const v=[{file:`${o?"bin/":"dist/"}${s||".bundle."+(t?"":"min")}${i?".js":".cjs"}`,format:o?"cjs":i?"esm":"umd",name:l,esModule:i,sourcemap:b,globals:D,exports:"auto"}];try{const F=await h(C);async function N(e){for(const t of v)await e.write(t)}g.verbose(F.watchFiles),await N(F)}catch(x){throw Error("Failed to bundle: "+x)}}async buildByEnv(e,t=me.ALL,o,a){try{X("lib")}catch(e){}try{X("dist")}catch(e){}i.mkdirSync("lib"),i.mkdirSync("dist"),[me.ALL,me.BUILD].includes(t)&&(await this.build(e,ue.ESM),await this.build(e,ue.CJS),this.patchFiles("lib")),[me.ALL,me.BUNDLE].includes(t)&&(await this.bundle(ue.ESM,e,!1,"src/index.ts",this.pkgName,a,o),await this.bundle(ue.CJS,e,!1,"src/index.ts",this.pkgName,a,o),this.patchFiles("dist")),this.copyAssets(ue.CJS),this.copyAssets(ue.ESM)}async buildDev(e=me.ALL,t,o){return this.buildByEnv(!0,e,t,o)}async buildProd(e=me.ALL,t,o){return this.buildByEnv(!1,e,t,o)}async buildDocs(){await M("npm install better-docs taffydb").promise,await M("npx markdown-include ./workdocs/readme-md.json").promise,await M("npx jsdoc -c ./workdocs/jsdocs.json -t ./node_modules/better-docs").promise,await M("npm remove better-docs taffydb").promise,[{src:"workdocs/assets",dest:"./docs/workdocs/assets"},{src:"workdocs/reports/coverage",dest:"./docs/workdocs/reports/coverage"},{src:"workdocs/reports/html",dest:"./docs/workdocs/reports/html"},{src:"workdocs/resources",dest:"./docs/workdocs/resources"},{src:"LICENSE.md",dest:"./docs/LICENSE.md"}].forEach(e=>{const{src:t,dest:o}=e;W(t,o)});try{const e=await Q(c.resolve(c.join(process.cwd(),"dist")));this.replacements[he]=e+" KB"}catch{this.replacements[he]="unknown"}try{U("./README.md",this.replacements)}catch(e){this.log.for(this.buildDocs).verbose("Failed to patch README.md: "+e)}}async run(e){const{dev:t,prod:o,docs:a,buildMode:s,includes:r,externals:n}=e;return t?await this.buildDev(s,r,n):o?await this.buildProd(s,r,n):a?await this.buildDocs():void 0}}const Te={ci:{type:"boolean",default:!0},message:{type:"string",short:"m"},tag:{type:"string",short:"t",default:void 0}};class be extends ne{constructor(){super("ReleaseScript",Te)}async prepareVersion(e){const t=this.log.for(this.prepareVersion);return(e=this.testVersion(e||""))||(t.verbose("No release message provided. Prompting for one:"),t.info("Listing latest git tags:"),await M("git tag --sort=-taggerdate | head -n 5").promise,await w.insistForText("tag","Enter the new tag number (accepts v*.*.*[-...])",e=>!!e.toString().match(/^v[0-9]+\.[0-9]+.[0-9]+(-[0-9a-zA-Z-]+)?$/)))}testVersion(e){const t=this.log.for(this.testVersion);switch(e=e.trim().toLowerCase()){case $.PATCH:case $.MINOR:case $.MAJOR:return t.verbose("Using provided SemVer update: "+e,1),e;default:return t.verbose("Testing provided version for SemVer compatibility: "+e,1),RegExp(k).test(e)?(t.verbose("version approved: "+e,1),e):void t.debug("Invalid version number: "+e)}}async prepareMessage(e){const t=this.log.for(this.prepareMessage);return e||(t.verbose("No release message provided. Prompting for one"),await w.insistForText("message","What should be the release message/ticket?",e=>!!e&&e.toString().length>5))}async run(e){let t;const{ci:o}=e;let{tag:a,message:s}=e;a=await this.prepareVersion(a),s=await this.prepareMessage(s),t=await M(`npm run prepare-release -- ${a} ${s}`,{cwd:process.cwd()}).promise,t=await M("git status --porcelain").promise,await t,t.logs.length&&await w.askConfirmation("git-changes","Do you want to push the changes to the remote repository?",!0)&&(await M("git add .").promise,await M(`git commit -m "${a} - ${s} - after release preparation${o?"":E}"`).promise),await M(`npm version "${a}" -m "${s}${o?"":E}"`).promise,await M("git push --follow-tags").promise,o||await M("NPM_TOKEN=$(cat .npmtoken) npm publish --access public").promise}}class we extends x{constructor(e,t,o,a="g"){super(e,t);try{this.regexp="string"==typeof o?RegExp(o,a):o}catch(e){throw Error("Invalid regular expression: "+e)}}test(e){let t;this.regexp.lastIndex=0;try{t=this.regexp.exec(e)}catch(e){return}return t}testAndResolve(e){const t=this.test(e);t&&this.resolve(t[0])}testAndReject(e){const t=this.test(e);t&&this.reject(t[0])}data(e){super.data(e),this.testAndResolve(e+"")}error(e){super.error(e),this.testAndReject(e+"")}}const Ce="##VERSION##",De="##PACKAGE##";export{N as AbortCode,ye as BuildScripts,ne as Command,C as DefaultCommandOptions,D as DefaultCommandValues,v as Encoding,ie as HttpClient,E as NoCIFLag,De as PACKAGE_NAME,we as RegexpOutputWriter,be as ReleaseScript,$ as SemVersion,k as SemVersionRegex,I as SetupScriptKey,x as StandardOutputWriter,F as Tokens,w as UserInput,Ce as VERSION,j as chainAbortController,W as copyFile,X as deletePath,R as getAllFiles,H as getDependencies,Q as getFileSizeZipped,V as getPackage,ge as getPackageDependencies,_ as getPackageVersion,re as getSlogan,q as installDependencies,z as installIfNotAvailable,ee as listFolder,te as listNodeModulesPackages,A as lockify,Z as normalizeImport,le as packageToGlobal,ce as parseList,U as patchFile,se as printBanner,Y as pushToGit,O as readFile,J as renameFile,M as runCommand,G as setPackageAttribute,B as spawnCommand,K as updateDependencies,L as writeFile};
|
|
2
|
-
|
|
1
|
+
import prompts from "prompts";
|
|
2
|
+
|
|
3
|
+
import { parseArgs } from "util";
|
|
4
|
+
|
|
5
|
+
import { Logging, escapeRegExp, LoggedClass, LoggedEnvironment, StopWatch, LogLevel } from "@decaf-ts/logging";
|
|
6
|
+
|
|
7
|
+
import fs from "fs";
|
|
8
|
+
|
|
9
|
+
import path from "path";
|
|
10
|
+
|
|
11
|
+
import { createRequire, builtinModules } from "module";
|
|
12
|
+
|
|
13
|
+
import { spawn } from "child_process";
|
|
14
|
+
|
|
15
|
+
import { style } from "styled-string-builder";
|
|
16
|
+
|
|
17
|
+
import { parse } from "shell-quote";
|
|
18
|
+
|
|
19
|
+
import zlib from "zlib";
|
|
20
|
+
|
|
21
|
+
import https from "https";
|
|
22
|
+
|
|
23
|
+
import { mkdir, writeFile as writeFile$1 } from "fs/promises";
|
|
24
|
+
|
|
25
|
+
import { rollup } from "rollup";
|
|
26
|
+
|
|
27
|
+
import typescript from "@rollup/plugin-typescript";
|
|
28
|
+
|
|
29
|
+
import commonjs from "@rollup/plugin-commonjs";
|
|
30
|
+
|
|
31
|
+
import { nodeResolve } from "@rollup/plugin-node-resolve";
|
|
32
|
+
|
|
33
|
+
import json from "@rollup/plugin-json";
|
|
34
|
+
|
|
35
|
+
import * as ts from "typescript";
|
|
36
|
+
|
|
37
|
+
import { ModuleKind } from "typescript";
|
|
38
|
+
|
|
39
|
+
class UserInput {
|
|
40
|
+
static {
|
|
41
|
+
this.logger = Logging.for(UserInput);
|
|
42
|
+
}
|
|
43
|
+
constructor(name) {
|
|
44
|
+
this.type = "text";
|
|
45
|
+
this.name = name;
|
|
46
|
+
}
|
|
47
|
+
setType(type) {
|
|
48
|
+
UserInput.logger.verbose(`Setting type to: ${type}`);
|
|
49
|
+
this.type = type;
|
|
50
|
+
return this;
|
|
51
|
+
}
|
|
52
|
+
setMessage(value) {
|
|
53
|
+
UserInput.logger.verbose(`Setting message to: ${value}`);
|
|
54
|
+
this.message = value;
|
|
55
|
+
return this;
|
|
56
|
+
}
|
|
57
|
+
setInitial(value) {
|
|
58
|
+
UserInput.logger.verbose(`Setting initial value to: ${value}`);
|
|
59
|
+
this.initial = value;
|
|
60
|
+
return this;
|
|
61
|
+
}
|
|
62
|
+
setStyle(value) {
|
|
63
|
+
UserInput.logger.verbose(`Setting style to: ${value}`);
|
|
64
|
+
this.style = value;
|
|
65
|
+
return this;
|
|
66
|
+
}
|
|
67
|
+
setFormat(value) {
|
|
68
|
+
UserInput.logger.verbose(`Setting format function`);
|
|
69
|
+
this.format = value;
|
|
70
|
+
return this;
|
|
71
|
+
}
|
|
72
|
+
setValidate(value) {
|
|
73
|
+
UserInput.logger.verbose(`Setting validate function`);
|
|
74
|
+
this.validate = value;
|
|
75
|
+
return this;
|
|
76
|
+
}
|
|
77
|
+
setOnState(value) {
|
|
78
|
+
UserInput.logger.verbose(`Setting onState callback`);
|
|
79
|
+
this.onState = value;
|
|
80
|
+
return this;
|
|
81
|
+
}
|
|
82
|
+
setMin(value) {
|
|
83
|
+
UserInput.logger.verbose(`Setting min value to: ${value}`);
|
|
84
|
+
this.min = value;
|
|
85
|
+
return this;
|
|
86
|
+
}
|
|
87
|
+
setMax(value) {
|
|
88
|
+
UserInput.logger.verbose(`Setting max value to: ${value}`);
|
|
89
|
+
this.max = value;
|
|
90
|
+
return this;
|
|
91
|
+
}
|
|
92
|
+
setFloat(value) {
|
|
93
|
+
UserInput.logger.verbose(`Setting float to: ${value}`);
|
|
94
|
+
this.float = value;
|
|
95
|
+
return this;
|
|
96
|
+
}
|
|
97
|
+
setRound(value) {
|
|
98
|
+
UserInput.logger.verbose(`Setting round to: ${value}`);
|
|
99
|
+
this.round = value;
|
|
100
|
+
return this;
|
|
101
|
+
}
|
|
102
|
+
setInstructions(value) {
|
|
103
|
+
UserInput.logger.verbose(`Setting instructions to: ${value}`);
|
|
104
|
+
this.instructions = value;
|
|
105
|
+
return this;
|
|
106
|
+
}
|
|
107
|
+
setIncrement(value) {
|
|
108
|
+
UserInput.logger.verbose(`Setting increment to: ${value}`);
|
|
109
|
+
this.increment = value;
|
|
110
|
+
return this;
|
|
111
|
+
}
|
|
112
|
+
setSeparator(value) {
|
|
113
|
+
UserInput.logger.verbose(`Setting separator to: ${value}`);
|
|
114
|
+
this.separator = value;
|
|
115
|
+
return this;
|
|
116
|
+
}
|
|
117
|
+
setActive(value) {
|
|
118
|
+
UserInput.logger.verbose(`Setting active style to: ${value}`);
|
|
119
|
+
this.active = value;
|
|
120
|
+
return this;
|
|
121
|
+
}
|
|
122
|
+
setInactive(value) {
|
|
123
|
+
UserInput.logger.verbose(`Setting inactive style to: ${value}`);
|
|
124
|
+
this.inactive = value;
|
|
125
|
+
return this;
|
|
126
|
+
}
|
|
127
|
+
setChoices(value) {
|
|
128
|
+
UserInput.logger.verbose(`Setting choices: ${JSON.stringify(value)}`);
|
|
129
|
+
this.choices = value;
|
|
130
|
+
return this;
|
|
131
|
+
}
|
|
132
|
+
setHint(value) {
|
|
133
|
+
UserInput.logger.verbose(`Setting hint to: ${value}`);
|
|
134
|
+
this.hint = value;
|
|
135
|
+
return this;
|
|
136
|
+
}
|
|
137
|
+
setWarn(value) {
|
|
138
|
+
UserInput.logger.verbose(`Setting warn to: ${value}`);
|
|
139
|
+
this.warn = value;
|
|
140
|
+
return this;
|
|
141
|
+
}
|
|
142
|
+
setSuggest(value) {
|
|
143
|
+
UserInput.logger.verbose(`Setting suggest function`);
|
|
144
|
+
this.suggest = value;
|
|
145
|
+
return this;
|
|
146
|
+
}
|
|
147
|
+
setLimit(value) {
|
|
148
|
+
UserInput.logger.verbose(`Setting limit to: ${value}`);
|
|
149
|
+
this.limit = value;
|
|
150
|
+
return this;
|
|
151
|
+
}
|
|
152
|
+
setMask(value) {
|
|
153
|
+
UserInput.logger.verbose(`Setting mask to: ${value}`);
|
|
154
|
+
this.mask = value;
|
|
155
|
+
return this;
|
|
156
|
+
}
|
|
157
|
+
setStdout(value) {
|
|
158
|
+
UserInput.logger.verbose(`Setting stdout stream`);
|
|
159
|
+
this.stdout = value;
|
|
160
|
+
return this;
|
|
161
|
+
}
|
|
162
|
+
setStdin(value) {
|
|
163
|
+
this.stdin = value;
|
|
164
|
+
return this;
|
|
165
|
+
}
|
|
166
|
+
async ask() {
|
|
167
|
+
return (await UserInput.ask(this))[this.name];
|
|
168
|
+
}
|
|
169
|
+
static async ask(question) {
|
|
170
|
+
const log = UserInput.logger.for(this.ask);
|
|
171
|
+
if (!Array.isArray(question)) {
|
|
172
|
+
question = [ question ];
|
|
173
|
+
}
|
|
174
|
+
let answers;
|
|
175
|
+
try {
|
|
176
|
+
log.verbose(`Asking questions: ${question.map(q => q.name).join(", ")}`);
|
|
177
|
+
answers = await prompts(question);
|
|
178
|
+
log.verbose(`Received answers: ${JSON.stringify(answers, null, 2)}`);
|
|
179
|
+
} catch (error) {
|
|
180
|
+
throw new Error(`Error while getting input: ${error}`);
|
|
181
|
+
}
|
|
182
|
+
return answers;
|
|
183
|
+
}
|
|
184
|
+
static async askNumber(name, question, min, max, initial) {
|
|
185
|
+
const log = UserInput.logger.for(this.askNumber);
|
|
186
|
+
log.verbose(`Asking number input: undefined, question: ${question}, min: ${min}, max: ${max}, initial: ${initial}`);
|
|
187
|
+
const userInput = new UserInput(name).setMessage(question).setType("number");
|
|
188
|
+
if (typeof min === "number") userInput.setMin(min);
|
|
189
|
+
if (typeof max === "number") userInput.setMax(max);
|
|
190
|
+
if (typeof initial === "number") userInput.setInitial(initial);
|
|
191
|
+
return (await this.ask(userInput))[name];
|
|
192
|
+
}
|
|
193
|
+
static async askText(name, question, mask = undefined, initial) {
|
|
194
|
+
const log = UserInput.logger.for(this.askText);
|
|
195
|
+
log.verbose(`Asking text input: undefined, question: ${question}, mask: ${mask}, initial: ${initial}`);
|
|
196
|
+
const userInput = new UserInput(name).setMessage(question);
|
|
197
|
+
if (mask) userInput.setMask(mask);
|
|
198
|
+
if (typeof initial === "string") userInput.setInitial(initial);
|
|
199
|
+
return (await this.ask(userInput))[name];
|
|
200
|
+
}
|
|
201
|
+
static async askConfirmation(name, question, initial) {
|
|
202
|
+
const log = UserInput.logger.for(this.askConfirmation);
|
|
203
|
+
log.verbose(`Asking confirmation input: undefined, question: ${question}, initial: ${initial}`);
|
|
204
|
+
const userInput = new UserInput(name).setMessage(question).setType("confirm");
|
|
205
|
+
if (typeof initial !== "undefined") userInput.setInitial(initial);
|
|
206
|
+
return (await this.ask(userInput))[name];
|
|
207
|
+
}
|
|
208
|
+
static async insist(input, test, defaultConfirmation, limit = 1) {
|
|
209
|
+
const log = UserInput.logger.for(this.insist);
|
|
210
|
+
log.verbose(`Insisting on input: ${input.name}, test: ${test.toString()}, defaultConfirmation: ${defaultConfirmation}, limit: ${limit}`);
|
|
211
|
+
let result = undefined;
|
|
212
|
+
let count = 0;
|
|
213
|
+
let confirmation;
|
|
214
|
+
try {
|
|
215
|
+
do {
|
|
216
|
+
result = (await UserInput.ask(input))[input.name];
|
|
217
|
+
if (!test(result)) {
|
|
218
|
+
result = undefined;
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
confirmation = await UserInput.askConfirmation(`${input.name}-confirm`, `Is the ${input.type} correct?`, defaultConfirmation);
|
|
222
|
+
if (!confirmation) result = undefined;
|
|
223
|
+
} while (typeof result === "undefined" && limit > 1 && count++ < limit);
|
|
224
|
+
} catch (e) {
|
|
225
|
+
log.error(`Error while insisting: ${e}`);
|
|
226
|
+
throw e;
|
|
227
|
+
}
|
|
228
|
+
if (typeof result === "undefined") log.info("no selection...");
|
|
229
|
+
return result;
|
|
230
|
+
}
|
|
231
|
+
static async insistForText(name, question, test, mask = undefined, initial, defaultConfirmation = false, limit = -1) {
|
|
232
|
+
const log = UserInput.logger.for(this.insistForText);
|
|
233
|
+
log.verbose(`Insisting for text input: undefined, question: ${question}, test: ${test.toString()}, mask: ${mask}, initial: ${initial}, defaultConfirmation: ${defaultConfirmation}, limit: ${limit}`);
|
|
234
|
+
const userInput = new UserInput(name).setMessage(question);
|
|
235
|
+
if (mask) userInput.setMask(mask);
|
|
236
|
+
if (typeof initial === "string") userInput.setInitial(initial);
|
|
237
|
+
return await this.insist(userInput, test, defaultConfirmation, limit);
|
|
238
|
+
}
|
|
239
|
+
static async insistForNumber(name, question, test, min, max, initial, defaultConfirmation = false, limit = -1) {
|
|
240
|
+
const log = UserInput.logger.for(this.insistForNumber);
|
|
241
|
+
log.verbose(`Insisting for number input: undefined, question: ${question}, test: ${test.toString()}, min: ${min}, max: ${max}, initial: ${initial}, defaultConfirmation: ${defaultConfirmation}, limit: ${limit}`);
|
|
242
|
+
const userInput = new UserInput(name).setMessage(question).setType("number");
|
|
243
|
+
if (typeof min === "number") userInput.setMin(min);
|
|
244
|
+
if (typeof max === "number") userInput.setMax(max);
|
|
245
|
+
if (typeof initial === "number") userInput.setInitial(initial);
|
|
246
|
+
return await this.insist(userInput, test, defaultConfirmation, limit);
|
|
247
|
+
}
|
|
248
|
+
static parseArgs(options) {
|
|
249
|
+
const log = UserInput.logger.for(this.parseArgs);
|
|
250
|
+
const args = {
|
|
251
|
+
args: process.argv.slice(2),
|
|
252
|
+
options: options
|
|
253
|
+
};
|
|
254
|
+
log.debug(`Parsing arguments: ${JSON.stringify(args, null, 2)}`);
|
|
255
|
+
try {
|
|
256
|
+
return parseArgs(args);
|
|
257
|
+
} catch (error) {
|
|
258
|
+
log.debug(`Error while parsing arguments:\n${JSON.stringify(args, null, 2)}\n | options\n${JSON.stringify(options, null, 2)}\n | ${error}`);
|
|
259
|
+
throw new Error(`Error while parsing arguments: ${error}`);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const DefaultCommandOptions = {
|
|
265
|
+
verbose: {
|
|
266
|
+
type: "boolean",
|
|
267
|
+
short: "V",
|
|
268
|
+
default: undefined
|
|
269
|
+
},
|
|
270
|
+
version: {
|
|
271
|
+
type: "boolean",
|
|
272
|
+
short: "v",
|
|
273
|
+
default: undefined
|
|
274
|
+
},
|
|
275
|
+
help: {
|
|
276
|
+
type: "boolean",
|
|
277
|
+
short: "h",
|
|
278
|
+
default: false
|
|
279
|
+
},
|
|
280
|
+
logLevel: {
|
|
281
|
+
type: "string",
|
|
282
|
+
default: "info"
|
|
283
|
+
},
|
|
284
|
+
logStyle: {
|
|
285
|
+
type: "boolean",
|
|
286
|
+
default: true
|
|
287
|
+
},
|
|
288
|
+
timestamp: {
|
|
289
|
+
type: "boolean",
|
|
290
|
+
default: true
|
|
291
|
+
},
|
|
292
|
+
banner: {
|
|
293
|
+
type: "boolean",
|
|
294
|
+
default: true
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
const DefaultCommandValues = Object.keys(DefaultCommandOptions).reduce((acc, key) => {
|
|
299
|
+
acc[key] = DefaultCommandOptions[key].default;
|
|
300
|
+
return acc;
|
|
301
|
+
}, {});
|
|
302
|
+
|
|
303
|
+
const Encoding = "utf-8";
|
|
304
|
+
|
|
305
|
+
const SemVersionRegex = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z])))/g;
|
|
306
|
+
|
|
307
|
+
var SemVersion;
|
|
308
|
+
|
|
309
|
+
(function(SemVersion) {
|
|
310
|
+
SemVersion["PATCH"] = "patch";
|
|
311
|
+
SemVersion["MINOR"] = "minor";
|
|
312
|
+
SemVersion["MAJOR"] = "major";
|
|
313
|
+
})(SemVersion || (SemVersion = {}));
|
|
314
|
+
|
|
315
|
+
const NoCIFLag = "-no-ci";
|
|
316
|
+
|
|
317
|
+
const SetupScriptKey = "postinstall";
|
|
318
|
+
|
|
319
|
+
var Tokens;
|
|
320
|
+
|
|
321
|
+
(function(Tokens) {
|
|
322
|
+
Tokens["GIT"] = ".token";
|
|
323
|
+
Tokens["NPM"] = ".npmtoken";
|
|
324
|
+
Tokens["DOCKER"] = ".dockertoken";
|
|
325
|
+
Tokens["CONFLUENCE"] = ".confluence-token";
|
|
326
|
+
})(Tokens || (Tokens = {}));
|
|
327
|
+
|
|
328
|
+
const AbortCode = "Aborted";
|
|
329
|
+
|
|
330
|
+
class StandardOutputWriter {
|
|
331
|
+
constructor(cmd, lock, ...args) {
|
|
332
|
+
this.cmd = cmd;
|
|
333
|
+
this.lock = lock;
|
|
334
|
+
this.logger = Logging.for(this.cmd);
|
|
335
|
+
}
|
|
336
|
+
log(type, data) {
|
|
337
|
+
data = Buffer.isBuffer(data) ? data.toString(Encoding) : data;
|
|
338
|
+
const log = type === "stderr" ? style(data).red.text : data;
|
|
339
|
+
this.logger.info(log);
|
|
340
|
+
}
|
|
341
|
+
data(chunk) {
|
|
342
|
+
this.log("stdout", String(chunk));
|
|
343
|
+
}
|
|
344
|
+
error(chunk) {
|
|
345
|
+
this.log("stderr", String(chunk));
|
|
346
|
+
}
|
|
347
|
+
errors(err) {
|
|
348
|
+
this.log("stderr", `Error executing command exited : ${err}`);
|
|
349
|
+
}
|
|
350
|
+
exit(code, logs) {
|
|
351
|
+
this.log("stdout", `command exited code : ${code === 0 ? style(code.toString()).green.text : style(code === null ? "null" : code.toString()).red.text}`);
|
|
352
|
+
if (code === 0) {
|
|
353
|
+
this.resolve(logs.map(l => l.trim()).join("\n"));
|
|
354
|
+
} else {
|
|
355
|
+
this.reject(new Error(logs.length ? logs.join("\n") : code.toString()));
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
parseCommand(command) {
|
|
359
|
+
if (Array.isArray(command)) {
|
|
360
|
+
this.cmd = command.join(" ");
|
|
361
|
+
return [ command[0], command.slice(1) ];
|
|
362
|
+
}
|
|
363
|
+
const parts = parse(command).filter(p => typeof p === "string").map(String);
|
|
364
|
+
this.cmd = parts.join(" ");
|
|
365
|
+
return [ parts[0], parts.slice(1) ];
|
|
366
|
+
}
|
|
367
|
+
resolve(reason) {
|
|
368
|
+
this.log("stdout", `${this.cmd} executed successfully: ${style(reason ? "ran to completion" : reason).green}`);
|
|
369
|
+
this.lock.resolve(reason);
|
|
370
|
+
}
|
|
371
|
+
reject(reason) {
|
|
372
|
+
if (!(reason instanceof Error)) {
|
|
373
|
+
reason = new Error(typeof reason === "number" ? `Exit code ${reason}` : reason);
|
|
374
|
+
}
|
|
375
|
+
this.log("stderr", `${this.cmd} failed to execute: ${style(reason.message).red}`);
|
|
376
|
+
this.lock.reject(reason);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
function lockify(f) {
|
|
381
|
+
let lock = Promise.resolve();
|
|
382
|
+
return (...params) => {
|
|
383
|
+
const result = lock.then(() => f(...params));
|
|
384
|
+
lock = result.catch(() => {});
|
|
385
|
+
return result;
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
function chainAbortController(argument0, ...remainder) {
|
|
390
|
+
let signals;
|
|
391
|
+
let controller;
|
|
392
|
+
if (argument0 instanceof AbortSignal) {
|
|
393
|
+
controller = new AbortController;
|
|
394
|
+
signals = [ argument0, ...remainder ];
|
|
395
|
+
} else {
|
|
396
|
+
controller = argument0;
|
|
397
|
+
signals = remainder;
|
|
398
|
+
}
|
|
399
|
+
if (controller.signal.aborted) {
|
|
400
|
+
return controller;
|
|
401
|
+
}
|
|
402
|
+
const handler = () => controller.abort();
|
|
403
|
+
for (const signal of signals) {
|
|
404
|
+
if (signal.aborted) {
|
|
405
|
+
controller.abort();
|
|
406
|
+
break;
|
|
407
|
+
}
|
|
408
|
+
signal.addEventListener("abort", handler, {
|
|
409
|
+
once: true,
|
|
410
|
+
signal: controller.signal
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
return controller;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
function spawnCommand(output, command, opts, abort, logger) {
|
|
417
|
+
function spawnInner(command, controller) {
|
|
418
|
+
const [cmd, argz] = output.parseCommand(command);
|
|
419
|
+
logger.info(`Running command: ${cmd}`);
|
|
420
|
+
logger.debug(`with args: ${argz.join(" ")}`);
|
|
421
|
+
const childProcess = spawn(cmd, argz, {
|
|
422
|
+
...opts,
|
|
423
|
+
cwd: opts.cwd || process.cwd(),
|
|
424
|
+
env: Object.assign({}, process.env, opts.env, {
|
|
425
|
+
PATH: process.env.PATH
|
|
426
|
+
}),
|
|
427
|
+
shell: opts.shell || false,
|
|
428
|
+
signal: controller.signal
|
|
429
|
+
});
|
|
430
|
+
logger.verbose(`pid : ${childProcess.pid}`);
|
|
431
|
+
return childProcess;
|
|
432
|
+
}
|
|
433
|
+
const m = command.match(/[<>$#]/g);
|
|
434
|
+
if (m) throw new Error(`Invalid command: ${command}. contains invalid characters: ${m}`);
|
|
435
|
+
if (command.includes(" | ")) {
|
|
436
|
+
const cmds = command.split(" | ");
|
|
437
|
+
const spawns = [];
|
|
438
|
+
const controllers = new Array(cmds.length);
|
|
439
|
+
controllers[0] = abort;
|
|
440
|
+
for (let i = 0; i < cmds.length; i++) {
|
|
441
|
+
if (i !== 0) controllers[i] = chainAbortController(controllers[i - 1].signal);
|
|
442
|
+
spawns.push(spawnInner(cmds[i], controllers[i]));
|
|
443
|
+
if (i === 0) continue;
|
|
444
|
+
spawns[i - 1].stdout.pipe(spawns[i].stdin);
|
|
445
|
+
}
|
|
446
|
+
return spawns[cmds.length - 1];
|
|
447
|
+
}
|
|
448
|
+
return spawnInner(command, abort);
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
function runCommand(command, opts = {}, outputConstructor = StandardOutputWriter, ...args) {
|
|
452
|
+
const logger = Logging.for(runCommand);
|
|
453
|
+
const abort = new AbortController;
|
|
454
|
+
const result = {
|
|
455
|
+
abort: abort,
|
|
456
|
+
command: command,
|
|
457
|
+
logs: [],
|
|
458
|
+
errs: []
|
|
459
|
+
};
|
|
460
|
+
const lock = new Promise((resolve, reject) => {
|
|
461
|
+
let output;
|
|
462
|
+
try {
|
|
463
|
+
output = new outputConstructor(command, {
|
|
464
|
+
resolve: resolve,
|
|
465
|
+
reject: reject
|
|
466
|
+
}, ...args);
|
|
467
|
+
result.cmd = spawnCommand(output, command, opts, abort, logger);
|
|
468
|
+
} catch (e) {
|
|
469
|
+
return reject(new Error(`Error running command ${command}: ${e}`));
|
|
470
|
+
}
|
|
471
|
+
result.cmd.stdout.setEncoding("utf8");
|
|
472
|
+
result.cmd.stdout.on("data", chunk => {
|
|
473
|
+
chunk = chunk.toString();
|
|
474
|
+
result.logs.push(chunk);
|
|
475
|
+
output.data(chunk);
|
|
476
|
+
});
|
|
477
|
+
result.cmd.stderr.on("data", data => {
|
|
478
|
+
data = data.toString();
|
|
479
|
+
result.errs.push(data);
|
|
480
|
+
output.error(data);
|
|
481
|
+
});
|
|
482
|
+
result.cmd.once("error", err => {
|
|
483
|
+
output.exit(err.message, result.errs);
|
|
484
|
+
});
|
|
485
|
+
result.cmd.once("exit", (code = 0) => {
|
|
486
|
+
if (abort.signal.aborted && code === null) code = AbortCode;
|
|
487
|
+
output.exit(code, code === 0 ? result.logs : result.errs);
|
|
488
|
+
});
|
|
489
|
+
});
|
|
490
|
+
Object.assign(result, {
|
|
491
|
+
promise: lock,
|
|
492
|
+
pipe: async cb => {
|
|
493
|
+
const l = logger.for("pipe");
|
|
494
|
+
try {
|
|
495
|
+
l.verbose(`Executing pipe function ${command}...`);
|
|
496
|
+
const result = await lock;
|
|
497
|
+
l.verbose(`Piping output to ${cb.name}: ${result}`);
|
|
498
|
+
return cb(result);
|
|
499
|
+
} catch (e) {
|
|
500
|
+
l.error(`Error piping command output: ${e}`);
|
|
501
|
+
throw e;
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
});
|
|
505
|
+
return result;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
const logger = Logging.for("fs");
|
|
509
|
+
|
|
510
|
+
const localRequire = createRequire(`${process.cwd()}/package.json`);
|
|
511
|
+
|
|
512
|
+
function isTestEnvironment() {
|
|
513
|
+
return process.env.NODE_ENV === "test" || typeof process.env.JEST_WORKER_ID !== "undefined";
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
function patchString(input, values, flags = "g", filter) {
|
|
517
|
+
Object.entries(values).forEach(([key, val]) => {
|
|
518
|
+
const regexp = new RegExp(escapeRegExp(key), flags);
|
|
519
|
+
input = input.replace(regexp, subStr => {
|
|
520
|
+
if (!filter || filter(subStr)) {
|
|
521
|
+
return val;
|
|
522
|
+
}
|
|
523
|
+
return val;
|
|
524
|
+
});
|
|
525
|
+
});
|
|
526
|
+
return input;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
function patchFile(path, values, filter) {
|
|
530
|
+
const log = logger.for(patchFile);
|
|
531
|
+
if (!fs.existsSync(path)) throw new Error(`File not found at path "${path}".`);
|
|
532
|
+
let content = readFile(path);
|
|
533
|
+
log.verbose(`Patching file "${path}"...`);
|
|
534
|
+
log.debug(`with value: ${JSON.stringify(values)}`);
|
|
535
|
+
try {
|
|
536
|
+
content = patchString(content, values, "g", filter);
|
|
537
|
+
} catch (error) {
|
|
538
|
+
throw new Error(`Error patching file: ${error}`);
|
|
539
|
+
}
|
|
540
|
+
writeFile(path, content);
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
function readFile(path) {
|
|
544
|
+
const log = logger.for(readFile);
|
|
545
|
+
try {
|
|
546
|
+
log.verbose(`Reading file "${path}"...`);
|
|
547
|
+
return fs.readFileSync(path, "utf8");
|
|
548
|
+
} catch (error) {
|
|
549
|
+
log.verbose(`Error reading file "${path}": ${error}`);
|
|
550
|
+
throw new Error(`Error reading file "${path}": ${error}`);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
function writeFile(path, data) {
|
|
555
|
+
const log = logger.for(writeFile);
|
|
556
|
+
try {
|
|
557
|
+
log.verbose(`Writing file "${path} with ${data.length} bytes...`);
|
|
558
|
+
fs.writeFileSync(path, data, "utf8");
|
|
559
|
+
} catch (error) {
|
|
560
|
+
log.verbose(`Error writing file "${path}": ${error}`);
|
|
561
|
+
throw new Error(`Error writing file "${path}": ${error}`);
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
function getAllFiles(p, filter) {
|
|
566
|
+
const log = logger.for(getAllFiles);
|
|
567
|
+
const files = [];
|
|
568
|
+
try {
|
|
569
|
+
log.verbose(`Retrieving all files from "${p}"...`);
|
|
570
|
+
const entries = fs.readdirSync(p);
|
|
571
|
+
entries.forEach(entry => {
|
|
572
|
+
const fullPath = path.join(p, entry);
|
|
573
|
+
const stat = fs.statSync(fullPath);
|
|
574
|
+
if (stat.isFile()) {
|
|
575
|
+
files.push(fullPath);
|
|
576
|
+
} else if (stat.isDirectory()) {
|
|
577
|
+
files.push(...getAllFiles(fullPath));
|
|
578
|
+
}
|
|
579
|
+
});
|
|
580
|
+
if (!filter) return files;
|
|
581
|
+
return files.filter(filter);
|
|
582
|
+
} catch (error) {
|
|
583
|
+
log.verbose(`Error retrieving files from "${p}": ${error}`);
|
|
584
|
+
throw new Error(`Error retrieving files from "${p}": ${error}`);
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
async function renameFile(source, dest) {
|
|
589
|
+
const log = logger.for(renameFile);
|
|
590
|
+
let descriptorSource, descriptorDest;
|
|
591
|
+
try {
|
|
592
|
+
descriptorSource = fs.statSync(source);
|
|
593
|
+
} catch (error) {
|
|
594
|
+
log.verbose(`Source path "${source}" does not exist: ${error}`);
|
|
595
|
+
throw new Error(`Source path "${source}" does not exist: ${error}`);
|
|
596
|
+
}
|
|
597
|
+
try {
|
|
598
|
+
descriptorDest = fs.statSync(dest);
|
|
599
|
+
} catch (e) {}
|
|
600
|
+
if (descriptorDest) {
|
|
601
|
+
log.verbose(`Destination path "${dest}" already exists`);
|
|
602
|
+
throw new Error(`Destination path "${dest}" already exists`);
|
|
603
|
+
}
|
|
604
|
+
try {
|
|
605
|
+
log.verbose(`Renaming ${descriptorSource.isFile() ? "file" : "directory"} "${source}" to "${dest}...`);
|
|
606
|
+
fs.renameSync(source, dest);
|
|
607
|
+
log.verbose(`Successfully renamed to "${dest}"`);
|
|
608
|
+
} catch (error) {
|
|
609
|
+
log.verbose(`Error renaming ${descriptorSource.isFile() ? "file" : "directory"} "${source}" to "${dest}": ${error}`);
|
|
610
|
+
throw new Error(`Error renaming ${descriptorSource.isFile() ? "file" : "directory"} "${source}" to "${dest}": ${error}`);
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
function copyFile(source, dest) {
|
|
615
|
+
const log = logger.for(copyFile);
|
|
616
|
+
let descriptorSource, descriptorDest;
|
|
617
|
+
try {
|
|
618
|
+
descriptorSource = fs.statSync(source);
|
|
619
|
+
} catch (error) {
|
|
620
|
+
log.verbose(`Source path "${source}" does not exist: ${error}`);
|
|
621
|
+
throw new Error(`Source path "${source}" does not exist: ${error}`);
|
|
622
|
+
}
|
|
623
|
+
try {
|
|
624
|
+
descriptorDest = fs.statSync(dest);
|
|
625
|
+
} catch (error) {
|
|
626
|
+
if (descriptorSource.isDirectory()) {
|
|
627
|
+
log.verbose(`Dest path "${dest}" does not exist. creating`);
|
|
628
|
+
fs.mkdirSync(dest, {
|
|
629
|
+
recursive: true
|
|
630
|
+
});
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
try {
|
|
634
|
+
log.verbose(`Copying ${descriptorSource.isFile() ? "file" : "directory"} "${source}" to "${dest}...`);
|
|
635
|
+
fs.cpSync(source, dest, {
|
|
636
|
+
recursive: true
|
|
637
|
+
});
|
|
638
|
+
} catch (error) {
|
|
639
|
+
log.verbose(`Error copying ${descriptorSource.isFile() ? "file" : "directory"} "${source}" to "${dest}: ${error}`);
|
|
640
|
+
throw new Error(`Error copying ${descriptorSource.isFile() ? "file" : "directory"} "${source}" to "${dest}: ${error}`);
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
function deletePath(p) {
|
|
645
|
+
const log = logger.for(deletePath);
|
|
646
|
+
try {
|
|
647
|
+
const descriptor = fs.statSync(p);
|
|
648
|
+
if (descriptor.isFile()) {
|
|
649
|
+
log.verbose(`Deleting file "${p}...`);
|
|
650
|
+
fs.rmSync(p, {
|
|
651
|
+
recursive: true,
|
|
652
|
+
force: true
|
|
653
|
+
});
|
|
654
|
+
} else if (descriptor.isDirectory()) fs.rmSync(p, {
|
|
655
|
+
recursive: true,
|
|
656
|
+
force: true
|
|
657
|
+
});
|
|
658
|
+
} catch (error) {
|
|
659
|
+
log.verbose(`Error Deleting "${p}": ${error}`);
|
|
660
|
+
throw new Error(`Error Deleting "${p}": ${error}`);
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
function getPackage(p = process.cwd(), property) {
|
|
665
|
+
let pkg;
|
|
666
|
+
try {
|
|
667
|
+
pkg = JSON.parse(readFile(path.join(p, `package.json`)));
|
|
668
|
+
} catch (error) {
|
|
669
|
+
throw new Error(`Failed to retrieve package information" ${error}`);
|
|
670
|
+
}
|
|
671
|
+
if (property) {
|
|
672
|
+
if (!(property in pkg)) throw new Error(`Property "${property}" not found in package.json`);
|
|
673
|
+
return pkg[property];
|
|
674
|
+
}
|
|
675
|
+
return pkg;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
function setPackageAttribute(attr, value, p = process.cwd()) {
|
|
679
|
+
const pkg = getPackage(p);
|
|
680
|
+
pkg[attr] = value;
|
|
681
|
+
writeFile(path.join(p, `package.json`), JSON.stringify(pkg, null, 2));
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
function getPackageVersion(p = process.cwd()) {
|
|
685
|
+
return getPackage(p, "version");
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
async function getDependencies(p = process.cwd()) {
|
|
689
|
+
const pkgPath = path.join(p, "package.json");
|
|
690
|
+
const lockPath = path.join(p, "package-lock.json");
|
|
691
|
+
let pkg;
|
|
692
|
+
try {
|
|
693
|
+
pkg = JSON.parse(readFile(pkgPath));
|
|
694
|
+
} catch (error) {
|
|
695
|
+
throw new Error(`Could not read package.json at ${pkgPath}: ${error}`);
|
|
696
|
+
}
|
|
697
|
+
let lock;
|
|
698
|
+
if (fs.existsSync(lockPath)) {
|
|
699
|
+
try {
|
|
700
|
+
lock = JSON.parse(readFile(lockPath));
|
|
701
|
+
} catch (error) {
|
|
702
|
+
logger.warn(`Unable to parse package-lock.json at ${lockPath}: ${error}`);
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
const mapDeps = (entries = {}) => Object.entries(entries).map(([name, version]) => ({
|
|
706
|
+
name: name,
|
|
707
|
+
version: resolveDependencyVersion(lock, name, version)
|
|
708
|
+
}));
|
|
709
|
+
return {
|
|
710
|
+
prod: mapDeps(pkg.dependencies),
|
|
711
|
+
dev: mapDeps(pkg.devDependencies),
|
|
712
|
+
peer: mapDeps(pkg.peerDependencies)
|
|
713
|
+
};
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
function resolveDependencyVersion(lock, name, fallback) {
|
|
717
|
+
if (lock) {
|
|
718
|
+
const packages = lock.packages || {};
|
|
719
|
+
const key = `node_modules/${name}`;
|
|
720
|
+
if (packages[key] && packages[key].version) {
|
|
721
|
+
return packages[key].version;
|
|
722
|
+
}
|
|
723
|
+
if (lock.dependencies && lock.dependencies[name]) {
|
|
724
|
+
return lock.dependencies[name].version || fallback;
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
return fallback;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
async function updateDependencies() {
|
|
731
|
+
const log = logger.for(updateDependencies);
|
|
732
|
+
log.info("checking for updates...");
|
|
733
|
+
await runCommand("npx npm-check-updates -u").promise;
|
|
734
|
+
log.info("updating...");
|
|
735
|
+
await runCommand("npx npm run do-install").promise;
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
async function installIfNotAvailable(deps, dependencies) {
|
|
739
|
+
deps = typeof deps === "string" ? [ deps ] : deps;
|
|
740
|
+
const current = {
|
|
741
|
+
prod: dependencies?.prod ? [ ...dependencies.prod ] : [],
|
|
742
|
+
dev: dependencies?.dev ? [ ...dependencies.dev ] : [],
|
|
743
|
+
peer: dependencies?.peer ? [ ...dependencies.peer ] : []
|
|
744
|
+
};
|
|
745
|
+
const known = new Set([ ...current.prod ?? [], ...current.dev ?? [], ...current.peer ?? [] ]);
|
|
746
|
+
const toInstall = [];
|
|
747
|
+
for (const dep of deps) {
|
|
748
|
+
if (known.has(dep)) continue;
|
|
749
|
+
try {
|
|
750
|
+
localRequire.resolve(dep);
|
|
751
|
+
known.add(dep);
|
|
752
|
+
} catch {
|
|
753
|
+
toInstall.push(dep);
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
if (toInstall.length) {
|
|
757
|
+
if (isTestEnvironment()) {
|
|
758
|
+
logger.verbose(`Skipping dependency install in test environment for: ${toInstall.join(", ")}`);
|
|
759
|
+
} else {
|
|
760
|
+
await installDependencies({
|
|
761
|
+
dev: toInstall
|
|
762
|
+
});
|
|
763
|
+
}
|
|
764
|
+
const devDeps = new Set(current.dev ?? []);
|
|
765
|
+
toInstall.forEach(dep => devDeps.add(dep));
|
|
766
|
+
current.dev = Array.from(devDeps);
|
|
767
|
+
}
|
|
768
|
+
return current;
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
async function pushToGit() {
|
|
772
|
+
const log = logger.for(pushToGit);
|
|
773
|
+
const gitUser = await runCommand("git config user.name").promise;
|
|
774
|
+
const gitEmail = await runCommand("git config user.email").promise;
|
|
775
|
+
log.verbose(`cached git id: ${gitUser}/${gitEmail}. changing to automation`);
|
|
776
|
+
await runCommand('git config user.email "automation@decaf.ts"').promise;
|
|
777
|
+
await runCommand('git config user.name "decaf"').promise;
|
|
778
|
+
log.info("Pushing changes to git...");
|
|
779
|
+
await runCommand("git add .").promise;
|
|
780
|
+
await runCommand(`git commit -m "refs #1 - after repo setup"`).promise;
|
|
781
|
+
await runCommand("git push").promise;
|
|
782
|
+
await runCommand(`git config user.email "${gitEmail}"`).promise;
|
|
783
|
+
await runCommand(`git config user.name "${gitUser}"`).promise;
|
|
784
|
+
log.verbose(`reverted to git id: ${gitUser}/${gitEmail}`);
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
async function installDependencies(dependencies) {
|
|
788
|
+
const log = logger.for(installDependencies);
|
|
789
|
+
const prod = dependencies.prod || [];
|
|
790
|
+
const dev = dependencies.dev || [];
|
|
791
|
+
const peer = dependencies.peer || [];
|
|
792
|
+
if (prod.length) {
|
|
793
|
+
log.info(`Installing dependencies ${prod.join(", ")}...`);
|
|
794
|
+
await runCommand(`npm install ${prod.join(" ")}`, {
|
|
795
|
+
cwd: process.cwd()
|
|
796
|
+
}).promise;
|
|
797
|
+
}
|
|
798
|
+
if (dev.length) {
|
|
799
|
+
log.info(`Installing devDependencies ${dev.join(", ")}...`);
|
|
800
|
+
await runCommand(`npm install --save-dev ${dev.join(" ")}`, {
|
|
801
|
+
cwd: process.cwd()
|
|
802
|
+
}).promise;
|
|
803
|
+
}
|
|
804
|
+
if (peer.length) {
|
|
805
|
+
log.info(`Installing peerDependencies ${peer.join(", ")}...`);
|
|
806
|
+
await runCommand(`npm install --save-peer ${peer.join(" ")}`, {
|
|
807
|
+
cwd: process.cwd()
|
|
808
|
+
}).promise;
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
async function normalizeImport(importPromise) {
|
|
813
|
+
return importPromise.then(m => m.default || m);
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
async function getFileSizeZipped(dir) {
|
|
817
|
+
const log = logger.for(getFileSizeZipped);
|
|
818
|
+
try {
|
|
819
|
+
const entries = fs.readdirSync(dir);
|
|
820
|
+
const candidates = entries.map(e => path.join(dir, e)).filter(p => {
|
|
821
|
+
try {
|
|
822
|
+
const s = fs.statSync(p);
|
|
823
|
+
return s.isFile() && (p.endsWith(".js") || p.endsWith(".cjs") || p.endsWith(".mjs"));
|
|
824
|
+
} catch {
|
|
825
|
+
return false;
|
|
826
|
+
}
|
|
827
|
+
});
|
|
828
|
+
if (candidates.length === 0) {
|
|
829
|
+
throw new Error(`No JS files found in directory ${dir}`);
|
|
830
|
+
}
|
|
831
|
+
let smallest = candidates[0];
|
|
832
|
+
let smallestSize = fs.statSync(smallest).size;
|
|
833
|
+
for (const c of candidates.slice(1)) {
|
|
834
|
+
const s = fs.statSync(c).size;
|
|
835
|
+
if (s < smallestSize) {
|
|
836
|
+
smallest = c;
|
|
837
|
+
smallestSize = s;
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
log.verbose(`Selected smallest bundle: ${smallest} (${smallestSize} bytes)`);
|
|
841
|
+
const buffer = fs.readFileSync(smallest);
|
|
842
|
+
const gz = zlib.gzipSync(buffer);
|
|
843
|
+
const sizeKb = Number((gz.length / 1024).toFixed(1));
|
|
844
|
+
log.verbose(`Gzipped size: ${gz.length} bytes (${sizeKb} KB)`);
|
|
845
|
+
return sizeKb;
|
|
846
|
+
} catch (e) {
|
|
847
|
+
log.verbose(`Failed to compute gzipped size for ${dir}: ${e}`);
|
|
848
|
+
throw e;
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
function listFolder(basePath = process.cwd(), filter) {
|
|
853
|
+
const log = logger.for(listFolder);
|
|
854
|
+
try {
|
|
855
|
+
if (!fs.existsSync(basePath)) return [];
|
|
856
|
+
const entries = fs.readdirSync(basePath, {
|
|
857
|
+
withFileTypes: true
|
|
858
|
+
});
|
|
859
|
+
const names = entries.filter(d => filter ? filter(d.name, d) : true).map(d => d.name);
|
|
860
|
+
return names;
|
|
861
|
+
} catch (e) {
|
|
862
|
+
log.verbose(`Failed to list folder ${basePath}: ${e}`);
|
|
863
|
+
return [];
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
function listNodeModulesPackages(basePath = path.join(process.cwd(), "node_modules")) {
|
|
868
|
+
const log = logger.for(listNodeModulesPackages);
|
|
869
|
+
try {
|
|
870
|
+
if (!fs.existsSync(basePath)) return [];
|
|
871
|
+
const entries = fs.readdirSync(basePath, {
|
|
872
|
+
withFileTypes: true
|
|
873
|
+
});
|
|
874
|
+
const names = [];
|
|
875
|
+
for (const e of entries) {
|
|
876
|
+
try {
|
|
877
|
+
if (!e.isDirectory()) continue;
|
|
878
|
+
if (e.name.startsWith(".")) continue;
|
|
879
|
+
if (e.name.startsWith("@")) {
|
|
880
|
+
const scopePath = path.join(basePath, e.name);
|
|
881
|
+
try {
|
|
882
|
+
const scoped = fs.readdirSync(scopePath, {
|
|
883
|
+
withFileTypes: true
|
|
884
|
+
});
|
|
885
|
+
for (const s of scoped) {
|
|
886
|
+
if (s.isDirectory() && !s.name.startsWith(".")) {
|
|
887
|
+
names.push(`${e.name}/${s.name}`);
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
} catch (err) {
|
|
891
|
+
log.verbose(`Failed to read scope ${scopePath}: ${err}`);
|
|
892
|
+
}
|
|
893
|
+
} else {
|
|
894
|
+
names.push(e.name);
|
|
895
|
+
}
|
|
896
|
+
} catch (err) {
|
|
897
|
+
log.verbose(`Skipping entry ${e.name} due to error: ${err}`);
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
return names;
|
|
901
|
+
} catch (e) {
|
|
902
|
+
log.verbose(`Failed to list node_modules packages at ${basePath}: ${e}`);
|
|
903
|
+
return [];
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
const slogans = [ {
|
|
908
|
+
Slogan: "No caffeine, no chaos. Just clean code.",
|
|
909
|
+
Tags: "Coffee-themed, Calm, Tech"
|
|
910
|
+
}, {
|
|
911
|
+
Slogan: "Full flavor, no jitters. That's Decaf-TS.",
|
|
912
|
+
Tags: "Coffee-themed, Cheerful"
|
|
913
|
+
}, {
|
|
914
|
+
Slogan: "Chill fullstack. Powered by Decaf.",
|
|
915
|
+
Tags: "Coffee-themed, Fun, Tech"
|
|
916
|
+
}, {
|
|
917
|
+
Slogan: "Decaf-TS: Brewed for calm code.",
|
|
918
|
+
Tags: "Coffee-themed, Branding"
|
|
919
|
+
}, {
|
|
920
|
+
Slogan: "Smooth as your morning Decaf.",
|
|
921
|
+
Tags: "Coffee-themed, Chill"
|
|
922
|
+
}, {
|
|
923
|
+
Slogan: "All the kick, none of the crash.",
|
|
924
|
+
Tags: "Coffee-themed, Energetic"
|
|
925
|
+
}, {
|
|
926
|
+
Slogan: "Sip back and ship faster.",
|
|
927
|
+
Tags: "Coffee-themed, Fun"
|
|
928
|
+
}, {
|
|
929
|
+
Slogan: "Keep calm and code Decaf.",
|
|
930
|
+
Tags: "Coffee-themed, Playful"
|
|
931
|
+
}, {
|
|
932
|
+
Slogan: "Code without the caffeine shakes.",
|
|
933
|
+
Tags: "Coffee-themed, Humorous"
|
|
934
|
+
}, {
|
|
935
|
+
Slogan: "Your fullstack, decaffeinated.",
|
|
936
|
+
Tags: "Coffee-themed, Technical"
|
|
937
|
+
}, {
|
|
938
|
+
Slogan: "No caffeine, no chaos. Just clean code.",
|
|
939
|
+
Tags: "Coffee-themed, Calm, Tech"
|
|
940
|
+
}, {
|
|
941
|
+
Slogan: "Full flavor, no jitters. That’s Decaf-TS.",
|
|
942
|
+
Tags: "Coffee-themed, Cheerful"
|
|
943
|
+
}, {
|
|
944
|
+
Slogan: "Chill fullstack. Powered by Decaf.",
|
|
945
|
+
Tags: "Coffee-themed, Fun, Tech"
|
|
946
|
+
}, {
|
|
947
|
+
Slogan: "Decaf-TS: Brewed for calm code.",
|
|
948
|
+
Tags: "Coffee-themed, Branding"
|
|
949
|
+
}, {
|
|
950
|
+
Slogan: "Smooth as your morning Decaf.",
|
|
951
|
+
Tags: "Coffee-themed, Chill"
|
|
952
|
+
}, {
|
|
953
|
+
Slogan: "All the kick, none of the crash.",
|
|
954
|
+
Tags: "Coffee-themed, Energetic"
|
|
955
|
+
}, {
|
|
956
|
+
Slogan: "Sip back and ship faster.",
|
|
957
|
+
Tags: "Coffee-themed, Fun"
|
|
958
|
+
}, {
|
|
959
|
+
Slogan: "Keep calm and code Decaf.",
|
|
960
|
+
Tags: "Coffee-themed, Playful"
|
|
961
|
+
}, {
|
|
962
|
+
Slogan: "Code without the caffeine shakes.",
|
|
963
|
+
Tags: "Coffee-themed, Humorous"
|
|
964
|
+
}, {
|
|
965
|
+
Slogan: "Your fullstack, decaffeinated.",
|
|
966
|
+
Tags: "Coffee-themed, Technical"
|
|
967
|
+
}, {
|
|
968
|
+
Slogan: "No caffeine, no chaos. Just clean code.",
|
|
969
|
+
Tags: "Coffee-themed, Calm, Tech"
|
|
970
|
+
}, {
|
|
971
|
+
Slogan: "Full flavor, no jitters. That’s Decaf-TS.",
|
|
972
|
+
Tags: "Coffee-themed, Cheerful"
|
|
973
|
+
}, {
|
|
974
|
+
Slogan: "Chill fullstack. Powered by Decaf.",
|
|
975
|
+
Tags: "Coffee-themed, Fun, Tech"
|
|
976
|
+
}, {
|
|
977
|
+
Slogan: "Decaf-TS: Brewed for calm code.",
|
|
978
|
+
Tags: "Coffee-themed, Branding"
|
|
979
|
+
}, {
|
|
980
|
+
Slogan: "Smooth as your morning Decaf.",
|
|
981
|
+
Tags: "Coffee-themed, Chill"
|
|
982
|
+
}, {
|
|
983
|
+
Slogan: "All the kick, none of the crash.",
|
|
984
|
+
Tags: "Coffee-themed, Energetic"
|
|
985
|
+
}, {
|
|
986
|
+
Slogan: "Sip back and ship faster.",
|
|
987
|
+
Tags: "Coffee-themed, Fun"
|
|
988
|
+
}, {
|
|
989
|
+
Slogan: "Keep calm and code Decaf.",
|
|
990
|
+
Tags: "Coffee-themed, Playful"
|
|
991
|
+
}, {
|
|
992
|
+
Slogan: "Code without the caffeine shakes.",
|
|
993
|
+
Tags: "Coffee-themed, Humorous"
|
|
994
|
+
}, {
|
|
995
|
+
Slogan: "Your fullstack, decaffeinated.",
|
|
996
|
+
Tags: "Coffee-themed, Technical"
|
|
997
|
+
}, {
|
|
998
|
+
Slogan: "No caffeine, no chaos. Just clean code.",
|
|
999
|
+
Tags: "Coffee-themed, Calm, Tech"
|
|
1000
|
+
}, {
|
|
1001
|
+
Slogan: "Full flavor, no jitters. That’s Decaf-TS.",
|
|
1002
|
+
Tags: "Coffee-themed, Cheerful"
|
|
1003
|
+
}, {
|
|
1004
|
+
Slogan: "Chill fullstack. Powered by Decaf.",
|
|
1005
|
+
Tags: "Coffee-themed, Fun, Tech"
|
|
1006
|
+
}, {
|
|
1007
|
+
Slogan: "Decaf-TS: Brewed for calm code.",
|
|
1008
|
+
Tags: "Coffee-themed, Branding"
|
|
1009
|
+
}, {
|
|
1010
|
+
Slogan: "Smooth as your morning Decaf.",
|
|
1011
|
+
Tags: "Coffee-themed, Chill"
|
|
1012
|
+
}, {
|
|
1013
|
+
Slogan: "All the kick, none of the crash.",
|
|
1014
|
+
Tags: "Coffee-themed, Energetic"
|
|
1015
|
+
}, {
|
|
1016
|
+
Slogan: "Sip back and ship faster.",
|
|
1017
|
+
Tags: "Coffee-themed, Fun"
|
|
1018
|
+
}, {
|
|
1019
|
+
Slogan: "Keep calm and code Decaf.",
|
|
1020
|
+
Tags: "Coffee-themed, Playful"
|
|
1021
|
+
}, {
|
|
1022
|
+
Slogan: "Code without the caffeine shakes.",
|
|
1023
|
+
Tags: "Coffee-themed, Humorous"
|
|
1024
|
+
}, {
|
|
1025
|
+
Slogan: "Your fullstack, decaffeinated.",
|
|
1026
|
+
Tags: "Coffee-themed, Technical"
|
|
1027
|
+
}, {
|
|
1028
|
+
Slogan: "No caffeine, no chaos. Just clean code.",
|
|
1029
|
+
Tags: "Coffee-themed, Calm, Tech"
|
|
1030
|
+
}, {
|
|
1031
|
+
Slogan: "Full flavor, no jitters. That’s Decaf-TS.",
|
|
1032
|
+
Tags: "Coffee-themed, Cheerful"
|
|
1033
|
+
}, {
|
|
1034
|
+
Slogan: "Chill fullstack. Powered by Decaf.",
|
|
1035
|
+
Tags: "Coffee-themed, Fun, Tech"
|
|
1036
|
+
}, {
|
|
1037
|
+
Slogan: "Decaf-TS: Brewed for calm code.",
|
|
1038
|
+
Tags: "Coffee-themed, Branding"
|
|
1039
|
+
}, {
|
|
1040
|
+
Slogan: "Smooth as your morning Decaf.",
|
|
1041
|
+
Tags: "Coffee-themed, Chill"
|
|
1042
|
+
}, {
|
|
1043
|
+
Slogan: "All the kick, none of the crash.",
|
|
1044
|
+
Tags: "Coffee-themed, Energetic"
|
|
1045
|
+
}, {
|
|
1046
|
+
Slogan: "Sip back and ship faster.",
|
|
1047
|
+
Tags: "Coffee-themed, Fun"
|
|
1048
|
+
}, {
|
|
1049
|
+
Slogan: "Keep calm and code Decaf.",
|
|
1050
|
+
Tags: "Coffee-themed, Playful"
|
|
1051
|
+
}, {
|
|
1052
|
+
Slogan: "Code without the caffeine shakes.",
|
|
1053
|
+
Tags: "Coffee-themed, Humorous"
|
|
1054
|
+
}, {
|
|
1055
|
+
Slogan: "Your fullstack, decaffeinated.",
|
|
1056
|
+
Tags: "Coffee-themed, Technical"
|
|
1057
|
+
}, {
|
|
1058
|
+
Slogan: "No caffeine, no chaos. Just clean code.",
|
|
1059
|
+
Tags: "Coffee-themed, Calm, Tech"
|
|
1060
|
+
}, {
|
|
1061
|
+
Slogan: "Full flavor, no jitters. That’s Decaf-TS.",
|
|
1062
|
+
Tags: "Coffee-themed, Cheerful"
|
|
1063
|
+
}, {
|
|
1064
|
+
Slogan: "Chill fullstack. Powered by Decaf.",
|
|
1065
|
+
Tags: "Coffee-themed, Fun, Tech"
|
|
1066
|
+
}, {
|
|
1067
|
+
Slogan: "Decaf-TS: Brewed for calm code.",
|
|
1068
|
+
Tags: "Coffee-themed, Branding"
|
|
1069
|
+
}, {
|
|
1070
|
+
Slogan: "Smooth as your morning Decaf.",
|
|
1071
|
+
Tags: "Coffee-themed, Chill"
|
|
1072
|
+
}, {
|
|
1073
|
+
Slogan: "All the kick, none of the crash.",
|
|
1074
|
+
Tags: "Coffee-themed, Energetic"
|
|
1075
|
+
}, {
|
|
1076
|
+
Slogan: "Sip back and ship faster.",
|
|
1077
|
+
Tags: "Coffee-themed, Fun"
|
|
1078
|
+
}, {
|
|
1079
|
+
Slogan: "Keep calm and code Decaf.",
|
|
1080
|
+
Tags: "Coffee-themed, Playful"
|
|
1081
|
+
}, {
|
|
1082
|
+
Slogan: "Code without the caffeine shakes.",
|
|
1083
|
+
Tags: "Coffee-themed, Humorous"
|
|
1084
|
+
}, {
|
|
1085
|
+
Slogan: "Your fullstack, decaffeinated.",
|
|
1086
|
+
Tags: "Coffee-themed, Technical"
|
|
1087
|
+
}, {
|
|
1088
|
+
Slogan: "No caffeine, no chaos. Just clean code.",
|
|
1089
|
+
Tags: "Coffee-themed, Calm, Tech"
|
|
1090
|
+
}, {
|
|
1091
|
+
Slogan: "Full flavor, no jitters. That’s Decaf-TS.",
|
|
1092
|
+
Tags: "Coffee-themed, Cheerful"
|
|
1093
|
+
}, {
|
|
1094
|
+
Slogan: "Chill fullstack. Powered by Decaf.",
|
|
1095
|
+
Tags: "Coffee-themed, Fun, Tech"
|
|
1096
|
+
}, {
|
|
1097
|
+
Slogan: "Decaf-TS: Brewed for calm code.",
|
|
1098
|
+
Tags: "Coffee-themed, Branding"
|
|
1099
|
+
}, {
|
|
1100
|
+
Slogan: "Smooth as your morning Decaf.",
|
|
1101
|
+
Tags: "Coffee-themed, Chill"
|
|
1102
|
+
}, {
|
|
1103
|
+
Slogan: "All the kick, none of the crash.",
|
|
1104
|
+
Tags: "Coffee-themed, Energetic"
|
|
1105
|
+
}, {
|
|
1106
|
+
Slogan: "Sip back and ship faster.",
|
|
1107
|
+
Tags: "Coffee-themed, Fun"
|
|
1108
|
+
}, {
|
|
1109
|
+
Slogan: "Keep calm and code Decaf.",
|
|
1110
|
+
Tags: "Coffee-themed, Playful"
|
|
1111
|
+
}, {
|
|
1112
|
+
Slogan: "Code without the caffeine shakes.",
|
|
1113
|
+
Tags: "Coffee-themed, Humorous"
|
|
1114
|
+
}, {
|
|
1115
|
+
Slogan: "Your fullstack, decaffeinated.",
|
|
1116
|
+
Tags: "Coffee-themed, Technical"
|
|
1117
|
+
}, {
|
|
1118
|
+
Slogan: "No caffeine, no chaos. Just clean code.",
|
|
1119
|
+
Tags: "Coffee-themed, Calm, Tech"
|
|
1120
|
+
}, {
|
|
1121
|
+
Slogan: "Full flavor, no jitters. That’s Decaf-TS.",
|
|
1122
|
+
Tags: "Coffee-themed, Cheerful"
|
|
1123
|
+
}, {
|
|
1124
|
+
Slogan: "Chill fullstack. Powered by Decaf.",
|
|
1125
|
+
Tags: "Coffee-themed, Fun, Tech"
|
|
1126
|
+
}, {
|
|
1127
|
+
Slogan: "Decaf-TS: Brewed for calm code.",
|
|
1128
|
+
Tags: "Coffee-themed, Branding"
|
|
1129
|
+
}, {
|
|
1130
|
+
Slogan: "Smooth as your morning Decaf.",
|
|
1131
|
+
Tags: "Coffee-themed, Chill"
|
|
1132
|
+
}, {
|
|
1133
|
+
Slogan: "All the kick, none of the crash.",
|
|
1134
|
+
Tags: "Coffee-themed, Energetic"
|
|
1135
|
+
}, {
|
|
1136
|
+
Slogan: "Sip back and ship faster.",
|
|
1137
|
+
Tags: "Coffee-themed, Fun"
|
|
1138
|
+
}, {
|
|
1139
|
+
Slogan: "Keep calm and code Decaf.",
|
|
1140
|
+
Tags: "Coffee-themed, Playful"
|
|
1141
|
+
}, {
|
|
1142
|
+
Slogan: "Code without the caffeine shakes.",
|
|
1143
|
+
Tags: "Coffee-themed, Humorous"
|
|
1144
|
+
}, {
|
|
1145
|
+
Slogan: "Your fullstack, decaffeinated.",
|
|
1146
|
+
Tags: "Coffee-themed, Technical"
|
|
1147
|
+
}, {
|
|
1148
|
+
Slogan: "No caffeine, no chaos. Just clean code.",
|
|
1149
|
+
Tags: "Coffee-themed, Calm, Tech"
|
|
1150
|
+
}, {
|
|
1151
|
+
Slogan: "Full flavor, no jitters. That’s Decaf-TS.",
|
|
1152
|
+
Tags: "Coffee-themed, Cheerful"
|
|
1153
|
+
}, {
|
|
1154
|
+
Slogan: "Chill fullstack. Powered by Decaf.",
|
|
1155
|
+
Tags: "Coffee-themed, Fun, Tech"
|
|
1156
|
+
}, {
|
|
1157
|
+
Slogan: "Decaf-TS: Brewed for calm code.",
|
|
1158
|
+
Tags: "Coffee-themed, Branding"
|
|
1159
|
+
}, {
|
|
1160
|
+
Slogan: "Smooth as your morning Decaf.",
|
|
1161
|
+
Tags: "Coffee-themed, Chill"
|
|
1162
|
+
}, {
|
|
1163
|
+
Slogan: "All the kick, none of the crash.",
|
|
1164
|
+
Tags: "Coffee-themed, Energetic"
|
|
1165
|
+
}, {
|
|
1166
|
+
Slogan: "Sip back and ship faster.",
|
|
1167
|
+
Tags: "Coffee-themed, Fun"
|
|
1168
|
+
}, {
|
|
1169
|
+
Slogan: "Keep calm and code Decaf.",
|
|
1170
|
+
Tags: "Coffee-themed, Playful"
|
|
1171
|
+
}, {
|
|
1172
|
+
Slogan: "Code without the caffeine shakes.",
|
|
1173
|
+
Tags: "Coffee-themed, Humorous"
|
|
1174
|
+
}, {
|
|
1175
|
+
Slogan: "Your fullstack, decaffeinated.",
|
|
1176
|
+
Tags: "Coffee-themed, Technical"
|
|
1177
|
+
}, {
|
|
1178
|
+
Slogan: "No caffeine, no chaos. Just clean code.",
|
|
1179
|
+
Tags: "Coffee-themed, Calm, Tech"
|
|
1180
|
+
}, {
|
|
1181
|
+
Slogan: "Full flavor, no jitters. That’s Decaf-TS.",
|
|
1182
|
+
Tags: "Coffee-themed, Cheerful"
|
|
1183
|
+
}, {
|
|
1184
|
+
Slogan: "Chill fullstack. Powered by Decaf.",
|
|
1185
|
+
Tags: "Coffee-themed, Fun, Tech"
|
|
1186
|
+
}, {
|
|
1187
|
+
Slogan: "Decaf-TS: Brewed for calm code.",
|
|
1188
|
+
Tags: "Coffee-themed, Branding"
|
|
1189
|
+
}, {
|
|
1190
|
+
Slogan: "Smooth as your morning Decaf.",
|
|
1191
|
+
Tags: "Coffee-themed, Chill"
|
|
1192
|
+
}, {
|
|
1193
|
+
Slogan: "All the kick, none of the crash.",
|
|
1194
|
+
Tags: "Coffee-themed, Energetic"
|
|
1195
|
+
}, {
|
|
1196
|
+
Slogan: "Sip back and ship faster.",
|
|
1197
|
+
Tags: "Coffee-themed, Fun"
|
|
1198
|
+
}, {
|
|
1199
|
+
Slogan: "Keep calm and code Decaf.",
|
|
1200
|
+
Tags: "Coffee-themed, Playful"
|
|
1201
|
+
}, {
|
|
1202
|
+
Slogan: "Code without the caffeine shakes.",
|
|
1203
|
+
Tags: "Coffee-themed, Humorous"
|
|
1204
|
+
}, {
|
|
1205
|
+
Slogan: "Your fullstack, decaffeinated.",
|
|
1206
|
+
Tags: "Coffee-themed, Technical"
|
|
1207
|
+
}, {
|
|
1208
|
+
Slogan: "Decaf-TS: Where smart contracts meet smart interfaces.",
|
|
1209
|
+
Tags: "Blockchain, Smart Contracts, Tech"
|
|
1210
|
+
}, {
|
|
1211
|
+
Slogan: "Ship dApps without the stress.",
|
|
1212
|
+
Tags: "Blockchain, Cheerful, Developer"
|
|
1213
|
+
}, {
|
|
1214
|
+
Slogan: "No CRUD, no problem — Decaf your data.",
|
|
1215
|
+
Tags: "Data, No-CRUD, Chill"
|
|
1216
|
+
}, {
|
|
1217
|
+
Slogan: "From DID to UI, without breaking a sweat.",
|
|
1218
|
+
Tags: "DID, SSI, UI, Calm"
|
|
1219
|
+
}, {
|
|
1220
|
+
Slogan: "Decaf-TS: Your frontend already understands your smart contract.",
|
|
1221
|
+
Tags: "Smart Contracts, DX, Magic"
|
|
1222
|
+
}, {
|
|
1223
|
+
Slogan: "Self-sovereign by design. Productive by default.",
|
|
1224
|
+
Tags: "SSI, Developer, Calm"
|
|
1225
|
+
}, {
|
|
1226
|
+
Slogan: "Build once. Deploy everywhere. Decentralized and delightful.",
|
|
1227
|
+
Tags: "Blockchain, Multi-platform, Happy"
|
|
1228
|
+
}, {
|
|
1229
|
+
Slogan: "Data that defines its own destiny.",
|
|
1230
|
+
Tags: "SSI, Data-driven, Empowerment"
|
|
1231
|
+
}, {
|
|
1232
|
+
Slogan: "Goodbye CRUD, hello intent-based interfaces.",
|
|
1233
|
+
Tags: "No-CRUD, UI, Technical"
|
|
1234
|
+
}, {
|
|
1235
|
+
Slogan: "The smoothest path from DID to done.",
|
|
1236
|
+
Tags: "DID, Workflow, Chill"
|
|
1237
|
+
}, {
|
|
1238
|
+
Slogan: "Because your dApp deserves more than boilerplate.",
|
|
1239
|
+
Tags: "Blockchain, DevX, Efficiency"
|
|
1240
|
+
}, {
|
|
1241
|
+
Slogan: "Own your data. Own your flow.",
|
|
1242
|
+
Tags: "SSI, Control, Ownership"
|
|
1243
|
+
}, {
|
|
1244
|
+
Slogan: "Write logic like it belongs with the data — because it does.",
|
|
1245
|
+
Tags: "Data Logic, Developer, Smart"
|
|
1246
|
+
}, {
|
|
1247
|
+
Slogan: "From smart contracts to smarter frontends.",
|
|
1248
|
+
Tags: "Smart Contracts, UI, DX"
|
|
1249
|
+
}, {
|
|
1250
|
+
Slogan: "No caffeine. No CRUD. Just the future.",
|
|
1251
|
+
Tags: "No-CRUD, Coffee-themed, Futuristic"
|
|
1252
|
+
}, {
|
|
1253
|
+
Slogan: "The future of web3 UX is Decaf.",
|
|
1254
|
+
Tags: "Blockchain, UX, Vision"
|
|
1255
|
+
}, {
|
|
1256
|
+
Slogan: "Code with confidence. Govern with clarity.",
|
|
1257
|
+
Tags: "Blockchain, Governance, Calm"
|
|
1258
|
+
}, {
|
|
1259
|
+
Slogan: "Interfaces that obey the data, not the other way around.",
|
|
1260
|
+
Tags: "UI, Data Logic, Self-aware"
|
|
1261
|
+
}, {
|
|
1262
|
+
Slogan: "Brew business logic right into your bytes.",
|
|
1263
|
+
Tags: "Data Logic, Coffee-themed, Fun"
|
|
1264
|
+
}, {
|
|
1265
|
+
Slogan: "DIDs done differently — and delightfully.",
|
|
1266
|
+
Tags: "DID, Self-Sovereign, Playful"
|
|
1267
|
+
}, {
|
|
1268
|
+
Slogan: "Decaf-TS-TS: Where blockchain contracts meet smart interfaces.",
|
|
1269
|
+
Tags: "Blockchain, Smart Contracts, Tech"
|
|
1270
|
+
}, {
|
|
1271
|
+
Slogan: "Ship dApps without the stress.",
|
|
1272
|
+
Tags: "Blockchain, Cheerful, Developer"
|
|
1273
|
+
}, {
|
|
1274
|
+
Slogan: "No boilerplate, no problem — Decaf-TS your data.",
|
|
1275
|
+
Tags: "Data, No-CRUD, Chill"
|
|
1276
|
+
}, {
|
|
1277
|
+
Slogan: "From DID to UI, without breaking a sweat.",
|
|
1278
|
+
Tags: "DID, SSI, UI, Calm"
|
|
1279
|
+
}, {
|
|
1280
|
+
Slogan: "Decaf-TS-TS: Your frontend already understands your blockchain contract.",
|
|
1281
|
+
Tags: "Smart Contracts, DX, Magic"
|
|
1282
|
+
}, {
|
|
1283
|
+
Slogan: "Self-sovereign by design. Productive by default.",
|
|
1284
|
+
Tags: "SSI, Developer, Calm"
|
|
1285
|
+
}, {
|
|
1286
|
+
Slogan: "Build once. Deploy everywhere. Decentralized and delightful.",
|
|
1287
|
+
Tags: "Blockchain, Multi-platform, Happy"
|
|
1288
|
+
}, {
|
|
1289
|
+
Slogan: "Data that defines its own destiny.",
|
|
1290
|
+
Tags: "SSI, Data-driven, Empowerment"
|
|
1291
|
+
}, {
|
|
1292
|
+
Slogan: "Goodbye boilerplate, hello intent-based interfaces.",
|
|
1293
|
+
Tags: "No-CRUD, UI, Technical"
|
|
1294
|
+
}, {
|
|
1295
|
+
Slogan: "The smoothest path from DID to done.",
|
|
1296
|
+
Tags: "DID, Workflow, Chill"
|
|
1297
|
+
}, {
|
|
1298
|
+
Slogan: "Because your dApp deserves more than boilerplate.",
|
|
1299
|
+
Tags: "Blockchain, DevX, Efficiency"
|
|
1300
|
+
}, {
|
|
1301
|
+
Slogan: "Own your data. Own your flow.",
|
|
1302
|
+
Tags: "SSI, Control, Ownership"
|
|
1303
|
+
}, {
|
|
1304
|
+
Slogan: "Write logic like it belongs with the data — because it does.",
|
|
1305
|
+
Tags: "Data Logic, Developer, Smart"
|
|
1306
|
+
}, {
|
|
1307
|
+
Slogan: "From blockchain contracts to smarter frontends.",
|
|
1308
|
+
Tags: "Smart Contracts, UI, DX"
|
|
1309
|
+
}, {
|
|
1310
|
+
Slogan: "No caffeine. No boilerplate. Just the future.",
|
|
1311
|
+
Tags: "No-CRUD, Coffee-themed, Futuristic"
|
|
1312
|
+
}, {
|
|
1313
|
+
Slogan: "The future of web3 UX is Decaf-TS.",
|
|
1314
|
+
Tags: "Blockchain, UX, Vision"
|
|
1315
|
+
}, {
|
|
1316
|
+
Slogan: "Code with confidence. Govern with clarity.",
|
|
1317
|
+
Tags: "Blockchain, Governance, Calm"
|
|
1318
|
+
}, {
|
|
1319
|
+
Slogan: "Interfaces that obey the data, not the other way around.",
|
|
1320
|
+
Tags: "UI, Data Logic, Self-aware"
|
|
1321
|
+
}, {
|
|
1322
|
+
Slogan: "Brew business logic right into your bytes.",
|
|
1323
|
+
Tags: "Data Logic, Coffee-themed, Fun"
|
|
1324
|
+
}, {
|
|
1325
|
+
Slogan: "DIDs done differently — and delightfully.",
|
|
1326
|
+
Tags: "DID, Self-Sovereign, Playful"
|
|
1327
|
+
}, {
|
|
1328
|
+
Slogan: "Decaf-TS-TS: Where blockchain contracts meet smart interfaces.",
|
|
1329
|
+
Tags: "Blockchain, Smart Contracts, Tech"
|
|
1330
|
+
}, {
|
|
1331
|
+
Slogan: "Ship dApps without the stress.",
|
|
1332
|
+
Tags: "Blockchain, Cheerful, Developer"
|
|
1333
|
+
}, {
|
|
1334
|
+
Slogan: "No boilerplate, no problem — Decaf-TS your data.",
|
|
1335
|
+
Tags: "Data, No-CRUD, Chill"
|
|
1336
|
+
}, {
|
|
1337
|
+
Slogan: "From DID to UI, without breaking a sweat.",
|
|
1338
|
+
Tags: "DID, SSI, UI, Calm"
|
|
1339
|
+
}, {
|
|
1340
|
+
Slogan: "Decaf-TS-TS: Your frontend already understands your blockchain contract.",
|
|
1341
|
+
Tags: "Smart Contracts, DX, Magic"
|
|
1342
|
+
}, {
|
|
1343
|
+
Slogan: "Self-sovereign by design. Productive by default.",
|
|
1344
|
+
Tags: "SSI, Developer, Calm"
|
|
1345
|
+
}, {
|
|
1346
|
+
Slogan: "Build once. Deploy everywhere. Decentralized and delightful.",
|
|
1347
|
+
Tags: "Blockchain, Multi-platform, Happy"
|
|
1348
|
+
}, {
|
|
1349
|
+
Slogan: "Data that defines its own destiny.",
|
|
1350
|
+
Tags: "SSI, Data-driven, Empowerment"
|
|
1351
|
+
}, {
|
|
1352
|
+
Slogan: "Goodbye boilerplate, hello intent-based interfaces.",
|
|
1353
|
+
Tags: "No-CRUD, UI, Technical"
|
|
1354
|
+
}, {
|
|
1355
|
+
Slogan: "The smoothest path from DID to done.",
|
|
1356
|
+
Tags: "DID, Workflow, Chill"
|
|
1357
|
+
}, {
|
|
1358
|
+
Slogan: "Because your dApp deserves more than boilerplate.",
|
|
1359
|
+
Tags: "Blockchain, DevX, Efficiency"
|
|
1360
|
+
}, {
|
|
1361
|
+
Slogan: "Own your data. Own your flow.",
|
|
1362
|
+
Tags: "SSI, Control, Ownership"
|
|
1363
|
+
}, {
|
|
1364
|
+
Slogan: "Write logic like it belongs with the data — because it does.",
|
|
1365
|
+
Tags: "Data Logic, Developer, Smart"
|
|
1366
|
+
}, {
|
|
1367
|
+
Slogan: "From blockchain contracts to smarter frontends.",
|
|
1368
|
+
Tags: "Smart Contracts, UI, DX"
|
|
1369
|
+
}, {
|
|
1370
|
+
Slogan: "No caffeine. No boilerplate. Just the future.",
|
|
1371
|
+
Tags: "No-CRUD, Coffee-themed, Futuristic"
|
|
1372
|
+
}, {
|
|
1373
|
+
Slogan: "The future of web3 UX is Decaf-TS.",
|
|
1374
|
+
Tags: "Blockchain, UX, Vision"
|
|
1375
|
+
}, {
|
|
1376
|
+
Slogan: "Code with confidence. Govern with clarity.",
|
|
1377
|
+
Tags: "Blockchain, Governance, Calm"
|
|
1378
|
+
}, {
|
|
1379
|
+
Slogan: "Interfaces that obey the data, not the other way around.",
|
|
1380
|
+
Tags: "UI, Data Logic, Self-aware"
|
|
1381
|
+
}, {
|
|
1382
|
+
Slogan: "Brew business logic right into your bytes.",
|
|
1383
|
+
Tags: "Data Logic, Coffee-themed, Fun"
|
|
1384
|
+
}, {
|
|
1385
|
+
Slogan: "DIDs done differently — and delightfully.",
|
|
1386
|
+
Tags: "DID, Self-Sovereign, Playful"
|
|
1387
|
+
}, {
|
|
1388
|
+
Slogan: "Decaf-TS-TS: Where blockchain contracts meet smart interfaces.",
|
|
1389
|
+
Tags: "Blockchain, Smart Contracts, Tech"
|
|
1390
|
+
}, {
|
|
1391
|
+
Slogan: "Ship dApps without the stress.",
|
|
1392
|
+
Tags: "Blockchain, Cheerful, Developer"
|
|
1393
|
+
}, {
|
|
1394
|
+
Slogan: "No boilerplate, no problem — Decaf-TS your data.",
|
|
1395
|
+
Tags: "Data, No-CRUD, Chill"
|
|
1396
|
+
}, {
|
|
1397
|
+
Slogan: "From DID to UI, without breaking a sweat.",
|
|
1398
|
+
Tags: "DID, SSI, UI, Calm"
|
|
1399
|
+
}, {
|
|
1400
|
+
Slogan: "Decaf-TS-TS: Your frontend already understands your blockchain contract.",
|
|
1401
|
+
Tags: "Smart Contracts, DX, Magic"
|
|
1402
|
+
}, {
|
|
1403
|
+
Slogan: "Self-sovereign by design. Productive by default.",
|
|
1404
|
+
Tags: "SSI, Developer, Calm"
|
|
1405
|
+
}, {
|
|
1406
|
+
Slogan: "Build once. Deploy everywhere. Decentralized and delightful.",
|
|
1407
|
+
Tags: "Blockchain, Multi-platform, Happy"
|
|
1408
|
+
}, {
|
|
1409
|
+
Slogan: "Data that defines its own destiny.",
|
|
1410
|
+
Tags: "SSI, Data-driven, Empowerment"
|
|
1411
|
+
}, {
|
|
1412
|
+
Slogan: "Goodbye boilerplate, hello intent-based interfaces.",
|
|
1413
|
+
Tags: "No-CRUD, UI, Technical"
|
|
1414
|
+
}, {
|
|
1415
|
+
Slogan: "The smoothest path from DID to done.",
|
|
1416
|
+
Tags: "DID, Workflow, Chill"
|
|
1417
|
+
}, {
|
|
1418
|
+
Slogan: "Because your dApp deserves more than boilerplate.",
|
|
1419
|
+
Tags: "Blockchain, DevX, Efficiency"
|
|
1420
|
+
}, {
|
|
1421
|
+
Slogan: "Own your data. Own your flow.",
|
|
1422
|
+
Tags: "SSI, Control, Ownership"
|
|
1423
|
+
}, {
|
|
1424
|
+
Slogan: "Write logic like it belongs with the data — because it does.",
|
|
1425
|
+
Tags: "Data Logic, Developer, Smart"
|
|
1426
|
+
}, {
|
|
1427
|
+
Slogan: "From blockchain contracts to smarter frontends.",
|
|
1428
|
+
Tags: "Smart Contracts, UI, DX"
|
|
1429
|
+
}, {
|
|
1430
|
+
Slogan: "No caffeine. No boilerplate. Just the future.",
|
|
1431
|
+
Tags: "No-CRUD, Coffee-themed, Futuristic"
|
|
1432
|
+
}, {
|
|
1433
|
+
Slogan: "The future of web3 UX is Decaf-TS.",
|
|
1434
|
+
Tags: "Blockchain, UX, Vision"
|
|
1435
|
+
}, {
|
|
1436
|
+
Slogan: "Code with confidence. Govern with clarity.",
|
|
1437
|
+
Tags: "Blockchain, Governance, Calm"
|
|
1438
|
+
}, {
|
|
1439
|
+
Slogan: "Interfaces that obey the data, not the other way around.",
|
|
1440
|
+
Tags: "UI, Data Logic, Self-aware"
|
|
1441
|
+
}, {
|
|
1442
|
+
Slogan: "Brew business logic right into your bytes.",
|
|
1443
|
+
Tags: "Data Logic, Coffee-themed, Fun"
|
|
1444
|
+
}, {
|
|
1445
|
+
Slogan: "DIDs done differently — and delightfully.",
|
|
1446
|
+
Tags: "DID, Self-Sovereign, Playful"
|
|
1447
|
+
}, {
|
|
1448
|
+
Slogan: "Decaf-TS-TS: Where blockchain contracts meet smart interfaces.",
|
|
1449
|
+
Tags: "Blockchain, Smart Contracts, Tech"
|
|
1450
|
+
}, {
|
|
1451
|
+
Slogan: "Ship dApps without the stress.",
|
|
1452
|
+
Tags: "Blockchain, Cheerful, Developer"
|
|
1453
|
+
}, {
|
|
1454
|
+
Slogan: "No boilerplate, no problem — Decaf-TS your data.",
|
|
1455
|
+
Tags: "Data, No-CRUD, Chill"
|
|
1456
|
+
}, {
|
|
1457
|
+
Slogan: "From DID to UI, without breaking a sweat.",
|
|
1458
|
+
Tags: "DID, SSI, UI, Calm"
|
|
1459
|
+
}, {
|
|
1460
|
+
Slogan: "Decaf-TS-TS: Your frontend already understands your blockchain contract.",
|
|
1461
|
+
Tags: "Smart Contracts, DX, Magic"
|
|
1462
|
+
}, {
|
|
1463
|
+
Slogan: "Self-sovereign by design. Productive by default.",
|
|
1464
|
+
Tags: "SSI, Developer, Calm"
|
|
1465
|
+
}, {
|
|
1466
|
+
Slogan: "Build once. Deploy everywhere. Decentralized and delightful.",
|
|
1467
|
+
Tags: "Blockchain, Multi-platform, Happy"
|
|
1468
|
+
}, {
|
|
1469
|
+
Slogan: "Data that defines its own destiny.",
|
|
1470
|
+
Tags: "SSI, Data-driven, Empowerment"
|
|
1471
|
+
}, {
|
|
1472
|
+
Slogan: "Goodbye boilerplate, hello intent-based interfaces.",
|
|
1473
|
+
Tags: "No-CRUD, UI, Technical"
|
|
1474
|
+
}, {
|
|
1475
|
+
Slogan: "The smoothest path from DID to done.",
|
|
1476
|
+
Tags: "DID, Workflow, Chill"
|
|
1477
|
+
}, {
|
|
1478
|
+
Slogan: "Because your dApp deserves more than boilerplate.",
|
|
1479
|
+
Tags: "Blockchain, DevX, Efficiency"
|
|
1480
|
+
}, {
|
|
1481
|
+
Slogan: "Own your data. Own your flow.",
|
|
1482
|
+
Tags: "SSI, Control, Ownership"
|
|
1483
|
+
}, {
|
|
1484
|
+
Slogan: "Write logic like it belongs with the data — because it does.",
|
|
1485
|
+
Tags: "Data Logic, Developer, Smart"
|
|
1486
|
+
}, {
|
|
1487
|
+
Slogan: "From blockchain contracts to smarter frontends.",
|
|
1488
|
+
Tags: "Smart Contracts, UI, DX"
|
|
1489
|
+
}, {
|
|
1490
|
+
Slogan: "No caffeine. No boilerplate. Just the future.",
|
|
1491
|
+
Tags: "No-CRUD, Coffee-themed, Futuristic"
|
|
1492
|
+
}, {
|
|
1493
|
+
Slogan: "The future of web3 UX is Decaf-TS.",
|
|
1494
|
+
Tags: "Blockchain, UX, Vision"
|
|
1495
|
+
}, {
|
|
1496
|
+
Slogan: "Code with confidence. Govern with clarity.",
|
|
1497
|
+
Tags: "Blockchain, Governance, Calm"
|
|
1498
|
+
}, {
|
|
1499
|
+
Slogan: "Interfaces that obey the data, not the other way around.",
|
|
1500
|
+
Tags: "UI, Data Logic, Self-aware"
|
|
1501
|
+
}, {
|
|
1502
|
+
Slogan: "Brew business logic right into your bytes.",
|
|
1503
|
+
Tags: "Data Logic, Coffee-themed, Fun"
|
|
1504
|
+
}, {
|
|
1505
|
+
Slogan: "DIDs done differently — and delightfully.",
|
|
1506
|
+
Tags: "DID, Self-Sovereign, Playful"
|
|
1507
|
+
} ];
|
|
1508
|
+
|
|
1509
|
+
const colors = [ "[38;5;215m", "[38;5;209m", "[38;5;205m", "[38;5;210m", "[38;5;217m", "[38;5;216m", "[38;5;224m", "[38;5;230m", "[38;5;230m" ];
|
|
1510
|
+
|
|
1511
|
+
function printBanner(logger) {
|
|
1512
|
+
const message = getSlogan();
|
|
1513
|
+
const banner = `# ░▒▓███████▓▒░ ░▒▓████████▓▒░ ░▒▓██████▓▒░ ░▒▓██████▓▒░ ░▒▓████████▓▒░ ░▒▓████████▓▒░ ░▒▓███████▓▒░ \n# ( ( ░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ \n# ) ) ░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ \n# [=======] ░▒▓█▓▒░░▒▓█▓▒░ ░▒▓██████▓▒░ ░▒▓█▓▒░ ░▒▓████████▓▒░ ░▒▓██████▓▒░ ░▒▓█▓▒░ ░▒▓██████▓▒░ \n# \`-----´ ░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ \n# ░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ \n# ░▒▓███████▓▒░ ░▒▓████████▓▒░ ░▒▓██████▓▒░ ░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓███████▓▒░ \n#`.split("\n");
|
|
1514
|
+
const maxLength = banner.reduce((max, line) => Math.max(max, line.length), 0);
|
|
1515
|
+
banner.push(`# ${message.padStart(maxLength - 3)}`);
|
|
1516
|
+
banner.forEach((line, index) => {
|
|
1517
|
+
(logger ? logger.info.bind(logger) : console.log.bind(console))(style(line || "").raw(colors[index]).text);
|
|
1518
|
+
});
|
|
1519
|
+
}
|
|
1520
|
+
|
|
1521
|
+
function getSlogan(i) {
|
|
1522
|
+
try {
|
|
1523
|
+
i = typeof i === "undefined" ? Math.floor(Math.random() * slogans.length) : i;
|
|
1524
|
+
return slogans[i].Slogan;
|
|
1525
|
+
} catch (error) {
|
|
1526
|
+
throw new Error(`Failed to retrieve slogans: ${error}`);
|
|
1527
|
+
}
|
|
1528
|
+
}
|
|
1529
|
+
|
|
1530
|
+
class Command extends LoggedClass {
|
|
1531
|
+
constructor(name, inputs = {}, requirements = []) {
|
|
1532
|
+
super();
|
|
1533
|
+
this.name = name;
|
|
1534
|
+
this.inputs = inputs;
|
|
1535
|
+
this.requirements = requirements;
|
|
1536
|
+
if (!Command.log) {
|
|
1537
|
+
Object.defineProperty(Command, "log", {
|
|
1538
|
+
writable: false,
|
|
1539
|
+
value: Logging.for(Command.name)
|
|
1540
|
+
});
|
|
1541
|
+
}
|
|
1542
|
+
this.inputs = Object.assign({}, DefaultCommandOptions, inputs);
|
|
1543
|
+
}
|
|
1544
|
+
async checkRequirements() {
|
|
1545
|
+
const {prod: prod, dev: dev, peer: peer} = await getDependencies();
|
|
1546
|
+
const missing = [];
|
|
1547
|
+
const fullList = Array.from(new Set([ ...prod, ...dev, ...peer ]).values()).map(d => d.name);
|
|
1548
|
+
for (const dep of this.requirements) if (!fullList.includes(dep)) missing.push(dep);
|
|
1549
|
+
if (!missing.length) return;
|
|
1550
|
+
}
|
|
1551
|
+
help(args) {
|
|
1552
|
+
return this.log.info(`This is help. I'm no use because I should have been overridden.`);
|
|
1553
|
+
}
|
|
1554
|
+
async execute() {
|
|
1555
|
+
const args = UserInput.parseArgs(this.inputs);
|
|
1556
|
+
const env = LoggedEnvironment.accumulate(DefaultCommandValues).accumulate(args.values);
|
|
1557
|
+
const {version: version, help: help, banner: banner} = env;
|
|
1558
|
+
if (version) {
|
|
1559
|
+
return getPackageVersion();
|
|
1560
|
+
}
|
|
1561
|
+
if (help) {
|
|
1562
|
+
return this.help(args);
|
|
1563
|
+
}
|
|
1564
|
+
if (banner) printBanner(this.log.for(printBanner, {
|
|
1565
|
+
timestamp: false,
|
|
1566
|
+
style: false,
|
|
1567
|
+
context: false,
|
|
1568
|
+
logLevel: false
|
|
1569
|
+
}));
|
|
1570
|
+
let result;
|
|
1571
|
+
try {
|
|
1572
|
+
result = await this.run(env);
|
|
1573
|
+
} catch (e) {
|
|
1574
|
+
throw e;
|
|
1575
|
+
}
|
|
1576
|
+
return result;
|
|
1577
|
+
}
|
|
1578
|
+
}
|
|
1579
|
+
|
|
1580
|
+
class HttpClient {
|
|
1581
|
+
static {
|
|
1582
|
+
this.log = Logging.for(HttpClient);
|
|
1583
|
+
}
|
|
1584
|
+
static async downloadFile(url) {
|
|
1585
|
+
return new Promise((resolve, reject) => {
|
|
1586
|
+
function request(url) {
|
|
1587
|
+
url = encodeURI(url);
|
|
1588
|
+
https.get(url, res => {
|
|
1589
|
+
if (res.statusCode === 301 || res.statusCode === 307) return request(res.headers.location);
|
|
1590
|
+
if (res.statusCode !== 200) {
|
|
1591
|
+
HttpClient.log.error(`Failed to fetch ${url} (status: ${res.statusCode})`);
|
|
1592
|
+
return reject(new Error(`Failed to fetch ${url}`));
|
|
1593
|
+
}
|
|
1594
|
+
let data = "";
|
|
1595
|
+
res.on("data", chunk => {
|
|
1596
|
+
data += chunk;
|
|
1597
|
+
});
|
|
1598
|
+
res.on("error", error => {
|
|
1599
|
+
reject(error);
|
|
1600
|
+
});
|
|
1601
|
+
res.on("end", () => {
|
|
1602
|
+
resolve(data);
|
|
1603
|
+
});
|
|
1604
|
+
});
|
|
1605
|
+
}
|
|
1606
|
+
request(url);
|
|
1607
|
+
});
|
|
1608
|
+
}
|
|
1609
|
+
}
|
|
1610
|
+
|
|
1611
|
+
const defaultCanvasOptions = {
|
|
1612
|
+
width: 1200,
|
|
1613
|
+
height: 260,
|
|
1614
|
+
padding: 32,
|
|
1615
|
+
backgroundColor: "#0f172a",
|
|
1616
|
+
headerFont: "bold 18px 'Segoe UI', sans-serif",
|
|
1617
|
+
rowFont: "14px 'Segoe UI', sans-serif",
|
|
1618
|
+
headerColor: "#f8fafc",
|
|
1619
|
+
rowColor: "#cbd5f5"
|
|
1620
|
+
};
|
|
1621
|
+
|
|
1622
|
+
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
|
|
1623
|
+
|
|
1624
|
+
const perfDebugEnabled = process.env.PERF_VERBOSE === "true";
|
|
1625
|
+
|
|
1626
|
+
const debugLog = (...args) => {
|
|
1627
|
+
if (perfDebugEnabled) {
|
|
1628
|
+
console.debug(...args);
|
|
1629
|
+
}
|
|
1630
|
+
};
|
|
1631
|
+
|
|
1632
|
+
const formatTable = (title, headers, rows) => {
|
|
1633
|
+
const columnWidths = headers.map((header, index) => Math.max(header.length, ...rows.map(row => row[index]?.length ?? 0)));
|
|
1634
|
+
const formatRow = values => "| " + values.map((value, index) => value.padEnd(columnWidths[index])).join(" | ") + " |";
|
|
1635
|
+
const headerLine = formatRow(headers);
|
|
1636
|
+
const divider = "| " + columnWidths.map(width => "-".repeat(width)).join(" | ") + " |";
|
|
1637
|
+
const body = rows.map(formatRow).join("\n");
|
|
1638
|
+
return `${title}\n${headerLine}\n${divider}\n${body}`;
|
|
1639
|
+
};
|
|
1640
|
+
|
|
1641
|
+
const ensureDirectory = async targetPath => {
|
|
1642
|
+
await mkdir(path.dirname(targetPath), {
|
|
1643
|
+
recursive: true
|
|
1644
|
+
});
|
|
1645
|
+
};
|
|
1646
|
+
|
|
1647
|
+
const renderMetricsTableToCanvas = async (headers, rows, options, outputPath) => {
|
|
1648
|
+
const config = {
|
|
1649
|
+
...defaultCanvasOptions,
|
|
1650
|
+
...options
|
|
1651
|
+
};
|
|
1652
|
+
let createCanvas;
|
|
1653
|
+
try {
|
|
1654
|
+
const canvasModule = await import("canvas");
|
|
1655
|
+
createCanvas = canvasModule.createCanvas;
|
|
1656
|
+
} catch (error) {
|
|
1657
|
+
console.warn("[PerfRunner] Canvas module not available, skipping chart.", error);
|
|
1658
|
+
return;
|
|
1659
|
+
}
|
|
1660
|
+
const canvas = createCanvas(config.width, config.height);
|
|
1661
|
+
const ctx = canvas.getContext("2d");
|
|
1662
|
+
ctx.fillStyle = config.backgroundColor;
|
|
1663
|
+
ctx.fillRect(0, 0, config.width, config.height);
|
|
1664
|
+
ctx.font = config.headerFont;
|
|
1665
|
+
ctx.fillStyle = config.headerColor;
|
|
1666
|
+
const columnWidth = (config.width - config.padding * 2) / headers.length;
|
|
1667
|
+
const headerY = config.padding + 24;
|
|
1668
|
+
headers.forEach((header, index) => {
|
|
1669
|
+
ctx.fillText(header, config.padding + columnWidth * index, headerY);
|
|
1670
|
+
});
|
|
1671
|
+
ctx.font = config.rowFont;
|
|
1672
|
+
ctx.fillStyle = config.rowColor;
|
|
1673
|
+
const rowHeight = 24;
|
|
1674
|
+
rows.forEach((row, rowIndex) => {
|
|
1675
|
+
const y = headerY + 12 + rowHeight * (rowIndex + 1);
|
|
1676
|
+
row.forEach((cell, cellIndex) => {
|
|
1677
|
+
ctx.fillText(cell, config.padding + columnWidth * cellIndex, y);
|
|
1678
|
+
});
|
|
1679
|
+
});
|
|
1680
|
+
await ensureDirectory(outputPath);
|
|
1681
|
+
await writeFile$1(outputPath, canvas.toBuffer("image/png"));
|
|
1682
|
+
console.log(`Stored performance chart at ${outputPath}`);
|
|
1683
|
+
};
|
|
1684
|
+
|
|
1685
|
+
class PerformanceRunner {
|
|
1686
|
+
constructor(scenario) {
|
|
1687
|
+
this.scenario = scenario;
|
|
1688
|
+
}
|
|
1689
|
+
async run() {
|
|
1690
|
+
if (this.scenario.initialize) {
|
|
1691
|
+
await this.scenario.initialize();
|
|
1692
|
+
}
|
|
1693
|
+
let phaseCounter = 0;
|
|
1694
|
+
const queue = this.scenario.phases.map(phase => ({
|
|
1695
|
+
phase: phase,
|
|
1696
|
+
phaseNumber: ++phaseCounter
|
|
1697
|
+
}));
|
|
1698
|
+
const results = [];
|
|
1699
|
+
while (queue.length) {
|
|
1700
|
+
const item = queue.shift();
|
|
1701
|
+
const phase = item.phase;
|
|
1702
|
+
const context = this.mergeContext(phase);
|
|
1703
|
+
console.info(`[PerfRunner] Starting phase #${item.phaseNumber} "${phase.name}"`, {
|
|
1704
|
+
iterations: phase.config.iterations,
|
|
1705
|
+
mode: phase.config.mode,
|
|
1706
|
+
concurrency: phase.config.concurrency,
|
|
1707
|
+
burst: phase.config.burst
|
|
1708
|
+
});
|
|
1709
|
+
const result = await this.runPhase(phase, context);
|
|
1710
|
+
console.info(`[PerfRunner] Completed phase #${item.phaseNumber} "${phase.name}"`, {
|
|
1711
|
+
total: result.aggregated.totalDurationMs.toFixed(2),
|
|
1712
|
+
avg: result.aggregated.averageMs.toFixed(2),
|
|
1713
|
+
failureCount: result.aggregated.failureCount
|
|
1714
|
+
});
|
|
1715
|
+
results.push(result);
|
|
1716
|
+
if (phase.generator) {
|
|
1717
|
+
const historySnapshot = [ ...results ];
|
|
1718
|
+
const metadata = {
|
|
1719
|
+
phaseNumber: item.phaseNumber,
|
|
1720
|
+
phaseName: phase.name,
|
|
1721
|
+
iterationCount: phase.config.iterations,
|
|
1722
|
+
burstSegments: result.segmentCount,
|
|
1723
|
+
segmentCount: result.segmentCount,
|
|
1724
|
+
mode: phase.config.mode,
|
|
1725
|
+
history: historySnapshot
|
|
1726
|
+
};
|
|
1727
|
+
const generatorResult = await phase.generator({
|
|
1728
|
+
result: result,
|
|
1729
|
+
history: historySnapshot,
|
|
1730
|
+
metadata: metadata
|
|
1731
|
+
});
|
|
1732
|
+
if (generatorResult) {
|
|
1733
|
+
const nextPhase = "config" in generatorResult ? {
|
|
1734
|
+
name: generatorResult.name ?? `${phase.name} → gen`,
|
|
1735
|
+
config: generatorResult.config,
|
|
1736
|
+
generator: phase.generator
|
|
1737
|
+
} : {
|
|
1738
|
+
name: `${phase.name} → gen`,
|
|
1739
|
+
config: generatorResult,
|
|
1740
|
+
generator: phase.generator
|
|
1741
|
+
};
|
|
1742
|
+
queue.push({
|
|
1743
|
+
phase: nextPhase,
|
|
1744
|
+
phaseNumber: ++phaseCounter
|
|
1745
|
+
});
|
|
1746
|
+
}
|
|
1747
|
+
}
|
|
1748
|
+
}
|
|
1749
|
+
await this.logSummary(results);
|
|
1750
|
+
return results;
|
|
1751
|
+
}
|
|
1752
|
+
async runPhase(phase, context) {
|
|
1753
|
+
await this.runWarmup(phase, context);
|
|
1754
|
+
const segments = this.buildSegmentIndices(phase.config.iterations, phase.config.burst);
|
|
1755
|
+
const collected = [];
|
|
1756
|
+
for (let segmentIndex = 0; segmentIndex < segments.length; segmentIndex += 1) {
|
|
1757
|
+
const indices = segments[segmentIndex];
|
|
1758
|
+
if (!indices.length) {
|
|
1759
|
+
continue;
|
|
1760
|
+
}
|
|
1761
|
+
debugLog(`[PerfRunner] Phase "${phase.name}" executing segment ${segmentIndex + 1}/${segments.length} (iterations ${indices[0]}-${indices[indices.length - 1]})`);
|
|
1762
|
+
const metrics = await this.executeSegment(this.scenario.handler, phase.config, context, indices);
|
|
1763
|
+
collected.push(...metrics);
|
|
1764
|
+
const burstInterval = phase.config.burst?.intervalMs;
|
|
1765
|
+
if (burstInterval && segmentIndex < segments.length - 1) {
|
|
1766
|
+
await delay(burstInterval);
|
|
1767
|
+
}
|
|
1768
|
+
}
|
|
1769
|
+
const sorted = [ ...collected ].sort((a, b) => a.iteration - b.iteration);
|
|
1770
|
+
const aggregated = this.aggregateMetrics(sorted);
|
|
1771
|
+
if (phase.config.pauseAfterMs) {
|
|
1772
|
+
await delay(phase.config.pauseAfterMs);
|
|
1773
|
+
}
|
|
1774
|
+
if (aggregated.failureCount > 0 && this.scenario.failOnError !== false) {
|
|
1775
|
+
throw new Error(`Phase ${phase.name} recorded ${aggregated.failureCount} failures`);
|
|
1776
|
+
}
|
|
1777
|
+
return {
|
|
1778
|
+
phase: phase,
|
|
1779
|
+
config: phase.config,
|
|
1780
|
+
iterationMetrics: sorted,
|
|
1781
|
+
aggregated: aggregated,
|
|
1782
|
+
context: context,
|
|
1783
|
+
segmentCount: segments.length
|
|
1784
|
+
};
|
|
1785
|
+
}
|
|
1786
|
+
async runWarmup(phase, context) {
|
|
1787
|
+
const warmup = phase.config.warmup;
|
|
1788
|
+
if (!warmup?.iterations) {
|
|
1789
|
+
return;
|
|
1790
|
+
}
|
|
1791
|
+
const handler = warmup.handler ?? this.scenario.handler;
|
|
1792
|
+
for (let index = 0; index < warmup.iterations; index += 1) {
|
|
1793
|
+
await handler({
|
|
1794
|
+
iteration: index,
|
|
1795
|
+
config: phase.config,
|
|
1796
|
+
loadFactor: this.computeLoadFactor(phase.config, index),
|
|
1797
|
+
context: context
|
|
1798
|
+
});
|
|
1799
|
+
if (warmup.delayBetweenIterationsMs && index < warmup.iterations - 1) {
|
|
1800
|
+
await delay(warmup.delayBetweenIterationsMs);
|
|
1801
|
+
}
|
|
1802
|
+
}
|
|
1803
|
+
}
|
|
1804
|
+
computeLoadFactor(config, iteration) {
|
|
1805
|
+
const base = config.loadStart ?? 1;
|
|
1806
|
+
const step = config.loadStep ?? 0;
|
|
1807
|
+
const multiplier = config.loadMultiplier ?? 1;
|
|
1808
|
+
return (base + step * iteration) * multiplier;
|
|
1809
|
+
}
|
|
1810
|
+
buildSegmentIndices(iterations, burst) {
|
|
1811
|
+
const total = Math.max(0, iterations);
|
|
1812
|
+
if (total === 0) {
|
|
1813
|
+
return [];
|
|
1814
|
+
}
|
|
1815
|
+
const chunk = burst?.size && burst.size > 0 ? Math.min(burst.size, total) : total;
|
|
1816
|
+
const segments = [];
|
|
1817
|
+
for (let cursor = 0; cursor < total; cursor += chunk) {
|
|
1818
|
+
const end = Math.min(total, cursor + chunk);
|
|
1819
|
+
segments.push(Array.from({
|
|
1820
|
+
length: end - cursor
|
|
1821
|
+
}, (_, idx) => cursor + idx));
|
|
1822
|
+
}
|
|
1823
|
+
return segments;
|
|
1824
|
+
}
|
|
1825
|
+
mergeContext(phase) {
|
|
1826
|
+
const baseContext = this.scenario.baseContext ?? {};
|
|
1827
|
+
const phaseContext = phase.config.context ?? {};
|
|
1828
|
+
return this.mergeContexts(baseContext, phaseContext);
|
|
1829
|
+
}
|
|
1830
|
+
mergeContexts(a, b) {
|
|
1831
|
+
return Object.assign({}, a, b);
|
|
1832
|
+
}
|
|
1833
|
+
async executeSegment(handler, config, context, indices) {
|
|
1834
|
+
if (!indices.length) {
|
|
1835
|
+
return [];
|
|
1836
|
+
}
|
|
1837
|
+
if (config.mode === "concurrent") {
|
|
1838
|
+
return this.collectConcurrent(handler, config, context, indices);
|
|
1839
|
+
}
|
|
1840
|
+
return this.collectSequential(handler, config, context, indices);
|
|
1841
|
+
}
|
|
1842
|
+
async collectSequential(handler, config, context, indices) {
|
|
1843
|
+
const metrics = [];
|
|
1844
|
+
const delayBetween = config.delayBetweenIterationsMs;
|
|
1845
|
+
for (let idx = 0; idx < indices.length; idx += 1) {
|
|
1846
|
+
metrics.push(await this.runIteration(handler, config, context, indices[idx]));
|
|
1847
|
+
if (delayBetween && idx < indices.length - 1) {
|
|
1848
|
+
await delay(delayBetween);
|
|
1849
|
+
}
|
|
1850
|
+
}
|
|
1851
|
+
return metrics;
|
|
1852
|
+
}
|
|
1853
|
+
async collectConcurrent(handler, config, context, indices) {
|
|
1854
|
+
const concurrency = Math.max(1, Math.min(config.concurrency ?? indices.length, indices.length));
|
|
1855
|
+
const metrics = [];
|
|
1856
|
+
let pointer = 0;
|
|
1857
|
+
const worker = async () => {
|
|
1858
|
+
while (pointer < indices.length) {
|
|
1859
|
+
const iteration = indices[pointer];
|
|
1860
|
+
pointer += 1;
|
|
1861
|
+
metrics.push(await this.runIteration(handler, config, context, iteration));
|
|
1862
|
+
}
|
|
1863
|
+
};
|
|
1864
|
+
await Promise.all(Array.from({
|
|
1865
|
+
length: concurrency
|
|
1866
|
+
}, () => worker()));
|
|
1867
|
+
return metrics;
|
|
1868
|
+
}
|
|
1869
|
+
async runIteration(handler, config, context, iteration) {
|
|
1870
|
+
const loadFactor = this.computeLoadFactor(config, iteration);
|
|
1871
|
+
const stopwatch = new StopWatch(true);
|
|
1872
|
+
let success = true;
|
|
1873
|
+
let meta;
|
|
1874
|
+
debugLog(`[PerfRunner] Iteration ${iteration} (phase=${config.metadata?.phaseName ?? "n/a"}, load=${loadFactor.toFixed(2)}) starting`);
|
|
1875
|
+
try {
|
|
1876
|
+
const result = await handler({
|
|
1877
|
+
iteration: iteration,
|
|
1878
|
+
config: config,
|
|
1879
|
+
loadFactor: loadFactor,
|
|
1880
|
+
context: context
|
|
1881
|
+
});
|
|
1882
|
+
if (typeof result?.success === "boolean") {
|
|
1883
|
+
success = result.success;
|
|
1884
|
+
}
|
|
1885
|
+
meta = result?.meta;
|
|
1886
|
+
} catch (error) {
|
|
1887
|
+
success = false;
|
|
1888
|
+
meta = {
|
|
1889
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1890
|
+
};
|
|
1891
|
+
}
|
|
1892
|
+
const durationMs = stopwatch.stop();
|
|
1893
|
+
debugLog(`[PerfRunner] Iteration ${iteration} complete in ${durationMs.toFixed(2)}ms, success=${success}`);
|
|
1894
|
+
return {
|
|
1895
|
+
iteration: iteration,
|
|
1896
|
+
durationMs: durationMs,
|
|
1897
|
+
success: success,
|
|
1898
|
+
meta: meta,
|
|
1899
|
+
loadFactor: loadFactor
|
|
1900
|
+
};
|
|
1901
|
+
}
|
|
1902
|
+
aggregateMetrics(metrics) {
|
|
1903
|
+
if (metrics.length === 0) {
|
|
1904
|
+
return {
|
|
1905
|
+
totalDurationMs: 0,
|
|
1906
|
+
minMs: 0,
|
|
1907
|
+
maxMs: 0,
|
|
1908
|
+
averageMs: 0,
|
|
1909
|
+
successCount: 0,
|
|
1910
|
+
failureCount: 0,
|
|
1911
|
+
loadStart: 0,
|
|
1912
|
+
loadEnd: 0
|
|
1913
|
+
};
|
|
1914
|
+
}
|
|
1915
|
+
const totalDurationMs = metrics.reduce((acc, metric) => acc + metric.durationMs, 0);
|
|
1916
|
+
const minMs = Math.min(...metrics.map(metric => metric.durationMs));
|
|
1917
|
+
const maxMs = Math.max(...metrics.map(metric => metric.durationMs));
|
|
1918
|
+
const averageMs = totalDurationMs / metrics.length;
|
|
1919
|
+
const successCount = metrics.filter(metric => metric.success).length;
|
|
1920
|
+
const failureCount = metrics.length - successCount;
|
|
1921
|
+
const loadStart = metrics[0]?.loadFactor ?? 0;
|
|
1922
|
+
const loadEnd = metrics[metrics.length - 1]?.loadFactor ?? loadStart;
|
|
1923
|
+
return {
|
|
1924
|
+
totalDurationMs: totalDurationMs,
|
|
1925
|
+
minMs: minMs,
|
|
1926
|
+
maxMs: maxMs,
|
|
1927
|
+
averageMs: averageMs,
|
|
1928
|
+
successCount: successCount,
|
|
1929
|
+
failureCount: failureCount,
|
|
1930
|
+
loadStart: loadStart,
|
|
1931
|
+
loadEnd: loadEnd
|
|
1932
|
+
};
|
|
1933
|
+
}
|
|
1934
|
+
async logSummary(results) {
|
|
1935
|
+
if (!results.length) {
|
|
1936
|
+
return;
|
|
1937
|
+
}
|
|
1938
|
+
const headers = [ "Phase", "Mode", "Iterations", "Total ms", "Avg ms", "Min ms", "Max ms", "Success", "Failures", "Load range" ];
|
|
1939
|
+
const rows = results.map(result => [ result.phase.name, result.config.mode, result.config.iterations.toString(), result.aggregated.totalDurationMs.toFixed(2), result.aggregated.averageMs.toFixed(2), result.aggregated.minMs.toFixed(2), result.aggregated.maxMs.toFixed(2), result.aggregated.successCount.toString(), result.aggregated.failureCount.toString(), `${result.aggregated.loadStart.toFixed(2)} → ${result.aggregated.loadEnd.toFixed(2)}` ]);
|
|
1940
|
+
console.log(formatTable(`Performance summary for ${this.scenario.name}`, headers, rows));
|
|
1941
|
+
if (this.shouldRenderCanvas()) {
|
|
1942
|
+
const chartPath = this.scenario.canvasOutputPath ?? path.join(process.cwd(), "workdocs", "reports", "performance-runner.png");
|
|
1943
|
+
await renderMetricsTableToCanvas(headers, rows, this.scenario.canvasOptions ?? defaultCanvasOptions, chartPath);
|
|
1944
|
+
}
|
|
1945
|
+
}
|
|
1946
|
+
shouldRenderCanvas() {
|
|
1947
|
+
return this.scenario.enableCanvas ?? Boolean(this.scenario.canvasOptions);
|
|
1948
|
+
}
|
|
1949
|
+
}
|
|
1950
|
+
|
|
1951
|
+
function parseList(input) {
|
|
1952
|
+
if (!input) return [];
|
|
1953
|
+
if (Array.isArray(input)) return input.map(i => `${i}`.trim()).filter(Boolean);
|
|
1954
|
+
return `${input}`.split(",").map(p => p.trim()).filter(Boolean);
|
|
1955
|
+
}
|
|
1956
|
+
|
|
1957
|
+
function packageToGlobal(name) {
|
|
1958
|
+
const withoutScope = name.replace(/^@/, "");
|
|
1959
|
+
const parts = withoutScope.split(/[/\-_.]+/).filter(Boolean);
|
|
1960
|
+
return parts.map((p, i) => i === 0 ? p.replace(/[^a-zA-Z0-9]/g, "") : `${p.charAt(0).toUpperCase()}${p.slice(1)}`).join("");
|
|
1961
|
+
}
|
|
1962
|
+
|
|
1963
|
+
function getPackageDependencies() {
|
|
1964
|
+
let pkg;
|
|
1965
|
+
try {
|
|
1966
|
+
pkg = getPackage(process.cwd());
|
|
1967
|
+
} catch {
|
|
1968
|
+
pkg = undefined;
|
|
1969
|
+
}
|
|
1970
|
+
try {
|
|
1971
|
+
const hasDeps = pkg && (Object.keys(pkg.dependencies || {}).length > 0 || Object.keys(pkg.devDependencies || {}).length > 0 || Object.keys(pkg.peerDependencies || {}).length > 0);
|
|
1972
|
+
if (!hasDeps) {
|
|
1973
|
+
const fallbackDir = path.resolve(__dirname, "../../..");
|
|
1974
|
+
try {
|
|
1975
|
+
pkg = getPackage(fallbackDir);
|
|
1976
|
+
} catch {}
|
|
1977
|
+
}
|
|
1978
|
+
} catch {}
|
|
1979
|
+
const deps = Object.keys(pkg && pkg.dependencies || {});
|
|
1980
|
+
const peer = Object.keys(pkg && pkg.peerDependencies || {});
|
|
1981
|
+
const dev = Object.keys(pkg && pkg.devDependencies || {});
|
|
1982
|
+
return Array.from(new Set([ ...deps, ...peer, ...dev ]));
|
|
1983
|
+
}
|
|
1984
|
+
|
|
1985
|
+
const VERSION_STRING = "##VERSION##";
|
|
1986
|
+
|
|
1987
|
+
const PACKAGE_STRING = "##PACKAGE##";
|
|
1988
|
+
|
|
1989
|
+
const PACKAGE_SIZE_STRING = "##PACKAGE_SIZE##";
|
|
1990
|
+
|
|
1991
|
+
var Modes;
|
|
1992
|
+
|
|
1993
|
+
(function(Modes) {
|
|
1994
|
+
Modes["CJS"] = "commonjs";
|
|
1995
|
+
Modes["ESM"] = "es2022";
|
|
1996
|
+
})(Modes || (Modes = {}));
|
|
1997
|
+
|
|
1998
|
+
var BuildMode;
|
|
1999
|
+
|
|
2000
|
+
(function(BuildMode) {
|
|
2001
|
+
BuildMode["BUILD"] = "build";
|
|
2002
|
+
BuildMode["BUNDLE"] = "bundle";
|
|
2003
|
+
BuildMode["ALL"] = "all";
|
|
2004
|
+
})(BuildMode || (BuildMode = {}));
|
|
2005
|
+
|
|
2006
|
+
const options$1 = {
|
|
2007
|
+
prod: {
|
|
2008
|
+
type: "boolean",
|
|
2009
|
+
default: false
|
|
2010
|
+
},
|
|
2011
|
+
dev: {
|
|
2012
|
+
type: "boolean",
|
|
2013
|
+
default: false
|
|
2014
|
+
},
|
|
2015
|
+
buildMode: {
|
|
2016
|
+
type: "string",
|
|
2017
|
+
default: BuildMode.ALL
|
|
2018
|
+
},
|
|
2019
|
+
includes: {
|
|
2020
|
+
type: "string",
|
|
2021
|
+
default: ""
|
|
2022
|
+
},
|
|
2023
|
+
externals: {
|
|
2024
|
+
type: "string",
|
|
2025
|
+
default: ""
|
|
2026
|
+
},
|
|
2027
|
+
docs: {
|
|
2028
|
+
type: "boolean",
|
|
2029
|
+
default: false
|
|
2030
|
+
},
|
|
2031
|
+
commands: {
|
|
2032
|
+
type: "boolean",
|
|
2033
|
+
default: false
|
|
2034
|
+
},
|
|
2035
|
+
entry: {
|
|
2036
|
+
type: "string",
|
|
2037
|
+
default: "./src/index.ts"
|
|
2038
|
+
},
|
|
2039
|
+
banner: {
|
|
2040
|
+
type: "boolean",
|
|
2041
|
+
default: false
|
|
2042
|
+
}
|
|
2043
|
+
};
|
|
2044
|
+
|
|
2045
|
+
const cjs2Transformer = (ext = ".cjs") => {
|
|
2046
|
+
const log = BuildScripts.log.for(cjs2Transformer);
|
|
2047
|
+
const resolutionCache = new Map;
|
|
2048
|
+
return transformationContext => sourceFile => {
|
|
2049
|
+
const sourceDir = path.dirname(sourceFile.fileName);
|
|
2050
|
+
function resolvePath(importPath) {
|
|
2051
|
+
const cacheKey = JSON.stringify([ sourceDir, importPath ]);
|
|
2052
|
+
const cachedValue = resolutionCache.get(cacheKey);
|
|
2053
|
+
if (cachedValue != null) return cachedValue;
|
|
2054
|
+
let resolvedPath = importPath;
|
|
2055
|
+
try {
|
|
2056
|
+
resolvedPath = path.resolve(sourceDir, resolvedPath + ".ts");
|
|
2057
|
+
} catch (error) {
|
|
2058
|
+
throw new Error(`Failed to resolve path ${importPath}: ${error}`);
|
|
2059
|
+
}
|
|
2060
|
+
let stat;
|
|
2061
|
+
try {
|
|
2062
|
+
stat = fs.statSync(resolvedPath);
|
|
2063
|
+
} catch (e) {
|
|
2064
|
+
try {
|
|
2065
|
+
log.verbose(`Testing existence of path ${resolvedPath} as a folder defaulting to index file`);
|
|
2066
|
+
stat = fs.statSync(resolvedPath.replace(/\.ts$/gm, ""));
|
|
2067
|
+
} catch (e2) {
|
|
2068
|
+
throw new Error(`Failed to resolve path ${importPath}: ${e}, ${e2}`);
|
|
2069
|
+
}
|
|
2070
|
+
}
|
|
2071
|
+
if (stat.isDirectory()) resolvedPath = resolvedPath.replace(/\.ts$/gm, "/index.ts");
|
|
2072
|
+
if (path.isAbsolute(resolvedPath)) {
|
|
2073
|
+
const extension = (/\.tsx?$/.exec(path.basename(resolvedPath)) || [])[0] || void 0;
|
|
2074
|
+
resolvedPath = "./" + path.relative(sourceDir, path.resolve(path.dirname(resolvedPath), path.basename(resolvedPath, extension) + ext));
|
|
2075
|
+
}
|
|
2076
|
+
resolutionCache.set(cacheKey, resolvedPath);
|
|
2077
|
+
return resolvedPath;
|
|
2078
|
+
}
|
|
2079
|
+
function visitNode(node) {
|
|
2080
|
+
if (shouldMutateModuleSpecifier(node)) {
|
|
2081
|
+
if (ts.isImportDeclaration(node)) {
|
|
2082
|
+
const resolvedPath = resolvePath(node.moduleSpecifier.text);
|
|
2083
|
+
const newModuleSpecifier = transformationContext.factory.createStringLiteral(resolvedPath);
|
|
2084
|
+
return transformationContext.factory.updateImportDeclaration(node, node.modifiers, node.importClause, newModuleSpecifier, undefined);
|
|
2085
|
+
} else if (ts.isExportDeclaration(node)) {
|
|
2086
|
+
const resolvedPath = resolvePath(node.moduleSpecifier.text);
|
|
2087
|
+
const newModuleSpecifier = transformationContext.factory.createStringLiteral(resolvedPath);
|
|
2088
|
+
return transformationContext.factory.updateExportDeclaration(node, node.modifiers, node.isTypeOnly, node.exportClause, newModuleSpecifier, undefined);
|
|
2089
|
+
}
|
|
2090
|
+
}
|
|
2091
|
+
return ts.visitEachChild(node, visitNode, transformationContext);
|
|
2092
|
+
}
|
|
2093
|
+
function shouldMutateModuleSpecifier(node) {
|
|
2094
|
+
if (!ts.isImportDeclaration(node) && !ts.isExportDeclaration(node)) return false;
|
|
2095
|
+
if (node.moduleSpecifier === undefined) return false;
|
|
2096
|
+
if (!ts.isStringLiteral(node.moduleSpecifier)) return false;
|
|
2097
|
+
if (!node.moduleSpecifier.text.startsWith("./") && !node.moduleSpecifier.text.startsWith("../")) return false;
|
|
2098
|
+
if (path.extname(node.moduleSpecifier.text) !== "") return false;
|
|
2099
|
+
return true;
|
|
2100
|
+
}
|
|
2101
|
+
return ts.visitNode(sourceFile, visitNode);
|
|
2102
|
+
};
|
|
2103
|
+
};
|
|
2104
|
+
|
|
2105
|
+
class BuildScripts extends Command {
|
|
2106
|
+
constructor() {
|
|
2107
|
+
super("BuildScripts", Object.assign({}, DefaultCommandOptions, options$1));
|
|
2108
|
+
this.replacements = {};
|
|
2109
|
+
const pkg = getPackage();
|
|
2110
|
+
const {name: name, version: version} = pkg;
|
|
2111
|
+
this.pkgName = name.includes("@") ? name.split("/")[1] : name;
|
|
2112
|
+
this.pkgVersion = version;
|
|
2113
|
+
this.replacements[VERSION_STRING] = this.pkgVersion;
|
|
2114
|
+
this.replacements[PACKAGE_STRING] = name;
|
|
2115
|
+
}
|
|
2116
|
+
patchFiles(p) {
|
|
2117
|
+
const log = this.log.for(this.patchFiles);
|
|
2118
|
+
const {name: name, version: version} = getPackage();
|
|
2119
|
+
log.info(`Patching ${name} ${version} module in ${p}...`);
|
|
2120
|
+
const stat = fs.statSync(p);
|
|
2121
|
+
if (stat.isDirectory()) fs.readdirSync(p, {
|
|
2122
|
+
withFileTypes: true,
|
|
2123
|
+
recursive: true
|
|
2124
|
+
}).filter(p => p.isFile()).forEach(file => patchFile(path.join(file.parentPath, file.name), Object.entries(this.replacements).reduce((acc, [key, val]) => {
|
|
2125
|
+
switch (key) {
|
|
2126
|
+
case VERSION_STRING:
|
|
2127
|
+
log.debug("Found VERSION string to replace");
|
|
2128
|
+
acc[`VERSION = "${VERSION_STRING}";`] = `VERSION = "${val}";`;
|
|
2129
|
+
break;
|
|
2130
|
+
|
|
2131
|
+
case PACKAGE_STRING:
|
|
2132
|
+
log.debug("Found PACKAGE_NAME string to replace");
|
|
2133
|
+
acc[`PACKAGE_NAME = "${PACKAGE_STRING}";`] = `PACKAGE_NAME = "${val}";`;
|
|
2134
|
+
break;
|
|
2135
|
+
|
|
2136
|
+
default:
|
|
2137
|
+
acc[key] = val;
|
|
2138
|
+
}
|
|
2139
|
+
return acc;
|
|
2140
|
+
}, {})));
|
|
2141
|
+
log.verbose(`Module ${name} ${version} patched in ${p}...`);
|
|
2142
|
+
}
|
|
2143
|
+
reportDiagnostics(diagnostics, logLevel) {
|
|
2144
|
+
const msg = this.formatDiagnostics(diagnostics);
|
|
2145
|
+
try {
|
|
2146
|
+
this.log[logLevel](msg);
|
|
2147
|
+
} catch (e) {
|
|
2148
|
+
console.warn(`Failed to get logger for ${logLevel}`);
|
|
2149
|
+
throw e;
|
|
2150
|
+
}
|
|
2151
|
+
return msg;
|
|
2152
|
+
}
|
|
2153
|
+
formatDiagnostics(diagnostics) {
|
|
2154
|
+
return diagnostics.map(diagnostic => {
|
|
2155
|
+
let message = "";
|
|
2156
|
+
if (diagnostic.file && diagnostic.start) {
|
|
2157
|
+
const {line: line, character: character} = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
|
|
2158
|
+
message += `${diagnostic.file.fileName} (${line + 1},${character + 1})`;
|
|
2159
|
+
}
|
|
2160
|
+
message += ": " + ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n");
|
|
2161
|
+
return message;
|
|
2162
|
+
}).join("\n");
|
|
2163
|
+
}
|
|
2164
|
+
readConfigFile(configFileName) {
|
|
2165
|
+
const configFileText = fs.readFileSync(configFileName).toString();
|
|
2166
|
+
const result = ts.parseConfigFileTextToJson(configFileName, configFileText);
|
|
2167
|
+
const configObject = result.config;
|
|
2168
|
+
if (!configObject) {
|
|
2169
|
+
this.reportDiagnostics([ result.error ], LogLevel.error);
|
|
2170
|
+
}
|
|
2171
|
+
const configParseResult = ts.parseJsonConfigFileContent(configObject, ts.sys, path.dirname(configFileName));
|
|
2172
|
+
if (configParseResult.errors.length > 0) this.reportDiagnostics(configParseResult.errors, LogLevel.error);
|
|
2173
|
+
return configParseResult;
|
|
2174
|
+
}
|
|
2175
|
+
evalDiagnostics(diagnostics) {
|
|
2176
|
+
if (diagnostics && diagnostics.length > 0) {
|
|
2177
|
+
const errors = diagnostics.filter(d => d.category === ts.DiagnosticCategory.Error);
|
|
2178
|
+
const warnings = diagnostics.filter(d => d.category === ts.DiagnosticCategory.Warning);
|
|
2179
|
+
const suggestions = diagnostics.filter(d => d.category === ts.DiagnosticCategory.Suggestion);
|
|
2180
|
+
const messages = diagnostics.filter(d => d.category === ts.DiagnosticCategory.Message);
|
|
2181
|
+
if (warnings.length) this.reportDiagnostics(warnings, LogLevel.warn);
|
|
2182
|
+
if (errors.length) {
|
|
2183
|
+
this.reportDiagnostics(diagnostics, LogLevel.error);
|
|
2184
|
+
throw new Error(`TypeScript reported ${diagnostics.length} diagnostic(s) during check; aborting.`);
|
|
2185
|
+
}
|
|
2186
|
+
if (suggestions.length) this.reportDiagnostics(suggestions, LogLevel.info);
|
|
2187
|
+
if (messages.length) this.reportDiagnostics(messages, LogLevel.info);
|
|
2188
|
+
}
|
|
2189
|
+
}
|
|
2190
|
+
preCheckDiagnostics(program) {
|
|
2191
|
+
const diagnostics = ts.getPreEmitDiagnostics(program);
|
|
2192
|
+
this.evalDiagnostics(diagnostics);
|
|
2193
|
+
}
|
|
2194
|
+
async checkTsDiagnostics(isDev, mode, bundle = false) {
|
|
2195
|
+
const log = this.log.for(this.checkTsDiagnostics);
|
|
2196
|
+
let tsConfig;
|
|
2197
|
+
try {
|
|
2198
|
+
tsConfig = this.readConfigFile("./tsconfig.json");
|
|
2199
|
+
} catch (e) {
|
|
2200
|
+
throw new Error(`Failed to parse tsconfig.json: ${e}`);
|
|
2201
|
+
}
|
|
2202
|
+
if (bundle) {
|
|
2203
|
+
tsConfig.options.module = ModuleKind.AMD;
|
|
2204
|
+
tsConfig.options.outDir = "dist";
|
|
2205
|
+
tsConfig.options.isolatedModules = false;
|
|
2206
|
+
tsConfig.options.outFile = this.pkgName;
|
|
2207
|
+
} else {
|
|
2208
|
+
tsConfig.options.outDir = `lib${mode === Modes.ESM ? "/esm" : ""}`;
|
|
2209
|
+
tsConfig.options.module = mode === Modes.ESM ? ModuleKind.ES2022 : ModuleKind.CommonJS;
|
|
2210
|
+
}
|
|
2211
|
+
tsConfig.options.inlineSourceMap = false;
|
|
2212
|
+
tsConfig.options.inlineSources = false;
|
|
2213
|
+
tsConfig.options.sourceMap = true;
|
|
2214
|
+
const program = ts.createProgram(tsConfig.fileNames, tsConfig.options);
|
|
2215
|
+
this.preCheckDiagnostics(program);
|
|
2216
|
+
log.verbose(`TypeScript checks passed (${bundle ? "bundle" : "normal"} mode).`);
|
|
2217
|
+
}
|
|
2218
|
+
async buildTs(isDev, mode, bundle = false) {
|
|
2219
|
+
const log = this.log.for(this.buildTs);
|
|
2220
|
+
log.info(`Building ${this.pkgName} ${this.pkgVersion} module (${mode}) in ${isDev ? "dev" : "prod"} mode...`);
|
|
2221
|
+
let tsConfig;
|
|
2222
|
+
try {
|
|
2223
|
+
tsConfig = this.readConfigFile("./tsconfig.json");
|
|
2224
|
+
} catch (e) {
|
|
2225
|
+
throw new Error(`Failed to parse tsconfig.json: ${e}`);
|
|
2226
|
+
}
|
|
2227
|
+
if (bundle) {
|
|
2228
|
+
tsConfig.options.module = ModuleKind.AMD;
|
|
2229
|
+
tsConfig.options.outDir = "dist";
|
|
2230
|
+
tsConfig.options.isolatedModules = false;
|
|
2231
|
+
tsConfig.options.outFile = this.pkgName;
|
|
2232
|
+
} else {
|
|
2233
|
+
tsConfig.options.outDir = `lib${mode === Modes.ESM ? "/esm" : ""}`;
|
|
2234
|
+
tsConfig.options.module = mode === Modes.ESM ? ModuleKind.ES2022 : ModuleKind.CommonJS;
|
|
2235
|
+
}
|
|
2236
|
+
if (isDev) {
|
|
2237
|
+
tsConfig.options.inlineSourceMap = true;
|
|
2238
|
+
tsConfig.options.inlineSources = true;
|
|
2239
|
+
tsConfig.options.sourceMap = false;
|
|
2240
|
+
} else {
|
|
2241
|
+
tsConfig.options.inlineSourceMap = false;
|
|
2242
|
+
tsConfig.options.inlineSources = false;
|
|
2243
|
+
tsConfig.options.sourceMap = true;
|
|
2244
|
+
}
|
|
2245
|
+
const program = ts.createProgram(tsConfig.fileNames, tsConfig.options);
|
|
2246
|
+
const transformations = {};
|
|
2247
|
+
if (mode === Modes.CJS) {
|
|
2248
|
+
transformations.before = [ cjs2Transformer(".cjs") ];
|
|
2249
|
+
} else if (mode === Modes.ESM) {
|
|
2250
|
+
transformations.before = [ cjs2Transformer(".js") ];
|
|
2251
|
+
}
|
|
2252
|
+
const emitResult = program.emit(undefined, undefined, undefined, undefined, transformations);
|
|
2253
|
+
const allDiagnostics = ts.getPreEmitDiagnostics(program).concat(emitResult.diagnostics);
|
|
2254
|
+
this.evalDiagnostics(allDiagnostics);
|
|
2255
|
+
}
|
|
2256
|
+
async build(isDev, mode, bundle = false) {
|
|
2257
|
+
const log = this.log.for(this.build);
|
|
2258
|
+
await this.buildTs(isDev, mode, bundle);
|
|
2259
|
+
log.verbose(`Module ${this.pkgName} ${this.pkgVersion} (${mode}) built in ${isDev ? "dev" : "prod"} mode...`);
|
|
2260
|
+
if (mode === Modes.CJS && !bundle) {
|
|
2261
|
+
const files = getAllFiles("lib", file => file.endsWith(".js") && !file.includes("/esm/"));
|
|
2262
|
+
for (const file of files) {
|
|
2263
|
+
log.verbose(`Patching ${file}'s cjs imports...`);
|
|
2264
|
+
const f = file.replace(".js", ".cjs");
|
|
2265
|
+
await renameFile(file, f);
|
|
2266
|
+
}
|
|
2267
|
+
}
|
|
2268
|
+
}
|
|
2269
|
+
copyAssets(mode) {
|
|
2270
|
+
const log = this.log.for(this.copyAssets);
|
|
2271
|
+
let hasAssets = false;
|
|
2272
|
+
try {
|
|
2273
|
+
hasAssets = fs.statSync("./src/assets").isDirectory();
|
|
2274
|
+
} catch (e) {
|
|
2275
|
+
return log.verbose(`No assets found in ./src/assets to copy`);
|
|
2276
|
+
}
|
|
2277
|
+
if (hasAssets) copyFile("./src/assets", `./${mode === Modes.CJS ? "lib" : "dist"}/assets`);
|
|
2278
|
+
}
|
|
2279
|
+
async bundle(mode, isDev, isLib, entryFile = "./src/index.ts", nameOverride = this.pkgName, externalsArg, includeArg = [ "prompts", "styled-string-builder", "typed-object-accumulator", "@decaf-ts/logging" ]) {
|
|
2280
|
+
await this.checkTsDiagnostics(isDev, mode, true);
|
|
2281
|
+
const isEsm = mode === Modes.ESM;
|
|
2282
|
+
const pkgName = this.pkgName;
|
|
2283
|
+
const log = this.log;
|
|
2284
|
+
const include = Array.from(new Set([ ...parseList(includeArg) ]));
|
|
2285
|
+
let externalsList = parseList(externalsArg);
|
|
2286
|
+
if (externalsList.length === 0) {
|
|
2287
|
+
try {
|
|
2288
|
+
externalsList = listNodeModulesPackages(path.join(process.cwd(), "node_modules"));
|
|
2289
|
+
} catch {}
|
|
2290
|
+
if (!externalsList || externalsList.length === 0) {
|
|
2291
|
+
externalsList = getPackageDependencies();
|
|
2292
|
+
}
|
|
2293
|
+
}
|
|
2294
|
+
const ext = Array.from(new Set([ ...function builtinList() {
|
|
2295
|
+
try {
|
|
2296
|
+
return Array.isArray(builtinModules) ? builtinModules : [];
|
|
2297
|
+
} catch {
|
|
2298
|
+
return [ "fs", "path", "process", "child_process", "util", "https", "http", "os", "stream", "crypto", "zlib", "net", "tls", "url", "querystring", "assert", "events", "tty", "dns", "querystring" ];
|
|
2299
|
+
}
|
|
2300
|
+
}(), ...externalsList ]));
|
|
2301
|
+
const rollupSourceMapOutput = isDev ? "inline" : true;
|
|
2302
|
+
const plugins = [ typescript({
|
|
2303
|
+
compilerOptions: {
|
|
2304
|
+
module: "esnext",
|
|
2305
|
+
declaration: false,
|
|
2306
|
+
outDir: isLib ? "bin" : "dist",
|
|
2307
|
+
sourceMap: isDev ? false : true,
|
|
2308
|
+
inlineSourceMap: isDev ? true : false,
|
|
2309
|
+
inlineSources: isDev ? true : false
|
|
2310
|
+
},
|
|
2311
|
+
include: [ "src/**/*.ts" ],
|
|
2312
|
+
exclude: [ "node_modules", "**/*.spec.ts" ],
|
|
2313
|
+
tsconfig: "./tsconfig.json"
|
|
2314
|
+
}), json() ];
|
|
2315
|
+
if (isLib) {
|
|
2316
|
+
plugins.push(commonjs({
|
|
2317
|
+
include: [],
|
|
2318
|
+
exclude: externalsList
|
|
2319
|
+
}), nodeResolve({
|
|
2320
|
+
resolveOnly: include
|
|
2321
|
+
}));
|
|
2322
|
+
}
|
|
2323
|
+
try {
|
|
2324
|
+
const terserMod = await import("@rollup/plugin-terser");
|
|
2325
|
+
const terserFn = terserMod && terserMod.terser || terserMod.default || terserMod;
|
|
2326
|
+
const terserOptionsDev = {
|
|
2327
|
+
parse: {
|
|
2328
|
+
ecma: 2020
|
|
2329
|
+
},
|
|
2330
|
+
compress: false,
|
|
2331
|
+
mangle: false,
|
|
2332
|
+
format: {
|
|
2333
|
+
comments: false,
|
|
2334
|
+
beautify: true
|
|
2335
|
+
}
|
|
2336
|
+
};
|
|
2337
|
+
const terserOptionsProd = {
|
|
2338
|
+
parse: {
|
|
2339
|
+
ecma: 2020
|
|
2340
|
+
},
|
|
2341
|
+
compress: {
|
|
2342
|
+
ecma: 2020,
|
|
2343
|
+
passes: 5,
|
|
2344
|
+
drop_console: true,
|
|
2345
|
+
drop_debugger: true,
|
|
2346
|
+
toplevel: true,
|
|
2347
|
+
module: isEsm,
|
|
2348
|
+
unsafe: true,
|
|
2349
|
+
unsafe_arrows: true,
|
|
2350
|
+
unsafe_comps: true,
|
|
2351
|
+
collapse_vars: true,
|
|
2352
|
+
reduce_funcs: true,
|
|
2353
|
+
reduce_vars: true
|
|
2354
|
+
},
|
|
2355
|
+
mangle: {
|
|
2356
|
+
toplevel: true
|
|
2357
|
+
},
|
|
2358
|
+
format: {
|
|
2359
|
+
comments: false,
|
|
2360
|
+
ascii_only: true
|
|
2361
|
+
},
|
|
2362
|
+
toplevel: true
|
|
2363
|
+
};
|
|
2364
|
+
plugins.push(terserFn(isDev ? terserOptionsDev : terserOptionsProd));
|
|
2365
|
+
} catch {}
|
|
2366
|
+
const input = {
|
|
2367
|
+
input: entryFile,
|
|
2368
|
+
plugins: plugins,
|
|
2369
|
+
external: ext,
|
|
2370
|
+
onwarn: undefined,
|
|
2371
|
+
treeshake: !isDev
|
|
2372
|
+
};
|
|
2373
|
+
const globals = {};
|
|
2374
|
+
ext.forEach(e => {
|
|
2375
|
+
globals[e] = packageToGlobal(e);
|
|
2376
|
+
});
|
|
2377
|
+
const outputs = [ {
|
|
2378
|
+
file: `${isLib ? "bin/" : "dist/"}${nameOverride ? nameOverride : `.bundle.${!isDev ? "min" : ""}`}${isEsm ? ".js" : ".cjs"}`,
|
|
2379
|
+
format: isLib ? "cjs" : isEsm ? "esm" : "umd",
|
|
2380
|
+
name: pkgName,
|
|
2381
|
+
esModule: isEsm,
|
|
2382
|
+
sourcemap: rollupSourceMapOutput,
|
|
2383
|
+
globals: globals,
|
|
2384
|
+
exports: "auto"
|
|
2385
|
+
} ];
|
|
2386
|
+
try {
|
|
2387
|
+
const bundle = await rollup(input);
|
|
2388
|
+
log.verbose(bundle.watchFiles);
|
|
2389
|
+
async function generateOutputs(bundle) {
|
|
2390
|
+
for (const outputOptions of outputs) {
|
|
2391
|
+
await bundle.write(outputOptions);
|
|
2392
|
+
}
|
|
2393
|
+
}
|
|
2394
|
+
await generateOutputs(bundle);
|
|
2395
|
+
} catch (e) {
|
|
2396
|
+
throw new Error(`Failed to bundle: ${e}`);
|
|
2397
|
+
}
|
|
2398
|
+
}
|
|
2399
|
+
async buildByEnv(entryFile = "./src/index.ts", isDev, mode = BuildMode.ALL, includesArg, externalsArg) {
|
|
2400
|
+
try {
|
|
2401
|
+
deletePath("lib");
|
|
2402
|
+
} catch (e) {}
|
|
2403
|
+
try {
|
|
2404
|
+
deletePath("dist");
|
|
2405
|
+
} catch (e) {}
|
|
2406
|
+
if ([ BuildMode.ALL, BuildMode.BUILD ].includes(mode)) {
|
|
2407
|
+
fs.mkdirSync("lib");
|
|
2408
|
+
await this.build(isDev, Modes.ESM);
|
|
2409
|
+
await this.build(isDev, Modes.CJS);
|
|
2410
|
+
this.patchFiles("lib");
|
|
2411
|
+
}
|
|
2412
|
+
if ([ BuildMode.ALL, BuildMode.BUNDLE ].includes(mode)) {
|
|
2413
|
+
fs.mkdirSync("dist");
|
|
2414
|
+
await this.bundle(Modes.ESM, isDev, false, entryFile || "./src/index.ts", this.pkgName, externalsArg, includesArg);
|
|
2415
|
+
await this.bundle(Modes.CJS, isDev, false, entryFile || "./src/index.ts", this.pkgName, externalsArg, includesArg);
|
|
2416
|
+
this.patchFiles("dist");
|
|
2417
|
+
}
|
|
2418
|
+
this.copyAssets(Modes.CJS);
|
|
2419
|
+
this.copyAssets(Modes.ESM);
|
|
2420
|
+
}
|
|
2421
|
+
async buildDev(entryFile = "./src/index.ts", mode = BuildMode.ALL, includesArg, externalsArg) {
|
|
2422
|
+
return this.buildByEnv(entryFile, true, mode, includesArg, externalsArg);
|
|
2423
|
+
}
|
|
2424
|
+
async buildProd(entryFile = "./src/index.ts", mode = BuildMode.ALL, includesArg, externalsArg) {
|
|
2425
|
+
return this.buildByEnv(entryFile, false, mode, includesArg, externalsArg);
|
|
2426
|
+
}
|
|
2427
|
+
async buildDocs() {
|
|
2428
|
+
await runCommand(`npm install better-docs taffydb`).promise;
|
|
2429
|
+
await runCommand(`npx markdown-include ./workdocs/readme-md.json`).promise;
|
|
2430
|
+
await runCommand(`npx jsdoc -c ./workdocs/jsdocs.json -t ./node_modules/better-docs`).promise;
|
|
2431
|
+
await runCommand(`npm remove better-docs taffydb`).promise;
|
|
2432
|
+
[ {
|
|
2433
|
+
src: "workdocs/assets",
|
|
2434
|
+
dest: "./docs/workdocs/assets"
|
|
2435
|
+
}, {
|
|
2436
|
+
src: "workdocs/reports/coverage",
|
|
2437
|
+
dest: "./docs/workdocs/reports/coverage"
|
|
2438
|
+
}, {
|
|
2439
|
+
src: "workdocs/reports/html",
|
|
2440
|
+
dest: "./docs/workdocs/reports/html"
|
|
2441
|
+
}, {
|
|
2442
|
+
src: "workdocs/resources",
|
|
2443
|
+
dest: "./docs/workdocs/resources"
|
|
2444
|
+
}, {
|
|
2445
|
+
src: "LICENSE.md",
|
|
2446
|
+
dest: "./docs/LICENSE.md"
|
|
2447
|
+
} ].forEach(f => {
|
|
2448
|
+
const {src: src, dest: dest} = f;
|
|
2449
|
+
copyFile(src, dest);
|
|
2450
|
+
});
|
|
2451
|
+
try {
|
|
2452
|
+
const sizeKb = await getFileSizeZipped(path.resolve(path.join(process.cwd(), "dist")));
|
|
2453
|
+
this.replacements[PACKAGE_SIZE_STRING] = `${sizeKb} KB`;
|
|
2454
|
+
} catch {
|
|
2455
|
+
this.replacements[PACKAGE_SIZE_STRING] = "unknown";
|
|
2456
|
+
}
|
|
2457
|
+
try {
|
|
2458
|
+
patchFile("./README.md", this.replacements);
|
|
2459
|
+
} catch (e) {
|
|
2460
|
+
const log = this.log.for(this.buildDocs);
|
|
2461
|
+
log.verbose(`Failed to patch README.md: ${e}`);
|
|
2462
|
+
}
|
|
2463
|
+
}
|
|
2464
|
+
async run(answers) {
|
|
2465
|
+
const {dev: dev, prod: prod, docs: docs, buildMode: buildMode, includes: includes, externals: externals, entry: entry} = answers;
|
|
2466
|
+
if (dev) {
|
|
2467
|
+
return await this.buildDev(entry || "./src/index.ts", buildMode, includes, externals);
|
|
2468
|
+
}
|
|
2469
|
+
if (prod) {
|
|
2470
|
+
return await this.buildProd(entry || "./src/index.ts", buildMode, includes, externals);
|
|
2471
|
+
}
|
|
2472
|
+
if (docs) {
|
|
2473
|
+
return await this.buildDocs();
|
|
2474
|
+
}
|
|
2475
|
+
}
|
|
2476
|
+
}
|
|
2477
|
+
|
|
2478
|
+
const options = {
|
|
2479
|
+
ci: {
|
|
2480
|
+
type: "boolean",
|
|
2481
|
+
default: true
|
|
2482
|
+
},
|
|
2483
|
+
message: {
|
|
2484
|
+
type: "string",
|
|
2485
|
+
short: "m"
|
|
2486
|
+
},
|
|
2487
|
+
tag: {
|
|
2488
|
+
type: "string",
|
|
2489
|
+
short: "t",
|
|
2490
|
+
default: undefined
|
|
2491
|
+
}
|
|
2492
|
+
};
|
|
2493
|
+
|
|
2494
|
+
class ReleaseScript extends Command {
|
|
2495
|
+
constructor() {
|
|
2496
|
+
super("ReleaseScript", options);
|
|
2497
|
+
}
|
|
2498
|
+
async prepareVersion(tag) {
|
|
2499
|
+
const log = this.log.for(this.prepareVersion);
|
|
2500
|
+
tag = this.testVersion(tag || "");
|
|
2501
|
+
if (!tag) {
|
|
2502
|
+
log.verbose("No release message provided. Prompting for one:");
|
|
2503
|
+
log.info(`Listing latest git tags:`);
|
|
2504
|
+
await runCommand("git tag --sort=-taggerdate | head -n 5").promise;
|
|
2505
|
+
return await UserInput.insistForText("tag", "Enter the new tag number (accepts v*.*.*[-...])", val => !!val.toString().match(/^v[0-9]+\.[0-9]+.[0-9]+(-[0-9a-zA-Z-]+)?$/));
|
|
2506
|
+
}
|
|
2507
|
+
return tag;
|
|
2508
|
+
}
|
|
2509
|
+
testVersion(version) {
|
|
2510
|
+
const log = this.log.for(this.testVersion);
|
|
2511
|
+
version = version.trim().toLowerCase();
|
|
2512
|
+
switch (version) {
|
|
2513
|
+
case SemVersion.PATCH:
|
|
2514
|
+
case SemVersion.MINOR:
|
|
2515
|
+
case SemVersion.MAJOR:
|
|
2516
|
+
log.verbose(`Using provided SemVer update: ${version}`, 1);
|
|
2517
|
+
return version;
|
|
2518
|
+
|
|
2519
|
+
default:
|
|
2520
|
+
log.verbose(`Testing provided version for SemVer compatibility: ${version}`, 1);
|
|
2521
|
+
if (!new RegExp(SemVersionRegex).test(version)) {
|
|
2522
|
+
log.debug(`Invalid version number: ${version}`);
|
|
2523
|
+
return undefined;
|
|
2524
|
+
}
|
|
2525
|
+
log.verbose(`version approved: ${version}`, 1);
|
|
2526
|
+
return version;
|
|
2527
|
+
}
|
|
2528
|
+
}
|
|
2529
|
+
async prepareMessage(message) {
|
|
2530
|
+
const log = this.log.for(this.prepareMessage);
|
|
2531
|
+
if (!message) {
|
|
2532
|
+
log.verbose("No release message provided. Prompting for one");
|
|
2533
|
+
return await UserInput.insistForText("message", "What should be the release message/ticket?", val => !!val && val.toString().length > 5);
|
|
2534
|
+
}
|
|
2535
|
+
return message;
|
|
2536
|
+
}
|
|
2537
|
+
async run(args) {
|
|
2538
|
+
let result;
|
|
2539
|
+
const {ci: ci} = args;
|
|
2540
|
+
let {tag: tag, message: message} = args;
|
|
2541
|
+
tag = await this.prepareVersion(tag);
|
|
2542
|
+
message = await this.prepareMessage(message);
|
|
2543
|
+
result = await runCommand(`npm run prepare-release -- ${tag} ${message}`, {
|
|
2544
|
+
cwd: process.cwd()
|
|
2545
|
+
}).promise;
|
|
2546
|
+
result = await runCommand("git status --porcelain").promise;
|
|
2547
|
+
await result;
|
|
2548
|
+
if (result.logs.length && await UserInput.askConfirmation("git-changes", "Do you want to push the changes to the remote repository?", true)) {
|
|
2549
|
+
await runCommand("git add .").promise;
|
|
2550
|
+
await runCommand(`git commit -m "${tag} - ${message} - after release preparation${ci ? "" : NoCIFLag}"`).promise;
|
|
2551
|
+
}
|
|
2552
|
+
await runCommand(`npm version "${tag}" -m "${message}${ci ? "" : NoCIFLag}"`).promise;
|
|
2553
|
+
await runCommand("git push --follow-tags").promise;
|
|
2554
|
+
if (!ci) {
|
|
2555
|
+
await runCommand("NPM_TOKEN=$(cat .npmtoken) npm publish --access public").promise;
|
|
2556
|
+
}
|
|
2557
|
+
}
|
|
2558
|
+
}
|
|
2559
|
+
|
|
2560
|
+
class RegexpOutputWriter extends StandardOutputWriter {
|
|
2561
|
+
constructor(cmd, lock, regexp, flags = "g") {
|
|
2562
|
+
super(cmd, lock);
|
|
2563
|
+
try {
|
|
2564
|
+
this.regexp = typeof regexp === "string" ? new RegExp(regexp, flags) : regexp;
|
|
2565
|
+
} catch (e) {
|
|
2566
|
+
throw new Error(`Invalid regular expression: ${e}`);
|
|
2567
|
+
}
|
|
2568
|
+
}
|
|
2569
|
+
test(data) {
|
|
2570
|
+
this.regexp.lastIndex = 0;
|
|
2571
|
+
let match;
|
|
2572
|
+
try {
|
|
2573
|
+
match = this.regexp.exec(data);
|
|
2574
|
+
} catch (e) {
|
|
2575
|
+
return console.debug(`Failed to parse chunk: ${data}\nError: ${e} `);
|
|
2576
|
+
}
|
|
2577
|
+
return match;
|
|
2578
|
+
}
|
|
2579
|
+
testAndResolve(data) {
|
|
2580
|
+
const match = this.test(data);
|
|
2581
|
+
if (match) this.resolve(match[0]);
|
|
2582
|
+
}
|
|
2583
|
+
testAndReject(data) {
|
|
2584
|
+
const match = this.test(data);
|
|
2585
|
+
if (match) this.reject(match[0]);
|
|
2586
|
+
}
|
|
2587
|
+
data(chunk) {
|
|
2588
|
+
super.data(chunk);
|
|
2589
|
+
this.testAndResolve(String(chunk));
|
|
2590
|
+
}
|
|
2591
|
+
error(chunk) {
|
|
2592
|
+
super.error(chunk);
|
|
2593
|
+
this.testAndReject(String(chunk));
|
|
2594
|
+
}
|
|
2595
|
+
}
|
|
2596
|
+
|
|
2597
|
+
const VERSION = "0.11.10.experimental.1";
|
|
2598
|
+
|
|
2599
|
+
const PACKAGE_NAME = "@decaf-ts/utils";
|
|
2600
|
+
|
|
2601
|
+
export { AbortCode, BuildScripts, Command, DefaultCommandOptions, DefaultCommandValues, Encoding, HttpClient, NoCIFLag, PACKAGE_NAME, PerformanceRunner, RegexpOutputWriter, ReleaseScript, SemVersion, SemVersionRegex, SetupScriptKey, StandardOutputWriter, Tokens, UserInput, VERSION, chainAbortController, copyFile, defaultCanvasOptions, deletePath, getAllFiles, getDependencies, getFileSizeZipped, getPackage, getPackageDependencies, getPackageVersion, getSlogan, installDependencies, installIfNotAvailable, listFolder, listNodeModulesPackages, lockify, normalizeImport, packageToGlobal, parseList, patchFile, printBanner, pushToGit, readFile, renameFile, runCommand, setPackageAttribute, spawnCommand, updateDependencies, writeFile };
|
|
2602
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuanMiLCJzb3VyY2VzIjpbIi4uL3NyYy9pbnB1dC9pbnB1dC50cyIsIi4uL3NyYy9jbGkvY29uc3RhbnRzLnRzIiwiLi4vc3JjL3V0aWxzL2NvbnN0YW50cy50cyIsIi4uL3NyYy93cml0ZXJzL1N0YW5kYXJkT3V0cHV0V3JpdGVyLnRzIiwiLi4vc3JjL3V0aWxzL3V0aWxzLnRzIiwiLi4vc3JjL3V0aWxzL2ZzLnRzIiwiLi4vc3JjL2Fzc2V0cy9zbG9nYW5zLnRzIiwiLi4vc3JjL291dHB1dC9jb21tb24udHMiLCIuLi9zcmMvY2xpL2NvbW1hbmQudHMiLCIuLi9zcmMvdXRpbHMvaHR0cC50cyIsIi4uL3NyYy91dGlscy9wZXJmb3JtYW5jZVJ1bm5lci50cyIsIi4uL3NyYy9jbGkvY29tbWFuZHMvYnVpbGQtc2NyaXB0cy50cyIsIi4uL3NyYy9jbGkvY29tbWFuZHMvdGFnLXJlbGVhc2UudHMiLCIuLi9zcmMvd3JpdGVycy9SZWdleHBPdXRwdXRXcml0ZXIudHMiLCIuLi9zcmMvaW5kZXgudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgQW5zd2VycyxcbiAgQ2hvaWNlLFxuICBGYWxzeSxcbiAgSW5pdGlhbFJldHVyblZhbHVlLFxuICBQcmV2Q2FsbGVyLFxuICBQcm9tcHRPYmplY3QsXG4gIFByb21wdFR5cGUsXG4gIFZhbHVlT3JGdW5jLFxufSBmcm9tIFwicHJvbXB0c1wiO1xuaW1wb3J0IHByb21wdHMgZnJvbSBcInByb21wdHNcIjtcbmltcG9ydCB7IHBhcnNlQXJncywgUGFyc2VBcmdzQ29uZmlnIH0gZnJvbSBcInV0aWxcIjtcbmltcG9ydCB7IFdyaXRhYmxlLCBSZWFkYWJsZSB9IGZyb20gXCJzdHJlYW1cIjtcbmltcG9ydCB7IFBhcnNlQXJnc09wdGlvbnNDb25maWcsIFBhcnNlQXJnc1Jlc3VsdCB9IGZyb20gXCIuL3R5cGVzXCI7XG5pbXBvcnQgeyBMb2dnaW5nIH0gZnJvbSBcIkBkZWNhZi10cy9sb2dnaW5nXCI7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIFJlcHJlc2VudHMgYSB1c2VyIGlucHV0IHByb21wdCB3aXRoIHZhcmlvdXMgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICogQHN1bW1hcnkgVGhpcyBjbGFzcyBwcm92aWRlcyBhIGZsZXhpYmxlIGludGVyZmFjZSBmb3IgY3JlYXRpbmcgYW5kIG1hbmFnaW5nIHVzZXIgaW5wdXQgcHJvbXB0cy5cbiAqIEl0IGltcGxlbWVudHMgdGhlIFByb21wdE9iamVjdCBpbnRlcmZhY2UgZnJvbSB0aGUgJ3Byb21wdHMnIGxpYnJhcnkgYW5kIG9mZmVycyBtZXRob2RzIHRvIHNldFxuICogdmFyaW91cyBwcm9wZXJ0aWVzIG9mIHRoZSBwcm9tcHQuIFRoZSBjbGFzcyBhbHNvIGluY2x1ZGVzIHN0YXRpYyBtZXRob2RzIGZvciBjb21tb24gaW5wdXQgc2NlbmFyaW9zXG4gKiBhbmQgYXJndW1lbnQgcGFyc2luZy5cbiAqXG4gKiBAdGVtcGxhdGUgUiAtIFRoZSB0eXBlIG9mIHRoZSBwcm9tcHQgbmFtZSwgZXh0ZW5kaW5nIHN0cmluZy5cbiAqXG4gKiBAcGFyYW0gbmFtZSAtIFRoZSBuYW1lIG9mIHRoZSBwcm9tcHQsIHVzZWQgYXMgdGhlIGtleSBpbiB0aGUgcmV0dXJuZWQgYW5zd2VycyBvYmplY3QuXG4gKlxuICogQGNsYXNzXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogaW1wb3J0IHsgVXNlcklucHV0IH0gZnJvbSAnQGRlY2FmLXRzL3V0aWxzJztcbiAqXG4gKiAvLyBDcmVhdGUgYSBzaW1wbGUgdGV4dCBpbnB1dFxuICogY29uc3QgbmFtZUlucHV0ID0gbmV3IFVzZXJJbnB1dCgnbmFtZScpXG4gKiAgIC5zZXRNZXNzYWdlKCdXaGF0IGlzIHlvdXIgbmFtZT8nKVxuICogICAuc2V0SW5pdGlhbCgnVXNlcicpO1xuICpcbiAqIC8vIENyZWF0ZSBhIG51bWJlciBpbnB1dCB3aXRoIHZhbGlkYXRpb25cbiAqIGNvbnN0IGFnZUlucHV0ID0gbmV3IFVzZXJJbnB1dCgnYWdlJylcbiAqICAgLnNldFR5cGUoJ251bWJlcicpXG4gKiAgIC5zZXRNZXNzYWdlKCdIb3cgb2xkIGFyZSB5b3U/JylcbiAqICAgLnNldE1pbigwKVxuICogICAuc2V0TWF4KDEyMCk7XG4gKlxuICogLy8gQXNrIGZvciBpbnB1dCBhbmQgcHJvY2VzcyB0aGUgcmVzdWx0c1xuICogYXN5bmMgZnVuY3Rpb24gZ2V0VXNlckluZm8oKSB7XG4gKiAgIGNvbnN0IGFuc3dlcnMgPSBhd2FpdCBVc2VySW5wdXQuYXNrKFtuYW1lSW5wdXQsIGFnZUlucHV0XSk7XG4gKiAgIGNvbnNvbGUubG9nKGBIZWxsbyAke2Fuc3dlcnMubmFtZX0sIHlvdSBhcmUgJHthbnN3ZXJzLmFnZX0geWVhcnMgb2xkLmApO1xuICogfVxuICpcbiAqIGdldFVzZXJJbmZvKCk7XG4gKiBgYGBcbiAqXG4gKiBAbWVybWFpZFxuICogc2VxdWVuY2VEaWFncmFtXG4gKiAgIHBhcnRpY2lwYW50IENsaWVudFxuICogICBwYXJ0aWNpcGFudCBVc2VySW5wdXRcbiAqICAgcGFydGljaXBhbnQgUHJvbXB0TGlicmFyeVxuICpcbiAqICAgQ2xpZW50LT4+VXNlcklucHV0OiBuZXcgVXNlcklucHV0KG5hbWUpXG4gKiAgIENsaWVudC0+PlVzZXJJbnB1dDogc2V0TWVzc2FnZShtZXNzYWdlKVxuICogICBDbGllbnQtPj5Vc2VySW5wdXQ6IHNldFR5cGUodHlwZSlcbiAqICAgQ2xpZW50LT4+VXNlcklucHV0OiBzZXRJbml0aWFsKGluaXRpYWwpXG4gKiAgIENsaWVudC0+PlVzZXJJbnB1dDogT3RoZXIgY29uZmlndXJhdGlvbiBtZXRob2RzXG4gKlxuICogICBDbGllbnQtPj5Vc2VySW5wdXQ6IGFzaygpXG4gKiAgIFVzZXJJbnB1dC0+PlByb21wdExpYnJhcnk6IHByb21wdHMocXVlc3Rpb24pXG4gKiAgIFByb21wdExpYnJhcnktPj5DbGllbnQ6IERpc3BsYXkgcHJvbXB0XG4gKiAgIENsaWVudC0+PlByb21wdExpYnJhcnk6IFVzZXIgcHJvdmlkZXMgaW5wdXRcbiAqICAgUHJvbXB0TGlicmFyeS0+PlVzZXJJbnB1dDogUmV0dXJuIGFuc3dlcnNcbiAqICAgVXNlcklucHV0LT4+Q2xpZW50OiBSZXR1cm4gcHJvY2Vzc2VkIGFuc3dlcnNcbiAqL1xuZXhwb3J0IGNsYXNzIFVzZXJJbnB1dDxSIGV4dGVuZHMgc3RyaW5nID0gc3RyaW5nPiBpbXBsZW1lbnRzIFByb21wdE9iamVjdDxSPiB7XG4gIHByaXZhdGUgc3RhdGljIHJlYWRvbmx5IGxvZ2dlciA9IExvZ2dpbmcuZm9yKFVzZXJJbnB1dCk7XG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gVGhlIHR5cGUgb2YgdGhlIHByb21wdC5cbiAgICogQHN1bW1hcnkgRGV0ZXJtaW5lcyB0aGUgaW5wdXQgbWV0aG9kIChlLmcuLCB0ZXh0LCBudW1iZXIsIGNvbmZpcm0pLlxuICAgKi9cbiAgdHlwZTogUHJvbXB0VHlwZSB8IEZhbHN5IHwgUHJldkNhbGxlcjxSLCBQcm9tcHRUeXBlIHwgRmFsc3k+ID0gXCJ0ZXh0XCI7XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBUaGUgbmFtZSBvZiB0aGUgcHJvbXB0LlxuICAgKiBAc3VtbWFyeSBVc2VkIGFzIHRoZSBrZXkgaW4gdGhlIHJldHVybmVkIGFuc3dlcnMgb2JqZWN0LlxuICAgKi9cbiAgbmFtZTogVmFsdWVPckZ1bmM8Uj47XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBUaGUgbWVzc2FnZSBkaXNwbGF5ZWQgdG8gdGhlIHVzZXIuXG4gICAqIEBzdW1tYXJ5IFRoZSBxdWVzdGlvbiBvciBpbnN0cnVjdGlvbiBwcmVzZW50ZWQgdG8gdGhlIHVzZXIuXG4gICAqL1xuICBtZXNzYWdlPzogVmFsdWVPckZ1bmM8c3RyaW5nPiB8IHVuZGVmaW5lZDtcblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFRoZSBpbml0aWFsIHZhbHVlIG9mIHRoZSBwcm9tcHQuXG4gICAqIEBzdW1tYXJ5IFRoZSBkZWZhdWx0IHZhbHVlIHByZXNlbnRlZCB0byB0aGUgdXNlci5cbiAgICovXG4gIGluaXRpYWw/OlxuICAgIHwgSW5pdGlhbFJldHVyblZhbHVlXG4gICAgfCBQcmV2Q2FsbGVyPFIsIEluaXRpYWxSZXR1cm5WYWx1ZSB8IFByb21pc2U8SW5pdGlhbFJldHVyblZhbHVlPj5cbiAgICB8IHVuZGVmaW5lZDtcblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFRoZSBzdHlsZSBvZiB0aGUgcHJvbXB0LlxuICAgKiBAc3VtbWFyeSBEZXRlcm1pbmVzIHRoZSB2aXN1YWwgc3R5bGUgb2YgdGhlIHByb21wdC5cbiAgICovXG4gIHN0eWxlPzogc3RyaW5nIHwgUHJldkNhbGxlcjxSLCBzdHJpbmcgfCBGYWxzeT4gfCB1bmRlZmluZWQ7XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBUaGUgZm9ybWF0IGZ1bmN0aW9uIGZvciB0aGUgaW5wdXQuXG4gICAqIEBzdW1tYXJ5IEEgZnVuY3Rpb24gdG8gZm9ybWF0IHRoZSB1c2VyJ3MgaW5wdXQgYmVmb3JlIGl0J3MgcmV0dXJuZWQuXG4gICAqL1xuICBmb3JtYXQ/OiBQcmV2Q2FsbGVyPFIsIHZvaWQ+IHwgdW5kZWZpbmVkO1xuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gVGhlIHZhbGlkYXRpb24gZnVuY3Rpb24gZm9yIHRoZSBpbnB1dC5cbiAgICogQHN1bW1hcnkgQSBmdW5jdGlvbiB0byB2YWxpZGF0ZSB0aGUgdXNlcidzIGlucHV0LlxuICAgKi9cbiAgdmFsaWRhdGU/OlxuICAgIHwgUHJldkNhbGxlcjxSLCBib29sZWFuIHwgc3RyaW5nIHwgUHJvbWlzZTxib29sZWFuIHwgc3RyaW5nPj5cbiAgICB8IHVuZGVmaW5lZDtcblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFRoZSBvblN0YXRlIGNhbGxiYWNrIGZ1bmN0aW9uLlxuICAgKiBAc3VtbWFyeSBBIGZ1bmN0aW9uIGNhbGxlZCB3aGVuIHRoZSBzdGF0ZSBvZiB0aGUgcHJvbXB0IGNoYW5nZXMuXG4gICAqL1xuICBvblN0YXRlPzogUHJldkNhbGxlcjxSLCB2b2lkPiB8IHVuZGVmaW5lZDtcblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFRoZSBtaW5pbXVtIHZhbHVlIGZvciBudW1iZXIgaW5wdXRzLlxuICAgKiBAc3VtbWFyeSBUaGUgbG93ZXN0IG51bWJlciB0aGUgdXNlciBjYW4gaW5wdXQuXG4gICAqL1xuICBtaW4/OiBudW1iZXIgfCBQcmV2Q2FsbGVyPFIsIG51bWJlciB8IEZhbHN5PiB8IHVuZGVmaW5lZDtcblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFRoZSBtYXhpbXVtIHZhbHVlIGZvciBudW1iZXIgaW5wdXRzLlxuICAgKiBAc3VtbWFyeSBUaGUgaGlnaGVzdCBudW1iZXIgdGhlIHVzZXIgY2FuIGlucHV0LlxuICAgKi9cbiAgbWF4PzogbnVtYmVyIHwgUHJldkNhbGxlcjxSLCBudW1iZXIgfCBGYWxzeT4gfCB1bmRlZmluZWQ7XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBXaGV0aGVyIHRvIGFsbG93IGZsb2F0IHZhbHVlcyBmb3IgbnVtYmVyIGlucHV0cy5cbiAgICogQHN1bW1hcnkgSWYgdHJ1ZSwgYWxsb3dzIGRlY2ltYWwgbnVtYmVycy5cbiAgICovXG4gIGZsb2F0PzogYm9vbGVhbiB8IFByZXZDYWxsZXI8UiwgYm9vbGVhbiB8IEZhbHN5PiB8IHVuZGVmaW5lZDtcblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFRoZSBudW1iZXIgb2YgZGVjaW1hbCBwbGFjZXMgdG8gcm91bmQgdG8gZm9yIGZsb2F0IGlucHV0cy5cbiAgICogQHN1bW1hcnkgRGV0ZXJtaW5lcyB0aGUgcHJlY2lzaW9uIG9mIGZsb2F0IGlucHV0cy5cbiAgICovXG4gIHJvdW5kPzogbnVtYmVyIHwgUHJldkNhbGxlcjxSLCBudW1iZXIgfCBGYWxzeT4gfCB1bmRlZmluZWQ7XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBJbnN0cnVjdGlvbnMgZm9yIHRoZSB1c2VyLlxuICAgKiBAc3VtbWFyeSBBZGRpdGlvbmFsIGd1aWRhbmNlIHByb3ZpZGVkIHRvIHRoZSB1c2VyLlxuICAgKi9cbiAgaW5zdHJ1Y3Rpb25zPzogc3RyaW5nIHwgYm9vbGVhbiB8IHVuZGVmaW5lZDtcblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFRoZSBpbmNyZW1lbnQgdmFsdWUgZm9yIG51bWJlciBpbnB1dHMuXG4gICAqIEBzdW1tYXJ5IFRoZSBzdGVwIHNpemUgd2hlbiBpbmNyZWFzaW5nIG9yIGRlY3JlYXNpbmcgdGhlIG51bWJlci5cbiAgICovXG4gIGluY3JlbWVudD86IG51bWJlciB8IFByZXZDYWxsZXI8UiwgbnVtYmVyIHwgRmFsc3k+IHwgdW5kZWZpbmVkO1xuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gVGhlIHNlcGFyYXRvciBmb3IgbGlzdCBpbnB1dHMuXG4gICAqIEBzdW1tYXJ5IFRoZSBjaGFyYWN0ZXIgdXNlZCB0byBzZXBhcmF0ZSBsaXN0IGl0ZW1zLlxuICAgKi9cbiAgc2VwYXJhdG9yPzogc3RyaW5nIHwgUHJldkNhbGxlcjxSLCBzdHJpbmcgfCBGYWxzeT4gfCB1bmRlZmluZWQ7XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBUaGUgYWN0aXZlIG9wdGlvbiBzdHlsZSBmb3Igc2VsZWN0IGlucHV0cy5cbiAgICogQHN1bW1hcnkgVGhlIHN0eWxlIGFwcGxpZWQgdG8gdGhlIGN1cnJlbnRseSBzZWxlY3RlZCBvcHRpb24uXG4gICAqL1xuICBhY3RpdmU/OiBzdHJpbmcgfCBQcmV2Q2FsbGVyPFIsIHN0cmluZyB8IEZhbHN5PiB8IHVuZGVmaW5lZDtcblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFRoZSBpbmFjdGl2ZSBvcHRpb24gc3R5bGUgZm9yIHNlbGVjdCBpbnB1dHMuXG4gICAqIEBzdW1tYXJ5IFRoZSBzdHlsZSBhcHBsaWVkIHRvIG5vbi1zZWxlY3RlZCBvcHRpb25zLlxuICAgKi9cbiAgaW5hY3RpdmU/OiBzdHJpbmcgfCBQcmV2Q2FsbGVyPFIsIHN0cmluZyB8IEZhbHN5PiB8IHVuZGVmaW5lZDtcblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFRoZSBhdmFpbGFibGUgY2hvaWNlcyBmb3Igc2VsZWN0LCBtdWx0aXNlbGVjdCwgb3IgYXV0b2NvbXBsZXRlIGlucHV0cy5cbiAgICogQHN1bW1hcnkgQW4gYXJyYXkgb2Ygb3B0aW9ucyB0aGF0IHRoZSB1c2VyIGNhbiBzZWxlY3QgZnJvbSBpbiBjaG9pY2UtYmFzZWQgcHJvbXB0cy5cbiAgICovXG4gIGNob2ljZXM/OiBDaG9pY2VbXSB8IFByZXZDYWxsZXI8UiwgQ2hvaWNlW10gfCBGYWxzeT4gfCB1bmRlZmluZWQ7XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBUaGUgaGludCB0ZXh0IGZvciB0aGUgcHJvbXB0LlxuICAgKiBAc3VtbWFyeSBBZGRpdGlvbmFsIGluZm9ybWF0aW9uIGRpc3BsYXllZCB0byB0aGUgdXNlci5cbiAgICovXG4gIGhpbnQ/OiBzdHJpbmcgfCBQcmV2Q2FsbGVyPFIsIHN0cmluZyB8IEZhbHN5PiB8IHVuZGVmaW5lZDtcblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFRoZSB3YXJuaW5nIHRleHQgZm9yIHRoZSBwcm9tcHQuXG4gICAqIEBzdW1tYXJ5IEEgd2FybmluZyBtZXNzYWdlIGRpc3BsYXllZCB0byB0aGUgdXNlci5cbiAgICovXG4gIHdhcm4/OiBzdHJpbmcgfCBQcmV2Q2FsbGVyPFIsIHN0cmluZyB8IEZhbHN5PiB8IHVuZGVmaW5lZDtcblxuICBzdWdnZXN0PzogKChpbnB1dDogYW55LCBjaG9pY2VzOiBDaG9pY2VbXSkgPT4gUHJvbWlzZTxhbnk+KSB8IHVuZGVmaW5lZDtcblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFRoZSBsaW1pdCBmb3IgbGlzdCBpbnB1dHMuXG4gICAqIEBzdW1tYXJ5IFRoZSBtYXhpbXVtIG51bWJlciBvZiBpdGVtcyB0aGF0IGNhbiBiZSBzZWxlY3RlZC5cbiAgICovXG4gIGxpbWl0PzogbnVtYmVyIHwgUHJldkNhbGxlcjxSLCBudW1iZXIgfCBGYWxzeT4gfCB1bmRlZmluZWQ7XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBUaGUgbWFzayBmb3IgcGFzc3dvcmQgaW5wdXRzLlxuICAgKiBAc3VtbWFyeSBUaGUgY2hhcmFjdGVyIHVzZWQgdG8gaGlkZSB0aGUgdXNlcidzIGlucHV0LlxuICAgKi9cbiAgbWFzaz86IHN0cmluZyB8IFByZXZDYWxsZXI8Uiwgc3RyaW5nIHwgRmFsc3k+IHwgdW5kZWZpbmVkO1xuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gVGhlIHN0ZG91dCBzdHJlYW0gZm9yIHRoZSBwcm9tcHQuXG4gICAqIEBzdW1tYXJ5IFRoZSBvdXRwdXQgc3RyZWFtIHVzZWQgYnkgdGhlIHByb21wdC5cbiAgICovXG4gIHN0ZG91dD86IFdyaXRhYmxlIHwgdW5kZWZpbmVkO1xuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gVGhlIHN0ZGluIHN0cmVhbSBmb3IgdGhlIHByb21wdC5cbiAgICogQHN1bW1hcnkgVGhlIGlucHV0IHN0cmVhbSB1c2VkIGJ5IHRoZSBwcm9tcHQuXG4gICAqL1xuICBzdGRpbj86IFJlYWRhYmxlIHwgdW5kZWZpbmVkO1xuXG4gIGNvbnN0cnVjdG9yKG5hbWU6IFZhbHVlT3JGdW5jPFI+KSB7XG4gICAgdGhpcy5uYW1lID0gbmFtZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gU2V0cyB0aGUgdHlwZSBvZiB0aGUgcHJvbXB0LlxuICAgKiBAc3VtbWFyeSBDb25maWd1cmVzIHRoZSBpbnB1dCBtZXRob2QgZm9yIHRoZSBwcm9tcHQuXG4gICAqXG4gICAqIEBwYXJhbSB0eXBlIC0gVGhlIHR5cGUgb2YgdGhlIHByb21wdC5cbiAgICogQHJldHVybnMgVGhpcyBVc2VySW5wdXQgaW5zdGFuY2UgZm9yIG1ldGhvZCBjaGFpbmluZy5cbiAgICovXG4gIHNldFR5cGUodHlwZTogUHJvbXB0VHlwZSB8IEZhbHN5IHwgUHJldkNhbGxlcjxSLCBQcm9tcHRUeXBlIHwgRmFsc3k+KTogdGhpcyB7XG4gICAgVXNlcklucHV0LmxvZ2dlci52ZXJib3NlKGBTZXR0aW5nIHR5cGUgdG86ICR7dHlwZX1gKTtcbiAgICB0aGlzLnR5cGUgPSB0eXBlO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBTZXRzIHRoZSBtZXNzYWdlIG9mIHRoZSBwcm9tcHQuXG4gICAqIEBzdW1tYXJ5IENvbmZpZ3VyZXMgdGhlIHF1ZXN0aW9uIG9yIGluc3RydWN0aW9uIHByZXNlbnRlZCB0byB0aGUgdXNlci5cbiAgICpcbiAgICogQHBhcmFtIHZhbHVlIC0gVGhlIG1lc3NhZ2UgdG8gYmUgZGlzcGxheWVkLlxuICAgKiBAcmV0dXJucyBUaGlzIFVzZXJJbnB1dCBpbnN0YW5jZSBmb3IgbWV0aG9kIGNoYWluaW5nLlxuICAgKi9cbiAgc2V0TWVzc2FnZSh2YWx1ZTogVmFsdWVPckZ1bmM8c3RyaW5nPiB8IHVuZGVmaW5lZCk6IHRoaXMge1xuICAgIFVzZXJJbnB1dC5sb2dnZXIudmVyYm9zZShgU2V0dGluZyBtZXNzYWdlIHRvOiAke3ZhbHVlfWApO1xuICAgIHRoaXMubWVzc2FnZSA9IHZhbHVlO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBTZXRzIHRoZSBpbml0aWFsIHZhbHVlIG9mIHRoZSBwcm9tcHQuXG4gICAqIEBzdW1tYXJ5IENvbmZpZ3VyZXMgdGhlIGRlZmF1bHQgdmFsdWUgcHJlc2VudGVkIHRvIHRoZSB1c2VyLlxuICAgKlxuICAgKiBAcGFyYW0gdmFsdWUgLSBUaGUgaW5pdGlhbCB2YWx1ZS5cbiAgICogQHJldHVybnMgVGhpcyBVc2VySW5wdXQgaW5zdGFuY2UgZm9yIG1ldGhvZCBjaGFpbmluZy5cbiAgICovXG4gIHNldEluaXRpYWwoXG4gICAgdmFsdWU6XG4gICAgICB8IEluaXRpYWxSZXR1cm5WYWx1ZVxuICAgICAgfCBQcmV2Q2FsbGVyPFIsIEluaXRpYWxSZXR1cm5WYWx1ZSB8IFByb21pc2U8SW5pdGlhbFJldHVyblZhbHVlPj5cbiAgICAgIHwgdW5kZWZpbmVkXG4gICk6IHRoaXMge1xuICAgIFVzZXJJbnB1dC5sb2dnZXIudmVyYm9zZShgU2V0dGluZyBpbml0aWFsIHZhbHVlIHRvOiAke3ZhbHVlfWApO1xuICAgIHRoaXMuaW5pdGlhbCA9IHZhbHVlO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBTZXRzIHRoZSBzdHlsZSBvZiB0aGUgcHJvbXB0LlxuICAgKiBAc3VtbWFyeSBDb25maWd1cmVzIHRoZSB2aXN1YWwgc3R5bGUgb2YgdGhlIHByb21wdC5cbiAgICpcbiAgICogQHBhcmFtIHZhbHVlIC0gVGhlIHN0eWxlIHRvIGJlIGFwcGxpZWQuXG4gICAqIEByZXR1cm5zIFRoaXMgVXNlcklucHV0IGluc3RhbmNlIGZvciBtZXRob2QgY2hhaW5pbmcuXG4gICAqL1xuICBzZXRTdHlsZSh2YWx1ZTogc3RyaW5nIHwgUHJldkNhbGxlcjxSLCBzdHJpbmcgfCBGYWxzeT4gfCB1bmRlZmluZWQpOiB0aGlzIHtcbiAgICBVc2VySW5wdXQubG9nZ2VyLnZlcmJvc2UoYFNldHRpbmcgc3R5bGUgdG86ICR7dmFsdWV9YCk7XG4gICAgdGhpcy5zdHlsZSA9IHZhbHVlO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBTZXRzIHRoZSBmb3JtYXQgZnVuY3Rpb24gb2YgdGhlIHByb21wdC5cbiAgICogQHN1bW1hcnkgQ29uZmlndXJlcyBhIGZ1bmN0aW9uIHRvIGZvcm1hdCB0aGUgdXNlcidzIGlucHV0IGJlZm9yZSBpdCdzIHJldHVybmVkLlxuICAgKlxuICAgKiBAcGFyYW0gdmFsdWUgLSBUaGUgZm9ybWF0IGZ1bmN0aW9uLlxuICAgKiBAcmV0dXJucyBUaGlzIFVzZXJJbnB1dCBpbnN0YW5jZSBmb3IgbWV0aG9kIGNoYWluaW5nLlxuICAgKi9cbiAgc2V0Rm9ybWF0KHZhbHVlOiBQcmV2Q2FsbGVyPFIsIHZvaWQ+IHwgdW5kZWZpbmVkKTogdGhpcyB7XG4gICAgVXNlcklucHV0LmxvZ2dlci52ZXJib3NlKGBTZXR0aW5nIGZvcm1hdCBmdW5jdGlvbmApO1xuICAgIHRoaXMuZm9ybWF0ID0gdmFsdWU7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFNldHMgdGhlIHZhbGlkYXRpb24gZnVuY3Rpb24gb2YgdGhlIHByb21wdC5cbiAgICogQHN1bW1hcnkgQ29uZmlndXJlcyBhIGZ1bmN0aW9uIHRvIHZhbGlkYXRlIHRoZSB1c2VyJ3MgaW5wdXQuXG4gICAqXG4gICAqIEBwYXJhbSB2YWx1ZSAtIFRoZSB2YWxpZGF0aW9uIGZ1bmN0aW9uLlxuICAgKiBAcmV0dXJucyBUaGlzIFVzZXJJbnB1dCBpbnN0YW5jZSBmb3IgbWV0aG9kIGNoYWluaW5nLlxuICAgKi9cbiAgc2V0VmFsaWRhdGUoXG4gICAgdmFsdWU6XG4gICAgICB8IFByZXZDYWxsZXI8UiwgYm9vbGVhbiB8IHN0cmluZyB8IFByb21pc2U8Ym9vbGVhbiB8IHN0cmluZz4+XG4gICAgICB8IHVuZGVmaW5lZFxuICApOiB0aGlzIHtcbiAgICBVc2VySW5wdXQubG9nZ2VyLnZlcmJvc2UoYFNldHRpbmcgdmFsaWRhdGUgZnVuY3Rpb25gKTtcbiAgICB0aGlzLnZhbGlkYXRlID0gdmFsdWU7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFNldHMgdGhlIG9uU3RhdGUgY2FsbGJhY2sgb2YgdGhlIHByb21wdC5cbiAgICogQHN1bW1hcnkgQ29uZmlndXJlcyBhIGZ1bmN0aW9uIHRvIGJlIGNhbGxlZCB3aGVuIHRoZSBzdGF0ZSBvZiB0aGUgcHJvbXB0IGNoYW5nZXMuXG4gICAqXG4gICAqIEBwYXJhbSB2YWx1ZSAtIFRoZSBvblN0YXRlIGNhbGxiYWNrIGZ1bmN0aW9uLlxuICAgKiBAcmV0dXJucyBUaGlzIFVzZXJJbnB1dCBpbnN0YW5jZSBmb3IgbWV0aG9kIGNoYWluaW5nLlxuICAgKi9cbiAgc2V0T25TdGF0ZSh2YWx1ZTogUHJldkNhbGxlcjxSLCB2b2lkPiB8IHVuZGVmaW5lZCk6IHRoaXMge1xuICAgIFVzZXJJbnB1dC5sb2dnZXIudmVyYm9zZShgU2V0dGluZyBvblN0YXRlIGNhbGxiYWNrYCk7XG4gICAgdGhpcy5vblN0YXRlID0gdmFsdWU7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFNldHMgdGhlIG1pbmltdW0gdmFsdWUgZm9yIG51bWJlciBpbnB1dHMuXG4gICAqIEBzdW1tYXJ5IENvbmZpZ3VyZXMgdGhlIGxvd2VzdCBudW1iZXIgdGhlIHVzZXIgY2FuIGlucHV0LlxuICAgKlxuICAgKiBAcGFyYW0gdmFsdWUgLSBUaGUgbWluaW11bSB2YWx1ZS5cbiAgICogQHJldHVybnMgVGhpcyBVc2VySW5wdXQgaW5zdGFuY2UgZm9yIG1ldGhvZCBjaGFpbmluZy5cbiAgICovXG4gIHNldE1pbih2YWx1ZTogbnVtYmVyIHwgUHJldkNhbGxlcjxSLCBudW1iZXIgfCBGYWxzeT4gfCB1bmRlZmluZWQpOiB0aGlzIHtcbiAgICBVc2VySW5wdXQubG9nZ2VyLnZlcmJvc2UoYFNldHRpbmcgbWluIHZhbHVlIHRvOiAke3ZhbHVlfWApO1xuICAgIHRoaXMubWluID0gdmFsdWU7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFNldHMgdGhlIG1heGltdW0gdmFsdWUgZm9yIG51bWJlciBpbnB1dHMuXG4gICAqIEBzdW1tYXJ5IENvbmZpZ3VyZXMgdGhlIGhpZ2hlc3QgbnVtYmVyIHRoZSB1c2VyIGNhbiBpbnB1dC5cbiAgICpcbiAgICogQHBhcmFtIHZhbHVlIC0gVGhlIG1heGltdW0gdmFsdWUuXG4gICAqIEByZXR1cm5zIFRoaXMgVXNlcklucHV0IGluc3RhbmNlIGZvciBtZXRob2QgY2hhaW5pbmcuXG4gICAqL1xuICBzZXRNYXgodmFsdWU6IG51bWJlciB8IFByZXZDYWxsZXI8UiwgbnVtYmVyIHwgRmFsc3k+IHwgdW5kZWZpbmVkKTogdGhpcyB7XG4gICAgVXNlcklucHV0LmxvZ2dlci52ZXJib3NlKGBTZXR0aW5nIG1heCB2YWx1ZSB0bzogJHt2YWx1ZX1gKTtcbiAgICB0aGlzLm1heCA9IHZhbHVlO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBTZXRzIHdoZXRoZXIgdG8gYWxsb3cgZmxvYXQgdmFsdWVzIGZvciBudW1iZXIgaW5wdXRzLlxuICAgKiBAc3VtbWFyeSBDb25maWd1cmVzIHdoZXRoZXIgZGVjaW1hbCBudW1iZXJzIGFyZSBhbGxvd2VkLlxuICAgKlxuICAgKiBAcGFyYW0gdmFsdWUgLSBXaGV0aGVyIHRvIGFsbG93IGZsb2F0IHZhbHVlcy5cbiAgICogQHJldHVybnMgVGhpcyBVc2VySW5wdXQgaW5zdGFuY2UgZm9yIG1ldGhvZCBjaGFpbmluZy5cbiAgICovXG4gIHNldEZsb2F0KHZhbHVlOiBib29sZWFuIHwgUHJldkNhbGxlcjxSLCBib29sZWFuIHwgRmFsc3k+IHwgdW5kZWZpbmVkKTogdGhpcyB7XG4gICAgVXNlcklucHV0LmxvZ2dlci52ZXJib3NlKGBTZXR0aW5nIGZsb2F0IHRvOiAke3ZhbHVlfWApO1xuICAgIHRoaXMuZmxvYXQgPSB2YWx1ZTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gU2V0cyB0aGUgbnVtYmVyIG9mIGRlY2ltYWwgcGxhY2VzIHRvIHJvdW5kIHRvIGZvciBmbG9hdCBpbnB1dHMuXG4gICAqIEBzdW1tYXJ5IENvbmZpZ3VyZXMgdGhlIHByZWNpc2lvbiBvZiBmbG9hdCBpbnB1dHMuXG4gICAqXG4gICAqIEBwYXJhbSB2YWx1ZSAtIFRoZSBudW1iZXIgb2YgZGVjaW1hbCBwbGFjZXMuXG4gICAqIEByZXR1cm5zIFRoaXMgVXNlcklucHV0IGluc3RhbmNlIGZvciBtZXRob2QgY2hhaW5pbmcuXG4gICAqL1xuICBzZXRSb3VuZCh2YWx1ZTogbnVtYmVyIHwgUHJldkNhbGxlcjxSLCBudW1iZXIgfCBGYWxzeT4gfCB1bmRlZmluZWQpOiB0aGlzIHtcbiAgICBVc2VySW5wdXQubG9nZ2VyLnZlcmJvc2UoYFNldHRpbmcgcm91bmQgdG86ICR7dmFsdWV9YCk7XG4gICAgdGhpcy5yb3VuZCA9IHZhbHVlO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBTZXRzIHRoZSBpbnN0cnVjdGlvbnMgZm9yIHRoZSB1c2VyLlxuICAgKiBAc3VtbWFyeSBDb25maWd1cmVzIGFkZGl0aW9uYWwgZ3VpZGFuY2UgcHJvdmlkZWQgdG8gdGhlIHVzZXIuXG4gICAqXG4gICAqIEBwYXJhbSB2YWx1ZSAtIFRoZSBpbnN0cnVjdGlvbnMuXG4gICAqIEByZXR1cm5zIFRoaXMgVXNlcklucHV0IGluc3RhbmNlIGZvciBtZXRob2QgY2hhaW5pbmcuXG4gICAqL1xuICBzZXRJbnN0cnVjdGlvbnModmFsdWU6IHN0cmluZyB8IGJvb2xlYW4gfCB1bmRlZmluZWQpOiB0aGlzIHtcbiAgICBVc2VySW5wdXQubG9nZ2VyLnZlcmJvc2UoYFNldHRpbmcgaW5zdHJ1Y3Rpb25zIHRvOiAke3ZhbHVlfWApO1xuICAgIHRoaXMuaW5zdHJ1Y3Rpb25zID0gdmFsdWU7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFNldHMgdGhlIGluY3JlbWVudCB2YWx1ZSBmb3IgbnVtYmVyIGlucHV0cy5cbiAgICogQHN1bW1hcnkgQ29uZmlndXJlcyB0aGUgc3RlcCBzaXplIHdoZW4gaW5jcmVhc2luZyBvciBkZWNyZWFzaW5nIHRoZSBudW1iZXIuXG4gICAqXG4gICAqIEBwYXJhbSB2YWx1ZSAtIFRoZSBpbmNyZW1lbnQgdmFsdWUuXG4gICAqIEByZXR1cm5zIFRoaXMgVXNlcklucHV0IGluc3RhbmNlIGZvciBtZXRob2QgY2hhaW5pbmcuXG4gICAqL1xuICBzZXRJbmNyZW1lbnQoXG4gICAgdmFsdWU6IG51bWJlciB8IFByZXZDYWxsZXI8UiwgbnVtYmVyIHwgRmFsc3k+IHwgdW5kZWZpbmVkXG4gICk6IHRoaXMge1xuICAgIFVzZXJJbnB1dC5sb2dnZXIudmVyYm9zZShgU2V0dGluZyBpbmNyZW1lbnQgdG86ICR7dmFsdWV9YCk7XG4gICAgdGhpcy5pbmNyZW1lbnQgPSB2YWx1ZTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gU2V0cyB0aGUgc2VwYXJhdG9yIGZvciBsaXN0IGlucHV0cy5cbiAgICogQHN1bW1hcnkgQ29uZmlndXJlcyB0aGUgY2hhcmFjdGVyIHVzZWQgdG8gc2VwYXJhdGUgbGlzdCBpdGVtcy5cbiAgICpcbiAgICogQHBhcmFtIHZhbHVlIC0gVGhlIHNlcGFyYXRvciBjaGFyYWN0ZXIuXG4gICAqIEByZXR1cm5zIFRoaXMgVXNlcklucHV0IGluc3RhbmNlIGZvciBtZXRob2QgY2hhaW5pbmcuXG4gICAqL1xuICBzZXRTZXBhcmF0b3IoXG4gICAgdmFsdWU6IHN0cmluZyB8IFByZXZDYWxsZXI8Uiwgc3RyaW5nIHwgRmFsc3k+IHwgdW5kZWZpbmVkXG4gICk6IHRoaXMge1xuICAgIFVzZXJJbnB1dC5sb2dnZXIudmVyYm9zZShgU2V0dGluZyBzZXBhcmF0b3IgdG86ICR7dmFsdWV9YCk7XG4gICAgdGhpcy5zZXBhcmF0b3IgPSB2YWx1ZTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gU2V0cyB0aGUgYWN0aXZlIG9wdGlvbiBzdHlsZSBmb3Igc2VsZWN0IGlucHV0cy5cbiAgICogQHN1bW1hcnkgQ29uZmlndXJlcyB0aGUgc3R5bGUgYXBwbGllZCB0byB0aGUgY3VycmVudGx5IHNlbGVjdGVkIG9wdGlvbi5cbiAgICpcbiAgICogQHBhcmFtIHZhbHVlIC0gVGhlIGFjdGl2ZSBvcHRpb24gc3R5bGUuXG4gICAqIEByZXR1cm5zIFRoaXMgVXNlcklucHV0IGluc3RhbmNlIGZvciBtZXRob2QgY2hhaW5pbmcuXG4gICAqL1xuICBzZXRBY3RpdmUodmFsdWU6IHN0cmluZyB8IFByZXZDYWxsZXI8Uiwgc3RyaW5nIHwgRmFsc3k+IHwgdW5kZWZpbmVkKTogdGhpcyB7XG4gICAgVXNlcklucHV0LmxvZ2dlci52ZXJib3NlKGBTZXR0aW5nIGFjdGl2ZSBzdHlsZSB0bzogJHt2YWx1ZX1gKTtcbiAgICB0aGlzLmFjdGl2ZSA9IHZhbHVlO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBTZXRzIHRoZSBpbmFjdGl2ZSBvcHRpb24gc3R5bGUgZm9yIHNlbGVjdCBpbnB1dHMuXG4gICAqIEBzdW1tYXJ5IENvbmZpZ3VyZXMgdGhlIHN0eWxlIGFwcGxpZWQgdG8gbm9uLXNlbGVjdGVkIG9wdGlvbnMuXG4gICAqXG4gICAqIEBwYXJhbSB2YWx1ZSAtIFRoZSBpbmFjdGl2ZSBvcHRpb24gc3R5bGUuXG4gICAqIEByZXR1cm5zIFRoaXMgVXNlcklucHV0IGluc3RhbmNlIGZvciBtZXRob2QgY2hhaW5pbmcuXG4gICAqL1xuICBzZXRJbmFjdGl2ZSh2YWx1ZTogc3RyaW5nIHwgUHJldkNhbGxlcjxSLCBzdHJpbmcgfCBGYWxzeT4gfCB1bmRlZmluZWQpOiB0aGlzIHtcbiAgICBVc2VySW5wdXQubG9nZ2VyLnZlcmJvc2UoYFNldHRpbmcgaW5hY3RpdmUgc3R5bGUgdG86ICR7dmFsdWV9YCk7XG4gICAgdGhpcy5pbmFjdGl2ZSA9IHZhbHVlO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBTZXRzIHRoZSBjaG9pY2VzIGZvciBzZWxlY3QsIG11bHRpc2VsZWN0LCBvciBhdXRvY29tcGxldGUgaW5wdXRzLlxuICAgKiBAc3VtbWFyeSBDb25maWd1cmVzIHRoZSBhdmFpbGFibGUgb3B0aW9ucyB0aGF0IHRoZSB1c2VyIGNhbiBzZWxlY3QgZnJvbSBpbiBjaG9pY2UtYmFzZWQgcHJvbXB0cy5cbiAgICpcbiAgICogQHBhcmFtIHZhbHVlIC0gVGhlIGFycmF5IG9mIGNob2ljZXMgb3IgYSBmdW5jdGlvbiB0byBkZXRlcm1pbmUgdGhlIGNob2ljZXMuXG4gICAqIEByZXR1cm5zIFRoaXMgVXNlcklucHV0IGluc3RhbmNlIGZvciBtZXRob2QgY2hhaW5pbmcuXG4gICAqL1xuICBzZXRDaG9pY2VzKFxuICAgIHZhbHVlOiBDaG9pY2VbXSB8IFByZXZDYWxsZXI8UiwgQ2hvaWNlW10gfCBGYWxzeT4gfCB1bmRlZmluZWRcbiAgKTogdGhpcyB7XG4gICAgVXNlcklucHV0LmxvZ2dlci52ZXJib3NlKGBTZXR0aW5nIGNob2ljZXM6ICR7SlNPTi5zdHJpbmdpZnkodmFsdWUpfWApO1xuICAgIHRoaXMuY2hvaWNlcyA9IHZhbHVlO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBTZXRzIHRoZSBoaW50IHRleHQgZm9yIHRoZSBwcm9tcHQuXG4gICAqIEBzdW1tYXJ5IENvbmZpZ3VyZXMgYWRkaXRpb25hbCBpbmZvcm1hdGlvbiBkaXNwbGF5ZWQgdG8gdGhlIHVzZXIuXG4gICAqXG4gICAqIEBwYXJhbSB2YWx1ZSAtIFRoZSBoaW50IHRleHQuXG4gICAqIEByZXR1cm5zIFRoaXMgVXNlcklucHV0IGluc3RhbmNlIGZvciBtZXRob2QgY2hhaW5pbmcuXG4gICAqL1xuICBzZXRIaW50KHZhbHVlOiBzdHJpbmcgfCBQcmV2Q2FsbGVyPFIsIHN0cmluZyB8IEZhbHN5PiB8IHVuZGVmaW5lZCk6IHRoaXMge1xuICAgIFVzZXJJbnB1dC5sb2dnZXIudmVyYm9zZShgU2V0dGluZyBoaW50IHRvOiAke3ZhbHVlfWApO1xuICAgIHRoaXMuaGludCA9IHZhbHVlO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBTZXRzIHRoZSB3YXJuaW5nIHRleHQgZm9yIHRoZSBwcm9tcHQuXG4gICAqIEBzdW1tYXJ5IENvbmZpZ3VyZXMgYSB3YXJuaW5nIG1lc3NhZ2UgZGlzcGxheWVkIHRvIHRoZSB1c2VyLlxuICAgKlxuICAgKiBAcGFyYW0gdmFsdWUgLSBUaGUgd2FybmluZyB0ZXh0LlxuICAgKiBAcmV0dXJucyBUaGlzIFVzZXJJbnB1dCBpbnN0YW5jZSBmb3IgbWV0aG9kIGNoYWluaW5nLlxuICAgKi9cbiAgc2V0V2Fybih2YWx1ZTogc3RyaW5nIHwgUHJldkNhbGxlcjxSLCBzdHJpbmcgfCBGYWxzeT4gfCB1bmRlZmluZWQpOiB0aGlzIHtcbiAgICBVc2VySW5wdXQubG9nZ2VyLnZlcmJvc2UoYFNldHRpbmcgd2FybiB0bzogJHt2YWx1ZX1gKTtcbiAgICB0aGlzLndhcm4gPSB2YWx1ZTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gU2V0cyB0aGUgc3VnZ2VzdGlvbiBmdW5jdGlvbiBmb3IgYXV0b2NvbXBsZXRlIGlucHV0cy5cbiAgICogQHN1bW1hcnkgQ29uZmlndXJlcyBhIGZ1bmN0aW9uIHRoYXQgcHJvdmlkZXMgc3VnZ2VzdGlvbnMgYmFzZWQgb24gdGhlIHVzZXIncyBpbnB1dCBhbmQgYXZhaWxhYmxlIGNob2ljZXMuXG4gICAqXG4gICAqIEBwYXJhbSB2YWx1ZSAtIEEgZnVuY3Rpb24gdGhhdCB0YWtlcyB0aGUgY3VycmVudCBpbnB1dCBhbmQgYXZhaWxhYmxlIGNob2ljZXMgYW5kIHJldHVybnMgYSBQcm9taXNlIHJlc29sdmluZyB0byBzdWdnZXN0aW9ucy5cbiAgICogQHJldHVybnMgVGhpcyBVc2VySW5wdXQgaW5zdGFuY2UgZm9yIG1ldGhvZCBjaGFpbmluZy5cbiAgICovXG4gIHNldFN1Z2dlc3QoXG4gICAgdmFsdWU6ICgoaW5wdXQ6IGFueSwgY2hvaWNlczogQ2hvaWNlW10pID0+IFByb21pc2U8YW55PikgfCB1bmRlZmluZWRcbiAgKTogdGhpcyB7XG4gICAgVXNlcklucHV0LmxvZ2dlci52ZXJib3NlKGBTZXR0aW5nIHN1Z2dlc3QgZnVuY3Rpb25gKTtcbiAgICB0aGlzLnN1Z2dlc3QgPSB2YWx1ZTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gU2V0cyB0aGUgbGltaXQgZm9yIGxpc3QgaW5wdXRzLlxuICAgKiBAc3VtbWFyeSBDb25maWd1cmVzIHRoZSBtYXhpbXVtIG51bWJlciBvZiBpdGVtcyB0aGF0IGNhbiBiZSBzZWxlY3RlZCBpbiBsaXN0LXR5cGUgcHJvbXB0cy5cbiAgICogQHRlbXBsYXRlIFIgLSBUaGUgdHlwZSBvZiB0aGUgcHJvbXB0IG5hbWUsIGV4dGVuZGluZyBzdHJpbmcuXG4gICAqIEBwYXJhbSB2YWx1ZSAtIFRoZSBtYXhpbXVtIG51bWJlciBvZiBpdGVtcyB0aGF0IGNhbiBiZSBzZWxlY3RlZCwgb3IgYSBmdW5jdGlvbiB0byBkZXRlcm1pbmUgdGhpcyB2YWx1ZS5cbiAgICogQHJldHVybiBUaGlzIFVzZXJJbnB1dCBpbnN0YW5jZSBmb3IgbWV0aG9kIGNoYWluaW5nLlxuICAgKi9cbiAgc2V0TGltaXQodmFsdWU6IG51bWJlciB8IFByZXZDYWxsZXI8UiwgbnVtYmVyIHwgRmFsc3k+IHwgdW5kZWZpbmVkKTogdGhpcyB7XG4gICAgVXNlcklucHV0LmxvZ2dlci52ZXJib3NlKGBTZXR0aW5nIGxpbWl0IHRvOiAke3ZhbHVlfWApO1xuICAgIHRoaXMubGltaXQgPSB2YWx1ZTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gU2V0cyB0aGUgbWFzayBmb3IgcGFzc3dvcmQgaW5wdXRzLlxuICAgKiBAc3VtbWFyeSBDb25maWd1cmVzIHRoZSBjaGFyYWN0ZXIgdXNlZCB0byBoaWRlIHRoZSB1c2VyJ3MgaW5wdXQgaW4gcGFzc3dvcmQtdHlwZSBwcm9tcHRzLlxuICAgKiBAdGVtcGxhdGUgUiAtIFRoZSB0eXBlIG9mIHRoZSBwcm9tcHQgbmFtZSwgZXh0ZW5kaW5nIHN0cmluZy5cbiAgICogQHBhcmFtIHZhbHVlIC0gVGhlIGNoYXJhY3RlciB1c2VkIHRvIG1hc2sgdGhlIGlucHV0LCBvciBhIGZ1bmN0aW9uIHRvIGRldGVybWluZSB0aGlzIHZhbHVlLlxuICAgKiBAcmV0dXJuIFRoaXMgVXNlcklucHV0IGluc3RhbmNlIGZvciBtZXRob2QgY2hhaW5pbmcuXG4gICAqL1xuICBzZXRNYXNrKHZhbHVlOiBzdHJpbmcgfCBQcmV2Q2FsbGVyPFIsIHN0cmluZyB8IEZhbHN5PiB8IHVuZGVmaW5lZCk6IHRoaXMge1xuICAgIFVzZXJJbnB1dC5sb2dnZXIudmVyYm9zZShgU2V0dGluZyBtYXNrIHRvOiAke3ZhbHVlfWApO1xuICAgIHRoaXMubWFzayA9IHZhbHVlO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBTZXRzIHRoZSBzdGRvdXQgc3RyZWFtIGZvciB0aGUgcHJvbXB0LlxuICAgKiBAc3VtbWFyeSBDb25maWd1cmVzIHRoZSBvdXRwdXQgc3RyZWFtIHVzZWQgYnkgdGhlIHByb21wdCBmb3IgZGlzcGxheWluZyBtZXNzYWdlcyBhbmQgcmVzdWx0cy5cbiAgICogQHBhcmFtIHZhbHVlIC0gVGhlIFdyaXRhYmxlIHN0cmVhbSB0byBiZSB1c2VkIGFzIHN0ZG91dC5cbiAgICogQHJldHVybiBUaGlzIFVzZXJJbnB1dCBpbnN0YW5jZSBmb3IgbWV0aG9kIGNoYWluaW5nLlxuICAgKi9cbiAgc2V0U3Rkb3V0KHZhbHVlOiBXcml0YWJsZSB8IHVuZGVmaW5lZCk6IHRoaXMge1xuICAgIFVzZXJJbnB1dC5sb2dnZXIudmVyYm9zZShgU2V0dGluZyBzdGRvdXQgc3RyZWFtYCk7XG4gICAgdGhpcy5zdGRvdXQgPSB2YWx1ZTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFNldHMgdGhlIHN0ZGluIHN0cmVhbSBmb3IgdGhlIHByb21wdC5cbiAgICogQHN1bW1hcnkgQ29uZmlndXJlcyB0aGUgaW5wdXQgc3RyZWFtIHVzZWQgYnkgdGhlIHByb21wdCBmb3IgcmVjZWl2aW5nIHVzZXIgaW5wdXQuXG4gICAqIEBwYXJhbSB2YWx1ZSAtIFRoZSBSZWFkYWJsZSBzdHJlYW0gdG8gYmUgdXNlZCBhcyBzdGRpbi5cbiAgICogQHJldHVybiBUaGlzIFVzZXJJbnB1dCBpbnN0YW5jZSBmb3IgbWV0aG9kIGNoYWluaW5nLlxuICAgKi9cbiAgc2V0U3RkaW4odmFsdWU6IFJlYWRhYmxlIHwgdW5kZWZpbmVkKTogdGhpcyB7XG4gICAgdGhpcy5zdGRpbiA9IHZhbHVlO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBBc2tzIHRoZSB1c2VyIGZvciBpbnB1dCBiYXNlZCBvbiB0aGUgY3VycmVudCBVc2VySW5wdXQgY29uZmlndXJhdGlvbi5cbiAgICogQHN1bW1hcnkgUHJvbXB0cyB0aGUgdXNlciBhbmQgcmV0dXJucyB0aGVpciByZXNwb25zZSBhcyBhIHNpbmdsZSB2YWx1ZS5cbiAgICogQHRlbXBsYXRlIFIgLSBUaGUgdHlwZSBvZiB0aGUgcHJvbXB0IG5hbWUsIGV4dGVuZGluZyBzdHJpbmcuXG4gICAqIEByZXR1cm4gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIHVzZXIncyBhbnN3ZXIuXG4gICAqL1xuICBhc3luYyBhc2soKSB7XG4gICAgcmV0dXJuIChhd2FpdCBVc2VySW5wdXQuYXNrKHRoaXMpKVt0aGlzLm5hbWUgYXMga2V5b2YgQW5zd2VyczxSPl07XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEFza3MgdGhlIHVzZXIgb25lIG9yIG1vcmUgcXVlc3Rpb25zIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBVc2VySW5wdXQgY29uZmlndXJhdGlvbnMuXG4gICAqIEBzdW1tYXJ5IFByb21wdHMgdGhlIHVzZXIgd2l0aCBvbmUgb3IgbW9yZSBxdWVzdGlvbnMgYW5kIHJldHVybnMgdGhlaXIgYW5zd2VycyBhcyBhbiBvYmplY3QuXG4gICAqIEB0ZW1wbGF0ZSBSIC0gVGhlIHR5cGUgb2YgdGhlIHByb21wdCBuYW1lLCBleHRlbmRpbmcgc3RyaW5nLlxuICAgKiBAcGFyYW0gcXVlc3Rpb24gLSBBIHNpbmdsZSBVc2VySW5wdXQgaW5zdGFuY2Ugb3IgYW4gYXJyYXkgb2YgVXNlcklucHV0IGluc3RhbmNlcy5cbiAgICogQHJldHVybiBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byBhbiBvYmplY3QgY29udGFpbmluZyB0aGUgdXNlcidzIGFuc3dlcnMuXG4gICAqIEBtZXJtYWlkXG4gICAqIHNlcXVlbmNlRGlhZ3JhbVxuICAgKiAgIHBhcnRpY2lwYW50IFUgYXMgVXNlclxuICAgKiAgIHBhcnRpY2lwYW50IEEgYXMgYXNrIG1ldGhvZFxuICAgKiAgIHBhcnRpY2lwYW50IFAgYXMgcHJvbXB0cyBsaWJyYXJ5XG4gICAqICAgQS0+PlA6IENhbGwgcHJvbXB0cyB3aXRoIHF1ZXN0aW9uKHMpXG4gICAqICAgUC0+PlU6IERpc3BsYXkgcHJvbXB0KHMpXG4gICAqICAgVS0+PlA6IFByb3ZpZGUgaW5wdXRcbiAgICogICBQLT4+QTogUmV0dXJuIGFuc3dlcnNcbiAgICogICBBLT4+QTogUHJvY2VzcyBhbnN3ZXJzXG4gICAqICAgQS0tPj5DYWxsZXI6IFJldHVybiBwcm9jZXNzZWQgYW5zd2Vyc1xuICAgKi9cbiAgc3RhdGljIGFzeW5jIGFzazxSIGV4dGVuZHMgc3RyaW5nID0gc3RyaW5nPihcbiAgICBxdWVzdGlvbjogVXNlcklucHV0PFI+IHwgVXNlcklucHV0PFI+W11cbiAgKSB7XG4gICAgY29uc3QgbG9nID0gVXNlcklucHV0LmxvZ2dlci5mb3IodGhpcy5hc2spO1xuICAgIGlmICghQXJyYXkuaXNBcnJheShxdWVzdGlvbikpIHtcbiAgICAgIHF1ZXN0aW9uID0gW3F1ZXN0aW9uXTtcbiAgICB9XG4gICAgbGV0IGFuc3dlcnM6IEFuc3dlcnM8Uj47XG4gICAgdHJ5IHtcbiAgICAgIGxvZy52ZXJib3NlKFxuICAgICAgICBgQXNraW5nIHF1ZXN0aW9uczogJHtxdWVzdGlvbi5tYXAoKHEpID0+IHEubmFtZSkuam9pbihcIiwgXCIpfWBcbiAgICAgICk7XG4gICAgICBhbnN3ZXJzID0gYXdhaXQgcHJvbXB0cyhxdWVzdGlvbik7XG4gICAgICBsb2cudmVyYm9zZShgUmVjZWl2ZWQgYW5zd2VyczogJHtKU09OLnN0cmluZ2lmeShhbnN3ZXJzLCBudWxsLCAyKX1gKTtcbiAgICB9IGNhdGNoIChlcnJvcjogdW5rbm93bikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBFcnJvciB3aGlsZSBnZXR0aW5nIGlucHV0OiAke2Vycm9yfWApO1xuICAgIH1cbiAgICByZXR1cm4gYW5zd2VycztcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gQXNrcyB0aGUgdXNlciBmb3IgYSBudW1iZXIgaW5wdXQuXG4gICAqIEBzdW1tYXJ5IFByb21wdHMgdGhlIHVzZXIgdG8gZW50ZXIgYSBudW1iZXIsIHdpdGggb3B0aW9uYWwgbWluaW11bSwgbWF4aW11bSwgYW5kIGluaXRpYWwgdmFsdWVzLlxuICAgKiBAcGFyYW0gbmFtZSAtIFRoZSBuYW1lIG9mIHRoZSBwcm9tcHQsIHVzZWQgYXMgdGhlIGtleSBpbiB0aGUgcmV0dXJuZWQgYW5zd2VycyBvYmplY3QuXG4gICAqIEBwYXJhbSBxdWVzdGlvbiAtIFRoZSBtZXNzYWdlIGRpc3BsYXllZCB0byB0aGUgdXNlci5cbiAgICogQHBhcmFtIG1pbiAtIFRoZSBtaW5pbXVtIGFsbG93ZWQgdmFsdWUgKG9wdGlvbmFsKS5cbiAgICogQHBhcmFtIG1heCAtIFRoZSBtYXhpbXVtIGFsbG93ZWQgdmFsdWUgKG9wdGlvbmFsKS5cbiAgICogQHBhcmFtIGluaXRpYWwgLSBUaGUgaW5pdGlhbCB2YWx1ZSBwcmVzZW50ZWQgdG8gdGhlIHVzZXIgKG9wdGlvbmFsKS5cbiAgICogQHJldHVybiBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgbnVtYmVyIGVudGVyZWQgYnkgdGhlIHVzZXIuXG4gICAqL1xuICBzdGF0aWMgYXN5bmMgYXNrTnVtYmVyKFxuICAgIG5hbWU6IHN0cmluZyxcbiAgICBxdWVzdGlvbjogc3RyaW5nLFxuICAgIG1pbj86IG51bWJlcixcbiAgICBtYXg/OiBudW1iZXIsXG4gICAgaW5pdGlhbD86IG51bWJlclxuICApOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIGNvbnN0IGxvZyA9IFVzZXJJbnB1dC5sb2dnZXIuZm9yKHRoaXMuYXNrTnVtYmVyKTtcbiAgICBsb2cudmVyYm9zZShcbiAgICAgIGBBc2tpbmcgbnVtYmVyIGlucHV0OiB1bmRlZmluZWQsIHF1ZXN0aW9uOiAke3F1ZXN0aW9ufSwgbWluOiAke21pbn0sIG1heDogJHttYXh9LCBpbml0aWFsOiAke2luaXRpYWx9YFxuICAgICk7XG4gICAgY29uc3QgdXNlcklucHV0ID0gbmV3IFVzZXJJbnB1dChuYW1lKVxuICAgICAgLnNldE1lc3NhZ2UocXVlc3Rpb24pXG4gICAgICAuc2V0VHlwZShcIm51bWJlclwiKTtcblxuICAgIGlmICh0eXBlb2YgbWluID09PSBcIm51bWJlclwiKSB1c2VySW5wdXQuc2V0TWluKG1pbik7XG5cbiAgICBpZiAodHlwZW9mIG1heCA9PT0gXCJudW1iZXJcIikgdXNlcklucHV0LnNldE1heChtYXgpO1xuXG4gICAgaWYgKHR5cGVvZiBpbml0aWFsID09PSBcIm51bWJlclwiKSB1c2VySW5wdXQuc2V0SW5pdGlhbChpbml0aWFsKTtcblxuICAgIHJldHVybiAoYXdhaXQgdGhpcy5hc2sodXNlcklucHV0KSlbbmFtZV07XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEFza3MgdGhlIHVzZXIgZm9yIGEgdGV4dCBpbnB1dC5cbiAgICogQHN1bW1hcnkgUHJvbXB0cyB0aGUgdXNlciB0byBlbnRlciB0ZXh0LCB3aXRoIG9wdGlvbmFsIG1hc2tpbmcgYW5kIGluaXRpYWwgdmFsdWUuXG4gICAqIEBwYXJhbSBuYW1lIC0gVGhlIG5hbWUgb2YgdGhlIHByb21wdCwgdXNlZCBhcyB0aGUga2V5IGluIHRoZSByZXR1cm5lZCBhbnN3ZXJzIG9iamVjdC5cbiAgICogQHBhcmFtIHF1ZXN0aW9uIC0gVGhlIG1lc3NhZ2UgZGlzcGxheWVkIHRvIHRoZSB1c2VyLlxuICAgKiBAcGFyYW0gbWFzayAtIFRoZSBjaGFyYWN0ZXIgdXNlZCB0byBtYXNrIHRoZSBpbnB1dCAob3B0aW9uYWwsIGZvciBwYXNzd29yZC1saWtlIGlucHV0cykuXG4gICAqIEBwYXJhbSBpbml0aWFsIC0gVGhlIGluaXRpYWwgdmFsdWUgcHJlc2VudGVkIHRvIHRoZSB1c2VyIChvcHRpb25hbCkuXG4gICAqIEByZXR1cm4gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIHRleHQgZW50ZXJlZCBieSB0aGUgdXNlci5cbiAgICovXG4gIHN0YXRpYyBhc3luYyBhc2tUZXh0KFxuICAgIG5hbWU6IHN0cmluZyxcbiAgICBxdWVzdGlvbjogc3RyaW5nLFxuICAgIG1hc2s6IHN0cmluZyB8IHVuZGVmaW5lZCA9IHVuZGVmaW5lZCxcbiAgICBpbml0aWFsPzogc3RyaW5nXG4gICk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgY29uc3QgbG9nID0gVXNlcklucHV0LmxvZ2dlci5mb3IodGhpcy5hc2tUZXh0KTtcbiAgICBsb2cudmVyYm9zZShcbiAgICAgIGBBc2tpbmcgdGV4dCBpbnB1dDogdW5kZWZpbmVkLCBxdWVzdGlvbjogJHtxdWVzdGlvbn0sIG1hc2s6ICR7bWFza30sIGluaXRpYWw6ICR7aW5pdGlhbH1gXG4gICAgKTtcbiAgICBjb25zdCB1c2VySW5wdXQgPSBuZXcgVXNlcklucHV0KG5hbWUpLnNldE1lc3NhZ2UocXVlc3Rpb24pO1xuXG4gICAgaWYgKG1hc2spIHVzZXJJbnB1dC5zZXRNYXNrKG1hc2spO1xuICAgIGlmICh0eXBlb2YgaW5pdGlhbCA9PT0gXCJzdHJpbmdcIikgdXNlcklucHV0LnNldEluaXRpYWwoaW5pdGlhbCk7XG4gICAgcmV0dXJuIChhd2FpdCB0aGlzLmFzayh1c2VySW5wdXQpKVtuYW1lXTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gQXNrcyB0aGUgdXNlciBmb3IgYSBjb25maXJtYXRpb24gKHllcy9ubykuXG4gICAqIEBzdW1tYXJ5IFByb21wdHMgdGhlIHVzZXIgd2l0aCBhIHllcy9ubyBxdWVzdGlvbiBhbmQgcmV0dXJucyBhIGJvb2xlYW4gcmVzdWx0LlxuICAgKiBAcGFyYW0gbmFtZSAtIFRoZSBuYW1lIG9mIHRoZSBwcm9tcHQsIHVzZWQgYXMgdGhlIGtleSBpbiB0aGUgcmV0dXJuZWQgYW5zd2VycyBvYmplY3QuXG4gICAqIEBwYXJhbSBxdWVzdGlvbiAtIFRoZSBtZXNzYWdlIGRpc3BsYXllZCB0byB0aGUgdXNlci5cbiAgICogQHBhcmFtIGluaXRpYWwgLSBUaGUgaW5pdGlhbCB2YWx1ZSBwcmVzZW50ZWQgdG8gdGhlIHVzZXIgKG9wdGlvbmFsKS5cbiAgICogQHJldHVybiBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byBhIGJvb2xlYW4gcmVwcmVzZW50aW5nIHRoZSB1c2VyJ3MgYW5zd2VyLlxuICAgKi9cbiAgc3RhdGljIGFzeW5jIGFza0NvbmZpcm1hdGlvbihcbiAgICBuYW1lOiBzdHJpbmcsXG4gICAgcXVlc3Rpb246IHN0cmluZyxcbiAgICBpbml0aWFsPzogYm9vbGVhblxuICApOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICBjb25zdCBsb2cgPSBVc2VySW5wdXQubG9nZ2VyLmZvcih0aGlzLmFza0NvbmZpcm1hdGlvbik7XG4gICAgbG9nLnZlcmJvc2UoXG4gICAgICBgQXNraW5nIGNvbmZpcm1hdGlvbiBpbnB1dDogdW5kZWZpbmVkLCBxdWVzdGlvbjogJHtxdWVzdGlvbn0sIGluaXRpYWw6ICR7aW5pdGlhbH1gXG4gICAgKTtcbiAgICBjb25zdCB1c2VySW5wdXQgPSBuZXcgVXNlcklucHV0KG5hbWUpXG4gICAgICAuc2V0TWVzc2FnZShxdWVzdGlvbilcbiAgICAgIC5zZXRUeXBlKFwiY29uZmlybVwiKTtcblxuICAgIGlmICh0eXBlb2YgaW5pdGlhbCAhPT0gXCJ1bmRlZmluZWRcIikgdXNlcklucHV0LnNldEluaXRpYWwoaW5pdGlhbCk7XG4gICAgcmV0dXJuIChhd2FpdCB0aGlzLmFzayh1c2VySW5wdXQpKVtuYW1lXTtcbiAgfVxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFJlcGVhdGVkbHkgYXNrcyBmb3IgaW5wdXQgdW50aWwgYSB2YWxpZCByZXNwb25zZSBpcyBnaXZlbiBvciB0aGUgbGltaXQgaXMgcmVhY2hlZC5cbiAgICogQHN1bW1hcnkgVGhpcyBtZXRob2QgaW5zaXN0cyBvbiBnZXR0aW5nIGEgdmFsaWQgaW5wdXQgZnJvbSB0aGUgdXNlciwgYWxsb3dpbmcgZm9yIGEgc3BlY2lmaWVkIG51bWJlciBvZiBhdHRlbXB0cy5cbiAgICpcbiAgICogQHRlbXBsYXRlIFIgLSBUaGUgdHlwZSBvZiB0aGUgZXhwZWN0ZWQgcmVzdWx0LlxuICAgKiBAcGFyYW0gaW5wdXQgLSBUaGUgVXNlcklucHV0IGluc3RhbmNlIHRvIHVzZSBmb3IgcHJvbXB0aW5nLlxuICAgKiBAcGFyYW0ge2Z1bmN0aW9uKHN0cmluZyk6Ym9vbGVhbn0gdGVzdCAtIFZhbGlkYXRvciBmdW5jdGlvbiByZWNlaXZpbmcgdGhlIHVzZXIgaW5wdXQgYW5kIHJldHVybmluZyB3aGV0aGVyIGl0IGlzIHZhbGlkLlxuICAgKiBAcGFyYW0gZGVmYXVsdENvbmZpcm1hdGlvbiAtIFRoZSBkZWZhdWx0IHZhbHVlIGZvciB0aGUgY29uZmlybWF0aW9uIHByb21wdCAodHJ1ZSBmb3IgeWVzLCBmYWxzZSBmb3Igbm8pLlxuICAgKiBAcGFyYW0gbGltaXQgLSBUaGUgbWF4aW11bSBudW1iZXIgb2YgYXR0ZW1wdHMgYWxsb3dlZCAoZGVmYXVsdCBpcyAxKS5cbiAgICogQHJldHVybiBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgdmFsaWQgaW5wdXQgb3IgdW5kZWZpbmVkIGlmIHRoZSBsaW1pdCBpcyByZWFjaGVkLlxuICAgKlxuICAgKiBAbWVybWFpZFxuICAgKiBzZXF1ZW5jZURpYWdyYW1cbiAgICogICBwYXJ0aWNpcGFudCBVIGFzIFVzZXJcbiAgICogICBwYXJ0aWNpcGFudCBJIGFzIGluc2lzdCBtZXRob2RcbiAgICogICBwYXJ0aWNpcGFudCBBIGFzIGFzayBtZXRob2RcbiAgICogICBwYXJ0aWNpcGFudCBUIGFzIHRlc3QgZnVuY3Rpb25cbiAgICogICBwYXJ0aWNpcGFudCBDIGFzIGFza0NvbmZpcm1hdGlvbiBtZXRob2RcbiAgICogICBsb29wIFVudGlsIHZhbGlkIGlucHV0IG9yIGxpbWl0IHJlYWNoZWRcbiAgICogICAgIEktPj5BOiBDYWxsIGFzayB3aXRoIGlucHV0XG4gICAqICAgICBBLT4+VTogUHJvbXB0IHVzZXJcbiAgICogICAgIFUtPj5BOiBQcm92aWRlIGlucHV0XG4gICAqICAgICBBLT4+STogUmV0dXJuIHJlc3VsdFxuICAgKiAgICAgSS0+PlQ6IFRlc3QgcmVzdWx0XG4gICAqICAgICBhbHQgVGVzdCBwYXNzZXNcbiAgICogICAgICAgSS0+PkM6IEFzayBmb3IgY29uZmlybWF0aW9uXG4gICAqICAgICAgIEMtPj5VOiBDb25maXJtIGlucHV0XG4gICAqICAgICAgIFUtPj5DOiBQcm92aWRlIGNvbmZpcm1hdGlvblxuICAgKiAgICAgICBDLT4+STogUmV0dXJuIGNvbmZpcm1hdGlvblxuICAgKiAgICAgICBhbHQgQ29uZmlybWVkXG4gICAqICAgICAgICAgSS0tPj5DYWxsZXI6IFJldHVybiB2YWxpZCByZXN1bHRcbiAgICogICAgICAgZWxzZSBOb3QgY29uZmlybWVkXG4gICAqICAgICAgICAgSS0+Pkk6IENvbnRpbnVlIGxvb3BcbiAgICogICAgICAgZW5kXG4gICAqICAgICBlbHNlIFRlc3QgZmFpbHNcbiAgICogICAgICAgSS0+Pkk6IENvbnRpbnVlIGxvb3BcbiAgICogICAgIGVuZFxuICAgKiAgIGVuZFxuICAgKiAgIEktLT4+Q2FsbGVyOiBSZXR1cm4gdW5kZWZpbmVkIGlmIGxpbWl0IHJlYWNoZWRcbiAgICovXG4gIHN0YXRpYyBhc3luYyBpbnNpc3Q8Uj4oXG4gICAgaW5wdXQ6IFVzZXJJbnB1dCxcbiAgICB0ZXN0OiAocmVzOiBzdHJpbmcgfCBudW1iZXIpID0+IGJvb2xlYW4sXG4gICAgZGVmYXVsdENvbmZpcm1hdGlvbjogYm9vbGVhbixcbiAgICBsaW1pdCA9IDFcbiAgKTogUHJvbWlzZTxSIHwgdW5kZWZpbmVkPiB7XG4gICAgY29uc3QgbG9nID0gVXNlcklucHV0LmxvZ2dlci5mb3IodGhpcy5pbnNpc3QpO1xuICAgIGxvZy52ZXJib3NlKFxuICAgICAgYEluc2lzdGluZyBvbiBpbnB1dDogJHtpbnB1dC5uYW1lfSwgdGVzdDogJHt0ZXN0LnRvU3RyaW5nKCl9LCBkZWZhdWx0Q29uZmlybWF0aW9uOiAke2RlZmF1bHRDb25maXJtYXRpb259LCBsaW1pdDogJHtsaW1pdH1gXG4gICAgKTtcbiAgICBsZXQgcmVzdWx0OiBzdHJpbmcgfCBudW1iZXIgfCB1bmRlZmluZWQgPSB1bmRlZmluZWQ7XG4gICAgbGV0IGNvdW50ID0gMDtcbiAgICBsZXQgY29uZmlybWF0aW9uOiBib29sZWFuO1xuICAgIHRyeSB7XG4gICAgICBkbyB7XG4gICAgICAgIHJlc3VsdCA9IChhd2FpdCBVc2VySW5wdXQuYXNrKGlucHV0KSlbXG4gICAgICAgICAgaW5wdXQubmFtZSBhcyBrZXlvZiBBbnN3ZXJzPHN0cmluZz5cbiAgICAgICAgXSBhcyBzdHJpbmc7XG4gICAgICAgIGlmICghdGVzdChyZXN1bHQpKSB7XG4gICAgICAgICAgcmVzdWx0ID0gdW5kZWZpbmVkO1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG4gICAgICAgIGNvbmZpcm1hdGlvbiA9IGF3YWl0IFVzZXJJbnB1dC5hc2tDb25maXJtYXRpb24oXG4gICAgICAgICAgYCR7aW5wdXQubmFtZX0tY29uZmlybWAsXG4gICAgICAgICAgYElzIHRoZSAke2lucHV0LnR5cGV9IGNvcnJlY3Q/YCxcbiAgICAgICAgICBkZWZhdWx0Q29uZmlybWF0aW9uXG4gICAgICAgICk7XG4gICAgICAgIGlmICghY29uZmlybWF0aW9uKSByZXN1bHQgPSB1bmRlZmluZWQ7XG4gICAgICB9IHdoaWxlICh0eXBlb2YgcmVzdWx0ID09PSBcInVuZGVmaW5lZFwiICYmIGxpbWl0ID4gMSAmJiBjb3VudCsrIDwgbGltaXQpO1xuICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgIGxvZy5lcnJvcihgRXJyb3Igd2hpbGUgaW5zaXN0aW5nOiAke2V9YCk7XG4gICAgICB0aHJvdyBlO1xuICAgIH1cblxuICAgIGlmICh0eXBlb2YgcmVzdWx0ID09PSBcInVuZGVmaW5lZFwiKSBsb2cuaW5mbyhcIm5vIHNlbGVjdGlvbi4uLlwiKTtcbiAgICByZXR1cm4gcmVzdWx0IGFzIFIgfCB1bmRlZmluZWQ7XG4gIH1cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBSZXBlYXRlZGx5IGFza3MgZm9yIHRleHQgaW5wdXQgdW50aWwgYSB2YWxpZCByZXNwb25zZSBpcyBnaXZlbiBvciB0aGUgbGltaXQgaXMgcmVhY2hlZC5cbiAgICogQHN1bW1hcnkgVGhpcyBtZXRob2QgaW5zaXN0cyBvbiBnZXR0aW5nIGEgdmFsaWQgdGV4dCBpbnB1dCBmcm9tIHRoZSB1c2VyLCBhbGxvd2luZyBmb3IgYSBzcGVjaWZpZWQgbnVtYmVyIG9mIGF0dGVtcHRzLlxuICAgKlxuICAgKiBAcGFyYW0gbmFtZSAtIFRoZSBuYW1lIG9mIHRoZSBwcm9tcHQsIHVzZWQgYXMgdGhlIGtleSBpbiB0aGUgcmV0dXJuZWQgYW5zd2VycyBvYmplY3QuXG4gICAqIEBwYXJhbSBxdWVzdGlvbiAtIFRoZSBtZXNzYWdlIGRpc3BsYXllZCB0byB0aGUgdXNlci5cbiAgICogQHBhcmFtIHtmdW5jdGlvbihudW1iZXIpOmJvb2xlYW59IHRlc3QgLSBWYWxpZGF0b3IgZnVuY3Rpb24gcmVjZWl2aW5nIHRoZSB1c2VyIGlucHV0IGFuZCByZXR1cm5pbmcgd2hldGhlciBpdCBpcyB2YWxpZC5cbiAgICogQHBhcmFtIG1hc2sgLSBUaGUgY2hhcmFjdGVyIHVzZWQgdG8gbWFzayB0aGUgaW5wdXQgKG9wdGlvbmFsLCBmb3IgcGFzc3dvcmQtbGlrZSBpbnB1dHMpLlxuICAgKiBAcGFyYW0gaW5pdGlhbCAtIFRoZSBpbml0aWFsIHZhbHVlIHByZXNlbnRlZCB0byB0aGUgdXNlciAob3B0aW9uYWwpLlxuICAgKiBAcGFyYW0gZGVmYXVsdENvbmZpcm1hdGlvbiAtIFRoZSBkZWZhdWx0IHZhbHVlIGZvciB0aGUgY29uZmlybWF0aW9uIHByb21wdCAodHJ1ZSBmb3IgeWVzLCBmYWxzZSBmb3Igbm8pLlxuICAgKiBAcGFyYW0gbGltaXQgLSBUaGUgbWF4aW11bSBudW1iZXIgb2YgYXR0ZW1wdHMgYWxsb3dlZCAoZGVmYXVsdCBpcyAtMSwgbWVhbmluZyB1bmxpbWl0ZWQpLlxuICAgKiBAcmV0dXJuIEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSB2YWxpZCBpbnB1dCBvciB1bmRlZmluZWQgaWYgdGhlIGxpbWl0IGlzIHJlYWNoZWQuXG4gICAqL1xuICBzdGF0aWMgYXN5bmMgaW5zaXN0Rm9yVGV4dChcbiAgICBuYW1lOiBzdHJpbmcsXG4gICAgcXVlc3Rpb246IHN0cmluZyxcbiAgICB0ZXN0OiAocmVzOiBzdHJpbmcpID0+IGJvb2xlYW4sXG4gICAgbWFzazogc3RyaW5nIHwgdW5kZWZpbmVkID0gdW5kZWZpbmVkLFxuICAgIGluaXRpYWw/OiBzdHJpbmcsXG4gICAgZGVmYXVsdENvbmZpcm1hdGlvbiA9IGZhbHNlLFxuICAgIGxpbWl0ID0gLTFcbiAgKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBjb25zdCBsb2cgPSBVc2VySW5wdXQubG9nZ2VyLmZvcih0aGlzLmluc2lzdEZvclRleHQpO1xuICAgIGxvZy52ZXJib3NlKFxuICAgICAgYEluc2lzdGluZyBmb3IgdGV4dCBpbnB1dDogdW5kZWZpbmVkLCBxdWVzdGlvbjogJHtxdWVzdGlvbn0sIHRlc3Q6ICR7dGVzdC50b1N0cmluZygpfSwgbWFzazogJHttYXNrfSwgaW5pdGlhbDogJHtpbml0aWFsfSwgZGVmYXVsdENvbmZpcm1hdGlvbjogJHtkZWZhdWx0Q29uZmlybWF0aW9ufSwgbGltaXQ6ICR7bGltaXR9YFxuICAgICk7XG4gICAgY29uc3QgdXNlcklucHV0ID0gbmV3IFVzZXJJbnB1dChuYW1lKS5zZXRNZXNzYWdlKHF1ZXN0aW9uKTtcblxuICAgIGlmIChtYXNrKSB1c2VySW5wdXQuc2V0TWFzayhtYXNrKTtcbiAgICBpZiAodHlwZW9mIGluaXRpYWwgPT09IFwic3RyaW5nXCIpIHVzZXJJbnB1dC5zZXRJbml0aWFsKGluaXRpYWwpO1xuICAgIHJldHVybiAoYXdhaXQgdGhpcy5pbnNpc3QoXG4gICAgICB1c2VySW5wdXQsXG4gICAgICB0ZXN0IGFzIChyZXM6IHN0cmluZyB8IG51bWJlcikgPT4gYm9vbGVhbixcbiAgICAgIGRlZmF1bHRDb25maXJtYXRpb24sXG4gICAgICBsaW1pdFxuICAgICkpIGFzIHN0cmluZztcbiAgfVxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFJlcGVhdGVkbHkgYXNrcyBmb3IgbnVtYmVyIGlucHV0IHVudGlsIGEgdmFsaWQgcmVzcG9uc2UgaXMgZ2l2ZW4gb3IgdGhlIGxpbWl0IGlzIHJlYWNoZWQuXG4gICAqIEBzdW1tYXJ5IFRoaXMgbWV0aG9kIGluc2lzdHMgb24gZ2V0dGluZyBhIHZhbGlkIG51bWJlciBpbnB1dCBmcm9tIHRoZSB1c2VyLCBhbGxvd2luZyBmb3IgYSBzcGVjaWZpZWQgbnVtYmVyIG9mIGF0dGVtcHRzLlxuICAgKlxuICAgKiBAcGFyYW0gbmFtZSAtIFRoZSBuYW1lIG9mIHRoZSBwcm9tcHQsIHVzZWQgYXMgdGhlIGtleSBpbiB0aGUgcmV0dXJuZWQgYW5zd2VycyBvYmplY3QuXG4gICAqIEBwYXJhbSBxdWVzdGlvbiAtIFRoZSBtZXNzYWdlIGRpc3BsYXllZCB0byB0aGUgdXNlci5cbiAgICogQHBhcmFtIHRlc3QgLSBBIGZ1bmN0aW9uIHRvIHZhbGlkYXRlIHRoZSB1c2VyJ3MgaW5wdXQuXG4gICAqIEBwYXJhbSBtaW4gLSBUaGUgbWluaW11bSBhbGxvd2VkIHZhbHVlIChvcHRpb25hbCkuXG4gICAqIEBwYXJhbSBtYXggLSBUaGUgbWF4aW11bSBhbGxvd2VkIHZhbHVlIChvcHRpb25hbCkuXG4gICAqIEBwYXJhbSBpbml0aWFsIC0gVGhlIGluaXRpYWwgdmFsdWUgcHJlc2VudGVkIHRvIHRoZSB1c2VyIChvcHRpb25hbCkuXG4gICAqIEBwYXJhbSBkZWZhdWx0Q29uZmlybWF0aW9uIC0gVGhlIGRlZmF1bHQgdmFsdWUgZm9yIHRoZSBjb25maXJtYXRpb24gcHJvbXB0ICh0cnVlIGZvciB5ZXMsIGZhbHNlIGZvciBubykuXG4gICAqIEBwYXJhbSBsaW1pdCAtIFRoZSBtYXhpbXVtIG51bWJlciBvZiBhdHRlbXB0cyBhbGxvd2VkIChkZWZhdWx0IGlzIC0xLCBtZWFuaW5nIHVubGltaXRlZCkuXG4gICAqIEByZXR1cm4gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIHZhbGlkIGlucHV0IG9yIHVuZGVmaW5lZCBpZiB0aGUgbGltaXQgaXMgcmVhY2hlZC5cbiAgICovXG4gIHN0YXRpYyBhc3luYyBpbnNpc3RGb3JOdW1iZXIoXG4gICAgbmFtZTogc3RyaW5nLFxuICAgIHF1ZXN0aW9uOiBzdHJpbmcsXG4gICAgdGVzdDogKHJlczogbnVtYmVyKSA9PiBib29sZWFuLFxuICAgIG1pbj86IG51bWJlcixcbiAgICBtYXg/OiBudW1iZXIsXG4gICAgaW5pdGlhbD86IG51bWJlcixcbiAgICBkZWZhdWx0Q29uZmlybWF0aW9uID0gZmFsc2UsXG4gICAgbGltaXQgPSAtMVxuICApOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIGNvbnN0IGxvZyA9IFVzZXJJbnB1dC5sb2dnZXIuZm9yKHRoaXMuaW5zaXN0Rm9yTnVtYmVyKTtcbiAgICBsb2cudmVyYm9zZShcbiAgICAgIGBJbnNpc3RpbmcgZm9yIG51bWJlciBpbnB1dDogdW5kZWZpbmVkLCBxdWVzdGlvbjogJHtxdWVzdGlvbn0sIHRlc3Q6ICR7dGVzdC50b1N0cmluZygpfSwgbWluOiAke21pbn0sIG1heDogJHttYXh9LCBpbml0aWFsOiAke2luaXRpYWx9LCBkZWZhdWx0Q29uZmlybWF0aW9uOiAke2RlZmF1bHRDb25maXJtYXRpb259LCBsaW1pdDogJHtsaW1pdH1gXG4gICAgKTtcbiAgICBjb25zdCB1c2VySW5wdXQgPSBuZXcgVXNlcklucHV0KG5hbWUpXG4gICAgICAuc2V0TWVzc2FnZShxdWVzdGlvbilcbiAgICAgIC5zZXRUeXBlKFwibnVtYmVyXCIpO1xuXG4gICAgaWYgKHR5cGVvZiBtaW4gPT09IFwibnVtYmVyXCIpIHVzZXJJbnB1dC5zZXRNaW4obWluKTtcblxuICAgIGlmICh0eXBlb2YgbWF4ID09PSBcIm51bWJlclwiKSB1c2VySW5wdXQuc2V0TWF4KG1heCk7XG5cbiAgICBpZiAodHlwZW9mIGluaXRpYWwgPT09IFwibnVtYmVyXCIpIHVzZXJJbnB1dC5zZXRJbml0aWFsKGluaXRpYWwpO1xuICAgIHJldHVybiAoYXdhaXQgdGhpcy5pbnNpc3QoXG4gICAgICB1c2VySW5wdXQsXG4gICAgICB0ZXN0IGFzIChyZXM6IHN0cmluZyB8IG51bWJlcikgPT4gYm9vbGVhbixcbiAgICAgIGRlZmF1bHRDb25maXJtYXRpb24sXG4gICAgICBsaW1pdFxuICAgICkpIGFzIG51bWJlcjtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUGFyc2VzIGNvbW1hbmQtbGluZSBhcmd1bWVudHMgYmFzZWQgb24gdGhlIHByb3ZpZGVkIG9wdGlvbnMuXG4gICAqIEBzdW1tYXJ5IFVzZXMgTm9kZS5qcydzIHV0aWwucGFyc2VBcmdzIHRvIHBhcnNlIGNvbW1hbmQtbGluZSBhcmd1bWVudHMgYW5kIHJldHVybiB0aGUgcmVzdWx0LlxuICAgKiBAcGFyYW0gb3B0aW9ucyAtIENvbmZpZ3VyYXRpb24gb3B0aW9ucyBmb3IgcGFyc2luZyBhcmd1bWVudHMuXG4gICAqIEByZXR1cm4gQW4gb2JqZWN0IGNvbnRhaW5pbmcgdGhlIHBhcnNlZCBhcmd1bWVudHMuXG4gICAqIEBtZXJtYWlkXG4gICAqIHNlcXVlbmNlRGlhZ3JhbVxuICAgKiAgIHBhcnRpY2lwYW50IEMgYXMgQ2FsbGVyXG4gICAqICAgcGFydGljaXBhbnQgUCBhcyBwYXJzZUFyZ3MgbWV0aG9kXG4gICAqICAgcGFydGljaXBhbnQgVSBhcyB1dGlsLnBhcnNlQXJnc1xuICAgKiAgIEMtPj5QOiBDYWxsIHdpdGggb3B0aW9uc1xuICAgKiAgIFAtPj5QOiBQcmVwYXJlIGFyZ3Mgb2JqZWN0XG4gICAqICAgUC0+PlU6IENhbGwgcGFyc2VBcmdzIHdpdGggcHJlcGFyZWQgYXJnc1xuICAgKiAgIFUtPj5QOiBSZXR1cm4gcGFyc2VkIHJlc3VsdFxuICAgKiAgIFAtLT4+QzogUmV0dXJuIFBhcnNlQXJnc1Jlc3VsdFxuICAgKi9cbiAgc3RhdGljIHBhcnNlQXJncyhvcHRpb25zOiBQYXJzZUFyZ3NPcHRpb25zQ29uZmlnKTogUGFyc2VBcmdzUmVzdWx0IHtcbiAgICBjb25zdCBsb2cgPSBVc2VySW5wdXQubG9nZ2VyLmZvcih0aGlzLnBhcnNlQXJncyk7XG4gICAgY29uc3QgYXJnczogUGFyc2VBcmdzQ29uZmlnID0ge1xuICAgICAgYXJnczogcHJvY2Vzcy5hcmd2LnNsaWNlKDIpLFxuICAgICAgb3B0aW9uczogb3B0aW9ucyxcbiAgICB9O1xuICAgIGxvZy5kZWJ1ZyhgUGFyc2luZyBhcmd1bWVudHM6ICR7SlNPTi5zdHJpbmdpZnkoYXJncywgbnVsbCwgMil9YCk7XG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiBwYXJzZUFyZ3MoYXJncyk7XG4gICAgfSBjYXRjaCAoZXJyb3I6IHVua25vd24pIHtcbiAgICAgIGxvZy5kZWJ1ZyhcbiAgICAgICAgYEVycm9yIHdoaWxlIHBhcnNpbmcgYXJndW1lbnRzOlxcbiR7SlNPTi5zdHJpbmdpZnkoYXJncywgbnVsbCwgMil9XFxuIHwgb3B0aW9uc1xcbiR7SlNPTi5zdHJpbmdpZnkob3B0aW9ucywgbnVsbCwgMil9XFxuIHwgJHtlcnJvcn1gXG4gICAgICApO1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBFcnJvciB3aGlsZSBwYXJzaW5nIGFyZ3VtZW50czogJHtlcnJvcn1gKTtcbiAgICB9XG4gIH1cbn1cbiIsIi8qKlxuICogQGRlc2NyaXB0aW9uIERlZmF1bHQgY29tbWFuZCBvcHRpb25zIGZvciBDTEkgY29tbWFuZHMuXG4gKiBAc3VtbWFyeSBEZWZpbmVzIHRoZSBzdHJ1Y3R1cmUgYW5kIGRlZmF1bHQgdmFsdWVzIGZvciBjb21tb24gY29tbWFuZC1saW5lIG9wdGlvbnMgdXNlZCBhY3Jvc3MgdmFyaW91cyBDTEkgY29tbWFuZHMuXG4gKiBAY29uc3QgRGVmYXVsdENvbW1hbmRPcHRpb25zXG4gKiBAdHlwZWRlZiB7T2JqZWN0fSBEZWZhdWx0Q29tbWFuZE9wdGlvbnNcbiAqIEBwcm9wZXJ0eSB7T2JqZWN0fSB2ZXJib3NlIC0gVmVyYm9zaXR5IGxldmVsIG9wdGlvbi5cbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSB2ZXJib3NlLnR5cGUgLSBUaGUgdHlwZSBvZiB0aGUgdmVyYm9zZSBvcHRpb24gKG51bWJlcikuXG4gKiBAcHJvcGVydHkge3N0cmluZ30gdmVyYm9zZS5zaG9ydCAtIFRoZSBzaG9ydCBmbGFnIGZvciB0aGUgdmVyYm9zZSBvcHRpb24gKFYpLlxuICogQHByb3BlcnR5IHtudW1iZXJ9IHZlcmJvc2UuZGVmYXVsdCAtIFRoZSBkZWZhdWx0IHZhbHVlIGZvciB2ZXJib3NpdHkgKDApLlxuICogQHByb3BlcnR5IHtPYmplY3R9IHZlcnNpb24gLSBWZXJzaW9uIGRpc3BsYXkgb3B0aW9uLlxuICogQHByb3BlcnR5IHtzdHJpbmd9IHZlcnNpb24udHlwZSAtIFRoZSB0eXBlIG9mIHRoZSB2ZXJzaW9uIG9wdGlvbiAoYm9vbGVhbikuXG4gKiBAcHJvcGVydHkge3N0cmluZ30gdmVyc2lvbi5zaG9ydCAtIFRoZSBzaG9ydCBmbGFnIGZvciB0aGUgdmVyc2lvbiBvcHRpb24gKHYpLlxuICogQHByb3BlcnR5IHt1bmRlZmluZWR9IHZlcnNpb24uZGVmYXVsdCAtIFRoZSBkZWZhdWx0IHZhbHVlIGZvciB2ZXJzaW9uIGRpc3BsYXkgKHVuZGVmaW5lZCkuXG4gKiBAcHJvcGVydHkge09iamVjdH0gaGVscCAtIEhlbHAgZGlzcGxheSBvcHRpb24uXG4gKiBAcHJvcGVydHkge3N0cmluZ30gaGVscC50eXBlIC0gVGhlIHR5cGUgb2YgdGhlIGhlbHAgb3B0aW9uIChib29sZWFuKS5cbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBoZWxwLnNob3J0IC0gVGhlIHNob3J0IGZsYWcgZm9yIHRoZSBoZWxwIG9wdGlvbiAoaCkuXG4gKiBAcHJvcGVydHkge2Jvb2xlYW59IGhlbHAuZGVmYXVsdCAtIFRoZSBkZWZhdWx0IHZhbHVlIGZvciBoZWxwIGRpc3BsYXkgKGZhbHNlKS5cbiAqIEBwcm9wZXJ0eSB7T2JqZWN0fSBsb2dMZXZlbCAtIExvZyBsZXZlbCBvcHRpb24uXG4gKiBAcHJvcGVydHkge3N0cmluZ30gbG9nTGV2ZWwudHlwZSAtIFRoZSB0eXBlIG9mIHRoZSBsb2dMZXZlbCBvcHRpb24gKHN0cmluZykuXG4gKiBAcHJvcGVydHkge3N0cmluZ30gbG9nTGV2ZWwuZGVmYXVsdCAtIFRoZSBkZWZhdWx0IHZhbHVlIGZvciBsb2cgbGV2ZWwgKFwiaW5mb1wiKS5cbiAqIEBwcm9wZXJ0eSB7T2JqZWN0fSBsb2dTdHlsZSAtIExvZyBzdHlsaW5nIG9wdGlvbi5cbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBsb2dTdHlsZS50eXBlIC0gVGhlIHR5cGUgb2YgdGhlIGxvZ1N0eWxlIG9wdGlvbiAoYm9vbGVhbikuXG4gKiBAcHJvcGVydHkge2Jvb2xlYW59IGxvZ1N0eWxlLmRlZmF1bHQgLSBUaGUgZGVmYXVsdCB2YWx1ZSBmb3IgbG9nIHN0eWxpbmcgKHRydWUpLlxuICogQHByb3BlcnR5IHtPYmplY3R9IHRpbWVzdGFtcCAtIFRpbWVzdGFtcCBkaXNwbGF5IG9wdGlvbi5cbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSB0aW1lc3RhbXAudHlwZSAtIFRoZSB0eXBlIG9mIHRoZSB0aW1lc3RhbXAgb3B0aW9uIChib29sZWFuKS5cbiAqIEBwcm9wZXJ0eSB7Ym9vbGVhbn0gdGltZXN0YW1wLmRlZmF1bHQgLSBUaGUgZGVmYXVsdCB2YWx1ZSBmb3IgdGltZXN0YW1wIGRpc3BsYXkgKHRydWUpLlxuICogQHByb3BlcnR5IHtPYmplY3R9IGJhbm5lciAtIEJhbm5lciBkaXNwbGF5IG9wdGlvbi5cbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBiYW5uZXIudHlwZSAtIFRoZSB0eXBlIG9mIHRoZSBiYW5uZXIgb3B0aW9uIChib29sZWFuKS5cbiAqIEBwcm9wZXJ0eSB7Ym9vbGVhbn0gYmFubmVyLmRlZmF1bHQgLSBUaGUgZGVmYXVsdCB2YWx1ZSBmb3IgYmFubmVyIGRpc3BsYXkgKGZhbHNlKS5cbiAqIEBtZW1iZXJPZiBtb2R1bGU6dXRpbHNcbiAqL1xuZXhwb3J0IGNvbnN0IERlZmF1bHRDb21tYW5kT3B0aW9ucyA9IHtcbiAgdmVyYm9zZToge1xuICAgIHR5cGU6IFwiYm9vbGVhblwiLFxuICAgIHNob3J0OiBcIlZcIixcbiAgICBkZWZhdWx0OiB1bmRlZmluZWQsXG4gIH0sXG4gIHZlcnNpb246IHtcbiAgICB0eXBlOiBcImJvb2xlYW5cIixcbiAgICBzaG9ydDogXCJ2XCIsXG4gICAgZGVmYXVsdDogdW5kZWZpbmVkLFxuICB9LFxuICBoZWxwOiB7XG4gICAgdHlwZTogXCJib29sZWFuXCIsXG4gICAgc2hvcnQ6IFwiaFwiLFxuICAgIGRlZmF1bHQ6IGZhbHNlLFxuICB9LFxuICBsb2dMZXZlbDoge1xuICAgIHR5cGU6IFwic3RyaW5nXCIsXG4gICAgZGVmYXVsdDogXCJpbmZvXCIsXG4gIH0sXG4gIGxvZ1N0eWxlOiB7XG4gICAgdHlwZTogXCJib29sZWFuXCIsXG4gICAgZGVmYXVsdDogdHJ1ZSxcbiAgfSxcbiAgdGltZXN0YW1wOiB7XG4gICAgdHlwZTogXCJib29sZWFuXCIsXG4gICAgZGVmYXVsdDogdHJ1ZSxcbiAgfSxcbiAgYmFubmVyOiB7XG4gICAgdHlwZTogXCJib29sZWFuXCIsXG4gICAgZGVmYXVsdDogdHJ1ZSxcbiAgfSxcbn07XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIERlZmF1bHQgY29tbWFuZCB2YWx1ZXMgZGVyaXZlZCBmcm9tIERlZmF1bHRDb21tYW5kT3B0aW9ucy5cbiAqIEBzdW1tYXJ5IENyZWF0ZXMgYW4gb2JqZWN0IHdpdGggdGhlIGRlZmF1bHQgdmFsdWVzIG9mIGFsbCBvcHRpb25zIGRlZmluZWQgaW4gRGVmYXVsdENvbW1hbmRPcHRpb25zLlxuICogQGNvbnN0IERlZmF1bHRDb21tYW5kVmFsdWVzXG4gKiBAdHlwZWRlZiB7T2JqZWN0fSBEZWZhdWx0Q29tbWFuZFZhbHVlc1xuICogQHByb3BlcnR5IHt1bmtub3dufSBba2V5OiBzdHJpbmddIC0gVGhlIGRlZmF1bHQgdmFsdWUgZm9yIGVhY2ggb3B0aW9uIGluIERlZmF1bHRDb21tYW5kT3B0aW9ucy5cbiAqIEBtZW1iZXJPZiBtb2R1bGU6dXRpbHNcbiAqL1xuZXhwb3J0IGNvbnN0IERlZmF1bHRDb21tYW5kVmFsdWVzOiB7XG4gIFtrIGluIGtleW9mIHR5cGVvZiBEZWZhdWx0Q29tbWFuZE9wdGlvbnNdOiB1bmtub3duO1xufSA9IE9iamVjdC5rZXlzKERlZmF1bHRDb21tYW5kT3B0aW9ucykucmVkdWNlKFxuICAoYWNjOiBSZWNvcmQ8a2V5b2YgdHlwZW9mIERlZmF1bHRDb21tYW5kT3B0aW9ucywgdW5rbm93bj4sIGtleTogc3RyaW5nKSA9PiB7XG4gICAgYWNjW2tleSBhcyBrZXlvZiB0eXBlb2YgRGVmYXVsdENvbW1hbmRPcHRpb25zXSA9XG4gICAgICBEZWZhdWx0Q29tbWFuZE9wdGlvbnNba2V5IGFzIGtleW9mIHR5cGVvZiBEZWZhdWx0Q29tbWFuZE9wdGlvbnNdLmRlZmF1bHQ7XG4gICAgcmV0dXJuIGFjYztcbiAgfSxcbiAge30gYXMgUmVjb3JkPGtleW9mIHR5cGVvZiBEZWZhdWx0Q29tbWFuZFZhbHVlcywgdW5rbm93bj5cbik7XG4iLCIvKipcbiAqIEBkZXNjcmlwdGlvbiBEZWZhdWx0IGVuY29kaW5nIGZvciB0ZXh0IG9wZXJhdGlvbnMuXG4gKiBAc3VtbWFyeSBUaGUgc3RhbmRhcmQgVVRGLTggZW5jb2RpbmcgdXNlZCBmb3IgdGV4dCBwcm9jZXNzaW5nLlxuICogQGNvbnN0IHtzdHJpbmd9IEVuY29kaW5nXG4gKiBAbWVtYmVyT2YgbW9kdWxlOnV0aWxzXG4gKi9cbmV4cG9ydCBjb25zdCBFbmNvZGluZyA9IFwidXRmLThcIjtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gUmVndWxhciBleHByZXNzaW9uIGZvciBzZW1hbnRpYyB2ZXJzaW9uaW5nLlxuICogQHN1bW1hcnkgQSByZWdleCBwYXR0ZXJuIHRvIG1hdGNoIGFuZCBwYXJzZSBzZW1hbnRpYyB2ZXJzaW9uIHN0cmluZ3MuXG4gKiBAY29uc3Qge1JlZ0V4cH0gU2VtVmVyc2lvblJlZ2V4XG4gKiBAbWVtYmVyT2YgbW9kdWxlOnV0aWxzXG4gKi9cbmV4cG9ydCBjb25zdCBTZW1WZXJzaW9uUmVnZXggPVxuICAvXihcXGQrKVxcLihcXGQrKVxcLihcXGQrKSg/Oi0oWzAtOUEtWmEtei1dKyg/OlxcLlswLTlBLVphLXpdKSkpL2c7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIEVudW0gZm9yIHNlbWFudGljIHZlcnNpb24gY29tcG9uZW50cy5cbiAqIEBzdW1tYXJ5IERlZmluZXMgdGhlIHRocmVlIGxldmVscyBvZiBzZW1hbnRpYyB2ZXJzaW9uaW5nOiBQQVRDSCwgTUlOT1IsIGFuZCBNQUpPUi5cbiAqIEBlbnVtIHtzdHJpbmd9XG4gKiBAbWVtYmVyT2YgbW9kdWxlOnV0aWxzXG4gKi9cbmV4cG9ydCBlbnVtIFNlbVZlcnNpb24ge1xuICAvKiogUGF0Y2ggdmVyc2lvbiBmb3IgYmFja3dhcmRzLWNvbXBhdGlibGUgYnVnIGZpeGVzLiAqL1xuICBQQVRDSCA9IFwicGF0Y2hcIixcbiAgLyoqIE1pbm9yIHZlcnNpb24gZm9yIGJhY2t3YXJkcy1jb21wYXRpYmxlIG5ldyBmZWF0dXJlcy4gKi9cbiAgTUlOT1IgPSBcIm1pbm9yXCIsXG4gIC8qKiBNYWpvciB2ZXJzaW9uIGZvciBjaGFuZ2VzIHRoYXQgYnJlYWsgYmFja3dhcmRzIGNvbXBhdGliaWxpdHkuICovXG4gIE1BSk9SID0gXCJtYWpvclwiLFxufVxuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBGbGFnIHRvIGluZGljYXRlIG5vbi1DSSBlbnZpcm9ubWVudC5cbiAqIEBzdW1tYXJ5IFVzZWQgdG8gc3BlY2lmeSB0aGF0IGEgY29tbWFuZCBzaG91bGQgcnVuIG91dHNpZGUgb2YgYSBDb250aW51b3VzIEludGVncmF0aW9uIGVudmlyb25tZW50LlxuICogQGNvbnN0IHtzdHJpbmd9IE5vQ0lGTGFnXG4gKiBAbWVtYmVyT2YgbW9kdWxlOnV0aWxzXG4gKi9cbmV4cG9ydCBjb25zdCBOb0NJRkxhZyA9IFwiLW5vLWNpXCI7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIEtleSBmb3IgdGhlIHNldHVwIHNjcmlwdCBpbiBwYWNrYWdlLmpzb24uXG4gKiBAc3VtbWFyeSBJZGVudGlmaWVzIHRoZSBzY3JpcHQgdGhhdCBydW5zIGFmdGVyIHBhY2thZ2UgaW5zdGFsbGF0aW9uLlxuICogQGNvbnN0IHtzdHJpbmd9IFNldHVwU2NyaXB0S2V5XG4gKiBAbWVtYmVyT2YgbW9kdWxlOnV0aWxzXG4gKi9cbmV4cG9ydCBjb25zdCBTZXR1cFNjcmlwdEtleSA9IFwicG9zdGluc3RhbGxcIjtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gRW51bSBmb3IgdmFyaW91cyBhdXRoZW50aWNhdGlvbiB0b2tlbnMuXG4gKiBAc3VtbWFyeSBEZWZpbmVzIHRoZSBmaWxlIG5hbWVzIGZvciBzdG9yaW5nIGRpZmZlcmVudCB0eXBlcyBvZiBhdXRoZW50aWNhdGlvbiB0b2tlbnMuXG4gKiBAZW51bSB7c3RyaW5nfVxuICogQG1lbWJlck9mIG1vZHVsZTp1dGlsc1xuICovXG5leHBvcnQgZW51bSBUb2tlbnMge1xuICAvKiogR2l0IGF1dGhlbnRpY2F0aW9uIHRva2VuIGZpbGUgbmFtZS4gKi9cbiAgR0lUID0gXCIudG9rZW5cIixcbiAgLyoqIE5QTSBhdXRoZW50aWNhdGlvbiB0b2tlbiBmaWxlIG5hbWUuICovXG4gIE5QTSA9IFwiLm5wbXRva2VuXCIsXG4gIC8qKiBEb2NrZXIgYXV0aGVudGljYXRpb24gdG9rZW4gZmlsZSBuYW1lLiAqL1xuICBET0NLRVIgPSBcIi5kb2NrZXJ0b2tlblwiLFxuICAvKiogQ29uZmx1ZW5jZSBhdXRoZW50aWNhdGlvbiB0b2tlbiBmaWxlIG5hbWUuICovXG4gIENPTkZMVUVOQ0UgPSBcIi5jb25mbHVlbmNlLXRva2VuXCIsXG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIENvZGUgdXNlZCB0byBpbmRpY2F0ZSBhbiBvcGVyYXRpb24gd2FzIGFib3J0ZWQuXG4gKiBAc3VtbWFyeSBTdGFuZGFyZCBtZXNzYWdlIHVzZWQgd2hlbiBhIHByb2Nlc3MgaXMgbWFudWFsbHkgdGVybWluYXRlZC5cbiAqIEBjb25zdCB7c3RyaW5nfSBBYm9ydENvZGVcbiAqIEBtZW1iZXJPZiBtb2R1bGU6dXRpbHNcbiAqL1xuZXhwb3J0IGNvbnN0IEFib3J0Q29kZSA9IFwiQWJvcnRlZFwiO1xuIiwiaW1wb3J0IHsgRW5jb2RpbmcgfSBmcm9tIFwiLi4vdXRpbHMvY29uc3RhbnRzXCI7XG5pbXBvcnQgeyBPdXRwdXRXcml0ZXIgfSBmcm9tIFwiLi9PdXRwdXRXcml0ZXJcIjtcbmltcG9ydCB7IFByb21pc2VFeGVjdXRvciB9IGZyb20gXCIuLi91dGlscy90eXBlc1wiO1xuaW1wb3J0IHsgT3V0cHV0VHlwZSB9IGZyb20gXCIuL3R5cGVzXCI7XG5pbXBvcnQgeyBzdHlsZSB9IGZyb20gXCJzdHlsZWQtc3RyaW5nLWJ1aWxkZXJcIjtcbmltcG9ydCB7IExvZ2dlciwgTG9nZ2luZyB9IGZyb20gXCJAZGVjYWYtdHMvbG9nZ2luZ1wiO1xuaW1wb3J0IHsgcGFyc2UgfSBmcm9tIFwic2hlbGwtcXVvdGVcIjtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gQSBzdGFuZGFyZCBvdXRwdXQgd3JpdGVyIGZvciBoYW5kbGluZyBjb21tYW5kIGV4ZWN1dGlvbiBvdXRwdXQuXG4gKiBAc3VtbWFyeSBUaGlzIGNsYXNzIGltcGxlbWVudHMgdGhlIE91dHB1dFdyaXRlciBpbnRlcmZhY2UgYW5kIHByb3ZpZGVzIG1ldGhvZHMgZm9yXG4gKiBoYW5kbGluZyB2YXJpb3VzIHR5cGVzIG9mIG91dHB1dCBmcm9tIGNvbW1hbmQgZXhlY3V0aW9uLCBpbmNsdWRpbmcgc3RhbmRhcmQgb3V0cHV0LFxuICogZXJyb3Igb3V0cHV0LCBhbmQgZXhpdCBjb2Rlcy4gSXQgYWxzbyBpbmNsdWRlcyB1dGlsaXR5IG1ldGhvZHMgZm9yIHBhcnNpbmcgY29tbWFuZHNcbiAqIGFuZCByZXNvbHZpbmcgb3IgcmVqZWN0aW5nIHByb21pc2VzIGJhc2VkIG9uIGV4ZWN1dGlvbiByZXN1bHRzLlxuICpcbiAqIEB0ZW1wbGF0ZSBSIC0gVGhlIHR5cGUgb2YgdGhlIHJlc29sdmVkIHZhbHVlLCBkZWZhdWx0aW5nIHRvIHN0cmluZy5cbiAqXG4gKiBAcGFyYW0gY21kIC0gVGhlIGNvbW1hbmQgc3RyaW5nIHRvIGJlIGV4ZWN1dGVkLlxuICogQHBhcmFtIGxvY2sgLSBBIFByb21pc2VFeGVjdXRvciB0byBjb250cm9sIHRoZSBhc3luY2hyb25vdXMgZmxvdy5cbiAqIEBwYXJhbSBhcmdzIC0gQWRkaXRpb25hbCBhcmd1bWVudHMgKHVudXNlZCBpbiB0aGUgY3VycmVudCBpbXBsZW1lbnRhdGlvbikuXG4gKlxuICogQGNsYXNzXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogaW1wb3J0IHsgU3RhbmRhcmRPdXRwdXRXcml0ZXIgfSBmcm9tICdAZGVjYWYtdHMvdXRpbHMnO1xuICogaW1wb3J0IHsgUHJvbWlzZUV4ZWN1dG9yIH0gZnJvbSAnQGRlY2FmLXRzL3V0aWxzJztcbiAqXG4gKiAvLyBDcmVhdGUgYSBwcm9taXNlIGV4ZWN1dG9yXG4gKiBjb25zdCBleGVjdXRvcjogUHJvbWlzZUV4ZWN1dG9yPHN0cmluZz4gPSB7XG4gKiAgIHJlc29sdmU6ICh2YWx1ZSkgPT4gY29uc29sZS5sb2coYFJlc29sdmVkOiAke3ZhbHVlfWApLFxuICogICByZWplY3Q6IChlcnJvcikgPT4gY29uc29sZS5lcnJvcihgUmVqZWN0ZWQ6ICR7ZXJyb3IubWVzc2FnZX1gKVxuICogfTtcbiAqXG4gKiAvLyBDcmVhdGUgYSBzdGFuZGFyZCBvdXRwdXQgd3JpdGVyXG4gKiBjb25zdCB3cml0ZXIgPSBuZXcgU3RhbmRhcmRPdXRwdXRXcml0ZXIoJ2xzIC1sYScsIGV4ZWN1dG9yKTtcbiAqXG4gKiAvLyBVc2UgdGhlIHdyaXRlciB0byBoYW5kbGUgY29tbWFuZCBvdXRwdXRcbiAqIHdyaXRlci5kYXRhKCdGaWxlIGxpc3Qgb3V0cHV0Li4uJyk7XG4gKiB3cml0ZXIuZXhpdCgwLCBbJ0NvbW1hbmQgZXhlY3V0ZWQgc3VjY2Vzc2Z1bGx5J10pO1xuICogYGBgXG4gKlxuICogQG1lcm1haWRcbiAqIHNlcXVlbmNlRGlhZ3JhbVxuICogICBwYXJ0aWNpcGFudCBDbGllbnRcbiAqICAgcGFydGljaXBhbnQgU3RhbmRhcmRPdXRwdXRXcml0ZXJcbiAqICAgcGFydGljaXBhbnQgTG9nZ2VyXG4gKiAgIHBhcnRpY2lwYW50IFByb21pc2VFeGVjdXRvclxuICpcbiAqICAgQ2xpZW50LT4+U3RhbmRhcmRPdXRwdXRXcml0ZXI6IG5ldyBTdGFuZGFyZE91dHB1dFdyaXRlcihjbWQsIGxvY2spXG4gKiAgIFN0YW5kYXJkT3V0cHV0V3JpdGVyLT4+TG9nZ2VyOiBMb2dnaW5nLmZvcihjbWQpXG4gKlxuICogICBDbGllbnQtPj5TdGFuZGFyZE91dHB1dFdyaXRlcjogZGF0YShjaHVuaylcbiAqICAgU3RhbmRhcmRPdXRwdXRXcml0ZXItPj5TdGFuZGFyZE91dHB1dFdyaXRlcjogbG9nKFwic3Rkb3V0XCIsIGNodW5rKVxuICogICBTdGFuZGFyZE91dHB1dFdyaXRlci0+PkxvZ2dlcjogbG9nZ2VyLmluZm8obG9nKVxuICpcbiAqICAgQ2xpZW50LT4+U3RhbmRhcmRPdXRwdXRXcml0ZXI6IGVycm9yKGNodW5rKVxuICogICBTdGFuZGFyZE91dHB1dFdyaXRlci0+PlN0YW5kYXJkT3V0cHV0V3JpdGVyOiBsb2coXCJzdGRlcnJcIiwgY2h1bmspXG4gKiAgIFN0YW5kYXJkT3V0cHV0V3JpdGVyLT4+TG9nZ2VyOiBsb2dnZXIuaW5mbyhsb2cpXG4gKlxuICogICBDbGllbnQtPj5TdGFuZGFyZE91dHB1dFdyaXRlcjogZXhpdChjb2RlLCBsb2dzKVxuICogICBTdGFuZGFyZE91dHB1dFdyaXRlci0+PlN0YW5kYXJkT3V0cHV0V3JpdGVyOiBsb2coXCJzdGRvdXRcIiwgZXhpdE1lc3NhZ2UpXG4gKiAgIGFsdCBjb2RlID09PSAwXG4gKiAgICAgU3RhbmRhcmRPdXRwdXRXcml0ZXItPj5TdGFuZGFyZE91dHB1dFdyaXRlcjogcmVzb2x2ZShsb2dzKVxuICogICAgIFN0YW5kYXJkT3V0cHV0V3JpdGVyLT4+UHJvbWlzZUV4ZWN1dG9yOiBsb2NrLnJlc29sdmUocmVhc29uKVxuICogICBlbHNlIGNvZGUgIT09IDBcbiAqICAgICBTdGFuZGFyZE91dHB1dFdyaXRlci0+PlN0YW5kYXJkT3V0cHV0V3JpdGVyOiByZWplY3QoZXJyb3IpXG4gKiAgICAgU3RhbmRhcmRPdXRwdXRXcml0ZXItPj5Qcm9taXNlRXhlY3V0b3I6IGxvY2sucmVqZWN0KHJlYXNvbilcbiAqICAgZW5kXG4gKi9cbmV4cG9ydCBjbGFzcyBTdGFuZGFyZE91dHB1dFdyaXRlcjxSID0gc3RyaW5nPiBpbXBsZW1lbnRzIE91dHB1dFdyaXRlciB7XG4gIHByb3RlY3RlZCBsb2dnZXI6IExvZ2dlcjtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcm90ZWN0ZWQgY21kOiBzdHJpbmcsXG4gICAgcHJvdGVjdGVkIGxvY2s6IFByb21pc2VFeGVjdXRvcjxSPixcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVudXNlZC12YXJzXG4gICAgLi4uYXJnczogdW5rbm93bltdXG4gICkge1xuICAgIHRoaXMubG9nZ2VyID0gTG9nZ2luZy5mb3IodGhpcy5jbWQpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBMb2dzIG91dHB1dCB0byB0aGUgY29uc29sZS5cbiAgICogQHN1bW1hcnkgRm9ybWF0cyBhbmQgbG9ncyB0aGUgZ2l2ZW4gZGF0YSB3aXRoIGEgdGltZXN0YW1wIGFuZCB0eXBlIGluZGljYXRvci5cbiAgICpcbiAgICogQHBhcmFtIHR5cGUgLSBUaGUgdHlwZSBvZiBvdXRwdXQgKHN0ZG91dCBvciBzdGRlcnIpLlxuICAgKiBAcGFyYW0gZGF0YSAtIFRoZSBkYXRhIHRvIGJlIGxvZ2dlZC5cbiAgICovXG4gIHByb3RlY3RlZCBsb2codHlwZTogT3V0cHV0VHlwZSwgZGF0YTogc3RyaW5nIHwgQnVmZmVyKSB7XG4gICAgZGF0YSA9IEJ1ZmZlci5pc0J1ZmZlcihkYXRhKSA/IGRhdGEudG9TdHJpbmcoRW5jb2RpbmcpIDogZGF0YTtcbiAgICBjb25zdCBsb2cgPSB0eXBlID09PSBcInN0ZGVyclwiID8gc3R5bGUoZGF0YSkucmVkLnRleHQgOiBkYXRhO1xuICAgIHRoaXMubG9nZ2VyLmluZm8obG9nKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gSGFuZGxlcyBzdGFuZGFyZCBvdXRwdXQgZGF0YS5cbiAgICogQHN1bW1hcnkgTG9ncyB0aGUgZ2l2ZW4gY2h1bmsgYXMgc3RhbmRhcmQgb3V0cHV0LlxuICAgKlxuICAgKiBAcGFyYW0gY2h1bmsgLSBUaGUgZGF0YSBjaHVuayB0byBiZSBsb2dnZWQuXG4gICAqL1xuICBkYXRhKGNodW5rOiBhbnkpIHtcbiAgICB0aGlzLmxvZyhcInN0ZG91dFwiLCBTdHJpbmcoY2h1bmspKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gSGFuZGxlcyBlcnJvciBvdXRwdXQgZGF0YS5cbiAgICogQHN1bW1hcnkgTG9ncyB0aGUgZ2l2ZW4gY2h1bmsgYXMgZXJyb3Igb3V0cHV0LlxuICAgKlxuICAgKiBAcGFyYW0gY2h1bmsgLSBUaGUgZXJyb3IgZGF0YSBjaHVuayB0byBiZSBsb2dnZWQuXG4gICAqL1xuICBlcnJvcihjaHVuazogYW55KSB7XG4gICAgdGhpcy5sb2coXCJzdGRlcnJcIiwgU3RyaW5nKGNodW5rKSk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEhhbmRsZXMgZXJyb3Igb2JqZWN0cy5cbiAgICogQHN1bW1hcnkgTG9ncyB0aGUgZXJyb3IgbWVzc2FnZSBmcm9tIHRoZSBnaXZlbiBFcnJvciBvYmplY3QuXG4gICAqXG4gICAqIEBwYXJhbSBlcnIgLSBUaGUgRXJyb3Igb2JqZWN0IHRvIGJlIGxvZ2dlZC5cbiAgICovXG4gIGVycm9ycyhlcnI6IEVycm9yKSB7XG4gICAgdGhpcy5sb2coXCJzdGRlcnJcIiwgYEVycm9yIGV4ZWN1dGluZyBjb21tYW5kIGV4aXRlZCA6ICR7ZXJyfWApO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBIYW5kbGVzIHRoZSBleGl0IG9mIGEgY29tbWFuZC5cbiAgICogQHN1bW1hcnkgTG9ncyB0aGUgZXhpdCBjb2RlIGFuZCByZXNvbHZlcyBvciByZWplY3RzIHRoZSBwcm9taXNlIGJhc2VkIG9uIHRoZSBjb2RlLlxuICAgKlxuICAgKiBAcGFyYW0gY29kZSAtIFRoZSBleGl0IGNvZGUgb2YgdGhlIGNvbW1hbmQuXG4gICAqIEBwYXJhbSBsb2dzIC0gQXJyYXkgb2YgbG9nIG1lc3NhZ2VzIHRvIGJlIHByb2Nlc3NlZCBiZWZvcmUgZXhpdGluZy5cbiAgICovXG4gIGV4aXQoY29kZTogbnVtYmVyIHwgc3RyaW5nLCBsb2dzOiBzdHJpbmdbXSkge1xuICAgIHRoaXMubG9nKFxuICAgICAgXCJzdGRvdXRcIixcbiAgICAgIGBjb21tYW5kIGV4aXRlZCBjb2RlIDogJHtjb2RlID09PSAwID8gc3R5bGUoY29kZS50b1N0cmluZygpKS5ncmVlbi50ZXh0IDogc3R5bGUoY29kZSA9PT0gbnVsbCA/IFwibnVsbFwiIDogY29kZS50b1N0cmluZygpKS5yZWQudGV4dH1gXG4gICAgKTtcbiAgICBpZiAoY29kZSA9PT0gMCkge1xuICAgICAgdGhpcy5yZXNvbHZlKGxvZ3MubWFwKChsKSA9PiBsLnRyaW0oKSkuam9pbihcIlxcblwiKSBhcyBSKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5yZWplY3QobmV3IEVycm9yKGxvZ3MubGVuZ3RoID8gbG9ncy5qb2luKFwiXFxuXCIpIDogY29kZS50b1N0cmluZygpKSk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBQYXJzZXMgYSBjb21tYW5kIHN0cmluZyBvciBhcnJheSBpbnRvIGNvbXBvbmVudHMuXG4gICAqIEBzdW1tYXJ5IENvbnZlcnRzIHRoZSBjb21tYW5kIGludG8gYSBjb25zaXN0ZW50IGZvcm1hdCBhbmQgc3RvcmVzIGl0LCB0aGVuIHJldHVybnMgaXQgc3BsaXQgaW50byBjb21tYW5kIGFuZCBhcmd1bWVudHMuXG4gICAqXG4gICAqIEBwYXJhbSBjb21tYW5kIC0gVGhlIGNvbW1hbmQgYXMgYSBzdHJpbmcgb3IgYXJyYXkgb2Ygc3RyaW5ncy5cbiAgICogQHJldHVybiBBIHR1cGxlIGNvbnRhaW5pbmcgdGhlIGNvbW1hbmQgYW5kIGl0cyBhcmd1bWVudHMgYXMgc2VwYXJhdGUgZWxlbWVudHMuXG4gICAqL1xuICBwYXJzZUNvbW1hbmQoY29tbWFuZDogc3RyaW5nIHwgc3RyaW5nW10pOiBbc3RyaW5nLCBzdHJpbmdbXV0ge1xuICAgIGlmIChBcnJheS5pc0FycmF5KGNvbW1hbmQpKSB7XG4gICAgICB0aGlzLmNtZCA9IGNvbW1hbmQuam9pbihcIiBcIik7XG4gICAgICByZXR1cm4gW2NvbW1hbmRbMF0sIGNvbW1hbmQuc2xpY2UoMSldO1xuICAgIH1cblxuICAgIGNvbnN0IHBhcnRzID0gcGFyc2UoY29tbWFuZClcbiAgICAgIC5maWx0ZXIoKHApID0+IHR5cGVvZiBwID09PSBcInN0cmluZ1wiKVxuICAgICAgLm1hcChTdHJpbmcpO1xuXG4gICAgdGhpcy5jbWQgPSBwYXJ0cy5qb2luKFwiIFwiKTtcbiAgICByZXR1cm4gW3BhcnRzWzBdLCBwYXJ0cy5zbGljZSgxKV07XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFJlc29sdmVzIHRoZSBwcm9taXNlIHdpdGggYSBzdWNjZXNzIG1lc3NhZ2UuXG4gICAqIEBzdW1tYXJ5IExvZ3MgYSBzdWNjZXNzIG1lc3NhZ2UgYW5kIHJlc29sdmVzIHRoZSBwcm9taXNlIHdpdGggdGhlIGdpdmVuIHJlYXNvbi5cbiAgICpcbiAgICogQHBhcmFtIHJlYXNvbiAtIFRoZSByZWFzb24gZm9yIHJlc29sdmluZyB0aGUgcHJvbWlzZS5cbiAgICovXG4gIHByb3RlY3RlZCByZXNvbHZlKHJlYXNvbjogUikge1xuICAgIHRoaXMubG9nKFxuICAgICAgXCJzdGRvdXRcIixcbiAgICAgIGAke3RoaXMuY21kfSBleGVjdXRlZCBzdWNjZXNzZnVsbHk6ICR7c3R5bGUocmVhc29uID8gXCJyYW4gdG8gY29tcGxldGlvblwiIDogKHJlYXNvbiBhcyBzdHJpbmcpKS5ncmVlbn1gXG4gICAgKTtcbiAgICB0aGlzLmxvY2sucmVzb2x2ZShyZWFzb24pO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBSZWplY3RzIHRoZSBwcm9taXNlIHdpdGggYW4gZXJyb3IgbWVzc2FnZS5cbiAgICogQHN1bW1hcnkgTG9ncyBhbiBlcnJvciBtZXNzYWdlIGFuZCByZWplY3RzIHRoZSBwcm9taXNlIHdpdGggdGhlIGdpdmVuIHJlYXNvbi5cbiAgICpcbiAgICogQHBhcmFtIHJlYXNvbiAtIFRoZSByZWFzb24gZm9yIHJlamVjdGluZyB0aGUgcHJvbWlzZSwgZWl0aGVyIGEgbnVtYmVyIChleGl0IGNvZGUpIG9yIGEgc3RyaW5nLlxuICAgKi9cbiAgcHJvdGVjdGVkIHJlamVjdChyZWFzb246IG51bWJlciB8IHN0cmluZyB8IEVycm9yKSB7XG4gICAgaWYgKCEocmVhc29uIGluc3RhbmNlb2YgRXJyb3IpKSB7XG4gICAgICByZWFzb24gPSBuZXcgRXJyb3IoXG4gICAgICAgIHR5cGVvZiByZWFzb24gPT09IFwibnVtYmVyXCIgPyBgRXhpdCBjb2RlICR7cmVhc29ufWAgOiByZWFzb25cbiAgICAgICk7XG4gICAgfVxuICAgIHRoaXMubG9nKFxuICAgICAgXCJzdGRlcnJcIixcbiAgICAgIGAke3RoaXMuY21kfSBmYWlsZWQgdG8gZXhlY3V0ZTogJHtzdHlsZShyZWFzb24ubWVzc2FnZSkucmVkfWBcbiAgICApO1xuICAgIHRoaXMubG9jay5yZWplY3QocmVhc29uKTtcbiAgfVxufVxuIiwiaW1wb3J0IHtcbiAgQ2hpbGRQcm9jZXNzV2l0aG91dE51bGxTdHJlYW1zLFxuICBzcGF3bixcbiAgU3Bhd25PcHRpb25zV2l0aG91dFN0ZGlvLFxufSBmcm9tIFwiY2hpbGRfcHJvY2Vzc1wiO1xuaW1wb3J0IHsgU3RhbmRhcmRPdXRwdXRXcml0ZXIgfSBmcm9tIFwiLi4vd3JpdGVycy9TdGFuZGFyZE91dHB1dFdyaXRlclwiO1xuaW1wb3J0IHsgQ29tbWFuZFJlc3VsdCB9IGZyb20gXCIuL3R5cGVzXCI7XG5pbXBvcnQgeyBPdXRwdXRXcml0ZXJDb25zdHJ1Y3RvciB9IGZyb20gXCIuLi93cml0ZXJzL3R5cGVzXCI7XG5pbXBvcnQgeyBBYm9ydENvZGUgfSBmcm9tIFwiLi9jb25zdGFudHNcIjtcbmltcG9ydCB7IExvZ2dlciwgTG9nZ2luZyB9IGZyb20gXCJAZGVjYWYtdHMvbG9nZ2luZ1wiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBDcmVhdGVzIGEgbG9ja2VkIHZlcnNpb24gb2YgYSBmdW5jdGlvbi5cbiAqIEBzdW1tYXJ5IFRoaXMgaGlnaGVyLW9yZGVyIGZ1bmN0aW9uIHRha2VzIGEgZnVuY3Rpb24gYW5kIHJldHVybnMgYSBuZXcgZnVuY3Rpb24gdGhhdCBlbnN1cmVzXG4gKiBzZXF1ZW50aWFsIGV4ZWN1dGlvbiBvZiB0aGUgb3JpZ2luYWwgZnVuY3Rpb24sIGV2ZW4gd2hlbiBjYWxsZWQgbXVsdGlwbGUgdGltZXMgY29uY3VycmVudGx5LlxuICogSXQgdXNlcyBhIFByb21pc2UtYmFzZWQgbG9ja2luZyBtZWNoYW5pc20gdG8gcXVldWUgZnVuY3Rpb24gY2FsbHMuXG4gKlxuICogQHRlbXBsYXRlIFIgLSBUaGUgcmV0dXJuIHR5cGUgb2YgdGhlIGlucHV0IGZ1bmN0aW9uLlxuICpcbiAqIEBwYXJhbSBmIC0gVGhlIGZ1bmN0aW9uIHRvIGJlIGxvY2tlZC4gSXQgY2FuIHRha2UgYW55IG51bWJlciBvZiBwYXJhbWV0ZXJzIGFuZCByZXR1cm4gYSB2YWx1ZSBvZiB0eXBlIFIuXG4gKiBAcmV0dXJuIEEgbmV3IGZ1bmN0aW9uIHdpdGggdGhlIHNhbWUgc2lnbmF0dXJlIGFzIHRoZSBpbnB1dCBmdW5jdGlvbiwgYnV0IHdpdGggc2VxdWVudGlhbCBleGVjdXRpb24gZ3VhcmFudGVlZC5cbiAqXG4gKiBAZnVuY3Rpb24gbG9ja2lmeVxuICpcbiAqIEBtZXJtYWlkXG4gKiBzZXF1ZW5jZURpYWdyYW1cbiAqICAgcGFydGljaXBhbnQgQ2FsbGVyXG4gKiAgIHBhcnRpY2lwYW50IExvY2tlZEZ1bmN0aW9uXG4gKiAgIHBhcnRpY2lwYW50IE9yaWdpbmFsRnVuY3Rpb25cbiAqICAgQ2FsbGVyLT4+TG9ja2VkRnVuY3Rpb246IENhbGwgd2l0aCBwYXJhbXNcbiAqICAgTG9ja2VkRnVuY3Rpb24tPj5Mb2NrZWRGdW5jdGlvbjogQ2hlY2sgY3VycmVudCBsb2NrXG4gKiAgIGFsdCBMb2NrIGlzIHJlc29sdmVkXG4gKiAgICAgTG9ja2VkRnVuY3Rpb24tPj5PcmlnaW5hbEZ1bmN0aW9uOiBFeGVjdXRlIHdpdGggcGFyYW1zXG4gKiAgICAgT3JpZ2luYWxGdW5jdGlvbi0tPj5Mb2NrZWRGdW5jdGlvbjogUmV0dXJuIHJlc3VsdFxuICogICAgIExvY2tlZEZ1bmN0aW9uLS0+PkNhbGxlcjogUmV0dXJuIHJlc3VsdFxuICogICBlbHNlIExvY2sgaXMgcGVuZGluZ1xuICogICAgIExvY2tlZEZ1bmN0aW9uLT4+TG9ja2VkRnVuY3Rpb246IFF1ZXVlIGV4ZWN1dGlvblxuICogICAgIExvY2tlZEZ1bmN0aW9uLS0+PkNhbGxlcjogUmV0dXJuIHByb21pc2VcbiAqICAgICBOb3RlIG92ZXIgTG9ja2VkRnVuY3Rpb246IFdhaXQgZm9yIHByZXZpb3VzIGV4ZWN1dGlvblxuICogICAgIExvY2tlZEZ1bmN0aW9uLT4+T3JpZ2luYWxGdW5jdGlvbjogRXhlY3V0ZSB3aXRoIHBhcmFtc1xuICogICAgIE9yaWdpbmFsRnVuY3Rpb24tLT4+TG9ja2VkRnVuY3Rpb246IFJldHVybiByZXN1bHRcbiAqICAgICBMb2NrZWRGdW5jdGlvbi0tPj5DYWxsZXI6IFJlc29sdmUgcHJvbWlzZSB3aXRoIHJlc3VsdFxuICogICBlbmRcbiAqICAgTG9ja2VkRnVuY3Rpb24tPj5Mb2NrZWRGdW5jdGlvbjogVXBkYXRlIGxvY2tcbiAqXG4gKiBAbWVtYmVyT2YgbW9kdWxlOnV0aWxzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBsb2NraWZ5PFI+KGY6ICguLi5wYXJhbXM6IHVua25vd25bXSkgPT4gUikge1xuICBsZXQgbG9jazogUHJvbWlzZTxSIHwgdm9pZD4gPSBQcm9taXNlLnJlc29sdmUoKTtcbiAgcmV0dXJuICguLi5wYXJhbXM6IHVua25vd25bXSkgPT4ge1xuICAgIGNvbnN0IHJlc3VsdCA9IGxvY2sudGhlbigoKSA9PiBmKC4uLnBhcmFtcykpO1xuICAgIGxvY2sgPSByZXN1bHQuY2F0Y2goKCkgPT4ge30pO1xuICAgIHJldHVybiByZXN1bHQ7XG4gIH07XG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIENoYWlucyBtdWx0aXBsZSBhYm9ydCBzaWduYWxzIHRvIGEgY29udHJvbGxlci5cbiAqIEBzdW1tYXJ5IENyZWF0ZXMgYSBtZWNoYW5pc20gd2hlcmUgbXVsdGlwbGUgYWJvcnQgc2lnbmFscyBjYW4gdHJpZ2dlciBhIHNpbmdsZSBhYm9ydCBjb250cm9sbGVyLlxuICogVGhpcyBpcyB1c2VmdWwgZm9yIGNvb3JkaW5hdGluZyBjYW5jZWxsYXRpb24gYWNyb3NzIG11bHRpcGxlIGFzeW5jaHJvbm91cyBvcGVyYXRpb25zLlxuICpcbiAqIEBwYXJhbSB7QWJvcnRDb250cm9sbGVyfSBjb250cm9sbGVyIC0gVGhlIGFib3J0IGNvbnRyb2xsZXIgdG8gYmUgdHJpZ2dlcmVkIGJ5IHNpZ25hbHMuXG4gKiBAcGFyYW0gey4uLkFib3J0U2lnbmFsfSBzaWduYWxzIC0gT25lIG9yIG1vcmUgYWJvcnQgc2lnbmFscyB0aGF0IGNhbiB0cmlnZ2VyIHRoZSBjb250cm9sbGVyLlxuICogQHJldHVybiB7QWJvcnRDb250cm9sbGVyfSBUaGUgaW5wdXQgY29udHJvbGxlciwgbm93IGNvbm5lY3RlZCB0byB0aGUgc2lnbmFscy5cbiAqXG4gKiBAZnVuY3Rpb24gY2hhaW5BYm9ydENvbnRyb2xsZXJcbiAqXG4gKiBAbWVtYmVyT2YgbW9kdWxlOnV0aWxzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjaGFpbkFib3J0Q29udHJvbGxlcihcbiAgY29udHJvbGxlcjogQWJvcnRDb250cm9sbGVyLFxuICAuLi5zaWduYWxzOiBBYm9ydFNpZ25hbFtdXG4pOiBBYm9ydENvbnRyb2xsZXI7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIENyZWF0ZXMgYSBuZXcgY29udHJvbGxlciBjaGFpbmVkIHRvIG11bHRpcGxlIGFib3J0IHNpZ25hbHMuXG4gKiBAc3VtbWFyeSBDcmVhdGVzIGEgbmV3IGFib3J0IGNvbnRyb2xsZXIgdGhhdCB3aWxsIGJlIHRyaWdnZXJlZCBpZiBhbnkgb2YgdGhlIHByb3ZpZGVkIHNpZ25hbHMgYXJlIGFib3J0ZWQuXG4gKlxuICogQHBhcmFtIHsuLi5BYm9ydFNpZ25hbH0gc2lnbmFscyAtIE9uZSBvciBtb3JlIGFib3J0IHNpZ25hbHMgdGhhdCBjYW4gdHJpZ2dlciB0aGUgbmV3IGNvbnRyb2xsZXIuXG4gKiBAcmV0dXJuIHtBYm9ydENvbnRyb2xsZXJ9IEEgbmV3IGFib3J0IGNvbnRyb2xsZXIgY29ubmVjdGVkIHRvIHRoZSBzaWduYWxzLlxuICpcbiAqIEBmdW5jdGlvbiBjaGFpbkFib3J0Q29udHJvbGxlclxuICpcbiAqIEBtZW1iZXJPZiBtb2R1bGU6dXRpbHNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNoYWluQWJvcnRDb250cm9sbGVyKFxuICAuLi5zaWduYWxzOiBBYm9ydFNpZ25hbFtdXG4pOiBBYm9ydENvbnRyb2xsZXI7XG5cbmV4cG9ydCBmdW5jdGlvbiBjaGFpbkFib3J0Q29udHJvbGxlcihcbiAgYXJndW1lbnQwOiBBYm9ydENvbnRyb2xsZXIgfCBBYm9ydFNpZ25hbCxcbiAgLi4ucmVtYWluZGVyOiBBYm9ydFNpZ25hbFtdXG4pOiBBYm9ydENvbnRyb2xsZXIge1xuICBsZXQgc2lnbmFsczogQWJvcnRTaWduYWxbXTtcbiAgbGV0IGNvbnRyb2xsZXI6IEFib3J0Q29udHJvbGxlcjtcblxuICAvLyBub3JtYWxpemUgYXJnc1xuICBpZiAoYXJndW1lbnQwIGluc3RhbmNlb2YgQWJvcnRTaWduYWwpIHtcbiAgICBjb250cm9sbGVyID0gbmV3IEFib3J0Q29udHJvbGxlcigpO1xuICAgIHNpZ25hbHMgPSBbYXJndW1lbnQwLCAuLi5yZW1haW5kZXJdO1xuICB9IGVsc2Uge1xuICAgIGNvbnRyb2xsZXIgPSBhcmd1bWVudDA7XG4gICAgc2lnbmFscyA9IHJlbWFpbmRlcjtcbiAgfVxuXG4gIC8vIGlmIHRoZSBjb250cm9sbGVyIGlzIGFscmVhZHkgYWJvcnRlZCwgZXhpdCBlYXJseVxuICBpZiAoY29udHJvbGxlci5zaWduYWwuYWJvcnRlZCkge1xuICAgIHJldHVybiBjb250cm9sbGVyO1xuICB9XG5cbiAgY29uc3QgaGFuZGxlciA9ICgpID0+IGNvbnRyb2xsZXIuYWJvcnQoKTtcblxuICBmb3IgKGNvbnN0IHNpZ25hbCBvZiBzaWduYWxzKSB7XG4gICAgLy8gY2hlY2sgYmVmb3JlIGFkZGluZyEgKGFuZCBhc3N1bWUgdGhlcmUgaXMgbm8gcG9zc2libGUgd2F5IHRoYXQgdGhlIHNpZ25hbCBjb3VsZFxuICAgIC8vIGFib3J0IGJldHdlZW4gdGhlIGBpZmAgY2hlY2sgYW5kIGFkZGluZyB0aGUgZXZlbnQgbGlzdGVuZXIpXG4gICAgaWYgKHNpZ25hbC5hYm9ydGVkKSB7XG4gICAgICBjb250cm9sbGVyLmFib3J0KCk7XG4gICAgICBicmVhaztcbiAgICB9XG4gICAgc2lnbmFsLmFkZEV2ZW50TGlzdGVuZXIoXCJhYm9ydFwiLCBoYW5kbGVyLCB7XG4gICAgICBvbmNlOiB0cnVlLFxuICAgICAgc2lnbmFsOiBjb250cm9sbGVyLnNpZ25hbCxcbiAgICB9KTtcbiAgfVxuXG4gIHJldHVybiBjb250cm9sbGVyO1xufVxuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBTcGF3bnMgYSBjb21tYW5kIGFzIGEgY2hpbGQgcHJvY2VzcyB3aXRoIG91dHB1dCBoYW5kbGluZy5cbiAqIEBzdW1tYXJ5IENyZWF0ZXMgYSBjaGlsZCBwcm9jZXNzIHRvIGV4ZWN1dGUgYSBjb21tYW5kIHdpdGggc3VwcG9ydCBmb3IgcGlwaW5nIG11bHRpcGxlIGNvbW1hbmRzLFxuICogY3VzdG9tIG91dHB1dCBoYW5kbGluZywgYW5kIGFib3J0IGNvbnRyb2wuIFRoaXMgZnVuY3Rpb24gaGFuZGxlcyB0aGUgbG93LWxldmVsIGRldGFpbHMgb2ZcbiAqIHNwYXduaW5nIHByb2Nlc3NlcyBhbmQgY29ubmVjdGluZyB0aGVpciBpbnB1dHMvb3V0cHV0cyB3aGVuIHBpcGluZyBpcyB1c2VkLlxuICpcbiAqIEB0ZW1wbGF0ZSBSIC0gVGhlIHR5cGUgb2YgdGhlIHByb2Nlc3NlZCBvdXRwdXQsIGRlZmF1bHRpbmcgdG8gc3RyaW5nLlxuICogQHBhcmFtIHtTdGFuZGFyZE91dHB1dFdyaXRlcjxSPn0gb3V0cHV0IC0gVGhlIG91dHB1dCB3cml0ZXIgdG8gaGFuZGxlIGNvbW1hbmQgb3V0cHV0LlxuICogQHBhcmFtIHtzdHJpbmd9IGNvbW1hbmQgLSBUaGUgY29tbWFuZCB0byBleGVjdXRlLCBjYW4gaW5jbHVkZSBwaXBlIG9wZXJhdG9ycy5cbiAqIEBwYXJhbSB7U3Bhd25PcHRpb25zV2l0aG91dFN0ZGlvfSBvcHRzIC0gT3B0aW9ucyBmb3IgdGhlIHNwYXduZWQgcHJvY2Vzcy5cbiAqIEBwYXJhbSB7QWJvcnRDb250cm9sbGVyfSBhYm9ydCAtIENvbnRyb2xsZXIgdG8gYWJvcnQgdGhlIGNvbW1hbmQgZXhlY3V0aW9uLlxuICogQHBhcmFtIHtMb2dnZXJ9IGxvZ2dlciAtIExvZ2dlciBmb3IgcmVjb3JkaW5nIGNvbW1hbmQgZXhlY3V0aW9uIGRldGFpbHMuXG4gKiBAcmV0dXJuIHtDaGlsZFByb2Nlc3NXaXRob3V0TnVsbFN0cmVhbXN9IFRoZSBzcGF3bmVkIGNoaWxkIHByb2Nlc3MuXG4gKlxuICogQGZ1bmN0aW9uIHNwYXduQ29tbWFuZFxuICpcbiAqIEBtZW1iZXJPZiBtb2R1bGU6dXRpbHNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNwYXduQ29tbWFuZDxSID0gc3RyaW5nPihcbiAgb3V0cHV0OiBTdGFuZGFyZE91dHB1dFdyaXRlcjxSPixcbiAgY29tbWFuZDogc3RyaW5nLFxuICBvcHRzOiBTcGF3bk9wdGlvbnNXaXRob3V0U3RkaW8sXG4gIGFib3J0OiBBYm9ydENvbnRyb2xsZXIsXG4gIGxvZ2dlcjogTG9nZ2VyXG4pOiBDaGlsZFByb2Nlc3NXaXRob3V0TnVsbFN0cmVhbXMge1xuICBmdW5jdGlvbiBzcGF3bklubmVyKGNvbW1hbmQ6IHN0cmluZywgY29udHJvbGxlcjogQWJvcnRDb250cm9sbGVyKSB7XG4gICAgY29uc3QgW2NtZCwgYXJnel0gPSBvdXRwdXQucGFyc2VDb21tYW5kKGNvbW1hbmQpO1xuICAgIGxvZ2dlci5pbmZvKGBSdW5uaW5nIGNvbW1hbmQ6ICR7Y21kfWApO1xuICAgIGxvZ2dlci5kZWJ1Zyhgd2l0aCBhcmdzOiAke2FyZ3ouam9pbihcIiBcIil9YCk7XG4gICAgY29uc3QgY2hpbGRQcm9jZXNzID0gc3Bhd24oY21kLCBhcmd6LCB7XG4gICAgICAuLi5vcHRzLFxuICAgICAgY3dkOiBvcHRzLmN3ZCB8fCBwcm9jZXNzLmN3ZCgpLFxuICAgICAgZW52OiBPYmplY3QuYXNzaWduKHt9LCBwcm9jZXNzLmVudiwgb3B0cy5lbnYsIHsgUEFUSDogcHJvY2Vzcy5lbnYuUEFUSCB9KSxcbiAgICAgIHNoZWxsOiBvcHRzLnNoZWxsIHx8IGZhbHNlLFxuICAgICAgc2lnbmFsOiBjb250cm9sbGVyLnNpZ25hbCxcbiAgICB9KTtcbiAgICBsb2dnZXIudmVyYm9zZShgcGlkIDogJHtjaGlsZFByb2Nlc3MucGlkfWApO1xuICAgIHJldHVybiBjaGlsZFByb2Nlc3M7XG4gIH1cblxuICBjb25zdCBtID0gY29tbWFuZC5tYXRjaCgvWzw+JCNdL2cpO1xuICBpZiAobSlcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICBgSW52YWxpZCBjb21tYW5kOiAke2NvbW1hbmR9LiBjb250YWlucyBpbnZhbGlkIGNoYXJhY3RlcnM6ICR7bX1gXG4gICAgKTtcbiAgaWYgKGNvbW1hbmQuaW5jbHVkZXMoXCIgfCBcIikpIHtcbiAgICBjb25zdCBjbWRzID0gY29tbWFuZC5zcGxpdChcIiB8IFwiKTtcbiAgICBjb25zdCBzcGF3bnMgPSBbXTtcbiAgICBjb25zdCBjb250cm9sbGVycyA9IG5ldyBBcnJheShjbWRzLmxlbmd0aCk7XG4gICAgY29udHJvbGxlcnNbMF0gPSBhYm9ydDtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGNtZHMubGVuZ3RoOyBpKyspIHtcbiAgICAgIGlmIChpICE9PSAwKVxuICAgICAgICBjb250cm9sbGVyc1tpXSA9IGNoYWluQWJvcnRDb250cm9sbGVyKGNvbnRyb2xsZXJzW2kgLSAxXS5zaWduYWwpO1xuICAgICAgc3Bhd25zLnB1c2goc3Bhd25Jbm5lcihjbWRzW2ldLCBjb250cm9sbGVyc1tpXSkpO1xuICAgICAgaWYgKGkgPT09IDApIGNvbnRpbnVlO1xuICAgICAgc3Bhd25zW2kgLSAxXS5zdGRvdXQucGlwZShzcGF3bnNbaV0uc3RkaW4pO1xuICAgIH1cbiAgICByZXR1cm4gc3Bhd25zW2NtZHMubGVuZ3RoIC0gMV07XG4gIH1cblxuICByZXR1cm4gc3Bhd25Jbm5lcihjb21tYW5kLCBhYm9ydCk7XG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIEV4ZWN1dGVzIGEgY29tbWFuZCBhc3luY2hyb25vdXNseSB3aXRoIGN1c3RvbWl6YWJsZSBvdXRwdXQgaGFuZGxpbmcuXG4gKiBAc3VtbWFyeSBUaGlzIGZ1bmN0aW9uIHJ1bnMgYSBzaGVsbCBjb21tYW5kIGFzIGEgY2hpbGQgcHJvY2VzcywgcHJvdmlkaW5nIGZpbmUtZ3JhaW5lZFxuICogY29udHJvbCBvdmVyIGl0cyBleGVjdXRpb24gYW5kIG91dHB1dCBoYW5kbGluZy4gSXQgc3VwcG9ydHMgY3VzdG9tIG91dHB1dCB3cml0ZXJzLFxuICogYWxsb3dzIGZvciBjb21tYW5kIGFib3J0aW9uLCBhbmQgY2FwdHVyZXMgYm90aCBzdGRvdXQgYW5kIHN0ZGVyci5cbiAqXG4gKiBAdGVtcGxhdGUgUiAtIFRoZSB0eXBlIG9mIHRoZSByZXNvbHZlZCB2YWx1ZSBmcm9tIHRoZSBjb21tYW5kIGV4ZWN1dGlvbi5cbiAqXG4gKiBAcGFyYW0gY29tbWFuZCAtIFRoZSBjb21tYW5kIHRvIHJ1biwgZWl0aGVyIGFzIGEgc3RyaW5nIG9yIGFuIGFycmF5IG9mIHN0cmluZ3MuXG4gKiBAcGFyYW0gb3B0cyAtIFNwYXduIG9wdGlvbnMgZm9yIHRoZSBjaGlsZCBwcm9jZXNzLiBEZWZhdWx0cyB0byBhbiBlbXB0eSBvYmplY3QuXG4gKiBAcGFyYW0gb3V0cHV0Q29uc3RydWN0b3IgLSBDb25zdHJ1Y3RvciBmb3IgdGhlIG91dHB1dCB3cml0ZXIuIERlZmF1bHRzIHRvIFN0YW5kYXJkT3V0cHV0V3JpdGVyLlxuICogQHBhcmFtIGFyZ3MgLSBBZGRpdGlvbmFsIGFyZ3VtZW50cyB0byBwYXNzIHRvIHRoZSBvdXRwdXQgY29uc3RydWN0b3IuXG4gKiBAcmV0dXJuIHtDb21tYW5kUmVzdWx0fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgY29tbWFuZCByZXN1bHQgb2YgdHlwZSBSLlxuICpcbiAqIEBmdW5jdGlvbiBydW5Db21tYW5kXG4gKlxuICogQG1lcm1haWRcbiAqIHNlcXVlbmNlRGlhZ3JhbVxuICogICBwYXJ0aWNpcGFudCBDYWxsZXJcbiAqICAgcGFydGljaXBhbnQgcnVuQ29tbWFuZFxuICogICBwYXJ0aWNpcGFudCBPdXRwdXRXcml0ZXJcbiAqICAgcGFydGljaXBhbnQgQ2hpbGRQcm9jZXNzXG4gKiAgIENhbGxlci0+PnJ1bkNvbW1hbmQ6IENhbGwgd2l0aCBjb21tYW5kIGFuZCBvcHRpb25zXG4gKiAgIHJ1bkNvbW1hbmQtPj5PdXRwdXRXcml0ZXI6IENyZWF0ZSBuZXcgaW5zdGFuY2VcbiAqICAgcnVuQ29tbWFuZC0+Pk91dHB1dFdyaXRlcjogUGFyc2UgY29tbWFuZFxuICogICBydW5Db21tYW5kLT4+Q2hpbGRQcm9jZXNzOiBTcGF3biBwcm9jZXNzXG4gKiAgIENoaWxkUHJvY2Vzcy0tPj5ydW5Db21tYW5kOiBSZXR1cm4gcHJvY2VzcyBvYmplY3RcbiAqICAgcnVuQ29tbWFuZC0+PkNoaWxkUHJvY2VzczogU2V0IHVwIGV2ZW50IGxpc3RlbmVyc1xuICogICBsb29wIEZvciBlYWNoIHN0ZG91dCBkYXRhXG4gKiAgICAgQ2hpbGRQcm9jZXNzLT4+cnVuQ29tbWFuZDogRW1pdCBzdGRvdXQgZGF0YVxuICogICAgIHJ1bkNvbW1hbmQtPj5PdXRwdXRXcml0ZXI6IEhhbmRsZSBzdGRvdXQgZGF0YVxuICogICBlbmRcbiAqICAgbG9vcCBGb3IgZWFjaCBzdGRlcnIgZGF0YVxuICogICAgIENoaWxkUHJvY2Vzcy0+PnJ1bkNvbW1hbmQ6IEVtaXQgc3RkZXJyIGRhdGFcbiAqICAgICBydW5Db21tYW5kLT4+T3V0cHV0V3JpdGVyOiBIYW5kbGUgc3RkZXJyIGRhdGFcbiAqICAgZW5kXG4gKiAgIENoaWxkUHJvY2Vzcy0+PnJ1bkNvbW1hbmQ6IEVtaXQgZXJyb3IgKGlmIGFueSlcbiAqICAgcnVuQ29tbWFuZC0+Pk91dHB1dFdyaXRlcjogSGFuZGxlIGVycm9yXG4gKiAgIENoaWxkUHJvY2Vzcy0+PnJ1bkNvbW1hbmQ6IEVtaXQgZXhpdFxuICogICBydW5Db21tYW5kLT4+T3V0cHV0V3JpdGVyOiBIYW5kbGUgZXhpdFxuICogICBPdXRwdXRXcml0ZXItLT4+cnVuQ29tbWFuZDogUmVzb2x2ZSBvciByZWplY3QgcHJvbWlzZVxuICogICBydW5Db21tYW5kLS0+PkNhbGxlcjogUmV0dXJuIENvbW1hbmRSZXN1bHRcbiAqXG4gKiBAbWVtYmVyT2YgbW9kdWxlOnV0aWxzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBydW5Db21tYW5kPFIgPSBzdHJpbmc+KFxuICBjb21tYW5kOiBzdHJpbmcsXG4gIG9wdHM6IFNwYXduT3B0aW9uc1dpdGhvdXRTdGRpbyA9IHt9LFxuICBvdXRwdXRDb25zdHJ1Y3RvcjogT3V0cHV0V3JpdGVyQ29uc3RydWN0b3I8XG4gICAgUixcbiAgICBTdGFuZGFyZE91dHB1dFdyaXRlcjxSPixcbiAgICBFcnJvclxuICA+ID0gU3RhbmRhcmRPdXRwdXRXcml0ZXI8Uj4sXG4gIC4uLmFyZ3M6IHVua25vd25bXVxuKTogQ29tbWFuZFJlc3VsdDxSPiB7XG4gIGNvbnN0IGxvZ2dlciA9IExvZ2dpbmcuZm9yKHJ1bkNvbW1hbmQpO1xuICBjb25zdCBhYm9ydCA9IG5ldyBBYm9ydENvbnRyb2xsZXIoKTtcblxuICBjb25zdCByZXN1bHQ6IE9taXQ8Q29tbWFuZFJlc3VsdCwgXCJwcm9taXNlXCIgfCBcInBpcGVcIj4gPSB7XG4gICAgYWJvcnQ6IGFib3J0LFxuICAgIGNvbW1hbmQ6IGNvbW1hbmQsXG4gICAgbG9nczogW10sXG4gICAgZXJyczogW10sXG4gIH07XG5cbiAgY29uc3QgbG9jayA9IG5ldyBQcm9taXNlPFI+KChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICBsZXQgb3V0cHV0O1xuICAgIHRyeSB7XG4gICAgICBvdXRwdXQgPSBuZXcgb3V0cHV0Q29uc3RydWN0b3IoXG4gICAgICAgIGNvbW1hbmQsXG4gICAgICAgIHtcbiAgICAgICAgICByZXNvbHZlLFxuICAgICAgICAgIHJlamVjdCxcbiAgICAgICAgfSxcbiAgICAgICAgLi4uYXJnc1xuICAgICAgKTtcblxuICAgICAgcmVzdWx0LmNtZCA9IHNwYXduQ29tbWFuZDxSPihvdXRwdXQsIGNvbW1hbmQsIG9wdHMsIGFib3J0LCBsb2dnZXIpO1xuICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgIHJldHVybiByZWplY3QobmV3IEVycm9yKGBFcnJvciBydW5uaW5nIGNvbW1hbmQgJHtjb21tYW5kfTogJHtlfWApKTtcbiAgICB9XG5cbiAgICByZXN1bHQuY21kLnN0ZG91dC5zZXRFbmNvZGluZyhcInV0ZjhcIik7XG5cbiAgICByZXN1bHQuY21kLnN0ZG91dC5vbihcImRhdGFcIiwgKGNodW5rOiBhbnkpID0+IHtcbiAgICAgIGNodW5rID0gY2h1bmsudG9TdHJpbmcoKTtcbiAgICAgIHJlc3VsdC5sb2dzLnB1c2goY2h1bmspO1xuICAgICAgb3V0cHV0LmRhdGEoY2h1bmspO1xuICAgIH0pO1xuXG4gICAgcmVzdWx0LmNtZC5zdGRlcnIub24oXCJkYXRhXCIsIChkYXRhOiBhbnkpID0+IHtcbiAgICAgIGRhdGEgPSBkYXRhLnRvU3RyaW5nKCk7XG4gICAgICByZXN1bHQuZXJycy5wdXNoKGRhdGEpO1xuICAgICAgb3V0cHV0LmVycm9yKGRhdGEpO1xuICAgIH0pO1xuXG4gICAgcmVzdWx0LmNtZC5vbmNlKFwiZXJyb3JcIiwgKGVycjogRXJyb3IpID0+IHtcbiAgICAgIG91dHB1dC5leGl0KGVyci5tZXNzYWdlLCByZXN1bHQuZXJycyk7XG4gICAgfSk7XG5cbiAgICByZXN1bHQuY21kLm9uY2UoXCJleGl0XCIsIChjb2RlOiBudW1iZXIgPSAwKSA9PiB7XG4gICAgICBpZiAoYWJvcnQuc2lnbmFsLmFib3J0ZWQgJiYgY29kZSA9PT0gbnVsbCkgY29kZSA9IEFib3J0Q29kZSBhcyBhbnk7XG4gICAgICBvdXRwdXQuZXhpdChjb2RlLCBjb2RlID09PSAwID8gcmVzdWx0LmxvZ3MgOiByZXN1bHQuZXJycyk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIE9iamVjdC5hc3NpZ24ocmVzdWx0LCB7XG4gICAgcHJvbWlzZTogbG9jayxcbiAgICBwaXBlOiBhc3luYyA8RT4oY2I6IChyOiBSKSA9PiBFKSA9PiB7XG4gICAgICBjb25zdCBsID0gbG9nZ2VyLmZvcihcInBpcGVcIik7XG4gICAgICB0cnkge1xuICAgICAgICBsLnZlcmJvc2UoYEV4ZWN1dGluZyBwaXBlIGZ1bmN0aW9uICR7Y29tbWFuZH0uLi5gKTtcbiAgICAgICAgY29uc3QgcmVzdWx0OiBSID0gYXdhaXQgbG9jaztcbiAgICAgICAgbC52ZXJib3NlKGBQaXBpbmcgb3V0cHV0IHRvICR7Y2IubmFtZX06ICR7cmVzdWx0fWApO1xuICAgICAgICByZXR1cm4gY2IocmVzdWx0KTtcbiAgICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgICAgbC5lcnJvcihgRXJyb3IgcGlwaW5nIGNvbW1hbmQgb3V0cHV0OiAke2V9YCk7XG4gICAgICAgIHRocm93IGU7XG4gICAgICB9XG4gICAgfSxcbiAgfSk7XG5cbiAgcmV0dXJuIHJlc3VsdCBhcyBDb21tYW5kUmVzdWx0PFI+O1xufVxuIiwiaW1wb3J0IGZzIGZyb20gXCJmc1wiO1xuaW1wb3J0IHBhdGggZnJvbSBcInBhdGhcIjtcbmltcG9ydCB7IGNyZWF0ZVJlcXVpcmUgfSBmcm9tIFwibW9kdWxlXCI7XG5pbXBvcnQgeyBydW5Db21tYW5kIH0gZnJvbSBcIi4vdXRpbHNcIjtcbmltcG9ydCB7IERlcGVuZGVuY3lNYXAsIFNpbXBsZURlcGVuZGVuY3lNYXAgfSBmcm9tIFwiLi90eXBlc1wiO1xuaW1wb3J0IHsgZXNjYXBlUmVnRXhwLCBMb2dnaW5nIH0gZnJvbSBcIkBkZWNhZi10cy9sb2dnaW5nXCI7XG5pbXBvcnQgemxpYiBmcm9tIFwiemxpYlwiO1xuXG5jb25zdCBsb2dnZXIgPSBMb2dnaW5nLmZvcihcImZzXCIpO1xuY29uc3QgbG9jYWxSZXF1aXJlID0gY3JlYXRlUmVxdWlyZShgJHtwcm9jZXNzLmN3ZCgpfS9wYWNrYWdlLmpzb25gKTtcbmZ1bmN0aW9uIGlzVGVzdEVudmlyb25tZW50KCkge1xuICByZXR1cm4gKFxuICAgIHByb2Nlc3MuZW52Lk5PREVfRU5WID09PSBcInRlc3RcIiB8fFxuICAgIHR5cGVvZiBwcm9jZXNzLmVudi5KRVNUX1dPUktFUl9JRCAhPT0gXCJ1bmRlZmluZWRcIlxuICApO1xufVxuXG5mdW5jdGlvbiBwYXRjaFN0cmluZyhcbiAgaW5wdXQ6IHN0cmluZyxcbiAgdmFsdWVzOiBSZWNvcmQ8c3RyaW5nLCBudW1iZXIgfCBzdHJpbmc+LFxuICBmbGFnczogc3RyaW5nID0gXCJnXCIsXG4gIGZpbHRlcj86IChzdHI6IHN0cmluZykgPT4gYm9vbGVhblxuKTogc3RyaW5nIHtcbiAgT2JqZWN0LmVudHJpZXModmFsdWVzKS5mb3JFYWNoKChba2V5LCB2YWxdKSA9PiB7XG4gICAgY29uc3QgcmVnZXhwID0gbmV3IFJlZ0V4cChlc2NhcGVSZWdFeHAoa2V5KSwgZmxhZ3MpO1xuICAgIGlucHV0ID0gaW5wdXQucmVwbGFjZShyZWdleHAsIChzdWJTdHI6IHN0cmluZykgPT4ge1xuICAgICAgaWYgKCFmaWx0ZXIgfHwgZmlsdGVyKHN1YlN0cikpIHtcbiAgICAgICAgcmV0dXJuIHZhbCBhcyBzdHJpbmc7XG4gICAgICB9XG4gICAgICByZXR1cm4gdmFsIGFzIHN0cmluZztcbiAgICB9KTtcbiAgfSk7XG4gIHJldHVybiBpbnB1dDtcbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gUGF0Y2hlcyBhIGZpbGUgd2l0aCBnaXZlbiB2YWx1ZXMuXG4gKiBAc3VtbWFyeSBSZWFkcyBhIGZpbGUsIGFwcGxpZXMgcGF0Y2hlcyB1c2luZyBUZXh0VXRpbHMsIGFuZCB3cml0ZXMgdGhlIHJlc3VsdCBiYWNrIHRvIHRoZSBmaWxlLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIC0gVGhlIHBhdGggdG8gdGhlIGZpbGUgdG8gYmUgcGF0Y2hlZC5cbiAqIEBwYXJhbSB7UmVjb3JkPHN0cmluZywgbnVtYmVyIHwgc3RyaW5nPn0gdmFsdWVzIC0gVGhlIHZhbHVlcyB0byBwYXRjaCBpbnRvIHRoZSBmaWxlLlxuICogQHJldHVybiB7dm9pZH1cbiAqXG4gKiBAZnVuY3Rpb24gcGF0Y2hGaWxlXG4gKlxuICogQG1lcm1haWRcbiAqIHNlcXVlbmNlRGlhZ3JhbVxuICogICBwYXJ0aWNpcGFudCBDYWxsZXJcbiAqICAgcGFydGljaXBhbnQgcGF0Y2hGaWxlXG4gKiAgIHBhcnRpY2lwYW50IGZzXG4gKiAgIHBhcnRpY2lwYW50IHJlYWRGaWxlXG4gKiAgIHBhcnRpY2lwYW50IFRleHRVdGlsc1xuICogICBwYXJ0aWNpcGFudCB3cml0ZUZpbGVcbiAqICAgQ2FsbGVyLT4+cGF0Y2hGaWxlOiBDYWxsIHdpdGggcGF0aCBhbmQgdmFsdWVzXG4gKiAgIHBhdGNoRmlsZS0+PmZzOiBDaGVjayBpZiBmaWxlIGV4aXN0c1xuICogICBwYXRjaEZpbGUtPj5yZWFkRmlsZTogUmVhZCBmaWxlIGNvbnRlbnRcbiAqICAgcmVhZEZpbGUtPj5mczogUmVhZCBmaWxlXG4gKiAgIGZzLS0+PnJlYWRGaWxlOiBSZXR1cm4gZmlsZSBjb250ZW50XG4gKiAgIHJlYWRGaWxlLS0+PnBhdGNoRmlsZTogUmV0dXJuIGZpbGUgY29udGVudFxuICogICBwYXRjaEZpbGUtPj5UZXh0VXRpbHM6IFBhdGNoIHN0cmluZ1xuICogICBUZXh0VXRpbHMtLT4+cGF0Y2hGaWxlOiBSZXR1cm4gcGF0Y2hlZCBjb250ZW50XG4gKiAgIHBhdGNoRmlsZS0+PndyaXRlRmlsZTogV3JpdGUgcGF0Y2hlZCBjb250ZW50XG4gKiAgIHdyaXRlRmlsZS0+PmZzOiBXcml0ZSB0byBmaWxlXG4gKiAgIGZzLS0+PndyaXRlRmlsZTogRmlsZSB3cml0dGVuXG4gKiAgIHdyaXRlRmlsZS0tPj5wYXRjaEZpbGU6IEZpbGUgd3JpdHRlblxuICogICBwYXRjaEZpbGUtLT4+Q2FsbGVyOiBQYXRjaGluZyBjb21wbGV0ZVxuICpcbiAqIEBtZW1iZXJPZiBtb2R1bGU6dXRpbHNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBhdGNoRmlsZShcbiAgcGF0aDogc3RyaW5nLFxuICB2YWx1ZXM6IFJlY29yZDxzdHJpbmcsIG51bWJlciB8IHN0cmluZz4sXG4gIGZpbHRlcj86IChzdHI6IHN0cmluZykgPT4gYm9vbGVhblxuKSB7XG4gIGNvbnN0IGxvZyA9IGxvZ2dlci5mb3IocGF0Y2hGaWxlKTtcbiAgaWYgKCFmcy5leGlzdHNTeW5jKHBhdGgpKVxuICAgIHRocm93IG5ldyBFcnJvcihgRmlsZSBub3QgZm91bmQgYXQgcGF0aCBcIiR7cGF0aH1cIi5gKTtcbiAgbGV0IGNvbnRlbnQgPSByZWFkRmlsZShwYXRoKTtcblxuICBsb2cudmVyYm9zZShgUGF0Y2hpbmcgZmlsZSBcIiR7cGF0aH1cIi4uLmApO1xuICBsb2cuZGVidWcoYHdpdGggdmFsdWU6ICR7SlNPTi5zdHJpbmdpZnkodmFsdWVzKX1gKTtcbiAgdHJ5IHtcbiAgICBjb250ZW50ID0gcGF0Y2hTdHJpbmcoY29udGVudCwgdmFsdWVzLCBcImdcIiwgZmlsdGVyKTtcbiAgfSBjYXRjaCAoZXJyb3I6IHVua25vd24pIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYEVycm9yIHBhdGNoaW5nIGZpbGU6ICR7ZXJyb3J9YCk7XG4gIH1cbiAgd3JpdGVGaWxlKHBhdGgsIGNvbnRlbnQpO1xufVxuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBSZWFkcyBhIGZpbGUgYW5kIHJldHVybnMgaXRzIGNvbnRlbnQuXG4gKiBAc3VtbWFyeSBSZWFkcyB0aGUgY29udGVudCBvZiBhIGZpbGUgYXQgdGhlIHNwZWNpZmllZCBwYXRoIGFuZCByZXR1cm5zIGl0IGFzIGEgc3RyaW5nLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIC0gVGhlIHBhdGggdG8gdGhlIGZpbGUgdG8gYmUgcmVhZC5cbiAqIEByZXR1cm4ge3N0cmluZ30gVGhlIGNvbnRlbnQgb2YgdGhlIGZpbGUuXG4gKlxuICogQGZ1bmN0aW9uIHJlYWRGaWxlXG4gKlxuICogQG1lbWJlck9mIG1vZHVsZTp1dGlsc1xuICovXG5leHBvcnQgZnVuY3Rpb24gcmVhZEZpbGUocGF0aDogc3RyaW5nKTogc3RyaW5nIHtcbiAgY29uc3QgbG9nID0gbG9nZ2VyLmZvcihyZWFkRmlsZSk7XG4gIHRyeSB7XG4gICAgbG9nLnZlcmJvc2UoYFJlYWRpbmcgZmlsZSBcIiR7cGF0aH1cIi4uLmApO1xuICAgIHJldHVybiBmcy5yZWFkRmlsZVN5bmMocGF0aCwgXCJ1dGY4XCIpO1xuICB9IGNhdGNoIChlcnJvcjogdW5rbm93bikge1xuICAgIGxvZy52ZXJib3NlKGBFcnJvciByZWFkaW5nIGZpbGUgXCIke3BhdGh9XCI6ICR7ZXJyb3J9YCk7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBFcnJvciByZWFkaW5nIGZpbGUgXCIke3BhdGh9XCI6ICR7ZXJyb3J9YCk7XG4gIH1cbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gV3JpdGVzIGRhdGEgdG8gYSBmaWxlLlxuICogQHN1bW1hcnkgV3JpdGVzIHRoZSBwcm92aWRlZCBkYXRhIHRvIGEgZmlsZSBhdCB0aGUgc3BlY2lmaWVkIHBhdGguXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBUaGUgcGF0aCB0byB0aGUgZmlsZSB0byBiZSB3cml0dGVuLlxuICogQHBhcmFtIHtzdHJpbmcgfCBCdWZmZXJ9IGRhdGEgLSBUaGUgZGF0YSB0byBiZSB3cml0dGVuIHRvIHRoZSBmaWxlLlxuICogQHJldHVybiB7dm9pZH1cbiAqXG4gKiBAZnVuY3Rpb24gd3JpdGVGaWxlXG4gKlxuICogQG1lbWJlck9mIG1vZHVsZTp1dGlsc1xuICovXG5leHBvcnQgZnVuY3Rpb24gd3JpdGVGaWxlKHBhdGg6IHN0cmluZywgZGF0YTogc3RyaW5nIHwgQnVmZmVyKTogdm9pZCB7XG4gIGNvbnN0IGxvZyA9IGxvZ2dlci5mb3Iod3JpdGVGaWxlKTtcbiAgdHJ5IHtcbiAgICBsb2cudmVyYm9zZShgV3JpdGluZyBmaWxlIFwiJHtwYXRofSB3aXRoICR7ZGF0YS5sZW5ndGh9IGJ5dGVzLi4uYCk7XG4gICAgZnMud3JpdGVGaWxlU3luYyhwYXRoLCBkYXRhLCBcInV0ZjhcIik7XG4gIH0gY2F0Y2ggKGVycm9yOiB1bmtub3duKSB7XG4gICAgbG9nLnZlcmJvc2UoYEVycm9yIHdyaXRpbmcgZmlsZSBcIiR7cGF0aH1cIjogJHtlcnJvcn1gKTtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYEVycm9yIHdyaXRpbmcgZmlsZSBcIiR7cGF0aH1cIjogJHtlcnJvcn1gKTtcbiAgfVxufVxuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBSZXRyaWV2ZXMgYWxsIGZpbGVzIHJlY3Vyc2l2ZWx5IGZyb20gYSBkaXJlY3RvcnkuXG4gKiBAc3VtbWFyeSBUcmF2ZXJzZXMgdGhyb3VnaCBkaXJlY3RvcmllcyBhbmQgc3ViZGlyZWN0b3JpZXMgdG8gY29sbGVjdCBhbGwgZmlsZSBwYXRocy5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gcCAtIFRoZSBwYXRoIHRvIHN0YXJ0IHNlYXJjaGluZyBmcm9tLlxuICogQHBhcmFtIHtmdW5jdGlvbn0gW2ZpbHRlcl0gLSBPcHRpb25hbCBmdW5jdGlvbiB0byBmaWx0ZXIgZmlsZXMgYnkgbmFtZSBvciBpbmRleC5cbiAqIEByZXR1cm4ge3N0cmluZ1tdfSBBcnJheSBvZiBmaWxlIHBhdGhzLlxuICpcbiAqIEBmdW5jdGlvbiBnZXRBbGxGaWxlc1xuICpcbiAqIEBtZW1iZXJPZiBtb2R1bGU6dXRpbHNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldEFsbEZpbGVzKFxuICBwOiBzdHJpbmcsXG4gIGZpbHRlcj86IChmOiBzdHJpbmcsIGk/OiBudW1iZXIpID0+IGJvb2xlYW5cbik6IHN0cmluZ1tdIHtcbiAgY29uc3QgbG9nID0gbG9nZ2VyLmZvcihnZXRBbGxGaWxlcyk7XG4gIGNvbnN0IGZpbGVzOiBzdHJpbmdbXSA9IFtdO1xuXG4gIHRyeSB7XG4gICAgbG9nLnZlcmJvc2UoYFJldHJpZXZpbmcgYWxsIGZpbGVzIGZyb20gXCIke3B9XCIuLi5gKTtcbiAgICBjb25zdCBlbnRyaWVzID0gZnMucmVhZGRpclN5bmMocCk7XG5cbiAgICBlbnRyaWVzLmZvckVhY2goKGVudHJ5KSA9PiB7XG4gICAgICBjb25zdCBmdWxsUGF0aCA9IHBhdGguam9pbihwLCBlbnRyeSk7XG4gICAgICBjb25zdCBzdGF0ID0gZnMuc3RhdFN5bmMoZnVsbFBhdGgpO1xuXG4gICAgICBpZiAoc3RhdC5pc0ZpbGUoKSkge1xuICAgICAgICBmaWxlcy5wdXNoKGZ1bGxQYXRoKTtcbiAgICAgIH0gZWxzZSBpZiAoc3RhdC5pc0RpcmVjdG9yeSgpKSB7XG4gICAgICAgIGZpbGVzLnB1c2goLi4uZ2V0QWxsRmlsZXMoZnVsbFBhdGgpKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICBpZiAoIWZpbHRlcikgcmV0dXJuIGZpbGVzO1xuICAgIHJldHVybiBmaWxlcy5maWx0ZXIoZmlsdGVyKTtcbiAgfSBjYXRjaCAoZXJyb3I6IHVua25vd24pIHtcbiAgICBsb2cudmVyYm9zZShgRXJyb3IgcmV0cmlldmluZyBmaWxlcyBmcm9tIFwiJHtwfVwiOiAke2Vycm9yfWApO1xuICAgIHRocm93IG5ldyBFcnJvcihgRXJyb3IgcmV0cmlldmluZyBmaWxlcyBmcm9tIFwiJHtwfVwiOiAke2Vycm9yfWApO1xuICB9XG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIFJlbmFtZXMgYSBmaWxlIG9yIGRpcmVjdG9yeS5cbiAqIEBzdW1tYXJ5IE1vdmVzIGEgZmlsZSBvciBkaXJlY3RvcnkgZnJvbSB0aGUgc291cmNlIHBhdGggdG8gdGhlIGRlc3RpbmF0aW9uIHBhdGguXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IHNvdXJjZSAtIFRoZSBzb3VyY2UgcGF0aCBvZiB0aGUgZmlsZSBvciBkaXJlY3RvcnkuXG4gKiBAcGFyYW0ge3N0cmluZ30gZGVzdCAtIFRoZSBkZXN0aW5hdGlvbiBwYXRoIGZvciB0aGUgZmlsZSBvciBkaXJlY3RvcnkuXG4gKiBAcmV0dXJuIHtQcm9taXNlPHZvaWQ+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIHRoZSByZW5hbWUgb3BlcmF0aW9uIGlzIGNvbXBsZXRlLlxuICpcbiAqIEBmdW5jdGlvbiByZW5hbWVGaWxlXG4gKlxuICogQG1lbWJlck9mIG1vZHVsZTp1dGlsc1xuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcmVuYW1lRmlsZShzb3VyY2U6IHN0cmluZywgZGVzdDogc3RyaW5nKSB7XG4gIGNvbnN0IGxvZyA9IGxvZ2dlci5mb3IocmVuYW1lRmlsZSk7XG4gIGxldCBkZXNjcmlwdG9yU291cmNlLCBkZXNjcmlwdG9yRGVzdDtcblxuICB0cnkge1xuICAgIGRlc2NyaXB0b3JTb3VyY2UgPSBmcy5zdGF0U3luYyhzb3VyY2UpO1xuICB9IGNhdGNoIChlcnJvcjogdW5rbm93bikge1xuICAgIGxvZy52ZXJib3NlKGBTb3VyY2UgcGF0aCBcIiR7c291cmNlfVwiIGRvZXMgbm90IGV4aXN0OiAke2Vycm9yfWApO1xuICAgIHRocm93IG5ldyBFcnJvcihgU291cmNlIHBhdGggXCIke3NvdXJjZX1cIiBkb2VzIG5vdCBleGlzdDogJHtlcnJvcn1gKTtcbiAgfVxuXG4gIHRyeSB7XG4gICAgZGVzY3JpcHRvckRlc3QgPSBmcy5zdGF0U3luYyhkZXN0KTtcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVudXNlZC12YXJzXG4gIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAvLyBkbyBub3RoaW5nLiBpdHMgb2tcbiAgfVxuICBpZiAoZGVzY3JpcHRvckRlc3QpIHtcbiAgICBsb2cudmVyYm9zZShgRGVzdGluYXRpb24gcGF0aCBcIiR7ZGVzdH1cIiBhbHJlYWR5IGV4aXN0c2ApO1xuICAgIHRocm93IG5ldyBFcnJvcihgRGVzdGluYXRpb24gcGF0aCBcIiR7ZGVzdH1cIiBhbHJlYWR5IGV4aXN0c2ApO1xuICB9XG5cbiAgdHJ5IHtcbiAgICBsb2cudmVyYm9zZShcbiAgICAgIGBSZW5hbWluZyAke2Rlc2NyaXB0b3JTb3VyY2UuaXNGaWxlKCkgPyBcImZpbGVcIiA6IFwiZGlyZWN0b3J5XCJ9IFwiJHtzb3VyY2V9XCIgdG8gXCIke2Rlc3R9Li4uYFxuICAgICk7XG4gICAgZnMucmVuYW1lU3luYyhzb3VyY2UsIGRlc3QpO1xuICAgIGxvZy52ZXJib3NlKGBTdWNjZXNzZnVsbHkgcmVuYW1lZCB0byBcIiR7ZGVzdH1cImApO1xuICB9IGNhdGNoIChlcnJvcjogdW5rbm93bikge1xuICAgIGxvZy52ZXJib3NlKFxuICAgICAgYEVycm9yIHJlbmFtaW5nICR7ZGVzY3JpcHRvclNvdXJjZS5pc0ZpbGUoKSA/IFwiZmlsZVwiIDogXCJkaXJlY3RvcnlcIn0gXCIke3NvdXJjZX1cIiB0byBcIiR7ZGVzdH1cIjogJHtlcnJvcn1gXG4gICAgKTtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICBgRXJyb3IgcmVuYW1pbmcgJHtkZXNjcmlwdG9yU291cmNlLmlzRmlsZSgpID8gXCJmaWxlXCIgOiBcImRpcmVjdG9yeVwifSBcIiR7c291cmNlfVwiIHRvIFwiJHtkZXN0fVwiOiAke2Vycm9yfWBcbiAgICApO1xuICB9XG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIENvcGllcyBhIGZpbGUgb3IgZGlyZWN0b3J5LlxuICogQHN1bW1hcnkgQ3JlYXRlcyBhIGNvcHkgb2YgYSBmaWxlIG9yIGRpcmVjdG9yeSBmcm9tIHRoZSBzb3VyY2UgcGF0aCB0byB0aGUgZGVzdGluYXRpb24gcGF0aC5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gc291cmNlIC0gVGhlIHNvdXJjZSBwYXRoIG9mIHRoZSBmaWxlIG9yIGRpcmVjdG9yeS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBkZXN0IC0gVGhlIGRlc3RpbmF0aW9uIHBhdGggZm9yIHRoZSBmaWxlIG9yIGRpcmVjdG9yeS5cbiAqIEByZXR1cm4ge3ZvaWR9XG4gKlxuICogQGZ1bmN0aW9uIGNvcHlGaWxlXG4gKlxuICogQG1lbWJlck9mIG1vZHVsZTp1dGlsc1xuICovXG5leHBvcnQgZnVuY3Rpb24gY29weUZpbGUoc291cmNlOiBzdHJpbmcsIGRlc3Q6IHN0cmluZykge1xuICBjb25zdCBsb2cgPSBsb2dnZXIuZm9yKGNvcHlGaWxlKTtcbiAgbGV0IGRlc2NyaXB0b3JTb3VyY2UsIGRlc2NyaXB0b3JEZXN0O1xuICB0cnkge1xuICAgIGRlc2NyaXB0b3JTb3VyY2UgPSBmcy5zdGF0U3luYyhzb3VyY2UpO1xuICB9IGNhdGNoIChlcnJvcjogdW5rbm93bikge1xuICAgIGxvZy52ZXJib3NlKGBTb3VyY2UgcGF0aCBcIiR7c291cmNlfVwiIGRvZXMgbm90IGV4aXN0OiAke2Vycm9yfWApO1xuICAgIHRocm93IG5ldyBFcnJvcihgU291cmNlIHBhdGggXCIke3NvdXJjZX1cIiBkb2VzIG5vdCBleGlzdDogJHtlcnJvcn1gKTtcbiAgfVxuICB0cnkge1xuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnNcbiAgICBkZXNjcmlwdG9yRGVzdCA9IGZzLnN0YXRTeW5jKGRlc3QpO1xuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnNcbiAgfSBjYXRjaCAoZXJyb3I6IHVua25vd24pIHtcbiAgICBpZiAoZGVzY3JpcHRvclNvdXJjZS5pc0RpcmVjdG9yeSgpKSB7XG4gICAgICBsb2cudmVyYm9zZShgRGVzdCBwYXRoIFwiJHtkZXN0fVwiIGRvZXMgbm90IGV4aXN0LiBjcmVhdGluZ2ApO1xuICAgICAgZnMubWtkaXJTeW5jKGRlc3QsIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xuICAgIH1cbiAgfVxuXG4gIHRyeSB7XG4gICAgbG9nLnZlcmJvc2UoXG4gICAgICBgQ29weWluZyAke2Rlc2NyaXB0b3JTb3VyY2UuaXNGaWxlKCkgPyBcImZpbGVcIiA6IFwiZGlyZWN0b3J5XCJ9IFwiJHtzb3VyY2V9XCIgdG8gXCIke2Rlc3R9Li4uYFxuICAgICk7XG4gICAgZnMuY3BTeW5jKHNvdXJjZSwgZGVzdCwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gIH0gY2F0Y2ggKGVycm9yOiB1bmtub3duKSB7XG4gICAgbG9nLnZlcmJvc2UoXG4gICAgICBgRXJyb3IgY29weWluZyAke2Rlc2NyaXB0b3JTb3VyY2UuaXNGaWxlKCkgPyBcImZpbGVcIiA6IFwiZGlyZWN0b3J5XCJ9IFwiJHtzb3VyY2V9XCIgdG8gXCIke2Rlc3R9OiAke2Vycm9yfWBcbiAgICApO1xuICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgIGBFcnJvciBjb3B5aW5nICR7ZGVzY3JpcHRvclNvdXJjZS5pc0ZpbGUoKSA/IFwiZmlsZVwiIDogXCJkaXJlY3RvcnlcIn0gXCIke3NvdXJjZX1cIiB0byBcIiR7ZGVzdH06ICR7ZXJyb3J9YFxuICAgICk7XG4gIH1cbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gRGVsZXRlcyBhIGZpbGUgb3IgZGlyZWN0b3J5LlxuICogQHN1bW1hcnkgUmVtb3ZlcyBhIGZpbGUgb3IgZGlyZWN0b3J5IGF0IHRoZSBzcGVjaWZpZWQgcGF0aCwgd2l0aCByZWN1cnNpdmUgYW5kIGZvcmNlIG9wdGlvbnMgZW5hYmxlZC5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gcCAtIFRoZSBwYXRoIHRvIHRoZSBmaWxlIG9yIGRpcmVjdG9yeSB0byBkZWxldGUuXG4gKiBAcmV0dXJuIHt2b2lkfVxuICpcbiAqIEBmdW5jdGlvbiBkZWxldGVQYXRoXG4gKlxuICogQG1lbWJlck9mIG1vZHVsZTp1dGlsc1xuICovXG5leHBvcnQgZnVuY3Rpb24gZGVsZXRlUGF0aChwOiBzdHJpbmcpIHtcbiAgY29uc3QgbG9nID0gbG9nZ2VyLmZvcihkZWxldGVQYXRoKTtcbiAgdHJ5IHtcbiAgICBjb25zdCBkZXNjcmlwdG9yID0gZnMuc3RhdFN5bmMocCk7XG4gICAgaWYgKGRlc2NyaXB0b3IuaXNGaWxlKCkpIHtcbiAgICAgIGxvZy52ZXJib3NlKGBEZWxldGluZyBmaWxlIFwiJHtwfS4uLmApO1xuICAgICAgZnMucm1TeW5jKHAsIHsgcmVjdXJzaXZlOiB0cnVlLCBmb3JjZTogdHJ1ZSB9KTtcbiAgICB9IGVsc2UgaWYgKGRlc2NyaXB0b3IuaXNEaXJlY3RvcnkoKSlcbiAgICAgIGZzLnJtU3luYyhwLCB7IHJlY3Vyc2l2ZTogdHJ1ZSwgZm9yY2U6IHRydWUgfSk7XG4gIH0gY2F0Y2ggKGVycm9yOiB1bmtub3duKSB7XG4gICAgbG9nLnZlcmJvc2UoYEVycm9yIERlbGV0aW5nIFwiJHtwfVwiOiAke2Vycm9yfWApO1xuICAgIHRocm93IG5ldyBFcnJvcihgRXJyb3IgRGVsZXRpbmcgXCIke3B9XCI6ICR7ZXJyb3J9YCk7XG4gIH1cbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gUmV0cmlldmVzIHBhY2thZ2UgaW5mb3JtYXRpb24gZnJvbSBwYWNrYWdlLmpzb24uXG4gKiBAc3VtbWFyeSBMb2FkcyBhbmQgcGFyc2VzIHRoZSBwYWNrYWdlLmpzb24gZmlsZSBmcm9tIGEgc3BlY2lmaWVkIGRpcmVjdG9yeSBvciB0aGUgY3VycmVudCB3b3JraW5nIGRpcmVjdG9yeS4gQ2FuIHJldHVybiB0aGUgZW50aXJlIHBhY2thZ2Ugb2JqZWN0IG9yIGEgc3BlY2lmaWMgcHJvcGVydHkuXG4gKiBAcGFyYW0ge3N0cmluZ30gW3A9cHJvY2Vzcy5jd2QoKV0gLSBUaGUgZGlyZWN0b3J5IHBhdGggd2hlcmUgdGhlIHBhY2thZ2UuanNvbiBmaWxlIGlzIGxvY2F0ZWQuXG4gKiBAcGFyYW0ge3N0cmluZ30gW3Byb3BlcnR5XSAtIE9wdGlvbmFsLiBUaGUgc3BlY2lmaWMgcHJvcGVydHkgdG8gcmV0cmlldmUgZnJvbSBwYWNrYWdlLmpzb24uXG4gKiBAcmV0dXJuIHtvYmplY3QgfCBzdHJpbmd9IFRoZSBwYXJzZWQgY29udGVudHMgb2YgcGFja2FnZS5qc29uIG9yIHRoZSB2YWx1ZSBvZiB0aGUgc3BlY2lmaWVkIHByb3BlcnR5LlxuICogQGZ1bmN0aW9uIGdldFBhY2thZ2VcbiAqIEBtZXJtYWlkXG4gKiBzZXF1ZW5jZURpYWdyYW1cbiAqICAgcGFydGljaXBhbnQgQ2FsbGVyXG4gKiAgIHBhcnRpY2lwYW50IGdldFBhY2thZ2VcbiAqICAgcGFydGljaXBhbnQgcmVhZEZpbGVcbiAqICAgcGFydGljaXBhbnQgSlNPTlxuICogICBDYWxsZXItPj5nZXRQYWNrYWdlOiBDYWxsIHdpdGggcGF0aCBhbmQgb3B0aW9uYWwgcHJvcGVydHlcbiAqICAgZ2V0UGFja2FnZS0+PnJlYWRGaWxlOiBSZWFkIHBhY2thZ2UuanNvblxuICogICByZWFkRmlsZS0tPj5nZXRQYWNrYWdlOiBSZXR1cm4gZmlsZSBjb250ZW50XG4gKiAgIGdldFBhY2thZ2UtPj5KU09OOiBQYXJzZSBmaWxlIGNvbnRlbnRcbiAqICAgSlNPTi0tPj5nZXRQYWNrYWdlOiBSZXR1cm4gcGFyc2VkIG9iamVjdFxuICogICBhbHQgcHJvcGVydHkgc3BlY2lmaWVkXG4gKiAgICAgZ2V0UGFja2FnZS0+PmdldFBhY2thZ2U6IENoZWNrIGlmIHByb3BlcnR5IGV4aXN0c1xuICogICAgIGFsdCBwcm9wZXJ0eSBleGlzdHNcbiAqICAgICAgIGdldFBhY2thZ2UtLT4+Q2FsbGVyOiBSZXR1cm4gcHJvcGVydHkgdmFsdWVcbiAqICAgICBlbHNlIHByb3BlcnR5IGRvZXNuJ3QgZXhpc3RcbiAqICAgICAgIGdldFBhY2thZ2UtLT4+Q2FsbGVyOiBUaHJvdyBFcnJvclxuICogICAgIGVuZFxuICogICBlbHNlIG5vIHByb3BlcnR5IHNwZWNpZmllZFxuICogICAgIGdldFBhY2thZ2UtLT4+Q2FsbGVyOiBSZXR1cm4gZW50aXJlIHBhY2thZ2Ugb2JqZWN0XG4gKiAgIGVuZFxuICogQG1lbWJlck9mIG1vZHVsZTp1dGlsc1xuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0UGFja2FnZShcbiAgcDogc3RyaW5nID0gcHJvY2Vzcy5jd2QoKSxcbiAgcHJvcGVydHk/OiBzdHJpbmdcbik6IG9iamVjdCB8IHN0cmluZyB7XG4gIGxldCBwa2c6IGFueTtcbiAgdHJ5IHtcbiAgICBwa2cgPSBKU09OLnBhcnNlKHJlYWRGaWxlKHBhdGguam9pbihwLCBgcGFja2FnZS5qc29uYCkpKTtcbiAgfSBjYXRjaCAoZXJyb3I6IHVua25vd24pIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYEZhaWxlZCB0byByZXRyaWV2ZSBwYWNrYWdlIGluZm9ybWF0aW9uXCIgJHtlcnJvcn1gKTtcbiAgfVxuXG4gIGlmIChwcm9wZXJ0eSkge1xuICAgIGlmICghKHByb3BlcnR5IGluIHBrZykpXG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYFByb3BlcnR5IFwiJHtwcm9wZXJ0eX1cIiBub3QgZm91bmQgaW4gcGFja2FnZS5qc29uYCk7XG4gICAgcmV0dXJuIHBrZ1twcm9wZXJ0eV0gYXMgc3RyaW5nO1xuICB9XG4gIHJldHVybiBwa2c7XG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIFNldHMgYW4gYXR0cmlidXRlIGluIHRoZSBwYWNrYWdlLmpzb24gZmlsZS5cbiAqIEBzdW1tYXJ5IFVwZGF0ZXMgYSBzcGVjaWZpYyBhdHRyaWJ1dGUgaW4gdGhlIHBhY2thZ2UuanNvbiBmaWxlIHdpdGggdGhlIHByb3ZpZGVkIHZhbHVlLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBhdHRyIC0gVGhlIGF0dHJpYnV0ZSBuYW1lIHRvIHNldCBpbiBwYWNrYWdlLmpzb24uXG4gKiBAcGFyYW0ge3N0cmluZyB8IG51bWJlciB8IG9iamVjdH0gdmFsdWUgLSBUaGUgdmFsdWUgdG8gc2V0IGZvciB0aGUgYXR0cmlidXRlLlxuICogQHBhcmFtIHtzdHJpbmd9IFtwPXByb2Nlc3MuY3dkKCldIC0gVGhlIGRpcmVjdG9yeSBwYXRoIHdoZXJlIHRoZSBwYWNrYWdlLmpzb24gZmlsZSBpcyBsb2NhdGVkLlxuICogQHJldHVybiB7dm9pZH1cbiAqXG4gKiBAZnVuY3Rpb24gc2V0UGFja2FnZUF0dHJpYnV0ZVxuICpcbiAqIEBtZW1iZXJPZiBtb2R1bGU6dXRpbHNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNldFBhY2thZ2VBdHRyaWJ1dGUoXG4gIGF0dHI6IHN0cmluZyxcbiAgdmFsdWU6IHN0cmluZyxcbiAgcDogc3RyaW5nID0gcHJvY2Vzcy5jd2QoKVxuKTogdm9pZCB7XG4gIGNvbnN0IHBrZyA9IGdldFBhY2thZ2UocCkgYXMgUmVjb3JkPHN0cmluZywgYW55PjtcbiAgcGtnW2F0dHJdID0gdmFsdWU7XG4gIHdyaXRlRmlsZShwYXRoLmpvaW4ocCwgYHBhY2thZ2UuanNvbmApLCBKU09OLnN0cmluZ2lmeShwa2csIG51bGwsIDIpKTtcbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gUmV0cmlldmVzIHRoZSB2ZXJzaW9uIGZyb20gcGFja2FnZS5qc29uLlxuICogQHN1bW1hcnkgQSBjb252ZW5pZW5jZSBmdW5jdGlvbiB0aGF0IGNhbGxzIGdldFBhY2thZ2UgdG8gcmV0cmlldmUgdGhlIFwidmVyc2lvblwiIHByb3BlcnR5IGZyb20gcGFja2FnZS5qc29uLlxuICogQHBhcmFtIHtzdHJpbmd9IFtwPXByb2Nlc3MuY3dkKCldIC0gVGhlIGRpcmVjdG9yeSBwYXRoIHdoZXJlIHRoZSBwYWNrYWdlLmpzb24gZmlsZSBpcyBsb2NhdGVkLlxuICogQHJldHVybiB7c3RyaW5nfSBUaGUgdmVyc2lvbiBzdHJpbmcgZnJvbSBwYWNrYWdlLmpzb24uXG4gKiBAZnVuY3Rpb24gZ2V0UGFja2FnZVZlcnNpb25cbiAqIEBtZW1iZXJPZiBtb2R1bGU6dXRpbHNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldFBhY2thZ2VWZXJzaW9uKHAgPSBwcm9jZXNzLmN3ZCgpKTogc3RyaW5nIHtcbiAgcmV0dXJuIGdldFBhY2thZ2UocCwgXCJ2ZXJzaW9uXCIpIGFzIHN0cmluZztcbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gUmV0cmlldmVzIGFsbCBkZXBlbmRlbmNpZXMgZnJvbSB0aGUgcHJvamVjdC5cbiAqIEBzdW1tYXJ5IEV4ZWN1dGVzICducG0gbHMgLS1qc29uJyBjb21tYW5kIHRvIGdldCBhIGRldGFpbGVkIGxpc3Qgb2YgYWxsIGRlcGVuZGVuY2llcyAocHJvZHVjdGlvbiwgZGV2ZWxvcG1lbnQsIGFuZCBwZWVyKSBhbmQgdGhlaXIgdmVyc2lvbnMuXG4gKiBAcGFyYW0ge3N0cmluZ30gW3BhdGg9cHJvY2Vzcy5jd2QoKV0gLSBUaGUgZGlyZWN0b3J5IHBhdGggb2YgdGhlIHByb2plY3QuXG4gKiBAcmV0dXJuIHtQcm9taXNlPHtwcm9kOiBBcnJheTx7bmFtZTogc3RyaW5nLCB2ZXJzaW9uOiBzdHJpbmd9PiwgZGV2OiBBcnJheTx7bmFtZTogc3RyaW5nLCB2ZXJzaW9uOiBzdHJpbmd9PiwgcGVlcjogQXJyYXk8e25hbWU6IHN0cmluZywgdmVyc2lvbjogc3RyaW5nfT59Pn0gQW4gb2JqZWN0IGNvbnRhaW5pbmcgYXJyYXlzIG9mIHByb2R1Y3Rpb24sIGRldmVsb3BtZW50LCBhbmQgcGVlciBkZXBlbmRlbmNpZXMuXG4gKiBAZnVuY3Rpb24gZ2V0RGVwZW5kZW5jaWVzXG4gKiBAbWVybWFpZFxuICogc2VxdWVuY2VEaWFncmFtXG4gKiAgIHBhcnRpY2lwYW50IENhbGxlclxuICogICBwYXJ0aWNpcGFudCBnZXREZXBlbmRlbmNpZXNcbiAqICAgcGFydGljaXBhbnQgcnVuQ29tbWFuZFxuICogICBwYXJ0aWNpcGFudCBKU09OXG4gKiAgIENhbGxlci0+PmdldERlcGVuZGVuY2llczogQ2FsbCB3aXRoIG9wdGlvbmFsIHBhdGhcbiAqICAgZ2V0RGVwZW5kZW5jaWVzLT4+cnVuQ29tbWFuZDogRXhlY3V0ZSAnbnBtIGxzIC0tanNvbidcbiAqICAgcnVuQ29tbWFuZC0tPj5nZXREZXBlbmRlbmNpZXM6IFJldHVybiBjb21tYW5kIG91dHB1dFxuICogICBnZXREZXBlbmRlbmNpZXMtPj5KU09OOiBQYXJzZSBjb21tYW5kIG91dHB1dFxuICogICBKU09OLS0+PmdldERlcGVuZGVuY2llczogUmV0dXJuIHBhcnNlZCBvYmplY3RcbiAqICAgZ2V0RGVwZW5kZW5jaWVzLT4+Z2V0RGVwZW5kZW5jaWVzOiBQcm9jZXNzIGRlcGVuZGVuY2llc1xuICogICBnZXREZXBlbmRlbmNpZXMtLT4+Q2FsbGVyOiBSZXR1cm4gcHJvY2Vzc2VkIGRlcGVuZGVuY2llc1xuICogQG1lbWJlck9mIG1vZHVsZTp1dGlsc1xuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZ2V0RGVwZW5kZW5jaWVzKFxuICBwOiBzdHJpbmcgPSBwcm9jZXNzLmN3ZCgpXG4pOiBQcm9taXNlPERlcGVuZGVuY3lNYXA+IHtcbiAgY29uc3QgcGtnUGF0aCA9IHBhdGguam9pbihwLCBcInBhY2thZ2UuanNvblwiKTtcbiAgY29uc3QgbG9ja1BhdGggPSBwYXRoLmpvaW4ocCwgXCJwYWNrYWdlLWxvY2suanNvblwiKTtcbiAgbGV0IHBrZzogYW55O1xuICB0cnkge1xuICAgIHBrZyA9IEpTT04ucGFyc2UocmVhZEZpbGUocGtnUGF0aCkpO1xuICB9IGNhdGNoIChlcnJvcjogdW5rbm93bikge1xuICAgIHRocm93IG5ldyBFcnJvcihgQ291bGQgbm90IHJlYWQgcGFja2FnZS5qc29uIGF0ICR7cGtnUGF0aH06ICR7ZXJyb3J9YCk7XG4gIH1cblxuICBsZXQgbG9jazogYW55O1xuICBpZiAoZnMuZXhpc3RzU3luYyhsb2NrUGF0aCkpIHtcbiAgICB0cnkge1xuICAgICAgbG9jayA9IEpTT04ucGFyc2UocmVhZEZpbGUobG9ja1BhdGgpKTtcbiAgICB9IGNhdGNoIChlcnJvcjogdW5rbm93bikge1xuICAgICAgbG9nZ2VyLndhcm4oYFVuYWJsZSB0byBwYXJzZSBwYWNrYWdlLWxvY2suanNvbiBhdCAke2xvY2tQYXRofTogJHtlcnJvcn1gKTtcbiAgICB9XG4gIH1cblxuICBjb25zdCBtYXBEZXBzID0gKGVudHJpZXM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7fSkgPT5cbiAgICBPYmplY3QuZW50cmllcyhlbnRyaWVzKS5tYXAoKFtuYW1lLCB2ZXJzaW9uXSkgPT4gKHtcbiAgICAgIG5hbWUsXG4gICAgICB2ZXJzaW9uOiByZXNvbHZlRGVwZW5kZW5jeVZlcnNpb24obG9jaywgbmFtZSwgdmVyc2lvbiksXG4gICAgfSkpO1xuXG4gIHJldHVybiB7XG4gICAgcHJvZDogbWFwRGVwcyhwa2cuZGVwZW5kZW5jaWVzKSxcbiAgICBkZXY6IG1hcERlcHMocGtnLmRldkRlcGVuZGVuY2llcyksXG4gICAgcGVlcjogbWFwRGVwcyhwa2cucGVlckRlcGVuZGVuY2llcyksXG4gIH07XG59XG5cbmZ1bmN0aW9uIHJlc29sdmVEZXBlbmRlbmN5VmVyc2lvbihcbiAgbG9jazogYW55LFxuICBuYW1lOiBzdHJpbmcsXG4gIGZhbGxiYWNrOiBzdHJpbmdcbik6IHN0cmluZyB7XG4gIGlmIChsb2NrKSB7XG4gICAgY29uc3QgcGFja2FnZXMgPSBsb2NrLnBhY2thZ2VzIHx8IHt9O1xuICAgIGNvbnN0IGtleSA9IGBub2RlX21vZHVsZXMvJHtuYW1lfWA7XG4gICAgaWYgKHBhY2thZ2VzW2tleV0gJiYgcGFja2FnZXNba2V5XS52ZXJzaW9uKSB7XG4gICAgICByZXR1cm4gcGFja2FnZXNba2V5XS52ZXJzaW9uO1xuICAgIH1cbiAgICBpZiAobG9jay5kZXBlbmRlbmNpZXMgJiYgbG9jay5kZXBlbmRlbmNpZXNbbmFtZV0pIHtcbiAgICAgIHJldHVybiBsb2NrLmRlcGVuZGVuY2llc1tuYW1lXS52ZXJzaW9uIHx8IGZhbGxiYWNrO1xuICAgIH1cbiAgfVxuICByZXR1cm4gZmFsbGJhY2s7XG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIFVwZGF0ZXMgcHJvamVjdCBkZXBlbmRlbmNpZXMgdG8gdGhlaXIgbGF0ZXN0IHZlcnNpb25zLlxuICogQHN1bW1hcnkgUnVucyBucG0tY2hlY2stdXBkYXRlcyB0byB1cGRhdGUgcGFja2FnZS5qc29uIGFuZCB0aGVuIGluc3RhbGxzIHRoZSB1cGRhdGVkIGRlcGVuZGVuY2llcy5cbiAqXG4gKiBAcmV0dXJuIHtQcm9taXNlPHZvaWQ+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIGRlcGVuZGVuY2llcyBhcmUgdXBkYXRlZC5cbiAqXG4gKiBAZnVuY3Rpb24gdXBkYXRlRGVwZW5kZW5jaWVzXG4gKlxuICogQG1lbWJlck9mIG1vZHVsZTp1dGlsc1xuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gdXBkYXRlRGVwZW5kZW5jaWVzKCkge1xuICBjb25zdCBsb2cgPSBsb2dnZXIuZm9yKHVwZGF0ZURlcGVuZGVuY2llcyk7XG4gIGxvZy5pbmZvKFwiY2hlY2tpbmcgZm9yIHVwZGF0ZXMuLi5cIik7XG4gIGF3YWl0IHJ1bkNvbW1hbmQoXCJucHggbnBtLWNoZWNrLXVwZGF0ZXMgLXVcIikucHJvbWlzZTtcbiAgbG9nLmluZm8oXCJ1cGRhdGluZy4uLlwiKTtcbiAgYXdhaXQgcnVuQ29tbWFuZChcIm5weCBucG0gcnVuIGRvLWluc3RhbGxcIikucHJvbWlzZTtcbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gSW5zdGFsbHMgZGVwZW5kZW5jaWVzIGlmIHRoZXkgYXJlIG5vdCBhbHJlYWR5IGF2YWlsYWJsZS5cbiAqIEBzdW1tYXJ5IENoZWNrcyBpZiBzcGVjaWZpZWQgZGVwZW5kZW5jaWVzIGFyZSBpbnN0YWxsZWQgYW5kIGluc3RhbGxzIGFueSB0aGF0IGFyZSBtaXNzaW5nLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nW10gfCBzdHJpbmd9IGRlcHMgLSBUaGUgZGVwZW5kZW5jaWVzIHRvIGNoZWNrIGFuZCBwb3RlbnRpYWxseSBpbnN0YWxsLlxuICogQHBhcmFtIHtTaW1wbGVEZXBlbmRlbmN5TWFwfSBbZGVwZW5kZW5jaWVzXSAtIE9wdGlvbmFsIG1hcCBvZiBleGlzdGluZyBkZXBlbmRlbmNpZXMuXG4gKiBAcmV0dXJuIHtQcm9taXNlPFNpbXBsZURlcGVuZGVuY3lNYXA+fSBVcGRhdGVkIG1hcCBvZiBkZXBlbmRlbmNpZXMuXG4gKlxuICogQGZ1bmN0aW9uIGluc3RhbGxJZk5vdEF2YWlsYWJsZVxuICpcbiAqIEBtZW1iZXJPZiBtb2R1bGU6dXRpbHNcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGluc3RhbGxJZk5vdEF2YWlsYWJsZShcbiAgZGVwczogc3RyaW5nW10gfCBzdHJpbmcsXG4gIGRlcGVuZGVuY2llcz86IFNpbXBsZURlcGVuZGVuY3lNYXBcbikge1xuICBkZXBzID0gdHlwZW9mIGRlcHMgPT09IFwic3RyaW5nXCIgPyBbZGVwc10gOiBkZXBzO1xuICBjb25zdCBjdXJyZW50OiBTaW1wbGVEZXBlbmRlbmN5TWFwID0ge1xuICAgIHByb2Q6IGRlcGVuZGVuY2llcz8ucHJvZCA/IFsuLi5kZXBlbmRlbmNpZXMucHJvZF0gOiBbXSxcbiAgICBkZXY6IGRlcGVuZGVuY2llcz8uZGV2ID8gWy4uLmRlcGVuZGVuY2llcy5kZXZdIDogW10sXG4gICAgcGVlcjogZGVwZW5kZW5jaWVzPy5wZWVyID8gWy4uLmRlcGVuZGVuY2llcy5wZWVyXSA6IFtdLFxuICB9O1xuXG4gIGNvbnN0IGtub3duID0gbmV3IFNldChbXG4gICAgLi4uKGN1cnJlbnQucHJvZCA/PyBbXSksXG4gICAgLi4uKGN1cnJlbnQuZGV2ID8/IFtdKSxcbiAgICAuLi4oY3VycmVudC5wZWVyID8/IFtdKSxcbiAgXSk7XG5cbiAgY29uc3QgdG9JbnN0YWxsOiBzdHJpbmdbXSA9IFtdO1xuICBmb3IgKGNvbnN0IGRlcCBvZiBkZXBzKSB7XG4gICAgaWYgKGtub3duLmhhcyhkZXApKSBjb250aW51ZTtcbiAgICB0cnkge1xuICAgICAgbG9jYWxSZXF1aXJlLnJlc29sdmUoZGVwKTtcbiAgICAgIGtub3duLmFkZChkZXApO1xuICAgIH0gY2F0Y2gge1xuICAgICAgdG9JbnN0YWxsLnB1c2goZGVwKTtcbiAgICB9XG4gIH1cblxuICBpZiAodG9JbnN0YWxsLmxlbmd0aCkge1xuICAgIGlmIChpc1Rlc3RFbnZpcm9ubWVudCgpKSB7XG4gICAgICBsb2dnZXIudmVyYm9zZShcbiAgICAgICAgYFNraXBwaW5nIGRlcGVuZGVuY3kgaW5zdGFsbCBpbiB0ZXN0IGVudmlyb25tZW50IGZvcjogJHt0b0luc3RhbGwuam9pbihcbiAgICAgICAgICBcIiwgXCJcbiAgICAgICAgKX1gXG4gICAgICApO1xuICAgIH0gZWxzZSB7XG4gICAgICBhd2FpdCBpbnN0YWxsRGVwZW5kZW5jaWVzKHsgZGV2OiB0b0luc3RhbGwgfSk7XG4gICAgfVxuICAgIGNvbnN0IGRldkRlcHMgPSBuZXcgU2V0KGN1cnJlbnQuZGV2ID8/IFtdKTtcbiAgICB0b0luc3RhbGwuZm9yRWFjaCgoZGVwKSA9PiBkZXZEZXBzLmFkZChkZXApKTtcbiAgICBjdXJyZW50LmRldiA9IEFycmF5LmZyb20oZGV2RGVwcyk7XG4gIH1cblxuICByZXR1cm4gY3VycmVudDtcbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gUHVzaGVzIGNoYW5nZXMgdG8gR2l0IHJlcG9zaXRvcnkuXG4gKiBAc3VtbWFyeSBUZW1wb3JhcmlseSBjaGFuZ2VzIEdpdCB1c2VyIGNvbmZpZ3VyYXRpb24sIGNvbW1pdHMgYWxsIGNoYW5nZXMsIHB1c2hlcyB0byByZW1vdGUsIGFuZCByZXN0b3JlcyBvcmlnaW5hbCB1c2VyIGNvbmZpZ3VyYXRpb24uXG4gKlxuICogQHJldHVybiB7UHJvbWlzZTx2b2lkPn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2hlbiBjaGFuZ2VzIGFyZSBwdXNoZWQuXG4gKlxuICogQGZ1bmN0aW9uIHB1c2hUb0dpdFxuICpcbiAqIEBtZW1iZXJPZiBtb2R1bGU6dXRpbHNcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHB1c2hUb0dpdCgpIHtcbiAgY29uc3QgbG9nID0gbG9nZ2VyLmZvcihwdXNoVG9HaXQpO1xuICBjb25zdCBnaXRVc2VyID0gYXdhaXQgcnVuQ29tbWFuZChcImdpdCBjb25maWcgdXNlci5uYW1lXCIpLnByb21pc2U7XG4gIGNvbnN0IGdpdEVtYWlsID0gYXdhaXQgcnVuQ29tbWFuZChcImdpdCBjb25maWcgdXNlci5lbWFpbFwiKS5wcm9taXNlO1xuICBsb2cudmVyYm9zZShgY2FjaGVkIGdpdCBpZDogJHtnaXRVc2VyfS8ke2dpdEVtYWlsfS4gY2hhbmdpbmcgdG8gYXV0b21hdGlvbmApO1xuICBhd2FpdCBydW5Db21tYW5kKCdnaXQgY29uZmlnIHVzZXIuZW1haWwgXCJhdXRvbWF0aW9uQGRlY2FmLnRzXCInKS5wcm9taXNlO1xuICBhd2FpdCBydW5Db21tYW5kKCdnaXQgY29uZmlnIHVzZXIubmFtZSBcImRlY2FmXCInKS5wcm9taXNlO1xuICBsb2cuaW5mbyhcIlB1c2hpbmcgY2hhbmdlcyB0byBnaXQuLi5cIik7XG4gIGF3YWl0IHJ1bkNvbW1hbmQoXCJnaXQgYWRkIC5cIikucHJvbWlzZTtcbiAgYXdhaXQgcnVuQ29tbWFuZChgZ2l0IGNvbW1pdCAtbSBcInJlZnMgIzEgLSBhZnRlciByZXBvIHNldHVwXCJgKS5wcm9taXNlO1xuICBhd2FpdCBydW5Db21tYW5kKFwiZ2l0IHB1c2hcIikucHJvbWlzZTtcbiAgYXdhaXQgcnVuQ29tbWFuZChgZ2l0IGNvbmZpZyB1c2VyLmVtYWlsIFwiJHtnaXRFbWFpbH1cImApLnByb21pc2U7XG4gIGF3YWl0IHJ1bkNvbW1hbmQoYGdpdCBjb25maWcgdXNlci5uYW1lIFwiJHtnaXRVc2VyfVwiYCkucHJvbWlzZTtcbiAgbG9nLnZlcmJvc2UoYHJldmVydGVkIHRvIGdpdCBpZDogJHtnaXRVc2VyfS8ke2dpdEVtYWlsfWApO1xufVxuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBJbnN0YWxscyBwcm9qZWN0IGRlcGVuZGVuY2llcy5cbiAqIEBzdW1tYXJ5IEluc3RhbGxzIHByb2R1Y3Rpb24sIGRldmVsb3BtZW50LCBhbmQgcGVlciBkZXBlbmRlbmNpZXMgYXMgc3BlY2lmaWVkLlxuICpcbiAqIEBwYXJhbSB7b2JqZWN0fSBkZXBlbmRlbmNpZXMgLSBPYmplY3QgY29udGFpbmluZyBhcnJheXMgb2YgZGVwZW5kZW5jaWVzIHRvIGluc3RhbGwuXG4gKiBAcGFyYW0ge3N0cmluZ1tdfSBbZGVwZW5kZW5jaWVzLnByb2RdIC0gUHJvZHVjdGlvbiBkZXBlbmRlbmNpZXMgdG8gaW5zdGFsbC5cbiAqIEBwYXJhbSB7c3RyaW5nW119IFtkZXBlbmRlbmNpZXMuZGV2XSAtIERldmVsb3BtZW50IGRlcGVuZGVuY2llcyB0byBpbnN0YWxsLlxuICogQHBhcmFtIHtzdHJpbmdbXX0gW2RlcGVuZGVuY2llcy5wZWVyXSAtIFBlZXIgZGVwZW5kZW5jaWVzIHRvIGluc3RhbGwuXG4gKiBAcmV0dXJuIHtQcm9taXNlPHZvaWQ+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIGFsbCBkZXBlbmRlbmNpZXMgYXJlIGluc3RhbGxlZC5cbiAqXG4gKiBAZnVuY3Rpb24gaW5zdGFsbERlcGVuZGVuY2llc1xuICpcbiAqIEBtZW1iZXJPZiBtb2R1bGU6dXRpbHNcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGluc3RhbGxEZXBlbmRlbmNpZXMoZGVwZW5kZW5jaWVzOiB7XG4gIHByb2Q/OiBzdHJpbmdbXTtcbiAgZGV2Pzogc3RyaW5nW107XG4gIHBlZXI/OiBzdHJpbmdbXTtcbn0pIHtcbiAgY29uc3QgbG9nID0gbG9nZ2VyLmZvcihpbnN0YWxsRGVwZW5kZW5jaWVzKTtcbiAgY29uc3QgcHJvZCA9IGRlcGVuZGVuY2llcy5wcm9kIHx8IFtdO1xuICBjb25zdCBkZXYgPSBkZXBlbmRlbmNpZXMuZGV2IHx8IFtdO1xuICBjb25zdCBwZWVyID0gZGVwZW5kZW5jaWVzLnBlZXIgfHwgW107XG4gIGlmIChwcm9kLmxlbmd0aCkge1xuICAgIGxvZy5pbmZvKGBJbnN0YWxsaW5nIGRlcGVuZGVuY2llcyAke3Byb2Quam9pbihcIiwgXCIpfS4uLmApO1xuICAgIGF3YWl0IHJ1bkNvbW1hbmQoYG5wbSBpbnN0YWxsICR7cHJvZC5qb2luKFwiIFwiKX1gLCB7IGN3ZDogcHJvY2Vzcy5jd2QoKSB9KVxuICAgICAgLnByb21pc2U7XG4gIH1cbiAgaWYgKGRldi5sZW5ndGgpIHtcbiAgICBsb2cuaW5mbyhgSW5zdGFsbGluZyBkZXZEZXBlbmRlbmNpZXMgJHtkZXYuam9pbihcIiwgXCIpfS4uLmApO1xuICAgIGF3YWl0IHJ1bkNvbW1hbmQoYG5wbSBpbnN0YWxsIC0tc2F2ZS1kZXYgJHtkZXYuam9pbihcIiBcIil9YCwge1xuICAgICAgY3dkOiBwcm9jZXNzLmN3ZCgpLFxuICAgIH0pLnByb21pc2U7XG4gIH1cbiAgaWYgKHBlZXIubGVuZ3RoKSB7XG4gICAgbG9nLmluZm8oYEluc3RhbGxpbmcgcGVlckRlcGVuZGVuY2llcyAke3BlZXIuam9pbihcIiwgXCIpfS4uLmApO1xuICAgIGF3YWl0IHJ1bkNvbW1hbmQoYG5wbSBpbnN0YWxsIC0tc2F2ZS1wZWVyICR7cGVlci5qb2luKFwiIFwiKX1gLCB7XG4gICAgICBjd2Q6IHByb2Nlc3MuY3dkKCksXG4gICAgfSkucHJvbWlzZTtcbiAgfVxufVxuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBOb3JtYWxpemVzIGltcG9ydHMgdG8gaGFuZGxlIGJvdGggQ29tbW9uSlMgYW5kIEVTTW9kdWxlIGZvcm1hdHMuXG4gKiBAc3VtbWFyeSBVdGlsaXR5IGZ1bmN0aW9uIHRvIGhhbmRsZSBtb2R1bGUgaW1wb3J0IGRpZmZlcmVuY2VzIGJldHdlZW4gZm9ybWF0cy5cbiAqXG4gKiBAdGVtcGxhdGUgVCAtIFR5cGUgb2YgdGhlIGltcG9ydGVkIG1vZHVsZS5cbiAqIEBwYXJhbSB7UHJvbWlzZTxUPn0gaW1wb3J0UHJvbWlzZSAtIFByb21pc2UgcmV0dXJuZWQgYnkgZHluYW1pYyBpbXBvcnQuXG4gKiBAcmV0dXJuIHtQcm9taXNlPFQ+fSBOb3JtYWxpemVkIG1vZHVsZS5cbiAqXG4gKiBAZnVuY3Rpb24gbm9ybWFsaXplSW1wb3J0XG4gKlxuICogQG1lbWJlck9mIG1vZHVsZTp1dGlsc1xuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gbm9ybWFsaXplSW1wb3J0PFQ+KFxuICBpbXBvcnRQcm9taXNlOiBQcm9taXNlPFQ+XG4pOiBQcm9taXNlPFQ+IHtcbiAgLy8gQ29tbW9uSlMncyBgbW9kdWxlLmV4cG9ydHNgIGlzIHdyYXBwZWQgYXMgYGRlZmF1bHRgIGluIEVTTW9kdWxlLlxuICByZXR1cm4gaW1wb3J0UHJvbWlzZS50aGVuKChtOiBhbnkpID0+IChtLmRlZmF1bHQgfHwgbSkgYXMgVCk7XG59XG5cbi8vIE5ldyBoZWxwZXI6IGNvbXB1dGUgZ3ppcHBlZCBzaXplIG9mIHNtYWxsZXN0IEpTIGZpbGUgaW4gYSBkaXJlY3RvcnlcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBnZXRGaWxlU2l6ZVppcHBlZChkaXI6IHN0cmluZyk6IFByb21pc2U8bnVtYmVyPiB7XG4gIGNvbnN0IGxvZyA9IGxvZ2dlci5mb3IoZ2V0RmlsZVNpemVaaXBwZWQpO1xuICB0cnkge1xuICAgIGNvbnN0IGVudHJpZXMgPSBmcy5yZWFkZGlyU3luYyhkaXIpO1xuICAgIGNvbnN0IGNhbmRpZGF0ZXMgPSBlbnRyaWVzXG4gICAgICAubWFwKChlKSA9PiBwYXRoLmpvaW4oZGlyLCBlKSlcbiAgICAgIC5maWx0ZXIoKHApID0+IHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBjb25zdCBzID0gZnMuc3RhdFN5bmMocCk7XG4gICAgICAgICAgcmV0dXJuIChcbiAgICAgICAgICAgIHMuaXNGaWxlKCkgJiZcbiAgICAgICAgICAgIChwLmVuZHNXaXRoKFwiLmpzXCIpIHx8IHAuZW5kc1dpdGgoXCIuY2pzXCIpIHx8IHAuZW5kc1dpdGgoXCIubWpzXCIpKVxuICAgICAgICAgICk7XG4gICAgICAgIH0gY2F0Y2gge1xuICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgfSk7XG5cbiAgICBpZiAoY2FuZGlkYXRlcy5sZW5ndGggPT09IDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgTm8gSlMgZmlsZXMgZm91bmQgaW4gZGlyZWN0b3J5ICR7ZGlyfWApO1xuICAgIH1cblxuICAgIC8vIGNob29zZSB0aGUgc21hbGxlc3QgYnkgcmF3IGZpbGUgc2l6ZVxuICAgIGxldCBzbWFsbGVzdCA9IGNhbmRpZGF0ZXNbMF07XG4gICAgbGV0IHNtYWxsZXN0U2l6ZSA9IGZzLnN0YXRTeW5jKHNtYWxsZXN0KS5zaXplO1xuICAgIGZvciAoY29uc3QgYyBvZiBjYW5kaWRhdGVzLnNsaWNlKDEpKSB7XG4gICAgICBjb25zdCBzID0gZnMuc3RhdFN5bmMoYykuc2l6ZTtcbiAgICAgIGlmIChzIDwgc21hbGxlc3RTaXplKSB7XG4gICAgICAgIHNtYWxsZXN0ID0gYztcbiAgICAgICAgc21hbGxlc3RTaXplID0gcztcbiAgICAgIH1cbiAgICB9XG5cbiAgICBsb2cudmVyYm9zZShcbiAgICAgIGBTZWxlY3RlZCBzbWFsbGVzdCBidW5kbGU6ICR7c21hbGxlc3R9ICgke3NtYWxsZXN0U2l6ZX0gYnl0ZXMpYFxuICAgICk7XG5cbiAgICBjb25zdCBidWZmZXIgPSBmcy5yZWFkRmlsZVN5bmMoc21hbGxlc3QpO1xuICAgIGNvbnN0IGd6ID0gemxpYi5nemlwU3luYyhidWZmZXIpO1xuICAgIGNvbnN0IHNpemVLYiA9IE51bWJlcigoZ3oubGVuZ3RoIC8gMTAyNCkudG9GaXhlZCgxKSk7XG4gICAgbG9nLnZlcmJvc2UoYEd6aXBwZWQgc2l6ZTogJHtnei5sZW5ndGh9IGJ5dGVzICgke3NpemVLYn0gS0IpYCk7XG4gICAgcmV0dXJuIHNpemVLYjtcbiAgfSBjYXRjaCAoZTogdW5rbm93bikge1xuICAgIGxvZy52ZXJib3NlKGBGYWlsZWQgdG8gY29tcHV0ZSBnemlwcGVkIHNpemUgZm9yICR7ZGlyfTogJHtlfWApO1xuICAgIHRocm93IGUgYXMgRXJyb3I7XG4gIH1cbn1cblxuLy8gTmV3IGhlbHBlcjogbGlzdCBmb2xkZXIgZW50cmllcyAobmFtZXMpIHdpdGggb3B0aW9uYWwgZmlsdGVyXG5leHBvcnQgZnVuY3Rpb24gbGlzdEZvbGRlcihcbiAgYmFzZVBhdGg6IHN0cmluZyA9IHByb2Nlc3MuY3dkKCksXG4gIGZpbHRlcj86IChuYW1lOiBzdHJpbmcsIGRpcmVudDogZnMuRGlyZW50KSA9PiBib29sZWFuXG4pOiBzdHJpbmdbXSB7XG4gIGNvbnN0IGxvZyA9IGxvZ2dlci5mb3IobGlzdEZvbGRlcik7XG4gIHRyeSB7XG4gICAgaWYgKCFmcy5leGlzdHNTeW5jKGJhc2VQYXRoKSkgcmV0dXJuIFtdO1xuICAgIGNvbnN0IGVudHJpZXMgPSBmcy5yZWFkZGlyU3luYyhiYXNlUGF0aCwgeyB3aXRoRmlsZVR5cGVzOiB0cnVlIH0pO1xuICAgIGNvbnN0IG5hbWVzID0gZW50cmllc1xuICAgICAgLmZpbHRlcigoZCkgPT4gKGZpbHRlciA/IGZpbHRlcihkLm5hbWUsIGQpIDogdHJ1ZSkpXG4gICAgICAubWFwKChkKSA9PiBkLm5hbWUpO1xuICAgIHJldHVybiBuYW1lcztcbiAgfSBjYXRjaCAoZTogdW5rbm93bikge1xuICAgIGxvZy52ZXJib3NlKGBGYWlsZWQgdG8gbGlzdCBmb2xkZXIgJHtiYXNlUGF0aH06ICR7ZX1gKTtcbiAgICByZXR1cm4gW107XG4gIH1cbn1cblxuLy8gTmV3IGhlbHBlcjogbGlzdCBub2RlX21vZHVsZXMgcGFja2FnZSBuYW1lcywgZXhwYW5kaW5nIHNjb3BlZCBwYWNrYWdlc1xuZXhwb3J0IGZ1bmN0aW9uIGxpc3ROb2RlTW9kdWxlc1BhY2thZ2VzKFxuICBiYXNlUGF0aDogc3RyaW5nID0gcGF0aC5qb2luKHByb2Nlc3MuY3dkKCksIFwibm9kZV9tb2R1bGVzXCIpXG4pOiBzdHJpbmdbXSB7XG4gIGNvbnN0IGxvZyA9IGxvZ2dlci5mb3IobGlzdE5vZGVNb2R1bGVzUGFja2FnZXMpO1xuICB0cnkge1xuICAgIGlmICghZnMuZXhpc3RzU3luYyhiYXNlUGF0aCkpIHJldHVybiBbXTtcbiAgICBjb25zdCBlbnRyaWVzID0gZnMucmVhZGRpclN5bmMoYmFzZVBhdGgsIHsgd2l0aEZpbGVUeXBlczogdHJ1ZSB9KTtcbiAgICBjb25zdCBuYW1lczogc3RyaW5nW10gPSBbXTtcblxuICAgIGZvciAoY29uc3QgZSBvZiBlbnRyaWVzKSB7XG4gICAgICB0cnkge1xuICAgICAgICBpZiAoIWUuaXNEaXJlY3RvcnkoKSkgY29udGludWU7XG4gICAgICAgIC8vIGlnbm9yZSBoaWRkZW4gZm9sZGVyc1xuICAgICAgICBpZiAoZS5uYW1lLnN0YXJ0c1dpdGgoXCIuXCIpKSBjb250aW51ZTtcbiAgICAgICAgaWYgKGUubmFtZS5zdGFydHNXaXRoKFwiQFwiKSkge1xuICAgICAgICAgIC8vIGEgc2NvcGUgZm9sZGVyOyBleHBhbmQgY29udGFpbmVkIHBhY2thZ2VzXG4gICAgICAgICAgY29uc3Qgc2NvcGVQYXRoID0gcGF0aC5qb2luKGJhc2VQYXRoLCBlLm5hbWUpO1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjb25zdCBzY29wZWQgPSBmcy5yZWFkZGlyU3luYyhzY29wZVBhdGgsIHsgd2l0aEZpbGVUeXBlczogdHJ1ZSB9KTtcbiAgICAgICAgICAgIGZvciAoY29uc3QgcyBvZiBzY29wZWQpIHtcbiAgICAgICAgICAgICAgaWYgKHMuaXNEaXJlY3RvcnkoKSAmJiAhcy5uYW1lLnN0YXJ0c1dpdGgoXCIuXCIpKSB7XG4gICAgICAgICAgICAgICAgbmFtZXMucHVzaChgJHtlLm5hbWV9LyR7cy5uYW1lfWApO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICAvLyBpZ25vcmUgc2NvcGUgcmVhZCBlcnJvcnNcbiAgICAgICAgICAgIGxvZy52ZXJib3NlKGBGYWlsZWQgdG8gcmVhZCBzY29wZSAke3Njb3BlUGF0aH06ICR7ZXJyfWApO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBuYW1lcy5wdXNoKGUubmFtZSk7XG4gICAgICAgIH1cbiAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICBsb2cudmVyYm9zZShgU2tpcHBpbmcgZW50cnkgJHtlLm5hbWV9IGR1ZSB0byBlcnJvcjogJHtlcnJ9YCk7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBuYW1lcztcbiAgfSBjYXRjaCAoZTogdW5rbm93bikge1xuICAgIGxvZy52ZXJib3NlKGBGYWlsZWQgdG8gbGlzdCBub2RlX21vZHVsZXMgcGFja2FnZXMgYXQgJHtiYXNlUGF0aH06ICR7ZX1gKTtcbiAgICByZXR1cm4gW107XG4gIH1cbn1cbiIsIi8qKlxuICogQGRlc2NyaXB0aW9uIERlZmluaXRpb24gb2YgYSBzbG9nYW4gaXRlbS5cbiAqIEBzdW1tYXJ5IFJlcHJlc2VudHMgYSBzaW5nbGUgc2xvZ2FuIGVudHJ5IHdpdGggdGV4dCBhbmQgdGFncy5cbiAqIEB0eXBlZGVmIHtPYmplY3R9IFNsb2dhbkl0ZW1cbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBTbG9nYW4gLSBUaGUgc2xvZ2FuIHRleHQuXG4gKiBAcHJvcGVydHkge3N0cmluZ30gVGFncyAtIENvbW1hLXNlcGFyYXRlZCB0YWdzIGRlc2NyaWJpbmcgdGhlIHNsb2dhbi5cbiAqIEBtZW1iZXJPZiBtb2R1bGU6dXRpbHNcbiAqL1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBMaXN0IG9mIGF2YWlsYWJsZSBzbG9nYW5zIGZvciBiYW5uZXJzIGFuZCBtZXNzYWdlcy5cbiAqIEBzdW1tYXJ5IEltbXV0YWJsZSBhcnJheSBvZiBzbG9nYW4gZW50cmllcyB1c2VkIGJ5IHtAbGluayBnZXRTbG9nYW59IGFuZCBiYW5uZXIgcmVuZGVyaW5nLlxuICogQHR5cGUge1Nsb2dhbkl0ZW1bXX1cbiAqIEBjb25zdCBzbG9nYW5zXG4gKiBAbWVtYmVyT2YgbW9kdWxlOnV0aWxzXG4gKi9cbmV4cG9ydCBjb25zdCBzbG9nYW5zID0gW1xuICB7XG4gICAgU2xvZ2FuOiBcIk5vIGNhZmZlaW5lLCBubyBjaGFvcy4gSnVzdCBjbGVhbiBjb2RlLlwiLFxuICAgIFRhZ3M6IFwiQ29mZmVlLXRoZW1lZCwgQ2FsbSwgVGVjaFwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIkZ1bGwgZmxhdm9yLCBubyBqaXR0ZXJzLiBUaGF0J3MgRGVjYWYtVFMuXCIsXG4gICAgVGFnczogXCJDb2ZmZWUtdGhlbWVkLCBDaGVlcmZ1bFwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIkNoaWxsIGZ1bGxzdGFjay4gUG93ZXJlZCBieSBEZWNhZi5cIixcbiAgICBUYWdzOiBcIkNvZmZlZS10aGVtZWQsIEZ1biwgVGVjaFwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIkRlY2FmLVRTOiBCcmV3ZWQgZm9yIGNhbG0gY29kZS5cIixcbiAgICBUYWdzOiBcIkNvZmZlZS10aGVtZWQsIEJyYW5kaW5nXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiU21vb3RoIGFzIHlvdXIgbW9ybmluZyBEZWNhZi5cIixcbiAgICBUYWdzOiBcIkNvZmZlZS10aGVtZWQsIENoaWxsXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiQWxsIHRoZSBraWNrLCBub25lIG9mIHRoZSBjcmFzaC5cIixcbiAgICBUYWdzOiBcIkNvZmZlZS10aGVtZWQsIEVuZXJnZXRpY1wiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIlNpcCBiYWNrIGFuZCBzaGlwIGZhc3Rlci5cIixcbiAgICBUYWdzOiBcIkNvZmZlZS10aGVtZWQsIEZ1blwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIktlZXAgY2FsbSBhbmQgY29kZSBEZWNhZi5cIixcbiAgICBUYWdzOiBcIkNvZmZlZS10aGVtZWQsIFBsYXlmdWxcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJDb2RlIHdpdGhvdXQgdGhlIGNhZmZlaW5lIHNoYWtlcy5cIixcbiAgICBUYWdzOiBcIkNvZmZlZS10aGVtZWQsIEh1bW9yb3VzXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiWW91ciBmdWxsc3RhY2ssIGRlY2FmZmVpbmF0ZWQuXCIsXG4gICAgVGFnczogXCJDb2ZmZWUtdGhlbWVkLCBUZWNobmljYWxcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJObyBjYWZmZWluZSwgbm8gY2hhb3MuIEp1c3QgY2xlYW4gY29kZS5cIixcbiAgICBUYWdzOiBcIkNvZmZlZS10aGVtZWQsIENhbG0sIFRlY2hcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJGdWxsIGZsYXZvciwgbm8gaml0dGVycy4gVGhhdFxcdTIwMTlzIERlY2FmLVRTLlwiLFxuICAgIFRhZ3M6IFwiQ29mZmVlLXRoZW1lZCwgQ2hlZXJmdWxcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJDaGlsbCBmdWxsc3RhY2suIFBvd2VyZWQgYnkgRGVjYWYuXCIsXG4gICAgVGFnczogXCJDb2ZmZWUtdGhlbWVkLCBGdW4sIFRlY2hcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJEZWNhZi1UUzogQnJld2VkIGZvciBjYWxtIGNvZGUuXCIsXG4gICAgVGFnczogXCJDb2ZmZWUtdGhlbWVkLCBCcmFuZGluZ1wiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIlNtb290aCBhcyB5b3VyIG1vcm5pbmcgRGVjYWYuXCIsXG4gICAgVGFnczogXCJDb2ZmZWUtdGhlbWVkLCBDaGlsbFwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIkFsbCB0aGUga2ljaywgbm9uZSBvZiB0aGUgY3Jhc2guXCIsXG4gICAgVGFnczogXCJDb2ZmZWUtdGhlbWVkLCBFbmVyZ2V0aWNcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJTaXAgYmFjayBhbmQgc2hpcCBmYXN0ZXIuXCIsXG4gICAgVGFnczogXCJDb2ZmZWUtdGhlbWVkLCBGdW5cIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJLZWVwIGNhbG0gYW5kIGNvZGUgRGVjYWYuXCIsXG4gICAgVGFnczogXCJDb2ZmZWUtdGhlbWVkLCBQbGF5ZnVsXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiQ29kZSB3aXRob3V0IHRoZSBjYWZmZWluZSBzaGFrZXMuXCIsXG4gICAgVGFnczogXCJDb2ZmZWUtdGhlbWVkLCBIdW1vcm91c1wiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIllvdXIgZnVsbHN0YWNrLCBkZWNhZmZlaW5hdGVkLlwiLFxuICAgIFRhZ3M6IFwiQ29mZmVlLXRoZW1lZCwgVGVjaG5pY2FsXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiTm8gY2FmZmVpbmUsIG5vIGNoYW9zLiBKdXN0IGNsZWFuIGNvZGUuXCIsXG4gICAgVGFnczogXCJDb2ZmZWUtdGhlbWVkLCBDYWxtLCBUZWNoXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiRnVsbCBmbGF2b3IsIG5vIGppdHRlcnMuIFRoYXRcXHUyMDE5cyBEZWNhZi1UUy5cIixcbiAgICBUYWdzOiBcIkNvZmZlZS10aGVtZWQsIENoZWVyZnVsXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiQ2hpbGwgZnVsbHN0YWNrLiBQb3dlcmVkIGJ5IERlY2FmLlwiLFxuICAgIFRhZ3M6IFwiQ29mZmVlLXRoZW1lZCwgRnVuLCBUZWNoXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiRGVjYWYtVFM6IEJyZXdlZCBmb3IgY2FsbSBjb2RlLlwiLFxuICAgIFRhZ3M6IFwiQ29mZmVlLXRoZW1lZCwgQnJhbmRpbmdcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJTbW9vdGggYXMgeW91ciBtb3JuaW5nIERlY2FmLlwiLFxuICAgIFRhZ3M6IFwiQ29mZmVlLXRoZW1lZCwgQ2hpbGxcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJBbGwgdGhlIGtpY2ssIG5vbmUgb2YgdGhlIGNyYXNoLlwiLFxuICAgIFRhZ3M6IFwiQ29mZmVlLXRoZW1lZCwgRW5lcmdldGljXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiU2lwIGJhY2sgYW5kIHNoaXAgZmFzdGVyLlwiLFxuICAgIFRhZ3M6IFwiQ29mZmVlLXRoZW1lZCwgRnVuXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiS2VlcCBjYWxtIGFuZCBjb2RlIERlY2FmLlwiLFxuICAgIFRhZ3M6IFwiQ29mZmVlLXRoZW1lZCwgUGxheWZ1bFwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIkNvZGUgd2l0aG91dCB0aGUgY2FmZmVpbmUgc2hha2VzLlwiLFxuICAgIFRhZ3M6IFwiQ29mZmVlLXRoZW1lZCwgSHVtb3JvdXNcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJZb3VyIGZ1bGxzdGFjaywgZGVjYWZmZWluYXRlZC5cIixcbiAgICBUYWdzOiBcIkNvZmZlZS10aGVtZWQsIFRlY2huaWNhbFwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIk5vIGNhZmZlaW5lLCBubyBjaGFvcy4gSnVzdCBjbGVhbiBjb2RlLlwiLFxuICAgIFRhZ3M6IFwiQ29mZmVlLXRoZW1lZCwgQ2FsbSwgVGVjaFwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIkZ1bGwgZmxhdm9yLCBubyBqaXR0ZXJzLiBUaGF0XFx1MjAxOXMgRGVjYWYtVFMuXCIsXG4gICAgVGFnczogXCJDb2ZmZWUtdGhlbWVkLCBDaGVlcmZ1bFwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIkNoaWxsIGZ1bGxzdGFjay4gUG93ZXJlZCBieSBEZWNhZi5cIixcbiAgICBUYWdzOiBcIkNvZmZlZS10aGVtZWQsIEZ1biwgVGVjaFwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIkRlY2FmLVRTOiBCcmV3ZWQgZm9yIGNhbG0gY29kZS5cIixcbiAgICBUYWdzOiBcIkNvZmZlZS10aGVtZWQsIEJyYW5kaW5nXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiU21vb3RoIGFzIHlvdXIgbW9ybmluZyBEZWNhZi5cIixcbiAgICBUYWdzOiBcIkNvZmZlZS10aGVtZWQsIENoaWxsXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiQWxsIHRoZSBraWNrLCBub25lIG9mIHRoZSBjcmFzaC5cIixcbiAgICBUYWdzOiBcIkNvZmZlZS10aGVtZWQsIEVuZXJnZXRpY1wiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIlNpcCBiYWNrIGFuZCBzaGlwIGZhc3Rlci5cIixcbiAgICBUYWdzOiBcIkNvZmZlZS10aGVtZWQsIEZ1blwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIktlZXAgY2FsbSBhbmQgY29kZSBEZWNhZi5cIixcbiAgICBUYWdzOiBcIkNvZmZlZS10aGVtZWQsIFBsYXlmdWxcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJDb2RlIHdpdGhvdXQgdGhlIGNhZmZlaW5lIHNoYWtlcy5cIixcbiAgICBUYWdzOiBcIkNvZmZlZS10aGVtZWQsIEh1bW9yb3VzXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiWW91ciBmdWxsc3RhY2ssIGRlY2FmZmVpbmF0ZWQuXCIsXG4gICAgVGFnczogXCJDb2ZmZWUtdGhlbWVkLCBUZWNobmljYWxcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJObyBjYWZmZWluZSwgbm8gY2hhb3MuIEp1c3QgY2xlYW4gY29kZS5cIixcbiAgICBUYWdzOiBcIkNvZmZlZS10aGVtZWQsIENhbG0sIFRlY2hcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJGdWxsIGZsYXZvciwgbm8gaml0dGVycy4gVGhhdFxcdTIwMTlzIERlY2FmLVRTLlwiLFxuICAgIFRhZ3M6IFwiQ29mZmVlLXRoZW1lZCwgQ2hlZXJmdWxcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJDaGlsbCBmdWxsc3RhY2suIFBvd2VyZWQgYnkgRGVjYWYuXCIsXG4gICAgVGFnczogXCJDb2ZmZWUtdGhlbWVkLCBGdW4sIFRlY2hcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJEZWNhZi1UUzogQnJld2VkIGZvciBjYWxtIGNvZGUuXCIsXG4gICAgVGFnczogXCJDb2ZmZWUtdGhlbWVkLCBCcmFuZGluZ1wiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIlNtb290aCBhcyB5b3VyIG1vcm5pbmcgRGVjYWYuXCIsXG4gICAgVGFnczogXCJDb2ZmZWUtdGhlbWVkLCBDaGlsbFwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIkFsbCB0aGUga2ljaywgbm9uZSBvZiB0aGUgY3Jhc2guXCIsXG4gICAgVGFnczogXCJDb2ZmZWUtdGhlbWVkLCBFbmVyZ2V0aWNcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJTaXAgYmFjayBhbmQgc2hpcCBmYXN0ZXIuXCIsXG4gICAgVGFnczogXCJDb2ZmZWUtdGhlbWVkLCBGdW5cIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJLZWVwIGNhbG0gYW5kIGNvZGUgRGVjYWYuXCIsXG4gICAgVGFnczogXCJDb2ZmZWUtdGhlbWVkLCBQbGF5ZnVsXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiQ29kZSB3aXRob3V0IHRoZSBjYWZmZWluZSBzaGFrZXMuXCIsXG4gICAgVGFnczogXCJDb2ZmZWUtdGhlbWVkLCBIdW1vcm91c1wiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIllvdXIgZnVsbHN0YWNrLCBkZWNhZmZlaW5hdGVkLlwiLFxuICAgIFRhZ3M6IFwiQ29mZmVlLXRoZW1lZCwgVGVjaG5pY2FsXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiTm8gY2FmZmVpbmUsIG5vIGNoYW9zLiBKdXN0IGNsZWFuIGNvZGUuXCIsXG4gICAgVGFnczogXCJDb2ZmZWUtdGhlbWVkLCBDYWxtLCBUZWNoXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiRnVsbCBmbGF2b3IsIG5vIGppdHRlcnMuIFRoYXRcXHUyMDE5cyBEZWNhZi1UUy5cIixcbiAgICBUYWdzOiBcIkNvZmZlZS10aGVtZWQsIENoZWVyZnVsXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiQ2hpbGwgZnVsbHN0YWNrLiBQb3dlcmVkIGJ5IERlY2FmLlwiLFxuICAgIFRhZ3M6IFwiQ29mZmVlLXRoZW1lZCwgRnVuLCBUZWNoXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiRGVjYWYtVFM6IEJyZXdlZCBmb3IgY2FsbSBjb2RlLlwiLFxuICAgIFRhZ3M6IFwiQ29mZmVlLXRoZW1lZCwgQnJhbmRpbmdcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJTbW9vdGggYXMgeW91ciBtb3JuaW5nIERlY2FmLlwiLFxuICAgIFRhZ3M6IFwiQ29mZmVlLXRoZW1lZCwgQ2hpbGxcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJBbGwgdGhlIGtpY2ssIG5vbmUgb2YgdGhlIGNyYXNoLlwiLFxuICAgIFRhZ3M6IFwiQ29mZmVlLXRoZW1lZCwgRW5lcmdldGljXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiU2lwIGJhY2sgYW5kIHNoaXAgZmFzdGVyLlwiLFxuICAgIFRhZ3M6IFwiQ29mZmVlLXRoZW1lZCwgRnVuXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiS2VlcCBjYWxtIGFuZCBjb2RlIERlY2FmLlwiLFxuICAgIFRhZ3M6IFwiQ29mZmVlLXRoZW1lZCwgUGxheWZ1bFwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIkNvZGUgd2l0aG91dCB0aGUgY2FmZmVpbmUgc2hha2VzLlwiLFxuICAgIFRhZ3M6IFwiQ29mZmVlLXRoZW1lZCwgSHVtb3JvdXNcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJZb3VyIGZ1bGxzdGFjaywgZGVjYWZmZWluYXRlZC5cIixcbiAgICBUYWdzOiBcIkNvZmZlZS10aGVtZWQsIFRlY2huaWNhbFwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIk5vIGNhZmZlaW5lLCBubyBjaGFvcy4gSnVzdCBjbGVhbiBjb2RlLlwiLFxuICAgIFRhZ3M6IFwiQ29mZmVlLXRoZW1lZCwgQ2FsbSwgVGVjaFwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIkZ1bGwgZmxhdm9yLCBubyBqaXR0ZXJzLiBUaGF0XFx1MjAxOXMgRGVjYWYtVFMuXCIsXG4gICAgVGFnczogXCJDb2ZmZWUtdGhlbWVkLCBDaGVlcmZ1bFwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIkNoaWxsIGZ1bGxzdGFjay4gUG93ZXJlZCBieSBEZWNhZi5cIixcbiAgICBUYWdzOiBcIkNvZmZlZS10aGVtZWQsIEZ1biwgVGVjaFwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIkRlY2FmLVRTOiBCcmV3ZWQgZm9yIGNhbG0gY29kZS5cIixcbiAgICBUYWdzOiBcIkNvZmZlZS10aGVtZWQsIEJyYW5kaW5nXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiU21vb3RoIGFzIHlvdXIgbW9ybmluZyBEZWNhZi5cIixcbiAgICBUYWdzOiBcIkNvZmZlZS10aGVtZWQsIENoaWxsXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiQWxsIHRoZSBraWNrLCBub25lIG9mIHRoZSBjcmFzaC5cIixcbiAgICBUYWdzOiBcIkNvZmZlZS10aGVtZWQsIEVuZXJnZXRpY1wiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIlNpcCBiYWNrIGFuZCBzaGlwIGZhc3Rlci5cIixcbiAgICBUYWdzOiBcIkNvZmZlZS10aGVtZWQsIEZ1blwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIktlZXAgY2FsbSBhbmQgY29kZSBEZWNhZi5cIixcbiAgICBUYWdzOiBcIkNvZmZlZS10aGVtZWQsIFBsYXlmdWxcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJDb2RlIHdpdGhvdXQgdGhlIGNhZmZlaW5lIHNoYWtlcy5cIixcbiAgICBUYWdzOiBcIkNvZmZlZS10aGVtZWQsIEh1bW9yb3VzXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiWW91ciBmdWxsc3RhY2ssIGRlY2FmZmVpbmF0ZWQuXCIsXG4gICAgVGFnczogXCJDb2ZmZWUtdGhlbWVkLCBUZWNobmljYWxcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJObyBjYWZmZWluZSwgbm8gY2hhb3MuIEp1c3QgY2xlYW4gY29kZS5cIixcbiAgICBUYWdzOiBcIkNvZmZlZS10aGVtZWQsIENhbG0sIFRlY2hcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJGdWxsIGZsYXZvciwgbm8gaml0dGVycy4gVGhhdFxcdTIwMTlzIERlY2FmLVRTLlwiLFxuICAgIFRhZ3M6IFwiQ29mZmVlLXRoZW1lZCwgQ2hlZXJmdWxcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJDaGlsbCBmdWxsc3RhY2suIFBvd2VyZWQgYnkgRGVjYWYuXCIsXG4gICAgVGFnczogXCJDb2ZmZWUtdGhlbWVkLCBGdW4sIFRlY2hcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJEZWNhZi1UUzogQnJld2VkIGZvciBjYWxtIGNvZGUuXCIsXG4gICAgVGFnczogXCJDb2ZmZWUtdGhlbWVkLCBCcmFuZGluZ1wiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIlNtb290aCBhcyB5b3VyIG1vcm5pbmcgRGVjYWYuXCIsXG4gICAgVGFnczogXCJDb2ZmZWUtdGhlbWVkLCBDaGlsbFwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIkFsbCB0aGUga2ljaywgbm9uZSBvZiB0aGUgY3Jhc2guXCIsXG4gICAgVGFnczogXCJDb2ZmZWUtdGhlbWVkLCBFbmVyZ2V0aWNcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJTaXAgYmFjayBhbmQgc2hpcCBmYXN0ZXIuXCIsXG4gICAgVGFnczogXCJDb2ZmZWUtdGhlbWVkLCBGdW5cIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJLZWVwIGNhbG0gYW5kIGNvZGUgRGVjYWYuXCIsXG4gICAgVGFnczogXCJDb2ZmZWUtdGhlbWVkLCBQbGF5ZnVsXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiQ29kZSB3aXRob3V0IHRoZSBjYWZmZWluZSBzaGFrZXMuXCIsXG4gICAgVGFnczogXCJDb2ZmZWUtdGhlbWVkLCBIdW1vcm91c1wiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIllvdXIgZnVsbHN0YWNrLCBkZWNhZmZlaW5hdGVkLlwiLFxuICAgIFRhZ3M6IFwiQ29mZmVlLXRoZW1lZCwgVGVjaG5pY2FsXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiTm8gY2FmZmVpbmUsIG5vIGNoYW9zLiBKdXN0IGNsZWFuIGNvZGUuXCIsXG4gICAgVGFnczogXCJDb2ZmZWUtdGhlbWVkLCBDYWxtLCBUZWNoXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiRnVsbCBmbGF2b3IsIG5vIGppdHRlcnMuIFRoYXRcXHUyMDE5cyBEZWNhZi1UUy5cIixcbiAgICBUYWdzOiBcIkNvZmZlZS10aGVtZWQsIENoZWVyZnVsXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiQ2hpbGwgZnVsbHN0YWNrLiBQb3dlcmVkIGJ5IERlY2FmLlwiLFxuICAgIFRhZ3M6IFwiQ29mZmVlLXRoZW1lZCwgRnVuLCBUZWNoXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiRGVjYWYtVFM6IEJyZXdlZCBmb3IgY2FsbSBjb2RlLlwiLFxuICAgIFRhZ3M6IFwiQ29mZmVlLXRoZW1lZCwgQnJhbmRpbmdcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJTbW9vdGggYXMgeW91ciBtb3JuaW5nIERlY2FmLlwiLFxuICAgIFRhZ3M6IFwiQ29mZmVlLXRoZW1lZCwgQ2hpbGxcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJBbGwgdGhlIGtpY2ssIG5vbmUgb2YgdGhlIGNyYXNoLlwiLFxuICAgIFRhZ3M6IFwiQ29mZmVlLXRoZW1lZCwgRW5lcmdldGljXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiU2lwIGJhY2sgYW5kIHNoaXAgZmFzdGVyLlwiLFxuICAgIFRhZ3M6IFwiQ29mZmVlLXRoZW1lZCwgRnVuXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiS2VlcCBjYWxtIGFuZCBjb2RlIERlY2FmLlwiLFxuICAgIFRhZ3M6IFwiQ29mZmVlLXRoZW1lZCwgUGxheWZ1bFwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIkNvZGUgd2l0aG91dCB0aGUgY2FmZmVpbmUgc2hha2VzLlwiLFxuICAgIFRhZ3M6IFwiQ29mZmVlLXRoZW1lZCwgSHVtb3JvdXNcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJZb3VyIGZ1bGxzdGFjaywgZGVjYWZmZWluYXRlZC5cIixcbiAgICBUYWdzOiBcIkNvZmZlZS10aGVtZWQsIFRlY2huaWNhbFwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIk5vIGNhZmZlaW5lLCBubyBjaGFvcy4gSnVzdCBjbGVhbiBjb2RlLlwiLFxuICAgIFRhZ3M6IFwiQ29mZmVlLXRoZW1lZCwgQ2FsbSwgVGVjaFwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIkZ1bGwgZmxhdm9yLCBubyBqaXR0ZXJzLiBUaGF0XFx1MjAxOXMgRGVjYWYtVFMuXCIsXG4gICAgVGFnczogXCJDb2ZmZWUtdGhlbWVkLCBDaGVlcmZ1bFwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIkNoaWxsIGZ1bGxzdGFjay4gUG93ZXJlZCBieSBEZWNhZi5cIixcbiAgICBUYWdzOiBcIkNvZmZlZS10aGVtZWQsIEZ1biwgVGVjaFwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIkRlY2FmLVRTOiBCcmV3ZWQgZm9yIGNhbG0gY29kZS5cIixcbiAgICBUYWdzOiBcIkNvZmZlZS10aGVtZWQsIEJyYW5kaW5nXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiU21vb3RoIGFzIHlvdXIgbW9ybmluZyBEZWNhZi5cIixcbiAgICBUYWdzOiBcIkNvZmZlZS10aGVtZWQsIENoaWxsXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiQWxsIHRoZSBraWNrLCBub25lIG9mIHRoZSBjcmFzaC5cIixcbiAgICBUYWdzOiBcIkNvZmZlZS10aGVtZWQsIEVuZXJnZXRpY1wiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIlNpcCBiYWNrIGFuZCBzaGlwIGZhc3Rlci5cIixcbiAgICBUYWdzOiBcIkNvZmZlZS10aGVtZWQsIEZ1blwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIktlZXAgY2FsbSBhbmQgY29kZSBEZWNhZi5cIixcbiAgICBUYWdzOiBcIkNvZmZlZS10aGVtZWQsIFBsYXlmdWxcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJDb2RlIHdpdGhvdXQgdGhlIGNhZmZlaW5lIHNoYWtlcy5cIixcbiAgICBUYWdzOiBcIkNvZmZlZS10aGVtZWQsIEh1bW9yb3VzXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiWW91ciBmdWxsc3RhY2ssIGRlY2FmZmVpbmF0ZWQuXCIsXG4gICAgVGFnczogXCJDb2ZmZWUtdGhlbWVkLCBUZWNobmljYWxcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJEZWNhZi1UUzogV2hlcmUgc21hcnQgY29udHJhY3RzIG1lZXQgc21hcnQgaW50ZXJmYWNlcy5cIixcbiAgICBUYWdzOiBcIkJsb2NrY2hhaW4sIFNtYXJ0IENvbnRyYWN0cywgVGVjaFwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIlNoaXAgZEFwcHMgd2l0aG91dCB0aGUgc3RyZXNzLlwiLFxuICAgIFRhZ3M6IFwiQmxvY2tjaGFpbiwgQ2hlZXJmdWwsIERldmVsb3BlclwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIk5vIENSVUQsIG5vIHByb2JsZW0gXFx1MjAxNCBEZWNhZiB5b3VyIGRhdGEuXCIsXG4gICAgVGFnczogXCJEYXRhLCBOby1DUlVELCBDaGlsbFwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIkZyb20gRElEIHRvIFVJLCB3aXRob3V0IGJyZWFraW5nIGEgc3dlYXQuXCIsXG4gICAgVGFnczogXCJESUQsIFNTSSwgVUksIENhbG1cIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJEZWNhZi1UUzogWW91ciBmcm9udGVuZCBhbHJlYWR5IHVuZGVyc3RhbmRzIHlvdXIgc21hcnQgY29udHJhY3QuXCIsXG4gICAgVGFnczogXCJTbWFydCBDb250cmFjdHMsIERYLCBNYWdpY1wiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIlNlbGYtc292ZXJlaWduIGJ5IGRlc2lnbi4gUHJvZHVjdGl2ZSBieSBkZWZhdWx0LlwiLFxuICAgIFRhZ3M6IFwiU1NJLCBEZXZlbG9wZXIsIENhbG1cIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJCdWlsZCBvbmNlLiBEZXBsb3kgZXZlcnl3aGVyZS4gRGVjZW50cmFsaXplZCBhbmQgZGVsaWdodGZ1bC5cIixcbiAgICBUYWdzOiBcIkJsb2NrY2hhaW4sIE11bHRpLXBsYXRmb3JtLCBIYXBweVwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIkRhdGEgdGhhdCBkZWZpbmVzIGl0cyBvd24gZGVzdGlueS5cIixcbiAgICBUYWdzOiBcIlNTSSwgRGF0YS1kcml2ZW4sIEVtcG93ZXJtZW50XCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiR29vZGJ5ZSBDUlVELCBoZWxsbyBpbnRlbnQtYmFzZWQgaW50ZXJmYWNlcy5cIixcbiAgICBUYWdzOiBcIk5vLUNSVUQsIFVJLCBUZWNobmljYWxcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJUaGUgc21vb3RoZXN0IHBhdGggZnJvbSBESUQgdG8gZG9uZS5cIixcbiAgICBUYWdzOiBcIkRJRCwgV29ya2Zsb3csIENoaWxsXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiQmVjYXVzZSB5b3VyIGRBcHAgZGVzZXJ2ZXMgbW9yZSB0aGFuIGJvaWxlcnBsYXRlLlwiLFxuICAgIFRhZ3M6IFwiQmxvY2tjaGFpbiwgRGV2WCwgRWZmaWNpZW5jeVwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIk93biB5b3VyIGRhdGEuIE93biB5b3VyIGZsb3cuXCIsXG4gICAgVGFnczogXCJTU0ksIENvbnRyb2wsIE93bmVyc2hpcFwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIldyaXRlIGxvZ2ljIGxpa2UgaXQgYmVsb25ncyB3aXRoIHRoZSBkYXRhIFxcdTIwMTQgYmVjYXVzZSBpdCBkb2VzLlwiLFxuICAgIFRhZ3M6IFwiRGF0YSBMb2dpYywgRGV2ZWxvcGVyLCBTbWFydFwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIkZyb20gc21hcnQgY29udHJhY3RzIHRvIHNtYXJ0ZXIgZnJvbnRlbmRzLlwiLFxuICAgIFRhZ3M6IFwiU21hcnQgQ29udHJhY3RzLCBVSSwgRFhcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJObyBjYWZmZWluZS4gTm8gQ1JVRC4gSnVzdCB0aGUgZnV0dXJlLlwiLFxuICAgIFRhZ3M6IFwiTm8tQ1JVRCwgQ29mZmVlLXRoZW1lZCwgRnV0dXJpc3RpY1wiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIlRoZSBmdXR1cmUgb2Ygd2ViMyBVWCBpcyBEZWNhZi5cIixcbiAgICBUYWdzOiBcIkJsb2NrY2hhaW4sIFVYLCBWaXNpb25cIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJDb2RlIHdpdGggY29uZmlkZW5jZS4gR292ZXJuIHdpdGggY2xhcml0eS5cIixcbiAgICBUYWdzOiBcIkJsb2NrY2hhaW4sIEdvdmVybmFuY2UsIENhbG1cIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJJbnRlcmZhY2VzIHRoYXQgb2JleSB0aGUgZGF0YSwgbm90IHRoZSBvdGhlciB3YXkgYXJvdW5kLlwiLFxuICAgIFRhZ3M6IFwiVUksIERhdGEgTG9naWMsIFNlbGYtYXdhcmVcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJCcmV3IGJ1c2luZXNzIGxvZ2ljIHJpZ2h0IGludG8geW91ciBieXRlcy5cIixcbiAgICBUYWdzOiBcIkRhdGEgTG9naWMsIENvZmZlZS10aGVtZWQsIEZ1blwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIkRJRHMgZG9uZSBkaWZmZXJlbnRseSBcXHUyMDE0IGFuZCBkZWxpZ2h0ZnVsbHkuXCIsXG4gICAgVGFnczogXCJESUQsIFNlbGYtU292ZXJlaWduLCBQbGF5ZnVsXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiRGVjYWYtVFMtVFM6IFdoZXJlIGJsb2NrY2hhaW4gY29udHJhY3RzIG1lZXQgc21hcnQgaW50ZXJmYWNlcy5cIixcbiAgICBUYWdzOiBcIkJsb2NrY2hhaW4sIFNtYXJ0IENvbnRyYWN0cywgVGVjaFwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIlNoaXAgZEFwcHMgd2l0aG91dCB0aGUgc3RyZXNzLlwiLFxuICAgIFRhZ3M6IFwiQmxvY2tjaGFpbiwgQ2hlZXJmdWwsIERldmVsb3BlclwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIk5vIGJvaWxlcnBsYXRlLCBubyBwcm9ibGVtIFxcdTIwMTQgRGVjYWYtVFMgeW91ciBkYXRhLlwiLFxuICAgIFRhZ3M6IFwiRGF0YSwgTm8tQ1JVRCwgQ2hpbGxcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJGcm9tIERJRCB0byBVSSwgd2l0aG91dCBicmVha2luZyBhIHN3ZWF0LlwiLFxuICAgIFRhZ3M6IFwiRElELCBTU0ksIFVJLCBDYWxtXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46XG4gICAgICBcIkRlY2FmLVRTLVRTOiBZb3VyIGZyb250ZW5kIGFscmVhZHkgdW5kZXJzdGFuZHMgeW91ciBibG9ja2NoYWluIGNvbnRyYWN0LlwiLFxuICAgIFRhZ3M6IFwiU21hcnQgQ29udHJhY3RzLCBEWCwgTWFnaWNcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJTZWxmLXNvdmVyZWlnbiBieSBkZXNpZ24uIFByb2R1Y3RpdmUgYnkgZGVmYXVsdC5cIixcbiAgICBUYWdzOiBcIlNTSSwgRGV2ZWxvcGVyLCBDYWxtXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiQnVpbGQgb25jZS4gRGVwbG95IGV2ZXJ5d2hlcmUuIERlY2VudHJhbGl6ZWQgYW5kIGRlbGlnaHRmdWwuXCIsXG4gICAgVGFnczogXCJCbG9ja2NoYWluLCBNdWx0aS1wbGF0Zm9ybSwgSGFwcHlcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJEYXRhIHRoYXQgZGVmaW5lcyBpdHMgb3duIGRlc3RpbnkuXCIsXG4gICAgVGFnczogXCJTU0ksIERhdGEtZHJpdmVuLCBFbXBvd2VybWVudFwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIkdvb2RieWUgYm9pbGVycGxhdGUsIGhlbGxvIGludGVudC1iYXNlZCBpbnRlcmZhY2VzLlwiLFxuICAgIFRhZ3M6IFwiTm8tQ1JVRCwgVUksIFRlY2huaWNhbFwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIlRoZSBzbW9vdGhlc3QgcGF0aCBmcm9tIERJRCB0byBkb25lLlwiLFxuICAgIFRhZ3M6IFwiRElELCBXb3JrZmxvdywgQ2hpbGxcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJCZWNhdXNlIHlvdXIgZEFwcCBkZXNlcnZlcyBtb3JlIHRoYW4gYm9pbGVycGxhdGUuXCIsXG4gICAgVGFnczogXCJCbG9ja2NoYWluLCBEZXZYLCBFZmZpY2llbmN5XCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiT3duIHlvdXIgZGF0YS4gT3duIHlvdXIgZmxvdy5cIixcbiAgICBUYWdzOiBcIlNTSSwgQ29udHJvbCwgT3duZXJzaGlwXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiV3JpdGUgbG9naWMgbGlrZSBpdCBiZWxvbmdzIHdpdGggdGhlIGRhdGEgXFx1MjAxNCBiZWNhdXNlIGl0IGRvZXMuXCIsXG4gICAgVGFnczogXCJEYXRhIExvZ2ljLCBEZXZlbG9wZXIsIFNtYXJ0XCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiRnJvbSBibG9ja2NoYWluIGNvbnRyYWN0cyB0byBzbWFydGVyIGZyb250ZW5kcy5cIixcbiAgICBUYWdzOiBcIlNtYXJ0IENvbnRyYWN0cywgVUksIERYXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiTm8gY2FmZmVpbmUuIE5vIGJvaWxlcnBsYXRlLiBKdXN0IHRoZSBmdXR1cmUuXCIsXG4gICAgVGFnczogXCJOby1DUlVELCBDb2ZmZWUtdGhlbWVkLCBGdXR1cmlzdGljXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiVGhlIGZ1dHVyZSBvZiB3ZWIzIFVYIGlzIERlY2FmLVRTLlwiLFxuICAgIFRhZ3M6IFwiQmxvY2tjaGFpbiwgVVgsIFZpc2lvblwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIkNvZGUgd2l0aCBjb25maWRlbmNlLiBHb3Zlcm4gd2l0aCBjbGFyaXR5LlwiLFxuICAgIFRhZ3M6IFwiQmxvY2tjaGFpbiwgR292ZXJuYW5jZSwgQ2FsbVwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIkludGVyZmFjZXMgdGhhdCBvYmV5IHRoZSBkYXRhLCBub3QgdGhlIG90aGVyIHdheSBhcm91bmQuXCIsXG4gICAgVGFnczogXCJVSSwgRGF0YSBMb2dpYywgU2VsZi1hd2FyZVwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIkJyZXcgYnVzaW5lc3MgbG9naWMgcmlnaHQgaW50byB5b3VyIGJ5dGVzLlwiLFxuICAgIFRhZ3M6IFwiRGF0YSBMb2dpYywgQ29mZmVlLXRoZW1lZCwgRnVuXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiRElEcyBkb25lIGRpZmZlcmVudGx5IFxcdTIwMTQgYW5kIGRlbGlnaHRmdWxseS5cIixcbiAgICBUYWdzOiBcIkRJRCwgU2VsZi1Tb3ZlcmVpZ24sIFBsYXlmdWxcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJEZWNhZi1UUy1UUzogV2hlcmUgYmxvY2tjaGFpbiBjb250cmFjdHMgbWVldCBzbWFydCBpbnRlcmZhY2VzLlwiLFxuICAgIFRhZ3M6IFwiQmxvY2tjaGFpbiwgU21hcnQgQ29udHJhY3RzLCBUZWNoXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiU2hpcCBkQXBwcyB3aXRob3V0IHRoZSBzdHJlc3MuXCIsXG4gICAgVGFnczogXCJCbG9ja2NoYWluLCBDaGVlcmZ1bCwgRGV2ZWxvcGVyXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiTm8gYm9pbGVycGxhdGUsIG5vIHByb2JsZW0gXFx1MjAxNCBEZWNhZi1UUyB5b3VyIGRhdGEuXCIsXG4gICAgVGFnczogXCJEYXRhLCBOby1DUlVELCBDaGlsbFwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIkZyb20gRElEIHRvIFVJLCB3aXRob3V0IGJyZWFraW5nIGEgc3dlYXQuXCIsXG4gICAgVGFnczogXCJESUQsIFNTSSwgVUksIENhbG1cIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjpcbiAgICAgIFwiRGVjYWYtVFMtVFM6IFlvdXIgZnJvbnRlbmQgYWxyZWFkeSB1bmRlcnN0YW5kcyB5b3VyIGJsb2NrY2hhaW4gY29udHJhY3QuXCIsXG4gICAgVGFnczogXCJTbWFydCBDb250cmFjdHMsIERYLCBNYWdpY1wiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIlNlbGYtc292ZXJlaWduIGJ5IGRlc2lnbi4gUHJvZHVjdGl2ZSBieSBkZWZhdWx0LlwiLFxuICAgIFRhZ3M6IFwiU1NJLCBEZXZlbG9wZXIsIENhbG1cIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJCdWlsZCBvbmNlLiBEZXBsb3kgZXZlcnl3aGVyZS4gRGVjZW50cmFsaXplZCBhbmQgZGVsaWdodGZ1bC5cIixcbiAgICBUYWdzOiBcIkJsb2NrY2hhaW4sIE11bHRpLXBsYXRmb3JtLCBIYXBweVwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIkRhdGEgdGhhdCBkZWZpbmVzIGl0cyBvd24gZGVzdGlueS5cIixcbiAgICBUYWdzOiBcIlNTSSwgRGF0YS1kcml2ZW4sIEVtcG93ZXJtZW50XCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiR29vZGJ5ZSBib2lsZXJwbGF0ZSwgaGVsbG8gaW50ZW50LWJhc2VkIGludGVyZmFjZXMuXCIsXG4gICAgVGFnczogXCJOby1DUlVELCBVSSwgVGVjaG5pY2FsXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiVGhlIHNtb290aGVzdCBwYXRoIGZyb20gRElEIHRvIGRvbmUuXCIsXG4gICAgVGFnczogXCJESUQsIFdvcmtmbG93LCBDaGlsbFwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIkJlY2F1c2UgeW91ciBkQXBwIGRlc2VydmVzIG1vcmUgdGhhbiBib2lsZXJwbGF0ZS5cIixcbiAgICBUYWdzOiBcIkJsb2NrY2hhaW4sIERldlgsIEVmZmljaWVuY3lcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJPd24geW91ciBkYXRhLiBPd24geW91ciBmbG93LlwiLFxuICAgIFRhZ3M6IFwiU1NJLCBDb250cm9sLCBPd25lcnNoaXBcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJXcml0ZSBsb2dpYyBsaWtlIGl0IGJlbG9uZ3Mgd2l0aCB0aGUgZGF0YSBcXHUyMDE0IGJlY2F1c2UgaXQgZG9lcy5cIixcbiAgICBUYWdzOiBcIkRhdGEgTG9naWMsIERldmVsb3BlciwgU21hcnRcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJGcm9tIGJsb2NrY2hhaW4gY29udHJhY3RzIHRvIHNtYXJ0ZXIgZnJvbnRlbmRzLlwiLFxuICAgIFRhZ3M6IFwiU21hcnQgQ29udHJhY3RzLCBVSSwgRFhcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJObyBjYWZmZWluZS4gTm8gYm9pbGVycGxhdGUuIEp1c3QgdGhlIGZ1dHVyZS5cIixcbiAgICBUYWdzOiBcIk5vLUNSVUQsIENvZmZlZS10aGVtZWQsIEZ1dHVyaXN0aWNcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJUaGUgZnV0dXJlIG9mIHdlYjMgVVggaXMgRGVjYWYtVFMuXCIsXG4gICAgVGFnczogXCJCbG9ja2NoYWluLCBVWCwgVmlzaW9uXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiQ29kZSB3aXRoIGNvbmZpZGVuY2UuIEdvdmVybiB3aXRoIGNsYXJpdHkuXCIsXG4gICAgVGFnczogXCJCbG9ja2NoYWluLCBHb3Zlcm5hbmNlLCBDYWxtXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiSW50ZXJmYWNlcyB0aGF0IG9iZXkgdGhlIGRhdGEsIG5vdCB0aGUgb3RoZXIgd2F5IGFyb3VuZC5cIixcbiAgICBUYWdzOiBcIlVJLCBEYXRhIExvZ2ljLCBTZWxmLWF3YXJlXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiQnJldyBidXNpbmVzcyBsb2dpYyByaWdodCBpbnRvIHlvdXIgYnl0ZXMuXCIsXG4gICAgVGFnczogXCJEYXRhIExvZ2ljLCBDb2ZmZWUtdGhlbWVkLCBGdW5cIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJESURzIGRvbmUgZGlmZmVyZW50bHkgXFx1MjAxNCBhbmQgZGVsaWdodGZ1bGx5LlwiLFxuICAgIFRhZ3M6IFwiRElELCBTZWxmLVNvdmVyZWlnbiwgUGxheWZ1bFwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIkRlY2FmLVRTLVRTOiBXaGVyZSBibG9ja2NoYWluIGNvbnRyYWN0cyBtZWV0IHNtYXJ0IGludGVyZmFjZXMuXCIsXG4gICAgVGFnczogXCJCbG9ja2NoYWluLCBTbWFydCBDb250cmFjdHMsIFRlY2hcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJTaGlwIGRBcHBzIHdpdGhvdXQgdGhlIHN0cmVzcy5cIixcbiAgICBUYWdzOiBcIkJsb2NrY2hhaW4sIENoZWVyZnVsLCBEZXZlbG9wZXJcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJObyBib2lsZXJwbGF0ZSwgbm8gcHJvYmxlbSBcXHUyMDE0IERlY2FmLVRTIHlvdXIgZGF0YS5cIixcbiAgICBUYWdzOiBcIkRhdGEsIE5vLUNSVUQsIENoaWxsXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiRnJvbSBESUQgdG8gVUksIHdpdGhvdXQgYnJlYWtpbmcgYSBzd2VhdC5cIixcbiAgICBUYWdzOiBcIkRJRCwgU1NJLCBVSSwgQ2FsbVwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOlxuICAgICAgXCJEZWNhZi1UUy1UUzogWW91ciBmcm9udGVuZCBhbHJlYWR5IHVuZGVyc3RhbmRzIHlvdXIgYmxvY2tjaGFpbiBjb250cmFjdC5cIixcbiAgICBUYWdzOiBcIlNtYXJ0IENvbnRyYWN0cywgRFgsIE1hZ2ljXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiU2VsZi1zb3ZlcmVpZ24gYnkgZGVzaWduLiBQcm9kdWN0aXZlIGJ5IGRlZmF1bHQuXCIsXG4gICAgVGFnczogXCJTU0ksIERldmVsb3BlciwgQ2FsbVwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIkJ1aWxkIG9uY2UuIERlcGxveSBldmVyeXdoZXJlLiBEZWNlbnRyYWxpemVkIGFuZCBkZWxpZ2h0ZnVsLlwiLFxuICAgIFRhZ3M6IFwiQmxvY2tjaGFpbiwgTXVsdGktcGxhdGZvcm0sIEhhcHB5XCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiRGF0YSB0aGF0IGRlZmluZXMgaXRzIG93biBkZXN0aW55LlwiLFxuICAgIFRhZ3M6IFwiU1NJLCBEYXRhLWRyaXZlbiwgRW1wb3dlcm1lbnRcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJHb29kYnllIGJvaWxlcnBsYXRlLCBoZWxsbyBpbnRlbnQtYmFzZWQgaW50ZXJmYWNlcy5cIixcbiAgICBUYWdzOiBcIk5vLUNSVUQsIFVJLCBUZWNobmljYWxcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJUaGUgc21vb3RoZXN0IHBhdGggZnJvbSBESUQgdG8gZG9uZS5cIixcbiAgICBUYWdzOiBcIkRJRCwgV29ya2Zsb3csIENoaWxsXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiQmVjYXVzZSB5b3VyIGRBcHAgZGVzZXJ2ZXMgbW9yZSB0aGFuIGJvaWxlcnBsYXRlLlwiLFxuICAgIFRhZ3M6IFwiQmxvY2tjaGFpbiwgRGV2WCwgRWZmaWNpZW5jeVwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIk93biB5b3VyIGRhdGEuIE93biB5b3VyIGZsb3cuXCIsXG4gICAgVGFnczogXCJTU0ksIENvbnRyb2wsIE93bmVyc2hpcFwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIldyaXRlIGxvZ2ljIGxpa2UgaXQgYmVsb25ncyB3aXRoIHRoZSBkYXRhIFxcdTIwMTQgYmVjYXVzZSBpdCBkb2VzLlwiLFxuICAgIFRhZ3M6IFwiRGF0YSBMb2dpYywgRGV2ZWxvcGVyLCBTbWFydFwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIkZyb20gYmxvY2tjaGFpbiBjb250cmFjdHMgdG8gc21hcnRlciBmcm9udGVuZHMuXCIsXG4gICAgVGFnczogXCJTbWFydCBDb250cmFjdHMsIFVJLCBEWFwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIk5vIGNhZmZlaW5lLiBObyBib2lsZXJwbGF0ZS4gSnVzdCB0aGUgZnV0dXJlLlwiLFxuICAgIFRhZ3M6IFwiTm8tQ1JVRCwgQ29mZmVlLXRoZW1lZCwgRnV0dXJpc3RpY1wiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIlRoZSBmdXR1cmUgb2Ygd2ViMyBVWCBpcyBEZWNhZi1UUy5cIixcbiAgICBUYWdzOiBcIkJsb2NrY2hhaW4sIFVYLCBWaXNpb25cIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJDb2RlIHdpdGggY29uZmlkZW5jZS4gR292ZXJuIHdpdGggY2xhcml0eS5cIixcbiAgICBUYWdzOiBcIkJsb2NrY2hhaW4sIEdvdmVybmFuY2UsIENhbG1cIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJJbnRlcmZhY2VzIHRoYXQgb2JleSB0aGUgZGF0YSwgbm90IHRoZSBvdGhlciB3YXkgYXJvdW5kLlwiLFxuICAgIFRhZ3M6IFwiVUksIERhdGEgTG9naWMsIFNlbGYtYXdhcmVcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJCcmV3IGJ1c2luZXNzIGxvZ2ljIHJpZ2h0IGludG8geW91ciBieXRlcy5cIixcbiAgICBUYWdzOiBcIkRhdGEgTG9naWMsIENvZmZlZS10aGVtZWQsIEZ1blwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIkRJRHMgZG9uZSBkaWZmZXJlbnRseSBcXHUyMDE0IGFuZCBkZWxpZ2h0ZnVsbHkuXCIsXG4gICAgVGFnczogXCJESUQsIFNlbGYtU292ZXJlaWduLCBQbGF5ZnVsXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiRGVjYWYtVFMtVFM6IFdoZXJlIGJsb2NrY2hhaW4gY29udHJhY3RzIG1lZXQgc21hcnQgaW50ZXJmYWNlcy5cIixcbiAgICBUYWdzOiBcIkJsb2NrY2hhaW4sIFNtYXJ0IENvbnRyYWN0cywgVGVjaFwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIlNoaXAgZEFwcHMgd2l0aG91dCB0aGUgc3RyZXNzLlwiLFxuICAgIFRhZ3M6IFwiQmxvY2tjaGFpbiwgQ2hlZXJmdWwsIERldmVsb3BlclwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIk5vIGJvaWxlcnBsYXRlLCBubyBwcm9ibGVtIFxcdTIwMTQgRGVjYWYtVFMgeW91ciBkYXRhLlwiLFxuICAgIFRhZ3M6IFwiRGF0YSwgTm8tQ1JVRCwgQ2hpbGxcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJGcm9tIERJRCB0byBVSSwgd2l0aG91dCBicmVha2luZyBhIHN3ZWF0LlwiLFxuICAgIFRhZ3M6IFwiRElELCBTU0ksIFVJLCBDYWxtXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46XG4gICAgICBcIkRlY2FmLVRTLVRTOiBZb3VyIGZyb250ZW5kIGFscmVhZHkgdW5kZXJzdGFuZHMgeW91ciBibG9ja2NoYWluIGNvbnRyYWN0LlwiLFxuICAgIFRhZ3M6IFwiU21hcnQgQ29udHJhY3RzLCBEWCwgTWFnaWNcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJTZWxmLXNvdmVyZWlnbiBieSBkZXNpZ24uIFByb2R1Y3RpdmUgYnkgZGVmYXVsdC5cIixcbiAgICBUYWdzOiBcIlNTSSwgRGV2ZWxvcGVyLCBDYWxtXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiQnVpbGQgb25jZS4gRGVwbG95IGV2ZXJ5d2hlcmUuIERlY2VudHJhbGl6ZWQgYW5kIGRlbGlnaHRmdWwuXCIsXG4gICAgVGFnczogXCJCbG9ja2NoYWluLCBNdWx0aS1wbGF0Zm9ybSwgSGFwcHlcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJEYXRhIHRoYXQgZGVmaW5lcyBpdHMgb3duIGRlc3RpbnkuXCIsXG4gICAgVGFnczogXCJTU0ksIERhdGEtZHJpdmVuLCBFbXBvd2VybWVudFwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIkdvb2RieWUgYm9pbGVycGxhdGUsIGhlbGxvIGludGVudC1iYXNlZCBpbnRlcmZhY2VzLlwiLFxuICAgIFRhZ3M6IFwiTm8tQ1JVRCwgVUksIFRlY2huaWNhbFwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIlRoZSBzbW9vdGhlc3QgcGF0aCBmcm9tIERJRCB0byBkb25lLlwiLFxuICAgIFRhZ3M6IFwiRElELCBXb3JrZmxvdywgQ2hpbGxcIixcbiAgfSxcbiAge1xuICAgIFNsb2dhbjogXCJCZWNhdXNlIHlvdXIgZEFwcCBkZXNlcnZlcyBtb3JlIHRoYW4gYm9pbGVycGxhdGUuXCIsXG4gICAgVGFnczogXCJCbG9ja2NoYWluLCBEZXZYLCBFZmZpY2llbmN5XCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiT3duIHlvdXIgZGF0YS4gT3duIHlvdXIgZmxvdy5cIixcbiAgICBUYWdzOiBcIlNTSSwgQ29udHJvbCwgT3duZXJzaGlwXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiV3JpdGUgbG9naWMgbGlrZSBpdCBiZWxvbmdzIHdpdGggdGhlIGRhdGEgXFx1MjAxNCBiZWNhdXNlIGl0IGRvZXMuXCIsXG4gICAgVGFnczogXCJEYXRhIExvZ2ljLCBEZXZlbG9wZXIsIFNtYXJ0XCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiRnJvbSBibG9ja2NoYWluIGNvbnRyYWN0cyB0byBzbWFydGVyIGZyb250ZW5kcy5cIixcbiAgICBUYWdzOiBcIlNtYXJ0IENvbnRyYWN0cywgVUksIERYXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiTm8gY2FmZmVpbmUuIE5vIGJvaWxlcnBsYXRlLiBKdXN0IHRoZSBmdXR1cmUuXCIsXG4gICAgVGFnczogXCJOby1DUlVELCBDb2ZmZWUtdGhlbWVkLCBGdXR1cmlzdGljXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiVGhlIGZ1dHVyZSBvZiB3ZWIzIFVYIGlzIERlY2FmLVRTLlwiLFxuICAgIFRhZ3M6IFwiQmxvY2tjaGFpbiwgVVgsIFZpc2lvblwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIkNvZGUgd2l0aCBjb25maWRlbmNlLiBHb3Zlcm4gd2l0aCBjbGFyaXR5LlwiLFxuICAgIFRhZ3M6IFwiQmxvY2tjaGFpbiwgR292ZXJuYW5jZSwgQ2FsbVwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIkludGVyZmFjZXMgdGhhdCBvYmV5IHRoZSBkYXRhLCBub3QgdGhlIG90aGVyIHdheSBhcm91bmQuXCIsXG4gICAgVGFnczogXCJVSSwgRGF0YSBMb2dpYywgU2VsZi1hd2FyZVwiLFxuICB9LFxuICB7XG4gICAgU2xvZ2FuOiBcIkJyZXcgYnVzaW5lc3MgbG9naWMgcmlnaHQgaW50byB5b3VyIGJ5dGVzLlwiLFxuICAgIFRhZ3M6IFwiRGF0YSBMb2dpYywgQ29mZmVlLXRoZW1lZCwgRnVuXCIsXG4gIH0sXG4gIHtcbiAgICBTbG9nYW46IFwiRElEcyBkb25lIGRpZmZlcmVudGx5IFxcdTIwMTQgYW5kIGRlbGlnaHRmdWxseS5cIixcbiAgICBUYWdzOiBcIkRJRCwgU2VsZi1Tb3ZlcmVpZ24sIFBsYXlmdWxcIixcbiAgfSxcbl07XG4iLCJpbXBvcnQgeyBzbG9nYW5zIH0gZnJvbSBcIi4uL2Fzc2V0cy9zbG9nYW5zXCI7XG5pbXBvcnQgeyBzdHlsZSB9IGZyb20gXCJzdHlsZWQtc3RyaW5nLWJ1aWxkZXJcIjtcbmltcG9ydCB7IExvZ2dlciB9IGZyb20gXCJAZGVjYWYtdHMvbG9nZ2luZ1wiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBBcnJheSBvZiBBTlNJIGNvbG9yIGNvZGVzIGZvciBiYW5uZXIgc3R5bGluZy5cbiAqIEBzdW1tYXJ5IERlZmluZXMgYSBzZXQgb2YgQU5TSSBjb2xvciBjb2RlcyB1c2VkIHRvIHN0eWxlIHRoZSBiYW5uZXIgdGV4dC5cbiAqIEBtZW1iZXJPZiBtb2R1bGU6dXRpbHNcbiAqL1xuY29uc3QgY29sb3JzID0gW1xuICBcIlxceDFiWzM4OzU7MjE1bVwiLCAvLyBzb2Z0IG9yYW5nZVxuICBcIlxceDFiWzM4OzU7MjA5bVwiLCAvLyBjb3JhbFxuICBcIlxceDFiWzM4OzU7MjA1bVwiLCAvLyBwaW5rXG4gIFwiXFx4MWJbMzg7NTsyMTBtXCIsIC8vIHBlYWNoeVxuICBcIlxceDFiWzM4OzU7MjE3bVwiLCAvLyBzYWxtb25cbiAgXCJcXHgxYlszODs1OzIxNm1cIiwgLy8gbGlnaHQgY29yYWxcbiAgXCJcXHgxYlszODs1OzIyNG1cIiwgLy8gbGlnaHQgcGVhY2hcbiAgXCJcXHgxYlszODs1OzIzMG1cIiwgLy8gc29mdCBjcmVhbVxuICBcIlxceDFiWzM4OzU7MjMwbVwiLCAvLyBzb2Z0IGNyZWFtXG5dO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBQcmludHMgYSBzdHlsZWQgYmFubmVyIHRvIHRoZSBjb25zb2xlLlxuICogQHN1bW1hcnkgR2VuZXJhdGVzIGFuZCBwcmludHMgYSBjb2xvcmZ1bCBBU0NJSSBhcnQgYmFubmVyIHdpdGggYSByYW5kb20gc2xvZ2FuLlxuICogQHBhcmFtIHtMb2dnZXJ9IFtsb2dnZXJdIC0gT3B0aW9uYWwgbG9nZ2VyIGZvciB2ZXJib3NlIG91dHB1dC5cbiAqIEBtZW1iZXJPZiBtb2R1bGU6dXRpbHNcbiAqIEBmdW5jdGlvbiBwcmludEJhbm5lclxuICogQG1lcm1haWRcbiAqIHNlcXVlbmNlRGlhZ3JhbVxuICogICBwYXJ0aWNpcGFudCBwcmludEJhbm5lclxuICogICBwYXJ0aWNpcGFudCBnZXRTbG9nYW5cbiAqICAgcGFydGljaXBhbnQgcGFkRW5kXG4gKiAgIHBhcnRpY2lwYW50IGNvbnNvbGVcbiAqICAgcHJpbnRCYW5uZXItPj5nZXRTbG9nYW46IENhbGwgZ2V0U2xvZ2FuKClcbiAqICAgZ2V0U2xvZ2FuLS0+PnByaW50QmFubmVyOiBSZXR1cm4gcmFuZG9tIHNsb2dhblxuICogICBwcmludEJhbm5lci0+PnByaW50QmFubmVyOiBDcmVhdGUgYmFubmVyIEFTQ0lJIGFydFxuICogICBwcmludEJhbm5lci0+PnByaW50QmFubmVyOiBTcGxpdCBiYW5uZXIgaW50byBsaW5lc1xuICogICBwcmludEJhbm5lci0+PnByaW50QmFubmVyOiBDYWxjdWxhdGUgbWF4IGxpbmUgbGVuZ3RoXG4gKiAgIHByaW50QmFubmVyLT4+cGFkRW5kOiBDYWxsIHBhZEVuZCB3aXRoIHNsb2dhblxuICogICBwYWRFbmQtLT4+cHJpbnRCYW5uZXI6IFJldHVybiBwYWRkZWQgc2xvZ2FuIGxpbmVcbiAqICAgbG9vcCBGb3IgZWFjaCBiYW5uZXIgbGluZVxuICogICAgIHByaW50QmFubmVyLT4+c3R5bGU6IENhbGwgc3R5bGUobGluZSlcbiAqICAgICBzdHlsZS0tPj5wcmludEJhbm5lcjogUmV0dXJuIHN0eWxlZCBsaW5lXG4gKiAgICAgcHJpbnRCYW5uZXItPj5jb25zb2xlOiBMb2cgc3R5bGVkIGxpbmVcbiAqICAgZW5kXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwcmludEJhbm5lcihsb2dnZXI/OiBMb2dnZXIpIHtcbiAgY29uc3QgbWVzc2FnZSA9IGdldFNsb2dhbigpO1xuICBjb25zdCBiYW5uZXI6IHN0cmluZyB8IHN0cmluZ1tdID1cbiAgICBgIyAgICAgICAgICAgICAgICAg4paR4paS4paT4paI4paI4paI4paI4paI4paI4paI4paT4paS4paRICDilpHilpLilpPilojilojilojilojilojilojilojilojilpPilpLilpEgIOKWkeKWkuKWk+KWiOKWiOKWiOKWiOKWiOKWiOKWk+KWkuKWkSAgIOKWkeKWkuKWk+KWiOKWiOKWiOKWiOKWiOKWiOKWk+KWkuKWkSAg4paR4paS4paT4paI4paI4paI4paI4paI4paI4paI4paI4paT4paS4paRICAgICAgIOKWkeKWkuKWk+KWiOKWiOKWiOKWiOKWiOKWiOKWiOKWiOKWk+KWkuKWkSAg4paR4paS4paT4paI4paI4paI4paI4paI4paI4paI4paT4paS4paRIFxuIyAgICAgICggKCAgICAgICAg4paR4paS4paT4paI4paT4paS4paR4paR4paS4paT4paI4paT4paS4paRIOKWkeKWkuKWk+KWiOKWk+KWkuKWkSAgICAgICAg4paR4paS4paT4paI4paT4paS4paR4paR4paS4paT4paI4paT4paS4paRIOKWkeKWkuKWk+KWiOKWk+KWkuKWkeKWkeKWkuKWk+KWiOKWk+KWkuKWkSDilpHilpLilpPilojilpPilpLilpEgICAgICAgICAgICAgICAgIOKWkeKWkuKWk+KWiOKWk+KWkuKWkSAgICAg4paR4paS4paT4paI4paT4paS4paRICAgICAgICBcbiMgICAgICAgKSApICAgICAgIOKWkeKWkuKWk+KWiOKWk+KWkuKWkeKWkeKWkuKWk+KWiOKWk+KWkuKWkSDilpHilpLilpPilojilpPilpLilpEgICAgICAgIOKWkeKWkuKWk+KWiOKWk+KWkuKWkSAgICAgICAg4paR4paS4paT4paI4paT4paS4paR4paR4paS4paT4paI4paT4paS4paRIOKWkeKWkuKWk+KWiOKWk+KWkuKWkSAgICAgICAgICAgICAgICAg4paR4paS4paT4paI4paT4paS4paRICAgICDilpHilpLilpPilojilpPilpLilpEgICAgICAgIFxuIyAgICBbPT09PT09PV0gICAg4paR4paS4paT4paI4paT4paS4paR4paR4paS4paT4paI4paT4paS4paRIOKWkeKWkuKWk+KWiOKWiOKWiOKWiOKWiOKWiOKWk+KWkuKWkSAgIOKWkeKWkuKWk+KWiOKWk+KWkuKWkSAgICAgICAg4paR4paS4paT4paI4paI4paI4paI4paI4paI4paI4paI4paT4paS4paRIOKWkeKWkuKWk+KWiOKWiOKWiOKWiOKWiOKWiOKWk+KWkuKWkSAgICAgICAgICAgIOKWkeKWkuKWk+KWiOKWk+KWkuKWkSAgICAgIOKWkeKWkuKWk+KWiOKWiOKWiOKWiOKWiOKWiOKWk+KWkuKWkSAgXG4jICAgICBcXGAtLS0tLcK0ICAgICDilpHilpLilpPilojilpPilpLilpHilpHilpLilpPilojilpPilpLilpEg4paR4paS4paT4paI4paT4paS4paRICAgICAgICDilpHilpLilpPilojilpPilpLilpEgICAgICAgIOKWkeKWkuKWk+KWiOKWk+KWkuKWkeKWkeKWkuKWk+KWiOKWk+KWkuKWkSDilpHilpLilpPilojilpPilpLilpEgICAgICAgICAgICAgICAgIOKWkeKWkuKWk+KWiOKWk+KWkuKWkSAgICAgICAgICAgIOKWkeKWkuKWk+KWiOKWk+KWkuKWkSBcbiMgICAgICAgICAgICAgICAgIOKWkeKWkuKWk+KWiOKWk+KWkuKWkeKWkeKWkuKWk+KWiOKWk+KWkuKWkSDilpHilpLilpPilojilpPilpLilpEgICAgICAgIOKWkeKWkuKWk+KWiOKWk+KWkuKWkeKWkeKWkuKWk+KWiOKWk+KWkuKWkSDilpHilpLilpPilojilpPilpLilpHilpHilpLilpPilojilpPilpLilpEg4paR4paS4paT4paI4paT4paS4paRICAgICAgICAgICAgICAgICDilpHilpLilpPilojilpPilpLilpEgICAgICAgICAgICDilpHilpLilpPilojilpPilpLilpEgXG4jICAgICAgICAgICAgICAgICDilpHilpLilpPilojilojilojilojilojilojilojilpPilpLilpEgIOKWkeKWkuKWk+KWiOKWiOKWiOKWiOKWiOKWiOKWiOKWiOKWk+KWkuKWkSAg4paR4paS4paT4paI4paI4paI4paI4paI4paI4paT4paS4paRICDilpHilpLilpPilojilpPilpLilpHilpHilpLilpPilojilpPilpLilpEg4paR4paS4paT4paI4paT4paS4paRICAgICAgICAgICAgICAgICDilpHilpLilpPilojilpPilpLilpEgICAgIOKWkeKWkuKWk+KWiOKWiOKWiOKWiOKWiOKWiOKWiOKWk+KWkuKWkSAgXG4jYC5zcGxpdChcIlxcblwiKTtcbiAgY29uc3QgbWF4TGVuZ3RoID0gYmFubmVyLnJlZHVjZSgobWF4LCBsaW5lKSA9PiBNYXRoLm1heChtYXgsIGxpbmUubGVuZ3RoKSwgMCk7XG4gIGJhbm5lci5wdXNoKGAjICAke21lc3NhZ2UucGFkU3RhcnQobWF4TGVuZ3RoIC0gMyl9YCk7XG4gIGJhbm5lci5mb3JFYWNoKChsaW5lLCBpbmRleCkgPT4ge1xuICAgIChsb2dnZXIgPyBsb2dnZXIuaW5mby5iaW5kKGxvZ2dlcikgOiBjb25zb2xlLmxvZy5iaW5kKGNvbnNvbGUpKShcbiAgICAgIHN0eWxlKGxpbmUgfHwgXCJcIikucmF3KGNvbG9yc1tpbmRleF0pLnRleHRcbiAgICApO1xuICB9KTtcbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gUmV0cmlldmVzIGEgc2xvZ2FuIGZyb20gdGhlIHByZWRlZmluZWQgbGlzdC5cbiAqIEBzdW1tYXJ5IEZldGNoZXMgYSByYW5kb20gc2xvZ2FuIG9yIGEgc3BlY2lmaWMgb25lIGJ5IGluZGV4IGZyb20gdGhlIHNsb2dhbnMgbGlzdC5cbiAqIEBwYXJhbSB7bnVtYmVyfSBbaV0gLSBPcHRpb25hbCBpbmRleCB0byByZXRyaWV2ZSBhIHNwZWNpZmljIHNsb2dhbi5cbiAqIEByZXR1cm4ge3N0cmluZ30gVGhlIHNlbGVjdGVkIHNsb2dhbi5cbiAqIEBmdW5jdGlvbiBnZXRTbG9nYW5cbiAqIEBtZW1iZXJPZiBtb2R1bGU6dXRpbHNcbiAqIEBtZXJtYWlkXG4gKiBzZXF1ZW5jZURpYWdyYW1cbiAqICAgcGFydGljaXBhbnQgZ2V0U2xvZ2FuXG4gKiAgIHBhcnRpY2lwYW50IE1hdGgucmFuZG9tXG4gKiAgIHBhcnRpY2lwYW50IHNsb2dhbnNcbiAqICAgYWx0IGkgaXMgdW5kZWZpbmVkXG4gKiAgICAgZ2V0U2xvZ2FuLT4+TWF0aC5yYW5kb206IEdlbmVyYXRlIHJhbmRvbSBpbmRleFxuICogICAgIE1hdGgucmFuZG9tLS0+PmdldFNsb2dhbjogUmV0dXJuIHJhbmRvbSBpbmRleFxuICogICBlbHNlIGkgaXMgZGVmaW5lZFxuICogICAgIE5vdGUgb3ZlciBnZXRTbG9nYW46IFVzZSBwcm92aWRlZCBpbmRleFxuICogICBlbmRcbiAqICAgZ2V0U2xvZ2FuLT4+c2xvZ2FuczogQWNjZXNzIHNsb2dhbiBhdCBpbmRleFxuICogICBzbG9nYW5zLS0+PmdldFNsb2dhbjogUmV0dXJuIHNsb2dhblxuICogICBhbHQgRXJyb3Igb2NjdXJzXG4gKiAgICAgZ2V0U2xvZ2FuLT4+Z2V0U2xvZ2FuOiBUaHJvdyBlcnJvclxuICogICBlbmRcbiAqICAgZ2V0U2xvZ2FuLS0+PkNhbGxlcjogUmV0dXJuIHNsb2dhblxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0U2xvZ2FuKGk/OiBudW1iZXIpOiBzdHJpbmcge1xuICB0cnkge1xuICAgIGkgPVxuICAgICAgdHlwZW9mIGkgPT09IFwidW5kZWZpbmVkXCIgPyBNYXRoLmZsb29yKE1hdGgucmFuZG9tKCkgKiBzbG9nYW5zLmxlbmd0aCkgOiBpO1xuICAgIHJldHVybiBzbG9nYW5zW2ldLlNsb2dhbjtcbiAgfSBjYXRjaCAoZXJyb3I6IHVua25vd24pIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYEZhaWxlZCB0byByZXRyaWV2ZSBzbG9nYW5zOiAke2Vycm9yfWApO1xuICB9XG59XG4iLCJpbXBvcnQgeyBQYXJzZUFyZ3NSZXN1bHQgfSBmcm9tIFwiLi4vaW5wdXQvdHlwZXNcIjtcbmltcG9ydCB7IENvbW1hbmRPcHRpb25zIH0gZnJvbSBcIi4vdHlwZXNcIjtcbmltcG9ydCB7IFVzZXJJbnB1dCB9IGZyb20gXCIuLi9pbnB1dC9pbnB1dFwiO1xuaW1wb3J0IHsgRGVmYXVsdENvbW1hbmRPcHRpb25zLCBEZWZhdWx0Q29tbWFuZFZhbHVlcyB9IGZyb20gXCIuL2NvbnN0YW50c1wiO1xuaW1wb3J0IHsgZ2V0RGVwZW5kZW5jaWVzLCBnZXRQYWNrYWdlVmVyc2lvbiB9IGZyb20gXCIuLi91dGlscy9mc1wiO1xuaW1wb3J0IHsgcHJpbnRCYW5uZXIgfSBmcm9tIFwiLi4vb3V0cHV0L2NvbW1vblwiO1xuaW1wb3J0IHtcbiAgTG9nZ2VkQ2xhc3MsXG4gIExvZ2dlZEVudmlyb25tZW50LFxuICBMb2dnZXIsXG4gIExvZ2dpbmcsXG4gIExvZ2dpbmdDb25maWcsXG59IGZyb20gXCJAZGVjYWYtdHMvbG9nZ2luZ1wiO1xuXG4vKipcbiAqIEBjbGFzcyBDb21tYW5kXG4gKiBAYWJzdHJhY3RcbiAqIEB0ZW1wbGF0ZSBJIC0gVGhlIHR5cGUgb2YgaW5wdXQgb3B0aW9ucyBmb3IgdGhlIGNvbW1hbmQuXG4gKiBAdGVtcGxhdGUgUiAtIFRoZSByZXR1cm4gdHlwZSBvZiB0aGUgY29tbWFuZCBleGVjdXRpb24uXG4gKiBAbWVtYmVyT2YgbW9kdWxlOnV0aWxzXG4gKiBAZGVzY3JpcHRpb24gQWJzdHJhY3QgYmFzZSBjbGFzcyBmb3IgY29tbWFuZCBpbXBsZW1lbnRhdGlvbi5cbiAqIEBzdW1tYXJ5IFByb3ZpZGVzIGEgc3RydWN0dXJlIGZvciBjcmVhdGluZyBjb21tYW5kLWxpbmUgaW50ZXJmYWNlIGNvbW1hbmRzIHdpdGggaW5wdXQgaGFuZGxpbmcsIGxvZ2dpbmcsIGFuZCBleGVjdXRpb24gZmxvdy5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gbmFtZSAtIFRoZSBuYW1lIG9mIHRoZSBjb21tYW5kLlxuICogQHBhcmFtIHtDb21tYW5kT3B0aW9uczxJPn0gW2lucHV0c10gLSBUaGUgaW5wdXQgb3B0aW9ucyBmb3IgdGhlIGNvbW1hbmQuXG4gKiBAcGFyYW0ge3N0cmluZ1tdfSBbcmVxdWlyZW1lbnRzXSAtIFRoZSBsaXN0IG9mIHJlcXVpcmVkIGRlcGVuZGVuY2llcyBmb3IgdGhlIGNvbW1hbmQuXG4gKi9cbmV4cG9ydCBhYnN0cmFjdCBjbGFzcyBDb21tYW5kPEksIFI+IGV4dGVuZHMgTG9nZ2VkQ2xhc3Mge1xuICAvKipcbiAgICogQHN0YXRpY1xuICAgKiBAZGVzY3JpcHRpb24gU3RhdGljIGxvZ2dlciBmb3IgdGhlIENvbW1hbmQgY2xhc3MuXG4gICAqIEB0eXBlIHtMb2dnZXJ9XG4gICAqL1xuICBzdGF0aWMgbG9nOiBMb2dnZXI7XG5cbiAgcHJvdGVjdGVkIGNvbnN0cnVjdG9yKFxuICAgIHByb3RlY3RlZCBuYW1lOiBzdHJpbmcsXG4gICAgcHJvdGVjdGVkIGlucHV0czogQ29tbWFuZE9wdGlvbnM8ST4gPSB7fSBhcyB1bmtub3duIGFzIENvbW1hbmRPcHRpb25zPEk+LFxuICAgIHByb3RlY3RlZCByZXF1aXJlbWVudHM6IHN0cmluZ1tdID0gW11cbiAgKSB7XG4gICAgc3VwZXIoKTtcbiAgICBpZiAoIUNvbW1hbmQubG9nKSB7XG4gICAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkoQ29tbWFuZCwgXCJsb2dcIiwge1xuICAgICAgICB3cml0YWJsZTogZmFsc2UsXG4gICAgICAgIHZhbHVlOiBMb2dnaW5nLmZvcihDb21tYW5kLm5hbWUpLFxuICAgICAgfSk7XG4gICAgfVxuICAgIHRoaXMuaW5wdXRzID0gT2JqZWN0LmFzc2lnbihcbiAgICAgIHt9LFxuICAgICAgRGVmYXVsdENvbW1hbmRPcHRpb25zLFxuICAgICAgaW5wdXRzXG4gICAgKSBhcyBDb21tYW5kT3B0aW9uczxJPjtcbiAgfVxuXG4gIC8qKlxuICAgKiBAcHJvdGVjdGVkXG4gICAqIEBhc3luY1xuICAgKiBAZGVzY3JpcHRpb24gQ2hlY2tzIGlmIGFsbCByZXF1aXJlZCBkZXBlbmRlbmNpZXMgYXJlIHByZXNlbnQuXG4gICAqIEBzdW1tYXJ5IFJldHJpZXZlcyB0aGUgbGlzdCBvZiBkZXBlbmRlbmNpZXMgYW5kIGNvbXBhcmVzIGl0IGFnYWluc3QgdGhlIHJlcXVpcmVkIGRlcGVuZGVuY2llcyBmb3IgdGhlIGNvbW1hbmQuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIHRoZSBjaGVjayBpcyBjb21wbGV0ZS5cbiAgICpcbiAgICogQG1lcm1haWRcbiAgICogc2VxdWVuY2VEaWFncmFtXG4gICAqICAgcGFydGljaXBhbnQgQ29tbWFuZFxuICAgKiAgIHBhcnRpY2lwYW50IGdldERlcGVuZGVuY2llc1xuICAgKiAgIHBhcnRpY2lwYW50IFNldFxuICAgKiAgIENvbW1hbmQtPj5nZXREZXBlbmRlbmNpZXM6IENhbGxcbiAgICogICBnZXREZXBlbmRlbmNpZXMtLT4+Q29tbWFuZDogUmV0dXJuIHtwcm9kLCBkZXYsIHBlZXJ9XG4gICAqICAgQ29tbWFuZC0+PlNldDogQ3JlYXRlIFNldCBmcm9tIHByb2QsIGRldiwgcGVlclxuICAgKiAgIFNldC0tPj5Db21tYW5kOiBSZXR1cm4gdW5pcXVlIGRlcGVuZGVuY2llc1xuICAgKiAgIENvbW1hbmQtPj5Db21tYW5kOiBDb21wYXJlIGFnYWluc3QgcmVxdWlyZW1lbnRzXG4gICAqICAgYWx0IE1pc3NpbmcgZGVwZW5kZW5jaWVzXG4gICAqICAgICBDb21tYW5kLT4+Q29tbWFuZDogQWRkIHRvIG1pc3NpbmcgbGlzdFxuICAgKiAgIGVuZFxuICAgKiAgIE5vdGUgb3ZlciBDb21tYW5kOiBJZiBtaXNzaW5nLmxlbmd0aCA+IDAsIGhhbmRsZSBtaXNzaW5nIGRlcGVuZGVuY2llc1xuICAgKi9cbiAgcHJvdGVjdGVkIGFzeW5jIGNoZWNrUmVxdWlyZW1lbnRzKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IHsgcHJvZCwgZGV2LCBwZWVyIH0gPSBhd2FpdCBnZXREZXBlbmRlbmNpZXMoKTtcbiAgICBjb25zdCBtaXNzaW5nID0gW107XG4gICAgY29uc3QgZnVsbExpc3QgPSBBcnJheS5mcm9tKFxuICAgICAgbmV3IFNldChbLi4ucHJvZCwgLi4uZGV2LCAuLi5wZWVyXSkudmFsdWVzKClcbiAgICApLm1hcCgoZCkgPT4gZC5uYW1lKTtcbiAgICBmb3IgKGNvbnN0IGRlcCBvZiB0aGlzLnJlcXVpcmVtZW50cylcbiAgICAgIGlmICghZnVsbExpc3QuaW5jbHVkZXMoZGVwKSkgbWlzc2luZy5wdXNoKGRlcCk7XG5cbiAgICBpZiAoIW1pc3NpbmcubGVuZ3RoKSByZXR1cm47XG4gIH1cblxuICAvKipcbiAgICogQHByb3RlY3RlZFxuICAgKiBAZGVzY3JpcHRpb24gUHJvdmlkZXMgaGVscCBpbmZvcm1hdGlvbiBmb3IgdGhlIGNvbW1hbmQuXG4gICAqIEBzdW1tYXJ5IFRoaXMgbWV0aG9kIHNob3VsZCBiZSBvdmVycmlkZGVuIGluIGRlcml2ZWQgY2xhc3NlcyB0byBwcm92aWRlIHNwZWNpZmljIGhlbHAgaW5mb3JtYXRpb24uXG4gICAqIEBwYXJhbSB7UGFyc2VBcmdzUmVzdWx0fSBhcmdzIC0gVGhlIHBhcnNlZCBjb21tYW5kLWxpbmUgYXJndW1lbnRzLlxuICAgKiBAcmV0dXJucyB7dm9pZH1cbiAgICovXG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnNcbiAgcHJvdGVjdGVkIGhlbHAoYXJnczogUGFyc2VBcmdzUmVzdWx0KTogdm9pZCB7XG4gICAgcmV0dXJuIHRoaXMubG9nLmluZm8oXG4gICAgICBgVGhpcyBpcyBoZWxwLiBJJ20gbm8gdXNlIGJlY2F1c2UgSSBzaG91bGQgaGF2ZSBiZWVuIG92ZXJyaWRkZW4uYFxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogQHByb3RlY3RlZFxuICAgKiBAYWJzdHJhY3RcbiAgICogQGRlc2NyaXB0aW9uIFJ1bnMgdGhlIGNvbW1hbmQgd2l0aCB0aGUgcHJvdmlkZWQgYXJndW1lbnRzLlxuICAgKiBAc3VtbWFyeSBUaGlzIG1ldGhvZCBzaG91bGQgYmUgaW1wbGVtZW50ZWQgaW4gZGVyaXZlZCBjbGFzc2VzIHRvIGRlZmluZSB0aGUgY29tbWFuZCdzIGJlaGF2aW9yLlxuICAgKiBAcGFyYW0ge1BhcnNlQXJnc1Jlc3VsdH0gYW5zd2VycyAtIFRoZSBwYXJzZWQgY29tbWFuZC1saW5lIGFyZ3VtZW50cy5cbiAgICogQHJldHVybnMge1Byb21pc2U8UiB8IHN0cmluZyB8IHZvaWQ+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aXRoIHRoZSBjb21tYW5kJ3MgcmVzdWx0LlxuICAgKi9cbiAgcHJvdGVjdGVkIGFic3RyYWN0IHJ1bjxSPihcbiAgICBhbnN3ZXJzOiBMb2dnaW5nQ29uZmlnICZcbiAgICAgIHR5cGVvZiBEZWZhdWx0Q29tbWFuZFZhbHVlcyAmIHsgW2sgaW4ga2V5b2YgSV06IHVua25vd24gfVxuICApOiBQcm9taXNlPFIgfCBzdHJpbmcgfCB2b2lkPjtcblxuICAvKipcbiAgICogQGFzeW5jXG4gICAqIEBkZXNjcmlwdGlvbiBFeGVjdXRlcyB0aGUgY29tbWFuZC5cbiAgICogQHN1bW1hcnkgVGhpcyBtZXRob2QgaGFuZGxlcyB0aGUgb3ZlcmFsbCBleGVjdXRpb24gZmxvdyBvZiB0aGUgY29tbWFuZCwgaW5jbHVkaW5nIHBhcnNpbmcgYXJndW1lbnRzLFxuICAgKiBzZXR0aW5nIHVwIGxvZ2dpbmcsIGNoZWNraW5nIGZvciB2ZXJzaW9uIG9yIGhlbHAgcmVxdWVzdHMsIGFuZCBydW5uaW5nIHRoZSBjb21tYW5kLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxSIHwgc3RyaW5nIHwgdm9pZD59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHdpdGggdGhlIGNvbW1hbmQncyByZXN1bHQuXG4gICAqXG4gICAqIEBtZXJtYWlkXG4gICAqIHNlcXVlbmNlRGlhZ3JhbVxuICAgKiAgIHBhcnRpY2lwYW50IENvbW1hbmRcbiAgICogICBwYXJ0aWNpcGFudCBVc2VySW5wdXRcbiAgICogICBwYXJ0aWNpcGFudCBMb2dnaW5nXG4gICAqICAgcGFydGljaXBhbnQgZ2V0UGFja2FnZVZlcnNpb25cbiAgICogICBwYXJ0aWNpcGFudCBwcmludEJhbm5lclxuICAgKiAgIENvbW1hbmQtPj5Vc2VySW5wdXQ6IHBhcnNlQXJncyhpbnB1dHMpXG4gICAqICAgVXNlcklucHV0LS0+PkNvbW1hbmQ6IFJldHVybiBQYXJzZUFyZ3NSZXN1bHRcbiAgICogICBDb21tYW5kLT4+Q29tbWFuZDogUHJvY2VzcyBvcHRpb25zXG4gICAqICAgQ29tbWFuZC0+PkxvZ2dpbmc6IHNldENvbmZpZyhvcHRpb25zKVxuICAgKiAgIGFsdCB2ZXJzaW9uIHJlcXVlc3RlZFxuICAgKiAgICAgQ29tbWFuZC0+PmdldFBhY2thZ2VWZXJzaW9uOiBDYWxsXG4gICAqICAgICBnZXRQYWNrYWdlVmVyc2lvbi0tPj5Db21tYW5kOiBSZXR1cm4gdmVyc2lvblxuICAgKiAgIGVsc2UgaGVscCByZXF1ZXN0ZWRcbiAgICogICAgIENvbW1hbmQtPj5Db21tYW5kOiBoZWxwKGFyZ3MpXG4gICAqICAgZWxzZSBiYW5uZXIgcmVxdWVzdGVkXG4gICAqICAgICBDb21tYW5kLT4+cHJpbnRCYW5uZXI6IENhbGxcbiAgICogICBlbmRcbiAgICogICBDb21tYW5kLT4+Q29tbWFuZDogcnVuKGFyZ3MpXG4gICAqICAgYWx0IGVycm9yIG9jY3Vyc1xuICAgKiAgICAgQ29tbWFuZC0+PkNvbW1hbmQ6IExvZyBlcnJvclxuICAgKiAgIGVuZFxuICAgKiAgIENvbW1hbmQtLT4+Q29tbWFuZDogUmV0dXJuIHJlc3VsdFxuICAgKi9cbiAgYXN5bmMgZXhlY3V0ZSgpOiBQcm9taXNlPFIgfCBzdHJpbmcgfCB2b2lkPiB7XG4gICAgY29uc3QgYXJnczogUGFyc2VBcmdzUmVzdWx0ID0gVXNlcklucHV0LnBhcnNlQXJncyh0aGlzLmlucHV0cyk7XG4gICAgY29uc3QgZW52ID0gTG9nZ2VkRW52aXJvbm1lbnQuYWNjdW11bGF0ZShEZWZhdWx0Q29tbWFuZFZhbHVlcykuYWNjdW11bGF0ZShcbiAgICAgIGFyZ3MudmFsdWVzXG4gICAgKTtcbiAgICBjb25zdCB7IHZlcnNpb24sIGhlbHAsIGJhbm5lciB9ID0gZW52O1xuXG4gICAgaWYgKHZlcnNpb24pIHtcbiAgICAgIHJldHVybiBnZXRQYWNrYWdlVmVyc2lvbigpO1xuICAgIH1cblxuICAgIGlmIChoZWxwKSB7XG4gICAgICByZXR1cm4gdGhpcy5oZWxwKGFyZ3MpO1xuICAgIH1cblxuICAgIGlmIChiYW5uZXIpXG4gICAgICBwcmludEJhbm5lcihcbiAgICAgICAgdGhpcy5sb2cuZm9yKHByaW50QmFubmVyLCB7XG4gICAgICAgICAgdGltZXN0YW1wOiBmYWxzZSxcbiAgICAgICAgICBzdHlsZTogZmFsc2UsXG4gICAgICAgICAgY29udGV4dDogZmFsc2UsXG4gICAgICAgICAgbG9nTGV2ZWw6IGZhbHNlLFxuICAgICAgICB9KVxuICAgICAgKTtcblxuICAgIGxldCByZXN1bHQ7XG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVzZWxlc3MtY2F0Y2hcbiAgICB0cnkge1xuICAgICAgcmVzdWx0ID0gYXdhaXQgdGhpcy5ydW4oZW52IGFzIGFueSk7XG4gICAgfSBjYXRjaCAoZTogdW5rbm93bikge1xuICAgICAgdGhyb3cgZTtcbiAgICB9XG5cbiAgICByZXR1cm4gcmVzdWx0IGFzIFI7XG4gIH1cbn1cbiIsIi8qIGlzdGFuYnVsIGlnbm9yZSBmaWxlICovXG5pbXBvcnQgaHR0cHMgZnJvbSBcImh0dHBzXCI7XG5pbXBvcnQgeyBMb2dnaW5nIH0gZnJvbSBcIkBkZWNhZi10cy9sb2dnaW5nXCI7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIEEgc2ltcGxlIEhUVFAgY2xpZW50IGZvciBkb3dubG9hZGluZyBmaWxlcy5cbiAqIEBzdW1tYXJ5IFRoaXMgY2xhc3MgcHJvdmlkZXMgZnVuY3Rpb25hbGl0eSB0byBkb3dubG9hZCBmaWxlcyBmcm9tIEhUVFBTIFVSTHMuXG4gKiBJdCB1c2VzIE5vZGUuanMgYnVpbHQtaW4gaHR0cHMgbW9kdWxlIHRvIG1ha2UgcmVxdWVzdHMuXG4gKlxuICogQGNsYXNzIEh0dHBDbGllbnRcbiAqL1xuZXhwb3J0IGNsYXNzIEh0dHBDbGllbnQge1xuICBwcm90ZWN0ZWQgc3RhdGljIGxvZyA9IExvZ2dpbmcuZm9yKEh0dHBDbGllbnQpO1xuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIERvd25sb2FkcyBhIGZpbGUgZnJvbSBhIGdpdmVuIFVSTC5cbiAgICogQHN1bW1hcnkgVGhpcyBtZXRob2Qgc2VuZHMgYSBHRVQgcmVxdWVzdCB0byB0aGUgc3BlY2lmaWVkIFVSTCBhbmQgcmV0dXJucyB0aGUgcmVzcG9uc2UgYm9keSBhcyBhIHN0cmluZy5cbiAgICogSXQgaGFuZGxlcyBkaWZmZXJlbnQgc2NlbmFyaW9zIHN1Y2ggYXMgbm9uLTIwMCBzdGF0dXMgY29kZXMgYW5kIG5ldHdvcmsgZXJyb3JzLlxuICAgKlxuICAgKiBAcGFyYW0gdXJsIC0gVGhlIFVSTCBvZiB0aGUgZmlsZSB0byBkb3dubG9hZC5cbiAgICogQHJldHVybiBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aXRoIHRoZSBmaWxlIGNvbnRlbnQgYXMgYSBzdHJpbmcuXG4gICAqXG4gICAqIEBtZXJtYWlkXG4gICAqIHNlcXVlbmNlRGlhZ3JhbVxuICAgKiAgIHBhcnRpY2lwYW50IENsaWVudFxuICAgKiAgIHBhcnRpY2lwYW50IEh0dHBDbGllbnRcbiAgICogICBwYXJ0aWNpcGFudCBIVFRQU1xuICAgKiAgIHBhcnRpY2lwYW50IFNlcnZlclxuICAgKiAgIENsaWVudC0+Pkh0dHBDbGllbnQ6IGRvd25sb2FkRmlsZSh1cmwpXG4gICAqICAgSHR0cENsaWVudC0+PkhUVFBTOiBnZXQodXJsKVxuICAgKiAgIEhUVFBTLT4+U2VydmVyOiBHRVQgcmVxdWVzdFxuICAgKiAgIFNlcnZlci0tPj5IVFRQUzogUmVzcG9uc2VcbiAgICogICBIVFRQUy0tPj5IdHRwQ2xpZW50OiBSZXNwb25zZSBvYmplY3RcbiAgICogICBhbHQgU3RhdHVzIGNvZGUgaXMgMjAwXG4gICAqICAgICBsb29wIEZvciBlYWNoIGRhdGEgY2h1bmtcbiAgICogICAgICAgSFRUUFMtPj5IdHRwQ2xpZW50OiAnZGF0YScgZXZlbnRcbiAgICogICAgICAgSHR0cENsaWVudC0+Pkh0dHBDbGllbnQ6IEFjY3VtdWxhdGUgZGF0YVxuICAgKiAgICAgZW5kXG4gICAqICAgICBIVFRQUy0+Pkh0dHBDbGllbnQ6ICdlbmQnIGV2ZW50XG4gICAqICAgICBIdHRwQ2xpZW50LS0+PkNsaWVudDogUmVzb2x2ZSB3aXRoIGRhdGFcbiAgICogICBlbHNlIFN0YXR1cyBjb2RlIGlzIG5vdCAyMDBcbiAgICogICAgIEh0dHBDbGllbnQtLT4+Q2xpZW50OiBSZWplY3Qgd2l0aCBlcnJvclxuICAgKiAgIGVuZFxuICAgKi9cbiAgc3RhdGljIGFzeW5jIGRvd25sb2FkRmlsZSh1cmw6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlPHN0cmluZz4oKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgZnVuY3Rpb24gcmVxdWVzdCh1cmw6IHN0cmluZykge1xuICAgICAgICB1cmwgPSBlbmNvZGVVUkkodXJsKTtcbiAgICAgICAgaHR0cHMuZ2V0KHVybCwgKHJlcykgPT4ge1xuICAgICAgICAgIGlmIChyZXMuc3RhdHVzQ29kZSA9PT0gMzAxIHx8IHJlcy5zdGF0dXNDb2RlID09PSAzMDcpXG4gICAgICAgICAgICByZXR1cm4gcmVxdWVzdChyZXMuaGVhZGVycy5sb2NhdGlvbiBhcyBzdHJpbmcpO1xuXG4gICAgICAgICAgaWYgKHJlcy5zdGF0dXNDb2RlICE9PSAyMDApIHtcbiAgICAgICAgICAgIEh0dHBDbGllbnQubG9nLmVycm9yKFxuICAgICAgICAgICAgICBgRmFpbGVkIHRvIGZldGNoICR7dXJsfSAoc3RhdHVzOiAke3Jlcy5zdGF0dXNDb2RlfSlgXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgcmV0dXJuIHJlamVjdChuZXcgRXJyb3IoYEZhaWxlZCB0byBmZXRjaCAke3VybH1gKSk7XG4gICAgICAgICAgfVxuICAgICAgICAgIGxldCBkYXRhID0gXCJcIjtcbiAgICAgICAgICByZXMub24oXCJkYXRhXCIsIChjaHVuaykgPT4ge1xuICAgICAgICAgICAgZGF0YSArPSBjaHVuaztcbiAgICAgICAgICB9KTtcbiAgICAgICAgICByZXMub24oXCJlcnJvclwiLCAoZXJyb3IpID0+IHtcbiAgICAgICAgICAgIHJlamVjdChlcnJvcik7XG4gICAgICAgICAgfSk7XG5cbiAgICAgICAgICByZXMub24oXCJlbmRcIiwgKCkgPT4ge1xuICAgICAgICAgICAgcmVzb2x2ZShkYXRhKTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgICByZXF1ZXN0KHVybCk7XG4gICAgfSk7XG4gIH1cbn1cbiIsImltcG9ydCBwYXRoIGZyb20gXCJwYXRoXCI7XG5pbXBvcnQgeyBta2Rpciwgd3JpdGVGaWxlIH0gZnJvbSBcImZzL3Byb21pc2VzXCI7XG5pbXBvcnQgeyBTdG9wV2F0Y2ggfSBmcm9tIFwiQGRlY2FmLXRzL2xvZ2dpbmdcIjtcblxuZXhwb3J0IHR5cGUgRXhlY3V0aW9uTW9kZSA9IFwic2VxdWVudGlhbFwiIHwgXCJjb25jdXJyZW50XCIgfCBcImJ1cnN0XCI7XG5cbmV4cG9ydCBpbnRlcmZhY2UgUGhhc2VCdXJzdENvbmZpZyB7XG4gIHNpemU6IG51bWJlcjtcbiAgaW50ZXJ2YWxNcz86IG51bWJlcjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBQaGFzZVdhcm11cENvbmZpZzxUQ29udGV4dCA9IFJlY29yZDxzdHJpbmcsIHVua25vd24+PiB7XG4gIGl0ZXJhdGlvbnM6IG51bWJlcjtcbiAgaGFuZGxlcj86IFBlcmZvcm1hbmNlSGFuZGxlcjxUQ29udGV4dD47XG4gIGRlbGF5QmV0d2Vlbkl0ZXJhdGlvbnNNcz86IG51bWJlcjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBQaGFzZUNvbmZpZzxUQ29udGV4dCA9IFJlY29yZDxzdHJpbmcsIHVua25vd24+PiB7XG4gIGl0ZXJhdGlvbnM6IG51bWJlcjtcbiAgbW9kZTogRXhlY3V0aW9uTW9kZTtcbiAgY29uY3VycmVuY3k/OiBudW1iZXI7XG4gIGRlbGF5QmV0d2Vlbkl0ZXJhdGlvbnNNcz86IG51bWJlcjtcbiAgYnVyc3Q/OiBQaGFzZUJ1cnN0Q29uZmlnO1xuICBsb2FkU3RhcnQ/OiBudW1iZXI7XG4gIGxvYWRTdGVwPzogbnVtYmVyO1xuICBsb2FkTXVsdGlwbGllcj86IG51bWJlcjtcbiAgY29udGV4dD86IFBhcnRpYWw8VENvbnRleHQ+O1xuICBtZXRhZGF0YT86IFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICB3YXJtdXA/OiBQaGFzZVdhcm11cENvbmZpZzxUQ29udGV4dD47XG4gIHBhdXNlQWZ0ZXJNcz86IG51bWJlcjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBQaGFzZTxUQ29udGV4dCA9IFJlY29yZDxzdHJpbmcsIHVua25vd24+PiB7XG4gIG5hbWU6IHN0cmluZztcbiAgY29uZmlnOiBQaGFzZUNvbmZpZzxUQ29udGV4dD47XG4gIGdlbmVyYXRvcj86IFBoYXNlR2VuZXJhdG9yPFRDb250ZXh0PjtcbiAgc3ViUGhhc2VzPzogUGhhc2U8VENvbnRleHQ+W107XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUGhhc2VHZW5lcmF0b3JQaGFzZTxUQ29udGV4dD4ge1xuICBuYW1lPzogc3RyaW5nO1xuICBjb25maWc6IFBoYXNlQ29uZmlnPFBhcnRpYWw8VENvbnRleHQ+Pjtcbn1cblxuZXhwb3J0IHR5cGUgUGhhc2VHZW5lcmF0b3JSZXN1bHQ8VENvbnRleHQ+ID1cbiAgfCBQaGFzZUNvbmZpZzxUQ29udGV4dD5cbiAgfCBQaGFzZUdlbmVyYXRvclBoYXNlPFRDb250ZXh0PjtcblxuZXhwb3J0IHR5cGUgUGhhc2VHZW5lcmF0b3I8VENvbnRleHQ+ID0gKFxuICBwYXlsb2FkOiBQaGFzZUdlbmVyYXRvclBheWxvYWQ8VENvbnRleHQ+XG4pID0+XG4gIHwgUHJvbWlzZTxQaGFzZUdlbmVyYXRvclJlc3VsdDxUQ29udGV4dD4gfCB1bmRlZmluZWQ+XG4gIHwgUGhhc2VHZW5lcmF0b3JSZXN1bHQ8VENvbnRleHQ+XG4gIHwgdW5kZWZpbmVkO1xuXG5leHBvcnQgaW50ZXJmYWNlIFBoYXNlUmVzdWx0PFRDb250ZXh0ID0gUmVjb3JkPHN0cmluZywgdW5rbm93bj4+IHtcbiAgcGhhc2U6IFBoYXNlPFRDb250ZXh0PjtcbiAgY29uZmlnOiBQaGFzZUNvbmZpZzxUQ29udGV4dD47XG4gIGl0ZXJhdGlvbk1ldHJpY3M6IEl0ZXJhdGlvbk1ldHJpY1tdO1xuICBhZ2dyZWdhdGVkOiBBZ2dyZWdhdGVkTWV0cmljcztcbiAgY29udGV4dDogVENvbnRleHQ7XG4gIHNlZ21lbnRDb3VudDogbnVtYmVyO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFBoYXNlR2VuZXJhdG9yTWV0YWRhdGE8VENvbnRleHQgPSBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPj4ge1xuICBwaGFzZU51bWJlcjogbnVtYmVyO1xuICBwaGFzZU5hbWU6IHN0cmluZztcbiAgaXRlcmF0aW9uQ291bnQ6IG51bWJlcjtcbiAgYnVyc3RTZWdtZW50czogbnVtYmVyO1xuICBzZWdtZW50Q291bnQ6IG51bWJlcjtcbiAgbW9kZTogRXhlY3V0aW9uTW9kZTtcbiAgaGlzdG9yeTogUGhhc2VSZXN1bHQ8VENvbnRleHQ+W107XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUGhhc2VHZW5lcmF0b3JQYXlsb2FkPFRDb250ZXh0ID0gUmVjb3JkPHN0cmluZywgdW5rbm93bj4+IHtcbiAgcmVzdWx0OiBQaGFzZVJlc3VsdDxUQ29udGV4dD47XG4gIGhpc3Rvcnk6IFBoYXNlUmVzdWx0PFRDb250ZXh0PltdO1xuICBtZXRhZGF0YTogUGhhc2VHZW5lcmF0b3JNZXRhZGF0YTxUQ29udGV4dD47XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQWdncmVnYXRlZE1ldHJpY3Mge1xuICB0b3RhbER1cmF0aW9uTXM6IG51bWJlcjtcbiAgbWluTXM6IG51bWJlcjtcbiAgbWF4TXM6IG51bWJlcjtcbiAgYXZlcmFnZU1zOiBudW1iZXI7XG4gIHN1Y2Nlc3NDb3VudDogbnVtYmVyO1xuICBmYWlsdXJlQ291bnQ6IG51bWJlcjtcbiAgbG9hZFN0YXJ0OiBudW1iZXI7XG4gIGxvYWRFbmQ6IG51bWJlcjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBJdGVyYXRpb25NZXRyaWMge1xuICBpdGVyYXRpb246IG51bWJlcjtcbiAgZHVyYXRpb25NczogbnVtYmVyO1xuICBzdWNjZXNzOiBib29sZWFuO1xuICBtZXRhPzogUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gIGxvYWRGYWN0b3I6IG51bWJlcjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBIYW5kbGVyUGF5bG9hZDxUQ29udGV4dCA9IFJlY29yZDxzdHJpbmcsIHVua25vd24+PiB7XG4gIGl0ZXJhdGlvbjogbnVtYmVyO1xuICBjb25maWc6IFBoYXNlQ29uZmlnPFRDb250ZXh0PjtcbiAgbG9hZEZhY3RvcjogbnVtYmVyO1xuICBjb250ZXh0OiBUQ29udGV4dDtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBIYW5kbGVyUmVzdWx0IHtcbiAgc3VjY2Vzcz86IGJvb2xlYW47XG4gIG1ldGE/OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbn1cblxuZXhwb3J0IHR5cGUgUGVyZm9ybWFuY2VIYW5kbGVyPFRDb250ZXh0ID0gUmVjb3JkPHN0cmluZywgdW5rbm93bj4+ID0gKFxuICBwYXlsb2FkOiBIYW5kbGVyUGF5bG9hZDxUQ29udGV4dD5cbikgPT4gUHJvbWlzZTxIYW5kbGVyUmVzdWx0PiB8IEhhbmRsZXJSZXN1bHQ7XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ2FudmFzUmVuZGVyT3B0aW9ucyB7XG4gIHdpZHRoPzogbnVtYmVyO1xuICBoZWlnaHQ/OiBudW1iZXI7XG4gIHBhZGRpbmc/OiBudW1iZXI7XG4gIGJhY2tncm91bmRDb2xvcj86IHN0cmluZztcbiAgaGVhZGVyRm9udD86IHN0cmluZztcbiAgcm93Rm9udD86IHN0cmluZztcbiAgaGVhZGVyQ29sb3I/OiBzdHJpbmc7XG4gIHJvd0NvbG9yPzogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFBlcmZvcm1hbmNlU2NlbmFyaW88VENvbnRleHQgPSBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPj4ge1xuICBuYW1lOiBzdHJpbmc7XG4gIGhhbmRsZXI6IFBlcmZvcm1hbmNlSGFuZGxlcjxUQ29udGV4dD47XG4gIHBoYXNlczogUGhhc2U8VENvbnRleHQ+W107XG4gIGJhc2VDb250ZXh0PzogVENvbnRleHQ7XG4gIGZhaWxPbkVycm9yPzogYm9vbGVhbjtcbiAgaW5pdGlhbGl6ZT86ICgpID0+IFByb21pc2U8dm9pZD4gfCB2b2lkO1xuICBjYW52YXNPcHRpb25zPzogQ2FudmFzUmVuZGVyT3B0aW9ucztcbiAgY2FudmFzT3V0cHV0UGF0aD86IHN0cmluZztcbiAgZW5hYmxlQ2FudmFzPzogYm9vbGVhbjtcbn1cblxuaW50ZXJmYWNlIFBoYXNlUXVldWVJdGVtPFRDb250ZXh0PiB7XG4gIHBoYXNlOiBQaGFzZTxUQ29udGV4dD47XG4gIHBoYXNlTnVtYmVyOiBudW1iZXI7XG59XG5cbmV4cG9ydCBjb25zdCBkZWZhdWx0Q2FudmFzT3B0aW9uczogUmVxdWlyZWQ8Q2FudmFzUmVuZGVyT3B0aW9ucz4gPSB7XG4gIHdpZHRoOiAxMjAwLFxuICBoZWlnaHQ6IDI2MCxcbiAgcGFkZGluZzogMzIsXG4gIGJhY2tncm91bmRDb2xvcjogXCIjMGYxNzJhXCIsXG4gIGhlYWRlckZvbnQ6IFwiYm9sZCAxOHB4ICdTZWdvZSBVSScsIHNhbnMtc2VyaWZcIixcbiAgcm93Rm9udDogXCIxNHB4ICdTZWdvZSBVSScsIHNhbnMtc2VyaWZcIixcbiAgaGVhZGVyQ29sb3I6IFwiI2Y4ZmFmY1wiLFxuICByb3dDb2xvcjogXCIjY2JkNWY1XCIsXG59O1xuXG5jb25zdCBkZWxheSA9IChtczogbnVtYmVyKSA9PiBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4gc2V0VGltZW91dChyZXNvbHZlLCBtcykpO1xuY29uc3QgcGVyZkRlYnVnRW5hYmxlZCA9IHByb2Nlc3MuZW52LlBFUkZfVkVSQk9TRSA9PT0gXCJ0cnVlXCI7XG5jb25zdCBkZWJ1Z0xvZyA9ICguLi5hcmdzOiB1bmtub3duW10pID0+IHtcbiAgaWYgKHBlcmZEZWJ1Z0VuYWJsZWQpIHtcbiAgICBjb25zb2xlLmRlYnVnKC4uLmFyZ3MpO1xuICB9XG59O1xuXG5jb25zdCBmb3JtYXRUYWJsZSA9IChcbiAgdGl0bGU6IHN0cmluZyxcbiAgaGVhZGVyczogc3RyaW5nW10sXG4gIHJvd3M6IHN0cmluZ1tdW11cbik6IHN0cmluZyA9PiB7XG4gIGNvbnN0IGNvbHVtbldpZHRocyA9IGhlYWRlcnMubWFwKChoZWFkZXIsIGluZGV4KSA9PlxuICAgIE1hdGgubWF4KGhlYWRlci5sZW5ndGgsIC4uLnJvd3MubWFwKChyb3cpID0+IHJvd1tpbmRleF0/Lmxlbmd0aCA/PyAwKSlcbiAgKTtcbiAgY29uc3QgZm9ybWF0Um93ID0gKHZhbHVlczogc3RyaW5nW10pID0+XG4gICAgXCJ8IFwiICtcbiAgICB2YWx1ZXNcbiAgICAgIC5tYXAoKHZhbHVlLCBpbmRleCkgPT4gdmFsdWUucGFkRW5kKGNvbHVtbldpZHRoc1tpbmRleF0pKVxuICAgICAgLmpvaW4oXCIgfCBcIikgK1xuICAgIFwiIHxcIjtcbiAgY29uc3QgaGVhZGVyTGluZSA9IGZvcm1hdFJvdyhoZWFkZXJzKTtcbiAgY29uc3QgZGl2aWRlciA9XG4gICAgXCJ8IFwiICsgY29sdW1uV2lkdGhzLm1hcCgod2lkdGgpID0+IFwiLVwiLnJlcGVhdCh3aWR0aCkpLmpvaW4oXCIgfCBcIikgKyBcIiB8XCI7XG4gIGNvbnN0IGJvZHkgPSByb3dzLm1hcChmb3JtYXRSb3cpLmpvaW4oXCJcXG5cIik7XG4gIHJldHVybiBgJHt0aXRsZX1cXG4ke2hlYWRlckxpbmV9XFxuJHtkaXZpZGVyfVxcbiR7Ym9keX1gO1xufTtcblxuY29uc3QgZW5zdXJlRGlyZWN0b3J5ID0gYXN5bmMgKHRhcmdldFBhdGg6IHN0cmluZykgPT4ge1xuICBhd2FpdCBta2RpcihwYXRoLmRpcm5hbWUodGFyZ2V0UGF0aCksIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xufTtcblxuY29uc3QgcmVuZGVyTWV0cmljc1RhYmxlVG9DYW52YXMgPSBhc3luYyAoXG4gIGhlYWRlcnM6IHN0cmluZ1tdLFxuICByb3dzOiBzdHJpbmdbXVtdLFxuICBvcHRpb25zOiBDYW52YXNSZW5kZXJPcHRpb25zLFxuICBvdXRwdXRQYXRoOiBzdHJpbmdcbikgPT4ge1xuICBjb25zdCBjb25maWcgPSB7IC4uLmRlZmF1bHRDYW52YXNPcHRpb25zLCAuLi5vcHRpb25zIH07XG4gIC8vIEB0cy1leHBlY3QtZXJyb3IgY2FudmFzIGltcG9ydFxuICBsZXQgY3JlYXRlQ2FudmFzOiAodHlwZW9mIGltcG9ydChcImNhbnZhc1wiKSlbXCJjcmVhdGVDYW52YXNcIl07XG4gIHRyeSB7XG4gICAgLy8gQHRzLWV4cGVjdC1lcnJvciBiZWNhdXNlIHdlIGFsbG93IG9wdGlvbmFsIGRlcGVuZGVuY3lcbiAgICBjb25zdCBjYW52YXNNb2R1bGUgPSBhd2FpdCBpbXBvcnQoXCJjYW52YXNcIik7XG4gICAgY3JlYXRlQ2FudmFzID0gY2FudmFzTW9kdWxlLmNyZWF0ZUNhbnZhcztcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICBjb25zb2xlLndhcm4oXG4gICAgICBcIltQZXJmUnVubmVyXSBDYW52YXMgbW9kdWxlIG5vdCBhdmFpbGFibGUsIHNraXBwaW5nIGNoYXJ0LlwiLFxuICAgICAgZXJyb3JcbiAgICApO1xuICAgIHJldHVybjtcbiAgfVxuICBjb25zdCBjYW52YXMgPSBjcmVhdGVDYW52YXMoY29uZmlnLndpZHRoLCBjb25maWcuaGVpZ2h0KTtcbiAgY29uc3QgY3R4ID0gY2FudmFzLmdldENvbnRleHQoXCIyZFwiKTtcblxuICBjdHguZmlsbFN0eWxlID0gY29uZmlnLmJhY2tncm91bmRDb2xvcjtcbiAgY3R4LmZpbGxSZWN0KDAsIDAsIGNvbmZpZy53aWR0aCwgY29uZmlnLmhlaWdodCk7XG5cbiAgY3R4LmZvbnQgPSBjb25maWcuaGVhZGVyRm9udDtcbiAgY3R4LmZpbGxTdHlsZSA9IGNvbmZpZy5oZWFkZXJDb2xvcjtcbiAgY29uc3QgY29sdW1uV2lkdGggPSAoY29uZmlnLndpZHRoIC0gY29uZmlnLnBhZGRpbmcgKiAyKSAvIGhlYWRlcnMubGVuZ3RoO1xuICBjb25zdCBoZWFkZXJZID0gY29uZmlnLnBhZGRpbmcgKyAyNDtcblxuICBoZWFkZXJzLmZvckVhY2goKGhlYWRlciwgaW5kZXgpID0+IHtcbiAgICBjdHguZmlsbFRleHQoaGVhZGVyLCBjb25maWcucGFkZGluZyArIGNvbHVtbldpZHRoICogaW5kZXgsIGhlYWRlclkpO1xuICB9KTtcblxuICBjdHguZm9udCA9IGNvbmZpZy5yb3dGb250O1xuICBjdHguZmlsbFN0eWxlID0gY29uZmlnLnJvd0NvbG9yO1xuICBjb25zdCByb3dIZWlnaHQgPSAyNDtcbiAgcm93cy5mb3JFYWNoKChyb3csIHJvd0luZGV4KSA9PiB7XG4gICAgY29uc3QgeSA9IGhlYWRlclkgKyAxMiArIHJvd0hlaWdodCAqIChyb3dJbmRleCArIDEpO1xuICAgIHJvdy5mb3JFYWNoKChjZWxsLCBjZWxsSW5kZXgpID0+IHtcbiAgICAgIGN0eC5maWxsVGV4dChjZWxsLCBjb25maWcucGFkZGluZyArIGNvbHVtbldpZHRoICogY2VsbEluZGV4LCB5KTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgYXdhaXQgZW5zdXJlRGlyZWN0b3J5KG91dHB1dFBhdGgpO1xuICBhd2FpdCB3cml0ZUZpbGUob3V0cHV0UGF0aCwgY2FudmFzLnRvQnVmZmVyKFwiaW1hZ2UvcG5nXCIpKTtcbiAgY29uc29sZS5sb2coYFN0b3JlZCBwZXJmb3JtYW5jZSBjaGFydCBhdCAke291dHB1dFBhdGh9YCk7XG59O1xuXG5leHBvcnQgY2xhc3MgUGVyZm9ybWFuY2VSdW5uZXI8VENvbnRleHQgPSBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPj4ge1xuICBjb25zdHJ1Y3Rvcihwcm90ZWN0ZWQgcmVhZG9ubHkgc2NlbmFyaW86IFBlcmZvcm1hbmNlU2NlbmFyaW88VENvbnRleHQ+KSB7fVxuXG4gIHB1YmxpYyBhc3luYyBydW4oKTogUHJvbWlzZTxQaGFzZVJlc3VsdDxUQ29udGV4dD5bXT4ge1xuICAgIGlmICh0aGlzLnNjZW5hcmlvLmluaXRpYWxpemUpIHtcbiAgICAgIGF3YWl0IHRoaXMuc2NlbmFyaW8uaW5pdGlhbGl6ZSgpO1xuICAgIH1cblxuICAgIGxldCBwaGFzZUNvdW50ZXIgPSAwO1xuICAgIGNvbnN0IHF1ZXVlOiBQaGFzZVF1ZXVlSXRlbTxUQ29udGV4dD5bXSA9IHRoaXMuc2NlbmFyaW8ucGhhc2VzLm1hcChcbiAgICAgIChwaGFzZSkgPT4gKHsgcGhhc2UsIHBoYXNlTnVtYmVyOiArK3BoYXNlQ291bnRlciB9KVxuICAgICk7XG4gICAgY29uc3QgcmVzdWx0czogUGhhc2VSZXN1bHQ8VENvbnRleHQ+W10gPSBbXTtcblxuICAgIHdoaWxlIChxdWV1ZS5sZW5ndGgpIHtcbiAgICAgIGNvbnN0IGl0ZW0gPSBxdWV1ZS5zaGlmdCgpITtcbiAgICAgIGNvbnN0IHBoYXNlID0gaXRlbS5waGFzZTtcbiAgICAgIGNvbnN0IGNvbnRleHQgPSB0aGlzLm1lcmdlQ29udGV4dChwaGFzZSk7XG4gICAgICBjb25zb2xlLmluZm8oXG4gICAgICAgIGBbUGVyZlJ1bm5lcl0gU3RhcnRpbmcgcGhhc2UgIyR7aXRlbS5waGFzZU51bWJlcn0gXCIke3BoYXNlLm5hbWV9XCJgLFxuICAgICAgICB7XG4gICAgICAgICAgaXRlcmF0aW9uczogcGhhc2UuY29uZmlnLml0ZXJhdGlvbnMsXG4gICAgICAgICAgbW9kZTogcGhhc2UuY29uZmlnLm1vZGUsXG4gICAgICAgICAgY29uY3VycmVuY3k6IHBoYXNlLmNvbmZpZy5jb25jdXJyZW5jeSxcbiAgICAgICAgICBidXJzdDogcGhhc2UuY29uZmlnLmJ1cnN0LFxuICAgICAgICB9XG4gICAgICApO1xuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgdGhpcy5ydW5QaGFzZShwaGFzZSwgY29udGV4dCk7XG4gICAgICBjb25zb2xlLmluZm8oXG4gICAgICAgIGBbUGVyZlJ1bm5lcl0gQ29tcGxldGVkIHBoYXNlICMke2l0ZW0ucGhhc2VOdW1iZXJ9IFwiJHtwaGFzZS5uYW1lfVwiYCxcbiAgICAgICAge1xuICAgICAgICAgIHRvdGFsOiByZXN1bHQuYWdncmVnYXRlZC50b3RhbER1cmF0aW9uTXMudG9GaXhlZCgyKSxcbiAgICAgICAgICBhdmc6IHJlc3VsdC5hZ2dyZWdhdGVkLmF2ZXJhZ2VNcy50b0ZpeGVkKDIpLFxuICAgICAgICAgIGZhaWx1cmVDb3VudDogcmVzdWx0LmFnZ3JlZ2F0ZWQuZmFpbHVyZUNvdW50LFxuICAgICAgICB9XG4gICAgICApO1xuICAgICAgcmVzdWx0cy5wdXNoKHJlc3VsdCk7XG5cbiAgICAgIGlmIChwaGFzZS5nZW5lcmF0b3IpIHtcbiAgICAgICAgY29uc3QgaGlzdG9yeVNuYXBzaG90ID0gWy4uLnJlc3VsdHNdO1xuICAgICAgICBjb25zdCBtZXRhZGF0YTogUGhhc2VHZW5lcmF0b3JNZXRhZGF0YTxUQ29udGV4dD4gPSB7XG4gICAgICAgICAgcGhhc2VOdW1iZXI6IGl0ZW0ucGhhc2VOdW1iZXIsXG4gICAgICAgICAgcGhhc2VOYW1lOiBwaGFzZS5uYW1lLFxuICAgICAgICAgIGl0ZXJhdGlvbkNvdW50OiBwaGFzZS5jb25maWcuaXRlcmF0aW9ucyxcbiAgICAgICAgICBidXJzdFNlZ21lbnRzOiByZXN1bHQuc2VnbWVudENvdW50LFxuICAgICAgICAgIHNlZ21lbnRDb3VudDogcmVzdWx0LnNlZ21lbnRDb3VudCxcbiAgICAgICAgICBtb2RlOiBwaGFzZS5jb25maWcubW9kZSxcbiAgICAgICAgICBoaXN0b3J5OiBoaXN0b3J5U25hcHNob3QsXG4gICAgICAgIH07XG4gICAgICAgIGNvbnN0IGdlbmVyYXRvclJlc3VsdCA9IGF3YWl0IHBoYXNlLmdlbmVyYXRvcih7XG4gICAgICAgICAgcmVzdWx0LFxuICAgICAgICAgIGhpc3Rvcnk6IGhpc3RvcnlTbmFwc2hvdCxcbiAgICAgICAgICBtZXRhZGF0YSxcbiAgICAgICAgfSk7XG4gICAgICAgIGlmIChnZW5lcmF0b3JSZXN1bHQpIHtcbiAgICAgICAgICBjb25zdCBuZXh0UGhhc2U6IFBoYXNlPFRDb250ZXh0PiA9IChcbiAgICAgICAgICAgIFwiY29uZmlnXCIgaW4gZ2VuZXJhdG9yUmVzdWx0XG4gICAgICAgICAgICAgID8ge1xuICAgICAgICAgICAgICAgICAgbmFtZTogZ2VuZXJhdG9yUmVzdWx0Lm5hbWUgPz8gYCR7cGhhc2UubmFtZX0g4oaSIGdlbmAsXG4gICAgICAgICAgICAgICAgICBjb25maWc6IGdlbmVyYXRvclJlc3VsdC5jb25maWcsXG4gICAgICAgICAgICAgICAgICBnZW5lcmF0b3I6IHBoYXNlLmdlbmVyYXRvcixcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIDoge1xuICAgICAgICAgICAgICAgICAgbmFtZTogYCR7cGhhc2UubmFtZX0g4oaSIGdlbmAsXG4gICAgICAgICAgICAgICAgICBjb25maWc6IGdlbmVyYXRvclJlc3VsdCxcbiAgICAgICAgICAgICAgICAgIGdlbmVyYXRvcjogcGhhc2UuZ2VuZXJhdG9yLFxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICApIGFzIGFueTtcbiAgICAgICAgICBxdWV1ZS5wdXNoKHtcbiAgICAgICAgICAgIHBoYXNlOiBuZXh0UGhhc2UsXG4gICAgICAgICAgICBwaGFzZU51bWJlcjogKytwaGFzZUNvdW50ZXIsXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICBhd2FpdCB0aGlzLmxvZ1N1bW1hcnkocmVzdWx0cyk7XG4gICAgcmV0dXJuIHJlc3VsdHM7XG4gIH1cblxuICBwcm90ZWN0ZWQgYXN5bmMgcnVuUGhhc2UoXG4gICAgcGhhc2U6IFBoYXNlPFRDb250ZXh0PixcbiAgICBjb250ZXh0OiBUQ29udGV4dFxuICApOiBQcm9taXNlPFBoYXNlUmVzdWx0PFRDb250ZXh0Pj4ge1xuICAgIGF3YWl0IHRoaXMucnVuV2FybXVwKHBoYXNlLCBjb250ZXh0KTtcbiAgICBjb25zdCBzZWdtZW50cyA9IHRoaXMuYnVpbGRTZWdtZW50SW5kaWNlcyhcbiAgICAgIHBoYXNlLmNvbmZpZy5pdGVyYXRpb25zLFxuICAgICAgcGhhc2UuY29uZmlnLmJ1cnN0XG4gICAgKTtcbiAgICBjb25zdCBjb2xsZWN0ZWQ6IEl0ZXJhdGlvbk1ldHJpY1tdID0gW107XG5cbiAgICBmb3IgKFxuICAgICAgbGV0IHNlZ21lbnRJbmRleCA9IDA7XG4gICAgICBzZWdtZW50SW5kZXggPCBzZWdtZW50cy5sZW5ndGg7XG4gICAgICBzZWdtZW50SW5kZXggKz0gMVxuICAgICkge1xuICAgICAgY29uc3QgaW5kaWNlcyA9IHNlZ21lbnRzW3NlZ21lbnRJbmRleF07XG4gICAgICBpZiAoIWluZGljZXMubGVuZ3RoKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuXG4gICAgICBkZWJ1Z0xvZyhcbiAgICAgICAgYFtQZXJmUnVubmVyXSBQaGFzZSBcIiR7cGhhc2UubmFtZX1cIiBleGVjdXRpbmcgc2VnbWVudCAke3NlZ21lbnRJbmRleCArIDF9LyR7XG4gICAgICAgICAgc2VnbWVudHMubGVuZ3RoXG4gICAgICAgIH0gKGl0ZXJhdGlvbnMgJHtpbmRpY2VzWzBdfS0ke2luZGljZXNbaW5kaWNlcy5sZW5ndGggLSAxXX0pYFxuICAgICAgKTtcblxuICAgICAgY29uc3QgbWV0cmljcyA9IGF3YWl0IHRoaXMuZXhlY3V0ZVNlZ21lbnQoXG4gICAgICAgIHRoaXMuc2NlbmFyaW8uaGFuZGxlcixcbiAgICAgICAgcGhhc2UuY29uZmlnLFxuICAgICAgICBjb250ZXh0LFxuICAgICAgICBpbmRpY2VzXG4gICAgICApO1xuICAgICAgY29sbGVjdGVkLnB1c2goLi4ubWV0cmljcyk7XG5cbiAgICAgIGNvbnN0IGJ1cnN0SW50ZXJ2YWwgPSBwaGFzZS5jb25maWcuYnVyc3Q/LmludGVydmFsTXM7XG4gICAgICBpZiAoYnVyc3RJbnRlcnZhbCAmJiBzZWdtZW50SW5kZXggPCBzZWdtZW50cy5sZW5ndGggLSAxKSB7XG4gICAgICAgIGF3YWl0IGRlbGF5KGJ1cnN0SW50ZXJ2YWwpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGNvbnN0IHNvcnRlZCA9IFsuLi5jb2xsZWN0ZWRdLnNvcnQoKGEsIGIpID0+IGEuaXRlcmF0aW9uIC0gYi5pdGVyYXRpb24pO1xuICAgIGNvbnN0IGFnZ3JlZ2F0ZWQgPSB0aGlzLmFnZ3JlZ2F0ZU1ldHJpY3Moc29ydGVkKTtcblxuICAgIGlmIChwaGFzZS5jb25maWcucGF1c2VBZnRlck1zKSB7XG4gICAgICBhd2FpdCBkZWxheShwaGFzZS5jb25maWcucGF1c2VBZnRlck1zKTtcbiAgICB9XG5cbiAgICBpZiAoYWdncmVnYXRlZC5mYWlsdXJlQ291bnQgPiAwICYmIHRoaXMuc2NlbmFyaW8uZmFpbE9uRXJyb3IgIT09IGZhbHNlKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBQaGFzZSAke3BoYXNlLm5hbWV9IHJlY29yZGVkICR7YWdncmVnYXRlZC5mYWlsdXJlQ291bnR9IGZhaWx1cmVzYFxuICAgICAgKTtcbiAgICB9XG5cbiAgICByZXR1cm4ge1xuICAgICAgcGhhc2UsXG4gICAgICBjb25maWc6IHBoYXNlLmNvbmZpZyxcbiAgICAgIGl0ZXJhdGlvbk1ldHJpY3M6IHNvcnRlZCxcbiAgICAgIGFnZ3JlZ2F0ZWQsXG4gICAgICBjb250ZXh0LFxuICAgICAgc2VnbWVudENvdW50OiBzZWdtZW50cy5sZW5ndGgsXG4gICAgfTtcbiAgfVxuXG4gIHByb3RlY3RlZCBhc3luYyBydW5XYXJtdXAoXG4gICAgcGhhc2U6IFBoYXNlPFRDb250ZXh0PixcbiAgICBjb250ZXh0OiBUQ29udGV4dFxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCB3YXJtdXAgPSBwaGFzZS5jb25maWcud2FybXVwO1xuICAgIGlmICghd2FybXVwPy5pdGVyYXRpb25zKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgaGFuZGxlciA9IHdhcm11cC5oYW5kbGVyID8/IHRoaXMuc2NlbmFyaW8uaGFuZGxlcjtcbiAgICBmb3IgKGxldCBpbmRleCA9IDA7IGluZGV4IDwgd2FybXVwLml0ZXJhdGlvbnM7IGluZGV4ICs9IDEpIHtcbiAgICAgIGF3YWl0IGhhbmRsZXIoe1xuICAgICAgICBpdGVyYXRpb246IGluZGV4LFxuICAgICAgICBjb25maWc6IHBoYXNlLmNvbmZpZyxcbiAgICAgICAgbG9hZEZhY3RvcjogdGhpcy5jb21wdXRlTG9hZEZhY3RvcihwaGFzZS5jb25maWcsIGluZGV4KSxcbiAgICAgICAgY29udGV4dCxcbiAgICAgIH0pO1xuICAgICAgaWYgKHdhcm11cC5kZWxheUJldHdlZW5JdGVyYXRpb25zTXMgJiYgaW5kZXggPCB3YXJtdXAuaXRlcmF0aW9ucyAtIDEpIHtcbiAgICAgICAgYXdhaXQgZGVsYXkod2FybXVwLmRlbGF5QmV0d2Vlbkl0ZXJhdGlvbnNNcyk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcHJvdGVjdGVkIGNvbXB1dGVMb2FkRmFjdG9yKFxuICAgIGNvbmZpZzogUGhhc2VDb25maWc8VENvbnRleHQ+LFxuICAgIGl0ZXJhdGlvbjogbnVtYmVyXG4gICk6IG51bWJlciB7XG4gICAgY29uc3QgYmFzZSA9IGNvbmZpZy5sb2FkU3RhcnQgPz8gMTtcbiAgICBjb25zdCBzdGVwID0gY29uZmlnLmxvYWRTdGVwID8/IDA7XG4gICAgY29uc3QgbXVsdGlwbGllciA9IGNvbmZpZy5sb2FkTXVsdGlwbGllciA/PyAxO1xuICAgIHJldHVybiAoYmFzZSArIHN0ZXAgKiBpdGVyYXRpb24pICogbXVsdGlwbGllcjtcbiAgfVxuXG4gIHByb3RlY3RlZCBidWlsZFNlZ21lbnRJbmRpY2VzKFxuICAgIGl0ZXJhdGlvbnM6IG51bWJlcixcbiAgICBidXJzdD86IFBoYXNlQnVyc3RDb25maWdcbiAgKTogbnVtYmVyW11bXSB7XG4gICAgY29uc3QgdG90YWwgPSBNYXRoLm1heCgwLCBpdGVyYXRpb25zKTtcbiAgICBpZiAodG90YWwgPT09IDApIHtcbiAgICAgIHJldHVybiBbXTtcbiAgICB9XG5cbiAgICBjb25zdCBjaHVuayA9XG4gICAgICBidXJzdD8uc2l6ZSAmJiBidXJzdC5zaXplID4gMCA/IE1hdGgubWluKGJ1cnN0LnNpemUsIHRvdGFsKSA6IHRvdGFsO1xuICAgIGNvbnN0IHNlZ21lbnRzOiBudW1iZXJbXVtdID0gW107XG5cbiAgICBmb3IgKGxldCBjdXJzb3IgPSAwOyBjdXJzb3IgPCB0b3RhbDsgY3Vyc29yICs9IGNodW5rKSB7XG4gICAgICBjb25zdCBlbmQgPSBNYXRoLm1pbih0b3RhbCwgY3Vyc29yICsgY2h1bmspO1xuICAgICAgc2VnbWVudHMucHVzaChcbiAgICAgICAgQXJyYXkuZnJvbSh7IGxlbmd0aDogZW5kIC0gY3Vyc29yIH0sIChfLCBpZHgpID0+IGN1cnNvciArIGlkeClcbiAgICAgICk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHNlZ21lbnRzO1xuICB9XG5cbiAgcHJvdGVjdGVkIG1lcmdlQ29udGV4dChwaGFzZTogUGhhc2U8VENvbnRleHQ+KTogVENvbnRleHQge1xuICAgIGNvbnN0IGJhc2VDb250ZXh0ID0gdGhpcy5zY2VuYXJpby5iYXNlQ29udGV4dCA/PyAoe30gYXMgVENvbnRleHQpO1xuICAgIGNvbnN0IHBoYXNlQ29udGV4dCA9IHBoYXNlLmNvbmZpZy5jb250ZXh0ID8/ICh7fSBhcyBUQ29udGV4dCk7XG4gICAgcmV0dXJuIHRoaXMubWVyZ2VDb250ZXh0cyhiYXNlQ29udGV4dCwgcGhhc2VDb250ZXh0KTtcbiAgfVxuXG4gIHByb3RlY3RlZCBtZXJnZUNvbnRleHRzKGE6IFRDb250ZXh0LCBiOiBQYXJ0aWFsPFRDb250ZXh0Pik6IFRDb250ZXh0IHtcbiAgICByZXR1cm4gT2JqZWN0LmFzc2lnbih7fSwgYSwgYik7XG4gIH1cblxuICBwcm90ZWN0ZWQgYXN5bmMgZXhlY3V0ZVNlZ21lbnQoXG4gICAgaGFuZGxlcjogUGVyZm9ybWFuY2VIYW5kbGVyPFRDb250ZXh0PixcbiAgICBjb25maWc6IFBoYXNlQ29uZmlnPFRDb250ZXh0PixcbiAgICBjb250ZXh0OiBUQ29udGV4dCxcbiAgICBpbmRpY2VzOiBudW1iZXJbXVxuICApOiBQcm9taXNlPEl0ZXJhdGlvbk1ldHJpY1tdPiB7XG4gICAgaWYgKCFpbmRpY2VzLmxlbmd0aCkge1xuICAgICAgcmV0dXJuIFtdO1xuICAgIH1cblxuICAgIGlmIChjb25maWcubW9kZSA9PT0gXCJjb25jdXJyZW50XCIpIHtcbiAgICAgIHJldHVybiB0aGlzLmNvbGxlY3RDb25jdXJyZW50KGhhbmRsZXIsIGNvbmZpZywgY29udGV4dCwgaW5kaWNlcyk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMuY29sbGVjdFNlcXVlbnRpYWwoaGFuZGxlciwgY29uZmlnLCBjb250ZXh0LCBpbmRpY2VzKTtcbiAgfVxuXG4gIHByb3RlY3RlZCBhc3luYyBjb2xsZWN0U2VxdWVudGlhbChcbiAgICBoYW5kbGVyOiBQZXJmb3JtYW5jZUhhbmRsZXI8VENvbnRleHQ+LFxuICAgIGNvbmZpZzogUGhhc2VDb25maWc8VENvbnRleHQ+LFxuICAgIGNvbnRleHQ6IFRDb250ZXh0LFxuICAgIGluZGljZXM6IG51bWJlcltdXG4gICk6IFByb21pc2U8SXRlcmF0aW9uTWV0cmljW10+IHtcbiAgICBjb25zdCBtZXRyaWNzOiBJdGVyYXRpb25NZXRyaWNbXSA9IFtdO1xuICAgIGNvbnN0IGRlbGF5QmV0d2VlbiA9IGNvbmZpZy5kZWxheUJldHdlZW5JdGVyYXRpb25zTXM7XG5cbiAgICBmb3IgKGxldCBpZHggPSAwOyBpZHggPCBpbmRpY2VzLmxlbmd0aDsgaWR4ICs9IDEpIHtcbiAgICAgIG1ldHJpY3MucHVzaChcbiAgICAgICAgYXdhaXQgdGhpcy5ydW5JdGVyYXRpb24oaGFuZGxlciwgY29uZmlnLCBjb250ZXh0LCBpbmRpY2VzW2lkeF0pXG4gICAgICApO1xuICAgICAgaWYgKGRlbGF5QmV0d2VlbiAmJiBpZHggPCBpbmRpY2VzLmxlbmd0aCAtIDEpIHtcbiAgICAgICAgYXdhaXQgZGVsYXkoZGVsYXlCZXR3ZWVuKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gbWV0cmljcztcbiAgfVxuXG4gIHByb3RlY3RlZCBhc3luYyBjb2xsZWN0Q29uY3VycmVudChcbiAgICBoYW5kbGVyOiBQZXJmb3JtYW5jZUhhbmRsZXI8VENvbnRleHQ+LFxuICAgIGNvbmZpZzogUGhhc2VDb25maWc8VENvbnRleHQ+LFxuICAgIGNvbnRleHQ6IFRDb250ZXh0LFxuICAgIGluZGljZXM6IG51bWJlcltdXG4gICk6IFByb21pc2U8SXRlcmF0aW9uTWV0cmljW10+IHtcbiAgICBjb25zdCBjb25jdXJyZW5jeSA9IE1hdGgubWF4KFxuICAgICAgMSxcbiAgICAgIE1hdGgubWluKGNvbmZpZy5jb25jdXJyZW5jeSA/PyBpbmRpY2VzLmxlbmd0aCwgaW5kaWNlcy5sZW5ndGgpXG4gICAgKTtcbiAgICBjb25zdCBtZXRyaWNzOiBJdGVyYXRpb25NZXRyaWNbXSA9IFtdO1xuICAgIGxldCBwb2ludGVyID0gMDtcblxuICAgIGNvbnN0IHdvcmtlciA9IGFzeW5jICgpID0+IHtcbiAgICAgIHdoaWxlIChwb2ludGVyIDwgaW5kaWNlcy5sZW5ndGgpIHtcbiAgICAgICAgY29uc3QgaXRlcmF0aW9uID0gaW5kaWNlc1twb2ludGVyXTtcbiAgICAgICAgcG9pbnRlciArPSAxO1xuICAgICAgICBtZXRyaWNzLnB1c2goXG4gICAgICAgICAgYXdhaXQgdGhpcy5ydW5JdGVyYXRpb24oaGFuZGxlciwgY29uZmlnLCBjb250ZXh0LCBpdGVyYXRpb24pXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfTtcblxuICAgIGF3YWl0IFByb21pc2UuYWxsKEFycmF5LmZyb20oeyBsZW5ndGg6IGNvbmN1cnJlbmN5IH0sICgpID0+IHdvcmtlcigpKSk7XG4gICAgcmV0dXJuIG1ldHJpY3M7XG4gIH1cblxuICBwcm90ZWN0ZWQgYXN5bmMgcnVuSXRlcmF0aW9uKFxuICAgIGhhbmRsZXI6IFBlcmZvcm1hbmNlSGFuZGxlcjxUQ29udGV4dD4sXG4gICAgY29uZmlnOiBQaGFzZUNvbmZpZzxUQ29udGV4dD4sXG4gICAgY29udGV4dDogVENvbnRleHQsXG4gICAgaXRlcmF0aW9uOiBudW1iZXJcbiAgKTogUHJvbWlzZTxJdGVyYXRpb25NZXRyaWM+IHtcbiAgICBjb25zdCBsb2FkRmFjdG9yID0gdGhpcy5jb21wdXRlTG9hZEZhY3Rvcihjb25maWcsIGl0ZXJhdGlvbik7XG4gICAgY29uc3Qgc3RvcHdhdGNoID0gbmV3IFN0b3BXYXRjaCh0cnVlKTtcbiAgICBsZXQgc3VjY2VzcyA9IHRydWU7XG4gICAgbGV0IG1ldGE6IFJlY29yZDxzdHJpbmcsIHVua25vd24+IHwgdW5kZWZpbmVkO1xuXG4gICAgZGVidWdMb2coXG4gICAgICBgW1BlcmZSdW5uZXJdIEl0ZXJhdGlvbiAke2l0ZXJhdGlvbn0gKHBoYXNlPSR7Y29uZmlnLm1ldGFkYXRhPy5waGFzZU5hbWUgPz8gXCJuL2FcIn0sIGxvYWQ9JHtsb2FkRmFjdG9yLnRvRml4ZWQoXG4gICAgICAgIDJcbiAgICAgICl9KSBzdGFydGluZ2BcbiAgICApO1xuICAgIHRyeSB7XG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBoYW5kbGVyKHsgaXRlcmF0aW9uLCBjb25maWcsIGxvYWRGYWN0b3IsIGNvbnRleHQgfSk7XG4gICAgICBpZiAodHlwZW9mIHJlc3VsdD8uc3VjY2VzcyA9PT0gXCJib29sZWFuXCIpIHtcbiAgICAgICAgc3VjY2VzcyA9IHJlc3VsdC5zdWNjZXNzO1xuICAgICAgfVxuICAgICAgbWV0YSA9IHJlc3VsdD8ubWV0YTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgc3VjY2VzcyA9IGZhbHNlO1xuICAgICAgbWV0YSA9IHsgZXJyb3I6IGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKSB9O1xuICAgIH1cblxuICAgIGNvbnN0IGR1cmF0aW9uTXMgPSBzdG9wd2F0Y2guc3RvcCgpO1xuICAgIGRlYnVnTG9nKFxuICAgICAgYFtQZXJmUnVubmVyXSBJdGVyYXRpb24gJHtpdGVyYXRpb259IGNvbXBsZXRlIGluICR7ZHVyYXRpb25Ncy50b0ZpeGVkKDIpfW1zLCBzdWNjZXNzPSR7c3VjY2Vzc31gXG4gICAgKTtcbiAgICByZXR1cm4geyBpdGVyYXRpb24sIGR1cmF0aW9uTXMsIHN1Y2Nlc3MsIG1ldGEsIGxvYWRGYWN0b3IgfTtcbiAgfVxuXG4gIHByb3RlY3RlZCBhZ2dyZWdhdGVNZXRyaWNzKG1ldHJpY3M6IEl0ZXJhdGlvbk1ldHJpY1tdKTogQWdncmVnYXRlZE1ldHJpY3Mge1xuICAgIGlmIChtZXRyaWNzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgdG90YWxEdXJhdGlvbk1zOiAwLFxuICAgICAgICBtaW5NczogMCxcbiAgICAgICAgbWF4TXM6IDAsXG4gICAgICAgIGF2ZXJhZ2VNczogMCxcbiAgICAgICAgc3VjY2Vzc0NvdW50OiAwLFxuICAgICAgICBmYWlsdXJlQ291bnQ6IDAsXG4gICAgICAgIGxvYWRTdGFydDogMCxcbiAgICAgICAgbG9hZEVuZDogMCxcbiAgICAgIH07XG4gICAgfVxuXG4gICAgY29uc3QgdG90YWxEdXJhdGlvbk1zID0gbWV0cmljcy5yZWR1Y2UoXG4gICAgICAoYWNjLCBtZXRyaWMpID0+IGFjYyArIG1ldHJpYy5kdXJhdGlvbk1zLFxuICAgICAgMFxuICAgICk7XG4gICAgY29uc3QgbWluTXMgPSBNYXRoLm1pbiguLi5tZXRyaWNzLm1hcCgobWV0cmljKSA9PiBtZXRyaWMuZHVyYXRpb25NcykpO1xuICAgIGNvbnN0IG1heE1zID0gTWF0aC5tYXgoLi4ubWV0cmljcy5tYXAoKG1ldHJpYykgPT4gbWV0cmljLmR1cmF0aW9uTXMpKTtcbiAgICBjb25zdCBhdmVyYWdlTXMgPSB0b3RhbER1cmF0aW9uTXMgLyBtZXRyaWNzLmxlbmd0aDtcbiAgICBjb25zdCBzdWNjZXNzQ291bnQgPSBtZXRyaWNzLmZpbHRlcigobWV0cmljKSA9PiBtZXRyaWMuc3VjY2VzcykubGVuZ3RoO1xuICAgIGNvbnN0IGZhaWx1cmVDb3VudCA9IG1ldHJpY3MubGVuZ3RoIC0gc3VjY2Vzc0NvdW50O1xuICAgIGNvbnN0IGxvYWRTdGFydCA9IG1ldHJpY3NbMF0/LmxvYWRGYWN0b3IgPz8gMDtcbiAgICBjb25zdCBsb2FkRW5kID0gbWV0cmljc1ttZXRyaWNzLmxlbmd0aCAtIDFdPy5sb2FkRmFjdG9yID8/IGxvYWRTdGFydDtcblxuICAgIHJldHVybiB7XG4gICAgICB0b3RhbER1cmF0aW9uTXMsXG4gICAgICBtaW5NcyxcbiAgICAgIG1heE1zLFxuICAgICAgYXZlcmFnZU1zLFxuICAgICAgc3VjY2Vzc0NvdW50LFxuICAgICAgZmFpbHVyZUNvdW50LFxuICAgICAgbG9hZFN0YXJ0LFxuICAgICAgbG9hZEVuZCxcbiAgICB9O1xuICB9XG5cbiAgcHJvdGVjdGVkIGFzeW5jIGxvZ1N1bW1hcnkocmVzdWx0czogUGhhc2VSZXN1bHQ8VENvbnRleHQ+W10pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAoIXJlc3VsdHMubGVuZ3RoKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgaGVhZGVycyA9IFtcbiAgICAgIFwiUGhhc2VcIixcbiAgICAgIFwiTW9kZVwiLFxuICAgICAgXCJJdGVyYXRpb25zXCIsXG4gICAgICBcIlRvdGFsIG1zXCIsXG4gICAgICBcIkF2ZyBtc1wiLFxuICAgICAgXCJNaW4gbXNcIixcbiAgICAgIFwiTWF4IG1zXCIsXG4gICAgICBcIlN1Y2Nlc3NcIixcbiAgICAgIFwiRmFpbHVyZXNcIixcbiAgICAgIFwiTG9hZCByYW5nZVwiLFxuICAgIF07XG5cbiAgICBjb25zdCByb3dzID0gcmVzdWx0cy5tYXAoKHJlc3VsdCkgPT4gW1xuICAgICAgcmVzdWx0LnBoYXNlLm5hbWUsXG4gICAgICByZXN1bHQuY29uZmlnLm1vZGUsXG4gICAgICByZXN1bHQuY29uZmlnLml0ZXJhdGlvbnMudG9TdHJpbmcoKSxcbiAgICAgIHJlc3VsdC5hZ2dyZWdhdGVkLnRvdGFsRHVyYXRpb25Ncy50b0ZpeGVkKDIpLFxuICAgICAgcmVzdWx0LmFnZ3JlZ2F0ZWQuYXZlcmFnZU1zLnRvRml4ZWQoMiksXG4gICAgICByZXN1bHQuYWdncmVnYXRlZC5taW5Ncy50b0ZpeGVkKDIpLFxuICAgICAgcmVzdWx0LmFnZ3JlZ2F0ZWQubWF4TXMudG9GaXhlZCgyKSxcbiAgICAgIHJlc3VsdC5hZ2dyZWdhdGVkLnN1Y2Nlc3NDb3VudC50b1N0cmluZygpLFxuICAgICAgcmVzdWx0LmFnZ3JlZ2F0ZWQuZmFpbHVyZUNvdW50LnRvU3RyaW5nKCksXG4gICAgICBgJHtyZXN1bHQuYWdncmVnYXRlZC5sb2FkU3RhcnQudG9GaXhlZCgyKX0g4oaSICR7cmVzdWx0LmFnZ3JlZ2F0ZWQubG9hZEVuZC50b0ZpeGVkKDIpfWAsXG4gICAgXSk7XG5cbiAgICBjb25zb2xlLmxvZyhcbiAgICAgIGZvcm1hdFRhYmxlKFxuICAgICAgICBgUGVyZm9ybWFuY2Ugc3VtbWFyeSBmb3IgJHt0aGlzLnNjZW5hcmlvLm5hbWV9YCxcbiAgICAgICAgaGVhZGVycyxcbiAgICAgICAgcm93c1xuICAgICAgKVxuICAgICk7XG5cbiAgICBpZiAodGhpcy5zaG91bGRSZW5kZXJDYW52YXMoKSkge1xuICAgICAgY29uc3QgY2hhcnRQYXRoID1cbiAgICAgICAgdGhpcy5zY2VuYXJpby5jYW52YXNPdXRwdXRQYXRoID8/XG4gICAgICAgIHBhdGguam9pbihcbiAgICAgICAgICBwcm9jZXNzLmN3ZCgpLFxuICAgICAgICAgIFwid29ya2RvY3NcIixcbiAgICAgICAgICBcInJlcG9ydHNcIixcbiAgICAgICAgICBcInBlcmZvcm1hbmNlLXJ1bm5lci5wbmdcIlxuICAgICAgICApO1xuICAgICAgYXdhaXQgcmVuZGVyTWV0cmljc1RhYmxlVG9DYW52YXMoXG4gICAgICAgIGhlYWRlcnMsXG4gICAgICAgIHJvd3MsXG4gICAgICAgIHRoaXMuc2NlbmFyaW8uY2FudmFzT3B0aW9ucyA/PyBkZWZhdWx0Q2FudmFzT3B0aW9ucyxcbiAgICAgICAgY2hhcnRQYXRoXG4gICAgICApO1xuICAgIH1cbiAgfVxuXG4gIHByb3RlY3RlZCBzaG91bGRSZW5kZXJDYW52YXMoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuc2NlbmFyaW8uZW5hYmxlQ2FudmFzID8/IEJvb2xlYW4odGhpcy5zY2VuYXJpby5jYW52YXNPcHRpb25zKTtcbiAgfVxufVxuIiwiaW1wb3J0IHsgQ29tbWFuZCB9IGZyb20gXCIuLi9jb21tYW5kXCI7XG5pbXBvcnQgeyBDb21tYW5kT3B0aW9ucyB9IGZyb20gXCIuLi90eXBlc1wiO1xuaW1wb3J0IHsgRGVmYXVsdENvbW1hbmRPcHRpb25zLCBEZWZhdWx0Q29tbWFuZFZhbHVlcyB9IGZyb20gXCIuLi9jb25zdGFudHNcIjtcbmltcG9ydCB7XG4gIGNvcHlGaWxlLFxuICBkZWxldGVQYXRoLFxuICBnZXRBbGxGaWxlcyxcbiAgZ2V0UGFja2FnZSxcbiAgcGF0Y2hGaWxlLFxuICByZW5hbWVGaWxlLFxuICBydW5Db21tYW5kLFxuICBnZXRGaWxlU2l6ZVppcHBlZCxcbiAgbGlzdE5vZGVNb2R1bGVzUGFja2FnZXMsXG59IGZyb20gXCIuLi8uLi91dGlsc1wiO1xuaW1wb3J0IGZzIGZyb20gXCJmc1wiO1xuaW1wb3J0IHBhdGggZnJvbSBcInBhdGhcIjtcbmltcG9ydCB7IElucHV0T3B0aW9ucywgT3V0cHV0T3B0aW9ucywgcm9sbHVwLCBSb2xsdXBCdWlsZCB9IGZyb20gXCJyb2xsdXBcIjtcbmltcG9ydCB0eXBlc2NyaXB0IGZyb20gXCJAcm9sbHVwL3BsdWdpbi10eXBlc2NyaXB0XCI7XG5pbXBvcnQgY29tbW9uanMgZnJvbSBcIkByb2xsdXAvcGx1Z2luLWNvbW1vbmpzXCI7XG5pbXBvcnQgeyBub2RlUmVzb2x2ZSB9IGZyb20gXCJAcm9sbHVwL3BsdWdpbi1ub2RlLXJlc29sdmVcIjtcbmltcG9ydCBqc29uIGZyb20gXCJAcm9sbHVwL3BsdWdpbi1qc29uXCI7XG5pbXBvcnQgeyBidWlsdGluTW9kdWxlcyB9IGZyb20gXCJtb2R1bGVcIjtcbmltcG9ydCB7IExvZ2dpbmdDb25maWcsIExvZ0xldmVsIH0gZnJvbSBcIkBkZWNhZi10cy9sb2dnaW5nXCI7XG5cbi8vIGRlY2xhcmUgb3B0aW9uYWwgdGVyc2VyIG1vZHVsZSB0byBzYXRpc2Z5IFR5cGVTY3JpcHQgd2hlbiB0eXBlcyBhcmVuJ3QgaW5zdGFsbGVkXG5kZWNsYXJlIG1vZHVsZSBcIkByb2xsdXAvcGx1Z2luLXRlcnNlclwiO1xuXG5pbXBvcnQgKiBhcyB0cyBmcm9tIFwidHlwZXNjcmlwdFwiO1xuaW1wb3J0IHsgRGlhZ25vc3RpYywgRW1pdFJlc3VsdCwgTW9kdWxlS2luZCwgU291cmNlRmlsZSB9IGZyb20gXCJ0eXBlc2NyaXB0XCI7XG5cbmV4cG9ydCBmdW5jdGlvbiBwYXJzZUxpc3QoaW5wdXQ/OiBzdHJpbmcgfCBzdHJpbmdbXSk6IHN0cmluZ1tdIHtcbiAgaWYgKCFpbnB1dCkgcmV0dXJuIFtdO1xuICBpZiAoQXJyYXkuaXNBcnJheShpbnB1dCkpXG4gICAgcmV0dXJuIGlucHV0Lm1hcCgoaSkgPT4gYCR7aX1gLnRyaW0oKSkuZmlsdGVyKEJvb2xlYW4pO1xuICByZXR1cm4gYCR7aW5wdXR9YFxuICAgIC5zcGxpdChcIixcIilcbiAgICAubWFwKChwKSA9PiBwLnRyaW0oKSlcbiAgICAuZmlsdGVyKEJvb2xlYW4pO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcGFja2FnZVRvR2xvYmFsKG5hbWU6IHN0cmluZyk6IHN0cmluZyB7XG4gIC8vIFJlbW92ZSBzY29wZSBhbmQgc3BsaXQgYnkgbm9uLWFscGhhbnVtZXJpYyBjaGFycywgdGhlbiBjYW1lbENhc2VcbiAgY29uc3Qgd2l0aG91dFNjb3BlID0gbmFtZS5yZXBsYWNlKC9eQC8sIFwiXCIpO1xuICBjb25zdCBwYXJ0cyA9IHdpdGhvdXRTY29wZS5zcGxpdCgvWy9cXC1fLl0rLykuZmlsdGVyKEJvb2xlYW4pO1xuICByZXR1cm4gcGFydHNcbiAgICAubWFwKChwLCBpKSA9PlxuICAgICAgaSA9PT0gMFxuICAgICAgICA/IHAucmVwbGFjZSgvW15hLXpBLVowLTldL2csIFwiXCIpXG4gICAgICAgIDogYCR7cC5jaGFyQXQoMCkudG9VcHBlckNhc2UoKX0ke3Auc2xpY2UoMSl9YFxuICAgIClcbiAgICAuam9pbihcIlwiKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldFBhY2thZ2VEZXBlbmRlbmNpZXMoKTogc3RyaW5nW10ge1xuICAvLyBUcnkgdGhlIGN1cnJlbnQgd29ya2luZyBkaXJlY3RvcnkgZmlyc3RcbiAgbGV0IHBrZzogYW55O1xuICB0cnkge1xuICAgIHBrZyA9IGdldFBhY2thZ2UocHJvY2Vzcy5jd2QoKSkgYXMgYW55O1xuICB9IGNhdGNoIHtcbiAgICBwa2cgPSB1bmRlZmluZWQ7XG4gIH1cblxuICAvLyBJZiBubyBkZXBlbmRlbmNpZXMgZm91bmQgaW4gY3dkLCB0cnkgdGhlIHBhY2thZ2UgbmV4dCB0byB0aGlzIHNvdXJjZSBmaWxlIChmYWxsYmFjayBmb3IgdGVzdHMpXG4gIHRyeSB7XG4gICAgY29uc3QgaGFzRGVwcyA9XG4gICAgICBwa2cgJiZcbiAgICAgIChPYmplY3Qua2V5cyhwa2cuZGVwZW5kZW5jaWVzIHx8IHt9KS5sZW5ndGggPiAwIHx8XG4gICAgICAgIE9iamVjdC5rZXlzKHBrZy5kZXZEZXBlbmRlbmNpZXMgfHwge30pLmxlbmd0aCA+IDAgfHxcbiAgICAgICAgT2JqZWN0LmtleXMocGtnLnBlZXJEZXBlbmRlbmNpZXMgfHwge30pLmxlbmd0aCA+IDApO1xuICAgIGlmICghaGFzRGVwcykge1xuICAgICAgY29uc3QgZmFsbGJhY2tEaXIgPSBwYXRoLnJlc29sdmUoX19kaXJuYW1lLCBcIi4uLy4uLy4uXCIpO1xuICAgICAgdHJ5IHtcbiAgICAgICAgcGtnID0gZ2V0UGFja2FnZShmYWxsYmFja0RpcikgYXMgYW55O1xuICAgICAgfSBjYXRjaCB7XG4gICAgICAgIC8vIGlnbm9yZSBhbmQga2VlcCBwa2cgYXMtaXNcbiAgICAgIH1cbiAgICB9XG4gIH0gY2F0Y2gge1xuICAgIC8vIGlnbm9yZVxuICB9XG5cbiAgY29uc3QgZGVwcyA9IE9iamVjdC5rZXlzKChwa2cgJiYgcGtnLmRlcGVuZGVuY2llcykgfHwge30pO1xuICBjb25zdCBwZWVyID0gT2JqZWN0LmtleXMoKHBrZyAmJiBwa2cucGVlckRlcGVuZGVuY2llcykgfHwge30pO1xuICBjb25zdCBkZXYgPSBPYmplY3Qua2V5cygocGtnICYmIHBrZy5kZXZEZXBlbmRlbmNpZXMpIHx8IHt9KTtcbiAgcmV0dXJuIEFycmF5LmZyb20obmV3IFNldChbLi4uZGVwcywgLi4ucGVlciwgLi4uZGV2XSkpO1xufVxuXG5jb25zdCBWRVJTSU9OX1NUUklORyA9IFwiIyNWRVJTSU9OIyNcIjtcbmNvbnN0IFBBQ0tBR0VfU1RSSU5HID0gXCIjI1BBQ0tBR0UjI1wiO1xuY29uc3QgUEFDS0FHRV9TSVpFX1NUUklORyA9IFwiIyNQQUNLQUdFX1NJWkUjI1wiO1xuXG5lbnVtIE1vZGVzIHtcbiAgQ0pTID0gXCJjb21tb25qc1wiLFxuICBFU00gPSBcImVzMjAyMlwiLFxufVxuXG5lbnVtIEJ1aWxkTW9kZSB7XG4gIEJVSUxEID0gXCJidWlsZFwiLFxuICBCVU5ETEUgPSBcImJ1bmRsZVwiLFxuICBBTEwgPSBcImFsbFwiLFxufVxuXG5jb25zdCBvcHRpb25zID0ge1xuICBwcm9kOiB7XG4gICAgdHlwZTogXCJib29sZWFuXCIsXG4gICAgZGVmYXVsdDogZmFsc2UsXG4gIH0sXG4gIGRldjoge1xuICAgIHR5cGU6IFwiYm9vbGVhblwiLFxuICAgIGRlZmF1bHQ6IGZhbHNlLFxuICB9LFxuICBidWlsZE1vZGU6IHtcbiAgICB0eXBlOiBcInN0cmluZ1wiLFxuICAgIGRlZmF1bHQ6IEJ1aWxkTW9kZS5BTEwsXG4gIH0sXG4gIGluY2x1ZGVzOiB7XG4gICAgdHlwZTogXCJzdHJpbmdcIixcbiAgICBkZWZhdWx0OiBcIlwiLFxuICB9LFxuICBleHRlcm5hbHM6IHtcbiAgICB0eXBlOiBcInN0cmluZ1wiLFxuICAgIGRlZmF1bHQ6IFwiXCIsXG4gIH0sXG4gIGRvY3M6IHtcbiAgICB0eXBlOiBcImJvb2xlYW5cIixcbiAgICBkZWZhdWx0OiBmYWxzZSxcbiAgfSxcbiAgY29tbWFuZHM6IHtcbiAgICB0eXBlOiBcImJvb2xlYW5cIixcbiAgICBkZWZhdWx0OiBmYWxzZSxcbiAgfSxcbiAgZW50cnk6IHtcbiAgICB0eXBlOiBcInN0cmluZ1wiLFxuICAgIGRlZmF1bHQ6IFwiLi9zcmMvaW5kZXgudHNcIixcbiAgfSxcbiAgYmFubmVyOiB7XG4gICAgdHlwZTogXCJib29sZWFuXCIsXG4gICAgZGVmYXVsdDogZmFsc2UsXG4gIH0sXG59O1xuXG5jb25zdCBjanMyVHJhbnNmb3JtZXIgPSAoZXh0ID0gXCIuY2pzXCIpID0+IHtcbiAgY29uc3QgbG9nID0gQnVpbGRTY3JpcHRzLmxvZy5mb3IoY2pzMlRyYW5zZm9ybWVyKTtcbiAgY29uc3QgcmVzb2x1dGlvbkNhY2hlID0gbmV3IE1hcDxzdHJpbmcsIHN0cmluZz4oKTtcblxuICByZXR1cm4gKHRyYW5zZm9ybWF0aW9uQ29udGV4dDogdHMuVHJhbnNmb3JtYXRpb25Db250ZXh0KSA9PiB7XG4gICAgcmV0dXJuIChzb3VyY2VGaWxlOiB0cy5Tb3VyY2VGaWxlKSA9PiB7XG4gICAgICBjb25zdCBzb3VyY2VEaXIgPSBwYXRoLmRpcm5hbWUoc291cmNlRmlsZS5maWxlTmFtZSk7XG5cbiAgICAgIGZ1bmN0aW9uIHJlc29sdmVQYXRoKGltcG9ydFBhdGg6IHN0cmluZykge1xuICAgICAgICBjb25zdCBjYWNoZUtleSA9IEpTT04uc3RyaW5naWZ5KFtzb3VyY2VEaXIsIGltcG9ydFBhdGhdKTtcbiAgICAgICAgY29uc3QgY2FjaGVkVmFsdWUgPSByZXNvbHV0aW9uQ2FjaGUuZ2V0KGNhY2hlS2V5KTtcbiAgICAgICAgaWYgKGNhY2hlZFZhbHVlICE9IG51bGwpIHJldHVybiBjYWNoZWRWYWx1ZTtcblxuICAgICAgICBsZXQgcmVzb2x2ZWRQYXRoID0gaW1wb3J0UGF0aDtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICByZXNvbHZlZFBhdGggPSBwYXRoLnJlc29sdmUoc291cmNlRGlyLCByZXNvbHZlZFBhdGggKyBcIi50c1wiKTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3I6IHVua25vd24pIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEZhaWxlZCB0byByZXNvbHZlIHBhdGggJHtpbXBvcnRQYXRofTogJHtlcnJvcn1gKTtcbiAgICAgICAgfVxuICAgICAgICBsZXQgc3RhdDtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBzdGF0ID0gZnMuc3RhdFN5bmMocmVzb2x2ZWRQYXRoKTtcbiAgICAgICAgfSBjYXRjaCAoZTogdW5rbm93bikge1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBsb2cudmVyYm9zZShcbiAgICAgICAgICAgICAgYFRlc3RpbmcgZXhpc3RlbmNlIG9mIHBhdGggJHtyZXNvbHZlZFBhdGh9IGFzIGEgZm9sZGVyIGRlZmF1bHRpbmcgdG8gaW5kZXggZmlsZWBcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICBzdGF0ID0gZnMuc3RhdFN5bmMocmVzb2x2ZWRQYXRoLnJlcGxhY2UoL1xcLnRzJC9nbSwgXCJcIikpO1xuICAgICAgICAgIH0gY2F0Y2ggKGUyOiB1bmtub3duKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgICAgIGBGYWlsZWQgdG8gcmVzb2x2ZSBwYXRoICR7aW1wb3J0UGF0aH06ICR7ZX0sICR7ZTJ9YFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHN0YXQuaXNEaXJlY3RvcnkoKSlcbiAgICAgICAgICByZXNvbHZlZFBhdGggPSByZXNvbHZlZFBhdGgucmVwbGFjZSgvXFwudHMkL2dtLCBcIi9pbmRleC50c1wiKTtcblxuICAgICAgICBpZiAocGF0aC5pc0Fic29sdXRlKHJlc29sdmVkUGF0aCkpIHtcbiAgICAgICAgICBjb25zdCBleHRlbnNpb24gPVxuICAgICAgICAgICAgKC9cXC50c3g/JC8uZXhlYyhwYXRoLmJhc2VuYW1lKHJlc29sdmVkUGF0aCkpIHx8IFtdKVswXSB8fCB2b2lkIDA7XG5cbiAgICAgICAgICByZXNvbHZlZFBhdGggPVxuICAgICAgICAgICAgXCIuL1wiICtcbiAgICAgICAgICAgIHBhdGgucmVsYXRpdmUoXG4gICAgICAgICAgICAgIHNvdXJjZURpcixcbiAgICAgICAgICAgICAgcGF0aC5yZXNvbHZlKFxuICAgICAgICAgICAgICAgIHBhdGguZGlybmFtZShyZXNvbHZlZFBhdGgpLFxuICAgICAgICAgICAgICAgIHBhdGguYmFzZW5hbWUocmVzb2x2ZWRQYXRoLCBleHRlbnNpb24pICsgZXh0XG4gICAgICAgICAgICAgIClcbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cblxuICAgICAgICByZXNvbHV0aW9uQ2FjaGUuc2V0KGNhY2hlS2V5LCByZXNvbHZlZFBhdGgpO1xuICAgICAgICByZXR1cm4gcmVzb2x2ZWRQYXRoO1xuICAgICAgfVxuXG4gICAgICBmdW5jdGlvbiB2aXNpdE5vZGUobm9kZTogdHMuTm9kZSk6IHRzLlZpc2l0UmVzdWx0PHRzLk5vZGU+IHtcbiAgICAgICAgaWYgKHNob3VsZE11dGF0ZU1vZHVsZVNwZWNpZmllcihub2RlKSkge1xuICAgICAgICAgIGlmICh0cy5pc0ltcG9ydERlY2xhcmF0aW9uKG5vZGUpKSB7XG4gICAgICAgICAgICBjb25zdCByZXNvbHZlZFBhdGggPSByZXNvbHZlUGF0aChub2RlLm1vZHVsZVNwZWNpZmllci50ZXh0KTtcbiAgICAgICAgICAgIGNvbnN0IG5ld01vZHVsZVNwZWNpZmllciA9XG4gICAgICAgICAgICAgIHRyYW5zZm9ybWF0aW9uQ29udGV4dC5mYWN0b3J5LmNyZWF0ZVN0cmluZ0xpdGVyYWwocmVzb2x2ZWRQYXRoKTtcbiAgICAgICAgICAgIHJldHVybiB0cmFuc2Zvcm1hdGlvbkNvbnRleHQuZmFjdG9yeS51cGRhdGVJbXBvcnREZWNsYXJhdGlvbihcbiAgICAgICAgICAgICAgbm9kZSxcbiAgICAgICAgICAgICAgbm9kZS5tb2RpZmllcnMsXG4gICAgICAgICAgICAgIG5vZGUuaW1wb3J0Q2xhdXNlLFxuICAgICAgICAgICAgICBuZXdNb2R1bGVTcGVjaWZpZXIsXG4gICAgICAgICAgICAgIHVuZGVmaW5lZFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9IGVsc2UgaWYgKHRzLmlzRXhwb3J0RGVjbGFyYXRpb24obm9kZSkpIHtcbiAgICAgICAgICAgIGNvbnN0IHJlc29sdmVkUGF0aCA9IHJlc29sdmVQYXRoKG5vZGUubW9kdWxlU3BlY2lmaWVyLnRleHQpO1xuICAgICAgICAgICAgY29uc3QgbmV3TW9kdWxlU3BlY2lmaWVyID1cbiAgICAgICAgICAgICAgdHJhbnNmb3JtYXRpb25Db250ZXh0LmZhY3RvcnkuY3JlYXRlU3RyaW5nTGl0ZXJhbChyZXNvbHZlZFBhdGgpO1xuICAgICAgICAgICAgcmV0dXJuIHRyYW5zZm9ybWF0aW9uQ29udGV4dC5mYWN0b3J5LnVwZGF0ZUV4cG9ydERlY2xhcmF0aW9uKFxuICAgICAgICAgICAgICBub2RlLFxuICAgICAgICAgICAgICBub2RlLm1vZGlmaWVycyxcbiAgICAgICAgICAgICAgbm9kZS5pc1R5cGVPbmx5LFxuICAgICAgICAgICAgICBub2RlLmV4cG9ydENsYXVzZSxcbiAgICAgICAgICAgICAgbmV3TW9kdWxlU3BlY2lmaWVyLFxuICAgICAgICAgICAgICB1bmRlZmluZWRcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHRzLnZpc2l0RWFjaENoaWxkKG5vZGUsIHZpc2l0Tm9kZSwgdHJhbnNmb3JtYXRpb25Db250ZXh0KTtcbiAgICAgIH1cblxuICAgICAgZnVuY3Rpb24gc2hvdWxkTXV0YXRlTW9kdWxlU3BlY2lmaWVyKG5vZGU6IHRzLk5vZGUpOiBub2RlIGlzIChcbiAgICAgICAgfCB0cy5JbXBvcnREZWNsYXJhdGlvblxuICAgICAgICB8IHRzLkV4cG9ydERlY2xhcmF0aW9uXG4gICAgICApICYge1xuICAgICAgICBtb2R1bGVTcGVjaWZpZXI6IHRzLlN0cmluZ0xpdGVyYWw7XG4gICAgICB9IHtcbiAgICAgICAgaWYgKCF0cy5pc0ltcG9ydERlY2xhcmF0aW9uKG5vZGUpICYmICF0cy5pc0V4cG9ydERlY2xhcmF0aW9uKG5vZGUpKVxuICAgICAgICAgIHJldHVybiBmYWxzZTtcblxuICAgICAgICBpZiAobm9kZS5tb2R1bGVTcGVjaWZpZXIgPT09IHVuZGVmaW5lZCkgcmV0dXJuIGZhbHNlO1xuICAgICAgICAvLyBvbmx5IHdoZW4gbW9kdWxlIHNwZWNpZmllciBpcyB2YWxpZFxuICAgICAgICBpZiAoIXRzLmlzU3RyaW5nTGl0ZXJhbChub2RlLm1vZHVsZVNwZWNpZmllcikpIHJldHVybiBmYWxzZTtcbiAgICAgICAgLy8gb25seSB3aGVuIHBhdGggaXMgcmVsYXRpdmVcbiAgICAgICAgaWYgKFxuICAgICAgICAgICFub2RlLm1vZHVsZVNwZWNpZmllci50ZXh0LnN0YXJ0c1dpdGgoXCIuL1wiKSAmJlxuICAgICAgICAgICFub2RlLm1vZHVsZVNwZWNpZmllci50ZXh0LnN0YXJ0c1dpdGgoXCIuLi9cIilcbiAgICAgICAgKVxuICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgLy8gb25seSB3aGVuIG1vZHVsZSBzcGVjaWZpZXIgaGFzIG5vIGV4dGVuc2lvblxuICAgICAgICBpZiAocGF0aC5leHRuYW1lKG5vZGUubW9kdWxlU3BlY2lmaWVyLnRleHQpICE9PSBcIlwiKSByZXR1cm4gZmFsc2U7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gdHMudmlzaXROb2RlKHNvdXJjZUZpbGUsIHZpc2l0Tm9kZSkgYXMgU291cmNlRmlsZTtcbiAgICB9O1xuICB9O1xufTtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gQSBjb21tYW5kLWxpbmUgc2NyaXB0IGZvciBidWlsZGluZyBhbmQgYnVuZGxpbmcgVHlwZVNjcmlwdCBwcm9qZWN0cy5cbiAqIEBzdW1tYXJ5IFRoaXMgY2xhc3MgcHJvdmlkZXMgYSBjb21wcmVoZW5zaXZlIGJ1aWxkIHNjcmlwdCB0aGF0IGhhbmRsZXMgVHlwZVNjcmlwdCBjb21waWxhdGlvbixcbiAqIGJ1bmRsaW5nIHdpdGggUm9sbHVwLCBhbmQgZG9jdW1lbnRhdGlvbiBnZW5lcmF0aW9uLiBJdCBzdXBwb3J0cyBkaWZmZXJlbnQgYnVpbGQgbW9kZXNcbiAqIChkZXZlbG9wbWVudCwgcHJvZHVjdGlvbiksIG1vZHVsZSBmb3JtYXRzIChDSlMsIEVTTSksIGFuZCBjYW4gYmUgZXh0ZW5kZWQgd2l0aCBjdXN0b21cbiAqIGNvbmZpZ3VyYXRpb25zLlxuICogQGNsYXNzIEJ1aWxkU2NyaXB0c1xuICovXG5leHBvcnQgY2xhc3MgQnVpbGRTY3JpcHRzIGV4dGVuZHMgQ29tbWFuZDxcbiAgQ29tbWFuZE9wdGlvbnM8dHlwZW9mIG9wdGlvbnM+LFxuICB2b2lkXG4+IHtcbiAgcHJpdmF0ZSByZXBsYWNlbWVudHM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7fTtcbiAgcHJpdmF0ZSByZWFkb25seSBwa2dWZXJzaW9uOiBzdHJpbmc7XG4gIHByaXZhdGUgcmVhZG9ubHkgcGtnTmFtZTogc3RyaW5nO1xuXG4gIGNvbnN0cnVjdG9yKCkge1xuICAgIHN1cGVyKFxuICAgICAgXCJCdWlsZFNjcmlwdHNcIixcbiAgICAgIE9iamVjdC5hc3NpZ24oe30sIERlZmF1bHRDb21tYW5kT3B0aW9ucywgb3B0aW9ucykgYXMgQ29tbWFuZE9wdGlvbnM8XG4gICAgICAgIHR5cGVvZiBvcHRpb25zXG4gICAgICA+XG4gICAgKTtcbiAgICBjb25zdCBwa2cgPSBnZXRQYWNrYWdlKCkgYXMgeyBuYW1lOiBzdHJpbmc7IHZlcnNpb246IHN0cmluZyB9O1xuICAgIGNvbnN0IHsgbmFtZSwgdmVyc2lvbiB9ID0gcGtnO1xuICAgIHRoaXMucGtnTmFtZSA9IG5hbWUuaW5jbHVkZXMoXCJAXCIpID8gbmFtZS5zcGxpdChcIi9cIilbMV0gOiBuYW1lO1xuICAgIHRoaXMucGtnVmVyc2lvbiA9IHZlcnNpb247XG4gICAgdGhpcy5yZXBsYWNlbWVudHNbVkVSU0lPTl9TVFJJTkddID0gdGhpcy5wa2dWZXJzaW9uO1xuICAgIHRoaXMucmVwbGFjZW1lbnRzW1BBQ0tBR0VfU1RSSU5HXSA9IG5hbWU7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFBhdGNoZXMgZmlsZXMgd2l0aCB2ZXJzaW9uIGFuZCBwYWNrYWdlIG5hbWUuXG4gICAqIEBzdW1tYXJ5IFRoaXMgbWV0aG9kIHJlYWRzIGFsbCBmaWxlcyBpbiBhIGRpcmVjdG9yeSwgZmluZHMgcGxhY2Vob2xkZXJzIGZvciB2ZXJzaW9uXG4gICAqIGFuZCBwYWNrYWdlIG5hbWUsIGFuZCByZXBsYWNlcyB0aGVtIHdpdGggdGhlIGFjdHVhbCB2YWx1ZXMgZnJvbSBwYWNrYWdlLmpzb24uXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBwIC0gVGhlIHBhdGggdG8gdGhlIGRpcmVjdG9yeSBjb250YWluaW5nIHRoZSBmaWxlcyB0byBwYXRjaC5cbiAgICovXG4gIHBhdGNoRmlsZXMocDogc3RyaW5nKSB7XG4gICAgY29uc3QgbG9nID0gdGhpcy5sb2cuZm9yKHRoaXMucGF0Y2hGaWxlcyk7XG4gICAgY29uc3QgeyBuYW1lLCB2ZXJzaW9uIH0gPSBnZXRQYWNrYWdlKCkgYXMgYW55O1xuICAgIGxvZy5pbmZvKGBQYXRjaGluZyAke25hbWV9ICR7dmVyc2lvbn0gbW9kdWxlIGluICR7cH0uLi5gKTtcbiAgICBjb25zdCBzdGF0ID0gZnMuc3RhdFN5bmMocCk7XG4gICAgaWYgKHN0YXQuaXNEaXJlY3RvcnkoKSlcbiAgICAgIGZzLnJlYWRkaXJTeW5jKHAsIHsgd2l0aEZpbGVUeXBlczogdHJ1ZSwgcmVjdXJzaXZlOiB0cnVlIH0pXG4gICAgICAgIC5maWx0ZXIoKHApID0+IHAuaXNGaWxlKCkpXG4gICAgICAgIC5mb3JFYWNoKChmaWxlKSA9PlxuICAgICAgICAgIHBhdGNoRmlsZShcbiAgICAgICAgICAgIHBhdGguam9pbihmaWxlLnBhcmVudFBhdGgsIGZpbGUubmFtZSksXG4gICAgICAgICAgICBPYmplY3QuZW50cmllcyh0aGlzLnJlcGxhY2VtZW50cykucmVkdWNlKFxuICAgICAgICAgICAgICAoYWNjOiBSZWNvcmQ8c3RyaW5nLCBhbnk+LCBba2V5LCB2YWxdKSA9PiB7XG4gICAgICAgICAgICAgICAgc3dpdGNoIChrZXkpIHtcbiAgICAgICAgICAgICAgICAgIGNhc2UgVkVSU0lPTl9TVFJJTkc6XG4gICAgICAgICAgICAgICAgICAgIGxvZy5kZWJ1ZyhcIkZvdW5kIFZFUlNJT04gc3RyaW5nIHRvIHJlcGxhY2VcIik7XG4gICAgICAgICAgICAgICAgICAgIGFjY1tgVkVSU0lPTiA9IFwiJHtWRVJTSU9OX1NUUklOR31cIjtgXSA9XG4gICAgICAgICAgICAgICAgICAgICAgYFZFUlNJT04gPSBcIiR7dmFsfVwiO2A7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgICAgY2FzZSBQQUNLQUdFX1NUUklORzpcbiAgICAgICAgICAgICAgICAgICAgbG9nLmRlYnVnKFwiRm91bmQgUEFDS0FHRV9OQU1FIHN0cmluZyB0byByZXBsYWNlXCIpO1xuICAgICAgICAgICAgICAgICAgICBhY2NbYFBBQ0tBR0VfTkFNRSA9IFwiJHtQQUNLQUdFX1NUUklOR31cIjtgXSA9XG4gICAgICAgICAgICAgICAgICAgICAgYFBBQ0tBR0VfTkFNRSA9IFwiJHt2YWx9XCI7YDtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgICAgICAgICBhY2Nba2V5XSA9IHZhbDtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuIGFjYztcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAge31cbiAgICAgICAgICAgIClcbiAgICAgICAgICApXG4gICAgICAgICk7XG4gICAgbG9nLnZlcmJvc2UoYE1vZHVsZSAke25hbWV9ICR7dmVyc2lvbn0gcGF0Y2hlZCBpbiAke3B9Li4uYCk7XG4gIH1cblxuICBwcml2YXRlIHJlcG9ydERpYWdub3N0aWNzKFxuICAgIGRpYWdub3N0aWNzOiBEaWFnbm9zdGljW10sXG4gICAgbG9nTGV2ZWw6IExvZ0xldmVsXG4gICk6IHN0cmluZyB7XG4gICAgY29uc3QgbXNnID0gdGhpcy5mb3JtYXREaWFnbm9zdGljcyhkaWFnbm9zdGljcyk7XG4gICAgdHJ5IHtcbiAgICAgIHRoaXMubG9nW2xvZ0xldmVsXShtc2cpO1xuICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgIGNvbnNvbGUud2FybihgRmFpbGVkIHRvIGdldCBsb2dnZXIgZm9yICR7bG9nTGV2ZWx9YCk7XG4gICAgICB0aHJvdyBlO1xuICAgIH1cbiAgICByZXR1cm4gbXNnO1xuICB9XG5cbiAgLy8gRm9ybWF0IGRpYWdub3N0aWNzIGludG8gYSBzaW5nbGUgc3RyaW5nIGZvciB0aHJvd2luZyBvciBsb2dnaW5nXG4gIHByaXZhdGUgZm9ybWF0RGlhZ25vc3RpY3MoZGlhZ25vc3RpY3M6IERpYWdub3N0aWNbXSk6IHN0cmluZyB7XG4gICAgcmV0dXJuIGRpYWdub3N0aWNzXG4gICAgICAubWFwKChkaWFnbm9zdGljKSA9PiB7XG4gICAgICAgIGxldCBtZXNzYWdlID0gXCJcIjtcbiAgICAgICAgaWYgKGRpYWdub3N0aWMuZmlsZSAmJiBkaWFnbm9zdGljLnN0YXJ0KSB7XG4gICAgICAgICAgY29uc3QgeyBsaW5lLCBjaGFyYWN0ZXIgfSA9XG4gICAgICAgICAgICBkaWFnbm9zdGljLmZpbGUuZ2V0TGluZUFuZENoYXJhY3Rlck9mUG9zaXRpb24oZGlhZ25vc3RpYy5zdGFydCk7XG4gICAgICAgICAgbWVzc2FnZSArPSBgJHtkaWFnbm9zdGljLmZpbGUuZmlsZU5hbWV9ICgke2xpbmUgKyAxfSwke2NoYXJhY3RlciArIDF9KWA7XG4gICAgICAgIH1cbiAgICAgICAgbWVzc2FnZSArPVxuICAgICAgICAgIFwiOiBcIiArIHRzLmZsYXR0ZW5EaWFnbm9zdGljTWVzc2FnZVRleHQoZGlhZ25vc3RpYy5tZXNzYWdlVGV4dCwgXCJcXG5cIik7XG4gICAgICAgIHJldHVybiBtZXNzYWdlO1xuICAgICAgfSlcbiAgICAgIC5qb2luKFwiXFxuXCIpO1xuICB9XG5cbiAgcHJpdmF0ZSByZWFkQ29uZmlnRmlsZShjb25maWdGaWxlTmFtZTogc3RyaW5nKSB7XG4gICAgLy8gUmVhZCBjb25maWcgZmlsZVxuICAgIGNvbnN0IGNvbmZpZ0ZpbGVUZXh0ID0gZnMucmVhZEZpbGVTeW5jKGNvbmZpZ0ZpbGVOYW1lKS50b1N0cmluZygpO1xuXG4gICAgLy8gUGFyc2UgSlNPTiwgYWZ0ZXIgcmVtb3ZpbmcgY29tbWVudHMuIEp1c3QgZmFuY2llciBKU09OLnBhcnNlXG4gICAgY29uc3QgcmVzdWx0ID0gdHMucGFyc2VDb25maWdGaWxlVGV4dFRvSnNvbihjb25maWdGaWxlTmFtZSwgY29uZmlnRmlsZVRleHQpO1xuICAgIGNvbnN0IGNvbmZpZ09iamVjdCA9IHJlc3VsdC5jb25maWc7XG4gICAgaWYgKCFjb25maWdPYmplY3QpIHtcbiAgICAgIHRoaXMucmVwb3J0RGlhZ25vc3RpY3MoW3Jlc3VsdC5lcnJvciFdLCBMb2dMZXZlbC5lcnJvcik7XG4gICAgfVxuXG4gICAgLy8gRXh0cmFjdCBjb25maWcgaW5mcm9tYXRpb25cbiAgICBjb25zdCBjb25maWdQYXJzZVJlc3VsdCA9IHRzLnBhcnNlSnNvbkNvbmZpZ0ZpbGVDb250ZW50KFxuICAgICAgY29uZmlnT2JqZWN0LFxuICAgICAgdHMuc3lzLFxuICAgICAgcGF0aC5kaXJuYW1lKGNvbmZpZ0ZpbGVOYW1lKVxuICAgICk7XG4gICAgaWYgKGNvbmZpZ1BhcnNlUmVzdWx0LmVycm9ycy5sZW5ndGggPiAwKVxuICAgICAgdGhpcy5yZXBvcnREaWFnbm9zdGljcyhjb25maWdQYXJzZVJlc3VsdC5lcnJvcnMsIExvZ0xldmVsLmVycm9yKTtcblxuICAgIHJldHVybiBjb25maWdQYXJzZVJlc3VsdDtcbiAgfVxuXG4gIHByaXZhdGUgZXZhbERpYWdub3N0aWNzKGRpYWdub3N0aWNzOiBEaWFnbm9zdGljW10pIHtcbiAgICBpZiAoZGlhZ25vc3RpY3MgJiYgZGlhZ25vc3RpY3MubGVuZ3RoID4gMCkge1xuICAgICAgY29uc3QgZXJyb3JzID0gZGlhZ25vc3RpY3MuZmlsdGVyKFxuICAgICAgICAoZCkgPT4gZC5jYXRlZ29yeSA9PT0gdHMuRGlhZ25vc3RpY0NhdGVnb3J5LkVycm9yXG4gICAgICApO1xuICAgICAgY29uc3Qgd2FybmluZ3MgPSBkaWFnbm9zdGljcy5maWx0ZXIoXG4gICAgICAgIChkKSA9PiBkLmNhdGVnb3J5ID09PSB0cy5EaWFnbm9zdGljQ2F0ZWdvcnkuV2FybmluZ1xuICAgICAgKTtcbiAgICAgIGNvbnN0IHN1Z2dlc3Rpb25zID0gZGlhZ25vc3RpY3MuZmlsdGVyKFxuICAgICAgICAoZCkgPT4gZC5jYXRlZ29yeSA9PT0gdHMuRGlhZ25vc3RpY0NhdGVnb3J5LlN1Z2dlc3Rpb25cbiAgICAgICk7XG4gICAgICBjb25zdCBtZXNzYWdlcyA9IGRpYWdub3N0aWNzLmZpbHRlcihcbiAgICAgICAgKGQpID0+IGQuY2F0ZWdvcnkgPT09IHRzLkRpYWdub3N0aWNDYXRlZ29yeS5NZXNzYWdlXG4gICAgICApO1xuICAgICAgLy8gTG9nIGRpYWdub3N0aWNzIHRvIGNvbnNvbGVcblxuICAgICAgaWYgKHdhcm5pbmdzLmxlbmd0aCkgdGhpcy5yZXBvcnREaWFnbm9zdGljcyh3YXJuaW5ncywgTG9nTGV2ZWwud2Fybik7XG4gICAgICBpZiAoZXJyb3JzLmxlbmd0aCkge1xuICAgICAgICB0aGlzLnJlcG9ydERpYWdub3N0aWNzKGRpYWdub3N0aWNzIGFzIERpYWdub3N0aWNbXSwgTG9nTGV2ZWwuZXJyb3IpO1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgYFR5cGVTY3JpcHQgcmVwb3J0ZWQgJHtkaWFnbm9zdGljcy5sZW5ndGh9IGRpYWdub3N0aWMocykgZHVyaW5nIGNoZWNrOyBhYm9ydGluZy5gXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgICBpZiAoc3VnZ2VzdGlvbnMubGVuZ3RoKVxuICAgICAgICB0aGlzLnJlcG9ydERpYWdub3N0aWNzKHN1Z2dlc3Rpb25zLCBMb2dMZXZlbC5pbmZvKTtcbiAgICAgIGlmIChtZXNzYWdlcy5sZW5ndGgpIHRoaXMucmVwb3J0RGlhZ25vc3RpY3MobWVzc2FnZXMsIExvZ0xldmVsLmluZm8pO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgcHJlQ2hlY2tEaWFnbm9zdGljcyhwcm9ncmFtOiB0cy5Qcm9ncmFtKSB7XG4gICAgY29uc3QgZGlhZ25vc3RpY3MgPSB0cy5nZXRQcmVFbWl0RGlhZ25vc3RpY3MocHJvZ3JhbSk7XG4gICAgdGhpcy5ldmFsRGlhZ25vc3RpY3MoZGlhZ25vc3RpY3MgYXMgYW55KTtcbiAgfVxuXG4gIC8vIENyZWF0ZSBhIFR5cGVTY3JpcHQgcHJvZ3JhbSBmb3IgdGhlIGN1cnJlbnQgdHNjb25maWcgYW5kIGZhaWwgaWYgdGhlcmUgYXJlIGFueSBlcnJvciBkaWFnbm9zdGljcy5cbiAgcHJpdmF0ZSBhc3luYyBjaGVja1RzRGlhZ25vc3RpY3MoXG4gICAgaXNEZXY6IGJvb2xlYW4sXG4gICAgbW9kZTogTW9kZXMsXG4gICAgYnVuZGxlID0gZmFsc2VcbiAgKSB7XG4gICAgY29uc3QgbG9nID0gdGhpcy5sb2cuZm9yKHRoaXMuY2hlY2tUc0RpYWdub3N0aWNzKTtcbiAgICBsZXQgdHNDb25maWc7XG4gICAgdHJ5IHtcbiAgICAgIHRzQ29uZmlnID0gdGhpcy5yZWFkQ29uZmlnRmlsZShcIi4vdHNjb25maWcuanNvblwiKTtcbiAgICB9IGNhdGNoIChlOiB1bmtub3duKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYEZhaWxlZCB0byBwYXJzZSB0c2NvbmZpZy5qc29uOiAke2V9YCk7XG4gICAgfVxuXG4gICAgaWYgKGJ1bmRsZSkge1xuICAgICAgdHNDb25maWcub3B0aW9ucy5tb2R1bGUgPSBNb2R1bGVLaW5kLkFNRDtcbiAgICAgIHRzQ29uZmlnLm9wdGlvbnMub3V0RGlyID0gXCJkaXN0XCI7XG4gICAgICB0c0NvbmZpZy5vcHRpb25zLmlzb2xhdGVkTW9kdWxlcyA9IGZhbHNlO1xuICAgICAgdHNDb25maWcub3B0aW9ucy5vdXRGaWxlID0gdGhpcy5wa2dOYW1lO1xuICAgIH0gZWxzZSB7XG4gICAgICB0c0NvbmZpZy5vcHRpb25zLm91dERpciA9IGBsaWIke21vZGUgPT09IE1vZGVzLkVTTSA/IFwiL2VzbVwiIDogXCJcIn1gO1xuICAgICAgdHNDb25maWcub3B0aW9ucy5tb2R1bGUgPVxuICAgICAgICBtb2RlID09PSBNb2Rlcy5FU00gPyBNb2R1bGVLaW5kLkVTMjAyMiA6IE1vZHVsZUtpbmQuQ29tbW9uSlM7XG4gICAgfVxuXG4gICAgLy8gRW5zdXJlIFR5cGVTY3JpcHQgZW1pdHMgaW5saW5lIHNvdXJjZSBtYXBzIGZvciBib3RoIGRldiBhbmQgcHJvZCAoYnVuZGxlcnMgd2lsbCBjb250cm9sIGV4dGVybmFsIG1hcHMpXG4gICAgLy8gS2VlcCBjb21tZW50cyBpbiBUUyBlbWl0IGJ5IGRlZmF1bHQ7IGJ1bmRsaW5nL21pbmlmaWNhdGlvbiB3aWxsIGhhbmRsZSByZW1vdmFsIHdoZXJlIHJlcXVlc3RlZC5cbiAgICAvLyBFbWl0IGV4dGVybmFsIHNvdXJjZSBtYXBzIGZyb20gVHlwZVNjcmlwdCBzbyBlZGl0b3JzL2RlYnVnZ2VycyBjYW4gZmluZCB0aGVtLlxuICAgIC8vIFR1cm4gb2ZmIGlubGluZSBtYXBzL3NvdXJjZXMgc28gYnVuZGxlcnMgKFJvbGx1cCkgY2FuIGNvbnRyb2wgd2hldGhlciBtYXBzIGFyZSBpbmxpbmVkIG9yIHdyaXR0ZW4gZXh0ZXJuYWxseS5cbiAgICB0c0NvbmZpZy5vcHRpb25zLmlubGluZVNvdXJjZU1hcCA9IGZhbHNlO1xuICAgIHRzQ29uZmlnLm9wdGlvbnMuaW5saW5lU291cmNlcyA9IGZhbHNlO1xuICAgIHRzQ29uZmlnLm9wdGlvbnMuc291cmNlTWFwID0gdHJ1ZTtcblxuICAgIGNvbnN0IHByb2dyYW0gPSB0cy5jcmVhdGVQcm9ncmFtKHRzQ29uZmlnLmZpbGVOYW1lcywgdHNDb25maWcub3B0aW9ucyk7XG4gICAgdGhpcy5wcmVDaGVja0RpYWdub3N0aWNzKHByb2dyYW0pO1xuICAgIGxvZy52ZXJib3NlKFxuICAgICAgYFR5cGVTY3JpcHQgY2hlY2tzIHBhc3NlZCAoJHtidW5kbGUgPyBcImJ1bmRsZVwiIDogXCJub3JtYWxcIn0gbW9kZSkuYFxuICAgICk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGJ1aWxkVHMoaXNEZXY6IGJvb2xlYW4sIG1vZGU6IE1vZGVzLCBidW5kbGUgPSBmYWxzZSkge1xuICAgIGNvbnN0IGxvZyA9IHRoaXMubG9nLmZvcih0aGlzLmJ1aWxkVHMpO1xuICAgIGxvZy5pbmZvKFxuICAgICAgYEJ1aWxkaW5nICR7dGhpcy5wa2dOYW1lfSAke3RoaXMucGtnVmVyc2lvbn0gbW9kdWxlICgke21vZGV9KSBpbiAke2lzRGV2ID8gXCJkZXZcIiA6IFwicHJvZFwifSBtb2RlLi4uYFxuICAgICk7XG4gICAgbGV0IHRzQ29uZmlnO1xuICAgIHRyeSB7XG4gICAgICB0c0NvbmZpZyA9IHRoaXMucmVhZENvbmZpZ0ZpbGUoXCIuL3RzY29uZmlnLmpzb25cIik7XG4gICAgfSBjYXRjaCAoZTogdW5rbm93bikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBGYWlsZWQgdG8gcGFyc2UgdHNjb25maWcuanNvbjogJHtlfWApO1xuICAgIH1cblxuICAgIGlmIChidW5kbGUpIHtcbiAgICAgIHRzQ29uZmlnLm9wdGlvbnMubW9kdWxlID0gTW9kdWxlS2luZC5BTUQ7XG4gICAgICB0c0NvbmZpZy5vcHRpb25zLm91dERpciA9IFwiZGlzdFwiO1xuICAgICAgdHNDb25maWcub3B0aW9ucy5pc29sYXRlZE1vZHVsZXMgPSBmYWxzZTtcbiAgICAgIHRzQ29uZmlnLm9wdGlvbnMub3V0RmlsZSA9IHRoaXMucGtnTmFtZTtcbiAgICB9IGVsc2Uge1xuICAgICAgdHNDb25maWcub3B0aW9ucy5vdXREaXIgPSBgbGliJHttb2RlID09PSBNb2Rlcy5FU00gPyBcIi9lc21cIiA6IFwiXCJ9YDtcbiAgICAgIHRzQ29uZmlnLm9wdGlvbnMubW9kdWxlID1cbiAgICAgICAgbW9kZSA9PT0gTW9kZXMuRVNNID8gTW9kdWxlS2luZC5FUzIwMjIgOiBNb2R1bGVLaW5kLkNvbW1vbkpTO1xuICAgIH1cblxuICAgIC8vIEFsd2F5cyBlbWl0IGlubGluZSBzb3VyY2UgbWFwcyBmcm9tIHRzYyAoYnVuZGxlciB3aWxsIGVtaXQgZXh0ZXJuYWwgbWFwcyBmb3IgcHJvZHVjdGlvbiBidW5kbGVzKS5cbiAgICAvLyBGb3IgZGV2IGJ1aWxkcyB3ZSB3YW50IFR5cGVTY3JpcHQgdG8gZW1pdCBpbmxpbmUgc291cmNlIG1hcHMgc28gbm8gc2VwYXJhdGUgLm1hcCBmaWxlcyBhcmUgcHJvZHVjZWQuXG4gICAgLy8gRm9yIHByb2R1Y3Rpb24gd2UgZW1pdCBleHRlcm5hbCBzb3VyY2UgbWFwcyBzbyB0aGUgYnVuZGxlciBjYW4gZnVydGhlciB0cmFuc2Zvcm0gYW5kIGVtaXQgdGhlbS5cbiAgICBpZiAoaXNEZXYpIHtcbiAgICAgIHRzQ29uZmlnLm9wdGlvbnMuaW5saW5lU291cmNlTWFwID0gdHJ1ZTtcbiAgICAgIHRzQ29uZmlnLm9wdGlvbnMuaW5saW5lU291cmNlcyA9IHRydWU7XG4gICAgICB0c0NvbmZpZy5vcHRpb25zLnNvdXJjZU1hcCA9IGZhbHNlO1xuICAgIH0gZWxzZSB7XG4gICAgICB0c0NvbmZpZy5vcHRpb25zLmlubGluZVNvdXJjZU1hcCA9IGZhbHNlO1xuICAgICAgdHNDb25maWcub3B0aW9ucy5pbmxpbmVTb3VyY2VzID0gZmFsc2U7XG4gICAgICB0c0NvbmZpZy5vcHRpb25zLnNvdXJjZU1hcCA9IHRydWU7XG4gICAgfVxuXG4gICAgLy8gRm9yIHByb2R1Y3Rpb24gYnVpbGRzIHdlIHN0aWxsIGtlZXAgVHlwZVNjcmlwdCBjb21tZW50cyAocmVtb3ZlQ29tbWVudHM9ZmFsc2UgaW4gdHNjb25maWcpXG4gICAgLy8gQnVuZGxlci90ZXJzZXIgd2lsbCBzdHJpcCBjb21tZW50cyBmb3IgcHJvZHVjdGlvbiBidW5kbGVzIGFzIHJlcXVlc3RlZC5cblxuICAgIGNvbnN0IHByb2dyYW0gPSB0cy5jcmVhdGVQcm9ncmFtKHRzQ29uZmlnLmZpbGVOYW1lcywgdHNDb25maWcub3B0aW9ucyk7XG5cbiAgICBjb25zdCB0cmFuc2Zvcm1hdGlvbnM6IHsgYmVmb3JlPzogYW55W10gfSA9IHt9O1xuICAgIGlmIChtb2RlID09PSBNb2Rlcy5DSlMpIHtcbiAgICAgIHRyYW5zZm9ybWF0aW9ucy5iZWZvcmUgPSBbY2pzMlRyYW5zZm9ybWVyKFwiLmNqc1wiKV07XG4gICAgfSBlbHNlIGlmIChtb2RlID09PSBNb2Rlcy5FU00pIHtcbiAgICAgIHRyYW5zZm9ybWF0aW9ucy5iZWZvcmUgPSBbY2pzMlRyYW5zZm9ybWVyKFwiLmpzXCIpXTtcbiAgICB9XG5cbiAgICBjb25zdCBlbWl0UmVzdWx0OiBFbWl0UmVzdWx0ID0gcHJvZ3JhbS5lbWl0KFxuICAgICAgdW5kZWZpbmVkLFxuICAgICAgdW5kZWZpbmVkLFxuICAgICAgdW5kZWZpbmVkLFxuICAgICAgdW5kZWZpbmVkLFxuICAgICAgdHJhbnNmb3JtYXRpb25zXG4gICAgKTtcblxuICAgIGNvbnN0IGFsbERpYWdub3N0aWNzID0gdHNcbiAgICAgIC5nZXRQcmVFbWl0RGlhZ25vc3RpY3MocHJvZ3JhbSlcbiAgICAgIC5jb25jYXQoZW1pdFJlc3VsdC5kaWFnbm9zdGljcyk7XG5cbiAgICB0aGlzLmV2YWxEaWFnbm9zdGljcyhhbGxEaWFnbm9zdGljcyk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGJ1aWxkKGlzRGV2OiBib29sZWFuLCBtb2RlOiBNb2RlcywgYnVuZGxlID0gZmFsc2UpIHtcbiAgICBjb25zdCBsb2cgPSB0aGlzLmxvZy5mb3IodGhpcy5idWlsZCk7XG4gICAgYXdhaXQgdGhpcy5idWlsZFRzKGlzRGV2LCBtb2RlLCBidW5kbGUpO1xuXG4gICAgbG9nLnZlcmJvc2UoXG4gICAgICBgTW9kdWxlICR7dGhpcy5wa2dOYW1lfSAke3RoaXMucGtnVmVyc2lvbn0gKCR7bW9kZX0pIGJ1aWx0IGluICR7aXNEZXYgPyBcImRldlwiIDogXCJwcm9kXCJ9IG1vZGUuLi5gXG4gICAgKTtcbiAgICBpZiAobW9kZSA9PT0gTW9kZXMuQ0pTICYmICFidW5kbGUpIHtcbiAgICAgIGNvbnN0IGZpbGVzID0gZ2V0QWxsRmlsZXMoXG4gICAgICAgIFwibGliXCIsXG4gICAgICAgIChmaWxlKSA9PiBmaWxlLmVuZHNXaXRoKFwiLmpzXCIpICYmICFmaWxlLmluY2x1ZGVzKFwiL2VzbS9cIilcbiAgICAgICk7XG5cbiAgICAgIGZvciAoY29uc3QgZmlsZSBvZiBmaWxlcykge1xuICAgICAgICBsb2cudmVyYm9zZShgUGF0Y2hpbmcgJHtmaWxlfSdzIGNqcyBpbXBvcnRzLi4uYCk7XG4gICAgICAgIGNvbnN0IGYgPSBmaWxlLnJlcGxhY2UoXCIuanNcIiwgXCIuY2pzXCIpO1xuICAgICAgICBhd2FpdCByZW5hbWVGaWxlKGZpbGUsIGYpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gQ29waWVzIGFzc2V0cyB0byB0aGUgYnVpbGQgb3V0cHV0IGRpcmVjdG9yeS5cbiAgICogQHN1bW1hcnkgVGhpcyBtZXRob2QgY2hlY2tzIGZvciB0aGUgZXhpc3RlbmNlIG9mIGFuICdhc3NldHMnIGRpcmVjdG9yeSBpbiB0aGUgc291cmNlXG4gICAqIGFuZCBjb3BpZXMgaXQgdG8gdGhlIGFwcHJvcHJpYXRlIGJ1aWxkIG91dHB1dCBkaXJlY3RvcnkgKGxpYiBvciBkaXN0KS5cbiAgICogQHBhcmFtIHtNb2Rlc30gbW9kZSAtIFRoZSBidWlsZCBtb2RlIChDSlMgb3IgRVNNKS5cbiAgICovXG4gIGNvcHlBc3NldHMobW9kZTogTW9kZXMpIHtcbiAgICBjb25zdCBsb2cgPSB0aGlzLmxvZy5mb3IodGhpcy5jb3B5QXNzZXRzKTtcbiAgICBsZXQgaGFzQXNzZXRzID0gZmFsc2U7XG4gICAgdHJ5IHtcbiAgICAgIGhhc0Fzc2V0cyA9IGZzLnN0YXRTeW5jKFwiLi9zcmMvYXNzZXRzXCIpLmlzRGlyZWN0b3J5KCk7XG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVudXNlZC12YXJzXG4gICAgfSBjYXRjaCAoZTogdW5rbm93bikge1xuICAgICAgcmV0dXJuIGxvZy52ZXJib3NlKGBObyBhc3NldHMgZm91bmQgaW4gLi9zcmMvYXNzZXRzIHRvIGNvcHlgKTtcbiAgICB9XG4gICAgaWYgKGhhc0Fzc2V0cylcbiAgICAgIGNvcHlGaWxlKFxuICAgICAgICBcIi4vc3JjL2Fzc2V0c1wiLFxuICAgICAgICBgLi8ke21vZGUgPT09IE1vZGVzLkNKUyA/IFwibGliXCIgOiBcImRpc3RcIn0vYXNzZXRzYFxuICAgICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gQnVuZGxlcyB0aGUgcHJvamVjdCB1c2luZyBSb2xsdXAuXG4gICAqIEBzdW1tYXJ5IFRoaXMgbWV0aG9kIGNvbmZpZ3VyZXMgYW5kIHJ1bnMgUm9sbHVwIHRvIGJ1bmRsZSB0aGUgcHJvamVjdC4gSXQgaGFuZGxlc1xuICAgKiBkaWZmZXJlbnQgbW9kdWxlIGZvcm1hdHMsIGRldmVsb3BtZW50IGFuZCBwcm9kdWN0aW9uIGJ1aWxkcywgYW5kIGV4dGVybmFsIGRlcGVuZGVuY2llcy5cbiAgICogQHBhcmFtIHtNb2Rlc30gbW9kZSAtIFRoZSBtb2R1bGUgZm9ybWF0IChDSlMgb3IgRVNNKS5cbiAgICogQHBhcmFtIHtib29sZWFufSBpc0RldiAtIFdoZXRoZXIgaXQncyBhIGRldmVsb3BtZW50IGJ1aWxkLlxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IGlzTGliIC0gV2hldGhlciBpdCdzIGEgbGlicmFyeSBidWlsZC5cbiAgICogQHBhcmFtIHtzdHJpbmd9IFtlbnRyeUZpbGU9XCJzcmMvaW5kZXgudHNcIl0gLSBUaGUgZW50cnkgZmlsZSBmb3IgdGhlIGJ1bmRsZS5cbiAgICogQHBhcmFtIHtzdHJpbmd9IFtuYW1lT3ZlcnJpZGU9dGhpcy5wa2dOYW1lXSAtIFRoZSBuYW1lIG9mIHRoZSBvdXRwdXQgYnVuZGxlLlxuICAgKiBAcGFyYW0ge3N0cmluZ3xzdHJpbmdbXX0gW2V4dGVybmFsc0FyZ10gLSBBIGxpc3Qgb2YgZXh0ZXJuYWwgZGVwZW5kZW5jaWVzLlxuICAgKiBAcGFyYW0ge3N0cmluZ3xzdHJpbmdbXX0gW2luY2x1ZGVBcmddIC0gQSBsaXN0IG9mIGRlcGVuZGVuY2llcyB0byBpbmNsdWRlLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn1cbiAgICovXG4gIGFzeW5jIGJ1bmRsZShcbiAgICBtb2RlOiBNb2RlcyxcbiAgICBpc0RldjogYm9vbGVhbixcbiAgICBpc0xpYjogYm9vbGVhbixcbiAgICBlbnRyeUZpbGU6IHN0cmluZyA9IFwiLi9zcmMvaW5kZXgudHNcIixcbiAgICBuYW1lT3ZlcnJpZGU6IHN0cmluZyA9IHRoaXMucGtnTmFtZSxcbiAgICBleHRlcm5hbHNBcmc/OiBzdHJpbmcgfCBzdHJpbmdbXSxcbiAgICBpbmNsdWRlQXJnOiBzdHJpbmcgfCBzdHJpbmdbXSA9IFtcbiAgICAgIFwicHJvbXB0c1wiLFxuICAgICAgXCJzdHlsZWQtc3RyaW5nLWJ1aWxkZXJcIixcbiAgICAgIFwidHlwZWQtb2JqZWN0LWFjY3VtdWxhdG9yXCIsXG4gICAgICBcIkBkZWNhZi10cy9sb2dnaW5nXCIsXG4gICAgXVxuICApIHtcbiAgICAvLyBSdW4gYSBUeXBlU2NyaXB0LW9ubHkgZGlhZ25vc3RpYyBjaGVjayBmb3IgdGhlIGJ1bmRsaW5nIGNvbmZpZ3VyYXRpb24gYW5kIGZhaWwgZmFzdCBvbiBhbnkgZXJyb3JzLlxuICAgIGF3YWl0IHRoaXMuY2hlY2tUc0RpYWdub3N0aWNzKGlzRGV2LCBtb2RlLCB0cnVlKTtcbiAgICBjb25zdCBpc0VzbSA9IG1vZGUgPT09IE1vZGVzLkVTTTtcbiAgICBjb25zdCBwa2dOYW1lID0gdGhpcy5wa2dOYW1lO1xuICAgIGNvbnN0IGxvZyA9IHRoaXMubG9nO1xuXG4gICAgLy8gbm9ybWFsaXplIGluY2x1ZGUgYW5kIGV4dGVybmFsc1xuICAgIGNvbnN0IGluY2x1ZGUgPSBBcnJheS5mcm9tKFxuICAgICAgbmV3IFNldChbLi4uKHBhcnNlTGlzdChpbmNsdWRlQXJnKSBhcyBzdHJpbmdbXSldKVxuICAgICk7XG4gICAgbGV0IGV4dGVybmFsc0xpc3QgPSBwYXJzZUxpc3QoZXh0ZXJuYWxzQXJnKTtcbiAgICBpZiAoZXh0ZXJuYWxzTGlzdC5sZW5ndGggPT09IDApIHtcbiAgICAgIC8vIGlmIG5vIGV4dGVybmFscyBzcGVjaWZpZWQsIGxpc3QgdG9wLWxldmVsIHBhY2thZ2VzIGluIG5vZGVfbW9kdWxlcyAoZXhwYW5kIHNjb3BlcylcbiAgICAgIHRyeSB7XG4gICAgICAgIGV4dGVybmFsc0xpc3QgPSBsaXN0Tm9kZU1vZHVsZXNQYWNrYWdlcyhcbiAgICAgICAgICBwYXRoLmpvaW4ocHJvY2Vzcy5jd2QoKSwgXCJub2RlX21vZHVsZXNcIilcbiAgICAgICAgKTtcbiAgICAgIH0gY2F0Y2gge1xuICAgICAgICAvLyBmYWxsYmFjayB0byBwYWNrYWdlLmpzb24gZGVwZW5kZW5jaWVzIGlmIGxpc3RpbmcgZmFpbHMgb3IgeWllbGRzIG5vdGhpbmdcbiAgICAgIH1cbiAgICAgIGlmICghZXh0ZXJuYWxzTGlzdCB8fCBleHRlcm5hbHNMaXN0Lmxlbmd0aCA9PT0gMCkge1xuICAgICAgICBleHRlcm5hbHNMaXN0ID0gZ2V0UGFja2FnZURlcGVuZGVuY2llcygpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGNvbnN0IGV4dCA9IEFycmF5LmZyb20oXG4gICAgICBuZXcgU2V0KFtcbiAgICAgICAgLy8gYnVpbHRpbnMgYW5kIGFsd2F5cyBleHRlcm5hbCBydW50aW1lIGRlcHNcbiAgICAgICAgLi4uKGZ1bmN0aW9uIGJ1aWx0aW5MaXN0KCk6IHN0cmluZ1tdIHtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgcmV0dXJuIChcbiAgICAgICAgICAgICAgQXJyYXkuaXNBcnJheShidWlsdGluTW9kdWxlcykgPyBidWlsdGluTW9kdWxlcyA6IFtdXG4gICAgICAgICAgICApIGFzIHN0cmluZ1tdO1xuICAgICAgICAgIH0gY2F0Y2gge1xuICAgICAgICAgICAgLy8gZmFsbGJhY2sgdG8gYSByZWFzb25hYmxlIHN1YnNldCBpZiBgYnVpbHRpbk1vZHVsZXNgIGlzIHVuYXZhaWxhYmxlXG4gICAgICAgICAgICByZXR1cm4gW1xuICAgICAgICAgICAgICBcImZzXCIsXG4gICAgICAgICAgICAgIFwicGF0aFwiLFxuICAgICAgICAgICAgICBcInByb2Nlc3NcIixcbiAgICAgICAgICAgICAgXCJjaGlsZF9wcm9jZXNzXCIsXG4gICAgICAgICAgICAgIFwidXRpbFwiLFxuICAgICAgICAgICAgICBcImh0dHBzXCIsXG4gICAgICAgICAgICAgIFwiaHR0cFwiLFxuICAgICAgICAgICAgICBcIm9zXCIsXG4gICAgICAgICAgICAgIFwic3RyZWFtXCIsXG4gICAgICAgICAgICAgIFwiY3J5cHRvXCIsXG4gICAgICAgICAgICAgIFwiemxpYlwiLFxuICAgICAgICAgICAgICBcIm5ldFwiLFxuICAgICAgICAgICAgICBcInRsc1wiLFxuICAgICAgICAgICAgICBcInVybFwiLFxuICAgICAgICAgICAgICBcInF1ZXJ5c3RyaW5nXCIsXG4gICAgICAgICAgICAgIFwiYXNzZXJ0XCIsXG4gICAgICAgICAgICAgIFwiZXZlbnRzXCIsXG4gICAgICAgICAgICAgIFwidHR5XCIsXG4gICAgICAgICAgICAgIFwiZG5zXCIsXG4gICAgICAgICAgICAgIFwicXVlcnlzdHJpbmdcIixcbiAgICAgICAgICAgIF07XG4gICAgICAgICAgfVxuICAgICAgICB9KSgpLFxuICAgICAgICAuLi5leHRlcm5hbHNMaXN0LFxuICAgICAgXSlcbiAgICApO1xuXG4gICAgLy8gRm9yIHBsdWdpbi10eXBlc2NyaXB0IHdlIHdhbnQgaXQgdG8gZW1pdCBzb3VyY2UgbWFwcyAobm90IGlubGluZSkgc28gUm9sbHVwIGNhblxuICAgIC8vIGRlY2lkZSB3aGV0aGVyIHRvIGlubGluZSBvciBlbWl0IGV4dGVybmFsIGZpbGVzLiBUaGUgUm9sbHVwIG91dHB1dC5zb3VyY2VtYXBcbiAgICAvLyBjb250cm9scyBmaW5hbCBtYXAgcGxhY2VtZW50LiBEbyBOT1Qgc2V0IGEgbm9uLXN0YW5kYXJkIGBzb3VyY2VtYXBgIGZpZWxkIG9uXG4gICAgLy8gdGhlIHJvbGx1cCBpbnB1dCBvcHRpb25zIChSb2xsdXAgd2lsbCByZWplY3QgaXQpLlxuICAgIGNvbnN0IHJvbGx1cFNvdXJjZU1hcE91dHB1dDogZmFsc2UgfCB0cnVlIHwgXCJpbmxpbmVcIiB8IFwiaGlkZGVuXCIgPSBpc0RldlxuICAgICAgPyBcImlubGluZVwiXG4gICAgICA6IHRydWU7XG5cbiAgICBjb25zdCBwbHVnaW5zID0gW1xuICAgICAgdHlwZXNjcmlwdCh7XG4gICAgICAgIGNvbXBpbGVyT3B0aW9uczoge1xuICAgICAgICAgIG1vZHVsZTogXCJlc25leHRcIixcbiAgICAgICAgICBkZWNsYXJhdGlvbjogZmFsc2UsXG4gICAgICAgICAgb3V0RGlyOiBpc0xpYiA/IFwiYmluXCIgOiBcImRpc3RcIixcbiAgICAgICAgICAvLyBGb3IgZGV2IGJ1bmRsZXMgZW1pdCBpbmxpbmUgc291cmNlIG1hcHMgKG5vIHNlcGFyYXRlIC5tYXAgZmlsZXMpLlxuICAgICAgICAgIC8vIEZvciBwcm9kIGJ1bmRsZXMgZW1pdCBleHRlcm5hbCBtYXBzIHNvIFJvbGx1cCBjYW4gd3JpdGUgdGhlbSB0byBkaXNrLlxuICAgICAgICAgIHNvdXJjZU1hcDogaXNEZXYgPyBmYWxzZSA6IHRydWUsXG4gICAgICAgICAgaW5saW5lU291cmNlTWFwOiBpc0RldiA/IHRydWUgOiBmYWxzZSxcbiAgICAgICAgICBpbmxpbmVTb3VyY2VzOiBpc0RldiA/IHRydWUgOiBmYWxzZSxcbiAgICAgICAgfSxcbiAgICAgICAgaW5jbHVkZTogW1wic3JjLyoqLyoudHNcIl0sXG4gICAgICAgIGV4Y2x1ZGU6IFtcIm5vZGVfbW9kdWxlc1wiLCBcIioqLyouc3BlYy50c1wiXSxcbiAgICAgICAgdHNjb25maWc6IFwiLi90c2NvbmZpZy5qc29uXCIsXG4gICAgICB9KSxcbiAgICAgIGpzb24oKSxcbiAgICBdO1xuXG4gICAgaWYgKGlzTGliKSB7XG4gICAgICBwbHVnaW5zLnB1c2goXG4gICAgICAgIGNvbW1vbmpzKHtcbiAgICAgICAgICBpbmNsdWRlOiBbXSxcbiAgICAgICAgICBleGNsdWRlOiBleHRlcm5hbHNMaXN0LFxuICAgICAgICB9KSxcbiAgICAgICAgbm9kZVJlc29sdmUoe1xuICAgICAgICAgIHJlc29sdmVPbmx5OiBpbmNsdWRlLFxuICAgICAgICB9KVxuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyBwcm9kdWN0aW9uIG1pbmlmaWNhdGlvbjogYWRkIHRlcnNlciBsYXN0IHNvIGl0IHNlZXMgcHJpb3Igc291cmNlIG1hcHNcbiAgICB0cnkge1xuICAgICAgY29uc3QgdGVyc2VyTW9kOiBhbnkgPSBhd2FpdCBpbXBvcnQoXCJAcm9sbHVwL3BsdWdpbi10ZXJzZXJcIik7XG4gICAgICBjb25zdCB0ZXJzZXJGbiA9XG4gICAgICAgICh0ZXJzZXJNb2QgJiYgdGVyc2VyTW9kLnRlcnNlcikgfHwgdGVyc2VyTW9kLmRlZmF1bHQgfHwgdGVyc2VyTW9kO1xuXG4gICAgICBjb25zdCB0ZXJzZXJPcHRpb25zRGV2OiBhbnkgPSB7XG4gICAgICAgIHBhcnNlOiB7IGVjbWE6IDIwMjAgfSxcbiAgICAgICAgY29tcHJlc3M6IGZhbHNlLFxuICAgICAgICBtYW5nbGU6IGZhbHNlLFxuICAgICAgICBmb3JtYXQ6IHtcbiAgICAgICAgICBjb21tZW50czogZmFsc2UsXG4gICAgICAgICAgYmVhdXRpZnk6IHRydWUsXG4gICAgICAgIH0sXG4gICAgICB9O1xuXG4gICAgICBjb25zdCB0ZXJzZXJPcHRpb25zUHJvZDogYW55ID0ge1xuICAgICAgICBwYXJzZTogeyBlY21hOiAyMDIwIH0sXG4gICAgICAgIGNvbXByZXNzOiB7XG4gICAgICAgICAgZWNtYTogMjAyMCxcbiAgICAgICAgICBwYXNzZXM6IDUsXG4gICAgICAgICAgZHJvcF9jb25zb2xlOiB0cnVlLFxuICAgICAgICAgIGRyb3BfZGVidWdnZXI6IHRydWUsXG4gICAgICAgICAgdG9wbGV2ZWw6IHRydWUsXG4gICAgICAgICAgbW9kdWxlOiBpc0VzbSxcbiAgICAgICAgICB1bnNhZmU6IHRydWUsXG4gICAgICAgICAgdW5zYWZlX2Fycm93czogdHJ1ZSxcbiAgICAgICAgICB1bnNhZmVfY29tcHM6IHRydWUsXG4gICAgICAgICAgY29sbGFwc2VfdmFyczogdHJ1ZSxcbiAgICAgICAgICByZWR1Y2VfZnVuY3M6IHRydWUsXG4gICAgICAgICAgcmVkdWNlX3ZhcnM6IHRydWUsXG4gICAgICAgIH0sXG4gICAgICAgIG1hbmdsZToge1xuICAgICAgICAgIHRvcGxldmVsOiB0cnVlLFxuICAgICAgICB9LFxuICAgICAgICBmb3JtYXQ6IHtcbiAgICAgICAgICBjb21tZW50czogZmFsc2UsXG4gICAgICAgICAgYXNjaWlfb25seTogdHJ1ZSxcbiAgICAgICAgfSxcbiAgICAgICAgdG9wbGV2ZWw6IHRydWUsXG4gICAgICB9O1xuXG4gICAgICBwbHVnaW5zLnB1c2godGVyc2VyRm4oaXNEZXYgPyB0ZXJzZXJPcHRpb25zRGV2IDogdGVyc2VyT3B0aW9uc1Byb2QpKTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIC8vIGlmIHRlcnNlciBpc24ndCBhdmFpbGFibGUsIGlnbm9yZVxuICAgIH1cblxuICAgIGNvbnN0IGlucHV0OiBJbnB1dE9wdGlvbnMgPSB7XG4gICAgICBpbnB1dDogZW50cnlGaWxlLFxuICAgICAgcGx1Z2luczogcGx1Z2lucyxcbiAgICAgIGV4dGVybmFsOiBleHQsXG4gICAgICBvbndhcm46IHVuZGVmaW5lZCxcbiAgICAgIC8vIGVuYWJsZSB0cmVlLXNoYWtpbmcgZm9yIHByb2R1Y3Rpb24gYnVuZGxlc1xuICAgICAgdHJlZXNoYWtlOiAhaXNEZXYsXG4gICAgfSBhcyBhbnk7XG5cbiAgICAvLyBwcmVwYXJlIG91dHB1dCBnbG9iYWxzIG1hcHBpbmcgZm9yIGV4dGVybmFsc1xuICAgIGNvbnN0IGdsb2JhbHM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7fTtcbiAgICAvLyBpbmNsdWRlIGFsbCBleHRlcm5hbHMgYW5kIGJ1aWx0aW5zIChleHQpIHNvIFJvbGx1cCB3b24ndCBndWVzcyBuYW1lcyBmb3IgYnVpbHRpbnNcbiAgICBleHQuZm9yRWFjaCgoZSkgPT4ge1xuICAgICAgZ2xvYmFsc1tlXSA9IHBhY2thZ2VUb0dsb2JhbChlKTtcbiAgICB9KTtcblxuICAgIGNvbnN0IG91dHB1dHM6IE91dHB1dE9wdGlvbnNbXSA9IFtcbiAgICAgIHtcbiAgICAgICAgZmlsZTogYCR7aXNMaWIgPyBcImJpbi9cIiA6IFwiZGlzdC9cIn0ke25hbWVPdmVycmlkZSA/IG5hbWVPdmVycmlkZSA6IGAuYnVuZGxlLiR7IWlzRGV2ID8gXCJtaW5cIiA6IFwiXCJ9YH0ke2lzRXNtID8gXCIuanNcIiA6IFwiLmNqc1wifWAsXG4gICAgICAgIGZvcm1hdDogaXNMaWIgPyBcImNqc1wiIDogaXNFc20gPyBcImVzbVwiIDogXCJ1bWRcIixcbiAgICAgICAgbmFtZTogcGtnTmFtZSxcbiAgICAgICAgZXNNb2R1bGU6IGlzRXNtLFxuICAgICAgICAvLyBvdXRwdXQgc291cmNlbWFwOiBpbmxpbmUgZm9yIGRldiwgZXh0ZXJuYWwgZm9yIHByb2RcbiAgICAgICAgc291cmNlbWFwOiByb2xsdXBTb3VyY2VNYXBPdXRwdXQsXG4gICAgICAgIGdsb2JhbHM6IGdsb2JhbHMsXG4gICAgICAgIGV4cG9ydHM6IFwiYXV0b1wiLFxuICAgICAgfSxcbiAgICBdO1xuXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGJ1bmRsZSA9IGF3YWl0IHJvbGx1cChpbnB1dCBhcyBhbnkpO1xuICAgICAgLy8gb25seSBsb2cgd2F0Y2hGaWxlcyBhdCB2ZXJib3NlIGxldmVsIHRvIGF2b2lkIG5vaXN5IGNvbnNvbGUgb3V0cHV0XG4gICAgICBsb2cudmVyYm9zZShidW5kbGUud2F0Y2hGaWxlcyk7XG4gICAgICBhc3luYyBmdW5jdGlvbiBnZW5lcmF0ZU91dHB1dHMoYnVuZGxlOiBSb2xsdXBCdWlsZCkge1xuICAgICAgICBmb3IgKGNvbnN0IG91dHB1dE9wdGlvbnMgb2Ygb3V0cHV0cykge1xuICAgICAgICAgIGF3YWl0IGJ1bmRsZS53cml0ZShvdXRwdXRPcHRpb25zKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBhd2FpdCBnZW5lcmF0ZU91dHB1dHMoYnVuZGxlKTtcbiAgICB9IGNhdGNoIChlOiB1bmtub3duKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYEZhaWxlZCB0byBidW5kbGU6ICR7ZX1gKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGJ1aWxkQnlFbnYoXG4gICAgZW50cnlGaWxlOiBzdHJpbmcgPSBcIi4vc3JjL2luZGV4LnRzXCIsXG4gICAgaXNEZXY6IGJvb2xlYW4sXG4gICAgbW9kZTogQnVpbGRNb2RlID0gQnVpbGRNb2RlLkFMTCxcbiAgICBpbmNsdWRlc0FyZz86IHN0cmluZyB8IHN0cmluZ1tdLFxuICAgIGV4dGVybmFsc0FyZz86IHN0cmluZyB8IHN0cmluZ1tdXG4gICkge1xuICAgIC8vIG5vdGU6IGluY2x1ZGVzIGFuZCBleHRlcm5hbHMgd2lsbCBiZSBwYXNzZWQgdGhyb3VnaCBmcm9tIHJ1bigpIGludG8gdGhpcyBtZXRob2QgYnkgY2FsbGVyc1xuICAgIHRyeSB7XG4gICAgICBkZWxldGVQYXRoKFwibGliXCIpO1xuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnVzZWQtdmFyc1xuICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgIC8vIGRvIG5vdGhpbmdcbiAgICB9XG4gICAgdHJ5IHtcbiAgICAgIGRlbGV0ZVBhdGgoXCJkaXN0XCIpO1xuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnVzZWQtdmFyc1xuICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgIC8vIGRvIG5vdGhpbmdcbiAgICB9XG5cbiAgICBpZiAoW0J1aWxkTW9kZS5BTEwsIEJ1aWxkTW9kZS5CVUlMRF0uaW5jbHVkZXMobW9kZSkpIHtcbiAgICAgIGZzLm1rZGlyU3luYyhcImxpYlwiKTtcbiAgICAgIGF3YWl0IHRoaXMuYnVpbGQoaXNEZXYsIE1vZGVzLkVTTSk7XG4gICAgICBhd2FpdCB0aGlzLmJ1aWxkKGlzRGV2LCBNb2Rlcy5DSlMpO1xuICAgICAgdGhpcy5wYXRjaEZpbGVzKFwibGliXCIpO1xuICAgIH1cblxuICAgIGlmIChbQnVpbGRNb2RlLkFMTCwgQnVpbGRNb2RlLkJVTkRMRV0uaW5jbHVkZXMobW9kZSkpIHtcbiAgICAgIGZzLm1rZGlyU3luYyhcImRpc3RcIik7XG4gICAgICBhd2FpdCB0aGlzLmJ1bmRsZShcbiAgICAgICAgTW9kZXMuRVNNLFxuICAgICAgICBpc0RldixcbiAgICAgICAgZmFsc2UsXG4gICAgICAgIGVudHJ5RmlsZSB8fCBcIi4vc3JjL2luZGV4LnRzXCIsXG4gICAgICAgIHRoaXMucGtnTmFtZSxcbiAgICAgICAgZXh0ZXJuYWxzQXJnLFxuICAgICAgICBpbmNsdWRlc0FyZ1xuICAgICAgKTtcbiAgICAgIGF3YWl0IHRoaXMuYnVuZGxlKFxuICAgICAgICBNb2Rlcy5DSlMsXG4gICAgICAgIGlzRGV2LFxuICAgICAgICBmYWxzZSxcbiAgICAgICAgZW50cnlGaWxlIHx8IFwiLi9zcmMvaW5kZXgudHNcIixcbiAgICAgICAgdGhpcy5wa2dOYW1lLFxuICAgICAgICBleHRlcm5hbHNBcmcsXG4gICAgICAgIGluY2x1ZGVzQXJnXG4gICAgICApO1xuICAgICAgdGhpcy5wYXRjaEZpbGVzKFwiZGlzdFwiKTtcbiAgICB9XG5cbiAgICB0aGlzLmNvcHlBc3NldHMoTW9kZXMuQ0pTKTtcbiAgICB0aGlzLmNvcHlBc3NldHMoTW9kZXMuRVNNKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gQnVpbGRzIHRoZSBwcm9qZWN0IGZvciBkZXZlbG9wbWVudC5cbiAgICogQHN1bW1hcnkgVGhpcyBtZXRob2QgcnVucyB0aGUgYnVpbGQgcHJvY2VzcyB3aXRoIGRldmVsb3BtZW50LXNwZWNpZmljIGNvbmZpZ3VyYXRpb25zLlxuICAgKiBAcGFyYW0ge0J1aWxkTW9kZX0gW21vZGU9QnVpbGRNb2RlLkFMTF0gLSBUaGUgYnVpbGQgbW9kZSAoYnVpbGQsIGJ1bmRsZSwgb3IgYWxsKS5cbiAgICogQHBhcmFtIHtzdHJpbmd8c3RyaW5nW119IFtpbmNsdWRlc0FyZ10gLSBBIGxpc3Qgb2YgZGVwZW5kZW5jaWVzIHRvIGluY2x1ZGUuXG4gICAqIEBwYXJhbSB7c3RyaW5nfHN0cmluZ1tdfSBbZXh0ZXJuYWxzQXJnXSAtIEEgbGlzdCBvZiBleHRlcm5hbCBkZXBlbmRlbmNpZXMuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fVxuICAgKi9cbiAgYXN5bmMgYnVpbGREZXYoXG4gICAgZW50cnlGaWxlOiBzdHJpbmcgPSBcIi4vc3JjL2luZGV4LnRzXCIsXG4gICAgbW9kZTogQnVpbGRNb2RlID0gQnVpbGRNb2RlLkFMTCxcbiAgICBpbmNsdWRlc0FyZz86IHN0cmluZyB8IHN0cmluZ1tdLFxuICAgIGV4dGVybmFsc0FyZz86IHN0cmluZyB8IHN0cmluZ1tdXG4gICkge1xuICAgIHJldHVybiB0aGlzLmJ1aWxkQnlFbnYoZW50cnlGaWxlLCB0cnVlLCBtb2RlLCBpbmNsdWRlc0FyZywgZXh0ZXJuYWxzQXJnKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gQnVpbGRzIHRoZSBwcm9qZWN0IGZvciBwcm9kdWN0aW9uLlxuICAgKiBAc3VtbWFyeSBUaGlzIG1ldGhvZCBydW5zIHRoZSBidWlsZCBwcm9jZXNzIHdpdGggcHJvZHVjdGlvbi1zcGVjaWZpYyBjb25maWd1cmF0aW9ucyxcbiAgICogaW5jbHVkaW5nIG1pbmlmaWNhdGlvbiBhbmQgb3RoZXIgb3B0aW1pemF0aW9ucy5cbiAgICogQHBhcmFtIHtCdWlsZE1vZGV9IFttb2RlPUJ1aWxkTW9kZS5BTExdIC0gVGhlIGJ1aWxkIG1vZGUgKGJ1aWxkLCBidW5kbGUsIG9yIGFsbCkuXG4gICAqIEBwYXJhbSB7c3RyaW5nfHN0cmluZ1tdfSBbaW5jbHVkZXNBcmddIC0gQSBsaXN0IG9mIGRlcGVuZGVuY2llcyB0byBpbmNsdWRlLlxuICAgKiBAcGFyYW0ge3N0cmluZ3xzdHJpbmdbXX0gW2V4dGVybmFsc0FyZ10gLSBBIGxpc3Qgb2YgZXh0ZXJuYWwgZGVwZW5kZW5jaWVzLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn1cbiAgICovXG4gIGFzeW5jIGJ1aWxkUHJvZChcbiAgICBlbnRyeUZpbGU6IHN0cmluZyA9IFwiLi9zcmMvaW5kZXgudHNcIixcbiAgICBtb2RlOiBCdWlsZE1vZGUgPSBCdWlsZE1vZGUuQUxMLFxuICAgIGluY2x1ZGVzQXJnPzogc3RyaW5nIHwgc3RyaW5nW10sXG4gICAgZXh0ZXJuYWxzQXJnPzogc3RyaW5nIHwgc3RyaW5nW11cbiAgKSB7XG4gICAgcmV0dXJuIHRoaXMuYnVpbGRCeUVudihlbnRyeUZpbGUsIGZhbHNlLCBtb2RlLCBpbmNsdWRlc0FyZywgZXh0ZXJuYWxzQXJnKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gR2VuZXJhdGVzIHRoZSBwcm9qZWN0IGRvY3VtZW50YXRpb24uXG4gICAqIEBzdW1tYXJ5IFRoaXMgbWV0aG9kIHVzZXMgSlNEb2MgYW5kIG90aGVyIHRvb2xzIHRvIGdlbmVyYXRlIEhUTUwgZG9jdW1lbnRhdGlvbiBmb3IgdGhlIHByb2plY3QuXG4gICAqIEl0IGFsc28gcGF0Y2hlcyB0aGUgUkVBRE1FLm1kIGZpbGUgd2l0aCB2ZXJzaW9uIGFuZCBwYWNrYWdlIHNpemUgaW5mb3JtYXRpb24uXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fVxuICAgKi9cbiAgYXN5bmMgYnVpbGREb2NzKCkge1xuICAgIGF3YWl0IHJ1bkNvbW1hbmQoYG5wbSBpbnN0YWxsIGJldHRlci1kb2NzIHRhZmZ5ZGJgKS5wcm9taXNlO1xuICAgIGF3YWl0IHJ1bkNvbW1hbmQoYG5weCBtYXJrZG93bi1pbmNsdWRlIC4vd29ya2RvY3MvcmVhZG1lLW1kLmpzb25gKS5wcm9taXNlO1xuICAgIGF3YWl0IHJ1bkNvbW1hbmQoXG4gICAgICBgbnB4IGpzZG9jIC1jIC4vd29ya2RvY3MvanNkb2NzLmpzb24gLXQgLi9ub2RlX21vZHVsZXMvYmV0dGVyLWRvY3NgXG4gICAgKS5wcm9taXNlO1xuICAgIGF3YWl0IHJ1bkNvbW1hbmQoYG5wbSByZW1vdmUgYmV0dGVyLWRvY3MgdGFmZnlkYmApLnByb21pc2U7XG4gICAgW1xuICAgICAge1xuICAgICAgICBzcmM6IFwid29ya2RvY3MvYXNzZXRzXCIsXG4gICAgICAgIGRlc3Q6IFwiLi9kb2NzL3dvcmtkb2NzL2Fzc2V0c1wiLFxuICAgICAgfSxcbiAgICAgIHtcbiAgICAgICAgc3JjOiBcIndvcmtkb2NzL3JlcG9ydHMvY292ZXJhZ2VcIixcbiAgICAgICAgZGVzdDogXCIuL2RvY3Mvd29ya2RvY3MvcmVwb3J0cy9jb3ZlcmFnZVwiLFxuICAgICAgfSxcbiAgICAgIHtcbiAgICAgICAgc3JjOiBcIndvcmtkb2NzL3JlcG9ydHMvaHRtbFwiLFxuICAgICAgICBkZXN0OiBcIi4vZG9jcy93b3JrZG9jcy9yZXBvcnRzL2h0bWxcIixcbiAgICAgIH0sXG4gICAgICB7XG4gICAgICAgIHNyYzogXCJ3b3JrZG9jcy9yZXNvdXJjZXNcIixcbiAgICAgICAgZGVzdDogXCIuL2RvY3Mvd29ya2RvY3MvcmVzb3VyY2VzXCIsXG4gICAgICB9LFxuICAgICAge1xuICAgICAgICBzcmM6IFwiTElDRU5TRS5tZFwiLFxuICAgICAgICBkZXN0OiBcIi4vZG9jcy9MSUNFTlNFLm1kXCIsXG4gICAgICB9LFxuICAgIF0uZm9yRWFjaCgoZikgPT4ge1xuICAgICAgY29uc3QgeyBzcmMsIGRlc3QgfSA9IGY7XG4gICAgICBjb3B5RmlsZShzcmMsIGRlc3QpO1xuICAgIH0pO1xuXG4gICAgLy8gcGF0Y2ggLi9SRUFETUUubWQgZmlsZSB0byByZXBsYWNlIHZlcnNpb24vcGFja2FnZS9wYWNrYWdlIHNpemUgc3RyaW5nc1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBzaXplS2IgPSBhd2FpdCBnZXRGaWxlU2l6ZVppcHBlZChcbiAgICAgICAgcGF0aC5yZXNvbHZlKHBhdGguam9pbihwcm9jZXNzLmN3ZCgpLCBcImRpc3RcIikpXG4gICAgICApO1xuICAgICAgdGhpcy5yZXBsYWNlbWVudHNbUEFDS0FHRV9TSVpFX1NUUklOR10gPSBgJHtzaXplS2J9IEtCYDtcbiAgICB9IGNhdGNoIHtcbiAgICAgIC8vIGlmIHdlIGNvdWxkbid0IGNvbXB1dGUgc2l6ZSwgbGVhdmUgcGxhY2Vob2xkZXIgb3Igc2V0IHRvIHVua25vd25cbiAgICAgIHRoaXMucmVwbGFjZW1lbnRzW1BBQ0tBR0VfU0laRV9TVFJJTkddID0gXCJ1bmtub3duXCI7XG4gICAgfVxuXG4gICAgLy8gUGF0Y2ggUkVBRE1FLm1kIGluIHByb2plY3Qgcm9vdFxuICAgIHRyeSB7XG4gICAgICBwYXRjaEZpbGUoXCIuL1JFQURNRS5tZFwiLCB0aGlzLnJlcGxhY2VtZW50cyk7XG4gICAgfSBjYXRjaCAoZTogdW5rbm93bikge1xuICAgICAgY29uc3QgbG9nID0gdGhpcy5sb2cuZm9yKHRoaXMuYnVpbGREb2NzIGFzIGFueSk7XG4gICAgICBsb2cudmVyYm9zZShgRmFpbGVkIHRvIHBhdGNoIFJFQURNRS5tZDogJHtlfWApO1xuICAgIH1cbiAgfVxuXG4gIHByb3RlY3RlZCBhc3luYyBydW48Uj4oXG4gICAgYW5zd2VyczogTG9nZ2luZ0NvbmZpZyAmXG4gICAgICB0eXBlb2YgRGVmYXVsdENvbW1hbmRWYWx1ZXMgJiB7IFtrIGluIGtleW9mIHR5cGVvZiBvcHRpb25zXTogdW5rbm93biB9XG4gICk6IFByb21pc2U8c3RyaW5nIHwgdm9pZCB8IFI+IHtcbiAgICBjb25zdCB7IGRldiwgcHJvZCwgZG9jcywgYnVpbGRNb2RlLCBpbmNsdWRlcywgZXh0ZXJuYWxzLCBlbnRyeSB9ID1cbiAgICAgIGFuc3dlcnMgYXMgYW55O1xuICAgIGlmIChkZXYpIHtcbiAgICAgIHJldHVybiBhd2FpdCB0aGlzLmJ1aWxkRGV2KFxuICAgICAgICBlbnRyeSB8fCBcIi4vc3JjL2luZGV4LnRzXCIsXG4gICAgICAgIGJ1aWxkTW9kZSBhcyBCdWlsZE1vZGUsXG4gICAgICAgIGluY2x1ZGVzLFxuICAgICAgICBleHRlcm5hbHNcbiAgICAgICk7XG4gICAgfVxuICAgIGlmIChwcm9kKSB7XG4gICAgICByZXR1cm4gYXdhaXQgdGhpcy5idWlsZFByb2QoXG4gICAgICAgIGVudHJ5IHx8IFwiLi9zcmMvaW5kZXgudHNcIixcbiAgICAgICAgYnVpbGRNb2RlIGFzIEJ1aWxkTW9kZSxcbiAgICAgICAgaW5jbHVkZXMsXG4gICAgICAgIGV4dGVybmFsc1xuICAgICAgKTtcbiAgICB9XG4gICAgaWYgKGRvY3MpIHtcbiAgICAgIHJldHVybiBhd2FpdCB0aGlzLmJ1aWxkRG9jcygpO1xuICAgIH1cbiAgfVxufVxuIiwiLyogaXN0YW5idWwgaWdub3JlIGZpbGUgKi9cbmltcG9ydCB7IHJ1bkNvbW1hbmQgfSBmcm9tIFwiLi4vLi4vdXRpbHMvdXRpbHNcIjtcbmltcG9ydCB7IE5vQ0lGTGFnLCBTZW1WZXJzaW9uLCBTZW1WZXJzaW9uUmVnZXggfSBmcm9tIFwiLi4vLi4vdXRpbHMvY29uc3RhbnRzXCI7XG5pbXBvcnQgeyBVc2VySW5wdXQgfSBmcm9tIFwiLi4vLi4vaW5wdXQvaW5wdXRcIjtcbmltcG9ydCB7IENvbW1hbmQgfSBmcm9tIFwiLi4vY29tbWFuZFwiO1xuaW1wb3J0IHsgRGVmYXVsdENvbW1hbmRWYWx1ZXMgfSBmcm9tIFwiLi4vaW5kZXhcIjtcbmltcG9ydCB7IExvZ2dpbmdDb25maWcgfSBmcm9tIFwiQGRlY2FmLXRzL2xvZ2dpbmdcIjtcblxuY29uc3Qgb3B0aW9ucyA9IHtcbiAgY2k6IHtcbiAgICB0eXBlOiBcImJvb2xlYW5cIixcbiAgICBkZWZhdWx0OiB0cnVlLFxuICB9LFxuICBtZXNzYWdlOiB7XG4gICAgdHlwZTogXCJzdHJpbmdcIixcbiAgICBzaG9ydDogXCJtXCIsXG4gIH0sXG4gIHRhZzoge1xuICAgIHR5cGU6IFwic3RyaW5nXCIsXG4gICAgc2hvcnQ6IFwidFwiLFxuICAgIGRlZmF1bHQ6IHVuZGVmaW5lZCxcbiAgfSxcbn07XG5cbi8qKlxuICogQGNsYXNzIFJlbGVhc2VTY3JpcHRcbiAqIEBleHRlbmRzIHtDb21tYW5kfVxuICogQGNhdmVnb3J5IHNjcmlwdHNcbiAqIEBkZXNjcmlwdGlvbiBBIGNvbW1hbmQtbGluZSBzY3JpcHQgZm9yIG1hbmFnaW5nIHJlbGVhc2VzIGFuZCB2ZXJzaW9uIHVwZGF0ZXMuXG4gKiBAc3VtbWFyeSBUaGlzIHNjcmlwdCBhdXRvbWF0ZXMgdGhlIHByb2Nlc3Mgb2YgY3JlYXRpbmcgYW5kIHB1c2hpbmcgbmV3IHJlbGVhc2VzLiBJdCBoYW5kbGVzIHZlcnNpb24gdXBkYXRlcyxcbiAqIGNvbW1pdCBtZXNzYWdlcywgYW5kIG9wdGlvbmFsbHkgcHVibGlzaGVzIHRvIE5QTS4gVGhlIHNjcmlwdCBzdXBwb3J0cyBzZW1hbnRpYyB2ZXJzaW9uaW5nIGFuZCBjYW4gd29yayBpbiBib3RoIENJIGFuZCBub24tQ0kgZW52aXJvbm1lbnRzLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gQ29uZmlndXJhdGlvbiBvcHRpb25zIGZvciB0aGUgc2NyaXB0XG4gKiBAcGFyYW0ge2Jvb2xlYW59IG9wdGlvbnMuY2kgLSBXaGV0aGVyIHRoZSBzY3JpcHQgaXMgcnVubmluZyBpbiBhIENJIGVudmlyb25tZW50IChkZWZhdWx0OiB0cnVlKVxuICogQHBhcmFtIHtzdHJpbmd9IG9wdGlvbnMubWVzc2FnZSAtIFRoZSByZWxlYXNlIG1lc3NhZ2UgKHNob3J0OiAnbScpXG4gKiBAcGFyYW0ge3N0cmluZ30gb3B0aW9ucy50YWcgLSBUaGUgdmVyc2lvbiB0YWcgdG8gdXNlIChzaG9ydDogJ3QnLCBkZWZhdWx0OiB1bmRlZmluZWQpXG4gKi9cbmV4cG9ydCBjbGFzcyBSZWxlYXNlU2NyaXB0IGV4dGVuZHMgQ29tbWFuZDx0eXBlb2Ygb3B0aW9ucywgdm9pZD4ge1xuICBjb25zdHJ1Y3RvcigpIHtcbiAgICBzdXBlcihcIlJlbGVhc2VTY3JpcHRcIiwgb3B0aW9ucyk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFByZXBhcmVzIHRoZSB2ZXJzaW9uIGZvciB0aGUgcmVsZWFzZS5cbiAgICogQHN1bW1hcnkgVGhpcyBtZXRob2QgdmFsaWRhdGVzIHRoZSBwcm92aWRlZCB0YWcgb3IgcHJvbXB0cyB0aGUgdXNlciBmb3IgYSBuZXcgb25lIGlmIG5vdCBwcm92aWRlZCBvciBpbnZhbGlkLlxuICAgKiBJdCBhbHNvIGRpc3BsYXlzIHRoZSBsYXRlc3QgZ2l0IHRhZ3MgZm9yIHJlZmVyZW5jZS5cbiAgICogQHBhcmFtIHtzdHJpbmd9IHRhZyAtIFRoZSB2ZXJzaW9uIHRhZyB0byBwcmVwYXJlXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZz59IFRoZSBwcmVwYXJlZCB2ZXJzaW9uIHRhZ1xuICAgKlxuICAgKiBAbWVybWFpZFxuICAgKiBzZXF1ZW5jZURpYWdyYW1cbiAgICogICBwYXJ0aWNpcGFudCBSIGFzIFJlbGVhc2VTY3JpcHRcbiAgICogICBwYXJ0aWNpcGFudCBUIGFzIFRlc3RWZXJzaW9uXG4gICAqICAgcGFydGljaXBhbnQgVSBhcyBVc2VySW5wdXRcbiAgICogICBwYXJ0aWNpcGFudCBHIGFzIEdpdFxuICAgKiAgIFItPj5UOiB0ZXN0VmVyc2lvbih0YWcpXG4gICAqICAgYWx0IHRhZyBpcyB2YWxpZFxuICAgKiAgICAgVC0tPj5SOiByZXR1cm4gdGFnXG4gICAqICAgZWxzZSB0YWcgaXMgaW52YWxpZCBvciBub3QgcHJvdmlkZWRcbiAgICogICAgIFItPj5HOiBMaXN0IGxhdGVzdCBnaXQgdGFnc1xuICAgKiAgICAgUi0+PlU6IFByb21wdCBmb3IgbmV3IHRhZ1xuICAgKiAgICAgVS0tPj5SOiByZXR1cm4gbmV3IHRhZ1xuICAgKiAgIGVuZFxuICAgKi9cbiAgYXN5bmMgcHJlcGFyZVZlcnNpb24odGFnPzogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBjb25zdCBsb2cgPSB0aGlzLmxvZy5mb3IodGhpcy5wcmVwYXJlVmVyc2lvbik7XG4gICAgdGFnID0gdGhpcy50ZXN0VmVyc2lvbigodGFnIGFzIHN0cmluZykgfHwgXCJcIik7XG4gICAgaWYgKCF0YWcpIHtcbiAgICAgIGxvZy52ZXJib3NlKFwiTm8gcmVsZWFzZSBtZXNzYWdlIHByb3ZpZGVkLiBQcm9tcHRpbmcgZm9yIG9uZTpcIik7XG4gICAgICBsb2cuaW5mbyhgTGlzdGluZyBsYXRlc3QgZ2l0IHRhZ3M6YCk7XG4gICAgICBhd2FpdCBydW5Db21tYW5kKFwiZ2l0IHRhZyAtLXNvcnQ9LXRhZ2dlcmRhdGUgfCBoZWFkIC1uIDVcIikucHJvbWlzZTtcbiAgICAgIHJldHVybiBhd2FpdCBVc2VySW5wdXQuaW5zaXN0Rm9yVGV4dChcbiAgICAgICAgXCJ0YWdcIixcbiAgICAgICAgXCJFbnRlciB0aGUgbmV3IHRhZyBudW1iZXIgKGFjY2VwdHMgdiouKi4qWy0uLi5dKVwiLFxuICAgICAgICAodmFsKSA9PlxuICAgICAgICAgICEhdmFsLnRvU3RyaW5nKCkubWF0Y2goL152WzAtOV0rXFwuWzAtOV0rLlswLTldKygtWzAtOWEtekEtWi1dKyk/JC8pXG4gICAgICApO1xuICAgIH1cbiAgICByZXR1cm4gdGFnO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBUZXN0cyBpZiB0aGUgcHJvdmlkZWQgdmVyc2lvbiBpcyB2YWxpZC5cbiAgICogQHN1bW1hcnkgVGhpcyBtZXRob2QgY2hlY2tzIGlmIHRoZSB2ZXJzaW9uIGlzIGEgdmFsaWQgc2VtYW50aWMgdmVyc2lvbiBvciBhIHByZWRlZmluZWQgdXBkYXRlIHR5cGUgKFBBVENILCBNSU5PUiwgTUFKT1IpLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gdmVyc2lvbiAtIFRoZSB2ZXJzaW9uIHRvIHRlc3RcbiAgICogQHJldHVybnMge3N0cmluZyB8IHVuZGVmaW5lZH0gVGhlIHZhbGlkYXRlZCB2ZXJzaW9uIG9yIHVuZGVmaW5lZCBpZiBpbnZhbGlkXG4gICAqL1xuICB0ZXN0VmVyc2lvbih2ZXJzaW9uOiBzdHJpbmcpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICAgIGNvbnN0IGxvZyA9IHRoaXMubG9nLmZvcih0aGlzLnRlc3RWZXJzaW9uKTtcbiAgICB2ZXJzaW9uID0gdmVyc2lvbi50cmltKCkudG9Mb3dlckNhc2UoKTtcbiAgICBzd2l0Y2ggKHZlcnNpb24pIHtcbiAgICAgIGNhc2UgU2VtVmVyc2lvbi5QQVRDSDpcbiAgICAgIGNhc2UgU2VtVmVyc2lvbi5NSU5PUjpcbiAgICAgIGNhc2UgU2VtVmVyc2lvbi5NQUpPUjpcbiAgICAgICAgbG9nLnZlcmJvc2UoYFVzaW5nIHByb3ZpZGVkIFNlbVZlciB1cGRhdGU6ICR7dmVyc2lvbn1gLCAxKTtcbiAgICAgICAgcmV0dXJuIHZlcnNpb247XG4gICAgICBkZWZhdWx0OlxuICAgICAgICBsb2cudmVyYm9zZShcbiAgICAgICAgICBgVGVzdGluZyBwcm92aWRlZCB2ZXJzaW9uIGZvciBTZW1WZXIgY29tcGF0aWJpbGl0eTogJHt2ZXJzaW9ufWAsXG4gICAgICAgICAgMVxuICAgICAgICApO1xuICAgICAgICBpZiAoIW5ldyBSZWdFeHAoU2VtVmVyc2lvblJlZ2V4KS50ZXN0KHZlcnNpb24pKSB7XG4gICAgICAgICAgbG9nLmRlYnVnKGBJbnZhbGlkIHZlcnNpb24gbnVtYmVyOiAke3ZlcnNpb259YCk7XG4gICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgfVxuICAgICAgICBsb2cudmVyYm9zZShgdmVyc2lvbiBhcHByb3ZlZDogJHt2ZXJzaW9ufWAsIDEpO1xuICAgICAgICByZXR1cm4gdmVyc2lvbjtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFByZXBhcmVzIHRoZSByZWxlYXNlIG1lc3NhZ2UuXG4gICAqIEBzdW1tYXJ5IFRoaXMgbWV0aG9kIGVpdGhlciByZXR1cm5zIHRoZSBwcm92aWRlZCBtZXNzYWdlIG9yIHByb21wdHMgdGhlIHVzZXIgZm9yIGEgbmV3IG9uZSBpZiBub3QgcHJvdmlkZWQuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbbWVzc2FnZV0gLSBUaGUgcmVsZWFzZSBtZXNzYWdlXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZz59IFRoZSBwcmVwYXJlZCByZWxlYXNlIG1lc3NhZ2VcbiAgICovXG4gIGFzeW5jIHByZXBhcmVNZXNzYWdlKG1lc3NhZ2U/OiBzdHJpbmcpIHtcbiAgICBjb25zdCBsb2cgPSB0aGlzLmxvZy5mb3IodGhpcy5wcmVwYXJlTWVzc2FnZSk7XG4gICAgaWYgKCFtZXNzYWdlKSB7XG4gICAgICBsb2cudmVyYm9zZShcIk5vIHJlbGVhc2UgbWVzc2FnZSBwcm92aWRlZC4gUHJvbXB0aW5nIGZvciBvbmVcIik7XG4gICAgICByZXR1cm4gYXdhaXQgVXNlcklucHV0Lmluc2lzdEZvclRleHQoXG4gICAgICAgIFwibWVzc2FnZVwiLFxuICAgICAgICBcIldoYXQgc2hvdWxkIGJlIHRoZSByZWxlYXNlIG1lc3NhZ2UvdGlja2V0P1wiLFxuICAgICAgICAodmFsKSA9PiAhIXZhbCAmJiB2YWwudG9TdHJpbmcoKS5sZW5ndGggPiA1XG4gICAgICApO1xuICAgIH1cbiAgICByZXR1cm4gbWVzc2FnZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUnVucyB0aGUgcmVsZWFzZSBzY3JpcHQuXG4gICAqIEBzdW1tYXJ5IFRoaXMgbWV0aG9kIG9yY2hlc3RyYXRlcyB0aGUgZW50aXJlIHJlbGVhc2UgcHJvY2VzcywgaW5jbHVkaW5nIHZlcnNpb24gcHJlcGFyYXRpb24sIG1lc3NhZ2UgY3JlYXRpb24sXG4gICAqIGdpdCBvcGVyYXRpb25zLCBhbmQgbnBtIHB1Ymxpc2hpbmcgKGlmIG5vdCBpbiBDSSBlbnZpcm9ubWVudCkuXG4gICAqIEBwYXJhbSB7UGFyc2VBcmdzUmVzdWx0fSBhcmdzIC0gVGhlIHBhcnNlZCBjb21tYW5kLWxpbmUgYXJndW1lbnRzXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fVxuICAgKlxuICAgKiBAbWVybWFpZFxuICAgKiBzZXF1ZW5jZURpYWdyYW1cbiAgICogICBwYXJ0aWNpcGFudCBSIGFzIFJlbGVhc2VTY3JpcHRcbiAgICogICBwYXJ0aWNpcGFudCBWIGFzIFByZXBhcmVWZXJzaW9uXG4gICAqICAgcGFydGljaXBhbnQgTSBhcyBQcmVwYXJlTWVzc2FnZVxuICAgKiAgIHBhcnRpY2lwYW50IE4gYXMgTlBNXG4gICAqICAgcGFydGljaXBhbnQgRyBhcyBHaXRcbiAgICogICBwYXJ0aWNpcGFudCBVIGFzIFVzZXJJbnB1dFxuICAgKiAgIFItPj5WOiBwcmVwYXJlVmVyc2lvbih0YWcpXG4gICAqICAgUi0+Pk06IHByZXBhcmVNZXNzYWdlKG1lc3NhZ2UpXG4gICAqICAgUi0+Pk46IFJ1biBwcmVwYXJlLXJlbGVhc2Ugc2NyaXB0XG4gICAqICAgUi0+Pkc6IENoZWNrIGdpdCBzdGF0dXNcbiAgICogICBhbHQgY2hhbmdlcyBleGlzdFxuICAgKiAgICAgUi0+PlU6IEFzayBmb3IgY29uZmlybWF0aW9uXG4gICAqICAgICBVLS0+PlI6IENvbmZpcm1cbiAgICogICAgIFItPj5HOiBBZGQgYW5kIGNvbW1pdCBjaGFuZ2VzXG4gICAqICAgZW5kXG4gICAqICAgUi0+Pk46IFVwZGF0ZSBucG0gdmVyc2lvblxuICAgKiAgIFItPj5HOiBQdXNoIGNoYW5nZXMgYW5kIHRhZ3NcbiAgICogICBhbHQgbm90IENJIGVudmlyb25tZW50XG4gICAqICAgICBSLT4+TjogUHVibGlzaCB0byBucG1cbiAgICogICBlbmRcbiAgICovXG4gIGFzeW5jIHJ1bihcbiAgICBhcmdzOiBMb2dnaW5nQ29uZmlnICZcbiAgICAgIHR5cGVvZiBEZWZhdWx0Q29tbWFuZFZhbHVlcyAmIHsgW2sgaW4ga2V5b2YgdHlwZW9mIG9wdGlvbnNdOiB1bmtub3duIH1cbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgbGV0IHJlc3VsdDogYW55O1xuICAgIGNvbnN0IHsgY2kgfSA9IGFyZ3M7XG4gICAgbGV0IHsgdGFnLCBtZXNzYWdlIH0gPSBhcmdzO1xuICAgIHRhZyA9IGF3YWl0IHRoaXMucHJlcGFyZVZlcnNpb24odGFnIGFzIHN0cmluZyk7XG4gICAgbWVzc2FnZSA9IGF3YWl0IHRoaXMucHJlcGFyZU1lc3NhZ2UobWVzc2FnZSBhcyBzdHJpbmcpO1xuICAgIHJlc3VsdCA9IGF3YWl0IHJ1bkNvbW1hbmQoYG5wbSBydW4gcHJlcGFyZS1yZWxlYXNlIC0tICR7dGFnfSAke21lc3NhZ2V9YCwge1xuICAgICAgY3dkOiBwcm9jZXNzLmN3ZCgpLFxuICAgIH0pLnByb21pc2U7XG4gICAgcmVzdWx0ID0gYXdhaXQgcnVuQ29tbWFuZChcImdpdCBzdGF0dXMgLS1wb3JjZWxhaW5cIikucHJvbWlzZTtcbiAgICBhd2FpdCByZXN1bHQ7XG4gICAgaWYgKFxuICAgICAgcmVzdWx0LmxvZ3MubGVuZ3RoICYmXG4gICAgICAoYXdhaXQgVXNlcklucHV0LmFza0NvbmZpcm1hdGlvbihcbiAgICAgICAgXCJnaXQtY2hhbmdlc1wiLFxuICAgICAgICBcIkRvIHlvdSB3YW50IHRvIHB1c2ggdGhlIGNoYW5nZXMgdG8gdGhlIHJlbW90ZSByZXBvc2l0b3J5P1wiLFxuICAgICAgICB0cnVlXG4gICAgICApKVxuICAgICkge1xuICAgICAgYXdhaXQgcnVuQ29tbWFuZChcImdpdCBhZGQgLlwiKS5wcm9taXNlO1xuICAgICAgYXdhaXQgcnVuQ29tbWFuZChcbiAgICAgICAgYGdpdCBjb21taXQgLW0gXCIke3RhZ30gLSAke21lc3NhZ2V9IC0gYWZ0ZXIgcmVsZWFzZSBwcmVwYXJhdGlvbiR7Y2kgPyBcIlwiIDogTm9DSUZMYWd9XCJgXG4gICAgICApLnByb21pc2U7XG4gICAgfVxuICAgIGF3YWl0IHJ1bkNvbW1hbmQoXG4gICAgICBgbnBtIHZlcnNpb24gXCIke3RhZ31cIiAtbSBcIiR7bWVzc2FnZX0ke2NpID8gXCJcIiA6IE5vQ0lGTGFnfVwiYFxuICAgICkucHJvbWlzZTtcbiAgICBhd2FpdCBydW5Db21tYW5kKFwiZ2l0IHB1c2ggLS1mb2xsb3ctdGFnc1wiKS5wcm9taXNlO1xuICAgIGlmICghY2kpIHtcbiAgICAgIGF3YWl0IHJ1bkNvbW1hbmQoXCJOUE1fVE9LRU49JChjYXQgLm5wbXRva2VuKSBucG0gcHVibGlzaCAtLWFjY2VzcyBwdWJsaWNcIilcbiAgICAgICAgLnByb21pc2U7XG4gICAgfVxuICB9XG59XG4iLCJpbXBvcnQgeyBTdGFuZGFyZE91dHB1dFdyaXRlciB9IGZyb20gXCIuL1N0YW5kYXJkT3V0cHV0V3JpdGVyXCI7XG5pbXBvcnQgeyBQcm9taXNlRXhlY3V0b3IgfSBmcm9tIFwiLi4vdXRpbHMvdHlwZXNcIjtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gQSBzcGVjaWFsaXplZCBvdXRwdXQgd3JpdGVyIHRoYXQgdXNlcyByZWd1bGFyIGV4cHJlc3Npb25zIHRvIHByb2Nlc3Mgb3V0cHV0LlxuICogQHN1bW1hcnkgVGhpcyBjbGFzcyBleHRlbmRzIFN0YW5kYXJkT3V0cHV0V3JpdGVyIHRvIHByb3ZpZGUgcmVnZXgtYmFzZWQgb3V0cHV0IHByb2Nlc3NpbmcuXG4gKiBJdCBhbGxvd3MgZm9yIHBhdHRlcm4gbWF0Y2hpbmcgaW4gdGhlIG91dHB1dCBzdHJlYW0gYW5kIGNhbiB0cmlnZ2VyIHNwZWNpZmljIGFjdGlvbnNcbiAqIGJhc2VkIG9uIG1hdGNoZWQgcGF0dGVybnMuXG4gKlxuICogQHRlbXBsYXRlIFQgLSBUaGUgdHlwZSBvZiB0aGUgcmVzb2x2ZWQgdmFsdWUsIGRlZmF1bHRpbmcgdG8gc3RyaW5nLlxuICpcbiAqIEBwYXJhbSBjbWQgLSBUaGUgY29tbWFuZCBzdHJpbmcgdG8gYmUgZXhlY3V0ZWQuXG4gKiBAcGFyYW0gbG9jayAtIEEgUHJvbWlzZUV4ZWN1dG9yIHRvIGNvbnRyb2wgdGhlIGFzeW5jaHJvbm91cyBmbG93LlxuICogQHBhcmFtIHJlZ2V4cCAtIEEgc3RyaW5nIG9yIFJlZ0V4cCB0byBtYXRjaCBhZ2FpbnN0IHRoZSBvdXRwdXQuXG4gKiBAcGFyYW0gZmxhZ3MgLSBPcHRpb25hbCBmbGFncyBmb3IgdGhlIFJlZ0V4cCBjb25zdHJ1Y3RvciwgZGVmYXVsdHMgdG8gXCJnXCIuXG4gKlxuICogQGNsYXNzXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogaW1wb3J0IHsgUmVnZXhwT3V0cHV0V3JpdGVyIH0gZnJvbSAnQGRlY2FmLXRzL3V0aWxzJztcbiAqIGltcG9ydCB7IFByb21pc2VFeGVjdXRvciB9IGZyb20gJ0BkZWNhZi10cy91dGlscyc7XG4gKiBcbiAqIC8vIENyZWF0ZSBhIHByb21pc2UgZXhlY3V0b3JcbiAqIGNvbnN0IGV4ZWN1dG9yOiBQcm9taXNlRXhlY3V0b3I8c3RyaW5nLCBFcnJvcj4gPSB7XG4gKiAgIHJlc29sdmU6ICh2YWx1ZSkgPT4gY29uc29sZS5sb2coYFJlc29sdmVkOiAke3ZhbHVlfWApLFxuICogICByZWplY3Q6IChlcnJvcikgPT4gY29uc29sZS5lcnJvcihgUmVqZWN0ZWQ6ICR7ZXJyb3IubWVzc2FnZX1gKVxuICogfTtcbiAqIFxuICogLy8gQ3JlYXRlIGEgcmVnZXhwIG91dHB1dCB3cml0ZXIgdGhhdCBtYXRjaGVzIHZlcnNpb24gbnVtYmVyc1xuICogY29uc3Qgd3JpdGVyID0gbmV3IFJlZ2V4cE91dHB1dFdyaXRlcignbm9kZSAtLXZlcnNpb24nLCBleGVjdXRvciwgL3YoXFxkK1xcLlxcZCtcXC5cXGQrKS8pO1xuICogXG4gKiAvLyBVc2UgdGhlIHdyaXRlciB0byBoYW5kbGUgY29tbWFuZCBvdXRwdXRcbiAqIHdyaXRlci5kYXRhKCd2MTQuMTcuMCcpOyAgLy8gVGhpcyB3aWxsIGF1dG9tYXRpY2FsbHkgcmVzb2x2ZSB3aXRoIFwidjE0LjE3LjBcIlxuICogYGBgXG4gKlxuICogQG1lcm1haWRcbiAqIHNlcXVlbmNlRGlhZ3JhbVxuICogICBwYXJ0aWNpcGFudCBDbGllbnRcbiAqICAgcGFydGljaXBhbnQgUmVnZXhwT3V0cHV0V3JpdGVyXG4gKiAgIHBhcnRpY2lwYW50IFN0YW5kYXJkT3V0cHV0V3JpdGVyXG4gKiAgIHBhcnRpY2lwYW50IExvZ2dlclxuICogICBcbiAqICAgQ2xpZW50LT4+UmVnZXhwT3V0cHV0V3JpdGVyOiBuZXcgUmVnZXhwT3V0cHV0V3JpdGVyKGNtZCwgbG9jaywgcmVnZXhwLCBmbGFncylcbiAqICAgUmVnZXhwT3V0cHV0V3JpdGVyLT4+U3RhbmRhcmRPdXRwdXRXcml0ZXI6IHN1cGVyKGNtZCwgbG9jaylcbiAqICAgU3RhbmRhcmRPdXRwdXRXcml0ZXItPj5Mb2dnZXI6IExvZ2dpbmcuZm9yKGNtZClcbiAqICAgUmVnZXhwT3V0cHV0V3JpdGVyLT4+UmVnZXhwT3V0cHV0V3JpdGVyOiBjb21waWxlIHJlZ2V4cFxuICogICBcbiAqICAgQ2xpZW50LT4+UmVnZXhwT3V0cHV0V3JpdGVyOiBkYXRhKGNodW5rKVxuICogICBSZWdleHBPdXRwdXRXcml0ZXItPj5TdGFuZGFyZE91dHB1dFdyaXRlcjogc3VwZXIuZGF0YShjaHVuaylcbiAqICAgU3RhbmRhcmRPdXRwdXRXcml0ZXItPj5Mb2dnZXI6IGxvZ2dlci5pbmZvKGxvZylcbiAqICAgUmVnZXhwT3V0cHV0V3JpdGVyLT4+UmVnZXhwT3V0cHV0V3JpdGVyOiB0ZXN0QW5kUmVzb2x2ZShjaHVuaylcbiAqICAgUmVnZXhwT3V0cHV0V3JpdGVyLT4+UmVnZXhwT3V0cHV0V3JpdGVyOiB0ZXN0KGNodW5rKVxuICogICBhbHQgbWF0Y2ggZm91bmRcbiAqICAgICBSZWdleHBPdXRwdXRXcml0ZXItPj5SZWdleHBPdXRwdXRXcml0ZXI6IHJlc29sdmUobWF0Y2hbMF0pXG4gKiAgICAgUmVnZXhwT3V0cHV0V3JpdGVyLT4+U3RhbmRhcmRPdXRwdXRXcml0ZXI6IHJlc29sdmUobWF0Y2hbMF0pXG4gKiAgIGVuZFxuICogICBcbiAqICAgQ2xpZW50LT4+UmVnZXhwT3V0cHV0V3JpdGVyOiBlcnJvcihjaHVuaylcbiAqICAgUmVnZXhwT3V0cHV0V3JpdGVyLT4+U3RhbmRhcmRPdXRwdXRXcml0ZXI6IHN1cGVyLmVycm9yKGNodW5rKVxuICogICBTdGFuZGFyZE91dHB1dFdyaXRlci0+PkxvZ2dlcjogbG9nZ2VyLmluZm8obG9nKVxuICogICBSZWdleHBPdXRwdXRXcml0ZXItPj5SZWdleHBPdXRwdXRXcml0ZXI6IHRlc3RBbmRSZWplY3QoY2h1bmspXG4gKiAgIFJlZ2V4cE91dHB1dFdyaXRlci0+PlJlZ2V4cE91dHB1dFdyaXRlcjogdGVzdChjaHVuaylcbiAqICAgYWx0IG1hdGNoIGZvdW5kXG4gKiAgICAgUmVnZXhwT3V0cHV0V3JpdGVyLT4+UmVnZXhwT3V0cHV0V3JpdGVyOiByZWplY3QobWF0Y2hbMF0pXG4gKiAgICAgUmVnZXhwT3V0cHV0V3JpdGVyLT4+U3RhbmRhcmRPdXRwdXRXcml0ZXI6IHJlamVjdChtYXRjaFswXSlcbiAqICAgZW5kXG4gKi9cbmV4cG9ydCBjbGFzcyBSZWdleHBPdXRwdXRXcml0ZXIgZXh0ZW5kcyBTdGFuZGFyZE91dHB1dFdyaXRlcjxzdHJpbmc+IHtcbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBUaGUgcmVndWxhciBleHByZXNzaW9uIHVzZWQgZm9yIG1hdGNoaW5nIG91dHB1dC5cbiAgICogQHN1bW1hcnkgVGhpcyByZWFkb25seSBwcm9wZXJ0eSBzdG9yZXMgdGhlIGNvbXBpbGVkIFJlZ0V4cCB1c2VkIGZvciBwYXR0ZXJuIG1hdGNoaW5nLlxuICAgKi9cbiAgcHJvdGVjdGVkIHJlYWRvbmx5IHJlZ2V4cDogUmVnRXhwO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIGNtZDogc3RyaW5nLFxuICAgIGxvY2s6IFByb21pc2VFeGVjdXRvcjxzdHJpbmcsIEVycm9yPixcbiAgICByZWdleHA6IHN0cmluZyB8IFJlZ0V4cCxcbiAgICBmbGFncyA9IFwiZ1wiXG4gICkge1xuICAgIHN1cGVyKGNtZCwgbG9jayk7XG4gICAgdHJ5IHtcbiAgICAgIHRoaXMucmVnZXhwID1cbiAgICAgICAgdHlwZW9mIHJlZ2V4cCA9PT0gXCJzdHJpbmdcIiA/IG5ldyBSZWdFeHAocmVnZXhwLCBmbGFncykgOiByZWdleHA7XG4gICAgfSBjYXRjaCAoZTogdW5rbm93bikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIHJlZ3VsYXIgZXhwcmVzc2lvbjogJHtlfWApO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gVGVzdHMgdGhlIGlucHV0IGRhdGEgYWdhaW5zdCB0aGUgc3RvcmVkIHJlZ3VsYXIgZXhwcmVzc2lvbi5cbiAgICogQHN1bW1hcnkgRXhlY3V0ZXMgdGhlIHJlZ3VsYXIgZXhwcmVzc2lvbiBvbiB0aGUgaW5wdXQgZGF0YSBhbmQgcmV0dXJucyB0aGUgbWF0Y2ggcmVzdWx0LlxuICAgKlxuICAgKiBAcGFyYW0gZGF0YSAtIFRoZSBzdHJpbmcgdG8gdGVzdCBhZ2FpbnN0IHRoZSByZWd1bGFyIGV4cHJlc3Npb24uXG4gICAqIEByZXR1cm4gVGhlIHJlc3VsdCBvZiB0aGUgcmVndWxhciBleHByZXNzaW9uIGV4ZWN1dGlvbiwgb3IgdW5kZWZpbmVkIGlmIGFuIGVycm9yIG9jY3Vycy5cbiAgICovXG4gIHByaXZhdGUgdGVzdChkYXRhOiBzdHJpbmcpIHtcbiAgICB0aGlzLnJlZ2V4cC5sYXN0SW5kZXggPSAwO1xuICAgIGxldCBtYXRjaDtcbiAgICB0cnkge1xuICAgICAgbWF0Y2ggPSB0aGlzLnJlZ2V4cC5leGVjKGRhdGEpO1xuICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgIHJldHVybiBjb25zb2xlLmRlYnVnKGBGYWlsZWQgdG8gcGFyc2UgY2h1bms6ICR7ZGF0YX1cXG5FcnJvcjogJHtlfSBgKTtcbiAgICB9XG4gICAgcmV0dXJuIG1hdGNoO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBUZXN0cyB0aGUgZGF0YSBhbmQgcmVzb2x2ZXMgdGhlIHByb21pc2UgaWYgYSBtYXRjaCBpcyBmb3VuZC5cbiAgICogQHN1bW1hcnkgRXhlY3V0ZXMgdGhlIHRlc3QgbWV0aG9kIGFuZCByZXNvbHZlcyB0aGUgcHJvbWlzZSB3aXRoIHRoZSBmaXJzdCBtYXRjaCBncm91cCBpZiBzdWNjZXNzZnVsLlxuICAgKlxuICAgKiBAcGFyYW0gZGF0YSAtIFRoZSBzdHJpbmcgdG8gdGVzdCBhZ2FpbnN0IHRoZSByZWd1bGFyIGV4cHJlc3Npb24uXG4gICAqL1xuICBwcm90ZWN0ZWQgdGVzdEFuZFJlc29sdmUoZGF0YTogc3RyaW5nKSB7XG4gICAgY29uc3QgbWF0Y2ggPSB0aGlzLnRlc3QoZGF0YSk7XG4gICAgaWYgKG1hdGNoKSB0aGlzLnJlc29sdmUobWF0Y2hbMF0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBUZXN0cyB0aGUgZGF0YSBhbmQgcmVqZWN0cyB0aGUgcHJvbWlzZSBpZiBhIG1hdGNoIGlzIGZvdW5kLlxuICAgKiBAc3VtbWFyeSBFeGVjdXRlcyB0aGUgdGVzdCBtZXRob2QgYW5kIHJlamVjdHMgdGhlIHByb21pc2Ugd2l0aCB0aGUgZmlyc3QgbWF0Y2ggZ3JvdXAgaWYgc3VjY2Vzc2Z1bC5cbiAgICpcbiAgICogQHBhcmFtIGRhdGEgLSBUaGUgc3RyaW5nIHRvIHRlc3QgYWdhaW5zdCB0aGUgcmVndWxhciBleHByZXNzaW9uLlxuICAgKi9cbiAgcHJvdGVjdGVkIHRlc3RBbmRSZWplY3QoZGF0YTogc3RyaW5nKSB7XG4gICAgY29uc3QgbWF0Y2ggPSB0aGlzLnRlc3QoZGF0YSk7XG4gICAgaWYgKG1hdGNoKSB0aGlzLnJlamVjdChtYXRjaFswXSk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFByb2Nlc3NlcyBpbmNvbWluZyBkYXRhIGNodW5rcy5cbiAgICogQHN1bW1hcnkgQ2FsbHMgdGhlIHBhcmVudCBjbGFzcyBkYXRhIG1ldGhvZCBhbmQgdGhlbiB0ZXN0cyB0aGUgZGF0YSBmb3IgYSBtYXRjaCB0byBwb3RlbnRpYWxseSByZXNvbHZlIHRoZSBwcm9taXNlLlxuICAgKlxuICAgKiBAcGFyYW0gY2h1bmsgLSBUaGUgZGF0YSBjaHVuayB0byBwcm9jZXNzLlxuICAgKi9cbiAgb3ZlcnJpZGUgZGF0YShjaHVuazogYW55KSB7XG4gICAgc3VwZXIuZGF0YShjaHVuayk7XG4gICAgdGhpcy50ZXN0QW5kUmVzb2x2ZShTdHJpbmcoY2h1bmspKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUHJvY2Vzc2VzIGluY29taW5nIGVycm9yIGNodW5rcy5cbiAgICogQHN1bW1hcnkgQ2FsbHMgdGhlIHBhcmVudCBjbGFzcyBlcnJvciBtZXRob2QgYW5kIHRoZW4gdGVzdHMgdGhlIGRhdGEgZm9yIGEgbWF0Y2ggdG8gcG90ZW50aWFsbHkgcmVqZWN0IHRoZSBwcm9taXNlLlxuICAgKlxuICAgKiBAcGFyYW0gY2h1bmsgLSBUaGUgZXJyb3IgY2h1bmsgdG8gcHJvY2Vzcy5cbiAgICovXG4gIG92ZXJyaWRlIGVycm9yKGNodW5rOiBhbnkpIHtcbiAgICBzdXBlci5lcnJvcihjaHVuayk7XG4gICAgdGhpcy50ZXN0QW5kUmVqZWN0KFN0cmluZyhjaHVuaykpO1xuICB9XG59XG4iLCJleHBvcnQgKiBmcm9tIFwiLi9jbGlcIjtcbmV4cG9ydCAqIGZyb20gXCIuL2lucHV0XCI7XG5leHBvcnQgKiBmcm9tIFwiLi9vdXRwdXRcIjtcbmV4cG9ydCAqIGZyb20gXCIuL3V0aWxzXCI7XG5leHBvcnQgKiBmcm9tIFwiLi93cml0ZXJzXCI7XG5cbi8qKlxuICogQG1vZHVsZSB1dGlsc1xuICogQGRlc2NyaXB0aW9uIFV0aWxpdGllcyBhbmQgYnVpbGRpbmcgYmxvY2tzIGZvciBEZWNhZi1UUyBDTEkgYW5kIHNjcmlwdGluZy5cbiAqIEBzdW1tYXJ5IEFnZ3JlZ2F0ZXMgQ0xJIGNvbW1hbmQgaW5mcmFzdHJ1Y3R1cmUsIGlucHV0IGhlbHBlcnMsIG91dHB1dCB3cml0ZXJzLCBmaWxlc3lzdGVtL25ldHdvcmsgdXRpbGl0aWVzLFxuICogYW5kIHNoYXJlZCB0eXBlcy4gQ29uc3VtZXJzIHR5cGljYWxseSB1c2Uge0BsaW5rIENvbW1hbmR9LCB7QGxpbmsgVXNlcklucHV0fSwge0BsaW5rIFN0YW5kYXJkT3V0cHV0V3JpdGVyfSxcbiAqIHtAbGluayBwcmludEJhbm5lcn0sIGFuZCB1dGlsaXRpZXMgZnJvbSB7QGxpbmsgbW9kdWxlOnV0aWxzfHV0aWxzfS5cbiAqXG4gKiBUaGlzIGVudHJ5cG9pbnQgcmUtZXhwb3J0cyBzdWJwYWNrYWdlczpcbiAqIC0gQ0xJIGZyYW1ld29yayB1bmRlciBgLi9jbGlgIChjb21tYW5kIGJhc2UsIG9wdGlvbnMsIGJ1aWx0LWluIGNvbW1hbmRzKVxuICogLSBJbnB1dCBoZWxwZXJzIHVuZGVyIGAuL2lucHV0YCAocHJvbXB0aW5nIGFuZCBhcmcgcGFyc2luZylcbiAqIC0gT3V0cHV0IGhlbHBlcnMgdW5kZXIgYC4vb3V0cHV0YCAoYmFubmVyIGFuZCBzdHlsaW5nKVxuICogLSBHZW5lcmFsIHV0aWxpdGllcyB1bmRlciBgLi91dGlsc2AgKGZzLCBodHRwLCBleGVjLCB0eXBlcylcbiAqIC0gV3JpdGVycyB1bmRlciBgLi93cml0ZXJzYCAoc3Rkb3V0L3N0ZGVyciBwcm9jZXNzb3JzKVxuICpcbiAqIE5vdGU6IEluZGl2aWR1YWwgZXhwb3J0cyBhcmUgZG9jdW1lbnRlZCBpbiB0aGVpciBzb3VyY2UgZmlsZXMuXG4gKi9cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gUmVwcmVzZW50cyB0aGUgY3VycmVudCB2ZXJzaW9uIG9mIHRoZSBtb2R1bGUuXG4gKiBAc3VtbWFyeSBTdG9yZXMgdGhlIHZlcnNpb24gZm9yIHRoZSBAZGVjYWYtdHMvdXRpbHMgcGFja2FnZS4gVGhlIGJ1aWxkIHJlcGxhY2VzXG4gKiB0aGUgcGxhY2Vob2xkZXIgd2l0aCB0aGUgYWN0dWFsIHZlcnNpb24gbnVtYmVyIGF0IHB1Ymxpc2ggdGltZS5cbiAqIEBjb25zdCBWRVJTSU9OXG4gKiBAbWVtYmVyT2YgbW9kdWxlOnV0aWxzXG4gKi9cbmV4cG9ydCBjb25zdCBWRVJTSU9OID0gXCIjI1ZFUlNJT04jI1wiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBSZXByZXNlbnRzIHRoZSBjdXJyZW50IHZlcnNpb24gb2YgdGhlIG1vZHVsZS5cbiAqIEBzdW1tYXJ5IFN0b3JlcyB0aGUgdmVyc2lvbiBmb3IgdGhlIEBkZWNhZi10cy91dGlscyBwYWNrYWdlLiBUaGUgYnVpbGQgcmVwbGFjZXNcbiAqIHRoZSBwbGFjZWhvbGRlciB3aXRoIHRoZSBhY3R1YWwgdmVyc2lvbiBudW1iZXIgYXQgcHVibGlzaCB0aW1lLlxuICogQGNvbnN0IFZFUlNJT05cbiAqIEBtZW1iZXJPZiBtb2R1bGU6dXRpbHNcbiAqL1xuZXhwb3J0IGNvbnN0IFBBQ0tBR0VfTkFNRSA9IFwiIyNQQUNLQUdFIyNcIjtcbiJdLCJuYW1lcyI6WyJVc2VySW5wdXQiLCJ0aGlzIiwibG9nZ2VyIiwiTG9nZ2luZyIsImZvciIsImNvbnN0cnVjdG9yIiwibmFtZSIsInR5cGUiLCJzZXRUeXBlIiwidmVyYm9zZSIsInNldE1lc3NhZ2UiLCJ2YWx1ZSIsIm1lc3NhZ2UiLCJzZXRJbml0aWFsIiwiaW5pdGlhbCIsInNldFN0eWxlIiwic3R5bGUiLCJzZXRGb3JtYXQiLCJmb3JtYXQiLCJzZXRWYWxpZGF0ZSIsInZhbGlkYXRlIiwic2V0T25TdGF0ZSIsIm9uU3RhdGUiLCJzZXRNaW4iLCJtaW4iLCJzZXRNYXgiLCJtYXgiLCJzZXRGbG9hdCIsImZsb2F0Iiwic2V0Um91bmQiLCJyb3VuZCIsInNldEluc3RydWN0aW9ucyIsImluc3RydWN0aW9ucyIsInNldEluY3JlbWVudCIsImluY3JlbWVudCIsInNldFNlcGFyYXRvciIsInNlcGFyYXRvciIsInNldEFjdGl2ZSIsImFjdGl2ZSIsInNldEluYWN0aXZlIiwiaW5hY3RpdmUiLCJzZXRDaG9pY2VzIiwiSlNPTiIsInN0cmluZ2lmeSIsImNob2ljZXMiLCJzZXRIaW50IiwiaGludCIsInNldFdhcm4iLCJ3YXJuIiwic2V0U3VnZ2VzdCIsInN1Z2dlc3QiLCJzZXRMaW1pdCIsImxpbWl0Iiwic2V0TWFzayIsIm1hc2siLCJzZXRTdGRvdXQiLCJzdGRvdXQiLCJzZXRTdGRpbiIsInN0ZGluIiwiYXNrIiwicXVlc3Rpb24iLCJsb2ciLCJBcnJheSIsImlzQXJyYXkiLCJhbnN3ZXJzIiwibWFwIiwicSIsImpvaW4iLCJwcm9tcHRzIiwiZXJyb3IiLCJFcnJvciIsImFza051bWJlciIsInVzZXJJbnB1dCIsImFza1RleHQiLCJ1bmRlZmluZWQiLCJhc2tDb25maXJtYXRpb24iLCJpbnNpc3QiLCJpbnB1dCIsInRlc3QiLCJkZWZhdWx0Q29uZmlybWF0aW9uIiwidG9TdHJpbmciLCJyZXN1bHQiLCJjb3VudCIsImNvbmZpcm1hdGlvbiIsImUiLCJpbmZvIiwiaW5zaXN0Rm9yVGV4dCIsImluc2lzdEZvck51bWJlciIsInBhcnNlQXJncyIsIm9wdGlvbnMiLCJhcmdzIiwicHJvY2VzcyIsImFyZ3YiLCJzbGljZSIsImRlYnVnIiwiRGVmYXVsdENvbW1hbmRPcHRpb25zIiwic2hvcnQiLCJkZWZhdWx0IiwidmVyc2lvbiIsImhlbHAiLCJsb2dMZXZlbCIsImxvZ1N0eWxlIiwidGltZXN0YW1wIiwiYmFubmVyIiwiRGVmYXVsdENvbW1hbmRWYWx1ZXMiLCJPYmplY3QiLCJrZXlzIiwicmVkdWNlIiwiYWNjIiwia2V5IiwiRW5jb2RpbmciLCJTZW1WZXJzaW9uUmVnZXgiLCJTZW1WZXJzaW9uIiwiTm9DSUZMYWciLCJTZXR1cFNjcmlwdEtleSIsIlRva2VucyIsIkFib3J0Q29kZSIsIlN0YW5kYXJkT3V0cHV0V3JpdGVyIiwiY21kIiwibG9jayIsImRhdGEiLCJCdWZmZXIiLCJpc0J1ZmZlciIsInJlZCIsInRleHQiLCJjaHVuayIsIlN0cmluZyIsImVycm9ycyIsImVyciIsImV4aXQiLCJjb2RlIiwibG9ncyIsImdyZWVuIiwicmVzb2x2ZSIsImwiLCJ0cmltIiwicmVqZWN0IiwibGVuZ3RoIiwicGFyc2VDb21tYW5kIiwiY29tbWFuZCIsInBhcnRzIiwicGFyc2UiLCJmaWx0ZXIiLCJwIiwicmVhc29uIiwibG9ja2lmeSIsImYiLCJQcm9taXNlIiwicGFyYW1zIiwidGhlbiIsImNhdGNoIiwiY2hhaW5BYm9ydENvbnRyb2xsZXIiLCJhcmd1bWVudDAiLCJyZW1haW5kZXIiLCJzaWduYWxzIiwiY29udHJvbGxlciIsIkFib3J0U2lnbmFsIiwiQWJvcnRDb250cm9sbGVyIiwic2lnbmFsIiwiYWJvcnRlZCIsImhhbmRsZXIiLCJhYm9ydCIsImFkZEV2ZW50TGlzdGVuZXIiLCJvbmNlIiwic3Bhd25Db21tYW5kIiwib3V0cHV0Iiwib3B0cyIsInNwYXduSW5uZXIiLCJhcmd6IiwiY2hpbGRQcm9jZXNzIiwic3Bhd24iLCJjd2QiLCJlbnYiLCJhc3NpZ24iLCJQQVRIIiwic2hlbGwiLCJwaWQiLCJtIiwibWF0Y2giLCJpbmNsdWRlcyIsImNtZHMiLCJzcGxpdCIsInNwYXducyIsImNvbnRyb2xsZXJzIiwiaSIsInB1c2giLCJwaXBlIiwicnVuQ29tbWFuZCIsIm91dHB1dENvbnN0cnVjdG9yIiwiZXJycyIsInNldEVuY29kaW5nIiwib24iLCJzdGRlcnIiLCJwcm9taXNlIiwiYXN5bmMiLCJjYiIsImxvY2FsUmVxdWlyZSIsImNyZWF0ZVJlcXVpcmUiLCJpc1Rlc3RFbnZpcm9ubWVudCIsIk5PREVfRU5WIiwiSkVTVF9XT1JLRVJfSUQiLCJwYXRjaFN0cmluZyIsInZhbHVlcyIsImZsYWdzIiwiZW50cmllcyIsImZvckVhY2giLCJ2YWwiLCJyZWdleHAiLCJSZWdFeHAiLCJlc2NhcGVSZWdFeHAiLCJyZXBsYWNlIiwic3ViU3RyIiwicGF0Y2hGaWxlIiwicGF0aCIsImZzIiwiZXhpc3RzU3luYyIsImNvbnRlbnQiLCJyZWFkRmlsZSIsIndyaXRlRmlsZSIsInJlYWRGaWxlU3luYyIsIndyaXRlRmlsZVN5bmMiLCJnZXRBbGxGaWxlcyIsImZpbGVzIiwicmVhZGRpclN5bmMiLCJlbnRyeSIsImZ1bGxQYXRoIiwic3RhdCIsInN0YXRTeW5jIiwiaXNGaWxlIiwiaXNEaXJlY3RvcnkiLCJyZW5hbWVGaWxlIiwic291cmNlIiwiZGVzdCIsImRlc2NyaXB0b3JTb3VyY2UiLCJkZXNjcmlwdG9yRGVzdCIsInJlbmFtZVN5bmMiLCJjb3B5RmlsZSIsIm1rZGlyU3luYyIsInJlY3Vyc2l2ZSIsImNwU3luYyIsImRlbGV0ZVBhdGgiLCJkZXNjcmlwdG9yIiwicm1TeW5jIiwiZm9yY2UiLCJnZXRQYWNrYWdlIiwicHJvcGVydHkiLCJwa2ciLCJzZXRQYWNrYWdlQXR0cmlidXRlIiwiYXR0ciIsImdldFBhY2thZ2VWZXJzaW9uIiwiZ2V0RGVwZW5kZW5jaWVzIiwicGtnUGF0aCIsImxvY2tQYXRoIiwibWFwRGVwcyIsInJlc29sdmVEZXBlbmRlbmN5VmVyc2lvbiIsInByb2QiLCJkZXBlbmRlbmNpZXMiLCJkZXYiLCJkZXZEZXBlbmRlbmNpZXMiLCJwZWVyIiwicGVlckRlcGVuZGVuY2llcyIsImZhbGxiYWNrIiwicGFja2FnZXMiLCJ1cGRhdGVEZXBlbmRlbmNpZXMiLCJpbnN0YWxsSWZOb3RBdmFpbGFibGUiLCJkZXBzIiwiY3VycmVudCIsImtub3duIiwiU2V0IiwidG9JbnN0YWxsIiwiZGVwIiwiaGFzIiwiYWRkIiwiaW5zdGFsbERlcGVuZGVuY2llcyIsImRldkRlcHMiLCJmcm9tIiwicHVzaFRvR2l0IiwiZ2l0VXNlciIsImdpdEVtYWlsIiwibm9ybWFsaXplSW1wb3J0IiwiaW1wb3J0UHJvbWlzZSIsImdldEZpbGVTaXplWmlwcGVkIiwiZGlyIiwiY2FuZGlkYXRlcyIsInMiLCJlbmRzV2l0aCIsInNtYWxsZXN0Iiwic21hbGxlc3RTaXplIiwic2l6ZSIsImMiLCJidWZmZXIiLCJneiIsInpsaWIiLCJnemlwU3luYyIsInNpemVLYiIsIk51bWJlciIsInRvRml4ZWQiLCJsaXN0Rm9sZGVyIiwiYmFzZVBhdGgiLCJ3aXRoRmlsZVR5cGVzIiwibmFtZXMiLCJkIiwibGlzdE5vZGVNb2R1bGVzUGFja2FnZXMiLCJzdGFydHNXaXRoIiwic2NvcGVQYXRoIiwic2NvcGVkIiwic2xvZ2FucyIsIlNsb2dhbiIsIlRhZ3MiLCJjb2xvcnMiLCJwcmludEJhbm5lciIsImdldFNsb2dhbiIsIm1heExlbmd0aCIsImxpbmUiLCJNYXRoIiwicGFkU3RhcnQiLCJpbmRleCIsImJpbmQiLCJjb25zb2xlIiwicmF3IiwiZmxvb3IiLCJyYW5kb20iLCJDb21tYW5kIiwiTG9nZ2VkQ2xhc3MiLCJpbnB1dHMiLCJyZXF1aXJlbWVudHMiLCJzdXBlciIsImRlZmluZVByb3BlcnR5Iiwid3JpdGFibGUiLCJjaGVja1JlcXVpcmVtZW50cyIsIm1pc3NpbmciLCJmdWxsTGlzdCIsImV4ZWN1dGUiLCJMb2dnZWRFbnZpcm9ubWVudCIsImFjY3VtdWxhdGUiLCJjb250ZXh0IiwicnVuIiwiSHR0cENsaWVudCIsImRvd25sb2FkRmlsZSIsInVybCIsInJlcXVlc3QiLCJlbmNvZGVVUkkiLCJodHRwcyIsImdldCIsInJlcyIsInN0YXR1c0NvZGUiLCJoZWFkZXJzIiwibG9jYXRpb24iLCJkZWZhdWx0Q2FudmFzT3B0aW9ucyIsIndpZHRoIiwiaGVpZ2h0IiwicGFkZGluZyIsImJhY2tncm91bmRDb2xvciIsImhlYWRlckZvbnQiLCJyb3dGb250IiwiaGVhZGVyQ29sb3IiLCJyb3dDb2xvciIsImRlbGF5IiwibXMiLCJzZXRUaW1lb3V0IiwicGVyZkRlYnVnRW5hYmxlZCIsIlBFUkZfVkVSQk9TRSIsImRlYnVnTG9nIiwiZm9ybWF0VGFibGUiLCJ0aXRsZSIsInJvd3MiLCJjb2x1bW5XaWR0aHMiLCJoZWFkZXIiLCJyb3ciLCJmb3JtYXRSb3ciLCJwYWRFbmQiLCJoZWFkZXJMaW5lIiwiZGl2aWRlciIsInJlcGVhdCIsImJvZHkiLCJlbnN1cmVEaXJlY3RvcnkiLCJ0YXJnZXRQYXRoIiwibWtkaXIiLCJkaXJuYW1lIiwicmVuZGVyTWV0cmljc1RhYmxlVG9DYW52YXMiLCJvdXRwdXRQYXRoIiwiY29uZmlnIiwiY3JlYXRlQ2FudmFzIiwiY2FudmFzTW9kdWxlIiwiaW1wb3J0IiwiY2FudmFzIiwiY3R4IiwiZ2V0Q29udGV4dCIsImZpbGxTdHlsZSIsImZpbGxSZWN0IiwiZm9udCIsImNvbHVtbldpZHRoIiwiaGVhZGVyWSIsImZpbGxUZXh0Iiwicm93SGVpZ2h0Iiwicm93SW5kZXgiLCJ5IiwiY2VsbCIsImNlbGxJbmRleCIsInRvQnVmZmVyIiwiUGVyZm9ybWFuY2VSdW5uZXIiLCJzY2VuYXJpbyIsImluaXRpYWxpemUiLCJwaGFzZUNvdW50ZXIiLCJxdWV1ZSIsInBoYXNlcyIsInBoYXNlIiwicGhhc2VOdW1iZXIiLCJyZXN1bHRzIiwiaXRlbSIsInNoaWZ0IiwibWVyZ2VDb250ZXh0IiwiaXRlcmF0aW9ucyIsIm1vZGUiLCJjb25jdXJyZW5jeSIsImJ1cnN0IiwicnVuUGhhc2UiLCJ0b3RhbCIsImFnZ3JlZ2F0ZWQiLCJ0b3RhbER1cmF0aW9uTXMiLCJhdmciLCJhdmVyYWdlTXMiLCJmYWlsdXJlQ291bnQiLCJnZW5lcmF0b3IiLCJoaXN0b3J5U25hcHNob3QiLCJtZXRhZGF0YSIsInBoYXNlTmFtZSIsIml0ZXJhdGlvbkNvdW50IiwiYnVyc3RTZWdtZW50cyIsInNlZ21lbnRDb3VudCIsImhpc3RvcnkiLCJnZW5lcmF0b3JSZXN1bHQiLCJuZXh0UGhhc2UiLCJsb2dTdW1tYXJ5IiwicnVuV2FybXVwIiwic2VnbWVudHMiLCJidWlsZFNlZ21lbnRJbmRpY2VzIiwiY29sbGVjdGVkIiwic2VnbWVudEluZGV4IiwiaW5kaWNlcyIsIm1ldHJpY3MiLCJleGVjdXRlU2VnbWVudCIsImJ1cnN0SW50ZXJ2YWwiLCJpbnRlcnZhbE1zIiwic29ydGVkIiwic29ydCIsImEiLCJiIiwiaXRlcmF0aW9uIiwiYWdncmVnYXRlTWV0cmljcyIsInBhdXNlQWZ0ZXJNcyIsImZhaWxPbkVycm9yIiwiaXRlcmF0aW9uTWV0cmljcyIsIndhcm11cCIsImxvYWRGYWN0b3IiLCJjb21wdXRlTG9hZEZhY3RvciIsImRlbGF5QmV0d2Vlbkl0ZXJhdGlvbnNNcyIsImJhc2UiLCJsb2FkU3RhcnQiLCJzdGVwIiwibG9hZFN0ZXAiLCJtdWx0aXBsaWVyIiwibG9hZE11bHRpcGxpZXIiLCJjdXJzb3IiLCJlbmQiLCJfIiwiaWR4IiwiYmFzZUNvbnRleHQiLCJwaGFzZUNvbnRleHQiLCJtZXJnZUNvbnRleHRzIiwiY29sbGVjdENvbmN1cnJlbnQiLCJjb2xsZWN0U2VxdWVudGlhbCIsImRlbGF5QmV0d2VlbiIsInJ1bkl0ZXJhdGlvbiIsInBvaW50ZXIiLCJ3b3JrZXIiLCJhbGwiLCJzdG9wd2F0Y2giLCJTdG9wV2F0Y2giLCJzdWNjZXNzIiwibWV0YSIsImR1cmF0aW9uTXMiLCJzdG9wIiwibWluTXMiLCJtYXhNcyIsInN1Y2Nlc3NDb3VudCIsImxvYWRFbmQiLCJtZXRyaWMiLCJzaG91bGRSZW5kZXJDYW52YXMiLCJjaGFydFBhdGgiLCJjYW52YXNPdXRwdXRQYXRoIiwiY2FudmFzT3B0aW9ucyIsImVuYWJsZUNhbnZhcyIsIkJvb2xlYW4iLCJwYXJzZUxpc3QiLCJwYWNrYWdlVG9HbG9iYWwiLCJ3aXRob3V0U2NvcGUiLCJjaGFyQXQiLCJ0b1VwcGVyQ2FzZSIsImdldFBhY2thZ2VEZXBlbmRlbmNpZXMiLCJoYXNEZXBzIiwiZmFsbGJhY2tEaXIiLCJfX2Rpcm5hbWUiLCJWRVJTSU9OX1NUUklORyIsIlBBQ0tBR0VfU1RSSU5HIiwiUEFDS0FHRV9TSVpFX1NUUklORyIsIk1vZGVzIiwiQnVpbGRNb2RlIiwiYnVpbGRNb2RlIiwiQUxMIiwiZXh0ZXJuYWxzIiwiZG9jcyIsImNvbW1hbmRzIiwiY2pzMlRyYW5zZm9ybWVyIiwiZXh0IiwiQnVpbGRTY3JpcHRzIiwicmVzb2x1dGlvbkNhY2hlIiwiTWFwIiwidHJhbnNmb3JtYXRpb25Db250ZXh0Iiwic291cmNlRmlsZSIsInNvdXJjZURpciIsImZpbGVOYW1lIiwicmVzb2x2ZVBhdGgiLCJpbXBvcnRQYXRoIiwiY2FjaGVLZXkiLCJjYWNoZWRWYWx1ZSIsInJlc29sdmVkUGF0aCIsImUyIiwiaXNBYnNvbHV0ZSIsImV4dGVuc2lvbiIsImV4ZWMiLCJiYXNlbmFtZSIsInJlbGF0aXZlIiwic2V0IiwidmlzaXROb2RlIiwibm9kZSIsInNob3VsZE11dGF0ZU1vZHVsZVNwZWNpZmllciIsInRzIiwiaXNJbXBvcnREZWNsYXJhdGlvbiIsIm1vZHVsZVNwZWNpZmllciIsIm5ld01vZHVsZVNwZWNpZmllciIsImZhY3RvcnkiLCJjcmVhdGVTdHJpbmdMaXRlcmFsIiwidXBkYXRlSW1wb3J0RGVjbGFyYXRpb24iLCJtb2RpZmllcnMiLCJpbXBvcnRDbGF1c2UiLCJpc0V4cG9ydERlY2xhcmF0aW9uIiwidXBkYXRlRXhwb3J0RGVjbGFyYXRpb24iLCJpc1R5cGVPbmx5IiwiZXhwb3J0Q2xhdXNlIiwidmlzaXRFYWNoQ2hpbGQiLCJpc1N0cmluZ0xpdGVyYWwiLCJleHRuYW1lIiwicmVwbGFjZW1lbnRzIiwicGtnTmFtZSIsInBrZ1ZlcnNpb24iLCJwYXRjaEZpbGVzIiwiZmlsZSIsInBhcmVudFBhdGgiLCJyZXBvcnREaWFnbm9zdGljcyIsImRpYWdub3N0aWNzIiwibXNnIiwiZm9ybWF0RGlhZ25vc3RpY3MiLCJkaWFnbm9zdGljIiwic3RhcnQiLCJjaGFyYWN0ZXIiLCJnZXRMaW5lQW5kQ2hhcmFjdGVyT2ZQb3NpdGlvbiIsImZsYXR0ZW5EaWFnbm9zdGljTWVzc2FnZVRleHQiLCJtZXNzYWdlVGV4dCIsInJlYWRDb25maWdGaWxlIiwiY29uZmlnRmlsZU5hbWUiLCJjb25maWdGaWxlVGV4dCIsInBhcnNlQ29uZmlnRmlsZVRleHRUb0pzb24iLCJjb25maWdPYmplY3QiLCJMb2dMZXZlbCIsImNvbmZpZ1BhcnNlUmVzdWx0IiwicGFyc2VKc29uQ29uZmlnRmlsZUNvbnRlbnQiLCJzeXMiLCJldmFsRGlhZ25vc3RpY3MiLCJjYXRlZ29yeSIsIkRpYWdub3N0aWNDYXRlZ29yeSIsIndhcm5pbmdzIiwiV2FybmluZyIsInN1Z2dlc3Rpb25zIiwiU3VnZ2VzdGlvbiIsIm1lc3NhZ2VzIiwiTWVzc2FnZSIsInByZUNoZWNrRGlhZ25vc3RpY3MiLCJwcm9ncmFtIiwiZ2V0UHJlRW1pdERpYWdub3N0aWNzIiwiY2hlY2tUc0RpYWdub3N0aWNzIiwiaXNEZXYiLCJidW5kbGUiLCJ0c0NvbmZpZyIsIm1vZHVsZSIsIk1vZHVsZUtpbmQiLCJBTUQiLCJvdXREaXIiLCJpc29sYXRlZE1vZHVsZXMiLCJvdXRGaWxlIiwiRVNNIiwiRVMyMDIyIiwiQ29tbW9uSlMiLCJpbmxpbmVTb3VyY2VNYXAiLCJpbmxpbmVTb3VyY2VzIiwic291cmNlTWFwIiwiY3JlYXRlUHJvZ3JhbSIsImZpbGVOYW1lcyIsImJ1aWxkVHMiLCJ0cmFuc2Zvcm1hdGlvbnMiLCJDSlMiLCJiZWZvcmUiLCJlbWl0UmVzdWx0IiwiZW1pdCIsImFsbERpYWdub3N0aWNzIiwiY29uY2F0IiwiYnVpbGQiLCJjb3B5QXNzZXRzIiwiaGFzQXNzZXRzIiwiaXNMaWIiLCJlbnRyeUZpbGUiLCJuYW1lT3ZlcnJpZGUiLCJleHRlcm5hbHNBcmciLCJpbmNsdWRlQXJnIiwiaXNFc20iLCJpbmNsdWRlIiwiZXh0ZXJuYWxzTGlzdCIsImJ1aWx0aW5MaXN0IiwiYnVpbHRpbk1vZHVsZXMiLCJyb2xsdXBTb3VyY2VNYXBPdXRwdXQiLCJwbHVnaW5zIiwidHlwZXNjcmlwdCIsImNvbXBpbGVyT3B0aW9ucyIsImRlY2xhcmF0aW9uIiwiZXhjbHVkZSIsInRzY29uZmlnIiwianNvbiIsImNvbW1vbmpzIiwibm9kZVJlc29sdmUiLCJyZXNvbHZlT25seSIsInRlcnNlck1vZCIsInRlcnNlckZuIiwidGVyc2VyIiwidGVyc2VyT3B0aW9uc0RldiIsImVjbWEiLCJjb21wcmVzcyIsIm1hbmdsZSIsImNvbW1lbnRzIiwiYmVhdXRpZnkiLCJ0ZXJzZXJPcHRpb25zUHJvZCIsInBhc3NlcyIsImRyb3BfY29uc29sZSIsImRyb3BfZGVidWdnZXIiLCJ0b3BsZXZlbCIsInVuc2FmZSIsInVuc2FmZV9hcnJvd3MiLCJ1bnNhZmVfY29tcHMiLCJjb2xsYXBzZV92YXJzIiwicmVkdWNlX2Z1bmNzIiwicmVkdWNlX3ZhcnMiLCJhc2NpaV9vbmx5IiwiZXh0ZXJuYWwiLCJvbndhcm4iLCJ0cmVlc2hha2UiLCJnbG9iYWxzIiwib3V0cHV0cyIsImVzTW9kdWxlIiwic291cmNlbWFwIiwiZXhwb3J0cyIsInJvbGx1cCIsIndhdGNoRmlsZXMiLCJnZW5lcmF0ZU91dHB1dHMiLCJvdXRwdXRPcHRpb25zIiwid3JpdGUiLCJidWlsZEJ5RW52IiwiaW5jbHVkZXNBcmciLCJCVUlMRCIsIkJVTkRMRSIsImJ1aWxkRGV2IiwiYnVpbGRQcm9kIiwiYnVpbGREb2NzIiwic3JjIiwiY2kiLCJ0YWciLCJSZWxlYXNlU2NyaXB0IiwicHJlcGFyZVZlcnNpb24iLCJ0ZXN0VmVyc2lvbiIsInRvTG93ZXJDYXNlIiwiUEFUQ0giLCJNSU5PUiIsIk1BSk9SIiwicHJlcGFyZU1lc3NhZ2UiLCJSZWdleHBPdXRwdXRXcml0ZXIiLCJsYXN0SW5kZXgiLCJ0ZXN0QW5kUmVzb2x2ZSIsInRlc3RBbmRSZWplY3QiLCJWRVJTSU9OIiwiUEFDS0FHRV9OQU1FIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztNQXdFYUE7O1FBQ2FDLEtBQUFDLFNBQVNDLFFBQVFDLElBQUlKO0FBQVc7SUF3SnhELFdBQUFLLENBQVlDO1FBbkpaTCxLQUFBTSxPQUErRDtRQW9KN0ROLEtBQUtLLE9BQU9BO0FBQ2Q7SUFTQSxPQUFBRSxDQUFRRDtRQUNOUCxVQUFVRSxPQUFPTyxR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UkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQ0U7SUFDRkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQ0U7SUFDRkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQ0U7SUFDRkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQVE7SUFDUkMsTUFBTTtHQUVSO0lBQ0VELFFBQ0U7SUFDRkMsTUFBTTtHQUVSO0lBQ0VE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
|