@riddance/deploy
Version:
219 lines • 44.5 kB
JavaScript
import { jsonResponse, okResponse, throwOnNotOK } from '@riddance/fetch';
import { isDeepStrictEqual } from 'node:util';
import { compare } from '../diff.js';
import { awsRequest, retryConflict } from '../lite.js';
export async function syncGateway(env, region, account, prefix, service, currentGateway, reflection, corsSites) {
if (currentGateway.api) {
await syncGatewayApi(currentGateway.api, env, prefix, service, corsSites);
await syncStage(env, prefix, service, currentGateway.api.apiId, currentGateway.stage);
const { ids, surplus: surplusIntegrations } = await syncIntegrations(env, region, account, prefix, service, currentGateway.api.apiId, currentGateway.integrations, reflection);
const integrationIdByName = Object.fromEntries(ids);
const nameByTarget = Object.fromEntries(ids.map(([name, integrationId]) => [`integrations/${integrationId}`, name]));
const { missing, surplus, existing } = compare(reflection.http, currentGateway.routes.map(r => ({
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
name: nameByTarget[r.target],
...r,
})));
await Promise.all(surplus.map(i => deleteRoute(env, currentGateway.api.apiId, i)));
await Promise.all([
...missing.map(fn => createRoute(env, currentGateway.api.apiId, asRoute(integrationIdByName[fn.name], fn))),
...existing.map(async ({ name, routeId, ...ex }) => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const fn = reflection.http.find(f => f.name === name);
const route = asRoute(integrationIdByName[fn.name], fn);
if (isDeepStrictEqual(ex, route)) {
return;
}
await updateRoute(env, currentGateway.api.apiId, routeId, route);
}),
]);
await Promise.all(surplusIntegrations.map(i => deleteIntegration(env, region, account, currentGateway.api.apiId, i.integrationId)));
return currentGateway.api.apiId;
}
else {
const gateway = await createGateway(env, prefix, service, corsSites);
const ids = await Promise.all(reflection.http.map(fn => createIntegration(env, gateway.apiId, fn.name, asIntegration(region, account, prefix, service, fn))));
const integrationIdByName = Object.fromEntries(ids);
await Promise.all(reflection.http.map(fn => createRoute(env, gateway.apiId, asRoute(integrationIdByName[fn.name], fn))));
return gateway.apiId;
}
}
async function syncIntegrations(env, region, account, prefix, service, apiId, currentIntegrations, reflection) {
const { missing, surplus, existing } = compare(reflection.http, currentIntegrations);
const ids = await Promise.all([
...missing.map(fn => createIntegration(env, apiId, fn.name, asIntegration(region, account, prefix, service, fn))),
...existing.map(async ({ name, integrationId, ...ex }) => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const fn = reflection.http.find(f => f.name === name);
const integration = asIntegration(region, account, prefix, service, fn);
if (isDeepStrictEqual(ex, integration)) {
return [name, integrationId];
}
await updateIntegration(env, apiId, integrationId, integration);
return [name, integrationId];
}),
]);
return { ids, surplus };
}
export async function* getApis(env, prefix) {
for (let next = '';;) {
const page = await jsonResponse(awsRequest(env, 'GET', 'apigateway', `/v2/apis/${next}`), 'Error getting APIs.');
for (const item of page.items.filter(a => a.name.startsWith(`${prefix}-`))) {
yield item;
}
if (!page.nextToken) {
break;
}
next = `?nextToken=${encodeURIComponent(page.nextToken)}`;
}
}
export async function getApi(env, prefix, service) {
const name = `${prefix}-${service}`;
for await (const api of getApis(env, prefix)) {
if (api.name === name) {
const [integrations, routes, stage] = await Promise.all([
getIntegrations(env, api.apiId, name.length + 1),
getRoutes(env, api.apiId),
getStage(env, api.apiId),
]);
return { api, integrations, routes: routes.items, stage };
}
}
return { integrations: [], routes: [] };
}
async function getIntegrations(env, apiId, prefixLength) {
const { items } = await jsonResponse(awsRequest(env, 'GET', 'apigateway', `/v2/apis/${apiId}/integrations`), 'Error getting API integrations.');
return items.map(i => ({
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
name: i.integrationUri.split(':').at(-1).slice(prefixLength),
...i,
}));
}
function asIntegration(region, account, prefix, service, fn) {
if (!region || !account) {
throw new Error('Weird');
}
return {
payloadFormatVersion: '2.0',
integrationType: 'AWS_PROXY',
integrationMethod: fn.method,
integrationUri: `arn:aws:lambda:${region}:${account}:function:${prefix}-${service}-${fn.name}`,
connectionType: 'INTERNET',
timeoutInMillis: Math.min(((fn.config.timeout ?? 15) + 5) * 1000, 30_000),
};
}
async function createIntegration(env, apiId, name, integration) {
console.log('creating API integration');
const created = await retryConflict(() => jsonResponse(awsRequest(env, 'POST', 'apigateway', `/v2/apis/${apiId}/integrations`, integration), 'Error creating API integration.'));
console.log(` from ${apiId} to ${integration.integrationUri} as ${created.integrationId}`);
return [name, created.integrationId];
}
async function updateIntegration(env, apiId, id, integration) {
console.log('updating API integration ' + id);
console.log(` from ${apiId} to ${integration.integrationUri}`);
await okResponse(awsRequest(env, 'PATCH', 'apigateway', `/v2/apis/${apiId}/integrations/${id}`, integration), 'Error updating API integration');
}
async function deleteIntegration(env, region, account, apiId, id) {
if (!region || !account) {
throw new Error('Weird');
}
console.log('deleting API integration ' + id);
await okResponse(awsRequest(env, 'DELETE', 'apigateway', `/v2/apis/${apiId}/integrations/${id}`), 'Error deleting API integration.');
}
function asRoute(integrationId, fn) {
if (!integrationId) {
throw new Error(`Weird: no integration ID for ${fn.method} ${fn.pathPattern}`);
}
let p = 0;
return {
routeKey: `${fn.method} /${trimTrailingSlash(fn.pathPattern.replaceAll('*', () => `{p${++p}}`))}`,
authorizationType: 'NONE',
apiKeyRequired: false,
target: `integrations/${integrationId}`,
};
}
function trimTrailingSlash(pathPattern) {
if (pathPattern.endsWith('/')) {
return pathPattern.slice(0, Math.max(0, pathPattern.length - 1));
}
return pathPattern;
}
async function getRoutes(env, apiId) {
return await jsonResponse(awsRequest(env, 'GET', 'apigateway', `/v2/apis/${apiId}/routes`), 'Error getting API routes.');
}
async function createRoute(env, apiId, route) {
console.log(`creating route ${route.routeKey} to ${route.target}`);
await retryConflict(() => okResponse(awsRequest(env, 'POST', 'apigateway', `/v2/apis/${apiId}/routes`, route), 'Error creating API route.'));
}
async function updateRoute(env, apiId, id, route) {
console.log(`updating API route ${id} to ${route.target}`);
await okResponse(awsRequest(env, 'PATCH', 'apigateway', `/v2/apis/${apiId}/routes/${id}`, route), 'Error updating API route.');
}
async function deleteRoute(env, apiId, route) {
console.log(`deleting API route ${route.routeId} from ${route.target}`);
await okResponse(awsRequest(env, 'DELETE', 'apigateway', `/v2/apis/${apiId}/routes/${route.routeId}`), 'Error deleting API route.');
}
async function createGateway(env, prefix, service, corsSites) {
console.log('creating gateway');
const gateway = await jsonResponse(awsRequest(env, 'POST', 'apigateway', `/v2/apis/`, {
name: `${prefix}-${service}`,
protocolType: 'HTTP',
corsConfiguration: corsSettings(corsSites),
tags: {
framework: 'riddance',
environment: prefix,
service,
},
}), 'Error creating gateway.');
await syncStage(env, prefix, service, gateway.apiId, undefined);
return gateway;
}
async function syncGatewayApi(gateway, env, prefix, service, corsSites) {
const corsConfiguration = corsSettings(corsSites);
if (isDeepStrictEqual(corsConfiguration, gateway.corsConfiguration)) {
return;
}
console.log('updating gateway');
await okResponse(awsRequest(env, 'PATCH', 'apigateway', `/v2/apis/${gateway.apiId}`, {
name: `${prefix}-${service}`,
protocolType: 'HTTP',
corsConfiguration,
tags: {
framework: 'riddance',
environment: prefix,
service,
},
}), 'Error updating gateway.');
}
function corsSettings(corsSites) {
return {
allowOrigins: corsSites,
allowCredentials: !isDeepStrictEqual(corsSites, ['*']),
maxAge: 600,
allowMethods: ['*'],
allowHeaders: ['*'],
exposeHeaders: ['*'],
};
}
async function getStage(env, apiId) {
const response = await awsRequest(env, 'GET', 'apigateway', `/v2/apis/${apiId}/stages/$default`);
if (response.status === 404) {
return undefined;
}
await throwOnNotOK(response, 'Error getting API stage.');
return (await response.json());
}
async function syncStage(env, prefix, service, apiId, stage) {
if (!stage) {
await okResponse(awsRequest(env, 'POST', 'apigateway', `/v2/apis/${apiId}/stages`, {
stageName: '$default',
autoDeploy: true,
tags: {
framework: 'riddance',
environment: prefix,
service,
},
}), 'Error creating stage.');
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXBpLWdhdGV3YXkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJhcGktZ2F0ZXdheS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsWUFBWSxFQUFFLFVBQVUsRUFBRSxZQUFZLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQTtBQUV4RSxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxXQUFXLENBQUE7QUFDN0MsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLFlBQVksQ0FBQTtBQUNwQyxPQUFPLEVBQVksVUFBVSxFQUFFLGFBQWEsRUFBRSxNQUFNLFlBQVksQ0FBQTtBQUVoRSxNQUFNLENBQUMsS0FBSyxVQUFVLFdBQVcsQ0FDN0IsR0FBYSxFQUNiLE1BQTBCLEVBQzFCLE9BQTJCLEVBQzNCLE1BQWMsRUFDZCxPQUFlLEVBQ2YsY0FBMEIsRUFDMUIsVUFBc0IsRUFDdEIsU0FBbUI7SUFFbkIsSUFBSSxjQUFjLENBQUMsR0FBRyxFQUFFLENBQUM7UUFDckIsTUFBTSxjQUFjLENBQUMsY0FBYyxDQUFDLEdBQUcsRUFBRSxHQUFHLEVBQUUsTUFBTSxFQUFFLE9BQU8sRUFBRSxTQUFTLENBQUMsQ0FBQTtRQUN6RSxNQUFNLFNBQVMsQ0FBQyxHQUFHLEVBQUUsTUFBTSxFQUFFLE9BQU8sRUFBRSxjQUFjLENBQUMsR0FBRyxDQUFDLEtBQUssRUFBRSxjQUFjLENBQUMsS0FBSyxDQUFDLENBQUE7UUFDckYsTUFBTSxFQUFFLEdBQUcsRUFBRSxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsR0FBRyxNQUFNLGdCQUFnQixDQUNoRSxHQUFHLEVBQ0gsTUFBTSxFQUNOLE9BQU8sRUFDUCxNQUFNLEVBQ04sT0FBTyxFQUNQLGNBQWMsQ0FBQyxHQUFHLENBQUMsS0FBSyxFQUN4QixjQUFjLENBQUMsWUFBWSxFQUMzQixVQUFVLENBQ2IsQ0FBQTtRQUNELE1BQU0sbUJBQW1CLEdBQUcsTUFBTSxDQUFDLFdBQVcsQ0FBQyxHQUFHLENBQUMsQ0FBQTtRQUNu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LEVBQUUsTUFBTTtnQkFDbkIsT0FBTzthQUNWO1NBQ0osQ0FBQyxFQUNGLHVCQUF1QixDQUMxQixDQUFBO0lBQ0wsQ0FBQztBQUNMLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBqc29uUmVzcG9uc2UsIG9rUmVzcG9uc2UsIHRocm93T25Ob3RPSyB9IGZyb20gJ0ByaWRkYW5jZS9mZXRjaCdcbmltcG9ydCB7IFJlZmxlY3Rpb24gfSBmcm9tICdAcmlkZGFuY2UvaG9zdC9yZWZsZWN0J1xuaW1wb3J0IHsgaXNEZWVwU3RyaWN0RXF1YWwgfSBmcm9tICdub2RlOnV0aWwnXG5pbXBvcnQgeyBjb21wYXJlIH0gZnJvbSAnLi4vZGlmZi5qcydcbmltcG9ydCB7IExvY2FsRW52LCBhd3NSZXF1ZXN0LCByZXRyeUNvbmZsaWN0IH0gZnJvbSAnLi4vbGl0ZS5qcydcblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHN5bmNHYXRld2F5KFxuICAgIGVudjogTG9jYWxFbnYsXG4gICAgcmVnaW9uOiBzdHJpbmcgfCB1bmRlZmluZWQsXG4gICAgYWNjb3VudDogc3RyaW5nIHwgdW5kZWZpbmVkLFxuICAgIHByZWZpeDogc3RyaW5nLFxuICAgIHNlcnZpY2U6IHN0cmluZyxcbiAgICBjdXJyZW50R2F0ZXdheTogQXdzR2F0ZXdheSxcbiAgICByZWZsZWN0aW9uOiBSZWZsZWN0aW9uLFxuICAgIGNvcnNTaXRlczogc3RyaW5nW10sXG4pIHtcbiAgICBpZiAoY3VycmVudEdhdGV3YXkuYXBpKSB7XG4gICAgICAgIGF3YWl0IHN5bmNHYXRld2F5QXBpKGN1cnJlbnRHYXRld2F5LmFwaSwgZW52LCBwcmVmaXgsIHNlcnZpY2UsIGNvcnNTaXRlcylcbiAgICAgICAgYXdhaXQgc3luY1N0YWdlKGVudiwgcHJlZml4LCBzZXJ2aWNlLCBjdXJyZW50R2F0ZXdheS5hcGkuYXBpSWQsIGN1cnJlbnRHYXRld2F5LnN0YWdlKVxuICAgICAgICBjb25zdCB7IGlkcywgc3VycGx1czogc3VycGx1c0ludGVncmF0aW9ucyB9ID0gYXdhaXQgc3luY0ludGVncmF0aW9ucyhcbiAgICAgICAgICAgIGVudixcbiAgICAgICAgICAgIHJlZ2lvbixcbiAgICAgICAgICAgIGFjY291bnQsXG4gICAgICAgICAgICBwcmVmaXgsXG4gICAgICAgICAgICBzZXJ2aWNlLFxuICAgICAgICAgICAgY3VycmVudEdhdGV3YXkuYXBpLmFwaUlkLFxuICAgICAgICAgICAgY3VycmVudEdhdGV3YXkuaW50ZWdyYXRpb25zLFxuICAgICAgICAgICAgcmVmbGVjdGlvbixcbiAgICAgICAgKVxuICAgICAgICBjb25zdCBpbnRlZ3JhdGlvbklkQnlOYW1lID0gT2JqZWN0LmZyb21FbnRyaWVzKGlkcylcbiAgICAgICAgY29uc3QgbmFtZUJ5VGFyZ2V0ID0gT2JqZWN0LmZyb21FbnRyaWVzKFxuICAgICAgICAgICAgaWRzLm1hcCgoW25hbWUsIGludGVncmF0aW9uSWRdKSA9PiBbYGludGVncmF0aW9ucy8ke2ludGVncmF0aW9uSWR9YCwgbmFtZV0pLFxuICAgICAgICApXG5cbiAgICAgICAgY29uc3QgeyBtaXNzaW5nLCBzdXJwbHVzLCBleGlzdGluZyB9ID0gY29tcGFyZShcbiAgICAgICAgICAgIHJlZmxlY3Rpb24uaHR0cCxcbiAgICAgICAgICAgIGN1cnJlbnRHYXRld2F5LnJvdXRlcy5tYXAociA9PiAoe1xuICAgICAgICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tbm9uLW51bGwtYXNzZXJ0aW9uXG4gICAgICAgICAgICAgICAgbmFtZTogbmFtZUJ5VGFyZ2V0W3IudGFyZ2V0XSEsXG4gICAgICAgICAgICAgICAgLi4ucixcbiAgICAgICAgICAgIH0pKSxcbiAgICAgICAgKVxuICAgICAgICBhd2FpdCBQcm9taXNlLmFsbChzdXJwbHVzLm1hcChpID0+IGRlbGV0ZVJvdXRlKGVudiwgY3VycmVudEdhdGV3YXkuYXBpLmFwaUlkLCBpKSkpXG4gICAgICAgIGF3YWl0IFByb21pc2UuYWxsKFtcbiAgICAgICAgICAgIC4uLm1pc3NpbmcubWFwKGZuID0+XG4gICAgICAgICAgICAgICAgY3JlYXRlUm91dGUoXG4gICAgICAgICAgICAgICAgICAgIGVudixcbiAgICAgICAgICAgICAgICAgICAgY3VycmVudEdhdGV3YXkuYXBpLmFwaUlkLFxuICAgICAgICAgICAgICAgICAgICBhc1JvdXRlKGludGVncmF0aW9uSWRCeU5hbWVbZm4ubmFtZV0sIGZuKSxcbiAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgKSxcbiAgICAgICAgICAgIC4uLmV4aXN0aW5nLm1hcChhc3luYyAoeyBuYW1lLCByb3V0ZUlkLCAuLi5leCB9KSA9PiB7XG4gICAgICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1ub24tbnVsbC1hc3NlcnRpb25cbiAgICAgICAgICAgICAgICBjb25zdCBmbiA9IHJlZmxlY3Rpb24uaHR0cC5maW5kKGYgPT4gZi5uYW1lID09PSBuYW1lKSFcbiAgICAgICAgICAgICAgICBjb25zdCByb3V0ZSA9IGFzUm91dGUoaW50ZWdyYXRpb25JZEJ5TmFtZVtmbi5uYW1lXSwgZm4pXG4gICAgICAgICAgICAgICAgaWYgKGlzRGVlcFN0cmljdEVxdWFsKGV4LCByb3V0ZSkpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGF3YWl0IHVwZGF0ZVJvdXRlKGVudiwgY3VycmVudEdhdGV3YXkuYXBpLmFwaUlkLCByb3V0ZUlkLCByb3V0ZSlcbiAgICAgICAgICAgIH0pLFxuICAgICAgICBdKVxuICAgICAgICBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgICAgICAgIHN1cnBsdXNJbnRlZ3JhdGlvbnMubWFwKGkgPT5cbiAgICAgICAgICAgICAgICBkZWxldGVJbnRlZ3JhdGlvbihlbnYsIHJlZ2lvbiwgYWNjb3VudCwgY3VycmVudEdhdGV3YXkuYXBpLmFwaUlkLCBpLmludGVncmF0aW9uSWQpLFxuICAgICAgICAgICAgKSxcbiAgICAgICAgKVxuICAgICAgICByZXR1cm4gY3VycmVudEdhdGV3YXkuYXBpLmFwaUlkXG4gICAgfSBlbHNlIHtcbiAgICAgICAgY29uc3QgZ2F0ZXdheSA9IGF3YWl0IGNyZWF0ZUdhdGV3YXkoZW52LCBwcmVmaXgsIHNlcnZpY2UsIGNvcnNTaXRlcylcbiAgICAgICAgY29uc3QgaWRzID0gYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICAgICAgICByZWZsZWN0aW9uLmh0dHAubWFwKGZuID0+XG4gICAgICAgICAgICAgICAgY3JlYXRlSW50ZWdyYXRpb24oXG4gICAgICAgICAgICAgICAgICAgIGVudixcbiAgICAgICAgICAgICAgICAgICAgZ2F0ZXdheS5hcGlJZCxcbiAgICAgICAgICAgICAgICAgICAgZm4ubmFtZSxcbiAgICAgICAgICAgICAgICAgICAgYXNJbnRlZ3JhdGlvbihyZWdpb24sIGFjY291bnQsIHByZWZpeCwgc2VydmljZSwgZm4pLFxuICAgICAgICAgICAgICAgICksXG4gICAgICAgICAgICApLFxuICAgICAgICApXG4gICAgICAgIGNvbnN0IGludGVncmF0aW9uSWRCeU5hbWUgPSBPYmplY3QuZnJvbUVudHJpZXMoaWRzKVxuICAgICAgICBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgICAgICAgIHJlZmxlY3Rpb24uaHR0cC5tYXAoZm4gPT5cbiAgICAgICAgICAgICAgICBjcmVhdGVSb3V0ZShlbnYsIGdhdGV3YXkuYXBpSWQsIGFzUm91dGUoaW50ZWdyYXRpb25JZEJ5TmFtZVtmbi5uYW1lXSwgZm4pKSxcbiAgICAgICAgICAgICksXG4gICAgICAgIClcbiAgICAgICAgcmV0dXJuIGdhdGV3YXkuYXBpSWRcbiAgICB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHN5bmNJbnRlZ3JhdGlvbnMoXG4gICAgZW52OiBMb2NhbEVudixcbiAgICByZWdpb246IHN0cmluZyB8IHVuZGVmaW5lZCxcbiAgICBhY2NvdW50OiBzdHJpbmcgfCB1bmRlZmluZWQsXG4gICAgcHJlZml4OiBzdHJpbmcsXG4gICAgc2VydmljZTogc3RyaW5nLFxuICAgIGFwaUlkOiBzdHJpbmcsXG4gICAgY3VycmVudEludGVncmF0aW9uczogKEF3c0ludGVncmF0aW9uICYgeyBuYW1lOiBzdHJpbmc7IGludGVncmF0aW9uSWQ6IHN0cmluZyB9KVtdLFxuICAgIHJlZmxlY3Rpb246IFJlZmxlY3Rpb24sXG4pIHtcbiAgICBjb25zdCB7IG1pc3NpbmcsIHN1cnBsdXMsIGV4aXN0aW5nIH0gPSBjb21wYXJlKHJlZmxlY3Rpb24uaHR0cCwgY3VycmVudEludGVncmF0aW9ucylcbiAgICBjb25zdCBpZHMgPSBhd2FpdCBQcm9taXNlLmFsbChbXG4gICAgICAgIC4uLm1pc3NpbmcubWFwKGZuID0+XG4gICAgICAgICAgICBjcmVhdGVJbnRlZ3JhdGlvbihcbiAgICAgICAgICAgICAgICBlbnYsXG4gICAgICAgICAgICAgICAgYXBpSWQsXG4gICAgICAgICAgICAgICAgZm4ubmFtZSxcbiAgICAgICAgICAgICAgICBhc0ludGVncmF0aW9uKHJlZ2lvbiwgYWNjb3VudCwgcHJlZml4LCBzZXJ2aWNlLCBmbiksXG4gICAgICAgICAgICApLFxuICAgICAgICApLFxuICAgICAgICAuLi5leGlzdGluZy5tYXAoYXN5bmMgKHsgbmFtZSwgaW50ZWdyYXRpb25JZCwgLi4uZXggfSkgPT4ge1xuICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1ub24tbnVsbC1hc3NlcnRpb25cbiAgICAgICAgICAgIGNvbnN0IGZuID0gcmVmbGVjdGlvbi5odHRwLmZpbmQoZiA9PiBmLm5hbWUgPT09IG5hbWUpIVxuICAgICAgICAgICAgY29uc3QgaW50ZWdyYXRpb24gPSBhc0ludGVncmF0aW9uKHJlZ2lvbiwgYWNjb3VudCwgcHJlZml4LCBzZXJ2aWNlLCBmbilcbiAgICAgICAgICAgIGlmIChpc0RlZXBTdHJpY3RFcXVhbChleCwgaW50ZWdyYXRpb24pKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIFtuYW1lLCBpbnRlZ3JhdGlvbklkXSBhcyBbc3RyaW5nLCBzdHJpbmddXG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBhd2FpdCB1cGRhdGVJbnRlZ3JhdGlvbihlbnYsIGFwaUlkLCBpbnRlZ3JhdGlvbklkLCBpbnRlZ3JhdGlvbilcbiAgICAgICAgICAgIHJldHVybiBbbmFtZSwgaW50ZWdyYXRpb25JZF0gYXMgW3N0cmluZywgc3RyaW5nXVxuICAgICAgICB9KSxcbiAgICBdKVxuICAgIHJldHVybiB7IGlkcywgc3VycGx1cyB9XG59XG5cbnR5cGUgQXdzR2F0ZXdheSA9IEF3YWl0ZWQ8UmV0dXJuVHlwZTx0eXBlb2YgZ2V0QXBpPj5cblxuZXhwb3J0IHR5cGUgQXdzR2F0ZXdheUFwaSA9IHtcbiAgICBhcGlJZDogc3RyaW5nXG4gICAgbmFtZTogc3RyaW5nXG4gICAgcHJvdG9jb2xUeXBlOiAnSFRUUCcgfCAnUkVTVCdcbiAgICBhcGlFbmRwb2ludDogc3RyaW5nXG4gICAgY29yc0NvbmZpZ3VyYXRpb246IHtcbiAgICAgICAgYWxsb3dPcmlnaW5zOiBzdHJpbmdbXVxuICAgICAgICBhbGxvd0NyZWRlbnRpYWxzOiBmYWxzZVxuICAgICAgICBtYXhBZ2U6IG51bWJlclxuICAgICAgICBhbGxvd01ldGhvZHM6IHN0cmluZ1tdXG4gICAgICAgIGFsbG93SGVhZGVyczogc3RyaW5nW11cbiAgICAgICAgZXhwb3NlSGVhZGVyczogc3RyaW5nW11cbiAgICB9XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiogZ2V0QXBpcyhlbnY6IExvY2FsRW52LCBwcmVmaXg6IHN0cmluZykge1xuICAgIGZvciAobGV0IG5leHQgPSAnJzsgOyApIHtcbiAgICAgICAgY29uc3QgcGFnZSA9IGF3YWl0IGpzb25SZXNwb25zZTx7IGl0ZW1zOiBBd3NHYXRld2F5QXBpW107IG5leHRUb2tlbj86IHN0cmluZyB9PihcbiAgICAgICAgICAgIGF3c1JlcXVlc3QoZW52LCAnR0VUJywgJ2FwaWdhdGV3YXknLCBgL3YyL2FwaXMvJHtuZXh0fWApLFxuICAgICAgICAgICAgJ0Vycm9yIGdldHRpbmcgQVBJcy4nLFxuICAgICAgICApXG4gICAgICAgIGZvciAoY29uc3QgaXRlbSBvZiBwYWdlLml0ZW1zLmZpbHRlcihhID0+IGEubmFtZS5zdGFydHNXaXRoKGAke3ByZWZpeH0tYCkpKSB7XG4gICAgICAgICAgICB5aWVsZCBpdGVtXG4gICAgICAgIH1cbiAgICAgICAgaWYgKCFwYWdlLm5leHRUb2tlbikge1xuICAgICAgICAgICAgYnJlYWtcbiAgICAgICAgfVxuICAgICAgICBuZXh0ID0gYD9uZXh0VG9rZW49JHtlbmNvZGVVUklDb21wb25lbnQocGFnZS5uZXh0VG9rZW4pfWBcbiAgICB9XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBnZXRBcGkoZW52OiBMb2NhbEVudiwgcHJlZml4OiBzdHJpbmcsIHNlcnZpY2U6IHN0cmluZykge1xuICAgIGNvbnN0IG5hbWUgPSBgJHtwcmVmaXh9LSR7c2VydmljZX1gXG4gICAgZm9yIGF3YWl0IChjb25zdCBhcGkgb2YgZ2V0QXBpcyhlbnYsIHByZWZpeCkpIHtcbiAgICAgICAgaWYgKGFwaS5uYW1lID09PSBuYW1lKSB7XG4gICAgICAgICAgICBjb25zdCBbaW50ZWdyYXRpb25zLCByb3V0ZXMsIHN0YWdlXSA9IGF3YWl0IFByb21pc2UuYWxsKFtcbiAgICAgICAgICAgICAgICBnZXRJbnRlZ3JhdGlvbnMoZW52LCBhcGkuYXBpSWQsIG5hbWUubGVuZ3RoICsgMSksXG4gICAgICAgICAgICAgICAgZ2V0Um91dGVzKGVudiwgYXBpLmFwaUlkKSxcbiAgICAgICAgICAgICAgICBnZXRTdGFnZShlbnYsIGFwaS5hcGlJZCksXG4gICAgICAgICAgICBdKVxuICAgICAgICAgICAgcmV0dXJuIHsgYXBpLCBpbnRlZ3JhdGlvbnMsIHJvdXRlczogcm91dGVzLml0ZW1zLCBzdGFnZSB9XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHsgaW50ZWdyYXRpb25zOiBbXSwgcm91dGVzOiBbXSB9XG59XG5cbmV4cG9ydCB0eXBlIEF3c0ludGVncmF0aW9uID0ge1xuICAgIHBheWxvYWRGb3JtYXRWZXJzaW9uOiAnMi4wJ1xuICAgIGludGVncmF0aW9uVHlwZTogJ0FXU19QUk9YWSdcbiAgICBpbnRlZ3JhdGlvbk1ldGhvZDogc3RyaW5nXG4gICAgaW50ZWdyYXRpb25Vcmk6IHN0cmluZ1xuICAgIGNvbm5lY3Rpb25UeXBlOiAnSU5URVJORVQnXG4gICAgdGltZW91dEluTWlsbGlzOiBudW1iZXIgfCB1bmRlZmluZWRcbn1cblxuYXN5bmMgZnVuY3Rpb24gZ2V0SW50ZWdyYXRpb25zKGVudjogTG9jYWxFbnYsIGFwaUlkOiBzdHJpbmcsIHByZWZpeExlbmd0aDogbnVtYmVyKSB7XG4gICAgY29uc3QgeyBpdGVtcyB9ID0gYXdhaXQganNvblJlc3BvbnNlPHtcbiAgICAgICAgaXRlbXM6IChBd3NJbnRlZ3JhdGlvbiAmIHsgaW50ZWdyYXRpb25JZDogc3RyaW5nIH0pW11cbiAgICB9PihcbiAgICAgICAgYXdzUmVxdWVzdChlbnYsICdHRVQnLCAnYXBpZ2F0ZXdheScsIGAvdjIvYXBpcy8ke2FwaUlkfS9pbnRlZ3JhdGlvbnNgKSxcbiAgICAgICAgJ0Vycm9yIGdldHRpbmcgQVBJIGludGVncmF0aW9ucy4nLFxuICAgIClcbiAgICByZXR1cm4gaXRlbXMubWFwKGkgPT4gKHtcbiAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1ub24tbnVsbC1hc3NlcnRpb25cbiAgICAgICAgbmFtZTogaS5pbnRlZ3JhdGlvblVyaS5zcGxpdCgnOicpLmF0KC0xKSEuc2xpY2UocHJlZml4TGVuZ3RoKSxcbiAgICAgICAgLi4uaSxcbiAgICB9KSlcbn1cblxuZnVuY3Rpb24gYXNJbnRlZ3JhdGlvbihcbiAgICByZWdpb246IHN0cmluZyB8IHVuZGVmaW5lZCxcbiAgICBhY2NvdW50OiBzdHJpbmcgfCB1bmRlZmluZWQsXG4gICAgcHJlZml4OiBzdHJpbmcsXG4gICAgc2VydmljZTogc3RyaW5nLFxuICAgIGZuOiB7IG5hbWU6IHN0cmluZzsgbWV0aG9kOiBzdHJpbmc7IHBhdGhQYXR0ZXJuOiBzdHJpbmc7IGNvbmZpZzogeyB0aW1lb3V0PzogbnVtYmVyIH0gfSxcbik6IEF3c0ludGVncmF0aW9uIHtcbiAgICBpZiAoIXJlZ2lvbiB8fCAhYWNjb3VudCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1dlaXJkJylcbiAgICB9XG4gICAgcmV0dXJuIHtcbiAgICAgICAgcGF5bG9hZEZvcm1hdFZlcnNpb246ICcyLjAnLFxuICAgICAgICBpbnRlZ3JhdGlvblR5cGU6ICdBV1NfUFJPWFknLFxuICAgICAgICBpbnRlZ3JhdGlvbk1ldGhvZDogZm4ubWV0aG9kLFxuICAgICAgICBpbnRlZ3JhdGlvblVyaTogYGFybjphd3M6bGFtYmRhOiR7cmVnaW9ufToke2FjY291bnR9OmZ1bmN0aW9uOiR7cHJlZml4fS0ke3NlcnZpY2V9LSR7Zm4ubmFtZX1gLFxuICAgICAgICBjb25uZWN0aW9uVHlwZTogJ0lOVEVSTkVUJyxcbiAgICAgICAgdGltZW91dEluTWlsbGlzOiBNYXRoLm1pbigoKGZuLmNvbmZpZy50aW1lb3V0ID8/IDE1KSArIDUpICogMTAwMCwgMzBfMDAwKSxcbiAgICB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGNyZWF0ZUludGVncmF0aW9uKFxuICAgIGVudjogTG9jYWxFbnYsXG4gICAgYXBpSWQ6IHN0cmluZyxcbiAgICBuYW1lOiBzdHJpbmcsXG4gICAgaW50ZWdyYXRpb246IEF3c0ludGVncmF0aW9uLFxuKSB7XG4gICAgY29uc29sZS5sb2coJ2NyZWF0aW5nIEFQSSBpbnRlZ3JhdGlvbicpXG4gICAgY29uc3QgY3JlYXRlZCA9IGF3YWl0IHJldHJ5Q29uZmxpY3QoKCkgPT5cbiAgICAgICAganNvblJlc3BvbnNlPHsgaW50ZWdyYXRpb25JZDogc3RyaW5nIH0+KFxuICAgICAgICAgICAgYXdzUmVxdWVzdChlbnYsICdQT1NUJywgJ2FwaWdhdGV3YXknLCBgL3YyL2FwaXMvJHthcGlJZH0vaW50ZWdyYXRpb25zYCwgaW50ZWdyYXRpb24pLFxuICAgICAgICAgICAgJ0Vycm9yIGNyZWF0aW5nIEFQSSBpbnRlZ3JhdGlvbi4nLFxuICAgICAgICApLFxuICAgIClcbiAgICBjb25zb2xlLmxvZyhgICBmcm9tICR7YXBpSWR9IHRvICR7aW50ZWdyYXRpb24uaW50ZWdyYXRpb25Vcml9IGFzICR7Y3JlYXRlZC5pbnRlZ3JhdGlvbklkfWApXG4gICAgcmV0dXJuIFtuYW1lLCBjcmVhdGVkLmludGVncmF0aW9uSWRdIGFzIFtzdHJpbmcsIHN0cmluZ11cbn1cblxuYXN5bmMgZnVuY3Rpb24gdXBkYXRlSW50ZWdyYXRpb24oXG4gICAgZW52OiBMb2NhbEVudixcbiAgICBhcGlJZDogc3RyaW5nLFxuICAgIGlkOiBzdHJpbmcsXG4gICAgaW50ZWdyYXRpb246IEF3c0ludGVncmF0aW9uLFxuKSB7XG4gICAgY29uc29sZS5sb2coJ3VwZGF0aW5nIEFQSSBpbnRlZ3JhdGlvbiAnICsgaWQpXG4gICAgY29uc29sZS5sb2coYCAgZnJvbSAke2FwaUlkfSB0byAke2ludGVncmF0aW9uLmludGVncmF0aW9uVXJpfWApXG4gICAgYXdhaXQgb2tSZXNwb25zZShcbiAgICAgICAgYXdzUmVxdWVzdChlbnYsICdQQVRDSCcsICdhcGlnYXRld2F5JywgYC92Mi9hcGlzLyR7YXBpSWR9L2ludGVncmF0aW9ucy8ke2lkfWAsIGludGVncmF0aW9uKSxcbiAgICAgICAgJ0Vycm9yIHVwZGF0aW5nIEFQSSBpbnRlZ3JhdGlvbicsXG4gICAgKVxufVxuXG5hc3luYyBmdW5jdGlvbiBkZWxldGVJbnRlZ3JhdGlvbihcbiAgICBlbnY6IExvY2FsRW52LFxuICAgIHJlZ2lvbjogc3RyaW5nIHwgdW5kZWZpbmVkLFxuICAgIGFjY291bnQ6IHN0cmluZyB8IHVuZGVmaW5lZCxcbiAgICBhcGlJZDogc3RyaW5nLFxuICAgIGlkOiBzdHJpbmcsXG4pIHtcbiAgICBpZiAoIXJlZ2lvbiB8fCAhYWNjb3VudCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1dlaXJkJylcbiAgICB9XG4gICAgY29uc29sZS5sb2coJ2RlbGV0aW5nIEFQSSBpbnRlZ3JhdGlvbiAnICsgaWQpXG4gICAgYXdhaXQgb2tSZXNwb25zZShcbiAgICAgICAgYXdzUmVxdWVzdChlbnYsICdERUxFVEUnLCAnYXBpZ2F0ZXdheScsIGAvdjIvYXBpcy8ke2FwaUlkfS9pbnRlZ3JhdGlvbnMvJHtpZH1gKSxcbiAgICAgICAgJ0Vycm9yIGRlbGV0aW5nIEFQSSBpbnRlZ3JhdGlvbi4nLFxuICAgIClcbn1cblxuZXhwb3J0IHR5cGUgQXdzUm91dGUgPSB7XG4gICAgcm91dGVLZXk6IHN0cmluZ1xuICAgIGF1dGhvcml6YXRpb25UeXBlOiAnTk9ORSdcbiAgICBhcGlLZXlSZXF1aXJlZDogZmFsc2VcbiAgICB0YXJnZXQ6IHN0cmluZ1xufVxuXG5mdW5jdGlvbiBhc1JvdXRlKFxuICAgIGludGVncmF0aW9uSWQ6IHN0cmluZyB8IHVuZGVmaW5lZCxcbiAgICBmbjogeyBtZXRob2Q6IHN0cmluZzsgcGF0aFBhdHRlcm46IHN0cmluZyB9LFxuKTogQXdzUm91dGUge1xuICAgIGlmICghaW50ZWdyYXRpb25JZCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFdlaXJkOiBubyBpbnRlZ3JhdGlvbiBJRCBmb3IgJHtmbi5tZXRob2R9ICR7Zm4ucGF0aFBhdHRlcm59YClcbiAgICB9XG4gICAgbGV0IHAgPSAwXG4gICAgcmV0dXJuIHtcbiAgICAgICAgcm91dGVLZXk6IGAke2ZuLm1ldGhvZH0gLyR7dHJpbVRyYWlsaW5nU2xhc2goXG4gICAgICAgICAgICBmbi5wYXRoUGF0dGVybi5yZXBsYWNlQWxsKCcqJywgKCkgPT4gYHtwJHsrK3B9fWApLFxuICAgICAgICApfWAsXG4gICAgICAgIGF1dGhvcml6YXRpb25UeXBlOiAnTk9ORScsXG4gICAgICAgIGFwaUtleVJlcXVpcmVkOiBmYWxzZSxcbiAgICAgICAgdGFyZ2V0OiBgaW50ZWdyYXRpb25zLyR7aW50ZWdyYXRpb25JZH1gLFxuICAgIH1cbn1cblxuZnVuY3Rpb24gdHJpbVRyYWlsaW5nU2xhc2gocGF0aFBhdHRlcm46IHN0cmluZykge1xuICAgIGlmIChwYXRoUGF0dGVybi5lbmRzV2l0aCgnLycpKSB7XG4gICAgICAgIHJldHVybiBwYXRoUGF0dGVybi5zbGljZSgwLCBNYXRoLm1heCgwLCBwYXRoUGF0dGVybi5sZW5ndGggLSAxKSlcbiAgICB9XG4gICAgcmV0dXJuIHBhdGhQYXR0ZXJuXG59XG5cbmFzeW5jIGZ1bmN0aW9uIGdldFJvdXRlcyhlbnY6IExvY2FsRW52LCBhcGlJZDogc3RyaW5nKSB7XG4gICAgcmV0dXJuIGF3YWl0IGpzb25SZXNwb25zZTx7XG4gICAgICAgIGl0ZW1zOiAoQXdzUm91dGUgJiB7IHJvdXRlSWQ6IHN0cmluZyB9KVtdXG4gICAgfT4oXG4gICAgICAgIGF3c1JlcXVlc3QoZW52LCAnR0VUJywgJ2FwaWdhdGV3YXknLCBgL3YyL2FwaXMvJHthcGlJZH0vcm91dGVzYCksXG4gICAgICAgICdFcnJvciBnZXR0aW5nIEFQSSByb3V0ZXMuJyxcbiAgICApXG59XG5cbmFzeW5jIGZ1bmN0aW9uIGNyZWF0ZVJvdXRlKGVudjogTG9jYWxFbnYsIGFwaUlkOiBzdHJpbmcsIHJvdXRlOiBBd3NSb3V0ZSkge1xuICAgIGNvbnNvbGUubG9nKGBjcmVhdGluZyByb3V0ZSAke3JvdXRlLnJvdXRlS2V5fSB0byAke3JvdXRlLnRhcmdldH1gKVxuICAgIGF3YWl0IHJldHJ5Q29uZmxpY3QoKCkgPT5cbiAgICAgICAgb2tSZXNwb25zZShcbiAgICAgICAgICAgIGF3c1JlcXVlc3QoZW52LCAnUE9TVCcsICdhcGlnYXRld2F5JywgYC92Mi9hcGlzLyR7YXBpSWR9L3JvdXRlc2AsIHJvdXRlKSxcbiAgICAgICAgICAgICdFcnJvciBjcmVhdGluZyBBUEkgcm91dGUuJyxcbiAgICAgICAgKSxcbiAgICApXG59XG5cbmFzeW5jIGZ1bmN0aW9uIHVwZGF0ZVJvdXRlKGVudjogTG9jYWxFbnYsIGFwaUlkOiBzdHJpbmcsIGlkOiBzdHJpbmcsIHJvdXRlOiBBd3NSb3V0ZSkge1xuICAgIGNvbnNvbGUubG9nKGB1cGRhdGluZyBBUEkgcm91dGUgJHtpZH0gdG8gJHtyb3V0ZS50YXJnZXR9YClcbiAgICBhd2FpdCBva1Jlc3BvbnNlKFxuICAgICAgICBhd3NSZXF1ZXN0KGVudiwgJ1BBVENIJywgJ2FwaWdhdGV3YXknLCBgL3YyL2FwaXMvJHthcGlJZH0vcm91dGVzLyR7aWR9YCwgcm91dGUpLFxuICAgICAgICAnRXJyb3IgdXBkYXRpbmcgQVBJIHJvdXRlLicsXG4gICAgKVxufVxuXG5hc3luYyBmdW5jdGlvbiBkZWxldGVSb3V0ZShlbnY6IExvY2FsRW52LCBhcGlJZDogc3RyaW5nLCByb3V0ZTogQXdzUm91dGUgJiB7IHJvdXRlSWQ6IHN0cmluZyB9KSB7XG4gICAgY29uc29sZS5sb2coYGRlbGV0aW5nIEFQSSByb3V0ZSAke3JvdXRlLnJvdXRlSWR9IGZyb20gJHtyb3V0ZS50YXJnZXR9YClcbiAgICBhd2FpdCBva1Jlc3BvbnNlKFxuICAgICAgICBhd3NSZXF1ZXN0KGVudiwgJ0RFTEVURScsICdhcGlnYXRld2F5JywgYC92Mi9hcGlzLyR7YXBpSWR9L3JvdXRlcy8ke3JvdXRlLnJvdXRlSWR9YCksXG4gICAgICAgICdFcnJvciBkZWxldGluZyBBUEkgcm91dGUuJyxcbiAgICApXG59XG5cbmFzeW5jIGZ1bmN0aW9uIGNyZWF0ZUdhdGV3YXkoZW52OiBMb2NhbEVudiwgcHJlZml4OiBzdHJpbmcsIHNlcnZpY2U6IHN0cmluZywgY29yc1NpdGVzOiBzdHJpbmdbXSkge1xuICAgIGNvbnNvbGUubG9nKCdjcmVhdGluZyBnYXRld2F5JylcbiAgICBjb25zdCBnYXRld2F5ID0gYXdhaXQganNvblJlc3BvbnNlPHsgYXBpSWQ6IHN0cmluZyB9PihcbiAgICAgICAgYXdzUmVxdWVzdChlbnYsICdQT1NUJywgJ2FwaWdhdGV3YXknLCBgL3YyL2FwaXMvYCwge1xuICAgICAgICAgICAgbmFtZTogYCR7cHJlZml4fS0ke3NlcnZpY2V9YCxcbiAgICAgICAgICAgIHByb3RvY29sVHlwZTogJ0hUVFAnLFxuICAgICAgICAgICAgY29yc0NvbmZpZ3VyYXRpb246IGNvcnNTZXR0aW5ncyhjb3JzU2l0ZXMpLFxuICAgICAgICAgICAgdGFnczoge1xuICAgICAgICAgICAgICAgIGZyYW1ld29yazogJ3JpZGRhbmNlJyxcbiAgICAgICAgICAgICAgICBlbnZpcm9ubWVudDogcHJlZml4LFxuICAgICAgICAgICAgICAgIHNlcnZpY2UsXG4gICAgICAgICAgICB9LFxuICAgICAgICB9KSxcbiAgICAgICAgJ0Vycm9yIGNyZWF0aW5nIGdhdGV3YXkuJyxcbiAgICApXG4gICAgYXdhaXQgc3luY1N0YWdlKGVudiwgcHJlZml4LCBzZXJ2aWNlLCBnYXRld2F5LmFwaUlkLCB1bmRlZmluZWQpXG4gICAgcmV0dXJuIGdhdGV3YXlcbn1cblxuYXN5bmMgZnVuY3Rpb24gc3luY0dhdGV3YXlBcGkoXG4gICAgZ2F0ZXdheTogQXdzR2F0ZXdheUFwaSxcbiAgICBlbnY6IExvY2FsRW52LFxuICAgIHByZWZpeDogc3RyaW5nLFxuICAgIHNlcnZpY2U6IHN0cmluZyxcbiAgICBjb3JzU2l0ZXM6IHN0cmluZ1tdLFxuKSB7XG4gICAgY29uc3QgY29yc0NvbmZpZ3VyYXRpb24gPSBjb3JzU2V0dGluZ3MoY29yc1NpdGVzKVxuICAgIGlmIChpc0RlZXBTdHJpY3RFcXVhbChjb3JzQ29uZmlndXJhdGlvbiwgZ2F0ZXdheS5jb3JzQ29uZmlndXJhdGlvbikpIHtcbiAgICAgICAgcmV0dXJuXG4gICAgfVxuICAgIGNvbnNvbGUubG9nKCd1cGRhdGluZyBnYXRld2F5JylcbiAgICBhd2FpdCBva1Jlc3BvbnNlKFxuICAgICAgICBhd3NSZXF1ZXN0KGVudiwgJ1BBVENIJywgJ2FwaWdhdGV3YXknLCBgL3YyL2FwaXMvJHtnYXRld2F5LmFwaUlkfWAsIHtcbiAgICAgICAgICAgIG5hbWU6IGAke3ByZWZpeH0tJHtzZXJ2aWNlfWAsXG4gICAgICAgICAgICBwcm90b2NvbFR5cGU6ICdIVFRQJyxcbiAgICAgICAgICAgIGNvcnNDb25maWd1cmF0aW9uLFxuICAgICAgICAgICAgdGFnczoge1xuICAgICAgICAgICAgICAgIGZyYW1ld29yazogJ3JpZGRhbmNlJyxcbiAgICAgICAgICAgICAgICBlbnZpcm9ubWVudDogcHJlZml4LFxuICAgICAgICAgICAgICAgIHNlcnZpY2UsXG4gICAgICAgICAgICB9LFxuICAgICAgICB9KSxcbiAgICAgICAgJ0Vycm9yIHVwZGF0aW5nIGdhdGV3YXkuJyxcbiAgICApXG59XG5cbmZ1bmN0aW9uIGNvcnNTZXR0aW5ncyhjb3JzU2l0ZXM6IHN0cmluZ1tdKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgICAgYWxsb3dPcmlnaW5zOiBjb3JzU2l0ZXMsXG4gICAgICAgIGFsbG93Q3JlZGVudGlhbHM6ICFpc0RlZXBTdHJpY3RFcXVhbChjb3JzU2l0ZXMsIFsnKiddKSxcbiAgICAgICAgbWF4QWdlOiA2MDAsXG4gICAgICAgIGFsbG93TWV0aG9kczogWycqJ10sXG4gICAgICAgIGFsbG93SGVhZGVyczogWycqJ10sXG4gICAgICAgIGV4cG9zZUhlYWRlcnM6IFsnKiddLFxuICAgIH1cbn1cblxuZXhwb3J0IHR5cGUgQXBpU3RhZ2UgPSB7XG4gICAgc3RhZ2VOYW1lOiBzdHJpbmdcbiAgICBkZXNjcmlwdGlvbjogc3RyaW5nXG4gICAgZGVwbG95bWVudElkOiBzdHJpbmdcbiAgICBjbGllbnRDZXJ0aWZpY2F0ZUlkOiBzdHJpbmdcbiAgICBkZWZhdWx0Um91dGVTZXR0aW5nczoge1xuICAgICAgICBkZXRhaWxlZE1ldHJpY3NFbmFibGVkOiBib29sZWFuXG4gICAgICAgIGxvZ2dpbmdMZXZlbDogJ0lORk8nIHwgJ0VSUk9SJyB8ICdPRkYnXG4gICAgICAgIGRhdGFUcmFjZUVuYWJsZWQ6IGJvb2xlYW5cbiAgICAgICAgdGhyb3R0bGluZ0J1cnN0TGltaXQ6IG51bWJlclxuICAgICAgICB0aHJvdHRsaW5nUmF0ZUxpbWl0OiBudW1iZXJcbiAgICB9XG4gICAgcm91dGVTZXR0aW5nczogeyBba2V5OiBzdHJpbmddOiBzdHJpbmcgfVxuICAgIHN0YWdlVmFyaWFibGVzOiB7IFtrZXk6IHN0cmluZ106IHN0cmluZyB9XG4gICAgYWNjZXNzTG9nU2V0dGluZ3M6IHtcbiAgICAgICAgZm9ybWF0OiBzdHJpbmdcbiAgICAgICAgZGVzdGluYXRpb25Bcm46IHN0cmluZ1xuICAgIH1cbiAgICBhdXRvRGVwbG95OiBib29sZWFuXG4gICAgbGFzdERlcGxveW1lbnRTdGF0dXNNZXNzYWdlOiBzdHJpbmdcbiAgICBjcmVhdGVkRGF0ZTogc3RyaW5nXG4gICAgbGFzdFVwZGF0ZWREYXRlOiBzdHJpbmdcbiAgICB0YWdzOiB7IFtrZXk6IHN0cmluZ106IHN0cmluZyB9XG4gICAgYXBpR2F0ZXdheU1hbmFnZWQ6IGJvb2xlYW5cbn1cblxuYXN5bmMgZnVuY3Rpb24gZ2V0U3RhZ2UoZW52OiBMb2NhbEVudiwgYXBpSWQ6IHN0cmluZykge1xuICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgYXdzUmVxdWVzdChlbnYsICdHRVQnLCAnYXBpZ2F0ZXdheScsIGAvdjIvYXBpcy8ke2FwaUlkfS9zdGFnZXMvJGRlZmF1bHRgKVxuICAgIGlmIChyZXNwb25zZS5zdGF0dXMgPT09IDQwNCkge1xuICAgICAgICByZXR1cm4gdW5kZWZpbmVkXG4gICAgfVxuICAgIGF3YWl0IHRocm93T25Ob3RPSyhyZXNwb25zZSwgJ0Vycm9yIGdldHRpbmcgQVBJIHN0YWdlLicpXG4gICAgcmV0dXJuIChhd2FpdCByZXNwb25zZS5qc29uKCkpIGFzIEFwaVN0YWdlXG59XG5cbmFzeW5jIGZ1bmN0aW9uIHN5bmNTdGFnZShcbiAgICBlbnY6IExvY2FsRW52LFxuICAgIHByZWZpeDogc3RyaW5nLFxuICAgIHNlcnZpY2U6IHN0cmluZyxcbiAgICBhcGlJZDogc3RyaW5nLFxuICAgIHN0YWdlOiBBcGlTdGFnZSB8IHVuZGVmaW5lZCxcbikge1xuICAgIGlmICghc3RhZ2UpIHtcbiAgICAgICAgYXdhaXQgb2tSZXNwb25zZShcbiAgICAgICAgICAgIGF3c1JlcXVlc3QoZW52LCAnUE9TVCcsICdhcGlnYXRld2F5JywgYC92Mi9hcGlzLyR7YXBpSWR9L3N0YWdlc2AsIHtcbiAgICAgICAgICAgICAgICBzdGFnZU5hbWU6ICckZGVmYXVsdCcsXG4gICAgICAgICAgICAgICAgYXV0b0RlcGxveTogdHJ1ZSxcbiAgICAgICAgICAgICAgICB0YWdzOiB7XG4gICAgICAgICAgICAgICAgICAgIGZyYW1ld29yazogJ3JpZGRhbmNlJyxcbiAgICAgICAgICAgICAgICAgICAgZW52aXJvbm1lbnQ6IHByZWZpeCxcbiAgICAgICAgICAgICAgICAgICAgc2VydmljZSxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSksXG4gICAgICAgICAgICAnRXJyb3IgY3JlYXRpbmcgc3RhZ2UuJyxcbiAgICAgICAgKVxuICAgIH1cbn1cbiJdfQ==