1 | import * as fs from 'fs-extra';
|
2 | import * as path from 'path';
|
3 | import { extract } from './extract';
|
4 | import { Provider } from './Provider';
|
5 | import { upload } from './upload';
|
6 | const METADATA_NAME = 'metadata';
|
7 | const MAX_SIZE = 1000000000;
|
8 | const KEEP_BACKUP_COUNT = 10;
|
9 | const extractTime = (prefix, file) => parseInt(file.name.slice(prefix.length).split('/')[1], 10);
|
10 | export 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=
|