UNPKG

50.3 kBJavaScriptView Raw
1/**
2 * @class TheClient
3 */
4'use strict';
5
6var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
7
8var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
9
10var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
11
12var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
13
14var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));
15
16var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread"));
17
18var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
19
20var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn"));
21
22var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf"));
23
24var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
25
26var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits"));
27
28var argx = require('argx');
29
30var asleep = require('asleep');
31
32var cookies = require('browser-cookies');
33
34var _require = require('bstorage'),
35 restore = _require.restore,
36 save = _require.save;
37
38var _require2 = require('bwindow'),
39 _get = _require2.get;
40
41var qs = require('qs');
42
43var _require3 = require('rfunc-client/shim/browser'),
44 RFuncClient = _require3.RFuncClient;
45
46var io = require('socket.io-client');
47
48var _require4 = require('the-check'),
49 isBrowser = _require4.isBrowser,
50 isProduction = _require4.isProduction,
51 unlessProduction = _require4.unlessProduction;
52
53var _require5 = require('the-pack'),
54 ThePack = _require5.ThePack;
55
56var _require6 = require('url'),
57 resolveUrl = _require6.resolve;
58
59var uuid = require('uuid');
60
61var IOEvents = require('./constants/IOEvents');
62
63var _require7 = require('./helpers'),
64 asController = _require7.asController,
65 debugController = _require7.debugController,
66 debugStream = _require7.debugStream,
67 parseClientUrl = _require7.parseClientUrl;
68
69var _require8 = require('./mixins'),
70 infoMix = _require8.infoMix,
71 pingPongMix = _require8.pingPongMix,
72 streamMix = _require8.streamMix;
73
74var debug = require('debug')('the:client');
75
76var NAMESPACE = '/rpc';
77var TheClientBase = [pingPongMix, infoMix, streamMix].reduce(function (Class, mix) {
78 return mix(Class);
79}, RFuncClient);
80
81var _ref = new ThePack({}),
82 decode = _ref.decode,
83 encode = _ref.encode;
84/** @lends TheClient */
85
86
87var TheClient =
88/*#__PURE__*/
89function (_TheClientBase) {
90 (0, _inherits2.default)(TheClient, _TheClientBase);
91 (0, _createClass2.default)(TheClient, null, [{
92 key: "for",
93 // noinspection ReservedWordAsName
94
95 /**
96 * Create the client instance
97 * @param {string} namespace
98 * @param {Object} [config={}]
99 * @returns {TheClient}
100 */
101 value: function _for() {
102 var namespace = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'default';
103 var config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
104 var key = [TheClient.CID_KEY, namespace].join('/').trim();
105 var cid = restore(key) || TheClient.newCID();
106 var client = new TheClient((0, _objectSpread2.default)({}, config, {
107 cid: cid
108 }));
109 var isBrowser = !!_get('document');
110
111 if (isBrowser) {
112 save(key, cid);
113 cookies.set(key, cid, {});
114 }
115
116 return client;
117 }
118 }]);
119
120 function TheClient(url, config) {
121 var _this;
122
123 (0, _classCallCheck2.default)(this, TheClient);
124 var args = argx(arguments);
125 url = args.shift('string');
126 config = args.pop('object') || {};
127
128 if (!url) {
129 url = parseClientUrl(config);
130 }
131
132 var _config = config,
133 _config$cid = _config.cid,
134 cid = _config$cid === void 0 ? TheClient.newCID() : _config$cid,
135 _config$forceNewSocke = _config.forceNewSocket,
136 forceNewSocket = _config$forceNewSocke === void 0 ? false : _config$forceNewSocke,
137 onGone = _config.onGone,
138 _config$version = _config.version,
139 version = _config$version === void 0 ? 'unknown' : _config$version,
140 restOptions = (0, _objectWithoutProperties2.default)(_config, ["cid", "forceNewSocket", "onGone", "version"]);
141
142 if (!url) {
143 throw new Error("[TheClient] Failed to parse urls with args ".concat(JSON.stringify(arguments)));
144 }
145
146 _this = (0, _possibleConstructorReturn2.default)(this, (0, _getPrototypeOf2.default)(TheClient).call(this, url, restOptions));
147 _this._onGone = onGone;
148 _this._forceNewSocket = forceNewSocket;
149 _this._gone = false;
150 _this._controllers = {};
151 _this._cid = cid;
152 _this._version = version;
153 _this._socket = null;
154 _this._closed = false;
155 return _this;
156 }
157
158 (0, _createClass2.default)(TheClient, [{
159 key: "assertNotClosed",
160 value: function assertNotClosed() {
161 if (this.closed) {
162 throw new Error("[TheClient] Already closed!");
163 }
164 }
165 }, {
166 key: "handleCallback",
167 value: function handleCallback(data) {
168 data = decode(data);
169 var _data = data,
170 controllerName = _data.controller,
171 name = _data.name,
172 values = _data.values;
173 var controller = this._controllers[controllerName];
174
175 if (!controller) {
176 return;
177 }
178
179 var callback = controller.callbacks[name];
180
181 if (!callback) {
182 return;
183 }
184
185 unlessProduction(function () {
186 console.groupCollapsed("[TheClient] Callback `".concat(controllerName, ".").concat(name, "()`"));
187 console.log('Signature', "`".concat(controllerName, ".").concat(name, "()`"));
188 console.log('Arguments', values);
189 console.groupEnd();
190 });
191 callback.apply(void 0, (0, _toConsumableArray2.default)(values));
192 }
193 }, {
194 key: "markAsGone",
195 value: function markAsGone() {
196 if (this._gone) {
197 return;
198 }
199
200 this._onGone && this._onGone();
201 this._gone = true;
202 }
203 }, {
204 key: "close",
205 value: function () {
206 var _close = (0, _asyncToGenerator2.default)(
207 /*#__PURE__*/
208 _regenerator.default.mark(function _callee() {
209 var socket;
210 return _regenerator.default.wrap(function _callee$(_context) {
211 while (1) {
212 switch (_context.prev = _context.next) {
213 case 0:
214 this._closed = true;
215 socket = this._socket;
216
217 if (socket) {
218 socket.close();
219 }
220
221 case 3:
222 case "end":
223 return _context.stop();
224 }
225 }
226 }, _callee, this);
227 }));
228
229 return function close() {
230 return _close.apply(this, arguments);
231 };
232 }()
233 /**
234 * Invoke a method
235 * @param {string} moduleName
236 * @param {string} methodName - Name of method to invoke
237 * @param {...*} params - Parameters
238 */
239
240 }, {
241 key: "invoke",
242 value: function () {
243 var _invoke = (0, _asyncToGenerator2.default)(
244 /*#__PURE__*/
245 _regenerator.default.mark(function _callee2(moduleName, methodName) {
246 var _len,
247 params,
248 _key,
249 cid,
250 socket,
251 iid,
252 _args2 = arguments;
253
254 return _regenerator.default.wrap(function _callee2$(_context2) {
255 while (1) {
256 switch (_context2.prev = _context2.next) {
257 case 0:
258 for (_len = _args2.length, params = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
259 params[_key - 2] = _args2[_key];
260 }
261
262 this.assertNotClosed();
263 cid = this.cid, socket = this.socket;
264 iid = uuid.v4(); // Invocation id
265
266 _context2.next = 6;
267 return new Promise(function (resolve, reject) {
268 var keptGoneTimer = -1;
269
270 var _onReturn = function onReturn(returned) {
271 if (!_onReturn) {
272 return null;
273 }
274
275 returned = decode(returned);
276
277 if (returned.iid !== iid) {
278 return;
279 }
280
281 socket.off(IOEvents.RPC_RETURN, _onReturn);
282 _onReturn = null;
283 _onKeep = null;
284 clearTimeout(keptGoneTimer);
285 var _returned = returned,
286 data = _returned.data,
287 errors = _returned.errors,
288 ok = _returned.ok;
289 debug('rpc return', moduleName, methodName, returned);
290
291 if (ok) {
292 resolve(data);
293 } else {
294 var e = errors[0];
295 reject(e.message || e);
296 }
297 };
298
299 var _onKeep = function onKeep(kept) {
300 if (!_onKeep) {
301 return;
302 }
303
304 kept = decode(kept);
305
306 if (kept.iid !== iid) {
307 return;
308 }
309
310 socket.off(IOEvents.RPC_KEEP, _onKeep);
311 _onKeep = null;
312 debug('rpc keep', moduleName, methodName);
313 clearTimeout(keptGoneTimer);
314 var _kept = kept,
315 duration = _kept.duration;
316 keptGoneTimer = setTimeout(function () {
317 // TODO throw error?
318 console.error("[TheClient] RPC call seems gone: `".concat(moduleName, ".").concat(methodName, "()`"));
319 }, duration * 2);
320 };
321
322 socket.on(IOEvents.RPC_RETURN, _onReturn);
323 socket.emit(IOEvents.RPC_CALL, encode({
324 cid: cid,
325 iid: iid,
326 methodName: methodName,
327 moduleName: moduleName,
328 params: params
329 }));
330 debug('rpc call', moduleName, methodName, params);
331 });
332
333 case 6:
334 return _context2.abrupt("return", _context2.sent);
335
336 case 7:
337 case "end":
338 return _context2.stop();
339 }
340 }
341 }, _callee2, this);
342 }));
343
344 return function invoke(_x, _x2) {
345 return _invoke.apply(this, arguments);
346 };
347 }()
348 }, {
349 key: "newSocket",
350 value: function () {
351 var _newSocket = (0, _asyncToGenerator2.default)(
352 /*#__PURE__*/
353 _regenerator.default.mark(function _callee3() {
354 var _this2 = this;
355
356 var query, socket;
357 return _regenerator.default.wrap(function _callee3$(_context3) {
358 while (1) {
359 switch (_context3.prev = _context3.next) {
360 case 0:
361 this.assertNotClosed();
362 query = qs.stringify(this.scope);
363 socket = io(resolveUrl(this.baseUrl, "".concat(NAMESPACE, "?").concat(query)), {
364 forceNew: this._forceNewSocket
365 });
366 socket.on(IOEvents.CLIENT_CALLBACK, function (data) {
367 return _this2.handleCallback(data);
368 });
369 socket.on('disconnect', function () {
370 debug('disconnect');
371
372 if (_this2.closed) {
373 return;
374 }
375
376 var goneTimer = setTimeout(function () {
377 return _this2.markAsGone();
378 }, 2 * 1000 + 2 * 1000 * Math.random());
379
380 var cancelGone = function cancelGone() {
381 debug('cancelGone');
382 clearTimeout(goneTimer);
383 socket.off('connect', cancelGone);
384 socket.off('reconnect', cancelGone);
385 };
386
387 socket.once('connect', cancelGone);
388 socket.once('reconnect', cancelGone);
389 socket.connect();
390 });
391 _context3.next = 7;
392 return new Promise(function (resolve, reject) {
393 socket.on('connect', function () {
394 debug('connect');
395 resolve(socket);
396 });
397 socket.on('error', function (e) {
398 debug('error', e);
399 reject(e);
400 });
401 });
402
403 case 7:
404 return _context3.abrupt("return", socket);
405
406 case 8:
407 case "end":
408 return _context3.stop();
409 }
410 }
411 }, _callee3, this);
412 }));
413
414 return function newSocket() {
415 return _newSocket.apply(this, arguments);
416 };
417 }()
418 /**
419 * Create an stream to server
420 * @param {string} name
421 * @param {Object} params - Stream params
422 * @param {Object} [options={}] - Optional setting
423 * @param {Boolean} [options.debug] - With debug mode
424 * @returns {*}
425 */
426
427 }, {
428 key: "stream",
429 value: function () {
430 var _stream = (0, _asyncToGenerator2.default)(
431 /*#__PURE__*/
432 _regenerator.default.mark(function _callee4(name) {
433 var params,
434 options,
435 _options$debug,
436 debug,
437 stream,
438 _args4 = arguments;
439
440 return _regenerator.default.wrap(function _callee4$(_context4) {
441 while (1) {
442 switch (_context4.prev = _context4.next) {
443 case 0:
444 params = _args4.length > 1 && _args4[1] !== undefined ? _args4[1] : {};
445 options = _args4.length > 2 && _args4[2] !== undefined ? _args4[2] : {};
446 this.assertNotClosed();
447 _options$debug = options.debug, debug = _options$debug === void 0 ? !isProduction() && isBrowser() : _options$debug;
448
449 if (this._socket) {
450 _context4.next = 8;
451 break;
452 }
453
454 _context4.next = 7;
455 return this.newSocket();
456
457 case 7:
458 this._socket = _context4.sent;
459
460 case 8:
461 _context4.next = 10;
462 return this.openStream(name, params);
463
464 case 10:
465 stream = _context4.sent;
466 return _context4.abrupt("return", debug ? debugStream(stream) : stream);
467
468 case 12:
469 case "end":
470 return _context4.stop();
471 }
472 }
473 }, _callee4, this);
474 }));
475
476 return function stream(_x3) {
477 return _stream.apply(this, arguments);
478 };
479 }()
480 /**
481 * Use a controller module
482 * @param {string} controllerName - Module name
483 * @param {Object} [options={}] - Optional setting
484 * @param {Boolean} [options.debug] - With debug mode
485 * @returns {*}
486 */
487
488 }, {
489 key: "use",
490 value: function () {
491 var _use = (0, _asyncToGenerator2.default)(
492 /*#__PURE__*/
493 _regenerator.default.mark(function _callee5(controllerName) {
494 var options,
495 _options$debug2,
496 debug,
497 controller,
498 instance,
499 spec,
500 cid,
501 _args5 = arguments;
502
503 return _regenerator.default.wrap(function _callee5$(_context5) {
504 while (1) {
505 switch (_context5.prev = _context5.next) {
506 case 0:
507 options = _args5.length > 1 && _args5[1] !== undefined ? _args5[1] : {};
508 this.assertNotClosed();
509 _options$debug2 = options.debug, debug = _options$debug2 === void 0 ? !isProduction() && isBrowser() : _options$debug2;
510 controller = this._controllers[controllerName];
511
512 if (this._socket) {
513 _context5.next = 8;
514 break;
515 }
516
517 _context5.next = 7;
518 return this.newSocket();
519
520 case 7:
521 this._socket = _context5.sent;
522
523 case 8:
524 if (controller) {
525 _context5.next = 19;
526 break;
527 }
528
529 _context5.next = 11;
530 return this.connect(controllerName);
531
532 case 11:
533 instance = _context5.sent;
534 _context5.next = 14;
535 return this.describe(controllerName);
536
537 case 14:
538 spec = _context5.sent;
539 cid = this.cid;
540 controller = asController(instance, spec, {
541 cid: cid
542 });
543
544 if (debug) {
545 controller = debugController(controller);
546 }
547
548 this._controllers[controllerName] = controller;
549
550 case 19:
551 return _context5.abrupt("return", controller);
552
553 case 20:
554 case "end":
555 return _context5.stop();
556 }
557 }
558 }, _callee5, this);
559 }));
560
561 return function use(_x4) {
562 return _use.apply(this, arguments);
563 };
564 }()
565 /**
566 * Use all controller modules
567 * @param {Object} [options={}] - Optional setting
568 * @returns {Promise<Object>}
569 */
570
571 }, {
572 key: "useAll",
573 value: function () {
574 var _useAll = (0, _asyncToGenerator2.default)(
575 /*#__PURE__*/
576 _regenerator.default.mark(function _callee6() {
577 var options,
578 serverInfo,
579 controllers,
580 controllerSpecs,
581 _iteratorNormalCompletion,
582 _didIteratorError,
583 _iteratorError,
584 _iterator,
585 _step,
586 _ref3,
587 methods,
588 name,
589 _args6 = arguments;
590
591 return _regenerator.default.wrap(function _callee6$(_context6) {
592 while (1) {
593 switch (_context6.prev = _context6.next) {
594 case 0:
595 options = _args6.length > 0 && _args6[0] !== undefined ? _args6[0] : {};
596 _context6.next = 3;
597 return this.serverInfo();
598
599 case 3:
600 serverInfo = _context6.sent;
601 controllers = {};
602 controllerSpecs = serverInfo.controllers;
603 _iteratorNormalCompletion = true;
604 _didIteratorError = false;
605 _iteratorError = undefined;
606 _context6.prev = 9;
607 _iterator = controllerSpecs[Symbol.iterator]();
608
609 case 11:
610 if (_iteratorNormalCompletion = (_step = _iterator.next()).done) {
611 _context6.next = 21;
612 break;
613 }
614
615 _ref3 = _step.value;
616 methods = _ref3.methods, name = _ref3.name;
617 this.specs[name] = {
618 methods: methods,
619 name: name
620 };
621 _context6.next = 17;
622 return this.use(name, options);
623
624 case 17:
625 controllers[name] = _context6.sent;
626
627 case 18:
628 _iteratorNormalCompletion = true;
629 _context6.next = 11;
630 break;
631
632 case 21:
633 _context6.next = 27;
634 break;
635
636 case 23:
637 _context6.prev = 23;
638 _context6.t0 = _context6["catch"](9);
639 _didIteratorError = true;
640 _iteratorError = _context6.t0;
641
642 case 27:
643 _context6.prev = 27;
644 _context6.prev = 28;
645
646 if (!_iteratorNormalCompletion && _iterator.return != null) {
647 _iterator.return();
648 }
649
650 case 30:
651 _context6.prev = 30;
652
653 if (!_didIteratorError) {
654 _context6.next = 33;
655 break;
656 }
657
658 throw _iteratorError;
659
660 case 33:
661 return _context6.finish(30);
662
663 case 34:
664 return _context6.finish(27);
665
666 case 35:
667 unlessProduction(function () {
668 if (typeof Proxy === 'undefined') {
669 return controllers;
670 }
671
672 return new Proxy(controllers, {
673 get: function get(target, key) {
674 var has = key in target;
675
676 if (!has) {
677 console.warn("[TheClient] Unknown controller name: \"".concat(key, "\""));
678 }
679
680 return target[key];
681 }
682 });
683 });
684 return _context6.abrupt("return", controllers);
685
686 case 37:
687 case "end":
688 return _context6.stop();
689 }
690 }
691 }, _callee6, this, [[9, 23, 27, 35], [28,, 30, 34]]);
692 }));
693
694 return function useAll() {
695 return _useAll.apply(this, arguments);
696 };
697 }()
698 }, {
699 key: "cid",
700 get: function get() {
701 return this._cid;
702 }
703 }, {
704 key: "closed",
705 get: function get() {
706 return this._closed;
707 }
708 }, {
709 key: "scope",
710 get: function get() {
711 var cid = this._cid,
712 rpc = this._rpc,
713 version = this._version;
714
715 var language = _get('navigator.language');
716
717 return {
718 /** Caller key */
719 callerKey: rpc && rpc.as,
720
721 /** Client ID */
722 cid: cid,
723
724 /** Host of client */
725 host: _get('location.host'),
726
727 /** Detected lang */
728 lang: language && language.split('-')[0],
729
730 /** Connecting protocol */
731 protocol: _get('location.protocol'),
732
733 /** Client instance version number */
734 v: version,
735
736 /** Via client */
737 via: 'client'
738 };
739 }
740 }, {
741 key: "socket",
742 get: function get() {
743 return this._socket;
744 }
745 }]);
746 return TheClient;
747}(TheClientBase);
748
749TheClient.RPC_ACTOR_NAME = 'rpc';
750TheClient.CID_KEY = 'the:cid';
751
752TheClient.newCID = function () {
753 return uuid.v4();
754};
755
756module.exports = TheClient;
757//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIlRoZUNsaWVudC5qcyJdLCJuYW1lcyI6WyJhcmd4IiwicmVxdWlyZSIsImFzbGVlcCIsImNvb2tpZXMiLCJyZXN0b3JlIiwic2F2ZSIsImdldCIsInFzIiwiUkZ1bmNDbGllbnQiLCJpbyIsImlzQnJvd3NlciIsImlzUHJvZHVjdGlvbiIsInVubGVzc1Byb2R1Y3Rpb24iLCJUaGVQYWNrIiwicmVzb2x2ZVVybCIsInJlc29sdmUiLCJ1dWlkIiwiSU9FdmVudHMiLCJhc0NvbnRyb2xsZXIiLCJkZWJ1Z0NvbnRyb2xsZXIiLCJkZWJ1Z1N0cmVhbSIsInBhcnNlQ2xpZW50VXJsIiwiaW5mb01peCIsInBpbmdQb25nTWl4Iiwic3RyZWFtTWl4IiwiZGVidWciLCJOQU1FU1BBQ0UiLCJUaGVDbGllbnRCYXNlIiwicmVkdWNlIiwiQ2xhc3MiLCJtaXgiLCJkZWNvZGUiLCJlbmNvZGUiLCJUaGVDbGllbnQiLCJuYW1lc3BhY2UiLCJjb25maWciLCJrZXkiLCJDSURfS0VZIiwiam9pbiIsInRyaW0iLCJjaWQiLCJuZXdDSUQiLCJjbGllbnQiLCJzZXQiLCJ1cmwiLCJhcmdzIiwiYXJndW1lbnRzIiwic2hpZnQiLCJwb3AiLCJmb3JjZU5ld1NvY2tldCIsIm9uR29uZSIsInZlcnNpb24iLCJyZXN0T3B0aW9ucyIsIkVycm9yIiwiSlNPTiIsInN0cmluZ2lmeSIsIl9vbkdvbmUiLCJfZm9yY2VOZXdTb2NrZXQiLCJfZ29uZSIsIl9jb250cm9sbGVycyIsIl9jaWQiLCJfdmVyc2lvbiIsIl9zb2NrZXQiLCJfY2xvc2VkIiwiY2xvc2VkIiwiZGF0YSIsImNvbnRyb2xsZXJOYW1lIiwiY29udHJvbGxlciIsIm5hbWUiLCJ2YWx1ZXMiLCJjYWxsYmFjayIsImNhbGxiYWNrcyIsImNvbnNvbGUiLCJncm91cENvbGxhcHNlZCIsImxvZyIsImdyb3VwRW5kIiwic29ja2V0IiwiY2xvc2UiLCJtb2R1bGVOYW1lIiwibWV0aG9kTmFtZSIsInBhcmFtcyIsImFzc2VydE5vdENsb3NlZCIsImlpZCIsInY0IiwiUHJvbWlzZSIsInJlamVjdCIsImtlcHRHb25lVGltZXIiLCJvblJldHVybiIsInJldHVybmVkIiwib2ZmIiwiUlBDX1JFVFVSTiIsIm9uS2VlcCIsImNsZWFyVGltZW91dCIsImVycm9ycyIsIm9rIiwiZSIsIm1lc3NhZ2UiLCJrZXB0IiwiUlBDX0tFRVAiLCJkdXJhdGlvbiIsInNldFRpbWVvdXQiLCJlcnJvciIsIm9uIiwiZW1pdCIsIlJQQ19DQUxMIiwicXVlcnkiLCJzY29wZSIsImJhc2VVcmwiLCJmb3JjZU5ldyIsIkNMSUVOVF9DQUxMQkFDSyIsImhhbmRsZUNhbGxiYWNrIiwiZ29uZVRpbWVyIiwibWFya0FzR29uZSIsIk1hdGgiLCJyYW5kb20iLCJjYW5jZWxHb25lIiwib25jZSIsImNvbm5lY3QiLCJvcHRpb25zIiwibmV3U29ja2V0Iiwib3BlblN0cmVhbSIsInN0cmVhbSIsImluc3RhbmNlIiwiZGVzY3JpYmUiLCJzcGVjIiwic2VydmVySW5mbyIsImNvbnRyb2xsZXJzIiwiY29udHJvbGxlclNwZWNzIiwibWV0aG9kcyIsInNwZWNzIiwidXNlIiwiUHJveHkiLCJ0YXJnZXQiLCJoYXMiLCJ3YXJuIiwicnBjIiwiX3JwYyIsImxhbmd1YWdlIiwiY2FsbGVyS2V5IiwiYXMiLCJob3N0IiwibGFuZyIsInNwbGl0IiwicHJvdG9jb2wiLCJ2IiwidmlhIiwiUlBDX0FDVE9SX05BTUUiLCJtb2R1bGUiLCJleHBvcnRzIl0sIm1hcHBpbmdzIjoiQUFBQTs7O0FBR0E7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUVBLElBQU1BLElBQUksR0FBR0MsT0FBTyxDQUFDLE1BQUQsQ0FBcEI7O0FBQ0EsSUFBTUMsTUFBTSxHQUFHRCxPQUFPLENBQUMsUUFBRCxDQUF0Qjs7QUFDQSxJQUFNRSxPQUFPLEdBQUdGLE9BQU8sQ0FBQyxpQkFBRCxDQUF2Qjs7ZUFDMEJBLE9BQU8sQ0FBQyxVQUFELEM7SUFBekJHLE8sWUFBQUEsTztJQUFTQyxJLFlBQUFBLEk7O2dCQUNESixPQUFP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QUFDQXVJLFFBQUFBLElBQUksRUFBRUosUUFBUSxJQUFJQSxRQUFRLENBQUNLLEtBQVQsQ0FBZSxHQUFmLEVBQW9CLENBQXBCLENBUmI7O0FBU0w7QUFDQUMsUUFBQUEsUUFBUSxFQUFFekksSUFBRyxDQUFDLG1CQUFELENBVlI7O0FBV0w7QUFDQTBJLFFBQUFBLENBQUMsRUFBRTdGLE9BWkU7O0FBYUw7QUFDQThGLFFBQUFBLEdBQUcsRUFBRTtBQWRBLE9BQVA7QUFnQkQ7Ozt3QkFFYTtBQUNaLGFBQU8sS0FBS25GLE9BQVo7QUFDRDs7O0VBL0VxQm5DLGE7O0FBb1R4Qk0sU0FBUyxDQUFDaUgsY0FBVixHQUEyQixLQUEzQjtBQUNBakgsU0FBUyxDQUFDSSxPQUFWLEdBQW9CLFNBQXBCOztBQUVBSixTQUFTLENBQUNRLE1BQVYsR0FBbUI7QUFBQSxTQUFNekIsSUFBSSxDQUFDbUUsRUFBTCxFQUFOO0FBQUEsQ0FBbkI7O0FBRUFnRSxNQUFNLENBQUNDLE9BQVAsR0FBaUJuSCxTQUFqQiIsInNvdXJjZVJvb3QiOiIuLi9saWIiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBjbGFzcyBUaGVDbGllbnRcbiAqL1xuJ3VzZSBzdHJpY3QnXG5cbmNvbnN0IGFyZ3ggPSByZXF1aXJlKCdhcmd4JylcbmNvbnN0IGFzbGVlcCA9IHJlcXVpcmUoJ2FzbGVlcCcpXG5jb25zdCBjb29raWVzID0gcmVxdWlyZSgnYnJvd3Nlci1jb29raWVzJylcbmNvbnN0IHsgcmVzdG9yZSwgc2F2ZSB9ID0gcmVxdWlyZSgnYnN0b3JhZ2UnKVxuY29uc3QgeyBnZXQgfSA9IHJlcXVpcmUoJ2J3aW5kb3cnKVxuY29uc3QgcXMgPSByZXF1aXJlKCdxcycpXG5jb25zdCB7IFJGdW5jQ2xpZW50IH0gPSByZXF1aXJlKCdyZnVuYy1jbGllbnQvc2hpbS9icm93c2VyJylcbmNvbnN0IGlvID0gcmVxdWlyZSgnc29ja2V0LmlvLWNsaWVudCcpXG5jb25zdCB7IGlzQnJvd3NlciwgaXNQcm9kdWN0aW9uLCB1bmxlc3NQcm9kdWN0aW9uIH0gPSByZXF1aXJlKCd0aGUtY2hlY2snKVxuY29uc3QgeyBUaGVQYWNrIH0gPSByZXF1aXJlKCd0aGUtcGFjaycpXG5jb25zdCB7IHJlc29sdmU6IHJlc29sdmVVcmwgfSA9IHJlcXVpcmUoJ3VybCcpXG5jb25zdCB1dWlkID0gcmVxdWlyZSgndXVpZCcpXG5jb25zdCBJT0V2ZW50cyA9IHJlcXVpcmUoJy4vY29uc3RhbnRzL0lPRXZlbnRzJylcbmNvbnN0IHtcbiAgYXNDb250cm9sbGVyLFxuICBkZWJ1Z0NvbnRyb2xsZXIsXG4gIGRlYnVnU3RyZWFtLFxuICBwYXJzZUNsaWVudFVybCxcbn0gPSByZXF1aXJlKCcuL2hlbHBlcnMnKVxuY29uc3QgeyBpbmZvTWl4LCBwaW5nUG9uZ01peCwgc3RyZWFtTWl4IH0gPSByZXF1aXJlKCcuL21peGlucycpXG5jb25zdCBkZWJ1ZyA9IHJlcXVpcmUoJ2RlYnVnJykoJ3RoZTpjbGllbnQnKVxuY29uc3QgTkFNRVNQQUNFID0gJy9ycGMnXG5cbmNvbnN0IFRoZUNsaWVudEJhc2UgPSBbXG4gIHBpbmdQb25nTWl4LFxuICBpbmZvTWl4LFxuICBzdHJlYW1NaXgsXG5dLnJlZHVjZSgoQ2xhc3MsIG1peCkgPT4gbWl4KENsYXNzKSwgUkZ1bmNDbGllbnQpXG5cbmNvbnN0IHsgZGVjb2RlLCBlbmNvZGUgfSA9IG5ldyBUaGVQYWNrKHt9KVxuXG4vKiogQGxlbmRzIFRoZUNsaWVudCAqL1xuY2xhc3MgVGhlQ2xpZW50IGV4dGVuZHMgVGhlQ2xpZW50QmFzZSB7XG4gIC8vIG5vaW5zcGVjdGlvbiBSZXNlcnZlZFdvcmRBc05hbWVcbiAgLyoqXG4gICAqIENyZWF0ZSB0aGUgY2xpZW50IGluc3RhbmNlXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lc3BhY2VcbiAgICogQHBhcmFtIHtPYmplY3R9IFtjb25maWc9e31dXG4gICAqIEByZXR1cm5zIHtUaGVDbGllbnR9XG4gICAqL1xuICBzdGF0aWMgZm9yIChuYW1lc3BhY2UgPSAnZGVmYXVsdCcsIGNvbmZpZyA9IHt9KSB7XG4gICAgY29uc3Qga2V5ID0gW1RoZUNsaWVudC5DSURfS0VZLCBuYW1lc3BhY2VdLmpvaW4oJy8nKS50cmltKClcbiAgICBjb25zdCBjaWQgPSByZXN0b3JlKGtleSkgfHwgVGhlQ2xpZW50Lm5ld0NJRCgpXG4gICAgY29uc3QgY2xpZW50ID0gbmV3IFRoZUNsaWVudCh7IC4uLmNvbmZpZywgY2lkIH0pXG4gICAgY29uc3QgaXNCcm93c2VyID0gISFnZXQoJ2RvY3VtZW50JylcbiAgICBpZiAoaXNCcm93c2VyKSB7XG4gICAgICBzYXZlKGtleSwgY2lkKVxuICAgICAgY29va2llcy5zZXQoa2V5LCBjaWQsIHt9KVxuICAgIH1cbiAgICByZXR1cm4gY2xpZW50XG4gIH1cblxuICBjb25zdHJ1Y3RvciAodXJsLCBjb25maWcpIHtcbiAgICBjb25zdCBhcmdzID0gYXJneChhcmd1bWVudHMpXG4gICAgdXJsID0gYXJncy5zaGlmdCgnc3RyaW5nJylcbiAgICBjb25maWcgPSBhcmdzLnBvcCgnb2JqZWN0JykgfHwge31cbiAgICBpZiAoIXVybCkge1xuICAgICAgdXJsID0gcGFyc2VDbGllbnRVcmwoY29uZmlnKVxuICAgIH1cbiAgICBjb25zdCB7XG4gICAgICBjaWQgPSBUaGVDbGllbnQubmV3Q0lEKCksXG4gICAgICBmb3JjZU5ld1NvY2tldCA9IGZhbHNlLFxuICAgICAgb25Hb25lLFxuICAgICAgdmVyc2lvbiA9ICd1bmtub3duJyxcbiAgICAgIC4uLnJlc3RPcHRpb25zXG4gICAgfSA9IGNvbmZpZ1xuICAgIGlmICghdXJsKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYFtUaGVDbGllbnRdIEZhaWxlZCB0byBwYXJzZSB1cmxzIHdpdGggYXJncyAke0pTT04uc3RyaW5naWZ5KGFyZ3VtZW50cyl9YClcbiAgICB9XG4gICAgc3VwZXIodXJsLCByZXN0T3B0aW9ucylcbiAgICB0aGlzLl9vbkdvbmUgPSBvbkdvbmVcbiAgICB0aGlzLl9mb3JjZU5ld1NvY2tldCA9IGZvcmNlTmV3U29ja2V0XG4gICAgdGhpcy5fZ29uZSA9IGZhbHNlXG4gICAgdGhpcy5fY29udHJvbGxlcnMgPSB7fVxuICAgIHRoaXMuX2NpZCA9IGNpZFxuICAgIHRoaXMuX3ZlcnNpb24gPSB2ZXJzaW9uXG4gICAgdGhpcy5fc29ja2V0ID0gbnVsbFxuICAgIHRoaXMuX2Nsb3NlZCA9IGZhbHNlXG4gIH1cblxuICBnZXQgY2lkICgpIHtcbiAgICByZXR1cm4gdGhpcy5fY2lkXG4gIH1cblxuICBnZXQgY2xvc2VkICgpIHtcbiAgICByZXR1cm4gdGhpcy5fY2xvc2VkXG4gIH1cblxuICBnZXQgc2NvcGUgKCkge1xuICAgIGNvbnN0IHsgX2NpZDogY2lkLCBfcnBjOiBycGMsIF92ZXJzaW9uOiB2ZXJzaW9uIH0gPSB0aGlzXG4gICAgY29uc3QgbGFuZ3VhZ2UgPSBnZXQoJ25hdmlnYXRvci5sYW5ndWFnZScpXG4gICAgcmV0dXJuIHtcbiAgICAgIC8qKiBDYWxsZXIga2V5ICovXG4gICAgICBjYWxsZXJLZXk6IHJwYyAmJiBycGMuYXMsXG4gICAgICAvKiogQ2xpZW50IElEICovXG4gICAgICBjaWQ6IGNpZCxcbiAgICAgIC8qKiBIb3N0IG9mIGNsaWVudCAqL1xuICAgICAgaG9zdDogZ2V0KCdsb2NhdGlvbi5ob3N0JyksXG4gICAgICAvKiogRGV0ZWN0ZWQgbGFuZyAqL1xuICAgICAgbGFuZzogbGFuZ3VhZ2UgJiYgbGFuZ3VhZ2Uuc3BsaXQoJy0nKVswXSxcbiAgICAgIC8qKiBDb25uZWN0aW5nIHByb3RvY29sICovXG4gICAgICBwcm90b2NvbDogZ2V0KCdsb2NhdGlvbi5wcm90b2NvbCcpLFxuICAgICAgLyoqIENsaWVudCBpbnN0YW5jZSB2ZXJzaW9uIG51bWJlciAqL1xuICAgICAgdjogdmVyc2lvbixcbiAgICAgIC8qKiBWaWEgY2xpZW50ICovXG4gICAgICB2aWE6ICdjbGllbnQnLFxuICAgIH1cbiAgfVxuXG4gIGdldCBzb2NrZXQgKCkge1xuICAgIHJldHVybiB0aGlzLl9zb2NrZXRcbiAgfVxuXG4gIGFzc2VydE5vdENsb3NlZCAoKSB7XG4gICAgaWYgKHRoaXMuY2xvc2VkKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYFtUaGVDbGllbnRdIEFscmVhZHkgY2xvc2VkIWApXG4gICAgfVxuICB9XG5cbiAgaGFuZGxlQ2FsbGJhY2sgKGRhdGEpIHtcbiAgICBkYXRhID0gZGVjb2RlKGRhdGEpXG4gICAgY29uc3QgeyBjb250cm9sbGVyOiBjb250cm9sbGVyTmFtZSwgbmFtZSwgdmFsdWVzIH0gPSBkYXRhXG4gICAgY29uc3QgY29udHJvbGxlciA9IHRoaXMuX2NvbnRyb2xsZXJzW2NvbnRyb2xsZXJOYW1lXVxuICAgIGlmICghY29udHJvbGxlcikge1xuICAgICAgcmV0dXJuXG4gICAgfVxuICAgIGNvbnN0IGNhbGxiYWNrID0gY29udHJvbGxlci5jYWxsYmFja3NbbmFtZV1cbiAgICBpZiAoIWNhbGxiYWNrKSB7XG4gICAgICByZXR1cm5cbiAgICB9XG4gICAgdW5sZXNzUHJvZHVjdGlvbigoKSA9PiB7XG4gICAgICBjb25zb2xlLmdyb3VwQ29sbGFwc2VkKGBbVGhlQ2xpZW50XSBDYWxsYmFjayBcXGAke2NvbnRyb2xsZXJOYW1lfS4ke25hbWV9KClcXGBgKVxuICAgICAgY29uc29sZS5sb2coJ1NpZ25hdHVyZScsIGBcXGAke2NvbnRyb2xsZXJOYW1lfS4ke25hbWV9KClcXGBgKVxuICAgICAgY29uc29sZS5sb2coJ0FyZ3VtZW50cycsIHZhbHVlcylcbiAgICAgIGNvbnNvbGUuZ3JvdXBFbmQoKVxuICAgIH0pXG4gICAgY2FsbGJhY2soLi4udmFsdWVzKVxuICB9XG5cbiAgbWFya0FzR29uZSAoKSB7XG4gICAgaWYgKHRoaXMuX2dvbmUpIHtcbiAgICAgIHJldHVyblxuICAgIH1cbiAgICB0aGlzLl9vbkdvbmUgJiYgdGhpcy5fb25Hb25lKClcbiAgICB0aGlzLl9nb25lID0gdHJ1ZVxuICB9XG5cbiAgYXN5bmMgY2xvc2UgKCkge1xuICAgIHRoaXMuX2Nsb3NlZCA9IHRydWVcbiAgICBjb25zdCBzb2NrZXQgPSB0aGlzLl9zb2NrZXRcbiAgICBpZiAoc29ja2V0KSB7XG4gICAgICBzb2NrZXQuY2xvc2UoKVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBJbnZva2UgYSBtZXRob2RcbiAgICogQHBhcmFtIHtzdHJpbmd9IG1vZHVsZU5hbWVcbiAgICogQHBhcmFtIHtzdHJpbmd9IG1ldGhvZE5hbWUgLSBOYW1lIG9mIG1ldGhvZCB0byBpbnZva2VcbiAgICogQHBhcmFtIHsuLi4qfSBwYXJhbXMgLSBQYXJhbWV0ZXJzXG4gICAqL1xuICBhc3luYyBpbnZva2UgKG1vZHVsZU5hbWUsIG1ldGhvZE5hbWUsIC4uLnBhcmFtcykge1xuICAgIHRoaXMuYXNzZXJ0Tm90Q2xvc2VkKClcbiAgICBjb25zdCB7IGNpZCwgc29ja2V0IH0gPSB0aGlzXG4gICAgY29uc3QgaWlkID0gdXVpZC52NCgpIC8vIEludm9jYXRpb24gaWRcblxuICAgIHJldHVybiBhd2FpdCBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICBsZXQga2VwdEdvbmVUaW1lciA9IC0xXG4gICAgICBsZXQgb25SZXR1cm4gPSAocmV0dXJuZWQpID0+IHtcbiAgICAgICAgaWYgKCFvblJldHVybikge1xuICAgICAgICAgIHJldHVybiBudWxsXG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuZWQgPSBkZWNvZGUocmV0dXJuZWQpXG4gICAgICAgIGlmIChyZXR1cm5lZC5paWQgIT09IGlpZCkge1xuICAgICAgICAgIHJldHVyblxuICAgICAgICB9XG4gICAgICAgIHNvY2tldC5vZmYoSU9FdmVudHMuUlBDX1JFVFVSTiwgb25SZXR1cm4pXG4gICAgICAgIG9uUmV0dXJuID0gbnVsbFxuICAgICAgICBvbktlZXAgPSBudWxsXG4gICAgICAgIGNsZWFyVGltZW91dChrZXB0R29uZVRpbWVyKVxuICAgICAgICBjb25zdCB7IGRhdGEsIGVycm9ycywgb2sgfSA9IHJldHVybmVkXG4gICAgICAgIGRlYnVnKCdycGMgcmV0dXJuJywgbW9kdWxlTmFtZSwgbWV0aG9kTmFtZSwgcmV0dXJuZWQpXG4gICAgICAgIGlmIChvaykge1xuICAgICAgICAgIHJlc29sdmUoZGF0YSlcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBjb25zdCBlID0gZXJyb3JzWzBdXG4gICAgICAgICAgcmVqZWN0KGUubWVzc2FnZSB8fCBlKVxuICAgICAgICB9XG4gICAgICB9XG4gICAgICBsZXQgb25LZWVwID0gKGtlcHQpID0+IHtcbiAgICAgICAgaWYgKCFvbktlZXApIHtcbiAgICAgICAgICByZXR1cm5cbiAgICAgICAgfVxuICAgICAgICBrZXB0ID0gZGVjb2RlKGtlcHQpXG4gICAgICAgIGlmIChrZXB0LmlpZCAhPT0gaWlkKSB7XG4gICAgICAgICAgcmV0dXJuXG4gICAgICAgIH1cbiAgICAgICAgc29ja2V0Lm9mZihJT0V2ZW50cy5SUENfS0VFUCwgb25LZWVwKVxuICAgICAgICBvbktlZXAgPSBudWxsXG4gICAgICAgIGRlYnVnKCdycGMga2VlcCcsIG1vZHVsZU5hbWUsIG1ldGhvZE5hbWUpXG4gICAgICAgIGNsZWFyVGltZW91dChrZXB0R29uZVRpbWVyKVxuICAgICAgICBjb25zdCB7IGR1cmF0aW9uIH0gPSBrZXB0XG4gICAgICAgIGtlcHRHb25lVGltZXIgPSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICAvLyBUT0RPIHRocm93IGVycm9yP1xuICAgICAgICAgIGNvbnNvbGUuZXJyb3IoYFtUaGVDbGllbnRdIFJQQyBjYWxsIHNlZW1zIGdvbmU6IFxcYCR7bW9kdWxlTmFtZX0uJHttZXRob2ROYW1lfSgpXFxgYClcbiAgICAgICAgfSwgZHVyYXRpb24gKiAyKVxuICAgICAgfVxuICAgICAgc29ja2V0Lm9uKElPRXZlbnRzLlJQQ19SRVRVUk4sIG9uUmV0dXJuKVxuXG4gICAgICBzb2NrZXQuZW1pdChJT0V2ZW50cy5SUENfQ0FMTCwgZW5jb2RlKHtcbiAgICAgICAgY2lkLFxuICAgICAgICBpaWQsXG4gICAgICAgIG1ldGhvZE5hbWUsXG4gICAgICAgIG1vZHVsZU5hbWUsXG4gICAgICAgIHBhcmFtcyxcbiAgICAgIH0pKVxuICAgICAgZGVidWcoJ3JwYyBjYWxsJywgbW9kdWxlTmFtZSwgbWV0aG9kTmFtZSwgcGFyYW1zKVxuICAgIH0pXG4gIH1cblxuICBhc3luYyBuZXdTb2NrZXQgKCkge1xuICAgIHRoaXMuYXNzZXJ0Tm90Q2xvc2VkKClcbiAgICBjb25zdCBxdWVyeSA9IHFzLnN0cmluZ2lmeSh0aGlzLnNjb3BlKVxuICAgIGNvbnN0IHNvY2tldCA9IGlvKHJlc29sdmVVcmwodGhpcy5iYXNlVXJsLCBgJHtOQU1FU1BBQ0V9PyR7cXVlcnl9YCksIHtcbiAgICAgIGZvcmNlTmV3OiB0aGlzLl9mb3JjZU5ld1NvY2tldCxcbiAgICB9KVxuICAgIHNvY2tldC5vbihJT0V2ZW50cy5DTElFTlRfQ0FMTEJBQ0ssIChkYXRhKSA9PiB0aGlzLmhhbmRsZUNhbGxiYWNrKGRhdGEpKVxuICAgIHNvY2tldC5vbignZGlzY29ubmVjdCcsICgpID0+IHtcbiAgICAgIGRlYnVnKCdkaXNjb25uZWN0JylcbiAgICAgIGlmICh0aGlzLmNsb3NlZCkge1xuICAgICAgICByZXR1cm5cbiAgICAgIH1cbiAgICAgIGNvbnN0IGdvbmVUaW1lciA9IHNldFRpbWVvdXQoXG4gICAgICAgICgpID0+IHRoaXMubWFya0FzR29uZSgpLFxuICAgICAgICAyICogMTAwMCArIDIgKiAxMDAwICogTWF0aC5yYW5kb20oKVxuICAgICAgKVxuICAgICAgY29uc3QgY2FuY2VsR29uZSA9ICgpID0+IHtcbiAgICAgICAgZGVidWcoJ2NhbmNlbEdvbmUnKVxuICAgICAgICBjbGVhclRpbWVvdXQoZ29uZVRpbWVyKVxuICAgICAgICBzb2NrZXQub2ZmKCdjb25uZWN0JywgY2FuY2VsR29uZSlcbiAgICAgICAgc29ja2V0Lm9mZigncmVjb25uZWN0JywgY2FuY2VsR29uZSlcbiAgICAgIH1cbiAgICAgIHNvY2tldC5vbmNlKCdjb25uZWN0JywgY2FuY2VsR29uZSlcbiAgICAgIHNvY2tldC5vbmNlKCdyZWNvbm5lY3QnLCBjYW5jZWxHb25lKVxuICAgICAgc29ja2V0LmNvbm5lY3QoKVxuICAgIH0pXG4gICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgc29ja2V0Lm9uKCdjb25uZWN0JywgKCkgPT4ge1xuICAgICAgICBkZWJ1ZygnY29ubmVjdCcpXG4gICAgICAgIHJlc29sdmUoc29ja2V0KVxuICAgICAgfSlcbiAgICAgIHNvY2tldC5vbignZXJyb3InLCAoZSkgPT4ge1xuICAgICAgICBkZWJ1ZygnZXJyb3InLCBlKVxuICAgICAgICByZWplY3QoZSlcbiAgICAgIH0pXG4gICAgfSlcbiAgICByZXR1cm4gc29ja2V0XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlIGFuIHN0cmVhbSB0byBzZXJ2ZXJcbiAgICogQHBhcmFtIHtzdHJpbmd9IG5hbWVcbiAgICogQHBhcmFtIHtPYmplY3R9IHBhcmFtcyAtIFN0cmVhbSBwYXJhbXNcbiAgICogQHBhcmFtIHtPYmplY3R9IFtvcHRpb25zPXt9XSAtIE9wdGlvbmFsIHNldHRpbmdcbiAgICogQHBhcmFtIHtCb29sZWFufSBbb3B0aW9ucy5kZWJ1Z10gLSBXaXRoIGRlYnVnIG1vZGVcbiAgICogQHJldHVybnMgeyp9XG4gICAqL1xuICBhc3luYyBzdHJlYW0gKG5hbWUsIHBhcmFtcyA9IHt9LCBvcHRpb25zID0ge30pIHtcbiAgICB0aGlzLmFzc2VydE5vdENsb3NlZCgpXG4gICAgY29uc3Qge1xuICAgICAgZGVidWcgPSAhaXNQcm9kdWN0aW9uKCkgJiYgaXNCcm93c2VyKCksXG4gICAgfSA9IG9wdGlvbnNcbiAgICBpZiAoIXRoaXMuX3NvY2tldCkge1xuICAgICAgdGhpcy5fc29ja2V0ID0gYXdhaXQgdGhpcy5uZXdTb2NrZXQoKVxuICAgIH1cbiAgICBjb25zdCBzdHJlYW0gPSBhd2FpdCB0aGlzLm9wZW5TdHJlYW0obmFtZSwgcGFyYW1zKVxuICAgIHJldHVybiBkZWJ1ZyA/IGRlYnVnU3RyZWFtKHN0cmVhbSkgOiBzdHJlYW1cbiAgfVxuXG4gIC8qKlxuICAgKiBVc2UgYSBjb250cm9sbGVyIG1vZHVsZVxuICAgKiBAcGFyYW0ge3N0cmluZ30gY29udHJvbGxlck5hbWUgLSBNb2R1bGUgbmFtZVxuICAgKiBAcGFyYW0ge09iamVjdH0gW29wdGlvbnM9e31dIC0gT3B0aW9uYWwgc2V0dGluZ1xuICAgKiBAcGFyYW0ge0Jvb2xlYW59IFtvcHRpb25zLmRlYnVnXSAtIFdpdGggZGVidWcgbW9kZVxuICAgKiBAcmV0dXJucyB7Kn1cbiAgICovXG4gIGFzeW5jIHVzZSAoY29udHJvbGxlck5hbWUsIG9wdGlvbnMgPSB7fSkge1xuICAgIHRoaXMuYXNzZXJ0Tm90Q2xvc2VkKClcbiAgICBjb25zdCB7XG4gICAgICBkZWJ1ZyA9ICFpc1Byb2R1Y3Rpb24oKSAmJiBpc0Jyb3dzZXIoKSxcbiAgICB9ID0gb3B0aW9uc1xuICAgIGxldCBjb250cm9sbGVyID0gdGhpcy5fY29udHJvbGxlcnNbY29udHJvbGxlck5hbWVdXG4gICAgaWYgKCF0aGlzLl9zb2NrZXQpIHtcbiAgICAgIHRoaXMuX3NvY2tldCA9IGF3YWl0IHRoaXMubmV3U29ja2V0KClcbiAgICB9XG4gICAgaWYgKCFjb250cm9sbGVyKSB7XG4gICAgICBjb25zdCBpbnN0YW5jZSA9IGF3YWl0IHRoaXMuY29ubmVjdChjb250cm9sbGVyTmFtZSlcbiAgICAgIGNvbnN0IHNwZWMgPSBhd2FpdCB0aGlzLmRlc2NyaWJlKGNvbnRyb2xsZXJOYW1lKVxuICAgICAgY29uc3QgeyBjaWQgfSA9IHRoaXNcbiAgICAgIGNvbnRyb2xsZXIgPSBhc0NvbnRyb2xsZXIoaW5zdGFuY2UsIHNwZWMsIHsgY2lkIH0pXG4gICAgICBpZiAoZGVidWcpIHtcbiAgICAgICAgY29udHJvbGxlciA9IGRlYnVnQ29udHJvbGxlcihjb250cm9sbGVyKVxuICAgICAgfVxuICAgICAgdGhpcy5fY29udHJvbGxlcnNbY29udHJvbGxlck5hbWVdID0gY29udHJvbGxlclxuICAgIH1cblxuICAgIHJldHVybiBjb250cm9sbGVyXG4gIH1cblxuICAvKipcbiAgICogVXNlIGFsbCBjb250cm9sbGVyIG1vZHVsZXNcbiAgICogQHBhcmFtIHtPYmplY3R9IFtvcHRpb25zPXt9XSAtIE9wdGlvbmFsIHNldHRpbmdcbiAgICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn1cbiAgICovXG4gIGFzeW5jIHVzZUFsbCAob3B0aW9ucyA9IHt9KSB7XG4gICAgY29uc3Qgc2VydmVySW5mbyA9IGF3YWl0IHRoaXMuc2VydmVySW5mbygpXG4gICAgY29uc3QgY29udHJvbGxlcnMgPSB7fVxuICAgIGNvbnN0IGNvbnRyb2xsZXJTcGVjcyA9IHNlcnZlckluZm8uY29udHJvbGxlcnNcbiAgICBmb3IgKGNvbnN0IHsgbWV0aG9kcywgbmFtZSB9IG9mIGNvbnRyb2xsZXJTcGVjcykge1xuICAgICAgdGhpcy5zcGVjc1tuYW1lXSA9IHsgbWV0aG9kcywgbmFtZSB9XG4gICAgICBjb250cm9sbGVyc1tuYW1lXSA9IGF3YWl0IHRoaXMudXNlKG5hbWUsIG9wdGlvbnMpXG4gICAgfVxuICAgIHVubGVzc1Byb2R1Y3Rpb24oKCkgPT4ge1xuICAgICAgaWYgKHR5cGVvZiBQcm94eSA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgcmV0dXJuIGNvbnRyb2xsZXJzXG4gICAgICB9XG4gICAgICByZXR1cm4gbmV3IFByb3h5KGNvbnRyb2xsZXJzLCB7XG4gICAgICAgIGdldCAodGFyZ2V0LCBrZXkpIHtcbiAgICAgICAgICBjb25zdCBoYXMgPSBrZXkgaW4gdGFyZ2V0XG4gICAgICAgICAgaWYgKCFoYXMpIHtcbiAgICAgICAgICAgIGNvbnNvbGUud2FybihgW1RoZUNsaWVudF0gVW5rbm93biBjb250cm9sbGVyIG5hbWU6IFwiJHtrZXl9XCJgKVxuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm4gdGFyZ2V0W2tleV1cbiAgICAgICAgfSxcbiAgICAgIH0pXG4gICAgfSlcbiAgICByZXR1cm4gY29udHJvbGxlcnNcbiAgfVxufVxuXG5UaGVDbGllbnQuUlBDX0FDVE9SX05BTUUgPSAncnBjJ1xuVGhlQ2xpZW50LkNJRF9LRVkgPSAndGhlOmNpZCdcblxuVGhlQ2xpZW50Lm5ld0NJRCA9ICgpID0+IHV1aWQudjQoKVxuXG5tb2R1bGUuZXhwb3J0cyA9IFRoZUNsaWVudFxuIl19
\No newline at end of file