"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _node = _interopRequireDefault(require("parse/node")); var _express = _interopRequireDefault(require("express")); var _logger = _interopRequireDefault(require("./logger")); var _util = require("util"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } // A router that is based on promises rather than req/res/next. // This is intended to replace the use of express.Router to handle // subsections of the API surface. // This will make it easier to have methods like 'batch' that // themselves use our routing information, without disturbing express // components that external developers may be modifying. const Layer = require('express/lib/router/layer'); function validateParameter(key, value) { if (key == 'className') { if (value.match(/_?[A-Za-z][A-Za-z_0-9]*/)) { return value; } } else if (key == 'objectId') { if (value.match(/[A-Za-z0-9]+/)) { return value; } } else { return value; } } class PromiseRouter { // Each entry should be an object with: // path: the path to route, in express format // method: the HTTP method that this route handles. // Must be one of: POST, GET, PUT, DELETE // handler: a function that takes request, and returns a promise. // Successful handlers should resolve to an object with fields: // status: optional. the http status code. defaults to 200 // response: a json object with the content of the response // location: optional. a location header constructor(routes = [], appId) { this.routes = routes; this.appId = appId; this.mountRoutes(); } // Leave the opportunity to // subclasses to mount their routes by overriding mountRoutes() {} // Merge the routes into this one merge(router) { for (var route of router.routes) { this.routes.push(route); } } route(method, path, ...handlers) { switch (method) { case 'POST': case 'GET': case 'PUT': case 'DELETE': break; default: throw 'cannot route method: ' + method; } let handler = handlers[0]; if (handlers.length > 1) { handler = function (req) { return handlers.reduce((promise, handler) => { return promise.then(() => { return handler(req); }); }, Promise.resolve()); }; } this.routes.push({ path: path, method: method, handler: handler, layer: new Layer(path, null, handler) }); } // Returns an object with: // handler: the handler that should deal with this request // params: any :-params that got parsed from the path // Returns undefined if there is no match. match(method, path) { for (var route of this.routes) { if (route.method != method) { continue; } const layer = route.layer || new Layer(route.path, null, route.handler); const match = layer.match(path); if (match) { const params = layer.params; Object.keys(params).forEach(key => { params[key] = validateParameter(key, params[key]); }); return { params: params, handler: route.handler }; } } } // Mount the routes on this router onto an express app (or express router) mountOnto(expressApp) { this.routes.forEach(route => { const method = route.method.toLowerCase(); const handler = makeExpressHandler(this.appId, route.handler); expressApp[method].call(expressApp, route.path, handler); }); return expressApp; } expressRouter() { return this.mountOnto(_express.default.Router()); } tryRouteRequest(method, path, request) { var match = this.match(method, path); if (!match) { throw new _node.default.Error(_node.default.Error.INVALID_JSON, 'cannot route ' + method + ' ' + path); } request.params = match.params; return new Promise((resolve, reject) => { match.handler(request).then(resolve, reject); }); } } // A helper function to make an express handler out of a a promise // handler. // Express handlers should never throw; if a promise handler throws we // just treat it like it resolved to an error. exports.default = PromiseRouter; function makeExpressHandler(appId, promiseHandler) { return function (req, res, next) { try { const url = maskSensitiveUrl(req); const body = Object.assign({}, req.body); const method = req.method; const headers = req.headers; _logger.default.logRequest({ method, url, headers, body }); promiseHandler(req).then(result => { if (!result.response && !result.location && !result.text) { _logger.default.error('the handler did not include a "response" or a "location" field'); throw 'control should not get here'; } _logger.default.logResponse({ method, url, result }); var status = result.status || 200; res.status(status); if (result.headers) { Object.keys(result.headers).forEach(header => { res.set(header, result.headers[header]); }); } if (result.text) { res.send(result.text); return; } if (result.location) { res.set('Location', result.location); // Override the default expressjs response // as it double encodes %encoded chars in URL if (!result.response) { res.send('Found. Redirecting to ' + result.location); return; } } res.json(result.response); }, error => { next(error); }).catch(e => { _logger.default.error(`Error generating response. ${(0, _util.inspect)(e)}`, { error: e }); next(e); }); } catch (e) { _logger.default.error(`Error handling request: ${(0, _util.inspect)(e)}`, { error: e }); next(e); } }; } function maskSensitiveUrl(req) { let maskUrl = req.originalUrl.toString(); const shouldMaskUrl = req.method === 'GET' && req.originalUrl.includes('/login') && !req.originalUrl.includes('classes'); if (shouldMaskUrl) { maskUrl = _logger.default.maskSensitiveUrl(maskUrl); } return maskUrl; } //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfbm9kZSIsIl9pbnRlcm9wUmVxdWlyZURlZmF1bHQiLCJyZXF1aXJlIiwiX2V4cHJlc3MiLCJfbG9nZ2VyIiwiX3V0aWwiLCJlIiwiX19lc01vZHVsZSIsImRlZmF1bHQiLCJMYXllciIsInZhbGlkYXRlUGFyYW1ldGVyIiwia2V5IiwidmFsdWUiLCJtYXRjaCIsIlByb21pc2VSb3V0ZXIiLCJjb25zdHJ1Y3RvciIsInJvdXRlcyIsImFwcElkIiwibW91bnRSb3V0ZXMiLCJtZXJnZSIsInJvdXRlciIsInJvdXRlIiwicHVzaCIsIm1ldGhvZCIsInBhdGgiLCJoYW5kbGVycyIsImhhbmRsZXIiLCJsZW5ndGgiLCJyZXEiLCJyZWR1Y2UiLCJwcm9taXNlIiwidGhlbiIsIlByb21pc2UiLCJyZXNvbHZlIiwibGF5ZXIiLCJwYXJhbXMiLCJPYmplY3QiLCJrZXlzIiwiZm9yRWFjaCIsIm1vdW50T250byIsImV4cHJlc3NBcHAiLCJ0b0xvd2VyQ2FzZSIsIm1ha2VFeHByZXNzSGFuZGxlciIsImNhbGwiLCJleHByZXNzUm91dGVyIiwiZXhwcmVzcyIsIlJvdXRlciIsInRyeVJvdXRlUmVxdWVzdCIsInJlcXVlc3QiLCJQYXJzZSIsIkVycm9yIiwiSU5WQUxJRF9KU09OIiwicmVqZWN0IiwiZXhwb3J0cyIsInByb21pc2VIYW5kbGVyIiwicmVzIiwibmV4dCIsInVybCIsIm1hc2tTZW5zaXRpdmVVcmwiLCJib2R5IiwiYXNzaWduIiwiaGVhZGVycyIsImxvZyIsImxvZ1JlcXVlc3QiLCJyZXN1bHQiLCJyZXNwb25zZSIsImxvY2F0aW9uIiwidGV4dCIsImVycm9yIiwibG9nUmVzcG9uc2UiLCJzdGF0dXMiLCJoZWFkZXIiLCJzZXQiLCJzZW5kIiwianNvbiIsImNhdGNoIiwiaW5zcGVjdCIsIm1hc2tVcmwiLCJvcmlnaW5hbFVybCIsInRvU3RyaW5nIiwic2hvdWxkTWFza1VybCIsImluY2x1ZGVzIl0sInNvdXJjZXMiOlsiLi4vc3JjL1Byb21pc2VSb3V0ZXIuanMiXSwic291cmNlc0NvbnRlbnQiOlsiLy8gQSByb3V0ZXIgdGhhdCBpcyBiYXNlZCBvbiBwcm9taXNlcyByYXRoZXIgdGhhbiByZXEvcmVzL25leHQuXG4vLyBUaGlzIGlzIGludGVuZGVkIHRvIHJlcGxhY2UgdGhlIHVzZSBvZiBleHByZXNzLlJvdXRlciB0byBoYW5kbGVcbi8vIHN1YnNlY3Rpb25zIG9mIHRoZSBBUEkgc3VyZmFjZS5cbi8vIFRoaXMgd2lsbCBtYWtlIGl0IGVhc2llciB0byBoYXZlIG1ldGhvZHMgbGlrZSAnYmF0Y2gnIHRoYXRcbi8vIHRoZW1zZWx2ZXMgdXNlIG91ciByb3V0aW5nIGluZm9ybWF0aW9uLCB3aXRob3V0IGRpc3R1cmJpbmcgZXhwcmVzc1xuLy8gY29tcG9uZW50cyB0aGF0IGV4dGVybmFsIGRldmVsb3BlcnMgbWF5IGJlIG1vZGlmeWluZy5cblxuaW1wb3J0IFBhcnNlIGZyb20gJ3BhcnNlL25vZGUnO1xuaW1wb3J0IGV4cHJlc3MgZnJvbSAnZXhwcmVzcyc7XG5pbXBvcnQgbG9nIGZyb20gJy4vbG9nZ2VyJztcbmltcG9ydCB7IGluc3BlY3QgfSBmcm9tICd1dGlsJztcbmNvbnN0IExheWVyID0gcmVxdWlyZSgnZXhwcmVzcy9saWIvcm91dGVyL2xheWVyJyk7XG5cbmZ1bmN0aW9uIHZhbGlkYXRlUGFyYW1ldGVyKGtleSwgdmFsdWUpIHtcbiAgaWYgKGtleSA9PSAnY2xhc3NOYW1lJykge1xuICAgIGlmICh2YWx1ZS5tYXRjaCgvXz9bQS1aYS16XVtBLVphLXpfMC05XSovKSkge1xuICAgICAgcmV0dXJuIHZhbHVlO1xuICAgIH1cbiAgfSBlbHNlIGlmIChrZXkgPT0gJ29iamVjdElkJykge1xuICAgIGlmICh2YWx1ZS5tYXRjaCgvW0EtWmEtejAtOV0rLykpIHtcbiAgICAgIHJldHVybiB2YWx1ZTtcbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgcmV0dXJuIHZhbHVlO1xuICB9XG59XG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIFByb21pc2VSb3V0ZXIge1xuICAvLyBFYWNoIGVudHJ5IHNob3VsZCBiZSBhbiBvYmplY3Qgd2l0aDpcbiAgLy8gcGF0aDogdGhlIHBhdGggdG8gcm91dGUsIGluIGV4cHJlc3MgZm9ybWF0XG4gIC8vIG1ldGhvZDogdGhlIEhUVFAgbWV0aG9kIHRoYXQgdGhpcyByb3V0ZSBoYW5kbGVzLlxuICAvLyAgIE11c3QgYmUgb25lIG9mOiBQT1NULCBHRVQsIFBVVCwgREVMRVRFXG4gIC8vIGhhbmRsZXI6IGEgZnVuY3Rpb24gdGhhdCB0YWtlcyByZXF1ZXN0LCBhbmQgcmV0dXJucyBhIHByb21pc2UuXG4gIC8vICAgU3VjY2Vzc2Z1bCBoYW5kbGVycyBzaG91bGQgcmVzb2x2ZSB0byBhbiBvYmplY3Qgd2l0aCBmaWVsZHM6XG4gIC8vICAgICBzdGF0dXM6IG9wdGlvbmFsLiB0aGUgaHR0cCBzdGF0dXMgY29kZS4gZGVmYXVsdHMgdG8gMjAwXG4gIC8vICAgICByZXNwb25zZTogYSBqc29uIG9iamVjdCB3aXRoIHRoZSBjb250ZW50IG9mIHRoZSByZXNwb25zZVxuICAvLyAgICAgbG9jYXRpb246IG9wdGlvbmFsLiBhIGxvY2F0aW9uIGhlYWRlclxuICBjb25zdHJ1Y3Rvcihyb3V0ZXMgPSBbXSwgYXBwSWQpIHtcbiAgICB0aGlzLnJvdXRlcyA9IHJvdXRlcztcbiAgICB0aGlzLmFwcElkID0gYXBwSWQ7XG4gICAgdGhpcy5tb3VudFJvdXRlcygpO1xuICB9XG5cbiAgLy8gTGVhdmUgdGhlIG9wcG9ydHVuaXR5IHRvXG4gIC8vIHN1YmNsYXNzZXMgdG8gbW91bnQgdGhlaXIgcm91dGVzIGJ5IG92ZXJyaWRpbmdcbiAgbW91bnRSb3V0ZXMoKSB7fVxuXG4gIC8vIE1lcmdlIHRoZSByb3V0ZXMgaW50byB0aGlzIG9uZVxuICBtZXJnZShyb3V0ZXIpIHtcbiAgICBmb3IgKHZhciByb3V0ZSBvZiByb3V0ZXIucm91dGVzKSB7XG4gICAgICB0aGlzLnJvdXRlcy5wdXNoKHJvdXRlKTtcbiAgICB9XG4gIH1cblxuICByb3V0ZShtZXRob2QsIHBhdGgsIC4uLmhhbmRsZXJzKSB7XG4gICAgc3dpdGNoIChtZXRob2QpIHtcbiAgICAgIGNhc2UgJ1BPU1QnOlxuICAgICAgY2FzZSAnR0VUJzpcbiAgICAgIGNhc2UgJ1BVVCc6XG4gICAgICBjYXNlICdERUxFVEUnOlxuICAgICAgICBicmVhaztcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHRocm93ICdjYW5ub3Qgcm91dGUgbWV0aG9kOiAnICsgbWV0aG9kO1xuICAgIH1cblxuICAgIGxldCBoYW5kbGVyID0gaGFuZGxlcnNbMF07XG5cbiAgICBpZiAoaGFuZGxlcnMubGVuZ3RoID4gMSkge1xuICAgICAgaGFuZGxlciA9IGZ1bmN0aW9uIChyZXEpIHtcbiAgICAgICAgcmV0dXJuIGhhbmRsZXJzLnJlZHVjZSgocHJvbWlzZSwgaGFuZGxlcikgPT4ge1xuICAgICAgICAgIHJldHVybiBwcm9taXNlLnRoZW4oKCkgPT4ge1xuICAgICAgICAgICAgcmV0dXJuIGhhbmRsZXIocmVxKTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSwgUHJvbWlzZS5yZXNvbHZlKCkpO1xuICAgICAgfTtcbiAgICB9XG5cbiAgICB0aGlzLnJvdXRlcy5wdXNoKHtcbiAgICAgIHBhdGg6IHBhdGgsXG4gICAgICBtZXRob2Q6IG1ldGhvZCxcbiAgICAgIGhhbmRsZXI6IGhhbmRsZXIsXG4gICAgICBsYXllcjogbmV3IExheWVyKHBhdGgsIG51bGwsIGhhbmRsZXIpLFxuICAgIH0pO1xuICB9XG5cbiAgLy8gUmV0dXJucyBhbiBvYmplY3Qgd2l0aDpcbiAgLy8gICBoYW5kbGVyOiB0aGUgaGFuZGxlciB0aGF0IHNob3VsZCBkZWFsIHdpdGggdGhpcyByZXF1ZXN0XG4gIC8vICAgcGFyYW1zOiBhbnkgOi1wYXJhbXMgdGhhdCBnb3QgcGFyc2VkIGZyb20gdGhlIHBhdGhcbiAgLy8gUmV0dXJucyB1bmRlZmluZWQgaWYgdGhlcmUgaXMgbm8gbWF0Y2guXG4gIG1hdGNoKG1ldGhvZCwgcGF0aCkge1xuICAgIGZvciAodmFyIHJvdXRlIG9mIHRoaXMucm91dGVzKSB7XG4gICAgICBpZiAocm91dGUubWV0aG9kICE9IG1ldGhvZCkge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IGxheWVyID0gcm91dGUubGF5ZXIgfHwgbmV3IExheWVyKHJvdXRlLnBhdGgsIG51bGwsIHJvdXRlLmhhbmRsZXIpO1xuICAgICAgY29uc3QgbWF0Y2ggPSBsYXllci5tYXRjaChwYXRoKTtcbiAgICAgIGlmIChtYXRjaCkge1xuICAgICAgICBjb25zdCBwYXJhbXMgPSBsYXllci5wYXJhbXM7XG4gICAgICAgIE9iamVjdC5rZXlzKHBhcmFtcykuZm9yRWFjaChrZXkgPT4ge1xuICAgICAgICAgIHBhcmFtc1trZXldID0gdmFsaWRhdGVQYXJhbWV0ZXIoa2V5LCBwYXJhbXNba2V5XSk7XG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4geyBwYXJhbXM6IHBhcmFtcywgaGFuZGxlcjogcm91dGUuaGFuZGxlciB9O1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8vIE1vdW50IHRoZSByb3V0ZXMgb24gdGhpcyByb3V0ZXIgb250byBhbiBleHByZXNzIGFwcCAob3IgZXhwcmVzcyByb3V0ZXIpXG4gIG1vdW50T250byhleHByZXNzQXBwKSB7XG4gICAgdGhpcy5yb3V0ZXMuZm9yRWFjaChyb3V0ZSA9PiB7XG4gICAgICBjb25zdCBtZXRob2QgPSByb3V0ZS5tZXRob2QudG9Mb3dlckNhc2UoKTtcbiAgICAgIGNvbnN0IGhhbmRsZXIgPSBtYWtlRXhwcmVzc0hhbmRsZXIodGhpcy5hcHBJZCwgcm91dGUuaGFuZGxlcik7XG4gICAgICBleHByZXNzQXBwW21ldGhvZF0uY2FsbChleHByZXNzQXBwLCByb3V0ZS5wYXRoLCBoYW5kbGVyKTtcbiAgICB9KTtcbiAgICByZXR1cm4gZXhwcmVzc0FwcDtcbiAgfVxuXG4gIGV4cHJlc3NSb3V0ZXIoKSB7XG4gICAgcmV0dXJuIHRoaXMubW91bnRPbnRvKGV4cHJlc3MuUm91dGVyKCkpO1xuICB9XG5cbiAgdHJ5Um91dGVSZXF1ZXN0KG1ldGhvZCwgcGF0aCwgcmVxdWVzdCkge1xuICAgIHZhciBtYXRjaCA9IHRoaXMubWF0Y2gobWV0aG9kLCBwYXRoKTtcbiAgICBpZiAoIW1hdGNoKSB7XG4gICAgICB0aHJvdyBuZXcgUGFyc2UuRXJyb3IoUGFyc2UuRXJyb3IuSU5WQUxJRF9KU09OLCAnY2Fubm90IHJvdXRlICcgKyBtZXRob2QgKyAnICcgKyBwYXRoKTtcbiAgICB9XG4gICAgcmVxdWVzdC5wYXJhbXMgPSBtYXRjaC5wYXJhbXM7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgIG1hdGNoLmhhbmRsZXIocmVxdWVzdCkudGhlbihyZXNvbHZlLCByZWplY3QpO1xuICAgIH0pO1xuICB9XG59XG5cbi8vIEEgaGVscGVyIGZ1bmN0aW9uIHRvIG1ha2UgYW4gZXhwcmVzcyBoYW5kbGVyIG91dCBvZiBhIGEgcHJvbWlzZVxuLy8gaGFuZGxlci5cbi8vIEV4cHJlc3MgaGFuZGxlcnMgc2hvdWxkIG5ldmVyIHRocm93OyBpZiBhIHByb21pc2UgaGFuZGxlciB0aHJvd3Mgd2Vcbi8vIGp1c3QgdHJlYXQgaXQgbGlrZSBpdCByZXNvbHZlZCB0byBhbiBlcnJvci5cbmZ1bmN0aW9uIG1ha2VFeHByZXNzSGFuZGxlcihhcHBJZCwgcHJvbWlzZUhhbmRsZXIpIHtcbiAgcmV0dXJuIGZ1bmN0aW9uIChyZXEsIHJlcywgbmV4dCkge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCB1cmwgPSBtYXNrU2Vuc2l0aXZlVXJsKHJlcSk7XG4gICAgICBjb25zdCBib2R5ID0gT2JqZWN0LmFzc2lnbih7fSwgcmVxLmJvZHkpO1xuICAgICAgY29uc3QgbWV0aG9kID0gcmVxLm1ldGhvZDtcbiAgICAgIGNvbnN0IGhlYWRlcnMgPSByZXEuaGVhZGVycztcbiAgICAgIGxvZy5sb2dSZXF1ZXN0KHtcbiAgICAgICAgbWV0aG9kLFxuICAgICAgICB1cmwsXG4gICAgICAgIGhlYWRlcnMsXG4gICAgICAgIGJvZHksXG4gICAgICB9KTtcbiAgICAgIHByb21pc2VIYW5kbGVyKHJlcSlcbiAgICAgICAgLnRoZW4oXG4gICAgICAgICAgcmVzdWx0ID0+IHtcbiAgICAgICAgICAgIGlmICghcmVzdWx0LnJlc3BvbnNlICYmICFyZXN1bHQubG9jYXRpb24gJiYgIXJlc3VsdC50ZXh0KSB7XG4gICAgICAgICAgICAgIGxvZy5lcnJvcigndGhlIGhhbmRsZXIgZGlkIG5vdCBpbmNsdWRlIGEgXCJyZXNwb25zZVwiIG9yIGEgXCJsb2NhdGlvblwiIGZpZWxkJyk7XG4gICAgICAgICAgICAgIHRocm93ICdjb250cm9sIHNob3VsZCBub3QgZ2V0IGhlcmUnO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBsb2cubG9nUmVzcG9uc2UoeyBtZXRob2QsIHVybCwgcmVzdWx0IH0pO1xuXG4gICAgICAgICAgICB2YXIgc3RhdHVzID0gcmVzdWx0LnN0YXR1cyB8fCAyMDA7XG4gICAgICAgICAgICByZXMuc3RhdHVzKHN0YXR1cyk7XG5cbiAgICAgICAgICAgIGlmIChyZXN1bHQuaGVhZGVycykge1xuICAgICAgICAgICAgICBPYmplY3Qua2V5cyhyZXN1bHQuaGVhZGVycykuZm9yRWFjaChoZWFkZXIgPT4ge1xuICAgICAgICAgICAgICAgIHJlcy5zZXQoaGVhZGVyLCByZXN1bHQuaGVhZGVyc1toZWFkZXJdKTtcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmIChyZXN1bHQudGV4dCkge1xuICAgICAgICAgICAgICByZXMuc2VuZChyZXN1bHQudGV4dCk7XG4gICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKHJlc3VsdC5sb2NhdGlvbikge1xuICAgICAgICAgICAgICByZXMuc2V0KCdMb2NhdGlvbicsIHJlc3VsdC5sb2NhdGlvbik7XG4gICAgICAgICAgICAgIC8vIE92ZXJyaWRlIHRoZSBkZWZhdWx0IGV4cHJlc3NqcyByZXNwb25zZVxuICAgICAgICAgICAgICAvLyBhcyBpdCBkb3VibGUgZW5jb2RlcyAlZW5jb2RlZCBjaGFycyBpbiBVUkxcbiAgICAgICAgICAgICAgaWYgKCFyZXN1bHQucmVzcG9uc2UpIHtcbiAgICAgICAgICAgICAgICByZXMuc2VuZCgnRm91bmQuIFJlZGlyZWN0aW5nIHRvICcgKyByZXN1bHQubG9jYXRpb24pO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmVzLmpzb24ocmVzdWx0LnJlc3BvbnNlKTtcbiAgICAgICAgICB9LFxuICAgICAgICAgIGVycm9yID0+IHtcbiAgICAgICAgICAgIG5leHQoZXJyb3IpO1xuICAgICAgICAgIH1cbiAgICAgICAgKVxuICAgICAgICAuY2F0Y2goZSA9PiB7XG4gICAgICAgICAgbG9nLmVycm9yKGBFcnJvciBnZW5lcmF0aW5nIHJlc3BvbnNlLiAke2luc3BlY3QoZSl9YCwgeyBlcnJvcjogZSB9KTtcbiAgICAgICAgICBuZXh0KGUpO1xuICAgICAgICB9KTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICBsb2cuZXJyb3IoYEVycm9yIGhhbmRsaW5nIHJlcXVlc3Q6ICR7aW5zcGVjdChlKX1gLCB7IGVycm9yOiBlIH0pO1xuICAgICAgbmV4dChlKTtcbiAgICB9XG4gIH07XG59XG5cbmZ1bmN0aW9uIG1hc2tTZW5zaXRpdmVVcmwocmVxKSB7XG4gIGxldCBtYXNrVXJsID0gcmVxLm9yaWdpbmFsVXJsLnRvU3RyaW5nKCk7XG4gIGNvbnN0IHNob3VsZE1hc2tVcmwgPVxuICAgIHJlcS5tZXRob2QgPT09ICdHRVQnICYmXG4gICAgcmVxLm9yaWdpbmFsVXJsLmluY2x1ZGVzKCcvbG9naW4nKSAmJlxuICAgICFyZXEub3JpZ2luYWxVcmwuaW5jbHVkZXMoJ2NsYXNzZXMnKTtcbiAgaWYgKHNob3VsZE1hc2tVcmwpIHtcbiAgICBtYXNrVXJsID0gbG9nLm1hc2tTZW5zaXRpdmVVcmwobWFza1VybCk7XG4gIH1cbiAgcmV0dXJuIG1hc2tVcmw7XG59XG4iXSwibWFwcGluZ3MiOiI7Ozs7OztBQU9BLElBQUFBLEtBQUEsR0FBQUMsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFDLFFBQUEsR0FBQUYsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFFLE9BQUEsR0FBQUgsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFHLEtBQUEsR0FBQUgsT0FBQTtBQUErQixTQUFBRCx1QkFBQUssQ0FBQSxXQUFBQSxDQUFBLElBQUFBLENBQUEsQ0FBQUMsVUFBQSxHQUFBRCxDQUFBLEtBQUFFLE9BQUEsRUFBQUYsQ0FBQTtBQVYvQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBTUEsTUFBTUcsS0FBSyxHQUFHUCxPQUFPLENBQUMsMEJBQTBCLENBQUM7QUFFakQsU0FBU1EsaUJBQWlCQSxDQUFDQyxHQUFHLEVBQUVDLEtBQUssRUFBRTtFQUNyQyxJQUFJRCxHQUFHLElBQUksV0FBVyxFQUFFO0lBQ3RCLElBQUlDLEtBQUssQ0FBQ0MsS0FBSyxDQUFDLHlCQUF5QixDQUFDLEVBQUU7TUFDMUMsT0FBT0QsS0FBSztJQUNkO0VBQ0YsQ0FBQyxNQUFNLElBQUlELEdBQUcsSUFBSSxVQUFVLEVBQUU7SUFDNUIsSUFBSUMsS0FBSyxDQUFDQyxLQUFLLENBQUMsY0FBYyxDQUFDLEVBQUU7TUFDL0IsT0FBT0QsS0FBSztJQUNkO0VBQ0YsQ0FBQyxNQUFNO0lBQ0wsT0FBT0EsS0FBSztFQUNkO0FBQ0Y7QUFFZSxNQUFNRSxhQUFhLENBQUM7RUFDakM7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0FDLFdBQVdBLENBQUNDLE1BQU0sR0FBRyxFQUFFLEVBQUVDLEtBQUssRUFBRTtJQUM5QixJQUFJLENBQUNELE1BQU0sR0FBR0EsTUFBTTtJQUNwQixJQUFJLENBQUNDLEtBQUssR0FBR0EsS0FBSztJQUNsQixJQUFJLENBQUNDLFdBQVcsQ0FB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QjtRQUNGO1FBRUEsSUFBSUgsTUFBTSxDQUFDRSxRQUFRLEVBQUU7VUFDbkJYLEdBQUcsQ0FBQ2lCLEdBQUcsQ0FBQyxVQUFVLEVBQUVSLE1BQU0sQ0FBQ0UsUUFBUSxDQUFDO1VBQ3BDO1VBQ0E7VUFDQSxJQUFJLENBQUNGLE1BQU0sQ0FBQ0MsUUFBUSxFQUFFO1lBQ3BCVixHQUFHLENBQUNrQixJQUFJLENBQUMsd0JBQXdCLEdBQUdULE1BQU0sQ0FBQ0UsUUFBUSxDQUFDO1lBQ3BEO1VBQ0Y7UUFDRjtRQUNBWCxHQUFHLENBQUNtQixJQUFJLENBQUNWLE1BQU0sQ0FBQ0MsUUFBUSxDQUFDO01BQzNCLENBQUMsRUFDREcsS0FBSyxJQUFJO1FBQ1BaLElBQUksQ0FBQ1ksS0FBSyxDQUFDO01BQ2IsQ0FDRixDQUFDLENBQ0FPLEtBQUssQ0FBQ3JFLENBQUMsSUFBSTtRQUNWd0QsZUFBRyxDQUFDTSxLQUFLLENBQUMsOEJBQThCLElBQUFRLGFBQU8sRUFBQ3RFLENBQUMsQ0FBQyxFQUFFLEVBQUU7VUFBRThELEtBQUssRUFBRTlEO1FBQUUsQ0FBQyxDQUFDO1FBQ25Fa0QsSUFBSSxDQUFDbEQsQ0FBQyxDQUFDO01BQ1QsQ0FBQyxDQUFDO0lBQ04sQ0FBQyxDQUFDLE9BQU9BLENBQUMsRUFBRTtNQUNWd0QsZUFBRyxDQUFDTSxLQUFLLENBQUMsMkJBQTJCLElBQUFRLGFBQU8sRUFBQ3RFLENBQUMsQ0FBQyxFQUFFLEVBQUU7UUFBRThELEtBQUssRUFBRTlEO01BQUUsQ0FBQyxDQUFDO01BQ2hFa0QsSUFBSSxDQUFDbEQsQ0FBQyxDQUFDO0lBQ1Q7RUFDRixDQUFDO0FBQ0g7QUFFQSxTQUFTb0QsZ0JBQWdCQSxDQUFDOUIsR0FBRyxFQUFFO0VBQzdCLElBQUlpRCxPQUFPLEdBQUdqRCxHQUFHLENBQUNrRCxXQUFXLENBQUNDLFFBQVEsQ0FBQyxDQUFDO0VBQ3hDLE1BQU1DLGFBQWEsR0FDakJwRCxHQUFHLENBQUNMLE1BQU0sS0FBSyxLQUFLLElBQ3BCSyxHQUFHLENBQUNrRCxXQUFXLENBQUNHLFFBQVEsQ0FBQyxRQUFRLENBQUMsSUFDbEMsQ0FBQ3JELEdBQUcsQ0FBQ2tELFdBQVcsQ0FBQ0csUUFBUSxDQUFDLFNBQVMsQ0FBQztFQUN0QyxJQUFJRCxhQUFhLEVBQUU7SUFDakJILE9BQU8sR0FBR2YsZUFBRyxDQUFDSixnQkFBZ0IsQ0FBQ21CLE9BQU8sQ0FBQztFQUN6QztFQUNBLE9BQU9BLE9BQU87QUFDaEIiLCJpZ25vcmVMaXN0IjpbXX0=