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 | /// <reference path="../error.d.ts" />
|
39 | function get_root_path_prefix() {
|
40 | return path.join(__dirname, '../../../../');
|
41 | }
|
42 | exports.get_root_path_prefix = get_root_path_prefix;
|
43 | // 先加载框架层面的错误定义,再加载用户层面的错误定义,支持用户定义错误覆盖框架层面的错误多语言消息定义。
|
44 | require('../error');
|
45 | var path = require('path');
|
46 | require(path.join(get_root_path_prefix(), './app/error')); // 初始化应用扩展的错误
|
47 | var base_1 = require("./base");
|
48 | var session_1 = require("./session");
|
49 | require(path.join(get_root_path_prefix(), './app/global.out') + '.' + base_1.get_suffix_ts_or_js()); // 初始化应用一些枚举常量定义等方法
|
50 | // 初始化IoC容器
|
51 | require(path.join(get_root_path_prefix(), './app/plugins/container'));
|
52 | var fs = require('fs');
|
53 | var view = require('nunjucks');
|
54 | var _ = require('lodash');
|
55 | var typeis = require('type-is');
|
56 | var querystring = require('querystring');
|
57 | function get_app_entries_path_prefix() {
|
58 | return path.join(get_root_path_prefix(), './app/entries');
|
59 | }
|
60 | // https://github.com/eqfox/http-body-parser 参照koa的源码正确解析post请求参数
|
61 | // 兼容application/json和application/x-www-form-urlencoded两种请求类型。
|
62 | function parse_post_param(headers, body) {
|
63 | try {
|
64 | if (!body) {
|
65 | return {};
|
66 | }
|
67 | if (typeis({ headers: headers }, ['json'])) {
|
68 | return JSON.parse(body.toString(headers['content-encoding'] || 'utf8'));
|
69 | }
|
70 | else if (typeof headers['Content-Type'] == 'string' && headers['Content-Type'].match(/application\/json/)) {
|
71 | // bugfix API网关的字段类型值的赋值差异与type-is库的字段名称不兼容问题(content-type与Content-Type区别)
|
72 | return JSON.parse(body.toString(headers['content-encoding'] || 'utf8'));
|
73 | }
|
74 | else if (typeis({ headers: headers }, ['urlencoded'])) {
|
75 | return querystring.parse(body.toString(headers['content-encoding'] || 'utf8'));
|
76 | }
|
77 | else if (typeof headers['Content-Type'] == 'string' && headers['Content-Type'] == 'application/x-www-form-urlencoded') {
|
78 | // bugfix 线上乐高post请求参数解析不正确问题调试做兼容适配处理 TODO 待查原因为啥typeis库失效了
|
79 | // application/x-www-form-urlencoded
|
80 | return querystring.parse(body.toString(headers['content-encoding'] ||
|
81 | headers['Content-Encoding'] || 'utf8'));
|
82 | }
|
83 | else {
|
84 | xthrow(ERR$PARAM, { headers: headers, body: body });
|
85 | }
|
86 | }
|
87 | catch (err) {
|
88 | xthrow(err, { headers: headers, body: body });
|
89 | }
|
90 | }
|
91 | exports.parse_post_param = parse_post_param;
|
92 | // 请求前置过滤处理
|
93 | function filter_request_begin(api_path, param) {
|
94 | return __awaiter(this, void 0, void 0, function () {
|
95 | var entry, obj, api_callback, context;
|
96 | return __generator(this, function (_a) {
|
97 | switch (_a.label) {
|
98 | case 0:
|
99 | entry = require(api_path).default;
|
100 | xassert(entry);
|
101 | obj = new entry();
|
102 | if (!obj._) return [3 /*break*/, 2];
|
103 | // 强制执行请求参数验证逻辑
|
104 | xassert(_.isFunction(obj._));
|
105 | return [4 /*yield*/, obj._(param)];
|
106 | case 1:
|
107 | _a.sent();
|
108 | _a.label = 2;
|
109 | case 2:
|
110 | api_callback = obj.$$;
|
111 | if (!('__mock__' in param)) return [3 /*break*/, 3];
|
112 | api_callback = obj.$ ? obj.$ : undefined;
|
113 | return [3 /*break*/, 5];
|
114 | case 3:
|
115 | if (!obj.context) return [3 /*break*/, 5];
|
116 | xassert(_.isFunction(obj.context));
|
117 | context = obj.context();
|
118 | xassert(_.isPlainObject(context.param) && _.isFunction(context.auth));
|
119 | return [4 /*yield*/, context.auth()];
|
120 | case 4:
|
121 | _a.sent();
|
122 | _a.label = 5;
|
123 | case 5: return [2 /*return*/, api_callback];
|
124 | }
|
125 | });
|
126 | });
|
127 | }
|
128 | // web页面的请求支持get或post,get仅仅用于页面跳转,自动兼容get和post用于表单递交以及web端的接口数据的返回处理(测试场景下支持get线上环境只支持post协议)。
|
129 | function web_request_process(api, param) {
|
130 | return __awaiter(this, void 0, void 0, function () {
|
131 | var prefix, api_path, out, is_html_request, api_callback, err_1, api_callback, data;
|
132 | return __generator(this, function (_a) {
|
133 | switch (_a.label) {
|
134 | case 0:
|
135 | prefix = get_app_entries_path_prefix();
|
136 | api_path = prefix + "/web/" + api;
|
137 | out = undefined;
|
138 | is_html_request = fs.existsSync(path.resolve(__dirname, prefix + "/web/" + api + ".html"));
|
139 | _a.label = 1;
|
140 | case 1:
|
141 | _a.trys.push([1, 4, , 9]);
|
142 | return [4 /*yield*/, filter_request_begin(api_path, param)];
|
143 | case 2:
|
144 | api_callback = _a.sent();
|
145 | xassert(_.isFunction(api_callback));
|
146 | return [4 /*yield*/, api_callback(param)]; // 回调API对应的业务逻辑实现
|
147 | case 3:
|
148 | out = _a.sent(); // 回调API对应的业务逻辑实现
|
149 | if (is_html_request) {
|
150 | // 仅在web请求html页面的时候如果检测到302跳转的时候忽略模板渲染直接返回
|
151 | if (global['__redirect_url__'] !== undefined) {
|
152 | return [2 /*return*/];
|
153 | }
|
154 | // 将out转换到对应的html试图绑定之后再输出
|
155 | view.configure(path.resolve(__dirname, prefix + "/web"), { noCache: true, autoescape: false });
|
156 | out = view.render("./" + api + ".html", out);
|
157 | return [2 /*return*/, out];
|
158 | }
|
159 | else {
|
160 | // 对于web页面的关联ajax接口进行规范rest接口数据格式的统一处理
|
161 | return [2 /*return*/, {
|
162 | success: true,
|
163 | content: out,
|
164 | errorLevel: undefined,
|
165 | errorCode: undefined,
|
166 | errorMsg: undefined,
|
167 | }];
|
168 | }
|
169 | return [3 /*break*/, 9];
|
170 | case 4:
|
171 | err_1 = _a.sent();
|
172 | // 业务错误报警处理 TODO 需要考虑错误忽略问题
|
173 | return [4 /*yield*/, xwarn(err_1, api, param)];
|
174 | case 5:
|
175 | // 业务错误报警处理 TODO 需要考虑错误忽略问题
|
176 | _a.sent();
|
177 | if (!is_html_request) return [3 /*break*/, 7];
|
178 | // 只对业务逻辑错误处理区分框架错误还是业务错误(业务错误error页面显示,框架错误http错误状态码)FIXME 需要改进掉
|
179 | xassert(fs.existsSync(path.resolve(__dirname, prefix + "/web/error." + base_1.get_suffix_ts_or_js())) &&
|
180 | fs.existsSync(path.resolve(__dirname, prefix + "/web/error.html")));
|
181 | api_callback = require(prefix + "/web/error." + base_1.get_suffix_ts_or_js()).default;
|
182 | xassert(_.isFunction(api_callback));
|
183 | return [4 /*yield*/, api_callback(err_1)];
|
184 | case 6:
|
185 | out = _a.sent();
|
186 | view.configure(path.resolve(__dirname, prefix + "/web"), { noCache: true, autoescape: false });
|
187 | out = view.render("./error.html", out);
|
188 | return [2 /*return*/, out];
|
189 | case 7:
|
190 | data = xerror(err_1);
|
191 | return [2 /*return*/, {
|
192 | success: false,
|
193 | content: data.param,
|
194 | errorLevel: 'error',
|
195 | errorCode: data.code,
|
196 | errorMsg: data.msg,
|
197 | }];
|
198 | case 8: return [3 /*break*/, 9];
|
199 | case 9: return [2 /*return*/];
|
200 | }
|
201 | });
|
202 | });
|
203 | }
|
204 | // rest api接口自动兼容get或post请求处理协议(测试场景下支持get线上环境只支持post协议)
|
205 | function rest_request_process(api, param) {
|
206 | return __awaiter(this, void 0, void 0, function () {
|
207 | var prefix, api_path, api_callback, out, err_2, data;
|
208 | return __generator(this, function (_a) {
|
209 | switch (_a.label) {
|
210 | case 0:
|
211 | _a.trys.push([0, 3, , 5]);
|
212 | prefix = get_app_entries_path_prefix();
|
213 | api_path = prefix + "/rest/" + api;
|
214 | return [4 /*yield*/, filter_request_begin(api_path, param)];
|
215 | case 1:
|
216 | api_callback = _a.sent();
|
217 | xassert(_.isFunction(api_callback));
|
218 | return [4 /*yield*/, api_callback(param)]; // 回调API对应的业务逻辑实现
|
219 | case 2:
|
220 | out = _a.sent() // 回调API对应的业务逻辑实现
|
221 | ;
|
222 | return [2 /*return*/, {
|
223 | success: true,
|
224 | content: out,
|
225 | errorLevel: undefined,
|
226 | errorCode: undefined,
|
227 | errorMsg: undefined,
|
228 | }];
|
229 | case 3:
|
230 | err_2 = _a.sent();
|
231 | return [4 /*yield*/, xwarn(err_2, api, param)];
|
232 | case 4:
|
233 | _a.sent();
|
234 | data = xerror(err_2);
|
235 | return [2 /*return*/, {
|
236 | success: false,
|
237 | content: data.param,
|
238 | errorLevel: 'error',
|
239 | errorCode: data.code,
|
240 | errorMsg: data.msg,
|
241 | }];
|
242 | case 5: return [2 /*return*/];
|
243 | }
|
244 | });
|
245 | });
|
246 | }
|
247 | // 返回格式是HTML还是JSON取决于API路径对应的ts文件是否存在同名的html模板文件,如果存在则返回HTML否则全部返回JSON数据。
|
248 | // 约定规范:POST请求都是restful的API接口(根据web和rest的路径进行具体区分),GET请求对应的路径有HTML就是WEB请求否则就是JSON请求。
|
249 | // 通过约定简化路由的定义。
|
250 | function request_process(api, param) {
|
251 | return __awaiter(this, void 0, void 0, function () {
|
252 | var out;
|
253 | return __generator(this, function (_a) {
|
254 | switch (_a.label) {
|
255 | case 0: return [4 /*yield*/, session_1.__framework_session_init__()
|
256 | // 根据API的前缀命名规范自动识别应用类型是纯rest项目还是纯web项目进行对应的处理逻辑
|
257 | ];
|
258 | case 1:
|
259 | _a.sent();
|
260 | if (!/^\/web\//.test(api)) return [3 /*break*/, 3];
|
261 | return [4 /*yield*/, web_request_process(api.replace(/^\/web\//, ''), param)];
|
262 | case 2: return [2 /*return*/, _a.sent()];
|
263 | case 3:
|
264 | if (!/^\/rest\//.test(api)) return [3 /*break*/, 5];
|
265 | return [4 /*yield*/, rest_request_process(api.replace(/^\/rest\//, ''), param)];
|
266 | case 4:
|
267 | out = _a.sent();
|
268 | global['__redirect_url__'] = undefined;
|
269 | return [2 /*return*/, out];
|
270 | case 5:
|
271 | // TODO 正确优化界面提示返回HTTPS状态码错误!!!!过滤无效URL定义。
|
272 | xthrow(ERR$PARAM, [api, param]);
|
273 | _a.label = 6;
|
274 | case 6: return [2 /*return*/];
|
275 | }
|
276 | });
|
277 | });
|
278 | }
|
279 | exports.request_process = request_process;
|
280 | // ajax返回成功结构说明
|
281 | // {
|
282 | // success: true,
|
283 | // content: 返回内容,{}/[]
|
284 | // }
|
285 | // ajax返回失败结构说明
|
286 | // {
|
287 | // success: false,
|
288 | // errorLevel:['info’, 'warn’, 'error’, 'fault’],
|
289 | // errorCode:错误码,
|
290 | // errorMsg:错误信息说明
|
291 | // }
|
292 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5pdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbImluaXQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLHNDQUFzQztBQUN0QztJQUNJLE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsY0FBYyxDQUFDLENBQUE7QUFDL0MsQ0FBQztBQUZELG9EQUVDO0FBRUQsc0RBQXNEO0FBQ3RELE9BQU8sQ0FBQyxVQUFVLENBQUMsQ0FBQTtBQUNuQixJQUFNLElBQUksR0FBRyxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUE7QUFDNUIsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsb0JBQW9CLEVBQUUsRUFBRSxhQUFhLENBQUMsQ0FBQyxDQUFBLENBQUMsYUFBYTtBQUV2RSwrQkFBMEM7QUFDMUMscUNBQW9EO0FBRXBELE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLG9CQUFvQixFQUFFLEVBQUUsa0JBQWtCLENBQUMsR0FBRyxHQUFHLEdBQUcsMEJBQW1CLEVBQUUsQ0FBQyxDQUFBLENBQUMsbUJBQW1CO0FBRWhILFdBQVc7QUFDWCxPQUFPLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxvQkFBb0IsRUFBRSxFQUFFLHlCQUF5QixDQUFDLENBQUMsQ0FBQTtBQUVyRSxJQUFNLEVBQUUsR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUE7QUFDeEIsSUFBTSxJQUFJLEdBQUcsT0FBTyxDQUFDLFVBQVUsQ0FBQyxDQUFBO0FBQ2hDLElBQU0sQ0FBQyxHQUFHLE9BQU8sQ0FBQyxRQUFRLENBQUMsQ0FBQTtBQUMzQixJQUFNLE1BQU0sR0FBRyxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUE7QUFDakMsSUFBTSxXQUFXLEdBQUcsT0FBTyxDQUFDLGFBQWEsQ0FBQyxDQUFBO0FBRTFDO0lBQ0ksT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLG9CQUFvQixFQUFFLEVB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SixlQUFlO0FBQ2YsSUFBSTtBQUNKLHNCQUFzQjtBQUN0QixxREFBcUQ7QUFDckQscUJBQXFCO0FBQ3JCLHNCQUFzQjtBQUN0QixJQUFJIiwic291cmNlc0NvbnRlbnQiOlsiLy8vIDxyZWZlcmVuY2UgcGF0aD1cIi4uL2Vycm9yLmQudHNcIiAvPlxuZXhwb3J0IGZ1bmN0aW9uIGdldF9yb290X3BhdGhfcHJlZml4KCkge1xuICAgIHJldHVybiBwYXRoLmpvaW4oX19kaXJuYW1lLCAnLi4vLi4vLi4vLi4vJylcbn1cblxuLy8g5YWI5Yqg6L295qGG5p625bGC6Z2i55qE6ZSZ6K+v5a6a5LmJ77yM5YaN5Yqg6L2955So5oi35bGC6Z2i55qE6ZSZ6K+v5a6a5LmJ77yM5pSv5oyB55So5oi35a6a5LmJ6ZSZ6K+v6KaG55uW5qGG5p625bGC6Z2i55qE6ZSZ6K+v5aSa6K+t6KiA5raI5oGv5a6a5LmJ44CCXG5yZXF1aXJlKCcuLi9lcnJvcicpXG5jb25zdCBwYXRoID0gcmVxdWlyZSgncGF0aCcpXG5yZXF1aXJlKHBhdGguam9pbihnZXRfcm9vdF9wYXRoX3ByZWZpeCgpLCAnLi9hcHAvZXJyb3InKSkgLy8g5Yid5aeL5YyW5bqU55So5omp5bGV55qE6ZSZ6K+vXG5cbmltcG9ydCB7Z2V0X3N1ZmZpeF90c19vcl9qc30gZnJvbSAnLi9iYXNlJ1xuaW1wb3J0IHtfX2ZyYW1ld29ya19zZXNzaW9uX2luaXRfX30gZnJvbSAnLi9zZXNzaW9uJ1xuXG5yZXF1aXJlKHBhdGguam9pbihnZXRfcm9vdF9wYXRoX3ByZWZpeCgpLCAnLi9hcHAvZ2xvYmFsLm91dCcpICsgJy4nICsgZ2V0X3N1ZmZpeF90c19vcl9qcygpKSAvLyDliJ3lp4vljJblupTnlKjkuIDkupvmnprkuL7luLjph4/lrprkuYnnrYnmlrnms5VcblxuLy8g5Yid5aeL5YyWSW9D5a655ZmoXG5yZXF1aXJlKHBhdGguam9pbihnZXRfcm9vdF9wYXRoX3ByZWZpeCgpLCAnLi9hcHAvcGx1Z2lucy9jb250YWluZXInKSlcblxuY29uc3QgZnMgPSByZXF1aXJlKCdmcycpXG5jb25zdCB2aWV3ID0gcmVxdWlyZSgnbnVuanVja3MnKVxuY29uc3QgXyA9IHJlcXVpcmUoJ2xvZGFzaCcpXG5jb25zdCB0eXBlaXMgPSByZXF1aXJlKCd0eXBlLWlzJylcbmNvbnN0IHF1ZXJ5c3RyaW5nID0gcmVxdWlyZSgncXVlcnlzdHJpbmcnKVxuXG5mdW5jdGlvbiBnZXRfYXBwX2VudHJpZXNfcGF0aF9wcmVmaXgoKSB7XG4gICAgcmV0dXJuIHBhdGguam9pbihnZXRfcm9vdF9wYXRoX3ByZWZpeCgpLCAnLi9hcHAvZW50cmllcycpXG59XG5cbi8vIGh0dHBzOi8vZ2l0aHViLmNvbS9lcWZveC9odHRwLWJvZHktcGFyc2VyIOWPgueFp2tvYeeahOa6kOeggeato+ehruino+aekHBvc3Tor7fmsYLlj4LmlbBcbi8vIOWFvOWuuWFwcGxpY2F0aW9uL2pzb27lkoxhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWTkuKTnp43or7fmsYLnsbvlnovjgIJcbmV4cG9ydCBmdW5jdGlvbiBwYXJzZV9wb3N0X3BhcmFtKGhlYWRlcnMsIGJvZHkpIHtcbiAgICB0cnkge1xuICAgICAgICBpZiAoIWJvZHkpIHtcbiAgICAgICAgICAgIHJldHVybiB7fVxuICAgICAgICB9XG4gICAgICAgIGlmICh0eXBlaXMoe2hlYWRlcnN9LCBbJ2pzb24nXSkpIHtcbiAgICAgICAgICAgIHJldHVybiBKU09OLnBhcnNlKGJvZHkudG9TdHJpbmcoaGVhZGVyc1snY29udGVudC1lbmNvZGluZyddIHx8ICd1dGY4JykpXG4gICAgICAgIH0gZWxzZSBpZiAodHlwZW9mIGhlYWRlcnNbJ0NvbnRlbnQtVHlwZSddID09ICdzdHJpbmcnICYmIGhlYWRlcnNbJ0NvbnRlbnQtVHlwZSddLm1hdGNoKC9hcHBsaWNhdGlvblxcL2pzb24vKSkge1xuICAgICAgICAgICAgLy8gYnVnZml4IEFQSee9keWFs+eahOWtl+auteexu+Wei+WAvOeahOi1i+WAvOW3ruW8guS4jnR5cGUtaXPlupPnmoTlrZfmrrXlkI3np7DkuI3lhbzlrrnpl67popgoY29udGVudC10eXBl5LiOQ29udGVudC1UeXBl5Yy65YirKVxuICAgICAgICAgICAgcmV0dXJuIEpTT04ucGFyc2UoYm9keS50b1N0cmluZyhoZWFkZXJzWydjb250ZW50LWVuY29kaW5nJ10gfHwgJ3V0ZjgnKSlcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmICh0eXBlaXMoe2hlYWRlcnN9LCBbJ3VybGVuY29kZWQnXSkpIHtcbiAgICAgICAgICAgIHJldHVybiBxdWVyeXN0cmluZy5wYXJzZShib2R5LnRvU3RyaW5nKGhlYWRlcnNbJ2NvbnRlbnQtZW5jb2RpbmcnXSB8fCAndXRmOCcpKVxuICAgICAgICB9IGVsc2UgaWYgKHR5cGVvZiBoZWFkZXJzWydDb250ZW50LVR5cGUnXSA9PSAnc3RyaW5nJyAmJiBoZWFkZXJzWydDb250ZW50LVR5cGUnXSA9PSAnYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkJykge1xuICAgICAgICAgICAgLy8gYnVnZml4IOe6v+S4iuS5kOmrmHBvc3Tor7fmsYLlj4LmlbDop6PmnpDkuI3mraPnoa7pl67popjosIPor5XlgZrlhbzlrrnpgILphY3lpITnkIYgVE9ETyDlvoXmn6Xljp/lm6DkuLrllaV0eXBlaXPlupPlpLHmlYjkuoZcbiAgICAgICAgICAgIC8vIGFwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZFxuICAgICAgICAgICAgcmV0dXJuIHF1ZXJ5c3RyaW5nLnBhcnNlKGJvZHkudG9TdHJpbmcoaGVhZGVyc1snY29udGVudC1lbmNvZGluZyddIHx8XG4gICAgICAgICAgICAgICAgaGVhZGVyc1snQ29udGVudC1FbmNvZGluZyddIHx8ICd1dGY4JykpXG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICB4dGhyb3coRVJSJFBBUkFNLCB7aGVhZGVycywgYm9keX0pXG4gICAgICAgIH1cbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgeHRocm93KGVyciwge2hlYWRlcnMsIGJvZHl9KVxuICAgIH1cbn1cblxuLy8g6K+35rGC5YmN572u6L+H5ruk5aSE55CGXG5hc3luYyBmdW5jdGlvbiBmaWx0ZXJfcmVxdWVzdF9iZWdpbihhcGlfcGF0aDogc3RyaW5nLCBwYXJhbTogYW55KSB7XG4gICAgY29uc3QgZW50cnkgPSByZXF1aXJlKGFwaV9wYXRoKS5kZWZhdWx0XG4gICAgeGFzc2VydChlbnRyeSlcbiAgICBjb25zdCBvYmogPSBuZXcgZW50cnkoKVxuICAgIGlmIChvYmouXykge1xuICAgICAgICAvLyDlvLrliLbmiafooYzor7fmsYLlj4LmlbDpqozor4HpgLvovpFcbiAgICAgICAgeGFzc2VydChfLmlzRnVuY3Rpb24ob2JqLl8pKVxuICAgICAgICBhd2FpdCBvYmouXyhwYXJhbSlcbiAgICB9XG4gICAgLy8g5a+55LqOTU9DS+i/mOaYr+ato+W8j+ivt+axgui3r+eUseeahOiwg+eUqOWIpOaWreWkhOeQhlxuICAgIGxldCBhcGlfY2FsbGJhY2sgPSBvYmouJCRcbiAgICBpZiAoJ19fbW9ja19fJyBpbiBwYXJhbSkge1xuICAgICAgICBhcGlfY2FsbGJhY2sgPSBvYmouJCA/IG9iai4kIDogdW5kZWZpbmVkXG4gICAgfSBlbHNlIHtcbiAgICAgICAgLy8g5q2j5byP6K+35rGC5YmN572u5aSE55CG77yaYXV0aOmJtOadg+OAgeetieetieaTjeS9nOe7n+S4gOahhuaetuS7o+eggeWunueOsFxuICAgICAgICBpZiAob2JqLmNvbnRleHQpIHtcbiAgICAgICAgICAgIHhhc3NlcnQoXy5pc0Z1bmN0aW9uKG9iai5jb250ZXh0KSlcbiAgICAgICAgICAgIGNvbnN0IGNvbnRleHQgPSBvYmouY29udGV4dCgpXG4gICAgICAgICAgICB4YXNzZXJ0KF8uaXNQbGFpbk9iamVjdChjb250ZXh0LnBhcmFtKSAmJiBfLmlzRnVuY3Rpb24oY29udGV4dC5hdXRoKSlcbiAgICAgICAgICAgIGF3YWl0IGNvbnRleHQuYXV0aCgpXG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGFwaV9jYWxsYmFja1xufVxuXG4vLyB3ZWLpobXpnaLnmoTor7fmsYLmlK/mjIFnZXTmiJZwb3N077yMZ2V05LuF5LuF55So5LqO6aG16Z2i6Lez6L2s77yM6Ieq5Yqo5YW85a65Z2V05ZKMcG9zdOeUqOS6juihqOWNlemAkuS6pOS7peWPindlYuerr+eahOaOpeWPo+aVsOaNrueahOi/lOWbnuWkhOeQhu+8iOa1i+ivleWcuuaZr+S4i+aUr+aMgWdldOe6v+S4iueOr+Wig+WPquaUr+aMgXBvc3TljY/orq7vvInjgIJcbmFzeW5jIGZ1bmN0aW9uIHdlYl9yZXF1ZXN0X3Byb2Nlc3MoYXBpOiBzdHJpbmcsIHBhcmFtOiBhbnkpIHtcbiAgICBsZXQgcHJlZml4ID0gZ2V0X2FwcF9lbnRyaWVzX3BhdGhfcHJlZml4KClcbiAgICBsZXQgYXBpX3BhdGggPSBgJHtwcmVmaXh9L3dlYi8ke2FwaX1gXG4gICAgbGV0IG91dDogYW55ID0gdW5kZWZpbmVkXG4gICAgbGV0IGlzX2h0bWxfcmVxdWVzdDogYm9vbGVhbiA9XG4gICAgICAgIGZzLmV4aXN0c1N5bmMocGF0aC5yZXNvbHZlKF9fZGlybmFtZSwgYCR7cHJlZml4fS93ZWIvJHthcGl9Lmh0bWxgKSlcblxuICAgIHRyeSB7XG4gICAgICAgIGxldCBhcGlfY2FsbGJhY2sgPSBhd2FpdCBmaWx0ZXJfcmVxdWVzdF9iZWdpbihhcGlfcGF0aCwgcGFyYW0pXG4gICAgICAgIHhhc3NlcnQoXy5pc0Z1bmN0aW9uKGFwaV9jYWxsYmFjaykpXG4gICAgICAgIG91dCA9IGF3YWl0IGFwaV9jYWxsYmFjayhwYXJhbSkgLy8g5Zue6LCDQVBJ5a+55bqU55qE5Lia5Yqh6YC76L6R5a6e546wXG4gICAgICAgIGlmIChpc19odG1sX3JlcXVlc3QpIHtcbiAgICAgICAgICAgIC8vIOS7heWcqHdlYuivt+axgmh0bWzpobXpnaLnmoTml7blgJnlpoLmnpzmo4DmtYvliLAzMDLot7PovaznmoTml7blgJnlv73nlaXmqKHmnb/muLLmn5Pnm7TmjqXov5Tlm55cbiAgICAgICAgICAgIGlmIChnbG9iYWxbJ19fcmVkaXJlY3RfdXJsX18nXSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuXG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyDlsIZvdXTovazmjaLliLDlr7nlupTnmoRodG1s6K+V5Zu+57uR5a6a5LmL5ZCO5YaN6L6T5Ye6XG4gICAgICAgICAgICB2aWV3LmNvbmZpZ3VyZShwYXRoLnJlc29sdmUoX19kaXJuYW1lLCBgJHtwcmVmaXh9L3dlYmApLCB7bm9DYWNoZTogdHJ1ZSwgYXV0b2VzY2FwZTogZmFsc2V9KVxuICAgICAgICAgICAgb3V0ID0gdmlldy5yZW5kZXIoYC4vJHthcGl9Lmh0bWxgLCBvdXQpXG4gICAgICAgICAgICByZXR1cm4gb3V0XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyDlr7nkuo53ZWLpobXpnaLnmoTlhbPogZRhamF45o6l5Y+j6L+b6KGM6KeE6IyDcmVzdOaOpeWPo+aVsOaNruagvOW8j+eahOe7n+S4gOWkhOeQhlxuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICBzdWNjZXNzOiB0cnVlLFxuICAgICAgICAgICAgICAgIGNvbnRlbnQ6IG91dCxcbiAgICAgICAgICAgICAgICBlcnJvckxldmVsOiB1bmRlZmluZWQsXG4gICAgICAgICAgICAgICAgZXJyb3JDb2RlOiB1bmRlZmluZWQsXG4gICAgICAgICAgICAgICAgZXJyb3JNc2c6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAvLyDkuJrliqHplJnor6/miqXorablpITnkIYgVE9ETyDpnIDopoHogIPomZHplJnor6/lv73nlaXpl67pophcbiAgICAgICAgYXdhaXQgeHdhcm4oZXJyLCBhcGksIHBhcmFtKVxuXG4gICAgICAgIGlmIChpc19odG1sX3JlcXVlc3QpIHtcbiAgICAgICAgICAgIC8vIOWPquWvueS4muWKoemAu+i+kemUmeivr+WkhOeQhuWMuuWIhuahhuaetumUmeivr+i/mOaYr+S4muWKoemUmeivr++8iOS4muWKoemUmeivr2Vycm9y6aG16Z2i5pi+56S677yM5qGG5p626ZSZ6K+vaHR0cOmUmeivr+eKtuaAgeegge+8iUZJWE1FIOmcgOimgeaUuei/m+aOiVxuICAgICAgICAgICAgeGFzc2VydChmcy5leGlzdHNTeW5jKHBhdGgucmVzb2x2ZShfX2Rpcm5hbWUsIGAke3ByZWZpeH0vd2ViL2Vycm9yLmAgKyBnZXRfc3VmZml4X3RzX29yX2pzKCkpKSAmJlxuICAgICAgICAgICAgICAgIGZzLmV4aXN0c1N5bmMocGF0aC5yZXNvbHZlKF9fZGlybmFtZSwgYCR7cHJlZml4fS93ZWIvZXJyb3IuaHRtbGApKSlcbiAgICAgICAgICAgIGxldCBhcGlfY2FsbGJhY2sgPSByZXF1aXJlKGAke3ByZWZpeH0vd2ViL2Vycm9yLmAgKyBnZXRfc3VmZml4X3RzX29yX2pzKCkpLmRlZmF1bHRcbiAgICAgICAgICAgIHhhc3NlcnQoXy5pc0Z1bmN0aW9uKGFwaV9jYWxsYmFjaykpXG4gICAgICAgICAgICBvdXQgPSBhd2FpdCBhcGlfY2FsbGJhY2soZXJyKVxuICAgICAgICAgICAgdmlldy5jb25maWd1cmUocGF0aC5yZXNvbHZlKF9fZGlybmFtZSwgYCR7cHJlZml4fS93ZWJgKSwge25vQ2FjaGU6IHRydWUsIGF1dG9lc2NhcGU6IGZhbHNlfSlcbiAgICAgICAgICAgIG91dCA9IHZpZXcucmVuZGVyKGAuL2Vycm9yLmh0bWxgLCBvdXQpXG4gICAgICAgICAgICByZXR1cm4gb3V0XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBsZXQgZGF0YSA9IHhlcnJvcihlcnIpXG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgICAgIGNvbnRlbnQ6IGRhdGEucGFyYW0sXG4gICAgICAgICAgICAgICAgZXJyb3JMZXZlbDogJ2Vycm9yJyxcbiAgICAgICAgICAgICAgICBlcnJvckNvZGU6IGRhdGEuY29kZSxcbiAgICAgICAgICAgICAgICBlcnJvck1zZzogZGF0YS5tc2csXG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG59XG5cbi8vIHJlc3QgYXBp5o6l5Y+j6Ieq5Yqo5YW85a65Z2V05oiWcG9zdOivt+axguWkhOeQhuWNj+iuru+8iOa1i+ivleWcuuaZr+S4i+aUr+aMgWdldOe6v+S4iueOr+Wig+WPquaUr+aMgXBvc3TljY/orq7vvIlcbmFzeW5jIGZ1bmN0aW9uIHJlc3RfcmVxdWVzdF9wcm9jZXNzKGFwaTogc3RyaW5nLCBwYXJhbTogYW55KSB7XG4gICAgdHJ5IHtcbiAgICAgICAgbGV0IHByZWZpeCA9IGdldF9hcHBfZW50cmllc19wYXRoX3ByZWZpeCgpXG4gICAgICAgIGxldCBhcGlfcGF0aCA9IGAke3ByZWZpeH0vcmVzdC8ke2FwaX1gXG4gICAgICAgIGxldCBhcGlfY2FsbGJhY2sgPSBhd2FpdCBmaWx0ZXJfcmVxdWVzdF9iZWdpbihhcGlfcGF0aCwgcGFyYW0pXG4gICAgICAgIHhhc3NlcnQoXy5pc0Z1bmN0aW9uKGFwaV9jYWxsYmFjaykpXG4gICAgICAgIGxldCBvdXQgPSBhd2FpdCBhcGlfY2FsbGJhY2socGFyYW0pIC8vIOWbnuiwg0FQSeWvueW6lOeahOS4muWKoemAu+i+keWunueOsFxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgc3VjY2VzczogdHJ1ZSxcbiAgICAgICAgICAgIGNvbnRlbnQ6IG91dCxcbiAgICAgICAgICAgIGVycm9yTGV2ZWw6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgIGVycm9yQ29kZTogdW5kZWZpbmVkLFxuICAgICAgICAgICAgZXJyb3JNc2c6IHVuZGVmaW5lZCxcbiAgICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICBhd2FpdCB4d2FybihlcnIsIGFwaSwgcGFyYW0pXG4gICAgICAgIGxldCBkYXRhID0geGVycm9yKGVycilcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgY29udGVudDogZGF0YS5wYXJhbSxcbiAgICAgICAgICAgIGVycm9yTGV2ZWw6ICdlcnJvcicsXG4gICAgICAgICAgICBlcnJvckNvZGU6IGRhdGEuY29kZSxcbiAgICAgICAgICAgIGVycm9yTXNnOiBkYXRhLm1zZyxcbiAgICAgICAgfVxuICAgIH1cblxufVxuXG4vLyDov5Tlm57moLzlvI/mmK9IVE1M6L+Y5pivSlNPTuWPluWGs+S6jkFQSei3r+W+hOWvueW6lOeahHRz5paH5Lu25piv5ZCm5a2Y5Zyo5ZCM5ZCN55qEaHRtbOaooeadv+aWh+S7tu+8jOWmguaenOWtmOWcqOWImei/lOWbnkhUTUzlkKbliJnlhajpg6jov5Tlm55KU09O5pWw5o2u44CCXG4vLyDnuqblrprop4TojIPvvJpQT1NU6K+35rGC6YO95pivcmVzdGZ1bOeahEFQSeaOpeWPo++8iOagueaNrndlYuWSjHJlc3TnmoTot6/lvoTov5vooYzlhbfkvZPljLrliIbvvInvvIxHRVTor7fmsYLlr7nlupTnmoTot6/lvoTmnIlIVE1M5bCx5pivV0VC6K+35rGC5ZCm5YiZ5bCx5pivSlNPTuivt+axguOAglxuLy8g6YCa6L+H57qm5a6a566A5YyW6Lev55Sx55qE5a6a5LmJ44CCXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcmVxdWVzdF9wcm9jZXNzKGFwaTogc3RyaW5nLCBwYXJhbTogYW55KSB7XG4gICAgYXdhaXQgX19mcmFtZXdvcmtfc2Vzc2lvbl9pbml0X18oKVxuICAgIC8vIOagueaNrkFQSeeahOWJjee8gOWRveWQjeinhOiMg+iHquWKqOivhuWIq+W6lOeUqOexu+Wei+aYr+e6r3Jlc3Tpobnnm67ov5jmmK/nuq93ZWLpobnnm67ov5vooYzlr7nlupTnmoTlpITnkIbpgLvovpFcbiAgICBpZiAoL15cXC93ZWJcXC8vLnRlc3QoYXBpKSkge1xuICAgICAgICByZXR1cm4gYXdhaXQgd2ViX3JlcXVlc3RfcHJvY2VzcyhhcGkucmVwbGFjZSgvXlxcL3dlYlxcLy8sICcnKSwgcGFyYW0pXG4gICAgfSBlbHNlIGlmICgvXlxcL3Jlc3RcXC8vLnRlc3QoYXBpKSkge1xuICAgICAgICBsZXQgb3V0ID0gYXdhaXQgcmVzdF9yZXF1ZXN0X3Byb2Nlc3MoYXBpLnJlcGxhY2UoL15cXC9yZXN0XFwvLywgJycpLCBwYXJhbSlcbiAgICAgICAgZ2xvYmFsWydfX3JlZGlyZWN0X3VybF9fJ10gPSB1bmRlZmluZWRcbiAgICAgICAgcmV0dXJuIG91dFxuICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIFRPRE8g5q2j56Gu5LyY5YyW55WM6Z2i5o+Q56S66L+U5ZueSFRUUFPnirbmgIHnoIHplJnor6/vvIHvvIHvvIHvvIHov4fmu6Tml6DmlYhVUkzlrprkuYnjgIJcbiAgICAgICAgeHRocm93KEVSUiRQQVJBTSwgW2FwaSwgcGFyYW1dKVxuICAgIH1cbn1cblxuLy8gYWpheOi/lOWbnuaIkOWKn+e7k+aehOivtOaYjlxuLy8ge1xuLy8gICAgIHN1Y2Nlc3M6IHRydWUsXG4vLyAgICAgY29udGVudDog6L+U5Zue5YaF5a6577yMe30vW11cbi8vIH1cbi8vIGFqYXjov5Tlm57lpLHotKXnu5PmnoTor7TmmI5cbi8vIHtcbi8vICAgICBzdWNjZXNzOiBmYWxzZSxcbi8vICAgICBlcnJvckxldmVsOlsnaW5mb+KAmSwgJ3dhcm7igJksICdlcnJvcuKAmSwgJ2ZhdWx04oCZXSxcbi8vICAgICBlcnJvckNvZGU66ZSZ6K+v56CBLFxuLy8gICAgIGVycm9yTXNnOumUmeivr+S/oeaBr+ivtOaYjlxuLy8gfSJdfQ== |
\ | No newline at end of file |