@discordeno/gateway 19.0.0-next.e2d86ea → 19.0.0-next.e30e5a2
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/README.md +16 -13
- package/dist/cjs/Shard.cjs +490 -0
- package/dist/cjs/index.cjs +22 -0
- package/dist/cjs/manager.cjs +464 -0
- package/dist/cjs/types.cjs +41 -0
- package/dist/esm/Shard.js +467 -0
- package/dist/esm/index.js +5 -0
- package/dist/esm/manager.js +449 -0
- package/dist/esm/types.js +23 -0
- package/dist/{Shard.d.ts → types/Shard.d.ts} +12 -89
- package/dist/types/Shard.d.ts.map +1 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/{manager.d.ts → types/manager.d.ts} +74 -12
- package/dist/types/manager.d.ts.map +1 -0
- package/dist/{types.d.ts → types/types.d.ts} +1 -2
- package/dist/types/types.d.ts.map +1 -0
- package/package.json +29 -24
- package/dist/Shard.d.ts.map +0 -1
- package/dist/Shard.js +0 -615
- package/dist/Shard.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -5
- package/dist/index.js.map +0 -1
- package/dist/manager.d.ts.map +0 -1
- package/dist/manager.js +0 -243
- package/dist/manager.js.map +0 -1
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -23
- package/dist/types.js.map +0 -1
- /package/dist/{index.d.ts → types/index.d.ts} +0 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
_export_star(require("./manager.cjs"), exports);
|
|
6
|
+
_export_star(require("./Shard.cjs"), exports);
|
|
7
|
+
_export_star(require("./types.cjs"), exports);
|
|
8
|
+
function _export_star(from, to) {
|
|
9
|
+
Object.keys(from).forEach(function(k) {
|
|
10
|
+
if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) {
|
|
11
|
+
Object.defineProperty(to, k, {
|
|
12
|
+
enumerable: true,
|
|
13
|
+
get: function() {
|
|
14
|
+
return from[k];
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
return from;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9pbmRleC50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgKiBmcm9tICcuL21hbmFnZXIuanMnXG5leHBvcnQgKiBmcm9tICcuL1NoYXJkLmpzJ1xuZXhwb3J0ICogZnJvbSAnLi90eXBlcy5qcydcbiJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7O3FCQUFjO3FCQUNBO3FCQUNBIn0=
|
|
@@ -0,0 +1,464 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-confusing-void-expression */ "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 _types = require("@discordeno/types");
|
|
12
|
+
const _utils = require("@discordeno/utils");
|
|
13
|
+
const _Shard = /*#__PURE__*/ _interop_require_default(require("./Shard.cjs"));
|
|
14
|
+
const _types1 = require("./types.cjs");
|
|
15
|
+
function _interop_require_default(obj) {
|
|
16
|
+
return obj && obj.__esModule ? obj : {
|
|
17
|
+
default: obj
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function createGatewayManager(options) {
|
|
21
|
+
const connectionOptions = options.connection ?? {
|
|
22
|
+
url: 'wss://gateway.discord.gg',
|
|
23
|
+
shards: 1,
|
|
24
|
+
sessionStartLimit: {
|
|
25
|
+
maxConcurrency: 1,
|
|
26
|
+
remaining: 1000,
|
|
27
|
+
total: 1000,
|
|
28
|
+
resetAfter: 1000 * 60 * 60 * 24
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
const gateway = {
|
|
32
|
+
events: options.events ?? {},
|
|
33
|
+
compress: options.compress ?? false,
|
|
34
|
+
intents: options.intents ?? 0,
|
|
35
|
+
properties: {
|
|
36
|
+
os: options.properties?.os ?? process.platform,
|
|
37
|
+
browser: options.properties?.browser ?? 'Discordeno',
|
|
38
|
+
device: options.properties?.device ?? 'Discordeno'
|
|
39
|
+
},
|
|
40
|
+
token: options.token,
|
|
41
|
+
url: options.url ?? connectionOptions.url ?? 'wss://gateway.discord.gg',
|
|
42
|
+
version: options.version ?? 10,
|
|
43
|
+
connection: connectionOptions,
|
|
44
|
+
totalShards: options.totalShards ?? connectionOptions.shards ?? 1,
|
|
45
|
+
lastShardId: options.lastShardId ?? (options.totalShards ? options.totalShards - 1 : connectionOptions ? connectionOptions.shards - 1 : 0),
|
|
46
|
+
firstShardId: options.firstShardId ?? 0,
|
|
47
|
+
totalWorkers: options.totalWorkers ?? 4,
|
|
48
|
+
shardsPerWorker: options.shardsPerWorker ?? 25,
|
|
49
|
+
spawnShardDelay: options.spawnShardDelay ?? 5300,
|
|
50
|
+
preferSnakeCase: options.preferSnakeCase ?? false,
|
|
51
|
+
shards: new Map(),
|
|
52
|
+
buckets: new Map(),
|
|
53
|
+
cache: {
|
|
54
|
+
requestMembers: {
|
|
55
|
+
enabled: options.cache?.requestMembers?.enabled ?? false,
|
|
56
|
+
pending: new _utils.Collection()
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
logger: options.logger ?? _utils.logger,
|
|
60
|
+
resharding: {
|
|
61
|
+
enabled: true,
|
|
62
|
+
shardsFullPercentage: 80,
|
|
63
|
+
checkInterval: 28800000,
|
|
64
|
+
shards: new _utils.Collection(),
|
|
65
|
+
pendingShards: new _utils.Collection(),
|
|
66
|
+
async getSessionInfo () {
|
|
67
|
+
throw new Error('[Resharding] was enabled but no getSessionInfo handler was provided. Please set a handler like: gateway.resharding.getSessionInfo = async () => { // insert code here to fetch getSessionInfo from rest process. }');
|
|
68
|
+
},
|
|
69
|
+
async checkIfReshardingIsNeeded () {
|
|
70
|
+
_utils.logger.warn(`[Resharding] Checking if resharding is needed.`);
|
|
71
|
+
// Resharding is disabled.
|
|
72
|
+
if (!gateway.resharding.enabled) return {
|
|
73
|
+
needed: false
|
|
74
|
+
};
|
|
75
|
+
_utils.logger.warn(`[Resharding] Resharding is enabled.`);
|
|
76
|
+
const sessionInfo = await gateway.resharding.getSessionInfo();
|
|
77
|
+
_utils.logger.warn(`[Resharding] Session info retrieved.`);
|
|
78
|
+
// Don't have enough identify limits to try resharding
|
|
79
|
+
if (sessionInfo.sessionStartLimit.remaining < sessionInfo.shards) return {
|
|
80
|
+
needed: false,
|
|
81
|
+
info: sessionInfo
|
|
82
|
+
};
|
|
83
|
+
_utils.logger.warn(`[Resharding] Able to reshard, checking whether necessary now.`);
|
|
84
|
+
// 2500 is the max amount of guilds a single shard can handle
|
|
85
|
+
// 1000 is the amount of guilds discord uses to determine how many shards to recommend.
|
|
86
|
+
// This algo helps check if your bot has grown enough to reshard.
|
|
87
|
+
const percentage = 2500 * sessionInfo.shards / (gateway.totalShards * 1000) * 100;
|
|
88
|
+
// Less than necessary% being used so do nothing
|
|
89
|
+
if (percentage < gateway.resharding.shardsFullPercentage) return {
|
|
90
|
+
needed: false,
|
|
91
|
+
info: sessionInfo
|
|
92
|
+
};
|
|
93
|
+
_utils.logger.warn(`[Resharding] Resharding is needed.`);
|
|
94
|
+
return {
|
|
95
|
+
needed: true,
|
|
96
|
+
info: sessionInfo
|
|
97
|
+
};
|
|
98
|
+
},
|
|
99
|
+
async reshard (info) {
|
|
100
|
+
_utils.logger.warn(`[Resharding] Starting the reshard process. Previous total shards. ${gateway.totalShards}`);
|
|
101
|
+
// Set values on gateway
|
|
102
|
+
gateway.totalShards = info.shards;
|
|
103
|
+
// Handles preparing mid sized bots for LBS
|
|
104
|
+
gateway.totalShards = gateway.calculateTotalShards();
|
|
105
|
+
// Set first shard id if provided in info
|
|
106
|
+
if (typeof info.firstShardId === 'number') gateway.firstShardId = info.firstShardId;
|
|
107
|
+
// Set last shard id if provided in info
|
|
108
|
+
if (typeof info.lastShardId === 'number') gateway.lastShardId = info.lastShardId;
|
|
109
|
+
_utils.logger.warn(`[Resharding] Starting the reshard process. New Total Shards. ${gateway.totalShards}`);
|
|
110
|
+
// Resetting buckets
|
|
111
|
+
gateway.buckets.clear();
|
|
112
|
+
// Refilling buckets with new values
|
|
113
|
+
gateway.prepareBuckets();
|
|
114
|
+
// SPREAD THIS OUT TO DIFFERENT WORKERS TO BEGIN STARTING UP
|
|
115
|
+
gateway.buckets.forEach(async (bucket, bucketId)=>{
|
|
116
|
+
for (const worker of bucket.workers){
|
|
117
|
+
for (const shardId of worker.queue){
|
|
118
|
+
await gateway.resharding.tellWorkerToPrepare(worker.id, shardId, bucketId);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
},
|
|
123
|
+
async tellWorkerToPrepare (workerId, shardId, bucketId) {
|
|
124
|
+
_utils.logger.warn(`[Resharding] Telling worker to prepare. Worker: ${workerId} | Shard: ${shardId} | Bucket: ${bucketId}`);
|
|
125
|
+
const shard = new _Shard.default({
|
|
126
|
+
id: shardId,
|
|
127
|
+
connection: {
|
|
128
|
+
compress: gateway.compress,
|
|
129
|
+
intents: gateway.intents,
|
|
130
|
+
properties: gateway.properties,
|
|
131
|
+
token: gateway.token,
|
|
132
|
+
totalShards: gateway.totalShards,
|
|
133
|
+
url: gateway.url,
|
|
134
|
+
version: gateway.version
|
|
135
|
+
},
|
|
136
|
+
// Ignore events until we are ready
|
|
137
|
+
events: {
|
|
138
|
+
async message (_shard, payload) {
|
|
139
|
+
if (payload.t === 'READY') {
|
|
140
|
+
await gateway.resharding.updateGuildsShardId(payload.d.guilds.map((g)=>g.id), shardId);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
requestIdentify: async ()=>{
|
|
145
|
+
await gateway.identify(shardId);
|
|
146
|
+
},
|
|
147
|
+
shardIsReady: async ()=>{
|
|
148
|
+
_utils.logger.debug(`[Shard] Shard #${shardId} is ready`);
|
|
149
|
+
await (0, _utils.delay)(gateway.spawnShardDelay);
|
|
150
|
+
_utils.logger.debug(`[Shard] Resolving shard identify request`);
|
|
151
|
+
gateway.buckets.get(shardId % gateway.connection.sessionStartLimit.maxConcurrency).identifyRequests.shift()?.();
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
if (gateway.preferSnakeCase) {
|
|
155
|
+
shard.forwardToBot = async (payload)=>{
|
|
156
|
+
shard.events?.message?.(shard, payload);
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
gateway.resharding.shards.set(shardId, shard);
|
|
160
|
+
const bucket = gateway.buckets.get(shardId % gateway.connection.sessionStartLimit.maxConcurrency);
|
|
161
|
+
if (!bucket) return;
|
|
162
|
+
return await new Promise((resolve)=>{
|
|
163
|
+
// Mark that we are making an identify request so another is not made.
|
|
164
|
+
bucket.identifyRequests.push(resolve);
|
|
165
|
+
_utils.logger.debug(`[Gateway] identifying shard #(${shardId}).`);
|
|
166
|
+
// This will trigger identify and when READY is received it will resolve the above request.
|
|
167
|
+
shard?.identify().then(async ()=>{
|
|
168
|
+
// Tell the manager that this shard is online
|
|
169
|
+
return await gateway.resharding.shardIsPending(shard);
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
},
|
|
173
|
+
async updateGuildsShardId (guildIds, shardId) {
|
|
174
|
+
_utils.logger.debug(`[Resharding] Updating the following guild ids shard to #${shardId}: ${guildIds.join(', ')}. Override this function to update your cache if you need to.`);
|
|
175
|
+
},
|
|
176
|
+
async shardIsPending (shard) {
|
|
177
|
+
// Save this in pending at the moment, until all shards are online
|
|
178
|
+
gateway.resharding.pendingShards.set(shard.id, shard);
|
|
179
|
+
_utils.logger.warn(`[Resharding] Shard #${shard.id} is now pending`);
|
|
180
|
+
// Check if all shards are now online.
|
|
181
|
+
if (gateway.lastShardId - gateway.firstShardId + 1 > gateway.resharding.pendingShards.size) return;
|
|
182
|
+
_utils.logger.warn(`[Resharding] All shards are now online.`);
|
|
183
|
+
// New shards start processing events
|
|
184
|
+
for (const shard of gateway.resharding.pendingShards.values()){
|
|
185
|
+
for(const event in options.events){
|
|
186
|
+
// @ts-expect-error fixing this seems complex and doesnt seem worth it, feel free to fix if you wish
|
|
187
|
+
shard.events[event] = options.events[event];
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
// Old shards stop processing events
|
|
191
|
+
for (const shard of gateway.shards.values()){
|
|
192
|
+
const oldHandler = shard.events.message;
|
|
193
|
+
// 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
|
|
194
|
+
shard.events = {
|
|
195
|
+
...shard.events,
|
|
196
|
+
message: async function(_, message) {
|
|
197
|
+
// Member checks need to continue but others can stop
|
|
198
|
+
if (message.t !== 'GUILD_MEMBERS_CHUNK') return;
|
|
199
|
+
// Process only the chunking events
|
|
200
|
+
oldHandler?.(shard, message);
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
_utils.logger.warn(`[Resharding] Shutting down old shards.`);
|
|
205
|
+
// Close old shards
|
|
206
|
+
await gateway.shutdown(_types1.ShardSocketCloseCodes.Resharded, 'Resharded!', false);
|
|
207
|
+
_utils.logger.warn(`[Resharding] Completed.`);
|
|
208
|
+
// Replace old shards
|
|
209
|
+
gateway.shards = gateway.resharding.shards;
|
|
210
|
+
}
|
|
211
|
+
},
|
|
212
|
+
calculateTotalShards () {
|
|
213
|
+
// Bots under 100k servers do not have access to LBS.
|
|
214
|
+
if (gateway.totalShards < 100) {
|
|
215
|
+
gateway.logger.debug(`[Gateway] Calculating total shards: ${gateway.totalShards}`);
|
|
216
|
+
return gateway.totalShards;
|
|
217
|
+
}
|
|
218
|
+
gateway.logger.debug(`[Gateway] Calculating total shards`, gateway.totalShards, gateway.connection.sessionStartLimit.maxConcurrency);
|
|
219
|
+
// Calculate a multiple of `maxConcurrency` which can be used to connect to the gateway.
|
|
220
|
+
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.
|
|
221
|
+
(gateway.connection.sessionStartLimit.maxConcurrency === 1 ? 16 : gateway.connection.sessionStartLimit.maxConcurrency)) * (gateway.connection.sessionStartLimit.maxConcurrency === 1 ? 16 : gateway.connection.sessionStartLimit.maxConcurrency);
|
|
222
|
+
},
|
|
223
|
+
calculateWorkerId (shardId) {
|
|
224
|
+
const workerId = Math.min(shardId % gateway.shardsPerWorker, gateway.totalWorkers - 1);
|
|
225
|
+
gateway.logger.debug(`[Gateway] Calculating workerId: Shard: ${shardId} -> Worker: ${workerId} -> Per Worker: ${gateway.shardsPerWorker} -> Total: ${gateway.totalWorkers}`);
|
|
226
|
+
return workerId;
|
|
227
|
+
},
|
|
228
|
+
prepareBuckets () {
|
|
229
|
+
for(let i = 0; i < gateway.connection.sessionStartLimit.maxConcurrency; ++i){
|
|
230
|
+
gateway.logger.debug(`[Gateway] Preparing buckets for concurrency: ${i}`);
|
|
231
|
+
gateway.buckets.set(i, {
|
|
232
|
+
workers: [],
|
|
233
|
+
identifyRequests: []
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
// ORGANIZE ALL SHARDS INTO THEIR OWN BUCKETS
|
|
237
|
+
for(let shardId = gateway.firstShardId; shardId <= gateway.lastShardId; ++shardId){
|
|
238
|
+
gateway.logger.debug(`[Gateway] Preparing buckets for shard: ${shardId}`);
|
|
239
|
+
if (shardId >= gateway.totalShards) {
|
|
240
|
+
throw new Error(`Shard (id: ${shardId}) is bigger or equal to the used amount of used shards which is ${gateway.totalShards}`);
|
|
241
|
+
}
|
|
242
|
+
const bucketId = shardId % gateway.connection.sessionStartLimit.maxConcurrency;
|
|
243
|
+
const bucket = gateway.buckets.get(bucketId);
|
|
244
|
+
if (!bucket) {
|
|
245
|
+
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}`);
|
|
246
|
+
}
|
|
247
|
+
// FIND A QUEUE IN THIS BUCKET THAT HAS SPACE
|
|
248
|
+
// const worker = bucket.workers.find((w) => w.queue.length < gateway.shardsPerWorker);
|
|
249
|
+
const workerId = gateway.calculateWorkerId(shardId);
|
|
250
|
+
const worker = bucket.workers.find((w)=>w.id === workerId);
|
|
251
|
+
if (worker) {
|
|
252
|
+
// IF THE QUEUE HAS SPACE JUST ADD IT TO THIS QUEUE
|
|
253
|
+
worker.queue.push(shardId);
|
|
254
|
+
} else {
|
|
255
|
+
bucket.workers.push({
|
|
256
|
+
id: workerId,
|
|
257
|
+
queue: [
|
|
258
|
+
shardId
|
|
259
|
+
]
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
for (const bucket of gateway.buckets.values()){
|
|
264
|
+
for (const worker of bucket.workers.values()){
|
|
265
|
+
// eslint-disable-next-line @typescript-eslint/require-array-sort-compare
|
|
266
|
+
worker.queue = worker.queue.sort((a, b)=>a - b);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
},
|
|
270
|
+
async spawnShards () {
|
|
271
|
+
// PREPARES ALL SHARDS IN SPECIFIC BUCKETS
|
|
272
|
+
gateway.prepareBuckets();
|
|
273
|
+
// Prefer concurrency of forEach instead of forof
|
|
274
|
+
await Promise.all([
|
|
275
|
+
...gateway.buckets.entries()
|
|
276
|
+
].map(async ([bucketId, bucket])=>{
|
|
277
|
+
for (const worker of bucket.workers){
|
|
278
|
+
for (const shardId of worker.queue){
|
|
279
|
+
await gateway.tellWorkerToIdentify(worker.id, shardId, bucketId);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}));
|
|
283
|
+
// Check and reshard automatically if auto resharding is enabled.
|
|
284
|
+
if (gateway.resharding.enabled && gateway.resharding.checkInterval !== -1) {
|
|
285
|
+
gateway.resharding.checkIntervalId = setInterval(async ()=>{
|
|
286
|
+
const reshardingInfo = await gateway.resharding.checkIfReshardingIsNeeded();
|
|
287
|
+
if (reshardingInfo.needed && reshardingInfo.info) await gateway.resharding.reshard(reshardingInfo.info);
|
|
288
|
+
}, gateway.resharding.checkInterval);
|
|
289
|
+
}
|
|
290
|
+
},
|
|
291
|
+
async shutdown (code, reason, clearReshardingInterval = true) {
|
|
292
|
+
gateway.shards.forEach((shard)=>shard.close(code, reason));
|
|
293
|
+
if (clearReshardingInterval && gateway.resharding.checkIntervalId) clearInterval(gateway.resharding.checkIntervalId);
|
|
294
|
+
await (0, _utils.delay)(5000);
|
|
295
|
+
},
|
|
296
|
+
async sendPayload (shardId, payload) {
|
|
297
|
+
const shard = gateway.shards.get(shardId);
|
|
298
|
+
if (!shard) {
|
|
299
|
+
throw new Error(`Shard (id: ${shardId} not found`);
|
|
300
|
+
}
|
|
301
|
+
await shard.send(payload);
|
|
302
|
+
},
|
|
303
|
+
async tellWorkerToIdentify (workerId, shardId, bucketId) {
|
|
304
|
+
gateway.logger.debug(`[Gateway] tell worker to identify (${workerId}, ${shardId}, ${bucketId})`);
|
|
305
|
+
await gateway.identify(shardId);
|
|
306
|
+
},
|
|
307
|
+
async identify (shardId) {
|
|
308
|
+
let shard = this.shards.get(shardId);
|
|
309
|
+
gateway.logger.debug(`[Gateway] identifying ${shard ? 'existing' : 'new'} shard (${shardId})`);
|
|
310
|
+
if (!shard) {
|
|
311
|
+
shard = new _Shard.default({
|
|
312
|
+
id: shardId,
|
|
313
|
+
connection: {
|
|
314
|
+
compress: this.compress,
|
|
315
|
+
intents: this.intents,
|
|
316
|
+
properties: this.properties,
|
|
317
|
+
token: this.token,
|
|
318
|
+
totalShards: this.totalShards,
|
|
319
|
+
url: this.url,
|
|
320
|
+
version: this.version
|
|
321
|
+
},
|
|
322
|
+
events: options.events ?? {},
|
|
323
|
+
logger: this.logger,
|
|
324
|
+
requestIdentify: async ()=>{
|
|
325
|
+
await gateway.identify(shardId);
|
|
326
|
+
},
|
|
327
|
+
shardIsReady: async ()=>{
|
|
328
|
+
gateway.logger.debug(`[Shard] Shard #${shardId} is ready`);
|
|
329
|
+
await (0, _utils.delay)(gateway.spawnShardDelay);
|
|
330
|
+
gateway.logger.debug(`[Shard] Resolving shard identify request`);
|
|
331
|
+
gateway.buckets.get(shardId % gateway.connection.sessionStartLimit.maxConcurrency).identifyRequests.shift()?.();
|
|
332
|
+
}
|
|
333
|
+
});
|
|
334
|
+
if (this.preferSnakeCase) {
|
|
335
|
+
shard.forwardToBot = async (payload)=>{
|
|
336
|
+
shard.events.message?.(shard, payload);
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
this.shards.set(shardId, shard);
|
|
340
|
+
}
|
|
341
|
+
const bucket = gateway.buckets.get(shardId % gateway.connection.sessionStartLimit.maxConcurrency);
|
|
342
|
+
if (!bucket) return;
|
|
343
|
+
return await new Promise((resolve)=>{
|
|
344
|
+
// Mark that we are making an identify request so another is not made.
|
|
345
|
+
bucket.identifyRequests.push(resolve);
|
|
346
|
+
gateway.logger.debug(`[Gateway] identifying shard #(${shardId}).`);
|
|
347
|
+
// This will trigger identify and when READY is received it will resolve the above request.
|
|
348
|
+
shard?.identify();
|
|
349
|
+
});
|
|
350
|
+
},
|
|
351
|
+
async kill (shardId) {
|
|
352
|
+
const shard = this.shards.get(shardId);
|
|
353
|
+
if (!shard) {
|
|
354
|
+
return gateway.logger.debug(`[Gateway] kill shard but not found (${shardId})`);
|
|
355
|
+
}
|
|
356
|
+
gateway.logger.debug(`[Gateway] kill shard (${shardId})`);
|
|
357
|
+
this.shards.delete(shardId);
|
|
358
|
+
await shard.shutdown();
|
|
359
|
+
},
|
|
360
|
+
async requestIdentify (shardId) {
|
|
361
|
+
gateway.logger.debug(`[Gateway] requesting identify`);
|
|
362
|
+
// const bucket = gateway.buckets.get(shardId % gateway.connection.sessionStartLimit.maxConcurrency)
|
|
363
|
+
// if (!bucket) return
|
|
364
|
+
// return await new Promise((resolve) => {
|
|
365
|
+
// bucket.identifyRequests.push(resolve)
|
|
366
|
+
// })
|
|
367
|
+
},
|
|
368
|
+
// Helpers methods below this
|
|
369
|
+
calculateShardId (guildId, totalShards) {
|
|
370
|
+
// If none is provided, use the total shards number from gateway object.
|
|
371
|
+
if (!totalShards) totalShards = gateway.totalShards;
|
|
372
|
+
// If it is only 1 shard, it will always be shard id 0
|
|
373
|
+
if (totalShards === 1) {
|
|
374
|
+
gateway.logger.debug(`[Gateway] calculateShardId (1 shard)`);
|
|
375
|
+
return 0;
|
|
376
|
+
}
|
|
377
|
+
gateway.logger.debug(`[Gateway] calculateShardId (guildId: ${guildId}, totalShards: ${totalShards})`);
|
|
378
|
+
return Number((BigInt(guildId) >> 22n) % BigInt(totalShards));
|
|
379
|
+
},
|
|
380
|
+
async joinVoiceChannel (guildId, channelId, options) {
|
|
381
|
+
const shardId = gateway.calculateShardId(guildId);
|
|
382
|
+
gateway.logger.debug(`[Gateway] joinVoiceChannel guildId: ${guildId} channelId: ${channelId}`);
|
|
383
|
+
await gateway.sendPayload(shardId, {
|
|
384
|
+
op: _types.GatewayOpcodes.VoiceStateUpdate,
|
|
385
|
+
d: {
|
|
386
|
+
guild_id: guildId.toString(),
|
|
387
|
+
channel_id: channelId.toString(),
|
|
388
|
+
self_mute: options?.selfMute ?? false,
|
|
389
|
+
self_deaf: options?.selfDeaf ?? true
|
|
390
|
+
}
|
|
391
|
+
});
|
|
392
|
+
},
|
|
393
|
+
async editBotStatus (data) {
|
|
394
|
+
gateway.logger.debug(`[Gateway] editBotStatus data: ${JSON.stringify(data)}`);
|
|
395
|
+
await Promise.all([
|
|
396
|
+
...gateway.shards.values()
|
|
397
|
+
].map(async (shard)=>{
|
|
398
|
+
gateway.editShardStatus(shard.id, data);
|
|
399
|
+
}));
|
|
400
|
+
},
|
|
401
|
+
async editShardStatus (shardId, data) {
|
|
402
|
+
gateway.logger.debug(`[Gateway] editShardStatus shardId: ${shardId} -> data: ${JSON.stringify(data)}`);
|
|
403
|
+
await gateway.sendPayload(shardId, {
|
|
404
|
+
op: _types.GatewayOpcodes.PresenceUpdate,
|
|
405
|
+
d: {
|
|
406
|
+
since: null,
|
|
407
|
+
afk: false,
|
|
408
|
+
activities: data.activities,
|
|
409
|
+
status: data.status
|
|
410
|
+
}
|
|
411
|
+
});
|
|
412
|
+
},
|
|
413
|
+
async requestMembers (guildId, options) {
|
|
414
|
+
const shardId = gateway.calculateShardId(guildId);
|
|
415
|
+
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');
|
|
416
|
+
gateway.logger.debug(`[Gateway] requestMembers guildId: ${guildId} -> data: ${JSON.stringify(options)}`);
|
|
417
|
+
if (options?.userIds?.length) {
|
|
418
|
+
gateway.logger.debug(`[Gateway] requestMembers guildId: ${guildId} -> setting user limit based on userIds length: ${options.userIds.length}`);
|
|
419
|
+
options.limit = options.userIds.length;
|
|
420
|
+
}
|
|
421
|
+
const members = !gateway.cache.requestMembers.enabled || !options?.nonce ? [] : new Promise((resolve, reject)=>{
|
|
422
|
+
// Should never happen.
|
|
423
|
+
if (!gateway.cache.requestMembers.enabled || !options?.nonce) {
|
|
424
|
+
reject(new Error("Can't request the members without the nonce or with the feature disabled."));
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
gateway.cache.requestMembers.pending.set(options.nonce, {
|
|
428
|
+
nonce: options.nonce,
|
|
429
|
+
resolve,
|
|
430
|
+
members: []
|
|
431
|
+
});
|
|
432
|
+
});
|
|
433
|
+
await gateway.sendPayload(shardId, {
|
|
434
|
+
op: _types.GatewayOpcodes.RequestGuildMembers,
|
|
435
|
+
d: {
|
|
436
|
+
guild_id: guildId.toString(),
|
|
437
|
+
// If a query is provided use it, OR if a limit is NOT provided use ""
|
|
438
|
+
query: options?.query ?? (options?.limit ? undefined : ''),
|
|
439
|
+
limit: options?.limit ?? 0,
|
|
440
|
+
presences: options?.presences ?? false,
|
|
441
|
+
user_ids: options?.userIds?.map((id)=>id.toString()),
|
|
442
|
+
nonce: options?.nonce
|
|
443
|
+
}
|
|
444
|
+
});
|
|
445
|
+
return await members;
|
|
446
|
+
},
|
|
447
|
+
async leaveVoiceChannel (guildId) {
|
|
448
|
+
const shardId = gateway.calculateShardId(guildId);
|
|
449
|
+
gateway.logger.debug(`[Gateway] leaveVoiceChannel guildId: ${guildId} Shard ${shardId}`);
|
|
450
|
+
await gateway.sendPayload(shardId, {
|
|
451
|
+
op: _types.GatewayOpcodes.VoiceStateUpdate,
|
|
452
|
+
d: {
|
|
453
|
+
guild_id: guildId.toString(),
|
|
454
|
+
channel_id: null,
|
|
455
|
+
self_mute: false,
|
|
456
|
+
self_deaf: false
|
|
457
|
+
}
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
};
|
|
461
|
+
return gateway;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9tYW5hZ2VyLnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qIGVzbGludC1kaXNhYmxlIEB0eXBlc2NyaXB0LWVzbGludC9uby1jb25mdXNpbmctdm9pZC1leHByZXNzaW9uICovXG5pbXBvcnQge1xuICBHYXRld2F5SW50ZW50cyxcbiAgR2F0ZXdheU9wY29kZXMsXG4gIHR5cGUgQXRMZWFzdE9uZSxcbiAgdHlwZSBCaWdTdHJpbmcsXG4gIHR5cGUgQ2FtZWxpemUsXG4gIHR5cGUgRGlzY29yZEdldEdhdGV3YXlCb3QsXG4gIHR5cGUgRGlzY29yZE1lbWJlcldpdGhVc2VyLFxuICB0eXBlIERpc2NvcmRSZWFkeSxcbiAgdHlwZSBSZXF1ZXN0R3VpbGRNZW1iZXJzLFxufSBmcm9tICdAZGlzY29yZGVuby90eXBlcydcbmltcG9ydCB7IENvbGxlY3Rpb24sIGRlbGF5LCBsb2dnZXIgfSBmcm9tICdAZGlzY29yZGVuby91dGlscydcbmltcG9ydCBTaGFyZCBmcm9tICcuL1NoYXJkLmpzJ1xuaW1wb3J0IHsgU2hhcmRTb2NrZXRDbG9zZUNvZGVzLCB0eXBlIFNoYXJkRXZlbnRzLCB0eXBlIFNoYXJkU29ja2V0UmVxdWVzdCwgdHlwZSBTdGF0dXNVcGRhdGUsIHR5cGUgVXBkYXRlVm9pY2VTdGF0ZSB9IGZyb20gJy4vdHlwZXMuanMnXG5cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVHYXRld2F5TWFuYWdlcihvcHRpb25zOiBDcmVhdGVHYXRld2F5TWFuYWdlck9wdGlvbnMpOiBHYXRld2F5TWFuYWdlciB7XG4gIGNvbnN0IGNvbm5lY3Rpb25PcHRpb25zID0gb3B0aW9ucy5jb25uZWN0aW9uID8/IHtcbiAgICB1cmw6ICd3c3M6Ly9nYXRld2F5LmRpc2NvcmQuZ2cnLFxuICAgIHNoYXJkczogMSxcbiAgICBzZXNzaW9uU3RhcnRMaW1pdDoge1xuICAgICAgbWF4Q29uY3VycmVuY3k6IDEsXG4gICAgICByZW1haW5pbmc6IDEwMDAsXG4gICAgICB0b3RhbDogMTAwMCxcbiAgICAgIHJlc2V0QWZ0ZXI6IDEwMDAgKiA2MCAqIDYwICogMjQsXG4gICAgfSxcbiAgfVxuXG4gIGNvbnN0IGdhdGV3YXk6IEdhdGV3YXlNYW5hZ2VyID0ge1xuICAgIGV2ZW50czogb3B0aW9ucy5ldmVudHMgPz8ge30sXG4gICAgY29tcHJlc3M6IG9wdGlvbnMuY29tcHJlc3MgPz8gZmFsc2UsXG4gICAgaW50ZW50czogb3B0aW9ucy5pbnRlbnRzID8/IDAsXG4gICAgcHJvcGVydGllczoge1xuICAgICAgb3M6IG9wdGlvbnMucHJvcGVydGllcz8ub3MgPz8gcHJvY2Vzcy5wbGF0Zm9ybSxcbiAgICAgIGJyb3dzZXI6IG9wdGlvbnMucHJvcGVydGllcz8uYnJvd3NlciA/PyAnRGlzY29yZGVubycsXG4gICAgICBkZXZpY2U6IG9wdGlvbnMucHJvcGVydGllcz8uZGV2aWNlID8/ICdEaXNjb3JkZW5vJyxcbiAgICB9LFxuICAgIHRva2VuOiBvcHRpb25zLnRva2VuLFxuICAgIHVybDogb3B0aW9ucy51cmwgPz8gY29ubmVjdGlvbk9wdGlvbnMudXJsID8/ICd3c3M6Ly9nYXRld2F5LmRpc2NvcmQuZ2cnLFxuICAgIHZlcnNpb246IG9wdGlvbnMudmVyc2lvbiA/PyAxMCxcbiAgICBjb25uZWN0aW9uOiBjb25uZWN0aW9uT3B0aW9ucyxcbiAgICB0b3RhbFNoYXJkczogb3B0aW9ucy50b3RhbFNoYXJkcyA/PyBjb25uZWN0aW9uT3B0aW9ucy5zaGFyZHMgPz8gMSxcbiAgICBsYXN0U2hhcmRJZDogb3B0aW9ucy5sYXN0U2hhcmRJZCA/PyAob3B0aW9ucy50b3RhbFNoYXJkcyA/IG9wdGlvbnMudG90YWxTaGFyZHMgLSAxIDogY29ubmVjdGlvbk9wdGlvbnMgPyBjb25uZWN0aW9uT3B0aW9ucy5zaGFyZHMgLSAxIDogMCksXG4gICAgZmlyc3RTaGFyZElkOiBvcHRpb25zLmZpcnN0U2hhcmRJZCA/PyAwLFxuICAgIHRvdGFsV29ya2Vyczogb3B0aW9ucy50b3RhbFdvcmtlcnMgPz8gNCxcbiAgICBzaGFyZHNQZXJXb3JrZXI6IG9wdGlvbnMuc2hhcmRzUGVyV29ya2VyID8/IDI1LFxuICAgIHNwYXduU2hhcmREZWxheTogb3B0aW9ucy5zcGF3blNoYXJkRGVsYXkgPz8gNTMwMCxcbiAgICBwcmVmZXJTbmFrZUNhc2U6IG9wdGlvbnMucHJlZmVyU25ha2VDYXNlID8/IGZhbHNlLFxuICAgIHNoYXJkczogbmV3IE1hcCgpLFxuICAgIGJ1Y2tldHM6IG5ldyBNYXAoKSxcbiAgICBjYWNoZToge1xuICAgICAgcmVxdWVzdE1lbWJlcnM6IHtcbiAgICAgICAgZW5hYmxlZDogb3B0aW9ucy5jYWNoZT8ucmVxdWVzdE1lbWJlcnM/LmVuYWJsZWQgPz8gZmFsc2UsXG4gICAgICAgIHBlbmRpbmc6IG5ldyBDb2xsZWN0aW9uKCksXG4gICAgICB9LFxuICAgIH0sXG4gICAgbG9nZ2VyOiBvcHRpb25zLmxvZ2dlciA/PyBsb2dnZXIsXG4gICAgcmVzaGFyZGluZzoge1xuICAgICAgZW5hYmxlZDogdHJ1ZSxcbiAgICAgIHNoYXJkc0Z1bGxQZXJjZW50YWdlOiA4MCxcbiAgICAgIGNoZWNrSW50ZXJ2YWw6IDI4ODAwMDAwLFxuICAgICAgc2hhcmRzOiBuZXcgQ29sbGVjdGlvbigpLFxuICAgICAgcGVuZGluZ1NoYXJkczogbmV3IENvbGxlY3Rpb24oKSxcbiAgICAgIGFzeW5jIGdldFNlc3Npb25JbmZvKCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgJ1tSZXNoYXJkaW5nXSB3YXMgZW5hYmxlZCBidXQgbm8gZ2V0U2Vzc2lvbkluZm8gaGFuZGxlciB3YXMgcHJvdmlkZWQuIFBsZWFzZSBzZXQgYSBoYW5kbGVyIGxpa2U6IGdhdGV3YXkucmVzaGFyZGluZy5nZXRTZXNzaW9uSW5mbyA9IGFzeW5jICgpID0+IHsgLy8gaW5zZXJ0IGNvZGUgaGVyZSB0byBmZXRjaCBnZXRTZXNzaW9uSW5mbyBmcm9tIHJlc3QgcHJvY2Vzcy4gfScsXG4gICAgICAgIClcbiAgICAgIH0sXG4gICAgICBhc3luYyBjaGVja0lmUmVzaGFyZGluZ0lzTmVlZGVkKCkge1xuICAgICAgICBsb2dnZXIud2FybihgW1Jlc2hhcmRpbmddIENoZWNraW5nIGlmIHJlc2hhcmRpbmcgaXMgbmVlZGVkLmApXG4gICAgICAgIC8vIFJlc2hhcmRpbmcgaXMgZGlzYWJsZWQuXG4gICAgICAgIGlmICghZ2F0ZXdheS5yZXNoYXJkaW5nLmVuYWJsZWQpIHJldHVybiB7IG5lZWRlZDogZmFsc2UgfVxuICAgICAgICBsb2dnZXIud2FybihgW1Jlc2hhcmRpbmddIFJlc2hhcmRpbmcgaXMgZW5hYmxlZC5gKVxuXG4gICAgICAgIGNvbnN0IHNlc3Npb25JbmZvID0gYXdhaXQgZ2F0ZXdheS5yZXNoYXJkaW5nLmdldFNlc3Npb25JbmZvKClcbiAgICAgICAgbG9nZ2VyLndhcm4oYFtSZXNoYXJkaW5nXSBTZXNzaW9uIGluZm8gcmV0cmlldmVkLmApXG4gICAgICAgIC8vIERvbid0IGhhdmUgZW5vdWdoIGlkZW50aWZ5IGxpbWl0cyB0byB0cnkgcmVzaGFyZGluZ1xuICAgICAgICBpZiAoc2Vzc2lvbkluZm8uc2Vzc2lvblN0YXJ0TGltaXQucmVtYWluaW5nIDwgc2Vzc2lvbkluZm8uc2hhcmRzKSByZXR1cm4geyBuZWVkZWQ6IGZhbHNlLCBpbmZvOiBzZXNzaW9uSW5mbyB9XG4gICAgICAgIGxvZ2dlci53YXJuKGBbUmVzaGFyZGluZ10gQWJsZSB0byByZXNoYXJkLCBjaGVja2luZyB3aGV0aGVyIG5lY2Vzc2FyeSBub3cuYClcblxuICAgICAgICAvLyAyNTAwIGlzIHRoZSBtYXggYW1vdW50IG9mIGd1aWxkcyBhIHNpbmdsZSBzaGFyZCBjYW4gaGFuZGxlXG4gICAgICAgIC8vIDEwMDAgaXMgdGhlIGFtb3VudCBvZiBndWlsZHMgZGlzY29yZCB1c2VzIHRvIGRldGVybWluZSBob3cgbWFueSBzaGFyZHMgdG8gcmVjb21tZW5kLlxuICAgICAgICAvLyBUaGlzIGFsZ28gaGVscHMgY2hlY2sgaWYgeW91ciBib3QgaGFzIGdyb3duIGVub3VnaCB0byByZXNoYXJkLlxuICAgICAgICBjb25zdCBwZXJjZW50YWdlID0gKCgyNTAwICogc2Vzc2lvbkluZm8uc2hhcmRzKSAvIChnYXRld2F5LnRvdGFsU2hhcmRzICogMTAwMCkpICogMTAwXG4gICAgICAgIC8vIExlc3MgdGhhbiBuZWNlc3NhcnklIGJlaW5nIHVzZWQgc28gZG8gbm90aGluZ1xuICAgICAgICBpZiAocGVyY2VudGFnZSA8IGdhdGV3YXkucmVzaGFyZGluZy5zaGFyZHNGdWxsUGVyY2VudGFnZSkgcmV0dXJuIHsgbmVlZGVkOiBmYWxzZSwgaW5mbzogc2Vzc2lvbkluZm8gfVxuICAgICAgICBsb2dnZXIud2FybihgW1Jlc2hhcmRpbmddIFJlc2hhcmRpbmcgaXMgbmVlZGVkLmApXG5cbiAgICAgICAgcmV0dXJuIHsgbmVlZGVkOiB0cnVlLCBpbmZvOiBzZXNzaW9uSW5mbyB9XG4gICAgICB9LFxuICAgICAgYXN5bmMgcmVzaGFyZChpbmZvKSB7XG4gICAgICAgIGxvZ2dlci53YXJuKGBbUmVzaGFyZGluZ10gU3RhcnRpbmcgdGhlIHJlc2hhcmQgcHJvY2Vzcy4gUHJldmlvdXMgdG90YWwgc2hhcmRzLiAke2dhdGV3YXkudG90YWxTaGFyZHN9YClcbiAgICAgICAgLy8gU2V0IHZhbHVlcyBvbiBnYXRld2F5XG4gICAgICAgIGdhdGV3YXkudG90YWxTaGFyZHMgPSBpbmZvLnNoYXJkc1xuICAgICAgICAvLyBIYW5kbGVzIHByZXBhcmluZyBtaWQgc2l6ZWQgYm90cyBmb3IgTEJTXG4gICAgICAgIGdhdGV3YXkudG90YWxTaGFyZHMgPSBnYXRld2F5LmNhbGN1bGF0ZVRvdGFsU2hhcmRzKClcbiAgICAgICAgLy8gU2V0IGZpcnN0IHNoYXJkIGlkIGlmIHByb3ZpZGVkIGluIGluZm9cbiAgICAgICAgaWYgKHR5cGVvZiBpbmZvLmZpcnN0U2hhcmRJZCA9PT0gJ251bWJlcicpIGdhdGV3YXkuZmlyc3RTaGFyZElkID0gaW5mby5maXJzdFNoYXJkSWRcbiAgICAgICAgLy8gU2V0IGxhc3Qgc2hhcmQgaWQgaWYgcHJvdmlkZWQgaW4gaW5mb1xuICAgICAgICBpZiAodHlwZW9mIGluZm8ubGFzdFNoYXJkSWQgPT09ICdudW1iZXInKSBnYXRld2F5Lmxhc3RTaGFyZElkID0gaW5mby5sYXN0U2hhcmRJZFxuICAgICAgICBsb2dnZXIud2FybihgW1Jlc2hhcmRpbmddIFN0YXJ0aW5nIHRoZSByZXNoYXJkIHByb2Nlc3MuIE5ldyBUb3RhbCBTaGFyZHMuICR7Z2F0ZXdheS50b3RhbFNoYXJkc31gKVxuXG4gICAgICAgIC8vIFJlc2V0dGluZyBidWNrZXRzXG4gICAgICAgIGdhdGV3YXkuYnVja2V0cy5jbGVhcigpXG4gICAgICAgIC8vIFJlZmlsbGluZyBidWNrZXRzIHdpdGggbmV3IHZhbHVlc1xuICAgICAgICBnYXRld2F5LnByZXBhcmVCdWNrZXRzKClcblxuICAgICAgICAvLyBTUFJFQUQgVEhJUyBPVVQgVE8gRElGRkVSRU5UIFdPUktFUlMgVE8gQkVHSU4gU1RBUlRJTkcgVVBcbiAgICAgICAgZ2F0ZXdheS5idWNrZXRzLmZvckVhY2goYXN5bmMgKGJ1Y2tldCwgYnVja2V0SWQpID0+IHtcbiAgICAgICAgICBmb3IgKGNvbnN0IHdvcmtlciBvZiBidWNrZXQud29ya2Vycykge1xuICAgICAgICAgICAgZm9yIChjb25zdCBzaGFyZElkIG9mIHdvcmtlci5xdWV1ZSkge1xuICAgICAgICAgICAgICBhd2FpdCBnYXRld2F5LnJlc2hhcmRpbmcudGVsbFdvcmtlclRvUHJlcGFyZSh3b3JrZXIuaWQsIHNoYXJkSWQsIGJ1Y2tldElkKVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSlcbiAgICAgIH0sXG4gICAgICBhc3luYyB0ZWxsV29ya2VyVG9QcmVwYXJlKHdvcmtlcklkLCBzaGFyZElkLCBidWNrZXRJZCkge1xuICAgICAgICBsb2dnZXIud2FybihgW1Jlc2hhcmRpbmddIFRlbGxpbmcgd29ya2VyIHRvIHByZXBhcmUuIFdvcmtlcjogJHt3b3JrZXJJZH0gfCBTaGFyZDogJHtzaGFyZElkfSB8IEJ1Y2tldDogJHtidWNrZXRJZH1gKVxuICAgICAgICBjb25zdCBzaGFyZCA9IG5ldyBTaGFyZCh7XG4gICAgICAgICAgaWQ6IHNoYXJkSWQsXG4gICAgICAgICAgY29ubmVjdGlvbjoge1xuICAgICAgICAgICAgY29tcHJlc3M6IGdhdGV3YXkuY29tcHJlc3MsXG4gICAgICAgICAgICBpbnRlbnRzOiBnYXRld2F5LmludGVudHMsXG4gICAgICAgICAgICBwcm9wZXJ0aWVzOiBnYXRld2F5LnByb3BlcnRpZXMsXG4gICAgICAgICAgICB0b2tlbjogZ2F0ZXdheS50b2tlbixcbiAgICAgICAgICAgIHRvdGFsU2hhcmRzOiBnYXRld2F5LnRvdGFsU2hhcmRzLFxuICAgICAgICAgICAgdXJsOiBnYXRld2F5LnVybCxcbiAgICAgICAgICAgIHZlcnNpb246IGdhdGV3YXkudmVyc2lvbixcbiAgICAgICAgICB9LFxuICAgICAgICAgIC8vIElnbm9yZSBldmVudHMgdW50aWwgd2UgYXJlIHJlYWR5XG4gICAgICAgICAgZXZlbnRzOiB7XG4gICAgICAgICAgICBhc3luYyBtZXNzYWdlKF9zaGFyZCwgcGF5bG9hZCkge1xuICAgICAgICAgICAgICBpZiAocGF5bG9hZC50ID09PSAnUkVBRFknKSB7XG4gICAgICAgICAgICAgICAgYXdhaXQgZ2F0ZXdheS5yZXNoYXJkaW5nLnVwZGF0ZUd1aWxkc1NoYXJkSWQoXG4gICAgICAgICAgICAgICAgICAocGF5bG9hZC5kIGFzIERpc2NvcmRSZWFkeSkuZ3VpbGRzLm1hcCgoZykgPT4gZy5pZCksXG4gICAgICAgICAgICAgICAgICBzaGFyZElkLFxuICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9LFxuICAgICAgICAgIHJlcXVlc3RJZGVudGlmeTogYXN5bmMgKCkgPT4ge1xuICAgICAgICAgICAgYXdhaXQgZ2F0ZXdheS5pZGVudGlmeShzaGFyZElkKVxuICAgICAgICAgIH0sXG4gICAgICAgICAgc2hhcmRJc1JlYWR5OiBhc3luYyAoKSA9PiB7XG4gICAgICAgICAgICBsb2dnZXIuZGVidWcoYFtTaGFyZF0gU2hhcmQgIyR7c2hhcmRJZH0gaXMgcmVhZHlgKVxuICAgICAgICAgICAgYXdhaXQgZGVsYXkoZ2F0ZXdheS5zcGF3blNoYXJkRGVsYXkpXG4gICAgICAgICAgICBsb2dnZXIuZGVidWcoYFtTaGFyZF0gUmVzb2x2aW5nIHNoYXJkIGlkZW50aWZ5IHJlcXVlc3RgKVxuICAgICAgICAgICAgZ2F0ZXdheS5idWNrZXRzLmdldChzaGFyZElkICUgZ2F0ZXdheS5jb25uZWN0aW9uLnNlc3Npb25TdGFydExpbWl0Lm1heENvbmN1cnJlbmN5KSEuaWRlbnRpZnlSZXF1ZXN0cy5zaGlmdCgpPy4oKVxuICAgICAgICAgIH0sXG4gICAgICAgIH0pXG5cbiAgICAgICAgaWYgKGdhdGV3YXkucHJlZmVyU25ha2VDYXNlKSB7XG4gICAgICAgICAgc2hhcmQuZm9yd2FyZFRvQm90ID0gYXN5bmMgKHBheWxvYWQpID0+IHtcbiAgICAgICAgICAgIHNoYXJkLmV2ZW50cz8ubWVzc2FnZT8uKHNoYXJkLCBwYXlsb2FkKVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGdhdGV3YXkucmVzaGFyZGluZy5zaGFyZHMuc2V0KHNoYXJkSWQsIHNoYXJkKVxuXG4gICAgICAgIGNvbnN0IGJ1Y2tldCA9IGdhdGV3YXkuYnVja2V0cy5nZXQoc2hhcmRJZCAlIGdhdGV3YXkuY29ubmVjdGlvbi5zZXNzaW9uU3RhcnRMaW1pdC5tYXhDb25jdXJyZW5jeSlcbiAgICAgICAgaWYgKCFidWNrZXQpIHJldHVyblxuXG4gICAgICAgIHJldHVybiBhd2FpdCBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4ge1xuICAgICAgICAgIC8vIE1hcmsgdGhhdCB3ZSBhcmUgbWFraW5nIGFuIGlkZW50aWZ5IHJlcXVlc3Qgc28gYW5vdGhlciBpcyBub3QgbWFkZS5cbiAgICAgICAgICBidWNrZXQuaWRlbnRpZnlSZXF1ZXN0cy5wdXNoKHJlc29sdmUpXG4gICAgICAgICAgbG9nZ2VyLmRlYnVnKGBbR2F0ZXdheV0gaWRlbnRpZnlpbmcgc2hhcmQgIygke3NoYXJkSWR9KS5gKVxuICAgICAgICAgIC8vIFRoaXMgd2lsbCB0cmlnZ2VyIGlkZW50aWZ5IGFuZCB3aGVuIFJFQURZIGlzIHJlY2VpdmVkIGl0IHdpbGwgcmVzb2x2ZSB0aGUgYWJvdmUgcmVxdWVzdC5cbiAgICAgICAgICBzaGFyZD8uaWRlbnRpZnkoKS50aGVuKGFzeW5jICgpID0+IHtcbiAgICAgICAgICAgIC8vIFRlbGwgdGhlIG1hbmFnZXIgdGhhdCB0aGlzIHNoYXJkIGlzIG9ubGluZVxuICAgICAgICAgICAgcmV0dXJuIGF3YWl0IGdhdGV3YXkucmVzaGFyZGluZy5zaGFyZElzUGVuZGluZyhzaGFyZClcbiAgICAgICAgICB9KVxuICAgICAgICB9KVxuICAgICAgfSxcbiAgICAgIGFzeW5jIHVwZGF0ZUd1aWxkc1NoYXJkSWQoZ3VpbGRJZHMsIHNoYXJkSWQpIHtcbiAgICAgICAgbG9nZ2VyLmRlYnVnKFxuICAgICAgICAgIGBbUmVzaGFyZGluZ10gVXBkYXRpbmcgdGhlIGZvbGxvd2luZyBndWlsZCBpZHMgc2hhcmQgdG8gIyR7c2hhcmRJZH06ICR7Z3VpbGRJZHMuam9pbignLCAnKX0uIE92ZXJyaWRlIHRoaXMgZnVuY3Rpb24gdG8gdXBkYXRlIHlvdXIgY2FjaGUgaWYgeW91IG5lZWQgdG8uYCxcbiAgICAgICAgKVxuICAgICAgfSxcbiAgICAgIGFzeW5jIHNoYXJkSXNQZW5kaW5nKHNoYXJkKSB7XG4gICAgICAgIC8vIFNhdmUgdGhpcyBpbiBwZW5kaW5nIGF0IHRoZSBtb21lbnQsIHVudGlsIGFsbCBzaGFyZHMgYXJlIG9ubGluZVxuICAgICAgICBnYXRld2F5LnJlc2hhcmRpbmcucGVuZGluZ1NoYXJkcy5zZXQoc2hhcmQuaWQsIHNoYXJkKVxuICAgICAgICBsb2dnZXIud2FybihgW1Jlc2hhcmRpbmddIFNoYXJkICMke3NoYXJkLmlkfSBpcyBub3cgcGVuZGluZ2ApXG4gICAgICAgIC8vIENoZWNrIGlmIGFsbCBzaGFyZHMgYXJlIG5vdyBvbmxpbmUuXG4gICAgICAgIGlmIChnYXRld2F5Lmxhc3RTaGFyZElkIC0gZ2F0ZXdheS5maXJzdFNoYXJkSWQgKyAxID4gZ2F0ZXdheS5yZXNoYXJkaW5nLnBlbmRpbmdTaGFyZHMuc2l6ZSkgcmV0dXJuXG4gICAgICAgIGxvZ2dlci53YXJuKGBbUmVzaGFyZGluZ10gQWxsIHNoYXJkcyBhcmUgbm93IG9ubGluZS5gKVxuXG4gICAgICAgIC8vIE5ldyBzaGFyZHMgc3RhcnQgcHJvY2Vzc2luZyBldmVudHNcbiAgICAgICAgZm9yIChjb25zdCBzaGFyZCBvZiBnYXRld2F5LnJlc2hhcmRpbmcucGVuZGluZ1NoYXJkcy52YWx1ZXMoKSkge1xuICAgICAgICAgIGZvciAoY29uc3QgZXZlbnQgaW4gb3B0aW9ucy5ldmVudHMpIHtcbiAgICAgICAgICAgIC8vIEB0cy1leHBlY3QtZXJyb3IgZml4aW5nIHRoaXMgc2VlbXMgY29tcGxleCBhbmQgZG9lc250IHNlZW0gd29ydGggaXQsIGZlZWwgZnJlZSB0byBmaXggaWYgeW91IHdpc2hcbiAgICAgICAgICAgIHNoYXJkLmV2ZW50c1tldmVudF0gPSBvcHRpb25zLmV2ZW50c1tldmVudF1cbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICAvLyBPbGQgc2hhcmRzIHN0b3AgcHJvY2Vzc2luZyBldmVudHNcbiAgICAgICAgZm9yIChjb25zdCBzaGFyZCBvZiBnYXRld2F5LnNoYXJkcy52YWx1ZXMoKSkge1xuICAgICAgICAgIGNvbnN0IG9sZEhhbmRsZXIgPSBzaGFyZC5ldmVudHMubWVzc2FnZVxuXG4gICAgICAgICAgLy8gQ2hhbmdlIHdpdGggc3ByZWFkIG9wZXJhdG9yIHRvIG5vdCBhZmZlY3QgbmV3IHNoYXJkcywgYXMgY2hhbmdpbmcgYW55dGhpbmcgb24gc2hhcmQuZXZlbnRzIHdpbGwgZGlyZWN0bHkgY2hhbmdlIG9wdGlvbnMuZXZlbnRzLCB3aGljaCBjaGFuZ2VzIG5ldyBzaGFyZHMnIGV2ZW50c1xuICAgICAgICAgIHNoYXJkLmV2ZW50cyA9IHtcbiAgICAgICAgICAgIC4uLnNoYXJkLmV2ZW50cyxcbiAgICAgICAgICAgIG1lc3NhZ2U6IGFzeW5jIGZ1bmN0aW9uIChfLCBtZXNzYWdlKSB7XG4gICAgICAgICAgICAgIC8vIE1lbWJlciBjaGVja3MgbmVlZCB0byBjb250aW51ZSBidXQgb3RoZXJzIGNhbiBzdG9wXG4gICAgICAgICAgICAgIGlmIChtZXNzYWdlLnQgIT09ICdHVUlMRF9NRU1CRVJTX0NIVU5LJykgcmV0dXJuXG4gICAgICAgICAgICAgIC8vIFByb2Nlc3Mgb25seSB0aGUgY2h1bmtpbmcgZXZlbnRzXG4gICAgICAgICAgICAgIG9sZEhhbmRsZXI/LihzaGFyZCwgbWVzc2FnZSlcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgbG9nZ2VyLndhcm4oYFtSZXNoYXJkaW5nXSBTaHV0dGluZyBkb3duIG9sZCBzaGFyZHMuYClcbiAgICAgICAgLy8gQ2xvc2Ugb2xkIHNoYXJkc1xuICAgICAgICBhd2FpdCBnYXRld2F5LnNodXRkb3duKFNoYXJkU29ja2V0Q2xvc2VDb2Rlcy5SZXNoYXJkZWQsICdSZXNoYXJkZWQhJywgZmFsc2UpXG4gICAgICAgIGxvZ2dlci53YXJuKGBbUmVzaGFyZGluZ10gQ29tcGxldGVkLmApXG5cbiAgICAgICAgLy8gUmVwbGFjZSBvbGQgc2hhcmRzXG4gICAgICAgIGdhdGV3YXkuc2hhcmRzID0gZ2F0ZXdheS5yZXNoYXJkaW5nLnNoYXJkc1xuICAgICAgfSxcbiAgICB9LFxuXG4gICAgY2FsY3VsYXRlVG90YWxTaGFyZHMoKSB7XG4gICAgICAvLyBCb3RzIHVuZGVyIDEwMGsgc2VydmVycyBkbyBub3QgaGF2ZSBhY2Nlc3MgdG8gTEJTLlxuICAgICAgaWYgKGdhdGV3YXkudG90YWxTaGFyZHMgPCAxMDApIHtcbiAgICAgICAgZ2F0ZXdheS5sb2dnZXIuZGVidWcoYFtHYXRld2F5XSBDYWxjdWxhdGluZyB0b3RhbCBzaGFyZHM6ICR7Z2F0ZXdheS50b3RhbFNoYXJkc31gKVxuICAgICAgICByZXR1cm4gZ2F0ZXdheS50b3RhbFNoYXJkc1xuICAgICAgfVxuXG4gICAgICBnYXRld2F5LmxvZ2dlci5kZWJ1ZyhgW0dhdGV3YXldIENhbGN1bGF0aW5nIHRvdGFsIHNoYXJkc2AsIGdhdGV3YXkudG90YWxTaGFyZHMsIGdhdGV3YXkuY29ubmVjdGlvbi5zZXNzaW9uU3RhcnRMaW1pdC5tYXhDb25jdXJyZW5jeSlcbiAgICAgIC8vIENhbGN1bGF0ZSBhIG11bHRpcGxlIG9mIGBtYXhDb25jdXJyZW5jeWAgd2hpY2ggY2FuIGJlIHVzZWQgdG8gY29ubmVjdCB0byB0aGUgZ2F0ZXdheS5cbiAgICAgIHJldHVybiAoXG4gICAgICAgIE1hdGguY2VpbChcbiAgICAgICAgICBnYXRld2F5LnRvdGFsU2hhcmRzIC9cbiAgICAgICAgICAgIC8vIElmIGBtYXhDb25jdXJyZW5jeWAgaXMgMSwgd2UgY2FuIHNhZmVseSB1c2UgMTYgdG8gZ2V0IGB0b3RhbFNoYXJkc2AgdG8gYmUgaW4gYSBtdWx0aXBsZSBvZiAxNiBzbyB0aGF0IHdlIGNhbiBwcmVwYXJlIGJvdHMgd2l0aCAxMDBrIHNlcnZlcnMgZm9yIExCUy5cbiAgICAgICAgICAgIChnYXRld2F5LmNvbm5lY3Rpb24uc2Vzc2lvblN0YXJ0TGltaXQubWF4Q29uY3VycmVuY3kgPT09IDEgPyAxNiA6IGdhdGV3YXkuY29ubmVjdGlvbi5zZXNzaW9uU3RhcnRMaW1pdC5tYXhDb25jdXJyZW5jeSksXG4gICAgICAgICkgKiAoZ2F0ZXdheS5jb25uZWN0aW9uLnNlc3Npb25TdGFydExpbWl0Lm1heENvbmN1cnJlbmN5ID09PSAxID8gMTYgOiBnYXRld2F5LmNvbm5lY3Rpb24uc2Vzc2lvblN0YXJ0TGltaXQubWF4Q29uY3VycmVuY3kpXG4gICAgICApXG4gICAgfSxcbiAgICBjYWxjdWxhdGVXb3JrZXJJZChzaGFyZElkKSB7XG4gICAgICBjb25zdCB3b3JrZXJJZCA9IE1hdGgubWluKHNoYXJkSWQgJSBnYXRld2F5LnNoYXJkc1BlcldvcmtlciwgZ2F0ZXdheS50b3RhbFdvcmtlcnMgLSAxKVxuICAgICAgZ2F0ZXdheS5sb2dnZXIuZGVidWcoXG4gICAgICAgIGBbR2F0ZXdheV0gQ2FsY3VsYXRpbmcgd29ya2VySWQ6IFNoYXJkOiAke3NoYXJkSWR9IC0+IFdvcmtlcjogJHt3b3JrZXJJZH0gLT4gUGVyIFdvcmtlcjogJHtnYXRld2F5LnNoYXJkc1Blcldvcmtlcn0gLT4gVG90YWw6ICR7Z2F0ZXdheS50b3RhbFdvcmtlcnN9YCxcbiAgICAgIClcbiAgICAgIHJldHVybiB3b3JrZXJJZFxuICAgIH0sXG4gICAgcHJlcGFyZUJ1Y2tldHMoKSB7XG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGdhdGV3YXkuY29ubmVjdGlvbi5zZXNzaW9uU3RhcnRMaW1pdC5tYXhDb25jdXJyZW5jeTsgKytpKSB7XG4gICAgICAgIGdhdGV3YXkubG9nZ2VyLmRlYnVnKGBbR2F0ZXdheV0gUHJlcGFyaW5nIGJ1Y2tldHMgZm9yIGNvbmN1cnJlbmN5OiAke2l9YClcbiAgICAgICAgZ2F0ZXdheS5idWNrZXRzLnNldChpLCB7XG4gICAgICAgICAgd29ya2VyczogW10sXG4gICAgICAgICAgaWRlbnRpZnlSZXF1ZXN0czogW10sXG4gICAgICAgIH0pXG4gICAgICB9XG5cbiAgICAgIC8vIE9SR0FOSVpFIEFMTCBTSEFSRFMgSU5UTyBUSEVJUiBPV04gQlVDS0VUU1xuICAgICAgZm9yIChsZXQgc2hhcmRJZCA9IGdhdGV3YXkuZmlyc3RTaGFyZElkOyBzaGFyZElkIDw9IGdhdGV3YXkubGFzdFNoYXJkSWQ7ICsrc2hhcmRJZCkge1xuICAgICAgICBnYXRld2F5LmxvZ2dlci5kZWJ1ZyhgW0dhdGV3YXldIFByZXBhcmluZyBidWNrZXRzIGZvciBzaGFyZDogJHtzaGFyZElkfWApXG4gICAgICAgIGlmIChzaGFyZElkID49IGdhdGV3YXkudG90YWxTaGFyZHMpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFNoYXJkIChpZDogJHtzaGFyZElkfSkgaXMgYmlnZ2VyIG9yIGVxdWFsIHRvIHRoZSB1c2VkIGFtb3VudCBvZiB1c2VkIHNoYXJkcyB3aGljaCBpcyAke2dhdGV3YXkudG90YWxTaGFyZHN9YClcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGJ1Y2tldElkID0gc2hhcmRJZCAlIGdhdGV3YXkuY29ubmVjdGlvbi5zZXNzaW9uU3RhcnRMaW1pdC5tYXhDb25jdXJyZW5jeVxuICAgICAgICBjb25zdCBidWNrZXQgPSBnYXRld2F5LmJ1Y2tldHMuZ2V0KGJ1Y2tldElkKVxuICAgICAgICBpZiAoIWJ1Y2tldCkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICAgIGBTaGFyZCAoaWQ6ICR7c2hhcmRJZH0pIGdvdCBhc3NpZ25lZCB0byBhbiBpbGxlZ2FsIGJ1Y2tldCBpZDogJHtidWNrZXRJZH0sIGV4cGVjdGVkIGEgYnVja2V0IGlkIGJldHdlZW4gMCBhbmQgJHtcbiAgICAgICAgICAgICAgZ2F0ZXdheS5jb25uZWN0aW9uLnNlc3Npb25TdGFydExpbWl0Lm1heENvbmN1cnJlbmN5IC0gMVxuICAgICAgICAgICAgfWAsXG4gICAgICAgICAgKVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gRklORCBBIFFVRVVFIElOIFRISVMgQlVDS0VUIFRIQVQgSEFTIFNQQUNFXG4gICAgICAgIC8vIGNvbnN0IHdvcmtlciA9IGJ1Y2tldC53b3JrZXJzLmZpbmQoKHcpID0+IHcucXVldWUubGVuZ3RoIDwgZ2F0ZXdheS5zaGFyZHNQZXJXb3JrZXIpO1xuICAgICAgICBjb25zdCB3b3JrZXJJZCA9IGdhdGV3YXkuY2FsY3VsYXRlV29ya2VySWQoc2hhcmRJZClcbiAgICAgICAgY29uc3Qgd29ya2VyID0gYnVja2V0LndvcmtlcnMuZmluZCgodykgPT4gdy5pZCA9PT0gd29ya2VySWQpXG4gICAgICAgIGlmICh3b3JrZXIpIHtcbiAgICAgICAgICAvLyBJRiBUSEUgUVVFVUUgSEFTIFNQQUNFIEpVU1QgQUREIElUIFRPIFRISVMgUVVFVUVcbiAgICAgICAgICB3b3JrZXIucXVldWUucHVzaChzaGFyZElkKVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGJ1Y2tldC53b3JrZXJzLnB1c2goeyBpZDogd29ya2VySWQsIHF1ZXVlOiBbc2hhcmRJZF0gfSlcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBmb3IgKGNvbnN0IGJ1Y2tldCBvZiBnYXRld2F5LmJ1Y2tldHMudmFsdWVzKCkpIHtcbiAgICAgICAgZm9yIChjb25zdCB3b3JrZXIgb2YgYnVja2V0LndvcmtlcnMudmFsdWVzKCkpIHtcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L3JlcXVpcmUtYXJyYXktc29ydC1jb21wYXJlXG4gICAgICAgICAgd29ya2VyLnF1ZXVlID0gd29ya2VyLnF1ZXVlLnNvcnQoKGEsIGIpID0+IGEgLSBiKVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfSxcbiAgICBhc3luYyBzcGF3blNoYXJkcygpIHtcbiAgICAgIC8vIFBSRVBBUkVTIEFMTCBTSEFSRFMgSU4gU1BFQ0lGSUMgQlVDS0VUU1xuICAgICAgZ2F0ZXdheS5wcmVwYXJlQnVja2V0cygpXG5cbiAgICAgIC8vIFByZWZlciBjb25jdXJyZW5jeSBvZiBmb3JFYWNoIGluc3RlYWQgb2YgZm9yb2ZcbiAgICAgIGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgICBbLi4uZ2F0ZXdheS5idWNrZXRzLmVudHJpZXMoKV0ubWFwKGFzeW5jIChbYnVja2V0SWQsIGJ1Y2tldF0pID0+IHtcbiAgICAgICAgICBmb3IgKGNvbnN0IHdvcmtlciBvZiBidWNrZXQud29ya2Vycykge1xuICAgICAgICAgICAgZm9yIChjb25zdCBzaGFyZElkIG9mIHdvcmtlci5xdWV1ZSkge1xuICAgICAgICAgICAgICBhd2FpdCBnYXRld2F5LnRlbGxXb3JrZXJUb0lkZW50aWZ5KHdvcmtlci5pZCwgc2hhcmRJZCwgYnVja2V0SWQpXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9KSxcbiAgICAgIClcblxuICAgICAgLy8gQ2hlY2sgYW5kIHJlc2hhcmQgYXV0b21hdGljYWxseSBpZiBhdXRvIHJlc2hhcmRpbmcgaXMgZW5hYmxlZC5cbiAgICAgIGlmIChnYXRld2F5LnJlc2hhcmRpbmcuZW5hYmxlZCAmJiBnYXRld2F5LnJlc2hhcmRpbmcuY2hlY2tJbnRlcnZhbCAhPT0gLTEpIHtcbiAgICAgICAgZ2F0ZXdheS5yZXNoYXJkaW5nLmNoZWNrSW50ZXJ2YWxJZCA9IHNldEludGVydmFsKGFzeW5jICgpID0+IHtcbiAgICAgICAgICBjb25zdCByZXNoYXJkaW5nSW5mbyA9IGF3YWl0IGdhdGV3YXkucmVzaGFyZGluZy5jaGVja0lmUmVzaGFyZGluZ0lzTmVlZGVkKClcblxuICAgICAgICAgIGlmIChyZXNoYXJkaW5nSW5mby5uZWVkZWQgJiYgcmVzaGFyZGluZ0luZm8uaW5mbykgYXdhaXQgZ2F0ZXdheS5yZXNoYXJkaW5nLnJlc2hhcmQocmVzaGFyZGluZ0luZm8uaW5mbylcbiAgICAgICAgfSwgZ2F0ZXdheS5yZXNoYXJkaW5nLmNoZWNrSW50ZXJ2YWwpXG4gICAgICB9XG4gICAgfSxcbiAgICBhc3luYyBzaHV0ZG93bihjb2RlLCByZWFzb24sIGNsZWFyUmVzaGFyZGluZ0ludGVydmFsID0gdHJ1ZSkge1xuICAgICAgZ2F0ZXdheS5zaGFyZHMuZm9yRWFjaCgoc2hhcmQpID0+IHNoYXJkLmNsb3NlKGNvZGUsIHJlYXNvbikpXG5cbiAgICAgIGlmIChjbGVhclJlc2hhcmRpbmdJbnRlcnZhbCAmJiBnYXRld2F5LnJlc2hhcmRpbmcuY2hlY2tJbnRlcnZhbElkKSBjbGVhckludGVydmFsKGdhdGV3YXkucmVzaGFyZGluZy5jaGVja0ludGVydmFsSWQpXG5cbiAgICAgIGF3YWl0IGRlbGF5KDUwMDApXG4gICAgfSxcbiAgICBhc3luYyBzZW5kUGF5bG9hZChzaGFyZElkLCBwYXlsb2FkKSB7XG4gICAgICBjb25zdCBzaGFyZCA9IGdhdGV3YXkuc2hhcmRzLmdldChzaGFyZElkKVxuXG4gICAgICBpZiAoIXNoYXJkKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgU2hhcmQgKGlkOiAke3NoYXJkSWR9IG5vdCBmb3VuZGApXG4gICAgICB9XG5cbiAgICAgIGF3YWl0IHNoYXJkLnNlbmQocGF5bG9hZClcbiAgICB9LFxuICAgIGFzeW5jIHRlbGxXb3JrZXJUb0lkZW50aWZ5KHdvcmtlcklkLCBzaGFyZElkLCBidWNrZXRJZCkge1xuICAgICAgZ2F0ZXdheS5sb2dnZXIuZGVidWcoYFtHYXRld2F5XSB0ZWxsIHdvcmtlciB0byBpZGVudGlmeSAoJHt3b3JrZXJJZH0sICR7c2hhcmRJZH0sICR7YnVja2V0SWR9KWApXG4gICAgICBhd2FpdCBnYXRld2F5LmlkZW50aWZ5KHNoYXJkSWQpXG4gICAgfSxcbiAgICBhc3luYyBpZGVudGlmeShzaGFyZElkOiBudW1iZXIpIHtcbiAgICAgIGxldCBzaGFyZCA9IHRoaXMuc2hhcmRzLmdldChzaGFyZElkKVxuICAgICAgZ2F0ZXdheS5sb2dnZXIuZGVidWcoYFtHYXRld2F5XSBpZGVudGlmeWluZyAke3NoYXJkID8gJ2V4aXN0aW5nJyA6ICduZXcnfSBzaGFyZCAoJHtzaGFyZElkfSlgKVxuXG4gICAgICBpZiAoIXNoYXJkKSB7XG4gICAgICAgIHNoYXJkID0gbmV3IFNoYXJkKHtcbiAgICAgICAgICBpZDogc2hhcmRJZCxcbiAgICAgICAgICBjb25uZWN0aW9uOiB7XG4gICAgICAgICAgICBjb21wcmVzczogdGhpcy5jb21wcmVzcyxcbiAgICAgICAgICAgIGludGVudHM6IHRoaXMuaW50ZW50cyxcbiAgICAgICAgICAgIHByb3BlcnRpZXM6IHRoaXMucHJvcGVydGllcyxcbiAgICAgICAgICAgIHRva2VuOiB0aGlzLnRva2VuLFxuICAgICAgICAgICAgdG90YWxTaGFyZHM6IHRoaXMudG90YWxTaGFyZHMsXG4gICAgICAgICAgICB1cmw6IHRoaXMudXJsLFxuICAgICAgICAgICAgdmVyc2lvbjogdGhpcy52ZXJzaW9uLFxuICAgICAgICAgIH0sXG4gICAgICAgICAgZXZlbnRzOiBvcHRpb25zLmV2ZW50cyA/PyB7fSxcbiAgICAgICAgICBsb2dnZXI6IHRoaXMubG9nZ2VyLFxuICAgICAgICAgIHJlcXVlc3RJZGVudGlmeTogYXN5bmMgKCkgPT4ge1xuICAgICAgICAgICAgYXdhaXQgZ2F0ZXdheS5pZGVudGlmeShzaGFyZElkKVxuICAgICAgICAgIH0sXG4gICAgICAgICAgc2hhcmRJc1JlYWR5OiBhc3luYyAoKSA9PiB7XG4gICAgICAgICAgICBnYXRld2F5LmxvZ2dlci5kZWJ1ZyhgW1NoYXJkXSBTaGFyZCAjJHtzaGFyZElkfSBpcyByZWFkeWApXG4gICAgICAgICAgICBhd2FpdCBkZWxheShnYXRld2F5LnNwYXduU2hhcmREZWxheSlcbiAgICAgICAgICAgIGdhdGV3YXkubG9nZ2VyLmRlYnVnKGBbU2hhcmRdIFJlc29sdmluZyBzaGFyZCBpZGVudGlmeSByZXF1ZXN0YClcbiAgICAgICAgICAgIGdhdGV3YXkuYnVja2V0cy5nZXQoc2hhcmRJZCAlIGdhdGV3YXkuY29ubmVjdGlvbi5zZXNzaW9uU3RhcnRMaW1pdC5tYXhDb25jdXJyZW5jeSkhLmlkZW50aWZ5UmVxdWVzdHMuc2hpZnQoKT8uKClcbiAgICAgICAgICB9LFxuICAgICAgICB9KVxuXG4gICAgICAgIGlmICh0aGlzLnByZWZlclNuYWtlQ2FzZSkge1xuICAgICAgICAgIHNoYXJkLmZvcndhcmRUb0JvdCA9IGFzeW5jIChwYXlsb2FkKSA9PiB7XG4gICAgICAgICAgICBzaGFyZCEuZXZlbnRzLm1lc3NhZ2U/LihzaGFyZCEsIHBheWxvYWQpXG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5zaGFyZHMuc2V0KHNoYXJkSWQsIHNoYXJkKVxuICAgICAgfVxuXG4gICAgICBjb25zdCBidWNrZXQgPSBnYXRld2F5LmJ1Y2tldHMuZ2V0KHNoYXJkSWQgJSBnYXRld2F5LmNvbm5lY3Rpb24uc2Vzc2lvblN0YXJ0TGltaXQubWF4Q29uY3VycmVuY3kpXG4gICAgICBpZiAoIWJ1Y2tldCkgcmV0dXJuXG5cbiAgICAgIHJldHVybiBhd2FpdCBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4ge1xuICAgICAgICAvLyBNYXJrIHRoYXQgd2UgYXJlIG1ha2luZyBhbiBpZGVudGlmeSByZXF1ZXN0IHNvIGFub3RoZXIgaXMgbm90IG1hZGUuXG4gICAgICAgIGJ1Y2tldC5pZGVudGlmeVJlcXVlc3RzLnB1c2gocmVzb2x2ZSlcbiAgICAgICAgZ2F0ZXdheS5sb2dnZXIuZGVidWcoYFtHYXRld2F5XSBpZGVudGlmeWluZyBzaGFyZCAjKCR7c2hhcmRJZH0pLmApXG4gICAgICAgIC8vIFRoaXMgd2lsbCB0cmlnZ2VyIGlkZW50aWZ5IGFuZCB3aGVuIFJFQURZIGlzIHJlY2VpdmVkIGl0IHdpbGwgcmVzb2x2ZSB0aGUgYWJvdmUgcmVxdWVzdC5cbiAgICAgICAgc2hhcmQ/LmlkZW50aWZ5KClcbiAgICAgIH0pXG4gICAgfSxcbiAgICBhc3luYyBraWxsKHNoYXJkSWQ6IG51bWJlcikge1xuICAgICAgY29uc3Qgc2hhcmQgPSB0aGlzLnNoYXJkcy5nZXQoc2hhcmRJZClcbiAgICAgIGlmICghc2hhcmQpIHtcbiAgICAgICAgcmV0dXJuIGdhdGV3YXkubG9nZ2VyLmRlYnVnKGBbR2F0ZXdheV0ga2lsbCBzaGFyZCBidXQgbm90IGZvdW5kICgke3NoYXJkSWR9KWApXG4gICAgICB9XG5cbiAgICAgIGdhdGV3YXkubG9nZ2VyLmRlYnVnKGBbR2F0ZXdheV0ga2lsbCBzaGFyZCAoJHtzaGFyZElkfSlgKVxuICAgICAgdGhpcy5zaGFyZHMuZGVsZXRlKHNoYXJkSWQpXG4gICAgICBhd2FpdCBzaGFyZC5zaHV0ZG93bigpXG4gICAgfSxcbiAgICBhc3luYyByZXF1ZXN0SWRlbnRpZnkoc2hhcmRJZDogbnVtYmVyKSB7XG4gICAgICBnYXRld2F5LmxvZ2dlci5kZWJ1ZyhgW0dhdGV3YXldIHJlcXVlc3RpbmcgaWRlbnRpZnlgKVxuICAgICAgLy8gY29uc3QgYnVja2V0ID0gZ2F0ZXdheS5idWNrZXRzLmdldChzaGFyZElkICUgZ2F0ZXdheS5jb25uZWN0aW9uLnNlc3Npb25TdGFydExpbWl0Lm1heENvbmN1cnJlbmN5KVxuICAgICAgLy8gaWYgKCFidWNrZXQpIHJldHVyblxuXG4gICAgICAvLyByZXR1cm4gYXdhaXQgbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHtcbiAgICAgIC8vICAgYnVja2V0LmlkZW50aWZ5UmVxdWVzdHMucHVzaChyZXNvbHZlKVxuICAgICAgLy8gfSlcbiAgICB9LFxuXG4gICAgLy8gSGVscGVycyBtZXRob2RzIGJlbG93IHRoaXNcblxuICAgIGNhbGN1bGF0ZVNoYXJkSWQoZ3VpbGRJZCwgdG90YWxTaGFyZHMpIHtcbiAgICAgIC8vIElmIG5vbmUgaXMgcHJvdmlkZWQsIHVzZSB0aGUgdG90YWwgc2hhcmRzIG51bWJlciBmcm9tIGdhdGV3YXkgb2JqZWN0LlxuICAgICAgaWYgKCF0b3RhbFNoYXJkcykgdG90YWxTaGFyZHMgPSBnYXRld2F5LnRvdGFsU2hhcmRzXG4gICAgICAvLyBJZiBpdCBpcyBvbmx5IDEgc2hhcmQsIGl0IHdpbGwgYWx3YXlzIGJlIHNoYXJkIGlkIDBcbiAgICAgIGlmICh0b3RhbFNoYXJkcyA9PT0gMSkge1xuICAgICAgICBnYXRld2F5LmxvZ2dlci5kZWJ1ZyhgW0dhdGV3YXldIGNhbGN1bGF0ZVNoYXJkSWQgKDEgc2hhcmQpYClcbiAgICAgICAgcmV0dXJuIDBcbiAgICAgIH1cblxuICAgICAgZ2F0ZXdheS5sb2dnZXIuZGVidWcoYFtHYXRld2F5XSBjYWxjdWxhdGVTaGFyZElkIChndWlsZElkOiAke2d1aWxkSWR9LCB0b3RhbFNoYXJkczogJHt0b3RhbFNoYXJkc30pYClcbiAgICAgIHJldHVybiBOdW1iZXIoKEJpZ0ludChndWlsZElkKSA+PiAyMm4pICUgQmlnSW50KHRvdGFsU2hhcmRzKSlcbiAgICB9LFxuXG4gICAgYXN5bmMgam9pblZvaWNlQ2hhbm5lbChndWlsZElkLCBjaGFubmVsSWQsIG9wdGlvbnMpIHtcbiAgICAgIGNvbnN0IHNoYXJkSWQgPSBnYXRld2F5LmNhbGN1bGF0ZVNoYXJkSWQoZ3VpbGRJZClcblxuICAgICAgZ2F0ZXdheS5sb2dnZXIuZGVidWcoYFtHYXRld2F5XSBqb2luVm9pY2VDaGFubmVsIGd1aWxkSWQ6ICR7Z3VpbGRJZH0gY2hhbm5lbElkOiAke2NoYW5uZWxJZH1gKVxuXG4gICAgICBhd2FpdCBnYXRld2F5LnNlbmRQYXlsb2FkKHNoYXJkSWQsIHtcbiAgICAgICAgb3A6IEdhdGV3YXlPcGNvZGVzLlZvaWNlU3RhdGVVcGRhdGUsXG4gICAgICAgIGQ6IHtcbiAgICAgICAgICBndWlsZF9pZDogZ3VpbGRJZC50b1N0cmluZygpLFxuICAgICAgICAgIGNoYW5uZWxfaWQ6IGNoYW5uZWxJZC50b1N0cmluZygpLFxuICAgICAgICAgIHNlbGZfbXV0ZTogb3B0aW9ucz8uc2VsZk11dGUgPz8gZmFsc2UsXG4gICAgICAgICAgc2VsZl9kZWFmOiBvcHRpb25zPy5zZWxmRGVhZiA/PyB0cnVlLFxuICAgICAgICB9LFxuICAgICAgfSlcbiAgICB9LFxuXG4gICAgYXN5bmMgZWRpdEJvdFN0YXR1cyhkYXRhKSB7XG4gICAgICBnYXRld2F5LmxvZ2dlci5kZWJ1ZyhgW0dhdGV3YXldIGVkaXRCb3RTdGF0dXMgZGF0YTogJHtKU09OLnN0cmluZ2lmeShkYXRhKX1gKVxuXG4gICAgICBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgICAgWy4uLmdhdGV3YXkuc2hhcmRzLnZhbHVlcygpXS5tYXAoYXN5bmMgKHNoYXJkKSA9PiB7XG4gICAgICAgICAgZ2F0ZXdheS5lZGl0U2hhcmRTdGF0dXMoc2hhcmQuaWQsIGRhdGEpXG4gICAgICAgIH0pLFxuICAgICAgKVxuICAgIH0sXG5cbiAgICBhc3luYyBlZGl0U2hhcmRTdGF0dXMoc2hhcmRJZCwgZGF0YSkge1xuICAgICAgZ2F0ZXdheS5sb2dnZXIuZGVidWcoYFtHYXRld2F5XSBlZGl0U2hhcmRTdGF0dXMgc2hhcmRJZDogJHtzaGFyZElkfSAtPiBkYXRhOiAke0pTT04uc3RyaW5naWZ5KGRhdGEpfWApXG5cbiAgICAgIGF3YWl0IGdhdGV3YXkuc2VuZFBheWxvYWQoc2hhcmRJZCwge1xuICAgICAgICBvcDogR2F0ZXdheU9wY29kZXMuUHJlc2VuY2VVcGRhdGUsXG4gICAgICAgIGQ6IHtcbiAgICAgICAgICBzaW5jZTogbnVsbCxcbiAgICAgICAgICBhZms6IGZhbHNlLFxuICAgICAgICAgIGFjdGl2aXRpZXM6IGRhdGEuYWN0aXZpdGllcyxcbiAgICAgICAgICBzdGF0dXM6IGRhdGEuc3RhdHVzLFxuICAgICAgICB9LFxuICAgICAgfSlcbiAgICB9LFxuXG4gICAgYXN5bmMgcmVxdWVzdE1lbWJlcnMoZ3VpbGRJZCwgb3B0aW9ucykge1xuICAgICAgY29uc3Qgc2hhcmRJZCA9IGdhdGV3YXkuY2FsY3VsYXRlU2hhcmRJZChndWlsZElkKVxuXG4gICAgICBpZiAoZ2F0ZXdheS5pbnRlbnRzICYmICghb3B0aW9ucz8ubGltaXQgfHwgb3B0aW9ucy5saW1pdCA+IDEpICYmICEoZ2F0ZXdheS5pbnRlbnRzICYgR2F0ZXdheUludGVudHMuR3VpbGRNZW1iZXJzKSlcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdDYW5ub3QgZmV0Y2ggbW9yZSB0aGVuIDEgbWVtYmVyIHdpdGhvdXQgdGhlIEdVSUxEX01FTUJFUlMgaW50ZW50JylcblxuICAgICAgZ2F0ZXdheS5sb2dnZXIuZGVidWcoYFtHYXRld2F5XSByZXF1ZXN0TWVtYmVycyBndWlsZElkOiAke2d1aWxkSWR9IC0+IGRhdGE6ICR7SlNPTi5zdHJpbmdpZnkob3B0aW9ucyl9YClcblxuICAgICAgaWYgKG9wdGlvbnM/LnVzZXJJZHM/Lmxlbmd0aCkge1xuICAgICAgICBnYXRld2F5LmxvZ2dlci5kZWJ1ZyhgW0dhdGV3YXldIHJlcXVlc3RNZW1iZXJzIGd1aWxkSWQ6ICR7Z3VpbGRJZH0gLT4gc2V0dGluZyB1c2VyIGxpbWl0IGJhc2VkIG9uIHVzZXJJZHMgbGVuZ3RoOiAke29wdGlvbnMudXNlcklkcy5sZW5ndGh9YClcblxuICAgICAgICBvcHRpb25zLmxpbWl0ID0gb3B0aW9ucy51c2VySWRzLmxlbmd0aFxuICAgICAgfVxuXG4gICAgICBjb25zdCBtZW1iZXJzID1cbiAgICAgICAgIWdhdGV3YXkuY2FjaGUucmVxdWVzdE1lbWJlcnMuZW5hYmxlZCB8fCAhb3B0aW9ucz8ubm9uY2VcbiAgICAgICAgICA/IFtdXG4gICAgICAgICAgOiBuZXcgUHJvbWlzZTxDYW1lbGl6ZTxEaXNjb3JkTWVtYmVyV2l0aFVzZXJbXT4+KChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgICAgICAgLy8gU2hvdWxkIG5ldmVyIGhhcHBlbi5cbiAgICAgICAgICAgICAgaWYgKCFnYXRld2F5LmNhY2hlLnJlcXVlc3RNZW1iZXJzLmVuYWJsZWQgfHwgIW9wdGlvbnM/Lm5vbmNlKSB7XG4gICAgICAgICAgICAgICAgcmVqZWN0KG5ldyBFcnJvcihcIkNhbid0IHJlcXVlc3QgdGhlIG1lbWJlcnMgd2l0aG91dCB0aGUgbm9uY2Ugb3Igd2l0aCB0aGUgZmVhdHVyZSBkaXNhYmxlZC5cIikpXG4gICAgICAgICAgICAgICAgcmV0dXJuXG4gICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICBnYXRld2F5LmNhY2hlLnJlcXVlc3RNZW1iZXJzLnBlbmRpbmcuc2V0KG9wdGlvbnMubm9uY2UsIHtcbiAgICAgICAgICAgICAgICBub25jZTogb3B0aW9ucy5ub25jZSxcbiAgICAgICAgICAgICAgICByZXNvbHZlLFxuICAgICAgICAgICAgICAgIG1lbWJlcnM6IFtdLFxuICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgfSlcblxuICAgICAgYXdhaXQgZ2F0ZXdheS5zZW5kUGF5bG9hZChzaGFyZElkLCB7XG4gICAgICAgIG9wOiBHYXRld2F5T3Bjb2Rlcy5SZXF1ZXN0R3VpbGRNZW1iZXJzLFxuICAgICAgICBkOiB7XG4gICAgICAgICAgZ3VpbGRfaWQ6IGd1aWxkSWQudG9TdHJpbmcoKSxcbiAgICAgICAgICAvLyBJZiBhIHF1ZXJ5IGlzIHByb3ZpZGVkIHVzZSBpdCwgT1IgaWYgYSBsaW1pdCBpcyBOT1QgcHJvdmlkZWQgdXNlIFwiXCJcbiAgICAgICAgICBxdWVyeTogb3B0aW9ucz8ucXVlcnkgPz8gKG9wdGlvbnM/LmxpbWl0ID8gdW5kZWZpbmVkIDogJycpLFxuICAgICAgICAgIGxpbWl0OiBvcHRpb25zPy5saW1pdCA/PyAwLFxuICAgICAgICAgIHByZXNlbmNlczogb3B0aW9ucz8ucHJlc2VuY2VzID8/IGZhbHNlLFxuICAgICAgICAgIHVzZXJfaWRzOiBvcHRpb25zPy51c2VySWRzPy5tYXAoKGlkKSA9PiBpZC50b1N0cmluZygpKSxcbiAgICAgICAgICBub25jZTogb3B0aW9ucz8ubm9uY2UsXG4gICAgICAgIH0sXG4gICAgICB9KVxuXG4gICAgICByZXR1cm4gYXdhaXQgbWVtYmVyc1xuICAgIH0sXG5cbiAgICBhc3luYyBsZWF2ZVZvaWNlQ2hhbm5lbChndWlsZElkKSB7XG4gICAgICBjb25zdCBzaGFyZElkID0gZ2F0ZXdheS5jYWxjdWxhdGVTaGFyZElkKGd1aWxkSWQpXG5cbiAgICAgIGdhdGV3YXkubG9nZ2VyLmRlYnVnKGBbR2F0ZXdheV0gbGVhdmVWb2ljZUNoYW5uZWwgZ3VpbGRJZDogJHtndWlsZElkfSBTaGFyZCAke3NoYXJkSWR9YClcblxuICAgICAgYXdhaXQgZ2F0ZXdheS5zZW5kUGF5bG9hZChzaGFyZElkLCB7XG4gICAgICAgIG9wOiBHYXRld2F5T3Bjb2Rlcy5Wb2ljZVN0YXRlVXBkYXRlLFxuICAgICAgICBkOiB7XG4gICAgICAgICAgZ3VpbGRfaWQ6IGd1aWxkSWQudG9TdHJpbmcoKSxcbiAgICAgICAgICBjaGFubmVsX2lkOiBudWxsLFxuICAgICAgICAgIHNlbGZfbXV0ZTogZmFsc2UsXG4gICAgICAgICAgc2VsZl9kZWFmOiBmYWxzZSxcbiAgICAgICAgfSxcbiAgICAgIH0pXG4gICAgfSxcbiAgfVxuXG4gIHJldHVybiBnYXRld2F5XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ3JlYXRlR2F0ZXdheU1hbmFnZXJPcHRpb25zIHtcbiAgLyoqXG4gICAqIElkIG9mIHRoZSBmaXJzdCBTaGFyZCB3aGljaCBzaG91bGQgZ2V0IGNvbnRyb2xsZWQgYnkgdGhpcyBtYW5hZ2VyLlxuICAgKiBAZGVmYXVsdCAwXG4gICAqL1xuICBmaXJzdFNoYXJkSWQ/OiBudW1iZXJcbiAgLyoqXG4gICAqIElkIG9mIHRoZSBsYXN0IFNoYXJkIHdoaWNoIHNob3VsZCBnZXQgY29udHJvbGxlZCBieSB0aGlzIG1hbmFnZXIuXG4gICAqIEBkZWZhdWx0IDBcbiAgICovXG4gIGxhc3RTaGFyZElkPzogbnVtYmVyXG4gIC8qKlxuICAgKiBEZWxheSBpbiBtaWxsaXNlY29uZHMgdG8gd2FpdCBiZWZvcmUgc3Bhd25pbmcgbmV4dCBzaGFyZC4gT1BUSU1BTCBJUyBBQk9WRSA1MTAwLiBZT1UgRE9OJ1QgV0FOVCBUTyBISVQgVEhFIFJBVEUgTElNSVQhISFcbiAgICogQGRlZmF1bHQgNTMwMFxuICAgKi9cbiAgc3Bhd25TaGFyZERlbGF5PzogbnVtYmVyXG4gIC8qKlxuICAgKiBXaGV0aGVyIHRvIHNlbmQgdGhlIGRpc2NvcmQgcGFja2V0cyBpbiBzbmFrZSBjYXNlIGZvcm0uXG4gICAqIEBkZWZhdWx0IGZhbHNlXG4gICAqL1xuICBwcmVmZXJTbmFrZUNhc2U/OiBib29sZWFuXG4gIC8qKlxuICAgKiBUb3RhbCBhbW91bnQgb2Ygc2hhcmRzIHlvdXIgYm90IHVzZXMuIFVzZWZ1bCBmb3IgemVyby1kb3dudGltZSB1cGRhdGVzIG9yIHJlc2hhcmRpbmcuXG4gICAqIEBkZWZhdWx0IDFcbiAgICovXG4gIHRvdGFsU2hhcmRzPzogbnVtYmVyXG4gIC8qKlxuICAgKiBUaGUgYW1vdW50IG9mIHNoYXJkcyB0byBsb2FkIHBlciB3b3JrZXIuXG4gICAqIEBkZWZhdWx0IDI1XG4gICAqL1xuICBzaGFyZHNQZXJXb3JrZXI/OiBudW1iZXJcbiAgLyoqXG4gICAqIFRoZSB0b3RhbCBhbW91bnQgb2Ygd29ya2VycyB0byB1c2UgZm9yIHlvdXIgYm90LlxuICAgKiBAZGVmYXVsdCA0XG4gICAqL1xuICB0b3RhbFdvcmtlcnM/OiBudW1iZXJcbiAgLyoqIEltcG9ydGFudCBkYXRhIHdoaWNoIGlzIHVzZWQgYnkgdGhlIG1hbmFnZXIgdG8gY29ubmVjdCBzaGFyZHMgdG8gdGhlIGdhdGV3YXkuICovXG4gIGNvbm5lY3Rpb24/OiBDYW1lbGl6ZTxEaXNjb3JkR2V0R2F0ZXdheUJvdD5cbiAgLyoqIFdoZXRoZXIgaW5jb21pbmcgcGF5bG9hZHMgYXJlIGNvbXByZXNzZWQgdXNpbmcgemxpYi5cbiAgICpcbiAgICogQGRlZmF1bHQgZmFsc2VcbiAgICovXG4gIGNvbXByZXNzPzogYm9vbGVhblxuICAvKiogVGhlIGNhbGN1bGF0ZWQgaW50ZW50IHZhbHVlIG9mIHRoZSBldmVudHMgd2hpY2ggdGhlIHNoYXJkIHNob3VsZCByZWNlaXZlLlxuICAgKlxuICAgKiBAZGVmYXVsdCAwXG4gICAqL1xuICBpbnRlbnRzPzogbnVtYmVyXG4gIC8qKiBJZGVudGlmeSBwcm9wZXJ0aWVzIHRvIHVzZSAqL1xuICBwcm9wZXJ0aWVzPzoge1xuICAgIC8qKiBPcGVyYXRpbmcgc3lzdGVtIHRoZSBzaGFyZCBydW5zIG9uLlxuICAgICAqXG4gICAgICogQGRlZmF1bHQgXCJkYXJ3aW5cIiB8IFwibGludXhcIiB8IFwid2luZG93c1wiXG4gICAgICovXG4gICAgb3M6IHN0cmluZ1xuICAgIC8qKiBUaGUgXCJicm93c2VyXCIgd2hlcmUgdGhpcyBzaGFyZCBpcyBydW5uaW5nIG9uLlxuICAgICAqXG4gICAgICogQGRlZmF1bHQgXCJEaXNjb3JkZW5vXCJcbiAgICAgKi9cbiAgICBicm93c2VyOiBzdHJpbmdcbiAgICAvKiogVGhlIGRldmljZSBvbiB3aGljaCB0aGUgc2hhcmQgaXMgcnVubmluZy5cbiAgICAgKlxuICAgICAqIEBkZWZhdWx0IFwiRGlzY29yZGVub1wiXG4gICAgICovXG4gICAgZGV2aWNlOiBzdHJpbmdcbiAgfVxuICAvKiogQm90IHRva2VuIHdoaWNoIGlzIHVzZWQgdG8gY29ubmVjdCB0byBEaXNjb3JkICovXG4gIHRva2VuOiBzdHJpbmdcbiAgLyoqIFRoZSBVUkwgb2YgdGhlIGdhdGV3YXkgd2hpY2ggc2hvdWxkIGJlIGNvbm5lY3RlZCB0by5cbiAgICpcbiAgICogQGRlZmF1bHQgXCJ3c3M6Ly9nYXRld2F5LmRpc2NvcmQuZ2dcIlxuICAgKi9cbiAgdXJsPzogc3RyaW5nXG4gIC8qKiBUaGUgZ2F0ZXdheSB2ZXJzaW9uIHdoaWNoIHNob3VsZCBiZSB1c2VkLlxuICAgKlxuICAgKiBAZGVmYXVsdCAxMFxuICAgKi9cbiAgdmVyc2lvbj86IG51bWJlclxuICAvKiogVGhlIGV2ZW50cyBoYW5kbGVycyAqL1xuICBldmVudHM/OiBTaGFyZEV2ZW50c1xuICAvKiogVGhpcyBtYW5hZ2VycyBjYWNoZSByZWxhdGVkIHNldHRpbmdzLiAqL1xuICBjYWNoZT86IHtcbiAgICByZXF1ZXN0TWVtYmVycz86IHtcbiAgICAgIC8qKlxuICAgICAgICogV2hldGhlciBvciBub3QgcmVxdWVzdCBtZW1iZXIgcmVxdWVzdHMgc2hvdWxkIGJlIGNhY2hlZC5cbiAgICAgICAqIEBkZWZhdWx0IGZhbHNlXG4gICAgICAgKi9cbiAgICAgIGVuYWJsZWQ/OiBib29sZWFuXG4gICAgfVxuICB9XG4gIC8qKlxuICAgKiBUaGUgbG9nZ2VyIHRoYXQgdGhlIGdhdGV3YXkgbWFuYWdlciB3aWxsIHVzZVxuICAgKiBAZGVmYXVsdCBsb2dnZXIgLy8gVGhlIGxvZ2dlciBleHBvcnRlZCBieSBgQGRpc2NvcmRlbm8vdXRpbHNgXG4gICAqL1xuICBsb2dnZXI/OiBQaWNrPHR5cGVvZiBsb2dnZXIsICdkZWJ1ZycgfCAnaW5mbycgfCAnd2FybicgfCAnZXJyb3InIHwgJ2ZhdGFsJz5cbn1cblxuZXhwb3J0IGludGVyZmFjZSBHYXRld2F5TWFuYWdlciBleHRlbmRzIFJlcXVpcmVkPENyZWF0ZUdhdGV3YXlNYW5hZ2VyT3B0aW9ucz4ge1xuICAvKiogVGhlIG1heCBjb25jdXJyZW5jeSBidWNrZXRzLiBUaG9zZSB3aWxsIGJlIGNyZWF0ZWQgd2hlbiB0aGUgYHNwYXduU2hhcmRzYCAod2hpY2ggY2FsbHMgYHByZXBhcmVCdWNrZXRzYCB1bmRlciB0aGUgaG9vZCkgZnVuY3Rpb24gZ2V0cyBjYWxsZWQuICovXG4gIGJ1Y2tldHM6IE1hcDxcbiAgICBudW1iZXIsXG4gICAge1xuICAgICAgd29ya2VyczogQXJyYXk8eyBpZDogbnVtYmVyOyBxdWV1ZTogbnVtYmVyW10gfT5cbiAgICAgIC8qKiBSZXF1ZXN0cyB0byBpZGVudGlmeSBzaGFyZHMgYXJlIG1hZGUgYmFzZWQgb24gd2hldGhlciBpdCBpcyBhdmFpbGFibGUgdG8gYmUgbWFkZS4gKi9cbiAgICAgIGlkZW50aWZ5UmVxdWVzdHM6IEFycmF5PCh2YWx1ZTogdm9pZCB8IFByb21pc2VMaWtlPHZvaWQ+KSA9PiB2b2lkPlxuICAgIH1cbiAgPlxuICAvKiogVGhlIHNoYXJkcyB0aGF0IGFyZSBjcmVhdGVkLiAqL1xuICBzaGFyZHM6IE1hcDxudW1iZXIsIFNoYXJkPlxuICAvKiogVGhlIGxvZ2dlciBmb3IgdGhlIGdhdGV3YXkgbWFuYWdlciAqL1xuICBsb2dnZXI6IFBpY2s8dHlwZW9mIGxvZ2dlciwgJ2RlYnVnJyB8ICdpbmZvJyB8ICd3YXJuJyB8ICdlcnJvcicgfCAnZmF0YWwnPlxuICAvKiogRXZlcnl0aGluZyByZWxhdGVkIHRvIHJlc2hhcmRpbmcuICovXG4gIHJlc2hhcmRpbmc6IHtcbiAgICAvKipcbiAgICAgKiBXaGV0aGVyIG9yIG5vdCBhdXRvbWF0ZWQgcmVzaGFyZGluZyBzaG91bGQgYmUgZW5hYmxlZC5cbiAgICAgKiBAZGVmYXVsdCB0cnVlXG4gICAgICovXG4gICAgZW5hYmxlZDogYm9vbGVhblxuICAgIC8qKlxuICAgICAqIFRoZSAlIG9mIGhvdyBmdWxsIGEgc2hhcmQgaXMgd2hlbiByZXNoYXJkaW5nIHNob3VsZCBiZSB0cmlnZ2VyZWQuXG4gICAgICogQGRlZmF1bHQgODAgYXMgaW4gODAlXG4gICAgICovXG4gICAgc2hhcmRzRnVsbFBlcmNlbnRhZ2U6IG51bWJlclxuICAgIC8qKlxuICAgICAqIFRoZSBpbnRlcnZhbCBpbiBtaWxsaXNlY29uZHMsIG9mIGhvdyBvZnRlbiB0byBjaGVjayB3aGV0aGVyIHJlc2hhcmRpbmcgaXMgbmVlZGVkIGFuZCByZXNoYXJkIGF1dG9tYXRpY2FsbHkuIFNldCB0byAtMSB0byBkaXNhYmxlIGF1dG8gcmVzaGFyZGluZy5cbiAgICAgKiBAZGVmYXVsdCAyODgwMDAwMCAoOCBob3VycylcbiAgICAgKi9cbiAgICBjaGVja0ludGVydmFsOiBudW1iZXJcbiAgICAvKipcbiAgICAgKiBUaGUgaW50ZXJ2YWwgaWQgb2YgdGhlIGNoZWNrIGludGVydmFsLiBUaGlzIGlzIHVzZWQgdG8gY2xlYXIgdGhlIGludGVydmFsIHdoZW4gdGhlIG1hbmFnZXIgaXMgc2h1dGRvd24uXG4gICAgICovXG4gICAgY2hlY2tJbnRlcnZhbElkPzogTm9kZUpTLlRpbWVvdXQgfCB1bmRlZmluZWRcbiAgICAvKiogSG9sZHMgdGhlIHNoYXJkcyB0aGF0IHJlc2hhcmRpbmcgaGFzIGNyZWF0ZWQuIE9uY2UgcmVzaGFyZGluZyBpcyBkb25lLCB0aGlzIHJlcGxhY2VzIHRoZSBnYXRld2F5LnNoYXJkcyAqL1xuICAgIHNoYXJkczogQ29sbGVjdGlvbjxudW1iZXIsIFNoYXJkPlxuICAgIC8qKiBIb2xkcyB0aGUgcGVuZGluZyBzaGFyZHMgdGhhdCBoYXZlIGJlZW4gY3JlYXRlZCBhbmQgYXJlIHBlbmRpbmcgYWxsIHNoYXJkcyBmaW5pc2ggbG9hZGluZy4gKi9cbiAgICBwZW5kaW5nU2hhcmRzOiBDb2xsZWN0aW9uPG51bWJlciwgU2hhcmQ+XG4gICAgLyoqIEhhbmRsZXIgdG8gZ2V0IHNoYXJkIGNvdW50IGFuZCBvdGhlciBzZXNzaW9uIGluZm8uICovXG4gICAgZ2V0U2Vzc2lvbkluZm86ICgpID0+IFByb21pc2U8Q2FtZWxpemU8RGlzY29yZEdldEdhdGV3YXlCb3Q+PlxuICAgIC8qKiBIYW5kbGVyIHRvIGVkaXQgdGhlIHNoYXJkIGlkIG9uIGFueSBjYWNoZWQgZ3VpbGRzLiAqL1xuICAgIHVwZGF0ZUd1aWxkc1NoYXJkSWQ6IChndWlsZElkczogc3RyaW5nW10sIHNoYXJkSWQ6IG51bWJlcikgPT4gUHJvbWlzZTx2b2lkPlxuICAgIC8qKiBIYW5kbGVyIHRvIGNoZWNrIGlmIHJlc2hhcmRpbmcgaXMgbmVjZXNzYXJ5LiAqL1xuICAgIGNoZWNrSWZSZXNoYXJkaW5nSXNOZWVkZWQ6ICgpID0+IFByb21pc2U8eyBuZWVkZWQ6IGJvb2xlYW47IGluZm8/OiBDYW1lbGl6ZTxEaXNjb3JkR2V0R2F0ZXdheUJvdD4gfT5cbiAgICAvKiogSGFuZGxlciB0byBiZWdpbiByZXNoYXJkaW5nLiAqL1xuICAgIHJlc2hhcmQ6IChpbmZvOiBDYW1lbGl6ZTxEaXNjb3JkR2V0R2F0ZXdheUJvdD4gJiB7IGZpcnN0U2hhcmRJZD86IG51bWJlcjsgbGFzdFNoYXJkSWQ/OiBudW1iZXIgfSkgPT4gUHJvbWlzZTx2b2lkPlxuICAgIC8qKiBIYW5kbGVyIHRvIGNvbW11bmljYXRlIHRvIGEgd29ya2VyIHRoYXQgYSBzaGFyZCBuZWVkcyB0byBiZSBjcmVhdGVkLiAqL1xuICAgIHRlbGxXb3JrZXJUb1ByZXBhcmU6ICh3b3JrZXJJZDogbnVtYmVyLCBzaGFyZElkOiBudW1iZXIsIGJ1Y2tldElkOiBudW1iZXIpID0+IFByb21pc2U8dm9pZD5cbiAgICAvKiogSGFuZGxlciB0byBhbGVydCB0aGUgZ2F0ZXdheSB0aGF0IGEgc2hhcmQocmVzaGFyZGVkKSBpcyBvbmxpbmUuIEl0IHNob3VsZCBub3cgd2FpdCBmb3IgYWxsIHNoYXJkcyB0byBiZSBwZW5kaW5nIGJlZm9yZSBzaHV0dGluZyBvZmYgb2xkIHNoYXJkcy4gKi9cbiAgICBzaGFyZElzUGVuZGluZzogKHNoYXJkOiBTaGFyZCkgPT4gUHJvbWlzZTx2b2lkPlxuICB9XG4gIC8qKiBEZXRlcm1pbmUgbWF4IG51bWJlciBvZiBzaGFyZHMgdG8gdXNlIGJhc2VkIHVwb24gdGhlIG1heCBjb25jdXJyZW5jeS4gKi9cbiAgY2FsY3VsYXRlVG90YWxTaGFyZHM6ICgpID0+IG51bWJlclxuICAvKiogRGV0ZXJtaW5lIHRoZSBpZCBvZiB0aGUgd29ya2VyIHdoaWNoIGlzIGhhbmRsaW5nIGEgc2hhcmQuICovXG4gIGNhbGN1bGF0ZVdvcmtlcklkOiAoc2hhcmRJZDogbnVtYmVyKSA9PiBudW1iZXJcbiAgLyoqIFByZXBhcmVzIGFsbCB0aGUgYnVja2V0cyB0aGF0IGFyZSBhdmFpbGFibGUgZm9yIGlkZW50aWZ5aW5nIHRoZSBzaGFyZHMuICovXG4gIHByZXBhcmVCdWNrZXRzOiAoKSA9PiB2b2lkXG4gIC8qKiBTdGFydCBpZGVudGlmeWluZyBhbGwgdGhlIHNoYXJkcy4gKi9cbiAgc3Bhd25TaGFyZHM6ICgpID0+IFByb21pc2U8dm9pZD5cbiAgLyoqIFNodXRkb3duIGFsbCBzaGFyZHMuICovXG4gIHNodXRkb3duOiAoY29kZTogbnVtYmVyLCByZWFzb246IHN0cmluZywgY2xlYXJSZXNoYXJkaW5nSW50ZXJ2YWw/OiBib29sZWFuKSA9PiBQcm9taXNlPHZvaWQ+XG4gIHNlbmRQYXlsb2FkOiAoc2hhcmRJZDogbnVtYmVyLCBwYXlsb2FkOiBTaGFyZFNvY2tldFJlcXVlc3QpID0+IFByb21pc2U8dm9pZD5cbiAgLyoqIEFsbG93cyB1c2VycyB0byBob29rIGluIGFuZCBjaGFuZ2UgdG8gY29tbXVuaWNhdGUgdG8gZGlmZmVyZW50IHdvcmtlcnMgYWNyb3NzIGRpZmZlcmVudCBzZXJ2ZXJzIG9yIGFueXRoaW5nIHRoZXkgbGlrZS4gRm9yIGV4YW1wbGUgdXNpbmcgcmVkaXMgcHVic3ViIHRvIHRhbGsgdG8gb3RoZXIgc2VydmVycy4gKi9cbiAgdGVsbFdvcmtlclRvSWRlbnRpZnk6ICh3b3JrZXJJZDogbnVtYmVyLCBzaGFyZElkOiBudW1iZXIsIGJ1Y2tldElkOiBudW1iZXIpID0+IFByb21pc2U8dm9pZD5cbiAgLyoqIFRlbGwgdGhlIG1hbmFnZXIgdG8gaWRlbnRpZnkgYSBTaGFyZC4gSWYgdGhpcyBTaGFyZCBpcyBub3QgYWxyZWFkeSBtYW5hZ2VkIHRoaXMgd2lsbCBhbHNvIGFkZCB0aGUgU2hhcmQgdG8gdGhlIG1hbmFnZXIuICovXG4gIGlkZW50aWZ5OiAoc2hhcmRJZDogbnVtYmVyKSA9PiBQcm9taXNlPHZvaWQ+XG4gIC8qKiBLaWxsIGEgc2hhcmQuIENsb3NlIGEgc2hhcmRzIGNvbm5lY3Rpb24gdG8gRGlzY29yZCdzIGdhdGV3YXkgKGlmIGFueSkgYW5kIHJlbW92ZSBpdCBmcm9tIHRoZSBtYW5hZ2VyLiAqL1xuICBraWxsOiAoc2hhcmRJZDogbnVtYmVyKSA9PiBQcm9taXNlPHZvaWQ+XG4gIC8qKiBUaGlzIGZ1bmN0aW9uIG1ha2VzIHN1cmUgdGhhdCB0aGUgYnVja2V0IGlzIGFsbG93ZWQgdG8gbWFrZSB0aGUgbmV4dCBpZGVudGlmeSByZXF1ZXN0LiAqL1xuICByZXF1ZXN0SWRlbnRpZnk6IChzaGFyZElkOiBudW1iZXIpID0+IFByb21pc2U8dm9pZD5cbiAgLyoqIENhbGN1bGF0ZXMgdGhlIG51bWJlciBvZiBzaGFyZHMgYmFzZWQgb24gdGhlIGd1aWxkIGlkIGFuZCB0b3RhbCBzaGFyZHMuICovXG4gIGNhbGN1bGF0ZVNoYXJkSWQ6IChndWlsZElkOiBCaWdTdHJpbmcsIHRvdGFsU2hhcmRzPzogbnVtYmVyKSA9PiBudW1iZXJcbiAgLyoqXG4gICAqIENvbm5lY3RzIHRoZSBib3QgdXNlciB0byBhIHZvaWNlIG9yIHN0YWdlIGNoYW5uZWwuXG4gICAqXG4gICAqIFRoaXMgZnVuY3Rpb24gc2VuZHMgdGhlIF9VcGRhdGUgVm9pY2UgU3RhdGVfIGdhdGV3YXkgY29tbWFuZCBvdmVyIHRoZSBnYXRld2F5IGJlaGluZCB0aGUgc2NlbmVzLlxuICAgKlxuICAgKiBAcGFyYW0gZ3VpbGRJZCAtIFRoZSBJRCBvZiB0aGUgZ3VpbGQgdGhlIHZvaWNlIGNoYW5uZWwgdG8gbGVhdmUgaXMgaW4uXG4gICAqIEBwYXJhbSBjaGFubmVsSWQgLSBUaGUgSUQgb2YgdGhlIGNoYW5uZWwgeW91IHdhbnQgdG8gam9pbi5cbiAgICpcbiAgICogQHJlbWFya3NcbiAgICogUmVxdWlyZXMgdGhlIGBDT05ORUNUYCBwZXJtaXNzaW9uLlxuICAgKlxuICAgKiBGaXJlcyBhIF9Wb2ljZSBTdGF0ZSBVcGRhdGVfIGdhdGV3YXkgZXZlbnQuXG4gICAqXG4gICAqIEBzZWUge0BsaW5rIGh0dHBzOi8vZGlzY29yZC5jb20vZGV2ZWxvcGVycy9kb2NzL3RvcGljcy9nYXRld2F5I3VwZGF0ZS12b2ljZS1zdGF0ZX1cbiAgICovXG4gIGpvaW5Wb2ljZUNoYW5uZWw6IChndWlsZElkOiBCaWdTdHJpbmcsIGNoYW5uZWxJZDogQmlnU3RyaW5nLCBvcHRpb25zPzogQXRMZWFzdE9uZTxPbWl0PFVwZGF0ZVZvaWNlU3RhdGUsICdndWlsZElkJyB8ICdjaGFubmVsSWQnPj4pID0+IFByb21pc2U8dm9pZD5cbiAgLyoqXG4gICAqIEVkaXRzIHRoZSBib3Qgc3RhdHVzIGluIGFsbCBzaGFyZHMgdGhhdCB0aGlzIGdhdGV3YXkgbWFuYWdlcy5cbiAgICpcbiAgICogQHBhcmFtIGRhdGEgVGhlIHN0YXR1cyBkYXRhIHRvIHNldCB0aGUgYm90cyBzdGF0dXMgdG8uXG4gICAqIEByZXR1cm5zIG5vdGhpbmdcbiAgICovXG4gIGVkaXRCb3RTdGF0dXM6IChkYXRhOiBTdGF0dXNVcGRhdGUpID0+IFByb21pc2U8dm9pZD5cbiAgLyoqXG4gICAqIEVkaXRzIHRoZSBib3QncyBzdGF0dXMgb24gb25lIHNoYXJkLlxuICAgKlxuICAgKiBAcGFyYW0gc2hhcmRJZCBUaGUgc2hhcmQgaWQgdG8gZWRpdCB0aGUgc3RhdHVzIGZvci5cbiAgICogQHBhcmFtIGRhdGEgVGhlIHN0YXR1cyBkYXRhIHRvIHNldCB0aGUgYm90cyBzdGF0dXMgdG8uXG4gICAqIEByZXR1cm5zIG5vdGhpbmdcbiAgICovXG4gIGVkaXRTaGFyZFN0YXR1czogKHNoYXJkSWQ6IG51bWJlciwgZGF0YTogU3RhdHVzVXBkYXRlKSA9PiBQcm9taXNlPHZvaWQ+XG4gIC8qKlxuICAgKiBGZXRjaGVzIHRoZSBsaXN0IG9mIG1lbWJlcnMgZm9yIGEgZ3VpbGQgb3ZlciB0aGUgZ2F0ZXdheS5cbiAgICpcbiAgICogQHBhcmFtIGd1aWxkSWQgLSBUaGUgSUQgb2YgdGhlIGd1aWxkIHRvIGdldCB0aGUgbGlzdCBvZiBtZW1iZXJzIGZvci5cbiAgICogQHBhcmFtIG9wdGlvbnMgLSBUaGUgcGFyYW1ldGVycyBmb3IgdGhlIGZldGNoaW5nIG9mIHRoZSBtZW1iZXJzLlxuICAgKlxuICAgKiBAcmVtYXJrc1xuICAgKiBJZiByZXF1ZXN0aW5nIHRoZSBlbnRpcmUgbWVtYmVyIGxpc3Q6XG4gICAqIC0gUmVxdWlyZXMgdGhlIGBHVUlMRF9NRU1CRVJTYCBpbnRlbnQuXG4gICAqXG4gICAqIElmIHJlcXVlc3RpbmcgcHJlc2VuY2VzICh7QGxpbmsgUmVxdWVzdEd1aWxkTWVtYmVycy5wcmVzZW5jZXMgfCBwcmVzZW5jZXN9IHNldCB0byBgdHJ1ZWApOlxuICAgKiAtIFJlcXVpcmVzIHRoZSBgR1VJTERfUFJFU0VOQ0VTYCBpbnRlbnQuXG4gICAqXG4gICAqIElmIHJlcXVlc3RpbmcgYSBwcmVmaXggKHtAbGluayBSZXF1ZXN0R3VpbGRNZW1iZXJzLnF1ZXJ5IHwgcXVlcnl9IG5vbi1gdW5kZWZpbmVkYCk6XG4gICAqIC0gUmV0dXJucyBhIG1heGltdW0gb2YgMTAwIG1lbWJlcnMuXG4gICAqXG4gICAqIElmIHJlcXVlc3RpbmcgYSB1c2VycyBieSBJRCAoe0BsaW5rIFJlcXVlc3RHdWlsZE1lbWJlcnMudXNlcklkcyB8IHVzZXJJZHN9IG5vbi1gdW5kZWZpbmVkYCk6XG4gICAqIC0gUmV0dXJucyBhIG1heGltdW0gb2YgMTAwIG1lbWJlcnMuXG4gICAqXG4gICAqIEZpcmVzIGEgX0d1aWxkIE1lbWJlcnMgQ2h1bmtfIGdhdGV3YXkgZXZlbnQgZm9yIGV2ZXJ5IDEwMDAgbWVtYmVycyBmZXRjaGVkLlxuICAgKlxuICAgKiBAc2VlIHtAbGluayBodHRwczovL2Rpc2NvcmQuY29tL2RldmVsb3BlcnMvZG9jcy90b3BpY3MvZ2F0ZXdheSNyZXF1ZXN0LWd1aWxkLW1lbWJlcnN9XG4gICAqL1xuICByZXF1ZXN0TWVtYmVyczogKGd1aWxkSWQ6IEJpZ1N0cmluZywgb3B0aW9ucz86IE9taXQ8UmVxdWVzdEd1aWxkTWVtYmVycywgJ2d1aWxkSWQnPikgPT4gUHJvbWlzZTxDYW1lbGl6ZTxEaXNjb3JkTWVtYmVyV2l0aFVzZXJbXT4+XG4gIC8qKlxuICAgKiBMZWF2ZXMgdGhlIHZvaWNlIGNoYW5uZWwgdGhlIGJvdCB1c2VyIGlzIGN1cnJlbnRseSBpbi5cbiAgICpcbiAgICogVGhpcyBmdW5jdGlvbiBzZW5kcyB0aGUgX1VwZGF0ZSBWb2ljZSBTdGF0ZV8gZ2F0ZXdheSBjb21tYW5kIG92ZXIgdGhlIGdhdGV3YXkgYmVoaW5kIHRoZSBzY2VuZXMuXG4gICAqXG4gICAqIEBwYXJhbSBndWlsZElkIC0gVGhlIElEIG9mIHRoZSBndWlsZCB0aGUgdm9pY2UgY2hhbm5lbCB0byBsZWF2ZSBpcyBpbi5cbiAgICpcbiAgICogQHJlbWFya3NcbiAgICogRmlyZXMgYSBfVm9pY2UgU3RhdGUgVXBkYXRlXyBnYXRld2F5IGV2ZW50LlxuICAgKlxuICAgKiBAc2VlIHtAbGluayBodHRwczovL2Rpc2NvcmQuY29tL2RldmVsb3BlcnMvZG9jcy90b3BpY3MvZ2F0ZXdheSN1cGRhdGUtdm9pY2Utc3RhdGV9XG4gICAqL1xuICBsZWF2ZVZvaWNlQ2hhbm5lbDogKGd1aWxkSWQ6IEJpZ1N0cmluZykgPT4gUHJvbWlzZTx2b2lkPlxuICAvKiogVGhpcyBtYW5hZ2VycyBjYWNoZSByZWxhdGVkIHNldHRpbmdzLiAqL1xuICBjYWNoZToge1xuICAgIHJlcXVlc3RNZW1iZXJzOiB7XG4gICAgICAvKipcbiAgICAgICAqIFdoZXRoZXIgb3Igbm90IHJlcXVlc3QgbWVtYmVyIHJlcXVlc3RzIHNob3VsZCBiZSBjYWNoZWQuXG4gICAgICAgKiBAZGVmYXVsdCBmYWxzZVxuICAgICAgICovXG4gICAgICBlbmFibGVkOiBib29sZWFuXG4gICAgICAvKiogVGhlIHBlbmRpbmcgcmVxdWVzdHMuICovXG4gICAgICBwZW5kaW5nOiBDb2xsZWN0aW9uPHN0cmluZywgUmVxdWVzdE1lbWJlclJlcXVlc3Q+XG4gICAgfVxuICB9XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUmVxdWVzdE1lbWJlclJlcXVlc3Qge1xuICAvKiogVGhlIHVuaXF1ZSBub25jZSBmb3IgdGhpcyByZXF1ZXN0LiAqL1xuICBub25jZTogc3RyaW5nXG4gIC8qKiBUaGUgcmVzb2x2ZXIgaGFuZGxlciB0byBydW4gd2hlbiBhbGwgbWVtYmVycyBhcnJpdmUuICovXG4gIHJlc29sdmU6ICh2YWx1ZTogQ2FtZWxpemU8RGlzY29yZE1lbWJlcldpdGhVc2VyW10+IHwgUHJvbWlzZUxpa2U8Q2FtZWxpemU8RGlzY29yZE1lbWJlcldpdGhVc2VyW10+PikgPT4gdm9pZFxuICAvKiogVGhlIG1lbWJlcnMgdGhhdCBoYXZlIGFscmVhZHkgYXJyaXZlZCBmb3IgdGhpcyByZXF1ZXN0LiAqL1xuICBtZW1iZXJzOiBEaXNjb3JkTWVtYmVyV2l0aFVzZXJbXVxufVxuIl0sIm5hbWVzIjpbImNyZWF0ZUdhdGV3YXlNYW5hZ2VyIiwib3B0aW9ucyIsImNvbm5lY3Rpb25PcHRpb25zIiwiY29ubmVjdGlvbiIsInVybCIsInNoYXJkcyIsInNlc3Npb25TdGFydExpbWl0IiwibWF4Q29uY3VycmVuY3kiLCJyZW1haW5pbmciLCJ0b3RhbCIsInJlc2V0QWZ0ZXIiLCJnYXRld2F5IiwiZXZlbnRzIiwiY29tcHJlc3MiLCJpbnRlbnRzIiwicHJvcGVydGllcyIsIm9zIiwicHJvY2VzcyIsInBsYXRmb3JtIiwiYnJvd3NlciIsImRldmljZSIsInRva2VuIiwidmVyc2lvbiIsInRvdGFsU2hhcmRzIiwibGFzdFNoYXJkSWQiLCJmaXJzdFNoYXJkSWQiLCJ0b3RhbFdvcmtlcnMiLCJzaGFyZHNQZXJXb3JrZXIiLCJzcGF3blNoYXJkRGVsYXkiLCJwcmVmZXJTbmFrZUNhc2UiLCJNYXAiLCJidWNrZXRzIiwiY2FjaGUiLCJyZXF1ZXN0TWVtYmVycyIsImVuYWJsZWQiLCJwZW5kaW5nIiwiQ29sbGVjdGlvbiIsImxvZ2dlciIsInJlc2hhcmRpbmciLCJzaGFyZHNGdWxsUGVyY2VudGFnZSIsImNoZWNrSW50ZXJ2YWwiLCJwZW5kaW5nU2hhcmRzIiwiZ2V0U2Vzc2lvbkluZm8iLCJFcnJvciIsImNoZWNrSWZSZXNoYXJkaW5nSXNOZWVkZWQiLCJ3YXJuIiwibmVlZGVkIiwic2Vzc2lvbkluZm8iLCJpbmZvIiwicGVyY2VudGFnZSIsInJlc2hhcmQiLCJjYWxjdWxhdGVUb3RhbFNoYXJkcyIsImNsZWFyIiwicHJlcGFyZUJ1Y2tldHMiLCJmb3JFYWNoIiwiYnVja2V0IiwiYnVja2V0SWQiLCJ3b3JrZXIiLCJ3b3JrZXJzIiwic2hhcmRJZCIsInF1ZXVlIiwidGVsbFdvcmtlclRvUHJlcGFyZSIsImlkIiwid29ya2VySWQiLCJzaGFyZCIsIlNoYXJkIiwibWVzc2FnZSIsIl9zaGFyZCIsInBheWxvYWQiLCJ0IiwidXBkYXRlR3VpbGRzU2hhcmRJZCIsImQiLCJndWlsZHMiLCJtYXAiLCJnIiwicmVxdWVzdElkZW50aWZ5IiwiaWRlbnRpZnkiLCJzaGFyZElzUmVhZHkiLCJkZWJ1ZyIsImRlbGF5IiwiZ2V0IiwiaWRlbnRpZnlSZXF1ZXN0cyIsInNoaWZ0IiwiZm9yd2FyZFRvQm90Iiwic2V0IiwiUHJvbWlzZSIsInJlc29sdmUiLCJwdXNoIiwidGhlbiIsInNoYXJkSXNQZW5kaW5nIiwiZ3VpbGRJZHMiLCJqb2luIiwic2l6ZSIsInZhbHVlcyIsImV2ZW50Iiwib2xkSGFuZGxlciIsIl8iLCJzaHV0ZG93biIsIlNoYXJkU29ja2V0Q2xvc2VDb2RlcyIsIlJlc2hhcmRlZCIsIk1hdGgiLCJjZWlsIiwiY2FsY3VsYXRlV29ya2VySWQiLCJtaW4iLCJpIiwiZmluZCIsInciLCJzb3J0IiwiYSIsImIiLCJzcGF3blNoYXJkcyIsImFsbCIsImVudHJpZXMiLCJ0ZWxsV29ya2VyVG9JZGVudGlmeSIsImNoZWNrSW50ZXJ2YWxJZCIsInNldEludGVydmFsIiwicmVzaGFyZGluZ0luZm8iLCJjb2RlIiwicmVhc29uIiwiY2xlYXJSZXNoYXJkaW5nSW50ZXJ2YWwiLCJjbG9zZSIsImNsZWFySW50ZXJ2YWwiLCJzZW5kUGF5bG9hZCIsInNlbmQiLCJraWxsIiwiZGVsZXRlIiwiY2FsY3VsYXRlU2hhcmRJZCIsImd1aWxkSWQiLCJOdW1iZXIiLCJCaWdJbnQiLCJqb2luVm9pY2VDaGFubmVsIiwiY2hhbm5lbElkIiwib3AiLCJHYXRld2F5T3Bjb2RlcyIsIlZvaWNlU3RhdGVVcGRhdGUiLCJndWlsZF9pZCIsInRvU3RyaW5nIiwiY2hhbm5lbF9pZCIsInNlbGZfbXV0ZSIsInNlbGZNdXRlIiwic2VsZl9kZWFmIiwic2VsZkRlYWYiLCJlZGl0Qm90U3RhdHVzIiwiZGF0YSIsIkpTT04iLCJzdHJpbmdpZnkiLCJlZGl0U2hhcmRTdGF0dXMiLCJQcmVzZW5jZVVwZGF0ZSIsInNpbmNlIiwiYWZrIiwiYWN0aXZpdGllcyIsInN0YXR1cyIsImxpbWl0IiwiR2F0ZXdheUludGVudHMiLCJHdWlsZE1lbWJlcnMiLCJ1c2VySWRzIiwibGVuZ3RoIiwibWVtYmVycyIsIm5vbmNlIiwicmVqZWN0IiwiUmVxdWVzdEd1aWxkTWVtYmVycyIsInF1ZXJ5IiwidW5kZWZpbmVkIiwicHJlc2VuY2VzIiwidXNlcl9pZHMiLCJsZWF2ZVZvaWNlQ2hhbm5lbCJdLCJtYXBwaW5ncyI6IkFBQUEsa0VBQWtFOzs7OytCQWdCbERBOzs7ZUFBQUE7Ozt1QkFMVDt1QkFDbUM7OERBQ3hCO3dCQUN5Rzs7Ozs7O0FBRXBILFNBQVNBLHFCQUFxQkMsT0FBb0M7SUFDdkUsTUFBTUMsb0JBQW9CRCxRQUFRRSxVQUFVLElBQUk7UUFDOUNDLEtBQUs7UUFDTEMsUUFBUTtRQUNSQyxtQkFBbUI7WUFDakJDLGdCQUFnQjtZQUNoQkMsV0FBVztZQUNYQyxPQUFPO1lBQ1BDLFlBQVksT0FBTyxLQUFLLEtBQUs7UUFDL0I7SUFDRjtJQUVBLE1BQU1DLFVBQTBCO1FBQzlCQyxRQUFRWCxRQUFRVyxNQUFNLElBQUksQ0FBQztRQUMzQkMsVUFBVVosUUFBUVksUUFBUSxJQUFJO1FBQzlCQyxTQUFTYixRQUFRYSxPQUFPLElBQUk7UUFDNUJDLFlBQVk7WUFDVkMsSUFBSWYsUUFBUWMsVUFBVSxFQUFFQyxNQUFNQyxRQUFRQyxRQUFRO1lBQzlDQyxTQUFTbEIsUUFBUWMsVUFBVSxFQUFFSSxXQUFXO1lBQ3hDQyxRQUFRbkIsUUFBUWMsVUFBVSxFQUFFSyxVQUFVO1FBQ3hDO1FBQ0FDLE9BQU9wQixRQUFRb0IsS0FBSztRQUNwQmpCLEtBQUtILFFBQVFHLEdBQUcsSUFBSUYsa0JBQWtCRSxHQUFHLElBQUk7UUFDN0NrQixTQUFTckIsUUFBUXFCLE9BQU8sSUFBSTtRQUM1Qm5CLFlBQVlEO1FBQ1pxQixhQUFhdEIsUUFBUXNCLFdBQVcsSUFBSXJCLGtCQUFrQkcsTUFBTSxJQUFJO1FBQ2hFbUIsYUFBYXZCLFFBQVF1QixXQUFXLElBQUt2QixDQUFBQSxRQUFRc0IsV0FBVyxHQUFHdEIsUUFBUXNCLFdBQVcsR0FBRyxJQUFJckIsb0JBQW9CQSxrQkFBa0JHLE1BQU0sR0FBRyxJQUFJLENBQUE7UUFDeElvQixjQUFjeEIsUUFBUXdCLFlBQVksSUFBSTtRQUN0Q0MsY0FBY3pCLFFBQVF5QixZQUFZLElBQUk7UUFDdENDLGlCQUFpQjFCLFFBQVEwQixlQUFlLElBQUk7UUFDNUNDLGlCQUFpQjNCLFFBQVEyQixlQUFlLElBQUk7UUFDNUNDLGlCQUFpQjVCLFFBQVE0QixlQUFlLElBQUk7UUFDNUN4QixRQUFRLElBQUl5QjtRQUNaQyxTQUFTLElBQUlEO1FBQ2JFLE9BQU87WUFDTEMsZ0JBQWdCO2dCQUNkQyxTQUFTakMsUUFBUStCLEtBQUssRUFBRUMsZ0JBQWdCQyxXQUFXO2dCQUNuREMsU0FBUyxJQUFJQyxpQkFBVTtZQUN6QjtRQUNGO1FBQ0FDLFFBQVFwQyxRQUFRb0MsTUFBTSxJQUFJQSxhQUFNO1FBQ2hDQyxZQUFZO1lBQ1ZKLFNBQVM7WUFDVEssc0JBQXNCO1lBQ3RCQyxlQUFlO1lBQ2ZuQyxRQUFRLElBQUkrQixpQkFBVTtZQUN0QkssZUFBZSxJQUFJTCxpQkFBVTtZQUM3QixNQUFNTTtnQkFDSixNQUFNLElBQUlDLE1BQ1I7WUFFSjtZQUNBLE1BQU1DO2dCQUNKUCxhQUFNLENBQUNRLElBQUksQ0FBQyxDQUFDLDhDQUE4QyxDQUFDO2dCQUM1RCwwQkFBMEI7Z0JBQzFCLElBQUksQ0FBQ2xDLFFBQVEyQixVQUFVLENBQUNKLE9BQU8sRUFBRSxPQUFPO29CQUFFWSxRQUFRO2dCQUFNO2dCQUN4RFQsYUFBTSxDQUFDUSxJQUFJLENBQUMsQ0FBQyxtQ0FBbUMsQ0FBQztnQkFFakQsTUFBTUUsY0FBYyxNQUFNcEMsUUFBUTJCLFVBQVUsQ0FBQ0ksY0FBYztnQkFDM0RMLGFBQU0sQ0FBQ1EsSUFBSSxDQUFDLENBQUMsb0NBQW9DLENBQUM7Z0JBQ2xELHNEQUFzRDtnQkFDdEQsSUFBSUUsWUFBWXpDLGlCQUFpQixDQUFDRSxTQUFTLEdBQUd1QyxZQUFZMUMsTUFBTSxFQUFFLE9BQU87b0JBQUV5QyxRQUFRO29CQUFPRSxNQUFNRDtnQkFBWTtnQkFDNUdWLGFBQU0sQ0FBQ1EsSUFBSSxDQUFDLENBQUMsNkRBQTZELENBQUM7Z0JBRTNFLDZEQUE2RDtnQkFDN0QsdUZBQXVGO2dCQUN2RixpRUFBaUU7Z0JBQ2pFLE1BQU1JLGFBQWEsQUFBRSxPQUFPRixZQUFZMUMsTUFBTSxHQUFLTSxDQUFBQSxRQUFRWSxXQUFXLEdBQUcsSUFBRyxJQUFNO2dCQUNsRixnREFBZ0Q7Z0JBQ2hELElBQUkwQixhQUFhdEMsUUFBUTJCLFVBQVUsQ0FBQ0Msb0JBQW9CLEVBQUUsT0FBTztvQkFBRU8sUUFBUTtvQkFBT0UsTUFBTUQ7Z0JBQVk7Z0JBQ3BHVixhQUFNLENBQUNRLElBQUksQ0FBQyxDQUFDLGtDQUFrQyxDQUFDO2dCQUVoRCxPQUFPO29CQUFFQyxRQUFRO29CQUFNRSxNQUFNRDtnQkFBWTtZQUMzQztZQUNBLE1BQU1HLFNBQVFGLElBQUk7Z0JBQ2hCWCxhQUFNLENBQUNRLElBQUksQ0FBQyxDQUFDLGtFQUFrRSxFQUFFbEMsUUFBUVksV0FBVyxDQUFDLENBQUM7Z0JBQ3RHLHdCQUF3QjtnQkFDeEJaLFFBQVFZLFdBQVcsR0FBR3lCLEtBQUszQyxNQUFNO2dCQUNqQywyQ0FBMkM7Z0JBQzNDTSxRQUFRWSxXQUFXLEdBQUdaLFFBQVF3QyxvQkFBb0I7Z0JBQ2xELHlDQUF5QztnQkFDekMsSUFBSSxPQUFPSCxLQUFLdkIsWUFBWSxLQUFLLFVBQVVkLFFBQVFjLFlBQVksR0FBR3VCLEtBQUt2QixZQUFZO2dCQUNuRix3Q0FBd0M7Z0JBQ3hDLElBQUksT0FBT3VCLEtBQUt4QixXQUFXLEtBQUssVUFBVWIsUUFBUWEsV0FBVyxHQUFHd0IsS0FBS3hCLFdBQVc7Z0JBQ2hGYSxhQUFNLENBQUNRLElBQUksQ0FBQyxDQUFDLDZEQUE2RCxFQUFFbEMsUUFBUVksV0FBVyxDQUFDLENBQUM7Z0JBRWpHLG9CQUFvQjtnQkFDcEJaLFFBQVFvQixPQUFPLENBQUNxQixLQUFLO2dCQUNyQixvQ0FBb0M7Z0JBQ3BDekMsUUFBUTBDLGNBQWM7Z0JBRXRCLDREQUE0RDtnQkFDNUQxQyxRQUFRb0IsT0FBTyxDQUFDdUIsT0FBTyxDQUFDLE9BQU9DLFFBQVFDO29CQUNyQyxLQUFLLE1BQU1DLFVBQVVGLE9BQU9HLE9BQU8sQ0FBRTt3QkFDbkMsS0FBSyxNQUFNQyxXQUFXRixPQUFPRyxLQUFLLENBQUU7NEJBQ2xDLE1BQU1qRCxRQUFRMkIsVUFBVSxDQUFDdUIsbUJBQW1CLENBQUNKLE9BQU9LLEVBQUUsRUFBRUgsU0FBU0g7d0JBQ25FO29CQUNGO2dCQUNGO1lBQ0Y7WUFDQSxNQUFNSyxxQkFBb0JFLFFBQVEsRUFBRUosT0FBTyxFQUFFSCxRQUFRO2dCQUNuRG5CLGFBQU0sQ0FBQ1EsSUFBSSxDQUFDLENBQUMsZ0RBQWdELEVBQUVrQixTQUFTLFVBQVUsRUFBRUosUUFBUSxXQUFXLEVBQUVILFNBQVMsQ0FBQztnQkFDbkgsTUFBTVEsUUFBUSxJQUFJQyxjQUFLLENBQUM7b0JBQ3RCSCxJQUFJSDtvQkFDSnhELFlBQVk7d0JBQ1ZVLFVBQVVGLFFBQVFFLFFBQVE7d0JBQzFCQyxTQUFTSCxRQUFRRyxPQUFPO3dCQUN4QkMsWUFBWUosUUFBUUksVUFBVTt3QkFDOUJNLE9BQU9WLFFBQVFVLEtBQUs7d0JBQ3BCRSxhQUFhWixRQUFRWSxXQUFXO3dCQUNoQ25CLEtBQUtPLFFBQVFQLEdBQUc7d0JBQ2hCa0IsU0FBU1gsUUFBUVcsT0FBTztvQkFDMUI7b0JBQ0EsbUNBQW1DO29CQUNuQ1YsUUFBUTt3QkFDTixNQUFNc0QsU0FBUUMsTUFBTSxFQUFFQyxPQUFPOzRCQUMzQixJQUFJQSxRQUFRQyxDQUFDLEtBQUssU0FBUztnQ0FDekIsTUFBTTFELFFBQVEyQixVQUFVLENBQUNnQyxtQkFBbUIsQ0FDMUMsQUFBQ0YsUUFBUUcsQ0FBQyxDQUFrQkMsTUFBTSxDQUFDQyxHQUFHLENBQUMsQ0FBQ0MsSUFBTUEsRUFBRVosRUFBRSxHQUNsREg7NEJBRUo7d0JBQ0Y7b0JBQ0Y7b0JBQ0FnQixpQkFBaUI7d0JBQ2YsTUFBTWhFLFFBQVFpRSxRQUFRLENBQUNqQjtvQkFDekI7b0JBQ0FrQixjQUFjO3dCQUNaeEMsYUFBTSxDQUFDeUMsS0FBSyxDQUFDLENBQUMsZUFBZSxFQUFFbkIsUUFBUSxTQUFTLENBQUM7d0JBQ2pELE1BQU1vQixJQUFBQSxZQUFLLEVBQUNwRSxRQUFRaUIsZUFBZTt3QkFDbkNTLGFBQU0sQ0FBQ3lDLEtBQUssQ0FBQyxDQUFDLHdDQUF3QyxDQUFDO3dCQUN2RG5FLFFBQVFvQixPQUFPLENBQUNpRCxHQUFHLENBQUNyQixVQUFVaEQsUUFBUVIsVUFBVSxDQUFDRyxpQkFBaUIsQ0FBQ0MsY0FBYyxFQUFHMEUsZ0JBQWdCLENBQUNDLEtBQUs7b0JBQzVHO2dCQUNGO2dCQUVBLElBQUl2RSxRQUFRa0IsZUFBZSxFQUFFO29CQUMzQm1DLE1BQU1tQixZQUFZLEdBQUcsT0FBT2Y7d0JBQzFCSixNQUFNcEQsTUFBTSxFQUFFc0QsVUFBVUYsT0FBT0k7b0JBQ2pDO2dCQUNGO2dCQUVBekQsUUFBUTJCLFVBQVUsQ0FBQ2pDLE1BQU0sQ0FBQytFLEdBQUcsQ0FBQ3pCLFNBQVNLO2dCQUV2QyxNQUFNVCxTQUFTNUMsUUFBUW9CLE9BQU8sQ0FBQ2lELEdBQUcsQ0FBQ3JCLFVBQVVoRCxRQUFRUixVQUFVLENBQUNHLGlCQUFpQixDQUFDQyxjQUFjO2dCQUNoRyxJQUFJLENBQUNnRCxRQUFRO2dCQUViLE9BQU8sTUFBTSxJQUFJOEIsUUFBUSxDQUFDQztvQkFDeEIsc0VBQXNFO29CQUN0RS9CLE9BQU8wQixnQkFBZ0IsQ0FBQ00sSUFBSSxDQUFDRDtvQkFDN0JqRCxhQUFNLENBQUN5QyxLQUFLLENBQUMsQ0FBQyw4QkFBOEIsRUFBRW5CLFFBQVEsRUFBRSxDQUFDO29CQUN6RCwyRkFBMkY7b0JBQzNGSyxPQUFPWSxXQUFXWSxLQUFLO3dCQUNyQiw2Q0FBNkM7d0JBQzdDLE9BQU8sTUFBTTdFLFFBQVEyQixVQUFVLENBQUNtRCxjQUFjLENBQUN6QjtvQkFDakQ7Z0JBQ0Y7WUFDRjtZQUNBLE1BQU1NLHFCQUFvQm9CLFFBQVEsRUFBRS9CLE9BQU87Z0JBQ3pDdEIsYUFBTSxDQUFDeUMsS0FBSyxDQUNWLENBQUMsd0RBQXdELEVBQUVuQixRQUFRLEVBQUUsRUFBRStCLFNBQVNDLElBQUksQ0FBQyxNQUFNLDZEQUE2RCxDQUFDO1lBRTdKO1lBQ0EsTUFBTUYsZ0JBQWV6QixLQUFLO2dCQUN4QixrRUFBa0U7Z0JBQ2xFckQsUUFBUTJCLFVBQVUsQ0FBQ0csYUFBYSxDQUFDMkMsR0FBRyxDQUFDcEIsTUFBTUYsRUFBRSxFQUFFRTtnQkFDL0MzQixhQUFNLENBQUNRLElBQUksQ0FBQyxDQUFDLG9CQUFvQixFQUFFbUIsTUFBTUYsRUFBRSxDQUFDLGVBQWUsQ0FBQztnQkFDNUQsc0NBQXNDO2dCQUN0QyxJQUFJbkQsUUFBUWEsV0FBVyxHQUFHYixRQUFRYyxZQUFZLEdBQUcsSUFBSWQsUUFBUTJCLFVBQVUsQ0FBQ0csYUFBYSxDQUFDbUQsSUFBSSxFQUFFO2dCQUM1RnZELGFBQU0sQ0FBQ1EsSUFBSSxDQUFDLENBQUMsdUNBQXVDLENBQUM7Z0JBRXJELHFDQUFxQztnQkFDckMsS0FBSyxNQUFNbUIsU0FBU3JELFFBQVEyQixVQUFVLENBQUNHLGFBQWEsQ0FBQ29ELE1BQU0sR0FBSTtvQkFDN0QsSUFBSyxNQUFNQyxTQUFTN0YsUUFBUVcsTUFBTSxDQUFFO3dCQUNsQyxvR0FBb0c7d0JBQ3BHb0QsTUFBTXBELE1BQU0sQ0FBQ2tGLE1BQU0sR0FBRzdGLFFBQVFXLE1BQU0sQ0FBQ2tGLE1BQU07b0JBQzdDO2dCQUNGO2dCQUVBLG9DQUFvQztnQkFDcEMsS0FBSyxNQUFNOUIsU0FBU3JELFFBQVFOLE1BQU0sQ0FBQ3dGLE1BQU0sR0FBSTtvQkFDM0MsTUFBTUUsYUFBYS9CLE1BQU1wRCxNQUFNLENBQUNzRCxPQUFPO29CQUV2QyxtS0FBbUs7b0JBQ25LRixNQUFNcEQsTUFBTSxHQUFHO3dCQUNiLEdBQUdvRCxNQUFNcEQsTUFBTTt3QkFDZnNELFNBQVMsZUFBZ0I4QixDQUFDLEVBQUU5QixPQUFPOzRCQUNqQyxxREFBcUQ7NEJBQ3JELElBQUlBLFFBQVFHLENBQUMsS0FBSyx1QkFBdUI7NEJBQ3pDLG1DQUFtQzs0QkFDbkMwQixhQUFhL0IsT0FBT0U7d0JBQ3RCO29CQUNGO2dCQUNGO2dCQUVBN0IsYUFBTSxDQUFDUSxJQUFJLENBQUMsQ0FBQyxzQ0FBc0MsQ0FBQztnQkFDcEQsbUJBQW1CO2dCQUNuQixNQUFNbEMsUUFBUXNGLFFBQVEsQ0FBQ0MsNkJBQXFCLENBQUNDLFNBQVMsRUFBRSxjQUFjO2dCQUN0RTlELGFBQU0sQ0FBQ1EsSUFBSSxDQUFDLENBQUMsdUJBQXVCLENBQUM7Z0JBRXJDLHFCQUFxQjtnQkFDckJsQyxRQUFRTixNQUFNLEdBQUdNLFFBQVEyQixVQUFVLENBQUNqQyxNQUFNO1lBQzVDO1FBQ0Y7UUFFQThDO1lBQ0UscURBQXFEO1lBQ3JELElBQUl4QyxRQUFRWSxXQUFXLEdBQUcsS0FBSztnQkFDN0JaLFFBQVEwQixNQUFNLENBQUN5QyxLQUFLLENBQUMsQ0FBQyxvQ0FBb0MsRUFBRW5FLFFBQVFZLFdBQVcsQ0FBQyxDQUFDO2dCQUNqRixPQUFPWixRQUFRWSxXQUFXO1lBQzVCO1lBRUFaLFFBQVEwQixNQUFNLENBQUN5QyxLQUFLLENBQUMsQ0FBQyxrQ0FBa0MsQ0FBQyxFQUFFbkUsUUFBUVksV0FBVyxFQUFFWixRQUFRUixVQUFVLENBQUNHLGlCQUFpQixDQUFDQyxjQUFjO1lBQ25JLHdGQUF3RjtZQUN4RixPQUNFNkYsS0FBS0MsSUFBSSxDQUNQMUYsUUFBUVksV0FBVyxHQUNqQix1SkFBdUo7WUFDdEpaLENBQUFBLFFBQVFSLFVBQVUsQ0FBQ0csaUJBQWlCLENBQUNDLGNBQWMsS0FBSyxJQUFJLEtBQUtJLFFBQVFSLFVBQVUsQ0FBQ0csaUJBQWlCLENBQUNDLGNBQWMsQUFBRCxLQUNuSEksQ0FBQUEsUUFBUVIsVUFBVSxDQUFDRyxpQkFBaUIsQ0FBQ0MsY0FBYyxLQUFLLElBQUksS0FBS0ksUUFBUVIsVUFBVSxDQUFDRyxpQkFBaUIsQ0FBQ0MsY0FBYyxBQUFEO1FBRTVIO1FBQ0ErRixtQkFBa0IzQyxPQUFPO1lBQ3ZCLE1BQU1JLFdBQVdxQyxLQUFLRyxHQUFHLENBQUM1QyxVQUFVaEQsUUFBUWdCLGVBQWUsRUFBRWhCLFFBQVFlLFlBQVksR0FBRztZQUNwRmYsUUFBUTBCLE1BQU0sQ0FBQ3lDLEtBQUssQ0FDbEIsQ0FBQyx1Q0FBdUMsRUFBRW5CLFFBQVEsWUFBWSxFQUFFSSxTQUFTLGdCQUFnQixFQUFFcEQsUUFBUWdCLGVBQWUsQ0FBQyxXQUFXLEVBQUVoQixRQUFRZSxZQUFZLENBQUMsQ0FBQztZQUV4SixPQUFPcUM7UUFDVDtRQUNBVjtZQUNFLElBQUssSUFBSW1ELElBQUksR0FBR0EsSUFBSTdGLFFBQVFSLFVBQVUsQ0FBQ0csaUJBQWlCLENBQUNDLGNBQWMsRUFBRSxFQUFFaUcsRUFBRztnQkFDNUU3RixRQUFRMEIsTUFBTSxDQUFDeUMsS0FBSyxDQUFDLENBQUMsNkNBQTZDLEVBQUUwQixFQUFFLENBQUM7Z0JBQ3hFN0YsUUFBUW9CLE9BQU8sQ0FBQ3FELEdBQUcsQ0FBQ29CLEdBQUc7b0JBQ3JCOUMsU0FBUyxFQUFFO29CQUNYdUIsa0JBQWtCLEVBQUU7Z0JBQ3RCO1lBQ0Y7WUFFQSw2Q0FBNkM7WUFDN0MsSUFBSyxJQUFJdEIsVUFBVWhELFFBQVFjLFlBQVksRUFBRWtDLFdBQVdoRCxRQUFRYSxXQUFXLEVBQUUsRUFBRW1DLFFBQVM7Z0JBQ2xGaEQsUUFBUTBCLE1BQU0sQ0FBQ3lDLEtBQUssQ0FBQyxDQUFDLHVDQUF1QyxFQUFFbkIsUUFBUSxDQUFDO2dCQUN4RSxJQUFJQSxXQUFXaEQsUUFBUVksV0FBVyxFQUFFO29CQUNsQyxNQUFNLElBQUlvQixNQUFNLENBQUMsV0FBVyxFQUFFZ0IsUUFBUSxnRUFBZ0UsRUFBRWhELFFBQVFZLFdBQVcsQ0FBQyxDQUFDO2dCQUMvSDtnQkFFQSxNQUFNaUMsV0FBV0csVUFBVWhELFFBQVFSLFVBQVUsQ0FBQ0csaUJBQWlCLENBQUNDLGNBQWM7Z0JBQzlFLE1BQU1nRCxTQUFTNUMsUUFBUW9CLE9BQU8sQ0FBQ2lELEdBQUcsQ0FBQ3hCO2dCQUNuQyxJQUFJLENBQUNELFFBQVE7b0JBQ1gsTUFBTSxJQUFJWixNQUNSLENBQUMsV0FBVyxFQUFFZ0IsUUFBUSx3Q0FBd0MsRUFBRUgsU0FBUyxxQ0FBcUMsRUFDNUc3QyxRQUFRUixVQUFVLENBQUNHLGlCQUFpQixDQUFDQyxjQUFjLEdBQUcsRUFDdkQsQ0FBQztnQkFFTjtnQkFFQSw2Q0FBNkM7Z0JBQzdDLHVGQUF1RjtnQkFDdkYsTUFBTXdELFdBQVdwRCxRQUFRMkYsaUJBQWlCLENBQUMzQztnQkFDM0MsTUFBTUYsU0FBU0YsT0FBT0csT0FBTyxDQUFDK0MsSUFBSSxDQUFDLENBQUNDLElBQU1BLEVBQUU1QyxFQUFFLEtBQUtDO2dCQUNuRCxJQUFJTixRQUFRO29CQUNWLG1EQUFtRDtvQkFDbkRBLE9BQU9HLEtBQUssQ0FBQzJCLElBQUksQ0FBQzVCO2dCQUNwQixPQUFPO29CQUNMSixPQUFPRyxPQUFPLENBQUM2QixJQUFJLENBQUM7d0JBQUV6QixJQUFJQzt3QkFBVUgsT0FBTzs0QkFBQ0Q7eUJBQVE7b0JBQUM7Z0JBQ3ZEO1lBQ0Y7WUFFQSxLQUFLLE1BQU1KLFVBQVU1QyxRQUFRb0IsT0FBTyxDQUFDOEQsTUFBTSxHQUFJO2dCQUM3QyxLQUFLLE1BQU1wQyxVQUFVRixPQUFPRyxPQUFPLENBQUNtQyxNQUFNLEdBQUk7b0JBQzVDLHlFQUF5RTtvQkFDekVwQyxPQUFPRyxLQUFLLEdBQUdILE9BQU9HLEtBQUssQ0FBQytDLElBQUksQ0FBQyxDQUFDQyxHQUFHQyxJQUFNRCxJQUFJQztnQkFDakQ7WUFDRjtRQUNGO1FBQ0EsTUFBTUM7WUFDSiwwQ0FBMEM7WUFDMUNuRyxRQUFRMEMsY0FBYztZQUV0QixpREFBaUQ7WUFDakQsTUFBTWdDLFFBQVEwQixHQUFHLENBQ2Y7bUJBQUlwRyxRQUFRb0IsT0FBTyxDQUFDaUYsT0FBTzthQUFHLENBQUN2QyxHQUFHLENBQUMsT0FBTyxDQUFDakIsVUFBVUQsT0FBTztnQkFDMUQsS0FBSyxNQUFNRSxVQUFVRixPQUFPRyxPQUFPLENBQUU7b0JBQ25DLEtBQUssTUFBTUMsV0FBV0YsT0FBT0csS0FBSyxDQUFFO3dCQUNsQyxNQUFNakQsUUFBUXNHLG9CQUFvQixDQUFDeEQsT0FBT0ssRUFBRSxFQUFFSCxTQUFTSDtvQkFDekQ7Z0JBQ0Y7WUFDRjtZQUdGLGlFQUFpRTtZQUNqRSxJQUFJN0MsUUFBUTJCLFVBQVUsQ0FBQ0osT0FBTyxJQUFJdkIsUUFBUTJCLFVBQVUsQ0FBQ0UsYUFBYSxLQUFLLENBQUMsR0FBRztnQkFDekU3QixRQUFRMkIsVUFBVSxDQUFDNEUsZUFBZSxHQUFHQyxZQUFZO29CQUMvQyxNQUFNQyxpQkFBaUIsTUFBTXpHLFFBQVEyQixVQUFVLENBQUNNLHlCQUF5QjtvQkFFekUsSUFBSXdFLGVBQWV0RSxNQUFNLElBQUlzRSxlQUFlcEUsSUFBSSxFQUFFLE1BQU1yQyxRQUFRMkIsVUFBVSxDQUFDWSxPQUFPLENBQUNrRSxlQUFlcEUsSUFBSTtnQkFDeEcsR0FBR3JDLFFBQVEyQixVQUFVLENBQUNFLGFBQWE7WUFDckM7UUFDRjtRQUNBLE1BQU15RCxVQUFTb0IsSUFBSSxFQUFFQyxNQUFNLEVBQUVDLDBCQUEwQixJQUFJO1lBQ3pENUcsUUFBUU4sTUFBTSxDQUFDaUQsT0FBTyxDQUFDLENBQUNVLFFBQVVBLE1BQU13RCxLQUFLLENBQUNILE1BQU1DO1lBRXBELElBQUlDLDJCQUEyQjVHLFFBQVEyQixVQUFVLENBQUM0RSxlQUFlLEVBQUVPLGNBQWM5RyxRQUFRMkIsVUFBVSxDQUFDNEUsZUFBZTtZQUVuSCxNQUFNbkMsSUFBQUEsWUFBSyxFQUFDO1FBQ2Q7UUFDQSxNQUFNMkMsYUFBWS9ELE9BQU8sRUFBRVMsT0FBTztZQUNoQyxNQUFNSixRQUFRckQsUUFBUU4sTUFBTSxDQUFDMkUsR0FBRyxDQUFDckI7WUFFakMsSUFBSSxDQUFDSyxPQUFPO2dCQUNWLE1BQU0sSUFBSXJCLE1BQU0sQ0FBQyxXQUFXLEVBQUVnQixRQUFRLFVBQVUsQ0FBQztZQUNuRDtZQUVBLE1BQU1LLE1BQU0yRCxJQUFJLENBQUN2RDtRQUNuQjtRQUNBLE1BQU02QyxzQkFBcUJsRCxRQUFRLEVBQUVKLE9BQU8sRUFBRUgsUUFBUTtZQUNwRDdDLFFBQVEwQixNQUFNLENBQUN5QyxLQUFLLENBQUMsQ0FBQyxtQ0FBbUMsRUFBRWYsU0FBUyxFQUFFLEVBQUVKLFFBQVEsRUFBRSxFQUFFSCxTQUFTLENBQUMsQ0FBQztZQUMvRixNQUFNN0MsUUFBUWlFLFFBQVEsQ0FBQ2pCO1FBQ3pCO1FBQ0EsTUFBTWlCLFVBQVNqQixPQUFlO1lBQzVCLElBQUlLLFFBQVEsSUFBSSxDQUFDM0QsTUFBTSxDQUFDMkUsR0FBRyxDQUFDckI7WUFDNUJoRCxRQUFRMEIsTUFBTSxDQUFDeUMsS0FBSyxDQUFDLENBQUMsc0JBQXNCLEVBQUVkLFFBQVEsYUFBYSxNQUFNLFFBQVEsRUFBRUwsUUFBUSxDQUFDLENBQUM7WUFFN0YsSUFBSSxDQUFDSyxPQUFPO2dCQUNWQSxRQUFRLElBQUlDLGNBQUssQ0FBQztvQkFDaEJILElBQUlIO29CQUNKeEQsWUFBWTt3QkFDVlUsVUFBVSxJQUFJLENBQUNBLFFBQVE7d0JBQ3ZCQyxTQUFTLElBQUksQ0FBQ0EsT0FBTzt3QkFDckJDLFlBQVksSUFBSSxDQUFDQSxVQUFVO3dCQUMzQk0sT0FBTyxJQUFJLENBQUNBLEtBQUs7d0JBQ2pCRSxhQUFhLElBQUksQ0FBQ0EsV0FBVzt3QkFDN0JuQixLQUFLLElBQUksQ0FBQ0EsR0FBRzt3QkFDYmtCLFNBQVMsSUFBSSxDQUFDQSxPQUFPO29CQUN2QjtvQkFDQVYsUUFBUVgsUUFBUVcsTUFBTSxJQUFJLENBQUM7b0JBQzNCeUIsUUFBUSxJQUFJLENBQUNBLE1BQU07b0JBQ25Cc0MsaUJBQWlCO3dCQUNmLE1BQU1oRSxRQUFRaUUsUUFBUSxDQUFDakI7b0JBQ3pCO29CQUNBa0IsY0FBYzt3QkFDWmxFLFFBQVEwQixNQUFNLENBQUN5QyxLQUFLLENBQUMsQ0FBQyxlQUFlLEVBQUVuQixRQUFRLFNBQVMsQ0FBQzt3QkFDekQsTUFBTW9CLElBQUFBLFlBQUssRUFBQ3BFLFFBQVFpQixlQUFlO3dCQUNuQ2pCLFFBQVEwQixNQUFNLENBQUN5QyxLQUFLLENBQUMsQ0FBQyx3Q0FBd0MsQ0FBQzt3QkFDL0RuRSxRQUFRb0IsT0FBTyxDQUFDaUQsR0FBRyxDQUFDckIsVUFBVWhELFFBQVFSLFVBQVUsQ0FBQ0csaUJBQWlCLENBQUNDLGNBQWMsRUFBRzBFLGdCQUFnQixDQUFDQyxLQUFLO29CQUM1RztnQkFDRjtnQkFFQSxJQUFJLElBQUksQ0FBQ3JELGVBQWUsRUFBRTtvQkFDeEJtQyxNQUFNbUIsWUFBWSxHQUFHLE9BQU9mO3dCQUMxQkosTUFBT3BELE1BQU0sQ0FBQ3NELE9BQU8sR0FBR0YsT0FBUUk7b0JBQ2xDO2dCQUNGO2dCQUVBLElBQUksQ0FBQy9ELE1BQU0sQ0FBQytFLEdBQUcsQ0FBQ3pCLFNBQVNLO1lBQzNCO1lBRUEsTUFBTVQsU0FBUzVDLFFBQVFvQixPQUFPLENBQUNpRCxHQUFHLENBQUNyQixVQUFVaEQsUUFBUVIsVUFBVSxDQUFDRyxpQkFBaUIsQ0FBQ0MsY0FBYztZQUNoRyxJQUFJLENBQUNnRCxRQUFRO1lBRWIsT0FBTyxNQUFNLElBQUk4QixRQUFRLENBQUNDO2dCQUN4QixzRUFBc0U7Z0JBQ3RFL0IsT0FBTzBCLGdCQUFnQixDQUFDTSxJQUFJLENBQUNEO2dCQUM3QjNFLFFBQVEwQixNQUFNLENBQUN5QyxLQUFLLENBQUMsQ0FBQyw4QkFBOEIsRUFBRW5CLFFBQVEsRUFBRSxDQUFDO2dCQUNqRSwyRkFBMkY7Z0JBQzNGSyxPQUFPWTtZQUNUO1FBQ0Y7UUFDQSxNQUFNZ0QsTUFBS2pFLE9BQWU7WUFDeEIsTUFBTUssUUFBUSxJQUFJLENBQUMzRCxNQUFNLENBQUMyRSxHQUFHLENBQUNyQjtZQUM5QixJQUFJLENBQUNLLE9BQU87Z0JBQ1YsT0FBT3JELFFBQVEwQixNQUFNLENBQUN5QyxLQUFLLENBQUMsQ0FBQyxvQ0FBb0MsRUFBRW5CLFFBQVEsQ0FBQyxDQUFDO1lBQy9FO1lBRUFoRCxRQUFRMEIsTUFBTSxDQUFDeUMsS0FBSyxDQUFDLENBQUMsc0JBQXNCLEVBQUVuQixRQUFRLENBQUMsQ0FBQztZQUN4RCxJQUFJLENBQUN0RCxNQUFNLENBQUN3SCxNQUFNLENBQUNsRTtZQUNuQixNQUFNSyxNQUFNaUMsUUFBUTtRQUN0QjtRQUNBLE1BQU10QixpQkFBZ0JoQixPQUFlO1lBQ25DaEQsUUFBUTBCLE1BQU0sQ0FBQ3lDLEtBQUssQ0FBQyxDQUFDLDZCQUE2QixDQUFDO1FBQ3BELG9HQUFvRztRQUNwRyxzQkFBc0I7UUFFdEIsMENBQTBDO1FBQzFDLDBDQUEwQztRQUMxQyxLQUFLO1FBQ1A7UUFFQSw2QkFBNkI7UUFFN0JnRCxrQkFBaUJDLE9BQU8sRUFBRXhHLFdBQVc7WUFDbkMsd0VBQXdFO1lBQ3hFLElBQUksQ0FBQ0EsYUFBYUEsY0FBY1osUUFBUVksV0FBVztZQUNuRCxzREFBc0Q7WUFDdEQsSUFBSUEsZ0JBQWdCLEdBQUc7Z0JBQ3JCWixRQUFRMEIsTUFBTSxDQUFDeUMsS0FBSyxDQUFDLENBQUMsb0NBQW9DLENBQUM7Z0JBQzNELE9BQU87WUFDVDtZQUVBbkUsUUFBUTBCLE1BQU0sQ0FBQ3lDLEtBQUssQ0FBQyxDQUFDLHFDQUFxQyxFQUFFaUQsUUFBUSxlQUFlLEVBQUV4RyxZQUFZLENBQUMsQ0FBQztZQUNwRyxPQUFPeUcsT0FBTyxBQUFDQyxDQUFBQSxPQUFPRixZQUFZLEdBQUcsQUFBRCxJQUFLRSxPQUFPMUc7UUFDbEQ7UUFFQSxNQUFNMkcsa0JBQWlCSCxPQUFPLEVBQUVJLFNBQVMsRUFBRWxJLE9BQU87WUFDaEQsTUFBTTBELFVBQVVoRCxRQUFRbUgsZ0JBQWdCLENBQUNDO1lBRXpDcEgsUUFBUTBCLE1BQU0sQ0FBQ3lDLEtBQUssQ0FBQyxDQUFDLG9DQUFvQyxFQUFFaUQsUUFBUSxZQUFZLEVBQUVJLFVBQVUsQ0FBQztZQUU3RixNQUFNeEgsUUFBUStHLFdBQVcsQ0FBQy9ELFNBQVM7Z0JBQ2pDeUUsSUFBSUMscUJBQWMsQ0FBQ0MsZ0JBQWdCO2dCQUNuQy9ELEdBQUc7b0JBQ0RnRSxVQUFVUixRQUFRUyxRQUFRO29CQUMxQkMsWUFBWU4sVUFBVUssUUFBUTtvQkFDOUJFLFdBQVd6SSxTQUFTMEksWUFBWTtvQkFDaENDLFdBQVczSSxTQUFTNEksWUFBWTtnQkFDbEM7WUFDRjtRQUNGO1FBRUEsTUFBTUMsZUFBY0MsSUFBSTtZQUN0QnBJLFFBQVEwQixNQUFNLENBQUN5QyxLQUFLLENBQUMsQ0FBQyw4QkFBOEIsRUFBRWtFLEtBQUtDLFNBQVMsQ0FBQ0YsTUFBTSxDQUFDO1lBRTVFLE1BQU0xRCxRQUFRMEIsR0FBRyxDQUNmO21CQUFJcEcsUUFBUU4sTUFBTSxDQUFDd0YsTUFBTTthQUFHLENBQUNwQixHQUFHLENBQUMsT0FBT1Q7Z0JBQ3RDckQsUUFBUXVJLGVBQWUsQ0FBQ2xGLE1BQU1GLEVBQUUsRUFBRWlGO1lBQ3BDO1FBRUo7UUFFQSxNQUFNRyxpQkFBZ0J2RixPQUFPLEVBQUVvRixJQUFJO1lBQ2pDcEksUUFBUTBCLE1BQU0sQ0FBQ3lDLEtBQUssQ0FBQyxDQUFDLG1DQUFtQyxFQUFFbkIsUUFBUSxVQUFVLEVBQUVxRixLQUFLQyxTQUFTLENBQUNGLE1BQU0sQ0FBQztZQUVyRyxNQUFNcEksUUFBUStHLFdBQVcsQ0FBQy9ELFNBQVM7Z0JBQ2pDeUUsSUFBSUMscUJBQWMsQ0FBQ2MsY0FBYztnQkFDakM1RSxHQUFHO29CQUNENkUsT0FBTztvQkFDUEMsS0FBSztvQkFDTEMsWUFBWVAsS0FBS08sVUFBVTtvQkFDM0JDLFFBQVFSLEtBQUtRLE1BQU07Z0JBQ3JCO1lBQ0Y7UUFDRjtRQUVBLE1BQU10SCxnQkFBZThGLE9BQU8sRUFBRTlILE9BQU87WUFDbkMsTUFBTTBELFVBQVVoRCxRQUFRbUgsZ0JBQWdCLENBQUNDO1lBRXpDLElBQUlwSCxRQUFRRyxPQUFPLElBQUssQ0FBQSxDQUFDYixTQUFTdUosU0FBU3ZKLFFBQVF1SixLQUFLLEdBQUcsQ0FBQSxLQUFNLENBQUU3SSxDQUFBQSxRQUFRRyxPQUFPLEdBQUcySSxxQkFBYyxDQUFDQyxZQUFZLEFBQUQsR0FDN0csTUFBTSxJQUFJL0csTUFBTTtZQUVsQmhDLFFBQVEwQixNQUFNLENBQUN5QyxLQUFLLENBQUMsQ0FBQyxrQ0FBa0MsRUFBRWlELFFBQVEsVUFBVSxFQUFFaUIsS0FBS0MsU0FBUyxDQUFDaEosU0FBUyxDQUFDO1lBRXZHLElBQUlBLFNBQVMwSixTQUFTQyxRQUFRO2dCQUM1QmpKLFFBQVEwQixNQUFNLENBQUN5QyxLQUFLLENBQUMsQ0FBQyxrQ0FBa0MsRUFBRWlELFFBQVEsZ0RBQWdELEVBQUU5SCxRQUFRMEosT0FBTyxDQUFDQyxNQUFNLENBQUMsQ0FBQztnQkFFNUkzSixRQUFRdUosS0FBSyxHQUFHdkosUUFBUTBKLE9BQU8sQ0FBQ0MsTUFBTTtZQUN4QztZQUVBLE1BQU1DLFVBQ0osQ0FBQ2xKLFFBQVFxQixLQUFLLENBQUNDLGNBQWMsQ0FBQ0MsT0FBTyxJQUFJLENBQUNqQyxTQUFTNkosUUFDL0MsRUFBRSxHQUNGLElBQUl6RSxRQUEyQyxDQUFDQyxTQUFTeUU7Z0JBQ3ZELHVCQUF1QjtnQkFDdkIsSUFBSSxDQUFDcEosUUFBUXFCLEtBQUssQ0FBQ0MsY0FBYyxDQUFDQyxPQUFPLElBQUksQ0FBQ2pDLFNBQVM2SixPQUFPO29CQUM1REMsT0FBTyxJQUFJcEgsTUFBTTtvQkFDakI7Z0JBQ0Y7Z0JBRUFoQyxRQUFRcUIsS0FBSyxDQUFDQyxjQUFjLENBQUNFLE9BQU8sQ0FBQ2lELEdBQUcsQ0FBQ25GLFFBQVE2SixLQUFLLEVBQUU7b0JBQ3REQSxPQUFPN0osUUFBUTZKLEtBQUs7b0JBQ3BCeEU7b0JBQ0F1RSxTQUFTLEVBQUU7Z0JBQ2I7WUFDRjtZQUVOLE1BQU1sSixRQUFRK0csV0FBVyxDQUFDL0QsU0FBUztnQkFDakN5RSxJQUFJQyxxQkFBYyxDQUFDMkIsbUJBQW1CO2dCQUN0Q3pGLEdBQUc7b0JBQ0RnRSxVQUFVUixRQUFRUyxRQUFRO29CQUMxQixzRUFBc0U7b0JBQ3RFeUIsT0FBT2hLLFNBQVNnSyxTQUFVaEssQ0FBQUEsU0FBU3VKLFFBQVFVLFlBQVksRUFBQztvQkFDeERWLE9BQU92SixTQUFTdUosU0FBUztvQkFDekJXLFdBQVdsSyxTQUFTa0ssYUFBYTtvQkFDakNDLFVBQVVuSyxTQUFTMEosU0FBU2xGLElBQUksQ0FBQ1gsS0FBT0EsR0FBRzBFLFFBQVE7b0JBQ25Ec0IsT0FBTzdKLFNBQVM2SjtnQkFDbEI7WUFDRjtZQUVBLE9BQU8sTUFBTUQ7UUFDZjtRQUVBLE1BQU1RLG1CQUFrQnRDLE9BQU87WUFDN0IsTUFBTXBFLFVBQVVoRCxRQUFRbUgsZ0JBQWdCLENBQUNDO1lBRXpDcEgsUUFBUTBCLE1BQU0sQ0FBQ3lDLEtBQUssQ0FBQyxDQUFDLHFDQUFxQyxFQUFFaUQsUUFBUSxPQUFPLEVBQUVwRSxRQUFRLENBQUM7WUFFdkYsTUFBTWhELFFBQVErRyxXQUFXLENBQUMvRCxTQUFTO2dCQUNqQ3lFLElBQUlDLHFCQUFjLENBQUNDLGdCQUFnQjtnQkFDbkMvRCxHQUFHO29CQUNEZ0UsVUFBVVIsUUFBUVMsUUFBUTtvQkFDMUJDLFlBQVk7b0JBQ1pDLFdBQVc7b0JBQ1hFLFdBQVc7Z0JBQ2I7WUFDRjtRQUNGO0lBQ0Y7SUFFQSxPQUFPakk7QUFDVCJ9
|