cdk-nextjs
Version:
Deploy Next.js apps on AWS with CDK
101 lines • 15.2 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.pruneS3 = pruneS3;
// eslint-disable-next-line import/no-extraneous-dependencies
const client_s3_1 = require("@aws-sdk/client-s3");
const utils_1 = require("../utils");
const s3Client = new client_s3_1.S3Client();
// Maximum number of concurrent operations
const MAX_CONCURRENT_OPERATIONS = 50;
/**
* Given `bucketName`, `currentBuildId`, and `msTtl`, list all objects
* in the bucket and delete any that 1/ do not have a metadata key of "next-build-id"
* and value of `currentBuildId` and 2/ were created more than `msTtl` ago
*/
async function pruneS3(props) {
const { bucketName, currentBuildId, msTtl } = props;
const cutoffDate = new Date(Date.now() - msTtl);
const objectsToDelete = [];
let continuationToken = undefined;
let listObjectsCount = 0;
do {
// List objects in the bucket
const listObjectsV2Input = {
Bucket: bucketName,
ContinuationToken: continuationToken,
};
const listResponse = await s3Client.send(new client_s3_1.ListObjectsV2Command(listObjectsV2Input));
if (!listResponse.Contents || listResponse.Contents.length === 0) {
break;
}
// Filter out objects without keys
const oldObjects = listResponse.Contents.filter((obj) => {
const lastModified = obj.LastModified || new Date();
return obj.Key && lastModified < cutoffDate;
});
(0, utils_1.debug)(`Checking old objects metadata to determine pruning: ${oldObjects.map((o) => o.Key)}`);
// Process objects in parallel with controlled concurrency
const checkResults = await processBatch(oldObjects, MAX_CONCURRENT_OPERATIONS, async (object) => {
if (!object.Key)
return null;
try {
const headResponse = await s3Client.send(new client_s3_1.HeadObjectCommand({
Bucket: bucketName,
Key: object.Key,
}));
const objectBuildId = headResponse.Metadata?.["next-build-id"];
// Return the key if it should be deleted
if (objectBuildId !== currentBuildId) {
return { Key: object.Key };
}
}
catch (error) {
console.error(`Error checking object ${object.Key}:`, error);
}
return null;
});
// Add valid objects to delete list
objectsToDelete.push(...checkResults.filter(Boolean));
if (listResponse.NextContinuationToken) {
continuationToken = listResponse.NextContinuationToken;
}
listObjectsCount++;
// assume less than 100K objects (100 * 1K objects per ListObjectsV2Command = 100K)
} while (continuationToken && listObjectsCount <= 100);
// Delete objects in parallel batches (respecting S3's 1000 objects per request limit)
if (objectsToDelete.length > 0) {
const deleteBatches = [];
for (let i = 0; i < objectsToDelete.length; i += 1000) {
const batch = objectsToDelete.slice(i, i + 1000);
deleteBatches.push(batch);
}
await processBatch(deleteBatches, 5, // Process up to 5 delete batches in parallel
async (batch) => {
try {
(0, utils_1.debug)(`Deleting objects: ${batch.map((b) => b.Key)} from ${bucketName}`);
await s3Client.send(new client_s3_1.DeleteObjectsCommand({
Bucket: bucketName,
Delete: { Objects: batch },
}));
(0, utils_1.debug)(`Deleted ${batch.length} objects from ${bucketName}`);
}
catch (error) {
console.error("Error deleting objects:", error);
}
});
}
(0, utils_1.debug)(`Pruning complete. Deleted ${objectsToDelete.length} objects from ${bucketName}`);
}
/**
* Process objects in batches to avoid overwhelming the system
*/
async function processBatch(items, batchSize, processFn) {
const results = [];
for (let i = 0; i < items.length; i += batchSize) {
const batch = items.slice(i, i + batchSize);
const batchResults = await Promise.all(batch.map(processFn));
results.push(...batchResults);
}
return results;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJ1bmUtczMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbGFtYmRhcy9wb3N0LWRlcGxveS9wcnVuZS1zMy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQTRCQSwwQkEyR0M7QUF2SUQsNkRBQTZEO0FBQzdELGtEQU00QjtBQUM1QixvQ0FBaUM7QUFFakMsTUFBTSxRQUFRLEdBQUcsSUFBSSxvQkFBUSxFQUFFLENBQUM7QUFDaEMsMENBQTBDO0FBQzFDLE1BQU0seUJBQXlCLEdBQUcsRUFBRSxDQUFDO0FBV3JDOzs7O0dBSUc7QUFDSSxLQUFLLFVBQVUsT0FBTyxDQUFDLEtBQW1CO0lBQy9DLE1BQU0sRUFBRSxVQUFVLEVBQUUsY0FBYyxFQUFFLEtBQUssRUFBRSxHQUFHLEtBQUssQ0FBQztJQUVwRCxNQUFNLFVBQVUsR0FBRyxJQUFJLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLEdBQUcsS0FBSyxDQUFDLENBQUM7SUFDaEQsTUFBTSxlQUFlLEdBQXNCLEVBQUUsQ0FBQztJQUU5QyxJQUFJLGlCQUFpQixHQUF1QixTQUFTLENBQUM7SUFDdEQsSUFBSSxnQkFBZ0IsR0FBRyxDQUFDLENBQUM7SUFFekIsR0FBRyxDQUFDO1FBQ0YsNkJBQTZCO1FBQzdCLE1BQU0sa0JBQWtCLEdBQThCO1lBQ3BELE1BQU0sRUFBRSxVQUFVO1lBQ2xCLGlCQUFpQixFQUFFLGlCQUFpQjtTQUNyQyxDQUFDO1FBQ0YsTUFBTSxZQUFZLEdBQUcsTUFBTSxRQUFRLENBQUMsSUFBSSxDQUN0QyxJQUFJLGdDQUFvQixDQUFDLGtCQUFrQixDQUFDLENBQzdDLENBQUM7UUFFRixJQUFJLENBQUMsWUFBWSxDQUFDLFFBQVEsSUFBSSxZQUFZLENBQUMsUUFBUSxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUNqRSxNQUFNO1FBQ1IsQ0FBQztRQUVELGtDQUFrQztRQUNsQyxNQUFNLFVBQVUsR0FBRyxZQUFZLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFDLEdBQUcsRUFBRSxFQUFFO1lBQ3RELE1BQU0sWUFBWSxHQUFHLEdBQUcsQ0FBQyxZQUFZLElBQUksSUFBSSxJQUFJLEVBQUUsQ0FBQztZQUNwRCxPQUFPLEdBQUcsQ0FBQyxHQUFHLElBQUksWUFBWSxHQUFHLFVBQVUsQ0FBQztRQUM5QyxDQUFDLENBQUMsQ0FBQztRQUNILElBQUEsYUFBSyxFQUNILHVEQUF1RCxVQUFVLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FDdEYsQ0FBQztRQUVGLDBEQUEwRDtRQUMxRCxNQUFNLFlBQVksR0FBRyxNQUFNLFlBQVksQ0FDckMsVUFBVSxFQUNWLHlCQUF5QixFQUN6QixLQUFLLEVBQUUsTUFBTSxFQUFFLEVBQUU7WUFDZixJQUFJLENBQUMsTUFBTSxDQUFDLEdBQUc7Z0JBQUUsT0FBTyxJQUFJLENBQUM7WUFFN0IsSUFBSSxDQUFDO2dCQUNILE1BQU0sWUFBWSxHQUFHLE1BQU0sUUFBUSxDQUFDLElBQUksQ0FDdEMsSUFBSSw2QkFBaUIsQ0FBQztvQkFDcEIsTUFBTSxFQUFFLFVBQVU7b0JBQ2xCLEdBQUcsRUFBRSxNQUFNLENBQUMsR0FBRztpQkFDaEIsQ0FBQyxDQUNILENBQUM7Z0JBRUYsTUFBTSxhQUFhLEdBQUcsWUFBWSxDQUFDLFFBQVEsRUFBRSxDQUFDLGVBQWUsQ0FBQyxDQUFDO2dCQUUvRCx5Q0FBeUM7Z0JBQ3pDLElBQUksYUFBYSxLQUFLLGNBQWMsRUFBRSxDQUFDO29CQUNyQyxPQUFPLEVBQUUsR0FBRyxFQUFFLE1BQU0sQ0FBQyxHQUFHLEVBQUUsQ0FBQztnQkFDN0IsQ0FBQztZQUNILENBQUM7WUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO2dCQUNmLE9BQU8sQ0FBQyxLQUFLLENBQUMseUJBQXlCLE1BQU0sQ0FBQyxHQUFHLEdBQUcsRUFBRSxLQUFLLENBQUMsQ0FBQztZQUMvRCxDQUFDO1lBRUQsT0FBTyxJQUFJLENBQUM7UUFDZCxDQUFDLENBQ0YsQ0FBQztRQUVGLG1DQUFtQztRQUNuQyxlQUFlLENBQUMsSUFBSSxDQUNsQixHQUFJLFlBQVksQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUF1QixDQUN2RCxDQUFDO1FBRUYsSUFBSSxZQUFZLENBQUMscUJBQXFCLEVBQUUsQ0FBQztZQUN2QyxpQkFBaUIsR0FBRyxZQUFZLENBQUMscUJBQXFCLENBQUM7UUFDekQsQ0FBQztRQUNELGdCQUFnQixFQUFFLENBQUM7UUFDbkIsbUZBQW1GO0lBQ3JGLENBQUMsUUFBUSxpQkFBaUIsSUFBSSxnQkFBZ0IsSUFBSSxHQUFHLEVBQUU7SUFFdkQsc0ZBQXNGO0lBQ3RGLElBQUksZUFBZSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztRQUMvQixNQUFNLGFBQWEsR0FBRyxFQUFFLENBQUM7UUFFekIsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLGVBQWUsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxJQUFJLElBQUksRUFBRSxDQUFDO1lBQ3RELE1BQU0sS0FBSyxHQUFHLGVBQWUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLENBQUMsR0FBRyxJQUFJLENBQUMsQ0FBQztZQUNqRCxhQUFhLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQzVCLENBQUM7UUFFRCxNQUFNLFlBQVksQ0FDaEIsYUFBYSxFQUNiLENBQUMsRUFBRSw2Q0FBNkM7UUFDaEQsS0FBSyxFQUFFLEtBQUssRUFBRSxFQUFFO1lBQ2QsSUFBSSxDQUFDO2dCQUNILElBQUEsYUFBSyxFQUNILHFCQUFxQixLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLFNBQVMsVUFBVSxFQUFFLENBQ2xFLENBQUM7Z0JBQ0YsTUFBTSxRQUFRLENBQUMsSUFBSSxDQUNqQixJQUFJLGdDQUFvQixDQUFDO29CQUN2QixNQUFNLEVBQUUsVUFBVTtvQkFDbEIsTUFBTSxFQUFFLEVBQUUsT0FBTyxFQUFFLEtBQUssRUFBRTtpQkFDM0IsQ0FBQyxDQUNILENBQUM7Z0JBQ0YsSUFBQSxhQUFLLEVBQUMsV0FBVyxLQUFLLENBQUMsTUFBTSxpQkFBaUIsVUFBVSxFQUFFLENBQUMsQ0FBQztZQUM5RCxDQUFDO1lBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztnQkFDZixPQUFPLENBQUMsS0FBSyxDQUFDLHlCQUF5QixFQUFFLEtBQUssQ0FBQyxDQUFDO1lBQ2xELENBQUM7UUFDSCxDQUFDLENBQ0YsQ0FBQztJQUNKLENBQUM7SUFFRCxJQUFBLGFBQUssRUFDSCw2QkFBNkIsZUFBZSxDQUFDLE1BQU0saUJBQWlCLFVBQVUsRUFBRSxDQUNqRixDQUFDO0FBQ0osQ0FBQztBQUVEOztHQUVHO0FBQ0gsS0FBSyxVQUFVLFlBQVksQ0FDekIsS0FBVSxFQUNWLFNBQWlCLEVBQ2pCLFNBQWtDO0lBRWxDLE1BQU0sT0FBTyxHQUFRLEVBQUUsQ0FBQztJQUV4QixLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsS0FBSyxDQUFDLE1BQU0sRUFBRSxDQUFDLElBQUksU0FBUyxFQUFFLENBQUM7UUFDakQsTUFBTSxLQUFLLEdBQUcsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsQ0FBQyxHQUFHLFNBQVMsQ0FBQyxDQUFDO1FBQzVDLE1BQU0sWUFBWSxHQUFHLE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUM7UUFDN0QsT0FBTyxDQUFDLElBQUksQ0FBQyxHQUFHLFlBQVksQ0FBQyxDQUFDO0lBQ2hDLENBQUM7SUFFRCxPQUFPLE9BQU8sQ0FBQztBQUNqQixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGltcG9ydC9uby1leHRyYW5lb3VzLWRlcGVuZGVuY2llc1xuaW1wb3J0IHtcbiAgUzNDbGllbnQsXG4gIExpc3RPYmplY3RzVjJDb21tYW5kLFxuICBEZWxldGVPYmplY3RzQ29tbWFuZCxcbiAgSGVhZE9iamVjdENvbW1hbmQsXG4gIExpc3RPYmplY3RzVjJDb21tYW5kSW5wdXQsXG59IGZyb20gXCJAYXdzLXNkay9jbGllbnQtczNcIjtcbmltcG9ydCB7IGRlYnVnIH0gZnJvbSBcIi4uL3V0aWxzXCI7XG5cbmNvbnN0IHMzQ2xpZW50ID0gbmV3IFMzQ2xpZW50KCk7XG4vLyBNYXhpbXVtIG51bWJlciBvZiBjb25jdXJyZW50IG9wZXJhdGlvbnNcbmNvbnN0IE1BWF9DT05DVVJSRU5UX09QRVJBVElPTlMgPSA1MDtcblxuaW50ZXJmYWNlIFBydW5lUzNQcm9wcyB7XG4gIGJ1Y2tldE5hbWU6IHN0cmluZztcbiAgY3VycmVudEJ1aWxkSWQ6IHN0cmluZztcbiAgLyoqXG4gICAqIFRpbWUgdG8gbGl2ZSBpbiBtaWxsaXNlY29uZHMuXG4gICAqL1xuICBtc1R0bDogbnVtYmVyO1xufVxuXG4vKipcbiAqIEdpdmVuIGBidWNrZXROYW1lYCwgYGN1cnJlbnRCdWlsZElkYCwgYW5kIGBtc1R0bGAsIGxpc3QgYWxsIG9iamVjdHNcbiAqIGluIHRoZSBidWNrZXQgYW5kIGRlbGV0ZSBhbnkgdGhhdCAxLyBkbyBub3QgaGF2ZSBhIG1ldGFkYXRhIGtleSBvZiBcIm5leHQtYnVpbGQtaWRcIlxuICogYW5kIHZhbHVlIG9mIGBjdXJyZW50QnVpbGRJZGAgYW5kIDIvIHdlcmUgY3JlYXRlZCBtb3JlIHRoYW4gYG1zVHRsYCBhZ29cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHBydW5lUzMocHJvcHM6IFBydW5lUzNQcm9wcykge1xuICBjb25zdCB7IGJ1Y2tldE5hbWUsIGN1cnJlbnRCdWlsZElkLCBtc1R0bCB9ID0gcHJvcHM7XG5cbiAgY29uc3QgY3V0b2ZmRGF0ZSA9IG5ldyBEYXRlKERhdGUubm93KCkgLSBtc1R0bCk7XG4gIGNvbnN0IG9iamVjdHNUb0RlbGV0ZTogeyBLZXk6IHN0cmluZyB9W10gPSBbXTtcblxuICBsZXQgY29udGludWF0aW9uVG9rZW46IHN0cmluZyB8IHVuZGVmaW5lZCA9IHVuZGVmaW5lZDtcbiAgbGV0IGxpc3RPYmplY3RzQ291bnQgPSAwO1xuXG4gIGRvIHtcbiAgICAvLyBMaXN0IG9iamVjdHMgaW4gdGhlIGJ1Y2tldFxuICAgIGNvbnN0IGxpc3RPYmplY3RzVjJJbnB1dDogTGlzdE9iamVjdHNWMkNvbW1hbmRJbnB1dCA9IHtcbiAgICAgIEJ1Y2tldDogYnVja2V0TmFtZSxcbiAgICAgIENvbnRpbnVhdGlvblRva2VuOiBjb250aW51YXRpb25Ub2tlbixcbiAgICB9O1xuICAgIGNvbnN0IGxpc3RSZXNwb25zZSA9IGF3YWl0IHMzQ2xpZW50LnNlbmQoXG4gICAgICBuZXcgTGlzdE9iamVjdHNWMkNvbW1hbmQobGlzdE9iamVjdHNWMklucHV0KSxcbiAgICApO1xuXG4gICAgaWYgKCFsaXN0UmVzcG9uc2UuQ29udGVudHMgfHwgbGlzdFJlc3BvbnNlLkNvbnRlbnRzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgYnJlYWs7XG4gICAgfVxuXG4gICAgLy8gRmlsdGVyIG91dCBvYmplY3RzIHdpdGhvdXQga2V5c1xuICAgIGNvbnN0IG9sZE9iamVjdHMgPSBsaXN0UmVzcG9uc2UuQ29udGVudHMuZmlsdGVyKChvYmopID0+IHtcbiAgICAgIGNvbnN0IGxhc3RNb2RpZmllZCA9IG9iai5MYXN0TW9kaWZpZWQgfHwgbmV3IERhdGUoKTtcbiAgICAgIHJldHVybiBvYmouS2V5ICYmIGxhc3RNb2RpZmllZCA8IGN1dG9mZkRhdGU7XG4gICAgfSk7XG4gICAgZGVidWcoXG4gICAgICBgQ2hlY2tpbmcgb2xkIG9iamVjdHMgbWV0YWRhdGEgdG8gZGV0ZXJtaW5lIHBydW5pbmc6ICR7b2xkT2JqZWN0cy5tYXAoKG8pID0+IG8uS2V5KX1gLFxuICAgICk7XG5cbiAgICAvLyBQcm9jZXNzIG9iamVjdHMgaW4gcGFyYWxsZWwgd2l0aCBjb250cm9sbGVkIGNvbmN1cnJlbmN5XG4gICAgY29uc3QgY2hlY2tSZXN1bHRzID0gYXdhaXQgcHJvY2Vzc0JhdGNoKFxuICAgICAgb2xkT2JqZWN0cyxcbiAgICAgIE1BWF9DT05DVVJSRU5UX09QRVJBVElPTlMsXG4gICAgICBhc3luYyAob2JqZWN0KSA9PiB7XG4gICAgICAgIGlmICghb2JqZWN0LktleSkgcmV0dXJuIG51bGw7XG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBjb25zdCBoZWFkUmVzcG9uc2UgPSBhd2FpdCBzM0NsaWVudC5zZW5kKFxuICAgICAgICAgICAgbmV3IEhlYWRPYmplY3RDb21tYW5kKHtcbiAgICAgICAgICAgICAgQnVja2V0OiBidWNrZXROYW1lLFxuICAgICAgICAgICAgICBLZXk6IG9iamVjdC5LZXksXG4gICAgICAgICAgICB9KSxcbiAgICAgICAgICApO1xuXG4gICAgICAgICAgY29uc3Qgb2JqZWN0QnVpbGRJZCA9IGhlYWRSZXNwb25zZS5NZXRhZGF0YT8uW1wibmV4dC1idWlsZC1pZFwiXTtcblxuICAgICAgICAgIC8vIFJldHVybiB0aGUga2V5IGlmIGl0IHNob3VsZCBiZSBkZWxldGVkXG4gICAgICAgICAgaWYgKG9iamVjdEJ1aWxkSWQgIT09IGN1cnJlbnRCdWlsZElkKSB7XG4gICAgICAgICAgICByZXR1cm4geyBLZXk6IG9iamVjdC5LZXkgfTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgY29uc29sZS5lcnJvcihgRXJyb3IgY2hlY2tpbmcgb2JqZWN0ICR7b2JqZWN0LktleX06YCwgZXJyb3IpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICB9LFxuICAgICk7XG5cbiAgICAvLyBBZGQgdmFsaWQgb2JqZWN0cyB0byBkZWxldGUgbGlzdFxuICAgIG9iamVjdHNUb0RlbGV0ZS5wdXNoKFxuICAgICAgLi4uKGNoZWNrUmVzdWx0cy5maWx0ZXIoQm9vbGVhbikgYXMgeyBLZXk6IHN0cmluZyB9W10pLFxuICAgICk7XG5cbiAgICBpZiAobGlzdFJlc3BvbnNlLk5leHRDb250aW51YXRpb25Ub2tlbikge1xuICAgICAgY29udGludWF0aW9uVG9rZW4gPSBsaXN0UmVzcG9uc2UuTmV4dENvbnRpbnVhdGlvblRva2VuO1xuICAgIH1cbiAgICBsaXN0T2JqZWN0c0NvdW50Kys7XG4gICAgLy8gYXNzdW1lIGxlc3MgdGhhbiAxMDBLIG9iamVjdHMgKDEwMCAqIDFLIG9iamVjdHMgcGVyIExpc3RPYmplY3RzVjJDb21tYW5kID0gMTAwSylcbiAgfSB3aGlsZSAoY29udGludWF0aW9uVG9rZW4gJiYgbGlzdE9iamVjdHNDb3VudCA8PSAxMDApO1xuXG4gIC8vIERlbGV0ZSBvYmplY3RzIGluIHBhcmFsbGVsIGJhdGNoZXMgKHJlc3BlY3RpbmcgUzMncyAxMDAwIG9iamVjdHMgcGVyIHJlcXVlc3QgbGltaXQpXG4gIGlmIChvYmplY3RzVG9EZWxldGUubGVuZ3RoID4gMCkge1xuICAgIGNvbnN0IGRlbGV0ZUJhdGNoZXMgPSBbXTtcblxuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgb2JqZWN0c1RvRGVsZXRlLmxlbmd0aDsgaSArPSAxMDAwKSB7XG4gICAgICBjb25zdCBiYXRjaCA9IG9iamVjdHNUb0RlbGV0ZS5zbGljZShpLCBpICsgMTAwMCk7XG4gICAgICBkZWxldGVCYXRjaGVzLnB1c2goYmF0Y2gpO1xuICAgIH1cblxuICAgIGF3YWl0IHByb2Nlc3NCYXRjaChcbiAgICAgIGRlbGV0ZUJhdGNoZXMsXG4gICAgICA1LCAvLyBQcm9jZXNzIHVwIHRvIDUgZGVsZXRlIGJhdGNoZXMgaW4gcGFyYWxsZWxcbiAgICAgIGFzeW5jIChiYXRjaCkgPT4ge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGRlYnVnKFxuICAgICAgICAgICAgYERlbGV0aW5nIG9iamVjdHM6ICR7YmF0Y2gubWFwKChiKSA9PiBiLktleSl9IGZyb20gJHtidWNrZXROYW1lfWAsXG4gICAgICAgICAgKTtcbiAgICAgICAgICBhd2FpdCBzM0NsaWVudC5zZW5kKFxuICAgICAgICAgICAgbmV3IERlbGV0ZU9iamVjdHNDb21tYW5kKHtcbiAgICAgICAgICAgICAgQnVja2V0OiBidWNrZXROYW1lLFxuICAgICAgICAgICAgICBEZWxldGU6IHsgT2JqZWN0czogYmF0Y2ggfSxcbiAgICAgICAgICAgIH0pLFxuICAgICAgICAgICk7XG4gICAgICAgICAgZGVidWcoYERlbGV0ZWQgJHtiYXRjaC5sZW5ndGh9IG9iamVjdHMgZnJvbSAke2J1Y2tldE5hbWV9YCk7XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgY29uc29sZS5lcnJvcihcIkVycm9yIGRlbGV0aW5nIG9iamVjdHM6XCIsIGVycm9yKTtcbiAgICAgICAgfVxuICAgICAgfSxcbiAgICApO1xuICB9XG5cbiAgZGVidWcoXG4gICAgYFBydW5pbmcgY29tcGxldGUuIERlbGV0ZWQgJHtvYmplY3RzVG9EZWxldGUubGVuZ3RofSBvYmplY3RzIGZyb20gJHtidWNrZXROYW1lfWAsXG4gICk7XG59XG5cbi8qKlxuICogUHJvY2VzcyBvYmplY3RzIGluIGJhdGNoZXMgdG8gYXZvaWQgb3ZlcndoZWxtaW5nIHRoZSBzeXN0ZW1cbiAqL1xuYXN5bmMgZnVuY3Rpb24gcHJvY2Vzc0JhdGNoPFQsIFI+KFxuICBpdGVtczogVFtdLFxuICBiYXRjaFNpemU6IG51bWJlcixcbiAgcHJvY2Vzc0ZuOiAoaXRlbTogVCkgPT4gUHJvbWlzZTxSPixcbik6IFByb21pc2U8UltdPiB7XG4gIGNvbnN0IHJlc3VsdHM6IFJbXSA9IFtdO1xuXG4gIGZvciAobGV0IGkgPSAwOyBpIDwgaXRlbXMubGVuZ3RoOyBpICs9IGJhdGNoU2l6ZSkge1xuICAgIGNvbnN0IGJhdGNoID0gaXRlbXMuc2xpY2UoaSwgaSArIGJhdGNoU2l6ZSk7XG4gICAgY29uc3QgYmF0Y2hSZXN1bHRzID0gYXdhaXQgUHJvbWlzZS5hbGwoYmF0Y2gubWFwKHByb2Nlc3NGbikpO1xuICAgIHJlc3VsdHMucHVzaCguLi5iYXRjaFJlc3VsdHMpO1xuICB9XG5cbiAgcmV0dXJuIHJlc3VsdHM7XG59XG4iXX0=