@riddance/deploy
Version:
205 lines • 31.2 kB
JavaScript
import { jsonResponse, 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, AWS_SESSION_TOKEN };
}
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(context, method, service, path, body, target, contentType) {
return awsStringRequest(context, method, service, path, body ? JSON.stringify(body) : '', contentType ?? 'application/json', target);
}
export function awsFormRequest(context, method, service, path, body) {
return awsStringRequest(context, method, service, path, body.toString(), 'application/x-www-form-urlencoded');
}
async function awsStringRequest({ env, log }, method, service, path, body, contentType, target) {
const region = service === 'iam' ? 'us-east-1' : (env.AWS_REGION ?? missing('AWS_REGION'));
const signer = new SignatureV4({
service,
region,
sha256: AwsHash,
credentials: {
accessKeyId: env.AWS_ACCESS_KEY_ID ?? missing('AWS_ACCESS_KEY_ID'),
secretAccessKey: env.AWS_SECRET_ACCESS_KEY ?? missing('AWS_SECRET_ACCESS_KEY'),
sessionToken: env.AWS_SESSION_TOKEN,
},
});
const uri = new URL(`https://${subdomain(service, 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',
...(target && { 'X-Amz-Target': target }),
},
body,
});
for (let retries = 0;; ++retries) {
const response = await fetch(uri.toString(), {
method,
headers,
body: body || undefined,
});
if (response.status === 429 && retries < 5) {
await response.arrayBuffer();
const after = response.headers.get('retry-after');
log.trace(` retrying #${retries + 1}${after ? ` (after ${after})` : ''}...`);
await setTimeout(retryDelay(after));
continue;
}
return response;
}
}
function retryDelay(value, def = 1000, jitter = 1000) {
const extra = Math.round(jitter * Math.random());
if (!value) {
return def + extra;
}
const seconds = Number(value);
if (Number.isFinite(seconds)) {
return seconds * 1000 + extra;
}
const time = new Date(value).getTime();
if (Number.isFinite(time)) {
return Math.max(0, time - Date.now()) + extra;
}
return def + extra;
}
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters
export async function* pages(context, service, path, itemMap, errorMessage) {
for (let next = '';;) {
const page = await jsonResponse(awsRequest(context, 'GET', service, path + next), errorMessage);
for (const item of itemMap(page.items)) {
yield item;
}
if (!page.nextToken) {
break;
}
next = `?nextToken=${encodeURIComponent(page.nextToken)}`;
}
}
function subdomain(service, region) {
switch (service) {
case 'iam':
return 'iam';
default:
return `${service}.${region}`;
}
}
export async function retry(log, request, when) {
for (let retries = 0;; ++retries) {
const response = await request();
const maxRetries = when(response);
if (maxRetries === undefined || maxRetries <= retries) {
return response;
}
log.trace(` retrying #${retries + 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);
}
function missing(what) {
throw new Error(what ? `Missing ${what}.` : 'Missing.');
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGl0ZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbImxpdGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFlBQVksRUFBRSxlQUFlLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQTtBQUMvRCxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sc0JBQXNCLENBQUE7QUFDbEQsT0FBTyxFQUFFLFVBQVUsRUFBRSxVQUFVLEVBQUUsTUFBTSxhQUFhLENBQUE7QUFDcEQsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLGtCQUFrQixDQUFBO0FBQzNDLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxTQUFTLENBQUE7QUFDakMsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLFdBQVcsQ0FBQTtBQUNoQyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sc0JBQXNCLENBQUE7QUFFakQsSUFBSSxpQkFBdUMsQ0FBQTtBQUUzQyxNQUFNLENBQUMsS0FBSyxVQUFVLFdBQVcsQ0FDN0IsTUFBMEIsRUFDMUIsT0FBZTtJQU9mLElBQUksRUFBRSxVQUFVLEVBQUUsaUJBQWlCLEVBQUUscUJBQXFCLEVBQUUsaUJBQWlCLEVBQUUsR0FBRztRQUM5RSxVQUFVLEVBQUUsTUFBTSxJQUFJLE9BQU8sQ0FBQyxHQUFHLENBQUMsVUFBVSxJQUFJLE9BQU8sQ0FBQyxHQUFHLENBQUMsa0JBQWtCO1FBQzlFLGlCQUFpQixFQUFFLE9BQU8sQ0FBQyxHQUFHLENBQUMsaUJBQWlCO1FBQ2hELHFCQUFxQixFQUFFLE9BQU8sQ0FBQyxHQUFHLENBQUMscUJBQXFCO1FBQ3hELGlCQUFpQixFQUFFLE9BQU8sQ0FBQyxHQUFHLENBQUMsaUJBQWlCO0tBQ25ELENBQUE7SUFDRCxJQUFJLFVBQVUsSUFBSSxpQkFBaUIsSUFBSSxxQkFBcUIsRUFBRSxDQUFDO1FBQzNELE9BQU8sRUFBRSxVQUFVLEVBQUUsaUJBQWlCLEVBQUUscUJBQXFCLEVBQUUsaUJBQWlCLEVBQUUsQ0FBQTtJQUN0RixDQUFDO0lBQ0QsTUFBTSxXQUFXLEdBQ2IsaUJBQWlCO1FBQ2pCLENBQ0ksTUFBTSxRQUFRLENBQ1YsT0FBTyxDQUFDLEdBQUcsQ0FBQywyQkFBMkIsSUFBSSxJQUFJLENBQUMsT0FBTyxFQUFFLEVBQUUsTUFBTSxFQUFFLGFBQWEsQ0FBQyxFQUNqRixPQUFPLENBQ1YsQ0FDSjthQUNJLEtBQUssQ0FBQyxJQUFJLENBQUM7YUFDWCxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7YUFDeEIsTUFBTSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQTtJQUN4RCxrREFBa0Q7SUFDbEQsaUJBQWlCLEdBQUcsV0FBVyxDQUFBO0lBRS9CLElBQUksY0FBYyxHQUFHLENBQUMsQ0FBQyxDQUFBO0lBQ3ZCLE1BQU0sT0FBTyxHQUFHLElBQUksT0FBTyxHQUFHLENBQUE7SUFDOUIsY0FBYyxHQUFHLFdBQVcsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLENBQUE7SUFDN0MsSUFBSSxjQUFjLEtBQUssQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUN4QixjQUFjLEdBQUcsV0FBVyxDQUFDLE9BQU8sQ0FBQyxXQUFXLENBQUMsQ0FBQTtJQUNyRCxDQUFDO0lBQ0QsSUFBSSxjQUFjLEtBQUssQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUN4QixNQUFNLElBQUksS0FBSyxDQUFDLG9CQUFvQixDQUFDLENBQUE7SUFDekMsQ0FBQztJQUNELE1BQU0sWUFBWSxHQUFHLFdBQVcsQ0FBQyxTQUFTLENBQ3RDLENBQUMsSUFBSSxFQUFFLEVBQUUsRUFBRSxFQUFFLENBQUMsRUFBRSxHQUFHLGNBQWMsSUFBSSxJQUFJLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQyxDQUM1RCxDQUFBO0lBQ0QsTUFBTSxZQUFZLEdBQUcsV0FBVztTQUMzQixLQUFLLENBQUMsY0FBYyxHQUFHLENBQUMsRUFBRSxZQUFZLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsWUFBWSxDQUFDO1NBQ3pFLEdBQUcsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7U0FDNUIsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLElBQUksRUFBRSxFQUFFLENBQUMsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUE7SUFDNUMsVUFBVSxLQUFLLFlBQVksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLEtBQUssUUFBUSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQTtJQUM5RCxpQkFBaUIsR0FBRyxZQUFZLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxLQUFLLG1CQUFtQixDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQTtJQUM5RSxxQkFBcUIsR0FBRyxZQUFZLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxLQUFLLHVCQUF1QixDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQTtJQUN0RixpQkFBaUIsR0FBRyxZQUFZLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxLQUFLLG1CQUFtQixDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQTtJQUM5RSxJQUFJLENBQUMsVUFBVSxJQUFJLENBQUMsaUJBQWlCLElBQUksQ0FBQyxxQkFBcUIsRUFBRSxDQUFDO1FBQzlELE1BQU0sSUFBSSxLQUFLLENBQUMsa0NBQWtDLENBQUMsQ0FBQTtJQUN2RCxDQUFDO0lBQ0QsT0FBTyxFQUFFLFVBQVUsRUFBRSxpQkFBaUIsRUFBRSxx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LE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUE7SUFDNUIsQ0FBQztJQUNELElBQUksV0FBVyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO1FBQzNCLE9BQU8sTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxVQUFVLEVBQUUsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFBO0lBQ3JFLENBQUM7SUFDRCxPQUFPLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUE7QUFDNUIsQ0FBQztBQUVELFNBQVMsT0FBTyxDQUFDLElBQWE7SUFDMUIsTUFBTSxJQUFJLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLFdBQVcsSUFBSSxHQUFHLENBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxDQUFBO0FBQzNELENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBqc29uUmVzcG9uc2UsIHRocm93bkhhc1N0YXR1cyB9IGZyb20gJ0ByaWRkYW5jZS9mZXRjaCdcbmltcG9ydCB7IFNpZ25hdHVyZVY0IH0gZnJvbSAnQHNtaXRoeS9zaWduYXR1cmUtdjQnXG5pbXBvcnQgeyBjcmVhdGVIYXNoLCBjcmVhdGVIbWFjIH0gZnJvbSAnbm9kZTpjcnlwdG8nXG5pbXBvcnQgeyByZWFkRmlsZSB9IGZyb20gJ25vZGU6ZnMvcHJvbWlzZXMnXG5pbXBvcnQgeyBob21lZGlyIH0gZnJvbSAnbm9kZTpvcydcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdub2RlOnBhdGgnXG5pbXBvcnQgeyBzZXRUaW1lb3V0IH0gZnJvbSAnbm9kZTp0aW1lcnMvcHJvbWlzZXMnXG5cbmxldCBjYWNoZWRDb25maWdMaW5lczogc3RyaW5nW10gfCB1bmRlZmluZWRcblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGxvY2FsQXdzRW52KFxuICAgIHJlZ2lvbjogc3RyaW5nIHwgdW5kZWZpbmVkLFxuICAgIHByb2ZpbGU6IHN0cmluZyxcbik6IFByb21pc2U8e1xuICAgIEFXU19SRUdJT046IHN0cmluZ1xuICAgIEFXU19BQ0NFU1NfS0VZX0lEOiBzdHJpbmdcbiAgICBBV1NfU0VDUkVUX0FDQ0VTU19LRVk6IHN0cmluZ1xuICAgIEFXU19TRVNTSU9OX1RPS0VOPzogc3RyaW5nXG59PiB7XG4gICAgbGV0IHsgQVdTX1JFR0lPTiwgQVdTX0FDQ0VTU19LRVlfSUQsIEFXU19TRUNSRVRfQUNDRVNTX0tFWSwgQVdTX1NFU1NJT05fVE9LRU4gfSA9IHtcbiAgICAgICAgQVdTX1JFR0lPTjogcmVnaW9uID8/IHByb2Nlc3MuZW52LkFXU19SRUdJT04gPz8gcHJvY2Vzcy5lbnYuQVdTX0RFRkFVTFRfUkVHSU9OLFxuICAgICAgICBBV1NfQUNDRVNTX0tFWV9JRDogcHJvY2Vzcy5lbnYuQVdTX0FDQ0VTU19LRVlfSUQsXG4gICAgICAgIEFXU19TRUNSRVRfQUNDRVNTX0tFWTogcHJvY2Vzcy5lbnYuQVdTX1NFQ1JFVF9BQ0NFU1NfS0VZLFxuICAgICAgICBBV1NfU0VTU0lPTl9UT0tFTjogcHJvY2Vzcy5lbnYuQVdTX1NFU1NJT05fVE9LRU4sXG4gICAgfVxuICAgIGlmIChBV1NfUkVHSU9OICYmIEFXU19BQ0NFU1NfS0VZX0lEICYmIEFXU19TRUNSRVRfQUNDRVNTX0tFWSkge1xuICAgICAgICByZXR1cm4geyBBV1NfUkVHSU9OLCBBV1NfQUNDRVNTX0tFWV9JRCwgQVdTX1NFQ1JFVF9BQ0NFU1NfS0VZLCBBV1NfU0VTU0lPTl9UT0tFTiB9XG4gICAgfVxuICAgIGNvbnN0IGNvbmZpZ0xpbmVzID1cbiAgICAgICAgY2FjaGVkQ29uZmlnTGluZXMgPz9cbiAgICAgICAgKFxuICAgICAgICAgICAgYXdhaXQgcmVhZEZpbGUoXG4gICAgICAgICAgICAgICAgcHJvY2Vzcy5lbnYuQVdTX1NIQVJFRF9DUkVERU5USUFMU19GSUxFID8/IGpvaW4oaG9tZWRpcigpLCAnLmF3cycsICdjcmVkZW50aWFscycpLFxuICAgICAgICAgICAgICAgICdhc2NpaScsXG4gICAgICAgICAgICApXG4gICAgICAgIClcbiAgICAgICAgICAgIC5zcGxpdCgnXFxuJylcbiAgICAgICAgICAgIC5tYXAobGluZSA9PiBsaW5lLnRyaW0oKSlcbiAgICAgICAgICAgIC5maWx0ZXIobGluZSA9PiAhIWxpbmUgJiYgIWxpbmUuc3RhcnRzV2l0aCgnIycpKVxuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSByZXF1aXJlLWF0b21pYy11cGRhdGVzXG4gICAgY2FjaGVkQ29uZmlnTGluZXMgPSBjb25maWdMaW5lc1xuXG4gICAgbGV0IHNlY3Rpb25CZWdpbkl4ID0gLTFcbiAgICBjb25zdCBzZWN0aW9uID0gYFske3Byb2ZpbGV9XWBcbiAgICBzZWN0aW9uQmVnaW5JeCA9IGNvbmZpZ0xpbmVzLmluZGV4T2Yoc2VjdGlvbilcbiAgICBpZiAoc2VjdGlvbkJlZ2luSXggPT09IC0xKSB7XG4gICAgICAgIHNlY3Rpb25CZWdpbkl4ID0gY29uZmlnTGluZXMuaW5kZXhPZignW2RlZmF1bHRdJylcbiAgICB9XG4gICAgaWYgKHNlY3Rpb25CZWdpbkl4ID09PSAtMSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1NlY3Rpb24gbm90IGZvdW5kLicpXG4gICAgfVxuICAgIGNvbnN0IHNlY3Rpb25FbmRJeCA9IGNvbmZpZ0xpbmVzLmZpbmRJbmRleChcbiAgICAgICAgKGxpbmUsIGl4KSA9PiBpeCA+IHNlY3Rpb25CZWdpbkl4ICYmIGxpbmUuc3RhcnRzV2l0aCgnWycpLFxuICAgIClcbiAgICBjb25zdCBzZWN0aW9uTGluZXMgPSBjb25maWdMaW5lc1xuICAgICAgICAuc2xpY2Uoc2VjdGlvbkJlZ2luSXggKyAxLCBzZWN0aW9uRW5kSXggPT09IC0xID8gdW5kZWZpbmVkIDogc2VjdGlvbkVuZEl4KVxuICAgICAgICAubWFwKGxpbmUgPT4gbGluZS5zcGxpdCgnPScpKVxuICAgICAgICAubWFwKChbaywgdl0pID0+IFtrPy50cmltKCksIHY/LnRyaW0oKV0pXG4gICAgQVdTX1JFR0lPTiA/Pz0gc2VjdGlvbkxpbmVzLmZpbmQoKFtrXSkgPT4gayA9PT0gJ3JlZ2lvbicpPy5bMV1cbiAgICBBV1NfQUNDRVNTX0tFWV9JRCA9IHNlY3Rpb25MaW5lcy5maW5kKChba10pID0+IGsgPT09ICdhd3NfYWNjZXNzX2tleV9pZCcpPy5bMV1cbiAgICBBV1NfU0VDUkVUX0FDQ0VTU19LRVkgPSBzZWN0aW9uTGluZXMuZmluZCgoW2tdKSA9PiBrID09PSAnYXdzX3NlY3JldF9hY2Nlc3Nfa2V5Jyk/LlsxXVxuICAgIEFXU19TRVNTSU9OX1RPS0VOID0gc2VjdGlvbkxpbmVzLmZpbmQoKFtrXSkgPT4gayA9PT0gJ2F3c19zZXNzaW9uX3Rva2VuJyk/LlsxXVxuICAgIGlmICghQVdTX1JFR0lPTiB8fCAhQVdTX0FDQ0VTU19LRVlfSUQgfHwgIUFXU19TRUNSRVRfQUNDRVNTX0tFWSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0luY29tcGxldGUgQVdTIGNyZWRlbnRpYWxzIGZpbGUuJylcbiAgICB9XG4gICAgcmV0dXJuIHsgQVdTX1JFR0lPTiwgQVdTX0FDQ0VTU19LRVlfSUQsIEFXU19TRUNSRVRfQUNDRVNTX0tFWSwgQVdTX1NFU1NJT05fVE9LRU4gfVxufVxuXG5leHBvcnQgdHlwZSBDb250ZXh0ID0ge1xuICAgIGxvZzogeyB0cmFjZTogKG1lc3NhZ2U6IHN0cmluZykgPT4gdm9pZCB9XG4gICAgZW52OiB7IFtrZXk6IHN0cmluZ106IHN0cmluZyB8IHVuZGVmaW5lZCB9XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBhd3NSZXF1ZXN0KFxuICAgIGNvbnRleHQ6IENvbnRleHQsXG4gICAgbWV0aG9kOiBzdHJpbmcsXG4gICAgc2VydmljZTogc3RyaW5nLFxuICAgIHBhdGg6IHN0cmluZyxcbiAgICBib2R5PzogdW5rbm93bixcbiAgICB0YXJnZXQ/OiBzdHJpbmcsXG4gICAgY29udGVudFR5cGU/OiBzdHJpbmcsXG4pIHtcbiAgICByZXR1cm4gYXdzU3RyaW5nUmVxdWVzdChcbiAgICAgICAgY29udGV4dCxcbiAgICAgICAgbWV0aG9kLFxuICAgICAgICBzZXJ2aWNlLFxuICAgICAgICBwYXRoLFxuICAgICAgICBib2R5ID8gSlNPTi5zdHJpbmdpZnkoYm9keSkgOiAnJyxcbiAgICAgICAgY29udGVudFR5cGUgPz8gJ2FwcGxpY2F0aW9uL2pzb24nLFxuICAgICAgICB0YXJnZXQsXG4gICAgKVxufVxuXG5leHBvcnQgZnVuY3Rpb24gYXdzRm9ybVJlcXVlc3QoXG4gICAgY29udGV4dDogQ29udGV4dCxcbiAgICBtZXRob2Q6IHN0cmluZyxcbiAgICBzZXJ2aWNlOiBzdHJpbmcsXG4gICAgcGF0aDogc3RyaW5nLFxuICAgIGJvZHk6IFVSTFNlYXJjaFBhcmFtcyxcbikge1xuICAgIHJldHVybiBhd3NTdHJpbmdSZXF1ZXN0KFxuICAgICAgICBjb250ZXh0LFxuICAgICAgICBtZXRob2QsXG4gICAgICAgIHNlcnZpY2UsXG4gICAgICAgIHBhdGgsXG4gICAgICAgIGJvZHkudG9TdHJpbmcoKSxcbiAgICAgICAgJ2FwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZCcsXG4gICAgKVxufVxuXG5hc3luYyBmdW5jdGlvbiBhd3NTdHJpbmdSZXF1ZXN0KFxuICAgIHsgZW52LCBsb2cgfTogQ29udGV4dCxcbiAgICBtZXRob2Q6IHN0cmluZyxcbiAgICBzZXJ2aWNlOiBzdHJpbmcsXG4gICAgcGF0aDogc3RyaW5nLFxuICAgIGJvZHk6IHN0cmluZyxcbiAgICBjb250ZW50VHlwZTogc3RyaW5nLFxuICAgIHRhcmdldD86IHN0cmluZyxcbikge1xuICAgIGNvbnN0IHJlZ2lvbiA9IHNlcnZpY2UgPT09ICdpYW0nID8gJ3VzLWVhc3QtMScgOiAoZW52LkFXU19SRUdJT04gPz8gbWlzc2luZygnQVdTX1JFR0lPTicpKVxuICAgIGNvbnN0IHNpZ25lciA9IG5ldyBTaWduYXR1cmVWNCh7XG4gICAgICAgIHNlcnZpY2UsXG4gICAgICAgIHJlZ2lvbixcbiAgICAgICAgc2hhMjU2OiBBd3NIYXNoLFxuICAgICAgICBjcmVkZW50aWFsczoge1xuICAgICAgICAgICAgYWNjZXNzS2V5SWQ6IGVudi5BV1NfQUNDRVNTX0tFWV9JRCA/PyBtaXNzaW5nKCdBV1NfQUNDRVNTX0tFWV9JRCcpLFxuICAgICAgICAgICAgc2VjcmV0QWNjZXNzS2V5OiBlbnYuQVdTX1NFQ1JFVF9BQ0NFU1NfS0VZID8/IG1pc3NpbmcoJ0FXU19TRUNSRVRfQUNDRVNTX0tFWScpLFxuICAgICAgICAgICAgc2Vzc2lvblRva2VuOiBlbnYuQVdTX1NFU1NJT05fVE9LRU4sXG4gICAgICAgIH0sXG4gICAgfSlcbiAgICBjb25zdCB1cmkgPSBuZXcgVVJMKGBodHRwczovLyR7c3ViZG9tYWluKHNlcnZpY2UsIHJlZ2lvbil9LmFtYXpvbmF3cy5jb20ke3BhdGh9YClcbiAgICBjb25zdCBxdWVyeTogeyBba2V5OiBzdHJpbmddOiBzdHJpbmcgfSA9IHt9XG4gICAgdXJpLnNlYXJjaFBhcmFtcy5mb3JFYWNoKCh2YWx1ZSwga2V5KSA9PiB7XG4gICAgICAgIHF1ZXJ5W2tleV0gPSB2YWx1ZVxuICAgIH0pXG4gICAgY29uc3QgeyBoZWFkZXJzIH0gPSBhd2FpdCBzaWduZXIuc2lnbih7XG4gICAgICAgIG1ldGhvZCxcbiAgICAgICAgcHJvdG9jb2w6ICdodHRwczonLFxuICAgICAgICBob3N0bmFtZTogdXJpLmhvc3RuYW1lLFxuICAgICAgICBwYXRoOiB1cmkucGF0aG5hbWUsXG4gICAgICAgIHF1ZXJ5LFxuICAgICAgICBoZWFkZXJzOiB7XG4gICAgICAgICAgICBob3N0OiB1cmkuaG9zdG5hbWUsXG4gICAgICAgICAgICAnY29udGVudC10eXBlJzogY29udGVudFR5cGUsXG4gICAgICAgICAgICBhY2NlcHQ6ICdhcHBsaWNhdGlvbi9qc29uJyxcbiAgICAgICAgICAgIC4uLih0YXJnZXQgJiYgeyAnWC1BbXotVGFyZ2V0JzogdGFyZ2V0IH0pLFxuICAgICAgICB9LFxuICAgICAgICBib2R5LFxuICAgIH0pXG4gICAgZm9yIChsZXQgcmV0cmllcyA9IDA7IDsgKytyZXRyaWVzKSB7XG4gICAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2godXJpLnRvU3RyaW5nKCksIHtcbiAgICAgICAgICAgIG1ldGhvZCxcbiAgICAgICAgICAgIGhlYWRlcnMsXG4gICAgICAgICAgICBib2R5OiBib2R5IHx8IHVuZGVmaW5lZCxcbiAgICAgICAgfSlcbiAgICAgICAgaWYgKHJlc3BvbnNlLnN0YXR1cyA9PT0gNDI5ICYmIHJldHJpZXMgPCA1KSB7XG4gICAgICAgICAgICBhd2FpdCByZXNwb25zZS5hcnJheUJ1ZmZlcigpXG4gICAgICAgICAgICBjb25zdCBhZnRlciA9IHJlc3BvbnNlLmhlYWRlcnMuZ2V0KCdyZXRyeS1hZnRlcicpXG4gICAgICAgICAgICBsb2cudHJhY2UoYCAgcmV0cnlpbmcgIyR7cmV0cmllcyArIDF9JHthZnRlciA/IGAgKGFmdGVyICR7YWZ0ZXJ9KWAgOiAnJ30uLi5gKVxuICAgICAgICAgICAgYXdhaXQgc2V0VGltZW91dChyZXRyeURlbGF5KGFmdGVyKSlcbiAgICAgICAgICAgIGNvbnRpbnVlXG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHJlc3BvbnNlXG4gICAgfVxufVxuXG5mdW5jdGlvbiByZXRyeURlbGF5KHZhbHVlOiBzdHJpbmcgfCBudWxsLCBkZWYgPSAxMDAwLCBqaXR0ZXIgPSAxMDAwKSB7XG4gICAgY29uc3QgZXh0cmEgPSBNYXRoLnJvdW5kKGppdHRlciAqIE1hdGgucmFuZG9tKCkpXG4gICAgaWYgKCF2YWx1ZSkge1xuICAgICAgICByZXR1cm4gZGVmICsgZXh0cmFcbiAgICB9XG4gICAgY29uc3Qgc2Vjb25kcyA9IE51bWJlcih2YWx1ZSlcbiAgICBpZiAoTnVtYmVyLmlzRmluaXRlKHNlY29uZHMpKSB7XG4gICAgICAgIHJldHVybiBzZWNvbmRzICogMTAwMCArIGV4dHJhXG4gICAgfVxuICAgIGNvbnN0IHRpbWUgPSBuZXcgRGF0ZSh2YWx1ZSkuZ2V0VGltZSgpXG4gICAgaWYgKE51bWJlci5pc0Zpbml0ZSh0aW1lKSkge1xuICAgICAgICByZXR1cm4gTWF0aC5tYXgoMCwgdGltZSAtIERhdGUubm93KCkpICsgZXh0cmFcbiAgICB9XG4gICAgcmV0dXJuIGRlZiArIGV4dHJhXG59XG5cbi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW5uZWNlc3NhcnktdHlwZS1wYXJhbWV0ZXJzXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24qIHBhZ2VzPFQsIFM+KFxuICAgIGNvbnRleHQ6IENvbnRleHQsXG4gICAgc2VydmljZTogc3RyaW5nLFxuICAgIHBhdGg6IHN0cmluZyxcbiAgICBpdGVtTWFwOiAoaXRlbXM6IFRbXSkgPT4gU1tdLFxuICAgIGVycm9yTWVzc2FnZTogc3RyaW5nLFxuKSB7XG4gICAgZm9yIChsZXQgbmV4dCA9ICcnOyA7ICkge1xuICAgICAgICBjb25zdCBwYWdlID0gYXdhaXQganNvblJlc3BvbnNlPHsgaXRlbXM6IFRbXTsgbmV4dFRva2VuPzogc3RyaW5nIH0+KFxuICAgICAgICAgICAgYXdzUmVxdWVzdChjb250ZXh0LCAnR0VUJywgc2VydmljZSwgcGF0aCArIG5leHQpLFxuICAgICAgICAgICAgZXJyb3JNZXNzYWdlLFxuICAgICAgICApXG4gICAgICAgIGZvciAoY29uc3QgaXRlbSBvZiBpdGVtTWFwKHBhZ2UuaXRlbXMpKSB7XG4gICAgICAgICAgICB5aWVsZCBpdGVtXG4gICAgICAgIH1cbiAgICAgICAgaWYgKCFwYWdlLm5leHRUb2tlbikge1xuICAgICAgICAgICAgYnJlYWtcbiAgICAgICAgfVxuICAgICAgICBuZXh0ID0gYD9uZXh0VG9rZW49JHtlbmNvZGVVUklDb21wb25lbnQocGFnZS5uZXh0VG9rZW4pfWBcbiAgICB9XG59XG5cbmZ1bmN0aW9uIHN1YmRvbWFpbihzZXJ2aWNlOiBzdHJpbmcsIHJlZ2lvbjogc3RyaW5nKSB7XG4gICAgc3dpdGNoIChzZXJ2aWNlKSB7XG4gICAgICAgIGNhc2UgJ2lhbSc6XG4gICAgICAgICAgICByZXR1cm4gJ2lhbSdcbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgIHJldHVybiBgJHtzZXJ2aWNlfS4ke3JlZ2lvbn1gXG4gICAgfVxufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcmV0cnk8VCBleHRlbmRzIHsgdXJsOiBzdHJpbmc7IHRleHQ6ICgpID0+IFByb21pc2U8c3RyaW5nPiB9PihcbiAgICBsb2c6IENvbnRleHRbJ2xvZyddLFxuICAgIHJlcXVlc3Q6ICgpID0+IFByb21pc2U8VD4sXG4gICAgd2hlbjogKHJlc3BvbnNlOiBUKSA9PiBudW1iZXIgfCB1bmRlZmluZWQsXG4pIHtcbiAgICBmb3IgKGxldCByZXRyaWVzID0gMDsgOyArK3JldHJpZXMpIHtcbiAgICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCByZXF1ZXN0KClcbiAgICAgICAgY29uc3QgbWF4UmV0cmllcyA9IHdoZW4ocmVzcG9uc2UpXG4gICAgICAgIGlmIChtYXhSZXRyaWVzID09PSB1bmRlZmluZWQgfHwgbWF4UmV0cmllcyA8PSByZXRyaWVzKSB7XG4gICAgICAgICAgICByZXR1cm4gcmVzcG9uc2VcbiAgICAgICAgfVxuICAgICAgICBsb2cudHJhY2UoYCAgcmV0cnlpbmcgIyR7cmV0cmllcyArIDF9Li4uICgke3Jlc3BvbnNlLnVybH0gLT4gJHthd2FpdCByZXNwb25zZS50ZXh0KCl9KWApXG4gICAgICAgIGF3YWl0IHNldFRpbWVvdXQoNTAwKVxuICAgIH1cbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGlzTm90Rm91bmQoZTogdW5rbm93bikge1xuICAgIHJldHVybiB0aHJvd25IYXNTdGF0dXMoZSwgNDA0KVxufVxuXG5leHBvcnQgZnVuY3Rpb24gaXNDb25mbGljdChlOiB1bmtub3duKSB7XG4gICAgcmV0dXJuIHRocm93bkhhc1N0YXR1cyhlLCA0MDkpXG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiByZXRyeUNvbmZsaWN0PFQ+KGZuOiAoKSA9PiBQcm9taXNlPFQ+KTogUHJvbWlzZTxUPiB7XG4gICAgY29uc3QgZGVhZGxpbmUgPSBuZXcgRGF0ZSgpXG4gICAgZGVhZGxpbmUuc2V0VVRDU2Vjb25kcyhkZWFkbGluZS5nZXRVVENTZWNvbmRzKCkgKyAzMClcbiAgICBmb3IgKDs7KSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICByZXR1cm4gYXdhaXQgZm4oKVxuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICBpZiAoIWlzQ29uZmxpY3QoZSkgfHwgbmV3IERhdGUoKSA+IGRlYWRsaW5lKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgZVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgYXdhaXQgc2V0VGltZW91dCgoKE1hdGgucmFuZG9tKCkgKyAwLjUpICogNTAwKSAvIDIpXG4gICAgICAgIH1cbiAgICB9XG59XG5cbnR5cGUgU291cmNlRGF0YSA9IHN0cmluZyB8IEFycmF5QnVmZmVyIHwgQXJyYXlCdWZmZXJWaWV3XG5cbmNsYXNzIEF3c0hhc2gge1xuICAgIHJlYWRvbmx5ICNzZWNyZXQ/OiBTb3VyY2VEYXRhXG4gICAgI2hhc2g6IFJldHVyblR5cGU8dHlwZW9mIGNyZWF0ZUhhc2g+IHwgUmV0dXJuVHlwZTx0eXBlb2YgY3JlYXRlSG1hYz5cblxuICAgIGNvbnN0cnVjdG9yKHNlY3JldD86IFNvdXJjZURhdGEpIHtcbiAgICAgICAgdGhpcy4jc2VjcmV0ID0gc2VjcmV0XG4gICAgICAgIHRoaXMuI2hhc2ggPSBtYWtlSGFzaCh0aGlzLiNzZWNyZXQpXG4gICAgfVxuXG4gICAgZGlnZXN0KCkge1xuICAgICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHRoaXMuI2hhc2guZGlnZXN0KCkpXG4gICAgfVxuXG4gICAgcmVzZXQoKSB7XG4gICAgICAgIHRoaXMuI2hhc2ggPSBtYWtlSGFzaCh0aGlzLiNzZWNyZXQpXG4gICAgfVxuXG4gICAgdXBkYXRlKGNodW5rOiBVaW50OEFycmF5KSB7XG4gICAgICAgIHRoaXMuI2hhc2gudXBkYXRlKG5ldyBVaW50OEFycmF5KEJ1ZmZlci5mcm9tKGNodW5rKSkpXG4gICAgfVxufVxuXG5mdW5jdGlvbiBtYWtlSGFzaChzZWNyZXQ/OiBTb3VyY2VEYXRhKSB7XG4gICAgcmV0dXJuIHNlY3JldCA/IGNyZWF0ZUhtYWMoJ3NoYTI1NicsIGNhc3RTb3VyY2VEYXRhKHNlY3JldCkpIDogY3JlYXRlSGFzaCgnc2hhMjU2Jylcbn1cblxuZnVuY3Rpb24gY2FzdFNvdXJjZURhdGEoZGF0YTogU291cmNlRGF0YSkge1xuICAgIGlmIChCdWZmZXIuaXNCdWZmZXIoZGF0YSkpIHtcbiAgICAgICAgcmV0dXJuIGRhdGFcbiAgICB9XG4gICAgaWYgKHR5cGVvZiBkYXRhID09PSAnc3RyaW5nJykge1xuICAgICAgICByZXR1cm4gQnVmZmVyLmZyb20oZGF0YSlcbiAgICB9XG4gICAgaWYgKEFycmF5QnVmZmVyLmlzVmlldyhkYXRhKSkge1xuICAgICAgICByZXR1cm4gQnVmZmVyLmZyb20oZGF0YS5idWZmZXIsIGRhdGEuYnl0ZU9mZnNldCwgZGF0YS5ieXRlTGVuZ3RoKVxuICAgIH1cbiAgICByZXR1cm4gQnVmZmVyLmZyb20oZGF0YSlcbn1cblxuZnVuY3Rpb24gbWlzc2luZyh3aGF0Pzogc3RyaW5nKTogbmV2ZXIge1xuICAgIHRocm93IG5ldyBFcnJvcih3aGF0ID8gYE1pc3NpbmcgJHt3aGF0fS5gIDogJ01pc3NpbmcuJylcbn1cbiJdfQ==