1 | ;
|
2 |
|
3 | // Small Express router that runs request handlers written as ES6 generators
|
4 | // using Node co.
|
5 |
|
6 | var _regeneratorRuntime = require('babel-runtime/regenerator')['default'];
|
7 |
|
8 | var express = require('abacus-express');
|
9 | var request = require('abacus-request');
|
10 | var batch = require('abacus-batch');
|
11 |
|
12 | var router = require('..');
|
13 |
|
14 | /* jshint noyield: true */
|
15 |
|
16 | describe('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 |