1 | ;
|
2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
3 | return new (P || (P = Promise))(function (resolve, reject) {
|
4 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
5 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
6 | function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
|
7 | step((generator = generator.apply(thisArg, _arguments || [])).next());
|
8 | });
|
9 | };
|
10 | var __generator = (this && this.__generator) || function (thisArg, body) {
|
11 | var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
12 | return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
13 | function verb(n) { return function (v) { return step([n, v]); }; }
|
14 | function step(op) {
|
15 | if (f) throw new TypeError("Generator is already executing.");
|
16 | while (_) try {
|
17 | 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;
|
18 | if (y = 0, t) op = [op[0] & 2, t.value];
|
19 | switch (op[0]) {
|
20 | case 0: case 1: t = op; break;
|
21 | case 4: _.label++; return { value: op[1], done: false };
|
22 | case 5: _.label++; y = op[1]; op = [0]; continue;
|
23 | case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
24 | default:
|
25 | if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
26 | if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
27 | if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
28 | if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
29 | if (t[2]) _.ops.pop();
|
30 | _.trys.pop(); continue;
|
31 | }
|
32 | op = body.call(thisArg, _);
|
33 | } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
34 | if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
35 | }
|
36 | };
|
37 | Object.defineProperty(exports, "__esModule", { value: true });
|
38 | // 根据架构设计约定自动识别各种运行环境
|
39 | if (process.env['NODE_ENV']) {
|
40 | global['__env__'] = process.env['NODE_ENV'];
|
41 | }
|
42 | else {
|
43 | if (process.argv.length >= 3 && process.argv[2] == 'https') {
|
44 | // 预发环境配置
|
45 | global['__env__'] = 'pre';
|
46 | }
|
47 | else if (process.argv.length >= 3 && process.argv[2] == 'http') {
|
48 | // 日常环境配置
|
49 | global['__env__'] = 'daily';
|
50 | }
|
51 | else {
|
52 | // 本地环境配置
|
53 | global['__env__'] = 'local';
|
54 | }
|
55 | }
|
56 | if (global['__env__'] != 'local') {
|
57 | require('source-map-support').install();
|
58 | }
|
59 | require('tsconfig-paths').register();
|
60 | var express = require('express');
|
61 | var app = express();
|
62 | var _ = require('lodash');
|
63 | var path = require('path');
|
64 | var http = require('http');
|
65 | var https = require('https');
|
66 | var fs = require('fs');
|
67 | var init_1 = require("./init");
|
68 | // 端口号启动参数配置
|
69 | var PORT = parseInt(process.argv[2]);
|
70 | if (!PORT) {
|
71 | PORT = 8888;
|
72 | }
|
73 | // 设置静态资源路径(必须要使用绝对路径)
|
74 | app.use(express.static(path.join(init_1.get_root_path_prefix(), './static')));
|
75 | // 引入json解析中间件
|
76 | var bodyParser = require('body-parser');
|
77 | app.use(function (req, res, next) {
|
78 | var rawBody = [];
|
79 | var size = 0;
|
80 | req.on('data', function (data) {
|
81 | rawBody.push(data);
|
82 | size += data.length;
|
83 | });
|
84 | req.on('end', function () {
|
85 | // 获取原始的content-type对应的body内容自行解析处理,解决本地环境和线上环境不兼容问题。
|
86 | req.rawBody = Buffer.concat(rawBody, size).toString();
|
87 | });
|
88 | next();
|
89 | });
|
90 | // 添加json解析
|
91 | app.use(bodyParser.json());
|
92 | app.use(bodyParser.urlencoded({ extended: false }));
|
93 | // 允许所有的请求形式
|
94 | app.use(function (req, res, next) {
|
95 | if (req.headers.origin) {
|
96 | // 获取源站动态允许请求跨域 (FIXME 需要进行安全限制对来源服务器网址合法性进行安全限制,本地开发调试全部放开请求)
|
97 | res.header("Access-Control-Allow-Origin", req.headers.origin);
|
98 | }
|
99 | // res.header("Access-Control-Allow-Origin", "*")
|
100 | res.header("Access-Control-Allow-Credentials", "true");
|
101 | res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
|
102 | res.header('Access-Control-Allow-Methods', 'POST, OPTIONS');
|
103 | next();
|
104 | });
|
105 | // 本地调试使用路由重定向映射功能模拟
|
106 | var routes = require(path.join(init_1.get_root_path_prefix(), './app/entries/route.map')).default;
|
107 | var _loop_1 = function (k) {
|
108 | app.all(k, function (req, res) {
|
109 | return __awaiter(this, void 0, void 0, function () {
|
110 | return __generator(this, function (_a) {
|
111 | req.headers.__api__ = routes[k].path;
|
112 | callback(req, res);
|
113 | return [2 /*return*/];
|
114 | });
|
115 | });
|
116 | });
|
117 | };
|
118 | for (var k in routes) {
|
119 | _loop_1(k);
|
120 | }
|
121 | // TODO SLS日志机制云端对接、监控机制的业务对接、性能测试的对接、ACM配置机制的对接、报错机制信息的正确解析处理、
|
122 | // TODO COOKIE解析、BUC登录验证、 会议室信息的JAVA接口联调、梅丽莎多语言对接、ACM的配置发布
|
123 | // TODO 错误页处理、SESSION模拟基于TableStore的实现、REST的实现、更多PAAS中间件根据业务需要对接集成进来、实际业务问题更多的优化扩展。。。
|
124 | // 匹配不包含.的所有路由进行处理,否则表示文件静态资源需要单独处理。(API网关不返回任何静态资源,静态资源需要全部上传到CDN上,API网关只处理一个网站图标请求)
|
125 | app.all(/^((?!\.).)*$/, callback);
|
126 | // TODO 通过请求的域名和入口文件的位置,自动区分:本地、日常、预发、线上,四种环境。(灰度通过线上版本位置自动区分)
|
127 | // 加载配置文件信息。。。比较特殊需要在每次请求的时候单独处理。
|
128 | // 日常与预发在一台机器上需要分别启动两个独立nodejs进程进行处理,确保二者内部运行太壮数据的隔离性。
|
129 | // nodejs服务支持证书配置问题,使用正式的域名证书进行绑定配置,测试的时候本地配置域名链接确保正常。
|
130 | if (process.argv[2] == 'https') {
|
131 | // 预发绑定HTTPS服务(对应AONE的日常机器)
|
132 | var privateKey = fs.readFileSync(path.join(init_1.get_root_path_prefix(), './secrete/private.pem'), 'utf8');
|
133 | var certificate = fs.readFileSync(path.join(init_1.get_root_path_prefix(), './secrete/public.crt'), 'utf8');
|
134 | var credentials = { key: privateKey, cert: certificate };
|
135 | var httpsServer = https.createServer(credentials, app);
|
136 | httpsServer.listen(443, function () {
|
137 | console.log('fc pre-release-test app listening on port 443!');
|
138 | });
|
139 | }
|
140 | else if (process.argv[2] == 'http') {
|
141 | // 日常绑定HTTP服务(对应AONE的日常机器,一台机器同时配置HTTP日常和HTTPS预发)
|
142 | var httpServer = http.createServer(app);
|
143 | httpServer.listen(80, function () {
|
144 | console.log('fc test app listening on port 80!');
|
145 | });
|
146 | }
|
147 | else {
|
148 | // 本地开发环境HTTP协议绑定指定的端口号
|
149 | var httpServer = http.createServer(app);
|
150 | httpServer.listen(PORT, function () {
|
151 | console.log("fc test app listening on port " + PORT + ", visit http://127.0.0.1:" + PORT);
|
152 | });
|
153 | }
|
154 | function callback(req, res) {
|
155 | return __awaiter(this, void 0, void 0, function () {
|
156 | var param, __api__, __url__, __header__, out, err_1;
|
157 | return __generator(this, function (_a) {
|
158 | switch (_a.label) {
|
159 | case 0:
|
160 | param = req.query || {};
|
161 | __api__ = req.headers.__api__ ? req.headers.__api__ : req.path;
|
162 | __url__ = req.protocol + '://' + req.get('host') + req.originalUrl;
|
163 | _a.label = 1;
|
164 | case 1:
|
165 | _a.trys.push([1, 3, , 5]);
|
166 | // 请求参数的自动格式化处理兼容get和post协议方便开发调试
|
167 | switch (req.method) {
|
168 | case 'GET':
|
169 | break;
|
170 | case 'POST':
|
171 | param = xassign(param, init_1.parse_post_param(req.headers, req.rawBody));
|
172 | break;
|
173 | case 'OPTIONS':
|
174 | // 仅仅支持本地开发跨域调试,线上需要禁止此方法的调用应该同域请求处理。
|
175 | res.sendStatus(200);
|
176 | return [2 /*return*/];
|
177 | default:
|
178 | // 400 Bad Request 客户端请求的语法错误,服务器无法理解
|
179 | res.sendStatus(400);
|
180 | return [2 /*return*/];
|
181 | }
|
182 | __header__ = req.headers;
|
183 | param = xassign(param, { __api__: __api__, __url__: __url__, __header__: __header__ });
|
184 | // 解析请求中的cookies数据并转换为JSON对象存储到全局变量中便于后续应用xcookie接口使用
|
185 | global['__request_cookies__'] = require('cookie').parse(_.get(req.headers, 'cookie', ''));
|
186 | // 获取use-agent请求头部信息
|
187 | global['__user_agent__'] = req['headers'] ? (req['headers']['user-agent'] ? req['headers']['user-agent'] : '') : '';
|
188 | // 取到客户端的IP地址信息
|
189 | global['__client_ip__'] = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
|
190 | return [4 /*yield*/, init_1.request_process(__api__, param)
|
191 | // 处理response的cookies设置
|
192 | ];
|
193 | case 2:
|
194 | out = _a.sent();
|
195 | // 处理response的cookies设置
|
196 | if (!_.isEmpty(global['__respond_cookies__'])) {
|
197 | res.setHeader('Set-Cookie', _.values(global['__respond_cookies__']));
|
198 | }
|
199 | if (global['__redirect_url__']) {
|
200 | res.redirect(302, global['__redirect_url__']);
|
201 | global['__redirect_url__'] = undefined;
|
202 | return [2 /*return*/];
|
203 | }
|
204 | res.send(out);
|
205 | return [3 /*break*/, 5];
|
206 | case 3:
|
207 | err_1 = _a.sent();
|
208 | // 通知框架自身实现逻辑的意外报错(框架自身不论何种情况都应该正常工作,一旦出现此问题大多数情况是框架自身问题或者流量引发的运维问题)
|
209 | return [4 /*yield*/, xwarn({
|
210 | __api__: __api__, __url__: __url__, param: param, message: err_1.message, stack: xstack(err_1)
|
211 | })
|
212 | // 500 Internal Server Error 服务器内部错误,无法完成请求
|
213 | ];
|
214 | case 4:
|
215 | // 通知框架自身实现逻辑的意外报错(框架自身不论何种情况都应该正常工作,一旦出现此问题大多数情况是框架自身问题或者流量引发的运维问题)
|
216 | _a.sent();
|
217 | // 500 Internal Server Error 服务器内部错误,无法完成请求
|
218 | res.sendStatus(500);
|
219 | return [3 /*break*/, 5];
|
220 | case 5: return [2 /*return*/];
|
221 | }
|
222 | });
|
223 | });
|
224 | }
|
225 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInRlc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLHFCQUFxQjtBQUNyQixJQUFJLE9BQU8sQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLEVBQUU7SUFDekIsTUFBTSxDQUFDLFNBQVMsQ0FBQyxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLENBQUE7Q0FDOUM7S0FBTTtJQUNILElBQUksT0FBTyxDQUFDLElBQUksQ0FBQyxNQUFNLElBQUksQ0FBQyxJQUFJLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUksT0FBTyxFQUFFO1FBQ3hELFNBQVM7UUFDVCxNQUFNLENBQUMsU0FBUyxDQUFDLEdBQUcsS0FBSyxDQUFBO0tBQzVCO1NBQU0sSUFBSSxPQUFPLENBQUMsSUFBSSxDQUFDLE1BQU0sSUFBSSxDQUFDLElBQUksT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsSUFBSSxNQUFNLEVBQUU7UUFDOUQsU0FBUztRQUNULE1BQU0sQ0FBQyxTQUFTLENBQUMsR0FBRyxPQUFPLENBQUE7S0FDOUI7U0FDSTtRQUNELFNBQVM7UUFDVCxNQUFNLENBQUMsU0FBUyxDQUFDLEdBQUcsT0FBTyxDQUFBO0tBQzlCO0NBQ0o7QUFDRCxJQUFJLE1BQU0sQ0FBQyxTQUFTLENBQUMsSUFBSSxPQUFPLEVBQUU7SUFDOUIsT0FBTyxDQUFDLG9CQUFvQixDQUFDLENBQUMsT0FBTyxFQUFFLENBQUE7Q0FDMUM7QUFDRCxPQUFPLENBQUMsZ0JBQWdCLENBQUMsQ0FBQyxRQUFRLEVBQUUsQ0FBQTtBQUNwQyxJQUFNLE9BQU8sR0FBRyxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUE7QUFDbEMsSUFBTSxHQUFHLEdBQUcsT0FBTyxFQUFFLENBQUE7QUFDckIsSUFBTSxDQUFDLEdBQUcsT0FBTyxDQUFDLFFBQVEsQ0FB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WUFBWSxFQUFFLENBQUMsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLHFCQUFxQixDQUFDLENBQUMsQ0FBQyxDQUFBO3FCQUN2RTtvQkFFRCxJQUFJLE1BQU0sQ0FBQyxrQkFBa0IsQ0FBQyxFQUFFO3dCQUM1QixHQUFHLENBQUMsUUFBUSxDQUFDLEdBQUcsRUFBRSxNQUFNLENBQUMsa0JBQWtCLENBQUMsQ0FBQyxDQUFBO3dCQUM3QyxNQUFNLENBQUMsa0JBQWtCLENBQUMsR0FBRyxTQUFTLENBQUE7d0JBQ3RDLHNCQUFNO3FCQUNUO29CQUNELEdBQUcsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUE7Ozs7b0JBRWIsb0VBQW9FO29CQUNwRSxxQkFBTSxLQUFLLENBQUM7NEJBQ1IsT0FBTyxTQUFBLEVBQUUsT0FBTyxTQUFBLEVBQUUsS0FBSyxPQUFBLEVBQUUsT0FBTyxFQUFFLEtBQUcsQ0FBQyxPQUFPLEVBQUUsS0FBSyxFQUFFLE1BQU0sQ0FBQyxLQUFHLENBQUM7eUJBQ3BFLENBQUM7d0JBQ0YsMkNBQTJDO3NCQUR6Qzs7b0JBSEYsb0VBQW9FO29CQUNwRSxTQUVFLENBQUE7b0JBQ0YsMkNBQTJDO29CQUMzQyxHQUFHLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQyxDQUFBOzs7Ozs7Q0FFMUIiLCJzb3VyY2VzQ29udGVudCI6WyIvLyDmoLnmja7mnrbmnoTorr7orqHnuqblrproh6rliqjor4bliKvlkITnp43ov5DooYznjq/looNcbmlmIChwcm9jZXNzLmVudlsnTk9ERV9FTlYnXSkge1xuICAgIGdsb2JhbFsnX19lbnZfXyddID0gcHJvY2Vzcy5lbnZbJ05PREVfRU5WJ11cbn0gZWxzZSB7XG4gICAgaWYgKHByb2Nlc3MuYXJndi5sZW5ndGggPj0gMyAmJiBwcm9jZXNzLmFyZ3ZbMl0gPT0gJ2h0dHBzJykge1xuICAgICAgICAvLyDpooTlj5Hnjq/looPphY3nva5cbiAgICAgICAgZ2xvYmFsWydfX2Vudl9fJ10gPSAncHJlJ1xuICAgIH0gZWxzZSBpZiAocHJvY2Vzcy5hcmd2Lmxlbmd0aCA+PSAzICYmIHByb2Nlc3MuYXJndlsyXSA9PSAnaHR0cCcpIHtcbiAgICAgICAgLy8g5pel5bi4546v5aKD6YWN572uXG4gICAgICAgIGdsb2JhbFsnX19lbnZfXyddID0gJ2RhaWx5J1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgLy8g5pys5Zyw546v5aKD6YWN572uXG4gICAgICAgIGdsb2JhbFsnX19lbnZfXyddID0gJ2xvY2FsJ1xuICAgIH1cbn1cbmlmIChnbG9iYWxbJ19fZW52X18nXSAhPSAnbG9jYWwnKSB7XG4gICAgcmVxdWlyZSgnc291cmNlLW1hcC1zdXBwb3J0JykuaW5zdGFsbCgpXG59XG5yZXF1aXJlKCd0c2NvbmZpZy1wYXRocycpLnJlZ2lzdGVyKClcbmNvbnN0IGV4cHJlc3MgPSByZXF1aXJlKCdleHByZXNzJylcbmNvbnN0IGFwcCA9IGV4cHJlc3MoKVxuY29uc3QgXyA9IHJlcXVpcmUoJ2xvZGFzaCcpXG5jb25zdCBwYXRoID0gcmVxdWlyZSgncGF0aCcpXG5jb25zdCBodHRwID0gcmVxdWlyZSgnaHR0cCcpXG5jb25zdCBodHRwcyA9IHJlcXVpcmUoJ2h0dHBzJylcbmNvbnN0IGZzID0gcmVxdWlyZSgnZnMnKVxuaW1wb3J0IHtnZXRfcm9vdF9wYXRoX3ByZWZpeCwgcmVxdWVzdF9wcm9jZXNzLCBwYXJzZV9wb3N0X3BhcmFtfSBmcm9tICcuL2luaXQnXG5cbi8vIOerr+WPo+WPt+WQr+WKqOWPguaVsOmFjee9rlxubGV0IFBPUlQ6IGFueSA9IHBhcnNlSW50KHByb2Nlc3MuYXJndlsyXSlcbmlmICghUE9SVCkge1xuICAgIFBPUlQgPSA4ODg4XG59XG5cbi8vIOiuvue9rumdmeaAgei1hOa6kOi3r+W+hO+8iOW/hemhu+imgeS9v+eUqOe7neWvuei3r+W+hO+8iVxuYXBwLnVzZShleHByZXNzLnN0YXRpYyhwYXRoLmpvaW4oZ2V0X3Jvb3RfcGF0aF9wcmVmaXgoKSwgJy4vc3RhdGljJykpKVxuXG4vLyDlvJXlhaVqc29u6Kej5p6Q5Lit6Ze05Lu2XG5jb25zdCBib2R5UGFyc2VyID0gcmVxdWlyZSgnYm9keS1wYXJzZXInKVxuYXBwLnVzZShmdW5jdGlvbiAocmVxLCByZXMsIG5leHQpIHtcbiAgICB2YXIgcmF3Qm9keSA9IFtdXG4gICAgdmFyIHNpemUgPSAwXG4gICAgcmVxLm9uKCdkYXRhJywgZnVuY3Rpb24gKGRhdGEpIHtcbiAgICAgICAgcmF3Qm9keS5wdXNoKGRhdGEpXG4gICAgICAgIHNpemUgKz0gZGF0YS5sZW5ndGhcbiAgICB9KVxuICAgIHJlcS5vbignZW5kJywgZnVuY3Rpb24gKCkge1xuICAgICAgICAvLyDojrflj5bljp/lp4vnmoRjb250ZW50LXR5cGXlr7nlupTnmoRib2R55YaF5a656Ieq6KGM6Kej5p6Q5aSE55CG77yM6Kej5Yaz5pys5Zyw546v5aKD5ZKM57q/5LiK546v5aKD5LiN5YW85a656Zeu6aKY44CCXG4gICAgICAgIHJlcS5yYXdCb2R5ID0gQnVmZmVyLmNvbmNhdChyYXdCb2R5LCBzaXplKS50b1N0cmluZygpXG4gICAgfSlcbiAgICBuZXh0KClcbn0pXG4vLyDmt7vliqBqc29u6Kej5p6QXG5hcHAudXNlKGJvZHlQYXJzZXIuanNvbigpKVxuYXBwLnVzZShib2R5UGFyc2VyLnVybGVuY29kZWQoe2V4dGVuZGVkOiBmYWxzZX0pKVxuLy8g5YWB6K645omA5pyJ55qE6K+35rGC5b2i5byPXG5hcHAudXNlKGZ1bmN0aW9uIChyZXEsIHJlcywgbmV4dCkge1xuICAgIGlmIChyZXEuaGVhZGVycy5vcmlnaW4pIHtcbiAgICAgICAgLy8g6I635Y+W5rqQ56uZ5Yqo5oCB5YWB6K646K+35rGC6Leo5Z+fIChGSVhNRSDpnIDopoHov5vooYzlronlhajpmZDliLblr7nmnaXmupDmnI3liqHlmajnvZHlnYDlkIjms5XmgKfov5vooYzlronlhajpmZDliLbvvIzmnKzlnLDlvIDlj5HosIPor5Xlhajpg6jmlL7lvIDor7fmsYIpXG4gICAgICAgIHJlcy5oZWFkZXIoXCJBY2Nlc3MtQ29udHJvbC1BbGxvdy1PcmlnaW5cIiwgcmVxLmhlYWRlcnMub3JpZ2luKTtcbiAgICB9XG4gICAgLy8gcmVzLmhlYWRlcihcIkFjY2Vzcy1Db250cm9sLUFsbG93LU9yaWdpblwiLCBcIipcIilcbiAgICByZXMuaGVhZGVyKFwiQWNjZXNzLUNvbnRyb2wtQWxsb3ctQ3JlZGVudGlhbHNcIiwgXCJ0cnVlXCIpXG4gICAgcmVzLmhlYWRlcihcIkFjY2Vzcy1Db250cm9sLUFsbG93LUhlYWRlcnNcIiwgXCJPcmlnaW4sIFgtUmVxdWVzdGVkLVdpdGgsIENvbnRlbnQtVHlwZSwgQWNjZXB0XCIpXG4gICAgcmVzLmhlYWRlcignQWNjZXNzLUNvbnRyb2wtQWxsb3ctTWV0aG9kcycsICdQT1NULCBPUFRJT05TJylcbiAgICBuZXh0KClcbn0pXG5cbi8vIOacrOWcsOiwg+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+8iOWvueW6lEFPTkXnmoTml6XluLjmnLrlmajvvIlcbiAgICBjb25zdCBwcml2YXRlS2V5ID0gZnMucmVhZEZpbGVTeW5jKFxuICAgICAgICBwYXRoLmpvaW4oZ2V0X3Jvb3RfcGF0aF9wcmVmaXgoKSwgJy4vc2VjcmV0ZS9wcml2YXRlLnBlbScpLCAndXRmOCcpXG4gICAgY29uc3QgY2VydGlmaWNhdGUgPSBmcy5yZWFkRmlsZVN5bmMoXG4gICAgICAgIHBhdGguam9pbihnZXRfcm9vdF9wYXRoX3ByZWZpeCgpLCAnLi9zZWNyZXRlL3B1YmxpYy5jcnQnKSwgJ3V0ZjgnKVxuICAgIGNvbnN0IGNyZWRlbnRpYWxzID0ge2tleTogcHJpdmF0ZUtleSwgY2VydDogY2VydGlmaWNhdGV9XG4gICAgY29uc3QgaHR0cHNTZXJ2ZXIgPSBodHRwcy5jcmVhdGVTZXJ2ZXIoY3JlZGVudGlhbHMsIGFwcClcbiAgICBodHRwc1NlcnZlci5saXN0ZW4oNDQzLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKCdmYyBwcmUtcmVsZWFzZS10ZXN0IGFwcCBsaXN0ZW5pbmcgb24gcG9ydCA0NDMhJylcbiAgICB9KVxufSBlbHNlIGlmIChwcm9jZXNzLmFyZ3ZbMl0gPT0gJ2h0dHAnKSB7XG4gICAgLy8g5pel5bi457uR5a6aSFRUUOacjeWKoe+8iOWvueW6lEFPTkXnmoTml6XluLjmnLrlmajvvIzkuIDlj7DmnLrlmajlkIzml7bphY3nva5IVFRQ5pel5bi45ZKMSFRUUFPpooTlj5HvvIlcbiAgICBjb25zdCBodHRwU2VydmVyID0gaHR0cC5jcmVhdGVTZXJ2ZXIoYXBwKVxuICAgIGh0dHBTZXJ2ZXIubGlzdGVuKDgwLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKCdmYyB0ZXN0IGFwcCBsaXN0ZW5pbmcgb24gcG9ydCA4MCEnKVxuICAgIH0pXG59IGVsc2Uge1xuICAgIC8vIOacrOWcsOW8gOWPkeeOr+Wig0hUVFDljY/orq7nu5HlrprmjIflrprnmoTnq6/lj6Plj7dcbiAgICBjb25zdCBodHRwU2VydmVyID0gaHR0cC5jcmVhdGVTZXJ2ZXIoYXBwKVxuICAgIGh0dHBTZXJ2ZXIubGlzdGVuKFBPUlQsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgY29uc29sZS5sb2coYGZjIHRlc3QgYXBwIGxpc3RlbmluZyBvbiBwb3J0ICR7UE9SVH0sIHZpc2l0IGh0dHA6Ly8xMjcuMC4wLjE6JHtQT1JUfWApXG4gICAgfSlcbn1cblxuYXN5bmMgZnVuY3Rpb24gY2FsbGJhY2socmVxLCByZXMpIHtcbiAgICBsZXQgcGFyYW0gPSByZXEucXVlcnkgfHwge31cbiAgICAvLyDooaXkuIrmoYbmnrbpooTlrprkuYnnmoTnvLrnnIHlj4LmlbBfX3VybF9fKOWFtuS7luabtOWkmuahhuaetuWPguaVsF9fYXBpX18gX19kZWJ1Z19fIF9fbW9ja19fIFRPRE8gX19wYXJhbV9fIOWcqGdldOS4rWpzb27lrZfnrKbkuLLnmoRiYXNlNjTmoLzlvI8pXG4gICAgbGV0IF9fYXBpX18gPSByZXEuaGVhZGVycy5fX2FwaV9fID8gcmVxLmhlYWRlcnMuX19hcGlfXyA6IHJlcS5wYXRoXG4gICAgbGV0IF9fdXJsX18gPSByZXEucHJvdG9jb2wgKyAnOi8vJyArIHJlcS5nZXQoJ2hvc3QnKSArIHJlcS5vcmlnaW5hbFVybFxuXG4gICAgdHJ5IHtcbiAgICAgICAgLy8g6K+35rGC5Y+C5pWw55qE6Ieq5Yqo5qC85byP5YyW5aSE55CG5YW85a65Z2V05ZKMcG9zdOWNj+iuruaWueS+v+W8gOWPkeiwg+ivlVxuICAgICAgICBzd2l0Y2ggKHJlcS5tZXRob2QpIHtcbiAgICAgICAgICAgIGNhc2UgJ0dFVCc6XG4gICAgICAgICAgICAgICAgYnJlYWtcbiAgICAgICAgICAgIGNhc2UgJ1BPU1QnOlxuICAgICAgICAgICAgICAgIHBhcmFtID0geGFzc2lnbihwYXJhbSwgcGFyc2VfcG9zdF9wYXJhbShyZXEuaGVhZGVycywgcmVxLnJhd0JvZHkpKVxuICAgICAgICAgICAgICAgIGJyZWFrXG4gICAgICAgICAgICBjYXNlICdPUFRJT05TJzpcbiAgICAgICAgICAgICAgICAvLyDku4Xku4XmlK/mjIHmnKzlnLDlvIDlj5Hot6jln5/osIPor5XvvIznur/kuIrpnIDopoHnpoHmraLmraTmlrnms5XnmoTosIPnlKjlupTor6XlkIzln5/or7fmsYLlpITnkIbjgIJcbiAgICAgICAgICAgICAgICByZXMuc2VuZFN0YXR1cygyMDApXG4gICAgICAgICAgICAgICAgcmV0dXJuXG4gICAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgICAgIC8vIDQwMCAgQmFkIFJlcXVlc3RcdOWuouaIt+err+ivt+axgueahOivreazlemUmeivr++8jOacjeWKoeWZqOaXoOazleeQhuino1xuICAgICAgICAgICAgICAgIHJlcy5zZW5kU3RhdHVzKDQwMClcbiAgICAgICAgICAgICAgICByZXR1cm5cbiAgICAgICAgfVxuICAgICAgICAvLyDooaXkuIror7fmsYLnmoRIRUFERVLlj4LmlbDliLDlupTnlKjkuK3ov5vooYzoh6rooYzlpITnkIbkuJrliqHpgLvovpHlrprliLbnmoTor7fmsYLlpLTpg6jkv6Hmga9cbiAgICAgICAgbGV0IF9faGVhZGVyX18gPSByZXEuaGVhZGVyc1xuICAgICAgICBwYXJhbSA9IHhhc3NpZ24ocGFyYW0sIHtfX2FwaV9fLCBfX3VybF9fLCBfX2hlYWRlcl9ffSlcblxuICAgICAgICAvLyDop6PmnpDor7fmsYLkuK3nmoRjb29raWVz5pWw5o2u5bm26L2s5o2i5Li6SlNPTuWvueixoeWtmOWCqOWIsOWFqOWxgOWPmOmHj+S4reS+v+S6juWQjue7reW6lOeUqHhjb29raWXmjqXlj6Pkvb/nlKhcbiAgICAgICAgZ2xvYmFsWydfX3JlcXVlc3RfY29va2llc19fJ10gPSByZXF1aXJlKCdjb29raWUnKS5wYXJzZShfLmdldChyZXEuaGVhZGVycywgJ2Nvb2tpZScsICcnKSlcblxuICAgICAgICAvLyDojrflj5Z1c2UtYWdlbnTor7fmsYLlpLTpg6jkv6Hmga9cbiAgICAgICAgZ2xvYmFsWydfX3VzZXJfYWdlbnRfXyddID0gcmVxWydoZWFkZXJzJ10gPyAocmVxWydoZWFkZXJzJ11bJ3VzZXItYWdlbnQnXSA/IHJlcVsnaGVhZGVycyddWyd1c2VyLWFnZW50J10gOiAnJykgOiAnJ1xuXG4gICAgICAgIC8vIOWPluWIsOWuouaIt+err+eahElQ5Zyw5Z2A5L+h5oGvXG4gICAgICAgIGdsb2JhbFsnX19jbGllbnRfaXBfXyddID0gcmVxLmhlYWRlcnNbJ3gtZm9yd2FyZGVkLWZvciddIHx8IHJlcS5jb25uZWN0aW9uLnJlbW90ZUFkZHJlc3NcblxuICAgICAgICAvLyDor7fmsYLlpITnkIZcbiAgICAgICAgbGV0IG91dCA9IGF3YWl0IHJlcXVlc3RfcHJvY2VzcyhfX2FwaV9fLCBwYXJhbSlcblxuICAgICAgICAvLyDlpITnkIZyZXNwb25zZeeahGNvb2tpZXPorr7nva5cbiAgICAgICAgaWYgKCFfLmlzRW1wdHkoZ2xvYmFsWydfX3Jlc3BvbmRfY29va2llc19fJ10pKSB7XG4gICAgICAgICAgICByZXMuc2V0SGVhZGVyKCdTZXQtQ29va2llJywgXy52YWx1ZXMoZ2xvYmFsWydfX3Jlc3BvbmRfY29va2llc19fJ10pKVxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGdsb2JhbFsnX19yZWRpcmVjdF91cmxfXyddKSB7XG4gICAgICAgICAgICByZXMucmVkaXJlY3QoMzAyLCBnbG9iYWxbJ19fcmVkaXJlY3RfdXJsX18nXSlcbiAgICAgICAgICAgIGdsb2JhbFsnX19yZWRpcmVjdF91cmxfXyddID0gdW5kZWZpbmVkXG4gICAgICAgICAgICByZXR1cm5cbiAgICAgICAgfVxuICAgICAgICByZXMuc2VuZChvdXQpXG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgIC8vIOmAmuefpeahhuaetuiHqui6q+WunueOsOmAu+i+keeahOaEj+WkluaKpemUme+8iOahhuaetuiHqui6q+S4jeiuuuS9leenjeaDheWGtemDveW6lOivpeato+W4uOW3peS9nO+8jOS4gOaXpuWHuueOsOatpOmXrumimOWkp+WkmuaVsOaDheWGteaYr+ahhuaetuiHqui6q+mXrumimOaIluiAhea1gemHj+W8leWPkeeahOi/kOe7tOmXrumimO+8iVxuICAgICAgICBhd2FpdCB4d2Fybih7XG4gICAgICAgICAgICBfX2FwaV9fLCBfX3VybF9fLCBwYXJhbSwgbWVzc2FnZTogZXJyLm1lc3NhZ2UsIHN0YWNrOiB4c3RhY2soZXJyKVxuICAgICAgICB9KVxuICAgICAgICAvLyA1MDBcdEludGVybmFsIFNlcnZlciBFcnJvclx05pyN5Yqh5Zmo5YaF6YOo6ZSZ6K+v77yM5peg5rOV5a6M5oiQ6K+35rGCXG4gICAgICAgIHJlcy5zZW5kU3RhdHVzKDUwMClcbiAgICB9XG59Il19 |
\ | No newline at end of file |