UNPKG

32.7 kBJavaScriptView Raw
1'use strict';
2
3var _slicedToArray2 = require('babel-runtime/helpers/slicedToArray');
4
5var _slicedToArray3 = _interopRequireDefault(_slicedToArray2);
6
7var _regenerator = require('babel-runtime/regenerator');
8
9var _regenerator2 = _interopRequireDefault(_regenerator);
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 Promise = require('bluebird');
22var _ = require('lodash');
23var eventToPromise = require('event-to-promise');
24
25var _require = require('./utils');
26
27var asyncLimit = _require.asyncLimit;
28
29
30var co = Promise.coroutine;
31
32// Associations for user class.
33
34var UserAssociations = function () {
35 function UserAssociations(props) {
36 (0, _classCallCheck3.default)(this, UserAssociations);
37
38 _.defaults(this, props);
39 }
40
41 (0, _createClass3.default)(UserAssociations, [{
42 key: 'userJoinRoomReport',
43 value: function userJoinRoomReport(userName, roomName) {
44 this.transport.emitToChannel(roomName, 'roomUserJoined', roomName, userName);
45 }
46 }, {
47 key: 'userLeftRoomReport',
48 value: function userLeftRoomReport(userName, roomName, enableUserlistUpdates) {
49 if (enableUserlistUpdates) {
50 this.transport.emitToChannel(roomName, 'roomUserLeft', roomName, userName);
51 }
52 }
53 }, {
54 key: 'userRemovedReport',
55 value: function userRemovedReport(userName, roomName, enableUserlistUpdates) {
56 var cn = this.echoChannel;
57 this.transport.emitToChannel(cn, 'roomAccessRemoved', roomName);
58 this.userLeftRoomReport(userName, roomName, enableUserlistUpdates);
59 }
60 }, {
61 key: 'socketJoinEcho',
62 value: function socketJoinEcho(id, roomName, njoined, isLocalCall) {
63 if (isLocalCall) {
64 this.transport.emitToChannel(this.echoChannel, 'roomJoinedEcho', roomName, id, njoined);
65 } else {
66 this.transport.sendToChannel(id, this.echoChannel, 'roomJoinedEcho', roomName, id, njoined);
67 }
68 }
69 }, {
70 key: 'socketLeftEcho',
71 value: function socketLeftEcho(id, roomName, njoined, isLocalCall) {
72 if (isLocalCall) {
73 this.transport.emitToChannel(this.echoChannel, 'roomLeftEcho', roomName, id, njoined);
74 } else {
75 this.transport.sendToChannel(id, this.echoChannel, 'roomLeftEcho', roomName, id, njoined);
76 }
77 }
78 }, {
79 key: 'socketConnectEcho',
80 value: function socketConnectEcho(id, nconnected) {
81 this.transport.sendToChannel(id, this.echoChannel, 'socketConnectEcho', id, nconnected);
82 }
83 }, {
84 key: 'socketDisconnectEcho',
85 value: function socketDisconnectEcho(id, nconnected) {
86 this.transport.sendToChannel(id, this.echoChannel, 'socketDisconnectEcho', id, nconnected);
87 }
88 }, {
89 key: 'leaveChannel',
90 value: function leaveChannel(id, channel) {
91 var _this = this;
92
93 return this.transport.leaveChannel(id, channel).catch(function (e) {
94 var info = { roomName: channel, id: id, opType: 'transportChannel' };
95 return _this.consistencyFailure(e, info);
96 });
97 }
98 }, {
99 key: 'socketLeaveChannels',
100 value: function socketLeaveChannels(id, channels) {
101 var _this2 = this;
102
103 return Promise.map(channels, function (channel) {
104 return _this2.leaveChannel(id, channel);
105 }, { concurrency: asyncLimit });
106 }
107 }, {
108 key: 'leaveChannelMessage',
109 value: function leaveChannelMessage(id, channel) {
110 var bus = this.clusterBus;
111 return Promise.try(function () {
112 bus.emit('roomLeaveSocket', id, channel);
113 return eventToPromise(bus, bus.makeSocketRoomLeftName(id, channel));
114 }).timeout(this.busAckTimeout).catchReturn();
115 }
116 }, {
117 key: 'channelLeaveSockets',
118 value: function channelLeaveSockets(channel, ids) {
119 var _this3 = this;
120
121 return Promise.map(ids, function (id) {
122 return _this3.leaveChannelMessage(id, channel);
123 }, { concurrency: asyncLimit });
124 }
125 }, {
126 key: 'rollbackRoomJoin',
127 value: function rollbackRoomJoin(error, roomName, id) {
128 var _this4 = this;
129
130 return this.userState.removeSocketFromRoom(id, roomName).catch(function (e) {
131 _this4.consistencyFailure(e, { roomName: roomName, opType: 'userRooms' });
132 return [1];
133 }).spread(function (njoined) {
134 if (!njoined) {
135 return _this4.leaveRoom(roomName);
136 } else {
137 return Promise.resolve();
138 }
139 }).thenThrow(error);
140 }
141 }, {
142 key: 'leaveRoom',
143 value: function leaveRoom(roomName) {
144 var _this5 = this;
145
146 return Promise.try(function () {
147 return _this5.state.getRoom(roomName);
148 }).then(function (room) {
149 return room.leave(_this5.userName).catch(function (error) {
150 return _this5.consistencyFailure(error, { roomName: roomName, opType: 'roomUserlist' });
151 });
152 }).catchReturn();
153 }
154 }, {
155 key: 'getNotifySettings',
156 value: function getNotifySettings(roomName) {
157 var _this6 = this;
158
159 return Promise.try(function () {
160 return _this6.state.getRoom(roomName);
161 }).then(function (room) {
162 return room.getNotificationsInfo(null, true);
163 }).catchReturn({});
164 }
165 }, {
166 key: 'joinSocketToRoom',
167 value: function joinSocketToRoom(id, roomName, isLocalCall) {
168 var lock = this.userState.lockToRoom(roomName, this.lockTTL);
169 return Promise.using(lock, co(_regenerator2.default.mark(function _callee() {
170 var _this7 = this;
171
172 var room, enableUserlistUpdates;
173 return _regenerator2.default.wrap(function _callee$(_context) {
174 while (1) {
175 switch (_context.prev = _context.next) {
176 case 0:
177 _context.next = 2;
178 return this.state.getRoom(roomName);
179
180 case 2:
181 room = _context.sent;
182 _context.next = 5;
183 return room.join(this.userName);
184
185 case 5:
186 _context.next = 7;
187 return room.roomState.userlistUpdatesGet();
188
189 case 7:
190 enableUserlistUpdates = _context.sent;
191 return _context.abrupt('return', this.userState.addSocketToRoom(id, roomName).then(function (njoined) {
192 return _this7.transport.joinChannel(id, roomName).then(function () {
193 if (njoined === 1 && enableUserlistUpdates) {
194 _this7.userJoinRoomReport(_this7.userName, roomName);
195 }
196 return _this7.socketJoinEcho(id, roomName, njoined, isLocalCall);
197 }).return(njoined);
198 }).catch(function (e) {
199 return _this7.rollbackRoomJoin(e, roomName, id);
200 }));
201
202 case 9:
203 case 'end':
204 return _context.stop();
205 }
206 }
207 }, _callee, this);
208 })).bind(this));
209 }
210 }, {
211 key: 'leaveSocketFromRoom',
212 value: function leaveSocketFromRoom(id, roomName, isLocalCall) {
213 var lock = this.userState.lockToRoom(roomName, this.lockTTL);
214 return Promise.using(lock, co(_regenerator2.default.mark(function _callee2() {
215 var _ref, _ref2, njoined, hasChanged, _ref3, enableUserlistUpdates;
216
217 return _regenerator2.default.wrap(function _callee2$(_context2) {
218 while (1) {
219 switch (_context2.prev = _context2.next) {
220 case 0:
221 _context2.next = 2;
222 return this.userState.removeSocketFromRoom(id, roomName);
223
224 case 2:
225 _ref = _context2.sent;
226 _ref2 = (0, _slicedToArray3.default)(_ref, 2);
227 njoined = _ref2[0];
228 hasChanged = _ref2[1];
229 _context2.next = 8;
230 return this.leaveChannel(id, roomName);
231
232 case 8:
233 if (!(njoined === 0)) {
234 _context2.next = 11;
235 break;
236 }
237
238 _context2.next = 11;
239 return this.leaveRoom(roomName);
240
241 case 11:
242 if (!hasChanged) {
243 _context2.next = 18;
244 break;
245 }
246
247 _context2.next = 14;
248 return this.getNotifySettings(roomName);
249
250 case 14:
251 _ref3 = _context2.sent;
252 enableUserlistUpdates = _ref3.enableUserlistUpdates;
253
254 this.socketLeftEcho(id, roomName, njoined, isLocalCall);
255 this.userLeftRoomReport(this.userName, roomName, enableUserlistUpdates);
256
257 case 18:
258 return _context2.abrupt('return', Promise.resolve(njoined));
259
260 case 19:
261 case 'end':
262 return _context2.stop();
263 }
264 }
265 }, _callee2, this);
266 })).bind(this));
267 }
268 }, {
269 key: 'removeUserSocket',
270 value: function removeUserSocket(id) {
271 var _this8 = this;
272
273 return this.userState.removeSocket(id).spread(function (roomsRemoved, joinedSockets, nconnected) {
274 roomsRemoved = roomsRemoved || [];
275 joinedSockets = joinedSockets || [];
276 nconnected = nconnected || 0;
277 return _this8.socketLeaveChannels(id, roomsRemoved).then(function () {
278 return Promise.map(roomsRemoved, function (roomName, idx) {
279 var njoined = joinedSockets[idx];
280 _this8.socketLeftEcho(id, roomName, njoined);
281 if (njoined) {
282 return Promise.resolve();
283 }
284 return _this8.leaveRoom(roomName).then(function () {
285 return _this8.getNotifySettings(roomName);
286 }).then(function (_ref4) {
287 var enableUserlistUpdates = _ref4.enableUserlistUpdates;
288 return _this8.userLeftRoomReport(_this8.userName, roomName, enableUserlistUpdates);
289 });
290 }, { concurrency: asyncLimit }).then(function () {
291 return _this8.socketDisconnectEcho(id, nconnected);
292 });
293 });
294 }).then(function () {
295 return _this8.state.removeSocket(id);
296 });
297 }
298 }, {
299 key: 'removeSocketFromServer',
300 value: function removeSocketFromServer(id) {
301 var _this9 = this;
302
303 return this.removeUserSocket(id).catch(function (e) {
304 var info = { id: id, opType: 'userSockets' };
305 return _this9.consistencyFailure(e, info);
306 });
307 }
308 }, {
309 key: 'removeUserSocketsFromRoom',
310 value: function removeUserSocketsFromRoom(roomName) {
311 var _this10 = this;
312
313 return this.userState.removeAllSocketsFromRoom(roomName).catch(function (e) {
314 var info = { roomName: roomName, opType: 'roomUserlist' };
315 return _this10.consistencyFailure(e, info);
316 });
317 }
318 }, {
319 key: 'removeFromRoom',
320 value: function removeFromRoom(roomName) {
321 var lock = this.userState.lockToRoom(roomName, this.lockTTL);
322 return Promise.using(lock, co(_regenerator2.default.mark(function _callee3() {
323 var removedSockets, _ref5, enableUserlistUpdates;
324
325 return _regenerator2.default.wrap(function _callee3$(_context3) {
326 while (1) {
327 switch (_context3.prev = _context3.next) {
328 case 0:
329 _context3.next = 2;
330 return this.removeUserSocketsFromRoom(roomName);
331
332 case 2:
333 removedSockets = _context3.sent;
334
335 removedSockets = removedSockets || [];
336 _context3.next = 6;
337 return this.channelLeaveSockets(roomName, removedSockets);
338
339 case 6:
340 if (!removedSockets.length) {
341 _context3.next = 12;
342 break;
343 }
344
345 _context3.next = 9;
346 return this.getNotifySettings(roomName);
347
348 case 9:
349 _ref5 = _context3.sent;
350 enableUserlistUpdates = _ref5.enableUserlistUpdates;
351
352 this.userRemovedReport(this.userName, roomName, enableUserlistUpdates);
353
354 case 12:
355 return _context3.abrupt('return', this.leaveRoom(roomName));
356
357 case 13:
358 case 'end':
359 return _context3.stop();
360 }
361 }
362 }, _callee3, this);
363 })).bind(this));
364 }
365 }, {
366 key: 'removeRoomUsers',
367 value: function removeRoomUsers(roomName, userNames) {
368 var _this11 = this;
369
370 userNames = userNames || [];
371 return Promise.map(userNames, function (userName) {
372 return _this11.state.getUser(userName).then(function (user) {
373 return user.removeFromRoom(roomName);
374 }).catchReturn();
375 }, { concurrency: asyncLimit });
376 }
377 }]);
378 return UserAssociations;
379}();
380
381module.exports = UserAssociations;
382//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9Vc2VyQXNzb2NpYXRpb25zLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUVBLElBQU0sVUFBVSxRQUFRLFVBQVIsQ0FBaEI7QUFDQSxJQUFNLElBQUksUUFBUSxRQUFSLENBQVY7QUFDQSxJQUFNLGlCQUFpQixRQUFRLGtCQUFSLENBQXZCOztlQUN1QixRQUFRLFNBQVIsQzs7SUFBZixVLFlBQUEsVTs7O0FBRVIsSUFBTSxLQUFLLFFBQVEsU0FBbkI7O0FBRUE7O0lBQ00sZ0I7QUFFSiw0QkFBYSxLQUFiLEVBQW9CO0FBQUE7O0FBQ2xCLE1BQUUsUUFBRixDQUFXLElBQVgsRUFBaUIsS0FBakI7QUFDRDs7Ozt1Q0FFbUIsUSxFQUFVLFEsRUFBVTtBQUN0QyxXQUFLLFNBQUwsQ0FBZSxhQUFmLENBQTZCLFFBQTdCLEVBQXVDLGdCQUF2QyxFQUF5RCxRQUF6RCxFQUFtRSxRQUFuRTtBQUNEOzs7dUNBRW1CLFEsRUFBVSxRLEVBQVUscUIsRUFBdUI7QUFDN0QsVUFBSSxxQkFBSixFQUEyQjtBQUN6QixhQUFLLFNBQUwsQ0FBZSxhQUFmLENBQTZCLFFBQTdCLEVBQXVDLGNBQXZDLEVBQXVELFFBQXZELEVBQWlFLFFBQWpFO0FBQ0Q7QUFDRjs7O3NDQUVrQixRLEVBQVUsUSxFQUFVLHFCLEVBQXVCO0FBQzVELFVBQUksS0FBSyxLQUFLLFdBQWQ7QUFDQSxXQUFLLFNBQUwsQ0FBZSxhQUFmLENBQTZCLEVBQTdCLEVBQWlDLG1CQUFqQyxFQUFzRCxRQUF0RDtBQUNBLFdBQUssa0JBQUwsQ0FBd0IsUUFBeEIsRUFBa0MsUUFBbEMsRUFBNEMscUJBQTVDO0FBQ0Q7OzttQ0FFZSxFLEVBQUksUSxFQUFVLE8sRUFBUyxXLEVBQWE7QUFDbEQsVUFBSSxXQUFKLEVBQWlCO0FBQ2YsYUFBSyxTQUFMLENBQWUsYUFBZixDQUNFLEtBQUssV0FEUCxFQUNvQixnQkFEcEIsRUFDc0MsUUFEdEMsRUFDZ0QsRUFEaEQs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Q29udGVudCI6WyIndXNlIHN0cmljdCdcblxuY29uc3QgUHJvbWlzZSA9IHJlcXVpcmUoJ2JsdWViaXJkJylcbmNvbnN0IF8gPSByZXF1aXJlKCdsb2Rhc2gnKVxuY29uc3QgZXZlbnRUb1Byb21pc2UgPSByZXF1aXJlKCdldmVudC10by1wcm9taXNlJylcbmNvbnN0IHsgYXN5bmNMaW1pdCB9ID0gcmVxdWlyZSgnLi91dGlscycpXG5cbmNvbnN0IGNvID0gUHJvbWlzZS5jb3JvdXRpbmVcblxuLy8gQXNzb2NpYXRpb25zIGZvciB1c2VyIGNsYXNzLlxuY2xhc3MgVXNlckFzc29jaWF0aW9ucyB7XG5cbiAgY29uc3RydWN0b3IgKHByb3BzKSB7XG4gICAgXy5kZWZhdWx0cyh0aGlzLCBwcm9wcylcbiAgfVxuXG4gIHVzZXJKb2luUm9vbVJlcG9ydCAodXNlck5hbWUsIHJvb21OYW1lKSB7XG4gICAgdGhpcy50cmFuc3BvcnQuZW1pdFRvQ2hhbm5lbChyb29tTmFtZSwgJ3Jvb21Vc2VySm9pbmVkJywgcm9vbU5hbWUsIHVzZXJOYW1lKVxuICB9XG5cbiAgdXNlckxlZnRSb29tUmVwb3J0ICh1c2VyTmFtZSwgcm9vbU5hbWUsIGVuYWJsZVVzZXJsaXN0VXBkYXRlcykge1xuICAgIGlmIChlbmFibGVVc2VybGlzdFVwZGF0ZXMpIHtcbiAgICAgIHRoaXMudHJhbnNwb3J0LmVtaXRUb0NoYW5uZWwocm9vbU5hbWUsICdyb29tVXNlckxlZnQnLCByb29tTmFtZSwgdXNlck5hbWUpXG4gICAgfVxuICB9XG5cbiAgdXNlclJlbW92ZWRSZXBvcnQgKHVzZXJOYW1lLCByb29tTmFtZSwgZW5hYmxlVXNlcmxpc3RVcGRhdGVzKSB7XG4gICAgbGV0IGNuID0gdGhpcy5lY2hvQ2hhbm5lbFxuICAgIHRoaXMudHJhbnNwb3J0LmVtaXRUb0NoYW5uZWwoY24sICdyb29tQWNjZXNzUmVtb3ZlZCcsIHJvb21OYW1lKVxuICAgIHRoaXMudXNlckxlZnRSb29tUmVwb3J0KHVzZXJOYW1lLCByb29tTmFtZSwgZW5hYmxlVXNlcmxpc3RVcGRhdGVzKVxuICB9XG5cbiAgc29ja2V0Sm9pbkVjaG8gKGlkLCByb29tTmFtZSwgbmpvaW5lZCwgaXNMb2NhbENhbGwpIHtcbiAgICBpZiAoaXNMb2NhbENhbGwpIHtcbiAgICAgIHRoaXMudHJhbnNwb3J0LmVtaXRUb0NoYW5uZWwoXG4gICAgICAgIHRoaXMuZWNob0NoYW5uZWwsICdyb29tSm9pbmVkRWNobycsIHJvb21OYW1lLCBpZCwgbmpvaW5lZClcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy50cmFuc3BvcnQuc2VuZFRvQ2hhbm5lbChcbiAgICAgICAgaWQsIHRoaXMuZWNob0NoYW5uZWwsICdyb29tSm9pbmVkRWNobycsIHJvb21OYW1lLCBpZCwgbmpvaW5lZClcbiAgICB9XG4gIH1cblxuICBzb2NrZXRMZWZ0RWNobyAoaWQsIHJvb21OYW1lLCBuam9pbmVkLCBpc0xvY2FsQ2FsbCkge1xuICAgIGlmIChpc0xvY2FsQ2FsbCkge1xuICAgICAgdGhpcy50cmFuc3BvcnQuZW1pdFRvQ2hhbm5lbChcbiAgICAgICAgdGhpcy5lY2hvQ2hhbm5lbCwgJ3Jvb21MZWZ0RWNobycsIHJvb21OYW1lLCBpZCwgbmpvaW5lZClcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy50cmFuc3BvcnQuc2VuZFRvQ2hhbm5lbChcbiAgICAgICAgaWQsIHRoaXMuZWNob0NoYW5uZWwsICdyb29tTGVmdEVjaG8nLCByb29tTmFtZSwgaWQsIG5qb2luZWQpXG4gICAgfVxuICB9XG5cbiAgc29ja2V0Q29ubmVjdEVjaG8gKGlkLCBuY29ubmVjdGVkKSB7XG4gICAgdGhpcy50cmFuc3BvcnQuc2VuZFRvQ2hhbm5lbChcbiAgICAgIGlkLCB0aGlzLmVjaG9DaGFubmVsLCAnc29ja2V0Q29ubmVjdEVjaG8nLCBpZCwgbmNvbm5lY3RlZClcbiAgfVxuXG4gIHNvY2tldERpc2Nvbm5lY3RFY2hvIChpZCwgbmNvbm5lY3RlZCkge1xuICAgIHRoaXMudHJhbnNwb3J0LnNlbmRUb0NoYW5uZWwoXG4gICAgICBpZCwgdGhpcy5lY2hvQ2hhbm5lbCwgJ3NvY2tldERpc2Nvbm5lY3RFY2hvJywgaWQsIG5jb25uZWN0ZWQpXG4gIH1cblxuICBsZWF2ZUNoYW5uZWwgKGlkLCBjaGFubmVsKSB7XG4gICAgcmV0dXJuIHRoaXMudHJhbnNwb3J0LmxlYXZlQ2hhbm5lbChpZCwgY2hhbm5lbCkuY2F0Y2goZSA9PiB7XG4gICAgICBsZXQgaW5mbyA9IHsgcm9vbU5hbWU6IGNoYW5uZWwsIGlkLCBvcFR5cGU6ICd0cmFuc3BvcnRDaGFubmVsJyB9XG4gICAgICByZXR1cm4gdGhpcy5jb25zaXN0ZW5jeUZhaWx1cmUoZSwgaW5mbylcbiAgICB9KVxuICB9XG5cbiAgc29ja2V0TGVhdmVDaGFubmVscyAoaWQsIGNoYW5uZWxzKSB7XG4gICAgcmV0dXJuIFByb21pc2UubWFwKFxuICAgICAgY2hhbm5lbHMsXG4gICAgICBjaGFubmVsID0+IHRoaXMubGVhdmVDaGFubmVsKGlkLCBjaGFubmVsKSxcbiAgICAgIHsgY29uY3VycmVuY3k6IGFzeW5jTGltaXQgfSlcbiAgfVxuXG4gIGxlYXZlQ2hhbm5lbE1lc3NhZ2UgKGlkLCBjaGFubmVsKSB7XG4gICAgbGV0IGJ1cyA9IHRoaXMuY2x1c3RlckJ1c1xuICAgIHJldHVybiBQcm9taXNlLnRyeSgoKSA9PiB7XG4gICAgICBidXMuZW1pdCgncm9vbUxlYXZlU29ja2V0JywgaWQsIGNoYW5uZWwpXG4gICAgICByZXR1cm4gZXZlbnRUb1Byb21pc2UoYnVzLCBidXMubWFrZVNvY2tldFJvb21MZWZ0TmFtZShpZCwgY2hhbm5lbCkpXG4gICAgfSkudGltZW91dCh0aGlzLmJ1c0Fja1RpbWVvdXQpLmNhdGNoUmV0dXJuKClcbiAgfVxuXG4gIGNoYW5uZWxMZWF2ZVNvY2tldHMgKGNoYW5uZWwsIGlkcykge1xuICAgIHJldHVybiBQcm9taXNlLm1hcChcbiAgICAgIGlkcyxcbiAgICAgIGlkID0+IHRoaXMubGVhdmVDaGFubmVsTWVzc2FnZShpZCwgY2hhbm5lbCksXG4gICAgICB7IGNvbmN1cnJlbmN5OiBhc3luY0xpbWl0IH0pXG4gIH1cblxuICByb2xsYmFja1Jvb21Kb2luIChlcnJvciwgcm9vbU5hbWUsIGlkKSB7XG4gICAgcmV0dXJuIHRoaXMudXNlclN0YXRlLnJlbW92ZVNvY2tldEZyb21Sb29tKGlkLCByb29tTmFtZSkuY2F0Y2goZSA9PiB7XG4gICAgICB0aGlzLmNvbnNpc3RlbmN5RmFpbHVyZShlLCB7IHJvb21OYW1lLCBvcFR5cGU6ICd1c2VyUm9vbXMnIH0pXG4gICAgICByZXR1cm4gWzFdXG4gICAgfSkuc3ByZWFkKG5qb2luZWQgPT4ge1xuICAgICAgaWYgKCFuam9pbmVkKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmxlYXZlUm9vbShyb29tTmFtZSlcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoKVxuICAgICAgfVxuICAgIH0pLnRoZW5UaHJvdyhlcnJvcilcbiAgfVxuXG4gIGxlYXZlUm9vbSAocm9vbU5hbWUpIHtcbiAgICByZXR1cm4gUHJvbWlzZVxuICAgICAgLnRyeSgoKSA9PiB0aGlzLnN0YXRlLmdldFJvb20ocm9vbU5hbWUpKVxuICAgICAgLnRoZW4ocm9vbSA9PiByb29tLmxlYXZlKHRoaXMudXNlck5hbWUpXG4gICAgICAgICAgICAuY2F0Y2goZXJyb3IgPT4gdGhpcy5jb25zaXN0ZW5jeUZhaWx1cmUoXG4gICAgICAgICAgICAgIGVycm9yLCB7cm9vbU5hbWUsIG9wVHlwZTogJ3Jvb21Vc2VybGlzdCd9KSkpXG4gICAgICAuY2F0Y2hSZXR1cm4oKVxuICB9XG5cbiAgZ2V0Tm90aWZ5U2V0dGluZ3MgKHJvb21OYW1lKSB7XG4gICAgcmV0dXJuIFByb21pc2VcbiAgICAgIC50cnkoKCkgPT4gdGhpcy5zdGF0ZS5nZXRSb29tKHJvb21OYW1lKSlcbiAgICAgIC50aGVuKHJvb20gPT4gcm9vbS5nZXROb3RpZmljYXRpb25zSW5mbyhudWxsLCB0cnVlKSlcbiAgICAgIC5jYXRjaFJldHVybih7fSlcbiAgfVxuXG4gIGpvaW5Tb2NrZXRUb1Jvb20gKGlkLCByb29tTmFtZSwgaXNMb2NhbENhbGwpIHtcbiAgICBsZXQgbG9jayA9IHRoaXMudXNlclN0YXRlLmxvY2tUb1Jvb20ocm9vbU5hbWUsIHRoaXMubG9ja1RUTClcbiAgICByZXR1cm4gUHJvbWlzZS51c2luZyhsb2NrLCBjbyhmdW5jdGlvbiAqICgpIHtcbiAgICAgIGxldCByb29tID0geWllbGQgdGhpcy5zdGF0ZS5nZXRSb29tKHJvb21OYW1lKVxuICAgICAgeWllbGQgcm9vbS5qb2luKHRoaXMudXNlck5hbWUpXG4gICAgICBsZXQgZW5hYmxlVXNlcmxpc3RVcGRhdGVzID0geWllbGQgcm9vbS5yb29tU3RhdGUudXNlcmxpc3RVcGRhdGVzR2V0KClcbiAgICAgIHJldHVybiB0aGlzLnVzZXJTdGF0ZS5hZGRTb2NrZXRUb1Jvb20oaWQsIHJvb21OYW1lKS50aGVuKG5qb2luZWQgPT4ge1xuICAgICAgICByZXR1cm4gdGhpcy50cmFuc3BvcnQuam9pbkNoYW5uZWwoaWQsIHJvb21OYW1lKS50aGVuKCgpID0+IHtcbiAgICAgICAgICBpZiAobmpvaW5lZCA9PT0gMSAmJiBlbmFibGVVc2VybGlzdFVwZGF0ZXMpIHtcbiAgICAgICAgICAgIHRoaXMudXNlckpvaW5Sb29tUmVwb3J0KHRoaXMudXNlck5hbWUsIHJvb21OYW1lKVxuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm4gdGhpcy5zb2NrZXRKb2luRWNobyhpZCwgcm9vbU5hbWUsIG5qb2luZWQsIGlzTG9jYWxDYWxsKVxuICAgICAgICB9KS5yZXR1cm4obmpvaW5lZClcbiAgICAgIH0pLmNhdGNoKGUgPT4gdGhpcy5yb2xsYmFja1Jvb21Kb2luKGUsIHJvb21OYW1lLCBpZCkpXG4gICAgfSkuYmluZCh0aGlzKSlcbiAgfVxuXG4gIGxlYXZlU29ja2V0RnJvbVJvb20gKGlkLCByb29tTmFtZSwgaXNMb2NhbENhbGwpIHtcbiAgICBsZXQgbG9jayA9IHRoaXMudXNlclN0YXRlLmxvY2tUb1Jvb20ocm9vbU5hbWUsIHRoaXMubG9ja1RUTClcbiAgICByZXR1cm4gUHJvbWlzZS51c2luZyhsb2NrLCBjbyhmdW5jdGlvbiAqICgpIHtcbiAgICAgIGxldCBbbmpvaW5lZCwgaGFzQ2hhbmdlZF0gPVxuICAgICAgICAgICAgeWllbGQgdGhpcy51c2VyU3RhdGUucmVtb3ZlU29ja2V0RnJvbVJvb20oaWQsIHJvb21OYW1lKVxuICAgICAgeWllbGQgdGhpcy5sZWF2ZUNoYW5uZWwoaWQsIHJvb21OYW1lKVxuICAgICAgaWYgKG5qb2luZWQgPT09IDApIHtcbiAgICAgICAgeWllbGQgdGhpcy5sZWF2ZVJvb20ocm9vbU5hbWUpXG4gICAgICB9XG4gICAgICBpZiAoaGFzQ2hhbmdlZCkge1xuICAgICAgICBsZXQgeyBlbmFibGVVc2VybGlzdFVwZGF0ZXMgfSA9IHlpZWxkIHRoaXMuZ2V0Tm90aWZ5U2V0dGluZ3Mocm9vbU5hbWUpXG4gICAgICAgIHRoaXMuc29ja2V0TGVmdEVjaG8oaWQsIHJvb21OYW1lLCBuam9pbmVkLCBpc0xvY2FsQ2FsbClcbiAgICAgICAgdGhpcy51c2VyTGVmdFJvb21SZXBvcnQodGhpcy51c2VyTmFtZSwgcm9vbU5hbWUsIGVuYWJsZVVzZXJsaXN0VXBkYXRlcylcbiAgICAgIH1cbiAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUobmpvaW5lZClcbiAgICB9KS5iaW5kKHRoaXMpKVxuICB9XG5cbiAgcmVtb3ZlVXNlclNvY2tldCAoaWQpIHtcbiAgICByZXR1cm4gdGhpcy51c2VyU3RhdGUucmVtb3ZlU29ja2V0KGlkKVxuICAgICAgLnNwcmVhZCgocm9vbXNSZW1vdmVkLCBqb2luZWRTb2NrZXRzLCBuY29ubmVjdGVkKSA9PiB7XG4gICAgICAgIHJvb21zUmVtb3ZlZCA9IHJvb21zUmVtb3ZlZCB8fCBbXVxuICAgICAgICBqb2luZWRTb2NrZXRzID0gam9pbmVkU29ja2V0cyB8fCBbXVxuICAgICAgICBuY29ubmVjdGVkID0gbmNvbm5lY3RlZCB8fCAwXG4gICAgICAgIHJldHVybiB0aGlzLnNvY2tldExlYXZlQ2hhbm5lbHMoaWQsIHJvb21zUmVtb3ZlZCkudGhlbigoKSA9PiB7XG4gICAgICAgICAgcmV0dXJuIFByb21pc2UubWFwKFxuICAgICAgICAgICAgcm9vbXNSZW1vdmVkLFxuICAgICAgICAgICAgKHJvb21OYW1lLCBpZHgpID0+IHtcbiAgICAgICAgICAgICAgbGV0IG5qb2luZWQgPSBqb2luZWRTb2NrZXRzW2lkeF1cbiAgICAgICAgICAgICAgdGhpcy5zb2NrZXRMZWZ0RWNobyhpZCwgcm9vbU5hbWUsIG5qb2luZWQpXG4gICAgICAgICAgICAgIGlmIChuam9pbmVkKSB7IHJldHVybiBQcm9taXNlLnJlc29sdmUoKSB9XG4gICAgICAgICAgICAgIHJldHVybiB0aGlzLmxlYXZlUm9vbShyb29tTmFtZSlcbiAgICAgICAgICAgICAgICAudGhlbigoKSA9PiB0aGlzLmdldE5vdGlmeVNldHRpbmdzKHJvb21OYW1lKSlcbiAgICAgICAgICAgICAgICAudGhlbigoe2VuYWJsZVVzZXJsaXN0VXBkYXRlc30pID0+IHRoaXMudXNlckxlZnRSb29tUmVwb3J0KFxuICAgICAgICAgICAgICAgICAgdGhpcy51c2VyTmFtZSwgcm9vbU5hbWUsIGVuYWJsZVVzZXJsaXN0VXBkYXRlcykpXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgeyBjb25jdXJyZW5jeTogYXN5bmNMaW1pdCB9KVxuICAgICAgICAgICAgLnRoZW4oKCkgPT4gdGhpcy5zb2NrZXREaXNjb25uZWN0RWNobyhpZCwgbmNvbm5lY3RlZCkpXG4gICAgICAgIH0pXG4gICAgICB9KS50aGVuKCgpID0+IHRoaXMuc3RhdGUucmVtb3ZlU29ja2V0KGlkKSlcbiAgfVxuXG4gIHJlbW92ZVNvY2tldEZyb21TZXJ2ZXIgKGlkKSB7XG4gICAgcmV0dXJuIHRoaXMucmVtb3ZlVXNlclNvY2tldChpZCkuY2F0Y2goZSA9PiB7XG4gICAgICBsZXQgaW5mbyA9IHsgaWQsIG9wVHlwZTogJ3VzZXJTb2NrZXRzJyB9XG4gICAgICByZXR1cm4gdGhpcy5jb25zaXN0ZW5jeUZhaWx1cmUoZSwgaW5mbylcbiAgICB9KVxuICB9XG5cbiAgcmVtb3ZlVXNlclNvY2tldHNGcm9tUm9vbSAocm9vbU5hbWUpIHtcbiAgICByZXR1cm4gdGhpcy51c2VyU3RhdGUucmVtb3ZlQWxsU29ja2V0c0Zyb21Sb29tKHJvb21OYW1lKS5jYXRjaChlID0+IHtcbiAgICAgIGxldCBpbmZvID0geyByb29tTmFtZSwgb3BUeXBlOiAncm9vbVVzZXJsaXN0JyB9XG4gICAgICByZXR1cm4gdGhpcy5jb25zaXN0ZW5jeUZhaWx1cmUoZSwgaW5mbylcbiAgICB9KVxuICB9XG5cbiAgcmVtb3ZlRnJvbVJvb20gKHJvb21OYW1lKSB7XG4gICAgbGV0IGxvY2sgPSB0aGlzLnVzZXJTdGF0ZS5sb2NrVG9Sb29tKHJvb21OYW1lLCB0aGlzLmxvY2tUVEwpXG4gICAgcmV0dXJuIFByb21pc2UudXNpbmcobG9jaywgY28oZnVuY3Rpb24gKiAoKSB7XG4gICAgICBsZXQgcmVtb3ZlZFNvY2tldHMgPSB5aWVsZCB0aGlzLnJlbW92ZVVzZXJTb2NrZXRzRnJvbVJvb20ocm9vbU5hbWUpXG4gICAgICByZW1vdmVkU29ja2V0cyA9IHJlbW92ZWRTb2NrZXRzIHx8IFtdXG4gICAgICB5aWVsZCB0aGlzLmNoYW5uZWxMZWF2ZVNvY2tldHMocm9vbU5hbWUsIHJlbW92ZWRTb2NrZXRzKVxuICAgICAgaWYgKHJlbW92ZWRTb2NrZXRzLmxlbmd0aCkge1xuICAgICAgICBsZXQgeyBlbmFibGVVc2VybGlzdFVwZGF0ZXMgfSA9IHlpZWxkIHRoaXMuZ2V0Tm90aWZ5U2V0dGluZ3Mocm9vbU5hbWUpXG4gICAgICAgIHRoaXMudXNlclJlbW92ZWRSZXBvcnQodGhpcy51c2VyTmFtZSwgcm9vbU5hbWUsIGVuYWJsZVVzZXJsaXN0VXBkYXRlcylcbiAgICAgIH1cbiAgICAgIHJldHVybiB0aGlzLmxlYXZlUm9vbShyb29tTmFtZSlcbiAgICB9KS5iaW5kKHRoaXMpKVxuICB9XG5cbiAgcmVtb3ZlUm9vbVVzZXJzIChyb29tTmFtZSwgdXNlck5hbWVzKSB7XG4gICAgdXNlck5hbWVzID0gdXNlck5hbWVzIHx8IFtdXG4gICAgcmV0dXJuIFByb21pc2UubWFwKFxuICAgICAgdXNlck5hbWVzLFxuICAgICAgdXNlck5hbWUgPT4ge1xuICAgICAgICByZXR1cm4gdGhpcy5zdGF0ZS5nZXRVc2VyKHVzZXJOYW1lKVxuICAgICAgICAgIC50aGVuKHVzZXIgPT4gdXNlci5yZW1vdmVGcm9tUm9vbShyb29tTmFtZSkpXG4gICAgICAgICAgLmNhdGNoUmV0dXJuKClcbiAgICAgIH0sXG4gICAgICB7IGNvbmN1cnJlbmN5OiBhc3luY0xpbWl0IH0pXG4gIH1cblxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IFVzZXJBc3NvY2lhdGlvbnNcbiJdfQ==
\No newline at end of file