UNPKG

@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.

158 lines 18.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.handler = handler; const client_ec2_1 = require("@aws-sdk/client-ec2"); const client_ecr_1 = require("@aws-sdk/client-ecr"); const client_imagebuilder_1 = require("@aws-sdk/client-imagebuilder"); const lambda_helpers_1 = require("../../lambda-helpers"); const ec2 = new client_ec2_1.EC2Client(); const ecr = new client_ecr_1.ECRClient(); const ib = new client_imagebuilder_1.ImagebuilderClient(); async function deleteResources(props) { const buildsToDelete = []; const amisToDelete = []; const dockerImagesToDelete = []; let result = {}; do { result = await ib.send(new client_imagebuilder_1.ListImageBuildVersionsCommand({ imageVersionArn: props.ImageVersionArn, nextToken: result.nextToken, })); if (result.imageSummaryList) { for (const image of result.imageSummaryList) { if (image.arn) { buildsToDelete.push(image.arn); } for (const output of image.outputResources?.amis ?? []) { if (output.image) { amisToDelete.push(output.image); } } for (const output of image.outputResources?.containers ?? []) { if (output.imageUris) { dockerImagesToDelete.push(...output.imageUris); } } } } } while (result.nextToken); // delete amis for (const imageId of amisToDelete) { try { console.log({ notice: 'Deleting AMI', image: imageId, }); const imageDesc = await ec2.send(new client_ec2_1.DescribeImagesCommand({ Owners: ['self'], ImageIds: [imageId], })); if (imageDesc.Images?.length !== 1) { console.warn({ notice: 'Unable to find AMI', image: imageId, }); continue; } await ec2.send(new client_ec2_1.DeregisterImageCommand({ ImageId: imageId, })); for (const blockMapping of imageDesc.Images[0].BlockDeviceMappings ?? []) { if (blockMapping.Ebs?.SnapshotId) { console.log({ notice: 'Deleting EBS snapshot', image: imageId, snapshot: blockMapping.Ebs.SnapshotId, }); await ec2.send(new client_ec2_1.DeleteSnapshotCommand({ SnapshotId: blockMapping.Ebs.SnapshotId, })); } } } catch (e) { console.warn({ notice: 'Failed to delete AMI', image: imageId, error: e, }); } } // delete docker images for (const image of dockerImagesToDelete) { try { console.log({ notice: 'Deleting Docker Image', image, }); // image looks like 0123456789.dkr.ecr.us-east-1.amazonaws.com/github-runners-test-windowsimagebuilderrepositorya4cbb6d8-hehdl99r7s3d:1.0.10-1 const parts = image.split('/')[1].split(':'); const repo = parts[0]; const tag = parts[1]; // delete image await ecr.send(new client_ecr_1.BatchDeleteImageCommand({ repositoryName: repo, imageIds: [ { imageTag: tag, }, ], })); } catch (e) { console.warn({ notice: 'Failed to delete docker image', image, error: e, }); } } // delete builds (last so retries would still work) for (const build of buildsToDelete) { try { console.log({ notice: 'Deleting Image Build', build, }); await ib.send(new client_imagebuilder_1.DeleteImageCommand({ imageBuildVersionArn: build, })); } catch (e) { console.warn({ notice: 'Failed to delete image version build', build, error: e, }); } } } async function handler(event, _context) { try { console.log({ ...event, ResponseURL: '...', }); const props = event.ResourceProperties; switch (event.RequestType) { case 'Create': case 'Update': // we just return the arn as the physical id // this way a change in the version will trigger delete of the old version on cleanup of stack // it will also trigger delete on stack deletion await (0, lambda_helpers_1.customResourceRespond)(event, 'SUCCESS', 'OK', props.ImageVersionArn, {}); break; case 'Delete': if (event.PhysicalResourceId != 'FAIL') { await deleteResources(props); } await (0, lambda_helpers_1.customResourceRespond)(event, 'SUCCESS', 'OK', event.PhysicalResourceId, {}); break; } } catch (e) { console.error(e); await (0, lambda_helpers_1.customResourceRespond)(event, 'FAILED', e.message || 'Internal Error', 'FAIL', {}); } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVsZXRlLXJlc291cmNlcy5sYW1iZGEuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvaW1hZ2UtYnVpbGRlcnMvYXdzLWltYWdlLWJ1aWxkZXIvZGVsZXRlLXJlc291cmNlcy5sYW1iZGEudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFtSkEsMEJBNEJDO0FBL0tELG9EQUFzSDtBQUN0SCxvREFBeUU7QUFDekUsc0VBQXFKO0FBRXJKLHlEQUE2RDtBQUU3RCxNQUFNLEdBQUcsR0FBRyxJQUFJLHNCQUFTLEVBQUUsQ0FBQztBQUM1QixNQUFNLEdBQUcsR0FBRyxJQUFJLHNCQUFTLEVBQUUsQ0FBQztBQUM1QixNQUFNLEVBQUUsR0FBRyxJQUFJLHdDQUFrQixFQUFFLENBQUM7QUFVcEMsS0FBSyxVQUFVLGVBQWUsQ0FBQyxLQUEyQjtJQUN4RCxNQUFNLGNBQWMsR0FBYSxFQUFFLENBQUM7SUFDcEMsTUFBTSxZQUFZLEdBQWEsRUFBRSxDQUFDO0lBQ2xDLE1BQU0sb0JBQW9CLEdBQWEsRUFBRSxDQUFDO0lBRTFDLElBQUksTUFBTSxHQUFtQyxFQUFFLENBQUM7SUFDaEQsR0FBRyxDQUFDO1FBQ0YsTUFBTSxHQUFHLE1BQU0sRUFBRSxDQUFDLElBQUksQ0FBQyxJQUFJLG1EQUE2QixDQUFDO1lBQ3ZELGVBQWUsRUFBRSxLQUFLLENBQUMsZUFBZTtZQUN0QyxTQUFTLEVBQUUsTUFBTSxDQUFDLFNBQVM7U0FDNUIsQ0FBQyxDQUFDLENBQUM7UUFDSixJQUFJLE1BQU0sQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO1lBQzVCLEtBQUssTUFBTSxLQUFLLElBQUksTUFBTSxDQUFDLGdCQUFnQixFQUFFLENBQUM7Z0JBQzVDLElBQUksS0FBSyxDQUFDLEdBQUcsRUFBRSxDQUFDO29CQUNkLGNBQWMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDO2dCQUNqQyxDQUFDO2dCQUNELEtBQUssTUFBTSxNQUFNLElBQUks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TUFBTSxLQUFLLEdBQUcsS0FBSyxDQUFDLGtCQUEwQyxDQUFDO1FBRS9ELFFBQVEsS0FBSyxDQUFDLFdBQVcsRUFBRSxDQUFDO1lBQzFCLEtBQUssUUFBUSxDQUFDO1lBQ2QsS0FBSyxRQUFRO2dCQUNYLDRDQUE0QztnQkFDNUMsOEZBQThGO2dCQUM5RixnREFBZ0Q7Z0JBQ2hELE1BQU0sSUFBQSxzQ0FBcUIsRUFBQyxLQUFLLEVBQUUsU0FBUyxFQUFFLElBQUksRUFBRSxLQUFLLENBQUMsZUFBZSxFQUFFLEVBQUUsQ0FBQyxDQUFDO2dCQUMvRSxNQUFNO1lBQ1IsS0FBSyxRQUFRO2dCQUNYLElBQUksS0FBSyxDQUFDLGtCQUFrQixJQUFJLE1BQU0sRUFBRSxDQUFDO29CQUN2QyxNQUFNLGVBQWUsQ0FBQyxLQUFLLENBQUMsQ0FBQztnQkFDL0IsQ0FBQztnQkFDRCxNQUFNLElBQUEsc0NBQXFCLEVBQUMsS0FBSyxFQUFFLFNBQVMsRUFBRSxJQUFJLEVBQUUsS0FBSyxDQUFDLGtCQUFrQixFQUFFLEVBQUUsQ0FBQyxDQUFDO2dCQUNsRixNQUFNO1FBQ1YsQ0FBQztJQUNILENBQUM7SUFBQyxPQUFPLENBQUMsRUFBRSxDQUFDO1FBQ1gsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNqQixNQUFNLElBQUEsc0NBQXFCLEVBQUMsS0FBSyxFQUFFLFFBQVEsRUFBRyxDQUFXLENBQUMsT0FBTyxJQUFJLGdCQUFnQixFQUFFLE1BQU0sRUFBRSxFQUFFLENBQUMsQ0FBQztJQUNyRyxDQUFDO0FBQ0gsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IERlbGV0ZVNuYXBzaG90Q29tbWFuZCwgRGVyZWdpc3RlckltYWdlQ29tbWFuZCwgRGVzY3JpYmVJbWFnZXNDb21tYW5kLCBFQzJDbGllbnQgfSBmcm9tICdAYXdzLXNkay9jbGllbnQtZWMyJztcbmltcG9ydCB7IEJhdGNoRGVsZXRlSW1hZ2VDb21tYW5kLCBFQ1JDbGllbnQgfSBmcm9tICdAYXdzLXNkay9jbGllbnQtZWNyJztcbmltcG9ydCB7IERlbGV0ZUltYWdlQ29tbWFuZCwgSW1hZ2VidWlsZGVyQ2xpZW50LCBMaXN0SW1hZ2VCdWlsZFZlcnNpb25zQ29tbWFuZCwgTGlzdEltYWdlQnVpbGRWZXJzaW9uc1Jlc3BvbnNlIH0gZnJvbSAnQGF3cy1zZGsvY2xpZW50LWltYWdlYnVpbGRlcic7XG5pbXBvcnQgKiBhcyBBV1NMYW1iZGEgZnJvbSAnYXdzLWxhbWJkYSc7XG5pbXBvcnQgeyBjdXN0b21SZXNvdXJjZVJlc3BvbmQgfSBmcm9tICcuLi8uLi9sYW1iZGEtaGVscGVycyc7XG5cbmNvbnN0IGVjMiA9IG5ldyBFQzJDbGllbnQoKTtcbmNvbnN0IGVjciA9IG5ldyBFQ1JDbGllbnQoKTtcbmNvbnN0IGliID0gbmV3IEltYWdlYnVpbGRlckNsaWVudCgpO1xuXG4vKipcbiAqIEBpbnRlcm5hbFxuICovXG5leHBvcnQgaW50ZXJmYWNlIERlbGV0ZVJlc291cmNlc1Byb3BzIHtcbiAgU2VydmljZVRva2VuOiBzdHJpbmc7XG4gIEltYWdlVmVyc2lvbkFybjogc3RyaW5nO1xufVxuXG5hc3luYyBmdW5jdGlvbiBkZWxldGVSZXNvdXJjZXMocHJvcHM6IERlbGV0ZVJlc291cmNlc1Byb3BzKSB7XG4gIGNvbnN0IGJ1aWxkc1RvRGVsZXRlOiBzdHJpbmdbXSA9IFtdO1xuICBjb25zdCBhbWlzVG9EZWxldGU6IHN0cmluZ1tdID0gW107XG4gIGNvbnN0IGRvY2tlckltYWdlc1RvRGVsZXRlOiBzdHJpbmdbXSA9IFtdO1xuXG4gIGxldCByZXN1bHQ6IExpc3RJbWFnZUJ1aWxkVmVyc2lvbnNSZXNwb25zZSA9IHt9O1xuICBkbyB7XG4gICAgcmVzdWx0ID0gYXdhaXQgaWIuc2VuZChuZXcgTGlzdEltYWdlQnVpbGRWZXJzaW9uc0NvbW1hbmQoe1xuICAgICAgaW1hZ2VWZXJzaW9uQXJuOiBwcm9wcy5JbWFnZVZlcnNpb25Bcm4sXG4gICAgICBuZXh0VG9rZW46IHJlc3VsdC5uZXh0VG9rZW4sXG4gICAgfSkpO1xuICAgIGlmIChyZXN1bHQuaW1hZ2VTdW1tYXJ5TGlzdCkge1xuICAgICAgZm9yIChjb25zdCBpbWFnZSBvZiByZXN1bHQuaW1hZ2VTdW1tYXJ5TGlzdCkge1xuICAgICAgICBpZiAoaW1hZ2UuYXJuKSB7XG4gICAgICAgICAgYnVpbGRzVG9EZWxldGUucHVzaChpbWFnZS5hcm4pO1xuICAgICAgICB9XG4gICAgICAgIGZvciAoY29uc3Qgb3V0cHV0IG9mIGltYWdlLm91dHB1dFJlc291cmNlcz8uYW1pcyA/PyBbXSkge1xuICAgICAgICAgIGlmIChvdXRwdXQuaW1hZ2UpIHtcbiAgICAgICAgICAgIGFtaXNUb0RlbGV0ZS5wdXNoKG91dHB1dC5pbWFnZSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGZvciAoY29uc3Qgb3V0cHV0IG9mIGltYWdlLm91dHB1dFJlc291cmNlcz8uY29udGFpbmVycyA/PyBbXSkge1xuICAgICAgICAgIGlmIChvdXRwdXQuaW1hZ2VVcmlzKSB7XG4gICAgICAgICAgICBkb2NrZXJJbWFnZXNUb0RlbGV0ZS5wdXNoKC4uLm91dHB1dC5pbWFnZVVyaXMpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfSB3aGlsZSAocmVzdWx0Lm5leHRUb2tlbik7XG5cbiAgLy8gZGVsZXRlIGFtaXNcbiAgZm9yIChjb25zdCBpbWFnZUlkIG9mIGFtaXNUb0RlbGV0ZSkge1xuICAgIHRyeSB7XG4gICAgICBjb25zb2xlLmxvZyh7XG4gICAgICAgIG5vdGljZTogJ0RlbGV0aW5nIEFNSScsXG4gICAgICAgIGltYWdlOiBpbWFnZUlkLFxuICAgICAgfSk7XG5cbiAgICAgIGNvbnN0IGltYWdlRGVzYyA9IGF3YWl0IGVjMi5zZW5kKG5ldyBEZXNjcmliZUltYWdlc0NvbW1hbmQoe1xuICAgICAgICBPd25lcnM6IFsnc2VsZiddLFxuICAgICAgICBJbWFnZUlkczogW2ltYWdlSWRdLFxuICAgICAgfSkpO1xuXG4gICAgICBpZiAoaW1hZ2VEZXNjLkltYWdlcz8ubGVuZ3RoICE9PSAxKSB7XG4gICAgICAgIGNvbnNvbGUud2Fybih7XG4gICAgICAgICAgbm90aWNlOiAnVW5hYmxlIHRvIGZpbmQgQU1JJyxcbiAgICAgICAgICBpbWFnZTogaW1hZ2VJZCxcbiAgICAgICAgfSk7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuXG4gICAgICBhd2FpdCBlYzIuc2VuZChuZXcgRGVyZWdpc3RlckltYWdlQ29tbWFuZCh7XG4gICAgICAgIEltYWdlSWQ6IGltYWdlSWQsXG4gICAgICB9KSk7XG5cbiAgICAgIGZvciAoY29uc3QgYmxvY2tNYXBwaW5nIG9mIGltYWdlRGVzYy5JbWFnZXNbMF0uQmxvY2tEZXZpY2VNYXBwaW5ncyA/PyBbXSkge1xuICAgICAgICBpZiAoYmxvY2tNYXBwaW5nLkVicz8uU25hcHNob3RJZCkge1xuICAgICAgICAgIGNvbnNvbGUubG9nKHtcbiAgICAgICAgICAgIG5vdGljZTogJ0RlbGV0aW5nIEVCUyBzbmFwc2hvdCcsXG4gICAgICAgICAgICBpbWFnZTogaW1hZ2VJZCxcbiAgICAgICAgICAgIHNuYXBzaG90OiBibG9ja01hcHBpbmcuRWJzLlNuYXBzaG90SWQsXG4gICAgICAgICAgfSk7XG5cbiAgICAgICAgICBhd2FpdCBlYzIuc2VuZChuZXcgRGVsZXRlU25hcHNob3RDb21tYW5kKHtcbiAgICAgICAgICAgIFNuYXBzaG90SWQ6IGJsb2NrTWFwcGluZy5FYnMuU25hcHNob3RJZCxcbiAgICAgICAgICB9KSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICBjb25zb2xlLndhcm4oe1xuICAgICAgICBub3RpY2U6ICdGYWlsZWQgdG8gZGVsZXRlIEFNSScsXG4gICAgICAgIGltYWdlOiBpbWFnZUlkLFxuICAgICAgICBlcnJvcjogZSxcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIC8vIGRlbGV0ZSBkb2NrZXIgaW1hZ2VzXG4gIGZvciAoY29uc3QgaW1hZ2Ugb2YgZG9ja2VySW1hZ2VzVG9EZWxldGUpIHtcbiAgICB0cnkge1xuICAgICAgY29uc29sZS5sb2coe1xuICAgICAgICBub3RpY2U6ICdEZWxldGluZyBEb2NrZXIgSW1hZ2UnLFxuICAgICAgICBpbWFnZSxcbiAgICAgIH0pO1xuXG4gICAgICAvLyBpbWFnZSBsb29rcyBsaWtlIDAxMjM0NTY3ODkuZGtyLmVjci51cy1lYXN0LTEuYW1hem9uYXdzLmNvbS9naXRodWItcnVubmVycy10ZXN0LXdpbmRvd3NpbWFnZWJ1aWxkZXJyZXBvc2l0b3J5YTRjYmI2ZDgtaGVoZGw5OXI3czNkOjEuMC4xMC0xXG4gICAgICBjb25zdCBwYXJ0cyA9IGltYWdlLnNwbGl0KCcvJylbMV0uc3BsaXQoJzonKTtcbiAgICAgIGNvbnN0IHJlcG8gPSBwYXJ0c1swXTtcbiAgICAgIGNvbnN0IHRhZyA9IHBhcnRzWzFdO1xuXG4gICAgICAvLyBkZWxldGUgaW1hZ2VcbiAgICAgIGF3YWl0IGVjci5zZW5kKG5ldyBCYXRjaERlbGV0ZUltYWdlQ29tbWFuZCh7XG4gICAgICAgIHJlcG9zaXRvcnlOYW1lOiByZXBvLFxuICAgICAgICBpbWFnZUlkczogW1xuICAgICAgICAgIHtcbiAgICAgICAgICAgIGltYWdlVGFnOiB0YWcsXG4gICAgICAgICAgfSxcbiAgICAgICAgXSxcbiAgICAgIH0pKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICBjb25zb2xlLndhcm4oe1xuICAgICAgICBub3RpY2U6ICdGYWlsZWQgdG8gZGVsZXRlIGRvY2tlciBpbWFnZScsXG4gICAgICAgIGltYWdlLFxuICAgICAgICBlcnJvcjogZSxcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIC8vIGRlbGV0ZSBidWlsZHMgKGxhc3Qgc28gcmV0cmllcyB3b3VsZCBzdGlsbCB3b3JrKVxuICBmb3IgKGNvbnN0IGJ1aWxkIG9mIGJ1aWxkc1RvRGVsZXRlKSB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnNvbGUubG9nKHtcbiAgICAgICAgbm90aWNlOiAnRGVsZXRpbmcgSW1hZ2UgQnVpbGQnLFxuICAgICAgICBidWlsZCxcbiAgICAgIH0pO1xuXG4gICAgICBhd2FpdCBpYi5zZW5kKG5ldyBEZWxldGVJbWFnZUNvbW1hbmQoe1xuICAgICAgICBpbWFnZUJ1aWxkVmVyc2lvbkFybjogYnVpbGQsXG4gICAgICB9KSk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgY29uc29sZS53YXJuKHtcbiAgICAgICAgbm90aWNlOiAnRmFpbGVkIHRvIGRlbGV0ZSBpbWFnZSB2ZXJzaW9uIGJ1aWxkJyxcbiAgICAgICAgYnVpbGQsXG4gICAgICAgIGVycm9yOiBlLFxuICAgICAgfSk7XG4gICAgfVxuICB9XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBoYW5kbGVyKGV2ZW50OiBBV1NMYW1iZGEuQ2xvdWRGb3JtYXRpb25DdXN0b21SZXNvdXJjZUV2ZW50LCBfY29udGV4dDogQVdTTGFtYmRhLkNvbnRleHQpIHtcbiAgdHJ5IHtcbiAgICBjb25zb2xlLmxvZyh7XG4gICAgICAuLi5ldmVudCxcbiAgICAgIFJlc3BvbnNlVVJMOiAnLi4uJyxcbiAgICB9KTtcblxuICAgIGNvbnN0IHByb3BzID0gZXZlbnQuUmVzb3VyY2VQcm9wZXJ0aWVzIGFzIERlbGV0ZVJlc291cmNlc1Byb3BzO1xuXG4gICAgc3dpdGNoIChldmVudC5SZXF1ZXN0VHlwZSkge1xuICAgICAgY2FzZSAnQ3JlYXRlJzpcbiAgICAgIGNhc2UgJ1VwZGF0ZSc6XG4gICAgICAgIC8vIHdlIGp1c3QgcmV0dXJuIHRoZSBhcm4gYXMgdGhlIHBoeXNpY2FsIGlkXG4gICAgICAgIC8vIHRoaXMgd2F5IGEgY2hhbmdlIGluIHRoZSB2ZXJzaW9uIHdpbGwgdHJpZ2dlciBkZWxldGUgb2YgdGhlIG9sZCB2ZXJzaW9uIG9uIGNsZWFudXAgb2Ygc3RhY2tcbiAgICAgICAgLy8gaXQgd2lsbCBhbHNvIHRyaWdnZXIgZGVsZXRlIG9uIHN0YWNrIGRlbGV0aW9uXG4gICAgICAgIGF3YWl0IGN1c3RvbVJlc291cmNlUmVzcG9uZChldmVudCwgJ1NVQ0NFU1MnLCAnT0snLCBwcm9wcy5JbWFnZVZlcnNpb25Bcm4sIHt9KTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlICdEZWxldGUnOlxuICAgICAgICBpZiAoZXZlbnQuUGh5c2ljYWxSZXNvdXJjZUlkICE9ICdGQUlMJykge1xuICAgICAgICAgIGF3YWl0IGRlbGV0ZVJlc291cmNlcyhwcm9wcyk7XG4gICAgICAgIH1cbiAgICAgICAgYXdhaXQgY3VzdG9tUmVzb3VyY2VSZXNwb25kKGV2ZW50LCAnU1VDQ0VTUycsICdPSycsIGV2ZW50LlBoeXNpY2FsUmVzb3VyY2VJZCwge30pO1xuICAgICAgICBicmVhaztcbiAgICB9XG4gIH0gY2F0Y2ggKGUpIHtcbiAgICBjb25zb2xlLmVycm9yKGUpO1xuICAgIGF3YWl0IGN1c3RvbVJlc291cmNlUmVzcG9uZChldmVudCwgJ0ZBSUxFRCcsIChlIGFzIEVycm9yKS5tZXNzYWdlIHx8ICdJbnRlcm5hbCBFcnJvcicsICdGQUlMJywge30pO1xuICB9XG59XG4iXX0=