UNPKG

39.4 kBJavaScriptView Raw
1'use strict';
2
3var _regenerator = require('babel-runtime/regenerator');
4
5var _regenerator2 = _interopRequireDefault(_regenerator);
6
7var _getIterator2 = require('babel-runtime/core-js/get-iterator');
8
9var _getIterator3 = _interopRequireDefault(_getIterator2);
10
11var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
12
13var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
14
15var _createClass2 = require('babel-runtime/helpers/createClass');
16
17var _createClass3 = _interopRequireDefault(_createClass2);
18
19function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
20
21var ChatServiceError = require('./ChatServiceError');
22var Promise = require('bluebird');
23var _ = require('lodash');
24
25var _require = require('es6-mixin');
26
27var mixin = _require.mixin;
28
29var _require2 = require('./utils');
30
31var asyncLimit = _require2.asyncLimit;
32var run = _require2.run;
33
34var RoomPermissions = function () {
35 function RoomPermissions(roomName, roomState, emitFailure) {
36 (0, _classCallCheck3.default)(this, RoomPermissions);
37
38 this.roomName = roomName;
39 this.roomState = roomState;
40 this.emitFailure = emitFailure;
41 }
42
43 (0, _createClass3.default)(RoomPermissions, [{
44 key: 'consistencyFailure',
45 value: function consistencyFailure(error, operationInfo) {
46 operationInfo.roomName = this.roomName;
47 operationInfo.opType = 'roomUserlist';
48 this.emitFailure('storeConsistencyFailure', error, operationInfo);
49 }
50 }, {
51 key: 'isAdmin',
52 value: function isAdmin(userName) {
53 var _this = this;
54
55 return this.roomState.ownerGet().then(function (owner) {
56 if (owner === userName) {
57 return true;
58 }
59 return _this.roomState.hasInList('adminlist', userName);
60 });
61 }
62 }, {
63 key: 'hasRemoveChangedCurrentAccess',
64 value: function hasRemoveChangedCurrentAccess(userName, listName) {
65 var _this2 = this;
66
67 return this.roomState.hasInList('userlist', userName).then(function (hasUser) {
68 if (!hasUser) {
69 return false;
70 }
71 return _this2.isAdmin(userName).then(function (admin) {
72 if (admin || listName !== 'whitelist') {
73 return false;
74 }
75 return _this2.roomState.whitelistOnlyGet();
76 });
77 }).catch(function (e) {
78 return _this2.consistencyFailure(e, { userName: userName });
79 });
80 }
81 }, {
82 key: 'hasAddChangedCurrentAccess',
83 value: function hasAddChangedCurrentAccess(userName, listName) {
84 var _this3 = this;
85
86 return this.roomState.hasInList('userlist', userName).then(function (hasUser) {
87 if (!hasUser) {
88 return false;
89 }
90 return _this3.isAdmin(userName).then(function (admin) {
91 return !(admin || listName !== 'blacklist');
92 });
93 }).catch(function (e) {
94 return _this3.consistencyFailure(e, { userName: userName });
95 });
96 }
97 }, {
98 key: 'getModeChangedCurrentAccess',
99 value: function getModeChangedCurrentAccess(value) {
100 if (!value) {
101 return [];
102 } else {
103 return this.roomState.getCommonUsers();
104 }
105 }
106 }, {
107 key: 'checkListChanges',
108 value: function checkListChanges(author, listName, values, bypassPermissions) {
109 var _this4 = this;
110
111 if (listName === 'userlist') {
112 return Promise.reject(new ChatServiceError('notAllowed'));
113 }
114 if (bypassPermissions) {
115 return Promise.resolve();
116 }
117 return this.roomState.ownerGet().then(function (owner) {
118 if (author === owner) {
119 return Promise.resolve();
120 }
121 if (listName === 'adminlist') {
122 return Promise.reject(new ChatServiceError('notAllowed'));
123 }
124 return _this4.roomState.hasInList('adminlist', author).then(function (admin) {
125 if (!admin) {
126 return Promise.reject(new ChatServiceError('notAllowed'));
127 }
128 var _iteratorNormalCompletion = true;
129 var _didIteratorError = false;
130 var _iteratorError = undefined;
131
132 try {
133 for (var _iterator = (0, _getIterator3.default)(values), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
134 var name = _step.value;
135
136 if (name !== owner) {
137 continue;
138 }
139 return Promise.reject(new ChatServiceError('notAllowed'));
140 }
141 } catch (err) {
142 _didIteratorError = true;
143 _iteratorError = err;
144 } finally {
145 try {
146 if (!_iteratorNormalCompletion && _iterator.return) {
147 _iterator.return();
148 }
149 } finally {
150 if (_didIteratorError) {
151 throw _iteratorError;
152 }
153 }
154 }
155
156 return Promise.resolve();
157 });
158 });
159 }
160 }, {
161 key: 'checkModeChange',
162 value: function checkModeChange(author, value, bypassPermissions) {
163 return this.isAdmin(author).then(function (admin) {
164 if (admin || bypassPermissions) {
165 return Promise.resolve();
166 }
167 return Promise.reject(new ChatServiceError('notAllowed'));
168 });
169 }
170 }, {
171 key: 'checkAcess',
172 value: function checkAcess(userName) {
173 return run(this, _regenerator2.default.mark(function _callee() {
174 var admin, blacklisted, whitelistOnly, whitelisted;
175 return _regenerator2.default.wrap(function _callee$(_context) {
176 while (1) {
177 switch (_context.prev = _context.next) {
178 case 0:
179 _context.next = 2;
180 return this.isAdmin(userName);
181
182 case 2:
183 admin = _context.sent;
184
185 if (!admin) {
186 _context.next = 5;
187 break;
188 }
189
190 return _context.abrupt('return', Promise.resolve());
191
192 case 5:
193 _context.next = 7;
194 return this.roomState.hasInList('blacklist', userName);
195
196 case 7:
197 blacklisted = _context.sent;
198
199 if (!blacklisted) {
200 _context.next = 10;
201 break;
202 }
203
204 return _context.abrupt('return', Promise.reject(new ChatServiceError('notAllowed')));
205
206 case 10:
207 _context.next = 12;
208 return this.roomState.whitelistOnlyGet();
209
210 case 12:
211 whitelistOnly = _context.sent;
212
213 if (whitelistOnly) {
214 _context.next = 15;
215 break;
216 }
217
218 return _context.abrupt('return', Promise.resolve());
219
220 case 15:
221 _context.next = 17;
222 return this.roomState.hasInList('whitelist', userName);
223
224 case 17:
225 whitelisted = _context.sent;
226
227 if (!whitelisted) {
228 _context.next = 20;
229 break;
230 }
231
232 return _context.abrupt('return', Promise.resolve());
233
234 case 20:
235 return _context.abrupt('return', Promise.reject(new ChatServiceError('notAllowed')));
236
237 case 21:
238 case 'end':
239 return _context.stop();
240 }
241 }
242 }, _callee, this);
243 }));
244 }
245 }, {
246 key: 'checkRead',
247 value: function checkRead(author, bypassPermissions) {
248 if (bypassPermissions) {
249 return Promise.resolve();
250 }
251 return run(this, _regenerator2.default.mark(function _callee2() {
252 var hasAuthor, admin;
253 return _regenerator2.default.wrap(function _callee2$(_context2) {
254 while (1) {
255 switch (_context2.prev = _context2.next) {
256 case 0:
257 _context2.next = 2;
258 return this.roomState.hasInList('userlist', author);
259
260 case 2:
261 hasAuthor = _context2.sent;
262
263 if (!hasAuthor) {
264 _context2.next = 5;
265 break;
266 }
267
268 return _context2.abrupt('return', Promise.resolve());
269
270 case 5:
271 _context2.next = 7;
272 return this.isAdmin(author);
273
274 case 7:
275 admin = _context2.sent;
276
277 if (!admin) {
278 _context2.next = 10;
279 break;
280 }
281
282 return _context2.abrupt('return', Promise.resolve());
283
284 case 10:
285 return _context2.abrupt('return', Promise.reject(new ChatServiceError('notJoined', this.roomName)));
286
287 case 11:
288 case 'end':
289 return _context2.stop();
290 }
291 }
292 }, _callee2, this);
293 }));
294 }
295 }, {
296 key: 'checkIsOwner',
297 value: function checkIsOwner(author, bypassPermissions) {
298 if (bypassPermissions) {
299 return Promise.resolve();
300 }
301 return this.roomState.ownerGet().then(function (owner) {
302 if (owner === author) {
303 return Promise.resolve();
304 }
305 return Promise.reject(new ChatServiceError('notAllowed'));
306 });
307 }
308 }]);
309 return RoomPermissions;
310}();
311
312// Implements room messaging state manipulations with the respect to
313// user's permissions.
314
315
316var Room = function () {
317 function Room(server, roomName) {
318 (0, _classCallCheck3.default)(this, Room);
319
320 this.server = server;
321 this.roomName = roomName;
322 this.listSizeLimit = this.server.roomListSizeLimit;
323 var State = this.server.state.RoomState;
324 this.roomState = new State(this.server, this.roomName);
325 mixin(this, RoomPermissions, this.roomName, this.roomState, this.server.emit.bind(this.server));
326 }
327
328 (0, _createClass3.default)(Room, [{
329 key: 'initState',
330 value: function initState(state) {
331 return this.roomState.initState(state);
332 }
333 }, {
334 key: 'removeState',
335 value: function removeState() {
336 return this.roomState.removeState();
337 }
338 }, {
339 key: 'startRemoving',
340 value: function startRemoving() {
341 return this.roomState.startRemoving();
342 }
343 }, {
344 key: 'getUsers',
345 value: function getUsers() {
346 return this.roomState.getList('userlist');
347 }
348 }, {
349 key: 'leave',
350 value: function leave(author) {
351 var _this5 = this;
352
353 return this.roomState.hasInList('userlist', author).then(function (hasAuthor) {
354 if (!hasAuthor) {
355 return Promise.resolve();
356 }
357 return _this5.roomState.removeFromList('userlist', [author]).then(function () {
358 return _this5.roomState.userSeenUpdate(author);
359 });
360 });
361 }
362 }, {
363 key: 'join',
364 value: function join(author) {
365 var _this6 = this;
366
367 return this.checkAcess(author).then(function () {
368 return _this6.roomState.hasInList('userlist', author);
369 }).then(function (hasAuthor) {
370 if (hasAuthor) {
371 return Promise.resolve();
372 }
373 return _this6.roomState.userSeenUpdate(author).then(function () {
374 return _this6.roomState.addToList('userlist', [author]);
375 });
376 });
377 }
378 }, {
379 key: 'message',
380 value: function message(author, msg, bypassPermissions) {
381 var _this7 = this;
382
383 return Promise.try(function () {
384 if (bypassPermissions) {
385 return Promise.resolve();
386 }
387 return _this7.roomState.hasInList('userlist', author).then(function (hasAuthor) {
388 if (hasAuthor) {
389 return Promise.resolve();
390 }
391 return Promise.reject(new ChatServiceError('notJoined', _this7.roomName));
392 });
393 }).then(function () {
394 return _this7.roomState.messageAdd(msg);
395 });
396 }
397 }, {
398 key: 'getList',
399 value: function getList(author, listName, bypassPermissions) {
400 var _this8 = this;
401
402 return this.checkRead(author, bypassPermissions).then(function () {
403 return _this8.roomState.getList(listName);
404 });
405 }
406 }, {
407 key: 'getRecentMessages',
408 value: function getRecentMessages(author, bypassPermissions) {
409 var _this9 = this;
410
411 return this.checkRead(author, bypassPermissions).then(function () {
412 return _this9.roomState.messagesGetRecent();
413 });
414 }
415 }, {
416 key: 'getHistoryInfo',
417 value: function getHistoryInfo(author, bypassPermissions) {
418 var _this10 = this;
419
420 return this.checkRead(author, bypassPermissions).then(function () {
421 return _this10.roomState.historyInfo();
422 });
423 }
424 }, {
425 key: 'getNotificationsInfo',
426 value: function getNotificationsInfo(author, bypassPermissions) {
427 var _this11 = this;
428
429 return this.checkRead(author, bypassPermissions).then(function () {
430 return Promise.join(_this11.roomState.userlistUpdatesGet(), _this11.roomState.accessListsUpdatesGet(), function (enableUserlistUpdates, enableAccessListsUpdates) {
431 return { enableUserlistUpdates: enableUserlistUpdates, enableAccessListsUpdates: enableAccessListsUpdates };
432 });
433 });
434 }
435 }, {
436 key: 'getMessages',
437 value: function getMessages(author, id, limit, bypassPermissions) {
438 var _this12 = this;
439
440 return this.checkRead(author, bypassPermissions).then(function () {
441 if (!bypassPermissions) {
442 limit = _.min([limit, _this12.server.historyMaxGetMessages]);
443 }
444 return _this12.roomState.messagesGet(id, limit);
445 });
446 }
447 }, {
448 key: 'addToList',
449 value: function addToList(author, listName, values, bypassPermissions) {
450 var _this13 = this;
451
452 return this.checkListChanges(author, listName, values, bypassPermissions).then(function () {
453 return _this13.roomState.addToList(listName, values, _this13.listSizeLimit);
454 }).then(function () {
455 return Promise.filter(values, function (val) {
456 return _this13.hasAddChangedCurrentAccess(val, listName);
457 }, { concurrency: asyncLimit });
458 });
459 }
460 }, {
461 key: 'removeFromList',
462 value: function removeFromList(author, listName, values, bypassPermissions) {
463 var _this14 = this;
464
465 return this.checkListChanges(author, listName, values, bypassPermissions).then(function () {
466 return _this14.roomState.removeFromList(listName, values);
467 }).then(function () {
468 return Promise.filter(values, function (val) {
469 return _this14.hasRemoveChangedCurrentAccess(val, listName);
470 }, { concurrency: asyncLimit });
471 });
472 }
473 }, {
474 key: 'getMode',
475 value: function getMode(author, bypassPermissions) {
476 var _this15 = this;
477
478 return this.checkRead(author, bypassPermissions).then(function () {
479 return _this15.roomState.whitelistOnlyGet();
480 });
481 }
482 }, {
483 key: 'getOwner',
484 value: function getOwner(author, bypassPermissions) {
485 var _this16 = this;
486
487 return this.checkRead(author, bypassPermissions).then(function () {
488 return _this16.roomState.ownerGet();
489 });
490 }
491 }, {
492 key: 'changeMode',
493 value: function changeMode(author, mode, bypassPermissions) {
494 var _this17 = this;
495
496 var whitelistOnly = mode;
497 return this.checkModeChange(author, mode, bypassPermissions).then(function () {
498 return _this17.roomState.whitelistOnlySet(whitelistOnly);
499 }).then(function () {
500 return _this17.getModeChangedCurrentAccess(whitelistOnly);
501 }).then(function (usernames) {
502 return [usernames, whitelistOnly];
503 });
504 }
505 }, {
506 key: 'userSeen',
507 value: function userSeen(author, userName, bypassPermissions) {
508 var _this18 = this;
509
510 return this.checkRead(author, bypassPermissions).then(function () {
511 return _this18.roomState.userSeenGet(userName);
512 });
513 }
514 }]);
515 return Room;
516}();
517
518module.exports = Room;
519//# sourceMappingURL=data:application/json;base64,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LE9BREQsQ0FBUDtBQUVEOzs7K0JBRVcsTSxFQUFRLEksRUFBTSxpQixFQUFtQjtBQUFBOztBQUMzQyxVQUFJLGdCQUFnQixJQUFwQjtBQUNBLGFBQU8sS0FBSyxlQUFMLENBQXFCLE1BQXJCLEVBQTZCLElBQTdCLEVBQW1DLGlCQUFuQyxFQUNKLElBREksQ0FDQztBQUFBLGVBQU0sUUFBSyxTQUFMLENBQWUsZ0JBQWYsQ0FBZ0MsYUFBaEMsQ0FBTjtBQUFBLE9BREQsRUFFSixJQUZJLENBRUM7QUFBQSxlQUFNLFFBQUssMkJBQUwsQ0FBaUMsYUFBakMsQ0FBTjtBQUFBLE9BRkQsRUFHSixJQUhJLENBR0M7QUFBQSxlQUFhLENBQUUsU0FBRixFQUFhLGFBQWIsQ0FBYjtBQUFBLE9BSEQsQ0FBUDtBQUlEOzs7NkJBRVMsTSxFQUFRLFEsRUFBVSxpQixFQUFtQjtBQUFBOztBQUM3QyxhQUFPLEtBQUssU0FBTCxDQUFlLE1BQWYsRUFBdUIsaUJBQXZCLEVBQ0osSUFESSxDQUNDO0FBQUEsZUFBTSxRQUFLLFNBQUwsQ0FBZSxXQUFmLENBQTJCLFFBQTNCLENBQU47QUFBQSxPQURELENBQVA7QUFFRDs7Ozs7QUFJSCxPQUFPLE9BQVAsR0FBaUIsSUFBakIiLCJmaWxlIjoiUm9vbS5qcyIsInNvdXJjZXNDb250ZW50IjpbIid1c2Ugc3RyaWN0J1xuXG5jb25zdCBDaGF0U2VydmljZUVycm9yID0gcmVxdWlyZSgnLi9DaGF0U2VydmljZUVycm9yJylcbmNvbnN0IFByb21pc2UgPSByZXF1aXJlKCdibHVlYmlyZCcpXG5jb25zdCBfID0gcmVxdWlyZSgnbG9kYXNoJylcbmNvbnN0IHsgbWl4aW4gfSA9IHJlcXVpcmUoJ2VzNi1taXhpbicpXG5jb25zdCB7IGFzeW5jTGltaXQsIHJ1biB9ID0gcmVxdWlyZSgnLi91dGlscycpXG5cbmNsYXNzIFJvb21QZXJtaXNzaW9ucyB7XG5cbiAgY29uc3RydWN0b3IgKHJvb21OYW1lLCByb29tU3RhdGUsIGVtaXRGYWlsdXJlKSB7XG4gICAgdGhpcy5yb29tTmFtZSA9IHJvb21OYW1lXG4gICAgdGhpcy5yb29tU3RhdGUgPSByb29tU3RhdGVcbiAgICB0aGlzLmVtaXRGYWlsdXJlID0gZW1pdEZhaWx1cmVcbiAgfVxuXG4gIGNvbnNpc3RlbmN5RmFpbHVyZSAoZXJyb3IsIG9wZXJhdGlvbkluZm8pIHtcbiAgICBvcGVyYXRpb25JbmZvLnJvb21OYW1lID0gdGhpcy5yb29tTmFtZVxuICAgIG9wZXJhdGlvbkluZm8ub3BUeXBlID0gJ3Jvb21Vc2VybGlzdCdcbiAgICB0aGlzLmVtaXRGYWlsdXJlKCdzdG9yZUNvbnNpc3RlbmN5RmFpbHVyZScsIGVycm9yLCBvcGVyYXRpb25JbmZvKVxuICB9XG5cbiAgaXNBZG1pbiAodXNlck5hbWUpIHtcbiAgICByZXR1cm4gdGhpcy5yb29tU3RhdGUub3duZXJHZXQoKS50aGVuKG93bmVyID0+IHtcbiAgICAgIGlmIChvd25lciA9PT0gdXNlck5hbWUpIHsgcmV0dXJuIHRydWUgfVxuICAgICAgcmV0dXJuIHRoaXMucm9vbVN0YXRlLmhhc0luTGlzdCgnYWRtaW5saXN0JywgdXNlck5hbWUpXG4gICAgfSlcbiAgfVxuXG4gIGhhc1JlbW92ZUNoYW5nZWRDdXJyZW50QWNjZXNzICh1c2VyTmFtZSwgbGlzdE5hbWUpIHtcbiAgICByZXR1cm4gdGhpcy5yb29tU3RhdGUuaGFzSW5MaXN0KCd1c2VybGlzdCcsIHVzZXJOYW1lKS50aGVuKGhhc1VzZXIgPT4ge1xuICAgICAgaWYgKCFoYXNVc2VyKSB7IHJldHVybiBmYWxzZSB9XG4gICAgICByZXR1cm4gdGhpcy5pc0FkbWluKHVzZXJOYW1lKS50aGVuKGFkbWluID0+IHtcbiAgICAgICAgaWYgKGFkbWluIHx8IGxpc3ROYW1lICE9PSAnd2hpdGVsaXN0JykgeyByZXR1cm4gZmFsc2UgfVxuICAgICAgICByZXR1cm4gdGhpcy5yb29tU3RhdGUud2hpdGVsaXN0T25seUdldCgpXG4gICAgICB9KVxuICAgIH0pLmNhdGNoKGUgPT4gdGhpcy5jb25zaXN0ZW5jeUZhaWx1cmUoZSwge3VzZXJOYW1lfSkpXG4gIH1cblxuICBoYXNBZGRDaGFuZ2VkQ3VycmVudEFjY2VzcyAodXNlck5hbWUsIGxpc3ROYW1lKSB7XG4gICAgcmV0dXJuIHRoaXMucm9vbVN0YXRlLmhhc0luTGlzdCgndXNlcmxpc3QnLCB1c2VyTmFtZSkudGhlbihoYXNVc2VyID0+IHtcbiAgICAgIGlmICghaGFzVXNlcikgeyByZXR1cm4gZmFsc2UgfVxuICAgICAgcmV0dXJuIHRoaXMuaXNBZG1pbih1c2VyTmFtZSlcbiAgICAgICAgLnRoZW4oYWRtaW4gPT4gIShhZG1pbiB8fCBsaXN0TmFtZSAhPT0gJ2JsYWNrbGlzdCcpKVxuICAgIH0pLmNhdGNoKGUgPT4gdGhpcy5jb25zaXN0ZW5jeUZhaWx1cmUoZSwge3VzZXJOYW1lfSkpXG4gIH1cblxuICBnZXRNb2RlQ2hhbmdlZEN1cnJlbnRBY2Nlc3MgKHZhbHVlKSB7XG4gICAgaWYgKCF2YWx1ZSkge1xuICAgICAgcmV0dXJuIFtdXG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiB0aGlzLnJvb21TdGF0ZS5nZXRDb21tb25Vc2VycygpXG4gICAgfVxuICB9XG5cbiAgY2hlY2tMaXN0Q2hhbmdlcyAoYXV0aG9yLCBsaXN0TmFtZSwgdmFsdWVzLCBieXBhc3NQZXJtaXNzaW9ucykge1xuICAgIGlmIChsaXN0TmFtZSA9PT0gJ3VzZXJsaXN0Jykge1xuICAgICAgcmV0dXJuIFByb21pc2UucmVqZWN0KG5ldyBDaGF0U2VydmljZUVycm9yKCdub3RBbGxvd2VkJykpXG4gICAgfVxuICAgIGlmIChieXBhc3NQZXJtaXNzaW9ucykgeyByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKCkgfVxuICAgIHJldHVybiB0aGlzLnJvb21TdGF0ZS5vd25lckdldCgpLnRoZW4ob3duZXIgPT4ge1xuICAgICAgaWYgKGF1dGhvciA9PT0gb3duZXIpIHsgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpIH1cbiAgICAgIGlmIChsaXN0TmFtZSA9PT0gJ2FkbWlubGlzdCcpIHtcbiAgICAgICAgcmV0dXJuIFByb21pc2UucmVqZWN0KG5ldyBDaGF0U2VydmljZUVycm9yKCdub3RBbGxvd2VkJykpXG4gICAgICB9XG4gICAgICByZXR1cm4gdGhpcy5yb29tU3RhdGUuaGFzSW5MaXN0KCdhZG1pbmxpc3QnLCBhdXRob3IpLnRoZW4oYWRtaW4gPT4ge1xuICAgICAgICBpZiAoIWFkbWluKSB7XG4gICAgICAgICAgcmV0dXJuIFByb21pc2UucmVqZWN0KG5ldyBDaGF0U2VydmljZUVycm9yKCdub3RBbGxvd2VkJykpXG4gICAgICAgIH1cbiAgICAgICAgZm9yIChsZXQgbmFtZSBvZiB2YWx1ZXMpIHtcbiAgICAgICAgICBpZiAobmFtZSAhPT0gb3duZXIpIHsgY29udGludWUgfVxuICAgICAgICAgIHJldHVybiBQcm9taXNlLnJlamVjdChuZXcgQ2hhdFNlcnZpY2VFcnJvcignbm90QWxsb3dlZCcpKVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoKVxuICAgICAgfSlcbiAgICB9KVxuICB9XG5cbiAgY2hlY2tNb2RlQ2hhbmdlIChhdXRob3IsIHZhbHVlLCBieXBhc3NQZXJtaXNzaW9ucykge1xuICAgIHJldHVybiB0aGlzLmlzQWRtaW4oYXV0aG9yKS50aGVuKGFkbWluID0+IHtcbiAgICAgIGlmIChhZG1pbiB8fCBieXBhc3NQZXJtaXNzaW9ucykgeyByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKCkgfVxuICAgICAgcmV0dXJuIFByb21pc2UucmVqZWN0KG5ldyBDaGF0U2VydmljZUVycm9yKCdub3RBbGxvd2VkJykpXG4gICAgfSlcbiAgfVxuXG4gIGNoZWNrQWNlc3MgKHVzZXJOYW1lKSB7XG4gICAgcmV0dXJuIHJ1bih0aGlzLCBmdW5jdGlvbiAqICgpIHtcbiAgICAgIGxldCBhZG1pbiA9IHlpZWxkIHRoaXMuaXNBZG1pbih1c2VyTmFtZSlcbiAgICAgIGlmIChhZG1pbikgeyByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKCkgfVxuICAgICAgbGV0IGJsYWNrbGlzdGVkID0geWllbGQgdGhpcy5yb29tU3RhdGUuaGFzSW5MaXN0KCdibGFja2xpc3QnLCB1c2VyTmFtZSlcbiAgICAgIGlmIChibGFja2xpc3RlZCkge1xuICAgICAgICByZXR1cm4gUHJvbWlzZS5yZWplY3QobmV3IENoYXRTZXJ2aWNlRXJyb3IoJ25vdEFsbG93ZWQnKSlcbiAgICAgIH1cbiAgICAgIGxldCB3aGl0ZWxpc3RPbmx5ID0geWllbGQgdGhpcy5yb29tU3RhdGUud2hpdGVsaXN0T25seUdldCgpXG4gICAgICBpZiAoIXdoaXRlbGlzdE9ubHkpIHsgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpIH1cbiAgICAgIGxldCB3aGl0ZWxpc3RlZCA9IHlpZWxkIHRoaXMucm9vbVN0YXRlLmhhc0luTGlzdCgnd2hpdGVsaXN0JywgdXNlck5hbWUpXG4gICAgICBpZiAod2hpdGVsaXN0ZWQpIHsgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpIH1cbiAgICAgIHJldHVybiBQcm9taXNlLnJlamVjdChuZXcgQ2hhdFNlcnZpY2VFcnJvcignbm90QWxsb3dlZCcpKVxuICAgIH0pXG4gIH1cblxuICBjaGVja1JlYWQgKGF1dGhvciwgYnlwYXNzUGVybWlzc2lvbnMpIHtcbiAgICBpZiAoYnlwYXNzUGVybWlzc2lvbnMpIHsgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpIH1cbiAgICByZXR1cm4gcnVuKHRoaXMsIGZ1bmN0aW9uICogKCkge1xuICAgICAgbGV0IGhhc0F1dGhvciA9IHlpZWxkIHRoaXMucm9vbVN0YXRlLmhhc0luTGlzdCgndXNlcmxpc3QnLCBhdXRob3IpXG4gICAgICBpZiAoaGFzQXV0aG9yKSB7IHJldHVybiBQcm9taXNlLnJlc29sdmUoKSB9XG4gICAgICBsZXQgYWRtaW4gPSB5aWVsZCB0aGlzLmlzQWRtaW4oYXV0aG9yKVxuICAgICAgaWYgKGFkbWluKSB7IHJldHVybiBQcm9taXNlLnJlc29sdmUoKSB9XG4gICAgICByZXR1cm4gUHJvbWlzZS5yZWplY3QobmV3IENoYXRTZXJ2aWNlRXJyb3IoJ25vdEpvaW5lZCcsIHRoaXMucm9vbU5hbWUpKVxuICAgIH0pXG4gIH1cblxuICBjaGVja0lzT3duZXIgKGF1dGhvciwgYnlwYXNzUGVybWlzc2lvbnMpIHtcbiAgICBpZiAoYnlwYXNzUGVybWlzc2lvbnMpIHsgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpIH1cbiAgICByZXR1cm4gdGhpcy5yb29tU3RhdGUub3duZXJHZXQoKS50aGVuKG93bmVyID0+IHtcbiAgICAgIGlmIChvd25lciA9PT0gYXV0aG9yKSB7IHJldHVybiBQcm9taXNlLnJlc29sdmUoKSB9XG4gICAgICByZXR1cm4gUHJvbWlzZS5yZWplY3QobmV3IENoYXRTZXJ2aWNlRXJyb3IoJ25vdEFsbG93ZWQnKSlcbiAgICB9KVxuICB9XG5cbn1cblxuLy8gSW1wbGVtZW50cyByb29tIG1lc3NhZ2luZyBzdGF0ZSBtYW5pcHVsYXRpb25zIHdpdGggdGhlIHJlc3BlY3QgdG9cbi8vIHVzZXIncyBwZXJtaXNzaW9ucy5cbmNsYXNzIFJvb20ge1xuXG4gIGNvbnN0cnVjdG9yIChzZXJ2ZXIsIHJvb21OYW1lKSB7XG4gICAgdGhpcy5zZXJ2ZXIgPSBzZXJ2ZXJcbiAgICB0aGlzLnJvb21OYW1lID0gcm9vbU5hbWVcbiAgICB0aGlzLmxpc3RTaXplTGltaXQgPSB0aGlzLnNlcnZlci5yb29tTGlzdFNpemVMaW1pdFxuICAgIGxldCBTdGF0ZSA9IHRoaXMuc2VydmVyLnN0YXRlLlJvb21TdGF0ZVxuICAgIHRoaXMucm9vbVN0YXRlID0gbmV3IFN0YXRlKHRoaXMuc2VydmVyLCB0aGlzLnJvb21OYW1lKVxuICAgIG1peGluKHRoaXMsIFJvb21QZXJtaXNzaW9ucywgdGhpcy5yb29tTmFtZSxcbiAgICAgICAgICB0aGlzLnJvb21TdGF0ZSwgdGhpcy5zZXJ2ZXIuZW1pdC5iaW5kKHRoaXMuc2VydmVyKSlcbiAgfVxuXG4gIGluaXRTdGF0ZSAoc3RhdGUpIHtcbiAgICByZXR1cm4gdGhpcy5yb29tU3RhdGUuaW5pdFN0YXRlKHN0YXRlKVxuICB9XG5cbiAgcmVtb3ZlU3RhdGUgKCkge1xuICAgIHJldHVybiB0aGlzLnJvb21TdGF0ZS5yZW1vdmVTdGF0ZSgpXG4gIH1cblxuICBzdGFydFJlbW92aW5nICgpIHtcbiAgICByZXR1cm4gdGhpcy5yb29tU3RhdGUuc3RhcnRSZW1vdmluZygpXG4gIH1cblxuICBnZXRVc2VycyAoKSB7XG4gICAgcmV0dXJuIHRoaXMucm9vbVN0YXRlLmdldExpc3QoJ3VzZXJsaXN0JylcbiAgfVxuXG4gIGxlYXZlIChhdXRob3IpIHtcbiAgICByZXR1cm4gdGhpcy5yb29tU3RhdGUuaGFzSW5MaXN0KCd1c2VybGlzdCcsIGF1dGhvcikudGhlbihoYXNBdXRob3IgPT4ge1xuICAgICAgaWYgKCFoYXNBdXRob3IpIHsgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpIH1cbiAgICAgIHJldHVybiB0aGlzLnJvb21TdGF0ZS5yZW1vdmVGcm9tTGlzdCgndXNlcmxpc3QnLCBbYXV0aG9yXSlcbiAgICAgICAgLnRoZW4oKCkgPT4gdGhpcy5yb29tU3RhdGUudXNlclNlZW5VcGRhdGUoYXV0aG9yKSlcbiAgICB9KVxuICB9XG5cbiAgam9pbiAoYXV0aG9yKSB7XG4gICAgcmV0dXJuIHRoaXMuY2hlY2tBY2VzcyhhdXRob3IpXG4gICAgICAudGhlbigoKSA9PiB0aGlzLnJvb21TdGF0ZS5oYXNJbkxpc3QoJ3VzZXJsaXN0JywgYXV0aG9yKSlcbiAgICAgIC50aGVuKGhhc0F1dGhvciA9PiB7XG4gICAgICAgIGlmIChoYXNBdXRob3IpIHsgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpIH1cbiAgICAgICAgcmV0dXJuIHRoaXMucm9vbVN0YXRlLnVzZXJTZWVuVXBkYXRlKGF1dGhvcilcbiAgICAgICAgICAudGhlbigoKSA9PiB0aGlzLnJvb21TdGF0ZS5hZGRUb0xpc3QoJ3VzZXJsaXN0JywgW2F1dGhvcl0pKVxuICAgICAgfSlcbiAgfVxuXG4gIG1lc3NhZ2UgKGF1dGhvciwgbXNnLCBieXBhc3NQZXJtaXNzaW9ucykge1xuICAgIHJldHVybiBQcm9taXNlLnRyeSgoKSA9PiB7XG4gICAgICBpZiAoYnlwYXNzUGVybWlzc2lvbnMpIHsgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpIH1cbiAgICAgIHJldHVybiB0aGlzLnJvb21TdGF0ZS5oYXNJbkxpc3QoJ3VzZXJsaXN0JywgYXV0aG9yKS50aGVuKGhhc0F1dGhvciA9PiB7XG4gICAgICAgIGlmIChoYXNBdXRob3IpIHsgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpIH1cbiAgICAgICAgcmV0dXJuIFByb21pc2UucmVqZWN0KG5ldyBDaGF0U2VydmljZUVycm9yKCdub3RKb2luZWQnLCB0aGlzLnJvb21OYW1lKSlcbiAgICAgIH0pXG4gICAgfSkudGhlbigoKSA9PiB0aGlzLnJvb21TdGF0ZS5tZXNzYWdlQWRkKG1zZykpXG4gIH1cblxuICBnZXRMaXN0IChhdXRob3IsIGxpc3ROYW1lLCBieXBhc3NQZXJtaXNzaW9ucykge1xuICAgIHJldHVybiB0aGlzLmNoZWNrUmVhZChhdXRob3IsIGJ5cGFzc1Blcm1pc3Npb25zKVxuICAgICAgLnRoZW4oKCkgPT4gdGhpcy5yb29tU3RhdGUuZ2V0TGlzdChsaXN0TmFtZSkpXG4gIH1cblxuICBnZXRSZWNlbnRNZXNzYWdlcyAoYXV0aG9yLCBieXBhc3NQZXJtaXNzaW9ucykge1xuICAgIHJldHVybiB0aGlzLmNoZWNrUmVhZChhdXRob3IsIGJ5cGFzc1Blcm1pc3Npb25zKVxuICAgICAgLnRoZW4oKCkgPT4gdGhpcy5yb29tU3RhdGUubWVzc2FnZXNHZXRSZWNlbnQoKSlcbiAgfVxuXG4gIGdldEhpc3RvcnlJbmZvIChhdXRob3IsIGJ5cGFzc1Blcm1pc3Npb25zKSB7XG4gICAgcmV0dXJuIHRoaXMuY2hlY2tSZWFkKGF1dGhvciwgYnlwYXNzUGVybWlzc2lvbnMpXG4gICAgICAudGhlbigoKSA9PiB0aGlzLnJvb21TdGF0ZS5oaXN0b3J5SW5mbygpKVxuICB9XG5cbiAgZ2V0Tm90aWZpY2F0aW9uc0luZm8gKGF1dGhvciwgYnlwYXNzUGVybWlzc2lvbnMpIHtcbiAgICByZXR1cm4gdGhpcy5jaGVja1JlYWQoYXV0aG9yLCBieXBhc3NQZXJtaXNzaW9ucylcbiAgICAgIC50aGVuKCgpID0+IFByb21pc2Uuam9pbihcbiAgICAgICAgdGhpcy5yb29tU3RhdGUudXNlcmxpc3RVcGRhdGVzR2V0KCksXG4gICAgICAgIHRoaXMucm9vbVN0YXRlLmFjY2Vzc0xpc3RzVXBkYXRlc0dldCgpLFxuICAgICAgICAoZW5hYmxlVXNlcmxpc3RVcGRhdGVzLCBlbmFibGVBY2Nlc3NMaXN0c1VwZGF0ZXMpID0+XG4gICAgICAgICAgKHsgZW5hYmxlVXNlcmxpc3RVcGRhdGVzLCBlbmFibGVBY2Nlc3NMaXN0c1VwZGF0ZXMgfSkpKVxuICB9XG5cbiAgZ2V0TWVzc2FnZXMgKGF1dGhvciwgaWQsIGxpbWl0LCBieXBhc3NQZXJtaXNzaW9ucykge1xuICAgIHJldHVybiB0aGlzLmNoZWNrUmVhZChhdXRob3IsIGJ5cGFzc1Blcm1pc3Npb25zKS50aGVuKCgpID0+IHtcbiAgICAgIGlmICghYnlwYXNzUGVybWlzc2lvbnMpIHtcbiAgICAgICAgbGltaXQgPSBfLm1pbihbIGxpbWl0LCB0aGlzLnNlcnZlci5oaXN0b3J5TWF4R2V0TWVzc2FnZXMgXSlcbiAgICAgIH1cbiAgICAgIHJldHVybiB0aGlzLnJvb21TdGF0ZS5tZXNzYWdlc0dldChpZCwgbGltaXQpXG4gICAgfSlcbiAgfVxuXG4gIGFkZFRvTGlzdCAoYXV0aG9yLCBsaXN0TmFtZSwgdmFsdWVzLCBieXBhc3NQZXJtaXNzaW9ucykge1xuICAgIHJldHVybiB0aGlzLmNoZWNrTGlzdENoYW5nZXMoYXV0aG9yLCBsaXN0TmFtZSwgdmFsdWVzLCBieXBhc3NQZXJtaXNzaW9ucylcbiAgICAgIC50aGVuKCgpID0+IHRoaXMucm9vbVN0YXRlLmFkZFRvTGlzdChsaXN0TmFtZSwgdmFsdWVzLCB0aGlzLmxpc3RTaXplTGltaXQpKVxuICAgICAgLnRoZW4oKCkgPT4gUHJvbWlzZS5maWx0ZXIoXG4gICAgICAgIHZhbHVlcyxcbiAgICAgICAgdmFsID0+IHRoaXMuaGFzQWRkQ2hhbmdlZEN1cnJlbnRBY2Nlc3ModmFsLCBsaXN0TmFtZSksXG4gICAgICAgIHsgY29uY3VycmVuY3k6IGFzeW5jTGltaXQgfSkpXG4gIH1cblxuICByZW1vdmVGcm9tTGlzdCAoYXV0aG9yLCBsaXN0TmFtZSwgdmFsdWVzLCBieXBhc3NQZXJtaXNzaW9ucykge1xuICAgIHJldHVybiB0aGlzLmNoZWNrTGlzdENoYW5nZXMoYXV0aG9yLCBsaXN0TmFtZSwgdmFsdWVzLCBieXBhc3NQZXJtaXNzaW9ucylcbiAgICAgIC50aGVuKCgpID0+IHRoaXMucm9vbVN0YXRlLnJlbW92ZUZyb21MaXN0KGxpc3ROYW1lLCB2YWx1ZXMpKVxuICAgICAgLnRoZW4oKCkgPT4gUHJvbWlzZS5maWx0ZXIoXG4gICAgICAgIHZhbHVlcyxcbiAgICAgICAgdmFsID0+IHRoaXMuaGFzUmVtb3ZlQ2hhbmdlZEN1cnJlbnRBY2Nlc3ModmFsLCBsaXN0TmFtZSksXG4gICAgICAgIHsgY29uY3VycmVuY3k6IGFzeW5jTGltaXQgfSkpXG4gIH1cblxuICBnZXRNb2RlIChhdXRob3IsIGJ5cGFzc1Blcm1pc3Npb25zKSB7XG4gICAgcmV0dXJuIHRoaXMuY2hlY2tSZWFkKGF1dGhvciwgYnlwYXNzUGVybWlzc2lvbnMpXG4gICAgICAudGhlbigoKSA9PiB0aGlzLnJvb21TdGF0ZS53aGl0ZWxpc3RPbmx5R2V0KCkpXG4gIH1cblxuICBnZXRPd25lciAoYXV0aG9yLCBieXBhc3NQZXJtaXNzaW9ucykge1xuICAgIHJldHVybiB0aGlzLmNoZWNrUmVhZChhdXRob3IsIGJ5cGFzc1Blcm1pc3Npb25zKVxuICAgICAgLnRoZW4oKCkgPT4gdGhpcy5yb29tU3RhdGUub3duZXJHZXQoKSlcbiAgfVxuXG4gIGNoYW5nZU1vZGUgKGF1dGhvciwgbW9kZSwgYnlwYXNzUGVybWlzc2lvbnMpIHtcbiAgICBsZXQgd2hpdGVsaXN0T25seSA9IG1vZGVcbiAgICByZXR1cm4gdGhpcy5jaGVja01vZGVDaGFuZ2UoYXV0aG9yLCBtb2RlLCBieXBhc3NQZXJtaXNzaW9ucylcbiAgICAgIC50aGVuKCgpID0+IHRoaXMucm9vbVN0YXRlLndoaXRlbGlzdE9ubHlTZXQod2hpdGVsaXN0T25seSkpXG4gICAgICAudGhlbigoKSA9PiB0aGlzLmdldE1vZGVDaGFuZ2VkQ3VycmVudEFjY2Vzcyh3aGl0ZWxpc3RPbmx5KSlcbiAgICAgIC50aGVuKHVzZXJuYW1lcyA9PiBbIHVzZXJuYW1lcywgd2hpdGVsaXN0T25seSBdKVxuICB9XG5cbiAgdXNlclNlZW4gKGF1dGhvciwgdXNlck5hbWUsIGJ5cGFzc1Blcm1pc3Npb25zKSB7XG4gICAgcmV0dXJuIHRoaXMuY2hlY2tSZWFkKGF1dGhvciwgYnlwYXNzUGVybWlzc2lvbnMpXG4gICAgICAudGhlbigoKSA9PiB0aGlzLnJvb21TdGF0ZS51c2VyU2VlbkdldCh1c2VyTmFtZSkpXG4gIH1cblxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IFJvb21cbiJdfQ==
\No newline at end of file