UNPKG

projen

Version:

CDK for software projects

369 lines 43.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.codeArtifactRegex = void 0; exports.isYarnClassic = isYarnClassic; exports.isYarnBerry = isYarnBerry; exports.isNpm = isNpm; exports.execCommand = execCommand; exports.executeCommandPriorInstallation = executeCommandPriorInstallation; exports.renderBundleName = renderBundleName; exports.extractCodeArtifactDetails = extractCodeArtifactDetails; exports.minVersion = minVersion; exports.tryResolveModule = tryResolveModule; exports.tryResolveModuleManifestPath = tryResolveModuleManifestPath; exports.tryResolveManifestPathFromDefaultExport = tryResolveManifestPathFromDefaultExport; exports.tryResolveManifestPathFromPath = tryResolveManifestPathFromPath; exports.tryResolveManifestPathFromSearch = tryResolveManifestPathFromSearch; exports.tryResolveModuleManifest = tryResolveModuleManifest; exports.tryResolveDependencyVersion = tryResolveDependencyVersion; exports.hasDependencyVersion = hasDependencyVersion; exports.installedVersionProbablyMatches = installedVersionProbablyMatches; const fs_1 = require("fs"); const path_1 = require("path"); const semver = require("semver"); const node_package_1 = require("./node-package"); const util_1 = require("../util"); /** * Check if package manager is yarn classic. */ function isYarnClassic(packageManager) { return (packageManager === node_package_1.NodePackageManager.YARN || packageManager === node_package_1.NodePackageManager.YARN_CLASSIC); } /** * Check if package manager is yarn berry. */ function isYarnBerry(packageManager) { return (packageManager === node_package_1.NodePackageManager.YARN2 || packageManager === node_package_1.NodePackageManager.YARN_BERRY); } /** * Check if package manager is npm. */ function isNpm(packageManager) { return packageManager === node_package_1.NodePackageManager.NPM; } /** * Returns the exec command prefix for the given package manager, or defaults to npx if non provided. * Optionally followed by a binary name. */ function execCommand(packageManager, bin) { let cmd; switch (packageManager) { case node_package_1.NodePackageManager.PNPM: cmd = "pnpm exec"; break; case node_package_1.NodePackageManager.YARN2: case node_package_1.NodePackageManager.YARN_BERRY: cmd = "yarn"; break; case node_package_1.NodePackageManager.BUN: cmd = "bunx"; break; case node_package_1.NodePackageManager.NPM: case node_package_1.NodePackageManager.YARN: case node_package_1.NodePackageManager.YARN_CLASSIC: default: cmd = "npx"; break; } return bin ? `${cmd} ${bin}` : cmd; } /** * Returns the command to execute a binary with the given package manager, without requiring installation of that binary as a project dependency. * @param packageManager The package manager to use when executing the command. */ function executeCommandPriorInstallation(packageManager) { switch (packageManager) { case node_package_1.NodePackageManager.PNPM: return "pnpm dlx"; case node_package_1.NodePackageManager.YARN2: case node_package_1.NodePackageManager.YARN_BERRY: return "yarn dlx"; case node_package_1.NodePackageManager.BUN: return "bunx"; case node_package_1.NodePackageManager.NPM: case node_package_1.NodePackageManager.YARN: case node_package_1.NodePackageManager.YARN_CLASSIC: default: return "npx"; } } function renderBundleName(entrypoint) { const parts = (0, path_1.join)(entrypoint).split(path_1.sep); if (parts[0] === "src") { parts.shift(); // just remove 'src' if its the first element for ergonomics } const p = parts.join(path_1.posix.sep); const dir = (0, path_1.dirname)(p); const base = (0, path_1.basename)(p, (0, path_1.extname)(p)); return path_1.posix.join(dir, base); } /** * Regex for AWS CodeArtifact registry */ exports.codeArtifactRegex = /^https:\/\/(?<registry>(?<domain>[^\.]+)-(?<accountId>\d{12})\.d\.codeartifact\.(?<region>[^\.]+).*\.amazonaws\.com\/.*\/(?<repository>[^\/]+)\/)/; /** * gets AWS details from the Code Artifact registry URL * throws exception if not matching expected pattern * @param registryUrl Code Artifact registry URL * @returns object containing the (domain, accountId, region, repository) */ function extractCodeArtifactDetails(registryUrl) { const match = registryUrl.match(exports.codeArtifactRegex); if (match?.groups) { const { domain, accountId, region, repository, registry } = match.groups; return { domain, accountId, region, repository, registry }; } throw new Error("Could not get CodeArtifact details from npm Registry"); } function minVersion(version) { if (semver.validRange(version)) { return semver.minVersion(version)?.version; } else { return version; } } /** * Attempt to resolve location of the given `moduleId`. * @param moduleId Module ID to lookup. * @param options Passed through to `require.resolve`. */ function tryResolveModule(moduleId, options) { try { return require.resolve(moduleId, options); } catch { return undefined; } } /** * Attempt to resolve a module's manifest (package.json) path via `require.resolve` lookup. * * @remarks * If the target package has `exports` that differ from the default * (i.e, it defines the `exports` field in its manifest) and does not * explicitly include an entry for `package.json`, this strategy will fail. * See {@link tryResolveManifestPathFromDefaultExport} as an alternative. * * @param moduleId Module ID to lookup. * @param options Passed through to `require.resolve`. */ function tryResolveModuleManifestPath(moduleId, options) { // cannot just `require('dependency/package.json')` here because // `options.paths` may not overlap with this node proc's resolution paths. const manifestId = `${moduleId}/package.json`; return tryResolveModule(manifestId, options); } /** * Attempt to resolve a module's manifest (package.json) path by looking for the nearest * `package.json` file that is an ancestor to the module's default export location. * * @param moduleId Module ID to lookup. * @param options Passed through to `require.resolve`. */ function tryResolveManifestPathFromDefaultExport(moduleId, options) { const defaultExportPath = tryResolveModule(moduleId, options); if (!defaultExportPath) { return undefined; } const moduleDir = (0, util_1.findUp)("package.json", defaultExportPath); if (!moduleDir) { return undefined; } return (0, path_1.join)(moduleDir, "package.json"); } /** * Attempt to resolve a module's manifest (package.json) path by checking for its existence under `node_modules` relative to `basePath`. * * @remarks * This strategy can be helpful in the scenario that a module defines * custom exports without `package.json` and no default export (i.e, some type definition packages). * * @param moduleId Module ID to lookup. * @param basePath Root path to search from. */ function tryResolveManifestPathFromPath(moduleId, basePath) { const base = basePath.includes("node_modules") ? basePath : (0, path_1.join)(basePath, "node_modules"); const filePath = (0, path_1.resolve)(base, ...moduleId.split("/"), "package.json"); if ((0, fs_1.existsSync)(filePath)) { return filePath; } return undefined; } /** * Attempt to resolve a module's manifest (package.json) path by searching for it in the optionally provided paths array * as well as the current node processes' default resolution paths. * @param moduleId Module ID to search for. * @param options Search options. */ function tryResolveManifestPathFromSearch(moduleId, options) { const searchPaths = [ ...(options?.paths ?? []), ...(require.resolve.paths(moduleId) ?? []), ]; for (const path of searchPaths) { const result = tryResolveManifestPathFromPath(moduleId, path); // early return on first result. if (result) { return result; } } return undefined; } /** * Attempt to resolve a module's manifest (package.json) using multiple strategies. * @param moduleId Module to resolve manifest path for. * @param options Resolution options. */ function tryResolveModuleManifest(moduleId, options) { const strategies = [ tryResolveModuleManifestPath, tryResolveManifestPathFromDefaultExport, tryResolveManifestPathFromSearch, ]; for (const strategy of strategies) { const result = strategy(moduleId, options); // early return on first result. if (result) { try { const manifest = JSON.parse((0, fs_1.readFileSync)(result, "utf8")); // verify name matches target module. if (manifest.name === moduleId) { return manifest; } } catch { // continue to next strategy. } } } return undefined; } /** * Attempt to resolve the installed version of a given dependency. * @param dependencyName Name of dependency. * @param options Optional options passed through to `require.resolve`. */ function tryResolveDependencyVersion(dependencyName, options) { const manifest = tryResolveModuleManifest(dependencyName, options); if (!manifest) { return undefined; } return manifest?.version; } /** * Whether the given dependency version is installed * * This can be used to test for the presence of certain versions of devDependencies, * and do something dependency-specific in certain Components. For example, test for * a version of Jest and generate different configs based on the Jest version. * * NOTE: The implementation of this function currently is currently * approximate: to do it correctly, we would need a separate implementation * for every package manager, to query its installed version (either that, or we * would code to query `package-lock.json`, `yarn.lock`, etc...). * * Instead, we will look at `package.json`, and assume that the versions * picked by the package manager match ~that. This will work well enough for * major version checks, but may fail for point versions. * * What we SHOULD do is: `actualVersion ∈ checkRange`. * * What we do instead is a slightly more sophisticated version of * `requestedRange ∩ checkRange != ∅`. This will always give a correct result if * `requestedRange ⊆ checkRange`, but may give false positives when `checkRange * ⊆ requestedRange`. * * May return `undefined` if the question cannot be answered. These include the * following cases: * * - The dependency is requested via local file dependencies (`file://...`) * - The dependency uses an other type of URL, such as a GitHub URL * - The dependency is not found in the `package.json`, such as when * bootstrapping from an external projen package, and the `package.json` * file only has that one external package as a dependency * * Otherwise it will return `true` if the installed version is probably in the * requested range, and `false` if it is probably not. * * This API may eventually be added to the public projen API, but only after * we implement exact version checking. * * @param dependencyName The name of the dependency * @param checkRange A particular version, or range of versions. */ function hasDependencyVersion(project, dependencyName, checkRange) { const file = node_package_1.NodePackage.of(project)?.file; if (!file) { return undefined; } if (!(0, fs_1.existsSync)(file.absolutePath)) { return undefined; } const pj = JSON.parse((0, fs_1.readFileSync)(file.absolutePath, "utf-8")); // Technicaly, we should be intersecting all ranges to come up with the most narrow dependency // range, but `semver` doesn't allow doing that and we don't want to add a dependency on `semver-intersect`. // // Let's take the first dependency declaration we find, and assume that people // set up their `package.json` correctly. let requestedRange; for (const key of ["dependencies", "devDependencies", "peerDependencies"]) { const deps = pj[key] ?? {}; let requestedVersion = deps[dependencyName]; if (requestedVersion) { // If this is not a valid range, it could be 'file:dep.tgz', or a GitHub URL. No way to know what // version we're getting, bail out. if (!semver.validRange(requestedVersion)) { return undefined; } requestedRange = requestedVersion; break; } } // If the dependency is not found in the `package.json`, we can't answer the question (yet). // This means that the dependency hasn't been added yet, which means we know (upstream) what we're going to request, // or we're going to ask for '*' and we'll get the latest version. if (!requestedRange) { return undefined; } return installedVersionProbablyMatches(requestedRange, checkRange); } /** * Whether the given requestedRange *probably* leads to the installation of a version that matches checkRange * * We assume that NPM always installs the most recent version of a package that * is allowed by the requestedRange. */ function installedVersionProbablyMatches(requestedRange, checkRange) { const options = { includePrerelease: true, loose: true, }; // No questions asked: always true if (semver.subset(requestedRange, checkRange, options)) { return true; } // Also no questions asked: always false if (!semver.intersects(requestedRange, checkRange, options)) { return false; } // Now we're in tricky territory. We intersect, but aren't a full subset. // We are in one of the following 2 situations, which we will tie-break by // assuming NPM will install the most recent matching version in 'requested'. // // requested | check | result // -----------|----------|----------- // >= 2 | >= 3 | probably true (chance of FP) // <= 2 | <= 1 | probably false (change of FN) // // `semver` doesn't make it easy to distinguish these cases (we can't request // the `maxVersion` that satisfies a range). Instead what we do is // get the `minVersion` of each range, and if they compare equal we assume // we're in the bottom case with `<=` checks, and return `false`. return !semver.eq(semver.minVersion(requestedRange, options) ?? "1.2.3", semver.minVersion(checkRange, options) ?? "1.2.3"); } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9qYXZhc2NyaXB0L3V0aWwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBVUEsc0NBS0M7QUFLRCxrQ0FLQztBQUtELHNCQUVDO0FBTUQsa0NBd0JDO0FBTUQsMEVBaUJDO0FBa0JELDRDQVVDO0FBY0QsZ0VBT0M7QUFFRCxnQ0FNQztBQU9ELDRDQVNDO0FBY0Qsb0VBUUM7QUFTRCwwRkFhQztBQVlELHdFQVlDO0FBUUQsNEVBZ0JDO0FBT0QsNERBMkJDO0FBT0Qsa0VBU0M7QUEyQ0Qsb0RBNENDO0FBUUQsMEVBcUNDO0FBaGJELDJCQUE4QztBQUM5QywrQkFBNkU7QUFDN0UsaUNBQWlDO0FBQ2pDLGlEQUFpRTtBQUVqRSxrQ0FBaUM7QUFFakM7O0dBRUc7QUFDSCxTQUFnQixhQUFhLENBQUMsY0FBa0M7SUFDOUQsT0FBTyxDQUNMLGNBQWMsS0FBSyxpQ0FBa0IsQ0FBQyxJQUFJO1FBQzFDLGNBQWMsS0FBSyxpQ0FBa0IsQ0FBQyxZQUFZLENBQ25ELENBQUM7QUFDSixDQUFDO0FBRUQ7O0dBRUc7QUFDSCxTQUFnQixXQUFXLENBQUMsY0FBa0M7SUFDNUQsT0FBTyxDQUNMLGNBQWMsS0FBSyxpQ0FBa0IsQ0FBQyxLQUFLO1FBQzNDLGNBQWMsS0FBSyxpQ0FBa0IsQ0FBQyxVQUFVLENBQ2pELENBQUM7QUFDSixDQUFDO0FBRUQ7O0dBRUc7QUFDSCxTQUFnQixLQUFLLENBQUMsY0FBa0M7SUFDdEQsT0FBTyxjQUFjLEtBQUssaUNBQWtCLENBQUMsR0FBRyxDQUFDO0FBQ25ELENBQUM7QUFFRDs7O0dBR0c7QUFDSCxTQUFnQixXQUFXLENBQ3pCLGNBQW1DLEVBQ25DLEdBQVk7SUFFWixJQUFJLEdBQVcsQ0FBQztJQUNoQixRQUFRLGNBQWMsRUFBRSxDQUFDO1FBQ3ZCLEtBQUssaUNBQWtCLENBQUMsSUFBSTtZQUMxQixHQUFHLEdBQUcsV0FBVyxDQUFDO1lBQ2xCLE1BQU07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LElBQUksTUFBTSxDQUFDLE1BQU0sQ0FBQyxjQUFjLEVBQUUsVUFBVSxFQUFFLE9BQU8sQ0FBQyxFQUFFLENBQUM7UUFDdkQsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBRUQsd0NBQXdDO0lBQ3hDLElBQUksQ0FBQyxNQUFNLENBQUMsVUFBVSxDQUFDLGNBQWMsRUFBRSxVQUFVLEVBQUUsT0FBTyxDQUFDLEVBQUUsQ0FBQztRQUM1RCxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFFRCx5RUFBeUU7SUFDekUsMEVBQTBFO0lBQzFFLDZFQUE2RTtJQUM3RSxFQUFFO0lBQ0YsaUNBQWlDO0lBQ2pDLHFDQUFxQztJQUNyQyx1REFBdUQ7SUFDdkQsd0RBQXdEO0lBQ3hELEVBQUU7SUFDRiw2RUFBNkU7SUFDN0Usa0VBQWtFO0lBQ2xFLDBFQUEwRTtJQUMxRSxpRUFBaUU7SUFFakUsT0FBTyxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQ2YsTUFBTSxDQUFDLFVBQVUsQ0FBQyxjQUFjLEVBQUUsT0FBTyxDQUFDLElBQUksT0FBTyxFQUNyRCxNQUFNLENBQUMsVUFBVSxDQUFDLFVBQVUsRUFBRSxPQUFPLENBQUMsSUFBSSxPQUFPLENBQ2xELENBQUM7QUFDSixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgZXhpc3RzU3luYywgcmVhZEZpbGVTeW5jIH0gZnJvbSBcImZzXCI7XG5pbXBvcnQgeyBiYXNlbmFtZSwgZGlybmFtZSwgZXh0bmFtZSwgam9pbiwgc2VwLCByZXNvbHZlLCBwb3NpeCB9IGZyb20gXCJwYXRoXCI7XG5pbXBvcnQgKiBhcyBzZW12ZXIgZnJvbSBcInNlbXZlclwiO1xuaW1wb3J0IHsgTm9kZVBhY2thZ2UsIE5vZGVQYWNrYWdlTWFuYWdlciB9IGZyb20gXCIuL25vZGUtcGFja2FnZVwiO1xuaW1wb3J0IHR5cGUgeyBQcm9qZWN0IH0gZnJvbSBcIi4uL3Byb2plY3RcIjtcbmltcG9ydCB7IGZpbmRVcCB9IGZyb20gXCIuLi91dGlsXCI7XG5cbi8qKlxuICogQ2hlY2sgaWYgcGFja2FnZSBtYW5hZ2VyIGlzIHlhcm4gY2xhc3NpYy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzWWFybkNsYXNzaWMocGFja2FnZU1hbmFnZXI6IE5vZGVQYWNrYWdlTWFuYWdlcik6IGJvb2xlYW4ge1xuICByZXR1cm4gKFxuICAgIHBhY2thZ2VNYW5hZ2VyID09PSBOb2RlUGFja2FnZU1hbmFnZXIuWUFSTiB8fFxuICAgIHBhY2thZ2VNYW5hZ2VyID09PSBOb2RlUGFja2FnZU1hbmFnZXIuWUFSTl9DTEFTU0lDXG4gICk7XG59XG5cbi8qKlxuICogQ2hlY2sgaWYgcGFja2FnZSBtYW5hZ2VyIGlzIHlhcm4gYmVycnkuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc1lhcm5CZXJyeShwYWNrYWdlTWFuYWdlcjogTm9kZVBhY2thZ2VNYW5hZ2VyKTogYm9vbGVhbiB7XG4gIHJldHVybiAoXG4gICAgcGFja2FnZU1hbmFnZXIgPT09IE5vZGVQYWNrYWdlTWFuYWdlci5ZQVJOMiB8fFxuICAgIHBhY2thZ2VNYW5hZ2VyID09PSBOb2RlUGFja2FnZU1hbmFnZXIuWUFSTl9CRVJSWVxuICApO1xufVxuXG4vKipcbiAqIENoZWNrIGlmIHBhY2thZ2UgbWFuYWdlciBpcyBucG0uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc05wbShwYWNrYWdlTWFuYWdlcjogTm9kZVBhY2thZ2VNYW5hZ2VyKTogYm9vbGVhbiB7XG4gIHJldHVybiBwYWNrYWdlTWFuYWdlciA9PT0gTm9kZVBhY2thZ2VNYW5hZ2VyLk5QTTtcbn1cblxuLyoqXG4gKiBSZXR1cm5zIHRoZSBleGVjIGNvbW1hbmQgcHJlZml4IGZvciB0aGUgZ2l2ZW4gcGFja2FnZSBtYW5hZ2VyLCBvciBkZWZhdWx0cyB0byBucHggaWYgbm9uIHByb3ZpZGVkLlxuICogT3B0aW9uYWxseSBmb2xsb3dlZCBieSBhIGJpbmFyeSBuYW1lLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZXhlY0NvbW1hbmQoXG4gIHBhY2thZ2VNYW5hZ2VyPzogTm9kZVBhY2thZ2VNYW5hZ2VyLFxuICBiaW4/OiBzdHJpbmcsXG4pOiBzdHJpbmcge1xuICBsZXQgY21kOiBzdHJpbmc7XG4gIHN3aXRjaCAocGFja2FnZU1hbmFnZXIpIHtcbiAgICBjYXNlIE5vZGVQYWNrYWdlTWFuYWdlci5QTlBNOlxuICAgICAgY21kID0gXCJwbnBtIGV4ZWNcIjtcbiAgICAgIGJyZWFrO1xuICAgIGNhc2UgTm9kZVBhY2thZ2VNYW5hZ2VyLllBUk4yOlxuICAgIGNhc2UgTm9kZVBhY2thZ2VNYW5hZ2VyLllBUk5fQkVSUlk6XG4gICAgICBjbWQgPSBcInlhcm5cIjtcbiAgICAgIGJyZWFrO1xuICAgIGNhc2UgTm9kZVBhY2thZ2VNYW5hZ2VyLkJVTjpcbiAgICAgIGNtZCA9IFwiYnVueFwiO1xuICAgICAgYnJlYWs7XG4gICAgY2FzZSBOb2RlUGFja2FnZU1hbmFnZXIuTlBNOlxuICAgIGNhc2UgTm9kZVBhY2thZ2VNYW5hZ2VyLllBUk46XG4gICAgY2FzZSBOb2RlUGFja2FnZU1hbmFnZXIuWUFSTl9DTEFTU0lDOlxuICAgIGRlZmF1bHQ6XG4gICAgICBjbWQgPSBcIm5weFwiO1xuICAgICAgYnJlYWs7XG4gIH1cbiAgcmV0dXJuIGJpbiA/IGAke2NtZH0gJHtiaW59YCA6IGNtZDtcbn1cblxuLyoqXG4gKiBSZXR1cm5zIHRoZSBjb21tYW5kIHRvIGV4ZWN1dGUgYSBiaW5hcnkgd2l0aCB0aGUgZ2l2ZW4gcGFja2FnZSBtYW5hZ2VyLCB3aXRob3V0IHJlcXVpcmluZyBpbnN0YWxsYXRpb24gb2YgdGhhdCBiaW5hcnkgYXMgYSBwcm9qZWN0IGRlcGVuZGVuY3kuXG4gKiBAcGFyYW0gcGFja2FnZU1hbmFnZXIgVGhlIHBhY2thZ2UgbWFuYWdlciB0byB1c2Ugd2hlbiBleGVjdXRpbmcgdGhlIGNvbW1hbmQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBleGVjdXRlQ29tbWFuZFByaW9ySW5zdGFsbGF0aW9uKFxuICBwYWNrYWdlTWFuYWdlcjogTm9kZVBhY2thZ2VNYW5hZ2VyLFxuKTogc3RyaW5nIHtcbiAgc3dpdGNoIChwYWNrYWdlTWFuYWdlcikge1xuICAgIGNhc2UgTm9kZVBhY2thZ2VNYW5hZ2VyLlBOUE06XG4gICAgICByZXR1cm4gXCJwbnBtIGRseFwiO1xuICAgIGNhc2UgTm9kZVBhY2thZ2VNYW5hZ2VyLllBUk4yOlxuICAgIGNhc2UgTm9kZVBhY2thZ2VNYW5hZ2VyLllBUk5fQkVSUlk6XG4gICAgICByZXR1cm4gXCJ5YXJuIGRseFwiO1xuICAgIGNhc2UgTm9kZVBhY2thZ2VNYW5hZ2VyLkJVTjpcbiAgICAgIHJldHVybiBcImJ1bnhcIjtcbiAgICBjYXNlIE5vZGVQYWNrYWdlTWFuYWdlci5OUE06XG4gICAgY2FzZSBOb2RlUGFja2FnZU1hbmFnZXIuWUFSTjpcbiAgICBjYXNlIE5vZGVQYWNrYWdlTWFuYWdlci5ZQVJOX0NMQVNTSUM6XG4gICAgZGVmYXVsdDpcbiAgICAgIHJldHVybiBcIm5weFwiO1xuICB9XG59XG5cbi8qKlxuICogQmFzaWMgaW50ZXJmYWNlIGZvciBgcGFja2FnZS5qc29uYC5cbiAqL1xuaW50ZXJmYWNlIFBhY2thZ2VNYW5pZmVzdCB7XG4gIFtrZXk6IHN0cmluZ106IGFueTtcblxuICAvKipcbiAgICogUGFja2FnZSBuYW1lLlxuICAgKi9cbiAgbmFtZTogc3RyaW5nO1xuICAvKipcbiAgICogUGFja2FnZSB2ZXJzaW9uLlxuICAgKi9cbiAgdmVyc2lvbjogc3RyaW5nO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcmVuZGVyQnVuZGxlTmFtZShlbnRyeXBvaW50OiBzdHJpbmcpIHtcbiAgY29uc3QgcGFydHMgPSBqb2luKGVudHJ5cG9pbnQpLnNwbGl0KHNlcCk7XG4gIGlmIChwYXJ0c1swXSA9PT0gXCJzcmNcIikge1xuICAgIHBhcnRzLnNoaWZ0KCk7IC8vIGp1c3QgcmVtb3ZlICdzcmMnIGlmIGl0cyB0aGUgZmlyc3QgZWxlbWVudCBmb3IgZXJnb25vbWljc1xuICB9XG5cbiAgY29uc3QgcCA9IHBhcnRzLmpvaW4ocG9zaXguc2VwKTtcbiAgY29uc3QgZGlyID0gZGlybmFtZShwKTtcbiAgY29uc3QgYmFzZSA9IGJhc2VuYW1lKHAsIGV4dG5hbWUocCkpO1xuICByZXR1cm4gcG9zaXguam9pbihkaXIsIGJhc2UpO1xufVxuXG4vKipcbiAqIFJlZ2V4IGZvciBBV1MgQ29kZUFydGlmYWN0IHJlZ2lzdHJ5XG4gKi9cbmV4cG9ydCBjb25zdCBjb2RlQXJ0aWZhY3RSZWdleCA9XG4gIC9eaHR0cHM6XFwvXFwvKD88cmVnaXN0cnk+KD88ZG9tYWluPlteXFwuXSspLSg/PGFjY291bnRJZD5cXGR7MTJ9KVxcLmRcXC5jb2RlYXJ0aWZhY3RcXC4oPzxyZWdpb24+W15cXC5dKykuKlxcLmFtYXpvbmF3c1xcLmNvbVxcLy4qXFwvKD88cmVwb3NpdG9yeT5bXlxcL10rKVxcLykvO1xuXG4vKipcbiAqIGdldHMgQVdTIGRldGFpbHMgZnJvbSB0aGUgQ29kZSBBcnRpZmFjdCByZWdpc3RyeSBVUkxcbiAqIHRocm93cyBleGNlcHRpb24gaWYgbm90IG1hdGNoaW5nIGV4cGVjdGVkIHBhdHRlcm5cbiAqIEBwYXJhbSByZWdpc3RyeVVybCBDb2RlIEFydGlmYWN0IHJlZ2lzdHJ5IFVSTFxuICogQHJldHVybnMgb2JqZWN0IGNvbnRhaW5pbmcgdGhlIChkb21haW4sIGFjY291bnRJZCwgcmVnaW9uLCByZXBvc2l0b3J5KVxuICovXG5leHBvcnQgZnVuY3Rpb24gZXh0cmFjdENvZGVBcnRpZmFjdERldGFpbHMocmVnaXN0cnlVcmw6IHN0cmluZykge1xuICBjb25zdCBtYXRjaCA9IHJlZ2lzdHJ5VXJsLm1hdGNoKGNvZGVBcnRpZmFjdFJlZ2V4KTtcbiAgaWYgKG1hdGNoPy5ncm91cHMpIHtcbiAgICBjb25zdCB7IGRvbWFpbiwgYWNjb3VudElkLCByZWdpb24sIHJlcG9zaXRvcnksIHJlZ2lzdHJ5IH0gPSBtYXRjaC5ncm91cHM7XG4gICAgcmV0dXJuIHsgZG9tYWluLCBhY2NvdW50SWQsIHJlZ2lvbiwgcmVwb3NpdG9yeSwgcmVnaXN0cnkgfTtcbiAgfVxuICB0aHJvdyBuZXcgRXJyb3IoXCJDb3VsZCBub3QgZ2V0IENvZGVBcnRpZmFjdCBkZXRhaWxzIGZyb20gbnBtIFJlZ2lzdHJ5XCIpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gbWluVmVyc2lvbih2ZXJzaW9uOiBzdHJpbmcpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICBpZiAoc2VtdmVyLnZhbGlkUmFuZ2UodmVyc2lvbikpIHtcbiAgICByZXR1cm4gc2VtdmVyLm1pblZlcnNpb24odmVyc2lvbik/LnZlcnNpb247XG4gIH0gZWxzZSB7XG4gICAgcmV0dXJuIHZlcnNpb247XG4gIH1cbn1cblxuLyoqXG4gKiBBdHRlbXB0IHRvIHJlc29sdmUgbG9jYXRpb24gb2YgdGhlIGdpdmVuIGBtb2R1bGVJZGAuXG4gKiBAcGFyYW0gbW9kdWxlSWQgTW9kdWxlIElEIHRvIGxvb2t1cC5cbiAqIEBwYXJhbSBvcHRpb25zIFBhc3NlZCB0aHJvdWdoIHRvIGByZXF1aXJlLnJlc29sdmVgLlxuICovXG5leHBvcnQgZnVuY3Rpb24gdHJ5UmVzb2x2ZU1vZHVsZShcbiAgbW9kdWxlSWQ6IHN0cmluZyxcbiAgb3B0aW9ucz86IHsgcGF0aHM6IHN0cmluZ1tdIH0sXG4pOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICB0cnkge1xuICAgIHJldHVybiByZXF1aXJlLnJlc29sdmUobW9kdWxlSWQsIG9wdGlvbnMpO1xuICB9IGNhdGNoIHtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG59XG5cbi8qKlxuICogQXR0ZW1wdCB0byByZXNvbHZlIGEgbW9kdWxlJ3MgbWFuaWZlc3QgKHBhY2thZ2UuanNvbikgcGF0aCB2aWEgYHJlcXVpcmUucmVzb2x2ZWAgbG9va3VwLlxuICpcbiAqIEByZW1hcmtzXG4gKiBJZiB0aGUgdGFyZ2V0IHBhY2thZ2UgaGFzIGBleHBvcnRzYCB0aGF0IGRpZmZlciBmcm9tIHRoZSBkZWZhdWx0XG4gKiAoaS5lLCBpdCBkZWZpbmVzIHRoZSBgZXhwb3J0c2AgZmllbGQgaW4gaXRzIG1hbmlmZXN0KSBhbmQgZG9lcyBub3RcbiAqIGV4cGxpY2l0bHkgaW5jbHVkZSBhbiBlbnRyeSBmb3IgYHBhY2thZ2UuanNvbmAsIHRoaXMgc3RyYXRlZ3kgd2lsbCBmYWlsLlxuICogU2VlIHtAbGluayB0cnlSZXNvbHZlTWFuaWZlc3RQYXRoRnJvbURlZmF1bHRFeHBvcnR9IGFzIGFuIGFsdGVybmF0aXZlLlxuICpcbiAqIEBwYXJhbSBtb2R1bGVJZCBNb2R1bGUgSUQgdG8gbG9va3VwLlxuICogQHBhcmFtIG9wdGlvbnMgUGFzc2VkIHRocm91Z2ggdG8gYHJlcXVpcmUucmVzb2x2ZWAuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB0cnlSZXNvbHZlTW9kdWxlTWFuaWZlc3RQYXRoKFxuICBtb2R1bGVJZDogc3RyaW5nLFxuICBvcHRpb25zPzogeyBwYXRoczogc3RyaW5nW10gfSxcbik6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIC8vIGNhbm5vdCBqdXN0IGByZXF1aXJlKCdkZXBlbmRlbmN5L3BhY2thZ2UuanNvbicpYCBoZXJlIGJlY2F1c2VcbiAgLy8gYG9wdGlvbnMucGF0aHNgIG1heSBub3Qgb3ZlcmxhcCB3aXRoIHRoaXMgbm9kZSBwcm9jJ3MgcmVzb2x1dGlvbiBwYXRocy5cbiAgY29uc3QgbWFuaWZlc3RJZCA9IGAke21vZHVsZUlkfS9wYWNrYWdlLmpzb25gO1xuICByZXR1cm4gdHJ5UmVzb2x2ZU1vZHVsZShtYW5pZmVzdElkLCBvcHRpb25zKTtcbn1cblxuLyoqXG4gKiBBdHRlbXB0IHRvIHJlc29sdmUgYSBtb2R1bGUncyBtYW5pZmVzdCAocGFja2FnZS5qc29uKSBwYXRoIGJ5IGxvb2tpbmcgZm9yIHRoZSBuZWFyZXN0XG4gKiBgcGFja2FnZS5qc29uYCBmaWxlIHRoYXQgaXMgYW4gYW5jZXN0b3IgdG8gdGhlIG1vZHVsZSdzIGRlZmF1bHQgZXhwb3J0IGxvY2F0aW9uLlxuICpcbiAqIEBwYXJhbSBtb2R1bGVJZCBNb2R1bGUgSUQgdG8gbG9va3VwLlxuICogQHBhcmFtIG9wdGlvbnMgUGFzc2VkIHRocm91Z2ggdG8gYHJlcXVpcmUucmVzb2x2ZWAuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB0cnlSZXNvbHZlTWFuaWZlc3RQYXRoRnJvbURlZmF1bHRFeHBvcnQoXG4gIG1vZHVsZUlkOiBzdHJpbmcsXG4gIG9wdGlvbnM/OiB7IHBhdGhzOiBzdHJpbmdbXSB9LFxuKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgY29uc3QgZGVmYXVsdEV4cG9ydFBhdGggPSB0cnlSZXNvbHZlTW9kdWxlKG1vZHVsZUlkLCBvcHRpb25zKTtcbiAgaWYgKCFkZWZhdWx0RXhwb3J0UGF0aCkge1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbiAgY29uc3QgbW9kdWxlRGlyID0gZmluZFVwKFwicGFja2FnZS5qc29uXCIsIGRlZmF1bHRFeHBvcnRQYXRoKTtcbiAgaWYgKCFtb2R1bGVEaXIpIHtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG4gIHJldHVybiBqb2luKG1vZHVsZURpciwgXCJwYWNrYWdlLmpzb25cIik7XG59XG5cbi8qKlxuICogQXR0ZW1wdCB0byByZXNvbHZlIGEgbW9kdWxlJ3MgbWFuaWZlc3QgKHBhY2thZ2UuanNvbikgcGF0aCBieSBjaGVja2luZyBmb3IgaXRzIGV4aXN0ZW5jZSB1bmRlciBgbm9kZV9tb2R1bGVzYCByZWxhdGl2ZSB0byBgYmFzZVBhdGhgLlxuICpcbiAqIEByZW1hcmtzXG4gKiBUaGlzIHN0cmF0ZWd5IGNhbiBiZSBoZWxwZnVsIGluIHRoZSBzY2VuYXJpbyB0aGF0IGEgbW9kdWxlIGRlZmluZXNcbiAqIGN1c3RvbSBleHBvcnRzIHdpdGhvdXQgYHBhY2thZ2UuanNvbmAgYW5kIG5vIGRlZmF1bHQgZXhwb3J0IChpLmUsIHNvbWUgdHlwZSBkZWZpbml0aW9uIHBhY2thZ2VzKS5cbiAqXG4gKiBAcGFyYW0gbW9kdWxlSWQgTW9kdWxlIElEIHRvIGxvb2t1cC5cbiAqIEBwYXJhbSBiYXNlUGF0aCBSb290IHBhdGggdG8gc2VhcmNoIGZyb20uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB0cnlSZXNvbHZlTWFuaWZlc3RQYXRoRnJvbVBhdGgoXG4gIG1vZHVsZUlkOiBzdHJpbmcsXG4gIGJhc2VQYXRoOiBzdHJpbmcsXG4pIHtcbiAgY29uc3QgYmFzZSA9IGJhc2VQYXRoLmluY2x1ZGVzKFwibm9kZV9tb2R1bGVzXCIpXG4gICAgPyBiYXNlUGF0aFxuICAgIDogam9pbihiYXNlUGF0aCwgXCJub2RlX21vZHVsZXNcIik7XG4gIGNvbnN0IGZpbGVQYXRoID0gcmVzb2x2ZShiYXNlLCAuLi5tb2R1bGVJZC5zcGxpdChcIi9cIiksIFwicGFja2FnZS5qc29uXCIpO1xuICBpZiAoZXhpc3RzU3luYyhmaWxlUGF0aCkpIHtcbiAgICByZXR1cm4gZmlsZVBhdGg7XG4gIH1cbiAgcmV0dXJuIHVuZGVmaW5lZDtcbn1cblxuLyoqXG4gKiBBdHRlbXB0IHRvIHJlc29sdmUgYSBtb2R1bGUncyBtYW5pZmVzdCAocGFja2FnZS5qc29uKSBwYXRoIGJ5IHNlYXJjaGluZyBmb3IgaXQgaW4gdGhlIG9wdGlvbmFsbHkgcHJvdmlkZWQgcGF0aHMgYXJyYXlcbiAqIGFzIHdlbGwgYXMgdGhlIGN1cnJlbnQgbm9kZSBwcm9jZXNzZXMnIGRlZmF1bHQgcmVzb2x1dGlvbiBwYXRocy5cbiAqIEBwYXJhbSBtb2R1bGVJZCBNb2R1bGUgSUQgdG8gc2VhcmNoIGZvci5cbiAqIEBwYXJhbSBvcHRpb25zIFNlYXJjaCBvcHRpb25zLlxuICovXG5leHBvcnQgZnVuY3Rpb24gdHJ5UmVzb2x2ZU1hbmlmZXN0UGF0aEZyb21TZWFyY2goXG4gIG1vZHVsZUlkOiBzdHJpbmcsXG4gIG9wdGlvbnM/OiB7IHBhdGhzOiBzdHJpbmdbXSB9LFxuKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgY29uc3Qgc2VhcmNoUGF0aHMgPSBbXG4gICAgLi4uKG9wdGlvbnM/LnBhdGhzID8/IFtdKSxcbiAgICAuLi4ocmVxdWlyZS5yZXNvbHZlLnBhdGhzKG1vZHVsZUlkKSA/PyBbXSksXG4gIF07XG4gIGZvciAoY29uc3QgcGF0aCBvZiBzZWFyY2hQYXRocykge1xuICAgIGNvbnN0IHJlc3VsdCA9IHRyeVJlc29sdmVNYW5pZmVzdFBhdGhGcm9tUGF0aChtb2R1bGVJZCwgcGF0aCk7XG4gICAgLy8gZWFybHkgcmV0dXJuIG9uIGZpcnN0IHJlc3VsdC5cbiAgICBpZiAocmVzdWx0KSB7XG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cbiAgfVxuICByZXR1cm4gdW5kZWZpbmVkO1xufVxuXG4vKipcbiAqIEF0dGVtcHQgdG8gcmVzb2x2ZSBhIG1vZHVsZSdzIG1hbmlmZXN0IChwYWNrYWdlLmpzb24pIHVzaW5nIG11bHRpcGxlIHN0cmF0ZWdpZXMuXG4gKiBAcGFyYW0gbW9kdWxlSWQgTW9kdWxlIHRvIHJlc29sdmUgbWFuaWZlc3QgcGF0aCBmb3IuXG4gKiBAcGFyYW0gb3B0aW9ucyBSZXNvbHV0aW9uIG9wdGlvbnMuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB0cnlSZXNvbHZlTW9kdWxlTWFuaWZlc3QoXG4gIG1vZHVsZUlkOiBzdHJpbmcsXG4gIG9wdGlvbnM/OiB7IHBhdGhzOiBzdHJpbmdbXSB9LFxuKTogUGFja2FnZU1hbmlmZXN0IHwgdW5kZWZpbmVkIHtcbiAgY29uc3Qgc3RyYXRlZ2llcyA9IFtcbiAgICB0cnlSZXNvbHZlTW9kdWxlTWFuaWZlc3RQYXRoLFxuICAgIHRyeVJlc29sdmVNYW5pZmVzdFBhdGhGcm9tRGVmYXVsdEV4cG9ydCxcbiAgICB0cnlSZXNvbHZlTWFuaWZlc3RQYXRoRnJvbVNlYXJjaCxcbiAgXTtcbiAgZm9yIChjb25zdCBzdHJhdGVneSBvZiBzdHJhdGVnaWVzKSB7XG4gICAgY29uc3QgcmVzdWx0ID0gc3RyYXRlZ3kobW9kdWxlSWQsIG9wdGlvbnMpO1xuICAgIC8vIGVhcmx5IHJldHVybiBvbiBmaXJzdCByZXN1bHQuXG4gICAgaWYgKHJlc3VsdCkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgbWFuaWZlc3QgPSBKU09OLnBhcnNlKFxuICAgICAgICAgIHJlYWRGaWxlU3luYyhyZXN1bHQsIFwidXRmOFwiKSxcbiAgICAgICAgKSBhcyBQYWNrYWdlTWFuaWZlc3Q7XG4gICAgICAgIC8vIHZlcmlmeSBuYW1lIG1hdGNoZXMgdGFyZ2V0IG1vZHVsZS5cbiAgICAgICAgaWYgKG1hbmlmZXN0Lm5hbWUgPT09IG1vZHVsZUlkKSB7XG4gICAgICAgICAgcmV0dXJuIG1hbmlmZXN0O1xuICAgICAgICB9XG4gICAgICB9IGNhdGNoIHtcbiAgICAgICAgLy8gY29udGludWUgdG8gbmV4dCBzdHJhdGVneS5cbiAgICAgIH1cbiAgICB9XG4gIH1cbiAgcmV0dXJuIHVuZGVmaW5lZDtcbn1cblxuLyoqXG4gKiBBdHRlbXB0IHRvIHJlc29sdmUgdGhlIGluc3RhbGxlZCB2ZXJzaW9uIG9mIGEgZ2l2ZW4gZGVwZW5kZW5jeS5cbiAqIEBwYXJhbSBkZXBlbmRlbmN5TmFtZSBOYW1lIG9mIGRlcGVuZGVuY3kuXG4gKiBAcGFyYW0gb3B0aW9ucyBPcHRpb25hbCBvcHRpb25zIHBhc3NlZCB0aHJvdWdoIHRvIGByZXF1aXJlLnJlc29sdmVgLlxuICovXG5leHBvcnQgZnVuY3Rpb24gdHJ5UmVzb2x2ZURlcGVuZGVuY3lWZXJzaW9uKFxuICBkZXBlbmRlbmN5TmFtZTogc3RyaW5nLFxuICBvcHRpb25zPzogeyBwYXRoczogc3RyaW5nW10gfSxcbik6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IG1hbmlmZXN0ID0gdHJ5UmVzb2x2ZU1vZHVsZU1hbmlmZXN0KGRlcGVuZGVuY3lOYW1lLCBvcHRpb25zKTtcbiAgaWYgKCFtYW5pZmVzdCkge1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbiAgcmV0dXJuIG1hbmlmZXN0Py52ZXJzaW9uO1xufVxuXG4vKipcbiAqIFdoZXRoZXIgdGhlIGdpdmVuIGRlcGVuZGVuY3kgdmVyc2lvbiBpcyBpbnN0YWxsZWRcbiAqXG4gKiBUaGlzIGNhbiBiZSB1c2VkIHRvIHRlc3QgZm9yIHRoZSBwcmVzZW5jZSBvZiBjZXJ0YWluIHZlcnNpb25zIG9mIGRldkRlcGVuZGVuY2llcyxcbiAqIGFuZCBkbyBzb21ldGhpbmcgZGVwZW5kZW5jeS1zcGVjaWZpYyBpbiBjZXJ0YWluIENvbXBvbmVudHMuIEZvciBleGFtcGxlLCB0ZXN0IGZvclxuICogYSB2ZXJzaW9uIG9mIEplc3QgYW5kIGdlbmVyYXRlIGRpZmZlcmVudCBjb25maWdzIGJhc2VkIG9uIHRoZSBKZXN0IHZlcnNpb24uXG4gKlxuICogTk9URTogVGhlIGltcGxlbWVudGF0aW9uIG9mIHRoaXMgZnVuY3Rpb24gY3VycmVudGx5IGlzIGN1cnJlbnRseVxuICogYXBwcm94aW1hdGU6IHRvIGRvIGl0IGNvcnJlY3RseSwgd2Ugd291bGQgbmVlZCBhIHNlcGFyYXRlIGltcGxlbWVudGF0aW9uXG4gKiBmb3IgZXZlcnkgcGFja2FnZSBtYW5hZ2VyLCB0byBxdWVyeSBpdHMgaW5zdGFsbGVkIHZlcnNpb24gKGVpdGhlciB0aGF0LCBvciB3ZVxuICogd291bGQgY29kZSB0byBxdWVyeSBgcGFja2FnZS1sb2NrLmpzb25gLCBgeWFybi5sb2NrYCwgZXRjLi4uKS5cbiAqXG4gKiBJbnN0ZWFkLCB3ZSB3aWxsIGxvb2sgYXQgYHBhY2thZ2UuanNvbmAsIGFuZCBhc3N1bWUgdGhhdCB0aGUgdmVyc2lvbnNcbiAqIHBpY2tlZCBieSB0aGUgcGFja2FnZSBtYW5hZ2VyIG1hdGNoIH50aGF0LiBUaGlzIHdpbGwgd29yayB3ZWxsIGVub3VnaCBmb3JcbiAqIG1ham9yIHZlcnNpb24gY2hlY2tzLCBidXQgbWF5IGZhaWwgZm9yIHBvaW50IHZlcnNpb25zLlxuICpcbiAqIFdoYXQgd2UgU0hPVUxEIGRvIGlzOiBgYWN0dWFsVmVyc2lvbiDiiIggY2hlY2tSYW5nZWAuXG4gKlxuICogV2hhdCB3ZSBkbyBpbnN0ZWFkIGlzIGEgc2xpZ2h0bHkgbW9yZSBzb3BoaXN0aWNhdGVkIHZlcnNpb24gb2ZcbiAqIGByZXF1ZXN0ZWRSYW5nZSDiiKkgY2hlY2tSYW5nZSAhPSDiiIVgLiBUaGlzIHdpbGwgYWx3YXlzIGdpdmUgYSBjb3JyZWN0IHJlc3VsdCBpZlxuICogYHJlcXVlc3RlZFJhbmdlIOKKhiBjaGVja1JhbmdlYCwgYnV0IG1heSBnaXZlIGZhbHNlIHBvc2l0aXZlcyB3aGVuIGBjaGVja1JhbmdlXG4gKiDiioYgcmVxdWVzdGVkUmFuZ2VgLlxuICpcbiAqIE1heSByZXR1cm4gYHVuZGVmaW5lZGAgaWYgdGhlIHF1ZXN0aW9uIGNhbm5vdCBiZSBhbnN3ZXJlZC4gVGhlc2UgaW5jbHVkZSB0aGVcbiAqIGZvbGxvd2luZyBjYXNlczpcbiAqXG4gKiAgIC0gVGhlIGRlcGVuZGVuY3kgaXMgcmVxdWVzdGVkIHZpYSBsb2NhbCBmaWxlIGRlcGVuZGVuY2llcyAoYGZpbGU6Ly8uLi5gKVxuICogICAtIFRoZSBkZXBlbmRlbmN5IHVzZXMgYW4gb3RoZXIgdHlwZSBvZiBVUkwsIHN1Y2ggYXMgYSBHaXRIdWIgVVJMXG4gKiAgIC0gVGhlIGRlcGVuZGVuY3kgaXMgbm90IGZvdW5kIGluIHRoZSBgcGFja2FnZS5qc29uYCwgc3VjaCBhcyB3aGVuXG4gKiAgICAgYm9vdHN0cmFwcGluZyBmcm9tIGFuIGV4dGVybmFsIHByb2plbiBwYWNrYWdlLCBhbmQgdGhlIGBwYWNrYWdlLmpzb25gXG4gKiAgICAgZmlsZSBvbmx5IGhhcyB0aGF0IG9uZSBleHRlcm5hbCBwYWNrYWdlIGFzIGEgZGVwZW5kZW5jeVxuICpcbiAqIE90aGVyd2lzZSBpdCB3aWxsIHJldHVybiBgdHJ1ZWAgaWYgdGhlIGluc3RhbGxlZCB2ZXJzaW9uIGlzIHByb2JhYmx5IGluIHRoZVxuICogcmVxdWVzdGVkIHJhbmdlLCBhbmQgYGZhbHNlYCBpZiBpdCBpcyBwcm9iYWJseSBub3QuXG4gKlxuICogVGhpcyBBUEkgbWF5IGV2ZW50dWFsbHkgYmUgYWRkZWQgdG8gdGhlIHB1YmxpYyBwcm9qZW4gQVBJLCBidXQgb25seSBhZnRlclxuICogd2UgaW1wbGVtZW50IGV4YWN0IHZlcnNpb24gY2hlY2tpbmcuXG4gKlxuICogQHBhcmFtIGRlcGVuZGVuY3lOYW1lIFRoZSBuYW1lIG9mIHRoZSBkZXBlbmRlbmN5XG4gKiBAcGFyYW0gY2hlY2tSYW5nZSBBIHBhcnRpY3VsYXIgdmVyc2lvbiwgb3IgcmFuZ2Ugb2YgdmVyc2lvbnMuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBoYXNEZXBlbmRlbmN5VmVyc2lvbihcbiAgcHJvamVjdDogUHJvamVjdCxcbiAgZGVwZW5kZW5jeU5hbWU6IHN0cmluZyxcbiAgY2hlY2tSYW5nZTogc3RyaW5nLFxuKTogYm9vbGVhbiB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IGZpbGUgPSBOb2RlUGFja2FnZS5vZihwcm9qZWN0KT8uZmlsZTtcbiAgaWYgKCFmaWxlKSB7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuXG4gIGlmICghZXhpc3RzU3luYyhmaWxlLmFic29sdXRlUGF0aCkpIHtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG5cbiAgY29uc3QgcGogPSBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhmaWxlLmFic29sdXRlUGF0aCwgXCJ1dGYtOFwiKSk7XG5cbiAgLy8gVGVjaG5pY2FseSwgd2Ugc2hvdWxkIGJlIGludGVyc2VjdGluZyBhbGwgcmFuZ2VzIHRvIGNvbWUgdXAgd2l0aCB0aGUgbW9zdCBuYXJyb3cgZGVwZW5kZW5jeVxuICAvLyByYW5nZSwgYnV0IGBzZW12ZXJgIGRvZXNuJ3QgYWxsb3cgZG9pbmcgdGhhdCBhbmQgd2UgZG9uJ3Qgd2FudCB0byBhZGQgYSBkZXBlbmRlbmN5IG9uIGBzZW12ZXItaW50ZXJzZWN0YC5cbiAgLy9cbiAgLy8gTGV0J3MgdGFrZSB0aGUgZmlyc3QgZGVwZW5kZW5jeSBkZWNsYXJhdGlvbiB3ZSBmaW5kLCBhbmQgYXNzdW1lIHRoYXQgcGVvcGxlXG4gIC8vIHNldCB1cCB0aGVpciBgcGFja2FnZS5qc29uYCBjb3JyZWN0bHkuXG4gIGxldCByZXF1ZXN0ZWRSYW5nZTogc3RyaW5nIHwgdW5kZWZpbmVkO1xuICBmb3IgKGNvbnN0IGtleSBvZiBbXCJkZXBlbmRlbmNpZXNcIiwgXCJkZXZEZXBlbmRlbmNpZXNcIiwgXCJwZWVyRGVwZW5kZW5jaWVzXCJdKSB7XG4gICAgY29uc3QgZGVwcyA9IHBqW2tleV0gPz8ge307XG4gICAgbGV0IHJlcXVlc3RlZFZlcnNpb24gPSBkZXBzW2RlcGVuZGVuY3lOYW1lXTtcbiAgICBpZiAocmVxdWVzdGVkVmVyc2lvbikge1xuICAgICAgLy8gSWYgdGhpcyBpcyBub3QgYSB2YWxpZCByYW5nZSwgaXQgY291bGQgYmUgJ2ZpbGU6ZGVwLnRneicsIG9yIGEgR2l0SHViIFVSTC4gTm8gd2F5IHRvIGtub3cgd2hhdFxuICAgICAgLy8gdmVyc2lvbiB3ZSdyZSBnZXR0aW5nLCBiYWlsIG91dC5cbiAgICAgIGlmICghc2VtdmVyLnZhbGlkUmFuZ2UocmVxdWVzdGVkVmVyc2lvbikpIHtcbiAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgIH1cbiAgICAgIHJlcXVlc3RlZFJhbmdlID0gcmVxdWVzdGVkVmVyc2lvbjtcbiAgICAgIGJyZWFrO1xuICAgIH1cbiAgfVxuXG4gIC8vIElmIHRoZSBkZXBlbmRlbmN5IGlzIG5vdCBmb3VuZCBpbiB0aGUgYHBhY2thZ2UuanNvbmAsIHdlIGNhbid0IGFuc3dlciB0aGUgcXVlc3Rpb24gKHlldCkuXG4gIC8vIFRoaXMgbWVhbnMgdGhhdCB0aGUgZGVwZW5kZW5jeSBoYXNuJ3QgYmVlbiBhZGRlZCB5ZXQsIHdoaWNoIG1lYW5zIHdlIGtub3cgKHVwc3RyZWFtKSB3aGF0IHdlJ3JlIGdvaW5nIHRvIHJlcXVlc3QsXG4gIC8vIG9yIHdlJ3JlIGdvaW5nIHRvIGFzayBmb3IgJyonIGFuZCB3ZSdsbCBnZXQgdGhlIGxhdGVzdCB2ZXJzaW9uLlxuICBpZiAoIXJlcXVlc3RlZFJhbmdlKSB7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuXG4gIHJldHVybiBpbnN0YWxsZWRWZXJzaW9uUHJvYmFibHlNYXRjaGVzKHJlcXVlc3RlZFJhbmdlLCBjaGVja1JhbmdlKTtcbn1cblxuLyoqXG4gKiBXaGV0aGVyIHRoZSBnaXZlbiByZXF1ZXN0ZWRSYW5nZSAqcHJvYmFibHkqIGxlYWRzIHRvIHRoZSBpbnN0YWxsYXRpb24gb2YgYSB2ZXJzaW9uIHRoYXQgbWF0Y2hlcyBjaGVja1JhbmdlXG4gKlxuICogV2UgYXNzdW1lIHRoYXQgTlBNIGFsd2F5cyBpbnN0YWxscyB0aGUgbW9zdCByZWNlbnQgdmVyc2lvbiBvZiBhIHBhY2thZ2UgdGhhdFxuICogaXMgYWxsb3dlZCBieSB0aGUgcmVxdWVzdGVkUmFuZ2UuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpbnN0YWxsZWRWZXJzaW9uUHJvYmFibHlNYXRjaGVzKFxuICByZXF1ZXN0ZWRSYW5nZTogc3RyaW5nLFxuICBjaGVja1JhbmdlOiBzdHJpbmcsXG4pOiBib29sZWFuIHtcbiAgY29uc3Qgb3B0aW9ucyA9IHtcbiAgICBpbmNsdWRlUHJlcmVsZWFzZTogdHJ1ZSxcbiAgICBsb29zZTogdHJ1ZSxcbiAgfTtcblxuICAvLyBObyBxdWVzdGlvbnMgYXNrZWQ6IGFsd2F5cyB0cnVlXG4gIGlmIChzZW12ZXIuc3Vic2V0KHJlcXVlc3RlZFJhbmdlLCBjaGVja1JhbmdlLCBvcHRpb25zKSkge1xuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgLy8gQWxzbyBubyBxdWVzdGlvbnMgYXNrZWQ6IGFsd2F5cyBmYWxzZVxuICBpZiAoIXNlbXZlci5pbnRlcnNlY3RzKHJlcXVlc3RlZFJhbmdlLCBjaGVja1JhbmdlLCBvcHRpb25zKSkge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIC8vIE5vdyB3ZSdyZSBpbiB0cmlja3kgdGVycml0b3J5LiBXZSBpbnRlcnNlY3QsIGJ1dCBhcmVuJ3QgYSBmdWxsIHN1YnNldC5cbiAgLy8gV2UgYXJlIGluIG9uZSBvZiB0aGUgZm9sbG93aW5nIDIgc2l0dWF0aW9ucywgd2hpY2ggd2Ugd2lsbCB0aWUtYnJlYWsgYnlcbiAgLy8gYXNzdW1pbmcgTlBNIHdpbGwgaW5zdGFsbCB0aGUgbW9zdCByZWNlbnQgbWF0Y2hpbmcgdmVyc2lvbiBpbiAncmVxdWVzdGVkJy5cbiAgLy9cbiAgLy8gcmVxdWVzdGVkICB8IGNoZWNrICAgIHwgcmVzdWx0XG4gIC8vIC0tLS0tLS0tLS0tfC0tLS0tLS0tLS18LS0tLS0tLS0tLS1cbiAgLy8gICA+PSAyICAgICB8ICA+PSAzICAgIHwgcHJvYmFibHkgdHJ1ZSAoY2hhbmNlIG9mIEZQKVxuICAvLyAgIDw9IDIgICAgIHwgIDw9IDEgICAgfCBwcm9iYWJseSBmYWxzZSAoY2hhbmdlIG9mIEZOKVxuICAvL1xuICAvLyBgc2VtdmVyYCBkb2Vzbid0IG1ha2UgaXQgZWFzeSB0byBkaXN0aW5ndWlzaCB0aGVzZSBjYXNlcyAod2UgY2FuJ3QgcmVxdWVzdFxuICAvLyB0aGUgYG1heFZlcnNpb25gIHRoYXQgc2F0aXNmaWVzIGEgcmFuZ2UpLiBJbnN0ZWFkIHdoYXQgd2UgZG8gaXNcbiAgLy8gZ2V0IHRoZSBgbWluVmVyc2lvbmAgb2YgZWFjaCByYW5nZSwgYW5kIGlmIHRoZXkgY29tcGFyZSBlcXVhbCB3ZSBhc3N1bWVcbiAgLy8gd2UncmUgaW4gdGhlIGJvdHRvbSBjYXNlIHdpdGggYDw9YCBjaGVja3MsIGFuZCByZXR1cm4gYGZhbHNlYC5cblxuICByZXR1cm4gIXNlbXZlci5lcShcbiAgICBzZW12ZXIubWluVmVyc2lvbihyZXF1ZXN0ZWRSYW5nZSwgb3B0aW9ucykgPz8gXCIxLjIuM1wiLFxuICAgIHNlbXZlci5taW5WZXJzaW9uKGNoZWNrUmFuZ2UsIG9wdGlvbnMpID8/IFwiMS4yLjNcIixcbiAgKTtcbn1cbiJdfQ==