@discordeno/gateway 19.0.0 → 20.0.0-next.3fd075a
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/dist/cjs/Shard.cjs +666 -0
- package/dist/cjs/index.cjs +22 -0
- package/dist/cjs/manager.cjs +513 -0
- package/dist/cjs/types.cjs +64 -0
- package/dist/esm/Shard.js +28 -11
- package/dist/esm/manager.js +14 -4
- package/dist/types/Shard.d.ts +14 -7
- package/dist/types/Shard.d.ts.map +1 -1
- package/dist/types/manager.d.ts +1 -1
- package/dist/types/manager.d.ts.map +1 -1
- package/package.json +7 -7
|
@@ -0,0 +1,513 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "createGatewayManager", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return createGatewayManager;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _nodecrypto = require("node:crypto");
|
|
12
|
+
const _types = require("@discordeno/types");
|
|
13
|
+
const _utils = require("@discordeno/utils");
|
|
14
|
+
const _Shard = /*#__PURE__*/ _interop_require_default(require("./Shard.cjs"));
|
|
15
|
+
const _types1 = require("./types.cjs");
|
|
16
|
+
function _interop_require_default(obj) {
|
|
17
|
+
return obj && obj.__esModule ? obj : {
|
|
18
|
+
default: obj
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function createGatewayManager(options) {
|
|
22
|
+
const connectionOptions = options.connection ?? {
|
|
23
|
+
url: 'wss://gateway.discord.gg',
|
|
24
|
+
shards: 1,
|
|
25
|
+
sessionStartLimit: {
|
|
26
|
+
maxConcurrency: 1,
|
|
27
|
+
remaining: 1000,
|
|
28
|
+
total: 1000,
|
|
29
|
+
resetAfter: 1000 * 60 * 60 * 24
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
const gateway = {
|
|
33
|
+
events: options.events ?? {},
|
|
34
|
+
compress: options.compress ?? false,
|
|
35
|
+
transportCompression: options.transportCompression ?? null,
|
|
36
|
+
intents: options.intents ?? 0,
|
|
37
|
+
properties: {
|
|
38
|
+
os: options.properties?.os ?? process.platform,
|
|
39
|
+
browser: options.properties?.browser ?? 'Discordeno',
|
|
40
|
+
device: options.properties?.device ?? 'Discordeno'
|
|
41
|
+
},
|
|
42
|
+
token: options.token,
|
|
43
|
+
url: options.url ?? connectionOptions.url ?? 'wss://gateway.discord.gg',
|
|
44
|
+
version: options.version ?? 10,
|
|
45
|
+
connection: connectionOptions,
|
|
46
|
+
totalShards: options.totalShards ?? connectionOptions.shards ?? 1,
|
|
47
|
+
lastShardId: options.lastShardId ?? (options.totalShards ? options.totalShards - 1 : connectionOptions ? connectionOptions.shards - 1 : 0),
|
|
48
|
+
firstShardId: options.firstShardId ?? 0,
|
|
49
|
+
totalWorkers: options.totalWorkers ?? 4,
|
|
50
|
+
shardsPerWorker: options.shardsPerWorker ?? 25,
|
|
51
|
+
spawnShardDelay: options.spawnShardDelay ?? 5300,
|
|
52
|
+
preferSnakeCase: options.preferSnakeCase ?? false,
|
|
53
|
+
shards: new Map(),
|
|
54
|
+
buckets: new Map(),
|
|
55
|
+
cache: {
|
|
56
|
+
requestMembers: {
|
|
57
|
+
enabled: options.cache?.requestMembers?.enabled ?? false,
|
|
58
|
+
pending: new _utils.Collection()
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
logger: options.logger ?? _utils.logger,
|
|
62
|
+
makePresence: options.makePresence ?? (()=>Promise.resolve(undefined)),
|
|
63
|
+
resharding: {
|
|
64
|
+
enabled: options.resharding?.enabled ?? true,
|
|
65
|
+
shardsFullPercentage: options.resharding?.shardsFullPercentage ?? 80,
|
|
66
|
+
checkInterval: options.resharding?.checkInterval ?? 28800000,
|
|
67
|
+
shards: new _utils.Collection(),
|
|
68
|
+
pendingShards: new _utils.Collection(),
|
|
69
|
+
getSessionInfo: options.resharding?.getSessionInfo,
|
|
70
|
+
updateGuildsShardId: options.resharding?.updateGuildsShardId,
|
|
71
|
+
async checkIfReshardingIsNeeded () {
|
|
72
|
+
gateway.logger.debug('[Resharding] Checking if resharding is needed.');
|
|
73
|
+
if (!gateway.resharding.enabled) {
|
|
74
|
+
gateway.logger.debug('[Resharding] Resharding is disabled.');
|
|
75
|
+
return {
|
|
76
|
+
needed: false
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
if (!gateway.resharding.getSessionInfo) {
|
|
80
|
+
throw new Error("[Resharding] Resharding is enabled but no 'resharding.getSessionInfo()' is not provided.");
|
|
81
|
+
}
|
|
82
|
+
gateway.logger.debug('[Resharding] Resharding is enabled.');
|
|
83
|
+
const sessionInfo = await gateway.resharding.getSessionInfo();
|
|
84
|
+
gateway.logger.debug(`[Resharding] Session info retrieved: ${JSON.stringify(sessionInfo)}`);
|
|
85
|
+
// Don't have enough identify limits to try resharding
|
|
86
|
+
if (sessionInfo.sessionStartLimit.remaining < sessionInfo.shards) {
|
|
87
|
+
gateway.logger.debug('[Resharding] Not enough session start limits left to reshard.');
|
|
88
|
+
return {
|
|
89
|
+
needed: false,
|
|
90
|
+
info: sessionInfo
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
gateway.logger.debug('[Resharding] Able to reshard, checking whether necessary now.');
|
|
94
|
+
// 2500 is the max amount of guilds a single shard can handle
|
|
95
|
+
// 1000 is the amount of guilds discord uses to determine how many shards to recommend.
|
|
96
|
+
// This algo helps check if your bot has grown enough to reshard.
|
|
97
|
+
// While this is imprecise as discord changes the recommended number of shard every 1000 guilds it is good enough
|
|
98
|
+
// The alternative is to store the guild count for each shard and require the Guilds intent for `GUILD_CREATE` and `GUILD_DELETE` events
|
|
99
|
+
const percentage = sessionInfo.shards / (gateway.totalShards * 2500 / 1000) * 100;
|
|
100
|
+
// Less than necessary% being used so do nothing
|
|
101
|
+
if (percentage < gateway.resharding.shardsFullPercentage) {
|
|
102
|
+
gateway.logger.debug('[Resharding] Resharding not needed.');
|
|
103
|
+
return {
|
|
104
|
+
needed: false,
|
|
105
|
+
info: sessionInfo
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
gateway.logger.info('[Resharding] Resharding is needed.');
|
|
109
|
+
return {
|
|
110
|
+
needed: true,
|
|
111
|
+
info: sessionInfo
|
|
112
|
+
};
|
|
113
|
+
},
|
|
114
|
+
async reshard (info) {
|
|
115
|
+
gateway.logger.info(`[Resharding] Starting the reshard process. Previous total shards: ${gateway.totalShards}`);
|
|
116
|
+
// Set values on gateway
|
|
117
|
+
gateway.totalShards = info.shards;
|
|
118
|
+
// Handles preparing mid sized bots for LBS
|
|
119
|
+
gateway.totalShards = gateway.calculateTotalShards();
|
|
120
|
+
// Set first shard id if provided in info
|
|
121
|
+
if (typeof info.firstShardId === 'number') gateway.firstShardId = info.firstShardId;
|
|
122
|
+
// Set last shard id if provided in info
|
|
123
|
+
if (typeof info.lastShardId === 'number') gateway.lastShardId = info.lastShardId;
|
|
124
|
+
gateway.logger.info(`[Resharding] Starting the reshard process. New total shards: ${gateway.totalShards}`);
|
|
125
|
+
// Resetting buckets
|
|
126
|
+
gateway.buckets.clear();
|
|
127
|
+
// Refilling buckets with new values
|
|
128
|
+
gateway.prepareBuckets();
|
|
129
|
+
// SPREAD THIS OUT TO DIFFERENT WORKERS TO BEGIN STARTING UP
|
|
130
|
+
gateway.buckets.forEach(async (bucket, bucketId)=>{
|
|
131
|
+
for (const worker of bucket.workers){
|
|
132
|
+
for (const shardId of worker.queue){
|
|
133
|
+
await gateway.resharding.tellWorkerToPrepare(worker.id, shardId, bucketId);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
},
|
|
138
|
+
async tellWorkerToPrepare (workerId, shardId, bucketId) {
|
|
139
|
+
gateway.logger.debug(`[Resharding] Telling worker to prepare. Worker: ${workerId} | Shard: ${shardId} | Bucket: ${bucketId}.`);
|
|
140
|
+
const shard = new _Shard.default({
|
|
141
|
+
id: shardId,
|
|
142
|
+
connection: {
|
|
143
|
+
compress: gateway.compress,
|
|
144
|
+
transportCompression: gateway.transportCompression ?? null,
|
|
145
|
+
intents: gateway.intents,
|
|
146
|
+
properties: gateway.properties,
|
|
147
|
+
token: gateway.token,
|
|
148
|
+
totalShards: gateway.totalShards,
|
|
149
|
+
url: gateway.url,
|
|
150
|
+
version: gateway.version
|
|
151
|
+
},
|
|
152
|
+
// Ignore events until we are ready
|
|
153
|
+
events: {
|
|
154
|
+
async message (_shard, payload) {
|
|
155
|
+
if (payload.t === 'READY') {
|
|
156
|
+
await gateway.resharding.updateGuildsShardId?.(payload.d.guilds.map((g)=>g.id), shardId);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
logger: gateway.logger,
|
|
161
|
+
requestIdentify: async ()=>{
|
|
162
|
+
await gateway.identify(shardId);
|
|
163
|
+
},
|
|
164
|
+
shardIsReady: async ()=>{
|
|
165
|
+
gateway.logger.debug(`[Shard] Shard #${shardId} is ready`);
|
|
166
|
+
await (0, _utils.delay)(gateway.spawnShardDelay);
|
|
167
|
+
gateway.logger.debug(`[Shard] Resolving shard identify request`);
|
|
168
|
+
gateway.buckets.get(shardId % gateway.connection.sessionStartLimit.maxConcurrency).identifyRequests.shift()?.();
|
|
169
|
+
},
|
|
170
|
+
makePresence: gateway.makePresence
|
|
171
|
+
});
|
|
172
|
+
if (gateway.preferSnakeCase) {
|
|
173
|
+
shard.forwardToBot = async (payload)=>{
|
|
174
|
+
shard.events?.message?.(shard, payload);
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
gateway.resharding.shards.set(shardId, shard);
|
|
178
|
+
const bucket = gateway.buckets.get(shardId % gateway.connection.sessionStartLimit.maxConcurrency);
|
|
179
|
+
if (!bucket) return;
|
|
180
|
+
return await new Promise((resolve)=>{
|
|
181
|
+
// Mark that we are making an identify request so another is not made.
|
|
182
|
+
bucket.identifyRequests.push(resolve);
|
|
183
|
+
gateway.logger.debug(`[Gateway] Identifying Shard #${shardId}.`);
|
|
184
|
+
// This will trigger identify and when READY is received it will resolve the above request.
|
|
185
|
+
shard?.identify().then(async ()=>{
|
|
186
|
+
// Tell the manager that this shard is online
|
|
187
|
+
return await gateway.resharding.shardIsPending(shard);
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
},
|
|
191
|
+
async shardIsPending (shard) {
|
|
192
|
+
// Save this in pending at the moment, until all shards are online
|
|
193
|
+
gateway.resharding.pendingShards.set(shard.id, shard);
|
|
194
|
+
gateway.logger.debug(`[Resharding] Shard #${shard.id} is now pending.`);
|
|
195
|
+
// Check if all shards are now online.
|
|
196
|
+
if (gateway.lastShardId - gateway.firstShardId >= gateway.resharding.pendingShards.size) return;
|
|
197
|
+
gateway.logger.info(`[Resharding] All shards are now online.`);
|
|
198
|
+
// New shards start processing events
|
|
199
|
+
for (const shard of gateway.resharding.shards.values()){
|
|
200
|
+
for(const event in options.events){
|
|
201
|
+
shard.events[event] = options.events[event];
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
// Old shards stop processing events
|
|
205
|
+
for (const shard of gateway.shards.values()){
|
|
206
|
+
const oldHandler = shard.events.message;
|
|
207
|
+
// Change with spread operator to not affect new shards, as changing anything on shard.events will directly change options.events, which changes new shards' events
|
|
208
|
+
shard.events = {
|
|
209
|
+
...shard.events,
|
|
210
|
+
message: async function(_, message) {
|
|
211
|
+
// Member checks need to continue but others can stop
|
|
212
|
+
if (message.t === 'GUILD_MEMBERS_CHUNK') {
|
|
213
|
+
oldHandler?.(shard, message);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
gateway.logger.info(`[Resharding] Shutting down old shards.`);
|
|
219
|
+
// Close old shards
|
|
220
|
+
await gateway.shutdown(_types1.ShardSocketCloseCodes.Resharded, 'Resharded!', false);
|
|
221
|
+
gateway.logger.info(`[Resharding] Completed.`);
|
|
222
|
+
// Replace old shards
|
|
223
|
+
gateway.shards = new _utils.Collection(gateway.resharding.shards);
|
|
224
|
+
// Clear our collections and keep only one reference to the shards, the one in gateway.shards
|
|
225
|
+
gateway.resharding.shards.clear();
|
|
226
|
+
gateway.resharding.pendingShards.clear();
|
|
227
|
+
}
|
|
228
|
+
},
|
|
229
|
+
calculateTotalShards () {
|
|
230
|
+
// Bots under 100k servers do not have access to LBS.
|
|
231
|
+
if (gateway.totalShards < 100) {
|
|
232
|
+
gateway.logger.debug(`[Gateway] Calculating total shards: ${gateway.totalShards}`);
|
|
233
|
+
return gateway.totalShards;
|
|
234
|
+
}
|
|
235
|
+
gateway.logger.debug(`[Gateway] Calculating total shards`, gateway.totalShards, gateway.connection.sessionStartLimit.maxConcurrency);
|
|
236
|
+
// Calculate a multiple of `maxConcurrency` which can be used to connect to the gateway.
|
|
237
|
+
return Math.ceil(gateway.totalShards / // If `maxConcurrency` is 1, we can safely use 16 to get `totalShards` to be in a multiple of 16 so that we can prepare bots with 100k servers for LBS.
|
|
238
|
+
(gateway.connection.sessionStartLimit.maxConcurrency === 1 ? 16 : gateway.connection.sessionStartLimit.maxConcurrency)) * (gateway.connection.sessionStartLimit.maxConcurrency === 1 ? 16 : gateway.connection.sessionStartLimit.maxConcurrency);
|
|
239
|
+
},
|
|
240
|
+
calculateWorkerId (shardId) {
|
|
241
|
+
const workerId = Math.min(shardId % gateway.shardsPerWorker, gateway.totalWorkers - 1);
|
|
242
|
+
gateway.logger.debug(`[Gateway] Calculating workerId: Shard: ${shardId} -> Worker: ${workerId} -> Per Worker: ${gateway.shardsPerWorker} -> Total: ${gateway.totalWorkers}`);
|
|
243
|
+
return workerId;
|
|
244
|
+
},
|
|
245
|
+
prepareBuckets () {
|
|
246
|
+
for(let i = 0; i < gateway.connection.sessionStartLimit.maxConcurrency; ++i){
|
|
247
|
+
gateway.logger.debug(`[Gateway] Preparing buckets for concurrency: ${i}`);
|
|
248
|
+
gateway.buckets.set(i, {
|
|
249
|
+
workers: [],
|
|
250
|
+
identifyRequests: []
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
// ORGANIZE ALL SHARDS INTO THEIR OWN BUCKETS
|
|
254
|
+
for(let shardId = gateway.firstShardId; shardId <= gateway.lastShardId; ++shardId){
|
|
255
|
+
gateway.logger.debug(`[Gateway] Preparing buckets for shard: ${shardId}`);
|
|
256
|
+
if (shardId >= gateway.totalShards) {
|
|
257
|
+
throw new Error(`Shard (id: ${shardId}) is bigger or equal to the used amount of used shards which is ${gateway.totalShards}`);
|
|
258
|
+
}
|
|
259
|
+
const bucketId = shardId % gateway.connection.sessionStartLimit.maxConcurrency;
|
|
260
|
+
const bucket = gateway.buckets.get(bucketId);
|
|
261
|
+
if (!bucket) {
|
|
262
|
+
throw new Error(`Shard (id: ${shardId}) got assigned to an illegal bucket id: ${bucketId}, expected a bucket id between 0 and ${gateway.connection.sessionStartLimit.maxConcurrency - 1}`);
|
|
263
|
+
}
|
|
264
|
+
// FIND A QUEUE IN THIS BUCKET THAT HAS SPACE
|
|
265
|
+
// const worker = bucket.workers.find((w) => w.queue.length < gateway.shardsPerWorker);
|
|
266
|
+
const workerId = gateway.calculateWorkerId(shardId);
|
|
267
|
+
const worker = bucket.workers.find((w)=>w.id === workerId);
|
|
268
|
+
if (worker) {
|
|
269
|
+
// IF THE QUEUE HAS SPACE JUST ADD IT TO THIS QUEUE
|
|
270
|
+
worker.queue.push(shardId);
|
|
271
|
+
} else {
|
|
272
|
+
bucket.workers.push({
|
|
273
|
+
id: workerId,
|
|
274
|
+
queue: [
|
|
275
|
+
shardId
|
|
276
|
+
]
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
for (const bucket of gateway.buckets.values()){
|
|
281
|
+
for (const worker of bucket.workers.values()){
|
|
282
|
+
worker.queue = worker.queue.sort((a, b)=>a - b);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
},
|
|
286
|
+
async spawnShards () {
|
|
287
|
+
// PREPARES ALL SHARDS IN SPECIFIC BUCKETS
|
|
288
|
+
gateway.prepareBuckets();
|
|
289
|
+
// Prefer concurrency of forEach instead of forof
|
|
290
|
+
await Promise.all([
|
|
291
|
+
...gateway.buckets.entries()
|
|
292
|
+
].map(async ([bucketId, bucket])=>{
|
|
293
|
+
for (const worker of bucket.workers){
|
|
294
|
+
for (const shardId of worker.queue){
|
|
295
|
+
await gateway.tellWorkerToIdentify(worker.id, shardId, bucketId);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}));
|
|
299
|
+
// Check and reshard automatically if auto resharding is enabled.
|
|
300
|
+
if (gateway.resharding.enabled && gateway.resharding.checkInterval !== -1) {
|
|
301
|
+
// It is better to ensure there is always only one
|
|
302
|
+
clearInterval(gateway.resharding.checkIntervalId);
|
|
303
|
+
if (!gateway.resharding.getSessionInfo) {
|
|
304
|
+
gateway.resharding.enabled = false;
|
|
305
|
+
gateway.logger.warn("[Resharding] Resharding is enabled but 'resharding.getSessionInfo()' was not provided. Disabling resharding.");
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
gateway.resharding.checkIntervalId = setInterval(async ()=>{
|
|
309
|
+
const reshardingInfo = await gateway.resharding.checkIfReshardingIsNeeded();
|
|
310
|
+
if (reshardingInfo.needed && reshardingInfo.info) await gateway.resharding.reshard(reshardingInfo.info);
|
|
311
|
+
}, gateway.resharding.checkInterval);
|
|
312
|
+
}
|
|
313
|
+
},
|
|
314
|
+
async shutdown (code, reason, clearReshardingInterval = true) {
|
|
315
|
+
if (clearReshardingInterval) clearInterval(gateway.resharding.checkIntervalId);
|
|
316
|
+
await Promise.all(Array.from(gateway.shards.values()).map((shard)=>shard.close(code, reason)));
|
|
317
|
+
},
|
|
318
|
+
async sendPayload (shardId, payload) {
|
|
319
|
+
const shard = gateway.shards.get(shardId);
|
|
320
|
+
if (!shard) {
|
|
321
|
+
throw new Error(`Shard (id: ${shardId} not found`);
|
|
322
|
+
}
|
|
323
|
+
await shard.send(payload);
|
|
324
|
+
},
|
|
325
|
+
async tellWorkerToIdentify (workerId, shardId, bucketId) {
|
|
326
|
+
gateway.logger.debug(`[Gateway] Tell worker to identify (${workerId}, ${shardId}, ${bucketId})`);
|
|
327
|
+
await gateway.identify(shardId);
|
|
328
|
+
},
|
|
329
|
+
async identify (shardId) {
|
|
330
|
+
let shard = this.shards.get(shardId);
|
|
331
|
+
gateway.logger.debug(`[Gateway] Identifying ${shard ? 'existing' : 'new'} shard (${shardId})`);
|
|
332
|
+
if (!shard) {
|
|
333
|
+
shard = new _Shard.default({
|
|
334
|
+
id: shardId,
|
|
335
|
+
connection: {
|
|
336
|
+
compress: this.compress,
|
|
337
|
+
transportCompression: gateway.transportCompression,
|
|
338
|
+
intents: this.intents,
|
|
339
|
+
properties: this.properties,
|
|
340
|
+
token: this.token,
|
|
341
|
+
totalShards: this.totalShards,
|
|
342
|
+
url: this.url,
|
|
343
|
+
version: this.version
|
|
344
|
+
},
|
|
345
|
+
events: options.events ?? {},
|
|
346
|
+
logger: this.logger,
|
|
347
|
+
requestIdentify: async ()=>{
|
|
348
|
+
await gateway.identify(shardId);
|
|
349
|
+
},
|
|
350
|
+
shardIsReady: async ()=>{
|
|
351
|
+
gateway.logger.debug(`[Shard] Shard #${shardId} is ready`);
|
|
352
|
+
await (0, _utils.delay)(gateway.spawnShardDelay);
|
|
353
|
+
gateway.logger.debug(`[Shard] Resolving shard identify request`);
|
|
354
|
+
gateway.buckets.get(shardId % gateway.connection.sessionStartLimit.maxConcurrency).identifyRequests.shift()?.();
|
|
355
|
+
},
|
|
356
|
+
makePresence: gateway.makePresence
|
|
357
|
+
});
|
|
358
|
+
if (this.preferSnakeCase) {
|
|
359
|
+
shard.forwardToBot = async (payload)=>{
|
|
360
|
+
shard.events.message?.(shard, payload);
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
this.shards.set(shardId, shard);
|
|
364
|
+
}
|
|
365
|
+
const bucket = gateway.buckets.get(shardId % gateway.connection.sessionStartLimit.maxConcurrency);
|
|
366
|
+
if (!bucket) return;
|
|
367
|
+
return await new Promise((resolve)=>{
|
|
368
|
+
// Mark that we are making an identify request so another is not made.
|
|
369
|
+
bucket.identifyRequests.push(resolve);
|
|
370
|
+
gateway.logger.debug(`[Gateway] Identifying Shard #${shardId}.`);
|
|
371
|
+
// This will trigger identify and when READY is received it will resolve the above request.
|
|
372
|
+
shard?.identify();
|
|
373
|
+
});
|
|
374
|
+
},
|
|
375
|
+
async kill (shardId) {
|
|
376
|
+
const shard = this.shards.get(shardId);
|
|
377
|
+
if (!shard) {
|
|
378
|
+
return gateway.logger.debug(`[Gateway] A kill for Shard #${shardId} was requested, but the shard could not be found`);
|
|
379
|
+
}
|
|
380
|
+
gateway.logger.debug(`[Gateway] Killing Shard #${shardId}`);
|
|
381
|
+
this.shards.delete(shardId);
|
|
382
|
+
await shard.shutdown();
|
|
383
|
+
},
|
|
384
|
+
async requestIdentify (_shardId) {
|
|
385
|
+
gateway.logger.debug(`[Gateway] Requesting identify`);
|
|
386
|
+
},
|
|
387
|
+
// Helpers methods below this
|
|
388
|
+
calculateShardId (guildId, totalShards) {
|
|
389
|
+
// If none is provided, use the total shards number from gateway object.
|
|
390
|
+
if (!totalShards) totalShards = gateway.totalShards;
|
|
391
|
+
// If it is only 1 shard, it will always be shard id 0
|
|
392
|
+
if (totalShards === 1) {
|
|
393
|
+
gateway.logger.debug(`[Gateway] calculateShardId (1 shard)`);
|
|
394
|
+
return 0;
|
|
395
|
+
}
|
|
396
|
+
gateway.logger.debug(`[Gateway] calculateShardId (guildId: ${guildId}, totalShards: ${totalShards})`);
|
|
397
|
+
return Number((BigInt(guildId) >> 22n) % BigInt(totalShards));
|
|
398
|
+
},
|
|
399
|
+
async joinVoiceChannel (guildId, channelId, options) {
|
|
400
|
+
const shardId = gateway.calculateShardId(guildId);
|
|
401
|
+
gateway.logger.debug(`[Gateway] joinVoiceChannel guildId: ${guildId} channelId: ${channelId}`);
|
|
402
|
+
await gateway.sendPayload(shardId, {
|
|
403
|
+
op: _types.GatewayOpcodes.VoiceStateUpdate,
|
|
404
|
+
d: {
|
|
405
|
+
guild_id: guildId.toString(),
|
|
406
|
+
channel_id: channelId.toString(),
|
|
407
|
+
self_mute: options?.selfMute ?? false,
|
|
408
|
+
self_deaf: options?.selfDeaf ?? true
|
|
409
|
+
}
|
|
410
|
+
});
|
|
411
|
+
},
|
|
412
|
+
async editBotStatus (data) {
|
|
413
|
+
gateway.logger.debug(`[Gateway] editBotStatus data: ${JSON.stringify(data)}`);
|
|
414
|
+
await Promise.all([
|
|
415
|
+
...gateway.shards.values()
|
|
416
|
+
].map(async (shard)=>{
|
|
417
|
+
gateway.editShardStatus(shard.id, data);
|
|
418
|
+
}));
|
|
419
|
+
},
|
|
420
|
+
async editShardStatus (shardId, data) {
|
|
421
|
+
gateway.logger.debug(`[Gateway] editShardStatus shardId: ${shardId} -> data: ${JSON.stringify(data)}`);
|
|
422
|
+
await gateway.sendPayload(shardId, {
|
|
423
|
+
op: _types.GatewayOpcodes.PresenceUpdate,
|
|
424
|
+
d: {
|
|
425
|
+
since: null,
|
|
426
|
+
afk: false,
|
|
427
|
+
activities: data.activities,
|
|
428
|
+
status: data.status
|
|
429
|
+
}
|
|
430
|
+
});
|
|
431
|
+
},
|
|
432
|
+
async requestMembers (guildId, options) {
|
|
433
|
+
const shardId = gateway.calculateShardId(guildId);
|
|
434
|
+
if (gateway.intents && (!options?.limit || options.limit > 1) && !(gateway.intents & _types.GatewayIntents.GuildMembers)) throw new Error('Cannot fetch more then 1 member without the GUILD_MEMBERS intent');
|
|
435
|
+
gateway.logger.debug(`[Gateway] requestMembers guildId: ${guildId} -> data: ${JSON.stringify(options)}`);
|
|
436
|
+
if (options?.userIds?.length) {
|
|
437
|
+
gateway.logger.debug(`[Gateway] requestMembers guildId: ${guildId} -> setting user limit based on userIds length: ${options.userIds.length}`);
|
|
438
|
+
options.limit = options.userIds.length;
|
|
439
|
+
}
|
|
440
|
+
if (!options?.nonce) {
|
|
441
|
+
let nonce = '';
|
|
442
|
+
while(!nonce || gateway.cache.requestMembers.pending.has(nonce)){
|
|
443
|
+
nonce = (0, _nodecrypto.randomBytes)(16).toString('hex');
|
|
444
|
+
}
|
|
445
|
+
options ??= {
|
|
446
|
+
limit: 0
|
|
447
|
+
};
|
|
448
|
+
options.nonce = nonce;
|
|
449
|
+
}
|
|
450
|
+
const members = !gateway.cache.requestMembers.enabled ? [] : new Promise((resolve, reject)=>{
|
|
451
|
+
// Should never happen.
|
|
452
|
+
if (!gateway.cache.requestMembers.enabled || !options?.nonce) {
|
|
453
|
+
reject(new Error("Can't request the members without the nonce or with the feature disabled."));
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
gateway.cache.requestMembers.pending.set(options.nonce, {
|
|
457
|
+
nonce: options.nonce,
|
|
458
|
+
resolve,
|
|
459
|
+
members: []
|
|
460
|
+
});
|
|
461
|
+
});
|
|
462
|
+
await gateway.sendPayload(shardId, {
|
|
463
|
+
op: _types.GatewayOpcodes.RequestGuildMembers,
|
|
464
|
+
d: {
|
|
465
|
+
guild_id: guildId.toString(),
|
|
466
|
+
// If a query is provided use it, OR if a limit is NOT provided use ""
|
|
467
|
+
query: options?.query ?? (options?.limit ? undefined : ''),
|
|
468
|
+
limit: options?.limit ?? 0,
|
|
469
|
+
presences: options?.presences ?? false,
|
|
470
|
+
user_ids: options?.userIds?.map((id)=>id.toString()),
|
|
471
|
+
nonce: options?.nonce
|
|
472
|
+
}
|
|
473
|
+
});
|
|
474
|
+
return await members;
|
|
475
|
+
},
|
|
476
|
+
async leaveVoiceChannel (guildId) {
|
|
477
|
+
const shardId = gateway.calculateShardId(guildId);
|
|
478
|
+
gateway.logger.debug(`[Gateway] leaveVoiceChannel guildId: ${guildId} Shard ${shardId}`);
|
|
479
|
+
await gateway.sendPayload(shardId, {
|
|
480
|
+
op: _types.GatewayOpcodes.VoiceStateUpdate,
|
|
481
|
+
d: {
|
|
482
|
+
guild_id: guildId.toString(),
|
|
483
|
+
channel_id: null,
|
|
484
|
+
self_mute: false,
|
|
485
|
+
self_deaf: false
|
|
486
|
+
}
|
|
487
|
+
});
|
|
488
|
+
},
|
|
489
|
+
async requestSoundboardSounds (guildIds) {
|
|
490
|
+
/**
|
|
491
|
+
* Discord will send the events for the guilds that are "under the shard" that sends the opcode.
|
|
492
|
+
* For this reason we need to group the ids with the shard the calculateShardId method gives
|
|
493
|
+
*/ const map = new Map();
|
|
494
|
+
for (const guildId of guildIds){
|
|
495
|
+
const shardId = gateway.calculateShardId(guildId);
|
|
496
|
+
const ids = map.get(shardId) ?? [];
|
|
497
|
+
map.set(shardId, ids);
|
|
498
|
+
ids.push(guildId);
|
|
499
|
+
}
|
|
500
|
+
await Promise.all([
|
|
501
|
+
...map.entries()
|
|
502
|
+
].map(([shardId, ids])=>gateway.sendPayload(shardId, {
|
|
503
|
+
op: _types.GatewayOpcodes.RequestSoundboardSounds,
|
|
504
|
+
d: {
|
|
505
|
+
guild_ids: ids
|
|
506
|
+
}
|
|
507
|
+
})));
|
|
508
|
+
}
|
|
509
|
+
};
|
|
510
|
+
return gateway;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9tYW5hZ2VyLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IHJhbmRvbUJ5dGVzIH0gZnJvbSAnbm9kZTpjcnlwdG8nXG5pbXBvcnQge1xuICB0eXBlIEF0TGVhc3RPbmUsXG4gIHR5cGUgQmlnU3RyaW5nLFxuICB0eXBlIENhbWVsaXplLFxuICB0eXBlIERpc2NvcmRHZXRHYXRld2F5Qm90LFxuICB0eXBlIERpc2NvcmRNZW1iZXJXaXRoVXNlcixcbiAgdHlwZSBEaXNjb3JkUmVhZHksXG4gIEdhdGV3YXlJbnRlbnRzLFxuICBHYXRld2F5T3Bjb2RlcyxcbiAgdHlwZSBSZXF1ZXN0R3VpbGRNZW1iZXJzLFxufSBmcm9tICdAZGlzY29yZGVuby90eXBlcydcbmltcG9ydCB7IENvbGxlY3Rpb24sIGRlbGF5LCBsb2dnZXIgfSBmcm9tICdAZGlzY29yZGVuby91dGlscydcbmltcG9ydCBTaGFyZCBmcm9tICcuL1NoYXJkLmpzJ1xuaW1wb3J0IHtcbiAgdHlwZSBCb3RTdGF0dXNVcGRhdGUsXG4gIHR5cGUgU2hhcmRFdmVudHMsXG4gIFNoYXJkU29ja2V0Q2xvc2VDb2RlcyxcbiAgdHlwZSBTaGFyZFNvY2tldFJlcXVlc3QsXG4gIHR5cGUgU3RhdHVzVXBkYXRlLFxuICB0eXBlIFRyYW5zcG9ydENvbXByZXNzaW9uLFxuICB0eXBlIFVwZGF0ZVZvaWNlU3RhdGUsXG59IGZyb20gJy4vdHlwZXMuanMnXG5cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVHYXRld2F5TWFuYWdlcihvcHRpb25zOiBDcmVhdGVHYXRld2F5TWFuYWdlck9wdGlvbnMpOiBHYXRld2F5TWFuYWdlciB7XG4gIGNvbnN0IGNvbm5lY3Rpb25PcHRpb25zID0gb3B0aW9ucy5jb25uZWN0aW9uID8/IHtcbiAgICB1cmw6ICd3c3M6Ly9nYXRld2F5LmRpc2NvcmQuZ2cnLFxuICAgIHNoYXJkczogMSxcbiAgICBzZXNzaW9uU3RhcnRMaW1pdDoge1xuICAgICAgbWF4Q29uY3VycmVuY3k6IDEsXG4gICAgICByZW1haW5pbmc6IDEwMDAsXG4gICAgICB0b3RhbDogMTAwMCxcbiAgICAgIHJlc2V0QWZ0ZXI6IDEwMDAgKiA2MCAqIDYwICogMjQsXG4gICAgfSxcbiAgfVxuXG4gIGNvbnN0IGdhdGV3YXk6IEdhdGV3YXlNYW5hZ2VyID0ge1xuICAgIGV2ZW50czogb3B0aW9ucy5ldmVudHMgPz8ge30sXG4gICAgY29tcHJlc3M6IG9wdGlvbnMuY29tcHJlc3MgPz8gZmFsc2UsXG4gICAgdHJhbnNwb3J0Q29tcHJlc3Npb246IG9wdGlvbnMudHJhbnNwb3J0Q29tcHJlc3Npb24gPz8gbnVsbCxcbiAgICBpbnRlbnRzOiBvcHRpb25zLmludGVudHMgPz8gMCxcbiAgICBwcm9wZXJ0aWVzOiB7XG4gICAgICBvczogb3B0aW9ucy5wcm9wZXJ0aWVzPy5vcyA/PyBwcm9jZXNzLnBsYXRmb3JtLFxuICAgICAgYnJvd3Nlcjogb3B0aW9ucy5wcm9wZXJ0aWVzPy5icm93c2VyID8/ICdEaXNjb3JkZW5vJyxcbiAgICAgIGRldmljZTogb3B0aW9ucy5wcm9wZXJ0aWVzPy5kZXZpY2UgPz8gJ0Rpc2NvcmRlbm8nLFxuICAgIH0sXG4gICAgdG9rZW46IG9wdGlvbnMudG9rZW4sXG4gICAgdXJsOiBvcHRpb25zLnVybCA/PyBjb25uZWN0aW9uT3B0aW9ucy51cmwgPz8gJ3dzczovL2dhdGV3YXkuZGlzY29yZC5nZycsXG4gICAgdmVyc2lvbjogb3B0aW9ucy52ZXJzaW9uID8/IDEwLFxuICAgIGNvbm5lY3Rpb246IGNvbm5lY3Rpb25PcHRpb25zLFxuICAgIHRvdGFsU2hhcmRzOiBvcHRpb25zLnRvdGFsU2hhcmRzID8/IGNvbm5lY3Rpb25PcHRpb25zLnNoYXJkcyA/PyAxLFxuICAgIGxhc3RTaGFyZElkOiBvcHRpb25zLmxhc3RTaGFyZElkID8/IChvcHRpb25zLnRvdGFsU2hhcmRzID8gb3B0aW9ucy50b3RhbFNoYXJkcyAtIDEgOiBjb25uZWN0aW9uT3B0aW9ucyA/IGNvbm5lY3Rpb25PcHRpb25zLnNoYXJkcyAtIDEgOiAwKSxcbiAgICBmaXJzdFNoYXJkSWQ6IG9wdGlvbnMuZmlyc3RTaGFyZElkID8/IDAsXG4gICAgdG90YWxXb3JrZXJzOiBvcHRpb25zLnRvdGFsV29ya2VycyA/PyA0LFxuICAgIHNoYXJkc1Blcldvcmtlcjogb3B0aW9ucy5zaGFyZHNQZXJXb3JrZXIgPz8gMjUsXG4gICAgc3Bhd25TaGFyZERlbGF5OiBvcHRpb25zLnNwYXduU2hhcmREZWxheSA/PyA1MzAwLFxuICAgIHByZWZlclNuYWtlQ2FzZTogb3B0aW9ucy5wcmVmZXJTbmFrZUNhc2UgPz8gZmFsc2UsXG4gICAgc2hhcmRzOiBuZXcgTWFwKCksXG4gICAgYnVja2V0czogbmV3IE1hcCgpLFxuICAgIGNhY2hlOiB7XG4gICAgICByZXF1ZXN0TWVtYmVyczoge1xuICAgICAgICBlbmFibGVkOiBvcHRpb25zLmNhY2hlPy5yZXF1ZXN0TWVtYmVycz8uZW5hYmxlZCA/PyBmYWxzZSxcbiAgICAgICAgcGVuZGluZzogbmV3IENvbGxlY3Rpb24oKSxcbiAgICAgIH0sXG4gICAgfSxcbiAgICBsb2dnZXI6IG9wdGlvbnMubG9nZ2VyID8/IGxvZ2dlcixcbiAgICBtYWtlUHJlc2VuY2U6IG9wdGlvbnMubWFrZVByZXNlbmNlID8/ICgoKSA9PiBQcm9taXNlLnJlc29sdmUodW5kZWZpbmVkKSksXG4gICAgcmVzaGFyZGluZzoge1xuICAgICAgZW5hYmxlZDogb3B0aW9ucy5yZXNoYXJkaW5nPy5lbmFibGVkID8/IHRydWUsXG4gICAgICBzaGFyZHNGdWxsUGVyY2VudGFnZTogb3B0aW9ucy5yZXNoYXJkaW5nPy5zaGFyZHNGdWxsUGVyY2VudGFnZSA/PyA4MCxcbiAgICAgIGNoZWNrSW50ZXJ2YWw6IG9wdGlvbnMucmVzaGFyZGluZz8uY2hlY2tJbnRlcnZhbCA/PyAyODgwMDAwMCwgLy8gOCBob3Vyc1xuICAgICAgc2hhcmRzOiBuZXcgQ29sbGVjdGlvbigpLFxuICAgICAgcGVuZGluZ1NoYXJkczogbmV3IENvbGxlY3Rpb24oKSxcbiAgICAgIGdldFNlc3Npb25JbmZvOiBvcHRpb25zLnJlc2hhcmRpbmc/LmdldFNlc3Npb25JbmZvLFxuICAgICAgdXBkYXRlR3VpbGRzU2hhcmRJZDogb3B0aW9ucy5yZXNoYXJkaW5nPy51cGRhdGVHdWlsZHNTaGFyZElkLFxuICAgICAgYXN5bmMgY2hlY2tJZlJlc2hhcmRpbmdJc05lZWRlZCgpIHtcbiAgICAgICAgZ2F0ZXdheS5sb2dnZXIuZGVidWcoJ1tSZXNoYXJkaW5nXSBDaGVja2luZyBpZiByZXNoYXJkaW5nIGlzIG5lZWRlZC4nKVxuXG4gICAgICAgIGlmICghZ2F0ZXdheS5yZXNoYXJkaW5nLmVuYWJsZWQpIHtcbiAgICAgICAgICBnYXRld2F5LmxvZ2dlci5kZWJ1ZygnW1Jlc2hhcmRpbmddIFJlc2hhcmRpbmcgaXMgZGlzYWJsZWQuJylcblxuICAgICAgICAgIHJldHVybiB7IG5lZWRlZDogZmFsc2UgfVxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCFnYXRld2F5LnJlc2hhcmRpbmcuZ2V0U2Vzc2lvbkluZm8pIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJbUmVzaGFyZGluZ10gUmVzaGFyZGluZyBpcyBlbmFibGVkIGJ1dCBubyAncmVzaGFyZGluZy5nZXRTZXNzaW9uSW5mbygpJyBpcyBub3QgcHJvdmlkZWQuXCIpXG4gICAgICAgIH1cblxuICAgICAgICBnYXRld2F5LmxvZ2dlci5kZWJ1ZygnW1Jlc2hhcmRpbmddIFJlc2hhcmRpbmcgaXMgZW5hYmxlZC4nKVxuXG4gICAgICAgIGNvbnN0IHNlc3Npb25JbmZvID0gYXdhaXQgZ2F0ZXdheS5yZXNoYXJkaW5nLmdldFNlc3Npb25JbmZvKClcblxuICAgICAgICBnYXRld2F5LmxvZ2dlci5kZWJ1ZyhgW1Jlc2hhcmRpbmddIFNlc3Npb24gaW5mbyByZXRyaWV2ZWQ6ICR7SlNPTi5zdHJpbmdpZnkoc2Vzc2lvbkluZm8pfWApXG5cbiAgICAgICAgLy8gRG9uJ3QgaGF2ZSBlbm91Z2ggaWRlbnRpZnkgbGltaXRzIHRvIHRyeSByZXNoYXJkaW5nXG4gICAgICAgIGlmIChzZXNzaW9uSW5mby5zZXNzaW9uU3RhcnRMaW1pdC5yZW1haW5pbmcgPCBzZXNzaW9uSW5mby5zaGFyZHMpIHtcbiAgICAgICAgICBnYXRld2F5LmxvZ2dlci5kZWJ1ZygnW1Jlc2hhcmRpbmddIE5vdCBlbm91Z2ggc2Vzc2lvbiBzdGFydCBsaW1pdHMgbGVmdCB0byByZXNoYXJkLicpXG5cbiAgICAgICAgICByZXR1cm4geyBuZWVkZWQ6IGZhbHNlLCBpbmZvOiBzZXNzaW9uSW5mbyB9XG4gICAgICAgIH1cblxuICAgICAgICBnYXRld2F5LmxvZ2dlci5kZWJ1ZygnW1Jlc2hhcmRpbmddIEFibGUgdG8gcmVzaGFyZCwgY2hlY2tpbmcgd2hldGhlciBuZWNlc3Nhcnkgbm93LicpXG5cbiAgICAgICAgLy8gMjUwMCBpcyB0aGUgbWF4IGFtb3VudCBvZiBndWlsZHMgYSBzaW5nbGUgc2hhcmQgY2FuIGhhbmRsZVxuICAgICAgICAvLyAxMDAwIGlzIHRoZSBhbW91bnQgb2YgZ3VpbGRzIGRpc2NvcmQgdXNlcyB0byBkZXRlcm1pbmUgaG93IG1hbnkgc2hhcmRzIHRvIHJlY29tbWVuZC5cbiAgICAgICAgLy8gVGhpcyBhbGdvIGhlbHBzIGNoZWNrIGlmIHlvdXIgYm90IGhhcyBncm93biBlbm91Z2ggdG8gcmVzaGFyZC5cbiAgICAgICAgLy8gV2hpbGUgdGhpcyBpcyBpbXByZWNpc2UgYXMgZGlzY29yZCBjaGFuZ2VzIHRoZSByZWNvbW1lbmRlZCBudW1iZXIgb2Ygc2hhcmQgZXZlcnkgMTAwMCBndWlsZHMgaXQgaXMgZ29vZCBlbm91Z2hcbiAgICAgICAgLy8gVGhlIGFsdGVybmF0aXZlIGlzIHRvIHN0b3JlIHRoZSBndWlsZCBjb3VudCBmb3IgZWFjaCBzaGFyZCBhbmQgcmVxdWlyZSB0aGUgR3VpbGRzIGludGVudCBmb3IgYEdVSUxEX0NSRUFURWAgYW5kIGBHVUlMRF9ERUxFVEVgIGV2ZW50c1xuICAgICAgICBjb25zdCBwZXJjZW50YWdlID0gKHNlc3Npb25JbmZvLnNoYXJkcyAvICgoZ2F0ZXdheS50b3RhbFNoYXJkcyAqIDI1MDApIC8gMTAwMCkpICogMTAwXG5cbiAgICAgICAgLy8gTGVzcyB0aGFuIG5lY2Vzc2FyeSUgYmVpbmcgdXNlZCBzbyBkbyBub3RoaW5nXG4gICAgICAgIGlmIChwZXJjZW50YWdlIDwgZ2F0ZXdheS5yZXNoYXJkaW5nLnNoYXJkc0Z1bGxQZXJjZW50YWdlKSB7XG4gICAgICAgICAgZ2F0ZXdheS5sb2dnZXIuZGVidWcoJ1tSZXNoYXJkaW5nXSBSZXNoYXJkaW5nIG5vdCBuZWVkZWQuJylcblxuICAgICAgICAgIHJldHVybiB7IG5lZWRlZDogZmFsc2UsIGluZm86IHNlc3Npb25JbmZvIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGdhdGV3YXkubG9nZ2VyLmluZm8oJ1tSZXNoYXJkaW5nXSBSZXNoYXJkaW5nIGlzIG5lZWRlZC4nKVxuXG4gICAgICAgIHJldHVybiB7IG5lZWRlZDogdHJ1ZSwgaW5mbzogc2Vzc2lvbkluZm8gfVxuICAgICAgfSxcbiAgICAgIGFzeW5jIHJlc2hhcmQoaW5mbykge1xuICAgICAgICBnYXRld2F5LmxvZ2dlci5pbmZvKGBbUmVzaGFyZGluZ10gU3RhcnRpbmcgdGhlIHJlc2hhcmQgcHJvY2Vzcy4gUHJldmlvdXMgdG90YWwgc2hhcmRzOiAke2dhdGV3YXkudG90YWxTaGFyZHN9YClcbiAgICAgICAgLy8gU2V0IHZhbHVlcyBvbiBnYXRld2F5XG4gICAgICAgIGdhdGV3YXkudG90YWxTaGFyZHMgPSBpbmZvLnNoYXJkc1xuICAgICAgICAvLyBIYW5kbGVzIHByZXBhcmluZyBtaWQgc2l6ZWQgYm90cyBmb3IgTEJTXG4gICAgICAgIGdhdGV3YXkudG90YWxTaGFyZHMgPSBnYXRld2F5LmNhbGN1bGF0ZVRvdGFsU2hhcmRzKClcbiAgICAgICAgLy8gU2V0IGZpcnN0IHNoYXJkIGlkIGlmIHByb3ZpZGVkIGluIGluZm9cbiAgICAgICAgaWYgKHR5cGVvZiBpbmZvLmZpcnN0U2hhcmRJZCA9PT0gJ251bWJlcicpIGdhdGV3YXkuZmlyc3RTaGFyZElkID0gaW5mby5maXJzdFNoYXJkSWRcbiAgICAgICAgLy8gU2V0IGxhc3Qgc2hhcmQgaWQgaWYgcHJvdmlkZWQgaW4gaW5mb1xuICAgICAgICBpZiAodHlwZW9mIGluZm8ubGFzdFNoYXJkSWQgPT09ICdudW1iZXInKSBnYXRld2F5Lmxhc3RTaGFyZElkID0gaW5mby5sYXN0U2hhcmRJZFxuICAgICAgICBnYXRld2F5LmxvZ2dlci5pbmZvKGBbUmVzaGFyZGluZ10gU3RhcnRpbmcgdGhlIHJlc2hhcmQgcHJvY2Vzcy4gTmV3IHRvdGFsIHNoYXJkczogJHtnYXRld2F5LnRvdGFsU2hhcmRzfWApXG5cbiAgICAgICAgLy8gUmVzZXR0aW5nIGJ1Y2tldHNcbiAgICAgICAgZ2F0ZXdheS5idWNrZXRzLmNsZWFyKClcbiAgICAgICAgLy8gUmVmaWxsaW5nIGJ1Y2tldHMgd2l0aCBuZXcgdmFsdWVzXG4gICAgICAgIGdhdGV3YXkucHJlcGFyZUJ1Y2tldHMoKVxuXG4gICAgICAgIC8vIFNQUkVBRCBUSElTIE9VVCBUTyBESUZGRVJFTlQgV09SS0VSUyBUTyBCRUdJTiBTVEFSVElORyBVUFxuICAgICAgICBnYXRld2F5LmJ1Y2tldHMuZm9yRWFjaChhc3luYyAoYnVja2V0LCBidWNrZXRJZCkgPT4ge1xuICAgICAgICAgIGZvciAoY29uc3Qgd29ya2VyIG9mIGJ1Y2tldC53b3JrZXJzKSB7XG4gICAgICAgICAgICBmb3IgKGNvbnN0IHNoYXJkSWQgb2Ygd29ya2VyLnF1ZXVlKSB7XG4gICAgICAgICAgICAgIGF3YWl0IGdhdGV3YXkucmVzaGFyZGluZy50ZWxsV29ya2VyVG9QcmVwYXJlKHdvcmtlci5pZCwgc2hhcmRJZCwgYnVja2V0SWQpXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9KVxuICAgICAgfSxcbiAgICAgIGFzeW5jIHRlbGxXb3JrZXJUb1ByZXBhcmUod29ya2VySWQsIHNoYXJkSWQsIGJ1Y2tldElkKSB7XG4gICAgICAgIGdhdGV3YXkubG9nZ2VyLmRlYnVnKGBbUmVzaGFyZGluZ10gVGVsbGluZyB3b3JrZXIgdG8gcHJlcGFyZS4gV29ya2VyOiAke3dvcmtlcklkfSB8IFNoYXJkOiAke3NoYXJkSWR9IHwgQnVja2V0OiAke2J1Y2tldElkfS5gKVxuICAgICAgICBjb25zdCBzaGFyZCA9IG5ldyBTaGFyZCh7XG4gICAgICAgICAgaWQ6IHNoYXJkSWQsXG4gICAgICAgICAgY29ubmVjdGlvbjoge1xuICAgICAgICAgICAgY29tcHJlc3M6IGdhdGV3YXkuY29tcHJlc3MsXG4gICAgICAgICAgICB0cmFuc3BvcnRDb21wcmVzc2lvbjogZ2F0ZXdheS50cmFuc3BvcnRDb21wcmVzc2lvbiA/PyBudWxsLFxuICAgICAgICAgICAgaW50ZW50czogZ2F0ZXdheS5pbnRlbnRzLFxuICAgICAgICAgICAgcHJvcGVydGllczogZ2F0ZXdheS5wcm9wZXJ0aWVzLFxuICAgICAgICAgICAgdG9rZW46IGdhdGV3YXkudG9rZW4sXG4gICAgICAgICAgICB0b3RhbFNoYXJkczogZ2F0ZXdheS50b3RhbFNoYXJkcyxcbiAgICAgICAgICAgIHVybDogZ2F0ZXdheS51cmwsXG4gICAgICAgICAgICB2ZXJzaW9uOiBnYXRld2F5LnZlcnNpb24sXG4gICAgICAgICAgfSxcbiAgICAgICAgICAvLyBJZ25vcmUgZXZlbnRzIHVudGlsIHdlIGFyZSByZWFkeVxuICAgICAgICAgIGV2ZW50czoge1xuICAgICAgICAgICAgYXN5bmMgbWVzc2FnZShfc2hhcmQsIHBheWxvYWQpIHtcbiAgICAgICAgICAgICAgaWYgKHBheWxvYWQudCA9PT0gJ1JFQURZJykge1xuICAgICAgICAgICAgICAgIGF3YWl0IGdhdGV3YXkucmVzaGFyZGluZy51cGRhdGVHdWlsZHNTaGFyZElkPy4oXG4gICAgICAgICAgICAgICAgICAocGF5bG9hZC5kIGFzIERpc2NvcmRSZWFkeSkuZ3VpbGRzLm1hcCgoZykgPT4gZy5pZCksXG4gICAgICAgICAgICAgICAgICBzaGFyZElkLFxuICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9LFxuICAgICAgICAgIGxvZ2dlcjogZ2F0ZXdheS5sb2dnZXIsXG4gICAgICAgICAgcmVxdWVzdElkZW50aWZ5OiBhc3luYyAoKSA9PiB7XG4gICAgICAgICAgICBhd2FpdCBnYXRld2F5LmlkZW50aWZ5KHNoYXJkSWQpXG4gICAgICAgICAgfSxcbiAgICAgICAgICBzaGFyZElzUmVhZHk6IGFzeW5jICgpID0+IHtcbiAgICAgICAgICAgIGdhdGV3YXkubG9nZ2VyLmRlYnVnKGBbU2hhcmRdIFNoYXJkICMke3NoYXJkSWR9IGlzIHJlYWR5YClcbiAgICAgICAgICAgIGF3YWl0IGRlbGF5KGdhdGV3YXkuc3Bhd25TaGFyZERlbGF5KVxuICAgICAgICAgICAgZ2F0ZXdheS5sb2dnZXIuZGVidWcoYFtTaGFyZF0gUmVzb2x2aW5nIHNoYXJkIGlkZW50aWZ5IHJlcXVlc3RgKVxuICAgICAgICAgICAgZ2F0ZXdheS5idWNrZXRzLmdldChzaGFyZElkICUgZ2F0ZXdheS5jb25uZWN0aW9uLnNlc3Npb25TdGFydExpbWl0Lm1heENvbmN1cnJlbmN5KSEuaWRlbnRpZnlSZXF1ZXN0cy5zaGlmdCgpPy4oKVxuICAgICAgICAgIH0sXG4gICAgICAgICAgbWFrZVByZXNlbmNlOiBnYXRld2F5Lm1ha2VQcmVzZW5jZSxcbiAgICAgICAgfSlcblxuICAgICAgICBpZiAoZ2F0ZXdheS5wcmVmZXJTbmFrZUNhc2UpIHtcbiAgICAgICAgICBzaGFyZC5mb3J3YXJkVG9Cb3QgPSBhc3luYyAocGF5bG9hZCkgPT4ge1xuICAgICAgICAgICAgc2hhcmQuZXZlbnRzPy5tZXNzYWdlPy4oc2hhcmQsIHBheWxvYWQpXG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgZ2F0ZXdheS5yZXNoYXJkaW5nLnNoYXJkcy5zZXQoc2hhcmRJZCwgc2hhcmQpXG5cbiAgICAgICAgY29uc3QgYnVja2V0ID0gZ2F0ZXdheS5idWNrZXRzLmdldChzaGFyZElkICUgZ2F0ZXdheS5jb25uZWN0aW9uLnNlc3Npb25TdGFydExpbWl0Lm1heENvbmN1cnJlbmN5KVxuICAgICAgICBpZiAoIWJ1Y2tldCkgcmV0dXJuXG5cbiAgICAgICAgcmV0dXJuIGF3YWl0IG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiB7XG4gICAgICAgICAgLy8gTWFyayB0aGF0IHdlIGFyZSBtYWtpbmcgYW4gaWRlbnRpZnkgcmVxdWVzdCBzbyBhbm90aGVyIGlzIG5vdCBtYWRlLlxuICAgICAgICAgIGJ1Y2tldC5pZGVudGlmeVJlcXVlc3RzLnB1c2gocmVzb2x2ZSlcbiAgICAgICAgICBnYXRld2F5LmxvZ2dlci5kZWJ1ZyhgW0dhdGV3YXldIElkZW50aWZ5aW5nIFNoYXJkICMke3NoYXJkSWR9LmApXG4gICAgICAgICAgLy8gVGhpcyB3aWxsIHRyaWdnZXIgaWRlbnRpZnkgYW5kIHdoZW4gUkVBRFkgaXMgcmVjZWl2ZWQgaXQgd2lsbCByZXNvbHZlIHRoZSBhYm92ZSByZXF1ZXN0LlxuICAgICAgICAgIHNoYXJkPy5pZGVudGlmeSgpLnRoZW4oYXN5bmMgKCkgPT4ge1xuICAgICAgICAgICAgLy8gVGVsbCB0aGUgbWFuYWdlciB0aGF0IHRoaXMgc2hhcmQgaXMgb25saW5lXG4gICAgICAgICAgICByZXR1cm4gYXdhaXQgZ2F0ZXdheS5yZXNoYXJkaW5nLnNoYXJkSXNQZW5kaW5nKHNoYXJkKVxuICAgICAgICAgIH0pXG4gICAgICAgIH0pXG4gICAgICB9LFxuICAgICAgYXN5bmMgc2hhcmRJc1BlbmRpbmcoc2hhcmQpIHtcbiAgICAgICAgLy8gU2F2ZSB0aGlzIGluIHBlbmRpbmcgYXQgdGhlIG1vbWVudCwgdW50aWwgYWxsIHNoYXJkcyBhcmUgb25saW5lXG4gICAgICAgIGdhdGV3YXkucmVzaGFyZGluZy5wZW5kaW5nU2hhcmRzLnNldChzaGFyZC5pZCwgc2hhcmQpXG4gICAgICAgIGdhdGV3YXkubG9nZ2VyLmRlYnVnKGBbUmVzaGFyZGluZ10gU2hhcmQgIyR7c2hhcmQuaWR9IGlzIG5vdyBwZW5kaW5nLmApXG5cbiAgICAgICAgLy8gQ2hlY2sgaWYgYWxsIHNoYXJkcyBhcmUgbm93IG9ubGluZS5cbiAgICAgICAgaWYgKGdhdGV3YXkubGFzdFNoYXJkSWQgLSBnYXRld2F5LmZpcnN0U2hhcmRJZCA+PSBnYXRld2F5LnJlc2hhcmRpbmcucGVuZGluZ1NoYXJkcy5zaXplKSByZXR1cm5cblxuICAgICAgICBnYXRld2F5LmxvZ2dlci5pbmZvKGBbUmVzaGFyZGluZ10gQWxsIHNoYXJkcyBhcmUgbm93IG9ubGluZS5gKVxuXG4gICAgICAgIC8vIE5ldyBzaGFyZHMgc3RhcnQgcHJvY2Vzc2luZyBldmVudHNcbiAgICAgICAgZm9yIChjb25zdCBzaGFyZCBvZiBnYXRld2F5LnJlc2hhcmRpbmcuc2hhcmRzLnZhbHVlcygpKSB7XG4gICAgICAgICAgZm9yIChjb25zdCBldmVudCBpbiBvcHRpb25zLmV2ZW50cykge1xuICAgICAgICAgICAgc2hhcmQuZXZlbnRzW2V2ZW50IGFzIGtleW9mIFNoYXJkRXZlbnRzXSA9IG9wdGlvbnMuZXZlbnRzW2V2ZW50IGFzIGtleW9mIFNoYXJkRXZlbnRzXSBhcyAoLi4uYXJnczogdW5rbm93bltdKSA9PiB1bmtub3duXG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gT2xkIHNoYXJkcyBzdG9wIHByb2Nlc3NpbmcgZXZlbnRzXG4gICAgICAgIGZvciAoY29uc3Qgc2hhcmQgb2YgZ2F0ZXdheS5zaGFyZHMudmFsdWVzKCkpIHtcbiAgICAgICAgICBjb25zdCBvbGRIYW5kbGVyID0gc2hhcmQuZXZlbnRzLm1lc3NhZ2VcblxuICAgICAgICAgIC8vIENoYW5nZSB3aXRoIHNwcmVhZCBvcGVyYXRvciB0byBub3QgYWZmZWN0IG5ldyBzaGFyZHMsIGFzIGNoYW5naW5nIGFueXRoaW5nIG9uIHNoYXJkLmV2ZW50cyB3aWxsIGRpcmVjdGx5IGNoYW5nZSBvcHRpb25zLmV2ZW50cywgd2hpY2ggY2hhbmdlcyBuZXcgc2hhcmRzJyBldmVudHNcbiAgICAgICAgICBzaGFyZC5ldmVudHMgPSB7XG4gICAgICAgICAgICAuLi5zaGFyZC5ldmVudHMsXG4gICAgICAgICAgICBtZXNzYWdlOiBhc3luYyBmdW5jdGlvbiAoXywgbWVzc2FnZSkge1xuICAgICAgICAgICAgICAvLyBNZW1iZXIgY2hlY2tzIG5lZWQgdG8gY29udGludWUgYnV0IG90aGVycyBjYW4gc3RvcFxuICAgICAgICAgICAgICBpZiAobWVzc2FnZS50ID09PSAnR1VJTERfTUVNQkVSU19DSFVOSycpIHtcbiAgICAgICAgICAgICAgICBvbGRIYW5kbGVyPy4oc2hhcmQsIG1lc3NhZ2UpXG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgZ2F0ZXdheS5sb2dnZXIuaW5mbyhgW1Jlc2hhcmRpbmddIFNodXR0aW5nIGRvd24gb2xkIHNoYXJkcy5gKVxuICAgICAgICAvLyBDbG9zZSBvbGQgc2hhcmRzXG4gICAgICAgIGF3YWl0IGdhdGV3YXkuc2h1dGRvd24oU2hhcmRTb2NrZXRDbG9zZUNvZGVzLlJlc2hhcmRlZCwgJ1Jlc2hhcmRlZCEnLCBmYWxzZSlcblxuICAgICAgICBnYXRld2F5LmxvZ2dlci5pbmZvKGBbUmVzaGFyZGluZ10gQ29tcGxldGVkLmApXG5cbiAgICAgICAgLy8gUmVwbGFjZSBvbGQgc2hhcmRzXG4gICAgICAgIGdhdGV3YXkuc2hhcmRzID0gbmV3IENvbGxlY3Rpb24oZ2F0ZXdheS5yZXNoYXJkaW5nLnNoYXJkcylcblxuICAgICAgICAvLyBDbGVhciBvdXIgY29sbGVjdGlvbnMgYW5kIGtlZXAgb25seSBvbmUgcmVmZXJlbmNlIHRvIHRoZSBzaGFyZHMsIHRoZSBvbmUgaW4gZ2F0ZXdheS5zaGFyZHNcbiAgICAgICAgZ2F0ZXdheS5yZXNoYXJkaW5nLnNoYXJkcy5jbGVhcigpXG4gICAgICAgIGdhdGV3YXkucmVzaGFyZGluZy5wZW5kaW5nU2hhcmRzLmNsZWFyKClcbiAgICAgIH0sXG4gICAgfSxcblxuICAgIGNhbGN1bGF0ZVRvdGFsU2hhcmRzKCkge1xuICAgICAgLy8gQm90cyB1bmRlciAxMDBrIHNlcnZlcnMgZG8gbm90IGhhdmUgYWNjZXNzIHRvIExCUy5cbiAgICAgIGlmIChnYXRld2F5LnRvdGFsU2hhcmRzIDwgMTAwKSB7XG4gICAgICAgIGdhdGV3YXkubG9nZ2VyLmRlYnVnKGBbR2F0ZXdheV0gQ2FsY3VsYXRpbmcgdG90YWwgc2hhcmRzOiAke2dhdGV3YXkudG90YWxTaGFyZHN9YClcbiAgICAgICAgcmV0dXJuIGdhdGV3YXkudG90YWxTaGFyZHNcbiAgICAgIH1cblxuICAgICAgZ2F0ZXdheS5sb2dnZXIuZGVidWcoYFtHYXRld2F5XSBDYWxjdWxhdGluZyB0b3RhbCBzaGFyZHNgLCBnYXRld2F5LnRvdGFsU2hhcmRzLCBnYXRld2F5LmNvbm5lY3Rpb24uc2Vzc2lvblN0YXJ0TGltaXQubWF4Q29uY3VycmVuY3kpXG4gICAgICAvLyBDYWxjdWxhdGUgYSBtdWx0aXBsZSBvZiBgbWF4Q29uY3VycmVuY3lgIHdoaWNoIGNhbiBiZSB1c2VkIHRvIGNvbm5lY3QgdG8gdGhlIGdhdGV3YXkuXG4gICAgICByZXR1cm4gKFxuICAgICAgICBNYXRoLmNlaWwoXG4gICAgICAgICAgZ2F0ZXdheS50b3RhbFNoYXJkcyAvXG4gICAgICAgICAgICAvLyBJZiBgbWF4Q29uY3VycmVuY3lgIGlzIDEsIHdlIGNhbiBzYWZlbHkgdXNlIDE2IHRvIGdldCBgdG90YWxTaGFyZHNgIHRvIGJlIGluIGEgbXVsdGlwbGUgb2YgMTYgc28gdGhhdCB3ZSBjYW4gcHJlcGFyZSBib3RzIHdpdGggMTAwayBzZXJ2ZXJzIGZvciBMQlMuXG4gICAgICAgICAgICAoZ2F0ZXdheS5jb25uZWN0aW9uLnNlc3Npb25TdGFydExpbWl0Lm1heENvbmN1cnJlbmN5ID09PSAxID8gMTYgOiBnYXRld2F5LmNvbm5lY3Rpb24uc2Vzc2lvblN0YXJ0TGltaXQubWF4Q29uY3VycmVuY3kpLFxuICAgICAgICApICogKGdhdGV3YXkuY29ubmVjdGlvbi5zZXNzaW9uU3RhcnRMaW1pdC5tYXhDb25jdXJyZW5jeSA9PT0gMSA/IDE2IDogZ2F0ZXdheS5jb25uZWN0aW9uLnNlc3Npb25TdGFydExpbWl0Lm1heENvbmN1cnJlbmN5KVxuICAgICAgKVxuICAgIH0sXG4gICAgY2FsY3VsYXRlV29ya2VySWQoc2hhcmRJZCkge1xuICAgICAgY29uc3Qgd29ya2VySWQgPSBNYXRoLm1pbihzaGFyZElkICUgZ2F0ZXdheS5zaGFyZHNQZXJXb3JrZXIsIGdhdGV3YXkudG90YWxXb3JrZXJzIC0gMSlcbiAgICAgIGdhdGV3YXkubG9nZ2VyLmRlYnVnKFxuICAgICAgICBgW0dhdGV3YXldIENhbGN1bGF0aW5nIHdvcmtlcklkOiBTaGFyZDogJHtzaGFyZElkfSAtPiBXb3JrZXI6ICR7d29ya2VySWR9IC0+IFBlciBXb3JrZXI6ICR7Z2F0ZXdheS5zaGFyZHNQZXJXb3JrZXJ9IC0+IFRvdGFsOiAke2dhdGV3YXkudG90YWxXb3JrZXJzfWAsXG4gICAgICApXG4gICAgICByZXR1cm4gd29ya2VySWRcbiAgICB9LFxuICAgIHByZXBhcmVCdWNrZXRzKCkge1xuICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBnYXRld2F5LmNvbm5lY3Rpb24uc2Vzc2lvblN0YXJ0TGltaXQubWF4Q29uY3VycmVuY3k7ICsraSkge1xuICAgICAgICBnYXRld2F5LmxvZ2dlci5kZWJ1ZyhgW0dhdGV3YXldIFByZXBhcmluZyBidWNrZXRzIGZvciBjb25jdXJyZW5jeTogJHtpfWApXG4gICAgICAgIGdhdGV3YXkuYnVja2V0cy5zZXQoaSwge1xuICAgICAgICAgIHdvcmtlcnM6IFtdLFxuICAgICAgICAgIGlkZW50aWZ5UmVxdWVzdHM6IFtdLFxuICAgICAgICB9KVxuICAgICAgfVxuXG4gICAgICAvLyBPUkdBTklaRSBBTEwgU0hBUkRTIElOVE8gVEhFSVIgT1dOIEJVQ0tFVFNcbiAgICAgIGZvciAobGV0IHNoYXJkSWQgPSBnYXRld2F5LmZpcnN0U2hhcmRJZDsgc2hhcmRJZCA8PSBnYXRld2F5Lmxhc3RTaGFyZElkOyArK3NoYXJkSWQpIHtcbiAgICAgICAgZ2F0ZXdheS5sb2dnZXIuZGVidWcoYFtHYXRld2F5XSBQcmVwYXJpbmcgYnVja2V0cyBmb3Igc2hhcmQ6ICR7c2hhcmRJZH1gKVxuICAgICAgICBpZiAoc2hhcmRJZCA+PSBnYXRld2F5LnRvdGFsU2hhcmRzKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBTaGFyZCAoaWQ6ICR7c2hhcmRJZH0pIGlzIGJpZ2dlciBvciBlcXVhbCB0byB0aGUgdXNlZCBhbW91bnQgb2YgdXNlZCBzaGFyZHMgd2hpY2ggaXMgJHtnYXRld2F5LnRvdGFsU2hhcmRzfWApXG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBidWNrZXRJZCA9IHNoYXJkSWQgJSBnYXRld2F5LmNvbm5lY3Rpb24uc2Vzc2lvblN0YXJ0TGltaXQubWF4Q29uY3VycmVuY3lcbiAgICAgICAgY29uc3QgYnVja2V0ID0gZ2F0ZXdheS5idWNrZXRzLmdldChidWNrZXRJZClcbiAgICAgICAgaWYgKCFidWNrZXQpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgICBgU2hhcmQgKGlkOiAke3NoYXJkSWR9KSBnb3QgYXNzaWduZWQgdG8gYW4gaWxsZWdhbCBidWNrZXQgaWQ6ICR7YnVja2V0SWR9LCBleHBlY3RlZCBhIGJ1Y2tldCBpZCBiZXR3ZWVuIDAgYW5kICR7XG4gICAgICAgICAgICAgIGdhdGV3YXkuY29ubmVjdGlvbi5zZXNzaW9uU3RhcnRMaW1pdC5tYXhDb25jdXJyZW5jeSAtIDFcbiAgICAgICAgICAgIH1gLFxuICAgICAgICAgIClcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEZJTkQgQSBRVUVVRSBJTiBUSElTIEJVQ0tFVCBUSEFUIEhBUyBTUEFDRVxuICAgICAgICAvLyBjb25zdCB3b3JrZXIgPSBidWNrZXQud29ya2Vycy5maW5kKCh3KSA9PiB3LnF1ZXVlLmxlbmd0aCA8IGdhdGV3YXkuc2hhcmRzUGVyV29ya2VyKTtcbiAgICAgICAgY29uc3Qgd29ya2VySWQgPSBnYXRld2F5LmNhbGN1bGF0ZVdvcmtlcklkKHNoYXJkSWQpXG4gICAgICAgIGNvbnN0IHdvcmtlciA9IGJ1Y2tldC53b3JrZXJzLmZpbmQoKHcpID0+IHcuaWQgPT09IHdvcmtlcklkKVxuICAgICAgICBpZiAod29ya2VyKSB7XG4gICAgICAgICAgLy8gSUYgVEhFIFFVRVVFIEhBUyBTUEFDRSBKVVNUIEFERCBJVCBUTyBUSElTIFFVRVVFXG4gICAgICAgICAgd29ya2VyLnF1ZXVlLnB1c2goc2hhcmRJZClcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBidWNrZXQud29ya2Vycy5wdXNoKHsgaWQ6IHdvcmtlcklkLCBxdWV1ZTogW3NoYXJkSWRdIH0pXG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgZm9yIChjb25zdCBidWNrZXQgb2YgZ2F0ZXdheS5idWNrZXRzLnZhbHVlcygpKSB7XG4gICAgICAgIGZvciAoY29uc3Qgd29ya2VyIG9mIGJ1Y2tldC53b3JrZXJzLnZhbHVlcygpKSB7XG4gICAgICAgICAgd29ya2VyLnF1ZXVlID0gd29ya2VyLnF1ZXVlLnNvcnQoKGEsIGIpID0+IGEgLSBiKVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfSxcbiAgICBhc3luYyBzcGF3blNoYXJkcygpIHtcbiAgICAgIC8vIFBSRVBBUkVTIEFMTCBTSEFSRFMgSU4gU1BFQ0lGSUMgQlVDS0VUU1xuICAgICAgZ2F0ZXdheS5wcmVwYXJlQnVja2V0cygpXG5cbiAgICAgIC8vIFByZWZlciBjb25jdXJyZW5jeSBvZiBmb3JFYWNoIGluc3RlYWQgb2YgZm9yb2ZcbiAgICAgIGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgICBbLi4uZ2F0ZXdheS5idWNrZXRzLmVudHJpZXMoKV0ubWFwKGFzeW5jIChbYnVja2V0SWQsIGJ1Y2tldF0pID0+IHtcbiAgICAgICAgICBmb3IgKGNvbnN0IHdvcmtlciBvZiBidWNrZXQud29ya2Vycykge1xuICAgICAgICAgICAgZm9yIChjb25zdCBzaGFyZElkIG9mIHdvcmtlci5xdWV1ZSkge1xuICAgICAgICAgICAgICBhd2FpdCBnYXRld2F5LnRlbGxXb3JrZXJUb0lkZW50aWZ5KHdvcmtlci5pZCwgc2hhcmRJZCwgYnVja2V0SWQpXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9KSxcbiAgICAgIClcblxuICAgICAgLy8gQ2hlY2sgYW5kIHJlc2hhcmQgYXV0b21hdGljYWxseSBpZiBhdXRvIHJlc2hhcmRpbmcgaXMgZW5hYmxlZC5cbiAgICAgIGlmIChnYXRld2F5LnJlc2hhcmRpbmcuZW5hYmxlZCAmJiBnYXRld2F5LnJlc2hhcmRpbmcuY2hlY2tJbnRlcnZhbCAhPT0gLTEpIHtcbiAgICAgICAgLy8gSXQgaXMgYmV0dGVyIHRvIGVuc3VyZSB0aGVyZSBpcyBhbHdheXMgb25seSBvbmVcbiAgICAgICAgY2xlYXJJbnRlcnZhbChnYXRld2F5LnJlc2hhcmRpbmcuY2hlY2tJbnRlcnZhbElkKVxuXG4gICAgICAgIGlmICghZ2F0ZXdheS5yZXNoYXJkaW5nLmdldFNlc3Npb25JbmZvKSB7XG4gICAgICAgICAgZ2F0ZXdheS5yZXNoYXJkaW5nLmVuYWJsZWQgPSBmYWxzZVxuICAgICAgICAgIGdhdGV3YXkubG9nZ2VyLndhcm4oXCJbUmVzaGFyZGluZ10gUmVzaGFyZGluZyBpcyBlbmFibGVkIGJ1dCAncmVzaGFyZGluZy5nZXRTZXNzaW9uSW5mbygpJyB3YXMgbm90IHByb3ZpZGVkLiBEaXNhYmxpbmcgcmVzaGFyZGluZy5cIilcblxuICAgICAgICAgIHJldHVyblxuICAgICAgICB9XG5cbiAgICAgICAgZ2F0ZXdheS5yZXNoYXJkaW5nLmNoZWNrSW50ZXJ2YWxJZCA9IHNldEludGVydmFsKGFzeW5jICgpID0+IHtcbiAgICAgICAgICBjb25zdCByZXNoYXJkaW5nSW5mbyA9IGF3YWl0IGdhdGV3YXkucmVzaGFyZGluZy5jaGVja0lmUmVzaGFyZGluZ0lzTmVlZGVkKClcblxuICAgICAgICAgIGlmIChyZXNoYXJkaW5nSW5mby5uZWVkZWQgJiYgcmVzaGFyZGluZ0luZm8uaW5mbykgYXdhaXQgZ2F0ZXdheS5yZXNoYXJkaW5nLnJlc2hhcmQocmVzaGFyZGluZ0luZm8uaW5mbylcbiAgICAgICAgfSwgZ2F0ZXdheS5yZXNoYXJkaW5nLmNoZWNrSW50ZXJ2YWwpXG4gICAgICB9XG4gICAgfSxcbiAgICBhc3luYyBzaHV0ZG93bihjb2RlLCByZWFzb24sIGNsZWFyUmVzaGFyZGluZ0ludGVydmFsID0gdHJ1ZSkge1xuICAgICAgaWYgKGNsZWFyUmVzaGFyZGluZ0ludGVydmFsKSBjbGVhckludGVydmFsKGdhdGV3YXkucmVzaGFyZGluZy5jaGVja0ludGVydmFsSWQpXG5cbiAgICAgIGF3YWl0IFByb21pc2UuYWxsKEFycmF5LmZyb20oZ2F0ZXdheS5zaGFyZHMudmFsdWVzKCkpLm1hcCgoc2hhcmQpID0+IHNoYXJkLmNsb3NlKGNvZGUsIHJlYXNvbikpKVxuICAgIH0sXG4gICAgYXN5bmMgc2VuZFBheWxvYWQoc2hhcmRJZCwgcGF5bG9hZCkge1xuICAgICAgY29uc3Qgc2hhcmQgPSBnYXRld2F5LnNoYXJkcy5nZXQoc2hhcmRJZClcblxuICAgICAgaWYgKCFzaGFyZCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFNoYXJkIChpZDogJHtzaGFyZElkfSBub3QgZm91bmRgKVxuICAgICAgfVxuXG4gICAgICBhd2FpdCBzaGFyZC5zZW5kKHBheWxvYWQpXG4gICAgfSxcbiAgICBhc3luYyB0ZWxsV29ya2VyVG9JZGVudGlmeSh3b3JrZXJJZCwgc2hhcmRJZCwgYnVja2V0SWQpIHtcbiAgICAgIGdhdGV3YXkubG9nZ2VyLmRlYnVnKGBbR2F0ZXdheV0gVGVsbCB3b3JrZXIgdG8gaWRlbnRpZnkgKCR7d29ya2VySWR9LCAke3NoYXJkSWR9LCAke2J1Y2tldElkfSlgKVxuICAgICAgYXdhaXQgZ2F0ZXdheS5pZGVudGlmeShzaGFyZElkKVxuICAgIH0sXG4gICAgYXN5bmMgaWRlbnRpZnkoc2hhcmRJZDogbnVtYmVyKSB7XG4gICAgICBsZXQgc2hhcmQgPSB0aGlzLnNoYXJkcy5nZXQoc2hhcmRJZClcbiAgICAgIGdhdGV3YXkubG9nZ2VyLmRlYnVnKGBbR2F0ZXdheV0gSWRlbnRpZnlpbmcgJHtzaGFyZCA/ICdleGlzdGluZycgOiAnbmV3J30gc2hhcmQgKCR7c2hhcmRJZH0pYClcblxuICAgICAgaWYgKCFzaGFyZCkge1xuICAgICAgICBzaGFyZCA9IG5ldyBTaGFyZCh7XG4gICAgICAgICAgaWQ6IHNoYXJkSWQsXG4gICAgICAgICAgY29ubmVjdGlvbjoge1xuICAgICAgICAgICAgY29tcHJlc3M6IHRoaXMuY29tcHJlc3MsXG4gICAgICAgICAgICB0cmFuc3BvcnRDb21wcmVzc2lvbjogZ2F0ZXdheS50cmFuc3BvcnRDb21wcmVzc2lvbixcbiAgICAgICAgICAgIGludGVudHM6IHRoaXMuaW50ZW50cyxcbiAgICAgICAgICAgIHByb3BlcnRpZXM6IHRoaXMucHJvcGVydGllcyxcbiAgICAgICAgICAgIHRva2VuOiB0aGlzLnRva2VuLFxuICAgICAgICAgICAgdG90YWxTaGFyZHM6IHRoaXMudG90YWxTaGFyZHMsXG4gICAgICAgICAgICB1cmw6IHRoaXMudXJsLFxuICAgICAgICAgICAgdmVyc2lvbjogdGhpcy52ZXJzaW9uLFxuICAgICAgICAgIH0sXG4gICAgICAgICAgZXZlbnRzOiBvcHRpb25zLmV2ZW50cyA/PyB7fSxcbiAgICAgICAgICBsb2dnZXI6IHRoaXMubG9nZ2VyLFxuICAgICAgICAgIHJlcXVlc3RJZGVudGlmeTogYXN5bmMgKCkgPT4ge1xuICAgICAgICAgICAgYXdhaXQgZ2F0ZXdheS5pZGVudGlmeShzaGFyZElkKVxuICAgICAgICAgIH0sXG4gICAgICAgICAgc2hhcmRJc1JlYWR5OiBhc3luYyAoKSA9PiB7XG4gICAgICAgICAgICBnYXRld2F5LmxvZ2dlci5kZWJ1ZyhgW1NoYXJkXSBTaGFyZCAjJHtzaGFyZElkfSBpcyByZWFkeWApXG4gICAgICAgICAgICBhd2FpdCBkZWxheShnYXRld2F5LnNwYXduU2hhcmREZWxheSlcbiAgICAgICAgICAgIGdhdGV3YXkubG9nZ2VyLmRlYnVnKGBbU2hhcmRdIFJlc29sdmluZyBzaGFyZCBpZGVudGlmeSByZXF1ZXN0YClcbiAgICAgICAgICAgIGdhdGV3YXkuYnVja2V0cy5nZXQoc2hhcmRJZCAlIGdhdGV3YXkuY29ubmVjdGlvbi5zZXNzaW9uU3RhcnRMaW1pdC5tYXhDb25jdXJyZW5jeSkhLmlkZW50aWZ5UmVxdWVzdHMuc2hpZnQoKT8uKClcbiAgICAgICAgICB9LFxuICAgICAgICAgIG1ha2VQcmVzZW5jZTogZ2F0ZXdheS5tYWtlUHJlc2VuY2UsXG4gICAgICAgIH0pXG5cbiAgICAgICAgaWYgKHRoaXMucHJlZmVyU25ha2VDYXNlKSB7XG4gICAgICAgICAgc2hhcmQuZm9yd2FyZFRvQm90ID0gYXN5bmMgKHBheWxvYWQpID0+IHtcbiAgICAgICAgICAgIHNoYXJkIS5ldmVudHMubWVzc2FnZT8uKHNoYXJkISwgcGF5bG9hZClcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnNoYXJkcy5zZXQoc2hhcmRJZCwgc2hhcmQpXG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGJ1Y2tldCA9IGdhdGV3YXkuYnVja2V0cy5nZXQoc2hhcmRJZCAlIGdhdGV3YXkuY29ubmVjdGlvbi5zZXNzaW9uU3RhcnRMaW1pdC5tYXhDb25jdXJyZW5jeSlcbiAgICAgIGlmICghYnVja2V0KSByZXR1cm5cblxuICAgICAgcmV0dXJuIGF3YWl0IG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiB7XG4gICAgICAgIC8vIE1hcmsgdGhhdCB3ZSBhcmUgbWFraW5nIGFuIGlkZW50aWZ5IHJlcXVlc3Qgc28gYW5vdGhlciBpcyBub3QgbWFkZS5cbiAgICAgICAgYnVja2V0LmlkZW50aWZ5UmVxdWVzdHMucHVzaChyZXNvbHZlKVxuICAgICAgICBnYXRld2F5LmxvZ2dlci5kZWJ1ZyhgW0dhdGV3YXldIElkZW50aWZ5aW5nIFNoYXJkICMke3NoYXJkSWR9LmApXG4gICAgICAgIC8vIFRoaXMgd2lsbCB0cmlnZ2VyIGlkZW50aWZ5IGFuZCB3aGVuIFJFQURZIGlzIHJlY2VpdmVkIGl0IHdpbGwgcmVzb2x2ZSB0aGUgYWJvdmUgcmVxdWVzdC5cbiAgICAgICAgc2hhcmQ/LmlkZW50aWZ5KClcbiAgICAgIH0pXG4gICAgfSxcbiAgICBhc3luYyBraWxsKHNoYXJkSWQ6IG51bWJlcikge1xuICAgICAgY29uc3Qgc2hhcmQgPSB0aGlzLnNoYXJkcy5nZXQoc2hhcmRJZClcbiAgICAgIGlmICghc2hhcmQpIHtcbiAgICAgICAgcmV0dXJuIGdhdGV3YXkubG9nZ2VyLmRlYnVnKGBbR2F0ZXdheV0gQSBraWxsIGZvciBTaGFyZCAjJHtzaGFyZElkfSB3YXMgcmVxdWVzdGVkLCBidXQgdGhlIHNoYXJkIGNvdWxkIG5vdCBiZSBmb3VuZGApXG4gICAgICB9XG5cbiAgICAgIGdhdGV3YXkubG9nZ2VyLmRlYnVnKGBbR2F0ZXdheV0gS2lsbGluZyBTaGFyZCAjJHtzaGFyZElkfWApXG4gICAgICB0aGlzLnNoYXJkcy5kZWxldGUoc2hhcmRJZClcbiAgICAgIGF3YWl0IHNoYXJkLnNodXRkb3duKClcbiAgICB9LFxuICAgIGFzeW5jIHJlcXVlc3RJZGVudGlmeShfc2hhcmRJZDogbnVtYmVyKSB7XG4gICAgICBnYXRld2F5LmxvZ2dlci5kZWJ1ZyhgW0dhdGV3YXldIFJlcXVlc3RpbmcgaWRlbnRpZnlgKVxuICAgIH0sXG5cbiAgICAvLyBIZWxwZXJzIG1ldGhvZHMgYmVsb3cgdGhpc1xuXG4gICAgY2FsY3VsYXRlU2hhcmRJZChndWlsZElkLCB0b3RhbFNoYXJkcykge1xuICAgICAgLy8gSWYgbm9uZSBpcyBwcm92aWRlZCwgdXNlIHRoZSB0b3RhbCBzaGFyZHMgbnVtYmVyIGZyb20gZ2F0ZXdheSBvYmplY3QuXG4gICAgICBpZiAoIXRvdGFsU2hhcmRzKSB0b3RhbFNoYXJkcyA9IGdhdGV3YXkudG90YWxTaGFyZHNcbiAgICAgIC8vIElmIGl0IGlzIG9ubHkgMSBzaGFyZCwgaXQgd2lsbCBhbHdheXMgYmUgc2hhcmQgaWQgMFxuICAgICAgaWYgKHRvdGFsU2hhcmRzID09PSAxKSB7XG4gICAgICAgIGdhdGV3YXkubG9nZ2VyLmRlYnVnKGBbR2F0ZXdheV0gY2FsY3VsYXRlU2hhcmRJZCAoMSBzaGFyZClgKVxuICAgICAgICByZXR1cm4gMFxuICAgICAgfVxuXG4gICAgICBnYXRld2F5LmxvZ2dlci5kZWJ1ZyhgW0dhdGV3YXldIGNhbGN1bGF0ZVNoYXJkSWQgKGd1aWxkSWQ6ICR7Z3VpbGRJZH0sIHRvdGFsU2hhcmRzOiAke3RvdGFsU2hhcmRzfSlgKVxuICAgICAgcmV0dXJuIE51bWJlcigoQmlnSW50KGd1aWxkSWQpID4+IDIybikgJSBCaWdJbnQodG90YWxTaGFyZHMpKVxuICAgIH0sXG5cbiAgICBhc3luYyBqb2luVm9pY2VDaGFubmVsKGd1aWxkSWQsIGNoYW5uZWxJZCwgb3B0aW9ucykge1xuICAgICAgY29uc3Qgc2hhcmRJZCA9IGdhdGV3YXkuY2FsY3VsYXRlU2hhcmRJZChndWlsZElkKVxuXG4gICAgICBnYXRld2F5LmxvZ2dlci5kZWJ1ZyhgW0dhdGV3YXldIGpvaW5Wb2ljZUNoYW5uZWwgZ3VpbGRJZDogJHtndWlsZElkfSBjaGFubmVsSWQ6ICR7Y2hhbm5lbElkfWApXG5cbiAgICAgIGF3YWl0IGdhdGV3YXkuc2VuZFBheWxvYWQoc2hhcmRJZCwge1xuICAgICAgICBvcDogR2F0ZXdheU9wY29kZXMuVm9pY2VTdGF0ZVVwZGF0ZSxcbiAgICAgICAgZDoge1xuICAgICAgICAgIGd1aWxkX2lkOiBndWlsZElkLnRvU3RyaW5nKCksXG4gICAgICAgICAgY2hhbm5lbF9pZDogY2hhbm5lbElkLnRvU3RyaW5nKCksXG4gICAgICAgICAgc2VsZl9tdXRlOiBvcHRpb25zPy5zZWxmTXV0ZSA/PyBmYWxzZSxcbiAgICAgICAgICBzZWxmX2RlYWY6IG9wdGlvbnM/LnNlbGZEZWFmID8/IHRydWUsXG4gICAgICAgIH0sXG4gICAgICB9KVxuICAgIH0sXG5cbiAgICBhc3luYyBlZGl0Qm90U3RhdHVzKGRhdGEpIHtcbiAgICAgIGdhdGV3YXkubG9nZ2VyLmRlYnVnKGBbR2F0ZXdheV0gZWRpdEJvdFN0YXR1cyBkYXRhOiAke0pTT04uc3RyaW5naWZ5KGRhdGEpfWApXG5cbiAgICAgIGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgICBbLi4uZ2F0ZXdheS5zaGFyZHMudmFsdWVzKCldLm1hcChhc3luYyAoc2hhcmQpID0+IHtcbiAgICAgICAgICBnYXRld2F5LmVkaXRTaGFyZFN0YXR1cyhzaGFyZC5pZCwgZGF0YSlcbiAgICAgICAgfSksXG4gICAgICApXG4gICAgfSxcblxuICAgIGFzeW5jIGVkaXRTaGFyZFN0YXR1cyhzaGFyZElkLCBkYXRhKSB7XG4gICAgICBnYXRld2F5LmxvZ2dlci5kZWJ1ZyhgW0dhdGV3YXldIGVkaXRTaGFyZFN0YXR1cyBzaGFyZElkOiAke3NoYXJkSWR9IC0+IGRhdGE6ICR7SlNPTi5zdHJpbmdpZnkoZGF0YSl9YClcblxuICAgICAgYXdhaXQgZ2F0ZXdheS5zZW5kUGF5bG9hZChzaGFyZElkLCB7XG4gICAgICAgIG9wOiBHYXRld2F5T3Bjb2Rlcy5QcmVzZW5jZVVwZGF0ZSxcbiAgICAgICAgZDoge1xuICAgICAgICAgIHNpbmNlOiBudWxsLFxuICAgICAgICAgIGFmazogZmFsc2UsXG4gICAgICAgICAgYWN0aXZpdGllczogZGF0YS5hY3Rpdml0aWVzLFxuICAgICAgICAgIHN0YXR1czogZGF0YS5zdGF0dXMsXG4gICAgICAgIH0sXG4gICAgICB9KVxuICAgIH0sXG5cbiAgICBhc3luYyByZXF1ZXN0TWVtYmVycyhndWlsZElkLCBvcHRpb25zKSB7XG4gICAgICBjb25zdCBzaGFyZElkID0gZ2F0ZXdheS5jYWxjdWxhdGVTaGFyZElkKGd1aWxkSWQpXG5cbiAgICAgIGlmIChnYXRld2F5LmludGVudHMgJiYgKCFvcHRpb25zPy5saW1pdCB8fCBvcHRpb25zLmxpbWl0ID4gMSkgJiYgIShnYXRld2F5LmludGVudHMgJiBHYXRld2F5SW50ZW50cy5HdWlsZE1lbWJlcnMpKVxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0Nhbm5vdCBmZXRjaCBtb3JlIHRoZW4gMSBtZW1iZXIgd2l0aG91dCB0aGUgR1VJTERfTUVNQkVSUyBpbnRlbnQnKVxuXG4gICAgICBnYXRld2F5LmxvZ2dlci5kZWJ1ZyhgW0dhdGV3YXldIHJlcXVlc3RNZW1iZXJzIGd1aWxkSWQ6ICR7Z3VpbGRJZH0gLT4gZGF0YTogJHtKU09OLnN0cmluZ2lmeShvcHRpb25zKX1gKVxuXG4gICAgICBpZiAob3B0aW9ucz8udXNlcklkcz8ubGVuZ3RoKSB7XG4gICAgICAgIGdhdGV3YXkubG9nZ2VyLmRlYnVnKGBbR2F0ZXdheV0gcmVxdWVzdE1lbWJlcnMgZ3VpbGRJZDogJHtndWlsZElkfSAtPiBzZXR0aW5nIHVzZXIgbGltaXQgYmFzZWQgb24gdXNlcklkcyBsZW5ndGg6ICR7b3B0aW9ucy51c2VySWRzLmxlbmd0aH1gKVxuXG4gICAgICAgIG9wdGlvbnMubGltaXQgPSBvcHRpb25zLnVzZXJJZHMubGVuZ3RoXG4gICAgICB9XG5cbiAgICAgIGlmICghb3B0aW9ucz8ubm9uY2UpIHtcbiAgICAgICAgbGV0IG5vbmNlID0gJydcblxuICAgICAgICB3aGlsZSAoIW5vbmNlIHx8IGdhdGV3YXkuY2FjaGUucmVxdWVzdE1lbWJlcnMucGVuZGluZy5oYXMobm9uY2UpKSB7XG4gICAgICAgICAgbm9uY2UgPSByYW5kb21CeXRlcygxNikudG9TdHJpbmcoJ2hleCcpXG4gICAgICAgIH1cblxuICAgICAgICBvcHRpb25zID8/PSB7IGxpbWl0OiAwIH1cbiAgICAgICAgb3B0aW9ucy5ub25jZSA9IG5vbmNlXG4gICAgICB9XG5cbiAgICAgIGNvbnN0IG1lbWJlcnMgPSAhZ2F0ZXdheS5jYWNoZS5yZXF1ZXN0TWVtYmVycy5lbmFibGVkXG4gICAgICAgID8gW11cbiAgICAgICAgOiBuZXcgUHJvbWlzZTxDYW1lbGl6ZTxEaXNjb3JkTWVtYmVyV2l0aFVzZXJbXT4+KChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgICAgIC8vIFNob3VsZCBuZXZlciBoYXBwZW4uXG4gICAgICAgICAgICBpZiAoIWdhdGV3YXkuY2FjaGUucmVxdWVzdE1lbWJlcnMuZW5hYmxlZCB8fCAhb3B0aW9ucz8ubm9uY2UpIHtcbiAgICAgICAgICAgICAgcmVqZWN0KG5ldyBFcnJvcihcIkNhbid0IHJlcXVlc3QgdGhlIG1lbWJlcnMgd2l0aG91dCB0aGUgbm9uY2Ugb3Igd2l0aCB0aGUgZmVhdHVyZSBkaXNhYmxlZC5cIikpXG4gICAgICAgICAgICAgIHJldHVyblxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBnYXRld2F5LmNhY2hlLnJlcXVlc3RNZW1iZXJzLnBlbmRpbmcuc2V0KG9wdGlvbnMubm9uY2UsIHtcbiAgICAgICAgICAgICAgbm9uY2U6IG9wdGlvbnMubm9uY2UsXG4gICAgICAgICAgICAgIHJlc29sdmUsXG4gICAgICAgICAgICAgIG1lbWJlcnM6IFtdLFxuICAgICAgICAgICAgfSlcbiAgICAgICAgICB9KVxuXG4gICAgICBhd2FpdCBnYXRld2F5LnNlbmRQYXlsb2FkKHNoYXJkSWQsIHtcbiAgICAgICAgb3A6IEdhdGV3YXlPcGNvZGVzLlJlcXVlc3RHdWlsZE1lbWJlcnMsXG4gICAgICAgIGQ6IHtcbiAgICAgICAgICBndWlsZF9pZDogZ3VpbGRJZC50b1N0cmluZygpLFxuICAgICAgICAgIC8vIElmIGEgcXVlcnkgaXMgcHJvdmlkZWQgdXNlIGl0LCBPUiBpZiBhIGxpbWl0IGlzIE5PVCBwcm92aWRlZCB1c2UgXCJcIlxuICAgICAgICAgIHF1ZXJ5OiBvcHRpb25zPy5xdWVyeSA/PyAob3B0aW9ucz8ubGltaXQgPyB1bmRlZmluZWQgOiAnJyksXG4gICAgICAgICAgbGltaXQ6IG9wdGlvbnM/LmxpbWl0ID8/IDAsXG4gICAgICAgICAgcHJlc2VuY2VzOiBvcHRpb25zPy5wcmVzZW5jZXMgPz8gZmFsc2UsXG4gICAgICAgICAgdXNlcl9pZHM6IG9wdGlvbnM/LnVzZXJJZHM/Lm1hcCgoaWQpID0+IGlkLnRvU3RyaW5nKCkpLFxuICAgICAgICAgIG5vbmNlOiBvcHRpb25zPy5ub25jZSxcbiAgICAgICAgfSxcbiAgICAgIH0pXG5cbiAgICAgIHJldHVybiBhd2FpdCBtZW1iZXJzXG4gICAgfSxcblxuICAgIGFzeW5jIGxlYXZlVm9pY2VDaGFubmVsKGd1aWxkSWQpIHtcbiAgICAgIGNvbnN0IHNoYXJkSWQgPSBnYXRld2F5LmNhbGN1bGF0ZVNoYXJkSWQoZ3VpbGRJZClcblxuICAgICAgZ2F0ZXdheS5sb2dnZXIuZGVidWcoYFtHYXRld2F5XSBsZWF2ZVZvaWNlQ2hhbm5lbCBndWlsZElkOiAke2d1aWxkSWR9IFNoYXJkICR7c2hhcmRJZH1gKVxuXG4gICAgICBhd2FpdCBnYXRld2F5LnNlbmRQYXlsb2FkKHNoYXJkSWQsIHtcbiAgICAgICAgb3A6IEdhdGV3YXlPcGNvZGVzLlZvaWNlU3RhdGVVcGRhdGUsXG4gICAgICAgIGQ6IHtcbiAgICAgICAgICBndWlsZF9pZDogZ3VpbGRJZC50b1N0cmluZygpLFxuICAgICAgICAgIGNoYW5uZWxfaWQ6IG51bGwsXG4gICAgICAgICAgc2VsZl9tdXRlOiBmYWxzZSxcbiAgICAgICAgICBzZWxmX2RlYWY6IGZhbHNlLFxuICAgICAgICB9LFxuICAgICAgfSlcbiAgICB9LFxuXG4gICAgYXN5bmMgcmVxdWVzdFNvdW5kYm9hcmRTb3VuZHMoZ3VpbGRJZHMpIHtcbiAgICAgIC8qKlxuICAgICAgICogRGlzY29yZCB3aWxsIHNlbmQgdGhlIGV2ZW50cyBmb3IgdGhlIGd1aWxkcyB0aGF0IGFyZSBcInVuZGVyIHRoZSBzaGFyZFwiIHRoYXQgc2VuZHMgdGhlIG9wY29kZS5cbiAgICAgICAqIEZvciB0aGlzIHJlYXNvbiB3ZSBuZWVkIHRvIGdyb3VwIHRoZSBpZHMgd2l0aCB0aGUgc2hhcmQgdGhlIGNhbGN1bGF0ZVNoYXJkSWQgbWV0aG9kIGdpdmVzXG4gICAgICAgKi9cblxuICAgICAgY29uc3QgbWFwID0gbmV3IE1hcDxudW1iZXIsIEJpZ1N0cmluZ1tdPigpXG5cbiAgICAgIGZvciAoY29uc3QgZ3VpbGRJZCBvZiBndWlsZElkcykge1xuICAgICAgICBjb25zdCBzaGFyZElkID0gZ2F0ZXdheS5jYWxjdWxhdGVTaGFyZElkKGd1aWxkSWQpXG5cbiAgICAgICAgY29uc3QgaWRzID0gbWFwLmdldChzaGFyZElkKSA/PyBbXVxuICAgICAgICBtYXAuc2V0KHNoYXJkSWQsIGlkcylcblxuICAgICAgICBpZHMucHVzaChndWlsZElkKVxuICAgICAgfVxuXG4gICAgICBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgICAgWy4uLm1hcC5lbnRyaWVzKCldLm1hcCgoW3NoYXJkSWQsIGlkc10pID0+XG4gICAgICAgICAgZ2F0ZXdheS5zZW5kUGF5bG9hZChzaGFyZElkLCB7XG4gICAgICAgICAgICBvcDogR2F0ZXdheU9wY29kZXMuUmVxdWVzdFNvdW5kYm9hcmRTb3VuZHMsXG4gICAgICAgICAgICBkOiB7XG4gICAgICAgICAgICAgIGd1aWxkX2lkczogaWRzLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9KSxcbiAgICAgICAgKSxcbiAgICAgIClcbiAgICB9LFxuICB9XG5cbiAgcmV0dXJuIGdhdGV3YXlcbn1cblxuZXhwb3J0IGludGVyZmFjZSBDcmVhdGVHYXRld2F5TWFuYWdlck9wdGlvbnMge1xuICAvKipcbiAgICogSWQgb2YgdGhlIGZpcnN0IFNoYXJkIHdoaWNoIHNob3VsZCBnZXQgY29udHJvbGxlZCBieSB0aGlzIG1hbmFnZXIuXG4gICAqIEBkZWZhdWx0IDBcbiAgICovXG4gIGZpcnN0U2hhcmRJZD86IG51bWJlclxuICAvKipcbiAgICogSWQgb2YgdGhlIGxhc3QgU2hhcmQgd2hpY2ggc2hvdWxkIGdldCBjb250cm9sbGVkIGJ5IHRoaXMgbWFuYWdlci5cbiAgICogQGRlZmF1bHQgMFxuICAgKi9cbiAgbGFzdFNoYXJkSWQ/OiBudW1iZXJcbiAgLyoqXG4gICAqIERlbGF5IGluIG1pbGxpc2Vjb25kcyB0byB3YWl0IGJlZm9yZSBzcGF3bmluZyBuZXh0IHNoYXJkLiBPUFRJTUFMIElTIEFCT1ZFIDUxMDAuIFlPVSBET04nVCBXQU5UIFRPIEhJVCBUSEUgUkFURSBMSU1JVCEhIVxuICAgKiBAZGVmYXVsdCA1MzAwXG4gICAqL1xuICBzcGF3blNoYXJkRGVsYXk/OiBudW1iZXJcbiAgLyoqXG4gICAqIFdoZXRoZXIgdG8gc2VuZCB0aGUgZGlzY29yZCBwYWNrZXRzIGluIHNuYWtlIGNhc2UgZm9ybS5cbiAgICogQGRlZmF1bHQgZmFsc2VcbiAgICovXG4gIHByZWZlclNuYWtlQ2FzZT86IGJvb2xlYW5cbiAgLyoqXG4gICAqIFRvdGFsIGFtb3VudCBvZiBzaGFyZHMgeW91ciBib3QgdXNlcy4gVXNlZnVsIGZvciB6ZXJvLWRvd250aW1lIHVwZGF0ZXMgb3IgcmVzaGFyZGluZy5cbiAgICogQGRlZmF1bHQgMVxuICAgKi9cbiAgdG90YWxTaGFyZHM/OiBudW1iZXJcbiAgLyoqXG4gICAqIFRoZSBhbW91bnQgb2Ygc2hhcmRzIHRvIGxvYWQgcGVyIHdvcmtlci5cbiAgICogQGRlZmF1bHQgMjVcbiAgICovXG4gIHNoYXJkc1Blcldvcmtlcj86IG51bWJlclxuICAvKipcbiAgICogVGhlIHRvdGFsIGFtb3VudCBvZiB3b3JrZXJzIHRvIHVzZSBmb3IgeW91ciBib3QuXG4gICAqIEBkZWZhdWx0IDRcbiAgICovXG4gIHRvdGFsV29ya2Vycz86IG51bWJlclxuICAvKiogSW1wb3J0YW50IGRhdGEgd2hpY2ggaXMgdXNlZCBieSB0aGUgbWFuYWdlciB0byBjb25uZWN0IHNoYXJkcyB0byB0aGUgZ2F0ZXdheS4gKi9cbiAgY29ubmVjdGlvbj86IENhbWVsaXplPERpc2NvcmRHZXRHYXRld2F5Qm90PlxuICAvKiogV2hldGhlciBpbmNvbWluZyBwYXlsb2FkcyBhcmUgY29tcHJlc3NlZCB1c2luZyB6bGliLlxuICAgKlxuICAgKiBAZGVmYXVsdCBmYWxzZVxuICAgKi9cbiAgY29tcHJlc3M/OiBib29sZWFuXG4gIC8qKiBXaGF0IHRyYW5zcG9ydCBjb21wcmVzc2lvbiBzaG91bGQgYmUgdXNlZCAqL1xuICB0cmFuc3BvcnRDb21wcmVzc2lvbj86IFRyYW5zcG9ydENvbXByZXNzaW9uIHwgbnVsbFxuICAvKiogVGhlIGNhbGN1bGF0ZWQgaW50ZW50IHZhbHVlIG9mIHRoZSBldmVudHMgd2hpY2ggdGhlIHNoYXJkIHNob3VsZCByZWNlaXZlLlxuICAgKlxuICAgKiBAZGVmYXVsdCAwXG4gICAqL1xuICBpbnRlbnRzPzogbnVtYmVyXG4gIC8qKiBJZGVudGlmeSBwcm9wZXJ0aWVzIHRvIHVzZSAqL1xuICBwcm9wZXJ0aWVzPzoge1xuICAgIC8qKiBPcGVyYXRpbmcgc3lzdGVtIHRoZSBzaGFyZCBydW5zIG9uLlxuICAgICAqXG4gICAgICogQGRlZmF1bHQgXCJkYXJ3aW5cIiB8IFwibGludXhcIiB8IFwid2luZG93c1wiXG4gICAgICovXG4gICAgb3M6IHN0cmluZ1xuICAgIC8qKiBUaGUgXCJicm93c2VyXCIgd2hlcmUgdGhpcyBzaGFyZCBpcyBydW5uaW5nIG9uLlxuICAgICAqXG4gICAgICogQGRlZmF1bHQgXCJEaXNjb3JkZW5vXCJcbiAgICAgKi9cbiAgICBicm93c2VyOiBzdHJpbmdcbiAgICAvKiogVGhlIGRldmljZSBvbiB3aGljaCB0aGUgc2hhcmQgaXMgcnVubmluZy5cbiAgICAgKlxuICAgICAqIEBkZWZhdWx0IFwiRGlzY29yZGVub1wiXG4gICAgICovXG4gICAgZGV2aWNlOiBzdHJpbmdcbiAgfVxuICAvKiogQm90IHRva2VuIHdoaWNoIGlzIHVzZWQgdG8gY29ubmVjdCB0byBEaXNjb3JkICovXG4gIHRva2VuOiBzdHJpbmdcbiAgLyoqIFRoZSBVUkwgb2YgdGhlIGdhdGV3YXkgd2hpY2ggc2hvdWxkIGJlIGNvbm5lY3RlZCB0by5cbiAgICpcbiAgICogQGRlZmF1bHQgXCJ3c3M6Ly9nYXRld2F5LmRpc2NvcmQuZ2dcIlxuICAgKi9cbiAgdXJsPzogc3RyaW5nXG4gIC8qKiBUaGUgZ2F0ZXdheSB2ZXJzaW9uIHdoaWNoIHNob3VsZCBiZSB1c2VkLlxuICAgKlxuICAgKiBAZGVmYXVsdCAxMFxuICAgKi9cbiAgdmVyc2lvbj86IG51bWJlclxuICAvKiogVGhlIGV2ZW50cyBoYW5kbGVycyAqL1xuICBldmVudHM/OiBTaGFyZEV2ZW50c1xuICAvKiogVGhpcyBtYW5hZ2VycyBjYWNoZSByZWxhdGVkIHNldHRpbmdzLiAqL1xuICBjYWNoZT86IHtcbiAgICByZXF1ZXN0TWVtYmVycz86IHtcbiAgICAgIC8qKlxuICAgICAgICogV2hldGhlciBvciBub3QgcmVxdWVzdCBtZW1iZXIgcmVxdWVzdHMgc2hvdWxkIGJlIGNhY2hlZC5cbiAgICAgICAqIEBkZWZhdWx0IGZhbHNlXG4gICAgICAgKi9cbiAgICAgIGVuYWJsZWQ/OiBib29sZWFuXG4gICAgfVxuICB9XG4gIC8qKlxuICAgKiBUaGUgbG9nZ2VyIHRoYXQgdGhlIGdhdGV3YXkgbWFuYWdlciB3aWxsIHVzZS5cbiAgICogQGRlZmF1bHQgbG9nZ2VyIC8vIFRoZSBsb2dnZXIgZXhwb3J0ZWQgYnkgYEBkaXNjb3JkZW5vL3V0aWxzYFxuICAgKi9cbiAgbG9nZ2VyPzogUGljazx0eXBlb2YgbG9nZ2VyLCAnZGVidWcnIHwgJ2luZm8nIHwgJ3dhcm4nIHwgJ2Vycm9yJyB8ICdmYXRhbCc+XG4gIC8qKlxuICAgKiBNYWtlIHRoZSBwcmVzZW5jZSBmb3Igd2hlbiB0aGUgYm90IGNvbm5lY3RzIHRvIHRoZSBnYXRld2F5XG4gICAqXG4gICAqIEByZW1hcmtzXG4gICAqIFRoaXMgZnVuY3Rpb24gd2lsbCBiZSBjYWxsZWQgZWFjaCB0aW1lIGEgU2hhcmQgaXMgZ29pbmcgdG8gaWRlbnRpZnlcbiAgICovXG4gIG1ha2VQcmVzZW5jZT86ICgpID0+IFByb21pc2U8Qm90U3RhdHVzVXBkYXRlIHwgdW5kZWZpbmVkPlxuICAvKiogT3B0aW9ucyByZWxhdGVkIHRvIHJlc2hhcmRpbmcuICovXG4gIHJlc2hhcmRpbmc/OiB7XG4gICAgLyoqXG4gICAgICogV2hldGhlciBvciBub3QgYXV0b21hdGVkIHJlc2hhcmRpbmcgc2hvdWxkIGJlIGVuYWJsZWQuXG4gICAgICogQGRlZmF1bHQgdHJ1ZVxuICAgICAqL1xuICAgIGVuYWJsZWQ6IGJvb2xlYW5cbiAgICAvKipcbiAgICAgKiBUaGUgJSBvZiBob3cgZnVsbCBhIHNoYXJkIGlzIHdoZW4gcmVzaGFyZGluZyBzaG91bGQgYmUgdHJpZ2dlcmVkLlxuICAgICAqXG4gICAgICogQHJlbWFya3NcbiAgICAgKiBXZSB1c2UgZGlzY29yZCByZWNvbW1lbmRlZCBzaGFyZCB2YWx1ZSB0byBnZXQgYW4gKiphcHByb3hpbWF0aW9uKiogb2YgdGhlIHNoYXJkIGZ1bGwgcGVyY2VudGFnZSB0byBjb21wYXJlIHdpdGggdGhpcyB2YWx1ZSBzbyB0aGUgYm90IG1heSBub3QgcmVzaGFyZCBhdCB0aGUgZXhhY3QgcGVyY2VudGFnZSBwcm92aWRlZCBidXQgbWF5IHJlc2hhcmQgd2hlbiBpdCBpcyBhIGJpdCBoaWdoZXIgdGhhbiB0aGUgcHJvdmlkZWQgcGVyY2VudGFnZS5cbiAgICAgKiBGb3IgYWNjdXJhdGUgY2FsY3VsYXRpb24sIHlvdSBtYXkgb3ZlcnJpZGUgdGhlIGBjaGVja0lmUmVzaGFyZGluZ0lzTmVlZGVkYCBmdW5jdGlvblxuICAgICAqXG4gICAgICogQGRlZmF1bHQgODAgYXMgaW4gODAlXG4gICAgICovXG4gICAgc2hhcmRzRnVsbFBlcmNlbnRhZ2U6IG51bWJlclxuICAgIC8qKlxuICAgICAqIFRoZSBpbnRlcnZhbCBpbiBtaWxsaXNlY29uZHMsIG9mIGhvdyBvZnRlbiB0byBjaGVjayB3aGV0aGVyIHJlc2hhcmRpbmcgaXMgbmVlZGVkIGFuZCByZXNoYXJkIGF1dG9tYXRpY2FsbHkuIFNldCB0byAtMSB0byBkaXNhYmxlIGF1dG8gcmVzaGFyZGluZy5cbiAgICAgKiBAZGVmYXVsdCAyODgwMDAwMCAoOCBob3VycylcbiAgICAgKi9cbiAgICBjaGVja0ludGVydmFsOiBudW1iZXJcbiAgICAvKiogSGFuZGxlciB0byBnZXQgc2hhcmQgY291bnQgYW5kIG90aGVyIHNlc3Npb24gaW5mby4gKi9cbiAgICBnZXRTZXNzaW9uSW5mbz86ICgpID0+IFByb21pc2U8Q2FtZWxpemU8RGlzY29yZEdldEdhdGV3YXlCb3Q+PlxuICAgIC8qKiBIYW5kbGVyIHRvIGVkaXQgdGhlIHNoYXJkIGlkIG9uIGFueSBjYWNoZWQgZ3VpbGRzLiAqL1xuICAgIHVwZGF0ZUd1aWxkc1NoYXJkSWQ/OiAoZ3VpbGRJZHM6IHN0cmluZ1tdLCBzaGFyZElkOiBudW1iZXIpID0+IFByb21pc2U8dm9pZD5cbiAgfVxufVxuXG5leHBvcnQgaW50ZXJmYWNlIEdhdGV3YXlNYW5hZ2VyIGV4dGVuZHMgUmVxdWlyZWQ8Q3JlYXRlR2F0ZXdheU1hbmFnZXJPcHRpb25zPiB7XG4gIC8qKiBUaGUgbWF4IGNvbmN1cnJlbmN5IGJ1Y2tldHMuIFRob3NlIHdpbGwgYmUgY3JlYXRlZCB3aGVuIHRoZSBgc3Bhd25TaGFyZHNgICh3aGljaCBjYWxscyBgcHJlcGFyZUJ1Y2tldHNgIHVuZGVyIHRoZSBob29kKSBmdW5jdGlvbiBnZXRzIGNhbGxlZC4gKi9cbiAgYnVja2V0czogTWFwPFxuICAgIG51bWJlcixcbiAgICB7XG4gICAgICB3b3JrZXJzOiBBcnJheTx7IGlkOiBudW1iZXI7IHF1ZXVlOiBudW1iZXJbXSB9PlxuICAgICAgLyoqIFJlcXVlc3RzIHRvIGlkZW50aWZ5IHNoYXJkcyBhcmUgbWFkZSBiYXNlZCBvbiB3aGV0aGVyIGl0IGlzIGF2YWlsYWJsZSB0byBiZSBtYWRlLiAqL1xuICAgICAgaWRlbnRpZnlSZXF1ZXN0czogQXJyYXk8KHZhbHVlOiB2b2lkIHwgUHJvbWlzZUxpa2U8dm9pZD4pID0+IHZvaWQ+XG4gICAgfVxuICA+XG4gIC8qKiBUaGUgc2hhcmRzIHRoYXQgYXJlIGNyZWF0ZWQuICovXG4gIHNoYXJkczogTWFwPG51bWJlciwgU2hhcmQ+XG4gIC8qKiBUaGUgbG9nZ2VyIGZvciB0aGUgZ2F0ZXdheSBtYW5hZ2VyLiAqL1xuICBsb2dnZXI6IFBpY2s8dHlwZW9mIGxvZ2dlciwgJ2RlYnVnJyB8ICdpbmZvJyB8ICd3YXJuJyB8ICdlcnJvcicgfCAnZmF0YWwnPlxuICAvKiogRXZlcnl0aGluZyByZWxhdGVkIHRvIHJlc2hhcmRpbmcuICovXG4gIHJlc2hhcmRpbmc6IENyZWF0ZUdhdGV3YXlNYW5hZ2VyT3B0aW9uc1sncmVzaGFyZGluZyddICYge1xuICAgIC8qKlxuICAgICAqIFRoZSBpbnRlcnZhbCBpZCBvZiB0aGUgY2hlY2sgaW50ZXJ2YWwuIFRoaXMgaXMgdXNlZCB0byBjbGVhciB0aGUgaW50ZXJ2YWwgd2hlbiB0aGUgbWFuYWdlciBpcyBzaHV0ZG93bi5cbiAgICAgKi9cbiAgICBjaGVja0ludGVydmFsSWQ/OiBOb2RlSlMuVGltZW91dCB8IHVuZGVmaW5lZFxuICAgIC8qKiBIb2xkcyB0aGUgc2hhcmRzIHRoYXQgcmVzaGFyZGluZyBoYXMgY3JlYXRlZC4gT25jZSByZXNoYXJkaW5nIGlzIGRvbmUsIHRoaXMgcmVwbGFjZXMgdGhlIGdhdGV3YXkuc2hhcmRzICovXG4gICAgc2hhcmRzOiBDb2xsZWN0aW9uPG51bWJlciwgU2hhcmQ+XG4gICAgLyoqIEhvbGRzIHRoZSBwZW5kaW5nIHNoYXJkcyB0aGF0IGhhdmUgYmVlbiBjcmVhdGVkIGFuZCBhcmUgcGVuZGluZyBhbGwgc2hhcmRzIGZpbmlzaCBsb2FkaW5nLiAqL1xuICAgIHBlbmRpbmdTaGFyZHM6IENvbGxlY3Rpb248bnVtYmVyLCBTaGFyZD5cbiAgICAvKiogSGFuZGxlciB0byBjaGVjayBpZiByZXNoYXJkaW5nIGlzIG5lY2Vzc2FyeS4gKi9cbiAgICBjaGVja0lmUmVzaGFyZGluZ0lzTmVlZGVkOiAoKSA9PiBQcm9taXNlPHsgbmVlZGVkOiBib29sZWFuOyBpbmZvPzogQ2FtZWxpemU8RGlzY29yZEdldEdhdGV3YXlCb3Q+IH0+XG4gICAgLyoqIEhhbmRsZXIgdG8gYmVnaW4gcmVzaGFyZGluZy4gKi9cbiAgICByZXNoYXJkOiAoaW5mbzogQ2FtZWxpemU8RGlzY29yZEdldEdhdGV3YXlCb3Q+ICYgeyBmaXJzdFNoYXJkSWQ/OiBudW1iZXI7IGxhc3RTaGFyZElkPzogbnVtYmVyIH0pID0+IFByb21pc2U8dm9pZD5cbiAgICAvKiogSGFuZGxlciB0byBjb21tdW5pY2F0ZSB0byBhIHdvcmtlciB0aGF0IGEgc2hhcmQgbmVlZHMgdG8gYmUgY3JlYXRlZC4gKi9cbiAgICB0ZWxsV29ya2VyVG9QcmVwYXJlOiAod29ya2VySWQ6IG51bWJlciwgc2hhcmRJZDogbnVtYmVyLCBidWNrZXRJZDogbnVtYmVyKSA9PiBQcm9taXNlPHZvaWQ+XG4gICAgLyoqIEhhbmRsZXIgdG8gYWxlcnQgdGhlIGdhdGV3YXkgdGhhdCBhIHNoYXJkKHJlc2hhcmRlZCkgaXMgb25saW5lLiBJdCBzaG91bGQgbm93IHdhaXQgZm9yIGFsbCBzaGFyZHMgdG8gYmUgcGVuZGluZyBiZWZvcmUgc2h1dHRpbmcgb2ZmIG9sZCBzaGFyZHMuICovXG4gICAgc2hhcmRJc1BlbmRpbmc6IChzaGFyZDogU2hhcmQpID0+IFByb21pc2U8dm9pZD5cbiAgfVxuICAvKiogRGV0ZXJtaW5lIG1heCBudW1iZXIgb2Ygc2hhcmRzIHRvIHVzZSBiYXNlZCB1cG9uIHRoZSBtYXggY29uY3VycmVuY3kuICovXG4gIGNhbGN1bGF0ZVRvdGFsU2hhcmRzOiAoKSA9PiBudW1iZXJcbiAgLyoqIERldGVybWluZSB0aGUgaWQgb2YgdGhlIHdvcmtlciB3aGljaCBpcyBoYW5kbGluZyBhIHNoYXJkLiAqL1xuICBjYWxjdWxhdGVXb3JrZXJJZDogKHNoYXJkSWQ6IG51bWJlcikgPT4gbnVtYmVyXG4gIC8qKiBQcmVwYXJlcyBhbGwgdGhlIGJ1Y2tldHMgdGhhdCBhcmUgYXZhaWxhYmxlIGZvciBpZGVudGlmeWluZyB0aGUgc2hhcmRzLiAqL1xuICBwcmVwYXJlQnVja2V0czogKCkgPT4gdm9pZFxuICAvKiogU3RhcnQgaWRlbnRpZnlpbmcgYWxsIHRoZSBzaGFyZHMuICovXG4gIHNwYXduU2hhcmRzOiAoKSA9PiBQcm9taXNlPHZvaWQ+XG4gIC8qKiBTaHV0ZG93biBhbGwgc2hhcmRzLiAqL1xuICBzaHV0ZG93bjogKGNvZGU6IG51bWJlciwgcmVhc29uOiBzdHJpbmcsIGNsZWFyUmVzaGFyZGluZ0ludGVydmFsPzogYm9vbGVhbikgPT4gUHJvbWlzZTx2b2lkPlxuICBzZW5kUGF5bG9hZDogKHNoYXJkSWQ6IG51bWJlciwgcGF5bG9hZDogU2hhcmRTb2NrZXRSZXF1ZXN0KSA9PiBQcm9taXNlPHZvaWQ+XG4gIC8qKiBBbGxvd3MgdXNlcnMgdG8gaG9vayBpbiBhbmQgY2hhbmdlIHRvIGNvbW11bmljYXRlIHRvIGRpZmZlcmVudCB3b3JrZXJzIGFjcm9zcyBkaWZmZXJlbnQgc2VydmVycyBvciBhbnl0aGluZyB0aGV5IGxpa2UuIEZvciBleGFtcGxlIHVzaW5nIHJlZGlzIHB1YnN1YiB0byB0YWxrIHRvIG90aGVyIHNlcnZlcnMuICovXG4gIHRlbGxXb3JrZXJUb0lkZW50aWZ5OiAod29ya2VySWQ6IG51bWJlciwgc2hhcmRJZDogbnVtYmVyLCBidWNrZXRJZDogbnVtYmVyKSA9PiBQcm9taXNlPHZvaWQ+XG4gIC8qKiBUZWxsIHRoZSBtYW5hZ2VyIHRvIGlkZW50aWZ5IGEgU2hhcmQuIElmIHRoaXMgU2hhcmQgaXMgbm90IGFscmVhZHkgbWFuYWdlZCB0aGlzIHdpbGwgYWxzbyBhZGQgdGhlIFNoYXJkIHRvIHRoZSBtYW5hZ2VyLiAqL1xuICBpZGVudGlmeTogKHNoYXJkSWQ6IG51bWJlcikgPT4gUHJvbWlzZTx2b2lkPlxuICAvKiogS2lsbCBhIHNoYXJkLiBDbG9zZSBhIHNoYXJkcyBjb25uZWN0aW9uIHRvIERpc2NvcmQncyBnYXRld2F5IChpZiBhbnkpIGFuZCByZW1vdmUgaXQgZnJvbSB0aGUgbWFuYWdlci4gKi9cbiAga2lsbDogKHNoYXJkSWQ6IG51bWJlcikgPT4gUHJvbWlzZTx2b2lkPlxuICAvKiogVGhpcyBmdW5jdGlvbiBtYWtlcyBzdXJlIHRoYXQgdGhlIGJ1Y2tldCBpcyBhbGxvd2VkIHRvIG1ha2UgdGhlIG5leHQgaWRlbnRpZnkgcmVxdWVzdC4gKi9cbiAgcmVxdWVzdElkZW50aWZ5OiAoc2hhcmRJZDogbnVtYmVyKSA9PiBQcm9taXNlPHZvaWQ+XG4gIC8qKiBDYWxjdWxhdGVzIHRoZSBudW1iZXIgb2Ygc2hhcmRzIGJhc2VkIG9uIHRoZSBndWlsZCBpZCBhbmQgdG90YWwgc2hhcmRzLiAqL1xuICBjYWxjdWxhdGVTaGFyZElkOiAoZ3VpbGRJZDogQmlnU3RyaW5nLCB0b3RhbFNoYXJkcz86IG51bWJlcikgPT4gbnVtYmVyXG4gIC8qKlxuICAgKiBDb25uZWN0cyB0aGUgYm90IHVzZXIgdG8gYSB2b2ljZSBvciBzdGFnZSBjaGFubmVsLlxuICAgKlxuICAgKiBUaGlzIGZ1bmN0aW9uIHNlbmRzIHRoZSBfVXBkYXRlIFZvaWNlIFN0YXRlXyBnYXRld2F5IGNvbW1hbmQgb3ZlciB0aGUgZ2F0ZXdheSBiZWhpbmQgdGhlIHNjZW5lcy5cbiAgICpcbiAgICogQHBhcmFtIGd1aWxkSWQgLSBUaGUgSUQgb2YgdGhlIGd1aWxkIHRoZSB2b2ljZSBjaGFubmVsIHRvIGxlYXZlIGlzIGluLlxuICAgKiBAcGFyYW0gY2hhbm5lbElkIC0gVGhlIElEIG9mIHRoZSBjaGFubmVsIHlvdSB3YW50IHRvIGpvaW4uXG4gICAqXG4gICAqIEByZW1hcmtzXG4gICAqIFJlcXVpcmVzIHRoZSBgQ09OTkVDVGAgcGVybWlzc2lvbi5cbiAgICpcbiAgICogRmlyZXMgYSBfVm9pY2UgU3RhdGUgVXBkYXRlXyBnYXRld2F5IGV2ZW50LlxuICAgKlxuICAgKiBAc2VlIHtAbGluayBodHRwczovL2Rpc2NvcmQuY29tL2RldmVsb3BlcnMvZG9jcy90b3BpY3MvZ2F0ZXdheSN1cGRhdGUtdm9pY2Utc3RhdGV9XG4gICAqL1xuICBqb2luVm9pY2VDaGFubmVsOiAoZ3VpbGRJZDogQmlnU3RyaW5nLCBjaGFubmVsSWQ6IEJpZ1N0cmluZywgb3B0aW9ucz86IEF0TGVhc3RPbmU8T21pdDxVcGRhdGVWb2ljZVN0YXRlLCAnZ3VpbGRJZCcgfCAnY2hhbm5lbElkJz4+KSA9PiBQcm9taXNlPHZvaWQ+XG4gIC8qKlxuICAgKiBFZGl0cyB0aGUgYm90IHN0YXR1cyBpbiBhbGwgc2hhcmRzIHRoYXQgdGhpcyBnYXRld2F5IG1hbmFnZXMuXG4gICAqXG4gICAqIEBwYXJhbSBkYXRhIFRoZSBzdGF0dXMgZGF0YSB0byBzZXQgdGhlIGJvdHMgc3RhdHVzIHRvLlxuICAgKiBAcmV0dXJucyBub3RoaW5nXG4gICAqL1xuICBlZGl0Qm90U3RhdHVzOiAoZGF0YTogU3RhdHVzVXBkYXRlKSA9PiBQcm9taXNlPHZvaWQ+XG4gIC8qKlxuICAgKiBFZGl0cyB0aGUgYm90J3Mgc3RhdHVzIG9uIG9uZSBzaGFyZC5cbiAgICpcbiAgICogQHBhcmFtIHNoYXJkSWQgVGhlIHNoYXJkIGlkIHRvIGVkaXQgdGhlIHN0YXR1cyBmb3IuXG4gICAqIEBwYXJhbSBkYXRhIFRoZSBzdGF0dXMgZGF0YSB0byBzZXQgdGhlIGJvdHMgc3RhdHVzIHRvLlxuICAgKiBAcmV0dXJucyBub3RoaW5nXG4gICAqL1xuICBlZGl0U2hhcmRTdGF0dXM6IChzaGFyZElkOiBudW1iZXIsIGRhdGE6IFN0YXR1c1VwZGF0ZSkgPT4gUHJvbWlzZTx2b2lkPlxuICAvKipcbiAgICogRmV0Y2hlcyB0aGUgbGlzdCBvZiBtZW1iZXJzIGZvciBhIGd1aWxkIG92ZXIgdGhlIGdhdGV3YXkuIElmIGBnYXRld2F5LmNhY2hlLnJlcXVlc3RNZW1iZXJzLmVuYWJsZWRgIGlzIG5vdCBzZXQsIHRoaXMgZnVuY3Rpb24gd2lsbCByZXR1cm4gYW4gZW1wdHkgYXJyYXkgYW5kIHlvdSdsbCBoYXZlIHRvIGhhbmRsZSB0aGUgYEdVSUxEX01FTUJFUlNfQ0hVTktgIGV2ZW50cyB5b3Vyc2VsZi5cbiAgICpcbiAgICogQHBhcmFtIGd1aWxkSWQgLSBUaGUgSUQgb2YgdGhlIGd1aWxkIHRvIGdldCB0aGUgbGlzdCBvZiBtZW1iZXJzIGZvci5cbiAgICogQHBhcmFtIG9wdGlvbnMgLSBUaGUgcGFyYW1ldGVycyBmb3IgdGhlIGZldGNoaW5nIG9mIHRoZSBtZW1iZXJzLlxuICAgKlxuICAgKiBAcmVtYXJrc1xuICAgKiBJZiByZXF1ZXN0aW5nIHRoZSBlbnRpcmUgbWVtYmVyIGxpc3Q6XG4gICAqIC0gUmVxdWlyZXMgdGhlIGBHVUlMRF9NRU1CRVJTYCBpbnRlbnQuXG4gICAqXG4gICAqIElmIHJlcXVlc3RpbmcgcHJlc2VuY2VzICh7QGxpbmsgUmVxdWVzdEd1aWxkTWVtYmVycy5wcmVzZW5jZXMgfCBwcmVzZW5jZXN9IHNldCB0byBgdHJ1ZWApOlxuICAgKiAtIFJlcXVpcmVzIHRoZSBgR1VJTERfUFJFU0VOQ0VTYCBpbnRlbnQuXG4gICAqXG4gICAqIElmIHJlcXVlc3RpbmcgYSBwcmVmaXggKHtAbGluayBSZXF1ZXN0R3VpbGRNZW1iZXJzLnF1ZXJ5IHwgcXVlcnl9IG5vbi1gdW5kZWZpbmVkYCk6XG4gICAqIC0gUmV0dXJucyBhIG1heGltdW0gb2YgMTAwIG1lbWJlcnMuXG4gICAqXG4gICAqIElmIHJlcXVlc3RpbmcgYSB1c2VycyBieSBJRCAoe0BsaW5rIFJlcXVlc3RHdWlsZE1lbWJlcnMudXNlcklkcyB8IHVzZXJJZHN9IG5vbi1gdW5kZWZpbmVkYCk6XG4gICAqIC0gUmV0dXJucyBhIG1heGltdW0gb2YgMTAwIG1lbWJlcnMuXG4gICAqXG4gICAqIEZpcmVzIGEgX0d1aWxkIE1lbWJlcnMgQ2h1bmtfIGdhdGV3YXkgZXZlbnQgZm9yIGV2ZXJ5IDEwMDAgbWVtYmVycyBmZXRjaGVkLlxuICAgKlxuICAgKiBAc2VlIHtAbGluayBodHRwczovL2Rpc2NvcmQuY29tL2RldmVsb3BlcnMvZG9jcy90b3BpY3MvZ2F0ZXdheSNyZXF1ZXN0LWd1aWxkLW1lbWJlcnN9XG4gICAqL1xuICByZXF1ZXN0TWVtYmVyczogKGd1aWxkSWQ6IEJpZ1N0cmluZywgb3B0aW9ucz86IE9taXQ8UmVxdWVzdEd1aWxkTWVtYmVycywgJ2d1aWxkSWQnPikgPT4gUHJvbWlzZTxDYW1lbGl6ZTxEaXNjb3JkTWVtYmVyV2l0aFVzZXJbXT4+XG4gIC8qKlxuICAgKiBMZWF2ZXMgdGhlIHZvaWNlIGNoYW5uZWwgdGhlIGJvdCB1c2VyIGlzIGN1cnJlbnRseSBpbi5cbiAgICpcbiAgICogVGhpcyBmdW5jdGlvbiBzZW5kcyB0aGUgX1VwZGF0ZSBWb2ljZSBTdGF0ZV8gZ2F0ZXdheSBjb21tYW5kIG92ZXIgdGhlIGdhdGV3YXkgYmVoaW5kIHRoZSBzY2VuZXMuXG4gICAqXG4gICAqIEBwYXJhbSBndWlsZElkIC0gVGhlIElEIG9mIHRoZSBndWlsZCB0aGUgdm9pY2UgY2hhbm5lbCB0byBsZWF2ZSBpcyBpbi5cbiAgICpcbiAgICogQHJlbWFya3NcbiAgICogRmlyZXMgYSBfVm9pY2UgU3RhdGUgVXBkYXRlXyBnYXRld2F5IGV2ZW50LlxuICAgKlxuICAgKiBAc2VlIHtAbGluayBodHRwczovL2Rpc2NvcmQuY29tL2RldmVsb3BlcnMvZG9jcy90b3BpY3MvZ2F0ZXdheSN1cGRhdGUtdm9pY2Utc3RhdGV9XG4gICAqL1xuICBsZWF2ZVZvaWNlQ2hhbm5lbDogKGd1aWxkSWQ6IEJpZ1N0cmluZykgPT4gUHJvbWlzZTx2b2lkPlxuICAvKipcbiAgICogVXNlZCB0byByZXF1ZXN0IHNvdW5kYm9hcmQgc291bmRzIGZvciBhIGxpc3Qgb2YgZ3VpbGRzLlxuICAgKlxuICAgKiBUaGlzIGZ1bmN0aW9uIHNlbmRzIG11bHRpcGxlIChzZWUgcmVtYXJrcykgX1JlcXVlc3QgU291bmRib2FyZCBTb3VuZHNfIGdhdGV3YXkgY29tbWFuZCBvdmVyIHRoZSBnYXRld2F5IGJlaGluZCB0aGUgc2NlbmVzLlxuICAgKlxuICAgKiBAcGFyYW0gZ3VpbGRJZHMgLSBUaGUgZ3VpbGRzIHRvIGdldCB0aGUgc291bmRzIGZyb21cbiAgICpcbiAgICogQHJlbWFya3NcbiAgICogRmlyZXMgYSBfU291bmRib2FyZCBTb3VuZHNfIGdhdGV3YXkgZXZlbnQuXG4gICAqXG4gICAqIOKaoO+4jyBEaXNjb3JkIHdpbGwgc2VuZCB0aGUgX1NvdW5kYm9hcmQgU291bmRzXyBmb3IgZWFjaCBvZiB0aGUgZ3VpbGQgaWRzXG4gICAqIGhvd2V2ZXIgeW91IG1heSBub3QgcmVjZWl2ZSB0aGUgc2FtZSBudW1iZXIgb2YgZXZlbnRzIGFzIHRoZSBpZHMgcGFzc2VkIHRvIF9SZXF1ZXN0IFNvdW5kYm9hcmQgU291bmRzXyBmb3Igb25lIG9mIHRoZSBmb2xsb3dpbmcgcmVhc29uczpcbiAgICogLSBUaGUgYm90IGlzIG5vdCBpbiB0aGUgc2VydmVyIHByb3ZpZGVkXG4gICAqIC0gVGhlIHNoYXJkIHRoZSBtZXNzYWdlIGhhcyBiZWVuIHNlbnQgZnJvbSBkb2VzIG5vdCByZWNlaXZlIGV2ZW50cyBmb3IgdGhlIHNwZWNpZmllZCBndWlsZFxuICAgKlxuICAgKiBUbyBhdm9pZCB0aGlzIERpc2NvcmRlbm8gd2lsbCBhdXRvbWF0aWNhbGx5IHRyeSB0byBncm91cCB0aGUgaWRzIGJhc2VkIG9uIHdoYXQgc2hhcmQgdGhleSB3aWxsIG5lZWQgdG8gYmUgc2VudCwgYnV0IHRoaXMgaW52b2x2ZXMgc2VuZGluZyBtdWx0aXBsZSBtZXNzYWdlcyBpbiBtdWx0aXBsZSBzaGFyZHNcbiAgICpcbiAgICogQHNlZSB7QGxpbmsgaHR0cHM6Ly9kaXNjb3JkLmNvbS9kZXZlbG9wZXJzL2RvY3MvdG9waWNzL2dhdGV3YXktZXZlbnRzI3JlcXVlc3Qtc291bmRib2FyZC1zb3VuZHN9XG4gICAqL1xuICByZXF1ZXN0U291bmRib2FyZFNvdW5kczogKGd1aWxkSWRzOiBCaWdTdHJpbmdbXSkgPT4gUHJvbWlzZTx2b2lkPlxuICAvKiogVGhpcyBtYW5hZ2VycyBjYWNoZSByZWxhdGVkIHNldHRpbmdzLiAqL1xuICBjYWNoZToge1xuICAgIHJlcXVlc3RNZW1iZXJzOiB7XG4gICAgICAvKipcbiAgICAgICAqIFdoZXRoZXIgb3Igbm90IHJlcXVlc3QgbWVtYmVyIHJlcXVlc3RzIHNob3VsZCBiZSBjYWNoZWQuXG4gICAgICAgKiBAZGVmYXVsdCBmYWxzZVxuICAgICAgICovXG4gICAgICBlbmFibGVkOiBib29sZWFuXG4gICAgICAvKiogVGhlIHBlbmRpbmcgcmVxdWVzdHMuICovXG4gICAgICBwZW5kaW5nOiBDb2xsZWN0aW9uPHN0cmluZywgUmVxdWVzdE1lbWJlclJlcXVlc3Q+XG4gICAgfVxuICB9XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUmVxdWVzdE1lbWJlclJlcXVlc3Qge1xuICAvKiogVGhlIHVuaXF1ZSBub25jZSBmb3IgdGhpcyByZXF1ZXN0LiAqL1xuICBub25jZTogc3RyaW5nXG4gIC8qKiBUaGUgcmVzb2x2ZXIgaGFuZGxlciB0byBydW4gd2hlbiBhbGwgbWVtYmVycyBhcnJpdmUuICovXG4gIHJlc29sdmU6ICh2YWx1ZTogQ2FtZWxpemU8RGlzY29yZE1lbWJlcldpdGhVc2VyW10+IHwgUHJvbWlzZUxpa2U8Q2FtZWxpemU8RGlzY29yZE1lbWJlcldpdGhVc2VyW10+PikgPT4gdm9pZFxuICAvKiogVGhlIG1lbWJlcnMgdGhhdCBoYXZlIGFscmVhZHkgYXJyaXZlZCBmb3IgdGhpcyByZXF1ZXN0LiAqL1xuICBtZW1iZXJzOiBEaXNjb3JkTWVtYmVyV2l0aFVzZXJbXVxufVxuIl0sIm5hbWVzIjpbImNyZWF0ZUdhdGV3YXlNYW5hZ2VyIiwib3B0aW9ucyIsImNvbm5lY3Rpb25PcHRpb25zIiwiY29ubmVjdGlvbiIsInVybCIsInNoYXJkcyIsInNlc3Npb25TdGFydExpbWl0IiwibWF4Q29uY3VycmVuY3kiLCJyZW1haW5pbmciLCJ0b3RhbCIsInJlc2V0QWZ0ZXIiLCJnYXRld2F5IiwiZXZlbnRzIiwiY29tcHJlc3MiLCJ0cmFuc3BvcnRDb21wcmVzc2lvbiIsImludGVudHMiLCJwcm9wZXJ0aWVzIiwib3MiLCJwcm9jZXNzIiwicGxhdGZvcm0iLCJicm93c2VyIiwiZGV2aWNlIiwidG9rZW4iLCJ2ZXJzaW9uIiwidG90YWxTaGFyZHMiLCJsYXN0U2hhcmRJZCIsImZpcnN0U2hhcmRJZCIsInRvdGFsV29ya2VycyIsInNoYXJkc1BlcldvcmtlciIsInNwYXduU2hhcmREZWxheSIsInByZWZlclNuYWtlQ2FzZSIsIk1hcCIsImJ1Y2tldHMiLCJjYWNoZSIsInJlcXVlc3RNZW1iZXJzIiwiZW5hYmxlZCIsInBlbmRpbmciLCJDb2xsZWN0aW9uIiwibG9nZ2VyIiwibWFrZVByZXNlbmNlIiwiUHJvbWlzZSIsInJlc29sdmUiLCJ1bmRlZmluZWQiLCJyZXNoYXJkaW5nIiwic2hhcmRzRnVsbFBlcmNlbnRhZ2UiLCJjaGVja0ludGVydmFsIiwicGVuZGluZ1NoYXJkcyIsImdldFNlc3Npb25JbmZvIiwidXBkYXRlR3VpbGRzU2hhcmRJZCIsImNoZWNrSWZSZXNoYXJkaW5nSXNOZWVkZWQiLCJkZWJ1ZyIsIm5lZWRlZCIsIkVycm9yIiwic2Vzc2lvbkluZm8iLCJKU09OIiwic3RyaW5naWZ5IiwiaW5mbyIsInBlcmNlbnRhZ2UiLCJyZXNoYXJkIiwiY2FsY3VsYXRlVG90YWxTaGFyZHMiLCJjbGVhciIsInByZXBhcmVCdWNrZXRzIiwiZm9yRWFjaCIsImJ1Y2tldCIsImJ1Y2tldElkIiwid29ya2VyIiwid29ya2VycyIsInNoYXJkSWQiLCJxdWV1ZSIsInRlbGxXb3JrZXJUb1ByZXBhcmUiLCJpZCIsIndvcmtlcklkIiwic2hhcmQiLCJTaGFyZCIsIm1lc3NhZ2UiLCJfc2hhcmQiLCJwYXlsb2FkIiwidCIsImQiLCJndWlsZHMiLCJtYXAiLCJnIiwicmVxdWVzdElkZW50aWZ5IiwiaWRlbnRpZnkiLCJzaGFyZElzUmVhZHkiLCJkZWxheSIsImdldCIsImlkZW50aWZ5UmVxdWVzdHMiLCJzaGlmdCIsImZvcndhcmRUb0JvdCIsInNldCIsInB1c2giLCJ0aGVuIiwic2hhcmRJc1BlbmRpbmciLCJzaXplIiwidmFsdWVzIiwiZXZlbnQiLCJvbGRIYW5kbGVyIiwiXyIsInNodXRkb3duIiwiU2hhcmRTb2NrZXRDbG9zZUNvZGVzIiwiUmVzaGFyZGVkIiwiTWF0aCIsImNlaWwiLCJjYWxjdWxhdGVXb3JrZXJJZCIsIm1pbiIsImkiLCJmaW5kIiwidyIsInNvcnQiLCJhIiwiYiIsInNwYXduU2hhcmRzIiwiYWxsIiwiZW50cmllcyIsInRlbGxXb3JrZXJUb0lkZW50aWZ5IiwiY2xlYXJJbnRlcnZhbCIsImNoZWNrSW50ZXJ2YWxJZCIsIndhcm4iLCJzZXRJbnRlcnZhbCIsInJlc2hhcmRpbmdJbmZvIiwiY29kZSIsInJlYXNvbiIsImNsZWFyUmVzaGFyZGluZ0ludGVydmFsIiwiQXJyYXkiLCJmcm9tIiwiY2xvc2UiLCJzZW5kUGF5bG9hZCIsInNlbmQiLCJraWxsIiwiZGVsZXRlIiwiX3NoYXJkSWQiLCJjYWxjdWxhdGVTaGFyZElkIiwiZ3VpbGRJZCIsIk51bWJlciIsIkJpZ0ludCIsImpvaW5Wb2ljZUNoYW5uZWwiLCJjaGFubmVsSWQiLCJvcCIsIkdhdGV3YXlPcGNvZGVzIiwiVm9pY2VTdGF0ZVVwZGF0ZSIsImd1aWxkX2lkIiwidG9TdHJpbmciLCJjaGFubmVsX2lkIiwic2VsZl9tdXRlIiwic2VsZk11dGUiLCJzZWxmX2RlYWYiLCJzZWxmRGVhZiIsImVkaXRCb3RTdGF0dXMiLCJkYXRhIiwiZWRpdFNoYXJkU3RhdHVzIiwiUHJlc2VuY2VVcGRhdGUiLCJzaW5jZSIsImFmayIsImFjdGl2aXRpZXMiLCJzdGF0dXMiLCJsaW1pdCIsIkdhdGV3YXlJbnRlbnRzIiwiR3VpbGRNZW1iZXJzIiwidXNlcklkcyIsImxlbmd0aCIsIm5vbmNlIiwiaGFzIiwicmFuZG9tQnl0ZXMiLCJtZW1iZXJzIiwicmVqZWN0IiwiUmVxdWVzdEd1aWxkTWVtYmVycyIsInF1ZXJ5IiwicHJlc2VuY2VzIiwidXNlcl9pZHMiLCJsZWF2ZVZvaWNlQ2hhbm5lbCIsInJlcXVlc3RTb3VuZGJvYXJkU291bmRzIiwiZ3VpbGRJZHMiLCJpZHMiLCJSZXF1ZXN0U291bmRib2FyZFNvdW5kcyIsImd1aWxkX2lkcyJdLCJtYXBwaW5ncyI6Ijs7OzsrQkF3QmdCQTs7O2VBQUFBOzs7NEJBeEJZO3VCQVdyQjt1QkFDbUM7OERBQ3hCO3dCQVNYOzs7Ozs7QUFFQSxTQUFTQSxxQkFBcUJDLE9BQW9DO0lBQ3ZFLE1BQU1DLG9CQUFvQkQsUUFBUUUsVUFBVSxJQUFJO1FBQzlDQyxLQUFLO1FBQ0xDLFFBQVE7UUFDUkMsbUJBQW1CO1lBQ2pCQyxnQkFBZ0I7WUFDaEJDLFdBQVc7WUFDWEMsT0FBTztZQUNQQyxZQUFZLE9BQU8sS0FBSyxLQUFLO1FBQy9CO0lBQ0Y7SUFFQSxNQUFNQyxVQUEwQjtRQUM5QkMsUUFBUVgsUUFBUVcsTUFBTSxJQUFJLENBQUM7UUFDM0JDLFVBQVVaLFFBQVFZLFFBQVEsSUFBSTtRQUM5QkMsc0JBQXNCYixRQUFRYSxvQkFBb0IsSUFBSTtRQUN0REMsU0FBU2QsUUFBUWMsT0FBTyxJQUFJO1FBQzVCQyxZQUFZO1lBQ1ZDLElBQUloQixRQUFRZSxVQUFVLEVBQUVDLE1BQU1DLFFBQVFDLFFBQVE7WUFDOUNDLFNBQVNuQixRQUFRZSxVQUFVLEVBQUVJLFdBQVc7WUFDeENDLFFBQVFwQixRQUFRZSxVQUFVLEVBQUVLLFVBQVU7UUFDeEM7UUFDQUMsT0FBT3JCLFFBQVFxQixLQUFLO1FBQ3BCbEIsS0FBS0gsUUFBUUcsR0FBRyxJQUFJRixrQkFBa0JFLEdBQUcsSUFBSTtRQUM3Q21CLFNBQVN0QixRQUFRc0IsT0FBTyxJQUFJO1FBQzVCcEIsWUFBWUQ7UUFDWnNCLGFBQWF2QixRQUFRdUIsV0FBVyxJQUFJdEIsa0JBQWtCRyxNQUFNLElBQUk7UUFDaEVvQixhQUFheEIsUUFBUXdCLFdBQVcsSUFBS3hCLENBQUFBLFFBQVF1QixXQUFXLEdBQUd2QixRQUFRdUIsV0FBVyxHQUFHLElBQUl0QixvQkFBb0JBLGtCQUFrQkcsTUFBTSxHQUFHLElBQUksQ0FBQTtRQUN4SXFCLGNBQWN6QixRQUFReUIsWUFBWSxJQUFJO1FBQ3RDQyxjQUFjMUIsUUFBUTBCLFlBQVksSUFBSTtRQUN0Q0MsaUJBQWlCM0IsUUFBUTJCLGVBQWUsSUFBSTtRQUM1Q0MsaUJBQWlCNUIsUUFBUTRCLGVBQWUsSUFBSTtRQUM1Q0MsaUJBQWlCN0IsUUFBUTZCLGVBQWUsSUFBSTtRQUM1Q3pCLFFBQVEsSUFBSTBCO1FBQ1pDLFNBQVMsSUFBSUQ7UUFDYkUsT0FBTztZQUNMQyxnQkFBZ0I7Z0JBQ2RDLFNBQVNsQyxRQUFRZ0MsS0FBSyxFQUFFQyxnQkFBZ0JDLFdBQVc7Z0JBQ25EQyxTQUFTLElBQUlDLGlCQUFVO1lBQ3pCO1FBQ0Y7UUFDQUMsUUFBUXJDLFFBQVFxQyxNQUFNLElBQUlBLGFBQU07UUFDaENDLGNBQWN0QyxRQUFRc0MsWUFBWSxJQUFLLENBQUEsSUFBTUMsUUFBUUMsT0FBTyxDQUFDQyxVQUFTO1FBQ3RFQyxZQUFZO1lBQ1ZSLFNBQVNsQyxRQUFRMEMsVUFBVSxFQUFFUixXQUFXO1lBQ3hDUyxzQkFBc0IzQyxRQUFRMEMsVUFBVSxFQUFFQyx3QkFBd0I7WUFDbEVDLGVBQWU1QyxRQUFRMEMsVUFBVSxFQUFFRSxpQkFBaUI7WUFDcER4QyxRQUFRLElBQUlnQyxpQkFBVTtZQUN0QlMsZUFBZSxJQUFJVCxpQkFBVTtZQUM3QlUsZ0JBQWdCOUMsUUFBUTBDLFVBQVUsRUFBRUk7WUFDcENDLHFCQUFxQi9DLFFBQVEwQyxVQUFVLEVBQUVLO1lBQ3pDLE1BQU1DO2dCQUNKdEMsUUFBUTJCLE1BQU0sQ0FBQ1ksS0FBSyxDQUFDO2dCQUVyQixJQUFJLENBQUN2QyxRQUFRZ0MsVUFBVSxDQUFDUixPQUFPLEVBQUU7b0JBQy9CeEIsUUFBUTJCLE1BQU0sQ0FBQ1ksS0FBSyxDQUFDO29CQUVyQixPQUFPO3dCQUFFQyxRQUFRO29CQUFNO2dCQUN6QjtnQkFFQSxJQUFJLENBQUN4QyxRQUFRZ0MsVUFBVSxDQUFDSSxjQUFjLEVBQUU7b0JBQ3RDLE1BQU0sSUFBSUssTUFBTTtnQkFDbEI7Z0JBRUF6QyxRQUFRMkIsTUFBTSxDQUFDWSxLQUFLLENBQUM7Z0JBRXJCLE1BQU1HLGNBQWMsTUFBTTFDLFFBQVFnQyxVQUFVLENBQUNJLGNBQWM7Z0JBRTNEcEMsUUFBUTJCLE1BQU0sQ0FBQ1ksS0FBSyxDQUFDLENBQUMscUNBQXFDLEVBQUVJLEtBQUtDLFNBQVMsQ0FBQ0YsY0FBYztnQkFFMUYsc0RBQXNEO2dCQUN0RCxJQUFJQSxZQUFZL0MsaUJBQWlCLENBQUNFLFNBQVMsR0FBRzZDLFlBQVloRCxNQUFNLEVBQUU7b0JBQ2hFTSxRQUFRMkIsTUFBTSxDQUFDWSxLQUFLLENBQUM7b0JBRXJCLE9BQU87d0JBQUVDLFFBQVE7d0JBQU9LLE1BQU1IO29CQUFZO2dCQUM1QztnQkFFQTFDLFFBQVEyQixNQUFNLENBQUNZLEtBQUssQ0FBQztnQkFFckIsNkRBQTZEO2dCQUM3RCx1RkFBdUY7Z0JBQ3ZGLGlFQUFpRTtnQkFDakUsaUhBQWlIO2dCQUNqSCx3SUFBd0k7Z0JBQ3hJLE1BQU1PLGFBQWEsQUFBQ0osWUFBWWhELE1BQU0sR0FBSSxDQUFBLEFBQUNNLFFBQVFhLFdBQVcsR0FBRyxPQUFRLElBQUcsSUFBTTtnQkFFbEYsZ0RBQWdEO2dCQUNoRCxJQUFJaUMsYUFBYTlDLFFBQVFnQyxVQUFVLENBQUNDLG9CQUFvQixFQUFFO29CQUN4RGpDLFFBQVEyQixNQUFNLENBQUNZLEtBQUssQ0FBQztvQkFFckIsT0FBTzt3QkFBRUMsUUFBUTt3QkFBT0ssTUFBTUg7b0JBQVk7Z0JBQzVDO2dCQUVBMUMsUUFBUTJCLE1BQU0sQ0FBQ2tCLElBQUksQ0FBQztnQkFFcEIsT0FBTztvQkFBRUwsUUFBUTtvQkFBTUssTUFBTUg7Z0JBQVk7WUFDM0M7WUFDQSxNQUFNSyxTQUFRRixJQUFJO2dCQUNoQjdDLFFBQVEyQixNQUFNLENBQUNrQixJQUFJLENBQUMsQ0FBQyxrRUFBa0UsRUFBRTdDLFFBQVFhLFdBQVcsRUFBRTtnQkFDOUcsd0JBQXdCO2dCQUN4QmIsUUFBUWEsV0FBVyxHQUFHZ0MsS0FBS25ELE1BQU07Z0JBQ2pDLDJDQUEyQztnQkFDM0NNLFFBQVFhLFdBQVcsR0FBR2IsUUFBUWdELG9CQUFvQjtnQkFDbEQseUNBQXlDO2dCQUN6QyxJQUFJLE9BQU9ILEtBQUs5QixZQUFZLEtBQUssVUFBVWYsUUFBUWUsWUFBWSxHQUFHOEIsS0FBSzlCLFlBQVk7Z0JBQ25GLHdDQUF3QztnQkFDeEMsSUFBSSxPQUFPOEIsS0FBSy9CLFdBQVcsS0FBSyxVQUFVZCxRQUFRYyxXQUFXLEdBQUcrQixLQUFLL0IsV0FBVztnQkFDaEZkLFFBQVEyQixNQUFNLENBQUNrQixJQUFJLENBQUMsQ0FBQyw2REFBNkQsRUFBRTdDLFFBQVFhLFdBQVcsRUFBRTtnQkFFekcsb0JBQW9CO2dCQUNwQmIsUUFBUXFCLE9BQU8sQ0FBQzRCLEtBQUs7Z0JBQ3JCLG9DQUFvQztnQkFDcENqRCxRQUFRa0QsY0FBYztnQkFFdEIsNERBQTREO2dCQUM1RGxELFFBQVFxQixPQUFPLENBQUM4QixPQUFPLENBQUMsT0FBT0MsUUFBUUM7b0JBQ3JDLEtBQUssTUFBTUMsVUFBVUYsT0FBT0csT0FBTyxDQUFFO3dCQUNuQyxLQUFLLE1BQU1DLFdBQVdGLE9BQU9HLEtBQUssQ0FBRTs0QkFDbEMsTUFBTXpELFFBQVFnQyxVQUFVLENBQUMwQixtQkFBbUIsQ0FBQ0osT0FBT0ssRUFBRSxFQUFFSCxTQUFTSDt3QkFDbkU7b0JBQ0Y7Z0JBQ0Y7WUFDRjtZQUNBLE1BQU1LLHFCQUFvQkUsUUFBUSxFQUFFSixPQUFPLEVBQUVILFFBQVE7Z0JBQ25EckQsUUFBUTJCLE1BQU0sQ0FBQ1ksS0FBSyxDQUFDLENBQUMsZ0RBQWdELEVBQUVxQixTQUFTLFVBQVUsRUFBRUosUUFBUSxXQUFXLEVBQUVILFNBQVMsQ0FBQyxDQUFDO2dCQUM3SCxNQUFNUSxRQUFRLElBQUlDLGNBQUssQ0FBQztvQkFDdEJILElBQUlIO29CQUNKaEUsWUFBWTt3QkFDVlUsVUFBVUYsUUFBUUUsUUFBUTt3QkFDMUJDLHNCQUFzQkgsUUFBUUcsb0JBQW9CLElBQUk7d0JBQ3REQyxTQUFTSixRQUFRSSxPQUFPO3dCQUN4QkMsWUFBWUwsUUFBUUssVUFBVTt3QkFDOUJNLE9BQU9YLFFBQVFXLEtBQUs7d0JBQ3BCRSxhQUFhYixRQUFRYSxXQUFXO3dCQUNoQ3BCLEtBQUtPLFFBQVFQLEdBQUc7d0JBQ2hCbUIsU0FBU1osUUFBUVksT0FBTztvQkFDMUI7b0JBQ0EsbUNBQW1DO29CQUNuQ1gsUUFBUTt3QkFDTixNQUFNOEQsU0FBUUMsTUFBTSxFQUFFQyxPQUFPOzRCQUMzQixJQUFJQSxRQUFRQyxDQUFDLEtBQUssU0FBUztnQ0FDekIsTUFBTWxFLFFBQVFnQyxVQUFVLENBQUNLLG1CQUFtQixHQUMxQyxBQUFDNEIsUUFBUUUsQ0FBQyxDQUFrQkMsTUFBTSxDQUFDQyxHQUFHLENBQUMsQ0FBQ0MsSUFBTUEsRUFBRVgsRUFBRSxHQUNsREg7NEJBRUo7d0JBQ0Y7b0JBQ0Y7b0JBQ0E3QixRQUFRM0IsUUFBUTJCLE1BQU07b0JBQ3RCNEMsaUJBQWlCO3dCQUNmLE1BQU12RSxRQUFRd0UsUUFBUSxDQUFDaEI7b0JBQ3pCO29CQUNBaUIsY0FBYzt3QkFDWnpFLFFBQVEyQixNQUFNLENBQUNZLEtBQUssQ0FBQyxDQUFDLGVBQWUsRUFBRWlCLFFBQVEsU0FBUyxDQUFDO3dCQUN6RCxNQUFNa0IsSUFBQUEsWUFBSyxFQUFDMUUsUUFBUWtCLGVBQWU7d0JBQ25DbEIsUUFBUTJCLE1BQU0sQ0FBQ1ksS0FBSyxDQUFDLENBQUMsd0NBQXdDLENBQUM7d0JBQy9EdkMsUUFBUXFCLE9BQU8sQ0FBQ3NELEdBQUcsQ0FBQ25CLFVBQVV4RCxRQUFRUixVQUFVLENBQUNHLGlCQUFpQixDQUFDQyxjQUFjLEVBQUdnRixnQkFBZ0IsQ0FBQ0MsS0FBSztvQkFDNUc7b0JBQ0FqRCxjQUFjNUIsUUFBUTRCLFlBQVk7Z0JBQ3BDO2dCQUVBLElBQUk1QixRQUFRbUIsZUFBZSxFQUFFO29CQUMzQjBDLE1BQU1pQixZQUFZLEdBQUcsT0FBT2I7d0JBQzFCSixNQUFNNUQsTUFBTSxFQUFFOEQsVUFBVUYsT0FBT0k7b0JBQ2pDO2dCQUNGO2dCQUVBakUsUUFBUWdDLFVBQVUsQ0FBQ3RDLE1BQU0sQ0FBQ3FGLEdBQUcsQ0FBQ3ZCLFNBQVNLO2dCQUV2QyxNQUFNVCxTQUFTcEQsUUFBUXFCLE9BQU8sQ0FBQ3NELEdBQUcsQ0FBQ25CLFVBQVV4RCxRQUFRUixVQUFVLENBQUNHLGlCQUFpQixDQUFDQyxjQUFjO2dCQUNoRyxJQUFJLENBQUN3RCxRQUFRO2dCQUViLE9BQU8sTUFBTSxJQUFJdkIsUUFBUSxDQUFDQztvQkFDeEIsc0VBQXNFO29CQUN0RXNCLE9BQU93QixnQkFBZ0IsQ0FBQ0ksSUFBSSxDQUFDbEQ7b0JBQzdCOUIsUUFBUTJCLE1BQU0sQ0FBQ1ksS0FBSyxDQUFDLENBQUMsNkJBQTZCLEVBQUVpQixRQUFRLENBQUMsQ0FBQztvQkFDL0QsMkZBQTJGO29CQUMzRkssT0FBT1csV0FBV1MsS0FBSzt3QkFDckIsNkNBQTZDO3dCQUM3QyxPQUFPLE1BQU1qRixRQUFRZ0MsVUFBVSxDQUFDa0QsY0FBYyxDQUFDckI7b0JBQ2pEO2dCQUNGO1lBQ0Y7WUFDQSxNQUFNcUIsZ0JBQWVyQixLQUFLO2dCQUN4QixrRUFBa0U7Z0JBQ2xFN0QsUUFBUWdDLFVBQVUsQ0FBQ0csYUFBYSxDQUFDNEMsR0FBRyxDQUFDbEIsTUFBTUYsRUFBRSxFQUFFRTtnQkFDL0M3RCxRQUFRMkIsTUFBTSxDQUFDWSxLQUFLLENBQUMsQ0FBQyxvQkFBb0IsRUFBRXNCLE1BQU1GLEVBQUUsQ0FBQyxnQkFBZ0IsQ0FBQztnQkFFdEUsc0NBQXNDO2dCQUN0QyxJQUFJM0QsUUFBUWMsV0FBVyxHQUFHZCxRQUFRZSxZQUFZLElBQUlmLFFBQVFnQyxVQUFVLENBQUNHLGFBQWEsQ0FBQ2dELElBQUksRUFBRTtnQkFFekZuRixRQUFRMkIsTUFBTSxDQUFDa0IsSUFBSSxDQUFDLENBQUMsdUNBQXVDLENBQUM7Z0JBRTdELHFDQUFxQztnQkFDckMsS0FBSyxNQUFNZ0IsU0FBUzdELFFBQVFnQyxVQUFVLENBQUN0QyxNQUFNLENBQUMwRixNQUFNLEdBQUk7b0JBQ3RELElBQUssTUFBTUMsU0FBUy9GLFFBQVFXLE1BQU0sQ0FBRTt3QkFDbEM0RCxNQUFNNUQsTUFBTSxDQUFDb0YsTUFBMkIsR0FBRy9GLFFBQVFXLE1BQU0sQ0FBQ29GLE1BQTJCO29CQUN2RjtnQkFDRjtnQkFFQSxvQ0FBb0M7Z0JBQ3BDLEtBQUssTUFBTXhCLFNBQVM3RCxRQUFRTixNQUFNLENBQUMwRixNQUFNLEdBQUk7b0JBQzNDLE1BQU1FLGFBQWF6QixNQUFNNUQsTUFBTSxDQUFDOEQsT0FBTztvQkFFdkMsbUtBQW1LO29CQUNuS0YsTUFBTTVELE1BQU0sR0FBRzt3QkFDYixHQUFHNEQsTUFBTTVELE1BQU07d0JBQ2Y4RCxTQUFTLGVBQWdCd0IsQ0FBQyxFQUFFeEIsT0FBTzs0QkFDakMscURBQXFEOzRCQUNyRCxJQUFJQSxRQUFRRyxDQUFDLEtBQUssdUJBQXVCO2dDQUN2Q29CLGFBQWF6QixPQUFPRTs0QkFDdEI7d0JBQ0Y7b0JBQ0Y7Z0JBQ0Y7Z0JBRUEvRCxRQUFRMkIsTUFBTSxDQUFDa0IsSUFBSSxDQUFDLENBQUMsc0NBQXNDLENBQUM7Z0JBQzVELG1CQUFtQjtnQkFDbkIsTUFBTTdDLFFBQVF3RixRQUFRLENBQUNDLDZCQUFxQixDQUFDQyxTQUFTLEVBQUUsY0FBYztnQkFFdEUxRixRQUFRMkIsTUFBTSxDQUFDa0IsSUFBSSxDQUFDLENBQUMsdUJBQXVCLENBQUM7Z0JBRTdDLHFCQUFxQjtnQkFDckI3QyxRQUFRTixNQUFNLEdBQUcsSUFBSWdDLGlCQUFVLENBQUMxQixRQUFRZ0MsVUFBVSxDQUFDdEMsTUFBTTtnQkFFekQsNkZBQTZGO2dCQUM3Rk0sUUFBUWdDLFVBQVUsQ0FBQ3RDLE1BQU0sQ0FBQ3VELEtBQUs7Z0JBQy9CakQsUUFBUWdDLFVBQVUsQ0FBQ0csYUFBYSxDQUFDYyxLQUFLO1lBQ3hDO1FBQ0Y7UUFFQUQ7WUFDRSxxREFBcUQ7WUFDckQsSUFBSWhELFFBQVFhLFdBQVcsR0FBRyxLQUFLO2dCQUM3QmIsUUFBUTJCLE1BQU0sQ0FBQ1ksS0FBSyxDQUFDLENBQUMsb0NBQW9DLEVBQUV2QyxRQUFRYSxXQUFXLEVBQUU7Z0JBQ2pGLE9BQU9iLFFBQVFhLFdBQVc7WUFDNUI7WUFFQWIsUUFBUTJCLE1BQU0sQ0FBQ1ksS0FBSyxDQUFDLENBQUMsa0NBQWtDLENBQUMsRUFBRXZDLFFBQVFhLFdBQVcsRUFBRWIsUUFBUVIsVUFBVSxDQUFDRyxpQkFBaUIsQ0FBQ0MsY0FBYztZQUNuSSx3RkFBd0Y7WUFDeEYsT0FDRStGLEtBQUtDLElBQUksQ0FDUDVGLFFBQVFhLFdBQVcsR0FDakIsdUpBQXVKO1lBQ3RKYixDQUFBQSxRQUFRUixVQUFVLENBQUNHLGlCQUFpQixDQUFDQyxjQUFjLEtBQUssSUFBSSxLQUFLSSxRQUFRUixVQUFVLENBQUNHLGlCQUFpQixDQUFDQyxjQUFjLEFBQUQsS0FDbkhJLENBQUFBLFFBQVFSLFVBQVUsQ0FBQ0csaUJBQWlCLENBQUNDLGNBQWMsS0FBSyxJQUFJLEtBQUtJLFFBQVFSLFVBQVUsQ0FBQ0csaUJBQWlCLENBQUNDLGNBQWMsQUFBRDtRQUU1SDtRQUNBaUcsbUJBQWtCckMsT0FBTztZQUN2QixNQUFNSSxXQUFXK0IsS0FBS0csR0FBRyxDQUFDdEMsVUFBVXhELFFBQVFpQixlQUFlLEVBQUVqQixRQUFRZ0IsWUFBWSxHQUFHO1lBQ3BGaEIsUUFBUTJCLE1BQU0sQ0FBQ1ksS0FBSyxDQUNsQixDQUFDLHVDQUF1QyxFQUFFaUIsUUFBUSxZQUFZLEVBQUVJLFNBQVMsZ0JBQWdCLEVBQUU1RCxRQUFRaUIsZUFBZSxDQUFDLFdBQVcsRUFBRWpCLFFBQVFnQixZQUFZLEVBQUU7WUFFeEosT0FBTzRDO1FBQ1Q7UUFDQVY7WUFDRSxJQUFLLElBQUk2QyxJQUFJLEdBQUdBLElBQUkvRixRQUFRUixVQUFVLENBQUNHLGlCQUFpQixDQUFDQyxjQUFjLEVBQUUsRUFBRW1HLEVBQUc7Z0JBQzVFL0YsUUFBUTJCLE1BQU0sQ0FBQ1ksS0FBSyxDQUFDLENBQUMsNkNBQTZDLEVBQUV3RCxHQUFHO2dCQUN4RS9GLFFBQVFxQixPQUFPLENBQUMwRCxHQUFHLENBQUNnQixHQUFHO29CQUNyQnhDLFNBQVMsRUFBRTtvQkFDWHFCLGtCQUFrQixFQUFFO2dCQUN0QjtZQUNGO1lBRUEsNkNBQTZDO1lBQzdDLElBQUssSUFBSXBCLFVBQVV4RCxRQUFRZSxZQUFZLEVBQUV5QyxXQUFXeEQsUUFBUWMsV0FBVyxFQUFFLEVBQUUwQyxRQUFTO2dCQUNsRnhELFFBQVEyQixNQUFNLENBQUNZLEtBQUssQ0FBQyxDQUFDLHVDQUF1QyxFQUFFaUIsU0FBUztnQkFDeEUsSUFBSUEsV0FBV3hELFFBQVFhLFdBQVcsRUFBRTtvQkFDbEMsTUFBTSxJQUFJNEIsTUFBTSxDQUFDLFdBQVcsRUFBRWUsUUFBUSxnRUFBZ0UsRUFBRXhELFFBQVFhLFdBQVcsRUFBRTtnQkFDL0g7Z0JBRUEsTUFBTXdDLFdBQVdHLFVBQVV4RCxRQUFRUixVQUFVLENBQUNHLGlCQUFpQixDQUFDQyxjQUFjO2dCQUM5RSxNQUFNd0QsU0FBU3BELFFBQVFxQixPQUFPLENBQUNzRCxHQUFHLENBQUN0QjtnQkFDbkMsSUFBSSxDQUFDRCxRQUFRO29CQUNYLE1BQU0sSUFBSVgsTUFDUixDQUFDLFdBQVcsRUFBRWUsUUFBUSx3Q0FBd0MsRUFBRUgsU0FBUyxxQ0FBcUMsRUFDNUdyRCxRQUFRUixVQUFVLENBQUNHLGlCQUFpQixDQUFDQyxjQUFjLEdBQUcsR0FDdEQ7Z0JBRU47Z0JBRUEsNkNBQTZDO2dCQUM3Qyx1RkFBdUY7Z0JBQ3ZGLE1BQU1nRSxXQUFXNUQsUUFBUTZGLGlCQUFpQixDQUFDckM7Z0JBQzNDLE1BQU1GLFNBQVNGLE9BQU9HLE9BQU8sQ0FBQ3lDLElBQUksQ0FBQyxDQUFDQyxJQUFNQSxFQUFFdEMsRUFBRSxLQUFLQztnQkFDbkQsSUFBSU4sUUFBUTtvQkFDVixtREFBbUQ7b0JBQ25EQSxPQUFPRyxLQUFLLENBQUN1QixJQUFJLENBQUN4QjtnQkFDcEIsT0FBTztvQkFDTEosT0FBT0csT0FBTyxDQUFDeUIsSUFBSSxDQUFDO3dCQUFFckIsSUFBSUM7d0JBQVVILE9BQU87NEJBQUNEO3lCQUFRO29CQUFDO2dCQUN2RDtZQUNGO1lBRUEsS0FBSyxNQUFNSixVQUFVcEQsUUFBUXFCLE9BQU8sQ0FBQytELE1BQU0sR0FBSTtnQkFDN0MsS0FBSyxNQUFNOUIsVUFBVUYsT0FBT0csT0FBTyxDQUFDNkIsTUFBTSxHQUFJO29CQUM1QzlCLE9BQU9HLEtBQUssR0FBR0gsT0FBT0csS0FBSyxDQUFDeUMsSUFBSSxDQUFDLENBQUNDLEdBQUdDLElBQU1ELElBQUlDO2dCQUNqRDtZQUNGO1FBQ0Y7UUFDQSxNQUFNQztZQUNKLDBDQUEwQztZQUMxQ3JHLFFBQVFrRCxjQUFjO1lBRXRCLGlEQUFpRDtZQUNqRCxNQUFNckIsUUFBUXlFLEdBQUcsQ0FDZjttQkFBSXRHLFFBQVFxQixPQUFPLENBQUNrRixPQUFPO2FBQUcsQ0FBQ2xDLEdBQUcsQ0FBQyxPQUFPLENBQUNoQixVQUFVRCxPQUFPO2dCQUMxRCxLQUFLLE1BQU1FLFVBQVVGLE9BQU9HLE9BQU8sQ0FBRTtvQkFDbkMsS0FBSyxNQUFNQyxXQUFXRixPQUFPRyxLQUFLLENBQUU7d0JBQ2xDLE1BQU16RCxRQUFRd0csb0JBQW9CLENBQUNsRCxPQUFPSyxFQUFFLEVBQUVILFNBQVNIO29CQUN6RDtnQkFDRjtZQUNGO1lBR0YsaUVBQWlFO1lBQ2pFLElBQUlyRCxRQUFRZ0MsVUFBVSxDQUFDUixPQUFPLElBQUl4QixRQUFRZ0MsVUFBVSxDQUFDRSxhQUFhLEtBQUssQ0FBQyxHQUFHO2dCQUN6RSxrREFBa0Q7Z0JBQ2xEdUUsY0FBY3pHLFFBQVFnQyxVQUFVLENBQUMwRSxlQUFlO2dCQUVoRCxJQUFJLENBQUMxRyxRQUFRZ0MsVUFBVSxDQUFDSSxjQUFjLEVBQUU7b0JBQ3RDcEMsUUFBUWdDLFVBQVUsQ0FBQ1IsT0FBTyxHQUFHO29CQUM3QnhCLFFBQVEyQixNQUFNLENBQUNnRixJQUFJLENBQUM7b0JBRXBCO2dCQUNGO2dCQUVBM0csUUFBUWdDLFVBQVUsQ0FBQzBFLGVBQWUsR0FBR0UsWUFBWTtvQkFDL0MsTUFBTUMsaUJBQWlCLE1BQU03RyxRQUFRZ0MsVUFBVSxDQUFDTSx5QkFBeUI7b0JBRXpFLElBQUl1RSxlQUFlckUsTUFBTSxJQUFJcUUsZUFBZWhFLElBQUksRUFBRSxNQUFNN0MsUUFBUWdDLFVBQVUsQ0FBQ2UsT0FBTyxDQUFDOEQsZUFBZWhFLElBQUk7Z0JBQ3hHLEdBQUc3QyxRQUFRZ0MsVUFBVSxDQUFDRSxhQUFhO1lBQ3JDO1FBQ0Y7UUFDQSxNQUFNc0QsVUFBU3NCLElBQUksRUFBRUMsTUFBTSxFQUFFQywwQkFBMEIsSUFBSTtZQUN6RCxJQUFJQSx5QkFBeUJQLGNBQWN6RyxRQUFRZ0MsVUFBVSxDQUFDMEUsZUFBZTtZQUU3RSxNQUFNN0UsUUFBUXlFLEdBQUcsQ0FBQ1csTUFBTUMsSUFBSSxDQUFDbEgsUUFBUU4sTUFBTSxDQUFDMEYsTUFBTSxJQUFJZixHQUFHLENBQUMsQ0FBQ1IsUUFBVUEsTUFBTXNELEtBQUssQ0FBQ0wsTUFBTUM7UUFDekY7UUFDQSxNQUFNSyxhQUFZNUQsT0FBTyxFQUFFUyxPQUFPO1lBQ2hDLE1BQU1KLFFBQVE3RCxRQUFRTixNQUFNLENBQUNpRixHQUFHLENBQUNuQjtZQUVqQyxJQUFJLENBQUNLLE9BQU87Z0JBQ1YsTUFBTSxJQUFJcEIsTUFBTSxDQUFDLFdBQVcsRUFBRWUsUUFBUSxVQUFVLENBQUM7WUFDbkQ7WUFFQSxNQUFNSyxNQUFNd0QsSUFBSSxDQUFDcEQ7UUFDbkI7UUFDQSxNQUFNdUMsc0JBQXFCNUMsUUFBUSxFQUFFSixPQUFPLEVBQUVILFFBQVE7WUFDcERyRCxRQUFRMkIsTUFBTSxDQUFDWSxLQUFLLENBQUMsQ0FBQyxtQ0FBbUMsRUFBRXFCLFNBQVMsRUFBRSxFQUFFSixRQUFRLEVBQUUsRUFBRUgsU0FBUyxDQUFDLENBQUM7WUFDL0YsTUFBTXJELFFBQVF3RSxRQUFRLENBQUNoQjtRQUN6QjtRQUNBLE1BQU1nQixVQUFTaEIsT0FBZTtZQUM1QixJQUFJSyxRQUFRLElBQUksQ0FBQ25FLE1BQU0sQ0FBQ2lGLEdBQUcsQ0FBQ25CO1lBQzVCeEQsUUFBUTJCLE1BQU0sQ0FBQ1ksS0FBSyxDQUFDLENBQUMsc0JBQXNCLEVBQUVzQixRQUFRLGFBQWEsTUFBTSxRQUFRLEVBQUVMLFFBQVEsQ0FBQyxDQUFDO1lBRTdGLElBQUksQ0FBQ0ssT0FBTztnQkFDVkEsUUFBUSxJQUFJQyxjQUFLLENBQUM7b0JBQ2hCSCxJQUFJSDtvQkFDSmhFLFlBQVk7d0JBQ1ZVLFVBQVUsSUFBSSxDQUFDQSxRQUFRO3dCQUN2QkMsc0JBQXNCSCxRQUFRRyxvQkFBb0I7d0JBQ2xEQyxTQUFTLElBQUksQ0FBQ0EsT0FBTzt3QkFDckJDLFlBQVksSUFBSSxDQUFDQSxVQUFVO3dCQUMzQk0sT0FBTyxJQUFJLENBQUNBLEtBQUs7d0JBQ2pCRSxhQUFhLElBQUksQ0FBQ0EsV0FBVzt3QkFDN0JwQixLQUFLLElBQUksQ0FBQ0EsR0FBRzt3QkFDYm1CLFNBQVMsSUFBSSxDQUFDQSxPQUFPO29CQUN2QjtvQkFDQVgsUUFBUVgsUUFBUVcsTUFBTSxJQUFJLENBQUM7b0JBQzNCMEIsUUFBUSxJQUFJLENBQUNBLE1BQU07b0JBQ25CNEMsaUJBQWlCO3dCQUNmLE1BQU12RSxRQUFRd0UsUUFBUSxDQUFDaEI7b0JBQ3pCO29CQUNBaUIsY0FBYzt3QkFDWnpFLFFBQVEyQixNQUFNLENBQUNZLEtBQUssQ0FBQyxDQUFDLGVBQWUsRUFBRWlCLFFBQVEsU0FBUyxDQUFDO3dCQUN6RCxNQUFNa0IsSUFBQUEsWUFBSyxFQUFDMUUsUUFBUWtCLGVBQWU7d0JBQ25DbEIsUUFBUTJCLE1BQU0sQ0FBQ1ksS0FBSyxDQUFDLENBQUMsd0NBQXdDLENBQUM7d0JBQy9EdkMsUUFBUXFCLE9BQU8sQ0FBQ3NELEdBQUcsQ0FBQ25CLFVBQVV4RCxRQUFRUixVQUFVLENBQUNHLGlCQUFpQixDQUFDQyxjQUFjLEVBQUdnRixnQkFBZ0IsQ0FBQ0MsS0FBSztvQkFDNUc7b0JBQ0FqRCxjQUFjNUIsUUFBUTRCLFlBQVk7Z0JBQ3BDO2dCQUVBLElBQUksSUFBSSxDQUFDVCxlQUFlLEVBQUU7b0JBQ3hCMEMsTUFBTWlCLFlBQVksR0FBRyxPQUFPYjt3QkFDMUJKLE1BQU81RCxNQUFNLENBQUM4RCxPQUFPLEdBQUdGLE9BQVFJO29CQUNsQztnQkFDRjtnQkFFQSxJQUFJLENBQUN2RSxNQUFNLENBQUNxRixHQUFHLENBQUN2QixTQUFTSztZQUMzQjtZQUVBLE1BQU1ULFNBQVNwRCxRQUFRcUIsT0FBTyxDQUFDc0QsR0FBRyxDQUFDbkIsVUFBVXhELFFBQVFSLFVBQVUsQ0FBQ0csaUJBQWlCLENBQUNDLGNBQWM7WUFDaEcsSUFBSSxDQUFDd0QsUUFBUTtZQUViLE9BQU8sTUFBTSxJQUFJdkIsUUFBUSxDQUFDQztnQkFDeEIsc0VBQXNFO2dCQUN0RXNCLE9BQU93QixnQkFBZ0IsQ0FBQ0ksSUFBSSxDQUFDbEQ7Z0JBQzdCOUIsUUFBUTJCLE1BQU0sQ0FBQ1ksS0FBSyxDQUFDLENBQUMsNkJBQTZCLEVBQUVpQixRQUFRLENBQUMsQ0FBQztnQkFDL0QsMkZBQTJGO2dCQUMzRkssT0FBT1c7WUFDVDtRQUNGO1FBQ0EsTUFBTThDLE1BQUs5RCxPQUFlO1lBQ3hCLE1BQU1LLFFBQVEsSUFBSSxDQUFDbkUsTUFBTSxDQUFDaUYsR0FBRyxDQUFDbkI7WUFDOUIsSUFBSSxDQUFDSyxPQUFPO2dCQUNWLE9BQU83RCxRQUFRMkIsTUFBTSxDQUFDWSxLQUFLLENBQUMsQ0FBQyw0QkFBNEIsRUFBRWlCLFFBQVEsZ0RBQWdELENBQUM7WUFDdEg7WUFFQXhELFFBQVEyQixNQUFNLENBQUNZLEtBQUssQ0FBQyxDQUFDLHlCQUF5QixFQUFFaUIsU0FBUztZQUMxRCxJQUFJLENBQUM5RCxNQUFNLENBQUM2SCxNQUFNLENBQUMvRDtZQUNuQixNQUFNSyxNQUFNMkIsUUFBUTtRQUN0QjtRQUNBLE1BQU1qQixpQkFBZ0JpRCxRQUFnQjtZQUNwQ3hILFFBQVEyQixNQUFNLENBQUNZLEtBQUssQ0FBQyxDQUFDLDZCQUE2QixDQUFDO1FBQ3REO1FBRUEsNkJBQTZCO1FBRTdCa0Ysa0JBQWlCQyxPQUFPLEVBQUU3RyxXQUFXO1lBQ25DLHdFQUF3RTtZQUN4RSxJQUFJLENBQUNBLGFBQWFBLGNBQWNiLFFBQVFhLFdBQVc7WUFDbkQsc0RBQXNEO1lBQ3RELElBQUlBLGdCQUFnQixHQUFHO2dCQUNyQmIsUUFBUTJCLE1BQU0sQ0FBQ1ksS0FBSyxDQUFDLENBQUMsb0NBQW9DLENBQUM7Z0JBQzNELE9BQU87WUFDVDtZQUVBdkMsUUFBUTJCLE1BQU0sQ0FBQ1ksS0FBSyxDQUFDLENBQUMscUNBQXFDLEVBQUVtRixRQUFRLGVBQWUsRUFBRTdHLFlBQVksQ0FBQyxDQUFDO1lBQ3BHLE9BQU84RyxPQUFPLEFBQUNDLENBQUFBLE9BQU9GLFlBQVksR0FBRyxBQUFELElBQUtFLE9BQU8vRztRQUNsRDtRQUVBLE1BQU1nSCxrQkFBaUJILE9BQU8sRUFBRUksU0FBUyxFQUFFeEksT0FBTztZQUNoRCxNQUFNa0UsVUFBVXhELFFBQVF5SCxnQkFBZ0IsQ0FBQ0M7WUFFekMxSCxRQUFRMkIsTUFBTSxDQUFDWSxLQUFLLENBQUMsQ0FBQyxvQ0FBb0MsRUFBRW1GLFFBQVEsWUFBWSxFQUFFSSxXQUFXO1lBRTdGLE1BQU05SCxRQUFRb0gsV0FBVyxDQUFDNUQsU0FBUztnQkFDakN1RSxJQUFJQyxxQkFBYyxDQUFDQyxnQkFBZ0I7Z0JBQ25DOUQsR0FBRztvQkFDRCtELFVBQVVSLFFBQVFTLFFBQVE7b0JBQzFCQyxZQUFZTixVQUFVSyxRQUFRO29CQUM5QkUsV0FBVy9JLFNBQVNnSixZQUFZO29CQUNoQ0MsV0FBV2pKLFNBQVNrSixZQUFZO2dCQUNsQztZQUNGO1FBQ0Y7UUFFQSxNQUFNQyxlQUFjQyxJQUFJO1lBQ3RCMUksUUFBUTJCLE1BQU0sQ0FBQ1ksS0FBSyxDQUFDLENBQUMsOEJBQThCLEVBQUVJLEtBQUtDLFNBQVMsQ0FBQzhGLE9BQU87WUFFNUUsTUFBTTdHLFFBQVF5RSxHQUFHLENBQ2Y7bUJBQUl0RyxRQUFRTixNQUFNLENBQUMwRixNQUFNO2FBQUcsQ0FBQ2YsR0FBRyxDQUFDLE9BQU9SO2dCQUN0QzdELFFBQVEySSxlQUFlLENBQUM5RSxNQUFNRixFQUFFLEVBQUUrRTtZQUNwQztRQUVKO1FBRUEsTUFBTUMsaUJBQWdCbkYsT0FBTyxFQUFFa0YsSUFBSTtZQUNqQzFJLFFBQVEyQixNQUFNLENBQUNZLEtBQUssQ0FBQyxDQUFDLG1DQUFtQyxFQUFFaUIsUUFBUSxVQUFVLEVBQUViLEtBQUtDLFNBQVMsQ0FBQzhGLE9BQU87WUFFckcsTUFBTTFJLFFBQVFvSCxXQUFXLENBQUM1RCxTQUFTO2dCQUNqQ3VFLElBQUlDLHFCQUFjLENBQUNZLGNBQWM7Z0JBQ2pDekUsR0FBRztvQkFDRDBFLE9BQU87b0JBQ1BDLEtBQUs7b0JBQ0xDLFlBQVlMLEtBQUtLLFVBQVU7b0JBQzNCQyxRQUFRTixLQUFLTSxNQUFNO2dCQUNyQjtZQUNGO1FBQ0Y7UUFFQSxNQUFNekgsZ0JBQWVtRyxPQUFPLEVBQUVwSSxPQUFPO1lBQ25DLE1BQU1rRSxVQUFVeEQsUUFBUXlILGdCQUFnQixDQUFDQztZQUV6QyxJQUFJMUgsUUFBUUksT0FBTyxJQUFLLENBQUEsQ0FBQ2QsU0FBUzJKLFNBQVMzSixRQUFRMkosS0FBSyxHQUFHLENBQUEsS0FBTSxDQUFFakosQ0FBQUEsUUFBUUksT0FBTyxHQUFHOEkscUJBQWMsQ0FBQ0MsWUFBWSxBQUFELEdBQzdHLE1BQU0sSUFBSTFHLE1BQU07WUFFbEJ6QyxRQUFRMkIsTUFBTSxDQUFDWSxLQUFLLENBQUMsQ0FBQyxrQ0FBa0MsRUFBRW1GLFFBQVEsVUFBVSxFQUFFL0UsS0FBS0MsU0FBUyxDQUFDdEQsVUFBVTtZQUV2RyxJQUFJQSxTQUFTOEosU0FBU0MsUUFBUTtnQkFDNUJySixRQUFRMkIsTUFBTSxDQUFDWSxLQUFLLENBQUMsQ0FBQyxrQ0FBa0MsRUFBRW1GLFFBQVEsZ0RBQWdELEVBQUVwSSxRQUFROEosT0FBTyxDQUFDQyxNQUFNLEVBQUU7Z0JBRTVJL0osUUFBUTJKLEtBQUssR0FBRzNKLFFBQVE4SixPQUFPLENBQUNDLE1BQU07WUFDeEM7WUFFQSxJQUFJLENBQUMvSixTQUFTZ0ssT0FBTztnQkFDbkIsSUFBSUEsUUFBUTtnQkFFWixNQUFPLENBQUNBLFNBQVN0SixRQUFRc0IsS0FBSyxDQUFDQyxjQUFjLENBQUNFLE9BQU8sQ0FBQzhILEdBQUcsQ0FBQ0QsT0FBUTtvQkFDaEVBLFFBQVFFLElBQUFBLHVCQUFXLEVBQUMsSUFBSXJCLFFBQVEsQ0FBQztnQkFDbkM7Z0JBRUE3SSxZQUFZO29CQUFFMkosT0FBTztnQkFBRTtnQkFDdkIzSixRQUFRZ0ssS0FBSyxHQUFHQTtZQUNsQjtZQUVBLE1BQU1HLFVBQVUsQ0FBQ3pKLFFBQVFzQixLQUFLLENBQUNDLGNBQWMsQ0FBQ0MsT0FBTyxHQUNqRCxFQUFFLEdBQ0YsSUFBSUssUUFBMkMsQ0FBQ0MsU0FBUzRIO2dCQUN2RCx1QkFBdUI7Z0JBQ3ZCLElBQUksQ0FBQzFKLFFBQVFzQixLQUFLLENBQUNDLGNBQWMsQ0FBQ0MsT0FBTyxJQUFJLENBQUNsQyxTQUFTZ0ssT0FBTztvQkFDNURJLE9BQU8sSUFBSWpILE1BQU07b0JBQ2pCO2dCQUNGO2dCQUVBekMsUUFBUXNCLEtBQUssQ0FBQ0MsY0FBYyxDQUFDRSxPQUFPLENBQUNzRCxHQUFHLENBQUN6RixRQUFRZ0ssS0FBSyxFQUFFO29CQUN0REEsT0FBT2hLLFFBQVFnSyxLQUFLO29CQUNwQnhIO29CQUNBMkgsU0FBUyxFQUFFO2dCQUNiO1lBQ0Y7WUFFSixNQUFNekosUUFBUW9ILFdBQVcsQ0FBQzVELFNBQVM7Z0JBQ2pDdUUsSUFBSUMscUJBQWMsQ0FBQzJCLG1CQUFtQjtnQkFDdEN4RixHQUFHO29CQUNEK0QsVUFBVVIsUUFBUVMsUUFBUTtvQkFDMUIsc0VBQXNFO29CQUN0RXlCLE9BQU90SyxTQUFTc0ssU0FBVXRLLENBQUFBLFNBQVMySixRQUFRbEgsWUFBWSxFQUFDO29CQUN4RGtILE9BQU8zSixTQUFTMkosU0FBUztvQkFDekJZLFdBQVd2SyxTQUFTdUssYUFBYTtvQkFDakNDLFVBQVV4SyxTQUFTOEosU0FBUy9FLElBQUksQ0FBQ1YsS0FBT0EsR0FBR3dFLFFBQVE7b0JBQ25EbUIsT0FBT2hLLFNBQVNnSztnQkFDbEI7WUFDRjtZQUVBLE9BQU8sTUFBTUc7UUFDZjtRQUVBLE1BQU1NLG1CQUFrQnJDLE9BQU87WUFDN0IsTUFBTWxFLFVBQVV4RCxRQUFReUgsZ0JBQWdCLENBQUNDO1lBRXpDMUgsUUFBUTJCLE1BQU0sQ0FBQ1ksS0FBSyxDQUFDLENBQUMscUNBQXFDLEVBQUVtRixRQUFRLE9BQU8sRUFBRWxFLFNBQVM7WUFFdkYsTUFBTXhELFFBQVFvSCxXQUFXLENBQUM1RCxTQUFTO2dCQUNqQ3VFLElBQUlDLHFCQUFjLENBQUNDLGdCQUFnQjtnQkFDbkM5RCxHQUFHO29CQUNEK0QsVUFBVVIsUUFBUVMsUUFBUTtvQkFDMUJDLFlBQVk7b0JBQ1pDLFdBQVc7b0JBQ1hFLFdBQVc7Z0JBQ2I7WUFDRjtRQUNGO1FBRUEsTUFBTXlCLHlCQUF3QkMsUUFBUTtZQUNwQzs7O09BR0MsR0FFRCxNQUFNNUYsTUFBTSxJQUFJakQ7WUFFaEIsS0FBSyxNQUFNc0csV0FBV3VDLFNBQVU7Z0JBQzlCLE1BQU16RyxVQUFVeEQsUUFBUXlILGdCQUFnQixDQUFDQztnQkFFekMsTUFBTXdDLE1BQU03RixJQUFJTSxHQUFHLENBQUNuQixZQUFZLEVBQUU7Z0JBQ2xDYSxJQUFJVSxHQUFHLENBQUN2QixTQUFTMEc7Z0JBRWpCQSxJQUFJbEYsSUFBSSxDQUFDMEM7WUFDWDtZQUVBLE1BQU03RixRQUFReUUsR0FBRyxDQUNmO21CQUFJakMsSUFBSWtDLE9BQU87YUFBRyxDQUFDbEMsR0FBRyxDQUFDLENBQUMsQ0FBQ2IsU0FBUzBHLElBQUksR0FDcENsSyxRQUFRb0gsV0FBVyxDQUFDNUQsU0FBUztvQkFDM0J1RSxJQUFJQyxxQkFBYyxDQUFDbUMsdUJBQXVCO29CQUMxQ2hHLEdBQUc7d0JBQ0RpRyxXQUFXRjtvQkFDYjtnQkFDRjtRQUdOO0lBQ0Y7SUFFQSxPQUFPbEs7QUFDVCJ9
|