UNPKG

21.7 kBJavaScriptView Raw
1import * as fs from 'fs-extra';
2import * as path from 'path';
3import { extract } from './extract';
4import { Provider } from './Provider';
5import { upload } from './upload';
6const METADATA_NAME = 'metadata';
7const MAX_SIZE = 1000000000;
8const KEEP_BACKUP_COUNT = 10;
9const extractTime = (prefix, file) => parseInt(file.name.slice(prefix.length).split('/')[1], 10);
10export class GCloudProvider extends Provider {
11 constructor({ environment, options }) {
12 super();
13 this.environment = environment;
14 this.options = options;
15 }
16 async canRestore() {
17 const { time } = await this.getLatestTime();
18 return time !== undefined;
19 }
20 async restore(monitorIn) {
21 const monitor = monitorIn.at('gcloud_provider');
22 const { prefix } = this.options;
23 const { dataPath, tmpPath } = this.environment;
24 const { time, files } = await this.getLatestTime();
25 if (time === undefined) {
26 throw new Error('Cannot restore');
27 }
28 const filePrefix = [prefix, time].join('/');
29 const fileAndPaths = files
30 .filter((file) => file.name.startsWith(filePrefix) && path.basename(file.name) !== METADATA_NAME)
31 .map((file) => ({
32 file,
33 filePath: path.resolve(tmpPath, path.basename(file.name)),
34 }));
35 // tslint:disable-next-line no-loop-statement
36 for (const { file, filePath } of fileAndPaths) {
37 await monitor
38 .withData({ filePath })
39 .captureSpanLog(async () => file.download({ destination: filePath, validation: true }), {
40 name: 'neo_restore_download',
41 });
42 }
43 await Promise.all(fileAndPaths.map(async ({ filePath }) => monitor.withData({ filePath }).captureSpanLog(async () => extract({
44 downloadPath: filePath,
45 dataPath,
46 }), { name: 'neo_restore_extract' })));
47 }
48 async backup(monitorIn) {
49 const monitor = monitorIn.at('gcloud_provider');
50 const { bucket, prefix, keepBackupCount = KEEP_BACKUP_COUNT, maxSizeBytes = MAX_SIZE } = this.options;
51 const { dataPath } = this.environment;
52 const files = await fs.readdir(dataPath);
53 const fileAndStats = await Promise.all(files.map(async (file) => {
54 const stat = await fs.stat(path.resolve(dataPath, file));
55 return { file, stat };
56 }));
57 const mutableFileLists = [];
58 let mutableCurrentFileList = [];
59 let currentSize = 0;
60 // tslint:disable-next-line no-loop-statement
61 for (const { file, stat } of fileAndStats) {
62 if (currentSize > maxSizeBytes) {
63 mutableFileLists.push(mutableCurrentFileList);
64 mutableCurrentFileList = [];
65 currentSize = 0;
66 }
67 mutableCurrentFileList.push(file);
68 currentSize += stat.size;
69 }
70 if (mutableCurrentFileList.length > 0) {
71 mutableFileLists.push(mutableCurrentFileList);
72 }
73 const storage = await this.getStorage();
74 const time = Math.round(Date.now() / 1000);
75 // tslint:disable-next-line no-loop-statement
76 for (const [idx, fileList] of mutableFileLists.entries()) {
77 await monitor.withData({ part: idx }).captureSpanLog(async () => upload({
78 dataPath,
79 write: storage
80 .bucket(bucket)
81 .file([prefix, `${time}`, `storage_part_${idx}.db.tar.gz`].join('/'))
82 .createWriteStream({ validation: true }),
83 fileList,
84 }), { name: 'neo_backup_push' });
85 }
86 await monitor.captureSpanLog(async () => storage
87 .bucket(bucket)
88 .file([prefix, `${time}`, METADATA_NAME].join('/'))
89 .save('', undefined), { name: 'neo_backup_push' });
90 const [fileNames] = await monitor.captureSpanLog(
91 // tslint:disable-next-line no-any no-void-expression no-use-of-empty-return-value
92 async () => storage.bucket(bucket).getFiles({ prefix }), {
93 name: 'neo_backup_list_files',
94 });
95 const times = [...new Set(fileNames.map((file) => extractTime(prefix, file)))];
96 // tslint:disable-next-line no-array-mutation
97 times.sort();
98 const deleteTimes = times.slice(0, -keepBackupCount);
99 await monitor.captureSpanLog(async () => Promise.all(deleteTimes.map(async (deleteTime) => storage.bucket(bucket).deleteFiles({ prefix: [prefix, `${deleteTime}`].join('/') }))), { name: 'neo_backup_delete_old' });
100 }
101 async getLatestTime() {
102 const { bucket, prefix } = this.options;
103 const storage = await this.getStorage();
104 // tslint:disable-next-line no-any no-void-expression no-use-of-empty-return-value
105 const [files] = (await storage.bucket(bucket).getFiles({ prefix }));
106 const metadataTimes = files
107 .filter((file) => path.basename(file.name) === METADATA_NAME)
108 .map((file) => extractTime(prefix, file));
109 // tslint:disable-next-line no-array-mutation
110 metadataTimes.sort();
111 const time = metadataTimes[metadataTimes.length - 1];
112 return { time, files };
113 }
114 async getStorage() {
115 const storage = await import('@google-cloud/storage');
116 // tslint:disable-next-line no-any
117 return new storage.Storage({ projectId: this.options.projectID });
118 }
119}
120
121//# sourceMappingURL=data:application/json;charset=utf8;base64,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QUUsSUFBSSxFQUFFLEtBQUssRUFBRSxDQUFDO0lBQ3pCLENBQUM7SUFFTyxLQUFLLENBQUMsVUFBVTtRQUN0QixNQUFNLE9BQU8sR0FBRyxNQUFNLE1BQU0sQ0FBQyx1QkFBdUIsQ0FBQyxDQUFDO1FBRXRELGtDQUFrQztRQUNsQyxPQUFPLElBQUksT0FBTyxDQUFDLE9BQU8sQ0FBQyxFQUFFLFNBQVMsRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLFNBQVMsRUFBRSxDQUFDLENBQUM7SUFDcEUsQ0FBQztDQUNGIiwiZmlsZSI6Im5lby1vbmUtbm9kZS1kYXRhLWJhY2t1cC9zcmMvcHJvdmlkZXIvR0Nsb3VkUHJvdmlkZXIuanMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmU6bm8tc3VibW9kdWxlLWltcG9ydHNcbmltcG9ydCB7IEZpbGUgfSBmcm9tICdAZ29vZ2xlLWNsb3VkL3N0b3JhZ2UvYnVpbGQvc3JjL2ZpbGUnO1xuaW1wb3J0IHsgTW9uaXRvciB9IGZyb20gJ0BuZW8tb25lL21vbml0b3InO1xuaW1wb3J0ICogYXMgZnMgZnJvbSAnZnMtZXh0cmEnO1xuaW1wb3J0ICogYXMgcGF0aCBmcm9tICdwYXRoJztcbmltcG9ydCB7IEVudmlyb25tZW50IH0gZnJvbSAnLi4vdHlwZXMnO1xuaW1wb3J0IHsgZXh0cmFjdCB9IGZyb20gJy4vZXh0cmFjdCc7XG5pbXBvcnQgeyBQcm92aWRlciB9IGZyb20gJy4vUHJvdmlkZXInO1xuaW1wb3J0IHsgdXBsb2FkIH0gZnJvbSAnLi91cGxvYWQnO1xuXG5leHBvcnQgaW50ZXJmYWNlIE9wdGlvbnMge1xuICByZWFkb25seSBwcm9qZWN0SUQ6IHN0cmluZztcbiAgcmVhZG9ubHkgYnVja2V0OiBzdHJpbmc7XG4gIHJlYWRvbmx5IHByZWZpeDogc3RyaW5nO1xuICByZWFkb25seSBrZWVwQmFja3VwQ291bnQ/OiBudW1iZXI7XG4gIHJlYWRvbmx5IG1heFNpemVCeXRlcz86IG51bWJlcjtcbn1cblxuY29uc3QgTUVUQURBVEFfTkFNRSA9ICdtZXRhZGF0YSc7XG5jb25zdCBNQVhfU0laRSA9IDFfMDAwXzAwMF8wMDA7XG5jb25zdCBLRUVQX0JBQ0tVUF9DT1VOVCA9IDEwO1xuXG5jb25zdCBleHRyYWN0VGltZSA9IChwcmVmaXg6IHN0cmluZywgZmlsZTogRmlsZSkgPT4gcGFyc2VJbnQoZmlsZS5uYW1lLnNsaWNlKHByZWZpeC5sZW5ndGgpLnNwbGl0KCcvJylbMV0sIDEwKTtcblxuZXhwb3J0IGNsYXNzIEdDbG91ZFByb3ZpZGVyIGV4dGVuZHMgUHJvdmlkZXIge1xuICBwcml2YXRlIHJlYWRvbmx5IGVudmlyb25tZW50OiBFbnZpcm9ubWVudDtcbiAgcHJpdmF0ZSByZWFkb25seSBvcHRpb25zOiBPcHRpb25zO1xuXG4gIHB1YmxpYyBjb25zdHJ1Y3Rvcih7IGVudmlyb25tZW50LCBvcHRpb25zIH06IHsgcmVhZG9ubHkgZW52aXJvbm1lbnQ6IEVudmlyb25tZW50OyByZWFkb25seSBvcHRpb25zOiBPcHRpb25zIH0pIHtcbiAgICBzdXBlcigpO1xuICAgIHRoaXMuZW52aXJvbm1lbnQgPSBlbnZpcm9ubWVudDtcbiAgICB0aGlzLm9wdGlvbnMgPSBvcHRpb25zO1xuICB9XG5cbiAgcHVibGljIGFzeW5jIGNhblJlc3RvcmUoKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgY29uc3QgeyB0aW1lIH0gPSBhd2FpdCB0aGlzLmdldExhdGVzdFRpbWUoKTtcblxuICAgIHJldHVybiB0aW1lICE9PSB1bmRlZmluZWQ7XG4gIH1cblxuICBwdWJsaWMgYXN5bmMgcmVzdG9yZShtb25pdG9ySW46IE1vbml0b3IpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCBtb25pdG9yID0gbW9uaXRvckluLmF0KCdnY2xvdWRfcHJvdmlkZXInKTtcbiAgICBjb25zdCB7IHByZWZpeCB9ID0gdGhpcy5vcHRpb25zO1xuICAgIGNvbnN0IHsgZGF0YVBhdGgsIHRtcFBhdGggfSA9IHRoaXMuZW52aXJvbm1lbnQ7XG5cbiAgICBjb25zdCB7IHRpbWUsIGZpbGVzIH0gPSBhd2FpdCB0aGlzLmdldExhdGVzdFRpbWUoKTtcbiAgICBpZiAodGltZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0Nhbm5vdCByZXN0b3JlJyk7XG4gICAgfVxuXG4gICAgY29uc3QgZmlsZVByZWZpeCA9IFtwcmVmaXgsIHRpbWVdLmpvaW4oJy8nKTtcbiAgICBjb25zdCBmaWxlQW5kUGF0aHMgPSBmaWxlc1xuICAgICAgLmZpbHRlcigoZmlsZSkgPT4gZmlsZS5uYW1lLnN0YXJ0c1dpdGgoZmlsZVByZWZpeCkgJiYgcGF0aC5iYXNlbmFtZShmaWxlLm5hbWUpICE9PSBNRVRBREFUQV9OQU1FKVxuICAgICAgLm1hcCgoZmlsZSkgPT4gKHtcbiAgICAgICAgZmlsZSxcbiAgICAgICAgZmlsZVBhdGg6IHBhdGgucmVzb2x2ZSh0bXBQYXRoLCBwYXRoLmJhc2VuYW1lKGZpbGUubmFtZSkpLFxuICAgICAgfSkpO1xuXG4gICAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lIG5vLWxvb3Atc3RhdGVtZW50XG4gICAgZm9yIChjb25zdCB7IGZpbGUsIGZpbGVQYXRoIH0gb2YgZmlsZUFuZFBhdGhzKSB7XG4gICAgICBhd2FpdCBtb25pdG9yXG4gICAgICAgIC53aXRoRGF0YSh7IGZpbGVQYXRoIH0pXG4gICAgICAgIC5jYXB0dXJlU3BhbkxvZyhhc3luYyAoKSA9PiBmaWxlLmRvd25sb2FkKHsgZGVzdGluYXRpb246IGZpbGVQYXRoLCB2YWxpZGF0aW9uOiB0cnVlIH0pLCB7XG4gICAgICAgICAgbmFtZTogJ25lb19yZXN0b3JlX2Rvd25sb2FkJyxcbiAgICAgICAgfSk7XG4gICAgfVxuICAgIGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgZmlsZUFuZFBhdGhzLm1hcChhc3luYyAoeyBmaWxlUGF0aCB9KSA9PlxuICAgICAgICBtb25pdG9yLndpdGhEYXRhKHsgZmlsZVBhdGggfSkuY2FwdHVyZVNwYW5Mb2coXG4gICAgICAgICAgYXN5bmMgKCkgPT5cbiAgICAgICAgICAgIGV4dHJhY3Qoe1xuICAgICAgICAgICAgICBkb3dubG9hZFBhdGg6IGZpbGVQYXRoLFxuICAgICAgICAgICAgICBkYXRhUGF0aCxcbiAgICAgICAgICAgIH0pLFxuICAgICAgICAgIHsgbmFtZTogJ25lb19yZXN0b3JlX2V4dHJhY3QnIH0sXG4gICAgICAgICksXG4gICAgICApLFxuICAgICk7XG4gIH1cblxuICBwdWJsaWMgYXN5bmMgYmFja3VwKG1vbml0b3JJbjogTW9uaXRvcik6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IG1vbml0b3IgPSBtb25pdG9ySW4uYXQoJ2djbG91ZF9wcm92aWRlcicpO1xuICAgIGNvbnN0IHsgYnVja2V0LCBwcmVmaXgsIGtlZXBCYWNrdXBDb3VudCA9IEtFRVBfQkFDS1VQX0NPVU5ULCBtYXhTaXplQnl0ZXMgPSBNQVhfU0laRSB9ID0gdGhpcy5vcHRpb25zO1xuICAgIGNvbnN0IHsgZGF0YVBhdGggfSA9IHRoaXMuZW52aXJvbm1lbnQ7XG5cbiAgICBjb25zdCBmaWxlcyA9IGF3YWl0IGZzLnJlYWRkaXIoZGF0YVBhdGgpO1xuICAgIGNvbnN0IGZpbGVBbmRTdGF0cyA9IGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgZmlsZXMubWFwKGFzeW5jIChmaWxlKSA9PiB7XG4gICAgICAgIGNvbnN0IHN0YXQgPSBhd2FpdCBmcy5zdGF0KHBhdGgucmVzb2x2ZShkYXRhUGF0aCwgZmlsZSkpO1xuXG4gICAgICAgIHJldHVybiB7IGZpbGUsIHN0YXQgfTtcbiAgICAgIH0pLFxuICAgICk7XG5cbiAgICBjb25zdCBtdXRhYmxlRmlsZUxpc3RzID0gW107XG4gICAgbGV0IG11dGFibGVDdXJyZW50RmlsZUxpc3QgPSBbXTtcbiAgICBsZXQgY3VycmVudFNpemUgPSAwO1xuICAgIC8vIHRzbGludDpkaXNhYmxlLW5leHQtbGluZSBuby1sb29wLXN0YXRlbWVudFxuICAgIGZvciAoY29uc3QgeyBmaWxlLCBzdGF0IH0gb2YgZmlsZUFuZFN0YXRzKSB7XG4gICAgICBpZiAoY3VycmVudFNpemUgPiBtYXhTaXplQnl0ZXMpIHtcbiAgICAgICAgbXV0YWJsZUZpbGVMaXN0cy5wdXNoKG11dGFibGVDdXJyZW50RmlsZUxpc3QpO1xuICAgICAgICBtdXRhYmxlQ3VycmVudEZpbGVMaXN0ID0gW107XG4gICAgICAgIGN1cnJlbnRTaXplID0gMDtcbiAgICAgIH1cblxuICAgICAgbXV0YWJsZUN1cnJlbnRGaWxlTGlzdC5wdXNoKGZpbGUpO1xuICAgICAgY3VycmVudFNpemUgKz0gc3RhdC5zaXplO1xuICAgIH1cblxuICAgIGlmIChtdXRhYmxlQ3VycmVudEZpbGVMaXN0Lmxlbmd0aCA+IDApIHtcbiAgICAgIG11dGFibGVGaWxlTGlzdHMucHVzaChtdXRhYmxlQ3VycmVudEZpbGVMaXN0KTtcbiAgICB9XG5cbiAgICBjb25zdCBzdG9yYWdlID0gYXdhaXQgdGhpcy5nZXRTdG9yYWdlKCk7XG4gICAgY29uc3QgdGltZSA9IE1hdGgucm91bmQoRGF0ZS5ub3coKSAvIDEwMDApO1xuICAgIC8vIHRzbGludDpkaXNhYmxlLW5leHQtbGluZSBuby1sb29wLXN0YXRlbWVudFxuICAgIGZvciAoY29uc3QgW2lkeCwgZmlsZUxpc3RdIG9mIG11dGFibGVGaWxlTGlzdHMuZW50cmllcygpKSB7XG4gICAgICBhd2FpdCBtb25pdG9yLndpdGhEYXRhKHsgcGFydDogaWR4IH0pLmNhcHR1cmVTcGFuTG9nKFxuICAgICAgICBhc3luYyAoKSA9PlxuICAgICAgICAgIHVwbG9hZCh7XG4gICAgICAgICAgICBkYXRhUGF0aCxcbiAgICAgICAgICAgIHdyaXRlOiBzdG9yYWdlXG4gICAgICAgICAgICAgIC5idWNrZXQoYnVja2V0KVxuICAgICAgICAgICAgICAuZmlsZShbcHJlZml4LCBgJHt0aW1lfWAsIGBzdG9yYWdlX3BhcnRfJHtpZHh9LmRiLnRhci5nemBdLmpvaW4oJy8nKSlcbiAgICAgICAgICAgICAgLmNyZWF0ZVdyaXRlU3RyZWFtKHsgdmFsaWRhdGlvbjogdHJ1ZSB9KSxcbiAgICAgICAgICAgIGZpbGVMaXN0LFxuICAgICAgICAgIH0pLFxuICAgICAgICB7IG5hbWU6ICduZW9fYmFja3VwX3B1c2gnIH0sXG4gICAgICApO1xuICAgIH1cblxuICAgIGF3YWl0IG1vbml0b3IuY2FwdHVyZVNwYW5Mb2c8UHJvbWlzZTx2b2lkPj4oXG4gICAgICBhc3luYyAoKSA9PlxuICAgICAgICBzdG9yYWdlXG4gICAgICAgICAgLmJ1Y2tldChidWNrZXQpXG4gICAgICAgICAgLmZpbGUoW3ByZWZpeCwgYCR7dGltZX1gLCBNRVRBREFUQV9OQU1FXS5qb2luKCcvJykpXG4gICAgICAgICAgLnNhdmUoJycsIHVuZGVmaW5lZCksXG4gICAgICB7IG5hbWU6ICduZW9fYmFja3VwX3B1c2gnIH0sXG4gICAgKTtcblxuICAgIGNvbnN0IFtmaWxlTmFtZXNdID0gYXdhaXQgbW9uaXRvci5jYXB0dXJlU3BhbkxvZyhcbiAgICAgIC8vIHRzbGludDpkaXNhYmxlLW5leHQtbGluZSBuby1hbnkgbm8tdm9pZC1leHByZXNzaW9uIG5vLXVzZS1vZi1lbXB0eS1yZXR1cm4tdmFsdWVcbiAgICAgIGFzeW5jICgpID0+IChzdG9yYWdlLmJ1Y2tldChidWNrZXQpLmdldEZpbGVzKHsgcHJlZml4IH0pIGFzIGFueSkgYXMgUHJvbWlzZTxbRmlsZVtdXT4sXG4gICAgICB7XG4gICAgICAgIG5hbWU6ICduZW9fYmFja3VwX2xpc3RfZmlsZXMnLFxuICAgICAgfSxcbiAgICApO1xuICAgIGNvbnN0IHRpbWVzID0gWy4uLm5ldyBTZXQoZmlsZU5hbWVzLm1hcCgoZmlsZSkgPT4gZXh0cmFjdFRpbWUocHJlZml4LCBmaWxlKSkpXTtcbiAgICAvLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmUgbm8tYXJyYXktbXV0YXRpb25cbiAgICB0aW1lcy5zb3J0KCk7XG5cbiAgICBjb25zdCBkZWxldGVUaW1lcyA9IHRpbWVzLnNsaWNlKDAsIC1rZWVwQmFja3VwQ291bnQpO1xuICAgIGF3YWl0IG1vbml0b3IuY2FwdHVyZVNwYW5Mb2c8UHJvbWlzZTx2b2lkW10+PihcbiAgICAgIGFzeW5jICgpID0+XG4gICAgICAgIFByb21pc2UuYWxsKFxuICAgICAgICAgIGRlbGV0ZVRpbWVzLm1hcChhc3luYyAoZGVsZXRlVGltZSkgPT5cbiAgICAgICAgICAgIHN0b3JhZ2UuYnVja2V0KGJ1Y2tldCkuZGVsZXRlRmlsZXMoeyBwcmVmaXg6IFtwcmVmaXgsIGAke2RlbGV0ZVRpbWV9YF0uam9pbignLycpIH0pLFxuICAgICAgICAgICksXG4gICAgICAgICksXG4gICAgICB7IG5hbWU6ICduZW9fYmFja3VwX2RlbGV0ZV9vbGQnIH0sXG4gICAgKTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgZ2V0TGF0ZXN0VGltZSgpOiBQcm9taXNlPHtcbiAgICByZWFkb25seSB0aW1lOiBudW1iZXIgfCB1bmRlZmluZWQ7XG4gICAgcmVhZG9ubHkgZmlsZXM6IFJlYWRvbmx5QXJyYXk8RmlsZT47XG4gIH0+IHtcbiAgICBjb25zdCB7IGJ1Y2tldCwgcHJlZml4IH0gPSB0aGlzLm9wdGlvbnM7XG5cbiAgICBjb25zdCBzdG9yYWdlID0gYXdhaXQgdGhpcy5nZXRTdG9yYWdlKCk7XG4gICAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lIG5vLWFueSBuby12b2lkLWV4cHJlc3Npb24gbm8tdXNlLW9mLWVtcHR5LXJldHVybi12YWx1ZVxuICAgIGNvbnN0IFtmaWxlc10gPSAoYXdhaXQgKHN0b3JhZ2UuYnVja2V0KGJ1Y2tldCkuZ2V0RmlsZXMoeyBwcmVmaXggfSkgYXMgYW55KSkgYXMgW0ZpbGVbXV07XG5cbiAgICBjb25zdCBtZXRhZGF0YVRpbWVzID0gZmlsZXNcbiAgICAgIC5maWx0ZXIoKGZpbGUpID0+IHBhdGguYmFzZW5hbWUoZmlsZS5uYW1lKSA9PT0gTUVUQURBVEFfTkFNRSlcbiAgICAgIC5tYXAoKGZpbGUpID0+IGV4dHJhY3RUaW1lKHByZWZpeCwgZmlsZSkpO1xuICAgIC8vIHRzbGludDpkaXNhYmxlLW5leHQtbGluZSBuby1hcnJheS1tdXRhdGlvblxuICAgIG1ldGFkYXRhVGltZXMuc29ydCgpO1xuXG4gICAgY29uc3QgdGltZSA9IG1ldGFkYXRhVGltZXNbbWV0YWRhdGFUaW1lcy5sZW5ndGggLSAxXSBhcyBudW1iZXIgfCB1bmRlZmluZWQ7XG5cbiAgICByZXR1cm4geyB0aW1lLCBmaWxlcyB9O1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBnZXRTdG9yYWdlKCkge1xuICAgIGNvbnN0IHN0b3JhZ2UgPSBhd2FpdCBpbXBvcnQoJ0Bnb29nbGUtY2xvdWQvc3RvcmFnZScpO1xuXG4gICAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lIG5vLWFueVxuICAgIHJldHVybiBuZXcgc3RvcmFnZS5TdG9yYWdlKHsgcHJvamVjdElkOiB0aGlzLm9wdGlvbnMucHJvamVjdElEIH0pO1xuICB9XG59XG4iXX0=