From b7b1e95eb8b0fdf8ed1b84075747bb23f3148712 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 1 Mar 2024 15:25:40 +0000 Subject: [PATCH] Add working PoC of snippets for both polyfilled vm and isolated-vm --- packages/server/package.json | 3 +- packages/server/src/api/controllers/script.ts | 2 +- packages/server/src/jsRunner/bundles/index.ts | 2 ++ .../jsRunner/bundles/snippets.ivm.bundle.js | 3 ++ .../server/src/jsRunner/bundles/snippets.ts | 18 ++++++++++++ packages/server/src/jsRunner/index.ts | 6 ++-- .../src/jsRunner/tests/isolatedVM.spec.ts | 2 +- packages/server/src/jsRunner/utilities.ts | 3 -- .../server/src/jsRunner/vm/isolated-vm.ts | 14 ++++++++- packages/server/src/threads/query.ts | 2 +- packages/string-templates/package.json | 3 +- .../src/helpers/javascript.js | 29 ++++++++++++++++++- .../string-templates/src/helpers/snippet.js | 1 + packages/string-templates/src/iife.js | 3 ++ packages/string-templates/src/index.js | 2 ++ 15 files changed, 81 insertions(+), 12 deletions(-) create mode 100644 packages/server/src/jsRunner/bundles/snippets.ivm.bundle.js create mode 100644 packages/server/src/jsRunner/bundles/snippets.ts delete mode 100644 packages/server/src/jsRunner/utilities.ts create mode 100644 packages/string-templates/src/helpers/snippet.js create mode 100644 packages/string-templates/src/iife.js diff --git a/packages/server/package.json b/packages/server/package.json index 45980a4be6..572e735335 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -13,9 +13,10 @@ "build": "node ./scripts/build.js", "postbuild": "copyfiles -f ../client/dist/budibase-client.js ../client/manifest.json client && copyfiles -f ../../yarn.lock ./dist/", "check:types": "tsc -p tsconfig.json --noEmit --paths null", + "build:isolated-vm-lib:snippets": "esbuild --minify --bundle src/jsRunner/bundles/snippets.ts --outfile=src/jsRunner/bundles/snippets.ivm.bundle.js --platform=node --format=iife --global-name=snippets", "build:isolated-vm-lib:string-templates": "esbuild --minify --bundle src/jsRunner/bundles/index-helpers.ts --outfile=src/jsRunner/bundles/index-helpers.ivm.bundle.js --platform=node --format=iife --external:handlebars --global-name=helpers", "build:isolated-vm-lib:bson": "esbuild --minify --bundle src/jsRunner/bundles/bsonPackage.ts --outfile=src/jsRunner/bundles/bson.ivm.bundle.js --platform=node --format=iife --global-name=bson", - "build:isolated-vm-libs": "yarn build:isolated-vm-lib:string-templates && yarn build:isolated-vm-lib:bson", + "build:isolated-vm-libs": "yarn build:isolated-vm-lib:string-templates && yarn build:isolated-vm-lib:bson && yarn build:isolated-vm-lib:snippets", "build:dev": "yarn prebuild && tsc --build --watch --preserveWatchOutput", "debug": "yarn build && node --expose-gc --inspect=9222 dist/index.js", "jest": "NODE_OPTIONS=\"--no-node-snapshot $NODE_OPTIONS\" jest", diff --git a/packages/server/src/api/controllers/script.ts b/packages/server/src/api/controllers/script.ts index b69fc430a6..4317f5fcde 100644 --- a/packages/server/src/api/controllers/script.ts +++ b/packages/server/src/api/controllers/script.ts @@ -1,6 +1,6 @@ import { Ctx } from "@budibase/types" import { IsolatedVM } from "../../jsRunner/vm" -import { iifeWrapper } from "../../jsRunner/utilities" +import { iifeWrapper } from "@budibase/string-templates" export async function execute(ctx: Ctx) { const { script, context } = ctx.request.body diff --git a/packages/server/src/jsRunner/bundles/index.ts b/packages/server/src/jsRunner/bundles/index.ts index 9e2960807a..f7685206a6 100644 --- a/packages/server/src/jsRunner/bundles/index.ts +++ b/packages/server/src/jsRunner/bundles/index.ts @@ -5,11 +5,13 @@ import fs from "fs" export const enum BundleType { HELPERS = "helpers", BSON = "bson", + SNIPPETS = "snippets", } const bundleSourceFile: Record = { [BundleType.HELPERS]: "./index-helpers.ivm.bundle.js", [BundleType.BSON]: "./bson.ivm.bundle.js", + [BundleType.SNIPPETS]: "./snippets.ivm.bundle.js", } const bundleSourceCode: Partial> = {} diff --git a/packages/server/src/jsRunner/bundles/snippets.ivm.bundle.js b/packages/server/src/jsRunner/bundles/snippets.ivm.bundle.js new file mode 100644 index 0000000000..e5bc2df6c6 --- /dev/null +++ b/packages/server/src/jsRunner/bundles/snippets.ivm.bundle.js @@ -0,0 +1,3 @@ +"use strict";var snippets=(()=>{var s=Object.create;var p=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var c=Object.getOwnPropertyNames;var l=Object.getPrototypeOf,m=Object.prototype.hasOwnProperty;var W=(e,r)=>()=>(r||e((r={exports:{}}).exports,r),r.exports),d=(e,r)=>{for(var n in r)p(e,n,{get:r[n],enumerable:!0})},o=(e,r,n,i)=>{if(r&&typeof r=="object"||typeof r=="function")for(let t of c(r))!m.call(e,t)&&t!==n&&p(e,t,{get:()=>r[t],enumerable:!(i=x(r,t))||i.enumerable});return e};var g=(e,r,n)=>(n=e!=null?s(l(e)):{},o(r||!e||!e.__esModule?p(n,"default",{value:e,enumerable:!0}):n,e)),v=e=>o(p({},"__esModule",{value:!0}),e);var u=W((_,f)=>{f.exports.iifeWrapper=e=>`(function(){ +${e} +})();`});var y={};d(y,{default:()=>w});var a=g(u()),w=new Proxy({},{get:function(e,r){return[eval][0]((0,a.iifeWrapper)($("snippets")[r]))}});return v(y);})(); diff --git a/packages/server/src/jsRunner/bundles/snippets.ts b/packages/server/src/jsRunner/bundles/snippets.ts new file mode 100644 index 0000000000..d45fe56ec0 --- /dev/null +++ b/packages/server/src/jsRunner/bundles/snippets.ts @@ -0,0 +1,18 @@ +// @ts-ignore +// eslint-disable-next-line local-rules/no-budibase-imports +import { iifeWrapper } from "@budibase/string-templates/iife" + +export default new Proxy( + {}, + { + get: function (_, name) { + // Get snippet definitions from global context, get the correct snippet + // then eval the JS. + // https://esbuild.github.io/content-types/#direct-eval for info on why + // eval is being called this way. + // @ts-ignore + // eslint-disable-next-line no-undef + return [eval][0](iifeWrapper($("snippets")[name])) + }, + } +) diff --git a/packages/server/src/jsRunner/index.ts b/packages/server/src/jsRunner/index.ts index 0c9f5d9f01..67aaffae7f 100644 --- a/packages/server/src/jsRunner/index.ts +++ b/packages/server/src/jsRunner/index.ts @@ -21,13 +21,15 @@ export function init() { memoryLimit: env.JS_RUNNER_MEMORY_LIMIT, invocationTimeout: env.JS_PER_INVOCATION_TIMEOUT_MS, isolateAccumulatedTimeout: env.JS_PER_REQUEST_TIMEOUT_MS, - }).withHelpers() + }) + .withHelpers() + .withSnippets() if (bbCtx) { // If we have a context, we want to persist it to reuse the isolate bbCtx.vm = vm } - const { helpers, ...rest } = ctx + const { helpers, snippets, ...rest } = ctx return vm.withContext(rest, () => vm.execute(js)) } catch (error: any) { if (error.message === "Script execution timed out.") { diff --git a/packages/server/src/jsRunner/tests/isolatedVM.spec.ts b/packages/server/src/jsRunner/tests/isolatedVM.spec.ts index 5296598ef1..5a9bc05d76 100644 --- a/packages/server/src/jsRunner/tests/isolatedVM.spec.ts +++ b/packages/server/src/jsRunner/tests/isolatedVM.spec.ts @@ -1,7 +1,7 @@ import fs from "fs" import path from "path" import { IsolatedVM } from "../vm" -import { iifeWrapper } from "../utilities" +import { iifeWrapper } from "@budibase/string-templates" function runJSWithIsolatedVM(script: string, context: Record) { const runner = new IsolatedVM() diff --git a/packages/server/src/jsRunner/utilities.ts b/packages/server/src/jsRunner/utilities.ts deleted file mode 100644 index fa398ec239..0000000000 --- a/packages/server/src/jsRunner/utilities.ts +++ /dev/null @@ -1,3 +0,0 @@ -export function iifeWrapper(script: string) { - return `(function(){\n${script}\n})();` -} diff --git a/packages/server/src/jsRunner/vm/isolated-vm.ts b/packages/server/src/jsRunner/vm/isolated-vm.ts index b0692f0fd1..fb45abf5df 100644 --- a/packages/server/src/jsRunner/vm/isolated-vm.ts +++ b/packages/server/src/jsRunner/vm/isolated-vm.ts @@ -7,7 +7,7 @@ import querystring from "querystring" import { BundleType, loadBundle } from "../bundles" import { VM } from "@budibase/types" -import { iifeWrapper } from "../utilities" +import { iifeWrapper } from "@budibase/string-templates" import environment from "../../environment" class ExecutionTimeoutError extends Error { @@ -98,6 +98,18 @@ export class IsolatedVM implements VM { return this } + withSnippets() { + const snippetsSource = loadBundle(BundleType.SNIPPETS) + const script = this.isolate.compileScriptSync( + `${snippetsSource};snippets=snippets.default;` + ) + script.runSync(this.vm, { timeout: this.invocationTimeout, release: false }) + new Promise(() => { + script.release() + }) + return this + } + withContext(context: Record, executeWithContext: () => T) { this.addToContext(context) diff --git a/packages/server/src/threads/query.ts b/packages/server/src/threads/query.ts index 9d7b7062a5..40caa6dfd8 100644 --- a/packages/server/src/threads/query.ts +++ b/packages/server/src/threads/query.ts @@ -8,7 +8,7 @@ import { QueryResponse, } from "./definitions" import { IsolatedVM } from "../jsRunner/vm" -import { iifeWrapper } from "../jsRunner/utilities" +import { iifeWrapper } from "@budibase/string-templates" import { getIntegration } from "../integrations" import { processStringSync } from "@budibase/string-templates" import { context, cache, auth } from "@budibase/backend-core" diff --git a/packages/string-templates/package.json b/packages/string-templates/package.json index ceafd5364f..340d74ef8a 100644 --- a/packages/string-templates/package.json +++ b/packages/string-templates/package.json @@ -12,7 +12,8 @@ "import": "./dist/bundle.mjs" }, "./package.json": "./package.json", - "./test/utils": "./test/utils.js" + "./test/utils": "./test/utils.js", + "./iife": "./src/iife.js" }, "files": [ "dist", diff --git a/packages/string-templates/src/helpers/javascript.js b/packages/string-templates/src/helpers/javascript.js index 7827736812..65c70cc330 100644 --- a/packages/string-templates/src/helpers/javascript.js +++ b/packages/string-templates/src/helpers/javascript.js @@ -2,6 +2,8 @@ const { atob, isBackendService, isJSAllowed } = require("../utilities") const cloneDeep = require("lodash.clonedeep") const { LITERAL_MARKER } = require("../helpers/constants") const { getJsHelperList } = require("./list") +const { iifeWrapper } = require("../iife") +const { CrazyLongSnippet } = require("./snippet") // The method of executing JS scripts depends on the bundle being built. // This setter is used in the entrypoint (either index.js or index.mjs). @@ -40,15 +42,30 @@ const getContextValue = (path, context) => { return data } +const snippets = { + Square: ` + return function(num) { + return num * num + } + `, + HelloWorld: ` + return "Hello, world!" + `, + CrazyLongSnippet: atob(CrazyLongSnippet), +} + // Evaluates JS code against a certain context module.exports.processJS = (handlebars, context) => { + // for testing + context.snippets = snippets + if (!isJSAllowed() || (isBackendService() && !runJS)) { throw new Error("JS disabled in environment.") } try { // Wrap JS in a function and immediately invoke it. // This is required to allow the final `return` statement to be valid. - const js = `(function(){${atob(handlebars)}})();` + const js = iifeWrapper(atob(handlebars)) // Our $ context function gets a value from context. // We clone the context to avoid mutation in the binding affecting real @@ -56,6 +73,16 @@ module.exports.processJS = (handlebars, context) => { const sandboxContext = { $: path => getContextValue(path, cloneDeep(context)), helpers: getJsHelperList(), + + // Proxy to evaluate snippets when running in the browser + snippets: new Proxy( + {}, + { + get: function (_, name) { + return eval(iifeWrapper(context.snippets[name])) + }, + } + ), } // Create a sandbox with our context and run the JS diff --git a/packages/string-templates/src/helpers/snippet.js b/packages/string-templates/src/helpers/snippet.js new file mode 100644 index 0000000000..950019a69f --- /dev/null +++ b/packages/string-templates/src/helpers/snippet.js @@ -0,0 +1 @@ +module.exports.CrazyLongSnippet = `LyoqCiAqIG1hcmtlZCAtIGEgbWFya2Rvd24gcGFyc2VyCiAqIENvcHlyaWdodCAoYykgMjAxMS0yMDIyLCBDaHJpc3RvcGhlciBKZWZmcmV5LiAoTUlUIExpY2Vuc2VkKQogKiBodHRwczovL2dpdGh1Yi5jb20vbWFya2VkanMvbWFya2VkCiAqLwoKLyoqCiAqIERPIE5PVCBFRElUIFRISVMgRklMRQogKiBUaGUgY29kZSBpbiB0aGlzIGZpbGUgaXMgZ2VuZXJhdGVkIGZyb20gZmlsZXMgaW4gLi9zcmMvCiAqLwoKZnVuY3Rpb24gZ2V0RGVmYXVsdHMoKSB7CiAgcmV0dXJuIHsKICAgIGJhc2VVcmw6IG51bGwsCiAgICBicmVha3M6IGZhbHNlLAogICAgZXh0ZW5zaW9uczogbnVsbCwKICAgIGdmbTogdHJ1ZSwKICAgIGhlYWRlcklkczogdHJ1ZSwKICAgIGhlYWRlclByZWZpeDogIiIsCiAgICBoaWdobGlnaHQ6IG51bGwsCiAgICBsYW5nUHJlZml4OiAibGFuZ3VhZ2UtIiwKICAgIG1hbmdsZTogdHJ1ZSwKICAgIHBlZGFudGljOiBmYWxzZSwKICAgIHJlbmRlcmVyOiBudWxsLAogICAgc2FuaXRpemU6IGZhbHNlLAogICAgc2FuaXRpemVyOiBudWxsLAogICAgc2lsZW50OiBmYWxzZSwKICAgIHNtYXJ0TGlzdHM6IGZhbHNlLAogICAgc21hcnR5cGFudHM6IGZhbHNlLAogICAgdG9rZW5pemVyOiBudWxsLAogICAgd2Fsa1Rva2VuczogbnVsbCwKICAgIHhodG1sOiBmYWxzZSwKICB9Cn0KCmxldCBkZWZhdWx0cyA9IGdldERlZmF1bHRzKCkKCmZ1bmN0aW9uIGNoYW5nZURlZmF1bHRzKG5ld0RlZmF1bHRzKSB7CiAgZGVmYXVsdHMgPSBuZXdEZWZhdWx0cwp9CgovKioKICogSGVscGVycwogKi8KY29uc3QgZXNjYXBlVGVzdCA9IC9bJjw+IiddLwpjb25zdCBlc2NhcGVSZXBsYWNlID0gL1smPD4iJ10vZwpjb25zdCBlc2NhcGVUZXN0Tm9FbmNvZGUgPSAvWzw+IiddfCYoPyEjP1x3KzspLwpjb25zdCBlc2NhcGVSZXBsYWNlTm9FbmNvZGUgPSAvWzw+IiddfCYoPyEjP1x3KzspL2cKY29uc3QgZXNjYXBlUmVwbGFjZW1lbnRzID0gewogICImIjogIiZhbXA7IiwKICAiPCI6ICImbHQ7IiwKICAiPiI6ICImZ3Q7IiwKICAnIic6ICImcXVvdDsiLAogICInIjogIiYjMzk7IiwKfQpjb25zdCBnZXRFc2NhcGVSZXBsYWNlbWVudCA9IGNoID0+IGVzY2FwZVJlcGxhY2VtZW50c1tjaF0KZnVuY3Rpb24gZXNjYXBlKGh0bWwsIGVuY29kZSkgewogIGlmIChlbmNvZGUpIHsKICAgIGlmIChlc2NhcGVUZXN0LnRlc3QoaHRtbCkpIHsKICAgICAgcmV0dXJuIGh0bWwucmVwbGFjZShlc2NhcGVSZXBsYWNlLCBnZXRFc2NhcGVSZXBsYWNlbWVudCkKICAgIH0KICB9IGVsc2UgewogICAgaWYgKGVzY2FwZVRlc3ROb0VuY29kZS50ZXN0KGh0bWwpKSB7CiAgICAgIHJldHVybiBodG1sLnJlcGxhY2UoZXNjYXBlUmVwbGFjZU5vRW5jb2RlLCBnZXRFc2NhcGVSZXBsYWNlbWVudCkKICAgIH0KICB9CgogIHJldHVybiBodG1sCn0KCmNvbnN0IHVuZXNjYXBlVGVzdCA9IC8mKCMoPzpcZCspfCg/OiN4WzAtOUEtRmEtZl0rKXwoPzpcdyspKTs/L2dpCgovKioKICogQHBhcmFtIHtzdHJpbmd9IGh0bWwKICovCmZ1bmN0aW9uIHVuZXNjYXBlKGh0bWwpIHsKICAvLyBleHBsaWNpdGx5IG1hdGNoIGRlY2ltYWwsIGhleCwgYW5kIG5hbWVkIEhUTUwgZW50aXRpZXMKICByZXR1cm4gaHRtbC5yZXBsYWNlKHVuZXNjYXBlVGVzdCwgKF8sIG4pID0+IHsKICAgIG4gPSBuLnRvTG93ZXJDYXNlKCkKICAgIGlmIChuID09PSAiY29sb24iKSByZXR1cm4gIjoiCiAgICBpZiAobi5jaGFyQXQoMCkgPT09ICIjIikgewogICAgICByZXR1cm4gbi5jaGFyQXQoMSkgPT09ICJ4IgogICAgICAgID8gU3RyaW5nLmZyb21DaGFyQ29kZShwYXJzZUludChuLnN1YnN0cmluZygyKSwgMTYpKQogICAgICAgIDogU3RyaW5nLmZyb21DaGFyQ29kZSgrbi5zdWJzdHJpbmcoMSkpCiAgICB9CiAgICByZXR1cm4gIiIKICB9KQp9Cgpjb25zdCBjYXJldCA9IC8oXnxbXlxbXSlcXi9nCgovKioKICogQHBhcmFtIHtzdHJpbmcgfCBSZWdFeHB9IHJlZ2V4CiAqIEBwYXJhbSB7c3RyaW5nfSBvcHQKICovCmZ1bmN0aW9uIGVkaXQocmVnZXgsIG9wdCkgewogIHJlZ2V4ID0gdHlwZW9mIHJlZ2V4ID09PSAic3RyaW5nIiA/IHJlZ2V4IDogcmVnZXguc291cmNlCiAgb3B0ID0gb3B0IHx8ICIiCiAgY29uc3Qgb2JqID0gewogICAgcmVwbGFjZTogKG5hbWUsIHZhbCkgPT4gewogICAgICB2YWwgPSB2YWwuc291cmNlIHx8IHZhbAogICAgICB2YWwgPSB2YWwucmVwbGFjZShjYXJldCwgIiQxIikKICAgICAgcmVnZXggPSByZWdleC5yZXBsYWNlKG5hbWUsIHZhbCkKICAgICAgcmV0dXJuIG9iagogICAgfSwKICAgIGdldFJlZ2V4OiAoKSA9PiB7CiAgICAgIHJldHVybiBuZXcgUmVnRXhwKHJlZ2V4LCBvcHQpCiAgICB9LAogIH0KICByZXR1cm4gb2JqCn0KCmNvbnN0IG5vbldvcmRBbmRDb2xvblRlc3QgPSAvW15cdzpdL2cKY29uc3Qgb3JpZ2luSW5kZXBlbmRlbnRVcmwgPSAvXiR8XlthLXpdW2EtejAtOSsuLV0qOnxeWz8jXS9pCgovKioKICogQHBhcmFtIHtib29sZWFufSBzYW5pdGl6ZQogKiBAcGFyYW0ge3N0cmluZ30gYmFzZQogKiBAcGFyYW0ge3N0cmluZ30gaHJlZgogKi8KZnVuY3Rpb24gY2xlYW5Vcmwoc2FuaXRpemUsIGJhc2UsIGhyZWYpIHsKICBpZiAoc2FuaXRpemUpIHsKICAgIGxldCBwcm90CiAgICB0cnkgewogICAgICBwcm90ID0gZGVjb2RlVVJJQ29tcG9uZW50KHVuZXNjYXBlKGhyZWYpKQogICAgICAgIC5yZXBsYWNlKG5vbldvcmRBbmRDb2xvblRlc3QsICIiKQogICAgICAgIC50b0xvd2VyQ2FzZSgpCiAgICB9IGNhdGNoIChlKSB7CiAgICAgIHJldHVybiBudWxsCiAgICB9CiAgICBpZiAoCiAgICAgIHByb3QuaW5kZXhPZigiamF2YXNjcmlwdDoiKSA9PT0gMCB8fAogICAgICBwcm90LmluZGV4T2YoInZic2NyaXB0OiIpID09PSAwIHx8CiAgICAgIHByb3QuaW5kZXhPZigiZGF0YToiKSA9PT0gMAogICAgKSB7CiAgICAgIHJldHVybiBudWxsCiAgICB9CiAgfQogIGlmIChiYXNlICYmICFvcmlnaW5JbmRlcGVuZGVudFVybC50ZXN0KGhyZWYpKSB7CiAgICBocmVmID0gcmVzb2x2ZVVybChiYXNlLCBocmVmKQogIH0KICB0cnkgewogICAgaHJlZiA9IGVuY29kZVVSSShocmVmKS5yZXBsYWNlKC8lMjUvZywgIiUiKQogIH0gY2F0Y2ggKGUpIHsKICAgIHJldHVybiBudWxsCiAgfQogIHJldHVybiBocmVmCn0KCmNvbnN0IGJhc2VVcmxzID0ge30KY29uc3QganVzdERvbWFpbiA9IC9eW146XSs6XC8qW14vXSokLwpjb25zdCBwcm90b2NvbCA9IC9eKFteOl0rOilbXHNcU10qJC8KY29uc3QgZG9tYWluID0gL14oW146XSs6XC8qW14vXSopW1xzXFNdKiQvCgovKioKICogQHBhcmFtIHtzdHJpbmd9IGJhc2UKICogQHBhcmFtIHtzdHJpbmd9IGhyZWYKICovCmZ1bmN0aW9uIHJlc29sdmVVcmwoYmFzZSwgaHJlZikgewogIGlmICghYmFzZVVybHNbIiAiICsgYmFzZV0pIHsKICAgIC8vIHdlIGNhbiBpZ25vcmUgZXZlcnl0aGluZyBpbiBiYXNlIGFmdGVyIHRoZSBsYXN0IHNsYXNoIG9mIGl0cyBwYXRoIGNvbXBvbmVudCwKICAgIC8vIGJ1dCB3ZSBtaWdodCBuZWVkIHRvIGFkZCBfdGhhdF8KICAgIC8vIGh0dHBzOi8vdG9vbHMuaWV0Zi5vcmcvaHRtbC9yZmMzOTg2I3NlY3Rpb24tMwogICAgaWYgKGp1c3REb21haW4udGVzdChiYXNlKSkgewogICAgICBiYXNlVXJsc1siICIgKyBiYXNlXSA9IGJhc2UgKyAiLyIKICAgIH0gZWxzZSB7CiAgICAgIGJhc2VVcmxzWyIgIiArIGJhc2VdID0gcnRyaW0oYmFzZSwgIi8iLCB0cnVlKQogICAgfQogIH0KICBiYXNlID0gYmFzZVVybHNbIiAiICsgYmFzZV0KICBjb25zdCByZWxhdGl2ZUJhc2UgPSBiYXNlLmluZGV4T2YoIjoiKSA9PT0gLTEKCiAgaWYgKGhyZWYuc3Vic3RyaW5nKDAsIDIpID09PSAiLy8iKSB7CiAgICBpZiAocmVsYXRpdmVCYXNlKSB7CiAgICAgIHJldHVybiBocmVmCiAgICB9CiAgICByZXR1cm4gYmFzZS5yZXBsYWNlKHByb3RvY29sLCAiJDEiKSArIGhyZWYKICB9IGVsc2UgaWYgKGhyZWYuY2hhckF0KDApID09PSAiLyIpIHsKICAgIGlmIChyZWxhdGl2ZUJhc2UpIHsKICAgICAgcmV0dXJuIGhyZWYKICAgIH0KICAgIHJldHVybiBiYXNlLnJlcGxhY2UoZG9tYWluLCAiJDEiKSArIGhyZWYKICB9IGVsc2UgewogICAgcmV0dXJuIGJhc2UgKyBocmVmCiAgfQp9Cgpjb25zdCBub29wVGVzdCA9IHsgZXhlYzogZnVuY3Rpb24gbm9vcFRlc3QoKSB7fSB9CgpmdW5jdGlvbiBtZXJnZShvYmopIHsKICBsZXQgaSA9IDEsCiAgICB0YXJnZXQsCiAgICBrZXkKCiAgZm9yICg7IGkgPCBhcmd1bWVudHMubGVuZ3RoOyBpKyspIHsKICAgIHRhcmdldCA9IGFyZ3VtZW50c1tpXQogICAgZm9yIChrZXkgaW4gdGFyZ2V0KSB7CiAgICAgIGlmIChPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwodGFyZ2V0LCBrZXkpKSB7CiAgICAgICAgb2JqW2tleV0gPSB0YXJnZXRba2V5XQogICAgICB9CiAgICB9CiAgfQoKICByZXR1cm4gb2JqCn0KCmZ1bmN0aW9uIHNwbGl0Q2VsbHModGFibGVSb3csIGNvdW50KSB7CiAgLy8gZW5zdXJlIHRoYXQgZXZlcnkgY2VsbC1kZWxpbWl0aW5nIHBpcGUgaGFzIGEgc3BhY2UKICAvLyBiZWZvcmUgaXQgdG8gZGlzdGluZ3Vpc2ggaXQgZnJvbSBhbiBlc2NhcGVkIHBpcGUKICBjb25zdCByb3cgPSB0YWJsZVJvdy5yZXBsYWNlKC9cfC9nLCAobWF0Y2gsIG9mZnNldCwgc3RyKSA9PiB7CiAgICAgIGxldCBlc2NhcGVkID0gZmFsc2UsCiAgICAgICAgY3VyciA9IG9mZnNldAogICAgICB3aGlsZSAoLS1jdXJyID49IDAgJiYgc3RyW2N1cnJdID09PSAiXFwiKSBlc2NhcGVkID0gIWVzY2FwZWQKICAgICAgaWYgKGVzY2FwZWQpIHsKICAgICAgICAvLyBvZGQgbnVtYmVyIG9mIHNsYXNoZXMgbWVhbnMgfCBpcyBlc2NhcGVkCiAgICAgICAgLy8gc28gd2UgbGVhdmUgaXQgYWxvbmUKICAgICAgICByZXR1cm4gInwiCiAgICAgIH0gZWxzZSB7CiAgICAgICAgLy8gYWRkIHNwYWNlIGJlZm9yZSB1bmVzY2FwZWQgfAogICAgICAgIHJldHVybiAiIHwiCiAgICAgIH0KICAgIH0pLAogICAgY2VsbHMgPSByb3cuc3BsaXQoLyBcfC8pCiAgbGV0IGkgPSAwCgogIC8vIEZpcnN0L2xhc3QgY2VsbCBpbiBhIHJvdyBjYW5ub3QgYmUgZW1wdHkgaWYgaXQgaGFzIG5vIGxlYWRpbmcvdHJhaWxpbmcgcGlwZQogIGlmICghY2VsbHNbMF0udHJpbSgpKSB7CiAgICBjZWxscy5zaGlmdCgpCiAgfQogIGlmIChjZWxscy5sZW5ndGggPiAwICYmICFjZWxsc1tjZWxscy5sZW5ndGggLSAxXS50cmltKCkpIHsKICAgIGNlbGxzLnBvcCgpCiAgfQoKICBpZiAoY2VsbHMubGVuZ3RoID4gY291bnQpIHsKICAgIGNlbGxzLnNwbGljZShjb3VudCkKICB9IGVsc2UgewogICAgd2hpbGUgKGNlbGxzLmxlbmd0aCA8IGNvdW50KSBjZWxscy5wdXNoKCIiKQogIH0KCiAgZm9yICg7IGkgPCBjZWxscy5sZW5ndGg7IGkrKykgewogICAgLy8gbGVhZGluZyBvciB0cmFpbGluZyB3aGl0ZXNwYWNlIGlzIGlnbm9yZWQgcGVyIHRoZSBnZm0gc3BlYwogICAgY2VsbHNbaV0gPSBjZWxsc1tpXS50cmltKCkucmVwbGFjZSgvXFxcfC9nLCAifCIpCiAgfQogIHJldHVybiBjZWxscwp9CgovKioKICogUmVtb3ZlIHRyYWlsaW5nICdjJ3MuIEVxdWl2YWxlbnQgdG8gc3RyLnJlcGxhY2UoL2MqJC8sICcnKS4KICogL2MqJC8gaXMgdnVsbmVyYWJsZSB0byBSRURPUy4KICoKICogQHBhcmFtIHtzdHJpbmd9IHN0cgogKiBAcGFyYW0ge3N0cmluZ30gYwogKiBAcGFyYW0ge2Jvb2xlYW59IGludmVydCBSZW1vdmUgc3VmZml4IG9mIG5vbi1jIGNoYXJzIGluc3RlYWQuIERlZmF1bHQgZmFsc2V5LgogKi8KZnVuY3Rpb24gcnRyaW0oc3RyLCBjLCBpbnZlcnQpIHsKICBjb25zdCBsID0gc3RyLmxlbmd0aAogIGlmIChsID09PSAwKSB7CiAgICByZXR1cm4gIiIKICB9CgogIC8vIExlbmd0aCBvZiBzdWZmaXggbWF0Y2hpbmcgdGhlIGludmVydCBjb25kaXRpb24uCiAgbGV0IHN1ZmZMZW4gPSAwCgogIC8vIFN0ZXAgbGVmdCB1bnRpbCB3ZSBmYWlsIHRvIG1hdGNoIHRoZSBpbnZlcnQgY29uZGl0aW9uLgogIHdoaWxlIChzdWZmTGVuIDwgbCkgewogICAgY29uc3QgY3VyckNoYXIgPSBzdHIuY2hhckF0KGwgLSBzdWZmTGVuIC0gMSkKICAgIGlmIChjdXJyQ2hhciA9PT0gYyAmJiAhaW52ZXJ0KSB7CiAgICAgIHN1ZmZMZW4rKwogICAgfSBlbHNlIGlmIChjdXJyQ2hhciAhPT0gYyAmJiBpbnZlcnQpIHsKICAgICAgc3VmZkxlbisrCiAgICB9IGVsc2UgewogICAgICBicmVhawogICAgfQogIH0KCiAgcmV0dXJuIHN0ci5zbGljZSgwLCBsIC0gc3VmZkxlbikKfQoKZnVuY3Rpb24gZmluZENsb3NpbmdCcmFja2V0KHN0ciwgYikgewogIGlmIChzdHIuaW5kZXhPZihiWzFdKSA9PT0gLTEpIHsKICAgIHJldHVybiAtMQogIH0KICBjb25zdCBsID0gc3RyLmxlbmd0aAogIGxldCBsZXZlbCA9IDAsCiAgICBpID0gMAogIGZvciAoOyBpIDwgbDsgaSsrKSB7CiAgICBpZiAoc3RyW2ldID09PSAiXFwiKSB7CiAgICAgIGkrKwogICAgfSBlbHNlIGlmIChzdHJbaV0gPT09IGJbMF0pIHsKICAgICAgbGV2ZWwrKwogICAgfSBlbHNlIGlmIChzdHJbaV0gPT09IGJbMV0pIHsKICAgICAgbGV2ZWwtLQogICAgICBpZiAobGV2ZWwgPCAwKSB7CiAgICAgICAgcmV0dXJuIGkKICAgICAgfQogICAgfQogIH0KICByZXR1cm4gLTEKfQoKZnVuY3Rpb24gY2hlY2tTYW5pdGl6ZURlcHJlY2F0aW9uKG9wdCkgewogIGlmIChvcHQgJiYgb3B0LnNhbml0aXplICYmICFvcHQuc2lsZW50KSB7CiAgICBjb25zb2xlLndhcm4oCiAgICAgICJtYXJrZWQoKTogc2FuaXRpemUgYW5kIHNhbml0aXplciBwYXJhbWV0ZXJzIGFyZSBkZXByZWNhdGVkIHNpbmNlIHZlcnNpb24gMC43LjAsIHNob3VsZCBub3QgYmUgdXNlZCBhbmQgd2lsbCBiZSByZW1vdmVkIGluIHRoZSBmdXR1cmUuIFJlYWQgbW9yZSBoZXJlOiBodHRwczovL21hcmtlZC5qcy5vcmcvIy9VU0lOR19BRFZBTkNFRC5tZCNvcHRpb25zIgogICAgKQogIH0KfQoKLy8gY29waWVkIGZyb20gaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9hLzU0NTAxMTMvODA2Nzc3Ci8qKgogKiBAcGFyYW0ge3N0cmluZ30gcGF0dGVybgogKiBAcGFyYW0ge251bWJlcn0gY291bnQKICovCmZ1bmN0aW9uIHJlcGVhdFN0cmluZyhwYXR0ZXJuLCBjb3VudCkgewogIGlmIChjb3VudCA8IDEpIHsKICAgIHJldHVybiAiIgogIH0KICBsZXQgcmVzdWx0ID0gIiIKICB3aGlsZSAoY291bnQgPiAxKSB7CiAgICBpZiAoY291bnQgJiAxKSB7CiAgICAgIHJlc3VsdCArPSBwYXR0ZXJuCiAgICB9CiAgICBjb3VudCA+Pj0gMQogICAgcGF0dGVybiArPSBwYXR0ZXJuCiAgfQogIHJldHVybiByZXN1bHQgKyBwYXR0ZXJuCn0KCmZ1bmN0aW9uIG91dHB1dExpbmsoY2FwLCBsaW5rLCByYXcsIGxleGVyKSB7CiAgY29uc3QgaHJlZiA9IGxpbmsuaHJlZgogIGNvbnN0IHRpdGxlID0gbGluay50aXRsZSA/IGVzY2FwZShsaW5rLnRpdGxlKSA6IG51bGwKICBjb25zdCB0ZXh0ID0gY2FwWzFdLnJlcGxhY2UoL1xcKFtcW1xdXSkvZywgIiQxIikKCiAgaWYgKGNhcFswXS5jaGFyQXQoMCkgIT09ICIhIikgewogICAgbGV4ZXIuc3RhdGUuaW5MaW5rID0gdHJ1ZQogICAgY29uc3QgdG9rZW4gPSB7CiAgICAgIHR5cGU6ICJsaW5rIiwKICAgICAgcmF3LAogICAgICBocmVmLAogICAgICB0aXRsZSwKICAgICAgdGV4dCwKICAgICAgdG9rZW5zOiBsZXhlci5pbmxpbmVUb2tlbnModGV4dCwgW10pLAogICAgfQogICAgbGV4ZXIuc3RhdGUuaW5MaW5rID0gZmFsc2UKICAgIHJldHVybiB0b2tlbgogIH0KICByZXR1cm4gewogICAgdHlwZTogImltYWdlIiwKICAgIHJhdywKICAgIGhyZWYsCiAgICB0aXRsZSwKICAgIHRleHQ6IGVzY2FwZSh0ZXh0KSwKICB9Cn0KCmZ1bmN0aW9uIGluZGVudENvZGVDb21wZW5zYXRpb24ocmF3LCB0ZXh0KSB7CiAgY29uc3QgbWF0Y2hJbmRlbnRUb0NvZGUgPSByYXcubWF0Y2goL14oXHMrKSg/OmBgYCkvKQoKICBpZiAobWF0Y2hJbmRlbnRUb0NvZGUgPT09IG51bGwpIHsKICAgIHJldHVybiB0ZXh0CiAgfQoKICBjb25zdCBpbmRlbnRUb0NvZGUgPSBtYXRjaEluZGVudFRvQ29kZVsxXQoKICByZXR1cm4gdGV4dAogICAgLnNwbGl0KCJcbiIpCiAgICAubWFwKG5vZGUgPT4gewogICAgICBjb25zdCBtYXRjaEluZGVudEluTm9kZSA9IG5vZGUubWF0Y2goL15ccysvKQogICAgICBpZiAobWF0Y2hJbmRlbnRJbk5vZGUgPT09IG51bGwpIHsKICAgICAgICByZXR1cm4gbm9kZQogICAgICB9CgogICAgICBjb25zdCBbaW5kZW50SW5Ob2RlXSA9IG1hdGNoSW5kZW50SW5Ob2RlCgogICAgICBpZiAoaW5kZW50SW5Ob2RlLmxlbmd0aCA+PSBpbmRlbnRUb0NvZGUubGVuZ3RoKSB7CiAgICAgICAgcmV0dXJuIG5vZGUuc2xpY2UoaW5kZW50VG9Db2RlLmxlbmd0aCkKICAgICAgfQoKICAgICAgcmV0dXJuIG5vZGUKICAgIH0pCiAgICAuam9pbigiXG4iKQp9CgovKioKICogVG9rZW5pemVyCiAqLwpjbGFzcyBUb2tlbml6ZXIgewogIGNvbnN0cnVjdG9yKG9wdGlvbnMpIHsKICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnMgfHwgZGVmYXVsdHMKICB9CgogIHNwYWNlKHNyYykgewogICAgY29uc3QgY2FwID0gdGhpcy5ydWxlcy5ibG9jay5uZXdsaW5lLmV4ZWMoc3JjKQogICAgaWYgKGNhcCAmJiBjYXBbMF0ubGVuZ3RoID4gMCkgewogICAgICByZXR1cm4gewogICAgICAgIHR5cGU6ICJzcGFjZSIsCiAgICAgICAgcmF3OiBjYXBbMF0sCiAgICAgIH0KICAgIH0KICB9CgogIGNvZGUoc3JjKSB7CiAgICBjb25zdCBjYXAgPSB0aGlzLnJ1bGVzLmJsb2NrLmNvZGUuZXhlYyhzcmMpCiAgICBpZiAoY2FwKSB7CiAgICAgIGNvbnN0IHRleHQgPSBjYXBbMF0ucmVwbGFjZSgvXiB7MSw0fS9nbSwgIiIpCiAgICAgIHJldHVybiB7CiAgICAgICAgdHlwZTogImNvZGUiLAogICAgICAgIHJhdzogY2FwWzBdLAogICAgICAgIGNvZGVCbG9ja1N0eWxlOiAiaW5kZW50ZWQiLAogICAgICAgIHRleHQ6ICF0aGlzLm9wdGlvbnMucGVkYW50aWMgPyBydHJpbSh0ZXh0LCAiXG4iKSA6IHRleHQsCiAgICAgIH0KICAgIH0KICB9CgogIGZlbmNlcyhzcmMpIHsKICAgIGNvbnN0IGNhcCA9IHRoaXMucnVsZXMuYmxvY2suZmVuY2VzLmV4ZWMoc3JjKQogICAgaWYgKGNhcCkgewogICAgICBjb25zdCByYXcgPSBjYXBbMF0KICAgICAgY29uc3QgdGV4dCA9IGluZGVudENvZGVDb21wZW5zYXRpb24ocmF3LCBjYXBbM10gfHwgIiIpCgogICAgICByZXR1cm4gewogICAgICAgIHR5cGU6ICJjb2RlIiwKICAgICAgICByYXcsCiAgICAgICAgbGFuZzogY2FwWzJdID8gY2FwWzJdLnRyaW0oKSA6IGNhcFsyXSwKICAgICAgICB0ZXh0LAogICAgICB9CiAgICB9CiAgfQoKICBoZWFkaW5nKHNyYykgewogICAgY29uc3QgY2FwID0gdGhpcy5ydWxlcy5ibG9jay5oZWFkaW5nLmV4ZWMoc3JjKQogICAgaWYgKGNhcCkgewogICAgICBsZXQgdGV4dCA9IGNhcFsyXS50cmltKCkKCiAgICAgIC8vIHJlbW92ZSB0cmFpbGluZyAjcwogICAgICBpZiAoLyMkLy50ZXN0KHRleHQpKSB7CiAgICAgICAgY29uc3QgdHJpbW1lZCA9IHJ0cmltKHRleHQsICIjIikKICAgICAgICBpZiAodGhpcy5vcHRpb25zLnBlZGFudGljKSB7CiAgICAgICAgICB0ZXh0ID0gdHJpbW1lZC50cmltKCkKICAgICAgICB9IGVsc2UgaWYgKCF0cmltbWVkIHx8IC8gJC8udGVzdCh0cmltbWVkKSkgewogICAgICAgICAgLy8gQ29tbW9uTWFyayByZXF1aXJlcyBzcGFjZSBiZWZvcmUgdHJhaWxpbmcgI3MKICAgICAgICAgIHRleHQgPSB0cmltbWVkLnRyaW0oKQogICAgICAgIH0KICAgICAgfQoKICAgICAgY29uc3QgdG9rZW4gPSB7CiAgICAgICAgdHlwZTogImhlYWRpbmciLAogICAgICAgIHJhdzogY2FwWzBdLAogICAgICAgIGRlcHRoOiBjYXBbMV0ubGVuZ3RoLAogICAgICAgIHRleHQsCiAgICAgICAgdG9rZW5zOiBbXSwKICAgICAgfQogICAgICB0aGlzLmxleGVyLmlubGluZSh0b2tlbi50ZXh0LCB0b2tlbi50b2tlbnMpCiAgICAgIHJldHVybiB0b2tlbgogICAgfQogIH0KCiAgaHIoc3JjKSB7CiAgICBjb25zdCBjYXAgPSB0aGlzLnJ1bGVzLmJsb2NrLmhyLmV4ZWMoc3JjKQogICAgaWYgKGNhcCkgewogICAgICByZXR1cm4gewogICAgICAgIHR5cGU6ICJociIsCiAgICAgICAgcmF3OiBjYXBbMF0sCiAgICAgIH0KICAgIH0KICB9CgogIGJsb2NrcXVvdGUoc3JjKSB7CiAgICBjb25zdCBjYXAgPSB0aGlzLnJ1bGVzLmJsb2NrLmJsb2NrcXVvdGUuZXhlYyhzcmMpCiAgICBpZiAoY2FwKSB7CiAgICAgIGNvbnN0IHRleHQgPSBjYXBbMF0ucmVwbGFjZSgvXiAqPlsgXHRdPy9nbSwgIiIpCgogICAgICByZXR1cm4gewogICAgICAgIHR5cGU6ICJibG9ja3F1b3RlIiwKICAgICAgICByYXc6IGNhcFswXSwKICAgICAgICB0b2tlbnM6IHRoaXMubGV4ZXIuYmxvY2tUb2tlbnModGV4dCwgW10pLAogICAgICAgIHRleHQsCiAgICAgIH0KICAgIH0KICB9CgogIGxpc3Qoc3JjKSB7CiAgICBsZXQgY2FwID0gdGhpcy5ydWxlcy5ibG9jay5saXN0LmV4ZWMoc3JjKQogICAgaWYgKGNhcCkgewogICAgICBsZXQgcmF3LAogICAgICAgIGlzdGFzaywKICAgICAgICBpc2NoZWNrZWQsCiAgICAgICAgaW5kZW50LAogICAgICAgIGksCiAgICAgICAgYmxhbmtMaW5lLAogICAgICAgIGVuZHNXaXRoQmxhbmtMaW5lLAogICAgICAgIGxpbmUsCiAgICAgICAgbmV4dExpbmUsCiAgICAgICAgcmF3TGluZSwKICAgICAgICBpdGVtQ29udGVudHMsCiAgICAgICAgZW5kRWFybHkKCiAgICAgIGxldCBidWxsID0gY2FwWzFdLnRyaW0oKQogICAgICBjb25zdCBpc29yZGVyZWQgPSBidWxsLmxlbmd0aCA+IDEKCiAgICAgIGNvbnN0IGxpc3QgPSB7CiAgICAgICAgdHlwZTogImxpc3QiLAogICAgICAgIHJhdzogIiIsCiAgICAgICAgb3JkZXJlZDogaXNvcmRlcmVkLAogICAgICAgIHN0YXJ0OiBpc29yZGVyZWQgPyArYnVsbC5zbGljZSgwLCAtMSkgOiAiIiwKICAgICAgICBsb29zZTogZmFsc2UsCiAgICAgICAgaXRlbXM6IFtdLAogICAgICB9CgogICAgICBidWxsID0gaXNvcmRlcmVkID8gYFxcZHsxLDl9XFwke2J1bGwuc2xpY2UoLTEpfWAgOiBgXFwke2J1bGx9YAoKICAgICAgaWYgKHRoaXMub3B0aW9ucy5wZWRhbnRpYykgewogICAgICAgIGJ1bGwgPSBpc29yZGVyZWQgPyBidWxsIDogIlsqKy1dIgogICAgICB9CgogICAgICAvLyBHZXQgbmV4dCBsaXN0IGl0ZW0KICAgICAgY29uc3QgaXRlbVJlZ2V4ID0gbmV3IFJlZ0V4cCgKICAgICAgICBgXiggezAsM30ke2J1bGx9KSgoPzpbXHQgXVteXFxuXSopPyg/OlxcbnwkKSlgCiAgICAgICkKCiAgICAgIC8vIENoZWNrIGlmIGN1cnJlbnQgYnVsbGV0IHBvaW50IGNhbiBzdGFydCBhIG5ldyBMaXN0IEl0ZW0KICAgICAgd2hpbGUgKHNyYykgewogICAgICAgIGVuZEVhcmx5ID0gZmFsc2UKICAgICAgICBpZiAoIShjYXAgPSBpdGVtUmVnZXguZXhlYyhzcmMpKSkgewogICAgICAgICAgYnJlYWsKICAgICAgICB9CgogICAgICAgIGlmICh0aGlzLnJ1bGVzLmJsb2NrLmhyLnRlc3Qoc3JjKSkgewogICAgICAgICAgLy8gRW5kIGxpc3QgaWYgYnVsbGV0IHdhcyBhY3R1YWxseSBIUiAocG9zc2libHkgbW92ZSBpbnRvIGl0ZW1SZWdleD8pCiAgICAgICAgICBicmVhawogICAgICAgIH0KCiAgICAgICAgcmF3ID0gY2FwWzBdCiAgICAgICAgc3JjID0gc3JjLnN1YnN0cmluZyhyYXcubGVuZ3RoKQoKICAgICAgICBsaW5lID0gY2FwWzJdLnNwbGl0KCJcbiIsIDEpWzBdCiAgICAgICAgbmV4dExpbmUgPSBzcmMuc3BsaXQoIlxuIiwgMSlbMF0KCiAgICAgICAgaWYgKHRoaXMub3B0aW9ucy5wZWRhbnRpYykgewogICAgICAgICAgaW5kZW50ID0gMgogICAgICAgICAgaXRlbUNvbnRlbnRzID0gbGluZS50cmltTGVmdCgpCiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIGluZGVudCA9IGNhcFsyXS5zZWFyY2goL1teIF0vKSAvLyBGaW5kIGZpcnN0IG5vbi1zcGFjZSBjaGFyCiAgICAgICAgICBpbmRlbnQgPSBpbmRlbnQgPiA0ID8gMSA6IGluZGVudCAvLyBUcmVhdCBpbmRlbnRlZCBjb2RlIGJsb2NrcyAoPiA0IHNwYWNlcykgYXMgaGF2aW5nIG9ubHkgMSBpbmRlbnQKICAgICAgICAgIGl0ZW1Db250ZW50cyA9IGxpbmUuc2xpY2UoaW5kZW50KQogICAgICAgICAgaW5kZW50ICs9IGNhcFsxXS5sZW5ndGgKICAgICAgICB9CgogICAgICAgIGJsYW5rTGluZSA9IGZhbHNlCgogICAgICAgIGlmICghbGluZSAmJiAvXiAqJC8udGVzdChuZXh0TGluZSkpIHsKICAgICAgICAgIC8vIEl0ZW1zIGJlZ2luIHdpdGggYXQgbW9zdCBvbmUgYmxhbmsgbGluZQogICAgICAgICAgcmF3ICs9IG5leHRMaW5lICsgIlxuIgogICAgICAgICAgc3JjID0gc3JjLnN1YnN0cmluZyhuZXh0TGluZS5sZW5ndGggKyAxKQogICAgICAgICAgZW5kRWFybHkgPSB0cnVlCiAgICAgICAgfQoKICAgICAgICBpZiAoIWVuZEVhcmx5KSB7CiAgICAgICAgICBjb25zdCBuZXh0QnVsbGV0UmVnZXggPSBuZXcgUmVnRXhwKAogICAgICAgICAgICBgXiB7MCwke01hdGgubWluKAogICAgICAgICAgICAgIDMsCiAgICAgICAgICAgICAgaW5kZW50IC0gMQogICAgICAgICAgICApfX0oPzpbKistXXxcXGR7MSw5fVsuKV0pKCg/OiBbXlxcbl0qKT8oPzpcXG58JCkpYAogICAgICAgICAgKQogICAgICAgICAgY29uc3QgaHJSZWdleCA9IG5ldyBSZWdFeHAoCiAgICAgICAgICAgIGBeIHswLCR7TWF0aC5taW4oCiAgICAgICAgICAgICAgMywKICAgICAgICAgICAgICBpbmRlbnQgLSAxCiAgICAgICAgICAgICl9fSgoPzotICopezMsfXwoPzpfICopezMsfXwoPzpcXCogKil7Myx9KSg/Olxcbit8JClgCiAgICAgICAgICApCgogICAgICAgICAgLy8gQ2hlY2sgaWYgZm9sbG93aW5nIGxpbmVzIHNob3VsZCBiZSBpbmNsdWRlZCBpbiBMaXN0IEl0ZW0KICAgICAgICAgIHdoaWxlIChzcmMpIHsKICAgICAgICAgICAgcmF3TGluZSA9IHNyYy5zcGxpdCgiXG4iLCAxKVswXQogICAgICAgICAgICBsaW5lID0gcmF3TGluZQoKICAgICAgICAgICAgLy8gUmUtYWxpZ24gdG8gZm9sbG93IGNvbW1vbm1hcmsgbmVzdGluZyBydWxlcwogICAgICAgICAgICBpZiAodGhpcy5vcHRpb25zLnBlZGFudGljKSB7CiAgICAgICAgICAgICAgbGluZSA9IGxpbmUucmVwbGFjZSgvXiB7MSw0fSg/PSggezR9KSpbXiBdKS9nLCAiICAiKQogICAgICAgICAgICB9CgogICAgICAgICAgICAvLyBFbmQgbGlzdCBpdGVtIGlmIGZvdW5kIHN0YXJ0IG9mIG5ldyBidWxsZXQKICAgICAgICAgICAgaWYgKG5leHRCdWxsZXRSZWdleC50ZXN0KGxpbmUpKSB7CiAgICAgICAgICAgICAgYnJlYWsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgLy8gSG9yaXpvbnRhbCBydWxlIGZvdW5kCiAgICAgICAgICAgIGlmIChoclJlZ2V4LnRlc3Qoc3JjKSkgewogICAgICAgICAgICAgIGJyZWFrCiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGlmIChsaW5lLnNlYXJjaCgvW14gXS8pID49IGluZGVudCB8fCAhbGluZS50cmltKCkpIHsKICAgICAgICAgICAgICAvLyBEZWRlbnQgaWYgcG9zc2libGUKICAgICAgICAgICAgICBpdGVtQ29udGVudHMgKz0gIlxuIiArIGxpbmUuc2xpY2UoaW5kZW50KQogICAgICAgICAgICB9IGVsc2UgaWYgKCFibGFua0xpbmUpIHsKICAgICAgICAgICAgICAvLyBVbnRpbCBibGFuayBsaW5lLCBpdGVtIGRvZXNuJ3QgbmVlZCBpbmRlbnRhdGlvbgogICAgICAgICAgICAgIGl0ZW1Db250ZW50cyArPSAiXG4iICsgbGluZQogICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgIC8vIE90aGVyd2lzZSwgaW1wcm9wZXIgaW5kZW50YXRpb24gZW5kcyB0aGlzIGl0ZW0KICAgICAgICAgICAgICBicmVhawogICAgICAgICAgICB9CgogICAgICAgICAgICBpZiAoIWJsYW5rTGluZSAmJiAhbGluZS50cmltKCkpIHsKICAgICAgICAgICAgICAvLyBDaGVjayBpZiBjdXJyZW50IGxpbmUgaXMgYmxhbmsKICAgICAgICAgICAgICBibGFua0xpbmUgPSB0cnVlCiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIHJhdyArPSByYXdMaW5lICsgIlxuIgogICAgICAgICAgICBzcmMgPSBzcmMuc3Vic3RyaW5nKHJhd0xpbmUubGVuZ3RoICsgMSkKICAgICAgICAgIH0KICAgICAgICB9CgogICAgICAgIGlmICghbGlzdC5sb29zZSkgewogICAgICAgICAgLy8gSWYgdGhlIHByZXZpb3VzIGl0ZW0gZW5kZWQgd2l0aCBhIGJsYW5rIGxpbmUsIHRoZSBsaXN0IGlzIGxvb3NlCiAgICAgICAgICBpZiAoZW5kc1dpdGhCbGFua0xpbmUpIHsKICAgICAgICAgICAgbGlzdC5sb29zZSA9IHRydWUKICAgICAgICAgIH0gZWxzZSBpZiAoL1xuICpcbiAqJC8udGVzdChyYXcpKSB7CiAgICAgICAgICAgIGVuZHNXaXRoQmxhbmtMaW5lID0gdHJ1ZQogICAgICAgICAgfQogICAgICAgIH0KCiAgICAgICAgLy8gQ2hlY2sgZm9yIHRhc2sgbGlzdCBpdGVtcwogICAgICAgIGlmICh0aGlzLm9wdGlvbnMuZ2ZtKSB7CiAgICAgICAgICBpc3Rhc2sgPSAvXlxbWyB4WF1cXSAvLmV4ZWMoaXRlbUNvbnRlbnRzKQogICAgICAgICAgaWYgKGlzdGFzaykgewogICAgICAgICAgICBpc2NoZWNrZWQgPSBpc3Rhc2tbMF0gIT09ICJbIF0gIgogICAgICAgICAgICBpdGVtQ29udGVudHMgPSBpdGVtQ29udGVudHMucmVwbGFjZSgvXlxbWyB4WF1cXSArLywgIiIpCiAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICBsaXN0Lml0ZW1zLnB1c2goewogICAgICAgICAgdHlwZTogImxpc3RfaXRlbSIsCiAgICAgICAgICByYXcsCiAgICAgICAgICB0YXNrOiAhIWlzdGFzaywKICAgICAgICAgIGNoZWNrZWQ6IGlzY2hlY2tlZCwKICAgICAgICAgIGxvb3NlOiBmYWxzZSwKICAgICAgICAgIHRleHQ6IGl0ZW1Db250ZW50cywKICAgICAgICB9KQoKICAgICAgICBsaXN0LnJhdyArPSByYXcKICAgICAgfQoKICAgICAgLy8gRG8gbm90IGNvbnN1bWUgbmV3bGluZXMgYXQgZW5kIG9mIGZpbmFsIGl0ZW0uIEFsdGVybmF0aXZlbHksIG1ha2UgaXRlbVJlZ2V4ICpzdGFydCogd2l0aCBhbnkgbmV3bGluZXMgdG8gc2ltcGxpZnkvc3BlZWQgdXAgZW5kc1dpdGhCbGFua0xpbmUgbG9naWMKICAgICAgbGlzdC5pdGVtc1tsaXN0Lml0ZW1zLmxlbmd0aCAtIDFdLnJhdyA9IHJhdy50cmltUmlnaHQoKQogICAgICBsaXN0Lml0ZW1zW2xpc3QuaXRlbXMubGVuZ3RoIC0gMV0udGV4dCA9IGl0ZW1Db250ZW50cy50cmltUmlnaHQoKQogICAgICBsaXN0LnJhdyA9IGxpc3QucmF3LnRyaW1SaWdodCgpCgogICAgICBjb25zdCBsID0gbGlzdC5pdGVtcy5sZW5ndGgKCiAgICAgIC8vIEl0ZW0gY2hpbGQgdG9rZW5zIGhhbmRsZWQgaGVyZSBhdCBlbmQgYmVjYXVzZSB3ZSBuZWVkZWQgdG8gaGF2ZSB0aGUgZmluYWwgaXRlbSB0byB0cmltIGl0IGZpcnN0CiAgICAgIGZvciAoaSA9IDA7IGkgPCBsOyBpKyspIHsKICAgICAgICB0aGlzLmxleGVyLnN0YXRlLnRvcCA9IGZhbHNlCiAgICAgICAgbGlzdC5pdGVtc1tpXS50b2tlbnMgPSB0aGlzLmxleGVyLmJsb2NrVG9rZW5zKGxpc3QuaXRlbXNbaV0udGV4dCwgW10pCiAgICAgICAgY29uc3Qgc3BhY2VycyA9IGxpc3QuaXRlbXNbaV0udG9rZW5zLmZpbHRlcih0ID0+IHQudHlwZSA9PT0gInNwYWNlIikKICAgICAgICBjb25zdCBoYXNNdWx0aXBsZUxpbmVCcmVha3MgPSBzcGFjZXJzLmV2ZXJ5KHQgPT4gewogICAgICAgICAgY29uc3QgY2hhcnMgPSB0LnJhdy5zcGxpdCgiIikKICAgICAgICAgIGxldCBsaW5lQnJlYWtzID0gMAogICAgICAgICAgZm9yIChjb25zdCBjaGFyIG9mIGNoYXJzKSB7CiAgICAgICAgICAgIGlmIChjaGFyID09PSAiXG4iKSB7CiAgICAgICAgICAgICAgbGluZUJyZWFrcyArPSAxCiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKGxpbmVCcmVha3MgPiAxKSB7CiAgICAgICAgICAgICAgcmV0dXJuIHRydWUKICAgICAgICAgICAgfQogICAgICAgICAgfQoKICAgICAgICAgIHJldHVybiBmYWxzZQogICAgICAgIH0pCgogICAgICAgIGlmICghbGlzdC5sb29zZSAmJiBzcGFjZXJzLmxlbmd0aCAmJiBoYXNNdWx0aXBsZUxpbmVCcmVha3MpIHsKICAgICAgICAgIC8vIEhhdmluZyBhIHNpbmdsZSBsaW5lIGJyZWFrIGRvZXNuJ3QgbWVhbiBhIGxpc3QgaXMgbG9vc2UuIEEgc2luZ2xlIGxpbmUgYnJlYWsgaXMgdGVybWluYXRpbmcgdGhlIGxhc3QgbGlzdCBpdGVtCiAgICAgICAgICBsaXN0Lmxvb3NlID0gdHJ1ZQogICAgICAgICAgbGlzdC5pdGVtc1tpXS5sb29zZSA9IHRydWUKICAgICAgICB9CiAgICAgIH0KCiAgICAgIHJldHVybiBsaXN0CiAgICB9CiAgfQoKICBodG1sKHNyYykgewogICAgY29uc3QgY2FwID0gdGhpcy5ydWxlcy5ibG9jay5odG1sLmV4ZWMoc3JjKQogICAgaWYgKGNhcCkgewogICAgICBjb25zdCB0b2tlbiA9IHsKICAgICAgICB0eXBlOiAiaHRtbCIsCiAgICAgICAgcmF3OiBjYXBbMF0sCiAgICAgICAgcHJlOgogICAgICAgICAgIXRoaXMub3B0aW9ucy5zYW5pdGl6ZXIgJiYKICAgICAgICAgIChjYXBbMV0gPT09ICJwcmUiIHx8IGNhcFsxXSA9PT0gInNjcmlwdCIgfHwgY2FwWzFdID09PSAic3R5bGUiKSwKICAgICAgICB0ZXh0OiBjYXBbMF0sCiAgICAgIH0KICAgICAgaWYgKHRoaXMub3B0aW9ucy5zYW5pdGl6ZSkgewogICAgICAgIHRva2VuLnR5cGUgPSAicGFyYWdyYXBoIgogICAgICAgIHRva2VuLnRleHQgPSB0aGlzLm9wdGlvbnMuc2FuaXRpemVyCiAgICAgICAgICA/IHRoaXMub3B0aW9ucy5zYW5pdGl6ZXIoY2FwWzBdKQogICAgICAgICAgOiBlc2NhcGUoY2FwWzBdKQogICAgICAgIHRva2VuLnRva2VucyA9IFtdCiAgICAgICAgdGhpcy5sZXhlci5pbmxpbmUodG9rZW4udGV4dCwgdG9rZW4udG9rZW5zKQogICAgICB9CiAgICAgIHJldHVybiB0b2tlbgogICAgfQogIH0KCiAgZGVmKHNyYykgewogICAgY29uc3QgY2FwID0gdGhpcy5ydWxlcy5ibG9jay5kZWYuZXhlYyhzcmMpCiAgICBpZiAoY2FwKSB7CiAgICAgIGlmIChjYXBbM10pIGNhcFszXSA9IGNhcFszXS5zdWJzdHJpbmcoMSwgY2FwWzNdLmxlbmd0aCAtIDEpCiAgICAgIGNvbnN0IHRhZyA9IGNhcFsxXS50b0xvd2VyQ2FzZSgpLnJlcGxhY2UoL1xzKy9nLCAiICIpCiAgICAgIHJldHVybiB7CiAgICAgICAgdHlwZTogImRlZiIsCiAgICAgICAgdGFnLAogICAgICAgIHJhdzogY2FwWzBdLAogICAgICAgIGhyZWY6IGNhcFsyXSwKICAgICAgICB0aXRsZTogY2FwWzNdLAogICAgICB9CiAgICB9CiAgfQoKICB0YWJsZShzcmMpIHsKICAgIGNvbnN0IGNhcCA9IHRoaXMucnVsZXMuYmxvY2sudGFibGUuZXhlYyhzcmMpCiAgICBpZiAoY2FwKSB7CiAgICAgIGNvbnN0IGl0ZW0gPSB7CiAgICAgICAgdHlwZTogInRhYmxlIiwKICAgICAgICBoZWFkZXI6IHNwbGl0Q2VsbHMoY2FwWzFdKS5tYXAoYyA9PiB7CiAgICAgICAgICByZXR1cm4geyB0ZXh0OiBjIH0KICAgICAgICB9KSwKICAgICAgICBhbGlnbjogY2FwWzJdLnJlcGxhY2UoL14gKnxcfCAqJC9nLCAiIikuc3BsaXQoLyAqXHwgKi8pLAogICAgICAgIHJvd3M6CiAgICAgICAgICBjYXBbM10gJiYgY2FwWzNdLnRyaW0oKQogICAgICAgICAgICA/IGNhcFszXS5yZXBsYWNlKC9cblsgXHRdKiQvLCAiIikuc3BsaXQoIlxuIikKICAgICAgICAgICAgOiBbXSwKICAgICAgfQoKICAgICAgaWYgKGl0ZW0uaGVhZGVyLmxlbmd0aCA9PT0gaXRlbS5hbGlnbi5sZW5ndGgpIHsKICAgICAgICBpdGVtLnJhdyA9IGNhcFswXQoKICAgICAgICBsZXQgbCA9IGl0ZW0uYWxpZ24ubGVuZ3RoCiAgICAgICAgbGV0IGksIGosIGssIHJvdwogICAgICAgIGZvciAoaSA9IDA7IGkgPCBsOyBpKyspIHsKICAgICAgICAgIGlmICgvXiAqLSs6ICokLy50ZXN0KGl0ZW0uYWxpZ25baV0pKSB7CiAgICAgICAgICAgIGl0ZW0uYWxpZ25baV0gPSAicmlnaHQiCiAgICAgICAgICB9IGVsc2UgaWYgKC9eICo6LSs6ICokLy50ZXN0KGl0ZW0uYWxpZ25baV0pKSB7CiAgICAgICAgICAgIGl0ZW0uYWxpZ25baV0gPSAiY2VudGVyIgogICAgICAgICAgfSBlbHNlIGlmICgvXiAqOi0rICokLy50ZXN0KGl0ZW0uYWxpZ25baV0pKSB7CiAgICAgICAgICAgIGl0ZW0uYWxpZ25baV0gPSAibGVmdCIKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIGl0ZW0uYWxpZ25baV0gPSBudWxsCiAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICBsID0gaXRlbS5yb3dzLmxlbmd0aAogICAgICAgIGZvciAoaSA9IDA7IGkgPCBsOyBpKyspIHsKICAgICAgICAgIGl0ZW0ucm93c1tpXSA9IHNwbGl0Q2VsbHMoaXRlbS5yb3dzW2ldLCBpdGVtLmhlYWRlci5sZW5ndGgpLm1hcChjID0+IHsKICAgICAgICAgICAgcmV0dXJuIHsgdGV4dDogYyB9CiAgICAgICAgICB9KQogICAgICAgIH0KCiAgICAgICAgLy8gcGFyc2UgY2hpbGQgdG9rZW5zIGluc2lkZSBoZWFkZXJzIGFuZCBjZWxscwoKICAgICAgICAvLyBoZWFkZXIgY2hpbGQgdG9rZW5zCiAgICAgICAgbCA9IGl0ZW0uaGVhZGVyLmxlbmd0aAogICAgICAgIGZvciAoaiA9IDA7IGogPCBsOyBqKyspIHsKICAgICAgICAgIGl0ZW0uaGVhZGVyW2pdLnRva2VucyA9IFtdCiAgICAgICAgICB0aGlzLmxleGVyLmlubGluZShpdGVtLmhlYWRlcltqXS50ZXh0LCBpdGVtLmhlYWRlcltqXS50b2tlbnMpCiAgICAgICAgfQoKICAgICAgICAvLyBjZWxsIGNoaWxkIHRva2VucwogICAgICAgIGwgPSBpdGVtLnJvd3MubGVuZ3RoCiAgICAgICAgZm9yIChqID0gMDsgaiA8IGw7IGorKykgewogICAgICAgICAgcm93ID0gaXRlbS5yb3dzW2pdCiAgICAgICAgICBmb3IgKGsgPSAwOyBrIDwgcm93Lmxlbmd0aDsgaysrKSB7CiAgICAgICAgICAgIHJvd1trXS50b2tlbnMgPSBbXQogICAgICAgICAgICB0aGlzLmxleGVyLmlubGluZShyb3dba10udGV4dCwgcm93W2tdLnRva2VucykKICAgICAgICAgIH0KICAgICAgICB9CgogICAgICAgIHJldHVybiBpdGVtCiAgICAgIH0KICAgIH0KICB9CgogIGxoZWFkaW5nKHNyYykgewogICAgY29uc3QgY2FwID0gdGhpcy5ydWxlcy5ibG9jay5saGVhZGluZy5leGVjKHNyYykKICAgIGlmIChjYXApIHsKICAgICAgY29uc3QgdG9rZW4gPSB7CiAgICAgICAgdHlwZTogImhlYWRpbmciLAogICAgICAgIHJhdzogY2FwWzBdLAogICAgICAgIGRlcHRoOiBjYXBbMl0uY2hhckF0KDApID09PSAiPSIgPyAxIDogMiwKICAgICAgICB0ZXh0OiBjYXBbMV0sCiAgICAgICAgdG9rZW5zOiBbXSwKICAgICAgfQogICAgICB0aGlzLmxleGVyLmlubGluZSh0b2tlbi50ZXh0LCB0b2tlbi50b2tlbnMpCiAgICAgIHJldHVybiB0b2tlbgogICAgfQogIH0KCiAgcGFyYWdyYXBoKHNyYykgewogICAgY29uc3QgY2FwID0gdGhpcy5ydWxlcy5ibG9jay5wYXJhZ3JhcGguZXhlYyhzcmMpCiAgICBpZiAoY2FwKSB7CiAgICAgIGNvbnN0IHRva2VuID0gewogICAgICAgIHR5cGU6ICJwYXJhZ3JhcGgiLAogICAgICAgIHJhdzogY2FwWzBdLAogICAgICAgIHRleHQ6CiAgICAgICAgICBjYXBbMV0uY2hhckF0KGNhcFsxXS5sZW5ndGggLSAxKSA9PT0gIlxuIgogICAgICAgICAgICA/IGNhcFsxXS5zbGljZSgwLCAtMSkKICAgICAgICAgICAgOiBjYXBbMV0sCiAgICAgICAgdG9rZW5zOiBbXSwKICAgICAgfQogICAgICB0aGlzLmxleGVyLmlubGluZSh0b2tlbi50ZXh0LCB0b2tlbi50b2tlbnMpCiAgICAgIHJldHVybiB0b2tlbgogICAgfQogIH0KCiAgdGV4dChzcmMpIHsKICAgIGNvbnN0IGNhcCA9IHRoaXMucnVsZXMuYmxvY2sudGV4dC5leGVjKHNyYykKICAgIGlmIChjYXApIHsKICAgICAgY29uc3QgdG9rZW4gPSB7CiAgICAgICAgdHlwZTogInRleHQiLAogICAgICAgIHJhdzogY2FwWzBdLAogICAgICAgIHRleHQ6IGNhcFswXSwKICAgICAgICB0b2tlbnM6IFtdLAogICAgICB9CiAgICAgIHRoaXMubGV4ZXIuaW5saW5lKHRva2VuLnRleHQsIHRva2VuLnRva2VucykKICAgICAgcmV0dXJuIHRva2VuCiAgICB9CiAgfQoKICBlc2NhcGUoc3JjKSB7CiAgICBjb25zdCBjYXAgPSB0aGlzLnJ1bGVzLmlubGluZS5lc2NhcGUuZXhlYyhzcmMpCiAgICBpZiAoY2FwKSB7CiAgICAgIHJldHVybiB7CiAgICAgICAgdHlwZTogImVzY2FwZSIsCiAgICAgICAgcmF3OiBjYXBbMF0sCiAgICAgICAgdGV4dDogZXNjYXBlKGNhcFsxXSksCiAgICAgIH0KICAgIH0KICB9CgogIHRhZyhzcmMpIHsKICAgIGNvbnN0IGNhcCA9IHRoaXMucnVsZXMuaW5saW5lLnRhZy5leGVjKHNyYykKICAgIGlmIChjYXApIHsKICAgICAgaWYgKCF0aGlzLmxleGVyLnN0YXRlLmluTGluayAmJiAvXjxhIC9pLnRlc3QoY2FwWzBdKSkgewogICAgICAgIHRoaXMubGV4ZXIuc3RhdGUuaW5MaW5rID0gdHJ1ZQogICAgICB9IGVsc2UgaWYgKHRoaXMubGV4ZXIuc3RhdGUuaW5MaW5rICYmIC9ePFwvYT4vaS50ZXN0KGNhcFswXSkpIHsKICAgICAgICB0aGlzLmxleGVyLnN0YXRlLmluTGluayA9IGZhbHNlCiAgICAgIH0KICAgICAgaWYgKAogICAgICAgICF0aGlzLmxleGVyLnN0YXRlLmluUmF3QmxvY2sgJiYKICAgICAgICAvXjwocHJlfGNvZGV8a2JkfHNjcmlwdCkoXHN8PikvaS50ZXN0KGNhcFswXSkKICAgICAgKSB7CiAgICAgICAgdGhpcy5sZXhlci5zdGF0ZS5pblJhd0Jsb2NrID0gdHJ1ZQogICAgICB9IGVsc2UgaWYgKAogICAgICAgIHRoaXMubGV4ZXIuc3RhdGUuaW5SYXdCbG9jayAmJgogICAgICAgIC9ePFwvKHByZXxjb2RlfGtiZHxzY3JpcHQpKFxzfD4pL2kudGVzdChjYXBbMF0pCiAgICAgICkgewogICAgICAgIHRoaXMubGV4ZXIuc3RhdGUuaW5SYXdCbG9jayA9IGZhbHNlCiAgICAgIH0KCiAgICAgIHJldHVybiB7CiAgICAgICAgdHlwZTogdGhpcy5vcHRpb25zLnNhbml0aXplID8gInRleHQiIDogImh0bWwiLAogICAgICAgIHJhdzogY2FwWzBdLAogICAgICAgIGluTGluazogdGhpcy5sZXhlci5zdGF0ZS5pbkxpbmssCiAgICAgICAgaW5SYXdCbG9jazogdGhpcy5sZXhlci5zdGF0ZS5pblJhd0Jsb2NrLAogICAgICAgIHRleHQ6IHRoaXMub3B0aW9ucy5zYW5pdGl6ZQogICAgICAgICAgPyB0aGlzLm9wdGlvbnMuc2FuaXRpemVyCiAgICAgICAgICAgID8gdGhpcy5vcHRpb25zLnNhbml0aXplcihjYXBbMF0pCiAgICAgICAgICAgIDogZXNjYXBlKGNhcFswXSkKICAgICAgICAgIDogY2FwWzBdLAogICAgICB9CiAgICB9CiAgfQoKICBsaW5rKHNyYykgewogICAgY29uc3QgY2FwID0gdGhpcy5ydWxlcy5pbmxpbmUubGluay5leGVjKHNyYykKICAgIGlmIChjYXApIHsKICAgICAgY29uc3QgdHJpbW1lZFVybCA9IGNhcFsyXS50cmltKCkKICAgICAgaWYgKCF0aGlzLm9wdGlvbnMucGVkYW50aWMgJiYgL148Ly50ZXN0KHRyaW1tZWRVcmwpKSB7CiAgICAgICAgLy8gY29tbW9ubWFyayByZXF1aXJlcyBtYXRjaGluZyBhbmdsZSBicmFja2V0cwogICAgICAgIGlmICghLz4kLy50ZXN0KHRyaW1tZWRVcmwpKSB7CiAgICAgICAgICByZXR1cm4KICAgICAgICB9CgogICAgICAgIC8vIGVuZGluZyBhbmdsZSBicmFja2V0IGNhbm5vdCBiZSBlc2NhcGVkCiAgICAgICAgY29uc3QgcnRyaW1TbGFzaCA9IHJ0cmltKHRyaW1tZWRVcmwuc2xpY2UoMCwgLTEpLCAiXFwiKQogICAgICAgIGlmICgodHJpbW1lZFVybC5sZW5ndGggLSBydHJpbVNsYXNoLmxlbmd0aCkgJSAyID09PSAwKSB7CiAgICAgICAgICByZXR1cm4KICAgICAgICB9CiAgICAgIH0gZWxzZSB7CiAgICAgICAgLy8gZmluZCBjbG9zaW5nIHBhcmVudGhlc2lzCiAgICAgICAgY29uc3QgbGFzdFBhcmVuSW5kZXggPSBmaW5kQ2xvc2luZ0JyYWNrZXQoY2FwWzJdLCAiKCkiKQogICAgICAgIGlmIChsYXN0UGFyZW5JbmRleCA+IC0xKSB7CiAgICAgICAgICBjb25zdCBzdGFydCA9IGNhcFswXS5pbmRleE9mKCIhIikgPT09IDAgPyA1IDogNAogICAgICAgICAgY29uc3QgbGlua0xlbiA9IHN0YXJ0ICsgY2FwWzFdLmxlbmd0aCArIGxhc3RQYXJlbkluZGV4CiAgICAgICAgICBjYXBbMl0gPSBjYXBbMl0uc3Vic3RyaW5nKDAsIGxhc3RQYXJlbkluZGV4KQogICAgICAgICAgY2FwWzBdID0gY2FwWzBdLnN1YnN0cmluZygwLCBsaW5rTGVuKS50cmltKCkKICAgICAgICAgIGNhcFszXSA9ICIiCiAgICAgICAgfQogICAgICB9CiAgICAgIGxldCBocmVmID0gY2FwWzJdCiAgICAgIGxldCB0aXRsZSA9ICIiCiAgICAgIGlmICh0aGlzLm9wdGlvbnMucGVkYW50aWMpIHsKICAgICAgICAvLyBzcGxpdCBwZWRhbnRpYyBocmVmIGFuZCB0aXRsZQogICAgICAgIGNvbnN0IGxpbmsgPSAvXihbXiciXSpbXlxzXSlccysoWyciXSkoLiopXDIvLmV4ZWMoaHJlZikKCiAgICAgICAgaWYgKGxpbmspIHsKICAgICAgICAgIGhyZWYgPSBsaW5rWzFdCiAgICAgICAgICB0aXRsZSA9IGxpbmtbM10KICAgICAgICB9CiAgICAgIH0gZWxzZSB7CiAgICAgICAgdGl0bGUgPSBjYXBbM10gPyBjYXBbM10uc2xpY2UoMSwgLTEpIDogIiIKICAgICAgfQoKICAgICAgaHJlZiA9IGhyZWYudHJpbSgpCiAgICAgIGlmICgvXjwvLnRlc3QoaHJlZikpIHsKICAgICAgICBpZiAodGhpcy5vcHRpb25zLnBlZGFudGljICYmICEvPiQvLnRlc3QodHJpbW1lZFVybCkpIHsKICAgICAgICAgIC8vIHBlZGFudGljIGFsbG93cyBzdGFydGluZyBhbmdsZSBicmFja2V0IHdpdGhvdXQgZW5kaW5nIGFuZ2xlIGJyYWNrZXQKICAgICAgICAgIGhyZWYgPSBocmVmLnNsaWNlKDEpCiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIGhyZWYgPSBocmVmLnNsaWNlKDEsIC0xKQogICAgICAgIH0KICAgICAgfQogICAgICByZXR1cm4gb3V0cHV0TGluaygKICAgICAgICBjYXAsCiAgICAgICAgewogICAgICAgICAgaHJlZjogaHJlZiA/IGhyZWYucmVwbGFjZSh0aGlzLnJ1bGVzLmlubGluZS5fZXNjYXBlcywgIiQxIikgOiBocmVmLAogICAgICAgICAgdGl0bGU6IHRpdGxlCiAgICAgICAgICAgID8gdGl0bGUucmVwbGFjZSh0aGlzLnJ1bGVzLmlubGluZS5fZXNjYXBlcywgIiQxIikKICAgICAgICAgICAgOiB0aXRsZSwKICAgICAgICB9LAogICAgICAgIGNhcFswXSwKICAgICAgICB0aGlzLmxleGVyCiAgICAgICkKICAgIH0KICB9CgogIHJlZmxpbmsoc3JjLCBsaW5rcykgewogICAgbGV0IGNhcAogICAgaWYgKAogICAgICAoY2FwID0gdGhpcy5ydWxlcy5pbmxpbmUucmVmbGluay5leGVjKHNyYykpIHx8CiAgICAgIChjYXAgPSB0aGlzLnJ1bGVzLmlubGluZS5ub2xpbmsuZXhlYyhzcmMpKQogICAgKSB7CiAgICAgIGxldCBsaW5rID0gKGNhcFsyXSB8fCBjYXBbMV0pLnJlcGxhY2UoL1xzKy9nLCAiICIpCiAgICAgIGxpbmsgPSBsaW5rc1tsaW5rLnRvTG93ZXJDYXNlKCldCiAgICAgIGlmICghbGluayB8fCAhbGluay5ocmVmKSB7CiAgICAgICAgY29uc3QgdGV4dCA9IGNhcFswXS5jaGFyQXQoMCkKICAgICAgICByZXR1cm4gewogICAgICAgICAgdHlwZTogInRleHQiLAogICAgICAgICAgcmF3OiB0ZXh0LAogICAgICAgICAgdGV4dCwKICAgICAgICB9CiAgICAgIH0KICAgICAgcmV0dXJuIG91dHB1dExpbmsoY2FwLCBsaW5rLCBjYXBbMF0sIHRoaXMubGV4ZXIpCiAgICB9CiAgfQoKICBlbVN0cm9uZyhzcmMsIG1hc2tlZFNyYywgcHJldkNoYXIgPSAiIikgewogICAgbGV0IG1hdGNoID0gdGhpcy5ydWxlcy5pbmxpbmUuZW1TdHJvbmcubERlbGltLmV4ZWMoc3JjKQogICAgaWYgKCFtYXRjaCkgcmV0dXJuCgogICAgLy8gXyBjYW4ndCBiZSBiZXR3ZWVuIHR3byBhbHBoYW51bWVyaWNzLiBccHtMfVxwe059IGluY2x1ZGVzIG5vbi1lbmdsaXNoIGFscGhhYmV0L251bWJlcnMgYXMgd2VsbAogICAgaWYgKG1hdGNoWzNdICYmIHByZXZDaGFyLm1hdGNoKC9bXHB7TH1ccHtOfV0vdSkpIHJldHVybgoKICAgIGNvbnN0IG5leHRDaGFyID0gbWF0Y2hbMV0gfHwgbWF0Y2hbMl0gfHwgIiIKCiAgICBpZiAoCiAgICAgICFuZXh0Q2hhciB8fAogICAgICAobmV4dENoYXIgJiYKICAgICAgICAocHJldkNoYXIgPT09ICIiIHx8IHRoaXMucnVsZXMuaW5saW5lLnB1bmN0dWF0aW9uLmV4ZWMocHJldkNoYXIpKSkKICAgICkgewogICAgICBjb25zdCBsTGVuZ3RoID0gbWF0Y2hbMF0ubGVuZ3RoIC0gMQogICAgICBsZXQgckRlbGltLAogICAgICAgIHJMZW5ndGgsCiAgICAgICAgZGVsaW1Ub3RhbCA9IGxMZW5ndGgsCiAgICAgICAgbWlkRGVsaW1Ub3RhbCA9IDAKCiAgICAgIGNvbnN0IGVuZFJlZyA9CiAgICAgICAgbWF0Y2hbMF1bMF0gPT09ICIqIgogICAgICAgICAgPyB0aGlzLnJ1bGVzLmlubGluZS5lbVN0cm9uZy5yRGVsaW1Bc3QKICAgICAgICAgIDogdGhpcy5ydWxlcy5pbmxpbmUuZW1TdHJvbmcuckRlbGltVW5kCiAgICAgIGVuZFJlZy5sYXN0SW5kZXggPSAwCgogICAgICAvLyBDbGlwIG1hc2tlZFNyYyB0byBzYW1lIHNlY3Rpb24gb2Ygc3RyaW5nIGFzIHNyYyAobW92ZSB0byBsZXhlcj8pCiAgICAgIG1hc2tlZFNyYyA9IG1hc2tlZFNyYy5zbGljZSgtMSAqIHNyYy5sZW5ndGggKyBsTGVuZ3RoKQoKICAgICAgd2hpbGUgKChtYXRjaCA9IGVuZFJlZy5leGVjKG1hc2tlZFNyYykpICE9IG51bGwpIHsKICAgICAgICByRGVsaW0gPQogICAgICAgICAgbWF0Y2hbMV0gfHwgbWF0Y2hbMl0gfHwgbWF0Y2hbM10gfHwgbWF0Y2hbNF0gfHwgbWF0Y2hbNV0gfHwgbWF0Y2hbNl0KCiAgICAgICAgaWYgKCFyRGVsaW0pIGNvbnRpbnVlIC8vIHNraXAgc2luZ2xlICogaW4gX19hYmMqYWJjX18KCiAgICAgICAgckxlbmd0aCA9IHJEZWxpbS5sZW5ndGgKCiAgICAgICAgaWYgKG1hdGNoWzNdIHx8IG1hdGNoWzRdKSB7CiAgICAgICAgICAvLyBmb3VuZCBhbm90aGVyIExlZnQgRGVsaW0KICAgICAgICAgIGRlbGltVG90YWwgKz0gckxlbmd0aAogICAgICAgICAgY29udGludWUKICAgICAgICB9IGVsc2UgaWYgKG1hdGNoWzVdIHx8IG1hdGNoWzZdKSB7CiAgICAgICAgICAvLyBlaXRoZXIgTGVmdCBvciBSaWdodCBEZWxpbQogICAgICAgICAgaWYgKGxMZW5ndGggJSAzICYmICEoKGxMZW5ndGggKyByTGVuZ3RoKSAlIDMpKSB7CiAgICAgICAgICAgIG1pZERlbGltVG90YWwgKz0gckxlbmd0aAogICAgICAgICAgICBjb250aW51ZSAvLyBDb21tb25NYXJrIEVtcGhhc2lzIFJ1bGVzIDktMTAKICAgICAgICAgIH0KICAgICAgICB9CgogICAgICAgIGRlbGltVG90YWwgLT0gckxlbmd0aAoKICAgICAgICBpZiAoZGVsaW1Ub3RhbCA+IDApIGNvbnRpbnVlIC8vIEhhdmVuJ3QgZm91bmQgZW5vdWdoIGNsb3NpbmcgZGVsaW1pdGVycwoKICAgICAgICAvLyBSZW1vdmUgZXh0cmEgY2hhcmFjdGVycy4gKmEqKiogLT4gKmEqCiAgICAgICAgckxlbmd0aCA9IE1hdGgubWluKHJMZW5ndGgsIHJMZW5ndGggKyBkZWxpbVRvdGFsICsgbWlkRGVsaW1Ub3RhbCkKCiAgICAgICAgLy8gQ3JlYXRlIGBlbWAgaWYgc21hbGxlc3QgZGVsaW1pdGVyIGhhcyBvZGQgY2hhciBjb3VudC4gKmEqKioKICAgICAgICBpZiAoTWF0aC5taW4obExlbmd0aCwgckxlbmd0aCkgJSAyKSB7CiAgICAgICAgICBjb25zdCB0ZXh0ID0gc3JjLnNsaWNlKDEsIGxMZW5ndGggKyBtYXRjaC5pbmRleCArIHJMZW5ndGgpCiAgICAgICAgICByZXR1cm4gewogICAgICAgICAgICB0eXBlOiAiZW0iLAogICAgICAgICAgICByYXc6IHNyYy5zbGljZSgwLCBsTGVuZ3RoICsgbWF0Y2guaW5kZXggKyByTGVuZ3RoICsgMSksCiAgICAgICAgICAgIHRleHQsCiAgICAgICAgICAgIHRva2VuczogdGhpcy5sZXhlci5pbmxpbmVUb2tlbnModGV4dCwgW10pLAogICAgICAgICAgfQogICAgICAgIH0KCiAgICAgICAgLy8gQ3JlYXRlICdzdHJvbmcnIGlmIHNtYWxsZXN0IGRlbGltaXRlciBoYXMgZXZlbiBjaGFyIGNvdW50LiAqKmEqKioKICAgICAgICBjb25zdCB0ZXh0ID0gc3JjLnNsaWNlKDIsIGxMZW5ndGggKyBtYXRjaC5pbmRleCArIHJMZW5ndGggLSAxKQogICAgICAgIHJldHVybiB7CiAgICAgICAgICB0eXBlOiAic3Ryb25nIiwKICAgICAgICAgIHJhdzogc3JjLnNsaWNlKDAsIGxMZW5ndGggKyBtYXRjaC5pbmRleCArIHJMZW5ndGggKyAxKSwKICAgICAgICAgIHRleHQsCiAgICAgICAgICB0b2tlbnM6IHRoaXMubGV4ZXIuaW5saW5lVG9rZW5zKHRleHQsIFtdKSwKICAgICAgICB9CiAgICAgIH0KICAgIH0KICB9CgogIGNvZGVzcGFuKHNyYykgewogICAgY29uc3QgY2FwID0gdGhpcy5ydWxlcy5pbmxpbmUuY29kZS5leGVjKHNyYykKICAgIGlmIChjYXApIHsKICAgICAgbGV0IHRleHQgPSBjYXBbMl0ucmVwbGFjZSgvXG4vZywgIiAiKQogICAgICBjb25zdCBoYXNOb25TcGFjZUNoYXJzID0gL1teIF0vLnRlc3QodGV4dCkKICAgICAgY29uc3QgaGFzU3BhY2VDaGFyc09uQm90aEVuZHMgPSAvXiAvLnRlc3QodGV4dCkgJiYgLyAkLy50ZXN0KHRleHQpCiAgICAgIGlmIChoYXNOb25TcGFjZUNoYXJzICYmIGhhc1NwYWNlQ2hhcnNPbkJvdGhFbmRzKSB7CiAgICAgICAgdGV4dCA9IHRleHQuc3Vic3RyaW5nKDEsIHRleHQubGVuZ3RoIC0gMSkKICAgICAgfQogICAgICB0ZXh0ID0gZXNjYXBlKHRleHQsIHRydWUpCiAgICAgIHJldHVybiB7CiAgICAgICAgdHlwZTogImNvZGVzcGFuIiwKICAgICAgICByYXc6IGNhcFswXSwKICAgICAgICB0ZXh0LAogICAgICB9CiAgICB9CiAgfQoKICBicihzcmMpIHsKICAgIGNvbnN0IGNhcCA9IHRoaXMucnVsZXMuaW5saW5lLmJyLmV4ZWMoc3JjKQogICAgaWYgKGNhcCkgewogICAgICByZXR1cm4gewogICAgICAgIHR5cGU6ICJiciIsCiAgICAgICAgcmF3OiBjYXBbMF0sCiAgICAgIH0KICAgIH0KICB9CgogIGRlbChzcmMpIHsKICAgIGNvbnN0IGNhcCA9IHRoaXMucnVsZXMuaW5saW5lLmRlbC5leGVjKHNyYykKICAgIGlmIChjYXApIHsKICAgICAgcmV0dXJuIHsKICAgICAgICB0eXBlOiAiZGVsIiwKICAgICAgICByYXc6IGNhcFswXSwKICAgICAgICB0ZXh0OiBjYXBbMl0sCiAgICAgICAgdG9rZW5zOiB0aGlzLmxleGVyLmlubGluZVRva2VucyhjYXBbMl0sIFtdKSwKICAgICAgfQogICAgfQogIH0KCiAgYXV0b2xpbmsoc3JjLCBtYW5nbGUpIHsKICAgIGNvbnN0IGNhcCA9IHRoaXMucnVsZXMuaW5saW5lLmF1dG9saW5rLmV4ZWMoc3JjKQogICAgaWYgKGNhcCkgewogICAgICBsZXQgdGV4dCwgaHJlZgogICAgICBpZiAoY2FwWzJdID09PSAiQCIpIHsKICAgICAgICB0ZXh0ID0gZXNjYXBlKHRoaXMub3B0aW9ucy5tYW5nbGUgPyBtYW5nbGUoY2FwWzFdKSA6IGNhcFsxXSkKICAgICAgICBocmVmID0gIm1haWx0bzoiICsgdGV4dAogICAgICB9IGVsc2UgewogICAgICAgIHRleHQgPSBlc2NhcGUoY2FwWzFdKQogICAgICAgIGhyZWYgPSB0ZXh0CiAgICAgIH0KCiAgICAgIHJldHVybiB7CiAgICAgICAgdHlwZTogImxpbmsiLAogICAgICAgIHJhdzogY2FwWzBdLAogICAgICAgIHRleHQsCiAgICAgICAgaHJlZiwKICAgICAgICB0b2tlbnM6IFsKICAgICAgICAgIHsKICAgICAgICAgICAgdHlwZTogInRleHQiLAogICAgICAgICAgICByYXc6IHRleHQsCiAgICAgICAgICAgIHRleHQsCiAgICAgICAgICB9LAogICAgICAgIF0sCiAgICAgIH0KICAgIH0KICB9CgogIHVybChzcmMsIG1hbmdsZSkgewogICAgbGV0IGNhcAogICAgaWYgKChjYXAgPSB0aGlzLnJ1bGVzLmlubGluZS51cmwuZXhlYyhzcmMpKSkgewogICAgICBsZXQgdGV4dCwgaHJlZgogICAgICBpZiAoY2FwWzJdID09PSAiQCIpIHsKICAgICAgICB0ZXh0ID0gZXNjYXBlKHRoaXMub3B0aW9ucy5tYW5nbGUgPyBtYW5nbGUoY2FwWzBdKSA6IGNhcFswXSkKICAgICAgICBocmVmID0gIm1haWx0bzoiICsgdGV4dAogICAgICB9IGVsc2UgewogICAgICAgIC8vIGRvIGV4dGVuZGVkIGF1dG9saW5rIHBhdGggdmFsaWRhdGlvbgogICAgICAgIGxldCBwcmV2Q2FwWmVybwogICAgICAgIGRvIHsKICAgICAgICAgIHByZXZDYXBaZXJvID0gY2FwWzBdCiAgICAgICAgICBjYXBbMF0gPSB0aGlzLnJ1bGVzLmlubGluZS5fYmFja3BlZGFsLmV4ZWMoY2FwWzBdKVswXQogICAgICAgIH0gd2hpbGUgKHByZXZDYXBaZXJvICE9PSBjYXBbMF0pCiAgICAgICAgdGV4dCA9IGVzY2FwZShjYXBbMF0pCiAgICAgICAgaWYgKGNhcFsxXSA9PT0gInd3dy4iKSB7CiAgICAgICAgICBocmVmID0gImh0dHA6Ly8iICsgdGV4dAogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBocmVmID0gdGV4dAogICAgICAgIH0KICAgICAgfQogICAgICByZXR1cm4gewogICAgICAgIHR5cGU6ICJsaW5rIiwKICAgICAgICByYXc6IGNhcFswXSwKICAgICAgICB0ZXh0LAogICAgICAgIGhyZWYsCiAgICAgICAgdG9rZW5zOiBbCiAgICAgICAgICB7CiAgICAgICAgICAgIHR5cGU6ICJ0ZXh0IiwKICAgICAgICAgICAgcmF3OiB0ZXh0LAogICAgICAgICAgICB0ZXh0LAogICAgICAgICAgfSwKICAgICAgICBdLAogICAgICB9CiAgICB9CiAgfQoKICBpbmxpbmVUZXh0KHNyYywgc21hcnR5cGFudHMpIHsKICAgIGNvbnN0IGNhcCA9IHRoaXMucnVsZXMuaW5saW5lLnRleHQuZXhlYyhzcmMpCiAgICBpZiAoY2FwKSB7CiAgICAgIGxldCB0ZXh0CiAgICAgIGlmICh0aGlzLmxleGVyLnN0YXRlLmluUmF3QmxvY2spIHsKICAgICAgICB0ZXh0ID0gdGhpcy5vcHRpb25zLnNhbml0aXplCiAgICAgICAgICA/IHRoaXMub3B0aW9ucy5zYW5pdGl6ZXIKICAgICAgICAgICAgPyB0aGlzLm9wdGlvbnMuc2FuaXRpemVyKGNhcFswXSkKICAgICAgICAgICAgOiBlc2NhcGUoY2FwWzBdKQogICAgICAgICAgOiBjYXBbMF0KICAgICAgfSBlbHNlIHsKICAgICAgICB0ZXh0ID0gZXNjYXBlKHRoaXMub3B0aW9ucy5zbWFydHlwYW50cyA/IHNtYXJ0eXBhbnRzKGNhcFswXSkgOiBjYXBbMF0pCiAgICAgIH0KICAgICAgcmV0dXJuIHsKICAgICAgICB0eXBlOiAidGV4dCIsCiAgICAgICAgcmF3OiBjYXBbMF0sCiAgICAgICAgdGV4dCwKICAgICAgfQogICAgfQogIH0KfQoKLyoqCiAqIEJsb2NrLUxldmVsIEdyYW1tYXIKICovCmNvbnN0IGJsb2NrID0gewogIG5ld2xpbmU6IC9eKD86ICooPzpcbnwkKSkrLywKICBjb2RlOiAvXiggezR9W15cbl0rKD86XG4oPzogKig/OlxufCQpKSopPykrLywKICBmZW5jZXM6CiAgICAvXiB7MCwzfShgezMsfSg/PVteYFxuXSpcbil8fnszLH0pKFteXG5dKilcbig/OnwoW1xzXFNdKj8pXG4pKD86IHswLDN9XDFbfmBdKiAqKD89XG58JCl8JCkvLAogIGhyOiAvXiB7MCwzfSgoPzotW1x0IF0qKXszLH18KD86X1sgXHRdKil7Myx9fCg/OlwqWyBcdF0qKXszLH0pKD86XG4rfCQpLywKICBoZWFkaW5nOiAvXiB7MCwzfSgjezEsNn0pKD89XHN8JCkoLiopKD86XG4rfCQpLywKICBibG9ja3F1b3RlOiAvXiggezAsM30+ID8ocGFyYWdyYXBofFteXG5dKikoPzpcbnwkKSkrLywKICBsaXN0OiAvXiggezAsM31idWxsKShbIFx0XVteXG5dKz8pPyg/OlxufCQpLywKICBodG1sOgogICAgIl4gezAsM30oPzoiICsgLy8gb3B0aW9uYWwgaW5kZW50YXRpb24KICAgICI8KHNjcmlwdHxwcmV8c3R5bGV8dGV4dGFyZWEpW1xccz5dW1xcc1xcU10qPyg/OjwvXFwxPlteXFxuXSpcXG4rfCQpIiArIC8vICgxKQogICAgInxjb21tZW50W15cXG5dKihcXG4rfCQpIiArIC8vICgyKQogICAgInw8XFw/W1xcc1xcU10qPyg/OlxcPz5cXG4qfCQpIiArIC8vICgzKQogICAgInw8IVtBLVpdW1xcc1xcU10qPyg/Oj5cXG4qfCQpIiArIC8vICg0KQogICAgInw8IVxcW0NEQVRBXFxbW1xcc1xcU10qPyg/OlxcXVxcXT5cXG4qfCQpIiArIC8vICg1KQogICAgInw8Lz8odGFnKSg/OiArfFxcbnwvPz4pW1xcc1xcU10qPyg/Oig/OlxcbiAqKStcXG58JCkiICsgLy8gKDYpCiAgICAifDwoPyFzY3JpcHR8cHJlfHN0eWxlfHRleHRhcmVhKShbYS16XVtcXHctXSopKD86YXR0cmlidXRlKSo/ICovPz4oPz1bIFxcdF0qKD86XFxufCQpKVtcXHNcXFNdKj8oPzooPzpcXG4gKikrXFxufCQpIiArIC8vICg3KSBvcGVuIHRhZwogICAgInw8Lyg/IXNjcmlwdHxwcmV8c3R5bGV8dGV4dGFyZWEpW2Etel1bXFx3LV0qXFxzKj4oPz1bIFxcdF0qKD86XFxufCQpKVtcXHNcXFNdKj8oPzooPzpcXG4gKikrXFxufCQpIiArIC8vICg3KSBjbG9zaW5nIHRhZwogICAgIikiLAogIGRlZjogL14gezAsM31cWyhsYWJlbClcXTogKig/OlxuICopPzw/KFteXHM+XSspPj8oPzooPzogKyg/OlxuICopP3wgKlxuICopKHRpdGxlKSk/ICooPzpcbit8JCkvLAogIHRhYmxlOiBub29wVGVzdCwKICBsaGVhZGluZzogL14oW15cbl0rKVxuIHswLDN9KD0rfC0rKSAqKD86XG4rfCQpLywKICAvLyByZWdleCB0ZW1wbGF0ZSwgcGxhY2Vob2xkZXJzIHdpbGwgYmUgcmVwbGFjZWQgYWNjb3JkaW5nIHRvIGRpZmZlcmVudCBwYXJhZ3JhcGgKICAvLyBpbnRlcnJ1cHRpb24gcnVsZXMgb2YgY29tbW9ubWFyayBhbmQgdGhlIG9yaWdpbmFsIG1hcmtkb3duIHNwZWM6CiAgX3BhcmFncmFwaDoKICAgIC9eKFteXG5dKyg/OlxuKD8haHJ8aGVhZGluZ3xsaGVhZGluZ3xibG9ja3F1b3RlfGZlbmNlc3xsaXN0fGh0bWx8dGFibGV8ICtcbilbXlxuXSspKikvLAogIHRleHQ6IC9eW15cbl0rLywKfQoKYmxvY2suX2xhYmVsID0gLyg/IVxzKlxdKSg/OlxcLnxbXlxbXF1cXF0pKy8KYmxvY2suX3RpdGxlID0gLyg/OiIoPzpcXCI/fFteIlxcXSkqInwnW14nXG5dKig/OlxuW14nXG5dKykqXG4/J3xcKFteKCldKlwpKS8KYmxvY2suZGVmID0gZWRpdChibG9jay5kZWYpCiAgLnJlcGxhY2UoImxhYmVsIiwgYmxvY2suX2xhYmVsKQogIC5yZXBsYWNlKCJ0aXRsZSIsIGJsb2NrLl90aXRsZSkKICAuZ2V0UmVnZXgoKQoKYmxvY2suYnVsbGV0ID0gLyg/OlsqKy1dfFxkezEsOX1bLildKS8KYmxvY2subGlzdEl0ZW1TdGFydCA9IGVkaXQoL14oICopKGJ1bGwpICovKQogIC5yZXBsYWNlKCJidWxsIiwgYmxvY2suYnVsbGV0KQogIC5nZXRSZWdleCgpCgpibG9jay5saXN0ID0gZWRpdChibG9jay5saXN0KQogIC5yZXBsYWNlKC9idWxsL2csIGJsb2NrLmJ1bGxldCkKICAucmVwbGFjZSgKICAgICJociIsCiAgICAiXFxuKyg/PVxcMT8oPzooPzotICopezMsfXwoPzpfICopezMsfXwoPzpcXCogKil7Myx9KSg/Olxcbit8JCkpIgogICkKICAucmVwbGFjZSgiZGVmIiwgIlxcbisoPz0iICsgYmxvY2suZGVmLnNvdXJjZSArICIpIikKICAuZ2V0UmVnZXgoKQoKYmxvY2suX3RhZyA9CiAgImFkZHJlc3N8YXJ0aWNsZXxhc2lkZXxiYXNlfGJhc2Vmb250fGJsb2NrcXVvdGV8Ym9keXxjYXB0aW9uIiArCiAgInxjZW50ZXJ8Y29sfGNvbGdyb3VwfGRkfGRldGFpbHN8ZGlhbG9nfGRpcnxkaXZ8ZGx8ZHR8ZmllbGRzZXR8ZmlnY2FwdGlvbiIgKwogICJ8ZmlndXJlfGZvb3Rlcnxmb3JtfGZyYW1lfGZyYW1lc2V0fGhbMS02XXxoZWFkfGhlYWRlcnxocnxodG1sfGlmcmFtZSIgKwogICJ8bGVnZW5kfGxpfGxpbmt8bWFpbnxtZW51fG1lbnVpdGVtfG1ldGF8bmF2fG5vZnJhbWVzfG9sfG9wdGdyb3VwfG9wdGlvbiIgKwogICJ8cHxwYXJhbXxzZWN0aW9ufHNvdXJjZXxzdW1tYXJ5fHRhYmxlfHRib2R5fHRkfHRmb290fHRofHRoZWFkfHRpdGxlfHRyIiArCiAgInx0cmFja3x1bCIKYmxvY2suX2NvbW1lbnQgPSAvPCEtLSg/IS0/PilbXHNcU10qPyg/Oi0tPnwkKS8KYmxvY2suaHRtbCA9IGVkaXQoYmxvY2suaHRtbCwgImkiKQogIC5yZXBsYWNlKCJjb21tZW50IiwgYmxvY2suX2NvbW1lbnQpCiAgLnJlcGxhY2UoInRhZyIsIGJsb2NrLl90YWcpCiAgLnJlcGxhY2UoCiAgICAiYXR0cmlidXRlIiwKICAgIC8gK1thLXpBLVo6X11bXHcuOi1dKig/OiAqPSAqIlteIlxuXSoifCAqPSAqJ1teJ1xuXSonfCAqPSAqW15ccyInPTw+YF0rKT8vCiAgKQogIC5nZXRSZWdleCgpCgpibG9jay5wYXJhZ3JhcGggPSBlZGl0KGJsb2NrLl9wYXJhZ3JhcGgpCiAgLnJlcGxhY2UoImhyIiwgYmxvY2suaHIpCiAgLnJlcGxhY2UoImhlYWRpbmciLCAiIHswLDN9I3sxLDZ9ICIpCiAgLnJlcGxhY2UoInxsaGVhZGluZyIsICIiKSAvLyBzZXRleCBoZWFkaW5ncyBkb24ndCBpbnRlcnJ1cHQgY29tbW9ubWFyayBwYXJhZ3JhcGhzCiAgLnJlcGxhY2UoInx0YWJsZSIsICIiKQogIC5yZXBsYWNlKCJibG9ja3F1b3RlIiwgIiB7MCwzfT4iKQogIC5yZXBsYWNlKCJmZW5jZXMiLCAiIHswLDN9KD86YHszLH0oPz1bXmBcXG5dKlxcbil8fnszLH0pW15cXG5dKlxcbiIpCiAgLnJlcGxhY2UoImxpc3QiLCAiIHswLDN9KD86WyorLV18MVsuKV0pICIpIC8vIG9ubHkgbGlzdHMgc3RhcnRpbmcgZnJvbSAxIGNhbiBpbnRlcnJ1cHQKICAucmVwbGFjZSgKICAgICJodG1sIiwKICAgICI8Lz8oPzp0YWcpKD86ICt8XFxufC8/Pil8PCg/OnNjcmlwdHxwcmV8c3R5bGV8dGV4dGFyZWF8IS0tKSIKICApCiAgLnJlcGxhY2UoInRhZyIsIGJsb2NrLl90YWcpIC8vIHBhcnMgY2FuIGJlIGludGVycnVwdGVkIGJ5IHR5cGUgKDYpIGh0bWwgYmxvY2tzCiAgLmdldFJlZ2V4KCkKCmJsb2NrLmJsb2NrcXVvdGUgPSBlZGl0KGJsb2NrLmJsb2NrcXVvdGUpCiAgLnJlcGxhY2UoInBhcmFncmFwaCIsIGJsb2NrLnBhcmFncmFwaCkKICAuZ2V0UmVnZXgoKQoKLyoqCiAqIE5vcm1hbCBCbG9jayBHcmFtbWFyCiAqLwoKYmxvY2subm9ybWFsID0gbWVyZ2Uoe30sIGJsb2NrKQoKLyoqCiAqIEdGTSBCbG9jayBHcmFtbWFyCiAqLwoKYmxvY2suZ2ZtID0gbWVyZ2Uoe30sIGJsb2NrLm5vcm1hbCwgewogIHRhYmxlOgogICAgIl4gKihbXlxcbiBdLipcXHwuKilcXG4iICsgLy8gSGVhZGVyCiAgICAiIHswLDN9KD86XFx8ICopPyg6Py0rOj8gKig/OlxcfCAqOj8tKzo/ICopKikoPzpcXHwgKik/IiArIC8vIEFsaWduCiAgICAiKD86XFxuKCg/Oig/ISAqXFxufGhyfGhlYWRpbmd8YmxvY2txdW90ZXxjb2RlfGZlbmNlc3xsaXN0fGh0bWwpLiooPzpcXG58JCkpKilcXG4qfCQpIiwgLy8gQ2VsbHMKfSkKCmJsb2NrLmdmbS50YWJsZSA9IGVkaXQoYmxvY2suZ2ZtLnRhYmxlKQogIC5yZXBsYWNlKCJociIsIGJsb2NrLmhyKQogIC5yZXBsYWNlKCJoZWFkaW5nIiwgIiB7MCwzfSN7MSw2fSAiKQogIC5yZXBsYWNlKCJibG9ja3F1b3RlIiwgIiB7MCwzfT4iKQogIC5yZXBsYWNlKCJjb2RlIiwgIiB7NH1bXlxcbl0iKQogIC5yZXBsYWNlKCJmZW5jZXMiLCAiIHswLDN9KD86YHszLH0oPz1bXmBcXG5dKlxcbil8fnszLH0pW15cXG5dKlxcbiIpCiAgLnJlcGxhY2UoImxpc3QiLCAiIHswLDN9KD86WyorLV18MVsuKV0pICIpIC8vIG9ubHkgbGlzdHMgc3RhcnRpbmcgZnJvbSAxIGNhbiBpbnRlcnJ1cHQKICAucmVwbGFjZSgKICAgICJodG1sIiwKICAgICI8Lz8oPzp0YWcpKD86ICt8XFxufC8/Pil8PCg/OnNjcmlwdHxwcmV8c3R5bGV8dGV4dGFyZWF8IS0tKSIKICApCiAgLnJlcGxhY2UoInRhZyIsIGJsb2NrLl90YWcpIC8vIHRhYmxlcyBjYW4gYmUgaW50ZXJydXB0ZWQgYnkgdHlwZSAoNikgaHRtbCBibG9ja3MKICAuZ2V0UmVnZXgoKQoKYmxvY2suZ2ZtLnBhcmFncmFwaCA9IGVkaXQoYmxvY2suX3BhcmFncmFwaCkKICAucmVwbGFjZSgiaHIiLCBibG9jay5ocikKICAucmVwbGFjZSgiaGVhZGluZyIsICIgezAsM30jezEsNn0gIikKICAucmVwbGFjZSgifGxoZWFkaW5nIiwgIiIpIC8vIHNldGV4IGhlYWRpbmdzIGRvbid0IGludGVycnVwdCBjb21tb25tYXJrIHBhcmFncmFwaHMKICAucmVwbGFjZSgidGFibGUiLCBibG9jay5nZm0udGFibGUpIC8vIGludGVycnVwdCBwYXJhZ3JhcGhzIHdpdGggdGFibGUKICAucmVwbGFjZSgiYmxvY2txdW90ZSIsICIgezAsM30+IikKICAucmVwbGFjZSgiZmVuY2VzIiwgIiB7MCwzfSg/OmB7Myx9KD89W15gXFxuXSpcXG4pfH57Myx9KVteXFxuXSpcXG4iKQogIC5yZXBsYWNlKCJsaXN0IiwgIiB7MCwzfSg/OlsqKy1dfDFbLildKSAiKSAvLyBvbmx5IGxpc3RzIHN0YXJ0aW5nIGZyb20gMSBjYW4gaW50ZXJydXB0CiAgLnJlcGxhY2UoCiAgICAiaHRtbCIsCiAgICAiPC8/KD86dGFnKSg/OiArfFxcbnwvPz4pfDwoPzpzY3JpcHR8cHJlfHN0eWxlfHRleHRhcmVhfCEtLSkiCiAgKQogIC5yZXBsYWNlKCJ0YWciLCBibG9jay5fdGFnKSAvLyBwYXJzIGNhbiBiZSBpbnRlcnJ1cHRlZCBieSB0eXBlICg2KSBodG1sIGJsb2NrcwogIC5nZXRSZWdleCgpCi8qKgogKiBQZWRhbnRpYyBncmFtbWFyIChvcmlnaW5hbCBKb2huIEdydWJlcidzIGxvb3NlIG1hcmtkb3duIHNwZWNpZmljYXRpb24pCiAqLwoKYmxvY2sucGVkYW50aWMgPSBtZXJnZSh7fSwgYmxvY2subm9ybWFsLCB7CiAgaHRtbDogZWRpdCgKICAgICJeICooPzpjb21tZW50ICooPzpcXG58XFxzKiQpIiArCiAgICAgICJ8PCh0YWcpW1xcc1xcU10rPzwvXFwxPiAqKD86XFxuezIsfXxcXHMqJCkiICsgLy8gY2xvc2VkIHRhZwogICAgICAifDx0YWcoPzpcIlteXCJdKlwifCdbXiddKid8XFxzW14nXCIvPlxcc10qKSo/Lz8+ICooPzpcXG57Mix9fFxccyokKSkiCiAgKQogICAgLnJlcGxhY2UoImNvbW1lbnQiLCBibG9jay5fY29tbWVudCkKICAgIC5yZXBsYWNlKAogICAgICAvdGFnL2csCiAgICAgICIoPyEoPzoiICsKICAgICAgICAiYXxlbXxzdHJvbmd8c21hbGx8c3xjaXRlfHF8ZGZufGFiYnJ8ZGF0YXx0aW1lfGNvZGV8dmFyfHNhbXB8a2JkfHN1YiIgKwogICAgICAgICJ8c3VwfGl8Ynx1fG1hcmt8cnVieXxydHxycHxiZGl8YmRvfHNwYW58YnJ8d2JyfGluc3xkZWx8aW1nKSIgKwogICAgICAgICJcXGIpXFx3Kyg/ITp8W15cXHdcXHNAXSpAKVxcYiIKICAgICkKICAgIC5nZXRSZWdleCgpLAogIGRlZjogL14gKlxbKFteXF1dKylcXTogKjw/KFteXHM+XSspPj8oPzogKyhbIihdW15cbl0rWyIpXSkpPyAqKD86XG4rfCQpLywKICBoZWFkaW5nOiAvXigjezEsNn0pKC4qKSg/OlxuK3wkKS8sCiAgZmVuY2VzOiBub29wVGVzdCwgLy8gZmVuY2VzIG5vdCBzdXBwb3J0ZWQKICBwYXJhZ3JhcGg6IGVkaXQoYmxvY2subm9ybWFsLl9wYXJhZ3JhcGgpCiAgICAucmVwbGFjZSgiaHIiLCBibG9jay5ocikKICAgIC5yZXBsYWNlKCJoZWFkaW5nIiwgIiAqI3sxLDZ9ICpbXlxuXSIpCiAgICAucmVwbGFjZSgibGhlYWRpbmciLCBibG9jay5saGVhZGluZykKICAgIC5yZXBsYWNlKCJibG9ja3F1b3RlIiwgIiB7MCwzfT4iKQogICAgLnJlcGxhY2UoInxmZW5jZXMiLCAiIikKICAgIC5yZXBsYWNlKCJ8bGlzdCIsICIiKQogICAgLnJlcGxhY2UoInxodG1sIiwgIiIpCiAgICAuZ2V0UmVnZXgoKSwKfSkKCi8qKgogKiBJbmxpbmUtTGV2ZWwgR3JhbW1hcgogKi8KY29uc3QgaW5saW5lID0gewogIGVzY2FwZTogL15cXChbISIjJCUmJygpKissXC0uLzo7PD0+P0BcW1xdXFxeX2B7fH1+XSkvLAogIGF1dG9saW5rOiAvXjwoc2NoZW1lOlteXHNceDAwLVx4MWY8Pl0qfGVtYWlsKT4vLAogIHVybDogbm9vcFRlc3QsCiAgdGFnOgogICAgIl5jb21tZW50IiArCiAgICAifF48L1thLXpBLVpdW1xcdzotXSpcXHMqPiIgKyAvLyBzZWxmLWNsb3NpbmcgdGFnCiAgICAifF48W2EtekEtWl1bXFx3LV0qKD86YXR0cmlidXRlKSo/XFxzKi8/PiIgKyAvLyBvcGVuIHRhZwogICAgInxePFxcP1tcXHNcXFNdKj9cXD8+IiArIC8vIHByb2Nlc3NpbmcgaW5zdHJ1Y3Rpb24sIGUuZy4gPD9waHAgPz4KICAgICJ8XjwhW2EtekEtWl0rXFxzW1xcc1xcU10qPz4iICsgLy8gZGVjbGFyYXRpb24sIGUuZy4gPCFET0NUWVBFIGh0bWw+CiAgICAifF48IVxcW0NEQVRBXFxbW1xcc1xcU10qP1xcXVxcXT4iLCAvLyBDREFUQSBzZWN0aW9uCiAgbGluazogL14hP1xbKGxhYmVsKVxdXChccyooaHJlZikoPzpccysodGl0bGUpKT9ccypcKS8sCiAgcmVmbGluazogL14hP1xbKGxhYmVsKVxdXFsocmVmKVxdLywKICBub2xpbms6IC9eIT9cWyhyZWYpXF0oPzpcW1xdKT8vLAogIHJlZmxpbmtTZWFyY2g6ICJyZWZsaW5rfG5vbGluayg/IVxcKCkiLAogIGVtU3Ryb25nOiB7CiAgICBsRGVsaW06IC9eKD86XCorKD86KFtwdW5jdF9dKXxbXlxzKl0pKXxeXysoPzooW3B1bmN0Kl0pfChbXlxzX10pKS8sCiAgICAvLyAgICAgICAgKDEpIGFuZCAoMikgY2FuIG9ubHkgYmUgYSBSaWdodCBEZWxpbWl0ZXIuICgzKSBhbmQgKDQpIGNhbiBvbmx5IGJlIExlZnQuICAoNSkgYW5kICg2KSBjYW4gYmUgZWl0aGVyIExlZnQgb3IgUmlnaHQuCiAgICAvLyAgICAgICAgICAoKSBTa2lwIG9ycGhhbiBpbnNpZGUgc3Ryb25nICAoKSBDb25zdW1lIHRvIGRlbGltICgxKSAjKioqICAgICAgICAgICAgICAgICgyKSBhKioqIywgYSoqKiAgICAgICAgICAgICAgICAgICAoMykgIyoqKmEsICoqKmEgICAgICAgICAgICAgICAgICg0KSAqKiojICAgICAgICAgICAgICAoNSkgIyoqKiMgICAgICAgICAgICAgICAgICg2KSBhKioqYQogICAgckRlbGltQXN0OgogICAgICAvXlteXypdKj9cX1xfW15fKl0qP1wqW15fKl0qPyg/PVxfXF8pfFteKl0rKD89W14qXSl8W3B1bmN0X10oXCorKSg/PVtcc118JCl8W15wdW5jdCpfXHNdKFwqKykoPz1bcHVuY3RfXHNdfCQpfFtwdW5jdF9cc10oXCorKSg/PVtecHVuY3QqX1xzXSl8W1xzXShcKispKD89W3B1bmN0X10pfFtwdW5jdF9dKFwqKykoPz1bcHVuY3RfXSl8W15wdW5jdCpfXHNdKFwqKykoPz1bXnB1bmN0Kl9cc10pLywKICAgIHJEZWxpbVVuZDoKICAgICAgL15bXl8qXSo/XCpcKlteXypdKj9cX1teXypdKj8oPz1cKlwqKXxbXl9dKyg/PVteX10pfFtwdW5jdCpdKFxfKykoPz1bXHNdfCQpfFtecHVuY3QqX1xzXShcXyspKD89W3B1bmN0KlxzXXwkKXxbcHVuY3QqXHNdKFxfKykoPz1bXnB1bmN0Kl9cc10pfFtcc10oXF8rKSg/PVtwdW5jdCpdKXxbcHVuY3QqXShcXyspKD89W3B1bmN0Kl0pLywgLy8gXi0gTm90IGFsbG93ZWQgZm9yIF8KICB9LAogIGNvZGU6IC9eKGArKShbXmBdfFteYF1bXHNcU10qP1teYF0pXDEoPyFgKS8sCiAgYnI6IC9eKCB7Mix9fFxcKVxuKD8hXHMqJCkvLAogIGRlbDogbm9vcFRlc3QsCiAgdGV4dDogL14oYCt8W15gXSkoPzooPz0gezIsfVxuKXxbXHNcU10qPyg/Oig/PVtcXDwhXFtgKl9dfFxiX3wkKXxbXiBdKD89IHsyLH1cbikpKS8sCiAgcHVuY3R1YXRpb246IC9eKFtcc3B1bmN0dWF0aW9uXSkvLAp9CgovLyBsaXN0IG9mIHB1bmN0dWF0aW9uIG1hcmtzIGZyb20gQ29tbW9uTWFyayBzcGVjCi8vIHdpdGhvdXQgKiBhbmQgXyB0byBoYW5kbGUgdGhlIGRpZmZlcmVudCBlbXBoYXNpcyBtYXJrZXJzICogYW5kIF8KaW5saW5lLl9wdW5jdHVhdGlvbiA9ICIhXCIjJCUmJygpK1xcLS4sLzo7PD0+P0BcXFtcXF1gXnt8fX4iCmlubGluZS5wdW5jdHVhdGlvbiA9IGVkaXQoaW5saW5lLnB1bmN0dWF0aW9uKQogIC5yZXBsYWNlKC9wdW5jdHVhdGlvbi9nLCBpbmxpbmUuX3B1bmN0dWF0aW9uKQogIC5nZXRSZWdleCgpCgovLyBzZXF1ZW5jZXMgZW0gc2hvdWxkIHNraXAgb3ZlciBbdGl0bGVdKGxpbmspLCBgY29kZWAsIDxodG1sPgppbmxpbmUuYmxvY2tTa2lwID0gL1xbW15cXV0qP1xdXChbXlwpXSo/XCl8YFteYF0qP2B8PFtePl0qPz4vZwppbmxpbmUuZXNjYXBlZEVtU3QgPSAvXFxcKnxcXF8vZwoKaW5saW5lLl9jb21tZW50ID0gZWRpdChibG9jay5fY29tbWVudCkucmVwbGFjZSgiKD86LS0+fCQpIiwgIi0tPiIpLmdldFJlZ2V4KCkKCmlubGluZS5lbVN0cm9uZy5sRGVsaW0gPSBlZGl0KGlubGluZS5lbVN0cm9uZy5sRGVsaW0pCiAgLnJlcGxhY2UoL3B1bmN0L2csIGlubGluZS5fcHVuY3R1YXRpb24pCiAgLmdldFJlZ2V4KCkKCmlubGluZS5lbVN0cm9uZy5yRGVsaW1Bc3QgPSBlZGl0KGlubGluZS5lbVN0cm9uZy5yRGVsaW1Bc3QsICJnIikKICAucmVwbGFjZSgvcHVuY3QvZywgaW5saW5lLl9wdW5jdHVhdGlvbikKICAuZ2V0UmVnZXgoKQoKaW5saW5lLmVtU3Ryb25nLnJEZWxpbVVuZCA9IGVkaXQoaW5saW5lLmVtU3Ryb25nLnJEZWxpbVVuZCwgImciKQogIC5yZXBsYWNlKC9wdW5jdC9nLCBpbmxpbmUuX3B1bmN0dWF0aW9uKQogIC5nZXRSZWdleCgpCgppbmxpbmUuX2VzY2FwZXMgPSAvXFwoWyEiIyQlJicoKSorLFwtLi86Ozw9Pj9AXFtcXVxcXl9ge3x9fl0pL2cKCmlubGluZS5fc2NoZW1lID0gL1thLXpBLVpdW2EtekEtWjAtOSsuLV17MSwzMX0vCmlubGluZS5fZW1haWwgPQogIC9bYS16QS1aMC05LiEjJCUmJyorLz0/Xl9ge3x9fi1dKyhAKVthLXpBLVowLTldKD86W2EtekEtWjAtOS1dezAsNjF9W2EtekEtWjAtOV0pPyg/OlwuW2EtekEtWjAtOV0oPzpbYS16QS1aMC05LV17MCw2MX1bYS16QS1aMC05XSk/KSsoPyFbLV9dKS8KaW5saW5lLmF1dG9saW5rID0gZWRpdChpbmxpbmUuYXV0b2xpbmspCiAgLnJlcGxhY2UoInNjaGVtZSIsIGlubGluZS5fc2NoZW1lKQogIC5yZXBsYWNlKCJlbWFpbCIsIGlubGluZS5fZW1haWwpCiAgLmdldFJlZ2V4KCkKCmlubGluZS5fYXR0cmlidXRlID0KICAvXHMrW2EtekEtWjpfXVtcdy46LV0qKD86XHMqPVxzKiJbXiJdKiJ8XHMqPVxzKidbXiddKid8XHMqPVxzKlteXHMiJz08PmBdKyk/LwoKaW5saW5lLnRhZyA9IGVkaXQoaW5saW5lLnRhZykKICAucmVwbGFjZSgiY29tbWVudCIsIGlubGluZS5fY29tbWVudCkKICAucmVwbGFjZSgiYXR0cmlidXRlIiwgaW5saW5lLl9hdHRyaWJ1dGUpCiAgLmdldFJlZ2V4KCkKCmlubGluZS5fbGFiZWwgPSAvKD86XFsoPzpcXC58W15cW1xdXFxdKSpcXXxcXC58YFteYF0qYHxbXlxbXF1cXGBdKSo/LwppbmxpbmUuX2hyZWYgPSAvPCg/OlxcLnxbXlxuPD5cXF0pKz58W15cc1x4MDAtXHgxZl0qLwppbmxpbmUuX3RpdGxlID0gLyIoPzpcXCI/fFteIlxcXSkqInwnKD86XFwnP3xbXidcXF0pKid8XCgoPzpcXFwpP3xbXilcXF0pKlwpLwoKaW5saW5lLmxpbmsgPSBlZGl0KGlubGluZS5saW5rKQogIC5yZXBsYWNlKCJsYWJlbCIsIGlubGluZS5fbGFiZWwpCiAgLnJlcGxhY2UoImhyZWYiLCBpbmxpbmUuX2hyZWYpCiAgLnJlcGxhY2UoInRpdGxlIiwgaW5saW5lLl90aXRsZSkKICAuZ2V0UmVnZXgoKQoKaW5saW5lLnJlZmxpbmsgPSBlZGl0KGlubGluZS5yZWZsaW5rKQogIC5yZXBsYWNlKCJsYWJlbCIsIGlubGluZS5fbGFiZWwpCiAgLnJlcGxhY2UoInJlZiIsIGJsb2NrLl9sYWJlbCkKICAuZ2V0UmVnZXgoKQoKaW5saW5lLm5vbGluayA9IGVkaXQoaW5saW5lLm5vbGluaykucmVwbGFjZSgicmVmIiwgYmxvY2suX2xhYmVsKS5nZXRSZWdleCgpCgppbmxpbmUucmVmbGlua1NlYXJjaCA9IGVkaXQoaW5saW5lLnJlZmxpbmtTZWFyY2gsICJnIikKICAucmVwbGFjZSgicmVmbGluayIsIGlubGluZS5yZWZsaW5rKQogIC5yZXBsYWNlKCJub2xpbmsiLCBpbmxpbmUubm9saW5rKQogIC5nZXRSZWdleCgpCgovKioKICogTm9ybWFsIElubGluZSBHcmFtbWFyCiAqLwoKaW5saW5lLm5vcm1hbCA9IG1lcmdlKHt9LCBpbmxpbmUpCgovKioKICogUGVkYW50aWMgSW5saW5lIEdyYW1tYXIKICovCgppbmxpbmUucGVkYW50aWMgPSBtZXJnZSh7fSwgaW5saW5lLm5vcm1hbCwgewogIHN0cm9uZzogewogICAgc3RhcnQ6IC9eX198XCpcKi8sCiAgICBtaWRkbGU6IC9eX18oPz1cUykoW1xzXFNdKj9cUylfXyg/IV8pfF5cKlwqKD89XFMpKFtcc1xTXSo/XFMpXCpcKig/IVwqKS8sCiAgICBlbmRBc3Q6IC9cKlwqKD8hXCopL2csCiAgICBlbmRVbmQ6IC9fXyg/IV8pL2csCiAgfSwKICBlbTogewogICAgc3RhcnQ6IC9eX3xcKi8sCiAgICBtaWRkbGU6IC9eKClcKig/PVxTKShbXHNcU10qP1xTKVwqKD8hXCopfF5fKD89XFMpKFtcc1xTXSo/XFMpXyg/IV8pLywKICAgIGVuZEFzdDogL1wqKD8hXCopL2csCiAgICBlbmRVbmQ6IC9fKD8hXykvZywKICB9LAogIGxpbms6IGVkaXQoL14hP1xbKGxhYmVsKVxdXCgoLio/KVwpLykKICAgIC5yZXBsYWNlKCJsYWJlbCIsIGlubGluZS5fbGFiZWwpCiAgICAuZ2V0UmVnZXgoKSwKICByZWZsaW5rOiBlZGl0KC9eIT9cWyhsYWJlbClcXVxzKlxbKFteXF1dKilcXS8pCiAgICAucmVwbGFjZSgibGFiZWwiLCBpbmxpbmUuX2xhYmVsKQogICAgLmdldFJlZ2V4KCksCn0pCgovKioKICogR0ZNIElubGluZSBHcmFtbWFyCiAqLwoKaW5saW5lLmdmbSA9IG1lcmdlKHt9LCBpbmxpbmUubm9ybWFsLCB7CiAgZXNjYXBlOiBlZGl0KGlubGluZS5lc2NhcGUpLnJlcGxhY2UoIl0pIiwgIn58XSkiKS5nZXRSZWdleCgpLAogIF9leHRlbmRlZF9lbWFpbDoKICAgIC9bQS1aYS16MC05Ll8rLV0rKEApW2EtekEtWjAtOS1fXSsoPzpcLlthLXpBLVowLTktX10qW2EtekEtWjAtOV0pKyg/IVstX10pLywKICB1cmw6IC9eKCg/OmZ0cHxodHRwcz8pOlwvXC98d3d3XC4pKD86W2EtekEtWjAtOVwtXStcLj8pK1teXHM8XSp8XmVtYWlsLywKICBfYmFja3BlZGFsOgogICAgLyg/OltePyEuLDo7Kl9+KCkmXSt8XChbXildKlwpfCYoPyFbYS16QS1aMC05XSs7JCl8Wz8hLiw6OypffildKyg/ISQpKSsvLAogIGRlbDogL14ofn4/KSg/PVteXHN+XSkoW1xzXFNdKj9bXlxzfl0pXDEoPz1bXn5dfCQpLywKICB0ZXh0OiAvXihbYH5dK3xbXmB+XSkoPzooPz0gezIsfVxuKXwoPz1bYS16QS1aMC05LiEjJCUmJyorXC89P19ge1x8fX4tXStAKXxbXHNcU10qPyg/Oig/PVtcXDwhXFtgKn5fXXxcYl98aHR0cHM/OlwvXC98ZnRwOlwvXC98d3d3XC58JCl8W14gXSg/PSB7Mix9XG4pfFteYS16QS1aMC05LiEjJCUmJyorXC89P19ge1x8fX4tXSg/PVthLXpBLVowLTkuISMkJSYnKitcLz0/X2B7XHx9fi1dK0ApKSkvLAp9KQoKaW5saW5lLmdmbS51cmwgPSBlZGl0KGlubGluZS5nZm0udXJsLCAiaSIpCiAgLnJlcGxhY2UoImVtYWlsIiwgaW5saW5lLmdmbS5fZXh0ZW5kZWRfZW1haWwpCiAgLmdldFJlZ2V4KCkKLyoqCiAqIEdGTSArIExpbmUgQnJlYWtzIElubGluZSBHcmFtbWFyCiAqLwoKaW5saW5lLmJyZWFrcyA9IG1lcmdlKHt9LCBpbmxpbmUuZ2ZtLCB7CiAgYnI6IGVkaXQoaW5saW5lLmJyKS5yZXBsYWNlKCJ7Mix9IiwgIioiKS5nZXRSZWdleCgpLAogIHRleHQ6IGVkaXQoaW5saW5lLmdmbS50ZXh0KQogICAgLnJlcGxhY2UoIlxcYl8iLCAiXFxiX3wgezIsfVxcbiIpCiAgICAucmVwbGFjZSgvXHsyLFx9L2csICIqIikKICAgIC5nZXRSZWdleCgpLAp9KQoKLyoqCiAqIHNtYXJ0eXBhbnRzIHRleHQgcmVwbGFjZW1lbnQKICogQHBhcmFtIHtzdHJpbmd9IHRleHQKICovCmZ1bmN0aW9uIHNtYXJ0eXBhbnRzKHRleHQpIHsKICByZXR1cm4gKAogICAgdGV4dAogICAgICAvLyBlbS1kYXNoZXMKICAgICAgLnJlcGxhY2UoLy0tLS9nLCAiXHUyMDE0IikKICAgICAgLy8gZW4tZGFzaGVzCiAgICAgIC5yZXBsYWNlKC8tLS9nLCAiXHUyMDEzIikKICAgICAgLy8gb3BlbmluZyBzaW5nbGVzCiAgICAgIC5yZXBsYWNlKC8oXnxbLVx1MjAxNC8oXFt7IlxzXSknL2csICIkMVx1MjAxOCIpCiAgICAgIC8vIGNsb3Npbmcgc2luZ2xlcyAmIGFwb3N0cm9waGVzCiAgICAgIC5yZXBsYWNlKC8nL2csICJcdTIwMTkiKQogICAgICAvLyBvcGVuaW5nIGRvdWJsZXMKICAgICAgLnJlcGxhY2UoLyhefFstXHUyMDE0LyhcW3tcdTIwMThcc10pIi9nLCAiJDFcdTIwMWMiKQogICAgICAvLyBjbG9zaW5nIGRvdWJsZXMKICAgICAgLnJlcGxhY2UoLyIvZywgIlx1MjAxZCIpCiAgICAgIC8vIGVsbGlwc2VzCiAgICAgIC5yZXBsYWNlKC9cLnszfS9nLCAiXHUyMDI2IikKICApCn0KCi8qKgogKiBtYW5nbGUgZW1haWwgYWRkcmVzc2VzCiAqIEBwYXJhbSB7c3RyaW5nfSB0ZXh0CiAqLwpmdW5jdGlvbiBtYW5nbGUodGV4dCkgewogIGxldCBvdXQgPSAiIiwKICAgIGksCiAgICBjaAoKICBjb25zdCBsID0gdGV4dC5sZW5ndGgKICBmb3IgKGkgPSAwOyBpIDwgbDsgaSsrKSB7CiAgICBjaCA9IHRleHQuY2hhckNvZGVBdChpKQogICAgaWYgKE1hdGgucmFuZG9tKCkgPiAwLjUpIHsKICAgICAgY2ggPSAieCIgKyBjaC50b1N0cmluZygxNikKICAgIH0KICAgIG91dCArPSAiJiMiICsgY2ggKyAiOyIKICB9CgogIHJldHVybiBvdXQKfQoKLyoqCiAqIEJsb2NrIExleGVyCiAqLwpjbGFzcyBMZXhlciB7CiAgY29uc3RydWN0b3Iob3B0aW9ucykgewogICAgdGhpcy50b2tlbnMgPSBbXQogICAgdGhpcy50b2tlbnMubGlua3MgPSBPYmplY3QuY3JlYXRlKG51bGwpCiAgICB0aGlzLm9wdGlvbnMgPSBvcHRpb25zIHx8IGRlZmF1bHRzCiAgICB0aGlzLm9wdGlvbnMudG9rZW5pemVyID0gdGhpcy5vcHRpb25zLnRva2VuaXplciB8fCBuZXcgVG9rZW5pemVyKCkKICAgIHRoaXMudG9rZW5pemVyID0gdGhpcy5vcHRpb25zLnRva2VuaXplcgogICAgdGhpcy50b2tlbml6ZXIub3B0aW9ucyA9IHRoaXMub3B0aW9ucwogICAgdGhpcy50b2tlbml6ZXIubGV4ZXIgPSB0aGlzCiAgICB0aGlzLmlubGluZVF1ZXVlID0gW10KICAgIHRoaXMuc3RhdGUgPSB7CiAgICAgIGluTGluazogZmFsc2UsCiAgICAgIGluUmF3QmxvY2s6IGZhbHNlLAogICAgICB0b3A6IHRydWUsCiAgICB9CgogICAgY29uc3QgcnVsZXMgPSB7CiAgICAgIGJsb2NrOiBibG9jay5ub3JtYWwsCiAgICAgIGlubGluZTogaW5saW5lLm5vcm1hbCwKICAgIH0KCiAgICBpZiAodGhpcy5vcHRpb25zLnBlZGFudGljKSB7CiAgICAgIHJ1bGVzLmJsb2NrID0gYmxvY2sucGVkYW50aWMKICAgICAgcnVsZXMuaW5saW5lID0gaW5saW5lLnBlZGFudGljCiAgICB9IGVsc2UgaWYgKHRoaXMub3B0aW9ucy5nZm0pIHsKICAgICAgcnVsZXMuYmxvY2sgPSBibG9jay5nZm0KICAgICAgaWYgKHRoaXMub3B0aW9ucy5icmVha3MpIHsKICAgICAgICBydWxlcy5pbmxpbmUgPSBpbmxpbmUuYnJlYWtzCiAgICAgIH0gZWxzZSB7CiAgICAgICAgcnVsZXMuaW5saW5lID0gaW5saW5lLmdmbQogICAgICB9CiAgICB9CiAgICB0aGlzLnRva2VuaXplci5ydWxlcyA9IHJ1bGVzCiAgfQoKICAvKioKICAgKiBFeHBvc2UgUnVsZXMKICAgKi8KICBzdGF0aWMgZ2V0IHJ1bGVzKCkgewogICAgcmV0dXJuIHsKICAgICAgYmxvY2ssCiAgICAgIGlubGluZSwKICAgIH0KICB9CgogIC8qKgogICAqIFN0YXRpYyBMZXggTWV0aG9kCiAgICovCiAgc3RhdGljIGxleChzcmMsIG9wdGlvbnMpIHsKICAgIGNvbnN0IGxleGVyID0gbmV3IExleGVyKG9wdGlvbnMpCiAgICByZXR1cm4gbGV4ZXIubGV4KHNyYykKICB9CgogIC8qKgogICAqIFN0YXRpYyBMZXggSW5saW5lIE1ldGhvZAogICAqLwogIHN0YXRpYyBsZXhJbmxpbmUoc3JjLCBvcHRpb25zKSB7CiAgICBjb25zdCBsZXhlciA9IG5ldyBMZXhlcihvcHRpb25zKQogICAgcmV0dXJuIGxleGVyLmlubGluZVRva2VucyhzcmMpCiAgfQoKICAvKioKICAgKiBQcmVwcm9jZXNzaW5nCiAgICovCiAgbGV4KHNyYykgewogICAgc3JjID0gc3JjLnJlcGxhY2UoL1xyXG58XHIvZywgIlxuIikKCiAgICB0aGlzLmJsb2NrVG9rZW5zKHNyYywgdGhpcy50b2tlbnMpCgogICAgbGV0IG5leHQKICAgIHdoaWxlICgobmV4dCA9IHRoaXMuaW5saW5lUXVldWUuc2hpZnQoKSkpIHsKICAgICAgdGhpcy5pbmxpbmVUb2tlbnMobmV4dC5zcmMsIG5leHQudG9rZW5zKQogICAgfQoKICAgIHJldHVybiB0aGlzLnRva2VucwogIH0KCiAgLyoqCiAgICogTGV4aW5nCiAgICovCiAgYmxvY2tUb2tlbnMoc3JjLCB0b2tlbnMgPSBbXSkgewogICAgaWYgKHRoaXMub3B0aW9ucy5wZWRhbnRpYykgewogICAgICBzcmMgPSBzcmMucmVwbGFjZSgvXHQvZywgIiAgICAiKS5yZXBsYWNlKC9eICskL2dtLCAiIikKICAgIH0gZWxzZSB7CiAgICAgIHNyYyA9IHNyYy5yZXBsYWNlKC9eKCAqKShcdCspL2dtLCAoXywgbGVhZGluZywgdGFicykgPT4gewogICAgICAgIHJldHVybiBsZWFkaW5nICsgIiAgICAiLnJlcGVhdCh0YWJzLmxlbmd0aCkKICAgICAgfSkKICAgIH0KCiAgICBsZXQgdG9rZW4sIGxhc3RUb2tlbiwgY3V0U3JjLCBsYXN0UGFyYWdyYXBoQ2xpcHBlZAoKICAgIHdoaWxlIChzcmMpIHsKICAgICAgaWYgKAogICAgICAgIHRoaXMub3B0aW9ucy5leHRlbnNpb25zICYmCiAgICAgICAgdGhpcy5vcHRpb25zLmV4dGVuc2lvbnMuYmxvY2sgJiYKICAgICAgICB0aGlzLm9wdGlvbnMuZXh0ZW5zaW9ucy5ibG9jay5zb21lKGV4dFRva2VuaXplciA9PiB7CiAgICAgICAgICBpZiAoKHRva2VuID0gZXh0VG9rZW5pemVyLmNhbGwoeyBsZXhlcjogdGhpcyB9LCBzcmMsIHRva2VucykpKSB7CiAgICAgICAgICAgIHNyYyA9IHNyYy5zdWJzdHJpbmcodG9rZW4ucmF3Lmxlbmd0aCkKICAgICAgICAgICAgdG9rZW5zLnB1c2godG9rZW4pCiAgICAgICAgICAgIHJldHVybiB0cnVlCiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gZmFsc2UKICAgICAgICB9KQogICAgICApIHsKICAgICAgICBjb250aW51ZQogICAgICB9CgogICAgICAvLyBuZXdsaW5lCiAgICAgIGlmICgodG9rZW4gPSB0aGlzLnRva2VuaXplci5zcGFjZShzcmMpKSkgewogICAgICAgIHNyYyA9IHNyYy5zdWJzdHJpbmcodG9rZW4ucmF3Lmxlbmd0aCkKICAgICAgICBpZiAodG9rZW4ucmF3Lmxlbmd0aCA9PT0gMSAmJiB0b2tlbnMubGVuZ3RoID4gMCkgewogICAgICAgICAgLy8gaWYgdGhlcmUncyBhIHNpbmdsZSBcbiBhcyBhIHNwYWNlciwgaXQncyB0ZXJtaW5hdGluZyB0aGUgbGFzdCBsaW5lLAogICAgICAgICAgLy8gc28gbW92ZSBpdCB0aGVyZSBzbyB0aGF0IHdlIGRvbid0IGdldCB1bmVjZXNzYXJ5IHBhcmFncmFwaCB0YWdzCiAgICAgICAgICB0b2tlbnNbdG9rZW5zLmxlbmd0aCAtIDFdLnJhdyArPSAiXG4iCiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIHRva2Vucy5wdXNoKHRva2VuKQogICAgICAgIH0KICAgICAgICBjb250aW51ZQogICAgICB9CgogICAgICAvLyBjb2RlCiAgICAgIGlmICgodG9rZW4gPSB0aGlzLnRva2VuaXplci5jb2RlKHNyYykpKSB7CiAgICAgICAgc3JjID0gc3JjLnN1YnN0cmluZyh0b2tlbi5yYXcubGVuZ3RoKQogICAgICAgIGxhc3RUb2tlbiA9IHRva2Vuc1t0b2tlbnMubGVuZ3RoIC0gMV0KICAgICAgICAvLyBBbiBpbmRlbnRlZCBjb2RlIGJsb2NrIGNhbm5vdCBpbnRlcnJ1cHQgYSBwYXJhZ3JhcGguCiAgICAgICAgaWYgKAogICAgICAgICAgbGFzdFRva2VuICYmCiAgICAgICAgICAobGFzdFRva2VuLnR5cGUgPT09ICJwYXJhZ3JhcGgiIHx8IGxhc3RUb2tlbi50eXBlID09PSAidGV4dCIpCiAgICAgICAgKSB7CiAgICAgICAgICBsYXN0VG9rZW4ucmF3ICs9ICJcbiIgKyB0b2tlbi5yYXcKICAgICAgICAgIGxhc3RUb2tlbi50ZXh0ICs9ICJcbiIgKyB0b2tlbi50ZXh0CiAgICAgICAgICB0aGlzLmlubGluZVF1ZXVlW3RoaXMuaW5saW5lUXVldWUubGVuZ3RoIC0gMV0uc3JjID0gbGFzdFRva2VuLnRleHQKICAgICAgICB9IGVsc2UgewogICAgICAgICAgdG9rZW5zLnB1c2godG9rZW4pCiAgICAgICAgfQogICAgICAgIGNvbnRpbnVlCiAgICAgIH0KCiAgICAgIC8vIGZlbmNlcwogICAgICBpZiAoKHRva2VuID0gdGhpcy50b2tlbml6ZXIuZmVuY2VzKHNyYykpKSB7CiAgICAgICAgc3JjID0gc3JjLnN1YnN0cmluZyh0b2tlbi5yYXcubGVuZ3RoKQogICAgICAgIHRva2Vucy5wdXNoKHRva2VuKQogICAgICAgIGNvbnRpbnVlCiAgICAgIH0KCiAgICAgIC8vIGhlYWRpbmcKICAgICAgaWYgKCh0b2tlbiA9IHRoaXMudG9rZW5pemVyLmhlYWRpbmcoc3JjKSkpIHsKICAgICAgICBzcmMgPSBzcmMuc3Vic3RyaW5nKHRva2VuLnJhdy5sZW5ndGgpCiAgICAgICAgdG9rZW5zLnB1c2godG9rZW4pCiAgICAgICAgY29udGludWUKICAgICAgfQoKICAgICAgLy8gaHIKICAgICAgaWYgKCh0b2tlbiA9IHRoaXMudG9rZW5pemVyLmhyKHNyYykpKSB7CiAgICAgICAgc3JjID0gc3JjLnN1YnN0cmluZyh0b2tlbi5yYXcubGVuZ3RoKQogICAgICAgIHRva2Vucy5wdXNoKHRva2VuKQogICAgICAgIGNvbnRpbnVlCiAgICAgIH0KCiAgICAgIC8vIGJsb2NrcXVvdGUKICAgICAgaWYgKCh0b2tlbiA9IHRoaXMudG9rZW5pemVyLmJsb2NrcXVvdGUoc3JjKSkpIHsKICAgICAgICBzcmMgPSBzcmMuc3Vic3RyaW5nKHRva2VuLnJhdy5sZW5ndGgpCiAgICAgICAgdG9rZW5zLnB1c2godG9rZW4pCiAgICAgICAgY29udGludWUKICAgICAgfQoKICAgICAgLy8gbGlzdAogICAgICBpZiAoKHRva2VuID0gdGhpcy50b2tlbml6ZXIubGlzdChzcmMpKSkgewogICAgICAgIHNyYyA9IHNyYy5zdWJzdHJpbmcodG9rZW4ucmF3Lmxlbmd0aCkKICAgICAgICB0b2tlbnMucHVzaCh0b2tlbikKICAgICAgICBjb250aW51ZQogICAgICB9CgogICAgICAvLyBodG1sCiAgICAgIGlmICgodG9rZW4gPSB0aGlzLnRva2VuaXplci5odG1sKHNyYykpKSB7CiAgICAgICAgc3JjID0gc3JjLnN1YnN0cmluZyh0b2tlbi5yYXcubGVuZ3RoKQogICAgICAgIHRva2Vucy5wdXNoKHRva2VuKQogICAgICAgIGNvbnRpbnVlCiAgICAgIH0KCiAgICAgIC8vIGRlZgogICAgICBpZiAoKHRva2VuID0gdGhpcy50b2tlbml6ZXIuZGVmKHNyYykpKSB7CiAgICAgICAgc3JjID0gc3JjLnN1YnN0cmluZyh0b2tlbi5yYXcubGVuZ3RoKQogICAgICAgIGxhc3RUb2tlbiA9IHRva2Vuc1t0b2tlbnMubGVuZ3RoIC0gMV0KICAgICAgICBpZiAoCiAgICAgICAgICBsYXN0VG9rZW4gJiYKICAgICAgICAgIChsYXN0VG9rZW4udHlwZSA9PT0gInBhcmFncmFwaCIgfHwgbGFzdFRva2VuLnR5cGUgPT09ICJ0ZXh0IikKICAgICAgICApIHsKICAgICAgICAgIGxhc3RUb2tlbi5yYXcgKz0gIlxuIiArIHRva2VuLnJhdwogICAgICAgICAgbGFzdFRva2VuLnRleHQgKz0gIlxuIiArIHRva2VuLnJhdwogICAgICAgICAgdGhpcy5pbmxpbmVRdWV1ZVt0aGlzLmlubGluZVF1ZXVlLmxlbmd0aCAtIDFdLnNyYyA9IGxhc3RUb2tlbi50ZXh0CiAgICAgICAgfSBlbHNlIGlmICghdGhpcy50b2tlbnMubGlua3NbdG9rZW4udGFnXSkgewogICAgICAgICAgdGhpcy50b2tlbnMubGlua3NbdG9rZW4udGFnXSA9IHsKICAgICAgICAgICAgaHJlZjogdG9rZW4uaHJlZiwKICAgICAgICAgICAgdGl0bGU6IHRva2VuLnRpdGxlLAogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBjb250aW51ZQogICAgICB9CgogICAgICAvLyB0YWJsZSAoZ2ZtKQogICAgICBpZiAoKHRva2VuID0gdGhpcy50b2tlbml6ZXIudGFibGUoc3JjKSkpIHsKICAgICAgICBzcmMgPSBzcmMuc3Vic3RyaW5nKHRva2VuLnJhdy5sZW5ndGgpCiAgICAgICAgdG9rZW5zLnB1c2godG9rZW4pCiAgICAgICAgY29udGludWUKICAgICAgfQoKICAgICAgLy8gbGhlYWRpbmcKICAgICAgaWYgKCh0b2tlbiA9IHRoaXMudG9rZW5pemVyLmxoZWFkaW5nKHNyYykpKSB7CiAgICAgICAgc3JjID0gc3JjLnN1YnN0cmluZyh0b2tlbi5yYXcubGVuZ3RoKQogICAgICAgIHRva2Vucy5wdXNoKHRva2VuKQogICAgICAgIGNvbnRpbnVlCiAgICAgIH0KCiAgICAgIC8vIHRvcC1sZXZlbCBwYXJhZ3JhcGgKICAgICAgLy8gcHJldmVudCBwYXJhZ3JhcGggY29uc3VtaW5nIGV4dGVuc2lvbnMgYnkgY2xpcHBpbmcgJ3NyYycgdG8gZXh0ZW5zaW9uIHN0YXJ0CiAgICAgIGN1dFNyYyA9IHNyYwogICAgICBpZiAodGhpcy5vcHRpb25zLmV4dGVuc2lvbnMgJiYgdGhpcy5vcHRpb25zLmV4dGVuc2lvbnMuc3RhcnRCbG9jaykgewogICAgICAgIGxldCBzdGFydEluZGV4ID0gSW5maW5pdHkKICAgICAgICBjb25zdCB0ZW1wU3JjID0gc3JjLnNsaWNlKDEpCiAgICAgICAgbGV0IHRlbXBTdGFydAogICAgICAgIHRoaXMub3B0aW9ucy5leHRlbnNpb25zLnN0YXJ0QmxvY2suZm9yRWFjaChmdW5jdGlvbiAoZ2V0U3RhcnRJbmRleCkgewogICAgICAgICAgdGVtcFN0YXJ0ID0gZ2V0U3RhcnRJbmRleC5jYWxsKHsgbGV4ZXI6IHRoaXMgfSwgdGVtcFNyYykKICAgICAgICAgIGlmICh0eXBlb2YgdGVtcFN0YXJ0ID09PSAibnVtYmVyIiAmJiB0ZW1wU3RhcnQgPj0gMCkgewogICAgICAgICAgICBzdGFydEluZGV4ID0gTWF0aC5taW4oc3RhcnRJbmRleCwgdGVtcFN0YXJ0KQogICAgICAgICAgfQogICAgICAgIH0pCiAgICAgICAgaWYgKHN0YXJ0SW5kZXggPCBJbmZpbml0eSAmJiBzdGFydEluZGV4ID49IDApIHsKICAgICAgICAgIGN1dFNyYyA9IHNyYy5zdWJzdHJpbmcoMCwgc3RhcnRJbmRleCArIDEpCiAgICAgICAgfQogICAgICB9CiAgICAgIGlmICh0aGlzLnN0YXRlLnRvcCAmJiAodG9rZW4gPSB0aGlzLnRva2VuaXplci5wYXJhZ3JhcGgoY3V0U3JjKSkpIHsKICAgICAgICBsYXN0VG9rZW4gPSB0b2tlbnNbdG9rZW5zLmxlbmd0aCAtIDFdCiAgICAgICAgaWYgKGxhc3RQYXJhZ3JhcGhDbGlwcGVkICYmIGxhc3RUb2tlbi50eXBlID09PSAicGFyYWdyYXBoIikgewogICAgICAgICAgbGFzdFRva2VuLnJhdyArPSAiXG4iICsgdG9rZW4ucmF3CiAgICAgICAgICBsYXN0VG9rZW4udGV4dCArPSAiXG4iICsgdG9rZW4udGV4dAogICAgICAgICAgdGhpcy5pbmxpbmVRdWV1ZS5wb3AoKQogICAgICAgICAgdGhpcy5pbmxpbmVRdWV1ZVt0aGlzLmlubGluZVF1ZXVlLmxlbmd0aCAtIDFdLnNyYyA9IGxhc3RUb2tlbi50ZXh0CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIHRva2Vucy5wdXNoKHRva2VuKQogICAgICAgIH0KICAgICAgICBsYXN0UGFyYWdyYXBoQ2xpcHBlZCA9IGN1dFNyYy5sZW5ndGggIT09IHNyYy5sZW5ndGgKICAgICAgICBzcmMgPSBzcmMuc3Vic3RyaW5nKHRva2VuLnJhdy5sZW5ndGgpCiAgICAgICAgY29udGludWUKICAgICAgfQoKICAgICAgLy8gdGV4dAogICAgICBpZiAoKHRva2VuID0gdGhpcy50b2tlbml6ZXIudGV4dChzcmMpKSkgewogICAgICAgIHNyYyA9IHNyYy5zdWJzdHJpbmcodG9rZW4ucmF3Lmxlbmd0aCkKICAgICAgICBsYXN0VG9rZW4gPSB0b2tlbnNbdG9rZW5zLmxlbmd0aCAtIDFdCiAgICAgICAgaWYgKGxhc3RUb2tlbiAmJiBsYXN0VG9rZW4udHlwZSA9PT0gInRleHQiKSB7CiAgICAgICAgICBsYXN0VG9rZW4ucmF3ICs9ICJcbiIgKyB0b2tlbi5yYXcKICAgICAgICAgIGxhc3RUb2tlbi50ZXh0ICs9ICJcbiIgKyB0b2tlbi50ZXh0CiAgICAgICAgICB0aGlzLmlubGluZVF1ZXVlLnBvcCgpCiAgICAgICAgICB0aGlzLmlubGluZVF1ZXVlW3RoaXMuaW5saW5lUXVldWUubGVuZ3RoIC0gMV0uc3JjID0gbGFzdFRva2VuLnRleHQKICAgICAgICB9IGVsc2UgewogICAgICAgICAgdG9rZW5zLnB1c2godG9rZW4pCiAgICAgICAgfQogICAgICAgIGNvbnRpbnVlCiAgICAgIH0KCiAgICAgIGlmIChzcmMpIHsKICAgICAgICBjb25zdCBlcnJNc2cgPSAiSW5maW5pdGUgbG9vcCBvbiBieXRlOiAiICsgc3JjLmNoYXJDb2RlQXQoMCkKICAgICAgICBpZiAodGhpcy5vcHRpb25zLnNpbGVudCkgewogICAgICAgICAgY29uc29sZS5lcnJvcihlcnJNc2cpCiAgICAgICAgICBicmVhawogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoZXJyTXNnKQogICAgICAgIH0KICAgICAgfQogICAgfQoKICAgIHRoaXMuc3RhdGUudG9wID0gdHJ1ZQogICAgcmV0dXJuIHRva2VucwogIH0KCiAgaW5saW5lKHNyYywgdG9rZW5zKSB7CiAgICB0aGlzLmlubGluZVF1ZXVlLnB1c2goeyBzcmMsIHRva2VucyB9KQogIH0KCiAgLyoqCiAgICogTGV4aW5nL0NvbXBpbGluZwogICAqLwogIGlubGluZVRva2VucyhzcmMsIHRva2VucyA9IFtdKSB7CiAgICBsZXQgdG9rZW4sIGxhc3RUb2tlbiwgY3V0U3JjCgogICAgLy8gU3RyaW5nIHdpdGggbGlua3MgbWFza2VkIHRvIGF2b2lkIGludGVyZmVyZW5jZSB3aXRoIGVtIGFuZCBzdHJvbmcKICAgIGxldCBtYXNrZWRTcmMgPSBzcmMKICAgIGxldCBtYXRjaAogICAgbGV0IGtlZXBQcmV2Q2hhciwgcHJldkNoYXIKCiAgICAvLyBNYXNrIG91dCByZWZsaW5rcwogICAgaWYgKHRoaXMudG9rZW5zLmxpbmtzKSB7CiAgICAgIGNvbnN0IGxpbmtzID0gT2JqZWN0LmtleXModGhpcy50b2tlbnMubGlua3MpCiAgICAgIGlmIChsaW5rcy5sZW5ndGggPiAwKSB7CiAgICAgICAgd2hpbGUgKAogICAgICAgICAgKG1hdGNoID0gdGhpcy50b2tlbml6ZXIucnVsZXMuaW5saW5lLnJlZmxpbmtTZWFyY2guZXhlYyhtYXNrZWRTcmMpKSAhPQogICAgICAgICAgbnVsbAogICAgICAgICkgewogICAgICAgICAgaWYgKAogICAgICAgICAgICBsaW5rcy5pbmNsdWRlcyhtYXRjaFswXS5zbGljZShtYXRjaFswXS5sYXN0SW5kZXhPZigiWyIpICsgMSwgLTEpKQogICAgICAgICAgKSB7CiAgICAgICAgICAgIG1hc2tlZFNyYyA9CiAgICAgICAgICAgICAgbWFza2VkU3JjLnNsaWNlKDAsIG1hdGNoLmluZGV4KSArCiAgICAgICAgICAgICAgIlsiICsKICAgICAgICAgICAgICByZXBlYXRTdHJpbmcoImEiLCBtYXRjaFswXS5sZW5ndGggLSAyKSArCiAgICAgICAgICAgICAgIl0iICsKICAgICAgICAgICAgICBtYXNrZWRTcmMuc2xpY2UoCiAgICAgICAgICAgICAgICB0aGlzLnRva2VuaXplci5ydWxlcy5pbmxpbmUucmVmbGlua1NlYXJjaC5sYXN0SW5kZXgKICAgICAgICAgICAgICApCiAgICAgICAgICB9CiAgICAgICAgfQogICAgICB9CiAgICB9CiAgICAvLyBNYXNrIG91dCBvdGhlciBibG9ja3MKICAgIHdoaWxlICgKICAgICAgKG1hdGNoID0gdGhpcy50b2tlbml6ZXIucnVsZXMuaW5saW5lLmJsb2NrU2tpcC5leGVjKG1hc2tlZFNyYykpICE9IG51bGwKICAgICkgewogICAgICBtYXNrZWRTcmMgPQogICAgICAgIG1hc2tlZFNyYy5zbGljZSgwLCBtYXRjaC5pbmRleCkgKwogICAgICAgICJbIiArCiAgICAgICAgcmVwZWF0U3RyaW5nKCJhIiwgbWF0Y2hbMF0ubGVuZ3RoIC0gMikgKwogICAgICAgICJdIiArCiAgICAgICAgbWFza2VkU3JjLnNsaWNlKHRoaXMudG9rZW5pemVyLnJ1bGVzLmlubGluZS5ibG9ja1NraXAubGFzdEluZGV4KQogICAgfQoKICAgIC8vIE1hc2sgb3V0IGVzY2FwZWQgZW0gJiBzdHJvbmcgZGVsaW1pdGVycwogICAgd2hpbGUgKAogICAgICAobWF0Y2ggPSB0aGlzLnRva2VuaXplci5ydWxlcy5pbmxpbmUuZXNjYXBlZEVtU3QuZXhlYyhtYXNrZWRTcmMpKSAhPSBudWxsCiAgICApIHsKICAgICAgbWFza2VkU3JjID0KICAgICAgICBtYXNrZWRTcmMuc2xpY2UoMCwgbWF0Y2guaW5kZXgpICsKICAgICAgICAiKysiICsKICAgICAgICBtYXNrZWRTcmMuc2xpY2UodGhpcy50b2tlbml6ZXIucnVsZXMuaW5saW5lLmVzY2FwZWRFbVN0Lmxhc3RJbmRleCkKICAgIH0KCiAgICB3aGlsZSAoc3JjKSB7CiAgICAgIGlmICgha2VlcFByZXZDaGFyKSB7CiAgICAgICAgcHJldkNoYXIgPSAiIgogICAgICB9CiAgICAgIGtlZXBQcmV2Q2hhciA9IGZhbHNlCgogICAgICAvLyBleHRlbnNpb25zCiAgICAgIGlmICgKICAgICAgICB0aGlzLm9wdGlvbnMuZXh0ZW5zaW9ucyAmJgogICAgICAgIHRoaXMub3B0aW9ucy5leHRlbnNpb25zLmlubGluZSAmJgogICAgICAgIHRoaXMub3B0aW9ucy5leHRlbnNpb25zLmlubGluZS5zb21lKGV4dFRva2VuaXplciA9PiB7CiAgICAgICAgICBpZiAoKHRva2VuID0gZXh0VG9rZW5pemVyLmNhbGwoeyBsZXhlcjogdGhpcyB9LCBzcmMsIHRva2VucykpKSB7CiAgICAgICAgICAgIHNyYyA9IHNyYy5zdWJzdHJpbmcodG9rZW4ucmF3Lmxlbmd0aCkKICAgICAgICAgICAgdG9rZW5zLnB1c2godG9rZW4pCiAgICAgICAgICAgIHJldHVybiB0cnVlCiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gZmFsc2UKICAgICAgICB9KQogICAgICApIHsKICAgICAgICBjb250aW51ZQogICAgICB9CgogICAgICAvLyBlc2NhcGUKICAgICAgaWYgKCh0b2tlbiA9IHRoaXMudG9rZW5pemVyLmVzY2FwZShzcmMpKSkgewogICAgICAgIHNyYyA9IHNyYy5zdWJzdHJpbmcodG9rZW4ucmF3Lmxlbmd0aCkKICAgICAgICB0b2tlbnMucHVzaCh0b2tlbikKICAgICAgICBjb250aW51ZQogICAgICB9CgogICAgICAvLyB0YWcKICAgICAgaWYgKCh0b2tlbiA9IHRoaXMudG9rZW5pemVyLnRhZyhzcmMpKSkgewogICAgICAgIHNyYyA9IHNyYy5zdWJzdHJpbmcodG9rZW4ucmF3Lmxlbmd0aCkKICAgICAgICBsYXN0VG9rZW4gPSB0b2tlbnNbdG9rZW5zLmxlbmd0aCAtIDFdCiAgICAgICAgaWYgKGxhc3RUb2tlbiAmJiB0b2tlbi50eXBlID09PSAidGV4dCIgJiYgbGFzdFRva2VuLnR5cGUgPT09ICJ0ZXh0IikgewogICAgICAgICAgbGFzdFRva2VuLnJhdyArPSB0b2tlbi5yYXcKICAgICAgICAgIGxhc3RUb2tlbi50ZXh0ICs9IHRva2VuLnRleHQKICAgICAgICB9IGVsc2UgewogICAgICAgICAgdG9rZW5zLnB1c2godG9rZW4pCiAgICAgICAgfQogICAgICAgIGNvbnRpbnVlCiAgICAgIH0KCiAgICAgIC8vIGxpbmsKICAgICAgaWYgKCh0b2tlbiA9IHRoaXMudG9rZW5pemVyLmxpbmsoc3JjKSkpIHsKICAgICAgICBzcmMgPSBzcmMuc3Vic3RyaW5nKHRva2VuLnJhdy5sZW5ndGgpCiAgICAgICAgdG9rZW5zLnB1c2godG9rZW4pCiAgICAgICAgY29udGludWUKICAgICAgfQoKICAgICAgLy8gcmVmbGluaywgbm9saW5rCiAgICAgIGlmICgodG9rZW4gPSB0aGlzLnRva2VuaXplci5yZWZsaW5rKHNyYywgdGhpcy50b2tlbnMubGlua3MpKSkgewogICAgICAgIHNyYyA9IHNyYy5zdWJzdHJpbmcodG9rZW4ucmF3Lmxlbmd0aCkKICAgICAgICBsYXN0VG9rZW4gPSB0b2tlbnNbdG9rZW5zLmxlbmd0aCAtIDFdCiAgICAgICAgaWYgKGxhc3RUb2tlbiAmJiB0b2tlbi50eXBlID09PSAidGV4dCIgJiYgbGFzdFRva2VuLnR5cGUgPT09ICJ0ZXh0IikgewogICAgICAgICAgbGFzdFRva2VuLnJhdyArPSB0b2tlbi5yYXcKICAgICAgICAgIGxhc3RUb2tlbi50ZXh0ICs9IHRva2VuLnRleHQKICAgICAgICB9IGVsc2UgewogICAgICAgICAgdG9rZW5zLnB1c2godG9rZW4pCiAgICAgICAgfQogICAgICAgIGNvbnRpbnVlCiAgICAgIH0KCiAgICAgIC8vIGVtICYgc3Ryb25nCiAgICAgIGlmICgodG9rZW4gPSB0aGlzLnRva2VuaXplci5lbVN0cm9uZyhzcmMsIG1hc2tlZFNyYywgcHJldkNoYXIpKSkgewogICAgICAgIHNyYyA9IHNyYy5zdWJzdHJpbmcodG9rZW4ucmF3Lmxlbmd0aCkKICAgICAgICB0b2tlbnMucHVzaCh0b2tlbikKICAgICAgICBjb250aW51ZQogICAgICB9CgogICAgICAvLyBjb2RlCiAgICAgIGlmICgodG9rZW4gPSB0aGlzLnRva2VuaXplci5jb2Rlc3BhbihzcmMpKSkgewogICAgICAgIHNyYyA9IHNyYy5zdWJzdHJpbmcodG9rZW4ucmF3Lmxlbmd0aCkKICAgICAgICB0b2tlbnMucHVzaCh0b2tlbikKICAgICAgICBjb250aW51ZQogICAgICB9CgogICAgICAvLyBicgogICAgICBpZiAoKHRva2VuID0gdGhpcy50b2tlbml6ZXIuYnIoc3JjKSkpIHsKICAgICAgICBzcmMgPSBzcmMuc3Vic3RyaW5nKHRva2VuLnJhdy5sZW5ndGgpCiAgICAgICAgdG9rZW5zLnB1c2godG9rZW4pCiAgICAgICAgY29udGludWUKICAgICAgfQoKICAgICAgLy8gZGVsIChnZm0pCiAgICAgIGlmICgodG9rZW4gPSB0aGlzLnRva2VuaXplci5kZWwoc3JjKSkpIHsKICAgICAgICBzcmMgPSBzcmMuc3Vic3RyaW5nKHRva2VuLnJhdy5sZW5ndGgpCiAgICAgICAgdG9rZW5zLnB1c2godG9rZW4pCiAgICAgICAgY29udGludWUKICAgICAgfQoKICAgICAgLy8gYXV0b2xpbmsKICAgICAgaWYgKCh0b2tlbiA9IHRoaXMudG9rZW5pemVyLmF1dG9saW5rKHNyYywgbWFuZ2xlKSkpIHsKICAgICAgICBzcmMgPSBzcmMuc3Vic3RyaW5nKHRva2VuLnJhdy5sZW5ndGgpCiAgICAgICAgdG9rZW5zLnB1c2godG9rZW4pCiAgICAgICAgY29udGludWUKICAgICAgfQoKICAgICAgLy8gdXJsIChnZm0pCiAgICAgIGlmICghdGhpcy5zdGF0ZS5pbkxpbmsgJiYgKHRva2VuID0gdGhpcy50b2tlbml6ZXIudXJsKHNyYywgbWFuZ2xlKSkpIHsKICAgICAgICBzcmMgPSBzcmMuc3Vic3RyaW5nKHRva2VuLnJhdy5sZW5ndGgpCiAgICAgICAgdG9rZW5zLnB1c2godG9rZW4pCiAgICAgICAgY29udGludWUKICAgICAgfQoKICAgICAgLy8gdGV4dAogICAgICAvLyBwcmV2ZW50IGlubGluZVRleHQgY29uc3VtaW5nIGV4dGVuc2lvbnMgYnkgY2xpcHBpbmcgJ3NyYycgdG8gZXh0ZW5zaW9uIHN0YXJ0CiAgICAgIGN1dFNyYyA9IHNyYwogICAgICBpZiAodGhpcy5vcHRpb25zLmV4dGVuc2lvbnMgJiYgdGhpcy5vcHRpb25zLmV4dGVuc2lvbnMuc3RhcnRJbmxpbmUpIHsKICAgICAgICBsZXQgc3RhcnRJbmRleCA9IEluZmluaXR5CiAgICAgICAgY29uc3QgdGVtcFNyYyA9IHNyYy5zbGljZSgxKQogICAgICAgIGxldCB0ZW1wU3RhcnQKICAgICAgICB0aGlzLm9wdGlvbnMuZXh0ZW5zaW9ucy5zdGFydElubGluZS5mb3JFYWNoKGZ1bmN0aW9uIChnZXRTdGFydEluZGV4KSB7CiAgICAgICAgICB0ZW1wU3RhcnQgPSBnZXRTdGFydEluZGV4LmNhbGwoeyBsZXhlcjogdGhpcyB9LCB0ZW1wU3JjKQogICAgICAgICAgaWYgKHR5cGVvZiB0ZW1wU3RhcnQgPT09ICJudW1iZXIiICYmIHRlbXBTdGFydCA+PSAwKSB7CiAgICAgICAgICAgIHN0YXJ0SW5kZXggPSBNYXRoLm1pbihzdGFydEluZGV4LCB0ZW1wU3RhcnQpCiAgICAgICAgICB9CiAgICAgICAgfSkKICAgICAgICBpZiAoc3RhcnRJbmRleCA8IEluZmluaXR5ICYmIHN0YXJ0SW5kZXggPj0gMCkgewogICAgICAgICAgY3V0U3JjID0gc3JjLnN1YnN0cmluZygwLCBzdGFydEluZGV4ICsgMSkKICAgICAgICB9CiAgICAgIH0KICAgICAgaWYgKCh0b2tlbiA9IHRoaXMudG9rZW5pemVyLmlubGluZVRleHQoY3V0U3JjLCBzbWFydHlwYW50cykpKSB7CiAgICAgICAgc3JjID0gc3JjLnN1YnN0cmluZyh0b2tlbi5yYXcubGVuZ3RoKQogICAgICAgIGlmICh0b2tlbi5yYXcuc2xpY2UoLTEpICE9PSAiXyIpIHsKICAgICAgICAgIC8vIFRyYWNrIHByZXZDaGFyIGJlZm9yZSBzdHJpbmcgb2YgX19fXyBzdGFydGVkCiAgICAgICAgICBwcmV2Q2hhciA9IHRva2VuLnJhdy5zbGljZSgtMSkKICAgICAgICB9CiAgICAgICAga2VlcFByZXZDaGFyID0gdHJ1ZQogICAgICAgIGxhc3RUb2tlbiA9IHRva2Vuc1t0b2tlbnMubGVuZ3RoIC0gMV0KICAgICAgICBpZiAobGFzdFRva2VuICYmIGxhc3RUb2tlbi50eXBlID09PSAidGV4dCIpIHsKICAgICAgICAgIGxhc3RUb2tlbi5yYXcgKz0gdG9rZW4ucmF3CiAgICAgICAgICBsYXN0VG9rZW4udGV4dCArPSB0b2tlbi50ZXh0CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIHRva2Vucy5wdXNoKHRva2VuKQogICAgICAgIH0KICAgICAgICBjb250aW51ZQogICAgICB9CgogICAgICBpZiAoc3JjKSB7CiAgICAgICAgY29uc3QgZXJyTXNnID0gIkluZmluaXRlIGxvb3Agb24gYnl0ZTogIiArIHNyYy5jaGFyQ29kZUF0KDApCiAgICAgICAgaWYgKHRoaXMub3B0aW9ucy5zaWxlbnQpIHsKICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyTXNnKQogICAgICAgICAgYnJlYWsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGVyck1zZykKICAgICAgICB9CiAgICAgIH0KICAgIH0KCiAgICByZXR1cm4gdG9rZW5zCiAgfQp9CgovKioKICogUmVuZGVyZXIKICovCmNsYXNzIFJlbmRlcmVyIHsKICBjb25zdHJ1Y3RvcihvcHRpb25zKSB7CiAgICB0aGlzLm9wdGlvbnMgPSBvcHRpb25zIHx8IGRlZmF1bHRzCiAgfQoKICBjb2RlKGNvZGUsIGluZm9zdHJpbmcsIGVzY2FwZWQpIHsKICAgIGNvbnN0IGxhbmcgPSAoaW5mb3N0cmluZyB8fCAiIikubWF0Y2goL1xTKi8pWzBdCiAgICBpZiAodGhpcy5vcHRpb25zLmhpZ2hsaWdodCkgewogICAgICBjb25zdCBvdXQgPSB0aGlzLm9wdGlvbnMuaGlnaGxpZ2h0KGNvZGUsIGxhbmcpCiAgICAgIGlmIChvdXQgIT0gbnVsbCAmJiBvdXQgIT09IGNvZGUpIHsKICAgICAgICBlc2NhcGVkID0gdHJ1ZQogICAgICAgIGNvZGUgPSBvdXQKICAgICAgfQogICAgfQoKICAgIGNvZGUgPSBjb2RlLnJlcGxhY2UoL1xuJC8sICIiKSArICJcbiIKCiAgICBpZiAoIWxhbmcpIHsKICAgICAgcmV0dXJuICgKICAgICAgICAiPHByZT48Y29kZT4iICsKICAgICAgICAoZXNjYXBlZCA/IGNvZGUgOiBlc2NhcGUoY29kZSwgdHJ1ZSkpICsKICAgICAgICAiPC9jb2RlPjwvcHJlPlxuIgogICAgICApCiAgICB9CgogICAgcmV0dXJuICgKICAgICAgJzxwcmU+PGNvZGUgY2xhc3M9IicgKwogICAgICB0aGlzLm9wdGlvbnMubGFuZ1ByZWZpeCArCiAgICAgIGVzY2FwZShsYW5nLCB0cnVlKSArCiAgICAgICciPicgKwogICAgICAoZXNjYXBlZCA/IGNvZGUgOiBlc2NhcGUoY29kZSwgdHJ1ZSkpICsKICAgICAgIjwvY29kZT48L3ByZT5cbiIKICAgICkKICB9CgogIC8qKgogICAqIEBwYXJhbSB7c3RyaW5nfSBxdW90ZQogICAqLwogIGJsb2NrcXVvdGUocXVvdGUpIHsKICAgIHJldHVybiBgPGJsb2NrcXVvdGU+XG4ke3F1b3RlfTwvYmxvY2txdW90ZT5cbmAKICB9CgogIGh0bWwoaHRtbCkgewogICAgcmV0dXJuIGh0bWwKICB9CgogIC8qKgogICAqIEBwYXJhbSB7c3RyaW5nfSB0ZXh0CiAgICogQHBhcmFtIHtzdHJpbmd9IGxldmVsCiAgICogQHBhcmFtIHtzdHJpbmd9IHJhdwogICAqIEBwYXJhbSB7YW55fSBzbHVnZ2VyCiAgICovCiAgaGVhZGluZyh0ZXh0LCBsZXZlbCwgcmF3LCBzbHVnZ2VyKSB7CiAgICBpZiAodGhpcy5vcHRpb25zLmhlYWRlcklkcykgewogICAgICBjb25zdCBpZCA9IHRoaXMub3B0aW9ucy5oZWFkZXJQcmVmaXggKyBzbHVnZ2VyLnNsdWcocmF3KQogICAgICByZXR1cm4gYDxoJHtsZXZlbH0gaWQ9IiR7aWR9Ij4ke3RleHR9PC9oJHtsZXZlbH0+XG5gCiAgICB9CgogICAgLy8gaWdub3JlIElEcwogICAgcmV0dXJuIGA8aCR7bGV2ZWx9PiR7dGV4dH08L2gke2xldmVsfT5cbmAKICB9CgogIGhyKCkgewogICAgcmV0dXJuIHRoaXMub3B0aW9ucy54aHRtbCA/ICI8aHIvPlxuIiA6ICI8aHI+XG4iCiAgfQoKICBsaXN0KGJvZHksIG9yZGVyZWQsIHN0YXJ0KSB7CiAgICBjb25zdCB0eXBlID0gb3JkZXJlZCA/ICJvbCIgOiAidWwiLAogICAgICBzdGFydGF0dCA9IG9yZGVyZWQgJiYgc3RhcnQgIT09IDEgPyAnIHN0YXJ0PSInICsgc3RhcnQgKyAnIicgOiAiIgogICAgcmV0dXJuICI8IiArIHR5cGUgKyBzdGFydGF0dCArICI+XG4iICsgYm9keSArICI8LyIgKyB0eXBlICsgIj5cbiIKICB9CgogIC8qKgogICAqIEBwYXJhbSB7c3RyaW5nfSB0ZXh0CiAgICovCiAgbGlzdGl0ZW0odGV4dCkgewogICAgcmV0dXJuIGA8bGk+JHt0ZXh0fTwvbGk+XG5gCiAgfQoKICBjaGVja2JveChjaGVja2VkKSB7CiAgICByZXR1cm4gKAogICAgICAiPGlucHV0ICIgKwogICAgICAoY2hlY2tlZCA/ICdjaGVja2VkPSIiICcgOiAiIikgKwogICAgICAnZGlzYWJsZWQ9IiIgdHlwZT0iY2hlY2tib3giJyArCiAgICAgICh0aGlzLm9wdGlvbnMueGh0bWwgPyAiIC8iIDogIiIpICsKICAgICAgIj4gIgogICAgKQogIH0KCiAgLyoqCiAgICogQHBhcmFtIHtzdHJpbmd9IHRleHQKICAgKi8KICBwYXJhZ3JhcGgodGV4dCkgewogICAgcmV0dXJuIGA8cD4ke3RleHR9PC9wPlxuYAogIH0KCiAgLyoqCiAgICogQHBhcmFtIHtzdHJpbmd9IGhlYWRlcgogICAqIEBwYXJhbSB7c3RyaW5nfSBib2R5CiAgICovCiAgdGFibGUoaGVhZGVyLCBib2R5KSB7CiAgICBpZiAoYm9keSkgYm9keSA9IGA8dGJvZHk+JHtib2R5fTwvdGJvZHk+YAoKICAgIHJldHVybiAoCiAgICAgICI8dGFibGU+XG4iICsgIjx0aGVhZD5cbiIgKyBoZWFkZXIgKyAiPC90aGVhZD5cbiIgKyBib2R5ICsgIjwvdGFibGU+XG4iCiAgICApCiAgfQoKICAvKioKICAgKiBAcGFyYW0ge3N0cmluZ30gY29udGVudAogICAqLwogIHRhYmxlcm93KGNvbnRlbnQpIHsKICAgIHJldHVybiBgPHRyPlxuJHtjb250ZW50fTwvdHI+XG5gCiAgfQoKICB0YWJsZWNlbGwoY29udGVudCwgZmxhZ3MpIHsKICAgIGNvbnN0IHR5cGUgPSBmbGFncy5oZWFkZXIgPyAidGgiIDogInRkIgogICAgY29uc3QgdGFnID0gZmxhZ3MuYWxpZ24gPyBgPCR7dHlwZX0gYWxpZ249IiR7ZmxhZ3MuYWxpZ259Ij5gIDogYDwke3R5cGV9PmAKICAgIHJldHVybiB0YWcgKyBjb250ZW50ICsgYDwvJHt0eXBlfT5cbmAKICB9CgogIC8qKgogICAqIHNwYW4gbGV2ZWwgcmVuZGVyZXIKICAgKiBAcGFyYW0ge3N0cmluZ30gdGV4dAogICAqLwogIHN0cm9uZyh0ZXh0KSB7CiAgICByZXR1cm4gYDxzdHJvbmc+JHt0ZXh0fTwvc3Ryb25nPmAKICB9CgogIC8qKgogICAqIEBwYXJhbSB7c3RyaW5nfSB0ZXh0CiAgICovCiAgZW0odGV4dCkgewogICAgcmV0dXJuIGA8ZW0+JHt0ZXh0fTwvZW0+YAogIH0KCiAgLyoqCiAgICogQHBhcmFtIHtzdHJpbmd9IHRleHQKICAgKi8KICBjb2Rlc3Bhbih0ZXh0KSB7CiAgICByZXR1cm4gYDxjb2RlPiR7dGV4dH08L2NvZGU+YAogIH0KCiAgYnIoKSB7CiAgICByZXR1cm4gdGhpcy5vcHRpb25zLnhodG1sID8gIjxici8+IiA6ICI8YnI+IgogIH0KCiAgLyoqCiAgICogQHBhcmFtIHtzdHJpbmd9IHRleHQKICAgKi8KICBkZWwodGV4dCkgewogICAgcmV0dXJuIGA8ZGVsPiR7dGV4dH08L2RlbD5gCiAgfQoKICAvKioKICAgKiBAcGFyYW0ge3N0cmluZ30gaHJlZgogICAqIEBwYXJhbSB7c3RyaW5nfSB0aXRsZQogICAqIEBwYXJhbSB7c3RyaW5nfSB0ZXh0CiAgICovCiAgbGluayhocmVmLCB0aXRsZSwgdGV4dCkgewogICAgaHJlZiA9IGNsZWFuVXJsKHRoaXMub3B0aW9ucy5zYW5pdGl6ZSwgdGhpcy5vcHRpb25zLmJhc2VVcmwsIGhyZWYpCiAgICBpZiAoaHJlZiA9PT0gbnVsbCkgewogICAgICByZXR1cm4gdGV4dAogICAgfQogICAgbGV0IG91dCA9ICc8YSBocmVmPSInICsgZXNjYXBlKGhyZWYpICsgJyInCiAgICBpZiAodGl0bGUpIHsKICAgICAgb3V0ICs9ICcgdGl0bGU9IicgKyB0aXRsZSArICciJwogICAgfQogICAgb3V0ICs9ICI+IiArIHRleHQgKyAiPC9hPiIKICAgIHJldHVybiBvdXQKICB9CgogIC8qKgogICAqIEBwYXJhbSB7c3RyaW5nfSBocmVmCiAgICogQHBhcmFtIHtzdHJpbmd9IHRpdGxlCiAgICogQHBhcmFtIHtzdHJpbmd9IHRleHQKICAgKi8KICBpbWFnZShocmVmLCB0aXRsZSwgdGV4dCkgewogICAgaHJlZiA9IGNsZWFuVXJsKHRoaXMub3B0aW9ucy5zYW5pdGl6ZSwgdGhpcy5vcHRpb25zLmJhc2VVcmwsIGhyZWYpCiAgICBpZiAoaHJlZiA9PT0gbnVsbCkgewogICAgICByZXR1cm4gdGV4dAogICAgfQoKICAgIGxldCBvdXQgPSBgPGltZyBzcmM9IiR7aHJlZn0iIGFsdD0iJHt0ZXh0fSJgCiAgICBpZiAodGl0bGUpIHsKICAgICAgb3V0ICs9IGAgdGl0bGU9IiR7dGl0bGV9ImAKICAgIH0KICAgIG91dCArPSB0aGlzLm9wdGlvbnMueGh0bWwgPyAiLz4iIDogIj4iCiAgICByZXR1cm4gb3V0CiAgfQoKICB0ZXh0KHRleHQpIHsKICAgIHJldHVybiB0ZXh0CiAgfQp9CgovKioKICogVGV4dFJlbmRlcmVyCiAqIHJldHVybnMgb25seSB0aGUgdGV4dHVhbCBwYXJ0IG9mIHRoZSB0b2tlbgogKi8KY2xhc3MgVGV4dFJlbmRlcmVyIHsKICAvLyBubyBuZWVkIGZvciBibG9jayBsZXZlbCByZW5kZXJlcnMKICBzdHJvbmcodGV4dCkgewogICAgcmV0dXJuIHRleHQKICB9CgogIGVtKHRleHQpIHsKICAgIHJldHVybiB0ZXh0CiAgfQoKICBjb2Rlc3Bhbih0ZXh0KSB7CiAgICByZXR1cm4gdGV4dAogIH0KCiAgZGVsKHRleHQpIHsKICAgIHJldHVybiB0ZXh0CiAgfQoKICBodG1sKHRleHQpIHsKICAgIHJldHVybiB0ZXh0CiAgfQoKICB0ZXh0KHRleHQpIHsKICAgIHJldHVybiB0ZXh0CiAgfQoKICBsaW5rKGhyZWYsIHRpdGxlLCB0ZXh0KSB7CiAgICByZXR1cm4gIiIgKyB0ZXh0CiAgfQoKICBpbWFnZShocmVmLCB0aXRsZSwgdGV4dCkgewogICAgcmV0dXJuICIiICsgdGV4dAogIH0KCiAgYnIoKSB7CiAgICByZXR1cm4gIiIKICB9Cn0KCi8qKgogKiBTbHVnZ2VyIGdlbmVyYXRlcyBoZWFkZXIgaWQKICovCmNsYXNzIFNsdWdnZXIgewogIGNvbnN0cnVjdG9yKCkgewogICAgdGhpcy5zZWVuID0ge30KICB9CgogIC8qKgogICAqIEBwYXJhbSB7c3RyaW5nfSB2YWx1ZQogICAqLwogIHNlcmlhbGl6ZSh2YWx1ZSkgewogICAgcmV0dXJuICgKICAgICAgdmFsdWUKICAgICAgICAudG9Mb3dlckNhc2UoKQogICAgICAgIC50cmltKCkKICAgICAgICAvLyByZW1vdmUgaHRtbCB0YWdzCiAgICAgICAgLnJlcGxhY2UoLzxbIVwvYS16XS4qPz4vZ2ksICIiKQogICAgICAgIC8vIHJlbW92ZSB1bndhbnRlZCBjaGFycwogICAgICAgIC5yZXBsYWNlKAogICAgICAgICAgL1tcdTIwMDAtXHUyMDZGXHUyRTAwLVx1MkU3RlxcJyEiIyQlJigpKissLi86Ozw9Pj9AW1xdXmB7fH1+XS9nLAogICAgICAgICAgIiIKICAgICAgICApCiAgICAgICAgLnJlcGxhY2UoL1xzL2csICItIikKICAgICkKICB9CgogIC8qKgogICAqIEZpbmRzIHRoZSBuZXh0IHNhZmUgKHVuaXF1ZSkgc2x1ZyB0byB1c2UKICAgKiBAcGFyYW0ge3N0cmluZ30gb3JpZ2luYWxTbHVnCiAgICogQHBhcmFtIHtib29sZWFufSBpc0RyeVJ1bgogICAqLwogIGdldE5leHRTYWZlU2x1ZyhvcmlnaW5hbFNsdWcsIGlzRHJ5UnVuKSB7CiAgICBsZXQgc2x1ZyA9IG9yaWdpbmFsU2x1ZwogICAgbGV0IG9jY3VyZW5jZUFjY3VtdWxhdG9yID0gMAogICAgaWYgKHRoaXMuc2Vlbi5oYXNPd25Qcm9wZXJ0eShzbHVnKSkgewogICAgICBvY2N1cmVuY2VBY2N1bXVsYXRvciA9IHRoaXMuc2VlbltvcmlnaW5hbFNsdWddCiAgICAgIGRvIHsKICAgICAgICBvY2N1cmVuY2VBY2N1bXVsYXRvcisrCiAgICAgICAgc2x1ZyA9IG9yaWdpbmFsU2x1ZyArICItIiArIG9jY3VyZW5jZUFjY3VtdWxhdG9yCiAgICAgIH0gd2hpbGUgKHRoaXMuc2Vlbi5oYXNPd25Qcm9wZXJ0eShzbHVnKSkKICAgIH0KICAgIGlmICghaXNEcnlSdW4pIHsKICAgICAgdGhpcy5zZWVuW29yaWdpbmFsU2x1Z10gPSBvY2N1cmVuY2VBY2N1bXVsYXRvcgogICAgICB0aGlzLnNlZW5bc2x1Z10gPSAwCiAgICB9CiAgICByZXR1cm4gc2x1ZwogIH0KCiAgLyoqCiAgICogQ29udmVydCBzdHJpbmcgdG8gdW5pcXVlIGlkCiAgICogQHBhcmFtIHtvYmplY3R9IFtvcHRpb25zXQogICAqIEBwYXJhbSB7Ym9vbGVhbn0gW29wdGlvbnMuZHJ5cnVuXSBHZW5lcmF0ZXMgdGhlIG5leHQgdW5pcXVlIHNsdWcgd2l0aG91dAogICAqIHVwZGF0aW5nIHRoZSBpbnRlcm5hbCBhY2N1bXVsYXRvci4KICAgKi8KICBzbHVnKHZhbHVlLCBvcHRpb25zID0ge30pIHsKICAgIGNvbnN0IHNsdWcgPSB0aGlzLnNlcmlhbGl6ZSh2YWx1ZSkKICAgIHJldHVybiB0aGlzLmdldE5leHRTYWZlU2x1ZyhzbHVnLCBvcHRpb25zLmRyeXJ1bikKICB9Cn0KCi8qKgogKiBQYXJzaW5nICYgQ29tcGlsaW5nCiAqLwpjbGFzcyBQYXJzZXIgewogIGNvbnN0cnVjdG9yKG9wdGlvbnMpIHsKICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnMgfHwgZGVmYXVsdHMKICAgIHRoaXMub3B0aW9ucy5yZW5kZXJlciA9IHRoaXMub3B0aW9ucy5yZW5kZXJlciB8fCBuZXcgUmVuZGVyZXIoKQogICAgdGhpcy5yZW5kZXJlciA9IHRoaXMub3B0aW9ucy5yZW5kZXJlcgogICAgdGhpcy5yZW5kZXJlci5vcHRpb25zID0gdGhpcy5vcHRpb25zCiAgICB0aGlzLnRleHRSZW5kZXJlciA9IG5ldyBUZXh0UmVuZGVyZXIoKQogICAgdGhpcy5zbHVnZ2VyID0gbmV3IFNsdWdnZXIoKQogIH0KCiAgLyoqCiAgICogU3RhdGljIFBhcnNlIE1ldGhvZAogICAqLwogIHN0YXRpYyBwYXJzZSh0b2tlbnMsIG9wdGlvbnMpIHsKICAgIGNvbnN0IHBhcnNlciA9IG5ldyBQYXJzZXIob3B0aW9ucykKICAgIHJldHVybiBwYXJzZXIucGFyc2UodG9rZW5zKQogIH0KCiAgLyoqCiAgICogU3RhdGljIFBhcnNlIElubGluZSBNZXRob2QKICAgKi8KICBzdGF0aWMgcGFyc2VJbmxpbmUodG9rZW5zLCBvcHRpb25zKSB7CiAgICBjb25zdCBwYXJzZXIgPSBuZXcgUGFyc2VyKG9wdGlvbnMpCiAgICByZXR1cm4gcGFyc2VyLnBhcnNlSW5saW5lKHRva2VucykKICB9CgogIC8qKgogICAqIFBhcnNlIExvb3AKICAgKi8KICBwYXJzZSh0b2tlbnMsIHRvcCA9IHRydWUpIHsKICAgIGxldCBvdXQgPSAiIiwKICAgICAgaSwKICAgICAgaiwKICAgICAgaywKICAgICAgbDIsCiAgICAgIGwzLAogICAgICByb3csCiAgICAgIGNlbGwsCiAgICAgIGhlYWRlciwKICAgICAgYm9keSwKICAgICAgdG9rZW4sCiAgICAgIG9yZGVyZWQsCiAgICAgIHN0YXJ0LAogICAgICBsb29zZSwKICAgICAgaXRlbUJvZHksCiAgICAgIGl0ZW0sCiAgICAgIGNoZWNrZWQsCiAgICAgIHRhc2ssCiAgICAgIGNoZWNrYm94LAogICAgICByZXQKCiAgICBjb25zdCBsID0gdG9rZW5zLmxlbmd0aAogICAgZm9yIChpID0gMDsgaSA8IGw7IGkrKykgewogICAgICB0b2tlbiA9IHRva2Vuc1tpXQoKICAgICAgLy8gUnVuIGFueSByZW5kZXJlciBleHRlbnNpb25zCiAgICAgIGlmICgKICAgICAgICB0aGlzLm9wdGlvbnMuZXh0ZW5zaW9ucyAmJgogICAgICAgIHRoaXMub3B0aW9ucy5leHRlbnNpb25zLnJlbmRlcmVycyAmJgogICAgICAgIHRoaXMub3B0aW9ucy5leHRlbnNpb25zLnJlbmRlcmVyc1t0b2tlbi50eXBlXQogICAgICApIHsKICAgICAgICByZXQgPSB0aGlzLm9wdGlvbnMuZXh0ZW5zaW9ucy5yZW5kZXJlcnNbdG9rZW4udHlwZV0uY2FsbCgKICAgICAgICAgIHsgcGFyc2VyOiB0aGlzIH0sCiAgICAgICAgICB0b2tlbgogICAgICAgICkKICAgICAgICBpZiAoCiAgICAgICAgICByZXQgIT09IGZhbHNlIHx8CiAgICAgICAgICAhWwogICAgICAgICAgICAic3BhY2UiLAogICAgICAgICAgICAiaHIiLAogICAgICAgICAgICAiaGVhZGluZyIsCiAgICAgICAgICAgICJjb2RlIiwKICAgICAgICAgICAgInRhYmxlIiwKICAgICAgICAgICAgImJsb2NrcXVvdGUiLAogICAgICAgICAgICAibGlzdCIsCiAgICAgICAgICAgICJodG1sIiwKICAgICAgICAgICAgInBhcmFncmFwaCIsCiAgICAgICAgICAgICJ0ZXh0IiwKICAgICAgICAgIF0uaW5jbHVkZXModG9rZW4udHlwZSkKICAgICAgICApIHsKICAgICAgICAgIG91dCArPSByZXQgfHwgIiIKICAgICAgICAgIGNvbnRpbnVlCiAgICAgICAgfQogICAgICB9CgogICAgICBzd2l0Y2ggKHRva2VuLnR5cGUpIHsKICAgICAgICBjYXNlICJzcGFjZSI6IHsKICAgICAgICAgIGNvbnRpbnVlCiAgICAgICAgfQogICAgICAgIGNhc2UgImhyIjogewogICAgICAgICAgb3V0ICs9IHRoaXMucmVuZGVyZXIuaHIoKQogICAgICAgICAgY29udGludWUKICAgICAgICB9CiAgICAgICAgY2FzZSAiaGVhZGluZyI6IHsKICAgICAgICAgIG91dCArPSB0aGlzLnJlbmRlcmVyLmhlYWRpbmcoCiAgICAgICAgICAgIHRoaXMucGFyc2VJbmxpbmUodG9rZW4udG9rZW5zKSwKICAgICAgICAgICAgdG9rZW4uZGVwdGgsCiAgICAgICAgICAgIHVuZXNjYXBlKHRoaXMucGFyc2VJbmxpbmUodG9rZW4udG9rZW5zLCB0aGlzLnRleHRSZW5kZXJlcikpLAogICAgICAgICAgICB0aGlzLnNsdWdnZXIKICAgICAgICAgICkKICAgICAgICAgIGNvbnRpbnVlCiAgICAgICAgfQogICAgICAgIGNhc2UgImNvZGUiOiB7CiAgICAgICAgICBvdXQgKz0gdGhpcy5yZW5kZXJlci5jb2RlKHRva2VuLnRleHQsIHRva2VuLmxhbmcsIHRva2VuLmVzY2FwZWQpCiAgICAgICAgICBjb250aW51ZQogICAgICAgIH0KICAgICAgICBjYXNlICJ0YWJsZSI6IHsKICAgICAgICAgIGhlYWRlciA9ICIiCgogICAgICAgICAgLy8gaGVhZGVyCiAgICAgICAgICBjZWxsID0gIiIKICAgICAgICAgIGwyID0gdG9rZW4uaGVhZGVyLmxlbmd0aAogICAgICAgICAgZm9yIChqID0gMDsgaiA8IGwyOyBqKyspIHsKICAgICAgICAgICAgY2VsbCArPSB0aGlzLnJlbmRlcmVyLnRhYmxlY2VsbCgKICAgICAgICAgICAgICB0aGlzLnBhcnNlSW5saW5lKHRva2VuLmhlYWRlcltqXS50b2tlbnMpLAogICAgICAgICAgICAgIHsgaGVhZGVyOiB0cnVlLCBhbGlnbjogdG9rZW4uYWxpZ25bal0gfQogICAgICAgICAgICApCiAgICAgICAgICB9CiAgICAgICAgICBoZWFkZXIgKz0gdGhpcy5yZW5kZXJlci50YWJsZXJvdyhjZWxsKQoKICAgICAgICAgIGJvZHkgPSAiIgogICAgICAgICAgbDIgPSB0b2tlbi5yb3dzLmxlbmd0aAogICAgICAgICAgZm9yIChqID0gMDsgaiA8IGwyOyBqKyspIHsKICAgICAgICAgICAgcm93ID0gdG9rZW4ucm93c1tqXQoKICAgICAgICAgICAgY2VsbCA9ICIiCiAgICAgICAgICAgIGwzID0gcm93Lmxlbmd0aAogICAgICAgICAgICBmb3IgKGsgPSAwOyBrIDwgbDM7IGsrKykgewogICAgICAgICAgICAgIGNlbGwgKz0gdGhpcy5yZW5kZXJlci50YWJsZWNlbGwodGhpcy5wYXJzZUlubGluZShyb3dba10udG9rZW5zKSwgewogICAgICAgICAgICAgICAgaGVhZGVyOiBmYWxzZSwKICAgICAgICAgICAgICAgIGFsaWduOiB0b2tlbi5hbGlnbltrXSwKICAgICAgICAgICAgICB9KQogICAgICAgICAgICB9CgogICAgICAgICAgICBib2R5ICs9IHRoaXMucmVuZGVyZXIudGFibGVyb3coY2VsbCkKICAgICAgICAgIH0KICAgICAgICAgIG91dCArPSB0aGlzLnJlbmRlcmVyLnRhYmxlKGhlYWRlciwgYm9keSkKICAgICAgICAgIGNvbnRpbnVlCiAgICAgICAgfQogICAgICAgIGNhc2UgImJsb2NrcXVvdGUiOiB7CiAgICAgICAgICBib2R5ID0gdGhpcy5wYXJzZSh0b2tlbi50b2tlbnMpCiAgICAgICAgICBvdXQgKz0gdGhpcy5yZW5kZXJlci5ibG9ja3F1b3RlKGJvZHkpCiAgICAgICAgICBjb250aW51ZQogICAgICAgIH0KICAgICAgICBjYXNlICJsaXN0IjogewogICAgICAgICAgb3JkZXJlZCA9IHRva2VuLm9yZGVyZWQKICAgICAgICAgIHN0YXJ0ID0gdG9rZW4uc3RhcnQKICAgICAgICAgIGxvb3NlID0gdG9rZW4ubG9vc2UKICAgICAgICAgIGwyID0gdG9rZW4uaXRlbXMubGVuZ3RoCgogICAgICAgICAgYm9keSA9ICIiCiAgICAgICAgICBmb3IgKGogPSAwOyBqIDwgbDI7IGorKykgewogICAgICAgICAgICBpdGVtID0gdG9rZW4uaXRlbXNbal0KICAgICAgICAgICAgY2hlY2tlZCA9IGl0ZW0uY2hlY2tlZAogICAgICAgICAgICB0YXNrID0gaXRlbS50YXNrCgogICAgICAgICAgICBpdGVtQm9keSA9ICIiCiAgICAgICAgICAgIGlmIChpdGVtLnRhc2spIHsKICAgICAgICAgICAgICBjaGVja2JveCA9IHRoaXMucmVuZGVyZXIuY2hlY2tib3goY2hlY2tlZCkKICAgICAgICAgICAgICBpZiAobG9vc2UpIHsKICAgICAgICAgICAgICAgIGlmICgKICAgICAgICAgICAgICAgICAgaXRlbS50b2tlbnMubGVuZ3RoID4gMCAmJgogICAgICAgICAgICAgICAgICBpdGVtLnRva2Vuc1swXS50eXBlID09PSAicGFyYWdyYXBoIgogICAgICAgICAgICAgICAgKSB7CiAgICAgICAgICAgICAgICAgIGl0ZW0udG9rZW5zWzBdLnRleHQgPSBjaGVja2JveCArICIgIiArIGl0ZW0udG9rZW5zWzBdLnRleHQKICAgICAgICAgICAgICAgICAgaWYgKAogICAgICAgICAgICAgICAgICAgIGl0ZW0udG9rZW5zWzBdLnRva2VucyAmJgogICAgICAgICAgICAgICAgICAgIGl0ZW0udG9rZW5zWzBdLnRva2Vucy5sZW5ndGggPiAwICYmCiAgICAgICAgICAgICAgICAgICAgaXRlbS50b2tlbnNbMF0udG9rZW5zWzBdLnR5cGUgPT09ICJ0ZXh0IgogICAgICAgICAgICAgICAgICApIHsKICAgICAgICAgICAgICAgICAgICBpdGVtLnRva2Vuc1swXS50b2tlbnNbMF0udGV4dCA9CiAgICAgICAgICAgICAgICAgICAgICBjaGVja2JveCArICIgIiArIGl0ZW0udG9rZW5zWzBdLnRva2Vuc1swXS50ZXh0CiAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgIGl0ZW0udG9rZW5zLnVuc2hpZnQoewogICAgICAgICAgICAgICAgICAgIHR5cGU6ICJ0ZXh0IiwKICAgICAgICAgICAgICAgICAgICB0ZXh0OiBjaGVja2JveCwKICAgICAgICAgICAgICAgICAgfSkKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgaXRlbUJvZHkgKz0gY2hlY2tib3gKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGl0ZW1Cb2R5ICs9IHRoaXMucGFyc2UoaXRlbS50b2tlbnMsIGxvb3NlKQogICAgICAgICAgICBib2R5ICs9IHRoaXMucmVuZGVyZXIubGlzdGl0ZW0oaXRlbUJvZHksIHRhc2ssIGNoZWNrZWQpCiAgICAgICAgICB9CgogICAgICAgICAgb3V0ICs9IHRoaXMucmVuZGVyZXIubGlzdChib2R5LCBvcmRlcmVkLCBzdGFydCkKICAgICAgICAgIGNvbnRpbnVlCiAgICAgICAgfQogICAgICAgIGNhc2UgImh0bWwiOiB7CiAgICAgICAgICAvLyBUT0RPIHBhcnNlIGlubGluZSBjb250ZW50IGlmIHBhcmFtZXRlciBtYXJrZG93bj0xCiAgICAgICAgICBvdXQgKz0gdGhpcy5yZW5kZXJlci5odG1sKHRva2VuLnRleHQpCiAgICAgICAgICBjb250aW51ZQogICAgICAgIH0KICAgICAgICBjYXNlICJwYXJhZ3JhcGgiOiB7CiAgICAgICAgICBvdXQgKz0gdGhpcy5yZW5kZXJlci5wYXJhZ3JhcGgodGhpcy5wYXJzZUlubGluZSh0b2tlbi50b2tlbnMpKQogICAgICAgICAgY29udGludWUKICAgICAgICB9CiAgICAgICAgY2FzZSAidGV4dCI6IHsKICAgICAgICAgIGJvZHkgPSB0b2tlbi50b2tlbnMgPyB0aGlzLnBhcnNlSW5saW5lKHRva2VuLnRva2VucykgOiB0b2tlbi50ZXh0CiAgICAgICAgICB3aGlsZSAoaSArIDEgPCBsICYmIHRva2Vuc1tpICsgMV0udHlwZSA9PT0gInRleHQiKSB7CiAgICAgICAgICAgIHRva2VuID0gdG9rZW5zWysraV0KICAgICAgICAgICAgYm9keSArPQogICAgICAgICAgICAgICJcbiIgKwogICAgICAgICAgICAgICh0b2tlbi50b2tlbnMgPyB0aGlzLnBhcnNlSW5saW5lKHRva2VuLnRva2VucykgOiB0b2tlbi50ZXh0KQogICAgICAgICAgfQogICAgICAgICAgb3V0ICs9IHRvcCA/IHRoaXMucmVuZGVyZXIucGFyYWdyYXBoKGJvZHkpIDogYm9keQogICAgICAgICAgY29udGludWUKICAgICAgICB9CgogICAgICAgIGRlZmF1bHQ6IHsKICAgICAgICAgIGNvbnN0IGVyck1zZyA9ICdUb2tlbiB3aXRoICInICsgdG9rZW4udHlwZSArICciIHR5cGUgd2FzIG5vdCBmb3VuZC4nCiAgICAgICAgICBpZiAodGhpcy5vcHRpb25zLnNpbGVudCkgewogICAgICAgICAgICBjb25zb2xlLmVycm9yKGVyck1zZykKICAgICAgICAgICAgcmV0dXJuCiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoZXJyTXNnKQogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfQogICAgfQoKICAgIHJldHVybiBvdXQKICB9CgogIC8qKgogICAqIFBhcnNlIElubGluZSBUb2tlbnMKICAgKi8KICBwYXJzZUlubGluZSh0b2tlbnMsIHJlbmRlcmVyKSB7CiAgICByZW5kZXJlciA9IHJlbmRlcmVyIHx8IHRoaXMucmVuZGVyZXIKICAgIGxldCBvdXQgPSAiIiwKICAgICAgaSwKICAgICAgdG9rZW4sCiAgICAgIHJldAoKICAgIGNvbnN0IGwgPSB0b2tlbnMubGVuZ3RoCiAgICBmb3IgKGkgPSAwOyBpIDwgbDsgaSsrKSB7CiAgICAgIHRva2VuID0gdG9rZW5zW2ldCgogICAgICAvLyBSdW4gYW55IHJlbmRlcmVyIGV4dGVuc2lvbnMKICAgICAgaWYgKAogICAgICAgIHRoaXMub3B0aW9ucy5leHRlbnNpb25zICYmCiAgICAgICAgdGhpcy5vcHRpb25zLmV4dGVuc2lvbnMucmVuZGVyZXJzICYmCiAgICAgICAgdGhpcy5vcHRpb25zLmV4dGVuc2lvbnMucmVuZGVyZXJzW3Rva2VuLnR5cGVdCiAgICAgICkgewogICAgICAgIHJldCA9IHRoaXMub3B0aW9ucy5leHRlbnNpb25zLnJlbmRlcmVyc1t0b2tlbi50eXBlXS5jYWxsKAogICAgICAgICAgeyBwYXJzZXI6IHRoaXMgfSwKICAgICAgICAgIHRva2VuCiAgICAgICAgKQogICAgICAgIGlmICgKICAgICAgICAgIHJldCAhPT0gZmFsc2UgfHwKICAgICAgICAgICFbCiAgICAgICAgICAgICJlc2NhcGUiLAogICAgICAgICAgICAiaHRtbCIsCiAgICAgICAgICAgICJsaW5rIiwKICAgICAgICAgICAgImltYWdlIiwKICAgICAgICAgICAgInN0cm9uZyIsCiAgICAgICAgICAgICJlbSIsCiAgICAgICAgICAgICJjb2Rlc3BhbiIsCiAgICAgICAgICAgICJiciIsCiAgICAgICAgICAgICJkZWwiLAogICAgICAgICAgICAidGV4dCIsCiAgICAgICAgICBdLmluY2x1ZGVzKHRva2VuLnR5cGUpCiAgICAgICAgKSB7CiAgICAgICAgICBvdXQgKz0gcmV0IHx8ICIiCiAgICAgICAgICBjb250aW51ZQogICAgICAgIH0KICAgICAgfQoKICAgICAgc3dpdGNoICh0b2tlbi50eXBlKSB7CiAgICAgICAgY2FzZSAiZXNjYXBlIjogewogICAgICAgICAgb3V0ICs9IHJlbmRlcmVyLnRleHQodG9rZW4udGV4dCkKICAgICAgICAgIGJyZWFrCiAgICAgICAgfQogICAgICAgIGNhc2UgImh0bWwiOiB7CiAgICAgICAgICBvdXQgKz0gcmVuZGVyZXIuaHRtbCh0b2tlbi50ZXh0KQogICAgICAgICAgYnJlYWsKICAgICAgICB9CiAgICAgICAgY2FzZSAibGluayI6IHsKICAgICAgICAgIG91dCArPSByZW5kZXJlci5saW5rKAogICAgICAgICAgICB0b2tlbi5ocmVmLAogICAgICAgICAgICB0b2tlbi50aXRsZSwKICAgICAgICAgICAgdGhpcy5wYXJzZUlubGluZSh0b2tlbi50b2tlbnMsIHJlbmRlcmVyKQogICAgICAgICAgKQogICAgICAgICAgYnJlYWsKICAgICAgICB9CiAgICAgICAgY2FzZSAiaW1hZ2UiOiB7CiAgICAgICAgICBvdXQgKz0gcmVuZGVyZXIuaW1hZ2UodG9rZW4uaHJlZiwgdG9rZW4udGl0bGUsIHRva2VuLnRleHQpCiAgICAgICAgICBicmVhawogICAgICAgIH0KICAgICAgICBjYXNlICJzdHJvbmciOiB7CiAgICAgICAgICBvdXQgKz0gcmVuZGVyZXIuc3Ryb25nKHRoaXMucGFyc2VJbmxpbmUodG9rZW4udG9rZW5zLCByZW5kZXJlcikpCiAgICAgICAgICBicmVhawogICAgICAgIH0KICAgICAgICBjYXNlICJlbSI6IHsKICAgICAgICAgIG91dCArPSByZW5kZXJlci5lbSh0aGlzLnBhcnNlSW5saW5lKHRva2VuLnRva2VucywgcmVuZGVyZXIpKQogICAgICAgICAgYnJlYWsKICAgICAgICB9CiAgICAgICAgY2FzZSAiY29kZXNwYW4iOiB7CiAgICAgICAgICBvdXQgKz0gcmVuZGVyZXIuY29kZXNwYW4odG9rZW4udGV4dCkKICAgICAgICAgIGJyZWFrCiAgICAgICAgfQogICAgICAgIGNhc2UgImJyIjogewogICAgICAgICAgb3V0ICs9IHJlbmRlcmVyLmJyKCkKICAgICAgICAgIGJyZWFrCiAgICAgICAgfQogICAgICAgIGNhc2UgImRlbCI6IHsKICAgICAgICAgIG91dCArPSByZW5kZXJlci5kZWwodGhpcy5wYXJzZUlubGluZSh0b2tlbi50b2tlbnMsIHJlbmRlcmVyKSkKICAgICAgICAgIGJyZWFrCiAgICAgICAgfQogICAgICAgIGNhc2UgInRleHQiOiB7CiAgICAgICAgICBvdXQgKz0gcmVuZGVyZXIudGV4dCh0b2tlbi50ZXh0KQogICAgICAgICAgYnJlYWsKICAgICAgICB9CiAgICAgICAgZGVmYXVsdDogewogICAgICAgICAgY29uc3QgZXJyTXNnID0gJ1Rva2VuIHdpdGggIicgKyB0b2tlbi50eXBlICsgJyIgdHlwZSB3YXMgbm90IGZvdW5kLicKICAgICAgICAgIGlmICh0aGlzLm9wdGlvbnMuc2lsZW50KSB7CiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyTXNnKQogICAgICAgICAgICByZXR1cm4KICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihlcnJNc2cpCiAgICAgICAgICB9CiAgICAgICAgfQogICAgICB9CiAgICB9CiAgICByZXR1cm4gb3V0CiAgfQp9CgovKioKICogTWFya2VkCiAqLwpmdW5jdGlvbiBtYXJrZWQoc3JjLCBvcHQsIGNhbGxiYWNrKSB7CiAgLy8gdGhyb3cgZXJyb3IgaW4gY2FzZSBvZiBub24gc3RyaW5nIGlucHV0CiAgaWYgKHR5cGVvZiBzcmMgPT09ICJ1bmRlZmluZWQiIHx8IHNyYyA9PT0gbnVsbCkgewogICAgdGhyb3cgbmV3IEVycm9yKCJtYXJrZWQoKTogaW5wdXQgcGFyYW1ldGVyIGlzIHVuZGVmaW5lZCBvciBudWxsIikKICB9CiAgaWYgKHR5cGVvZiBzcmMgIT09ICJzdHJpbmciKSB7CiAgICB0aHJvdyBuZXcgRXJyb3IoCiAgICAgICJtYXJrZWQoKTogaW5wdXQgcGFyYW1ldGVyIGlzIG9mIHR5cGUgIiArCiAgICAgICAgT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKHNyYykgKwogICAgICAgICIsIHN0cmluZyBleHBlY3RlZCIKICAgICkKICB9CgogIGlmICh0eXBlb2Ygb3B0ID09PSAiZnVuY3Rpb24iKSB7CiAgICBjYWxsYmFjayA9IG9wdAogICAgb3B0ID0gbnVsbAogIH0KCiAgb3B0ID0gbWVyZ2Uoe30sIG1hcmtlZC5kZWZhdWx0cywgb3B0IHx8IHt9KQogIGNoZWNrU2FuaXRpemVEZXByZWNhdGlvbihvcHQpCgogIGlmIChjYWxsYmFjaykgewogICAgY29uc3QgaGlnaGxpZ2h0ID0gb3B0LmhpZ2hsaWdodAogICAgbGV0IHRva2VucwoKICAgIHRyeSB7CiAgICAgIHRva2VucyA9IExleGVyLmxleChzcmMsIG9wdCkKICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgcmV0dXJuIGNhbGxiYWNrKGUpCiAgICB9CgogICAgY29uc3QgZG9uZSA9IGZ1bmN0aW9uIChlcnIpIHsKICAgICAgbGV0IG91dAoKICAgICAgaWYgKCFlcnIpIHsKICAgICAgICB0cnkgewogICAgICAgICAgaWYgKG9wdC53YWxrVG9rZW5zKSB7CiAgICAgICAgICAgIG1hcmtlZC53YWxrVG9rZW5zKHRva2Vucywgb3B0LndhbGtUb2tlbnMpCiAgICAgICAgICB9CiAgICAgICAgICBvdXQgPSBQYXJzZXIucGFyc2UodG9rZW5zLCBvcHQpCiAgICAgICAgfSBjYXRjaCAoZSkgewogICAgICAgICAgZXJyID0gZQogICAgICAgIH0KICAgICAgfQoKICAgICAgb3B0LmhpZ2hsaWdodCA9IGhpZ2hsaWdodAoKICAgICAgcmV0dXJuIGVyciA/IGNhbGxiYWNrKGVycikgOiBjYWxsYmFjayhudWxsLCBvdXQpCiAgICB9CgogICAgaWYgKCFoaWdobGlnaHQgfHwgaGlnaGxpZ2h0Lmxlbmd0aCA8IDMpIHsKICAgICAgcmV0dXJuIGRvbmUoKQogICAgfQoKICAgIGRlbGV0ZSBvcHQuaGlnaGxpZ2h0CgogICAgaWYgKCF0b2tlbnMubGVuZ3RoKSByZXR1cm4gZG9uZSgpCgogICAgbGV0IHBlbmRpbmcgPSAwCiAgICBtYXJrZWQud2Fsa1Rva2Vucyh0b2tlbnMsIGZ1bmN0aW9uICh0b2tlbikgewogICAgICBpZiAodG9rZW4udHlwZSA9PT0gImNvZGUiKSB7CiAgICAgICAgcGVuZGluZysrCiAgICAgICAgc2V0VGltZW91dCgoKSA9PiB7CiAgICAgICAgICBoaWdobGlnaHQodG9rZW4udGV4dCwgdG9rZW4ubGFuZywgZnVuY3Rpb24gKGVyciwgY29kZSkgewogICAgICAgICAgICBpZiAoZXJyKSB7CiAgICAgICAgICAgICAgcmV0dXJuIGRvbmUoZXJyKQogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmIChjb2RlICE9IG51bGwgJiYgY29kZSAhPT0gdG9rZW4udGV4dCkgewogICAgICAgICAgICAgIHRva2VuLnRleHQgPSBjb2RlCiAgICAgICAgICAgICAgdG9rZW4uZXNjYXBlZCA9IHRydWUKICAgICAgICAgICAgfQoKICAgICAgICAgICAgcGVuZGluZy0tCiAgICAgICAgICAgIGlmIChwZW5kaW5nID09PSAwKSB7CiAgICAgICAgICAgICAgZG9uZSgpCiAgICAgICAgICAgIH0KICAgICAgICAgIH0pCiAgICAgICAgfSwgMCkKICAgICAgfQogICAgfSkKCiAgICBpZiAocGVuZGluZyA9PT0gMCkgewogICAgICBkb25lKCkKICAgIH0KCiAgICByZXR1cm4KICB9CgogIHRyeSB7CiAgICBjb25zdCB0b2tlbnMgPSBMZXhlci5sZXgoc3JjLCBvcHQpCiAgICBpZiAob3B0LndhbGtUb2tlbnMpIHsKICAgICAgbWFya2VkLndhbGtUb2tlbnModG9rZW5zLCBvcHQud2Fsa1Rva2VucykKICAgIH0KICAgIHJldHVybiBQYXJzZXIucGFyc2UodG9rZW5zLCBvcHQpCiAgfSBjYXRjaCAoZSkgewogICAgZS5tZXNzYWdlICs9ICJcblBsZWFzZSByZXBvcnQgdGhpcyB0byBodHRwczovL2dpdGh1Yi5jb20vbWFya2VkanMvbWFya2VkLiIKICAgIGlmIChvcHQuc2lsZW50KSB7CiAgICAgIHJldHVybiAoCiAgICAgICAgIjxwPkFuIGVycm9yIG9jY3VycmVkOjwvcD48cHJlPiIgKwogICAgICAgIGVzY2FwZShlLm1lc3NhZ2UgKyAiIiwgdHJ1ZSkgKwogICAgICAgICI8L3ByZT4iCiAgICAgICkKICAgIH0KICAgIHRocm93IGUKICB9Cn0KCi8qKgogKiBPcHRpb25zCiAqLwoKbWFya2VkLm9wdGlvbnMgPSBtYXJrZWQuc2V0T3B0aW9ucyA9IGZ1bmN0aW9uIChvcHQpIHsKICBtZXJnZShtYXJrZWQuZGVmYXVsdHMsIG9wdCkKICBjaGFuZ2VEZWZhdWx0cyhtYXJrZWQuZGVmYXVsdHMpCiAgcmV0dXJuIG1hcmtlZAp9CgptYXJrZWQuZ2V0RGVmYXVsdHMgPSBnZXREZWZhdWx0cwoKbWFya2VkLmRlZmF1bHRzID0gZGVmYXVsdHMKCi8qKgogKiBVc2UgRXh0ZW5zaW9uCiAqLwoKbWFya2VkLnVzZSA9IGZ1bmN0aW9uICguLi5hcmdzKSB7CiAgY29uc3Qgb3B0cyA9IG1lcmdlKHt9LCAuLi5hcmdzKQogIGNvbnN0IGV4dGVuc2lvbnMgPSBtYXJrZWQuZGVmYXVsdHMuZXh0ZW5zaW9ucyB8fCB7CiAgICByZW5kZXJlcnM6IHt9LAogICAgY2hpbGRUb2tlbnM6IHt9LAogIH0KICBsZXQgaGFzRXh0ZW5zaW9ucwoKICBhcmdzLmZvckVhY2gocGFjayA9PiB7CiAgICAvLyA9PS0tIFBhcnNlICJhZGRvbiIgZXh0ZW5zaW9ucyAtLT09IC8vCiAgICBpZiAocGFjay5leHRlbnNpb25zKSB7CiAgICAgIGhhc0V4dGVuc2lvbnMgPSB0cnVlCiAgICAgIHBhY2suZXh0ZW5zaW9ucy5mb3JFYWNoKGV4dCA9PiB7CiAgICAgICAgaWYgKCFleHQubmFtZSkgewogICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCJleHRlbnNpb24gbmFtZSByZXF1aXJlZCIpCiAgICAgICAgfQogICAgICAgIGlmIChleHQucmVuZGVyZXIpIHsKICAgICAgICAgIC8vIFJlbmRlcmVyIGV4dGVuc2lvbnMKICAgICAgICAgIGNvbnN0IHByZXZSZW5kZXJlciA9IGV4dGVuc2lvbnMucmVuZGVyZXJzCiAgICAgICAgICAgID8gZXh0ZW5zaW9ucy5yZW5kZXJlcnNbZXh0Lm5hbWVdCiAgICAgICAgICAgIDogbnVsbAogICAgICAgICAgaWYgKHByZXZSZW5kZXJlcikgewogICAgICAgICAgICAvLyBSZXBsYWNlIGV4dGVuc2lvbiB3aXRoIGZ1bmMgdG8gcnVuIG5ldyBleHRlbnNpb24gYnV0IGZhbGwgYmFjayBpZiBmYWxzZQogICAgICAgICAgICBleHRlbnNpb25zLnJlbmRlcmVyc1tleHQubmFtZV0gPSBmdW5jdGlvbiAoLi4uYXJncykgewogICAgICAgICAgICAgIGxldCByZXQgPSBleHQucmVuZGVyZXIuYXBwbHkodGhpcywgYXJncykKICAgICAgICAgICAgICBpZiAocmV0ID09PSBmYWxzZSkgewogICAgICAgICAgICAgICAgcmV0ID0gcHJldlJlbmRlcmVyLmFwcGx5KHRoaXMsIGFyZ3MpCiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIHJldHVybiByZXQKICAgICAgICAgICAgfQogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgZXh0ZW5zaW9ucy5yZW5kZXJlcnNbZXh0Lm5hbWVdID0gZXh0LnJlbmRlcmVyCiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGlmIChleHQudG9rZW5pemVyKSB7CiAgICAgICAgICAvLyBUb2tlbml6ZXIgRXh0ZW5zaW9ucwogICAgICAgICAgaWYgKCFleHQubGV2ZWwgfHwgKGV4dC5sZXZlbCAhPT0gImJsb2NrIiAmJiBleHQubGV2ZWwgIT09ICJpbmxpbmUiKSkgewogICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoImV4dGVuc2lvbiBsZXZlbCBtdXN0IGJlICdibG9jaycgb3IgJ2lubGluZSciKQogICAgICAgICAgfQogICAgICAgICAgaWYgKGV4dGVuc2lvbnNbZXh0LmxldmVsXSkgewogICAgICAgICAgICBleHRlbnNpb25zW2V4dC5sZXZlbF0udW5zaGlmdChleHQudG9rZW5pemVyKQogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgZXh0ZW5zaW9uc1tleHQubGV2ZWxdID0gW2V4dC50b2tlbml6ZXJdCiAgICAgICAgICB9CiAgICAgICAgICBpZiAoZXh0LnN0YXJ0KSB7CiAgICAgICAgICAgIC8vIEZ1bmN0aW9uIHRvIGNoZWNrIGZvciBzdGFydCBvZiB0b2tlbgogICAgICAgICAgICBpZiAoZXh0LmxldmVsID09PSAiYmxvY2siKSB7CiAgICAgICAgICAgICAgaWYgKGV4dGVuc2lvbnMuc3RhcnRCbG9jaykgewogICAgICAgICAgICAgICAgZXh0ZW5zaW9ucy5zdGFydEJsb2NrLnB1c2goZXh0LnN0YXJ0KQogICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICBleHRlbnNpb25zLnN0YXJ0QmxvY2sgPSBbZXh0LnN0YXJ0XQogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSBlbHNlIGlmIChleHQubGV2ZWwgPT09ICJpbmxpbmUiKSB7CiAgICAgICAgICAgICAgaWYgKGV4dGVuc2lvbnMuc3RhcnRJbmxpbmUpIHsKICAgICAgICAgICAgICAgIGV4dGVuc2lvbnMuc3RhcnRJbmxpbmUucHVzaChleHQuc3RhcnQpCiAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgIGV4dGVuc2lvbnMuc3RhcnRJbmxpbmUgPSBbZXh0LnN0YXJ0XQogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBpZiAoZXh0LmNoaWxkVG9rZW5zKSB7CiAgICAgICAgICAvLyBDaGlsZCB0b2tlbnMgdG8gYmUgdmlzaXRlZCBieSB3YWxrVG9rZW5zCiAgICAgICAgICBleHRlbnNpb25zLmNoaWxkVG9rZW5zW2V4dC5uYW1lXSA9IGV4dC5jaGlsZFRva2VucwogICAgICAgIH0KICAgICAgfSkKICAgIH0KCiAgICAvLyA9PS0tIFBhcnNlICJvdmVyd3JpdGUiIGV4dGVuc2lvbnMgLS09PSAvLwogICAgaWYgKHBhY2sucmVuZGVyZXIpIHsKICAgICAgY29uc3QgcmVuZGVyZXIgPSBtYXJrZWQuZGVmYXVsdHMucmVuZGVyZXIgfHwgbmV3IFJlbmRlcmVyKCkKICAgICAgZm9yIChjb25zdCBwcm9wIGluIHBhY2sucmVuZGVyZXIpIHsKICAgICAgICBjb25zdCBwcmV2UmVuZGVyZXIgPSByZW5kZXJlcltwcm9wXQogICAgICAgIC8vIFJlcGxhY2UgcmVuZGVyZXIgd2l0aCBmdW5jIHRvIHJ1biBleHRlbnNpb24sIGJ1dCBmYWxsIGJhY2sgaWYgZmFsc2UKICAgICAgICByZW5kZXJlcltwcm9wXSA9ICguLi5hcmdzKSA9PiB7CiAgICAgICAgICBsZXQgcmV0ID0gcGFjay5yZW5kZXJlcltwcm9wXS5hcHBseShyZW5kZXJlciwgYXJncykKICAgICAgICAgIGlmIChyZXQgPT09IGZhbHNlKSB7CiAgICAgICAgICAgIHJldCA9IHByZXZSZW5kZXJlci5hcHBseShyZW5kZXJlciwgYXJncykKICAgICAgICAgIH0KICAgICAgICAgIHJldHVybiByZXQKICAgICAgICB9CiAgICAgIH0KICAgICAgb3B0cy5yZW5kZXJlciA9IHJlbmRlcmVyCiAgICB9CiAgICBpZiAocGFjay50b2tlbml6ZXIpIHsKICAgICAgY29uc3QgdG9rZW5pemVyID0gbWFya2VkLmRlZmF1bHRzLnRva2VuaXplciB8fCBuZXcgVG9rZW5pemVyKCkKICAgICAgZm9yIChjb25zdCBwcm9wIGluIHBhY2sudG9rZW5pemVyKSB7CiAgICAgICAgY29uc3QgcHJldlRva2VuaXplciA9IHRva2VuaXplcltwcm9wXQogICAgICAgIC8vIFJlcGxhY2UgdG9rZW5pemVyIHdpdGggZnVuYyB0byBydW4gZXh0ZW5zaW9uLCBidXQgZmFsbCBiYWNrIGlmIGZhbHNlCiAgICAgICAgdG9rZW5pemVyW3Byb3BdID0gKC4uLmFyZ3MpID0+IHsKICAgICAgICAgIGxldCByZXQgPSBwYWNrLnRva2VuaXplcltwcm9wXS5hcHBseSh0b2tlbml6ZXIsIGFyZ3MpCiAgICAgICAgICBpZiAocmV0ID09PSBmYWxzZSkgewogICAgICAgICAgICByZXQgPSBwcmV2VG9rZW5pemVyLmFwcGx5KHRva2VuaXplciwgYXJncykKICAgICAgICAgIH0KICAgICAgICAgIHJldHVybiByZXQKICAgICAgICB9CiAgICAgIH0KICAgICAgb3B0cy50b2tlbml6ZXIgPSB0b2tlbml6ZXIKICAgIH0KCiAgICAvLyA9PS0tIFBhcnNlIFdhbGtUb2tlbnMgZXh0ZW5zaW9ucyAtLT09IC8vCiAgICBpZiAocGFjay53YWxrVG9rZW5zKSB7CiAgICAgIGNvbnN0IHdhbGtUb2tlbnMgPSBtYXJrZWQuZGVmYXVsdHMud2Fsa1Rva2VucwogICAgICBvcHRzLndhbGtUb2tlbnMgPSBmdW5jdGlvbiAodG9rZW4pIHsKICAgICAgICBwYWNrLndhbGtUb2tlbnMuY2FsbCh0aGlzLCB0b2tlbikKICAgICAgICBpZiAod2Fsa1Rva2VucykgewogICAgICAgICAgd2Fsa1Rva2Vucy5jYWxsKHRoaXMsIHRva2VuKQogICAgICAgIH0KICAgICAgfQogICAgfQoKICAgIGlmIChoYXNFeHRlbnNpb25zKSB7CiAgICAgIG9wdHMuZXh0ZW5zaW9ucyA9IGV4dGVuc2lvbnMKICAgIH0KCiAgICBtYXJrZWQuc2V0T3B0aW9ucyhvcHRzKQogIH0pCn0KCi8qKgogKiBSdW4gY2FsbGJhY2sgZm9yIGV2ZXJ5IHRva2VuCiAqLwoKbWFya2VkLndhbGtUb2tlbnMgPSBmdW5jdGlvbiAodG9rZW5zLCBjYWxsYmFjaykgewogIGZvciAoY29uc3QgdG9rZW4gb2YgdG9rZW5zKSB7CiAgICBjYWxsYmFjay5jYWxsKG1hcmtlZCwgdG9rZW4pCiAgICBzd2l0Y2ggKHRva2VuLnR5cGUpIHsKICAgICAgY2FzZSAidGFibGUiOiB7CiAgICAgICAgZm9yIChjb25zdCBjZWxsIG9mIHRva2VuLmhlYWRlcikgewogICAgICAgICAgbWFya2VkLndhbGtUb2tlbnMoY2VsbC50b2tlbnMsIGNhbGxiYWNrKQogICAgICAgIH0KICAgICAgICBmb3IgKGNvbnN0IHJvdyBvZiB0b2tlbi5yb3dzKSB7CiAgICAgICAgICBmb3IgKGNvbnN0IGNlbGwgb2Ygcm93KSB7CiAgICAgICAgICAgIG1hcmtlZC53YWxrVG9rZW5zKGNlbGwudG9rZW5zLCBjYWxsYmFjaykKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgYnJlYWsKICAgICAgfQogICAgICBjYXNlICJsaXN0IjogewogICAgICAgIG1hcmtlZC53YWxrVG9rZW5zKHRva2VuLml0ZW1zLCBjYWxsYmFjaykKICAgICAgICBicmVhawogICAgICB9CiAgICAgIGRlZmF1bHQ6IHsKICAgICAgICBpZiAoCiAgICAgICAgICBtYXJrZWQuZGVmYXVsdHMuZXh0ZW5zaW9ucyAmJgogICAgICAgICAgbWFya2VkLmRlZmF1bHRzLmV4dGVuc2lvbnMuY2hpbGRUb2tlbnMgJiYKICAgICAgICAgIG1hcmtlZC5kZWZhdWx0cy5leHRlbnNpb25zLmNoaWxkVG9rZW5zW3Rva2VuLnR5cGVdCiAgICAgICAgKSB7CiAgICAgICAgICAvLyBXYWxrIGFueSBleHRlbnNpb25zCiAgICAgICAgICBtYXJrZWQuZGVmYXVsdHMuZXh0ZW5zaW9ucy5jaGlsZFRva2Vuc1t0b2tlbi50eXBlXS5mb3JFYWNoKGZ1bmN0aW9uICgKICAgICAgICAgICAgY2hpbGRUb2tlbnMKICAgICAgICAgICkgewogICAgICAgICAgICBtYXJrZWQud2Fsa1Rva2Vucyh0b2tlbltjaGlsZFRva2Vuc10sIGNhbGxiYWNrKQogICAgICAgICAgfSkKICAgICAgICB9IGVsc2UgaWYgKHRva2VuLnRva2VucykgewogICAgICAgICAgbWFya2VkLndhbGtUb2tlbnModG9rZW4udG9rZW5zLCBjYWxsYmFjaykKICAgICAgICB9CiAgICAgIH0KICAgIH0KICB9Cn0KCi8qKgogKiBQYXJzZSBJbmxpbmUKICogQHBhcmFtIHtzdHJpbmd9IHNyYwogKi8KbWFya2VkLnBhcnNlSW5saW5lID0gZnVuY3Rpb24gKHNyYywgb3B0KSB7CiAgLy8gdGhyb3cgZXJyb3IgaW4gY2FzZSBvZiBub24gc3RyaW5nIGlucHV0CiAgaWYgKHR5cGVvZiBzcmMgPT09ICJ1bmRlZmluZWQiIHx8IHNyYyA9PT0gbnVsbCkgewogICAgdGhyb3cgbmV3IEVycm9yKAogICAgICAibWFya2VkLnBhcnNlSW5saW5lKCk6IGlucHV0IHBhcmFtZXRlciBpcyB1bmRlZmluZWQgb3IgbnVsbCIKICAgICkKICB9CiAgaWYgKHR5cGVvZiBzcmMgIT09ICJzdHJpbmciKSB7CiAgICB0aHJvdyBuZXcgRXJyb3IoCiAgICAgICJtYXJrZWQucGFyc2VJbmxpbmUoKTogaW5wdXQgcGFyYW1ldGVyIGlzIG9mIHR5cGUgIiArCiAgICAgICAgT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKHNyYykgKwogICAgICAgICIsIHN0cmluZyBleHBlY3RlZCIKICAgICkKICB9CgogIG9wdCA9IG1lcmdlKHt9LCBtYXJrZWQuZGVmYXVsdHMsIG9wdCB8fCB7fSkKICBjaGVja1Nhbml0aXplRGVwcmVjYXRpb24ob3B0KQoKICB0cnkgewogICAgY29uc3QgdG9rZW5zID0gTGV4ZXIubGV4SW5saW5lKHNyYywgb3B0KQogICAgaWYgKG9wdC53YWxrVG9rZW5zKSB7CiAgICAgIG1hcmtlZC53YWxrVG9rZW5zKHRva2Vucywgb3B0LndhbGtUb2tlbnMpCiAgICB9CiAgICByZXR1cm4gUGFyc2VyLnBhcnNlSW5saW5lKHRva2Vucywgb3B0KQogIH0gY2F0Y2ggKGUpIHsKICAgIGUubWVzc2FnZSArPSAiXG5QbGVhc2UgcmVwb3J0IHRoaXMgdG8gaHR0cHM6Ly9naXRodWIuY29tL21hcmtlZGpzL21hcmtlZC4iCiAgICBpZiAob3B0LnNpbGVudCkgewogICAgICByZXR1cm4gKAogICAgICAgICI8cD5BbiBlcnJvciBvY2N1cnJlZDo8L3A+PHByZT4iICsKICAgICAgICBlc2NhcGUoZS5tZXNzYWdlICsgIiIsIHRydWUpICsKICAgICAgICAiPC9wcmU+IgogICAgICApCiAgICB9CiAgICB0aHJvdyBlCiAgfQp9CgovKioKICogRXhwb3NlCiAqLwptYXJrZWQuUGFyc2VyID0gUGFyc2VyCm1hcmtlZC5wYXJzZXIgPSBQYXJzZXIucGFyc2UKbWFya2VkLlJlbmRlcmVyID0gUmVuZGVyZXIKbWFya2VkLlRleHRSZW5kZXJlciA9IFRleHRSZW5kZXJlcgptYXJrZWQuTGV4ZXIgPSBMZXhlcgptYXJrZWQubGV4ZXIgPSBMZXhlci5sZXgKbWFya2VkLlRva2VuaXplciA9IFRva2VuaXplcgptYXJrZWQuU2x1Z2dlciA9IFNsdWdnZXIKbWFya2VkLnBhcnNlID0gbWFya2VkCgpjb25zdCBvcHRpb25zID0gbWFya2VkLm9wdGlvbnMKY29uc3Qgc2V0T3B0aW9ucyA9IG1hcmtlZC5zZXRPcHRpb25zCmNvbnN0IHVzZSA9IG1hcmtlZC51c2UKY29uc3Qgd2Fsa1Rva2VucyA9IG1hcmtlZC53YWxrVG9rZW5zCmNvbnN0IHBhcnNlSW5saW5lID0gbWFya2VkLnBhcnNlSW5saW5lCmNvbnN0IHBhcnNlID0gbWFya2VkCmNvbnN0IHBhcnNlciA9IFBhcnNlci5wYXJzZQpjb25zdCBsZXhlciA9IExleGVyLmxleAoKY29uc3QgZW1haWwgPSB0cmlnZ2VyLnJvdwpyZXR1cm4gbWFya2VkKGVtYWlsLk1lc3NhZ2Up` diff --git a/packages/string-templates/src/iife.js b/packages/string-templates/src/iife.js new file mode 100644 index 0000000000..d043c14565 --- /dev/null +++ b/packages/string-templates/src/iife.js @@ -0,0 +1,3 @@ +module.exports.iifeWrapper = script => { + return `(function(){\n${script}\n})();` +} diff --git a/packages/string-templates/src/index.js b/packages/string-templates/src/index.js index 0125b9e0ab..5ae773516f 100644 --- a/packages/string-templates/src/index.js +++ b/packages/string-templates/src/index.js @@ -3,6 +3,7 @@ const handlebars = require("handlebars") const { registerAll, registerMinimum } = require("./helpers/index") const processors = require("./processors") const { atob, btoa, isBackendService } = require("./utilities") +const { iifeWrapper } = require("./iife") const manifest = require("../manifest.json") const { FIND_HBS_REGEX, @@ -426,3 +427,4 @@ function defaultJSSetup() { defaultJSSetup() module.exports.defaultJSSetup = defaultJSSetup +module.exports.iifeWrapper = iifeWrapper