@riddance/deploy
Version:
153 lines • 29.5 kB
JavaScript
import { jsonResponse, okResponse } from '@riddance/fetch';
import { resolveCpu } from '@riddance/host/reflect';
import JSZip from 'jszip';
import { createHash } from 'node:crypto';
import { isDeepStrictEqual } from 'node:util';
import { compare } from '../diff.js';
import { awsRequest, retry, retryConflict } from '../lite.js';
export async function syncLambda(env, prefix, currentFunctions, reflection, environment, role, code) {
const zipped = Object.fromEntries(await Promise.all(Object.entries(code).map(async ([name, c]) => [name, await zip(c)])));
const { missing, surplus, existing } = compare(reflection.http, currentFunctions);
const created = await Promise.all(missing.map(fn => createLambda(env, prefix, fn.name, reflection.name, role, fn.config, environment, zipped[fn.name])));
await Promise.all(surplus.map(fn => deleteLambda(env, prefix, reflection.name, fn.name)));
await Promise.all(existing.map(awsFn => updateLambda(env, prefix, awsFn.name, reflection.name, role, reflection.http.find(fn => fn.name === awsFn.name)?.config, awsFn, environment, zipped[awsFn.name])));
return [...currentFunctions.map(fn => ({ id: fn.id, name: fn.name })), ...created];
}
async function zip(code) {
const buffer = await new JSZip()
.file('index.js', code, {
compression: 'DEFLATE',
compressionOptions: { level: 9 },
date: new Date(2022, 8, 1),
})
.generateAsync({ type: 'nodebuffer' });
return {
zipped: buffer.toString('base64'),
size: buffer.length < 1024
? `${buffer.length} bytes`
: `${Math.ceil(buffer.length / 102.4) / 10} KiB`,
sha256: createHash('sha256').update(buffer).digest('base64'),
};
}
export async function getFunctions(env, prefix, service) {
const funcs = [];
let marker = '';
for (;;) {
const page = await jsonResponse(awsRequest(env, 'GET', 'lambda', `/2015-03-31/functions/?${marker}`), 'Error listing functions');
funcs.push(...page.Functions);
if (page.NextMarker === null) {
break;
}
marker = `Marker=${encodeURIComponent(page.NextMarker)}`;
}
const fnPrefix = `${prefix}-${service}-`.toLowerCase();
return funcs
.filter(fn => fn.FunctionName.startsWith(fnPrefix))
.map(fn => ({
id: fn.FunctionArn,
name: fn.FunctionName.slice(fnPrefix.length),
runtime: fn.Runtime,
memory: fn.MemorySize,
timeout: fn.Timeout,
env: fn.Environment?.Variables ?? {},
cpus: fn.Architectures,
hash: fn.CodeSha256,
size: fn.CodeSize < 1024
? `${fn.CodeSize} bytes`
: `${Math.ceil(fn.CodeSize / 102.4) / 10} KiB`,
}));
}
async function createLambda(env, prefix, name, service, role, config, environment, code) {
if (!code) {
throw new Error('No code');
}
console.log(`creating lambda ${name} (${code.size})`);
const response = await jsonResponse(retry(() => awsRequest(env, 'POST', 'lambda', '/2015-03-31/functions', {
FunctionName: `${prefix}-${service}-${name}`,
Code: { ZipFile: code.zipped },
PackageType: 'Zip',
Architectures: lambdaArchitecture(config),
...lambdaConfig(config, role, environment),
Tags: {
framework: 'riddance',
environment: prefix,
service,
},
}), r => (r.status === 400 ? 25 : undefined)), 'Error creating lambda ' + name);
return { name, id: response.FunctionArn };
}
async function updateLambda(env, prefix, name, service, role, config, awsFn, environment, code) {
if (!code) {
throw new Error('No code');
}
if (!config) {
throw new Error('No config');
}
const cpus = lambdaArchitecture(config);
if (!isDeepStrictEqual({ cpus, hash: code.sha256 }, { cpus: awsFn.cpus, hash: awsFn.hash })) {
console.log(`updating code for lambda ${name} (${awsFn.size} -> ${code.size})`);
await okResponse(awsRequest(env, 'PUT', 'lambda', `/2015-03-31/functions/${prefix}-${service}-${name}/code`, {
ZipFile: code.zipped,
Architectures: cpus,
}), 'Error updating code for lambda ' + name);
}
const awsConfig = lambdaConfig(config, role, environment);
if (!isDeepStrictEqual({
env: awsConfig.Environment.Variables,
memory: awsConfig.MemorySize,
timeout: awsConfig.Timeout,
runtime: awsConfig.Runtime,
}, {
env: awsFn.env,
memory: awsFn.memory,
timeout: awsFn.timeout,
runtime: awsFn.runtime,
})) {
console.log('updating config for lambda ' + name);
await retryConflict(() => okResponse(awsRequest(env, 'PUT', 'lambda', `/2015-03-31/functions/${prefix}-${service}-${name}/configuration`, awsConfig), 'Error updating config for lambda ' + name));
}
}
async function deleteLambda(env, prefix, service, name) {
console.log('deleting lambda ' + name);
await okResponse(awsRequest(env, 'DELETE', 'lambda', `/2015-03-31/functions/${prefix}-${service}-${name}`), 'Error deleting lambda ' + name);
}
function lambdaConfig(config, role, environment) {
return {
Role: role,
Runtime: getRuntime(config),
Handler: 'index.handler',
Timeout: config.timeout ?? 15,
MemorySize: config.compute === 'high' || config.memory === 'high' ? 3008 : 128,
TracingConfig: {
Mode: 'PassThrough',
},
Environment: {
Variables: environment,
},
};
}
function getRuntime(config) {
switch (config.nodeVersion?.slice(0, 4)) {
case '>=20':
return 'nodejs20.x';
case '>=18':
return 'nodejs18.x';
default:
throw new Error('Unsupported engine; please specify either "node": ">=18" or "node": ">=20" as an engine in your package.json.');
}
}
function lambdaArchitecture(config) {
switch (resolveCpu(config, config.compute === 'high'
? ['x64', 'x32', 'arm64', 'arm']
: ['arm64', 'arm', 'x64', 'x32'])) {
case 'arm64':
case 'arm':
return ['arm64'];
case 'x64':
case 'x32':
return ['x86_64'];
default:
throw new Error('Unsupported CPUs: ' + (config.cpus?.join(', ') ?? ''));
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGFtYmRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsibGFtYmRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxZQUFZLEVBQUUsVUFBVSxFQUFFLE1BQU0saUJBQWlCLENBQUE7QUFDMUQsT0FBTyxFQUF3QyxVQUFVLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQTtBQUN6RixPQUFPLEtBQUssTUFBTSxPQUFPLENBQUE7QUFDekIsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGFBQWEsQ0FBQTtBQUN4QyxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxXQUFXLENBQUE7QUFDN0MsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLFlBQVksQ0FBQTtBQUNwQyxPQUFPLEVBQVksVUFBVSxFQUFFLEtBQUssRUFBRSxhQUFhLEVBQUUsTUFBTSxZQUFZLENBQUE7QUFFdkUsTUFBTSxDQUFDLEtBQUssVUFBVSxVQUFVLENBQzVCLEdBQWEsRUFDYixNQUFjLEVBQ2QsZ0JBQW1DLEVBQ25DLFVBQXNCLEVBQ3RCLFdBQXNDLEVBQ3RDLElBQVksRUFDWixJQUFnQztJQUVoQyxNQUFNLE1BQU0sR0FBRyxNQUFNLENBQUMsV0FBVyxDQUM3QixNQUFNLE9BQU8sQ0FBQyxHQUFHLENBQ2IsTUFBTSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxHQUFHLENBQ3BCLEtBQUssRUFBRSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsRUFBRSxFQUFFLENBQ2hCLENBQUMsSUFBSSxFQUFFLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUE4QyxDQUN4RSxDQUNKLENBQ0osQ0FBQTtJQUVELE1BQU0sRUFBRSxPQUFPLEVBQUUsT0FBTyxFQUFFLFFBQVEsRUFBRSxHQUFHLE9BQU8sQ0FBQyxVQUFVLENBQUMsSUFBSSxFQUFFLGdCQUFnQixDQUFDLENBQUE7SUFDakYsTUFBTSxPQUFPLEdBQUcsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUM3QixPQUFPLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQ2IsWUFBWSxDQUNSLEdBQUcsRUFDSCxNQUFNLEVBQ04sRUFBRSxDQUFDLElBQUksRUFDUCxVQUFVLENBQUMsSUFBSSxFQUNmLElBQUksRUFDSixFQUFFLENBQUMsTUFBTSxFQUNULFdBQVcsRUFDWCxNQUFNLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUNsQixDQUNKLENBQ0osQ0FBQTtJQUNELE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsWUFBWSxDQUFDLEdBQUcsRUFBRSxNQUFNLEVBQUUsVUFBVSxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFBO0lBQ3pGLE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FDYixRQUFRLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQ2pCLFlBQVksQ0FDUixHQUFHLEVBQ0gsTUFBTSxFQUNOLEtBQUssQ0FBQyxJQUFJLEVBQ1YsVUFBVSxDQUFDLElBQUksRUFDZixJQUFJLEVBQ0osVUFBVSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsSUFBSSxLQUFLLEtBQUssQ0FBQyxJQUFJLENBQUMsRUFBRSxNQUFNLEVBQzFELEtBQUssRUFDTCxXQUFXLEVBQ1gsTUFBTSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FDckIsQ0FDSixDQUNKLENBQUE7SUFFRCxPQUFPLENBQUMsR0FBRyxnQkFBZ0IsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUUsRUFBRSxFQUFFLEVBQUUsQ0FBQyxFQUFFLEVBQUUsSUFBSSxFQUFFLEVBQUUsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLEVBQUUsR0FBRyxPQUFPLENBQUMsQ0FBQTtBQUN0RixDQUFDO0FBRUQsS0FBSyxVQUFVLEdBQUcsQ0FBQyxJQUFZO0lBQzNCLE1BQU0sTUFBTSxHQUFHLE1BQU0sSUFBSSxLQUFLLEVBQUU7U0FDM0IsSUFBSSxDQUFDLFVBQVUsRUFBRSxJQUFJLEVBQUU7UUFDcEIsV0FBVyxFQUFFLFNBQVM7UUFDdEIsa0JBQWtCLEVBQUUsRUFBRSxLQUFLLEVBQUUsQ0FBQyxFQUFFO1FBQ2hDLElBQUksRUFBRSxJQUFJLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQztLQUM3QixDQUFDO1NBQ0QsYUFBYSxDQUFDLEVBQUUsSUFBSSxFQUFFLFlBQVksRUFBRSxDQUFDLENBQUE7SUFDMUMsT0FBTztRQUNILE1BQU0sRUFBRSxNQUFNLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQztRQUNqQyxJQUFJLEVBQ0EsTUFBTSxDQUFDLE1BQU0sR0FBRyxJQUFJO1lBQ2hCLENBQUMsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxNQUFNLFFBQVE7WUFDMUIsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxHQUFHLEtBQUssQ0FBQyxHQUFHLEVBQUUsTUFBTTtRQUN4RCxNQUFNLEVBQUUsVUFBVSxDQUFDLFFBQVEsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDO0tBQy9ELENBQUE7QUFDTCxDQUFDO0FBaURELE1BQU0sQ0FBQyxLQUFLLFVBQVUsWUFBWSxDQUM5QixHQUFhLEVBQ2IsTUFBYyxFQUNkLE9BQWU7SUFFZixNQUFNLEtBQUssR0FBRyxFQUFFLENBQUE7SUFDaEIsSUFBSSxNQUFNLEdBQUcsRUFBRSxDQUFBO0lBQ2YsU0FBUyxDQUFDO1FBQ04sTUFBTSxJQUFJLEdBQUcsTUFBTSxZQUFZLENBSTNCLFVBQVUsQ0FBQyxHQUFHLEVBQUUsS0FBSyxFQUFFLFFBQVEsRUFBRSwwQkFBMEIsTUFBTSxFQUFFLENBQUMsRUFDcEUseUJBQXlCLENBQzVCLENBQUE7UUFDRCxLQUFLLENBQUMsSUFBSSxDQUFDLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFBO1FBQzdCLElBQUksSUFBSSxDQUFDLFVBQVUsS0FBSyxJQUFJLEVBQUUsQ0FBQztZQUMzQixNQUFLO1FBQ1QsQ0FBQztRQUNELE1BQU0sR0FBRyxVQUFVLGtCQUFrQixDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFBO0lBQzVELENBQUM7SUFDRCxNQUFNLFFBQVEsR0FBRyxHQUFHLE1BQU0sSUFBSSxPQUFPLEdBQUcsQ0FBQyxXQUFXLEVBQUUsQ0FBQTtJQUN0RCxPQUFPLEtBQUs7U0FDUCxNQUFNLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsWUFBWSxDQUFDLFVBQVUsQ0FBQyxRQUFRLENBQUMsQ0FBQztTQUNsRCxHQUFHLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQ1IsRUFBRSxFQUFFLEVBQUUsQ0FBQyxXQUFXO1FBQ2xCLElBQUksRUFBRSxFQUFFLENBQUMsWUFBWSxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDO1FBQzVDLE9BQU8sRUFBRSxFQUFFLENBQUMsT0FBTztRQUNuQixNQUFNLEVBQUUsRUFBRSxDQUFDLFVBQVU7UUFDckIsT0FBTyxFQUFFLEVBQUUsQ0FBQyxPQUFPO1FBQ25CLEdBQUcsRUFBRSxFQUFFLENBQUMsV0FBVyxFQUFFLFNBQVMsSUFBSSxFQUFFO1FBQ3BDLElBQUksRUFBRSxFQUFFLENBQUMsYUFBYTtRQUN0QixJQUFJLEVBQUUsRUFBRSxDQUFDLFVBQVU7UUFDbkIsSUFBSSxFQUNBLEVBQUUsQ0FBQyxRQUFRLEdBQUcsSUFBSTtZQUNkLENBQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxRQUFRLFFBQVE7WUFDeEIsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsUUFBUSxHQUFHLEtBQUssQ0FBQyxHQUFHLEVBQUUsTUFBTTtLQUN6RCxDQUFDLENBQUMsQ0FBQTtBQUNYLENBQUM7QUFRRCxLQUFLLFVBQVUsWUFBWSxDQUN2QixHQUFhLEVBQ2IsTUFBYyxFQUNkLElBQVksRUFDWixPQUFlLEVBQ2YsSUFBWSxFQUNaLE1BQWMsRUFDZCxXQUFzQyxFQUN0QyxJQUF1RDtJQUV2RCxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDUixNQUFNLElBQUksS0FBSyxDQUFDLFNBQVMsQ0FBQyxDQUFBO0lBQzlCLENBQUM7SUFDRCxPQUFPLENBQUMsR0FBRyxDQUFDLG1CQUFtQixJQUFJLEtBQUssSUFBSSxDQUFDLElBQUksR0FBRyxDQUFDLENBQUE7SUFDckQsTUFBTSxRQUFRLEdBQUcsTUFBTSxZQUFZLENBQy9CLEtBQUssQ0FDRCxHQUFHLEVBQUUsQ0FDRCxVQUFVLENBQUMsR0FBRyxFQUFFLE1BQU0sRUFBRSxRQUFRLEVBQUUsdUJBQXVCLEVBQUU7UUFDdkQsWUFBWSxFQUFFLEdBQUcsTUFBTSxJQUFJLE9BQU8sSUFBSSxJQUFJLEVBQUU7UUFDNUMsSUFBSSxFQUFFLEVBQUUsT0FBTyxFQUFFLElBQUksQ0FBQyxNQUFNLEVBQUU7UUFDOUIsV0FBVyxFQUFFLEtBQUs7UUFDbEIsYUFBYSxFQUFFLGtCQUFrQixDQUFDLE1BQU0sQ0FBQztRQUN6QyxHQUFHLFlBQVksQ0FBQyxNQUFNLEVBQUUsSUFBSSxFQUFFLFdBQVcsQ0FBQztRQUMxQyxJQUFJLEVBQUU7WUFDRixTQUFTLEVBQUUsVUFBVTtZQUNyQixXQUFXLEVBQUUsTUFBTTtZQUNuQixPQUFPO1NBQ1Y7S0FDSixDQUFDLEVBQ04sQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLEtBQUssR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUMzQyxFQUNELHdCQUF3QixHQUFHLElBQUksQ0FDbEMsQ0FBQTtJQUNELE9BQU8sRUFBRSxJQUFJLEVBQUUsRUFBRSxFQUFFLFFBQVEsQ0FBQyxXQUFXLEVBQUUsQ0FBQTtBQUM3QyxDQUFDO0FBRUQsS0FBSyxVQUFVLFlBQVksQ0FDdkIsR0FBYSxFQUNiLE1BQWMsRUFDZCxJQUFZLEVBQ1osT0FBZSxFQUNmLElBQVksRUFDWixNQUEwQixFQUMxQixLQUFzQixFQUN0QixXQUFzQyxFQUN0QyxJQUF1RDtJQUV2RCxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDUixNQUFNLElBQUksS0FBSyxDQUFDLFNBQVMsQ0FBQyxDQUFBO0lBQzlCLENBQUM7SUFDRCxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7UUFDVixNQUFNLElBQUksS0FBSyxDQUFDLFdBQVcsQ0FBQyxDQUFBO0lBQ2hDLENBQUM7SUFDRCxNQUFNLElBQUksR0FBRyxrQkFBa0IsQ0FBQyxNQUFNLENBQUMsQ0FBQTtJQUN2QyxJQUFJLENBQUMsaUJBQWlCLENBQUMsRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLElBQUksQ0FBQyxNQUFNLEVBQUUsRUFBRSxFQUFFLElBQUksRUFBRSxLQUFLLENBQUMsSUFBSSxFQUFFLElBQUksRUFBRSxLQUFLLENBQUMsSUFBSSxFQUFFLENBQUMsRUFBRSxDQUFDO1FBQzFGLE9BQU8sQ0FBQyxHQUFHLENBQUMsNEJBQTRCLElBQUksS0FBSyxLQUFLLENBQUMsSUFBSSxPQUFPLElBQUksQ0FBQyxJQUFJLEdBQUcsQ0FBQyxDQUFBO1FBQy9FLE1BQU0sVUFBVSxDQUNaLFVBQVUsQ0FDTixHQUFHLEVBQ0gsS0FBSyxFQUNMLFFBQVEsRUFDUix5QkFBeUIsTUFBTSxJQUFJLE9BQU8sSUFBSSxJQUFJLE9BQU8sRUFDekQ7WUFDSSxPQUFPLEVBQUUsSUFBSSxDQUFDLE1BQU07WUFDcEIsYUFBYSxFQUFFLElBQUk7U0FDdEIsQ0FDSixFQUNELGlDQUFpQyxHQUFHLElBQUksQ0FDM0MsQ0FBQTtJQUNMLENBQUM7SUFDRCxNQUFNLFNBQVMsR0FBRyxZQUFZLENBQUMsTUFBTSxFQUFFLElBQUksRUFBRSxXQUFXLENBQUMsQ0FBQTtJQUN6RCxJQUNJLENBQUMsaUJBQWlCLENBQ2Q7UUFDSSxHQUFHLEVBQUUsU0FBUyxDQUFDLFdBQVcsQ0FBQyxTQUFTO1FBQ3BDLE1BQU0sRUFBRSxTQUFTLENBQUMsVUFBVTtRQUM1QixPQUFPLEVBQUUsU0FBUyxDQUFDLE9BQU87UUFDMUIsT0FBTyxFQUFFLFNBQVMsQ0FBQyxPQUFPO0tBQzdCLEVBQ0Q7UUFDSSxHQUFHLEVBQUUsS0FBSyxDQUFDLEdBQUc7UUFDZCxNQUFNLEVBQUUsS0FBSyxDQUFDLE1BQU07UUFDcEIsT0FBTyxFQUFFLEtBQUssQ0FBQyxPQUFPO1FBQ3RCLE9BQU8sRUFBRSxLQUFLLENBQUMsT0FBTztLQUN6QixDQUNKLEVBQ0gsQ0FBQztRQUNDLE9BQU8sQ0FBQyxHQUFHLENBQUMsNkJBQTZCLEdBQUcsSUFBSSxDQUFDLENBQUE7UUFDakQsTUFBTSxhQUFhLENBQUMsR0FBRyxFQUFFLENBQ3JCLFVBQVUsQ0FDTixVQUFVLENBQ04sR0FBRyxFQUNILEtBQUssRUFDTCxRQUFRLEVBQ1IseUJBQXlCLE1BQU0sSUFBSSxPQUFPLElBQUksSUFBSSxnQkFBZ0IsRUFDbEUsU0FBUyxDQUNaLEVBQ0QsbUNBQW1DLEdBQUcsSUFBSSxDQUM3QyxDQUNKLENBQUE7SUFDTCxDQUFDO0FBQ0wsQ0FBQztBQUVELEtBQUssVUFBVSxZQUFZLENBQUMsR0FBYSxFQUFFLE1BQWMsRUFBRSxPQUFlLEVBQUUsSUFBWTtJQUNwRixPQUFPLENBQUMsR0FBRyxDQUFDLGtCQUFrQixHQUFHLElBQUksQ0FBQyxDQUFBO0lBQ3RDLE1BQU0sVUFBVSxDQUNaLFVBQVUsQ0FBQyxHQUFHLEVBQUUsUUFBUSxFQUFFLFFBQVEsRUFBRSx5QkFBeUIsTUFBTSxJQUFJLE9BQU8sSUFBSSxJQUFJLEVBQUUsQ0FBQyxFQUN6Rix3QkFBd0IsR0FBRyxJQUFJLENBQ2xDLENBQUE7QUFDTCxDQUFDO0FBRUQsU0FBUyxZQUFZLENBQUMsTUFBYyxFQUFFLElBQVksRUFBRSxXQUFzQztJQUN0RixPQUFPO1FBQ0gsSUFBSSxFQUFFLElBQUk7UUFDVixPQUFPLEVBQUUsVUFBVSxDQUFDLE1BQU0sQ0FBQztRQUMzQixPQUFPLEVBQUUsZUFBZTtRQUN4QixPQUFPLEVBQUUsTUFBTSxDQUFDLE9BQU8sSUFBSSxFQUFFO1FBQzdCLFVBQVUsRUFBRSxNQUFNLENBQUMsT0FBTyxLQUFLLE1BQU0sSUFBSSxNQUFNLENBQUMsTUFBTSxLQUFLLE1BQU0sQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxHQUFHO1FBQzlFLGFBQWEsRUFBRTtZQUNYLElBQUksRUFBRSxhQUFhO1NBQ3RCO1FBQ0QsV0FBVyxFQUFFO1lBQ1QsU0FBUyxFQUFFLFdBQVc7U0FDekI7S0FDSixDQUFBO0FBQ0wsQ0FBQztBQUVELFNBQVMsVUFBVSxDQUFDLE1BQWM7SUFDOUIsUUFBUSxNQUFNLENBQUMsV0FBVyxFQUFFLEtBQUssQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUN0QyxLQUFLLE1BQU07WUFDUCxPQUFPLFlBQVksQ0FBQTtRQUN2QixLQUFLLE1BQU07WUFDUCxPQUFPLFlBQVksQ0FBQTtRQUN2QjtZQUNJLE1BQU0sSUFBSSxLQUFLLENBQ1gsK0dBQStHLENBQ2xILENBQUE7SUFDVCxDQUFDO0FBQ0wsQ0FBQztBQUVELFNBQVMsa0JBQWtCLENBQUMsTUFBYztJQUN0QyxRQUNJLFVBQVUsQ0FDTixNQUFNLEVBQ04sTUFBTSxDQUFDLE9BQU8sS0FBSyxNQUFNO1FBQ3JCLENBQUMsQ0FBQyxDQUFDLEtBQUssRUFBRSxLQUFLLEVBQUUsT0FBTyxFQUFFLEtBQUssQ0FBQztRQUNoQyxDQUFDLENBQUMsQ0FBQyxPQUFPLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLLENBQUMsQ0FDdkMsRUFDSCxDQUFDO1FBQ0MsS0FBSyxPQUFPLENBQUM7UUFDYixLQUFLLEtBQUs7WUFDTixPQUFPLENBQUMsT0FBTyxDQUFDLENBQUE7UUFDcEIsS0FBSyxLQUFLLENBQUM7UUFDWCxLQUFLLEtBQUs7WUFDTixPQUFPLENBQUMsUUFBUSxDQUFDLENBQUE7UUFDckI7WUFDSSxNQUFNLElBQUksS0FBSyxDQUFDLG9CQUFvQixHQUFHLENBQUMsTUFBTSxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQTtJQUMvRSxDQUFDO0FBQ0wsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGpzb25SZXNwb25zZSwgb2tSZXNwb25zZSB9IGZyb20gJ0ByaWRkYW5jZS9mZXRjaCdcbmltcG9ydCB7IFBhY2thZ2VKc29uQ29uZmlndXJhdGlvbiwgUmVmbGVjdGlvbiwgcmVzb2x2ZUNwdSB9IGZyb20gJ0ByaWRkYW5jZS9ob3N0L3JlZmxlY3QnXG5pbXBvcnQgSlNaaXAgZnJvbSAnanN6aXAnXG5pbXBvcnQgeyBjcmVhdGVIYXNoIH0gZnJvbSAnbm9kZTpjcnlwdG8nXG5pbXBvcnQgeyBpc0RlZXBTdHJpY3RFcXVhbCB9IGZyb20gJ25vZGU6dXRpbCdcbmltcG9ydCB7IGNvbXBhcmUgfSBmcm9tICcuLi9kaWZmLmpzJ1xuaW1wb3J0IHsgTG9jYWxFbnYsIGF3c1JlcXVlc3QsIHJldHJ5LCByZXRyeUNvbmZsaWN0IH0gZnJvbSAnLi4vbGl0ZS5qcydcblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHN5bmNMYW1iZGEoXG4gICAgZW52OiBMb2NhbEVudixcbiAgICBwcmVmaXg6IHN0cmluZyxcbiAgICBjdXJyZW50RnVuY3Rpb25zOiBBd3NGdW5jdGlvbkxpdGVbXSxcbiAgICByZWZsZWN0aW9uOiBSZWZsZWN0aW9uLFxuICAgIGVudmlyb25tZW50OiB7IFtrZXk6IHN0cmluZ106IHN0cmluZyB9LFxuICAgIHJvbGU6IHN0cmluZyxcbiAgICBjb2RlOiB7IFtuYW1lOiBzdHJpbmddOiBzdHJpbmcgfSxcbikge1xuICAgIGNvbnN0IHppcHBlZCA9IE9iamVjdC5mcm9tRW50cmllcyhcbiAgICAgICAgYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICAgICAgICBPYmplY3QuZW50cmllcyhjb2RlKS5tYXAoXG4gICAgICAgICAgICAgICAgYXN5bmMgKFtuYW1lLCBjXSkgPT5cbiAgICAgICAgICAgICAgICAgICAgW25hbWUsIGF3YWl0IHppcChjKV0gYXMgW3N0cmluZywgQXdhaXRlZDxSZXR1cm5UeXBlPHR5cGVvZiB6aXA+Pl0sXG4gICAgICAgICAgICApLFxuICAgICAgICApLFxuICAgIClcblxuICAgIGNvbnN0IHsgbWlzc2luZywgc3VycGx1cywgZXhpc3RpbmcgfSA9IGNvbXBhcmUocmVmbGVjdGlvbi5odHRwLCBjdXJyZW50RnVuY3Rpb25zKVxuICAgIGNvbnN0IGNyZWF0ZWQgPSBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgICAgbWlzc2luZy5tYXAoZm4gPT5cbiAgICAgICAgICAgIGNyZWF0ZUxhbWJkYShcbiAgICAgICAgICAgICAgICBlbnYsXG4gICAgICAgICAgICAgICAgcHJlZml4LFxuICAgICAgICAgICAgICAgIGZuLm5hbWUsXG4gICAgICAgICAgICAgICAgcmVmbGVjdGlvbi5uYW1lLFxuICAgICAgICAgICAgICAgIHJvbGUsXG4gICAgICAgICAgICAgICAgZm4uY29uZmlnLFxuICAgICAgICAgICAgICAgIGVudmlyb25tZW50LFxuICAgICAgICAgICAgICAgIHppcHBlZFtmbi5uYW1lXSxcbiAgICAgICAgICAgICksXG4gICAgICAgICksXG4gICAgKVxuICAgIGF3YWl0IFByb21pc2UuYWxsKHN1cnBsdXMubWFwKGZuID0+IGRlbGV0ZUxhbWJkYShlbnYsIHByZWZpeCwgcmVmbGVjdGlvbi5uYW1lLCBmbi5uYW1lKSkpXG4gICAgYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICAgIGV4aXN0aW5nLm1hcChhd3NGbiA9PlxuICAgICAgICAgICAgdXBkYXRlTGFtYmRhKFxuICAgICAgICAgICAgICAgIGVudixcbiAgICAgICAgICAgICAgICBwcmVmaXgsXG4gICAgICAgICAgICAgICAgYXdzRm4ubmFtZSxcbiAgICAgICAgICAgICAgICByZWZsZWN0aW9uLm5hbWUsXG4gICAgICAgICAgICAgICAgcm9sZSxcbiAgICAgICAgICAgICAgICByZWZsZWN0aW9uLmh0dHAuZmluZChmbiA9PiBmbi5uYW1lID09PSBhd3NGbi5uYW1lKT8uY29uZmlnLFxuICAgICAgICAgICAgICAgIGF3c0ZuLFxuICAgICAgICAgICAgICAgIGVudmlyb25tZW50LFxuICAgICAgICAgICAgICAgIHppcHBlZFthd3NGbi5uYW1lXSxcbiAgICAgICAgICAgICksXG4gICAgICAgICksXG4gICAgKVxuXG4gICAgcmV0dXJuIFsuLi5jdXJyZW50RnVuY3Rpb25zLm1hcChmbiA9PiAoeyBpZDogZm4uaWQsIG5hbWU6IGZuLm5hbWUgfSkpLCAuLi5jcmVhdGVkXVxufVxuXG5hc3luYyBmdW5jdGlvbiB6aXAoY29kZTogc3RyaW5nKSB7XG4gICAgY29uc3QgYnVmZmVyID0gYXdhaXQgbmV3IEpTWmlwKClcbiAgICAgICAgLmZpbGUoJ2luZGV4LmpzJywgY29kZSwge1xuICAgICAgICAgICAgY29tcHJlc3Npb246ICdERUZMQVRFJyxcbiAgICAgICAgICAgIGNvbXByZXNzaW9uT3B0aW9uczogeyBsZXZlbDogOSB9LFxuICAgICAgICAgICAgZGF0ZTogbmV3IERhdGUoMjAyMiwgOCwgMSksXG4gICAgICAgIH0pXG4gICAgICAgIC5nZW5lcmF0ZUFzeW5jKHsgdHlwZTogJ25vZGVidWZmZXInIH0pXG4gICAgcmV0dXJuIHtcbiAgICAgICAgemlwcGVkOiBidWZmZXIudG9TdHJpbmcoJ2Jhc2U2NCcpLFxuICAgICAgICBzaXplOlxuICAgICAgICAgICAgYnVmZmVyLmxlbmd0aCA8IDEwMjRcbiAgICAgICAgICAgICAgICA/IGAke2J1ZmZlci5sZW5ndGh9IGJ5dGVzYFxuICAgICAgICAgICAgICAgIDogYCR7TWF0aC5jZWlsKGJ1ZmZlci5sZW5ndGggLyAxMDIuNCkgLyAxMH0gS2lCYCxcbiAgICAgICAgc2hhMjU2OiBjcmVhdGVIYXNoKCdzaGEyNTYnKS51cGRhdGUoYnVmZmVyKS5kaWdlc3QoJ2Jhc2U2NCcpLFxuICAgIH1cbn1cblxudHlwZSBBcmNoaXRlY3R1cmVzID0gWydhcm02NCddIHwgWyd4ODZfNjQnXVxuZXhwb3J0IHR5cGUgQXdzRnVuY3Rpb25MaXRlID0ge1xuICAgIGlkOiBzdHJpbmdcbiAgICBuYW1lOiBzdHJpbmdcbiAgICBydW50aW1lOiBzdHJpbmdcbiAgICBtZW1vcnk6IG51bWJlclxuICAgIHRpbWVvdXQ6IG51bWJlclxuICAgIGVudjogeyBba2V5OiBzdHJpbmddOiBzdHJpbmcgfVxuICAgIGNwdXM6IEFyY2hpdGVjdHVyZXNcbiAgICBoYXNoOiBzdHJpbmdcbiAgICBzaXplOiBzdHJpbmdcbn1cblxudHlwZSBBd3NGdW5jdGlvbiA9IHtcbiAgICBEZXNjcmlwdGlvbjogc3RyaW5nXG4gICAgVHJhY2luZ0NvbmZpZzoge1xuICAgICAgICBNb2RlOiAnUGFzc1Rocm91Z2gnXG4gICAgfVxuICAgIFJldmlzaW9uSWQ6IHN0cmluZ1xuICAgIExhc3RNb2RpZmllZDogc3RyaW5nXG4gICAgRnVuY3Rpb25Bcm46IHN0cmluZ1xuICAgIEZ1bmN0aW9uTmFtZTogc3RyaW5nXG4gICAgUnVudGltZTogJ25vZGVqczE4LngnIHwgJ25vZGVqczIwLngnXG4gICAgVmVyc2lvbjogJyRMQVRFU1QnXG4gICAgUGFja2FnZVR5cGU6ICdaaXAnXG4gICAgTWVtb3J5U2l6ZTogbnVtYmVyXG4gICAgVGltZW91dDogbnVtYmVyXG4gICAgSGFuZGxlcjogJ2luZGV4LmhhbmRsZXInXG4gICAgQ29kZVNoYTI1Njogc3RyaW5nXG4gICAgUm9sZTogc3RyaW5nXG4gICAgU2lnbmluZ1Byb2ZpbGVWZXJzaW9uQXJuOiBudWxsXG4gICAgTWFzdGVyQXJuOiBudWxsXG4gICAgQ29kZVNpemU6IG51bWJlclxuICAgIFN0YXRlOiBudWxsXG4gICAgU3RhdGVSZWFzb246IG51bGxcbiAgICBFbnZpcm9ubWVudD86IHtcbiAgICAgICAgVmFyaWFibGVzOiB7IFtrZXk6IHN0cmluZ106IHN0cmluZyB9XG4gICAgICAgIEVycm9yOiBudWxsXG4gICAgfVxuICAgIEVwaGVtZXJhbFN0b3JhZ2U6IHtcbiAgICAgICAgU2l6ZTogbnVtYmVyXG4gICAgfVxuICAgIFN0YXRlUmVhc29uQ29kZTogbnVsbFxuICAgIExhc3RVcGRhdGVTdGF0dXNSZWFzb25Db2RlOiBudWxsXG4gICAgQXJjaGl0ZWN0dXJlczogQXJjaGl0ZWN0dXJlc1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZ2V0RnVuY3Rpb25zKFxuICAgIGVudjogTG9jYWxFbnYsXG4gICAgcHJlZml4OiBzdHJpbmcsXG4gICAgc2VydmljZTogc3RyaW5nLFxuKTogUHJvbWlzZTxBd3NGdW5jdGlvbkxpdGVbXT4ge1xuICAgIGNvbnN0IGZ1bmNzID0gW11cbiAgICBsZXQgbWFya2VyID0gJydcbiAgICBmb3IgKDs7KSB7XG4gICAgICAgIGNvbnN0IHBhZ2UgPSBhd2FpdCBqc29uUmVzcG9uc2U8e1xuICAgICAgICAgICAgRnVuY3Rpb25zOiBBd3NGdW5jdGlvbltdXG4gICAgICAgICAgICBOZXh0TWFya2VyOiBzdHJpbmcgfCBudWxsXG4gICAgICAgIH0+KFxuICAgICAgICAgICAgYXdzUmVxdWVzdChlbnYsICdHRVQnLCAnbGFtYmRhJywgYC8yMDE1LTAzLTMxL2Z1bmN0aW9ucy8/JHttYXJrZXJ9YCksXG4gICAgICAgICAgICAnRXJyb3IgbGlzdGluZyBmdW5jdGlvbnMnLFxuICAgICAgICApXG4gICAgICAgIGZ1bmNzLnB1c2goLi4ucGFnZS5GdW5jdGlvbnMpXG4gICAgICAgIGlmIChwYWdlLk5leHRNYXJrZXIgPT09IG51bGwpIHtcbiAgICAgICAgICAgIGJyZWFrXG4gICAgICAgIH1cbiAgICAgICAgbWFya2VyID0gYE1hcmtlcj0ke2VuY29kZVVSSUNvbXBvbmVudChwYWdlLk5leHRNYXJrZXIpfWBcbiAgICB9XG4gICAgY29uc3QgZm5QcmVmaXggPSBgJHtwcmVmaXh9LSR7c2VydmljZX0tYC50b0xvd2VyQ2FzZSgpXG4gICAgcmV0dXJuIGZ1bmNzXG4gICAgICAgIC5maWx0ZXIoZm4gPT4gZm4uRnVuY3Rpb25OYW1lLnN0YXJ0c1dpdGgoZm5QcmVmaXgpKVxuICAgICAgICAubWFwKGZuID0+ICh7XG4gICAgICAgICAgICBpZDogZm4uRnVuY3Rpb25Bcm4sXG4gICAgICAgICAgICBuYW1lOiBmbi5GdW5jdGlvbk5hbWUuc2xpY2UoZm5QcmVmaXgubGVuZ3RoKSxcbiAgICAgICAgICAgIHJ1bnRpbWU6IGZuLlJ1bnRpbWUsXG4gICAgICAgICAgICBtZW1vcnk6IGZuLk1lbW9yeVNpemUsXG4gICAgICAgICAgICB0aW1lb3V0OiBmbi5UaW1lb3V0LFxuICAgICAgICAgICAgZW52OiBmbi5FbnZpcm9ubWVudD8uVmFyaWFibGVzID8/IHt9LFxuICAgICAgICAgICAgY3B1czogZm4uQXJjaGl0ZWN0dXJlcyxcbiAgICAgICAgICAgIGhhc2g6IGZuLkNvZGVTaGEyNTYsXG4gICAgICAgICAgICBzaXplOlxuICAgICAgICAgICAgICAgIGZuLkNvZGVTaXplIDwgMTAyNFxuICAgICAgICAgICAgICAgICAgICA/IGAke2ZuLkNvZGVTaXplfSBieXRlc2BcbiAgICAgICAgICAgICAgICAgICAgOiBgJHtNYXRoLmNlaWwoZm4uQ29kZVNpemUgLyAxMDIuNCkgLyAxMH0gS2lCYCxcbiAgICAgICAgfSkpXG59XG5cbnR5cGUgQ29uZmlnID0ge1xuICAgIG1lbW9yeT86IHN0cmluZ1xuICAgIGNvbXB1dGU/OiBzdHJpbmdcbiAgICB0aW1lb3V0PzogbnVtYmVyXG59ICYgUGFja2FnZUpzb25Db25maWd1cmF0aW9uXG5cbmFzeW5jIGZ1bmN0aW9uIGNyZWF0ZUxhbWJkYShcbiAgICBlbnY6IExvY2FsRW52LFxuICAgIHByZWZpeDogc3RyaW5nLFxuICAgIG5hbWU6IHN0cmluZyxcbiAgICBzZXJ2aWNlOiBzdHJpbmcsXG4gICAgcm9sZTogc3RyaW5nLFxuICAgIGNvbmZpZzogQ29uZmlnLFxuICAgIGVudmlyb25tZW50OiB7IFtrZXk6IHN0cmluZ106IHN0cmluZyB9LFxuICAgIGNvZGU/OiB7IHppcHBlZDogc3RyaW5nOyBzaGEyNTY6IHN0cmluZzsgc2l6ZTogc3RyaW5nIH0sXG4pIHtcbiAgICBpZiAoIWNvZGUpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdObyBjb2RlJylcbiAgICB9XG4gICAgY29uc29sZS5sb2coYGNyZWF0aW5nIGxhbWJkYSAke25hbWV9ICgke2NvZGUuc2l6ZX0pYClcbiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGpzb25SZXNwb25zZTx7IEZ1bmN0aW9uQXJuOiBzdHJpbmcgfT4oXG4gICAgICAgIHJldHJ5KFxuICAgICAgICAgICAgKCkgPT5cbiAgICAgICAgICAgICAgICBhd3NSZXF1ZXN0KGVudiwgJ1BPU1QnLCAnbGFtYmRhJywgJy8yMDE1LTAzLTMxL2Z1bmN0aW9ucycsIHtcbiAgICAgICAgICAgICAgICAgICAgRnVuY3Rpb25OYW1lOiBgJHtwcmVmaXh9LSR7c2VydmljZX0tJHtuYW1lfWAsXG4gICAgICAgICAgICAgICAgICAgIENvZGU6IHsgWmlwRmlsZTogY29kZS56aXBwZWQgfSxcbiAgICAgICAgICAgICAgICAgICAgUGFja2FnZVR5cGU6ICdaaXAnLFxuICAgICAgICAgICAgICAgICAgICBBcmNoaXRlY3R1cmVzOiBsYW1iZGFBcmNoaXRlY3R1cmUoY29uZmlnKSxcbiAgICAgICAgICAgICAgICAgICAgLi4ubGFtYmRhQ29uZmlnKGNvbmZpZywgcm9sZSwgZW52aXJvbm1lbnQpLFxuICAgICAgICAgICAgICAgICAgICBUYWdzOiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBmcmFtZXdvcms6ICdyaWRkYW5jZScsXG4gICAgICAgICAgICAgICAgICAgICAgICBlbnZpcm9ubWVudDogcHJlZml4LFxuICAgICAgICAgICAgICAgICAgICAgICAgc2VydmljZSxcbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICB9KSxcbiAgICAgICAgICAgIHIgPT4gKHIuc3RhdHVzID09PSA0MDAgPyAyNSA6IHVuZGVmaW5lZCksXG4gICAgICAgICksXG4gICAgICAgICdFcnJvciBjcmVhdGluZyBsYW1iZGEgJyArIG5hbWUsXG4gICAgKVxuICAgIHJldHVybiB7IG5hbWUsIGlkOiByZXNwb25zZS5GdW5jdGlvbkFybiB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHVwZGF0ZUxhbWJkYShcbiAgICBlbnY6IExvY2FsRW52LFxuICAgIHByZWZpeDogc3RyaW5nLFxuICAgIG5hbWU6IHN0cmluZyxcbiAgICBzZXJ2aWNlOiBzdHJpbmcsXG4gICAgcm9sZTogc3RyaW5nLFxuICAgIGNvbmZpZzogQ29uZmlnIHwgdW5kZWZpbmVkLFxuICAgIGF3c0ZuOiBBd3NGdW5jdGlvbkxpdGUsXG4gICAgZW52aXJvbm1lbnQ6IHsgW2tleTogc3RyaW5nXTogc3RyaW5nIH0sXG4gICAgY29kZT86IHsgemlwcGVkOiBzdHJpbmc7IHNoYTI1Njogc3RyaW5nOyBzaXplOiBzdHJpbmcgfSxcbikge1xuICAgIGlmICghY29kZSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ05vIGNvZGUnKVxuICAgIH1cbiAgICBpZiAoIWNvbmZpZykge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ05vIGNvbmZpZycpXG4gICAgfVxuICAgIGNvbnN0IGNwdXMgPSBsYW1iZGFBcmNoaXRlY3R1cmUoY29uZmlnKVxuICAgIGlmICghaXNEZWVwU3RyaWN0RXF1YWwoeyBjcHVzLCBoYXNoOiBjb2RlLnNoYTI1NiB9LCB7IGNwdXM6IGF3c0ZuLmNwdXMsIGhhc2g6IGF3c0ZuLmhhc2ggfSkpIHtcbiAgICAgICAgY29uc29sZS5sb2coYHVwZGF0aW5nIGNvZGUgZm9yIGxhbWJkYSAke25hbWV9ICgke2F3c0ZuLnNpemV9IC0+ICR7Y29kZS5zaXplfSlgKVxuICAgICAgICBhd2FpdCBva1Jlc3BvbnNlKFxuICAgICAgICAgICAgYXdzUmVxdWVzdChcbiAgICAgICAgICAgICAgICBlbnYsXG4gICAgICAgICAgICAgICAgJ1BVVCcsXG4gICAgICAgICAgICAgICAgJ2xhbWJkYScsXG4gICAgICAgICAgICAgICAgYC8yMDE1LTAzLTMxL2Z1bmN0aW9ucy8ke3ByZWZpeH0tJHtzZXJ2aWNlfS0ke25hbWV9L2NvZGVgLFxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgWmlwRmlsZTogY29kZS56aXBwZWQsXG4gICAgICAgICAgICAgICAgICAgIEFyY2hpdGVjdHVyZXM6IGNwdXMsXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICksXG4gICAgICAgICAgICAnRXJyb3IgdXBkYXRpbmcgY29kZSBmb3IgbGFtYmRhICcgKyBuYW1lLFxuICAgICAgICApXG4gICAgfVxuICAgIGNvbnN0IGF3c0NvbmZpZyA9IGxhbWJkYUNvbmZpZyhjb25maWcsIHJvbGUsIGVudmlyb25tZW50KVxuICAgIGlmIChcbiAgICAgICAgIWlzRGVlcFN0cmljdEVxdWFsKFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIGVudjogYXdzQ29uZmlnLkVudmlyb25tZW50LlZhcmlhYmxlcyxcbiAgICAgICAgICAgICAgICBtZW1vcnk6IGF3c0NvbmZpZy5NZW1vcnlTaXplLFxuICAgICAgICAgICAgICAgIHRpbWVvdXQ6IGF3c0NvbmZpZy5UaW1lb3V0LFxuICAgICAgICAgICAgICAgIHJ1bnRpbWU6IGF3c0NvbmZpZy5SdW50aW1lLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBlbnY6IGF3c0ZuLmVudixcbiAgICAgICAgICAgICAgICBtZW1vcnk6IGF3c0ZuLm1lbW9yeSxcbiAgICAgICAgICAgICAgICB0aW1lb3V0OiBhd3NGbi50aW1lb3V0LFxuICAgICAgICAgICAgICAgIHJ1bnRpbWU6IGF3c0ZuLnJ1bnRpbWUsXG4gICAgICAgICAgICB9LFxuICAgICAgICApXG4gICAgKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKCd1cGRhdGluZyBjb25maWcgZm9yIGxhbWJkYSAnICsgbmFtZSlcbiAgICAgICAgYXdhaXQgcmV0cnlDb25mbGljdCgoKSA9PlxuICAgICAgICAgICAgb2tSZXNwb25zZShcbiAgICAgICAgICAgICAgICBhd3NSZXF1ZXN0KFxuICAgICAgICAgICAgICAgICAgICBlbnYsXG4gICAgICAgICAgICAgICAgICAgICdQVVQnLFxuICAgICAgICAgICAgICAgICAgICAnbGFtYmRhJyxcbiAgICAgICAgICAgICAgICAgICAgYC8yMDE1LTAzLTMxL2Z1bmN0aW9ucy8ke3ByZWZpeH0tJHtzZXJ2aWNlfS0ke25hbWV9L2NvbmZpZ3VyYXRpb25gLFxuICAgICAgICAgICAgICAgICAgICBhd3NDb25maWcsXG4gICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgICAnRXJyb3IgdXBkYXRpbmcgY29uZmlnIGZvciBsYW1iZGEgJyArIG5hbWUsXG4gICAgICAgICAgICApLFxuICAgICAgICApXG4gICAgfVxufVxuXG5hc3luYyBmdW5jdGlvbiBkZWxldGVMYW1iZGEoZW52OiBMb2NhbEVudiwgcHJlZml4OiBzdHJpbmcsIHNlcnZpY2U6IHN0cmluZywgbmFtZTogc3RyaW5nKSB7XG4gICAgY29uc29sZS5sb2coJ2RlbGV0aW5nIGxhbWJkYSAnICsgbmFtZSlcbiAgICBhd2FpdCBva1Jlc3BvbnNlKFxuICAgICAgICBhd3NSZXF1ZXN0KGVudiwgJ0RFTEVURScsICdsYW1iZGEnLCBgLzIwMTUtMDMtMzEvZnVuY3Rpb25zLyR7cHJlZml4fS0ke3NlcnZpY2V9LSR7bmFtZX1gKSxcbiAgICAgICAgJ0Vycm9yIGRlbGV0aW5nIGxhbWJkYSAnICsgbmFtZSxcbiAgICApXG59XG5cbmZ1bmN0aW9uIGxhbWJkYUNvbmZpZyhjb25maWc6IENvbmZpZywgcm9sZTogc3RyaW5nLCBlbnZpcm9ubWVudDogeyBba2V5OiBzdHJpbmddOiBzdHJpbmcgfSkge1xuICAgIHJldHVybiB7XG4gICAgICAgIFJvbGU6IHJvbGUsXG4gICAgICAgIFJ1bnRpbWU6IGdldFJ1bnRpbWUoY29uZmlnKSxcbiAgICAgICAgSGFuZGxlcjogJ2luZGV4LmhhbmRsZXInLFxuICAgICAgICBUaW1lb3V0OiBjb25maWcudGltZW91dCA/PyAxNSxcbiAgICAgICAgTWVtb3J5U2l6ZTogY29uZmlnLmNvbXB1dGUgPT09ICdoaWdoJyB8fCBjb25maWcubWVtb3J5ID09PSAnaGlnaCcgPyAzMDA4IDogMTI4LFxuICAgICAgICBUcmFjaW5nQ29uZmlnOiB7XG4gICAgICAgICAgICBNb2RlOiAnUGFzc1Rocm91Z2gnLFxuICAgICAgICB9LFxuICAgICAgICBFbnZpcm9ubWVudDoge1xuICAgICAgICAgICAgVmFyaWFibGVzOiBlbnZpcm9ubWVudCxcbiAgICAgICAgfSxcbiAgICB9XG59XG5cbmZ1bmN0aW9uIGdldFJ1bnRpbWUoY29uZmlnOiBDb25maWcpIHtcbiAgICBzd2l0Y2ggKGNvbmZpZy5ub2RlVmVyc2lvbj8uc2xpY2UoMCwgNCkpIHtcbiAgICAgICAgY2FzZSAnPj0yMCc6XG4gICAgICAgICAgICByZXR1cm4gJ25vZGVqczIwLngnXG4gICAgICAgIGNhc2UgJz49MTgnOlxuICAgICAgICAgICAgcmV0dXJuICdub2RlanMxOC54J1xuICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICAgICAgICdVbnN1cHBvcnRlZCBlbmdpbmU7IHBsZWFzZSBzcGVjaWZ5IGVpdGhlciBcIm5vZGVcIjogXCI+PTE4XCIgb3IgXCJub2RlXCI6IFwiPj0yMFwiIGFzIGFuIGVuZ2luZSBpbiB5b3VyIHBhY2thZ2UuanNvbi4nLFxuICAgICAgICAgICAgKVxuICAgIH1cbn1cblxuZnVuY3Rpb24gbGFtYmRhQXJjaGl0ZWN0dXJlKGNvbmZpZzogQ29uZmlnKSB7XG4gICAgc3dpdGNoIChcbiAgICAgICAgcmVzb2x2ZUNwdShcbiAgICAgICAgICAgIGNvbmZpZyxcbiAgICAgICAgICAgIGNvbmZpZy5jb21wdXRlID09PSAnaGlnaCdcbiAgICAgICAgICAgICAgICA/IFsneDY0JywgJ3gzMicsICdhcm02NCcsICdhcm0nXVxuICAgICAgICAgICAgICAgIDogWydhcm02NCcsICdhcm0nLCAneDY0JywgJ3gzMiddLFxuICAgICAgICApXG4gICAgKSB7XG4gICAgICAgIGNhc2UgJ2FybTY0JzpcbiAgICAgICAgY2FzZSAnYXJtJzpcbiAgICAgICAgICAgIHJldHVybiBbJ2FybTY0J11cbiAgICAgICAgY2FzZSAneDY0JzpcbiAgICAgICAgY2FzZSAneDMyJzpcbiAgICAgICAgICAgIHJldHVybiBbJ3g4Nl82NCddXG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1Vuc3VwcG9ydGVkIENQVXM6ICcgKyAoY29uZmlnLmNwdXM/LmpvaW4oJywgJykgPz8gJycpKVxuICAgIH1cbn1cbiJdfQ==