@discordeno/rest 19.0.0-next.fd518cb → 19.0.0-next.fda3003
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/index.cjs +25 -0
- package/dist/cjs/invalidBucket.cjs +87 -0
- package/dist/cjs/manager.cjs +1446 -0
- package/dist/cjs/queue.cjs +166 -0
- package/dist/cjs/routes.cjs +581 -0
- package/dist/cjs/types.cjs +6 -0
- package/dist/cjs/typings/routes.cjs +6 -0
- package/dist/esm/index.js +8 -0
- package/dist/esm/invalidBucket.js +83 -0
- package/dist/esm/manager.js +1404 -0
- package/dist/esm/queue.js +156 -0
- package/dist/esm/routes.js +571 -0
- package/dist/esm/types.js +3 -0
- package/dist/esm/typings/routes.js +3 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/{invalidBucket.d.ts → types/invalidBucket.d.ts} +5 -0
- package/dist/types/invalidBucket.d.ts.map +1 -0
- package/dist/types/manager.d.ts.map +1 -0
- package/dist/{queue.d.ts → types/queue.d.ts} +12 -0
- package/dist/types/queue.d.ts.map +1 -0
- package/dist/types/routes.d.ts.map +1 -0
- package/dist/{types.d.ts → types/types.d.ts} +446 -110
- package/dist/types/types.d.ts.map +1 -0
- package/dist/{typings → types/typings}/routes.d.ts +46 -5
- package/dist/types/typings/routes.d.ts.map +1 -0
- package/package.json +29 -23
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -8
- package/dist/index.js.map +0 -1
- package/dist/invalidBucket.d.ts.map +0 -1
- package/dist/invalidBucket.js +0 -82
- package/dist/invalidBucket.js.map +0 -1
- package/dist/manager.d.ts.map +0 -1
- package/dist/manager.js +0 -1102
- package/dist/manager.js.map +0 -1
- package/dist/queue.d.ts.map +0 -1
- package/dist/queue.js +0 -153
- package/dist/queue.js.map +0 -1
- package/dist/routes.d.ts.map +0 -1
- package/dist/routes.js +0 -487
- package/dist/routes.js.map +0 -1
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -3
- package/dist/types.js.map +0 -1
- package/dist/typings/routes.d.ts.map +0 -1
- package/dist/typings/routes.js +0 -3
- package/dist/typings/routes.js.map +0 -1
- /package/dist/{index.d.ts → types/index.d.ts} +0 -0
- /package/dist/{manager.d.ts → types/manager.d.ts} +0 -0
- /package/dist/{routes.d.ts → types/routes.d.ts} +0 -0
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "Queue", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return Queue;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _utils = require("@discordeno/utils");
|
|
12
|
+
let Queue = class Queue {
|
|
13
|
+
constructor(rest, options){
|
|
14
|
+
/** Amount of requests that have are remaining. Defaults to 1. */ this.remaining = 1;
|
|
15
|
+
/** Max requests for this this. Defaults to 1. */ this.max = 1;
|
|
16
|
+
/** The time that discord allows to make the max number of requests. Defaults to 0 */ this.interval = 0;
|
|
17
|
+
/** The requests that are currently pending. */ this.waiting = [];
|
|
18
|
+
/** The requests that are currently pending. */ this.pending = [];
|
|
19
|
+
/** Whether or not the waiting queue is already processing. */ this.processing = false;
|
|
20
|
+
/** Whether or not the pending queue is already processing. */ this.processingPending = false;
|
|
21
|
+
/** Whether the first request is pending. */ this.firstRequest = false;
|
|
22
|
+
/** When requests started being made to determine when the interval will reset it. */ this.frozenAt = 0;
|
|
23
|
+
/** The time in milliseconds to wait before deleting this queue if it is empty. Defaults to 60000(one minute). */ this.deleteQueueDelay = 60000;
|
|
24
|
+
this.rest = rest;
|
|
25
|
+
this.url = options.url;
|
|
26
|
+
this.requestAuthorization = options.requestAuthorization;
|
|
27
|
+
if (options.interval) this.interval = options.interval;
|
|
28
|
+
if (options.max) this.max = options.max;
|
|
29
|
+
if (options.remaining) this.remaining = options.remaining;
|
|
30
|
+
if (options.timeoutId) this.timeoutId = options.timeoutId;
|
|
31
|
+
if (options.deleteQueueDelay) this.deleteQueueDelay = options.deleteQueueDelay;
|
|
32
|
+
}
|
|
33
|
+
/** Check if there is any remaining requests that are allowed. */ isRequestAllowed() {
|
|
34
|
+
return this.remaining > 0;
|
|
35
|
+
}
|
|
36
|
+
/** Pauses the execution until a request is allowed to be made. */ async waitUntilRequestAvailable() {
|
|
37
|
+
// eslint-disable-next-line no-async-promise-executor
|
|
38
|
+
return await new Promise(async (resolve)=>{
|
|
39
|
+
// If whatever amount of requests is left is more than the safety margin, allow the request
|
|
40
|
+
if (this.isRequestAllowed()) {
|
|
41
|
+
// this.remaining++;
|
|
42
|
+
resolve();
|
|
43
|
+
} else {
|
|
44
|
+
this.waiting.push(resolve);
|
|
45
|
+
await this.processWaiting();
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
/** Process the queue of requests waiting to be handled. */ async processWaiting() {
|
|
50
|
+
// If already processing, that loop will handle all waiting requests.
|
|
51
|
+
if (this.processing) return;
|
|
52
|
+
// Mark as processing so other loops don't start
|
|
53
|
+
this.processing = true;
|
|
54
|
+
while(this.waiting.length > 0){
|
|
55
|
+
this.rest.logger.debug(`[Queue] ${this.getQueueType()} ${this.url} process waiting while loop ran.`);
|
|
56
|
+
if (this.isRequestAllowed()) {
|
|
57
|
+
// Resolve the next item in the queue
|
|
58
|
+
this.waiting.shift()?.();
|
|
59
|
+
} else {
|
|
60
|
+
await (0, _utils.delay)(1000);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// Mark as false so next pending request can be triggered by new loop.
|
|
64
|
+
this.processing = false;
|
|
65
|
+
}
|
|
66
|
+
/** Process the queue of all requests pending to be sent. */ async processPending() {
|
|
67
|
+
// If already processing, that loop will handle all pending requests.
|
|
68
|
+
if (this.processingPending || !this.pending.length) return;
|
|
69
|
+
// Mark as processing so other loops don't start
|
|
70
|
+
this.processingPending = true;
|
|
71
|
+
while(this.pending.length > 0){
|
|
72
|
+
this.rest.logger.debug(`Queue ${this.getQueueType()} ${this.url} process pending while loop ran with ${this.pending.length}.`);
|
|
73
|
+
if (!this.firstRequest && !this.isRequestAllowed()) {
|
|
74
|
+
const now = Date.now();
|
|
75
|
+
const future = this.frozenAt + this.interval;
|
|
76
|
+
await (0, _utils.delay)(future > now ? future - now : 1000);
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
const request = this.pending[0];
|
|
80
|
+
if (request) {
|
|
81
|
+
const basicURL = this.rest.simplifyUrl(request.route, request.method);
|
|
82
|
+
// If this url is still rate limited, try again
|
|
83
|
+
const urlResetIn = this.rest.checkRateLimits(basicURL, this.requestAuthorization);
|
|
84
|
+
if (urlResetIn) await (0, _utils.delay)(urlResetIn);
|
|
85
|
+
// IF A BUCKET EXISTS, CHECK THE BUCKET'S RATE LIMITS
|
|
86
|
+
const bucketResetIn = request.bucketId ? this.rest.checkRateLimits(request.bucketId, this.requestAuthorization) : false;
|
|
87
|
+
if (bucketResetIn) await (0, _utils.delay)(bucketResetIn);
|
|
88
|
+
this.firstRequest = false;
|
|
89
|
+
this.remaining--;
|
|
90
|
+
if (this.remaining === 0 && this.interval !== 0) {
|
|
91
|
+
this.timeoutId ??= setTimeout(()=>{
|
|
92
|
+
this.remaining = this.max;
|
|
93
|
+
this.timeoutId = undefined;
|
|
94
|
+
}, this.interval);
|
|
95
|
+
}
|
|
96
|
+
// Remove from queue, we are executing it.
|
|
97
|
+
this.pending.shift();
|
|
98
|
+
// Check if this request is able to be made globally
|
|
99
|
+
await this.rest.invalidBucket.waitUntilRequestAvailable();
|
|
100
|
+
if (request.requestBodyOptions?.headers?.authorization) request.requestBodyOptions.headers.authorization = this.requestAuthorization;
|
|
101
|
+
await this.rest.sendRequest(request)// Should be handled in sendRequest, this catch just prevents bots from dying
|
|
102
|
+
.catch(()=>null);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
this.rest.logger.debug(`Queue ${this.getQueueType()} ${this.url} process pending while loop exited with ${this.pending.length}.`);
|
|
106
|
+
// Mark as false so next pending request can be triggered by new loop.
|
|
107
|
+
this.processingPending = false;
|
|
108
|
+
this.cleanup();
|
|
109
|
+
}
|
|
110
|
+
handleCompletedRequest(headers) {
|
|
111
|
+
if (headers.max === 0) {
|
|
112
|
+
this.remaining++;
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
if (!this.frozenAt) this.frozenAt = Date.now();
|
|
116
|
+
if (headers.interval !== undefined) this.interval = headers.interval;
|
|
117
|
+
if (headers.remaining !== undefined) this.remaining = headers.remaining;
|
|
118
|
+
if (this.remaining <= 1) {
|
|
119
|
+
this.timeoutId ??= setTimeout(()=>{
|
|
120
|
+
this.remaining = this.max;
|
|
121
|
+
this.timeoutId = undefined;
|
|
122
|
+
}, headers.interval);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/** Checks if a request is available and adds it to the queue. Also triggers queue processing if not already processing. */ async makeRequest(options) {
|
|
126
|
+
await this.waitUntilRequestAvailable();
|
|
127
|
+
this.pending.push(options);
|
|
128
|
+
this.processPending();
|
|
129
|
+
}
|
|
130
|
+
/** Cleans up the queue by checking if there is nothing left and removing it. */ cleanup() {
|
|
131
|
+
if (!this.isQueueClearable()) {
|
|
132
|
+
this.processPending();
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
this.rest.logger.debug(`[Queue] ${this.getQueueType()} ${this.url}. Delaying delete for ${this.deleteQueueDelay}ms`);
|
|
136
|
+
// Delete in a minute giving a bit of time to allow new requests that may reuse this queue
|
|
137
|
+
clearTimeout(this.deleteQueueTimeout);
|
|
138
|
+
this.deleteQueueTimeout = setTimeout(()=>{
|
|
139
|
+
if (!this.isQueueClearable()) {
|
|
140
|
+
this.rest.logger.debug(`[Queue] ${this.getQueueType()} ${this.url}. is not clearable. Restarting processing of queue.`);
|
|
141
|
+
this.processPending();
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
this.rest.logger.debug(`[Queue] ${this.getQueueType()} ${this.url}. Deleting`);
|
|
145
|
+
if (this.timeoutId) clearTimeout(this.timeoutId);
|
|
146
|
+
// No requests have been requested for this queue so we nuke this queue
|
|
147
|
+
this.rest.queues.delete(`${this.requestAuthorization}${this.url}`);
|
|
148
|
+
this.rest.logger.debug(`[Queue] ${this.getQueueType()} ${this.url}. Deleted! Remaining: (${this.rest.queues.size})`, [
|
|
149
|
+
...this.rest.queues.values()
|
|
150
|
+
].map((queue)=>`${queue.getQueueType()}${queue.url}`));
|
|
151
|
+
}, this.deleteQueueDelay);
|
|
152
|
+
}
|
|
153
|
+
/** Simply checks if the queue is able to be cleared or it has requests pending. */ isQueueClearable() {
|
|
154
|
+
if (this.firstRequest) return false;
|
|
155
|
+
if (this.waiting.length > 0) return false;
|
|
156
|
+
if (this.pending.length > 0) return false;
|
|
157
|
+
if (this.processing) return false;
|
|
158
|
+
if (this.processingPending) return false;
|
|
159
|
+
return true;
|
|
160
|
+
}
|
|
161
|
+
getQueueType() {
|
|
162
|
+
return this.requestAuthorization.split(' ')[0];
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9xdWV1ZS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBkZWxheSB9IGZyb20gJ0BkaXNjb3JkZW5vL3V0aWxzJ1xuaW1wb3J0IHR5cGUgeyBSZXN0TWFuYWdlciwgU2VuZFJlcXVlc3RPcHRpb25zIH0gZnJvbSAnLi90eXBlcy5qcydcblxuZXhwb3J0IGNsYXNzIFF1ZXVlIHtcbiAgLyoqIFRoZSByZXN0IG1hbmFnZXIgKi9cbiAgcmVzdDogUmVzdE1hbmFnZXJcbiAgLyoqIEFtb3VudCBvZiByZXF1ZXN0cyB0aGF0IGhhdmUgYXJlIHJlbWFpbmluZy4gRGVmYXVsdHMgdG8gMS4gKi9cbiAgcmVtYWluaW5nOiBudW1iZXIgPSAxXG4gIC8qKiBNYXggcmVxdWVzdHMgZm9yIHRoaXMgdGhpcy4gRGVmYXVsdHMgdG8gMS4gKi9cbiAgbWF4OiBudW1iZXIgPSAxXG4gIC8qKiBUaGUgdGltZSB0aGF0IGRpc2NvcmQgYWxsb3dzIHRvIG1ha2UgdGhlIG1heCBudW1iZXIgb2YgcmVxdWVzdHMuIERlZmF1bHRzIHRvIDAgKi9cbiAgaW50ZXJ2YWw6IG51bWJlciA9IDBcbiAgLyoqIHRpbWVyIHRvIHJlc2V0IHRvIDAgKi9cbiAgdGltZW91dElkOiBOb2RlSlMuVGltZW91dCB8IHVuZGVmaW5lZFxuICAvKiogVGhlIHJlcXVlc3RzIHRoYXQgYXJlIGN1cnJlbnRseSBwZW5kaW5nLiAqL1xuICB3YWl0aW5nOiBBcnJheTwodmFsdWU6IHZvaWQgfCBQcm9taXNlTGlrZTx2b2lkPikgPT4gdm9pZD4gPSBbXVxuICAvKiogVGhlIHJlcXVlc3RzIHRoYXQgYXJlIGN1cnJlbnRseSBwZW5kaW5nLiAqL1xuICBwZW5kaW5nOiBTZW5kUmVxdWVzdE9wdGlvbnNbXSA9IFtdXG4gIC8qKiBXaGV0aGVyIG9yIG5vdCB0aGUgd2FpdGluZyBxdWV1ZSBpcyBhbHJlYWR5IHByb2Nlc3NpbmcuICovXG4gIHByb2Nlc3Npbmc6IGJvb2xlYW4gPSBmYWxzZVxuICAvKiogV2hldGhlciBvciBub3QgdGhlIHBlbmRpbmcgcXVldWUgaXMgYWxyZWFkeSBwcm9jZXNzaW5nLiAqL1xuICBwcm9jZXNzaW5nUGVuZGluZzogYm9vbGVhbiA9IGZhbHNlXG4gIC8qKiBXaGV0aGVyIHRoZSBmaXJzdCByZXF1ZXN0IGlzIHBlbmRpbmcuICovXG4gIGZpcnN0UmVxdWVzdDogYm9vbGVhbiA9IGZhbHNlXG4gIC8qKiBUaGUgdXJsIHRoYXQgYWxsIHRoZSByZXF1ZXN0cyBpbiB0aGlzIHF1ZXVlIGFyZSBzZW50IHRvLiAqL1xuICB1cmw6IHN0cmluZ1xuICAvKiogV2hlbiByZXF1ZXN0cyBzdGFydGVkIGJlaW5nIG1hZGUgdG8gZGV0ZXJtaW5lIHdoZW4gdGhlIGludGVydmFsIHdpbGwgcmVzZXQgaXQuICovXG4gIGZyb3plbkF0OiBudW1iZXIgPSAwXG4gIC8qKiBUaGUgdGltZSBpbiBtaWxsaXNlY29uZHMgdG8gd2FpdCBiZWZvcmUgZGVsZXRpbmcgdGhpcyBxdWV1ZSBpZiBpdCBpcyBlbXB0eS4gRGVmYXVsdHMgdG8gNjAwMDAob25lIG1pbnV0ZSkuICovXG4gIGRlbGV0ZVF1ZXVlRGVsYXk6IG51bWJlciA9IDYwMDAwXG4gIC8qKiBUaGUgdGltZW91dCBmb3IgdGhlIGRlbGV0aW9uIG9mIHRoaXMgcXVldWUgKi9cbiAgZGVsZXRlUXVldWVUaW1lb3V0PzogTm9kZUpTLlRpbWVvdXRcbiAgLyoqXG4gICAqIFRoZSBhdXRob3JpemF0aW9uIGJlaW5nIHVzZWQgZm9yIHRoZSByZXF1ZXN0cyBpbiB0aGlzIHF1ZXVlXG4gICAqXG4gICAqIEByZW1hcmtzXG4gICAqIFRoaXMgaXMgYWxzbyB1c2VkIHRvIGdldCB0aGUga2V5IHRoaXMgcXVldWUgaXMgc3RvcmVkIGFzIGluIHRoZSBxdWV1ZSBtYXBwaW5nIG9mIHRoZSByZXN0IG1hbmFnZXJcbiAgICovXG4gIHJlcXVlc3RBdXRob3JpemF0aW9uOiBzdHJpbmdcblxuICBjb25zdHJ1Y3RvcihyZXN0OiBSZXN0TWFuYWdlciwgb3B0aW9uczogUXVldWVPcHRpb25zKSB7XG4gICAgdGhpcy5yZXN0ID0gcmVzdFxuICAgIHRoaXMudXJsID0gb3B0aW9ucy51cmxcbiAgICB0aGlzLnJlcXVlc3RBdXRob3JpemF0aW9uID0gb3B0aW9ucy5yZXF1ZXN0QXV0aG9yaXphdGlvblxuXG4gICAgaWYgKG9wdGlvbnMuaW50ZXJ2YWwpIHRoaXMuaW50ZXJ2YWwgPSBvcHRpb25zLmludGVydmFsXG4gICAgaWYgKG9wdGlvbnMubWF4KSB0aGlzLm1heCA9IG9wdGlvbnMubWF4XG4gICAgaWYgKG9wdGlvbnMucmVtYWluaW5nKSB0aGlzLnJlbWFpbmluZyA9IG9wdGlvbnMucmVtYWluaW5nXG4gICAgaWYgKG9wdGlvbnMudGltZW91dElkKSB0aGlzLnRpbWVvdXRJZCA9IG9wdGlvbnMudGltZW91dElkXG4gICAgaWYgKG9wdGlvbnMuZGVsZXRlUXVldWVEZWxheSkgdGhpcy5kZWxldGVRdWV1ZURlbGF5ID0gb3B0aW9ucy5kZWxldGVRdWV1ZURlbGF5XG4gIH1cblxuICAvKiogQ2hlY2sgaWYgdGhlcmUgaXMgYW55IHJlbWFpbmluZyByZXF1ZXN0cyB0aGF0IGFyZSBhbGxvd2VkLiAqL1xuICBpc1JlcXVlc3RBbGxvd2VkKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLnJlbWFpbmluZyA+IDBcbiAgfVxuXG4gIC8qKiBQYXVzZXMgdGhlIGV4ZWN1dGlvbiB1bnRpbCBhIHJlcXVlc3QgaXMgYWxsb3dlZCB0byBiZSBtYWRlLiAqL1xuICBhc3luYyB3YWl0VW50aWxSZXF1ZXN0QXZhaWxhYmxlKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1hc3luYy1wcm9taXNlLWV4ZWN1dG9yXG4gICAgcmV0dXJuIGF3YWl0IG5ldyBQcm9taXNlKGFzeW5jIChyZXNvbHZlKSA9PiB7XG4gICAgICAvLyBJZiB3aGF0ZXZlciBhbW91bnQgb2YgcmVxdWVzdHMgaXMgbGVmdCBpcyBtb3JlIHRoYW4gdGhlIHNhZmV0eSBtYXJnaW4sIGFsbG93IHRoZSByZXF1ZXN0XG4gICAgICBpZiAodGhpcy5pc1JlcXVlc3RBbGxvd2VkKCkpIHtcbiAgICAgICAgLy8gdGhpcy5yZW1haW5pbmcrKztcbiAgICAgICAgcmVzb2x2ZSgpXG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLndhaXRpbmcucHVzaChyZXNvbHZlKVxuICAgICAgICBhd2FpdCB0aGlzLnByb2Nlc3NXYWl0aW5nKClcbiAgICAgIH1cbiAgICB9KVxuICB9XG5cbiAgLyoqIFByb2Nlc3MgdGhlIHF1ZXVlIG9mIHJlcXVlc3RzIHdhaXRpbmcgdG8gYmUgaGFuZGxlZC4gKi9cbiAgYXN5bmMgcHJvY2Vzc1dhaXRpbmcoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgLy8gSWYgYWxyZWFkeSBwcm9jZXNzaW5nLCB0aGF0IGxvb3Agd2lsbCBoYW5kbGUgYWxsIHdhaXRpbmcgcmVxdWVzdHMuXG4gICAgaWYgKHRoaXMucHJvY2Vzc2luZykgcmV0dXJuXG4gICAgLy8gTWFyayBhcyBwcm9jZXNzaW5nIHNvIG90aGVyIGxvb3BzIGRvbid0IHN0YXJ0XG4gICAgdGhpcy5wcm9jZXNzaW5nID0gdHJ1ZVxuXG4gICAgd2hpbGUgKHRoaXMud2FpdGluZy5sZW5ndGggPiAwKSB7XG4gICAgICB0aGlzLnJlc3QubG9nZ2VyLmRlYnVnKGBbUXVldWVdICR7dGhpcy5nZXRRdWV1ZVR5cGUoKX0gJHt0aGlzLnVybH0gcHJvY2VzcyB3YWl0aW5nIHdoaWxlIGxvb3AgcmFuLmApXG4gICAgICBpZiAodGhpcy5pc1JlcXVlc3RBbGxvd2VkKCkpIHtcbiAgICAgICAgLy8gUmVzb2x2ZSB0aGUgbmV4dCBpdGVtIGluIHRoZSBxdWV1ZVxuICAgICAgICB0aGlzLndhaXRpbmcuc2hpZnQoKT8uKClcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGF3YWl0IGRlbGF5KDEwMDApXG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gTWFyayBhcyBmYWxzZSBzbyBuZXh0IHBlbmRpbmcgcmVxdWVzdCBjYW4gYmUgdHJpZ2dlcmVkIGJ5IG5ldyBsb29wLlxuICAgIHRoaXMucHJvY2Vzc2luZyA9IGZhbHNlXG4gIH1cblxuICAvKiogUHJvY2VzcyB0aGUgcXVldWUgb2YgYWxsIHJlcXVlc3RzIHBlbmRpbmcgdG8gYmUgc2VudC4gKi9cbiAgYXN5bmMgcHJvY2Vzc1BlbmRpbmcoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgLy8gSWYgYWxyZWFkeSBwcm9jZXNzaW5nLCB0aGF0IGxvb3Agd2lsbCBoYW5kbGUgYWxsIHBlbmRpbmcgcmVxdWVzdHMuXG4gICAgaWYgKHRoaXMucHJvY2Vzc2luZ1BlbmRpbmcgfHwgIXRoaXMucGVuZGluZy5sZW5ndGgpIHJldHVyblxuXG4gICAgLy8gTWFyayBhcyBwcm9jZXNzaW5nIHNvIG90aGVyIGxvb3BzIGRvbid0IHN0YXJ0XG4gICAgdGhpcy5wcm9jZXNzaW5nUGVuZGluZyA9IHRydWVcblxuICAgIHdoaWxlICh0aGlzLnBlbmRpbmcubGVuZ3RoID4gMCkge1xuICAgICAgdGhpcy5yZXN0LmxvZ2dlci5kZWJ1ZyhgUXVldWUgJHt0aGlzLmdldFF1ZXVlVHlwZSgpfSAke3RoaXMudXJsfSBwcm9jZXNzIHBlbmRpbmcgd2hpbGUgbG9vcCByYW4gd2l0aCAke3RoaXMucGVuZGluZy5sZW5ndGh9LmApXG4gICAgICBpZiAoIXRoaXMuZmlyc3RSZXF1ZXN0ICYmICF0aGlzLmlzUmVxdWVzdEFsbG93ZWQoKSkge1xuICAgICAgICBjb25zdCBub3cgPSBEYXRlLm5vdygpXG4gICAgICAgIGNvbnN0IGZ1dHVyZSA9IHRoaXMuZnJvemVuQXQgKyB0aGlzLmludGVydmFsXG4gICAgICAgIGF3YWl0IGRlbGF5KGZ1dHVyZSA+IG5vdyA/IGZ1dHVyZSAtIG5vdyA6IDEwMDApXG4gICAgICAgIGNvbnRpbnVlXG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHJlcXVlc3QgPSB0aGlzLnBlbmRpbmdbMF1cbiAgICAgIGlmIChyZXF1ZXN0KSB7XG4gICAgICAgIGNvbnN0IGJhc2ljVVJMID0gdGhpcy5yZXN0LnNpbXBsaWZ5VXJsKHJlcXVlc3Qucm91dGUsIHJlcXVlc3QubWV0aG9kKVxuXG4gICAgICAgIC8vIElmIHRoaXMgdXJsIGlzIHN0aWxsIHJhdGUgbGltaXRlZCwgdHJ5IGFnYWluXG4gICAgICAgIGNvbnN0IHVybFJlc2V0SW4gPSB0aGlzLnJlc3QuY2hlY2tSYXRlTGltaXRzKGJhc2ljVVJMLCB0aGlzLnJlcXVlc3RBdXRob3JpemF0aW9uKVxuICAgICAgICBpZiAodXJsUmVzZXRJbikgYXdhaXQgZGVsYXkodXJsUmVzZXRJbilcblxuICAgICAgICAvLyBJRiBBIEJVQ0tFVCBFWElTVFMsIENIRUNLIFRIRSBCVUNLRVQnUyBSQVRFIExJTUlUU1xuICAgICAgICBjb25zdCBidWNrZXRSZXNldEluID0gcmVxdWVzdC5idWNrZXRJZCA/IHRoaXMucmVzdC5jaGVja1JhdGVMaW1pdHMocmVxdWVzdC5idWNrZXRJZCwgdGhpcy5yZXF1ZXN0QXV0aG9yaXphdGlvbikgOiBmYWxzZVxuICAgICAgICBpZiAoYnVja2V0UmVzZXRJbikgYXdhaXQgZGVsYXkoYnVja2V0UmVzZXRJbilcblxuICAgICAgICB0aGlzLmZpcnN0UmVxdWVzdCA9IGZhbHNlXG4gICAgICAgIHRoaXMucmVtYWluaW5nLS1cblxuICAgICAgICBpZiAodGhpcy5yZW1haW5pbmcgPT09IDAgJiYgdGhpcy5pbnRlcnZhbCAhPT0gMCkge1xuICAgICAgICAgIHRoaXMudGltZW91dElkID8/PSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICAgIHRoaXMucmVtYWluaW5nID0gdGhpcy5tYXhcbiAgICAgICAgICAgIHRoaXMudGltZW91dElkID0gdW5kZWZpbmVkXG4gICAgICAgICAgfSwgdGhpcy5pbnRlcnZhbClcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFJlbW92ZSBmcm9tIHF1ZXVlLCB3ZSBhcmUgZXhlY3V0aW5nIGl0LlxuICAgICAgICB0aGlzLnBlbmRpbmcuc2hpZnQoKVxuICAgICAgICAvLyBDaGVjayBpZiB0aGlzIHJlcXVlc3QgaXMgYWJsZSB0byBiZSBtYWRlIGdsb2JhbGx5XG4gICAgICAgIGF3YWl0IHRoaXMucmVzdC5pbnZhbGlkQnVja2V0LndhaXRVbnRpbFJlcXVlc3RBdmFpbGFibGUoKVxuXG4gICAgICAgIGlmIChyZXF1ZXN0LnJlcXVlc3RCb2R5T3B0aW9ucz8uaGVhZGVycz8uYXV0aG9yaXphdGlvbikgcmVxdWVzdC5yZXF1ZXN0Qm9keU9wdGlvbnMuaGVhZGVycy5hdXRob3JpemF0aW9uID0gdGhpcy5yZXF1ZXN0QXV0aG9yaXphdGlvblxuXG4gICAgICAgIGF3YWl0IHRoaXMucmVzdFxuICAgICAgICAgIC5zZW5kUmVxdWVzdChyZXF1ZXN0KVxuICAgICAgICAgIC8vIFNob3VsZCBiZSBoYW5kbGVkIGluIHNlbmRSZXF1ZXN0LCB0aGlzIGNhdGNoIGp1c3QgcHJldmVudHMgYm90cyBmcm9tIGR5aW5nXG4gICAgICAgICAgLmNhdGNoKCgpID0+IG51bGwpXG4gICAgICB9XG4gICAgfVxuXG4gICAgdGhpcy5yZXN0LmxvZ2dlci5kZWJ1ZyhgUXVldWUgJHt0aGlzLmdldFF1ZXVlVHlwZSgpfSAke3RoaXMudXJsfSBwcm9jZXNzIHBlbmRpbmcgd2hpbGUgbG9vcCBleGl0ZWQgd2l0aCAke3RoaXMucGVuZGluZy5sZW5ndGh9LmApXG5cbiAgICAvLyBNYXJrIGFzIGZhbHNlIHNvIG5leHQgcGVuZGluZyByZXF1ZXN0IGNhbiBiZSB0cmlnZ2VyZWQgYnkgbmV3IGxvb3AuXG4gICAgdGhpcy5wcm9jZXNzaW5nUGVuZGluZyA9IGZhbHNlXG4gICAgdGhpcy5jbGVhbnVwKClcbiAgfVxuXG4gIGhhbmRsZUNvbXBsZXRlZFJlcXVlc3QoaGVhZGVyczogeyBtYXg/OiBudW1iZXI7IGludGVydmFsPzogbnVtYmVyOyByZW1haW5pbmc/OiBudW1iZXIgfSk6IHZvaWQge1xuICAgIGlmIChoZWFkZXJzLm1heCA9PT0gMCkge1xuICAgICAgdGhpcy5yZW1haW5pbmcrK1xuICAgICAgcmV0dXJuXG4gICAgfVxuXG4gICAgaWYgKCF0aGlzLmZyb3plbkF0KSB0aGlzLmZyb3plbkF0ID0gRGF0ZS5ub3coKVxuICAgIGlmIChoZWFkZXJzLmludGVydmFsICE9PSB1bmRlZmluZWQpIHRoaXMuaW50ZXJ2YWwgPSBoZWFkZXJzLmludGVydmFsXG4gICAgaWYgKGhlYWRlcnMucmVtYWluaW5nICE9PSB1bmRlZmluZWQpIHRoaXMucmVtYWluaW5nID0gaGVhZGVycy5yZW1haW5pbmdcblxuICAgIGlmICh0aGlzLnJlbWFpbmluZyA8PSAxKSB7XG4gICAgICB0aGlzLnRpbWVvdXRJZCA/Pz0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgIHRoaXMucmVtYWluaW5nID0gdGhpcy5tYXhcbiAgICAgICAgdGhpcy50aW1lb3V0SWQgPSB1bmRlZmluZWRcbiAgICAgIH0sIGhlYWRlcnMuaW50ZXJ2YWwpXG4gICAgfVxuICB9XG5cbiAgLyoqIENoZWNrcyBpZiBhIHJlcXVlc3QgaXMgYXZhaWxhYmxlIGFuZCBhZGRzIGl0IHRvIHRoZSBxdWV1ZS4gQWxzbyB0cmlnZ2VycyBxdWV1ZSBwcm9jZXNzaW5nIGlmIG5vdCBhbHJlYWR5IHByb2Nlc3NpbmcuICovXG4gIGFzeW5jIG1ha2VSZXF1ZXN0KG9wdGlvbnM6IFNlbmRSZXF1ZXN0T3B0aW9ucyk6IFByb21pc2U8dm9pZD4ge1xuICAgIGF3YWl0IHRoaXMud2FpdFVudGlsUmVxdWVzdEF2YWlsYWJsZSgpXG4gICAgdGhpcy5wZW5kaW5nLnB1c2gob3B0aW9ucylcbiAgICB0aGlzLnByb2Nlc3NQZW5kaW5nKClcbiAgfVxuXG4gIC8qKiBDbGVhbnMgdXAgdGhlIHF1ZXVlIGJ5IGNoZWNraW5nIGlmIHRoZXJlIGlzIG5vdGhpbmcgbGVmdCBhbmQgcmVtb3ZpbmcgaXQuICovXG4gIGNsZWFudXAoKTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLmlzUXVldWVDbGVhcmFibGUoKSkge1xuICAgICAgdGhpcy5wcm9jZXNzUGVuZGluZygpXG4gICAgICByZXR1cm5cbiAgICB9XG5cbiAgICB0aGlzLnJlc3QubG9nZ2VyLmRlYnVnKGBbUXVldWVdICR7dGhpcy5nZXRRdWV1ZVR5cGUoKX0gJHt0aGlzLnVybH0uIERlbGF5aW5nIGRlbGV0ZSBmb3IgJHt0aGlzLmRlbGV0ZVF1ZXVlRGVsYXl9bXNgKVxuXG4gICAgLy8gRGVsZXRlIGluIGEgbWludXRlIGdpdmluZyBhIGJpdCBvZiB0aW1lIHRvIGFsbG93IG5ldyByZXF1ZXN0cyB0aGF0IG1heSByZXVzZSB0aGlzIHF1ZXVlXG4gICAgY2xlYXJUaW1lb3V0KHRoaXMuZGVsZXRlUXVldWVUaW1lb3V0KVxuICAgIHRoaXMuZGVsZXRlUXVldWVUaW1lb3V0ID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICBpZiAoIXRoaXMuaXNRdWV1ZUNsZWFyYWJsZSgpKSB7XG4gICAgICAgIHRoaXMucmVzdC5sb2dnZXIuZGVidWcoYFtRdWV1ZV0gJHt0aGlzLmdldFF1ZXVlVHlwZSgpfSAke3RoaXMudXJsfS4gaXMgbm90IGNsZWFyYWJsZS4gUmVzdGFydGluZyBwcm9jZXNzaW5nIG9mIHF1ZXVlLmApXG4gICAgICAgIHRoaXMucHJvY2Vzc1BlbmRpbmcoKVxuICAgICAgICByZXR1cm5cbiAgICAgIH1cblxuICAgICAgdGhpcy5yZXN0LmxvZ2dlci5kZWJ1ZyhgW1F1ZXVlXSAke3RoaXMuZ2V0UXVldWVUeXBlKCl9ICR7dGhpcy51cmx9LiBEZWxldGluZ2ApXG5cbiAgICAgIGlmICh0aGlzLnRpbWVvdXRJZCkgY2xlYXJUaW1lb3V0KHRoaXMudGltZW91dElkKVxuXG4gICAgICAvLyBObyByZXF1ZXN0cyBoYXZlIGJlZW4gcmVxdWVzdGVkIGZvciB0aGlzIHF1ZXVlIHNvIHdlIG51a2UgdGhpcyBxdWV1ZVxuICAgICAgdGhpcy5yZXN0LnF1ZXVlcy5kZWxldGUoYCR7dGhpcy5yZXF1ZXN0QXV0aG9yaXphdGlvbn0ke3RoaXMudXJsfWApXG4gICAgICB0aGlzLnJlc3QubG9nZ2VyLmRlYnVnKFxuICAgICAgICBgW1F1ZXVlXSAke3RoaXMuZ2V0UXVldWVUeXBlKCl9ICR7dGhpcy51cmx9LiBEZWxldGVkISBSZW1haW5pbmc6ICgke3RoaXMucmVzdC5xdWV1ZXMuc2l6ZX0pYCxcbiAgICAgICAgWy4uLnRoaXMucmVzdC5xdWV1ZXMudmFsdWVzKCldLm1hcCgocXVldWUpID0+IGAke3F1ZXVlLmdldFF1ZXVlVHlwZSgpfSR7cXVldWUudXJsfWApLFxuICAgICAgKVxuICAgIH0sIHRoaXMuZGVsZXRlUXVldWVEZWxheSlcbiAgfVxuXG4gIC8qKiBTaW1wbHkgY2hlY2tzIGlmIHRoZSBxdWV1ZSBpcyBhYmxlIHRvIGJlIGNsZWFyZWQgb3IgaXQgaGFzIHJlcXVlc3RzIHBlbmRpbmcuICovXG4gIGlzUXVldWVDbGVhcmFibGUoKTogYm9vbGVhbiB7XG4gICAgaWYgKHRoaXMuZmlyc3RSZXF1ZXN0KSByZXR1cm4gZmFsc2VcbiAgICBpZiAodGhpcy53YWl0aW5nLmxlbmd0aCA+IDApIHJldHVybiBmYWxzZVxuICAgIGlmICh0aGlzLnBlbmRpbmcubGVuZ3RoID4gMCkgcmV0dXJuIGZhbHNlXG4gICAgaWYgKHRoaXMucHJvY2Vzc2luZykgcmV0dXJuIGZhbHNlXG4gICAgaWYgKHRoaXMucHJvY2Vzc2luZ1BlbmRpbmcpIHJldHVybiBmYWxzZVxuXG4gICAgcmV0dXJuIHRydWVcbiAgfVxuXG4gIGdldFF1ZXVlVHlwZSgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLnJlcXVlc3RBdXRob3JpemF0aW9uLnNwbGl0KCcgJylbMF1cbiAgfVxufVxuXG5leHBvcnQgaW50ZXJmYWNlIFF1ZXVlT3B0aW9ucyB7XG4gIC8qKiBIb3cgbWFueSByZXF1ZXN0cyBhcmUgcmVtYWluaW5nLiBEZWZhdWx0cyB0byAxICovXG4gIHJlbWFpbmluZz86IG51bWJlclxuICAvKiogTWF4IG51bWJlciBvZiByZXF1ZXN0cyBhbGxvd2VkIGluIHRoaXMgdGhpcy4gRGVmYXVsdHMgdG8gMS4gKi9cbiAgbWF4PzogbnVtYmVyXG4gIC8qKiBUaGUgdGltZSBpbiBtaWxsaXNlY29uZHMgdGhhdCBkaXNjb3JkIGFsbG93cyB0byBtYWtlIHRoZSBtYXggbnVtYmVyIG9mIGludmFsaWQgcmVxdWVzdHMuIERlZmF1bHRzIHRvIDAgKi9cbiAgaW50ZXJ2YWw/OiBudW1iZXJcbiAgLyoqIHRpbWVyIHRvIHJlc2V0IHRvIDAgKi9cbiAgdGltZW91dElkPzogTm9kZUpTLlRpbWVvdXRcbiAgLyoqIFRoZSB1cmwgdGhpcyBxdWV1ZSB3aWxsIGJlIGhhbmRsaW5nLiAqL1xuICB1cmw6IHN0cmluZ1xuICAvKiogVGhlIHRpbWUgaW4gbWlsbGlzZWNvbmRzIHRvIHdhaXQgYmVmb3JlIGRlbGV0aW5nIHRoaXMgcXVldWUgaWYgaXQgaXMgZW1wdHkuIERlZmF1bHRzIHRvIDYwMDAwKG9uZSBtaW51dGUpLiAqL1xuICBkZWxldGVRdWV1ZURlbGF5PzogbnVtYmVyXG4gIC8qKiBUaGUgYmFzZSBrZXkgdGhhdCBpZGVudGlmaWVzIHRoaXMgcXVldWUgaW4gdGhlIHJlc3QgbWFuYWdlciAqL1xuICByZXF1ZXN0QXV0aG9yaXphdGlvbjogc3RyaW5nXG59XG4iXSwibmFtZXMiOlsiUXVldWUiLCJjb25zdHJ1Y3RvciIsInJlc3QiLCJvcHRpb25zIiwicmVtYWluaW5nIiwibWF4IiwiaW50ZXJ2YWwiLCJ3YWl0aW5nIiwicGVuZGluZyIsInByb2Nlc3NpbmciLCJwcm9jZXNzaW5nUGVuZGluZyIsImZpcnN0UmVxdWVzdCIsImZyb3plbkF0IiwiZGVsZXRlUXVldWVEZWxheSIsInVybCIsInJlcXVlc3RBdXRob3JpemF0aW9uIiwidGltZW91dElkIiwiaXNSZXF1ZXN0QWxsb3dlZCIsIndhaXRVbnRpbFJlcXVlc3RBdmFpbGFibGUiLCJQcm9taXNlIiwicmVzb2x2ZSIsInB1c2giLCJwcm9jZXNzV2FpdGluZyIsImxlbmd0aCIsImxvZ2dlciIsImRlYnVnIiwiZ2V0UXVldWVUeXBlIiwic2hpZnQiLCJkZWxheSIsInByb2Nlc3NQZW5kaW5nIiwibm93IiwiRGF0ZSIsImZ1dHVyZSIsInJlcXVlc3QiLCJiYXNpY1VSTCIsInNpbXBsaWZ5VXJsIiwicm91dGUiLCJtZXRob2QiLCJ1cmxSZXNldEluIiwiY2hlY2tSYXRlTGltaXRzIiwiYnVja2V0UmVzZXRJbiIsImJ1Y2tldElkIiwic2V0VGltZW91dCIsInVuZGVmaW5lZCIsImludmFsaWRCdWNrZXQiLCJyZXF1ZXN0Qm9keU9wdGlvbnMiLCJoZWFkZXJzIiwiYXV0aG9yaXphdGlvbiIsInNlbmRSZXF1ZXN0IiwiY2F0Y2giLCJjbGVhbnVwIiwiaGFuZGxlQ29tcGxldGVkUmVxdWVzdCIsIm1ha2VSZXF1ZXN0IiwiaXNRdWV1ZUNsZWFyYWJsZSIsImNsZWFyVGltZW91dCIsImRlbGV0ZVF1ZXVlVGltZW91dCIsInF1ZXVlcyIsImRlbGV0ZSIsInNpemUiLCJ2YWx1ZXMiLCJtYXAiLCJxdWV1ZSIsInNwbGl0Il0sIm1hcHBpbmdzIjoiOzs7OytCQUdhQTs7O2VBQUFBOzs7dUJBSFM7QUFHZixJQUFBLEFBQU1BLFFBQU4sTUFBTUE7SUFxQ1hDLFlBQVlDLElBQWlCLEVBQUVDLE9BQXFCLENBQUU7UUFsQ3RELCtEQUErRCxRQUMvREMsWUFBb0I7UUFDcEIsK0NBQStDLFFBQy9DQyxNQUFjO1FBQ2QsbUZBQW1GLFFBQ25GQyxXQUFtQjtRQUduQiw2Q0FBNkMsUUFDN0NDLFVBQTRELEVBQUU7UUFDOUQsNkNBQTZDLFFBQzdDQyxVQUFnQyxFQUFFO1FBQ2xDLDREQUE0RCxRQUM1REMsYUFBc0I7UUFDdEIsNERBQTRELFFBQzVEQyxvQkFBNkI7UUFDN0IsMENBQTBDLFFBQzFDQyxlQUF3QjtRQUd4QixtRkFBbUYsUUFDbkZDLFdBQW1CO1FBQ25CLCtHQUErRyxRQUMvR0MsbUJBQTJCO1FBWXpCLElBQUksQ0FBQ1gsSUFBSSxHQUFHQTtRQUNaLElBQUksQ0FBQ1ksR0FBRyxHQUFHWCxRQUFRVyxHQUFHO1FBQ3RCLElBQUksQ0FBQ0Msb0JBQW9CLEdBQUdaLFFBQVFZLG9CQUFvQjtRQUV4RCxJQUFJWixRQUFRRyxRQUFRLEVBQUUsSUFBSSxDQUFDQSxRQUFRLEdBQUdILFFBQVFHLFFBQVE7UUFDdEQsSUFBSUgsUUFBUUUsR0FBRyxFQUFFLElBQUksQ0FBQ0EsR0FBRyxHQUFHRixRQUFRRSxHQUFHO1FBQ3ZDLElBQUlGLFFBQVFDLFNBQVMsRUFBRSxJQUFJLENBQUNBLFNBQVMsR0FBR0QsUUFBUUMsU0FBUztRQUN6RCxJQUFJRCxRQUFRYSxTQUFTLEVBQUUsSUFBSSxDQUFDQSxTQUFTLEdBQUdiLFFBQVFhLFNBQVM7UUFDekQsSUFBSWIsUUFBUVUsZ0JBQWdCLEVBQUUsSUFBSSxDQUFDQSxnQkFBZ0IsR0FBR1YsUUFBUVUsZ0JBQWdCO0lBQ2hGO0lBRUEsK0RBQStELEdBQy9ESSxtQkFBNEI7UUFDMUIsT0FBTyxJQUFJLENBQUNiLFNBQVMsR0FBRztJQUMxQjtJQUVBLGdFQUFnRSxHQUNoRSxNQUFNYyw0QkFBMkM7UUFDL0MscURBQXFEO1FBQ3JELE9BQU8sTUFBTSxJQUFJQyxRQUFRLE9BQU9DO1lBQzlCLDJGQUEyRjtZQUMzRixJQUFJLElBQUksQ0FBQ0gsZ0JBQWdCLElBQUk7Z0JBQzNCLG9CQUFvQjtnQkFDcEJHO1lBQ0YsT0FBTztnQkFDTCxJQUFJLENBQUNiLE9BQU8sQ0FBQ2MsSUFBSSxDQUFDRDtnQkFDbEIsTUFBTSxJQUFJLENBQUNFLGNBQWM7WUFDM0I7UUFDRjtJQUNGO0lBRUEseURBQXlELEdBQ3pELE1BQU1BLGlCQUFnQztRQUNwQyxxRUFBcUU7UUFDckUsSUFBSSxJQUFJLENBQUNiLFVBQVUsRUFBRTtRQUNyQixnREFBZ0Q7UUFDaEQsSUFBSSxDQUFDQSxVQUFVLEdBQUc7UUFFbEIsTUFBTyxJQUFJLENBQUNGLE9BQU8sQ0FBQ2dCLE1BQU0sR0FBRyxFQUFHO1lBQzlCLElBQUksQ0FBQ3JCLElBQUksQ0FBQ3NCLE1BQU0sQ0FBQ0MsS0FBSyxDQUFDLENBQUMsUUFBUSxFQUFFLElBQUksQ0FBQ0MsWUFBWSxHQUFHLENBQUMsRUFBRSxJQUFJLENBQUNaLEdBQUcsQ0FBQyxnQ0FBZ0MsQ0FBQztZQUNuRyxJQUFJLElBQUksQ0FBQ0csZ0JBQWdCLElBQUk7Z0JBQzNCLHFDQUFxQztnQkFDckMsSUFBSSxDQUFDVixPQUFPLENBQUNvQixLQUFLO1lBQ3BCLE9BQU87Z0JBQ0wsTUFBTUMsSUFBQUEsWUFBSyxFQUFDO1lBQ2Q7UUFDRjtRQUVBLHNFQUFzRTtRQUN0RSxJQUFJLENBQUNuQixVQUFVLEdBQUc7SUFDcEI7SUFFQSwwREFBMEQsR0FDMUQsTUFBTW9CLGlCQUFnQztRQUNwQyxxRUFBcUU7UUFDckUsSUFBSSxJQUFJLENBQUNuQixpQkFBaUIsSUFBSSxDQUFDLElBQUksQ0FBQ0YsT0FBTyxDQUFDZSxNQUFNLEVBQUU7UUFFcEQsZ0RBQWdEO1FBQ2hELElBQUksQ0FBQ2IsaUJBQWlCLEdBQUc7UUFFekIsTUFBTyxJQUFJLENBQUNGLE9BQU8sQ0FBQ2UsTUFBTSxHQUFHLEVBQUc7WUFDOUIsSUFBSSxDQUFDckIsSUFBSSxDQUFDc0IsTUFBTSxDQUFDQyxLQUFLLENBQUMsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDQyxZQUFZLEdBQUcsQ0FBQyxFQUFFLElBQUksQ0FBQ1osR0FBRyxDQUFDLHFDQUFxQyxFQUFFLElBQUksQ0FBQ04sT0FBTyxDQUFDZSxNQUFNLENBQUMsQ0FBQyxDQUFDO1lBQzdILElBQUksQ0FBQyxJQUFJLENBQUNaLFlBQVksSUFBSSxDQUFDLElBQUksQ0FBQ00sZ0JBQWdCLElBQUk7Z0JBQ2xELE1BQU1hLE1BQU1DLEtBQUtELEdBQUc7Z0JBQ3BCLE1BQU1FLFNBQVMsSUFBSSxDQUFDcEIsUUFBUSxHQUFHLElBQUksQ0FBQ04sUUFBUTtnQkFDNUMsTUFBTXNCLElBQUFBLFlBQUssRUFBQ0ksU0FBU0YsTUFBTUUsU0FBU0YsTUFBTTtnQkFDMUM7WUFDRjtZQUVBLE1BQU1HLFVBQVUsSUFBSSxDQUFDekIsT0FBTyxDQUFDLEVBQUU7WUFDL0IsSUFBSXlCLFNBQVM7Z0JBQ1gsTUFBTUMsV0FBVyxJQUFJLENBQUNoQyxJQUFJLENBQUNpQyxXQUFXLENBQUNGLFFBQVFHLEtBQUssRUFBRUgsUUFBUUksTUFBTTtnQkFFcEUsK0NBQStDO2dCQUMvQyxNQUFNQyxhQUFhLElBQUksQ0FBQ3BDLElBQUksQ0FBQ3FDLGVBQWUsQ0FBQ0wsVUFBVSxJQUFJLENBQUNuQixvQkFBb0I7Z0JBQ2hGLElBQUl1QixZQUFZLE1BQU1WLElBQUFBLFlBQUssRUFBQ1U7Z0JBRTVCLHFEQUFxRDtnQkFDckQsTUFBTUUsZ0JBQWdCUCxRQUFRUSxRQUFRLEdBQUcsSUFBSSxDQUFDdkMsSUFBSSxDQUFDcUMsZUFBZSxDQUFDTixRQUFRUSxRQUFRLEVBQUUsSUFBSSxDQUFDMUIsb0JBQW9CLElBQUk7Z0JBQ2xILElBQUl5QixlQUFlLE1BQU1aLElBQUFBLFlBQUssRUFBQ1k7Z0JBRS9CLElBQUksQ0FBQzdCLFlBQVksR0FBRztnQkFDcEIsSUFBSSxDQUFDUCxTQUFTO2dCQUVkLElBQUksSUFBSSxDQUFDQSxTQUFTLEtBQUssS0FBSyxJQUFJLENBQUNFLFFBQVEsS0FBSyxHQUFHO29CQUMvQyxJQUFJLENBQUNVLFNBQVMsS0FBSzBCLFdBQVc7d0JBQzVCLElBQUksQ0FBQ3RDLFNBQVMsR0FBRyxJQUFJLENBQUNDLEdBQUc7d0JBQ3pCLElBQUksQ0FBQ1csU0FBUyxHQUFHMkI7b0JBQ25CLEdBQUcsSUFBSSxDQUFDckMsUUFBUTtnQkFDbEI7Z0JBRUEsMENBQTBDO2dCQUMxQyxJQUFJLENBQUNFLE9BQU8sQ0FBQ21CLEtBQUs7Z0JBQ2xCLG9EQUFvRDtnQkFDcEQsTUFBTSxJQUFJLENBQUN6QixJQUFJLENBQUMwQyxhQUFhLENBQUMxQix5QkFBeUI7Z0JBRXZELElBQUllLFFBQVFZLGtCQUFrQixFQUFFQyxTQUFTQyxlQUFlZCxRQUFRWSxrQkFBa0IsQ0FBQ0MsT0FBTyxDQUFDQyxhQUFhLEdBQUcsSUFBSSxDQUFDaEMsb0JBQW9CO2dCQUVwSSxNQUFNLElBQUksQ0FBQ2IsSUFBSSxDQUNaOEMsV0FBVyxDQUFDZixRQUNiLDZFQUE2RTtpQkFDNUVnQixLQUFLLENBQUMsSUFBTTtZQUNqQjtRQUNGO1FBRUEsSUFBSSxDQUFDL0MsSUFBSSxDQUFDc0IsTUFBTSxDQUFDQyxLQUFLLENBQUMsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDQyxZQUFZLEdBQUcsQ0FBQyxFQUFFLElBQUksQ0FBQ1osR0FBRyxDQUFDLHdDQUF3QyxFQUFFLElBQUksQ0FBQ04sT0FBTyxDQUFDZSxNQUFNLENBQUMsQ0FBQyxDQUFDO1FBRWhJLHNFQUFzRTtRQUN0RSxJQUFJLENBQUNiLGlCQUFpQixHQUFHO1FBQ3pCLElBQUksQ0FBQ3dDLE9BQU87SUFDZDtJQUVBQyx1QkFBdUJMLE9BQWdFLEVBQVE7UUFDN0YsSUFBSUEsUUFBUXpDLEdBQUcsS0FBSyxHQUFHO1lBQ3JCLElBQUksQ0FBQ0QsU0FBUztZQUNkO1FBQ0Y7UUFFQSxJQUFJLENBQUMsSUFBSSxDQUFDUSxRQUFRLEVBQUUsSUFBSSxDQUFDQSxRQUFRLEdBQUdtQixLQUFLRCxHQUFHO1FBQzVDLElBQUlnQixRQUFReEMsUUFBUSxLQUFLcUMsV0FBVyxJQUFJLENBQUNyQyxRQUFRLEdBQUd3QyxRQUFReEMsUUFBUTtRQUNwRSxJQUFJd0MsUUFBUTFDLFNBQVMsS0FBS3VDLFdBQVcsSUFBSSxDQUFDdkMsU0FBUyxHQUFHMEMsUUFBUTFDLFNBQVM7UUFFdkUsSUFBSSxJQUFJLENBQUNBLFNBQVMsSUFBSSxHQUFHO1lBQ3ZCLElBQUksQ0FBQ1ksU0FBUyxLQUFLMEIsV0FBVztnQkFDNUIsSUFBSSxDQUFDdEMsU0FBUyxHQUFHLElBQUksQ0FBQ0MsR0FBRztnQkFDekIsSUFBSSxDQUFDVyxTQUFTLEdBQUcyQjtZQUNuQixHQUFHRyxRQUFReEMsUUFBUTtRQUNyQjtJQUNGO0lBRUEseUhBQXlILEdBQ3pILE1BQU04QyxZQUFZakQsT0FBMkIsRUFBaUI7UUFDNUQsTUFBTSxJQUFJLENBQUNlLHlCQUF5QjtRQUNwQyxJQUFJLENBQUNWLE9BQU8sQ0FBQ2EsSUFBSSxDQUFDbEI7UUFDbEIsSUFBSSxDQUFDMEIsY0FBYztJQUNyQjtJQUVBLDhFQUE4RSxHQUM5RXFCLFVBQWdCO1FBQ2QsSUFBSSxDQUFDLElBQUksQ0FBQ0csZ0JBQWdCLElBQUk7WUFDNUIsSUFBSSxDQUFDeEIsY0FBYztZQUNuQjtRQUNGO1FBRUEsSUFBSSxDQUFDM0IsSUFBSSxDQUFDc0IsTUFBTSxDQUFDQyxLQUFLLENBQUMsQ0FBQyxRQUFRLEVBQUUsSUFBSSxDQUFDQyxZQUFZLEdBQUcsQ0FBQyxFQUFFLElBQUksQ0FBQ1osR0FBRyxDQUFDLHNCQUFzQixFQUFFLElBQUksQ0FBQ0QsZ0JBQWdCLENBQUMsRUFBRSxDQUFDO1FBRW5ILDBGQUEwRjtRQUMxRnlDLGFBQWEsSUFBSSxDQUFDQyxrQkFBa0I7UUFDcEMsSUFBSSxDQUFDQSxrQkFBa0IsR0FBR2IsV0FBVztZQUNuQyxJQUFJLENBQUMsSUFBSSxDQUFDVyxnQkFBZ0IsSUFBSTtnQkFDNUIsSUFBSSxDQUFDbkQsSUFBSSxDQUFDc0IsTUFBTSxDQUFDQyxLQUFLLENBQUMsQ0FBQyxRQUFRLEVBQUUsSUFBSSxDQUFDQyxZQUFZLEdBQUcsQ0FBQyxFQUFFLElBQUksQ0FBQ1osR0FBRyxDQUFDLG1EQUFtRCxDQUFDO2dCQUN0SCxJQUFJLENBQUNlLGNBQWM7Z0JBQ25CO1lBQ0Y7WUFFQSxJQUFJLENBQUMzQixJQUFJLENBQUNzQixNQUFNLENBQUNDLEtBQUssQ0FBQyxDQUFDLFFBQVEsRUFBRSxJQUFJLENBQUNDLFlBQVksR0FBRyxDQUFDLEVBQUUsSUFBSSxDQUFDWixHQUFHLENBQUMsVUFBVSxDQUFDO1lBRTdFLElBQUksSUFBSSxDQUFDRSxTQUFTLEVBQUVzQyxhQUFhLElBQUksQ0FBQ3RDLFNBQVM7WUFFL0MsdUVBQXVFO1lBQ3ZFLElBQUksQ0FBQ2QsSUFBSSxDQUFDc0QsTUFBTSxDQUFDQyxNQUFNLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQzFDLG9CQUFvQixDQUFDLEVBQUUsSUFBSSxDQUFDRCxHQUFHLENBQUMsQ0FBQztZQUNqRSxJQUFJLENBQUNaLElBQUksQ0FBQ3NCLE1BQU0sQ0FBQ0MsS0FBSyxDQUNwQixDQUFDLFFBQVEsRUFBRSxJQUFJLENBQUNDLFlBQVksR0FBRyxDQUFDLEVBQUUsSUFBSSxDQUFDWixHQUFHLENBQUMsdUJBQXVCLEVBQUUsSUFBSSxDQUFDWixJQUFJLENBQUNzRCxNQUFNLENBQUNFLElBQUksQ0FBQyxDQUFDLENBQUMsRUFDNUY7bUJBQUksSUFBSSxDQUFDeEQsSUFBSSxDQUFDc0QsTUFBTSxDQUFDRyxNQUFNO2FBQUcsQ0FBQ0MsR0FBRyxDQUFDLENBQUNDLFFBQVUsQ0FBQyxFQUFFQSxNQUFNbkMsWUFBWSxHQUFHLEVBQUVtQyxNQUFNL0MsR0FBRyxDQUFDLENBQUM7UUFFdkYsR0FBRyxJQUFJLENBQUNELGdCQUFnQjtJQUMxQjtJQUVBLGlGQUFpRixHQUNqRndDLG1CQUE0QjtRQUMxQixJQUFJLElBQUksQ0FBQzFDLFlBQVksRUFBRSxPQUFPO1FBQzlCLElBQUksSUFBSSxDQUFDSixPQUFPLENBQUNnQixNQUFNLEdBQUcsR0FBRyxPQUFPO1FBQ3BDLElBQUksSUFBSSxDQUFDZixPQUFPLENBQUNlLE1BQU0sR0FBRyxHQUFHLE9BQU87UUFDcEMsSUFBSSxJQUFJLENBQUNkLFVBQVUsRUFBRSxPQUFPO1FBQzVCLElBQUksSUFBSSxDQUFDQyxpQkFBaUIsRUFBRSxPQUFPO1FBRW5DLE9BQU87SUFDVDtJQUVBZ0IsZUFBdUI7UUFDckIsT0FBTyxJQUFJLENBQUNYLG9CQUFvQixDQUFDK0MsS0FBSyxDQUFDLElBQUksQ0FBQyxFQUFFO0lBQ2hEO0FBQ0YifQ==
|