UNPKG

jsii-release

Version:

Release jsii modules to multiple package managers

612 lines (611 loc) 75.2 kB
"use strict"; var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) { if (value !== null && value !== void 0) { if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected."); var dispose, inner; if (async) { if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined."); dispose = value[Symbol.asyncDispose]; } if (dispose === void 0) { if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined."); dispose = value[Symbol.dispose]; if (async) inner = dispose; } if (typeof dispose !== "function") throw new TypeError("Object not disposable."); if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } }; env.stack.push({ value: value, dispose: dispose, async: async }); } else if (async) { env.stack.push({ async: true }); } return value; }; var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) { return function (env) { function fail(e) { env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e; env.hasError = true; } var r, s = 0; function next() { while (r = env.stack.pop()) { try { if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next); if (r.dispose) { var result = r.dispose.call(r.value); if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); }); } else s |= 1; } catch (e) { fail(e); } } if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve(); if (env.hasError) throw env.error; } return next(); }; })(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) { var e = new Error(message); return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; }); Object.defineProperty(exports, "__esModule", { value: true }); exports.autoCleanDir = autoCleanDir; /** * Legacy vs compatibility endpoint * ================================== * * This script talks about legacy vs compatibility endpoint a bunch. * * Both implement the Nexus 2 protocol, however: * * - The "legacy" endpoint is the Sonatype OSSRH endpoint that was deprecated June 2025. * - The "compatibility" endpoint is a Nexus 2-compatible endpoint stood up for the new * publishing service, Central Publishing. * * It should be the same protocol but of course there are subtle differences * between them (in how they signal error when you try to republish an already * published version, and even in the wire protocol accepted) so we have to * treat them differently here. * * There is also an "official new" protocol for the new publishing mechanism, * but the Maven plugin they supply for that doesn't support that. In their words: * * > it appears that you are using the "two stage"[1] deployment process, which is * > not yet supported by the new plugin. You are the first publisher to have * > requested this, so we were not familiar with this specific usecase when * > building the new plugin * > [1] <https://github.com/sonatype/nexus-maven-plugins/blob/43a9940b134c3f87ebe4daa82552e844d9c578b8/staging/maven-plugin/WORKFLOWS.md#two-shots> */ const fs_1 = require("fs"); const zx_1 = require("zx"); const LEGACY_OSSRH_SERVER_ID = 'ossrh'; const COMPAT_CENTRAL_SERVER_ID = 'central-ossrh'; const NEXUS_MAVEN_STAGING_PLUGIN = 'org.sonatype.plugins:nexus-staging-maven-plugin:1.7.0'; async function main() { const args = process.argv.slice(2); const javaRoot = args[0] ?? 'dist/java'; (0, zx_1.cd)(javaRoot); const poms = await (0, zx_1.glob)('**/*.pom'); if (poms.length === 0) { throw new SimpleError(`No JARS to publish: no .pom files found under ${process.cwd()}`); } (0, zx_1.echo)(`POMs found: ${poms}`); const sharedOptions = { username: envVar('MAVEN_USERNAME'), password: envVar('MAVEN_PASSWORD'), dryRun: process.env.MAVEN_DRYRUN === 'true' || process.env.PUBLIB_DRYRUN === 'true', verbose: process.env.MAVEN_VERBOSE === 'true', poms, }; let options; const serverId = process.env.MAVEN_SERVER_ID ?? LEGACY_OSSRH_SERVER_ID; switch (serverId) { case LEGACY_OSSRH_SERVER_ID: options = { type: 'legacy-ossrh', ...sharedOptions, stagingProfileId: envVar('MAVEN_STAGING_PROFILE_ID'), endpoint: process.env.MAVEN_ENDPOINT, privateKey: parsePrivateKeyFromEnv(), }; break; case COMPAT_CENTRAL_SERVER_ID: options = { type: 'compat-ossrh', ...sharedOptions, // Not required by the new endpoint: can be any value (maybe never was required to begin with?) stagingProfileId: 'publib', endpoint: process.env.MAVEN_ENDPOINT, privateKey: parsePrivateKeyFromEnv(), }; break; default: // We haven't implemented signing for this, so fail loudly if people try to use it anyway if (process.env.MAVEN_GPG_PRIVATE_KEY || process.env.MAVEN_GPG_PRIVATE_KEY_FILE) { throw new SimpleError('MAVEN_GPG_PRIVATE_KEY[_FILE] is only supported for OSSRH publishing'); } options = { type: 'custom-nexus', ...sharedOptions, serverId, repositoryUrl: envVar('MAVEN_REPOSITORY_URL'), }; break; } await mavenPublish(options); (0, zx_1.echo)('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'); (0, zx_1.echo)('✅ All Done!'); } function parsePrivateKeyFromEnv() { if (process.env.MAVEN_GPG_PRIVATE_KEY_FILE) { return { type: 'file', fileName: process.env.MAVEN_GPG_PRIVATE_KEY_FILE, passPhrase: envVar('MAVEN_GPG_PRIVATE_KEY_PASSPHRASE') }; } if (process.env.MAVEN_GPG_PRIVATE_KEY) { return { type: 'material', keyMaterial: process.env.MAVEN_GPG_PRIVATE_KEY, passPhrase: envVar('MAVEN_GPG_PRIVATE_KEY_PASSPHRASE') }; } throw new SimpleError('MAVEN_GPG_PRIVATE_KEY[_FILE] is required'); } //---------------------------------------------------------------------- // Publishing functions // async function mavenPublish(options) { const env_1 = { stack: [], error: void 0, hasError: false }; try { const workDir = __addDisposableResource(env_1, autoCleanDir(), true); const maven = new Maven(workDir.dir, options.verbose, options.dryRun); const x = options.type; switch (x) { case 'legacy-ossrh': await deployLegacyOssrh(maven, options); break; case 'compat-ossrh': await deployCompatOssrh(maven, options); break; case 'custom-nexus': await deployCustomNexus(maven, options); break; default: assertNever(x); } } catch (e_1) { env_1.error = e_1; env_1.hasError = true; } finally { const result_1 = __disposeResources(env_1); if (result_1) await result_1; } } /** * Deploy to the legacy OSSRH Nexus server */ async function deployLegacyOssrh(maven, options) { (0, zx_1.echo)('📦 Publishing to Maven Central'); const defaultEndpoint = 'https://oss.sonatype.org'; const staged = await deployStagedRepository(maven, { ...options, endpoint: options.endpoint ?? defaultEndpoint, republishWill400: false, }); if (staged.type !== 'success') { return; } /* const released = await releaseRepo({ serverUrl: options.endpoint ?? defaultEndpoint, username: options.username, password: options.password, repositoryId: staged.repositoryId, }); if (released) { return; } */ // Send a remote release command to the repository const releaseOutput = await maven.exec(`${NEXUS_MAVEN_STAGING_PLUGIN}:rc-release`, { properties: { nexusUrl: options.endpoint ?? defaultEndpoint, serverId: staged.serverId, stagingRepositoryId: staged.repositoryId, }, nothrow: true, }); if (!releaseOutput) { (0, zx_1.echo)('🏜️ Stopped here because of dry-run'); return; } if (releaseOutput.exitCode !== 0) { // If release failed, check if this was caused because we are trying to publish // the same version again, which is not an error. The magic string "does not // allow updating artifact" for a ".pom" file indicates that we are trying to // override an existing version. Otherwise, fail! const looksLikeDuplicatePublish = releaseOutput.lines() .filter(l => l.includes('does not allow updating artifact')) .filter(l => l.includes('.pom')) .length > 0; if (!looksLikeDuplicatePublish) { throw new SimpleError('Release failed'); } (0, zx_1.echo)('⚠️ Artifact already published. Skipping'); } } /** * Deploy to the compat OSSRH Nexus server */ async function deployCompatOssrh(maven, options) { (0, zx_1.echo)('📦 Publishing to Maven Central (Compat endpoint)'); const defaultEndpoint = 'https://ossrh-staging-api.central.sonatype.com/'; const endpoint = options.endpoint ?? defaultEndpoint; const staged = await deployStagedRepository(maven, { ...options, endpoint, republishWill400: true, }); if (staged.type !== 'success') { return; } const released = await releaseRepo({ serverUrl: endpoint, username: options.username, password: options.password, repositoryId: staged.repositoryId, }); if (released === 'duplicate-version') { (0, zx_1.echo)('⚠️ Version(s) already published. Skipping'); } } /** * Deploy to a custom Nexus server */ async function deployCustomNexus(maven, options) { (0, zx_1.echo)(`📦 Publishing to ${options.serverId}`); await maven.writeSettingsFile(options.serverId, false); for (const pom of options.poms) { const deployOutput = await maven.exec('deploy:deploy-file', { properties: { url: options.repositoryUrl, repositoryId: options.serverId, pomFile: pom, ...jarsFromPom(pom), }, nothrow: true, }); if (deployOutput?.exitCode && deployOutput.exitCode > 0) { if (deployOutput.stdout.includes('409 Conflict')) { (0, zx_1.echo)('⚠️ Artifact already published. Skipping'); } else { throw new SimpleError('Release failed'); } } } } /** * Create the staging repository. This is the same between the legacy and compat endpoints. * * `republishWill400`: in the compatibility endpoint, staging a version that has already * been published will lead to a `400 Bad Request`, with no further info. We needed to have * run the Maven command with `--debug` logging to see the actual error message in the output. * * In the legacy endpoint, staging takes multiple minutes, and Maven will poll * every 3s and print the output. We therefore don't use verbose mode to avoid * stdout spam. In the legacy endpoint, duplicate version publishing gets * reported during the 'release' step anyway, not during staging. */ async function deployStagedRepository(maven, options) { const serverId = 'ossrh'; await maven.writeSettingsFile(serverId, true); // First -- sign artifacts const signedDir = zx_1.path.join(maven.workDir, 'signed'); await fs_1.promises.mkdir(signedDir, { recursive: true }); await signJars(maven, options.poms, signedDir, serverId, options.privateKey); (0, zx_1.echo)('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'); (0, zx_1.echo)(' Deploying and closing repository...'); (0, zx_1.echo)('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'); const nexusMavenStaging = 'org.sonatype.plugins:nexus-staging-maven-plugin:1.7.0'; const stageOutput = await maven.exec(`${nexusMavenStaging}:deploy-staged-repository`, { properties: { repositoryDirectory: signedDir, nexusUrl: options.endpoint, serverId, stagingProgressTimeoutMinutes: '30', stagingProfileId: options.stagingProfileId, }, nothrow: true, verbose: options.republishWill400, }); // FIXME: New staging API throws an error here on duplicate versions if (stageOutput === undefined) { (0, zx_1.echo)('🏜️ Stopped here because of dry-run'); return { type: 'dry-run' }; } if (options.republishWill400 && stageOutput.text().match(/Component with package url.*already exists/)) { // We've seen this fail with the above error message on the OSSRH compatibility API when trying to republish // an already-published version. // // This is potentially a problem if there are multiple versions in the source directory at once, because nothing // will be published if there's one package in there that has already been published previously. But c'est la vie. (0, zx_1.echo)('⚠️ Version(s) already published. Skipping'); return { type: 'already-published' }; } else if (stageOutput.exitCode && stageOutput.exitCode > 0) { throw stageOutput; } // Grep the repository ID out of the printed output // [INFO] * Closing staging repository with ID "XXXXXXXXXX". const m = stageOutput.stdout.match(/Closing staging repository with ID "([^"]+)"/); if (!m) { throw new SimpleError('Unable to extract repository ID from deploy-staged-repository output. This means it failed to close or there was an unexpected problem. At any rate, we can\'t release it. Sorry.'); } const repositoryId = m[1]; return { type: 'success', repositoryId, serverId }; } /** * Send a custom "release" command to the new Sonatype backwards compatibility endpoint * * When using the `nexus-staging-maven-plugin`'s `release` or `rc-release` commands, we get the following * error: * * Sending: * * ``` * <stagingActionRequest><data><stagedRepositoryIds class="java.util.Arrays$ArrayList"><a class="string-array"><string>io.github.rix0rrr--63edbcbe-f058-44eb-85f4-fd9dce1aef40</string></a></stagedRepositoryIds><description>unknown</description><autoDropAfterRelease>true</autoDropAfterRelease></data></stagingActionRequest> * ``` * * Error: * * ``` * Failed to process request: Got unexpected XML element when reading stagedRepositoryIds: Got unexpected element StartElement(a, {"": "", "xml": "http://www.w3.org/XML/1998/namespace", "xmlns": "http://www.w3.org/2000/xmlns/"}, [class -> string-array]), expected one of: string * ``` * * Doing a manual slightly modified version of the above request succeeds, so we'll just proceed with doing * that. * * The endpoint also supports JSON, which we prefer over XML. * * This endpoint will never return an error, even if the publish didn't happen because * of duplicate version publishing (not for the legacy, nor for the compatibility endpoint). * * @see https://central.sonatype.org/publish/publish-portal-ossrh-staging-api/ * @see https://support.sonatype.com/hc/en-us/articles/213465448-Automatically-dropping-old-staging-repositories */ async function releaseRepo(options) { (0, zx_1.echo)(`🚀 Releasing repository ${options.repositoryId} at ${options.serverUrl}`); const url = new URL('service/local/staging/bulk/promote', options.serverUrl); const response = await fetch(url, { method: 'POST', body: JSON.stringify({ data: { stagedRepositoryIds: [options.repositoryId], description: options.description ?? 'Deployment', autoDropAfterRelease: true, }, }), headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', 'Authorization': `Basic ${btoa(`${options.username}:${options.password}`)}`, }, }); const body = await response.text(); // It's possible that (due to some replication latency?) the initial "stage" succeeds, // but the "release" fails, if we try to publish an already-published version again. // // Unfortunately there is no great error code to detect this right now, but I've observed // this error when it happened. // I have a support request out to Sonatype for this, we'll see if this changes over time. if (response.status === 400 && body === 'Failed to process request: service error') { return 'duplicate-version'; } if (!response.ok) { throw new Error(`HTTP ${response.status} ${response.statusText}: ${body}`); } console.log(body); return 'ok'; } /** * Sign and stage our artifacts into a local directory */ async function signJars(maven, poms, targetDir, serverId, key) { const env_2 = { stack: [], error: void 0, hasError: false }; try { const gpg = __addDisposableResource(env_2, await importGpgKey(key), true); // on a mac, --pinentry-mode to "loopback" are required and I couldn't find a // way to do so via -Dgpg.gpgArguments or the settings file, so here we are. let gpgBin = 'gpg'; if (zx_1.os.platform() === 'darwin') { gpgBin = zx_1.path.join(maven.workDir, 'publib-gpg.sh'); await fs_1.promises.writeFile(gpgBin, [ '#!/bin/bash', 'exec gpg --pinentry-mode loopback "\$@"', ].join('\n'), 'utf-8'); await (0, zx_1.$) `chmod +x ${gpgBin}`; } for (const pom of poms) { await maven.exec('gpg:sign-and-deploy-file', { properties: { 'url': `file://${targetDir}`, 'repositoryId': serverId, // Most likely not necessary 'gpg.homedir': gpg.home, 'gpg.keyname': gpg.keyId, 'gpg.executable': gpgBin, 'pomFile': pom, ...jarsFromPom(pom), }, }); } } catch (e_2) { env_2.error = e_2; env_2.hasError = true; } finally { const result_2 = __disposeResources(env_2); if (result_2) await result_2; } } /** * Based on the path of a .pom file, return the paths of the corresponding jars */ function jarsFromPom(pom) { return { file: pom.replace(/\.pom$/, '.jar'), sources: pom.replace(/\.pom$/, '-sources.jar'), javadoc: pom.replace(/\.pom$/, '-javadoc.jar'), }; } /** * Create a temporary directory and import the GPG key material into a new keychain there */ async function importGpgKey(key) { // GnuPG will occasionally bail out with "gpg: <whatever> failed: Inappropriate ioctl for device", the following attempts to fix const gpgHome = autoCleanDir(); try { // In CI environments there will be no tty, and we don't want this to stop the script. // The variable will be populated with a nonsensical string ("not a tty") but that doesn't seem to matter. const tty = (await (0, zx_1.$)({ stdio: ['inherit', 'pipe', 'pipe'], nothrow: true }) `tty`).stdout; let privateKeyFile; const type = key.type; switch (type) { case 'file': privateKeyFile = key.fileName; break; case 'material': privateKeyFile = zx_1.path.join(gpgHome.dir, 'private.pem'); await (0, zx_1.$) `echo -e ${key.keyMaterial} > ${privateKeyFile}`; break; default: assertNever(type); } const env = { GNUPGHOME: gpgHome.dir, GPG_TTY: tty, }; const $$ = (0, zx_1.$)({ env: { ...process.env, ...env } }); await $$ `gpg --allow-secret-key-import --batch --yes --no-tty --import ${privateKeyFile}`; const gpgKeyId = (await $$ `gpg --list-keys --with-colons | grep pub | cut -d: -f5`).stdout.trim(); (0, zx_1.echo)(`gpg_key_id=${gpgKeyId}`); return { keyId: gpgKeyId, env, home: gpgHome.dir, [Symbol.asyncDispose]: async () => gpgHome[Symbol.asyncDispose](), }; } catch (e) { await gpgHome[Symbol.asyncDispose](); throw e; } } class Maven { constructor(workDir, verbose, dryRun) { this.workDir = workDir; this.verbose = verbose; this.dryRun = dryRun; this.settingsFile = zx_1.path.join(workDir, 'mvn-settings.xml'); } /** * Create a settings.xml file with the user+password for maven */ async writeSettingsFile(serverId, signedArtifacts) { const lines = []; lines.push('<?xml version="1.0" encoding="UTF-8" ?>', '<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"', ' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"', ' xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0', ' http://maven.apache.org/xsd/settings-1.0.0.xsd">', ' <servers>', ' <server>', ` <id>${serverId}</id>`, // Maven will read these, surrounding code has already made sure they are set ' <username>${env.MAVEN_USERNAME}</username>', ' <password>${env.MAVEN_PASSWORD}</password>', ' </server>'); if (signedArtifacts) { lines.push(' <server>', ' <id>gpg.passphrase</id>', // Maven will read these, surrounding code has already made sure they are set ' <passphrase>${env.MAVEN_GPG_PRIVATE_KEY_PASSPHRASE}</passphrase>', ' </server>'); } lines.push(' </servers>', '</settings>'); await fs_1.promises.writeFile(this.settingsFile, lines.join('\n'), 'utf-8'); } async exec(mojo, options) { const args = [ `--settings=${this.settingsFile}`, '--batch-mode', ...(options.verbose ?? this.verbose ? ['-X'] : []), mojo, ...Object.entries(options.properties).map(([k, v]) => `-D${k}=${v}`), ]; if (this.dryRun) { (0, zx_1.echo)(`[DRY-RUN] mvn ${args.map(zx_1.quote).join(' ')}`); return undefined; } const env = { ...process.env, JDK_JAVA_OPTIONS: [ // If we don't add this, we'll get an error like the following during the nexus-staging-maven-plugin:rc-release mojo. // Don't know where this is coming from all of a sudden. // // [ERROR] message : No converter available // [ERROR] type : java.util.Arrays$ArrayList // [ERROR] converter : com.thoughtworks.xstream.converters.reflection.ReflectionConverter // [ERROR] message[1] : Unable to make field protected transient int java.util.AbstractList.modCount accessible: module java.base does not "opens java.util" to unnamed module @7c8d5312 '--add-opens=java.base/java.util=ALL-UNNAMED', '--add-opens=java.base/java.lang=ALL-UNNAMED', '--add-opens=java.base/java.lang.invoke=ALL-UNNAMED', ].join(' '), }; return (0, zx_1.$)({ verbose: true, nothrow: options.nothrow, env }) `mvn ${args}`; } } /** * A expected error that doesn't need a stack trace */ class SimpleError extends Error { } /** * Require an environment variable */ function envVar(name) { const ret = process.env[name]; if (!ret) { throw new SimpleError(`${name} is required`); } return ret; } /** * A temporary directory that cleans when it goes out of scope * * Use with `using`. Could have been async but it's depending * on an already-sync API, so why not sync? */ function autoCleanDir() { const dir = (0, zx_1.tmpdir)(); return { dir, [Symbol.asyncDispose]: async () => { await fs_1.promises.rm(dir, { force: true, recursive: true }); }, }; } function assertNever(value) { throw new Error('Unexpected value: ' + value); } // A 'zx' primer // // - By default: stderr is printed to the terminal if it is captured. // - { verbose: true }: print the command, stdout and stderr to the terminal // - { quiet: true }: print neither stdout nor stderr // // .text(): return everything that's captured (stderr and stdout together if stderr is captured) main().catch(e => { if (e instanceof zx_1.ProcessOutput) { (0, zx_1.echo)(`❌ Subprocess failed with exit code ${e.exitCode}`); } else if (e instanceof SimpleError) { (0, zx_1.echo)('❌', e.message); } else { console.error(e); } process.exitCode = 1; }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHVibGliLW1hdmVuLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2Jpbi9wdWJsaWItbWF2ZW4udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBNm5CQSxvQ0FRQztBQXJvQkQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0F5Qkc7QUFDSCwyQkFBb0M7QUFDcEMsMkJBQStFO0FBRS9FLE1BQU0sc0JBQXNCLEdBQUcsT0FBTyxDQUFDO0FBQ3ZDLE1BQU0sd0JBQXdCLEdBQUcsZUFBZSxDQUFDO0FBRWpELE1BQU0sMEJBQTBCLEdBQUcsdURBQXVELENBQUM7QUFFM0YsS0FBSyxVQUFVLElBQUk7SUFDakIsTUFBTSxJQUFJLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDbkMsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFJLFdBQVcsQ0FBQztJQUV4QyxJQUFBLE9BQUUsRUFBQyxRQUFRLENBQUMsQ0FBQztJQUViLE1BQU0sSUFBSSxHQUFHLE1BQU0sSUFBQSxTQUFJLEVBQUMsVUFBVSxDQUFDLENBQUM7SUFDcEMsSUFBSSxJQUFJLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO1FBQ3RCLE1BQU0sSUFBSSxXQUFXLENBQUMsaURBQWlELE9BQU8sQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDMUYsQ0FBQztJQUVELElBQUEsU0FBSSxFQUFDLGVBQWUsSUFBSSxFQUFFLENBQUMsQ0FBQztJQUU1QixNQUFNLGFBQWEsR0FBeUI7UUFDMUMsUUFBUSxFQUFFLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQztRQUNsQyxRQUFRLEVBQUUsTUFBTSxDQUFDLGdCQUFnQixDQUFDO1FBQ2xDLE1BQU0sRUFBRSxPQUFPLENBQUMsR0FBRyxDQUFDLFlBQVksS0FBSyxN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RSxDQUFDLEVBQUUsQ0FBQyxHQUFHLEVBQUUsRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFFLFNBQVMsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO1FBQ3JELENBQUM7S0FDRixDQUFDO0FBQ0osQ0FBQztBQUVELFNBQVMsV0FBVyxDQUFDLEtBQVk7SUFDL0IsTUFBTSxJQUFJLEtBQUssQ0FBQyxvQkFBb0IsR0FBRyxLQUFLLENBQUMsQ0FBQztBQUNoRCxDQUFDO0FBRUQsZ0JBQWdCO0FBQ2hCLEVBQUU7QUFDRixxRUFBcUU7QUFDckUsNEVBQTRFO0FBQzVFLHFEQUFxRDtBQUNyRCxFQUFFO0FBQ0YsZ0dBQWdHO0FBRWhHLElBQUksRUFBRSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsRUFBRTtJQUNmLElBQUksQ0FBQyxZQUFZLGtCQUFhLEVBQUUsQ0FBQztRQUMvQixJQUFBLFNBQUksRUFBQyxzQ0FBc0MsQ0FBQyxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUM7SUFDM0QsQ0FBQztTQUFNLElBQUksQ0FBQyxZQUFZLFdBQVcsRUFBRSxDQUFDO1FBQ3BDLElBQUEsU0FBSSxFQUFDLEdBQUcsRUFBRSxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDdkIsQ0FBQztTQUFNLENBQUM7UUFDTixPQUFPLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ25CLENBQUM7SUFDRCxPQUFPLENBQUMsUUFBUSxHQUFHLENBQUMsQ0FBQztBQUN2QixDQUFDLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogTGVnYWN5IHZzIGNvbXBhdGliaWxpdHkgZW5kcG9pbnRcbiAqID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqXG4gKiBUaGlzIHNjcmlwdCB0YWxrcyBhYm91dCBsZWdhY3kgdnMgY29tcGF0aWJpbGl0eSBlbmRwb2ludCBhIGJ1bmNoLlxuICpcbiAqIEJvdGggaW1wbGVtZW50IHRoZSBOZXh1cyAyIHByb3RvY29sLCBob3dldmVyOlxuICpcbiAqIC0gVGhlIFwibGVnYWN5XCIgZW5kcG9pbnQgaXMgdGhlIFNvbmF0eXBlIE9TU1JIIGVuZHBvaW50IHRoYXQgd2FzIGRlcHJlY2F0ZWQgSnVuZSAyMDI1LlxuICogLSBUaGUgXCJjb21wYXRpYmlsaXR5XCIgZW5kcG9pbnQgaXMgYSBOZXh1cyAyLWNvbXBhdGlibGUgZW5kcG9pbnQgc3Rvb2QgdXAgZm9yIHRoZSBuZXdcbiAqICAgcHVibGlzaGluZyBzZXJ2aWNlLCBDZW50cmFsIFB1Ymxpc2hpbmcuXG4gKlxuICogSXQgc2hvdWxkIGJlIHRoZSBzYW1lIHByb3RvY29sIGJ1dCBvZiBjb3Vyc2UgdGhlcmUgYXJlIHN1YnRsZSBkaWZmZXJlbmNlc1xuICogYmV0d2VlbiB0aGVtIChpbiBob3cgdGhleSBzaWduYWwgZXJyb3Igd2hlbiB5b3UgdHJ5IHRvIHJlcHVibGlzaCBhbiBhbHJlYWR5XG4gKiBwdWJsaXNoZWQgdmVyc2lvbiwgYW5kIGV2ZW4gaW4gdGhlIHdpcmUgcHJvdG9jb2wgYWNjZXB0ZWQpIHNvIHdlIGhhdmUgdG9cbiAqIHRyZWF0IHRoZW0gZGlmZmVyZW50bHkgaGVyZS5cbiAqXG4gKiBUaGVyZSBpcyBhbHNvIGFuIFwib2ZmaWNpYWwgbmV3XCIgcHJvdG9jb2wgZm9yIHRoZSBuZXcgcHVibGlzaGluZyBtZWNoYW5pc20sXG4gKiBidXQgdGhlIE1hdmVuIHBsdWdpbiB0aGV5IHN1cHBseSBmb3IgdGhhdCBkb2Vzbid0IHN1cHBvcnQgdGhhdC4gSW4gdGhlaXIgd29yZHM6XG4gKlxuICogPiBpdCBhcHBlYXJzIHRoYXQgeW91IGFyZSB1c2luZyB0aGUgXCJ0d28gc3RhZ2VcIlsxXSBkZXBsb3ltZW50IHByb2Nlc3MsIHdoaWNoIGlzXG4gKiA+IG5vdCB5ZXQgc3VwcG9ydGVkIGJ5IHRoZSBuZXcgcGx1Z2luLiBZb3UgYXJlIHRoZSBmaXJzdCBwdWJsaXNoZXIgdG8gaGF2ZVxuICogPiByZXF1ZXN0ZWQgdGhpcywgc28gd2Ugd2VyZSBub3QgZmFtaWxpYXIgd2l0aCB0aGlzIHNwZWNpZmljIHVzZWNhc2Ugd2hlblxuICogPiBidWlsZGluZyB0aGUgbmV3IHBsdWdpblxuICogPiBbMV0gPGh0dHBzOi8vZ2l0aHViLmNvbS9zb25hdHlwZS9uZXh1cy1tYXZlbi1wbHVnaW5zL2Jsb2IvNDNhOTk0MGIxMzRjM2Y4N2ViZTRkYWE4MjU1MmU4NDRkOWM1NzhiOC9zdGFnaW5nL21hdmVuLXBsdWdpbi9XT1JLRkxPV1MubWQjdHdvLXNob3RzPlxuICovXG5pbXBvcnQgeyBwcm9taXNlcyBhcyBmcyB9IGZyb20gJ2ZzJztcbmltcG9ydCB7ICQsIGNkLCBlY2hvLCBnbG9iLCBvcywgcGF0aCwgUHJvY2Vzc091dHB1dCwgcXVvdGUsIHRtcGRpciB9IGZyb20gJ3p4JztcblxuY29uc3QgTEVHQUNZX09TU1JIX1NFUlZFUl9JRCA9ICdvc3NyaCc7XG5jb25zdCBDT01QQVRfQ0VOVFJBTF9TRVJWRVJfSUQgPSAnY2VudHJhbC1vc3NyaCc7XG5cbmNvbnN0IE5FWFVTX01BVkVOX1NUQUdJTkdfUExVR0lOID0gJ29yZy5zb25hdHlwZS5wbHVnaW5zOm5leHVzLXN0YWdpbmctbWF2ZW4tcGx1Z2luOjEuNy4wJztcblxuYXN5bmMgZnVuY3Rpb24gbWFpbigpIHtcbiAgY29uc3QgYXJncyA9IHByb2Nlc3MuYXJndi5zbGljZSgyKTtcbiAgY29uc3QgamF2YVJvb3QgPSBhcmdzWzBdID8/ICdkaXN0L2phdmEnO1xuXG4gIGNkKGphdmFSb290KTtcblxuICBjb25zdCBwb21zID0gYXdhaXQgZ2xvYignKiovKi5wb20nKTtcbiAgaWYgKHBvbXMubGVuZ3RoID09PSAwKSB7XG4gICAgdGhyb3cgbmV3IFNpbXBsZUVycm9yKGBObyBKQVJTIHRvIHB1Ymxpc2g6IG5vIC5wb20gZmlsZXMgZm91bmQgdW5kZXIgJHtwcm9jZXNzLmN3ZCgpfWApO1xuICB9XG5cbiAgZWNobyhgUE9NcyBmb3VuZDogJHtwb21zfWApO1xuXG4gIGNvbnN0IHNoYXJlZE9wdGlvbnM6IFNoYXJlZFB1Ymxpc2hPcHRpb25zID0ge1xuICAgIHVzZXJuYW1lOiBlbnZWYXIoJ01BVkVOX1VTRVJOQU1FJyksXG4gICAgcGFzc3dvcmQ6IGVudlZhcignTUFWRU5fUEFTU1dPUkQnKSxcbiAgICBkcnlSdW46IHByb2Nlc3MuZW52Lk1BVkVOX0RSWVJVTiA9PT0gJ3RydWUnIHx8IHByb2Nlc3MuZW52LlBVQkxJQl9EUllSVU4gPT09ICd0cnVlJyxcbiAgICB2ZXJib3NlOiBwcm9jZXNzLmVudi5NQVZFTl9WRVJCT1NFID09PSAndHJ1ZScsXG4gICAgcG9tcyxcbiAgfTtcblxuICBsZXQgb3B0aW9uczogTWF2ZW5QdWJsaXNoT3B0aW9ucztcbiAgY29uc3Qgc2VydmVySWQgPSBwcm9jZXNzLmVudi5NQVZFTl9TRVJWRVJfSUQgPz8gTEVHQUNZX09TU1JIX1NFUlZFUl9JRDtcblxuICBzd2l0Y2ggKHNlcnZlcklkKSB7XG4gICAgY2FzZSBMRUdBQ1lfT1NTUkhfU0VSVkVSX0lEOlxuICAgICAgb3B0aW9ucyA9IHtcbiAgICAgICAgdHlwZTogJ2xlZ2FjeS1vc3NyaCcsXG4gICAgICAgIC4uLnNoYXJlZE9wdGlvbnMsXG4gICAgICAgIHN0YWdpbmdQcm9maWxlSWQ6IGVudlZhcignTUFWRU5fU1RBR0lOR19QUk9GSUxFX0lEJyksXG4gICAgICAgIGVuZHBvaW50OiBwcm9jZXNzLmVudi5NQVZFTl9FTkRQT0lOVCxcbiAgICAgICAgcHJpdmF0ZUtleTogcGFyc2VQcml2YXRlS2V5RnJvbUVudigpLFxuICAgICAgfTtcbiAgICAgIGJyZWFrO1xuICAgIGNhc2UgQ09NUEFUX0NFTlRSQUxfU0VSVkVSX0lEOlxuICAgICAgb3B0aW9ucyA9IHtcbiAgICAgICAgdHlwZTogJ2NvbXBhdC1vc3NyaCcsXG4gICAgICAgIC4uLnNoYXJlZE9wdGlvbnMsXG4gICAgICAgIC8vIE5vdCByZXF1aXJlZCBieSB0aGUgbmV3IGVuZHBvaW50OiBjYW4gYmUgYW55IHZhbHVlIChtYXliZSBuZXZlciB3YXMgcmVxdWlyZWQgdG8gYmVnaW4gd2l0aD8pXG4gICAgICAgIHN0YWdpbmdQcm9maWxlSWQ6ICdwdWJsaWInLFxuICAgICAgICBlbmRwb2ludDogcHJvY2Vzcy5lbnYuTUFWRU5fRU5EUE9JTlQsXG4gICAgICAgIHByaXZhdGVLZXk6IHBhcnNlUHJpdmF0ZUtleUZyb21FbnYoKSxcbiAgICAgIH07XG4gICAgICBicmVhaztcbiAgICBkZWZhdWx0OlxuICAgICAgLy8gV2UgaGF2ZW4ndCBpbXBsZW1lbnRlZCBzaWduaW5nIGZvciB0aGlzLCBzbyBmYWlsIGxvdWRseSBpZiBwZW9wbGUgdHJ5IHRvIHVzZSBpdCBhbnl3YXlcbiAgICAgIGlmIChwcm9jZXNzLmVudi5NQVZFTl9HUEdfUFJJVkFURV9LRVkgfHwgcHJvY2Vzcy5lbnYuTUFWRU5fR1BHX1BSSVZBVEVfS0VZX0ZJTEUpIHtcbiAgICAgICAgdGhyb3cgbmV3IFNpbXBsZUVycm9yKCdNQVZFTl9HUEdfUFJJVkFURV9LRVlbX0ZJTEVdIGlzIG9ubHkgc3VwcG9ydGVkIGZvciBPU1NSSCBwdWJsaXNoaW5nJyk7XG4gICAgICB9XG5cbiAgICAgIG9wdGlvbnMgPSB7XG4gICAgICAgIHR5cGU6ICdjdXN0b20tbmV4dXMnLFxuICAgICAgICAuLi5zaGFyZWRPcHRpb25zLFxuICAgICAgICBzZXJ2ZXJJZCxcbiAgICAgICAgcmVwb3NpdG9yeVVybDogZW52VmFyKCdNQVZFTl9SRVBPU0lUT1JZX1VSTCcpLFxuICAgICAgfTtcbiAgICAgIGJyZWFrO1xuICB9XG5cbiAgYXdhaXQgbWF2ZW5QdWJsaXNoKG9wdGlvbnMpO1xuXG4gIGVjaG8oJ35+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn4nKTtcbiAgZWNobygn4pyFIEFsbCBEb25lIScpO1xufVxuXG5mdW5jdGlvbiBwYXJzZVByaXZhdGVLZXlGcm9tRW52KCk6IFByaXZhdGVLZXkge1xuICBpZiAocHJvY2Vzcy5lbnYuTUFWRU5fR1BHX1BSSVZBVEVfS0VZX0ZJTEUpIHtcbiAgICByZXR1cm4geyB0eXBlOiAnZmlsZScsIGZpbGVOYW1lOiBwcm9jZXNzLmVudi5NQVZFTl9HUEdfUFJJVkFURV9LRVlfRklMRSwgcGFzc1BocmFzZTogZW52VmFyKCdNQVZFTl9HUEdfUFJJVkFURV9LRVlfUEFTU1BIUkFTRScpIH07XG4gIH1cbiAgaWYgKHByb2Nlc3MuZW52Lk1BVkVOX0dQR19QUklWQVRFX0tFWSkge1xuICAgIHJldHVybiB7IHR5cGU6ICdtYXRlcmlhbCcsIGtleU1hdGVyaWFsOiBwcm9jZXNzLmVudi5NQVZFTl9HUEdfUFJJVkFURV9LRVksIHBhc3NQaHJhc2U6IGVudlZhcignTUFWRU5fR1BHX1BSSVZBVEVfS0VZX1BBU1NQSFJBU0UnKSB9O1xuICB9XG4gIHRocm93IG5ldyBTaW1wbGVFcnJvcignTUFWRU5fR1BHX1BSSVZBVEVfS0VZW19GSUxFXSBpcyByZXF1aXJlZCcpO1xufVxuXG4vLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbi8vICBNb2RlbGluZyBhbGwgdGhlIHBhcmFtZXRlcnMgc28gdGhhdCB3ZSBjYW4gcHVsbCB0aGUgZW52aXJvbm1lbnQgcGFyc2luZyBmb3J3YXJkXG4vL1xuXG5pbnRlcmZhY2UgU2hhcmVkUHVibGlzaE9wdGlvbnMge1xuICByZWFkb25seSB1c2VybmFtZTogc3RyaW5nO1xuICByZWFkb25seSBwYXNzd29yZDogc3RyaW5nO1xuICByZWFkb25seSBkcnlSdW46IGJvb2xlYW47XG4gIHJlYWRvbmx5IHZlcmJvc2U6IGJvb2xlYW47XG4gIHJlYWRvbmx5IHBvbXM6IHN0cmluZ1tdO1xufVxuXG5pbnRlcmZhY2UgTGVnYWN5T3NzcmhQdWJsaXNoT3B0aW9ucyBleHRlbmRzIFNoYXJlZFB1Ymxpc2hPcHRpb25zIHtcbiAgdHlwZTogJ2xlZ2FjeS1vc3NyaCc7XG4gIHJlYWRvbmx5IHByaXZhdGVLZXk6IFByaXZhdGVLZXk7XG4gIHJlYWRvbmx5IGVuZHBvaW50Pzogc3RyaW5nO1xuICByZWFkb25seSBzdGFnaW5nUHJvZmlsZUlkOiBzdHJpbmc7XG59XG5cbmludGVyZmFjZSBDb21wYXRPc3NyaFB1Ymxpc2hPcHRpb25zIGV4dGVuZHMgU