sliftutils 1.7.95 → 1.7.97
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/index.d.ts +129 -27
- package/package.json +1 -1
- package/storage/remoteStorage/chainStartup.d.ts +123 -0
- package/storage/remoteStorage/chainStartup.ts +482 -0
- package/storage/remoteStorage/createArchives.d.ts +2 -27
- package/storage/remoteStorage/createArchives.ts +57 -358
- package/storage/remoteStorage/dist/chainStartup.ts.cache +466 -0
- package/storage/remoteStorage/dist/createArchives.ts.cache +52 -361
- package/storage/remoteStorage/dist/storageServerState.ts.cache +3 -3
- package/storage/remoteStorage/storageServerState.ts +1 -1
|
@@ -0,0 +1,466 @@
|
|
|
1
|
+
"use strict"; var console = (function shimConsole() { let baseConsole = globalThis.console; if (typeof window !== "undefined") return baseConsole; let name = __filename.replaceAll("\\", "/").split("/").pop(); let dirName = __dirname.replaceAll("\\", "/").split("/").pop(); let context = { __FILE__: __filename, __DIR__: __dirname, __NAME__: name, __DIRNAME__: dirName }; let newConsole = { ...baseConsole }; for (let shim of ["log", "info", "warn", "error"]) { newConsole[shim] = (...args) => { args.push(context); baseConsole[shim](...args); }; } newConsole.__context = context; return newConsole; })(); "use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true , configurable: true});
|
|
3
|
+
//exports.RoutingRewriteLoop = exports.writeRoutingToAllStores = exports.chooseStartupConfig = exports.disposeProbes = exports.probeSources = exports.ChainStateManager = exports.CONFIG_WRITE_REFRESH_INTERVAL = exports.CONFIG_WRITE_RETRY_INTERVAL = void 0;
|
|
4
|
+
const misc_1 = require("socket-function/src/misc");
|
|
5
|
+
const remoteConfig_1 = require("./remoteConfig");
|
|
6
|
+
const sourceWrapper_1 = require("./sourceWrapper");
|
|
7
|
+
const intermediateSources_1 = require("./intermediateSources");
|
|
8
|
+
const storageClientController_1 = require("./storageClientController");
|
|
9
|
+
// The LIFECYCLE of an ArchivesChain's state, and nothing else: initializing it (probing every configured source, deciding which routing config to run, writing ours out when it is the newest), the retry when initialization fails, the poll that adopts newer configs, the availability recheck, and the loop that keeps re-writing our config. None of this is request dispatch - the chain (createArchives.ts) asks the ChainStateManager for the current state and dispatches over it.
|
|
10
|
+
const CONFIG_POLL_INTERVAL = 5 * 60 * 1000;
|
|
11
|
+
const AVAILABILITY_RECHECK_THROTTLE = 5 * 1000;
|
|
12
|
+
// The routing config write is retried on this cadence while it is failing. A store that never received the config rejects every write aimed at it, so this not landing is a big deal - each failed attempt is logged.
|
|
13
|
+
exports.CONFIG_WRITE_RETRY_INTERVAL = 5 * 60 * 1000;
|
|
14
|
+
// ...and even after success it is re-written on this cadence, in case a store lost it or a server appeared late
|
|
15
|
+
exports.CONFIG_WRITE_REFRESH_INTERVAL = 60 * 60 * 1000;
|
|
16
|
+
/** The chain's state and everything about HAVING one: init (with its retry), the config poll, availability rechecks, and the routing rewrite loop. The chain constructs one, asks it getState() on every call, and disposes it. */
|
|
17
|
+
class ChainStateManager {
|
|
18
|
+
constructor(config) {
|
|
19
|
+
this.config = config;
|
|
20
|
+
this.initRetryDelay = sourceWrapper_1.RETRY_START_DELAY;
|
|
21
|
+
this.disposed = false;
|
|
22
|
+
this.lastAvailabilityRecheck = 0;
|
|
23
|
+
this.configured = config.configured;
|
|
24
|
+
this.activeConfig = config.configured;
|
|
25
|
+
this.routingRewriter = new RoutingRewriteLoop({
|
|
26
|
+
configured: config.configured,
|
|
27
|
+
debugName: config.debugName,
|
|
28
|
+
latest: () => this.latestState,
|
|
29
|
+
});
|
|
30
|
+
this.unsubscribeRoutingPush = (0, storageClientController_1.onServerRoutingChanged)(() => {
|
|
31
|
+
void this.refreshActiveConfig().catch((e) => { var _a; return console.error(`Config refresh failed for ${this.config.debugName()}: ${(_a = e.stack) !== null && _a !== void 0 ? _a : e}`); });
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
/** The newest adopted state, synchronously - undefined until the first init finishes. */
|
|
35
|
+
latest() {
|
|
36
|
+
return this.latestState;
|
|
37
|
+
}
|
|
38
|
+
getState() {
|
|
39
|
+
if (this.disposed) {
|
|
40
|
+
return Promise.reject(new Error(`ArchivesChain ${this.config.debugName()} has been disposed`));
|
|
41
|
+
}
|
|
42
|
+
if (!this.statePromise) {
|
|
43
|
+
let promise = this.init();
|
|
44
|
+
this.statePromise = promise;
|
|
45
|
+
promise.then(() => {
|
|
46
|
+
this.initRetryDelay = sourceWrapper_1.RETRY_START_DELAY;
|
|
47
|
+
}, (e) => {
|
|
48
|
+
var _a, _b, _c;
|
|
49
|
+
if (this.disposed || this.initRetryTimer)
|
|
50
|
+
return;
|
|
51
|
+
console.error(`Storage init failed for ${this.config.debugName()}, retrying in ${Math.round(this.initRetryDelay / 1000)}s. ${(_a = e.stack) !== null && _a !== void 0 ? _a : e}`);
|
|
52
|
+
this.initRetryTimer = setTimeout(() => {
|
|
53
|
+
this.initRetryTimer = undefined;
|
|
54
|
+
if (this.disposed)
|
|
55
|
+
return;
|
|
56
|
+
if (this.statePromise === promise) {
|
|
57
|
+
this.statePromise = undefined;
|
|
58
|
+
}
|
|
59
|
+
this.getState().catch(() => { });
|
|
60
|
+
}, this.initRetryDelay);
|
|
61
|
+
(_c = (_b = this.initRetryTimer).unref) === null || _c === void 0 ? void 0 : _c.call(_b);
|
|
62
|
+
this.initRetryDelay = Math.min(sourceWrapper_1.RETRY_MAX_DELAY, this.initRetryDelay * sourceWrapper_1.RETRY_GROWTH);
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
return this.statePromise;
|
|
66
|
+
}
|
|
67
|
+
async init() {
|
|
68
|
+
let configs = this.configured.sources.map(remoteConfig_1.normalizeSource);
|
|
69
|
+
let readOnly = this.isReadOnly(this.configured);
|
|
70
|
+
let probes = await probeSources(configs, readOnly);
|
|
71
|
+
try {
|
|
72
|
+
let { active, needsWrite, existing } = chooseStartupConfig({ configured: this.configured, probes, debugName: this.config.debugName() });
|
|
73
|
+
let sources = await this.buildSources(active);
|
|
74
|
+
let configWriteFailed = false;
|
|
75
|
+
if (needsWrite) {
|
|
76
|
+
console.log(`Storage routing config for ${this.config.debugName()} is out of date (stored version ${existing && (0, remoteConfig_1.getConfigVersion)(existing) || "none"}, ours ${(0, remoteConfig_1.getConfigVersion)(this.configured)})`);
|
|
77
|
+
let { failures, total } = await writeRoutingToAllStores({ configured: this.configured, sources, debugName: this.config.debugName() });
|
|
78
|
+
configWriteFailed = failures.length > 0;
|
|
79
|
+
if (failures.length && failures.length === total) {
|
|
80
|
+
// Nobody has our config, so running on it would just disagree with every server. The stored one (when there is one) is what the servers actually run.
|
|
81
|
+
console.error(`The storage routing config for ${this.config.debugName()} (version ${(0, remoteConfig_1.getConfigVersion)(this.configured)}) could not be written to ANY of the ${total} stores. ${existing && `Running on the stored config (version ${(0, remoteConfig_1.getConfigVersion)(existing)}) until a write succeeds.` || `No stored config exists either, so servers will reject writes until this succeeds.`} Retrying in ${exports.CONFIG_WRITE_RETRY_INTERVAL / 1000}s. Failures: ${failures.join(" | ")}`);
|
|
82
|
+
if (existing) {
|
|
83
|
+
active = existing;
|
|
84
|
+
for (let source of sources) {
|
|
85
|
+
source.dispose();
|
|
86
|
+
}
|
|
87
|
+
sources = await this.buildSources(active);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
else if (failures.length) {
|
|
91
|
+
console.error(`The storage routing config for ${this.config.debugName()} (version ${(0, remoteConfig_1.getConfigVersion)(this.configured)}) was written to ${total - failures.length} of ${total} stores. Retrying the rest in ${exports.CONFIG_WRITE_RETRY_INTERVAL / 1000}s (they also pull it from the stores that have it). Failures: ${failures.join(" | ")}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
for (let source of sources) {
|
|
95
|
+
let probe = probes.find(x => x.responded && x.sourceConfig.url === source.config.url);
|
|
96
|
+
if (probe) {
|
|
97
|
+
source.seedLatency(probe.latency);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
this.activeConfig = active;
|
|
101
|
+
this.startConfigPoll();
|
|
102
|
+
let state = { config: active, sources };
|
|
103
|
+
this.latestState = state;
|
|
104
|
+
this.routingRewriter.start(configWriteFailed);
|
|
105
|
+
return state;
|
|
106
|
+
}
|
|
107
|
+
finally {
|
|
108
|
+
disposeProbes(probes);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/** Clientside, a config with public sources is served entirely over plain URL downloads - no API connection, no access grant, and no writing. directConnect opts out of that. */
|
|
112
|
+
isReadOnly(config) {
|
|
113
|
+
if (this.config.directConnect || (0, misc_1.isNode)())
|
|
114
|
+
return false;
|
|
115
|
+
return config.sources.map(remoteConfig_1.normalizeSource).some(x => x.public);
|
|
116
|
+
}
|
|
117
|
+
async createChainSource(sourceConfig, readOnly) {
|
|
118
|
+
let source = await sourceWrapper_1.SourceWrapper.create(sourceConfig, { readOnly });
|
|
119
|
+
source.startPinging();
|
|
120
|
+
return source;
|
|
121
|
+
}
|
|
122
|
+
async buildSources(config) {
|
|
123
|
+
let readOnly = this.isReadOnly(config);
|
|
124
|
+
let sources = [];
|
|
125
|
+
for (let sourceConfig of config.sources.map(remoteConfig_1.normalizeSource)) {
|
|
126
|
+
sources.push(await this.createChainSource(sourceConfig, readOnly));
|
|
127
|
+
}
|
|
128
|
+
return sources;
|
|
129
|
+
}
|
|
130
|
+
startConfigPoll() {
|
|
131
|
+
var _a, _b;
|
|
132
|
+
if (this.pollTimer || this.disposed)
|
|
133
|
+
return;
|
|
134
|
+
this.pollTimer = setInterval(() => {
|
|
135
|
+
void this.refreshActiveConfig().catch((e) => {
|
|
136
|
+
var _a;
|
|
137
|
+
console.error(`Checking for a new storage routing config failed for ${this.config.debugName()}: ${(_a = e.stack) !== null && _a !== void 0 ? _a : e}`);
|
|
138
|
+
});
|
|
139
|
+
}, CONFIG_POLL_INTERVAL);
|
|
140
|
+
(_b = (_a = this.pollTimer).unref) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
141
|
+
}
|
|
142
|
+
refreshActiveConfig() {
|
|
143
|
+
if (!this.configRefreshInFlight) {
|
|
144
|
+
this.configRefreshInFlight = this.checkForNewConfig().finally(() => {
|
|
145
|
+
this.configRefreshInFlight = undefined;
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
return this.configRefreshInFlight;
|
|
149
|
+
}
|
|
150
|
+
async fetchLatestConfig(state) {
|
|
151
|
+
var _a;
|
|
152
|
+
let errors = [];
|
|
153
|
+
for (let source of state.sources) {
|
|
154
|
+
try {
|
|
155
|
+
let latest = await source.readRoutingConfig();
|
|
156
|
+
if (latest)
|
|
157
|
+
return (0, remoteConfig_1.normalizeRemoteConfig)(latest);
|
|
158
|
+
}
|
|
159
|
+
catch (e) {
|
|
160
|
+
errors.push(`${source.config.url}: ${(_a = e.stack) !== null && _a !== void 0 ? _a : e}`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
if (errors.length === state.sources.length) {
|
|
164
|
+
throw new Error(`No storage source could give us the routing config for ${this.config.debugName()}: ${errors.join(" | ")}`);
|
|
165
|
+
}
|
|
166
|
+
return undefined;
|
|
167
|
+
}
|
|
168
|
+
async checkForNewConfig() {
|
|
169
|
+
if (this.disposed || !this.statePromise)
|
|
170
|
+
return;
|
|
171
|
+
let state;
|
|
172
|
+
try {
|
|
173
|
+
state = await this.statePromise;
|
|
174
|
+
}
|
|
175
|
+
catch (_a) {
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
let latest = await this.fetchLatestConfig(state);
|
|
179
|
+
if (!latest)
|
|
180
|
+
return;
|
|
181
|
+
await this.adoptNewConfig(state, latest);
|
|
182
|
+
}
|
|
183
|
+
async adoptNewConfig(state, latest) {
|
|
184
|
+
var _a;
|
|
185
|
+
if (JSON.stringify(latest) === JSON.stringify(state.config))
|
|
186
|
+
return;
|
|
187
|
+
let received = new Date().toISOString();
|
|
188
|
+
let onlyIntermediatesChanged = JSON.stringify((0, intermediateSources_1.resolveIntermediateSources)(latest)) === JSON.stringify((0, intermediateSources_1.resolveIntermediateSources)(state.config));
|
|
189
|
+
if (onlyIntermediatesChanged) {
|
|
190
|
+
console.log(`Storage routing switchover windows changed (version ${(0, remoteConfig_1.getConfigVersion)(state.config)} -> ${(0, remoteConfig_1.getConfigVersion)(latest)}), received ${received}, rebuilding sources. New config: ${JSON.stringify(latest)}`);
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
console.log(`Storage routing config changed (version ${(0, remoteConfig_1.getConfigVersion)(state.config)} -> ${(0, remoteConfig_1.getConfigVersion)(latest)}), received ${received}, rebuilding sources. New config: ${JSON.stringify(latest)}`);
|
|
194
|
+
}
|
|
195
|
+
let strippedKey = (config) => JSON.stringify({ ...config, validWindow: undefined });
|
|
196
|
+
let oldByConfig = new Map();
|
|
197
|
+
for (let source of state.sources) {
|
|
198
|
+
let key = strippedKey(source.config);
|
|
199
|
+
let list = oldByConfig.get(key);
|
|
200
|
+
if (!list) {
|
|
201
|
+
list = [];
|
|
202
|
+
oldByConfig.set(key, list);
|
|
203
|
+
}
|
|
204
|
+
list.push(source);
|
|
205
|
+
}
|
|
206
|
+
let readOnly = this.isReadOnly(latest);
|
|
207
|
+
let sources = [];
|
|
208
|
+
for (let sourceConfig of latest.sources.map(remoteConfig_1.normalizeSource)) {
|
|
209
|
+
let old = (_a = oldByConfig.get(strippedKey(sourceConfig))) === null || _a === void 0 ? void 0 : _a.shift();
|
|
210
|
+
if (old) {
|
|
211
|
+
old.updateValidWindow(sourceConfig.validWindow);
|
|
212
|
+
sources.push(old);
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
sources.push(await this.createChainSource(sourceConfig, readOnly));
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
for (let leftovers of oldByConfig.values()) {
|
|
219
|
+
for (let leftover of leftovers) {
|
|
220
|
+
leftover.dispose();
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
this.activeConfig = latest;
|
|
224
|
+
let newState = { config: latest, sources };
|
|
225
|
+
this.latestState = newState;
|
|
226
|
+
this.statePromise = Promise.resolve(newState);
|
|
227
|
+
}
|
|
228
|
+
/** Every source failed: re-contact all of them (routing re-read + connection re-attempt) and adopt whatever config comes back. Throttled, and deduplicated across concurrent callers. */
|
|
229
|
+
recheckAvailability() {
|
|
230
|
+
if (this.availabilityRecheckInFlight)
|
|
231
|
+
return this.availabilityRecheckInFlight;
|
|
232
|
+
if (Date.now() - this.lastAvailabilityRecheck < AVAILABILITY_RECHECK_THROTTLE)
|
|
233
|
+
return Promise.resolve();
|
|
234
|
+
this.lastAvailabilityRecheck = Date.now();
|
|
235
|
+
this.availabilityRecheckInFlight = this.recheckAvailabilityNow().finally(() => {
|
|
236
|
+
this.availabilityRecheckInFlight = undefined;
|
|
237
|
+
});
|
|
238
|
+
return this.availabilityRecheckInFlight;
|
|
239
|
+
}
|
|
240
|
+
async recheckAvailabilityNow() {
|
|
241
|
+
if (this.disposed || !this.statePromise)
|
|
242
|
+
return;
|
|
243
|
+
let state;
|
|
244
|
+
try {
|
|
245
|
+
state = await this.statePromise;
|
|
246
|
+
}
|
|
247
|
+
catch (_a) {
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
console.log(`Every storage source failed for ${this.config.debugName()}; re-contacting all ${state.sources.length} sources (routing re-read + connection re-attempt)`);
|
|
251
|
+
let results = await Promise.all(state.sources.map(async (source) => {
|
|
252
|
+
try {
|
|
253
|
+
return await source.readRoutingConfig();
|
|
254
|
+
}
|
|
255
|
+
catch (_a) {
|
|
256
|
+
return undefined;
|
|
257
|
+
}
|
|
258
|
+
}));
|
|
259
|
+
let latest = results.find(x => x);
|
|
260
|
+
if (!latest)
|
|
261
|
+
return;
|
|
262
|
+
await this.adoptNewConfig(state, latest);
|
|
263
|
+
}
|
|
264
|
+
dispose() {
|
|
265
|
+
var _a;
|
|
266
|
+
this.disposed = true;
|
|
267
|
+
(_a = this.unsubscribeRoutingPush) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
268
|
+
if (this.pollTimer) {
|
|
269
|
+
clearInterval(this.pollTimer);
|
|
270
|
+
}
|
|
271
|
+
if (this.initRetryTimer) {
|
|
272
|
+
clearTimeout(this.initRetryTimer);
|
|
273
|
+
}
|
|
274
|
+
this.routingRewriter.dispose();
|
|
275
|
+
let statePromise = this.statePromise;
|
|
276
|
+
if (statePromise) {
|
|
277
|
+
void statePromise.then(state => {
|
|
278
|
+
for (let source of state.sources) {
|
|
279
|
+
source.dispose();
|
|
280
|
+
}
|
|
281
|
+
}, () => { });
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
exports.ChainStateManager = ChainStateManager;
|
|
286
|
+
/** One throwaway SourceWrapper per configured source, each asked for its stored routing config - which also measures first-contact latency, seeded into the real sources afterwards. The probes MUST be disposed (disposeProbes) once the caller is done with them. */
|
|
287
|
+
async function probeSources(configs, readOnly) {
|
|
288
|
+
return await Promise.all(configs.map(async (sourceConfig) => {
|
|
289
|
+
var _a;
|
|
290
|
+
let probe = await sourceWrapper_1.SourceWrapper.create(sourceConfig, { background: false, readOnly });
|
|
291
|
+
let start = Date.now();
|
|
292
|
+
try {
|
|
293
|
+
let existing = await probe.readRoutingConfig();
|
|
294
|
+
return { probe, sourceConfig, responded: true, latency: Date.now() - start, existing, error: "" };
|
|
295
|
+
}
|
|
296
|
+
catch (e) {
|
|
297
|
+
return { probe, sourceConfig, responded: false, latency: 0, existing: undefined, error: `${sourceConfig.url}: ${(_a = e.stack) !== null && _a !== void 0 ? _a : e}` };
|
|
298
|
+
}
|
|
299
|
+
}));
|
|
300
|
+
}
|
|
301
|
+
exports.probeSources = probeSources;
|
|
302
|
+
function disposeProbes(probes) {
|
|
303
|
+
for (let probe of probes) {
|
|
304
|
+
probe.probe.dispose();
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
exports.disposeProbes = disposeProbes;
|
|
308
|
+
/**
|
|
309
|
+
* Which routing config the chain should RUN: the newest of ours and every stored one. needsWrite
|
|
310
|
+
* when ours is strictly the newest, meaning the stores have to be told about it. A stored config
|
|
311
|
+
* with our exact version but DIFFERENT content wins without a write, loudly: config updates must
|
|
312
|
+
* bump the version, or they are ignored - silently taking the changed one would make "what is the
|
|
313
|
+
* bucket running" depend on which process started last.
|
|
314
|
+
*
|
|
315
|
+
* Throws when no source answered at all: with nothing stored and nobody to write to, there is no
|
|
316
|
+
* config to run.
|
|
317
|
+
*/
|
|
318
|
+
function chooseStartupConfig(config) {
|
|
319
|
+
let { configured, probes, debugName } = config;
|
|
320
|
+
let found = probes.find(x => x.responded);
|
|
321
|
+
if (!found) {
|
|
322
|
+
throw new Error(`Cannot initialize storage for ${debugName}: no source answered. ${probes.map(x => x.error).join(" | ")}`);
|
|
323
|
+
}
|
|
324
|
+
let existing = found.existing;
|
|
325
|
+
let active = configured;
|
|
326
|
+
let needsWrite = true;
|
|
327
|
+
if (existing && (0, remoteConfig_1.getConfigVersion)(existing) >= (0, remoteConfig_1.getConfigVersion)(configured)) {
|
|
328
|
+
if ((0, remoteConfig_1.getConfigVersion)(existing) === (0, remoteConfig_1.getConfigVersion)(configured) && JSON.stringify(existing) !== JSON.stringify(configured)) {
|
|
329
|
+
console.error(`Archives configuration updated without updating the version, for ${found.sourceConfig.url}. Updates will be ignored until you increase the version. Using: ${JSON.stringify(existing)}, ignoring: ${JSON.stringify(configured)}`);
|
|
330
|
+
}
|
|
331
|
+
active = existing;
|
|
332
|
+
needsWrite = false;
|
|
333
|
+
}
|
|
334
|
+
if (needsWrite) {
|
|
335
|
+
let best;
|
|
336
|
+
let conflictUrl;
|
|
337
|
+
for (let probe of probes) {
|
|
338
|
+
let stored = probe.existing;
|
|
339
|
+
if (!stored)
|
|
340
|
+
continue;
|
|
341
|
+
if (!best || (0, remoteConfig_1.getConfigVersion)(stored) > (0, remoteConfig_1.getConfigVersion)(best)) {
|
|
342
|
+
best = stored;
|
|
343
|
+
}
|
|
344
|
+
if ((0, remoteConfig_1.getConfigVersion)(stored) === (0, remoteConfig_1.getConfigVersion)(configured) && JSON.stringify(stored) !== JSON.stringify(configured)) {
|
|
345
|
+
conflictUrl = probe.sourceConfig.url;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
if (best && (0, remoteConfig_1.getConfigVersion)(best) >= (0, remoteConfig_1.getConfigVersion)(configured)) {
|
|
349
|
+
if (conflictUrl && (0, remoteConfig_1.getConfigVersion)(best) === (0, remoteConfig_1.getConfigVersion)(configured)) {
|
|
350
|
+
console.error(`Archives configuration updated without updating the version, for ${conflictUrl}. Updates will be ignored until you increase the version. Using: ${JSON.stringify(best)}, ignoring: ${JSON.stringify(configured)}`);
|
|
351
|
+
}
|
|
352
|
+
active = best;
|
|
353
|
+
needsWrite = false;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
return { active, needsWrite, existing };
|
|
357
|
+
}
|
|
358
|
+
exports.chooseStartupConfig = chooseStartupConfig;
|
|
359
|
+
/**
|
|
360
|
+
* Writes the given routing config to every configured store, one write per url+name: the write
|
|
361
|
+
* lands in the store the entry NAMES, so two entries sharing a URL but naming different stores are
|
|
362
|
+
* two separate deliveries - deduping by URL alone leaves the second store unconfigured forever. All
|
|
363
|
+
* in parallel, every failure tolerated (no-write-access included - the attempt classifies it,
|
|
364
|
+
* nothing pre-checks it): a down node must not stop the others from getting the config - they would
|
|
365
|
+
* then reject writes as unconfigured precisely BECAUSE it never arrived - and it must never stop
|
|
366
|
+
* the chain from starting. A store that missed it pulls it off its peers, and the rewrite loop
|
|
367
|
+
* tries again (see RoutingRewriteLoop).
|
|
368
|
+
*/
|
|
369
|
+
async function writeRoutingToAllStores(config) {
|
|
370
|
+
let { configured, sources, debugName } = config;
|
|
371
|
+
let routingData = (0, remoteConfig_1.serializeRemoteConfig)(configured);
|
|
372
|
+
let routingWriteTime = Date.now();
|
|
373
|
+
let targets = [];
|
|
374
|
+
let seen = new Set();
|
|
375
|
+
for (let source of sources) {
|
|
376
|
+
let key = `${source.config.url}|${source.config.name}`;
|
|
377
|
+
if (seen.has(key))
|
|
378
|
+
continue;
|
|
379
|
+
seen.add(key);
|
|
380
|
+
targets.push(source);
|
|
381
|
+
}
|
|
382
|
+
console.log(`Writing routing config version ${(0, remoteConfig_1.getConfigVersion)(configured)} for ${debugName} to all ${targets.length} stores (write time ${new Date(routingWriteTime).toISOString()}): ${targets.map(x => `${x.config.url} (store ${JSON.stringify(x.config.name)})`).join(", ")}`);
|
|
383
|
+
let failures = [];
|
|
384
|
+
await Promise.all(targets.map(async (source) => {
|
|
385
|
+
var _a;
|
|
386
|
+
try {
|
|
387
|
+
await source.write(archives => archives.set(remoteConfig_1.ROUTING_FILE, routingData, { lastModified: routingWriteTime }));
|
|
388
|
+
console.log(`Wrote storage routing config version ${(0, remoteConfig_1.getConfigVersion)(configured)} to ${source.config.url} (store ${JSON.stringify(source.config.name)})`);
|
|
389
|
+
}
|
|
390
|
+
catch (e) {
|
|
391
|
+
failures.push(`${source.config.url} (store ${JSON.stringify(source.config.name)}): ${(_a = e.stack) !== null && _a !== void 0 ? _a : e}`);
|
|
392
|
+
}
|
|
393
|
+
}));
|
|
394
|
+
return { failures, total: targets.length };
|
|
395
|
+
}
|
|
396
|
+
exports.writeRoutingToAllStores = writeRoutingToAllStores;
|
|
397
|
+
/**
|
|
398
|
+
* The periodic re-write of the chain's in-code config: failures retried on the short interval - a
|
|
399
|
+
* store without the config rejects every write aimed at it, so this not landing is a big deal,
|
|
400
|
+
* logged on every attempt - and even success repeated hourly, in case a store lost it. The failure
|
|
401
|
+
* this exists for: a server whose trust was only granted AFTER startup, so the startup write was
|
|
402
|
+
* rejected and nothing else would ever retry it.
|
|
403
|
+
*/
|
|
404
|
+
class RoutingRewriteLoop {
|
|
405
|
+
constructor(config) {
|
|
406
|
+
this.config = config;
|
|
407
|
+
this.disposed = false;
|
|
408
|
+
}
|
|
409
|
+
/** (Re)arms the loop - called at the end of every init, with whether that init's write failed (which picks the short retry interval). */
|
|
410
|
+
start(failedAtStartup) {
|
|
411
|
+
this.schedule(failedAtStartup && exports.CONFIG_WRITE_RETRY_INTERVAL || exports.CONFIG_WRITE_REFRESH_INTERVAL);
|
|
412
|
+
}
|
|
413
|
+
dispose() {
|
|
414
|
+
this.disposed = true;
|
|
415
|
+
if (this.timer) {
|
|
416
|
+
clearTimeout(this.timer);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
schedule(delay) {
|
|
420
|
+
var _a, _b;
|
|
421
|
+
if (this.disposed)
|
|
422
|
+
return;
|
|
423
|
+
if (this.timer) {
|
|
424
|
+
clearTimeout(this.timer);
|
|
425
|
+
}
|
|
426
|
+
this.timer = setTimeout(() => {
|
|
427
|
+
this.timer = undefined;
|
|
428
|
+
void this.rewrite().catch((e) => {
|
|
429
|
+
var _a;
|
|
430
|
+
console.error(`Rewriting the storage routing config for ${this.config.debugName()} failed: ${(_a = e.stack) !== null && _a !== void 0 ? _a : e}`);
|
|
431
|
+
this.schedule(exports.CONFIG_WRITE_RETRY_INTERVAL);
|
|
432
|
+
});
|
|
433
|
+
}, delay);
|
|
434
|
+
(_b = (_a = this.timer).unref) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
435
|
+
}
|
|
436
|
+
async rewrite() {
|
|
437
|
+
if (this.disposed)
|
|
438
|
+
return;
|
|
439
|
+
let configured = this.config.configured;
|
|
440
|
+
let state = this.config.latest();
|
|
441
|
+
if (!state) {
|
|
442
|
+
this.schedule(exports.CONFIG_WRITE_RETRY_INTERVAL);
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
445
|
+
// The bucket adopted a NEWER config than our in-code one, so ours is stale and every store would (rightly) refuse it
|
|
446
|
+
if ((0, remoteConfig_1.getConfigVersion)(state.config) > (0, remoteConfig_1.getConfigVersion)(configured)) {
|
|
447
|
+
this.schedule(exports.CONFIG_WRITE_REFRESH_INTERVAL);
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
// Same version but different content: startup already decided the stored one wins until the version is bumped (see chooseStartupConfig), and re-writing ours would flip the bucket back and forth between the two
|
|
451
|
+
if ((0, remoteConfig_1.getConfigVersion)(state.config) === (0, remoteConfig_1.getConfigVersion)(configured) && JSON.stringify(state.config) !== JSON.stringify(configured)) {
|
|
452
|
+
this.schedule(exports.CONFIG_WRITE_REFRESH_INTERVAL);
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
let { failures, total } = await writeRoutingToAllStores({ configured, sources: state.sources, debugName: this.config.debugName() });
|
|
456
|
+
if (failures.length) {
|
|
457
|
+
console.error(`The periodic routing config write for ${this.config.debugName()} (version ${(0, remoteConfig_1.getConfigVersion)(configured)}) failed on ${failures.length} of ${total} stores - retrying in ${exports.CONFIG_WRITE_RETRY_INTERVAL / 1000}s: ${failures.join(" | ")}`);
|
|
458
|
+
this.schedule(exports.CONFIG_WRITE_RETRY_INTERVAL);
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
this.schedule(exports.CONFIG_WRITE_REFRESH_INTERVAL);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
exports.RoutingRewriteLoop = RoutingRewriteLoop;
|
|
465
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hhaW5TdGFydHVwLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiY2hhaW5TdGFydHVwLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLG1EQUFrRDtBQUVsRCxpREFBK0g7QUFDL0gsbURBQWtHO0FBQ2xHLCtEQUFtRTtBQUNuRSx1RUFBbUU7QUFFbkUsNGRBQTRkO0FBRTVkLE1BQU0sb0JBQW9CLEdBQUcsQ0FBQyxHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUM7QUFDM0MsTUFBTSw2QkFBNkIsR0FBRyxDQUFDLEdBQUcsSUFBSSxDQUFDO0FBQy9DLHNOQUFzTjtBQUN6TSxRQUFBLDJCQUEyQixHQUFHLENBQUMsR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFDO0FBQ3pELGdIQUFnSDtBQUNuRyxRQUFBLDZCQUE2QixHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFDO0FBTzVELG1PQUFtTztBQUNuTyxNQUFhLGlCQUFpQjtJQWMxQixZQUFvQixNQUtuQjtRQUxtQixXQUFNLEdBQU4sTUFBTSxDQUt6QjtRQVpPLG1CQUFjLEdBQUcsaUNBQWlCLENBQUM7UUFHbkMsYUFBUSxHQUFHLEtBQUssQ0FBQztRQWtOakIsNEJBQXVCLEdBQUcsQ0FBQyxDQUFDO1FBeE1oQyxJQUFJLENBQUMsVUFBVSxHQUFHLE1BQU0sQ0FBQyxVQUFVLENBQUM7UUFDcEMsSUFBSSxDQUFDLFlBQVksR0FBRyxNQUFNLENBQUMsVUFBVSxDQUFDO1FBQ3RDLElBQUksQ0FBQyxlQUFlLEdBQUcsSUFBSSxrQkFBa0IsQ0FBQztZQUMxQyxVQUFVLEVBQUUsTUFBTSxDQUFDLFVBQVU7WUFDN0IsU0FBUyxFQUFFLE1BQU0sQ0FBQyxTQUFTO1lBQzNCLE1BQU0sRUFBRSxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsV0FBVztTQUNqQyxDQUFDLENBQUM7UUFDSCxJQUFJLENBQUMsc0JBQXNCLEdBQUcsSUFBQSxnREFBc0IsRUFBQyxHQUFHLEVBQUU7WUFDdEQsS0FBSyxJQUFJLENBQUMsbUJBQW1CLEVBQUUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFRLEVBQUUsRUFBRSxXQUFDLE9BQUEsT0FBTyxDQUFDLEtBQUssQ0FBQyw2QkFBNkIsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLEVBQUUsS0FBSyxNQUFBLENBQUMsQ0FBQyxLQUFLLG1DQUFJLENBQUMsRUFBRSxDQUFDLENBQUEsRUFBQSxDQUFDLENBQUM7UUFDaEosQ0FBQyxDQUFDLENBQUM7SUFDUCxDQUFDO0lBRUQseUZBQXlGO0lBQ2xGLE1BQU07UUFDVCxPQUFPLElBQUksQ0FBQyxXQUFXLENBQUM7SUFDNUIsQ0FBQztJQUVNLFFBQVE7UUFDWCxJQUFJLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztZQUNoQixPQUFPLE9BQU8sQ0FBQyxNQUFNLENBQUMsSUFBSSxLQUFLLENBQUMsaUJBQWlCLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxFQUFFLG9CQUFvQixDQUFDLENBQUMsQ0FBQztRQUNuRyxDQUFDO1FBQ0QsSUFBSSxDQUFDLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQztZQUNyQixJQUFJLE9BQU8sR0FBRyxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDMUIsSUFBSSxDQUFDLFlBQVksR0FBRyxPQUFPLENBQUM7WUFDNUIsT0FBTyxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUU7Z0JBQ2QsSUFBSSxDQUFDLGNBQWMsR0FBRyxpQ0FBaUIsQ0FBQztZQUM1QyxDQUFDLEVBQUUsQ0FBQyxDQUFRLEVBQUUsRUFBRTs7Z0JBQ1osSUFBSSxJQUFJLENBQUMsUUFBUSxJQUFJLElBQUksQ0FBQyxjQUFjO29CQUFFLE9BQU87Z0JBQ2pELE9BQU8sQ0FBQyxLQUFLLENBQUMsMkJBQTJCLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxFQUFFLGlCQUFpQixJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxjQUFjLEdBQUcsSUFBSSxDQUFDLE1BQU0sTUFBQSxDQUFDLENBQUMsS0FBSyxtQ0FBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO2dCQUM3SSxJQUFJLENBQUMsY0FBYyxHQUFHLFVBQVUsQ0FBQyxHQUFHLEVBQUU7b0JBQ2xDLElBQUksQ0FBQyxjQUFjLEdBQUcsU0FBUyxDQUFDO29CQUNoQyxJQUFJLElBQUksQ0FBQyxRQUFRO3dCQUFFLE9BQU87b0JBQzFCLElBQUksSUFBSSxDQUFDLFlBQVksS0FBSyxPQUFPLEVBQUUsQ0FBQzt3QkFDaEMsSUFBSSxDQUFDLFlBQVksR0FBRyxTQUFTLENBQUM7b0JBQ2xDLENBQUM7b0JBQ0QsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDLEtBQUssQ0FBQyxHQUFHLEVBQUUsR0FBRyxDQUFDLENBQUMsQ0FBQztnQkFDckMsQ0FBQyxFQUFFLElBQUksQ0FBQyxjQUFjLENBQUMsQ0FBQztnQkFDeEIsTUFBQSxNQUFDLElBQUksQ0FBQyxjQUF5QyxFQUFDLEtBQUssa0RBQUksQ0FBQztnQkFDMUQsSUFBSSxDQUFDLGNBQWMsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLCtCQUFlLEVBQUUsSUFBSSxDQUFDLGNBQWMsR0FBRyw0QkFBWSxDQUFDLENBQUM7WUFDeEYsQ0FBQyxDQUFDLENBQUM7UUFDUCxDQUFDO1FBQ0QsT0FBTyxJQUFJLENBQUMsWUFBWSxDQUFDO0lBQzdCLENBQUM7SUFFTyxLQUFLLENBQUMsSUFBSTtRQUNkLElBQUksT0FBTyxHQUFHLElBQUksQ0FBQyxVQUFVLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyw4QkFBZSxDQUFDLENBQUM7UUFDM0QsSUFBSSxRQUFRLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDaEQsSUFBSSxNQUFNLEdBQUcsTUFBTSxZQUFZLENBQUMsT0FBTyxFQUFFLFFBQVEsQ0FBQyxDQUFDO1FBQ25ELElBQUksQ0FBQztZQUNELElBQUksRUFBRSxNQUFNLEVBQUUsVUFBVSxFQUFFLFFBQVEsRUFBRSxHQUFHLG1CQUFtQixDQUFDLEVBQUUsVUFBVSxFQUFFLElBQUksQ0FBQyxVQUFVLEVBQUUsTUFBTSxFQUFFLFNBQVMsRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLFNBQVMsRUFBRSxFQUFFLENBQUMsQ0FBQztZQUN4SSxJQUFJLE9BQU8sR0FBRyxNQUFNLElBQUksQ0FBQyxZQUFZLENBQUMsTUFBTSxDQUFDLENBQUM7WUFDOUMsSUFBSSxpQkFBaUIsR0FBRyxLQUFLLENBQUM7WUFDOUIsSUFBSSxVQUFVLEVBQUUsQ0FBQztnQkFDYixPQUFPLENBQUMsR0FBRyxDQUFDLDhCQUE4QixJQUFJLENBQUMsTUFBTSxDQUFDLFNBQVMsRUFBRSxtQ0FBbUMsUUFBUSxJQUFJLElBQUEsK0JBQWdCLEVBQUMsUUFBUSxDQUFDLElBQUksTUFBTSxVQUFVLElBQUEsK0JBQWdCLEVBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsQ0FBQztnQkFDcE0sSUFBSSxFQUFFLFFBQVEsRUFBRSxLQUFLLEVBQUUsR0FBRyxNQUFNLHVCQUF1QixDQUFDLEVBQUUsVUFBVSxFQUFFLElBQUksQ0FBQyxVQUFVLEVBQUUsT0FBTyxFQUFFLFNBQVMsRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLFNBQVMsRUFBRSxFQUFFLENBQUMsQ0FBQztnQkFDdEksaUJBQWlCLEdBQUcsUUFBUSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUM7Z0JBQ3hDLElBQUksUUFBUSxDQUFDLE1BQU0sSUFBSSxRQUFRLENBQUMsTUFBTSxLQUFLLEtBQUssRUFBRSxDQUFDO29CQUMvQyxzSkFBc0o7b0JBQ3RKLE9BQU8sQ0FBQyxLQUFLLENBQUMsa0NBQWtDLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxFQUFFLGFBQWEsSUFBQSwrQkFBZ0IsRUFBQyxJQUFJLENBQUMsVUFBVSxDQUFDLHdDQUF3QyxLQUFLLFlBQVksUUFBUSxJQUFJLHlDQUF5QyxJQUFBLCtCQUFnQixFQUFDLFFBQVEsQ0FBQywyQkFBMkIsSUFBSSxvRkFBb0YsZ0JBQWdCLG1DQUEyQixHQUFHLElBQUksZ0JBQWdCLFFBQVEsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDO29CQUMxYyxJQUFJLFFBQVEsRUFBRSxDQUFDO3dCQUNYLE1BQU0sR0FBRyxRQUFRLENBQUM7d0JBQ2xCLEtBQUssSUFBSSxNQUFNLElBQUksT0FBTyxFQUFFLENBQUM7NEJBQ3pCLE1BQU0sQ0FBQyxPQUFPLEVBQUUsQ0FBQzt3QkFDckIsQ0FBQzt3QkFDRCxPQUFPLEdBQUcsTUFBTSxJQUFJLENBQUMsWUFBWSxDQUFDLE1BQU0sQ0FBQyxDQUFDO29CQUM5QyxDQUFDO2dCQUNMLENBQUM7cUJBQU0sSUFBSSxRQUFRLENBQUMsTUFBTSxFQUFFLENBQUM7b0JBQ3pCLE9BQU8sQ0FBQyxLQUFLLENBQUMsa0NBQWtDLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxFQUFFLGFBQWEsSUFBQSwrQkFBZ0IsRUFBQyxJQUFJLENBQUMsVUFBVSxDQUFDLG9CQUFvQixLQUFLLEdBQUcsUUFBUSxDQUFDLE1BQU0sT0FBTyxLQUFLLGlDQUFpQyxtQ0FBMkIsR0FBRyxJQUFJLGlFQUFpRSxRQUFRLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQztnQkFDNVUsQ0FBQztZQUNMLENBQUM7WUFDRCxLQUFLLElBQUksTUFBTSxJQUFJLE9BQU8sRUFBRSxDQUFDO2dCQUN6QixJQUFJLEtBQUssR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLFNBQVMsSUFBSSxDQUFDLENBQUMsWUFBWSxDQUFDLEdBQUcsS0FBSyxNQUFNLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDO2dCQUN0RixJQUFJLEtBQUssRUFBRSxDQUFDO29CQUNSLE1BQU0sQ0FBQyxXQUFXLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDO2dCQUN0QyxDQUFDO1lBQ0wsQ0FBQztZQUNELElBQUksQ0FBQyxZQUFZLEdBQUcsTUFBTSxDQUFDO1lBQzNCLElBQUksQ0FBQyxlQUFlLEVBQUUsQ0FBQztZQUN2QixJQUFJLEtBQUssR0FBZSxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsT0FBTyxFQUFFLENBQUM7WUFDcEQsSUFBSSxDQUFDLFdBQVcsR0FBRyxLQUFLLENBQUM7WUFDekIsSUFBSSxDQUFDLGVBQWUsQ0FBQyxLQUFLLENBQUMsaUJBQWlCLENBQUMsQ0FBQztZQUM5QyxPQUFPLEtBQUssQ0FBQztRQUNqQixDQUFDO2dCQUFTLENBQUM7WUFDUCxhQUFhLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDMUIsQ0FBQztJQUNMLENBQUM7SUFFRCxpTEFBaUw7SUFDekssVUFBVSxDQUFDLE1BQW9CO1FBQ25DLElBQUksSUFBSSxDQUFDLE1BQU0sQ0FBQyxhQUFhLElBQUksSUFBQSxhQUFNLEdBQUU7WUFBRSxPQUFPLEtBQUssQ0FBQztRQUN4RCxPQUFPLE1BQU0sQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLDhCQUFlLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDbkUsQ0FBQztJQUVPLEtBQUssQ0FBQyxpQkFBaUIsQ0FBQyxZQUEwQixFQUFFLFFBQWlCO1FBQ3pFLElBQUksTUFBTSxHQUFHLE1BQU0sNkJBQWEsQ0FBQyxNQUFNLENBQUMsWUFBWSxFQUFFLEVBQUUsUUFBUSxFQUFFLENBQUMsQ0FBQztRQUNwRSxNQUFNLENBQUMsWUFBWSxFQUFFLENBQUM7UUFDdEIsT0FBTyxNQUFNLENBQUM7SUFDbEIsQ0FBQztJQUVPLEtBQUssQ0FBQyxZQUFZLENBQUMsTUFBb0I7UUFDM0MsSUFBSSxRQUFRLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUN2QyxJQUFJLE9BQU8sR0FBb0IsRUFBRSxDQUFDO1FBQ2xDLEtBQUssSUFBSSxZQUFZLElBQUksTUFBTSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsOEJBQWUsQ0FBQyxFQUFFLENBQUM7WUFDM0QsT0FBTyxDQUFDLElBQUksQ0FBQyxNQUFNLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxZQUFZLEVBQUUsUUFBUSxDQUFDLENBQUMsQ0FBQztRQUN2RSxDQUFDO1FBQ0QsT0FBTyxPQUFPLENBQUM7SUFDbkIsQ0FBQztJQUVPLGVBQWU7O1FBQ25CLElBQUksSUFBSSxDQUFDLFNBQVMsSUFBSSxJQUFJLENBQUMsUUFBUTtZQUFFLE9BQU87UUFDNUMsSUFBSSxDQUFDLFNBQVMsR0FBRyxXQUFXLENBQUMsR0FBRyxFQUFFO1lBQzlCLEtBQUssSUFBSSxDQUFDLG1CQUFtQixFQUFFLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBUSxFQUFFLEVBQUU7O2dCQUMvQyxPQUFPLENBQUMsS0FBSyxDQUFDLHdEQUF3RCxJQUFJLENBQUMsTUFBTSxDQUFDLFNBQVMsRUFBRSxLQUFLLE1BQUEsQ0FBQyxDQUFDLEtBQUssbUNBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztZQUN0SCxDQUFDLENBQUMsQ0FBQztRQUNQLENBQUMsRUFBRSxvQkFBb0IsQ0FBQyxDQUFDO1FBQ3pCLE1BQUEsTUFBQyxJQUFJLENBQUMsU0FBb0MsRUFBQyxLQUFLLGtEQUFJLENBQUM7SUFDekQsQ0FBQztJQUlNLG1CQUFtQjtRQUN0QixJQUFJLENBQUMsSUFBSSxDQUFDLHFCQUFxQixFQUFFLENBQUM7WUFDOUIsSUFBSSxDQUFDLHFCQUFxQixHQUFHLElBQUksQ0FBQyxpQkFBaUIsRUFBRSxDQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUU7Z0JBQy9ELElBQUksQ0FBQyxxQkFBcUIsR0FBRyxTQUFTLENBQUM7WUFDM0MsQ0FBQyxDQUFDLENBQUM7UUFDUCxDQUFDO1FBQ0QsT0FBTyxJQUFJLENBQUMscUJBQXFCLENBQUM7SUFDdEMsQ0FBQztJQUVPLEtBQUssQ0FBQyxpQkFBaUIsQ0FBQyxLQUFpQjs7UUFDN0MsSUFBSSxNQUFNLEdBQWEsRUFBRSxDQUFDO1FBQzFCLEtBQUssSUFBSSxNQUFNLElBQUksS0FBSyxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQy9CLElBQUksQ0FBQztnQkFDRCxJQUFJLE1BQU0sR0FBRyxNQUFNLE1BQU0sQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO2dCQUM5QyxJQUFJLE1BQU07b0JBQUUsT0FBTyxJQUFBLG9DQUFxQixFQUFDLE1BQU0sQ0FBQyxDQUFDO1lBQ3JELENBQUM7WUFBQyxPQUFPLENBQUMsRUFBRSxDQUFDO2dCQUNULE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDLEdBQUcsS0FBSyxNQUFDLENBQVcsQ0FBQyxLQUFLLG1DQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7WUFDcEUsQ0FBQztRQUNMLENBQUM7UUFDRCxJQUFJLE1BQU0sQ0FBQyxNQUFNLEtBQUssS0FBSyxDQUFDLE9BQU8sQ0FBQyxNQUFNLEVBQUUsQ0FBQztZQUN6QyxNQUFNLElBQUksS0FBSyxDQUFDLDBEQUEwRCxJQUFJLENBQUMsTUFBTSxDQUFDLFNBQVMsRUFBRSxLQUFLLE1BQU0sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQ2hJLENBQUM7UUFDRCxPQUFPLFNBQVMsQ0FBQztJQUNyQixDQUFDO0lBRU8sS0FBSyxDQUFDLGlCQUFpQjtRQUMzQixJQUFJLElBQUksQ0FBQyxRQUFRLElBQUksQ0FBQyxJQUFJLENBQUMsWUFBWTtZQUFFLE9BQU87UUFDaEQsSUFBSSxLQUFpQixDQUFDO1FBQ3RCLElBQUksQ0FBQztZQUNELEtBQUssR0FBRyxNQUFNLElBQUksQ0FBQyxZQUFZLENBQUM7UUFDcEMsQ0FBQztRQUFDLFdBQU0sQ0FBQztZQUNMLE9BQU87UUFDWCxDQUFDO1FBQ0QsSUFBSSxNQUFNLEdBQUcsTUFBTSxJQUFJLENBQUMsaUJBQWlCLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDakQsSUFBSSxDQUFDLE1BQU07WUFBRSxPQUFPO1FBQ3BCLE1BQU0sSUFBSSxDQUFDLGNBQWMsQ0FBQyxLQUFLLEVBQUUsTUFBTSxDQUFDLENBQUM7SUFDN0MsQ0FBQztJQUVPLEtBQUssQ0FBQyxjQUFjLENBQUMsS0FBaUIsRUFBRSxNQUFvQjs7UUFDaEUsSUFBSSxJQUFJLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxLQUFLLElBQUksQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQztZQUFFLE9BQU87UUFDcEUsSUFBSSxRQUFRLEdBQUcsSUFBSSxJQUFJLEVBQUUsQ0FBQyxXQUFXLEVBQUUsQ0FBQztRQUN4QyxJQUFJLHdCQUF3QixHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBQSxnREFBMEIsRUFBQyxNQUFNLENBQUMsQ0FBQyxLQUFLLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBQSxnREFBMEIsRUFBQyxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQztRQUMvSSxJQUFJLHdCQUF3QixFQUFFLENBQUM7WUFDM0IsT0FBTyxDQUFDLEdBQUcsQ0FBQyx1REFBdUQsSUFBQSwrQkFBZ0IsRUFBQyxLQUFLLENBQUMsTUFBTSxDQUFDLE9BQU8sSUFBQSwrQkFBZ0IsRUFBQyxNQUFNLENBQUMsZUFBZSxRQUFRLHFDQUFxQyxJQUFJLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUMxTixDQUFDO2FBQU0sQ0FBQztZQUNKLE9BQU8sQ0FBQyxHQUFHLENBQUMsMkNBQTJDLElBQUEsK0JBQWdCLEVBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxPQUFPLElBQUEsK0JBQWdCLEVBQUMsTUFBTSxDQUFDLGVBQWUsUUFBUSxxQ0FBcUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDOU0sQ0FBQztRQUNELElBQUksV0FBVyxHQUFHLENBQUMsTUFBb0IsRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxFQUFFLEdBQUcsTUFBTSxFQUFFLFdBQVcsRUFBRSxTQUFTLEVBQUUsQ0FBQyxDQUFDO1FBQ2xHLElBQUksV0FBVyxHQUFHLElBQUksR0FBRyxFQUEyQixDQUFDO1FBQ3JELEtBQUssSUFBSSxNQUFNLElBQUksS0FBSyxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQy9CLElBQUksR0FBRyxHQUFHLFdBQVcsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUM7WUFDckMsSUFBSSxJQUFJLEdBQUcsV0FBVyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUNoQyxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7Z0JBQ1IsSUFBSSxHQUFHLEVBQUUsQ0FBQztnQkFDVixXQUFXLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxJQUFJLENBQUMsQ0FBQztZQUMvQixDQUFDO1lBQ0QsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUN0QixDQUFDO1FBQ0QsSUFBSSxRQUFRLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUN2QyxJQUFJLE9BQU8sR0FBb0IsRUFBRSxDQUFDO1FBQ2xDLEtBQUssSUFBSSxZQUFZLElBQUksTUFBTSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsOEJBQWUsQ0FBQyxFQUFFLENBQUM7WUFDM0QsSUFBSSxHQUFHLEdBQUcsTUFBQSxXQUFXLENBQUMsR0FBRyxDQUFDLFdBQVcsQ0FBQyxZQUFZLENBQUMsQ0FBQywwQ0FBRSxLQUFLLEVBQUUsQ0FBQztZQUM5RCxJQUFJLEdBQUcsRUFBRSxDQUFDO2dCQUNOLEdBQUcsQ0FBQyxpQkFBaUIsQ0FBQyxZQUFZLENBQUMsV0FBVyxDQUFDLENBQUM7Z0JBQ2hELE9BQU8sQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7WUFDdEIsQ0FBQztpQkFBTSxDQUFDO2dCQUNKLE9BQU8sQ0FBQyxJQUFJLENBQUMsTUFBTSxJQUFJLENBQUMsaUJBQWlCLENBQUMsWUFBWSxFQUFFLFFBQVEsQ0FBQyxDQUFDLENBQUM7WUFDdkUsQ0FBQztRQUNMLENBQUM7UUFDRCxLQUFLLElBQUksU0FBUyxJQUFJLFdBQVcsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDO1lBQ3pDLEtBQUssSUFBSSxRQUFRLElBQUksU0FBUyxFQUFFLENBQUM7Z0JBQzdCLFFBQVEsQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUN2QixDQUFDO1FBQ0wsQ0FBQztRQUNELElBQUksQ0FBQyxZQUFZLEdBQUcsTUFBTSxDQUFDO1FBQzNCLElBQUksUUFBUSxHQUFlLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxPQUFPLEVBQUUsQ0FBQztRQUN2RCxJQUFJLENBQUMsV0FBVyxHQUFHLFFBQVEsQ0FBQztRQUM1QixJQUFJLENBQUMsWUFBWSxHQUFHLE9BQU8sQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDbEQsQ0FBQztJQUlELHlMQUF5TDtJQUNsTCxtQkFBbUI7UUFDdEIsSUFBSSxJQUFJLENBQUMsMkJBQTJCO1lBQUUsT0FBTyxJQUFJLENBQUMsMkJBQTJCLENBQUM7UUFDOUUsSUFBSSxJQUFJLENBQUMsR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFDLHVCQUF1QixHQUFHLDZCQUE2QjtZQUFFLE9BQU8sT0FBTyxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ3hHLElBQUksQ0FBQyx1QkFBdUIsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7UUFDMUMsSUFBSSxDQUFDLDJCQUEyQixHQUFHLElBQUksQ0FBQyxzQkFBc0IsRUFBRSxDQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUU7WUFDMUUsSUFBSSxDQUFDLDJCQUEyQixHQUFHLFNBQVMsQ0FBQztRQUNqRCxDQUFDLENBQUMsQ0FBQztRQUNILE9BQU8sSUFBSSxDQUFDLDJCQUEyQixDQUFDO0lBQzVDLENBQUM7SUFDTyxLQUFLLENBQUMsc0JBQXNCO1FBQ2hDLElBQUksSUFBSSxDQUFDLFFBQVEsSUFBSSxDQUFDLElBQUksQ0FBQyxZQUFZO1lBQUUsT0FBTztRQUNoRCxJQUFJLEtBQWlCLENBQUM7UUFDdEIsSUFBSSxDQUFDO1lBQ0QsS0FBSyxHQUFHLE1BQU0sSUFBSSxDQUFDLFlBQVksQ0FBQztRQUNwQyxDQUFDO1FBQUMsV0FBTSxDQUFDO1lBQ0wsT0FBTztRQUNYLENBQUM7UUFDRCxPQUFPLENBQUMsR0FBRyxDQUFDLG1DQUFtQyxJQUFJLENBQUMsTUFBTSxDQUFDLFNBQVMsRUFBRSx1QkFBdUIsS0FBSyxDQUFDLE9BQU8sQ0FBQyxNQUFNLG9EQUFvRCxDQUFDLENBQUM7UUFDdkssSUFBSSxPQUFPLEdBQUcsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLEtBQUssRUFBQyxNQUFNLEVBQUMsRUFBRTtZQUM3RCxJQUFJLENBQUM7Z0JBQ0QsT0FBTyxNQUFNLE1BQU0sQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1lBQzVDLENBQUM7WUFBQyxXQUFNLENBQUM7Z0JBQ0wsT0FBTyxTQUFTLENBQUM7WUFDckIsQ0FBQztRQUNMLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDSixJQUFJLE1BQU0sR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDbEMsSUFBSSxDQUFDLE1BQU07WUFBRSxPQUFPO1FBQ3BCLE1BQU0sSUFBSSxDQUFDLGNBQWMsQ0FBQyxLQUFLLEVBQUUsTUFBTSxDQUFDLENBQUM7SUFDN0MsQ0FBQztJQUVNLE9BQU87O1FBQ1YsSUFBSSxDQUFDLFFBQVEsR0FBRyxJQUFJLENBQUM7UUFDckIsTUFBQSxJQUFJLENBQUMsc0JBQXNCLG9EQUFJLENBQUM7UUFDaEMsSUFBSSxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7WUFDakIsYUFBYSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUNsQyxDQUFDO1FBQ0QsSUFBSSxJQUFJLENBQUMsY0FBYyxFQUFFLENBQUM7WUFDdEIsWUFBWSxDQUFDLElBQUksQ0FBQyxjQUFjLENBQUMsQ0FBQztRQUN0QyxDQUFDO1FBQ0QsSUFBSSxDQUFDLGVBQWUsQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUMvQixJQUFJLFlBQVksR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDO1FBQ3JDLElBQUksWUFBWSxFQUFFLENBQUM7WUFDZixLQUFLLFlBQVksQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUU7Z0JBQzNCLEtBQUssSUFBSSxNQUFNLElBQUksS0FBSyxDQUFDLE9BQU8sRUFBRSxDQUFDO29CQUMvQixNQUFNLENBQUMsT0FBTyxFQUFFLENBQUM7Z0JBQ3JCLENBQUM7WUFDTCxDQUFDLEVBQUUsR0FBRyxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUM7UUFDbEIsQ0FBQztJQUNMLENBQUM7Q0FDSjtBQWhSRCw4Q0FnUkM7QUFXRCx1UUFBdVE7QUFDaFEsS0FBSyxVQUFVLFlBQVksQ0FBQyxPQUF1QixFQUFFLFFBQWlCO0lBQ3pFLE9BQU8sTUFBTSxPQUFPLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsS0FBSyxFQUFDLFlBQVksRUFBQyxFQUFFOztRQUN0RCxJQUFJLEtBQUssR0FBRyxNQUFNLDZCQUFhLENBQUMsTUFBTSxDQUFDLFlBQVksRUFBRSxFQUFFLFVBQVUsRUFBRSxLQUFLLEVBQUUsUUFBUSxFQUFFLENBQUMsQ0FBQztRQUN0RixJQUFJLEtBQUssR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7UUFDdkIsSUFBSSxDQUFDO1lBQ0QsSUFBSSxRQUFRLEdBQUcsTUFBTSxLQUFLLENBQUMsaUJBQWlCLEVBQUUsQ0FBQztZQUMvQyxPQUFPLEVBQUUsS0FBSyxFQUFFLFlBQVksRUFBRSxTQUFTLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRSxJQUFJLENBQUMsR0FBRyxFQUFFLEdBQUcsS0FBSyxFQUFFLFFBQVEsRUFBRSxLQUFLLEVBQUUsRUFBRSxFQUFFLENBQUM7UUFDdEcsQ0FBQztRQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7WUFDVCxPQUFPLEVBQUUsS0FBSyxFQUFFLFlBQVksRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRSxDQUFDLEVBQUUsUUFBUSxFQUFFLFNBQVMsRUFBRSxLQUFLLEVBQUUsR0FBRyxZQUFZLENBQUMsR0FBRyxLQUFLLE1BQUMsQ0FBVyxDQUFDLEtBQUssbUNBQUksQ0FBQyxFQUFFLEVBQUUsQ0FBQztRQUNoSixDQUFDO0lBQ0wsQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUNSLENBQUM7QUFYRCxvQ0FXQztBQUVELFNBQWdCLGFBQWEsQ0FBQyxNQUFxQjtJQUMvQyxLQUFLLElBQUksS0FBSyxJQUFJLE1BQU0sRUFBRSxDQUFDO1FBQ3ZCLEtBQUssQ0FBQyxLQUFLLENBQUMsT0FBTyxFQUFFLENBQUM7SUFDMUIsQ0FBQztBQUNMLENBQUM7QUFKRCxzQ0FJQztBQUVEOzs7Ozs7Ozs7R0FTRztBQUNILFNBQWdCLG1CQUFtQixDQUFDLE1BQThFO0lBQzlHLElBQUksRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFLFNBQVMsRUFBRSxHQUFHLE1BQU0sQ0FBQztJQUMvQyxJQUFJLEtBQUssR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBQzFDLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUNULE1BQU0sSUFBSSxLQUFLLENBQUMsaUNBQWlDLFNBQVMseUJBQXlCLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUMvSCxDQUFDO0lBQ0QsSUFBSSxRQUFRLEdBQUcsS0FBSyxDQUFDLFFBQVEsQ0FBQztJQUM5QixJQUFJLE1BQU0sR0FBRyxVQUFVLENBQUM7SUFDeEIsSUFBSSxVQUFVLEdBQUcsSUFBSSxDQUFDO0lBQ3RCLElBQUksUUFBUSxJQUFJLElBQUEsK0JBQWdCLEVBQUMsUUFBUSxDQUFDLElBQUksSUFBQSwrQkFBZ0IsRUFBQyxVQUFVLENBQUMsRUFBRSxDQUFDO1FBQ3pFLElBQUksSUFBQSwrQkFBZ0IsRUFBQyxRQUFRLENBQUMsS0FBSyxJQUFBLCtCQUFnQixFQUFDLFVBQVUsQ0FBQyxJQUFJLElBQUksQ0FBQyxTQUFTLENBQUMsUUFBUSxDQUFDLEtBQUssSUFBSSxDQUFDLFNBQVMsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDO1lBQ3pILE9BQU8sQ0FBQyxLQUFLLENBQUMsb0VBQW9FLEtBQUssQ0FBQyxZQUFZLENBQUMsR0FBRyxvRUFBb0UsSUFBSSxDQUFDLFNBQVMsQ0FBQyxRQUFRLENBQUMsZUFBZSxJQUFJLENBQUMsU0FBUyxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUNyUCxDQUFDO1FBQ0QsTUFBTSxHQUFHLFFBQVEsQ0FBQztRQUNsQixVQUFVLEdBQUcsS0FBSyxDQUFDO0lBQ3ZCLENBQUM7SUFDRCxJQUFJLFVBQVUsRUFBRSxDQUFDO1FBQ2IsSUFBSSxJQUE4QixDQUFDO1FBQ25DLElBQUksV0FBK0IsQ0FBQztRQUNwQyxLQUFLLElBQUksS0FBSyxJQUFJLE1BQU0sRUFBRSxDQUFDO1lBQ3ZCLElBQUksTUFBTSxHQUFHLEtBQUssQ0FBQyxRQUFRLENBQUM7WUFDNUIsSUFBSSxDQUFDLE1BQU07Z0JBQUUsU0FBUztZQUN0QixJQUFJLENBQUMsSUFBSSxJQUFJLElBQUEsK0JBQWdCLEVBQUMsTUFBTSxDQUFDLEdBQUcsSUFBQSwrQkFBZ0IsRUFBQyxJQUFJLENBQUMsRUFBRSxDQUFDO2dCQUM3RCxJQUFJLEdBQUcsTUFBTSxDQUFDO1lBQ2xCLENBQUM7WUFDRCxJQUFJLElBQUEsK0JBQWdCLEVBQUMsTUFBTSxDQUFDLEtBQUssSUFBQSwrQkFBZ0IsRUFBQyxVQUFVLENBQUMsSUFBSSxJQUFJLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxLQUFLLElBQUksQ0FBQyxTQUFTLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQztnQkFDckgsV0FBVyxHQUFHLEtBQUssQ0FBQyxZQUFZLENBQUMsR0FBRyxDQUFDO1lBQ3pDLENBQUM7UUFDTCxDQUFDO1FBQ0QsSUFBSSxJQUFJLElBQUksSUFBQSwrQkFBZ0IsRUFBQyxJQUFJLENBQUMsSUFBSSxJQUFBLCtCQUFnQixFQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUM7WUFDakUsSUFBSSxXQUFXLElBQUksSUFBQSwrQkFBZ0IsRUFBQyxJQUFJLENBQUMsS0FBSyxJQUFBLCtCQUFnQixFQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUM7Z0JBQ3pFLE9BQU8sQ0FBQyxLQUFLLENBQUMsb0VBQW9FLFdBQVcsb0VBQW9FLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLGVBQWUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDLENBQUM7WUFDdE8sQ0FBQztZQUNELE1BQU0sR0FBRyxJQUFJLENBQUM7WUFDZCxVQUFVLEdBQUcsS0FBSyxDQUFDO1FBQ3ZCLENBQUM7SUFDTCxDQUFDO0lBQ0QsT0FBTyxFQUFFLE1BQU0sRUFBRSxVQUFVLEVBQUUsUUFBUSxFQUFFLENBQUM7QUFDNUMsQ0FBQztBQXRDRCxrREFzQ0M7QUFFRDs7Ozs7Ozs7O0dBU0c7QUFDSSxLQUFLLFVBQVUsdUJBQXVCLENBQUMsTUFBaUY7SUFDM0gsSUFBSSxFQUFFLFVBQVUsRUFBRSxPQUFPLEVBQUUsU0FBUyxFQUFFLEdBQUcsTUFBTSxDQUFDO0lBQ2hELElBQUksV0FBVyxHQUFHLElBQUEsb0NBQXFCLEVBQUMsVUFBVSxDQUFDLENBQUM7SUFDcEQsSUFBSSxnQkFBZ0IsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7SUFDbEMsSUFBSSxPQUFPLEdBQW9CLEVBQUUsQ0FBQztJQUNsQyxJQUFJLElBQUksR0FBRyxJQUFJLEdBQUcsRUFBVSxDQUFDO0lBQzdCLEtBQUssSUFBSSxNQUFNLElBQUksT0FBTyxFQUFFLENBQUM7UUFDekIsSUFBSSxHQUFHLEdBQUcsR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDLEdBQUcsSUFBSSxNQUFNLENBQUMsTUFBTSxDQUFDLElBQUksRUFBRSxDQUFDO1FBQ3ZELElBQUksSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUM7WUFBRSxTQUFTO1FBQzVCLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDZCxPQUFPLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ3pCLENBQUM7SUFDRCxPQUFPLENBQUMsR0FBRyxDQUFDLGtDQUFrQyxJQUFBLCtCQUFnQixFQUFDLFVBQVUsQ0FBQyxRQUFRLFNBQVMsV0FBVyxPQUFPLENBQUMsTUFBTSx1QkFBdUIsSUFBSSxJQUFJLENBQUMsZ0JBQWdCLENBQUMsQ0FBQyxXQUFXLEVBQUUsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsTUFBTSxDQUFDLEdBQUcsV0FBVyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDcFIsSUFBSSxRQUFRLEdBQWEsRUFBRSxDQUFDO0lBQzVCLE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLEtBQUssRUFBQyxNQUFNLEVBQUMsRUFBRTs7UUFDekMsSUFBSSxDQUFDO1lBQ0QsTUFBTSxNQUFNLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQywyQkFBWSxFQUFFLFdBQVcsRUFBRSxFQUFFLFlBQVksRUFBRSxnQkFBZ0IsRUFBRSxDQUFDLENBQUMsQ0FBQztZQUM1RyxPQUFPLENBQUMsR0FBRyxDQUFDLHdDQUF3QyxJQUFBLCtCQUFnQixFQUFDLFVBQVUsQ0FBQyxPQUFPLE1BQU0sQ0FBQyxNQUFNLENBQUMsR0FBRyxXQUFXLElBQUksQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDOUosQ0FBQztRQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7WUFDVCxRQUFRLENBQUMsSUFBSSxDQUFDLEdBQUcsTUFBTSxDQUFDLE1BQU0sQ0FBQyxHQUFHLFdBQVcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxNQUFNLE1BQUMsQ0FBVyxDQUFDLEtBQUssbUNBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUNwSCxDQUFDO0lBQ0wsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNKLE9BQU8sRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLE9BQU8sQ0FBQyxNQUFNLEVBQUUsQ0FBQztBQUMvQyxDQUFDO0FBdkJELDBEQXVCQztBQUVEOzs7Ozs7R0FNRztBQUNILE1BQWEsa0JBQWtCO0lBQzNCLFlBQW9CLE1BS25CO1FBTG1CLFdBQU0sR0FBTixNQUFNLENBS3pCO1FBR08sYUFBUSxHQUFHLEtBQUssQ0FBQztJQUhwQixDQUFDO0lBS04seUlBQXlJO0lBQ2xJLEtBQUssQ0FBQyxlQUF3QjtRQUNqQyxJQUFJLENBQUMsUUFBUSxDQUFDLGVBQWUsSUFBSSxtQ0FBMkIsSUFBSSxxQ0FBNkIsQ0FBQyxDQUFDO0lBQ25HLENBQUM7SUFFTSxPQUFPO1FBQ1YsSUFBSSxDQUFDLFFBQVEsR0FBRyxJQUFJLENBQUM7UUFDckIsSUFBSSxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDYixZQUFZLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQzdCLENBQUM7SUFDTCxDQUFDO0lBRU8sUUFBUSxDQUFDLEtBQWE7O1FBQzFCLElBQUksSUFBSSxDQUFDLFFBQVE7WUFBRSxPQUFPO1FBQzFCLElBQUksSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQ2IsWUFBWSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUM3QixDQUFDO1FBQ0QsSUFBSSxDQUFDLEtBQUssR0FBRyxVQUFVLENBQUMsR0FBRyxFQUFFO1lBQ3pCLElBQUksQ0FBQyxLQUFLLEdBQUcsU0FBUyxDQUFDO1lBQ3ZCLEtBQUssSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQVEsRUFBRSxFQUFFOztnQkFDbkMsT0FBTyxDQUFDLEtBQUssQ0FBQyw0Q0FBNEMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLEVBQUUsWUFBWSxNQUFBLENBQUMsQ0FBQyxLQUFLLG1DQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7Z0JBQzdHLElBQUksQ0FBQyxRQUFRLENBQUMsbUNBQTJCLENBQUMsQ0FBQztZQUMvQyxDQUFDLENBQUMsQ0FBQztRQUNQLENBQUMsRUFBRSxLQUFLLENBQUMsQ0FBQztRQUNWLE1BQUEsTUFBQyxJQUFJLENBQUMsS0FBZ0MsRUFBQyxLQUFLLGtEQUFJLENBQUM7SUFDckQsQ0FBQztJQUVPLEtBQUssQ0FBQyxPQUFPO1FBQ2pCLElBQUksSUFBSSxDQUFDLFFBQVE7WUFBRSxPQUFPO1FBQzFCLElBQUksVUFBVSxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsVUFBVSxDQUFDO1FBQ3hDLElBQUksS0FBSyxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxFQUFFLENBQUM7UUFDakMsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQ1QsSUFBSSxDQUFDLFFBQVEsQ0FBQyxtQ0FBMkIsQ0FBQyxDQUFDO1lBQzNDLE9BQU87UUFDWCxDQUFDO1FBQ0QscUhBQXFIO1FBQ3JILElBQUksSUFBQSwrQkFBZ0IsRUFBQyxLQUFLLENBQUMsTUFBTSxDQUFDLEdBQUcsSUFBQSwrQkFBZ0IsRUFBQyxVQUFVLENBQUMsRUFBRSxDQUFDO1lBQ2hFLElBQUksQ0FBQyxRQUFRLENBQUMscUNBQTZCLENBQUMsQ0FBQztZQUM3QyxPQUFPO1FBQ1gsQ0FBQztRQUNELGtOQUFrTjtRQUNsTixJQUFJLElBQUEsK0JBQWdCLEVBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxLQUFLLElBQUEsK0JBQWdCLEVBQUMsVUFBVSxDQUFDLElBQUksSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLEtBQUssSUFBSSxDQUFDLFNBQVMsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDO1lBQ2pJLElBQUksQ0FBQyxRQUFRLENBQUMscUNBQTZCLENBQUMsQ0FBQztZQUM3QyxPQUFPO1FBQ1gsQ0FBQztRQUNELElBQUksRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLEdBQUcsTUFBTSx1QkFBdUIsQ0FBQyxFQUFFLFVBQVUsRUFBRSxPQUFPLEVBQUUsS0FBSyxDQUFDLE9BQU8sRUFBRSxTQUFTLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFDcEksSUFBSSxRQUFRLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDbEIsT0FBTyxDQUFDLEtBQUssQ0FBQyx5Q0FBeUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLEVBQUUsYUFBYSxJQUFBLCtCQUFnQixFQUFDLFVBQVUsQ0FBQyxlQUFlLFFBQVEsQ0FBQyxNQUFNLE9BQU8sS0FBSyx5QkFBeUIsbUNBQTJCLEdBQUcsSUFBSSxNQUFNLFFBQVEsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1lBQzFQLElBQUksQ0FBQyxRQUFRLENBQUMsbUNBQTJCLENBQUMsQ0FBQztZQUMzQyxPQUFPO1FBQ1gsQ0FBQztRQUNELElBQUksQ0FBQyxRQUFRLENBQUMscUNBQTZCLENBQUMsQ0FBQztJQUNqRCxDQUFDO0NBQ0o7QUFoRUQsZ0RBZ0VDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgaXNOb2RlIH0gZnJvbSBcInNvY2tldC1mdW5jdGlvbi9zcmMvbWlzY1wiO1xuaW1wb3J0IHsgUmVtb3RlQ29uZmlnLCBTb3VyY2VDb25maWcgfSBmcm9tIFwiLi4vSUFyY2hpdmVzXCI7XG5pbXBvcnQgeyBST1VUSU5HX0ZJTEUsIGdldENvbmZpZ1ZlcnNpb24sIHNlcmlhbGl6ZVJlbW90ZUNvbmZpZywgbm9ybWFsaXplUmVtb3RlQ29uZmlnLCBub3JtYWxpemVTb3VyY2UgfSBmcm9tIFwiLi9yZW1vdGVDb25maWdcIjtcbmltcG9ydCB7IFNvdXJjZVdyYXBwZXIsIFJFVFJZX1NUQVJUX0RFTEFZLCBSRVRSWV9NQVhfREVMQVksIFJFVFJZX0dST1dUSCB9IGZyb20gXCIuL3NvdXJjZVdyYXBwZXJcIjtcbmltcG9ydCB7IHJlc29sdmVJbnRlcm1lZGlhdGVTb3VyY2VzIH0gZnJvbSBcIi4vaW50ZXJtZWRpYXRlU291cmNlc1wiO1xuaW1wb3J0IHsgb25TZXJ2ZXJSb3V0aW5nQ2hhbmdlZCB9IGZyb20gXCIuL3N0b3JhZ2VDbGllbnRDb250cm9sbGVyXCI7XG5cbi8vIFRoZSBMSUZFQ1lDTEUgb2YgYW4gQXJjaGl2ZXNDaGFpbidzIHN0YXRlLCBhbmQgbm90aGluZyBlbHNlOiBpbml0aWFsaXppbmcgaXQgKHByb2JpbmcgZXZlcnkgY29uZmlndXJlZCBzb3VyY2UsIGRlY2lkaW5nIHdoaWNoIHJvdXRpbmcgY29uZmlnIHRvIHJ1biwgd3JpdGluZyBvdXJzIG91dCB3aGVuIGl0IGlzIHRoZSBuZXdlc3QpLCB0aGUgcmV0cnkgd2hlbiBpbml0aWFsaXphdGlvbiBmYWlscywgdGhlIHBvbGwgdGhhdCBhZG9wdHMgbmV3ZXIgY29uZmlncywgdGhlIGF2YWlsYWJpbGl0eSByZWNoZWNrLCBhbmQgdGhlIGxvb3AgdGhhdCBrZWVwcyByZS13cml0aW5nIG91ciBjb25maWcuIE5vbmUgb2YgdGhpcyBpcyByZXF1ZXN0IGRpc3BhdGNoIC0gdGhlIGNoYWluIChjcmVhdGVBcmNoaXZlcy50cykgYXNrcyB0aGUgQ2hhaW5TdGF0ZU1hbmFnZXIgZm9yIHRoZSBjdXJyZW50IHN0YXRlIGFuZCBkaXNwYXRjaGVzIG92ZXIgaXQuXG5cbmNvbnN0IENPTkZJR19QT0xMX0lOVEVSVkFMID0gNSAqIDYwICogMTAwMDtcbmNvbnN0IEFWQUlMQUJJTElUWV9SRUNIRUNLX1RIUk9UVExFID0gNSAqIDEwMDA7XG4vLyBUaGUgcm91dGluZyBjb25maWcgd3JpdGUgaXMgcmV0cmllZCBvbiB0aGlzIGNhZGVuY2Ugd2hpbGUgaXQgaXMgZmFpbGluZy4gQSBzdG9yZSB0aGF0IG5ldmVyIHJlY2VpdmVkIHRoZSBjb25maWcgcmVqZWN0cyBldmVyeSB3cml0ZSBhaW1lZCBhdCBpdCwgc28gdGhpcyBub3QgbGFuZGluZyBpcyBhIGJpZyBkZWFsIC0gZWFjaCBmYWlsZWQgYXR0ZW1wdCBpcyBsb2dnZWQuXG5leHBvcnQgY29uc3QgQ09ORklHX1dSSVRFX1JFVFJZX0lOVEVSVkFMID0gNSAqIDYwICogMTAwMDtcbi8vIC4uLmFuZCBldmVuIGFmdGVyIHN1Y2Nlc3MgaXQgaXMgcmUtd3JpdHRlbiBvbiB0aGlzIGNhZGVuY2UsIGluIGNhc2UgYSBzdG9yZSBsb3N0IGl0IG9yIGEgc2VydmVyIGFwcGVhcmVkIGxhdGVcbmV4cG9ydCBjb25zdCBDT05GSUdfV1JJVEVfUkVGUkVTSF9JTlRFUlZBTCA9IDYwICogNjAgKiAxMDAwO1xuXG5leHBvcnQgdHlwZSBDaGFpblN0YXRlID0ge1xuICAgIGNvbmZpZzogUmVtb3RlQ29uZmlnO1xuICAgIHNvdXJjZXM6IFNvdXJjZVdyYXBwZXJbXTtcbn07XG5cbi8qKiBUaGUgY2hhaW4ncyBzdGF0ZSBhbmQgZXZlcnl0aGluZyBhYm91dCBIQVZJTkcgb25lOiBpbml0ICh3aXRoIGl0cyByZXRyeSksIHRoZSBjb25maWcgcG9sbCwgYXZhaWxhYmlsaXR5IHJlY2hlY2tzLCBhbmQgdGhlIHJvdXRpbmcgcmV3cml0ZSBsb29wLiBUaGUgY2hhaW4gY29uc3RydWN0cyBvbmUsIGFza3MgaXQgZ2V0U3RhdGUoKSBvbiBldmVyeSBjYWxsLCBhbmQgZGlzcG9zZXMgaXQuICovXG5leHBvcnQgY2xhc3MgQ2hhaW5TdGF0ZU1hbmFnZXIge1xuICAgIHB1YmxpYyByZWFkb25seSBjb25maWd1cmVkOiBSZW1vdGVDb25maWc7XG4gICAgLyoqIFRoZSBuZXdlc3QgYWRvcHRlZCBjb25maWcgLSB3aGF0IGdldERlYnVnTmFtZSBhbmQgZGlzcGF0Y2ggZGVjaXNpb25zIHJlYWQuIFN0YXJ0cyBhcyB0aGUgY29uZmlndXJlZCBvbmUgYW5kIG1vdmVzIHdpdGggZXZlcnkgYWRvcHRpb24uICovXG4gICAgcHVibGljIGFjdGl2ZUNvbmZpZzogUmVtb3RlQ29uZmlnO1xuICAgIHByaXZhdGUgc3RhdGVQcm9taXNlOiBQcm9taXNlPENoYWluU3RhdGU+IHwgdW5kZWZpbmVkO1xuICAgIC8vIFRoZSByZXNvbHZlZCBzdGF0ZSwgZm9yIHN5bmNocm9ub3VzIGFjY2VzcyAoZ2V0R2V0VVJMcykgLSBhbHdheXMgdGhlIG5ld2VzdCBhZG9wdGVkIGNvbmZpZywgd2hlcmUgc3RhdGVQcm9taXNlIG1heSBicmllZmx5IGxhZyBkdXJpbmcgYSByZWJ1aWxkXG4gICAgcHJpdmF0ZSBsYXRlc3RTdGF0ZTogQ2hhaW5TdGF0ZSB8IHVuZGVmaW5lZDtcbiAgICBwcml2YXRlIGluaXRSZXRyeURlbGF5ID0gUkVUUllfU1RBUlRfREVMQVk7XG4gICAgcHJpdmF0ZSBpbml0UmV0cnlUaW1lcjogUmV0dXJuVHlwZTx0eXBlb2Ygc2V0VGltZW91dD4gfCB1bmRlZmluZWQ7XG4gICAgcHJpdmF0ZSBwb2xsVGltZXI6IFJldHVyblR5cGU8dHlwZW9mIHNldEludGVydmFsPiB8IHVuZGVmaW5lZDtcbiAgICBwcml2YXRlIGRpc3Bvc2VkID0gZmFsc2U7XG4gICAgcHJpdmF0ZSB1bnN1YnNjcmliZVJvdXRpbmdQdXNoOiAoKCkgPT4gdm9pZCkgfCB1bmRlZmluZWQ7XG4gICAgcHJpdmF0ZSByb3V0aW5nUmV3cml0ZXI6IFJvdXRpbmdSZXdyaXRlTG9vcDtcblxuICAgIGNvbnN0cnVjdG9yKHByaXZhdGUgY29uZmlnOiB7XG4gICAgICAgIGNvbmZpZ3VyZWQ6IFJlbW90ZUNvbmZpZztcbiAgICAgICAgZGVidWdOYW1lOiAoKSA9PiBzdHJpbmc7XG4gICAgICAgIC8qKiBTZWUgQXJjaGl2ZXNDaGFpbk9wdGlvbnMuZGlyZWN0Q29ubmVjdC4gKi9cbiAgICAgICAgZGlyZWN0Q29ubmVjdD86IGJvb2xlYW47XG4gICAgfSkge1xuICAgICAgICB0aGlzLmNvbmZpZ3VyZWQgPSBjb25maWcuY29uZmlndXJlZDtcbiAgICAgICAgdGhpcy5hY3RpdmVDb25maWcgPSBjb25maWcuY29uZmlndXJlZDtcbiAgICAgICAgdGhpcy5yb3V0aW5nUmV3cml0ZXIgPSBuZXcgUm91dGluZ1Jld3JpdGVMb29wKHtcbiAgICAgICAgICAgIGNvbmZpZ3VyZWQ6IGNvbmZpZy5jb25maWd1cmVkLFxuICAgICAgICAgICAgZGVidWdOYW1lOiBjb25maWcuZGVidWdOYW1lLFxuICAgICAgICAgICAgbGF0ZXN0OiAoKSA9PiB0aGlzLmxhdGVzdFN0YXRlLFxuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy51bnN1YnNjcmliZVJvdXRpbmdQdXNoID0gb25TZXJ2ZXJSb3V0aW5nQ2hhbmdlZCgoKSA9PiB7XG4gICAgICAgICAgICB2b2lkIHRoaXMucmVmcmVzaEFjdGl2ZUNvbmZpZygpLmNhdGNoKChlOiBFcnJvcikgPT4gY29uc29sZS5lcnJvcihgQ29uZmlnIHJlZnJlc2ggZmFpbGVkIGZvciAke3RoaXMuY29uZmlnLmRlYnVnTmFtZSgpfTogJHtlLnN0YWNrID8/IGV9YCkpO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICAvKiogVGhlIG5ld2VzdCBhZG9wdGVkIHN0YXRlLCBzeW5jaHJvbm91c2x5IC0gdW5kZWZpbmVkIHVudGlsIHRoZSBmaXJzdCBpbml0IGZpbmlzaGVzLiAqL1xuICAgIHB1YmxpYyBsYXRlc3QoKTogQ2hhaW5TdGF0ZSB8IHVuZGVmaW5lZCB7XG4gICAgICAgIHJldHVybiB0aGlzLmxhdGVzdFN0YXRlO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXRTdGF0ZSgpOiBQcm9taXNlPENoYWluU3RhdGU+IHtcbiAgICAgICAgaWYgKHRoaXMuZGlzcG9zZWQpIHtcbiAgICAgICAgICAgIHJldHVybiBQcm9taXNlLnJlamVjdChuZXcgRXJyb3IoYEFyY2hpdmVzQ2hhaW4gJHt0aGlzLmNvbmZpZy5kZWJ1Z05hbWUoKX0gaGFzIGJlZW4gZGlzcG9zZWRgKSk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCF0aGlzLnN0YXRlUHJvbWlzZSkge1xuICAgICAgICAgICAgbGV0IHByb21pc2UgPSB0aGlzLmluaXQoKTtcbiAgICAgICAgICAgIHRoaXMuc3RhdGVQcm9taXNlID0gcHJvbWlzZTtcbiAgICAgICAgICAgIHByb21pc2UudGhlbigoKSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy5pbml0UmV0cnlEZWxheSA9IFJFVFJZX1NUQVJUX0RFTEFZO1xuICAgICAgICAgICAgfSwgKGU6IEVycm9yKSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuZGlzcG9zZWQgfHwgdGhpcy5pbml0UmV0cnlUaW1lcikgcmV0dXJuO1xuICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoYFN0b3JhZ2UgaW5pdCBmYWlsZWQgZm9yICR7dGhpcy5jb25maWcuZGVidWdOYW1lKCl9LCByZXRyeWluZyBpbiAke01hdGgucm91bmQodGhpcy5pbml0UmV0cnlEZWxheSAvIDEwMDApfXMuICR7ZS5zdGFjayA/PyBlfWApO1xuICAgICAgICAgICAgICAgIHRoaXMuaW5pdFJldHJ5VGltZXIgPSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5pbml0UmV0cnlUaW1lciA9IHVuZGVmaW5lZDtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMuZGlzcG9zZWQpIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMuc3RhdGVQcm9taXNlID09PSBwcm9taXNlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnN0YXRlUHJvbWlzZSA9IHVuZGVmaW5lZDtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB0aGlzLmdldFN0YXRlKCkuY2F0Y2goKCkgPT4geyB9KTtcbiAgICAgICAgICAgICAgICB9LCB0aGlzLmluaXRSZXRyeURlbGF5KTtcbiAgICAgICAgICAgICAgICAodGhpcy5pbml0UmV0cnlUaW1lciBhcyB7IHVucmVmPzogKCkgPT4gdm9pZCB9KS51bnJlZj8uKCk7XG4gICAgICAgICAgICAgICAgdGhpcy5pbml0UmV0cnlEZWxheSA9IE1hdGgubWluKFJFVFJZX01BWF9ERUxBWSwgdGhpcy5pbml0UmV0cnlEZWxheSAqIFJFVFJZX0dST1dUSCk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGhpcy5zdGF0ZVByb21pc2U7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBpbml0KCk6IFByb21pc2U8Q2hhaW5TdGF0ZT4ge1xuICAgICAgICBsZXQgY29uZmlncyA9IHRoaXMuY29uZmlndXJlZC5zb3VyY2VzLm1hcChub3JtYWxpemVTb3VyY2UpO1xuICAgICAgICBsZXQgcmVhZE9ubHkgPSB0aGlzLmlzUmVhZE9ubHkodGhpcy5jb25maWd1cmVkKTtcbiAgICAgICAgbGV0IHByb2JlcyA9IGF3YWl0IHByb2JlU291cmNlcyhjb25maWdzLCByZWFkT25seSk7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBsZXQgeyBhY3RpdmUsIG5lZWRzV3JpdGUsIGV4aXN0aW5nIH0gPSBjaG9vc2VTdGFydHVwQ29uZmlnKHsgY29uZmlndXJlZDogdGhpcy5jb25maWd1cmVkLCBwcm9iZXMsIGRlYnVnTmFtZTogdGhpcy5jb25maWcuZGVidWdOYW1lKCkgfSk7XG4gICAgICAgICAgICBsZXQgc291cmNlcyA9IGF3YWl0IHRoaXMuYnVpbGRTb3VyY2VzKGFjdGl2ZSk7XG4gICAgICAgICAgICBsZXQgY29uZmlnV3JpdGVGYWlsZWQgPSBmYWxzZTtcbiAgICAgICAgICAgIGlmIChuZWVkc1dyaXRlKSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5sb2coYFN0b3JhZ2Ugcm91dGluZyBjb25maWcgZm9yICR7dGhpcy5jb25maWcuZGVidWdOYW1lKCl9IGlzIG91dCBvZiBkYXRlIChzdG9yZWQgdmVyc2lvbiAke2V4aXN0aW5nICYmIGdldENvbmZpZ1ZlcnNpb24oZXhpc3RpbmcpIHx8IFwibm9uZVwifSwgb3VycyAke2dldENvbmZpZ1ZlcnNpb24odGhpcy5jb25maWd1cmVkKX0pYCk7XG4gICAgICAgICAgICAgICAgbGV0IHsgZmFpbHVyZXMsIHRvdGFsIH0gPSBhd2FpdCB3cml0ZVJvdXRpbmdUb0FsbFN0b3Jlcyh7IGNvbmZpZ3VyZWQ6IHRoaXMuY29uZmlndXJlZCwgc291cmNlcywgZGVidWdOYW1lOiB0aGlzLmNvbmZpZy5kZWJ1Z05hbWUoKSB9KTtcbiAgICAgICAgICAgICAgICBjb25maWdXcml0ZUZhaWxlZCA9IGZhaWx1cmVzLmxlbmd0aCA+IDA7XG4gICAgICAgICAgICAgICAgaWYgKGZhaWx1cmVzLmxlbmd0aCAmJiBmYWlsdXJlcy5sZW5ndGggPT09IHRvdGFsKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIE5vYm9keSBoYXMgb3VyIGNvbmZpZywgc28gcnVubmluZyBvbiBpdCB3b3VsZCBqdXN0IGRpc2FncmVlIHdpdGggZXZlcnkgc2VydmVyLiBUaGUgc3RvcmVkIG9uZSAod2hlbiB0aGVyZSBpcyBvbmUpIGlzIHdoYXQgdGhlIHNlcnZlcnMgYWN0dWFsbHkgcnVuLlxuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKGBUaGUgc3RvcmFnZSByb3V0aW5nIGNvbmZpZyBmb3IgJHt0aGlzLmNvbmZpZy5kZWJ1Z05hbWUoKX0gKHZlcnNpb24gJHtnZXRDb25maWdWZXJzaW9uKHRoaXMuY29uZmlndXJlZCl9KSBjb3VsZCBub3QgYmUgd3JpdHRlbiB0byBBTlkgb2YgdGhlICR7dG90YWx9IHN0b3Jlcy4gJHtleGlzdGluZyAmJiBgUnVubmluZyBvbiB0aGUgc3RvcmVkIGNvbmZpZyAodmVyc2lvbiAke2dldENvbmZpZ1ZlcnNpb24oZXhpc3RpbmcpfSkgdW50aWwgYSB3cml0ZSBzdWNjZWVkcy5gIHx8IGBObyBzdG9yZWQgY29uZmlnIGV4aXN0cyBlaXRoZXIsIHNvIHNlcnZlcnMgd2lsbCByZWplY3Qgd3JpdGVzIHVudGlsIHRoaXMgc3VjY2VlZHMuYH0gUmV0cnlpbmcgaW4gJHtDT05GSUdfV1JJVEVfUkVUUllfSU5URVJWQUwgLyAxMDAwfXMuIEZhaWx1cmVzOiAke2ZhaWx1cmVzLmpvaW4oXCIgfCBcIil9YCk7XG4gICAgICAgICAgICAgICAgICAgIGlmIChleGlzdGluZykge1xuICAgICAgICAgICAgICAgICAgICAgICAgYWN0aXZlID0gZXhpc3Rpbmc7XG4gICAgICAgICAgICAgICAgICAgICAgICBmb3IgKGxldCBzb3VyY2Ugb2Ygc291cmNlcykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNvdXJjZS5kaXNwb3NlKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICBzb3VyY2VzID0gYXdhaXQgdGhpcy5idWlsZFNvdXJjZXMoYWN0aXZlKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoZmFpbHVyZXMubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoYFRoZSBzdG9yYWdlIHJvdXRpbmcgY29uZmlnIGZvciAke3RoaXMuY29uZmlnLmRlYnVnTmFtZSgpfSAodmVyc2lvbiAke2dldENvbmZpZ1ZlcnNpb24odGhpcy5jb25maWd1cmVkKX0pIHdhcyB3cml0dGVuIHRvICR7dG90YWwgLSBmYWlsdXJlcy5sZW5ndGh9IG9mICR7dG90YWx9IHN0b3Jlcy4gUmV0cnlpbmcgdGhlIHJlc3QgaW4gJHtDT05GSUdfV1JJVEVfUkVUUllfSU5URVJWQUwgLyAxMDAwfXMgKHRoZXkgYWxzbyBwdWxsIGl0IGZyb20gdGhlIHN0b3JlcyB0aGF0IGhhdmUgaXQpLiBGYWlsdXJlczogJHtmYWlsdXJlcy5qb2luKFwiIHwgXCIpfWApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGZvciAobGV0IHNvdXJjZSBvZiBzb3VyY2VzKSB7XG4gICAgICAgICAgICAgICAgbGV0IHByb2JlID0gcHJvYmVzLmZpbmQoeCA9PiB4LnJlc3BvbmRlZCAmJiB4LnNvdXJjZUNvbmZpZy51cmwgPT09IHNvdXJjZS5jb25maWcudXJsKTtcbiAgICAgICAgICAgICAgICBpZiAocHJvYmUpIHtcbiAgICAgICAgICAgICAgICAgICAgc291cmNlLnNlZWRMYXRlbmN5KHByb2JlLmxhdGVuY3kpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRoaXMuYWN0aXZlQ29uZmlnID0gYWN0aXZlO1xuICAgICAgICAgICAgdGhpcy5zdGFydENvbmZpZ1BvbGwoKTtcbiAgICAgICAgICAgIGxldCBzdGF0ZTogQ2hhaW5TdGF0ZSA9IHsgY29uZmlnOiBhY3RpdmUsIHNvdXJjZXMgfTtcbiAgICAgICAgICAgIHRoaXMubGF0ZXN0U3RhdGUgPSBzdGF0ZTtcbiAgICAgICAgICAgIHRoaXMucm91dGluZ1Jld3JpdGVyLnN0YXJ0KGNvbmZpZ1dyaXRlRmFpbGVkKTtcbiAgICAgICAgICAgIHJldHVybiBzdGF0ZTtcbiAgICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgICAgIGRpc3Bvc2VQcm9iZXMocHJvYmVzKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKiBDbGllbnRzaWRlLCBhIGNvbmZpZyB3aXRoIHB1YmxpYyBzb3VyY2VzIGlzIHNlcnZlZCBlbnRpcmVseSBvdmVyIHBsYWluIFVSTCBkb3dubG9hZHMgLSBubyBBUEkgY29ubmVjdGlvbiwgbm8gYWNjZXNzIGdyYW50LCBhbmQgbm8gd3JpdGluZy4gZGlyZWN0Q29ubmVjdCBvcHRzIG91dCBvZiB0aGF0LiAqL1xuICAgIHByaXZhdGUgaXNSZWFkT25seShjb25maWc6IFJlbW90ZUNvbmZpZyk6IGJvb2xlYW4ge1xuICAgICAgICBpZiAodGhpcy5jb25maWcuZGlyZWN0Q29ubmVjdCB8fCBpc05vZGUoKSkgcmV0dXJuIGZhbHNlO1xuICAgICAgICByZXR1cm4gY29uZmlnLnNvdXJjZXMubWFwKG5vcm1hbGl6ZVNvdXJjZSkuc29tZSh4ID0+IHgucHVibGljKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIGNyZWF0ZUNoYWluU291cmNlKHNvdXJjZUNvbmZpZzogU291cmNlQ29uZmlnLCByZWFkT25seTogYm9vbGVhbik6IFByb21pc2U8U291cmNlV3JhcHBlcj4ge1xuICAgICAgICBsZXQgc291cmNlID0gYXdhaXQgU291cmNlV3JhcHBlci5jcmVhdGUoc291cmNlQ29uZmlnLCB7IHJlYWRPbmx5IH0pO1xuICAgICAgICBzb3VyY2Uuc3RhcnRQaW5naW5nKCk7XG4gICAgICAgIHJldHVybiBzb3VyY2U7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBidWlsZFNvdXJjZXMoY29uZmlnOiBSZW1vdGVDb25maWcpOiBQcm9taXNlPFNvdXJjZVdyYXBwZXJbXT4ge1xuICAgICAgICBsZXQgcmVhZE9ubHkgPSB0aGlzLmlzUmVhZE9ubHkoY29uZmlnKTtcbiAgICAgICAgbGV0IHNvdXJjZXM6IFNvdXJjZVdyYXBwZXJbXSA9IFtdO1xuICAgICAgICBmb3IgKGxldCBzb3VyY2VDb25maWcgb2YgY29uZmlnLnNvdXJjZXMubWFwKG5vcm1hbGl6ZVNvdXJjZSkpIHtcbiAgICAgICAgICAgIHNvdXJjZXMucHVzaChhd2FpdCB0aGlzLmNyZWF0ZUNoYWluU291cmNlKHNvdXJjZUNvbmZpZywgcmVhZE9ubHkpKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gc291cmNlcztcbiAgICB9XG5cbiAgICBwcml2YXRlIHN0YXJ0Q29uZmlnUG9sbCgpOiB2b2lkIHtcbiAgICAgICAgaWYgKHRoaXMucG9sbFRpbWVyIHx8IHRoaXMuZGlzcG9zZWQpIHJldHVybjtcbiAgICAgICAgdGhpcy5wb2xsVGltZXIgPSBzZXRJbnRlcnZhbCgoKSA9PiB7XG4gICAgICAgICAgICB2b2lkIHRoaXMucmVmcmVzaEFjdGl2ZUNvbmZpZygpLmNhdGNoKChlOiBFcnJvcikgPT4ge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoYENoZWNraW5nIGZvciBhIG5ldyBzdG9yYWdlIHJvdXRpbmcgY29uZmlnIGZhaWxlZCBmb3IgJHt0aGlzLmNvbmZpZy5kZWJ1Z05hbWUoKX06ICR7ZS5zdGFjayA/PyBlfWApO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0sIENPTkZJR19QT0xMX0lOVEVSVkFMKTtcbiAgICAgICAgKHRoaXMucG9sbFRpbWVyIGFzIHsgdW5yZWY/OiAoKSA9PiB2b2lkIH0pLnVucmVmPy4oKTtcbiAgICB9XG5cbiAgICAvLyBEZWR1cGxpY2F0ZXMgY29uY3VycmVudCByZWZyZXNoZXMgKHRoZSBwb2xsIHRpbWVyIGFuZCB3cm9uZy10YXJnZXQgd3JpdGUgcmV0cmllcyBzaGFyZSB0aGlzKVxuICAgIHByaXZhdGUgY29uZmlnUmVmcmVzaEluRmxpZ2h0OiBQcm9taXNlPHZvaWQ+IHwgdW5kZWZpbmVkO1xuICAgIHB1YmxpYyByZWZyZXNoQWN0aXZlQ29uZmlnKCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBpZiAoIXRoaXMuY29uZmlnUmVmcmVzaEluRmxpZ2h0KSB7XG4gICAgICAgICAgICB0aGlzLmNvbmZpZ1JlZnJlc2hJbkZsaWdodCA9IHRoaXMuY2hlY2tGb3JOZXdDb25maWcoKS5maW5hbGx5KCgpID0+IHtcbiAgICAgICAgICAgICAgICB0aGlzLmNvbmZpZ1JlZnJlc2hJbkZsaWdodCA9IHVuZGVmaW5lZDtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0aGlzLmNvbmZpZ1JlZnJlc2hJbkZsaWdodDtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIGZldGNoTGF0ZXN0Q29uZmlnKHN0YXRlOiBDaGFpblN0YXRlKTogUHJvbWlzZTxSZW1vdGVDb25maWcgfCB1bmRlZmluZWQ+IHtcbiAgICAgICAgbGV0IGVycm9yczogc3RyaW5nW10gPSBbXTtcbiAgICAgICAgZm9yIChsZXQgc291cmNlIG9mIHN0YXRlLnNvdXJjZXMpIHtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgbGV0IGxhdGVzdCA9IGF3YWl0IHNvdXJjZS5yZWFkUm91dGluZ0NvbmZpZygpO1xuICAgICAgICAgICAgICAgIGlmIChsYXRlc3QpIHJldHVybiBub3JtYWxpemVSZW1vdGVDb25maWcobGF0ZXN0KTtcbiAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgICAgICBlcnJvcnMucHVzaChgJHtzb3VyY2UuY29uZmlnLnVybH06ICR7KGUgYXMgRXJyb3IpLnN0YWNrID8/IGV9YCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGVycm9ycy5sZW5ndGggPT09IHN0YXRlLnNvdXJjZXMubGVuZ3RoKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYE5vIHN0b3JhZ2Ugc291cmNlIGNvdWxkIGdpdmUgdXMgdGhlIHJvdXRpbmcgY29uZmlnIGZvciAke3RoaXMuY29uZmlnLmRlYnVnTmFtZSgpfTogJHtlcnJvcnMuam9pbihcIiB8IFwiKX1gKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgY2hlY2tGb3JOZXdDb25maWcoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGlmICh0aGlzLmRpc3Bvc2VkIHx8ICF0aGlzLnN0YXRlUHJvbWlzZSkgcmV0dXJuO1xuICAgICAgICBsZXQgc3RhdGU6IENoYWluU3RhdGU7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBzdGF0ZSA9IGF3YWl0IHRoaXMuc3RhdGVQcm9taXNlO1xuICAgICAgICB9IGNhdGNoIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBsZXQgbGF0ZXN0ID0gYXdhaXQgdGhpcy5mZXRjaExhdGVzdENvbmZpZyhzdGF0ZSk7XG4gICAgICAgIGlmICghbGF0ZXN0KSByZXR1cm47XG4gICAgICAgIGF3YWl0IHRoaXMuYWRvcHROZXdDb25maWcoc3RhdGUsIGxhdGVzdCk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBhZG9wdE5ld0NvbmZpZyhzdGF0ZTogQ2hhaW5TdGF0ZSwgbGF0ZXN0OiBSZW1vdGVDb25maWcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgaWYgKEpTT04uc3RyaW5naWZ5KGxhdGVzdCkgPT09IEpTT04uc3RyaW5naWZ5KHN0YXRlLmNvbmZpZykpIHJldHVybjtcbiAgICAgICAgbGV0IHJlY2VpdmVkID0gbmV3IERhdGUoKS50b0lTT1N0cmluZygpO1xuICAgICAgICBsZXQgb25seUludGVybWVkaWF0ZXNDaGFuZ2VkID0gSlNPTi5zdHJpbmdpZnkocmVzb2x2ZUludGVybWVkaWF0ZVNvdXJjZXMobGF0ZXN0KSkgPT09IEpTT04uc3RyaW5naWZ5KHJlc29sdmVJbnRlcm1lZGlhdGVTb3VyY2VzKHN0YXRlLmNvbmZpZykpO1xuICAgICAgICBpZiAob25seUludGVybWVkaWF0ZXNDaGFuZ2VkKSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhgU3RvcmFnZSByb3V0aW5nIHN3aXRjaG92ZXIgd2luZG93cyBjaGFuZ2VkICh2ZXJzaW9uICR7Z2V0Q29uZmlnVmVyc2lvbihzdGF0ZS5jb25maWcpfSAtPiAke2dldENvbmZpZ1ZlcnNpb24obGF0ZXN0KX0pLCByZWNlaXZlZCAke3JlY2VpdmVkfSwgcmVidWlsZGluZyBzb3VyY2VzLiBOZXcgY29uZmlnOiAke0pTT04uc3RyaW5naWZ5KGxhdGVzdCl9YCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhgU3RvcmFnZSByb3V0aW5nIGNvbmZpZyBjaGFuZ2VkICh2ZXJzaW9uICR7Z2V0Q29uZmlnVmVyc2lvbihzdGF0ZS5jb25maWcpfSAtPiAke2dldENvbmZpZ1ZlcnNpb24obGF0ZXN0KX0pLCByZWNlaXZlZCAke3JlY2VpdmVkfSwgcmVidWlsZGluZyBzb3VyY2VzLiBOZXcgY29uZmlnOiAke0pTT04uc3RyaW5naWZ5KGxhdGVzdCl9YCk7XG4gICAgICAgIH1cbiAgICAgICAgbGV0IHN0cmlwcGVkS2V5ID0gKGNvbmZpZzogU291cmNlQ29uZmlnKSA9PiBKU09OLnN0cmluZ2lmeSh7IC4uLmNvbmZpZywgdmFsaWRXaW5kb3c6IHVuZGVmaW5lZCB9KTtcbiAgICAgICAgbGV0IG9sZEJ5Q29uZmlnID0gbmV3IE1hcDxzdHJpbmcsIFNvdXJjZVdyYXBwZXJbXT4oKTtcbiAgICAgICAgZm9yIChsZXQgc291cmNlIG9mIHN0YXRlLnNvdXJjZXMpIHtcbiAgICAgICAgICAgIGxldCBrZXkgPSBzdHJpcHBlZEtleShzb3VyY2UuY29uZmlnKTtcbiAgICAgICAgICAgIGxldCBsaXN0ID0gb2xkQnlDb25maWcuZ2V0KGtleSk7XG4gICAgICAgICAgICBpZiAoIWxpc3QpIHtcbiAgICAgICAgICAgICAgICBsaXN0ID0gW107XG4gICAgICAgICAgICAgICAgb2xkQnlDb25maWcuc2V0KGtleSwgbGlzdCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBsaXN0LnB1c2goc291cmNlKTtcbiAgICAgICAgfVxuICAgICAgICBsZXQgcmVhZE9ubHkgPSB0aGlzLmlzUmVhZE9ubHkobGF0ZXN0KTtcbiAgICAgICAgbGV0IHNvdXJjZXM6IFNvdXJjZVdyYXBwZXJbXSA9IFtdO1xuICAgICAgICBmb3IgKGxldCBzb3VyY2VDb25maWcgb2YgbGF0ZXN0LnNvdXJjZXMubWFwKG5vcm1hbGl6ZVNvdXJjZSkpIHtcbiAgICAgICAgICAgIGxldCBvbGQgPSBvbGRCeUNvbmZpZy5nZXQoc3RyaXBwZWRLZXkoc291cmNlQ29uZmlnKSk/LnNoaWZ0KCk7XG4gICAgICAgICAgICBpZiAob2xkKSB7XG4gICAgICAgICAgICAgICAgb2xkLnVwZGF0ZVZhbGlkV2luZG93KHNvdXJjZUNvbmZpZy52YWxpZFdpbmRvdyk7XG4gICAgICAgICAgICAgICAgc291cmNlcy5wdXNoKG9sZCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHNvdXJjZXMucHVzaChhd2FpdCB0aGlzLmNyZWF0ZUNoYWluU291cmNlKHNvdXJjZUNvbmZpZywgcmVhZE9ubHkpKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBmb3IgKGxldCBsZWZ0b3ZlcnMgb2Ygb2xkQnlDb25maWcudmFsdWVzKCkpIHtcbiAgICAgICAgICAgIGZvciAobGV0IGxlZnRvdmVyIG9mIGxlZnRvdmVycykge1xuICAgICAgICAgICAgICAgIGxlZnRvdmVyLmRpc3Bvc2UoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICB0aGlzLmFjdGl2ZUNvbmZpZyA9IGxhdGVzdDtcbiAgICAgICAgbGV0IG5ld1N0YXRlOiBDaGFpblN0YXRlID0geyBjb25maWc6IGxhdGVzdCwgc291cmNlcyB9O1xuICAgICAgICB0aGlzLmxhdGVzdFN0YXRlID0gbmV3U3RhdGU7XG4gICAgICAgIHRoaXMuc3RhdGVQcm9taXNlID0gUHJvbWlzZS5yZXNvbHZlKG5ld1N0YXRlKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGxhc3RBdmFpbGFiaWxpdHlSZWNoZWNrID0gMDtcbiAgICBwcml2YXRlIGF2YWlsYWJpbGl0eVJlY2hlY2tJbkZsaWdodDogUHJvbWlzZTx2b2lkPiB8IHVuZGVmaW5lZDtcbiAgICAvKiogRXZlcnkgc291cmNlIGZhaWxlZDogcmUtY29udGFjdCBhbGwgb2YgdGhlbSAocm91dGluZyByZS1yZWFkICsgY29ubmVjdGlvbiByZS1hdHRlbXB0KSBhbmQgYWRvcHQgd2hhdGV2ZXIgY29uZmlnIGNvbWVzIGJhY2suIFRocm90dGxlZCwgYW5kIGRlZHVwbGljYXRlZCBhY3Jvc3MgY29uY3VycmVudCBjYWxsZXJzLiAqL1xuICAgIHB1YmxpYyByZWNoZWNrQXZhaWxhYmlsaXR5KCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBpZiAodGhpcy5hdmFpbGFiaWxpdHlSZWNoZWNrSW5GbGlnaHQpIHJldHVybiB0aGlzLmF2YWlsYWJpbGl0eVJlY2hlY2tJbkZsaWdodDtcbiAgICAgICAgaWYgKERhdGUubm93KCkgLSB0aGlzLmxhc3RBdmFpbGFiaWxpdHlSZWNoZWNrIDwgQVZBSUxBQklMSVRZX1JFQ0hFQ0tfVEhST1RUTEUpIHJldHVybiBQcm9taXNlLnJlc29sdmUoKTtcbiAgICAgICAgdGhpcy5sYXN0QXZhaWxhYmlsaXR5UmVjaGVjayA9IERhdGUubm93KCk7XG4gICAgICAgIHRoaXMuYXZhaWxhYmlsaXR5UmVjaGVja0luRmxpZ2h0ID0gdGhpcy5yZWNoZWNrQXZhaWxhYmlsaXR5Tm93KCkuZmluYWxseSgoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLmF2YWlsYWJpbGl0eVJlY2hlY2tJbkZsaWdodCA9IHVuZGVmaW5lZDtcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiB0aGlzLmF2YWlsYWJpbGl0eVJlY2hlY2tJbkZsaWdodDtcbiAgICB9XG4gICAgcHJpdmF0ZSBhc3luYyByZWNoZWNrQXZhaWxhYmlsaXR5Tm93KCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBpZiAodGhpcy5kaXNwb3NlZCB8fCAhdGhpcy5zdGF0ZVByb21pc2UpIHJldHVybjtcbiAgICAgICAgbGV0IHN0YXRlOiBDaGFpblN0YXRlO1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgc3RhdGUgPSBhd2FpdCB0aGlzLnN0YXRlUHJvbWlzZTtcbiAgICAgICAgfSBjYXRjaCB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgY29uc29sZS5sb2coYEV2ZXJ5IHN0b3JhZ2Ugc291cmNlIGZhaWxlZCBmb3IgJHt0aGlzLmNvbmZpZy5kZWJ1Z05hbWUoKX07IHJlLWNvbnRhY3RpbmcgYWxsICR7c3RhdGUuc291cmNlcy5sZW5ndGh9IHNvdXJjZXMgKHJvdXRpbmcgcmUtcmVhZCArIGNvbm5lY3Rpb24gcmUtYXR0ZW1wdClgKTtcbiAgICAgICAgbGV0IHJlc3VsdHMgPSBhd2FpdCBQcm9taXNlLmFsbChzdGF0ZS5zb3VyY2VzLm1hcChhc3luYyBzb3VyY2UgPT4ge1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICByZXR1cm4gYXdhaXQgc291cmNlLnJlYWRSb3V0aW5nQ29uZmlnKCk7XG4gICAgICAgICAgICB9IGNhdGNoIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KSk7XG4gICAgICAgIGxldCBsYXRlc3QgPSByZXN1bHRzLmZpbmQoeCA9PiB4KTtcbiAgICAgICAgaWYgKCFsYXRlc3QpIHJldHVybjtcbiAgICAgICAgYXdhaXQgdGhpcy5hZG9wdE5ld0NvbmZpZyhzdGF0ZSwgbGF0ZXN0KTtcbiAgICB9XG5cbiAgICBwdWJsaWMgZGlzcG9zZSgpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5kaXNwb3NlZCA9IHRydWU7XG4gICAgICAgIHRoaXMudW5zdWJzY3JpYmVSb3V0aW5nUHVzaD8uKCk7XG4gICAgICAgIGlmICh0aGlzLnBvbGxUaW1lcikge1xuICAgICAgICAgICAgY2xlYXJJbnRlcnZhbCh0aGlzLnBvbGxUaW1lcik7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRoaXMuaW5pdFJldHJ5VGltZXIpIHtcbiAgICAgICAgICAgIGNsZWFyVGltZW91dCh0aGlzLmluaXRSZXRyeVRpbWVyKTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLnJvdXRpbmdSZXdyaXRlci5kaXNwb3NlKCk7XG4gICAgICAgIGxldCBzdGF0ZVByb21pc2UgPSB0aGlzLnN0YXRlUHJvbWlzZTtcbiAgICAgICAgaWYgKHN0YXRlUHJvbWlzZSkge1xuICAgICAgICAgICAgdm9pZCBzdGF0ZVByb21pc2UudGhlbihzdGF0ZSA9PiB7XG4gICAgICAgICAgICAgICAgZm9yIChsZXQgc291cmNlIG9mIHN0YXRlLnNvdXJjZXMpIHtcbiAgICAgICAgICAgICAgICAgICAgc291cmNlLmRpc3Bvc2UoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9LCAoKSA9PiB7IH0pO1xuICAgICAgICB9XG4gICAgfVxufVxuXG5leHBvcnQgdHlwZSBTb3VyY2VQcm9iZSA9IHtcbiAgICBwcm9iZTogU291cmNlV3JhcHBlcjtcbiAgICBzb3VyY2VDb25maWc6IFNvdXJjZUNvbmZpZztcbiAgICByZXNwb25kZWQ6IGJvb2xlYW47XG4gICAgbGF0ZW5jeTogbnVtYmVyO1xuICAgIGV4aXN0aW5nOiBSZW1vdGVDb25maWcgfCB1bmRlZmluZWQ7XG4gICAgZXJyb3I6IHN0cmluZztcbn07XG5cbi8qKiBPbmUgdGhyb3dhd2F5IFNvdXJjZVdyYXBwZXIgcGVyIGNvbmZpZ3VyZWQgc291cmNlLCBlYWNoIGFza2VkIGZvciBpdHMgc3RvcmVkIHJvdXRpbmcgY29uZmlnIC0gd2hpY2ggYWxzbyBtZWFzdXJlcyBmaXJzdC1jb250YWN0IGxhdGVuY3ksIHNlZWRlZCBpbnRvIHRoZSByZWFsIHNvdXJjZXMgYWZ0ZXJ3YXJkcy4gVGhlIHByb2JlcyBNVVNUIGJlIGRpc3Bvc2VkIChkaXNwb3NlUHJvYmVzKSBvbmNlIHRoZSBjYWxsZXIgaXMgZG9uZSB3aXRoIHRoZW0uICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcHJvYmVTb3VyY2VzKGNvbmZpZ3M6IFNvdXJjZUNvbmZpZ1tdLCByZWFkT25seTogYm9vbGVhbik6IFByb21pc2U8U291cmNlUHJvYmVbXT4ge1xuICAgIHJldHVybiBhd2FpdCBQcm9taXNlLmFsbChjb25maWdzLm1hcChhc3luYyBzb3VyY2VDb25maWcgPT4ge1xuICAgICAgICBsZXQgcHJvYmUgPSBhd2FpdCBTb3VyY2VXcmFwcGVyLmNyZWF0ZShzb3VyY2VDb25maWcsIHsgYmFja2dyb3VuZDogZmFsc2UsIHJlYWRPbmx5IH0pO1xuICAgICAgICBsZXQgc3RhcnQgPSBEYXRlLm5vdygpO1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgbGV0IGV4aXN0aW5nID0gYXdhaXQgcHJvYmUucmVhZFJvdXRpbmdDb25maWcoKTtcbiAgICAgICAgICAgIHJldHVybiB7IHByb2JlLCBzb3VyY2VDb25maWcsIHJlc3BvbmRlZDogdHJ1ZSwgbGF0ZW5jeTogRGF0ZS5ub3coKSAtIHN0YXJ0LCBleGlzdGluZywgZXJyb3I6IFwiXCIgfTtcbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgcmV0dXJuIHsgcHJvYmUsIHNvdXJjZUNvbmZpZywgcmVzcG9uZGVkOiBmYWxzZSwgbGF0ZW5jeTogMCwgZXhpc3Rpbmc6IHVuZGVmaW5lZCwgZXJyb3I6IGAke3NvdXJjZUNvbmZpZy51cmx9OiAkeyhlIGFzIEVycm9yKS5zdGFjayA/PyBlfWAgfTtcbiAgICAgICAgfVxuICAgIH0pKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGRpc3Bvc2VQcm9iZXMocHJvYmVzOiBTb3VyY2VQcm9iZVtdKTogdm9pZCB7XG4gICAgZm9yIChsZXQgcHJvYmUgb2YgcHJvYmVzKSB7XG4gICAgICAgIHByb2JlLnByb2JlLmRpc3Bvc2UoKTtcbiAgICB9XG59XG5cbi8qKlxuICogV2hpY2ggcm91dGluZyBjb25maWcgdGhlIGNoYWluIHNob3VsZCBSVU46IHRoZSBuZXdlc3Qgb2Ygb3VycyBhbmQgZXZlcnkgc3RvcmVkIG9uZS4gbmVlZHNXcml0ZVxuICogd2hlbiBvdXJzIGlzIHN0cmljdGx5IHRoZSBuZXdlc3QsIG1lYW5pbmcgdGhlIHN0b3JlcyBoYXZlIHRvIGJlIHRvbGQgYWJvdXQgaXQuIEEgc3RvcmVkIGNvbmZpZ1xuICogd2l0aCBvdXIgZXhhY3QgdmVyc2lvbiBidXQgRElGRkVSRU5UIGNvbnRlbnQgd2lucyB3aXRob3V0IGEgd3JpdGUsIGxvdWRseTogY29uZmlnIHVwZGF0ZXMgbXVzdFxuICogYnVtcCB0aGUgdmVyc2lvbiwgb3IgdGhleSBhcmUgaWdub3JlZCAtIHNpbGVudGx5IHRha2luZyB0aGUgY2hhbmdlZCBvbmUgd291bGQgbWFrZSBcIndoYXQgaXMgdGhlXG4gKiBidWNrZXQgcnVubmluZ1wiIGRlcGVuZCBvbiB3aGljaCBwcm9jZXNzIHN0YXJ0ZWQgbGFzdC5cbiAqXG4gKiBUaHJvd3Mgd2hlbiBubyBzb3VyY2UgYW5zd2VyZWQgYXQgYWxsOiB3aXRoIG5vdGhpbmcgc3RvcmVkIGFuZCBub2JvZHkgdG8gd3JpdGUgdG8sIHRoZXJlIGlzIG5vXG4gKiBjb25maWcgdG8gcnVuLlxuICovXG5leHBvcnQgZnVuY3Rpb24gY2hvb3NlU3RhcnR1cENvbmZpZyhjb25maWc6IHsgY29uZmlndXJlZDogUmVtb3RlQ29uZmlnOyBwcm9iZXM6IFNvdXJjZVByb2JlW107IGRlYnVnTmFtZTogc3RyaW5nIH0pOiB7IGFjdGl2ZTogUmVtb3RlQ29uZmlnOyBuZWVkc1dyaXRlOiBib29sZWFuOyBleGlzdGluZzogUmVtb3RlQ29uZmlnIHwgdW5kZWZpbmVkIH0ge1xuICAgIGxldCB7IGNvbmZpZ3VyZWQsIHByb2JlcywgZGVidWdOYW1lIH0gPSBjb25maWc7XG4gICAgbGV0IGZvdW5kID0gcHJvYmVzLmZpbmQoeCA9PiB4LnJlc3BvbmRlZCk7XG4gICAgaWYgKCFmb3VuZCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYENhbm5vdCBpbml0aWFsaXplIHN0b3JhZ2UgZm9yICR7ZGVidWdOYW1lfTogbm8gc291cmNlIGFuc3dlcmVkLiAke3Byb2Jlcy5tYXAoeCA9PiB4LmVycm9yKS5qb2luKFwiIHwgXCIpfWApO1xuICAgIH1cbiAgICBsZXQgZXhpc3RpbmcgPSBmb3VuZC5leGlzdGluZztcbiAgICBsZXQgYWN0aXZlID0gY29uZmlndXJlZDtcbiAgICBsZXQgbmVlZHNXcml0ZSA9IHRydWU7XG4gICAgaWYgKGV4aXN0aW5nICYmIGdldENvbmZpZ1ZlcnNpb24oZXhpc3RpbmcpID49IGdldENvbmZpZ1ZlcnNpb24oY29uZmlndXJlZCkpIHtcbiAgICAgICAgaWYgKGdldENvbmZpZ1ZlcnNpb24oZXhpc3RpbmcpID09PSBnZXRDb25maWdWZXJzaW9uKGNvbmZpZ3VyZWQpICYmIEpTT04uc3RyaW5naWZ5KGV4aXN0aW5nKSAhPT0gSlNPTi5zdHJpbmdpZnkoY29uZmlndXJlZCkpIHtcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoYEFyY2hpdmVzIGNvbmZpZ3VyYXRpb24gdXBkYXRlZCB3aXRob3V0IHVwZGF0aW5nIHRoZSB2ZXJzaW9uLCBmb3IgJHtmb3VuZC5zb3VyY2VDb25maWcudXJsfS4gVXBkYXRlcyB3aWxsIGJlIGlnbm9yZWQgdW50aWwgeW91IGluY3JlYXNlIHRoZSB2ZXJzaW9uLiBVc2luZzogJHtKU09OLnN0cmluZ2lmeShleGlzdGluZyl9LCBpZ25vcmluZzogJHtKU09OLnN0cmluZ2lmeShjb25maWd1cmVkKX1gKTtcbiAgICAgICAgfVxuICAgICAgICBhY3RpdmUgPSBleGlzdGluZztcbiAgICAgICAgbmVlZHNXcml0ZSA9IGZhbHNlO1xuICAgIH1cbiAgICBpZiAobmVlZHNXcml0ZSkge1xuICAgICAgICBsZXQgYmVzdDogUmVtb3RlQ29uZmlnIHwgdW5kZWZpbmVkO1xuICAgICAgICBsZXQgY29uZmxpY3RVcmw6IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgICAgICAgZm9yIChsZXQgcHJvYmUgb2YgcHJvYmVzKSB7XG4gICAgICAgICAgICBsZXQgc3RvcmVkID0gcHJvYmUuZXhpc3Rpbmc7XG4gICAgICAgICAgICBpZiAoIXN0b3JlZCkgY29udGludWU7XG4gICAgICAgICAgICBpZiAoIWJlc3QgfHwgZ2V0Q29uZmlnVmVyc2lvbihzdG9yZWQpID4gZ2V0Q29uZmlnVmVyc2lvbihiZXN0KSkge1xuICAgICAgICAgICAgICAgIGJlc3QgPSBzdG9yZWQ7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoZ2V0Q29uZmlnVmVyc2lvbihzdG9yZWQpID09PSBnZXRDb25maWdWZXJzaW9uKGNvbmZpZ3VyZWQpICYmIEpTT04uc3RyaW5naWZ5KHN0b3JlZCkgIT09IEpTT04uc3RyaW5naWZ5KGNvbmZpZ3VyZWQpKSB7XG4gICAgICAgICAgICAgICAgY29uZmxpY3RVcmwgPSBwcm9iZS5zb3VyY2VDb25maWcudXJsO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGlmIChiZXN0ICYmIGdldENvbmZpZ1ZlcnNpb24oYmVzdCkgPj0gZ2V0Q29uZmlnVmVyc2lvbihjb25maWd1cmVkKSkge1xuICAgICAgICAgICAgaWYgKGNvbmZsaWN0VXJsICYmIGdldENvbmZpZ1ZlcnNpb24oYmVzdCkgPT09IGdldENvbmZpZ1ZlcnNpb24oY29uZmlndXJlZCkpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKGBBcmNoaXZlcyBjb25maWd1cmF0aW9uIHVwZGF0ZWQgd2l0aG91dCB1cGRhdGluZyB0aGUgdmVyc2lvbiwgZm9yICR7Y29uZmxpY3RVcmx9LiBVcGRhdGVzIHdpbGwgYmUgaWdub3JlZCB1bnRpbCB5b3UgaW5jcmVhc2UgdGhlIHZlcnNpb24uIFVzaW5nOiAke0pTT04uc3RyaW5naWZ5KGJlc3QpfSwgaWdub3Jpbmc6ICR7SlNPTi5zdHJpbmdpZnkoY29uZmlndXJlZCl9YCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBhY3RpdmUgPSBiZXN0O1xuICAgICAgICAgICAgbmVlZHNXcml0ZSA9IGZhbHNlO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiB7IGFjdGl2ZSwgbmVlZHNXcml0ZSwgZXhpc3RpbmcgfTtcbn1cblxuLyoqXG4gKiBXcml0ZXMgdGhlIGdpdmVuIHJvdXRpbmcgY29uZmlnIHRvIGV2ZXJ5IGNvbmZpZ3VyZWQgc3RvcmUsIG9uZSB3cml0ZSBwZXIgdXJsK25hbWU6IHRoZSB3cml0ZVxuICogbGFuZHMgaW4gdGhlIHN0b3JlIHRoZSBlbnRyeSBOQU1FUywgc28gdHdvIGVudHJpZXMgc2hhcmluZyBhIFVSTCBidXQgbmFtaW5nIGRpZmZlcmVudCBzdG9yZXMgYXJlXG4gKiB0d28gc2VwYXJhdGUgZGVsaXZlcmllcyAtIGRlZHVwaW5nIGJ5IFVSTCBhbG9uZSBsZWF2ZXMgdGhlIHNlY29uZCBzdG9yZSB1bmNvbmZpZ3VyZWQgZm9yZXZlci4gQWxsXG4gKiBpbiBwYXJhbGxlbCwgZXZlcnkgZmFpbHVyZSB0b2xlcmF0ZWQgKG5vLXdyaXRlLWFjY2VzcyBpbmNsdWRlZCAtIHRoZSBhdHRlbXB0IGNsYXNzaWZpZXMgaXQsXG4gKiBub3RoaW5nIHByZS1jaGVja3MgaXQpOiBhIGRvd24gbm9kZSBtdXN0IG5vdCBzdG9wIHRoZSBvdGhlcnMgZnJvbSBnZXR0aW5nIHRoZSBjb25maWcgLSB0aGV5IHdvdWxkXG4gKiB0aGVuIHJlamVjdCB3cml0ZXMgYXMgdW5jb25maWd1cmVkIHByZWNpc2VseSBCRUNBVVNFIGl0IG5ldmVyIGFycml2ZWQgLSBhbmQgaXQgbXVzdCBuZXZlciBzdG9wXG4gKiB0aGUgY2hhaW4gZnJvbSBzdGFydGluZy4gQSBzdG9yZSB0aGF0IG1pc3NlZCBpdCBwdWxscyBpdCBvZmYgaXRzIHBlZXJzLCBhbmQgdGhlIHJld3JpdGUgbG9vcFxuICogdHJpZXMgYWdhaW4gKHNlZSBSb3V0aW5nUmV3cml0ZUxvb3ApLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gd3JpdGVSb3V0aW5nVG9BbGxTdG9yZXMoY29uZmlnOiB7IGNvbmZpZ3VyZWQ6IFJlbW90ZUNvbmZpZzsgc291cmNlczogU291cmNlV3JhcHBlcltdOyBkZWJ1Z05hbWU6IHN0cmluZyB9KTogUHJvbWlzZTx7IGZhaWx1cmVzOiBzdHJpbmdbXTsgdG90YWw6IG51bWJlciB9PiB7XG4gICAgbGV0IHsgY29uZmlndXJlZCwgc291cmNlcywgZGVidWdOYW1lIH0gPSBjb25maWc7XG4gICAgbGV0IHJvdXRpbmdEYXRhID0gc2VyaWFsaXplUmVtb3RlQ29uZmlnKGNvbmZpZ3VyZWQpO1xuICAgIGxldCByb3V0aW5nV3JpdGVUaW1lID0gRGF0ZS5ub3coKTtcbiAgICBsZXQgdGFyZ2V0czogU291cmNlV3JhcHBlcltdID0gW107XG4gICAgbGV0IHNlZW4gPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgICBmb3IgKGxldCBzb3VyY2Ugb2Ygc291cmNlcykge1xuICAgICAgICBsZXQga2V5ID0gYCR7c291cmNlLmNvbmZpZy51cmx9fCR7c291cmNlLmNvbmZpZy5uYW1lfWA7XG4gICAgICAgIGlmIChzZWVuLmhhcyhrZXkpKSBjb250aW51ZTtcbiAgICAgICAgc2Vlbi5hZGQoa2V5KTtcbiAgICAgICAgdGFyZ2V0cy5wdXNoKHNvdXJjZSk7XG4gICAgfVxuICAgIGNvbnNvbGUubG9nKGBXcml0aW5nIHJvdXRpbmcgY29uZmlnIHZlcnNpb24gJHtnZXRDb25maWdWZXJzaW9uKGNvbmZpZ3VyZWQpfSBmb3IgJHtkZWJ1Z05hbWV9IHRvIGFsbCAke3RhcmdldHMubGVuZ3RofSBzdG9yZXMgKHdyaXRlIHRpbWUgJHtuZXcgRGF0ZShyb3V0aW5nV3JpdGVUaW1lKS50b0lTT1N0cmluZygpfSk6ICR7dGFyZ2V0cy5tYXAoeCA9PiBgJHt4LmNvbmZpZy51cmx9IChzdG9yZSAke0pTT04uc3RyaW5naWZ5KHguY29uZmlnLm5hbWUpfSlgKS5qb2luKFwiLCBcIil9YCk7XG4gICAgbGV0IGZhaWx1cmVzOiBzdHJpbmdbXSA9IFtdO1xuICAgIGF3YWl0IFByb21pc2UuYWxsKHRhcmdldHMubWFwKGFzeW5jIHNvdXJjZSA9PiB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBhd2FpdCBzb3VyY2Uud3JpdGUoYXJjaGl2ZXMgPT4gYXJjaGl2ZXMuc2V0KFJPVVRJTkdfRklMRSwgcm91dGluZ0RhdGEsIHsgbGFzdE1vZGlmaWVkOiByb3V0aW5nV3JpdGVUaW1lIH0pKTtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKGBXcm90ZSBzdG9yYWdlIHJvdXRpbmcgY29uZmlnIHZlcnNpb24gJHtnZXRDb25maWdWZXJzaW9uKGNvbmZpZ3VyZWQpfSB0byAke3NvdXJjZS5jb25maWcudXJsfSAoc3RvcmUgJHtKU09OLnN0cmluZ2lmeShzb3VyY2UuY29uZmlnLm5hbWUpfSlgKTtcbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgZmFpbHVyZXMucHVzaChgJHtzb3VyY2UuY29uZmlnLnVybH0gKHN0b3JlICR7SlNPTi5zdHJpbmdpZnkoc291cmNlLmNvbmZpZy5uYW1lKX0pOiAkeyhlIGFzIEVycm9yKS5zdGFjayA/PyBlfWApO1xuICAgICAgICB9XG4gICAgfSkpO1xuICAgIHJldHVybiB7IGZhaWx1cmVzLCB0b3RhbDogdGFyZ2V0cy5sZW5ndGggfTtcbn1cblxuLyoqXG4gKiBUaGUgcGVyaW9kaWMgcmUtd3JpdGUgb2YgdGhlIGNoYWluJ3MgaW4tY29kZSBjb25maWc6IGZhaWx1cmVzIHJldHJpZWQgb24gdGhlIHNob3J0IGludGVydmFsIC0gYVxuICogc3RvcmUgd2l0aG91dCB0aGUgY29uZmlnIHJlamVjdHMgZXZlcnkgd3JpdGUgYWltZWQgYXQgaXQsIHNvIHRoaXMgbm90IGxhbmRpbmcgaXMgYSBiaWcgZGVhbCxcbiAqIGxvZ2dlZCBvbiBldmVyeSBhdHRlbXB0IC0gYW5kIGV2ZW4gc3VjY2VzcyByZXBlYXRlZCBob3VybHksIGluIGNhc2UgYSBzdG9yZSBsb3N0IGl0LiBUaGUgZmFpbHVyZVxuICogdGhpcyBleGlzdHMgZm9yOiBhIHNlcnZlciB3aG9zZSB0cnVzdCB3YXMgb25seSBncmFudGVkIEFGVEVSIHN0YXJ0dXAsIHNvIHRoZSBzdGFydHVwIHdyaXRlIHdhc1xuICogcmVqZWN0ZWQgYW5kIG5vdGhpbmcgZWxzZSB3b3VsZCBldmVyIHJldHJ5IGl0LlxuICovXG5leHBvcnQgY2xhc3MgUm91dGluZ1Jld3JpdGVMb29wIHtcbiAgICBjb25zdHJ1Y3Rvcihwcml2YXRlIGNvbmZpZzoge1xuICAgICAgICBjb25maWd1cmVkOiBSZW1vdGVDb25maWc7XG4gICAgICAgIGRlYnVnTmFtZTogKCkgPT4gc3RyaW5nO1xuICAgICAgICAvKiogVGhlIGNoYWluJ3MgbmV3ZXN0IGFkb3B0ZWQgc3RhdGU6IHdoYXQgZGVjaWRlcyB3aGV0aGVyIG91cnMgaXMgc3RpbGwgdGhlIGNvbmZpZyB0byB3cml0ZSwgYW5kIHRoZSBzb3VyY2VzIGl0IGlzIHdyaXR0ZW4gdGhyb3VnaC4gVW5kZWZpbmVkIHVudGlsIHRoZSBmaXJzdCBpbml0IGZpbmlzaGVzLiAqL1xuICAgICAgICBsYXRlc3Q6ICgpID0+IHsgY29uZmlnOiBSZW1vdGVDb25maWc7IHNvdXJjZXM6IFNvdXJjZVdyYXBwZXJbXSB9IHwgdW5kZWZpbmVkO1xuICAgIH0pIHsgfVxuXG4gICAgcHJpdmF0ZSB0aW1lcjogUmV0dXJuVHlwZTx0eXBlb2Ygc2V0VGltZW91dD4gfCB1bmRlZmluZWQ7XG4gICAgcHJpdmF0ZSBkaXNwb3NlZCA9IGZhbHNlO1xuXG4gICAgLyoqIChSZSlhcm1zIHRoZSBsb29wIC0gY2FsbGVkIGF0IHRoZSBlbmQgb2YgZXZlcnkgaW5pdCwgd2l0aCB3aGV0aGVyIHRoYXQgaW5pdCdzIHdyaXRlIGZhaWxlZCAod2hpY2ggcGlja3MgdGhlIHNob3J0IHJldHJ5IGludGVydmFsKS4gKi9cbiAgICBwdWJsaWMgc3RhcnQoZmFpbGVkQXRTdGFydHVwOiBib29sZWFuKTogdm9pZCB7XG4gICAgICAgIHRoaXMuc2NoZWR1bGUoZmFpbGVkQXRTdGFydHVwICYmIENPTkZJR19XUklURV9SRVRSWV9JTlRFUlZBTCB8fCBDT05GSUdfV1JJVEVfUkVGUkVTSF9JTlRFUlZBTCk7XG4gICAgfVxuXG4gICAgcHVibGljIGRpc3Bvc2UoKTogdm9pZCB7XG4gICAgICAgIHRoaXMuZGlzcG9zZWQgPSB0cnVlO1xuICAgICAgICBpZiAodGhpcy50aW1lcikge1xuICAgICAgICAgICAgY2xlYXJUaW1lb3V0KHRoaXMudGltZXIpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBzY2hlZHVsZShkZWxheTogbnVtYmVyKTogdm9pZCB7XG4gICAgICAgIGlmICh0aGlzLmRpc3Bvc2VkKSByZXR1cm47XG4gICAgICAgIGlmICh0aGlzLnRpbWVyKSB7XG4gICAgICAgICAgICBjbGVhclRpbWVvdXQodGhpcy50aW1lcik7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy50aW1lciA9IHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy50aW1lciA9IHVuZGVmaW5lZDtcbiAgICAgICAgICAgIHZvaWQgdGhpcy5yZXdyaXRlKCkuY2F0Y2goKGU6IEVycm9yKSA9PiB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihgUmV3cml0aW5nIHRoZSBzdG9yYWdlIHJvdXRpbmcgY29uZmlnIGZvciAke3RoaXMuY29uZmlnLmRlYnVnTmFtZSgpfSBmYWlsZWQ6ICR7ZS5zdGFjayA/PyBlfWApO1xuICAgICAgICAgICAgICAgIHRoaXMuc2NoZWR1bGUoQ09ORklHX1dSSVRFX1JFVFJZX0lOVEVSVkFMKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9LCBkZWxheSk7XG4gICAgICAgICh0aGlzLnRpbWVyIGFzIHsgdW5yZWY/OiAoKSA9PiB2b2lkIH0pLnVucmVmPy4oKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIHJld3JpdGUoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGlmICh0aGlzLmRpc3Bvc2VkKSByZXR1cm47XG4gICAgICAgIGxldCBjb25maWd1cmVkID0gdGhpcy5jb25maWcuY29uZmlndXJlZDtcbiAgICAgICAgbGV0IHN0YXRlID0gdGhpcy5jb25maWcubGF0ZXN0KCk7XG4gICAgICAgIGlmICghc3RhdGUpIHtcbiAgICAgICAgICAgIHRoaXMuc2NoZWR1bGUoQ09ORklHX1dSSVRFX1JFVFJZX0lOVEVSVkFMKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICAvLyBUaGUgYnVja2V0IGFkb3B0ZWQgYSBORVdFUiBjb25maWcgdGhhbiBvdXIgaW4tY29kZSBvbmUsIHNvIG91cnMgaXMgc3RhbGUgYW5kIGV2ZXJ5IHN0b3JlIHdvdWxkIChyaWdodGx5KSByZWZ1c2UgaXRcbiAgICAgICAgaWYgKGdldENvbmZpZ1ZlcnNpb24oc3RhdGUuY29uZmlnKSA+IGdldENvbmZpZ1ZlcnNpb24oY29uZmlndXJlZCkpIHtcbiAgICAgICAgICAgIHRoaXMuc2NoZWR1bGUoQ09ORklHX1dSSVRFX1JFRlJFU0hfSU5URVJWQUwpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIC8vIFNhbWUgdmVyc2lvbiBidXQgZGlmZmVyZW50IGNvbnRlbnQ6IHN0YXJ0dXAgYWxyZWFkeSBkZWNpZGVkIHRoZSBzdG9yZWQgb25lIHdpbnMgdW50aWwgdGhlIHZlcnNpb24gaXMgYnVtcGVkIChzZWUgY2hvb3NlU3RhcnR1cENvbmZpZyksIGFuZCByZS13cml0aW5nIG91cnMgd291bGQgZmxpcCB0aGUgYnVja2V0IGJhY2sgYW5kIGZvcnRoIGJldHdlZW4gdGhlIHR3b1xuICAgICAgICBpZiAoZ2V0Q29uZmlnVmVyc2lvbihzdGF0ZS5jb25maWcpID09PSBnZXRDb25maWdWZXJzaW9uKGNvbmZpZ3VyZWQpICYmIEpTT04uc3RyaW5naWZ5KHN0YXRlLmNvbmZpZykgIT09IEpTT04uc3RyaW5naWZ5KGNvbmZpZ3VyZWQpKSB7XG4gICAgICAgICAgICB0aGlzLnNjaGVkdWxlKENPTkZJR19XUklURV9SRUZSRVNIX0lOVEVSVkFMKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBsZXQgeyBmYWlsdXJlcywgdG90YWwgfSA9IGF3YWl0IHdyaXRlUm91dGluZ1RvQWxsU3RvcmVzKHsgY29uZmlndXJlZCwgc291cmNlczogc3RhdGUuc291cmNlcywgZGVidWdOYW1lOiB0aGlzLmNvbmZpZy5kZWJ1Z05hbWUoKSB9KTtcbiAgICAgICAgaWYgKGZhaWx1cmVzLmxlbmd0aCkge1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcihgVGhlIHBlcmlvZGljIHJvdXRpbmcgY29uZmlnIHdyaXRlIGZvciAke3RoaXMuY29uZmlnLmRlYnVnTmFtZSgpfSAodmVyc2lvbiAke2dldENvbmZpZ1ZlcnNpb24oY29uZmlndXJlZCl9KSBmYWlsZWQgb24gJHtmYWlsdXJlcy5sZW5ndGh9IG9mICR7dG90YWx9IHN0b3JlcyAtIHJldHJ5aW5nIGluICR7Q09ORklHX1dSSVRFX1JFVFJZX0lOVEVSVkFMIC8gMTAwMH1zOiAke2ZhaWx1cmVzLmpvaW4oXCIgfCBcIil9YCk7XG4gICAgICAgICAgICB0aGlzLnNjaGVkdWxlKENPTkZJR19XUklURV9SRVRSWV9JTlRFUlZBTCk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5zY2hlZHVsZShDT05GSUdfV1JJVEVfUkVGUkVTSF9JTlRFUlZBTCk7XG4gICAgfVxufVxuIl19
|
|
466
|
+
/* _JS_SOURCE_HASH = "d36ce7c1c47d19c7a2c75d2ec689971b811cf13f66d47cb04f742490229aa5d8"; */
|