UNPKG

17.3 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.default = exports.QueueClosedError = void 0;
7
8var _autoBind = _interopRequireDefault(require("auto-bind"));
9
10var _Module = _interopRequireDefault(require("./Module"));
11
12function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
13
14function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
15
16const {
17 MODULE_NAME,
18 log,
19 warn,
20 error,
21 noteGauge,
22 noteCount,
23 trackOp
24} = new _Module.default(__filename); // eslint-disable-line no-unused-vars
25
26const DEFAULT_MAX_QUEUE_SIZE = -1;
27
28class QueueClosedError extends Error {
29 constructor(queueName) {
30 super(queueName ? `Queue '${queueName}' is closed` : 'Queue closed');
31 }
32
33}
34
35exports.QueueClosedError = QueueClosedError;
36
37class AsyncQueue {
38 constructor(config) {
39 _defineProperty(this, "name", void 0);
40
41 _defineProperty(this, "_items", void 0);
42
43 _defineProperty(this, "_closed", void 0);
44
45 _defineProperty(this, "_maxSize", void 0);
46
47 _defineProperty(this, "_enqueueWaitingList", void 0);
48
49 _defineProperty(this, "_dequeueWaitingList", void 0);
50
51 _defineProperty(this, "_closeWaitingList", void 0);
52
53 _defineProperty(this, "getLength", () => {
54 return this._items.length;
55 });
56
57 // config
58 config = config || {
59 name: undefined,
60 maxSize: undefined
61 };
62 this.name = config.name;
63 this._maxSize = config.maxSize || DEFAULT_MAX_QUEUE_SIZE; // state
64
65 this._items = [];
66 this._closed = false;
67 this._enqueueWaitingList = [];
68 this._dequeueWaitingList = [];
69 this._closeWaitingList = [];
70 (0, _autoBind.default)(this);
71 }
72
73 async enqueue(newItem) {
74 if (this._closed) {
75 throw new Error(`Queue is closed`);
76 } // wait for space to enqueue
77
78
79 if (this._maxSize > 0 && this._items.length >= this._maxSize) {
80 await new Promise((res, rej) => this._enqueueWaitingList.push({
81 res,
82 rej
83 }));
84 } //log(`Enqueued '${newItem}' to queue '${this.name}'`)
85 // release oldest waiting dequeue
86
87
88 if (this._dequeueWaitingList.length) {
89 this._dequeueWaitingList.shift().res(newItem);
90 } else {
91 this._items.push(newItem);
92 }
93
94 this.name && noteCount(`${this.name}.enqueue`, 1);
95 this.name && noteGauge(`${this.name}.items`, this._items.length);
96 }
97
98 async dequeue() {
99 let item;
100
101 if (this._items.length === 0) {
102 // if there are NO queued items
103 if (this._closed) {
104 throw new QueueClosedError(this.name);
105 }
106
107 item = await new Promise((res, rej) => this._dequeueWaitingList.push({
108 res,
109 rej
110 }));
111 } else {
112 // if there are queued items
113 item = this._items.shift(); // release oldest waiting enqueue
114
115 if (this._enqueueWaitingList.length) {
116 this._enqueueWaitingList.shift().res();
117 }
118 }
119
120 this.name && noteCount(`${this.name}.dequeue`, 1);
121 this.name && noteGauge(`${this.name}.items`, this._items.length); //log(`Dequeued '${item}' from queue '${this.name}'`)
122 // release all waiting closes
123
124 if (this._items.length === 0) {
125 this._closeWaitingList.forEach(cbs => cbs.res());
126 }
127
128 return item;
129 }
130
131 dequeueAllAvailable() {
132 const items = this._items.splice(0);
133
134 this.name && noteCount(`${this.name}.dequeue`, items.length);
135 this.name && noteGauge(`${this.name}.items`, this._items.length);
136
137 if (this._enqueueWaitingList.length > 0) {
138 const enqueuesToRelease = Math.min(this._enqueueWaitingList.length, this._maxSize);
139
140 for (let index = 0; index < enqueuesToRelease; index++) {
141 this._enqueueWaitingList.shift().res();
142 }
143 } // release all waiting closes
144
145
146 this._closeWaitingList.forEach(cbs => cbs.res());
147
148 return items;
149 }
150
151 async close() {
152 this._closed = true; // fail all waiting enqueued
153
154 this._enqueueWaitingList.forEach(cbs => cbs.rej(new Error('Queue closed'))); // wait for all existing items to be dequeued
155
156
157 if (this._items.length > 0) {
158 await new Promise((res, rej) => this._closeWaitingList.push({
159 res,
160 rej
161 }));
162 } // release all remaining waiting dequeues
163
164
165 this._dequeueWaitingList.forEach(cbs => cbs.rej(new QueueClosedError(this.name)));
166 }
167
168 async enqueueRange(newItems) {
169 for (const newItem of newItems) {
170 await this.enqueue(newItem);
171 }
172 }
173
174 async dequeueRange(count) {
175 const results = [];
176
177 while (results.length < count) {
178 try {
179 const item = await this.dequeue();
180 results.push(item);
181 } catch (err) {
182 if (err instanceof QueueClosedError) break;
183 throw err;
184 }
185 }
186
187 return results;
188 }
189
190}
191
192exports.default = AsyncQueue;
193//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9Bc3luY1F1ZXVlLmpzIl0sIm5hbWVzIjpbIk1PRFVMRV9OQU1FIiwibG9nIiwid2FybiIsImVycm9yIiwibm90ZUdhdWdlIiwibm90ZUNvdW50IiwidHJhY2tPcCIsIk1vZHVsZSIsIl9fZmlsZW5hbWUiLCJERUZBVUxUX01BWF9RVUVVRV9TSVpFIiwiUXVldWVDbG9zZWRFcnJvciIsIkVycm9yIiwiY29uc3RydWN0b3IiLCJxdWV1ZU5hbWUiLCJBc3luY1F1ZXVlIiwiY29uZmlnIiwiX2l0ZW1zIiwibGVuZ3RoIiwibmFtZSIsInVuZGVmaW5lZCIsIm1heFNpemUiLCJfbWF4U2l6ZSIsIl9jbG9zZWQiLCJfZW5xdWV1ZVdhaXRpbmdMaXN0IiwiX2RlcXVldWVXYWl0aW5nTGlzdCIsIl9jbG9zZVdhaXRpbmdMaXN0IiwiZW5xdWV1ZSIsIm5ld0l0ZW0iLCJQcm9taXNlIiwicmVzIiwicmVqIiwicHVzaCIsInNoaWZ0IiwiZGVxdWV1ZSIsIml0ZW0iLCJmb3JFYWNoIiwiY2JzIiwiZGVxdWV1ZUFsbEF2YWlsYWJsZSIsIml0ZW1zIiwic3BsaWNlIiwiZW5xdWV1ZXNUb1JlbGVhc2UiLCJNYXRoIiwibWluIiwiaW5kZXgiLCJjbG9zZSIsImVucXVldWVSYW5nZSIsIm5ld0l0ZW1zIiwiZGVxdWV1ZVJhbmdlIiwiY291bnQiLCJyZXN1bHRzIiwiZXJyIl0sIm1hcHBpbmdzIjoiOzs7Ozs7O0FBRUE7O0FBRUE7Ozs7OztBQUVBLE1BQU07QUFBRUEsRUFBQUEsV0FBRjtBQUFlQyxFQUFBQSxHQUFmO0FBQW9CQyxFQUFBQSxJQUFwQjtBQUEwQkMsRUFBQUEsS0FBMUI7QUFBaUNDLEVBQUFBLFNBQWpDO0FBQTRDQyxFQUFBQSxTQUE1QztBQUF1REMsRUFBQUE7QUFBdkQsSUFBbUUsSUFBSUMsZUFBSixDQUFXQyxVQUFYLENBQXpFLEMsQ0FBZ0c7O0FBR2hHLE1BQU1DLHNCQUFzQixHQUFHLENBQUMsQ0FBaEM7O0FBT08sTUFBTUMsZ0JBQU4sU0FBK0JDLEtBQS9CLENBQXFDO0FBQzFDQyxFQUFBQSxXQUFXLENBQUNDLFNBQUQsRUFBcUI7QUFDOUIsVUFBTUEsU0FBUyxHQUFJLFVBQVNBLFNBQVUsYUFBdkIsR0FBc0MsY0FBckQ7QUFDRDs7QUFIeUM7Ozs7QUFNN0IsTUFBTUMsVUFBTixDQUFvQjtBQWFqQ0YsRUFBQUEsV0FBVyxDQUFDRyxNQUFELEVBQXVCO0FBQUE7O0FBQUE7O0FBQUE7O0FBQUE7O0FBQUE7O0FBQUE7O0FBQUE7O0FBQUEsdUNBbUl0QixNQUFjO0FBQ3hCLGFBQU8sS0FBS0MsTUFBTCxDQUFZQyxNQUFuQjtBQUNELEtBcklpQzs7QUFFaEM7QUFDQUYsSUFBQUEsTUFBTSxHQUFHQSxNQUFNLElBQUk7QUFBRUcsTUFBQUEsSUFBSSxFQUFFQyxTQUFSO0FBQW1CQyxNQUFBQSxPQUFPLEVBQUVEO0FBQTVCLEtBQW5CO0FBQ0EsU0FBS0QsSUFBTCxHQUFZSCxNQUFNLENBQUNHLElBQW5CO0FBQ0EsU0FBS0csUUFBTCxHQUFnQk4sTUFBTSxDQUFDSyxPQUFQLElBQWtCWCxzQkFBbEMsQ0FMZ0MsQ0FPaEM7O0FBQ0EsU0FBS08sTUFBTCxHQUFjLEVBQWQ7QUFDQSxTQUFLTSxPQUFMLEdBQWUsS0FBZjtBQUVBLFNBQUtDLG1CQUFMLEdBQTJCLEVBQTNCO0FBQ0EsU0FBS0MsbUJBQUwsR0FBMkIsRUFBM0I7QUFDQSxTQUFLQyxpQkFBTCxHQUF5QixFQUF6QjtBQUVBLDJCQUFTLElBQVQ7QUFDRDs7QUFHRCxRQUFNQyxPQUFOLENBQWNDLE9BQWQsRUFBeUM7QUFFdkMsUUFBSSxLQUFLTCxPQUFULEVBQWtCO0FBQ2hCLFlBQU0sSUFBSVgsS0FBSixDQUFXLGlCQUFYLENBQU47QUFDRCxLQUpzQyxDQU12Qzs7O0FBQ0EsUUFBSSxLQUFLVSxRQUFMLEdBQWdCLENBQWhCLElBQXFCLEtBQUtMLE1BQUwsQ0FBWUMsTUFBWixJQUFzQixLQUFLSSxRQUFwRCxFQUE4RDtBQUM1RCxZQUFNLElBQUlPLE9BQUosQ0FBWSxDQUFDQyxHQUFELEVBQU1DLEdBQU4sS0FBYyxLQUFLUCxtQkFBTCxDQUF5QlEsSUFBekIsQ0FBOEI7QUFBRUYsUUFBQUEsR0FBRjtBQUFPQyxRQUFBQTtBQUFQLE9BQTlCLENBQTFCLENBQU47QUFDRCxLQVRzQyxDQVd2QztBQUVBOzs7QUFDQSxRQUFJLEtBQUtOLG1CQUFMLENBQXlCUCxNQUE3QixFQUFxQztBQUNuQyxXQUFLTyxtQkFBTCxDQUF5QlEsS0FBekIsR0FBaUNILEdBQWpDLENBQXFDRixPQUFyQztBQUNELEtBRkQsTUFFTztBQUNMLFdBQUtYLE1BQUwsQ0FBWWUsSUFBWixDQUFpQkosT0FBakI7QUFDRDs7QUFFRCxTQUFLVCxJQUFMLElBQWFiLFNBQVMsQ0FBRSxHQUFFLEtBQUthLElBQUssVUFBZCxFQUF5QixDQUF6QixDQUF0QjtBQUNBLFNBQUtBLElBQUwsSUFBYWQsU0FBUyxDQUFFLEdBQUUsS0FBS2MsSUFBSyxRQUFkLEVBQXVCLEtBQUtGLE1BQUwsQ0FBWUMsTUFBbkMsQ0FBdEI7QUFDRDs7QUFFRCxRQUFNZ0IsT0FBTixHQUE0QjtBQUMxQixRQUFJQyxJQUFKOztBQUNBLFFBQUksS0FBS2xCLE1BQUwsQ0FBWUMsTUFBWixLQUF1QixDQUEzQixFQUE4QjtBQUFFO0FBRTlCLFVBQUksS0FBS0ssT0FBVCxFQUFrQjtBQUNoQixjQUFNLElBQUlaLGdCQUFKLENBQXFCLEtBQUtRLElBQTFCLENBQU47QUFDRDs7QUFDRGdCLE1BQUFBLElBQUksR0FBRyxNQUFNLElBQUlOLE9BQUosQ0FBWSxDQUFDQyxHQUFELEVBQU1DLEdBQU4sS0FBYyxLQUFLTixtQkFBTCxDQUF5Qk8sSUFBekIsQ0FBOEI7QUFBRUYsUUFBQUEsR0FBRjtBQUFPQyxRQUFBQTtBQUFQLE9BQTlCLENBQTFCLENBQWI7QUFFRCxLQVBELE1BT087QUFBRTtBQUVQSSxNQUFBQSxJQUFJLEdBQUcsS0FBS2xCLE1BQUwsQ0FBWWdCLEtBQVosRUFBUCxDQUZLLENBSUw7O0FBQ0EsVUFBSSxLQUFLVCxtQkFBTCxDQUF5Qk4sTUFBN0IsRUFBcUM7QUFDbkMsYUFBS00sbUJBQUwsQ0FBeUJTLEtBQXpCLEdBQWlDSCxHQUFqQztBQUNEO0FBRUY7O0FBRUQsU0FBS1gsSUFBTCxJQUFhYixTQUFTLENBQUUsR0FBRSxLQUFLYSxJQUFLLFVBQWQsRUFBeUIsQ0FBekIsQ0FBdEI7QUFDQSxTQUFLQSxJQUFMLElBQWFkLFNBQVMsQ0FBRSxHQUFFLEtBQUtjLElBQUssUUFBZCxFQUF1QixLQUFLRixNQUFMLENBQVlDLE1BQW5DLENBQXRCLENBckIwQixDQXVCMUI7QUFFQTs7QUFDQSxRQUFJLEtBQUtELE1BQUwsQ0FBWUMsTUFBWixLQUF1QixDQUEzQixFQUE4QjtBQUM1QixXQUFLUSxpQkFBTCxDQUF1QlUsT0FBdkIsQ0FBK0JDLEdBQUcsSUFBSUEsR0FBRyxDQUFDUCxHQUFKLEVBQXRDO0FBQ0Q7O0FBRUQsV0FBT0ssSUFBUDtBQUNEOztBQUVERyxFQUFBQSxtQkFBbUIsR0FBYTtBQUM5QixVQUFNQyxLQUFLLEdBQUcsS0FBS3RCLE1BQUwsQ0FBWXVCLE1BQVosQ0FBbUIsQ0FBbkIsQ0FBZDs7QUFFQSxTQUFLckIsSUFBTCxJQUFhYixTQUFTLENBQUUsR0FBRSxLQUFLYSxJQUFLLFVBQWQsRUFBeUJvQixLQUFLLENBQUNyQixNQUEvQixDQUF0QjtBQUNBLFNBQUtDLElBQUwsSUFBYWQsU0FBUyxDQUFFLEdBQUUsS0FBS2MsSUFBSyxRQUFkLEVBQXVCLEtBQUtGLE1BQUwsQ0FBWUMsTUFBbkMsQ0FBdEI7O0FBRUEsUUFBSSxLQUFLTSxtQkFBTCxDQUF5Qk4sTUFBekIsR0FBa0MsQ0FBdEMsRUFBeUM7QUFDdkMsWUFBTXVCLGlCQUFpQixHQUFHQyxJQUFJLENBQUNDLEdBQUwsQ0FBUyxLQUFLbkIsbUJBQUwsQ0FBeUJOLE1BQWxDLEVBQTBDLEtBQUtJLFFBQS9DLENBQTFCOztBQUNBLFdBQUssSUFBSXNCLEtBQUssR0FBRyxDQUFqQixFQUFvQkEsS0FBSyxHQUFHSCxpQkFBNUIsRUFBK0NHLEtBQUssRUFBcEQsRUFBd0Q7QUFDdEQsYUFBS3BCLG1CQUFMLENBQXlCUyxLQUF6QixHQUFpQ0gsR0FBakM7QUFDRDtBQUNGLEtBWDZCLENBYTlCOzs7QUFDQSxTQUFLSixpQkFBTCxDQUF1QlUsT0FBdkIsQ0FBK0JDLEdBQUcsSUFBSUEsR0FBRyxDQUFDUCxHQUFKLEVBQXRDOztBQUVBLFdBQU9TLEtBQVA7QUFDRDs7QUFFRCxRQUFNTSxLQUFOLEdBQTZCO0FBQzNCLFNBQUt0QixPQUFMLEdBQWUsSUFBZixDQUQyQixDQUczQjs7QUFDQSxTQUFLQyxtQkFBTCxDQUF5QlksT0FBekIsQ0FBaUNDLEdBQUcsSUFBSUEsR0FBRyxDQUFDTixHQUFKLENBQVEsSUFBSW5CLEtBQUosQ0FBVSxjQUFWLENBQVIsQ0FBeEMsRUFKMkIsQ0FNM0I7OztBQUNBLFFBQUksS0FBS0ssTUFBTCxDQUFZQyxNQUFaLEdBQXFCLENBQXpCLEVBQTRCO0FBQzFCLFlBQU0sSUFBSVcsT0FBSixDQUFZLENBQUNDLEdBQUQsRUFBTUMsR0FBTixLQUFlLEtBQUtMLGlCQUFMLENBQXVCTSxJQUF2QixDQUE0QjtBQUFFRixRQUFBQSxHQUFGO0FBQU9DLFFBQUFBO0FBQVAsT0FBNUIsQ0FBM0IsQ0FBTjtBQUNELEtBVDBCLENBVzNCOzs7QUFDQSxTQUFLTixtQkFBTCxDQUF5QlcsT0FBekIsQ0FBaUNDLEdBQUcsSUFBSUEsR0FBRyxDQUFDTixHQUFKLENBQVEsSUFBSXBCLGdCQUFKLENBQXFCLEtBQUtRLElBQTFCLENBQVIsQ0FBeEM7QUFDRDs7QUFFRCxRQUFNMkIsWUFBTixDQUFvQkMsUUFBcEIsRUFBd0M7QUFDdEMsU0FBSyxNQUFNbkIsT0FBWCxJQUFzQm1CLFFBQXRCLEVBQWdDO0FBQzlCLFlBQU0sS0FBS3BCLE9BQUwsQ0FBYUMsT0FBYixDQUFOO0FBQ0Q7QUFDRjs7QUFFRCxRQUFNb0IsWUFBTixDQUFtQkMsS0FBbkIsRUFBcUQ7QUFDbkQsVUFBTUMsT0FBTyxHQUFHLEVBQWhCOztBQUNBLFdBQU9BLE9BQU8sQ0FBQ2hDLE1BQVIsR0FBaUIrQixLQUF4QixFQUErQjtBQUM3QixVQUFJO0FBQ0YsY0FBTWQsSUFBSSxHQUFHLE1BQU0sS0FBS0QsT0FBTCxFQUFuQjtBQUNBZ0IsUUFBQUEsT0FBTyxDQUFDbEIsSUFBUixDQUFhRyxJQUFiO0FBQ0QsT0FIRCxDQUdFLE9BQU9nQixHQUFQLEVBQVk7QUFDWixZQUFJQSxHQUFHLFlBQVl4QyxnQkFBbkIsRUFDRTtBQUNGLGNBQU13QyxHQUFOO0FBQ0Q7QUFDRjs7QUFDRCxXQUFPRCxPQUFQO0FBQ0Q7O0FBOUlnQyIsInNvdXJjZXNDb250ZW50IjpbIi8vQGZsb3dcblxuaW1wb3J0IGF1dG9CaW5kIGZyb20gJ2F1dG8tYmluZCdcblxuaW1wb3J0IE1vZHVsZSBmcm9tICcuL01vZHVsZSdcblxuY29uc3QgeyBNT0RVTEVfTkFNRSwgbG9nLCB3YXJuLCBlcnJvciwgbm90ZUdhdWdlLCBub3RlQ291bnQsIHRyYWNrT3AgfSA9IG5ldyBNb2R1bGUoX19maWxlbmFtZSkgLy8gZXNsaW50LWRpc2FibGUtbGluZSBuby11bnVzZWQtdmFyc1xuXG5cbmNvbnN0IERFRkFVTFRfTUFYX1FVRVVFX1NJWkUgPSAtMVxuXG50eXBlIFF1ZXVlQ29uZmlnID0ge3xcbiAgbmFtZT86ID9zdHJpbmcsXG4gIG1heFNpemU/OiA/bnVtYmVyLFxufH1cblxuZXhwb3J0IGNsYXNzIFF1ZXVlQ2xvc2VkRXJyb3IgZXh0ZW5kcyBFcnJvciB7XG4gIGNvbnN0cnVjdG9yKHF1ZXVlTmFtZTogP3N0cmluZykge1xuICAgIHN1cGVyKHF1ZXVlTmFtZSA/IGBRdWV1ZSAnJHtxdWV1ZU5hbWV9JyBpcyBjbG9zZWRgIDogJ1F1ZXVlIGNsb3NlZCcpXG4gIH1cbn1cblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgQXN5bmNRdWV1ZTxUPiB7XG4gIFxuICBuYW1lOiA/c3RyaW5nXG5cbiAgX2l0ZW1zOiBBcnJheTxUPlxuICBfY2xvc2VkOiBib29sZWFuXG4gIF9tYXhTaXplOiBudW1iZXJcblxuICBfZW5xdWV1ZVdhaXRpbmdMaXN0OiBBcnJheTx7IHJlczogKCkgPT4gdm9pZCwgcmVqOiAoZXJyOiBFcnJvcikgPT4gdm9pZCB9PlxuICBfZGVxdWV1ZVdhaXRpbmdMaXN0OiBBcnJheTx7IHJlczogKFQpID0+IHZvaWQsIHJlajogKGVycjogRXJyb3IpID0+IHZvaWQgfT5cbiAgX2Nsb3NlV2FpdGluZ0xpc3Q6IEFycmF5PHsgcmVzOiAoKSA9PiB2b2lkLCByZWo6IChlcnI6IEVycm9yKSA9PiB2b2lkIH0+XG5cblxuICBjb25zdHJ1Y3Rvcihjb25maWc/OiBRdWV1ZUNvbmZpZykge1xuXG4gICAgLy8gY29uZmlnXG4gICAgY29uZmlnID0gY29uZmlnIHx8IHsgbmFtZTogdW5kZWZpbmVkLCBtYXhTaXplOiB1bmRlZmluZWQgfVxuICAgIHRoaXMubmFtZSA9IGNvbmZpZy5uYW1lXG4gICAgdGhpcy5fbWF4U2l6ZSA9IGNvbmZpZy5tYXhTaXplIHx8IERFRkFVTFRfTUFYX1FVRVVFX1NJWkVcblxuICAgIC8vIHN0YXRlXG4gICAgdGhpcy5faXRlbXMgPSBbXVxuICAgIHRoaXMuX2Nsb3NlZCA9IGZhbHNlXG5cbiAgICB0aGlzLl9lbnF1ZXVlV2FpdGluZ0xpc3QgPSBbXVxuICAgIHRoaXMuX2RlcXVldWVXYWl0aW5nTGlzdCA9IFtdXG4gICAgdGhpcy5fY2xvc2VXYWl0aW5nTGlzdCA9IFtdXG5cbiAgICBhdXRvQmluZCh0aGlzKVxuICB9XG5cblxuICBhc3luYyBlbnF1ZXVlKG5ld0l0ZW06IFQpOiBQcm9taXNlPHZvaWQ+IHtcblxuICAgIGlmICh0aGlzLl9jbG9zZWQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgUXVldWUgaXMgY2xvc2VkYClcbiAgICB9XG5cbiAgICAvLyB3YWl0IGZvciBzcGFjZSB0byBlbnF1ZXVlXG4gICAgaWYgKHRoaXMuX21heFNpemUgPiAwICYmIHRoaXMuX2l0ZW1zLmxlbmd0aCA+PSB0aGlzLl9tYXhTaXplKSB7XG4gICAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzLCByZWopID0+IHRoaXMuX2VucXVldWVXYWl0aW5nTGlzdC5wdXNoKHsgcmVzLCByZWogfSkpICBcbiAgICB9XG5cbiAgICAvL2xvZyhgRW5xdWV1ZWQgJyR7bmV3SXRlbX0nIHRvIHF1ZXVlICcke3RoaXMubmFtZX0nYCkgICAgXG4gICAgXG4gICAgLy8gcmVsZWFzZSBvbGRlc3Qgd2FpdGluZyBkZXF1ZXVlXG4gICAgaWYgKHRoaXMuX2RlcXVldWVXYWl0aW5nTGlzdC5sZW5ndGgpIHtcbiAgICAgIHRoaXMuX2RlcXVldWVXYWl0aW5nTGlzdC5zaGlmdCgpLnJlcyhuZXdJdGVtKVxuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLl9pdGVtcy5wdXNoKG5ld0l0ZW0pXG4gICAgfVxuXG4gICAgdGhpcy5uYW1lICYmIG5vdGVDb3VudChgJHt0aGlzLm5hbWV9LmVucXVldWVgLCAxKVxuICAgIHRoaXMubmFtZSAmJiBub3RlR2F1Z2UoYCR7dGhpcy5uYW1lfS5pdGVtc2AsIHRoaXMuX2l0ZW1zLmxlbmd0aClcbiAgfVxuXG4gIGFzeW5jIGRlcXVldWUoKTogUHJvbWlzZTxUPiB7XG4gICAgbGV0IGl0ZW06IFRcbiAgICBpZiAodGhpcy5faXRlbXMubGVuZ3RoID09PSAwKSB7IC8vIGlmIHRoZXJlIGFyZSBOTyBxdWV1ZWQgaXRlbXNcbiAgICAgXG4gICAgICBpZiAodGhpcy5fY2xvc2VkKSB7XG4gICAgICAgIHRocm93IG5ldyBRdWV1ZUNsb3NlZEVycm9yKHRoaXMubmFtZSlcbiAgICAgIH1cbiAgICAgIGl0ZW0gPSBhd2FpdCBuZXcgUHJvbWlzZSgocmVzLCByZWopID0+IHRoaXMuX2RlcXVldWVXYWl0aW5nTGlzdC5wdXNoKHsgcmVzLCByZWogfSkpICBcbiAgICAgIFxuICAgIH0gZWxzZSB7IC8vIGlmIHRoZXJlIGFyZSBxdWV1ZWQgaXRlbXNcbiAgICAgIFxuICAgICAgaXRlbSA9IHRoaXMuX2l0ZW1zLnNoaWZ0KCkgXG5cbiAgICAgIC8vIHJlbGVhc2Ugb2xkZXN0IHdhaXRpbmcgZW5xdWV1ZVxuICAgICAgaWYgKHRoaXMuX2VucXVldWVXYWl0aW5nTGlzdC5sZW5ndGgpIHtcbiAgICAgICAgdGhpcy5fZW5xdWV1ZVdhaXRpbmdMaXN0LnNoaWZ0KCkucmVzKClcbiAgICAgIH0gIFxuXG4gICAgfVxuXG4gICAgdGhpcy5uYW1lICYmIG5vdGVDb3VudChgJHt0aGlzLm5hbWV9LmRlcXVldWVgLCAxKVxuICAgIHRoaXMubmFtZSAmJiBub3RlR2F1Z2UoYCR7dGhpcy5uYW1lfS5pdGVtc2AsIHRoaXMuX2l0ZW1zLmxlbmd0aClcblxuICAgIC8vbG9nKGBEZXF1ZXVlZCAnJHtpdGVtfScgZnJvbSBxdWV1ZSAnJHt0aGlzLm5hbWV9J2ApXG5cbiAgICAvLyByZWxlYXNlIGFsbCB3YWl0aW5nIGNsb3Nlc1xuICAgIGlmICh0aGlzLl9pdGVtcy5sZW5ndGggPT09IDApIHtcbiAgICAgIHRoaXMuX2Nsb3NlV2FpdGluZ0xpc3QuZm9yRWFjaChjYnMgPT4gY2JzLnJlcygpKVxuICAgIH1cblxuICAgIHJldHVybiBpdGVtICAgXG4gIH1cblxuICBkZXF1ZXVlQWxsQXZhaWxhYmxlKCk6IEFycmF5PFQ+IHtcbiAgICBjb25zdCBpdGVtcyA9IHRoaXMuX2l0ZW1zLnNwbGljZSgwKVxuXG4gICAgdGhpcy5uYW1lICYmIG5vdGVDb3VudChgJHt0aGlzLm5hbWV9LmRlcXVldWVgLCBpdGVtcy5sZW5ndGgpXG4gICAgdGhpcy5uYW1lICYmIG5vdGVHYXVnZShgJHt0aGlzLm5hbWV9Lml0ZW1zYCwgdGhpcy5faXRlbXMubGVuZ3RoKVxuXG4gICAgaWYgKHRoaXMuX2VucXVldWVXYWl0aW5nTGlzdC5sZW5ndGggPiAwKSB7XG4gICAgICBjb25zdCBlbnF1ZXVlc1RvUmVsZWFzZSA9IE1hdGgubWluKHRoaXMuX2VucXVldWVXYWl0aW5nTGlzdC5sZW5ndGgsIHRoaXMuX21heFNpemUpXG4gICAgICBmb3IgKGxldCBpbmRleCA9IDA7IGluZGV4IDwgZW5xdWV1ZXNUb1JlbGVhc2U7IGluZGV4KyspIHtcbiAgICAgICAgdGhpcy5fZW5xdWV1ZVdhaXRpbmdMaXN0LnNoaWZ0KCkucmVzKClcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyByZWxlYXNlIGFsbCB3YWl0aW5nIGNsb3Nlc1xuICAgIHRoaXMuX2Nsb3NlV2FpdGluZ0xpc3QuZm9yRWFjaChjYnMgPT4gY2JzLnJlcygpKVxuXG4gICAgcmV0dXJuIGl0ZW1zXG4gIH1cblxuICBhc3luYyBjbG9zZSgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0aGlzLl9jbG9zZWQgPSB0cnVlXG5cbiAgICAvLyBmYWlsIGFsbCB3YWl0aW5nIGVucXVldWVkXG4gICAgdGhpcy5fZW5xdWV1ZVdhaXRpbmdMaXN0LmZvckVhY2goY2JzID0+IGNicy5yZWoobmV3IEVycm9yKCdRdWV1ZSBjbG9zZWQnKSkpXG5cbiAgICAvLyB3YWl0IGZvciBhbGwgZXhpc3RpbmcgaXRlbXMgdG8gYmUgZGVxdWV1ZWRcbiAgICBpZiAodGhpcy5faXRlbXMubGVuZ3RoID4gMCkge1xuICAgICAgYXdhaXQgbmV3IFByb21pc2UoKHJlcywgcmVqKSAgPT4gdGhpcy5fY2xvc2VXYWl0aW5nTGlzdC5wdXNoKHsgcmVzLCByZWogfSkpICBcbiAgICB9XG5cbiAgICAvLyByZWxlYXNlIGFsbCByZW1haW5pbmcgd2FpdGluZyBkZXF1ZXVlc1xuICAgIHRoaXMuX2RlcXVldWVXYWl0aW5nTGlzdC5mb3JFYWNoKGNicyA9PiBjYnMucmVqKG5ldyBRdWV1ZUNsb3NlZEVycm9yKHRoaXMubmFtZSkpKVxuICB9XG5cbiAgYXN5bmMgZW5xdWV1ZVJhbmdlIChuZXdJdGVtczogQXJyYXk8VD4pIHtcbiAgICBmb3IgKGNvbnN0IG5ld0l0ZW0gb2YgbmV3SXRlbXMpIHtcbiAgICAgIGF3YWl0IHRoaXMuZW5xdWV1ZShuZXdJdGVtKVxuICAgIH1cbiAgfVxuXG4gIGFzeW5jIGRlcXVldWVSYW5nZShjb3VudDogbnVtYmVyKTogUHJvbWlzZTxBcnJheTxUPj4ge1xuICAgIGNvbnN0IHJlc3VsdHMgPSBbXVxuICAgIHdoaWxlIChyZXN1bHRzLmxlbmd0aCA8IGNvdW50KSB7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCBpdGVtID0gYXdhaXQgdGhpcy5kZXF1ZXVlKClcbiAgICAgICAgcmVzdWx0cy5wdXNoKGl0ZW0pXG4gICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgaWYgKGVyciBpbnN0YW5jZW9mIFF1ZXVlQ2xvc2VkRXJyb3IpXG4gICAgICAgICAgYnJlYWtcbiAgICAgICAgdGhyb3cgZXJyXG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiByZXN1bHRzXG4gIH1cblxuICBnZXRMZW5ndGggPSAoKTogbnVtYmVyID0+IHtcbiAgICByZXR1cm4gdGhpcy5faXRlbXMubGVuZ3RoXG4gIH1cbn1cbiJdfQ==
\No newline at end of file