UNPKG

@riddance/deploy

Version:

162 lines 24 kB
import { thrownHasStatus } from '@riddance/fetch'; import { SignatureV4 } from '@smithy/signature-v4'; import { createHash, createHmac } from 'node:crypto'; import { readFile } from 'node:fs/promises'; import { homedir } from 'node:os'; import { join } from 'node:path'; import { setTimeout } from 'node:timers/promises'; let cachedConfigLines; export async function localAwsEnv(region, profile) { let { AWS_REGION, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN } = { AWS_REGION: region ?? process.env.AWS_REGION ?? process.env.AWS_DEFAULT_REGION, AWS_ACCESS_KEY_ID: process.env.AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY: process.env.AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN: process.env.AWS_SESSION_TOKEN, }; if (AWS_REGION && AWS_ACCESS_KEY_ID && AWS_SECRET_ACCESS_KEY) { return { AWS_REGION, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY }; } const configLines = cachedConfigLines ?? (await readFile(process.env.AWS_SHARED_CREDENTIALS_FILE ?? join(homedir(), '.aws', 'credentials'), 'ascii')) .split('\n') .map(line => line.trim()) .filter(line => !!line && !line.startsWith('#')); // eslint-disable-next-line require-atomic-updates cachedConfigLines = configLines; let sectionBeginIx = -1; const section = `[${profile}]`; sectionBeginIx = configLines.indexOf(section); if (sectionBeginIx === -1) { sectionBeginIx = configLines.indexOf('[default]'); } if (sectionBeginIx === -1) { throw new Error('Section not found.'); } const sectionEndIx = configLines.findIndex((line, ix) => ix > sectionBeginIx && line.startsWith('[')); const sectionLines = configLines .slice(sectionBeginIx + 1, sectionEndIx === -1 ? undefined : sectionEndIx) .map(line => line.split('=')) .map(([k, v]) => [k?.trim(), v?.trim()]); AWS_REGION ??= sectionLines.find(([k]) => k === 'region')?.[1]; AWS_ACCESS_KEY_ID = sectionLines.find(([k]) => k === 'aws_access_key_id')?.[1]; AWS_SECRET_ACCESS_KEY = sectionLines.find(([k]) => k === 'aws_secret_access_key')?.[1]; AWS_SESSION_TOKEN = sectionLines.find(([k]) => k === 'aws_session_token')?.[1]; if (!AWS_REGION || !AWS_ACCESS_KEY_ID || !AWS_SECRET_ACCESS_KEY) { throw new Error('Incomplete AWS credentials file.'); } return { AWS_REGION, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN }; } export function awsRequest(env, method, service, path, body) { return awsStringRequest(env, method, service, path, body ? JSON.stringify(body) : '', 'application/json'); } export function awsFormRequest(env, method, service, path, body) { return awsStringRequest(env, method, service, path, body.toString(), 'application/x-www-form-urlencoded'); } async function awsStringRequest(env, method, service, path, body, contentType) { const signer = new SignatureV4({ service, region: service === 'iam' ? 'us-east-1' : env.AWS_REGION, sha256: AwsHash, credentials: { accessKeyId: env.AWS_ACCESS_KEY_ID, secretAccessKey: env.AWS_SECRET_ACCESS_KEY, sessionToken: env.AWS_SESSION_TOKEN, }, }); const uri = new URL(`https://${subdomain(service, env.AWS_REGION)}.amazonaws.com${path}`); const query = {}; uri.searchParams.forEach((value, key) => { query[key] = value; }); const { headers } = await signer.sign({ method, protocol: 'https:', hostname: uri.hostname, path: uri.pathname, query, headers: { host: uri.hostname, 'content-type': contentType, accept: 'application/json', }, body, }); return await fetch(uri.toString(), { method, headers, body: body || undefined, }); } function subdomain(service, region) { switch (service) { case 'iam': return 'iam'; default: return `${service}.${region}`; } } export async function retry(request, when) { for (let attempts = 0;; ++attempts) { const response = await request(); const maxRetries = when(response); if (maxRetries === undefined || maxRetries <= attempts) { return response; } console.log(`retrying #${attempts + 1}... (${response.url} -> ${await response.text()})`); await setTimeout(500); } } export function isNotFound(e) { return thrownHasStatus(e, 404); } export function isConflict(e) { return thrownHasStatus(e, 409); } export async function retryConflict(fn) { const deadline = new Date(); deadline.setUTCSeconds(deadline.getUTCSeconds() + 30); for (;;) { try { return await fn(); } catch (e) { if (!isConflict(e) || new Date() > deadline) { throw e; } await setTimeout(((Math.random() + 0.5) * 500) / 2); } } } class AwsHash { #secret; #hash; constructor(secret) { this.#secret = secret; this.#hash = makeHash(this.#secret); } digest() { return Promise.resolve(this.#hash.digest()); } reset() { this.#hash = makeHash(this.#secret); } update(chunk) { this.#hash.update(new Uint8Array(Buffer.from(chunk))); } } function makeHash(secret) { return secret ? createHmac('sha256', castSourceData(secret)) : createHash('sha256'); } function castSourceData(data) { if (Buffer.isBuffer(data)) { return data; } if (typeof data === 'string') { return Buffer.from(data); } if (ArrayBuffer.isView(data)) { return Buffer.from(data.buffer, data.byteOffset, data.byteLength); } return Buffer.from(data); } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGl0ZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbImxpdGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLGlCQUFpQixDQUFBO0FBQ2pELE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQTtBQUNsRCxPQUFPLEVBQUUsVUFBVSxFQUFFLFVBQVUsRUFBRSxNQUFNLGFBQWEsQ0FBQTtBQUNwRCxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sa0JBQWtCLENBQUE7QUFDM0MsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLFNBQVMsQ0FBQTtBQUNqQyxPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0sV0FBVyxDQUFBO0FBQ2hDLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQTtBQVNqRCxJQUFJLGlCQUF1QyxDQUFBO0FBRTNDLE1BQU0sQ0FBQyxLQUFLLFVBQVUsV0FBVyxDQUFDLE1BQTBCLEVBQUUsT0FBZTtJQUN6RSxJQUFJLEVBQUUsVUFBVSxFQUFFLGlCQUFpQixFQUFFLHFCQUFxQixFQUFFLGlCQUFpQixFQUFFLEdBQUc7UUFDOUUsVUFBVSxFQUFFLE1BQU0sSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLFVBQVUsSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLGtCQUFrQjtRQUM5RSxpQkFBaUIsRUFBRSxPQUFPLENBQUMsR0FBRyxDQUFDLGlCQUFpQjtRQUNoRCxxQkFBcUIsRUFBRSxPQUFPLENBQUMsR0FBRyxDQUFDLHFCQUFxQjtRQUN4RCxpQkFBaUIsRUFBRSxPQUFPLENBQUMsR0FBRyxDQUFDLGlCQUFpQjtLQUNuRCxDQUFBO0lBQ0QsSUFBSSxVQUFVLElBQUksaUJBQWlCLElBQUkscUJBQXFCLEVBQUUsQ0FBQztRQUMzRCxPQUFPLEVBQUUsVUFBVSxFQUFFLGlCQUFpQixFQUFFLHFCQUFxQixFQUFFLENBQUE7SUFDbkUsQ0FBQztJQUNELE1BQU0sV0FBVyxHQUNi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QUFXLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7UUFDM0IsT0FBTyxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLFVBQVUsRUFBRSxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUE7SUFDckUsQ0FBQztJQUNELE9BQU8sTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQTtBQUM1QixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgdGhyb3duSGFzU3RhdHVzIH0gZnJvbSAnQHJpZGRhbmNlL2ZldGNoJ1xuaW1wb3J0IHsgU2lnbmF0dXJlVjQgfSBmcm9tICdAc21pdGh5L3NpZ25hdHVyZS12NCdcbmltcG9ydCB7IGNyZWF0ZUhhc2gsIGNyZWF0ZUhtYWMgfSBmcm9tICdub2RlOmNyeXB0bydcbmltcG9ydCB7IHJlYWRGaWxlIH0gZnJvbSAnbm9kZTpmcy9wcm9taXNlcydcbmltcG9ydCB7IGhvbWVkaXIgfSBmcm9tICdub2RlOm9zJ1xuaW1wb3J0IHsgam9pbiB9IGZyb20gJ25vZGU6cGF0aCdcbmltcG9ydCB7IHNldFRpbWVvdXQgfSBmcm9tICdub2RlOnRpbWVycy9wcm9taXNlcydcblxuZXhwb3J0IHR5cGUgTG9jYWxFbnYgPSB7XG4gICAgQVdTX1JFR0lPTjogc3RyaW5nXG4gICAgQVdTX0FDQ0VTU19LRVlfSUQ6IHN0cmluZ1xuICAgIEFXU19TRUNSRVRfQUNDRVNTX0tFWTogc3RyaW5nXG4gICAgQVdTX1NFU1NJT05fVE9LRU4/OiBzdHJpbmdcbn1cblxubGV0IGNhY2hlZENvbmZpZ0xpbmVzOiBzdHJpbmdbXSB8IHVuZGVmaW5lZFxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gbG9jYWxBd3NFbnYocmVnaW9uOiBzdHJpbmcgfCB1bmRlZmluZWQsIHByb2ZpbGU6IHN0cmluZyk6IFByb21pc2U8TG9jYWxFbnY+IHtcbiAgICBsZXQgeyBBV1NfUkVHSU9OLCBBV1NfQUNDRVNTX0tFWV9JRCwgQVdTX1NFQ1JFVF9BQ0NFU1NfS0VZLCBBV1NfU0VTU0lPTl9UT0tFTiB9ID0ge1xuICAgICAgICBBV1NfUkVHSU9OOiByZWdpb24gPz8gcHJvY2Vzcy5lbnYuQVdTX1JFR0lPTiA/PyBwcm9jZXNzLmVudi5BV1NfREVGQVVMVF9SRUdJT04sXG4gICAgICAgIEFXU19BQ0NFU1NfS0VZX0lEOiBwcm9jZXNzLmVudi5BV1NfQUNDRVNTX0tFWV9JRCxcbiAgICAgICAgQVdTX1NFQ1JFVF9BQ0NFU1NfS0VZOiBwcm9jZXNzLmVudi5BV1NfU0VDUkVUX0FDQ0VTU19LRVksXG4gICAgICAgIEFXU19TRVNTSU9OX1RPS0VOOiBwcm9jZXNzLmVudi5BV1NfU0VTU0lPTl9UT0tFTixcbiAgICB9XG4gICAgaWYgKEFXU19SRUdJT04gJiYgQVdTX0FDQ0VTU19LRVlfSUQgJiYgQVdTX1NFQ1JFVF9BQ0NFU1NfS0VZKSB7XG4gICAgICAgIHJldHVybiB7IEFXU19SRUdJT04sIEFXU19BQ0NFU1NfS0VZX0lELCBBV1NfU0VDUkVUX0FDQ0VTU19LRVkgfVxuICAgIH1cbiAgICBjb25zdCBjb25maWdMaW5lcyA9XG4gICAgICAgIGNhY2hlZENvbmZpZ0xpbmVzID8/XG4gICAgICAgIChcbiAgICAgICAgICAgIGF3YWl0IHJlYWRGaWxlKFxuICAgICAgICAgICAgICAgIHByb2Nlc3MuZW52LkFXU19TSEFSRURfQ1JFREVOVElBTFNfRklMRSA/PyBqb2luKGhvbWVkaXIoKSwgJy5hd3MnLCAnY3JlZGVudGlhbHMnKSxcbiAgICAgICAgICAgICAgICAnYXNjaWknLFxuICAgICAgICAgICAgKVxuICAgICAgICApXG4gICAgICAgICAgICAuc3BsaXQoJ1xcbicpXG4gICAgICAgICAgICAubWFwKGxpbmUgPT4gbGluZS50cmltKCkpXG4gICAgICAgICAgICAuZmlsdGVyKGxpbmUgPT4gISFsaW5lICYmICFsaW5lLnN0YXJ0c1dpdGgoJyMnKSlcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgcmVxdWlyZS1hdG9taWMtdXBkYXRlc1xuICAgIGNhY2hlZENvbmZpZ0xpbmVzID0gY29uZmlnTGluZXNcblxuICAgIGxldCBzZWN0aW9uQmVnaW5JeCA9IC0xXG4gICAgY29uc3Qgc2VjdGlvbiA9IGBbJHtwcm9maWxlfV1gXG4gICAgc2VjdGlvbkJlZ2luSXggPSBjb25maWdMaW5lcy5pbmRleE9mKHNlY3Rpb24pXG4gICAgaWYgKHNlY3Rpb25CZWdpbkl4ID09PSAtMSkge1xuICAgICAgICBzZWN0aW9uQmVnaW5JeCA9IGNvbmZpZ0xpbmVzLmluZGV4T2YoJ1tkZWZhdWx0XScpXG4gICAgfVxuICAgIGlmIChzZWN0aW9uQmVnaW5JeCA9PT0gLTEpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdTZWN0aW9uIG5vdCBmb3VuZC4nKVxuICAgIH1cbiAgICBjb25zdCBzZWN0aW9uRW5kSXggPSBjb25maWdMaW5lcy5maW5kSW5kZXgoXG4gICAgICAgIChsaW5lLCBpeCkgPT4gaXggPiBzZWN0aW9uQmVnaW5JeCAmJiBsaW5lLnN0YXJ0c1dpdGgoJ1snKSxcbiAgICApXG4gICAgY29uc3Qgc2VjdGlvbkxpbmVzID0gY29uZmlnTGluZXNcbiAgICAgICAgLnNsaWNlKHNlY3Rpb25CZWdpbkl4ICsgMSwgc2VjdGlvbkVuZEl4ID09PSAtMSA/IHVuZGVmaW5lZCA6IHNlY3Rpb25FbmRJeClcbiAgICAgICAgLm1hcChsaW5lID0+IGxpbmUuc3BsaXQoJz0nKSlcbiAgICAgICAgLm1hcCgoW2ssIHZdKSA9PiBbaz8udHJpbSgpLCB2Py50cmltKCldKVxuICAgIEFXU19SRUdJT04gPz89IHNlY3Rpb25MaW5lcy5maW5kKChba10pID0+IGsgPT09ICdyZWdpb24nKT8uWzFdXG4gICAgQVdTX0FDQ0VTU19LRVlfSUQgPSBzZWN0aW9uTGluZXMuZmluZCgoW2tdKSA9PiBrID09PSAnYXdzX2FjY2Vzc19rZXlfaWQnKT8uWzFdXG4gICAgQVdTX1NFQ1JFVF9BQ0NFU1NfS0VZID0gc2VjdGlvbkxpbmVzLmZpbmQoKFtrXSkgPT4gayA9PT0gJ2F3c19zZWNyZXRfYWNjZXNzX2tleScpPy5bMV1cbiAgICBBV1NfU0VTU0lPTl9UT0tFTiA9IHNlY3Rpb25MaW5lcy5maW5kKChba10pID0+IGsgPT09ICdhd3Nfc2Vzc2lvbl90b2tlbicpPy5bMV1cbiAgICBpZiAoIUFXU19SRUdJT04gfHwgIUFXU19BQ0NFU1NfS0VZX0lEIHx8ICFBV1NfU0VDUkVUX0FDQ0VTU19LRVkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbmNvbXBsZXRlIEFXUyBjcmVkZW50aWFscyBmaWxlLicpXG4gICAgfVxuICAgIHJldHVybiB7IEFXU19SRUdJT04sIEFXU19BQ0NFU1NfS0VZX0lELCBBV1NfU0VDUkVUX0FDQ0VTU19LRVksIEFXU19TRVNTSU9OX1RPS0VOIH1cbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGF3c1JlcXVlc3QoXG4gICAgZW52OiBMb2NhbEVudixcbiAgICBtZXRob2Q6IHN0cmluZyxcbiAgICBzZXJ2aWNlOiBzdHJpbmcsXG4gICAgcGF0aDogc3RyaW5nLFxuICAgIGJvZHk/OiB1bmtub3duLFxuKSB7XG4gICAgcmV0dXJuIGF3c1N0cmluZ1JlcXVlc3QoXG4gICAgICAgIGVudixcbiAgICAgICAgbWV0aG9kLFxuICAgICAgICBzZXJ2aWNlLFxuICAgICAgICBwYXRoLFxuICAgICAgICBib2R5ID8gSlNPTi5zdHJpbmdpZnkoYm9keSkgOiAnJyxcbiAgICAgICAgJ2FwcGxpY2F0aW9uL2pzb24nLFxuICAgIClcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGF3c0Zvcm1SZXF1ZXN0KFxuICAgIGVudjogTG9jYWxFbnYsXG4gICAgbWV0aG9kOiBzdHJpbmcsXG4gICAgc2VydmljZTogc3RyaW5nLFxuICAgIHBhdGg6IHN0cmluZyxcbiAgICBib2R5OiBVUkxTZWFyY2hQYXJhbXMsXG4pIHtcbiAgICByZXR1cm4gYXdzU3RyaW5nUmVxdWVzdChcbiAgICAgICAgZW52LFxuICAgICAgICBtZXRob2QsXG4gICAgICAgIHNlcnZpY2UsXG4gICAgICAgIHBhdGgsXG4gICAgICAgIGJvZHkudG9TdHJpbmcoKSxcbiAgICAgICAgJ2FwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZCcsXG4gICAgKVxufVxuXG5hc3luYyBmdW5jdGlvbiBhd3NTdHJpbmdSZXF1ZXN0KFxuICAgIGVudjogTG9jYWxFbnYsXG4gICAgbWV0aG9kOiBzdHJpbmcsXG4gICAgc2VydmljZTogc3RyaW5nLFxuICAgIHBhdGg6IHN0cmluZyxcbiAgICBib2R5OiBzdHJpbmcsXG4gICAgY29udGVudFR5cGU6IHN0cmluZyxcbikge1xuICAgIGNvbnN0IHNpZ25lciA9IG5ldyBTaWduYXR1cmVWNCh7XG4gICAgICAgIHNlcnZpY2UsXG4gICAgICAgIHJlZ2lvbjogc2VydmljZSA9PT0gJ2lhbScgPyAndXMtZWFzdC0xJyA6IGVudi5BV1NfUkVHSU9OLFxuICAgICAgICBzaGEyNTY6IEF3c0hhc2gsXG4gICAgICAgIGNyZWRlbnRpYWxzOiB7XG4gICAgICAgICAgICBhY2Nlc3NLZXlJZDogZW52LkFXU19BQ0NFU1NfS0VZX0lELFxuICAgICAgICAgICAgc2VjcmV0QWNjZXNzS2V5OiBlbnYuQVdTX1NFQ1JFVF9BQ0NFU1NfS0VZLFxuICAgICAgICAgICAgc2Vzc2lvblRva2VuOiBlbnYuQVdTX1NFU1NJT05fVE9LRU4sXG4gICAgICAgIH0sXG4gICAgfSlcbiAgICBjb25zdCB1cmkgPSBuZXcgVVJMKGBodHRwczovLyR7c3ViZG9tYWluKHNlcnZpY2UsIGVudi5BV1NfUkVHSU9OKX0uYW1hem9uYXdzLmNvbSR7cGF0aH1gKVxuICAgIGNvbnN0IHF1ZXJ5OiB7IFtrZXk6IHN0cmluZ106IHN0cmluZyB9ID0ge31cbiAgICB1cmkuc2VhcmNoUGFyYW1zLmZvckVhY2goKHZhbHVlLCBrZXkpID0+IHtcbiAgICAgICAgcXVlcnlba2V5XSA9IHZhbHVlXG4gICAgfSlcbiAgICBjb25zdCB7IGhlYWRlcnMgfSA9IGF3YWl0IHNpZ25lci5zaWduKHtcbiAgICAgICAgbWV0aG9kLFxuICAgICAgICBwcm90b2NvbDogJ2h0dHBzOicsXG4gICAgICAgIGhvc3RuYW1lOiB1cmkuaG9zdG5hbWUsXG4gICAgICAgIHBhdGg6IHVyaS5wYXRobmFtZSxcbiAgICAgICAgcXVlcnksXG4gICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICAgIGhvc3Q6IHVyaS5ob3N0bmFtZSxcbiAgICAgICAgICAgICdjb250ZW50LXR5cGUnOiBjb250ZW50VHlwZSxcbiAgICAgICAgICAgIGFjY2VwdDogJ2FwcGxpY2F0aW9uL2pzb24nLFxuICAgICAgICB9LFxuICAgICAgICBib2R5LFxuICAgIH0pXG4gICAgcmV0dXJuIGF3YWl0IGZldGNoKHVyaS50b1N0cmluZygpLCB7XG4gICAgICAgIG1ldGhvZCxcbiAgICAgICAgaGVhZGVycyxcbiAgICAgICAgYm9keTogYm9keSB8fCB1bmRlZmluZWQsXG4gICAgfSlcbn1cblxuZnVuY3Rpb24gc3ViZG9tYWluKHNlcnZpY2U6IHN0cmluZywgcmVnaW9uOiBzdHJpbmcpIHtcbiAgICBzd2l0Y2ggKHNlcnZpY2UpIHtcbiAgICAgICAgY2FzZSAnaWFtJzpcbiAgICAgICAgICAgIHJldHVybiAnaWFtJ1xuICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgcmV0dXJuIGAke3NlcnZpY2V9LiR7cmVnaW9ufWBcbiAgICB9XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiByZXRyeTxUIGV4dGVuZHMgeyB1cmw6IHN0cmluZzsgdGV4dDogKCkgPT4gUHJvbWlzZTxzdHJpbmc+IH0+KFxuICAgIHJlcXVlc3Q6ICgpID0+IFByb21pc2U8VD4sXG4gICAgd2hlbjogKHJlc3BvbnNlOiBUKSA9PiBudW1iZXIgfCB1bmRlZmluZWQsXG4pIHtcbiAgICBmb3IgKGxldCBhdHRlbXB0cyA9IDA7IDsgKythdHRlbXB0cykge1xuICAgICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHJlcXVlc3QoKVxuICAgICAgICBjb25zdCBtYXhSZXRyaWVzID0gd2hlbihyZXNwb25zZSlcbiAgICAgICAgaWYgKG1heFJldHJpZXMgPT09IHVuZGVmaW5lZCB8fCBtYXhSZXRyaWVzIDw9IGF0dGVtcHRzKSB7XG4gICAgICAgICAgICByZXR1cm4gcmVzcG9uc2VcbiAgICAgICAgfVxuICAgICAgICBjb25zb2xlLmxvZyhgcmV0cnlpbmcgIyR7YXR0ZW1wdHMgKyAxfS4uLiAoJHtyZXNwb25zZS51cmx9IC0+ICR7YXdhaXQgcmVzcG9uc2UudGV4dCgpfSlgKVxuICAgICAgICBhd2FpdCBzZXRUaW1lb3V0KDUwMClcbiAgICB9XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBpc05vdEZvdW5kKGU6IHVua25vd24pIHtcbiAgICByZXR1cm4gdGhyb3duSGFzU3RhdHVzKGUsIDQwNClcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGlzQ29uZmxpY3QoZTogdW5rbm93bikge1xuICAgIHJldHVybiB0aHJvd25IYXNTdGF0dXMoZSwgNDA5KVxufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcmV0cnlDb25mbGljdDxUPihmbjogKCkgPT4gUHJvbWlzZTxUPik6IFByb21pc2U8VD4ge1xuICAgIGNvbnN0IGRlYWRsaW5lID0gbmV3IERhdGUoKVxuICAgIGRlYWRsaW5lLnNldFVUQ1NlY29uZHMoZGVhZGxpbmUuZ2V0VVRDU2Vjb25kcygpICsgMzApXG4gICAgZm9yICg7Oykge1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgcmV0dXJuIGF3YWl0IGZuKClcbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgaWYgKCFpc0NvbmZsaWN0KGUpIHx8IG5ldyBEYXRlKCkgPiBkZWFkbGluZSkge1xuICAgICAgICAgICAgICAgIHRocm93IGVcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGF3YWl0IHNldFRpbWVvdXQoKChNYXRoLnJhbmRvbSgpICsgMC41KSAqIDUwMCkgLyAyKVxuICAgICAgICB9XG4gICAgfVxufVxuXG50eXBlIFNvdXJjZURhdGEgPSBzdHJpbmcgfCBBcnJheUJ1ZmZlciB8IEFycmF5QnVmZmVyVmlld1xuXG5jbGFzcyBBd3NIYXNoIHtcbiAgICByZWFkb25seSAjc2VjcmV0PzogU291cmNlRGF0YVxuICAgICNoYXNoOiBSZXR1cm5UeXBlPHR5cGVvZiBjcmVhdGVIYXNoPiB8IFJldHVyblR5cGU8dHlwZW9mIGNyZWF0ZUhtYWM+XG5cbiAgICBjb25zdHJ1Y3RvcihzZWNyZXQ/OiBTb3VyY2VEYXRhKSB7XG4gICAgICAgIHRoaXMuI3NlY3JldCA9IHNlY3JldFxuICAgICAgICB0aGlzLiNoYXNoID0gbWFrZUhhc2godGhpcy4jc2VjcmV0KVxuICAgIH1cblxuICAgIGRpZ2VzdCgpIHtcbiAgICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSh0aGlzLiNoYXNoLmRpZ2VzdCgpKVxuICAgIH1cblxuICAgIHJlc2V0KCkge1xuICAgICAgICB0aGlzLiNoYXNoID0gbWFrZUhhc2godGhpcy4jc2VjcmV0KVxuICAgIH1cblxuICAgIHVwZGF0ZShjaHVuazogVWludDhBcnJheSkge1xuICAgICAgICB0aGlzLiNoYXNoLnVwZGF0ZShuZXcgVWludDhBcnJheShCdWZmZXIuZnJvbShjaHVuaykpKVxuICAgIH1cbn1cblxuZnVuY3Rpb24gbWFrZUhhc2goc2VjcmV0PzogU291cmNlRGF0YSkge1xuICAgIHJldHVybiBzZWNyZXQgPyBjcmVhdGVIbWFjKCdzaGEyNTYnLCBjYXN0U291cmNlRGF0YShzZWNyZXQpKSA6IGNyZWF0ZUhhc2goJ3NoYTI1NicpXG59XG5cbmZ1bmN0aW9uIGNhc3RTb3VyY2VEYXRhKGRhdGE6IFNvdXJjZURhdGEpIHtcbiAgICBpZiAoQnVmZmVyLmlzQnVmZmVyKGRhdGEpKSB7XG4gICAgICAgIHJldHVybiBkYXRhXG4gICAgfVxuICAgIGlmICh0eXBlb2YgZGF0YSA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgcmV0dXJuIEJ1ZmZlci5mcm9tKGRhdGEpXG4gICAgfVxuICAgIGlmIChBcnJheUJ1ZmZlci5pc1ZpZXcoZGF0YSkpIHtcbiAgICAgICAgcmV0dXJuIEJ1ZmZlci5mcm9tKGRhdGEuYnVmZmVyLCBkYXRhLmJ5dGVPZmZzZXQsIGRhdGEuYnl0ZUxlbmd0aClcbiAgICB9XG4gICAgcmV0dXJuIEJ1ZmZlci5mcm9tKGRhdGEpXG59XG4iXX0=