1 | ;
|
2 | var __assign = (this && this.__assign) || Object.assign || function(t) {
|
3 | for (var s, i = 1, n = arguments.length; i < n; i++) {
|
4 | s = arguments[i];
|
5 | for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
6 | t[p] = s[p];
|
7 | }
|
8 | return t;
|
9 | };
|
10 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
11 | return new (P || (P = Promise))(function (resolve, reject) {
|
12 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
13 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
14 | function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
|
15 | step((generator = generator.apply(thisArg, _arguments || [])).next());
|
16 | });
|
17 | };
|
18 | var __generator = (this && this.__generator) || function (thisArg, body) {
|
19 | var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
20 | return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
21 | function verb(n) { return function (v) { return step([n, v]); }; }
|
22 | function step(op) {
|
23 | if (f) throw new TypeError("Generator is already executing.");
|
24 | while (_) try {
|
25 | 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;
|
26 | if (y = 0, t) op = [op[0] & 2, t.value];
|
27 | switch (op[0]) {
|
28 | case 0: case 1: t = op; break;
|
29 | case 4: _.label++; return { value: op[1], done: false };
|
30 | case 5: _.label++; y = op[1]; op = [0]; continue;
|
31 | case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
32 | default:
|
33 | if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
34 | if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
35 | if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
36 | if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
37 | if (t[2]) _.ops.pop();
|
38 | _.trys.pop(); continue;
|
39 | }
|
40 | op = body.call(thisArg, _);
|
41 | } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
42 | if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
43 | }
|
44 | };
|
45 | var _this = this;
|
46 | Object.defineProperty(exports, "__esModule", { value: true });
|
47 | process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
48 | require("reflect-metadata");
|
49 | var inversify_1 = require("inversify");
|
50 | var typeorm_1 = require("@bxjs/typeorm");
|
51 | var session_1 = require("./session");
|
52 | var $$ = require("./plugins");
|
53 | var path = require('path');
|
54 | var ErrorStackParser = require('error-stack-parser');
|
55 | var cookie = require('cookie');
|
56 | var MobileDetect = require('mobile-detect');
|
57 | var fetch = require('node-fetch');
|
58 | var _ = require('lodash');
|
59 | var moment = require('moment');
|
60 | var extend = require('extend');
|
61 | var querystring = require('querystring');
|
62 | // const parameter = require('parameter')
|
63 | // const parameterCheckInstance = new parameter({
|
64 | // // translate: function () {
|
65 | // // var args = Array.prototype.slice.call(arguments);
|
66 | // // // Assume there have I18n.t method for convert language.
|
67 | // // return I18n.t.apply(I18n, args);
|
68 | // // }
|
69 | // })
|
70 | var circular_json = require("circular-json");
|
71 | var mockjs = require('mockjs');
|
72 | var shortid = require('shortid');
|
73 | var validatorjs = require('validatorjs');
|
74 | var cross_spawn = require('cross-spawn');
|
75 | var ACMClient = require('acm-client');
|
76 | var co = require('co');
|
77 | // FIXME HACK原生方法JSON转换不可逆的BUG(JAVA端传来的富文本字段内容含有\n\t字符串中的字符生成JSON字符串无法正常解析报错)
|
78 | var raw_stringify = JSON.stringify;
|
79 | function new_stringify(value, replacer, space) {
|
80 | var out = raw_stringify(value, replacer, space);
|
81 | if (_.isString(out)) {
|
82 | out = out.replace(/\\n/g, '\\\\n')
|
83 | .replace(/\\t/g, '\\\\t')
|
84 | .replace(/\\u/g, '\\\\u'); //JAVA端返回的unicode字符转义处理
|
85 | }
|
86 | return out;
|
87 | }
|
88 | JSON.stringify = new_stringify;
|
89 | // ts-node本地调试需要加载对应的源代码后缀名称
|
90 | function get_suffix_ts_or_js() {
|
91 | if (global['__env__'] == 'local' && !/^\/code\/node_modules/.test(__dirname)) {
|
92 | return 'ts';
|
93 | }
|
94 | else {
|
95 | return 'js';
|
96 | }
|
97 | }
|
98 | exports.get_suffix_ts_or_js = get_suffix_ts_or_js;
|
99 | // 准确定位错误码位置,间接得到函数调用位置地址信息,结合符号报表的正确解析处理完美得到错误定位信息,准确代码调试。
|
100 | function __get_base_func_caller_source_position(position) {
|
101 | if (position === void 0) { position = 3; }
|
102 | try {
|
103 | throw new Error();
|
104 | }
|
105 | catch (err) {
|
106 | var out = ErrorStackParser.parse(err);
|
107 | var idx = 0;
|
108 | // 找到第二个TS文件的执行位置
|
109 | var find_ts_sufix_file_count = 0;
|
110 | for (; idx < out.length; idx++) {
|
111 | if (/\.ts$/.test(out[idx].fileName)) {
|
112 | find_ts_sufix_file_count += 1;
|
113 | }
|
114 | if (find_ts_sufix_file_count == position) {
|
115 | break;
|
116 | }
|
117 | }
|
118 | if (find_ts_sufix_file_count == position) {
|
119 | return '[' + out[idx]['fileName'] + ':' + out[idx]['lineNumber'] + ']';
|
120 | }
|
121 | else {
|
122 | // TODO 需要定位为什么调用栈无法找到对应的位置出现越界??
|
123 | // console.error(err)
|
124 | console.error(circular_json.stringify(out, null, 4)
|
125 | .replace(/\r/g, '').replace(/\n/g, ''));
|
126 | return '#';
|
127 | }
|
128 | }
|
129 | }
|
130 | // 获取异常调用栈用于辅助错误提示定位
|
131 | function xstack(err, compact) {
|
132 | if (compact === void 0) { compact = true; }
|
133 | try {
|
134 | // TODO 优化裁剪一些无用信息减少日志尺寸更加便于人工分析处理
|
135 | var stack = ErrorStackParser.parse(err);
|
136 | if (compact) {
|
137 | var sources = [];
|
138 | for (var _i = 0, stack_1 = stack; _i < stack_1.length; _i++) {
|
139 | var v = stack_1[_i];
|
140 | sources.push(v['fileName'] + ":" + v['lineNumber']);
|
141 | }
|
142 | return sources;
|
143 | }
|
144 | return stack;
|
145 | }
|
146 | catch (err1) {
|
147 | var source = __get_base_func_caller_source_position();
|
148 | return "invalid error input param (" + source + ")";
|
149 | }
|
150 | }
|
151 | exports.xstack = xstack;
|
152 | // // 错误栈的递归嵌套格式显示数据结构定义(param嵌套找到最后一个msg的JSON解析语法错误就是错误链的原始错误发生位置)
|
153 | // let x = {
|
154 | // "code": "UNKNOWN",
|
155 | // "msg": "未知错误",
|
156 | // "param": {
|
157 | // "msg": "您输入的用户名或密码错误,请重新登录 (ErrorCode: 1005, url: https://login.alibaba-inc.com/authorize/login.do)"
|
158 | // },
|
159 | // "stack": "[\"/Users/chujinghui/Desktop/work/xjs/bxjs/framework/base.ts:110\",\"/Users/chujinghui/Desktop/work/xjs/bxjs/app/entries/web/mobile/meeting-room-visit.ts:161\",\"/Users/chujinghui/Desktop/work/xjs/bxjs/app/entries/web/mobile/meeting-room-visit.js:40\",\"/Users/chujinghui/Desktop/work/xjs/bxjs/app/entries/web/mobile/meeting-room-visit.js:21\",\"/Users/chujinghui/Desktop/work/xjs/bxjs/app/entries/web/mobile/meeting-room-visit.js:13\",\"internal/process/next_tick.js:188\"]",
|
160 | // }
|
161 | // 对于异常内容的格式化参数解析处理成为四元组code/msg/param/stack
|
162 | function xerror(err, __param) {
|
163 | xassert(err instanceof Error);
|
164 | try {
|
165 | // 标准错误的统一转换处理
|
166 | var data_1 = JSON.parse(err.message);
|
167 | if (data_1.code && data_1.msg && ERRORS[data_1.code]) {
|
168 | return data_1;
|
169 | }
|
170 | }
|
171 | catch (err) {
|
172 | // ignore parse error
|
173 | }
|
174 | // 非标准错误的统一格式转换处理
|
175 | var msg = ERRORS[ERR$UNKNOWN]['zh']; // TODO 错误码多语言回传到客户端问题
|
176 | var code = ERR$UNKNOWN;
|
177 | var param = { msg: err.message, param: __param }; // 用户自定义的错误参数信息 msg为非错误码JSON四元组就是嵌套的终止条件。
|
178 | var stack = xstack(err);
|
179 | var data = { msg: msg, code: code, param: param, stack: stack };
|
180 | return data;
|
181 | }
|
182 | exports.xerror = xerror;
|
183 | // 用于获取错误栈的root cause根本原因(第一个被拦截的错误发生位置)
|
184 | function xroot(err) {
|
185 | xassert(err instanceof Error);
|
186 | var _a = xerror(err), msg = _a.msg, param = _a.param, code = _a.code, stack = _a.stack;
|
187 | // 递归遍历找到错误链的root cause
|
188 | for (; param && param.msg;) {
|
189 | try {
|
190 | var json = JSON.parse(param.msg);
|
191 | param = json.param;
|
192 | }
|
193 | catch (err) {
|
194 | msg = param.msg;
|
195 | code = param.code;
|
196 | stack = param.stack;
|
197 | param = param.param;
|
198 | break;
|
199 | }
|
200 | }
|
201 | return { msg: msg, code: code, param: param, stack: stack };
|
202 | }
|
203 | exports.xroot = xroot;
|
204 | // TODO 报错处理(显示问题反馈联系人信息)
|
205 | // 将未处理的错误上抛的异常链记录下来用于精准追踪代码的执行过程(以及准确获取到根节点的错误码)
|
206 | // 对于promise异步回调的统一出错处理写法实例
|
207 | // export function login(username: string, password: string) {
|
208 | // return new Promise((resolve, reject) => {
|
209 | // co(function* () {
|
210 | // let user = yield buc.oauthclient.login(username, password)
|
211 | // resolve(user)
|
212 | // }).catch(async function (err) {
|
213 | // xthrow(err, reject)
|
214 | // })
|
215 | // })
|
216 | // }
|
217 | function xthrow(code, param, reject_param) {
|
218 | if (code === void 0) { code = ERR$UNKNOWN; }
|
219 | if (param === void 0) { param = undefined; }
|
220 | if (reject_param === void 0) { reject_param = undefined; }
|
221 | // promise中进行reject异常处理的抛出错误方法的形参逻辑预处理转换。
|
222 | var reject = _.isFunction(param) ? param : undefined;
|
223 | if (reject)
|
224 | param = reject_param;
|
225 | var data = {};
|
226 | var source = __get_base_func_caller_source_position();
|
227 | if (code instanceof Error) {
|
228 | try {
|
229 | data = JSON.parse(code.message);
|
230 | // 将透传上抛的错误的路径信息和附加参数也记录下来方便提供完整应用堆栈信息辅助调试业务逻辑
|
231 | if (!_.isArray(data.stack)) {
|
232 | data.stack = [];
|
233 | }
|
234 | data.stack.push(source);
|
235 | }
|
236 | catch (err) {
|
237 | // ignore
|
238 | }
|
239 | // 标准错误直接上抛处理
|
240 | if (data.code && data.msg && ERRORS[data.code]) {
|
241 | // 测试严重BUG reject函数类型表达式为假必须要用lodash判定是否为函数
|
242 | if (_.isFunction(reject)) {
|
243 | // promise回调中进行抛错误处理
|
244 | var err = new Error(JSON.stringify(data));
|
245 | reject(err);
|
246 | return;
|
247 | }
|
248 | else {
|
249 | throw new Error(JSON.stringify(data));
|
250 | }
|
251 | }
|
252 | // 将非标准错误转换为标准错误后再上抛处理
|
253 | data = xerror(code, param);
|
254 | data.code = ERR$UNKNOWN;
|
255 | data.msg = ERRORS[ERR$UNKNOWN]['zh']; // FIXME TODO 错误码的多语言处理转换!!
|
256 | data.param = { msg: code.message, param: param, stack: [source] };
|
257 | }
|
258 | else {
|
259 | // 对于常量定义错误的统一格式化处理
|
260 | data = { code: code, msg: global['ERRORS'][code]['zh'], param: param, stack: [source] };
|
261 | }
|
262 | // 对于是否promise场景下的错误上抛进行正确的转换处理
|
263 | if (_.isFunction(reject)) {
|
264 | // promise回调中进行抛错误处理
|
265 | reject(new Error(JSON.stringify(data)));
|
266 | }
|
267 | else {
|
268 | // 非promise回调中异常传递
|
269 | throw new Error(JSON.stringify(data));
|
270 | }
|
271 | }
|
272 | exports.xthrow = xthrow;
|
273 | function xassert(expr, code, param) {
|
274 | if (code === void 0) { code = ERR$ASSERT; }
|
275 | var source = __get_base_func_caller_source_position();
|
276 | var stack = [source];
|
277 | if (!expr)
|
278 | throw new Error(JSON.stringify({ code: code, msg: global['ERRORS'][code]['zh'], param: param, stack: stack }));
|
279 | return expr;
|
280 | }
|
281 | exports.xassert = xassert;
|
282 | // // https://github.com/node-modules/parameter 参数验证规则详见此文档(egg团队开发的组件)
|
283 | // // 注意事项:GET通过URL传递的参数都是字符串类型应该尽量避免GET传递参数,需要多用POST的JSON格式传递参数并且POSTMAN上进行辅助测试正确数据类型映射。
|
284 | // export function xcheck(param: { [propName: string]: any }, rules: { [propName: string]: any }) {
|
285 | // let errors = parameterCheckInstance.validate(rules, param)
|
286 | // if (_.isEmpty(errors)) {
|
287 | // return true
|
288 | // } else {
|
289 | // xthrow(ERR$PARAM, errors)
|
290 | // }
|
291 | // }
|
292 | function xlog() {
|
293 | var args = [];
|
294 | for (var _i = 0; _i < arguments.length; _i++) {
|
295 | args[_i] = arguments[_i];
|
296 | }
|
297 | // 兼容云端以及本地日志调试(解决任意对象的JSON字符串内容的完整输出)
|
298 | var source = __get_base_func_caller_source_position();
|
299 | var output = circular_json.stringify(args.slice(), null, 4);
|
300 | if (global['__env__'] != 'prod' && !/^\/code\/node_modules/.test(__dirname)) {
|
301 | // 打印到控制台一份日志(在阿里云非线上FC环境中)
|
302 | console.log.apply(undefined, [source + output]);
|
303 | // 写日志文件到/tmp下临时处理一下 TODO 需要改为类似log4j的本地日志库仅在非线上环境使用方便开发单机日常机器上调试。
|
304 | var fs = require('fs');
|
305 | var logFilePath = process.env['NODE_LOGFILE'] ? process.env['NODE_LOGFILE'] : '/tmp/bxjs.log';
|
306 | fs.appendFileSync(logFilePath, source + output + "\r\n");
|
307 | }
|
308 | else {
|
309 | // 生产环境下只打印到控制台绑定的SLS日志服务器上,并且需要去除掉换行信息否则打印会不正常。
|
310 | output = output.replace(/\r/g, '').replace(/\n/g, '');
|
311 | console.log.apply(undefined, [source + output]);
|
312 | }
|
313 | }
|
314 | exports.xlog = xlog;
|
315 | // // 将详细错误信息及时发送到钉钉群上实时反馈给维护者
|
316 | // await xwarn({
|
317 | // code,
|
318 | // // TODO 如何认证通过了获取到用户信息也需要发送过去,方便联系对接人员进行立刻问题处理反馈。
|
319 | // message,
|
320 | // stack,
|
321 | // param,
|
322 | // })
|
323 | // 将详细错误信息及时发送到钉钉群上实时反馈给维护者
|
324 | // 钉钉IM群机器人报警通知
|
325 | function xwarn() {
|
326 | var args = [];
|
327 | for (var _i = 0; _i < arguments.length; _i++) {
|
328 | args[_i] = arguments[_i];
|
329 | }
|
330 | return __awaiter(this, void 0, void 0, function () {
|
331 | var source, out, access_token, mobiles;
|
332 | return __generator(this, function (_a) {
|
333 | switch (_a.label) {
|
334 | case 0:
|
335 | source = __get_base_func_caller_source_position();
|
336 | // 对于异常参数警告信息进行错误内容标准解析
|
337 | if (args.length > 0 && args[0] instanceof Error) {
|
338 | args[0] = xerror(args[0]);
|
339 | }
|
340 | out = [source, moment().format('YYYY-MM-DD HH:mm:ss'), __assign({}, args)];
|
341 | access_token = xconfig('framework.warn.dingding.access_token');
|
342 | mobiles = xconfig('framework.warn.dingding.mobiles');
|
343 | if (!access_token || !mobiles) {
|
344 | access_token = '020a09eac5f2fa320ae851442d5e19e23693c64ad2255c85354b4a49a5a48d35';
|
345 | mobiles = ['15381151346'];
|
346 | }
|
347 | return [4 /*yield*/, xpost("https://oapi.dingtalk.com/robot/send?access_token=" + access_token, {
|
348 | msgtype: 'text',
|
349 | text: {
|
350 | content: out
|
351 | },
|
352 | at: {
|
353 | atMobiles: mobiles,
|
354 | isAtAll: false
|
355 | }
|
356 | })
|
357 | // 线上SLS日志上也保存一份
|
358 | // console.warn(out)
|
359 | ];
|
360 | case 1:
|
361 | _a.sent();
|
362 | // 线上SLS日志上也保存一份
|
363 | // console.warn(out)
|
364 | xlog(out);
|
365 | return [2 /*return*/];
|
366 | }
|
367 | });
|
368 | });
|
369 | }
|
370 | // 捕获未监听到的异常记录后直接退出(运行堆栈已经破坏直接记录日志后异常退出即可,由外部监控自动重启)
|
371 | process.on('uncaughtException', function (err) {
|
372 | return __awaiter(this, void 0, void 0, function () {
|
373 | return __generator(this, function (_a) {
|
374 | switch (_a.label) {
|
375 | case 0:
|
376 | xlog(xerror(err));
|
377 | return [4 /*yield*/, xwarn(err)];
|
378 | case 1:
|
379 | _a.sent();
|
380 | process.exit(-1);
|
381 | return [2 /*return*/];
|
382 | }
|
383 | });
|
384 | });
|
385 | });
|
386 | // 记录await/async中出现未捕获的异常错误
|
387 | process.on('unhandledRejection', function (reason, p) { return __awaiter(_this, void 0, void 0, function () {
|
388 | return __generator(this, function (_a) {
|
389 | switch (_a.label) {
|
390 | case 0:
|
391 | xlog('Unhandled Rejection at: Promise', p, 'reason:', reason);
|
392 | // application specific logging, throwing an error, or other logic here
|
393 | return [4 /*yield*/, xwarn(reason, p)];
|
394 | case 1:
|
395 | // application specific logging, throwing an error, or other logic here
|
396 | _a.sent();
|
397 | process.exit(-1);
|
398 | return [2 /*return*/];
|
399 | }
|
400 | });
|
401 | }); });
|
402 | // async/await的非阻塞异步延迟方法,用于调试阻塞程序的执行进行单步调试的效果。
|
403 | var sleep = require('sleep-async')();
|
404 | function xsleep(ms) {
|
405 | if (ms === void 0) { ms = -1; }
|
406 | if (ms <= 0) {
|
407 | ms = 50 * 365 * 24 * 3600 * 1000; // 50年最大数视为永久阻塞方便断点单步调试问题
|
408 | }
|
409 | return new Promise(function (resolve, reject) {
|
410 | try {
|
411 | sleep.sleep(ms, function () {
|
412 | resolve();
|
413 | });
|
414 | }
|
415 | catch (err) {
|
416 | xlog(xerror(err));
|
417 | resolve();
|
418 | // xthrow(err,reject)
|
419 | }
|
420 | });
|
421 | }
|
422 | exports.xsleep = xsleep;
|
423 | function xpost(url, param, headers, timeout) {
|
424 | if (timeout === void 0) { timeout = 3000; }
|
425 | return __awaiter(this, void 0, void 0, function () {
|
426 | var res, json, text, err_1;
|
427 | return __generator(this, function (_a) {
|
428 | switch (_a.label) {
|
429 | case 0:
|
430 | // TODO 线上测试不稳定超时暂时忽略掉通过进程最大运行时间去控制超时失败
|
431 | timeout = 5000; // -1 不行线上会被阻塞住僵死
|
432 | res = null;
|
433 | json = null;
|
434 | text = null;
|
435 | _a.label = 1;
|
436 | case 1:
|
437 | _a.trys.push([1, 4, , 5]);
|
438 | return [4 /*yield*/, fetch(url, {
|
439 | method: 'POST',
|
440 | body: JSON.stringify(param),
|
441 | headers: __assign({ 'Content-Type': 'application/json' }, headers),
|
442 | timeout: timeout <= 0 ? 0 : timeout,
|
443 | })];
|
444 | case 2:
|
445 | res = _a.sent();
|
446 | return [4 /*yield*/, res.text()]; // 解析出完整的返回内容避免HTML以及非法格式信息便于正确报错定位后端接口错误
|
447 | case 3:
|
448 | text = _a.sent(); // 解析出完整的返回内容避免HTML以及非法格式信息便于正确报错定位后端接口错误
|
449 | json = JSON.parse(text);
|
450 | return [2 /*return*/, json];
|
451 | case 4:
|
452 | err_1 = _a.sent();
|
453 | xthrow(err_1, { url: url, param: param, headers: headers, text: text });
|
454 | return [3 /*break*/, 5];
|
455 | case 5: return [2 /*return*/];
|
456 | }
|
457 | });
|
458 | });
|
459 | }
|
460 | exports.xpost = xpost;
|
461 | // 默认超时3000毫秒
|
462 | function xget(url, param, headers, timeout) {
|
463 | if (timeout === void 0) { timeout = 3000; }
|
464 | return __awaiter(this, void 0, void 0, function () {
|
465 | var res, json, text, err_2;
|
466 | return __generator(this, function (_a) {
|
467 | switch (_a.label) {
|
468 | case 0:
|
469 | // TODO 线上测试不稳定超时暂时忽略掉通过进程最大运行时间去控制超时失败
|
470 | timeout = 5000; // -1 不行线上会被阻塞住僵死
|
471 | res = null;
|
472 | json = null;
|
473 | text = null;
|
474 | _a.label = 1;
|
475 | case 1:
|
476 | _a.trys.push([1, 4, , 5]);
|
477 | url = url + (param ? '?' : '') + querystring.stringify(param);
|
478 | return [4 /*yield*/, fetch(url, {
|
479 | method: 'GET',
|
480 | headers: __assign({ 'Content-Type': 'application/json' }, headers),
|
481 | timeout: timeout <= 0 ? 0 : timeout,
|
482 | })];
|
483 | case 2:
|
484 | res = _a.sent();
|
485 | return [4 /*yield*/, res.text()]; // 解析出完整的返回内容避免HTML以及非法格式信息便于正确报错定位后端接口错误
|
486 | case 3:
|
487 | text = _a.sent(); // 解析出完整的返回内容避免HTML以及非法格式信息便于正确报错定位后端接口错误
|
488 | json = JSON.parse(text);
|
489 | return [2 /*return*/, json];
|
490 | case 4:
|
491 | err_2 = _a.sent();
|
492 | xthrow(err_2, { url: url, param: param, headers: headers, text: text });
|
493 | return [3 /*break*/, 5];
|
494 | case 5: return [2 /*return*/];
|
495 | }
|
496 | });
|
497 | });
|
498 | }
|
499 | exports.xget = xget;
|
500 | // 302临时重定向跳转实现
|
501 | function xredirect(url, param) {
|
502 | if (param === void 0) { param = {}; }
|
503 | // TODO 多个程序实例并发处理的时候存在时序问题不能保证全局变量被准确清空。
|
504 | // 检查应用重复设置重定向地址未及时return返回控制器问题
|
505 | xassert(global['__redirect_url__'] === undefined);
|
506 | if (param) {
|
507 | xassert(_.isPlainObject(param));
|
508 | // 删除param中两个框架预定义参数__url__和__api__不允许进行参数传递(禁止业务逻辑使用避免框架后续升级以及与短网址功能冲突)
|
509 | delete param.__api__;
|
510 | delete param.__url__;
|
511 | // 补额外的附加参数
|
512 | if (/\?/.test(url)) {
|
513 | url += '&';
|
514 | }
|
515 | else {
|
516 | url += '?';
|
517 | }
|
518 | url += querystring.stringify(param);
|
519 | }
|
520 | global['__redirect_url__'] = url;
|
521 | }
|
522 | exports.xredirect = xredirect;
|
523 | // 如果只有key参数表示读取属性(缺省值为undefined),如果key为空表示读取所有的请求cookies属性,否则表示响应设置cookies
|
524 | function xcookie(key, value, option) {
|
525 | if (!arguments.length) {
|
526 | // 读取所有的请求cookies属性object
|
527 | return global['__request_cookies__'] ? global['__request_cookies__'] : {};
|
528 | }
|
529 | else if (arguments.length == 1) {
|
530 | return key ? xcookie()[key] : undefined;
|
531 | }
|
532 | else {
|
533 | if (global['__respond_cookies__'] === undefined) {
|
534 | global['__respond_cookies__'] = {};
|
535 | }
|
536 | if (key) {
|
537 | // COOKIES缺省属性设置(有效时间24小时并且统一关联到根页面上获取COOKIES值)
|
538 | option = xassign({ path: '/', maxAge: 24 * 3600 }, option);
|
539 | global['__respond_cookies__'][key] = cookie.serialize(key, value, option);
|
540 | }
|
541 | return;
|
542 | }
|
543 | }
|
544 | exports.xcookie = xcookie;
|
545 | // 判断user-agent请求是否为移动端
|
546 | function xismobile() {
|
547 | var md = new MobileDetect(global['__user_agent__']);
|
548 | return !!md.mobile();
|
549 | }
|
550 | function xassign(target, source) {
|
551 | var args = [];
|
552 | for (var _i = 2; _i < arguments.length; _i++) {
|
553 | args[_i - 2] = arguments[_i];
|
554 | }
|
555 | var param = [true, target, source].concat(args);
|
556 | return extend.apply(null, param);
|
557 | }
|
558 | // 查询app/config目录下的应用配置数据
|
559 | function xconfig(path, defaultValue) {
|
560 | if (defaultValue === void 0) { defaultValue = undefined; }
|
561 | if (global['__config__']) {
|
562 | return _.get(global['__config__'], path, defaultValue);
|
563 | }
|
564 | var fp = require('path');
|
565 | var fs = require('fs');
|
566 | // 自动获取app/config的相对路径目录位置得到根路径的位置
|
567 | var config_path = '';
|
568 | if (__dirname.includes('/node_modules/@bxjs/base/')) {
|
569 | // 在应用目录下
|
570 | config_path = fp.join(__dirname, '../../../../app/config');
|
571 | }
|
572 | else {
|
573 | // 在axjs库开发目录下
|
574 | config_path = fp.join(__dirname, '../app/config');
|
575 | }
|
576 | // 自动识别判断运行环境global['__env__']并且加载对应的base数据和env数据
|
577 | var config_base_path = config_path + '/config.base.' + get_suffix_ts_or_js();
|
578 | var config_env_path = config_path + ("/config." + global['__env__'] + ".") + get_suffix_ts_or_js();
|
579 | if (!fs.existsSync(config_base_path)) {
|
580 | return defaultValue;
|
581 | }
|
582 | var config_base = require(config_base_path).default;
|
583 | var config_env = {};
|
584 | if (fs.existsSync(config_env_path)) {
|
585 | config_env = require(config_env_path).default;
|
586 | }
|
587 | // bugfix Object.assign不支持深度拷贝问题
|
588 | // global['__config__'] = Object.assign({}, config_base, config_env)
|
589 | // global['__config__'] = _.assign({}, config_env, config_base)
|
590 | global['__config__'] = xassign({}, config_base, config_env);
|
591 | return _.get(global['__config__'], path, defaultValue);
|
592 | }
|
593 | function xconnect(callback, config) {
|
594 | if (config === void 0) { config = 'default'; }
|
595 | return __awaiter(this, void 0, void 0, function () {
|
596 | var _this = this;
|
597 | return __generator(this, function (_a) {
|
598 | return [2 /*return*/, new Promise(function (resolve, reject) { return __awaiter(_this, void 0, void 0, function () {
|
599 | var cfg, mng, name, db_1, err_3;
|
600 | var _this = this;
|
601 | return __generator(this, function (_a) {
|
602 | switch (_a.label) {
|
603 | case 0:
|
604 | cfg = {};
|
605 | _a.label = 1;
|
606 | case 1:
|
607 | _a.trys.push([1, 3, , 4]);
|
608 | cfg = xassign({}, xconfig('plugins.database.default', {}));
|
609 | xassert(!_.isEmpty(cfg), ERR$PARAM, { config: config });
|
610 | // 强制补上约定的实体存放路径定义位置(不允许配置是约定规范)
|
611 | if (__dirname.includes('/node_modules/@bxjs/base/')) {
|
612 | // 在应用目录下
|
613 | cfg['entities'] = [
|
614 | path.join(__dirname, '../../../../app/plugins/database/entity/*.' + get_suffix_ts_or_js())
|
615 | ];
|
616 | }
|
617 | else {
|
618 | // 在axjs库开发目录下
|
619 | cfg['entities'] = [
|
620 | path.join(__dirname, '../app/plugins/database/entity/*.' + get_suffix_ts_or_js())
|
621 | ];
|
622 | }
|
623 | mng = typeorm_1.getConnectionManager();
|
624 | name = cfg.name ? cfg.name : 'default';
|
625 | if (!mng.has(name)) {
|
626 | mng.create(cfg);
|
627 | }
|
628 | db_1 = mng.get(name);
|
629 | if (global['__connection__'] === undefined) {
|
630 | global['__connection__'] = {};
|
631 | }
|
632 | if (!db_1.isConnected) { // TODO 需要进行连接池的管理
|
633 | global['__connection__'][name] = db_1.connect();
|
634 | }
|
635 | return [4 /*yield*/, global['__connection__'][name].then(function (connection) { return __awaiter(_this, void 0, void 0, function () {
|
636 | var out;
|
637 | return __generator(this, function (_a) {
|
638 | switch (_a.label) {
|
639 | case 0:
|
640 | xassert(db_1.isConnected);
|
641 | return [4 /*yield*/, callback(connection)
|
642 | // await db.close() // typeorm没有进行连接池的管理不能进行销毁
|
643 | ];
|
644 | case 1:
|
645 | out = _a.sent();
|
646 | // await db.close() // typeorm没有进行连接池的管理不能进行销毁
|
647 | resolve(out);
|
648 | return [2 /*return*/];
|
649 | }
|
650 | });
|
651 | }); }).catch(function (err) { return __awaiter(_this, void 0, void 0, function () {
|
652 | return __generator(this, function (_a) {
|
653 | // await db.close()
|
654 | xthrow(err, reject, { cfg: cfg });
|
655 | return [2 /*return*/];
|
656 | });
|
657 | }); })];
|
658 | case 2:
|
659 | _a.sent();
|
660 | return [3 /*break*/, 4];
|
661 | case 3:
|
662 | err_3 = _a.sent();
|
663 | xthrow(err_3, reject, { cfg: cfg });
|
664 | return [3 /*break*/, 4];
|
665 | case 4: return [2 /*return*/];
|
666 | }
|
667 | });
|
668 | }); })];
|
669 | });
|
670 | });
|
671 | }
|
672 | // 创建XBaseEntity对象并且自动赋值前端请求的赋值数据
|
673 | function xnew(TYPE, param) {
|
674 | var args = [];
|
675 | for (var _i = 2; _i < arguments.length; _i++) {
|
676 | args[_i - 2] = arguments[_i];
|
677 | }
|
678 | // 泛型实现类似这个功能
|
679 | // asset = new AlilangAsset()
|
680 | // getRepository(AlilangAsset).merge(asset, param as any)
|
681 | // AlilangAsset.merge(asset, param as any)
|
682 | // return asset
|
683 | var obj = new TYPE();
|
684 | if (_.isEmpty(param)) {
|
685 | return obj;
|
686 | }
|
687 | var repo = typeorm_1.getRepository(TYPE);
|
688 | repo.merge.apply(repo, [obj, param].concat(args));
|
689 | return obj;
|
690 | }
|
691 | // 查询构造器易用性封装
|
692 | function xquery(connect, TYPE, alias) {
|
693 | return connect.getRepository(TYPE).createQueryBuilder(alias);
|
694 | }
|
695 | // 分页查询获取总数以及原始记录数据
|
696 | function xcount(sql, page, size) {
|
697 | return __awaiter(this, void 0, void 0, function () {
|
698 | var _a, count, rows;
|
699 | return __generator(this, function (_b) {
|
700 | switch (_b.label) {
|
701 | case 0:
|
702 | xassert(page >= 1);
|
703 | return [4 /*yield*/, Promise.all([
|
704 | sql.getCount(),
|
705 | sql.offset((page - 1) * size).limit(size).getRawMany()
|
706 | ])];
|
707 | case 1:
|
708 | _a = _b.sent(), count = _a[0], rows = _a[1];
|
709 | return [2 /*return*/, [rows, count]];
|
710 | }
|
711 | });
|
712 | });
|
713 | }
|
714 | // 路由参数的修饰符配置
|
715 | // TODO 更多接口相关参数的配置扩展,例如:是否支持JSONP
|
716 | function xroute(param) {
|
717 | // 缺省值处理
|
718 | param = xassign({ name: '', desc: '', path: '', auth: true }, param);
|
719 | return function (target, propertyKey, descriptor) {
|
720 | var _this = this;
|
721 | // TODO 注入到类实例定义中进行全局引用动态类的特性添加(trait功能的动态实现)
|
722 | // 动态绑定路由类实例的上下文属性
|
723 | target.prototype.context = function () {
|
724 | return {
|
725 | param: param,
|
726 | // 是否登录的鉴权方法统一框架层面上的处理实现,此处仅仅是通用接口的约束的定义。
|
727 | auth: function () { return __awaiter(_this, void 0, void 0, function () {
|
728 | var auth, _a;
|
729 | return __generator(this, function (_b) {
|
730 | switch (_b.label) {
|
731 | case 0:
|
732 | if (!(param && param.auth)) return [3 /*break*/, 2];
|
733 | auth = xgot(YAuth);
|
734 | _a = xassert;
|
735 | return [4 /*yield*/, auth.getLoginStatus()];
|
736 | case 1:
|
737 | _a.apply(void 0, [_b.sent(), ERR$UNAUTHORIZED]);
|
738 | _b.label = 2;
|
739 | case 2: return [2 /*return*/];
|
740 | }
|
741 | });
|
742 | }); }
|
743 | };
|
744 | };
|
745 | };
|
746 | }
|
747 | // 完全没有必要的多余定义,需要通过MOCK定义进行细节数据类型的显性定义处理逻辑验证。
|
748 | // // 基本数据类型的规范扩展定义,方便API接口的定义以及形参自动验证合法性,并且与数据库数据类型保持一致。
|
749 | // type INT = number // 有符号整数
|
750 | // type UINT = number // 无符号整数
|
751 | // type DECIMAL = number // 精确小数
|
752 | // type FLOAT = number // 单精度浮点数(不精确小数)
|
753 | // type DOUBLE = number// 双精度浮点数(不精确小数)
|
754 | // type BOOL = boolean
|
755 | // type STR = string
|
756 | // type DATE = string // 年月日 '2017-06-25'
|
757 | // type TIME = string // 时分秒 '00:00:00'
|
758 | // type DATETIME = string // 年月日时分秒 '2017-06-25 00:00:00'
|
759 | // 模拟数据模板定义使用教程 http://mockjs.com/0.1/#%E6%95%B0%E6%8D%AE%E5%8D%A0%E4%BD%8D%E7%AC%A6%E5%AE%9A%E4%B9%89%20DPD
|
760 | function xmock(rules) {
|
761 | return mockjs.mock(rules);
|
762 | }
|
763 | function xrandom(name, data) {
|
764 | var _a;
|
765 | mockjs.Random.extend((_a = {},
|
766 | _a[name] = function () {
|
767 | var args = [];
|
768 | for (var _i = 0; _i < arguments.length; _i++) {
|
769 | args[_i] = arguments[_i];
|
770 | }
|
771 | xassert(data.length > 0);
|
772 | if (data.length == 1)
|
773 | return data[0];
|
774 | var max = data.length - 1;
|
775 | var idx = xmock("@int(0," + max + ")");
|
776 | return data[idx];
|
777 | },
|
778 | _a));
|
779 | }
|
780 | // 扩展一些预定义bxjs的基础随机方法或者覆盖一些mockjs中的方法
|
781 | mockjs.Random.extend({
|
782 | // bxjs表定义的主键统一定义(约定系统中为字符串7-14字节长度算法)
|
783 | id: function () {
|
784 | var args = [];
|
785 | for (var _i = 0; _i < arguments.length; _i++) {
|
786 | args[_i] = arguments[_i];
|
787 | }
|
788 | return shortid.generate();
|
789 | },
|
790 | // 中国手机号随机生成算法(约定系统中的手机号为字符串数据类型)
|
791 | mobile: function () {
|
792 | var args = [];
|
793 | for (var _i = 0; _i < arguments.length; _i++) {
|
794 | args[_i] = arguments[_i];
|
795 | }
|
796 | var isps = [
|
797 | 134, 135, 136, 137, 138, 139, 147, 150, 151, 152, 157, 158, 159, 182, 183, 184, 187, 188, 178,
|
798 | 130, 131, 132, 145, 155, 156, 185, 186, 176,
|
799 | 133, 134, 153, 180, 181, 189, 177, 173,
|
800 | 176, 173, 177, 178, 170,
|
801 | 140, 141, 142, 143, 144, 146, 148, 149, 154
|
802 | ];
|
803 | var max = isps.length - 1;
|
804 | var idx = xmock("@int(0," + max + ")");
|
805 | var num = xmock("@int(100000000,199999999)");
|
806 | return (isps[idx] * 100000000 + num % 100000000) + '';
|
807 | },
|
808 | // 转换为缺省中文内容提示
|
809 | paragraph: function () {
|
810 | var args = [];
|
811 | for (var _i = 0; _i < arguments.length; _i++) {
|
812 | args[_i] = arguments[_i];
|
813 | }
|
814 | switch (args.length) {
|
815 | case 0:
|
816 | return xmock('@cparagraph');
|
817 | case 1:
|
818 | return xmock("@cparagraph(" + args[0] + ")");
|
819 | case 2:
|
820 | return xmock("@cparagraph(" + args[0] + "," + args[1] + ")");
|
821 | default:
|
822 | xassert(false);
|
823 | }
|
824 | },
|
825 | sentence: function () {
|
826 | var args = [];
|
827 | for (var _i = 0; _i < arguments.length; _i++) {
|
828 | args[_i] = arguments[_i];
|
829 | }
|
830 | switch (args.length) {
|
831 | case 0:
|
832 | return xmock('@csentence');
|
833 | case 1:
|
834 | return xmock("@csentence(" + args[0] + ")");
|
835 | case 2:
|
836 | return xmock("@csentence(" + args[0] + "," + args[1] + ")");
|
837 | default:
|
838 | xassert(false);
|
839 | }
|
840 | },
|
841 | title: function () {
|
842 | var args = [];
|
843 | for (var _i = 0; _i < arguments.length; _i++) {
|
844 | args[_i] = arguments[_i];
|
845 | }
|
846 | switch (args.length) {
|
847 | case 0:
|
848 | return xmock('@ctitle');
|
849 | case 1:
|
850 | return xmock("@ctitle(" + args[0] + ")");
|
851 | case 2:
|
852 | return xmock("@ctitle(" + args[0] + "," + args[1] + ")");
|
853 | default:
|
854 | xassert(false);
|
855 | }
|
856 | },
|
857 | });
|
858 | // laravel风格JSON对象验证器封装,详细文档见 https://github.com/skaterdav85/validatorjs
|
859 | function xcheck(param, rules, messages) {
|
860 | var obj = new validatorjs(param, rules);
|
861 | if (obj.fails()) {
|
862 | xthrow(ERR$PARAM, obj.errors);
|
863 | }
|
864 | }
|
865 | // 【IoC容器管理】应用层的插件实现类绑定到BXJS统一注册的标准插件的映射关系在全局容器实例中注册
|
866 | function xbind(TYPE) {
|
867 | var o = new TYPE();
|
868 | return xcontainer.bind(o.id).to(require("@app/plugins/" + o.id).default);
|
869 | }
|
870 | // 【IoC容器管理】框架或应用依赖标准规范接口插件的类实例获取方法
|
871 | function xgot(TYPE) {
|
872 | var o = new TYPE();
|
873 | return xcontainer.get(o.id);
|
874 | }
|
875 | // 同步系统命令调用执行
|
876 | function xcmd() {
|
877 | var args = [];
|
878 | for (var _i = 0; _i < arguments.length; _i++) {
|
879 | args[_i] = arguments[_i];
|
880 | }
|
881 | return __awaiter(this, void 0, void 0, function () {
|
882 | var options, cmd, ret, err_4;
|
883 | return __generator(this, function (_a) {
|
884 | switch (_a.label) {
|
885 | case 0:
|
886 | _a.trys.push([0, 1, , 3]);
|
887 | options = {};
|
888 | options.cwd = options.cwd || process.env.__ctxPath || process.cwd();
|
889 | xassert(_.isArray(args) && args.length > 0);
|
890 | cmd = args.shift();
|
891 | ret = cross_spawn.sync(cmd, args, xassign({ stdio: 'inherit' }, options));
|
892 | xassert(ret.status === 0, ERR$UNKNOWN, ret);
|
893 | return [2 /*return*/, ret];
|
894 | case 1:
|
895 | err_4 = _a.sent();
|
896 | return [4 /*yield*/, xwarn(err_4)];
|
897 | case 2:
|
898 | _a.sent();
|
899 | xthrow(err_4);
|
900 | return [3 /*break*/, 3];
|
901 | case 3: return [2 /*return*/];
|
902 | }
|
903 | });
|
904 | });
|
905 | }
|
906 | // 对于数组嵌套回调函数的nodejs异步处理方法的统一封装
|
907 | function xmap(values, callack) {
|
908 | return __awaiter(this, void 0, void 0, function () {
|
909 | return __generator(this, function (_a) {
|
910 | xassert(_.isArray(values) && _.isFunction(callack));
|
911 | return [2 /*return*/, Promise.all(values.map(callack))];
|
912 | });
|
913 | });
|
914 | }
|
915 | // Refer to document: https://help.aliyun.com/document_detail/62670.html
|
916 | // 获取ACM配置信息接口的统一封装
|
917 | function xacm(group, id) {
|
918 | return __awaiter(this, void 0, void 0, function () {
|
919 | var cfg, acm;
|
920 | var _this = this;
|
921 | return __generator(this, function (_a) {
|
922 | cfg = xconfig("plugins.acm");
|
923 | xassert(group && cfg && cfg[group], ERR$CONFIG, { cfg: cfg });
|
924 | acm = new ACMClient(cfg[group]);
|
925 | return [2 /*return*/, new Promise(function (resolve, reject) { return __awaiter(_this, void 0, void 0, function () {
|
926 | return __generator(this, function (_a) {
|
927 | try {
|
928 | co(function () {
|
929 | var content, err_5;
|
930 | return __generator(this, function (_a) {
|
931 | switch (_a.label) {
|
932 | case 0:
|
933 | _a.trys.push([0, 2, , 3]);
|
934 | group = group + ':' + global['__env__']; // 补上环境后缀支持各种开发环境的个性化配置
|
935 | return [4 /*yield*/, acm.getConfig(id, group)];
|
936 | case 1:
|
937 | content = _a.sent();
|
938 | xassert(content, ERR$CONFIG, { id: id, group: group });
|
939 | resolve(content);
|
940 | return [3 /*break*/, 3];
|
941 | case 2:
|
942 | err_5 = _a.sent();
|
943 | xthrow(err_5, reject, { id: id, group: group, cfg: cfg[group] });
|
944 | return [3 /*break*/, 3];
|
945 | case 3: return [2 /*return*/];
|
946 | }
|
947 | });
|
948 | });
|
949 | }
|
950 | catch (err) {
|
951 | xthrow(err, reject, { id: id, group: group, cfg: cfg[group] });
|
952 | }
|
953 | return [2 /*return*/];
|
954 | });
|
955 | }); })];
|
956 | });
|
957 | });
|
958 | }
|
959 | if (!global['__env__']) {
|
960 | global['__env__'] = 'local'; // local,daily,pre,gray,prod 在统一入口处自动识别配置(目前暂不支持gray配置尚未开发无法自动识别)
|
961 | }
|
962 | global['__config__'] = undefined;
|
963 | global['__session__'] = {};
|
964 | global['__cache__'] = {};
|
965 | global['__user__'] = {};
|
966 | global['__user_agent__'] = undefined;
|
967 | global['__client_ip__'] = undefined;
|
968 | global['__redirect_url__'] = undefined;
|
969 | global['__request_cookies__'] = {};
|
970 | global['__respond_cookies__'] = {};
|
971 | global['xconnect'] = xconnect;
|
972 | global['xnew'] = xnew;
|
973 | global['xquery'] = xquery;
|
974 | global['xcount'] = xcount;
|
975 | global['xassign'] = xassign;
|
976 | global['xconfig'] = xconfig;
|
977 | global['xthrow'] = xthrow;
|
978 | global['xassert'] = xassert;
|
979 | global['xerror'] = xerror;
|
980 | global['xroot'] = xroot;
|
981 | global['xstack'] = xstack;
|
982 | global['xwarn'] = xwarn;
|
983 | global['xlog'] = xlog;
|
984 | global['xpost'] = xpost;
|
985 | global['xget'] = xget;
|
986 | global['xsleep'] = xsleep;
|
987 | global['xredirect'] = xredirect;
|
988 | global['xcookie'] = xcookie;
|
989 | global['xismobile'] = xismobile;
|
990 | global['xsession'] = session_1.xsession;
|
991 | global['xuser'] = session_1.xuser;
|
992 | global['xcache'] = session_1.xcache;
|
993 | global['xroute'] = xroute;
|
994 | global['xmock'] = xmock;
|
995 | global['xrandom'] = xrandom;
|
996 | global['xcheck'] = xcheck;
|
997 | global['xcontainer'] = new inversify_1.Container(); // 全局单实例容器初始化
|
998 | global['xbind'] = xbind;
|
999 | global['xgot'] = xgot;
|
1000 | global['YAuth'] = $$.YAuth; // 全局声明认证插件规范抽象类
|
1001 | global['xcmd'] = xcmd;
|
1002 | global['xmap'] = xmap;
|
1003 | global['xacm'] = xacm;
|
1004 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFzZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbImJhc2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSxpQkF5d0JBOztBQXp3QkEsT0FBTyxDQUFDLEdBQUcsQ0FBQyw0QkFBNEIsR0FBRyxHQUFHLENBQUE7QUFDOUMsNEJBQXlCO0FBQ3pCLHVDQUFtQztBQUNuQyx5Q0FBNkc7QUFDN0cscUNBQWlEO0FBQ2pELDhCQUErQjtBQUUvQixJQUFNLElBQUksR0FBRyxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUE7QUFDNUIsSUFBTSxnQkFBZ0IsR0FBRyxPQUFPLENBQUMsb0JBQW9CLENBQUMsQ0FBQTtBQUN0RCxJQUFNLE1BQU0sR0FBRyxPQUFPLENBQUMsUUFBUSxDQUFDLENBQUE7QUFDaEMsSUFBTSxZQUFZLEdBQUcsT0FBTyxDQUFDLGVBQWUsQ0FBQyxDQUFBO0FBQzdDLElBQU0sS0FBSyxHQUFHLE9BQU8sQ0FBQyxZQUFZLENBQUMsQ0FBQTtBQUNuQyxJQUFNLENBQUMsR0FBRyxPQUFPLENBQUMsUUFBUSxDQUFDLENBQUE7QUFDM0IsSUFBTSxNQUFNLEdBQUcsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFBO0FBQ2hDLElBQU0sTUFBTSxHQUFHLE9BQU8sQ0FBQyxRQUFRLENBQUMsQ0FBQTtBQUNoQyxJQUFNLFdBQVcsR0FBRyxPQUFPLENBQUMsYUFBYSxDQUFDLENBQUE7QUFDMUMseUNBQXlDO0FBQ3pDLGlEQUFpRDtBQUNqRCxrQ0FBa0M7QUFDbEMsK0RBQStEO0FBQy9ELHNFQUFzRTtBQUN0RSw4Q0FBOEM7QUFDOUMsV0FBVztBQUNYLEtBQUs7QUFDTCxJQUFNLGFBQWEsR0FBRyxPQUFPLENBQUMsZUFBZSxDQUFDLENBQUE7QUFDOUMsSUFBTSxNQUFNLEdBQUcsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFBO0FBQ2hDLElBQU0sT0FBTyxHQUFHLE9BQU8sQ0FB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QUFDLEdBQUcsRUFBRSxDQUFDLEtBQUssQ0FBQSxDQUFDLGdCQUFnQjtBQUMzQyxNQUFNLENBQUMsTUFBTSxDQUFDLEdBQUcsSUFBSSxDQUFBO0FBQ3JCLE1BQU0sQ0FBQyxNQUFNLENBQUMsR0FBRyxJQUFJLENBQUE7QUFDckIsTUFBTSxDQUFDLE1BQU0sQ0FBQyxHQUFHLElBQUksQ0FBQSIsInNvdXJjZXNDb250ZW50IjpbInByb2Nlc3MuZW52Lk5PREVfVExTX1JFSkVDVF9VTkFVVEhPUklaRUQgPSAnMCdcbmltcG9ydCAncmVmbGVjdC1tZXRhZGF0YSdcbmltcG9ydCB7Q29udGFpbmVyfSBmcm9tICdpbnZlcnNpZnknXG5pbXBvcnQge2dldENvbm5lY3Rpb25NYW5hZ2VyLCBDb25uZWN0aW9uLCBCYXNlRW50aXR5LCBnZXRSZXBvc2l0b3J5LCBTZWxlY3RRdWVyeUJ1aWxkZXJ9IGZyb20gJ0BieGpzL3R5cGVvcm0nXG5pbXBvcnQge3hzZXNzaW9uLCB4dXNlciwgeGNhY2hlfSBmcm9tICcuL3Nlc3Npb24nXG5pbXBvcnQgKiBhcyAkJCBmcm9tICcuL3BsdWdpbnMnXG5cbmNvbnN0IHBhdGggPSByZXF1aXJlKCdwYXRoJylcbmNvbnN0IEVycm9yU3RhY2tQYXJzZXIgPSByZXF1aXJlKCdlcnJvci1zdGFjay1wYXJzZXInKVxuY29uc3QgY29va2llID0gcmVxdWlyZSgnY29va2llJylcbmNvbnN0IE1vYmlsZURldGVjdCA9IHJlcXVpcmUoJ21vYmlsZS1kZXRlY3QnKVxuY29uc3QgZmV0Y2ggPSByZXF1aXJlKCdub2RlLWZldGNoJylcbmNvbnN0IF8gPSByZXF1aXJlKCdsb2Rhc2gnKVxuY29uc3QgbW9tZW50ID0gcmVxdWlyZSgnbW9tZW50JylcbmNvbnN0IGV4dGVuZCA9IHJlcXVpcmUoJ2V4dGVuZCcpXG5jb25zdCBxdWVyeXN0cmluZyA9IHJlcXVpcmUoJ3F1ZXJ5c3RyaW5nJylcbi8vIGNvbnN0IHBhcmFtZXRlciA9IHJlcXVpcmUoJ3BhcmFtZXRlcicpXG4vLyBjb25zdCBwYXJhbWV0ZXJDaGVja0luc3RhbmNlID0gbmV3IHBhcmFtZXRlcih7XG4vLyAgICAgLy8gdHJhbnNsYXRlOiBmdW5jdGlvbiAoKSB7XG4vLyAgICAgLy8gICAgIHZhciBhcmdzID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzKTtcbi8vICAgICAvLyAgICAgLy8gQXNzdW1lIHRoZXJlIGhhdmUgSTE4bi50IG1ldGhvZCBmb3IgY29udmVydCBsYW5ndWFnZS5cbi8vICAgICAvLyAgICAgcmV0dXJuIEkxOG4udC5hcHBseShJMThuLCBhcmdzKTtcbi8vICAgICAvLyB9XG4vLyB9KVxuY29uc3QgY2lyY3VsYXJfanNvbiA9IHJlcXVpcmUoXCJjaXJjdWxhci1qc29uXCIpXG5jb25zdCBtb2NranMgPSByZXF1aXJlKCdtb2NranMnKVxuY29uc3Qgc2hvcnRpZCA9IHJlcXVpcmUoJ3Nob3J0aWQnKVxuY29uc3QgdmFsaWRhdG9yanMgPSByZXF1aXJlKCd2YWxpZGF0b3JqcycpXG5jb25zdCBjcm9zc19zcGF3biA9IHJlcXVpcmUoJ2Nyb3NzLXNwYXduJylcbmNvbnN0IEFDTUNsaWVudCA9IHJlcXVpcmUoJ2FjbS1jbGllbnQnKVxuY29uc3QgY28gPSByZXF1aXJlKCdjbycpXG5cbi8vIEZJWE1FIEhBQ0vljp/nlJ/mlrnms5VKU09O6L2s5o2i5LiN5Y+v6YCG55qEQlVH77yISkFWQeerr+S8oOadpeeahOWvjOaWh+acrOWtl+auteWGheWuueWQq+aciVxcblxcdOWtl+espuS4suS4reeahOWtl+espueUn+aIkEpTT07lrZfnrKbkuLLml6Dms5XmraPluLjop6PmnpDmiqXplJnvvIlcbmNvbnN0IHJhd19zdHJpbmdpZnkgPSBKU09OLnN0cmluZ2lmeVxuXG5mdW5jdGlvbiBuZXdfc3RyaW5naWZ5KHZhbHVlOiBhbnksIHJlcGxhY2VyPzogKGtleTogc3RyaW5nLCB2YWx1ZTogYW55KSA9PiBhbnksXG4gICAgICAgICAgICAgICAgICAgICAgIHNwYWNlPzogc3RyaW5nIHwgbnVtYmVyKTogc3RyaW5nIHtcbiAgICBsZXQgb3V0ID0gcmF3X3N0cmluZ2lmeSh2YWx1ZSwgcmVwbGFjZXIsIHNwYWNlKVxuICAgIGlmIChfLmlzU3RyaW5nKG91dCkpIHtcbiAgICAgICAgb3V0ID0gb3V0LnJlcGxhY2UoL1xcXFxuL2csICdcXFxcXFxcXG4nKVxuICAgICAgICAgICAgLnJlcGxhY2UoL1xcXFx0L2csICdcXFxcXFxcXHQnKVxuICAgICAgICAgICAgLnJlcGxhY2UoL1xcXFx1L2csICdcXFxcXFxcXHUnKSAvL0pBVkHnq6/ov5Tlm57nmoR1bmljb2Rl5a2X56ym6L2s5LmJ5aSE55CGXG4gICAgfVxuICAgIHJldHVybiBvdXRcbn1cblxuSlNPTi5zdHJpbmdpZnkgPSBuZXdfc3RyaW5naWZ5IGFzIGFueVxuXG4vLyB0cy1ub2Rl5pys5Zyw6LCD6K+V6ZyA6KaB5Yqg6L295a+55bqU55qE5rqQ5Luj56CB5ZCO57yA5ZCN56ewXG5leHBvcnQgZnVuY3Rpb24gZ2V0X3N1ZmZpeF90c19vcl9qcygpIHtcbiAgICBpZiAoZ2xvYmFsWydfX2Vudl9fJ10gPT0gJ2xvY2FsJyAmJiAhL15cXC9jb2RlXFwvbm9kZV9tb2R1bGVzLy50ZXN0KF9fZGlybmFtZSkpIHtcbiAgICAgICAgcmV0dXJuICd0cydcbiAgICB9IGVsc2Uge1xuICAgICAgICByZXR1cm4gJ2pzJ1xuICAgIH1cbn1cblxuLy8g5YeG56Gu5a6a5L2N6ZSZ6K+v56CB5L2N572u77yM6Ze05o6l5b6X5Yiw5Ye95pWw6LCD55So5L2N572u5Zyw5Z2A5L+h5oGv77yM57uT5ZCI56ym5Y+35oql6KGo55qE5q2j56Gu6Kej5p6Q5aSE55CG5a6M576O5b6X5Yiw6ZSZ6K+v5a6a5L2N5L+h5oGv77yM5YeG56Gu5Luj56CB6LCD6K+V44CCXG5mdW5jdGlvbiBfX2dldF9iYXNlX2Z1bmNfY2FsbGVyX3NvdXJjZV9wb3NpdGlvbihwb3NpdGlvbjogbnVtYmVyID0gMykge1xuICAgIHRyeSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcigpXG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgIGxldCBvdXQgPSBFcnJvclN0YWNrUGFyc2VyLnBhcnNlKGVycilcbiAgICAgICAgbGV0IGlkeCA9IDBcbiAgICAgICAgLy8g5om+5Yiw56ys5LqM5LiqVFPmlofku7bnmoTmiafooYzkvY3nva5cbiAgICAgICAgbGV0IGZpbmRfdHNfc3VmaXhfZmlsZV9jb3VudCA9IDBcbiAgICAgICAgZm9yICg7IGlkeCA8IG91dC5sZW5ndGg7IGlkeCsrKSB7XG4gICAgICAgICAgICBpZiAoL1xcLnRzJC8udGVzdChvdXRbaWR4XS5maWxlTmFtZSkpIHtcbiAgICAgICAgICAgICAgICBmaW5kX3RzX3N1Zml4X2ZpbGVfY291bnQgKz0gMVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGZpbmRfdHNfc3VmaXhfZmlsZV9jb3VudCA9PSBwb3NpdGlvbikge1xuICAgICAgICAgICAgICAgIGJyZWFrXG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGZpbmRfdHNfc3VmaXhfZmlsZV9jb3VudCA9PSBwb3NpdGlvbikge1xuICAgICAgICAgICAgcmV0dXJuICdbJyArIG91dFtpZHhdWydmaWxlTmFtZSddICsgJzonICsgb3V0W2lkeF1bJ2xpbmVOdW1iZXInXSArICddJ1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gVE9ETyDpnIDopoHlrprkvY3kuLrku4DkuYjosIPnlKjmoIjml6Dms5Xmib7liLDlr7nlupTnmoTkvY3nva7lh7rnjrDotornlYzvvJ/vvJ9cbiAgICAgICAgICAgIC8vIGNvbnNvbGUuZXJyb3IoZXJyKVxuICAgICAgICAgICAgY29uc29sZS5lcnJvcihjaXJjdWxhcl9qc29uLnN0cmluZ2lmeShvdXQsIG51bGwsIDQpXG4gICAgICAgICAgICAgICAgLnJlcGxhY2UoL1xcci9nLCAnJykucmVwbGFjZSgvXFxuL2csICcnKSlcbiAgICAgICAgICAgIHJldHVybiAnIydcbiAgICAgICAgfVxuXG4gICAgfVxufVxuXG4vLyDojrflj5blvILluLjosIPnlKjmoIjnlKjkuo7ovoXliqnplJnor6/mj5DnpLrlrprkvY1cbmV4cG9ydCBmdW5jdGlvbiB4c3RhY2soZXJyLCBjb21wYWN0ID0gdHJ1ZSkge1xuICAgIHRyeSB7XG4gICAgICAgIC8vIFRPRE8g5LyY5YyW6KOB5Ymq5LiA5Lqb5peg55So5L+h5oGv5YeP5bCR5pel5b+X5bC65a+45pu05Yqg5L6/5LqO5Lq65bel5YiG5p6Q5aSE55CGXG4gICAgICAgIGxldCBzdGFjayA9IEVycm9yU3RhY2tQYXJzZXIucGFyc2UoZXJyKVxuICAgICAgICBpZiAoY29tcGFjdCkge1xuICAgICAgICAgICAgbGV0IHNvdXJjZXM6IHN0cmluZ1tdID0gW11cbiAgICAgICAgICAgIGZvciAobGV0IHYgb2Ygc3RhY2spIHtcbiAgICAgICAgICAgICAgICBzb3VyY2VzLnB1c2goYCR7dlsnZmlsZU5hbWUnXX06JHt2WydsaW5lTnVtYmVyJ119YClcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBzb3VyY2VzXG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHN0YWNrXG4gICAgfSBjYXRjaCAoZXJyMSkge1xuICAgICAgICBsZXQgc291cmNlID0gX19nZXRfYmFzZV9mdW5jX2NhbGxlcl9zb3VyY2VfcG9zaXRpb24oKVxuICAgICAgICByZXR1cm4gYGludmFsaWQgZXJyb3IgaW5wdXQgcGFyYW0gKCR7c291cmNlfSlgXG4gICAgfVxufVxuXG4vLyAvLyDplJnor6/moIjnmoTpgJLlvZLltYzlpZfmoLzlvI/mmL7npLrmlbDmja7nu5PmnoTlrprkuYnvvIhwYXJhbeW1jOWll+aJvuWIsOacgOWQjuS4gOS4qm1zZ+eahEpTT07op6PmnpDor63ms5XplJnor6/lsLHmmK/plJnor6/pk77nmoTljp/lp4vplJnor6/lj5HnlJ/kvY3nva7vvIlcbi8vIGxldCB4ID0ge1xuLy8gICAgIFwiY29kZVwiOiBcIlVOS05PV05cIixcbi8vICAgICBcIm1zZ1wiOiBcIuacquefpemUmeivr1wiLFxuLy8gICAgIFwicGFyYW1cIjoge1xuLy8gICAgICAgICBcIm1zZ1wiOiBcIuaCqOi+k+WFpeeahOeUqOaIt+WQjeaIluWvhueggemUmeivr++8jOivt+mHjeaWsOeZu+W9lSAoRXJyb3JDb2RlOiAxMDA1LCB1cmw6IGh0dHBzOi8vbG9naW4uYWxpYmFiYS1pbmMuY29tL2F1dGhvcml6ZS9sb2dpbi5kbylcIlxuLy8gICAgIH0sXG4vLyAgICAgXCJzdGFja1wiOiBcIltcXFwiL1VzZXJzL2NodWppbmdodWkvRGVza3RvcC93b3JrL3hqcy9ieGpzL2ZyYW1ld29yay9iYXNlLnRzOjExMFxcXCIsXFxcIi9Vc2Vycy9jaHVqaW5naHVpL0Rlc2t0b3Avd29yay94anMvYnhqcy9hcHAvZW50cmllcy93ZWIvbW9iaWxlL21lZXRpbmctcm9vbS12aXNpdC50czoxNjFcXFwiLFxcXCIvVXNlcnMvY2h1amluZ2h1aS9EZXNrdG9wL3dvcmsveGpzL2J4anMvYXBwL2VudHJpZXMvd2ViL21vYmlsZS9tZWV0aW5nLXJvb20tdmlzaXQuanM6NDBcXFwiLFxcXCIvVXNlcnMvY2h1amluZ2h1aS9EZXNrdG9wL3dvcmsveGpzL2J4anMvYXBwL2VudHJpZXMvd2ViL21vYmlsZS9tZWV0aW5nLXJvb20tdmlzaXQuanM6MjFcXFwiLFxcXCIvVXNlcnMvY2h1amluZ2h1aS9EZXNrdG9wL3dvcmsveGpzL2J4anMvYXBwL2VudHJpZXMvd2ViL21vYmlsZS9tZWV0aW5nLXJvb20tdmlzaXQuanM6MTNcXFwiLFxcXCJpbnRlcm5hbC9wcm9jZXNzL25leHRfdGljay5qczoxODhcXFwiXVwiLFxuLy8gfVxuXG4vLyDlr7nkuo7lvILluLjlhoXlrrnnmoTmoLzlvI/ljJblj4LmlbDop6PmnpDlpITnkIbmiJDkuLrlm5vlhYPnu4Rjb2RlL21zZy9wYXJhbS9zdGFja1xuZXhwb3J0IGZ1bmN0aW9uIHhlcnJvcihlcnIsIF9fcGFyYW0/OiBhbnkpIHtcbiAgICB4YXNzZXJ0KGVyciBpbnN0YW5jZW9mIEVycm9yKVxuICAgIHRyeSB7XG4gICAgICAgIC8vIOagh+WHhumUmeivr+eahOe7n+S4gOi9rOaNouWkhOeQhlxuICAgICAgICBsZXQgZGF0YTogYW55ID0gSlNPTi5wYXJzZShlcnIubWVzc2FnZSlcbiAgICAgICAgaWYgKGRhdGEuY29kZSAmJiBkYXRhLm1zZyAmJiBFUlJPUlNbZGF0YS5jb2RlXSkge1xuICAgICAgICAgICAgcmV0dXJuIGRhdGFcbiAgICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAvLyBpZ25vcmUgcGFyc2UgZXJyb3JcbiAgICB9XG4gICAgLy8g6Z2e5qCH5YeG6ZSZ6K+v55qE57uf5LiA5qC85byP6L2s5o2i5aSE55CGXG4gICAgbGV0IG1zZyA9IEVSUk9SU1tFUlIkVU5LTk9XTl1bJ3poJ10gLy8gVE9ETyDplJnor6/noIHlpJror63oqIDlm57kvKDliLDlrqLmiLfnq6/pl67pophcbiAgICBsZXQgY29kZSA9IEVSUiRVTktOT1dOXG4gICAgbGV0IHBhcmFtOiBhbnkgPSB7bXNnOiBlcnIubWVzc2FnZSwgcGFyYW06IF9fcGFyYW19IC8vIOeUqOaIt+iHquWumuS5ieeahOmUmeivr+WPguaVsOS/oeaBryBtc2fkuLrpnZ7plJnor6/noIFKU09O5Zub5YWD57uE5bCx5piv5bWM5aWX55qE57uI5q2i5p2h5Lu244CCXG4gICAgbGV0IHN0YWNrID0geHN0YWNrKGVycilcbiAgICBsZXQgZGF0YSA9IHttc2csIGNvZGUsIHBhcmFtLCBzdGFja31cbiAgICByZXR1cm4gZGF0YVxufVxuXG4vLyDnlKjkuo7ojrflj5bplJnor6/moIjnmoRyb290IGNhdXNl5qC55pys5Y6f5Zug77yI56ys5LiA5Liq6KKr5oum5oiq55qE6ZSZ6K+v5Y+R55Sf5L2N572u77yJXG5leHBvcnQgZnVuY3Rpb24geHJvb3QoZXJyOiBFcnJvcikge1xuICAgIHhhc3NlcnQoZXJyIGluc3RhbmNlb2YgRXJyb3IpXG4gICAgbGV0IHttc2csIHBhcmFtLCBjb2RlLCBzdGFja30gPSB4ZXJyb3IoZXJyKVxuXG4gICAgLy8g6YCS5b2S6YGN5Y6G5om+5Yiw6ZSZ6K+v6ZO+55qEcm9vdCBjYXVzZVxuICAgIGZvciAoOyBwYXJhbSAmJiBwYXJhbS5tc2c7KSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBsZXQganNvbjogYW55ID0gSlNPTi5wYXJzZShwYXJhbS5tc2cpXG4gICAgICAgICAgICBwYXJhbSA9IGpzb24ucGFyYW1cbiAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICBtc2cgPSBwYXJhbS5tc2dcbiAgICAgICAgICAgIGNvZGUgPSBwYXJhbS5jb2RlXG4gICAgICAgICAgICBzdGFjayA9IHBhcmFtLnN0YWNrXG4gICAgICAgICAgICBwYXJhbSA9IHBhcmFtLnBhcmFtXG4gICAgICAgICAgICBicmVha1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiB7bXNnLCBjb2RlLCBwYXJhbSwgc3RhY2t9XG59XG5cbi8vIFRPRE8g5oql6ZSZ5aSE55CG77yI5pi+56S66Zeu6aKY5Y+N6aaI6IGU57O75Lq65L+h5oGv77yJXG4vLyDlsIbmnKrlpITnkIbnmoTplJnor6/kuIrmipvnmoTlvILluLjpk77orrDlvZXkuIvmnaXnlKjkuo7nsr7lh4bov73ouKrku6PnoIHnmoTmiafooYzov4fnqIvvvIjku6Xlj4rlh4bnoa7ojrflj5bliLDmoLnoioLngrnnmoTplJnor6/noIHvvIlcbi8vIOWvueS6jnByb21pc2XlvILmraXlm57osIPnmoTnu5/kuIDlh7rplJnlpITnkIblhpnms5Xlrp7kvotcbi8vIGV4cG9ydCBmdW5jdGlvbiBsb2dpbih1c2VybmFtZTogc3RyaW5nLCBwYXNzd29yZDogc3RyaW5nKSB7XG4vLyAgICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbi8vICAgICAgICAgY28oZnVuY3Rpb24qICgpIHtcbi8vICAgICAgICAgICAgIGxldCB1c2VyID0geWllbGQgYnVjLm9hdXRoY2xpZW50LmxvZ2luKHVzZXJuYW1lLCBwYXNzd29yZClcbi8vICAgICAgICAgICAgIHJlc29sdmUodXNlcilcbi8vICAgICAgICAgfSkuY2F0Y2goYXN5bmMgZnVuY3Rpb24gKGVycikge1xuLy8gICAgICAgICAgICAgeHRocm93KGVyciwgcmVqZWN0KVxuLy8gICAgICAgICB9KVxuLy8gICAgIH0pXG4vLyB9XG5leHBvcnQgZnVuY3Rpb24geHRocm93KGNvZGU6IHN0cmluZyB8IEVycm9yID0gRVJSJFVOS05PV04sIHBhcmFtOiBhbnkgPSB1bmRlZmluZWQsIHJlamVjdF9wYXJhbTogYW55ID0gdW5kZWZpbmVkKSB7XG4gICAgLy8gcHJvbWlzZeS4rei/m+ihjHJlamVjdOW8guW4uOWkhOeQhueahOaKm+WHuumUmeivr+aWueazleeahOW9ouWPgumAu+i+kemihOWkhOeQhui9rOaNouOAglxuICAgIGxldCByZWplY3Q6IGFueSA9IF8uaXNGdW5jdGlvbihwYXJhbSkgPyBwYXJhbSA6IHVuZGVmaW5lZFxuICAgIGlmIChyZWplY3QpIHBhcmFtID0gcmVqZWN0X3BhcmFtXG4gICAgbGV0IGRhdGE6IGFueSA9IHt9XG4gICAgbGV0IHNvdXJjZSA9IF9fZ2V0X2Jhc2VfZnVuY19jYWxsZXJfc291cmNlX3Bvc2l0aW9uKClcblxuICAgIGlmIChjb2RlIGluc3RhbmNlb2YgRXJyb3IpIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGRhdGEgPSBKU09OLnBhcnNlKGNvZGUubWVzc2FnZSlcbiAgICAgICAgICAgIC8vIOWwhumAj+S8oOS4iuaKm+eahOmUmeivr+eahOi3r+W+hOS/oeaBr+WSjOmZhOWKoOWPguaVsOS5n+iusOW9leS4i+adpeaWueS+v+aPkOS+m+WujOaVtOW6lOeUqOWghuagiOS/oeaBr+i+heWKqeiwg+ivleS4muWKoemAu+i+kVxuICAgICAgICAgICAgaWYgKCFfLmlzQXJyYXkoZGF0YS5zdGFjaykpIHtcbiAgICAgICAgICAgICAgICBkYXRhLnN0YWNrID0gW11cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGRhdGEuc3RhY2sucHVzaChzb3VyY2UpXG4gICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgLy8gaWdub3JlXG4gICAgICAgIH1cbiAgICAgICAgLy8g5qCH5YeG6ZSZ6K+v55u05o6l5LiK5oqb5aSE55CGXG4gICAgICAgIGlmIChkYXRhLmNvZGUgJiYgZGF0YS5tc2cgJiYgRVJST1JTW2RhdGEuY29kZV0pIHtcbiAgICAgICAgICAgIC8vIOa1i+ivleS4pemHjUJVRyByZWplY3Tlh73mlbDnsbvlnovooajovr7lvI/kuLrlgYflv4XpobvopoHnlKhsb2Rhc2jliKTlrprmmK/lkKbkuLrlh73mlbBcbiAgICAgICAgICAgIGlmIChfLmlzRnVuY3Rpb24ocmVqZWN0KSkge1xuICAgICAgICAgICAgICAgIC8vIHByb21pc2Xlm57osIPkuK3ov5vooYzmipvplJnor6/lpITnkIZcbiAgICAgICAgICAgICAgICBsZXQgZXJyID0gbmV3IEVycm9yKEpTT04uc3RyaW5naWZ5KGRhdGEpKVxuICAgICAgICAgICAgICAgIHJlamVjdChlcnIpXG4gICAgICAgICAgICAgICAgcmV0dXJuXG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihKU09OLnN0cmluZ2lmeShkYXRhKSlcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICAvLyDlsIbpnZ7moIflh4bplJnor6/ovazmjaLkuLrmoIflh4bplJnor6/lkI7lho3kuIrmipvlpITnkIZcbiAgICAgICAgZGF0YSA9IHhlcnJvcihjb2RlLCBwYXJhbSlcbiAgICAgICAgZGF0YS5jb2RlID0gRVJSJFVOS05PV05cbiAgICAgICAgZGF0YS5tc2cgPSBFUlJPUlNbRVJSJFVOS05PV05dWyd6aCddIC8vIEZJWE1FIFRPRE8g6ZSZ6K+v56CB55qE5aSa6K+t6KiA5aSE55CG6L2s5o2i77yB77yBXG4gICAgICAgIGRhdGEucGFyYW0gPSB7bXNnOiBjb2RlLm1lc3NhZ2UsIHBhcmFtLCBzdGFjazogW3NvdXJjZV19XG4gICAgfSBlbHNlIHtcbiAgICAgICAgLy8g5a+55LqO5bi46YeP5a6a5LmJ6ZSZ6K+v55qE57uf5LiA5qC85byP5YyW5aSE55CGXG4gICAgICAgIGRhdGEgPSB7Y29kZSwgbXNnOiBnbG9iYWxbJ0VSUk9SUyddW2NvZGUgYXMgc3RyaW5nXVsnemgnXSwgcGFyYW0sIHN0YWNrOiBbc291cmNlXX1cbiAgICB9XG5cbiAgICAvLyDlr7nkuo7mmK/lkKZwcm9taXNl5Zy65pmv5LiL55qE6ZSZ6K+v5LiK5oqb6L+b6KGM5q2j56Gu55qE6L2s5o2i5aSE55CGXG4gICAgaWYgKF8uaXNGdW5jdGlvbihyZWplY3QpKSB7XG4gICAgICAgIC8vIHByb21pc2Xlm57osIPkuK3ov5vooYzmipvplJnor6/lpITnkIZcbiAgICAgICAgcmVqZWN0KG5ldyBFcnJvcihKU09OLnN0cmluZ2lmeShkYXRhKSkpXG4gICAgfSBlbHNlIHtcbiAgICAgICAgLy8g6Z2ecHJvbWlzZeWbnuiwg+S4reW8guW4uOS8oOmAklxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoSlNPTi5zdHJpbmdpZnkoZGF0YSkpXG4gICAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24geGFzc2VydChleHByOiBhbnksIGNvZGU6IHN0cmluZyA9IEVSUiRBU1NFUlQsIHBhcmFtPzogYW55KSB7XG4gICAgbGV0IHNvdXJjZSA9IF9fZ2V0X2Jhc2VfZnVuY19jYWxsZXJfc291cmNlX3Bvc2l0aW9uKClcbiAgICBsZXQgc3RhY2sgPSBbc291cmNlXVxuICAgIGlmICghZXhwcikgdGhyb3cgbmV3IEVycm9yKEpTT04uc3RyaW5naWZ5KHtjb2RlLCBtc2c6IGdsb2JhbFsnRVJST1JTJ11bY29kZV1bJ3poJ10sIHBhcmFtLCBzdGFja30pKVxuICAgIHJldHVybiBleHByXG59XG5cbi8vIC8vIGh0dHBzOi8vZ2l0aHViLmNvbS9ub2RlLW1vZHVsZXMvcGFyYW1ldGVyIOWPguaVsOmqjOivgeinhOWImeivpuingeatpOaWh+aho++8iGVnZ+WboumYn+W8gOWPkeeahOe7hOS7tu+8iVxuLy8gLy8g5rOo5oSP5LqL6aG577yaR0VU6YCa6L+HVVJM5Lyg6YCS55qE5Y+C5pWw6YO95piv5a2X56ym5Liy57G75Z6L5bqU6K+l5bC96YeP6YG/5YWNR0VU5Lyg6YCS5Y+C5pWw77yM6ZyA6KaB5aSa55SoUE9TVOeahEpTT07moLzlvI/kvKDpgJLlj4LmlbDlubbkuJRQT1NUTUFO5LiK6L+b6KGM6L6F5Yqp5rWL6K+V5q2j56Gu5pWw5o2u57G75Z6L5pig5bCE44CCXG4vLyBleHBvcnQgZnVuY3Rpb24geGNoZWNrKHBhcmFtOiB7IFtwcm9wTmFtZTogc3RyaW5nXTogYW55IH0sIHJ1bGVzOiB7IFtwcm9wTmFtZTogc3RyaW5nXTogYW55IH0pIHtcbi8vICAgICBsZXQgZXJyb3JzID0gcGFyYW1ldGVyQ2hlY2tJbnN0YW5jZS52YWxpZGF0ZShydWxlcywgcGFyYW0pXG4vLyAgICAgaWYgKF8uaXNFbXB0eShlcnJvcnMpKSB7XG4vLyAgICAgICAgIHJldHVybiB0cnVlXG4vLyAgICAgfSBlbHNlIHtcbi8vICAgICAgICAgeHRocm93KEVSUiRQQVJBTSwgZXJyb3JzKVxuLy8gICAgIH1cbi8vIH1cblxuZXhwb3J0IGZ1bmN0aW9uIHhsb2coLi4uYXJncykge1xuICAgIC8vIOWFvOWuueS6keerr+S7peWPiuacrOWcsOaXpeW/l+iwg+ivle+8iOino+WGs+S7u+aEj+WvueixoeeahEpTT07lrZfnrKbkuLLlhoXlrrnnmoTlrozmlbTovpPlh7rvvIlcbiAgICBsZXQgc291cmNlID0gX19nZXRfYmFzZV9mdW5jX2NhbGxlcl9zb3VyY2VfcG9zaXRpb24oKVxuICAgIGxldCBvdXRwdXQgPSBjaXJjdWxhcl9qc29uLnN0cmluZ2lmeShbLi4uYXJnc10sIG51bGwsIDQpXG4gICAgaWYgKGdsb2JhbFsnX19lbnZfXyddICE9ICdwcm9kJyAmJiAhL15cXC9jb2RlXFwvbm9kZV9tb2R1bGVzLy50ZXN0KF9fZGlybmFtZSkpIHtcbiAgICAgICAgLy8g5omT5Y2w5Yiw5o6n5Yi25Y+w5LiA5Lu95pel5b+XKOWcqOmYv+mHjOS6kemdnue6v+S4ikZD546v5aKD5LitKVxuICAgICAgICBjb25zb2xlLmxvZy5hcHBseSh1bmRlZmluZWQsIFtzb3VyY2UgKyBvdXRwdXRdKVxuICAgICAgICAvLyDlhpnml6Xlv5fmlofku7bliLAvdG1w5LiL5Li05pe25aSE55CG5LiA5LiLIFRPRE8g6ZyA6KaB5pS55Li657G75Ly8bG9nNGrnmoTmnKzlnLDml6Xlv5flupPku4XlnKjpnZ7nur/kuIrnjq/looPkvb/nlKjmlrnkvr/lvIDlj5HljZXmnLrml6XluLjmnLrlmajkuIrosIPor5XjgIJcbiAgICAgICAgY29uc3QgZnMgPSByZXF1aXJlKCdmcycpXG4gICAgICAgIGNvbnN0IGxvZ0ZpbGVQYXRoID0gcHJvY2Vzcy5lbnZbJ05PREVfTE9HRklMRSddID8gcHJvY2Vzcy5lbnZbJ05PREVfTE9HRklMRSddIDogJy90bXAvYnhqcy5sb2cnXG4gICAgICAgIGZzLmFwcGVuZEZpbGVTeW5jKGxvZ0ZpbGVQYXRoLCBzb3VyY2UgKyBvdXRwdXQgKyBcIlxcclxcblwiKVxuICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIOeUn+S6p+eOr+Wig+S4i+WPquaJk+WNsOWIsOaOp+WItuWPsOe7keWumueahFNMU+aXpeW/l+acjeWKoeWZqOS4iu+8jOW5tuS4lOmcgOimgeWOu+mZpOaOieaNouihjOS/oeaBr+WQpuWImeaJk+WNsOS8muS4jeato+W4uOOAglxuICAgICAgICBvdXRwdXQgPSBvdXRwdXQucmVwbGFjZSgvXFxyL2csICcnKS5yZXBsYWNlKC9cXG4vZywgJycpXG4gICAgICAgIGNvbnNvbGUubG9nLmFwcGx5KHVuZGVmaW5lZCwgW3NvdXJjZSArIG91dHB1dF0pXG4gICAgfVxufVxuXG4vLyAvLyDlsIbor6bnu4bplJnor6/kv6Hmga/lj4rml7blj5HpgIHliLDpkonpkonnvqTkuIrlrp7ml7blj43ppojnu5nnu7TmiqTogIVcbi8vIGF3YWl0IHh3YXJuKHtcbi8vICAgICBjb2RlLFxuLy8gICAgIC8vIFRPRE8g5aaC5L2V6K6k6K+B6YCa6L+H5LqG6I635Y+W5Yiw55So5oi35L+h5oGv5Lmf6ZyA6KaB5Y+R6YCB6L+H5Y6777yM5pa55L6/6IGU57O75a+55o6l5Lq65ZGY6L+b6KGM56uL5Yi76Zeu6aKY5aSE55CG5Y+N6aaI44CCXG4vLyAgICAgbWVzc2FnZSxcbi8vICAgICBzdGFjayxcbi8vICAgICBwYXJhbSxcbi8vIH0pXG4vLyDlsIbor6bnu4bplJnor6/kv6Hmga/lj4rml7blj5HpgIHliLDpkonpkonnvqTkuIrlrp7ml7blj43ppojnu5nnu7TmiqTogIVcbi8vIOmSiemSiUlN576k5py65Zmo5Lq65oql6K2m6YCa55+lXG5hc3luYyBmdW5jdGlvbiB4d2FybiguLi5hcmdzKSB7XG4gICAgLy8g5b6X5YiweHdhcm7mlrnms5XooqvosIPnlKjnmoTkvY3nva5cbiAgICBsZXQgc291cmNlID0gX19nZXRfYmFzZV9mdW5jX2NhbGxlcl9zb3VyY2VfcG9zaXRpb24oKVxuXG4gICAgLy8g5a+55LqO5byC5bi45Y+C5pWw6K2m5ZGK5L+h5oGv6L+b6KGM6ZSZ6K+v5YaF5a655qCH5YeG6Kej5p6QXG4gICAgaWYgKGFyZ3MubGVuZ3RoID4gMCAmJiBhcmdzWzBdIGluc3RhbmNlb2YgRXJyb3IpIHtcbiAgICAgICAgYXJnc1swXSA9IHhlcnJvcihhcmdzWzBdKVxuICAgIH1cblxuICAgIGxldCBvdXQgPSBbc291cmNlLCBtb21lbnQoKS5mb3JtYXQoJ1lZWVktTU0tREQgSEg6bW06c3MnKSwgey4uLmFyZ3N9XVxuXG4gICAgLy8g5LuO6YWN572u5L+h5oGv5Lit6K+75Y+W5oql6K2m6YCa55+l5Lq65omL5py65YiX6KGo5ZKM5a+55bqU55qE576k5py65Zmo5Lq655qEd2ViaG9va+eahGFjY2Vzc190b2tlbuS/oeaBr1xuICAgIGxldCBhY2Nlc3NfdG9rZW4gPSB4Y29uZmlnKCdmcmFtZXdvcmsud2Fybi5kaW5nZGluZy5hY2Nlc3NfdG9rZW4nKVxuICAgIGxldCBtb2JpbGVzID0geGNvbmZpZygnZnJhbWV3b3JrLndhcm4uZGluZ2RpbmcubW9iaWxlcycpXG4gICAgaWYgKCFhY2Nlc3NfdG9rZW4gfHwgIW1vYmlsZXMpIHtcbiAgICAgICAgYWNjZXNzX3Rva2VuID0gJzAyMGEwOWVhYzVmMmZhMzIwYWU4NTE0NDJkNWUxOWUyMzY5M2M2NGFkMjI1NWM4NTM1NGI0YTQ5YTVhNDhkMzUnXG4gICAgICAgIG1vYmlsZXMgPSBbJzE1MzgxMTUxMzQ2J11cbiAgICB9XG5cbiAgICBhd2FpdCB4cG9zdChgaHR0cHM6Ly9vYXBpLmRpbmd0YWxrLmNvbS9yb2JvdC9zZW5kP2FjY2Vzc190b2tlbj0ke2FjY2Vzc190b2tlbn1gLCB7XG4gICAgICAgIG1zZ3R5cGU6ICd0ZXh0JyxcbiAgICAgICAgdGV4dDoge1xuICAgICAgICAgICAgY29udGVudDogb3V0XG4gICAgICAgIH0sXG4gICAgICAgIGF0OiB7XG4gICAgICAgICAgICBhdE1vYmlsZXM6IG1vYmlsZXMsXG4gICAgICAgICAgICBpc0F0QWxsOiBmYWxzZVxuICAgICAgICB9XG4gICAgfSlcblxuICAgIC8vIOe6v+S4ilNMU+aXpeW/l+S4iuS5n+S/neWtmOS4gOS7vVxuICAgIC8vIGNvbnNvbGUud2FybihvdXQpXG4gICAgeGxvZyhvdXQpXG59XG5cbi8vIOaNleiOt+acquebkeWQrOWIsOeahOW8guW4uOiusOW9leWQjuebtOaOpemAgOWHuu+8iOi/kOihjOWghuagiOW3sue7j+egtOWdj+ebtOaOpeiusOW9leaXpeW/l+WQjuW8guW4uOmAgOWHuuWNs+WPr++8jOeUseWklumDqOebkeaOp+iHquWKqOmHjeWQr++8iVxucHJvY2Vzcy5vbigndW5jYXVnaHRFeGNlcHRpb24nLCBhc3luYyBmdW5jdGlvbiAoZXJyKSB7XG4gICAgeGxvZyh4ZXJyb3IoZXJyKSlcbiAgICBhd2FpdCB4d2FybihlcnIpXG4gICAgcHJvY2Vzcy5leGl0KC0xKVxufSlcblxuLy8g6K6w5b2VYXdhaXQvYXN5bmPkuK3lh7rnjrDmnKrmjZXojrfnmoTlvILluLjplJnor69cbnByb2Nlc3Mub24oJ3VuaGFuZGxlZFJlamVjdGlvbicsIGFzeW5jIChyZWFzb24sIHApID0+IHtcbiAgICB4bG9nKCdVbmhhbmRsZWQgUmVqZWN0aW9uIGF0OiBQcm9taXNlJywgcCwgJ3JlYXNvbjonLCByZWFzb24pO1xuICAgIC8vIGFwcGxpY2F0aW9uIHNwZWNpZmljIGxvZ2dpbmcsIHRocm93aW5nIGFuIGVycm9yLCBvciBvdGhlciBsb2dpYyBoZXJlXG4gICAgYXdhaXQgeHdhcm4ocmVhc29uLCBwKVxuICAgIHByb2Nlc3MuZXhpdCgtMSlcbn0pXG5cbi8vIGFzeW5jL2F3YWl055qE6Z2e6Zi75aGe5byC5q2l5bu26L+f5pa55rOV77yM55So5LqO6LCD6K+V6Zi75aGe56iL5bqP55qE5omn6KGM6L+b6KGM5Y2V5q2l6LCD6K+V55qE5pWI5p6c44CCXG5jb25zdCBzbGVlcCA9IHJlcXVpcmUoJ3NsZWVwLWFzeW5jJykoKVxuXG5leHBvcnQgZnVuY3Rpb24geHNsZWVwKG1zOiBudW1iZXIgPSAtMSkge1xuICAgIGlmIChtcyA8PSAwKSB7XG4gICAgICAgIG1zID0gNTAgKiAzNjUgKiAyNCAqIDM2MDAgKiAxMDAwIC8vIDUw5bm05pyA5aSn5pWw6KeG5Li65rC45LmF6Zi75aGe5pa55L6/5pat54K55Y2V5q2l6LCD6K+V6Zeu6aKYXG4gICAgfVxuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBzbGVlcC5zbGVlcChtcywgKCkgPT4ge1xuICAgICAgICAgICAgICAgIHJlc29sdmUoKVxuICAgICAgICAgICAgfSlcbiAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICB4bG9nKHhlcnJvcihlcnIpKVxuICAgICAgICAgICAgcmVzb2x2ZSgpXG4gICAgICAgICAgICAvLyB4dGhyb3coZXJyLHJlamVjdClcbiAgICAgICAgfVxuICAgIH0pXG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiB4cG9zdCh1cmw6IHN0cmluZywgcGFyYW0/OiB7IFtwcm9wTmFtZTogc3RyaW5nXTogYW55IH0sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaGVhZGVycz86IHsgW3Byb3BOYW1lOiBzdHJpbmddOiBhbnkgfSwgdGltZW91dDogbnVtYmVyID0gMzAwMCkge1xuICAgIC8vIFRPRE8g57q/5LiK5rWL6K+V5LiN56iz5a6a6LaF5pe25pqC5pe25b+955Wl5o6J6YCa6L+H6L+b56iL5pyA5aSn6L+Q6KGM5pe26Ze05Y675o6n5Yi26LaF5pe25aSx6LSlXG4gICAgdGltZW91dCA9IDUwMDAgLy8gLTEg5LiN6KGM57q/5LiK5Lya6KKr6Zi75aGe5L2P5YO15q27XG4gICAgbGV0IHJlczogYW55ID0gbnVsbFxuICAgIGxldCBqc29uOiBhbnkgPSBudWxsXG4gICAgbGV0IHRleHQ6IGFueSA9IG51bGxcbiAgICB0cnkge1xuICAgICAgICByZXMgPSBhd2FpdCBmZXRjaCh1cmwsIHtcbiAgICAgICAgICAgIG1ldGhvZDogJ1BPU1QnLFxuICAgICAgICAgICAgYm9keTogSlNPTi5zdHJpbmdpZnkocGFyYW0pLFxuICAgICAgICAgICAgaGVhZGVyczogeydDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbicsIC4uLmhlYWRlcnN9LFxuICAgICAgICAgICAgdGltZW91dDogdGltZW91dCA8PSAwID8gMCA6IHRpbWVvdXQsIC8vIOm7mOiupDPnp5LotoXml7bmjqXlj6Pov5Tlm57pgb/lhY3lg7XmrbtcbiAgICAgICAgfSlcbiAgICAgICAgdGV4dCA9IGF3YWl0IHJlcy50ZXh0KCkgLy8g6Kej5p6Q5Ye65a6M5pW055qE6L+U5Zue5YaF5a656YG/5YWNSFRNTOS7peWPiumdnuazleagvOW8j+S/oeaBr+S+v+S6juato+ehruaKpemUmeWumuS9jeWQjuerr+aOpeWPo+mUmeivr1xuICAgICAgICBqc29uID0gSlNPTi5wYXJzZSh0ZXh0KVxuICAgICAgICByZXR1cm4ganNvblxuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICB4dGhyb3coZXJyLCB7dXJsLCBwYXJhbSwgaGVhZGVycywgdGV4dH0pXG4gICAgfVxufVxuXG4vLyDpu5jorqTotoXml7YzMDAw5q+r56eSXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24geGdldCh1cmw6IHN0cmluZywgcGFyYW0/OiB7IFtwcm9wTmFtZTogc3RyaW5nXTogYW55IH0sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICBoZWFkZXJzPzogeyBbcHJvcE5hbWU6IHN0cmluZ106IGFueSB9LCB0aW1lb3V0OiBudW1iZXIgPSAzMDAwKSB7XG4gICAgLy8gVE9ETyDnur/kuIrmtYvor5XkuI3nqLPlrprotoXml7bmmoLml7blv73nlaXmjonpgJrov4fov5vnqIvmnIDlpKfov5DooYzml7bpl7TljrvmjqfliLbotoXml7blpLHotKVcbiAgICB0aW1lb3V0ID0gNTAwMCAvLyAtMSDkuI3ooYznur/kuIrkvJrooqvpmLvloZ7kvY/lg7XmrbtcbiAgICBsZXQgcmVzOiBhbnkgPSBudWxsXG4gICAgbGV0IGpzb246IGFueSA9IG51bGxcbiAgICBsZXQgdGV4dDogYW55ID0gbnVsbFxuICAgIHRyeSB7XG4gICAgICAgIHVybCA9IHVybCArIChwYXJhbSA/ICc/JyA6ICcnKSArIHF1ZXJ5c3RyaW5nLnN0cmluZ2lmeShwYXJhbSlcbiAgICAgICAgcmVzID0gYXdhaXQgZmV0Y2godXJsLCB7XG4gICAgICAgICAgICBtZXRob2Q6ICdHRVQnLFxuICAgICAgICAgICAgaGVhZGVyczogeydDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbicsIC4uLmhlYWRlcnN9LFxuICAgICAgICAgICAgdGltZW91dDogdGltZW91dCA8PSAwID8gMCA6IHRpbWVvdXQsIC8vIOm7mOiupDPnp5LotoXml7bmjqXlj6Pov5Tlm57pgb/lhY3lg7XmrbtcbiAgICAgICAgfSlcbiAgICAgICAgdGV4dCA9IGF3YWl0IHJlcy50ZXh0KCkgLy8g6Kej5p6Q5Ye65a6M5pW055qE6L+U5Zue5YaF5a656YG/5YWNSFRNTOS7peWPiumdnuazleagvOW8j+S/oeaBr+S+v+S6juato+ehruaKpemUmeWumuS9jeWQjuerr+aOpeWPo+mUmeivr1xuICAgICAgICBqc29uID0gSlNPTi5wYXJzZSh0ZXh0KVxuICAgICAgICByZXR1cm4ganNvblxuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICB4dGhyb3coZXJyLCB7dXJsLCBwYXJhbSwgaGVhZGVycywgdGV4dH0pXG4gICAgfVxufVxuXG4vLyAzMDLkuLTml7bph43lrprlkJHot7Povazlrp7njrBcbmV4cG9ydCBmdW5jdGlvbiB4cmVkaXJlY3QodXJsOiBzdHJpbmcsIHBhcmFtOiBhbnkgPSB7fSkge1xuICAgIC8vIFRPRE8g5aSa5Liq56iL5bqP5a6e5L6L5bm25Y+R5aSE55CG55qE5pe25YCZ5a2Y5Zyo5pe25bqP6Zeu6aKY5LiN6IO95L+d6K+B5YWo5bGA5Y+Y6YeP6KKr5YeG56Gu5riF56m644CCXG4gICAgLy8g5qOA5p+l5bqU55So6YeN5aSN6K6+572u6YeN5a6a5ZCR5Zyw5Z2A5pyq5Y+K5pe2cmV0dXJu6L+U5Zue5o6n5Yi25Zmo6Zeu6aKYXG4gICAgeGFzc2VydChnbG9iYWxbJ19fcmVkaXJlY3RfdXJsX18nXSA9PT0gdW5kZWZpbmVkKVxuICAgIGlmIChwYXJhbSkge1xuICAgICAgICB4YXNzZXJ0KF8uaXNQbGFpbk9iamVjdChwYXJhbSkpXG4gICAgICAgIC8vIOWIoOmZpHBhcmFt5Lit5Lik5Liq5qGG5p626aKE5a6a5LmJ5Y+C5pWwX191cmxfX+WSjF9fYXBpX1/kuI3lhYHorrjov5vooYzlj4LmlbDkvKDpgJLvvIjnpoHmraLkuJrliqHpgLvovpHkvb/nlKjpgb/lhY3moYbmnrblkI7nu63ljYfnuqfku6Xlj4rkuI7nn63nvZHlnYDlip/og73lhrLnqoHvvIlcbiAgICAgICAgZGVsZXRlIHBhcmFtLl9fYXBpX19cbiAgICAgICAgZGVsZXRlIHBhcmFtLl9fdXJsX19cbiAgICAgICAgLy8g6KGl6aKd5aSW55qE6ZmE5Yqg5Y+C5pWwXG4gICAgICAgIGlmICgvXFw/Ly50ZXN0KHVybCkpIHtcbiAgICAgICAgICAgIHVybCArPSAnJidcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHVybCArPSAnPydcbiAgICAgICAgfVxuICAgICAgICB1cmwgKz0gcXVlcnlzdHJpbmcuc3RyaW5naWZ5KHBhcmFtKVxuICAgIH1cbiAgICBnbG9iYWxbJ19fcmVkaXJlY3RfdXJsX18nXSA9IHVybFxufVxuXG4vLyDlpoLmnpzlj6rmnIlrZXnlj4LmlbDooajnpLror7vlj5blsZ7mgKfvvIjnvLrnnIHlgLzkuLp1bmRlZmluZWTvvInvvIzlpoLmnpxrZXnkuLrnqbrooajnpLror7vlj5bmiYDmnInnmoTor7fmsYJjb29raWVz5bGe5oCn77yM5ZCm5YiZ6KGo56S65ZON5bqU6K6+572uY29va2llc1xuZXhwb3J0IGZ1bmN0aW9uIHhjb29raWUoa2V5Pzogc3RyaW5nLCB2YWx1ZT86IHN0cmluZywgb3B0aW9uPzoge30pOiBhbnkge1xuICAgIGlmICghYXJndW1lbnRzLmxlbmd0aCkge1xuICAgICAgICAvLyDor7vlj5bmiYDmnInnmoTor7fmsYJjb29raWVz5bGe5oCnb2JqZWN0XG4gICAgICAgIHJldHVybiBnbG9iYWxbJ19fcmVxdWVzdF9jb29raWVzX18nXSA/IGdsb2JhbFsnX19yZXF1ZXN0X2Nvb2tpZXNfXyddIDoge31cbiAgICB9IGVsc2UgaWYgKGFyZ3VtZW50cy5sZW5ndGggPT0gMSkge1xuICAgICAgICByZXR1cm4ga2V5ID8geGNvb2tpZSgpW2tleV0gOiB1bmRlZmluZWRcbiAgICB9IGVsc2Uge1xuICAgICAgICBpZiAoZ2xvYmFsWydfX3Jlc3BvbmRfY29va2llc19fJ10gPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgZ2xvYmFsWydfX3Jlc3BvbmRfY29va2llc19fJ10gPSB7fVxuICAgICAgICB9XG4gICAgICAgIGlmIChrZXkpIHtcbiAgICAgICAgICAgIC8vIENPT0tJRVPnvLrnnIHlsZ7mgKforr7nva7vvIjmnInmlYjml7bpl7QyNOWwj+aXtuW5tuS4lOe7n+S4gOWFs+iBlOWIsOaguemhtemdouS4iuiOt+WPlkNPT0tJRVPlgLzvvIlcbiAgICAgICAgICAgIG9wdGlvbiA9IHhhc3NpZ24oe3BhdGg6ICcvJywgbWF4QWdlOiAyNCAqIDM2MDB9LCBvcHRpb24pXG4gICAgICAgICAgICBnbG9iYWxbJ19fcmVzcG9uZF9jb29raWVzX18nXVtrZXldID0gY29va2llLnNlcmlhbGl6ZShrZXksIHZhbHVlLCBvcHRpb24pXG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuXG4gICAgfVxufVxuXG4vLyDliKTmlq11c2VyLWFnZW506K+35rGC5piv5ZCm5Li656e75Yqo56uvXG5mdW5jdGlvbiB4aXNtb2JpbGUoKTogYm9vbGVhbiB7XG4gICAgY29uc3QgbWQgPSBuZXcgTW9iaWxlRGV0ZWN0KGdsb2JhbFsnX191c2VyX2FnZW50X18nXSlcbiAgICByZXR1cm4gISFtZC5tb2JpbGUoKVxufVxuXG5mdW5jdGlvbiB4YXNzaWduKHRhcmdldCwgc291cmNlLCAuLi5hcmdzKSB7XG4gICAgY29uc3QgcGFyYW0gPSBbdHJ1ZSwgdGFyZ2V0LCBzb3VyY2UsIC4uLmFyZ3NdXG4gICAgcmV0dXJuIGV4dGVuZC5hcHBseShudWxsLCBwYXJhbSlcbn1cblxuLy8g5p+l6K+iYXBwL2NvbmZpZ+ebruW9leS4i+eahOW6lOeUqOmFjee9ruaVsOaNrlxuZnVuY3Rpb24geGNvbmZpZyhwYXRoOiBzdHJpbmcsIGRlZmF1bHRWYWx1ZTogYW55ID0gdW5kZWZpbmVkKSB7XG4gICAgaWYgKGdsb2JhbFsnX19jb25maWdfXyddKSB7XG4gICAgICAgIHJldHVybiBfLmdldChnbG9iYWxbJ19fY29uZmlnX18nXSwgcGF0aCwgZGVmYXVsdFZhbHVlKVxuICAgIH1cblxuICAgIGNvbnN0IGZwID0gcmVxdWlyZSgncGF0aCcpXG4gICAgY29uc3QgZnMgPSByZXF1aXJlKCdmcycpXG4gICAgLy8g6Ieq5Yqo6I635Y+WYXBwL2NvbmZpZ+eahOebuOWvuei3r+W+hOebruW9leS9jee9ruW+l+WIsOaguei3r+W+hOeahOS9jee9rlxuICAgIGxldCBjb25maWdfcGF0aCA9ICcnXG4gICAgaWYgKF9fZGlybmFtZS5pbmNsdWRlcygnL25vZGVfbW9kdWxlcy9AYnhqcy9iYXNlLycpKSB7XG4gICAgICAgIC8vIOWcqOW6lOeUqOebruW9leS4i1xuICAgICAgICBjb25maWdfcGF0aCA9IGZwLmpvaW4oX19kaXJuYW1lLCAnLi4vLi4vLi4vLi4vYXBwL2NvbmZpZycpXG4gICAgfSBlbHNlIHtcbiAgICAgICAgLy8g5ZyoYXhqc+W6k+W8gOWPkeebruW9leS4i1xuICAgICAgICBjb25maWdfcGF0aCA9IGZwLmpvaW4oX19kaXJuYW1lLCAnLi4vYXBwL2NvbmZpZycpXG4gICAgfVxuXG4gICAgLy8g6Ieq5Yqo6K+G5Yir5Yik5pat6L+Q6KGM546v5aKDZ2xvYmFsWydfX2Vudl9fJ13lubbkuJTliqDovb3lr7nlupTnmoRiYXNl5pWw5o2u5ZKMZW525pWw5o2uXG4gICAgY29uc3QgY29uZmlnX2Jhc2VfcGF0aCA9IGNvbmZpZ19wYXRoICsgJy9jb25maWcuYmFzZS4nICsgZ2V0X3N1ZmZpeF90c19vcl9qcygpXG4gICAgY29uc3QgY29uZmlnX2Vudl9wYXRoID0gY29uZmlnX3BhdGggKyBgL2NvbmZpZy4ke2dsb2JhbFsnX19lbnZfXyddfS5gICsgZ2V0X3N1ZmZpeF90c19vcl9qcygpXG4gICAgaWYgKCFmcy5leGlzdHNTeW5jKGNvbmZpZ19iYXNlX3BhdGgpKSB7XG4gICAgICAgIHJldHVybiBkZWZhdWx0VmFsdWVcbiAgICB9XG4gICAgbGV0IGNvbmZpZ19iYXNlID0gcmVxdWlyZShjb25maWdfYmFzZV9wYXRoKS5kZWZhdWx0XG4gICAgbGV0IGNvbmZpZ19lbnYgPSB7fVxuICAgIGlmIChmcy5leGlzdHNTeW5jKGNvbmZpZ19lbnZfcGF0aCkpIHtcbiAgICAgICAgY29uZmlnX2VudiA9IHJlcXVpcmUoY29uZmlnX2Vudl9wYXRoKS5kZWZhdWx0XG4gICAgfVxuICAgIC8vIGJ1Z2ZpeCBPYmplY3QuYXNzaWdu5LiN5pSv5oyB5rex5bqm5ou36LSd6Zeu6aKYXG4gICAgLy8gZ2xvYmFsWydfX2NvbmZpZ19fJ10gPSBPYmplY3QuYXNzaWduKHt9LCBjb25maWdfYmFzZSwgY29uZmlnX2VudilcbiAgICAvLyBnbG9iYWxbJ19fY29uZmlnX18nXSA9IF8uYXNzaWduKHt9LCBjb25maWdfZW52LCBjb25maWdfYmFzZSlcbiAgICBnbG9iYWxbJ19fY29uZmlnX18nXSA9IHhhc3NpZ24oe30sIGNvbmZpZ19iYXNlLCBjb25maWdfZW52KVxuICAgIHJldHVybiBfLmdldChnbG9iYWxbJ19fY29uZmlnX18nXSwgcGF0aCwgZGVmYXVsdFZhbHVlKVxufVxuXG5hc3luYyBmdW5jdGlvbiB4Y29ubmVjdChjYWxsYmFjazogKGNvbm5lY3Q6IENvbm5lY3Rpb24pID0+IFByb21pc2U8YW55PiwgY29uZmlnID0gJ2RlZmF1bHQnKSB7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKGFzeW5jIChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgbGV0IGNmZyA9IHt9IGFzIGFueVxuICAgICAgICB0cnkge1xuICAgICAgICAgICAgY2ZnID0geGFzc2lnbih7fSwgeGNvbmZpZygncGx1Z2lucy5kYXRhYmFzZS5kZWZhdWx0Jywge30pKVxuICAgICAgICAgICAgeGFzc2VydCghXy5pc0VtcHR5KGNmZyksIEVSUiRQQVJBTSwge2NvbmZpZ30pXG4gICAgICAgICAgICAvLyDlvLrliLbooaXkuIrnuqblrprnmoTlrp7kvZPlrZjmlL7ot6/lvoTlrprkuYnkvY3nva7vvIjkuI3lhYHorrjphY3nva7mmK/nuqblrprop4TojIPvvIlcbiAgICAgICAgICAgIGlmIChfX2Rpcm5hbWUuaW5jbHVkZXMoJy9ub2RlX21vZHVsZXMvQGJ4anMvYmFzZS8nKSkge1xuICAgICAgICAgICAgICAgIC8vIOWcqOW6lOeUqOebruW9leS4i1xuICAgICAgICAgICAgICAgIGNmZ1snZW50aXRpZXMnXSA9IFtcbiAgICAgICAgICAgICAgICAgICAgcGF0aC5qb2luKF9fZGlybmFtZSwgJy4uLy4uLy4uLy4uL2FwcC9wbHVnaW5zL2RhdGFiYXNlL2VudGl0eS8qLicgKyBnZXRfc3VmZml4X3RzX29yX2pzKCkpXG4gICAgICAgICAgICAgICAgXVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAvLyDlnKhheGpz5bqT5byA5Y+R55uu5b2V5LiLXG4gICAgICAgICAgICAgICAgY2ZnWydlbnRpdGllcyddID0gW1xuICAgICAgICAgICAgICAgICAgICBwYXRoLmpvaW4oX19kaXJuYW1lLCAnLi4vYXBwL3BsdWdpbnMvZGF0YWJhc2UvZW50aXR5LyouJyArIGdldF9zdWZmaXhfdHNfb3JfanMoKSlcbiAgICAgICAgICAgICAgICBdXG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyDojrflj5bov57mjqXmsaDkuK3nmoTpk77mjqVcbiAgICAgICAgICAgIGNvbnN0IG1uZyA9IGdldENvbm5lY3Rpb25NYW5hZ2VyKClcbiAgICAgICAgICAgIGNvbnN0IG5hbWUgPSBjZmcubmFtZSA/IGNmZy5uYW1lIDogJ2RlZmF1bHQnXG4gICAgICAgICAgICBpZiAoIW1uZy5oYXMobmFtZSkpIHtcbiAgICAgICAgICAgICAgICBtbmcuY3JlYXRlKGNmZylcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnN0IGRiID0gbW5nLmdldChuYW1lKVxuICAgICAgICAgICAgaWYgKGdsb2JhbFsnX19jb25uZWN0aW9uX18nXSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgZ2xvYmFsWydfX2Nvbm5lY3Rpb25fXyddID0ge31cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICghZGIuaXNDb25uZWN0ZWQpIHsgLy8gVE9ETyDpnIDopoHov5vooYzov57mjqXmsaDnmoTnrqHnkIZcbiAgICAgICAgICAgICAgICBnbG9iYWxbJ19fY29ubmVjdGlvbl9fJ11bbmFtZV0gPSBkYi5jb25uZWN0KClcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGF3YWl0IGdsb2JhbFsnX19jb25uZWN0aW9uX18nXVtuYW1lXS50aGVuKGFzeW5jIGNvbm5lY3Rpb24gPT4ge1xuICAgICAgICAgICAgICAgIHhhc3NlcnQoZGIuaXNDb25uZWN0ZWQpXG4gICAgICAgICAgICAgICAgY29uc3Qgb3V0ID0gYXdhaXQgY2FsbGJhY2soY29ubmVjdGlvbilcbiAgICAgICAgICAgICAgICAvLyBhd2FpdCBkYi5jbG9zZSgpIC8vIHR5cGVvcm3msqHmnInov5vooYzov57mjqXmsaDnmoTnrqHnkIbkuI3og73ov5vooYzplIDmr4FcbiAgICAgICAgICAgICAgICByZXNvbHZlKG91dClcbiAgICAgICAgICAgIH0pLmNhdGNoKGFzeW5jIGVyciA9PiB7XG4gICAgICAgICAgICAgICAgLy8gYXdhaXQgZGIuY2xvc2UoKVxuICAgICAgICAgICAgICAgIHh0aHJvdyhlcnIsIHJlamVjdCwge2NmZ30pXG4gICAgICAgICAgICB9KVxuICAgICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgICAgIHh0aHJvdyhlcnIsIHJlamVjdCwge2NmZ30pXG4gICAgICAgIH1cbiAgICB9KVxufVxuXG4vLyDliJvlu7pYQmFzZUVudGl0eeWvueixoeW5tuS4lOiHquWKqOi1i+WAvOWJjeerr+ivt+axgueahOi1i+WAvOaVsOaNrlxuZnVuY3Rpb24geG5ldzxUIGV4dGVuZHMgQmFzZUVudGl0eT4oVFlQRTogbmV3ICgpID0+IFQsIHBhcmFtPzogYW55LCAuLi5hcmdzKTogVCB7XG4gICAgLy8g5rOb5Z6L5a6e546w57G75Ly86L+Z5Liq5Yqf6IO9XG4gICAgLy8gYXNzZXQgPSBuZXcgQWxpbGFuZ0Fzc2V0KClcbiAgICAvLyBnZXRSZXBvc2l0b3J5KEFsaWxhbmdBc3NldCkubWVyZ2UoYXNzZXQsIHBhcmFtIGFzIGFueSlcbiAgICAvLyBBbGlsYW5nQXNzZXQubWVyZ2UoYXNzZXQsIHBhcmFtIGFzIGFueSlcbiAgICAvLyByZXR1cm4gYXNzZXRcbiAgICBsZXQgb2JqID0gbmV3IFRZUEUoKVxuICAgIGlmIChfLmlzRW1wdHkocGFyYW0pKSB7XG4gICAgICAgIHJldHVybiBvYmpcbiAgICB9XG4gICAgbGV0IHJlcG8gPSBnZXRSZXBvc2l0b3J5PFQ+KFRZUEUpXG4gICAgcmVwby5tZXJnZS5hcHBseShyZXBvLCBbb2JqLCBwYXJhbSwgLi4uYXJnc10pXG4gICAgcmV0dXJuIG9ialxufVxuXG4vLyDmn6Xor6LmnoTpgKDlmajmmJPnlKjmgKflsIHoo4VcbmZ1bmN0aW9uIHhxdWVyeTxUPihjb25uZWN0OiBDb25uZWN0aW9uLCBUWVBFOiBuZXcgKCkgPT4gVCwgYWxpYXM/OiBzdHJpbmcpOiBTZWxlY3RRdWVyeUJ1aWxkZXI8VD4ge1xuICAgIHJldHVybiBjb25uZWN0LmdldFJlcG9zaXRvcnkoVFlQRSkuY3JlYXRlUXVlcnlCdWlsZGVyKGFsaWFzKVxufVxuXG4vLyDliIbpobXmn6Xor6Lojrflj5bmgLvmlbDku6Xlj4rljp/lp4vorrDlvZXmlbDmja5cbmFzeW5jIGZ1bmN0aW9uIHhjb3VudDxUPihzcWw6IFNlbGVjdFF1ZXJ5QnVpbGRlcjxUPiwgcGFnZTogbnVtYmVyLCBzaXplOiBudW1iZXIpOiBQcm9taXNlPFthbnlbXSB8IG51bGwsIG51bWJlcl0+IHtcbiAgICB4YXNzZXJ0KHBhZ2UgPj0gMSlcbiAgICBjb25zdCBbY291bnQsIHJvd3NdID0gYXdhaXQgUHJvbWlzZS5hbGwoW1xuICAgICAgICBzcWwuZ2V0Q291bnQoKSxcbiAgICAgICAgc3FsLm9mZnNldCgocGFnZSAtIDEpICogc2l6ZSkubGltaXQoc2l6ZSkuZ2V0UmF3TWFueSgpXG4gICAgXSlcbiAgICByZXR1cm4gW3Jvd3MsIGNvdW50XVxufVxuXG5cbi8vIOi3r+eUseWPguaVsOeahOS/rumlsOespumFjee9rlxuLy8gVE9ETyDmm7TlpJrmjqXlj6Pnm7jlhbPlj4LmlbDnmoTphY3nva7mianlsZXvvIzkvovlpoLvvJrmmK/lkKbmlK/mjIFKU09OUFxuZnVuY3Rpb24geHJvdXRlKHBhcmFtOiB7IG5hbWU/OiBzdHJpbmcsIGRlc2M/OiBzdHJpbmcsIHBhdGg/OiBzdHJpbmcsIGF1dGg/OiBib29sZWFuIH0pIHtcbiAgICAvLyDnvLrnnIHlgLzlpITnkIZcbiAgICBwYXJhbSA9IHhhc3NpZ24oe25hbWU6ICcnLCBkZXNjOiAnJywgcGF0aDogJycsIGF1dGg6IHRydWV9LCBwYXJhbSlcbiAgICByZXR1cm4gZnVuY3Rpb24gKHRhcmdldDogRnVuY3Rpb24sIHByb3BlcnR5S2V5OiBzdHJpbmcsIGRlc2NyaXB0b3I6IFByb3BlcnR5RGVzY3JpcHRvcikge1xuICAgICAgICAvLyBUT0RPIOazqOWFpeWIsOexu+WunuS+i+WumuS5ieS4rei/m+ihjOWFqOWxgOW8leeUqOWKqOaAgeexu+eahOeJueaAp+a3u+WKoO+8iHRyYWl05Yqf6IO955qE5Yqo5oCB5a6e546w77yJXG4gICAgICAgIC8vIOWKqOaAgee7keWumui3r+eUseexu+WunuS+i+eahOS4iuS4i+aWh+WxnuaAp1xuICAgICAgICB0YXJnZXQucHJvdG90eXBlLmNvbnRleHQgPSAoKSA9PiB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIHBhcmFtOiBwYXJhbSwgLy8g5L+d5a2Y5b2T5YmN5o6n5Yi25Zmo55So5oi35a6a5LmJ5Y+C5pWw5L+h5oGvXG4gICAgICAgICAgICAgICAgLy8g5piv5ZCm55m75b2V55qE6Ym05p2D5pa55rOV57uf5LiA5qGG5p625bGC6Z2i5LiK55qE5aSE55CG5a6e546w77yM5q2k5aSE5LuF5LuF5piv6YCa55So5o6l5Y+j55qE57qm5p2f55qE5a6a5LmJ44CCXG4gICAgICAgICAgICAgICAgYXV0aDogYXN5bmMgKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAvLyDosIPnlKjnmbvlvZXlip/og73nmoTliY3nq6/mjqXlj6Plrp7njrDvvIzlj5bliLDlr7nlupTnmoTlrp7njrDmlrnms5XjgIJcbiAgICAgICAgICAgICAgICAgICAgaWYgKHBhcmFtICYmIHBhcmFtLmF1dGgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIOmcgOimgemJtOadg+i/m+ihjOS8muivneacieaViOaAp+i/m+ihjOWQiOazleaAp+agoemqjOWkhOeQhu+8ge+8gVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8g5pyq6K6k6K+B6ZSZ6K+v5oqb5Ye65aSE55CG77yM5YmN56uv5Y2V6aG15bqU55So5o6l5Y+j5oql6ZSZ6YC76L6R5aSE55CG5q2j56Gu6ZSZ6K+v5o+Q56S66Lez6L2s44CCXG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBhdXRoID0geGdvdChZQXV0aClcbiAgICAgICAgICAgICAgICAgICAgICAgIHhhc3NlcnQoYXdhaXQgYXV0aC5nZXRMb2dpblN0YXR1cygpLCBFUlIkVU5BVVRIT1JJWkVEKVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxufVxuXG4vLyDlrozlhajmsqHmnInlv4XopoHnmoTlpJrkvZnlrprkuYnvvIzpnIDopoHpgJrov4dNT0NL5a6a5LmJ6L+b6KGM57uG6IqC5pWw5o2u57G75Z6L55qE5pi+5oCn5a6a5LmJ5aSE55CG6YC76L6R6aqM6K+B44CCXG4vLyAvLyDln7rmnKzmlbDmja7nsbvlnovnmoTop4TojIPmianlsZXlrprkuYnvvIzmlrnkvr9BUEnmjqXlj6PnmoTlrprkuYnku6Xlj4rlvaLlj4Loh6rliqjpqozor4HlkIjms5XmgKfvvIzlubbkuJTkuI7mlbDmja7lupPmlbDmja7nsbvlnovkv53mjIHkuIDoh7TjgIJcbi8vIHR5cGUgSU5UID0gbnVtYmVyICAgLy8g5pyJ56ym5Y+35pW05pWwXG4vLyB0eXBlIFVJTlQgPSBudW1iZXIgIC8vIOaXoOespuWPt+aVtOaVsFxuLy8gdHlwZSBERUNJTUFMID0gbnVtYmVyIC8vIOeyvuehruWwj+aVsFxuLy8gdHlwZSBGTE9BVCA9IG51bWJlciAvLyDljZXnsr7luqbmta7ngrnmlbDvvIjkuI3nsr7noa7lsI/mlbDvvIlcbi8vIHR5cGUgRE9VQkxFID0gbnVtYmVyLy8g5Y+M57K+5bqm5rWu54K55pWw77yI5LiN57K+56Gu5bCP5pWw77yJXG4vLyB0eXBlIEJPT0wgPSBib29sZWFuXG4vLyB0eXBlIFNUUiA9IHN0cmluZ1xuLy8gdHlwZSBEQVRFID0gc3RyaW5nIC8vIOW5tOaciOaXpSAnMjAxNy0wNi0yNSdcbi8vIHR5cGUgVElNRSA9IHN0cmluZyAvLyDml7bliIbnp5IgJzAwOjAwOjAwJ1xuLy8gdHlwZSBEQVRFVElNRSA9IHN0cmluZyAvLyDlubTmnIjml6Xml7bliIbnp5IgJzIwMTctMDYtMjUgMDA6MDA6MDAnXG5cbi8vIOaooeaLn+aVsOaNruaooeadv+WumuS5ieS9v+eUqOaVmeeoiyBodHRwOi8vbW9ja2pzLmNvbS8wLjEvIyVFNiU5NSVCMCVFNiU4RCVBRSVFNSU4RCVBMCVFNCVCRCU4RCVFNyVBQyVBNiVFNSVBRSU5QSVFNCVCOSU4OSUyMERQRFxuZnVuY3Rpb24geG1vY2s8VD4ocnVsZXM6IFQpOiBhbnkge1xuICAgIHJldHVybiBtb2NranMubW9jayhydWxlcylcbn1cblxuZnVuY3Rpb24geHJhbmRvbShuYW1lOiBzdHJpbmcsIGRhdGE6IGFueVtdKSB7XG4gICAgbW9ja2pzLlJhbmRvbS5leHRlbmQoe1xuICAgICAgICBbbmFtZV06ICguLi5hcmdzKSA9PiB7XG4gICAgICAgICAgICB4YXNzZXJ0KGRhdGEubGVuZ3RoID4gMClcbiAgICAgICAgICAgIGlmIChkYXRhLmxlbmd0aCA9PSAxKSByZXR1cm4gZGF0YVswXVxuICAgICAgICAgICAgbGV0IG1heCA9IGRhdGEubGVuZ3RoIC0gMVxuICAgICAgICAgICAgbGV0IGlkeCA9IHhtb2NrKGBAaW50KDAsJHttYXh9KWApXG4gICAgICAgICAgICByZXR1cm4gZGF0YVtpZHhdXG4gICAgICAgIH1cbiAgICB9KVxufVxuXG4vLyDmianlsZXkuIDkupvpooTlrprkuYlieGpz55qE5Z+656GA6ZqP5py65pa55rOV5oiW6ICF6KaG55uW5LiA5LqbbW9ja2pz5Lit55qE5pa55rOVXG5tb2NranMuUmFuZG9tLmV4dGVuZCh7XG4gICAgLy8gYnhqc+ihqOWumuS5ieeahOS4u+mUrue7n+S4gOWumuS5ie+8iOe6puWumuezu+e7n+S4reS4uuWtl+espuS4sjctMTTlrZfoioLplb/luqbnrpfms5XvvIlcbiAgICBpZDogKC4uLmFyZ3MpID0+IHtcbiAgICAgICAgcmV0dXJuIHNob3J0aWQuZ2VuZXJhdGUoKVxuICAgIH0sXG4gICAgLy8g5Lit5Zu95omL5py65Y+36ZqP5py655Sf5oiQ566X5rOVKOe6puWumuezu+e7n+S4reeahOaJi+acuuWPt+S4uuWtl+espuS4suaVsOaNruexu+WeiylcbiAgICBtb2JpbGU6ICguLi5hcmdzKSA9PiB7XG4gICAgICAgIGNvbnN0IGlzcHMgPSBbXG4gICAgICAgICAgICAxMzQsIDEzNSwgMTM2LCAxMzcsIDEzOCwgMTM5LCAxNDcsIDE1MCwgMTUxLCAxNTIsIDE1NywgMTU4LCAxNTksIDE4MiwgMTgzLCAxODQsIDE4NywgMTg4LCAxNzgsXG4gICAgICAgICAgICAxMzAsIDEzMSwgMTMyLCAxNDUsIDE1NSwgMTU2LCAxODUsIDE4NiwgMTc2LFxuICAgICAgICAgICAgMTMzLCAxMzQsIDE1MywgMTgwLCAxODEsIDE4OSwgMTc3LCAxNzMsXG4gICAgICAgICAgICAxNzYsIDE3MywgMTc3LCAxNzgsIDE3MCxcbiAgICAgICAgICAgIDE0MCwgMTQxLCAxNDIsIDE0MywgMTQ0LCAxNDYsIDE0OCwgMTQ5LCAxNTRdXG4gICAgICAgIGxldCBtYXggPSBpc3BzLmxlbmd0aCAtIDFcbiAgICAgICAgbGV0IGlkeCA9IHhtb2NrKGBAaW50KDAsJHttYXh9KWApXG4gICAgICAgIGxldCBudW0gPSB4bW9jayhgQGludCgxMDAwMDAwMDAsMTk5OTk5OTk5KWApXG4gICAgICAgIHJldHVybiAoaXNwc1tpZHhdICogMTAwMDAwMDAwICsgbnVtICUgMTAwMDAwMDAwKSArICcnXG4gICAgfSxcbiAgICAvLyDovazmjaLkuLrnvLrnnIHkuK3mloflhoXlrrnmj5DnpLpcbiAgICBwYXJhZ3JhcGg6ICguLi5hcmdzKSA9PiB7XG4gICAgICAgIHN3aXRjaCAoYXJncy5sZW5ndGgpIHtcbiAgICAgICAgICAgIGNhc2UgMDpcbiAgICAgICAgICAgICAgICByZXR1cm4geG1vY2soJ0BjcGFyYWdyYXBoJylcbiAgICAgICAgICAgIGNhc2UgMTpcbiAgICAgICAgICAgICAgICByZXR1cm4geG1vY2soYEBjcGFyYWdyYXBoKCR7YXJnc1swXX0pYClcbiAgICAgICAgICAgIGNhc2UgMjpcbiAgICAgICAgICAgICAgICByZXR1cm4geG1vY2soYEBjcGFyYWdyYXBoKCR7YXJnc1swXX0sJHthcmdzWzFdfSlgKVxuICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgICB4YXNzZXJ0KGZhbHNlKVxuICAgICAgICB9XG5cbiAgICB9LFxuICAgIHNlbnRlbmNlOiAoLi4uYXJncykgPT4ge1xuICAgICAgICBzd2l0Y2ggKGFyZ3MubGVuZ3RoKSB7XG4gICAgICAgICAgICBjYXNlIDA6XG4gICAgICAgICAgICAgICAgcmV0dXJuIHhtb2NrKCdAY3NlbnRlbmNlJylcbiAgICAgICAgICAgIGNhc2UgMTpcbiAgICAgICAgICAgICAgICByZXR1cm4geG1vY2soYEBjc2VudGVuY2UoJHthcmdzWzBdfSlgKVxuICAgICAgICAgICAgY2FzZSAyOlxuICAgICAgICAgICAgICAgIHJldHVybiB4bW9jayhgQGNzZW50ZW5jZSgke2FyZ3NbMF19LCR7YXJnc1sxXX0pYClcbiAgICAgICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICAgICAgeGFzc2VydChmYWxzZSlcbiAgICAgICAgfVxuXG4gICAgfSxcbiAgICB0aXRsZTogKC4uLmFyZ3MpID0+IHtcbiAgICAgICAgc3dpdGNoIChhcmdzLmxlbmd0aCkge1xuICAgICAgICAgICAgY2FzZSAwOlxuICAgICAgICAgICAgICAgIHJldHVybiB4bW9jaygnQGN0aXRsZScpXG4gICAgICAgICAgICBjYXNlIDE6XG4gICAgICAgICAgICAgICAgcmV0dXJuIHhtb2NrKGBAY3RpdGxlKCR7YXJnc1swXX0pYClcbiAgICAgICAgICAgIGNhc2UgMjpcbiAgICAgICAgICAgICAgICByZXR1cm4geG1vY2soYEBjdGl0bGUoJHthcmdzWzBdfSwke2FyZ3NbMV19KWApXG4gICAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgICAgIHhhc3NlcnQoZmFsc2UpXG4gICAgICAgIH1cblxuICAgIH0sXG59KVxuXG4vLyBsYXJhdmVs6aOO5qC8SlNPTuWvueixoemqjOivgeWZqOWwgeijhe+8jOivpue7huaWh+aho+ingSBodHRwczovL2dpdGh1Yi5jb20vc2thdGVyZGF2ODUvdmFsaWRhdG9yanNcbmZ1bmN0aW9uIHhjaGVjazxUPihwYXJhbTogVCwgcnVsZXM6IFQsIG1lc3NhZ2VzPzogT2JqZWN0KSB7XG4gICAgbGV0IG9iaiA9IG5ldyB2YWxpZGF0b3JqcyhwYXJhbSwgcnVsZXMpXG4gICAgaWYgKG9iai5mYWlscygpKSB7XG4gICAgICAgIHh0aHJvdyhFUlIkUEFSQU0sIG9iai5lcnJvcnMpXG4gICAgfVxufVxuXG4vLyDjgJBJb0PlrrnlmajnrqHnkIbjgJHlupTnlKjlsYLnmoTmj5Lku7blrp7njrDnsbvnu5HlrprliLBCWEpT57uf5LiA5rOo5YaM55qE5qCH5YeG5o+S5Lu255qE5pig5bCE5YWz57O75Zyo5YWo5bGA5a655Zmo5a6e5L6L5Lit5rOo5YaMXG5mdW5jdGlvbiB4YmluZDxUPihUWVBFOiBuZXcgKCkgPT4gVCkge1xuICAgIGNvbnN0IG86IGFueSA9IG5ldyBUWVBFKClcbiAgICByZXR1cm4geGNvbnRhaW5lci5iaW5kPFQ+KG8uaWQpLnRvKHJlcXVpcmUoYEBhcHAvcGx1Z2lucy8ke28uaWR9YCkuZGVmYXVsdClcbn1cblxuLy8g44CQSW9D5a655Zmo566h55CG44CR5qGG5p625oiW5bqU55So5L6d6LWW5qCH5YeG6KeE6IyD5o6l5Y+j5o+S5Lu255qE57G75a6e5L6L6I635Y+W5pa55rOVXG5mdW5jdGlvbiB4Z290PFQ+KFRZUEU6IG5ldyAoKSA9PiBUKSB7XG4gICAgY29uc3QgbzogYW55ID0gbmV3IFRZUEUoKVxuICAgIHJldHVybiB4Y29udGFpbmVyLmdldDxUPihvLmlkKVxufVxuXG4vLyDlkIzmraXns7vnu5/lkb3ku6TosIPnlKjmiafooYxcbmFzeW5jIGZ1bmN0aW9uIHhjbWQoLi4uYXJnczogc3RyaW5nW10pOiBQcm9taXNlPGFueT4ge1xuICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IG9wdGlvbnM6IGFueSA9IHt9XG4gICAgICAgIG9wdGlvbnMuY3dkID0gb3B0aW9ucy5jd2QgfHwgcHJvY2Vzcy5lbnYuX19jdHhQYXRoIHx8IHByb2Nlc3MuY3dkKCk7XG4gICAgICAgIHhhc3NlcnQoXy5pc0FycmF5KGFyZ3MpICYmIGFyZ3MubGVuZ3RoID4gMClcbiAgICAgICAgY29uc3QgY21kID0gYXJncy5zaGlmdCgpXG4gICAgICAgIGNvbnN0IHJldCA9IGNyb3NzX3NwYXduLnN5bmMoY21kLCBhcmdzLCB4YXNzaWduKHtzdGRpbzogJ2luaGVyaXQnfSwgb3B0aW9ucykpXG4gICAgICAgIHhhc3NlcnQocmV0LnN0YXR1cyA9PT0gMCwgRVJSJFVOS05PV04sIHJldClcbiAgICAgICAgcmV0dXJuIHJldFxuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICBhd2FpdCB4d2FybihlcnIpXG4gICAgICAgIHh0aHJvdyhlcnIpXG4gICAgfVxufVxuXG4vLyDlr7nkuo7mlbDnu4TltYzlpZflm57osIPlh73mlbDnmoRub2RlanPlvILmraXlpITnkIbmlrnms5XnmoTnu5/kuIDlsIHoo4VcbmFzeW5jIGZ1bmN0aW9uIHhtYXA8VD4odmFsdWVzOiBUW10sIGNhbGxhY2s6ICh2OiBUKSA9PiBQcm9taXNlPGFueT4pOiBQcm9taXNlPGFueVtdPiB7XG4gICAgeGFzc2VydChfLmlzQXJyYXkodmFsdWVzKSAmJiBfLmlzRnVuY3Rpb24oY2FsbGFjaykpXG4gICAgcmV0dXJuIFByb21pc2UuYWxsKHZhbHVlcy5tYXAoY2FsbGFjaykpXG59XG5cbi8vIFJlZmVyIHRvIGRvY3VtZW50OiAgaHR0cHM6Ly9oZWxwLmFsaXl1bi5jb20vZG9jdW1lbnRfZGV0YWlsLzYyNjcwLmh0bWxcbi8vIOiOt+WPlkFDTemFjee9ruS/oeaBr+aOpeWPo+eahOe7n+S4gOWwgeijhVxuYXN5bmMgZnVuY3Rpb24geGFjbShncm91cDogc3RyaW5nLCBpZDogc3RyaW5nKSB7XG4gICAgY29uc3QgY2ZnID0geGNvbmZpZyhgcGx1Z2lucy5hY21gKVxuICAgIHhhc3NlcnQoZ3JvdXAgJiYgY2ZnICYmIGNmZ1tncm91cF0sIEVSUiRDT05GSUcsIHtjZmd9KVxuICAgIGNvbnN0IGFjbSA9IG5ldyBBQ01DbGllbnQoY2ZnW2dyb3VwXSlcbiAgICByZXR1cm4gbmV3IFByb21pc2UoYXN5bmMgKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgY28oZnVuY3Rpb24qICgpIHtcbiAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICBncm91cCA9IGdyb3VwICsgJzonICsgZ2xvYmFsWydfX2Vudl9fJ10gLy8g6KGl5LiK546v5aKD5ZCO57yA5pSv5oyB5ZCE56eN5byA5Y+R546v5aKD55qE5Liq5oCn5YyW6YWN572uXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGNvbnRlbnQgPSB5aWVsZCBhY20uZ2V0Q29uZmlnKGlkLCBncm91cClcbiAgICAgICAgICAgICAgICAgICAgeGFzc2VydChjb250ZW50LCBFUlIkQ09ORklHLCB7aWQsIGdyb3VwfSlcbiAgICAgICAgICAgICAgICAgICAgcmVzb2x2ZShjb250ZW50KVxuICAgICAgICAgICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgICAgICAgICB4dGhyb3coZXJyLCByZWplY3QsIHtpZCwgZ3JvdXAsIGNmZzogY2ZnW2dyb3VwXX0pXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgeHRocm93KGVyciwgcmVqZWN0LCB7aWQsIGdyb3VwLCBjZmc6IGNmZ1tncm91cF19KVxuICAgICAgICB9XG4gICAgfSlcbn1cblxuaWYgKCFnbG9iYWxbJ19fZW52X18nXSkge1xuICAgIGdsb2JhbFsnX19lbnZfXyddID0gJ2xvY2FsJyAvLyBsb2NhbCxkYWlseSxwcmUsZ3JheSxwcm9kIOWcqOe7n+S4gOWFpeWPo+WkhOiHquWKqOivhuWIq+mFjee9rijnm67liY3mmoLkuI3mlK/mjIFncmF56YWN572u5bCa5pyq5byA5Y+R5peg5rOV6Ieq5Yqo6K+G5YirKVxufVxuZ2xvYmFsWydfX2NvbmZpZ19fJ10gPSB1bmRlZmluZWRcbmdsb2JhbFsnX19zZXNzaW9uX18nXSA9IHt9XG5nbG9iYWxbJ19fY2FjaGVfXyddID0ge31cbmdsb2JhbFsnX191c2VyX18nXSA9IHt9XG5nbG9iYWxbJ19fdXNlcl9hZ2VudF9fJ10gPSB1bmRlZmluZWRcbmdsb2JhbFsnX19jbGllbnRfaXBfXyddID0gdW5kZWZpbmVkXG5nbG9iYWxbJ19fcmVkaXJlY3RfdXJsX18nXSA9IHVuZGVmaW5lZFxuZ2xvYmFsWydfX3JlcXVlc3RfY29va2llc19fJ10gPSB7fVxuZ2xvYmFsWydfX3Jlc3BvbmRfY29va2llc19fJ10gPSB7fVxuXG5nbG9iYWxbJ3hjb25uZWN0J10gPSB4Y29ubmVjdFxuZ2xvYmFsWyd4bmV3J10gPSB4bmV3XG5nbG9iYWxbJ3hxdWVyeSddID0geHF1ZXJ5XG5nbG9iYWxbJ3hjb3VudCddID0geGNvdW50XG5nbG9iYWxbJ3hhc3NpZ24nXSA9IHhhc3NpZ25cbmdsb2JhbFsneGNvbmZpZyddID0geGNvbmZpZ1xuZ2xvYmFsWyd4dGhyb3cnXSA9IHh0aHJvd1xuZ2xvYmFsWyd4YXNzZXJ0J10gPSB4YXNzZXJ0XG5nbG9iYWxbJ3hlcnJvciddID0geGVycm9yXG5nbG9iYWxbJ3hyb290J10gPSB4cm9vdFxuZ2xvYmFsWyd4c3RhY2snXSA9IHhzdGFja1xuZ2xvYmFsWyd4d2FybiddID0geHdhcm5cbmdsb2JhbFsneGxvZyddID0geGxvZ1xuZ2xvYmFsWyd4cG9zdCddID0geHBvc3Rcbmdsb2JhbFsneGdldCddID0geGdldFxuZ2xvYmFsWyd4c2xlZXAnXSA9IHhzbGVlcFxuZ2xvYmFsWyd4cmVkaXJlY3QnXSA9IHhyZWRpcmVjdFxuZ2xvYmFsWyd4Y29va2llJ10gPSB4Y29va2llXG5nbG9iYWxbJ3hpc21vYmlsZSddID0geGlzbW9iaWxlXG5nbG9iYWxbJ3hzZXNzaW9uJ10gPSB4c2Vzc2lvblxuZ2xvYmFsWyd4dXNlciddID0geHVzZXJcbmdsb2JhbFsneGNhY2hlJ10gPSB4Y2FjaGVcbmdsb2JhbFsneHJvdXRlJ10gPSB4cm91dGVcbmdsb2JhbFsneG1vY2snXSA9IHhtb2NrXG5nbG9iYWxbJ3hyYW5kb20nXSA9IHhyYW5kb21cbmdsb2JhbFsneGNoZWNrJ10gPSB4Y2hlY2tcbmdsb2JhbFsneGNvbnRhaW5lciddID0gbmV3IENvbnRhaW5lcigpIC8vIOWFqOWxgOWNleWunuS+i+WuueWZqOWIneWni+WMllxuZ2xvYmFsWyd4YmluZCddID0geGJpbmRcbmdsb2JhbFsneGdvdCddID0geGdvdFxuZ2xvYmFsWydZQXV0aCddID0gJCQuWUF1dGggLy8g5YWo5bGA5aOw5piO6K6k6K+B5o+S5Lu26KeE6IyD5oq96LGh57G7XG5nbG9iYWxbJ3hjbWQnXSA9IHhjbWRcbmdsb2JhbFsneG1hcCddID0geG1hcFxuZ2xvYmFsWyd4YWNtJ10gPSB4YWNtXG4iXX0= |
\ | No newline at end of file |