@discordeno/rest 19.0.0-next.e2d86ea → 19.0.0-next.e33b44e

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.
Files changed (51) hide show
  1. package/dist/cjs/index.cjs +25 -0
  2. package/dist/cjs/invalidBucket.cjs +87 -0
  3. package/dist/cjs/manager.cjs +1395 -0
  4. package/dist/cjs/queue.cjs +167 -0
  5. package/dist/cjs/routes.cjs +581 -0
  6. package/dist/cjs/types.cjs +6 -0
  7. package/dist/cjs/typings/routes.cjs +6 -0
  8. package/dist/esm/index.js +8 -0
  9. package/dist/esm/invalidBucket.js +83 -0
  10. package/dist/esm/manager.js +1353 -0
  11. package/dist/esm/queue.js +157 -0
  12. package/dist/esm/routes.js +571 -0
  13. package/dist/esm/types.js +3 -0
  14. package/dist/esm/typings/routes.js +3 -0
  15. package/dist/tsconfig.tsbuildinfo +1 -0
  16. package/dist/types/index.d.ts.map +1 -0
  17. package/dist/{invalidBucket.d.ts → types/invalidBucket.d.ts} +5 -0
  18. package/dist/types/invalidBucket.d.ts.map +1 -0
  19. package/dist/types/manager.d.ts.map +1 -0
  20. package/dist/{queue.d.ts → types/queue.d.ts} +5 -0
  21. package/dist/types/queue.d.ts.map +1 -0
  22. package/dist/types/routes.d.ts.map +1 -0
  23. package/dist/{types.d.ts → types/types.d.ts} +435 -108
  24. package/dist/types/types.d.ts.map +1 -0
  25. package/dist/{typings → types/typings}/routes.d.ts +46 -5
  26. package/dist/types/typings/routes.d.ts.map +1 -0
  27. package/package.json +29 -23
  28. package/dist/index.d.ts.map +0 -1
  29. package/dist/index.js +0 -8
  30. package/dist/index.js.map +0 -1
  31. package/dist/invalidBucket.d.ts.map +0 -1
  32. package/dist/invalidBucket.js +0 -82
  33. package/dist/invalidBucket.js.map +0 -1
  34. package/dist/manager.d.ts.map +0 -1
  35. package/dist/manager.js +0 -1112
  36. package/dist/manager.js.map +0 -1
  37. package/dist/queue.d.ts.map +0 -1
  38. package/dist/queue.js +0 -153
  39. package/dist/queue.js.map +0 -1
  40. package/dist/routes.d.ts.map +0 -1
  41. package/dist/routes.js +0 -487
  42. package/dist/routes.js.map +0 -1
  43. package/dist/types.d.ts.map +0 -1
  44. package/dist/types.js +0 -3
  45. package/dist/types.js.map +0 -1
  46. package/dist/typings/routes.d.ts.map +0 -1
  47. package/dist/typings/routes.js +0 -3
  48. package/dist/typings/routes.js.map +0 -1
  49. /package/dist/{index.d.ts → types/index.d.ts} +0 -0
  50. /package/dist/{manager.d.ts → types/manager.d.ts} +0 -0
  51. /package/dist/{routes.d.ts → types/routes.d.ts} +0 -0
