UNPKG

25.3 kBJavaScriptView Raw
1"use strict";
2
3var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
5Object.defineProperty(exports, "__esModule", {
6 value: true
7});
8exports["default"] = void 0;
9
10var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
11
12var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
13
14var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
15
16var _express = _interopRequireDefault(require("express"));
17
18var _http = _interopRequireDefault(require("http"));
19
20var _net = _interopRequireDefault(require("net"));
21
22var _path = _interopRequireDefault(require("path"));
23
24var _socket = _interopRequireDefault(require("socket.io"));
25
26var _inputs = _interopRequireDefault(require("./inputs"));
27
28// File path to UI app build artifacts (static JS/CSS/HTML)
29var UI_BUILD_PATH = process.env.LOGIO_SERVER_UI_BUILD_PATH || _path["default"].resolve(__dirname, 'ui');
30/**
31 * Broadcast an inbound message to socket.io channels
32 */
33
34
35function handleNewMessage(_x, _x2, _x3, _x4) {
36 return _handleNewMessage.apply(this, arguments);
37}
38/**
39 * Broadcast a new input coming online to all browsers
40 */
41
42
43function _handleNewMessage() {
44 _handleNewMessage = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee(config, inputs, io, msgParts) {
45 var _msgParts$slice, _msgParts$slice2, mtype, stream, source, msg, inputName;
46
47 return _regenerator["default"].wrap(function _callee$(_context) {
48 while (1) {
49 switch (_context.prev = _context.next) {
50 case 0:
51 _msgParts$slice = msgParts.slice(0, 3), _msgParts$slice2 = (0, _slicedToArray2["default"])(_msgParts$slice, 3), mtype = _msgParts$slice2[0], stream = _msgParts$slice2[1], source = _msgParts$slice2[2];
52 msg = msgParts.slice(3).join('|');
53 inputName = inputs.add(stream, source); // Broadcast message to input channel
54
55 io.to(inputName).emit(mtype, {
56 inputName: inputName,
57 msg: msg,
58 stream: stream,
59 source: source
60 }); // Broadcast ping to all browsers
61
62 io.emit('+ping', {
63 inputName: inputName,
64 stream: stream,
65 source: source
66 });
67
68 if (config.debug) {
69 // eslint-disable-next-line no-console
70 console.log(msgParts.join('|'));
71 }
72
73 case 6:
74 case "end":
75 return _context.stop();
76 }
77 }
78 }, _callee);
79 }));
80 return _handleNewMessage.apply(this, arguments);
81}
82
83function handleRegisterInput(_x5, _x6, _x7, _x8) {
84 return _handleRegisterInput.apply(this, arguments);
85}
86/**
87 * Broadcast an input going offline to all browsers
88 */
89
90
91function _handleRegisterInput() {
92 _handleRegisterInput = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee2(config, inputs, io, msgParts) {
93 var _msgParts$slice3, _msgParts$slice4, mtype, stream, source, inputName;
94
95 return _regenerator["default"].wrap(function _callee2$(_context2) {
96 while (1) {
97 switch (_context2.prev = _context2.next) {
98 case 0:
99 _msgParts$slice3 = msgParts.slice(0, 3), _msgParts$slice4 = (0, _slicedToArray2["default"])(_msgParts$slice3, 3), mtype = _msgParts$slice4[0], stream = _msgParts$slice4[1], source = _msgParts$slice4[2];
100 inputName = inputs.add(stream, source);
101 io.emit(mtype, {
102 stream: stream,
103 source: source,
104 inputName: inputName
105 });
106
107 case 3:
108 case "end":
109 return _context2.stop();
110 }
111 }
112 }, _callee2);
113 }));
114 return _handleRegisterInput.apply(this, arguments);
115}
116
117function handleDeregisterInput(_x9, _x10, _x11, _x12) {
118 return _handleDeregisterInput.apply(this, arguments);
119} // Maps TCP message prefix to handler function
120
121
122function _handleDeregisterInput() {
123 _handleDeregisterInput = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee3(config, inputs, io, msgParts) {
124 var _msgParts$slice5, _msgParts$slice6, mtype, stream, source, inputName;
125
126 return _regenerator["default"].wrap(function _callee3$(_context3) {
127 while (1) {
128 switch (_context3.prev = _context3.next) {
129 case 0:
130 _msgParts$slice5 = msgParts.slice(0, 3), _msgParts$slice6 = (0, _slicedToArray2["default"])(_msgParts$slice5, 3), mtype = _msgParts$slice6[0], stream = _msgParts$slice6[1], source = _msgParts$slice6[2];
131 inputName = inputs.remove(stream, source);
132 io.emit(mtype, {
133 stream: stream,
134 source: source,
135 inputName: inputName
136 });
137
138 case 3:
139 case "end":
140 return _context3.stop();
141 }
142 }
143 }, _callee3);
144 }));
145 return _handleDeregisterInput.apply(this, arguments);
146}
147
148var messageHandlers = {
149 '+msg': handleNewMessage,
150 '+input': handleRegisterInput,
151 '-input': handleDeregisterInput
152};
153/**
154 * Broadcast an inbound message to socket.io channels
155 */
156
157function broadcastMessage(_x13, _x14, _x15, _x16) {
158 return _broadcastMessage.apply(this, arguments);
159}
160/**
161 * Start message & web servers
162 */
163
164
165function _broadcastMessage() {
166 _broadcastMessage = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee5(config, inputs, io, data) {
167 var msgs;
168 return _regenerator["default"].wrap(function _callee5$(_context5) {
169 while (1) {
170 switch (_context5.prev = _context5.next) {
171 case 0:
172 // Parse raw message into parts
173 // NOTE: After split on null termination character, last item will always
174 // be either an empty string or a partial/incomplete message
175 msgs = data.toString().split('\0').slice(0, -1).filter(function (msg) {
176 return !!msg.trim();
177 });
178 msgs.forEach( /*#__PURE__*/function () {
179 var _ref = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee4(msg) {
180 var msgParts, messageHandler;
181 return _regenerator["default"].wrap(function _callee4$(_context4) {
182 while (1) {
183 switch (_context4.prev = _context4.next) {
184 case 0:
185 msgParts = msg.split('|');
186 messageHandler = messageHandlers[msgParts[0]];
187
188 if (!messageHandler) {
189 _context4.next = 7;
190 break;
191 }
192
193 _context4.next = 5;
194 return messageHandler(config, inputs, io, msgParts);
195
196 case 5:
197 _context4.next = 8;
198 break;
199
200 case 7:
201 // eslint-disable-next-line no-console
202 console.error("Unknown message type: ".concat(msgParts[0]));
203
204 case 8:
205 case "end":
206 return _context4.stop();
207 }
208 }
209 }, _callee4);
210 }));
211
212 return function (_x18) {
213 return _ref.apply(this, arguments);
214 };
215 }());
216
217 case 2:
218 case "end":
219 return _context5.stop();
220 }
221 }
222 }, _callee5);
223 }));
224 return _broadcastMessage.apply(this, arguments);
225}
226
227function main(_x17) {
228 return _main.apply(this, arguments);
229}
230
231function _main() {
232 _main = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee9(config) {
233 var server, httpServer, io, inputs, messageServer;
234 return _regenerator["default"].wrap(function _callee9$(_context9) {
235 while (1) {
236 switch (_context9.prev = _context9.next) {
237 case 0:
238 // Create HTTP server w/ static file serving & socket.io bindings
239 server = (0, _express["default"])();
240 server.use('/', _express["default"]["static"](UI_BUILD_PATH));
241 httpServer = new _http["default"].Server(server);
242 io = (0, _socket["default"])(httpServer);
243 inputs = new _inputs["default"](); // Create TCP message server
244
245 messageServer = _net["default"].createServer( /*#__PURE__*/function () {
246 var _ref2 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee7(socket) {
247 return _regenerator["default"].wrap(function _callee7$(_context7) {
248 while (1) {
249 switch (_context7.prev = _context7.next) {
250 case 0:
251 socket.on('data', /*#__PURE__*/function () {
252 var _ref3 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee6(data) {
253 return _regenerator["default"].wrap(function _callee6$(_context6) {
254 while (1) {
255 switch (_context6.prev = _context6.next) {
256 case 0:
257 _context6.next = 2;
258 return broadcastMessage(config, inputs, io, data);
259
260 case 2:
261 case "end":
262 return _context6.stop();
263 }
264 }
265 }, _callee6);
266 }));
267
268 return function (_x20) {
269 return _ref3.apply(this, arguments);
270 };
271 }());
272
273 case 1:
274 case "end":
275 return _context7.stop();
276 }
277 }
278 }, _callee7);
279 }));
280
281 return function (_x19) {
282 return _ref2.apply(this, arguments);
283 };
284 }()); // When a new browser connects, register stream activation events
285
286 io.on('connection', /*#__PURE__*/function () {
287 var _ref4 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee8(socket) {
288 return _regenerator["default"].wrap(function _callee8$(_context8) {
289 while (1) {
290 switch (_context8.prev = _context8.next) {
291 case 0:
292 // Send existing inputs to browser
293 inputs.getInputs().forEach(function (input) {
294 socket.emit('+input', input);
295 }); // Register input activation events
296
297 socket.on('+activate', function (inputName) {
298 socket.join(inputName);
299 });
300 socket.on('-activate', function (inputName) {
301 socket.leave(inputName);
302 });
303
304 case 3:
305 case "end":
306 return _context8.stop();
307 }
308 }
309 }, _callee8);
310 }));
311
312 return function (_x21) {
313 return _ref4.apply(this, arguments);
314 };
315 }()); // Start listening for requests
316
317 messageServer.listen(config.messageServer.port, config.messageServer.host, function () {
318 // eslint-disable-next-line no-console
319 console.log("TCP message server listening on port ".concat(config.messageServer.port));
320 });
321 httpServer.listen(config.httpServer.port, config.httpServer.host, function () {
322 // eslint-disable-next-line no-console
323 console.log("HTTP server listening on port ".concat(config.httpServer.port));
324 });
325
326 case 9:
327 case "end":
328 return _context9.stop();
329 }
330 }
331 }, _callee9);
332 }));
333 return _main.apply(this, arguments);
334}
335
336var _default = main;
337exports["default"] = _default;
338//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9zZXJ2ZXIudHMiXSwibmFtZXMiOlsiVUlfQlVJTERfUEFUSCIsInByb2Nlc3MiLCJlbnYiLCJMT0dJT19TRVJWRVJfVUlfQlVJTERfUEFUSCIsInBhdGgiLCJyZXNvbHZlIiwiX19kaXJuYW1lIiwiaGFuZGxlTmV3TWVzc2FnZSIsImNvbmZpZyIsImlucHV0cyIsImlvIiwibXNnUGFydHMiLCJzbGljZSIsIm10eXBlIiwic3RyZWFtIiwic291cmNlIiwibXNnIiwiam9pbiIsImlucHV0TmFtZSIsImFkZCIsInRvIiwiZW1pdCIsImRlYnVnIiwiY29uc29sZSIsImxvZyIsImhhbmRsZVJlZ2lzdGVySW5wdXQiLCJoYW5kbGVEZXJlZ2lzdGVySW5wdXQiLCJyZW1vdmUiLCJtZXNzYWdlSGFuZGxlcnMiLCJicm9hZGNhc3RNZXNzYWdlIiwiZGF0YSIsIm1zZ3MiLCJ0b1N0cmluZyIsInNwbGl0IiwiZmlsdGVyIiwidHJpbSIsImZvckVhY2giLCJtZXNzYWdlSGFuZGxlciIsImVycm9yIiwibWFpbiIsInNlcnZlciIsInVzZSIsImV4cHJlc3MiLCJodHRwU2VydmVyIiwiaHR0cCIsIlNlcnZlciIsIklucHV0UmVnaXN0cnkiLCJtZXNzYWdlU2VydmVyIiwibmV0IiwiY3JlYXRlU2VydmVyIiwic29ja2V0Iiwib24iLCJnZXRJbnB1dHMiLCJpbnB1dCIsImxlYXZlIiwibGlzdGVuIiwicG9ydCIsImhvc3QiXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7OztBQUFBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUdBO0FBQ0EsSUFBTUEsYUFBYSxHQUFHQyxPQUFPLENBQUNDLEdBQVIsQ0FBWUMsMEJBQVosSUFDakJDLGlCQUFLQyxPQUFMLENBQWFDLFNBQWIsRUFBd0IsSUFBeEIsQ0FETDtBQUdBOzs7OztTQUdlQyxnQjs7O0FBbUJmOzs7Ozs7b0dBbkJBLGlCQUNFQyxNQURGLEVBRUVDLE1BRkYsRUFHRUMsRUFIRixFQUlFQyxRQUpG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LHdCQUFBQSxNQUFNLENBQUNDLEVBQVAsQ0FBVSxXQUFWLEVBQXVCLFVBQUNqQyxTQUFELEVBQWU7QUFDcENnQywwQkFBQUEsTUFBTSxDQUFDSSxLQUFQLENBQWFwQyxTQUFiO0FBQ0QseUJBRkQ7O0FBVGtCO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBLGVBQXBCOztBQUFBO0FBQUE7QUFBQTtBQUFBLGlCQWhCRixDQThCRTs7QUFDQTZCLFlBQUFBLGFBQWEsQ0FBQ1EsTUFBZCxDQUFxQi9DLE1BQU0sQ0FBQ3VDLGFBQVAsQ0FBcUJTLElBQTFDLEVBQWdEaEQsTUFBTSxDQUFDdUMsYUFBUCxDQUFxQlUsSUFBckUsRUFBMkUsWUFBTTtBQUMvRTtBQUNBbEMsY0FBQUEsT0FBTyxDQUFDQyxHQUFSLGdEQUFvRGhCLE1BQU0sQ0FBQ3VDLGFBQVAsQ0FBcUJTLElBQXpFO0FBQ0QsYUFIRDtBQUlBYixZQUFBQSxVQUFVLENBQUNZLE1BQVgsQ0FBa0IvQyxNQUFNLENBQUNtQyxVQUFQLENBQWtCYSxJQUFwQyxFQUEwQ2hELE1BQU0sQ0FBQ21DLFVBQVAsQ0FBa0JjLElBQTVELEVBQWtFLFlBQU07QUFDdEU7QUFDQWxDLGNBQUFBLE9BQU8sQ0FBQ0MsR0FBUix5Q0FBNkNoQixNQUFNLENBQUNtQyxVQUFQLENBQWtCYSxJQUEvRDtBQUNELGFBSEQ7O0FBbkNGO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBLEc7Ozs7ZUF5Q2VqQixJIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IGV4cHJlc3MgZnJvbSAnZXhwcmVzcydcbmltcG9ydCBodHRwIGZyb20gJ2h0dHAnXG5pbXBvcnQgbmV0IGZyb20gJ25ldCdcbmltcG9ydCBwYXRoIGZyb20gJ3BhdGgnXG5pbXBvcnQgc29ja2V0aW8gZnJvbSAnc29ja2V0LmlvJ1xuaW1wb3J0IElucHV0UmVnaXN0cnkgZnJvbSAnLi9pbnB1dHMnXG5pbXBvcnQgeyBNZXNzYWdlSGFuZGxlcnMsIFNlcnZlckNvbmZpZyB9IGZyb20gJy4vdHlwZXMnXG5cbi8vIEZpbGUgcGF0aCB0byBVSSBhcHAgYnVpbGQgYXJ0aWZhY3RzIChzdGF0aWMgSlMvQ1NTL0hUTUwpXG5jb25zdCBVSV9CVUlMRF9QQVRIID0gcHJvY2Vzcy5lbnYuTE9HSU9fU0VSVkVSX1VJX0JVSUxEX1BBVEhcbiAgfHwgcGF0aC5yZXNvbHZlKF9fZGlybmFtZSwgJ3VpJylcblxuLyoqXG4gKiBCcm9hZGNhc3QgYW4gaW5ib3VuZCBtZXNzYWdlIHRvIHNvY2tldC5pbyBjaGFubmVsc1xuICovXG5hc3luYyBmdW5jdGlvbiBoYW5kbGVOZXdNZXNzYWdlKFxuICBjb25maWc6IFNlcnZlckNvbmZpZyxcbiAgaW5wdXRzOiBJbnB1dFJlZ2lzdHJ5LFxuICBpbzogU29ja2V0SU8uU2VydmVyLFxuICBtc2dQYXJ0czogQXJyYXk8c3RyaW5nPixcbik6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCBbbXR5cGUsIHN0cmVhbSwgc291cmNlXSA9IG1zZ1BhcnRzLnNsaWNlKDAsIDMpXG4gIGNvbnN0IG1zZyA9IG1zZ1BhcnRzLnNsaWNlKDMpLmpvaW4oJ3wnKVxuICBjb25zdCBpbnB1dE5hbWUgPSBpbnB1dHMuYWRkKHN0cmVhbSwgc291cmNlKVxuICAvLyBCcm9hZGNhc3QgbWVzc2FnZSB0byBpbnB1dCBjaGFubmVsXG4gIGlvLnRvKGlucHV0TmFtZSkuZW1pdChtdHlwZSwgeyBpbnB1dE5hbWUsIG1zZywgc3RyZWFtLCBzb3VyY2UgfSlcbiAgLy8gQnJvYWRjYXN0IHBpbmcgdG8gYWxsIGJyb3dzZXJzXG4gIGlvLmVtaXQoJytwaW5nJywgeyBpbnB1dE5hbWUsIHN0cmVhbSwgc291cmNlIH0pXG4gIGlmIChjb25maWcuZGVidWcpIHtcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tY29uc29sZVxuICAgIGNvbnNvbGUubG9nKG1zZ1BhcnRzLmpvaW4oJ3wnKSlcbiAgfVxufVxuXG4vKipcbiAqIEJyb2FkY2FzdCBhIG5ldyBpbnB1dCBjb21pbmcgb25saW5lIHRvIGFsbCBicm93c2Vyc1xuICovXG5hc3luYyBmdW5jdGlvbiBoYW5kbGVSZWdpc3RlcklucHV0KFxuICBjb25maWc6IFNlcnZlckNvbmZpZyxcbiAgaW5wdXRzOiBJbnB1dFJlZ2lzdHJ5LFxuICBpbzogU29ja2V0SU8uU2VydmVyLFxuICBtc2dQYXJ0czogQXJyYXk8c3RyaW5nPixcbik6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCBbbXR5cGUsIHN0cmVhbSwgc291cmNlXSA9IG1zZ1BhcnRzLnNsaWNlKDAsIDMpXG4gIGNvbnN0IGlucHV0TmFtZSA9IGlucHV0cy5hZGQoc3RyZWFtLCBzb3VyY2UpXG4gIGlvLmVtaXQobXR5cGUsIHsgc3RyZWFtLCBzb3VyY2UsIGlucHV0TmFtZSB9KVxufVxuXG4vKipcbiAqIEJyb2FkY2FzdCBhbiBpbnB1dCBnb2luZyBvZmZsaW5lIHRvIGFsbCBicm93c2Vyc1xuICovXG5hc3luYyBmdW5jdGlvbiBoYW5kbGVEZXJlZ2lzdGVySW5wdXQoXG4gIGNvbmZpZzogU2VydmVyQ29uZmlnLFxuICBpbnB1dHM6IElucHV0UmVnaXN0cnksXG4gIGlvOiBTb2NrZXRJTy5TZXJ2ZXIsXG4gIG1zZ1BhcnRzOiBBcnJheTxzdHJpbmc+LFxuKTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IFttdHlwZSwgc3RyZWFtLCBzb3VyY2VdID0gbXNnUGFydHMuc2xpY2UoMCwgMylcbiAgY29uc3QgaW5wdXROYW1lID0gaW5wdXRzLnJlbW92ZShzdHJlYW0sIHNvdXJjZSlcbiAgaW8uZW1pdChtdHlwZSwgeyBzdHJlYW0sIHNvdXJjZSwgaW5wdXROYW1lIH0pXG59XG5cbi8vIE1hcHMgVENQIG1lc3NhZ2UgcHJlZml4IHRvIGhhbmRsZXIgZnVuY3Rpb25cbmNvbnN0IG1lc3NhZ2VIYW5kbGVyczogTWVzc2FnZUhhbmRsZXJzID0ge1xuICAnK21zZyc6IGhhbmRsZU5ld01lc3NhZ2UsXG4gICcraW5wdXQnOiBoYW5kbGVSZWdpc3RlcklucHV0LFxuICAnLWlucHV0JzogaGFuZGxlRGVyZWdpc3RlcklucHV0LFxufVxuXG4vKipcbiAqIEJyb2FkY2FzdCBhbiBpbmJvdW5kIG1lc3NhZ2UgdG8gc29ja2V0LmlvIGNoYW5uZWxzXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGJyb2FkY2FzdE1lc3NhZ2UoXG4gIGNvbmZpZzogU2VydmVyQ29uZmlnLFxuICBpbnB1dHM6IElucHV0UmVnaXN0cnksXG4gIGlvOiBTb2NrZXRJTy5TZXJ2ZXIsXG4gIGRhdGE6IEJ1ZmZlcixcbik6IFByb21pc2U8dm9pZD4ge1xuICAvLyBQYXJzZSByYXcgbWVzc2FnZSBpbnRvIHBhcnRzXG4gIC8vIE5PVEU6IEFmdGVyIHNwbGl0IG9uIG51bGwgdGVybWluYXRpb24gY2hhcmFjdGVyLCBsYXN0IGl0ZW0gd2lsbCBhbHdheXNcbiAgLy8gYmUgZWl0aGVyIGFuIGVtcHR5IHN0cmluZyBvciBhIHBhcnRpYWwvaW5jb21wbGV0ZSBtZXNzYWdlXG4gIGNvbnN0IG1zZ3MgPSBkYXRhLnRvU3RyaW5nKClcbiAgICAuc3BsaXQoJ1xcMCcpXG4gICAgLnNsaWNlKDAsIC0xKVxuICAgIC5maWx0ZXIobXNnID0+ICEhbXNnLnRyaW0oKSlcbiAgbXNncy5mb3JFYWNoKGFzeW5jIChtc2cpID0+IHtcbiAgICBjb25zdCBtc2dQYXJ0cyA9IG1zZy5zcGxpdCgnfCcpXG4gICAgY29uc3QgbWVzc2FnZUhhbmRsZXIgPSBtZXNzYWdlSGFuZGxlcnNbbXNnUGFydHNbMF1dXG4gICAgaWYgKG1lc3NhZ2VIYW5kbGVyKSB7XG4gICAgICBhd2FpdCBtZXNzYWdlSGFuZGxlcihjb25maWcsIGlucHV0cywgaW8sIG1zZ1BhcnRzKVxuICAgIH0gZWxzZSB7XG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tY29uc29sZVxuICAgICAgY29uc29sZS5lcnJvcihgVW5rbm93biBtZXNzYWdlIHR5cGU6ICR7bXNnUGFydHNbMF19YClcbiAgICB9XG4gIH0pXG59XG5cbi8qKlxuICogU3RhcnQgbWVzc2FnZSAmIHdlYiBzZXJ2ZXJzXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIG1haW4oY29uZmlnOiBTZXJ2ZXJDb25maWcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgLy8gQ3JlYXRlIEhUVFAgc2VydmVyIHcvIHN0YXRpYyBmaWxlIHNlcnZpbmcgJiBzb2NrZXQuaW8gYmluZGluZ3NcbiAgY29uc3Qgc2VydmVyID0gZXhwcmVzcygpXG4gIHNlcnZlci51c2UoJy8nLCBleHByZXNzLnN0YXRpYyhVSV9CVUlMRF9QQVRIKSlcbiAgY29uc3QgaHR0cFNlcnZlciA9IG5ldyBodHRwLlNlcnZlcihzZXJ2ZXIpXG4gIGNvbnN0IGlvID0gc29ja2V0aW8oaHR0cFNlcnZlcilcbiAgY29uc3QgaW5wdXRzID0gbmV3IElucHV0UmVnaXN0cnkoKVxuXG4gIC8vIENyZWF0ZSBUQ1AgbWVzc2FnZSBzZXJ2ZXJcbiAgY29uc3QgbWVzc2FnZVNlcnZlciA9IG5ldC5jcmVhdGVTZXJ2ZXIoYXN5bmMgKHNvY2tldDogbmV0LlNvY2tldCkgPT4ge1xuICAgIHNvY2tldC5vbignZGF0YScsIGFzeW5jIChkYXRhOiBCdWZmZXIpID0+IHtcbiAgICAgIGF3YWl0IGJyb2FkY2FzdE1lc3NhZ2UoY29uZmlnLCBpbnB1dHMsIGlvLCBkYXRhKVxuICAgIH0pXG4gIH0pXG5cbiAgLy8gV2hlbiBhIG5ldyBicm93c2VyIGNvbm5lY3RzLCByZWdpc3RlciBzdHJlYW0gYWN0aXZhdGlvbiBldmVudHNcbiAgaW8ub24oJ2Nvbm5lY3Rpb24nLCBhc3luYyAoc29ja2V0OiBTb2NrZXRJTy5Tb2NrZXQpID0+IHtcbiAgICAvLyBTZW5kIGV4aXN0aW5nIGlucHV0cyB0byBicm93c2VyXG4gICAgaW5wdXRzLmdldElucHV0cygpLmZvckVhY2goKGlucHV0KSA9PiB7XG4gICAgICBzb2NrZXQuZW1pdCgnK2lucHV0JywgaW5wdXQpXG4gICAgfSlcbiAgICAvLyBSZWdpc3RlciBpbnB1dCBhY3RpdmF0aW9uIGV2ZW50c1xuICAgIHNvY2tldC5vbignK2FjdGl2YXRlJywgKGlucHV0TmFtZSkgPT4ge1xuICAgICAgc29ja2V0LmpvaW4oaW5wdXROYW1lKVxuICAgIH0pXG4gICAgc29ja2V0Lm9uKCctYWN0aXZhdGUnLCAoaW5wdXROYW1lKSA9PiB7XG4gICAgICBzb2NrZXQubGVhdmUoaW5wdXROYW1lKVxuICAgIH0pXG4gIH0pXG5cbiAgLy8gU3RhcnQgbGlzdGVuaW5nIGZvciByZXF1ZXN0c1xuICBtZXNzYWdlU2VydmVyLmxpc3Rlbihjb25maWcubWVzc2FnZVNlcnZlci5wb3J0LCBjb25maWcubWVzc2FnZVNlcnZlci5ob3N0LCAoKSA9PiB7XG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLWNvbnNvbGVcbiAgICBjb25zb2xlLmxvZyhgVENQIG1lc3NhZ2Ugc2VydmVyIGxpc3RlbmluZyBvbiBwb3J0ICR7Y29uZmlnLm1lc3NhZ2VTZXJ2ZXIucG9ydH1gKVxuICB9KVxuICBodHRwU2VydmVyLmxpc3Rlbihjb25maWcuaHR0cFNlcnZlci5wb3J0LCBjb25maWcuaHR0cFNlcnZlci5ob3N0LCAoKSA9PiB7XG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLWNvbnNvbGVcbiAgICBjb25zb2xlLmxvZyhgSFRUUCBzZXJ2ZXIgbGlzdGVuaW5nIG9uIHBvcnQgJHtjb25maWcuaHR0cFNlcnZlci5wb3J0fWApXG4gIH0pXG59XG5cbmV4cG9ydCBkZWZhdWx0IG1haW5cbiJdfQ==
\No newline at end of file