@cloudsnorkel/cdk-github-runners
Version:
CDK construct to create GitHub Actions self-hosted runners. Creates ephemeral runners on demand. Easy to deploy and highly customizable.
149 lines • 18.6 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.clearFailuresCache = clearFailuresCache;
exports.handler = handler;
const lambda_github_1 = require("./lambda-github");
/**
* Get webhook delivery failures since the last processed delivery ID.
*
* @internal
*/
async function newDeliveryFailures(octokit, sinceId) {
const deliveries = new Map();
const successfulDeliveries = new Set();
const timeLimitMs = 1000 * 60 * 30; // don't look at deliveries over 30 minutes old
let lastId = 0;
let processedCount = 0;
for await (const response of octokit.paginate.iterator('GET /app/hook/deliveries')) {
if (response.status !== 200) {
throw new Error('Failed to fetch webhook deliveries');
}
for (const delivery of response.data) {
const deliveredAt = new Date(delivery.delivered_at);
const success = delivery.status === 'OK';
if (delivery.id <= sinceId) {
// stop processing if we reach the last processed delivery ID
console.info({
notice: 'Reached last processed delivery ID',
sinceId: sinceId,
deliveryId: delivery.id,
guid: delivery.guid,
processedCount,
});
return { deliveries, lastId };
}
lastId = Math.max(lastId, delivery.id);
if (deliveredAt.getTime() < Date.now() - timeLimitMs) {
// stop processing if the delivery is too old (for first iteration and performance of further iterations)
console.info({
notice: 'Stopping at old delivery',
deliveryId: delivery.id,
guid: delivery.guid,
deliveredAt: deliveredAt,
processedCount,
});
return { deliveries, lastId };
}
console.debug({
notice: 'Processing webhook delivery',
deliveryId: delivery.id,
guid: delivery.guid,
status: delivery.status,
deliveredAt: delivery.delivered_at,
redelivery: delivery.redelivery,
});
processedCount++;
if (success) {
successfulDeliveries.add(delivery.guid);
continue;
}
if (successfulDeliveries.has(delivery.guid)) {
// do not redeliver deliveries that were already successful
continue;
}
deliveries.set(delivery.guid, { id: delivery.id, deliveredAt, redelivery: delivery.redelivery });
}
}
console.info({
notice: 'No more webhook deliveries to process',
deliveryId: 'DONE',
guid: 'DONE',
deliveredAt: 'DONE',
processedCount,
});
return { deliveries, lastId };
}
let lastDeliveryIdProcessed = 0;
const failures = new Map();
/**
* Clear the cache of webhook delivery failures.
*
* For unit testing purposes only.
*
* @internal
*/
function clearFailuresCache() {
lastDeliveryIdProcessed = 0;
failures.clear();
}
async function handler() {
const octokit = await (0, lambda_github_1.getAppOctokit)();
if (!octokit) {
console.info({
notice: 'Skipping webhook redelivery',
reason: 'App installation might not be configured or the app is not installed.',
});
return;
}
// fetch deliveries since the last processed delivery ID
// for any failures:
// 1. if this is not a redelivery, save the delivery ID and time, and finally retry
// 2. if this is a redelivery, check if the original delivery is still within the time limit and retry if it is
const { deliveries, lastId } = await newDeliveryFailures(octokit, lastDeliveryIdProcessed);
lastDeliveryIdProcessed = Math.max(lastDeliveryIdProcessed, lastId);
const timeLimitMs = 1000 * 60 * 60 * 3; // retry for up to 3 hours
for (const [guid, details] of deliveries) {
if (!details.redelivery) {
failures.set(guid, { id: details.id, firstDeliveredAt: details.deliveredAt });
console.log({
notice: 'Redelivering failed delivery',
deliveryId: details.id,
guid: guid,
firstDeliveredAt: details.deliveredAt,
});
await (0, lambda_github_1.redeliver)(octokit, details.id);
}
else {
// if this is a redelivery, check if the original delivery is still within the time limit
const originalFailure = failures.get(guid);
if (originalFailure) {
if (new Date().getTime() - originalFailure.firstDeliveredAt.getTime() < timeLimitMs) {
console.log({
notice: 'Redelivering failed delivery',
deliveryId: details.id,
guid: guid,
firstDeliveredAt: originalFailure.firstDeliveredAt,
});
await (0, lambda_github_1.redeliver)(octokit, details.id);
}
else {
failures.delete(guid); // no need to keep track of this anymore
console.log({
notice: 'Skipping redelivery of old failed delivery',
deliveryId: details.id,
guid: guid,
firstDeliveredAt: originalFailure?.firstDeliveredAt,
});
}
}
else {
console.log({
notice: 'Skipping redelivery of old failed delivery',
deliveryId: details.id,
guid: guid,
});
}
}
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2ViaG9vay1yZWRlbGl2ZXJ5LmxhbWJkYS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy93ZWJob29rLXJlZGVsaXZlcnkubGFtYmRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBK0ZBLGdEQUdDO0FBRUQsMEJBeURDO0FBNUpELG1EQUEyRDtBQUUzRDs7OztHQUlHO0FBQ0gsS0FBSyxVQUFVLG1CQUFtQixDQUFDLE9BQWdCLEVBQUUsT0FBZTtJQUNsRSxNQUFNLFVBQVUsR0FBd0UsSUFBSSxHQUFHLEVBQUUsQ0FBQztJQUNsRyxNQUFNLG9CQUFvQixHQUFnQixJQUFJLEdBQUcsRUFBRSxDQUFDO0lBQ3BELE1BQU0sV0FBVyxHQUFHLElBQUksR0FBRyxFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUMsK0NBQStDO0lBQ25GLElBQUksTUFBTSxHQUFHLENBQUMsQ0FBQztJQUNmLElBQUksY0FBYyxHQUFHLENBQUMsQ0FBQztJQUV2QixJQUFJLEtBQUssRUFBRSxNQUFNLFFBQVEsSUFBSSxPQUFPLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQywwQkFBMEIsQ0FBQyxFQUFFLENBQUM7UUFDbkYsSUFBSSxRQUFRLENBQUMsTUFBTSxLQUFLLEdBQUcsRUFBRSxDQUFDO1lBQzVCLE1BQU0sSUFBSSxLQUFLLENBQUMsb0NBQW9DLENBQUMsQ0FBQztRQUN4RCxDQUFDO1FBRUQsS0FBSyxNQUFNLFFBQVEsSUFBSSxRQUFRLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDckMsTUFBTSxXQUFXLEdBQUcsSUFBSSxJQUFJLENBQUMsUUFBUSxDQUFDLFlBQVksQ0FBQyxDQUFDO1lBQ3BELE1BQU0sT0FBTyxHQUFHLFFBQVEsQ0FBQyxNQUFNLEtBQUssSUFBSSxDQUFDO1lBRXpDLElBQUksUUFBUSxDQUFDLEVBQUUsSUFBSSxPQUFPLEVBQUUsQ0FBQztnQkFDM0IsNkRBQTZEO2dCQUM3RCxPQUFPLENBQUMsSUFBSSxDQUFDO29CQUNYLE1BQU0sRUFBRSxv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QUMsRUFBRTt3QkFDdEIsSUFBSSxFQUFFLElBQUk7d0JBQ1YsZ0JBQWdCLEVBQUUsZUFBZSxDQUFDLGdCQUFnQjtxQkFDbkQsQ0FBQyxDQUFDO29CQUNILE1BQU0sSUFBQSx5QkFBUyxFQUFDLE9BQU8sRUFBRSxPQUFPLENBQUMsRUFBRSxDQUFDLENBQUM7Z0JBQ3ZDLENBQUM7cUJBQU0sQ0FBQztvQkFDTixRQUFRLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsd0NBQXdDO29CQUMvRCxPQUFPLENBQUMsR0FBRyxDQUFDO3dCQUNWLE1BQU0sRUFBRSw0Q0FBNEM7d0JBQ3BELFVBQVUsRUFBRSxPQUFPLENBQUMsRUFBRTt3QkFDdEIsSUFBSSxFQUFFLElBQUk7d0JBQ1YsZ0JBQWdCLEVBQUUsZUFBZSxFQUFFLGdCQUFnQjtxQkFDcEQsQ0FBQyxDQUFDO2dCQUNMLENBQUM7WUFDSCxDQUFDO2lCQUFNLENBQUM7Z0JBQ04sT0FBTyxDQUFDLEdBQUcsQ0FBQztvQkFDVixNQUFNLEVBQUUsNENBQTRDO29CQUNwRCxVQUFVLEVBQUUsT0FBTyxDQUFDLEVBQUU7b0JBQ3RCLElBQUksRUFBRSxJQUFJO2lCQUNYLENBQUMsQ0FBQztZQUNMLENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQztBQUNILENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgdHlwZSB7IE9jdG9raXQgfSBmcm9tICdAb2N0b2tpdC9yZXN0JztcbmltcG9ydCB7IGdldEFwcE9jdG9raXQsIHJlZGVsaXZlciB9IGZyb20gJy4vbGFtYmRhLWdpdGh1Yic7XG5cbi8qKlxuICogR2V0IHdlYmhvb2sgZGVsaXZlcnkgZmFpbHVyZXMgc2luY2UgdGhlIGxhc3QgcHJvY2Vzc2VkIGRlbGl2ZXJ5IElELlxuICpcbiAqIEBpbnRlcm5hbFxuICovXG5hc3luYyBmdW5jdGlvbiBuZXdEZWxpdmVyeUZhaWx1cmVzKG9jdG9raXQ6IE9jdG9raXQsIHNpbmNlSWQ6IG51bWJlcikge1xuICBjb25zdCBkZWxpdmVyaWVzOiBNYXA8c3RyaW5nLCB7IGlkOiBudW1iZXI7IGRlbGl2ZXJlZEF0OiBEYXRlOyByZWRlbGl2ZXJ5OiBib29sZWFuIH0+ID0gbmV3IE1hcCgpO1xuICBjb25zdCBzdWNjZXNzZnVsRGVsaXZlcmllczogU2V0PHN0cmluZz4gPSBuZXcgU2V0KCk7XG4gIGNvbnN0IHRpbWVMaW1pdE1zID0gMTAwMCAqIDYwICogMzA7IC8vIGRvbid0IGxvb2sgYXQgZGVsaXZlcmllcyBvdmVyIDMwIG1pbnV0ZXMgb2xkXG4gIGxldCBsYXN0SWQgPSAwO1xuICBsZXQgcHJvY2Vzc2VkQ291bnQgPSAwO1xuXG4gIGZvciBhd2FpdCAoY29uc3QgcmVzcG9uc2Ugb2Ygb2N0b2tpdC5wYWdpbmF0ZS5pdGVyYXRvcignR0VUIC9hcHAvaG9vay9kZWxpdmVyaWVzJykpIHtcbiAgICBpZiAocmVzcG9uc2Uuc3RhdHVzICE9PSAyMDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignRmFpbGVkIHRvIGZldGNoIHdlYmhvb2sgZGVsaXZlcmllcycpO1xuICAgIH1cblxuICAgIGZvciAoY29uc3QgZGVsaXZlcnkgb2YgcmVzcG9uc2UuZGF0YSkge1xuICAgICAgY29uc3QgZGVsaXZlcmVkQXQgPSBuZXcgRGF0ZShkZWxpdmVyeS5kZWxpdmVyZWRfYXQpO1xuICAgICAgY29uc3Qgc3VjY2VzcyA9IGRlbGl2ZXJ5LnN0YXR1cyA9PT0gJ09LJztcblxuICAgICAgaWYgKGRlbGl2ZXJ5LmlkIDw9IHNpbmNlSWQpIHtcbiAgICAgICAgLy8gc3RvcCBwcm9jZXNzaW5nIGlmIHdlIHJlYWNoIHRoZSBsYXN0IHByb2Nlc3NlZCBkZWxpdmVyeSBJRFxuICAgICAgICBjb25zb2xlLmluZm8oe1xuICAgICAgICAgIG5vdGljZTogJ1JlYWNoZWQgbGFzdCBwcm9jZXNzZWQgZGVsaXZlcnkgSUQnLFxuICAgICAgICAgIHNpbmNlSWQ6IHNpbmNlSWQsXG4gICAgICAgICAgZGVsaXZlcnlJZDogZGVsaXZlcnkuaWQsXG4gICAgICAgICAgZ3VpZDogZGVsaXZlcnkuZ3VpZCxcbiAgICAgICAgICBwcm9jZXNzZWRDb3VudCxcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiB7IGRlbGl2ZXJpZXMsIGxhc3RJZCB9O1xuICAgICAgfVxuXG4gICAgICBsYXN0SWQgPSBNYXRoLm1heChsYXN0SWQsIGRlbGl2ZXJ5LmlkKTtcblxuICAgICAgaWYgKGRlbGl2ZXJlZEF0LmdldFRpbWUoKSA8IERhdGUubm93KCkgLSB0aW1lTGltaXRNcykge1xuICAgICAgICAvLyBzdG9wIHByb2Nlc3NpbmcgaWYgdGhlIGRlbGl2ZXJ5IGlzIHRvbyBvbGQgKGZvciBmaXJzdCBpdGVyYXRpb24gYW5kIHBlcmZvcm1hbmNlIG9mIGZ1cnRoZXIgaXRlcmF0aW9ucylcbiAgICAgICAgY29uc29sZS5pbmZvKHtcbiAgICAgICAgICBub3RpY2U6ICdTdG9wcGluZyBhdCBvbGQgZGVsaXZlcnknLFxuICAgICAgICAgIGRlbGl2ZXJ5SWQ6IGRlbGl2ZXJ5LmlkLFxuICAgICAgICAgIGd1aWQ6IGRlbGl2ZXJ5Lmd1aWQsXG4gICAgICAgICAgZGVsaXZlcmVkQXQ6IGRlbGl2ZXJlZEF0LFxuICAgICAgICAgIHByb2Nlc3NlZENvdW50LFxuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuIHsgZGVsaXZlcmllcywgbGFzdElkIH07XG4gICAgICB9XG5cbiAgICAgIGNvbnNvbGUuZGVidWcoe1xuICAgICAgICBub3RpY2U6ICdQcm9jZXNzaW5nIHdlYmhvb2sgZGVsaXZlcnknLFxuICAgICAgICBkZWxpdmVyeUlkOiBkZWxpdmVyeS5pZCxcbiAgICAgICAgZ3VpZDogZGVsaXZlcnkuZ3VpZCxcbiAgICAgICAgc3RhdHVzOiBkZWxpdmVyeS5zdGF0dXMsXG4gICAgICAgIGRlbGl2ZXJlZEF0OiBkZWxpdmVyeS5kZWxpdmVyZWRfYXQsXG4gICAgICAgIHJlZGVsaXZlcnk6IGRlbGl2ZXJ5LnJlZGVsaXZlcnksXG4gICAgICB9KTtcbiAgICAgIHByb2Nlc3NlZENvdW50Kys7XG5cbiAgICAgIGlmIChzdWNjZXNzKSB7XG4gICAgICAgIHN1Y2Nlc3NmdWxEZWxpdmVyaWVzLmFkZChkZWxpdmVyeS5ndWlkKTtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG5cbiAgICAgIGlmIChzdWNjZXNzZnVsRGVsaXZlcmllcy5oYXMoZGVsaXZlcnkuZ3VpZCkpIHtcbiAgICAgICAgLy8gZG8gbm90IHJlZGVsaXZlciBkZWxpdmVyaWVzIHRoYXQgd2VyZSBhbHJlYWR5IHN1Y2Nlc3NmdWxcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG5cbiAgICAgIGRlbGl2ZXJpZXMuc2V0KGRlbGl2ZXJ5Lmd1aWQsIHsgaWQ6IGRlbGl2ZXJ5LmlkLCBkZWxpdmVyZWRBdCwgcmVkZWxpdmVyeTogZGVsaXZlcnkucmVkZWxpdmVyeSB9KTtcbiAgICB9XG4gIH1cblxuICBjb25zb2xlLmluZm8oe1xuICAgIG5vdGljZTogJ05vIG1vcmUgd2ViaG9vayBkZWxpdmVyaWVzIHRvIHByb2Nlc3MnLFxuICAgIGRlbGl2ZXJ5SWQ6ICdET05FJyxcbiAgICBndWlkOiAnRE9ORScsXG4gICAgZGVsaXZlcmVkQXQ6ICdET05FJyxcbiAgICBwcm9jZXNzZWRDb3VudCxcbiAgfSk7XG5cbiAgcmV0dXJuIHsgZGVsaXZlcmllcywgbGFzdElkIH07XG59XG5cbmxldCBsYXN0RGVsaXZlcnlJZFByb2Nlc3NlZCA9IDA7XG5jb25zdCBmYWlsdXJlczogTWFwPHN0cmluZywgeyBpZDogbnVtYmVyOyBmaXJzdERlbGl2ZXJlZEF0OiBEYXRlIH0+ID0gbmV3IE1hcCgpO1xuXG4vKipcbiAqIENsZWFyIHRoZSBjYWNoZSBvZiB3ZWJob29rIGRlbGl2ZXJ5IGZhaWx1cmVzLlxuICpcbiAqIEZvciB1bml0IHRlc3RpbmcgcHVycG9zZXMgb25seS5cbiAqXG4gKiBAaW50ZXJuYWxcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNsZWFyRmFpbHVyZXNDYWNoZSgpIHtcbiAgbGFzdERlbGl2ZXJ5SWRQcm9jZXNzZWQgPSAwO1xuICBmYWlsdXJlcy5jbGVhcigpO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gaGFuZGxlcigpIHtcbiAgY29uc3Qgb2N0b2tpdCA9IGF3YWl0IGdldEFwcE9jdG9raXQoKTtcbiAgaWYgKCFvY3Rva2l0KSB7XG4gICAgY29uc29sZS5pbmZvKHtcbiAgICAgIG5vdGljZTogJ1NraXBwaW5nIHdlYmhvb2sgcmVkZWxpdmVyeScsXG4gICAgICByZWFzb246ICdBcHAgaW5zdGFsbGF0aW9uIG1pZ2h0IG5vdCBiZSBjb25maWd1cmVkIG9yIHRoZSBhcHAgaXMgbm90IGluc3RhbGxlZC4nLFxuICAgIH0pO1xuICAgIHJldHVybjtcbiAgfVxuXG4gIC8vIGZldGNoIGRlbGl2ZXJpZXMgc2luY2UgdGhlIGxhc3QgcHJvY2Vzc2VkIGRlbGl2ZXJ5IElEXG4gIC8vIGZvciBhbnkgZmFpbHVyZXM6XG4gIC8vICAxLiBpZiB0aGlzIGlzIG5vdCBhIHJlZGVsaXZlcnksIHNhdmUgdGhlIGRlbGl2ZXJ5IElEIGFuZCB0aW1lLCBhbmQgZmluYWxseSByZXRyeVxuICAvLyAgMi4gaWYgdGhpcyBpcyBhIHJlZGVsaXZlcnksIGNoZWNrIGlmIHRoZSBvcmlnaW5hbCBkZWxpdmVyeSBpcyBzdGlsbCB3aXRoaW4gdGhlIHRpbWUgbGltaXQgYW5kIHJldHJ5IGlmIGl0IGlzXG4gIGNvbnN0IHsgZGVsaXZlcmllcywgbGFzdElkIH0gPSBhd2FpdCBuZXdEZWxpdmVyeUZhaWx1cmVzKG9jdG9raXQsIGxhc3REZWxpdmVyeUlkUHJvY2Vzc2VkKTtcbiAgbGFzdERlbGl2ZXJ5SWRQcm9jZXNzZWQgPSBNYXRoLm1heChsYXN0RGVsaXZlcnlJZFByb2Nlc3NlZCwgbGFzdElkKTtcbiAgY29uc3QgdGltZUxpbWl0TXMgPSAxMDAwICogNjAgKiA2MCAqIDM7IC8vIHJldHJ5IGZvciB1cCB0byAzIGhvdXJzXG4gIGZvciAoY29uc3QgW2d1aWQsIGRldGFpbHNdIG9mIGRlbGl2ZXJpZXMpIHtcbiAgICBpZiAoIWRldGFpbHMucmVkZWxpdmVyeSkge1xuICAgICAgZmFpbHVyZXMuc2V0KGd1aWQsIHsgaWQ6IGRldGFpbHMuaWQsIGZpcnN0RGVsaXZlcmVkQXQ6IGRldGFpbHMuZGVsaXZlcmVkQXQgfSk7XG4gICAgICBjb25zb2xlLmxvZyh7XG4gICAgICAgIG5vdGljZTogJ1JlZGVsaXZlcmluZyBmYWlsZWQgZGVsaXZlcnknLFxuICAgICAgICBkZWxpdmVyeUlkOiBkZXRhaWxzLmlkLFxuICAgICAgICBndWlkOiBndWlkLFxuICAgICAgICBmaXJzdERlbGl2ZXJlZEF0OiBkZXRhaWxzLmRlbGl2ZXJlZEF0LFxuICAgICAgfSk7XG4gICAgICBhd2FpdCByZWRlbGl2ZXIob2N0b2tpdCwgZGV0YWlscy5pZCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIGlmIHRoaXMgaXMgYSByZWRlbGl2ZXJ5LCBjaGVjayBpZiB0aGUgb3JpZ2luYWwgZGVsaXZlcnkgaXMgc3RpbGwgd2l0aGluIHRoZSB0aW1lIGxpbWl0XG4gICAgICBjb25zdCBvcmlnaW5hbEZhaWx1cmUgPSBmYWlsdXJlcy5nZXQoZ3VpZCk7XG4gICAgICBpZiAob3JpZ2luYWxGYWlsdXJlKSB7XG4gICAgICAgIGlmIChuZXcgRGF0ZSgpLmdldFRpbWUoKSAtIG9yaWdpbmFsRmFpbHVyZS5maXJzdERlbGl2ZXJlZEF0LmdldFRpbWUoKSA8IHRpbWVMaW1pdE1zKSB7XG4gICAgICAgICAgY29uc29sZS5sb2coe1xuICAgICAgICAgICAgbm90aWNlOiAnUmVkZWxpdmVyaW5nIGZhaWxlZCBkZWxpdmVyeScsXG4gICAgICAgICAgICBkZWxpdmVyeUlkOiBkZXRhaWxzLmlkLFxuICAgICAgICAgICAgZ3VpZDogZ3VpZCxcbiAgICAgICAgICAgIGZpcnN0RGVsaXZlcmVkQXQ6IG9yaWdpbmFsRmFpbHVyZS5maXJzdERlbGl2ZXJlZEF0LFxuICAgICAgICAgIH0pO1xuICAgICAgICAgIGF3YWl0IHJlZGVsaXZlcihvY3Rva2l0LCBkZXRhaWxzLmlkKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBmYWlsdXJlcy5kZWxldGUoZ3VpZCk7IC8vIG5vIG5lZWQgdG8ga2VlcCB0cmFjayBvZiB0aGlzIGFueW1vcmVcbiAgICAgICAgICBjb25zb2xlLmxvZyh7XG4gICAgICAgICAgICBub3RpY2U6ICdTa2lwcGluZyByZWRlbGl2ZXJ5IG9mIG9sZCBmYWlsZWQgZGVsaXZlcnknLFxuICAgICAgICAgICAgZGVsaXZlcnlJZDogZGV0YWlscy5pZCxcbiAgICAgICAgICAgIGd1aWQ6IGd1aWQsXG4gICAgICAgICAgICBmaXJzdERlbGl2ZXJlZEF0OiBvcmlnaW5hbEZhaWx1cmU/LmZpcnN0RGVsaXZlcmVkQXQsXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnNvbGUubG9nKHtcbiAgICAgICAgICBub3RpY2U6ICdTa2lwcGluZyByZWRlbGl2ZXJ5IG9mIG9sZCBmYWlsZWQgZGVsaXZlcnknLFxuICAgICAgICAgIGRlbGl2ZXJ5SWQ6IGRldGFpbHMuaWQsXG4gICAgICAgICAgZ3VpZDogZ3VpZCxcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfVxuICB9XG59XG4iXX0=