@@ -0,0 +1,167 @@
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
+ /** The authentication header used for the OAuth2 request. Defaults to an empty string for non-OAuth2 requests */ this.authentication = '';
25
+ this.rest = rest;
26
+ this.url = options.url;
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
+ if (options.authentication) this.authentication = options.authentication;
33
+ }
34
+ /** Check if there is any remaining requests that are allowed. */ isRequestAllowed() {
35
+ return this.remaining > 0;
36
+ }
37
+ /** Pauses the execution until a request is allowed to be made. */ async waitUntilRequestAvailable() {
38
+ // eslint-disable-next-line no-async-promise-executor
39
+ return await new Promise(async (resolve)=>{
40
+ // If whatever amount of requests is left is more than the safety margin, allow the request
41
+ if (this.isRequestAllowed()) {
42
+ // this.remaining++;
43
+ resolve();
44
+ } else {
45
+ this.waiting.push(resolve);
46
+ await this.processWaiting();
47
+ }
48
+ });
49
+ }
50
+ /** Process the queue of requests waiting to be handled. */ async processWaiting() {
51
+ // If already processing, that loop will handle all waiting requests.
52
+ if (this.processing) return;
53
+ // Mark as processing so other loops don't start
54
+ this.processing = true;
55
+ while(this.waiting.length > 0){
56
+ this.rest.logger.debug(`[Queue] ${this.isOauth2Queue() ? '' : 'Bearer '}${this.url} process waiting while loop ran.`);
57
+ if (this.isRequestAllowed()) {
58
+ // Resolve the next item in the queue
59
+ this.waiting.shift()?.();
60
+ } else {
61
+ await (0, _utils.delay)(1000);
62
+ }
63
+ }
64
+ // Mark as false so next pending request can be triggered by new loop.
65
+ this.processing = false;
66
+ }
67
+ /** Process the queue of all requests pending to be sent. */ async processPending() {
68
+ // If already processing, that loop will handle all pending requests.
69
+ if (this.processingPending || !this.pending.length) return;
70
+ // Mark as processing so other loops don't start
71
+ this.processingPending = true;
72
+ while(this.pending.length > 0){
73
+ this.rest.logger.debug(`Queue ${this.isOauth2Queue() ? '' : 'Bearer '}${this.url} process pending while loop ran with ${this.pending.length}.`);
74
+ if (!this.firstRequest && !this.isRequestAllowed()) {
75
+ const now = Date.now();
76
+ const future = this.frozenAt + this.interval;
77
+ await (0, _utils.delay)(future > now ? future - now : 1000);
78
+ continue;
79
+ }
80
+ const request = this.pending[0];
81
+ if (request) {
82
+ const basicURL = this.rest.simplifyUrl(request.route, request.method);
83
+ // If this url is still rate limited, try again
84
+ const urlResetIn = this.rest.checkRateLimits(basicURL, request.requestBodyOptions?.headers);
85
+ if (urlResetIn) await (0, _utils.delay)(urlResetIn);
86
+ // IF A BUCKET EXISTS, CHECK THE BUCKET'S RATE LIMITS
87
+ const bucketResetIn = request.bucketId ? this.rest.checkRateLimits(request.bucketId, request.requestBodyOptions?.headers) : false;
88
+ if (bucketResetIn) await (0, _utils.delay)(bucketResetIn);
89
+ this.firstRequest = false;
90
+ this.remaining--;
91
+ if (this.timeoutId && this.remaining === 0 && this.interval !== 0) {
92
+ this.timeoutId = setTimeout(()=>{
93
+ this.remaining = this.max;
94
+ this.timeoutId = undefined;
95
+ }, this.interval);
96
+ }
97
+ // Remove from queue, we are executing it.
98
+ this.pending.shift();
99
+ // Check if this request is able to be made globally
100
+ await this.rest.invalidBucket.waitUntilRequestAvailable();
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.isOauth2Queue() ? '' : 'Bearer '}${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.isOauth2Queue() ? '' : 'Bearer '}${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
+ setTimeout(async ()=>{
138
+ if (!this.isQueueClearable()) {
139
+ this.rest.logger.debug(`[Queue] ${this.isOauth2Queue() ? '' : 'Bearer '}${this.url}. is not clearable. Restarting processing of queue.`);
140
+ this.processPending();
141
+ return;
142
+ }
143
+ this.rest.logger.debug(`[Queue] ${this.url}. Deleting`);
144
+ if (this.timeoutId) clearTimeout(this.timeoutId);
145
+ // No requests have been requested for this queue so we nuke this queue
146
+ this.rest.queues.delete(`${this.authentication}${this.url}`);
147
+ this.rest.logger.debug(`[Queue] ${this.url}. Deleted! Remaining: (${this.rest.queues.size})`, [
148
+ ...this.rest.queues.values()
149
+ ].map((queue)=>`${queue.isOauth2Queue() ? '' : 'Bearer '}${queue.url}`));
150
+ if (this.rest.queues.size) this.processPending();
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.interval === 0) return false;
158
+ if (this.processing) return false;
159
+ if (this.processingPending) return false;
160
+ return true;
161
+ }
162
+ isOauth2Queue() {
163
+ return this.authentication === '';
164
+ }
165
+ };
166
+
167
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9xdWV1ZS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBkZWxheSB9IGZyb20gJ0BkaXNjb3JkZW5vL3V0aWxzJ1xuaW1wb3J0IHR5cGUgeyBSZXN0TWFuYWdlciwgU2VuZFJlcXVlc3RPcHRpb25zIH0gZnJvbSAnLi90eXBlcy5qcydcblxuZXhwb3J0IGNsYXNzIFF1ZXVlIHtcbiAgLyoqIFRoZSByZXN0IG1hbmFnZXIgKi9cbiAgcmVzdDogUmVzdE1hbmFnZXJcbiAgLyoqIEFtb3VudCBvZiByZXF1ZXN0cyB0aGF0IGhhdmUgYXJlIHJlbWFpbmluZy4gRGVmYXVsdHMgdG8gMS4gKi9cbiAgcmVtYWluaW5nOiBudW1iZXIgPSAxXG4gIC8qKiBNYXggcmVxdWVzdHMgZm9yIHRoaXMgdGhpcy4gRGVmYXVsdHMgdG8gMS4gKi9cbiAgbWF4OiBudW1iZXIgPSAxXG4gIC8qKiBUaGUgdGltZSB0aGF0IGRpc2NvcmQgYWxsb3dzIHRvIG1ha2UgdGhlIG1heCBudW1iZXIgb2YgcmVxdWVzdHMuIERlZmF1bHRzIHRvIDAgKi9cbiAgaW50ZXJ2YWw6IG51bWJlciA9IDBcbiAgLyoqIHRpbWVyIHRvIHJlc2V0IHRvIDAgKi9cbiAgdGltZW91dElkOiBOb2RlSlMuVGltZW91dCB8IHVuZGVmaW5lZFxuICAvKiogVGhlIHJlcXVlc3RzIHRoYXQgYXJlIGN1cnJlbnRseSBwZW5kaW5nLiAqL1xuICB3YWl0aW5nOiBBcnJheTwodmFsdWU6IHZvaWQgfCBQcm9taXNlTGlrZTx2b2lkPikgPT4gdm9pZD4gPSBbXVxuICAvKiogVGhlIHJlcXVlc3RzIHRoYXQgYXJlIGN1cnJlbnRseSBwZW5kaW5nLiAqL1xuICBwZW5kaW5nOiBTZW5kUmVxdWVzdE9wdGlvbnNbXSA9IFtdXG4gIC8qKiBXaGV0aGVyIG9yIG5vdCB0aGUgd2FpdGluZyBxdWV1ZSBpcyBhbHJlYWR5IHByb2Nlc3NpbmcuICovXG4gIHByb2Nlc3Npbmc6IGJvb2xlYW4gPSBmYWxzZVxuICAvKiogV2hldGhlciBvciBub3QgdGhlIHBlbmRpbmcgcXVldWUgaXMgYWxyZWFkeSBwcm9jZXNzaW5nLiAqL1xuICBwcm9jZXNzaW5nUGVuZGluZzogYm9vbGVhbiA9IGZhbHNlXG4gIC8qKiBXaGV0aGVyIHRoZSBmaXJzdCByZXF1ZXN0IGlzIHBlbmRpbmcuICovXG4gIGZpcnN0UmVxdWVzdDogYm9vbGVhbiA9IGZhbHNlXG4gIC8qKiBUaGUgdXJsIHRoYXQgYWxsIHRoZSByZXF1ZXN0cyBpbiB0aGlzIHF1ZXVlIGFyZSBzZW50IHRvLiAqL1xuICB1cmw6IHN0cmluZ1xuICAvKiogV2hlbiByZXF1ZXN0cyBzdGFydGVkIGJlaW5nIG1hZGUgdG8gZGV0ZXJtaW5lIHdoZW4gdGhlIGludGVydmFsIHdpbGwgcmVzZXQgaXQuICovXG4gIGZyb3plbkF0OiBudW1iZXIgPSAwXG4gIC8qKiBUaGUgdGltZSBpbiBtaWxsaXNlY29uZHMgdG8gd2FpdCBiZWZvcmUgZGVsZXRpbmcgdGhpcyBxdWV1ZSBpZiBpdCBpcyBlbXB0eS4gRGVmYXVsdHMgdG8gNjAwMDAob25lIG1pbnV0ZSkuICovXG4gIGRlbGV0ZVF1ZXVlRGVsYXk6IG51bWJlciA9IDYwMDAwXG4gIC8qKiBUaGUgYXV0aGVudGljYXRpb24gaGVhZGVyIHVzZWQgZm9yIHRoZSBPQXV0aDIgcmVxdWVzdC4gRGVmYXVsdHMgdG8gYW4gZW1wdHkgc3RyaW5nIGZvciBub24tT0F1dGgyIHJlcXVlc3RzICovXG4gIGF1dGhlbnRpY2F0aW9uOiBzdHJpbmcgPSAnJ1xuXG4gIGNvbnN0cnVjdG9yKHJlc3Q6IFJlc3RNYW5hZ2VyLCBvcHRpb25zOiBRdWV1ZU9wdGlvbnMpIHtcbiAgICB0aGlzLnJlc3QgPSByZXN0XG4gICAgdGhpcy51cmwgPSBvcHRpb25zLnVybFxuXG4gICAgaWYgKG9wdGlvbnMuaW50ZXJ2YWwpIHRoaXMuaW50ZXJ2YWwgPSBvcHRpb25zLmludGVydmFsXG4gICAgaWYgKG9wdGlvbnMubWF4KSB0aGlzLm1heCA9IG9wdGlvbnMubWF4XG4gICAgaWYgKG9wdGlvbnMucmVtYWluaW5nKSB0aGlzLnJlbWFpbmluZyA9IG9wdGlvbnMucmVtYWluaW5nXG4gICAgaWYgKG9wdGlvbnMudGltZW91dElkKSB0aGlzLnRpbWVvdXRJZCA9IG9wdGlvbnMudGltZW91dElkXG4gICAgaWYgKG9wdGlvbnMuZGVsZXRlUXVldWVEZWxheSkgdGhpcy5kZWxldGVRdWV1ZURlbGF5ID0gb3B0aW9ucy5kZWxldGVRdWV1ZURlbGF5XG4gICAgaWYgKG9wdGlvbnMuYXV0aGVudGljYXRpb24pIHRoaXMuYXV0aGVudGljYXRpb24gPSBvcHRpb25zLmF1dGhlbnRpY2F0aW9uXG4gIH1cblxuICAvKiogQ2hlY2sgaWYgdGhlcmUgaXMgYW55IHJlbWFpbmluZyByZXF1ZXN0cyB0aGF0IGFyZSBhbGxvd2VkLiAqL1xuICBpc1JlcXVlc3RBbGxvd2VkKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLnJlbWFpbmluZyA+IDBcbiAgfVxuXG4gIC8qKiBQYXVzZXMgdGhlIGV4ZWN1dGlvbiB1bnRpbCBhIHJlcXVlc3QgaXMgYWxsb3dlZCB0byBiZSBtYWRlLiAqL1xuICBhc3luYyB3YWl0VW50aWxSZXF1ZXN0QXZhaWxhYmxlKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1hc3luYy1wcm9taXNlLWV4ZWN1dG9yXG4gICAgcmV0dXJuIGF3YWl0IG5ldyBQcm9taXNlKGFzeW5jIChyZXNvbHZlKSA9PiB7XG4gICAgICAvLyBJZiB3aGF0ZXZlciBhbW91bnQgb2YgcmVxdWVzdHMgaXMgbGVmdCBpcyBtb3JlIHRoYW4gdGhlIHNhZmV0eSBtYXJnaW4sIGFsbG93IHRoZSByZXF1ZXN0XG4gICAgICBpZiAodGhpcy5pc1JlcXVlc3RBbGxvd2VkKCkpIHtcbiAgICAgICAgLy8gdGhpcy5yZW1haW5pbmcrKztcbiAgICAgICAgcmVzb2x2ZSgpXG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLndhaXRpbmcucHVzaChyZXNvbHZlKVxuICAgICAgICBhd2FpdCB0aGlzLnByb2Nlc3NXYWl0aW5nKClcbiAgICAgIH1cbiAgICB9KVxuICB9XG5cbiAgLyoqIFByb2Nlc3MgdGhlIHF1ZXVlIG9mIHJlcXVlc3RzIHdhaXRpbmcgdG8gYmUgaGFuZGxlZC4gKi9cbiAgYXN5bmMgcHJvY2Vzc1dhaXRpbmcoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgLy8gSWYgYWxyZWFkeSBwcm9jZXNzaW5nLCB0aGF0IGxvb3Agd2lsbCBoYW5kbGUgYWxsIHdhaXRpbmcgcmVxdWVzdHMuXG4gICAgaWYgKHRoaXMucHJvY2Vzc2luZykgcmV0dXJuXG4gICAgLy8gTWFyayBhcyBwcm9jZXNzaW5nIHNvIG90aGVyIGxvb3BzIGRvbid0IHN0YXJ0XG4gICAgdGhpcy5wcm9jZXNzaW5nID0gdHJ1ZVxuXG4gICAgd2hpbGUgKHRoaXMud2FpdGluZy5sZW5ndGggPiAwKSB7XG4gICAgICB0aGlzLnJlc3QubG9nZ2VyLmRlYnVnKGBbUXVldWVdICR7dGhpcy5pc09hdXRoMlF1ZXVlKCkgPyAnJyA6ICdCZWFyZXIgJ30ke3RoaXMudXJsfSBwcm9jZXNzIHdhaXRpbmcgd2hpbGUgbG9vcCByYW4uYClcbiAgICAgIGlmICh0aGlzLmlzUmVxdWVzdEFsbG93ZWQoKSkge1xuICAgICAgICAvLyBSZXNvbHZlIHRoZSBuZXh0IGl0ZW0gaW4gdGhlIHF1ZXVlXG4gICAgICAgIHRoaXMud2FpdGluZy5zaGlmdCgpPy4oKVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgYXdhaXQgZGVsYXkoMTAwMClcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBNYXJrIGFzIGZhbHNlIHNvIG5leHQgcGVuZGluZyByZXF1ZXN0IGNhbiBiZSB0cmlnZ2VyZWQgYnkgbmV3IGxvb3AuXG4gICAgdGhpcy5wcm9jZXNzaW5nID0gZmFsc2VcbiAgfVxuXG4gIC8qKiBQcm9jZXNzIHRoZSBxdWV1ZSBvZiBhbGwgcmVxdWVzdHMgcGVuZGluZyB0byBiZSBzZW50LiAqL1xuICBhc3luYyBwcm9jZXNzUGVuZGluZygpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAvLyBJZiBhbHJlYWR5IHByb2Nlc3NpbmcsIHRoYXQgbG9vcCB3aWxsIGhhbmRsZSBhbGwgcGVuZGluZyByZXF1ZXN0cy5cbiAgICBpZiAodGhpcy5wcm9jZXNzaW5nUGVuZGluZyB8fCAhdGhpcy5wZW5kaW5nLmxlbmd0aCkgcmV0dXJuXG5cbiAgICAvLyBNYXJrIGFzIHByb2Nlc3Npbmcgc28gb3RoZXIgbG9vcHMgZG9uJ3Qgc3RhcnRcbiAgICB0aGlzLnByb2Nlc3NpbmdQZW5kaW5nID0gdHJ1ZVxuXG4gICAgd2hpbGUgKHRoaXMucGVuZGluZy5sZW5ndGggPiAwKSB7XG4gICAgICB0aGlzLnJlc3QubG9nZ2VyLmRlYnVnKGBRdWV1ZSAke3RoaXMuaXNPYXV0aDJRdWV1ZSgpID8gJycgOiAnQmVhcmVyICd9JHt0aGlzLnVybH0gcHJvY2VzcyBwZW5kaW5nIHdoaWxlIGxvb3AgcmFuIHdpdGggJHt0aGlzLnBlbmRpbmcubGVuZ3RofS5gKVxuICAgICAgaWYgKCF0aGlzLmZpcnN0UmVxdWVzdCAmJiAhdGhpcy5pc1JlcXVlc3RBbGxvd2VkKCkpIHtcbiAgICAgICAgY29uc3Qgbm93ID0gRGF0ZS5ub3coKVxuICAgICAgICBjb25zdCBmdXR1cmUgPSB0aGlzLmZyb3plbkF0ICsgdGhpcy5pbnRlcnZhbFxuICAgICAgICBhd2FpdCBkZWxheShmdXR1cmUgPiBub3cgPyBmdXR1cmUgLSBub3cgOiAxMDAwKVxuICAgICAgICBjb250aW51ZVxuICAgICAgfVxuXG4gICAgICBjb25zdCByZXF1ZXN0ID0gdGhpcy5wZW5kaW5nWzBdXG4gICAgICBpZiAocmVxdWVzdCkge1xuICAgICAgICBjb25zdCBiYXNpY1VSTCA9IHRoaXMucmVzdC5zaW1wbGlmeVVybChyZXF1ZXN0LnJvdXRlLCByZXF1ZXN0Lm1ldGhvZClcblxuICAgICAgICAvLyBJZiB0aGlzIHVybCBpcyBzdGlsbCByYXRlIGxpbWl0ZWQsIHRyeSBhZ2FpblxuICAgICAgICBjb25zdCB1cmxSZXNldEluID0gdGhpcy5yZXN0LmNoZWNrUmF0ZUxpbWl0cyhiYXNpY1VSTCwgcmVxdWVzdC5yZXF1ZXN0Qm9keU9wdGlvbnM/LmhlYWRlcnMpXG4gICAgICAgIGlmICh1cmxSZXNldEluKSBhd2FpdCBkZWxheSh1cmxSZXNldEluKVxuXG4gICAgICAgIC8vIElGIEEgQlVDS0VUIEVYSVNUUywgQ0hFQ0sgVEhFIEJVQ0tFVCdTIFJBVEUgTElNSVRTXG4gICAgICAgIGNvbnN0IGJ1Y2tldFJlc2V0SW4gPSByZXF1ZXN0LmJ1Y2tldElkID8gdGhpcy5yZXN0LmNoZWNrUmF0ZUxpbWl0cyhyZXF1ZXN0LmJ1Y2tldElkLCByZXF1ZXN0LnJlcXVlc3RCb2R5T3B0aW9ucz8uaGVhZGVycykgOiBmYWxzZVxuICAgICAgICBpZiAoYnVja2V0UmVzZXRJbikgYXdhaXQgZGVsYXkoYnVja2V0UmVzZXRJbilcblxuICAgICAgICB0aGlzLmZpcnN0UmVxdWVzdCA9IGZhbHNlXG4gICAgICAgIHRoaXMucmVtYWluaW5nLS1cblxuICAgICAgICBpZiAodGhpcy50aW1lb3V0SWQgJiYgdGhpcy5yZW1haW5pbmcgPT09IDAgJiYgdGhpcy5pbnRlcnZhbCAhPT0gMCkge1xuICAgICAgICAgIHRoaXMudGltZW91dElkID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLnJlbWFpbmluZyA9IHRoaXMubWF4XG4gICAgICAgICAgICB0aGlzLnRpbWVvdXRJZCA9IHVuZGVmaW5lZFxuICAgICAgICAgIH0sIHRoaXMuaW50ZXJ2YWwpXG4gICAgICAgIH1cblxuICAgICAgICAvLyBSZW1vdmUgZnJvbSBxdWV1ZSwgd2UgYXJlIGV4ZWN1dGluZyBpdC5cbiAgICAgICAgdGhpcy5wZW5kaW5nLnNoaWZ0KClcbiAgICAgICAgLy8gQ2hlY2sgaWYgdGhpcyByZXF1ZXN0IGlzIGFibGUgdG8gYmUgbWFkZSBnbG9iYWxseVxuICAgICAgICBhd2FpdCB0aGlzLnJlc3QuaW52YWxpZEJ1Y2tldC53YWl0VW50aWxSZXF1ZXN0QXZhaWxhYmxlKClcblxuICAgICAgICBhd2FpdCB0aGlzLnJlc3RcbiAgICAgICAgICAuc2VuZFJlcXVlc3QocmVxdWVzdClcbiAgICAgICAgICAvLyBTaG91bGQgYmUgaGFuZGxlZCBpbiBzZW5kUmVxdWVzdCwgdGhpcyBjYXRjaCBqdXN0IHByZXZlbnRzIGJvdHMgZnJvbSBkeWluZ1xuICAgICAgICAgIC5jYXRjaCgoKSA9PiBudWxsKVxuICAgICAgfVxuICAgIH1cblxuICAgIHRoaXMucmVzdC5sb2dnZXIuZGVidWcoYFF1ZXVlICR7dGhpcy5pc09hdXRoMlF1ZXVlKCkgPyAnJyA6ICdCZWFyZXIgJ30ke3RoaXMudXJsfSBwcm9jZXNzIHBlbmRpbmcgd2hpbGUgbG9vcCBleGl0ZWQgd2l0aCAke3RoaXMucGVuZGluZy5sZW5ndGh9LmApXG5cbiAgICAvLyBNYXJrIGFzIGZhbHNlIHNvIG5leHQgcGVuZGluZyByZXF1ZXN0IGNhbiBiZSB0cmlnZ2VyZWQgYnkgbmV3IGxvb3AuXG4gICAgdGhpcy5wcm9jZXNzaW5nUGVuZGluZyA9IGZhbHNlXG4gICAgdGhpcy5jbGVhbnVwKClcbiAgfVxuXG4gIGhhbmRsZUNvbXBsZXRlZFJlcXVlc3QoaGVhZGVyczogeyBtYXg/OiBudW1iZXI7IGludGVydmFsPzogbnVtYmVyOyByZW1haW5pbmc/OiBudW1iZXIgfSk6IHZvaWQge1xuICAgIGlmIChoZWFkZXJzLm1heCA9PT0gMCkge1xuICAgICAgdGhpcy5yZW1haW5pbmcrK1xuICAgICAgcmV0dXJuXG4gICAgfVxuXG4gICAgaWYgKCF0aGlzLmZyb3plbkF0KSB0aGlzLmZyb3plbkF0ID0gRGF0ZS5ub3coKVxuICAgIGlmIChoZWFkZXJzLmludGVydmFsICE9PSB1bmRlZmluZWQpIHRoaXMuaW50ZXJ2YWwgPSBoZWFkZXJzLmludGVydmFsXG4gICAgaWYgKGhlYWRlcnMucmVtYWluaW5nICE9PSB1bmRlZmluZWQpIHRoaXMucmVtYWluaW5nID0gaGVhZGVycy5yZW1haW5pbmdcblxuICAgIGlmICh0aGlzLnJlbWFpbmluZyA8PSAxKSB7XG4gICAgICB0aGlzLnRpbWVvdXRJZCA9IHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICB0aGlzLnJlbWFpbmluZyA9IHRoaXMubWF4XG4gICAgICAgIHRoaXMudGltZW91dElkID0gdW5kZWZpbmVkXG4gICAgICB9LCBoZWFkZXJzLmludGVydmFsKVxuICAgIH1cbiAgfVxuXG4gIC8qKiBDaGVja3MgaWYgYSByZXF1ZXN0IGlzIGF2YWlsYWJsZSBhbmQgYWRkcyBpdCB0byB0aGUgcXVldWUuIEFsc28gdHJpZ2dlcnMgcXVldWUgcHJvY2Vzc2luZyBpZiBub3QgYWxyZWFkeSBwcm9jZXNzaW5nLiAqL1xuICBhc3luYyBtYWtlUmVxdWVzdChvcHRpb25zOiBTZW5kUmVxdWVzdE9wdGlvbnMpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBhd2FpdCB0aGlzLndhaXRVbnRpbFJlcXVlc3RBdmFpbGFibGUoKVxuICAgIHRoaXMucGVuZGluZy5wdXNoKG9wdGlvbnMpXG4gICAgdGhpcy5wcm9jZXNzUGVuZGluZygpXG4gIH1cblxuICAvKiogQ2xlYW5zIHVwIHRoZSBxdWV1ZSBieSBjaGVja2luZyBpZiB0aGVyZSBpcyBub3RoaW5nIGxlZnQgYW5kIHJlbW92aW5nIGl0LiAqL1xuICBjbGVhbnVwKCk6IHZvaWQge1xuICAgIGlmICghdGhpcy5pc1F1ZXVlQ2xlYXJhYmxlKCkpIHtcbiAgICAgIHRoaXMucHJvY2Vzc1BlbmRpbmcoKVxuICAgICAgcmV0dXJuXG4gICAgfVxuXG4gICAgdGhpcy5yZXN0LmxvZ2dlci5kZWJ1ZyhgW1F1ZXVlXSAke3RoaXMuaXNPYXV0aDJRdWV1ZSgpID8gJycgOiAnQmVhcmVyICd9JHt0aGlzLnVybH0uIERlbGF5aW5nIGRlbGV0ZSBmb3IgJHt0aGlzLmRlbGV0ZVF1ZXVlRGVsYXl9bXNgKVxuICAgIC8vIERlbGV0ZSBpbiBhIG1pbnV0ZSBnaXZpbmcgYSBiaXQgb2YgdGltZSB0byBhbGxvdyBuZXcgcmVxdWVzdHMgdGhhdCBtYXkgcmV1c2UgdGhpcyBxdWV1ZVxuICAgIHNldFRpbWVvdXQoYXN5bmMgKCkgPT4ge1xuICAgICAgaWYgKCF0aGlzLmlzUXVldWVDbGVhcmFibGUoKSkge1xuICAgICAgICB0aGlzLnJlc3QubG9nZ2VyLmRlYnVnKGBbUXVldWVdICR7dGhpcy5pc09hdXRoMlF1ZXVlKCkgPyAnJyA6ICdCZWFyZXIgJ30ke3RoaXMudXJsfS4gaXMgbm90IGNsZWFyYWJsZS4gUmVzdGFydGluZyBwcm9jZXNzaW5nIG9mIHF1ZXVlLmApXG4gICAgICAgIHRoaXMucHJvY2Vzc1BlbmRpbmcoKVxuICAgICAgICByZXR1cm5cbiAgICAgIH1cblxuICAgICAgdGhpcy5yZXN0LmxvZ2dlci5kZWJ1ZyhgW1F1ZXVlXSAke3RoaXMudXJsfS4gRGVsZXRpbmdgKVxuICAgICAgaWYgKHRoaXMudGltZW91dElkKSBjbGVhclRpbWVvdXQodGhpcy50aW1lb3V0SWQpXG4gICAgICAvLyBObyByZXF1ZXN0cyBoYXZlIGJlZW4gcmVxdWVzdGVkIGZvciB0aGlzIHF1ZXVlIHNvIHdlIG51a2UgdGhpcyBxdWV1ZVxuICAgICAgdGhpcy5yZXN0LnF1ZXVlcy5kZWxldGUoYCR7dGhpcy5hdXRoZW50aWNhdGlvbn0ke3RoaXMudXJsfWApXG4gICAgICB0aGlzLnJlc3QubG9nZ2VyLmRlYnVnKFxuICAgICAgICBgW1F1ZXVlXSAke3RoaXMudXJsfS4gRGVsZXRlZCEgUmVtYWluaW5nOiAoJHt0aGlzLnJlc3QucXVldWVzLnNpemV9KWAsXG4gICAgICAgIFsuLi50aGlzLnJlc3QucXVldWVzLnZhbHVlcygpXS5tYXAoKHF1ZXVlKSA9PiBgJHtxdWV1ZS5pc09hdXRoMlF1ZXVlKCkgPyAnJyA6ICdCZWFyZXIgJ30ke3F1ZXVlLnVybH1gKSxcbiAgICAgIClcbiAgICAgIGlmICh0aGlzLnJlc3QucXVldWVzLnNpemUpIHRoaXMucHJvY2Vzc1BlbmRpbmcoKVxuICAgIH0sIHRoaXMuZGVsZXRlUXVldWVEZWxheSlcbiAgfVxuXG4gIC8qKiBTaW1wbHkgY2hlY2tzIGlmIHRoZSBxdWV1ZSBpcyBhYmxlIHRvIGJlIGNsZWFyZWQgb3IgaXQgaGFzIHJlcXVlc3RzIHBlbmRpbmcuICovXG4gIGlzUXVldWVDbGVhcmFibGUoKTogYm9vbGVhbiB7XG4gICAgaWYgKHRoaXMuZmlyc3RSZXF1ZXN0KSByZXR1cm4gZmFsc2VcbiAgICBpZiAodGhpcy53YWl0aW5nLmxlbmd0aCA+IDApIHJldHVybiBmYWxzZVxuICAgIGlmICh0aGlzLnBlbmRpbmcubGVuZ3RoID4gMCkgcmV0dXJuIGZhbHNlXG4gICAgaWYgKHRoaXMuaW50ZXJ2YWwgPT09IDApIHJldHVybiBmYWxzZVxuICAgIGlmICh0aGlzLnByb2Nlc3NpbmcpIHJldHVybiBmYWxzZVxuICAgIGlmICh0aGlzLnByb2Nlc3NpbmdQZW5kaW5nKSByZXR1cm4gZmFsc2VcblxuICAgIHJldHVybiB0cnVlXG4gIH1cblxuICBpc09hdXRoMlF1ZXVlKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmF1dGhlbnRpY2F0aW9uID09PSAnJ1xuICB9XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUXVldWVPcHRpb25zIHtcbiAgLyoqIEhvdyBtYW55IHJlcXVlc3RzIGFyZSByZW1haW5pbmcuIERlZmF1bHRzIHRvIDEgKi9cbiAgcmVtYWluaW5nPzogbnVtYmVyXG4gIC8qKiBNYXggbnVtYmVyIG9mIHJlcXVlc3RzIGFsbG93ZWQgaW4gdGhpcyB0aGlzLiBEZWZhdWx0cyB0byAxLiAqL1xuICBtYXg/OiBudW1iZXJcbiAgLyoqIFRoZSB0aW1lIGluIG1pbGxpc2Vjb25kcyB0aGF0IGRpc2NvcmQgYWxsb3dzIHRvIG1ha2UgdGhlIG1heCBudW1iZXIgb2YgaW52YWxpZCByZXF1ZXN0cy4gRGVmYXVsdHMgdG8gMCAqL1xuICBpbnRlcnZhbD86IG51bWJlclxuICAvKiogdGltZXIgdG8gcmVzZXQgdG8gMCAqL1xuICB0aW1lb3V0SWQ/OiBOb2RlSlMuVGltZW91dFxuICAvKiogVGhlIHVybCB0aGlzIHF1ZXVlIHdpbGwgYmUgaGFuZGxpbmcuICovXG4gIHVybDogc3RyaW5nXG4gIC8qKiBUaGUgdGltZSBpbiBtaWxsaXNlY29uZHMgdG8gd2FpdCBiZWZvcmUgZGVsZXRpbmcgdGhpcyBxdWV1ZSBpZiBpdCBpcyBlbXB0eS4gRGVmYXVsdHMgdG8gNjAwMDAob25lIG1pbnV0ZSkuICovXG4gIGRlbGV0ZVF1ZXVlRGVsYXk/OiBudW1iZXJcbiAgLyoqIEF1dGhlbnRpY2F0aW9uIHVzZWQgZm9yIHRoZSByZXF1ZXN0LiBJbiBub24tT0F1dGgyIHNpdHVhdGlvbnMgc2hvdWxkIGJlIGFuIGVtcHR5IHN0cmluZy4gRGVmYXVsdHMgdG8gYW4gZW1wdHkgc3RyaW5nICovXG4gIGF1dGhlbnRpY2F0aW9uPzogc3RyaW5nXG59XG4iXSwibmFtZXMiOlsiUXVldWUiLCJjb25zdHJ1Y3RvciIsInJlc3QiLCJvcHRpb25zIiwicmVtYWluaW5nIiwibWF4IiwiaW50ZXJ2YWwiLCJ3YWl0aW5nIiwicGVuZGluZyIsInByb2Nlc3NpbmciLCJwcm9jZXNzaW5nUGVuZGluZyIsImZpcnN0UmVxdWVzdCIsImZyb3plbkF0IiwiZGVsZXRlUXVldWVEZWxheSIsImF1dGhlbnRpY2F0aW9uIiwidXJsIiwidGltZW91dElkIiwiaXNSZXF1ZXN0QWxsb3dlZCIsIndhaXRVbnRpbFJlcXVlc3RBdmFpbGFibGUiLCJQcm9taXNlIiwicmVzb2x2ZSIsInB1c2giLCJwcm9jZXNzV2FpdGluZyIsImxlbmd0aCIsImxvZ2dlciIsImRlYnVnIiwiaXNPYXV0aDJRdWV1ZSIsInNoaWZ0IiwiZGVsYXkiLCJwcm9jZXNzUGVuZGluZyIsIm5vdyIsIkRhdGUiLCJmdXR1cmUiLCJyZXF1ZXN0IiwiYmFzaWNVUkwiLCJzaW1wbGlmeVVybCIsInJvdXRlIiwibWV0aG9kIiwidXJsUmVzZXRJbiIsImNoZWNrUmF0ZUxpbWl0cyIsInJlcXVlc3RCb2R5T3B0aW9ucyIsImhlYWRlcnMiLCJidWNrZXRSZXNldEluIiwiYnVja2V0SWQiLCJzZXRUaW1lb3V0IiwidW5kZWZpbmVkIiwiaW52YWxpZEJ1Y2tldCIsInNlbmRSZXF1ZXN0IiwiY2F0Y2giLCJjbGVhbnVwIiwiaGFuZGxlQ29tcGxldGVkUmVxdWVzdCIsIm1ha2VSZXF1ZXN0IiwiaXNRdWV1ZUNsZWFyYWJsZSIsImNsZWFyVGltZW91dCIsInF1ZXVlcyIsImRlbGV0ZSIsInNpemUiLCJ2YWx1ZXMiLCJtYXAiLCJxdWV1ZSJdLCJtYXBwaW5ncyI6Ijs7OzsrQkFHYUE7OztlQUFBQTs7O3VCQUhTO0FBR2YsSUFBQSxBQUFNQSxRQUFOLE1BQU1BO0lBOEJYQyxZQUFZQyxJQUFpQixFQUFFQyxPQUFxQixDQUFFO1FBM0J0RCwrREFBK0QsUUFDL0RDLFlBQW9CO1FBQ3BCLCtDQUErQyxRQUMvQ0MsTUFBYztRQUNkLG1GQUFtRixRQUNuRkMsV0FBbUI7UUFHbkIsNkNBQTZDLFFBQzdDQyxVQUE0RCxFQUFFO1FBQzlELDZDQUE2QyxRQUM3Q0MsVUFBZ0MsRUFBRTtRQUNsQyw0REFBNEQsUUFDNURDLGFBQXNCO1FBQ3RCLDREQUE0RCxRQUM1REMsb0JBQTZCO1FBQzdCLDBDQUEwQyxRQUMxQ0MsZUFBd0I7UUFHeEIsbUZBQW1GLFFBQ25GQyxXQUFtQjtRQUNuQiwrR0FBK0csUUFDL0dDLG1CQUEyQjtRQUMzQiwrR0FBK0csUUFDL0dDLGlCQUF5QjtRQUd2QixJQUFJLENBQUNaLElBQUksR0FBR0E7UUFDWixJQUFJLENBQUNhLEdBQUcsR0FBR1osUUFBUVksR0FBRztRQUV0QixJQUFJWixRQUFRRyxRQUFRLEVBQUUsSUFBSSxDQUFDQSxRQUFRLEdBQUdILFFBQVFHLFFBQVE7UUFDdEQsSUFBSUgsUUFBUUUsR0FBRyxFQUFFLElBQUksQ0FBQ0EsR0FBRyxHQUFHRixRQUFRRSxHQUFHO1FBQ3ZDLElBQUlGLFFBQVFDLFNBQVMsRUFBRSxJQUFJLENBQUNBLFNBQVMsR0FBR0QsUUFBUUMsU0FBUztRQUN6RCxJQUFJRCxRQUFRYSxTQUFTLEVBQUUsSUFBSSxDQUFDQSxTQUFTLEdBQUdiLFFBQVFhLFNBQVM7UUFDekQsSUFBSWIsUUFBUVUsZ0JBQWdCLEVBQUUsSUFBSSxD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