vite-plugin-react-server
Version:
Vite plugin for React Server Components (RSC)
265 lines (263 loc) • 52.1 kB
JavaScript
/**
* vite-plugin-react-server
* Copyright (c) Nico Brinkkemper
* MIT License
*/
import { perEnvironmentState } from 'vite';
import { resolveOptions } from '../config/resolveOptions.js';
import { readFileSync } from 'node:fs';
import { join, resolve } from 'node:path';
import { getNodeEnv, isValidEnv } from '../config/getNodeEnv.js';
import { DEFAULT_CONFIG } from '../config/defaults.js';
import { resolveRegExp } from '../config/resolveRegExp.js';
import { userProjectRoot } from '../root.js';
import { createDefaultModuleID } from '../config/createModuleID.js';
import { buildClientPackagesPattern } from '../clientPackages/pattern.js';
import { detectClientModule } from 'react-server-loader/directives';
import { isViteInjectedCode } from '../loader/isViteInjectedCode.js';
import { createTransformer } from 'react-server-loader/transformer';
const createTransformerPlugin = (options) => {
return (userOptions) => {
const { name } = options;
const transformationCache = perEnvironmentState(() => /* @__PURE__ */ new Map());
const defaultEnvironment = options.defaultEnvironment ?? (name === "client" ? "client" : "server");
const allowedEnvironments = options.allowedEnvironments ?? (name === "client" ? defaultEnvironment === "client" ? ["client", "ssr"] : ["client"] : defaultEnvironment === "server" ? ["server", "ssr"] : ["server"]);
const logPrefix = `[vite-plugin-react-server:transform-${defaultEnvironment}-as-${name}]`;
const resolvedOptionsResult = resolveOptions(userOptions);
if (resolvedOptionsResult.type === "error")
throw resolvedOptionsResult.error;
const { userOptions: resolvedUserOptions } = resolvedOptionsResult;
let isBuild = true;
let isSSR = true;
const nodeEnv = getNodeEnv(process.env.NODE_ENV);
let mode = nodeEnv;
let runtimeResolvedUserOptions = resolvedUserOptions;
const outDir = resolvedUserOptions.build.outDir || "dist";
const serverDir = join(
outDir,
resolvedUserOptions.build.server || "server"
);
const clientDir = join(
outDir,
resolvedUserOptions.build.client || "client"
);
const staticDir = join(
outDir,
resolvedUserOptions.build.static || "static"
);
const modulePattern = resolveRegExp(
userOptions.autoDiscover?.modulePattern ?? DEFAULT_CONFIG.AUTO_DISCOVER.modulePattern
);
const nodeModulesPattern = resolveRegExp(
userOptions.autoDiscover?.vendorPattern ?? DEFAULT_CONFIG.AUTO_DISCOVER.vendorPattern
);
let cachedPackagesRef;
let cachedPattern = null;
const getClientPackagesPattern = () => {
const pkgs = userOptions.clientPackages ?? [];
if (pkgs !== cachedPackagesRef) {
cachedPackagesRef = pkgs;
cachedPattern = buildClientPackagesPattern(pkgs);
}
return cachedPattern;
};
const noDist = (id) => {
if (id.startsWith(userProjectRoot) || id.startsWith(join(userProjectRoot, outDir)) || id.startsWith(join(outDir, staticDir)) || id.startsWith(join(outDir, serverDir)) || id.startsWith(join(outDir, clientDir))) {
return true;
}
return false;
};
return {
name: `vite-plugin-react-server:transform-${name}`,
enforce: "post",
// CRITICAL: Enable per-environment hooks during dev to prevent cache contamination
perEnvironmentStartEndDuringDev: true,
// Note: Removed applyToEnvironment - let transform hook handle filtering
// With --app builds, applyToEnvironment may not be called correctly
configResolved(config) {
isBuild = config.command === "build";
isSSR = Boolean(config.build.ssr);
mode = config.mode;
if (!isValidEnv(mode)) {
throw new Error(`Invalid mode: ${mode}`);
}
const runtimeOptionsResult = resolveOptions({
...userOptions,
loader: {
...userOptions.loader,
mode
}
}, true);
if (runtimeOptionsResult.type === "success") {
runtimeResolvedUserOptions = runtimeOptionsResult.userOptions;
}
if (runtimeResolvedUserOptions.loader) {
runtimeResolvedUserOptions.loader.moduleID = createDefaultModuleID(
runtimeResolvedUserOptions,
{
command: config.command,
mode: config.mode},
mode
);
}
const logger = config.customLogger || config.logger;
if (runtimeResolvedUserOptions.verbose) {
logger.info(
`${logPrefix} configResolved: isBuild=${isBuild} isSSR=${isSSR} mode=${mode} allowed=${JSON.stringify(
allowedEnvironments
)} defaultEnv=${defaultEnvironment} importServerPath=${runtimeResolvedUserOptions.loader?.importServerPath}`
);
}
},
async buildStart() {
},
transform: {
order: "post",
// when transforming to:
// dist/server / env=server - it adds registerClientReference and registerServerReference based on directive (ssg portable)
// dist/client / env=ssr - removes use client directive and hides server modules, hides client entry or without exports (ssg portable)
// dist/static / env=client - removes use client directive and hides server modules, emits client entry (and is browser portable)
async handler(code, id, { ssr } = {}) {
const isWhitelistedClientPackage = getClientPackagesPattern()?.test(id) ?? false;
if (nodeModulesPattern.test(id) && !isWhitelistedClientPackage || !modulePattern.test(id) || !noDist(id) && !isWhitelistedClientPackage) {
return null;
}
let [, normalizedPath] = resolvedUserOptions.normalizer(id);
const normalizedId = id.replace(/\\/g, "/");
const normalizedServerDir = serverDir.replace(/\\/g, "/");
const normalizedClientDir = clientDir.replace(/\\/g, "/");
const isFromServerBuild = normalizedId.includes(`/${normalizedServerDir}/`) || normalizedId.includes(`dist/server/`);
const isFromClientBuild = normalizedId.includes(`/${normalizedClientDir}/`) || normalizedId.includes(`dist/client/`);
const isFromStaticBuild = normalizedId.includes(`dist/static/`);
const isBuiltFile = isBuild && /-[a-zA-Z0-9_]{6,}\.(js|mjs|cjs)$/.test(normalizedId);
const isAlreadyTransformed = code.includes(
runtimeResolvedUserOptions.loader?.registerClientReferenceName ?? "registerClientReference"
);
if (isAlreadyTransformed) {
if (runtimeResolvedUserOptions.verbose) {
this.environment?.logger?.info(
`[react-${name}-transform] Encountered already transformed file: ${id}. This indicates two transformers are running on the same file: ${this.environment?.name} and ${Object.entries(this.environment?.plugins ?? {}).map(([name2, plugin]) => `${name2} (${plugin.name})`).join(", ")}`
);
this.environment?.logger?.info("");
}
return {
code,
map: null
};
}
const isServerEnv = this.environment?.name === "server";
const envCache = transformationCache(this);
const cacheKey = `${normalizedPath}:${isServerEnv ? "server" : "client"}:${code}`;
if (envCache.has(cacheKey)) {
if (runtimeResolvedUserOptions.verbose) {
this.environment?.logger?.info(
`[react-${name}-transform] Using cached transformation for: ${normalizedPath} (${isServerEnv ? "server" : "client"}) env=${this.environment?.name}`
);
}
return envCache.get(cacheKey);
}
let originalSourceContent;
try {
const sourcePath = resolve(userProjectRoot, id);
originalSourceContent = readFileSync(sourcePath, "utf-8");
} catch (error) {
originalSourceContent = code;
}
const isClientByDirective = detectClientModule({
source: code,
parseFn: (src, opts) => this.parse(src, opts)
});
let finalModuleID = runtimeResolvedUserOptions.loader?.moduleID ? runtimeResolvedUserOptions.loader.moduleID(
normalizedPath,
originalSourceContent,
isClientByDirective
) : normalizedPath;
const needsHosting = isWhitelistedClientPackage || isClientByDirective;
if (needsHosting && typeof finalModuleID === "string" && !finalModuleID.startsWith("/")) {
finalModuleID = "/" + finalModuleID;
}
if (runtimeResolvedUserOptions.verbose) {
this.environment?.logger?.info(
`[react-${name}-transform] ModuleID transformation: ${normalizedPath} -> ${finalModuleID}`
);
}
const envName = this.environment?.name?.toLowerCase() || "";
const isServerEnvironment = envName === "server" || envName === "rsc" || envName === "react-server";
const transformer = createTransformer({
parseFn: (source) => {
const ast = this.parse(source, {
allowReturnOutsideFunction: true,
jsx: true
});
return ast;
},
options: {
loader: runtimeResolvedUserOptions.loader,
verbose: runtimeResolvedUserOptions.verbose,
panicThreshold: runtimeResolvedUserOptions.panicThreshold,
logger: this.environment?.logger,
moduleBase: userOptions.moduleBase ?? "",
// Vite injects preamble (e.g. __vitePreload for dynamic imports)
// above a module's own source; don't flag it as code-before-directive.
tolerateLeadingCode: isViteInjectedCode
},
// Pass the actual environment context to the transformer
// Only the actual "server" environment should transform client components to registerClientReference
// SSR environment needs actual React components, not placeholders
isServerEnvironment,
ssr
});
if (isFromServerBuild || isFromClientBuild || isFromStaticBuild || isBuiltFile) {
const buildType = isFromServerBuild ? "server" : isFromClientBuild ? "client" : isFromStaticBuild ? "static" : "built";
if (isFromServerBuild && runtimeResolvedUserOptions.loader?.isClientComponentByName?.(id)) {
if (runtimeResolvedUserOptions.verbose) {
this.environment?.logger?.info(
`[react-${name}-transform] Allowing transformation of server-built client component: ${id}`
);
}
} else {
if (runtimeResolvedUserOptions.verbose) {
this.environment?.logger?.info(
`[react-${name}-transform] Skipping built file from ${buildType} build: ${id}`
);
}
return {
code,
map: null
};
}
}
const transformResult = await transformer(
code,
normalizedPath,
finalModuleID
);
if (!transformResult) {
return { code, map: null };
}
const { code: transformed, map } = transformResult;
const result = { code: transformed, map };
envCache.set(cacheKey, result);
if (runtimeResolvedUserOptions.verbose) {
const hasDirectives = code.includes('"use client"') || code.includes('"use server"') || code.includes("'use client'") || code.includes("'use server'");
if (transformed !== code) {
this.environment?.logger?.info(
`[react-${name}-transform] ` + id.split("/").pop() + (code.startsWith('"use client"') ? " (client)" : "") + (hasDirectives ? " (directives processed)" : "")
);
this.environment?.logger?.info(
`[react-${name}-transform] ` + transformed.slice(0, 100) + "..."
);
} else if (hasDirectives) {
this.environment?.logger?.info(
`[react-${name}-transform] ` + id.split("/").pop() + " (directives already processed)"
);
}
}
return result;
}
}
};
};
};
export { createTransformerPlugin };
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3JlYXRlVHJhbnNmb3JtZXJQbHVnaW4uanMiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3BsdWdpbi90cmFuc2Zvcm1lci9jcmVhdGVUcmFuc2Zvcm1lclBsdWdpbi50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgdHlwZSB7IFBsdWdpbiB9IGZyb20gXCJ2aXRlXCI7XG5pbXBvcnQgeyBwZXJFbnZpcm9ubWVudFN0YXRlIH0gZnJvbSBcInZpdGVcIjtcbmltcG9ydCB0eXBlIHsgVml0ZVBsdWdpbkZuIH0gZnJvbSBcIi4uL3R5cGVzLmpzXCI7XG5pbXBvcnQgeyBjcmVhdGVUcmFuc2Zvcm1lciB9IGZyb20gXCIuLi9sb2FkZXIvY3JlYXRlVHJhbnNmb3JtZXIuanNcIjtcbmltcG9ydCB0eXBlIHsgUHJvZ3JhbSB9IGZyb20gXCJhY29yblwiO1xuaW1wb3J0IHsgcmVzb2x2ZU9wdGlvbnMgfSBmcm9tIFwiLi4vY29uZmlnL3Jlc29sdmVPcHRpb25zLmpzXCI7XG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tIFwibm9kZTpmc1wiO1xuaW1wb3J0IHsgcmVzb2x2ZSwgam9pbiB9IGZyb20gXCJub2RlOnBhdGhcIjtcbmltcG9ydCB7IGdldE5vZGVFbnYsIGlzVmFsaWRFbnYgfSBmcm9tIFwiLi4vY29uZmlnL2dldE5vZGVFbnYuanNcIjtcblxuLy8gaW1wb3J0IHsgZ2V0RW52aXJvbm1lbnROYW1lIH0gZnJvbSBcIi4uL2Vudi9wbHVnaW4uanNcIjtcbmltcG9ydCB7IERFRkFVTFRfQ09ORklHIH0gZnJvbSBcIi4uL2NvbmZpZy9kZWZhdWx0cy5qc1wiO1xuaW1wb3J0IHsgcmVzb2x2ZVJlZ0V4cCB9IGZyb20gXCIuLi9jb25maWcvcmVzb2x2ZVJlZ0V4cC5qc1wiO1xuaW1wb3J0IHsgdXNlclByb2plY3RSb290IH0gZnJvbSBcIi4uL3Jvb3QuanNcIjtcbmltcG9ydCB7IGNyZWF0ZURlZmF1bHRNb2R1bGVJRCB9IGZyb20gXCIuLi9jb25maWcvY3JlYXRlTW9kdWxlSUQuanNcIjtcbmltcG9ydCB7IGJ1aWxkQ2xpZW50UGFja2FnZXNQYXR0ZXJuIH0gZnJvbSBcIi4uL2NsaWVudFBhY2thZ2VzL2luZGV4LmpzXCI7XG5pbXBvcnQgeyBkZXRlY3RDbGllbnRNb2R1bGUgfSBmcm9tIFwicmVhY3Qtc2VydmVyLWxvYWRlci9kaXJlY3RpdmVzXCI7XG5pbXBvcnQgeyBpc1ZpdGVJbmplY3RlZENvZGUgfSBmcm9tIFwiLi4vbG9hZGVyL2lzVml0ZUluamVjdGVkQ29kZS5qc1wiO1xuXG5leHBvcnQgaW50ZXJmYWNlIFRyYW5zZm9ybWVyUGx1Z2luT3B0aW9ucyB7XG4gIG5hbWU6IHN0cmluZztcbiAgLyoqXG4gICAqIE9wdGlvbmFsLiBJZiBvbWl0dGVkLCBzZW5zaWJsZSBkZWZhdWx0cyBhcmUgYXBwbGllZCBiYXNlZCBvbiBgbmFtZWA6XG4gICAqIC0gbmFtZSA9PT0gXCJjbGllbnRcIiAtPiBbXCJjbGllbnRcIiwgXCJzc3JcIl1cbiAgICogLSBuYW1lID09PSBcInNlcnZlclwiIC0+IFtcInNlcnZlclwiXVxuICAgKi9cbiAgYWxsb3dlZEVudmlyb25tZW50cz86IChcImNsaWVudFwiIHwgXCJzZXJ2ZXJcIiB8IFwic3NyXCIpW107XG4gIC8qKlxuICAgKiBPcHRpb25hbC4gSWYgb21pdHRlZCwgc2Vuc2libGUgZGVmYXVsdHMgYXJlIGFwcGxpZWQgYmFzZWQgb24gYG5hbWVgOlxuICAgKiAtIG5hbWUgPT09IFwiY2xpZW50XCIgLT4gXCJjbGllbnRcIlxuICAgKiAtIG5hbWUgPT09IFwic2VydmVyXCIgLT4gXCJzZXJ2ZXJcIlxuICAgKi9cbiAgZGVmYXVsdEVudmlyb25tZW50PzogXCJjbGllbnRcIiB8IFwic2VydmVyXCIgfCBcInNzclwiO1xufVxuXG5leHBvcnQgY29uc3QgY3JlYXRlVHJhbnNmb3JtZXJQbHVnaW4gPSAoXG4gIG9wdGlvbnM6IFRyYW5zZm9ybWVyUGx1Z2luT3B0aW9uc1xuKTogVml0ZVBsdWdpbkZuID0+IHtcbiAgcmV0dXJuICh1c2VyT3B0aW9ucykgPT4ge1xuICAgIGNvbnN0IHsgbmFtZSB9ID0gb3B0aW9ucztcblxuICAgIC8vIENSSVRJQ0FMOiBVc2UgcGVyLWVudmlyb25tZW50IHN0YXRlIHRvIHByZXZlbnQgY3Jvc3MtZW52aXJvbm1lbnQgY2FjaGUgY29udGFtaW5hdGlvblxuICAgIC8vIFRoaXMgZml4ZXMgdGhlIGlzc3VlIHdoZXJlIHNlcnZlciBlbnZpcm9ubWVudCBjYWNoZWQgbW9kdWxlcyBhZmZlY3QgY2xpZW50IGVudmlyb25tZW50IGJ1aWxkc1xuICAgIGNvbnN0IHRyYW5zZm9ybWF0aW9uQ2FjaGUgPSBwZXJFbnZpcm9ubWVudFN0YXRlPFxuICAgICAgTWFwPHN0cmluZywgeyBjb2RlOiBzdHJpbmc7IG1hcDogYW55IH0+XG4gICAgPigoKSA9PiBuZXcgTWFwKCkpO1xuICAgIGNvbnN0IGRlZmF1bHRFbnZpcm9ubWVudCA9XG4gICAgICBvcHRpb25zLmRlZmF1bHRFbnZpcm9ubWVudCA/PyAobmFtZSA9PT0gXCJjbGllbnRcIiA/IFwiY2xpZW50XCIgOiBcInNlcnZlclwiKTtcbiAgICBjb25zdCBhbGxvd2VkRW52aXJvbm1lbnRzID1cbiAgICAgIG9wdGlvbnMuYWxsb3dlZEVudmlyb25tZW50cyA/P1xuICAgICAgKG5hbWUgPT09IFwiY2xpZW50XCJcbiAgICAgICAgPyBkZWZhdWx0RW52aXJvbm1lbnQgPT09IFwiY2xpZW50XCJcbiAgICAgICAgICA/IFtcImNsaWVudFwiLCBcInNzclwiXVxuICAgICAgICAgIDogW1wiY2xpZW50XCJdXG4gICAgICAgIDogZGVmYXVsdEVudmlyb25tZW50ID09PSBcInNlcnZlclwiXG4gICAgICAgID8gW1wic2VydmVyXCIsIFwic3NyXCJdXG4gICAgICAgIDogW1wic2VydmVyXCJdKTtcbiAgICBjb25zdCBsb2dQcmVmaXggPSBgW3ZpdGUtcGx1Z2luLXJlYWN0LXNlcnZlcjp0cmFuc2Zvcm0tJHtkZWZhdWx0RW52aXJvbm1lbnR9LWFzLSR7bmFtZX1dYDtcblxuICAgIGNvbnN0IHJlc29sdmVkT3B0aW9uc1Jlc3VsdCA9IHJlc29sdmVPcHRpb25zKHVzZXJPcHRpb25zKTtcbiAgICBpZiAocmVzb2x2ZWRPcHRpb25zUmVzdWx0LnR5cGUgPT09IFwiZXJyb3JcIilcbiAgICAgIHRocm93IHJlc29sdmVkT3B0aW9uc1Jlc3VsdC5lcnJvcjtcbiAgICBjb25zdCB7IHVzZXJPcHRpb25zOiByZXNvbHZlZFVzZXJPcHRpb25zIH0gPSByZXNvbHZlZE9wdGlvbnNSZXN1bHQ7XG5cbiAgICBsZXQgaXNCdWlsZCA9IHRydWU7XG4gICAgbGV0IGlzU1NSID0gdHJ1ZTtcbiAgICBjb25zdCBub2RlRW52ID0gZ2V0Tm9kZUVudihwcm9jZXNzLmVudi5OT0RFX0VOVik7XG4gICAgbGV0IG1vZGUgPSBub2RlRW52O1xuICAgIGxldCBydW50aW1lUmVzb2x2ZWRVc2VyT3B0aW9ucyA9IHJlc29sdmVkVXNlck9wdGlvbnM7XG5cbiAgICAvLyBVc2UgZ2xvYmFsIGNhY2hlIGZvciB0cmFuc2Zvcm1hdGlvbiByZXN1bHRzIHRvIGVuc3VyZSBjb25zaXN0ZW50IGhhc2hpbmcgYWNyb3NzIGFsbCBwbHVnaW4gaW5zdGFuY2VzXG4gICAgY29uc3Qgb3V0RGlyID0gcmVzb2x2ZWRVc2VyT3B0aW9ucy5idWlsZC5vdXREaXIgfHwgXCJkaXN0XCI7XG4gICAgY29uc3Qgc2VydmVyRGlyID0gam9pbihcbiAgICAgIG91dERpcixcbiAgICAgIHJlc29sdmVkVXNlck9wdGlvbnMuYnVpbGQuc2VydmVyIHx8IFwic2VydmVyXCJcbiAgICApO1xuICAgIGNvbnN0IGNsaWVudERpciA9IGpvaW4oXG4gICAgICBvdXREaXIsXG4gICAgICByZXNvbHZlZFVzZXJPcHRpb25zLmJ1aWxkLmNsaWVudCB8fCBcImNsaWVudFwiXG4gICAgKTtcbiAgICBjb25zdCBzdGF0aWNEaXIgPSBqb2luKFxuICAgICAgb3V0RGlyLFxuICAgICAgcmVzb2x2ZWRVc2VyT3B0aW9ucy5idWlsZC5zdGF0aWMgfHwgXCJzdGF0aWNcIlxuICAgICk7XG4gICAgY29uc3QgbW9kdWxlUGF0dGVybiA9IHJlc29sdmVSZWdFeHAoXG4gICAgICB1c2VyT3B0aW9ucy5hdXRvRGlzY292ZXI/Lm1vZHVsZVBhdHRlcm4gPz9cbiAgICAgICAgREVGQVVMVF9DT05GSUcuQVVUT19ESVNDT1ZFUi5tb2R1bGVQYXR0ZXJuXG4gICAgKTtcbiAgICBjb25zdCBub2RlTW9kdWxlc1BhdHRlcm4gPSByZXNvbHZlUmVnRXhwKFxuICAgICAgdXNlck9wdGlvbnMuYXV0b0Rpc2NvdmVyPy52ZW5kb3JQYXR0ZXJuID8/XG4gICAgICAgIERFRkFVTFRfQ09ORklHLkFVVE9fRElTQ09WRVIudmVuZG9yUGF0dGVyblxuICAgICk7XG4gICAgLy8gV2hpdGVsaXN0IG9mIG5vZGVfbW9kdWxlcyBwYWNrYWdlcyB0aGF0IHNob3VsZCBzdGlsbCBnbyB0aHJvdWdoIHRoZVxuICAgIC8vIFJTQyB0cmFuc2Zvcm0g4oCUIGxpYnJhcmllcyB0aGF0IHVzZSB0aGUgcGVyLWZpbGUgYFwidXNlIGNsaWVudFwiYFxuICAgIC8vIGNvbnZlbnRpb24gaW50ZXJuYWxseSAoZS5nLiBAY2hha3JhLXVpL3JlYWN0KS4gV2l0aG91dCB0aGlzIG9wdC1pbixcbiAgICAvLyB0aGVpciBgXCJ1c2UgY2xpZW50XCJgIGJvdW5kYXJpZXMgZ2V0IGlubGluZWQgaW50byB0aGUgc2VydmVyIGJ1bmRsZVxuICAgIC8vIGFuZCBydW50aW1lIENKUy9FU00gaW50ZXJvcCB0cmlwcyBvbiBgaW1wb3J0IHsgY3JlYXRlQ29udGV4dCB9IGZyb21cbiAgICAvLyAncmVhY3QnYC5cbiAgICAvL1xuICAgIC8vIFJlYWQgbGF6aWx5IChwZXItdHJhbnNmb3JtLWNhbGwpIGFuZCBtZW1vaXplZCBieSBsaXN0IGlkZW50aXR5LCBzb1xuICAgIC8vIHRoZSBhdXRvLWRldGVjdGVkIHBhY2thZ2VzIHRoYXQgYGNsaWVudFBhY2thZ2VzRGlzY292ZXJ5UGx1Z2luYFxuICAgIC8vIG1lcmdlcyBpbnRvIGB1c2VyT3B0aW9ucy5jbGllbnRQYWNrYWdlc2AgZHVyaW5nIGl0cyBhc3luYyBgY29uZmlnYFxuICAgIC8vIGhvb2sgdGFrZSBlZmZlY3QgZm9yIHRyYW5zZm9ybSBmaWx0ZXJpbmcgd2l0aG91dCBhIHNlcGFyYXRlXG4gICAgLy8gY29uZmlnUmVzb2x2ZWQgaG9vay5cbiAgICBsZXQgY2FjaGVkUGFja2FnZXNSZWY6IHJlYWRvbmx5IHN0cmluZ1tdIHwgdW5kZWZpbmVkO1xuICAgIGxldCBjYWNoZWRQYXR0ZXJuOiBSZWdFeHAgfCBudWxsID0gbnVsbDtcbiAgICBjb25zdCBnZXRDbGllbnRQYWNrYWdlc1BhdHRlcm4gPSAoKTogUmVnRXhwIHwgbnVsbCA9PiB7XG4gICAgICBjb25zdCBwa2dzID1cbiAgICAgICAgKHVzZXJPcHRpb25zIGFzIHsgY2xpZW50UGFja2FnZXM/OiByZWFkb25seSBzdHJpbmdbXSB9KVxuICAgICAgICAgIC5jbGllbnRQYWNrYWdlcyA/PyBbXTtcbiAgICAgIGlmIChwa2dzICE9PSBjYWNoZWRQYWNrYWdlc1JlZikge1xuICAgICAgICBjYWNoZWRQYWNrYWdlc1JlZiA9IHBrZ3M7XG4gICAgICAgIGNhY2hlZFBhdHRlcm4gPSBidWlsZENsaWVudFBhY2thZ2VzUGF0dGVybihwa2dzKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBjYWNoZWRQYXR0ZXJuO1xuICAgIH07XG4gICAgY29uc3Qgbm9EaXN0ID0gKGlkOiBzdHJpbmcpID0+IHtcbiAgICAgIC8vIEFsbG93IGZpbGVzIGZyb20gdGVzdCBmaXh0dXJlcyBhbmQgcHJvamVjdCByb290XG4gICAgICBpZiAoXG4gICAgICAgIGlkLnN0YXJ0c1dpdGgodXNlclByb2plY3RSb290KSB8fFxuICAgICAgICBpZC5zdGFydHNXaXRoKGpvaW4odXNlclByb2plY3RSb290LCBvdXREaXIpKSB8fFxuICAgICAgICBpZC5zdGFydHNXaXRoKGpvaW4ob3V0RGlyLCBzdGF0aWNEaXIpKSB8fFxuICAgICAgICBpZC5zdGFydHNXaXRoKGpvaW4ob3V0RGlyLCBzZXJ2ZXJEaXIpKSB8fFxuICAgICAgICBpZC5zdGFydHNXaXRoKGpvaW4ob3V0RGlyLCBjbGllbnREaXIpKVxuICAgICAgKSB7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgfVxuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH07XG5cbiAgICByZXR1cm4ge1xuICAgICAgbmFtZTogYHZpdGUtcGx1Z2luLXJlYWN0LXNlcnZlcjp0cmFuc2Zvcm0tJHtuYW1lfWAsXG4gICAgICBlbmZvcmNlOiBcInBvc3RcIixcbiAgICAgIC8vIENSSVRJQ0FMOiBFbmFibGUgcGVyLWVudmlyb25tZW50IGhvb2tzIGR1cmluZyBkZXYgdG8gcHJldmVudCBjYWNoZSBjb250YW1pbmF0aW9uXG4gICAgICBwZXJFbnZpcm9ubWVudFN0YXJ0RW5kRHVyaW5nRGV2OiB0cnVlLFxuICAgICAgLy8gTm90ZTogUmVtb3ZlZCBhcHBseVRvRW52aXJvbm1lbnQgLSBsZXQgdHJhbnNmb3JtIGhvb2sgaGFuZGxlIGZpbHRlcmluZ1xuICAgICAgLy8gV2l0aCAtLWFwcCBidWlsZHMsIGFwcGx5VG9FbnZpcm9ubWVudCBtYXkgbm90IGJlIGNhbGxlZCBjb3JyZWN0bHlcbiAgICAgIGNvbmZpZ1Jlc29sdmVkKGNvbmZpZykge1xuICAgICAgICBpc0J1aWxkID0gY29uZmlnLmNvbW1hbmQgPT09IFwiYnVpbGRcIjtcbiAgICAgICAgaXNTU1IgPSBCb29sZWFuKGNvbmZpZy5idWlsZC5zc3IpO1xuICAgICAgICBtb2RlID0gY29uZmlnLm1vZGUgYXMgXCJkZXZlbG9wbWVudFwiIHwgXCJwcm9kdWN0aW9uXCIgfCBcInRlc3RcIjtcbiAgICAgICAgaWYgKCFpc1ZhbGlkRW52KG1vZGUpKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIG1vZGU6ICR7bW9kZX1gKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIENSSVRJQ0FMOiBSZS1yZXNvbHZlIG9wdGlvbnMgd2l0aCBydW50aW1lIG1vZGUgdG8gZ2V0IGNvcnJlY3QgaW1wb3J0U2VydmVyUGF0aFxuICAgICAgICAvLyBUaGlzIGVuc3VyZXMgdGVzdCBtb2RlIHVzZXMgcmVhY3Qtc2VydmVyLWRvbS1lc20vc2VydmVyLm5vZGUgaW5zdGVhZCBvZiBzZXJ2ZXJcbiAgICAgICAgLy8gRm9yY2UgcmUtcmVzb2x2ZSB0byBhdm9pZCBjYWNoZWQgbW9kdWxlSUQgZnVuY3Rpb25zIGZyb20gZGlmZmVyZW50IGJ1aWxkIGNvbnRleHRzXG4gICAgICAgIGNvbnN0IHJ1bnRpbWVPcHRpb25zUmVzdWx0ID0gcmVzb2x2ZU9wdGlvbnMoe1xuICAgICAgICAgIC4uLnVzZXJPcHRpb25zLFxuICAgICAgICAgIGxvYWRlcjoge1xuICAgICAgICAgICAgLi4udXNlck9wdGlvbnMubG9hZGVyLFxuICAgICAgICAgICAgbW9kZTogbW9kZSxcbiAgICAgICAgICB9LFxuICAgICAgICB9LCB0cnVlKTsgLy8gRm9yY2UgcmVzb2x2ZSB0byBieXBhc3MgY2FjaGVcbiAgICAgICAgaWYgKHJ1bnRpbWVPcHRpb25zUmVzdWx0LnR5cGUgPT09IFwic3VjY2Vzc1wiKSB7XG4gICAgICAgICAgcnVudGltZVJlc29sdmVkVXNlck9wdGlvbnMgPSBydW50aW1lT3B0aW9uc1Jlc3VsdC51c2VyT3B0aW9ucztcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIENSSVRJQ0FMOiBVcGRhdGUgbW9kdWxlSUQgZnVuY3Rpb24gd2l0aCBjb3JyZWN0IGNvbmZpZ0VudiBmb3IgYnVpbGQgbW9kZVxuICAgICAgICAvLyBUaGlzIGVuc3VyZXMgY2xpZW50IGNvbXBvbmVudCBoYXNoaW5nIHVzZXMgdGhlIGNvcnJlY3QgYnVpbGQgY29udGV4dFxuICAgICAgICAvLyBBTFdBWVMgcmVjcmVhdGUgdGhlIG1vZHVsZUlEIHRvIGVuc3VyZSBpdCBtYXRjaGVzIHRoZSBjdXJyZW50IGNvbW1hbmRcbiAgICAgICAgaWYgKHJ1bnRpbWVSZXNvbHZlZFVzZXJPcHRpb25zLmxvYWRlcikge1xuICAgICAgICAgIHJ1bnRpbWVSZXNvbHZlZFVzZXJPcHRpb25zLmxvYWRlci5tb2R1bGVJRCA9IGNyZWF0ZURlZmF1bHRNb2R1bGVJRChcbiAgICAgICAgICAgIHJ1bnRpbWVSZXNvbHZlZFVzZXJPcHRpb25zLFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICBjb21tYW5kOiBjb25maWcuY29tbWFuZCxcbiAgICAgICAgICAgICAgbW9kZTogY29uZmlnLm1vZGUsXG4gICAgICAgICAgICAgIGlzU3NyQnVpbGQ6IGlzU1NSLFxuICAgICAgICAgICAgICBpc1ByZXZpZXc6IGZhbHNlLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIG1vZGVcbiAgICAgICAgICApO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gTm90ZTogY29uZGl0aW9uIG92ZXJyaWRlIGlzIHNldCBpbiBlbnYgcGx1Z2luIGR1cmluZyBjb25maWcgcGhhc2VcbiAgICAgICAgLy8gVmVyYm9zZSBzdW1tYXJ5IChjb25maWcgaG9vayBoYXMgdm9pZCBjb250ZXh0LCB1c2UgY29uZmlnIGxvZ2dlcilcbiAgICAgICAgY29uc3QgbG9nZ2VyID0gY29uZmlnLmN1c3RvbUxvZ2dlciB8fCBjb25maWcubG9nZ2VyO1xuICAgICAgICAvLyBPbmx5IGxvZyBpbiB2ZXJib3NlIG1vZGVcbiAgICAgICAgaWYgKHJ1bnRpbWVSZXNvbHZlZFVzZXJPcHRpb25zLnZlcmJvc2UpIHtcbiAgICAgICAgICBsb2dnZXIuaW5mbyhcbiAgICAgICAgICAgIGAke2xvZ1ByZWZpeH0gY29uZmlnUmVzb2x2ZWQ6IGlzQnVpbGQ9JHtpc0J1aWxkfSBpc1NTUj0ke2lzU1NSfSBtb2RlPSR7bW9kZX0gYWxsb3dlZD0ke0pTT04uc3RyaW5naWZ5KFxuICAgICAgICAgICAgICBhbGxvd2VkRW52aXJvbm1lbnRzXG4gICAgICAgICAgICApfSBkZWZhdWx0RW52PSR7ZGVmYXVsdEVudmlyb25tZW50fSBpbXBvcnRTZXJ2ZXJQYXRoPSR7XG4gICAgICAgICAgICAgIHJ1bnRpbWVSZXNvbHZlZFVzZXJPcHRpb25zLmxvYWRlcj8uaW1wb3J0U2VydmVyUGF0aFxuICAgICAgICAgICAgfWBcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICB9LFxuICAgICAgYXN5bmMgYnVpbGRTdGFydCgpIHtcbiAgICAgICAgLy8gTm8gbG9uZ2VyIGxvYWQgc3RhdGljIG1hbmlmZXN0IC0gcmVseSBvbiBoYXNoIGNvb3JkaW5hdGlvbiB0byBlbnN1cmUgY29uc2lzdGVudCBoYXNoZXNcbiAgICAgICAgLy8gVGhpcyByZW1vdmVzIHRoZSBmaWxlIEkvTyBkZXBlbmRlbmN5IGFuZCBhbGxvd3MgcGFyYWxsZWwgYnVpbGRzXG4gICAgICB9LFxuICAgICAgdHJhbnNmb3JtOiB7XG4gICAgICAgIG9yZGVyOiBcInBvc3RcIixcbiAgICAgICAgLy8gd2hlbiB0cmFuc2Zvcm1pbmcgdG86XG4gICAgICAgIC8vIGRpc3Qvc2VydmVyIC8gZW52PXNlcnZlciAtIGl0IGFkZHMgcmVnaXN0ZXJDbGllbnRSZWZlcmVuY2UgYW5kIHJlZ2lzdGVyU2VydmVyUmVmZXJlbmNlIGJhc2VkIG9uIGRpcmVjdGl2ZSAoc3NnIHBvcnRhYmxlKVxuICAgICAgICAvLyBkaXN0L2NsaWVudCAvIGVudj1zc3IgLSByZW1vdmVzIHVzZSBjbGllbnQgZGlyZWN0aXZlIGFuZCBoaWRlcyBzZXJ2ZXIgbW9kdWxlcywgaGlkZXMgY2xpZW50IGVudHJ5IG9yIHdpdGhvdXQgZXhwb3J0cyAoc3NnIHBvcnRhYmxlKVxuICAgICAgICAvLyBkaXN0L3N0YXRpYyAvIGVudj1jbGllbnQgIC0gIHJlbW92ZXMgdXNlIGNsaWVudCBkaXJlY3RpdmUgYW5kIGhpZGVzIHNlcnZlciBtb2R1bGVzLCBlbWl0cyBjbGllbnQgZW50cnkgKGFuZCBpcyBicm93c2VyIHBvcnRhYmxlKVxuICAgICAgICBhc3luYyBoYW5kbGVyKGNvZGUsIGlkLCB7IHNzciB9ID0ge30pIHtcbiAgICAgICAgICBjb25zdCBpc1doaXRlbGlzdGVkQ2xpZW50UGFja2FnZSA9XG4gICAgICAgICAgICBnZXRDbGllbnRQYWNrYWdlc1BhdHRlcm4oKT8udGVzdChpZCkgPz8gZmFsc2U7XG4gICAgICAgICAgaWYgKFxuICAgICAgICAgICAgKG5vZGVNb2R1bGVzUGF0dGVybi50ZXN0KGlkKSAmJiAhaXNXaGl0ZWxpc3RlZENsaWVudFBhY2thZ2UpIHx8XG4gICAgICAgICAgICAhbW9kdWxlUGF0dGVybi50ZXN0KGlkKSB8fFxuICAgICAgICAgICAgKCFub0Rpc3QoaWQpICYmICFpc1doaXRlbGlzdGVkQ2xpZW50UGFja2FnZSlcbiAgICAgICAgICApIHtcbiAgICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICAgIH1cbiAgICAgICAgICBsZXQgWywgbm9ybWFsaXplZFBhdGhdID0gcmVzb2x2ZWRVc2VyT3B0aW9ucy5ub3JtYWxpemVyKGlkKTtcblxuICAgICAgICAgIC8vIENoZWNrIGlmIHRoaXMgaXMgYSBidWlsdCBmaWxlIHRoYXQgZG9lc24ndCBuZWVkIHRyYW5zZm9ybWF0aW9uXG4gICAgICAgICAgLy8gTm9ybWFsaXplIHBhdGhzIHRvIGhhbmRsZSBjcm9zcy1wbGF0Zm9ybSBkaWZmZXJlbmNlc1xuICAgICAgICAgIGNvbnN0IG5vcm1hbGl6ZWRJZCA9IGlkLnJlcGxhY2UoL1xcXFwvZywgXCIvXCIpO1xuICAgICAgICAgIGNvbnN0IG5vcm1hbGl6ZWRTZXJ2ZXJEaXIgPSBzZXJ2ZXJEaXIucmVwbGFjZSgvXFxcXC9nLCBcIi9cIik7XG4gICAgICAgICAgY29uc3Qgbm9ybWFsaXplZENsaWVudERpciA9IGNsaWVudERpci5yZXBsYWNlKC9cXFxcL2csIFwiL1wiKTtcblxuICAgICAgICAgIC8vIENoZWNrIGlmIHRoZSBmaWxlIGlzIGZyb20gYSBidWlsZCBvdXRwdXQgZGlyZWN0b3J5XG4gICAgICAgICAgY29uc3QgaXNGcm9tU2VydmVyQnVpbGQgPVxuICAgICAgICAgICAgbm9ybWFsaXplZElkLmluY2x1ZGVzKGAvJHtub3JtYWxpemVkU2VydmVyRGlyfS9gKSB8fFxuICAgICAgICAgICAgbm9ybWFsaXplZElkLmluY2x1ZGVzKGBkaXN0L3NlcnZlci9gKTtcbiAgICAgICAgICBjb25zdCBpc0Zyb21DbGllbnRCdWlsZCA9XG4gICAgICAgICAgICBub3JtYWxpemVkSWQuaW5jbHVkZXMoYC8ke25vcm1hbGl6ZWRDbGllbnREaXJ9L2ApIHx8XG4gICAgICAgICAgICBub3JtYWxpemVkSWQuaW5jbHVkZXMoYGRpc3QvY2xpZW50L2ApO1xuICAgICAgICAgIGNvbnN0IGlzRnJvbVN0YXRpY0J1aWxkID0gbm9ybWFsaXplZElkLmluY2x1ZGVzKGBkaXN0L3N0YXRpYy9gKTtcblxuICAgICAgICAgIC8vIENoZWNrIGlmIHRoaXMgbG9va3MgbGlrZSBhIGJ1aWx0L2hhc2hlZCBmaWxlIChzaG91bGQgbmV2ZXIgYmUgdHJhbnNmb3JtZWQpXG4gICAgICAgICAgLy8gQnVpbHQgZmlsZXMgaGF2ZSBoYXNoZXMgYW5kIGFyZSBhbHJlYWR5IHByb2Nlc3NlZFxuICAgICAgICAgIGNvbnN0IGlzQnVpbHRGaWxlID1cbiAgICAgICAgICAgIGlzQnVpbGQgJiYgLy1bYS16QS1aMC05X117Nix9XFwuKGpzfG1qc3xjanMpJC8udGVzdChub3JtYWxpemVkSWQpO1xuXG4gICAgICAgICAgLy8gQ2hlY2sgaWYgdGhpcyBmaWxlIGlzIGFscmVhZHkgdHJhbnNmb3JtZWQgKGNvbnRhaW5zIHJlZ2lzdGVyQ2xpZW50UmVmZXJlbmNlKVxuICAgICAgICAgIGNvbnN0IGlzQWxyZWFkeVRyYW5zZm9ybWVkID0gY29kZS5pbmNsdWRlcyhcbiAgICAgICAgICAgIHJ1bnRpbWVSZXNvbHZlZFVzZXJPcHRpb25zLmxvYWRlcj8ucmVnaXN0ZXJDbGllbnRSZWZlcmVuY2VOYW1lID8/XG4gICAgICAgICAgICAgIFwicmVnaXN0ZXJDbGllbnRSZWZlcmVuY2VcIlxuICAgICAgICAgICk7XG4gICAgICAgICAgaWYgKGlzQWxyZWFkeVRyYW5zZm9ybWVkKSB7XG4gICAgICAgICAgICBpZiAocnVudGltZVJlc29sdmVkVXNlck9wdGlvbnMudmVyYm9zZSkge1xuICAgICAgICAgICAgICB0aGlzLmVudmlyb25tZW50Py5sb2dnZXI/LmluZm8oXG4gICAgICAgICAgICAgICAgYFtyZWFjdC0ke25hbWV9LXRyYW5zZm9ybV0gRW5jb3VudGVyZWQgYWxyZWFkeSB0cmFuc2Zvcm1lZCBmaWxlOiAke2lkfS4gVGhpcyBpbmRpY2F0ZXMgdHdvIHRyYW5zZm9ybWVycyBhcmUgcnVubmluZyBvbiB0aGUgc2FtZSBmaWxlOiAke1xuICAgICAgICAgICAgICAgICAgdGhpcy5lbnZpcm9ubWVudD8ubmFtZVxuICAgICAgICAgICAgICAgIH0gYW5kICR7T2JqZWN0LmVudHJpZXModGhpcy5lbnZpcm9ubWVudD8ucGx1Z2lucyA/PyB7fSlcbiAgICAgICAgICAgICAgICAgIC5tYXAoKFtuYW1lLCBwbHVnaW5dKSA9PiBgJHtuYW1lfSAoJHtwbHVnaW4ubmFtZX0pYClcbiAgICAgICAgICAgICAgICAgIC5qb2luKFwiLCBcIil9YFxuICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICB0aGlzLmVudmlyb25tZW50Py5sb2dnZXI/LmluZm8oJycpXG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICBjb2RlOiBjb2RlLFxuICAgICAgICAgICAgICBtYXA6IG51bGwsXG4gICAgICAgICAgICB9O1xuICAgICAgICAgIH1cblxuICAgICAgICAgIC8vIENoZWNrIGlmIHdlJ3ZlIGFscmVhZHkgdHJhbnNmb3JtZWQgdGhpcyBtb2R1bGUgdG8gYXZvaWQgZG91YmxlLWhhc2hpbmdcbiAgICAgICAgICAvLyBJbmNsdWRlIGVudmlyb25tZW50IGNvbnRleHQgaW4gY2FjaGUga2V5IHNpbmNlIGRpZmZlcmVudCBlbnZpcm9ubWVudHMgbmVlZCBkaWZmZXJlbnQgdHJhbnNmb3JtYXRpb25zXG4gICAgICAgICAgY29uc3QgaXNTZXJ2ZXJFbnYgPSB0aGlzLmVudmlyb25tZW50Py5uYW1lID09PSBcInNlcnZlclwiO1xuICAgICAgICAgIC8vIENSSVRJQ0FMOiBVc2UgcGVyLWVudmlyb25tZW50IGNhY2hlIHRvIHByZXZlbnQgY3Jvc3MtZW52aXJvbm1lbnQgY29udGFtaW5hdGlvblxuICAgICAgICAgIGNvbnN0IGVudkNhY2hlID0gdHJhbnNmb3JtYXRpb25DYWNoZSh0aGlzKTtcbiAgICAgICAgICBjb25zdCBjYWNoZUtleSA9IGAke25vcm1hbGl6ZWRQYXRofToke1xuICAgICAgICAgICAgaXNTZXJ2ZXJFbnYgPyBcInNlcnZlclwiIDogXCJjbGllbnRcIlxuICAgICAgICAgIH06JHtjb2RlfWA7XG4gICAgICAgICAgaWYgKGVudkNhY2hlLmhhcyhjYWNoZUtleSkpIHtcbiAgICAgICAgICAgIGlmIChydW50aW1lUmVzb2x2ZWRVc2VyT3B0aW9ucy52ZXJib3NlKSB7XG4gICAgICAgICAgICAgIHRoaXMuZW52aXJvbm1lbnQ/LmxvZ2dlcj8uaW5mbyhcbiAgICAgICAgICAgICAgICBgW3JlYWN0LSR7bmFtZX0tdHJhbnNmb3JtXSBVc2luZyBjYWNoZWQgdHJhbnNmb3JtYXRpb24gZm9yOiAke25vcm1hbGl6ZWRQYXRofSAoJHtcbiAgICAgICAgICAgICAgICAgIGlzU2VydmVyRW52ID8gXCJzZXJ2ZXJcIiA6IFwiY2xpZW50XCJcbiAgICAgICAgICAgICAgICB9KSBlbnY9JHt0aGlzLmVudmlyb25tZW50Py5uYW1lfWBcbiAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBlbnZDYWNoZS5nZXQoY2FjaGVLZXkpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIC8vIEdldCB0aGUgb3JpZ2luYWwgc291cmNlIGNvbnRlbnQgZm9yIGNvbnNpc3RlbnQgaGFzaGluZ1xuICAgICAgICAgIC8vIFJlYWQgdGhlIGZpbGUgZGlyZWN0bHkgdG8gZW5zdXJlIHdlIHVzZSB0aGUgb3JpZ2luYWwgY29udGVudCwgbm90IHRyYW5zZm9ybWVkIGNvZGVcbiAgICAgICAgICBsZXQgb3JpZ2luYWxTb3VyY2VDb250ZW50OiBzdHJpbmc7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGNvbnN0IHNvdXJjZVBhdGggPSByZXNvbHZlKHVzZXJQcm9qZWN0Um9vdCwgaWQpO1xuICAgICAgICAgICAgb3JpZ2luYWxTb3VyY2VDb250ZW50ID0gcmVhZEZpbGVTeW5jKHNvdXJjZVBhdGgsIFwidXRmLThcIik7XG4gICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICAgIC8vIEZhbGxiYWNrIHRvIHRoZSBwcm92aWRlZCBjb2RlIGlmIHdlIGNhbid0IHJlYWQgdGhlIGZpbGVcbiAgICAgICAgICAgIG9yaWdpbmFsU291cmNlQ29udGVudCA9IGNvZGU7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gUm9idXN0bHkgZGV0ZXJtaW5lIHdoZXRoZXIgdGhpcyBtb2R1bGUgaXMgYSBjbGllbnQgcmVmZXJlbmNlIGJ5IGFcbiAgICAgICAgICAvLyB0b3Atb2YtZmlsZSBgXCJ1c2UgY2xpZW50XCJgIERJUkVDVElWRSAobm90IGJ5IHRoZSBgLmNsaWVudC5gXG4gICAgICAgICAgLy8gZmlsZW5hbWUpLiBgZGV0ZWN0Q2xpZW50TW9kdWxlYCBwYXJzZXMgd2l0aCBSb2xsdXAncyBKU1gtYXdhcmVcbiAgICAgICAgICAvLyBgdGhpcy5wYXJzZWAgYW5kIHJldXNlcyBgYW5hbHl6ZURpcmVjdGl2ZXNgIGludGVybmFsbHk7IGlmIHRoZVxuICAgICAgICAgIC8vIHBhcnNlIGZhaWxzIGl0IGZhbGxzIGJhY2sgdG8gdGhlIHBhcnNlci1mcmVlIGNoYXItc2Nhbm5lci4gV2VcbiAgICAgICAgICAvLyBwYXNzIGBzb3VyY2VgIG9ubHkgKG5vIGBtb2R1bGVJZGApIHNvIHRoZSBmaWxlbmFtZSBwYXR0ZXJuIGlzXG4gICAgICAgICAgLy8gc2tpcHBlZCBoZXJlIOKAlCB0aGF0IHBhdGggaXMgaGFuZGxlZCBkb3duc3RyZWFtIGluXG4gICAgICAgICAgLy8gYGNyZWF0ZU1vZHVsZUlEYCB2aWEgdGhlIHNhbWUgaGVscGVyLlxuICAgICAgICAgIGNvbnN0IGlzQ2xpZW50QnlEaXJlY3RpdmUgPSBkZXRlY3RDbGllbnRNb2R1bGUoe1xuICAgICAgICAgICAgc291cmNlOiBjb2RlLFxuICAgICAgICAgICAgcGFyc2VGbjogKHNyYywgb3B0cykgPT4gdGhpcy5wYXJzZShzcmMsIG9wdHMpIGFzIFByb2dyYW0sXG4gICAgICAgICAgfSk7XG5cbiAgICAgICAgICAvLyBVc2UgdGhlIG9yaWdpbmFsIG5vcm1hbGl6ZWQgcGF0aCBmb3IgbW9kdWxlSUQgZnVuY3Rpb24gY2FsbHNcbiAgICAgICAgICAvLyBUaGlzIGVuc3VyZXMgcmVnaXN0ZXJDbGllbnRSZWZlcmVuY2UgY2FsbHMgdXNlIHRoZSBjb3JyZWN0IHBhdGhzLlxuICAgICAgICAgIC8vIFBhc3MgYGlzQ2xpZW50QnlEaXJlY3RpdmVgIHNvIHRoZSBtb2R1bGVJRCBmdW5jdGlvbiBhcHBsaWVzIHRoZVxuICAgICAgICAgIC8vIGhvc3RlZC1wYXRoIHRyYW5zZm9ybSAoc3RyaXAgbW9kdWxlQmFzZSDihpIgZXh0ZW5zaW9uIG1hcCDihpIgaGFzaCDihpJcbiAgICAgICAgICAvLyBtb2R1bGVCYXNlUGF0aCBwcmVmaXgpIHRvIGRpcmVjdGl2ZS1vbmx5IGNsaWVudCBtb2R1bGVzIHRoYXQgaGF2ZVxuICAgICAgICAgIC8vIG5vIGAuY2xpZW50LmAgc3VmZml4IOKAlCB0aGUgZGVmYXVsdCBtb2R1bGVJRCBjYW4ndCBwYXJzZSByYXcgVFNYIHRvXG4gICAgICAgICAgLy8gZGV0ZWN0IHRoZSBkaXJlY3RpdmUgaXRzZWxmLlxuICAgICAgICAgIGxldCBmaW5hbE1vZHVsZUlEID0gcnVudGltZVJlc29sdmVkVXNlck9wdGlvbnMubG9hZGVyPy5tb2R1bGVJRFxuICAgICAgICAgICAgPyBydW50aW1lUmVzb2x2ZWRVc2VyT3B0aW9ucy5sb2FkZXIubW9kdWxlSUQoXG4gICAgICAgICAgICAgICAgbm9ybWFsaXplZFBhdGgsXG4gICAgICAgICAgICAgICAgb3JpZ2luYWxTb3VyY2VDb250ZW50LFxuICAgICAgICAgICAgICAgIGlzQ2xpZW50QnlEaXJlY3RpdmVcbiAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgOiBub3JtYWxpemVkUGF0aDtcblxuICAgICAgICAgIC8vIENsaWVudCByZWZlcmVuY2VzIG11c3QgYmUgSE9TVEVEOiB0aGVpciBtb2R1bGVJRCBoYXMgdG8gc3RhcnQgd2l0aFxuICAgICAgICAgIC8vIHRoZSBidW5kbGVyJ3MgYmFzZVVSTCBvciByZWFjdC1zZXJ2ZXItZG9tLWVzbSdzXG4gICAgICAgICAgLy8gYHNlcmlhbGl6ZUNsaWVudFJlZmVyZW5jZWAgdGhyb3dzIFwiQXR0ZW1wdGVkIHRvIGxvYWQgYSBDbGllbnRcbiAgICAgICAgICAvLyBNb2R1bGUgb3V0c2lkZSB0aGUgaG9zdGVkIHJvb3RcIi4gVGhlIGh0bWwtd29ya2VyIHRoZW4gbWF0ZXJpYWxpemVzXG4gICAgICAgICAgLy8gZWFjaCByZWYgYnkgaW1wb3J0aW5nIGA8ZGlzdC9jbGllbnQ+Lzxtb2R1bGVJRD5gLCBzbyB0aGUgbGVhZGluZ1xuICAgICAgICAgIC8vIGAvYCBpcyB3aGF0IG1ha2VzIHRoYXQgcmVzb2x2ZSB0byBkaXNrLlxuICAgICAgICAgIC8vXG4gICAgICAgICAgLy8gVGhpcyBjb3ZlcnMgdHdvIGNhc2VzIHRoZSBkZWZhdWx0IG1vZHVsZUlEIHJldHVybnMgdW5wcmVmaXhlZDpcbiAgICAgICAgICAvLyAgIDEuIHdoaXRlbGlzdGVkIG5vZGVfbW9kdWxlcyBjbGllbnQgcGFja2FnZXMgKG5vIGAuY2xpZW50LmBcbiAgICAgICAgICAvLyAgICAgIHN1ZmZpeDsgYnVuZGxlZCB0byBgZGlzdC9jbGllbnQvbm9kZV9tb2R1bGVzLzxwa2c+L+KApmAgdmlhXG4gICAgICAgICAgLy8gICAgICBgbm9FeHRlcm5hbDogY2xpZW50UGFja2FnZXNgKSwgYW5kXG4gICAgICAgICAgLy8gICAyLiBmaXJzdC1wYXJ0eSBkaXJlY3RpdmUtb25seSBjbGllbnQgbW9kdWxlcyAobm8gYC5jbGllbnQuYFxuICAgICAgICAgIC8vICAgICAgc3VmZml4OyBlbWl0dGVkIHRvIGBkaXN0L2NsaWVudC88cGF0aD5gIGJ5IHRoZSBTU1IgYnVpbGQg4oCUXG4gICAgICAgICAgLy8gICAgICBzZWUgcmVzb2x2ZUNsaWVudFJlZmVyZW5jZXNQbHVnaW4ncyBpbnB1dCBjb2xsZWN0aW9uKS5cbiAgICAgICAgICBjb25zdCBuZWVkc0hvc3RpbmcgPSBpc1doaXRlbGlzdGVkQ2xpZW50UGFja2FnZSB8fCBpc0NsaWVudEJ5RGlyZWN0aXZlO1xuICAgICAgICAgIGlmIChcbiAgICAgICAgICAgIG5lZWRzSG9zdGluZyAmJlxuICAgICAgICAgICAgdHlwZW9mIGZpbmFsTW9kdWxlSUQgPT09IFwic3RyaW5nXCIgJiZcbiAgICAgICAgICAgICFmaW5hbE1vZHVsZUlELnN0YXJ0c1dpdGgoXCIvXCIpXG4gICAgICAgICAgKSB7XG4gICAgICAgICAgICBmaW5hbE1vZHVsZUlEID0gXCIvXCIgKyBmaW5hbE1vZHVsZUlEO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGlmIChydW50aW1lUmVzb2x2ZWRVc2VyT3B0aW9ucy52ZXJib3NlKSB7XG4gICAgICAgICAgICB0aGlzLmVudmlyb25tZW50Py5sb2dnZXI/LmluZm8oXG4gICAgICAgICAgICAgIGBbcmVhY3QtJHtuYW1lfS10cmFuc2Zvcm1dIE1vZHVsZUlEIHRyYW5zZm9ybWF0aW9uOiAke25vcm1hbGl6ZWRQYXRofSAtPiAke2ZpbmFsTW9kdWxlSUR9YFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICAvLyBEZXRlcm1pbmUgaWYgdGhpcyBpcyBhIHNlcnZlciBlbnZpcm9ubWVudFxuICAgICAgICAgIC8vIENoZWNrIGJvdGggdGhlIGVudmlyb25tZW50IG5hbWUgYW5kIGlmIHdlJ3JlIGRvaW5nIHNlcnZlci1zaWRlIHJlbmRlcmluZyBmb3Igc3RhdGljIGdlbmVyYXRpb25cbiAgICAgICAgICBjb25zdCBlbnZOYW1lID0gdGhpcy5lbnZpcm9ubWVudD8ubmFtZT8udG9Mb3dlckNhc2UoKSB8fCBcIlwiO1xuICAgICAgICAgIGNvbnN0IGlzU2VydmVyRW52aXJvbm1lbnQgPSBlbnZOYW1lID09PSBcInNlcnZlclwiIHx8IGVudk5hbWUgPT09IFwicnNjXCIgfHwgZW52TmFtZSA9PT0gXCJyZWFjdC1zZXJ2ZXJcIjtcblxuICAgICAgICAgIGNvbnN0IHRyYW5zZm9ybWVyID0gY3JlYXRlVHJhbnNmb3JtZXIoe1xuICAgICAgICAgICAgcGFyc2VGbjogKHNvdXJjZSkgPT4ge1xuICAgICAgICAgICAgICBjb25zdCBhc3QgPSB0aGlzLnBhcnNlKHNvdXJjZSwge1xuICAgICAgICAgICAgICAgIGFsbG93UmV0dXJuT3V0c2lkZUZ1bmN0aW9uOiB0cnVlLFxuICAgICAgICAgICAgICAgIGpzeDogdHJ1ZSxcbiAgICAgICAgICAgICAgfSkgYXMgUHJvZ3JhbTtcbiAgICAgICAgICAgICAgcmV0dXJuIGFzdDtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBvcHRpb25zOiB7XG4gICAgICAgICAgICAgIGxvYWRlcjogcnVudGltZVJlc29sdmVkVXNlck9wdGlvbnMubG9hZGVyLFxuICAgICAgICAgICAgICB2ZXJib3NlOiBydW50aW1lUmVzb2x2ZWRVc2VyT3B0aW9ucy52ZXJib3NlLFxuICAgICAgICAgICAgICBwYW5pY1RocmVzaG9sZDogcnVudGltZVJlc29sdmVkVXNlck9wdGlvbnMucGFuaWNUaHJlc2hvbGQsXG4gICAgICAgICAgICAgIGxvZ2dlcjogdGhpcy5lbnZpcm9ubWVudD8ubG9nZ2VyLFxuICAgICAgICAgICAgICBtb2R1bGVCYXNlOiB1c2VyT3B0aW9ucy5tb2R1bGVCYXNlID8/IFwiXCIsXG4gICAgICAgICAgICAgIC8vIFZpdGUgaW5qZWN0cyBwcmVhbWJsZSAoZS5nLiBfX3ZpdGVQcmVsb2FkIGZvciBkeW5hbWljIGltcG9ydHMpXG4gICAgICAgICAgICAgIC8vIGFib3ZlIGEgbW9kdWxlJ3Mgb3duIHNvdXJjZTsgZG9uJ3QgZmxhZyBpdCBhcyBjb2RlLWJlZm9yZS1kaXJlY3RpdmUuXG4gICAgICAgICAgICAgIHRvbGVyYXRlTGVhZGluZ0NvZGU6IGlzVml0ZUluamVjdGVkQ29kZSxcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIC8vIFBhc3MgdGhlIGFjdHVhbCBlbnZpcm9ubWVudCBjb250ZXh0IHRvIHRoZSB0cmFuc2Zvcm1lclxuICAgICAgICAgICAgLy8gT25seSB0aGUgYWN0dWFsIFwic2VydmVyXCIgZW52aXJvbm1lbnQgc2hvdWxkIHRyYW5zZm9ybSBjbGllbnQgY29tcG9uZW50cyB0byByZWdpc3RlckNsaWVudFJlZmVyZW5jZVxuICAgICAgICAgICAgLy8gU1NSIGVudmlyb25tZW50IG5lZWRzIGFjdHVhbCBSZWFjdCBjb21wb25lbnRzLCBub3QgcGxhY2Vob2xkZXJzXG4gICAgICAgICAgICBpc1NlcnZlckVudmlyb25tZW50OiBpc1NlcnZlckVudmlyb25tZW50LFxuICAgICAgICAgICAgc3NyOiBzc3IsXG4gICAgICAgICAgfSk7XG5cbiAgICAgICAgICAvLyBTa2lwIGZpbGVzIGZyb20gb3V0cHV0IGRpcmVjdG9yaWVzIHRoYXQgYXJlIGFscmVhZHkgYnVpbHQgYW5kIHRyYW5zZm9ybWVkXG4gICAgICAgICAgLy8gQnV0IGFsbG93IHRyYW5zZm9ybWF0aW9uIG9mIHNlcnZlci1idWlsdCBjbGllbnQgY29tcG9uZW50cyB0aGF0IG5lZWQgcmVnaXN0ZXJDbGllbnRSZWZlcmVuY2VcblxuICAgICAgICAgIGlmIChcbiAgICAgICAgICAgIGlzRnJvbVNlcnZlckJ1aWxkIHx8XG4gICAgICAgICAgICBpc0Zyb21DbGllbnRCdWlsZCB8fFxuICAgICAgICAgICAgaXNGcm9tU3RhdGljQnVpbGQgfHxcbiAgICAgICAgICAgIGlzQnVpbHRGaWxlXG4gICAgICAgICAgKSB7XG4gICAgICAgICAgICBjb25zdCBidWlsZFR5cGUgPSBpc0Zyb21TZXJ2ZXJCdWlsZFxuICAgICAgICAgICAgICA/IFwic2VydmVyXCJcbiAgICAgICAgICAgICAgOiBpc0Zyb21DbGllbnRCdWlsZFxuICAgICAgICAgICAgICA/IFwiY2xpZW50XCJcbiAgICAgICAgICAgICAgOiBpc0Zyb21TdGF0aWNCdWlsZFxuICAgICAgICAgICAgICA/IFwic3RhdGljXCJcbiAgICAgICAgICAgICAgOiBcImJ1aWx0XCI7XG5cbiAgICAgICAgICAgIC8vIEFsbG93IHRyYW5zZm9ybWF0aW9uIG9mIHNlcnZlci1idWlsdCBjbGllbnQgY29tcG9uZW50c1xuICAgICAgICAgICAgaWYgKFxuICAgICAgICAgICAgICBpc0Zyb21TZXJ2ZXJCdWlsZCAmJlxuICAgICAgICAgICAgICBydW50aW1lUmVzb2x2ZWRVc2VyT3B0aW9ucy5sb2FkZXI/LmlzQ2xpZW50Q29tcG9uZW50QnlOYW1lPy4oaWQpXG4gICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgaWYgKHJ1bnRpbWVSZXNvbHZlZFVzZXJPcHRpb25zLnZlcmJvc2UpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmVudmlyb25tZW50Py5sb2dnZXI/LmluZm8oXG4gICAgICAgICAgICAgICAgICBgW3JlYWN0LSR7bmFtZX0tdHJhbnNmb3JtXSBBbGxvd2luZyB0cmFuc2Zvcm1hdGlvbiBvZiBzZXJ2ZXItYnVpbHQgY2xpZW50IGNvbXBvbmVudDogJHtpZH1gXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAvLyBEb24ndCBza2lwIC0gbGV0IGl0IGZhbGwgdGhyb3VnaCB0byB0cmFuc2Zvcm1lclxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgaWYgKHJ1bnRpbWVSZXNvbHZlZFVzZXJPcHRpb25zLnZlcmJvc2UpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmVudmlyb25tZW50Py5sb2dnZXI/LmluZm8oXG4gICAgICAgICAgICAgICAgICBgW3JlYWN0LSR7bmFtZX0tdHJhbnNmb3JtXSBTa2lwcGluZyBidWlsdCBmaWxlIGZyb20gJHtidWlsZFR5cGV9IGJ1aWxkOiAke2lkfWBcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgY29kZTogY29kZSxcbiAgICAgICAgICAgICAgICBtYXA6IG51bGwsXG4gICAgICAgICAgICAgIH07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgY29uc3QgdHJhbnNmb3JtUmVzdWx0ID0gYXdhaXQgdHJhbnNmb3JtZXIoXG4gICAgICAgICAgICBjb2RlLFxuICAgICAgICAgICAgbm9ybWFsaXplZFBhdGgsXG4gICAgICAgICAgICBmaW5hbE1vZHVsZUlEXG4gICAgICAgICAgKTtcblxuICAgICAgICAgIC8vIElmIHRyYW5zZm9ybWVyIHJldHVybnMgbnVsbCAoZS5nLiwgZm9yIGJ1aWx0IGZpbGVzKSwgcmV0dXJuIG9yaWdpbmFsIGNvZGVcbiAgICAgICAgICBpZiAoIXRyYW5zZm9ybVJlc3VsdCkge1xuICAgICAgICAgICAgcmV0dXJuIHsgY29kZSwgbWFwOiBudWxsIH07XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgY29uc3QgeyBjb2RlOiB0cmFuc2Zvcm1lZCwgbWFwIH0gPSB0cmFuc2Zvcm1SZXN1bHQ7XG5cbiAgICAgICAgICAvLyBTdG9yZSB0aGUgdHJhbnNmb3JtYXRpb24gcmVzdWx0IGluIHBlci1lbnZpcm9ubWVudCBjYWNoZVxuICAgICAgICAgIGNvbnN0IHJlc3VsdCA9IHsgY29kZTogdHJhbnNmb3JtZWQsIG1hcCB9O1xuICAgICAgICAgIGVudkNhY2hlLnNldChjYWNoZUtleSwgcmVzdWx0KTtcblxuICAgICAgICAgIC8vIExvZ2dpbmcgZm9yIHZlcmJvc2UgbW9kZVxuICAgICAgICAgIGlmIChydW50aW1lUmVzb2x2ZWRVc2VyT3B0aW9ucy52ZXJib3NlKSB7XG4gICAgICAgICAgICBjb25zdCBoYXNEaXJlY3RpdmVzID1cbiAgICAgICAgICAgICAgY29kZS5pbmNsdWRlcygnXCJ1c2UgY2xpZW50XCInKSB8fFxuICAgICAgICAgICAgICBjb2RlLmluY2x1ZGVzKCdcInVzZSBzZXJ2ZXJcIicpIHx8XG4gICAgICAgICAgICAgIGNvZGUuaW5jbHVkZXMoXCIndXNlIGNsaWVudCdcIikgfHxcbiAgICAgICAgICAgICAgY29kZS5pbmNsdWRlcyhcIid1c2Ugc2VydmVyJ1wiKTtcblxuICAgICAgICAgICAgaWYgKHRyYW5zZm9ybWVkICE9PSBjb2RlKSB7XG4gICAgICAgICAgICAgIHRoaXMuZW52aXJvbm1lbnQ/LmxvZ2dlcj8uaW5mbyhcbiAgICAgICAgICAgICAgICBgW3JlYWN0LSR7bmFtZX0tdHJhbnNmb3JtXSBgICtcbiAgICAgICAgICAgICAgICAgIGlkLnNwbGl0KFwiL1wiKS5wb3AoKSArXG4gICAgICAgICAgICAgICAgICAoY29kZS5zdGFydHNXaXRoKCdcInVzZSBjbGllbnRcIicpID8gXCIgKGNsaWVudClcIiA6IFwiXCIpICtcbiAgICAgICAgICAgICAgICAgIChoYXNEaXJlY3RpdmVzID8gXCIgKGRpcmVjdGl2ZXMgcHJvY2Vzc2VkKVwiIDogXCJcIilcbiAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgdGhpcy5lbnZpcm9ubWVudD8ubG9nZ2VyPy5pbmZvKFxuICAgICAgICAgICAgICAgIGBbcmVhY3QtJHtuYW1lfS10cmFuc2Zvcm1dIGAgKyB0cmFuc2Zvcm1lZC5zbGljZSgwLCAxMDApICsgXCIuLi5cIlxuICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfSBlbHNlIGlmIChoYXNEaXJlY3RpdmVzKSB7XG4gICAgICAgICAgICAgIHRoaXMuZW52aXJvbm1lbnQ/LmxvZ2dlcj8uaW5mbyhcbiAgICAgICAgICAgICAgICBgW3JlYWN0LSR7bmFtZX0tdHJhbnNmb3JtXSBgICtcbiAgICAgICAgICAgICAgICAgIGlkLnNwbGl0KFwiL1wiKS5wb3AoKSArXG4gICAgICAgICAgICAgICAgICBcIiAoZGlyZWN0aXZlcyBhbHJlYWR5IHByb2Nlc3NlZClcIlxuICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cblxuICAgICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgIH0gYXMgUGx1Z2luO1xuICB9O1xufTtcbiJdLCJuYW1lcyI6WyJuYW1lIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBbUNhLE1BQUEsdUJBQUEsR0FBMEIsQ0FDckMsT0FDaUIsS0FBQTtBQUNqQixFQUFBLE9BQU8sQ0FBQyxXQUFnQixLQUFBO0FBQ3RCLElBQU0sTUFBQSxFQUFFLE1BQVMsR0FBQSxPQUFBO0FBSWpCLElBQUEsTUFBTSxtQkFBc0IsR0FBQSxtQkFBQSxDQUUxQixzQkFBTSxJQUFJLEtBQUssQ0FBQTtBQUNqQixJQUFBLE1BQU0sa0JBQ0osR0FBQSxPQUFBLENBQVEsa0JBQXVCLEtBQUEsSUFBQSxLQUFTLFdBQVcsUUFBVyxHQUFBLFFBQUEsQ0FBQTtBQUNoRSxJQUFNLE1BQUEsbUJBQUEsR0FDSixRQUFRLG1CQUNQLEtBQUEsSUFBQSxLQUFTLFdBQ04sa0JBQXVCLEtBQUEsUUFBQSxHQUNyQixDQUFDLFFBQVUsRUFBQSxLQUFLLElBQ2hCLENBQUMsUUFBUSxJQUNYLGtCQUF1QixLQUFBLFFBQUEsR0FDdkIsQ0FBQyxRQUFVLEVBQUEsS0FBSyxDQUNoQixHQUFBLENBQUMsUUFBUSxDQUFBLENBQUE7QUFDZixJQUFBLE1BQU0sU0FBWSxHQUFBLENBQUEsb0NBQUEsRUFBdUMsa0JBQWtCLENBQUEsSUFBQSxFQUFPLElBQUksQ0FBQSxDQUFBLENBQUE7QUFFdEYsSUFBTSxNQUFBLHFCQUFBLEdBQXdCLGVBQWUsV0FBVyxDQUFBO0FBQ3hELElBQUEsSUFBSSxzQkFBc0IsSUFBUyxLQUFBLE9BQUE7QUFDakMsTUFBQSxNQUFNLHFCQUFzQixDQUFBLEtBQUE7QUFDOUIsSUFBTSxNQUFBLEVBQUUsV0FBYSxFQUFBLG1CQUFBLEVB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