UNPKG

projen

Version:

CDK for software projects

321 lines 38.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.codeArtifactRegex = void 0; exports.isYarnClassic = isYarnClassic; exports.isYarnBerry = isYarnBerry; exports.isNpm = isNpm; 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; } 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9qYXZhc2NyaXB0L3V0aWwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBVUEsc0NBS0M7QUFLRCxrQ0FLQztBQUtELHNCQUVDO0FBa0JELDRDQVVDO0FBY0QsZ0VBT0M7QUFFRCxnQ0FNQztBQU9ELDRDQVNDO0FBY0Qsb0VBUUM7QUFTRCwwRkFhQztBQVlELHdFQVlDO0FBUUQsNEVBZ0JDO0FBT0QsNERBMkJDO0FBT0Qsa0VBU0M7QUEyQ0Qsb0RBNENDO0FBUUQsMEVBcUNDO0FBM1hELDJCQUE4QztBQUM5QywrQkFBNkU7QUFDN0UsaUNBQWlDO0FBQ2pDLGlEQUFpRTtBQUVqRSxrQ0FBaUM7QUFFakM7O0dBRUc7QUFDSCxTQUFnQixhQUFhLENBQUMsY0FBa0M7SUFDOUQsT0FBTyxDQUNMLGNBQWMsS0FBSyxpQ0FBa0IsQ0FBQyxJQUFJO1FBQzFDLGNBQWMsS0FBSyxpQ0FBa0IsQ0FBQyxZQUFZLENBQ25ELENBQUM7QUFDSixDQUFDO0FBRUQ7O0dBRUc7QUFDSCxTQUFnQixXQUFXLENBQUMsY0FBa0M7SUFDNUQsT0FBTyxDQUNMLGNBQWMsS0FBSyxpQ0FBa0IsQ0FBQyxLQUFLO1FBQzNDLGNBQWMsS0FBSyxpQ0FBa0IsQ0FBQyxVQUFVLENBQ2pELENBQUM7QUFDSixDQUFDO0FBRUQ7O0dBRUc7QUFDSCxTQUFnQixLQUFLLENBQUMsY0FBa0M7SUFDdEQsT0FBTyxjQUFjLEtBQUssaUNBQWtCLENBQUMsR0FBRyxDQUFDO0FBQ25ELENBQUM7QUFrQkQsU0FBZ0IsZ0JBQWdCLENBQUMsVUFBa0I7SUFDakQsTUFBTSxLQUFLLEdBQUcsSUFBQSxXQUFJLEVBQUMsVUFBVSxDQUFDLENBQUMsS0FBSyxDQUFDLFVBQUcsQ0FBQyxDQUFDO0lBQzFDLElBQUksS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLEtBQUssRUFBRSxDQUFDO1FBQ3ZCLEtBQUssQ0FBQyxLQUFLLEVBQUUsQ0FB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QUksQ0FBQztJQUNkLENBQUM7SUFFRCx3Q0FBd0M7SUFDeEMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsY0FBYyxFQUFFLFVBQVUsRUFBRSxPQUFPLENBQUMsRUFBRSxDQUFDO1FBQzVELE9BQU8sS0FBSyxDQUFDO0lBQ2YsQ0FBQztJQUVELHlFQUF5RTtJQUN6RSwwRUFBMEU7SUFDMUUsNkVBQTZFO0lBQzdFLEVBQUU7SUFDRixpQ0FBaUM7SUFDakMscUNBQXFDO0lBQ3JDLHVEQUF1RDtJQUN2RCx3REFBd0Q7SUFDeEQsRUFBRTtJQUNGLDZFQUE2RTtJQUM3RSxrRUFBa0U7SUFDbEUsMEVBQTBFO0lBQzFFLGlFQUFpRTtJQUVqRSxPQUFPLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FDZixNQUFNLENBQUMsVUFBVSxDQUFDLGNBQWMsRUFBRSxPQUFPLENBQUMsSUFBSSxPQUFPLEVBQ3JELE1BQU0sQ0FBQyxVQUFVLENBQUMsVUFBVSxFQUFFLE9BQU8sQ0FBQyxJQUFJLE9BQU8sQ0FDbEQsQ0FBQztBQUNKLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBleGlzdHNTeW5jLCByZWFkRmlsZVN5bmMgfSBmcm9tIFwiZnNcIjtcbmltcG9ydCB7IGJhc2VuYW1lLCBkaXJuYW1lLCBleHRuYW1lLCBqb2luLCBzZXAsIHJlc29sdmUsIHBvc2l4IH0gZnJvbSBcInBhdGhcIjtcbmltcG9ydCAqIGFzIHNlbXZlciBmcm9tIFwic2VtdmVyXCI7XG5pbXBvcnQgeyBOb2RlUGFja2FnZSwgTm9kZVBhY2thZ2VNYW5hZ2VyIH0gZnJvbSBcIi4vbm9kZS1wYWNrYWdlXCI7XG5pbXBvcnQgeyBQcm9qZWN0IH0gZnJvbSBcIi4uL3Byb2plY3RcIjtcbmltcG9ydCB7IGZpbmRVcCB9IGZyb20gXCIuLi91dGlsXCI7XG5cbi8qKlxuICogQ2hlY2sgaWYgcGFja2FnZSBtYW5hZ2VyIGlzIHlhcm4gY2xhc3NpYy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzWWFybkNsYXNzaWMocGFja2FnZU1hbmFnZXI6IE5vZGVQYWNrYWdlTWFuYWdlcik6IGJvb2xlYW4ge1xuICByZXR1cm4gKFxuICAgIHBhY2thZ2VNYW5hZ2VyID09PSBOb2RlUGFja2FnZU1hbmFnZXIuWUFSTiB8fFxuICAgIHBhY2thZ2VNYW5hZ2VyID09PSBOb2RlUGFja2FnZU1hbmFnZXIuWUFSTl9DTEFTU0lDXG4gICk7XG59XG5cbi8qKlxuICogQ2hlY2sgaWYgcGFja2FnZSBtYW5hZ2VyIGlzIHlhcm4gYmVycnkuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc1lhcm5CZXJyeShwYWNrYWdlTWFuYWdlcjogTm9kZVBhY2thZ2VNYW5hZ2VyKTogYm9vbGVhbiB7XG4gIHJldHVybiAoXG4gICAgcGFja2FnZU1hbmFnZXIgPT09IE5vZGVQYWNrYWdlTWFuYWdlci5ZQVJOMiB8fFxuICAgIHBhY2thZ2VNYW5hZ2VyID09PSBOb2RlUGFja2FnZU1hbmFnZXIuWUFSTl9CRVJSWVxuICApO1xufVxuXG4vKipcbiAqIENoZWNrIGlmIHBhY2thZ2UgbWFuYWdlciBpcyBucG0uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc05wbShwYWNrYWdlTWFuYWdlcjogTm9kZVBhY2thZ2VNYW5hZ2VyKTogYm9vbGVhbiB7XG4gIHJldHVybiBwYWNrYWdlTWFuYWdlciA9PT0gTm9kZVBhY2thZ2VNYW5hZ2VyLk5QTTtcbn1cblxuLyoqXG4gKiBCYXNpYyBpbnRlcmZhY2UgZm9yIGBwYWNrYWdlLmpzb25gLlxuICovXG5pbnRlcmZhY2UgUGFja2FnZU1hbmlmZXN0IHtcbiAgW2tleTogc3RyaW5nXTogYW55O1xuXG4gIC8qKlxuICAgKiBQYWNrYWdlIG5hbWUuXG4gICAqL1xuICBuYW1lOiBzdHJpbmc7XG4gIC8qKlxuICAgKiBQYWNrYWdlIHZlcnNpb24uXG4gICAqL1xuICB2ZXJzaW9uOiBzdHJpbmc7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiByZW5kZXJCdW5kbGVOYW1lKGVudHJ5cG9pbnQ6IHN0cmluZykge1xuICBjb25zdCBwYXJ0cyA9IGpvaW4oZW50cnlwb2ludCkuc3BsaXQoc2VwKTtcbiAgaWYgKHBhcnRzWzBdID09PSBcInNyY1wiKSB7XG4gICAgcGFydHMuc2hpZnQoKTsgLy8ganVzdCByZW1vdmUgJ3NyYycgaWYgaXRzIHRoZSBmaXJzdCBlbGVtZW50IGZvciBlcmdvbm9taWNzXG4gIH1cblxuICBjb25zdCBwID0gcGFydHMuam9pbihwb3NpeC5zZXApO1xuICBjb25zdCBkaXIgPSBkaXJuYW1lKHApO1xuICBjb25zdCBiYXNlID0gYmFzZW5hbWUocCwgZXh0bmFtZShwKSk7XG4gIHJldHVybiBwb3NpeC5qb2luKGRpciwgYmFzZSk7XG59XG5cbi8qKlxuICogUmVnZXggZm9yIEFXUyBDb2RlQXJ0aWZhY3QgcmVnaXN0cnlcbiAqL1xuZXhwb3J0IGNvbnN0IGNvZGVBcnRpZmFjdFJlZ2V4ID1cbiAgL15odHRwczpcXC9cXC8oPzxyZWdpc3RyeT4oPzxkb21haW4+W15cXC5dKyktKD88YWNjb3VudElkPlxcZHsxMn0pXFwuZFxcLmNvZGVhcnRpZmFjdFxcLig/PHJlZ2lvbj5bXlxcLl0rKS4qXFwuYW1hem9uYXdzXFwuY29tXFwvLipcXC8oPzxyZXBvc2l0b3J5PlteXFwvXSspXFwvKS87XG5cbi8qKlxuICogZ2V0cyBBV1MgZGV0YWlscyBmcm9tIHRoZSBDb2RlIEFydGlmYWN0IHJlZ2lzdHJ5IFVSTFxuICogdGhyb3dzIGV4Y2VwdGlvbiBpZiBub3QgbWF0Y2hpbmcgZXhwZWN0ZWQgcGF0dGVyblxuICogQHBhcmFtIHJlZ2lzdHJ5VXJsIENvZGUgQXJ0aWZhY3QgcmVnaXN0cnkgVVJMXG4gKiBAcmV0dXJucyBvYmplY3QgY29udGFpbmluZyB0aGUgKGRvbWFpbiwgYWNjb3VudElkLCByZWdpb24sIHJlcG9zaXRvcnkpXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBleHRyYWN0Q29kZUFydGlmYWN0RGV0YWlscyhyZWdpc3RyeVVybDogc3RyaW5nKSB7XG4gIGNvbnN0IG1hdGNoID0gcmVnaXN0cnlVcmwubWF0Y2goY29kZUFydGlmYWN0UmVnZXgpO1xuICBpZiAobWF0Y2g/Lmdyb3Vwcykge1xuICAgIGNvbnN0IHsgZG9tYWluLCBhY2NvdW50SWQsIHJlZ2lvbiwgcmVwb3NpdG9yeSwgcmVnaXN0cnkgfSA9IG1hdGNoLmdyb3VwcztcbiAgICByZXR1cm4geyBkb21haW4sIGFjY291bnRJZCwgcmVnaW9uLCByZXBvc2l0b3J5LCByZWdpc3RyeSB9O1xuICB9XG4gIHRocm93IG5ldyBFcnJvcihcIkNvdWxkIG5vdCBnZXQgQ29kZUFydGlmYWN0IGRldGFpbHMgZnJvbSBucG0gUmVnaXN0cnlcIik7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBtaW5WZXJzaW9uKHZlcnNpb246IHN0cmluZyk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIGlmIChzZW12ZXIudmFsaWRSYW5nZSh2ZXJzaW9uKSkge1xuICAgIHJldHVybiBzZW12ZXIubWluVmVyc2lvbih2ZXJzaW9uKT8udmVyc2lvbjtcbiAgfSBlbHNlIHtcbiAgICByZXR1cm4gdmVyc2lvbjtcbiAgfVxufVxuXG4vKipcbiAqIEF0dGVtcHQgdG8gcmVzb2x2ZSBsb2NhdGlvbiBvZiB0aGUgZ2l2ZW4gYG1vZHVsZUlkYC5cbiAqIEBwYXJhbSBtb2R1bGVJZCBNb2R1bGUgSUQgdG8gbG9va3VwLlxuICogQHBhcmFtIG9wdGlvbnMgUGFzc2VkIHRocm91Z2ggdG8gYHJlcXVpcmUucmVzb2x2ZWAuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB0cnlSZXNvbHZlTW9kdWxlKFxuICBtb2R1bGVJZDogc3RyaW5nLFxuICBvcHRpb25zPzogeyBwYXRoczogc3RyaW5nW10gfSxcbik6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIHRyeSB7XG4gICAgcmV0dXJuIHJlcXVpcmUucmVzb2x2ZShtb2R1bGVJZCwgb3B0aW9ucyk7XG4gIH0gY2F0Y2gge1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbn1cblxuLyoqXG4gKiBBdHRlbXB0IHRvIHJlc29sdmUgYSBtb2R1bGUncyBtYW5pZmVzdCAocGFja2FnZS5qc29uKSBwYXRoIHZpYSBgcmVxdWlyZS5yZXNvbHZlYCBsb29rdXAuXG4gKlxuICogQHJlbWFya3NcbiAqIElmIHRoZSB0YXJnZXQgcGFja2FnZSBoYXMgYGV4cG9ydHNgIHRoYXQgZGlmZmVyIGZyb20gdGhlIGRlZmF1bHRcbiAqIChpLmUsIGl0IGRlZmluZXMgdGhlIGBleHBvcnRzYCBmaWVsZCBpbiBpdHMgbWFuaWZlc3QpIGFuZCBkb2VzIG5vdFxuICogZXhwbGljaXRseSBpbmNsdWRlIGFuIGVudHJ5IGZvciBgcGFja2FnZS5qc29uYCwgdGhpcyBzdHJhdGVneSB3aWxsIGZhaWwuXG4gKiBTZWUge0BsaW5rIHRyeVJlc29sdmVNYW5pZmVzdFBhdGhGcm9tRGVmYXVsdEV4cG9ydH0gYXMgYW4gYWx0ZXJuYXRpdmUuXG4gKlxuICogQHBhcmFtIG1vZHVsZUlkIE1vZHVsZSBJRCB0byBsb29rdXAuXG4gKiBAcGFyYW0gb3B0aW9ucyBQYXNzZWQgdGhyb3VnaCB0byBgcmVxdWlyZS5yZXNvbHZlYC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRyeVJlc29sdmVNb2R1bGVNYW5pZmVzdFBhdGgoXG4gIG1vZHVsZUlkOiBzdHJpbmcsXG4gIG9wdGlvbnM/OiB7IHBhdGhzOiBzdHJpbmdbXSB9LFxuKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgLy8gY2Fubm90IGp1c3QgYHJlcXVpcmUoJ2RlcGVuZGVuY3kvcGFja2FnZS5qc29uJylgIGhlcmUgYmVjYXVzZVxuICAvLyBgb3B0aW9ucy5wYXRoc2AgbWF5IG5vdCBvdmVybGFwIHdpdGggdGhpcyBub2RlIHByb2MncyByZXNvbHV0aW9uIHBhdGhzLlxuICBjb25zdCBtYW5pZmVzdElkID0gYCR7bW9kdWxlSWR9L3BhY2thZ2UuanNvbmA7XG4gIHJldHVybiB0cnlSZXNvbHZlTW9kdWxlKG1hbmlmZXN0SWQsIG9wdGlvbnMpO1xufVxuXG4vKipcbiAqIEF0dGVtcHQgdG8gcmVzb2x2ZSBhIG1vZHVsZSdzIG1hbmlmZXN0IChwYWNrYWdlLmpzb24pIHBhdGggYnkgbG9va2luZyBmb3IgdGhlIG5lYXJlc3RcbiAqIGBwYWNrYWdlLmpzb25gIGZpbGUgdGhhdCBpcyBhbiBhbmNlc3RvciB0byB0aGUgbW9kdWxlJ3MgZGVmYXVsdCBleHBvcnQgbG9jYXRpb24uXG4gKlxuICogQHBhcmFtIG1vZHVsZUlkIE1vZHVsZSBJRCB0byBsb29rdXAuXG4gKiBAcGFyYW0gb3B0aW9ucyBQYXNzZWQgdGhyb3VnaCB0byBgcmVxdWlyZS5yZXNvbHZlYC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRyeVJlc29sdmVNYW5pZmVzdFBhdGhGcm9tRGVmYXVsdEV4cG9ydChcbiAgbW9kdWxlSWQ6IHN0cmluZyxcbiAgb3B0aW9ucz86IHsgcGF0aHM6IHN0cmluZ1tdIH0sXG4pOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICBjb25zdCBkZWZhdWx0RXhwb3J0UGF0aCA9IHRyeVJlc29sdmVNb2R1bGUobW9kdWxlSWQsIG9wdGlvbnMpO1xuICBpZiAoIWRlZmF1bHRFeHBvcnRQYXRoKSB7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuICBjb25zdCBtb2R1bGVEaXIgPSBmaW5kVXAoXCJwYWNrYWdlLmpzb25cIiwgZGVmYXVsdEV4cG9ydFBhdGgpO1xuICBpZiAoIW1vZHVsZURpcikge1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbiAgcmV0dXJuIGpvaW4obW9kdWxlRGlyLCBcInBhY2thZ2UuanNvblwiKTtcbn1cblxuLyoqXG4gKiBBdHRlbXB0IHRvIHJlc29sdmUgYSBtb2R1bGUncyBtYW5pZmVzdCAocGFja2FnZS5qc29uKSBwYXRoIGJ5IGNoZWNraW5nIGZvciBpdHMgZXhpc3RlbmNlIHVuZGVyIGBub2RlX21vZHVsZXNgIHJlbGF0aXZlIHRvIGBiYXNlUGF0aGAuXG4gKlxuICogQHJlbWFya3NcbiAqIFRoaXMgc3RyYXRlZ3kgY2FuIGJlIGhlbHBmdWwgaW4gdGhlIHNjZW5hcmlvIHRoYXQgYSBtb2R1bGUgZGVmaW5lc1xuICogY3VzdG9tIGV4cG9ydHMgd2l0aG91dCBgcGFja2FnZS5qc29uYCBhbmQgbm8gZGVmYXVsdCBleHBvcnQgKGkuZSwgc29tZSB0eXBlIGRlZmluaXRpb24gcGFja2FnZXMpLlxuICpcbiAqIEBwYXJhbSBtb2R1bGVJZCBNb2R1bGUgSUQgdG8gbG9va3VwLlxuICogQHBhcmFtIGJhc2VQYXRoIFJvb3QgcGF0aCB0byBzZWFyY2ggZnJvbS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRyeVJlc29sdmVNYW5pZmVzdFBhdGhGcm9tUGF0aChcbiAgbW9kdWxlSWQ6IHN0cmluZyxcbiAgYmFzZVBhdGg6IHN0cmluZyxcbikge1xuICBjb25zdCBiYXNlID0gYmFzZVBhdGguaW5jbHVkZXMoXCJub2RlX21vZHVsZXNcIilcbiAgICA/IGJhc2VQYXRoXG4gICAgOiBqb2luKGJhc2VQYXRoLCBcIm5vZGVfbW9kdWxlc1wiKTtcbiAgY29uc3QgZmlsZVBhdGggPSByZXNvbHZlKGJhc2UsIC4uLm1vZHVsZUlkLnNwbGl0KFwiL1wiKSwgXCJwYWNrYWdlLmpzb25cIik7XG4gIGlmIChleGlzdHNTeW5jKGZpbGVQYXRoKSkge1xuICAgIHJldHVybiBmaWxlUGF0aDtcbiAgfVxuICByZXR1cm4gdW5kZWZpbmVkO1xufVxuXG4vKipcbiAqIEF0dGVtcHQgdG8gcmVzb2x2ZSBhIG1vZHVsZSdzIG1hbmlmZXN0IChwYWNrYWdlLmpzb24pIHBhdGggYnkgc2VhcmNoaW5nIGZvciBpdCBpbiB0aGUgb3B0aW9uYWxseSBwcm92aWRlZCBwYXRocyBhcnJheVxuICogYXMgd2VsbCBhcyB0aGUgY3VycmVudCBub2RlIHByb2Nlc3NlcycgZGVmYXVsdCByZXNvbHV0aW9uIHBhdGhzLlxuICogQHBhcmFtIG1vZHVsZUlkIE1vZHVsZSBJRCB0byBzZWFyY2ggZm9yLlxuICogQHBhcmFtIG9wdGlvbnMgU2VhcmNoIG9wdGlvbnMuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB0cnlSZXNvbHZlTWFuaWZlc3RQYXRoRnJvbVNlYXJjaChcbiAgbW9kdWxlSWQ6IHN0cmluZyxcbiAgb3B0aW9ucz86IHsgcGF0aHM6IHN0cmluZ1tdIH0sXG4pOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICBjb25zdCBzZWFyY2hQYXRocyA9IFtcbiAgICAuLi4ob3B0aW9ucz8ucGF0aHMgPz8gW10pLFxuICAgIC4uLihyZXF1aXJlLnJlc29sdmUucGF0aHMobW9kdWxlSWQpID8/IFtdKSxcbiAgXTtcbiAgZm9yIChjb25zdCBwYXRoIG9mIHNlYXJjaFBhdGhzKSB7XG4gICAgY29uc3QgcmVzdWx0ID0gdHJ5UmVzb2x2ZU1hbmlmZXN0UGF0aEZyb21QYXRoKG1vZHVsZUlkLCBwYXRoKTtcbiAgICAvLyBlYXJseSByZXR1cm4gb24gZmlyc3QgcmVzdWx0LlxuICAgIGlmIChyZXN1bHQpIHtcbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfVxuICB9XG4gIHJldHVybiB1bmRlZmluZWQ7XG59XG5cbi8qKlxuICogQXR0ZW1wdCB0byByZXNvbHZlIGEgbW9kdWxlJ3MgbWFuaWZlc3QgKHBhY2thZ2UuanNvbikgdXNpbmcgbXVsdGlwbGUgc3RyYXRlZ2llcy5cbiAqIEBwYXJhbSBtb2R1bGVJZCBNb2R1bGUgdG8gcmVzb2x2ZSBtYW5pZmVzdCBwYXRoIGZvci5cbiAqIEBwYXJhbSBvcHRpb25zIFJlc29sdXRpb24gb3B0aW9ucy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRyeVJlc29sdmVNb2R1bGVNYW5pZmVzdChcbiAgbW9kdWxlSWQ6IHN0cmluZyxcbiAgb3B0aW9ucz86IHsgcGF0aHM6IHN0cmluZ1tdIH0sXG4pOiBQYWNrYWdlTWFuaWZlc3QgfCB1bmRlZmluZWQge1xuICBjb25zdCBzdHJhdGVnaWVzID0gW1xuICAgIHRyeVJlc29sdmVNb2R1bGVNYW5pZmVzdFBhdGgsXG4gICAgdHJ5UmVzb2x2ZU1hbmlmZXN0UGF0aEZyb21EZWZhdWx0RXhwb3J0LFxuICAgIHRyeVJlc29sdmVNYW5pZmVzdFBhdGhGcm9tU2VhcmNoLFxuICBdO1xuICBmb3IgKGNvbnN0IHN0cmF0ZWd5IG9mIHN0cmF0ZWdpZXMpIHtcbiAgICBjb25zdCByZXN1bHQgPSBzdHJhdGVneShtb2R1bGVJZCwgb3B0aW9ucyk7XG4gICAgLy8gZWFybHkgcmV0dXJuIG9uIGZpcnN0IHJlc3VsdC5cbiAgICBpZiAocmVzdWx0KSB7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCBtYW5pZmVzdCA9IEpTT04ucGFyc2UoXG4gICAgICAgICAgcmVhZEZpbGVTeW5jKHJlc3VsdCwgXCJ1dGY4XCIpLFxuICAgICAgICApIGFzIFBhY2thZ2VNYW5pZmVzdDtcbiAgICAgICAgLy8gdmVyaWZ5IG5hbWUgbWF0Y2hlcyB0YXJnZXQgbW9kdWxlLlxuICAgICAgICBpZiAobWFuaWZlc3QubmFtZSA9PT0gbW9kdWxlSWQpIHtcbiAgICAgICAgICByZXR1cm4gbWFuaWZlc3Q7XG4gICAgICAgIH1cbiAgICAgIH0gY2F0Y2gge1xuICAgICAgICAvLyBjb250aW51ZSB0byBuZXh0IHN0cmF0ZWd5LlxuICAgICAgfVxuICAgIH1cbiAgfVxuICByZXR1cm4gdW5kZWZpbmVkO1xufVxuXG4vKipcbiAqIEF0dGVtcHQgdG8gcmVzb2x2ZSB0aGUgaW5zdGFsbGVkIHZlcnNpb24gb2YgYSBnaXZlbiBkZXBlbmRlbmN5LlxuICogQHBhcmFtIGRlcGVuZGVuY3lOYW1lIE5hbWUgb2YgZGVwZW5kZW5jeS5cbiAqIEBwYXJhbSBvcHRpb25zIE9wdGlvbmFsIG9wdGlvbnMgcGFzc2VkIHRocm91Z2ggdG8gYHJlcXVpcmUucmVzb2x2ZWAuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB0cnlSZXNvbHZlRGVwZW5kZW5jeVZlcnNpb24oXG4gIGRlcGVuZGVuY3lOYW1lOiBzdHJpbmcsXG4gIG9wdGlvbnM/OiB7IHBhdGhzOiBzdHJpbmdbXSB9LFxuKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgY29uc3QgbWFuaWZlc3QgPSB0cnlSZXNvbHZlTW9kdWxlTWFuaWZlc3QoZGVwZW5kZW5jeU5hbWUsIG9wdGlvbnMpO1xuICBpZiAoIW1hbmlmZXN0KSB7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuICByZXR1cm4gbWFuaWZlc3Q/LnZlcnNpb247XG59XG5cbi8qKlxuICogV2hldGhlciB0aGUgZ2l2ZW4gZGVwZW5kZW5jeSB2ZXJzaW9uIGlzIGluc3RhbGxlZFxuICpcbiAqIFRoaXMgY2FuIGJlIHVzZWQgdG8gdGVzdCBmb3IgdGhlIHByZXNlbmNlIG9mIGNlcnRhaW4gdmVyc2lvbnMgb2YgZGV2RGVwZW5kZW5jaWVzLFxuICogYW5kIGRvIHNvbWV0aGluZyBkZXBlbmRlbmN5LXNwZWNpZmljIGluIGNlcnRhaW4gQ29tcG9uZW50cy4gRm9yIGV4YW1wbGUsIHRlc3QgZm9yXG4gKiBhIHZlcnNpb24gb2YgSmVzdCBhbmQgZ2VuZXJhdGUgZGlmZmVyZW50IGNvbmZpZ3MgYmFzZWQgb24gdGhlIEplc3QgdmVyc2lvbi5cbiAqXG4gKiBOT1RFOiBUaGUgaW1wbGVtZW50YXRpb24gb2YgdGhpcyBmdW5jdGlvbiBjdXJyZW50bHkgaXMgY3VycmVudGx5XG4gKiBhcHByb3hpbWF0ZTogdG8gZG8gaXQgY29ycmVjdGx5LCB3ZSB3b3VsZCBuZWVkIGEgc2VwYXJhdGUgaW1wbGVtZW50YXRpb25cbiAqIGZvciBldmVyeSBwYWNrYWdlIG1hbmFnZXIsIHRvIHF1ZXJ5IGl0cyBpbnN0YWxsZWQgdmVyc2lvbiAoZWl0aGVyIHRoYXQsIG9yIHdlXG4gKiB3b3VsZCBjb2RlIHRvIHF1ZXJ5IGBwYWNrYWdlLWxvY2suanNvbmAsIGB5YXJuLmxvY2tgLCBldGMuLi4pLlxuICpcbiAqIEluc3RlYWQsIHdlIHdpbGwgbG9vayBhdCBgcGFja2FnZS5qc29uYCwgYW5kIGFzc3VtZSB0aGF0IHRoZSB2ZXJzaW9uc1xuICogcGlja2VkIGJ5IHRoZSBwYWNrYWdlIG1hbmFnZXIgbWF0Y2ggfnRoYXQuIFRoaXMgd2lsbCB3b3JrIHdlbGwgZW5vdWdoIGZvclxuICogbWFqb3IgdmVyc2lvbiBjaGVja3MsIGJ1dCBtYXkgZmFpbCBmb3IgcG9pbnQgdmVyc2lvbnMuXG4gKlxuICogV2hhdCB3ZSBTSE9VTEQgZG8gaXM6IGBhY3R1YWxWZXJzaW9uIOKIiCBjaGVja1JhbmdlYC5cbiAqXG4gKiBXaGF0IHdlIGRvIGluc3RlYWQgaXMgYSBzbGlnaHRseSBtb3JlIHNvcGhpc3RpY2F0ZWQgdmVyc2lvbiBvZlxuICogYHJlcXVlc3RlZFJhbmdlIOKIqSBjaGVja1JhbmdlICE9IOKIhWAuIFRoaXMgd2lsbCBhbHdheXMgZ2l2ZSBhIGNvcnJlY3QgcmVzdWx0IGlmXG4gKiBgcmVxdWVzdGVkUmFuZ2Ug4oqGIGNoZWNrUmFuZ2VgLCBidXQgbWF5IGdpdmUgZmFsc2UgcG9zaXRpdmVzIHdoZW4gYGNoZWNrUmFuZ2VcbiAqIOKKhiByZXF1ZXN0ZWRSYW5nZWAuXG4gKlxuICogTWF5IHJldHVybiBgdW5kZWZpbmVkYCBpZiB0aGUgcXVlc3Rpb24gY2Fubm90IGJlIGFuc3dlcmVkLiBUaGVzZSBpbmNsdWRlIHRoZVxuICogZm9sbG93aW5nIGNhc2VzOlxuICpcbiAqICAgLSBUaGUgZGVwZW5kZW5jeSBpcyByZXF1ZXN0ZWQgdmlhIGxvY2FsIGZpbGUgZGVwZW5kZW5jaWVzIChgZmlsZTovLy4uLmApXG4gKiAgIC0gVGhlIGRlcGVuZGVuY3kgdXNlcyBhbiBvdGhlciB0eXBlIG9mIFVSTCwgc3VjaCBhcyBhIEdpdEh1YiBVUkxcbiAqICAgLSBUaGUgZGVwZW5kZW5jeSBpcyBub3QgZm91bmQgaW4gdGhlIGBwYWNrYWdlLmpzb25gLCBzdWNoIGFzIHdoZW5cbiAqICAgICBib290c3RyYXBwaW5nIGZyb20gYW4gZXh0ZXJuYWwgcHJvamVuIHBhY2thZ2UsIGFuZCB0aGUgYHBhY2thZ2UuanNvbmBcbiAqICAgICBmaWxlIG9ubHkgaGFzIHRoYXQgb25lIGV4dGVybmFsIHBhY2thZ2UgYXMgYSBkZXBlbmRlbmN5XG4gKlxuICogT3RoZXJ3aXNlIGl0IHdpbGwgcmV0dXJuIGB0cnVlYCBpZiB0aGUgaW5zdGFsbGVkIHZlcnNpb24gaXMgcHJvYmFibHkgaW4gdGhlXG4gKiByZXF1ZXN0ZWQgcmFuZ2UsIGFuZCBgZmFsc2VgIGlmIGl0IGlzIHByb2JhYmx5IG5vdC5cbiAqXG4gKiBUaGlzIEFQSSBtYXkgZXZlbnR1YWxseSBiZSBhZGRlZCB0byB0aGUgcHVibGljIHByb2plbiBBUEksIGJ1dCBvbmx5IGFmdGVyXG4gKiB3ZSBpbXBsZW1lbnQgZXhhY3QgdmVyc2lvbiBjaGVja2luZy5cbiAqXG4gKiBAcGFyYW0gZGVwZW5kZW5jeU5hbWUgVGhlIG5hbWUgb2YgdGhlIGRlcGVuZGVuY3lcbiAqIEBwYXJhbSBjaGVja1JhbmdlIEEgcGFydGljdWxhciB2ZXJzaW9uLCBvciByYW5nZSBvZiB2ZXJzaW9ucy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGhhc0RlcGVuZGVuY3lWZXJzaW9uKFxuICBwcm9qZWN0OiBQcm9qZWN0LFxuICBkZXBlbmRlbmN5TmFtZTogc3RyaW5nLFxuICBjaGVja1JhbmdlOiBzdHJpbmcsXG4pOiBib29sZWFuIHwgdW5kZWZpbmVkIHtcbiAgY29uc3QgZmlsZSA9IE5vZGVQYWNrYWdlLm9mKHByb2plY3QpPy5maWxlO1xuICBpZiAoIWZpbGUpIHtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG5cbiAgaWYgKCFleGlzdHNTeW5jKGZpbGUuYWJzb2x1dGVQYXRoKSkge1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cblxuICBjb25zdCBwaiA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKGZpbGUuYWJzb2x1dGVQYXRoLCBcInV0Zi04XCIpKTtcblxuICAvLyBUZWNobmljYWx5LCB3ZSBzaG91bGQgYmUgaW50ZXJzZWN0aW5nIGFsbCByYW5nZXMgdG8gY29tZSB1cCB3aXRoIHRoZSBtb3N0IG5hcnJvdyBkZXBlbmRlbmN5XG4gIC8vIHJhbmdlLCBidXQgYHNlbXZlcmAgZG9lc24ndCBhbGxvdyBkb2luZyB0aGF0IGFuZCB3ZSBkb24ndCB3YW50IHRvIGFkZCBhIGRlcGVuZGVuY3kgb24gYHNlbXZlci1pbnRlcnNlY3RgLlxuICAvL1xuICAvLyBMZXQncyB0YWtlIHRoZSBmaXJzdCBkZXBlbmRlbmN5IGRlY2xhcmF0aW9uIHdlIGZpbmQsIGFuZCBhc3N1bWUgdGhhdCBwZW9wbGVcbiAgLy8gc2V0IHVwIHRoZWlyIGBwYWNrYWdlLmpzb25gIGNvcnJlY3RseS5cbiAgbGV0IHJlcXVlc3RlZFJhbmdlOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG4gIGZvciAoY29uc3Qga2V5IG9mIFtcImRlcGVuZGVuY2llc1wiLCBcImRldkRlcGVuZGVuY2llc1wiLCBcInBlZXJEZXBlbmRlbmNpZXNcIl0pIHtcbiAgICBjb25zdCBkZXBzID0gcGpba2V5XSA/PyB7fTtcbiAgICBsZXQgcmVxdWVzdGVkVmVyc2lvbiA9IGRlcHNbZGVwZW5kZW5jeU5hbWVdO1xuICAgIGlmIChyZXF1ZXN0ZWRWZXJzaW9uKSB7XG4gICAgICAvLyBJZiB0aGlzIGlzIG5vdCBhIHZhbGlkIHJhbmdlLCBpdCBjb3VsZCBiZSAnZmlsZTpkZXAudGd6Jywgb3IgYSBHaXRIdWIgVVJMLiBObyB3YXkgdG8ga25vdyB3aGF0XG4gICAgICAvLyB2ZXJzaW9uIHdlJ3JlIGdldHRpbmcsIGJhaWwgb3V0LlxuICAgICAgaWYgKCFzZW12ZXIudmFsaWRSYW5nZShyZXF1ZXN0ZWRWZXJzaW9uKSkge1xuICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgfVxuICAgICAgcmVxdWVzdGVkUmFuZ2UgPSByZXF1ZXN0ZWRWZXJzaW9uO1xuICAgICAgYnJlYWs7XG4gICAgfVxuICB9XG5cbiAgLy8gSWYgdGhlIGRlcGVuZGVuY3kgaXMgbm90IGZvdW5kIGluIHRoZSBgcGFja2FnZS5qc29uYCwgd2UgY2FuJ3QgYW5zd2VyIHRoZSBxdWVzdGlvbiAoeWV0KS5cbiAgLy8gVGhpcyBtZWFucyB0aGF0IHRoZSBkZXBlbmRlbmN5IGhhc24ndCBiZWVuIGFkZGVkIHlldCwgd2hpY2ggbWVhbnMgd2Uga25vdyAodXBzdHJlYW0pIHdoYXQgd2UncmUgZ29pbmcgdG8gcmVxdWVzdCxcbiAgLy8gb3Igd2UncmUgZ29pbmcgdG8gYXNrIGZvciAnKicgYW5kIHdlJ2xsIGdldCB0aGUgbGF0ZXN0IHZlcnNpb24uXG4gIGlmICghcmVxdWVzdGVkUmFuZ2UpIHtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG5cbiAgcmV0dXJuIGluc3RhbGxlZFZlcnNpb25Qcm9iYWJseU1hdGNoZXMocmVxdWVzdGVkUmFuZ2UsIGNoZWNrUmFuZ2UpO1xufVxuXG4vKipcbiAqIFdoZXRoZXIgdGhlIGdpdmVuIHJlcXVlc3RlZFJhbmdlICpwcm9iYWJseSogbGVhZHMgdG8gdGhlIGluc3RhbGxhdGlvbiBvZiBhIHZlcnNpb24gdGhhdCBtYXRjaGVzIGNoZWNrUmFuZ2VcbiAqXG4gKiBXZSBhc3N1bWUgdGhhdCBOUE0gYWx3YXlzIGluc3RhbGxzIHRoZSBtb3N0IHJlY2VudCB2ZXJzaW9uIG9mIGEgcGFja2FnZSB0aGF0XG4gKiBpcyBhbGxvd2VkIGJ5IHRoZSByZXF1ZXN0ZWRSYW5nZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGluc3RhbGxlZFZlcnNpb25Qcm9iYWJseU1hdGNoZXMoXG4gIHJlcXVlc3RlZFJhbmdlOiBzdHJpbmcsXG4gIGNoZWNrUmFuZ2U6IHN0cmluZyxcbik6IGJvb2xlYW4ge1xuICBjb25zdCBvcHRpb25zID0ge1xuICAgIGluY2x1ZGVQcmVyZWxlYXNlOiB0cnVlLFxuICAgIGxvb3NlOiB0cnVlLFxuICB9O1xuXG4gIC8vIE5vIHF1ZXN0aW9ucyBhc2tlZDogYWx3YXlzIHRydWVcbiAgaWYgKHNlbXZlci5zdWJzZXQocmVxdWVzdGVkUmFuZ2UsIGNoZWNrUmFuZ2UsIG9wdGlvbnMpKSB7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICAvLyBBbHNvIG5vIHF1ZXN0aW9ucyBhc2tlZDogYWx3YXlzIGZhbHNlXG4gIGlmICghc2VtdmVyLmludGVyc2VjdHMocmVxdWVzdGVkUmFuZ2UsIGNoZWNrUmFuZ2UsIG9wdGlvbnMpKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgLy8gTm93IHdlJ3JlIGluIHRyaWNreSB0ZXJyaXRvcnkuIFdlIGludGVyc2VjdCwgYnV0IGFyZW4ndCBhIGZ1bGwgc3Vic2V0LlxuICAvLyBXZSBhcmUgaW4gb25lIG9mIHRoZSBmb2xsb3dpbmcgMiBzaXR1YXRpb25zLCB3aGljaCB3ZSB3aWxsIHRpZS1icmVhayBieVxuICAvLyBhc3N1bWluZyBOUE0gd2lsbCBpbnN0YWxsIHRoZSBtb3N0IHJlY2VudCBtYXRjaGluZyB2ZXJzaW9uIGluICdyZXF1ZXN0ZWQnLlxuICAvL1xuICAvLyByZXF1ZXN0ZWQgIHwgY2hlY2sgICAgfCByZXN1bHRcbiAgLy8gLS0tLS0tLS0tLS18LS0tLS0tLS0tLXwtLS0tLS0tLS0tLVxuICAvLyAgID49IDIgICAgIHwgID49IDMgICAgfCBwcm9iYWJseSB0cnVlIChjaGFuY2Ugb2YgRlApXG4gIC8vICAgPD0gMiAgICAgfCAgPD0gMSAgICB8IHByb2JhYmx5IGZhbHNlIChjaGFuZ2Ugb2YgRk4pXG4gIC8vXG4gIC8vIGBzZW12ZXJgIGRvZXNuJ3QgbWFrZSBpdCBlYXN5IHRvIGRpc3Rpbmd1aXNoIHRoZXNlIGNhc2VzICh3ZSBjYW4ndCByZXF1ZXN0XG4gIC8vIHRoZSBgbWF4VmVyc2lvbmAgdGhhdCBzYXRpc2ZpZXMgYSByYW5nZSkuIEluc3RlYWQgd2hhdCB3ZSBkbyBpc1xuICAvLyBnZXQgdGhlIGBtaW5WZXJzaW9uYCBvZiBlYWNoIHJhbmdlLCBhbmQgaWYgdGhleSBjb21wYXJlIGVxdWFsIHdlIGFzc3VtZVxuICAvLyB3ZSdyZSBpbiB0aGUgYm90dG9tIGNhc2Ugd2l0aCBgPD1gIGNoZWNrcywgYW5kIHJldHVybiBgZmFsc2VgLlxuXG4gIHJldHVybiAhc2VtdmVyLmVxKFxuICAgIHNlbXZlci5taW5WZXJzaW9uKHJlcXVlc3RlZFJhbmdlLCBvcHRpb25zKSA/PyBcIjEuMi4zXCIsXG4gICAgc2VtdmVyLm1pblZlcnNpb24oY2hlY2tSYW5nZSwgb3B0aW9ucykgPz8gXCIxLjIuM1wiLFxuICApO1xufVxuIl19