sliftutils 1.7.88 → 1.7.90
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +3 -1
- package/dist/treeSummary.ts.cache +2 -2
- package/index.d.ts +679 -300
- package/misc/dist/environment.ts.cache +2 -2
- package/misc/dist/getSecret.ts.cache +2 -2
- package/misc/dist/strings.ts.cache +2 -2
- package/misc/dist/zip.ts.cache +2 -2
- package/misc/https/dist/certs.ts.cache +2 -2
- package/misc/https/dist/cloudflareHelpers.ts.cache +2 -2
- package/misc/https/dist/dns.ts.cache +2 -2
- package/misc/https/dist/hostServer.ts.cache +49 -21
- package/misc/https/dist/hostsFile.ts.cache +82 -0
- package/misc/https/dist/httpsCerts.ts.cache +2 -2
- package/misc/https/dist/persistentLocalStorage.ts.cache +2 -2
- package/misc/https/hostServer.d.ts +6 -2
- package/misc/https/hostServer.ts +52 -19
- package/misc/https/hostsFile.d.ts +7 -0
- package/misc/https/hostsFile.ts +66 -0
- package/package.json +1 -1
- package/render-utils/dist/observer.tsx.cache +2 -2
- package/storage/ArchivesDisk.d.ts +3 -6
- package/storage/ArchivesDisk.ts +26 -2
- package/storage/BulkDatabase2/BulkDatabaseReader.ts +1 -1
- package/storage/BulkDatabase2/dist/BulkDatabaseBase.ts.cache +2 -2
- package/storage/BulkDatabase2/dist/BulkDatabaseFormat.ts.cache +2 -2
- package/storage/BulkDatabase2/dist/BulkDatabaseMerge.ts.cache +2 -2
- package/storage/BulkDatabase2/dist/BulkDatabaseReader.ts.cache +3 -3
- package/storage/BulkDatabase2/dist/LoadedIndex.ts.cache +2 -2
- package/storage/BulkDatabase2/dist/WriteOverlay.ts.cache +2 -2
- package/storage/BulkDatabase2/dist/blockCache.ts.cache +2 -2
- package/storage/BulkDatabase2/dist/mergeLock.ts.cache +2 -2
- package/storage/BulkDatabase2/dist/mergeMarkers.ts.cache +2 -2
- package/storage/BulkDatabase2/dist/streamLog.ts.cache +2 -2
- package/storage/BulkDatabase2/dist/syncClient.ts.cache +2 -2
- package/storage/IArchives.d.ts +37 -24
- package/storage/IArchives.ts +47 -62
- package/storage/LogMap.d.ts +56 -0
- package/storage/LogMap.ts +220 -0
- package/storage/archiveHelpers.d.ts +36 -0
- package/storage/archiveHelpers.ts +103 -0
- package/storage/backblaze.d.ts +7 -12
- package/storage/backblaze.ts +53 -48
- package/storage/dist/ArchivesDisk.ts.cache +29 -3
- package/storage/dist/FileFolderAPI.tsx.cache +2 -2
- package/storage/dist/IArchives.ts.cache +17 -53
- package/storage/dist/IndexedDBFileFolderAPI.ts.cache +2 -2
- package/storage/dist/JSONStorage.ts.cache +2 -2
- package/storage/dist/LogMap.ts.cache +212 -0
- package/storage/dist/PendingManager.tsx.cache +2 -2
- package/storage/dist/TransactionStorage.ts.cache +2 -2
- package/storage/dist/archiveHelpers.ts.cache +87 -0
- package/storage/dist/backblaze.ts.cache +59 -45
- package/storage/dist/fileSystemPointer.ts.cache +2 -2
- package/storage/dist/remoteFileStorage.ts.cache +2 -2
- package/storage/remoteStorage/ArchivesDelayed.d.ts +66 -0
- package/storage/remoteStorage/ArchivesDelayed.ts +237 -0
- package/storage/remoteStorage/ArchivesRemote.d.ts +5 -6
- package/storage/remoteStorage/ArchivesRemote.ts +26 -5
- package/storage/remoteStorage/ArchivesUrl.d.ts +2 -5
- package/storage/remoteStorage/ArchivesUrl.ts +2 -2
- package/storage/remoteStorage/accessPage.tsx +12 -0
- package/storage/remoteStorage/blobStore.d.ts +162 -189
- package/storage/remoteStorage/blobStore.ts +495 -952
- package/storage/remoteStorage/bucketDisk.d.ts +24 -3
- package/storage/remoteStorage/bucketDisk.ts +56 -22
- package/storage/remoteStorage/certTrustModal.d.ts +1 -0
- package/storage/remoteStorage/certTrustModal.tsx +48 -0
- package/storage/remoteStorage/cliArgs.d.ts +2 -0
- package/storage/remoteStorage/cliArgs.ts +5 -0
- package/storage/remoteStorage/createArchives.d.ts +8 -7
- package/storage/remoteStorage/createArchives.ts +65 -26
- package/storage/remoteStorage/deployTakeover.ts +1 -1
- package/storage/remoteStorage/dist/ArchivesDelayed.ts.cache +220 -0
- package/storage/remoteStorage/dist/ArchivesRemote.ts.cache +26 -6
- package/storage/remoteStorage/dist/ArchivesUrl.ts.cache +3 -3
- package/storage/remoteStorage/dist/accessPage.tsx.cache +13 -3
- package/storage/remoteStorage/dist/accessStats.ts.cache +2 -2
- package/storage/remoteStorage/dist/blobStore.ts.cache +484 -966
- package/storage/remoteStorage/dist/bucketDisk.ts.cache +60 -29
- package/storage/remoteStorage/dist/certTrustModal.tsx.cache +55 -0
- package/storage/remoteStorage/dist/cliArgs.ts.cache +9 -4
- package/storage/remoteStorage/dist/createArchives.ts.cache +64 -27
- package/storage/remoteStorage/dist/deployTakeover.ts.cache +5 -5
- package/storage/remoteStorage/dist/intermediateManagement.ts.cache +286 -0
- package/storage/remoteStorage/dist/intermediateSources.ts.cache +2 -2
- package/storage/remoteStorage/dist/remoteConfig.ts.cache +122 -56
- package/storage/remoteStorage/dist/serverConfig.ts.cache +4 -4
- package/storage/remoteStorage/dist/sourceWrapper.ts.cache +7 -11
- package/storage/remoteStorage/dist/sourcesList.ts.cache +3 -6
- package/storage/remoteStorage/dist/storageClientController.ts.cache +2 -2
- package/storage/remoteStorage/dist/storageController.ts.cache +33 -36
- package/storage/remoteStorage/dist/storageServer.ts.cache +27 -7
- package/storage/remoteStorage/dist/storageServerCli.ts.cache +7 -3
- package/storage/remoteStorage/dist/storageServerState.ts.cache +138 -707
- package/storage/remoteStorage/dist/storeConfig.ts.cache +52 -0
- package/storage/remoteStorage/dist/storePlan.ts.cache +110 -81
- package/storage/remoteStorage/dist/storeSources.ts.cache +51 -0
- package/storage/remoteStorage/dist/storeSync.ts.cache +651 -0
- package/storage/remoteStorage/dist/validation.ts.cache +14 -4
- package/storage/remoteStorage/intermediateManagement.d.ts +12 -0
- package/storage/remoteStorage/intermediateManagement.ts +264 -0
- package/storage/remoteStorage/remoteConfig.d.ts +32 -0
- package/storage/remoteStorage/remoteConfig.ts +115 -50
- package/storage/remoteStorage/serverConfig.d.ts +1 -1
- package/storage/remoteStorage/serverConfig.ts +1 -1
- package/storage/remoteStorage/sourceWrapper.ts +4 -8
- package/storage/remoteStorage/sourcesList.d.ts +0 -2
- package/storage/remoteStorage/sourcesList.ts +0 -3
- package/storage/remoteStorage/spec.md +18 -4
- package/storage/remoteStorage/storageController.d.ts +10 -0
- package/storage/remoteStorage/storageController.ts +37 -41
- package/storage/remoteStorage/storageServer.d.ts +2 -0
- package/storage/remoteStorage/storageServer.ts +28 -4
- package/storage/remoteStorage/storageServerCli.ts +5 -1
- package/storage/remoteStorage/storageServerState.d.ts +39 -26
- package/storage/remoteStorage/storageServerState.ts +149 -669
- package/storage/remoteStorage/storeConfig.d.ts +30 -0
- package/storage/remoteStorage/storeConfig.ts +62 -0
- package/storage/remoteStorage/storePlan.d.ts +29 -17
- package/storage/remoteStorage/storePlan.ts +112 -85
- package/storage/remoteStorage/storeSources.d.ts +11 -0
- package/storage/remoteStorage/storeSources.ts +47 -0
- package/storage/remoteStorage/storeSync.d.ts +53 -0
- package/storage/remoteStorage/storeSync.ts +632 -0
- package/storage/remoteStorage/validation.d.ts +2 -0
- package/storage/remoteStorage/validation.ts +10 -0
|
@@ -1,114 +1,28 @@
|
|
|
1
|
-
"use strict";
|
|
1
|
+
"use strict";
|
|
2
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
3
|
return (mod && mod.__esModule && mod.default) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true , configurable: true});
|
|
6
|
-
//exports.BlobStore = exports.
|
|
6
|
+
//exports.BlobStore = exports.WINDOW_END_FLUSH_MARGIN = void 0;
|
|
7
7
|
const path_1 = __importDefault(require("path"));
|
|
8
8
|
const caching_1 = require("socket-function/src/caching");
|
|
9
|
-
const batching_1 = require("socket-function/src/batching");
|
|
10
9
|
const misc_1 = require("socket-function/src/misc");
|
|
11
|
-
const format_1 = require("socket-function/src/formatting/format");
|
|
12
10
|
const IArchives_1 = require("../IArchives");
|
|
13
11
|
const ArchivesDisk_1 = require("../ArchivesDisk");
|
|
14
|
-
const backblaze_1 = require("../backblaze");
|
|
15
12
|
const remoteConfig_1 = require("./remoteConfig");
|
|
16
13
|
const storePlan_1 = require("./storePlan");
|
|
17
|
-
const
|
|
18
|
-
const
|
|
14
|
+
const ArchivesDelayed_1 = require("./ArchivesDelayed");
|
|
15
|
+
const LogMap_1 = require("../LogMap");
|
|
19
16
|
const sourcesList_1 = require("./sourcesList");
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
// The overlay is polled this often for due flushes - fine enough that the fast (remote) flush lands close to MAX_REMOTE_FAST_BUFFER, not one coarse tick later
|
|
25
|
-
const FAST_FLUSH_POLL = 1000 * 2;
|
|
17
|
+
const storeSync_1 = require("./storeSync");
|
|
18
|
+
const storeConfig_1 = require("./storeConfig");
|
|
19
|
+
const ArchivesDelayed_2 = require("./ArchivesDelayed");
|
|
20
|
+
// The storage engine of the remote storage server. Data lives in synchronization sources (at minimum an ArchivesDisk, the local disk); BlobStore keeps an index of every file (path, last modified time, size, and which source currently holds the data) in a BulkDatabase2, and answers every read from it (see ArchivesSource in IArchives.ts). Keeping that index in agreement with the sources is StoreSync's job, not this file's; what lives here is the index itself, reads, writes, and the validation a write has to pass.
|
|
26
21
|
// Fast writes are never delayed past our own valid window, and within this margin of the window's end they write through immediately - so when the next window's source takes over, the writes are already on disk
|
|
27
22
|
exports.WINDOW_END_FLUSH_MARGIN = misc_1.timeInMinute * 5;
|
|
28
|
-
// Index changes are buffered in memory and written to the BulkDatabase2 in batches
|
|
29
|
-
const INDEX_FLUSH_INTERVAL = 1000 * 30;
|
|
30
|
-
// Sources with a native (index-backed) change feed are polled this often
|
|
31
|
-
const CHANGES_POLL_INTERVAL = 1000 * 60;
|
|
32
|
-
// Full metadata rescans. supportsChangesAfter is the heuristic for "one of our own storage servers": their index-backed listings are cheap, so hourly is fine. Everything else (backblaze, plain disk) pays the full listing cost, so it rescans much less often.
|
|
33
|
-
const FULL_RESCAN_INTERVAL = 1000 * 60 * 60;
|
|
34
|
-
const FULL_RESCAN_UNINDEXED_INTERVAL = 1000 * 60 * 60 * 6;
|
|
35
|
-
// On a request for a file the index doesn't know, changes-after sources are re-polled, at most this often
|
|
36
|
-
const MISS_CHECK_INTERVAL = 1000 * 5;
|
|
37
|
-
// Change polls re-request this much overlap, so clock skew between us and a source can't drop changes
|
|
38
|
-
const CHANGES_POLL_OVERLAP = misc_1.timeInMinute;
|
|
39
|
-
const SCAN_RETRY_DELAY = 1000 * 30;
|
|
40
|
-
// Deletes are tombstones (an empty file IS a missing file): the size-0 index entry is what lets a deletion propagate/reconcile like any other write, and it expires after this long
|
|
41
|
-
const TOMBSTONE_EXPIRY = 1000 * 60 * 60 * 24 * 7;
|
|
42
|
-
const TOMBSTONE_CLEANUP_INTERVAL = 1000 * 60 * 60;
|
|
43
|
-
// While a metadata scan or full sync is running, its progress is logged this often
|
|
44
|
-
const SYNC_PROGRESS_LOG_INTERVAL = 1000 * 60;
|
|
45
|
-
const DISK_LIMIT_CHECK_INTERVAL = 1000 * 60;
|
|
46
|
-
// Full syncs download this many files concurrently (high-latency sources like backblaze would otherwise crawl one round-trip at a time)
|
|
47
|
-
const FULL_SYNC_PARALLEL = 8;
|
|
48
|
-
// A full sync running longer than this is console.errored (and again every interval after), so a sync that will take days is loud instead of a quiet console.log every minute
|
|
49
|
-
const FULL_SYNC_SLOW_ERROR_INTERVAL = 1000 * 60 * 60;
|
|
50
|
-
// A reconcile pass skips failing files (one bad value must not stop the rest), but this many failures in a row means the target itself is down, so the pass aborts until the next scan cycle
|
|
51
|
-
const RECONCILE_MAX_CONSECUTIVE_FAILURES = 5;
|
|
52
|
-
const RECONCILE_ERROR_LOG_LIMIT = 3;
|
|
53
23
|
const WRONG_TARGET_LOG_THROTTLE = 60 * 1000;
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
constructor(disk) {
|
|
57
|
-
this.disk = disk;
|
|
58
|
-
}
|
|
59
|
-
async get2(config) {
|
|
60
|
-
return await this.disk.get2(config.path, { range: config.range, includeTombstones: config.includeTombstones });
|
|
61
|
-
}
|
|
62
|
-
async set(config) {
|
|
63
|
-
await this.disk.set(config.path, config.data, { lastModified: config.lastModified });
|
|
64
|
-
}
|
|
65
|
-
async del(config) {
|
|
66
|
-
if (config.path === remoteConfig_1.ROUTING_FILE) {
|
|
67
|
-
throw new Error(`The routing config ${JSON.stringify(remoteConfig_1.ROUTING_FILE)} cannot be deleted (overwrite it to change the bucket's configuration)`);
|
|
68
|
-
}
|
|
69
|
-
await this.disk.del(config.path, { lastModified: config.lastModified });
|
|
70
|
-
}
|
|
71
|
-
async getInfo(config) {
|
|
72
|
-
return await this.disk.getInfo(config.path, { includeTombstones: config.includeTombstones });
|
|
73
|
-
}
|
|
74
|
-
async findInfo(config) {
|
|
75
|
-
return await this.disk.findInfo(config.prefix, { shallow: config.shallow, type: config.type });
|
|
76
|
-
}
|
|
77
|
-
async getChangesAfter2(config) {
|
|
78
|
-
return await this.disk.getChangesAfter2(config);
|
|
79
|
-
}
|
|
80
|
-
async startLargeUpload() {
|
|
81
|
-
return await this.disk.startLargeUpload();
|
|
82
|
-
}
|
|
83
|
-
async appendLargeUpload(config) {
|
|
84
|
-
await this.disk.appendLargeUpload(config.id, config.data);
|
|
85
|
-
}
|
|
86
|
-
async finishLargeUpload(config) {
|
|
87
|
-
await this.disk.finishLargeUpload(config.id, config.path, config.lastModified);
|
|
88
|
-
}
|
|
89
|
-
async cancelLargeUpload(config) {
|
|
90
|
-
await this.disk.cancelLargeUpload(config.id);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
exports.RawDiskStore = RawDiskStore;
|
|
94
|
-
function newScanTally() {
|
|
95
|
-
return { filtered: 0, new: 0, updated: 0, tombstone: 0, unchanged: 0 };
|
|
96
|
-
}
|
|
97
|
-
function formatScanTally(tally, total) {
|
|
98
|
-
let pct = (n) => `${Math.round(n / Math.max(total, 1) * 1000) / 10}%`;
|
|
99
|
-
return `${tally.new} new paths (${pct(tally.new)}), ${tally.updated} newer writes (${pct(tally.updated)}), ${tally.tombstone} deletions (${pct(tally.tombstone)}), ${tally.unchanged} unchanged (${pct(tally.unchanged)}), ${tally.filtered} outside route (${pct(tally.filtered)})`;
|
|
100
|
-
}
|
|
101
|
-
function newSourceState() {
|
|
102
|
-
return {
|
|
103
|
-
supportsChangesAfter: false,
|
|
104
|
-
initialScan: (0, misc_1.promiseObj)(),
|
|
105
|
-
scanComplete: false,
|
|
106
|
-
scannedCount: 0,
|
|
107
|
-
changesAfterTime: 0,
|
|
108
|
-
lastMissCheck: 0,
|
|
109
|
-
stopped: { stop: false },
|
|
110
|
-
};
|
|
111
|
-
}
|
|
24
|
+
// Marks an upload id that never reached the disk, so it can never collide with one ArchivesDisk handed out
|
|
25
|
+
const DISCARDED_UPLOAD_PREFIX = "discarded_";
|
|
112
26
|
let lastWrongTargetLog = 0;
|
|
113
27
|
function logWrongTargetRejection(message) {
|
|
114
28
|
if (Date.now() - lastWrongTargetLog < WRONG_TARGET_LOG_THROTTLE)
|
|
@@ -116,75 +30,154 @@ function logWrongTargetRejection(message) {
|
|
|
116
30
|
lastWrongTargetLog = Date.now();
|
|
117
31
|
console.log(message);
|
|
118
32
|
}
|
|
33
|
+
// The bucket store, and the only one: every bucket a server holds is served by these, one per store name in its routing config. Its sources are plain IArchives - the first is always the store's own disk folder, the rest are the configured peers (see createStoreSource) - so "no synchronization" is simply a store with no peers, not a different kind of store.
|
|
119
34
|
class BlobStore {
|
|
120
|
-
constructor(
|
|
121
|
-
|
|
35
|
+
constructor(
|
|
36
|
+
// Public for StoreSync, which logs it with everything it does
|
|
37
|
+
folder,
|
|
38
|
+
/** The name this store answers to (see CommonConfig.name) - the entries of the routing config that carry it are the ones that configure it, and the rest are its peers. */
|
|
39
|
+
storeName, config) {
|
|
122
40
|
this.folder = folder;
|
|
123
|
-
this.
|
|
41
|
+
this.storeName = storeName;
|
|
124
42
|
this.config = config;
|
|
43
|
+
// ── state ──
|
|
44
|
+
// Set once the store is shutting down; every loop it owns (and StoreSync's maintenance loops) stops on it
|
|
45
|
+
this.stopped = { stop: false };
|
|
46
|
+
// Whether init has reached the point where a newly added source can start scanning immediately
|
|
47
|
+
this.syncStarted = false;
|
|
48
|
+
/** Its sources, in config order: slot 0 is always its own disk folder, the rest are the peers it synchronizes with. Filled by updateSources, which is also how they change. The store OWNS them - writes pick among them, reads resolve holders through them - and StoreSync only scans whatever is in here at the time. */
|
|
49
|
+
this.sources = [];
|
|
50
|
+
// Uploads immutability already decided against: the client is mid-stream by the time we know, so it keeps sending and every part is dropped
|
|
51
|
+
this.discardedUploads = new Set();
|
|
52
|
+
this.nextDiscardedUpload = 1;
|
|
53
|
+
// Per slot: the persistent sourcesListIndex of that slot's URL, filled by registerSlot before the slot's sync runs
|
|
54
|
+
this.slotSourcesListIndexes = [];
|
|
55
|
+
this.slotRegistrations = [];
|
|
56
|
+
// The routing config this store last applied, so a write of an identical (or older) one is not re-applied
|
|
57
|
+
this.appliedRoutingVersion = -1;
|
|
125
58
|
// #region Main interface
|
|
126
59
|
this.init = (0, caching_1.lazy)(async () => {
|
|
127
|
-
|
|
60
|
+
// Configure first: the config decides what the sources ARE, and everything below is per source. With no config at all that is just our own disk, which is enough to serve and to be written to.
|
|
61
|
+
await this.applyRoutingConfig();
|
|
128
62
|
for (let i = 0; i < this.sources.length; i++) {
|
|
129
63
|
await this.registerSlot(i);
|
|
130
64
|
}
|
|
65
|
+
// After the slots, which is what index entries name as their holder
|
|
131
66
|
await this.loadIndex();
|
|
132
67
|
this.syncStarted = true;
|
|
133
|
-
|
|
134
|
-
if (!this.isLive(i))
|
|
135
|
-
continue;
|
|
136
|
-
void this.runSourceSync(i);
|
|
137
|
-
}
|
|
138
|
-
(0, batching_1.runInfinitePoll)(FAST_FLUSH_POLL, () => this.flushOverlay(), this.stopped);
|
|
139
|
-
(0, batching_1.runInfinitePoll)(INDEX_FLUSH_INTERVAL, () => this.flushIndex(), this.stopped);
|
|
140
|
-
(0, batching_1.runInfinitePoll)(TOMBSTONE_CLEANUP_INTERVAL, () => this.cleanupTombstones(), this.stopped);
|
|
141
|
-
if ((_a = this.config) === null || _a === void 0 ? void 0 : _a.readerDiskLimit) {
|
|
142
|
-
(0, batching_1.runInfinitePoll)(DISK_LIMIT_CHECK_INTERVAL, () => this.enforceDiskLimit(), this.stopped);
|
|
143
|
-
}
|
|
68
|
+
this.sync.start();
|
|
144
69
|
});
|
|
145
|
-
//
|
|
146
|
-
|
|
147
|
-
this.
|
|
148
|
-
|
|
149
|
-
this.
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
70
|
+
// Applying it touches the sources, so it is serialized behind whatever application is already running rather than interleaving with it
|
|
71
|
+
this.routingApplies = Promise.resolve();
|
|
72
|
+
this.sourcesList = new sourcesList_1.SourcesList(path_1.default.join(folder, "index", "sourcesList.txt"));
|
|
73
|
+
this.index = new LogMap_1.LogMap(path_1.default.join(folder, "index", "blobIndex3.log"));
|
|
74
|
+
this.sync = new storeSync_1.StoreSync(this);
|
|
75
|
+
this.storeConfig = new storeConfig_1.StoreConfig(storeName, []);
|
|
76
|
+
this.ownDisk = new ArchivesDisk_1.ArchivesDisk(folder);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Re-reads the routing config out of this store and applies it to itself. Called at startup and
|
|
80
|
+
* whenever that file changes here - which is the ONE mechanism: a config written by an operator
|
|
81
|
+
* and a config pulled off a peer are the same event, a write of that path into this store.
|
|
82
|
+
*
|
|
83
|
+
* A store with no routing config configures itself as its own disk, valid always, for the whole
|
|
84
|
+
* key space. That is a complete, working store - it just has nobody to synchronize with - and it
|
|
85
|
+
* is what lets a store exist before it has ever heard of a configuration.
|
|
86
|
+
*/
|
|
87
|
+
async applyRoutingConfig() {
|
|
88
|
+
var _a, _b;
|
|
89
|
+
let routing = await this.readRoutingConfig();
|
|
90
|
+
let entries = [];
|
|
91
|
+
let peers = [];
|
|
92
|
+
for (let source of (routing === null || routing === void 0 ? void 0 : routing.sources) || []) {
|
|
93
|
+
if (typeof source === "string")
|
|
94
|
+
continue;
|
|
95
|
+
if (source.name === this.storeName && ((_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.isSelf) === null || _b === void 0 ? void 0 : _b.call(_a, source))) {
|
|
96
|
+
entries.push(source);
|
|
97
|
+
continue;
|
|
154
98
|
}
|
|
155
|
-
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
this.
|
|
161
|
-
this.
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
99
|
+
peers.push(source);
|
|
100
|
+
}
|
|
101
|
+
if (routing && !entries.length) {
|
|
102
|
+
console.warn(`The routing config in store ${this.folder} (version ${(0, remoteConfig_1.getConfigVersion)(routing)}) does not name this store (${JSON.stringify(this.storeName)}) as one of ours, so it stays a disk-only store`);
|
|
103
|
+
}
|
|
104
|
+
this.storeConfig.update(entries);
|
|
105
|
+
this.updateSources(this.planSources(peers));
|
|
106
|
+
this.appliedRoutingVersion = routing && (0, remoteConfig_1.getConfigVersion)(routing) || -1;
|
|
107
|
+
}
|
|
108
|
+
// The routing config as this store holds it, read straight off its folder: the store may be configuring itself before it has scanned anything, and this file is what decides what a scan would even talk to
|
|
109
|
+
async readRoutingConfig() {
|
|
110
|
+
let data = await this.ownDisk.get(remoteConfig_1.ROUTING_FILE);
|
|
111
|
+
if (!data || !data.length)
|
|
112
|
+
return undefined;
|
|
113
|
+
try {
|
|
114
|
+
return (0, remoteConfig_1.parseRoutingData)(data);
|
|
115
|
+
}
|
|
116
|
+
catch (e) {
|
|
117
|
+
console.error(`Ignoring the routing config in store ${this.folder}: it could not be parsed (${e.message})`);
|
|
118
|
+
return undefined;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/** The version of the routing config this store is running, so a copy found on a peer is only taken when it is genuinely newer. -1 means it has none. */
|
|
122
|
+
routingVersion() {
|
|
123
|
+
return this.appliedRoutingVersion;
|
|
124
|
+
}
|
|
125
|
+
reapplyRoutingConfig() {
|
|
126
|
+
let next = this.routingApplies.then(() => this.applyRoutingConfig());
|
|
127
|
+
this.routingApplies = next.catch(() => { });
|
|
128
|
+
void next.catch((e) => { var _a; return console.error(`Applying the routing config in store ${this.folder} failed: ${(_a = e.stack) !== null && _a !== void 0 ? _a : e}`); });
|
|
129
|
+
}
|
|
130
|
+
// Our own disk first (always), then every peer whose route overlaps ours - the sources this store synchronizes with, as its own config describes them
|
|
131
|
+
planSources(peers) {
|
|
132
|
+
let self = this.storeConfig.current();
|
|
133
|
+
let makeSpec = (sourceConfig, validWindows, route, noFullSync) => {
|
|
134
|
+
let writeDelay = (0, ArchivesDelayed_1.sourceWriteDelay)({ sourceConfig, fast: self.fast, writeDelay: self.writeDelay });
|
|
135
|
+
return {
|
|
136
|
+
identity: (0, remoteConfig_1.sourceIdentity)(sourceConfig),
|
|
137
|
+
url: (0, remoteConfig_1.sourcePersistentUrl)(sourceConfig, this.folder),
|
|
138
|
+
validWindows,
|
|
139
|
+
route,
|
|
140
|
+
noFullSync,
|
|
141
|
+
intermediate: sourceConfig === null || sourceConfig === void 0 ? void 0 : sourceConfig.intermediate,
|
|
142
|
+
sourceConfig,
|
|
143
|
+
create: () => {
|
|
144
|
+
var _a, _b;
|
|
145
|
+
let created = (_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.createSource) === null || _b === void 0 ? void 0 : _b.call(_a, { sourceConfig, writeDelay });
|
|
146
|
+
if (!created) {
|
|
147
|
+
throw new Error(`This store has no way to build sources, so it cannot use ${JSON.stringify((sourceConfig === null || sourceConfig === void 0 ? void 0 : sourceConfig.url) || this.folder)} (store ${this.folder}). Pass createSource.`);
|
|
148
|
+
}
|
|
149
|
+
return created;
|
|
150
|
+
},
|
|
151
|
+
applyConfig: (source) => { var _a, _b; return (_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.applySource) === null || _b === void 0 ? void 0 : _b.call(_a, source, sourceConfig, writeDelay); },
|
|
152
|
+
};
|
|
153
|
+
};
|
|
154
|
+
// Our own disk accepts writes while ANY window this store holds is open; with no config at all it is simply always valid
|
|
155
|
+
let ownWindows = this.storeConfig.all().map(x => x.validWindow);
|
|
156
|
+
let specs = [makeSpec(undefined, ownWindows.length && ownWindows || [IArchives_1.FULL_VALID_WINDOW], undefined, undefined)];
|
|
157
|
+
// One spec per endpoint, carrying all of its windows: a switchover splits one window around an intermediate, and that is still one source to us
|
|
158
|
+
let byIdentity = new Map();
|
|
159
|
+
for (let peer of peers) {
|
|
160
|
+
let shared = (0, remoteConfig_1.routeIntersection)(self.route, peer.route);
|
|
161
|
+
if (!shared)
|
|
162
|
+
continue;
|
|
163
|
+
let identity = (0, remoteConfig_1.sourceIdentity)(peer);
|
|
164
|
+
let existing = byIdentity.get(identity);
|
|
165
|
+
if (existing) {
|
|
166
|
+
existing.validWindows.push(peer.validWindow);
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
let spec = makeSpec(peer, [peer.validWindow], shared, peer.noFullSync || self.noFullSync);
|
|
170
|
+
byIdentity.set(identity, spec);
|
|
171
|
+
specs.push(spec);
|
|
172
|
+
}
|
|
173
|
+
return specs;
|
|
179
174
|
}
|
|
180
|
-
// Stops all synchronization scans/polls and flushes pending writes. Only used when the store genuinely cannot continue (
|
|
175
|
+
// Stops all synchronization scans/polls and flushes pending writes. Only used when the store genuinely cannot continue (its route or disk limit changed, process shutdown) - routine config changes go through updateSources instead, which the store survives.
|
|
181
176
|
async dispose() {
|
|
182
177
|
this.stopped.stop = true;
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
await this.flushOverlay(true);
|
|
187
|
-
await this.flushIndex();
|
|
178
|
+
this.sync.stop();
|
|
179
|
+
await this.flushDelayedWrites(true);
|
|
180
|
+
await this.index.flush();
|
|
188
181
|
}
|
|
189
182
|
async get2(config) {
|
|
190
183
|
if (config.internal) {
|
|
@@ -193,28 +186,18 @@ class BlobStore {
|
|
|
193
186
|
await this.init();
|
|
194
187
|
let key = config.path;
|
|
195
188
|
let range = config.range;
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
if (overlayEntry.data.length === 0 && !config.includeTombstones)
|
|
200
|
-
return undefined;
|
|
201
|
-
let data = overlayEntry.data;
|
|
202
|
-
let size = data.length;
|
|
203
|
-
if (range) {
|
|
204
|
-
data = data.subarray(Math.min(range.start, data.length), Math.min(range.end, data.length));
|
|
205
|
-
}
|
|
206
|
-
return { data, writeTime: overlayEntry.t, size };
|
|
207
|
-
}
|
|
208
|
-
let entry = await this.getIndexEntry(key);
|
|
209
|
-
if (!entry)
|
|
210
|
-
return undefined;
|
|
211
|
-
if (entry.size === 0) {
|
|
189
|
+
// Not in the index means it does not exist here: the index IS the answer, and scanning heals it on its own schedule. An entry whose holder is no longer in the source list is still valid - getEntryHolder resolves the persisted URL directly, and get2's fallback loop covers a holder that is gone entirely.
|
|
190
|
+
let entry = this.getIndexEntry(key);
|
|
191
|
+
if (!entry) {
|
|
212
192
|
if (!config.includeTombstones)
|
|
213
193
|
return undefined;
|
|
214
|
-
// A
|
|
215
|
-
|
|
194
|
+
// A deletion has no bytes - the tombstone IS the answer, so a flag-caller gets its time with empty data
|
|
195
|
+
let deleted = this.getDeletedEntry(key);
|
|
196
|
+
if (!deleted)
|
|
197
|
+
return undefined;
|
|
198
|
+
return { data: Buffer.alloc(0), writeTime: deleted.writeTime, size: 0 };
|
|
216
199
|
}
|
|
217
|
-
|
|
200
|
+
this.sync.noteAccess(key);
|
|
218
201
|
let holderArchives = await this.getEntryHolder(entry);
|
|
219
202
|
let result;
|
|
220
203
|
let holderError;
|
|
@@ -274,8 +257,8 @@ class BlobStore {
|
|
|
274
257
|
}
|
|
275
258
|
if (holderError)
|
|
276
259
|
throw holderError;
|
|
277
|
-
// The holder answered "not there" and no other source has it either: the entry was stale
|
|
278
|
-
this.
|
|
260
|
+
// The holder answered "not there" and no other source has it either: the entry was stale. Forgotten rather than deleted - nothing happened to this file, we were simply wrong about holding it, and saying otherwise would push a deletion out to everyone else.
|
|
261
|
+
this.purgeIndexEntry(key);
|
|
279
262
|
return undefined;
|
|
280
263
|
}
|
|
281
264
|
async set(config) {
|
|
@@ -286,25 +269,20 @@ class BlobStore {
|
|
|
286
269
|
await this.init();
|
|
287
270
|
let writeTime = config.lastModified || Date.now();
|
|
288
271
|
let route = (0, remoteConfig_1.getRoute)(key);
|
|
289
|
-
// The routing file defines the windows/routes, so they can't possibly apply to it (and it never flows through validation)
|
|
290
|
-
if (key
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
if (!timeValid.some(x => (0, remoteConfig_1.routeContains)(x.route, route))) {
|
|
298
|
-
logWrongTargetRejection(`Rejecting fresh write of ${JSON.stringify(key)} (store ${this.folder}): route ${route} is outside our routes ${JSON.stringify(timeValid.map(x => x.route || IArchives_1.FULL_ROUTE))} at writeTime ${writeTime} (the client's shard config is stale)`);
|
|
299
|
-
throw new Error(`${IArchives_1.STORAGE_WRONG_ROUTE} This store does not handle route ${route} (key ${JSON.stringify(key)}, our routes at this time: ${JSON.stringify(timeValid.map(x => x.route || IArchives_1.FULL_ROUTE))}, store ${this.folder}). Re-resolve the source for this key and retry.`);
|
|
300
|
-
}
|
|
301
|
-
}
|
|
272
|
+
// The routing file defines the windows/routes, so they can't possibly apply to it (and it never flows through validation) - but it has a rule of its own, which is ours to enforce because the file is ours
|
|
273
|
+
if (key === remoteConfig_1.ROUTING_FILE) {
|
|
274
|
+
this.assertRoutingConfigWritable(data);
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
this.assertWriteTarget(key, route, config.lastModified);
|
|
278
|
+
}
|
|
279
|
+
if (key !== remoteConfig_1.ROUTING_FILE && this.storeConfig.all().length) {
|
|
302
280
|
if (config.forceSetImmutable) {
|
|
303
281
|
if (!config.lastModified) {
|
|
304
282
|
throw new Error(`forceSetImmutable requires lastModified (synchronization writes are ordered by their write time), writing ${JSON.stringify(key)} (store ${this.folder})`);
|
|
305
283
|
}
|
|
306
284
|
// Immutability wins: an existing path is kept instead of the push throwing (see SetConfig.forceSetImmutable)
|
|
307
|
-
let self = (0, storePlan_1.selectEntryAt)(this.
|
|
285
|
+
let self = (0, storePlan_1.selectEntryAt)(this.storeConfig.all(), writeTime, route);
|
|
308
286
|
if ((self === null || self === void 0 ? void 0 : self.immutable) && await this.getInfo({ path: key }))
|
|
309
287
|
return;
|
|
310
288
|
}
|
|
@@ -316,12 +294,14 @@ class BlobStore {
|
|
|
316
294
|
if (!config.lastModified) {
|
|
317
295
|
throw new Error(`Internal writes must carry lastModified (they are synchronization pushes, ordered by their write time), writing ${JSON.stringify(key)} (store ${this.folder})`);
|
|
318
296
|
}
|
|
319
|
-
|
|
297
|
+
// The routing file is exempt for the same reason it skips every other check: it is the file that DEFINES our windows and routes, so judging it by the config it is about to replace is how a store gets stuck on a config it can never be told to leave
|
|
298
|
+
if (key !== remoteConfig_1.ROUTING_FILE) {
|
|
299
|
+
this.assertInternalWriteAccepted(key, config.lastModified, route);
|
|
300
|
+
}
|
|
320
301
|
await this.setInternal(key, data, { lastModified: config.lastModified });
|
|
321
302
|
return;
|
|
322
303
|
}
|
|
323
|
-
|
|
324
|
-
await this.setOrDelete(key, data, { fast: self === null || self === void 0 ? void 0 : self.fast, writeDelay: self === null || self === void 0 ? void 0 : self.writeDelay, lastModified: config.lastModified });
|
|
304
|
+
await this.setOrDelete(key, data, { lastModified: config.lastModified });
|
|
325
305
|
}
|
|
326
306
|
async del(config) {
|
|
327
307
|
let key = config.path;
|
|
@@ -329,6 +309,8 @@ class BlobStore {
|
|
|
329
309
|
throw new Error(`The routing config ${JSON.stringify(remoteConfig_1.ROUTING_FILE)} cannot be deleted (overwrite it to change the bucket's configuration)`);
|
|
330
310
|
}
|
|
331
311
|
await this.init();
|
|
312
|
+
// A deletion lands in exactly the same place a write would, so it is judged the same way: one aimed at a shard we don't serve is just as invisible as a write to it
|
|
313
|
+
this.assertWriteTarget(key, (0, remoteConfig_1.getRoute)(key), config.lastModified);
|
|
332
314
|
if (config.internal) {
|
|
333
315
|
if (!config.lastModified) {
|
|
334
316
|
throw new Error(`Internal deletions must carry lastModified (they are synchronization pushes, ordered by their write time), deleting ${JSON.stringify(key)} (store ${this.folder})`);
|
|
@@ -338,135 +320,128 @@ class BlobStore {
|
|
|
338
320
|
await this.setInternal(key, Buffer.alloc(0), { lastModified: config.lastModified });
|
|
339
321
|
return;
|
|
340
322
|
}
|
|
341
|
-
// Deletes are
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
323
|
+
// Deletes are writes (an empty file IS a missing file): the tombstone is ordered by write time like any other write, propagates through synchronization, and is eventually expired
|
|
324
|
+
await this.setOrDelete(key, Buffer.alloc(0), { lastModified: config.lastModified });
|
|
325
|
+
}
|
|
326
|
+
/** A node-side move: the bytes never travel through the client. Deliberately just get2 + set + del rather than a disk rename, so the destination write passes EVERY rule a set passes (windows, routes, immutability, only-take-latest, index, fan-out to peers) and the deletion propagates as a normal tombstone - a rename would bypass all of it. The set stamps fresh, so the moved file beats any tombstone at its new path. */
|
|
327
|
+
async move(config) {
|
|
328
|
+
await this.init();
|
|
329
|
+
if (config.fromPath === config.toPath)
|
|
330
|
+
return;
|
|
331
|
+
if (config.fromPath === remoteConfig_1.ROUTING_FILE || config.toPath === remoteConfig_1.ROUTING_FILE) {
|
|
332
|
+
throw new Error(`The routing config ${JSON.stringify(remoteConfig_1.ROUTING_FILE)} cannot be moved (store ${this.folder})`);
|
|
333
|
+
}
|
|
334
|
+
let result = await this.get2({ path: config.fromPath });
|
|
335
|
+
if (!result || !result.data.length) {
|
|
336
|
+
throw new Error(`Cannot move ${JSON.stringify(config.fromPath)} to ${JSON.stringify(config.toPath)}: the source file does not exist (store ${this.folder})`);
|
|
337
|
+
}
|
|
338
|
+
await this.set({ path: config.toPath, data: result.data });
|
|
339
|
+
await this.del({ path: config.fromPath });
|
|
345
340
|
}
|
|
346
341
|
async getInfo(config) {
|
|
347
342
|
await this.init();
|
|
348
343
|
let key = config.path;
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
}
|
|
355
|
-
let entry = await this.getIndexEntry(key);
|
|
356
|
-
if (!entry)
|
|
344
|
+
// Not in the index means it does not exist here: the index IS the answer, and scanning heals it on its own schedule. An entry whose holder is no longer in the source list is still valid - getEntryHolder resolves the persisted URL directly, and get2's fallback loop covers a holder that is gone entirely.
|
|
345
|
+
let entry = this.getIndexEntry(key);
|
|
346
|
+
if (entry)
|
|
347
|
+
return { writeTime: entry.writeTime, size: entry.size };
|
|
348
|
+
if (!config.includeTombstones)
|
|
357
349
|
return undefined;
|
|
358
|
-
|
|
350
|
+
let deleted = this.getDeletedEntry(key);
|
|
351
|
+
if (!deleted)
|
|
359
352
|
return undefined;
|
|
360
|
-
return { writeTime:
|
|
353
|
+
return { writeTime: deleted.writeTime, size: 0 };
|
|
361
354
|
}
|
|
362
355
|
async findInfo(config) {
|
|
363
356
|
await this.init();
|
|
364
|
-
await this.waitForRequiredScans();
|
|
357
|
+
await this.sync.waitForRequiredScans();
|
|
365
358
|
let prefix = config.prefix;
|
|
366
359
|
let infos = new Map();
|
|
367
|
-
|
|
360
|
+
// Deletions are not in here at all, which is what a listing wants: an empty file IS a missing file
|
|
361
|
+
for (let [key, entry] of this.indexEntries()) {
|
|
368
362
|
if (!key.startsWith(prefix))
|
|
369
363
|
continue;
|
|
370
|
-
// Tombstones are missing files, so listings hide them
|
|
371
|
-
if (entry.size === 0)
|
|
372
|
-
continue;
|
|
373
364
|
infos.set(key, { path: key, createTime: entry.writeTime, size: entry.size });
|
|
374
365
|
}
|
|
375
|
-
for (let [key, overlayEntry] of this.overlay) {
|
|
376
|
-
if (!key.startsWith(prefix))
|
|
377
|
-
continue;
|
|
378
|
-
if (overlayEntry.data.length === 0) {
|
|
379
|
-
infos.delete(key);
|
|
380
|
-
continue;
|
|
381
|
-
}
|
|
382
|
-
infos.set(key, { path: key, createTime: overlayEntry.t, size: overlayEntry.data.length });
|
|
383
|
-
}
|
|
384
366
|
let files = (0, ArchivesDisk_1.applyFindInfoShape)(Array.from(infos.values()), prefix, { shallow: config.shallow, type: config.type });
|
|
385
367
|
(0, misc_1.sort)(files, x => x.path);
|
|
386
368
|
return files;
|
|
387
369
|
}
|
|
388
|
-
// All files changed after config.time —
|
|
370
|
+
// All files changed after config.time — straight from the index. Filters on when WE learned of the change (changedAt), so files synchronized late (with old write times) are still reported. Deletions ARE reported, as size-0 entries: a caller reading a change feed has to hear about them, and size 0 is how the feed says "gone" (an empty file IS a missing file). config.routes lets a store syncing a partial shard ask for just its slice.
|
|
389
371
|
async getChangesAfter2(config) {
|
|
390
372
|
await this.init();
|
|
391
|
-
await this.waitForRequiredScans();
|
|
373
|
+
await this.sync.waitForRequiredScans();
|
|
392
374
|
let inRoutes = (key) => !config.routes || config.routes.some(route => (0, remoteConfig_1.routeContains)(route, (0, remoteConfig_1.getRoute)(key)));
|
|
393
375
|
let files = [];
|
|
394
|
-
for (let [key, entry] of this.
|
|
376
|
+
for (let [key, entry] of this.indexEntries()) {
|
|
395
377
|
if (entry.changedAt <= config.time)
|
|
396
378
|
continue;
|
|
397
|
-
if (this.overlay.has(key))
|
|
398
|
-
continue;
|
|
399
379
|
if (!inRoutes(key))
|
|
400
380
|
continue;
|
|
401
381
|
files.push({ path: key, createTime: entry.writeTime, size: entry.size });
|
|
402
382
|
}
|
|
403
|
-
for (let [key,
|
|
404
|
-
if (
|
|
383
|
+
for (let [key, tombstone] of this.deletedEntries()) {
|
|
384
|
+
if (tombstone.changedAt <= config.time)
|
|
405
385
|
continue;
|
|
406
386
|
if (!inRoutes(key))
|
|
407
387
|
continue;
|
|
408
|
-
files.push({ path: key, createTime:
|
|
388
|
+
files.push({ path: key, createTime: tombstone.writeTime, size: 0 });
|
|
409
389
|
}
|
|
410
390
|
(0, misc_1.sort)(files, x => x.path);
|
|
411
391
|
return files;
|
|
412
392
|
}
|
|
413
393
|
async getSyncStatus() {
|
|
414
394
|
await this.init();
|
|
415
|
-
return
|
|
416
|
-
allScansComplete: this.sourceStates.every(x => x.scanComplete),
|
|
417
|
-
indexSize: this.mem.size,
|
|
418
|
-
sources: this.sources.map((x, i) => ({
|
|
419
|
-
debugName: x.source.getDebugName(),
|
|
420
|
-
validWindows: x.validWindows,
|
|
421
|
-
route: x.route,
|
|
422
|
-
noFullSync: x.noFullSync,
|
|
423
|
-
supportsChangesAfter: this.sourceStates[i].supportsChangesAfter,
|
|
424
|
-
initialScanComplete: this.sourceStates[i].scanComplete,
|
|
425
|
-
scannedCount: this.sourceStates[i].scannedCount,
|
|
426
|
-
})).filter((x, i) => this.isLive(i)),
|
|
427
|
-
};
|
|
395
|
+
return this.sync.getStatus();
|
|
428
396
|
}
|
|
429
|
-
/** The
|
|
397
|
+
/** The index's totals plus any in-progress background synchronization. */
|
|
430
398
|
getSyncProgress() {
|
|
431
|
-
|
|
399
|
+
let totals = this.namedIndexTotals();
|
|
432
400
|
return {
|
|
433
|
-
index: { fileCount:
|
|
434
|
-
sources:
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
byteCount: this.sourceByteCounts[i],
|
|
438
|
-
})).filter((x, i) => this.isLive(i)),
|
|
439
|
-
readerDiskLimit: (_a = this.config) === null || _a === void 0 ? void 0 : _a.readerDiskLimit,
|
|
440
|
-
syncing: [...this.syncActivities],
|
|
401
|
+
index: { fileCount: totals.fileCount, byteCount: totals.byteCount },
|
|
402
|
+
sources: totals.sources,
|
|
403
|
+
readerDiskLimit: this.readerDiskLimit,
|
|
404
|
+
syncing: this.sync.getActivities(),
|
|
441
405
|
};
|
|
442
406
|
}
|
|
443
|
-
/**
|
|
407
|
+
/** getSyncProgress's totals, but loading the index first, so they are never the zeroes of a store nothing has touched yet. */
|
|
444
408
|
async computeIndexTotals() {
|
|
445
409
|
await this.init();
|
|
446
|
-
|
|
447
|
-
let byteCount = 0;
|
|
448
|
-
let sources = this.sources.map(x => ({ debugName: x.source.getDebugName(), fileCount: 0, byteCount: 0 }));
|
|
449
|
-
for (let entry of this.mem.values()) {
|
|
450
|
-
if (entry.size === 0)
|
|
451
|
-
continue;
|
|
452
|
-
fileCount++;
|
|
453
|
-
byteCount += entry.size;
|
|
454
|
-
let slot = this.slotForSourcesListIndex(entry.sourcesListIndex);
|
|
455
|
-
if (slot !== undefined) {
|
|
456
|
-
sources[slot].fileCount++;
|
|
457
|
-
sources[slot].byteCount += entry.size;
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
return { fileCount, byteCount, sources: sources.filter((x, i) => this.isLive(i)) };
|
|
410
|
+
return this.namedIndexTotals();
|
|
461
411
|
}
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
412
|
+
namedIndexTotals() {
|
|
413
|
+
let totals = this.indexTotals();
|
|
414
|
+
return {
|
|
415
|
+
fileCount: totals.fileCount,
|
|
416
|
+
byteCount: totals.byteCount,
|
|
417
|
+
sources: this.sources
|
|
418
|
+
.map((x, i) => ({ debugName: x.source.getDebugName(), ...totals.slots[i] }))
|
|
419
|
+
.filter((x, i) => this.isLive(i)),
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* The store's sources, as the current routing config says they should be. This is the ONLY way
|
|
424
|
+
* they are ever set: the first call populates an empty store, every later one applies a change to
|
|
425
|
+
* the running one. Windows, routes and flags move in place, genuinely new endpoints are added and
|
|
426
|
+
* start scanning, and endpoints that are gone go dead (their scans stop, their index entries
|
|
427
|
+
* drop).
|
|
428
|
+
*
|
|
429
|
+
* A store is never rebuilt for a config change. Its name decides its folder and its identity, and
|
|
430
|
+
* a config change cannot change either - so there is nothing a change can do to a store except
|
|
431
|
+
* this.
|
|
432
|
+
*/
|
|
433
|
+
updateSources(specs) {
|
|
434
|
+
var _a, _b, _c, _d;
|
|
465
435
|
if (!specs.length || specs[0].identity !== "disk") {
|
|
466
436
|
throw new Error(`updateSources expects the disk source first (identity "disk"), got ${JSON.stringify(specs.map(x => x.identity))} (store ${this.folder})`);
|
|
467
437
|
}
|
|
468
|
-
if (
|
|
469
|
-
|
|
438
|
+
if (!this.sources.length) {
|
|
439
|
+
// First call: the disk slot has to exist before anything can be matched against it
|
|
440
|
+
let disk = specs[0];
|
|
441
|
+
let source = disk.create();
|
|
442
|
+
(_a = (0, ArchivesDelayed_2.asDelayed)(source)) === null || _a === void 0 ? void 0 : _a.bindFlushDeadline(() => this.writeFlushDeadline());
|
|
443
|
+
this.sources.push({ source, url: disk.url, validWindows: disk.validWindows, route: disk.route, noFullSync: disk.noFullSync, sourceConfig: disk.sourceConfig, identity: disk.identity });
|
|
444
|
+
this.sync.addSource(0);
|
|
470
445
|
}
|
|
471
446
|
let setWindows = (i, windows) => {
|
|
472
447
|
let old = this.sources[i].validWindows;
|
|
@@ -494,8 +469,9 @@ class BlobStore {
|
|
|
494
469
|
}
|
|
495
470
|
let matched = new Set();
|
|
496
471
|
for (let spec of specs.slice(1)) {
|
|
497
|
-
let slot = (
|
|
472
|
+
let slot = (_b = liveByIdentity.get(spec.identity)) === null || _b === void 0 ? void 0 : _b.shift();
|
|
498
473
|
if (slot !== undefined) {
|
|
474
|
+
// The SAME endpoint (see sourceIdentity), so we are already synchronized with it: the slot keeps its connection, its completed scans, and its index entries, and only the policy on it moves. Recreating it here would mean rescanning the endpoint from scratch every time a flag changes.
|
|
499
475
|
matched.add(slot);
|
|
500
476
|
setWindows(slot, spec.validWindows);
|
|
501
477
|
let existing = this.sources[slot];
|
|
@@ -503,115 +479,114 @@ class BlobStore {
|
|
|
503
479
|
console.log(`Route changed for ${existing.source.getDebugName()} (store ${this.folder}): ${JSON.stringify(existing.route)} -> ${JSON.stringify(spec.route)}`);
|
|
504
480
|
existing.route = spec.route;
|
|
505
481
|
}
|
|
482
|
+
if (JSON.stringify(existing.sourceConfig) !== JSON.stringify(spec.sourceConfig)) {
|
|
483
|
+
console.log(`Config changed for ${existing.source.getDebugName()} (store ${this.folder}), keeping the source (so it is not rescanned): ${JSON.stringify(existing.sourceConfig)} -> ${JSON.stringify(spec.sourceConfig)}`);
|
|
484
|
+
}
|
|
485
|
+
// The source carries its config (and its write delay) into everything it does, so it has to learn the new one - see applySourceConfig
|
|
486
|
+
(_c = spec.applyConfig) === null || _c === void 0 ? void 0 : _c.call(spec, existing.source);
|
|
506
487
|
existing.noFullSync = spec.noFullSync;
|
|
507
488
|
existing.sourceConfig = spec.sourceConfig;
|
|
508
489
|
continue;
|
|
509
490
|
}
|
|
510
491
|
let source = spec.create();
|
|
492
|
+
(_d = (0, ArchivesDelayed_2.asDelayed)(source)) === null || _d === void 0 ? void 0 : _d.bindFlushDeadline(() => this.writeFlushDeadline());
|
|
511
493
|
this.sources.push({ source, url: spec.url, validWindows: spec.validWindows, route: spec.route, noFullSync: spec.noFullSync, intermediate: spec.intermediate, sourceConfig: spec.sourceConfig, identity: spec.identity });
|
|
512
|
-
|
|
513
|
-
this.
|
|
514
|
-
this.sourceByteCounts.push(0);
|
|
515
|
-
console.log(`Added sync source ${source.getDebugName()} (store ${this.folder})`);
|
|
516
|
-
if (this.syncStarted) {
|
|
517
|
-
void this.runSourceSync(this.sources.length - 1);
|
|
518
|
-
}
|
|
494
|
+
console.log(`Added sync source ${source.getDebugName()} (store ${this.folder}): a genuinely new endpoint, so it is scanned from scratch`);
|
|
495
|
+
this.sync.addSource(this.sources.length - 1);
|
|
519
496
|
}
|
|
520
497
|
for (let i = 1; i < originalLength; i++) {
|
|
521
498
|
if (!this.isLive(i) || matched.has(i))
|
|
522
499
|
continue;
|
|
523
|
-
this
|
|
524
|
-
|
|
525
|
-
let deadline = this.baseWriteWindowEnd() - exports.WINDOW_END_FLUSH_MARGIN;
|
|
526
|
-
let recapped = 0;
|
|
527
|
-
for (let entry of this.overlay.values()) {
|
|
528
|
-
if (entry.fastFlushAt <= deadline && entry.slowFlushAt <= deadline)
|
|
529
|
-
continue;
|
|
530
|
-
entry.fastFlushAt = Math.min(entry.fastFlushAt, deadline);
|
|
531
|
-
entry.slowFlushAt = Math.min(entry.slowFlushAt, deadline);
|
|
532
|
-
recapped++;
|
|
533
|
-
}
|
|
534
|
-
if (recapped) {
|
|
535
|
-
console.log(`Re-capped ${recapped} pending fast writes to the new flush deadline ${new Date(deadline).toISOString()} (store ${this.folder})`);
|
|
536
|
-
if (deadline <= Date.now()) {
|
|
537
|
-
void this.flushOverlay().catch((e) => { var _a; return console.error(`Flushing fast writes after a valid window change failed (store ${this.folder}): ${(_a = e.stack) !== null && _a !== void 0 ? _a : e}`); });
|
|
538
|
-
}
|
|
500
|
+
// The slot is dead the moment this returns; dropping the index entries it held is the part that reads the index, so it finishes in the background
|
|
501
|
+
void this.sync.removeSource(i).catch((e) => { var _a; return console.error(`Removing sync source ${this.sources[i].source.getDebugName()} (store ${this.folder}) failed: ${(_a = e.stack) !== null && _a !== void 0 ? _a : e}`); });
|
|
539
502
|
}
|
|
540
503
|
}
|
|
541
504
|
/** Rescans our own disk's metadata into the index - used around valid window handoffs, where another process wrote files to the shared folder that our index hasn't seen. */
|
|
542
505
|
async rescanBase() {
|
|
543
506
|
await this.init();
|
|
544
|
-
await this.
|
|
507
|
+
await this.sync.rescanBase();
|
|
545
508
|
}
|
|
546
|
-
/** A boundary scan of the node that owned (part of) our route in the valid window before ours, when that node is different storage (a disk rescan can't see its writes)
|
|
509
|
+
/** A boundary scan of the node that owned (part of) our route in the valid window before ours, when that node is different storage (a disk rescan can't see its writes). */
|
|
547
510
|
async boundaryScanRemote(source, config) {
|
|
548
511
|
await this.init();
|
|
549
|
-
|
|
550
|
-
console.log(`Boundary scan of ${source.getDebugName()} starting: changes since ${new Date(config.since).toISOString()}, route ${JSON.stringify(config.route || IArchives_1.FULL_ROUTE)} (store ${this.folder})`);
|
|
551
|
-
let changes = await source.getChangesAfter2({ time: config.since, routes: config.route && [config.route] || undefined });
|
|
552
|
-
let tally = newScanTally();
|
|
553
|
-
for (let file of changes) {
|
|
554
|
-
if (file.path === remoteConfig_1.ROUTING_FILE) {
|
|
555
|
-
tally.filtered++;
|
|
556
|
-
continue;
|
|
557
|
-
}
|
|
558
|
-
let overlayEntry = this.overlay.get(file.path);
|
|
559
|
-
let entry = this.mem.get(file.path);
|
|
560
|
-
let currentTime = overlayEntry && overlayEntry.t || entry && entry.writeTime || 0;
|
|
561
|
-
if (file.createTime <= currentTime) {
|
|
562
|
-
tally.unchanged++;
|
|
563
|
-
continue;
|
|
564
|
-
}
|
|
565
|
-
if (file.size === 0) {
|
|
566
|
-
// A tombstone stores nothing on our own source - the index entry alone records it
|
|
567
|
-
this.setIndexEntry(file.path, { writeTime: file.createTime, size: 0, sourcesListIndex: this.sourcesListIndexOfSlot(0) });
|
|
568
|
-
tally.tombstone++;
|
|
569
|
-
continue;
|
|
570
|
-
}
|
|
571
|
-
let copied = await (0, IArchives_1.copyArchiveFile)({ from: source, to: this.sources[0].source, path: file.path, size: file.size, writeTime: file.createTime, forceSetImmutable: true, noChecks: true, internal: true });
|
|
572
|
-
if (!copied)
|
|
573
|
-
continue;
|
|
574
|
-
if (copied.size === 0) {
|
|
575
|
-
this.setIndexEntry(file.path, { writeTime: copied.writeTime, size: 0, sourcesListIndex: this.sourcesListIndexOfSlot(0) });
|
|
576
|
-
tally.tombstone++;
|
|
577
|
-
continue;
|
|
578
|
-
}
|
|
579
|
-
this.setIndexEntry(file.path, { writeTime: copied.writeTime, size: copied.size, sourcesListIndex: this.sourcesListIndexOfSlot(0) });
|
|
580
|
-
if (entry || overlayEntry) {
|
|
581
|
-
tally.updated++;
|
|
582
|
-
}
|
|
583
|
-
else {
|
|
584
|
-
tally.new++;
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
console.log(`Boundary scan of ${source.getDebugName()} finished in ${Math.round((Date.now() - scanStart) / 1000)}s (store ${this.folder}): ${changes.length} changes: ${formatScanTally(tally, changes.length)}`);
|
|
512
|
+
await this.sync.boundaryScanRemote(source, config);
|
|
588
513
|
}
|
|
589
|
-
// Large uploads stream onto the local disk source directly (they may not fit in memory)
|
|
514
|
+
// Large uploads stream onto the local disk source directly (they may not fit in memory), and reconciliation carries them to the other sources - there is no delayed-write stage they could pass through. The write itself is validated exactly like set's, right here: the client is about to send the whole file, so every reason to refuse it must be found before the first byte.
|
|
590
515
|
async startLargeUpload(config) {
|
|
591
516
|
await this.init();
|
|
592
|
-
|
|
593
|
-
|
|
517
|
+
let key = config === null || config === void 0 ? void 0 : config.path;
|
|
518
|
+
if (key) {
|
|
519
|
+
let writeTime = (config === null || config === void 0 ? void 0 : config.lastModified) || Date.now();
|
|
520
|
+
let route = (0, remoteConfig_1.getRoute)(key);
|
|
521
|
+
if (key !== remoteConfig_1.ROUTING_FILE) {
|
|
522
|
+
this.assertWriteTarget(key, route, config === null || config === void 0 ? void 0 : config.lastModified);
|
|
523
|
+
}
|
|
524
|
+
if (key !== remoteConfig_1.ROUTING_FILE && this.storeConfig.all().length) {
|
|
525
|
+
if (config === null || config === void 0 ? void 0 : config.forceSetImmutable) {
|
|
526
|
+
if (!config.lastModified) {
|
|
527
|
+
throw new Error(`forceSetImmutable requires lastModified (synchronization writes are ordered by their write time), uploading ${JSON.stringify(key)} (store ${this.folder})`);
|
|
528
|
+
}
|
|
529
|
+
// Immutability wins: an existing path is kept instead of the push throwing (see SetConfig.forceSetImmutable). The client is already streaming, so the upload is accepted and every part discarded - the alternative is throwing at a caller that did nothing wrong.
|
|
530
|
+
let self = (0, storePlan_1.selectEntryAt)(this.storeConfig.all(), writeTime, route);
|
|
531
|
+
if ((self === null || self === void 0 ? void 0 : self.immutable) && await this.getInfo({ path: key })) {
|
|
532
|
+
let id = `${DISCARDED_UPLOAD_PREFIX}${this.nextDiscardedUpload++}`;
|
|
533
|
+
this.discardedUploads.add(id);
|
|
534
|
+
return id;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
else {
|
|
538
|
+
await this.assertMutable(key, writeTime);
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
if (config === null || config === void 0 ? void 0 : config.internal) {
|
|
542
|
+
if (!config.lastModified) {
|
|
543
|
+
throw new Error(`Internal writes must carry lastModified (they are synchronization pushes, ordered by their write time), uploading ${JSON.stringify(key)} (store ${this.folder})`);
|
|
544
|
+
}
|
|
545
|
+
this.assertInternalWriteAccepted(key, config.lastModified, route);
|
|
546
|
+
}
|
|
594
547
|
}
|
|
595
548
|
return await this.getDiskSource().disk.startLargeUpload();
|
|
596
549
|
}
|
|
597
550
|
async appendLargeUpload(config) {
|
|
551
|
+
if (this.discardedUploads.has(config.id))
|
|
552
|
+
return;
|
|
598
553
|
await this.getDiskSource().disk.appendLargeUpload(config.id, config.data);
|
|
599
554
|
}
|
|
600
555
|
async finishLargeUpload(config) {
|
|
556
|
+
if (this.discardedUploads.delete(config.id))
|
|
557
|
+
return;
|
|
601
558
|
let { disk, sourceIndex } = this.getDiskSource();
|
|
559
|
+
if (config.lastModified) {
|
|
560
|
+
(0, IArchives_1.assertValidLastModified)(config.lastModified);
|
|
561
|
+
// An older write never overwrites a newer one (see IArchives.set) - a newer value can land while a long upload is still streaming, so this is re-checked here rather than only at the start
|
|
562
|
+
if (config.lastModified < await this.currentWriteTime(config.path)) {
|
|
563
|
+
await disk.cancelLargeUpload(config.id);
|
|
564
|
+
return;
|
|
565
|
+
}
|
|
566
|
+
}
|
|
602
567
|
await disk.finishLargeUpload(config.id, config.path, config.lastModified);
|
|
603
|
-
|
|
604
|
-
// includeTombstones: a zero-byte upload is still a real file whose index entry must be written
|
|
605
|
-
let info = await disk.getInfo(config.path, { includeTombstones: true });
|
|
568
|
+
let info = await disk.getInfo(config.path);
|
|
606
569
|
if (info) {
|
|
607
570
|
this.setIndexEntry(config.path, { writeTime: info.writeTime, size: info.size, sourcesListIndex: this.sourcesListIndexOfSlot(sourceIndex) });
|
|
608
571
|
}
|
|
609
572
|
}
|
|
610
573
|
async cancelLargeUpload(config) {
|
|
574
|
+
if (this.discardedUploads.delete(config.id))
|
|
575
|
+
return;
|
|
611
576
|
await this.getDiskSource().disk.cancelLargeUpload(config.id);
|
|
612
577
|
}
|
|
578
|
+
// #endregion
|
|
579
|
+
// #region Internals
|
|
580
|
+
/** Bytes of read cache the disk may hold; see CommonConfig.readerDiskLimit (StoreSync enforces it). Read from the config in effect, so raising or removing the limit takes effect on the next eviction pass. */
|
|
581
|
+
get readerDiskLimit() {
|
|
582
|
+
return this.storeConfig.current().readerDiskLimit;
|
|
583
|
+
}
|
|
584
|
+
/** The write time a new write has to beat, or 0 when we have never heard of the key. Counts DELETIONS too: a write older than the deletion that removed it must not bring it back. The index is authoritative even for a write still buffered in a delayed source, since the entry is recorded when the write is accepted rather than when it reaches storage. */
|
|
585
|
+
currentWriteTime(key) {
|
|
586
|
+
return this.index.timeOf(key);
|
|
587
|
+
}
|
|
613
588
|
isLive(sourceIndex) {
|
|
614
|
-
return
|
|
589
|
+
return this.sync.isLive(sourceIndex);
|
|
615
590
|
}
|
|
616
591
|
registerSlot(slot) {
|
|
617
592
|
let existing = this.slotRegistrations[slot];
|
|
@@ -623,7 +598,11 @@ class BlobStore {
|
|
|
623
598
|
this.slotRegistrations[slot] = registration;
|
|
624
599
|
return registration;
|
|
625
600
|
}
|
|
626
|
-
|
|
601
|
+
/** The persistent sourcesListIndex of a slot, or undefined when the slot never got that far (a source removed before its registration resolved). */
|
|
602
|
+
slotSourcesListIndex(slot) {
|
|
603
|
+
return this.slotSourcesListIndexes[slot];
|
|
604
|
+
}
|
|
605
|
+
// The persistent sourcesListIndex of a slot - only valid once the slot's registration resolved (init and the source's sync loop guarantee that before any indexing happens)
|
|
627
606
|
sourcesListIndexOfSlot(slot) {
|
|
628
607
|
var _a;
|
|
629
608
|
let index = this.slotSourcesListIndexes[slot];
|
|
@@ -652,105 +631,142 @@ class BlobStore {
|
|
|
652
631
|
return (_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.resolveSourceUrl) === null || _b === void 0 ? void 0 : _b.call(_a, url);
|
|
653
632
|
}
|
|
654
633
|
async loadIndex() {
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
let sourcesListIndexMap = new Map(sourcesListIndexes.map(x => [x.key, x.value]));
|
|
662
|
-
for (let entry of writeTimes) {
|
|
663
|
-
let size = sizeMap.get(entry.key);
|
|
664
|
-
let sourcesListIndex = sourcesListIndexMap.get(entry.key);
|
|
665
|
-
// Explicit checks, as 0 is a valid size and a valid sourcesListIndex
|
|
666
|
-
if (size === undefined || sourcesListIndex === undefined)
|
|
667
|
-
continue;
|
|
668
|
-
// The routing config is only ever read off our own disk (see updateScanIndex), and a loaded bucket always has it there - a persisted entry pointing elsewhere is stale
|
|
669
|
-
if (entry.key === remoteConfig_1.ROUTING_FILE) {
|
|
670
|
-
sourcesListIndex = this.sourcesListIndexOfSlot(0);
|
|
671
|
-
}
|
|
672
|
-
let full = { writeTime: entry.value, size, sourcesListIndex, changedAt: entry.time, lastAccess: entry.time };
|
|
673
|
-
this.mem.set(entry.key, full);
|
|
674
|
-
this.countEntry(full, 1);
|
|
634
|
+
await this.index.load();
|
|
635
|
+
// The routing config is only ever read off our own disk (see StoreSync's scan handling), and a loaded bucket always has it there - a persisted entry pointing elsewhere is stale, so it is corrected once, here
|
|
636
|
+
let routing = this.getIndexEntry(remoteConfig_1.ROUTING_FILE);
|
|
637
|
+
let baseSourcesListIndex = this.sourcesListIndexOfSlot(0);
|
|
638
|
+
if (routing && routing.sourcesListIndex !== baseSourcesListIndex) {
|
|
639
|
+
this.setIndexEntry(remoteConfig_1.ROUTING_FILE, { writeTime: routing.writeTime, size: routing.size, sourcesListIndex: baseSourcesListIndex });
|
|
675
640
|
}
|
|
676
641
|
}
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
642
|
+
/** A file we hold. A deleted one is not one: it is a tombstone, and only getDeletedEntry knows about it. */
|
|
643
|
+
getIndexEntry(key) {
|
|
644
|
+
let entry = this.index.get(key);
|
|
645
|
+
if (!entry)
|
|
646
|
+
return undefined;
|
|
647
|
+
return { ...entry.value, writeTime: entry.time, changedAt: entry.changedAt };
|
|
648
|
+
}
|
|
649
|
+
/** When a key was deleted, if it was. A deletion is an absence with a time attached - that time is what makes it propagate and what expires it. */
|
|
650
|
+
getDeletedEntry(key) {
|
|
651
|
+
let tombstone = this.index.getDeleted(key);
|
|
652
|
+
if (!tombstone)
|
|
653
|
+
return undefined;
|
|
654
|
+
return { writeTime: tombstone.time, changedAt: tombstone.changedAt };
|
|
655
|
+
}
|
|
656
|
+
/** Every file we hold, for the passes that walk them all (listings, scans, reconciliation, eviction). Deletions are not in here - see deletedEntries. Live: deleting entries while iterating is expected here, and safe. */
|
|
657
|
+
*indexEntries() {
|
|
658
|
+
for (let [key, entry] of this.index.entries()) {
|
|
659
|
+
yield [key, { ...entry.value, writeTime: entry.time, changedAt: entry.changedAt }];
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
/** Every deletion we know of. A much smaller walk than the files, which is what makes expiring them cheap. */
|
|
663
|
+
*deletedEntries() {
|
|
664
|
+
for (let [key, tombstone] of this.index.deletedEntries()) {
|
|
665
|
+
yield [key, { writeTime: tombstone.time, changedAt: tombstone.changedAt }];
|
|
687
666
|
}
|
|
688
667
|
}
|
|
668
|
+
/** How many files we hold, deletions excluded. */
|
|
669
|
+
indexSize() {
|
|
670
|
+
return this.index.size;
|
|
671
|
+
}
|
|
672
|
+
/** Totals over the files we hold, broken down by the slot holding each (entries can name a source that is no longer configured, which counts towards the total but no slot). */
|
|
673
|
+
indexTotals() {
|
|
674
|
+
let fileCount = 0;
|
|
675
|
+
let byteCount = 0;
|
|
676
|
+
let slots = this.sources.map(() => ({ fileCount: 0, byteCount: 0 }));
|
|
677
|
+
for (let [, entry] of this.indexEntries()) {
|
|
678
|
+
fileCount++;
|
|
679
|
+
byteCount += entry.size;
|
|
680
|
+
let slot = this.slotForSourcesListIndex(entry.sourcesListIndex);
|
|
681
|
+
if (slot === undefined)
|
|
682
|
+
continue;
|
|
683
|
+
slots[slot].fileCount++;
|
|
684
|
+
slots[slot].byteCount += entry.size;
|
|
685
|
+
}
|
|
686
|
+
return { fileCount, byteCount, slots };
|
|
687
|
+
}
|
|
688
|
+
/** Records a file, as of its write time. Returns false, having changed nothing, when we already know something at least as new - the index cannot be made to go backwards, whichever path the write came in by. */
|
|
689
689
|
setIndexEntry(key, entry) {
|
|
690
690
|
var _a, _b;
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
691
|
+
if (!this.index.set(key, { size: entry.size, sourcesListIndex: entry.sourcesListIndex }, entry.writeTime))
|
|
692
|
+
return false;
|
|
693
|
+
// The routing config landing here - written by an operator, or pulled off a peer by synchronization - is how this store learns what it is meant to be
|
|
694
|
+
if (key === remoteConfig_1.ROUTING_FILE && this.syncStarted) {
|
|
695
|
+
this.reapplyRoutingConfig();
|
|
696
|
+
}
|
|
696
697
|
(_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.onIndexChanged) === null || _b === void 0 ? void 0 : _b.call(_a, key);
|
|
698
|
+
return true;
|
|
697
699
|
}
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
this.
|
|
704
|
-
|
|
700
|
+
/** Records a DELETION, as of its time: the key stops existing here, and the tombstone is what makes that fact propagate and reconcile like any other write. Same ordering rule as setIndexEntry. */
|
|
701
|
+
setIndexDeleted(key, writeTime) {
|
|
702
|
+
var _a, _b;
|
|
703
|
+
if (!this.index.delete(key, writeTime))
|
|
704
|
+
return false;
|
|
705
|
+
(_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.onIndexChanged) === null || _b === void 0 ? void 0 : _b.call(_a, key);
|
|
706
|
+
return true;
|
|
705
707
|
}
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
708
|
+
/** Forgets a key entirely, tombstone included. NOT a deletion: it says nothing happened to the file, only that we no longer know anything about it - for an entry whose holder turned out not to have it, and for a tombstone old enough that everyone has heard. */
|
|
709
|
+
purgeIndexEntry(key) {
|
|
710
|
+
this.index.purge(key);
|
|
711
|
+
}
|
|
712
|
+
// ── validation (from this store's own routing entries) ──
|
|
713
|
+
/**
|
|
714
|
+
* Every write, however it is stamped, has to be one we are actually meant to hold - because the
|
|
715
|
+
* alternative is not a smaller problem, it is a silent one. A write that lands on a store that
|
|
716
|
+
* does not serve its route (or on a server that is not in the bucket's config at all) goes into a
|
|
717
|
+
* folder nothing scans and no peer reconciles: it succeeds, and then it is gone. The markers make
|
|
718
|
+
* the client re-read the routing config and retry, which is exactly the right outcome when the
|
|
719
|
+
* reason it aimed here is that its config was stale.
|
|
720
|
+
*/
|
|
721
|
+
assertWriteTarget(key, route, lastModified) {
|
|
722
|
+
if (!this.storeConfig.all().length) {
|
|
723
|
+
logWrongTargetRejection(`Rejecting write of ${JSON.stringify(key)} (store ${this.folder}): this server has no entry in the bucket's routing config, so nothing would ever scan or reconcile what it stored`);
|
|
724
|
+
throw new Error(`${IArchives_1.STORAGE_WRONG_VALID_WINDOW} This server is not in the routing config for this bucket, so it cannot accept writes (store ${this.folder}). Re-resolve the currently valid source and retry.`);
|
|
725
|
+
}
|
|
726
|
+
if (!lastModified) {
|
|
727
|
+
this.assertFreshWriteTarget(key, Date.now(), route);
|
|
725
728
|
return;
|
|
726
729
|
}
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
async flushIndex() {
|
|
730
|
-
if (!this.dirty.size)
|
|
730
|
+
// A stamped write picked its own time, so no window can judge it (that is the whole point of a synchronized write) - but the ROUTE is not a matter of timing, and a stamped write to the wrong shard is exactly as invisible as a fresh one
|
|
731
|
+
if (this.storeConfig.all().some(x => (0, remoteConfig_1.routeContains)(x.route, route)))
|
|
731
732
|
return;
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
733
|
+
logWrongTargetRejection(`Rejecting stamped write of ${JSON.stringify(key)} (store ${this.folder}): route ${route} is outside every route we serve ${JSON.stringify(this.storeConfig.all().map(x => x.route || IArchives_1.FULL_ROUTE))}`);
|
|
734
|
+
throw new Error(`${IArchives_1.STORAGE_WRONG_ROUTE} This store does not handle route ${route} (key ${JSON.stringify(key)}, our routes: ${JSON.stringify(this.storeConfig.all().map(x => x.route || IArchives_1.FULL_ROUTE))}, store ${this.folder}). Re-resolve the source for this key and retry.`);
|
|
735
|
+
}
|
|
736
|
+
/**
|
|
737
|
+
* Whether a routing config may be written here. Two rules, and this is the one place either is
|
|
738
|
+
* applied - a config only ever enters the system through a write, so a config that got in is a
|
|
739
|
+
* config that passed, and reading one back never judges it again.
|
|
740
|
+
*
|
|
741
|
+
* The config has to be valid as a whole (see assertValidRemoteConfig), and it has to outrank what
|
|
742
|
+
* we are running: the same version means the same config, so re-writing it is harmless, but a
|
|
743
|
+
* lower one is an older config arriving late and must never undo a newer one.
|
|
744
|
+
*/
|
|
745
|
+
assertRoutingConfigWritable(data) {
|
|
746
|
+
let routing = (0, remoteConfig_1.parseRoutingData)(data);
|
|
747
|
+
(0, remoteConfig_1.assertValidRemoteConfig)(routing);
|
|
748
|
+
let incoming = (0, remoteConfig_1.getConfigVersion)(routing);
|
|
749
|
+
let current = this.routingVersion();
|
|
750
|
+
if (incoming >= current)
|
|
751
|
+
return;
|
|
752
|
+
throw new Error(`Refusing to write ${remoteConfig_1.ROUTING_FILE} to store ${this.folder}: its version (${incoming}) is older than the one this store is running (${current}). Increment the version to update it.`);
|
|
753
|
+
}
|
|
754
|
+
// A fresh (unstamped) write must land on the node the config currently points at: the markers tell the client its config is stale, so it re-resolves and retries against the right node instead of us silently accepting data we were never meant to hold.
|
|
755
|
+
assertFreshWriteTarget(key, writeTime, route) {
|
|
756
|
+
let timeValid = this.storeConfig.all().filter(x => writeTime >= x.validWindow[0] && writeTime < x.validWindow[1]);
|
|
757
|
+
if (!timeValid.length) {
|
|
758
|
+
logWrongTargetRejection(`Rejecting fresh write of ${JSON.stringify(key)} (store ${this.folder}): writeTime ${writeTime} (${new Date(writeTime).toISOString()}) is outside all our valid windows ${JSON.stringify(this.storeConfig.all().map(x => x.validWindow))} (a switchover moved the write target)`);
|
|
759
|
+
throw new Error(`${IArchives_1.STORAGE_WRONG_VALID_WINDOW} This store is not a valid write target at ${writeTime} (our valid windows: ${JSON.stringify(this.storeConfig.all().map(x => x.validWindow))}, store ${this.folder}). Re-resolve the currently valid source and retry.`);
|
|
760
|
+
}
|
|
761
|
+
if (!timeValid.some(x => (0, remoteConfig_1.routeContains)(x.route, route))) {
|
|
762
|
+
logWrongTargetRejection(`Rejecting fresh write of ${JSON.stringify(key)} (store ${this.folder}): route ${route} is outside our routes ${JSON.stringify(timeValid.map(x => x.route || IArchives_1.FULL_ROUTE))} at writeTime ${writeTime} (the client's shard config is stale)`);
|
|
763
|
+
throw new Error(`${IArchives_1.STORAGE_WRONG_ROUTE} This store does not handle route ${route} (key ${JSON.stringify(key)}, our routes at this time: ${JSON.stringify(timeValid.map(x => x.route || IArchives_1.FULL_ROUTE))}, store ${this.folder}). Re-resolve the source for this key and retry.`);
|
|
743
764
|
}
|
|
744
|
-
if (writes.length)
|
|
745
|
-
await this.index.writeBatch(writes);
|
|
746
|
-
if (deletes.length)
|
|
747
|
-
await this.index.deleteBatch(deletes);
|
|
748
765
|
}
|
|
749
|
-
// ── validation (from this store's own routing entries) ──
|
|
750
766
|
async assertMutable(key, writeTime) {
|
|
751
|
-
if (!this.
|
|
767
|
+
if (!this.storeConfig.all().length)
|
|
752
768
|
return;
|
|
753
|
-
let self = (0, storePlan_1.selectEntryAt)(this.
|
|
769
|
+
let self = (0, storePlan_1.selectEntryAt)(this.storeConfig.all(), writeTime, (0, remoteConfig_1.getRoute)(key));
|
|
754
770
|
if (!(self === null || self === void 0 ? void 0 : self.immutable))
|
|
755
771
|
return;
|
|
756
772
|
if (await this.getInfo({ path: key })) {
|
|
@@ -759,397 +775,23 @@ class BlobStore {
|
|
|
759
775
|
}
|
|
760
776
|
// See SetConfig.internal: the stamp must land inside SOME window+route this store is configured for (any window, including past ones - synchronization moves old data), so a confused peer can't stuff data onto a store that was never meant to hold it
|
|
761
777
|
assertInternalWriteAccepted(key, writeTime, route) {
|
|
762
|
-
if (!this.
|
|
778
|
+
if (!this.storeConfig.all().length)
|
|
763
779
|
return;
|
|
764
|
-
let covered = this.
|
|
780
|
+
let covered = this.storeConfig.all().some(x => writeTime >= x.validWindow[0] && writeTime < x.validWindow[1] && (0, remoteConfig_1.routeContains)(x.route, route));
|
|
765
781
|
if (!covered) {
|
|
766
|
-
throw new Error(`Internal write of ${JSON.stringify(key)} rejected: writeTime ${writeTime} (${new Date(writeTime).toISOString()}) at route ${route} is outside every window/route this store is configured for: ${JSON.stringify(this.
|
|
767
|
-
}
|
|
768
|
-
}
|
|
769
|
-
// ── synchronization ──
|
|
770
|
-
async runSourceSync(sourceIndex) {
|
|
771
|
-
var _a;
|
|
772
|
-
await this.registerSlot(sourceIndex);
|
|
773
|
-
let { source } = this.sources[sourceIndex];
|
|
774
|
-
let state = this.sourceStates[sourceIndex];
|
|
775
|
-
// Read live for every pass, not captured - updateSources can change it while loops run
|
|
776
|
-
let noFullSync = () => this.sources[sourceIndex].noFullSync;
|
|
777
|
-
let intermediate = this.sources[sourceIndex].intermediate;
|
|
778
|
-
let listing;
|
|
779
|
-
while (!this.stopped.stop && !state.stopped.stop) {
|
|
780
|
-
if (this.isDeadIntermediate(sourceIndex)) {
|
|
781
|
-
console.log(`Not scanning sync source ${source.getDebugName()} (store ${this.folder}): it is an intermediate whose window already ended`);
|
|
782
|
-
break;
|
|
783
|
-
}
|
|
784
|
-
try {
|
|
785
|
-
let config = await source.getConfig();
|
|
786
|
-
state.supportsChangesAfter = !!config.supportsChangesAfter;
|
|
787
|
-
listing = await this.scanSource(sourceIndex);
|
|
788
|
-
break;
|
|
789
|
-
}
|
|
790
|
-
catch (e) {
|
|
791
|
-
if (intermediate) {
|
|
792
|
-
console.error(`Initial scan of intermediate sync source ${source.getDebugName()} (store ${this.folder}) failed; not retrying (intermediates are temporary switchover ports): ${(_a = e.stack) !== null && _a !== void 0 ? _a : e}`);
|
|
793
|
-
break;
|
|
794
|
-
}
|
|
795
|
-
console.error(`Initial scan of sync source ${source.getDebugName()} failed, retrying:`, e);
|
|
796
|
-
await (0, batching_1.delay)(SCAN_RETRY_DELAY);
|
|
797
|
-
}
|
|
798
|
-
}
|
|
799
|
-
state.scanComplete = true;
|
|
800
|
-
state.initialScan.resolve(undefined);
|
|
801
|
-
if (this.stopped.stop || state.stopped.stop)
|
|
802
|
-
return;
|
|
803
|
-
// An intermediate that never produced a listing is dead or dying - polling and copying from it would only log errors
|
|
804
|
-
if (intermediate && !listing)
|
|
805
|
-
return;
|
|
806
|
-
if (listing) {
|
|
807
|
-
await this.reconcileSource(sourceIndex, listing);
|
|
808
|
-
}
|
|
809
|
-
if (!noFullSync()) {
|
|
810
|
-
try {
|
|
811
|
-
await this.copySourceFiles(sourceIndex);
|
|
812
|
-
}
|
|
813
|
-
catch (e) {
|
|
814
|
-
console.error(`Copying files from sync source ${source.getDebugName()} failed:`, e);
|
|
815
|
-
}
|
|
816
|
-
}
|
|
817
|
-
if (state.supportsChangesAfter) {
|
|
818
|
-
(0, batching_1.runInfinitePoll)(CHANGES_POLL_INTERVAL, async () => {
|
|
819
|
-
if (this.isDeadIntermediate(sourceIndex))
|
|
820
|
-
return;
|
|
821
|
-
await this.pollChanges(sourceIndex);
|
|
822
|
-
if (!noFullSync())
|
|
823
|
-
await this.copySourceFiles(sourceIndex);
|
|
824
|
-
}, state.stopped);
|
|
825
|
-
// Change polls only show what the source HAS, never what it's missing, so pushes run on the full-rescan cadence (findInfo on an index-backed source is cheap)
|
|
826
|
-
(0, batching_1.runInfinitePoll)(FULL_RESCAN_INTERVAL, async () => {
|
|
827
|
-
if (this.isDeadIntermediate(sourceIndex))
|
|
828
|
-
return;
|
|
829
|
-
let files = await source.findInfo("");
|
|
830
|
-
await this.reconcileSource(sourceIndex, new Map(files.map(x => [x.path, x.createTime])));
|
|
831
|
-
}, state.stopped);
|
|
832
|
-
}
|
|
833
|
-
else {
|
|
834
|
-
(0, batching_1.runInfinitePoll)(FULL_RESCAN_UNINDEXED_INTERVAL, async () => {
|
|
835
|
-
if (this.isDeadIntermediate(sourceIndex))
|
|
836
|
-
return;
|
|
837
|
-
let rescan = await this.scanSource(sourceIndex);
|
|
838
|
-
await this.reconcileSource(sourceIndex, rescan);
|
|
839
|
-
if (!noFullSync())
|
|
840
|
-
await this.copySourceFiles(sourceIndex);
|
|
841
|
-
}, state.stopped);
|
|
842
|
-
}
|
|
843
|
-
}
|
|
844
|
-
// An intermediate is a deploy switchover's temporary alternate port: once its window is past, the port is gone for good, so scanning it (or retrying a failed scan) can never succeed - it would just log errors forever. (Dead only once EVERY window has ended - an intermediate normally has just one.)
|
|
845
|
-
isDeadIntermediate(sourceIndex) {
|
|
846
|
-
let { intermediate, validWindows } = this.sources[sourceIndex];
|
|
847
|
-
return !!intermediate && validWindows.every(w => w[1] <= Date.now());
|
|
848
|
-
}
|
|
849
|
-
// Full metadata scan (size, writeTime, path) of one source, applied to the index. Returns the source's listing (path -> write time), which reconcileSource uses for the push direction.
|
|
850
|
-
async scanSource(sourceIndex) {
|
|
851
|
-
var _a, _b;
|
|
852
|
-
let { source, route } = this.sources[sourceIndex];
|
|
853
|
-
let state = this.sourceStates[sourceIndex];
|
|
854
|
-
let scanStart = Date.now();
|
|
855
|
-
let activity = { type: "metadataScan", sourceDebugName: source.getDebugName(), startTime: scanStart };
|
|
856
|
-
this.syncActivities.add(activity);
|
|
857
|
-
console.log(`Metadata scan of ${source.getDebugName()} starting (store ${this.folder})`);
|
|
858
|
-
let progressTimer = setInterval(() => {
|
|
859
|
-
console.log(`Metadata scan of ${source.getDebugName()} still running (${Math.round((Date.now() - scanStart) / 1000)}s, store ${this.folder})`);
|
|
860
|
-
}, SYNC_PROGRESS_LOG_INTERVAL);
|
|
861
|
-
(_b = (_a = progressTimer).unref) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
862
|
-
// The listing request deliberately takes no time or route filters: our slowest sources (backblaze) support neither, so filtering would happen after the full fetch anyway - little benefit, more room for desynchronization. And if a full listing ever becomes too big to send over the network, it is also too big for the receiving process to hold in memory - the fix is more routing shards (each storing and sending less), not filtering.
|
|
863
|
-
let files;
|
|
864
|
-
try {
|
|
865
|
-
files = await source.findInfo("");
|
|
866
|
-
}
|
|
867
|
-
finally {
|
|
868
|
-
clearInterval(progressTimer);
|
|
869
|
-
this.syncActivities.delete(activity);
|
|
870
|
-
}
|
|
871
|
-
// The source may have been removed while the listing was in flight; its results are dead
|
|
872
|
-
if (state.stopped.stop)
|
|
873
|
-
return new Map();
|
|
874
|
-
let indexSizeBefore = this.mem.size;
|
|
875
|
-
let seen = new Map();
|
|
876
|
-
let tally = newScanTally();
|
|
877
|
-
let newPaths = 0;
|
|
878
|
-
for (let file of files) {
|
|
879
|
-
seen.set(file.path, file.createTime);
|
|
880
|
-
if (!this.mem.has(file.path)) {
|
|
881
|
-
newPaths++;
|
|
882
|
-
}
|
|
883
|
-
tally[this.updateScanIndex(sourceIndex, file)]++;
|
|
884
|
-
}
|
|
885
|
-
state.scannedCount = files.length;
|
|
886
|
-
// Index entries this source was the holder of, but that vanished from it (e.g. deleted while we were offline), come out of the index. Entries changed after the scan started are kept — the scan listing may simply predate them. Tombstones have no physical file for a listing to vouch for, so they're exempt (cleanupTombstones expires them instead).
|
|
887
|
-
let removedFromIndex = 0;
|
|
888
|
-
let missingOnSource = 0;
|
|
889
|
-
let scannedSourcesListIndex = this.sourcesListIndexOfSlot(sourceIndex);
|
|
890
|
-
for (let [key, entry] of this.mem) {
|
|
891
|
-
if (seen.has(key))
|
|
892
|
-
continue;
|
|
893
|
-
if (entry.sourcesListIndex === scannedSourcesListIndex && entry.size !== 0 && entry.changedAt < scanStart) {
|
|
894
|
-
this.deleteIndexEntry(key);
|
|
895
|
-
removedFromIndex++;
|
|
896
|
-
continue;
|
|
897
|
-
}
|
|
898
|
-
// Counted only when the source SHOULD hold the entry (its route matches) - these are what the reconcile pass pushes to it (which also ignores the valid window: synchronization moves existing values, the window only routes fresh writes)
|
|
899
|
-
if (entry.size === 0 || key === remoteConfig_1.ROUTING_FILE)
|
|
900
|
-
continue;
|
|
901
|
-
if (!(0, remoteConfig_1.routeContains)(route, (0, remoteConfig_1.getRoute)(key)))
|
|
902
|
-
continue;
|
|
903
|
-
missingOnSource++;
|
|
904
|
-
}
|
|
905
|
-
// Percentages are of the union of both sides (our index + their listing), so every count has a stable denominator
|
|
906
|
-
let union = indexSizeBefore + newPaths;
|
|
907
|
-
let pct = (n) => `${Math.round(n / Math.max(union, 1) * 1000) / 10}%`;
|
|
908
|
-
console.log(`Metadata scan of ${source.getDebugName()} finished in ${Math.round((Date.now() - scanStart) / 1000)}s (store ${this.folder}): ${files.length} listed vs ${indexSizeBefore} indexed (union ${union}): ${formatScanTally(tally, union)}, ${missingOnSource} in index but missing on source (${pct(missingOnSource)}), ${removedFromIndex} removed from index (${pct(removedFromIndex)})`);
|
|
909
|
-
state.changesAfterTime = Math.max(state.changesAfterTime, scanStart - CHANGES_POLL_OVERLAP);
|
|
910
|
-
return seen;
|
|
911
|
-
}
|
|
912
|
-
// The push direction of synchronization: everything we know that the source is missing (or holds an older copy of) is written to it — including deletions, as tombstone writes. This is what heals a source whose background writes failed (e.g. it was down): the next scan sees what's missing and re-sends it. A failing file is skipped, not fatal (immutable targets are handled by forceSetImmutable, and one unreadable value must not stop the rest of the pass) - only a run of consecutive failures (the source itself is down) aborts until the next scan cycle.
|
|
913
|
-
async reconcileSource(sourceIndex, listing) {
|
|
914
|
-
var _a;
|
|
915
|
-
let { source, validWindows, route } = this.sources[sourceIndex];
|
|
916
|
-
let state = this.sourceStates[sourceIndex];
|
|
917
|
-
let acceptsWrites = (0, IArchives_1.windowsAcceptWrites)(validWindows);
|
|
918
|
-
let targetSourcesListIndex = this.sourcesListIndexOfSlot(sourceIndex);
|
|
919
|
-
let pushed = 0;
|
|
920
|
-
let failed = 0;
|
|
921
|
-
let consecutiveFailures = 0;
|
|
922
|
-
let errors = [];
|
|
923
|
-
let aborted = false;
|
|
924
|
-
for (let [key, entry] of this.mem) {
|
|
925
|
-
if (this.stopped.stop || state.stopped.stop)
|
|
926
|
-
return;
|
|
927
|
-
if (entry.sourcesListIndex === targetSourcesListIndex)
|
|
928
|
-
continue;
|
|
929
|
-
// The routing file is NEVER synchronized between storage nodes - it is only ever written directly to each node, and only ever read off our own disk
|
|
930
|
-
if (key === remoteConfig_1.ROUTING_FILE)
|
|
931
|
-
continue;
|
|
932
|
-
if (!acceptsWrites)
|
|
933
|
-
continue;
|
|
934
|
-
if (!(0, remoteConfig_1.routeContains)(route, (0, remoteConfig_1.getRoute)(key)))
|
|
935
|
-
continue;
|
|
936
|
-
let theirTime = listing.get(key);
|
|
937
|
-
if (theirTime !== undefined && theirTime >= entry.writeTime)
|
|
938
|
-
continue;
|
|
939
|
-
try {
|
|
940
|
-
if (entry.size === 0) {
|
|
941
|
-
// A deletion only needs pushing while the source still holds an older copy. It travels as del (never as an empty set - set rejects empty buffers), with the ORIGINAL deletion time so ordering survives.
|
|
942
|
-
if (theirTime === undefined)
|
|
943
|
-
continue;
|
|
944
|
-
await source.del(key, { lastModified: entry.writeTime, noChecks: true, internal: true });
|
|
945
|
-
pushed++;
|
|
946
|
-
consecutiveFailures = 0;
|
|
947
|
-
continue;
|
|
948
|
-
}
|
|
949
|
-
let holder = await this.getEntryHolder(entry);
|
|
950
|
-
if (!holder)
|
|
951
|
-
continue;
|
|
952
|
-
let copied = await (0, IArchives_1.copyArchiveFile)({ from: holder, to: source, path: key, size: entry.size, writeTime: entry.writeTime, forceSetImmutable: true, noChecks: true, internal: true });
|
|
953
|
-
if (!copied)
|
|
954
|
-
continue;
|
|
955
|
-
pushed++;
|
|
956
|
-
consecutiveFailures = 0;
|
|
957
|
-
}
|
|
958
|
-
catch (e) {
|
|
959
|
-
failed++;
|
|
960
|
-
consecutiveFailures++;
|
|
961
|
-
if (errors.length < RECONCILE_ERROR_LOG_LIMIT) {
|
|
962
|
-
errors.push(`${key}: ${(_a = e.stack) !== null && _a !== void 0 ? _a : e}`);
|
|
963
|
-
}
|
|
964
|
-
if (consecutiveFailures >= RECONCILE_MAX_CONSECUTIVE_FAILURES) {
|
|
965
|
-
aborted = true;
|
|
966
|
-
break;
|
|
967
|
-
}
|
|
968
|
-
}
|
|
969
|
-
}
|
|
970
|
-
if (failed) {
|
|
971
|
-
console.error(`Reconciling sync source ${source.getDebugName()} (store ${this.folder}): pushed ${pushed} files, ${failed} failed${aborted && ` before aborting the pass (${consecutiveFailures} consecutive failures - the source looks down; the next scan cycle retries)` || ""}. First errors: ${errors.join(" | ")}`);
|
|
972
|
-
}
|
|
973
|
-
else if (pushed) {
|
|
974
|
-
console.log(`Reconciled sync source ${source.getDebugName()} (store ${this.folder}): pushed ${pushed} files it was missing or held older copies of`);
|
|
975
|
-
}
|
|
976
|
-
}
|
|
977
|
-
updateScanIndex(sourceIndex, file) {
|
|
978
|
-
// An in-flight scan can outlive its source's removal; its results are dead
|
|
979
|
-
if (!this.isLive(sourceIndex))
|
|
980
|
-
return "filtered";
|
|
981
|
-
if (file.path === remoteConfig_1.ROUTING_FILE) {
|
|
982
|
-
// The routing config is NEVER pulled from other sources - it only ever arrives as an explicit, version-validated write, and is only ever read off our own disk. Route and valid-window filters can't possibly apply to it either: it is the file DEFINING them, so filtering it would mean certain sources could never have their routing config updated, ever.
|
|
983
|
-
if (sourceIndex !== 0)
|
|
984
|
-
return "filtered";
|
|
985
|
-
}
|
|
986
|
-
else {
|
|
987
|
-
// The valid window is deliberately NOT applied here: it decides where WRITES route, but a scan is us asking a source what it already holds - existing values synchronize regardless of the window (the same reasoning that lets synchronization ignore the immutable flag). Only the route filters: a partially-overlapping shard's listing legitimately includes keys that aren't ours.
|
|
988
|
-
let { route } = this.sources[sourceIndex];
|
|
989
|
-
if (!(0, remoteConfig_1.routeContains)(route, (0, remoteConfig_1.getRoute)(file.path)))
|
|
990
|
-
return "filtered";
|
|
991
|
-
}
|
|
992
|
-
let existing = this.mem.get(file.path);
|
|
993
|
-
// The highest write time wins across all sources (ties keep the existing entry)
|
|
994
|
-
if (existing && file.createTime <= existing.writeTime)
|
|
995
|
-
return "unchanged";
|
|
996
|
-
this.setIndexEntry(file.path, { writeTime: file.createTime, size: file.size, sourcesListIndex: this.sourcesListIndexOfSlot(sourceIndex) });
|
|
997
|
-
if (file.size === 0)
|
|
998
|
-
return "tombstone";
|
|
999
|
-
if (existing)
|
|
1000
|
-
return "updated";
|
|
1001
|
-
return "new";
|
|
1002
|
-
}
|
|
1003
|
-
async pollChanges(sourceIndex) {
|
|
1004
|
-
let { source, route } = this.sources[sourceIndex];
|
|
1005
|
-
let state = this.sourceStates[sourceIndex];
|
|
1006
|
-
let pollStart = Date.now();
|
|
1007
|
-
let changes = await source.getChangesAfter2({ time: state.changesAfterTime, routes: route && [route] || undefined });
|
|
1008
|
-
let tally = newScanTally();
|
|
1009
|
-
for (let file of changes) {
|
|
1010
|
-
tally[this.updateScanIndex(sourceIndex, file)]++;
|
|
1011
|
-
}
|
|
1012
|
-
// Polls run constantly, so only the ones that actually changed the index get a line
|
|
1013
|
-
if (tally.new || tally.updated || tally.tombstone) {
|
|
1014
|
-
console.log(`Changes poll of ${source.getDebugName()} (store ${this.folder}): ${changes.length} changes: ${formatScanTally(tally, changes.length)}`);
|
|
1015
|
-
}
|
|
1016
|
-
state.scannedCount += changes.length;
|
|
1017
|
-
state.changesAfterTime = pollStart - CHANGES_POLL_OVERLAP;
|
|
1018
|
-
}
|
|
1019
|
-
// Downloads the files a source currently holds onto our own base source (the local disk), preserving their modified times — so a newer local write always wins. Skipped for noFullSync sources (fronting a large database without copying it); reads still down-cache lazily.
|
|
1020
|
-
async copySourceFiles(sourceIndex) {
|
|
1021
|
-
var _a, _b, _c, _d;
|
|
1022
|
-
if (sourceIndex === 0)
|
|
1023
|
-
return;
|
|
1024
|
-
let { source } = this.sources[sourceIndex];
|
|
1025
|
-
let state = this.sourceStates[sourceIndex];
|
|
1026
|
-
let pending = [];
|
|
1027
|
-
let totalBytes = 0;
|
|
1028
|
-
let copiedSourcesListIndex = this.sourcesListIndexOfSlot(sourceIndex);
|
|
1029
|
-
for (let [key, entry] of this.mem) {
|
|
1030
|
-
if (entry.sourcesListIndex !== copiedSourcesListIndex)
|
|
1031
|
-
continue;
|
|
1032
|
-
if (entry.size === 0)
|
|
1033
|
-
continue;
|
|
1034
|
-
pending.push({ key, entry });
|
|
1035
|
-
totalBytes += entry.size;
|
|
1036
|
-
}
|
|
1037
|
-
if (!pending.length)
|
|
1038
|
-
return;
|
|
1039
|
-
let activity = {
|
|
1040
|
-
type: "fullSync",
|
|
1041
|
-
sourceDebugName: source.getDebugName(),
|
|
1042
|
-
startTime: Date.now(),
|
|
1043
|
-
doneFiles: 0,
|
|
1044
|
-
totalFiles: pending.length,
|
|
1045
|
-
doneBytes: 0,
|
|
1046
|
-
totalBytes,
|
|
1047
|
-
};
|
|
1048
|
-
this.syncActivities.add(activity);
|
|
1049
|
-
let progressLogged = false;
|
|
1050
|
-
let logProgress = () => {
|
|
1051
|
-
progressLogged = true;
|
|
1052
|
-
console.log(`Full sync from ${source.getDebugName()} (store ${this.folder}): ${activity.doneFiles}/${pending.length} files (${((activity.doneFiles || 0) / pending.length * 100).toFixed(1)}%), ${(0, format_1.formatNumber)(activity.doneBytes || 0)}B/${(0, format_1.formatNumber)(totalBytes)}B (${(totalBytes && (activity.doneBytes || 0) / totalBytes * 100 || 100).toFixed(1)}%)`);
|
|
1053
|
-
};
|
|
1054
|
-
let progressTimer = setInterval(logProgress, SYNC_PROGRESS_LOG_INTERVAL);
|
|
1055
|
-
(_b = (_a = progressTimer).unref) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
1056
|
-
let slowErrorTimer = setInterval(() => {
|
|
1057
|
-
let elapsed = Date.now() - activity.startTime;
|
|
1058
|
-
let doneFiles = activity.doneFiles || 0;
|
|
1059
|
-
let doneBytes = activity.doneBytes || 0;
|
|
1060
|
-
let bytesPerSecond = doneBytes / (elapsed / 1000);
|
|
1061
|
-
let remainingBytes = totalBytes - doneBytes;
|
|
1062
|
-
let etaText = "unknown (no bytes transferred yet)";
|
|
1063
|
-
if (bytesPerSecond > 0) {
|
|
1064
|
-
let remainingMs = remainingBytes / bytesPerSecond * 1000;
|
|
1065
|
-
etaText = `${(0, format_1.formatTime)(remainingMs)} remaining, completing around ${new Date(Date.now() + remainingMs).toISOString()}`;
|
|
1066
|
-
}
|
|
1067
|
-
console.error(`Full sync from ${source.getDebugName()} (store ${this.folder}) has been running for ${(0, format_1.formatTime)(elapsed)}: ${doneFiles}/${pending.length} files (${(doneFiles / pending.length * 100).toFixed(1)}%), ${(0, format_1.formatNumber)(doneBytes)}B/${(0, format_1.formatNumber)(totalBytes)}B (${(totalBytes && doneBytes / totalBytes * 100 || 100).toFixed(1)}%), ${(0, format_1.formatNumber)(bytesPerSecond)}B/s. Estimated ${etaText}.`);
|
|
1068
|
-
}, FULL_SYNC_SLOW_ERROR_INTERVAL);
|
|
1069
|
-
(_d = (_c = slowErrorTimer).unref) === null || _d === void 0 ? void 0 : _d.call(_c);
|
|
1070
|
-
try {
|
|
1071
|
-
let nextIndex = 0;
|
|
1072
|
-
let failed = false;
|
|
1073
|
-
let copyWorker = async () => {
|
|
1074
|
-
while (!failed && !this.stopped.stop && !state.stopped.stop) {
|
|
1075
|
-
let index = nextIndex++;
|
|
1076
|
-
if (index >= pending.length)
|
|
1077
|
-
return;
|
|
1078
|
-
let { key, entry } = pending[index];
|
|
1079
|
-
let copied = await (0, IArchives_1.copyArchiveFile)({ from: source, to: this.sources[0].source, path: key, size: entry.size, writeTime: entry.writeTime, forceSetImmutable: true, noChecks: true, internal: true });
|
|
1080
|
-
if (copied) {
|
|
1081
|
-
// Only move the entry's source if it wasn't changed while we copied
|
|
1082
|
-
if (this.mem.get(key) === entry) {
|
|
1083
|
-
this.setIndexEntry(key, { writeTime: copied.writeTime, size: copied.size, sourcesListIndex: this.sourcesListIndexOfSlot(0) });
|
|
1084
|
-
}
|
|
1085
|
-
}
|
|
1086
|
-
activity.doneFiles = (activity.doneFiles || 0) + 1;
|
|
1087
|
-
activity.doneBytes = (activity.doneBytes || 0) + entry.size;
|
|
1088
|
-
}
|
|
1089
|
-
};
|
|
1090
|
-
let workers = [];
|
|
1091
|
-
for (let i = 0; i < Math.min(FULL_SYNC_PARALLEL, pending.length); i++) {
|
|
1092
|
-
workers.push(copyWorker().catch((e) => {
|
|
1093
|
-
// Stop the other workers pulling new files, then surface the error
|
|
1094
|
-
failed = true;
|
|
1095
|
-
throw e;
|
|
1096
|
-
}));
|
|
1097
|
-
}
|
|
1098
|
-
await Promise.all(workers);
|
|
1099
|
-
}
|
|
1100
|
-
finally {
|
|
1101
|
-
clearInterval(progressTimer);
|
|
1102
|
-
clearInterval(slowErrorTimer);
|
|
1103
|
-
this.syncActivities.delete(activity);
|
|
1104
|
-
// A sync slow enough to have logged progress also logs its completion
|
|
1105
|
-
if (progressLogged) {
|
|
1106
|
-
logProgress();
|
|
1107
|
-
}
|
|
1108
|
-
}
|
|
1109
|
-
}
|
|
1110
|
-
// findInfo and getChangesAfter2 list from the index, so they must wait for our own base source's initial scan (which might lag minutes) before the listing is trustworthy. The base (local disk) is implicitly required - remote sources are not, they come and go.
|
|
1111
|
-
async waitForRequiredScans() {
|
|
1112
|
-
await this.sourceStates[0].initialScan.promise;
|
|
1113
|
-
}
|
|
1114
|
-
// A requested file isn't in the index: our own base source (implicitly required) is checked directly if its initial scan hasn't finished, and changes-after sources are re-polled (at most every 5 seconds)
|
|
1115
|
-
async checkMissingKey(key) {
|
|
1116
|
-
for (let i = 0; i < this.sources.length; i++) {
|
|
1117
|
-
if (!this.isLive(i))
|
|
1118
|
-
continue;
|
|
1119
|
-
let { source } = this.sources[i];
|
|
1120
|
-
let state = this.sourceStates[i];
|
|
1121
|
-
if (i === 0 && !state.scanComplete) {
|
|
1122
|
-
// includeTombstones: a deletion on disk (an empty file) must be ingested as a tombstone, write time included
|
|
1123
|
-
let info = await source.getInfo(key, { includeTombstones: true });
|
|
1124
|
-
if (info) {
|
|
1125
|
-
this.updateScanIndex(i, { path: key, createTime: info.writeTime, size: info.size });
|
|
1126
|
-
}
|
|
1127
|
-
continue;
|
|
1128
|
-
}
|
|
1129
|
-
if (state.supportsChangesAfter && Date.now() - state.lastMissCheck > MISS_CHECK_INTERVAL) {
|
|
1130
|
-
state.lastMissCheck = Date.now();
|
|
1131
|
-
await this.pollChanges(i);
|
|
1132
|
-
}
|
|
782
|
+
throw new Error(`Internal write of ${JSON.stringify(key)} rejected: writeTime ${writeTime} (${new Date(writeTime).toISOString()}) at route ${route} is outside every window/route this store is configured for: ${JSON.stringify(this.storeConfig.all().map(x => ({ validWindow: x.validWindow, route: x.route || IArchives_1.FULL_ROUTE })))} (store ${this.folder})`);
|
|
1133
783
|
}
|
|
1134
784
|
}
|
|
1135
|
-
|
|
1136
|
-
// An entry whose holder is no longer in the source list is still valid - getEntryHolder resolves the persisted URL directly (and get2's fallback loop covers a holder that is gone entirely)
|
|
1137
|
-
let entry = this.mem.get(key);
|
|
1138
|
-
if (entry)
|
|
1139
|
-
return entry;
|
|
1140
|
-
await this.checkMissingKey(key);
|
|
1141
|
-
return this.mem.get(key);
|
|
1142
|
-
}
|
|
1143
|
-
/** Internal (store-to-store) read: purely the local disk, completely short-circuiting the index and holder resolution - the caller is another store, and chasing OUR remote holders while answering it is how infinite get loops between stores form. No window or route checks: if the bytes are on our disk, the caller may have them. Note fast writes still sitting in the overlay are invisible here; the caller re-finds them after our flush. */
|
|
785
|
+
/** Internal (store-to-store) read: purely the local disk, completely short-circuiting the index and holder resolution - the caller is another store, and chasing OUR remote holders while answering it is how infinite get loops between stores form. No window or route checks: if the bytes are on our disk, the caller may have them. Note this reads the disk past any write delay, so a fast write still buffered in memory is invisible here; the caller re-finds it once it flushes. */
|
|
1144
786
|
async getInternal2(config) {
|
|
1145
787
|
await this.init();
|
|
1146
788
|
// includeTombstones forwards to the disk: a flag-caller (a peer store's synchronization) needs to see our deletions, not just our content. A tombstone deleted from disk entirely only lives in our index, so fall back to that.
|
|
1147
789
|
let result = await this.getDiskSource().disk.get2(config.path, { range: config.range, includeTombstones: config.includeTombstones });
|
|
1148
790
|
if (!result || !result.data) {
|
|
1149
791
|
if (config.includeTombstones) {
|
|
1150
|
-
let
|
|
1151
|
-
if (
|
|
1152
|
-
return { data: Buffer.alloc(0), writeTime:
|
|
792
|
+
let deleted = this.getDeletedEntry(config.path);
|
|
793
|
+
if (deleted)
|
|
794
|
+
return { data: Buffer.alloc(0), writeTime: deleted.writeTime, size: 0 };
|
|
1153
795
|
}
|
|
1154
796
|
return undefined;
|
|
1155
797
|
}
|
|
@@ -1159,18 +801,15 @@ class BlobStore {
|
|
|
1159
801
|
async setInternal(key, data, config) {
|
|
1160
802
|
await this.init();
|
|
1161
803
|
(0, IArchives_1.assertValidLastModified)(config.lastModified);
|
|
1162
|
-
|
|
1163
|
-
let entry = this.mem.get(key);
|
|
1164
|
-
let currentTime = overlayEntry && overlayEntry.t || entry && entry.writeTime || 0;
|
|
1165
|
-
if (config.lastModified < currentTime)
|
|
804
|
+
if (config.lastModified < await this.currentWriteTime(key))
|
|
1166
805
|
return;
|
|
1167
806
|
if (data.length === 0) {
|
|
1168
|
-
// A
|
|
807
|
+
// A deletion stores nothing on our own source - the tombstone is the whole of it
|
|
1169
808
|
await this.sources[0].source.del(key);
|
|
809
|
+
this.setIndexDeleted(key, config.lastModified);
|
|
810
|
+
return;
|
|
1170
811
|
}
|
|
1171
|
-
|
|
1172
|
-
await this.sources[0].source.set(key, data, { lastModified: config.lastModified, forceSetImmutable: true, noChecks: true });
|
|
1173
|
-
}
|
|
812
|
+
await this.sources[0].source.set(key, data, { lastModified: config.lastModified, forceSetImmutable: true, noChecks: true });
|
|
1174
813
|
this.setIndexEntry(key, { writeTime: config.lastModified, size: data.length, sourcesListIndex: this.sourcesListIndexOfSlot(0) });
|
|
1175
814
|
}
|
|
1176
815
|
// The read's bytes came from a remote source, so write them onto our own base source (the local disk), which becomes the entry's new holder - reads only pay the remote fetch once
|
|
@@ -1185,42 +824,27 @@ class BlobStore {
|
|
|
1185
824
|
let lastModified = config.lastModified;
|
|
1186
825
|
if (lastModified) {
|
|
1187
826
|
(0, IArchives_1.assertValidLastModified)(lastModified);
|
|
1188
|
-
let overlayEntry = this.overlay.get(key);
|
|
1189
|
-
let entry = this.mem.get(key);
|
|
1190
|
-
let currentTime = overlayEntry && overlayEntry.t || entry && entry.writeTime || 0;
|
|
1191
827
|
// An older write never overwrites a newer one (see IArchives.set)
|
|
1192
|
-
if (lastModified <
|
|
1193
|
-
return;
|
|
1194
|
-
}
|
|
1195
|
-
let writeTime = lastModified || Date.now();
|
|
1196
|
-
if (config.fast) {
|
|
1197
|
-
// A writeDelay of zero is a real choice (no delay at all), so only an omitted delay gets the default
|
|
1198
|
-
let writeDelay = config.writeDelay;
|
|
1199
|
-
if (writeDelay === undefined) {
|
|
1200
|
-
writeDelay = exports.DEFAULT_FAST_WRITE_DELAY;
|
|
1201
|
-
}
|
|
1202
|
-
// The delay never extends past our own valid window's end (minus the margin, so the writes are on disk before the next window's source takes over - a deploy switchover is just this too, since its remap ends our window). Past that point fast writes write through immediately.
|
|
1203
|
-
let deadline = this.baseWriteWindowEnd() - exports.WINDOW_END_FLUSH_MARGIN;
|
|
1204
|
-
if (writeDelay > 0 && Date.now() < deadline) {
|
|
1205
|
-
// Own disk + our own storage servers (type-"remote") flush within MAX_REMOTE_FAST_BUFFER; the non-"remote" sources (backblaze) wait the full writeDelay
|
|
1206
|
-
let fastFlushAt = Math.min(Date.now() + Math.min(writeDelay, MAX_REMOTE_FAST_BUFFER), deadline);
|
|
1207
|
-
let slowFlushAt = Math.min(Date.now() + writeDelay, deadline);
|
|
1208
|
-
this.overlay.set(key, { data, t: writeTime, fastFlushAt, slowFlushAt });
|
|
828
|
+
if (lastModified < await this.currentWriteTime(key))
|
|
1209
829
|
return;
|
|
1210
|
-
}
|
|
1211
830
|
}
|
|
1212
|
-
this.
|
|
1213
|
-
await this.writeToSources(key, data,
|
|
831
|
+
// Fast writes are not handled here: a source that was configured with a write delay buffers them itself (see ArchivesDelayed), so this write lands in memory and returns, exactly as it would have. The index is updated either way, so the write is immediately visible to readers of this store.
|
|
832
|
+
await this.writeToSources(key, data, lastModified || Date.now());
|
|
1214
833
|
}
|
|
1215
|
-
|
|
1216
|
-
|
|
834
|
+
/** The instant every delayed write must be on its source: the end of our own write window that contains now, minus the flush margin (so the next window's source finds the data on handoff). The LATEST end among covering windows - overlapping windows hand off at the last one. No window contains now (an inert store, or a moment between our windows) -> 0, i.e. nothing may be delayed at all. */
|
|
835
|
+
writeFlushDeadline() {
|
|
836
|
+
// Before updateSources has run there is nothing to hold a write anyway, and nothing may be delayed
|
|
837
|
+
if (!this.sources.length)
|
|
838
|
+
return 0;
|
|
1217
839
|
let now = Date.now();
|
|
1218
840
|
let end = 0;
|
|
1219
841
|
for (let w of this.sources[0].validWindows) {
|
|
1220
842
|
if (w[0] <= now && now < w[1])
|
|
1221
843
|
end = Math.max(end, w[1]);
|
|
1222
844
|
}
|
|
1223
|
-
|
|
845
|
+
if (!end)
|
|
846
|
+
return 0;
|
|
847
|
+
return end - exports.WINDOW_END_FLUSH_MARGIN;
|
|
1224
848
|
}
|
|
1225
849
|
getWritableSources(config) {
|
|
1226
850
|
let writable = [];
|
|
@@ -1233,9 +857,9 @@ class BlobStore {
|
|
|
1233
857
|
}
|
|
1234
858
|
return writable;
|
|
1235
859
|
}
|
|
1236
|
-
//
|
|
1237
|
-
async writeToSources(key, data, writeTime
|
|
1238
|
-
var _a, _b
|
|
860
|
+
// Our own source (the first writable one) plus every route-matching peer. Each source decides for itself how long it holds the write before it hits storage (see ArchivesDelayed) - here they all just get written.
|
|
861
|
+
async writeToSources(key, data, writeTime) {
|
|
862
|
+
var _a, _b;
|
|
1239
863
|
// The routing file is NEVER synchronized between storage nodes: the writer writes it directly to each node, so we store it on our own disk only (no valid-window filter - routing/valid windows can't possibly apply to the file defining them) and never forward it to other sources.
|
|
1240
864
|
(_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.onWriteCounted) === null || _b === void 0 ? void 0 : _b.call(_a, "flushed", data.length);
|
|
1241
865
|
let isRouting = key === remoteConfig_1.ROUTING_FILE;
|
|
@@ -1244,15 +868,14 @@ class BlobStore {
|
|
|
1244
868
|
if (first === undefined) {
|
|
1245
869
|
throw new Error(`No source accepts writes (every source's valid window is in the past), so writes cannot be stored (store ${this.folder})`);
|
|
1246
870
|
}
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
}
|
|
871
|
+
// Only our own (first) source blocks the write. Downstream sources are written in the background: a down downstream source must not fail or stall writes, and reconciliation re-sends anything they missed once they come back.
|
|
872
|
+
if (data.length === 0) {
|
|
873
|
+
// A deletion stores nothing on our own source - the tombstone is the whole of it
|
|
874
|
+
await this.sources[first].source.del(key);
|
|
875
|
+
this.setIndexDeleted(key, writeTime);
|
|
876
|
+
}
|
|
877
|
+
else {
|
|
878
|
+
await this.sources[first].source.set(key, data, { lastModified: writeTime, noChecks: true });
|
|
1256
879
|
this.setIndexEntry(key, { writeTime, size: data.length, sourcesListIndex: this.sourcesListIndexOfSlot(first) });
|
|
1257
880
|
}
|
|
1258
881
|
if (isRouting)
|
|
@@ -1261,8 +884,6 @@ class BlobStore {
|
|
|
1261
884
|
for (let i of writable) {
|
|
1262
885
|
if (!(0, remoteConfig_1.routeContains)(this.sources[i].route, route))
|
|
1263
886
|
continue;
|
|
1264
|
-
if ((config === null || config === void 0 ? void 0 : config.downstream) && !config.downstream(this.sources[i]))
|
|
1265
|
-
continue;
|
|
1266
887
|
// Deletions travel as del carrying the original write time (never as empty sets - set rejects empty buffers). Backblaze materializes such dels as real empty files, so its listings still show the deletion for other stores to scan in as a tombstone.
|
|
1267
888
|
let push;
|
|
1268
889
|
if (data.length === 0) {
|
|
@@ -1277,123 +898,20 @@ class BlobStore {
|
|
|
1277
898
|
});
|
|
1278
899
|
}
|
|
1279
900
|
}
|
|
901
|
+
// Slot 0 is always this store's own folder (see planSources), so the disk is known without searching for it - and it is the unwrapped one, past any write delay
|
|
1280
902
|
getDiskSource() {
|
|
1281
|
-
|
|
1282
|
-
let source = this.sources[i].source;
|
|
1283
|
-
if (source instanceof ArchivesDisk_1.ArchivesDisk)
|
|
1284
|
-
return { disk: source, sourceIndex: i };
|
|
1285
|
-
}
|
|
1286
|
-
throw new Error(`Large uploads require an ArchivesDisk source, and this store has none (store ${this.folder})`);
|
|
1287
|
-
}
|
|
1288
|
-
isRemoteSource(source) {
|
|
1289
|
-
var _a;
|
|
1290
|
-
return ((_a = source.sourceConfig) === null || _a === void 0 ? void 0 : _a.type) === "remote";
|
|
1291
|
-
}
|
|
1292
|
-
async flushOverlay(force) {
|
|
1293
|
-
let now = Date.now();
|
|
1294
|
-
for (let [key, entry] of this.overlay) {
|
|
1295
|
-
let doFast = !entry.fastFlushed && (force || entry.fastFlushAt <= now);
|
|
1296
|
-
let doSlow = force || entry.slowFlushAt <= now;
|
|
1297
|
-
if (!doFast && !doSlow)
|
|
1298
|
-
continue;
|
|
1299
|
-
if (doSlow) {
|
|
1300
|
-
// The remaining sources: if the fast flush already ran, only the non-"remote" ones (own disk + remote peers are done); otherwise everything at once (writeDelay was <= MAX_REMOTE_FAST_BUFFER, or a forced/window-boundary flush)
|
|
1301
|
-
await this.writeToSources(key, entry.data, entry.t, entry.fastFlushed ? { writeBase: false, downstream: s => !this.isRemoteSource(s) } : undefined);
|
|
1302
|
-
// Only remove if it wasn't overwritten while we were flushing
|
|
1303
|
-
if (this.overlay.get(key) === entry) {
|
|
1304
|
-
this.overlay.delete(key);
|
|
1305
|
-
}
|
|
1306
|
-
continue;
|
|
1307
|
-
}
|
|
1308
|
-
// Fast stage: own disk + our own storage servers only; the entry stays in the overlay for its slow flush
|
|
1309
|
-
await this.writeToSources(key, entry.data, entry.t, { downstream: s => this.isRemoteSource(s) });
|
|
1310
|
-
entry.fastFlushed = true;
|
|
1311
|
-
}
|
|
1312
|
-
}
|
|
1313
|
-
async enforceDiskLimit() {
|
|
1314
|
-
var _a, _b;
|
|
1315
|
-
let limit = (_a = this.config) === null || _a === void 0 ? void 0 : _a.readerDiskLimit;
|
|
1316
|
-
if (!limit || this.evicting)
|
|
1317
|
-
return;
|
|
1318
|
-
if (this.sourceByteCounts[0] <= limit)
|
|
1319
|
-
return;
|
|
1320
|
-
this.evicting = true;
|
|
1321
|
-
let evictedFiles = 0;
|
|
1322
|
-
let evictedBytes = 0;
|
|
1323
|
-
try {
|
|
1324
|
-
let baseSourcesListIndex = this.sourcesListIndexOfSlot(0);
|
|
1325
|
-
let candidates = [];
|
|
1326
|
-
for (let [key, entry] of this.mem) {
|
|
1327
|
-
if (entry.sourcesListIndex !== baseSourcesListIndex || entry.size === 0 || key === remoteConfig_1.ROUTING_FILE)
|
|
1328
|
-
continue;
|
|
1329
|
-
candidates.push({ key, entry });
|
|
1330
|
-
}
|
|
1331
|
-
(0, misc_1.sort)(candidates, x => x.entry.lastAccess);
|
|
1332
|
-
for (let { key, entry } of candidates) {
|
|
1333
|
-
if (this.stopped.stop)
|
|
1334
|
-
return;
|
|
1335
|
-
if (this.sourceByteCounts[0] <= limit)
|
|
1336
|
-
break;
|
|
1337
|
-
if (this.mem.get(key) !== entry)
|
|
1338
|
-
continue;
|
|
1339
|
-
let holder;
|
|
1340
|
-
for (let i = 1; i < this.sources.length; i++) {
|
|
1341
|
-
if (!this.isLive(i))
|
|
1342
|
-
continue;
|
|
1343
|
-
try {
|
|
1344
|
-
let info = await this.sources[i].source.getInfo(key);
|
|
1345
|
-
if (info && info.writeTime >= entry.writeTime) {
|
|
1346
|
-
holder = i;
|
|
1347
|
-
break;
|
|
1348
|
-
}
|
|
1349
|
-
}
|
|
1350
|
-
catch (_c) {
|
|
1351
|
-
// A down source just can't vouch for this file right now
|
|
1352
|
-
}
|
|
1353
|
-
}
|
|
1354
|
-
if (holder === undefined)
|
|
1355
|
-
continue;
|
|
1356
|
-
await this.sources[0].source.del(key);
|
|
1357
|
-
this.setIndexEntry(key, { writeTime: entry.writeTime, size: entry.size, sourcesListIndex: this.sourcesListIndexOfSlot(holder) });
|
|
1358
|
-
evictedFiles++;
|
|
1359
|
-
evictedBytes += entry.size;
|
|
1360
|
-
}
|
|
1361
|
-
}
|
|
1362
|
-
finally {
|
|
1363
|
-
this.evicting = false;
|
|
1364
|
-
if (evictedFiles) {
|
|
1365
|
-
console.log(`Disk cache over readerDiskLimit (store ${this.folder}): evicted ${evictedFiles} least-recently-used files (${(0, format_1.formatNumber)(evictedBytes)}B), now at ${(0, format_1.formatNumber)(this.sourceByteCounts[0])}B/${(0, format_1.formatNumber)(((_b = this.config) === null || _b === void 0 ? void 0 : _b.readerDiskLimit) || 0)}B`);
|
|
1366
|
-
}
|
|
1367
|
-
}
|
|
903
|
+
return { disk: this.ownDisk, sourceIndex: 0 };
|
|
1368
904
|
}
|
|
1369
|
-
|
|
1370
|
-
async
|
|
1371
|
-
let
|
|
1372
|
-
|
|
1373
|
-
if (
|
|
1374
|
-
return;
|
|
1375
|
-
if (entry.size !== 0)
|
|
1376
|
-
continue;
|
|
1377
|
-
if (entry.writeTime > cutoff)
|
|
905
|
+
/** Writes everything still held by a delayed source (see ArchivesDelayed). force also writes what isn't due yet - shutdown cannot leave writes in memory. */
|
|
906
|
+
async flushDelayedWrites(force) {
|
|
907
|
+
for (let { source } of this.sources) {
|
|
908
|
+
let delayed = (0, ArchivesDelayed_2.asDelayed)(source);
|
|
909
|
+
if (!delayed)
|
|
1378
910
|
continue;
|
|
1379
|
-
|
|
1380
|
-
for (let i = 0; i < this.sources.length; i++) {
|
|
1381
|
-
if (!this.isLive(i))
|
|
1382
|
-
continue;
|
|
1383
|
-
let sourceEntry = this.sources[i];
|
|
1384
|
-
if (!(0, IArchives_1.windowsAcceptWrites)(sourceEntry.validWindows))
|
|
1385
|
-
continue;
|
|
1386
|
-
let source = sourceEntry.source;
|
|
1387
|
-
if (!(source instanceof backblaze_1.ArchivesBackblaze))
|
|
1388
|
-
continue;
|
|
1389
|
-
void source.del(key).catch((e) => {
|
|
1390
|
-
var _a;
|
|
1391
|
-
console.error(`Removing expired tombstone ${key} from ${source.getDebugName()} failed: ${(_a = e.stack) !== null && _a !== void 0 ? _a : e}`);
|
|
1392
|
-
});
|
|
1393
|
-
}
|
|
911
|
+
await delayed.flush(force);
|
|
1394
912
|
}
|
|
1395
913
|
}
|
|
1396
914
|
}
|
|
1397
915
|
exports.BlobStore = BlobStore;
|
|
1398
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmxvYlN0b3JlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiYmxvYlN0b3JlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFBLGdEQUF3QjtBQUN4Qix5REFBbUQ7QUFDbkQsMkRBQXNFO0FBQ3RFLG1EQUEwRTtBQUMxRSxrRUFBaUY7QUFDakYsNENBR3NCO0FBQ3RCLGtEQUFtRTtBQUNuRSw0Q0FBaUQ7QUFDakQsaURBQXVFO0FBQ3ZFLDJDQUE0QztBQUM1Qyx3RUFBdUY7QUFDdkYsb0RBQThGO0FBQzlGLCtDQUE0QztBQUU1QyxxdEJBQXF0QjtBQUV4c0IsUUFBQSx3QkFBd0IsR0FBRyxtQkFBWSxHQUFHLENBQUMsQ0FBQztBQUN6RCw2WUFBNlk7QUFDN1ksTUFBTSxzQkFBc0IsR0FBRyxJQUFJLEdBQUcsQ0FBQyxDQUFDO0FBQ3hDLCtKQUErSjtBQUMvSixNQUFNLGVBQWUsR0FBRyxJQUFJLEdBQUcsQ0FBQyxDQUFDO0FBQ2pDLG1OQUFtTjtBQUN0TSxRQUFBLHVCQUF1QixHQUFHLG1CQUFZLEdBQUcsQ0FBQyxDQUFDO0FBQ3hELG1GQUFtRjtBQUNuRixNQUFNLG9CQUFvQixHQUFHLElBQUksR0FBRyxFQUFFLENBQUM7QUFDdkMseUVBQXlFO0FBQ3pFLE1BQU0scUJBQXFCLEdBQUcsSUFBSSxHQUFHLEVBQUUsQ0FBQztBQUN4QyxrUUFBa1E7QUFDbFEsTUFBTSxvQkFBb0IsR0FBRyxJQUFJLEdBQUcsRUFBRSxHQUFHLEVBQUUsQ0FBQztBQUM1QyxNQUFNLDhCQUE4QixHQUFHLElBQUksR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLENBQUMsQ0FBQztBQUMxRCwwR0FBMEc7QUFDMUcsTUFBTSxtQkFBbUIsR0FBRyxJQUFJLEdBQUcsQ0FBQyxDQUFDO0FBQ3JDLHNHQUFzRztBQUN0RyxNQUFNLG9CQUFvQixHQUFHLG1CQUFZLENBQUM7QUFDMUMsTUFBTSxnQkFBZ0IsR0FBRyxJQUFJLEdBQUcsRUFBRSxDQUFDO0FBQ25DLG9MQUFv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QUM7Z0JBQUUsU0FBUztZQUMvQixJQUFJLEtBQUssQ0FBQyxTQUFTLEdBQUcsTUFBTTtnQkFBRSxTQUFTO1lBQ3ZDLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUMzQixLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQztnQkFDM0MsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDO29CQUFFLFNBQVM7Z0JBQzlCLElBQUksV0FBVyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUM7Z0JBQ2xDLElBQUksQ0FBQyxJQUFBLCtCQUFtQixFQUFDLFdBQVcsQ0FBQyxZQUFZLENBQUM7b0JBQUUsU0FBUztnQkFDN0QsSUFBSSxNQUFNLEdBQUcsV0FBVyxDQUFDLE1BQU0sQ0FBQztnQkFDaEMsSUFBSSxDQUFDLENBQUMsTUFBTSxZQUFZLDZCQUFpQixDQUFDO29CQUFFLFNBQVM7Z0JBQ3JELEtBQUssTUFBTSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFRLEVBQUUsRUFBRTs7b0JBQ3BDLE9BQU8sQ0FBQyxLQUFLLENBQUMsOEJBQThCLEdBQUcsU0FBUyxNQUFNLENBQUMsWUFBWSxFQUFFLFlBQVksTUFBQSxDQUFDLENBQUMsS0FBSyxtQ0FBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO2dCQUM3RyxDQUFDLENBQUMsQ0FBQztZQUNQLENBQUM7UUFDTCxDQUFDO0lBQ0wsQ0FBQztDQUdKO0FBcHNDRCw4QkFvc0NDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHBhdGggZnJvbSBcInBhdGhcIjtcbmltcG9ydCB7IGxhenkgfSBmcm9tIFwic29ja2V0LWZ1bmN0aW9uL3NyYy9jYWNoaW5nXCI7XG5pbXBvcnQgeyBydW5JbmZpbml0ZVBvbGwsIGRlbGF5IH0gZnJvbSBcInNvY2tldC1mdW5jdGlvbi9zcmMvYmF0Y2hpbmdcIjtcbmltcG9ydCB7IHRpbWVJbk1pbnV0ZSwgc29ydCwgcHJvbWlzZU9iaiB9IGZyb20gXCJzb2NrZXQtZnVuY3Rpb24vc3JjL21pc2NcIjtcbmltcG9ydCB7IGZvcm1hdE51bWJlciwgZm9ybWF0VGltZSB9IGZyb20gXCJzb2NrZXQtZnVuY3Rpb24vc3JjL2Zvcm1hdHRpbmcvZm9ybWF0XCI7XG5pbXBvcnQge1xuICAgIElBcmNoaXZlcywgQXJjaGl2ZUZpbGVJbmZvLCBBcmNoaXZlc1NvdXJjZSwgQXJjaGl2ZXNTeW5jU3RhdHVzLCBDaGFuZ2VzQWZ0ZXJDb25maWcsIEZpbmRDb25maWcsIEhvc3RlZENvbmZpZywgU291cmNlQ29uZmlnLCBhc3NlcnRWYWxpZExhc3RNb2RpZmllZCxcbiAgICB3aW5kb3dBY2NlcHRzV3JpdGVzLCB3aW5kb3dzQWNjZXB0V3JpdGVzLCBTeW5jQWN0aXZpdHksIEZVTExfUk9VVEUsIFNUT1JBR0VfV1JPTkdfVkFMSURfV0lORE9XLCBTVE9SQUdFX1dST05HX1JPVVRFLCBjb3B5QXJjaGl2ZUZpbGUsXG59IGZyb20gXCIuLi9JQXJjaGl2ZXNcIjtcbmltcG9ydCB7IEFyY2hpdmVzRGlzaywgYXBwbHlGaW5kSW5mb1NoYXBlIH0gZnJvbSBcIi4uL0FyY2hpdmVzRGlza1wiO1xuaW1wb3J0IHsgQXJjaGl2ZXNCYWNrYmxhemUgfSBmcm9tIFwiLi4vYmFja2JsYXplXCI7XG5pbXBvcnQgeyBST1VUSU5HX0ZJTEUsIGdldFJvdXRlLCByb3V0ZUNvbnRhaW5zIH0gZnJvbSBcIi4vcmVtb3RlQ29uZmlnXCI7XG5pbXBvcnQgeyBzZWxlY3RFbnRyeUF0IH0gZnJvbSBcIi4vc3RvcmVQbGFuXCI7XG5pbXBvcnQgeyBCdWxrRGF0YWJhc2VCYXNlLCBub29wUmVhY3RpdmVEZXBzIH0gZnJvbSBcIi4uL0J1bGtEYXRhYmFzZTIvQnVsa0RhdGFiYXNlQmFzZVwiO1xuaW1wb3J0IHsgd3JhcEhhbmRsZSwgTm9kZUpTRGlyZWN0b3J5SGFuZGxlV3JhcHBlciwgRGlyZWN0b3J5V3JhcHBlciB9IGZyb20gXCIuLi9GaWxlRm9sZGVyQVBJXCI7XG5pbXBvcnQgeyBTb3VyY2VzTGlzdCB9IGZyb20gXCIuL3NvdXJjZXNMaXN0XCI7XG5cbi8vIFRoZSBzdG9yYWdlIGVuZ2luZSBvZiB0aGUgcmVtb3RlIHN0b3JhZ2Ugc2VydmVyLiBEYXRhIGxpdmVzIGluIHN5bmNocm9uaXphdGlvbiBzb3VyY2VzIChhdCBtaW5pbXVtIGFuIEFyY2hpdmVzRGlzaywgdGhlIGxvY2FsIGRpc2spOyBCbG9iU3RvcmUga2VlcHMgYW4gaW5kZXggb2YgZXZlcnkgZmlsZSAocGF0aCwgbGFzdCBtb2RpZmllZCB0aW1lLCBzaXplLCBhbmQgd2hpY2ggc291cmNlIGN1cnJlbnRseSBob2xkcyB0aGUgZGF0YSkgaW4gYSBCdWxrRGF0YWJhc2UyLCBhbmQgc3luY2hyb25pemVzIHRoZSBpbmRleCBmcm9tIGFsbCBzb3VyY2VzIChzZWUgQXJjaGl2ZXNTb3VyY2UgaW4gSUFyY2hpdmVzLnRzKS4gRXZlcnkgc3RhcnR1cCBmdWxseSByZXNjYW5zIGVhY2ggc291cmNlJ3MgbWV0YWRhdGEsIHNvIHRoZSBpbmRleCBzZWxmLWhlYWxzOyB0aGUgZmlsZSB3aXRoIHRoZSBoaWdoZXN0IHdyaXRlIHRpbWUgd2lucyBhY3Jvc3MgYWxsIHNvdXJjZXMsIHNvIG11bHRpcGxlIHNvdXJjZXMgbmVlZCBubyBzdGFja2luZyBvcmRlci4gVGhlIHN0b3JlIGFsc28gaG9sZHMgaXRzIG93biByb3V0aW5nIGVudHJpZXMgKHRoZSBzZWxmIGVudHJpZXMgb2YgdGhlIE9ORSByb3V0ZSBpdCBzZXJ2ZXMpLCBzbyBpdCB2YWxpZGF0ZXMgd3JpdGVzIGl0c2VsZjogdmFsaWQgd2luZG93cywgcm91dGVzLCBpbW11dGFiaWxpdHksIGFuZCBpbnRlcm5hbC1wdXNoIGFjY2VwdGFuY2UuXG5cbmV4cG9ydCBjb25zdCBERUZBVUxUX0ZBU1RfV1JJVEVfREVMQVkgPSB0aW1lSW5NaW51dGUgKiA1O1xuLy8gVGhlIG1vc3QgYSBmYXN0IHdyaXRlIGlzIGJ1ZmZlcmVkIGJlZm9yZSByZWFjaGluZyBvdXIgT1dOIHN0b3JhZ2Ugc2VydmVycyAodHlwZS1cInJlbW90ZVwiIGRvd25zdHJlYW0gc291cmNlcykgYW5kIG91ciBvd24gZGlzayAtIHNob3J0LCBzbyBjcm9zcy1ub2RlIHJlZHVuZGFuY3kgYW5kIHJlYWQteW91ci13cml0ZXMgYWNyb3NzIG5vZGVzIGRvbid0IHdhaXQgdGhlIGZ1bGwgd3JpdGVEZWxheS4gVGhlIHdyaXRlRGVsYXkgKGRlZmF1bHQgNSBtaW4pIGlzIHJlc2VydmVkIGZvciB0aGUgbm9uLVwicmVtb3RlXCIgc291cmNlcyAoYmFja2JsYXplIGV0YykuIEEgZmFzdCB3cml0ZSB3aXRoIGEgd3JpdGVEZWxheSBzaG9ydGVyIHRoYW4gdGhpcyB1c2VzIHRoZSBzaG9ydGVyIG9uZSBmb3IgYm90aC5cbmNvbnN0IE1BWF9SRU1PVEVfRkFTVF9CVUZGRVIgPSAxMDAwICogNTtcbi8vIFRoZSBvdmVybGF5IGlzIHBvbGxlZCB0aGlzIG9mdGVuIGZvciBkdWUgZmx1c2hlcyAtIGZpbmUgZW5vdWdoIHRoYXQgdGhlIGZhc3QgKHJlbW90ZSkgZmx1c2ggbGFuZHMgY2xvc2UgdG8gTUFYX1JFTU9URV9GQVNUX0JVRkZFUiwgbm90IG9uZSBjb2Fyc2UgdGljayBsYXRlclxuY29uc3QgRkFTVF9GTFVTSF9QT0xMID0gMTAwMCAqIDI7XG4vLyBGYXN0IHdyaXRlcyBhcmUgbmV2ZXIgZGVsYXllZCBwYXN0IG91ciBvd24gdmFsaWQgd2luZG93LCBhbmQgd2l0aGluIHRoaXMgbWFyZ2luIG9mIHRoZSB3aW5kb3cncyBlbmQgdGhleSB3cml0ZSB0aHJvdWdoIGltbWVkaWF0ZWx5IC0gc28gd2hlbiB0aGUgbmV4dCB3aW5kb3cncyBzb3VyY2UgdGFrZXMgb3ZlciwgdGhlIHdyaXRlcyBhcmUgYWxyZWFkeSBvbiBkaXNrXG5leHBvcnQgY29uc3QgV0lORE9XX0VORF9GTFVTSF9NQVJHSU4gPSB0aW1lSW5NaW51dGUgKiA1O1xuLy8gSW5kZXggY2hhbmdlcyBhcmUgYnVmZmVyZWQgaW4gbWVtb3J5IGFuZCB3cml0dGVuIHRvIHRoZSBCdWxrRGF0YWJhc2UyIGluIGJhdGNoZXNcbmNvbnN0IElOREVYX0ZMVVNIX0lOVEVSVkFMID0gMTAwMCAqIDMwO1xuLy8gU291cmNlcyB3aXRoIGEgbmF0aXZlIChpbmRleC1iYWNrZWQpIGNoYW5nZSBmZWVkIGFyZSBwb2xsZWQgdGhpcyBvZnRlblxuY29uc3QgQ0hBTkdFU19QT0xMX0lOVEVSVkFMID0gMTAwMCAqIDYwO1xuLy8gRnVsbCBtZXRhZGF0YSByZXNjYW5zLiBzdXBwb3J0c0NoYW5nZXNBZnRlciBpcyB0aGUgaGV1cmlzdGljIGZvciBcIm9uZSBvZiBvdXIgb3duIHN0b3JhZ2Ugc2VydmVyc1wiOiB0aGVpciBpbmRleC1iYWNrZWQgbGlzdGluZ3MgYXJlIGNoZWFwLCBzbyBob3VybHkgaXMgZmluZS4gRXZlcnl0aGluZyBlbHNlIChiYWNrYmxhemUsIHBsYWluIGRpc2spIHBheXMgdGhlIGZ1bGwgbGlzdGluZyBjb3N0LCBzbyBpdCByZXNjYW5zIG11Y2ggbGVzcyBvZnRlbi5cbmNvbnN0IEZVTExfUkVTQ0FOX0lOVEVSVkFMID0gMTAwMCAqIDYwICogNjA7XG5jb25zdCBGVUxMX1JFU0NBTl9VTklOREVYRURfSU5URVJWQUwgPSAxMDAwICogNjAgKiA2MCAqIDY7XG4vLyBPbiBhIHJlcXVlc3QgZm9yIGEgZmlsZSB0aGUgaW5kZXggZG9lc24ndCBrbm93LCBjaGFuZ2VzLWFmdGVyIHNvdXJjZXMgYXJlIHJlLXBvbGxlZCwgYXQgbW9zdCB0aGlzIG9mdGVuXG5jb25zdCBNSVNTX0NIRUNLX0lOVEVSVkFMID0gMTAwMCAqIDU7XG4vLyBDaGFuZ2UgcG9sbHMgcmUtcmVxdWVzdCB0aGlzIG11Y2ggb3ZlcmxhcCwgc28gY2xvY2sgc2tldyBiZXR3ZWVuIHVzIGFuZCBhIHNvdXJjZSBjYW4ndCBkcm9wIGNoYW5nZXNcbmNvbnN0IENIQU5HRVNfUE9MTF9PVkVSTEFQID0gdGltZUluTWludXRlO1xuY29uc3QgU0NBTl9SRVRSWV9ERUxBWSA9IDEwMDAgKiAzMDtcbi8vIERlbGV0ZXMgYXJlIHRvbWJzdG9uZXMgKGFuIGVtcHR5IGZpbGUgSVMgYSBtaXNzaW5nIGZpbGUpOiB0aGUgc2l6ZS0wIGluZGV4IGVudHJ5IGlzIHdoYXQgbGV0cyBhIGRlbGV0aW9uIHByb3BhZ2F0ZS9yZWNvbmNpbGUgbGlrZSBhbnkgb3RoZXIgd3JpdGUsIGFuZCBpdCBleHBpcmVzIGFmdGVyIHRoaXMgbG9uZ1xuY29uc3QgVE9NQlNUT05FX0VYUElSWSA9IDEwMDAgKiA2MCAqIDYwICogMjQgKiA3O1xuY29uc3QgVE9NQlNUT05FX0NMRUFOVVBfSU5URVJWQUwgPSAxMDAwICogNjAgKiA2MDtcbi8vIFdoaWxlIGEgbWV0YWRhdGEgc2NhbiBvciBmdWxsIHN5bmMgaXMgcnVubmluZywgaXRzIHByb2dyZXNzIGlzIGxvZ2dlZCB0aGlzIG9mdGVuXG5jb25zdCBTWU5DX1BST0dSRVNTX0xPR19JTlRFUlZBTCA9IDEwMDAgKiA2MDtcbmNvbnN0IERJU0tfTElNSVRfQ0hFQ0tfSU5URVJWQUwgPSAxMDAwICogNjA7XG4vLyBGdWxsIHN5bmNzIGRvd25sb2FkIHRoaXMgbWFueSBmaWxlcyBjb25jdXJyZW50bHkgKGhpZ2gtbGF0ZW5jeSBzb3VyY2VzIGxpa2UgYmFja2JsYXplIHdvdWxkIG90aGVyd2lzZSBjcmF3bCBvbmUgcm91bmQtdHJpcCBhdCBhIHRpbWUpXG5jb25zdCBGVUxMX1NZTkNfUEFSQUxMRUwgPSA4O1xuLy8gQSBmdWxsIHN5bmMgcnVubmluZyBsb25nZXIgdGhhbiB0aGlzIGlzIGNvbnNvbGUuZXJyb3JlZCAoYW5kIGFnYWluIGV2ZXJ5IGludGVydmFsIGFmdGVyKSwgc28gYSBzeW5jIHRoYXQgd2lsbCB0YWtlIGRheXMgaXMgbG91ZCBpbnN0ZWFkIG9mIGEgcXVpZXQgY29uc29sZS5sb2cgZXZlcnkgbWludXRlXG5jb25zdCBGVUxMX1NZTkNfU0xPV19FUlJPUl9JTlRFUlZBTCA9IDEwMDAgKiA2MCAqIDYwO1xuLy8gQSByZWNvbmNpbGUgcGFzcyBza2lwcyBmYWlsaW5nIGZpbGVzIChvbmUgYmFkIHZhbHVlIG11c3Qgbm90IHN0b3AgdGhlIHJlc3QpLCBidXQgdGhpcyBtYW55IGZhaWx1cmVzIGluIGEgcm93IG1lYW5zIHRoZSB0YXJnZXQgaXRzZWxmIGlzIGRvd24sIHNvIHRoZSBwYXNzIGFib3J0cyB1bnRpbCB0aGUgbmV4dCBzY2FuIGN5Y2xlXG5jb25zdCBSRUNPTkNJTEVfTUFYX0NPTlNFQ1VUSVZFX0ZBSUxVUkVTID0gNTtcbmNvbnN0IFJFQ09OQ0lMRV9FUlJPUl9MT0dfTElNSVQgPSAzO1xuY29uc3QgV1JPTkdfVEFSR0VUX0xPR19USFJPVFRMRSA9IDYwICogMTAwMDtcblxuLy8gV2hhdCB0aGUgc3RvcmFnZSBzZXJ2ZXIgbmVlZHMgZnJvbSBhIGJ1Y2tldCdzIHN0b3JlLiBCbG9iU3RvcmUgaW1wbGVtZW50cyBpdCBmdWxseSAod2l0aCB2YWxpZGF0aW9uIGZyb20gaXRzIHJvdXRpbmcgZW50cmllcyk7IFJhd0Rpc2tTdG9yZSBhZGFwdHMgYW4gQXJjaGl2ZXNEaXNrIGZvciByYXdEaXNrIGJ1Y2tldHMgKG5vIGluZGV4LCBubyBzeW5jLCBubyB2YWxpZGF0aW9uIC0gcmF3IG1lYW5zIHJhdykuXG5leHBvcnQgdHlwZSBJQnVja2V0U3RvcmUgPSB7XG4gICAgLyoqIGludGVybmFsIChzdG9yZS10by1zdG9yZSkgcmVhZHMgYW5zd2VyIHB1cmVseSBmcm9tIHRoZSBsb2NhbCBkaXNrOyBzZWUgR2V0Q29uZmlnLmludGVybmFsICovXG4gICAgZ2V0Mihjb25maWc6IHsgcGF0aDogc3RyaW5nOyByYW5nZT86IHsgc3RhcnQ6IG51bWJlcjsgZW5kOiBudW1iZXIgfTsgaW50ZXJuYWw/OiBib29sZWFuOyBpbmNsdWRlVG9tYnN0b25lcz86IGJvb2xlYW4gfSk6IFByb21pc2U8eyBkYXRhOiBCdWZmZXI7IHdyaXRlVGltZTogbnVtYmVyOyBzaXplOiBudW1iZXIgfSB8IHVuZGVmaW5lZD47XG4gICAgLyoqIGludGVybmFsIChzdG9yZS10by1zdG9yZSkgd3JpdGVzIGdvIHRvIHRoZSBsb2NhbCBkaXNrICsgaW5kZXggd2l0aCBubyBmYW4tb3V0OyBzZWUgU2V0Q29uZmlnLmludGVybmFsICovXG4gICAgc2V0KGNvbmZpZzogeyBwYXRoOiBzdHJpbmc7IGRhdGE6IEJ1ZmZlcjsgbGFzdE1vZGlmaWVkPzogbnVtYmVyOyBmb3JjZVNldEltbXV0YWJsZT86IGJvb2xlYW47IGludGVybmFsPzogYm9vbGVhbiB9KTogUHJvbWlzZTx2b2lkPjtcbiAgICBkZWwoY29uZmlnOiB7IHBhdGg6IHN0cmluZzsgbGFzdE1vZGlmaWVkPzogbnVtYmVyOyBpbnRlcm5hbD86IGJvb2xlYW4gfSk6IFByb21pc2U8dm9pZD47XG4gICAgZ2V0SW5mbyhjb25maWc6IHsgcGF0aDogc3RyaW5nOyBpbmNsdWRlVG9tYnN0b25lcz86IGJvb2xlYW4gfSk6IFByb21pc2U8eyB3cml0ZVRpbWU6IG51bWJlcjsgc2l6ZTogbnVtYmVyIH0gfCB1bmRlZmluZWQ+O1xuICAgIGZpbmRJbmZvKGNvbmZpZzogRmluZENvbmZpZyAmIHsgcHJlZml4OiBzdHJpbmcgfSk6IFByb21pc2U8QXJjaGl2ZUZpbGVJbmZvW10+O1xuICAgIGdldENoYW5nZXNBZnRlcjIoY29uZmlnOiBDaGFuZ2VzQWZ0ZXJDb25maWcpOiBQcm9taXNlPEFyY2hpdmVGaWxlSW5mb1tdPjtcbiAgICBnZXRTeW5jU3RhdHVzPygpOiBQcm9taXNlPEFyY2hpdmVzU3luY1N0YXR1cz47XG4gICAgZ2V0U3luY1Byb2dyZXNzPygpOiB7XG4gICAgICAgIGluZGV4OiB7IGZpbGVDb3VudDogbnVtYmVyOyBieXRlQ291bnQ6IG51bWJlciB9O1xuICAgICAgICBzb3VyY2VzOiB7IGRlYnVnTmFtZTogc3RyaW5nOyBmaWxlQ291bnQ6IG51bWJlcjsgYnl0ZUNvdW50OiBudW1iZXIgfVtdO1xuICAgICAgICByZWFkZXJEaXNrTGltaXQ/OiBudW1iZXI7XG4gICAgICAgIHN5bmNpbmc6IFN5bmNBY3Rpdml0eVtdO1xuICAgIH07XG4gICAgY29tcHV0ZUluZGV4VG90YWxzPygpOiBQcm9taXNlPHsgZmlsZUNvdW50OiBudW1iZXI7IGJ5dGVDb3VudDogbnVtYmVyOyBzb3VyY2VzOiB7IGRlYnVnTmFtZTogc3RyaW5nOyBmaWxlQ291bnQ6IG51bWJlcjsgYnl0ZUNvdW50OiBudW1iZXIgfVtdIH0+O1xuICAgIC8qKiBwYXRoL2xhc3RNb2RpZmllZCBsZXQgdGhlIHN0b3JlIHJlamVjdCBhbiB1cGxvYWQgaW50byBhbiBpbW11dGFibGUgYnVja2V0IGJlZm9yZSBhbnkgYnl0ZXMgbW92ZSAqL1xuICAgIHN0YXJ0TGFyZ2VVcGxvYWQoY29uZmlnPzogeyBwYXRoPzogc3RyaW5nOyBsYXN0TW9kaWZpZWQ/OiBudW1iZXIgfSk6IFByb21pc2U8c3RyaW5nPjtcbiAgICBhcHBlbmRMYXJnZVVwbG9hZChjb25maWc6IHsgaWQ6IHN0cmluZzsgZGF0YTogQnVmZmVyIH0pOiBQcm9taXNlPHZvaWQ+O1xuICAgIGZpbmlzaExhcmdlVXBsb2FkKGNvbmZpZzogeyBpZDogc3RyaW5nOyBwYXRoOiBzdHJpbmc7IGxhc3RNb2RpZmllZD86IG51bWJlciB9KTogUHJvbWlzZTx2b2lkPjtcbiAgICBjYW5jZWxMYXJnZVVwbG9hZChjb25maWc6IHsgaWQ6IHN0cmluZyB9KTogUHJvbWlzZTx2b2lkPjtcbn07XG5cbi8qKiByYXdEaXNrIGJ1Y2tldHM6IHRoZSBkaXNrIElTIHRoZSBzdG9yZS4gTm8gaW5kZXgsIG5vIHN5bmNocm9uaXphdGlvbiwgbm8gd2luZG93L3JvdXRlL2ltbXV0YWJpbGl0eSB2YWxpZGF0aW9uLiAqL1xuZXhwb3J0IGNsYXNzIFJhd0Rpc2tTdG9yZSBpbXBsZW1lbnRzIElCdWNrZXRTdG9yZSB7XG4gICAgY29uc3RydWN0b3IocHJpdmF0ZSBkaXNrOiBBcmNoaXZlc0Rpc2spIHsgfVxuXG4gICAgcHVibGljIGFzeW5jIGdldDIoY29uZmlnOiB7IHBhdGg6IHN0cmluZzsgcmFuZ2U/OiB7IHN0YXJ0OiBudW1iZXI7IGVuZDogbnVtYmVyIH07IGludGVybmFsPzogYm9vbGVhbjsgaW5jbHVkZVRvbWJzdG9uZXM/OiBib29sZWFuIH0pOiBQcm9taXNlPHsgZGF0YTogQnVmZmVyOyB3cml0ZVRpbWU6IG51bWJlcjsgc2l6ZTogbnVtYmVyIH0gfCB1bmRlZmluZWQ+IHtcbiAgICAgICAgcmV0dXJuIGF3YWl0IHRoaXMuZGlzay5nZXQyKGNvbmZpZy5wYXRoLCB7IHJhbmdlOiBjb25maWcucmFuZ2UsIGluY2x1ZGVUb21ic3RvbmVzOiBjb25maWcuaW5jbHVkZVRvbWJzdG9uZXMgfSk7XG4gICAgfVxuICAgIHB1YmxpYyBhc3luYyBzZXQoY29uZmlnOiB7IHBhdGg6IHN0cmluZzsgZGF0YTogQnVmZmVyOyBsYXN0TW9kaWZpZWQ/OiBudW1iZXI7IGZvcmNlU2V0SW1tdXRhYmxlPzogYm9vbGVhbjsgaW50ZXJuYWw/OiBib29sZWFuIH0pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgYXdhaXQgdGhpcy5kaXNrLnNldChjb25maWcucGF0aCwgY29uZmlnLmRhdGEsIHsgbGFzdE1vZGlmaWVkOiBjb25maWcubGFzdE1vZGlmaWVkIH0pO1xuICAgIH1cbiAgICBwdWJsaWMgYXN5bmMgZGVsKGNvbmZpZzogeyBwYXRoOiBzdHJpbmc7IGxhc3RNb2RpZmllZD86IG51bWJlcjsgaW50ZXJuYWw/OiBib29sZWFuIH0pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgaWYgKGNvbmZpZy5wYXRoID09PSBST1VUSU5HX0ZJTEUpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgVGhlIHJvdXRpbmcgY29uZmlnICR7SlNPTi5zdHJpbmdpZnkoUk9VVElOR19GSUxFKX0gY2Fubm90IGJlIGRlbGV0ZWQgKG92ZXJ3cml0ZSBpdCB0byBjaGFuZ2UgdGhlIGJ1Y2tldCdzIGNvbmZpZ3VyYXRpb24pYCk7XG4gICAgICAgIH1cbiAgICAgICAgYXdhaXQgdGhpcy5kaXNrLmRlbChjb25maWcucGF0aCwgeyBsYXN0TW9kaWZpZWQ6IGNvbmZpZy5sYXN0TW9kaWZpZWQgfSk7XG4gICAgfVxuICAgIHB1YmxpYyBhc3luYyBnZXRJbmZvKGNvbmZpZzogeyBwYXRoOiBzdHJpbmc7IGluY2x1ZGVUb21ic3RvbmVzPzogYm9vbGVhbiB9KTogUHJvbWlzZTx7IHdyaXRlVGltZTogbnVtYmVyOyBzaXplOiBudW1iZXIgfSB8IHVuZGVmaW5lZD4ge1xuICAgICAgICByZXR1cm4gYXdhaXQgdGhpcy5kaXNrLmdldEluZm8oY29uZmlnLnBhdGgsIHsgaW5jbHVkZVRvbWJzdG9uZXM6IGNvbmZpZy5pbmNsdWRlVG9tYnN0b25lcyB9KTtcbiAgICB9XG4gICAgcHVibGljIGFzeW5jIGZpbmRJbmZvKGNvbmZpZzogRmluZENvbmZpZyAmIHsgcHJlZml4OiBzdHJpbmcgfSk6IFByb21pc2U8QXJjaGl2ZUZpbGVJbmZvW10+IHtcbiAgICAgICAgcmV0dXJuIGF3YWl0IHRoaXMuZGlzay5maW5kSW5mbyhjb25maWcucHJlZml4LCB7IHNoYWxsb3c6IGNvbmZpZy5zaGFsbG93LCB0eXBlOiBjb25maWcudHlwZSB9KTtcbiAgICB9XG4gICAgcHVibGljIGFzeW5jIGdldENoYW5nZXNBZnRlcjIoY29uZmlnOiBDaGFuZ2VzQWZ0ZXJDb25maWcpOiBQcm9taXNlPEFyY2hpdmVGaWxlSW5mb1tdPiB7XG4gICAgICAgIHJldHVybiBhd2FpdCB0aGlzLmRpc2suZ2V0Q2hhbmdlc0FmdGVyMihjb25maWcpO1xuICAgIH1cbiAgICBwdWJsaWMgYXN5bmMgc3RhcnRMYXJnZVVwbG9hZCgpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgICAgICByZXR1cm4gYXdhaXQgdGhpcy5kaXNrLnN0YXJ0TGFyZ2VVcGxvYWQoKTtcbiAgICB9XG4gICAgcHVibGljIGFzeW5jIGFwcGVuZExhcmdlVXBsb2FkKGNvbmZpZzogeyBpZDogc3RyaW5nOyBkYXRhOiBCdWZmZXIgfSk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBhd2FpdCB0aGlzLmRpc2suYXBwZW5kTGFyZ2VVcGxvYWQoY29uZmlnLmlkLCBjb25maWcuZGF0YSk7XG4gICAgfVxuICAgIHB1YmxpYyBhc3luYyBmaW5pc2hMYXJnZVVwbG9hZChjb25maWc6IHsgaWQ6IHN0cmluZzsgcGF0aDogc3RyaW5nOyBsYXN0TW9kaWZpZWQ/OiBudW1iZXIgfSk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBhd2FpdCB0aGlzLmRpc2suZmluaXNoTGFyZ2VVcGxvYWQoY29uZmlnLmlkLCBjb25maWcucGF0aCwgY29uZmlnLmxhc3RNb2RpZmllZCk7XG4gICAgfVxuICAgIHB1YmxpYyBhc3luYyBjYW5jZWxMYXJnZVVwbG9hZChjb25maWc6IHsgaWQ6IHN0cmluZyB9KTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGF3YWl0IHRoaXMuZGlzay5jYW5jZWxMYXJnZVVwbG9hZChjb25maWcuaWQpO1xuICAgIH1cbn1cblxudHlwZSBPdmVybGF5RW50cnkgPSB7XG4gICAgLy8gQSB6ZXJvLWxlbmd0aCBidWZmZXIgaXMgYSBwZW5kaW5nIGRlbGV0ZSAodG9tYnN0b25lKVxuICAgIGRhdGE6IEJ1ZmZlcjtcbiAgICB0OiBudW1iZXI7XG4gICAgLy8gV2hlbiB0byBmbHVzaCB0byBvdXIgb3duIGRpc2sgKyB0eXBlLVwicmVtb3RlXCIgZG93bnN0cmVhbSBzb3VyY2VzIChvdXIgb3duIHN0b3JhZ2Ugc2VydmVycyk6IHNob3J0LCBzbyBjcm9zcy1ub2RlIHJlYWRzIGFuZCByZWR1bmRhbmN5IGRvbid0IHdhaXQgdGhlIGZ1bGwgd3JpdGVEZWxheVxuICAgIGZhc3RGbHVzaEF0OiBudW1iZXI7XG4gICAgLy8gV2hlbiB0byBmbHVzaCB0byB0aGUgcmVtYWluaW5nIChub24tXCJyZW1vdGVcIikgZG93bnN0cmVhbSBzb3VyY2VzLCBlLmcuIGJhY2tibGF6ZTogdGhlIGZ1bGwgd3JpdGVEZWxheSwgY29hbGVzY2luZyB0byBrZWVwIGV4cGVuc2l2ZSBleHRlcm5hbCB3cml0ZXMgcmFyZVxuICAgIHNsb3dGbHVzaEF0OiBudW1iZXI7XG4gICAgLy8gU2V0IG9uY2UgdGhlIGZhc3QgZmx1c2ggaGFzIHJ1biAob3duIGRpc2sgKyByZW1vdGUgcGVlcnMgd3JpdHRlbik7IHRoZSBzbG93IGZsdXNoIHRoZW4gb25seSBuZWVkcyB0aGUgbm9uLXJlbW90ZSBzb3VyY2VzXG4gICAgZmFzdEZsdXNoZWQ/OiBib29sZWFuO1xufTtcblxuLy8gT25lIHJvdyBvZiB0aGUgQnVsa0RhdGFiYXNlMiBpbmRleCAoa2V5IGlzIHRoZSBmaWxlIHBhdGgpXG50eXBlIEJsb2JJbmRleEVudHJ5ID0ge1xuICAgIGtleTogc3RyaW5nO1xuICAgIHdyaXRlVGltZTogbnVtYmVyO1xuICAgIHNpemU6IG51bWJlcjtcbiAgICAvLyBXaGljaCBzeW5jaHJvbml6YXRpb24gc291cmNlIGN1cnJlbnRseSBob2xkcyB0aGUgZGF0YTogdGhlIGxpbmUgbnVtYmVyIG9mIHRoZSBzb3VyY2UncyBVUkwgaW4gdGhlIHN0b3JlJ3MgYXBwZW5kLW9ubHkgc291cmNlcyBsaXN0IChzZWUgU291cmNlc0xpc3QpIC0gTk9UIGEgcG9zaXRpb24gaW4gdGhlIGluLW1lbW9yeSBzb3VyY2VzIGFycmF5LCB3aGljaCBjaGFuZ2VzIGJldHdlZW4gcnVuc1xuICAgIHNvdXJjZXNMaXN0SW5kZXg6IG51bWJlcjtcbn07XG50eXBlIEluZGV4RW50cnkgPSB7XG4gICAgd3JpdGVUaW1lOiBudW1iZXI7XG4gICAgc2l6ZTogbnVtYmVyO1xuICAgIHNvdXJjZXNMaXN0SW5kZXg6IG51bWJlcjtcbiAgICAvLyBXaGVuIFdFIGxhc3QgY2hhbmdlZCB0aGlzIGVudHJ5IChub3QgdGhlIGZpbGUncyB3cml0ZSB0aW1lKSDigJQgd2hhdCBnZXRDaGFuZ2VzQWZ0ZXIyIGZpbHRlcnMgb24sIHNvIGxhdGUtYXJyaXZpbmcgZmlsZXMgd2l0aCBvbGQgd3JpdGUgdGltZXMgYXJlIHN0aWxsIHJlcG9ydGVkXG4gICAgY2hhbmdlZEF0OiBudW1iZXI7XG4gICAgLy8gSW4tbWVtb3J5IG9ubHkgKG5vdCBwZXJzaXN0ZWQpOiB3aGVuIHRoZSBmaWxlIHdhcyBsYXN0IHNlcnZlZCwgZm9yIHJlYWRlckRpc2tMaW1pdCdzIExSVSBldmljdGlvbi4gU3RhcnRzIGFzIGNoYW5nZWRBdCBvbiBsb2FkLlxuICAgIGxhc3RBY2Nlc3M6IG51bWJlcjtcbn07XG5cbnR5cGUgU291cmNlU3RhdGUgPSB7XG4gICAgc3VwcG9ydHNDaGFuZ2VzQWZ0ZXI6IGJvb2xlYW47XG4gICAgaW5pdGlhbFNjYW46IFJldHVyblR5cGU8dHlwZW9mIHByb21pc2VPYmo+O1xuICAgIHNjYW5Db21wbGV0ZTogYm9vbGVhbjtcbiAgICAvLyBGaWxlcyBzZWVuIGluIHRoaXMgc291cmNlJ3Mgc2NhbnMgLyBjaGFuZ2UgcG9sbHMgc28gZmFyXG4gICAgc2Nhbm5lZENvdW50OiBudW1iZXI7XG4gICAgLy8gV2F0ZXJtYXJrIGZvciBnZXRDaGFuZ2VzQWZ0ZXIyIHBvbGxzXG4gICAgY2hhbmdlc0FmdGVyVGltZTogbnVtYmVyO1xuICAgIGxhc3RNaXNzQ2hlY2s6IG51bWJlcjtcbiAgICAvLyBQZXItc2xvdCBzdG9wIHRva2VuOiBhIHJlbW92ZWQgc291cmNlJ3MgbG9vcHMgc3RvcCB3aXRob3V0IHRvdWNoaW5nIHRoZSByZXN0IG9mIHRoZSBzdG9yZVxuICAgIHN0b3BwZWQ6IHsgc3RvcDogYm9vbGVhbiB9O1xuICAgIC8vIEEgcmVtb3ZlZCBzb3VyY2UncyBzbG90IHN0YXlzIGluIHRoZSBhcnJheXMgKHRoZXkgYXJlIG5ldmVyIHNwbGljZWQsIHNvIHNsb3QgbnVtYmVycyBoZWxkIGJ5IHJ1bm5pbmcgbG9vcHMgc3RheSBtZWFuaW5nZnVsKSwgbWFya2VkIGRlYWQgLSBuZXZlciBzY2FubmVkLCB3cml0dGVuLCBvciByZWFkLiBJbmRleCBlbnRyaWVzIGRvbid0IHJlZmVyZW5jZSBzbG90cyBhdCBhbGw7IHRoZXkgcGVyc2lzdCB0aGUgc291cmNlcyBsaXN0J3Mgc291cmNlc0xpc3RJbmRleC5cbiAgICBkZWFkPzogYm9vbGVhbjtcbn07XG5cbi8vIE9uZSBzb3VyY2Ugb2YgYSBsaXZlIHNvdXJjZS1saXN0IHVwZGF0ZTsgc2VlIEJsb2JTdG9yZS51cGRhdGVTb3VyY2VzXG5leHBvcnQgdHlwZSBCbG9iU291cmNlU3BlYyA9IHtcbiAgICAvLyBNYXRjaGVkIGFnYWluc3QgQXJjaGl2ZXNTb3VyY2UuaWRlbnRpdHkgKFwiZGlza1wiIGZvciB0aGUgYmFzZSBzbG90KTsgZXF1YWwgaWRlbnRpdGllcyBwYWlyIG9mZiBpbiBvcmRlclxuICAgIGlkZW50aXR5OiBzdHJpbmc7XG4gICAgLy8gU2VlIEFyY2hpdmVzU291cmNlLnVybFxuICAgIHVybDogc3RyaW5nO1xuICAgIHZhbGlkV2luZG93czogW251bWJlciwgbnVtYmVyXVtdO1xuICAgIHJvdXRlPzogW251bWJlciwgbnVtYmVyXTtcbiAgICBub0Z1bGxTeW5jPzogYm9vbGVhbjtcbiAgICAvLyBTZWUgQXJjaGl2ZXNTb3VyY2UuaW50ZXJtZWRpYXRlXG4gICAgaW50ZXJtZWRpYXRlPzogc3RyaW5nO1xuICAgIC8vIFNlZSBBcmNoaXZlc1NvdXJjZS5zb3VyY2VDb25maWcgKGFic2VudCBmb3IgdGhlIGJhc2UgZGlzayBzb3VyY2UpXG4gICAgc291cmNlQ29uZmlnPzogU291cmNlQ29uZmlnO1xuICAgIC8vIE9ubHkgY2FsbGVkIGZvciBzb3VyY2VzIHRoYXQgZG9uJ3QgbWF0Y2ggYW4gZXhpc3RpbmcgbGl2ZSBzbG90XG4gICAgY3JlYXRlOiAoKSA9PiBJQXJjaGl2ZXM7XG59O1xuXG4vLyBXaGF0IGEgc2Nhbm5lZCBsaXN0aW5nIGVudHJ5IG1lYW50IHdoZW4gY29tcGFyZWQgYWdhaW5zdCBvdXIgaW5kZXhcbnR5cGUgU2Nhbk91dGNvbWUgPSBcImZpbHRlcmVkXCIgfCBcIm5ld1wiIHwgXCJ1cGRhdGVkXCIgfCBcInRvbWJzdG9uZVwiIHwgXCJ1bmNoYW5nZWRcIjtcbnR5cGUgU2NhblRhbGx5ID0gUmVjb3JkPFNjYW5PdXRjb21lLCBudW1iZXI+O1xuZnVuY3Rpb24gbmV3U2NhblRhbGx5KCk6IFNjYW5UYWxseSB7XG4gICAgcmV0dXJuIHsgZmlsdGVyZWQ6IDAsIG5ldzogMCwgdXBkYXRlZDogMCwgdG9tYnN0b25lOiAwLCB1bmNoYW5nZWQ6IDAgfTtcbn1cbmZ1bmN0aW9uIGZvcm1hdFNjYW5UYWxseSh0YWxseTogU2NhblRhbGx5LCB0b3RhbDogbnVtYmVyKTogc3RyaW5nIHtcbiAgICBsZXQgcGN0ID0gKG46IG51bWJlcikgPT4gYCR7TWF0aC5yb3VuZChuIC8gTWF0aC5tYXgodG90YWwsIDEpICogMTAwMCkgLyAxMH0lYDtcbiAgICByZXR1cm4gYCR7dGFsbHkubmV3fSBuZXcgcGF0aHMgKCR7cGN0KHRhbGx5Lm5ldyl9KSwgJHt0YWxseS51cGRhdGVkfSBuZXdlciB3cml0ZXMgKCR7cGN0KHRhbGx5LnVwZGF0ZWQpfSksICR7dGFsbHkudG9tYnN0b25lfSBkZWxldGlvbnMgKCR7cGN0KHRhbGx5LnRvbWJzdG9uZSl9KSwgJHt0YWxseS51bmNoYW5nZWR9IHVuY2hhbmdlZCAoJHtwY3QodGFsbHkudW5jaGFuZ2VkKX0pLCAke3RhbGx5LmZpbHRlcmVkfSBvdXRzaWRlIHJvdXRlICgke3BjdCh0YWxseS5maWx0ZXJlZCl9KWA7XG59XG5cbmZ1bmN0aW9uIG5ld1NvdXJjZVN0YXRlKCk6IFNvdXJjZVN0YXRlIHtcbiAgICByZXR1cm4ge1xuICAgICAgICBzdXBwb3J0c0NoYW5nZXNBZnRlcjogZmFsc2UsXG4gICAgICAgIGluaXRpYWxTY2FuOiBwcm9taXNlT2JqKCksXG4gICAgICAgIHNjYW5Db21wbGV0ZTogZmFsc2UsXG4gICAgICAgIHNjYW5uZWRDb3VudDogMCxcbiAgICAgICAgY2hhbmdlc0FmdGVyVGltZTogMCxcbiAgICAgICAgbGFzdE1pc3NDaGVjazogMCxcbiAgICAgICAgc3RvcHBlZDogeyBzdG9wOiBmYWxzZSB9LFxuICAgIH07XG59XG5cbmxldCBsYXN0V3JvbmdUYXJnZXRMb2cgPSAwO1xuZnVuY3Rpb24gbG9nV3JvbmdUYXJnZXRSZWplY3Rpb24obWVzc2FnZTogc3RyaW5nKTogdm9pZCB7XG4gICAgaWYgKERhdGUubm93KCkgLSBsYXN0V3JvbmdUYXJnZXRMb2cgPCBXUk9OR19UQVJHRVRfTE9HX1RIUk9UVExFKSByZXR1cm47XG4gICAgbGFzdFdyb25nVGFyZ2V0TG9nID0gRGF0ZS5ub3coKTtcbiAgICBjb25zb2xlLmxvZyhtZXNzYWdlKTtcbn1cblxuZXhwb3J0IGNsYXNzIEJsb2JTdG9yZSBpbXBsZW1lbnRzIElCdWNrZXRTdG9yZSB7XG4gICAgY29uc3RydWN0b3IoXG4gICAgICAgIHByaXZhdGUgZm9sZGVyOiBzdHJpbmcsXG4gICAgICAgIHByaXZhdGUgc291cmNlczogQXJjaGl2ZXNTb3VyY2VbXSxcbiAgICAgICAgcHJpdmF0ZSBjb25maWc/OiB7XG4gICAgICAgICAgICAvLyBDYWxsZWQgd2hlbmV2ZXIgYSBrZXkncyBpbmRleCBlbnRyeSBjaGFuZ2VzIChvdXIgb3duIHdyaXRlcyBBTkQgZmlsZXMgcHVsbGVkIGluIHZpYSBzeW5jaHJvbml6YXRpb24pIOKAlCBob3cgdGhlIHN0b3JhZ2Ugc2VydmVyIG5vdGljZXMgcm91dGluZyBjb25maWcgdXBkYXRlcy5cbiAgICAgICAgICAgIG9uSW5kZXhDaGFuZ2VkPzogKGtleTogc3RyaW5nKSA9PiB2b2lkO1xuICAgICAgICAgICAgLy8gTFJVLWJvdW5kIHRoZSBkaXNrIChiYXNlIHNvdXJjZSkgdG8gdGhpcyBtYW55IGJ5dGVzOyBzZWUgQ29tbW9uQ29uZmlnLnJlYWRlckRpc2tMaW1pdFxuICAgICAgICAgICAgcmVhZGVyRGlza0xpbWl0PzogbnVtYmVyO1xuICAgICAgICAgICAgLy8gRXZlcnkgYWNjZXB0ZWQgd3JpdGUgKFwib3JpZ2luYWxcIikgYW5kIGV2ZXJ5IHdyaXRlIHRoYXQgYWN0dWFsbHkgcmVhY2hlZCB0aGUgc291cmNlcyAoXCJmbHVzaGVkXCIpLiBGYXN0IHdyaXRlcyBjb2FsZXNjZSwgc28gdGhlIHR3byBjb3VudHMgZGlmZmVyLlxuICAgICAgICAgICAgb25Xcml0ZUNvdW50ZWQ/OiAoa2luZDogXCJvcmlnaW5hbFwiIHwgXCJmbHVzaGVkXCIsIGJ5dGVzOiBudW1iZXIpID0+IHZvaWQ7XG4gICAgICAgICAgICAvLyBSZXNvbHZlcyBhIHBlcnNpc3RlZCBzb3VyY2UgVVJMIChzZWUgQXJjaGl2ZXNTb3VyY2UudXJsKSB0byBhIGNhY2hlZCBJQXJjaGl2ZXMsIHNvIGVudHJpZXMgd2hvc2UgaG9sZGVyIGlzIG5vIGxvbmdlciBjb25maWd1cmVkIGNhbiBzdGlsbCBiZSByZWFkXG4gICAgICAgICAgICByZXNvbHZlU291cmNlVXJsPzogKHVybDogc3RyaW5nKSA9PiBJQXJjaGl2ZXM7XG4gICAgICAgICAgICAvLyBUaGlzIHN0b3JlJ3Mgb3duIGVudHJpZXMgaW4gdGhlIHJvdXRpbmcgY29uZmlnIChhbGwgdGhlIHNhbWUgcm91dGUsIGRpZmZlcmVudCB2YWxpZCB3aW5kb3dzKS4gV2hhdCBzZXQvZGVsIHZhbGlkYXRlIGFnYWluc3Q6IHZhbGlkIHdpbmRvd3MgYW5kIHJvdXRlcyBmb3IgZnJlc2ggd3JpdGVzLCBpbW11dGFiaWxpdHksIGludGVybmFsLXB1c2ggYWNjZXB0YW5jZSwgYW5kIHRoZSBmYXN0L3dyaXRlRGVsYXkgZmxhZ3MuIEVtcHR5ID0gbm8gdmFsaWRhdGlvbiAoYSBzdG9yZSBzZXJ2aW5nIGxlZnRvdmVyIGRpc2sgZGF0YSB3aXRoIG5vIGNvbmZpZykuXG4gICAgICAgICAgICBlbnRyaWVzPzogSG9zdGVkQ29uZmlnW107XG4gICAgICAgIH1cbiAgICApIHsgfVxuXG4gICAgLy8gI3JlZ2lvbiBNYWluIGludGVyZmFjZVxuXG4gICAgcHVibGljIGluaXQgPSBsYXp5KGFzeW5jICgpID0+IHtcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLnNvdXJjZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIGF3YWl0IHRoaXMucmVnaXN0ZXJTbG90KGkpO1xuICAgICAgICB9XG4gICAgICAgIGF3YWl0IHRoaXMubG9hZEluZGV4KCk7XG4gICAgICAgIHRoaXMuc3luY1N0YXJ0ZWQgPSB0cnVlO1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMuc291cmNlcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgaWYgKCF0aGlzLmlzTGl2ZShpKSkgY29udGludWU7XG4gICAgICAgICAgICB2b2lkIHRoaXMucnVuU291cmNlU3luYyhpKTtcbiAgICAgICAgfVxuICAgICAgICBydW5JbmZpbml0ZVBvbGwoRkFTVF9GTFVTSF9QT0xMLCAoKSA9PiB0aGlzLmZsdXNoT3ZlcmxheSgpLCB0aGlzLnN0b3BwZWQpO1xuICAgICAgICBydW5JbmZpbml0ZVBvbGwoSU5ERVhfRkxVU0hfSU5URVJWQUwsICgpID0+IHRoaXMuZmx1c2hJbmRleCgpLCB0aGlzLnN0b3BwZWQpO1xuICAgICAgICBydW5JbmZpbml0ZVBvbGwoVE9NQlNUT05FX0NMRUFOVVBfSU5URVJWQUwsICgpID0+IHRoaXMuY2xlYW51cFRvbWJzdG9uZXMoKSwgdGhpcy5zdG9wcGVkKTtcbiAgICAgICAgaWYgKHRoaXMuY29uZmlnPy5yZWFkZXJEaXNrTGltaXQpIHtcbiAgICAgICAgICAgIHJ1bkluZmluaXRlUG9sbChESVNLX0xJTUlUX0NIRUNLX0lOVEVSVkFMLCAoKSA9PiB0aGlzLmVuZm9yY2VEaXNrTGltaXQoKSwgdGhpcy5zdG9wcGVkKTtcbiAgICAgICAgfVxuICAgIH0pO1xuXG4gICAgLy8gU3RvcHMgYWxsIHN5bmNocm9uaXphdGlvbiBzY2Fucy9wb2xscyBhbmQgZmx1c2hlcyBwZW5kaW5nIHdyaXRlcy4gT25seSB1c2VkIHdoZW4gdGhlIHN0b3JlIGdlbnVpbmVseSBjYW5ub3QgY29udGludWUgKHJhd0Rpc2sgZmxpcCwgcHJvY2VzcyBzaHV0ZG93bikgLSByb3V0aW5lIGNvbmZpZyBjaGFuZ2VzIGdvIHRocm91Z2ggdXBkYXRlU291cmNlcyBpbnN0ZWFkLCB3aGljaCB0aGUgc3RvcmUgc3Vydml2ZXMuXG4gICAgcHVibGljIGFzeW5jIGRpc3Bvc2UoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIHRoaXMuc3RvcHBlZC5zdG9wID0gdHJ1ZTtcbiAgICAgICAgZm9yIChsZXQgc3RhdGUgb2YgdGhpcy5zb3VyY2VTdGF0ZXMpIHtcbiAgICAgICAgICAgIHN0YXRlLnN0b3BwZWQuc3RvcCA9IHRydWU7XG4gICAgICAgIH1cbiAgICAgICAgYXdhaXQgdGhpcy5mbHVzaE92ZXJsYXkodHJ1ZSk7XG4gICAgICAgIGF3YWl0IHRoaXMuZmx1c2hJbmRleCgpO1xuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyBnZXQyKGNvbmZpZzogeyBwYXRoOiBzdHJpbmc7IHJhbmdlPzogeyBzdGFydDogbnVtYmVyOyBlbmQ6IG51bWJlciB9OyBpbnRlcm5hbD86IGJvb2xlYW47IGluY2x1ZGVUb21ic3RvbmVzPzogYm9vbGVhbiB9KTogUHJvbWlzZTx7IGRhdGE6IEJ1ZmZlcjsgd3JpdGVUaW1lOiBudW1iZXI7IHNpemU6IG51bWJlciB9IHwgdW5kZWZpbmVkPiB7XG4gICAgICAgIGlmIChjb25maWcuaW50ZXJuYWwpIHtcbiAgICAgICAgICAgIHJldHVybiBhd2FpdCB0aGlzLmdldEludGVybmFsMihjb25maWcpO1xuICAgICAgICB9XG4gICAgICAgIGF3YWl0IHRoaXMuaW5pdCgpO1xuICAgICAgICBsZXQga2V5ID0gY29uZmlnLnBhdGg7XG4gICAgICAgIGxldCByYW5nZSA9IGNvbmZpZy5yYW5nZTtcbiAgICAgICAgbGV0IG92ZXJsYXlFbnRyeSA9IHRoaXMub3ZlcmxheS5nZXQoa2V5KTtcbiAgICAgICAgaWYgKG92ZXJsYXlFbnRyeSkge1xuICAgICAgICAgICAgLy8gQW4gZW1wdHkgZmlsZSBJUyBhIG1pc3NpbmcgZmlsZSAodG9tYnN0b25lKVxuICAgICAgICAgICAgaWYgKG92ZXJsYXlFbnRyeS5kYXRhLmxlbmd0aCA9PT0gMCAmJiAhY29uZmlnLmluY2x1ZGVUb21ic3RvbmVzKSByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICAgICAgbGV0IGRhdGEgPSBvdmVybGF5RW50cnkuZGF0YTtcbiAgICAgICAgICAgIGxldCBzaXplID0gZGF0YS5sZW5ndGg7XG4gICAgICAgICAgICBpZiAocmFuZ2UpIHtcbiAgICAgICAgICAgICAgICBkYXRhID0gZGF0YS5zdWJhcnJheShNYXRoLm1pbihyYW5nZS5zdGFydCwgZGF0YS5sZW5ndGgpLCBNYXRoLm1pbihyYW5nZS5lbmQsIGRhdGEubGVuZ3RoKSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4geyBkYXRhLCB3cml0ZVRpbWU6IG92ZXJsYXlFbnRyeS50LCBzaXplIH07XG4gICAgICAgIH1cbiAgICAgICAgbGV0IGVudHJ5ID0gYXdhaXQgdGhpcy5nZXRJbmRleEVudHJ5KGtleSk7XG4gICAgICAgIGlmICghZW50cnkpIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgIGlmIChlbnRyeS5zaXplID09PSAwKSB7XG4gICAgICAgICAgICBpZiAoIWNvbmZpZy5pbmNsdWRlVG9tYnN0b25lcykgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgICAgIC8vIEEgdG9tYnN0b25lIGhhcyBubyBzdG9yZWQgYnl0ZXMgLSB0aGUgaW5kZXggZW50cnkgYWxvbmUgaXMgdGhlIGRlbGV0aW9uLCBzbyB0aGUgZmxhZy1jYWxsZXIgZ2V0cyBpdHMgd3JpdGUgdGltZSB3aXRoIGVtcHR5IGRhdGFcbiAgICAgICAgICAgIHJldHVybiB7IGRhdGE6IEJ1ZmZlci5hbGxvYygwKSwgd3JpdGVUaW1lOiBlbnRyeS53cml0ZVRpbWUsIHNpemU6IDAgfTtcbiAgICAgICAgfVxuICAgICAgICBlbnRyeS5sYXN0QWNjZXNzID0gRGF0ZS5ub3coKTtcbiAgICAgICAgbGV0IGhvbGRlckFyY2hpdmVzID0gYXdhaXQgdGhpcy5nZXRFbnRyeUhvbGRlcihlbnRyeSk7XG4gICAgICAgIGxldCByZXN1bHQ6IHsgZGF0YTogQnVmZmVyOyB3cml0ZVRpbWU6IG51bWJlcjsgc2l6ZTogbnVtYmVyIH0gfCB1bmRlZmluZWQ7XG4gICAgICAgIGxldCBob2xkZXJFcnJvcjogRXJyb3IgfCB1bmRlZmluZWQ7XG4gICAgICAgIGlmIChob2xkZXJBcmNoaXZlcykge1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICAvLyBpbmNsdWRlVG9tYnN0b25lczogdGhlIGhvbGRlciBhbnN3ZXJpbmcgXCJkZWxldGVkXCIgKGEgdG9tYnN0b25lLCB3aXRoIGl0cyB3cml0ZSB0aW1lKSBtdXN0IGJlIGRpc3Rpbmd1aXNoYWJsZSBmcm9tIFwiSSBsb3N0IHRoZSBmaWxlXCIgLSB0aGUgZm9ybWVyIGlzIGF1dGhvcml0YXRpdmUgYW5kIG11c3QgTk9UIGZhbGwgYmFjayB0byBvbGRlciBjb3BpZXMsIHdoaWNoIHdvdWxkIHJlc3VycmVjdCB0aGUgZGVsZXRpb24gZm9yIHRoaXMgcmVhZFxuICAgICAgICAgICAgICAgIGxldCBhbnN3ZXIgPSBhd2FpdCBob2xkZXJBcmNoaXZlcy5nZXQyKGtleSwgeyByYW5nZSwgaW50ZXJuYWw6IHRydWUsIGluY2x1ZGVUb21ic3RvbmVzOiB0cnVlIH0pO1xuICAgICAgICAgICAgICAgIGlmIChhbnN3ZXIgJiYgYW5zd2VyLmRhdGEgJiYgIWFuc3dlci5kYXRhLmxlbmd0aCAmJiAhKHJhbmdlICYmIGFuc3dlci5zaXplKSAmJiBhbnN3ZXIud3JpdGVUaW1lID49IGVudHJ5LndyaXRlVGltZSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAvLyBOT1RFOiBhIHJhbmdlZCByZWFkIG9mIGEgcmVhbCBmaWxlIGNhbiBsZWdpdGltYXRlbHkgYmUgZW1wdHkgKHJhbmdlIHBhc3QgRU9GKSwgc28gb25seSB1bnJhbmdlZCBlbXB0aW5lc3MgbWVhbnMgdG9tYnN0b25lL2Fic2VudFxuICAgICAgICAgICAgICAgIGlmIChhbnN3ZXIgJiYgYW5zd2VyLmRhdGEgJiYgKGFuc3dlci5kYXRhLmxlbmd0aCB8fCByYW5nZSAmJiBhbnN3ZXIuc2l6ZSkpIHtcbiAgICAgICAgICAgICAgICAgICAgcmVzdWx0ID0geyBkYXRhOiBhbnN3ZXIuZGF0YSwgd3JpdGVUaW1lOiBhbnN3ZXIud3JpdGVUaW1lLCBzaXplOiBhbnN3ZXIuc2l6ZSB9O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgICAgICBob2xkZXJFcnJvciA9IGUgYXMgRXJyb3I7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHJlc3VsdCkge1xuICAgICAgICAgICAgLy8gUmFuZ2VkIHJlYWRzIGNhbid0IHBvcHVsYXRlIGEgY2FjaGUgKHRoZXkncmUgcGFydGlhbClcbiAgICAgICAgICAgIGlmICh0aGlzLnNsb3RGb3JTb3VyY2VzTGlzdEluZGV4KGVudHJ5LnNvdXJjZXNMaXN0SW5kZXgpICE9PSAwICYmICFyYW5nZSkge1xuICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMuY2FjaGVSZWFkKGtleSwgcmVzdWx0KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICAgIH1cbiAgICAgICAgLy8gVGhlIHJvdXRpbmcgZmlsZSBpcyBvbmx5IGV2ZXIgcmVhZCBvZmYgb3VyIG93biBkaXNrIC0gZmFsbGluZyBiYWNrIHRvIGFub3RoZXIgc291cmNlJ3MgY29weSB3b3VsZCBzeW5jaHJvbml6ZSBpdCBiZXR3ZWVuIG5vZGVzIHRocm91Z2ggdGhlIHJlYWQgcGF0aCwgd2hpY2ggaXQgbmV2ZXIgaXNcbiAgICAgICAgaWYgKGtleSA9PT0gUk9VVElOR19GSUxFKSB7XG4gICAgICAgICAgICBpZiAoaG9sZGVyRXJyb3IpIHRocm93IGhvbGRlckVycm9yO1xuICAgICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgfVxuICAgICAgICAvLyBUaGUgaG9sZGVyIGlzIGRvd24gb3IgbG9zdCB0aGUgZmlsZS4gQU5ZIG90aGVyIHNvdXJjZSdzIGNvcHkgYmVhdHMgbm8gdmFsdWUgLSBldmVuIGFuIE9MREVSIG9uZSAtIGFuZCBpdCdzIGNvcGllZCBvbnRvIG91ciBkaXNrIHNvIHRoZSBuZXh0IHJlYWQgZG9lc24ndCBkZXBlbmQgb24gbHVjay5cbiAgICAgICAgbGV0IGhvbGRlclNsb3QgPSB0aGlzLnNsb3RGb3JTb3VyY2VzTGlzdEluZGV4KGVudHJ5LnNvdXJjZXNMaXN0SW5kZXgpO1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMuc291cmNlcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgaWYgKGkgPT09IGhvbGRlclNsb3QgfHwgIXRoaXMuaXNMaXZlKGkpKSBjb250aW51ZTtcbiAgICAgICAgICAgIGxldCBmYWxsYmFjazogeyBkYXRhOiBCdWZmZXI7IHdyaXRlVGltZTogbnVtYmVyOyBzaXplOiBudW1iZXIgfSB8IHVuZGVmaW5lZDtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgbGV0IGFuc3dlciA9IGF3YWl0IHRoaXMuc291cmNlc1tpXS5zb3VyY2UuZ2V0MihrZXksIHsgaW50ZXJuYWw6IHRydWUgfSk7XG4gICAgICAgICAgICAgICAgLy8gRW1wdHkgZGF0YSBjb3VudHMgYXMgYWJzZW50IC0gYSB0b21ic3RvbmUsIG5vdCBjb250ZW50ICh0aGlzIHJlYWQgaXMgdW5yYW5nZWQsIHNvIGVtcHRpbmVzcyBpcyB1bmFtYmlndW91cylcbiAgICAgICAgICAgICAgICBpZiAoYW5zd2VyICYmIGFuc3dlci5kYXRhICYmIGFuc3dlci5kYXRhLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgICAgICBmYWxsYmFjayA9IHsgZGF0YTogYW5zd2VyLmRhdGEsIHdyaXRlVGltZTogYW5zd2VyLndyaXRlVGltZSwgc2l6ZTogYW5zd2VyLnNpemUgfTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGNhdGNoIHtcbiAgICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICghZmFsbGJhY2spIGNvbnRpbnVlO1xuICAgICAgICAgICAgYXdhaXQgdGhpcy5jYWNoZVJlYWQoa2V5LCBmYWxsYmFjayk7XG4gICAgICAgICAgICBsZXQgZGF0YSA9IGZhbGxiYWNrLmRhdGE7XG4gICAgICAgICAgICBpZiAocmFuZ2UpIHtcbiAgICAgICAgICAgICAgICBkYXRhID0gZGF0YS5zdWJhcnJheShNYXRoLm1pbihyYW5nZS5zdGFydCwgZGF0YS5sZW5ndGgpLCBNYXRoLm1pbihyYW5nZS5lbmQsIGRhdGEubGVuZ3RoKSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4geyBkYXRhLCB3cml0ZVRpbWU6IGZhbGxiYWNrLndyaXRlVGltZSwgc2l6ZTogZmFsbGJhY2suc2l6ZSB9O1xuICAgICAgICB9XG4gICAgICAgIGlmIChob2xkZXJFcnJvcikgdGhyb3cgaG9sZGVyRXJyb3I7XG4gICAgICAgIC8vIFRoZSBob2xkZXIgYW5zd2VyZWQgXCJub3QgdGhlcmVcIiBhbmQgbm8gb3RoZXIgc291cmNlIGhhcyBpdCBlaXRoZXI6IHRoZSBlbnRyeSB3YXMgc3RhbGVcbiAgICAgICAgdGhpcy5kZWxldGVJbmRleEVudHJ5KGtleSk7XG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIHNldChjb25maWc6IHsgcGF0aDogc3RyaW5nOyBkYXRhOiBCdWZmZXI7IGxhc3RNb2RpZmllZD86IG51bWJlcjsgZm9yY2VTZXRJbW11dGFibGU/OiBib29sZWFuOyBpbnRlcm5hbD86IGJvb2xlYW4gfSk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBsZXQgeyBwYXRoOiBrZXksIGRhdGEgfSA9IGNvbmZpZztcbiAgICAgICAgaWYgKCFkYXRhLmxlbmd0aCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBzZXQgd2FzIGNhbGxlZCB3aXRoIGFuIGVtcHR5IGJ1ZmZlciBmb3IgJHtKU09OLnN0cmluZ2lmeShrZXkpfSAoc3RvcmUgJHt0aGlzLmZvbGRlcn0pOiBhbiBlbXB0eSBmaWxlIElTIGEgZGVsZXRpb24gaW4gdGhpcyBzeXN0ZW0gYW5kIHdvdWxkIHJlYWQgYmFjayBhcyBtaXNzaW5nIC0gY2FsbCBkZWwgaW5zdGVhZGApO1xuICAgICAgICB9XG4gICAgICAgIGF3YWl0IHRoaXMuaW5pdCgpO1xuICAgICAgICBsZXQgd3JpdGVUaW1lID0gY29uZmlnLmxhc3RNb2RpZmllZCB8fCBEYXRlLm5vdygpO1xuICAgICAgICBsZXQgcm91dGUgPSBnZXRSb3V0ZShrZXkpO1xuICAgICAgICAvLyBUaGUgcm91dGluZyBmaWxlIGRlZmluZXMgdGhlIHdpbmRvd3Mvcm91dGVzLCBzbyB0aGV5IGNhbid0IHBvc3NpYmx5IGFwcGx5IHRvIGl0IChhbmQgaXQgbmV2ZXIgZmxvd3MgdGhyb3VnaCB2YWxpZGF0aW9uKVxuICAgICAgICBpZiAoa2V5ICE9PSBST1VUSU5HX0ZJTEUgJiYgdGhpcy5lbnRyaWVzLmxlbmd0aCkge1xuICAgICAgICAgICAgaWYgKCFjb25maWcubGFzdE1vZGlmaWVkKSB7XG4gICAgICAgICAgICAgICAgbGV0IHRpbWVWYWxpZCA9IHRoaXMuZW50cmllcy5maWx0ZXIoeCA9PiB3cml0ZVRpbWUgPj0geC52YWxpZFdpbmRvd1swXSAmJiB3cml0ZVRpbWUgPCB4LnZhbGlkV2luZG93WzFdKTtcbiAgICAgICAgICAgICAgICBpZiAoIXRpbWVWYWxpZC5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICAgICAgbG9nV3JvbmdUYXJnZXRSZWplY3Rpb24oYFJlamVjdGluZyBmcmVzaCB3cml0ZSBvZiAke0pTT04uc3RyaW5naWZ5KGtleSl9IChzdG9yZSAke3RoaXMuZm9sZGVyfSk6IHdyaXRlVGltZSAke3dyaXRlVGltZX0gKCR7bmV3IERhdGUod3JpdGVUaW1lKS50b0lTT1N0cmluZygpfSkgaXMgb3V0c2lkZSBhbGwgb3VyIHZhbGlkIHdpbmRvd3MgJHtKU09OLnN0cmluZ2lmeSh0aGlzLmVudHJpZXMubWFwKHggPT4geC52YWxpZFdpbmRvdykpfSAoYSBzd2l0Y2hvdmVyIG1vdmVkIHRoZSB3cml0ZSB0YXJnZXQpYCk7XG4gICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgJHtTVE9SQUdFX1dST05HX1ZBTElEX1dJTkRPV30gVGhpcyBzdG9yZSBpcyBub3QgYSB2YWxpZCB3cml0ZSB0YXJnZXQgYXQgJHt3cml0ZVRpbWV9IChvdXIgdmFsaWQgd2luZG93czogJHtKU09OLnN0cmluZ2lmeSh0aGlzLmVudHJpZXMubWFwKHggPT4geC52YWxpZFdpbmRvdykpfSwgc3RvcmUgJHt0aGlzLmZvbGRlcn0pLiBSZS1yZXNvbHZlIHRoZSBjdXJyZW50bHkgdmFsaWQgc291cmNlIGFuZCByZXRyeS5gKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKCF0aW1lVmFsaWQuc29tZSh4ID0+IHJvdXRlQ29udGFpbnMoeC5yb3V0ZSwgcm91dGUpKSkge1xuICAgICAgICAgICAgICAgICAgICBsb2dXcm9uZ1RhcmdldFJlamVjdGlvbihgUmVqZWN0aW5nIGZyZXNoIHdyaXRlIG9mICR7SlNPTi5zdHJpbmdpZnkoa2V5KX0gKHN0b3JlICR7dGhpcy5mb2xkZXJ9KTogcm91dGUgJHtyb3V0ZX0gaXMgb3V0c2lkZSBvdXIgcm91dGVzICR7SlNPTi5zdHJpbmdpZnkodGltZVZhbGlkLm1hcCh4ID0+IHgucm91dGUgfHwgRlVMTF9ST1VURSkpfSBhdCB3cml0ZVRpbWUgJHt3cml0ZVRpbWV9ICh0aGUgY2xpZW50J3Mgc2hhcmQgY29uZmlnIGlzIHN0YWxlKWApO1xuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYCR7U1RPUkFHRV9XUk9OR19ST1VURX0gVGhpcyBzdG9yZSBkb2VzIG5vdCBoYW5kbGUgcm91dGUgJHtyb3V0ZX0gKGtleSAke0pTT04uc3RyaW5naWZ5KGtleSl9LCBvdXIgcm91dGVzIGF0IHRoaXMgdGltZTogJHtKU09OLnN0cmluZ2lmeSh0aW1lVmFsaWQubWFwKHggPT4geC5yb3V0ZSB8fCBGVUxMX1JPVVRFKSl9LCBzdG9yZSAke3RoaXMuZm9sZGVyfSkuIFJlLXJlc29sdmUgdGhlIHNvdXJjZSBmb3IgdGhpcyBrZXkgYW5kIHJldHJ5LmApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChjb25maWcuZm9yY2VTZXRJbW11dGFibGUpIHtcbiAgICAgICAgICAgICAgICBpZiAoIWNvbmZpZy5sYXN0TW9kaWZpZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBmb3JjZVNldEltbXV0YWJsZSByZXF1aXJlcyBsYXN0TW9kaWZpZWQgKHN5bmNocm9uaXphdGlvbiB3cml0ZXMgYXJlIG9yZGVyZWQgYnkgdGhlaXIgd3JpdGUgdGltZSksIHdyaXRpbmcgJHtKU09OLnN0cmluZ2lmeShrZXkpfSAoc3RvcmUgJHt0aGlzLmZvbGRlcn0pYCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIC8vIEltbXV0YWJpbGl0eSB3aW5zOiBhbiBleGlzdGluZyBwYXRoIGlzIGtlcHQgaW5zdGVhZCBvZiB0aGUgcHVzaCB0aHJvd2luZyAoc2VlIFNldENvbmZpZy5mb3JjZVNldEltbXV0YWJsZSlcbiAgICAgICAgICAgICAgICBsZXQgc2VsZiA9IHNlbGVjdEVudHJ5QXQodGhpcy5lbnRyaWVzLCB3cml0ZVRpbWUsIHJvdXRlKTtcbiAgICAgICAgICAgICAgICBpZiAoc2VsZj8uaW1tdXRhYmxlICYmIGF3YWl0IHRoaXMuZ2V0SW5mbyh7IHBhdGg6IGtleSB9KSkgcmV0dXJuO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLmFzc2VydE11dGFibGUoa2V5LCB3cml0ZVRpbWUpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGlmIChjb25maWcuaW50ZXJuYWwpIHtcbiAgICAgICAgICAgIGlmICghY29uZmlnLmxhc3RNb2RpZmllZCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgSW50ZXJuYWwgd3JpdGVzIG11c3QgY2FycnkgbGFzdE1vZGlmaWVkICh0aGV5IGFyZSBzeW5jaHJvbml6YXRpb24gcHVzaGVzLCBvcmRlcmVkIGJ5IHRoZWlyIHdyaXRlIHRpbWUpLCB3cml0aW5nICR7SlNPTi5zdHJpbmdpZnkoa2V5KX0gKHN0b3JlICR7dGhpcy5mb2xkZXJ9KWApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhpcy5hc3NlcnRJbnRlcm5hbFdyaXRlQWNjZXB0ZWQoa2V5LCBjb25maWcubGFzdE1vZGlmaWVkLCByb3V0ZSk7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLnNldEludGVybmFsKGtleSwgZGF0YSwgeyBsYXN0TW9kaWZpZWQ6IGNvbmZpZy5sYXN0TW9kaWZpZWQgfSk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgbGV0IHNlbGYgPSB0aGlzLmVudHJpZXMubGVuZ3RoICYmIHNlbGVjdEVudHJ5QXQodGhpcy5lbnRyaWVzLCB3cml0ZVRpbWUsIHJvdXRlKSB8fCB1bmRlZmluZWQ7XG4gICAgICAgIGF3YWl0IHRoaXMuc2V0T3JEZWxldGUoa2V5LCBkYXRhLCB7IGZhc3Q6IHNlbGY/LmZhc3QsIHdyaXRlRGVsYXk6IHNlbGY/LndyaXRlRGVsYXksIGxhc3RNb2RpZmllZDogY29uZmlnLmxhc3RNb2RpZmllZCB9KTtcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgZGVsKGNvbmZpZzogeyBwYXRoOiBzdHJpbmc7IGxhc3RNb2RpZmllZD86IG51bWJlcjsgaW50ZXJuYWw/OiBib29sZWFuIH0pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgbGV0IGtleSA9IGNvbmZpZy5wYXRoO1xuICAgICAgICBpZiAoa2V5ID09PSBST1VUSU5HX0ZJTEUpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgVGhlIHJvdXRpbmcgY29uZmlnICR7SlNPTi5zdHJpbmdpZnkoUk9VVElOR19GSUxFKX0gY2Fubm90IGJlIGRlbGV0ZWQgKG92ZXJ3cml0ZSBpdCB0byBjaGFuZ2UgdGhlIGJ1Y2tldCdzIGNvbmZpZ3VyYXRpb24pYCk7XG4gICAgICAgIH1cbiAgICAgICAgYXdhaXQgdGhpcy5pbml0KCk7XG4gICAgICAgIGlmIChjb25maWcuaW50ZXJuYWwpIHtcbiAgICAgICAgICAgIGlmICghY29uZmlnLmxhc3RNb2RpZmllZCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgSW50ZXJuYWwgZGVsZXRpb25zIG11c3QgY2FycnkgbGFzdE1vZGlmaWVkICh0aGV5IGFyZSBzeW5jaHJvbml6YXRpb24gcHVzaGVzLCBvcmRlcmVkIGJ5IHRoZWlyIHdyaXRlIHRpbWUpLCBkZWxldGluZyAke0pTT04uc3RyaW5naWZ5KGtleSl9IChzdG9yZSAke3RoaXMuZm9sZGVyfSlgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRoaXMuYXNzZXJ0SW50ZXJuYWxXcml0ZUFjY2VwdGVkKGtleSwgY29uZmlnLmxhc3RNb2RpZmllZCwgZ2V0Um91dGUoa2V5KSk7XG4gICAgICAgICAgICAvLyBzZXRJbnRlcm5hbCB0cmVhdHMgYW4gZW1wdHkgYnVmZmVyIGFzIGV4YWN0bHkgYSBkZWxldGlvbjogZGlzayByZW1vdmFsIHBsdXMgYSB0b21ic3RvbmUgaW5kZXggZW50cnksIG5vIGZhbi1vdXRcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuc2V0SW50ZXJuYWwoa2V5LCBCdWZmZXIuYWxsb2MoMCksIHsgbGFzdE1vZGlmaWVkOiBjb25maWcubGFzdE1vZGlmaWVkIH0pO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIC8vIERlbGV0ZXMgYXJlIHRvbWJzdG9uZSB3cml0ZXMgKGFuIGVtcHR5IGZpbGUgSVMgYSBtaXNzaW5nIGZpbGUpOiB0aGUgc2l6ZS0wIGluZGV4IGVudHJ5IGlzIG9yZGVyZWQgYnkgd3JpdGUgdGltZSBsaWtlIGFueSBvdGhlciB3cml0ZSwgcHJvcGFnYXRlcyB0aHJvdWdoIHN5bmNocm9uaXphdGlvbiwgYW5kIGV4cGlyZXMgYWZ0ZXIgVE9NQlNUT05FX0VYUElSWVxuICAgICAgICBsZXQgd3JpdGVUaW1lID0gY29uZmlnLmxhc3RNb2RpZmllZCB8fCBEYXRlLm5vdygpO1xuICAgICAgICBsZXQgc2VsZiA9IHRoaXMuZW50cmllcy5sZW5ndGggJiYgc2VsZWN0RW50cnlBdCh0aGlzLmVudHJpZXMsIHdyaXRlVGltZSwgZ2V0Um91dGUoa2V5KSkgfHwgdW5kZWZpbmVkO1xuICAgICAgICBhd2FpdCB0aGlzLnNldE9yRGVsZXRlKGtleSwgQnVmZmVyLmFsbG9jKDApLCB7IGZhc3Q6IHNlbGY/LmZhc3QsIHdyaXRlRGVsYXk6IHNlbGY/LndyaXRlRGVsYXksIGxhc3RNb2RpZmllZDogY29uZmlnLmxhc3RNb2RpZmllZCB9KTtcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgZ2V0SW5mbyhjb25maWc6IHsgcGF0aDogc3RyaW5nOyBpbmNsdWRlVG9tYnN0b25lcz86IGJvb2xlYW4gfSk6IFByb21pc2U8eyB3cml0ZVRpbWU6IG51bWJlcjsgc2l6ZTogbnVtYmVyIH0gfCB1bmRlZmluZWQ+IHtcbiAgICAgICAgYXdhaXQgdGhpcy5pbml0KCk7XG4gICAgICAgIGxldCBrZXkgPSBjb25maWcucGF0aDtcbiAgICAgICAgbGV0IG92ZXJsYXlFbnRyeSA9IHRoaXMub3ZlcmxheS5nZXQoa2V5KTtcbiAgICAgICAgaWYgKG92ZXJsYXlFbnRyeSkge1xuICAgICAgICAgICAgaWYgKCFvdmVybGF5RW50cnkuZGF0YS5sZW5ndGggJiYgIWNvbmZpZy5pbmNsdWRlVG9tYnN0b25lcykgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgICAgIHJldHVybiB7IHdyaXRlVGltZTogb3ZlcmxheUVudHJ5LnQsIHNpemU6IG92ZXJsYXlFbnRyeS5kYXRhLmxlbmd0aCB9O1xuICAgICAgICB9XG4gICAgICAgIGxldCBlbnRyeSA9IGF3YWl0IHRoaXMuZ2V0SW5kZXhFbnRyeShrZXkpO1xuICAgICAgICBpZiAoIWVudHJ5KSByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICBpZiAoIWVudHJ5LnNpemUgJiYgIWNvbmZpZy5pbmNsdWRlVG9tYnN0b25lcykgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgcmV0dXJuIHsgd3JpdGVUaW1lOiBlbnRyeS53cml0ZVRpbWUsIHNpemU6IGVudHJ5LnNpemUgfTtcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgZmluZEluZm8oY29uZmlnOiBGaW5kQ29uZmlnICYgeyBwcmVmaXg6IHN0cmluZyB9KTogUHJvbWlzZTxBcmNoaXZlRmlsZUluZm9bXT4ge1xuICAgICAgICBhd2FpdCB0aGlzLmluaXQoKTtcbiAgICAgICAgYXdhaXQgdGhpcy53YWl0Rm9yUmVxdWlyZWRTY2FucygpO1xuICAgICAgICBsZXQgcHJlZml4ID0gY29uZmlnLnByZWZpeDtcbiAgICAgICAgbGV0IGluZm9zID0gbmV3IE1hcDxzdHJpbmcsIEFyY2hpdmVGaWxlSW5mbz4oKTtcbiAgICAgICAgZm9yIChsZXQgW2tleSwgZW50cnldIG9mIHRoaXMubWVtKSB7XG4gICAgICAgICAgICBpZiAoIWtleS5zdGFydHNXaXRoKHByZWZpeCkpIGNvbnRpbnVlO1xuICAgICAgICAgICAgLy8gVG9tYnN0b25lcyBhcmUgbWlzc2luZyBmaWxlcywgc28gbGlzdGluZ3MgaGlkZSB0aGVtXG4gICAgICAgICAgICBpZiAoZW50cnkuc2l6ZSA9PT0gMCkgY29udGludWU7XG4gICAgICAgICAgICBpbmZvcy5zZXQoa2V5LCB7IHBhdGg6IGtleSwgY3JlYXRlVGltZTogZW50cnkud3JpdGVUaW1lLCBzaXplOiBlbnRyeS5zaXplIH0pO1xuICAgICAgICB9XG4gICAgICAgIGZvciAobGV0IFtrZXksIG92ZXJsYXlFbnRyeV0gb2YgdGhpcy5vdmVybGF5KSB7XG4gICAgICAgICAgICBpZiAoIWtleS5zdGFydHNXaXRoKHByZWZpeCkpIGNvbnRpbnVlO1xuICAgICAgICAgICAgaWYgKG92ZXJsYXlFbnRyeS5kYXRhLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgICAgIGluZm9zLmRlbGV0ZShrZXkpO1xuICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaW5mb3Muc2V0KGtleSwgeyBwYXRoOiBrZXksIGNyZWF0ZVRpbWU6IG92ZXJsYXlFbnRyeS50LCBzaXplOiBvdmVybGF5RW50cnkuZGF0YS5sZW5ndGggfSk7XG4gICAgICAgIH1cbiAgICAgICAgbGV0IGZpbGVzID0gYXBwbHlGaW5kSW5mb1NoYXBlKEFycmF5LmZyb20oaW5mb3MudmFsdWVzKCkpLCBwcmVmaXgsIHsgc2hhbGxvdzogY29uZmlnLnNoYWxsb3csIHR5cGU6IGNvbmZpZy50eXBlIH0pO1xuICAgICAgICBzb3J0KGZpbGVzLCB4ID0+IHgucGF0aCk7XG4gICAgICAgIHJldHVybiBmaWxlcztcbiAgICB9XG5cbiAgICAvLyBBbGwgZmlsZXMgY2hhbmdlZCBhZnRlciBjb25maWcudGltZSDigJQgZmFzdCwgc3RyYWlnaHQgZnJvbSB0aGUgaW4tbWVtb3J5IGluZGV4LiBGaWx0ZXJzIG9uIHdoZW4gV0UgbGVhcm5lZCBvZiB0aGUgY2hhbmdlIChjaGFuZ2VkQXQpLCBzbyBmaWxlcyBzeW5jaHJvbml6ZWQgbGF0ZSAod2l0aCBvbGQgd3JpdGUgdGltZXMpIGFyZSBzdGlsbCByZXBvcnRlZC4gRGVsZXRpb25zIEFSRSByZXBvcnRlZCwgYXMgc2l6ZS0wIHRvbWJzdG9uZSBlbnRyaWVzIOKAlCB0aGF0J3MgaG93IHRoZXkgcHJvcGFnYXRlIHRvIHN0b3JlcyBzeW5jaW5nIGZyb20gdXMuIGNvbmZpZy5yb3V0ZXMgbGV0cyBhIHN0b3JlIHN5bmNpbmcgYSBwYXJ0aWFsIHNoYXJkIGFzayBmb3IganVzdCBpdHMgc2xpY2UuXG4gICAgcHVibGljIGFzeW5jIGdldENoYW5nZXNBZnRlcjIoY29uZmlnOiBDaGFuZ2VzQWZ0ZXJDb25maWcpOiBQcm9taXNlPEFyY2hpdmVGaWxlSW5mb1tdPiB7XG4gICAgICAgIGF3YWl0IHRoaXMuaW5pdCgpO1xuICAgICAgICBhd2FpdCB0aGlzLndhaXRGb3JSZXF1aXJlZFNjYW5zKCk7XG4gICAgICAgIGxldCBpblJvdXRlcyA9IChrZXk6IHN0cmluZykgPT4gIWNvbmZpZy5yb3V0ZXMgfHwgY29uZmlnLnJvdXRlcy5zb21lKHJvdXRlID0+IHJvdXRlQ29udGFpbnMocm91dGUsIGdldFJvdXRlKGtleSkpKTtcbiAgICAgICAgbGV0IGZpbGVzOiBBcmNoaXZlRmlsZUluZm9bXSA9IFtdO1xuICAgICAgICBmb3IgKGxldCBba2V5LCBlbnRyeV0gb2YgdGhpcy5tZW0pIHtcbiAgICAgICAgICAgIGlmIChlbnRyeS5jaGFuZ2VkQXQgPD0gY29uZmlnLnRpbWUpIGNvbnRpbnVlO1xuICAgICAgICAgICAgaWYgKHRoaXMub3ZlcmxheS5oYXMoa2V5KSkgY29udGludWU7XG4gICAgICAgICAgICBpZiAoIWluUm91dGVzKGtleSkpIGNvbnRpbnVlO1xuICAgICAgICAgICAgZmlsZXMucHVzaCh7IHBhdGg6IGtleSwgY3JlYXRlVGltZTogZW50cnkud3JpdGVUaW1lLCBzaXplOiBlbnRyeS5zaXplIH0pO1xuICAgICAgICB9XG4gICAgICAgIGZvciAobGV0IFtrZXksIG92ZXJsYXlFbnRyeV0gb2YgdGhpcy5vdmVybGF5KSB7XG4gICAgICAgICAgICBpZiAob3ZlcmxheUVudHJ5LnQgPD0gY29uZmlnLnRpbWUpIGNvbnRpbnVlO1xuICAgICAgICAgICAgaWYgKCFpblJvdXRlcyhrZXkpKSBjb250aW51ZTtcbiAgICAgICAgICAgIGZpbGVzLnB1c2goeyBwYXRoOiBrZXksIGNyZWF0ZVRpbWU6IG92ZXJsYXlFbnRyeS50LCBzaXplOiBvdmVybGF5RW50cnkuZGF0YS5sZW5ndGggfSk7XG4gICAgICAgIH1cbiAgICAgICAgc29ydChmaWxlcywgeCA9PiB4LnBhdGgpO1xuICAgICAgICByZXR1cm4gZmlsZXM7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIGdldFN5bmNTdGF0dXMoKTogUHJvbWlzZTxBcmNoaXZlc1N5bmNTdGF0dXM+IHtcbiAgICAgICAgYXdhaXQgdGhpcy5pbml0KCk7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBhbGxTY2Fuc0NvbXBsZXRlOiB0aGlzLnNvdXJjZVN0YXRlcy5ldmVyeSh4ID0+IHguc2NhbkNvbXBsZXRlKSxcbiAgICAgICAgICAgIGluZGV4U2l6ZTogdGhpcy5tZW0uc2l6ZSxcbiAgICAgICAgICAgIHNvdXJjZXM6IHRoaXMuc291cmNlcy5tYXAoKHgsIGkpID0+ICh7XG4gICAgICAgICAgICAgICAgZGVidWdOYW1lOiB4LnNvdXJjZS5nZXREZWJ1Z05hbWUoKSxcbiAgICAgICAgICAgICAgICB2YWxpZFdpbmRvd3M6IHgudmFsaWRXaW5kb3dzLFxuICAgICAgICAgICAgICAgIHJvdXRlOiB4LnJvdXRlLFxuICAgICAgICAgICAgICAgIG5vRnVsbFN5bmM6IHgubm9GdWxsU3luYyxcbiAgICAgICAgICAgICAgICBzdXBwb3J0c0NoYW5nZXNBZnRlcjogdGhpcy5zb3VyY2VTdGF0ZXNbaV0uc3VwcG9ydHNDaGFuZ2VzQWZ0ZXIsXG4gICAgICAgICAgICAgICAgaW5pdGlhbFNjYW5Db21wbGV0ZTogdGhpcy5zb3VyY2VTdGF0ZXNbaV0uc2NhbkNvbXBsZXRlLFxuICAgICAgICAgICAgICAgIHNjYW5uZWRDb3VudDogdGhpcy5zb3VyY2VTdGF0ZXNbaV0uc2Nhbm5lZENvdW50LFxuICAgICAgICAgICAgfSkpLmZpbHRlcigoeCwgaSkgPT4gdGhpcy5pc0xpdmUoaSkpLFxuICAgICAgICB9O1xuICAgIH1cblxuICAgIC8qKiBUaGUgY2hlYXAgYWx3YXlzLWN1cnJlbnQgdG90YWxzIHBsdXMgYW55IGluLXByb2dyZXNzIGJhY2tncm91bmQgc3luY2hyb25pemF0aW9uLiAqL1xuICAgIHB1YmxpYyBnZXRTeW5jUHJvZ3Jlc3MoKToge1xuICAgICAgICBpbmRleDogeyBmaWxlQ291bnQ6IG51bWJlcjsgYnl0ZUNvdW50OiBudW1iZXIgfTtcbiAgICAgICAgc291cmNlczogeyBkZWJ1Z05hbWU6IHN0cmluZzsgZmlsZUNvdW50OiBudW1iZXI7IGJ5dGVDb3VudDogbnVtYmVyIH1bXTtcbiAgICAgICAgcmVhZGVyRGlza0xpbWl0PzogbnVtYmVyO1xuICAgICAgICBzeW5jaW5nOiBTeW5jQWN0aXZpdHlbXTtcbiAgICB9IHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIGluZGV4OiB7IGZpbGVDb3VudDogdGhpcy5pbmRleEZpbGVDb3VudCwgYnl0ZUNvdW50OiB0aGlzLmluZGV4Qnl0ZUNvdW50IH0sXG4gICAgICAgICAgICBzb3VyY2VzOiB0aGlzLnNvdXJjZXMubWFwKCh4LCBpKSA9PiAoe1xuICAgICAgICAgICAgICAgIGRlYnVnTmFtZTogeC5zb3VyY2UuZ2V0RGVidWdOYW1lKCksXG4gICAgICAgICAgICAgICAgZmlsZUNvdW50OiB0aGlzLnNvdXJjZUZpbGVDb3VudHNbaV0sXG4gICAgICAgICAgICAgICAgYnl0ZUNvdW50OiB0aGlzLnNvdXJjZUJ5dGVDb3VudHNbaV0sXG4gICAgICAgICAgICB9KSkuZmlsdGVyKCh4LCBpKSA9PiB0aGlzLmlzTGl2ZShpKSksXG4gICAgICAgICAgICByZWFkZXJEaXNrTGltaXQ6IHRoaXMuY29uZmlnPy5yZWFkZXJEaXNrTGltaXQsXG4gICAgICAgICAgICBzeW5jaW5nOiBbLi4udGhpcy5zeW5jQWN0aXZpdGllc10sXG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgLyoqIFdhbGtzIHRoZSB3aG9sZSBpbmRleCBmb3IgZXhhY3QgdG90YWxzIC0gbW9yZSBleHBlbnNpdmUgdGhhbiBnZXRTeW5jUHJvZ3Jlc3MsIGJ1dCBpbW11bmUgdG8gYW55IGRyaWZ0IGluIHRoZSBtYWludGFpbmVkIGNvdW50ZXJzIChhbmQgbG9hZHMgdGhlIGluZGV4IGZpcnN0LCBzbyBpdCdzIG5ldmVyIGNvbGQgemVyb3MpLiAqL1xuICAgIHB1YmxpYyBhc3luYyBjb21wdXRlSW5kZXhUb3RhbHMoKTogUHJvbWlzZTx7XG4gICAgICAgIGZpbGVDb3VudDogbnVtYmVyO1xuICAgICAgICBieXRlQ291bnQ6IG51bWJlcjtcbiAgICAgICAgc291cmNlczogeyBkZWJ1Z05hbWU6IHN0cmluZzsgZmlsZUNvdW50OiBudW1iZXI7IGJ5dGVDb3VudDogbnVtYmVyIH1bXTtcbiAgICB9PiB7XG4gICAgICAgIGF3YWl0IHRoaXMuaW5pdCgpO1xuICAgICAgICBsZXQgZmlsZUNvdW50ID0gMDtcbiAgICAgICAgbGV0IGJ5dGVDb3VudCA9IDA7XG4gICAgICAgIGxldCBzb3VyY2VzID0gdGhpcy5zb3VyY2VzLm1hcCh4ID0+ICh7IGRlYnVnTmFtZTogeC5zb3VyY2UuZ2V0RGVidWdOYW1lKCksIGZpbGVDb3VudDogMCwgYnl0ZUNvdW50OiAwIH0pKTtcbiAgICAgICAgZm9yIChsZXQgZW50cnkgb2YgdGhpcy5tZW0udmFsdWVzKCkpIHtcbiAgICAgICAgICAgIGlmIChlbnRyeS5zaXplID09PSAwKSBjb250aW51ZTtcbiAgICAgICAgICAgIGZpbGVDb3VudCsrO1xuICAgICAgICAgICAgYnl0ZUNvdW50ICs9IGVudHJ5LnNpemU7XG4gICAgICAgICAgICBsZXQgc2xvdCA9IHRoaXMuc2xvdEZvclNvdXJjZXNMaXN0SW5kZXgoZW50cnkuc291cmNlc0xpc3RJbmRleCk7XG4gICAgICAgICAgICBpZiAoc2xvdCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgc291cmNlc1tzbG90XS5maWxlQ291bnQrKztcbiAgICAgICAgICAgICAgICBzb3VyY2VzW3Nsb3RdLmJ5dGVDb3VudCArPSBlbnRyeS5zaXplO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiB7IGZpbGVDb3VudCwgYnl0ZUNvdW50LCBzb3VyY2VzOiBzb3VyY2VzLmZpbHRlcigoeCwgaSkgPT4gdGhpcy5pc0xpdmUoaSkpIH07XG4gICAgfVxuXG4gICAgLyoqIEFwcGxpZXMgYSBjb25maWcgY2hhbmdlIHRvIHRoZSBSVU5OSU5HIHN0b3JlOiB3aW5kb3dzL3JvdXRlcyB1cGRhdGUgaW4gcGxhY2UsIG5ldyBzb3VyY2VzIGFyZSBhZGRlZCAodGhlaXIgc3luYyBzdGFydHMgaW1tZWRpYXRlbHkpLCBhbmQgcmVtb3ZlZCBzb3VyY2VzJyBzbG90cyBnbyBkZWFkICh0aGVpciBzY2FucyBzdG9wLCB0aGVpciBpbmRleCBlbnRyaWVzIGRyb3ApLiBUaGUgc3RvcmUgc3Vydml2ZXMgZXZlcnkgcm91dGluZSBjb25maWcgZXZvbHV0aW9uIC0gaXQgaXMgbmV2ZXIgZGVzdHJveWVkIGZvciBhIHNvdXJjZS1saXN0IGNoYW5nZSwgb25seSBmb3Igc3RydWN0dXJhbCBmbGlwcyBpdCBjYW5ub3QgZXhwcmVzcyAocmF3RGlzaykuIFBlbmRpbmcgZmFzdCB3cml0ZXMgYXJlIHJlLWNhcHBlZCB0byB0aGUgbmV3IGZsdXNoIGRlYWRsaW5lIChmbHVzaGluZyBpbW1lZGlhdGVseSB3aGVuIGl0IGhhcyBhbHJlYWR5IHBhc3NlZCkuICovXG4gICAgcHVibGljIHVwZGF0ZVNvdXJjZXMoc3BlY3M6IEJsb2JTb3VyY2VTcGVjW10sIGVudHJpZXM/OiBIb3N0ZWRDb25maWdbXSk6IHZvaWQge1xuICAgICAgICBpZiAoIXNwZWNzLmxlbmd0aCB8fCBzcGVjc1swXS5pZGVudGl0eSAhPT0gXCJkaXNrXCIpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgdXBkYXRlU291cmNlcyBleHBlY3RzIHRoZSBkaXNrIHNvdXJjZSBmaXJzdCAoaWRlbnRpdHkgXCJkaXNrXCIpLCBnb3QgJHtKU09OLnN0cmluZ2lmeShzcGVjcy5tYXAoeCA9PiB4LmlkZW50aXR5KSl9IChzdG9yZSAke3RoaXMuZm9sZGVyfSlgKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoZW50cmllcykge1xuICAgICAgICAgICAgdGhpcy5lbnRyaWVzID0gZW50cmllcztcbiAgICAgICAgfVxuICAgICAgICBsZXQgc2V0V2luZG93cyA9IChpOiBudW1iZXIsIHdpbmRvd3M6IFtudW1iZXIsIG51bWJlcl1bXSkgPT4ge1xuICAgICAgICAgICAgbGV0IG9sZCA9IHRoaXMuc291cmNlc1tpXS52YWxpZFdpbmRvd3M7XG4gICAgICAgICAgICBpZiAoSlNPTi5zdHJpbmdpZnkob2xkKSA9PT0gSlNPTi5zdHJpbmdpZnkod2luZG93cykpIHJldHVybjtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKGBWYWxpZCB3aW5kb3dzIGNoYW5nZWQgZm9yICR7dGhpcy5zb3VyY2VzW2ldLnNvdXJjZS5nZXREZWJ1Z05hbWUoKX0gKHN0b3JlICR7dGhpcy5mb2xkZXJ9KTogJHtKU09OLnN0cmluZ2lmeShvbGQpfSAtPiAke0pTT04uc3RyaW5naWZ5KHdpbmRvd3MpfWApO1xuICAgICAgICAgICAgdGhpcy5zb3VyY2VzW2ldLnZhbGlkV2luZG93cyA9IHdpbmRvd3M7XG4gICAgICAgIH07XG4gICAgICAgIHNldFdpbmRvd3MoMCwgc3BlY3NbMF0udmFsaWRXaW5kb3dzKTtcbiAgICAgICAgLy8gTGl2ZSBzbG90cyBwYWlyIHdpdGggc3BlY3MgYnkgaWRlbnRpdHkuIEVhY2ggZW5kcG9pbnQgaXMgbm93IE9ORSBzcGVjIGNhcnJ5aW5nIGFsbCBpdHMgd2luZG93cywgc28gdGhpcyBpcyBhIDE6MSBwYWlyaW5nOyBhbnkgbGVmdG92ZXIgZHVwbGljYXRlIHNsb3RzIGZyb20gYmVmb3JlIChhbiBlbmRwb2ludCB0aGF0IHVzZWQgdG8gYmUgc3BsaXQgaW50byBzZXZlcmFsIHNsb3RzKSBnbyB1bm1hdGNoZWQgYmVsb3cgYW5kIGFyZSBjb2xsYXBzZWQgYXdheS5cbiAgICAgICAgbGV0IGxpdmVCeUlkZW50aXR5ID0gbmV3IE1hcDxzdHJpbmcsIG51bWJlcltdPigpO1xuICAgICAgICBsZXQgb3JpZ2luYWxMZW5ndGggPSB0aGlzLnNvdXJjZXMubGVuZ3RoO1xuICAgICAgICBmb3IgKGxldCBpID0gMTsgaSA8IG9yaWdpbmFsTGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIGlmICghdGhpcy5pc0xpdmUoaSkpIGNvbnRpbnVlO1xuICAgICAgICAgICAgbGV0IGlkID0gdGhpcy5zb3VyY2VzW2ldLmlkZW50aXR5O1xuICAgICAgICAgICAgaWYgKGlkID09PSB1bmRlZmluZWQpIGNvbnRpbnVlO1xuICAgICAgICAgICAgbGV0IGxpc3QgPSBsaXZlQnlJZGVudGl0eS5nZXQoaWQpO1xuICAgICAgICAgICAgaWYgKCFsaXN0KSB7XG4gICAgICAgICAgICAgICAgbGlzdCA9IFtdO1xuICAgICAgICAgICAgICAgIGxpdmVCeUlkZW50aXR5LnNldChpZCwgbGlzdCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBsaXN0LnB1c2goaSk7XG4gICAgICAgIH1cbiAgICAgICAgbGV0IG1hdGNoZWQgPSBuZXcgU2V0PG51bWJlcj4oKTtcbiAgICAgICAgZm9yIChsZXQgc3BlYyBvZiBzcGVjcy5zbGljZSgxKSkge1xuICAgICAgICAgICAgbGV0IHNsb3QgPSBsaXZlQnlJZGVudGl0eS5nZXQoc3BlYy5pZGVudGl0eSk/LnNoaWZ0KCk7XG4gICAgICAgICAgICBpZiAoc2xvdCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgbWF0Y2hlZC5hZGQoc2xvdCk7XG4gICAgICAgICAgICAgICAgc2V0V2luZG93cyhzbG90LCBzcGVjLnZhbGlkV2luZG93cyk7XG4gICAgICAgICAgICAgICAgbGV0IGV4aXN0aW5nID0gdGhpcy5zb3VyY2VzW3Nsb3RdO1xuICAgICAgICAgICAgICAgIGlmIChKU09OLnN0cmluZ2lmeShleGlzdGluZy5yb3V0ZSkgIT09IEpTT04uc3RyaW5naWZ5KHNwZWMucm91dGUpKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKGBSb3V0ZSBjaGFuZ2VkIGZvciAke2V4aXN0aW5nLnNvdXJjZS5nZXREZWJ1Z05hbWUoKX0gKHN0b3JlICR7dGhpcy5mb2xkZXJ9KTogJHtKU09OLnN0cmluZ2lmeShleGlzdGluZy5yb3V0ZSl9IC0+ICR7SlNPTi5zdHJpbmdpZnkoc3BlYy5yb3V0ZSl9YCk7XG4gICAgICAgICAgICAgICAgICAgIGV4aXN0aW5nLnJvdXRlID0gc3BlYy5yb3V0ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZXhpc3Rpbmcubm9GdWxsU3luYyA9IHNwZWMubm9GdWxsU3luYztcbiAgICAgICAgICAgICAgICBleGlzdGluZy5zb3VyY2VDb25maWcgPSBzcGVjLnNvdXJjZUNvbmZpZztcbiAgICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGxldCBzb3VyY2UgPSBzcGVjLmNyZWF0ZSgpO1xuICAgICAgICAgICAgdGhpcy5zb3VyY2VzLnB1c2goeyBzb3VyY2UsIHVybDogc3BlYy51cmwsIHZhbGlkV2luZG93czogc3BlYy52YWxpZFdpbmRvd3MsIHJvdXRlOiBzcGVjLnJvdXRlLCBub0Z1bGxTeW5jOiBzcGVjLm5vRnVsbFN5bmMsIGludGVybWVkaWF0ZTogc3BlYy5pbnRlcm1lZGlhdGUsIHNvdXJjZUNvbmZpZzogc3BlYy5zb3VyY2VDb25maWcsIGlkZW50aXR5OiBzcGVjLmlkZW50aXR5IH0pO1xuICAgICAgICAgICAgdGhpcy5zb3VyY2VTdGF0ZXMucHVzaChuZXdTb3VyY2VTdGF0ZSgpKTtcbiAgICAgICAgICAgIHRoaXMuc291cmNlRmlsZUNvdW50cy5wdXNoKDApO1xuICAgICAgICAgICAgdGhpcy5zb3VyY2VCeXRlQ291bnRzLnB1c2goMCk7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhgQWRkZWQgc3luYyBzb3VyY2UgJHtzb3VyY2UuZ2V0RGVidWdOYW1lKCl9IChzdG9yZSAke3RoaXMuZm9sZGVyfSlgKTtcbiAgICAgICAgICAgIGlmICh0aGlzLnN5bmNTdGFydGVkKSB7XG4gICAgICAgICAgICAgICAgdm9pZCB0aGlzLnJ1blNvdXJjZVN5bmModGhpcy5zb3VyY2VzLmxlbmd0aCAtIDEpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGZvciAobGV0IGkgPSAxOyBpIDwgb3JpZ2luYWxMZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgaWYgKCF0aGlzLmlzTGl2ZShpKSB8fCBtYXRjaGVkLmhhcyhpKSkgY29udGludWU7XG4gICAgICAgICAgICB0aGlzLnJlbW92ZVNvdXJjZShpKTtcbiAgICAgICAgfVxuICAgICAgICBsZXQgZGVhZGxpbmUgPSB0aGlzLmJhc2VXcml0ZVdpbmRvd0VuZCgpIC0gV0lORE9XX0VORF9GTFVTSF9NQVJHSU47XG4gICAgICAgIGxldCByZWNhcHBlZCA9IDA7XG4gICAgICAgIGZvciAobGV0IGVudHJ5IG9mIHRoaXMub3ZlcmxheS52YWx1ZXMoKSkge1xuICAgICAgICAgICAgaWYgKGVudHJ5LmZhc3RGbHVzaEF0IDw9IGRlYWRsaW5lICYmIGVudHJ5LnNsb3dGbHVzaEF0IDw9IGRlYWRsaW5lKSBjb250aW51ZTtcbiAgICAgICAgICAgIGVudHJ5LmZhc3RGbHVzaEF0ID0gTWF0aC5taW4oZW50cnkuZmFzdEZsdXNoQXQsIGRlYWRsaW5lKTtcbiAgICAgICAgICAgIGVudHJ5LnNsb3dGbHVzaEF0ID0gTWF0aC5taW4oZW50cnkuc2xvd0ZsdXNoQXQsIGRlYWRsaW5lKTtcbiAgICAgICAgICAgIHJlY2FwcGVkKys7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHJlY2FwcGVkKSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhgUmUtY2FwcGVkICR7cmVjYXBwZWR9IHBlbmRpbmcgZmFzdCB3cml0ZXMgdG8gdGhlIG5ldyBmbHVzaCBkZWFkbGluZSAke25ldyBEYXRlKGRlYWRsaW5lKS50b0lTT1N0cmluZygpfSAoc3RvcmUgJHt0aGlzLmZvbGRlcn0pYCk7XG4gICAgICAgICAgICBpZiAoZGVhZGxpbmUgPD0gRGF0ZS5ub3coKSkge1xuICAgICAgICAgICAgICAgIHZvaWQgdGhpcy5mbHVzaE92ZXJsYXkoKS5jYXRjaCgoZTogRXJyb3IpID0+IGNvbnNvbGUuZXJyb3IoYEZsdXNoaW5nIGZhc3Qgd3JpdGVzIGFmdGVyIGEgdmFsaWQgd2luZG93IGNoYW5nZSBmYWlsZWQgKHN0b3JlICR7dGhpcy5mb2xkZXJ9KTogJHtlLnN0YWNrID8/IGV9YCkpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqIFJlc2NhbnMgb3VyIG93biBkaXNrJ3MgbWV0YWRhdGEgaW50byB0aGUgaW5kZXggLSB1c2VkIGFyb3VuZCB2YWxpZCB3aW5kb3cgaGFuZG9mZnMsIHdoZXJlIGFub3RoZXIgcHJvY2VzcyB3cm90ZSBmaWxlcyB0byB0aGUgc2hhcmVkIGZvbGRlciB0aGF0IG91ciBpbmRleCBoYXNuJ3Qgc2Vlbi4gKi9cbiAgICBwdWJsaWMgYXN5bmMgcmVzY2FuQmFzZSgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgYXdhaXQgdGhpcy5pbml0KCk7XG4gICAgICAgIGF3YWl0IHRoaXMuc2NhblNvdXJjZSgwKTtcbiAgICB9XG5cbiAgICAvKiogQSBib3VuZGFyeSBzY2FuIG9mIHRoZSBub2RlIHRoYXQgb3duZWQgKHBhcnQgb2YpIG91ciByb3V0ZSBpbiB0aGUgdmFsaWQgd2luZG93IGJlZm9yZSBvdXJzLCB3aGVuIHRoYXQgbm9kZSBpcyBkaWZmZXJlbnQgc3RvcmFnZSAoYSBkaXNrIHJlc2NhbiBjYW4ndCBzZWUgaXRzIHdyaXRlcyk6IGp1c3QgaXRzIGNoYW5nZXMgc2luY2UgdGhlIGJvdW5kYXJ5IG5laWdoYm9yaG9vZCwgd2l0aCBtYXRjaGluZyB2YWx1ZXMgcHVsbGVkIG9udG8gb3VyIG93biBkaXNrLiAqL1xuICAgIHB1YmxpYyBhc3luYyBib3VuZGFyeVNjYW5SZW1vdGUoc291cmNlOiBJQXJjaGl2ZXMsIGNvbmZpZzogeyBzaW5jZTogbnVtYmVyOyByb3V0ZT86IFtudW1iZXIsIG51bWJlcl0gfSk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBhd2FpdCB0aGlzLmluaXQoKTtcbiAgICAgICAgbGV0IHNjYW5TdGFydCA9IERhdGUubm93KCk7XG4gICAgICAgIGNvbnNvbGUubG9nKGBCb3VuZGFyeSBzY2FuIG9mICR7c291cmNlLmdldERlYnVnTmFtZSgpfSBzdGFydGluZzogY2hhbmdlcyBzaW5jZSAke25ldyBEYXRlKGNvbmZpZy5zaW5jZSkudG9JU09TdHJpbmcoKX0sIHJvdXRlICR7SlNPTi5zdHJpbmdpZnkoY29uZmlnLnJvdXRlIHx8IEZVTExfUk9VVEUpfSAoc3RvcmUgJHt0aGlzLmZvbGRlcn0pYCk7XG4gICAgICAgIGxldCBjaGFuZ2VzID0gYXdhaXQgc291cmNlLmdldENoYW5nZXNBZnRlcjIoeyB0aW1lOiBjb25maWcuc2luY2UsIHJvdXRlczogY29uZmlnLnJvdXRlICYmIFtjb25maWcucm91dGVdIHx8IHVuZGVmaW5lZCB9KTtcbiAgICAgICAgbGV0IHRhbGx5ID0gbmV3U2NhblRhbGx5KCk7XG4gICAgICAgIGZvciAobGV0IGZpbGUgb2YgY2hhbmdlcykge1xuICAgICAgICAgICAgaWYgKGZpbGUucGF0aCA9PT0gUk9VVElOR19GSUxFKSB7XG4gICAgICAgICAgICAgICAgdGFsbHkuZmlsdGVyZWQrKztcbiAgICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGxldCBvdmVybGF5RW50cnkgPSB0aGlzLm92ZXJsYXkuZ2V0KGZpbGUucGF0aCk7XG4gICAgICAgICAgICBsZXQgZW50cnkgPSB0aGlzLm1lbS5nZXQoZmlsZS5wYXRoKTtcbiAgICAgICAgICAgIGxldCBjdXJyZW50VGltZSA9IG92ZXJsYXlFbnRyeSAmJiBvdmVybGF5RW50cnkudCB8fCBlbnRyeSAmJiBlbnRyeS53cml0ZVRpbWUgfHwgMDtcbiAgICAgICAgICAgIGlmIChmaWxlLmNyZWF0ZVRpbWUgPD0gY3VycmVudFRpbWUpIHtcbiAgICAgICAgICAgICAgICB0YWxseS51bmNoYW5nZWQrKztcbiAgICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChmaWxlLnNpemUgPT09IDApIHtcbiAgICAgICAgICAgICAgICAvLyBBIHRvbWJzdG9uZSBzdG9yZXMgbm90aGluZyBvbiBvdXIgb3duIHNvdXJjZSAtIHRoZSBpbmRleCBlbnRyeSBhbG9uZSByZWNvcmRzIGl0XG4gICAgICAgICAgICAgICAgdGhpcy5zZXRJbmRleEVudHJ5KGZpbGUucGF0aCwgeyB3cml0ZVRpbWU6IGZpbGUuY3JlYXRlVGltZSwgc2l6ZTogMCwgc291cmNlc0xpc3RJbmRleDogdGhpcy5zb3VyY2VzTGlzdEluZGV4T2ZTbG90KDApIH0pO1xuICAgICAgICAgICAgICAgIHRhbGx5LnRvbWJzdG9uZSsrO1xuICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgbGV0IGNvcGllZCA9IGF3YWl0IGNvcHlBcmNoaXZlRmlsZSh7IGZyb206IHNvdXJjZSwgdG86IHRoaXMuc291cmNlc1swXS5zb3VyY2UsIHBhdGg6IGZpbGUucGF0aCwgc2l6ZTogZmlsZS5zaXplLCB3cml0ZVRpbWU6IGZpbGUuY3JlYXRlVGltZSwgZm9yY2VTZXRJbW11dGFibGU6IHRydWUsIG5vQ2hlY2tzOiB0cnVlLCBpbnRlcm5hbDogdHJ1ZSB9KTtcbiAgICAgICAgICAgIGlmICghY29waWVkKSBjb250aW51ZTtcbiAgICAgICAgICAgIGlmIChjb3BpZWQuc2l6ZSA9PT0gMCkge1xuICAgICAgICAgICAgICAgIHRoaXMuc2V0SW5kZXhFbnRyeShmaWxlLnBhdGgsIHsgd3JpdGVUaW1lOiBjb3BpZWQud3JpdGVUaW1lLCBzaXplOiAwLCBzb3VyY2VzTGlzdEluZGV4OiB0aGlzLnNvdXJjZXNMaXN0SW5kZXhPZlNsb3QoMCkgfSk7XG4gICAgICAgICAgICAgICAgdGFsbHkudG9tYnN0b25lKys7XG4gICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLnNldEluZGV4RW50cnkoZmlsZS5wYXRoLCB7IHdyaXRlVGltZTogY29waWVkLndyaXRlVGltZSwgc2l6ZTogY29waWVkLnNpemUsIHNvdXJjZXNMaXN0SW5kZXg6IHRoaXMuc291cmNlc0xpc3RJbmRleE9mU2xvdCgwKSB9KTtcbiAgICAgICAgICAgIGlmIChlbnRyeSB8fCBvdmVybGF5RW50cnkpIHtcbiAgICAgICAgICAgICAgICB0YWxseS51cGRhdGVkKys7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRhbGx5Lm5ldysrO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGNvbnNvbGUubG9nKGBCb3VuZGFyeSBzY2FuIG9mICR7c291cmNlLmdldERlYnVnTmFtZSgpfSBmaW5pc2hlZCBpbiAke01hdGgucm91bmQoKERhdGUubm93KCkgLSBzY2FuU3RhcnQpIC8gMTAwMCl9cyAoc3RvcmUgJHt0aGlzLmZvbGRlcn0pOiAke2NoYW5nZXMubGVuZ3RofSBjaGFuZ2VzOiAke2Zvcm1hdFNjYW5UYWxseSh0YWxseSwgY2hhbmdlcy5sZW5ndGgpfWApO1xuICAgIH1cblxuICAgIC8vIExhcmdlIHVwbG9hZHMgc3RyZWFtIG9udG8gdGhlIGxvY2FsIGRpc2sgc291cmNlIGRpcmVjdGx5ICh0aGV5IG1heSBub3QgZml0IGluIG1lbW9yeSlcbiAgICBwdWJsaWMgYXN5bmMgc3RhcnRMYXJnZVVwbG9hZChjb25maWc/OiB7IHBhdGg/OiBzdHJpbmc7IGxhc3RNb2RpZmllZD86IG51bWJlciB9KTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICAgICAgYXdhaXQgdGhpcy5pbml0KCk7XG4gICAgICAgIGlmIChjb25maWc/LnBhdGgpIHtcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuYXNzZXJ0TXV0YWJsZShjb25maWcucGF0aCwgY29uZmlnLmxhc3RNb2RpZmllZCB8fCBEYXRlLm5vdygpKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gYXdhaXQgdGhpcy5nZXREaXNrU291cmNlKCkuZGlzay5zdGFydExhcmdlVXBsb2FkKCk7XG4gICAgfVxuICAgIHB1YmxpYyBhc3luYyBhcHBlbmRMYXJnZVVwbG9hZChjb25maWc6IHsgaWQ6IHN0cmluZzsgZGF0YTogQnVmZmVyIH0pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgYXdhaXQgdGhpcy5nZXREaXNrU291cmNlKCkuZGlzay5hcHBlbmRMYXJnZVVwbG9hZChjb25maWcuaWQsIGNvbmZpZy5kYXRhKTtcbiAgICB9XG4gICAgcHVibGljIGFzeW5jIGZpbmlzaExhcmdlVXBsb2FkKGNvbmZpZzogeyBpZDogc3RyaW5nOyBwYXRoOiBzdHJpbmc7IGxhc3RNb2RpZmllZD86IG51bWJlciB9KTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGxldCB7IGRpc2ssIHNvdXJjZUluZGV4IH0gPSB0aGlzLmdldERpc2tTb3VyY2UoKTtcbiAgICAgICAgYXdhaXQgZGlzay5maW5pc2hMYXJnZVVwbG9hZChjb25maWcuaWQsIGNvbmZpZy5wYXRoLCBjb25maWcubGFzdE1vZGlmaWVkKTtcbiAgICAgICAgdGhpcy5vdmVybGF5LmRlbGV0ZShjb25maWcucGF0aCk7XG4gICAgICAgIC8vIGluY2x1ZGVUb21ic3RvbmVzOiBhIHplcm8tYnl0ZSB1cGxvYWQgaXMgc3RpbGwgYSByZWFsIGZpbGUgd2hvc2UgaW5kZXggZW50cnkgbXVzdCBiZSB3cml0dGVuXG4gICAgICAgIGxldCBpbmZvID0gYXdhaXQgZGlzay5nZXRJbmZvKGNvbmZpZy5wYXRoLCB7IGluY2x1ZGVUb21ic3RvbmVzOiB0cnVlIH0pO1xuICAgICAgICBpZiAoaW5mbykge1xuICAgICAgICAgICAgdGhpcy5zZXRJbmRleEVudHJ5KGNvbmZpZy5wYXRoLCB7IHdyaXRlVGltZTogaW5mby53cml0ZVRpbWUsIHNpemU6IGluZm8uc2l6ZSwgc291cmNlc0xpc3RJbmRleDogdGhpcy5zb3VyY2VzTGlzdEluZGV4T2ZTbG90KHNvdXJjZUluZGV4KSB9KTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBwdWJsaWMgYXN5bmMgY2FuY2VsTGFyZ2VVcGxvYWQoY29uZmlnOiB7IGlkOiBzdHJpbmcgfSk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBhd2FpdCB0aGlzLmdldERpc2tTb3VyY2UoKS5kaXNrLmNhbmNlbExhcmdlVXBsb2FkKGNvbmZpZy5pZCk7XG4gICAgfVxuXG4gICAgLy8gI2VuZHJlZ2lvblxuXG4gICAgLy8gI3JlZ2lvbiBJbnRlcm5hbHNcblxuICAgIHByaXZhdGUgc3RvcHBlZCA9IHsgc3RvcDogZmFsc2UgfTtcblxuICAgIC8vIFRoZSBpbmRleCdzIEJ1bGtEYXRhYmFzZTIgZmlsZXMgbGl2ZSB1bmRlciA8Zm9sZGVyPi9pbmRleC4gXCJibG9iSW5kZXgyXCI6IHRoZSBcImJsb2JJbmRleFwiIGdlbmVyYXRpb24gcGVyc2lzdGVkIHNvdXJjZXMtYXJyYXkgcG9zaXRpb25zIGFzIHRoZSBob2xkaW5nIHNvdXJjZSwgd2hpY2ggYXJlIG5vdCBzdGFibGUgYWNyb3NzIHJ1bnMgLSBpdHMgZW50cmllcyBhcmUgdW51c2FibGUsIHNvIGl0IGlzIHNpbXBseSBuZXZlciByZWFkIGFnYWluLlxuICAgIHByaXZhdGUgaW5kZXggPSBuZXcgQnVsa0RhdGFiYXNlQmFzZTxCbG9iSW5kZXhFbnRyeT4oXCJibG9iSW5kZXgyXCIsIG5vb3BSZWFjdGl2ZURlcHMsIGFzeW5jIChwOiBzdHJpbmcpID0+IHtcbiAgICAgICAgbGV0IGJhc2U6IERpcmVjdG9yeVdyYXBwZXIgPSBuZXcgTm9kZUpTRGlyZWN0b3J5SGFuZGxlV3JhcHBlcihwYXRoLmpvaW4odGhpcy5mb2xkZXIsIFwiaW5kZXhcIikpO1xuICAgICAgICBmb3IgKGxldCBwYXJ0IG9mIHAuc3BsaXQoXCIvXCIpKSB7XG4gICAgICAgICAgICBpZiAocGFydCkgYmFzZSA9IGF3YWl0IGJhc2UuZ2V0RGlyZWN0b3J5SGFuZGxlKHBhcnQsIHsgY3JlYXRlOiB0cnVlIH0pO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB3cmFwSGFuZGxlKGJhc2UpO1xuICAgIH0pO1xuICAgIC8vIFRoZSBpbi1tZW1vcnkgY29weSBvZiB0aGUgaW5kZXguIEFsbCByZWFkcyBhcmUgc2VydmVkIGZyb20gaXQ7IGNoYW5nZXMgYXJlIGJ1ZmZlcmVkIGluIGRpcnR5IGFuZCBmbHVzaGVkIHRvIHRoZSBCdWxrRGF0YWJhc2UyIGluIGJhdGNoZXMgKHVuZGVmaW5lZCA9IGRlbGV0ZSkuXG4gICAgcHJpdmF0ZSBtZW0gPSBuZXcgTWFwPHN0cmluZywgSW5kZXhFbnRyeT4oKTtcbiAgICAvLyBMaXZlIHRvdGFscyBvdmVyIG1lbSAodG9tYnN0b25lcyBleGNsdWRlZCksIGFkanVzdGVkIG9uIGV2ZXJ5IG11dGF0aW9uIGFuZCByZWNvbXB1dGVkIG9uIGxvYWQgLSBzbyBhbnkgZHJpZnQgaGVhbHMgb24gcmVzdGFydC4gY29tcHV0ZUluZGV4VG90YWxzIGdpdmVzIHRoZSB3YWxrLXRoZS1pbmRleCB0cnV0aC5cbiAgICBwcml2YXRlIGluZGV4RmlsZUNvdW50ID0gMDtcbiAgICBwcml2YXRlIGluZGV4Qnl0ZUNvdW50ID0gMDtcbiAgICAvLyBUaGUgc2FtZSB0b3RhbHMgcGVyIGhvbGRpbmcgc291cmNlIChpbmRleCAwID0gb3VyIGRpc2ssIHdoaWNoIHJlYWRlckRpc2tMaW1pdCBib3VuZHMpXG4gICAgcHJpdmF0ZSBzb3VyY2VGaWxlQ291bnRzID0gdGhpcy5zb3VyY2VzLm1hcCgoKSA9PiAwKTtcbiAgICBwcml2YXRlIHNvdXJjZUJ5dGVDb3VudHMgPSB0aGlzLnNvdXJjZXMubWFwKCgpID0+IDApO1xuICAgIC8vIEJhY2tncm91bmQgc2NhbnMgLyBmdWxsIHN5bmNzIGN1cnJlbnRseSBpbiBwcm9ncmVzcyAoYSBTZXQgLSBvbmUgc291cmNlIGNhbiBoYXZlIGEgY2hhbmdlIHBvbGwncyBmdWxsIHN5bmMgYW5kIGEgcmVzY2FuIG92ZXJsYXBwaW5nKVxuICAgIHByaXZhdGUgc3luY0FjdGl2aXRpZXMgPSBuZXcgU2V0PFN5bmNBY3Rpdml0eT4oKTtcbiAgICBwcml2YXRlIGRpcnR5ID0gbmV3IE1hcDxzdHJpbmcsIEluZGV4RW50cnkgfCB1bmRlZmluZWQ+KCk7XG4gICAgcHJpdmF0ZSBvdmVybGF5ID0gbmV3IE1hcDxzdHJpbmcsIE92ZXJsYXlFbnRyeT4oKTtcbiAgICBwcml2YXRlIHNvdXJjZVN0YXRlcyA9IHRoaXMuc291cmNlcy5tYXAoKCkgPT4gbmV3U291cmNlU3RhdGUoKSk7XG4gICAgcHJpdmF0ZSBzeW5jU3RhcnRlZCA9IGZhbHNlO1xuICAgIHByaXZhdGUgZW50cmllcyA9IHRoaXMuY29uZmlnPy5lbnRyaWVzIHx8IFtdO1xuICAgIC8vIFRoZSBwZXJzaXN0ZW50IGlkZW50aXRpZXMgYmVoaW5kIEluZGV4RW50cnkuc291cmNlc0xpc3RJbmRleCAoc2VlIFNvdXJjZXNMaXN0KVxuICAgIHByaXZhdGUgc291cmNlc0xpc3QgPSBuZXcgU291cmNlc0xpc3QocGF0aC5qb2luKHRoaXMuZm9sZGVyLCBcImluZGV4XCIsIFwic291cmNlc0xpc3QudHh0XCIpKTtcbiAgICAvLyBQZXIgc2xvdDogdGhlIHBlcnNpc3RlbnQgc291cmNlc0xpc3RJbmRleCBvZiB0aGF0IHNsb3QncyBVUkwsIGZpbGxlZCBieSByZWdpc3RlclNsb3QgYmVmb3JlIHRoZSBzbG90J3Mgc3luYyBydW5zXG4gICAgcHJpdmF0ZSBzbG90U291cmNlc0xpc3RJbmRleGVzOiBudW1iZXJbXSA9IFtdO1xuICAgIHByaXZhdGUgc2xvdFJlZ2lzdHJhdGlvbnM6IFByb21pc2U8dm9pZD5bXSA9IFtdO1xuXG4gICAgcHJpdmF0ZSBpc0xpdmUoc291cmNlSW5kZXg6IG51bWJlcik6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gISF0aGlzLnNvdXJjZXNbc291cmNlSW5kZXhdICYmICF0aGlzLnNvdXJjZVN0YXRlc1tzb3VyY2VJbmRleF0uZGVhZDtcbiAgICB9XG5cbiAgICBwcml2YXRlIHJlZ2lzdGVyU2xvdChzbG90OiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgbGV0IGV4aXN0aW5nID0gdGhpcy5zbG90UmVnaXN0cmF0aW9uc1tzbG90XTtcbiAgICAgICAgaWYgKGV4aXN0aW5nKSByZXR1cm4gZXhpc3Rpbmc7XG4gICAgICAgIGxldCByZWdpc3RyYXRpb24gPSB0aGlzLnNvdXJjZXNMaXN0LmVuc3VyZSh0aGlzLnNvdXJjZXNbc2xvdF0udXJsKS50aGVuKGluZGV4ID0+IHtcbiAgICAgICAgICAgIHRoaXMuc2xvdFNvdXJjZXNMaXN0SW5kZXhlc1tzbG90XSA9IGluZGV4O1xuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy5zbG90UmVnaXN0cmF0aW9uc1tzbG90XSA9IHJlZ2lzdHJhdGlvbjtcbiAgICAgICAgcmV0dXJuIHJlZ2lzdHJhdGlvbjtcbiAgICB9XG5cbiAgICAvLyBUaGUgcGVyc2lzdGVudCBzb3VyY2VzTGlzdEluZGV4IG9mIGEgc2xvdCAtIG9ubHkgdmFsaWQgb25jZSB0aGUgc2xvdCdzIHJlZ2lzdHJhdGlvbiByZXNvbHZlZCAoaW5pdCBhbmQgcnVuU291cmNlU3luYyBndWFyYW50ZWUgdGhhdCBiZWZvcmUgYW55IGluZGV4aW5nIGhhcHBlbnMpXG4gICAgcHJpdmF0ZSBzb3VyY2VzTGlzdEluZGV4T2ZTbG90KHNsb3Q6IG51bWJlcik6IG51bWJlciB7XG4gICAgICAgIGxldCBpbmRleCA9IHRoaXMuc2xvdFNvdXJjZXNMaXN0SW5kZXhlc1tzbG90XTtcbiAgICAgICAgaWYgKGluZGV4ID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgU291cmNlIHNsb3QgJHtzbG90fSAoJHt0aGlzLnNvdXJjZXNbc2xvdF0/LnVybH0pIGhhcyBubyByZWdpc3RlcmVkIHNvdXJjZXNMaXN0SW5kZXggeWV0IChzdG9yZSAke3RoaXMuZm9sZGVyfSlgKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gaW5kZXg7XG4gICAgfVxuXG4gICAgLy8gVGhlIGxpdmUgc2xvdCBjdXJyZW50bHkgc2VydmluZyBhIHBlcnNpc3RlbnQgc291cmNlc0xpc3RJbmRleCwgb3IgdW5kZWZpbmVkIHdoZW4gbm8gY29uZmlndXJlZCBzb3VyY2UgaGFzIHRoYXQgVVJMIGFueW1vcmUuIExpbmVhciwgYnV0IHRoZSBzb3VyY2VzIGxpc3QgaXMgdGlueSBhbmQgdGhpcyBpcyBhbHdheXMgY3VycmVudCAoc2xvdHMgZHlpbmcsIG9yIHNldmVyYWwgc2xvdHMgc2hhcmluZyBvbmUgVVJMIGFjcm9zcyB2YWxpZCB3aW5kb3dzLCBuZWVkIG5vIGJvb2trZWVwaW5nKS5cbiAgICBwcml2YXRlIHNsb3RGb3JTb3VyY2VzTGlzdEluZGV4KHNvdXJjZXNMaXN0SW5kZXg6IG51bWJlcik6IG51bWJlciB8IHVuZGVmaW5lZCB7XG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5zbG90U291cmNlc0xpc3RJbmRleGVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBpZiAodGhpcy5zbG90U291cmNlc0xpc3RJbmRleGVzW2ldID09PSBzb3VyY2VzTGlzdEluZGV4ICYmIHRoaXMuaXNMaXZlKGkpKSByZXR1cm4gaTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH1cblxuICAgIC8vIFRoZSBJQXJjaGl2ZXMgY3VycmVudGx5IGhvbGRpbmcgYW4gZW50cnkncyBieXRlczogdGhlIGxpdmUgc2xvdCB3aGVuIHRoZSBob2xkZXIgaXMgc3RpbGwgY29uZmlndXJlZCwgb3RoZXJ3aXNlIHJlc29sdmVkIChjYWNoZWQpIHN0cmFpZ2h0IGZyb20gaXRzIHBlcnNpc3RlZCBVUkwgLSB3aW5kb3dzL3JvdXRlcyBkZWNpZGUgd2hlbiBhIHNvdXJjZSBpcyBzY2FubmVkIG9yIHdyaXR0ZW4sIGJ1dCBmb3IgcmVhZGluZyBieXRlcyB3ZSBrbm93IGl0IGhvbGRzLCB0aGUgVVJMIGFsb25lIGlzIGVub3VnaFxuICAgIHByaXZhdGUgYXN5bmMgZ2V0RW50cnlIb2xkZXIoZW50cnk6IEluZGV4RW50cnkpOiBQcm9taXNlPElBcmNoaXZlcyB8IHVuZGVmaW5lZD4ge1xuICAgICAgICBsZXQgc2xvdCA9IHRoaXMuc2xvdEZvclNvdXJjZXNMaXN0SW5kZXgoZW50cnkuc291cmNlc0xpc3RJbmRleCk7XG4gICAgICAgIGlmIChzbG90ICE9PSB1bmRlZmluZWQpIHJldHVybiB0aGlzLnNvdXJjZXNbc2xvdF0uc291cmNlO1xuICAgICAgICBsZXQgdXJsID0gdGhpcy5zb3VyY2VzTGlzdC5nZXRVcmwoZW50cnkuc291cmNlc0xpc3RJbmRleCkgfHwgYXdhaXQgdGhpcy5zb3VyY2VzTGlzdC5nZXRVcmxSZWxvYWRpbmcoZW50cnkuc291cmNlc0xpc3RJbmRleCk7XG4gICAgICAgIGlmICghdXJsKSByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICByZXR1cm4gdGhpcy5jb25maWc/LnJlc29sdmVTb3VyY2VVcmw/Lih1cmwpO1xuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgbG9hZEluZGV4KCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBsZXQgW3dyaXRlVGltZXMsIHNpemVzLCBzb3VyY2VzTGlzdEluZGV4ZXNdID0gYXdhaXQgUHJvbWlzZS5hbGwoW1xuICAgICAgICAgICAgdGhpcy5pbmRleC5nZXRDb2x1bW4oXCJ3cml0ZVRpbWVcIiksXG4gICAgICAgICAgICB0aGlzLmluZGV4LmdldENvbHVtbihcInNpemVcIiksXG4gICAgICAgICAgICB0aGlzLmluZGV4LmdldENvbHVtbihcInNvdXJjZXNMaXN0SW5kZXhcIiksXG4gICAgICAgIF0pO1xuICAgICAgICBsZXQgc2l6ZU1hcCA9IG5ldyBNYXAoc2l6ZXMubWFwKHggPT4gW3gua2V5LCB4LnZhbHVlXSkpO1xuICAgICAgICBsZXQgc291cmNlc0xpc3RJbmRleE1hcCA9IG5ldyBNYXAoc291cmNlc0xpc3RJbmRleGVzLm1hcCh4ID0+IFt4LmtleSwgeC52YWx1ZV0pKTtcbiAgICAgICAgZm9yIChsZXQgZW50cnkgb2Ygd3JpdGVUaW1lcykge1xuICAgICAgICAgICAgbGV0IHNpemUgPSBzaXplTWFwLmdldChlbnRyeS5rZXkpO1xuICAgICAgICAgICAgbGV0IHNvdXJjZXNMaXN0SW5kZXggPSBzb3VyY2VzTGlzdEluZGV4TWFwLmdldChlbnRyeS5rZXkpO1xuICAgICAgICAgICAgLy8gRXhwbGljaXQgY2hlY2tzLCBhcyAwIGlzIGEgdmFsaWQgc2l6ZSBhbmQgYSB2YWxpZCBzb3VyY2VzTGlzdEluZGV4XG4gICAgICAgICAgICBpZiAoc2l6ZSA9PT0gdW5kZWZpbmVkIHx8IHNvdXJjZXNMaXN0SW5kZXggPT09IHVuZGVmaW5lZCkgY29udGludWU7XG4gICAgICAgICAgICAvLyBUaGUgcm91dGluZyBjb25maWcgaXMgb25seSBldmVyIHJlYWQgb2ZmIG91ciBvd24gZGlzayAoc2VlIHVwZGF0ZVNjYW5JbmRleCksIGFuZCBhIGxvYWRlZCBidWNrZXQgYWx3YXlzIGhhcyBpdCB0aGVyZSAtIGEgcGVyc2lzdGVkIGVudHJ5IHBvaW50aW5nIGVsc2V3aGVyZSBpcyBzdGFsZVxuICAgICAgICAgICAgaWYgKGVudHJ5LmtleSA9PT0gUk9VVElOR19GSUxFKSB7XG4gICAgICAgICAgICAgICAgc291cmNlc0xpc3RJbmRleCA9IHRoaXMuc291cmNlc0xpc3RJbmRleE9mU2xvdCgwKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGxldCBmdWxsOiBJbmRleEVudHJ5ID0geyB3cml0ZVRpbWU6IGVudHJ5LnZhbHVlLCBzaXplLCBzb3VyY2VzTGlzdEluZGV4LCBjaGFuZ2VkQXQ6IGVudHJ5LnRpbWUsIGxhc3RBY2Nlc3M6IGVudHJ5LnRpbWUgfTtcbiAgICAgICAgICAgIHRoaXMubWVtLnNldChlbnRyeS5rZXksIGZ1bGwpO1xuICAgICAgICAgICAgdGhpcy5jb3VudEVudHJ5KGZ1bGwsIDEpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBjb3VudEVudHJ5KGVudHJ5OiBJbmRleEVudHJ5IHwgdW5kZWZpbmVkLCBkaXJlY3Rpb246IG51bWJlcik6IHZvaWQge1xuICAgICAgICBpZiAoIWVudHJ5IHx8IGVudHJ5LnNpemUgPT09IDApIHJldHVybjtcbiAgICAgICAgdGhpcy5pbmRleEZpbGVDb3VudCArPSBkaXJlY3Rpb247XG4gICAgICAgIHRoaXMuaW5kZXhCeXRlQ291bnQgKz0gZW50cnkuc2l6ZSAqIGRpcmVjdGlvbjtcbiAgICAgICAgLy8gRW50cmllcyBjYW4gcmVmZXJlbmNlIGEgc291cmNlIG5vIGxvbmdlciBjb25maWd1cmVkIChyZWFkYWJsZSB2aWEgZ2V0RW50cnlIb2xkZXIsIGJ1dCB3aXRoIG5vIHNsb3QgdG8gY291bnQgdW5kZXIpXG4gICAgICAgIGxldCBzbG90ID0gdGhpcy5zbG90Rm9yU291cmNlc0xpc3RJbmRleChlbnRyeS5zb3VyY2VzTGlzdEluZGV4KTtcbiAgICAgICAgaWYgKHNsb3QgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgdGhpcy5zb3VyY2VGaWxlQ291bnRzW3Nsb3RdICs9IGRpcmVjdGlvbjtcbiAgICAgICAgICAgIHRoaXMuc291cmNlQnl0ZUNvdW50c1tzbG90XSArPSBlbnRyeS5zaXplICogZGlyZWN0aW9uO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBzZXRJbmRleEVudHJ5KGtleTogc3RyaW5nLCBlbnRyeTogeyB3cml0ZVRpbWU6IG51bWJlcjsgc2l6ZTogbnVtYmVyOyBzb3VyY2VzTGlzdEluZGV4OiBudW1iZXIgfSk6IHZvaWQge1xuICAgICAgICBsZXQgZnVsbDogSW5kZXhFbnRyeSA9IHsgLi4uZW50cnksIGNoYW5nZWRBdDogRGF0ZS5ub3coKSwgbGFzdEFjY2VzczogRGF0ZS5ub3coKSB9O1xuICAgICAgICB0aGlzLmNvdW50RW50cnkodGhpcy5tZW0uZ2V0KGtleSksIC0xKTtcbiAgICAgICAgdGhpcy5jb3VudEVudHJ5KGZ1bGwsIDEpO1xuICAgICAgICB0aGlzLm1lbS5zZXQoa2V5LCBmdWxsKTtcbiAgICAgICAgdGhpcy5kaXJ0eS5zZXQoa2V5LCBmdWxsKTtcbiAgICAgICAgdGhpcy5jb25maWc/Lm9uSW5kZXhDaGFuZ2VkPy4oa2V5KTtcbiAgICB9XG4gICAgcHJpdmF0ZSBkZWxldGVJbmRleEVudHJ5KGtleTogc3RyaW5nKTogdm9pZCB7XG4gICAgICAgIGxldCBleGlzdGluZyA9IHRoaXMubWVtLmdldChrZXkpO1xuICAgICAgICBpZiAoIWV4aXN0aW5nKSByZXR1cm47XG4gICAgICAgIHRoaXMuY291bnRFbnRyeShleGlzdGluZywgLTEpO1xuICAgICAgICB0aGlzLm1lbS5kZWxldGUoa2V5KTtcbiAgICAgICAgdGhpcy5kaXJ0eS5zZXQoa2V5LCB1bmRlZmluZWQpO1xuICAgIH1cblxuICAgIC8vIFRoZSBzbG90IHN0YXlzIGluIHRoZSBhcnJheXMgZm9yZXZlciAoaW5kZXggZW50cmllcyByZWZlcmVuY2Ugc291cmNlcyBieSBzbG90IG51bWJlcik7IGl0IGp1c3QgZ29lcyBkZWFkIC0gbG9vcHMgc3RvcCwgYW5kIGl0cyBpbmRleCBlbnRyaWVzIGRyb3AgKG90aGVyIHNvdXJjZXMnIHNjYW5zIHJlLWZpbmQgYW55IGNvcHkgdGhhdCdzIHN0aWxsIHJlYWNoYWJsZSB0aHJvdWdoIHRoZSBuZXcgY29uZmlnKVxuICAgIHByaXZhdGUgcmVtb3ZlU291cmNlKHNvdXJjZUluZGV4OiBudW1iZXIpOiB2b2lkIHtcbiAgICAgICAgbGV0IHN0YXRlID0gdGhpcy5zb3VyY2VTdGF0ZXNbc291cmNlSW5kZXhdO1xuICAgICAgICBsZXQgc291cmNlID0gdGhpcy5zb3VyY2VzW3NvdXJjZUluZGV4XS5zb3VyY2U7XG4gICAgICAgIHN0YXRlLmRlYWQgPSB0cnVlO1xuICAgICAgICBzdGF0ZS5zdG9wcGVkLnN0b3AgPSB0cnVlO1xuICAgICAgICBzdGF0ZS5zY2FuQ29tcGxldGUgPSB0cnVlO1xuICAgICAgICBzdGF0ZS5pbml0aWFsU2Nhbi5yZXNvbHZlKHVuZGVmaW5lZCk7XG4gICAgICAgIGxldCBzb3VyY2VzTGlzdEluZGV4ID0gdGhpcy5zbG90U291cmNlc0xpc3RJbmRleGVzW3NvdXJjZUluZGV4XTtcbiAgICAgICAgLy8gVGhlIHNhbWUgVVJMIGNhbiBiZSBhbm90aGVyIGxpdmUgc2xvdCAob25lIGVudHJ5IHBlciB2YWxpZCB3aW5kb3cpIC0gdGhlIGVuZHBvaW50IGlzIHN0aWxsIGNvbmZpZ3VyZWQsIHNvIGl0cyBlbnRyaWVzIHN0YXlcbiAgICAgICAgaWYgKHNvdXJjZXNMaXN0SW5kZXggIT09IHVuZGVmaW5lZCAmJiB0aGlzLnNsb3RGb3JTb3VyY2VzTGlzdEluZGV4KHNvdXJjZXNMaXN0SW5kZXgpID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIGxldCBkcm9wcGVkID0gMDtcbiAgICAgICAgICAgIGZvciAobGV0IFtrZXksIGVudHJ5XSBvZiB0aGlzLm1lbSkge1xuICAgICAgICAgICAgICAgIGlmIChlbnRyeS5zb3VyY2VzTGlzdEluZGV4ICE9PSBzb3VyY2VzTGlzdEluZGV4KSBjb250aW51ZTtcbiAgICAgICAgICAgICAgICB0aGlzLmRlbGV0ZUluZGV4RW50cnkoa2V5KTtcbiAgICAgICAgICAgICAgICBkcm9wcGVkKys7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhgUmVtb3ZlZCBzeW5jIHNvdXJjZSAke3NvdXJjZS5nZXREZWJ1Z05hbWUoKX0gKHN0b3JlICR7dGhpcy5mb2xkZXJ9KTogaXRzIHNjYW5zIGFyZSBzdG9wcGVkIGFuZCAke2Ryb3BwZWR9IGluZGV4IGVudHJpZXMgaXQgaGVsZCB3ZXJlIGRyb3BwZWRgKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBjb25zb2xlLmxvZyhgUmVtb3ZlZCBzeW5jIHNvdXJjZSAke3NvdXJjZS5nZXREZWJ1Z05hbWUoKX0gKHN0b3JlICR7dGhpcy5mb2xkZXJ9KTogaXRzIHNjYW5zIGFyZSBzdG9wcGVkIChpdHMgVVJMIGlzIHN0aWxsIHNlcnZlZCBieSBhbm90aGVyIHNsb3QsIHNvIGl0cyBpbmRleCBlbnRyaWVzIHN0YXkpYCk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBmbHVzaEluZGV4KCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBpZiAoIXRoaXMuZGlydHkuc2l6ZSkgcmV0dXJuO1xuICAgICAgICBsZXQgZGlydHkgPSB0aGlzLmRpcnR5O1xuICAgICAgICB0aGlzLmRpcnR5ID0gbmV3IE1hcCgpO1xuICAgICAgICBsZXQgd3JpdGVzOiBCbG9iSW5kZXhFbnRyeVtdID0gW107XG4gICAgICAgIGxldCBkZWxldGVzOiBzdHJpbmdbXSA9IFtdO1xuICAgICAgICBmb3IgKGxldCBba2V5LCBlbnRyeV0gb2YgZGlydHkpIHtcbiAgICAgICAgICAgIGlmIChlbnRyeSkge1xuICAgICAgICAgICAgICAgIHdyaXRlcy5wdXNoKHsga2V5LCB3cml0ZVRpbWU6IGVudHJ5LndyaXRlVGltZSwgc2l6ZTogZW50cnkuc2l6ZSwgc291cmNlc0xpc3RJbmRleDogZW50cnkuc291cmNlc0xpc3RJbmRleCB9KTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgZGVsZXRlcy5wdXNoKGtleSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHdyaXRlcy5sZW5ndGgpIGF3YWl0IHRoaXMuaW5kZXgud3JpdGVCYXRjaCh3cml0ZXMpO1xuICAgICAgICBpZiAoZGVsZXRlcy5sZW5ndGgpIGF3YWl0IHRoaXMuaW5kZXguZGVsZXRlQmF0Y2goZGVsZXRlcyk7XG4gICAgfVxuXG4gICAgLy8g4pSA4pSAIHZhbGlkYXRpb24gKGZyb20gdGhpcyBzdG9yZSdzIG93biByb3V0aW5nIGVudHJpZXMpIOKUgOKUgFxuXG4gICAgcHJpdmF0ZSBhc3luYyBhc3NlcnRNdXRhYmxlKGtleTogc3RyaW5nLCB3cml0ZVRpbWU6IG51bWJlcik6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBpZiAoIXRoaXMuZW50cmllcy5sZW5ndGgpIHJldHVybjtcbiAgICAgICAgbGV0IHNlbGYgPSBzZWxlY3RFbnRyeUF0KHRoaXMuZW50cmllcywgd3JpdGVUaW1lLCBnZXRSb3V0ZShrZXkpKTtcbiAgICAgICAgaWYgKCFzZWxmPy5pbW11dGFibGUpIHJldHVybjtcbiAgICAgICAgaWYgKGF3YWl0IHRoaXMuZ2V0SW5mbyh7IHBhdGg6IGtleSB9KSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBUaGlzIHN0b3JlIGlzIGltbXV0YWJsZSAoYXQgd3JpdGUgdGltZSAke3dyaXRlVGltZX0pIGFuZCAke0pTT04uc3RyaW5naWZ5KGtleSl9IGFscmVhZHkgZXhpc3RzLCBzbyBpdCBjYW5ub3QgYmUgd3JpdHRlbiB0byAoc3RvcmUgJHt0aGlzLmZvbGRlcn0pYCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBTZWUgU2V0Q29uZmlnLmludGVybmFsOiB0aGUgc3RhbXAgbXVzdCBsYW5kIGluc2lkZSBTT01FIHdpbmRvdytyb3V0ZSB0aGlzIHN0b3JlIGlzIGNvbmZpZ3VyZWQgZm9yIChhbnkgd2luZG93LCBpbmNsdWRpbmcgcGFzdCBvbmVzIC0gc3luY2hyb25pemF0aW9uIG1vdmVzIG9sZCBkYXRhKSwgc28gYSBjb25mdXNlZCBwZWVyIGNhbid0IHN0dWZmIGRhdGEgb250byBhIHN0b3JlIHRoYXQgd2FzIG5ldmVyIG1lYW50IHRvIGhvbGQgaXRcbiAgICBwcml2YXRlIGFzc2VydEludGVybmFsV3JpdGVBY2NlcHRlZChrZXk6IHN0cmluZywgd3JpdGVUaW1lOiBudW1iZXIsIHJvdXRlOiBudW1iZXIpOiB2b2lkIHtcbiAgICAgICAgaWYgKCF0aGlzLmVudHJpZXMubGVuZ3RoKSByZXR1cm47XG4gICAgICAgIGxldCBjb3ZlcmVkID0gdGhpcy5lbnRyaWVzLnNvbWUoeCA9PiB3cml0ZVRpbWUgPj0geC52YWxpZFdpbmRvd1swXSAmJiB3cml0ZVRpbWUgPCB4LnZhbGlkV2luZG93WzFdICYmIHJvdXRlQ29udGFpbnMoeC5yb3V0ZSwgcm91dGUpKTtcbiAgICAgICAgaWYgKCFjb3ZlcmVkKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEludGVybmFsIHdyaXRlIG9mICR7SlNPTi5zdHJpbmdpZnkoa2V5KX0gcmVqZWN0ZWQ6IHdyaXRlVGltZSAke3dyaXRlVGltZX0gKCR7bmV3IERhdGUod3JpdGVUaW1lKS50b0lTT1N0cmluZygpfSkgYXQgcm91dGUgJHtyb3V0ZX0gaXMgb3V0c2lkZSBldmVyeSB3aW5kb3cvcm91dGUgdGhpcyBzdG9yZSBpcyBjb25maWd1cmVkIGZvcjogJHtKU09OLnN0cmluZ2lmeSh0aGlzLmVudHJpZXMubWFwKHggPT4gKHsgdmFsaWRXaW5kb3c6IHgudmFsaWRXaW5kb3csIHJvdXRlOiB4LnJvdXRlIHx8IEZVTExfUk9VVEUgfSkpKX0gKHN0b3JlICR7dGhpcy5mb2xkZXJ9KWApO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLy8g4pSA4pSAIHN5bmNocm9uaXphdGlvbiDilIDilIBcblxuICAgIHByaXZhdGUgYXN5bmMgcnVuU291cmNlU3luYyhzb3VyY2VJbmRleDogbnVtYmVyKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGF3YWl0IHRoaXMucmVnaXN0ZXJTbG90KHNvdXJjZUluZGV4KTtcbiAgICAgICAgbGV0IHsgc291cmNlIH0gPSB0aGlzLnNvdXJjZXNbc291cmNlSW5kZXhdO1xuICAgICAgICBsZXQgc3RhdGUgPSB0aGlzLnNvdXJjZVN0YXRlc1tzb3VyY2VJbmRleF07XG4gICAgICAgIC8vIFJlYWQgbGl2ZSBmb3IgZXZlcnkgcGFzcywgbm90IGNhcHR1cmVkIC0gdXBkYXRlU291cmNlcyBjYW4gY2hhbmdlIGl0IHdoaWxlIGxvb3BzIHJ1blxuICAgICAgICBsZXQgbm9GdWxsU3luYyA9ICgpID0+IHRoaXMuc291cmNlc1tzb3VyY2VJbmRleF0ubm9GdWxsU3luYztcbiAgICAgICAgbGV0IGludGVybWVkaWF0ZSA9IHRoaXMuc291cmNlc1tzb3VyY2VJbmRleF0uaW50ZXJtZWRpYXRlO1xuICAgICAgICBsZXQgbGlzdGluZzogTWFwPHN0cmluZywgbnVtYmVyPiB8IHVuZGVmaW5lZDtcbiAgICAgICAgd2hpbGUgKCF0aGlzLnN0b3BwZWQuc3RvcCAmJiAhc3RhdGUuc3RvcHBlZC5zdG9wKSB7XG4gICAgICAgICAgICBpZiAodGhpcy5pc0RlYWRJbnRlcm1lZGlhdGUoc291cmNlSW5kZXgpKSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5sb2coYE5vdCBzY2FubmluZyBzeW5jIHNvdXJjZSAke3NvdXJjZS5nZXREZWJ1Z05hbWUoKX0gKHN0b3JlICR7dGhpcy5mb2xkZXJ9KTogaXQgaXMgYW4gaW50ZXJtZWRpYXRlIHdob3NlIHdpbmRvdyBhbHJlYWR5IGVuZGVkYCk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIGxldCBjb25maWcgPSBhd2FpdCBzb3VyY2UuZ2V0Q29uZmlnKCk7XG4gICAgICAgICAgICAgICAgc3RhdGUuc3VwcG9ydHNDaGFuZ2VzQWZ0ZXIgPSAhIWNvbmZpZy5zdXBwb3J0c0NoYW5nZXNBZnRlcjtcbiAgICAgICAgICAgICAgICBsaXN0aW5nID0gYXdhaXQgdGhpcy5zY2FuU291cmNlKHNvdXJjZUluZGV4KTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgICAgICBpZiAoaW50ZXJtZWRpYXRlKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoYEluaXRpYWwgc2NhbiBvZiBpbnRlcm1lZGlhdGUgc3luYyBzb3VyY2UgJHtzb3VyY2UuZ2V0RGVidWdOYW1lKCl9IChzdG9yZSAke3RoaXMuZm9sZGVyfSkgZmFpbGVkOyBub3QgcmV0cnlpbmcgKGludGVybWVkaWF0ZXMgYXJlIHRlbXBvcmFyeSBzd2l0Y2hvdmVyIHBvcnRzKTogJHsoZSBhcyBFcnJvcikuc3RhY2sgPz8gZX1gKTtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoYEluaXRpYWwgc2NhbiBvZiBzeW5jIHNvdXJjZSAke3NvdXJjZS5nZXREZWJ1Z05hbWUoKX0gZmFpbGVkLCByZXRyeWluZzpgLCBlKTtcbiAgICAgICAgICAgICAgICBhd2FpdCBkZWxheShTQ0FOX1JFVFJZX0RFTEFZKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBzdGF0ZS5zY2FuQ29tcGxldGUgPSB0cnVlO1xuICAgICAgICBzdGF0ZS5pbml0aWFsU2Nhbi5yZXNvbHZlKHVuZGVmaW5lZCk7XG4gICAgICAgIGlmICh0aGlzLnN0b3BwZWQuc3RvcCB8fCBzdGF0ZS5zdG9wcGVkLnN0b3ApIHJldHVybjtcbiAgICAgICAgLy8gQW4gaW50ZXJtZWRpYXRlIHRoYXQgbmV2ZXIgcHJvZHVjZWQgYSBsaXN0aW5nIGlzIGRlYWQgb3IgZHlpbmcgLSBwb2xsaW5nIGFuZCBjb3B5aW5nIGZyb20gaXQgd291bGQgb25seSBsb2cgZXJyb3JzXG4gICAgICAgIGlmIChpbnRlcm1lZGlhdGUgJiYgIWxpc3RpbmcpIHJldHVybjtcbiAgICAgICAgaWYgKGxpc3RpbmcpIHtcbiAgICAgICAgICAgIGF3YWl0IHRoaXMucmVjb25jaWxlU291cmNlKHNvdXJjZUluZGV4LCBsaXN0aW5nKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIW5vRnVsbFN5bmMoKSkge1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLmNvcHlTb3VyY2VGaWxlcyhzb3VyY2VJbmRleCk7XG4gICAgICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihgQ29weWluZyBmaWxlcyBmcm9tIHN5bmMgc291cmNlICR7c291cmNlLmdldERlYnVnTmFtZSgpfSBmYWlsZWQ6YCwgZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHN0YXRlLnN1cHBvcnRzQ2hhbmdlc0FmdGVyKSB7XG4gICAgICAgICAgICBydW5JbmZpbml0ZVBvbGwoQ0hBTkdFU19QT0xMX0lOVEVSVkFMLCBhc3luYyAoKSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuaXNEZWFkSW50ZXJtZWRpYXRlKHNvdXJjZUluZGV4KSkgcmV0dXJuO1xuICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMucG9sbENoYW5nZXMoc291cmNlSW5kZXgpO1xuICAgICAgICAgICAgICAgIGlmICghbm9GdWxsU3luYygpKSBhd2FpdCB0aGlzLmNvcHlTb3VyY2VGaWxlcyhzb3VyY2VJbmRleCk7XG4gICAgICAgICAgICB9LCBzdGF0ZS5zdG9wcGVkKTtcbiAgICAgICAgICAgIC8vIENoYW5nZSBwb2xscyBvbmx5IHNob3cgd2hhdCB0aGUgc291cmNlIEhBUywgbmV2ZXIgd2hhdCBpdCdzIG1pc3NpbmcsIHNvIHB1c2hlcyBydW4gb24gdGhlIGZ1bGwtcmVzY2FuIGNhZGVuY2UgKGZpbmRJbmZvIG9uIGFuIGluZGV4LWJhY2tlZCBzb3VyY2UgaXMgY2hlYXApXG4gICAgICAgICAgICBydW5JbmZpbml0ZVBvbGwoRlVMTF9SRVNDQU5fSU5URVJWQUwsIGFzeW5jICgpID0+IHtcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5pc0RlYWRJbnRlcm1lZGlhdGUoc291cmNlSW5kZXgpKSByZXR1cm47XG4gICAgICAgICAgICAgICAgbGV0IGZpbGVzID0gYXdhaXQgc291cmNlLmZpbmRJbmZvKFwiXCIpO1xuICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMucmVjb25jaWxlU291cmNlKHNvdXJjZUluZGV4LCBuZXcgTWFwKGZpbGVzLm1hcCh4ID0+IFt4LnBhdGgsIHguY3JlYXRlVGltZV0pKSk7XG4gICAgICAgICAgICB9LCBzdGF0ZS5zdG9wcGVkKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJ1bkluZmluaXRlUG9sbChGVUxMX1JFU0NBTl9VTklOREVYRURfSU5URVJWQUwsIGFzeW5jICgpID0+IHtcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5pc0RlYWRJbnRlcm1lZGlhdGUoc291cmNlSW5kZXgpKSByZXR1cm47XG4gICAgICAgICAgICAgICAgbGV0IHJlc2NhbiA9IGF3YWl0IHRoaXMuc2NhblNvdXJjZShzb3VyY2VJbmRleCk7XG4gICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5yZWNvbmNpbGVTb3VyY2Uoc291cmNlSW5kZXgsIHJlc2Nhbik7XG4gICAgICAgICAgICAgICAgaWYgKCFub0Z1bGxTeW5jKCkpIGF3YWl0IHRoaXMuY29weVNvdXJjZUZpbGVzKHNvdXJjZUluZGV4KTtcbiAgICAgICAgICAgIH0sIHN0YXRlLnN0b3BwZWQpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLy8gQW4gaW50ZXJtZWRpYXRlIGlzIGEgZGVwbG95IHN3aXRjaG92ZXIncyB0ZW1wb3JhcnkgYWx0ZXJuYXRlIHBvcnQ6IG9uY2UgaXRzIHdpbmRvdyBpcyBwYXN0LCB0aGUgcG9ydCBpcyBnb25lIGZvciBnb29kLCBzbyBzY2FubmluZyBpdCAob3IgcmV0cnlpbmcgYSBmYWlsZWQgc2NhbikgY2FuIG5ldmVyIHN1Y2NlZWQgLSBpdCB3b3VsZCBqdXN0IGxvZyBlcnJvcnMgZm9yZXZlci4gKERlYWQgb25seSBvbmNlIEVWRVJZIHdpbmRvdyBoYXMgZW5kZWQgLSBhbiBpbnRlcm1lZGlhdGUgbm9ybWFsbHkgaGFzIGp1c3Qgb25lLilcbiAgICBwcml2YXRlIGlzRGVhZEludGVybWVkaWF0ZShzb3VyY2VJbmRleDogbnVtYmVyKTogYm9vbGVhbiB7XG4gICAgICAgIGxldCB7IGludGVybWVkaWF0ZSwgdmFsaWRXaW5kb3dzIH0gPSB0aGlzLnNvdXJjZXNbc291cmNlSW5kZXhdO1xuICAgICAgICByZXR1cm4gISFpbnRlcm1lZGlhdGUgJiYgdmFsaWRXaW5kb3dzLmV2ZXJ5KHcgPT4gd1sxXSA8PSBEYXRlLm5vdygpKTtcbiAgICB9XG5cbiAgICAvLyBGdWxsIG1ldGFkYXRhIHNjYW4gKHNpemUsIHdyaXRlVGltZSwgcGF0aCkgb2Ygb25lIHNvdXJjZSwgYXBwbGllZCB0byB0aGUgaW5kZXguIFJldHVybnMgdGhlIHNvdXJjZSdzIGxpc3RpbmcgKHBhdGggLT4gd3JpdGUgdGltZSksIHdoaWNoIHJlY29uY2lsZVNvdXJjZSB1c2VzIGZvciB0aGUgcHVzaCBkaXJlY3Rpb24uXG4gICAgcHJpdmF0ZSBhc3luYyBzY2FuU291cmNlKHNvdXJjZUluZGV4OiBudW1iZXIpOiBQcm9taXNlPE1hcDxzdHJpbmcsIG51bWJlcj4+IHtcbiAgICAgICAgbGV0IHsgc291cmNlLCByb3V0ZSB9ID0gdGhpcy5zb3VyY2VzW3NvdXJjZUluZGV4XTtcbiAgICAgICAgbGV0IHN0YXRlID0gdGhpcy5zb3VyY2VTdGF0ZXNbc291cmNlSW5kZXhdO1xuICAgICAgICBsZXQgc2NhblN0YXJ0ID0gRGF0ZS5ub3coKTtcbiAgICAgICAgbGV0IGFjdGl2aXR5OiBTeW5jQWN0aXZpdHkgPSB7IHR5cGU6IFwibWV0YWRhdGFTY2FuXCIsIHNvdXJjZURlYnVnTmFtZTogc291cmNlLmdldERlYnVnTmFtZSgpLCBzdGFydFRpbWU6IHNjYW5TdGFydCB9O1xuICAgICAgICB0aGlzLnN5bmNBY3Rpdml0aWVzLmFkZChhY3Rpdml0eSk7XG4gICAgICAgIGNvbnNvbGUubG9nKGBNZXRhZGF0YSBzY2FuIG9mICR7c291cmNlLmdldERlYnVnTmFtZSgpfSBzdGFydGluZyAoc3RvcmUgJHt0aGlzLmZvbGRlcn0pYCk7XG4gICAgICAgIGxldCBwcm9ncmVzc1RpbWVyID0gc2V0SW50ZXJ2YWwoKCkgPT4ge1xuICAgICAgICAgICAgY29uc29sZS5sb2coYE1ldGFkYXRhIHNjYW4gb2YgJHtzb3VyY2UuZ2V0RGVidWdOYW1lKCl9IHN0aWxsIHJ1bm5pbmcgKCR7TWF0aC5yb3VuZCgoRGF0ZS5ub3coKSAtIHNjYW5TdGFydCkgLyAxMDAwKX1zLCBzdG9yZSAke3RoaXMuZm9sZGVyfSlgKTtcbiAgICAgICAgfSwgU1lOQ19QUk9HUkVTU19MT0dfSU5URVJWQUwpO1xuICAgICAgICAocHJvZ3Jlc3NUaW1lciBhcyB7IHVucmVmPzogKCkgPT4gdm9pZCB9KS51bnJlZj8uKCk7XG4gICAgICAgIC8vIFRoZSBsaXN0aW5nIHJlcXVlc3QgZGVsaWJlcmF0ZWx5IHRha2VzIG5vIHRpbWUgb3Igcm91dGUgZmlsdGVyczogb3VyIHNsb3dlc3Qgc291cmNlcyAoYmFja2JsYXplKSBzdXBwb3J0IG5laXRoZXIsIHNvIGZpbHRlcmluZyB3b3VsZCBoYXBwZW4gYWZ0ZXIgdGhlIGZ1bGwgZmV0Y2ggYW55d2F5IC0gbGl0dGxlIGJlbmVmaXQsIG1vcmUgcm9vbSBmb3IgZGVzeW5jaHJvbml6YXRpb24uIEFuZCBpZiBhIGZ1bGwgbGlzdGluZyBldmVyIGJlY29tZXMgdG9vIGJpZyB0byBzZW5kIG92ZXIgdGhlIG5ldHdvcmssIGl0IGlzIGFsc28gdG9vIGJpZyBmb3IgdGhlIHJlY2VpdmluZyBwcm9jZXNzIHRvIGhvbGQgaW4gbWVtb3J5IC0gdGhlIGZpeCBpcyBtb3JlIHJvdXRpbmcgc2hhcmRzIChlYWNoIHN0b3JpbmcgYW5kIHNlbmRpbmcgbGVzcyksIG5vdCBmaWx0ZXJpbmcuXG4gICAgICAgIGxldCBmaWxlczogQXJjaGl2ZUZpbGVJbmZvW107XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBmaWxlcyA9IGF3YWl0IHNvdXJjZS5maW5kSW5mbyhcIlwiKTtcbiAgICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgICAgIGNsZWFySW50ZXJ2YWwocHJvZ3Jlc3NUaW1lcik7XG4gICAgICAgICAgICB0aGlzLnN5bmNBY3Rpdml0aWVzLmRlbGV0ZShhY3Rpdml0eSk7XG4gICAgICAgIH1cbiAgICAgICAgLy8gVGhlIHNvdXJjZSBtYXkgaGF2ZSBiZWVuIHJlbW92ZWQgd2hpbGUgdGhlIGxpc3Rpbmcgd2FzIGluIGZsaWdodDsgaXRzIHJlc3VsdHMgYXJlIGRlYWRcbiAgICAgICAgaWYgKHN0YXRlLnN0b3BwZWQuc3RvcCkgcmV0dXJuIG5ldyBNYXAoKTtcbiAgICAgICAgbGV0IGluZGV4U2l6ZUJlZm9yZSA9IHRoaXMubWVtLnNpemU7XG4gICAgICAgIGxldCBzZWVuID0gbmV3IE1hcDxzdHJpbmcsIG51bWJlcj4oKTtcbiAgICAgICAgbGV0IHRhbGx5ID0gbmV3U2NhblRhbGx5KCk7XG4gICAgICAgIGxldCBuZXdQYXRocyA9IDA7XG4gICAgICAgIGZvciAobGV0IGZpbGUgb2YgZmlsZXMpIHtcbiAgICAgICAgICAgIHNlZW4uc2V0KGZpbGUucGF0aCwgZmlsZS5jcmVhdGVUaW1lKTtcbiAgICAgICAgICAgIGlmICghdGhpcy5tZW0uaGFzKGZpbGUucGF0aCkpIHtcbiAgICAgICAgICAgICAgICBuZXdQYXRocysrO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGFsbHlbdGhpcy51cGRhdGVTY2FuSW5kZXgoc291cmNlSW5kZXgsIGZpbGUpXSsrO1xuICAgICAgICB9XG4gICAgICAgIHN0YXRlLnNjYW5uZWRDb3VudCA9IGZpbGVzLmxlbmd0aDtcbiAgICAgICAgLy8gSW5kZXggZW50cmllcyB0aGlzIHNvdXJjZSB3YXMgdGhlIGhvbGRlciBvZiwgYnV0IHRoYXQgdmFuaXNoZWQgZnJvbSBpdCAoZS5nLiBkZWxldGVkIHdoaWxlIHdlIHdlcmUgb2ZmbGluZSksIGNvbWUgb3V0IG9mIHRoZSBpbmRleC4gRW50cmllcyBjaGFuZ2VkIGFmdGVyIHRoZSBzY2FuIHN0YXJ0ZWQgYXJlIGtlcHQg4oCUIHRoZSBzY2FuIGxpc3RpbmcgbWF5IHNpbXBseSBwcmVkYXRlIHRoZW0uIFRvbWJzdG9uZXMgaGF2ZSBubyBwaHlzaWNhbCBmaWxlIGZvciBhIGxpc3RpbmcgdG8gdm91Y2ggZm9yLCBzbyB0aGV5J3JlIGV4ZW1wdCAoY2xlYW51cFRvbWJzdG9uZXMgZXhwaXJlcyB0aGVtIGluc3RlYWQpLlxuICAgICAgICBsZXQgcmVtb3ZlZEZyb21JbmRleCA9IDA7XG4gICAgICAgIGxldCBtaXNzaW5nT25Tb3VyY2UgPSAwO1xuICAgICAgICBsZXQgc2Nhbm5lZFNvdXJjZXNMaXN0SW5kZXggPSB0aGlzLnNvdXJjZXNMaXN0SW5kZXhPZlNsb3Qoc291cmNlSW5kZXgpO1xuICAgICAgICBmb3IgKGxldCBba2V5LCBlbnRyeV0gb2YgdGhpcy5tZW0pIHtcbiAgICAgICAgICAgIGlmIChzZWVuLmhhcyhrZXkpKSBjb250aW51ZTtcbiAgICAgICAgICAgIGlmIChlbnRyeS5zb3VyY2VzTGlzdEluZGV4ID09PSBzY2FubmVkU291cmNlc0xpc3RJbmRleCAmJiBlbnRyeS5zaXplICE9PSAwICYmIGVudHJ5LmNoYW5nZWRBdCA8IHNjYW5TdGFydCkge1xuICAgICAgICAgICAgICAgIHRoaXMuZGVsZXRlSW5kZXhFbnRyeShrZXkpO1xuICAgICAgICAgICAgICAgIHJlbW92ZWRGcm9tSW5kZXgrKztcbiAgICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIENvdW50ZWQgb25seSB3aGVuIHRoZSBzb3VyY2UgU0hPVUxEIGhvbGQgdGhlIGVudHJ5IChpdHMgcm91dGUgbWF0Y2hlcykgLSB0aGVzZSBhcmUgd2hhdCB0aGUgcmVjb25jaWxlIHBhc3MgcHVzaGVzIHRvIGl0ICh3aGljaCBhbHNvIGlnbm9yZXMgdGhlIHZhbGlkIHdpbmRvdzogc3luY2hyb25pemF0aW9uIG1vdmVzIGV4aXN0aW5nIHZhbHVlcywgdGhlIHdpbmRvdyBvbmx5IHJvdXRlcyBmcmVzaCB3cml0ZXMpXG4gICAgICAgICAgICBpZiAoZW50cnkuc2l6ZSA9PT0gMCB8fCBrZXkgPT09IFJPVVRJTkdfRklMRSkgY29udGludWU7XG4gICAgICAgICAgICBpZiAoIXJvdXRlQ29udGFpbnMocm91dGUsIGdldFJvdXRlKGtleSkpKSBjb250aW51ZTtcbiAgICAgICAgICAgIG1pc3NpbmdPblNvdXJjZSsrO1xuICAgICAgICB9XG4gICAgICAgIC8vIFBlcmNlbnRhZ2VzIGFyZSBvZiB0aGUgdW5pb24gb2YgYm90aCBzaWRlcyAob3VyIGluZGV4ICsgdGhlaXIgbGlzdGluZyksIHNvIGV2ZXJ5IGNvdW50IGhhcyBhIHN0YWJsZSBkZW5vbWluYXRvclxuICAgICAgICBsZXQgdW5pb24gPSBpbmRleFNpemVCZWZvcmUgKyBuZXdQYXRocztcbiAgICAgICAgbGV0IHBjdCA9IChuOiBudW1iZXIpID0+IGAke01hdGgucm91bmQobiAvIE1hdGgubWF4KHVuaW9uLCAxKSAqIDEwMDApIC8gMTB9JWA7XG4gICAgICAgIGNvbnNvbGUubG9nKGBNZXRhZGF0YSBzY2FuIG9mICR7c291cmNlLmdldERlYnVnTmFtZSgpfSBmaW5pc2hlZCBpbiAke01hdGgucm91bmQoKERhdGUubm93KCkgLSBzY2FuU3RhcnQpIC8gMTAwMCl9cyAoc3RvcmUgJHt0aGlzLmZvbGRlcn0pOiAke2ZpbGVzLmxlbmd0aH0gbGlzdGVkIHZzICR7aW5kZXhTaXplQmVmb3JlfSBpbmRleGVkICh1bmlvbiAke3VuaW9ufSk6ICR7Zm9ybWF0U2NhblRhbGx5KHRhbGx5LCB1bmlvbil9LCAke21pc3NpbmdPblNvdXJjZX0gaW4gaW5kZXggYnV0IG1pc3Npbmcgb24gc291cmNlICgke3BjdChtaXNzaW5nT25Tb3VyY2UpfSksICR7cmVtb3ZlZEZyb21JbmRleH0gcmVtb3ZlZCBmcm9tIGluZGV4ICgke3BjdChyZW1vdmVkRnJvbUluZGV4KX0pYCk7XG4gICAgICAgIHN0YXRlLmNoYW5nZXNBZnRlclRpbWUgPSBNYXRoLm1heChzdGF0ZS5jaGFuZ2VzQWZ0ZXJUaW1lLCBzY2FuU3RhcnQgLSBDSEFOR0VTX1BPTExfT1ZFUkxBUCk7XG4gICAgICAgIHJldHVybiBzZWVuO1xuICAgIH1cblxuICAgIC8vIFRoZSBwdXNoIGRpcmVjdGlvbiBvZiBzeW5jaHJvbml6YXRpb246IGV2ZXJ5dGhpbmcgd2Uga25vdyB0aGF0IHRoZSBzb3VyY2UgaXMgbWlzc2luZyAob3IgaG9sZHMgYW4gb2xkZXIgY29weSBvZikgaXMgd3JpdHRlbiB0byBpdCDigJQgaW5jbHVkaW5nIGRlbGV0aW9ucywgYXMgdG9tYnN0b25lIHdyaXRlcy4gVGhpcyBpcyB3aGF0IGhlYWxzIGEgc291cmNlIHdob3NlIGJhY2tncm91bmQgd3JpdGVzIGZhaWxlZCAoZS5nLiBpdCB3YXMgZG93bik6IHRoZSBuZXh0IHNjYW4gc2VlcyB3aGF0J3MgbWlzc2luZyBhbmQgcmUtc2VuZHMgaXQuIEEgZmFpbGluZyBmaWxlIGlzIHNraXBwZWQsIG5vdCBmYXRhbCAoaW1tdXRhYmxlIHRhcmdldHMgYXJlIGhhbmRsZWQgYnkgZm9yY2VTZXRJbW11dGFibGUsIGFuZCBvbmUgdW5yZWFkYWJsZSB2YWx1ZSBtdXN0IG5vdCBzdG9wIHRoZSByZXN0IG9mIHRoZSBwYXNzKSAtIG9ubHkgYSBydW4gb2YgY29uc2VjdXRpdmUgZmFpbHVyZXMgKHRoZSBzb3VyY2UgaXRzZWxmIGlzIGRvd24pIGFib3J0cyB1bnRpbCB0aGUgbmV4dCBzY2FuIGN5Y2xlLlxuICAgIHByaXZhdGUgYXN5bmMgcmVjb25jaWxlU291cmNlKHNvdXJjZUluZGV4OiBudW1iZXIsIGxpc3Rpbmc6IE1hcDxzdHJpbmcsIG51bWJlcj4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgbGV0IHsgc291cmNlLCB2YWxpZFdpbmRvd3MsIHJvdXRlIH0gPSB0aGlzLnNvdXJjZXNbc291cmNlSW5kZXhdO1xuICAgICAgICBsZXQgc3RhdGUgPSB0aGlzLnNvdXJjZVN0YXRlc1tzb3VyY2VJbmRleF07XG4gICAgICAgIGxldCBhY2NlcHRzV3JpdGVzID0gd2luZG93c0FjY2VwdFdyaXRlcyh2YWxpZFdpbmRvd3MpO1xuICAgICAgICBsZXQgdGFyZ2V0U291cmNlc0xpc3RJbmRleCA9IHRoaXMuc291cmNlc0xpc3RJbmRleE9mU2xvdChzb3VyY2VJbmRleCk7XG4gICAgICAgIGxldCBwdXNoZWQgPSAwO1xuICAgICAgICBsZXQgZmFpbGVkID0gMDtcbiAgICAgICAgbGV0IGNvbnNlY3V0aXZlRmFpbHVyZXMgPSAwO1xuICAgICAgICBsZXQgZXJyb3JzOiBzdHJpbmdbXSA9IFtdO1xuICAgICAgICBsZXQgYWJvcnRlZCA9IGZhbHNlO1xuICAgICAgICBmb3IgKGxldCBba2V5LCBlbnRyeV0gb2YgdGhpcy5tZW0pIHtcbiAgICAgICAgICAgIGlmICh0aGlzLnN0b3BwZWQuc3RvcCB8fCBzdGF0ZS5zdG9wcGVkLnN0b3ApIHJldHVybjtcbiAgICAgICAgICAgIGlmIChlbnRyeS5zb3VyY2VzTGlzdEluZGV4ID09PSB0YXJnZXRTb3VyY2VzTGlzdEluZGV4KSBjb250aW51ZTtcbiAgICAgICAgICAgIC8vIFRoZSByb3V0aW5nIGZpbGUgaXMgTkVWRVIgc3luY2hyb25pemVkIGJldHdlZW4gc3RvcmFnZSBub2RlcyAtIGl0IGlzIG9ubHkgZXZlciB3cml0dGVuIGRpcmVjdGx5IHRvIGVhY2ggbm9kZSwgYW5kIG9ubHkgZXZlciByZWFkIG9mZiBvdXIgb3duIGRpc2tcbiAgICAgICAgICAgIGlmIChrZXkgPT09IFJPVVRJTkdfRklMRSkgY29udGludWU7XG4gICAgICAgICAgICBpZiAoIWFjY2VwdHNXcml0ZXMpIGNvbnRpbnVlO1xuICAgICAgICAgICAgaWYgKCFyb3V0ZUNvbnRhaW5zKHJvdXRlLCBnZXRSb3V0ZShrZXkpKSkgY29udGludWU7XG4gICAgICAgICAgICBsZXQgdGhlaXJUaW1lID0gbGlzdGluZy5nZXQoa2V5KTtcbiAgICAgICAgICAgIGlmICh0aGVpclRpbWUgIT09IHVuZGVmaW5lZCAmJiB0aGVpclRpbWUgPj0gZW50cnkud3JpdGVUaW1lKSBjb250aW51ZTtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgaWYgKGVudHJ5LnNpemUgPT09IDApIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gQSBkZWxldGlvbiBvbmx5IG5lZWRzIHB1c2hpbmcgd2hpbGUgdGhlIHNvdXJjZSBzdGlsbCBob2xkcyBhbiBvbGRlciBjb3B5LiBJdCB0cmF2ZWxzIGFzIGRlbCAobmV2ZXIgYXMgYW4gZW1wdHkgc2V0IC0gc2V0IHJlamVjdHMgZW1wdHkgYnVmZmVycyksIHdpdGggdGhlIE9SSUdJTkFMIGRlbGV0aW9uIHRpbWUgc28gb3JkZXJpbmcgc3Vydml2ZXMuXG4gICAgICAgICAgICAgICAgICAgIGlmICh0aGVpclRpbWUgPT09IHVuZGVmaW5lZCkgY29udGludWU7XG4gICAgICAgICAgICAgICAgICAgIGF3YWl0IHNvdXJjZS5kZWwoa2V5LCB7IGxhc3RNb2RpZmllZDogZW50cnkud3JpdGVUaW1lLCBub0NoZWNrczogdHJ1ZSwgaW50ZXJuYWw6IHRydWUgfSk7XG4gICAgICAgICAgICAgICAgICAgIHB1c2hlZCsrO1xuICAgICAgICAgICAgICAgICAgICBjb25zZWN1dGl2ZUZhaWx1cmVzID0gMDtcbiAgICAgICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGxldCBob2xkZXIgPSBhd2FpdCB0aGlzLmdldEVudHJ5SG9sZGVyKGVudHJ5KTtcbiAgICAgICAgICAgICAgICBpZiAoIWhvbGRlcikgY29udGludWU7XG4gICAgICAgICAgICAgICAgbGV0IGNvcGllZCA9IGF3YWl0IGNvcHlBcmNoaXZlRmlsZSh7IGZyb206IGhvbGRlciwgdG86IHNvdXJjZSwgcGF0aDoga2V5LCBzaXplOiBlbnRyeS5zaXplLCB3cml0ZVRpbWU6IGVudHJ5LndyaXRlVGltZSwgZm9yY2VTZXRJbW11dGFibGU6IHRydWUsIG5vQ2hlY2tzOiB0cnVlLCBpbnRlcm5hbDogdHJ1ZSB9KTtcbiAgICAgICAgICAgICAgICBpZiAoIWNvcGllZCkgY29udGludWU7XG4gICAgICAgICAgICAgICAgcHVzaGVkKys7XG4gICAgICAgICAgICAgICAgY29uc2VjdXRpdmVGYWlsdXJlcyA9IDA7XG4gICAgICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICAgICAgZmFpbGVkKys7XG4gICAgICAgICAgICAgICAgY29uc2VjdXRpdmVGYWlsdXJlcysrO1xuICAgICAgICAgICAgICAgIGlmIChlcnJvcnMubGVuZ3RoIDwgUkVDT05DSUxFX0VSUk9SX0xPR19MSU1JVCkge1xuICAgICAgICAgICAgICAgICAgICBlcnJvcnMucHVzaChgJHtrZXl9OiAkeyhlIGFzIEVycm9yKS5zdGFjayA/PyBlfWApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAoY29uc2VjdXRpdmVGYWlsdXJlcyA+PSBSRUNPTkNJTEVfTUFYX0NPTlNFQ1VUSVZFX0ZBSUxVUkVTKSB7XG4gICAgICAgICAgICAgICAgICAgIGFib3J0ZWQgPSB0cnVlO1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGZhaWxlZCkge1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcihgUmVjb25jaWxpbmcgc3luYyBzb3VyY2UgJHtzb3VyY2UuZ2V0RGVidWdOYW1lKCl9IChzdG9yZSAke3RoaXMuZm9sZGVyfSk6IHB1c2hlZCAke3B1c2hlZH0gZmlsZXMsICR7ZmFpbGVkfSBmYWlsZWQke2Fib3J0ZWQgJiYgYCBiZWZvcmUgYWJvcnRpbmcgdGhlIHBhc3MgKCR7Y29uc2VjdXRpdmVGYWlsdXJlc30gY29uc2VjdXRpdmUgZmFpbHVyZXMgLSB0aGUgc291cmNlIGxvb2tzIGRvd247IHRoZSBuZXh0IHNjYW4gY3ljbGUgcmV0cmllcylgIHx8IFwiXCJ9LiBGaXJzdCBlcnJvcnM6ICR7ZXJyb3JzLmpvaW4oXCIgfCBcIil9YCk7XG4gICAgICAgIH0gZWxzZSBpZiAocHVzaGVkKSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhgUmVjb25jaWxlZCBzeW5jIHNvdXJjZSAke3NvdXJjZS5nZXREZWJ1Z05hbWUoKX0gKHN0b3JlICR7dGhpcy5mb2xkZXJ9KTogcHVzaGVkICR7cHVzaGVkfSBmaWxlcyBpdCB3YXMgbWlzc2luZyBvciBoZWxkIG9sZGVyIGNvcGllcyBvZmApO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSB1cGRhdGVTY2FuSW5kZXgoc291cmNlSW5kZXg6IG51bWJlciwgZmlsZTogQXJjaGl2ZUZpbGVJbmZvKTogU2Nhbk91dGNvbWUge1xuICAgICAgICAvLyBBbiBpbi1mbGlnaHQgc2NhbiBjYW4gb3V0bGl2ZSBpdHMgc291cmNlJ3MgcmVtb3ZhbDsgaXRzIHJlc3VsdHMgYXJlIGRlYWRcbiAgICAgICAgaWYgKCF0aGlzLmlzTGl2ZShzb3VyY2VJbmRleCkpIHJldHVybiBcImZpbHRlcmVkXCI7XG4gICAgICAgIGlmIChmaWxlLnBhdGggPT09IFJPVVRJTkdfRklMRSkge1xuICAgICAgICAgICAgLy8gVGhlIHJvdXRpbmcgY29uZmlnIGlzIE5FVkVSIHB1bGxlZCBmcm9tIG90aGVyIHNvdXJjZXMgLSBpdCBvbmx5IGV2ZXIgYXJyaXZlcyBhcyBhbiBleHBsaWNpdCwgdmVyc2lvbi12YWxpZGF0ZWQgd3JpdGUsIGFuZCBpcyBvbmx5IGV2ZXIgcmVhZCBvZmYgb3VyIG93biBkaXNrLiBSb3V0ZSBhbmQgdmFsaWQtd2luZG93IGZpbHRlcnMgY2FuJ3QgcG9zc2libHkgYXBwbHkgdG8gaXQgZWl0aGVyOiBpdCBpcyB0aGUgZmlsZSBERUZJTklORyB0aGVtLCBzbyBmaWx0ZXJpbmcgaXQgd291bGQgbWVhbiBjZXJ0YWluIHNvdXJjZXMgY291bGQgbmV2ZXIgaGF2ZSB0aGVpciByb3V0aW5nIGNvbmZpZyB1cGRhdGVkLCBldmVyLlxuICAgICAgICAgICAgaWYgKHNvdXJjZUluZGV4ICE9PSAwKSByZXR1cm4gXCJmaWx0ZXJlZFwiO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gVGhlIHZhbGlkIHdpbmRvdyBpcyBkZWxpYmVyYXRlbHkgTk9UIGFwcGxpZWQgaGVyZTogaXQgZGVjaWRlcyB3aGVyZSBXUklURVMgcm91dGUsIGJ1dCBhIHNjYW4gaXMgdXMgYXNraW5nIGEgc291cmNlIHdoYXQgaXQgYWxyZWFkeSBob2xkcyAtIGV4aXN0aW5nIHZhbHVlcyBzeW5jaHJvbml6ZSByZWdhcmRsZXNzIG9mIHRoZSB3aW5kb3cgKHRoZSBzYW1lIHJlYXNvbmluZyB0aGF0IGxldHMgc3luY2hyb25pemF0aW9uIGlnbm9yZSB0aGUgaW1tdXRhYmxlIGZsYWcpLiBPbmx5IHRoZSByb3V0ZSBmaWx0ZXJzOiBhIHBhcnRpYWxseS1vdmVybGFwcGluZyBzaGFyZCdzIGxpc3RpbmcgbGVnaXRpbWF0ZWx5IGluY2x1ZGVzIGtleXMgdGhhdCBhcmVuJ3Qgb3Vycy5cbiAgICAgICAgICAgIGxldCB7IHJvdXRlIH0gPSB0aGlzLnNvdXJjZXNbc291cmNlSW5kZXhdO1xuICAgICAgICAgICAgaWYgKCFyb3V0ZUNvbnRhaW5zKHJvdXRlLCBnZXRSb3V0ZShmaWxlLnBhdGgpKSkgcmV0dXJuIFwiZmlsdGVyZWRcIjtcbiAgICAgICAgfVxuICAgICAgICBsZXQgZXhpc3RpbmcgPSB0aGlzLm1lbS5nZXQoZmlsZS5wYXRoKTtcbiAgICAgICAgLy8gVGhlIGhpZ2hlc3Qgd3JpdGUgdGltZSB3aW5zIGFjcm9zcyBhbGwgc291cmNlcyAodGllcyBrZWVwIHRoZSBleGlzdGluZyBlbnRyeSlcbiAgICAgICAgaWYgKGV4aXN0aW5nICYmIGZpbGUuY3JlYXRlVGltZSA8PSBleGlzdGluZy53cml0ZVRpbWUpIHJldHVybiBcInVuY2hhbmdlZFwiO1xuICAgICAgICB0aGlzLnNldEluZGV4RW50cnkoZmlsZS5wYXRoLCB7IHdyaXRlVGltZTogZmlsZS5jcmVhdGVUaW1lLCBzaXplOiBmaWxlLnNpemUsIHNvdXJjZXNMaXN0SW5kZXg6IHRoaXMuc291cmNlc0xpc3RJbmRleE9mU2xvdChzb3VyY2VJbmRleCkgfSk7XG4gICAgICAgIGlmIChmaWxlLnNpemUgPT09IDApIHJldHVybiBcInRvbWJzdG9uZVwiO1xuICAgICAgICBpZiAoZXhpc3RpbmcpIHJldHVybiBcInVwZGF0ZWRcIjtcbiAgICAgICAgcmV0dXJuIFwibmV3XCI7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBwb2xsQ2hhbmdlcyhzb3VyY2VJbmRleDogbnVtYmVyKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGxldCB7IHNvdXJjZSwgcm91dGUgfSA9IHRoaXMuc291cmNlc1tzb3VyY2VJbmRleF07XG4gICAgICAgIGxldCBzdGF0ZSA9IHRoaXMuc291cmNlU3RhdGVzW3NvdXJjZUluZGV4XTtcbiAgICAgICAgbGV0IHBvbGxTdGFydCA9IERhdGUubm93KCk7XG4gICAgICAgIGxldCBjaGFuZ2VzID0gYXdhaXQgc291cmNlLmdldENoYW5nZXNBZnRlcjIoeyB0aW1lOiBzdGF0ZS5jaGFuZ2VzQWZ0ZXJUaW1lLCByb3V0ZXM6IHJvdXRlICYmIFtyb3V0ZV0gfHwgdW5kZWZpbmVkIH0pO1xuICAgICAgICBsZXQgdGFsbHkgPSBuZXdTY2FuVGFsbHkoKTtcbiAgICAgICAgZm9yIChsZXQgZmlsZSBvZiBjaGFuZ2VzKSB7XG4gICAgICAgICAgICB0YWxseVt0aGlzLnVwZGF0ZVNjYW5JbmRleChzb3VyY2VJbmRleCwgZmlsZSldKys7XG4gICAgICAgIH1cbiAgICAgICAgLy8gUG9sbHMgcnVuIGNvbnN0YW50bHksIHNvIG9ubHkgdGhlIG9uZXMgdGhhdCBhY3R1YWxseSBjaGFuZ2VkIHRoZSBpbmRleCBnZXQgYSBsaW5lXG4gICAgICAgIGlmICh0YWxseS5uZXcgfHwgdGFsbHkudXBkYXRlZCB8fCB0YWxseS50b21ic3RvbmUpIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKGBDaGFuZ2VzIHBvbGwgb2YgJHtzb3VyY2UuZ2V0RGVidWdOYW1lKCl9IChzdG9yZSAke3RoaXMuZm9sZGVyfSk6ICR7Y2hhbmdlcy5sZW5ndGh9IGNoYW5nZXM6ICR7Zm9ybWF0U2NhblRhbGx5KHRhbGx5LCBjaGFuZ2VzLmxlbmd0aCl9YCk7XG4gICAgICAgIH1cbiAgICAgICAgc3RhdGUuc2Nhbm5lZENvdW50ICs9IGNoYW5nZXMubGVuZ3RoO1xuICAgICAgICBzdGF0ZS5jaGFuZ2VzQWZ0ZXJUaW1lID0gcG9sbFN0YXJ0IC0gQ0hBTkdFU19QT0xMX09WRVJMQVA7XG4gICAgfVxuXG4gICAgLy8gRG93bmxvYWRzIHRoZSBmaWxlcyBhIHNvdXJjZSBjdXJyZW50bHkgaG9sZHMgb250byBvdXIgb3duIGJhc2Ugc291cmNlICh0aGUgbG9jYWwgZGlzayksIHByZXNlcnZpbmcgdGhlaXIgbW9kaWZpZWQgdGltZXMg4oCUIHNvIGEgbmV3ZXIgbG9jYWwgd3JpdGUgYWx3YXlzIHdpbnMuIFNraXBwZWQgZm9yIG5vRnVsbFN5bmMgc291cmNlcyAoZnJvbnRpbmcgYSBsYXJnZSBkYXRhYmFzZSB3aXRob3V0IGNvcHlpbmcgaXQpOyByZWFkcyBzdGlsbCBkb3duLWNhY2hlIGxhemlseS5cbiAgICBwcml2YXRlIGFzeW5jIGNvcHlTb3VyY2VGaWxlcyhzb3VyY2VJbmRleDogbnVtYmVyKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGlmIChzb3VyY2VJbmRleCA9PT0gMCkgcmV0dXJuO1xuICAgICAgICBsZXQgeyBzb3VyY2UgfSA9IHRoaXMuc291cmNlc1tzb3VyY2VJbmRleF07XG4gICAgICAgIGxldCBzdGF0ZSA9IHRoaXMuc291cmNlU3RhdGVzW3NvdXJjZUluZGV4XTtcbiAgICAgICAgbGV0IHBlbmRpbmc6IHsga2V5OiBzdHJpbmc7IGVudHJ5OiBJbmRleEVudHJ5IH1bXSA9IFtdO1xuICAgICAgICBsZXQgdG90YWxCeXRlcyA9IDA7XG4gICAgICAgIGxldCBjb3BpZWRTb3VyY2VzTGlzdEluZGV4ID0gdGhpcy5zb3VyY2VzTGlzdEluZGV4T2ZTbG90KHNvdXJjZUluZGV4KTtcbiAgICAgICAgZm9yIChsZXQgW2tleSwgZW50cnldIG9mIHRoaXMubWVtKSB7XG4gICAgICAgICAgICBpZiAoZW50cnkuc291cmNlc0xpc3RJbmRleCAhPT0gY29waWVkU291cmNlc0xpc3RJbmRleCkgY29udGludWU7XG4gICAgICAgICAgICBpZiAoZW50cnkuc2l6ZSA9PT0gMCkgY29udGludWU7XG4gICAgICAgICAgICBwZW5kaW5nLnB1c2goeyBrZXksIGVudHJ5IH0pO1xuICAgICAgICAgICAgdG90YWxCeXRlcyArPSBlbnRyeS5zaXplO1xuICAgICAgICB9XG4gICAgICAgIGlmICghcGVuZGluZy5sZW5ndGgpIHJldHVybjtcbiAgICAgICAgbGV0IGFjdGl2aXR5OiBTeW5jQWN0aXZpdHkgPSB7XG4gICAgICAgICAgICB0eXBlOiBcImZ1bGxTeW5jXCIsXG4gICAgICAgICAgICBzb3VyY2VEZWJ1Z05hbWU6IHNvdXJjZS5nZXREZWJ1Z05hbWUoKSxcbiAgICAgICAgICAgIHN0YXJ0VGltZTogRGF0ZS5ub3coKSxcbiAgICAgICAgICAgIGRvbmVGaWxlczogMCxcbiAgICAgICAgICAgIHRvdGFsRmlsZXM6IHBlbmRpbmcubGVuZ3RoLFxuICAgICAgICAgICAgZG9uZUJ5dGVzOiAwLFxuICAgICAgICAgICAgdG90YWxCeXRlcyxcbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy5zeW5jQWN0aXZpdGllcy5hZGQoYWN0aXZpdHkpO1xuICAgICAgICBsZXQgcHJvZ3Jlc3NMb2dnZWQgPSBmYWxzZTtcbiAgICAgICAgbGV0IGxvZ1Byb2dyZXNzID0gKCkgPT4ge1xuICAgICAgICAgICAgcHJvZ3Jlc3NMb2dnZWQgPSB0cnVlO1xuICAgICAgICAgICAgY29uc29sZS5sb2coYEZ1bGwgc3luYyBmcm9tICR7c291cmNlLmdldERlYnVnTmFtZSgpfSAoc3RvcmUgJHt0aGlzLmZvbGRlcn0pOiAke2FjdGl2aXR5LmRvbmVGaWxlc30vJHtwZW5kaW5nLmxlbmd0aH0gZmlsZXMgKCR7KChhY3Rpdml0eS5kb25lRmlsZXMgfHwgMCkgLyBwZW5kaW5nLmxlbmd0aCAqIDEwMCkudG9GaXhlZCgxKX0lKSwgJHtmb3JtYXROdW1iZXIoYWN0aXZpdHkuZG9uZUJ5dGVzIHx8IDApfUIvJHtmb3JtYXROdW1iZXIodG90YWxCeXRlcyl9QiAoJHsodG90YWxCeXRlcyAmJiAoYWN0aXZpdHkuZG9uZUJ5dGVzIHx8IDApIC8gdG90YWxCeXRlcyAqIDEwMCB8fCAxMDApLnRvRml4ZWQoMSl9JSlgKTtcbiAgICAgICAgfTtcbiAgICAgICAgbGV0IHByb2dyZXNzVGltZXIgPSBzZXRJbnRlcnZhbChsb2dQcm9ncmVzcywgU1lOQ19QUk9HUkVTU19MT0dfSU5URVJWQUwpO1xuICAgICAgICAocHJvZ3Jlc3NUaW1lciBhcyB7IHVucmVmPzogKCkgPT4gdm9pZCB9KS51bnJlZj8uKCk7XG4gICAgICAgIGxldCBzbG93RXJyb3JUaW1lciA9IHNldEludGVydmFsKCgpID0+IHtcbiAgICAgICAgICAgIGxldCBlbGFwc2VkID0gRGF0ZS5ub3coKSAtIGFjdGl2aXR5LnN0YXJ0VGltZTtcbiAgICAgICAgICAgIGxldCBkb25lRmlsZXMgPSBhY3Rpdml0eS5kb25lRmlsZXMgfHwgMDtcbiAgICAgICAgICAgIGxldCBkb25lQnl0ZXMgPSBhY3Rpdml0eS5kb25lQnl0ZXMgfHwgMDtcbiAgICAgICAgICAgIGxldCBieXRlc1BlclNlY29uZCA9IGRvbmVCeXRlcyAvIChlbGFwc2VkIC8gMTAwMCk7XG4gICAgICAgICAgICBsZXQgcmVtYWluaW5nQnl0ZXMgPSB0b3RhbEJ5dGVzIC0gZG9uZUJ5dGVzO1xuICAgICAgICAgICAgbGV0IGV0YVRleHQgPSBcInVua25vd24gKG5vIGJ5dGVzIHRyYW5zZmVycmVkIHlldClcIjtcbiAgICAgICAgICAgIGlmIChieXRlc1BlclNlY29uZCA+IDApIHtcbiAgICAgICAgICAgICAgICBsZXQgcmVtYWluaW5nTXMgPSByZW1haW5pbmdCeXRlcyAvIGJ5dGVzUGVyU2Vjb25kICogMTAwMDtcbiAgICAgICAgICAgICAgICBldGFUZXh0ID0gYCR7Zm9ybWF0VGltZShyZW1haW5pbmdNcyl9IHJlbWFpbmluZywgY29tcGxldGluZyBhcm91bmQgJHtuZXcgRGF0ZShEYXRlLm5vdygpICsgcmVtYWluaW5nTXMpLnRvSVNPU3RyaW5nKCl9YDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoYEZ1bGwgc3luYyBmcm9tICR7c291cmNlLmdldERlYnVnTmFtZSgpfSAoc3RvcmUgJHt0aGlzLmZvbGRlcn0pIGhhcyBiZWVuIHJ1bm5pbmcgZm9yICR7Zm9ybWF0VGltZShlbGFwc2VkKX06ICR7ZG9uZUZpbGVzfS8ke3BlbmRpbmcubGVuZ3RofSBmaWxlcyAoJHsoZG9uZUZpbGVzIC8gcGVuZGluZy5sZW5ndGggKiAxMDApLnRvRml4ZWQoMSl9JSksICR7Zm9ybWF0TnVtYmVyKGRvbmVCeXRlcyl9Qi8ke2Zvcm1hdE51bWJlcih0b3RhbEJ5dGVzKX1CICgkeyh0b3RhbEJ5dGVzICYmIGRvbmVCeXRlcyAvIHRvdGFsQnl0ZXMgKiAxMDAgfHwgMTAwKS50b0ZpeGVkKDEpfSUpLCAke2Zvcm1hdE51bWJlcihieXRlc1BlclNlY29uZCl9Qi9zLiBFc3RpbWF0ZWQgJHtldGFUZXh0fS5gKTtcbiAgICAgICAgfSwgRlVMTF9TWU5DX1NMT1dfRVJST1JfSU5URVJWQUwpO1xuICAgICAgICAoc2xvd0Vycm9yVGltZXIgYXMgeyB1bnJlZj86ICgpID0+IHZvaWQgfSkudW5yZWY/LigpO1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgbGV0IG5leHRJbmRleCA9IDA7XG4gICAgICAgICAgICBsZXQgZmFpbGVkID0gZmFsc2U7XG4gICAgICAgICAgICBsZXQgY29weVdvcmtlciA9IGFzeW5jICgpID0+IHtcbiAgICAgICAgICAgICAgICB3aGlsZSAoIWZhaWxlZCAmJiAhdGhpcy5zdG9wcGVkLnN0b3AgJiYgIXN0YXRlLnN0b3BwZWQuc3RvcCkge1xuICAgICAgICAgICAgICAgICAgICBsZXQgaW5kZXggPSBuZXh0SW5kZXgrKztcbiAgICAgICAgICAgICAgICAgICAgaWYgKGluZGV4ID49IHBlbmRpbmcubGVuZ3RoKSByZXR1cm47XG4gICAgICAgICAgICAgICAgICAgIGxldCB7IGtleSwgZW50cnkgfSA9IHBlbmRpbmdbaW5kZXhdO1xuICAgICAgICAgICAgICAgICAgICBsZXQgY29waWVkID0gYXdhaXQgY29weUFyY2hpdmVGaWxlKHsgZnJvbTogc291cmNlLCB0bzogdGhpcy5zb3VyY2VzWzBdLnNvdXJjZSwgcGF0aDoga2V5LCBzaXplOiBlbnRyeS5zaXplLCB3cml0ZVRpbWU6IGVudHJ5LndyaXRlVGltZSwgZm9yY2VTZXRJbW11dGFibGU6IHRydWUsIG5vQ2hlY2tzOiB0cnVlLCBpbnRlcm5hbDogdHJ1ZSB9KTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGNvcGllZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gT25seSBtb3ZlIHRoZSBlbnRyeSdzIHNvdXJjZSBpZiBpdCB3YXNuJ3QgY2hhbmdlZCB3aGlsZSB3ZSBjb3BpZWRcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLm1lbS5nZXQoa2V5KSA9PT0gZW50cnkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnNldEluZGV4RW50cnkoa2V5LCB7IHdyaXRlVGltZTogY29waWVkLndyaXRlVGltZSwgc2l6ZTogY29waWVkLnNpemUsIHNvdXJjZXNMaXN0SW5kZXg6IHRoaXMuc291cmNlc0xpc3RJbmRleE9mU2xvdCgwKSB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBhY3Rpdml0eS5kb25lRmlsZXMgPSAoYWN0aXZpdHkuZG9uZUZpbGVzIHx8IDApICsgMTtcbiAgICAgICAgICAgICAgICAgICAgYWN0aXZpdHkuZG9uZUJ5dGVzID0gKGFjdGl2aXR5LmRvbmVCeXRlcyB8fCAwKSArIGVudHJ5LnNpemU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIGxldCB3b3JrZXJzOiBQcm9taXNlPHZvaWQ+W10gPSBbXTtcbiAgICAgICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgTWF0aC5taW4oRlVMTF9TWU5DX1BBUkFMTEVMLCBwZW5kaW5nLmxlbmd0aCk7IGkrKykge1xuICAgICAgICAgICAgICAgIHdvcmtlcnMucHVzaChjb3B5V29ya2VyKCkuY2F0Y2goKGU6IEVycm9yKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIC8vIFN0b3AgdGhlIG90aGVyIHdvcmtlcnMgcHVsbGluZyBuZXcgZmlsZXMsIHRoZW4gc3VyZmFjZSB0aGUgZXJyb3JcbiAgICAgICAgICAgICAgICAgICAgZmFpbGVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgZTtcbiAgICAgICAgICAgICAgICB9KSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBhd2FpdCBQcm9taXNlLmFsbCh3b3JrZXJzKTtcbiAgICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgICAgIGNsZWFySW50ZXJ2YWwocHJvZ3Jlc3NUaW1lcik7XG4gICAgICAgICAgICBjbGVhckludGVydmFsKHNsb3dFcnJvclRpbWVyKTtcbiAgICAgICAgICAgIHRoaXMuc3luY0FjdGl2aXRpZXMuZGVsZXRlKGFjdGl2aXR5KTtcbiAgICAgICAgICAgIC8vIEEgc3luYyBzbG93IGVub3VnaCB0byBoYXZlIGxvZ2dlZCBwcm9ncmVzcyBhbHNvIGxvZ3MgaXRzIGNvbXBsZXRpb25cbiAgICAgICAgICAgIGlmIChwcm9ncmVzc0xvZ2dlZCkge1xuICAgICAgICAgICAgICAgIGxvZ1Byb2dyZXNzKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBmaW5kSW5mbyBhbmQgZ2V0Q2hhbmdlc0FmdGVyMiBsaXN0IGZyb20gdGhlIGluZGV4LCBzbyB0aGV5IG11c3Qgd2FpdCBmb3Igb3VyIG93biBiYXNlIHNvdXJjZSdzIGluaXRpYWwgc2NhbiAod2hpY2ggbWlnaHQgbGFnIG1pbnV0ZXMpIGJlZm9yZSB0aGUgbGlzdGluZyBpcyB0cnVzdHdvcnRoeS4gVGhlIGJhc2UgKGxvY2FsIGRpc2spIGlzIGltcGxpY2l0bHkgcmVxdWlyZWQgLSByZW1vdGUgc291cmNlcyBhcmUgbm90LCB0aGV5IGNvbWUgYW5kIGdvLlxuICAgIHByaXZhdGUgYXN5bmMgd2FpdEZvclJlcXVpcmVkU2NhbnMoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGF3YWl0IHRoaXMuc291cmNlU3RhdGVzWzBdLmluaXRpYWxTY2FuLnByb21pc2U7XG4gICAgfVxuXG4gICAgLy8gQSByZXF1ZXN0ZWQgZmlsZSBpc24ndCBpbiB0aGUgaW5kZXg6IG91ciBvd24gYmFzZSBzb3VyY2UgKGltcGxpY2l0bHkgcmVxdWlyZWQpIGlzIGNoZWNrZWQgZGlyZWN0bHkgaWYgaXRzIGluaXRpYWwgc2NhbiBoYXNuJ3QgZmluaXNoZWQsIGFuZCBjaGFuZ2VzLWFmdGVyIHNvdXJjZXMgYXJlIHJlLXBvbGxlZCAoYXQgbW9zdCBldmVyeSA1IHNlY29uZHMpXG4gICAgcHJpdmF0ZSBhc3luYyBjaGVja01pc3NpbmdLZXkoa2V5OiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLnNvdXJjZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIGlmICghdGhpcy5pc0xpdmUoaSkpIGNvbnRpbnVlO1xuICAgICAgICAgICAgbGV0IHsgc291cmNlIH0gPSB0aGlzLnNvdXJjZXNbaV07XG4gICAgICAgICAgICBsZXQgc3RhdGUgPSB0aGlzLnNvdXJjZVN0YXRlc1tpXTtcbiAgICAgICAgICAgIGlmIChpID09PSAwICYmICFzdGF0ZS5zY2FuQ29tcGxldGUpIHtcbiAgICAgICAgICAgICAgICAvLyBpbmNsdWRlVG9tYnN0b25lczogYSBkZWxldGlvbiBvbiBkaXNrIChhbiBlbXB0eSBmaWxlKSBtdXN0IGJlIGluZ2VzdGVkIGFzIGEgdG9tYnN0b25lLCB3cml0ZSB0aW1lIGluY2x1ZGVkXG4gICAgICAgICAgICAgICAgbGV0IGluZm8gPSBhd2FpdCBzb3VyY2UuZ2V0SW5mbyhrZXksIHsgaW5jbHVkZVRvbWJzdG9uZXM6IHRydWUgfSk7XG4gICAgICAgICAgICAgICAgaWYgKGluZm8pIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy51cGRhdGVTY2FuSW5kZXgoaSwgeyBwYXRoOiBrZXksIGNyZWF0ZVRpbWU6IGluZm8ud3JpdGVUaW1lLCBzaXplOiBpbmZvLnNpemUgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHN0YXRlLnN1cHBvcnRzQ2hhbmdlc0FmdGVyICYmIERhdGUubm93KCkgLSBzdGF0ZS5sYXN0TWlzc0NoZWNrID4gTUlTU19DSEVDS19JTlRFUlZBTCkge1xuICAgICAgICAgICAgICAgIHN0YXRlLmxhc3RNaXNzQ2hlY2sgPSBEYXRlLm5vdygpO1xuICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMucG9sbENoYW5nZXMoaSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIGdldEluZGV4RW50cnkoa2V5OiBzdHJpbmcpOiBQcm9taXNlPEluZGV4RW50cnkgfCB1bmRlZmluZWQ+IHtcbiAgICAgICAgLy8gQW4gZW50cnkgd2hvc2UgaG9sZGVyIGlzIG5vIGxvbmdlciBpbiB0aGUgc291cmNlIGxpc3QgaXMgc3RpbGwgdmFsaWQgLSBnZXRFbnRyeUhvbGRlciByZXNvbHZlcyB0aGUgcGVyc2lzdGVkIFVSTCBkaXJlY3RseSAoYW5kIGdldDIncyBmYWxsYmFjayBsb29wIGNvdmVycyBhIGhvbGRlciB0aGF0IGlzIGdvbmUgZW50aXJlbHkpXG4gICAgICAgIGxldCBlbnRyeSA9IHRoaXMubWVtLmdldChrZXkpO1xuICAgICAgICBpZiAoZW50cnkpIHJldHVybiBlbnRyeTtcbiAgICAgICAgYXdhaXQgdGhpcy5jaGVja01pc3NpbmdLZXkoa2V5KTtcbiAgICAgICAgcmV0dXJuIHRoaXMubWVtLmdldChrZXkpO1xuICAgIH1cblxuICAgIC8qKiBJbnRlcm5hbCAoc3RvcmUtdG8tc3RvcmUpIHJlYWQ6IHB1cmVseSB0aGUgbG9jYWwgZGlzaywgY29tcGxldGVseSBzaG9ydC1jaXJjdWl0aW5nIHRoZSBpbmRleCBhbmQgaG9sZGVyIHJlc29sdXRpb24gLSB0aGUgY2FsbGVyIGlzIGFub3RoZXIgc3RvcmUsIGFuZCBjaGFzaW5nIE9VUiByZW1vdGUgaG9sZGVycyB3aGlsZSBhbnN3ZXJpbmcgaXQgaXMgaG93IGluZmluaXRlIGdldCBsb29wcyBiZXR3ZWVuIHN0b3JlcyBmb3JtLiBObyB3aW5kb3cgb3Igcm91dGUgY2hlY2tzOiBpZiB0aGUgYnl0ZXMgYXJlIG9uIG91ciBkaXNrLCB0aGUgY2FsbGVyIG1heSBoYXZlIHRoZW0uIE5vdGUgZmFzdCB3cml0ZXMgc3RpbGwgc2l0dGluZyBpbiB0aGUgb3ZlcmxheSBhcmUgaW52aXNpYmxlIGhlcmU7IHRoZSBjYWxsZXIgcmUtZmluZHMgdGhlbSBhZnRlciBvdXIgZmx1c2guICovXG4gICAgcHJpdmF0ZSBhc3luYyBnZXRJbnRlcm5hbDIoY29uZmlnOiB7IHBhdGg6IHN0cmluZzsgcmFuZ2U/OiB7IHN0YXJ0OiBudW1iZXI7IGVuZDogbnVtYmVyIH07IGluY2x1ZGVUb21ic3RvbmVzPzogYm9vbGVhbiB9KTogUHJvbWlzZTx7IGRhdGE6IEJ1ZmZlcjsgd3JpdGVUaW1lOiBudW1iZXI7IHNpemU6IG51bWJlciB9IHwgdW5kZWZpbmVkPiB7XG4gICAgICAgIGF3YWl0IHRoaXMuaW5pdCgpO1xuICAgICAgICAvLyBpbmNsdWRlVG9tYnN0b25lcyBmb3J3YXJkcyB0byB0aGUgZGlzazogYSBmbGFnLWNhbGxlciAoYSBwZWVyIHN0b3JlJ3Mgc3luY2hyb25pemF0aW9uKSBuZWVkcyB0byBzZWUgb3VyIGRlbGV0aW9ucywgbm90IGp1c3Qgb3VyIGNvbnRlbnQuIEEgdG9tYnN0b25lIGRlbGV0ZWQgZnJvbSBkaXNrIGVudGlyZWx5IG9ubHkgbGl2ZXMgaW4gb3VyIGluZGV4LCBzbyBmYWxsIGJhY2sgdG8gdGhhdC5cbiAgICAgICAgbGV0IHJlc3VsdCA9IGF3YWl0IHRoaXMuZ2V0RGlza1NvdXJjZSgpLmRpc2suZ2V0Mihjb25maWcucGF0aCwgeyByYW5nZTogY29uZmlnLnJhbmdlLCBpbmNsdWRlVG9tYnN0b25lczogY29uZmlnLmluY2x1ZGVUb21ic3RvbmVzIH0pO1xuICAgICAgICBpZiAoIXJlc3VsdCB8fCAhcmVzdWx0LmRhdGEpIHtcbiAgICAgICAgICAgIGlmIChjb25maWcuaW5jbHVkZVRvbWJzdG9uZXMpIHtcbiAgICAgICAgICAgICAgICBsZXQgZW50cnkgPSB0aGlzLm1lbS5nZXQoY29uZmlnLnBhdGgpO1xuICAgICAgICAgICAgICAgIGlmIChlbnRyeSAmJiAhZW50cnkuc2l6ZSkgcmV0dXJuIHsgZGF0YTogQnVmZmVyLmFsbG9jKDApLCB3cml0ZVRpbWU6IGVudHJ5LndyaXRlVGltZSwgc2l6ZTogMCB9O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4geyBkYXRhOiByZXN1bHQuZGF0YSwgd3JpdGVUaW1lOiByZXN1bHQud3JpdGVUaW1lLCBzaXplOiByZXN1bHQuc2l6ZSB9O1xuICAgIH1cblxuICAgIC8qKiBJbnRlcm5hbCAoc3RvcmUtdG8tc3RvcmUpIHdyaXRlOiB0aGUgbG9jYWwgZGlzayBwbHVzIG91ciBpbmRleCwgd2l0aCBOTyBkb3duc3RyZWFtIGZhbi1vdXQgLSB0aGUgcHVzaGluZyBzdG9yZSBvd25zIHByb3BhZ2F0aW9uLCBhbmQgZmFubmluZyBpdHMgcHVzaGVzIGJhY2sgb3V0IGlzIGhvdyB3cml0ZSBsb29wcyBiZXR3ZWVuIHN0b3JlcyBmb3JtLiBPbmx5LXRha2UtbGF0ZXN0IHN0aWxsIGFwcGxpZXMgaGVyZS4gKi9cbiAgICBwcml2YXRlIGFzeW5jIHNldEludGVybmFsKGtleTogc3RyaW5nLCBkYXRhOiBCdWZmZXIsIGNvbmZpZzogeyBsYXN0TW9kaWZpZWQ6IG51bWJlciB9KTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGF3YWl0IHRoaXMuaW5pdCgpO1xuICAgICAgICBhc3NlcnRWYWxpZExhc3RNb2RpZmllZChjb25maWcubGFzdE1vZGlmaWVkKTtcbiAgICAgICAgbGV0IG92ZXJsYXlFbnRyeSA9IHRoaXMub3ZlcmxheS5nZXQoa2V5KTtcbiAgICAgICAgbGV0IGVudHJ5ID0gdGhpcy5tZW0uZ2V0KGtleSk7XG4gICAgICAgIGxldCBjdXJyZW50VGltZSA9IG92ZXJsYXlFbnRyeSAmJiBvdmVybGF5RW50cnkudCB8fCBlbnRyeSAmJiBlbnRyeS53cml0ZVRpbWUgfHwgMDtcbiAgICAgICAgaWYgKGNvbmZpZy5sYXN0TW9kaWZpZWQgPCBjdXJyZW50VGltZSkgcmV0dXJuO1xuICAgICAgICBpZiAoZGF0YS5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgIC8vIEEgdG9tYnN0b25lIHN0b3JlcyBub3RoaW5nIG9uIG91ciBvd24gc291cmNlIC0gdGhlIGluZGV4IGVudHJ5IGFsb25lIHJlY29yZHMgaXRcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuc291cmNlc1swXS5zb3VyY2UuZGVsKGtleSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLnNvdXJjZXNbMF0uc291cmNlLnNldChrZXksIGRhdGEsIHsgbGFzdE1vZGlmaWVkOiBjb25maWcubGFzdE1vZGlmaWVkLCBmb3JjZVNldEltbXV0YWJsZTogdHJ1ZSwgbm9DaGVja3M6IHRydWUgfSk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5zZXRJbmRleEVudHJ5KGtleSwgeyB3cml0ZVRpbWU6IGNvbmZpZy5sYXN0TW9kaWZpZWQsIHNpemU6IGRhdGEubGVuZ3RoLCBzb3VyY2VzTGlzdEluZGV4OiB0aGlzLnNvdXJjZXNMaXN0SW5kZXhPZlNsb3QoMCkgfSk7XG4gICAgfVxuXG4gICAgLy8gVGhlIHJlYWQncyBieXRlcyBjYW1lIGZyb20gYSByZW1vdGUgc291cmNlLCBzbyB3cml0ZSB0aGVtIG9udG8gb3VyIG93biBiYXNlIHNvdXJjZSAodGhlIGxvY2FsIGRpc2spLCB3aGljaCBiZWNvbWVzIHRoZSBlbnRyeSdzIG5ldyBob2xkZXIgLSByZWFkcyBvbmx5IHBheSB0aGUgcmVtb3RlIGZldGNoIG9uY2VcbiAgICBwcml2YXRlIGFzeW5jIGNhY2hlUmVhZChrZXk6IHN0cmluZywgcmVzdWx0OiB7IGRhdGE6IEJ1ZmZlcjsgd3JpdGVUaW1lOiBudW1iZXIgfSk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBhd2FpdCB0aGlzLnNvdXJjZXNbMF0uc291cmNlLnNldChrZXksIHJlc3VsdC5kYXRhLCB7IGxhc3RNb2RpZmllZDogcmVzdWx0LndyaXRlVGltZSwgZm9yY2VTZXRJbW11dGFibGU6IHRydWUsIG5vQ2hlY2tzOiB0cnVlIH0pO1xuICAgICAgICB0aGlzLnNldEluZGV4RW50cnkoa2V5LCB7IHdyaXRlVGltZTogcmVzdWx0LndyaXRlVGltZSwgc2l6ZTogcmVzdWx0LmRhdGEubGVuZ3RoLCBzb3VyY2VzTGlzdEluZGV4OiB0aGlzLnNvdXJjZXNMaXN0SW5kZXhPZlNsb3QoMCkgfSk7XG4gICAgfVxuXG4gICAgLy8gVGhlIHNoYXJlZCBlbmdpbmUgb2Ygc2V0IGFuZCBkZWw6IGFuIGVtcHR5IGJ1ZmZlciBpcyBleGFjdGx5IGEgZGVsZXRpb24gaGVyZSwgd2hpY2ggaXMgd2h5IHRoZSBlbXB0eS1idWZmZXIgcmVqZWN0aW9uIGxpdmVzIGluIHNldCAodGhlIHB1YmxpYyBBUEkpLCBub3QgaW4gdGhpcyBtYWNoaW5lcnlcbiAgICBwcml2YXRlIGFzeW5jIHNldE9yRGVsZXRlKGtleTogc3RyaW5nLCBkYXRhOiBCdWZmZXIsIGNvbmZpZzogeyBmYXN0PzogYm9vbGVhbjsgd3JpdGVEZWxheT86IG51bWJlcjsgbGFzdE1vZGlmaWVkPzogbnVtYmVyIH0pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgdGhpcy5jb25maWc/Lm9uV3JpdGVDb3VudGVkPy4oXCJvcmlnaW5hbFwiLCBkYXRhLmxlbmd0aCk7XG4gICAgICAgIGxldCBsYXN0TW9kaWZpZWQgPSBjb25maWcubGFzdE1vZGlmaWVkO1xuICAgICAgICBpZiAobGFzdE1vZGlmaWVkKSB7XG4gICAgICAgICAgICBhc3NlcnRWYWxpZExhc3RNb2RpZmllZChsYXN0TW9kaWZpZWQpO1xuICAgICAgICAgICAgbGV0IG92ZXJsYXlFbnRyeSA9IHRoaXMub3ZlcmxheS5nZXQoa2V5KTtcbiAgICAgICAgICAgIGxldCBlbnRyeSA9IHRoaXMubWVtLmdldChrZXkpO1xuICAgICAgICAgICAgbGV0IGN1cnJlbnRUaW1lID0gb3ZlcmxheUVudHJ5ICYmIG92ZXJsYXlFbnRyeS50IHx8IGVudHJ5ICYmIGVudHJ5LndyaXRlVGltZSB8fCAwO1xuICAgICAgICAgICAgLy8gQW4gb2xkZXIgd3JpdGUgbmV2ZXIgb3ZlcndyaXRlcyBhIG5ld2VyIG9uZSAoc2VlIElBcmNoaXZlcy5zZXQpXG4gICAgICAgICAgICBpZiAobGFzdE1vZGlmaWVkIDwgY3VycmVudFRpbWUpIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBsZXQgd3JpdGVUaW1lID0gbGFzdE1vZGlmaWVkIHx8IERhdGUubm93KCk7XG4gICAgICAgIGlmIChjb25maWcuZmFzdCkge1xuICAgICAgICAgICAgLy8gQSB3cml0ZURlbGF5IG9mIHplcm8gaXMgYSByZWFsIGNob2ljZSAobm8gZGVsYXkgYXQgYWxsKSwgc28gb25seSBhbiBvbWl0dGVkIGRlbGF5IGdldHMgdGhlIGRlZmF1bHRcbiAgICAgICAgICAgIGxldCB3cml0ZURlbGF5ID0gY29uZmlnLndyaXRlRGVsYXk7XG4gICAgICAgICAgICBpZiAod3JpdGVEZWxheSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgd3JpdGVEZWxheSA9IERFRkFVTFRfRkFTVF9XUklURV9ERUxBWTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIFRoZSBkZWxheSBuZXZlciBleHRlbmRzIHBhc3Qgb3VyIG93biB2YWxpZCB3aW5kb3cncyBlbmQgKG1pbnVzIHRoZSBtYXJnaW4sIHNvIHRoZSB3cml0ZXMgYXJlIG9uIGRpc2sgYmVmb3JlIHRoZSBuZXh0IHdpbmRvdydzIHNvdXJjZSB0YWtlcyBvdmVyIC0gYSBkZXBsb3kgc3dpdGNob3ZlciBpcyBqdXN0IHRoaXMgdG9vLCBzaW5jZSBpdHMgcmVtYXAgZW5kcyBvdXIgd2luZG93KS4gUGFzdCB0aGF0IHBvaW50IGZhc3Qgd3JpdGVzIHdyaXRlIHRocm91Z2ggaW1tZWRpYXRlbHkuXG4gICAgICAgICAgICBsZXQgZGVhZGxpbmUgPSB0aGlzLmJhc2VXcml0ZVdpbmRvd0VuZCgpIC0gV0lORE9XX0VORF9GTFVTSF9NQVJHSU47XG4gICAgICAgICAgICBpZiAod3JpdGVEZWxheSA+IDAgJiYgRGF0ZS5ub3coKSA8IGRlYWRsaW5lKSB7XG4gICAgICAgICAgICAgICAgLy8gT3duIGRpc2sgKyBvdXIgb3duIHN0b3JhZ2Ugc2VydmVycyAodHlwZS1cInJlbW90ZVwiKSBmbHVzaCB3aXRoaW4gTUFYX1JFTU9URV9GQVNUX0JVRkZFUjsgdGhlIG5vbi1cInJlbW90ZVwiIHNvdXJjZXMgKGJhY2tibGF6ZSkgd2FpdCB0aGUgZnVsbCB3cml0ZURlbGF5XG4gICAgICAgICAgICAgICAgbGV0IGZhc3RGbHVzaEF0ID0gTWF0aC5taW4oRGF0ZS5ub3coKSArIE1hdGgubWluKHdyaXRlRGVsYXksIE1BWF9SRU1PVEVfRkFTVF9CVUZGRVIpLCBkZWFkbGluZSk7XG4gICAgICAgICAgICAgICAgbGV0IHNsb3dGbHVzaEF0ID0gTWF0aC5taW4oRGF0ZS5ub3coKSArIHdyaXRlRGVsYXksIGRlYWRsaW5lKTtcbiAgICAgICAgICAgICAgICB0aGlzLm92ZXJsYXkuc2V0KGtleSwgeyBkYXRhLCB0OiB3cml0ZVRpbWUsIGZhc3RGbHVzaEF0LCBzbG93Rmx1c2hBdCB9KTtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5vdmVybGF5LmRlbGV0ZShrZXkpO1xuICAgICAgICBhd2FpdCB0aGlzLndyaXRlVG9Tb3VyY2VzKGtleSwgZGF0YSwgd3JpdGVUaW1lKTtcbiAgICB9XG5cbiAgICAvLyBUaGUgZW5kIG9mIG91ciBvd24gKGJhc2UgZGlzaykgd3JpdGUgd2luZG93IHRoYXQgQ09OVEFJTlMgbm93IC0gdGhlIGRlYWRsaW5lIGZhc3Qgd3JpdGVzIG11c3QgZmx1c2ggYmVmb3JlLCBzbyB0aGUgbmV4dCB3aW5kb3cncyBzb3VyY2UgaGFzIHRoZSBkYXRhIG9uIGhhbmRvZmYuIFRoZSBMQVRFU1QgZW5kIGFtb25nIGNvdmVyaW5nIHdpbmRvd3MgKG92ZXJsYXBwaW5nIHdpbmRvd3MgaGFuZCBvZmYgYXQgdGhlIGxhc3Qgb25lKS4gTm8gd2luZG93IGNvbnRhaW5zIG5vdyAoYW4gaW5lcnQgc3RvcmUsIG9yIGEgbW9tZW50IGJldHdlZW4gb3VyIHdpbmRvd3MpIC0+IDAsIGkuZS4gZmx1c2ggdGhyb3VnaCBpbW1lZGlhdGVseS5cbiAgICBwcml2YXRlIGJhc2VXcml0ZVdpbmRvd0VuZCgpOiBudW1iZXIge1xuICAgICAgICBsZXQgbm93ID0gRGF0ZS5ub3coKTtcbiAgICAgICAgbGV0IGVuZCA9IDA7XG4gICAgICAgIGZvciAobGV0IHcgb2YgdGhpcy5zb3VyY2VzWzBdLnZhbGlkV2luZG93cykge1xuICAgICAgICAgICAgaWYgKHdbMF0gPD0gbm93ICYmIG5vdyA8IHdbMV0pIGVuZCA9IE1hdGgubWF4KGVuZCwgd1sxXSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGVuZDtcbiAgICB9XG5cbiAgICBwcml2YXRlIGdldFdyaXRhYmxlU291cmNlcyhjb25maWc/OiB7IGlnbm9yZVdpbmRvdz86IGJvb2xlYW4gfSk6IG51bWJlcltdIHtcbiAgICAgICAgbGV0IHdyaXRhYmxlOiBudW1iZXJbXSA9IFtdO1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMuc291cmNlcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgaWYgKCF0aGlzLmlzTGl2ZShpKSkgY29udGludWU7XG4gICAgICAgICAgICBpZiAoIWNvbmZpZz8uaWdub3JlV2luZG93ICYmICF3aW5kb3dzQWNjZXB0V3JpdGVzKHRoaXMuc291cmNlc1tpXS52YWxpZFdpbmRvd3MpKSBjb250aW51ZTtcbiAgICAgICAgICAgIHdyaXRhYmxlLnB1c2goaSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHdyaXRhYmxlO1xuICAgIH1cblxuICAgIC8vIGNvbmZpZyBsZXRzIGEgc3RhZ2VkIGZhc3QgZmx1c2ggd3JpdGUgb25seSBQQVJUIG9mIHRoZSBzb3VyY2VzOiB3cml0ZUJhc2UgKG91ciBvd24gZGlzayArIGluZGV4KSBkZWZhdWx0cyBvbiwgYW5kIGRvd25zdHJlYW0gZmlsdGVycyB3aGljaCBub24tYmFzZSBwZWVycyBnZXQgdGhlIGZhbi1vdXQgKHRoZSBmYXN0IGZsdXNoIHdyaXRlcyBvbmx5IHR5cGUtXCJyZW1vdGVcIiBwZWVycywgdGhlIHNsb3cgZmx1c2ggb25seSB0aGUgcmVzdCkuIEEgZnVsbCB3cml0ZSAobm8gY29uZmlnKSBkb2VzIGJhc2UgKyBldmVyeSByb3V0ZS1tYXRjaGluZyBwZWVyLCBhcyBiZWZvcmUuXG4gICAgcHJpdmF0ZSBhc3luYyB3cml0ZVRvU291cmNlcyhrZXk6IHN0cmluZywgZGF0YTogQnVmZmVyLCB3cml0ZVRpbWU6IG51bWJlciwgY29uZmlnPzogeyB3cml0ZUJhc2U/OiBib29sZWFuOyBkb3duc3RyZWFtPzogKHNvdXJjZTogQXJjaGl2ZXNTb3VyY2UpID0+IGJvb2xlYW4gfSk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICAvLyBUaGUgcm91dGluZyBmaWxlIGlzIE5FVkVSIHN5bmNocm9uaXplZCBiZXR3ZWVuIHN0b3JhZ2Ugbm9kZXM6IHRoZSB3cml0ZXIgd3JpdGVzIGl0IGRpcmVjdGx5IHRvIGVhY2ggbm9kZSwgc28gd2Ugc3RvcmUgaXQgb24gb3VyIG93biBkaXNrIG9ubHkgKG5vIHZhbGlkLXdpbmRvdyBmaWx0ZXIgLSByb3V0aW5nL3ZhbGlkIHdpbmRvd3MgY2FuJ3QgcG9zc2libHkgYXBwbHkgdG8gdGhlIGZpbGUgZGVmaW5pbmcgdGhlbSkgYW5kIG5ldmVyIGZvcndhcmQgaXQgdG8gb3RoZXIgc291cmNlcy5cbiAgICAgICAgdGhpcy5jb25maWc/Lm9uV3JpdGVDb3VudGVkPy4oXCJmbHVzaGVkXCIsIGRhdGEubGVuZ3RoKTtcbiAgICAgICAgbGV0IGlzUm91dGluZyA9IGtleSA9PT0gUk9VVElOR19GSUxFO1xuICAgICAgICBsZXQgd3JpdGFibGUgPSB0aGlzLmdldFdyaXRhYmxlU291cmNlcyh7IGlnbm9yZVdpbmRvdzogaXNSb3V0aW5nIH0pO1xuICAgICAgICBsZXQgZmlyc3QgPSB3cml0YWJsZS5zaGlmdCgpO1xuICAgICAgICBpZiAoZmlyc3QgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBObyBzb3VyY2UgYWNjZXB0cyB3cml0ZXMgKGV2ZXJ5IHNvdXJjZSdzIHZhbGlkIHdpbmRvdyBpcyBpbiB0aGUgcGFzdCksIHNvIHdyaXRlcyBjYW5ub3QgYmUgc3RvcmVkIChzdG9yZSAke3RoaXMuZm9sZGVyfSlgKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoY29uZmlnPy53cml0ZUJhc2UgPz8gdHJ1ZSkge1xuICAgICAgICAgICAgLy8gT25seSBvdXIgb3duIChmaXJzdCkgc291cmNlIGJsb2NrcyB0aGUgd3JpdGUuIERvd25zdHJlYW0gc291cmNlcyBhcmUgd3JpdHRlbiBpbiB0aGUgYmFja2dyb3VuZDogYSBkb3duIGRvd25zdHJlYW0gc291cmNlIG11c3Qgbm90IGZhaWwgb3Igc3RhbGwgd3JpdGVzLCBhbmQgcmVjb25jaWxlU291cmNlIHJlLXNlbmRzIGFueXRoaW5nIHRoZXkgbWlzc2VkIG9uY2UgdGhleSBjb21lIGJhY2suXG4gICAgICAgICAgICBpZiAoZGF0YS5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgICAgICAvLyBBIHRvbWJzdG9uZSBzdG9yZXMgbm90aGluZyBvbiBvdXIgb3duIHNvdXJjZSAtIHRoZSBpbmRleCBlbnRyeSBhbG9uZSByZWNvcmRzIGl0XG4gICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5zb3VyY2VzW2ZpcnN0XS5zb3VyY2UuZGVsKGtleSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMuc291cmNlc1tmaXJzdF0uc291cmNlLnNldChrZXksIGRhdGEsIHsgbGFzdE1vZGlmaWVkOiB3cml0ZVRpbWUsIG5vQ2hlY2tzOiB0cnVlIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhpcy5zZXRJbmRleEVudHJ5KGtleSwgeyB3cml0ZVRpbWUsIHNpemU6IGRhdGEubGVuZ3RoLCBzb3VyY2VzTGlzdEluZGV4OiB0aGlzLnNvdXJjZXNMaXN0SW5kZXhPZlNsb3QoZmlyc3QpIH0pO1xuICAgICAgICB9XG4gICAgICAgIGlmIChpc1JvdXRpbmcpIHJldHVybjtcbiAgICAgICAgbGV0IHJvdXRlID0gZ2V0Um91dGUoa2V5KTtcbiAgICAgICAgZm9yIChsZXQgaSBvZiB3cml0YWJsZSkge1xuICAgICAgICAgICAgaWYgKCFyb3V0ZUNvbnRhaW5zKHRoaXMuc291cmNlc1tpXS5yb3V0ZSwgcm91dGUpKSBjb250aW51ZTtcbiAgICAgICAgICAgIGlmIChjb25maWc/LmRvd25zdHJlYW0gJiYgIWNvbmZpZy5kb3duc3RyZWFtKHRoaXMuc291cmNlc1tpXSkpIGNvbnRpbnVlO1xuICAgICAgICAgICAgLy8gRGVsZXRpb25zIHRyYXZlbCBhcyBkZWwgY2FycnlpbmcgdGhlIG9yaWdpbmFsIHdyaXRlIHRpbWUgKG5ldmVyIGFzIGVtcHR5IHNldHMgLSBzZXQgcmVqZWN0cyBlbXB0eSBidWZmZXJzKS4gQmFja2JsYXplIG1hdGVyaWFsaXplcyBzdWNoIGRlbHMgYXMgcmVhbCBlbXB0eSBmaWxlcywgc28gaXRzIGxpc3RpbmdzIHN0aWxsIHNob3cgdGhlIGRlbGV0aW9uIGZvciBvdGhlciBzdG9yZXMgdG8gc2NhbiBpbiBhcyBhIHRvbWJzdG9uZS5cbiAgICAgICAgICAgIGxldCBwdXNoOiBQcm9taXNlPHVua25vd24+O1xuICAgICAgICAgICAgaWYgKGRhdGEubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICAgICAgcHVzaCA9IHRoaXMuc291cmNlc1tpXS5zb3VyY2UuZGVsKGtleSwgeyBsYXN0TW9kaWZpZWQ6IHdyaXRlVGltZSwgbm9DaGVja3M6IHRydWUsIGludGVybmFsOiB0cnVlIH0pO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBwdXNoID0gdGhpcy5zb3VyY2VzW2ldLnNvdXJjZS5zZXQoa2V5LCBkYXRhLCB7IGxhc3RNb2RpZmllZDogd3JpdGVUaW1lLCBmb3JjZVNldEltbXV0YWJsZTogdHJ1ZSwgbm9DaGVja3M6IHRydWUsIGludGVybmFsOiB0cnVlIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdm9pZCBwdXNoLmNhdGNoKChlOiBFcnJvcikgPT4ge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoYEJhY2tncm91bmQgd3JpdGUgb2YgJHtrZXl9IHRvIHN5bmMgc291cmNlICR7dGhpcy5zb3VyY2VzW2ldLnNvdXJjZS5nZXREZWJ1Z05hbWUoKX0gZmFpbGVkOiAke2Uuc3RhY2sgPz8gZX1gKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBnZXREaXNrU291cmNlKCk6IHsgZGlzazogQXJjaGl2ZXNEaXNrOyBzb3VyY2VJbmRleDogbnVtYmVyIH0ge1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMuc291cmNlcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgbGV0IHNvdXJjZSA9IHRoaXMuc291cmNlc1tpXS5zb3VyY2U7XG4gICAgICAgICAgICBpZiAoc291cmNlIGluc3RhbmNlb2YgQXJjaGl2ZXNEaXNrKSByZXR1cm4geyBkaXNrOiBzb3VyY2UsIHNvdXJjZUluZGV4OiBpIH07XG4gICAgICAgIH1cbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBMYXJnZSB1cGxvYWRzIHJlcXVpcmUgYW4gQXJjaGl2ZXNEaXNrIHNvdXJjZSwgYW5kIHRoaXMgc3RvcmUgaGFzIG5vbmUgKHN0b3JlICR7dGhpcy5mb2xkZXJ9KWApO1xuICAgIH1cblxuICAgIHByaXZhdGUgaXNSZW1vdGVTb3VyY2Uoc291cmNlOiBBcmNoaXZlc1NvdXJjZSk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gc291cmNlLnNvdXJjZUNvbmZpZz8udHlwZSA9PT0gXCJyZW1vdGVcIjtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIGZsdXNoT3ZlcmxheShmb3JjZT86IGJvb2xlYW4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgbGV0IG5vdyA9IERhdGUubm93KCk7XG4gICAgICAgIGZvciAobGV0IFtrZXksIGVudHJ5XSBvZiB0aGlzLm92ZXJsYXkpIHtcbiAgICAgICAgICAgIGxldCBkb0Zhc3QgPSAhZW50cnkuZmFzdEZsdXNoZWQgJiYgKGZvcmNlIHx8IGVudHJ5LmZhc3RGbHVzaEF0IDw9IG5vdyk7XG4gICAgICAgICAgICBsZXQgZG9TbG93ID0gZm9yY2UgfHwgZW50cnkuc2xvd0ZsdXNoQXQgPD0gbm93O1xuICAgICAgICAgICAgaWYgKCFkb0Zhc3QgJiYgIWRvU2xvdykgY29udGludWU7XG4gICAgICAgICAgICBpZiAoZG9TbG93KSB7XG4gICAgICAgICAgICAgICAgLy8gVGhlIHJlbWFpbmluZyBzb3VyY2VzOiBpZiB0aGUgZmFzdCBmbHVzaCBhbHJlYWR5IHJhbiwgb25seSB0aGUgbm9uLVwicmVtb3RlXCIgb25lcyAob3duIGRpc2sgKyByZW1vdGUgcGVlcnMgYXJlIGRvbmUpOyBvdGhlcndpc2UgZXZlcnl0aGluZyBhdCBvbmNlICh3cml0ZURlbGF5IHdhcyA8PSBNQVhfUkVNT1RFX0ZBU1RfQlVGRkVSLCBvciBhIGZvcmNlZC93aW5kb3ctYm91bmRhcnkgZmx1c2gpXG4gICAgICAgICAgICAgICAgYXdhaXQgdGhpcy53cml0ZVRvU291cmNlcyhrZXksIGVudHJ5LmRhdGEsIGVudHJ5LnQsIGVudHJ5LmZhc3RGbHVzaGVkID8geyB3cml0ZUJhc2U6IGZhbHNlLCBkb3duc3RyZWFtOiBzID0+ICF0aGlzLmlzUmVtb3RlU291cmNlKHMpIH0gOiB1bmRlZmluZWQpO1xuICAgICAgICAgICAgICAgIC8vIE9ubHkgcmVtb3ZlIGlmIGl0IHdhc24ndCBvdmVyd3JpdHRlbiB3aGlsZSB3ZSB3ZXJlIGZsdXNoaW5nXG4gICAgICAgICAgICAgICAgaWYgKHRoaXMub3ZlcmxheS5nZXQoa2V5KSA9PT0gZW50cnkpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5vdmVybGF5LmRlbGV0ZShrZXkpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIEZhc3Qgc3RhZ2U6IG93biBkaXNrICsgb3VyIG93biBzdG9yYWdlIHNlcnZlcnMgb25seTsgdGhlIGVudHJ5IHN0YXlzIGluIHRoZSBvdmVybGF5IGZvciBpdHMgc2xvdyBmbHVzaFxuICAgICAgICAgICAgYXdhaXQgdGhpcy53cml0ZVRvU291cmNlcyhrZXksIGVudHJ5LmRhdGEsIGVudHJ5LnQsIHsgZG93bnN0cmVhbTogcyA9PiB0aGlzLmlzUmVtb3RlU291cmNlKHMpIH0pO1xuICAgICAgICAgICAgZW50cnkuZmFzdEZsdXNoZWQgPSB0cnVlO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLy8gcmVhZGVyRGlza0xpbWl0OiB0aGUgZGlzayBpcyBvbmx5IGEgYm91bmRlZCByZWFkIGNhY2hlLCBzbyBvbmNlIGl0IGV4Y2VlZHMgdGhlIGxpbWl0LCB0aGUgbGVhc3QgcmVjZW50bHkgdXNlZCBmaWxlcyBhcmUgZGVsZXRlZCBmcm9tIGl0IC0gYnV0IE9OTFkgd2hlbiBhbm90aGVyIHNvdXJjZSB2ZXJpZmlhYmx5IGhvbGRzIGEgc2FtZS1vci1uZXdlciBjb3B5ICh0aGUgb25seSBjb3B5IG9mIGEgZmlsZSBpcyBuZXZlciBkZWxldGVkKSwgYW5kIHRoZSBpbmRleCBlbnRyeSByZXBvaW50cyB0byB0aGF0IHNvdXJjZSBzbyByZWFkcyBrZWVwIHdvcmtpbmcgKHJlLWNhY2hpbmcgb24gdGhlIG5leHQgcmVhZCkuXG4gICAgcHJpdmF0ZSBldmljdGluZyA9IGZhbHNlO1xuICAgIHByaXZhdGUgYXN5bmMgZW5mb3JjZURpc2tMaW1pdCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgbGV0IGxpbWl0ID0gdGhpcy5jb25maWc/LnJlYWRlckRpc2tMaW1pdDtcbiAgICAgICAgaWYgKCFsaW1pdCB8fCB0aGlzLmV2aWN0aW5nKSByZXR1cm47XG4gICAgICAgIGlmICh0aGlzLnNvdXJjZUJ5dGVDb3VudHNbMF0gPD0gbGltaXQpIHJldHVybjtcbiAgICAgICAgdGhpcy5ldmljdGluZyA9IHRydWU7XG4gICAgICAgIGxldCBldmljdGVkRmlsZXMgPSAwO1xuICAgICAgICBsZXQgZXZpY3RlZEJ5dGVzID0gMDtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGxldCBiYXNlU291cmNlc0xpc3RJbmRleCA9IHRoaXMuc291cmNlc0xpc3RJbmRleE9mU2xvdCgwKTtcbiAgICAgICAgICAgIGxldCBjYW5kaWRhdGVzOiB7IGtleTogc3RyaW5nOyBlbnRyeTogSW5kZXhFbnRyeSB9W10gPSBbXTtcbiAgICAgICAgICAgIGZvciAobGV0IFtrZXksIGVudHJ5XSBvZiB0aGlzLm1lbSkge1xuICAgICAgICAgICAgICAgIGlmIChlbnRyeS5zb3VyY2VzTGlzdEluZGV4ICE9PSBiYXNlU291cmNlc0xpc3RJbmRleCB8fCBlbnRyeS5zaXplID09PSAwIHx8IGtleSA9PT0gUk9VVElOR19GSUxFKSBjb250aW51ZTtcbiAgICAgICAgICAgICAgICBjYW5kaWRhdGVzLnB1c2goeyBrZXksIGVudHJ5IH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgc29ydChjYW5kaWRhdGVzLCB4ID0+IHguZW50cnkubGFzdEFjY2Vzcyk7XG4gICAgICAgICAgICBmb3IgKGxldCB7IGtleSwgZW50cnkgfSBvZiBjYW5kaWRhdGVzKSB7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuc3RvcHBlZC5zdG9wKSByZXR1cm47XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuc291cmNlQnl0ZUNvdW50c1swXSA8PSBsaW1pdCkgYnJlYWs7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMubWVtLmdldChrZXkpICE9PSBlbnRyeSkgY29udGludWU7XG4gICAgICAgICAgICAgICAgbGV0IGhvbGRlcjogbnVtYmVyIHwgdW5kZWZpbmVkO1xuICAgICAgICAgICAgICAgIGZvciAobGV0IGkgPSAxOyBpIDwgdGhpcy5zb3VyY2VzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmICghdGhpcy5pc0xpdmUoaSkpIGNvbnRpbnVlO1xuICAgICAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICAgICAgbGV0IGluZm8gPSBhd2FpdCB0aGlzLnNvdXJjZXNbaV0uc291cmNlLmdldEluZm8oa2V5KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChpbmZvICYmIGluZm8ud3JpdGVUaW1lID49IGVudHJ5LndyaXRlVGltZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhvbGRlciA9IGk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH0gY2F0Y2gge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gQSBkb3duIHNvdXJjZSBqdXN0IGNhbid0IHZvdWNoIGZvciB0aGlzIGZpbGUgcmlnaHQgbm93XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKGhvbGRlciA9PT0gdW5kZWZpbmVkKSBjb250aW51ZTtcbiAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLnNvdXJjZXNbMF0uc291cmNlLmRlbChrZXkpO1xuICAgICAgICAgICAgICAgIHRoaXMuc2V0SW5kZXhFbnRyeShrZXksIHsgd3JpdGVUaW1lOiBlbnRyeS53cml0ZVRpbWUsIHNpemU6IGVudHJ5LnNpemUsIHNvdXJjZXNMaXN0SW5kZXg6IHRoaXMuc291cmNlc0xpc3RJbmRleE9mU2xvdChob2xkZXIpIH0pO1xuICAgICAgICAgICAgICAgIGV2aWN0ZWRGaWxlcysrO1xuICAgICAgICAgICAgICAgIGV2aWN0ZWRCeXRlcyArPSBlbnRyeS5zaXplO1xuICAgICAgICAgICAgfVxuICAgICAgICB9IGZpbmFsbHkge1xuICAgICAgICAgICAgdGhpcy5ldmljdGluZyA9IGZhbHNlO1xuICAgICAgICAgICAgaWYgKGV2aWN0ZWRGaWxlcykge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKGBEaXNrIGNhY2hlIG92ZXIgcmVhZGVyRGlza0xpbWl0IChzdG9yZSAke3RoaXMuZm9sZGVyfSk6IGV2aWN0ZWQgJHtldmljdGVkRmlsZXN9IGxlYXN0LXJlY2VudGx5LXVzZWQgZmlsZXMgKCR7Zm9ybWF0TnVtYmVyKGV2aWN0ZWRCeXRlcyl9QiksIG5vdyBhdCAke2Zvcm1hdE51bWJlcih0aGlzLnNvdXJjZUJ5dGVDb3VudHNbMF0pfUIvJHtmb3JtYXROdW1iZXIodGhpcy5jb25maWc/LnJlYWRlckRpc2tMaW1pdCB8fCAwKX1CYCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBUb21ic3RvbmVzIG9ubHkgbmVlZCB0byBleGlzdCBsb25nIGVub3VnaCBmb3IgZXZlcnkgc3RvcmUgdG8gbGVhcm4gb2YgdGhlIGRlbGV0aW9uOyBleHBpcmVkIG9uZXMgY29tZSBvdXQgb2YgdGhlIGluZGV4LiBUaGUgcGh5c2ljYWwgZW1wdHkgZmlsZSBpcyByZW1vdmVkIG9ubHkgb24gYmFja2JsYXplIHNvdXJjZXM6IHJlbW90ZSBzdG9yZXMgZXhwaXJlIHRoZWlyIG93biB0b21ic3RvbmVzIChhIGRlbCB0aGVyZSB3b3VsZCBqdXN0IG1pbnQgYSBmcmVzaCBvbmUpLCBhbmQgb3VyIG93biBkaXNrIG5ldmVyIHN0b3JlZCBhbnl0aGluZyBmb3IgaXQuXG4gICAgcHJpdmF0ZSBhc3luYyBjbGVhbnVwVG9tYnN0b25lcygpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgbGV0IGN1dG9mZiA9IERhdGUubm93KCkgLSBUT01CU1RPTkVfRVhQSVJZO1xuICAgICAgICBmb3IgKGxldCBba2V5LCBlbnRyeV0gb2YgdGhpcy5tZW0pIHtcbiAgICAgICAgICAgIGlmICh0aGlzLnN0b3BwZWQuc3RvcCkgcmV0dXJuO1xuICAgICAgICAgICAgaWYgKGVudHJ5LnNpemUgIT09IDApIGNvbnRpbnVlO1xuICAgICAgICAgICAgaWYgKGVudHJ5LndyaXRlVGltZSA+IGN1dG9mZikgY29udGludWU7XG4gICAgICAgICAgICB0aGlzLmRlbGV0ZUluZGV4RW50cnkoa2V5KTtcbiAgICAgICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5zb3VyY2VzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgaWYgKCF0aGlzLmlzTGl2ZShpKSkgY29udGludWU7XG4gICAgICAgICAgICAgICAgbGV0IHNvdXJjZUVudHJ5ID0gdGhpcy5zb3VyY2VzW2ldO1xuICAgICAgICAgICAgICAgIGlmICghd2luZG93c0FjY2VwdFdyaXRlcyhzb3VyY2VFbnRyeS52YWxpZFdpbmRvd3MpKSBjb250aW51ZTtcbiAgICAgICAgICAgICAgICBsZXQgc291cmNlID0gc291cmNlRW50cnkuc291cmNlO1xuICAgICAgICAgICAgICAgIGlmICghKHNvdXJjZSBpbnN0YW5jZW9mIEFyY2hpdmVzQmFja2JsYXplKSkgY29udGludWU7XG4gICAgICAgICAgICAgICAgdm9pZCBzb3VyY2UuZGVsKGtleSkuY2F0Y2goKGU6IEVycm9yKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoYFJlbW92aW5nIGV4cGlyZWQgdG9tYnN0b25lICR7a2V5fSBmcm9tICR7c291cmNlLmdldERlYnVnTmFtZSgpfSBmYWlsZWQ6ICR7ZS5zdGFjayA/PyBlfWApO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgLy8gI2VuZHJlZ2lvblxufVxuIl19
|
|
1399
|
-
/* _JS_SOURCE_HASH = "
|
|
916
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmxvYlN0b3JlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiYmxvYlN0b3JlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFBLGdEQUF3QjtBQUN4Qix5REFBbUQ7QUFDbkQsbURBQThEO0FBQzlELDRDQUdzQjtBQUN0QixrREFBbUU7QUFDbkUsaURBQTRMO0FBQzVMLDJDQUE0QztBQUM1Qyx1REFBcUQ7QUFDckQsc0NBQW1DO0FBQ25DLCtDQUE0QztBQUM1QywyQ0FBd0M7QUFDeEMsK0NBQTRDO0FBQzVDLHVEQUE2RDtBQUU3RCxxZ0JBQXFnQjtBQUVyZ0IsbU5BQW1OO0FBQ3RNLFFBQUEsdUJBQXVCLEdBQUcsbUJBQVksR0FBRyxDQUFDLENBQUM7QUFDeEQsTUFBTSx5QkFBeUIsR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFDO0FBQzVDLDJHQUEyRztBQUMzRyxNQUFNLHVCQUF1QixHQUFHLFlBQVksQ0FBQztBQW9DN0MsSUFBSSxrQkFBa0IsR0FBRyxDQUFDLENBQUM7QUFDM0IsU0FBUyx1QkFBdUIsQ0FBQyxPQUFlO0lBQzVDLElBQUksSUFBSSxDQUFDLEdBQUcsRUFBRSxHQUFHLGtCQUFrQixHQUFHLHlCQUF5QjtRQUFFLE9BQU87SUFDeEUsa0JBQWtCLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO0lBQ2hDLE9BQU8sQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUM7QUFDekIsQ0FBQztBQUVELHVXQUF1VztBQUN2VyxNQUFhLFNBQVM7SUFxQmxCO0lBQ0ksOERBQThEO0lBQ3ZELE1BQWM7SUFDckIsMktBQTJLO0lBQ3BLLFNBQWlCLEVBQ2hCLE1BYVA7UUFoQk0sV0FBTSxHQUFOLE1BQU0sQ0FBUTtRQUVkLGNBQVMsR0FBVCxTQUFTLENBQVE7UUFDaEIsV0FBTSxHQUFOLE1BQU0sQ0FhYjtRQXRDTCxjQUFjO1FBQ2QsMEdBQTBHO1FBQ25HLFlBQU8sR0FBRyxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsQ0FBQztR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SSxFQUFFLEVBQUUsWUFBWSxFQUFFLFNBQVMsRUFBRSxpQkFBaUIsRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztZQUN2SSxDQUFDO1lBQ0QsS0FBSyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBUSxFQUFFLEVBQUU7O2dCQUN6QixPQUFPLENBQUMsS0FBSyxDQUFDLHVCQUF1QixHQUFHLG1CQUFtQixJQUFJLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxZQUFZLEVBQUUsWUFBWSxNQUFBLENBQUMsQ0FBQyxLQUFLLG1DQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7WUFDaEksQ0FBQyxDQUFDLENBQUM7UUFDUCxDQUFDO0lBQ0wsQ0FBQztJQUVELGdLQUFnSztJQUN4SixhQUFhO1FBQ2pCLE9BQU8sRUFBRSxJQUFJLEVBQUUsSUFBSSxDQUFDLE9BQU8sRUFBRSxXQUFXLEVBQUUsQ0FBQyxFQUFFLENBQUM7SUFDbEQsQ0FBQztJQUVELDZKQUE2SjtJQUNySixLQUFLLENBQUMsa0JBQWtCLENBQUMsS0FBZTtRQUM1QyxLQUFLLElBQUksRUFBRSxNQUFNLEVBQUUsSUFBSSxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDbEMsSUFBSSxPQUFPLEdBQUcsSUFBQSwyQkFBUyxFQUFDLE1BQU0sQ0FBQyxDQUFDO1lBQ2hDLElBQUksQ0FBQyxPQUFPO2dCQUFFLFNBQVM7WUFDdkIsTUFBTSxPQUFPLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQy9CLENBQUM7SUFDTCxDQUFDO0NBR0o7QUF6NEJELDhCQXk0QkMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgcGF0aCBmcm9tIFwicGF0aFwiO1xuaW1wb3J0IHsgbGF6eSB9IGZyb20gXCJzb2NrZXQtZnVuY3Rpb24vc3JjL2NhY2hpbmdcIjtcbmltcG9ydCB7IHRpbWVJbk1pbnV0ZSwgc29ydCB9IGZyb20gXCJzb2NrZXQtZnVuY3Rpb24vc3JjL21pc2NcIjtcbmltcG9ydCB7XG4gICAgSUFyY2hpdmVzLCBBcmNoaXZlRmlsZUluZm8sIEFyY2hpdmVzU291cmNlLCBBcmNoaXZlc1N5bmNTdGF0dXMsIENoYW5nZXNBZnRlckNvbmZpZywgRmluZENvbmZpZywgSG9zdGVkQ29uZmlnLCBSZW1vdGVDb25maWcsIFNvdXJjZUNvbmZpZywgYXNzZXJ0VmFsaWRMYXN0TW9kaWZpZWQsXG4gICAgd2luZG93c0FjY2VwdFdyaXRlcywgU3luY0FjdGl2aXR5LCBGVUxMX1JPVVRFLCBGVUxMX1ZBTElEX1dJTkRPVywgU1RPUkFHRV9XUk9OR19WQUxJRF9XSU5ET1csIFNUT1JBR0VfV1JPTkdfUk9VVEUsXG59IGZyb20gXCIuLi9JQXJjaGl2ZXNcIjtcbmltcG9ydCB7IEFyY2hpdmVzRGlzaywgYXBwbHlGaW5kSW5mb1NoYXBlIH0gZnJvbSBcIi4uL0FyY2hpdmVzRGlza1wiO1xuaW1wb3J0IHsgUk9VVElOR19GSUxFLCBnZXRSb3V0ZSwgcm91dGVDb250YWlucywgcm91dGVJbnRlcnNlY3Rpb24sIHBhcnNlUm91dGluZ0RhdGEsIGFzc2VydFZhbGlkUmVtb3RlQ29uZmlnLCBnZXRDb25maWdWZXJzaW9uLCBzb3VyY2VJZGVudGl0eSwgc291cmNlUGVyc2lzdGVudFVybCB9IGZyb20gXCIuL3JlbW90ZUNvbmZpZ1wiO1xuaW1wb3J0IHsgc2VsZWN0RW50cnlBdCB9IGZyb20gXCIuL3N0b3JlUGxhblwiO1xuaW1wb3J0IHsgc291cmNlV3JpdGVEZWxheSB9IGZyb20gXCIuL0FyY2hpdmVzRGVsYXllZFwiO1xuaW1wb3J0IHsgTG9nTWFwIH0gZnJvbSBcIi4uL0xvZ01hcFwiO1xuaW1wb3J0IHsgU291cmNlc0xpc3QgfSBmcm9tIFwiLi9zb3VyY2VzTGlzdFwiO1xuaW1wb3J0IHsgU3RvcmVTeW5jIH0gZnJvbSBcIi4vc3RvcmVTeW5jXCI7XG5pbXBvcnQgeyBTdG9yZUNvbmZpZyB9IGZyb20gXCIuL3N0b3JlQ29uZmlnXCI7XG5pbXBvcnQgeyBhc0RlbGF5ZWQsIHVud3JhcERlbGF5ZWQgfSBmcm9tIFwiLi9BcmNoaXZlc0RlbGF5ZWRcIjtcblxuLy8gVGhlIHN0b3JhZ2UgZW5naW5lIG9mIHRoZSByZW1vdGUgc3RvcmFnZSBzZXJ2ZXIuIERhdGEgbGl2ZXMgaW4gc3luY2hyb25pemF0aW9uIHNvdXJjZXMgKGF0IG1pbmltdW0gYW4gQXJjaGl2ZXNEaXNrLCB0aGUgbG9jYWwgZGlzayk7IEJsb2JTdG9yZSBrZWVwcyBhbiBpbmRleCBvZiBldmVyeSBmaWxlIChwYXRoLCBsYXN0IG1vZGlmaWVkIHRpbWUsIHNpemUsIGFuZCB3aGljaCBzb3VyY2UgY3VycmVudGx5IGhvbGRzIHRoZSBkYXRhKSBpbiBhIEJ1bGtEYXRhYmFzZTIsIGFuZCBhbnN3ZXJzIGV2ZXJ5IHJlYWQgZnJvbSBpdCAoc2VlIEFyY2hpdmVzU291cmNlIGluIElBcmNoaXZlcy50cykuIEtlZXBpbmcgdGhhdCBpbmRleCBpbiBhZ3JlZW1lbnQgd2l0aCB0aGUgc291cmNlcyBpcyBTdG9yZVN5bmMncyBqb2IsIG5vdCB0aGlzIGZpbGUnczsgd2hhdCBsaXZlcyBoZXJlIGlzIHRoZSBpbmRleCBpdHNlbGYsIHJlYWRzLCB3cml0ZXMsIGFuZCB0aGUgdmFsaWRhdGlvbiBhIHdyaXRlIGhhcyB0byBwYXNzLlxuXG4vLyBGYXN0IHdyaXRlcyBhcmUgbmV2ZXIgZGVsYXllZCBwYXN0IG91ciBvd24gdmFsaWQgd2luZG93LCBhbmQgd2l0aGluIHRoaXMgbWFyZ2luIG9mIHRoZSB3aW5kb3cncyBlbmQgdGhleSB3cml0ZSB0aHJvdWdoIGltbWVkaWF0ZWx5IC0gc28gd2hlbiB0aGUgbmV4dCB3aW5kb3cncyBzb3VyY2UgdGFrZXMgb3ZlciwgdGhlIHdyaXRlcyBhcmUgYWxyZWFkeSBvbiBkaXNrXG5leHBvcnQgY29uc3QgV0lORE9XX0VORF9GTFVTSF9NQVJHSU4gPSB0aW1lSW5NaW51dGUgKiA1O1xuY29uc3QgV1JPTkdfVEFSR0VUX0xPR19USFJPVFRMRSA9IDYwICogMTAwMDtcbi8vIE1hcmtzIGFuIHVwbG9hZCBpZCB0aGF0IG5ldmVyIHJlYWNoZWQgdGhlIGRpc2ssIHNvIGl0IGNhbiBuZXZlciBjb2xsaWRlIHdpdGggb25lIEFyY2hpdmVzRGlzayBoYW5kZWQgb3V0XG5jb25zdCBESVNDQVJERURfVVBMT0FEX1BSRUZJWCA9IFwiZGlzY2FyZGVkX1wiO1xuXG5cbi8qKiBXaGF0IHdlIHN0b3JlIGFib3V0IGEgZmlsZS4gSXRzIHRpbWVzIGFyZSBub3QgaW4gaGVyZTogdGhlIGluZGV4IGtlZXBzIHRob3NlIGZvciBldmVyeSBrZXksIGRlbGV0ZWQgb25lcyBpbmNsdWRlZCAoc2VlIExvZ01hcCkuICovXG50eXBlIEluZGV4VmFsdWUgPSB7XG4gICAgc2l6ZTogbnVtYmVyO1xuICAgIC8vIFdoaWNoIHN5bmNocm9uaXphdGlvbiBzb3VyY2UgY3VycmVudGx5IGhvbGRzIHRoZSBkYXRhOiB0aGUgbGluZSBudW1iZXIgb2YgdGhlIHNvdXJjZSdzIFVSTCBpbiB0aGUgc3RvcmUncyBhcHBlbmQtb25seSBzb3VyY2VzIGxpc3QgKHNlZSBTb3VyY2VzTGlzdCkgLSBOT1QgYSBwb3NpdGlvbiBpbiB0aGUgaW4tbWVtb3J5IHNvdXJjZXMgYXJyYXksIHdoaWNoIGNoYW5nZXMgYmV0d2VlbiBydW5zXG4gICAgc291cmNlc0xpc3RJbmRleDogbnVtYmVyO1xufTtcblxuLyoqIE9uZSBmaWxlIHdlIGhvbGQsIGFzIGV2ZXJ5dGhpbmcgb3V0c2lkZSB0aGUgaW5kZXggc2VlcyBpdC4gKi9cbmV4cG9ydCB0eXBlIEluZGV4RW50cnkgPSBJbmRleFZhbHVlICYge1xuICAgIHdyaXRlVGltZTogbnVtYmVyO1xuICAgIC8vIFdoZW4gV0UgbGFzdCBjaGFuZ2VkIHRoaXMgZW50cnkgKG5vdCB0aGUgZmlsZSdzIHdyaXRlIHRpbWUpIOKAlCB3aGF0IGdldENoYW5nZXNBZnRlcjIgZmlsdGVycyBvbiwgc28gbGF0ZS1hcnJpdmluZyBmaWxlcyB3aXRoIG9sZCB3cml0ZSB0aW1lcyBhcmUgc3RpbGwgcmVwb3J0ZWRcbiAgICBjaGFuZ2VkQXQ6IG51bWJlcjtcbn07XG5cbi8vIE9uZSBzb3VyY2Ugb2YgYSBsaXZlIHNvdXJjZS1saXN0IHVwZGF0ZTsgc2VlIEJsb2JTdG9yZS51cGRhdGVTb3VyY2VzXG5leHBvcnQgdHlwZSBCbG9iU291cmNlU3BlYyA9IHtcbiAgICAvLyBNYXRjaGVkIGFnYWluc3QgQXJjaGl2ZXNTb3VyY2UuaWRlbnRpdHkgKFwiZGlza1wiIGZvciB0aGUgYmFzZSBzbG90KTsgZXF1YWwgaWRlbnRpdGllcyBwYWlyIG9mZiBpbiBvcmRlclxuICAgIGlkZW50aXR5OiBzdHJpbmc7XG4gICAgLy8gU2VlIEFyY2hpdmVzU291cmNlLnVybFxuICAgIHVybDogc3RyaW5nO1xuICAgIHZhbGlkV2luZG93czogW251bWJlciwgbnVtYmVyXVtdO1xuICAgIHJvdXRlPzogW251bWJlciwgbnVtYmVyXTtcbiAgICBub0Z1bGxTeW5jPzogYm9vbGVhbjtcbiAgICAvLyBTZWUgQXJjaGl2ZXNTb3VyY2UuaW50ZXJtZWRpYXRlXG4gICAgaW50ZXJtZWRpYXRlPzogc3RyaW5nO1xuICAgIC8vIFNlZSBBcmNoaXZlc1NvdXJjZS5zb3VyY2VDb25maWcgKGFic2VudCBmb3IgdGhlIGJhc2UgZGlzayBzb3VyY2UpXG4gICAgc291cmNlQ29uZmlnPzogU291cmNlQ29uZmlnO1xuICAgIC8vIE9ubHkgY2FsbGVkIGZvciBzb3VyY2VzIHRoYXQgZG9uJ3QgbWF0Y2ggYW4gZXhpc3RpbmcgbGl2ZSBzbG90XG4gICAgY3JlYXRlOiAoKSA9PiBJQXJjaGl2ZXM7XG4gICAgLy8gVGhlIG9wcG9zaXRlIGNhc2U6IHRoZSBlbmRwb2ludCBpcyBhbHJlYWR5IHJ1bm5pbmcgYW5kIG9ubHkgaXRzIGNvbmZpZyBjaGFuZ2VkLCBzbyB0aGUgUlVOTklORyBzb3VyY2UgaXMgaGFuZGVkIHRoZSBuZXcgb25lIChzZWUgYXBwbHlTb3VyY2VDb25maWcpXG4gICAgYXBwbHlDb25maWc/OiAoc291cmNlOiBJQXJjaGl2ZXMpID0+IHZvaWQ7XG59O1xuXG5sZXQgbGFzdFdyb25nVGFyZ2V0TG9nID0gMDtcbmZ1bmN0aW9uIGxvZ1dyb25nVGFyZ2V0UmVqZWN0aW9uKG1lc3NhZ2U6IHN0cmluZyk6IHZvaWQge1xuICAgIGlmIChEYXRlLm5vdygpIC0gbGFzdFdyb25nVGFyZ2V0TG9nIDwgV1JPTkdfVEFSR0VUX0xPR19USFJPVFRMRSkgcmV0dXJuO1xuICAgIGxhc3RXcm9uZ1RhcmdldExvZyA9IERhdGUubm93KCk7XG4gICAgY29uc29sZS5sb2cobWVzc2FnZSk7XG59XG5cbi8vIFRoZSBidWNrZXQgc3RvcmUsIGFuZCB0aGUgb25seSBvbmU6IGV2ZXJ5IGJ1Y2tldCBhIHNlcnZlciBob2xkcyBpcyBzZXJ2ZWQgYnkgdGhlc2UsIG9uZSBwZXIgc3RvcmUgbmFtZSBpbiBpdHMgcm91dGluZyBjb25maWcuIEl0cyBzb3VyY2VzIGFyZSBwbGFpbiBJQXJjaGl2ZXMgLSB0aGUgZmlyc3QgaXMgYWx3YXlzIHRoZSBzdG9yZSdzIG93biBkaXNrIGZvbGRlciwgdGhlIHJlc3QgYXJlIHRoZSBjb25maWd1cmVkIHBlZXJzIChzZWUgY3JlYXRlU3RvcmVTb3VyY2UpIC0gc28gXCJubyBzeW5jaHJvbml6YXRpb25cIiBpcyBzaW1wbHkgYSBzdG9yZSB3aXRoIG5vIHBlZXJzLCBub3QgYSBkaWZmZXJlbnQga2luZCBvZiBzdG9yZS5cbmV4cG9ydCBjbGFzcyBCbG9iU3RvcmUge1xuICAgIC8vIOKUgOKUgCBzdGF0ZSDilIDilIBcbiAgICAvLyBTZXQgb25jZSB0aGUgc3RvcmUgaXMgc2h1dHRpbmcgZG93bjsgZXZlcnkgbG9vcCBpdCBvd25zIChhbmQgU3RvcmVTeW5jJ3MgbWFpbnRlbmFuY2UgbG9vcHMpIHN0b3BzIG9uIGl0XG4gICAgcHVibGljIHN0b3BwZWQgPSB7IHN0b3A6IGZhbHNlIH07XG4gICAgLy8gV2hldGhlciBpbml0IGhhcyByZWFjaGVkIHRoZSBwb2ludCB3aGVyZSBhIG5ld2x5IGFkZGVkIHNvdXJjZSBjYW4gc3RhcnQgc2Nhbm5pbmcgaW1tZWRpYXRlbHlcbiAgICBwdWJsaWMgc3luY1N0YXJ0ZWQgPSBmYWxzZTtcbiAgICAvKiogSXRzIHNvdXJjZXMsIGluIGNvbmZpZyBvcmRlcjogc2xvdCAwIGlzIGFsd2F5cyBpdHMgb3duIGRpc2sgZm9sZGVyLCB0aGUgcmVzdCBhcmUgdGhlIHBlZXJzIGl0IHN5bmNocm9uaXplcyB3aXRoLiBGaWxsZWQgYnkgdXBkYXRlU291cmNlcywgd2hpY2ggaXMgYWxzbyBob3cgdGhleSBjaGFuZ2UuIFRoZSBzdG9yZSBPV05TIHRoZW0gLSB3cml0ZXMgcGljayBhbW9uZyB0aGVtLCByZWFkcyByZXNvbHZlIGhvbGRlcnMgdGhyb3VnaCB0aGVtIC0gYW5kIFN0b3JlU3luYyBvbmx5IHNjYW5zIHdoYXRldmVyIGlzIGluIGhlcmUgYXQgdGhlIHRpbWUuICovXG4gICAgcHVibGljIHNvdXJjZXM6IEFyY2hpdmVzU291cmNlW10gPSBbXTtcbiAgICAvLyBVcGxvYWRzIGltbXV0YWJpbGl0eSBhbHJlYWR5IGRlY2lkZWQgYWdhaW5zdDogdGhlIGNsaWVudCBpcyBtaWQtc3RyZWFtIGJ5IHRoZSB0aW1lIHdlIGtub3csIHNvIGl0IGtlZXBzIHNlbmRpbmcgYW5kIGV2ZXJ5IHBhcnQgaXMgZHJvcHBlZFxuICAgIHByaXZhdGUgZGlzY2FyZGVkVXBsb2FkcyA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICAgIHByaXZhdGUgbmV4dERpc2NhcmRlZFVwbG9hZCA9IDE7XG4gICAgLy8gVGhlIHBlcnNpc3RlbnQgaWRlbnRpdGllcyBiZWhpbmQgSW5kZXhFbnRyeS5zb3VyY2VzTGlzdEluZGV4IChzZWUgU291cmNlc0xpc3QpXG4gICAgcHJpdmF0ZSBzb3VyY2VzTGlzdDogU291cmNlc0xpc3Q7XG4gICAgLy8gUGVyIHNsb3Q6IHRoZSBwZXJzaXN0ZW50IHNvdXJjZXNMaXN0SW5kZXggb2YgdGhhdCBzbG90J3MgVVJMLCBmaWxsZWQgYnkgcmVnaXN0ZXJTbG90IGJlZm9yZSB0aGUgc2xvdCdzIHN5bmMgcnVuc1xuICAgIHByaXZhdGUgc2xvdFNvdXJjZXNMaXN0SW5kZXhlczogbnVtYmVyW10gPSBbXTtcbiAgICBwcml2YXRlIHNsb3RSZWdpc3RyYXRpb25zOiBQcm9taXNlPHZvaWQ+W10gPSBbXTtcbiAgICAvLyBFdmVyeSBmaWxlIHdlIGtub3cgb2YsIGluIG1lbW9yeSwgd2l0aCBhbiBhcHBlbmQtb25seSBsb2cgb2YgdGhlIGNoYW5nZXMgYmVoaW5kIGl0IChzZWUgTG9nTWFwKS4gQSBuZXcgZmlsZSBuYW1lIGVhY2ggdGltZSB0aGUgZW50cnkgZm9ybWF0IGNoYW5nZXMgZ2VuZXJhdGlvbjogdGhlIHByZXZpb3VzIG9uZXMgY2Fubm90IGJlIHJlYWQsIGFuZCBhIHNjYW4gcmVidWlsZHMgdGhlIGluZGV4IGFueXdheSwgc28gdGhleSBhcmUgc2ltcGx5IG5ldmVyIHJlYWQgYWdhaW4uXG4gICAgcHJpdmF0ZSBpbmRleDogTG9nTWFwPEluZGV4VmFsdWU+O1xuICAgIC8qKiBLZWVwaW5nIHRoZSBpbmRleCBpbiBhZ3JlZW1lbnQgd2l0aCB0aGUgc291cmNlczogc2Nhbm5pbmcsIHB1bGxpbmcsIHB1c2hpbmcsIGFuZCB0aGUgbWFpbnRlbmFuY2UgdGhhdCBmb2xsb3dzIGZyb20gaG9sZGluZyBhbiBpbmRleCAoZGlzay1saW1pdCBldmljdGlvbiwgdG9tYnN0b25lIGV4cGlyeSkuIEl0IHJlYWRzIGFuZCB3cml0ZXMgdGhpcyBzdG9yZSdzIGluZGV4IGFuZCBzb3VyY2VzIC0gaXQgZG9lcyBub3Qgb3duIHRoZW0uICovXG4gICAgcHVibGljIHN5bmM6IFN0b3JlU3luYztcblxuICAgIGNvbnN0cnVjdG9yKFxuICAgICAgICAvLyBQdWJsaWMgZm9yIFN0b3JlU3luYywgd2hpY2ggbG9ncyBpdCB3aXRoIGV2ZXJ5dGhpbmcgaXQgZG9lc1xuICAgICAgICBwdWJsaWMgZm9sZGVyOiBzdHJpbmcsXG4gICAgICAgIC8qKiBUaGUgbmFtZSB0aGlzIHN0b3JlIGFuc3dlcnMgdG8gKHNlZSBDb21tb25Db25maWcubmFtZSkgLSB0aGUgZW50cmllcyBvZiB0aGUgcm91dGluZyBjb25maWcgdGhhdCBjYXJyeSBpdCBhcmUgdGhlIG9uZXMgdGhhdCBjb25maWd1cmUgaXQsIGFuZCB0aGUgcmVzdCBhcmUgaXRzIHBlZXJzLiAqL1xuICAgICAgICBwdWJsaWMgc3RvcmVOYW1lOiBzdHJpbmcsXG4gICAgICAgIHByaXZhdGUgY29uZmlnPzoge1xuICAgICAgICAgICAgLyoqIFdoZXRoZXIgYSBjb25maWcgZW50cnkgaXMgVEhJUyBTRVJWRVIgKHNhbWUgYWNjb3VudCwgc2FtZSBidWNrZXQsIG91ciBvd24gYWRkcmVzcykuIEluamVjdGVkIGJlY2F1c2UgYSBzdG9yZSBrbm93cyBub3RoaW5nIGFib3V0IHNlcnZlcnMgLSBpdCBvbmx5IG5lZWRzIHRvIHRlbGwgaXRzIG93biBlbnRyaWVzIGFwYXJ0IGZyb20gaXRzIHBlZXJzJy4gQWJzZW50IG1lYW5zIG5vdGhpbmcgaXMgdXMsIHdoaWNoIGlzIHdoYXQgYSBiYXJlIHN0b3JlIChubyBzZXJ2ZXIgYXJvdW5kIGl0KSB3YW50cy4gKi9cbiAgICAgICAgICAgIGlzU2VsZj86IChzb3VyY2U6IFNvdXJjZUNvbmZpZykgPT4gYm9vbGVhbjtcbiAgICAgICAgICAgIC8qKiBCdWlsZHMgb25lIG9mIGl0cyBzb3VyY2VzLiBJbmplY3RlZCBmb3IgdGhlIHNhbWUgcmVhc29uLCBhbmQgYmVjYXVzZSB0aGUgZGVsYXkgaXQgaXMgY3JlYXRlZCB3aXRoIGlzIHRoaXMgc3RvcmUncyBwb2xpY3kuICovXG4gICAgICAgICAgICBjcmVhdGVTb3VyY2U/OiAoY29uZmlnOiB7IHNvdXJjZUNvbmZpZz86IFNvdXJjZUNvbmZpZzsgd3JpdGVEZWxheTogbnVtYmVyIH0pID0+IElBcmNoaXZlcztcbiAgICAgICAgICAgIC8qKiBIYW5kcyBhIHJ1bm5pbmcgc291cmNlIGEgY2hhbmdlZCBjb25maWcsIHNvIGFuIGVuZHBvaW50IHdlIGFscmVhZHkgdGFsayB0byBpcyBuZXZlciByZWJ1aWx0IGp1c3QgYmVjYXVzZSBhIGZsYWcgbW92ZWQuICovXG4gICAgICAgICAgICBhcHBseVNvdXJjZT86IChzb3VyY2U6IElBcmNoaXZlcywgc291cmNlQ29uZmlnOiBTb3VyY2VDb25maWcgfCB1bmRlZmluZWQsIHdyaXRlRGVsYXk6IG51bWJlcikgPT4gdm9pZDtcbiAgICAgICAgICAgIC8vIENhbGxlZCB3aGVuZXZlciBhIGtleSdzIGluZGV4IGVudHJ5IGNoYW5nZXMgKG91ciBvd24gd3JpdGVzIEFORCBmaWxlcyBwdWxsZWQgaW4gdmlhIHN5bmNocm9uaXphdGlvbikg4oCUIGhvdyB0aGUgc3RvcmFnZSBzZXJ2ZXIgbm90aWNlcyByb3V0aW5nIGNvbmZpZyB1cGRhdGVzLlxuICAgICAgICAgICAgb25JbmRleENoYW5nZWQ/OiAoa2V5OiBzdHJpbmcpID0+IHZvaWQ7XG4gICAgICAgICAgICAvLyBFdmVyeSBhY2NlcHRlZCB3cml0ZSAoXCJvcmlnaW5hbFwiKSBhbmQgZXZlcnkgd3JpdGUgdGhhdCBhY3R1YWxseSByZWFjaGVkIHRoZSBzb3VyY2VzIChcImZsdXNoZWRcIikuIEZhc3Qgd3JpdGVzIGNvYWxlc2NlLCBzbyB0aGUgdHdvIGNvdW50cyBkaWZmZXIuXG4gICAgICAgICAgICBvbldyaXRlQ291bnRlZD86IChraW5kOiBcIm9yaWdpbmFsXCIgfCBcImZsdXNoZWRcIiwgYnl0ZXM6IG51bWJlcikgPT4gdm9pZDtcbiAgICAgICAgICAgIC8vIFJlc29sdmVzIGEgcGVyc2lzdGVkIHNvdXJjZSBVUkwgKHNlZSBBcmNoaXZlc1NvdXJjZS51cmwpIHRvIGEgY2FjaGVkIElBcmNoaXZlcywgc28gZW50cmllcyB3aG9zZSBob2xkZXIgaXMgbm8gbG9uZ2VyIGNvbmZpZ3VyZWQgY2FuIHN0aWxsIGJlIHJlYWRcbiAgICAgICAgICAgIHJlc29sdmVTb3VyY2VVcmw/OiAodXJsOiBzdHJpbmcpID0+IElBcmNoaXZlcztcbiAgICAgICAgfVxuICAgICkge1xuICAgICAgICB0aGlzLnNvdXJjZXNMaXN0ID0gbmV3IFNvdXJjZXNMaXN0KHBhdGguam9pbihmb2xkZXIsIFwiaW5kZXhcIiwgXCJzb3VyY2VzTGlzdC50eHRcIikpO1xuICAgICAgICB0aGlzLmluZGV4ID0gbmV3IExvZ01hcDxJbmRleFZhbHVlPihwYXRoLmpvaW4oZm9sZGVyLCBcImluZGV4XCIsIFwiYmxvYkluZGV4My5sb2dcIikpO1xuICAgICAgICB0aGlzLnN5bmMgPSBuZXcgU3RvcmVTeW5jKHRoaXMpO1xuICAgICAgICB0aGlzLnN0b3JlQ29uZmlnID0gbmV3IFN0b3JlQ29uZmlnKHN0b3JlTmFtZSwgW10pO1xuICAgICAgICB0aGlzLm93bkRpc2sgPSBuZXcgQXJjaGl2ZXNEaXNrKGZvbGRlcik7XG4gICAgfVxuXG4gICAgLyoqIFRoaXMgc3RvcmUncyBmb2xkZXIsIHVud3JhcHBlZDogdGhlIHNhbWUgYnl0ZXMgc2xvdCAwIHNlcnZlcywgYnV0IHJlYWNoZWQgd2l0aG91dCBpdHMgd3JpdGUgZGVsYXkuIFVzZWQgZm9yIHRoZSB0d28gdGhpbmdzIHRoYXQgY2Fubm90IGdvIHRocm91Z2ggYSBidWZmZXJlZCBzb3VyY2UgLSByZWFkaW5nIG91ciBvd24gcm91dGluZyBjb25maWcgYmVmb3JlIHdlIGhhdmUgYW55IHNvdXJjZXMsIGFuZCBzdHJlYW1pbmcgYSBsYXJnZSB1cGxvYWQgdGhhdCBtdXN0IG5vdCBzaXQgaW4gbWVtb3J5LiAqL1xuICAgIHByaXZhdGUgb3duRGlzazogQXJjaGl2ZXNEaXNrO1xuXG4gICAgLyoqIFdoYXQgdGhpcyBzdG9yZSBpcyBjb25maWd1cmVkIHRvIGJlLiBJdCBvd25zIHRoaXM6IHRoZSByb3V0aW5nIGNvbmZpZyBpcyBhIGZpbGUgSU4gdGhlIHN0b3JlLCBzbyB0aGUgc3RvcmUgcmVhZHMgaXQsIGFwcGxpZXMgaXQgdG8gaXRzZWxmLCBhbmQgcmUtYXBwbGllcyBpdCB3aGVuZXZlciB0aGUgZmlsZSBjaGFuZ2VzIC0gYnkgb3VyIG93biB3cml0ZSwgb3IgYnkgYSBwZWVyJ3MgY29weSBhcnJpdmluZyB0aHJvdWdoIHN5bmNocm9uaXphdGlvbi4gKi9cbiAgICBwdWJsaWMgc3RvcmVDb25maWc6IFN0b3JlQ29uZmlnO1xuICAgIC8vIFRoZSByb3V0aW5nIGNvbmZpZyB0aGlzIHN0b3JlIGxhc3QgYXBwbGllZCwgc28gYSB3cml0ZSBvZiBhbiBpZGVudGljYWwgKG9yIG9sZGVyKSBvbmUgaXMgbm90IHJlLWFwcGxpZWRcbiAgICBwcml2YXRlIGFwcGxpZWRSb3V0aW5nVmVyc2lvbiA9IC0xO1xuXG4gICAgLy8gI3JlZ2lvbiBNYWluIGludGVyZmFjZVxuXG4gICAgcHVibGljIGluaXQgPSBsYXp5KGFzeW5jICgpID0+IHtcbiAgICAgICAgLy8gQ29uZmlndXJlIGZpcnN0OiB0aGUgY29uZmlnIGRlY2lkZXMgd2hhdCB0aGUgc291cmNlcyBBUkUsIGFuZCBldmVyeXRoaW5nIGJlbG93IGlzIHBlciBzb3VyY2UuIFdpdGggbm8gY29uZmlnIGF0IGFsbCB0aGF0IGlzIGp1c3Qgb3VyIG93biBkaXNrLCB3aGljaCBpcyBlbm91Z2ggdG8gc2VydmUgYW5kIHRvIGJlIHdyaXR0ZW4gdG8uXG4gICAgICAgIGF3YWl0IHRoaXMuYXBwbHlSb3V0aW5nQ29uZmlnKCk7XG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5zb3VyY2VzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLnJlZ2lzdGVyU2xvdChpKTtcbiAgICAgICAgfVxuICAgICAgICAvLyBBZnRlciB0aGUgc2xvdHMsIHdoaWNoIGlzIHdoYXQgaW5kZXggZW50cmllcyBuYW1lIGFzIHRoZWlyIGhvbGRlclxuICAgICAgICBhd2FpdCB0aGlzLmxvYWRJbmRleCgpO1xuICAgICAgICB0aGlzLnN5bmNTdGFydGVkID0gdHJ1ZTtcbiAgICAgICAgdGhpcy5zeW5jLnN0YXJ0KCk7XG4gICAgfSk7XG5cbiAgICAvKipcbiAgICAgKiBSZS1yZWFkcyB0aGUgcm91dGluZyBjb25maWcgb3V0IG9mIHRoaXMgc3RvcmUgYW5kIGFwcGxpZXMgaXQgdG8gaXRzZWxmLiBDYWxsZWQgYXQgc3RhcnR1cCBhbmRcbiAgICAgKiB3aGVuZXZlciB0aGF0IGZpbGUgY2hhbmdlcyBoZXJlIC0gd2hpY2ggaXMgdGhlIE9ORSBtZWNoYW5pc206IGEgY29uZmlnIHdyaXR0ZW4gYnkgYW4gb3BlcmF0b3JcbiAgICAgKiBhbmQgYSBjb25maWcgcHVsbGVkIG9mZiBhIHBlZXIgYXJlIHRoZSBzYW1lIGV2ZW50LCBhIHdyaXRlIG9mIHRoYXQgcGF0aCBpbnRvIHRoaXMgc3RvcmUuXG4gICAgICpcbiAgICAgKiBBIHN0b3JlIHdpdGggbm8gcm91dGluZyBjb25maWcgY29uZmlndXJlcyBpdHNlbGYgYXMgaXRzIG93biBkaXNrLCB2YWxpZCBhbHdheXMsIGZvciB0aGUgd2hvbGVcbiAgICAgKiBrZXkgc3BhY2UuIFRoYXQgaXMgYSBjb21wbGV0ZSwgd29ya2luZyBzdG9yZSAtIGl0IGp1c3QgaGFzIG5vYm9keSB0byBzeW5jaHJvbml6ZSB3aXRoIC0gYW5kIGl0XG4gICAgICogaXMgd2hhdCBsZXRzIGEgc3RvcmUgZXhpc3QgYmVmb3JlIGl0IGhhcyBldmVyIGhlYXJkIG9mIGEgY29uZmlndXJhdGlvbi5cbiAgICAgKi9cbiAgICBwdWJsaWMgYXN5bmMgYXBwbHlSb3V0aW5nQ29uZmlnKCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBsZXQgcm91dGluZyA9IGF3YWl0IHRoaXMucmVhZFJvdXRpbmdDb25maWcoKTtcbiAgICAgICAgbGV0IGVudHJpZXM6IEhvc3RlZENvbmZpZ1tdID0gW107XG4gICAgICAgIGxldCBwZWVyczogU291cmNlQ29uZmlnW10gPSBbXTtcbiAgICAgICAgZm9yIChsZXQgc291cmNlIG9mIHJvdXRpbmc/LnNvdXJjZXMgfHwgW10pIHtcbiAgICAgICAgICAgIGlmICh0eXBlb2Ygc291cmNlID09PSBcInN0cmluZ1wiKSBjb250aW51ZTtcbiAgICAgICAgICAgIGlmIChzb3VyY2UubmFtZSA9PT0gdGhpcy5zdG9yZU5hbWUgJiYgdGhpcy5jb25maWc/LmlzU2VsZj8uKHNvdXJjZSkpIHtcbiAgICAgICAgICAgICAgICBlbnRyaWVzLnB1c2goc291cmNlIGFzIEhvc3RlZENvbmZpZyk7XG4gICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBwZWVycy5wdXNoKHNvdXJjZSk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHJvdXRpbmcgJiYgIWVudHJpZXMubGVuZ3RoKSB7XG4gICAgICAgICAgICBjb25zb2xlLndhcm4oYFRoZSByb3V0aW5nIGNvbmZpZyBpbiBzdG9yZSAke3RoaXMuZm9sZGVyfSAodmVyc2lvbiAke2dldENvbmZpZ1ZlcnNpb24ocm91dGluZyl9KSBkb2VzIG5vdCBuYW1lIHRoaXMgc3RvcmUgKCR7SlNPTi5zdHJpbmdpZnkodGhpcy5zdG9yZU5hbWUpfSkgYXMgb25lIG9mIG91cnMsIHNvIGl0IHN0YXlzIGEgZGlzay1vbmx5IHN0b3JlYCk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5zdG9yZUNvbmZpZy51cGRhdGUoZW50cmllcyk7XG4gICAgICAgIHRoaXMudXBkYXRlU291cmNlcyh0aGlzLnBsYW5Tb3VyY2VzKHBlZXJzKSk7XG4gICAgICAgIHRoaXMuYXBwbGllZFJvdXRpbmdWZXJzaW9uID0gcm91dGluZyAmJiBnZXRDb25maWdWZXJzaW9uKHJvdXRpbmcpIHx8IC0xO1xuICAgIH1cblxuICAgIC8vIFRoZSByb3V0aW5nIGNvbmZpZyBhcyB0aGlzIHN0b3JlIGhvbGRzIGl0LCByZWFkIHN0cmFpZ2h0IG9mZiBpdHMgZm9sZGVyOiB0aGUgc3RvcmUgbWF5IGJlIGNvbmZpZ3VyaW5nIGl0c2VsZiBiZWZvcmUgaXQgaGFzIHNjYW5uZWQgYW55dGhpbmcsIGFuZCB0aGlzIGZpbGUgaXMgd2hhdCBkZWNpZGVzIHdoYXQgYSBzY2FuIHdvdWxkIGV2ZW4gdGFsayB0b1xuICAgIHByaXZhdGUgYXN5bmMgcmVhZFJvdXRpbmdDb25maWcoKTogUHJvbWlzZTxSZW1vdGVDb25maWcgfCB1bmRlZmluZWQ+IHtcbiAgICAgICAgbGV0IGRhdGEgPSBhd2FpdCB0aGlzLm93bkRpc2suZ2V0KFJPVVRJTkdfRklMRSk7XG4gICAgICAgIGlmICghZGF0YSB8fCAhZGF0YS5sZW5ndGgpIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICByZXR1cm4gcGFyc2VSb3V0aW5nRGF0YShkYXRhKTtcbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcihgSWdub3JpbmcgdGhlIHJvdXRpbmcgY29uZmlnIGluIHN0b3JlICR7dGhpcy5mb2xkZXJ9OiBpdCBjb3VsZCBub3QgYmUgcGFyc2VkICgkeyhlIGFzIEVycm9yKS5tZXNzYWdlfSlgKTtcbiAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKiogVGhlIHZlcnNpb24gb2YgdGhlIHJvdXRpbmcgY29uZmlnIHRoaXMgc3RvcmUgaXMgcnVubmluZywgc28gYSBjb3B5IGZvdW5kIG9uIGEgcGVlciBpcyBvbmx5IHRha2VuIHdoZW4gaXQgaXMgZ2VudWluZWx5IG5ld2VyLiAtMSBtZWFucyBpdCBoYXMgbm9uZS4gKi9cbiAgICBwdWJsaWMgcm91dGluZ1ZlcnNpb24oKTogbnVtYmVyIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuYXBwbGllZFJvdXRpbmdWZXJzaW9uO1xuICAgIH1cblxuICAgIC8vIEFwcGx5aW5nIGl0IHRvdWNoZXMgdGhlIHNvdXJjZXMsIHNvIGl0IGlzIHNlcmlhbGl6ZWQgYmVoaW5kIHdoYXRldmVyIGFwcGxpY2F0aW9uIGlzIGFscmVhZHkgcnVubmluZyByYXRoZXIgdGhhbiBpbnRlcmxlYXZpbmcgd2l0aCBpdFxuICAgIHByaXZhdGUgcm91dGluZ0FwcGxpZXM6IFByb21pc2U8dm9pZD4gPSBQcm9taXNlLnJlc29sdmUoKTtcbiAgICBwdWJsaWMgcmVhcHBseVJvdXRpbmdDb25maWcoKTogdm9pZCB7XG4gICAgICAgIGxldCBuZXh0ID0gdGhpcy5yb3V0aW5nQXBwbGllcy50aGVuKCgpID0+IHRoaXMuYXBwbHlSb3V0aW5nQ29uZmlnKCkpO1xuICAgICAgICB0aGlzLnJvdXRpbmdBcHBsaWVzID0gbmV4dC5jYXRjaCgoKSA9PiB7IH0pO1xuICAgICAgICB2b2lkIG5leHQuY2F0Y2goKGU6IEVycm9yKSA9PiBjb25zb2xlLmVycm9yKGBBcHBseWluZyB0aGUgcm91dGluZyBjb25maWcgaW4gc3RvcmUgJHt0aGlzLmZvbGRlcn0gZmFpbGVkOiAke2Uuc3RhY2sgPz8gZX1gKSk7XG4gICAgfVxuXG4gICAgLy8gT3VyIG93biBkaXNrIGZpcnN0IChhbHdheXMpLCB0aGVuIGV2ZXJ5IHBlZXIgd2hvc2Ugcm91dGUgb3ZlcmxhcHMgb3VycyAtIHRoZSBzb3VyY2VzIHRoaXMgc3RvcmUgc3luY2hyb25pemVzIHdpdGgsIGFzIGl0cyBvd24gY29uZmlnIGRlc2NyaWJlcyB0aGVtXG4gICAgcHJpdmF0ZSBwbGFuU291cmNlcyhwZWVyczogU291cmNlQ29uZmlnW10pOiBCbG9iU291cmNlU3BlY1tdIHtcbiAgICAgICAgbGV0IHNlbGYgPSB0aGlzLnN0b3JlQ29uZmlnLmN1cnJlbnQoKTtcbiAgICAgICAgbGV0IG1ha2VTcGVjID0gKHNvdXJjZUNvbmZpZzogU291cmNlQ29uZmlnIHwgdW5kZWZpbmVkLCB2YWxpZFdpbmRvd3M6IFtudW1iZXIsIG51bWJlcl1bXSwgcm91dGU6IFtudW1iZXIsIG51bWJlcl0gfCB1bmRlZmluZWQsIG5vRnVsbFN5bmM6IGJvb2xlYW4gfCB1bmRlZmluZWQpOiBCbG9iU291cmNlU3BlYyA9PiB7XG4gICAgICAgICAgICBsZXQgd3JpdGVEZWxheSA9IHNvdXJjZVdyaXRlRGVsYXkoeyBzb3VyY2VDb25maWcsIGZhc3Q6IHNlbGYuZmFzdCwgd3JpdGVEZWxheTogc2VsZi53cml0ZURlbGF5IH0pO1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICBpZGVudGl0eTogc291cmNlSWRlbnRpdHkoc291cmNlQ29uZmlnKSxcbiAgICAgICAgICAgICAgICB1cmw6IHNvdXJjZVBlcnNpc3RlbnRVcmwoc291cmNlQ29uZmlnLCB0aGlzLmZvbGRlciksXG4gICAgICAgICAgICAgICAgdmFsaWRXaW5kb3dzLFxuICAgICAgICAgICAgICAgIHJvdXRlLFxuICAgICAgICAgICAgICAgIG5vRnVsbFN5bmMsXG4gICAgICAgICAgICAgICAgaW50ZXJtZWRpYXRlOiBzb3VyY2VDb25maWc/LmludGVybWVkaWF0ZSxcbiAgICAgICAgICAgICAgICBzb3VyY2VDb25maWcsXG4gICAgICAgICAgICAgICAgY3JlYXRlOiAoKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGxldCBjcmVhdGVkID0gdGhpcy5jb25maWc/LmNyZWF0ZVNvdXJjZT8uKHsgc291cmNlQ29uZmlnLCB3cml0ZURlbGF5IH0pO1xuICAgICAgICAgICAgICAgICAgICBpZiAoIWNyZWF0ZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgVGhpcyBzdG9yZSBoYXMgbm8gd2F5IHRvIGJ1aWxkIHNvdXJjZXMsIHNvIGl0IGNhbm5vdCB1c2UgJHtKU09OLnN0cmluZ2lmeShzb3VyY2VDb25maWc/LnVybCB8fCB0aGlzLmZvbGRlcil9IChzdG9yZSAke3RoaXMuZm9sZGVyfSkuIFBhc3MgY3JlYXRlU291cmNlLmApO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBjcmVhdGVkO1xuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgYXBwbHlDb25maWc6IChzb3VyY2U6IElBcmNoaXZlcykgPT4gdGhpcy5jb25maWc/LmFwcGx5U291cmNlPy4oc291cmNlLCBzb3VyY2VDb25maWcsIHdyaXRlRGVsYXkpLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgfTtcbiAgICAgICAgLy8gT3VyIG93biBkaXNrIGFjY2VwdHMgd3JpdGVzIHdoaWxlIEFOWSB3aW5kb3cgdGhpcyBzdG9yZSBob2xkcyBpcyBvcGVuOyB3aXRoIG5vIGNvbmZpZyBhdCBhbGwgaXQgaXMgc2ltcGx5IGFsd2F5cyB2YWxpZFxuICAgICAgICBsZXQgb3duV2luZG93cyA9IHRoaXMuc3RvcmVDb25maWcuYWxsKCkubWFwKHggPT4geC52YWxpZFdpbmRvdyk7XG4gICAgICAgIGxldCBzcGVjczogQmxvYlNvdXJjZVNwZWNbXSA9IFttYWtlU3BlYyh1bmRlZmluZWQsIG93bldpbmRvd3MubGVuZ3RoICYmIG93bldpbmRvd3MgfHwgW0ZVTExfVkFMSURfV0lORE9XXSwgdW5kZWZpbmVkLCB1bmRlZmluZWQpXTtcbiAgICAgICAgLy8gT25lIHNwZWMgcGVyIGVuZHBvaW50LCBjYXJyeWluZyBhbGwgb2YgaXRzIHdpbmRvd3M6IGEgc3dpdGNob3ZlciBzcGxpdHMgb25lIHdpbmRvdyBhcm91bmQgYW4gaW50ZXJtZWRpYXRlLCBhbmQgdGhhdCBpcyBzdGlsbCBvbmUgc291cmNlIHRvIHVzXG4gICAgICAgIGxldCBieUlkZW50aXR5ID0gbmV3IE1hcDxzdHJpbmcsIEJsb2JTb3VyY2VTcGVjPigpO1xuICAgICAgICBmb3IgKGxldCBwZWVyIG9mIHBlZXJzKSB7XG4gICAgICAgICAgICBsZXQgc2hhcmVkID0gcm91dGVJbnRlcnNlY3Rpb24oc2VsZi5yb3V0ZSwgcGVlci5yb3V0ZSk7XG4gICAgICAgICAgICBpZiAoIXNoYXJlZCkgY29udGludWU7XG4gICAgICAgICAgICBsZXQgaWRlbnRpdHkgPSBzb3VyY2VJZGVudGl0eShwZWVyKTtcbiAgICAgICAgICAgIGxldCBleGlzdGluZyA9IGJ5SWRlbnRpdHkuZ2V0KGlkZW50aXR5KTtcbiAgICAgICAgICAgIGlmIChleGlzdGluZykge1xuICAgICAgICAgICAgICAgIGV4aXN0aW5nLnZhbGlkV2luZG93cy5wdXNoKHBlZXIudmFsaWRXaW5kb3cpO1xuICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgbGV0IHNwZWMgPSBtYWtlU3BlYyhwZWVyLCBbcGVlci52YWxpZFdpbmRvd10sIHNoYXJlZCwgcGVlci5ub0Z1bGxTeW5jIHx8IHNlbGYubm9GdWxsU3luYyk7XG4gICAgICAgICAgICBieUlkZW50aXR5LnNldChpZGVudGl0eSwgc3BlYyk7XG4gICAgICAgICAgICBzcGVjcy5wdXNoKHNwZWMpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBzcGVjcztcbiAgICB9XG5cbiAgICAvLyBTdG9wcyBhbGwgc3luY2hyb25pemF0aW9uIHNjYW5zL3BvbGxzIGFuZCBmbHVzaGVzIHBlbmRpbmcgd3JpdGVzLiBPbmx5IHVzZWQgd2hlbiB0aGUgc3RvcmUgZ2VudWluZWx5IGNhbm5vdCBjb250aW51ZSAoaXRzIHJvdXRlIG9yIGRpc2sgbGltaXQgY2hhbmdlZCwgcHJvY2VzcyBzaHV0ZG93bikgLSByb3V0aW5lIGNvbmZpZyBjaGFuZ2VzIGdvIHRocm91Z2ggdXBkYXRlU291cmNlcyBpbnN0ZWFkLCB3aGljaCB0aGUgc3RvcmUgc3Vydml2ZXMuXG4gICAgcHVibGljIGFzeW5jIGRpc3Bvc2UoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIHRoaXMuc3RvcHBlZC5zdG9wID0gdHJ1ZTtcbiAgICAgICAgdGhpcy5zeW5jLnN0b3AoKTtcbiAgICAgICAgYXdhaXQgdGhpcy5mbHVzaERlbGF5ZWRXcml0ZXModHJ1ZSk7XG4gICAgICAgIGF3YWl0IHRoaXMuaW5kZXguZmx1c2goKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgZ2V0Mihjb25maWc6IHsgcGF0aDogc3RyaW5nOyByYW5nZT86IHsgc3RhcnQ6IG51bWJlcjsgZW5kOiBudW1iZXIgfTsgaW50ZXJuYWw/OiBib29sZWFuOyBpbmNsdWRlVG9tYnN0b25lcz86IGJvb2xlYW4gfSk6IFByb21pc2U8eyBkYXRhOiBCdWZmZXI7IHdyaXRlVGltZTogbnVtYmVyOyBzaXplOiBudW1iZXIgfSB8IHVuZGVmaW5lZD4ge1xuICAgICAgICBpZiAoY29uZmlnLmludGVybmFsKSB7XG4gICAgICAgICAgICByZXR1cm4gYXdhaXQgdGhpcy5nZXRJbnRlcm5hbDIoY29uZmlnKTtcbiAgICAgICAgfVxuICAgICAgICBhd2FpdCB0aGlzLmluaXQoKTtcbiAgICAgICAgbGV0IGtleSA9IGNvbmZpZy5wYXRoO1xuICAgICAgICBsZXQgcmFuZ2UgPSBjb25maWcucmFuZ2U7XG4gICAgICAgIC8vIE5vdCBpbiB0aGUgaW5kZXggbWVhbnMgaXQgZG9lcyBub3QgZXhpc3QgaGVyZTogdGhlIGluZGV4IElTIHRoZSBhbnN3ZXIsIGFuZCBzY2FubmluZyBoZWFscyBpdCBvbiBpdHMgb3duIHNjaGVkdWxlLiBBbiBlbnRyeSB3aG9zZSBob2xkZXIgaXMgbm8gbG9uZ2VyIGluIHRoZSBzb3VyY2UgbGlzdCBpcyBzdGlsbCB2YWxpZCAtIGdldEVudHJ5SG9sZGVyIHJlc29sdmVzIHRoZSBwZXJzaXN0ZWQgVVJMIGRpcmVjdGx5LCBhbmQgZ2V0MidzIGZhbGxiYWNrIGxvb3AgY292ZXJzIGEgaG9sZGVyIHRoYXQgaXMgZ29uZSBlbnRpcmVseS5cbiAgICAgICAgbGV0IGVudHJ5ID0gdGhpcy5nZXRJbmRleEVudHJ5KGtleSk7XG4gICAgICAgIGlmICghZW50cnkpIHtcbiAgICAgICAgICAgIGlmICghY29uZmlnLmluY2x1ZGVUb21ic3RvbmVzKSByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICAgICAgLy8gQSBkZWxldGlvbiBoYXMgbm8gYnl0ZXMgLSB0aGUgdG9tYnN0b25lIElTIHRoZSBhbnN3ZXIsIHNvIGEgZmxhZy1jYWxsZXIgZ2V0cyBpdHMgdGltZSB3aXRoIGVtcHR5IGRhdGFcbiAgICAgICAgICAgIGxldCBkZWxldGVkID0gdGhpcy5nZXREZWxldGVkRW50cnkoa2V5KTtcbiAgICAgICAgICAgIGlmICghZGVsZXRlZCkgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgICAgIHJldHVybiB7IGRhdGE6IEJ1ZmZlci5hbGxvYygwKSwgd3JpdGVUaW1lOiBkZWxldGVkLndyaXRlVGltZSwgc2l6ZTogMCB9O1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuc3luYy5ub3RlQWNjZXNzKGtleSk7XG4gICAgICAgIGxldCBob2xkZXJBcmNoaXZlcyA9IGF3YWl0IHRoaXMuZ2V0RW50cnlIb2xkZXIoZW50cnkpO1xuICAgICAgICBsZXQgcmVzdWx0OiB7IGRhdGE6IEJ1ZmZlcjsgd3JpdGVUaW1lOiBudW1iZXI7IHNpemU6IG51bWJlciB9IHwgdW5kZWZpbmVkO1xuICAgICAgICBsZXQgaG9sZGVyRXJyb3I6IEVycm9yIHwgdW5kZWZpbmVkO1xuICAgICAgICBpZiAoaG9sZGVyQXJjaGl2ZXMpIHtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgLy8gaW5jbHVkZVRvbWJzdG9uZXM6IHRoZSBob2xkZXIgYW5zd2VyaW5nIFwiZGVsZXRlZFwiIChhIHRvbWJzdG9uZSwgd2l0aCBpdHMgd3JpdGUgdGltZSkgbXVzdCBiZSBkaXN0aW5ndWlzaGFibGUgZnJvbSBcIkkgbG9zdCB0aGUgZmlsZVwiIC0gdGhlIGZvcm1lciBpcyBhdXRob3JpdGF0aXZlIGFuZCBtdXN0IE5PVCBmYWxsIGJhY2sgdG8gb2xkZXIgY29waWVzLCB3aGljaCB3b3VsZCByZXN1cnJlY3QgdGhlIGRlbGV0aW9uIGZvciB0aGlzIHJlYWRcbiAgICAgICAgICAgICAgICBsZXQgYW5zd2VyID0gYXdhaXQgaG9sZGVyQXJjaGl2ZXMuZ2V0MihrZXksIHsgcmFuZ2UsIGludGVybmFsOiB0cnVlLCBpbmNsdWRlVG9tYnN0b25lczogdHJ1ZSB9KTtcbiAgICAgICAgICAgICAgICBpZiAoYW5zd2VyICYmIGFuc3dlci5kYXRhICYmICFhbnN3ZXIuZGF0YS5sZW5ndGggJiYgIShyYW5nZSAmJiBhbnN3ZXIuc2l6ZSkgJiYgYW5zd2VyLndyaXRlVGltZSA+PSBlbnRyeS53cml0ZVRpbWUpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgLy8gTk9URTogYSByYW5nZWQgcmVhZCBvZiBhIHJlYWwgZmlsZSBjYW4gbGVnaXRpbWF0ZWx5IGJlIGVtcHR5IChyYW5nZSBwYXN0IEVPRiksIHNvIG9ubHkgdW5yYW5nZWQgZW1wdGluZXNzIG1lYW5zIHRvbWJzdG9uZS9hYnNlbnRcbiAgICAgICAgICAgICAgICBpZiAoYW5zd2VyICYmIGFuc3dlci5kYXRhICYmIChhbnN3ZXIuZGF0YS5sZW5ndGggfHwgcmFuZ2UgJiYgYW5zd2VyLnNpemUpKSB7XG4gICAgICAgICAgICAgICAgICAgIHJlc3VsdCA9IHsgZGF0YTogYW5zd2VyLmRhdGEsIHdyaXRlVGltZTogYW5zd2VyLndyaXRlVGltZSwgc2l6ZTogYW5zd2VyLnNpemUgfTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICAgICAgaG9sZGVyRXJyb3IgPSBlIGFzIEVycm9yO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGlmIChyZXN1bHQpIHtcbiAgICAgICAgICAgIC8vIFJhbmdlZCByZWFkcyBjYW4ndCBwb3B1bGF0ZSBhIGNhY2hlICh0aGV5J3JlIHBhcnRpYWwpXG4gICAgICAgICAgICBpZiAodGhpcy5zbG90Rm9yU291cmNlc0xpc3RJbmRleChlbnRyeS5zb3VyY2VzTGlzdEluZGV4KSAhPT0gMCAmJiAhcmFuZ2UpIHtcbiAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLmNhY2hlUmVhZChrZXksIHJlc3VsdCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgICB9XG4gICAgICAgIC8vIFRoZSByb3V0aW5nIGZpbGUgaXMgb25seSBldmVyIHJlYWQgb2ZmIG91ciBvd24gZGlzayAtIGZhbGxpbmcgYmFjayB0byBhbm90aGVyIHNvdXJjZSdzIGNvcHkgd291bGQgc3luY2hyb25pemUgaXQgYmV0d2VlbiBub2RlcyB0aHJvdWdoIHRoZSByZWFkIHBhdGgsIHdoaWNoIGl0IG5ldmVyIGlzXG4gICAgICAgIGlmIChrZXkgPT09IFJPVVRJTkdfRklMRSkge1xuICAgICAgICAgICAgaWYgKGhvbGRlckVycm9yKSB0aHJvdyBob2xkZXJFcnJvcjtcbiAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgIH1cbiAgICAgICAgLy8gVGhlIGhvbGRlciBpcyBkb3duIG9yIGxvc3QgdGhlIGZpbGUuIEFOWSBvdGhlciBzb3VyY2UncyBjb3B5IGJlYXRzIG5vIHZhbHVlIC0gZXZlbiBhbiBPTERFUiBvbmUgLSBhbmQgaXQncyBjb3BpZWQgb250byBvdXIgZGlzayBzbyB0aGUgbmV4dCByZWFkIGRvZXNuJ3QgZGVwZW5kIG9uIGx1Y2suXG4gICAgICAgIGxldCBob2xkZXJTbG90ID0gdGhpcy5zbG90Rm9yU291cmNlc0xpc3RJbmRleChlbnRyeS5zb3VyY2VzTGlzdEluZGV4KTtcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLnNvdXJjZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIGlmIChpID09PSBob2xkZXJTbG90IHx8ICF0aGlzLmlzTGl2ZShpKSkgY29udGludWU7XG4gICAgICAgICAgICBsZXQgZmFsbGJhY2s6IHsgZGF0YTogQnVmZmVyOyB3cml0ZVRpbWU6IG51bWJlcjsgc2l6ZTogbnVtYmVyIH0gfCB1bmRlZmluZWQ7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIGxldCBhbnN3ZXIgPSBhd2FpdCB0aGlzLnNvdXJjZXNbaV0uc291cmNlLmdldDIoa2V5LCB7IGludGVybmFsOiB0cnVlIH0pO1xuICAgICAgICAgICAgICAgIC8vIEVtcHR5IGRhdGEgY291bnRzIGFzIGFic2VudCAtIGEgdG9tYnN0b25lLCBub3QgY29udGVudCAodGhpcyByZWFkIGlzIHVucmFuZ2VkLCBzbyBlbXB0aW5lc3MgaXMgdW5hbWJpZ3VvdXMpXG4gICAgICAgICAgICAgICAgaWYgKGFuc3dlciAmJiBhbnN3ZXIuZGF0YSAmJiBhbnN3ZXIuZGF0YS5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICAgICAgZmFsbGJhY2sgPSB7IGRhdGE6IGFuc3dlci5kYXRhLCB3cml0ZVRpbWU6IGFuc3dlci53cml0ZVRpbWUsIHNpemU6IGFuc3dlci5zaXplIH07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBjYXRjaCB7XG4gICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoIWZhbGxiYWNrKSBjb250aW51ZTtcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuY2FjaGVSZWFkKGtleSwgZmFsbGJhY2spO1xuICAgICAgICAgICAgbGV0IGRhdGEgPSBmYWxsYmFjay5kYXRhO1xuICAgICAgICAgICAgaWYgKHJhbmdlKSB7XG4gICAgICAgICAgICAgICAgZGF0YSA9IGRhdGEuc3ViYXJyYXkoTWF0aC5taW4ocmFuZ2Uuc3RhcnQsIGRhdGEubGVuZ3RoKSwgTWF0aC5taW4ocmFuZ2UuZW5kLCBkYXRhLmxlbmd0aCkpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHsgZGF0YSwgd3JpdGVUaW1lOiBmYWxsYmFjay53cml0ZVRpbWUsIHNpemU6IGZhbGxiYWNrLnNpemUgfTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoaG9sZGVyRXJyb3IpIHRocm93IGhvbGRlckVycm9yO1xuICAgICAgICAvLyBUaGUgaG9sZGVyIGFuc3dlcmVkIFwibm90IHRoZXJlXCIgYW5kIG5vIG90aGVyIHNvdXJjZSBoYXMgaXQgZWl0aGVyOiB0aGUgZW50cnkgd2FzIHN0YWxlLiBGb3Jnb3R0ZW4gcmF0aGVyIHRoYW4gZGVsZXRlZCAtIG5vdGhpbmcgaGFwcGVuZWQgdG8gdGhpcyBmaWxlLCB3ZSB3ZXJlIHNpbXBseSB3cm9uZyBhYm91dCBob2xkaW5nIGl0LCBhbmQgc2F5aW5nIG90aGVyd2lzZSB3b3VsZCBwdXNoIGEgZGVsZXRpb24gb3V0IHRvIGV2ZXJ5b25lIGVsc2UuXG4gICAgICAgIHRoaXMucHVyZ2VJbmRleEVudHJ5KGtleSk7XG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIHNldChjb25maWc6IHsgcGF0aDogc3RyaW5nOyBkYXRhOiBCdWZmZXI7IGxhc3RNb2RpZmllZD86IG51bWJlcjsgZm9yY2VTZXRJbW11dGFibGU/OiBib29sZWFuOyBpbnRlcm5hbD86IGJvb2xlYW4gfSk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBsZXQgeyBwYXRoOiBrZXksIGRhdGEgfSA9IGNvbmZpZztcbiAgICAgICAgaWYgKCFkYXRhLmxlbmd0aCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBzZXQgd2FzIGNhbGxlZCB3aXRoIGFuIGVtcHR5IGJ1ZmZlciBmb3IgJHtKU09OLnN0cmluZ2lmeShrZXkpfSAoc3RvcmUgJHt0aGlzLmZvbGRlcn0pOiBhbiBlbXB0eSBmaWxlIElTIGEgZGVsZXRpb24gaW4gdGhpcyBzeXN0ZW0gYW5kIHdvdWxkIHJlYWQgYmFjayBhcyBtaXNzaW5nIC0gY2FsbCBkZWwgaW5zdGVhZGApO1xuICAgICAgICB9XG4gICAgICAgIGF3YWl0IHRoaXMuaW5pdCgpO1xuICAgICAgICBsZXQgd3JpdGVUaW1lID0gY29uZmlnLmxhc3RNb2RpZmllZCB8fCBEYXRlLm5vdygpO1xuICAgICAgICBsZXQgcm91dGUgPSBnZXRSb3V0ZShrZXkpO1xuICAgICAgICAvLyBUaGUgcm91dGluZyBmaWxlIGRlZmluZXMgdGhlIHdpbmRvd3Mvcm91dGVzLCBzbyB0aGV5IGNhbid0IHBvc3NpYmx5IGFwcGx5IHRvIGl0IChhbmQgaXQgbmV2ZXIgZmxvd3MgdGhyb3VnaCB2YWxpZGF0aW9uKSAtIGJ1dCBpdCBoYXMgYSBydWxlIG9mIGl0cyBvd24sIHdoaWNoIGlzIG91cnMgdG8gZW5mb3JjZSBiZWNhdXNlIHRoZSBmaWxlIGlzIG91cnNcbiAgICAgICAgaWYgKGtleSA9PT0gUk9VVElOR19GSUxFKSB7XG4gICAgICAgICAgICB0aGlzLmFzc2VydFJvdXRpbmdDb25maWdXcml0YWJsZShkYXRhKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuYXNzZXJ0V3JpdGVUYXJnZXQoa2V5LCByb3V0ZSwgY29uZmlnLmxhc3RNb2RpZmllZCk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGtleSAhPT0gUk9VVElOR19GSUxFICYmIHRoaXMuc3RvcmVDb25maWcuYWxsKCkubGVuZ3RoKSB7XG4gICAgICAgICAgICBpZiAoY29uZmlnLmZvcmNlU2V0SW1tdXRhYmxlKSB7XG4gICAgICAgICAgICAgICAgaWYgKCFjb25maWcubGFzdE1vZGlmaWVkKSB7XG4gICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgZm9yY2VTZXRJbW11dGFibGUgcmVxdWlyZXMgbGFzdE1vZGlmaWVkIChzeW5jaHJvbml6YXRpb24gd3JpdGVzIGFyZSBvcmRlcmVkIGJ5IHRoZWlyIHdyaXRlIHRpbWUpLCB3cml0aW5nICR7SlNPTi5zdHJpbmdpZnkoa2V5KX0gKHN0b3JlICR7dGhpcy5mb2xkZXJ9KWApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAvLyBJbW11dGFiaWxpdHkgd2luczogYW4gZXhpc3RpbmcgcGF0aCBpcyBrZXB0IGluc3RlYWQgb2YgdGhlIHB1c2ggdGhyb3dpbmcgKHNlZSBTZXRDb25maWcuZm9yY2VTZXRJbW11dGFibGUpXG4gICAgICAgICAgICAgICAgbGV0IHNlbGYgPSBzZWxlY3RFbnRyeUF0KHRoaXMuc3RvcmVDb25maWcuYWxsKCksIHdyaXRlVGltZSwgcm91dGUpO1xuICAgICAgICAgICAgICAgIGlmIChzZWxmPy5pbW11dGFibGUgJiYgYXdhaXQgdGhpcy5nZXRJbmZvKHsgcGF0aDoga2V5IH0pKSByZXR1cm47XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMuYXNzZXJ0TXV0YWJsZShrZXksIHdyaXRlVGltZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGNvbmZpZy5pbnRlcm5hbCkge1xuICAgICAgICAgICAgaWYgKCFjb25maWcubGFzdE1vZGlmaWVkKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbnRlcm5hbCB3cml0ZXMgbXVzdCBjYXJyeSBsYXN0TW9kaWZpZWQgKHRoZXkgYXJlIHN5bmNocm9uaXphdGlvbiBwdXNoZXMsIG9yZGVyZWQgYnkgdGhlaXIgd3JpdGUgdGltZSksIHdyaXRpbmcgJHtKU09OLnN0cmluZ2lmeShrZXkpfSAoc3RvcmUgJHt0aGlzLmZvbGRlcn0pYCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBUaGUgcm91dGluZyBmaWxlIGlzIGV4ZW1wdCBmb3IgdGhlIHNhbWUgcmVhc29uIGl0IHNraXBzIGV2ZXJ5IG90aGVyIGNoZWNrOiBpdCBpcyB0aGUgZmlsZSB0aGF0IERFRklORVMgb3VyIHdpbmRvd3MgYW5kIHJvdXRlcywgc28ganVkZ2luZyBpdCBieSB0aGUgY29uZmlnIGl0IGlzIGFib3V0IHRvIHJlcGxhY2UgaXMgaG93IGEgc3RvcmUgZ2V0cyBzdHVjayBvbiBhIGNvbmZpZyBpdCBjYW4gbmV2ZXIgYmUgdG9sZCB0byBsZWF2ZVxuICAgICAgICAgICAgaWYgKGtleSAhPT0gUk9VVElOR19GSUxFKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5hc3NlcnRJbnRlcm5hbFdyaXRlQWNjZXB0ZWQoa2V5LCBjb25maWcubGFzdE1vZGlmaWVkLCByb3V0ZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBhd2FpdCB0aGlzLnNldEludGVybmFsKGtleSwgZGF0YSwgeyBsYXN0TW9kaWZpZWQ6IGNvbmZpZy5sYXN0TW9kaWZpZWQgfSk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgYXdhaXQgdGhpcy5zZXRPckRlbGV0ZShrZXksIGRhdGEsIHsgbGFzdE1vZGlmaWVkOiBjb25maWcubGFzdE1vZGlmaWVkIH0pO1xuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyBkZWwoY29uZmlnOiB7IHBhdGg6IHN0cmluZzsgbGFzdE1vZGlmaWVkPzogbnVtYmVyOyBpbnRlcm5hbD86IGJvb2xlYW4gfSk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBsZXQga2V5ID0gY29uZmlnLnBhdGg7XG4gICAgICAgIGlmIChrZXkgPT09IFJPVVRJTkdfRklMRSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBUaGUgcm91dGluZyBjb25maWcgJHtKU09OLnN0cmluZ2lmeShST1VUSU5HX0ZJTEUpfSBjYW5ub3QgYmUgZGVsZXRlZCAob3ZlcndyaXRlIGl0IHRvIGNoYW5nZSB0aGUgYnVja2V0J3MgY29uZmlndXJhdGlvbilgKTtcbiAgICAgICAgfVxuICAgICAgICBhd2FpdCB0aGlzLmluaXQoKTtcbiAgICAgICAgLy8gQSBkZWxldGlvbiBsYW5kcyBpbiBleGFjdGx5IHRoZSBzYW1lIHBsYWNlIGEgd3JpdGUgd291bGQsIHNvIGl0IGlzIGp1ZGdlZCB0aGUgc2FtZSB3YXk6IG9uZSBhaW1lZCBhdCBhIHNoYXJkIHdlIGRvbid0IHNlcnZlIGlzIGp1c3QgYXMgaW52aXNpYmxlIGFzIGEgd3JpdGUgdG8gaXRcbiAgICAgICAgdGhpcy5hc3NlcnRXcml0ZVRhcmdldChrZXksIGdldFJvdXRlKGtleSksIGNvbmZpZy5sYXN0TW9kaWZpZWQpO1xuICAgICAgICBpZiAoY29uZmlnLmludGVybmFsKSB7XG4gICAgICAgICAgICBpZiAoIWNvbmZpZy5sYXN0TW9kaWZpZWQpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEludGVybmFsIGRlbGV0aW9ucyBtdXN0IGNhcnJ5IGxhc3RNb2RpZmllZCAodGhleSBhcmUgc3luY2hyb25pemF0aW9uIHB1c2hlcywgb3JkZXJlZCBieSB0aGVpciB3cml0ZSB0aW1lKSwgZGVsZXRpbmcgJHtKU09OLnN0cmluZ2lmeShrZXkpfSAoc3RvcmUgJHt0aGlzLmZvbGRlcn0pYCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLmFzc2VydEludGVybmFsV3JpdGVBY2NlcHRlZChrZXksIGNvbmZpZy5sYXN0TW9kaWZpZWQsIGdldFJvdXRlKGtleSkpO1xuICAgICAgICAgICAgLy8gc2V0SW50ZXJuYWwgdHJlYXRzIGFuIGVtcHR5IGJ1ZmZlciBhcyBleGFjdGx5IGEgZGVsZXRpb246IGRpc2sgcmVtb3ZhbCBwbHVzIGEgdG9tYnN0b25lIGluZGV4IGVudHJ5LCBubyBmYW4tb3V0XG4gICAgICAgICAgICBhd2FpdCB0aGlzLnNldEludGVybmFsKGtleSwgQnVmZmVyLmFsbG9jKDApLCB7IGxhc3RNb2RpZmllZDogY29uZmlnLmxhc3RNb2RpZmllZCB9KTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICAvLyBEZWxldGVzIGFyZSB3cml0ZXMgKGFuIGVtcHR5IGZpbGUgSVMgYSBtaXNzaW5nIGZpbGUpOiB0aGUgdG9tYnN0b25lIGlzIG9yZGVyZWQgYnkgd3JpdGUgdGltZSBsaWtlIGFueSBvdGhlciB3cml0ZSwgcHJvcGFnYXRlcyB0aHJvdWdoIHN5bmNocm9uaXphdGlvbiwgYW5kIGlzIGV2ZW50dWFsbHkgZXhwaXJlZFxuICAgICAgICBhd2FpdCB0aGlzLnNldE9yRGVsZXRlKGtleSwgQnVmZmVyLmFsbG9jKDApLCB7IGxhc3RNb2RpZmllZDogY29uZmlnLmxhc3RNb2RpZmllZCB9KTtcbiAgICB9XG5cbiAgICAvKiogQSBub2RlLXNpZGUgbW92ZTogdGhlIGJ5dGVzIG5ldmVyIHRyYXZlbCB0aHJvdWdoIHRoZSBjbGllbnQuIERlbGliZXJhdGVseSBqdXN0IGdldDIgKyBzZXQgKyBkZWwgcmF0aGVyIHRoYW4gYSBkaXNrIHJlbmFtZSwgc28gdGhlIGRlc3RpbmF0aW9uIHdyaXRlIHBhc3NlcyBFVkVSWSBydWxlIGEgc2V0IHBhc3NlcyAod2luZG93cywgcm91dGVzLCBpbW11dGFiaWxpdHksIG9ubHktdGFrZS1sYXRlc3QsIGluZGV4LCBmYW4tb3V0IHRvIHBlZXJzKSBhbmQgdGhlIGRlbGV0aW9uIHByb3BhZ2F0ZXMgYXMgYSBub3JtYWwgdG9tYnN0b25lIC0gYSByZW5hbWUgd291bGQgYnlwYXNzIGFsbCBvZiBpdC4gVGhlIHNldCBzdGFtcHMgZnJlc2gsIHNvIHRoZSBtb3ZlZCBmaWxlIGJlYXRzIGFueSB0b21ic3RvbmUgYXQgaXRzIG5ldyBwYXRoLiAqL1xuICAgIHB1YmxpYyBhc3luYyBtb3ZlKGNvbmZpZzogeyBmcm9tUGF0aDogc3RyaW5nOyB0b1BhdGg6IHN0cmluZyB9KTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGF3YWl0IHRoaXMuaW5pdCgpO1xuICAgICAgICBpZiAoY29uZmlnLmZyb21QYXRoID09PSBjb25maWcudG9QYXRoKSByZXR1cm47XG4gICAgICAgIGlmIChjb25maWcuZnJvbVBhdGggPT09IFJPVVRJTkdfRklMRSB8fCBjb25maWcudG9QYXRoID09PSBST1VUSU5HX0ZJTEUpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgVGhlIHJvdXRpbmcgY29uZmlnICR7SlNPTi5zdHJpbmdpZnkoUk9VVElOR19GSUxFKX0gY2Fubm90IGJlIG1vdmVkIChzdG9yZSAke3RoaXMuZm9sZGVyfSlgKTtcbiAgICAgICAgfVxuICAgICAgICBsZXQgcmVzdWx0ID0gYXdhaXQgdGhpcy5nZXQyKHsgcGF0aDogY29uZmlnLmZyb21QYXRoIH0pO1xuICAgICAgICBpZiAoIXJlc3VsdCB8fCAhcmVzdWx0LmRhdGEubGVuZ3RoKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYENhbm5vdCBtb3ZlICR7SlNPTi5zdHJpbmdpZnkoY29uZmlnLmZyb21QYXRoKX0gdG8gJHtKU09OLnN0cmluZ2lmeShjb25maWcudG9QYXRoKX06IHRoZSBzb3VyY2UgZmlsZSBkb2VzIG5vdCBleGlzdCAoc3RvcmUgJHt0aGlzLmZvbGRlcn0pYCk7XG4gICAgICAgIH1cbiAgICAgICAgYXdhaXQgdGhpcy5zZXQoeyBwYXRoOiBjb25maWcudG9QYXRoLCBkYXRhOiByZXN1bHQuZGF0YSB9KTtcbiAgICAgICAgYXdhaXQgdGhpcy5kZWwoeyBwYXRoOiBjb25maWcuZnJvbVBhdGggfSk7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIGdldEluZm8oY29uZmlnOiB7IHBhdGg6IHN0cmluZzsgaW5jbHVkZVRvbWJzdG9uZXM/OiBib29sZWFuIH0pOiBQcm9taXNlPHsgd3JpdGVUaW1lOiBudW1iZXI7IHNpemU6IG51bWJlciB9IHwgdW5kZWZpbmVkPiB7XG4gICAgICAgIGF3YWl0IHRoaXMuaW5pdCgpO1xuICAgICAgICBsZXQga2V5ID0gY29uZmlnLnBhdGg7XG4gICAgICAgIC8vIE5vdCBpbiB0aGUgaW5kZXggbWVhbnMgaXQgZG9lcyBub3QgZXhpc3QgaGVyZTogdGhlIGluZGV4IElTIHRoZSBhbnN3ZXIsIGFuZCBzY2FubmluZyBoZWFscyBpdCBvbiBpdHMgb3duIHNjaGVkdWxlLiBBbiBlbnRyeSB3aG9zZSBob2xkZXIgaXMgbm8gbG9uZ2VyIGluIHRoZSBzb3VyY2UgbGlzdCBpcyBzdGlsbCB2YWxpZCAtIGdldEVudHJ5SG9sZGVyIHJlc29sdmVzIHRoZSBwZXJzaXN0ZWQgVVJMIGRpcmVjdGx5LCBhbmQgZ2V0MidzIGZhbGxiYWNrIGxvb3AgY292ZXJzIGEgaG9sZGVyIHRoYXQgaXMgZ29uZSBlbnRpcmVseS5cbiAgICAgICAgbGV0IGVudHJ5ID0gdGhpcy5nZXRJbmRleEVudHJ5KGtleSk7XG4gICAgICAgIGlmIChlbnRyeSkgcmV0dXJuIHsgd3JpdGVUaW1lOiBlbnRyeS53cml0ZVRpbWUsIHNpemU6IGVudHJ5LnNpemUgfTtcbiAgICAgICAgaWYgKCFjb25maWcuaW5jbHVkZVRvbWJzdG9uZXMpIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgIGxldCBkZWxldGVkID0gdGhpcy5nZXREZWxldGVkRW50cnkoa2V5KTtcbiAgICAgICAgaWYgKCFkZWxldGVkKSByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICByZXR1cm4geyB3cml0ZVRpbWU6IGRlbGV0ZWQud3JpdGVUaW1lLCBzaXplOiAwIH07XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIGZpbmRJbmZvKGNvbmZpZzogRmluZENvbmZpZyAmIHsgcHJlZml4OiBzdHJpbmcgfSk6IFByb21pc2U8QXJjaGl2ZUZpbGVJbmZvW10+IHtcbiAgICAgICAgYXdhaXQgdGhpcy5pbml0KCk7XG4gICAgICAgIGF3YWl0IHRoaXMuc3luYy53YWl0Rm9yUmVxdWlyZWRTY2FucygpO1xuICAgICAgICBsZXQgcHJlZml4ID0gY29uZmlnLnByZWZpeDtcbiAgICAgICAgbGV0IGluZm9zID0gbmV3IE1hcDxzdHJpbmcsIEFyY2hpdmVGaWxlSW5mbz4oKTtcbiAgICAgICAgLy8gRGVsZXRpb25zIGFyZSBub3QgaW4gaGVyZSBhdCBhbGwsIHdoaWNoIGlzIHdoYXQgYSBsaXN0aW5nIHdhbnRzOiBhbiBlbXB0eSBmaWxlIElTIGEgbWlzc2luZyBmaWxlXG4gICAgICAgIGZvciAobGV0IFtrZXksIGVudHJ5XSBvZiB0aGlzLmluZGV4RW50cmllcygpKSB7XG4gICAgICAgICAgICBpZiAoIWtleS5zdGFydHNXaXRoKHByZWZpeCkpIGNvbnRpbnVlO1xuICAgICAgICAgICAgaW5mb3Muc2V0KGtleSwgeyBwYXRoOiBrZXksIGNyZWF0ZVRpbWU6IGVudHJ5LndyaXRlVGltZSwgc2l6ZTogZW50cnkuc2l6ZSB9KTtcbiAgICAgICAgfVxuICAgICAgICBsZXQgZmlsZXMgPSBhcHBseUZpbmRJbmZvU2hhcGUoQXJyYXkuZnJvbShpbmZvcy52YWx1ZXMoKSksIHByZWZpeCwgeyBzaGFsbG93OiBjb25maWcuc2hhbGxvdywgdHlwZTogY29uZmlnLnR5cGUgfSk7XG4gICAgICAgIHNvcnQoZmlsZXMsIHggPT4geC5wYXRoKTtcbiAgICAgICAgcmV0dXJuIGZpbGVzO1xuICAgIH1cblxuICAgIC8vIEFsbCBmaWxlcyBjaGFuZ2VkIGFmdGVyIGNvbmZpZy50aW1lIOKAlCBzdHJhaWdodCBmcm9tIHRoZSBpbmRleC4gRmlsdGVycyBvbiB3aGVuIFdFIGxlYXJuZWQgb2YgdGhlIGNoYW5nZSAoY2hhbmdlZEF0KSwgc28gZmlsZXMgc3luY2hyb25pemVkIGxhdGUgKHdpdGggb2xkIHdyaXRlIHRpbWVzKSBhcmUgc3RpbGwgcmVwb3J0ZWQuIERlbGV0aW9ucyBBUkUgcmVwb3J0ZWQsIGFzIHNpemUtMCBlbnRyaWVzOiBhIGNhbGxlciByZWFkaW5nIGEgY2hhbmdlIGZlZWQgaGFzIHRvIGhlYXIgYWJvdXQgdGhlbSwgYW5kIHNpemUgMCBpcyBob3cgdGhlIGZlZWQgc2F5cyBcImdvbmVcIiAoYW4gZW1wdHkgZmlsZSBJUyBhIG1pc3NpbmcgZmlsZSkuIGNvbmZpZy5yb3V0ZXMgbGV0cyBhIHN0b3JlIHN5bmNpbmcgYSBwYXJ0aWFsIHNoYXJkIGFzayBmb3IganVzdCBpdHMgc2xpY2UuXG4gICAgcHVibGljIGFzeW5jIGdldENoYW5nZXNBZnRlcjIoY29uZmlnOiBDaGFuZ2VzQWZ0ZXJDb25maWcpOiBQcm9taXNlPEFyY2hpdmVGaWxlSW5mb1tdPiB7XG4gICAgICAgIGF3YWl0IHRoaXMuaW5pdCgpO1xuICAgICAgICBhd2FpdCB0aGlzLnN5bmMud2FpdEZvclJlcXVpcmVkU2NhbnMoKTtcbiAgICAgICAgbGV0IGluUm91dGVzID0gKGtleTogc3RyaW5nKSA9PiAhY29uZmlnLnJvdXRlcyB8fCBjb25maWcucm91dGVzLnNvbWUocm91dGUgPT4gcm91dGVDb250YWlucyhyb3V0ZSwgZ2V0Um91dGUoa2V5KSkpO1xuICAgICAgICBsZXQgZmlsZXM6IEFyY2hpdmVGaWxlSW5mb1tdID0gW107XG4gICAgICAgIGZvciAobGV0IFtrZXksIGVudHJ5XSBvZiB0aGlzLmluZGV4RW50cmllcygpKSB7XG4gICAgICAgICAgICBpZiAoZW50cnkuY2hhbmdlZEF0IDw9IGNvbmZpZy50aW1lKSBjb250aW51ZTtcbiAgICAgICAgICAgIGlmICghaW5Sb3V0ZXMoa2V5KSkgY29udGludWU7XG4gICAgICAgICAgICBmaWxlcy5wdXNoKHsgcGF0aDoga2V5LCBjcmVhdGVUaW1lOiBlbnRyeS53cml0ZVRpbWUsIHNpemU6IGVudHJ5LnNpemUgfSk7XG4gICAgICAgIH1cbiAgICAgICAgZm9yIChsZXQgW2tleSwgdG9tYnN0b25lXSBvZiB0aGlzLmRlbGV0ZWRFbnRyaWVzKCkpIHtcbiAgICAgICAgICAgIGlmICh0b21ic3RvbmUuY2hhbmdlZEF0IDw9IGNvbmZpZy50aW1lKSBjb250aW51ZTtcbiAgICAgICAgICAgIGlmICghaW5Sb3V0ZXMoa2V5KSkgY29udGludWU7XG4gICAgICAgICAgICBmaWxlcy5wdXNoKHsgcGF0aDoga2V5LCBjcmVhdGVUaW1lOiB0b21ic3RvbmUud3JpdGVUaW1lLCBzaXplOiAwIH0pO1xuICAgICAgICB9XG4gICAgICAgIHNvcnQoZmlsZXMsIHggPT4geC5wYXRoKTtcbiAgICAgICAgcmV0dXJuIGZpbGVzO1xuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyBnZXRTeW5jU3RhdHVzKCk6IFByb21pc2U8QXJjaGl2ZXNTeW5jU3RhdHVzPiB7XG4gICAgICAgIGF3YWl0IHRoaXMuaW5pdCgpO1xuICAgICAgICByZXR1cm4gdGhpcy5zeW5jLmdldFN0YXR1cygpO1xuICAgIH1cblxuICAgIC8qKiBUaGUgaW5kZXgncyB0b3RhbHMgcGx1cyBhbnkgaW4tcHJvZ3Jlc3MgYmFja2dyb3VuZCBzeW5jaHJvbml6YXRpb24uICovXG4gICAgcHVibGljIGdldFN5bmNQcm9ncmVzcygpOiB7XG4gICAgICAgIGluZGV4OiB7IGZpbGVDb3VudDogbnVtYmVyOyBieXRlQ291bnQ6IG51bWJlciB9O1xuICAgICAgICBzb3VyY2VzOiB7IGRlYnVnTmFtZTogc3RyaW5nOyBmaWxlQ291bnQ6IG51bWJlcjsgYnl0ZUNvdW50OiBudW1iZXIgfVtdO1xuICAgICAgICByZWFkZXJEaXNrTGltaXQ/OiBudW1iZXI7XG4gICAgICAgIHN5bmNpbmc6IFN5bmNBY3Rpdml0eVtdO1xuICAgIH0ge1xuICAgICAgICBsZXQgdG90YWxzID0gdGhpcy5uYW1lZEluZGV4VG90YWxzKCk7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBpbmRleDogeyBmaWxlQ291bnQ6IHRvdGFscy5maWxlQ291bnQsIGJ5dGVDb3VudDogdG90YWxzLmJ5dGVDb3VudCB9LFxuICAgICAgICAgICAgc291cmNlczogdG90YWxzLnNvdXJjZXMsXG4gICAgICAgICAgICByZWFkZXJEaXNrTGltaXQ6IHRoaXMucmVhZGVyRGlza0xpbWl0LFxuICAgICAgICAgICAgc3luY2luZzogdGhpcy5zeW5jLmdldEFjdGl2aXRpZXMoKSxcbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICAvKiogZ2V0U3luY1Byb2dyZXNzJ3MgdG90YWxzLCBidXQgbG9hZGluZyB0aGUgaW5kZXggZmlyc3QsIHNvIHRoZXkgYXJlIG5ldmVyIHRoZSB6ZXJvZXMgb2YgYSBzdG9yZSBub3RoaW5nIGhhcyB0b3VjaGVkIHlldC4gKi9cbiAgICBwdWJsaWMgYXN5bmMgY29tcHV0ZUluZGV4VG90YWxzKCk6IFByb21pc2U8e1xuICAgICAgICBmaWxlQ291bnQ6IG51bWJlcjtcbiAgICAgICAgYnl0ZUNvdW50OiBudW1iZXI7XG4gICAgICAgIHNvdXJjZXM6IHsgZGVidWdOYW1lOiBzdHJpbmc7IGZpbGVDb3VudDogbnVtYmVyOyBieXRlQ291bnQ6IG51bWJlciB9W107XG4gICAgfT4ge1xuICAgICAgICBhd2FpdCB0aGlzLmluaXQoKTtcbiAgICAgICAgcmV0dXJuIHRoaXMubmFtZWRJbmRleFRvdGFscygpO1xuICAgIH1cblxuICAgIHByaXZhdGUgbmFtZWRJbmRleFRvdGFscygpOiB7IGZpbGVDb3VudDogbnVtYmVyOyBieXRlQ291bnQ6IG51bWJlcjsgc291cmNlczogeyBkZWJ1Z05hbWU6IHN0cmluZzsgZmlsZUNvdW50OiBudW1iZXI7IGJ5dGVDb3VudDogbnVtYmVyIH1bXSB9IHtcbiAgICAgICAgbGV0IHRvdGFscyA9IHRoaXMuaW5kZXhUb3RhbHMoKTtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIGZpbGVDb3VudDogdG90YWxzLmZpbGVDb3VudCxcbiAgICAgICAgICAgIGJ5dGVDb3VudDogdG90YWxzLmJ5dGVDb3VudCxcbiAgICAgICAgICAgIHNvdXJjZXM6IHRoaXMuc291cmNlc1xuICAgICAgICAgICAgICAgIC5tYXAoKHgsIGkpID0+ICh7IGRlYnVnTmFtZTogeC5zb3VyY2UuZ2V0RGVidWdOYW1lKCksIC4uLnRvdGFscy5zbG90c1tpXSB9KSlcbiAgICAgICAgICAgICAgICAuZmlsdGVyKCh4LCBpKSA9PiB0aGlzLmlzTGl2ZShpKSksXG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVGhlIHN0b3JlJ3Mgc291cmNlcywgYXMgdGhlIGN1cnJlbnQgcm91dGluZyBjb25maWcgc2F5cyB0aGV5IHNob3VsZCBiZS4gVGhpcyBpcyB0aGUgT05MWSB3YXlcbiAgICAgKiB0aGV5IGFyZSBldmVyIHNldDogdGhlIGZpcnN0IGNhbGwgcG9wdWxhdGVzIGFuIGVtcHR5IHN0b3JlLCBldmVyeSBsYXRlciBvbmUgYXBwbGllcyBhIGNoYW5nZSB0b1xuICAgICAqIHRoZSBydW5uaW5nIG9uZS4gV2luZG93cywgcm91dGVzIGFuZCBmbGFncyBtb3ZlIGluIHBsYWNlLCBnZW51aW5lbHkgbmV3IGVuZHBvaW50cyBhcmUgYWRkZWQgYW5kXG4gICAgICogc3RhcnQgc2Nhbm5pbmcsIGFuZCBlbmRwb2ludHMgdGhhdCBhcmUgZ29uZSBnbyBkZWFkICh0aGVpciBzY2FucyBzdG9wLCB0aGVpciBpbmRleCBlbnRyaWVzXG4gICAgICogZHJvcCkuXG4gICAgICpcbiAgICAgKiBBIHN0b3JlIGlzIG5ldmVyIHJlYnVpbHQgZm9yIGEgY29uZmlnIGNoYW5nZS4gSXRzIG5hbWUgZGVjaWRlcyBpdHMgZm9sZGVyIGFuZCBpdHMgaWRlbnRpdHksIGFuZFxuICAgICAqIGEgY29uZmlnIGNoYW5nZSBjYW5ub3QgY2hhbmdlIGVpdGhlciAtIHNvIHRoZXJlIGlzIG5vdGhpbmcgYSBjaGFuZ2UgY2FuIGRvIHRvIGEgc3RvcmUgZXhjZXB0XG4gICAgICogdGhpcy5cbiAgICAgKi9cbiAgICBwdWJsaWMgdXBkYXRlU291cmNlcyhzcGVjczogQmxvYlNvdXJjZVNwZWNbXSk6IHZvaWQge1xuICAgICAgICBpZiAoIXNwZWNzLmxlbmd0aCB8fCBzcGVjc1swXS5pZGVudGl0eSAhPT0gXCJkaXNrXCIpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgdXBkYXRlU291cmNlcyBleHBlY3RzIHRoZSBkaXNrIHNvdXJjZSBmaXJzdCAoaWRlbnRpdHkgXCJkaXNrXCIpLCBnb3QgJHtKU09OLnN0cmluZ2lmeShzcGVjcy5tYXAoeCA9PiB4LmlkZW50aXR5KSl9IChzdG9yZSAke3RoaXMuZm9sZGVyfSlgKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIXRoaXMuc291cmNlcy5sZW5ndGgpIHtcbiAgICAgICAgICAgIC8vIEZpcnN0IGNhbGw6IHRoZSBkaXNrIHNsb3QgaGFzIHRvIGV4aXN0IGJlZm9yZSBhbnl0aGluZyBjYW4gYmUgbWF0Y2hlZCBhZ2FpbnN0IGl0XG4gICAgICAgICAgICBsZXQgZGlzayA9IHNwZWNzWzBdO1xuICAgICAgICAgICAgbGV0IHNvdXJjZSA9IGRpc2suY3JlYXRlKCk7XG4gICAgICAgICAgICBhc0RlbGF5ZWQoc291cmNlKT8uYmluZEZsdXNoRGVhZGxpbmUoKCkgPT4gdGhpcy53cml0ZUZsdXNoRGVhZGxpbmUoKSk7XG4gICAgICAgICAgICB0aGlzLnNvdXJjZXMucHVzaCh7IHNvdXJjZSwgdXJsOiBkaXNrLnVybCwgdmFsaWRXaW5kb3dzOiBkaXNrLnZhbGlkV2luZG93cywgcm91dGU6IGRpc2sucm91dGUsIG5vRnVsbFN5bmM6IGRpc2subm9GdWxsU3luYywgc291cmNlQ29uZmlnOiBkaXNrLnNvdXJjZUNvbmZpZywgaWRlbnRpdHk6IGRpc2suaWRlbnRpdHkgfSk7XG4gICAgICAgICAgICB0aGlzLnN5bmMuYWRkU291cmNlKDApO1xuICAgICAgICB9XG4gICAgICAgIGxldCBzZXRXaW5kb3dzID0gKGk6IG51bWJlciwgd2luZG93czogW251bWJlciwgbnVtYmVyXVtdKSA9PiB7XG4gICAgICAgICAgICBsZXQgb2xkID0gdGhpcy5zb3VyY2VzW2ldLnZhbGlkV2luZG93cztcbiAgICAgICAgICAgIGlmIChKU09OLnN0cmluZ2lmeShvbGQpID09PSBKU09OLnN0cmluZ2lmeSh3aW5kb3dzKSkgcmV0dXJuO1xuICAgICAgICAgICAgY29uc29sZS5sb2coYFZhbGlkIHdpbmRvd3MgY2hhbmdlZCBmb3IgJHt0aGlzLnNvdXJjZXNbaV0uc291cmNlLmdldERlYnVnTmFtZSgpfSAoc3RvcmUgJHt0aGlzLmZvbGRlcn0pOiAke0pTT04uc3RyaW5naWZ5KG9sZCl9IC0+ICR7SlNPTi5zdHJpbmdpZnkod2luZG93cyl9YCk7XG4gICAgICAgICAgICB0aGlzLnNvdXJjZXNbaV0udmFsaWRXaW5kb3dzID0gd2luZG93cztcbiAgICAgICAgfTtcbiAgICAgICAgc2V0V2luZG93cygwLCBzcGVjc1swXS52YWxpZFdpbmRvd3MpO1xuICAgICAgICAvLyBMaXZlIHNsb3RzIHBhaXIgd2l0aCBzcGVjcyBieSBpZGVudGl0eS4gRWFjaCBlbmRwb2ludCBpcyBub3cgT05FIHNwZWMgY2FycnlpbmcgYWxsIGl0cyB3aW5kb3dzLCBzbyB0aGlzIGlzIGEgMToxIHBhaXJpbmc7IGFueSBsZWZ0b3ZlciBkdXBsaWNhdGUgc2xvdHMgZnJvbSBiZWZvcmUgKGFuIGVuZHBvaW50IHRoYXQgdXNlZCB0byBiZSBzcGxpdCBpbnRvIHNldmVyYWwgc2xvdHMpIGdvIHVubWF0Y2hlZCBiZWxvdyBhbmQgYXJlIGNvbGxhcHNlZCBhd2F5LlxuICAgICAgICBsZXQgbGl2ZUJ5SWRlbnRpdHkgPSBuZXcgTWFwPHN0cmluZywgbnVtYmVyW10+KCk7XG4gICAgICAgIGxldCBvcmlnaW5hbExlbmd0aCA9IHRoaXMuc291cmNlcy5sZW5ndGg7XG4gICAgICAgIGZvciAobGV0IGkgPSAxOyBpIDwgb3JpZ2luYWxMZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgaWYgKCF0aGlzLmlzTGl2ZShpKSkgY29udGludWU7XG4gICAgICAgICAgICBsZXQgaWQgPSB0aGlzLnNvdXJjZXNbaV0uaWRlbnRpdHk7XG4gICAgICAgICAgICBpZiAoaWQgPT09IHVuZGVmaW5lZCkgY29udGludWU7XG4gICAgICAgICAgICBsZXQgbGlzdCA9IGxpdmVCeUlkZW50aXR5LmdldChpZCk7XG4gICAgICAgICAgICBpZiAoIWxpc3QpIHtcbiAgICAgICAgICAgICAgICBsaXN0ID0gW107XG4gICAgICAgICAgICAgICAgbGl2ZUJ5SWRlbnRpdHkuc2V0KGlkLCBsaXN0KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGxpc3QucHVzaChpKTtcbiAgICAgICAgfVxuICAgICAgICBsZXQgbWF0Y2hlZCA9IG5ldyBTZXQ8bnVtYmVyPigpO1xuICAgICAgICBmb3IgKGxldCBzcGVjIG9mIHNwZWNzLnNsaWNlKDEpKSB7XG4gICAgICAgICAgICBsZXQgc2xvdCA9IGxpdmVCeUlkZW50aXR5LmdldChzcGVjLmlkZW50aXR5KT8uc2hpZnQoKTtcbiAgICAgICAgICAgIGlmIChzbG90ICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICAvLyBUaGUgU0FNRSBlbmRwb2ludCAoc2VlIHNvdXJjZUlkZW50aXR5KSwgc28gd2UgYXJlIGFscmVhZHkgc3luY2hyb25pemVkIHdpdGggaXQ6IHRoZSBzbG90IGtlZXBzIGl0cyBjb25uZWN0aW9uLCBpdHMgY29tcGxldGVkIHNjYW5zLCBhbmQgaXRzIGluZGV4IGVudHJpZXMsIGFuZCBvbmx5IHRoZSBwb2xpY3kgb24gaXQgbW92ZXMuIFJlY3JlYXRpbmcgaXQgaGVyZSB3b3VsZCBtZWFuIHJlc2Nhbm5pbmcgdGhlIGVuZHBvaW50IGZyb20gc2NyYXRjaCBldmVyeSB0aW1lIGEgZmxhZyBjaGFuZ2VzLlxuICAgICAgICAgICAgICAgIG1hdGNoZWQuYWRkKHNsb3QpO1xuICAgICAgICAgICAgICAgIHNldFdpbmRvd3Moc2xvdCwgc3BlYy52YWxpZFdpbmRvd3MpO1xuICAgICAgICAgICAgICAgIGxldCBleGlzdGluZyA9IHRoaXMuc291cmNlc1tzbG90XTtcbiAgICAgICAgICAgICAgICBpZiAoSlNPTi5zdHJpbmdpZnkoZXhpc3Rpbmcucm91dGUpICE9PSBKU09OLnN0cmluZ2lmeShzcGVjLnJvdXRlKSkge1xuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhgUm91dGUgY2hhbmdlZCBmb3IgJHtleGlzdGluZy5zb3VyY2UuZ2V0RGVidWdOYW1lKCl9IChzdG9yZSAke3RoaXMuZm9sZGVyfSk6ICR7SlNPTi5zdHJpbmdpZnkoZXhpc3Rpbmcucm91dGUpfSAtPiAke0pTT04uc3RyaW5naWZ5KHNwZWMucm91dGUpfWApO1xuICAgICAgICAgICAgICAgICAgICBleGlzdGluZy5yb3V0ZSA9IHNwZWMucm91dGU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmIChKU09OLnN0cmluZ2lmeShleGlzdGluZy5zb3VyY2VDb25maWcpICE9PSBKU09OLnN0cmluZ2lmeShzcGVjLnNvdXJjZUNvbmZpZykpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coYENvbmZpZyBjaGFuZ2VkIGZvciAke2V4aXN0aW5nLnNvdXJjZS5nZXREZWJ1Z05hbWUoKX0gKHN0b3JlICR7dGhpcy5mb2xkZXJ9KSwga2VlcGluZyB0aGUgc291cmNlIChzbyBpdCBpcyBub3QgcmVzY2FubmVkKTogJHtKU09OLnN0cmluZ2lmeShleGlzdGluZy5zb3VyY2VDb25maWcpfSAtPiAke0pTT04uc3RyaW5naWZ5KHNwZWMuc291cmNlQ29uZmlnKX1gKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgLy8gVGhlIHNvdXJjZSBjYXJyaWVzIGl0cyBjb25maWcgKGFuZCBpdHMgd3JpdGUgZGVsYXkpIGludG8gZXZlcnl0aGluZyBpdCBkb2VzLCBzbyBpdCBoYXMgdG8gbGVhcm4gdGhlIG5ldyBvbmUgLSBzZWUgYXBwbHlTb3VyY2VDb25maWdcbiAgICAgICAgICAgICAgICBzcGVjLmFwcGx5Q29uZmlnPy4oZXhpc3Rpbmcuc291cmNlKTtcbiAgICAgICAgICAgICAgICBleGlzdGluZy5ub0Z1bGxTeW5jID0gc3BlYy5ub0Z1bGxTeW5jO1xuICAgICAgICAgICAgICAgIGV4aXN0aW5nLnNvdXJjZUNvbmZpZyA9IHNwZWMuc291cmNlQ29uZmlnO1xuICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgbGV0IHNvdXJjZSA9IHNwZWMuY3JlYXRlKCk7XG4gICAgICAgICAgICBhc0RlbGF5ZWQoc291cmNlKT8uYmluZEZsdXNoRGVhZGxpbmUoKCkgPT4gdGhpcy53cml0ZUZsdXNoRGVhZGxpbmUoKSk7XG4gICAgICAgICAgICB0aGlzLnNvdXJjZXMucHVzaCh7IHNvdXJjZSwgdXJsOiBzcGVjLnVybCwgdmFsaWRXaW5kb3dzOiBzcGVjLnZhbGlkV2luZG93cywgcm91dGU6IHNwZWMucm91dGUsIG5vRnVsbFN5bmM6IHNwZWMubm9GdWxsU3luYywgaW50ZXJtZWRpYXRlOiBzcGVjLmludGVybWVkaWF0ZSwgc291cmNlQ29uZmlnOiBzcGVjLnNvdXJjZUNvbmZpZywgaWRlbnRpdHk6IHNwZWMuaWRlbnRpdHkgfSk7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhgQWRkZWQgc3luYyBzb3VyY2UgJHtzb3VyY2UuZ2V0RGVidWdOYW1lKCl9IChzdG9yZSAke3RoaXMuZm9sZGVyfSk6IGEgZ2VudWluZWx5IG5ldyBlbmRwb2ludCwgc28gaXQgaXMgc2Nhbm5lZCBmcm9tIHNjcmF0Y2hgKTtcbiAgICAgICAgICAgIHRoaXMuc3luYy5hZGRTb3VyY2UodGhpcy5zb3VyY2VzLmxlbmd0aCAtIDEpO1xuICAgICAgICB9XG4gICAgICAgIGZvciAobGV0IGkgPSAxOyBpIDwgb3JpZ2luYWxMZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgaWYgKCF0aGlzLmlzTGl2ZShpKSB8fCBtYXRjaGVkLmhhcyhpKSkgY29udGludWU7XG4gICAgICAgICAgICAvLyBUaGUgc2xvdCBpcyBkZWFkIHRoZSBtb21lbnQgdGhpcyByZXR1cm5zOyBkcm9wcGluZyB0aGUgaW5kZXggZW50cmllcyBpdCBoZWxkIGlzIHRoZSBwYXJ0IHRoYXQgcmVhZHMgdGhlIGluZGV4LCBzbyBpdCBmaW5pc2hlcyBpbiB0aGUgYmFja2dyb3VuZFxuICAgICAgICAgICAgdm9pZCB0aGlzLnN5bmMucmVtb3ZlU291cmNlKGkpLmNhdGNoKChlOiBFcnJvcikgPT4gY29uc29sZS5lcnJvcihgUmVtb3Zpbmcgc3luYyBzb3VyY2UgJHt0aGlzLnNvdXJjZXNbaV0uc291cmNlLmdldERlYnVnTmFtZSgpfSAoc3RvcmUgJHt0aGlzLmZvbGRlcn0pIGZhaWxlZDogJHtlLnN0YWNrID8/IGV9YCkpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqIFJlc2NhbnMgb3VyIG93biBkaXNrJ3MgbWV0YWRhdGEgaW50byB0aGUgaW5kZXggLSB1c2VkIGFyb3VuZCB2YWxpZCB3aW5kb3cgaGFuZG9mZnMsIHdoZXJlIGFub3RoZXIgcHJvY2VzcyB3cm90ZSBmaWxlcyB0byB0aGUgc2hhcmVkIGZvbGRlciB0aGF0IG91ciBpbmRleCBoYXNuJ3Qgc2Vlbi4gKi9cbiAgICBwdWJsaWMgYXN5bmMgcmVzY2FuQmFzZSgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgYXdhaXQgdGhpcy5pbml0KCk7XG4gICAgICAgIGF3YWl0IHRoaXMuc3luYy5yZXNjYW5CYXNlKCk7XG4gICAgfVxuXG4gICAgLyoqIEEgYm91bmRhcnkgc2NhbiBvZiB0aGUgbm9kZSB0aGF0IG93bmVkIChwYXJ0IG9mKSBvdXIgcm91dGUgaW4gdGhlIHZhbGlkIHdpbmRvdyBiZWZvcmUgb3Vycywgd2hlbiB0aGF0IG5vZGUgaXMgZGlmZmVyZW50IHN0b3JhZ2UgKGEgZGlzayByZXNjYW4gY2FuJ3Qgc2VlIGl0cyB3cml0ZXMpLiAqL1xuICAgIHB1YmxpYyBhc3luYyBib3VuZGFyeVNjYW5SZW1vdGUoc291cmNlOiBJQXJjaGl2ZXMsIGNvbmZpZzogeyBzaW5jZTogbnVtYmVyOyByb3V0ZT86IFtudW1iZXIsIG51bWJlcl0gfSk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBhd2FpdCB0aGlzLmluaXQoKTtcbiAgICAgICAgYXdhaXQgdGhpcy5zeW5jLmJvdW5kYXJ5U2NhblJlbW90ZShzb3VyY2UsIGNvbmZpZyk7XG4gICAgfVxuXG4gICAgLy8gTGFyZ2UgdXBsb2FkcyBzdHJlYW0gb250byB0aGUgbG9jYWwgZGlzayBzb3VyY2UgZGlyZWN0bHkgKHRoZXkgbWF5IG5vdCBmaXQgaW4gbWVtb3J5KSwgYW5kIHJlY29uY2lsaWF0aW9uIGNhcnJpZXMgdGhlbSB0byB0aGUgb3RoZXIgc291cmNlcyAtIHRoZXJlIGlzIG5vIGRlbGF5ZWQtd3JpdGUgc3RhZ2UgdGhleSBjb3VsZCBwYXNzIHRocm91Z2guIFRoZSB3cml0ZSBpdHNlbGYgaXMgdmFsaWRhdGVkIGV4YWN0bHkgbGlrZSBzZXQncywgcmlnaHQgaGVyZTogdGhlIGNsaWVudCBpcyBhYm91dCB0byBzZW5kIHRoZSB3aG9sZSBmaWxlLCBzbyBldmVyeSByZWFzb24gdG8gcmVmdXNlIGl0IG11c3QgYmUgZm91bmQgYmVmb3JlIHRoZSBmaXJzdCBieXRlLlxuICAgIHB1YmxpYyBhc3luYyBzdGFydExhcmdlVXBsb2FkKGNvbmZpZz86IHsgcGF0aD86IHN0cmluZzsgbGFzdE1vZGlmaWVkPzogbnVtYmVyOyBmb3JjZVNldEltbXV0YWJsZT86IGJvb2xlYW47IG5vQ2hlY2tzPzogYm9vbGVhbjsgaW50ZXJuYWw/OiBib29sZWFuIH0pOiBQcm9taXNlPHN0cmluZz4ge1xuICAgICAgICBhd2FpdCB0aGlzLmluaXQoKTtcbiAgICAgICAgbGV0IGtleSA9IGNvbmZpZz8ucGF0aDtcbiAgICAgICAgaWYgKGtleSkge1xuICAgICAgICAgICAgbGV0IHdyaXRlVGltZSA9IGNvbmZpZz8ubGFzdE1vZGlmaWVkIHx8IERhdGUubm93KCk7XG4gICAgICAgICAgICBsZXQgcm91dGUgPSBnZXRSb3V0ZShrZXkpO1xuICAgICAgICAgICAgaWYgKGtleSAhPT0gUk9VVElOR19GSUxFKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5hc3NlcnRXcml0ZVRhcmdldChrZXksIHJvdXRlLCBjb25maWc/Lmxhc3RNb2RpZmllZCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoa2V5ICE9PSBST1VUSU5HX0ZJTEUgJiYgdGhpcy5zdG9yZUNvbmZpZy5hbGwoKS5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICBpZiAoY29uZmlnPy5mb3JjZVNldEltbXV0YWJsZSkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoIWNvbmZpZy5sYXN0TW9kaWZpZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgZm9yY2VTZXRJbW11dGFibGUgcmVxdWlyZXMgbGFzdE1vZGlmaWVkIChzeW5jaHJvbml6YXRpb24gd3JpdGVzIGFyZSBvcmRlcmVkIGJ5IHRoZWlyIHdyaXRlIHRpbWUpLCB1cGxvYWRpbmcgJHtKU09OLnN0cmluZ2lmeShrZXkpfSAoc3RvcmUgJHt0aGlzLmZvbGRlcn0pYCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgLy8gSW1tdXRhYmlsaXR5IHdpbnM6IGFuIGV4aXN0aW5nIHBhdGggaXMga2VwdCBpbnN0ZWFkIG9mIHRoZSBwdXNoIHRocm93aW5nIChzZWUgU2V0Q29uZmlnLmZvcmNlU2V0SW1tdXRhYmxlKS4gVGhlIGNsaWVudCBpcyBhbHJlYWR5IHN0cmVhbWluZywgc28gdGhlIHVwbG9hZCBpcyBhY2NlcHRlZCBhbmQgZXZlcnkgcGFydCBkaXNjYXJkZWQgLSB0aGUgYWx0ZXJuYXRpdmUgaXMgdGhyb3dpbmcgYXQgYSBjYWxsZXIgdGhhdCBkaWQgbm90aGluZyB3cm9uZy5cbiAgICAgICAgICAgICAgICAgICAgbGV0IHNlbGYgPSBzZWxlY3RFbnRyeUF0KHRoaXMuc3RvcmVDb25maWcuYWxsKCksIHdyaXRlVGltZSwgcm91dGUpO1xuICAgICAgICAgICAgICAgICAgICBpZiAoc2VsZj8uaW1tdXRhYmxlICYmIGF3YWl0IHRoaXMuZ2V0SW5mbyh7IHBhdGg6IGtleSB9KSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgbGV0IGlkID0gYCR7RElTQ0FSREVEX1VQTE9BRF9QUkVGSVh9JHt0aGlzLm5leHREaXNjYXJkZWRVcGxvYWQrK31gO1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5kaXNjYXJkZWRVcGxvYWRzLmFkZChpZCk7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gaWQ7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLmFzc2VydE11dGFibGUoa2V5LCB3cml0ZVRpbWUpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChjb25maWc/LmludGVybmFsKSB7XG4gICAgICAgICAgICAgICAgaWYgKCFjb25maWcubGFzdE1vZGlmaWVkKSB7XG4gICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgSW50ZXJuYWwgd3JpdGVzIG11c3QgY2FycnkgbGFzdE1vZGlmaWVkICh0aGV5IGFyZSBzeW5jaHJvbml6YXRpb24gcHVzaGVzLCBvcmRlcmVkIGJ5IHRoZWlyIHdyaXRlIHRpbWUpLCB1cGxvYWRpbmcgJHtKU09OLnN0cmluZ2lmeShrZXkpfSAoc3RvcmUgJHt0aGlzLmZvbGRlcn0pYCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHRoaXMuYXNzZXJ0SW50ZXJuYWxXcml0ZUFjY2VwdGVkKGtleSwgY29uZmlnLmxhc3RNb2RpZmllZCwgcm91dGUpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBhd2FpdCB0aGlzLmdldERpc2tTb3VyY2UoKS5kaXNrLnN0YXJ0TGFyZ2VVcGxvYWQoKTtcbiAgICB9XG4gICAgcHVibGljIGFzeW5jIGFwcGVuZExhcmdlVXBsb2FkKGNvbmZpZzogeyBpZDogc3RyaW5nOyBkYXRhOiBCdWZmZXIgfSk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBpZiAodGhpcy5kaXNjYXJkZWRVcGxvYWRzLmhhcyhjb25maWcuaWQpKSByZXR1cm47XG4gICAgICAgIGF3YWl0IHRoaXMuZ2V0RGlza1NvdXJjZSgpLmRpc2suYXBwZW5kTGFyZ2VVcGxvYWQoY29uZmlnLmlkLCBjb25maWcuZGF0YSk7XG4gICAgfVxuICAgIHB1YmxpYyBhc3luYyBmaW5pc2hMYXJnZVVwbG9hZChjb25maWc6IHsgaWQ6IHN0cmluZzsgcGF0aDogc3RyaW5nOyBsYXN0TW9kaWZpZWQ/OiBudW1iZXI7IGZvcmNlU2V0SW1tdXRhYmxlPzogYm9vbGVhbjsgbm9DaGVja3M/OiBib29sZWFuOyBpbnRlcm5hbD86IGJvb2xlYW4gfSk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBpZiAodGhpcy5kaXNjYXJkZWRVcGxvYWRzLmRlbGV0ZShjb25maWcuaWQpKSByZXR1cm47XG4gICAgICAgIGxldCB7IGRpc2ssIHNvdXJjZUluZGV4IH0gPSB0aGlzLmdldERpc2tTb3VyY2UoKTtcbiAgICAgICAgaWYgKGNvbmZpZy5sYXN0TW9kaWZpZWQpIHtcbiAgICAgICAgICAgIGFzc2VydFZhbGlkTGFzdE1vZGlmaWVkKGNvbmZpZy5sYXN0TW9kaWZpZWQpO1xuICAgICAgICAgICAgLy8gQW4gb2xkZXIgd3JpdGUgbmV2ZXIgb3ZlcndyaXRlcyBhIG5ld2VyIG9uZSAoc2VlIElBcmNoaXZlcy5zZXQpIC0gYSBuZXdlciB2YWx1ZSBjYW4gbGFuZCB3aGlsZSBhIGxvbmcgdXBsb2FkIGlzIHN0aWxsIHN0cmVhbWluZywgc28gdGhpcyBpcyByZS1jaGVja2VkIGhlcmUgcmF0aGVyIHRoYW4gb25seSBhdCB0aGUgc3RhcnRcbiAgICAgICAgICAgIGlmIChjb25maWcubGFzdE1vZGlmaWVkIDwgYXdhaXQgdGhpcy5jdXJyZW50V3JpdGVUaW1lKGNvbmZpZy5wYXRoKSkge1xuICAgICAgICAgICAgICAgIGF3YWl0IGRpc2suY2FuY2VsTGFyZ2VVcGxvYWQoY29uZmlnLmlkKTtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgYXdhaXQgZGlzay5maW5pc2hMYXJnZVVwbG9hZChjb25maWcuaWQsIGNvbmZpZy5wYXRoLCBjb25maWcubGFzdE1vZGlmaWVkKTtcbiAgICAgICAgbGV0IGluZm8gPSBhd2FpdCBkaXNrLmdldEluZm8oY29uZmlnLnBhdGgpO1xuICAgICAgICBpZiAoaW5mbykge1xuICAgICAgICAgICAgdGhpcy5zZXRJbmRleEVudHJ5KGNvbmZpZy5wYXRoLCB7IHdyaXRlVGltZTogaW5mby53cml0ZVRpbWUsIHNpemU6IGluZm8uc2l6ZSwgc291cmNlc0xpc3RJbmRleDogdGhpcy5zb3VyY2VzTGlzdEluZGV4T2ZTbG90KHNvdXJjZUluZGV4KSB9KTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBwdWJsaWMgYXN5bmMgY2FuY2VsTGFyZ2VVcGxvYWQoY29uZmlnOiB7IGlkOiBzdHJpbmcgfSk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBpZiAodGhpcy5kaXNjYXJkZWRVcGxvYWRzLmRlbGV0ZShjb25maWcuaWQpKSByZXR1cm47XG4gICAgICAgIGF3YWl0IHRoaXMuZ2V0RGlza1NvdXJjZSgpLmRpc2suY2FuY2VsTGFyZ2VVcGxvYWQoY29uZmlnLmlkKTtcbiAgICB9XG5cbiAgICAvLyAjZW5kcmVnaW9uXG5cbiAgICAvLyAjcmVnaW9uIEludGVybmFsc1xuXG4gICAgLyoqIEJ5dGVzIG9mIHJlYWQgY2FjaGUgdGhlIGRpc2sgbWF5IGhvbGQ7IHNlZSBDb21tb25Db25maWcucmVhZGVyRGlza0xpbWl0IChTdG9yZVN5bmMgZW5mb3JjZXMgaXQpLiBSZWFkIGZyb20gdGhlIGNvbmZpZyBpbiBlZmZlY3QsIHNvIHJhaXNpbmcgb3IgcmVtb3ZpbmcgdGhlIGxpbWl0IHRha2VzIGVmZmVjdCBvbiB0aGUgbmV4dCBldmljdGlvbiBwYXNzLiAqL1xuICAgIHB1YmxpYyBnZXQgcmVhZGVyRGlza0xpbWl0KCk6IG51bWJlciB8IHVuZGVmaW5lZCB7XG4gICAgICAgIHJldHVybiB0aGlzLnN0b3JlQ29uZmlnLmN1cnJlbnQoKS5yZWFkZXJEaXNrTGltaXQ7XG4gICAgfVxuXG4gICAgLyoqIFRoZSB3cml0ZSB0aW1lIGEgbmV3IHdyaXRlIGhhcyB0byBiZWF0LCBvciAwIHdoZW4gd2UgaGF2ZSBuZXZlciBoZWFyZCBvZiB0aGUga2V5LiBDb3VudHMgREVMRVRJT05TIHRvbzogYSB3cml0ZSBvbGRlciB0aGFuIHRoZSBkZWxldGlvbiB0aGF0IHJlbW92ZWQgaXQgbXVzdCBub3QgYnJpbmcgaXQgYmFjay4gVGhlIGluZGV4IGlzIGF1dGhvcml0YXRpdmUgZXZlbiBmb3IgYSB3cml0ZSBzdGlsbCBidWZmZXJlZCBpbiBhIGRlbGF5ZWQgc291cmNlLCBzaW5jZSB0aGUgZW50cnkgaXMgcmVjb3JkZWQgd2hlbiB0aGUgd3JpdGUgaXMgYWNjZXB0ZWQgcmF0aGVyIHRoYW4gd2hlbiBpdCByZWFjaGVzIHN0b3JhZ2UuICovXG4gICAgcHVibGljIGN1cnJlbnRXcml0ZVRpbWUoa2V5OiBzdHJpbmcpOiBudW1iZXIge1xuICAgICAgICByZXR1cm4gdGhpcy5pbmRleC50aW1lT2Yoa2V5KTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGlzTGl2ZShzb3VyY2VJbmRleDogbnVtYmVyKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiB0aGlzLnN5bmMuaXNMaXZlKHNvdXJjZUluZGV4KTtcbiAgICB9XG5cbiAgICBwdWJsaWMgcmVnaXN0ZXJTbG90KHNsb3Q6IG51bWJlcik6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBsZXQgZXhpc3RpbmcgPSB0aGlzLnNsb3RSZWdpc3RyYXRpb25zW3Nsb3RdO1xuICAgICAgICBpZiAoZXhpc3RpbmcpIHJldHVybiBleGlzdGluZztcbiAgICAgICAgbGV0IHJlZ2lzdHJhdGlvbiA9IHRoaXMuc291cmNlc0xpc3QuZW5zdXJlKHRoaXMuc291cmNlc1tzbG90XS51cmwpLnRoZW4oaW5kZXggPT4ge1xuICAgICAgICAgICAgdGhpcy5zbG90U291cmNlc0xpc3RJbmRleGVzW3Nsb3RdID0gaW5kZXg7XG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLnNsb3RSZWdpc3RyYXRpb25zW3Nsb3RdID0gcmVnaXN0cmF0aW9uO1xuICAgICAgICByZXR1cm4gcmVnaXN0cmF0aW9uO1xuICAgIH1cblxuICAgIC8qKiBUaGUgcGVyc2lzdGVudCBzb3VyY2VzTGlzdEluZGV4IG9mIGEgc2xvdCwgb3IgdW5kZWZpbmVkIHdoZW4gdGhlIHNsb3QgbmV2ZXIgZ290IHRoYXQgZmFyIChhIHNvdXJjZSByZW1vdmVkIGJlZm9yZSBpdHMgcmVnaXN0cmF0aW9uIHJlc29sdmVkKS4gKi9cbiAgICBwdWJsaWMgc2xvdFNvdXJjZXNMaXN0SW5kZXgoc2xvdDogbnVtYmVyKTogbnVtYmVyIHwgdW5kZWZpbmVkIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuc2xvdFNvdXJjZXNMaXN0SW5kZXhlc1tzbG90XTtcbiAgICB9XG5cbiAgICAvLyBUaGUgcGVyc2lzdGVudCBzb3VyY2VzTGlzdEluZGV4IG9mIGEgc2xvdCAtIG9ubHkgdmFsaWQgb25jZSB0aGUgc2xvdCdzIHJlZ2lzdHJhdGlvbiByZXNvbHZlZCAoaW5pdCBhbmQgdGhlIHNvdXJjZSdzIHN5bmMgbG9vcCBndWFyYW50ZWUgdGhhdCBiZWZvcmUgYW55IGluZGV4aW5nIGhhcHBlbnMpXG4gICAgcHVibGljIHNvdXJjZXNMaXN0SW5kZXhPZlNsb3Qoc2xvdDogbnVtYmVyKTogbnVtYmVyIHtcbiAgICAgICAgbGV0IGluZGV4ID0gdGhpcy5zbG90U291cmNlc0xpc3RJbmRleGVzW3Nsb3RdO1xuICAgICAgICBpZiAoaW5kZXggPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBTb3VyY2Ugc2xvdCAke3Nsb3R9ICgke3RoaXMuc291cmNlc1tzbG90XT8udXJsfSkgaGFzIG5vIHJlZ2lzdGVyZWQgc291cmNlc0xpc3RJbmRleCB5ZXQgKHN0b3JlICR7dGhpcy5mb2xkZXJ9KWApO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBpbmRleDtcbiAgICB9XG5cbiAgICAvLyBUaGUgbGl2ZSBzbG90IGN1cnJlbnRseSBzZXJ2aW5nIGEgcGVyc2lzdGVudCBzb3VyY2VzTGlzdEluZGV4LCBvciB1bmRlZmluZWQgd2hlbiBubyBjb25maWd1cmVkIHNvdXJjZSBoYXMgdGhhdCBVUkwgYW55bW9yZS4gTGluZWFyLCBidXQgdGhlIHNvdXJjZXMgbGlzdCBpcyB0aW55IGFuZCB0aGlzIGlzIGFsd2F5cyBjdXJyZW50IChzbG90cyBkeWluZywgb3Igc2V2ZXJhbCBzbG90cyBzaGFyaW5nIG9uZSBVUkwgYWNyb3NzIHZhbGlkIHdpbmRvd3MsIG5lZWQgbm8gYm9va2tlZXBpbmcpLlxuICAgIHB1YmxpYyBzbG90Rm9yU291cmNlc0xpc3RJbmRleChzb3VyY2VzTGlzdEluZGV4OiBudW1iZXIpOiBudW1iZXIgfCB1bmRlZmluZWQge1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMuc2xvdFNvdXJjZXNMaXN0SW5kZXhlcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgaWYgKHRoaXMuc2xvdFNvdXJjZXNMaXN0SW5kZXhlc1tpXSA9PT0gc291cmNlc0xpc3RJbmRleCAmJiB0aGlzLmlzTGl2ZShpKSkgcmV0dXJuIGk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG5cbiAgICAvLyBUaGUgSUFyY2hpdmVzIGN1cnJlbnRseSBob2xkaW5nIGFuIGVudHJ5J3MgYnl0ZXM6IHRoZSBsaXZlIHNsb3Qgd2hlbiB0aGUgaG9sZGVyIGlzIHN0aWxsIGNvbmZpZ3VyZWQsIG90aGVyd2lzZSByZXNvbHZlZCAoY2FjaGVkKSBzdHJhaWdodCBmcm9tIGl0cyBwZXJzaXN0ZWQgVVJMIC0gd2luZG93cy9yb3V0ZXMgZGVjaWRlIHdoZW4gYSBzb3VyY2UgaXMgc2Nhbm5lZCBvciB3cml0dGVuLCBidXQgZm9yIHJlYWRpbmcgYnl0ZXMgd2Uga25vdyBpdCBob2xkcywgdGhlIFVSTCBhbG9uZSBpcyBlbm91Z2hcbiAgICBwdWJsaWMgYXN5bmMgZ2V0RW50cnlIb2xkZXIoZW50cnk6IEluZGV4RW50cnkpOiBQcm9taXNlPElBcmNoaXZlcyB8IHVuZGVmaW5lZD4ge1xuICAgICAgICBsZXQgc2xvdCA9IHRoaXMuc2xvdEZvclNvdXJjZXNMaXN0SW5kZXgoZW50cnkuc291cmNlc0xpc3RJbmRleCk7XG4gICAgICAgIGlmIChzbG90ICE9PSB1bmRlZmluZWQpIHJldHVybiB0aGlzLnNvdXJjZXNbc2xvdF0uc291cmNlO1xuICAgICAgICBsZXQgdXJsID0gdGhpcy5zb3VyY2VzTGlzdC5nZXRVcmwoZW50cnkuc291cmNlc0xpc3RJbmRleCkgfHwgYXdhaXQgdGhpcy5zb3VyY2VzTGlzdC5nZXRVcmxSZWxvYWRpbmcoZW50cnkuc291cmNlc0xpc3RJbmRleCk7XG4gICAgICAgIGlmICghdXJsKSByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICByZXR1cm4gdGhpcy5jb25maWc/LnJlc29sdmVTb3VyY2VVcmw/Lih1cmwpO1xuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgbG9hZEluZGV4KCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBhd2FpdCB0aGlzLmluZGV4LmxvYWQoKTtcbiAgICAgICAgLy8gVGhlIHJvdXRpbmcgY29uZmlnIGlzIG9ubHkgZXZlciByZWFkIG9mZiBvdXIgb3duIGRpc2sgKHNlZSBTdG9yZVN5bmMncyBzY2FuIGhhbmRsaW5nKSwgYW5kIGEgbG9hZGVkIGJ1Y2tldCBhbHdheXMgaGFzIGl0IHRoZXJlIC0gYSBwZXJzaXN0ZWQgZW50cnkgcG9pbnRpbmcgZWxzZXdoZXJlIGlzIHN0YWxlLCBzbyBpdCBpcyBjb3JyZWN0ZWQgb25jZSwgaGVyZVxuICAgICAgICBsZXQgcm91dGluZyA9IHRoaXMuZ2V0SW5kZXhFbnRyeShST1VUSU5HX0ZJTEUpO1xuICAgICAgICBsZXQgYmFzZVNvdXJjZXNMaXN0SW5kZXggPSB0aGlzLnNvdXJjZXNMaXN0SW5kZXhPZlNsb3QoMCk7XG4gICAgICAgIGlmIChyb3V0aW5nICYmIHJvdXRpbmcuc291cmNlc0xpc3RJbmRleCAhPT0gYmFzZVNvdXJjZXNMaXN0SW5kZXgpIHtcbiAgICAgICAgICAgIHRoaXMuc2V0SW5kZXhFbnRyeShST1VUSU5HX0ZJTEUsIHsgd3JpdGVUaW1lOiByb3V0aW5nLndyaXRlVGltZSwgc2l6ZTogcm91dGluZy5zaXplLCBzb3VyY2VzTGlzdEluZGV4OiBiYXNlU291cmNlc0xpc3RJbmRleCB9KTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKiBBIGZpbGUgd2UgaG9sZC4gQSBkZWxldGVkIG9uZSBpcyBub3Qgb25lOiBpdCBpcyBhIHRvbWJzdG9uZSwgYW5kIG9ubHkgZ2V0RGVsZXRlZEVudHJ5IGtub3dzIGFib3V0IGl0LiAqL1xuICAgIHB1YmxpYyBnZXRJbmRleEVudHJ5KGtleTogc3RyaW5nKTogSW5kZXhFbnRyeSB8IHVuZGVmaW5lZCB7XG4gICAgICAgIGxldCBlbnRyeSA9IHRoaXMuaW5kZXguZ2V0KGtleSk7XG4gICAgICAgIGlmICghZW50cnkpIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgIHJldHVybiB7IC4uLmVudHJ5LnZhbHVlLCB3cml0ZVRpbWU6IGVudHJ5LnRpbWUsIGNoYW5nZWRBdDogZW50cnkuY2hhbmdlZEF0IH07XG4gICAgfVxuXG4gICAgLyoqIFdoZW4gYSBrZXkgd2FzIGRlbGV0ZWQsIGlmIGl0IHdhcy4gQSBkZWxldGlvbiBpcyBhbiBhYnNlbmNlIHdpdGggYSB0aW1lIGF0dGFjaGVkIC0gdGhhdCB0aW1lIGlzIHdoYXQgbWFrZXMgaXQgcHJvcGFnYXRlIGFuZCB3aGF0IGV4cGlyZXMgaXQuICovXG4gICAgcHVibGljIGdldERlbGV0ZWRFbnRyeShrZXk6IHN0cmluZyk6IHsgd3JpdGVUaW1lOiBudW1iZXI7IGNoYW5nZWRBdDogbnVtYmVyIH0gfCB1bmRlZmluZWQge1xuICAgICAgICBsZXQgdG9tYnN0b25lID0gdGhpcy5pbmRleC5nZXREZWxldGVkKGtleSk7XG4gICAgICAgIGlmICghdG9tYnN0b25lKSByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICByZXR1cm4geyB3cml0ZVRpbWU6IHRvbWJzdG9uZS50aW1lLCBjaGFuZ2VkQXQ6IHRvbWJzdG9uZS5jaGFuZ2VkQXQgfTtcbiAgICB9XG5cbiAgICAvKiogRXZlcnkgZmlsZSB3ZSBob2xkLCBmb3IgdGhlIHBhc3NlcyB0aGF0IHdhbGsgdGhlbSBhbGwgKGxpc3RpbmdzLCBzY2FucywgcmVjb25jaWxpYXRpb24sIGV2aWN0aW9uKS4gRGVsZXRpb25zIGFyZSBub3QgaW4gaGVyZSAtIHNlZSBkZWxldGVkRW50cmllcy4gTGl2ZTogZGVsZXRpbmcgZW50cmllcyB3aGlsZSBpdGVyYXRpbmcgaXMgZXhwZWN0ZWQgaGVyZSwgYW5kIHNhZmUuICovXG4gICAgcHVibGljICppbmRleEVudHJpZXMoKTogSXRlcmFibGVJdGVyYXRvcjxbc3RyaW5nLCBJbmRleEVudHJ5XT4ge1xuICAgICAgICBmb3IgKGxldCBba2V5LCBlbnRyeV0gb2YgdGhpcy5pbmRleC5lbnRyaWVzKCkpIHtcbiAgICAgICAgICAgIHlpZWxkIFtrZXksIHsgLi4uZW50cnkudmFsdWUsIHdyaXRlVGltZTogZW50cnkudGltZSwgY2hhbmdlZEF0OiBlbnRyeS5jaGFuZ2VkQXQgfV07XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKiogRXZlcnkgZGVsZXRpb24gd2Uga25vdyBvZi4gQSBtdWNoIHNtYWxsZXIgd2FsayB0aGFuIHRoZSBmaWxlcywgd2hpY2ggaXMgd2hhdCBtYWtlcyBleHBpcmluZyB0aGVtIGNoZWFwLiAqL1xuICAgIHB1YmxpYyAqZGVsZXRlZEVudHJpZXMoKTogSXRlcmFibGVJdGVyYXRvcjxbc3RyaW5nLCB7IHdyaXRlVGltZTogbnVtYmVyOyBjaGFuZ2VkQXQ6IG51bWJlciB9XT4ge1xuICAgICAgICBmb3IgKGxldCBba2V5LCB0b21ic3RvbmVdIG9mIHRoaXMuaW5kZXguZGVsZXRlZEVudHJpZXMoKSkge1xuICAgICAgICAgICAgeWllbGQgW2tleSwgeyB3cml0ZVRpbWU6IHRvbWJzdG9uZS50aW1lLCBjaGFuZ2VkQXQ6IHRvbWJzdG9uZS5jaGFuZ2VkQXQgfV07XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKiogSG93IG1hbnkgZmlsZXMgd2UgaG9sZCwgZGVsZXRpb25zIGV4Y2x1ZGVkLiAqL1xuICAgIHB1YmxpYyBpbmRleFNpemUoKTogbnVtYmVyIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuaW5kZXguc2l6ZTtcbiAgICB9XG5cbiAgICAvKiogVG90YWxzIG92ZXIgdGhlIGZpbGVzIHdlIGhvbGQsIGJyb2tlbiBkb3duIGJ5IHRoZSBzbG90IGhvbGRpbmcgZWFjaCAoZW50cmllcyBjYW4gbmFtZSBhIHNvdXJjZSB0aGF0IGlzIG5vIGxvbmdlciBjb25maWd1cmVkLCB3aGljaCBjb3VudHMgdG93YXJkcyB0aGUgdG90YWwgYnV0IG5vIHNsb3QpLiAqL1xuICAgIHB1YmxpYyBpbmRleFRvdGFscygpOiB7IGZpbGVDb3VudDogbnVtYmVyOyBieXRlQ291bnQ6IG51bWJlcjsgc2xvdHM6IHsgZmlsZUNvdW50OiBudW1iZXI7IGJ5dGVDb3VudDogbnVtYmVyIH1bXSB9IHtcbiAgICAgICAgbGV0IGZpbGVDb3VudCA9IDA7XG4gICAgICAgIGxldCBieXRlQ291bnQgPSAwO1xuICAgICAgICBsZXQgc2xvdHMgPSB0aGlzLnNvdXJjZXMubWFwKCgpID0+ICh7IGZpbGVDb3VudDogMCwgYnl0ZUNvdW50OiAwIH0pKTtcbiAgICAgICAgZm9yIChsZXQgWywgZW50cnldIG9mIHRoaXMuaW5kZXhFbnRyaWVzKCkpIHtcbiAgICAgICAgICAgIGZpbGVDb3VudCsrO1xuICAgICAgICAgICAgYnl0ZUNvdW50ICs9IGVudHJ5LnNpemU7XG4gICAgICAgICAgICBsZXQgc2xvdCA9IHRoaXMuc2xvdEZvclNvdXJjZXNMaXN0SW5kZXgoZW50cnkuc291cmNlc0xpc3RJbmRleCk7XG4gICAgICAgICAgICBpZiAoc2xvdCA9PT0gdW5kZWZpbmVkKSBjb250aW51ZTtcbiAgICAgICAgICAgIHNsb3RzW3Nsb3RdLmZpbGVDb3VudCsrO1xuICAgICAgICAgICAgc2xvdHNbc2xvdF0uYnl0ZUNvdW50ICs9IGVudHJ5LnNpemU7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHsgZmlsZUNvdW50LCBieXRlQ291bnQsIHNsb3RzIH07XG4gICAgfVxuXG4gICAgLyoqIFJlY29yZHMgYSBmaWxlLCBhcyBvZiBpdHMgd3JpdGUgdGltZS4gUmV0dXJucyBmYWxzZSwgaGF2aW5nIGNoYW5nZWQgbm90aGluZywgd2hlbiB3ZSBhbHJlYWR5IGtub3cgc29tZXRoaW5nIGF0IGxlYXN0IGFzIG5ldyAtIHRoZSBpbmRleCBjYW5ub3QgYmUgbWFkZSB0byBnbyBiYWNrd2FyZHMsIHdoaWNoZXZlciBwYXRoIHRoZSB3cml0ZSBjYW1lIGluIGJ5LiAqL1xuICAgIHB1YmxpYyBzZXRJbmRleEVudHJ5KGtleTogc3RyaW5nLCBlbnRyeTogeyB3cml0ZVRpbWU6IG51bWJlcjsgc2l6ZTogbnVtYmVyOyBzb3VyY2VzTGlzdEluZGV4OiBudW1iZXIgfSk6IGJvb2xlYW4ge1xuICAgICAgICBpZiAoIXRoaXMuaW5kZXguc2V0KGtleSwgeyBzaXplOiBlbnRyeS5zaXplLCBzb3VyY2VzTGlzdEluZGV4OiBlbnRyeS5zb3VyY2VzTGlzdEluZGV4IH0sIGVudHJ5LndyaXRlVGltZSkpIHJldHVybiBmYWxzZTtcbiAgICAgICAgLy8gVGhlIHJvdXRpbmcgY29uZmlnIGxhbmRpbmcgaGVyZSAtIHdyaXR0ZW4gYnkgYW4gb3BlcmF0b3IsIG9yIHB1bGxlZCBvZmYgYSBwZWVyIGJ5IHN5bmNocm9uaXphdGlvbiAtIGlzIGhvdyB0aGlzIHN0b3JlIGxlYXJucyB3aGF0IGl0IGlzIG1lYW50IHRvIGJlXG4gICAgICAgIGlmIChrZXkgPT09IFJPVVRJTkdfRklMRSAmJiB0aGlzLnN5bmNTdGFydGVkKSB7XG4gICAgICAgICAgICB0aGlzLnJlYXBwbHlSb3V0aW5nQ29uZmlnKCk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5jb25maWc/Lm9uSW5kZXhDaGFuZ2VkPy4oa2V5KTtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuXG4gICAgLyoqIFJlY29yZHMgYSBERUxFVElPTiwgYXMgb2YgaXRzIHRpbWU6IHRoZSBrZXkgc3RvcHMgZXhpc3RpbmcgaGVyZSwgYW5kIHRoZSB0b21ic3RvbmUgaXMgd2hhdCBtYWtlcyB0aGF0IGZhY3QgcHJvcGFnYXRlIGFuZCByZWNvbmNpbGUgbGlrZSBhbnkgb3RoZXIgd3JpdGUuIFNhbWUgb3JkZXJpbmcgcnVsZSBhcyBzZXRJbmRleEVudHJ5LiAqL1xuICAgIHB1YmxpYyBzZXRJbmRleERlbGV0ZWQoa2V5OiBzdHJpbmcsIHdyaXRlVGltZTogbnVtYmVyKTogYm9vbGVhbiB7XG4gICAgICAgIGlmICghdGhpcy5pbmRleC5kZWxldGUoa2V5LCB3cml0ZVRpbWUpKSByZXR1cm4gZmFsc2U7XG4gICAgICAgIHRoaXMuY29uZmlnPy5vbkluZGV4Q2hhbmdlZD8uKGtleSk7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cblxuICAgIC8qKiBGb3JnZXRzIGEga2V5IGVudGlyZWx5LCB0b21ic3RvbmUgaW5jbHVkZWQuIE5PVCBhIGRlbGV0aW9uOiBpdCBzYXlzIG5vdGhpbmcgaGFwcGVuZWQgdG8gdGhlIGZpbGUsIG9ubHkgdGhhdCB3ZSBubyBsb25nZXIga25vdyBhbnl0aGluZyBhYm91dCBpdCAtIGZvciBhbiBlbnRyeSB3aG9zZSBob2xkZXIgdHVybmVkIG91dCBub3QgdG8gaGF2ZSBpdCwgYW5kIGZvciBhIHRvbWJzdG9uZSBvbGQgZW5vdWdoIHRoYXQgZXZlcnlvbmUgaGFzIGhlYXJkLiAqL1xuICAgIHB1YmxpYyBwdXJnZUluZGV4RW50cnkoa2V5OiBzdHJpbmcpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5pbmRleC5wdXJnZShrZXkpO1xuICAgIH1cblxuICAgIC8vIOKUgOKUgCB2YWxpZGF0aW9uIChmcm9tIHRoaXMgc3RvcmUncyBvd24gcm91dGluZyBlbnRyaWVzKSDilIDilIBcblxuICAgIC8qKlxuICAgICAqIEV2ZXJ5IHdyaXRlLCBob3dldmVyIGl0IGlzIHN0YW1wZWQsIGhhcyB0byBiZSBvbmUgd2UgYXJlIGFjdHVhbGx5IG1lYW50IHRvIGhvbGQgLSBiZWNhdXNlIHRoZVxuICAgICAqIGFsdGVybmF0aXZlIGlzIG5vdCBhIHNtYWxsZXIgcHJvYmxlbSwgaXQgaXMgYSBzaWxlbnQgb25lLiBBIHdyaXRlIHRoYXQgbGFuZHMgb24gYSBzdG9yZSB0aGF0XG4gICAgICogZG9lcyBub3Qgc2VydmUgaXRzIHJvdXRlIChvciBvbiBhIHNlcnZlciB0aGF0IGlzIG5vdCBpbiB0aGUgYnVja2V0J3MgY29uZmlnIGF0IGFsbCkgZ29lcyBpbnRvIGFcbiAgICAgKiBmb2xkZXIgbm90aGluZyBzY2FucyBhbmQgbm8gcGVlciByZWNvbmNpbGVzOiBpdCBzdWNjZWVkcywgYW5kIHRoZW4gaXQgaXMgZ29uZS4gVGhlIG1hcmtlcnMgbWFrZVxuICAgICAqIHRoZSBjbGllbnQgcmUtcmVhZCB0aGUgcm91dGluZyBjb25maWcgYW5kIHJldHJ5LCB3aGljaCBpcyBleGFjdGx5IHRoZSByaWdodCBvdXRjb21lIHdoZW4gdGhlXG4gICAgICogcmVhc29uIGl0IGFpbWVkIGhlcmUgaXMgdGhhdCBpdHMgY29uZmlnIHdhcyBzdGFsZS5cbiAgICAgKi9cbiAgICBwcml2YXRlIGFzc2VydFdyaXRlVGFyZ2V0KGtleTogc3RyaW5nLCByb3V0ZTogbnVtYmVyLCBsYXN0TW9kaWZpZWQ6IG51bWJlciB8IHVuZGVmaW5lZCk6IHZvaWQge1xuICAgICAgICBpZiAoIXRoaXMuc3RvcmVDb25maWcuYWxsKCkubGVuZ3RoKSB7XG4gICAgICAgICAgICBsb2dXcm9uZ1RhcmdldFJlamVjdGlvbihgUmVqZWN0aW5nIHdyaXRlIG9mICR7SlNPTi5zdHJpbmdpZnkoa2V5KX0gKHN0b3JlICR7dGhpcy5mb2xkZXJ9KTogdGhpcyBzZXJ2ZXIgaGFzIG5vIGVudHJ5IGluIHRoZSBidWNrZXQncyByb3V0aW5nIGNvbmZpZywgc28gbm90aGluZyB3b3VsZCBldmVyIHNjYW4gb3IgcmVjb25jaWxlIHdoYXQgaXQgc3RvcmVkYCk7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYCR7U1RPUkFHRV9XUk9OR19WQUxJRF9XSU5ET1d9IFRoaXMgc2VydmVyIGlzIG5vdCBpbiB0aGUgcm91dGluZyBjb25maWcgZm9yIHRoaXMgYnVja2V0LCBzbyBpdCBjYW5ub3QgYWNjZXB0IHdyaXRlcyAoc3RvcmUgJHt0aGlzLmZvbGRlcn0pLiBSZS1yZXNvbHZlIHRoZSBjdXJyZW50bHkgdmFsaWQgc291cmNlIGFuZCByZXRyeS5gKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIWxhc3RNb2RpZmllZCkge1xuICAgICAgICAgICAgdGhpcy5hc3NlcnRGcmVzaFdyaXRlVGFyZ2V0KGtleSwgRGF0ZS5ub3coKSwgcm91dGUpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIC8vIEEgc3RhbXBlZCB3cml0ZSBwaWNrZWQgaXRzIG93biB0aW1lLCBzbyBubyB3aW5kb3cgY2FuIGp1ZGdlIGl0ICh0aGF0IGlzIHRoZSB3aG9sZSBwb2ludCBvZiBhIHN5bmNocm9uaXplZCB3cml0ZSkgLSBidXQgdGhlIFJPVVRFIGlzIG5vdCBhIG1hdHRlciBvZiB0aW1pbmcsIGFuZCBhIHN0YW1wZWQgd3JpdGUgdG8gdGhlIHdyb25nIHNoYXJkIGlzIGV4YWN0bHkgYXMgaW52aXNpYmxlIGFzIGEgZnJlc2ggb25lXG4gICAgICAgIGlmICh0aGlzLnN0b3JlQ29uZmlnLmFsbCgpLnNvbWUoeCA9PiByb3V0ZUNvbnRhaW5zKHgucm91dGUsIHJvdXRlKSkpIHJldHVybjtcbiAgICAgICAgbG9nV3JvbmdUYXJnZXRSZWplY3Rpb24oYFJlamVjdGluZyBzdGFtcGVkIHdyaXRlIG9mICR7SlNPTi5zdHJpbmdpZnkoa2V5KX0gKHN0b3JlICR7dGhpcy5mb2xkZXJ9KTogcm91dGUgJHtyb3V0ZX0gaXMgb3V0c2lkZSBldmVyeSByb3V0ZSB3ZSBzZXJ2ZSAke0pTT04uc3RyaW5naWZ5KHRoaXMuc3RvcmVDb25maWcuYWxsKCkubWFwKHggPT4geC5yb3V0ZSB8fCBGVUxMX1JPVVRFKSl9YCk7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgJHtTVE9SQUdFX1dST05HX1JPVVRFfSBUaGlzIHN0b3JlIGRvZXMgbm90IGhhbmRsZSByb3V0ZSAke3JvdXRlfSAoa2V5ICR7SlNPTi5zdHJpbmdpZnkoa2V5KX0sIG91ciByb3V0ZXM6ICR7SlNPTi5zdHJpbmdpZnkodGhpcy5zdG9yZUNvbmZpZy5hbGwoKS5tYXAoeCA9PiB4LnJvdXRlIHx8IEZVTExfUk9VVEUpKX0sIHN0b3JlICR7dGhpcy5mb2xkZXJ9KS4gUmUtcmVzb2x2ZSB0aGUgc291cmNlIGZvciB0aGlzIGtleSBhbmQgcmV0cnkuYCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogV2hldGhlciBhIHJvdXRpbmcgY29uZmlnIG1heSBiZSB3cml0dGVuIGhlcmUuIFR3byBydWxlcywgYW5kIHRoaXMgaXMgdGhlIG9uZSBwbGFjZSBlaXRoZXIgaXNcbiAgICAgKiBhcHBsaWVkIC0gYSBjb25maWcgb25seSBldmVyIGVudGVycyB0aGUgc3lzdGVtIHRocm91Z2ggYSB3cml0ZSwgc28gYSBjb25maWcgdGhhdCBnb3QgaW4gaXMgYVxuICAgICAqIGNvbmZpZyB0aGF0IHBhc3NlZCwgYW5kIHJlYWRpbmcgb25lIGJhY2sgbmV2ZXIganVkZ2VzIGl0IGFnYWluLlxuICAgICAqXG4gICAgICogVGhlIGNvbmZpZyBoYXMgdG8gYmUgdmFsaWQgYXMgYSB3aG9sZSAoc2VlIGFzc2VydFZhbGlkUmVtb3RlQ29uZmlnKSwgYW5kIGl0IGhhcyB0byBvdXRyYW5rIHdoYXRcbiAgICAgKiB3ZSBhcmUgcnVubmluZzogdGhlIHNhbWUgdmVyc2lvbiBtZWFucyB0aGUgc2FtZSBjb25maWcsIHNvIHJlLXdyaXRpbmcgaXQgaXMgaGFybWxlc3MsIGJ1dCBhXG4gICAgICogbG93ZXIgb25lIGlzIGFuIG9sZGVyIGNvbmZpZyBhcnJpdmluZyBsYXRlIGFuZCBtdXN0IG5ldmVyIHVuZG8gYSBuZXdlciBvbmUuXG4gICAgICovXG4gICAgcHJpdmF0ZSBhc3NlcnRSb3V0aW5nQ29uZmlnV3JpdGFibGUoZGF0YTogQnVmZmVyKTogdm9pZCB7XG4gICAgICAgIGxldCByb3V0aW5nID0gcGFyc2VSb3V0aW5nRGF0YShkYXRhKTtcbiAgICAgICAgYXNzZXJ0VmFsaWRSZW1vdGVDb25maWcocm91dGluZyk7XG4gICAgICAgIGxldCBpbmNvbWluZyA9IGdldENvbmZpZ1ZlcnNpb24ocm91dGluZyk7XG4gICAgICAgIGxldCBjdXJyZW50ID0gdGhpcy5yb3V0aW5nVmVyc2lvbigpO1xuICAgICAgICBpZiAoaW5jb21pbmcgPj0gY3VycmVudCkgcmV0dXJuO1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFJlZnVzaW5nIHRvIHdyaXRlICR7Uk9VVElOR19GSUxFfSB0byBzdG9yZSAke3RoaXMuZm9sZGVyfTogaXRzIHZlcnNpb24gKCR7aW5jb21pbmd9KSBpcyBvbGRlciB0aGFuIHRoZSBvbmUgdGhpcyBzdG9yZSBpcyBydW5uaW5nICgke2N1cnJlbnR9KS4gSW5jcmVtZW50IHRoZSB2ZXJzaW9uIHRvIHVwZGF0ZSBpdC5gKTtcbiAgICB9XG5cbiAgICAvLyBBIGZyZXNoICh1bnN0YW1wZWQpIHdyaXRlIG11c3QgbGFuZCBvbiB0aGUgbm9kZSB0aGUgY29uZmlnIGN1cnJlbnRseSBwb2ludHMgYXQ6IHRoZSBtYXJrZXJzIHRlbGwgdGhlIGNsaWVudCBpdHMgY29uZmlnIGlzIHN0YWxlLCBzbyBpdCByZS1yZXNvbHZlcyBhbmQgcmV0cmllcyBhZ2FpbnN0IHRoZSByaWdodCBub2RlIGluc3RlYWQgb2YgdXMgc2lsZW50bHkgYWNjZXB0aW5nIGRhdGEgd2Ugd2VyZSBuZXZlciBtZWFudCB0byBob2xkLlxuICAgIHByaXZhdGUgYXNzZXJ0RnJlc2hXcml0ZVRhcmdldChrZXk6IHN0cmluZywgd3JpdGVUaW1lOiBudW1iZXIsIHJvdXRlOiBudW1iZXIpOiB2b2lkIHtcbiAgICAgICAgbGV0IHRpbWVWYWxpZCA9IHRoaXMuc3RvcmVDb25maWcuYWxsKCkuZmlsdGVyKHggPT4gd3JpdGVUaW1lID49IHgudmFsaWRXaW5kb3dbMF0gJiYgd3JpdGVUaW1lIDwgeC52YWxpZFdpbmRvd1sxXSk7XG4gICAgICAgIGlmICghdGltZVZhbGlkLmxlbmd0aCkge1xuICAgICAgICAgICAgbG9nV3JvbmdUYXJnZXRSZWplY3Rpb24oYFJlamVjdGluZyBmcmVzaCB3cml0ZSBvZiAke0pTT04uc3RyaW5naWZ5KGtleSl9IChzdG9yZSAke3RoaXMuZm9sZGVyfSk6IHdyaXRlVGltZSAke3dyaXRlVGltZX0gKCR7bmV3IERhdGUod3JpdGVUaW1lKS50b0lTT1N0cmluZygpfSkgaXMgb3V0c2lkZSBhbGwgb3VyIHZhbGlkIHdpbmRvd3MgJHtKU09OLnN0cmluZ2lmeSh0aGlzLnN0b3JlQ29uZmlnLmFsbCgpLm1hcCh4ID0+IHgudmFsaWRXaW5kb3cpKX0gKGEgc3dpdGNob3ZlciBtb3ZlZCB0aGUgd3JpdGUgdGFyZ2V0KWApO1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGAke1NUT1JBR0VfV1JPTkdfVkFMSURfV0lORE9XfSBUaGlzIHN0b3JlIGlzIG5vdCBhIHZhbGlkIHdyaXRlIHRhcmdldCBhdCAke3dyaXRlVGltZX0gKG91ciB2YWxpZCB3aW5kb3dzOiAke0pTT04uc3RyaW5naWZ5KHRoaXMuc3RvcmVDb25maWcuYWxsKCkubWFwKHggPT4geC52YWxpZFdpbmRvdykpfSwgc3RvcmUgJHt0aGlzLmZvbGRlcn0pLiBSZS1yZXNvbHZlIHRoZSBjdXJyZW50bHkgdmFsaWQgc291cmNlIGFuZCByZXRyeS5gKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIXRpbWVWYWxpZC5zb21lKHggPT4gcm91dGVDb250YWlucyh4LnJvdXRlLCByb3V0ZSkpKSB7XG4gICAgICAgICAgICBsb2dXcm9uZ1RhcmdldFJlamVjdGlvbihgUmVqZWN0aW5nIGZyZXNoIHdyaXRlIG9mICR7SlNPTi5zdHJpbmdpZnkoa2V5KX0gKHN0b3JlICR7dGhpcy5mb2xkZXJ9KTogcm91dGUgJHtyb3V0ZX0gaXMgb3V0c2lkZSBvdXIgcm91dGVzICR7SlNPTi5zdHJpbmdpZnkodGltZVZhbGlkLm1hcCh4ID0+IHgucm91dGUgfHwgRlVMTF9ST1VURSkpfSBhdCB3cml0ZVRpbWUgJHt3cml0ZVRpbWV9ICh0aGUgY2xpZW50J3Mgc2hhcmQgY29uZmlnIGlzIHN0YWxlKWApO1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGAke1NUT1JBR0VfV1JPTkdfUk9VVEV9IFRoaXMgc3RvcmUgZG9lcyBub3QgaGFuZGxlIHJvdXRlICR7cm91dGV9IChrZXkgJHtKU09OLnN0cmluZ2lmeShrZXkpfSwgb3VyIHJvdXRlcyBhdCB0aGlzIHRpbWU6ICR7SlNPTi5zdHJpbmdpZnkodGltZVZhbGlkLm1hcCh4ID0+IHgucm91dGUgfHwgRlVMTF9ST1VURSkpfSwgc3RvcmUgJHt0aGlzLmZvbGRlcn0pLiBSZS1yZXNvbHZlIHRoZSBzb3VyY2UgZm9yIHRoaXMga2V5IGFuZCByZXRyeS5gKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgYXNzZXJ0TXV0YWJsZShrZXk6IHN0cmluZywgd3JpdGVUaW1lOiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgaWYgKCF0aGlzLnN0b3JlQ29uZmlnLmFsbCgpLmxlbmd0aCkgcmV0dXJuO1xuICAgICAgICBsZXQgc2VsZiA9IHNlbGVjdEVudHJ5QXQodGhpcy5zdG9yZUNvbmZpZy5hbGwoKSwgd3JpdGVUaW1lLCBnZXRSb3V0ZShrZXkpKTtcbiAgICAgICAgaWYgKCFzZWxmPy5pbW11dGFibGUpIHJldHVybjtcbiAgICAgICAgaWYgKGF3YWl0IHRoaXMuZ2V0SW5mbyh7IHBhdGg6IGtleSB9KSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBUaGlzIHN0b3JlIGlzIGltbXV0YWJsZSAoYXQgd3JpdGUgdGltZSAke3dyaXRlVGltZX0pIGFuZCAke0pTT04uc3RyaW5naWZ5KGtleSl9IGFscmVhZHkgZXhpc3RzLCBzbyBpdCBjYW5ub3QgYmUgd3JpdHRlbiB0byAoc3RvcmUgJHt0aGlzLmZvbGRlcn0pYCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBTZWUgU2V0Q29uZmlnLmludGVybmFsOiB0aGUgc3RhbXAgbXVzdCBsYW5kIGluc2lkZSBTT01FIHdpbmRvdytyb3V0ZSB0aGlzIHN0b3JlIGlzIGNvbmZpZ3VyZWQgZm9yIChhbnkgd2luZG93LCBpbmNsdWRpbmcgcGFzdCBvbmVzIC0gc3luY2hyb25pemF0aW9uIG1vdmVzIG9sZCBkYXRhKSwgc28gYSBjb25mdXNlZCBwZWVyIGNhbid0IHN0dWZmIGRhdGEgb250byBhIHN0b3JlIHRoYXQgd2FzIG5ldmVyIG1lYW50IHRvIGhvbGQgaXRcbiAgICBwcml2YXRlIGFzc2VydEludGVybmFsV3JpdGVBY2NlcHRlZChrZXk6IHN0cmluZywgd3JpdGVUaW1lOiBudW1iZXIsIHJvdXRlOiBudW1iZXIpOiB2b2lkIHtcbiAgICAgICAgaWYgKCF0aGlzLnN0b3JlQ29uZmlnLmFsbCgpLmxlbmd0aCkgcmV0dXJuO1xuICAgICAgICBsZXQgY292ZXJlZCA9IHRoaXMuc3RvcmVDb25maWcuYWxsKCkuc29tZSh4ID0+IHdyaXRlVGltZSA+PSB4LnZhbGlkV2luZG93WzBdICYmIHdyaXRlVGltZSA8IHgudmFsaWRXaW5kb3dbMV0gJiYgcm91dGVDb250YWlucyh4LnJvdXRlLCByb3V0ZSkpO1xuICAgICAgICBpZiAoIWNvdmVyZWQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgSW50ZXJuYWwgd3JpdGUgb2YgJHtKU09OLnN0cmluZ2lmeShrZXkpfSByZWplY3RlZDogd3JpdGVUaW1lICR7d3JpdGVUaW1lfSAoJHtuZXcgRGF0ZSh3cml0ZVRpbWUpLnRvSVNPU3RyaW5nKCl9KSBhdCByb3V0ZSAke3JvdXRlfSBpcyBvdXRzaWRlIGV2ZXJ5IHdpbmRvdy9yb3V0ZSB0aGlzIHN0b3JlIGlzIGNvbmZpZ3VyZWQgZm9yOiAke0pTT04uc3RyaW5naWZ5KHRoaXMuc3RvcmVDb25maWcuYWxsKCkubWFwKHggPT4gKHsgdmFsaWRXaW5kb3c6IHgudmFsaWRXaW5kb3csIHJvdXRlOiB4LnJvdXRlIHx8IEZVTExfUk9VVEUgfSkpKX0gKHN0b3JlICR7dGhpcy5mb2xkZXJ9KWApO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqIEludGVybmFsIChzdG9yZS10by1zdG9yZSkgcmVhZDogcHVyZWx5IHRoZSBsb2NhbCBkaXNrLCBjb21wbGV0ZWx5IHNob3J0LWNpcmN1aXRpbmcgdGhlIGluZGV4IGFuZCBob2xkZXIgcmVzb2x1dGlvbiAtIHRoZSBjYWxsZXIgaXMgYW5vdGhlciBzdG9yZSwgYW5kIGNoYXNpbmcgT1VSIHJlbW90ZSBob2xkZXJzIHdoaWxlIGFuc3dlcmluZyBpdCBpcyBob3cgaW5maW5pdGUgZ2V0IGxvb3BzIGJldHdlZW4gc3RvcmVzIGZvcm0uIE5vIHdpbmRvdyBvciByb3V0ZSBjaGVja3M6IGlmIHRoZSBieXRlcyBhcmUgb24gb3VyIGRpc2ssIHRoZSBjYWxsZXIgbWF5IGhhdmUgdGhlbS4gTm90ZSB0aGlzIHJlYWRzIHRoZSBkaXNrIHBhc3QgYW55IHdyaXRlIGRlbGF5LCBzbyBhIGZhc3Qgd3JpdGUgc3RpbGwgYnVmZmVyZWQgaW4gbWVtb3J5IGlzIGludmlzaWJsZSBoZXJlOyB0aGUgY2FsbGVyIHJlLWZpbmRzIGl0IG9uY2UgaXQgZmx1c2hlcy4gKi9cbiAgICBwcml2YXRlIGFzeW5jIGdldEludGVybmFsMihjb25maWc6IHsgcGF0aDogc3RyaW5nOyByYW5nZT86IHsgc3RhcnQ6IG51bWJlcjsgZW5kOiBudW1iZXIgfTsgaW5jbHVkZVRvbWJzdG9uZXM/OiBib29sZWFuIH0pOiBQcm9taXNlPHsgZGF0YTogQnVmZmVyOyB3cml0ZVRpbWU6IG51bWJlcjsgc2l6ZTogbnVtYmVyIH0gfCB1bmRlZmluZWQ+IHtcbiAgICAgICAgYXdhaXQgdGhpcy5pbml0KCk7XG4gICAgICAgIC8vIGluY2x1ZGVUb21ic3RvbmVzIGZvcndhcmRzIHRvIHRoZSBkaXNrOiBhIGZsYWctY2FsbGVyIChhIHBlZXIgc3RvcmUncyBzeW5jaHJvbml6YXRpb24pIG5lZWRzIHRvIHNlZSBvdXIgZGVsZXRpb25zLCBub3QganVzdCBvdXIgY29udGVudC4gQSB0b21ic3RvbmUgZGVsZXRlZCBmcm9tIGRpc2sgZW50aXJlbHkgb25seSBsaXZlcyBpbiBvdXIgaW5kZXgsIHNvIGZhbGwgYmFjayB0byB0aGF0LlxuICAgICAgICBsZXQgcmVzdWx0ID0gYXdhaXQgdGhpcy5nZXREaXNrU291cmNlKCkuZGlzay5nZXQyKGNvbmZpZy5wYXRoLCB7IHJhbmdlOiBjb25maWcucmFuZ2UsIGluY2x1ZGVUb21ic3RvbmVzOiBjb25maWcuaW5jbHVkZVRvbWJzdG9uZXMgfSk7XG4gICAgICAgIGlmICghcmVzdWx0IHx8ICFyZXN1bHQuZGF0YSkge1xuICAgICAgICAgICAgaWYgKGNvbmZpZy5pbmNsdWRlVG9tYnN0b25lcykge1xuICAgICAgICAgICAgICAgIGxldCBkZWxldGVkID0gdGhpcy5nZXREZWxldGVkRW50cnkoY29uZmlnLnBhdGgpO1xuICAgICAgICAgICAgICAgIGlmIChkZWxldGVkKSByZXR1cm4geyBkYXRhOiBCdWZmZXIuYWxsb2MoMCksIHdyaXRlVGltZTogZGVsZXRlZC53cml0ZVRpbWUsIHNpemU6IDAgfTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHsgZGF0YTogcmVzdWx0LmRhdGEsIHdyaXRlVGltZTogcmVzdWx0LndyaXRlVGltZSwgc2l6ZTogcmVzdWx0LnNpemUgfTtcbiAgICB9XG5cbiAgICAvKiogSW50ZXJuYWwgKHN0b3JlLXRvLXN0b3JlKSB3cml0ZTogdGhlIGxvY2FsIGRpc2sgcGx1cyBvdXIgaW5kZXgsIHdpdGggTk8gZG93bnN0cmVhbSBmYW4tb3V0IC0gdGhlIHB1c2hpbmcgc3RvcmUgb3ducyBwcm9wYWdhdGlvbiwgYW5kIGZhbm5pbmcgaXRzIHB1c2hlcyBiYWNrIG91dCBpcyBob3cgd3JpdGUgbG9vcHMgYmV0d2VlbiBzdG9yZXMgZm9ybS4gT25seS10YWtlLWxhdGVzdCBzdGlsbCBhcHBsaWVzIGhlcmUuICovXG4gICAgcHJpdmF0ZSBhc3luYyBzZXRJbnRlcm5hbChrZXk6IHN0cmluZywgZGF0YTogQnVmZmVyLCBjb25maWc6IHsgbGFzdE1vZGlmaWVkOiBudW1iZXIgfSk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBhd2FpdCB0aGlzLmluaXQoKTtcbiAgICAgICAgYXNzZXJ0VmFsaWRMYXN0TW9kaWZpZWQoY29uZmlnLmxhc3RNb2RpZmllZCk7XG4gICAgICAgIGlmIChjb25maWcubGFzdE1vZGlmaWVkIDwgYXdhaXQgdGhpcy5jdXJyZW50V3JpdGVUaW1lKGtleSkpIHJldHVybjtcbiAgICAgICAgaWYgKGRhdGEubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICAvLyBBIGRlbGV0aW9uIHN0b3JlcyBub3RoaW5nIG9uIG91ciBvd24gc291cmNlIC0gdGhlIHRvbWJzdG9uZSBpcyB0aGUgd2hvbGUgb2YgaXRcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuc291cmNlc1swXS5zb3VyY2UuZGVsKGtleSk7XG4gICAgICAgICAgICB0aGlzLnNldEluZGV4RGVsZXRlZChrZXksIGNvbmZpZy5sYXN0TW9kaWZpZWQpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGF3YWl0IHRoaXMuc291cmNlc1swXS5zb3VyY2Uuc2V0KGtleSwgZGF0YSwgeyBsYXN0TW9kaWZpZWQ6IGNvbmZpZy5sYXN0TW9kaWZpZWQsIGZvcmNlU2V0SW1tdXRhYmxlOiB0cnVlLCBub0NoZWNrczogdHJ1ZSB9KTtcbiAgICAgICAgdGhpcy5zZXRJbmRleEVudHJ5KGtleSwgeyB3cml0ZVRpbWU6IGNvbmZpZy5sYXN0TW9kaWZpZWQsIHNpemU6IGRhdGEubGVuZ3RoLCBzb3VyY2VzTGlzdEluZGV4OiB0aGlzLnNvdXJjZXNMaXN0SW5kZXhPZlNsb3QoMCkgfSk7XG4gICAgfVxuXG4gICAgLy8gVGhlIHJlYWQncyBieXRlcyBjYW1lIGZyb20gYSByZW1vdGUgc291cmNlLCBzbyB3cml0ZSB0aGVtIG9udG8gb3VyIG93biBiYXNlIHNvdXJjZSAodGhlIGxvY2FsIGRpc2spLCB3aGljaCBiZWNvbWVzIHRoZSBlbnRyeSdzIG5ldyBob2xkZXIgLSByZWFkcyBvbmx5IHBheSB0aGUgcmVtb3RlIGZldGNoIG9uY2VcbiAgICBwcml2YXRlIGFzeW5jIGNhY2hlUmVhZChrZXk6IHN0cmluZywgcmVzdWx0OiB7IGRhdGE6IEJ1ZmZlcjsgd3JpdGVUaW1lOiBudW1iZXIgfSk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBhd2FpdCB0aGlzLnNvdXJjZXNbMF0uc291cmNlLnNldChrZXksIHJlc3VsdC5kYXRhLCB7IGxhc3RNb2RpZmllZDogcmVzdWx0LndyaXRlVGltZSwgZm9yY2VTZXRJbW11dGFibGU6IHRydWUsIG5vQ2hlY2tzOiB0cnVlIH0pO1xuICAgICAgICB0aGlzLnNldEluZGV4RW50cnkoa2V5LCB7IHdyaXRlVGltZTogcmVzdWx0LndyaXRlVGltZSwgc2l6ZTogcmVzdWx0LmRhdGEubGVuZ3RoLCBzb3VyY2VzTGlzdEluZGV4OiB0aGlzLnNvdXJjZXNMaXN0SW5kZXhPZlNsb3QoMCkgfSk7XG4gICAgfVxuXG4gICAgLy8gVGhlIHNoYXJlZCBlbmdpbmUgb2Ygc2V0IGFuZCBkZWw6IGFuIGVtcHR5IGJ1ZmZlciBpcyBleGFjdGx5IGEgZGVsZXRpb24gaGVyZSwgd2hpY2ggaXMgd2h5IHRoZSBlbXB0eS1idWZmZXIgcmVqZWN0aW9uIGxpdmVzIGluIHNldCAodGhlIHB1YmxpYyBBUEkpLCBub3QgaW4gdGhpcyBtYWNoaW5lcnlcbiAgICBwcml2YXRlIGFzeW5jIHNldE9yRGVsZXRlKGtleTogc3RyaW5nLCBkYXRhOiBCdWZmZXIsIGNvbmZpZzogeyBsYXN0TW9kaWZpZWQ/OiBudW1iZXIgfSk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICB0aGlzLmNvbmZpZz8ub25Xcml0ZUNvdW50ZWQ/LihcIm9yaWdpbmFsXCIsIGRhdGEubGVuZ3RoKTtcbiAgICAgICAgbGV0IGxhc3RNb2RpZmllZCA9IGNvbmZpZy5sYXN0TW9kaWZpZWQ7XG4gICAgICAgIGlmIChsYXN0TW9kaWZpZWQpIHtcbiAgICAgICAgICAgIGFzc2VydFZhbGlkTGFzdE1vZGlmaWVkKGxhc3RNb2RpZmllZCk7XG4gICAgICAgICAgICAvLyBBbiBvbGRlciB3cml0ZSBuZXZlciBvdmVyd3JpdGVzIGEgbmV3ZXIgb25lIChzZWUgSUFyY2hpdmVzLnNldClcbiAgICAgICAgICAgIGlmIChsYXN0TW9kaWZpZWQgPCBhd2FpdCB0aGlzLmN1cnJlbnRXcml0ZVRpbWUoa2V5KSkgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIC8vIEZhc3Qgd3JpdGVzIGFyZSBub3QgaGFuZGxlZCBoZXJlOiBhIHNvdXJjZSB0aGF0IHdhcyBjb25maWd1cmVkIHdpdGggYSB3cml0ZSBkZWxheSBidWZmZXJzIHRoZW0gaXRzZWxmIChzZWUgQXJjaGl2ZXNEZWxheWVkKSwgc28gdGhpcyB3cml0ZSBsYW5kcyBpbiBtZW1vcnkgYW5kIHJldHVybnMsIGV4YWN0bHkgYXMgaXQgd291bGQgaGF2ZS4gVGhlIGluZGV4IGlzIHVwZGF0ZWQgZWl0aGVyIHdheSwgc28gdGhlIHdyaXRlIGlzIGltbWVkaWF0ZWx5IHZpc2libGUgdG8gcmVhZGVycyBvZiB0aGlzIHN0b3JlLlxuICAgICAgICBhd2FpdCB0aGlzLndyaXRlVG9Tb3VyY2VzKGtleSwgZGF0YSwgbGFzdE1vZGlmaWVkIHx8IERhdGUubm93KCkpO1xuICAgIH1cblxuICAgIC8qKiBUaGUgaW5zdGFudCBldmVyeSBkZWxheWVkIHdyaXRlIG11c3QgYmUgb24gaXRzIHNvdXJjZTogdGhlIGVuZCBvZiBvdXIgb3duIHdyaXRlIHdpbmRvdyB0aGF0IGNvbnRhaW5zIG5vdywgbWludXMgdGhlIGZsdXNoIG1hcmdpbiAoc28gdGhlIG5leHQgd2luZG93J3Mgc291cmNlIGZpbmRzIHRoZSBkYXRhIG9uIGhhbmRvZmYpLiBUaGUgTEFURVNUIGVuZCBhbW9uZyBjb3ZlcmluZyB3aW5kb3dzIC0gb3ZlcmxhcHBpbmcgd2luZG93cyBoYW5kIG9mZiBhdCB0aGUgbGFzdCBvbmUuIE5vIHdpbmRvdyBjb250YWlucyBub3cgKGFuIGluZXJ0IHN0b3JlLCBvciBhIG1vbWVudCBiZXR3ZWVuIG91ciB3aW5kb3dzKSAtPiAwLCBpLmUuIG5vdGhpbmcgbWF5IGJlIGRlbGF5ZWQgYXQgYWxsLiAqL1xuICAgIHB1YmxpYyB3cml0ZUZsdXNoRGVhZGxpbmUoKTogbnVtYmVyIHtcbiAgICAgICAgLy8gQmVmb3JlIHVwZGF0ZVNvdXJjZXMgaGFzIHJ1biB0aGVyZSBpcyBub3RoaW5nIHRvIGhvbGQgYSB3cml0ZSBhbnl3YXksIGFuZCBub3RoaW5nIG1heSBiZSBkZWxheWVkXG4gICAgICAgIGlmICghdGhpcy5zb3VyY2VzLmxlbmd0aCkgcmV0dXJuIDA7XG4gICAgICAgIGxldCBub3cgPSBEYXRlLm5vdygpO1xuICAgICAgICBsZXQgZW5kID0gMDtcbiAgICAgICAgZm9yIChsZXQgdyBvZiB0aGlzLnNvdXJjZXNbMF0udmFsaWRXaW5kb3dzKSB7XG4gICAgICAgICAgICBpZiAod1swXSA8PSBub3cgJiYgbm93IDwgd1sxXSkgZW5kID0gTWF0aC5tYXgoZW5kLCB3WzFdKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIWVuZCkgcmV0dXJuIDA7XG4gICAgICAgIHJldHVybiBlbmQgLSBXSU5ET1dfRU5EX0ZMVVNIX01BUkdJTjtcbiAgICB9XG5cbiAgICBwcml2YXRlIGdldFdyaXRhYmxlU291cmNlcyhjb25maWc/OiB7IGlnbm9yZVdpbmRvdz86IGJvb2xlYW4gfSk6IG51bWJlcltdIHtcbiAgICAgICAgbGV0IHdyaXRhYmxlOiBudW1iZXJbXSA9IFtdO1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMuc291cmNlcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgaWYgKCF0aGlzLmlzTGl2ZShpKSkgY29udGludWU7XG4gICAgICAgICAgICBpZiAoIWNvbmZpZz8uaWdub3JlV2luZG93ICYmICF3aW5kb3dzQWNjZXB0V3JpdGVzKHRoaXMuc291cmNlc1tpXS52YWxpZFdpbmRvd3MpKSBjb250aW51ZTtcbiAgICAgICAgICAgIHdyaXRhYmxlLnB1c2goaSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHdyaXRhYmxlO1xuICAgIH1cblxuICAgIC8vIE91ciBvd24gc291cmNlICh0aGUgZmlyc3Qgd3JpdGFibGUgb25lKSBwbHVzIGV2ZXJ5IHJvdXRlLW1hdGNoaW5nIHBlZXIuIEVhY2ggc291cmNlIGRlY2lkZXMgZm9yIGl0c2VsZiBob3cgbG9uZyBpdCBob2xkcyB0aGUgd3JpdGUgYmVmb3JlIGl0IGhpdHMgc3RvcmFnZSAoc2VlIEFyY2hpdmVzRGVsYXllZCkgLSBoZXJlIHRoZXkgYWxsIGp1c3QgZ2V0IHdyaXR0ZW4uXG4gICAgcHJpdmF0ZSBhc3luYyB3cml0ZVRvU291cmNlcyhrZXk6IHN0cmluZywgZGF0YTogQnVmZmVyLCB3cml0ZVRpbWU6IG51bWJlcik6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICAvLyBUaGUgcm91dGluZyBmaWxlIGlzIE5FVkVSIHN5bmNocm9uaXplZCBiZXR3ZWVuIHN0b3JhZ2Ugbm9kZXM6IHRoZSB3cml0ZXIgd3JpdGVzIGl0IGRpcmVjdGx5IHRvIGVhY2ggbm9kZSwgc28gd2Ugc3RvcmUgaXQgb24gb3VyIG93biBkaXNrIG9ubHkgKG5vIHZhbGlkLXdpbmRvdyBmaWx0ZXIgLSByb3V0aW5nL3ZhbGlkIHdpbmRvd3MgY2FuJ3QgcG9zc2libHkgYXBwbHkgdG8gdGhlIGZpbGUgZGVmaW5pbmcgdGhlbSkgYW5kIG5ldmVyIGZvcndhcmQgaXQgdG8gb3RoZXIgc291cmNlcy5cbiAgICAgICAgdGhpcy5jb25maWc/Lm9uV3JpdGVDb3VudGVkPy4oXCJmbHVzaGVkXCIsIGRhdGEubGVuZ3RoKTtcbiAgICAgICAgbGV0IGlzUm91dGluZyA9IGtleSA9PT0gUk9VVElOR19GSUxFO1xuICAgICAgICBsZXQgd3JpdGFibGUgPSB0aGlzLmdldFdyaXRhYmxlU291cmNlcyh7IGlnbm9yZVdpbmRvdzogaXNSb3V0aW5nIH0pO1xuICAgICAgICBsZXQgZmlyc3QgPSB3cml0YWJsZS5zaGlmdCgpO1xuICAgICAgICBpZiAoZmlyc3QgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBObyBzb3VyY2UgYWNjZXB0cyB3cml0ZXMgKGV2ZXJ5IHNvdXJjZSdzIHZhbGlkIHdpbmRvdyBpcyBpbiB0aGUgcGFzdCksIHNvIHdyaXRlcyBjYW5ub3QgYmUgc3RvcmVkIChzdG9yZSAke3RoaXMuZm9sZGVyfSlgKTtcbiAgICAgICAgfVxuICAgICAgICAvLyBPbmx5IG91ciBvd24gKGZpcnN0KSBzb3VyY2UgYmxvY2tzIHRoZSB3cml0ZS4gRG93bnN0cmVhbSBzb3VyY2VzIGFyZSB3cml0dGVuIGluIHRoZSBiYWNrZ3JvdW5kOiBhIGRvd24gZG93bnN0cmVhbSBzb3VyY2UgbXVzdCBub3QgZmFpbCBvciBzdGFsbCB3cml0ZXMsIGFuZCByZWNvbmNpbGlhdGlvbiByZS1zZW5kcyBhbnl0aGluZyB0aGV5IG1pc3NlZCBvbmNlIHRoZXkgY29tZSBiYWNrLlxuICAgICAgICBpZiAoZGF0YS5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgIC8vIEEgZGVsZXRpb24gc3RvcmVzIG5vdGhpbmcgb24gb3VyIG93biBzb3VyY2UgLSB0aGUgdG9tYnN0b25lIGlzIHRoZSB3aG9sZSBvZiBpdFxuICAgICAgICAgICAgYXdhaXQgdGhpcy5zb3VyY2VzW2ZpcnN0XS5zb3VyY2UuZGVsKGtleSk7XG4gICAgICAgICAgICB0aGlzLnNldEluZGV4RGVsZXRlZChrZXksIHdyaXRlVGltZSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLnNvdXJjZXNbZmlyc3RdLnNvdXJjZS5zZXQoa2V5LCBkYXRhLCB7IGxhc3RNb2RpZmllZDogd3JpdGVUaW1lLCBub0NoZWNrczogdHJ1ZSB9KTtcbiAgICAgICAgICAgIHRoaXMuc2V0SW5kZXhFbnRyeShrZXksIHsgd3JpdGVUaW1lLCBzaXplOiBkYXRhLmxlbmd0aCwgc291cmNlc0xpc3RJbmRleDogdGhpcy5zb3VyY2VzTGlzdEluZGV4T2ZTbG90KGZpcnN0KSB9KTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoaXNSb3V0aW5nKSByZXR1cm47XG4gICAgICAgIGxldCByb3V0ZSA9IGdldFJvdXRlKGtleSk7XG4gICAgICAgIGZvciAobGV0IGkgb2Ygd3JpdGFibGUpIHtcbiAgICAgICAgICAgIGlmICghcm91dGVDb250YWlucyh0aGlzLnNvdXJjZXNbaV0ucm91dGUsIHJvdXRlKSkgY29udGludWU7XG4gICAgICAgICAgICAvLyBEZWxldGlvbnMgdHJhdmVsIGFzIGRlbCBjYXJyeWluZyB0aGUgb3JpZ2luYWwgd3JpdGUgdGltZSAobmV2ZXIgYXMgZW1wdHkgc2V0cyAtIHNldCByZWplY3RzIGVtcHR5IGJ1ZmZlcnMpLiBCYWNrYmxhemUgbWF0ZXJpYWxpemVzIHN1Y2ggZGVscyBhcyByZWFsIGVtcHR5IGZpbGVzLCBzbyBpdHMgbGlzdGluZ3Mgc3RpbGwgc2hvdyB0aGUgZGVsZXRpb24gZm9yIG90aGVyIHN0b3JlcyB0byBzY2FuIGluIGFzIGEgdG9tYnN0b25lLlxuICAgICAgICAgICAgbGV0IHB1c2g6IFByb21pc2U8dW5rbm93bj47XG4gICAgICAgICAgICBpZiAoZGF0YS5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgICAgICBwdXNoID0gdGhpcy5zb3VyY2VzW2ldLnNvdXJjZS5kZWwoa2V5LCB7IGxhc3RNb2RpZmllZDogd3JpdGVUaW1lLCBub0NoZWNrczogdHJ1ZSwgaW50ZXJuYWw6IHRydWUgfSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHB1c2ggPSB0aGlzLnNvdXJjZXNbaV0uc291cmNlLnNldChrZXksIGRhdGEsIHsgbGFzdE1vZGlmaWVkOiB3cml0ZVRpbWUsIGZvcmNlU2V0SW1tdXRhYmxlOiB0cnVlLCBub0NoZWNrczogdHJ1ZSwgaW50ZXJuYWw6IHRydWUgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2b2lkIHB1c2guY2F0Y2goKGU6IEVycm9yKSA9PiB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihgQmFja2dyb3VuZCB3cml0ZSBvZiAke2tleX0gdG8gc3luYyBzb3VyY2UgJHt0aGlzLnNvdXJjZXNbaV0uc291cmNlLmdldERlYnVnTmFtZSgpfSBmYWlsZWQ6ICR7ZS5zdGFjayA/PyBlfWApO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBTbG90IDAgaXMgYWx3YXlzIHRoaXMgc3RvcmUncyBvd24gZm9sZGVyIChzZWUgcGxhblNvdXJjZXMpLCBzbyB0aGUgZGlzayBpcyBrbm93biB3aXRob3V0IHNlYXJjaGluZyBmb3IgaXQgLSBhbmQgaXQgaXMgdGhlIHVud3JhcHBlZCBvbmUsIHBhc3QgYW55IHdyaXRlIGRlbGF5XG4gICAgcHJpdmF0ZSBnZXREaXNrU291cmNlKCk6IHsgZGlzazogQXJjaGl2ZXNEaXNrOyBzb3VyY2VJbmRleDogbnVtYmVyIH0ge1xuICAgICAgICByZXR1cm4geyBkaXNrOiB0aGlzLm93bkRpc2ssIHNvdXJjZUluZGV4OiAwIH07XG4gICAgfVxuXG4gICAgLyoqIFdyaXRlcyBldmVyeXRoaW5nIHN0aWxsIGhlbGQgYnkgYSBkZWxheWVkIHNvdXJjZSAoc2VlIEFyY2hpdmVzRGVsYXllZCkuIGZvcmNlIGFsc28gd3JpdGVzIHdoYXQgaXNuJ3QgZHVlIHlldCAtIHNodXRkb3duIGNhbm5vdCBsZWF2ZSB3cml0ZXMgaW4gbWVtb3J5LiAqL1xuICAgIHByaXZhdGUgYXN5bmMgZmx1c2hEZWxheWVkV3JpdGVzKGZvcmNlPzogYm9vbGVhbik6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBmb3IgKGxldCB7IHNvdXJjZSB9IG9mIHRoaXMuc291cmNlcykge1xuICAgICAgICAgICAgbGV0IGRlbGF5ZWQgPSBhc0RlbGF5ZWQoc291cmNlKTtcbiAgICAgICAgICAgIGlmICghZGVsYXllZCkgY29udGludWU7XG4gICAgICAgICAgICBhd2FpdCBkZWxheWVkLmZsdXNoKGZvcmNlKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8vICNlbmRyZWdpb25cbn1cbiJdfQ==
|
|
917
|
+
/* _JS_SOURCE_HASH = "211623a15b7da110aa39f742d99692ae6557381f8a55dbb64b2936e899670dd8"; */
|