@bxjs/base
Version:
bxjs base framework & api
250 lines • 32.8 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
Object.defineProperty(exports, "__esModule", { value: true });
// 根据架构设计约定自动识别各种运行环境
if (process.env['NODE_ENV']) {
global['__env__'] = process.env['NODE_ENV'];
}
else {
if (process.argv.length >= 3 && process.argv[2] == 'https') {
// 预发环境配置
global['__env__'] = 'pre';
}
else if (process.argv.length >= 3 && process.argv[2] == 'http') {
// 日常环境配置
global['__env__'] = 'daily';
}
else {
// 本地环境配置
global['__env__'] = 'local';
}
}
if (global['__env__'] != 'local') {
require('source-map-support').install();
}
require('tsconfig-paths').register();
var express = require('express');
var app = express();
var _ = require('lodash');
var path = require('path');
var http = require('http');
var https = require('https');
var fs = require('fs');
var init_1 = require("./init");
// 端口号启动参数配置
var PORT = parseInt(process.argv[2]);
if (!PORT) {
PORT = 8888;
}
// 设置静态资源路径(必须要使用绝对路径)
app.use(express.static(path.join(init_1.get_root_path_prefix(), './static')));
// 引入json解析中间件
var bodyParser = require('body-parser');
app.use(function (req, res, next) {
var rawBody = [];
var size = 0;
req.on('data', function (data) {
rawBody.push(data);
size += data.length;
});
req.on('end', function () {
// 获取原始的content-type对应的body内容自行解析处理,解决本地环境和线上环境不兼容问题。
req.rawBody = Buffer.concat(rawBody, size).toString();
});
next();
});
// 添加json解析
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
// 允许所有的请求形式
app.use(function (req, res, next) {
if (req.headers.origin) {
// 获取源站动态允许请求跨域 (FIXME 需要进行安全限制对来源服务器网址合法性进行安全限制,本地开发调试全部放开请求)
res.header("Access-Control-Allow-Origin", req.headers.origin);
}
// res.header("Access-Control-Allow-Origin", "*")
res.header("Access-Control-Allow-Credentials", "true");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept,u_token");
res.header('Access-Control-Allow-Methods', 'POST, OPTIONS');
next();
});
// 本地调试使用路由重定向映射功能模拟
var routes = require(path.join(init_1.get_root_path_prefix(), './app/entries/route.map')).default;
var _loop_1 = function (k) {
app.all(k, function (req, res) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
req.headers.__api__ = routes[k].path;
callback(req, res);
return [2 /*return*/];
});
});
});
};
for (var k in routes) {
_loop_1(k);
}
// TODO SLS日志机制云端对接、监控机制的业务对接、性能测试的对接、ACM配置机制的对接、报错机制信息的正确解析处理、
// TODO COOKIE解析、BUC登录验证、 会议室信息的JAVA接口联调、梅丽莎多语言对接、ACM的配置发布
// TODO 错误页处理、SESSION模拟基于TableStore的实现、REST的实现、更多PAAS中间件根据业务需要对接集成进来、实际业务问题更多的优化扩展。。。
// 匹配不包含.的所有路由进行处理,否则表示文件静态资源需要单独处理。(API网关不返回任何静态资源,静态资源需要全部上传到CDN上,API网关只处理一个网站图标请求)
app.all(/^((?!\.).)*$/, callback);
// TODO 通过请求的域名和入口文件的位置,自动区分:本地、日常、预发、线上,四种环境。(灰度通过线上版本位置自动区分)
// 加载配置文件信息。。。比较特殊需要在每次请求的时候单独处理。
// 日常与预发在一台机器上需要分别启动两个独立nodejs进程进行处理,确保二者内部运行太壮数据的隔离性。
// nodejs服务支持证书配置问题,使用正式的域名证书进行绑定配置,测试的时候本地配置域名链接确保正常。
if (process.argv[2] == 'https') {
// 预发绑定HTTPS服务(对应AONE的日常机器)
var privateKey = fs.readFileSync(path.join(init_1.get_root_path_prefix(), './secrete/private.pem'), 'utf8');
var certificate = fs.readFileSync(path.join(init_1.get_root_path_prefix(), './secrete/public.crt'), 'utf8');
var credentials = { key: privateKey, cert: certificate };
var httpsServer = https.createServer(credentials, app);
httpsServer.listen(443, function () {
// console.log('fc pre-release-test app listening on port 443!')
process.send('fc pre-release-test app listening on port 443!');
});
}
else if (process.argv[2] == 'http') {
// 日常绑定HTTP服务(对应AONE的日常机器,一台机器同时配置HTTP日常和HTTPS预发)
var httpServer = http.createServer(app);
httpServer.listen(80, function () {
// console.log('fc test app listening on port 80!')
process.send('fc test app listening on port 80!');
});
}
else {
// 本地开发环境HTTP协议绑定指定的端口号
var httpServer = http.createServer(app);
httpServer.listen(PORT, function () {
process.send("fc test app listening on port " + PORT + ", visit http://127.0.0.1:" + PORT);
// console.log(`fc test app listening on port ${PORT}, visit http://127.0.0.1:${PORT}`)
});
}
function callback(req, res) {
return __awaiter(this, void 0, void 0, function () {
var err_1;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
_a.trys.push([0, 2, , 3]);
return [4 /*yield*/, __callback__(req, res)];
case 1:
_a.sent();
return [3 /*break*/, 3];
case 2:
err_1 = _a.sent();
return [3 /*break*/, 3];
case 3:
// 按照CGI模式每个子进程处理一个唯一的请求确保全局变量的唯一性简化代码实现避免潜在的并发问题
process.exit();
return [2 /*return*/];
}
});
});
}
function __callback__(req, res) {
return __awaiter(this, void 0, void 0, function () {
var param, __api__, __url__, __header__, out, err_2;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
param = req.query || {};
__api__ = req.headers.__api__ ? req.headers.__api__ : req.path;
__url__ = req.protocol + '://' + req.get('host') + req.originalUrl;
_a.label = 1;
case 1:
_a.trys.push([1, 3, , 5]);
// 请求参数的自动格式化处理兼容get和post协议方便开发调试
switch (req.method) {
case 'GET':
break;
case 'POST':
param = xassign(param, init_1.parse_post_param(req.headers, req.rawBody));
break;
case 'OPTIONS':
// 仅仅支持本地开发跨域调试,线上需要禁止此方法的调用应该同域请求处理。
res.sendStatus(200);
return [2 /*return*/];
default:
// 400 Bad Request 客户端请求的语法错误,服务器无法理解
res.sendStatus(400);
return [2 /*return*/];
}
__header__ = req.headers;
param = xassign(param, { __api__: __api__, __url__: __url__, __header__: __header__ });
// 解析请求中的cookies数据并转换为JSON对象存储到全局变量中便于后续应用xcookie接口使用
global['__request_cookies__'] = require('cookie').parse(_.get(req.headers, 'cookie', ''));
// 获取use-agent请求头部信息
global['__user_agent__'] = req['headers'] ? (req['headers']['user-agent'] ? req['headers']['user-agent'] : '') : '';
// 取到客户端的IP地址信息
global['__client_ip__'] = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
return [4 /*yield*/, init_1.request_process(__api__, param)
// 处理response的cookies设置
];
case 2:
out = _a.sent();
// 处理response的cookies设置
if (!_.isEmpty(global['__respond_cookies__'])) {
res.setHeader('Set-Cookie', _.values(global['__respond_cookies__']));
}
if (global['__redirect_url__']) {
res.redirect(302, global['__redirect_url__']);
global['__redirect_url__'] = undefined;
return [2 /*return*/];
}
res.send(out);
return [3 /*break*/, 5];
case 3:
err_2 = _a.sent();
// 通知框架自身实现逻辑的意外报错(框架自身不论何种情况都应该正常工作,一旦出现此问题大多数情况是框架自身问题或者流量引发的运维问题)
return [4 /*yield*/, xwarn({
__api__: __api__, __url__: __url__, param: param, message: err_2.message, stack: xstack(err_2)
})
// 500 Internal Server Error 服务器内部错误,无法完成请求
];
case 4:
// 通知框架自身实现逻辑的意外报错(框架自身不论何种情况都应该正常工作,一旦出现此问题大多数情况是框架自身问题或者流量引发的运维问题)
_a.sent();
// 500 Internal Server Error 服务器内部错误,无法完成请求
res.sendStatus(500);
return [3 /*break*/, 5];
case 5: return [2 /*return*/];
}
});
});
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVzdC1jbGllbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJ0ZXN0LWNsaWVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUEscUJBQXFCO0FBQ3JCLElBQUksT0FBTyxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsRUFBRTtJQUN6QixNQUFNLENBQUMsU0FBUyxDQUFDLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsQ0FBQTtDQUM5QztLQUFNO0lBQ0gsSUFBSSxPQUFPLENBQUMsSUFBSSxDQUFDLE1BQU0sSUFBSSxDQUFDLElBQUksT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsSUFBSSxPQUFPLEVBQUU7UUFDeEQsU0FBUztRQUNULE1BQU0sQ0FBQyxTQUFTLENBQUMsR0FBRyxLQUFLLENBQUE7S0FDNUI7U0FBTSxJQUFJLE9BQU8sQ0FBQyxJQUFJLENBQUMsTUFBTSxJQUFJLENBQUMsSUFBSSxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFJLE1BQU0sRUFBRTtRQUM5RCxTQUFTO1FBQ1QsTUFBTSxDQUFDLFNBQVMsQ0FBQyxHQUFHLE9BQU8sQ0FBQTtLQUM5QjtTQUNJO1FBQ0QsU0FBUztRQUNULE1BQU0sQ0FBQyxTQUFTLENBQUMsR0FBRyxPQUFPLENBQUE7S0FDOUI7Q0FDSjtBQUNELElBQUksTUFBTSxDQUFDLFNBQVMsQ0FBQyxJQUFJLE9BQU8sRUFBRTtJQUM5QixPQUFPLENBQUMsb0JBQW9CLENBQUMsQ0FBQyxPQUFPLEVBQUUsQ0FBQTtDQUMxQztBQUNELE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDLFFBQVEsRUFBRSxDQUFBO0FBQ3BDLElBQU0sT0FBTyxHQUFHLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQTtBQUNsQyxJQUFNLEdBQUcsR0FBRyxPQUFPLEVBQUUsQ0FBQTtBQUNyQixJQUFNLENBQUMsR0FBRyxPQUFP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Q0FBQyxhQUFhLENBQUE7b0JBRzlFLHFCQUFNLHNCQUFlLENBQUMsT0FBTyxFQUFFLEtBQUssQ0FBQzt3QkFFL0MsdUJBQXVCO3NCQUZ3Qjs7b0JBQTNDLEdBQUcsR0FBRyxTQUFxQztvQkFFL0MsdUJBQXVCO29CQUN2QixJQUFJLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMscUJBQXFCLENBQUMsQ0FBQyxFQUFFO3dCQUMzQyxHQUFHLENBQUMsU0FBUyxDQUFDLFlBQVksRUFBRSxDQUFDLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDLENBQUMsQ0FBQTtxQkFDdkU7b0JBRUQsSUFBSSxNQUFNLENBQUMsa0JBQWtCLENBQUMsRUFBRTt3QkFDNUIsR0FBRyxDQUFDLFFBQVEsQ0FBQyxHQUFHLEVBQUUsTUFBTSxDQUFDLGtCQUFrQixDQUFDLENBQUMsQ0FBQTt3QkFDN0MsTUFBTSxDQUFDLGtCQUFrQixDQUFDLEdBQUcsU0FBUyxDQUFBO3dCQUN0QyxzQkFBTTtxQkFDVDtvQkFDRCxHQUFHLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFBOzs7O29CQUViLG9FQUFvRTtvQkFDcEUscUJBQU0sS0FBSyxDQUFDOzRCQUNSLE9BQU8sU0FBQSxFQUFFLE9BQU8sU0FBQSxFQUFFLEtBQUssT0FBQSxFQUFFLE9BQU8sRUFBRSxLQUFHLENBQUMsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLENBQUMsS0FBRyxDQUFDO3lCQUNwRSxDQUFDO3dCQUNGLDJDQUEyQztzQkFEekM7O29CQUhGLG9FQUFvRTtvQkFDcEUsU0FFRSxDQUFBO29CQUNGLDJDQUEyQztvQkFDM0MsR0FBRyxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsQ0FBQTs7Ozs7O0NBRTFCIiwic291cmNlc0NvbnRlbnQiOlsiLy8g5qC55o2u5p625p6E6K6+6K6h57qm5a6a6Ieq5Yqo6K+G5Yir5ZCE56eN6L+Q6KGM546v5aKDXG5pZiAocHJvY2Vzcy5lbnZbJ05PREVfRU5WJ10pIHtcbiAgICBnbG9iYWxbJ19fZW52X18nXSA9IHByb2Nlc3MuZW52WydOT0RFX0VOViddXG59IGVsc2Uge1xuICAgIGlmIChwcm9jZXNzLmFyZ3YubGVuZ3RoID49IDMgJiYgcHJvY2Vzcy5hcmd2WzJdID09ICdodHRwcycpIHtcbiAgICAgICAgLy8g6aKE5Y+R546v5aKD6YWN572uXG4gICAgICAgIGdsb2JhbFsnX19lbnZfXyddID0gJ3ByZSdcbiAgICB9IGVsc2UgaWYgKHByb2Nlc3MuYXJndi5sZW5ndGggPj0gMyAmJiBwcm9jZXNzLmFyZ3ZbMl0gPT0gJ2h0dHAnKSB7XG4gICAgICAgIC8vIOaXpeW4uOeOr+Wig+mFjee9rlxuICAgICAgICBnbG9iYWxbJ19fZW52X18nXSA9ICdkYWlseSdcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIC8vIOacrOWcsOeOr+Wig+mFjee9rlxuICAgICAgICBnbG9iYWxbJ19fZW52X18nXSA9ICdsb2NhbCdcbiAgICB9XG59XG5pZiAoZ2xvYmFsWydfX2Vudl9fJ10gIT0gJ2xvY2FsJykge1xuICAgIHJlcXVpcmUoJ3NvdXJjZS1tYXAtc3VwcG9ydCcpLmluc3RhbGwoKVxufVxucmVxdWlyZSgndHNjb25maWctcGF0aHMnKS5yZWdpc3RlcigpXG5jb25zdCBleHByZXNzID0gcmVxdWlyZSgnZXhwcmVzcycpXG5jb25zdCBhcHAgPSBleHByZXNzKClcbmNvbnN0IF8gPSByZXF1aXJlKCdsb2Rhc2gnKVxuY29uc3QgcGF0aCA9IHJlcXVpcmUoJ3BhdGgnKVxuY29uc3QgaHR0cCA9IHJlcXVpcmUoJ2h0dHAnKVxuY29uc3QgaHR0cHMgPSByZXF1aXJlKCdodHRwcycpXG5jb25zdCBmcyA9IHJlcXVpcmUoJ2ZzJylcbmltcG9ydCB7Z2V0X3Jvb3RfcGF0aF9wcmVmaXgsIHJlcXVlc3RfcHJvY2VzcywgcGFyc2VfcG9zdF9wYXJhbX0gZnJvbSAnLi9pbml0J1xuXG4vLyDnq6/lj6Plj7flkK/liqjlj4LmlbDphY3nva5cbmxldCBQT1JUOiBhbnkgPSBwYXJzZUludChwcm9jZXNzLmFyZ3ZbMl0pXG5pZiAoIVBPUlQpIHtcbiAgICBQT1JUID0gODg4OFxufVxuXG4vLyDorr7nva7pnZnmgIHotYTmupDot6/lvoTvvIjlv4XpobvopoHkvb/nlKjnu53lr7not6/lvoTvvIlcbmFwcC51c2UoZXhwcmVzcy5zdGF0aWMocGF0aC5qb2luKGdldF9yb290X3BhdGhfcHJlZml4KCksICcuL3N0YXRpYycpKSlcblxuLy8g5byV5YWlanNvbuino+aekOS4remXtOS7tlxuY29uc3QgYm9keVBhcnNlciA9IHJlcXVpcmUoJ2JvZHktcGFyc2VyJylcbmFwcC51c2UoZnVuY3Rpb24gKHJlcSwgcmVzLCBuZXh0KSB7XG4gICAgdmFyIHJhd0JvZHkgPSBbXVxuICAgIHZhciBzaXplID0gMFxuICAgIHJlcS5vbignZGF0YScsIGZ1bmN0aW9uIChkYXRhKSB7XG4gICAgICAgIHJhd0JvZHkucHVzaChkYXRhKVxuICAgICAgICBzaXplICs9IGRhdGEubGVuZ3RoXG4gICAgfSlcbiAgICByZXEub24oJ2VuZCcsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgLy8g6I635Y+W5Y6f5aeL55qEY29udGVudC10eXBl5a+55bqU55qEYm9keeWGheWuueiHquihjOino+aekOWkhOeQhu+8jOino+WGs+acrOWcsOeOr+Wig+WSjOe6v+S4iueOr+Wig+S4jeWFvOWuuemXrumimOOAglxuICAgICAgICByZXEucmF3Qm9keSA9IEJ1ZmZlci5jb25jYXQocmF3Qm9keSwgc2l6ZSkudG9TdHJpbmcoKVxuICAgIH0pXG4gICAgbmV4dCgpXG59KVxuLy8g5re75YqganNvbuino+aekFxuYXBwLnVzZShib2R5UGFyc2VyLmpzb24oKSlcbmFwcC51c2UoYm9keVBhcnNlci51cmxlbmNvZGVkKHtleHRlbmRlZDogZmFsc2V9KSlcbi8vIOWFgeiuuOaJgOacieeahOivt+axguW9ouW8j1xuYXBwLnVzZShmdW5jdGlvbiAocmVxLCByZXMsIG5leHQpIHtcbiAgICBpZiAocmVxLmhlYWRlcnMub3JpZ2luKSB7XG4gICAgICAgIC8vIOiOt+WPlua6kOermeWKqOaAgeWFgeiuuOivt+axgui3qOWfnyAoRklYTUUg6ZyA6KaB6L+b6KGM5a6J5YWo6ZmQ5Yi25a+55p2l5rqQ5pyN5Yqh5Zmo572R5Z2A5ZCI5rOV5oCn6L+b6KGM5a6J5YWo6ZmQ5Yi277yM5pys5Zyw5byA5Y+R6LCD6K+V5YWo6YOo5pS+5byA6K+35rGCKVxuICAgICAgICByZXMuaGVhZGVyKFwiQWNjZXNzLUNvbnRyb2wtQWxsb3ctT3JpZ2luXCIsIHJlcS5oZWFkZXJzLm9yaWdpbik7XG4gICAgfVxuICAgIC8vIHJlcy5oZWFkZXIoXCJBY2Nlc3MtQ29udHJvbC1BbGxvdy1PcmlnaW5cIiwgXCIqXCIpXG4gICAgcmVzLmhlYWRlcihcIkFjY2Vzcy1Db250cm9sLUFsbG93LUNyZWRlbnRpYWxzXCIsIFwidHJ1ZVwiKVxuICAgIHJlcy5oZWFkZXIoXCJBY2Nlc3MtQ29udHJvbC1BbGxvdy1IZWFkZXJzXCIsIFwiT3JpZ2luLCBYLVJlcXVlc3RlZC1XaXRoLCBDb250ZW50LVR5cGUsIEFjY2VwdCx1X3Rva2VuXCIpXG4gICAgcmVzLmhlYWRlcignQWNjZXNzLUNvbnRyb2wtQWxsb3ctTWV0aG9kcycsICdQT1NULCBPUFRJT05TJylcbiAgICBuZXh0KClcbn0pXG5cbi8vIOacrOWcsOiwg+ivleS9v+eUqOi3r+eUsemHjeWumuWQkeaYoOWwhOWKn+iDveaooeaLn1xuY29uc3Qgcm91dGVzID0gcmVxdWlyZShwYXRoLmpvaW4oZ2V0X3Jvb3RfcGF0aF9wcmVmaXgoKSwgJy4vYXBwL2VudHJpZXMvcm91dGUubWFwJykpLmRlZmF1bHRcbmZvciAobGV0IGsgaW4gcm91dGVzKSB7XG4gICAgYXBwLmFsbChrLCBhc3luYyBmdW5jdGlvbiAocmVxLCByZXMpIHtcbiAgICAgICAgcmVxLmhlYWRlcnMuX19hcGlfXyA9IHJvdXRlc1trXS5wYXRoXG4gICAgICAgIGNhbGxiYWNrKHJlcSwgcmVzKVxuICAgIH0pXG59XG5cbi8vIFRPRE8gU0xT5pel5b+X5py65Yi25LqR56uv5a+55o6l44CB55uR5o6n5py65Yi255qE5Lia5Yqh5a+55o6l44CB5oCn6IO95rWL6K+V55qE5a+55o6l44CBQUNN6YWN572u5py65Yi255qE5a+55o6l44CB5oql6ZSZ5py65Yi25L+h5oGv55qE5q2j56Gu6Kej5p6Q5aSE55CG44CBXG4vLyBUT0RPIENPT0tJReino+aekOOAgUJVQ+eZu+W9lemqjOivgeOAgSAgIOS8muiuruWupOS/oeaBr+eahEpBVkHmjqXlj6PogZTosIPjgIHmooXkuL3ojo7lpJror63oqIDlr7nmjqXjgIFBQ03nmoTphY3nva7lj5HluINcbi8vIFRPRE8g6ZSZ6K+v6aG15aSE55CG44CBU0VTU0lPTuaooeaLn+WfuuS6jlRhYmxlU3RvcmXnmoTlrp7njrDjgIFSRVNU55qE5a6e546w44CB5pu05aSaUEFBU+S4remXtOS7tuagueaNruS4muWKoemcgOimgeWvueaOpembhuaIkOi/m+adpeOAgeWunumZheS4muWKoemXrumimOabtOWkmueahOS8mOWMluaJqeWxleOAguOAguOAglxuLy8g5Yy56YWN5LiN5YyF5ZCrLueahOaJgOaciei3r+eUsei/m+ihjOWkhOeQhu+8jOWQpuWImeihqOekuuaWh+S7tumdmeaAgei1hOa6kOmcgOimgeWNleeLrOWkhOeQhuOAgu+8iEFQSee9keWFs+S4jei/lOWbnuS7u+S9lemdmeaAgei1hOa6kO+8jOmdmeaAgei1hOa6kOmcgOimgeWFqOmDqOS4iuS8oOWIsENETuS4iu+8jEFQSee9keWFs+WPquWkhOeQhuS4gOS4que9keermeWbvuagh+ivt+axgu+8iVxuYXBwLmFsbCgvXigoPyFcXC4pLikqJC8sIGNhbGxiYWNrKVxuXG4vLyBUT0RPIOmAmui/h+ivt+axgueahOWfn+WQjeWSjOWFpeWPo+aWh+S7tueahOS9jee9ru+8jOiHquWKqOWMuuWIhu+8muacrOWcsOOAgeaXpeW4uOOAgemihOWPkeOAgee6v+S4iu+8jOWbm+enjeeOr+Wig+OAgu+8iOeBsOW6pumAmui/h+e6v+S4iueJiOacrOS9jee9ruiHquWKqOWMuuWIhu+8iVxuLy8g5Yqg6L296YWN572u5paH5Lu25L+h5oGv44CC44CC44CC5q+U6L6D54m55q6K6ZyA6KaB5Zyo5q+P5qyh6K+35rGC55qE5pe25YCZ5Y2V54us5aSE55CG44CCXG4vLyDml6XluLjkuI7pooTlj5HlnKjkuIDlj7DmnLrlmajkuIrpnIDopoHliIbliKvlkK/liqjkuKTkuKrni6znq4tub2RlanPov5vnqIvov5vooYzlpITnkIbvvIznoa7kv53kuozogIXlhoXpg6jov5DooYzlpKrlo67mlbDmja7nmoTpmpTnprvmgKfjgIJcblxuLy8gbm9kZWpz5pyN5Yqh5pSv5oyB6K+B5Lmm6YWN572u6Zeu6aKY77yM5L2/55So5q2j5byP55qE5Z+f5ZCN6K+B5Lmm6L+b6KGM57uR5a6a6YWN572u77yM5rWL6K+V55qE5pe25YCZ5pys5Zyw6YWN572u5Z+f5ZCN6ZO+5o6l56Gu5L+d5q2j5bi444CCXG5pZiAocHJvY2Vzcy5hcmd2WzJdID09ICdodHRwcycpIHtcbiAgICAvLyDpooTlj5Hnu5HlrppIVFRQU+acjeWKoe+8iOWvueW6lEFPTkXnmoTml6XluLjmnLrlmajvvIlcbiAgICBjb25zdCBwcml2YXRlS2V5ID0gZnMucmVhZEZpbGVTeW5jKFxuICAgICAgICBwYXRoLmpvaW4oZ2V0X3Jvb3RfcGF0aF9wcmVmaXgoKSwgJy4vc2VjcmV0ZS9wcml2YXRlLnBlbScpLCAndXRmOCcpXG4gICAgY29uc3QgY2VydGlmaWNhdGUgPSBmcy5yZWFkRmlsZVN5bmMoXG4gICAgICAgIHBhdGguam9pbihnZXRfcm9vdF9wYXRoX3ByZWZpeCgpLCAnLi9zZWNyZXRlL3B1YmxpYy5jcnQnKSwgJ3V0ZjgnKVxuICAgIGNvbnN0IGNyZWRlbnRpYWxzID0ge2tleTogcHJpdmF0ZUtleSwgY2VydDogY2VydGlmaWNhdGV9XG4gICAgY29uc3QgaHR0cHNTZXJ2ZXIgPSBodHRwcy5jcmVhdGVTZXJ2ZXIoY3JlZGVudGlhbHMsIGFwcClcbiAgICBodHRwc1NlcnZlci5saXN0ZW4oNDQzLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgIC8vIGNvbnNvbGUubG9nKCdmYyBwcmUtcmVsZWFzZS10ZXN0IGFwcCBsaXN0ZW5pbmcgb24gcG9ydCA0NDMhJylcbiAgICAgICAgcHJvY2Vzcy5zZW5kKCdmYyBwcmUtcmVsZWFzZS10ZXN0IGFwcCBsaXN0ZW5pbmcgb24gcG9ydCA0NDMhJylcbiAgICB9KVxufSBlbHNlIGlmIChwcm9jZXNzLmFyZ3ZbMl0gPT0gJ2h0dHAnKSB7XG4gICAgLy8g5pel5bi457uR5a6aSFRUUOacjeWKoe+8iOWvueW6lEFPTkXnmoTml6XluLjmnLrlmajvvIzkuIDlj7DmnLrlmajlkIzml7bphY3nva5IVFRQ5pel5bi45ZKMSFRUUFPpooTlj5HvvIlcbiAgICBjb25zdCBodHRwU2VydmVyID0gaHR0cC5jcmVhdGVTZXJ2ZXIoYXBwKVxuICAgIGh0dHBTZXJ2ZXIubGlzdGVuKDgwLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgIC8vIGNvbnNvbGUubG9nKCdmYyB0ZXN0IGFwcCBsaXN0ZW5pbmcgb24gcG9ydCA4MCEnKVxuICAgICAgICBwcm9jZXNzLnNlbmQoJ2ZjIHRlc3QgYXBwIGxpc3RlbmluZyBvbiBwb3J0IDgwIScpXG4gICAgfSlcbn0gZWxzZSB7XG4gICAgLy8g5pys5Zyw5byA5Y+R546v5aKDSFRUUOWNj+iurue7keWumuaMh+WumueahOerr+WPo+WPt1xuICAgIGNvbnN0IGh0dHBTZXJ2ZXIgPSBodHRwLmNyZWF0ZVNlcnZlcihhcHApXG4gICAgaHR0cFNlcnZlci5saXN0ZW4oUE9SVCwgZnVuY3Rpb24gKCkge1xuICAgICAgICBwcm9jZXNzLnNlbmQoYGZjIHRlc3QgYXBwIGxpc3RlbmluZyBvbiBwb3J0ICR7UE9SVH0sIHZpc2l0IGh0dHA6Ly8xMjcuMC4wLjE6JHtQT1JUfWApXG4gICAgICAgIC8vIGNvbnNvbGUubG9nKGBmYyB0ZXN0IGFwcCBsaXN0ZW5pbmcgb24gcG9ydCAke1BPUlR9LCB2aXNpdCBodHRwOi8vMTI3LjAuMC4xOiR7UE9SVH1gKVxuICAgIH0pXG59XG5cbmFzeW5jIGZ1bmN0aW9uIGNhbGxiYWNrKHJlcSwgcmVzKSB7XG4gICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgX19jYWxsYmFja19fKHJlcSwgcmVzKVxuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAvLyBpZ25vcmUgZXJyb3JcbiAgICB9XG4gICAgLy8g5oyJ54WnQ0dJ5qih5byP5q+P5Liq5a2Q6L+b56iL5aSE55CG5LiA5Liq5ZSv5LiA55qE6K+35rGC56Gu5L+d5YWo5bGA5Y+Y6YeP55qE5ZSv5LiA5oCn566A5YyW5Luj56CB5a6e546w6YG/5YWN5r2c5Zyo55qE5bm25Y+R6Zeu6aKYXG4gICAgcHJvY2Vzcy5leGl0KClcbn1cblxuYXN5bmMgZnVuY3Rpb24gX19jYWxsYmFja19fKHJlcSwgcmVzKSB7XG4gICAgbGV0IHBhcmFtID0gcmVxLnF1ZXJ5IHx8IHt9XG4gICAgLy8g6KGl5LiK5qGG5p626aKE5a6a5LmJ55qE57y655yB5Y+C5pWwX191cmxfXyjlhbbku5bmm7TlpJrmoYbmnrblj4LmlbBfX2FwaV9fIF9fZGVidWdfXyBfX21vY2tfXyBUT0RPIF9fcGFyYW1fXyDlnKhnZXTkuK1qc29u5a2X56ym5Liy55qEYmFzZTY05qC85byPKVxuICAgIGxldCBfX2FwaV9fID0gcmVxLmhlYWRlcnMuX19hcGlfXyA/IHJlcS5oZWFkZXJzLl9fYXBpX18gOiByZXEucGF0aFxuICAgIGxldCBfX3VybF9fID0gcmVxLnByb3RvY29sICsgJzovLycgKyByZXEuZ2V0KCdob3N0JykgKyByZXEub3JpZ2luYWxVcmxcblxuICAgIHRyeSB7XG4gICAgICAgIC8vIOivt+axguWPguaVsOeahOiHquWKqOagvOW8j+WMluWkhOeQhuWFvOWuuWdldOWSjHBvc3TljY/orq7mlrnkvr/lvIDlj5HosIPor5VcbiAgICAgICAgc3dpdGNoIChyZXEubWV0aG9kKSB7XG4gICAgICAgICAgICBjYXNlICdHRVQnOlxuICAgICAgICAgICAgICAgIGJyZWFrXG4gICAgICAgICAgICBjYXNlICdQT1NUJzpcbiAgICAgICAgICAgICAgICBwYXJhbSA9IHhhc3NpZ24ocGFyYW0sIHBhcnNlX3Bvc3RfcGFyYW0ocmVxLmhlYWRlcnMsIHJlcS5yYXdCb2R5KSlcbiAgICAgICAgICAgICAgICBicmVha1xuICAgICAgICAgICAgY2FzZSAnT1BUSU9OUyc6XG4gICAgICAgICAgICAgICAgLy8g5LuF5LuF5pSv5oyB5pys5Zyw5byA5Y+R6Leo5Z+f6LCD6K+V77yM57q/5LiK6ZyA6KaB56aB5q2i5q2k5pa55rOV55qE6LCD55So5bqU6K+l5ZCM5Z+f6K+35rGC5aSE55CG44CCXG4gICAgICAgICAgICAgICAgcmVzLnNlbmRTdGF0dXMoMjAwKVxuICAgICAgICAgICAgICAgIHJldHVyblxuICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgICAvLyA0MDAgIEJhZCBSZXF1ZXN0XHTlrqLmiLfnq6/or7fmsYLnmoTor63ms5XplJnor6/vvIzmnI3liqHlmajml6Dms5XnkIbop6NcbiAgICAgICAgICAgICAgICByZXMuc2VuZFN0YXR1cyg0MDApXG4gICAgICAgICAgICAgICAgcmV0dXJuXG4gICAgICAgIH1cbiAgICAgICAgLy8g6KGl5LiK6K+35rGC55qESEVBREVS5Y+C5pWw5Yiw5bqU55So5Lit6L+b6KGM6Ieq6KGM5aSE55CG5Lia5Yqh6YC76L6R5a6a5Yi255qE6K+35rGC5aS06YOo5L+h5oGvXG4gICAgICAgIGxldCBfX2hlYWRlcl9fID0gcmVxLmhlYWRlcnNcbiAgICAgICAgcGFyYW0gPSB4YXNzaWduKHBhcmFtLCB7X19hcGlfXywgX191cmxfXywgX19oZWFkZXJfX30pXG5cbiAgICAgICAgLy8g6Kej5p6Q6K+35rGC5Lit55qEY29va2llc+aVsOaNruW5tui9rOaNouS4ukpTT07lr7nosaHlrZjlgqjliLDlhajlsYDlj5jph4/kuK3kvr/kuo7lkI7nu63lupTnlKh4Y29va2ll5o6l5Y+j5L2/55SoXG4gICAgICAgIGdsb2JhbFsnX19yZXF1ZXN0X2Nvb2tpZXNfXyddID0gcmVxdWlyZSgnY29va2llJykucGFyc2UoXy5nZXQocmVxLmhlYWRlcnMsICdjb29raWUnLCAnJykpXG5cbiAgICAgICAgLy8g6I635Y+WdXNlLWFnZW506K+35rGC5aS06YOo5L+h5oGvXG4gICAgICAgIGdsb2JhbFsnX191c2VyX2FnZW50X18nXSA9IHJlcVsnaGVhZGVycyddID8gKHJlcVsnaGVhZGVycyddWyd1c2VyLWFnZW50J10gPyByZXFbJ2hlYWRlcnMnXVsndXNlci1hZ2VudCddIDogJycpIDogJydcblxuICAgICAgICAvLyDlj5bliLDlrqLmiLfnq6/nmoRJUOWcsOWdgOS/oeaBr1xuICAgICAgICBnbG9iYWxbJ19fY2xpZW50X2lwX18nXSA9IHJlcS5oZWFkZXJzWyd4LWZvcndhcmRlZC1mb3InXSB8fCByZXEuY29ubmVjdGlvbi5yZW1vdGVBZGRyZXNzXG5cbiAgICAgICAgLy8g6K+35rGC5aSE55CGXG4gICAgICAgIGxldCBvdXQgPSBhd2FpdCByZXF1ZXN0X3Byb2Nlc3MoX19hcGlfXywgcGFyYW0pXG5cbiAgICAgICAgLy8g5aSE55CGcmVzcG9uc2XnmoRjb29raWVz6K6+572uXG4gICAgICAgIGlmICghXy5pc0VtcHR5KGdsb2JhbFsnX19yZXNwb25kX2Nvb2tpZXNfXyddKSkge1xuICAgICAgICAgICAgcmVzLnNldEhlYWRlcignU2V0LUNvb2tpZScsIF8udmFsdWVzKGdsb2JhbFsnX19yZXNwb25kX2Nvb2tpZXNfXyddKSlcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChnbG9iYWxbJ19fcmVkaXJlY3RfdXJsX18nXSkge1xuICAgICAgICAgICAgcmVzLnJlZGlyZWN0KDMwMiwgZ2xvYmFsWydfX3JlZGlyZWN0X3VybF9fJ10pXG4gICAgICAgICAgICBnbG9iYWxbJ19fcmVkaXJlY3RfdXJsX18nXSA9IHVuZGVmaW5lZFxuICAgICAgICAgICAgcmV0dXJuXG4gICAgICAgIH1cbiAgICAgICAgcmVzLnNlbmQob3V0KVxuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAvLyDpgJrnn6XmoYbmnrboh6rouqvlrp7njrDpgLvovpHnmoTmhI/lpJbmiqXplJnvvIjmoYbmnrboh6rouqvkuI3orrrkvZXnp43mg4XlhrXpg73lupTor6XmraPluLjlt6XkvZzvvIzkuIDml6blh7rnjrDmraTpl67popjlpKflpJrmlbDmg4XlhrXmmK/moYbmnrboh6rouqvpl67popjmiJbogIXmtYHph4/lvJXlj5HnmoTov5Dnu7Tpl67popjvvIlcbiAgICAgICAgYXdhaXQgeHdhcm4oe1xuICAgICAgICAgICAgX19hcGlfXywgX191cmxfXywgcGFyYW0sIG1lc3NhZ2U6IGVyci5tZXNzYWdlLCBzdGFjazogeHN0YWNrKGVycilcbiAgICAgICAgfSlcbiAgICAgICAgLy8gNTAwXHRJbnRlcm5hbCBTZXJ2ZXIgRXJyb3JcdOacjeWKoeWZqOWGhemDqOmUmeivr++8jOaXoOazleWujOaIkOivt+axglxuICAgICAgICByZXMuc2VuZFN0YXR1cyg1MDApXG4gICAgfVxufVxuIl19