@riddance/deploy
Version:
209 lines • 44.7 kB
JavaScript
import { jsonResponse, okResponse, throwOnNotOK } from '@riddance/fetch';
import { isDeepStrictEqual } from 'node:util';
import { compare } from '../diff.js';
import { awsRequest, pages, retryConflict } from '../lite.js';
export async function syncGateway(context, region, account, prefix, service, currentGateway, reflection, corsSites) {
if (currentGateway.api) {
await syncGatewayApi(context, currentGateway.api, prefix, service, corsSites);
await syncStage(context, prefix, service, currentGateway.api.apiId, currentGateway.stage);
const { ids, surplus: surplusIntegrations } = await syncIntegrations(context, 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(context, currentGateway.api.apiId, i)));
await Promise.all([
...missing.map(fn => createRoute(context, 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(context, currentGateway.api.apiId, routeId, route);
}),
]);
await Promise.all(surplusIntegrations.map(i => deleteIntegration(context, region, account, currentGateway.api.apiId, i.integrationId)));
return currentGateway.api.apiId;
}
else {
const gateway = await createGateway(context, prefix, service, corsSites);
const ids = await Promise.all(reflection.http.map(fn => createIntegration(context, gateway.apiId, fn.name, asIntegration(region, account, prefix, service, fn))));
const integrationIdByName = Object.fromEntries(ids);
await Promise.all(reflection.http.map(fn => createRoute(context, gateway.apiId, asRoute(integrationIdByName[fn.name], fn))));
return gateway.apiId;
}
}
async function syncIntegrations(context, region, account, prefix, service, apiId, currentIntegrations, reflection) {
const { missing, surplus, existing } = compare(reflection.http, currentIntegrations);
const ids = await Promise.all([
...missing.map(fn => createIntegration(context, 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(context, apiId, integrationId, integration);
return [name, integrationId];
}),
]);
return { ids, surplus };
}
export function getApis(context, prefix) {
return pages(context, 'apigateway', '/v2/apis/', (items) => items.filter(a => a.name.startsWith(`${prefix}-`)), 'Error getting APIs.');
}
export async function getApi(context, prefix, service) {
const name = `${prefix}-${service}`;
for await (const api of getApis(context, prefix)) {
if (api.name === name) {
const [integrations, routes, stage] = await Promise.all([
Array.fromAsync(getIntegrations(context, api.apiId, name.length + 1)),
Array.fromAsync(getRoutes(context, api.apiId)),
getStage(context, api.apiId),
]);
return { api, integrations, routes, stage };
}
}
return { integrations: [], routes: [] };
}
function getIntegrations(context, apiId, prefixLength) {
return pages(context, 'apigateway', `/v2/apis/${apiId}/integrations`, (items) => items.map(i => ({
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
name: i.integrationUri.split(':').at(-1).slice(prefixLength),
...i,
})), 'Error getting API integrations.');
}
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(context, apiId, name, integration) {
context.log.trace('creating API integration');
const created = await retryConflict(() => jsonResponse(awsRequest(context, 'POST', 'apigateway', `/v2/apis/${apiId}/integrations`, integration), 'Error creating API integration.'));
context.log.trace(` from ${apiId} to ${integration.integrationUri} as ${created.integrationId}`);
return [name, created.integrationId];
}
async function updateIntegration(context, apiId, id, integration) {
context.log.trace('updating API integration ' + id);
context.log.trace(` from ${apiId} to ${integration.integrationUri}`);
await okResponse(awsRequest(context, 'PATCH', 'apigateway', `/v2/apis/${apiId}/integrations/${id}`, integration), 'Error updating API integration');
}
async function deleteIntegration(context, region, account, apiId, id) {
if (!region || !account) {
throw new Error('Weird');
}
context.log.trace('deleting API integration ' + id);
await okResponse(awsRequest(context, '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;
}
function getRoutes(context, apiId) {
return pages(context, 'apigateway', `/v2/apis/${apiId}/routes`, (routes) => routes, 'Error getting API routes.');
}
async function createRoute(context, apiId, route) {
context.log.trace(`creating route ${route.routeKey} to ${route.target}`);
await retryConflict(() => okResponse(awsRequest(context, 'POST', 'apigateway', `/v2/apis/${apiId}/routes`, route), 'Error creating API route.'));
}
async function updateRoute(context, apiId, id, route) {
context.log.trace(`updating API route ${id} to ${route.target}`);
await okResponse(awsRequest(context, 'PATCH', 'apigateway', `/v2/apis/${apiId}/routes/${id}`, route), 'Error updating API route.');
}
async function deleteRoute(context, apiId, route) {
context.log.trace(`deleting API route ${route.routeId} from ${route.target}`);
await okResponse(awsRequest(context, 'DELETE', 'apigateway', `/v2/apis/${apiId}/routes/${route.routeId}`), 'Error deleting API route.');
}
async function createGateway(context, prefix, service, corsSites) {
context.log.trace('creating gateway');
const gateway = await jsonResponse(awsRequest(context, 'POST', 'apigateway', `/v2/apis/`, {
name: `${prefix}-${service}`,
protocolType: 'HTTP',
corsConfiguration: corsSettings(corsSites),
tags: {
framework: 'riddance',
environment: prefix,
service,
},
}), 'Error creating gateway.');
await syncStage(context, prefix, service, gateway.apiId, undefined);
return gateway;
}
async function syncGatewayApi(context, gateway, prefix, service, corsSites) {
const corsConfiguration = corsSettings(corsSites);
if (isDeepStrictEqual(corsConfiguration, gateway.corsConfiguration)) {
return;
}
context.log.trace('updating gateway');
await okResponse(awsRequest(context, '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(context, apiId) {
const response = await awsRequest(context, '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(context, prefix, service, apiId, stage) {
if (!stage) {
await okResponse(awsRequest(context, 'POST', 'apigateway', `/v2/apis/${apiId}/stages`, {
stageName: '$default',
autoDeploy: true,
tags: {
framework: 'riddance',
environment: prefix,
service,
},
}), 'Error creating stage.');
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXBpLWdhdGV3YXkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJhcGktZ2F0ZXdheS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsWUFBWSxFQUFFLFVBQVUsRUFBRSxZQUFZLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQTtBQUV4RSxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxXQUFXLENBQUE7QUFDN0MsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLFlBQVksQ0FBQTtBQUNwQyxPQUFPLEVBQWdCLFVBQVUsRUFBRSxLQUFLLEVBQUUsYUFBYSxFQUFFLE1BQU0sWUFBWSxDQUFBO0FBRTNFLE1BQU0sQ0FBQyxLQUFLLFVBQVUsV0FBVyxDQUM3QixPQUFnQixFQUNoQixNQUEwQixFQUMxQixPQUEyQixFQUMzQixNQUFjLEVBQ2QsT0FBZSxFQUNmLGNBQTBCLEVBQzFCLFVBQXNCLEVBQ3RCLFNBQW1CO0lBRW5CLElBQUksY0FBYyxDQUFDLEdBQUcsRUFBRSxDQUFDO1FBQ3JCLE1BQU0sY0FBYyxDQUFDLE9BQU8sRUFBRSxjQUFjLENBQUMsR0FBRyxFQUFFLE1BQU0sRUFBRSxPQUFPLEVBQUUsU0FBUyxDQUFDLENBQUE7UUFDN0UsTUFBTSxTQUFTLENBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxPQUFPLEVBQUUsY0FBYyxDQUFDLEdBQUcsQ0FBQyxLQUFLLEVBQUUsY0FBYyxDQUFDLEtBQUssQ0FBQyxDQUFBO1FBQ3pGLE1BQU0sRUFBRSxHQUFHLEVBQUUsT0FBTyxFQUFFLG1CQUFtQixFQUFFLEdBQUcsTUFBTSxnQkFBZ0IsQ0FDaEUsT0FBTyxFQUNQLE1BQU0sRUFDTixPQUFPLEVBQ1AsTUFBTSxFQUNOLE9BQU8sRUFDUCxjQUFjLENBQUMsR0FBRyxDQUFDLEtBQUssRUFDeEIsY0FBYyxDQUFDLFlBQVksRUFDM0IsVUFBVSxDQUNiLENBQUE7UUFDRCxNQUFNLG1CQUFtQixHQUFHLE1BQU0sQ0FBQyxXQUFXLENBQUMsR0FBRyxD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LENBQUM7UUFDdEQsTUFBTSxFQUFFLEdBQUc7UUFDWCxZQUFZLEVBQUUsQ0FBQyxHQUFHLENBQUM7UUFDbkIsWUFBWSxFQUFFLENBQUMsR0FBRyxDQUFDO1FBQ25CLGFBQWEsRUFBRSxDQUFDLEdBQUcsQ0FBQztLQUN2QixDQUFBO0FBQ0wsQ0FBQztBQTRCRCxLQUFLLFVBQVUsUUFBUSxDQUFDLE9BQWdCLEVBQUUsS0FBYTtJQUNuRCxNQUFNLFFBQVEsR0FBRyxNQUFNLFVBQVUsQ0FDN0IsT0FBTyxFQUNQLEtBQUssRUFDTCxZQUFZLEVBQ1osWUFBWSxLQUFLLGtCQUFrQixDQUN0QyxDQUFBO0lBQ0QsSUFBSSxRQUFRLENBQUMsTUFBTSxLQUFLLEdBQUcsRUFBRSxDQUFDO1FBQzFCLE9BQU8sU0FBUyxDQUFBO0lBQ3BCLENBQUM7SUFDRCxNQUFNLFlBQVksQ0FBQyxRQUFRLEVBQUUsMEJBQTBCLENBQUMsQ0FBQTtJQUN4RCxPQUFPLENBQUMsTUFBTSxRQUFRLENBQUMsSUFBSSxFQUFFLENBQWEsQ0FBQTtBQUM5QyxDQUFDO0FBRUQsS0FBSyxVQUFVLFNBQVMsQ0FDcEIsT0FBZ0IsRUFDaEIsTUFBYyxFQUNkLE9BQWUsRUFDZixLQUFhLEVBQ2IsS0FBMkI7SUFFM0IsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQ1QsTUFBTSxVQUFVLENBQ1osVUFBVSxDQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsWUFBWSxFQUFFLFlBQVksS0FBSyxTQUFTLEVBQUU7WUFDbEUsU0FBUyxFQUFFLFVBQVU7WUFDckIsVUFBVSxFQUFFLElBQUk7WUFDaEIsSUFBSSxFQUFFO2dCQUNGLFNBQVMsRUFBRSxVQUFVO2dCQUNyQixXQUFXLEVBQUUsTUFBTTtnQkFDbkIsT0FBTzthQUNWO1NBQ0osQ0FBQyxFQUNGLHVCQUF1QixDQUMxQixDQUFBO0lBQ0wsQ0FBQztBQUNMLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBqc29uUmVzcG9uc2UsIG9rUmVzcG9uc2UsIHRocm93T25Ob3RPSyB9IGZyb20gJ0ByaWRkYW5jZS9mZXRjaCdcbmltcG9ydCB7IFJlZmxlY3Rpb24gfSBmcm9tICdAcmlkZGFuY2UvaG9zdC9yZWZsZWN0J1xuaW1wb3J0IHsgaXNEZWVwU3RyaWN0RXF1YWwgfSBmcm9tICdub2RlOnV0aWwnXG5pbXBvcnQgeyBjb21wYXJlIH0gZnJvbSAnLi4vZGlmZi5qcydcbmltcG9ydCB7IHR5cGUgQ29udGV4dCwgYXdzUmVxdWVzdCwgcGFnZXMsIHJldHJ5Q29uZmxpY3QgfSBmcm9tICcuLi9saXRlLmpzJ1xuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc3luY0dhdGV3YXkoXG4gICAgY29udGV4dDogQ29udGV4dCxcbiAgICByZWdpb246IHN0cmluZyB8IHVuZGVmaW5lZCxcbiAgICBhY2NvdW50OiBzdHJpbmcgfCB1bmRlZmluZWQsXG4gICAgcHJlZml4OiBzdHJpbmcsXG4gICAgc2VydmljZTogc3RyaW5nLFxuICAgIGN1cnJlbnRHYXRld2F5OiBBd3NHYXRld2F5LFxuICAgIHJlZmxlY3Rpb246IFJlZmxlY3Rpb24sXG4gICAgY29yc1NpdGVzOiBzdHJpbmdbXSxcbikge1xuICAgIGlmIChjdXJyZW50R2F0ZXdheS5hcGkpIHtcbiAgICAgICAgYXdhaXQgc3luY0dhdGV3YXlBcGkoY29udGV4dCwgY3VycmVudEdhdGV3YXkuYXBpLCBwcmVmaXgsIHNlcnZpY2UsIGNvcnNTaXRlcylcbiAgICAgICAgYXdhaXQgc3luY1N0YWdlKGNvbnRleHQsIHByZWZpeCwgc2VydmljZSwgY3VycmVudEdhdGV3YXkuYXBpLmFwaUlkLCBjdXJyZW50R2F0ZXdheS5zdGFnZSlcbiAgICAgICAgY29uc3QgeyBpZHMsIHN1cnBsdXM6IHN1cnBsdXNJbnRlZ3JhdGlvbnMgfSA9IGF3YWl0IHN5bmNJbnRlZ3JhdGlvbnMoXG4gICAgICAgICAgICBjb250ZXh0LFxuICAgICAgICAgICAgcmVnaW9uLFxuICAgICAgICAgICAgYWNjb3VudCxcbiAgICAgICAgICAgIHByZWZpeCxcbiAgICAgICAgICAgIHNlcnZpY2UsXG4gICAgICAgICAgICBjdXJyZW50R2F0ZXdheS5hcGkuYXBpSWQsXG4gICAgICAgICAgICBjdXJyZW50R2F0ZXdheS5pbnRlZ3JhdGlvbnMsXG4gICAgICAgICAgICByZWZsZWN0aW9uLFxuICAgICAgICApXG4gICAgICAgIGNvbnN0IGludGVncmF0aW9uSWRCeU5hbWUgPSBPYmplY3QuZnJvbUVudHJpZXMoaWRzKVxuICAgICAgICBjb25zdCBuYW1lQnlUYXJnZXQgPSBPYmplY3QuZnJvbUVudHJpZXMoXG4gICAgICAgICAgICBpZHMubWFwKChbbmFtZSwgaW50ZWdyYXRpb25JZF0pID0+IFtgaW50ZWdyYXRpb25zLyR7aW50ZWdyYXRpb25JZH1gLCBuYW1lXSksXG4gICAgICAgIClcblxuICAgICAgICBjb25zdCB7IG1pc3NpbmcsIHN1cnBsdXMsIGV4aXN0aW5nIH0gPSBjb21wYXJlKFxuICAgICAgICAgICAgcmVmbGVjdGlvbi5odHRwLFxuICAgICAgICAgICAgY3VycmVudEdhdGV3YXkucm91dGVzLm1hcChyID0+ICh7XG4gICAgICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1ub24tbnVsbC1hc3NlcnRpb25cbiAgICAgICAgICAgICAgICBuYW1lOiBuYW1lQnlUYXJnZXRbci50YXJnZXRdISxcbiAgICAgICAgICAgICAgICAuLi5yLFxuICAgICAgICAgICAgfSkpLFxuICAgICAgICApXG4gICAgICAgIGF3YWl0IFByb21pc2UuYWxsKHN1cnBsdXMubWFwKGkgPT4gZGVsZXRlUm91dGUoY29udGV4dCwgY3VycmVudEdhdGV3YXkuYXBpLmFwaUlkLCBpKSkpXG4gICAgICAgIGF3YWl0IFByb21pc2UuYWxsKFtcbiAgICAgICAgICAgIC4uLm1pc3NpbmcubWFwKGZuID0+XG4gICAgICAgICAgICAgICAgY3JlYXRlUm91dGUoXG4gICAgICAgICAgICAgICAgICAgIGNvbnRleHQsXG4gICAgICAgICAgICAgICAgICAgIGN1cnJlbnRHYXRld2F5LmFwaS5hcGlJZCxcbiAgICAgICAgICAgICAgICAgICAgYXNSb3V0ZShpbnRlZ3JhdGlvbklkQnlOYW1lW2ZuLm5hbWVdLCBmbiksXG4gICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICksXG4gICAgICAgICAgICAuLi5leGlzdGluZy5tYXAoYXN5bmMgKHsgbmFtZSwgcm91dGVJZCwgLi4uZXggfSkgPT4ge1xuICAgICAgICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tbm9uLW51bGwtYXNzZXJ0aW9uXG4gICAgICAgICAgICAgICAgY29uc3QgZm4gPSByZWZsZWN0aW9uLmh0dHAuZmluZChmID0+IGYubmFtZSA9PT0gbmFtZSkhXG4gICAgICAgICAgICAgICAgY29uc3Qgcm91dGUgPSBhc1JvdXRlKGludGVncmF0aW9uSWRCeU5hbWVbZm4ubmFtZV0sIGZuKVxuICAgICAgICAgICAgICAgIGlmIChpc0RlZXBTdHJpY3RFcXVhbChleCwgcm91dGUpKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVyblxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBhd2FpdCB1cGRhdGVSb3V0ZShjb250ZXh0LCBjdXJyZW50R2F0ZXdheS5hcGkuYXBpSWQsIHJvdXRlSWQsIHJvdXRlKVxuICAgICAgICAgICAgfSksXG4gICAgICAgIF0pXG4gICAgICAgIGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgICAgICAgc3VycGx1c0ludGVncmF0aW9ucy5tYXAoaSA9PlxuICAgICAgICAgICAgICAgIGRlbGV0ZUludGVncmF0aW9uKFxuICAgICAgICAgICAgICAgICAgICBjb250ZXh0LFxuICAgICAgICAgICAgICAgICAgICByZWdpb24sXG4gICAgICAgICAgICAgICAgICAgIGFjY291bnQsXG4gICAgICAgICAgICAgICAgICAgIGN1cnJlbnRHYXRld2F5LmFwaS5hcGlJZCxcbiAgICAgICAgICAgICAgICAgICAgaS5pbnRlZ3JhdGlvbklkLFxuICAgICAgICAgICAgICAgICksXG4gICAgICAgICAgICApLFxuICAgICAgICApXG4gICAgICAgIHJldHVybiBjdXJyZW50R2F0ZXdheS5hcGkuYXBpSWRcbiAgICB9IGVsc2Uge1xuICAgICAgICBjb25zdCBnYXRld2F5ID0gYXdhaXQgY3JlYXRlR2F0ZXdheShjb250ZXh0LCBwcmVmaXgsIHNlcnZpY2UsIGNvcnNTaXRlcylcbiAgICAgICAgY29uc3QgaWRzID0gYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICAgICAgICByZWZsZWN0aW9uLmh0dHAubWFwKGZuID0+XG4gICAgICAgICAgICAgICAgY3JlYXRlSW50ZWdyYXRpb24oXG4gICAgICAgICAgICAgICAgICAgIGNvbnRleHQsXG4gICAgICAgICAgICAgICAgICAgIGdhdGV3YXkuYXBpSWQsXG4gICAgICAgICAgICAgICAgICAgIGZuLm5hbWUsXG4gICAgICAgICAgICAgICAgICAgIGFzSW50ZWdyYXRpb24ocmVnaW9uLCBhY2NvdW50LCBwcmVmaXgsIHNlcnZpY2UsIGZuKSxcbiAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgKSxcbiAgICAgICAgKVxuICAgICAgICBjb25zdCBpbnRlZ3JhdGlvbklkQnlOYW1lID0gT2JqZWN0LmZyb21FbnRyaWVzKGlkcylcbiAgICAgICAgYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICAgICAgICByZWZsZWN0aW9uLmh0dHAubWFwKGZuID0+XG4gICAgICAgICAgICAgICAgY3JlYXRlUm91dGUoY29udGV4dCwgZ2F0ZXdheS5hcGlJZCwgYXNSb3V0ZShpbnRlZ3JhdGlvbklkQnlOYW1lW2ZuLm5hbWVdLCBmbikpLFxuICAgICAgICAgICAgKSxcbiAgICAgICAgKVxuICAgICAgICByZXR1cm4gZ2F0ZXdheS5hcGlJZFxuICAgIH1cbn1cblxuYXN5bmMgZnVuY3Rpb24gc3luY0ludGVncmF0aW9ucyhcbiAgICBjb250ZXh0OiBDb250ZXh0LFxuICAgIHJlZ2lvbjogc3RyaW5nIHwgdW5kZWZpbmVkLFxuICAgIGFjY291bnQ6IHN0cmluZyB8IHVuZGVmaW5lZCxcbiAgICBwcmVmaXg6IHN0cmluZyxcbiAgICBzZXJ2aWNlOiBzdHJpbmcsXG4gICAgYXBpSWQ6IHN0cmluZyxcbiAgICBjdXJyZW50SW50ZWdyYXRpb25zOiAoQXdzSW50ZWdyYXRpb24gJiB7IG5hbWU6IHN0cmluZzsgaW50ZWdyYXRpb25JZDogc3RyaW5nIH0pW10sXG4gICAgcmVmbGVjdGlvbjogUmVmbGVjdGlvbixcbikge1xuICAgIGNvbnN0IHsgbWlzc2luZywgc3VycGx1cywgZXhpc3RpbmcgfSA9IGNvbXBhcmUocmVmbGVjdGlvbi5odHRwLCBjdXJyZW50SW50ZWdyYXRpb25zKVxuICAgIGNvbnN0IGlkcyA9IGF3YWl0IFByb21pc2UuYWxsKFtcbiAgICAgICAgLi4ubWlzc2luZy5tYXAoZm4gPT5cbiAgICAgICAgICAgIGNyZWF0ZUludGVncmF0aW9uKFxuICAgICAgICAgICAgICAgIGNvbnRleHQsXG4gICAgICAgICAgICAgICAgYXBpSWQsXG4gICAgICAgICAgICAgICAgZm4ubmFtZSxcbiAgICAgICAgICAgICAgICBhc0ludGVncmF0aW9uKHJlZ2lvbiwgYWNjb3VudCwgcHJlZml4LCBzZXJ2aWNlLCBmbiksXG4gICAgICAgICAgICApLFxuICAgICAgICApLFxuICAgICAgICAuLi5leGlzdGluZy5tYXAoYXN5bmMgKHsgbmFtZSwgaW50ZWdyYXRpb25JZCwgLi4uZXggfSkgPT4ge1xuICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1ub24tbnVsbC1hc3NlcnRpb25cbiAgICAgICAgICAgIGNvbnN0IGZuID0gcmVmbGVjdGlvbi5odHRwLmZpbmQoZiA9PiBmLm5hbWUgPT09IG5hbWUpIVxuICAgICAgICAgICAgY29uc3QgaW50ZWdyYXRpb24gPSBhc0ludGVncmF0aW9uKHJlZ2lvbiwgYWNjb3VudCwgcHJlZml4LCBzZXJ2aWNlLCBmbilcbiAgICAgICAgICAgIGlmIChpc0RlZXBTdHJpY3RFcXVhbChleCwgaW50ZWdyYXRpb24pKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIFtuYW1lLCBpbnRlZ3JhdGlvbklkXSBhcyBbc3RyaW5nLCBzdHJpbmddXG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBhd2FpdCB1cGRhdGVJbnRlZ3JhdGlvbihjb250ZXh0LCBhcGlJZCwgaW50ZWdyYXRpb25JZCwgaW50ZWdyYXRpb24pXG4gICAgICAgICAgICByZXR1cm4gW25hbWUsIGludGVncmF0aW9uSWRdIGFzIFtzdHJpbmcsIHN0cmluZ11cbiAgICAgICAgfSksXG4gICAgXSlcbiAgICByZXR1cm4geyBpZHMsIHN1cnBsdXMgfVxufVxuXG50eXBlIEF3c0dhdGV3YXkgPSBBd2FpdGVkPFJldHVyblR5cGU8dHlwZW9mIGdldEFwaT4+XG5cbmV4cG9ydCB0eXBlIEF3c0dhdGV3YXlBcGkgPSB7XG4gICAgYXBpSWQ6IHN0cmluZ1xuICAgIG5hbWU6IHN0cmluZ1xuICAgIHByb3RvY29sVHlwZTogJ0hUVFAnIHwgJ1JFU1QnXG4gICAgYXBpRW5kcG9pbnQ6IHN0cmluZ1xuICAgIGNvcnNDb25maWd1cmF0aW9uOiB7XG4gICAgICAgIGFsbG93T3JpZ2luczogc3RyaW5nW11cbiAgICAgICAgYWxsb3dDcmVkZW50aWFsczogZmFsc2VcbiAgICAgICAgbWF4QWdlOiBudW1iZXJcbiAgICAgICAgYWxsb3dNZXRob2RzOiBzdHJpbmdbXVxuICAgICAgICBhbGxvd0hlYWRlcnM6IHN0cmluZ1tdXG4gICAgICAgIGV4cG9zZUhlYWRlcnM6IHN0cmluZ1tdXG4gICAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0QXBpcyhjb250ZXh0OiBDb250ZXh0LCBwcmVmaXg6IHN0cmluZykge1xuICAgIHJldHVybiBwYWdlcyhcbiAgICAgICAgY29udGV4dCxcbiAgICAgICAgJ2FwaWdhdGV3YXknLFxuICAgICAgICAnL3YyL2FwaXMvJyxcbiAgICAgICAgKGl0ZW1zOiBBd3NHYXRld2F5QXBpW10pID0+IGl0ZW1zLmZpbHRlcihhID0+IGEubmFtZS5zdGFydHNXaXRoKGAke3ByZWZpeH0tYCkpLFxuICAgICAgICAnRXJyb3IgZ2V0dGluZyBBUElzLicsXG4gICAgKVxufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZ2V0QXBpKGNvbnRleHQ6IENvbnRleHQsIHByZWZpeDogc3RyaW5nLCBzZXJ2aWNlOiBzdHJpbmcpIHtcbiAgICBjb25zdCBuYW1lID0gYCR7cHJlZml4fS0ke3NlcnZpY2V9YFxuICAgIGZvciBhd2FpdCAoY29uc3QgYXBpIG9mIGdldEFwaXMoY29udGV4dCwgcHJlZml4KSkge1xuICAgICAgICBpZiAoYXBpLm5hbWUgPT09IG5hbWUpIHtcbiAgICAgICAgICAgIGNvbnN0IFtpbnRlZ3JhdGlvbnMsIHJvdXRlcywgc3RhZ2VdID0gYXdhaXQgUHJvbWlzZS5hbGwoW1xuICAgICAgICAgICAgICAgIEFycmF5LmZyb21Bc3luYyhnZXRJbnRlZ3JhdGlvbnMoY29udGV4dCwgYXBpLmFwaUlkLCBuYW1lLmxlbmd0aCArIDEpKSxcbiAgICAgICAgICAgICAgICBBcnJheS5mcm9tQXN5bmMoZ2V0Um91dGVzKGNvbnRleHQsIGFwaS5hcGlJZCkpLFxuICAgICAgICAgICAgICAgIGdldFN0YWdlKGNvbnRleHQsIGFwaS5hcGlJZCksXG4gICAgICAgICAgICBdKVxuICAgICAgICAgICAgcmV0dXJuIHsgYXBpLCBpbnRlZ3JhdGlvbnMsIHJvdXRlcywgc3RhZ2UgfVxuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiB7IGludGVncmF0aW9uczogW10sIHJvdXRlczogW10gfVxufVxuXG5leHBvcnQgdHlwZSBBd3NJbnRlZ3JhdGlvbiA9IHtcbiAgICBwYXlsb2FkRm9ybWF0VmVyc2lvbjogJzIuMCdcbiAgICBpbnRlZ3JhdGlvblR5cGU6ICdBV1NfUFJPWFknXG4gICAgaW50ZWdyYXRpb25NZXRob2Q6IHN0cmluZ1xuICAgIGludGVncmF0aW9uVXJpOiBzdHJpbmdcbiAgICBjb25uZWN0aW9uVHlwZTogJ0lOVEVSTkVUJ1xuICAgIHRpbWVvdXRJbk1pbGxpczogbnVtYmVyIHwgdW5kZWZpbmVkXG59XG5cbmZ1bmN0aW9uIGdldEludGVncmF0aW9ucyhjb250ZXh0OiBDb250ZXh0LCBhcGlJZDogc3RyaW5nLCBwcmVmaXhMZW5ndGg6IG51bWJlcikge1xuICAgIHJldHVybiBwYWdlcyhcbiAgICAgICAgY29udGV4dCxcbiAgICAgICAgJ2FwaWdhdGV3YXknLFxuICAgICAgICBgL3YyL2FwaXMvJHthcGlJZH0vaW50ZWdyYXRpb25zYCxcbiAgICAgICAgKGl0ZW1zOiAoQXdzSW50ZWdyYXRpb24gJiB7IGludGVncmF0aW9uSWQ6IHN0cmluZyB9KVtdKSA9PlxuICAgICAgICAgICAgaXRlbXMubWFwKGkgPT4gKHtcbiAgICAgICAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLW5vbi1udWxsLWFzc2VydGlvblxuICAgICAgICAgICAgICAgIG5hbWU6IGkuaW50ZWdyYXRpb25Vcmkuc3BsaXQoJzonKS5hdCgtMSkhLnNsaWNlKHByZWZpeExlbmd0aCksXG4gICAgICAgICAgICAgICAgLi4uaSxcbiAgICAgICAgICAgIH0pKSxcbiAgICAgICAgJ0Vycm9yIGdldHRpbmcgQVBJIGludGVncmF0aW9ucy4nLFxuICAgIClcbn1cblxuZnVuY3Rpb24gYXNJbnRlZ3JhdGlvbihcbiAgICByZWdpb246IHN0cmluZyB8IHVuZGVmaW5lZCxcbiAgICBhY2NvdW50OiBzdHJpbmcgfCB1bmRlZmluZWQsXG4gICAgcHJlZml4OiBzdHJpbmcsXG4gICAgc2VydmljZTogc3RyaW5nLFxuICAgIGZuOiB7IG5hbWU6IHN0cmluZzsgbWV0aG9kOiBzdHJpbmc7IHBhdGhQYXR0ZXJuOiBzdHJpbmc7IGNvbmZpZzogeyB0aW1lb3V0PzogbnVtYmVyIH0gfSxcbik6IEF3c0ludGVncmF0aW9uIHtcbiAgICBpZiAoIXJlZ2lvbiB8fCAhYWNjb3VudCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1dlaXJkJylcbiAgICB9XG4gICAgcmV0dXJuIHtcbiAgICAgICAgcGF5bG9hZEZvcm1hdFZlcnNpb246ICcyLjAnLFxuICAgICAgICBpbnRlZ3JhdGlvblR5cGU6ICdBV1NfUFJPWFknLFxuICAgICAgICBpbnRlZ3JhdGlvbk1ldGhvZDogZm4ubWV0aG9kLFxuICAgICAgICBpbnRlZ3JhdGlvblVyaTogYGFybjphd3M6bGFtYmRhOiR7cmVnaW9ufToke2FjY291bnR9OmZ1bmN0aW9uOiR7cHJlZml4fS0ke3NlcnZpY2V9LSR7Zm4ubmFtZX1gLFxuICAgICAgICBjb25uZWN0aW9uVHlwZTogJ0lOVEVSTkVUJyxcbiAgICAgICAgdGltZW91dEluTWlsbGlzOiBNYXRoLm1pbigoKGZuLmNvbmZpZy50aW1lb3V0ID8/IDE1KSArIDUpICogMTAwMCwgMzBfMDAwKSxcbiAgICB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGNyZWF0ZUludGVncmF0aW9uKFxuICAgIGNvbnRleHQ6IENvbnRleHQsXG4gICAgYXBpSWQ6IHN0cmluZyxcbiAgICBuYW1lOiBzdHJpbmcsXG4gICAgaW50ZWdyYXRpb246IEF3c0ludGVncmF0aW9uLFxuKSB7XG4gICAgY29udGV4dC5sb2cudHJhY2UoJ2NyZWF0aW5nIEFQSSBpbnRlZ3JhdGlvbicpXG4gICAgY29uc3QgY3JlYXRlZCA9IGF3YWl0IHJldHJ5Q29uZmxpY3QoKCkgPT5cbiAgICAgICAganNvblJlc3BvbnNlPHsgaW50ZWdyYXRpb25JZDogc3RyaW5nIH0+KFxuICAgICAgICAgICAgYXdzUmVxdWVzdChcbiAgICAgICAgICAgICAgICBjb250ZXh0LFxuICAgICAgICAgICAgICAgICdQT1NUJyxcbiAgICAgICAgICAgICAgICAnYXBpZ2F0ZXdheScsXG4gICAgICAgICAgICAgICAgYC92Mi9hcGlzLyR7YXBpSWR9L2ludGVncmF0aW9uc2AsXG4gICAgICAgICAgICAgICAgaW50ZWdyYXRpb24sXG4gICAgICAgICAgICApLFxuICAgICAgICAgICAgJ0Vycm9yIGNyZWF0aW5nIEFQSSBpbnRlZ3JhdGlvbi4nLFxuICAgICAgICApLFxuICAgIClcbiAgICBjb250ZXh0LmxvZy50cmFjZShcbiAgICAgICAgYCAgZnJvbSAke2FwaUlkfSB0byAke2ludGVncmF0aW9uLmludGVncmF0aW9uVXJpfSBhcyAke2NyZWF0ZWQuaW50ZWdyYXRpb25JZH1gLFxuICAgIClcbiAgICByZXR1cm4gW25hbWUsIGNyZWF0ZWQuaW50ZWdyYXRpb25JZF0gYXMgW3N0cmluZywgc3RyaW5nXVxufVxuXG5hc3luYyBmdW5jdGlvbiB1cGRhdGVJbnRlZ3JhdGlvbihcbiAgICBjb250ZXh0OiBDb250ZXh0LFxuICAgIGFwaUlkOiBzdHJpbmcsXG4gICAgaWQ6IHN0cmluZyxcbiAgICBpbnRlZ3JhdGlvbjogQXdzSW50ZWdyYXRpb24sXG4pIHtcbiAgICBjb250ZXh0LmxvZy50cmFjZSgndXBkYXRpbmcgQVBJIGludGVncmF0aW9uICcgKyBpZClcbiAgICBjb250ZXh0LmxvZy50cmFjZShgICBmcm9tICR7YXBpSWR9IHRvICR7aW50ZWdyYXRpb24uaW50ZWdyYXRpb25Vcml9YClcbiAgICBhd2FpdCBva1Jlc3BvbnNlKFxuICAgICAgICBhd3NSZXF1ZXN0KFxuICAgICAgICAgICAgY29udGV4dCxcbiAgICAgICAgICAgICdQQVRDSCcsXG4gICAgICAgICAgICAnYXBpZ2F0ZXdheScsXG4gICAgICAgICAgICBgL3YyL2FwaXMvJHthcGlJZH0vaW50ZWdyYXRpb25zLyR7aWR9YCxcbiAgICAgICAgICAgIGludGVncmF0aW9uLFxuICAgICAgICApLFxuICAgICAgICAnRXJyb3IgdXBkYXRpbmcgQVBJIGludGVncmF0aW9uJyxcbiAgICApXG59XG5cbmFzeW5jIGZ1bmN0aW9uIGRlbGV0ZUludGVncmF0aW9uKFxuICAgIGNvbnRleHQ6IENvbnRleHQsXG4gICAgcmVnaW9uOiBzdHJpbmcgfCB1bmRlZmluZWQsXG4gICAgYWNjb3VudDogc3RyaW5nIHwgdW5kZWZpbmVkLFxuICAgIGFwaUlkOiBzdHJpbmcsXG4gICAgaWQ6IHN0cmluZyxcbikge1xuICAgIGlmICghcmVnaW9uIHx8ICFhY2NvdW50KSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignV2VpcmQnKVxuICAgIH1cbiAgICBjb250ZXh0LmxvZy50cmFjZSgnZGVsZXRpbmcgQVBJIGludGVncmF0aW9uICcgKyBpZClcbiAgICBhd2FpdCBva1Jlc3BvbnNlKFxuICAgICAgICBhd3NSZXF1ZXN0KGNvbnRleHQsICdERUxFVEUnLCAnYXBpZ2F0ZXdheScsIGAvdjIvYXBpcy8ke2FwaUlkfS9pbnRlZ3JhdGlvbnMvJHtpZH1gKSxcbiAgICAgICAgJ0Vycm9yIGRlbGV0aW5nIEFQSSBpbnRlZ3JhdGlvbi4nLFxuICAgIClcbn1cblxuZXhwb3J0IHR5cGUgQXdzUm91dGUgPSB7XG4gICAgcm91dGVLZXk6IHN0cmluZ1xuICAgIGF1dGhvcml6YXRpb25UeXBlOiAnTk9ORSdcbiAgICBhcGlLZXlSZXF1aXJlZDogZmFsc2VcbiAgICB0YXJnZXQ6IHN0cmluZ1xufVxuXG5mdW5jdGlvbiBhc1JvdXRlKFxuICAgIGludGVncmF0aW9uSWQ6IHN0cmluZyB8IHVuZGVmaW5lZCxcbiAgICBmbjogeyBtZXRob2Q6ICdHRVQnIHwgJ1BBVENIJyB8ICdQVVQnIHwgJ1BPU1QnIHwgJ0RFTEVURSc7IHBhdGhQYXR0ZXJuOiBzdHJpbmcgfSxcbik6IEF3c1JvdXRlIHtcbiAgICBpZiAoIWludGVncmF0aW9uSWQpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBXZWlyZDogbm8gaW50ZWdyYXRpb24gSUQgZm9yICR7Zm4ubWV0aG9kfSAke2ZuLnBhdGhQYXR0ZXJufWApXG4gICAgfVxuICAgIGxldCBwID0gMFxuICAgIHJldHVybiB7XG4gICAgICAgIHJvdXRlS2V5OiBgJHtmbi5tZXRob2R9IC8ke3RyaW1UcmFpbGluZ1NsYXNoKFxuICAgICAgICAgICAgZm4ucGF0aFBhdHRlcm4ucmVwbGFjZUFsbCgnKicsICgpID0+IGB7cCR7KytwfX1gKSxcbiAgICAgICAgKX1gLFxuICAgICAgICBhdXRob3JpemF0aW9uVHlwZTogJ05PTkUnLFxuICAgICAgICBhcGlLZXlSZXF1aXJlZDogZmFsc2UsXG4gICAgICAgIHRhcmdldDogYGludGVncmF0aW9ucy8ke2ludGVncmF0aW9uSWR9YCxcbiAgICB9XG59XG5cbmZ1bmN0aW9uIHRyaW1UcmFpbGluZ1NsYXNoKHBhdGhQYXR0ZXJuOiBzdHJpbmcpIHtcbiAgICBpZiAocGF0aFBhdHRlcm4uZW5kc1dpdGgoJy8nKSkge1xuICAgICAgICByZXR1cm4gcGF0aFBhdHRlcm4uc2xpY2UoMCwgTWF0aC5tYXgoMCwgcGF0aFBhdHRlcm4ubGVuZ3RoIC0gMSkpXG4gICAgfVxuICAgIHJldHVybiBwYXRoUGF0dGVyblxufVxuXG5mdW5jdGlvbiBnZXRSb3V0ZXMoY29udGV4dDogQ29udGV4dCwgYXBpSWQ6IHN0cmluZykge1xuICAgIHJldHVybiBwYWdlcyhcbiAgICAgICAgY29udGV4dCxcbiAgICAgICAgJ2FwaWdhdGV3YXknLFxuICAgICAgICBgL3YyL2FwaXMvJHthcGlJZH0vcm91dGVzYCxcbiAgICAgICAgKHJvdXRlczogKEF3c1JvdXRlICYgeyByb3V0ZUlkOiBzdHJpbmcgfSlbXSkgPT4gcm91dGVzLFxuICAgICAgICAnRXJyb3IgZ2V0dGluZyBBUEkgcm91dGVzLicsXG4gICAgKVxufVxuXG5hc3luYyBmdW5jdGlvbiBjcmVhdGVSb3V0ZShjb250ZXh0OiBDb250ZXh0LCBhcGlJZDogc3RyaW5nLCByb3V0ZTogQXdzUm91dGUpIHtcbiAgICBjb250ZXh0LmxvZy50cmFjZShgY3JlYXRpbmcgcm91dGUgJHtyb3V0ZS5yb3V0ZUtleX0gdG8gJHtyb3V0ZS50YXJnZXR9YClcbiAgICBhd2FpdCByZXRyeUNvbmZsaWN0KCgpID0+XG4gICAgICAgIG9rUmVzcG9uc2UoXG4gICAgICAgICAgICBhd3NSZXF1ZXN0KGNvbnRleHQsICdQT1NUJywgJ2FwaWdhdGV3YXknLCBgL3YyL2FwaXMvJHthcGlJZH0vcm91dGVzYCwgcm91dGUpLFxuICAgICAgICAgICAgJ0Vycm9yIGNyZWF0aW5nIEFQSSByb3V0ZS4nLFxuICAgICAgICApLFxuICAgIClcbn1cblxuYXN5bmMgZnVuY3Rpb24gdXBkYXRlUm91dGUoY29udGV4dDogQ29udGV4dCwgYXBpSWQ6IHN0cmluZywgaWQ6IHN0cmluZywgcm91dGU6IEF3c1JvdXRlKSB7XG4gICAgY29udGV4dC5sb2cudHJhY2UoYHVwZGF0aW5nIEFQSSByb3V0ZSAke2lkfSB0byAke3JvdXRlLnRhcmdldH1gKVxuICAgIGF3YWl0IG9rUmVzcG9uc2UoXG4gICAgICAgIGF3c1JlcXVlc3QoY29udGV4dCwgJ1BBVENIJywgJ2FwaWdhdGV3YXknLCBgL3YyL2FwaXMvJHthcGlJZH0vcm91dGVzLyR7aWR9YCwgcm91dGUpLFxuICAgICAgICAnRXJyb3IgdXBkYXRpbmcgQVBJIHJvdXRlLicsXG4gICAgKVxufVxuXG5hc3luYyBmdW5jdGlvbiBkZWxldGVSb3V0ZShjb250ZXh0OiBDb250ZXh0LCBhcGlJZDogc3RyaW5nLCByb3V0ZTogQXdzUm91dGUgJiB7IHJvdXRlSWQ6IHN0cmluZyB9KSB7XG4gICAgY29udGV4dC5sb2cudHJhY2UoYGRlbGV0aW5nIEFQSSByb3V0ZSAke3JvdXRlLnJvdXRlSWR9IGZyb20gJHtyb3V0ZS50YXJnZXR9YClcbiAgICBhd2FpdCBva1Jlc3BvbnNlKFxuICAgICAgICBhd3NSZXF1ZXN0KGNvbnRleHQsICdERUxFVEUnLCAnYXBpZ2F0ZXdheScsIGAvdjIvYXBpcy8ke2FwaUlkfS9yb3V0ZXMvJHtyb3V0ZS5yb3V0ZUlkfWApLFxuICAgICAgICAnRXJyb3IgZGVsZXRpbmcgQVBJIHJvdXRlLicsXG4gICAgKVxufVxuXG5hc3luYyBmdW5jdGlvbiBjcmVhdGVHYXRld2F5KFxuICAgIGNvbnRleHQ6IENvbnRleHQsXG4gICAgcHJlZml4OiBzdHJpbmcsXG4gICAgc2VydmljZTogc3RyaW5nLFxuICAgIGNvcnNTaXRlczogc3RyaW5nW10sXG4pIHtcbiAgICBjb250ZXh0LmxvZy50cmFjZSgnY3JlYXRpbmcgZ2F0ZXdheScpXG4gICAgY29uc3QgZ2F0ZXdheSA9IGF3YWl0IGpzb25SZXNwb25zZTx7IGFwaUlkOiBzdHJpbmcgfT4oXG4gICAgICAgIGF3c1JlcXVlc3QoY29udGV4dCwgJ1BPU1QnLCAnYXBpZ2F0ZXdheScsIGAvdjIvYXBpcy9gLCB7XG4gICAgICAgICAgICBuYW1lOiBgJHtwcmVmaXh9LSR7c2VydmljZX1gLFxuICAgICAgICAgICAgcHJvdG9jb2xUeXBlOiAnSFRUUCcsXG4gICAgICAgICAgICBjb3JzQ29uZmlndXJhdGlvbjogY29yc1NldHRpbmdzKGNvcnNTaXRlcyksXG4gICAgICAgICAgICB0YWdzOiB7XG4gICAgICAgICAgICAgICAgZnJhbWV3b3JrOiAncmlkZGFuY2UnLFxuICAgICAgICAgICAgICAgIGVudmlyb25tZW50OiBwcmVmaXgsXG4gICAgICAgICAgICAgICAgc2VydmljZSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgIH0pLFxuICAgICAgICAnRXJyb3IgY3JlYXRpbmcgZ2F0ZXdheS4nLFxuICAgIClcbiAgICBhd2FpdCBzeW5jU3RhZ2UoY29udGV4dCwgcHJlZml4LCBzZXJ2aWNlLCBnYXRld2F5LmFwaUlkLCB1bmRlZmluZWQpXG4gICAgcmV0dXJuIGdhdGV3YXlcbn1cblxuYXN5bmMgZnVuY3Rpb24gc3luY0dhdGV3YXlBcGkoXG4gICAgY29udGV4dDogQ29udGV4dCxcbiAgICBnYXRld2F5OiBBd3NHYXRld2F5QXBpLFxuICAgIHByZWZpeDogc3RyaW5nLFxuICAgIHNlcnZpY2U6IHN0cmluZyxcbiAgICBjb3JzU2l0ZXM6IHN0cmluZ1tdLFxuKSB7XG4gICAgY29uc3QgY29yc0NvbmZpZ3VyYXRpb24gPSBjb3JzU2V0dGluZ3MoY29yc1NpdGVzKVxuICAgIGlmIChpc0RlZXBTdHJpY3RFcXVhbChjb3JzQ29uZmlndXJhdGlvbiwgZ2F0ZXdheS5jb3JzQ29uZmlndXJhdGlvbikpIHtcbiAgICAgICAgcmV0dXJuXG4gICAgfVxuICAgIGNvbnRleHQubG9nLnRyYWNlKCd1cGRhdGluZyBnYXRld2F5JylcbiAgICBhd2FpdCBva1Jlc3BvbnNlKFxuICAgICAgICBhd3NSZXF1ZXN0KGNvbnRleHQsICdQQVRDSCcsICdhcGlnYXRld2F5JywgYC92Mi9hcGlzLyR7Z2F0ZXdheS5hcGlJZH1gLCB7XG4gICAgICAgICAgICBuYW1lOiBgJHtwcmVmaXh9LSR7c2VydmljZX1gLFxuICAgICAgICAgICAgcHJvdG9jb2xUeXBlOiAnSFRUUCcsXG4gICAgICAgICAgICBjb3JzQ29uZmlndXJhdGlvbixcbiAgICAgICAgICAgIHRhZ3M6IHtcbiAgICAgICAgICAgICAgICBmcmFtZXdvcms6ICdyaWRkYW5jZScsXG4gICAgICAgICAgICAgICAgZW52aXJvbm1lbnQ6IHByZWZpeCxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgfSksXG4gICAgICAgICdFcnJvciB1cGRhdGluZyBnYXRld2F5LicsXG4gICAgKVxufVxuXG5mdW5jdGlvbiBjb3JzU2V0dGluZ3MoY29yc1NpdGVzOiBzdHJpbmdbXSkge1xuICAgIHJldHVybiB7XG4gICAgICAgIGFsbG93T3JpZ2luczogY29yc1NpdGVzLFxuICAgICAgICBhbGxvd0NyZWRlbnRpYWxzOiAhaXNEZWVwU3RyaWN0RXF1YWwoY29yc1NpdGVzLCBbJyonXSksXG4gICAgICAgIG1heEFnZTogNjAwLFxuICAgICAgICBhbGxvd01ldGhvZHM6IFsnKiddLFxuICAgICAgICBhbGxvd0hlYWRlcnM6IFsnKiddLFxuICAgICAgICBleHBvc2VIZWFkZXJzOiBbJyonXSxcbiAgICB9XG59XG5cbmV4cG9ydCB0eXBlIEFwaVN0YWdlID0ge1xuICAgIHN0YWdlTmFtZTogc3RyaW5nXG4gICAgZGVzY3JpcHRpb246IHN0cmluZ1xuICAgIGRlcGxveW1lbnRJZDogc3RyaW5nXG4gICAgY2xpZW50Q2VydGlmaWNhdGVJZDogc3RyaW5nXG4gICAgZGVmYXVsdFJvdXRlU2V0dGluZ3M6IHtcbiAgICAgICAgZGV0YWlsZWRNZXRyaWNzRW5hYmxlZDogYm9vbGVhblxuICAgICAgICBsb2dnaW5nTGV2ZWw6ICdJTkZPJyB8ICdFUlJPUicgfCAnT0ZGJ1xuICAgICAgICBkYXRhVHJhY2VFbmFibGVkOiBib29sZWFuXG4gICAgICAgIHRocm90dGxpbmdCdXJzdExpbWl0OiBudW1iZXJcbiAgICAgICAgdGhyb3R0bGluZ1JhdGVMaW1pdDogbnVtYmVyXG4gICAgfVxuICAgIHJvdXRlU2V0dGluZ3M6IHsgW2tleTogc3RyaW5nXTogc3RyaW5nIH1cbiAgICBzdGFnZVZhcmlhYmxlczogeyBba2V5OiBzdHJpbmddOiBzdHJpbmcgfVxuICAgIGFjY2Vzc0xvZ1NldHRpbmdzOiB7XG4gICAgICAgIGZvcm1hdDogc3RyaW5nXG4gICAgICAgIGRlc3RpbmF0aW9uQXJuOiBzdHJpbmdcbiAgICB9XG4gICAgYXV0b0RlcGxveTogYm9vbGVhblxuICAgIGxhc3REZXBsb3ltZW50U3RhdHVzTWVzc2FnZTogc3RyaW5nXG4gICAgY3JlYXRlZERhdGU6IHN0cmluZ1xuICAgIGxhc3RVcGRhdGVkRGF0ZTogc3RyaW5nXG4gICAgdGFnczogeyBba2V5OiBzdHJpbmddOiBzdHJpbmcgfVxuICAgIGFwaUdhdGV3YXlNYW5hZ2VkOiBib29sZWFuXG59XG5cbmFzeW5jIGZ1bmN0aW9uIGdldFN0YWdlKGNvbnRleHQ6IENvbnRleHQsIGFwaUlkOiBzdHJpbmcpIHtcbiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGF3c1JlcXVlc3QoXG4gICAgICAgIGNvbnRleHQsXG4gICAgICAgICdHRVQnLFxuICAgICAgICAnYXBpZ2F0ZXdheScsXG4gICAgICAgIGAvdjIvYXBpcy8ke2FwaUlkfS9zdGFnZXMvJGRlZmF1bHRgLFxuICAgIClcbiAgICBpZiAocmVzcG9uc2Uuc3RhdHVzID09PSA0MDQpIHtcbiAgICAgICAgcmV0dXJuIHVuZGVmaW5lZFxuICAgIH1cbiAgICBhd2FpdCB0aHJvd09uTm90T0socmVzcG9uc2UsICdFcnJvciBnZXR0aW5nIEFQSSBzdGFnZS4nKVxuICAgIHJldHVybiAoYXdhaXQgcmVzcG9uc2UuanNvbigpKSBhcyBBcGlTdGFnZVxufVxuXG5hc3luYyBmdW5jdGlvbiBzeW5jU3RhZ2UoXG4gICAgY29udGV4dDogQ29udGV4dCxcbiAgICBwcmVmaXg6IHN0cmluZyxcbiAgICBzZXJ2aWNlOiBzdHJpbmcsXG4gICAgYXBpSWQ6IHN0cmluZyxcbiAgICBzdGFnZTogQXBpU3RhZ2UgfCB1bmRlZmluZWQsXG4pIHtcbiAgICBpZiAoIXN0YWdlKSB7XG4gICAgICAgIGF3YWl0IG9rUmVzcG9uc2UoXG4gICAgICAgICAgICBhd3NSZXF1ZXN0KGNvbnRleHQsICdQT1NUJywgJ2FwaWdhdGV3YXknLCBgL3YyL2FwaXMvJHthcGlJZH0vc3RhZ2VzYCwge1xuICAgICAgICAgICAgICAgIHN0YWdlTmFtZTogJyRkZWZhdWx0JyxcbiAgICAgICAgICAgICAgICBhdXRvRGVwbG95OiB0cnVlLFxuICAgICAgICAgICAgICAgIHRhZ3M6IHtcbiAgICAgICAgICAgICAgICAgICAgZnJhbWV3b3JrOiAncmlkZGFuY2UnLFxuICAgICAgICAgICAgICAgICAgICBlbnZpcm9ubWVudDogcHJlZml4LFxuICAgICAgICAgICAgICAgICAgICBzZXJ2aWNlLFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB9KSxcbiAgICAgICAgICAgICdFcnJvciBjcmVhdGluZyBzdGFnZS4nLFxuICAgICAgICApXG4gICAgfVxufVxuIl19