UNPKG

33 kBJavaScriptView Raw
1'use strict';
2
3// Small Express router that runs request handlers written as ES6 generators
4// using Node co.
5
6var _regeneratorRuntime = require('babel-runtime/regenerator')['default'];
7
8var express = require('abacus-express');
9var request = require('abacus-request');
10var batch = require('abacus-batch');
11
12var router = require('..');
13
14/* jshint noyield: true */
15
16describe('abacus-router', function () {
17 var exit = undefined;
18 beforeEach(function () {
19 // Save process.exit function as tests mock it
20 exit = process.exit;
21 });
22 afterEach(function () {
23 // Restore original process.exit function
24 process.exit = exit;
25 });
26
27 it('handles HTTP requests', function (done) {
28 // Create a test Express app
29 var app = express();
30
31 // Create a router
32 var routes = router();
33
34 // Add a simple router level middleware
35 routes.use(function (req, res, next) {
36 return next();
37 });
38
39 // Add a few test routes
40 routes.get('/ok/request', function (req, res) {
41 // Return an OK response with a body
42 res.send('okay');
43 });
44 routes.get('/ok/generator/request', _regeneratorRuntime.mark(function callee$2$0(req) {
45 return _regeneratorRuntime.wrap(function callee$2$0$(context$3$0) {
46 while (1) switch (context$3$0.prev = context$3$0.next) {
47 case 0:
48 return context$3$0.abrupt('return', {
49 body: 'okay'
50 });
51
52 case 1:
53 case 'end':
54 return context$3$0.stop();
55 }
56 }, callee$2$0, this);
57 }));
58 routes.get('/500/request', function (req, res) {
59 // Return an error status
60 res.status(500).end();
61 });
62 routes.get('/err/request/:message', function (req, res) {
63 // Return a JSON error object with a message field
64 res.status(500).send({
65 message: req.params.message
66 });
67 });
68
69 // Add our router to the app
70 app.use(routes);
71
72 // Listen on an ephemeral port
73 var server = app.listen(0);
74
75 var cbs = 0;
76 var done1 = function done1() {
77 if (++cbs === 4) done();
78 };
79
80 // Send an HTTP request, expecting an OK response
81 request.get('http://localhost::p/:v/:r', {
82 p: server.address().port,
83 v: 'ok',
84 r: 'request'
85 }, function (err, val) {
86 expect(err).to.equal(undefined);
87 expect(val.statusCode).to.equal(200);
88 expect(val.body).to.equal('okay');
89 done1();
90 });
91
92 // Send an HTTP request, expecting an OK response
93 request.get('http://localhost::p/:v/generator/:r', {
94 p: server.address().port,
95 v: 'ok',
96 r: 'request'
97 }, function (err, val) {
98 expect(err).to.equal(undefined);
99 expect(val.statusCode).to.equal(200);
100 expect(val.body).to.equal('okay');
101 done1();
102 });
103
104 // Send an HTTP request, expecting a 500 status code
105 // Here test the option to pass the URI as a field of the options object
106 request.get({
107 uri: 'http://localhost::p/:v/:r',
108 p: server.address().port,
109 v: '500',
110 r: 'request'
111 }, function (err, val) {
112 expect(err.message).to.equal('HTTP response status code 500');
113 expect(val).to.equal(undefined);
114 done1();
115 });
116
117 // Send an HTTP request, expecting an error message
118 request.get('http://localhost::p/:v/:r/:m', {
119 p: server.address().port,
120 v: 'err',
121 r: 'request',
122 m: 'duh'
123 }, function (err, val) {
124 expect(err.message).to.equal('duh');
125 expect(val).to.equal(undefined);
126 done1();
127 });
128 });
129
130 it('handles exceptions', function (done) {
131 process.exit = spy();
132
133 // Create a test Express app
134 var app = express();
135
136 // Create a router
137 var routes = router();
138
139 // Add a test route
140 routes.get('/err/generator/request/:message', _regeneratorRuntime.mark(function callee$2$0(req) {
141 return _regeneratorRuntime.wrap(function callee$2$0$(context$3$0) {
142 while (1) switch (context$3$0.prev = context$3$0.next) {
143 case 0:
144 throw new Error(req.params.message);
145
146 case 1:
147 case 'end':
148 return context$3$0.stop();
149 }
150 }, callee$2$0, this);
151 }));
152
153 // Add our router to the app
154 app.use(routes);
155
156 // Listen on an ephemeral port
157 var server = app.listen(0);
158
159 // Send an HTTP request, expecting an error message
160 request.get('http://localhost::p/:v/generator/:r/:m', {
161 p: server.address().port,
162 v: 'err',
163 r: 'request',
164 m: 'boo'
165 }, function (err, val) {
166 expect(err.message).to.equal('HTTP response status code 500');
167 expect(val).to.equal(undefined);
168 expect(process.exit.args.length).to.equal(1);
169 done();
170 });
171 });
172
173 it('handles domain asynchronous exceptions', function (done) {
174 process.exit = spy();
175
176 // Create a test Express app
177 var app = express();
178
179 // Create a router
180 var routes = router();
181
182 // Add a test route
183 routes.get('/err/request/:message', function (req, res) {
184 // Throw an asynchronous exception with a message field
185 process.nextTick(function () {
186 throw new Error(req.params.message);
187 });
188 });
189
190 // Add our router to the app
191 app.use(routes);
192
193 // Listen on an ephemeral port
194 var server = app.listen(0);
195
196 // Send an HTTP request, expecting an error message
197 request.get('http://localhost::p/:v/:r/:m', {
198 p: server.address().port,
199 v: 'err',
200 r: 'request',
201 m: 'boo'
202 }, function (err, val) {
203 expect(err.message).to.equal('HTTP response status code 500');
204 expect(val).to.equal(undefined);
205 expect(process.exit.args.length).to.equal(1);
206 done();
207 });
208 });
209
210 it('handles batched HTTP requests', function (done) {
211 // Create a test Express app
212 var app = express();
213
214 // Create a router
215 var routes = router();
216
217 // Add a few test routes
218 routes.get('/ok/request', function (req, res) {
219 // Return an OK response with a body
220 res.send('okay');
221 });
222 routes.get('/ok/generator/request', _regeneratorRuntime.mark(function callee$2$0(req) {
223 return _regeneratorRuntime.wrap(function callee$2$0$(context$3$0) {
224 while (1) switch (context$3$0.prev = context$3$0.next) {
225 case 0:
226 return context$3$0.abrupt('return', {
227 body: 'okay'
228 });
229
230 case 1:
231 case 'end':
232 return context$3$0.stop();
233 }
234 }, callee$2$0, this);
235 }));
236 routes.get('/500/request', function (req, res) {
237 // Return an error status
238 res.status(500).end();
239 });
240 routes.get('/err/request/:message', function (req, res) {
241 // Return a JSON error object with a message field
242 res.status(500).send({
243 message: req.params.message
244 });
245 });
246
247 // Add our router to the app
248 app.use(routes);
249
250 // Add batch router middleware to the app
251 app.use(router.batch(routes));
252
253 // Listen on an ephemeral port
254 var server = app.listen(0);
255
256 var cbs = 0;
257 var done1 = function done1() {
258 if (++cbs === 4) done();
259 };
260
261 // Use a batch version of the request module
262 var brequest = batch(request);
263
264 // Send an HTTP request, expecting an OK response
265 brequest.get('http://localhost::p/:v/:r', {
266 p: server.address().port,
267 v: 'ok',
268 r: 'request'
269 }, function (err, val) {
270 expect(err).to.equal(undefined);
271 expect(val.statusCode).to.equal(200);
272 expect(val.body).to.equal('okay');
273 done1();
274 });
275
276 // Send an HTTP request, expecting an OK response
277 brequest.get('http://localhost::p/:v/generator/:r', {
278 p: server.address().port,
279 v: 'ok',
280 r: 'request'
281 }, function (err, val) {
282 expect(err).to.equal(undefined);
283 expect(val.statusCode).to.equal(200);
284 expect(val.body).to.equal('okay');
285 done1();
286 });
287
288 // Send an HTTP request, expecting a 500 status code
289 // Here test the option to pass the URI as a field of the options object
290 brequest.get({
291 uri: 'http://localhost::p/:v/:r',
292 p: server.address().port,
293 v: '500',
294 r: 'request'
295 }, function (err, val) {
296 expect(err.message).to.equal('HTTP response status code 500');
297 expect(val).to.equal(undefined);
298 done1();
299 });
300
301 // Send an HTTP request, expecting an error message
302 brequest.get('http://localhost::p/:v/:r/:m', {
303 p: server.address().port,
304 v: 'err',
305 r: 'request',
306 m: 'duh'
307 }, function (err, val) {
308 expect(err.message).to.equal('duh');
309 expect(val).to.equal(undefined);
310 done1();
311 });
312 });
313
314 it('handles unhandled exceptions at middleware and' + 'responds back with a 500 for a batch http request', function (done) {
315 // Create a test Express app
316 var app = express();
317
318 // Create a router
319 var routes = router();
320
321 // Add a test route that throws an exception
322 routes.get('/exception/request', function (req, res) {
323 if (req.cause.unhandled.exception) res.status(200).send({ message: '' });
324 });
325
326 // Add our router to the app
327 app.use(routes);
328
329 // Add batch router middleware to the app
330 app.use(router.batch(routes));
331
332 // Listen on an ephemeral port
333 var server = app.listen(0);
334
335 // Use a batch version of the request module
336 var brequest = batch(request);
337
338 // Send an HTTP request, expecting a 500 status code
339 brequest.get({
340 uri: 'http://localhost::p/:v/:r',
341 p: server.address().port,
342 v: 'exception',
343 r: 'request'
344 }, function (err, val) {
345 expect(err.message).to.equal('HTTP response status code 500');
346 expect(val).to.equal(undefined);
347 done();
348 });
349 });
350});
351
352// Return an OK response with a body
353
354// Throw an exception with a message field
355
356// Return an OK response with a body
357//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy90ZXN0L3Rlc3QuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsWUFBWSxDQUFDOzs7Ozs7O0FBS2IsSUFBTSxPQUFPLEdBQUcsT0FBTyxDQUFDLGdCQUFnQixDQUFDLENBQUM7QUFDMUMsSUFBTSxPQUFPLEdBQUcsT0FBTyxDQUFDLGdCQUFnQixDQUFDLENBQUM7QUFDMUMsSUFBTSxLQUFLLEdBQUcsT0FBTyxDQUFDLGNBQWMsQ0FBQyxDQUFDOztBQUV0QyxJQUFNLE1BQU0sR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7Ozs7QUFJN0IsUUFBUSxDQUFDLGVBQWUsRUFBRSxZQUFNO0FBQzlCLE1BQUksSUFBSSxZQUFBLENBQUM7QUFDVCxZQUFVLENBQUMsWUFBTTs7QUFFZixRQUFJLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQztHQUNyQixDQUFDLENBQUM7QUFDSCxXQUFTLENBQUMsWUFBTTs7QUFFZCxXQUFPLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQztHQUNyQixDQUFDLENBQUM7O0FBRUgsSUFBRSxDQUFDLHVCQUF1QixFQUFFLFVBQUMsSUFBSSxFQUFLOztBQUVwQyxRQUFNLEdBQUcsR0FBRyxPQUFPLEVBQUUsQ0FBQzs7O0FBR3RCLFFBQU0sTUFBTSxHQUFHLE1BQU0sRUFBRSxDQUFDOzs7QUFHeEIsVUFBTSxDQUFDLEdBQUcsQ0FBQyxVQUFDLEdBQUcsRUFBRSxHQUFHLEVBQUUsSUFBSTthQUFLLElBQUksRUFBRTtLQUFBLENBQUMsQ0FBQzs7O0FBR3ZDLFVBQU0sQ0FBQyxHQUFHLENBQUMsYUFBYSxFQUFFLFVBQUMsR0FBRyxFQUFFLEdBQUcsRUFBSzs7QUFFdEMsU0FBRyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztLQUNsQixDQUFDLENBQUM7QUFDSCxVQUFNLENBQUMsR0FBRyxDQUFDLHVCQUF1QiwyQkFBRSxvQkFBVyxHQUFHOzs7O2dEQUV6QztBQUNMLGtCQUFJLEVBQUUsTUFBTTthQUNiOzs7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QUFNLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMsK0JBQStCLENBQUMsQ0FBQztBQUM5RCxZQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsQ0FBQztBQUNoQyxVQUFJLEVBQUUsQ0FBQztLQUNSLENBQUMsQ0FBQztHQUNKLENBQUMsQ0FBQztDQUNOLENBQUMsQ0FBQyIsImZpbGUiOiJ0ZXN0LmpzIiwic291cmNlc0NvbnRlbnQiOlsiJ3VzZSBzdHJpY3QnO1xuXG4vLyBTbWFsbCBFeHByZXNzIHJvdXRlciB0aGF0IHJ1bnMgcmVxdWVzdCBoYW5kbGVycyB3cml0dGVuIGFzIEVTNiBnZW5lcmF0b3JzXG4vLyB1c2luZyBOb2RlIGNvLlxuXG5jb25zdCBleHByZXNzID0gcmVxdWlyZSgnYWJhY3VzLWV4cHJlc3MnKTtcbmNvbnN0IHJlcXVlc3QgPSByZXF1aXJlKCdhYmFjdXMtcmVxdWVzdCcpO1xuY29uc3QgYmF0Y2ggPSByZXF1aXJlKCdhYmFjdXMtYmF0Y2gnKTtcblxuY29uc3Qgcm91dGVyID0gcmVxdWlyZSgnLi4nKTtcblxuLyoganNoaW50IG5veWllbGQ6IHRydWUgKi9cblxuZGVzY3JpYmUoJ2FiYWN1cy1yb3V0ZXInLCAoKSA9PiB7XG4gIGxldCBleGl0O1xuICBiZWZvcmVFYWNoKCgpID0+IHtcbiAgICAvLyBTYXZlIHByb2Nlc3MuZXhpdCBmdW5jdGlvbiBhcyB0ZXN0cyBtb2NrIGl0XG4gICAgZXhpdCA9IHByb2Nlc3MuZXhpdDtcbiAgfSk7XG4gIGFmdGVyRWFjaCgoKSA9PiB7XG4gICAgLy8gUmVzdG9yZSBvcmlnaW5hbCBwcm9jZXNzLmV4aXQgZnVuY3Rpb25cbiAgICBwcm9jZXNzLmV4aXQgPSBleGl0O1xuICB9KTtcblxuICBpdCgnaGFuZGxlcyBIVFRQIHJlcXVlc3RzJywgKGRvbmUpID0+IHtcbiAgICAvLyBDcmVhdGUgYSB0ZXN0IEV4cHJlc3MgYXBwXG4gICAgY29uc3QgYXBwID0gZXhwcmVzcygpO1xuXG4gICAgLy8gQ3JlYXRlIGEgcm91dGVyXG4gICAgY29uc3Qgcm91dGVzID0gcm91dGVyKCk7XG5cbiAgICAvLyBBZGQgYSBzaW1wbGUgcm91dGVyIGxldmVsIG1pZGRsZXdhcmVcbiAgICByb3V0ZXMudXNlKChyZXEsIHJlcywgbmV4dCkgPT4gbmV4dCgpKTtcblxuICAgIC8vIEFkZCBhIGZldyB0ZXN0IHJvdXRlc1xuICAgIHJvdXRlcy5nZXQoJy9vay9yZXF1ZXN0JywgKHJlcSwgcmVzKSA9PiB7XG4gICAgICAvLyBSZXR1cm4gYW4gT0sgcmVzcG9uc2Ugd2l0aCBhIGJvZHlcbiAgICAgIHJlcy5zZW5kKCdva2F5Jyk7XG4gICAgfSk7XG4gICAgcm91dGVzLmdldCgnL29rL2dlbmVyYXRvci9yZXF1ZXN0JywgZnVuY3Rpb24gKihyZXEpIHtcbiAgICAgIC8vIFJldHVybiBhbiBPSyByZXNwb25zZSB3aXRoIGEgYm9keVxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgYm9keTogJ29rYXknXG4gICAgICB9O1xuICAgIH0pO1xuICAgIHJvdXRlcy5nZXQoJy81MDAvcmVxdWVzdCcsIChyZXEsIHJlcykgPT4ge1xuICAgICAgLy8gUmV0dXJuIGFuIGVycm9yIHN0YXR1c1xuICAgICAgcmVzLnN0YXR1cyg1MDApLmVuZCgpO1xuICAgIH0pO1xuICAgIHJvdXRlcy5nZXQoJy9lcnIvcmVxdWVzdC86bWVzc2FnZScsIChyZXEsIHJlcykgPT4ge1xuICAgICAgLy8gUmV0dXJuIGEgSlNPTiBlcnJvciBvYmplY3Qgd2l0aCBhIG1lc3NhZ2UgZmllbGRcbiAgICAgIHJlcy5zdGF0dXMoNTAwKS5zZW5kKHtcbiAgICAgICAgbWVzc2FnZTogcmVxLnBhcmFtcy5tZXNzYWdlXG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIC8vIEFkZCBvdXIgcm91dGVyIHRvIHRoZSBhcHBcbiAgICBhcHAudXNlKHJvdXRlcyk7XG5cbiAgICAvLyBMaXN0ZW4gb24gYW4gZXBoZW1lcmFsIHBvcnRcbiAgICBjb25zdCBzZXJ2ZXIgPSBhcHAubGlzdGVuKDApO1xuXG4gICAgbGV0IGNicyA9IDA7XG4gICAgY29uc3QgZG9uZTEgPSAoKSA9PiB7XG4gICAgICBpZigrK2NicyA9PT0gNCkgZG9uZSgpO1xuICAgIH07XG5cbiAgICAvLyBTZW5kIGFuIEhUVFAgcmVxdWVzdCwgZXhwZWN0aW5nIGFuIE9LIHJlc3BvbnNlXG4gICAgcmVxdWVzdC5nZXQoJ2h0dHA6Ly9sb2NhbGhvc3Q6OnAvOnYvOnInLCB7XG4gICAgICBwOiBzZXJ2ZXIuYWRkcmVzcygpLnBvcnQsXG4gICAgICB2OiAnb2snLFxuICAgICAgcjogJ3JlcXVlc3QnXG4gICAgfSwgKGVyciwgdmFsKSA9PiB7XG4gICAgICBleHBlY3QoZXJyKS50by5lcXVhbCh1bmRlZmluZWQpO1xuICAgICAgZXhwZWN0KHZhbC5zdGF0dXNDb2RlKS50by5lcXVhbCgyMDApO1xuICAgICAgZXhwZWN0KHZhbC5ib2R5KS50by5lcXVhbCgnb2theScpO1xuICAgICAgZG9uZTEoKTtcbiAgICB9KTtcblxuICAgIC8vIFNlbmQgYW4gSFRUUCByZXF1ZXN0LCBleHBlY3RpbmcgYW4gT0sgcmVzcG9uc2VcbiAgICByZXF1ZXN0LmdldCgnaHR0cDovL2xvY2FsaG9zdDo6cC86di9nZW5lcmF0b3IvOnInLCB7XG4gICAgICBwOiBzZXJ2ZXIuYWRkcmVzcygpLnBvcnQsXG4gICAgICB2OiAnb2snLFxuICAgICAgcjogJ3JlcXVlc3QnXG4gICAgfSwgKGVyciwgdmFsKSA9PiB7XG4gICAgICBleHBlY3QoZXJyKS50by5lcXVhbCh1bmRlZmluZWQpO1xuICAgICAgZXhwZWN0KHZhbC5zdGF0dXNDb2RlKS50by5lcXVhbCgyMDApO1xuICAgICAgZXhwZWN0KHZhbC5ib2R5KS50by5lcXVhbCgnb2theScpO1xuICAgICAgZG9uZTEoKTtcbiAgICB9KTtcblxuICAgIC8vIFNlbmQgYW4gSFRUUCByZXF1ZXN0LCBleHBlY3RpbmcgYSA1MDAgc3RhdHVzIGNvZGVcbiAgICAvLyBIZXJlIHRlc3QgdGhlIG9wdGlvbiB0byBwYXNzIHRoZSBVUkkgYXMgYSBmaWVsZCBvZiB0aGUgb3B0aW9ucyBvYmplY3RcbiAgICByZXF1ZXN0LmdldCh7XG4gICAgICB1cmk6ICdodHRwOi8vbG9jYWxob3N0OjpwLzp2LzpyJyxcbiAgICAgIHA6IHNlcnZlci5hZGRyZXNzKCkucG9ydCxcbiAgICAgIHY6ICc1MDAnLFxuICAgICAgcjogJ3JlcXVlc3QnXG4gICAgfSwgKGVyciwgdmFsKSA9PiB7XG4gICAgICBleHBlY3QoZXJyLm1lc3NhZ2UpLnRvLmVxdWFsKCdIVFRQIHJlc3BvbnNlIHN0YXR1cyBjb2RlIDUwMCcpO1xuICAgICAgZXhwZWN0KHZhbCkudG8uZXF1YWwodW5kZWZpbmVkKTtcbiAgICAgIGRvbmUxKCk7XG4gICAgfSk7XG5cbiAgICAvLyBTZW5kIGFuIEhUVFAgcmVxdWVzdCwgZXhwZWN0aW5nIGFuIGVycm9yIG1lc3NhZ2VcbiAgICByZXF1ZXN0LmdldCgnaHR0cDovL2xvY2FsaG9zdDo6cC86di86ci86bScsIHtcbiAgICAgIHA6IHNlcnZlci5hZGRyZXNzKCkucG9ydCxcbiAgICAgIHY6ICdlcnInLFxuICAgICAgcjogJ3JlcXVlc3QnLFxuICAgICAgbTogJ2R1aCdcbiAgICB9LCAoZXJyLCB2YWwpID0+IHtcbiAgICAgIGV4cGVjdChlcnIubWVzc2FnZSkudG8uZXF1YWwoJ2R1aCcpO1xuICAgICAgZXhwZWN0KHZhbCkudG8uZXF1YWwodW5kZWZpbmVkKTtcbiAgICAgIGRvbmUxKCk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIGl0KCdoYW5kbGVzIGV4Y2VwdGlvbnMnLCAoZG9uZSkgPT4ge1xuICAgIHByb2Nlc3MuZXhpdCA9IHNweSgpO1xuXG4gICAgLy8gQ3JlYXRlIGEgdGVzdCBFeHByZXNzIGFwcFxuICAgIGNvbnN0IGFwcCA9IGV4cHJlc3MoKTtcblxuICAgIC8vIENyZWF0ZSBhIHJvdXRlclxuICAgIGNvbnN0IHJvdXRlcyA9IHJvdXRlcigpO1xuXG4gICAgLy8gQWRkIGEgdGVzdCByb3V0ZVxuICAgIHJvdXRlcy5nZXQoJy9lcnIvZ2VuZXJhdG9yL3JlcXVlc3QvOm1lc3NhZ2UnLCBmdW5jdGlvbiAqKHJlcSkge1xuICAgICAgLy8gVGhyb3cgYW4gZXhjZXB0aW9uIHdpdGggYSBtZXNzYWdlIGZpZWxkXG4gICAgICB0aHJvdyBuZXcgRXJyb3IocmVxLnBhcmFtcy5tZXNzYWdlKTtcbiAgICB9KTtcblxuICAgIC8vIEFkZCBvdXIgcm91dGVyIHRvIHRoZSBhcHBcbiAgICBhcHAudXNlKHJvdXRlcyk7XG5cbiAgICAvLyBMaXN0ZW4gb24gYW4gZXBoZW1lcmFsIHBvcnRcbiAgICBjb25zdCBzZXJ2ZXIgPSBhcHAubGlzdGVuKDApO1xuXG4gICAgLy8gU2VuZCBhbiBIVFRQIHJlcXVlc3QsIGV4cGVjdGluZyBhbiBlcnJvciBtZXNzYWdlXG4gICAgcmVxdWVzdC5nZXQoJ2h0dHA6Ly9sb2NhbGhvc3Q6OnAvOnYvZ2VuZXJhdG9yLzpyLzptJywge1xuICAgICAgcDogc2VydmVyLmFkZHJlc3MoKS5wb3J0LFxuICAgICAgdjogJ2VycicsXG4gICAgICByOiAncmVxdWVzdCcsXG4gICAgICBtOiAnYm9vJ1xuICAgIH0sIChlcnIsIHZhbCkgPT4ge1xuICAgICAgZXhwZWN0KGVyci5tZXNzYWdlKS50by5lcXVhbCgnSFRUUCByZXNwb25zZSBzdGF0dXMgY29kZSA1MDAnKTtcbiAgICAgIGV4cGVjdCh2YWwpLnRvLmVxdWFsKHVuZGVmaW5lZCk7XG4gICAgICBleHBlY3QocHJvY2Vzcy5leGl0LmFyZ3MubGVuZ3RoKS50by5lcXVhbCgxKTtcbiAgICAgIGRvbmUoKTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgaXQoJ2hhbmRsZXMgZG9tYWluIGFzeW5jaHJvbm91cyBleGNlcHRpb25zJywgKGRvbmUpID0+IHtcbiAgICBwcm9jZXNzLmV4aXQgPSBzcHkoKTtcblxuICAgIC8vIENyZWF0ZSBhIHRlc3QgRXhwcmVzcyBhcHBcbiAgICBjb25zdCBhcHAgPSBleHByZXNzKCk7XG5cbiAgICAvLyBDcmVhdGUgYSByb3V0ZXJcbiAgICBjb25zdCByb3V0ZXMgPSByb3V0ZXIoKTtcblxuICAgIC8vIEFkZCBhIHRlc3Qgcm91dGVcbiAgICByb3V0ZXMuZ2V0KCcvZXJyL3JlcXVlc3QvOm1lc3NhZ2UnLCAocmVxLCByZXMpID0+IHtcbiAgICAgIC8vIFRocm93IGFuIGFzeW5jaHJvbm91cyBleGNlcHRpb24gd2l0aCBhIG1lc3NhZ2UgZmllbGRcbiAgICAgIHByb2Nlc3MubmV4dFRpY2soKCkgPT4ge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IocmVxLnBhcmFtcy5tZXNzYWdlKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgLy8gQWRkIG91ciByb3V0ZXIgdG8gdGhlIGFwcFxuICAgIGFwcC51c2Uocm91dGVzKTtcblxuICAgIC8vIExpc3RlbiBvbiBhbiBlcGhlbWVyYWwgcG9ydFxuICAgIGNvbnN0IHNlcnZlciA9IGFwcC5saXN0ZW4oMCk7XG5cbiAgICAvLyBTZW5kIGFuIEhUVFAgcmVxdWVzdCwgZXhwZWN0aW5nIGFuIGVycm9yIG1lc3NhZ2VcbiAgICByZXF1ZXN0LmdldCgnaHR0cDovL2xvY2FsaG9zdDo6cC86di86ci86bScsIHtcbiAgICAgIHA6IHNlcnZlci5hZGRyZXNzKCkucG9ydCxcbiAgICAgIHY6ICdlcnInLFxuICAgICAgcjogJ3JlcXVlc3QnLFxuICAgICAgbTogJ2JvbydcbiAgICB9LCAoZXJyLCB2YWwpID0+IHtcbiAgICAgIGV4cGVjdChlcnIubWVzc2FnZSkudG8uZXF1YWwoJ0hUVFAgcmVzcG9uc2Ugc3RhdHVzIGNvZGUgNTAwJyk7XG4gICAgICBleHBlY3QodmFsKS50by5lcXVhbCh1bmRlZmluZWQpO1xuICAgICAgZXhwZWN0KHByb2Nlc3MuZXhpdC5hcmdzLmxlbmd0aCkudG8uZXF1YWwoMSk7XG4gICAgICBkb25lKCk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIGl0KCdoYW5kbGVzIGJhdGNoZWQgSFRUUCByZXF1ZXN0cycsIChkb25lKSA9PiB7XG4gICAgLy8gQ3JlYXRlIGEgdGVzdCBFeHByZXNzIGFwcFxuICAgIGNvbnN0IGFwcCA9IGV4cHJlc3MoKTtcblxuICAgIC8vIENyZWF0ZSBhIHJvdXRlclxuICAgIGNvbnN0IHJvdXRlcyA9IHJvdXRlcigpO1xuXG4gICAgLy8gQWRkIGEgZmV3IHRlc3Qgcm91dGVzXG4gICAgcm91dGVzLmdldCgnL29rL3JlcXVlc3QnLCAocmVxLCByZXMpID0+IHtcbiAgICAgIC8vIFJldHVybiBhbiBPSyByZXNwb25zZSB3aXRoIGEgYm9keVxuICAgICAgcmVzLnNlbmQoJ29rYXknKTtcbiAgICB9KTtcbiAgICByb3V0ZXMuZ2V0KCcvb2svZ2VuZXJhdG9yL3JlcXVlc3QnLCBmdW5jdGlvbiAqKHJlcSkge1xuICAgICAgLy8gUmV0dXJuIGFuIE9LIHJlc3BvbnNlIHdpdGggYSBib2R5XG4gICAgICByZXR1cm4ge1xuICAgICAgICBib2R5OiAnb2theSdcbiAgICAgIH07XG4gICAgfSk7XG4gICAgcm91dGVzLmdldCgnLzUwMC9yZXF1ZXN0JywgKHJlcSwgcmVzKSA9PiB7XG4gICAgICAvLyBSZXR1cm4gYW4gZXJyb3Igc3RhdHVzXG4gICAgICByZXMuc3RhdHVzKDUwMCkuZW5kKCk7XG4gICAgfSk7XG4gICAgcm91dGVzLmdldCgnL2Vyci9yZXF1ZXN0LzptZXNzYWdlJywgKHJlcSwgcmVzKSA9PiB7XG4gICAgICAvLyBSZXR1cm4gYSBKU09OIGVycm9yIG9iamVjdCB3aXRoIGEgbWVzc2FnZSBmaWVsZFxuICAgICAgcmVzLnN0YXR1cyg1MDApLnNlbmQoe1xuICAgICAgICBtZXNzYWdlOiByZXEucGFyYW1zLm1lc3NhZ2VcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgLy8gQWRkIG91ciByb3V0ZXIgdG8gdGhlIGFwcFxuICAgIGFwcC51c2Uocm91dGVzKTtcblxuICAgIC8vIEFkZCBiYXRjaCByb3V0ZXIgbWlkZGxld2FyZSB0byB0aGUgYXBwXG4gICAgYXBwLnVzZShyb3V0ZXIuYmF0Y2gocm91dGVzKSk7XG5cbiAgICAvLyBMaXN0ZW4gb24gYW4gZXBoZW1lcmFsIHBvcnRcbiAgICBjb25zdCBzZXJ2ZXIgPSBhcHAubGlzdGVuKDApO1xuXG4gICAgbGV0IGNicyA9IDA7XG4gICAgY29uc3QgZG9uZTEgPSAoKSA9PiB7XG4gICAgICBpZigrK2NicyA9PT0gNCkgZG9uZSgpO1xuICAgIH07XG5cbiAgICAvLyBVc2UgYSBiYXRjaCB2ZXJzaW9uIG9mIHRoZSByZXF1ZXN0IG1vZHVsZVxuICAgIGNvbnN0IGJyZXF1ZXN0ID0gYmF0Y2gocmVxdWVzdCk7XG5cbiAgICAvLyBTZW5kIGFuIEhUVFAgcmVxdWVzdCwgZXhwZWN0aW5nIGFuIE9LIHJlc3BvbnNlXG4gICAgYnJlcXVlc3QuZ2V0KCdodHRwOi8vbG9jYWxob3N0OjpwLzp2LzpyJywge1xuICAgICAgcDogc2VydmVyLmFkZHJlc3MoKS5wb3J0LFxuICAgICAgdjogJ29rJyxcbiAgICAgIHI6ICdyZXF1ZXN0J1xuICAgIH0sIChlcnIsIHZhbCkgPT4ge1xuICAgICAgZXhwZWN0KGVycikudG8uZXF1YWwodW5kZWZpbmVkKTtcbiAgICAgIGV4cGVjdCh2YWwuc3RhdHVzQ29kZSkudG8uZXF1YWwoMjAwKTtcbiAgICAgIGV4cGVjdCh2YWwuYm9keSkudG8uZXF1YWwoJ29rYXknKTtcbiAgICAgIGRvbmUxKCk7XG4gICAgfSk7XG5cbiAgICAvLyBTZW5kIGFuIEhUVFAgcmVxdWVzdCwgZXhwZWN0aW5nIGFuIE9LIHJlc3BvbnNlXG4gICAgYnJlcXVlc3QuZ2V0KCdodHRwOi8vbG9jYWxob3N0OjpwLzp2L2dlbmVyYXRvci86cicsIHtcbiAgICAgIHA6IHNlcnZlci5hZGRyZXNzKCkucG9ydCxcbiAgICAgIHY6ICdvaycsXG4gICAgICByOiAncmVxdWVzdCdcbiAgICB9LCAoZXJyLCB2YWwpID0+IHtcbiAgICAgIGV4cGVjdChlcnIpLnRvLmVxdWFsKHVuZGVmaW5lZCk7XG4gICAgICBleHBlY3QodmFsLnN0YXR1c0NvZGUpLnRvLmVxdWFsKDIwMCk7XG4gICAgICBleHBlY3QodmFsLmJvZHkpLnRvLmVxdWFsKCdva2F5Jyk7XG4gICAgICBkb25lMSgpO1xuICAgIH0pO1xuXG4gICAgLy8gU2VuZCBhbiBIVFRQIHJlcXVlc3QsIGV4cGVjdGluZyBhIDUwMCBzdGF0dXMgY29kZVxuICAgIC8vIEhlcmUgdGVzdCB0aGUgb3B0aW9uIHRvIHBhc3MgdGhlIFVSSSBhcyBhIGZpZWxkIG9mIHRoZSBvcHRpb25zIG9iamVjdFxuICAgIGJyZXF1ZXN0LmdldCh7XG4gICAgICB1cmk6ICdodHRwOi8vbG9jYWxob3N0OjpwLzp2LzpyJyxcbiAgICAgIHA6IHNlcnZlci5hZGRyZXNzKCkucG9ydCxcbiAgICAgIHY6ICc1MDAnLFxuICAgICAgcjogJ3JlcXVlc3QnXG4gICAgfSwgKGVyciwgdmFsKSA9PiB7XG4gICAgICBleHBlY3QoZXJyLm1lc3NhZ2UpLnRvLmVxdWFsKCdIVFRQIHJlc3BvbnNlIHN0YXR1cyBjb2RlIDUwMCcpO1xuICAgICAgZXhwZWN0KHZhbCkudG8uZXF1YWwodW5kZWZpbmVkKTtcbiAgICAgIGRvbmUxKCk7XG4gICAgfSk7XG5cbiAgICAvLyBTZW5kIGFuIEhUVFAgcmVxdWVzdCwgZXhwZWN0aW5nIGFuIGVycm9yIG1lc3NhZ2VcbiAgICBicmVxdWVzdC5nZXQoJ2h0dHA6Ly9sb2NhbGhvc3Q6OnAvOnYvOnIvOm0nLCB7XG4gICAgICBwOiBzZXJ2ZXIuYWRkcmVzcygpLnBvcnQsXG4gICAgICB2OiAnZXJyJyxcbiAgICAgIHI6ICdyZXF1ZXN0JyxcbiAgICAgIG06ICdkdWgnXG4gICAgfSwgKGVyciwgdmFsKSA9PiB7XG4gICAgICBleHBlY3QoZXJyLm1lc3NhZ2UpLnRvLmVxdWFsKCdkdWgnKTtcbiAgICAgIGV4cGVjdCh2YWwpLnRvLmVxdWFsKHVuZGVmaW5lZCk7XG4gICAgICBkb25lMSgpO1xuICAgIH0pO1xuICB9KTtcblxuICBpdCgnaGFuZGxlcyB1bmhhbmRsZWQgZXhjZXB0aW9ucyBhdCBtaWRkbGV3YXJlIGFuZCcgK1xuICAgICdyZXNwb25kcyBiYWNrIHdpdGggYSA1MDAgZm9yIGEgYmF0Y2ggaHR0cCByZXF1ZXN0JywgKGRvbmUpID0+IHtcbiAgICAgIC8vIENyZWF0ZSBhIHRlc3QgRXhwcmVzcyBhcHBcbiAgICAgIGNvbnN0IGFwcCA9IGV4cHJlc3MoKTtcblxuICAgICAgLy8gQ3JlYXRlIGEgcm91dGVyXG4gICAgICBjb25zdCByb3V0ZXMgPSByb3V0ZXIoKTtcblxuICAgICAgLy8gQWRkIGEgdGVzdCByb3V0ZSB0aGF0IHRocm93cyBhbiBleGNlcHRpb25cbiAgICAgIHJvdXRlcy5nZXQoJy9leGNlcHRpb24vcmVxdWVzdCcsIChyZXEsIHJlcykgPT4ge1xuICAgICAgICBpZiAocmVxLmNhdXNlLnVuaGFuZGxlZC5leGNlcHRpb24pXG4gICAgICAgICAgcmVzLnN0YXR1cygyMDApLnNlbmQoeyBtZXNzYWdlOiAnJyB9KTtcbiAgICAgIH0pO1xuXG4gICAgICAvLyBBZGQgb3VyIHJvdXRlciB0byB0aGUgYXBwXG4gICAgICBhcHAudXNlKHJvdXRlcyk7XG5cbiAgICAgIC8vIEFkZCBiYXRjaCByb3V0ZXIgbWlkZGxld2FyZSB0byB0aGUgYXBwXG4gICAgICBhcHAudXNlKHJvdXRlci5iYXRjaChyb3V0ZXMpKTtcblxuICAgICAgLy8gTGlzdGVuIG9uIGFuIGVwaGVtZXJhbCBwb3J0XG4gICAgICBjb25zdCBzZXJ2ZXIgPSBhcHAubGlzdGVuKDApO1xuXG4gICAgICAvLyBVc2UgYSBiYXRjaCB2ZXJzaW9uIG9mIHRoZSByZXF1ZXN0IG1vZHVsZVxuICAgICAgY29uc3QgYnJlcXVlc3QgPSBiYXRjaChyZXF1ZXN0KTtcblxuICAgICAgLy8gU2VuZCBhbiBIVFRQIHJlcXVlc3QsIGV4cGVjdGluZyBhIDUwMCBzdGF0dXMgY29kZVxuICAgICAgYnJlcXVlc3QuZ2V0KHtcbiAgICAgICAgdXJpOiAnaHR0cDovL2xvY2FsaG9zdDo6cC86di86cicsXG4gICAgICAgIHA6IHNlcnZlci5hZGRyZXNzKCkucG9ydCxcbiAgICAgICAgdjogJ2V4Y2VwdGlvbicsXG4gICAgICAgIHI6ICdyZXF1ZXN0J1xuICAgICAgfSwgKGVyciwgdmFsKSA9PiB7XG4gICAgICAgIGV4cGVjdChlcnIubWVzc2FnZSkudG8uZXF1YWwoJ0hUVFAgcmVzcG9uc2Ugc3RhdHVzIGNvZGUgNTAwJyk7XG4gICAgICAgIGV4cGVjdCh2YWwpLnRvLmVxdWFsKHVuZGVmaW5lZCk7XG4gICAgICAgIGRvbmUoKTtcbiAgICAgIH0pO1xuICAgIH0pO1xufSk7XG4iXX0=
\No newline at end of file