UNPKG

cdk-nextjs

Version:

Deploy Next.js apps on AWS with CDK

243 lines 47.3 kB
"use strict"; var _a; Object.defineProperty(exports, "__esModule", { value: true }); exports.NextjsBuild = void 0; const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti"); const node_child_process_1 = require("node:child_process"); const node_fs_1 = require("node:fs"); const node_path_1 = require("node:path"); const posix_1 = require("node:path/posix"); const aws_cdk_lib_1 = require("aws-cdk-lib"); const aws_ecr_assets_1 = require("aws-cdk-lib/aws-ecr-assets"); const aws_lambda_1 = require("aws-cdk-lib/aws-lambda"); const constructs_1 = require("constructs"); const constants_1 = require("../constants"); /** * Builds Next.js assets. * @link https://nextjs.org/docs/pages/api-reference/next-config-js/output */ class NextjsBuild extends constructs_1.Construct { constructor(scope, id, props) { super(scope, id); /** * Repository name for the builder image. */ this.builderImageRepo = "cdk-nextjs/builder"; this.containerRuntime = process.env.CDK_DOCKER || "docker"; this.builderImageAlias = `${this.builderImageRepo}:${this.node.addr.slice(30)}`; this.relativePathToPackage = props.relativePathToPackage || "."; this.props = props; this.relativePathToEntrypoint = this.getRelativeEntrypointPath(); if (!props.builderImageProps?.skipBuild) { this.createBuilderImage(); } this.buildImageDigest = this.getBuilderImageDigest(); this.buildId = this.getBuildId(); this.publicDirEntries = this.getPublicDirEntries(); if (props.nextjsType === constants_1.NextjsType.GLOBAL_CONTAINERS || props.nextjsType === constants_1.NextjsType.REGIONAL_CONTAINERS) { this.imageForNextjsContainers = this.createImageForNextjsContainers(); } else { this.imageForNextjsFunctions = this.createImageForNextjsFunctions(); } this.imageForNextjsAssetsDeployment = this.createImageForNextjsAssetsDeployment(); } getRelativeEntrypointPath() { // joinPosix b/c this will be used in linux container return (0, posix_1.join)(this.props.relativePathToPackage || "", "server.js"); } /** * A builder or base image needs to be created so that the same image can be * built `FROM` for `NextjsFunctions` or `NextjsContainers` and `NextjsAssetsDeployment`. * This image doesn't need to be uploaded to ECR so we're "manually" creating * it with `execSync` and other images will be built `FROM` it. */ createBuilderImage() { const buildCommand = this.props.buildCommand || "npm run build"; const { buildArgs = { BUILD_COMMAND: buildCommand, RELATIVE_PATH_TO_PACKAGE: this.relativePathToPackage, ...this.props.builderImageProps?.buildArgs, }, envVarNames = [], exclude = [ "**/node_modules", ".git", "**/cdk.out", "**/.next", ".gitignore", "*.md", ], file = "builder.Dockerfile", platform, } = this.props.builderImageProps || {}; // to be added to user provided build context before builder image is built const filePathsToCopy = [ (0, node_path_1.join)(__dirname, "cdk-nextjs-cache-handler.cjs"), ]; // to be removed from user provided build context after builder image is built const filePathsToRemove = [ (0, node_path_1.join)(this.props.buildContext, "cdk-nextjs-cache-handler.cjs"), ]; // if custom file (Dockerfile) is not specified then use library's default builder.Dockerfile + .dockerignore if (!this.props.builderImageProps?.file) { filePathsToCopy.push((0, node_path_1.join)(__dirname, file)); filePathsToRemove.push((0, node_path_1.join)(this.props.buildContext, file)); const excludeFileStr = exclude?.join("\n"); const dockerignoreFilePath = (0, node_path_1.join)(this.props.buildContext, ".dockerignore"); (0, node_fs_1.writeFileSync)(dockerignoreFilePath, excludeFileStr); filePathsToRemove.push(dockerignoreFilePath); } for (const filePathToCopy of filePathsToCopy) { (0, node_fs_1.cpSync)(filePathToCopy, (0, node_path_1.join)(this.props.buildContext, (0, node_path_1.basename)(filePathToCopy))); } const buildArgsStr = this.createBuildArgStr(buildArgs); this.injectBuilderDockerfileEnvVars((0, node_path_1.join)(this.props.buildContext, file), envVarNames); const command = this.props.builderImageProps?.command || `${this.containerRuntime} build ${platform ? `--platform ${platform.platform}` : ""} --file ${file} --tag ${this.builderImageAlias} ${buildArgsStr} .`; let error; try { console.log(`Building image with command: ${command} in directory: ${this.props.buildContext}`); (0, node_child_process_1.execSync)(command, { stdio: "inherit", cwd: this.props.buildContext, env: process.env, }); } catch (err) { error = err; } finally { for (const filePathToRemove of filePathsToRemove) { (0, node_fs_1.rmSync)(filePathToRemove); } } if (error) throw error; } injectBuilderDockerfileEnvVars(builderDockerfilePath, envVarNames) { const envVars = {}; for (const envVarName of envVarNames) { if (process.env[envVarName]) { envVars[envVarName] = process.env[envVarName]; } } const content = Object.entries(envVars) .map(([name, value]) => `${name}="${value}"`) .join(" "); const oldFile = (0, node_fs_1.readFileSync)(builderDockerfilePath).toString(); const newFile = oldFile.replace(constants_1.INJECT_CDK_NEXTJS_BUILD_ENV_VARS, content); (0, node_fs_1.writeFileSync)(builderDockerfilePath, newFile); } createBuildArgStr(buildArgs) { return Object.entries(buildArgs).reduce((acc, [key, value]) => { return `${acc} --build-arg ${key}="${value}"`; }, ""); } getBuilderImageDigest() { const digest = (0, node_child_process_1.execSync)(`${this.containerRuntime} images --no-trunc --quiet ${this.builderImageAlias}`, { encoding: "utf-8" }); return digest.slice(0, -1); // remove trailing \n } getPublicDirEntries() { const publicDirPath = (0, posix_1.join)("/app", this.props.relativePathToPackage || "", "public"); if ((0, node_fs_1.existsSync)(publicDirPath)) { const publicDirEntriesString = (0, node_child_process_1.execSync)(`${this.containerRuntime} run ${this.builderImageAlias} node -e "console.log(JSON.stringify(fs.readdirSync('${publicDirPath}', { withFileTypes: true }).map((e) => ({ name: e.name, isDirectory: e.isDirectory()}))))"`, { encoding: "utf-8" }); return JSON.parse(publicDirEntriesString); } else { return []; } } getBuildId() { const buildIdPath = (0, posix_1.join)("/app", this.props.relativePathToPackage || "", ".next", "BUILD_ID"); const buildId = (0, node_child_process_1.execSync)(`${this.containerRuntime} run ${this.builderImageAlias} /bin/sh -c "cat ${buildIdPath}"`, { encoding: "utf-8" }); return buildId; } createImageForNextjsContainers() { const dockerfileNamePrefix = this.props.nextjsType === constants_1.NextjsType.GLOBAL_CONTAINERS ? "global" : "regional"; const dockerfileName = `${dockerfileNamePrefix}-containers.Dockerfile`; // cdk-nextjs/builder-{hash} already contains built nextjs app which we'll // `COPY --from=cdk-nextjs/builder-{hash}` so we just need the Dockerfile // which is in lib/nextjs-build folder. const buildContext = this.props.overrides?.containersImageBuildContext ?? (0, node_path_1.join)(__dirname, "..", "..", "lib", "nextjs-build"); const dockerImageAsset = new aws_ecr_assets_1.DockerImageAsset(this, "Image", { directory: buildContext, extraHash: this.buildImageDigest, // rebuild when builder hash changes file: dockerfileName, ignoreMode: aws_cdk_lib_1.IgnoreMode.DOCKER, ...this.props.overrides?.nextjsContainersDockerImageAssetProps, buildArgs: { [constants_1.BUILD_ID_ARG_NAME]: this.buildId, [constants_1.BUILDER_IMAGE_ALIAS_ARG_NAME]: this.builderImageAlias, [constants_1.CACHE_PATH_ARG_NAME]: constants_1.CACHE_PATH, [constants_1.DATA_CACHE_PATH_ARG_NAME]: constants_1.DATA_CACHE_PATH, [constants_1.PUBLIC_PATH_ARG_NAME]: constants_1.PUBLIC_PATH, [constants_1.IMAGE_CACHE_PATH_ARG_NAME]: constants_1.IMAGE_CACHE_PATH, [constants_1.MOUNT_PATH_ARG_NAME]: constants_1.MOUNT_PATH, [constants_1.RELATIVE_PATH_TO_PACKAGE_ARG_NAME]: this.relativePathToPackage, ...this.props.overrides?.nextjsContainersDockerImageAssetProps ?.buildArgs, }, }); return dockerImageAsset; } createImageForNextjsFunctions() { const dockerfileName = "global-functions.Dockerfile"; // cdk-nextjs/builder-{hash} already contains built nextjs app which we'll // `COPY --from=cdk-nextjs/builder-{hash}` so we just need the Dockerfile // which is in lib/nextjs-build folder. const buildContext = this.props.overrides?.functionsImageBuildContext ?? (0, node_path_1.join)(__dirname, "..", "..", "lib", "nextjs-build"); const dockerImageCode = aws_lambda_1.DockerImageCode.fromImageAsset(buildContext, { cmd: ["node", this.relativePathToEntrypoint], extraHash: this.buildImageDigest, // rebuild when builder hash changes file: dockerfileName, ignoreMode: aws_cdk_lib_1.IgnoreMode.DOCKER, ...this.props.overrides?.nextjsFunctionsAssetImageCodeProps, buildArgs: { [constants_1.BUILD_ID_ARG_NAME]: this.buildId, [constants_1.BUILDER_IMAGE_ALIAS_ARG_NAME]: this.builderImageAlias, [constants_1.CACHE_PATH_ARG_NAME]: constants_1.CACHE_PATH, [constants_1.DATA_CACHE_PATH_ARG_NAME]: constants_1.DATA_CACHE_PATH, [constants_1.PUBLIC_PATH_ARG_NAME]: constants_1.PUBLIC_PATH, [constants_1.IMAGE_CACHE_PATH_ARG_NAME]: constants_1.IMAGE_CACHE_PATH, [constants_1.MOUNT_PATH_ARG_NAME]: constants_1.MOUNT_PATH, [constants_1.RELATIVE_PATH_TO_PACKAGE_ARG_NAME]: this.relativePathToPackage, ...this.props.overrides?.nextjsFunctionsAssetImageCodeProps?.buildArgs, }, }); // TODO: how to clean up temp dir? // rmSync(tempDir, { recursive: true }); return dockerImageCode; } createImageForNextjsAssetsDeployment() { const dockerfileName = "assets-deployment.Dockerfile"; /** * Path to bundled custom resource code */ const buildContext = this.props.overrides?.assetsDeploymentImageBuildContext ?? (0, node_path_1.join)(__dirname, "..", "..", "assets", "lambdas", "assets-deployment", "assets-deployment.lambda"); // cdk-nextjs/builder-{hash} already contains Next.js built code which // we'll copy into final image. But we also need lambda code to run // asset deployment tasks const dockerImageCode = aws_lambda_1.DockerImageCode.fromImageAsset(buildContext, { extraHash: this.buildImageDigest, // rebuild when builder hash changes file: dockerfileName, ignoreMode: aws_cdk_lib_1.IgnoreMode.DOCKER, ...this.props.overrides?.nextjsAssetDeploymentAssetImageCodeProps, buildArgs: { [constants_1.BUILD_ID_ARG_NAME]: this.buildId, [constants_1.BUILDER_IMAGE_ALIAS_ARG_NAME]: this.builderImageAlias, [constants_1.PUBLIC_PATH_ARG_NAME]: constants_1.PUBLIC_PATH, [constants_1.RELATIVE_PATH_TO_PACKAGE_ARG_NAME]: this.relativePathToPackage, ...this.props.overrides?.nextjsAssetDeploymentAssetImageCodeProps ?.buildArgs, }, }); return dockerImageCode; } } exports.NextjsBuild = NextjsBuild; _a = JSII_RTTI_SYMBOL_1; NextjsBuild[_a] = { fqn: "cdk-nextjs.NextjsBuild", version: "0.4.10" }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmV4dGpzLWJ1aWxkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL25leHRqcy1idWlsZC9uZXh0anMtYnVpbGQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSwyREFBOEM7QUFDOUMscUNBTWlCO0FBQ2pCLHlDQUEyQztBQUMzQywyQ0FBb0Q7QUFDcEQsNkNBQXlDO0FBQ3pDLCtEQUF3RTtBQUN4RSx1REFBOEU7QUFDOUUsMkNBQXVDO0FBQ3ZDLDRDQWdCc0I7QUEwR3RCOzs7R0FHRztBQUNILE1BQWEsV0FBWSxTQUFRLHNCQUFTO0lBb0R4QyxZQUFZLEtBQWdCLEVBQUUsRUFBVSxFQUFFLEtBQXVCO1FBQy9ELEtBQUssQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFWbkI7O1dBRUc7UUFDSyxxQkFBZ0IsR0FBRyxvQkFBb0IsQ0FBQztRQUV4QyxxQkFBZ0IsR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFDLFVBQVUsSUFBSSxRQUFRLENBQUM7UUFNNUQsSUFBSSxDQUFDLGlCQUFpQixHQUFHLEdBQUcsSUFBSSxDQUFDLGdCQUFnQixJQUFJLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDO1FBQ2hGLElBQUksQ0FBQyxxQkFBcUIsR0FBRyxLQUFLLENBQUMscUJBQXFCLElBQUksR0FBRyxDQUFDO1FBQ2hFLElBQUksQ0FBQyxLQUFLLEdBQUcsS0FBSyxDQUFDO1FBQ25CLElBQUksQ0FBQyx3QkFBd0IsR0FBRyxJQUFJLENBQUMseUJBQXlCLEVBQUUsQ0FBQztRQUNqRSxJQUFJLENBQUMsS0FBSyxDQUFDLGlCQUFpQixFQUFFLFNBQVMsRUFBRSxDQUFDO1lBQ3hDLElBQUksQ0FBQyxrQkFBa0IsRUFBRSxDQUFDO1FBQzVCLENBQUM7UUFDRCxJQUFJLENBQUMsZ0JBQWdCLEdBQUcsSUFBSSxDQUFDLHFCQUFxQixFQUFFLENBQUM7UUFDckQsSUFBSSxD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U3luYyB9IGZyb20gXCJub2RlOmNoaWxkX3Byb2Nlc3NcIjtcbmltcG9ydCB7XG4gIGNwU3luYyxcbiAgZXhpc3RzU3luYyxcbiAgcmVhZEZpbGVTeW5jLFxuICBybVN5bmMsXG4gIHdyaXRlRmlsZVN5bmMsXG59IGZyb20gXCJub2RlOmZzXCI7XG5pbXBvcnQgeyBiYXNlbmFtZSwgam9pbiB9IGZyb20gXCJub2RlOnBhdGhcIjtcbmltcG9ydCB7IGpvaW4gYXMgam9pblBvc2l4IH0gZnJvbSBcIm5vZGU6cGF0aC9wb3NpeFwiO1xuaW1wb3J0IHsgSWdub3JlTW9kZSB9IGZyb20gXCJhd3MtY2RrLWxpYlwiO1xuaW1wb3J0IHsgRG9ja2VySW1hZ2VBc3NldCwgUGxhdGZvcm0gfSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWVjci1hc3NldHNcIjtcbmltcG9ydCB7IEFzc2V0SW1hZ2VDb2RlUHJvcHMsIERvY2tlckltYWdlQ29kZSB9IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtbGFtYmRhXCI7XG5pbXBvcnQgeyBDb25zdHJ1Y3QgfSBmcm9tIFwiY29uc3RydWN0c1wiO1xuaW1wb3J0IHtcbiAgQlVJTERFUl9JTUFHRV9BTElBU19BUkdfTkFNRSxcbiAgTU9VTlRfUEFUSCxcbiAgSU1BR0VfQ0FDSEVfUEFUSCxcbiAgSU1BR0VfQ0FDSEVfUEFUSF9BUkdfTkFNRSxcbiAgTU9VTlRfUEFUSF9BUkdfTkFNRSxcbiAgTmV4dGpzVHlwZSxcbiAgUFVCTElDX1BBVEgsXG4gIFBVQkxJQ19QQVRIX0FSR19OQU1FLFxuICBSRUxBVElWRV9QQVRIX1RPX1BBQ0tBR0VfQVJHX05BTUUsXG4gIEJVSUxEX0lEX0FSR19OQU1FLFxuICBEQVRBX0NBQ0hFX1BBVEhfQVJHX05BTUUsXG4gIERBVEFfQ0FDSEVfUEFUSCxcbiAgQ0FDSEVfUEFUSCxcbiAgQ0FDSEVfUEFUSF9BUkdfTkFNRSxcbiAgSU5KRUNUX0NES19ORVhUSlNfQlVJTERfRU5WX1ZBUlMsXG59IGZyb20gXCIuLi9jb25zdGFudHNcIjtcbmltcG9ydCB7IE9wdGlvbmFsRG9ja2VySW1hZ2VBc3NldFByb3BzIH0gZnJvbSBcIi4uL2dlbmVyYXRlZC1zdHJ1Y3RzL09wdGlvbmFsRG9ja2VySW1hZ2VBc3NldFByb3BzXCI7XG5pbXBvcnQgeyBOZXh0anNCYXNlUHJvcHMgfSBmcm9tIFwiLi4vcm9vdC1jb25zdHJ1Y3RzL25leHRqcy1iYXNlLWNvbnN0cnVjdFwiO1xuXG5leHBvcnQgaW50ZXJmYWNlIEJ1aWxkZXJJbWFnZVByb3BzIHtcbiAgLyoqXG4gICAqIEJ1aWxkIEFyZ3MgdG8gYmUgcGFzc2VkIHRvIGBkb2NrZXIgYnVpbGRgIGNvbW1hbmQuXG4gICAqIEBzZWUgaHR0cHM6Ly9kb2NzLmRvY2tlci5jb20vYnVpbGQvYnVpbGRpbmcvdmFyaWFibGVzLyNidWlsZC1hcmd1bWVudHNcbiAgICovXG4gIHJlYWRvbmx5IGJ1aWxkQXJncz86IFJlY29yZDxzdHJpbmcsIHN0cmluZz47XG4gIC8qKlxuICAgKiBgZG9ja2VyIGJ1aWxkIC4uLmAgY29tbWFuZCB0byBydW4gaW4ge0BsaW5rIE5leHRCYXNlUHJvcHMuYnVpbGRDb250ZXh0fS5cbiAgICogRGVmYXVsdCBpbnRlcnBvbGF0ZXMgb3RoZXIgcHJvcHMuIElmIHlvdSBvdmVycmlkZSwgb3RoZXIgcHJvcHMgd2lsbCBoYXZlXG4gICAqIG5vIGVmZmVjdCBvbiBjb21tYW5kLlxuICAgKi9cbiAgcmVhZG9ubHkgY29tbWFuZD86IHN0cmluZztcbiAgLyoqXG4gICAqIEVudmlyb25tZW50IHZhcmlhYmxlcyBuYW1lcyB0byBwYXNzIGZyb20gaG9zdCB0byBjb250YWluZXIgZHVyaW5nIGJ1aWxkIHByb2Nlc3MuXG4gICAqXG4gICAqIFRoZXNlIHZhcmlhYmxlIG5hbWVzIHdpbGwgYmUgc2V0IGJlZm9yZSB0aGUgYnVpbGQgY29tbWFuZCBpbiBidWlsZGVyLkRvY2tlcmZpbGVcbiAgICogbGlrZTogYEFQSV9LRVk9XCJNWV9BUElfS0VZXCIgbnBtIHJ1biBidWlsZGBcbiAgICpcbiAgICogQGV4YW1wbGUgW1wiTVlfQVBJX0tFWVwiXVxuICAgKi9cbiAgcmVhZG9ubHkgZW52VmFyTmFtZXM/OiBzdHJpbmdbXTtcbiAgLyoqXG4gICAqIExpbmVzIGluIC5kb2NrZXJpZ25vcmUgZmlsZSB3aGljaCB3aWxsIGJlIGNyZWF0ZWQgaW4geW91ciB7QGxpbmsgTmV4dEJhc2VQcm9wcy5idWlsZENvbnRleHR9XG4gICAqIEBkZWZhdWx0IFtcIm5vZGVfbW9kdWxlc1wiLCBcIi5naXRcIiwgXCIuZ2l0aWdub3JlXCIsIFwiLm1kXCJdXG4gICAqL1xuICByZWFkb25seSBleGNsdWRlPzogc3RyaW5nW107XG4gIC8qKlxuICAgKiBOYW1lIG9mIERvY2tlcmZpbGUgaW4gYnVpbGRlciBidWlsZCBjb250ZXh0LiBJZiBzcGVjaWZpZWQsIHlvdSBhcmUgcmVzcG9uc2libGVcbiAgICogZm9yIGVuc3VyaW5nIGl0IGV4aXN0cyBpbiBidWlsZCBjb250ZXh0IGJlZm9yZSBjb25zdHJ1Y3QgaXMgaW5zdGFudGlhdGVkLlxuICAgKiBAZGVmYXVsdCBcImJ1aWxkZXIuRG9ja2VyZmlsZVwiXG4gICAqL1xuICByZWFkb25seSBmaWxlPzogc3RyaW5nO1xuICByZWFkb25seSBwbGF0Zm9ybT86IFBsYXRmb3JtO1xuICAvKipcbiAgICogU2tpcCBidWlsZGluZyB0aGUgYnVpbGRlciBpbWFnZS5cbiAgICogQGRlZmF1bHQgZmFsc2VcbiAgICovXG4gIHJlYWRvbmx5IHNraXBCdWlsZD86IGJvb2xlYW47XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgTmV4dGpzQnVpbGRPdmVycmlkZXMge1xuICByZWFkb25seSBuZXh0anNDb250YWluZXJzRG9ja2VySW1hZ2VBc3NldFByb3BzPzogT3B0aW9uYWxEb2NrZXJJbWFnZUFzc2V0UHJvcHM7XG4gIHJlYWRvbmx5IG5leHRqc0Z1bmN0aW9uc0Fzc2V0SW1hZ2VDb2RlUHJvcHM/OiBBc3NldEltYWdlQ29kZVByb3BzO1xuICByZWFkb25seSBuZXh0anNBc3NldERlcGxveW1lbnRBc3NldEltYWdlQ29kZVByb3BzPzogQXNzZXRJbWFnZUNvZGVQcm9wcztcbiAgLyoqXG4gICAqIERlZmF1bHQgZm9sZGVyIGZvciBidWlsZCBjb250ZXh0IGlzIHRoZSBcImxpYi9uZXh0anMtYnVpbGRcIiBmb2xkZXIgaW4gdGhlXG4gICAqIGluc3RhbGxlZCBjZGstbmV4dGpzIGxpYnJhcnkgd2hpY2ggaGFzIHRoZSBcImdsb2JhbC1mdW5jdGlvbnMuRG9ja2VyZmlsZVwiLlxuICAgKiBOb3RlLCBpZiB5b3Ugc3BlY2lmeSB0aGlzIHRoZW4geW91J3JlIHJlc3BvbnNpYmxlIGZvciBlbnN1cmluZyB0aGUgZG9ja2VyZmlsZVxuICAgKiBpcyBwcmVzZW50IGluIHRoZSBidWlsZCBjb250ZXh0IGRpcmVjdG9yeSBhbmQgYW55IHJlZmVyZW5jZWQgZmlsZXMgYXJlXG4gICAqIHByZXNlbnQgYXMgd2VsbC4gWW91IGNhbiBzcGVjaWZ5IGRvY2tlcmZpbGUgbmFtZSB3aXRoIGFkamFjZW50XG4gICAqIGBuZXh0anNGdW5jdGlvbnNBc3NldEltYWdlQ29kZVByb3BzLmZpbGVgIHByb3BlcnR5LlxuICAgKiBAZGVmYXVsdCBcImNkay1uZXh0anMvbGliL25leHRqcy1idWlsZFwiXG4gICAqL1xuICByZWFkb25seSBmdW5jdGlvbnNJbWFnZUJ1aWxkQ29udGV4dD86IHN0cmluZztcbiAgLyoqXG4gICAqIERlZmF1bHQgZm9sZGVyIGZvciBidWlsZCBjb250ZXh0IGlzIHRoZSBcImxpYi9uZXh0anMtYnVpbGRcIiBmb2xkZXIgaW4gdGhlXG4gICAqIGluc3RhbGxlZCBjZGstbmV4dGpzIGxpYnJhcnkgd2hpY2ggaGFzIHRoZSBcImFzc2V0cy1kZXBsb3ltZW50LkRvY2tlcmZpbGVcIi5cbiAgICogTm90ZSwgaWYgeW91IHNwZWNpZnkgdGhpcyB0aGVuIHlvdSdyZSByZXNwb25zaWJsZSBmb3IgZW5zdXJpbmcgdGhlIGRvY2tlcmZpbGVcbiAgICogaXMgcHJlc2VudCBpbiB0aGUgYnVpbGQgY29udGV4dCBkaXJlY3RvcnkgYW5kIGFueSByZWZlcmVuY2VkIGZpbGVzIGFyZVxuICAgKiBwcmVzZW50IGFzIHdlbGwuIFlvdSBjYW4gc3BlY2lmeSBkb2NrZXJmaWxlIG5hbWUgd2l0aCBhZGphY2VudFxuICAgKiBgbmV4dGpzQXNzZXREZXBsb3ltZW50QXNzZXRJbWFnZUNvZGVQcm9wcy5maWxlYCBwcm9wZXJ0eS5cbiAgICogQGRlZmF1bHQgXCJjZGstbmV4dGpzL2xpYi9uZXh0anMtYnVpbGRcIlxuICAgKi9cbiAgcmVhZG9ubHkgYXNzZXRzRGVwbG95bWVudEltYWdlQnVpbGRDb250ZXh0Pzogc3RyaW5nO1xuICAvKipcbiAgICogRGVmYXVsdCBmb2xkZXIgZm9yIGJ1aWxkIGNvbnRleHQgaXMgdGhlIFwiYXNzZXRzL2xhbWJkYXMvYXNzZXRzLWRlcGxveW1lbnQvYXNzZXRzLWRlcGxveW1lbnQubGFtYmRhXCIgZm9sZGVyIGluIHRoZVxuICAgKiBpbnN0YWxsZWQgY2RrLW5leHRqcyBsaWJyYXJ5IHdoaWNoIGhhcyB0aGUgXCJ7Li4ufS1jb250YWluZXJzLkRvY2tlcmZpbGVcIi5cbiAgICogTm90ZSwgaWYgeW91IHNwZWNpZnkgdGhpcyB0aGVuIHlvdSdyZSByZXNwb25zaWJsZSBmb3IgZW5zdXJpbmcgdGhlIGRvY2tlcmZpbGVcbiAgICogaXMgcHJlc2VudCBpbiB0aGUgYnVpbGQgY29udGV4dCBkaXJlY3RvcnkgYW5kIGFueSByZWZlcmVuY2VkIGZpbGVzIGFyZVxuICAgKiBwcmVzZW50IGFzIHdlbGwuIFlvdSBjYW4gc3BlY2lmeSBkb2NrZXJmaWxlIG5hbWUgd2l0aCBhZGphY2VudFxuICAgKiBgbmV4dGpzQ29udGFpbmVyc0RvY2tlckltYWdlQXNzZXRQcm9wcy5maWxlYCBwcm9wZXJ0eS5cbiAgICogQGRlZmF1bHQgXCJjZGstbmV4dGpzL2xpYi9uZXh0anMtYnVpbGRcIlxuICAgKi9cbiAgcmVhZG9ubHkgY29udGFpbmVyc0ltYWdlQnVpbGRDb250ZXh0Pzogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIE5leHRqc0J1aWxkUHJvcHMge1xuICAvKipcbiAgICogQHNlZSB7QGxpbmsgTmV4dGpzQmFzZVByb3BzW1wiYnVpbGRDb21tYW5kXCJdfVxuICAgKi9cbiAgcmVhZG9ubHkgYnVpbGRDb21tYW5kOiBOZXh0anNCYXNlUHJvcHNbXCJidWlsZENvbW1hbmRcIl07XG4gIC8qKlxuICAgKiBAc2VlIHtAbGluayBOZXh0anNCYXNlUHJvcHNbXCJidWlsZENvbnRleHRcIl19XG4gICAqL1xuICByZWFkb25seSBidWlsZENvbnRleHQ6IE5leHRqc0Jhc2VQcm9wc1tcImJ1aWxkQ29udGV4dFwiXTtcbiAgLyoqXG4gICAqXG4gICAqL1xuICByZWFkb25seSBidWlsZGVySW1hZ2VQcm9wcz86IEJ1aWxkZXJJbWFnZVByb3BzO1xuICAvKipcbiAgICogQHNlZSB7QGxpbmsgTmV4dGpzQmFzZVByb3BzLnJlbGF0aXZlUGF0aFRvUGFja2FnZX1cbiAgICovXG4gIHJlYWRvbmx5IHJlbGF0aXZlUGF0aFRvUGFja2FnZT86IE5leHRqc0Jhc2VQcm9wc1tcInJlbGF0aXZlUGF0aFRvUGFja2FnZVwiXTtcbiAgcmVhZG9ubHkgbmV4dGpzVHlwZTogTmV4dGpzVHlwZTtcbiAgcmVhZG9ubHkgb3ZlcnJpZGVzPzogTmV4dGpzQnVpbGRPdmVycmlkZXM7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUHVibGljRGlyRW50cnkge1xuICByZWFkb25seSBuYW1lOiBzdHJpbmc7XG4gIHJlYWRvbmx5IGlzRGlyZWN0b3J5OiBib29sZWFuO1xufVxuXG4vKipcbiAqIEJ1aWxkcyBOZXh0LmpzIGFzc2V0cy5cbiAqIEBsaW5rIGh0dHBzOi8vbmV4dGpzLm9yZy9kb2NzL3BhZ2VzL2FwaS1yZWZlcmVuY2UvbmV4dC1jb25maWctanMvb3V0cHV0XG4gKi9cbmV4cG9ydCBjbGFzcyBOZXh0anNCdWlsZCBleHRlbmRzIENvbnN0cnVjdCB7XG4gIC8qKlxuICAgKiBJbWFnZSBhbGlhcyBvZiBidWlsZGVyIGltYWdlIE5leHQuanMgYXBwIHdoaWNoIGlzIGJ1aWx0IGZvciBvdGhlciBpbWFnZXMgdG8gYmVcbiAgICogYnVpbHQgYEZST01gLiBUaGlzIGltYWdlIGlzbid0IGJ1aWx0IHdpdGggQ0RLIEFzc2V0cyBjb25zdHJ1Y3QgYi9jIGl0XG4gICAqIGRvZXNuJ3QgbmVlZCB0byBiZSB1cGxvYWRlZCB0byBFQ1IuIFdlIHN0aWxsIG5lZWQgdG8gaW5jbHVkZSBzbGljZSBvZlxuICAgKiBgbm9kZS5hZGRyYCBpbiB0YWcgaW4gY2FzZSBtdWx0aXBsZSBjZGstbmV4dGpzIGNvbnN0cnVjdHMgYXJlIHVzZWQuXG4gICAqL1xuICBidWlsZGVySW1hZ2VBbGlhczogc3RyaW5nO1xuICAvKipcbiAgICogVW5pcXVlIGlkIGZvciBOZXh0LmpzIGJ1aWxkLiBVc2VkIHRvIHBhcnRpdGlvbiBFRlMgRmlsZVN5c3RlbS5cbiAgICovXG4gIGJ1aWxkSWQ6IHN0cmluZztcbiAgLyoqXG4gICAqIEhhc2ggb2YgYnVpbGRlciBpbWFnZSB3aGljaCB3aWxsIGNoYW5nZSB3aGVuZXZlciB0aGUgaW1hZ2UgY2hhbmdlcy4gVXNlZnVsXG4gICAqIGZvciBwYXNzaW5nIHRvIHByb3BlcnRpZXMgb2YgY3VzdG9tIHJlc291cmNlcyB0aGF0IGRlcGVuZCB1cG9uIHRoZSBidWlsZGVyXG4gICAqIGltYWdlIHRvIHJlLXJ1biB3aGVuIGJ1aWxkIGltYWdlIGNoYW5nZXMuXG4gICAqL1xuICBidWlsZEltYWdlRGlnZXN0OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBEb2NrZXIgaW1hZ2UgYnVpbHQgaWYgdXNpbmcgRmFyZ2F0ZS5cbiAgICovXG4gIGltYWdlRm9yTmV4dGpzQ29udGFpbmVycz86IERvY2tlckltYWdlQXNzZXQ7XG4gIC8qKlxuICAgKiBEb2NrZXIgaW1hZ2UgYnVpbHQgaWYgdXNpbmcgTGFtYmRhLlxuICAgKi9cbiAgaW1hZ2VGb3JOZXh0anNGdW5jdGlvbnM/OiBEb2NrZXJJbWFnZUNvZGU7XG4gIC8qKlxuICAgKiBEb2NrZXIgaW1hZ2UgYnVpbHQgZm9yIGBOZXh0anNBc3NldHNEZXBsb3ltZW50YFxuICAgKi9cbiAgaW1hZ2VGb3JOZXh0anNBc3NldHNEZXBsb3ltZW50OiBEb2NrZXJJbWFnZUNvZGU7XG4gIC8qKlxuICAgKiBBYnNvbHV0ZSBwYXRoIHRvIHB1YmxpYy4gVXNlIGJ5IENsb3VkRnJvbnQvQUxCIHRvIGNyZWF0ZSBiZWhhdmlvcnMvcnVsZXNcbiAgICogQGV4YW1wbGUgXCIvVXNlcnMvam9obi9teWFwcC9wdWJsaWNcIlxuICAgKi9cbiAgcHVibGljRGlyRW50cmllczogUHVibGljRGlyRW50cnlbXTtcbiAgLyoqXG4gICAqIFRoZSBlbnRyeXBvaW50IEphdmFTY3JpcHQgZmlsZSB1c2VkIGFzIGFuIGFyZ3VtZW50IGZvciBOb2RlLmpzIHRvIHJ1biB0aGVcbiAgICogTmV4dC5qcyBzdGFuZGFsb25lIHNlcnZlciByZWxhdGl2ZSB0byB0aGUgc3RhbmRhbG9uZSBkaXJlY3RvcnkuXG4gICAqIEBleGFtcGxlIFwiLi9zZXJ2ZXIuanNcIlxuICAgKiBAZXhhbXBsZSBcIi4vcGFja2FnZXMvdWkvc2VydmVyLmpzXCIgKG1vbm9yZXBvKVxuICAgKi9cbiAgcmVsYXRpdmVQYXRoVG9FbnRyeXBvaW50OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFJlcG9zaXRvcnkgbmFtZSBmb3IgdGhlIGJ1aWxkZXIgaW1hZ2UuXG4gICAqL1xuICBwcml2YXRlIGJ1aWxkZXJJbWFnZVJlcG8gPSBcImNkay1uZXh0anMvYnVpbGRlclwiO1xuXG4gIHByaXZhdGUgY29udGFpbmVyUnVudGltZSA9IHByb2Nlc3MuZW52LkNES19ET0NLRVIgfHwgXCJkb2NrZXJcIjtcbiAgcHJpdmF0ZSBwcm9wczogTmV4dGpzQnVpbGRQcm9wcztcbiAgcHJpdmF0ZSByZWxhdGl2ZVBhdGhUb1BhY2thZ2U6IHN0cmluZztcblxuICBjb25zdHJ1Y3RvcihzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCBwcm9wczogTmV4dGpzQnVpbGRQcm9wcykge1xuICAgIHN1cGVyKHNjb3BlLCBpZCk7XG4gICAgdGhpcy5idWlsZGVySW1hZ2VBbGlhcyA9IGAke3RoaXMuYnVpbGRlckltYWdlUmVwb306JHt0aGlzLm5vZGUuYWRkci5zbGljZSgzMCl9YDtcbiAgICB0aGlzLnJlbGF0aXZlUGF0aFRvUGFja2FnZSA9IHByb3BzLnJlbGF0aXZlUGF0aFRvUGFja2FnZSB8fCBcIi5cIjtcbiAgICB0aGlzLnByb3BzID0gcHJvcHM7XG4gICAgdGhpcy5yZWxhdGl2ZVBhdGhUb0VudHJ5cG9pbnQgPSB0aGlzLmdldFJlbGF0aXZlRW50cnlwb2ludFBhdGgoKTtcbiAgICBpZiAoIXByb3BzLmJ1aWxkZXJJbWFnZVByb3BzPy5za2lwQnVpbGQpIHtcbiAgICAgIHRoaXMuY3JlYXRlQnVpbGRlckltYWdlKCk7XG4gICAgfVxuICAgIHRoaXMuYnVpbGRJbWFnZURpZ2VzdCA9IHRoaXMuZ2V0QnVpbGRlckltYWdlRGlnZXN0KCk7XG4gICAgdGhpcy5idWlsZElkID0gdGhpcy5nZXRCdWlsZElkKCk7XG4gICAgdGhpcy5wdWJsaWNEaXJFbnRyaWVzID0gdGhpcy5nZXRQdWJsaWNEaXJFbnRyaWVzKCk7XG4gICAgaWYgKFxuICAgICAgcHJvcHMubmV4dGpzVHlwZSA9PT0gTmV4dGpzVHlwZS5HTE9CQUxfQ09OVEFJTkVSUyB8fFxuICAgICAgcHJvcHMubmV4dGpzVHlwZSA9PT0gTmV4dGpzVHlwZS5SRUdJT05BTF9DT05UQUlORVJTXG4gICAgKSB7XG4gICAgICB0aGlzLmltYWdlRm9yTmV4dGpzQ29udGFpbmVycyA9IHRoaXMuY3JlYXRlSW1hZ2VGb3JOZXh0anNDb250YWluZXJzKCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuaW1hZ2VGb3JOZXh0anNGdW5jdGlvbnMgPSB0aGlzLmNyZWF0ZUltYWdlRm9yTmV4dGpzRnVuY3Rpb25zKCk7XG4gICAgfVxuICAgIHRoaXMuaW1hZ2VGb3JOZXh0anNBc3NldHNEZXBsb3ltZW50ID1cbiAgICAgIHRoaXMuY3JlYXRlSW1hZ2VGb3JOZXh0anNBc3NldHNEZXBsb3ltZW50KCk7XG4gIH1cblxuICBwcml2YXRlIGdldFJlbGF0aXZlRW50cnlwb2ludFBhdGgoKSB7XG4gICAgLy8gam9pblBvc2l4IGIvYyB0aGlzIHdpbGwgYmUgdXNlZCBpbiBsaW51eCBjb250YWluZXJcbiAgICByZXR1cm4gam9pblBvc2l4KHRoaXMucHJvcHMucmVsYXRpdmVQYXRoVG9QYWNrYWdlIHx8IFwiXCIsIFwic2VydmVyLmpzXCIpO1xuICB9XG4gIC8qKlxuICAgKiBBIGJ1aWxkZXIgb3IgYmFzZSBpbWFnZSBuZWVkcyB0byBiZSBjcmVhdGVkIHNvIHRoYXQgdGhlIHNhbWUgaW1hZ2UgY2FuIGJlXG4gICAqIGJ1aWx0IGBGUk9NYCBmb3IgYE5leHRqc0Z1bmN0aW9uc2Agb3IgYE5leHRqc0NvbnRhaW5lcnNgIGFuZCBgTmV4dGpzQXNzZXRzRGVwbG95bWVudGAuXG4gICAqIFRoaXMgaW1hZ2UgZG9lc24ndCBuZWVkIHRvIGJlIHVwbG9hZGVkIHRvIEVDUiBzbyB3ZSdyZSBcIm1hbnVhbGx5XCIgY3JlYXRpbmdcbiAgICogaXQgd2l0aCBgZXhlY1N5bmNgIGFuZCBvdGhlciBpbWFnZXMgd2lsbCBiZSBidWlsdCBgRlJPTWAgaXQuXG4gICAqL1xuICBwcml2YXRlIGNyZWF0ZUJ1aWxkZXJJbWFnZSgpIHtcbiAgICBjb25zdCBidWlsZENvbW1hbmQgPSB0aGlzLnByb3BzLmJ1aWxkQ29tbWFuZCB8fCBcIm5wbSBydW4gYnVpbGRcIjtcbiAgICBjb25zdCB7XG4gICAgICBidWlsZEFyZ3MgPSB7XG4gICAgICAgIEJVSUxEX0NPTU1BTkQ6IGJ1aWxkQ29tbWFuZCxcbiAgICAgICAgUkVMQVRJVkVfUEFUSF9UT19QQUNLQUdFOiB0aGlzLnJlbGF0aXZlUGF0aFRvUGFja2FnZSxcbiAgICAgICAgLi4udGhpcy5wcm9wcy5idWlsZGVySW1hZ2VQcm9wcz8uYnVpbGRBcmdzLFxuICAgICAgfSxcbiAgICAgIGVudlZhck5hbWVzID0gW10sXG4gICAgICBleGNsdWRlID0gW1xuICAgICAgICBcIioqL25vZGVfbW9kdWxlc1wiLFxuICAgICAgICBcIi5naXRcIixcbiAgICAgICAgXCIqKi9jZGsub3V0XCIsXG4gICAgICAgIFwiKiovLm5leHRcIixcbiAgICAgICAgXCIuZ2l0aWdub3JlXCIsXG4gICAgICAgIFwiKi5tZFwiLFxuICAgICAgXSxcbiAgICAgIGZpbGUgPSBcImJ1aWxkZXIuRG9ja2VyZmlsZVwiLFxuICAgICAgcGxhdGZvcm0sXG4gICAgfSA9IHRoaXMucHJvcHMuYnVpbGRlckltYWdlUHJvcHMgfHwge307XG5cbiAgICAvLyB0byBiZSBhZGRlZCB0byB1c2VyIHByb3ZpZGVkIGJ1aWxkIGNvbnRleHQgYmVmb3JlIGJ1aWxkZXIgaW1hZ2UgaXMgYnVpbHRcbiAgICBjb25zdCBmaWxlUGF0aHNUb0NvcHk6IHN0cmluZ1tdID0gW1xuICAgICAgam9pbihfX2Rpcm5hbWUsIFwiY2RrLW5leHRqcy1jYWNoZS1oYW5kbGVyLmNqc1wiKSxcbiAgICBdO1xuICAgIC8vIHRvIGJlIHJlbW92ZWQgZnJvbSB1c2VyIHByb3ZpZGVkIGJ1aWxkIGNvbnRleHQgYWZ0ZXIgYnVpbGRlciBpbWFnZSBpcyBidWlsdFxuICAgIGNvbnN0IGZpbGVQYXRoc1RvUmVtb3ZlOiBzdHJpbmdbXSA9IFtcbiAgICAgIGpvaW4odGhpcy5wcm9wcy5idWlsZENvbnRleHQsIFwiY2RrLW5leHRqcy1jYWNoZS1oYW5kbGVyLmNqc1wiKSxcbiAgICBdO1xuXG4gICAgLy8gaWYgY3VzdG9tIGZpbGUgKERvY2tlcmZpbGUpIGlzIG5vdCBzcGVjaWZpZWQgdGhlbiB1c2UgbGlicmFyeSdzIGRlZmF1bHQgYnVpbGRlci5Eb2NrZXJmaWxlICsgLmRvY2tlcmlnbm9yZVxuICAgIGlmICghdGhpcy5wcm9wcy5idWlsZGVySW1hZ2VQcm9wcz8uZmlsZSkge1xuICAgICAgZmlsZVBhdGhzVG9Db3B5LnB1c2goam9pbihfX2Rpcm5hbWUsIGZpbGUpKTtcbiAgICAgIGZpbGVQYXRoc1RvUmVtb3ZlLnB1c2goam9pbih0aGlzLnByb3BzLmJ1aWxkQ29udGV4dCwgZmlsZSkpO1xuICAgICAgY29uc3QgZXhjbHVkZUZpbGVTdHIgPSBleGNsdWRlPy5qb2luKFwiXFxuXCIpO1xuICAgICAgY29uc3QgZG9ja2VyaWdub3JlRmlsZVBhdGggPSBqb2luKFxuICAgICAgICB0aGlzLnByb3BzLmJ1aWxkQ29udGV4dCxcbiAgICAgICAgXCIuZG9ja2VyaWdub3JlXCIsXG4gICAgICApO1xuICAgICAgd3JpdGVGaWxlU3luYyhkb2NrZXJpZ25vcmVGaWxlUGF0aCwgZXhjbHVkZUZpbGVTdHIpO1xuICAgICAgZmlsZVBhdGhzVG9SZW1vdmUucHVzaChkb2NrZXJpZ25vcmVGaWxlUGF0aCk7XG4gICAgfVxuXG4gICAgZm9yIChjb25zdCBmaWxlUGF0aFRvQ29weSBvZiBmaWxlUGF0aHNUb0NvcHkpIHtcbiAgICAgIGNwU3luYyhcbiAgICAgICAgZmlsZVBhdGhUb0NvcHksXG4gICAgICAgIGpvaW4odGhpcy5wcm9wcy5idWlsZENvbnRleHQsIGJhc2VuYW1lKGZpbGVQYXRoVG9Db3B5KSksXG4gICAgICApO1xuICAgIH1cblxuICAgIGNvbnN0IGJ1aWxkQXJnc1N0ciA9IHRoaXMuY3JlYXRlQnVpbGRBcmdTdHIoYnVpbGRBcmdzKTtcbiAgICB0aGlzLmluamVjdEJ1aWxkZXJEb2NrZXJmaWxlRW52VmFycyhcbiAgICAgIGpvaW4odGhpcy5wcm9wcy5idWlsZENvbnRleHQsIGZpbGUpLFxuICAgICAgZW52VmFyTmFtZXMsXG4gICAgKTtcbiAgICBjb25zdCBjb21tYW5kID1cbiAgICAgIHRoaXMucHJvcHMuYnVpbGRlckltYWdlUHJvcHM/LmNvbW1hbmQgfHxcbiAgICAgIGAke3RoaXMuY29udGFpbmVyUnVudGltZX0gYnVpbGQgJHtwbGF0Zm9ybSA/IGAtLXBsYXRmb3JtICR7cGxhdGZvcm0ucGxhdGZvcm19YCA6IFwiXCJ9IC0tZmlsZSAke2ZpbGV9IC0tdGFnICR7dGhpcy5idWlsZGVySW1hZ2VBbGlhc30gJHtidWlsZEFyZ3NTdHJ9IC5gO1xuICAgIGxldCBlcnJvcjogdW5rbm93bjtcbiAgICB0cnkge1xuICAgICAgY29uc29sZS5sb2coXG4gICAgICAgIGBCdWlsZGluZyBpbWFnZSB3aXRoIGNvbW1hbmQ6ICR7Y29tbWFuZH0gaW4gZGlyZWN0b3J5OiAke3RoaXMucHJvcHMuYnVpbGRDb250ZXh0fWAsXG4gICAgICApO1xuICAgICAgZXhlY1N5bmMoY29tbWFuZCwge1xuICAgICAgICBzdGRpbzogXCJpbmhlcml0XCIsXG4gICAgICAgIGN3ZDogdGhpcy5wcm9wcy5idWlsZENvbnRleHQsXG4gICAgICAgIGVudjogcHJvY2Vzcy5lbnYsXG4gICAgICB9KTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIGVycm9yID0gZXJyO1xuICAgIH0gZmluYWxseSB7XG4gICAgICBmb3IgKGNvbnN0IGZpbGVQYXRoVG9SZW1vdmUgb2YgZmlsZVBhdGhzVG9SZW1vdmUpIHtcbiAgICAgICAgcm1TeW5jKGZpbGVQYXRoVG9SZW1vdmUpO1xuICAgICAgfVxuICAgIH1cbiAgICBpZiAoZXJyb3IpIHRocm93IGVycm9yO1xuICB9XG4gIHByaXZhdGUgaW5qZWN0QnVpbGRlckRvY2tlcmZpbGVFbnZWYXJzKFxuICAgIGJ1aWxkZXJEb2NrZXJmaWxlUGF0aDogc3RyaW5nLFxuICAgIGVudlZhck5hbWVzOiBzdHJpbmdbXSxcbiAgKSB7XG4gICAgY29uc3QgZW52VmFyczogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHt9O1xuICAgIGZvciAoY29uc3QgZW52VmFyTmFtZSBvZiBlbnZWYXJOYW1lcykge1xuICAgICAgaWYgKHByb2Nlc3MuZW52W2VudlZhck5hbWVdKSB7XG4gICAgICAgIGVudlZhcnNbZW52VmFyTmFtZV0gPSBwcm9jZXNzLmVudltlbnZWYXJOYW1lXTtcbiAgICAgIH1cbiAgICB9XG4gICAgY29uc3QgY29udGVudCA9IE9iamVjdC5lbnRyaWVzKGVudlZhcnMpXG4gICAgICAubWFwKChbbmFtZSwgdmFsdWVdKSA9PiBgJHtuYW1lfT1cIiR7dmFsdWV9XCJgKVxuICAgICAgLmpvaW4oXCIgXCIpO1xuICAgIGNvbnN0IG9sZEZpbGUgPSByZWFkRmlsZVN5bmMoYnVpbGRlckRvY2tlcmZpbGVQYXRoKS50b1N0cmluZygpO1xuICAgIGNvbnN0IG5ld0ZpbGUgPSBvbGRGaWxlLnJlcGxhY2UoSU5KRUNUX0NES19ORVhUSlNfQlVJTERfRU5WX1ZBUlMsIGNvbnRlbnQpO1xuICAgIHdyaXRlRmlsZVN5bmMoYnVpbGRlckRvY2tlcmZpbGVQYXRoLCBuZXdGaWxlKTtcbiAgfVxuICBwcml2YXRlIGNyZWF0ZUJ1aWxkQXJnU3RyKFxuICAgIGJ1aWxkQXJnczogUmVxdWlyZWQ8QnVpbGRlckltYWdlUHJvcHM+W1wiYnVpbGRBcmdzXCJdLFxuICApIHtcbiAgICByZXR1cm4gT2JqZWN0LmVudHJpZXMoYnVpbGRBcmdzKS5yZWR1Y2UoKGFjYywgW2tleSwgdmFsdWVdKSA9PiB7XG4gICAgICByZXR1cm4gYCR7YWNjfSAtLWJ1aWxkLWFyZyAke2tleX09XCIke3ZhbHVlfVwiYDtcbiAgICB9LCBcIlwiKTtcbiAgfVxuICBwcml2YXRlIGdldEJ1aWxkZXJJbWFnZURpZ2VzdCgpIHtcbiAgICBjb25zdCBkaWdlc3QgPSBleGVjU3luYyhcbiAgICAgIGAke3RoaXMuY29udGFpbmVyUnVudGltZX0gaW1hZ2VzIC0tbm8tdHJ1bmMgLS1xdWlldCAke3RoaXMuYnVpbGRlckltYWdlQWxpYXN9YCxcbiAgICAgIHsgZW5jb2Rpbmc6IFwidXRmLThcIiB9LFxuICAgICk7XG4gICAgcmV0dXJuIGRpZ2VzdC5zbGljZSgwLCAtMSk7IC8vIHJlbW92ZSB0cmFpbGluZyBcXG5cbiAgfVxuICBwcml2YXRlIGdldFB1YmxpY0RpckVudHJpZXMoKTogUHVibGljRGlyRW50cnlbXSB7XG4gICAgY29uc3QgcHVibGljRGlyUGF0aCA9IGpvaW5Qb3NpeChcbiAgICAgIFwiL2FwcFwiLFxuICAgICAgdGhpcy5wcm9wcy5yZWxhdGl2ZVBhdGhUb1BhY2thZ2UgfHwgXCJcIixcbiAgICAgIFwicHVibGljXCIsXG4gICAgKTtcbiAgICBpZiAoZXhpc3RzU3luYyhwdWJsaWNEaXJQYXRoKSkge1xuICAgICAgY29uc3QgcHVibGljRGlyRW50cmllc1N0cmluZyA9IGV4ZWNTeW5jKFxuICAgICAgICBgJHt0aGlzLmNvbnRhaW5lclJ1bnRpbWV9IHJ1biAke3RoaXMuYnVpbGRlckltYWdlQWxpYXN9IG5vZGUgLWUgXCJjb25zb2xlLmxvZyhKU09OLnN0cmluZ2lmeShmcy5yZWFkZGlyU3luYygnJHtwdWJsaWNEaXJQYXRofScsIHsgd2l0aEZpbGVUeXBlczogdHJ1ZSB9KS5tYXAoKGUpID0+ICh7IG5hbWU6IGUubmFtZSwgaXNEaXJlY3Rvcnk6IGUuaXNEaXJlY3RvcnkoKX0pKSkpXCJgLFxuICAgICAgICB7IGVuY29kaW5nOiBcInV0Zi04XCIgfSxcbiAgICAgICk7XG4gICAgICByZXR1cm4gSlNPTi5wYXJzZShwdWJsaWNEaXJFbnRyaWVzU3RyaW5nKSBhcyBQdWJsaWNEaXJFbnRyeVtdO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gW107XG4gICAgfVxuICB9XG4gIHByaXZhdGUgZ2V0QnVpbGRJZCgpIHtcbiAgICBjb25zdCBidWlsZElkUGF0aCA9IGpvaW5Qb3NpeChcbiAgICAgIFwiL2FwcFwiLFxuICAgICAgdGhpcy5wcm9wcy5yZWxhdGl2ZVBhdGhUb1BhY2thZ2UgfHwgXCJcIixcbiAgICAgIFwiLm5leHRcIixcbiAgICAgIFwiQlVJTERfSURcIixcbiAgICApO1xuICAgIGNvbnN0IGJ1aWxkSWQgPSBleGVjU3luYyhcbiAgICAgIGAke3RoaXMuY29udGFpbmVyUnVudGltZX0gcnVuICR7dGhpcy5idWlsZGVySW1hZ2VBbGlhc30gL2Jpbi9zaCAtYyBcImNhdCAke2J1aWxkSWRQYXRofVwiYCxcbiAgICAgIHsgZW5jb2Rpbmc6IFwidXRmLThcIiB9LFxuICAgICk7XG4gICAgcmV0dXJuIGJ1aWxkSWQ7XG4gIH1cbiAgcHJpdmF0ZSBjcmVhdGVJbWFnZUZvck5leHRqc0NvbnRhaW5lcnMoKSB7XG4gICAgY29uc3QgZG9ja2VyZmlsZU5hbWVQcmVmaXggPVxuICAgICAgdGhpcy5wcm9wcy5uZXh0anNUeXBlID09PSBOZXh0anNUeXBlLkdMT0JBTF9DT05UQUlORVJTXG4gICAgICAgID8gXCJnbG9iYWxcIlxuICAgICAgICA6IFwicmVnaW9uYWxcIjtcbiAgICBjb25zdCBkb2NrZXJmaWxlTmFtZSA9IGAke2RvY2tlcmZpbGVOYW1lUHJlZml4fS1jb250YWluZXJzLkRvY2tlcmZpbGVgO1xuICAgIC8vIGNkay1uZXh0anMvYnVpbGRlci17aGFzaH0gYWxyZWFkeSBjb250YWlucyBidWlsdCBuZXh0anMgYXBwIHdoaWNoIHdlJ2xsXG4gICAgLy8gYENPUFkgLS1mcm9tPWNkay1uZXh0anMvYnVpbGRlci17aGFzaH1gIHNvIHdlIGp1c3QgbmVlZCB0aGUgRG9ja2VyZmlsZVxuICAgIC8vIHdoaWNoIGlzIGluIGxpYi9uZXh0anMtYnVpbGQgZm9sZGVyLlxuICAgIGNvbnN0IGJ1aWxkQ29udGV4dCA9XG4gICAgICB0aGlzLnByb3BzLm92ZXJyaWRlcz8uY29udGFpbmVyc0ltYWdlQnVpbGRDb250ZXh0ID8/XG4gICAgICBqb2luKF9fZGlybmFtZSwgXCIuLlwiLCBcIi4uXCIsIFwibGliXCIsIFwibmV4dGpzLWJ1aWxkXCIpO1xuICAgIGNvbnN0IGRvY2tlckltYWdlQXNzZXQgPSBuZXcgRG9ja2VySW1hZ2VBc3NldCh0aGlzLCBcIkltYWdlXCIsIHtcbiAgICAgIGRpcmVjdG9yeTogYnVpbGRDb250ZXh0LFxuICAgICAgZXh0cmFIYXNoOiB0aGlzLmJ1aWxkSW1hZ2VEaWdlc3QsIC8vIHJlYnVpbGQgd2hlbiBidWlsZGVyIGhhc2ggY2hhbmdlc1xuICAgICAgZmlsZTogZG9ja2VyZmlsZU5hbWUsXG4gICAgICBpZ25vcmVNb2RlOiBJZ25vcmVNb2RlLkRPQ0tFUixcbiAgICAgIC4uLnRoaXMucHJvcHMub3ZlcnJpZGVzPy5uZXh0anNDb250YWluZXJzRG9ja2VySW1hZ2VBc3NldFByb3BzLFxuICAgICAgYnVpbGRBcmdzOiB7XG4gICAgICAgIFtCVUlMRF9JRF9BUkdfTkFNRV06IHRoaXMuYnVpbGRJZCxcbiAgICAgICAgW0JVSUxERVJfSU1BR0VfQUxJQVNfQVJHX05BTUVdOiB0aGlzLmJ1aWxkZXJJbWFnZUFsaWFzLFxuICAgICAgICBbQ0FDSEVfUEFUSF9BUkdfTkFNRV06IENBQ0hFX1BBVEgsXG4gICAgICAgIFtEQVRBX0NBQ0hFX1BBVEhfQVJHX05BTUVdOiBEQVRBX0NBQ0hFX1BBVEgsXG4gICAgICAgIFtQVUJMSUNfUEFUSF9BUkdfTkFNRV06IFBVQkxJQ19QQVRILFxuICAgICAgICBbSU1BR0VfQ0FDSEVfUEFUSF9BUkdfTkFNRV06IElNQUdFX0NBQ0hFX1BBVEgsXG4gICAgICAgIFtNT1VOVF9QQVRIX0FSR19OQU1FXTogTU9VTlRfUEFUSCxcbiAgICAgICAgW1JFTEFUSVZFX1BBVEhfVE9fUEFDS0FHRV9BUkdfTkFNRV06IHRoaXMucmVsYXRpdmVQYXRoVG9QYWNrYWdlLFxuICAgICAgICAuLi50aGlzLnByb3BzLm92ZXJyaWRlcz8ubmV4dGpzQ29udGFpbmVyc0RvY2tlckltYWdlQXNzZXRQcm9wc1xuICAgICAgICAgID8uYnVpbGRBcmdzLFxuICAgICAgfSxcbiAgICB9KTtcbiAgICByZXR1cm4gZG9ja2VySW1hZ2VBc3NldDtcbiAgfVxuXG4gIHByaXZhdGUgY3JlYXRlSW1hZ2VGb3JOZXh0anNGdW5jdGlvbnMoKSB7XG4gICAgY29uc3QgZG9ja2VyZmlsZU5hbWUgPSBcImdsb2JhbC1mdW5jdGlvbnMuRG9ja2VyZmlsZVwiO1xuICAgIC8vIGNkay1uZXh0anMvYnVpbGRlci17aGFzaH0gYWxyZWFkeSBjb250YWlucyBidWlsdCBuZXh0anMgYXBwIHdoaWNoIHdlJ2xsXG4gICAgLy8gYENPUFkgLS1mcm9tPWNkay1uZXh0anMvYnVpbGRlci17aGFzaH1gIHNvIHdlIGp1c3QgbmVlZCB0aGUgRG9ja2VyZmlsZVxuICAgIC8vIHdoaWNoIGlzIGluIGxpYi9uZXh0anMtYnVpbGQgZm9sZGVyLlxuICAgIGNvbnN0IGJ1aWxkQ29udGV4dCA9XG4gICAgICB0aGlzLnByb3BzLm92ZXJyaWRlcz8uZnVuY3Rpb25zSW1hZ2VCdWlsZENvbnRleHQgPz9cbiAgICAgIGpvaW4oX19kaXJuYW1lLCBcIi4uXCIsIFwiLi5cIiwgXCJsaWJcIiwgXCJuZXh0anMtYnVpbGRcIik7XG4gICAgY29uc3QgZG9ja2VySW1hZ2VDb2RlID0gRG9ja2VySW1hZ2VDb2RlLmZyb21JbWFnZUFzc2V0KGJ1aWxkQ29udGV4dCwge1xuICAgICAgY21kOiBbXCJub2RlXCIsIHRoaXMucmVsYXRpdmVQYXRoVG9FbnRyeXBvaW50XSxcbiAgICAgIGV4dHJhSGFzaDogdGhpcy5idWlsZEltYWdlRGlnZXN0LCAvLyByZWJ1aWxkIHdoZW4gYnVpbGRlciBoYXNoIGNoYW5nZXNcbiAgICAgIGZpbGU6IGRvY2tlcmZpbGVOYW1lLFxuICAgICAgaWdub3JlTW9kZTogSWdub3JlTW9kZS5ET0NLRVIsXG4gICAgICAuLi50aGlzLnByb3BzLm92ZXJyaWRlcz8ubmV4dGpzRnVuY3Rpb25zQXNzZXRJbWFnZUNvZGVQcm9wcyxcbiAgICAgIGJ1aWxkQXJnczoge1xuICAgICAgICBbQlVJTERfSURfQVJHX05BTUVdOiB0aGlzLmJ1aWxkSWQsXG4gICAgICAgIFtCVUlMREVSX0lNQUdFX0FMSUFTX0FSR19OQU1FXTogdGhpcy5idWlsZGVySW1hZ2VBbGlhcyxcbiAgICAgICAgW0NBQ0hFX1BBVEhfQVJHX05BTUVdOiBDQUNIRV9QQVRILFxuICAgICAgICBbREFUQV9DQUNIRV9QQVRIX0FSR19OQU1FXTogREFUQV9DQUNIRV9QQVRILFxuICAgICAgICBbUFVCTElDX1BBVEhfQVJHX05BTUVdOiBQVUJMSUNfUEFUSCxcbiAgICAgICAgW0lNQUdFX0NBQ0hFX1BBVEhfQVJHX05BTUVdOiBJTUFHRV9DQUNIRV9QQVRILFxuICAgICAgICBbTU9VTlRfUEFUSF9BUkdfTkFNRV06IE1PVU5UX1BBVEgsXG4gICAgICAgIFtSRUxBVElWRV9QQVRIX1RPX1BBQ0tBR0VfQVJHX05BTUVdOiB0aGlzLnJlbGF0aXZlUGF0aFRvUGFja2FnZSxcbiAgICAgICAgLi4udGhpcy5wcm9wcy5vdmVycmlkZXM/Lm5leHRqc0Z1bmN0aW9uc0Fzc2V0SW1hZ2VDb2RlUHJvcHM/LmJ1aWxkQXJncyxcbiAgICAgIH0sXG4gICAgfSk7XG4gICAgLy8gVE9ETzogaG93IHRvIGNsZWFuIHVwIHRlbXAgZGlyP1xuICAgIC8vIHJtU3luYyh0ZW1wRGlyLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcbiAgICByZXR1cm4gZG9ja2VySW1hZ2VDb2RlO1xuICB9XG5cbiAgcHJpdmF0ZSBjcmVhdGVJbWFnZUZvck5leHRqc0Fzc2V0c0RlcGxveW1lbnQoKSB7XG4gICAgY29uc3QgZG9ja2VyZmlsZU5hbWUgPSBcImFzc2V0cy1kZXBsb3ltZW50LkRvY2tlcmZpbGVcIjtcbiAgICAvKipcbiAgICAgKiBQYXRoIHRvIGJ1bmRsZWQgY3VzdG9tIHJlc291cmNlIGNvZGVcbiAgICAgKi9cbiAgICBjb25zdCBidWlsZENvbnRleHQgPVxuICAgICAgdGhpcy5wcm9wcy5vdmVycmlkZXM/LmFzc2V0c0RlcGxveW1lbnRJbWFnZUJ1aWxkQ29udGV4dCA/P1xuICAgICAgam9pbihcbiAgICAgICAgX19kaXJuYW1lLFxuICAgICAgICBcIi4uXCIsXG4gICAgICAgIFwiLi5cIixcbiAgICAgICAgXCJhc3NldHNcIixcbiAgICAgICAgXCJsYW1iZGFzXCIsXG4gICAgICAgIFwiYXNzZXRzLWRlcGxveW1lbnRcIixcbiAgICAgICAgXCJhc3NldHMtZGVwbG95bWVudC5sYW1iZGFcIixcbiAgICAgICk7XG4gICAgLy8gY2RrLW5leHRqcy9idWlsZGVyLXtoYXNofSBhbHJlYWR5IGNvbnRhaW5zIE5leHQuanMgYnVpbHQgY29kZSB3aGljaFxuICAgIC8vIHdlJ2xsIGNvcHkgaW50byBmaW5hbCBpbWFnZS4gQnV0IHdlIGFsc28gbmVlZCBsYW1iZGEgY29kZSB0byBydW5cbiAgICAvLyBhc3NldCBkZXBsb3ltZW50IHRhc2tzXG4gICAgY29uc3QgZG9ja2VySW1hZ2VDb2RlID0gRG9ja2VySW1hZ2VDb2RlLmZyb21JbWFnZUFzc2V0KGJ1aWxkQ29udGV4dCwge1xuICAgICAgZXh0cmFIYXNoOiB0aGlzLmJ1aWxkSW1hZ2VEaWdlc3QsIC8vIHJlYnVpbGQgd2hlbiBidWlsZGVyIGhhc2ggY2hhbmdlc1xuICAgICAgZmlsZTogZG9ja2VyZmlsZU5hbWUsXG4gICAgICBpZ25vcmVNb2RlOiBJZ25vcmVNb2RlLkRPQ0tFUixcbiAgICAgIC4uLnRoaXMucHJvcHMub3ZlcnJpZGVzPy5uZXh0anNBc3NldERlcGxveW1lbnRBc3NldEltYWdlQ29kZVByb3BzLFxuICAgICAgYnVpbGRBcmdzOiB7XG4gICAgICAgIFtCVUlMRF9JRF9BUkdfTkFNRV06IHRoaXMuYnVpbGRJZCxcbiAgICAgICAgW0JVSUxERVJfSU1BR0VfQUxJQVNfQVJHX05BTUVdOiB0aGlzLmJ1aWxkZXJJbWFnZUFsaWFzLFxuICAgICAgICBbUFVCTElDX1BBVEhfQVJHX05BTUVdOiBQVUJMSUNfUEFUSCxcbiAgICAgICAgW1JFTEFUSVZFX1BBVEhfVE9fUEFDS0FHRV9BUkdfTkFNRV06IHRoaXMucmVsYXRpdmVQYXRoVG9QYWNrYWdlLFxuICAgICAgICAuLi50aGlzLnByb3BzLm92ZXJyaWRlcz8ubmV4dGpzQXNzZXREZXBsb3ltZW50QXNzZXRJbWFnZUNvZGVQcm9wc1xuICAgICAgICAgID8uYnVpbGRBcmdzLFxuICAgICAgfSxcbiAgICB9KTtcbiAgICByZXR1cm4gZG9ja2VySW1hZ2VDb2RlO1xuICB9XG59XG4iXX0=