1 | ;
|
2 |
|
3 | var _toConsumableArray2 = require('babel-runtime/helpers/toConsumableArray');
|
4 |
|
5 | var _toConsumableArray3 = _interopRequireDefault(_toConsumableArray2);
|
6 |
|
7 | var _getIterator2 = require('babel-runtime/core-js/get-iterator');
|
8 |
|
9 | var _getIterator3 = _interopRequireDefault(_getIterator2);
|
10 |
|
11 | var _stringify = require('babel-runtime/core-js/json/stringify');
|
12 |
|
13 | var _stringify2 = _interopRequireDefault(_stringify);
|
14 |
|
15 | var _slicedToArray2 = require('babel-runtime/helpers/slicedToArray');
|
16 |
|
17 | var _slicedToArray3 = _interopRequireDefault(_slicedToArray2);
|
18 |
|
19 | var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of');
|
20 |
|
21 | var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
|
22 |
|
23 | var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');
|
24 |
|
25 | var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
|
26 |
|
27 | var _inherits2 = require('babel-runtime/helpers/inherits');
|
28 |
|
29 | var _inherits3 = _interopRequireDefault(_inherits2);
|
30 |
|
31 | var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
|
32 |
|
33 | var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
|
34 |
|
35 | var _createClass2 = require('babel-runtime/helpers/createClass');
|
36 |
|
37 | var _createClass3 = _interopRequireDefault(_createClass2);
|
38 |
|
39 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
40 |
|
41 | var ChatServiceError = require('./ChatServiceError');
|
42 | var Promise = require('bluebird');
|
43 | var Redis = require('ioredis');
|
44 | var Room = require('./Room');
|
45 | var User = require('./User');
|
46 | var _ = require('lodash');
|
47 | var promiseRetry = require('promise-retry');
|
48 | var uid = require('uid-safe');
|
49 |
|
50 | var _require = require('es6-mixin');
|
51 |
|
52 | var mixin = _require.mixin;
|
53 |
|
54 |
|
55 | var namespace = 'chatservice';
|
56 |
|
57 | function initSet(redis, set, values) {
|
58 | return redis.del(set).then(function () {
|
59 | if (!values) {
|
60 | return Promise.resolve();
|
61 | } else {
|
62 | return redis.sadd(set, values);
|
63 | }
|
64 | });
|
65 | }
|
66 |
|
67 | // State init/remove operations.
|
68 |
|
69 | var StateOperations = function () {
|
70 | function StateOperations(name, exitsErrorName, redis, makeKeyName, stateReset) {
|
71 | (0, _classCallCheck3.default)(this, StateOperations);
|
72 |
|
73 | this.name = name;
|
74 | this.exitsErrorName = exitsErrorName;
|
75 | this.redis = redis;
|
76 | this.makeKeyName = makeKeyName;
|
77 | this.stateReset = stateReset;
|
78 | }
|
79 |
|
80 | (0, _createClass3.default)(StateOperations, [{
|
81 | key: 'initState',
|
82 | value: function initState(state) {
|
83 | var _this = this;
|
84 |
|
85 | return this.redis.setnx(this.makeKeyName('exists'), true).then(function (isnew) {
|
86 | if (!isnew) {
|
87 | var error = new ChatServiceError(_this.exitsErrorName, _this.name);
|
88 | return Promise.reject(error);
|
89 | } else {
|
90 | return Promise.resolve();
|
91 | }
|
92 | }).then(function () {
|
93 | return _this.stateReset(state);
|
94 | }).then(function () {
|
95 | return _this.redis.setnx(_this.makeKeyName('isInit'), true);
|
96 | });
|
97 | }
|
98 | }, {
|
99 | key: 'removeState',
|
100 | value: function removeState() {
|
101 | var _this2 = this;
|
102 |
|
103 | return this.stateReset().then(function () {
|
104 | return _this2.redis.del(_this2.makeKeyName('exists'), _this2.makeKeyName('isInit'));
|
105 | });
|
106 | }
|
107 | }, {
|
108 | key: 'startRemoving',
|
109 | value: function startRemoving() {
|
110 | return this.redis.del(this.makeKeyName('isInit'));
|
111 | }
|
112 | }]);
|
113 | return StateOperations;
|
114 | }();
|
115 |
|
116 | // Redis lock operations.
|
117 |
|
118 |
|
119 | var LockOperations = function () {
|
120 | function LockOperations(redis) {
|
121 | (0, _classCallCheck3.default)(this, LockOperations);
|
122 |
|
123 | this.redis = redis;
|
124 | }
|
125 |
|
126 | (0, _createClass3.default)(LockOperations, [{
|
127 | key: 'lock',
|
128 | value: function lock(key, val, ttl) {
|
129 | var _this3 = this;
|
130 |
|
131 | return promiseRetry({ minTimeout: 100, retries: 10, factor: 1.5, randomize: true }, function (retry, n) {
|
132 | return _this3.redis.set(key, val, 'NX', 'PX', ttl).then(function (res) {
|
133 | if (!res) {
|
134 | var error = new ChatServiceError('timeout');
|
135 | return retry(error);
|
136 | } else {
|
137 | return null;
|
138 | }
|
139 | }).catch(retry);
|
140 | });
|
141 | }
|
142 | }, {
|
143 | key: 'unlock',
|
144 | value: function unlock(key, val) {
|
145 | return this.redis.unlock(key, val);
|
146 | }
|
147 | }]);
|
148 | return LockOperations;
|
149 | }();
|
150 |
|
151 | // Redis scripts.
|
152 |
|
153 |
|
154 | var luaCommands = {
|
155 | unlock: {
|
156 | numberOfKeys: 1,
|
157 | lua: '\nif redis.call("get",KEYS[1]) == ARGV[1] then\n return redis.call("del",KEYS[1])\nelse\n return 0\nend'
|
158 | },
|
159 |
|
160 | messageAdd: {
|
161 | numberOfKeys: 5,
|
162 | lua: '\nlocal msg = ARGV[1]\nlocal ts = ARGV[2]\n\nlocal lastMessageId = KEYS[1]\nlocal historyMaxSize = KEYS[2]\nlocal messagesIds = KEYS[3]\nlocal messagesTimestamps = KEYS[4]\nlocal messagesHistory = KEYS[5]\n\nlocal id = tonumber(redis.call(\'INCR\', lastMessageId))\nlocal maxsz = tonumber(redis.call(\'GET\', historyMaxSize))\n\nredis.call(\'LPUSH\', messagesIds, id)\nredis.call(\'LPUSH\', messagesTimestamps, ts)\nredis.call(\'LPUSH\', messagesHistory, msg)\n\nlocal sz = tonumber(redis.call(\'LLEN\', messagesHistory))\n\nif sz > maxsz then\n redis.call(\'RPOP\', messagesIds)\n redis.call(\'RPOP\', messagesTimestamps)\n redis.call(\'RPOP\', messagesHistory)\nend\n\nreturn {id}'
|
163 | },
|
164 |
|
165 | messagesGet: {
|
166 | numberOfKeys: 5,
|
167 | lua: '\nlocal id = ARGV[1]\nlocal maxlen = ARGV[2]\n\nlocal lastMessageId = KEYS[1]\nlocal historyMaxSize = KEYS[2]\nlocal messagesIds = KEYS[3]\nlocal messagesTimestamps = KEYS[4]\nlocal messagesHistory = KEYS[5]\n\nlocal lastid = tonumber(redis.call(\'GET\', lastMessageId))\nlocal maxsz = tonumber(redis.call(\'GET\', historyMaxSize))\nlocal id = math.min(id, lastid)\nlocal endp = lastid - id\nlocal len = math.min(maxlen, endp)\nlocal start = math.max(0, endp - len)\n\nif start >= endp then\n return {}\nend\n\nendp = endp - 1\nlocal msgs = redis.call(\'LRANGE\', messagesHistory, start, endp)\nlocal tss = redis.call(\'LRANGE\', messagesTimestamps, start, endp)\nlocal ids = redis.call(\'LRANGE\', messagesIds, start, endp)\n\nreturn {msgs, tss, ids}'
|
168 | },
|
169 |
|
170 | getSocketsToRooms: {
|
171 | numberOfKeys: 1,
|
172 | lua: '\nlocal result = {}\nlocal sockets = KEYS[1]\nlocal prefix = ARGV[1]\nlocal ids = redis.call(\'HKEYS\', sockets)\n\nif table.getn(ids) == 0 then\n local jsonResult = cjson.encode(cjson.null)\n return {jsonResult}\nend\n\nfor i, id in pairs(ids) do\n local joined = redis.call(\'SMEMBERS\', prefix .. id)\n result[id] = joined\nend\n\nlocal jsonResult = cjson.encode(result)\nreturn {jsonResult}'
|
173 | },
|
174 |
|
175 | removeAllSocketsFromRoom: {
|
176 | numberOfKeys: 1,
|
177 | lua: '\nlocal room = KEYS[1]\nlocal prefix = ARGV[1]\nlocal roomName = ARGV[2]\nlocal ids = redis.call(\'SMEMBERS\', room)\n\nif table.getn(ids) == 0 then\n local jsonResult = cjson.encode(cjson.null)\n return {jsonResult}\nend\n\nredis.call(\'DEL\', room)\n\nfor i, id in pairs(ids) do\n redis.call(\'SREM\', prefix .. id, roomName)\nend\n\nlocal jsonResult = cjson.encode(ids)\nreturn {jsonResult}'
|
178 | },
|
179 |
|
180 | removeSocket: {
|
181 | numberOfKeys: 2,
|
182 | lua: '\nlocal id = KEYS[1]\nlocal sockets = KEYS[2]\nlocal prefix = ARGV[1]\nlocal socketid = ARGV[2]\n\nlocal rooms = redis.call(\'SMEMBERS\', id)\nredis.call(\'DEL\', id)\n\nredis.call(\'HDEL\', sockets, socketid)\nlocal nconnected = redis.call(\'HLEN\', sockets)\n\nlocal removedRooms = {}\nlocal joinedSockets = {}\n\nfor i, room in pairs(rooms) do\n local ismember = redis.call(\'SISMEMBER\', prefix .. room, socketid)\n if ismember == 1 then\n redis.call(\'SREM\', prefix .. room, socketid)\n local njoined = redis.call(\'SCARD\', prefix .. room)\n table.insert(removedRooms, room)\n table.insert(joinedSockets, njoined)\n end\nend\n\nif table.getn(removedRooms) == 0 or table.getn(rooms) == 0 then\n local jsonResult = cjson.encode({cjson.null, cjson.null, nconnected})\n return {jsonResult}\nend\n\nlocal jsonResult = cjson.encode({removedRooms, joinedSockets, nconnected})\nreturn {jsonResult}'
|
183 | }
|
184 |
|
185 | };
|
186 |
|
187 | // Implements state API lists management.
|
188 |
|
189 | var ListsStateRedis = function () {
|
190 | function ListsStateRedis() {
|
191 | (0, _classCallCheck3.default)(this, ListsStateRedis);
|
192 | }
|
193 |
|
194 | (0, _createClass3.default)(ListsStateRedis, [{
|
195 | key: 'makeKeyName',
|
196 | value: function makeKeyName(keyName) {
|
197 | return namespace + ':' + this.prefix + ':{' + this.name + '}:' + keyName;
|
198 | }
|
199 | }, {
|
200 | key: 'checkList',
|
201 | value: function checkList(listName, num, limit) {
|
202 | if (!this.hasList(listName)) {
|
203 | var error = new ChatServiceError('noList', listName);
|
204 | return Promise.reject(error);
|
205 | }
|
206 | if (listName === 'userlist') {
|
207 | return Promise.resolve();
|
208 | }
|
209 | return this.redis.scard(listName).then(function (sz) {
|
210 | if (sz + num > limit) {
|
211 | var _error = new ChatServiceError('listLimitExceeded', listName);
|
212 | return Promise.reject(_error);
|
213 | } else {
|
214 | return Promise.resolve();
|
215 | }
|
216 | });
|
217 | }
|
218 | }, {
|
219 | key: 'addToList',
|
220 | value: function addToList(listName, elems, limit) {
|
221 | var _this4 = this;
|
222 |
|
223 | var num = elems.length;
|
224 | return this.checkList(listName, num, limit).then(function () {
|
225 | return _this4.redis.sadd(_this4.makeKeyName(listName), elems);
|
226 | });
|
227 | }
|
228 | }, {
|
229 | key: 'removeFromList',
|
230 | value: function removeFromList(listName, elems) {
|
231 | var _this5 = this;
|
232 |
|
233 | return this.checkList(listName).then(function () {
|
234 | return _this5.redis.srem(_this5.makeKeyName(listName), elems);
|
235 | });
|
236 | }
|
237 | }, {
|
238 | key: 'getList',
|
239 | value: function getList(listName) {
|
240 | var _this6 = this;
|
241 |
|
242 | return this.checkList(listName).then(function () {
|
243 | return _this6.redis.smembers(_this6.makeKeyName(listName));
|
244 | });
|
245 | }
|
246 | }, {
|
247 | key: 'hasInList',
|
248 | value: function hasInList(listName, elem) {
|
249 | var _this7 = this;
|
250 |
|
251 | return this.checkList(listName).then(function () {
|
252 | return _this7.redis.sismember(_this7.makeKeyName(listName), elem);
|
253 | }).then(function (data) {
|
254 | return Promise.resolve(Boolean(data));
|
255 | });
|
256 | }
|
257 | }, {
|
258 | key: 'whitelistOnlySet',
|
259 | value: function whitelistOnlySet(mode) {
|
260 | var whitelistOnly = mode ? true : '';
|
261 | return this.redis.set(this.makeKeyName('whitelistMode'), whitelistOnly);
|
262 | }
|
263 | }, {
|
264 | key: 'whitelistOnlyGet',
|
265 | value: function whitelistOnlyGet() {
|
266 | return this.redis.get(this.makeKeyName('whitelistMode')).then(function (data) {
|
267 | return Promise.resolve(Boolean(data));
|
268 | });
|
269 | }
|
270 | }]);
|
271 | return ListsStateRedis;
|
272 | }();
|
273 |
|
274 | // Implements room state API.
|
275 |
|
276 |
|
277 | var RoomStateRedis = function (_ListsStateRedis) {
|
278 | (0, _inherits3.default)(RoomStateRedis, _ListsStateRedis);
|
279 |
|
280 | function RoomStateRedis(server, roomName) {
|
281 | (0, _classCallCheck3.default)(this, RoomStateRedis);
|
282 |
|
283 | var _this8 = (0, _possibleConstructorReturn3.default)(this, (0, _getPrototypeOf2.default)(RoomStateRedis).call(this));
|
284 |
|
285 | _this8.server = server;
|
286 | _this8.roomName = roomName;
|
287 | _this8.name = _this8.roomName;
|
288 | _this8.historyMaxGetMessages = _this8.server.historyMaxGetMessages;
|
289 | _this8.redis = _this8.server.redis;
|
290 | _this8.exitsErrorName = 'roomExists';
|
291 | _this8.prefix = 'rooms';
|
292 | mixin(_this8, StateOperations, _this8.name, _this8.exitsErrorName, _this8.redis, _this8.makeKeyName.bind(_this8), _this8.stateReset.bind(_this8));
|
293 | return _this8;
|
294 | }
|
295 |
|
296 | (0, _createClass3.default)(RoomStateRedis, [{
|
297 | key: 'stateReset',
|
298 | value: function stateReset(state) {
|
299 | state = state || {};
|
300 | var _state = state;
|
301 | var whitelist = _state.whitelist;
|
302 | var blacklist = _state.blacklist;
|
303 | var adminlist = _state.adminlist;
|
304 | var whitelistOnly = _state.whitelistOnly;
|
305 | var owner = _state.owner;
|
306 | var historyMaxSize = _state.historyMaxSize;
|
307 | var _state$enableAccessLi = _state.enableAccessListsUpdates;
|
308 | var enableAccessListsUpdates = _state$enableAccessLi === undefined ? this.server.enableAccessListsUpdates : _state$enableAccessLi;
|
309 | var _state$enableUserlist = _state.enableUserlistUpdates;
|
310 | var enableUserlistUpdates = _state$enableUserlist === undefined ? this.server.enableUserlistUpdates : _state$enableUserlist;
|
311 |
|
312 | if (!owner) {
|
313 | owner = '';
|
314 | }
|
315 | return Promise.all([initSet(this.redis, this.makeKeyName('whitelist'), whitelist), initSet(this.redis, this.makeKeyName('blacklist'), blacklist), initSet(this.redis, this.makeKeyName('adminlist'), adminlist), initSet(this.redis, this.makeKeyName('userlist'), null), this.redis.del(this.makeKeyName('messagesHistory')), this.redis.del(this.makeKeyName('messagesTimestamps')), this.redis.del(this.makeKeyName('messagesIds')), this.redis.del(this.makeKeyName('usersseen')), this.redis.set(this.makeKeyName('lastMessageId'), 0), this.redis.set(this.makeKeyName('owner'), owner), this.whitelistOnlySet(whitelistOnly), this.accessListsUpdatesSet(enableAccessListsUpdates), this.userlistUpdatesSet(enableUserlistUpdates), this.historyMaxSizeSet(historyMaxSize)]).return();
|
316 | }
|
317 | }, {
|
318 | key: 'hasList',
|
319 | value: function hasList(listName) {
|
320 | return listName === 'adminlist' || listName === 'whitelist' || listName === 'blacklist' || listName === 'userlist';
|
321 | }
|
322 | }, {
|
323 | key: 'ownerGet',
|
324 | value: function ownerGet() {
|
325 | return this.redis.get(this.makeKeyName('owner'));
|
326 | }
|
327 | }, {
|
328 | key: 'ownerSet',
|
329 | value: function ownerSet(owner) {
|
330 | return this.redis.set(this.makeKeyName('owner'), owner);
|
331 | }
|
332 | }, {
|
333 | key: 'accessListsUpdatesSet',
|
334 | value: function accessListsUpdatesSet(enableAccessListsUpdates) {
|
335 | enableAccessListsUpdates = enableAccessListsUpdates ? true : '';
|
336 | return this.redis.set(this.makeKeyName('enableAccessListsUpdates'), enableAccessListsUpdates);
|
337 | }
|
338 | }, {
|
339 | key: 'accessListsUpdatesGet',
|
340 | value: function accessListsUpdatesGet() {
|
341 | return this.redis.get(this.makeKeyName('enableAccessListsUpdates')).then(function (data) {
|
342 | return Promise.resolve(Boolean(data));
|
343 | });
|
344 | }
|
345 | }, {
|
346 | key: 'userlistUpdatesSet',
|
347 | value: function userlistUpdatesSet(enableUserlistUpdates) {
|
348 | enableUserlistUpdates = enableUserlistUpdates ? true : '';
|
349 | return this.redis.set(this.makeKeyName('enableUserlistUpdates'), enableUserlistUpdates);
|
350 | }
|
351 | }, {
|
352 | key: 'userlistUpdatesGet',
|
353 | value: function userlistUpdatesGet() {
|
354 | return this.redis.get(this.makeKeyName('enableUserlistUpdates')).then(function (data) {
|
355 | return Promise.resolve(Boolean(data));
|
356 | });
|
357 | }
|
358 | }, {
|
359 | key: 'historyMaxSizeSet',
|
360 | value: function historyMaxSizeSet(historyMaxSize) {
|
361 | var limit = historyMaxSize;
|
362 | if (!(_.isNumber(historyMaxSize) && historyMaxSize >= 0)) {
|
363 | limit = this.server.historyMaxSize;
|
364 | }
|
365 | if (limit === 0) {
|
366 | return this.redis.multi().set(this.makeKeyName('historyMaxSize'), limit).del(this.makeKeyName('messagesHistory')).del(this.makeKeyName('messagesTimestamps')).del(this.makeKeyName('messagesIds')).exec();
|
367 | } else {
|
368 | var last = limit - 1;
|
369 | return this.redis.multi().set(this.makeKeyName('historyMaxSize'), limit).ltrim(this.makeKeyName('messagesHistory'), 0, last).ltrim(this.makeKeyName('messagesTimestamps'), 0, last).ltrim(this.makeKeyName('messagesIds'), 0, last).exec();
|
370 | }
|
371 | }
|
372 | }, {
|
373 | key: 'historyInfo',
|
374 | value: function historyInfo() {
|
375 | var _this9 = this;
|
376 |
|
377 | return this.redis.multi().get(this.makeKeyName('historyMaxSize')).llen(this.makeKeyName('messagesHistory')).get(this.makeKeyName('lastMessageId')).exec().spread(function (_ref, _ref2, _ref3) {
|
378 | var _ref6 = (0, _slicedToArray3.default)(_ref, 2);
|
379 |
|
380 | var historyMaxSize = _ref6[1];
|
381 |
|
382 | var _ref5 = (0, _slicedToArray3.default)(_ref2, 2);
|
383 |
|
384 | var historySize = _ref5[1];
|
385 |
|
386 | var _ref4 = (0, _slicedToArray3.default)(_ref3, 2);
|
387 |
|
388 | var lastMessageId = _ref4[1];
|
389 |
|
390 | historySize = parseInt(historySize);
|
391 | historyMaxSize = parseFloat(historyMaxSize);
|
392 | lastMessageId = parseInt(lastMessageId);
|
393 | var info = { historySize: historySize,
|
394 | historyMaxSize: historyMaxSize,
|
395 | historyMaxGetMessages: _this9.historyMaxGetMessages,
|
396 | lastMessageId: lastMessageId };
|
397 | return Promise.resolve(info);
|
398 | });
|
399 | }
|
400 | }, {
|
401 | key: 'getCommonUsers',
|
402 | value: function getCommonUsers() {
|
403 | return this.redis.sdiff(this.makeKeyName('userlist'), this.makeKeyName('whitelist'), this.makeKeyName('adminlist'));
|
404 | }
|
405 | }, {
|
406 | key: 'messageAdd',
|
407 | value: function messageAdd(msg) {
|
408 | var timestamp = _.now();
|
409 | var smsg = (0, _stringify2.default)(msg);
|
410 | return this.redis.messageAdd(this.makeKeyName('lastMessageId'), this.makeKeyName('historyMaxSize'), this.makeKeyName('messagesIds'), this.makeKeyName('messagesTimestamps'), this.makeKeyName('messagesHistory'), smsg, timestamp).spread(function (id) {
|
411 | msg.id = id;
|
412 | msg.timestamp = timestamp;
|
413 | return Promise.resolve(msg);
|
414 | });
|
415 | }
|
416 | }, {
|
417 | key: 'convertMessages',
|
418 | value: function convertMessages(msgs, tss, ids) {
|
419 | var data = [];
|
420 | if (!msgs) {
|
421 | return Promise.resolve(data);
|
422 | }
|
423 | for (var idx = 0; idx < msgs.length; idx++) {
|
424 | var msg = msgs[idx];
|
425 | var obj = JSON.parse(msg, function (key, val) {
|
426 | if (val && val.type === 'Buffer') {
|
427 | return new Buffer(val.data);
|
428 | } else {
|
429 | return val;
|
430 | }
|
431 | });
|
432 | obj.timestamp = parseInt(tss[idx]);
|
433 | obj.id = parseInt(ids[idx]);
|
434 | data[idx] = obj;
|
435 | }
|
436 | return Promise.resolve(data);
|
437 | }
|
438 | }, {
|
439 | key: 'messagesGetRecent',
|
440 | value: function messagesGetRecent() {
|
441 | var _this10 = this;
|
442 |
|
443 | if (this.historyMaxGetMessages <= 0) {
|
444 | return Promise.resolve([]);
|
445 | }
|
446 | var limit = this.historyMaxGetMessages - 1;
|
447 | return this.redis.multi().lrange(this.makeKeyName('messagesHistory'), 0, limit).lrange(this.makeKeyName('messagesTimestamps'), 0, limit).lrange(this.makeKeyName('messagesIds'), 0, limit).exec().spread(function (_ref7, _ref8, _ref9) {
|
448 | var _ref12 = (0, _slicedToArray3.default)(_ref7, 2);
|
449 |
|
450 | var msgs = _ref12[1];
|
451 |
|
452 | var _ref11 = (0, _slicedToArray3.default)(_ref8, 2);
|
453 |
|
454 | var tss = _ref11[1];
|
455 |
|
456 | var _ref10 = (0, _slicedToArray3.default)(_ref9, 2);
|
457 |
|
458 | var ids = _ref10[1];
|
459 |
|
460 | return _this10.convertMessages(msgs, tss, ids);
|
461 | });
|
462 | }
|
463 | }, {
|
464 | key: 'messagesGet',
|
465 | value: function messagesGet(id) {
|
466 | var _this11 = this;
|
467 |
|
468 | var maxMessages = arguments.length <= 1 || arguments[1] === undefined ? this.historyMaxGetMessages : arguments[1];
|
469 |
|
470 | if (maxMessages <= 0) {
|
471 | return Promise.resolve([]);
|
472 | }
|
473 | id = _.max([0, id]);
|
474 | return this.redis.messagesGet(this.makeKeyName('lastMessageId'), this.makeKeyName('historyMaxSize'), this.makeKeyName('messagesIds'), this.makeKeyName('messagesTimestamps'), this.makeKeyName('messagesHistory'), id, maxMessages).spread(function (msgs, tss, ids) {
|
475 | return _this11.convertMessages(msgs, tss, ids);
|
476 | });
|
477 | }
|
478 | }, {
|
479 | key: 'userSeenGet',
|
480 | value: function userSeenGet(userName) {
|
481 | return this.redis.multi().hget(this.makeKeyName('usersseen'), userName).sismember(this.makeKeyName('userlist'), userName).exec().spread(function (_ref13, _ref14) {
|
482 | var _ref16 = (0, _slicedToArray3.default)(_ref13, 2);
|
483 |
|
484 | var ts = _ref16[1];
|
485 |
|
486 | var _ref15 = (0, _slicedToArray3.default)(_ref14, 2);
|
487 |
|
488 | var isjoined = _ref15[1];
|
489 |
|
490 | var joined = Boolean(isjoined);
|
491 | var timestamp = ts ? parseInt(ts) : null;
|
492 | return { joined: joined, timestamp: timestamp };
|
493 | });
|
494 | }
|
495 | }, {
|
496 | key: 'userSeenUpdate',
|
497 | value: function userSeenUpdate(userName) {
|
498 | var timestamp = _.now();
|
499 | return this.redis.hset(this.makeKeyName('usersseen'), userName, timestamp);
|
500 | }
|
501 | }]);
|
502 | return RoomStateRedis;
|
503 | }(ListsStateRedis);
|
504 |
|
505 | // Implements direct messaging state API.
|
506 |
|
507 |
|
508 | var DirectMessagingStateRedis = function (_ListsStateRedis2) {
|
509 | (0, _inherits3.default)(DirectMessagingStateRedis, _ListsStateRedis2);
|
510 |
|
511 | function DirectMessagingStateRedis(server, userName) {
|
512 | (0, _classCallCheck3.default)(this, DirectMessagingStateRedis);
|
513 |
|
514 | var _this12 = (0, _possibleConstructorReturn3.default)(this, (0, _getPrototypeOf2.default)(DirectMessagingStateRedis).call(this));
|
515 |
|
516 | _this12.server = server;
|
517 | _this12.userName = userName;
|
518 | _this12.name = _this12.userName;
|
519 | _this12.prefix = 'users';
|
520 | _this12.exitsErrorName = 'userExists';
|
521 | _this12.redis = _this12.server.redis;
|
522 | mixin(_this12, StateOperations, _this12.name, _this12.exitsErrorName, _this12.redis, _this12.makeKeyName.bind(_this12), _this12.stateReset.bind(_this12));
|
523 | return _this12;
|
524 | }
|
525 |
|
526 | (0, _createClass3.default)(DirectMessagingStateRedis, [{
|
527 | key: 'hasList',
|
528 | value: function hasList(listName) {
|
529 | return listName === 'whitelist' || listName === 'blacklist';
|
530 | }
|
531 | }, {
|
532 | key: 'stateReset',
|
533 | value: function stateReset(state) {
|
534 | state = state || {};
|
535 | var _state2 = state;
|
536 | var whitelist = _state2.whitelist;
|
537 | var blacklist = _state2.blacklist;
|
538 | var whitelistOnly = _state2.whitelistOnly;
|
539 |
|
540 | whitelistOnly = whitelistOnly ? true : '';
|
541 | return Promise.all([initSet(this.redis, this.makeKeyName('whitelist'), whitelist), initSet(this.redis, this.makeKeyName('blacklist'), blacklist), this.redis.set(this.makeKeyName('whitelistMode'), whitelistOnly)]).return();
|
542 | }
|
543 | }]);
|
544 | return DirectMessagingStateRedis;
|
545 | }(ListsStateRedis);
|
546 |
|
547 | // Implements user state API.
|
548 |
|
549 |
|
550 | var UserStateRedis = function () {
|
551 | function UserStateRedis(server, userName) {
|
552 | (0, _classCallCheck3.default)(this, UserStateRedis);
|
553 |
|
554 | this.server = server;
|
555 | this.userName = userName;
|
556 | this.name = this.userName;
|
557 | this.prefix = 'users';
|
558 | this.redis = this.server.redis;
|
559 | mixin(this, LockOperations, this.redis);
|
560 | }
|
561 |
|
562 | (0, _createClass3.default)(UserStateRedis, [{
|
563 | key: 'makeKeyName',
|
564 | value: function makeKeyName(keyName) {
|
565 | return namespace + ':' + this.prefix + ':{' + this.name + '}:' + keyName;
|
566 | }
|
567 | }, {
|
568 | key: 'makeSocketToRooms',
|
569 | value: function makeSocketToRooms() {
|
570 | var id = arguments.length <= 0 || arguments[0] === undefined ? '' : arguments[0];
|
571 |
|
572 | return this.makeKeyName('socketsToRooms:' + id);
|
573 | }
|
574 | }, {
|
575 | key: 'makeRoomToSockets',
|
576 | value: function makeRoomToSockets() {
|
577 | var room = arguments.length <= 0 || arguments[0] === undefined ? '' : arguments[0];
|
578 |
|
579 | return this.makeKeyName('roomsToSockets:' + room);
|
580 | }
|
581 | }, {
|
582 | key: 'makeRoomLock',
|
583 | value: function makeRoomLock(room) {
|
584 | return this.makeKeyName('roomLock:' + room);
|
585 | }
|
586 | }, {
|
587 | key: 'addSocket',
|
588 | value: function addSocket(id, uid) {
|
589 | return this.redis.multi().hset(this.makeKeyName('sockets'), id, uid).hlen(this.makeKeyName('sockets')).exec().spread(function (_, _ref17) {
|
590 | var _ref18 = (0, _slicedToArray3.default)(_ref17, 2);
|
591 |
|
592 | var nconnected = _ref18[1];
|
593 | return Promise.resolve(nconnected);
|
594 | });
|
595 | }
|
596 | }, {
|
597 | key: 'getAllSockets',
|
598 | value: function getAllSockets() {
|
599 | return this.redis.hkeys(this.makeKeyName('sockets'));
|
600 | }
|
601 | }, {
|
602 | key: 'getSocketsToInstance',
|
603 | value: function getSocketsToInstance() {
|
604 | return this.redis.hgetall(this.makeKeyName('sockets'));
|
605 | }
|
606 | }, {
|
607 | key: 'getRoomToSockets',
|
608 | value: function getRoomToSockets(roomName) {
|
609 | return this.redis.smembers(this.makeRoomToSockets(roomName));
|
610 | }
|
611 | }, {
|
612 | key: 'getSocketsToRooms',
|
613 | value: function getSocketsToRooms() {
|
614 | return this.redis.getSocketsToRooms(this.makeKeyName('sockets'), this.makeSocketToRooms()).spread(function (result) {
|
615 | var data = JSON.parse(result) || {};
|
616 | var _iteratorNormalCompletion = true;
|
617 | var _didIteratorError = false;
|
618 | var _iteratorError = undefined;
|
619 |
|
620 | try {
|
621 | for (var _iterator = (0, _getIterator3.default)(_.toPairs(data)), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
622 | var _step$value = (0, _slicedToArray3.default)(_step.value, 2);
|
623 |
|
624 | var k = _step$value[0];
|
625 | var v = _step$value[1];
|
626 |
|
627 | if (_.isEmpty(v)) {
|
628 | data[k] = [];
|
629 | }
|
630 | }
|
631 | } catch (err) {
|
632 | _didIteratorError = true;
|
633 | _iteratorError = err;
|
634 | } finally {
|
635 | try {
|
636 | if (!_iteratorNormalCompletion && _iterator.return) {
|
637 | _iterator.return();
|
638 | }
|
639 | } finally {
|
640 | if (_didIteratorError) {
|
641 | throw _iteratorError;
|
642 | }
|
643 | }
|
644 | }
|
645 |
|
646 | return Promise.resolve(data);
|
647 | });
|
648 | }
|
649 | }, {
|
650 | key: 'addSocketToRoom',
|
651 | value: function addSocketToRoom(id, roomName) {
|
652 | return this.redis.multi().sadd(this.makeSocketToRooms(id), roomName).sadd(this.makeRoomToSockets(roomName), id).scard(this.makeRoomToSockets(roomName)).exec().then(function (_ref19) {
|
653 | var _ref20 = (0, _slicedToArray3.default)(_ref19, 3);
|
654 |
|
655 | var _ref20$ = (0, _slicedToArray3.default)(_ref20[2], 2);
|
656 |
|
657 | var njoined = _ref20$[1];
|
658 | return Promise.resolve(njoined);
|
659 | });
|
660 | }
|
661 | }, {
|
662 | key: 'removeSocketFromRoom',
|
663 | value: function removeSocketFromRoom(id, roomName) {
|
664 | return this.redis.multi().scard(this.makeRoomToSockets(roomName)).srem(this.makeSocketToRooms(id), roomName).srem(this.makeRoomToSockets(roomName), id).scard(this.makeRoomToSockets(roomName)).exec().then(function (_ref21) {
|
665 | var _ref22 = (0, _slicedToArray3.default)(_ref21, 4);
|
666 |
|
667 | var _ref22$ = (0, _slicedToArray3.default)(_ref22[0], 2);
|
668 |
|
669 | var wasjoined = _ref22$[1];
|
670 |
|
671 | var _ref22$2 = (0, _slicedToArray3.default)(_ref22[3], 2);
|
672 |
|
673 | var njoined = _ref22$2[1];
|
674 |
|
675 | var hasChanged = njoined !== wasjoined;
|
676 | return Promise.resolve([njoined, hasChanged]);
|
677 | });
|
678 | }
|
679 | }, {
|
680 | key: 'removeAllSocketsFromRoom',
|
681 | value: function removeAllSocketsFromRoom(roomName) {
|
682 | return this.redis.removeAllSocketsFromRoom(this.makeRoomToSockets(roomName), this.makeSocketToRooms(), roomName).spread(function (result) {
|
683 | return Promise.resolve(JSON.parse(result));
|
684 | });
|
685 | }
|
686 | }, {
|
687 | key: 'removeSocket',
|
688 | value: function removeSocket(id) {
|
689 | return this.redis.removeSocket(this.makeSocketToRooms(id), this.makeKeyName('sockets'), this.makeRoomToSockets(), id).spread(function (result) {
|
690 | return Promise.resolve(JSON.parse(result));
|
691 | });
|
692 | }
|
693 | }, {
|
694 | key: 'lockToRoom',
|
695 | value: function lockToRoom(roomName, ttl) {
|
696 | var _this13 = this;
|
697 |
|
698 | return uid(18).then(function (val) {
|
699 | var start = _.now();
|
700 | return _this13.lock(_this13.makeRoomLock(roomName), val, ttl).then(function () {
|
701 | return Promise.resolve().disposer(function () {
|
702 | if (start + ttl < _.now()) {
|
703 | _this13.server.emit('lockTimeExceeded', val, { userName: _this13.userName, roomName: roomName });
|
704 | }
|
705 | return _this13.unlock(_this13.makeRoomLock(roomName), val);
|
706 | });
|
707 | });
|
708 | });
|
709 | }
|
710 | }]);
|
711 | return UserStateRedis;
|
712 | }();
|
713 |
|
714 | // Implements global state API.
|
715 |
|
716 |
|
717 | var RedisState = function () {
|
718 | function RedisState(server, options) {
|
719 | (0, _classCallCheck3.default)(this, RedisState);
|
720 |
|
721 | this.server = server;
|
722 | this.options = options;
|
723 | this.closed = false;
|
724 | if (this.options.useCluster) {
|
725 | this.redis = new (Function.prototype.bind.apply(Redis.Cluster, [null].concat((0, _toConsumableArray3.default)(this.options.redisOptions))))();
|
726 | } else {
|
727 | var redisOptions = _.castArray(this.options.redisOptions);
|
728 | this.redis = new (Function.prototype.bind.apply(Redis, [null].concat((0, _toConsumableArray3.default)(redisOptions))))();
|
729 | }
|
730 | this.RoomState = RoomStateRedis;
|
731 | this.UserState = UserStateRedis;
|
732 | this.DirectMessagingState = DirectMessagingStateRedis;
|
733 | this.lockTTL = this.options.lockTTL || 10000;
|
734 | this.instanceUID = this.server.instanceUID;
|
735 | this.server.redis = this.redis;
|
736 | var _iteratorNormalCompletion2 = true;
|
737 | var _didIteratorError2 = false;
|
738 | var _iteratorError2 = undefined;
|
739 |
|
740 | try {
|
741 | for (var _iterator2 = (0, _getIterator3.default)(_.toPairs(luaCommands)), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
|
742 | var _step2$value = (0, _slicedToArray3.default)(_step2.value, 2);
|
743 |
|
744 | var cmd = _step2$value[0];
|
745 | var def = _step2$value[1];
|
746 |
|
747 | this.redis.defineCommand(cmd, {
|
748 | numberOfKeys: def.numberOfKeys,
|
749 | lua: def.lua
|
750 | });
|
751 | }
|
752 | } catch (err) {
|
753 | _didIteratorError2 = true;
|
754 | _iteratorError2 = err;
|
755 | } finally {
|
756 | try {
|
757 | if (!_iteratorNormalCompletion2 && _iterator2.return) {
|
758 | _iterator2.return();
|
759 | }
|
760 | } finally {
|
761 | if (_didIteratorError2) {
|
762 | throw _iteratorError2;
|
763 | }
|
764 | }
|
765 | }
|
766 | }
|
767 |
|
768 | (0, _createClass3.default)(RedisState, [{
|
769 | key: 'makeKeyName',
|
770 | value: function makeKeyName(prefix, name, keyName) {
|
771 | return namespace + ':' + prefix + ':{' + name + '}:' + keyName;
|
772 | }
|
773 | }, {
|
774 | key: 'hasRoom',
|
775 | value: function hasRoom(name) {
|
776 | return this.redis.get(this.makeKeyName('rooms', name, 'isInit'));
|
777 | }
|
778 | }, {
|
779 | key: 'hasUser',
|
780 | value: function hasUser(name) {
|
781 | return this.redis.get(this.makeKeyName('users', name, 'isInit'));
|
782 | }
|
783 | }, {
|
784 | key: 'close',
|
785 | value: function close() {
|
786 | this.closed = true;
|
787 | return this.redis.quit().return();
|
788 | }
|
789 | }, {
|
790 | key: 'getRoom',
|
791 | value: function getRoom(name) {
|
792 | var isPredicate = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1];
|
793 |
|
794 | var room = new Room(this.server, name);
|
795 | return this.hasRoom(name).then(function (exists) {
|
796 | if (!exists) {
|
797 | if (isPredicate) {
|
798 | return Promise.resolve(null);
|
799 | } else {
|
800 | var error = new ChatServiceError('noRoom', name);
|
801 | return Promise.reject(error);
|
802 | }
|
803 | }
|
804 | return Promise.resolve(room);
|
805 | });
|
806 | }
|
807 | }, {
|
808 | key: 'addRoom',
|
809 | value: function addRoom(name, state) {
|
810 | var room = new Room(this.server, name);
|
811 | return room.initState(state).return(room);
|
812 | }
|
813 | }, {
|
814 | key: 'removeRoom',
|
815 | value: function removeRoom(name) {
|
816 | return Promise.resolve();
|
817 | }
|
818 | }, {
|
819 | key: 'addSocket',
|
820 | value: function addSocket(id, userName) {
|
821 | return this.redis.hset(this.makeKeyName('instances', this.instanceUID, 'sockets'), id, userName);
|
822 | }
|
823 | }, {
|
824 | key: 'removeSocket',
|
825 | value: function removeSocket(id) {
|
826 | return this.redis.hdel(this.makeKeyName('instances', this.instanceUID, 'sockets'), id);
|
827 | }
|
828 | }, {
|
829 | key: 'getInstanceSockets',
|
830 | value: function getInstanceSockets() {
|
831 | var uid = arguments.length <= 0 || arguments[0] === undefined ? this.instanceUID : arguments[0];
|
832 |
|
833 | return this.redis.hgetall(this.makeKeyName('instances', uid, 'sockets'));
|
834 | }
|
835 | }, {
|
836 | key: 'updateHeartbeat',
|
837 | value: function updateHeartbeat() {
|
838 | return this.redis.set(this.makeKeyName('instances', this.instanceUID, 'heartbeat'), _.now()).catchReturn();
|
839 | }
|
840 | }, {
|
841 | key: 'getInstanceHeartbeat',
|
842 | value: function getInstanceHeartbeat() {
|
843 | var uid = arguments.length <= 0 || arguments[0] === undefined ? this.instanceUID : arguments[0];
|
844 |
|
845 | return this.redis.get(this.makeKeyName('instances', uid, 'heartbeat')).then(function (ts) {
|
846 | return ts ? parseInt(ts) : null;
|
847 | });
|
848 | }
|
849 | }, {
|
850 | key: 'getOrAddUser',
|
851 | value: function getOrAddUser(name, state) {
|
852 | var user = new User(this.server, name);
|
853 | return this.hasUser(name).then(function (exists) {
|
854 | if (!exists) {
|
855 | return user.initState(state);
|
856 | } else {
|
857 | return Promise.resolve();
|
858 | }
|
859 | }).catch(ChatServiceError, function (e) {
|
860 | return user;
|
861 | }).return(user);
|
862 | }
|
863 | }, {
|
864 | key: 'getUser',
|
865 | value: function getUser(name) {
|
866 | var isPredicate = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1];
|
867 |
|
868 | var user = new User(this.server, name);
|
869 | return this.hasUser(name).then(function (exists) {
|
870 | if (!exists) {
|
871 | if (isPredicate) {
|
872 | return Promise.resolve(null);
|
873 | } else {
|
874 | var error = new ChatServiceError('noUser', name);
|
875 | return Promise.reject(error);
|
876 | }
|
877 | }
|
878 | return Promise.resolve(user);
|
879 | });
|
880 | }
|
881 | }, {
|
882 | key: 'addUser',
|
883 | value: function addUser(name, state) {
|
884 | var user = new User(this.server, name);
|
885 | return user.initState(state).return(user);
|
886 | }
|
887 | }, {
|
888 | key: 'removeUser',
|
889 | value: function removeUser(name) {
|
890 | return Promise.resolve();
|
891 | }
|
892 | }]);
|
893 | return RedisState;
|
894 | }();
|
895 |
|
896 | module.exports = RedisState;
|
897 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9SZWRpc1N0YXRlLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBRUEsSUFBTSxtQkFBbUIsUUFBUSxvQkFBUixDQUF6QjtBQUNBLElBQU0sVUFBVSxRQUFRLFVBQVIsQ0FBaEI7QUFDQSxJQUFNLFFBQVEsUUFBUSxTQUFSLENBQWQ7QUFDQSxJQUFNLE9BQU8sUUFBUSxRQUFSLENBQWI7QUFDQSxJQUFNLE9BQU8sUUFBUSxRQUFSLENBQWI7QUFDQSxJQUFNLElBQUksUUFBUSxRQUFSLENBQVY7QUFDQSxJQUFNLGVBQWUsUUFBUSxlQUFSLENBQXJCO0FBQ0EsSUFBTSxNQUFNLFFBQVEsVUFBUixDQUFaOztlQUNrQixRQUFRLFdBQVIsQzs7SUFBVixLLFlBQUEsSzs7O0FBRVIsSUFBSSxZQUFZLGFBQWhCOztBQUVBLFNBQVMsT0FBVCxDQUFrQixLQUFsQixFQUF5QixHQUF6QixFQUE4QixNQUE5QixFQUFzQztBQUNwQyxTQUFPLE1BQU0sR0FBTixDQUFVLEdBQVYsRUFBZSxJQUFmLENBQW9CLFlBQU07QUFDL0IsUUFBSSxDQUFDLE1BQUwsRUFBYTtBQUNYLGFBQU8sUUFBUSxPQUFSLEVBQVA7QUFDRCxLQUZELE1BRU87QUFDTCxhQUFPLE1BQU0sSUFBTixDQUFXLEdBQVgsRUFBZ0IsTUFBaEIsQ0FBUDtBQUNEO0FBQ0YsR0FOTSxDQUFQO0FBT0Q7O0FBR0Q7O0lBQ00sZTtBQUVKLDJCQUFhLElBQWIsRUFBbUIsY0FBbkIsRUFBbUMsS0FBbkMsRUFBMEMsV0FBMUMsRUFBdUQsVUFBdkQsRUFBbUU7QUFBQTs7QUFDakUsU0FBSyxJQUFMLEdBQVksSUFBWjtBQUNBLFNBQUssY0FBTCxHQUFzQixjQUF0QjtBQUNBLFNBQUssS0FBTCxHQUFhLEtBQWI7QUFDQSxTQUFLLFdBQUwsR0FBbUIsV0FBbkI7QUFDQSxTQUFLLFVBQUwsR0FBa0IsVUFBbEI7QUFDRDs7Ozs4QkFF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O0FBQUEsVUFBckIsV0FBcUIseURBQVAsS0FBTzs7QUFDbEMsVUFBSSxPQUFPLElBQUksSUFBSixDQUFTLEtBQUssTUFBZCxFQUFzQixJQUF0QixDQUFYO0FBQ0EsYUFBTyxLQUFLLE9BQUwsQ0FBYSxJQUFiLEVBQW1CLElBQW5CLENBQXdCLGtCQUFVO0FBQ3ZDLFlBQUksQ0FBQyxNQUFMLEVBQWE7QUFDWCxjQUFJLFdBQUosRUFBaUI7QUFDZixtQkFBTyxRQUFRLE9BQVIsQ0FBZ0IsSUFBaEIsQ0FBUDtBQUNELFdBRkQsTUFFTztBQUNMLGdCQUFJLFFBQVEsSUFBSSxnQkFBSixDQUFxQixRQUFyQixFQUErQixJQUEvQixDQUFaO0FBQ0EsbUJBQU8sUUFBUSxNQUFSLENBQWUsS0FBZixDQUFQO0FBQ0Q7QUFDRjtBQUNELGVBQU8sUUFBUSxPQUFSLENBQWdCLElBQWhCLENBQVA7QUFDRCxPQVZNLENBQVA7QUFXRDs7OzRCQUVRLEksRUFBTSxLLEVBQU87QUFDcEIsVUFBSSxPQUFPLElBQUksSUFBSixDQUFTLEtBQUssTUFBZCxFQUFzQixJQUF0QixDQUFYO0FBQ0EsYUFBTyxLQUFLLFNBQUwsQ0FBZSxLQUFmLEVBQXNCLE1BQXRCLENBQTZCLElBQTdCLENBQVA7QUFDRDs7OytCQUVXLEksRUFBTTtBQUNoQixhQUFPLFFBQVEsT0FBUixFQUFQO0FBQ0Q7Ozs7O0FBSUgsT0FBTyxPQUFQLEdBQWlCLFVBQWpCIiwiZmlsZSI6IlJlZGlzU3RhdGUuanMiLCJzb3VyY2VzQ29udGVudCI6WyIndXNlIHN0cmljdCdcblxuY29uc3QgQ2hhdFNlcnZpY2VFcnJvciA9IHJlcXVpcmUoJy4vQ2hhdFNlcnZpY2VFcnJvcicpXG5jb25zdCBQcm9taXNlID0gcmVxdWlyZSgnYmx1ZWJpcmQnKVxuY29uc3QgUmVkaXMgPSByZXF1aXJlKCdpb3JlZGlzJylcbmNvbnN0IFJvb20gPSByZXF1aXJlKCcuL1Jvb20nKVxuY29uc3QgVXNlciA9IHJlcXVpcmUoJy4vVXNlcicpXG5jb25zdCBfID0gcmVxdWlyZSgnbG9kYXNoJylcbmNvbnN0IHByb21pc2VSZXRyeSA9IHJlcXVpcmUoJ3Byb21pc2UtcmV0cnknKVxuY29uc3QgdWlkID0gcmVxdWlyZSgndWlkLXNhZmUnKVxuY29uc3QgeyBtaXhpbiB9ID0gcmVxdWlyZSgnZXM2LW1peGluJylcblxubGV0IG5hbWVzcGFjZSA9ICdjaGF0c2VydmljZSdcblxuZnVuY3Rpb24gaW5pdFNldCAocmVkaXMsIHNldCwgdmFsdWVzKSB7XG4gIHJldHVybiByZWRpcy5kZWwoc2V0KS50aGVuKCgpID0+IHtcbiAgICBpZiAoIXZhbHVlcykge1xuICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpXG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiByZWRpcy5zYWRkKHNldCwgdmFsdWVzKVxuICAgIH1cbiAgfSlcbn1cblxuXG4vLyBTdGF0ZSBpbml0L3JlbW92ZSBvcGVyYXRpb25zLlxuY2xhc3MgU3RhdGVPcGVyYXRpb25zIHtcblxuICBjb25zdHJ1Y3RvciAobmFtZSwgZXhpdHNFcnJvck5hbWUsIHJlZGlzLCBtYWtlS2V5TmFtZSwgc3RhdGVSZXNldCkge1xuICAgIHRoaXMubmFtZSA9IG5hbWVcbiAgICB0aGlzLmV4aXRzRXJyb3JOYW1lID0gZXhpdHNFcnJvck5hbWVcbiAgICB0aGlzLnJlZGlzID0gcmVkaXNcbiAgICB0aGlzLm1ha2VLZXlOYW1lID0gbWFrZUtleU5hbWVcbiAgICB0aGlzLnN0YXRlUmVzZXQgPSBzdGF0ZVJlc2V0XG4gIH1cblxuICBpbml0U3RhdGUgKHN0YXRlKSB7XG4gICAgcmV0dXJuIHRoaXMucmVkaXMuc2V0bngodGhpcy5tYWtlS2V5TmFtZSgnZXhpc3RzJyksIHRydWUpLnRoZW4oaXNuZXcgPT4ge1xuICAgICAgaWYgKCFpc25ldykge1xuICAgICAgICBsZXQgZXJyb3IgPSBuZXcgQ2hhdFNlcnZpY2VFcnJvcih0aGlzLmV4aXRzRXJyb3JOYW1lLCB0aGlzLm5hbWUpXG4gICAgICAgIHJldHVybiBQcm9taXNlLnJlamVjdChlcnJvcilcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoKVxuICAgICAgfVxuICAgIH0pLnRoZW4oKCkgPT4gdGhpcy5zdGF0ZVJlc2V0KHN0YXRlKSlcbiAgICAgIC50aGVuKCgpID0+IHRoaXMucmVkaXMuc2V0bngodGhpcy5tYWtlS2V5TmFtZSgnaXNJbml0JyksIHRydWUpKVxuICB9XG5cbiAgcmVtb3ZlU3RhdGUgKCkge1xuICAgIHJldHVybiB0aGlzLnN0YXRlUmVzZXQoKS50aGVuKCgpID0+IHtcbiAgICAgIHJldHVybiB0aGlzLnJlZGlzLmRlbChcbiAgICAgICAgdGhpcy5tYWtlS2V5TmFtZSgnZXhpc3RzJyksIHRoaXMubWFrZUtleU5hbWUoJ2lzSW5pdCcpKVxuICAgIH0pXG4gIH1cblxuICBzdGFydFJlbW92aW5nICgpIHtcbiAgICByZXR1cm4gdGhpcy5yZWRpcy5kZWwodGhpcy5tYWtlS2V5TmFtZSgnaXNJbml0JykpXG4gIH1cblxufVxuXG4vLyBSZWRpcyBsb2NrIG9wZXJhdGlvbnMuXG5jbGFzcyBMb2NrT3BlcmF0aW9ucyB7XG5cbiAgY29uc3RydWN0b3IgKHJlZGlzKSB7XG4gICAgdGhpcy5yZWRpcyA9IHJlZGlzXG4gIH1cblxuICBsb2NrIChrZXksIHZhbCwgdHRsKSB7XG4gICAgcmV0dXJuIHByb21pc2VSZXRyeShcbiAgICAgIHttaW5UaW1lb3V0OiAxMDAsIHJldHJpZXM6IDEwLCBmYWN0b3I6IDEuNSwgcmFuZG9taXplOiB0cnVlfSxcbiAgICAgIChyZXRyeSwgbikgPT4ge1xuICAgICAgICByZXR1cm4gdGhpcy5yZWRpcy5zZXQoa2V5LCB2YWwsICdOWCcsICdQWCcsIHR0bCkudGhlbihyZXMgPT4ge1xuICAgICAgICAgIGlmICghcmVzKSB7XG4gICAgICAgICAgICBsZXQgZXJyb3IgPSBuZXcgQ2hhdFNlcnZpY2VFcnJvcigndGltZW91dCcpXG4gICAgICAgICAgICByZXR1cm4gcmV0cnkoZXJyb3IpXG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiBudWxsXG4gICAgICAgICAgfVxuICAgICAgICB9KS5jYXRjaChyZXRyeSlcbiAgICAgIH0pXG4gIH1cblxuICB1bmxvY2sgKGtleSwgdmFsKSB7XG4gICAgcmV0dXJuIHRoaXMucmVkaXMudW5sb2NrKGtleSwgdmFsKVxuICB9XG5cbn1cblxuLy8gUmVkaXMgc2NyaXB0cy5cbmxldCBsdWFDb21tYW5kcyA9IHtcbiAgdW5sb2NrOiB7XG4gICAgbnVtYmVyT2ZLZXlzOiAxLFxuICAgIGx1YTogYFxuaWYgcmVkaXMuY2FsbChcImdldFwiLEtFWVNbMV0pID09IEFSR1ZbMV0gdGhlblxuICByZXR1cm4gcmVkaXMuY2FsbChcImRlbFwiLEtFWVNbMV0pXG5lbHNlXG4gIHJldHVybiAwXG5lbmRgXG4gIH0sXG5cbiAgbWVzc2FnZUFkZDoge1xuICAgIG51bWJlck9mS2V5czogNSxcbiAgICBsdWE6IGBcbmxvY2FsIG1zZyA9IEFSR1ZbMV1cbmxvY2FsIHRzID0gQVJHVlsyXVxuXG5sb2NhbCBsYXN0TWVzc2FnZUlkID0gS0VZU1sxXVxubG9jYWwgaGlzdG9yeU1heFNpemUgPSBLRVlTWzJdXG5sb2NhbCBtZXNzYWdlc0lkcyA9IEtFWVNbM11cbmxvY2FsIG1lc3NhZ2VzVGltZXN0YW1wcyA9IEtFWVNbNF1cbmxvY2FsIG1lc3NhZ2VzSGlzdG9yeSA9IEtFWVNbNV1cblxubG9jYWwgaWQgPSB0b251bWJlcihyZWRpcy5jYWxsKCdJTkNSJywgbGFzdE1lc3NhZ2VJZCkpXG5sb2NhbCBtYXhzeiA9IHRvbnVtYmVyKHJlZGlzLmNhbGwoJ0dFVCcsIGhpc3RvcnlNYXhTaXplKSlcblxucmVkaXMuY2FsbCgnTFBVU0gnLCBtZXNzYWdlc0lkcywgaWQpXG5yZWRpcy5jYWxsKCdMUFVTSCcsIG1lc3NhZ2VzVGltZXN0YW1wcywgdHMpXG5yZWRpcy5jYWxsKCdMUFVTSCcsIG1lc3NhZ2VzSGlzdG9yeSwgbXNnKVxuXG5sb2NhbCBzeiA9IHRvbnVtYmVyKHJlZGlzLmNhbGwoJ0xMRU4nLCBtZXNzYWdlc0hpc3RvcnkpKVxuXG5pZiBzeiA+IG1heHN6IHRoZW5cbiAgcmVkaXMuY2FsbCgnUlBPUCcsIG1lc3NhZ2VzSWRzKVxuICByZWRpcy5jYWxsKCdSUE9QJywgbWVzc2FnZXNUaW1lc3RhbXBzKVxuICByZWRpcy5jYWxsKCdSUE9QJywgbWVzc2FnZXNIaXN0b3J5KVxuZW5kXG5cbnJldHVybiB7aWR9YFxuICB9LFxuXG4gIG1lc3NhZ2VzR2V0OiB7XG4gICAgbnVtYmVyT2ZLZXlzOiA1LFxuICAgIGx1YTogYFxubG9jYWwgaWQgPSBBUkdWWzFdXG5sb2NhbCBtYXhsZW4gPSBBUkdWWzJdXG5cbmxvY2FsIGxhc3RNZXNzYWdlSWQgPSBLRVlTWzFdXG5sb2NhbCBoaXN0b3J5TWF4U2l6ZSA9IEtFWVNbMl1cbmxvY2FsIG1lc3NhZ2VzSWRzID0gS0VZU1szXVxubG9jYWwgbWVzc2FnZXNUaW1lc3RhbXBzID0gS0VZU1s0XVxubG9jYWwgbWVzc2FnZXNIaXN0b3J5ID0gS0VZU1s1XVxuXG5sb2NhbCBsYXN0aWQgPSB0b251bWJlcihyZWRpcy5jYWxsKCdHRVQnLCBsYXN0TWVzc2FnZUlkKSlcbmxvY2FsIG1heHN6ID0gdG9udW1iZXIocmVkaXMuY2FsbCgnR0VUJywgaGlzdG9yeU1heFNpemUpKVxubG9jYWwgaWQgPSBtYXRoLm1pbihpZCwgbGFzdGlkKVxubG9jYWwgZW5kcCA9IGxhc3RpZCAtIGlkXG5sb2NhbCBsZW4gPSBtYXRoLm1pbihtYXhsZW4sIGVuZHApXG5sb2NhbCBzdGFydCA9IG1hdGgubWF4KDAsIGVuZHAgLSBsZW4pXG5cbmlmIHN0YXJ0ID49IGVuZHAgdGhlblxuICByZXR1cm4ge31cbmVuZFxuXG5lbmRwID0gZW5kcCAtIDFcbmxvY2FsIG1zZ3MgPSByZWRpcy5jYWxsKCdMUkFOR0UnLCBtZXNzYWdlc0hpc3RvcnksIHN0YXJ0LCBlbmRwKVxubG9jYWwgdHNzID0gcmVkaXMuY2FsbCgnTFJBTkdFJywgbWVzc2FnZXNUaW1lc3RhbXBzLCBzdGFydCwgZW5kcClcbmxvY2FsIGlkcyA9IHJlZGlzLmNhbGwoJ0xSQU5HRScsIG1lc3NhZ2VzSWRzLCBzdGFydCwgZW5kcClcblxucmV0dXJuIHttc2dzLCB0c3MsIGlkc31gXG4gIH0sXG5cbiAgZ2V0U29ja2V0c1RvUm9vbXM6IHtcbiAgICBudW1iZXJPZktleXM6IDEsXG4gICAgbHVhOiBgXG5sb2NhbCByZXN1bHQgPSB7fVxubG9jYWwgc29ja2V0cyA9IEtFWVNbMV1cbmxvY2FsIHByZWZpeCA9IEFSR1ZbMV1cbmxvY2FsIGlkcyA9IHJlZGlzLmNhbGwoJ0hLRVlTJywgc29ja2V0cylcblxuaWYgdGFibGUuZ2V0bihpZHMpID09IDAgdGhlblxuICBsb2NhbCBqc29uUmVzdWx0ID0gY2pzb24uZW5jb2RlKGNqc29uLm51bGwpXG4gIHJldHVybiB7anNvblJlc3VsdH1cbmVuZFxuXG5mb3IgaSwgaWQgaW4gcGFpcnMoaWRzKSBkb1xuICBsb2NhbCBqb2luZWQgPSByZWRpcy5jYWxsKCdTTUVNQkVSUycsIHByZWZpeCAuLiBpZClcbiAgcmVzdWx0W2lkXSA9IGpvaW5lZFxuZW5kXG5cbmxvY2FsIGpzb25SZXN1bHQgPSBjanNvbi5lbmNvZGUocmVzdWx0KVxucmV0dXJuIHtqc29uUmVzdWx0fWBcbiAgfSxcblxuICByZW1vdmVBbGxTb2NrZXRzRnJvbVJvb206IHtcbiAgICBudW1iZXJPZktleXM6IDEsXG4gICAgbHVhOiBgXG5sb2NhbCByb29tID0gS0VZU1sxXVxubG9jYWwgcHJlZml4ID0gQVJHVlsxXVxubG9jYWwgcm9vbU5hbWUgPSBBUkdWWzJdXG5sb2NhbCBpZHMgPSByZWRpcy5jYWxsKCdTTUVNQkVSUycsIHJvb20pXG5cbmlmIHRhYmxlLmdldG4oaWRzKSA9PSAwIHRoZW5cbiAgbG9jYWwganNvblJlc3VsdCA9IGNqc29uLmVuY29kZShjanNvbi5udWxsKVxuICByZXR1cm4ge2pzb25SZXN1bHR9XG5lbmRcblxucmVkaXMuY2FsbCgnREVMJywgcm9vbSlcblxuZm9yIGksIGlkIGluIHBhaXJzKGlkcykgZG9cbiAgcmVkaXMuY2FsbCgnU1JFTScsIHByZWZpeCAuLiBpZCwgcm9vbU5hbWUpXG5lbmRcblxubG9jYWwganNvblJlc3VsdCA9IGNqc29uLmVuY29kZShpZHMpXG5yZXR1cm4ge2pzb25SZXN1bHR9YFxuICB9LFxuXG4gIHJlbW92ZVNvY2tldDoge1xuICAgIG51bWJlck9mS2V5czogMixcbiAgICBsdWE6IGBcbmxvY2FsIGlkID0gS0VZU1sxXVxubG9jYWwgc29ja2V0cyA9IEtFWVNbMl1cbmxvY2FsIHByZWZpeCA9IEFSR1ZbMV1cbmxvY2FsIHNvY2tldGlkID0gQVJHVlsyXVxuXG5sb2NhbCByb29tcyA9IHJlZGlzLmNhbGwoJ1NNRU1CRVJTJywgaWQpXG5yZWRpcy5jYWxsKCdERUwnLCBpZClcblxucmVkaXMuY2FsbCgnSERFTCcsIHNvY2tldHMsIHNvY2tldGlkKVxubG9jYWwgbmNvbm5lY3RlZCA9IHJlZGlzLmNhbGwoJ0hMRU4nLCBzb2NrZXRzKVxuXG5sb2NhbCByZW1vdmVkUm9vbXMgPSB7fVxubG9jYWwgam9pbmVkU29ja2V0cyA9IHt9XG5cbmZvciBpLCByb29tIGluIHBhaXJzKHJvb21zKSBkb1xuICBsb2NhbCBpc21lbWJlciA9IHJlZGlzLmNhbGwoJ1NJU01FTUJFUicsIHByZWZpeCAuLiByb29tLCBzb2NrZXRpZClcbiAgaWYgaXNtZW1iZXIgPT0gMSB0aGVuXG4gICAgcmVkaXMuY2FsbCgnU1JFTScsIHByZWZpeCAuLiByb29tLCBzb2NrZXRpZClcbiAgICBsb2NhbCBuam9pbmVkID0gcmVkaXMuY2FsbCgnU0NBUkQnLCBwcmVmaXggLi4gcm9vbSlcbiAgICB0YWJsZS5pbnNlcnQocmVtb3ZlZFJvb21zLCByb29tKVxuICAgIHRhYmxlLmluc2VydChqb2luZWRTb2NrZXRzLCBuam9pbmVkKVxuICBlbmRcbmVuZFxuXG5pZiB0YWJsZS5nZXRuKHJlbW92ZWRSb29tcykgPT0gMCBvciB0YWJsZS5nZXRuKHJvb21zKSA9PSAwIHRoZW5cbiAgbG9jYWwganNvblJlc3VsdCA9IGNqc29uLmVuY29kZSh7Y2pzb24ubnVsbCwgY2pzb24ubnVsbCwgbmNvbm5lY3RlZH0pXG4gIHJldHVybiB7anNvblJlc3VsdH1cbmVuZFxuXG5sb2NhbCBqc29uUmVzdWx0ID0gY2pzb24uZW5jb2RlKHtyZW1vdmVkUm9vbXMsIGpvaW5lZFNvY2tldHMsIG5jb25uZWN0ZWR9KVxucmV0dXJuIHtqc29uUmVzdWx0fWBcbiAgfVxuXG59XG5cbi8vIEltcGxlbWVudHMgc3RhdGUgQVBJIGxpc3RzIG1hbmFnZW1lbnQuXG5jbGFzcyBMaXN0c1N0YXRlUmVkaXMge1xuXG4gIG1ha2VLZXlOYW1lIChrZXlOYW1lKSB7XG4gICAgcmV0dXJuIGAke25hbWVzcGFjZX06JHt0aGlzLnByZWZpeH06eyR7dGhpcy5uYW1lfX06JHtrZXlOYW1lfWBcbiAgfVxuXG4gIGNoZWNrTGlzdCAobGlzdE5hbWUsIG51bSwgbGltaXQpIHtcbiAgICBpZiAoIXRoaXMuaGFzTGlzdChsaXN0TmFtZSkpIHtcbiAgICAgIGxldCBlcnJvciA9IG5ldyBDaGF0U2VydmljZUVycm9yKCdub0xpc3QnLCBsaXN0TmFtZSlcbiAgICAgIHJldHVybiBQcm9taXNlLnJlamVjdChlcnJvcilcbiAgICB9XG4gICAgaWYgKGxpc3ROYW1lID09PSAndXNlcmxpc3QnKSB7XG4gICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKClcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMucmVkaXMuc2NhcmQobGlzdE5hbWUpLnRoZW4oc3ogPT4ge1xuICAgICAgaWYgKHN6ICsgbnVtID4gbGltaXQpIHtcbiAgICAgICAgbGV0IGVycm9yID0gbmV3IENoYXRTZXJ2aWNlRXJyb3IoJ2xpc3RMaW1pdEV4Y2VlZGVkJywgbGlzdE5hbWUpXG4gICAgICAgIHJldHVybiBQcm9taXNlLnJlamVjdChlcnJvcilcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoKVxuICAgICAgfVxuICAgIH0pXG4gIH1cblxuICBhZGRUb0xpc3QgKGxpc3ROYW1lLCBlbGVtcywgbGltaXQpIHtcbiAgICBsZXQgbnVtID0gZWxlbXMubGVuZ3RoXG4gICAgcmV0dXJuIHRoaXMuY2hlY2tMaXN0KGxpc3ROYW1lLCBudW0sIGxpbWl0KVxuICAgICAgLnRoZW4oKCkgPT4gdGhpcy5yZWRpcy5zYWRkKHRoaXMubWFrZUtleU5hbWUobGlzdE5hbWUpLCBlbGVtcykpXG4gIH1cblxuICByZW1vdmVGcm9tTGlzdCAobGlzdE5hbWUsIGVsZW1zKSB7XG4gICAgcmV0dXJuIHRoaXMuY2hlY2tMaXN0KGxpc3ROYW1lKVxuICAgICAgLnRoZW4oKCkgPT4gdGhpcy5yZWRpcy5zcmVtKHRoaXMubWFrZUtleU5hbWUobGlzdE5hbWUpLCBlbGVtcykpXG4gIH1cblxuICBnZXRMaXN0IChsaXN0TmFtZSkge1xuICAgIHJldHVybiB0aGlzLmNoZWNrTGlzdChsaXN0TmFtZSlcbiAgICAgIC50aGVuKCgpID0+IHRoaXMucmVkaXMuc21lbWJlcnModGhpcy5tYWtlS2V5TmFtZShsaXN0TmFtZSkpKVxuICB9XG5cbiAgaGFzSW5MaXN0IChsaXN0TmFtZSwgZWxlbSkge1xuICAgIHJldHVybiB0aGlzLmNoZWNrTGlzdChsaXN0TmFtZSlcbiAgICAgIC50aGVuKCgpID0+IHRoaXMucmVkaXMuc2lzbWVtYmVyKHRoaXMubWFrZUtleU5hbWUobGlzdE5hbWUpLCBlbGVtKSlcbiAgICAgIC50aGVuKGRhdGEgPT4gUHJvbWlzZS5yZXNvbHZlKEJvb2xlYW4oZGF0YSkpKVxuICB9XG5cbiAgd2hpdGVsaXN0T25seVNldCAobW9kZSkge1xuICAgIGxldCB3aGl0ZWxpc3RPbmx5ID0gbW9kZSA/IHRydWUgOiAnJ1xuICAgIHJldHVybiB0aGlzLnJlZGlzLnNldCh0aGlzLm1ha2VLZXlOYW1lKCd3aGl0ZWxpc3RNb2RlJyksIHdoaXRlbGlzdE9ubHkpXG4gIH1cblxuICB3aGl0ZWxpc3RPbmx5R2V0ICgpIHtcbiAgICByZXR1cm4gdGhpcy5yZWRpcy5nZXQodGhpcy5tYWtlS2V5TmFtZSgnd2hpdGVsaXN0TW9kZScpKVxuICAgICAgLnRoZW4oZGF0YSA9PiBQcm9taXNlLnJlc29sdmUoQm9vbGVhbihkYXRhKSkpXG4gIH1cblxufVxuXG4vLyBJbXBsZW1lbnRzIHJvb20gc3RhdGUgQVBJLlxuY2xhc3MgUm9vbVN0YXRlUmVkaXMgZXh0ZW5kcyBMaXN0c1N0YXRlUmVkaXMge1xuXG4gIGNvbnN0cnVjdG9yIChzZXJ2ZXIsIHJvb21OYW1lKSB7XG4gICAgc3VwZXIoKVxuICAgIHRoaXMuc2VydmVyID0gc2VydmVyXG4gICAgdGhpcy5yb29tTmFtZSA9IHJvb21OYW1lXG4gICAgdGhpcy5uYW1lID0gdGhpcy5yb29tTmFtZVxuICAgIHRoaXMuaGlzdG9yeU1heEdldE1lc3NhZ2VzID0gdGhpcy5zZXJ2ZXIuaGlzdG9yeU1heEdldE1lc3NhZ2VzXG4gICAgdGhpcy5yZWRpcyA9IHRoaXMuc2VydmVyLnJlZGlzXG4gICAgdGhpcy5leGl0c0Vycm9yTmFtZSA9ICdyb29tRXhpc3RzJ1xuICAgIHRoaXMucHJlZml4ID0gJ3Jvb21zJ1xuICAgIG1peGluKHRoaXMsIFN0YXRlT3BlcmF0aW9ucywgdGhpcy5uYW1lLCB0aGlzLmV4aXRzRXJyb3JOYW1lLCB0aGlzLnJlZGlzLFxuICAgICAgICAgIHRoaXMubWFrZUtleU5hbWUuYmluZCh0aGlzKSwgdGhpcy5zdGF0ZVJlc2V0LmJpbmQodGhpcykpXG4gIH1cblxuICBzdGF0ZVJlc2V0IChzdGF0ZSkge1xuICAgIHN0YXRlID0gc3RhdGUgfHwge31cbiAgICBsZXQgeyB3aGl0ZWxpc3QsIGJsYWNrbGlzdCwgYWRtaW5saXN0LFxuICAgICAgICAgIHdoaXRlbGlzdE9ubHksIG93bmVyLCBoaXN0b3J5TWF4U2l6ZSxcbiAgICAgICAgICBlbmFibGVBY2Nlc3NMaXN0c1VwZGF0ZXMgPSB0aGlzLnNlcnZlci5lbmFibGVBY2Nlc3NMaXN0c1VwZGF0ZXMsXG4gICAgICAgICAgZW5hYmxlVXNlcmxpc3RVcGRhdGVzID0gdGhpcy5zZXJ2ZXIuZW5hYmxlVXNlcmxpc3RVcGRhdGVzXG4gICAgICAgIH0gPSBzdGF0ZVxuICAgIGlmICghb3duZXIpIHsgb3duZXIgPSAnJyB9XG4gICAgcmV0dXJuIFByb21pc2UuYWxsKFtcbiAgICAgIGluaXRTZXQodGhpcy5yZWRpcywgdGhpcy5tYWtlS2V5TmFtZSgnd2hpdGVsaXN0JyksIHdoaXRlbGlzdCksXG4gICAgICBpbml0U2V0KHRoaXMucmVkaXMsIHRoaXMubWFrZUtleU5hbWUoJ2JsYWNrbGlzdCcpLCBibGFja2xpc3QpLFxuICAgICAgaW5pdFNldCh0aGlzLnJlZGlzLCB0aGlzLm1ha2VLZXlOYW1lKCdhZG1pbmxpc3QnKSwgYWRtaW5saXN0KSxcbiAgICAgIGluaXRTZXQodGhpcy5yZWRpcywgdGhpcy5tYWtlS2V5TmFtZSgndXNlcmxpc3QnKSwgbnVsbCksXG4gICAgICB0aGlzLnJlZGlzLmRlbCh0aGlzLm1ha2VLZXlOYW1lKCdtZXNzYWdlc0hpc3RvcnknKSksXG4gICAgICB0aGlzLnJlZGlzLmRlbCh0aGlzLm1ha2VLZXlOYW1lKCdtZXNzYWdlc1RpbWVzdGFtcHMnKSksXG4gICAgICB0aGlzLnJlZGlzLmRlbCh0aGlzLm1ha2VLZXlOYW1lKCdtZXNzYWdlc0lkcycpKSxcbiAgICAgIHRoaXMucmVkaXMuZGVsKHRoaXMubWFrZUtleU5hbWUoJ3VzZXJzc2VlbicpKSxcbiAgICAgIHRoaXMucmVkaXMuc2V0KHRoaXMubWFrZUtleU5hbWUoJ2xhc3RNZXNzYWdlSWQnKSwgMCksXG4gICAgICB0aGlzLnJlZGlzLnNldCh0aGlzLm1ha2VLZXlOYW1lKCdvd25lcicpLCBvd25lciksXG4gICAgICB0aGlzLndoaXRlbGlzdE9ubHlTZXQod2hpdGVsaXN0T25seSksXG4gICAgICB0aGlzLmFjY2Vzc0xpc3RzVXBkYXRlc1NldChlbmFibGVBY2Nlc3NMaXN0c1VwZGF0ZXMpLFxuICAgICAgdGhpcy51c2VybGlzdFVwZGF0ZXNTZXQoZW5hYmxlVXNlcmxpc3RVcGRhdGVzKSxcbiAgICAgIHRoaXMuaGlzdG9yeU1heFNpemVTZXQoaGlzdG9yeU1heFNpemUpXG4gICAgXSkucmV0dXJuKClcbiAgfVxuXG4gIGhhc0xpc3QgKGxpc3ROYW1lKSB7XG4gICAgcmV0dXJuIGxpc3ROYW1lID09PSAnYWRtaW5saXN0JyB8fCBsaXN0TmFtZSA9PT0gJ3doaXRlbGlzdCcgfHxcbiAgICAgIGxpc3ROYW1lID09PSAnYmxhY2tsaXN0JyB8fCBsaXN0TmFtZSA9PT0gJ3VzZXJsaXN0J1xuICB9XG5cbiAgb3duZXJHZXQgKCkge1xuICAgIHJldHVybiB0aGlzLnJlZGlzLmdldCh0aGlzLm1ha2VLZXlOYW1lKCdvd25lcicpKVxuICB9XG5cbiAgb3duZXJTZXQgKG93bmVyKSB7XG4gICAgcmV0dXJuIHRoaXMucmVkaXMuc2V0KHRoaXMubWFrZUtleU5hbWUoJ293bmVyJyksIG93bmVyKVxuICB9XG5cbiAgYWNjZXNzTGlzdHNVcGRhdGVzU2V0IChlbmFibGVBY2Nlc3NMaXN0c1VwZGF0ZXMpIHtcbiAgICBlbmFibGVBY2Nlc3NMaXN0c1VwZGF0ZXMgPSBlbmFibGVBY2Nlc3NMaXN0c1VwZGF0ZXMgPyB0cnVlIDogJydcbiAgICByZXR1cm4gdGhpcy5yZWRpcy5zZXQodGhpcy5tYWtlS2V5TmFtZSgnZW5hYmxlQWNjZXNzTGlzdHNVcGRhdGVzJyksXG4gICAgICAgICAgICAgICAgICAgICAgICAgIGVuYWJsZUFjY2Vzc0xpc3RzVXBkYXRlcylcbiAgfVxuXG4gIGFjY2Vzc0xpc3RzVXBkYXRlc0dldCAoKSB7XG4gICAgcmV0dXJuIHRoaXMucmVkaXMuZ2V0KHRoaXMubWFrZUtleU5hbWUoJ2VuYWJsZUFjY2Vzc0xpc3RzVXBkYXRlcycpKVxuICAgICAgLnRoZW4oZGF0YSA9PiBQcm9taXNlLnJlc29sdmUoQm9vbGVhbihkYXRhKSkpXG4gIH1cblxuICB1c2VybGlzdFVwZGF0ZXNTZXQgKGVuYWJsZVVzZXJsaXN0VXBkYXRlcykge1xuICAgIGVuYWJsZVVzZXJsaXN0VXBkYXRlcyA9IGVuYWJsZVVzZXJsaXN0VXBkYXRlcyA/IHRydWUgOiAnJ1xuICAgIHJldHVybiB0aGlzLnJlZGlzLnNldCh0aGlzLm1ha2VLZXlOYW1lKCdlbmFibGVVc2VybGlzdFVwZGF0ZXMnKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgZW5hYmxlVXNlcmxpc3RVcGRhdGVzKVxuICB9XG5cbiAgdXNlcmxpc3RVcGRhdGVzR2V0ICgpIHtcbiAgICByZXR1cm4gdGhpcy5yZWRpcy5nZXQodGhpcy5tYWtlS2V5TmFtZSgnZW5hYmxlVXNlcmxpc3RVcGRhdGVzJykpXG4gICAgICAudGhlbihkYXRhID0+IFByb21pc2UucmVzb2x2ZShCb29sZWFuKGRhdGEpKSlcbiAgfVxuXG4gIGhpc3RvcnlNYXhTaXplU2V0IChoaXN0b3J5TWF4U2l6ZSkge1xuICAgIGxldCBsaW1pdCA9IGhpc3RvcnlNYXhTaXplXG4gICAgaWYgKCEoXy5pc051bWJlcihoaXN0b3J5TWF4U2l6ZSkgJiYgaGlzdG9yeU1heFNpemUgPj0gMCkpIHtcbiAgICAgIGxpbWl0ID0gdGhpcy5zZXJ2ZXIuaGlzdG9yeU1heFNpemVcbiAgICB9XG4gICAgaWYgKGxpbWl0ID09PSAwKSB7XG4gICAgICByZXR1cm4gdGhpcy5yZWRpcy5tdWx0aSgpXG4gICAgICAgIC5zZXQodGhpcy5tYWtlS2V5TmFtZSgnaGlzdG9yeU1heFNpemUnKSwgbGltaXQpXG4gICAgICAgIC5kZWwodGhpcy5tYWtlS2V5TmFtZSgnbWVzc2FnZXNIaXN0b3J5JykpXG4gICAgICAgIC5kZWwodGhpcy5tYWtlS2V5TmFtZSgnbWVzc2FnZXNUaW1lc3RhbXBzJykpXG4gICAgICAgIC5kZWwodGhpcy5tYWtlS2V5TmFtZSgnbWVzc2FnZXNJZHMnKSlcbiAgICAgICAgLmV4ZWMoKVxuICAgIH0gZWxzZSB7XG4gICAgICBsZXQgbGFzdCA9IGxpbWl0IC0gMVxuICAgICAgcmV0dXJuIHRoaXMucmVkaXMubXVsdGkoKVxuICAgICAgICAuc2V0KHRoaXMubWFrZUtleU5hbWUoJ2hpc3RvcnlNYXhTaXplJyksIGxpbWl0KVxuICAgICAgICAubHRyaW0odGhpcy5tYWtlS2V5TmFtZSgnbWVzc2FnZXNIaXN0b3J5JyksIDAsIGxhc3QpXG4gICAgICAgIC5sdHJpbSh0aGlzLm1ha2VLZXlOYW1lKCdtZXNzYWdlc1RpbWVzdGFtcHMnKSwgMCwgbGFzdClcbiAgICAgICAgLmx0cmltKHRoaXMubWFrZUtleU5hbWUoJ21lc3NhZ2VzSWRzJyksIDAsIGxhc3QpXG4gICAgICAgIC5leGVjKClcbiAgICB9XG4gIH1cblxuICBoaXN0b3J5SW5mbyAoKSB7XG4gICAgcmV0dXJuIHRoaXMucmVkaXMubXVsdGkoKVxuICAgICAgLmdldCh0aGlzLm1ha2VLZXlOYW1lKCdoaXN0b3J5TWF4U2l6ZScpKVxuICAgICAgLmxsZW4odGhpcy5tYWtlS2V5TmFtZSgnbWVzc2FnZXNIaXN0b3J5JykpXG4gICAgICAuZ2V0KHRoaXMubWFrZUtleU5hbWUoJ2xhc3RNZXNzYWdlSWQnKSlcbiAgICAgIC5leGVjKClcbiAgICAgIC5zcHJlYWQoKFssIGhpc3RvcnlNYXhTaXplXSwgWywgaGlzdG9yeVNpemVdLCBbLCBsYXN0TWVzc2FnZUlkXSkgPT4ge1xuICAgICAgICBoaXN0b3J5U2l6ZSA9IHBhcnNlSW50KGhpc3RvcnlTaXplKVxuICAgICAgICBoaXN0b3J5TWF4U2l6ZSA9IHBhcnNlRmxvYXQoaGlzdG9yeU1heFNpemUpXG4gICAgICAgIGxhc3RNZXNzYWdlSWQgPSBwYXJzZUludChsYXN0TWVzc2FnZUlkKVxuICAgICAgICBsZXQgaW5mbyA9IHsgaGlzdG9yeVNpemUsXG4gICAgICAgICAgICAgICAgICAgICBoaXN0b3J5TWF4U2l6ZSxcbiAgICAgICAgICAgICAgICAgICAgIGhpc3RvcnlNYXhHZXRNZXNzYWdlczogdGhpcy5oaXN0b3J5TWF4R2V0TWVzc2FnZXMsXG4gICAgICAgICAgICAgICAgICAgICBsYXN0TWVzc2FnZUlkIH1cbiAgICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZShpbmZvKVxuICAgICAgfSlcbiAgfVxuXG4gIGdldENvbW1vblVzZXJzICgpIHtcbiAgICByZXR1cm4gdGhpcy5yZWRpcy5zZGlmZih0aGlzLm1ha2VLZXlOYW1lKCd1c2VybGlzdCcpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMubWFrZUtleU5hbWUoJ3doaXRlbGlzdCcpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMubWFrZUtleU5hbWUoJ2FkbWlubGlzdCcpKVxuICB9XG5cbiAgbWVzc2FnZUFkZCAobXNnKSB7XG4gICAgbGV0IHRpbWVzdGFtcCA9IF8ubm93KClcbiAgICBsZXQgc21zZyA9IEpTT04uc3RyaW5naWZ5KG1zZylcbiAgICByZXR1cm4gdGhpcy5yZWRpcy5tZXNzYWdlQWRkKFxuICAgICAgdGhpcy5tYWtlS2V5TmFtZSgnbGFzdE1lc3NhZ2VJZCcpLCB0aGlzLm1ha2VLZXlOYW1lKCdoaXN0b3J5TWF4U2l6ZScpLFxuICAgICAgdGhpcy5tYWtlS2V5TmFtZSgnbWVzc2FnZXNJZHMnKSwgdGhpcy5tYWtlS2V5TmFtZSgnbWVzc2FnZXNUaW1lc3RhbXBzJyksXG4gICAgICB0aGlzLm1ha2VLZXlOYW1lKCdtZXNzYWdlc0hpc3RvcnknKSwgc21zZywgdGltZXN0YW1wKVxuICAgICAgLnNwcmVhZChpZCA9PiB7XG4gICAgICAgIG1zZy5pZCA9IGlkXG4gICAgICAgIG1zZy50aW1lc3RhbXAgPSB0aW1lc3RhbXBcbiAgICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZShtc2cpXG4gICAgICB9KVxuICB9XG5cbiAgY29udmVydE1lc3NhZ2VzIChtc2dzLCB0c3MsIGlkcykge1xuICAgIGxldCBkYXRhID0gW11cbiAgICBpZiAoIW1zZ3MpIHtcbiAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoZGF0YSlcbiAgICB9XG4gICAgZm9yIChsZXQgaWR4ID0gMDsgaWR4IDwgbXNncy5sZW5ndGg7IGlkeCsrKSB7XG4gICAgICBsZXQgbXNnID0gbXNnc1tpZHhdXG4gICAgICBsZXQgb2JqID0gSlNPTi5wYXJzZShtc2csIChrZXksIHZhbCkgPT4ge1xuICAgICAgICBpZiAodmFsICYmIHZhbC50eXBlID09PSAnQnVmZmVyJykge1xuICAgICAgICAgIHJldHVybiBuZXcgQnVmZmVyKHZhbC5kYXRhKVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHJldHVybiB2YWxcbiAgICAgICAgfVxuICAgICAgfSlcbiAgICAgIG9iai50aW1lc3RhbXAgPSBwYXJzZUludCh0c3NbaWR4XSlcbiAgICAgIG9iai5pZCA9IHBhcnNlSW50KGlkc1tpZHhdKVxuICAgICAgZGF0YVtpZHhdID0gb2JqXG4gICAgfVxuICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoZGF0YSlcbiAgfVxuXG4gIG1lc3NhZ2VzR2V0UmVjZW50ICgpIHtcbiAgICBpZiAodGhpcy5oaXN0b3J5TWF4R2V0TWVzc2FnZXMgPD0gMCkgeyByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKFtdKSB9XG4gICAgbGV0IGxpbWl0ID0gdGhpcy5oaXN0b3J5TWF4R2V0TWVzc2FnZXMgLSAxXG4gICAgcmV0dXJuIHRoaXMucmVkaXMubXVsdGkoKVxuICAgICAgLmxyYW5nZSh0aGlzLm1ha2VLZXlOYW1lKCdtZXNzYWdlc0hpc3RvcnknKSwgMCwgbGltaXQpXG4gICAgICAubHJhbmdlKHRoaXMubWFrZUtleU5hbWUoJ21lc3NhZ2VzVGltZXN0YW1wcycpLCAwLCBsaW1pdClcbiAgICAgIC5scmFuZ2UodGhpcy5tYWtlS2V5TmFtZSgnbWVzc2FnZXNJZHMnKSwgMCwgbGltaXQpXG4gICAgICAuZXhlYygpXG4gICAgICAuc3ByZWFkKChbLCBtc2dzXSwgWywgdHNzXSwgWywgaWRzXSkgPT4ge1xuICAgICAgICByZXR1cm4gdGhpcy5jb252ZXJ0TWVzc2FnZXMobXNncywgdHNzLCBpZHMpXG4gICAgICB9KVxuICB9XG5cbiAgbWVzc2FnZXNHZXQgKGlkLCBtYXhNZXNzYWdlcyA9IHRoaXMuaGlzdG9yeU1heEdldE1lc3NhZ2VzKSB7XG4gICAgaWYgKG1heE1lc3NhZ2VzIDw9IDApIHsgcmV0dXJuIFByb21pc2UucmVzb2x2ZShbXSkgfVxuICAgIGlkID0gXy5tYXgoWzAsIGlkXSlcbiAgICByZXR1cm4gdGhpcy5yZWRpcy5tZXNzYWdlc0dldChcbiAgICAgIHRoaXMubWFrZUtleU5hbWUoJ2xhc3RNZXNzYWdlSWQnKSwgdGhpcy5tYWtlS2V5TmFtZSgnaGlzdG9yeU1heFNpemUnKSxcbiAgICAgIHRoaXMubWFrZUtleU5hbWUoJ21lc3NhZ2VzSWRzJyksIHRoaXMubWFrZUtleU5hbWUoJ21lc3NhZ2VzVGltZXN0YW1wcycpLFxuICAgICAgdGhpcy5tYWtlS2V5TmFtZSgnbWVzc2FnZXNIaXN0b3J5JyksIGlkLCBtYXhNZXNzYWdlcylcbiAgICAgIC5zcHJlYWQoKG1zZ3MsIHRzcywgaWRzKSA9PiB7XG4gICAgICAgIHJldHVybiB0aGlzLmNvbnZlcnRNZXNzYWdlcyhtc2dzLCB0c3MsIGlkcylcbiAgICAgIH0pXG4gIH1cblxuICB1c2VyU2VlbkdldCAodXNlck5hbWUpIHtcbiAgICByZXR1cm4gdGhpcy5yZWRpcy5tdWx0aSgpXG4gICAgICAuaGdldCh0aGlzLm1ha2VLZXlOYW1lKCd1c2Vyc3NlZW4nKSwgdXNlck5hbWUpXG4gICAgICAuc2lzbWVtYmVyKHRoaXMubWFrZUtleU5hbWUoJ3VzZXJsaXN0JyksIHVzZXJOYW1lKVxuICAgICAgLmV4ZWMoKVxuICAgICAgLnNwcmVhZCgoWywgdHNdLCBbLCBpc2pvaW5lZF0pID0+IHtcbiAgICAgICAgbGV0IGpvaW5lZCA9IEJvb2xlYW4oaXNqb2luZWQpXG4gICAgICAgIGxldCB0aW1lc3RhbXAgPSB0cyA/IHBhcnNlSW50KHRzKSA6IG51bGxcbiAgICAgICAgcmV0dXJuIHtqb2luZWQsIHRpbWVzdGFtcH1cbiAgICAgIH0pXG4gIH1cblxuICB1c2VyU2VlblVwZGF0ZSAodXNlck5hbWUpIHtcbiAgICBsZXQgdGltZXN0YW1wID0gXy5ub3coKVxuICAgIHJldHVybiB0aGlzLnJlZGlzLmhzZXQodGhpcy5tYWtlS2V5TmFtZSgndXNlcnNzZWVuJyksIHVzZXJOYW1lLCB0aW1lc3RhbXApXG4gIH1cblxufVxuXG4vLyBJbXBsZW1lbnRzIGRpcmVjdCBtZXNzYWdpbmcgc3RhdGUgQVBJLlxuY2xhc3MgRGlyZWN0TWVzc2FnaW5nU3RhdGVSZWRpcyBleHRlbmRzIExpc3RzU3RhdGVSZWRpcyB7XG5cbiAgY29uc3RydWN0b3IgKHNlcnZlciwgdXNlck5hbWUpIHtcbiAgICBzdXBlcigpXG4gICAgdGhpcy5zZXJ2ZXIgPSBzZXJ2ZXJcbiAgICB0aGlzLnVzZXJOYW1lID0gdXNlck5hbWVcbiAgICB0aGlzLm5hbWUgPSB0aGlzLnVzZXJOYW1lXG4gICAgdGhpcy5wcmVmaXggPSAndXNlcnMnXG4gICAgdGhpcy5leGl0c0Vycm9yTmFtZSA9ICd1c2VyRXhpc3RzJ1xuICAgIHRoaXMucmVkaXMgPSB0aGlzLnNlcnZlci5yZWRpc1xuICAgIG1peGluKHRoaXMsIFN0YXRlT3BlcmF0aW9ucywgdGhpcy5uYW1lLCB0aGlzLmV4aXRzRXJyb3JOYW1lLCB0aGlzLnJlZGlzLFxuICAgICAgICAgIHRoaXMubWFrZUtleU5hbWUuYmluZCh0aGlzKSwgdGhpcy5zdGF0ZVJlc2V0LmJpbmQodGhpcykpXG4gIH1cblxuICBoYXNMaXN0IChsaXN0TmFtZSkge1xuICAgIHJldHVybiBsaXN0TmFtZSA9PT0gJ3doaXRlbGlzdCcgfHwgbGlzdE5hbWUgPT09ICdibGFja2xpc3QnXG4gIH1cblxuICBzdGF0ZVJlc2V0IChzdGF0ZSkge1xuICAgIHN0YXRlID0gc3RhdGUgfHwge31cbiAgICBsZXQgeyB3aGl0ZWxpc3QsIGJsYWNrbGlzdCwgd2hpdGVsaXN0T25seSB9ID0gc3RhdGVcbiAgICB3aGl0ZWxpc3RPbmx5ID0gd2hpdGVsaXN0T25seSA/IHRydWUgOiAnJ1xuICAgIHJldHVybiBQcm9taXNlLmFsbChbXG4gICAgICBpbml0U2V0KHRoaXMucmVkaXMsIHRoaXMubWFrZUtleU5hbWUoJ3doaXRlbGlzdCcpLCB3aGl0ZWxpc3QpLFxuICAgICAgaW5pdFNldCh0aGlzLnJlZGlzLCB0aGlzLm1ha2VLZXlOYW1lKCdibGFja2xpc3QnKSwgYmxhY2tsaXN0KSxcbiAgICAgIHRoaXMucmVkaXMuc2V0KHRoaXMubWFrZUtleU5hbWUoJ3doaXRlbGlzdE1vZGUnKSwgd2hpdGVsaXN0T25seSlcbiAgICBdKS5yZXR1cm4oKVxuICB9XG5cbn1cblxuLy8gSW1wbGVtZW50cyB1c2VyIHN0YXRlIEFQSS5cbmNsYXNzIFVzZXJTdGF0ZVJlZGlzIHtcblxuICBjb25zdHJ1Y3RvciAoc2VydmVyLCB1c2VyTmFtZSkge1xuICAgIHRoaXMuc2VydmVyID0gc2VydmVyXG4gICAgdGhpcy51c2VyTmFtZSA9IHVzZXJOYW1lXG4gICAgdGhpcy5uYW1lID0gdGhpcy51c2VyTmFtZVxuICAgIHRoaXMucHJlZml4ID0gJ3VzZXJzJ1xuICAgIHRoaXMucmVkaXMgPSB0aGlzLnNlcnZlci5yZWRpc1xuICAgIG1peGluKHRoaXMsIExvY2tPcGVyYXRpb25zLCB0aGlzLnJlZGlzKVxuICB9XG5cbiAgbWFrZUtleU5hbWUgKGtleU5hbWUpIHtcbiAgICByZXR1cm4gYCR7bmFtZXNwYWNlfToke3RoaXMucHJlZml4fTp7JHt0aGlzLm5hbWV9fToke2tleU5hbWV9YFxuICB9XG5cbiAgbWFrZVNvY2tldFRvUm9vbXMgKGlkID0gJycpIHtcbiAgICByZXR1cm4gdGhpcy5tYWtlS2V5TmFtZShgc29ja2V0c1RvUm9vbXM6JHtpZH1gKVxuICB9XG5cbiAgbWFrZVJvb21Ub1NvY2tldHMgKHJvb20gPSAnJykge1xuICAgIHJldHVybiB0aGlzLm1ha2VLZXlOYW1lKGByb29tc1RvU29ja2V0czoke3Jvb219YClcbiAgfVxuXG4gIG1ha2VSb29tTG9jayAocm9vbSkge1xuICAgIHJldHVybiB0aGlzLm1ha2VLZXlOYW1lKGByb29tTG9jazoke3Jvb219YClcbiAgfVxuXG4gIGFkZFNvY2tldCAoaWQsIHVpZCkge1xuICAgIHJldHVybiB0aGlzLnJlZGlzLm11bHRpKClcbiAgICAgIC5oc2V0KHRoaXMubWFrZUtleU5hbWUoJ3NvY2tldHMnKSwgaWQsIHVpZClcbiAgICAgIC5obGVuKHRoaXMubWFrZUtleU5hbWUoJ3NvY2tldHMnKSlcbiAgICAgIC5leGVjKClcbiAgICAgIC5zcHJlYWQoKF8sIFssIG5jb25uZWN0ZWRdKSA9PiBQcm9taXNlLnJlc29sdmUobmNvbm5lY3RlZCkpXG4gIH1cblxuICBnZXRBbGxTb2NrZXRzICgpIHtcbiAgICByZXR1cm4gdGhpcy5yZWRpcy5oa2V5cyh0aGlzLm1ha2VLZXlOYW1lKCdzb2NrZXRzJykpXG4gIH1cblxuICBnZXRTb2NrZXRzVG9JbnN0YW5jZSAoKSB7XG4gICAgcmV0dXJuIHRoaXMucmVkaXMuaGdldGFsbCh0aGlzLm1ha2VLZXlOYW1lKCdzb2NrZXRzJykpXG4gIH1cblxuICBnZXRSb29tVG9Tb2NrZXRzIChyb29tTmFtZSkge1xuICAgIHJldHVybiB0aGlzLnJlZGlzLnNtZW1iZXJzKHRoaXMubWFrZVJvb21Ub1NvY2tldHMocm9vbU5hbWUpKVxuICB9XG5cbiAgZ2V0U29ja2V0c1RvUm9vbXMgKCkge1xuICAgIHJldHVybiB0aGlzLnJlZGlzLmdldFNvY2tldHNUb1Jvb21zKFxuICAgICAgdGhpcy5tYWtlS2V5TmFtZSgnc29ja2V0cycpLCB0aGlzLm1ha2VTb2NrZXRUb1Jvb21zKCkpXG4gICAgICAuc3ByZWFkKHJlc3VsdCA9PiB7XG4gICAgICAgIGxldCBkYXRhID0gSlNPTi5wYXJzZShyZXN1bHQpIHx8IHt9XG4gICAgICAgIGZvciAobGV0IFtrLCB2XSBvZiBfLnRvUGFpcnMoZGF0YSkpIHtcbiAgICAgICAgICBpZiAoXy5pc0VtcHR5KHYpKSB7IGRhdGFba10gPSBbXSB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZShkYXRhKVxuICAgICAgfSlcbiAgfVxuXG4gIGFkZFNvY2tldFRvUm9vbSAoaWQsIHJvb21OYW1lKSB7XG4gICAgcmV0dXJuIHRoaXMucmVkaXMubXVsdGkoKVxuICAgICAgLnNhZGQodGhpcy5tYWtlU29ja2V0VG9Sb29tcyhpZCksIHJvb21OYW1lKVxuICAgICAgLnNhZGQodGhpcy5tYWtlUm9vbVRvU29ja2V0cyhyb29tTmFtZSksIGlkKVxuICAgICAgLnNjYXJkKHRoaXMubWFrZVJvb21Ub1NvY2tldHMocm9vbU5hbWUpKVxuICAgICAgLmV4ZWMoKVxuICAgICAgLnRoZW4oKFssICwgWywgbmpvaW5lZF1dKSA9PiBQcm9taXNlLnJlc29sdmUobmpvaW5lZCkpXG4gIH1cblxuICByZW1vdmVTb2NrZXRGcm9tUm9vbSAoaWQsIHJvb21OYW1lKSB7XG4gICAgcmV0dXJuIHRoaXMucmVkaXMubXVsdGkoKVxuICAgICAgLnNjYXJkKHRoaXMubWFrZVJvb21Ub1NvY2tldHMocm9vbU5hbWUpKVxuICAgICAgLnNyZW0odGhpcy5tYWtlU29ja2V0VG9Sb29tcyhpZCksIHJvb21OYW1lKVxuICAgICAgLnNyZW0odGhpcy5tYWtlUm9vbVRvU29ja2V0cyhyb29tTmFtZSksIGlkKVxuICAgICAgLnNjYXJkKHRoaXMubWFrZVJvb21Ub1NvY2tldHMocm9vbU5hbWUpKVxuICAgICAgLmV4ZWMoKVxuICAgICAgLnRoZW4oKFtbLCB3YXNqb2luZWRdLCAsICwgWywgbmpvaW5lZF1dKSA9PiB7XG4gICAgICAgIGxldCBoYXNDaGFuZ2VkID0gbmpvaW5lZCAhPT0gd2Fzam9pbmVkXG4gICAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoW25qb2luZWQsIGhhc0NoYW5nZWRdKVxuICAgICAgfSlcbiAgfVxuXG4gIHJlbW92ZUFsbFNvY2tldHNGcm9tUm9vbSAocm9vbU5hbWUpIHtcbiAgICByZXR1cm4gdGhpcy5yZWRpcy5yZW1vdmVBbGxTb2NrZXRzRnJvbVJvb20oXG4gICAgICB0aGlzLm1ha2VSb29tVG9Tb2NrZXRzKHJvb21OYW1lKSwgdGhpcy5tYWtlU29ja2V0VG9Sb29tcygpLCByb29tTmFtZSlcbiAgICAgIC5zcHJlYWQocmVzdWx0ID0+IFByb21pc2UucmVzb2x2ZShKU09OLnBhcnNlKHJlc3VsdCkpKVxuICB9XG5cbiAgcmVtb3ZlU29ja2V0IChpZCkge1xuICAgIHJldHVybiB0aGlzLnJlZGlzLnJlbW92ZVNvY2tldChcbiAgICAgIHRoaXMubWFrZVNvY2tldFRvUm9vbXMoaWQpLCB0aGlzLm1ha2VLZXlOYW1lKCdzb2NrZXRzJyksXG4gICAgICB0aGlzLm1ha2VSb29tVG9Tb2NrZXRzKCksIGlkKVxuICAgICAgLnNwcmVhZChyZXN1bHQgPT4gUHJvbWlzZS5yZXNvbHZlKEpTT04ucGFyc2UocmVzdWx0KSkpXG4gIH1cblxuICBsb2NrVG9Sb29tIChyb29tTmFtZSwgdHRsKSB7XG4gICAgcmV0dXJuIHVpZCgxOCkudGhlbih2YWwgPT4ge1xuICAgICAgbGV0IHN0YXJ0ID0gXy5ub3coKVxuICAgICAgcmV0dXJuIHRoaXMubG9jayh0aGlzLm1ha2VSb29tTG9jayhyb29tTmFtZSksIHZhbCwgdHRsKS50aGVuKCgpID0+IHtcbiAgICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpLmRpc3Bvc2VyKCgpID0+IHtcbiAgICAgICAgICBpZiAoc3RhcnQgKyB0dGwgPCBfLm5vdygpKSB7XG4gICAgICAgICAgICB0aGlzLnNlcnZlci5lbWl0KFxuICAgICAgICAgICAgICAnbG9ja1RpbWVFeGNlZWRlZCcsIHZhbCwge3VzZXJOYW1lOiB0aGlzLnVzZXJOYW1lLCByb29tTmFtZX0pXG4gICAgICAgICAgfVxuICAgICAgICAgIHJldHVybiB0aGlzLnVubG9jayh0aGlzLm1ha2VSb29tTG9jayhyb29tTmFtZSksIHZhbClcbiAgICAgICAgfSlcbiAgICAgIH0pXG4gICAgfSlcbiAgfVxuXG59XG5cbi8vIEltcGxlbWVudHMgZ2xvYmFsIHN0YXRlIEFQSS5cbmNsYXNzIFJlZGlzU3RhdGUge1xuXG4gIGNvbnN0cnVjdG9yIChzZXJ2ZXIsIG9wdGlvbnMpIHtcbiAgICB0aGlzLnNlcnZlciA9IHNlcnZlclxuICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnNcbiAgICB0aGlzLmNsb3NlZCA9IGZhbHNlXG4gICAgaWYgKHRoaXMub3B0aW9ucy51c2VDbHVzdGVyKSB7XG4gICAgICB0aGlzLnJlZGlzID0gbmV3IFJlZGlzLkNsdXN0ZXIoLi4udGhpcy5vcHRpb25zLnJlZGlzT3B0aW9ucylcbiAgICB9IGVsc2Uge1xuICAgICAgbGV0IHJlZGlzT3B0aW9ucyA9IF8uY2FzdEFycmF5KHRoaXMub3B0aW9ucy5yZWRpc09wdGlvbnMpXG4gICAgICB0aGlzLnJlZGlzID0gbmV3IFJlZGlzKC4uLnJlZGlzT3B0aW9ucylcbiAgICB9XG4gICAgdGhpcy5Sb29tU3RhdGUgPSBSb29tU3RhdGVSZWRpc1xuICAgIHRoaXMuVXNlclN0YXRlID0gVXNlclN0YXRlUmVkaXNcbiAgICB0aGlzLkRpcmVjdE1lc3NhZ2luZ1N0YXRlID0gRGlyZWN0TWVzc2FnaW5nU3RhdGVSZWRpc1xuICAgIHRoaXMubG9ja1RUTCA9IHRoaXMub3B0aW9ucy5sb2NrVFRMIHx8IDEwMDAwXG4gICAgdGhpcy5pbnN0YW5jZVVJRCA9IHRoaXMuc2VydmVyLmluc3RhbmNlVUlEXG4gICAgdGhpcy5zZXJ2ZXIucmVkaXMgPSB0aGlzLnJlZGlzXG4gICAgZm9yIChsZXQgW2NtZCwgZGVmXSBvZiBfLnRvUGFpcnMobHVhQ29tbWFuZHMpKSB7XG4gICAgICB0aGlzLnJlZGlzLmRlZmluZUNvbW1hbmQoY21kLCB7XG4gICAgICAgIG51bWJlck9mS2V5czogZGVmLm51bWJlck9mS2V5cyxcbiAgICAgICAgbHVhOiBkZWYubHVhXG4gICAgICB9KVxuICAgIH1cbiAgfVxuXG4gIG1ha2VLZXlOYW1lIChwcmVmaXgsIG5hbWUsIGtleU5hbWUpIHtcbiAgICByZXR1cm4gYCR7bmFtZXNwYWNlfToke3ByZWZpeH06eyR7bmFtZX19OiR7a2V5TmFtZX1gXG4gIH1cblxuICBoYXNSb29tIChuYW1lKSB7XG4gICAgcmV0dXJuIHRoaXMucmVkaXMuZ2V0KHRoaXMubWFrZUtleU5hbWUoJ3Jvb21zJywgbmFtZSwgJ2lzSW5pdCcpKVxuICB9XG5cbiAgaGFzVXNlciAobmFtZSkge1xuICAgIHJldHVybiB0aGlzLnJlZGlzLmdldCh0aGlzLm1ha2VLZXlOYW1lKCd1c2VycycsIG5hbWUsICdpc0luaXQnKSlcbiAgfVxuXG4gIGNsb3NlICgpIHtcbiAgICB0aGlzLmNsb3NlZCA9IHRydWVcbiAgICByZXR1cm4gdGhpcy5yZWRpcy5xdWl0KCkucmV0dXJuKClcbiAgfVxuXG4gIGdldFJvb20gKG5hbWUsIGlzUHJlZGljYXRlID0gZmFsc2UpIHtcbiAgICBsZXQgcm9vbSA9IG5ldyBSb29tKHRoaXMuc2VydmVyLCBuYW1lKVxuICAgIHJldHVybiB0aGlzLmhhc1Jvb20obmFtZSkudGhlbihleGlzdHMgPT4ge1xuICAgICAgaWYgKCFleGlzdHMpIHtcbiAgICAgICAgaWYgKGlzUHJlZGljYXRlKSB7XG4gICAgICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZShudWxsKVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGxldCBlcnJvciA9IG5ldyBDaGF0U2VydmljZUVycm9yKCdub1Jvb20nLCBuYW1lKVxuICAgICAgICAgIHJldHVybiBQcm9taXNlLnJlamVjdChlcnJvcilcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZShyb29tKVxuICAgIH0pXG4gIH1cblxuICBhZGRSb29tIChuYW1lLCBzdGF0ZSkge1xuICAgIGxldCByb29tID0gbmV3IFJvb20odGhpcy5zZXJ2ZXIsIG5hbWUpXG4gICAgcmV0dXJuIHJvb20uaW5pdFN0YXRlKHN0YXRlKS5yZXR1cm4ocm9vbSlcbiAgfVxuXG4gIHJlbW92ZVJvb20gKG5hbWUpIHtcbiAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKClcbiAgfVxuXG4gIGFkZFNvY2tldCAoaWQsIHVzZXJOYW1lKSB7XG4gICAgcmV0dXJuIHRoaXMucmVkaXMuaHNldChcbiAgICAgIHRoaXMubWFrZUtleU5hbWUoJ2luc3RhbmNlcycsIHRoaXMuaW5zdGFuY2VVSUQsICdzb2NrZXRzJyksIGlkLCB1c2VyTmFtZSlcbiAgfVxuXG4gIHJlbW92ZVNvY2tldCAoaWQpIHtcbiAgICByZXR1cm4gdGhpcy5yZWRpcy5oZGVsKFxuICAgICAgdGhpcy5tYWtlS2V5TmFtZSgnaW5zdGFuY2VzJywgdGhpcy5pbnN0YW5jZVVJRCwgJ3NvY2tldHMnKSwgaWQpXG4gIH1cblxuICBnZXRJbnN0YW5jZVNvY2tldHMgKHVpZCA9IHRoaXMuaW5zdGFuY2VVSUQpIHtcbiAgICByZXR1cm4gdGhpcy5yZWRpcy5oZ2V0YWxsKHRoaXMubWFrZUtleU5hbWUoJ2luc3RhbmNlcycsIHVpZCwgJ3NvY2tldHMnKSlcbiAgfVxuXG4gIHVwZGF0ZUhlYXJ0YmVhdCAoKSB7XG4gICAgcmV0dXJuIHRoaXMucmVkaXMuc2V0KFxuICAgICAgdGhpcy5tYWtlS2V5TmFtZSgnaW5zdGFuY2VzJywgdGhpcy5pbnN0YW5jZVVJRCwgJ2hlYXJ0YmVhdCcpLCBfLm5vdygpKVxuICAgICAgLmNhdGNoUmV0dXJuKClcbiAgfVxuXG4gIGdldEluc3RhbmNlSGVhcnRiZWF0ICh1aWQgPSB0aGlzLmluc3RhbmNlVUlEKSB7XG4gICAgcmV0dXJuIHRoaXMucmVkaXMuZ2V0KHRoaXMubWFrZUtleU5hbWUoJ2luc3RhbmNlcycsIHVpZCwgJ2hlYXJ0YmVhdCcpKVxuICAgICAgLnRoZW4odHMgPT4gdHMgPyBwYXJzZUludCh0cykgOiBudWxsKVxuICB9XG5cbiAgZ2V0T3JBZGRVc2VyIChuYW1lLCBzdGF0ZSkge1xuICAgIGxldCB1c2VyID0gbmV3IFVzZXIodGhpcy5zZXJ2ZXIsIG5hbWUpXG4gICAgcmV0dXJuIHRoaXMuaGFzVXNlcihuYW1lKS50aGVuKGV4aXN0cyA9PiB7XG4gICAgICBpZiAoIWV4aXN0cykge1xuICAgICAgICByZXR1cm4gdXNlci5pbml0U3RhdGUoc3RhdGUpXG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKClcbiAgICAgIH1cbiAgICB9KS5jYXRjaChDaGF0U2VydmljZUVycm9yLCBlID0+IHVzZXIpXG4gICAgICAucmV0dXJuKHVzZXIpXG4gIH1cblxuICBnZXRVc2VyIChuYW1lLCBpc1ByZWRpY2F0ZSA9IGZhbHNlKSB7XG4gICAgbGV0IHVzZXIgPSBuZXcgVXNlcih0aGlzLnNlcnZlciwgbmFtZSlcbiAgICByZXR1cm4gdGhpcy5oYXNVc2VyKG5hbWUpLnRoZW4oZXhpc3RzID0+IHtcbiAgICAgIGlmICghZXhpc3RzKSB7XG4gICAgICAgIGlmIChpc1ByZWRpY2F0ZSkge1xuICAgICAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUobnVsbClcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBsZXQgZXJyb3IgPSBuZXcgQ2hhdFNlcnZpY2VFcnJvcignbm9Vc2VyJywgbmFtZSlcbiAgICAgICAgICByZXR1cm4gUHJvbWlzZS5yZWplY3QoZXJyb3IpXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUodXNlcilcbiAgICB9KVxuICB9XG5cbiAgYWRkVXNlciAobmFtZSwgc3RhdGUpIHtcbiAgICBsZXQgdXNlciA9IG5ldyBVc2VyKHRoaXMuc2VydmVyLCBuYW1lKVxuICAgIHJldHVybiB1c2VyLmluaXRTdGF0ZShzdGF0ZSkucmV0dXJuKHVzZXIpXG4gIH1cblxuICByZW1vdmVVc2VyIChuYW1lKSB7XG4gICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpXG4gIH1cblxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IFJlZGlzU3RhdGVcbiJdfQ== |
\ | No newline at end of file |