UNPKG

22.1 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.default = void 0;
7
8var _events = _interopRequireDefault(require("events"));
9
10var _autoBind = _interopRequireDefault(require("auto-bind"));
11
12var _AsyncQueue = _interopRequireWildcard(require("./AsyncQueue"));
13
14var _asyncSyncUtils = require("./asyncSyncUtils");
15
16var _errorUtils = require("./errorUtils");
17
18function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }
19
20function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
21
22function _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; }
23
24/**
25 * A thread-pool abstraction for ES6 async operations",
26 *
27 * @export
28 * @class ThreadPool
29 * @extends {EventEmitter}
30 */
31class ThreadPool extends _events.default {
32 static async run(options) {
33 options.errorHandler = options.errorHandler || (err => {
34 throw err;
35 });
36
37 const tp = new ThreadPool(options);
38
39 if (options.items) {
40 await tp.queueItems(options.items);
41 }
42
43 return await tp.runAllQueued();
44 }
45
46 static async all(items, task, threads) {
47 const tp = new ThreadPool({
48 task: task,
49 threads: threads,
50 items: items
51 });
52
53 if (items) {
54 await tp.queueItems(items);
55 }
56
57 return await tp.runAllQueued();
58 }
59 /**
60 * Creates an instance of ThreadPool
61 */
62
63
64 constructor(options) {
65 super();
66
67 _defineProperty(this, "queuedCount", 0);
68
69 _defineProperty(this, "startedCount", 0);
70
71 _defineProperty(this, "endedCount", 0);
72
73 _defineProperty(this, "_options", void 0);
74
75 _defineProperty(this, "_errorHandler", void 0);
76
77 _defineProperty(this, "_uncaughtErrors", []);
78
79 _defineProperty(this, "_closed", false);
80
81 _defineProperty(this, "_queuedTasks", void 0);
82
83 _defineProperty(this, "_threadsSemaphore", void 0);
84
85 _defineProperty(this, "_completeEvent", void 0);
86
87 _defineProperty(this, "_allTasksCompleteOrSomeFailedEvent", void 0);
88
89 _defineProperty(this, "_res", []);
90
91 this._options = options;
92 this._options.threads = this._options.threads || Infinity;
93
94 this._errorHandler = this._options.errorHandler || (err => {
95 throw err;
96 }); // eslint-disable-line no-console
97
98
99 this._queuedTasks = new _AsyncQueue.default({
100 name: options.name,
101 maxSize: options.queueMaxSize
102 });
103 this._threadsSemaphore = new _asyncSyncUtils.Semaphore(this._options.threads);
104 this._completeEvent = new _asyncSyncUtils.OneTimeBroadcastEvent(false);
105 this._allTasksCompleteOrSomeFailedEvent = new _asyncSyncUtils.OneTimeBroadcastEvent(false);
106 (0, _autoBind.default)(this);
107 }
108 /**
109 * Queues an itme from the ThreadPool
110 */
111
112
113 async queueItem(item) {
114 if (this._closed) throw new Error(`Trying to queue a job to a closed ThreadPool`);
115 const index = this.queuedCount++;
116 await this._queuedTasks.enqueue({
117 func: async () => this._res[index] = await this._options.task(item),
118 index: index
119 });
120 }
121 /**
122 * Queues an itme from the ThreadPool
123 */
124
125
126 async queueItems(queueItem) {
127 for (const item of queueItem) {
128 await this.queueItem(item);
129 }
130 }
131 /**
132 * Starts executing all queued tasks
133 *
134 * This function should be awaited - it will return after the ThreadPool has been closed and all it's tasks completed, or after a task threw an error.
135 */
136
137
138 async run() {
139 try {
140 while (true) {
141 // wait for an available task
142 // TODO: also wait for errors here?
143 let task;
144
145 try {
146 task = await this._queuedTasks.dequeue();
147 } catch (err) {
148 if (err instanceof _AsyncQueue.QueueClosedError) break;
149 throw err;
150 } // wait for an available 'thread'
151
152
153 await this._threadsSemaphore.enter();
154
155 if (this._uncaughtErrors.length) {
156 break;
157 }
158
159 this._allTasksCompleteOrSomeFailedEvent.reset(); // NOTE: no await
160
161
162 this._runTask(task);
163 } // wait for completion
164
165
166 if (this.startedCount > 0) {
167 await this._allTasksCompleteOrSomeFailedEvent.wait();
168 }
169
170 this._throwUncaughtErrors();
171 } finally {
172 this._completeEvent.signal();
173 }
174 }
175 /**
176 * Starts executing all queued tasks
177 *
178 * This function should not be awaited - it will return immediatly
179 */
180
181
182 startRun() {
183 (async () => {
184 try {
185 await this.run();
186 } catch (err) {} // eslint-disable-line no-empty
187
188 })();
189 }
190 /**
191 * Closes the ThreadPool for further task queueing, the ThreadPool's completion can be awaited afte'r it's called
192 */
193
194
195 close() {
196 this._closed = true;
197
198 this._queuedTasks.close(); // NOTE: NO AWAIT
199 // TODO: await completion
200
201 }
202 /**
203 * Closes the ThreadPool, runs it's tasks and awaits their completion
204 */
205
206
207 async runAllQueued() {
208 this.close();
209 await this.run();
210 return this._res;
211 }
212 /**
213 * Awaits the closing and completion of all ThreadPool tasks
214 */
215
216
217 async waitComplete() {
218 await this._completeEvent.wait();
219
220 this._throwUncaughtErrors();
221
222 return this._res;
223 }
224 /**
225 * Closes the ThreadPool and awaits the running and completion of all ThreadPool tasks
226 */
227
228
229 async closeAndWaitComplete() {
230 this.close();
231 return await this.waitComplete();
232 }
233 /****************** privates ******************/
234
235
236 _throwUncaughtErrors() {
237 if (this._uncaughtErrors.length > 0) {
238 throw new _errorUtils.ExtendedError(`Errors were thrown during execution of ThreadPool`, {
239 threadPoolName: this._options.name,
240 errorCount: this._uncaughtErrors.length,
241 errorMessages: this._uncaughtErrors.map(e => e.message),
242 uncaughtErrors: this._uncaughtErrors
243 });
244 }
245 }
246
247 async _runTask(task) {
248 try {
249 this.startedCount++;
250 await task.func();
251 } catch (err) {
252 try {
253 this._errorHandler(err);
254 } catch (err2) {
255 this._uncaughtErrors.push(err2);
256
257 await this._allTasksCompleteOrSomeFailedEvent.signal();
258 }
259 } finally {
260 this.endedCount++; // fire 'progress' event
261
262 this.emit('progress', {
263 endedCount: this.endedCount
264 });
265
266 this._threadsSemaphore.exit();
267
268 if (this._threadsSemaphore.takenCount === 0) {
269 this._allTasksCompleteOrSomeFailedEvent.signal();
270 }
271 }
272 }
273
274}
275
276exports.default = ThreadPool;
277//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9UaHJlYWRQb29sLmpzIl0sIm5hbWVzIjpbIlRocmVhZFBvb2wiLCJFdmVudEVtaXR0ZXIiLCJydW4iLCJvcHRpb25zIiwiZXJyb3JIYW5kbGVyIiwiZXJyIiwidHAiLCJpdGVtcyIsInF1ZXVlSXRlbXMiLCJydW5BbGxRdWV1ZWQiLCJhbGwiLCJ0YXNrIiwidGhyZWFkcyIsImNvbnN0cnVjdG9yIiwiX29wdGlvbnMiLCJJbmZpbml0eSIsIl9lcnJvckhhbmRsZXIiLCJfcXVldWVkVGFza3MiLCJBc3luY1F1ZXVlIiwibmFtZSIsIm1heFNpemUiLCJxdWV1ZU1heFNpemUiLCJfdGhyZWFkc1NlbWFwaG9yZSIsIlNlbWFwaG9yZSIsIl9jb21wbGV0ZUV2ZW50IiwiT25lVGltZUJyb2FkY2FzdEV2ZW50IiwiX2FsbFRhc2tzQ29tcGxldGVPclNvbWVGYWlsZWRFdmVudCIsInF1ZXVlSXRlbSIsIml0ZW0iLCJfY2xvc2VkIiwiRXJyb3IiLCJpbmRleCIsInF1ZXVlZENvdW50IiwiZW5xdWV1ZSIsImZ1bmMiLCJfcmVzIiwiZGVxdWV1ZSIsIlF1ZXVlQ2xvc2VkRXJyb3IiLCJlbnRlciIsIl91bmNhdWdodEVycm9ycyIsImxlbmd0aCIsInJlc2V0IiwiX3J1blRhc2siLCJzdGFydGVkQ291bnQiLCJ3YWl0IiwiX3Rocm93VW5jYXVnaHRFcnJvcnMiLCJzaWduYWwiLCJzdGFydFJ1biIsImNsb3NlIiwid2FpdENvbXBsZXRlIiwiY2xvc2VBbmRXYWl0Q29tcGxldGUiLCJFeHRlbmRlZEVycm9yIiwidGhyZWFkUG9vbE5hbWUiLCJlcnJvckNvdW50IiwiZXJyb3JNZXNzYWdlcyIsIm1hcCIsImUiLCJtZXNzYWdlIiwidW5jYXVnaHRFcnJvcnMiLCJlcnIyIiwicHVzaCIsImVuZGVkQ291bnQiLCJlbWl0IiwiZXhpdCIsInRha2VuQ291bnQiXSwibWFwcGluZ3MiOiI7Ozs7Ozs7QUFFQTs7QUFDQTs7QUFFQTs7QUFDQTs7QUFDQTs7Ozs7Ozs7QUFpQkE7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R0FBbkI7QUFDRCxPQUZELENBRUUsT0FBT3NELElBQVAsRUFBYTtBQUNiLGFBQUtwQixlQUFMLENBQXFCcUIsSUFBckIsQ0FBMEJELElBQTFCOztBQUNBLGNBQU0sS0FBS2pDLGtDQUFMLENBQXdDb0IsTUFBeEMsRUFBTjtBQUNEO0FBQ0YsS0FWRCxTQVVVO0FBQ1IsV0FBS2UsVUFBTCxHQURRLENBRVI7O0FBQ0EsV0FBS0MsSUFBTCxDQUFVLFVBQVYsRUFBc0I7QUFBRUQsUUFBQUEsVUFBVSxFQUFFLEtBQUtBO0FBQW5CLE9BQXRCOztBQUNBLFdBQUt2QyxpQkFBTCxDQUF1QnlDLElBQXZCOztBQUNBLFVBQUksS0FBS3pDLGlCQUFMLENBQXVCMEMsVUFBdkIsS0FBc0MsQ0FBMUMsRUFBNkM7QUFDM0MsYUFBS3RDLGtDQUFMLENBQXdDb0IsTUFBeEM7QUFDRDtBQUNGO0FBQ0Y7O0FBaE53RCIsInNvdXJjZXNDb250ZW50IjpbIi8vIEBmbG93XG5cbmltcG9ydCBFdmVudEVtaXR0ZXIgZnJvbSAnZXZlbnRzJ1xuaW1wb3J0IGF1dG9CaW5kIGZyb20gJ2F1dG8tYmluZCdcblxuaW1wb3J0IEFzeW5jUXVldWUsIHsgUXVldWVDbG9zZWRFcnJvciB9IGZyb20gJy4vQXN5bmNRdWV1ZSdcbmltcG9ydCB7IE9uZVRpbWVCcm9hZGNhc3RFdmVudCwgU2VtYXBob3JlIH0gZnJvbSAnLi9hc3luY1N5bmNVdGlscydcbmltcG9ydCB7IEV4dGVuZGVkRXJyb3IgfSBmcm9tICcuL2Vycm9yVXRpbHMnXG5cblxudHlwZSBUaHJlYWRQb29sT3B0aW9uczxULCBSPiA9IHtcbiAgbmFtZT86ID9zdHJpbmcsXG4gIHRocmVhZHM/OiA/bnVtYmVyLFxuICBpdGVtcz86ID9BcnJheTxUPixcbiAgdGFzazogKGl0ZW06IFQpID0+IFByb21pc2U8Uj4sXG4gIGVycm9ySGFuZGxlcj86ID8oZXJyOiBFcnJvcikgPT4gdm9pZCwgXG4gIHF1ZXVlTWF4U2l6ZT86ID9udW1iZXIsXG59XG5cbnR5cGUgVGFzazxSPiA9IHsgXG4gIGZ1bmM6ICgpID0+IFByb21pc2U8Uj4sIFxuICBpbmRleDogbnVtYmVyLFxufVxuXG4vKipcbiAqIEEgdGhyZWFkLXBvb2wgYWJzdHJhY3Rpb24gZm9yIEVTNiBhc3luYyBvcGVyYXRpb25zXCIsXG4gKiBcbiAqIEBleHBvcnRcbiAqIEBjbGFzcyBUaHJlYWRQb29sXG4gKiBAZXh0ZW5kcyB7RXZlbnRFbWl0dGVyfVxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBUaHJlYWRQb29sPFQsIFI+IGV4dGVuZHMgRXZlbnRFbWl0dGVyIHtcbiAgXG4gIHF1ZXVlZENvdW50OiBudW1iZXIgPSAwXG4gIHN0YXJ0ZWRDb3VudDogbnVtYmVyID0gMFxuICBlbmRlZENvdW50OiBudW1iZXIgPSAwXG5cbiAgX29wdGlvbnM6IFRocmVhZFBvb2xPcHRpb25zPFQsIFI+XG4gIF9lcnJvckhhbmRsZXI6IChlcnI6IEVycm9yKSA9PiB2b2lkXG4gIF91bmNhdWdodEVycm9yczogQXJyYXk8RXJyb3I+ID0gW11cbiAgX2Nsb3NlZDogYm9vbGVhbiA9IGZhbHNlXG4gIF9xdWV1ZWRUYXNrczogQXN5bmNRdWV1ZTx7IGZ1bmM6ICgpID0+IFByb21pc2U8Uj4sIGluZGV4OiBudW1iZXIgfT5cbiAgX3RocmVhZHNTZW1hcGhvcmU6IFNlbWFwaG9yZVxuICBfY29tcGxldGVFdmVudDogT25lVGltZUJyb2FkY2FzdEV2ZW50XG4gIF9hbGxUYXNrc0NvbXBsZXRlT3JTb21lRmFpbGVkRXZlbnQ6IE9uZVRpbWVCcm9hZGNhc3RFdmVudFxuICBfcmVzOiBBcnJheTxSPiA9IFtdXG5cblxuICBzdGF0aWMgYXN5bmMgcnVuKG9wdGlvbnM6IFRocmVhZFBvb2xPcHRpb25zPFQsIFI+KTogUHJvbWlzZTxBcnJheTxSPj4ge1xuICAgIG9wdGlvbnMuZXJyb3JIYW5kbGVyID0gb3B0aW9ucy5lcnJvckhhbmRsZXIgfHwgKChlcnIpID0+IHsgdGhyb3cgZXJyIH0pXG4gICAgY29uc3QgdHAgPSBuZXcgVGhyZWFkUG9vbChvcHRpb25zKVxuICAgIGlmIChvcHRpb25zLml0ZW1zKSB7XG4gICAgICBhd2FpdCB0cC5xdWV1ZUl0ZW1zKG9wdGlvbnMuaXRlbXMpXG4gICAgfVxuICAgIHJldHVybiBhd2FpdCB0cC5ydW5BbGxRdWV1ZWQoKVxuICB9XG5cbiAgc3RhdGljIGFzeW5jIGFsbChpdGVtczogQXJyYXk8VD4sIHRhc2s6IChpdGVtOiBUKSA9PiBQcm9taXNlPFI+LCB0aHJlYWRzOiA/bnVtYmVyKTogUHJvbWlzZTxBcnJheTxSPj4ge1xuICAgIGNvbnN0IHRwID0gbmV3IFRocmVhZFBvb2woe1xuICAgICAgdGFzazogdGFzayxcbiAgICAgIHRocmVhZHM6IHRocmVhZHMsXG4gICAgICBpdGVtczogaXRlbXMsXG4gICAgfSlcbiAgICBpZiAoaXRlbXMpIHtcbiAgICAgIGF3YWl0IHRwLnF1ZXVlSXRlbXMoaXRlbXMpXG4gICAgfVxuICAgIHJldHVybiBhd2FpdCB0cC5ydW5BbGxRdWV1ZWQoKVxuICB9XG5cblxuICAvKipcbiAgICogQ3JlYXRlcyBhbiBpbnN0YW5jZSBvZiBUaHJlYWRQb29sXG4gICAqL1xuICBjb25zdHJ1Y3RvcihvcHRpb25zOiBUaHJlYWRQb29sT3B0aW9uczxULCBSPikge1xuICAgIHN1cGVyKClcblxuICAgIHRoaXMuX29wdGlvbnMgPSBvcHRpb25zXG4gICAgdGhpcy5fb3B0aW9ucy50aHJlYWRzID0gdGhpcy5fb3B0aW9ucy50aHJlYWRzIHx8IEluZmluaXR5XG5cbiAgICB0aGlzLl9lcnJvckhhbmRsZXIgPSB0aGlzLl9vcHRpb25zLmVycm9ySGFuZGxlciB8fCAoKGVycikgPT4geyB0aHJvdyBlcnIgfSkgLy8gZXNsaW50LWRpc2FibGUtbGluZSBuby1jb25zb2xlXG5cbiAgICB0aGlzLl9xdWV1ZWRUYXNrcyA9IG5ldyBBc3luY1F1ZXVlKHsgXG4gICAgICBuYW1lOiBvcHRpb25zLm5hbWUsXG4gICAgICBtYXhTaXplOiBvcHRpb25zLnF1ZXVlTWF4U2l6ZSxcbiAgICB9KVxuICAgIHRoaXMuX3RocmVhZHNTZW1hcGhvcmUgPSBuZXcgU2VtYXBob3JlKHRoaXMuX29wdGlvbnMudGhyZWFkcylcbiAgICB0aGlzLl9jb21wbGV0ZUV2ZW50ID0gbmV3IE9uZVRpbWVCcm9hZGNhc3RFdmVudChmYWxzZSlcbiAgICB0aGlzLl9hbGxUYXNrc0NvbXBsZXRlT3JTb21lRmFpbGVkRXZlbnQgPSBuZXcgT25lVGltZUJyb2FkY2FzdEV2ZW50KGZhbHNlKVxuXG4gICAgYXV0b0JpbmQodGhpcylcbiAgfVxuXG4gIC8qKlxuICAgKiBRdWV1ZXMgYW4gaXRtZSBmcm9tIHRoZSBUaHJlYWRQb29sXG4gICAqL1xuICBhc3luYyBxdWV1ZUl0ZW0oaXRlbTogVCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICh0aGlzLl9jbG9zZWQpXG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYFRyeWluZyB0byBxdWV1ZSBhIGpvYiB0byBhIGNsb3NlZCBUaHJlYWRQb29sYClcblxuICAgIGNvbnN0IGluZGV4ID0gdGhpcy5xdWV1ZWRDb3VudCsrICAgXG4gICAgYXdhaXQgdGhpcy5fcXVldWVkVGFza3MuZW5xdWV1ZSh7IFxuICAgICAgZnVuYzogYXN5bmMgKCkgPT4gdGhpcy5fcmVzW2luZGV4XSA9IGF3YWl0IHRoaXMuX29wdGlvbnMudGFzayhpdGVtKSwgXG4gICAgICBpbmRleDogaW5kZXgsXG4gICAgfSlcbiAgfVxuXG4gIC8qKlxuICAgKiBRdWV1ZXMgYW4gaXRtZSBmcm9tIHRoZSBUaHJlYWRQb29sXG4gICAqL1xuICBhc3luYyBxdWV1ZUl0ZW1zKHF1ZXVlSXRlbTogQXJyYXk8VD4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBmb3IgKGNvbnN0IGl0ZW0gb2YgcXVldWVJdGVtKSB7XG4gICAgICBhd2FpdCB0aGlzLnF1ZXVlSXRlbShpdGVtKVxuICAgIH1cbiAgfVxuICBcbiAgLyoqXG4gICAqIFN0YXJ0cyBleGVjdXRpbmcgYWxsIHF1ZXVlZCB0YXNrc1xuICAgKiBcbiAgICogVGhpcyBmdW5jdGlvbiBzaG91bGQgYmUgYXdhaXRlZCAtIGl0IHdpbGwgcmV0dXJuIGFmdGVyIHRoZSBUaHJlYWRQb29sIGhhcyBiZWVuIGNsb3NlZCBhbmQgYWxsIGl0J3MgdGFza3MgY29tcGxldGVkLCBvciBhZnRlciBhIHRhc2sgdGhyZXcgYW4gZXJyb3IuXG4gICAqL1xuICBhc3luYyBydW4oKSB7XG4gICAgdHJ5IHtcbiAgICAgIHdoaWxlICh0cnVlKSB7XG5cbiAgICAgICAgLy8gd2FpdCBmb3IgYW4gYXZhaWxhYmxlIHRhc2tcbiAgICAgICAgLy8gVE9ETzogYWxzbyB3YWl0IGZvciBlcnJvcnMgaGVyZT9cbiAgICAgICAgbGV0IHRhc2tcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICB0YXNrID0gYXdhaXQgdGhpcy5fcXVldWVkVGFza3MuZGVxdWV1ZSgpXG4gICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgIGlmIChlcnIgaW5zdGFuY2VvZiBRdWV1ZUNsb3NlZEVycm9yKVxuICAgICAgICAgICAgYnJlYWtcbiAgICAgICAgICB0aHJvdyBlcnJcbiAgICAgICAgfVxuICBcbiAgICAgICAgLy8gd2FpdCBmb3IgYW4gYXZhaWxhYmxlICd0aHJlYWQnXG4gICAgICAgIGF3YWl0IHRoaXMuX3RocmVhZHNTZW1hcGhvcmUuZW50ZXIoKVxuICAgICAgICBpZiAodGhpcy5fdW5jYXVnaHRFcnJvcnMubGVuZ3RoKSB7XG4gICAgICAgICAgYnJlYWtcbiAgICAgICAgfVxuICBcbiAgICAgICAgdGhpcy5fYWxsVGFza3NDb21wbGV0ZU9yU29tZUZhaWxlZEV2ZW50LnJlc2V0KClcbiAgICAgICAgXG4gICAgICAgIC8vIE5PVEU6IG5vIGF3YWl0XG4gICAgICAgIHRoaXMuX3J1blRhc2sodGFzaylcbiAgICAgIH1cbiAgXG4gICAgICAvLyB3YWl0IGZvciBjb21wbGV0aW9uXG4gICAgICBpZiAodGhpcy5zdGFydGVkQ291bnQgPiAwKSB7XG4gICAgICAgIGF3YWl0IHRoaXMuX2FsbFRhc2tzQ29tcGxldGVPclNvbWVGYWlsZWRFdmVudC53YWl0KClcbiAgICAgIH1cbiAgXG4gICAgICB0aGlzLl90aHJvd1VuY2F1Z2h0RXJyb3JzKClcbiAgICB9IGZpbmFsbHkge1xuICAgICAgdGhpcy5fY29tcGxldGVFdmVudC5zaWduYWwoKVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBTdGFydHMgZXhlY3V0aW5nIGFsbCBxdWV1ZWQgdGFza3NcbiAgICogXG4gICAqIFRoaXMgZnVuY3Rpb24gc2hvdWxkIG5vdCBiZSBhd2FpdGVkIC0gaXQgd2lsbCByZXR1cm4gaW1tZWRpYXRseVxuICAgKi9cbiAgc3RhcnRSdW4oKSB7XG4gICAgKGFzeW5jICgpID0+IHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IHRoaXMucnVuKClcbiAgICAgIH0gY2F0Y2ggKGVycikge30gLy8gZXNsaW50LWRpc2FibGUtbGluZSBuby1lbXB0eVxuICAgIH0pKClcbiAgfVxuXG4gIC8qKlxuICAgKiBDbG9zZXMgdGhlIFRocmVhZFBvb2wgZm9yIGZ1cnRoZXIgdGFzayBxdWV1ZWluZywgdGhlIFRocmVhZFBvb2wncyBjb21wbGV0aW9uIGNhbiBiZSBhd2FpdGVkIGFmdGUnciBpdCdzIGNhbGxlZFxuICAgKi9cbiAgY2xvc2UoKSB7XG4gICAgdGhpcy5fY2xvc2VkID0gdHJ1ZVxuICAgIHRoaXMuX3F1ZXVlZFRhc2tzLmNsb3NlKCkgLy8gTk9URTogTk8gQVdBSVRcbiAgICAvLyBUT0RPOiBhd2FpdCBjb21wbGV0aW9uXG4gIH1cblxuICAvKipcbiAgICogQ2xvc2VzIHRoZSBUaHJlYWRQb29sLCBydW5zIGl0J3MgdGFza3MgYW5kIGF3YWl0cyB0aGVpciBjb21wbGV0aW9uXG4gICAqL1xuICBhc3luYyBydW5BbGxRdWV1ZWQoKTogUHJvbWlzZTxBcnJheTxSPj4ge1xuICAgIHRoaXMuY2xvc2UoKVxuICAgIGF3YWl0IHRoaXMucnVuKClcbiAgICByZXR1cm4gdGhpcy5fcmVzXG4gIH1cblxuICAvKipcbiAgICogQXdhaXRzIHRoZSBjbG9zaW5nIGFuZCBjb21wbGV0aW9uIG9mIGFsbCBUaHJlYWRQb29sIHRhc2tzXG4gICAqL1xuICBhc3luYyB3YWl0Q29tcGxldGUoKTogUHJvbWlzZTxBcnJheTxSPj4ge1xuICAgIGF3YWl0IHRoaXMuX2NvbXBsZXRlRXZlbnQud2FpdCgpXG4gICAgdGhpcy5fdGhyb3dVbmNhdWdodEVycm9ycygpXG4gICAgcmV0dXJuIHRoaXMuX3Jlc1xuICB9XG5cbiAgLyoqXG4gICAqIENsb3NlcyB0aGUgVGhyZWFkUG9vbCBhbmQgYXdhaXRzIHRoZSBydW5uaW5nIGFuZCBjb21wbGV0aW9uIG9mIGFsbCBUaHJlYWRQb29sIHRhc2tzXG4gICAqL1xuICBhc3luYyBjbG9zZUFuZFdhaXRDb21wbGV0ZSgpOiBQcm9taXNlPEFycmF5PFI+PiB7XG4gICAgdGhpcy5jbG9zZSgpXG4gICAgcmV0dXJuIGF3YWl0IHRoaXMud2FpdENvbXBsZXRlKClcbiAgfVxuXG4gIC8qKioqKioqKioqKioqKioqKiogcHJpdmF0ZXMgKioqKioqKioqKioqKioqKioqL1xuXG4gIF90aHJvd1VuY2F1Z2h0RXJyb3JzKCkgeyAgIFxuICAgIGlmICh0aGlzLl91bmNhdWdodEVycm9ycy5sZW5ndGggPiAwKSB7XG4gICAgICB0aHJvdyBuZXcgRXh0ZW5kZWRFcnJvcihgRXJyb3JzIHdlcmUgdGhyb3duIGR1cmluZyBleGVjdXRpb24gb2YgVGhyZWFkUG9vbGAsIHtcbiAgICAgICAgdGhyZWFkUG9vbE5hbWU6IHRoaXMuX29wdGlvbnMubmFtZSxcbiAgICAgICAgZXJyb3JDb3VudDogdGhpcy5fdW5jYXVnaHRFcnJvcnMubGVuZ3RoLFxuICAgICAgICBlcnJvck1lc3NhZ2VzOiB0aGlzLl91bmNhdWdodEVycm9ycy5tYXAoZSA9PiBlLm1lc3NhZ2UpLFxuICAgICAgICB1bmNhdWdodEVycm9yczogdGhpcy5fdW5jYXVnaHRFcnJvcnMsXG4gICAgICB9KVxuICAgIH1cbiAgfVxuXG4gIGFzeW5jIF9ydW5UYXNrKHRhc2s6IFRhc2s8Uj4pIHtcbiAgICB0cnkge1xuICAgICAgdGhpcy5zdGFydGVkQ291bnQrK1xuICAgICAgYXdhaXQgdGFzay5mdW5jKClcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIHRoaXMuX2Vycm9ySGFuZGxlcihlcnIpXG4gICAgICB9IGNhdGNoIChlcnIyKSB7XG4gICAgICAgIHRoaXMuX3VuY2F1Z2h0RXJyb3JzLnB1c2goZXJyMilcbiAgICAgICAgYXdhaXQgdGhpcy5fYWxsVGFza3NDb21wbGV0ZU9yU29tZUZhaWxlZEV2ZW50LnNpZ25hbCgpXG4gICAgICB9XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIHRoaXMuZW5kZWRDb3VudCsrICAgICAgICAgIFxuICAgICAgLy8gZmlyZSAncHJvZ3Jlc3MnIGV2ZW50XG4gICAgICB0aGlzLmVtaXQoJ3Byb2dyZXNzJywgeyBlbmRlZENvdW50OiB0aGlzLmVuZGVkQ291bnQgfSlcbiAgICAgIHRoaXMuX3RocmVhZHNTZW1hcGhvcmUuZXhpdCgpXG4gICAgICBpZiAodGhpcy5fdGhyZWFkc1NlbWFwaG9yZS50YWtlbkNvdW50ID09PSAwKSB7XG4gICAgICAgIHRoaXMuX2FsbFRhc2tzQ29tcGxldGVPclNvbWVGYWlsZWRFdmVudC5zaWduYWwoKVxuICAgICAgfVxuICAgIH1cbiAgfVxufVxuIl19
\No newline at end of file