UNPKG

35.2 kBJavaScriptView Raw
1"use strict";
2var __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};
10var __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};
37Object.defineProperty(exports, "__esModule", { value: true });
38/// <reference path="../error.d.ts" />
39function get_root_path_prefix() {
40 return path.join(__dirname, '../../../../');
41}
42exports.get_root_path_prefix = get_root_path_prefix;
43// 先加载框架层面的错误定义,再加载用户层面的错误定义,支持用户定义错误覆盖框架层面的错误多语言消息定义。
44require('../error');
45var path = require('path');
46require(path.join(get_root_path_prefix(), './app/error')); // 初始化应用扩展的错误
47var base_1 = require("./base");
48var session_1 = require("./session");
49require(path.join(get_root_path_prefix(), './app/global.out') + '.' + base_1.get_suffix_ts_or_js()); // 初始化应用一些枚举常量定义等方法
50// 初始化IoC容器
51require(path.join(get_root_path_prefix(), './app/plugins/container'));
52var fs = require('fs');
53var view = require('nunjucks');
54var _ = require('lodash');
55var typeis = require('type-is');
56var querystring = require('querystring');
57function 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两种请求类型。
62function 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}
91exports.parse_post_param = parse_post_param;
92// 请求前置过滤处理
93function 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协议)。
129function 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协议)
205function 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// 通过约定简化路由的定义。
250function 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}
279exports.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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5pdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbImluaXQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLHNDQUFzQztBQUN0QztJQUNJLE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsY0FBYyxDQUFDLENBQUE7QUFDL0MsQ0FBQztBQUZELG9EQUVDO0FBRUQsc0RBQXNEO0FBQ3RELE9BQU8sQ0FBQyxVQUFVLENBQUMsQ0FBQTtBQUNuQixJQUFNLElBQUksR0FBRyxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUE7QUFDNUIsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsb0JBQW9CLEVBQUUsRUFBRSxhQUFhLENBQUMsQ0FBQyxDQUFBLENBQUMsYUFBYTtBQUV2RSwrQkFBMEM7QUFDMUMscUNBQW9EO0FBRXBELE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLG9CQUFvQixFQUFFLEVBQUUsa0JBQWtCLENBQUMsR0FBRyxHQUFHLEdBQUcsMEJBQW1CLEVBQUUsQ0FBQyxDQUFBLENBQUMsbUJBQW1CO0FBRWhILFdBQVc7QUFDWCxPQUFPLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxvQkFBb0IsRUFBRSxFQUFFLHlCQUF5QixDQUFDLENBQUMsQ0FBQTtBQUVyRSxJQUFNLEVBQUUsR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUE7QUFDeEIsSUFBTSxJQUFJLEdBQUcsT0FBTyxDQUFDLFVBQVUsQ0FBQyxDQUFBO0FBQ2hDLElBQU0sQ0FBQyxHQUFHLE9BQU8sQ0FBQyxRQUFRLENBQUMsQ0FBQTtBQUMzQixJQUFNLE1BQU0sR0FBRyxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUE7QUFDakMsSUFBTSxXQUFXLEdBQUcsT0FBTyxDQUFDLGFBQWEsQ0FBQyxDQUFBO0FBRTFDO0lBQ0ksT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLG9CQUFvQixFQUFFLEVBQUUsZUFBZSxDQUFDLENBQUE7QUFDN0QsQ0FBQztBQUVELGlFQUFpRTtBQUNqRSw4REFBOEQ7QUFDOUQsMEJBQWlDLE9BQU8sRUFBRSxJQUFJO0lBQzFDLElBQUk7UUFDQSxJQUFJLENBQUMsSUFBSSxFQUFFO1lBQ1AsT0FBTyxFQUFFLENBQUE7U0FDWjtRQUNELElBQUksTUFBTSxDQUFDLEVBQUMsT0FBTyxTQUFBLEVBQUMsRUFBRSxDQUFDLE1BQU0sQ0FBQyxDQUFDLEVBQUU7WUFDN0IsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLGtCQUFrQixDQUFDLElBQUksTUFBTSxDQUFDLENBQUMsQ0FBQTtTQUMxRTthQUFNLElBQUksT0FBTyxPQUFPLENBQUMsY0FBYyxDQUFDLElBQUksUUFBUSxJQUFJLE9BQU8sQ0FBQyxjQUFjLENBQUMsQ0FBQyxLQUFLLENBQUMsbUJBQW1CLENBQUMsRUFBRTtZQUN6RywwRUFBMEU7WUFDMUUsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLGtCQUFrQixDQUFDLElBQUksTUFBTSxDQUFDLENBQUMsQ0FBQTtTQUMxRTthQUNJLElBQUksTUFBTSxDQUFDLEVBQUMsT0FBTyxTQUFBLEVBQUMsRUFBRSxDQUFDLFlBQVksQ0FBQyxDQUFDLEVBQUU7WUFDeEMsT0FBTyxXQUFXLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLGtCQUFrQixDQUFDLElBQUksTUFBTSxDQUFDLENBQUMsQ0FBQTtTQUNqRjthQUFNLElBQUksT0FBTyxPQUFPLENBQUMsY0FBYyxDQUFDLElBQUksUUFBUSxJQUFJLE9BQU8sQ0FBQyxjQUFjLENBQUMsSUFBSSxtQ0FBbUMsRUFBRTtZQUNySCw0REFBNEQ7WUFDNUQsb0NBQW9DO1lBQ3BDLE9BQU8sV0FBVyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxrQkFBa0IsQ0FBQztnQkFDOUQsT0FBTyxDQUFDLGtCQUFrQixDQUFDLElBQUksTUFBTSxDQUFDLENBQUMsQ0FBQTtTQUM5QzthQUNJO1lBQ0QsTUFBTSxDQUFDLFNBQVMsRUFBRSxFQUFDLE9BQU8sU0FBQSxFQUFFLElBQUksTUFBQSxFQUFDLENBQUMsQ0FBQTtTQUNyQztLQUNKO0lBQUMsT0FBTyxHQUFHLEVBQUU7UUFDVixNQUFNLENBQUMsR0FBRyxFQUFFLEVBQUMsT0FBTyxTQUFBLEVBQUUsSUFBSSxNQUFBLEVBQUMsQ0FBQyxDQUFBO0tBQy9CO0FBQ0wsQ0FBQztBQXpCRCw0Q0F5QkM7QUFFRCxXQUFXO0FBQ1gsOEJBQW9DLFFBQWdCLEVBQUUsS0FBVTs7Ozs7O29CQUN0RCxLQUFLLEdBQUcsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDLE9BQU8sQ0FBQTtvQkFDdkMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFBO29CQUNSLEdBQUcsR0FBRyxJQUFJLEtBQUssRUFBRSxDQUFBO3lCQUNuQixHQUFHLENBQUMsQ0FBQyxFQUFMLHdCQUFLO29CQUNMLGVBQWU7b0JBQ2YsT0FBTyxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUE7b0JBQzVCLHFCQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLEVBQUE7O29CQUFsQixTQUFrQixDQUFBOzs7b0JBR2xCLFlBQVksR0FBRyxHQUFHLENBQUMsRUFBRSxDQUFBO3lCQUNyQixDQUFBLFVBQVUsSUFBSSxLQUFLLENBQUEsRUFBbkIsd0JBQW1CO29CQUNuQixZQUFZLEdBQUcsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFBOzs7eUJBR3BDLEdBQUcsQ0FBQyxPQUFPLEVBQVgsd0JBQVc7b0JBQ1gsT0FBTyxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUE7b0JBQzVCLE9BQU8sR0FBRyxHQUFHLENBQUMsT0FBTyxFQUFFLENBQUE7b0JBQzdCLE9BQU8sQ0FBQyxDQUFDLENBQUMsYUFBYSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUMsVUFBVSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFBO29CQUNyRSxxQkFBTSxPQUFPLENBQUMsSUFBSSxFQUFFLEVBQUE7O29CQUFwQixTQUFvQixDQUFBOzt3QkFHNUIsc0JBQU8sWUFBWSxFQUFBOzs7O0NBQ3RCO0FBRUQsOEZBQThGO0FBQzlGLDZCQUFtQyxHQUFXLEVBQUUsS0FBVTs7Ozs7O29CQUNsRCxNQUFNLEdBQUcsMkJBQTJCLEVBQUUsQ0FBQTtvQkFDdEMsUUFBUSxHQUFNLE1BQU0sYUFBUSxHQUFLLENBQUE7b0JBQ2pDLEdBQUcsR0FBUSxTQUFTLENBQUE7b0JBQ3BCLGVBQWUsR0FDZixFQUFFLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsU0FBUyxFQUFLLE1BQU0sYUFBUSxHQUFHLFVBQU8sQ0FBQyxDQUFDLENBQUE7Ozs7b0JBR2hELHFCQUFNLG9CQUFvQixDQUFDLFFBQVEsRUFBRSxLQUFLLENBQUMsRUFBQTs7b0JBQTFELFlBQVksR0FBRyxTQUEyQztvQkFDOUQsT0FBTyxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUMsWUFBWSxDQUFDLENBQUMsQ0FBQTtvQkFDN0IscUJBQU0sWUFBWSxDQUFDLEtBQUssQ0FBQyxFQUFBLENBQUMsaUJBQWlCOztvQkFBakQsR0FBRyxHQUFHLFNBQXlCLENBQUEsQ0FBQyxpQkFBaUI7b0JBQ2pELElBQUksZUFBZSxFQUFFO3dCQUNqQiwwQ0FBMEM7d0JBQzFDLElBQUksTUFBTSxDQUFDLGtCQUFrQixDQUFDLEtBQUssU0FBUyxFQUFFOzRCQUMxQyxzQkFBTTt5QkFDVDt3QkFDRCwwQkFBMEI7d0JBQzFCLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxTQUFTLEVBQUssTUFBTSxTQUFNLENBQUMsRUFBRSxFQUFDLE9BQU8sRUFBRSxJQUFJLEVBQUUsVUFBVSxFQUFFLEtBQUssRUFBQyxDQUFDLENBQUE7d0JBQzVGLEdBQUcsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLE9BQUssR0FBRyxVQUFPLEVBQUUsR0FBRyxDQUFDLENBQUE7d0JBQ3ZDLHNCQUFPLEdBQUcsRUFBQTtxQkFDYjt5QkFBTTt3QkFDSCxzQ0FBc0M7d0JBQ3RDLHNCQUFPO2dDQUNILE9BQU8sRUFBRSxJQUFJO2dDQUNiLE9BQU8sRUFBRSxHQUFHO2dDQUNaLFVBQVUsRUFBRSxTQUFTO2dDQUNyQixTQUFTLEVBQUUsU0FBUztnQ0FDcEIsUUFBUSxFQUFFLFNBQVM7NkJBQ3RCLEVBQUE7cUJBQ0o7Ozs7b0JBRUQsMkJBQTJCO29CQUMzQixxQkFBTSxLQUFLLENBQUMsS0FBRyxFQUFFLEdBQUcsRUFBRSxLQUFLLENBQUMsRUFBQTs7b0JBRDVCLDJCQUEyQjtvQkFDM0IsU0FBNEIsQ0FBQTt5QkFFeEIsZUFBZSxFQUFmLHdCQUFlO29CQUNmLGlFQUFpRTtvQkFDakUsT0FBTyxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxTQUFTLEVBQUssTUFBTSxnQkFBYSxHQUFHLDBCQUFtQixFQUFFLENBQUMsQ0FBQzt3QkFDMUYsRUFBRSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLFNBQVMsRUFBSyxNQUFNLG9CQUFpQixDQUFDLENBQUMsQ0FBQyxDQUFBO29CQUNuRSxZQUFZLEdBQUcsT0FBTyxDQUFJLE1BQU0sZ0JBQWEsR0FBRywwQkFBbUIsRUFBRSxDQUFDLENBQUMsT0FBTyxDQUFBO29CQUNsRixPQUFPLENBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFBO29CQUM3QixxQkFBTSxZQUFZLENBQUMsS0FBRyxDQUFDLEVBQUE7O29CQUE3QixHQUFHLEdBQUcsU0FBdUIsQ0FBQTtvQkFDN0IsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLFNBQVMsRUFBSyxNQUFNLFNBQU0sQ0FBQyxFQUFFLEVBQUMsT0FBTyxFQUFFLElBQUksRUFBRSxVQUFVLEVBQUUsS0FBSyxFQUFDLENBQUMsQ0FBQTtvQkFDNUYsR0FBRyxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsY0FBYyxFQUFFLEdBQUcsQ0FBQyxDQUFBO29CQUN0QyxzQkFBTyxHQUFHLEVBQUE7O29CQUVOLElBQUksR0FBRyxNQUFNLENBQUMsS0FBRyxDQUFDLENBQUE7b0JBQ3RCLHNCQUFPOzRCQUNILE9BQU8sRUFBRSxLQUFLOzRCQUNkLE9BQU8sRUFBRSxJQUFJLENBQUMsS0FBSzs0QkFDbkIsVUFBVSxFQUFFLE9BQU87NEJBQ25CLFNBQVMsRUFBRSxJQUFJLENBQUMsSUFBSTs0QkFDcEIsUUFBUSxFQUFFLElBQUksQ0FBQyxHQUFHO3lCQUNyQixFQUFBOzs7Ozs7Q0FHWjtBQUVELHdEQUF3RDtBQUN4RCw4QkFBb0MsR0FBVyxFQUFFLEtBQVU7Ozs7Ozs7b0JBRS9DLE1BQU0sR0FBRywyQkFBMkIsRUFBRSxDQUFBO29CQUN0QyxRQUFRLEdBQU0sTUFBTSxjQUFTLEdBQUssQ0FBQTtvQkFDbkIscUJBQU0sb0JBQW9CLENBQUMsUUFBUSxFQUFFLEtBQUssQ0FBQyxFQUFBOztvQkFBMUQsWUFBWSxHQUFHLFNBQTJDO29CQUM5RCxPQUFPLENBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFBO29CQUN6QixxQkFBTSxZQUFZLENBQUMsS0FBSyxDQUFDLEVBQUEsQ0FBQyxpQkFBaUI7O29CQUFqRCxHQUFHLEdBQUcsU0FBeUIsQ0FBQyxpQkFBaUI7b0JBQWxCO29CQUNuQyxzQkFBTzs0QkFDSCxPQUFPLEVBQUUsSUFBSTs0QkFDYixPQUFPLEVBQUUsR0FBRzs0QkFDWixVQUFVLEVBQUUsU0FBUzs0QkFDckIsU0FBUyxFQUFFLFNBQVM7NEJBQ3BCLFFBQVEsRUFBRSxTQUFTO3lCQUN0QixFQUFBOzs7b0JBRUQscUJBQU0sS0FBSyxDQUFDLEtBQUcsRUFBRSxHQUFHLEVBQUUsS0FBSyxDQUFDLEVBQUE7O29CQUE1QixTQUE0QixDQUFBO29CQUN4QixJQUFJLEdBQUcsTUFBTSxDQUFDLEtBQUcsQ0FBQyxDQUFBO29CQUN0QixzQkFBTzs0QkFDSCxPQUFPLEVBQUUsS0FBSzs0QkFDZCxPQUFPLEVBQUUsSUFBSSxDQUFDLEtBQUs7NEJBQ25CLFVBQVUsRUFBRSxPQUFPOzRCQUNuQixTQUFTLEVBQUUsSUFBSSxDQUFDLElBQUk7NEJBQ3BCLFFBQVEsRUFBRSxJQUFJLENBQUMsR0FBRzt5QkFDckIsRUFBQTs7Ozs7Q0FHUjtBQUVELHlFQUF5RTtBQUN6RSxvRkFBb0Y7QUFDcEYsZUFBZTtBQUNmLHlCQUFzQyxHQUFXLEVBQUUsS0FBVTs7Ozs7d0JBQ3pELHFCQUFNLG9DQUEwQixFQUFFO29CQUNsQyxnREFBZ0Q7a0JBRGQ7O29CQUFsQyxTQUFrQyxDQUFBO3lCQUU5QixVQUFVLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFwQix3QkFBb0I7b0JBQ2IscUJBQU0sbUJBQW1CLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxVQUFVLEVBQUUsRUFBRSxDQUFDLEVBQUUsS0FBSyxDQUFDLEVBQUE7d0JBQXBFLHNCQUFPLFNBQTZELEVBQUE7O3lCQUM3RCxXQUFXLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFyQix3QkFBcUI7b0JBQ2xCLHFCQUFNLG9CQUFvQixDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsV0FBVyxFQUFFLEVBQUUsQ0FBQyxFQUFFLEtBQUssQ0FBQyxFQUFBOztvQkFBckUsR0FBRyxHQUFHLFNBQStEO29CQUN6RSxNQUFNLENBQUMsa0JBQWtCLENBQUMsR0FBRyxTQUFTLENBQUE7b0JBQ3RDLHNCQUFPLEdBQUcsRUFBQTs7b0JBRVYsMENBQTBDO29CQUMxQyxNQUFNLENBQUMsU0FBUyxFQUFFLENBQUMsR0FBRyxFQUFFLEtBQUssQ0FBQyxDQUFDLENBQUE7Ozs7OztDQUV0QztBQWJELDBDQWFDO0FBRUQsZUFBZTtBQUNmLElBQUk7QUFDSixxQkFBcUI7QUFDckIsMEJBQTBCO0FBQzFCLElBQUk7QUFDSixlQUFlO0FBQ2YsSUFBSTtBQUNKLHNCQUFzQjtBQUN0QixxREFBcUQ7QUFDckQscUJBQXFCO0FBQ3JCLHNCQUFzQjtBQUN0QixJQUFJIiwic291cmNlc0NvbnRlbnQiOlsiLy8vIDxyZWZlcmVuY2UgcGF0aD1cIi4uL2Vycm9yLmQudHNcIiAvPlxuZXhwb3J0IGZ1bmN0aW9uIGdldF9yb290X3BhdGhfcHJlZml4KCkge1xuICAgIHJldHVybiBwYXRoLmpvaW4oX19kaXJuYW1lLCAnLi4vLi4vLi4vLi4vJylcbn1cblxuLy8g5YWI5Yqg6L295qGG5p625bGC6Z2i55qE6ZSZ6K+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