UNPKG

135 kBJavaScriptView Raw
1"use strict";
2var __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};
10var __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};
18var __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};
45var _this = this;
46Object.defineProperty(exports, "__esModule", { value: true });
47process.env.TZ = 'Asia/Shanghai';
48process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
49require("reflect-metadata");
50var inversify_1 = require("inversify");
51var typeorm_1 = require("@bxjs/typeorm");
52var session_1 = require("./session");
53var $$ = require("./plugins");
54var path = require('path');
55var ErrorStackParser = require('error-stack-parser');
56var cookie = require('cookie');
57var MobileDetect = require('mobile-detect');
58var fetch = require('node-fetch');
59var _ = require('lodash');
60var moment = require('moment');
61var extend = require('extend');
62var querystring = require('querystring');
63// const parameter = require('parameter')
64// const parameterCheckInstance = new parameter({
65// // translate: function () {
66// // var args = Array.prototype.slice.call(arguments);
67// // // Assume there have I18n.t method for convert language.
68// // return I18n.t.apply(I18n, args);
69// // }
70// })
71var circular_json = require("circular-json");
72var mockjs = require('mockjs');
73var shortid = require('shortid');
74var validatorjs = require('validatorjs');
75var cross_spawn = require('cross-spawn');
76var ACMClient = require('amber_utf-8');
77var co = require('co');
78// FIXME HACK原生方法JSON转换不可逆的BUG(JAVA端传来的富文本字段内容含有\n\t字符串中的字符生成JSON字符串无法正常解析报错)
79var raw_stringify = JSON.stringify;
80function new_stringify(value, replacer, space) {
81 var out = raw_stringify(value, replacer, space);
82 if (_.isString(out)) {
83 out = out.replace(/\\n/g, '\\\\n')
84 .replace(/\\t/g, '\\\\t')
85 .replace(/\\u/g, '\\\\u'); //JAVA端返回的unicode字符转义处理
86 }
87 return out;
88}
89JSON.stringify = new_stringify;
90// ts-node本地调试需要加载对应的源代码后缀名称
91function get_suffix_ts_or_js() {
92 if (global['__env__'] == 'local' && !/^\/code\/node_modules/.test(__dirname)) {
93 return 'ts';
94 }
95 else {
96 return 'js';
97 }
98}
99exports.get_suffix_ts_or_js = get_suffix_ts_or_js;
100// 准确定位错误码位置,间接得到函数调用位置地址信息,结合符号报表的正确解析处理完美得到错误定位信息,准确代码调试。
101function __get_base_func_caller_source_position(position) {
102 if (position === void 0) { position = 3; }
103 try {
104 throw new Error();
105 }
106 catch (err) {
107 var out = ErrorStackParser.parse(err);
108 var idx = 0;
109 // 找到第二个TS文件的执行位置
110 var find_ts_sufix_file_count = 0;
111 for (; idx < out.length; idx++) {
112 if (/\.ts$/.test(out[idx].fileName)) {
113 find_ts_sufix_file_count += 1;
114 }
115 if (find_ts_sufix_file_count == position) {
116 break;
117 }
118 }
119 if (find_ts_sufix_file_count == position) {
120 return '[' + out[idx]['fileName'] + ':' + out[idx]['lineNumber'] + ']';
121 }
122 else {
123 // TODO 需要定位为什么调用栈无法找到对应的位置出现越界??
124 // console.error(err)
125 console.error(circular_json.stringify(out, null, 4)
126 .replace(/\r/g, '').replace(/\n/g, ''));
127 return '#';
128 }
129 }
130}
131// 获取异常调用栈用于辅助错误提示定位
132function xstack(err, compact) {
133 if (compact === void 0) { compact = true; }
134 try {
135 // TODO 优化裁剪一些无用信息减少日志尺寸更加便于人工分析处理
136 var stack = ErrorStackParser.parse(err);
137 if (compact) {
138 var sources = [];
139 for (var _i = 0, stack_1 = stack; _i < stack_1.length; _i++) {
140 var v = stack_1[_i];
141 sources.push(v['fileName'] + ":" + v['lineNumber']);
142 }
143 return sources;
144 }
145 return stack;
146 }
147 catch (err1) {
148 var source = __get_base_func_caller_source_position();
149 return "invalid error input param (" + source + ")";
150 }
151}
152exports.xstack = xstack;
153// // 错误栈的递归嵌套格式显示数据结构定义(param嵌套找到最后一个msg的JSON解析语法错误就是错误链的原始错误发生位置)
154// let x = {
155// "code": "UNKNOWN",
156// "msg": "未知错误",
157// "param": {
158// "msg": "您输入的用户名或密码错误,请重新登录 (ErrorCode: 1005, url: https://login.alibaba-inc.com/authorize/login.do)"
159// },
160// "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\"]",
161// }
162// 对于异常内容的格式化参数解析处理成为四元组code/msg/param/stack
163function xerror(err, __param) {
164 xassert(err instanceof Error);
165 try {
166 // 标准错误的统一转换处理
167 var data_1 = JSON.parse(err.message);
168 if (data_1.code && data_1.msg && ERRORS[data_1.code]) {
169 return data_1;
170 }
171 }
172 catch (err) {
173 // ignore parse error
174 }
175 // 非标准错误的统一格式转换处理
176 var msg = ERRORS[ERR$UNKNOWN]['zh']; // TODO 错误码多语言回传到客户端问题
177 var code = ERR$UNKNOWN;
178 var param = { msg: err.message, param: __param }; // 用户自定义的错误参数信息 msg为非错误码JSON四元组就是嵌套的终止条件。
179 var stack = xstack(err);
180 var data = { msg: msg, code: code, param: param, stack: stack };
181 return data;
182}
183exports.xerror = xerror;
184// 用于获取错误栈的root cause根本原因(第一个被拦截的错误发生位置)
185function xroot(err) {
186 xassert(err instanceof Error);
187 var _a = xerror(err), msg = _a.msg, param = _a.param, code = _a.code, stack = _a.stack;
188 // 递归遍历找到错误链的root cause
189 for (; param && param.msg;) {
190 try {
191 var json = JSON.parse(param.msg);
192 param = json.param;
193 }
194 catch (err) {
195 msg = param.msg;
196 code = param.code;
197 stack = param.stack;
198 param = param.param;
199 break;
200 }
201 }
202 return { msg: msg, code: code, param: param, stack: stack };
203}
204exports.xroot = xroot;
205// TODO 报错处理(显示问题反馈联系人信息)
206// 将未处理的错误上抛的异常链记录下来用于精准追踪代码的执行过程(以及准确获取到根节点的错误码)
207// 对于promise异步回调的统一出错处理写法实例
208// export function login(username: string, password: string) {
209// return new Promise((resolve, reject) => {
210// co(function* () {
211// let user = yield buc.oauthclient.login(username, password)
212// resolve(user)
213// }).catch(async function (err) {
214// xthrow(err, reject)
215// })
216// })
217// }
218function xthrow(code, param, reject_param) {
219 if (code === void 0) { code = ERR$UNKNOWN; }
220 if (param === void 0) { param = undefined; }
221 if (reject_param === void 0) { reject_param = undefined; }
222 // promise中进行reject异常处理的抛出错误方法的形参逻辑预处理转换。
223 var reject = _.isFunction(param) ? param : undefined;
224 if (reject)
225 param = reject_param;
226 var data = {};
227 var source = __get_base_func_caller_source_position();
228 if (code instanceof Error) {
229 try {
230 data = JSON.parse(code.message);
231 // 将透传上抛的错误的路径信息和附加参数也记录下来方便提供完整应用堆栈信息辅助调试业务逻辑
232 if (!_.isArray(data.stack)) {
233 data.stack = [];
234 }
235 data.stack.push(source);
236 }
237 catch (err) {
238 // ignore
239 }
240 // 标准错误直接上抛处理
241 if (data.code && data.msg && ERRORS[data.code]) {
242 // 测试严重BUG reject函数类型表达式为假必须要用lodash判定是否为函数
243 if (_.isFunction(reject)) {
244 // promise回调中进行抛错误处理
245 var err = new Error(JSON.stringify(data));
246 reject(err);
247 return;
248 }
249 else {
250 throw new Error(JSON.stringify(data));
251 }
252 }
253 // 将非标准错误转换为标准错误后再上抛处理
254 data = xerror(code, param);
255 data.code = ERR$UNKNOWN;
256 data.msg = ERRORS[ERR$UNKNOWN]['zh']; // FIXME TODO 错误码的多语言处理转换!!
257 data.param = { msg: code.message, param: param, stack: [source] };
258 }
259 else {
260 // 对于常量定义错误的统一格式化处理
261 data = { code: code, msg: global['ERRORS'][code]['zh'], param: param, stack: [source] };
262 }
263 // 对于是否promise场景下的错误上抛进行正确的转换处理
264 if (_.isFunction(reject)) {
265 // promise回调中进行抛错误处理
266 reject(new Error(JSON.stringify(data)));
267 }
268 else {
269 // 非promise回调中异常传递
270 throw new Error(JSON.stringify(data));
271 }
272}
273exports.xthrow = xthrow;
274function xassert(expr, code, param) {
275 if (code === void 0) { code = ERR$ASSERT; }
276 var source = __get_base_func_caller_source_position();
277 var stack = [source];
278 if (!expr)
279 throw new Error(JSON.stringify({ code: code, msg: global['ERRORS'][code]['zh'], param: param, stack: stack }));
280 return expr;
281}
282exports.xassert = xassert;
283// // https://github.com/node-modules/parameter 参数验证规则详见此文档(egg团队开发的组件)
284// // 注意事项:GET通过URL传递的参数都是字符串类型应该尽量避免GET传递参数,需要多用POST的JSON格式传递参数并且POSTMAN上进行辅助测试正确数据类型映射。
285// export function xcheck(param: { [propName: string]: any }, rules: { [propName: string]: any }) {
286// let errors = parameterCheckInstance.validate(rules, param)
287// if (_.isEmpty(errors)) {
288// return true
289// } else {
290// xthrow(ERR$PARAM, errors)
291// }
292// }
293function xlog() {
294 var args = [];
295 for (var _i = 0; _i < arguments.length; _i++) {
296 args[_i] = arguments[_i];
297 }
298 // 兼容云端以及本地日志调试(解决任意对象的JSON字符串内容的完整输出)
299 var source = __get_base_func_caller_source_position() + '[' + xnow('YYYY-MM-DD HH:mm:ss.SSS') + ']';
300 var output = circular_json.stringify(args.slice(), null, 4);
301 if (global['__env__'] != 'prod' && !/^\/code\/node_modules/.test(__dirname)) {
302 // 打印到控制台一份日志(在阿里云非线上FC环境中)
303 console.log.apply(undefined, [source + output]);
304 // 写日志文件到/tmp下临时处理一下 TODO 需要改为类似log4j的本地日志库仅在非线上环境使用方便开发单机日常机器上调试。
305 var fs = require('fs');
306 var logFilePath = process.env['NODE_LOGFILE'] ? process.env['NODE_LOGFILE'] : '/tmp/bxjs.log';
307 fs.appendFileSync(logFilePath, source + output + "\r\n");
308 }
309 else {
310 // 生产环境下只打印到控制台绑定的SLS日志服务器上,并且需要去除掉换行信息否则打印会不正常。
311 // 去除掉换行方便方便SLS上的日志输出排版显示
312 output = output.replace(/\r/g, '').replace(/\n/g, '');
313 console.log.apply(undefined, [source + output]);
314 }
315}
316exports.xlog = xlog;
317// // 将详细错误信息及时发送到钉钉群上实时反馈给维护者
318// await xwarn({
319// code,
320// // TODO 如何认证通过了获取到用户信息也需要发送过去,方便联系对接人员进行立刻问题处理反馈。
321// message,
322// stack,
323// param,
324// })
325// 将详细错误信息及时发送到钉钉群上实时反馈给维护者
326// 钉钉IM群机器人报警通知
327function xwarn() {
328 var args = [];
329 for (var _i = 0; _i < arguments.length; _i++) {
330 args[_i] = arguments[_i];
331 }
332 return __awaiter(this, void 0, void 0, function () {
333 var source, out, access_token, mobiles;
334 return __generator(this, function (_a) {
335 switch (_a.label) {
336 case 0:
337 source = __get_base_func_caller_source_position();
338 // 对于异常参数警告信息进行错误内容标准解析
339 if (args.length > 0 && args[0] instanceof Error) {
340 args[0] = xerror(args[0]);
341 }
342 out = [source, xnow('YYYY-MM-DD HH:mm:ss.SSS'), __assign({}, args)];
343 access_token = xconfig('framework.warn.dingding.access_token');
344 mobiles = xconfig('framework.warn.dingding.mobiles');
345 if (!access_token || !mobiles) {
346 access_token = '020a09eac5f2fa320ae851442d5e19e23693c64ad2255c85354b4a49a5a48d35';
347 mobiles = ['15381151346'];
348 }
349 return [4 /*yield*/, xpost("https://oapi.dingtalk.com/robot/send?access_token=" + access_token, {
350 msgtype: 'text',
351 text: {
352 content: out
353 },
354 at: {
355 atMobiles: mobiles,
356 isAtAll: false
357 }
358 })
359 // 线上SLS日志上也保存一份
360 // console.warn(out)
361 ];
362 case 1:
363 _a.sent();
364 // 线上SLS日志上也保存一份
365 // console.warn(out)
366 xlog(out);
367 return [2 /*return*/];
368 }
369 });
370 });
371}
372// 捕获未监听到的异常记录后直接退出(运行堆栈已经破坏直接记录日志后异常退出即可,由外部监控自动重启)
373process.on('uncaughtException', function (err) {
374 return __awaiter(this, void 0, void 0, function () {
375 return __generator(this, function (_a) {
376 switch (_a.label) {
377 case 0:
378 xlog(xerror(err));
379 return [4 /*yield*/, xwarn(err)];
380 case 1:
381 _a.sent();
382 process.exit(-1);
383 return [2 /*return*/];
384 }
385 });
386 });
387});
388// 记录await/async中出现未捕获的异常错误
389process.on('unhandledRejection', function (reason, p) { return __awaiter(_this, void 0, void 0, function () {
390 return __generator(this, function (_a) {
391 switch (_a.label) {
392 case 0:
393 xlog('Unhandled Rejection at: Promise', p, 'reason:', reason);
394 // application specific logging, throwing an error, or other logic here
395 return [4 /*yield*/, xwarn(reason, p)];
396 case 1:
397 // application specific logging, throwing an error, or other logic here
398 _a.sent();
399 process.exit(-1);
400 return [2 /*return*/];
401 }
402 });
403}); });
404// async/await的非阻塞异步延迟方法,用于调试阻塞程序的执行进行单步调试的效果。
405var sleep = require('sleep-async')();
406function xsleep(ms) {
407 if (ms === void 0) { ms = -1; }
408 if (ms <= 0) {
409 ms = 50 * 365 * 24 * 3600 * 1000; // 50年最大数视为永久阻塞方便断点单步调试问题
410 }
411 return new Promise(function (resolve, reject) {
412 try {
413 sleep.sleep(ms, function () {
414 resolve();
415 });
416 }
417 catch (err) {
418 xlog(xerror(err));
419 resolve();
420 // xthrow(err,reject)
421 }
422 });
423}
424exports.xsleep = xsleep;
425function xpost(url, param, headers, timeout) {
426 if (timeout === void 0) { timeout = 3000; }
427 return __awaiter(this, void 0, void 0, function () {
428 var res, json, text, err_1;
429 return __generator(this, function (_a) {
430 switch (_a.label) {
431 case 0:
432 // TODO 线上测试不稳定超时暂时忽略掉通过进程最大运行时间去控制超时失败
433 timeout = 5000; // -1 不行线上会被阻塞住僵死
434 res = null;
435 json = null;
436 text = null;
437 _a.label = 1;
438 case 1:
439 _a.trys.push([1, 4, , 5]);
440 return [4 /*yield*/, fetch(url, {
441 method: 'POST',
442 body: JSON.stringify(param),
443 headers: __assign({ 'Content-Type': 'application/json' }, headers),
444 timeout: timeout <= 0 ? 0 : timeout,
445 })];
446 case 2:
447 res = _a.sent();
448 return [4 /*yield*/, res.text()]; // 解析出完整的返回内容避免HTML以及非法格式信息便于正确报错定位后端接口错误
449 case 3:
450 text = _a.sent(); // 解析出完整的返回内容避免HTML以及非法格式信息便于正确报错定位后端接口错误
451 json = JSON.parse(text);
452 return [2 /*return*/, json];
453 case 4:
454 err_1 = _a.sent();
455 xthrow(err_1, { url: url, param: param, headers: headers, text: text });
456 return [3 /*break*/, 5];
457 case 5: return [2 /*return*/];
458 }
459 });
460 });
461}
462exports.xpost = xpost;
463// 默认超时3000毫秒
464function xget(url, param, headers, timeout) {
465 if (timeout === void 0) { timeout = 3000; }
466 return __awaiter(this, void 0, void 0, function () {
467 var res, json, text, err_2;
468 return __generator(this, function (_a) {
469 switch (_a.label) {
470 case 0:
471 // TODO 线上测试不稳定超时暂时忽略掉通过进程最大运行时间去控制超时失败
472 timeout = 5000; // -1 不行线上会被阻塞住僵死
473 res = null;
474 json = null;
475 text = null;
476 _a.label = 1;
477 case 1:
478 _a.trys.push([1, 4, , 5]);
479 url = url + (param ? '?' : '') + querystring.stringify(param);
480 return [4 /*yield*/, fetch(url, {
481 method: 'GET',
482 headers: __assign({ 'Content-Type': 'application/json' }, headers),
483 timeout: timeout <= 0 ? 0 : timeout,
484 })];
485 case 2:
486 res = _a.sent();
487 return [4 /*yield*/, res.text()]; // 解析出完整的返回内容避免HTML以及非法格式信息便于正确报错定位后端接口错误
488 case 3:
489 text = _a.sent(); // 解析出完整的返回内容避免HTML以及非法格式信息便于正确报错定位后端接口错误
490 json = JSON.parse(text);
491 return [2 /*return*/, json];
492 case 4:
493 err_2 = _a.sent();
494 xthrow(err_2, { url: url, param: param, headers: headers, text: text });
495 return [3 /*break*/, 5];
496 case 5: return [2 /*return*/];
497 }
498 });
499 });
500}
501exports.xget = xget;
502// 302临时重定向跳转实现
503function xredirect(url, param) {
504 if (param === void 0) { param = {}; }
505 // TODO 多个程序实例并发处理的时候存在时序问题不能保证全局变量被准确清空。
506 // 检查应用重复设置重定向地址未及时return返回控制器问题
507 xassert(global['__redirect_url__'] === undefined);
508 if (param) {
509 xassert(_.isPlainObject(param));
510 // 删除param中两个框架预定义参数__url__和__api__不允许进行参数传递(禁止业务逻辑使用避免框架后续升级以及与短网址功能冲突)
511 delete param.__api__;
512 delete param.__url__;
513 // 补额外的附加参数
514 if (/\?/.test(url)) {
515 url += '&';
516 }
517 else {
518 url += '?';
519 }
520 url += querystring.stringify(param);
521 }
522 global['__redirect_url__'] = url;
523}
524exports.xredirect = xredirect;
525// 如果只有key参数表示读取属性(缺省值为undefined),如果key为空表示读取所有的请求cookies属性,否则表示响应设置cookies
526function xcookie(key, value, option) {
527 if (!arguments.length) {
528 // 读取所有的请求cookies属性object
529 return global['__request_cookies__'] ? global['__request_cookies__'] : {};
530 }
531 else if (arguments.length == 1) {
532 return key ? xcookie()[key] : undefined;
533 }
534 else {
535 if (global['__respond_cookies__'] === undefined) {
536 global['__respond_cookies__'] = {};
537 }
538 if (key) {
539 // COOKIES缺省属性设置(有效时间24小时并且统一关联到根页面上获取COOKIES值)
540 option = xassign({ path: '/', maxAge: 24 * 3600 }, option);
541 global['__respond_cookies__'][key] = cookie.serialize(key, value, option);
542 }
543 return;
544 }
545}
546exports.xcookie = xcookie;
547// 判断user-agent请求是否为移动端
548function xismobile() {
549 var md = new MobileDetect(global['__user_agent__']);
550 return !!md.mobile();
551}
552function xassign(target, source) {
553 var args = [];
554 for (var _i = 2; _i < arguments.length; _i++) {
555 args[_i - 2] = arguments[_i];
556 }
557 var param = [true, target, source].concat(args);
558 return extend.apply(null, param);
559}
560// 查询app/config目录下的应用配置数据
561function xconfig(path, defaultValue) {
562 if (defaultValue === void 0) { defaultValue = undefined; }
563 if (global['__config__']) {
564 return _.get(global['__config__'], path, defaultValue);
565 }
566 var fp = require('path');
567 var fs = require('fs');
568 // 自动获取app/config的相对路径目录位置得到根路径的位置
569 var config_path = '';
570 if (__dirname.includes('/node_modules/@bxjs/base/')) {
571 // 在应用目录下
572 config_path = fp.join(__dirname, '../../../../app/config');
573 }
574 else {
575 // 在axjs库开发目录下
576 config_path = fp.join(__dirname, '../app/config');
577 }
578 // 自动识别判断运行环境global['__env__']并且加载对应的base数据和env数据
579 var config_base_path = config_path + '/config.base.' + get_suffix_ts_or_js();
580 var config_env_path = config_path + ("/config." + global['__env__'] + ".") + get_suffix_ts_or_js();
581 if (!fs.existsSync(config_base_path)) {
582 return defaultValue;
583 }
584 var config_base = require(config_base_path).default;
585 var config_env = {};
586 if (fs.existsSync(config_env_path)) {
587 config_env = require(config_env_path).default;
588 }
589 // bugfix Object.assign不支持深度拷贝问题
590 // global['__config__'] = Object.assign({}, config_base, config_env)
591 // global['__config__'] = _.assign({}, config_env, config_base)
592 global['__config__'] = xassign({}, config_base, config_env);
593 return _.get(global['__config__'], path, defaultValue);
594}
595function xconnect(callback, config) {
596 if (config === void 0) { config = 'default'; }
597 return __awaiter(this, void 0, void 0, function () {
598 var _this = this;
599 return __generator(this, function (_a) {
600 return [2 /*return*/, new Promise(function (resolve, reject) { return __awaiter(_this, void 0, void 0, function () {
601 var cfg, mng, name_1, db_1;
602 var _this = this;
603 return __generator(this, function (_a) {
604 cfg = {};
605 try {
606 cfg = xassign({}, xconfig('plugins.database.default', {}));
607 xassert(!_.isEmpty(cfg), ERR$PARAM, { config: config });
608 // 强制补上约定的实体存放路径定义位置(不允许配置是约定规范)
609 if (__dirname.includes('/node_modules/@bxjs/base/')) {
610 // 在应用目录下
611 cfg['entities'] = [
612 path.join(__dirname, '../../../../app/plugins/database/entity/*.' + get_suffix_ts_or_js())
613 ];
614 }
615 else {
616 // 在axjs库开发目录下
617 cfg['entities'] = [
618 path.join(__dirname, '../app/plugins/database/entity/*.' + get_suffix_ts_or_js())
619 ];
620 }
621 mng = typeorm_1.getConnectionManager();
622 name_1 = cfg.name ? cfg.name : 'default';
623 if (!mng.has(name_1)) {
624 mng.create(cfg);
625 }
626 db_1 = mng.get(name_1);
627 if (global['g_connection'] === undefined) {
628 global['g_connection'] = {};
629 }
630 if (!db_1.isConnected) { // TODO 需要进行连接池的管理
631 global['g_connection'][name_1] = db_1.connect();
632 }
633 global['g_connection'][name_1].then(function (connection) { return __awaiter(_this, void 0, void 0, function () {
634 var out;
635 return __generator(this, function (_a) {
636 switch (_a.label) {
637 case 0:
638 xassert(db_1.isConnected);
639 return [4 /*yield*/, callback(connection)
640 // await db.close() // typeorm没有进行连接池的管理不能进行销毁
641 ];
642 case 1:
643 out = _a.sent();
644 // await db.close() // typeorm没有进行连接池的管理不能进行销毁
645 resolve(out);
646 return [2 /*return*/];
647 }
648 });
649 }); }).catch(function (err) { return __awaiter(_this, void 0, void 0, function () {
650 return __generator(this, function (_a) {
651 // await db.close()
652 xthrow(err, reject, { config: config, name: name_1 });
653 return [2 /*return*/];
654 });
655 }); });
656 }
657 catch (err) {
658 xthrow(err, reject, { config: config });
659 }
660 return [2 /*return*/];
661 });
662 }); })];
663 });
664 });
665}
666// 创建XBaseEntity对象并且自动赋值前端请求的赋值数据
667function xnew(TYPE, param) {
668 var args = [];
669 for (var _i = 2; _i < arguments.length; _i++) {
670 args[_i - 2] = arguments[_i];
671 }
672 // 泛型实现类似这个功能
673 // asset = new AlilangAsset()
674 // getRepository(AlilangAsset).merge(asset, param as any)
675 // AlilangAsset.merge(asset, param as any)
676 // return asset
677 var obj = new TYPE();
678 if (_.isEmpty(param)) {
679 return obj;
680 }
681 var repo = typeorm_1.getRepository(TYPE);
682 repo.merge.apply(repo, [obj, param].concat(args));
683 return obj;
684}
685// 查询构造器易用性封装
686function xquery(connect, TYPE, alias) {
687 return connect.getRepository(TYPE).createQueryBuilder(alias);
688}
689// 分页查询获取总数以及原始记录数据
690function xcount(sql, page, size) {
691 return __awaiter(this, void 0, void 0, function () {
692 var _a, count, rows;
693 return __generator(this, function (_b) {
694 switch (_b.label) {
695 case 0:
696 xassert(page >= 1);
697 return [4 /*yield*/, Promise.all([
698 sql.getCount(),
699 sql.offset((page - 1) * size).limit(size).getRawMany()
700 ])];
701 case 1:
702 _a = _b.sent(), count = _a[0], rows = _a[1];
703 return [2 /*return*/, [rows, count]];
704 }
705 });
706 });
707}
708// 路由参数的修饰符配置
709// TODO 更多接口相关参数的配置扩展,例如:是否支持JSONP
710function xroute(param) {
711 // 缺省值处理
712 // name 接口名称
713 // desc 接口描述
714 // path 路径路由重写
715 // auth 是否需要登录鉴权(缺省需要进行鉴权为true)
716 // nowrap 是否对于JSON请求进行success/content的标准进行包装(缺省进行包装为false)
717 param = xassign({ name: '', desc: '', path: '', auth: true, nowrap: false }, param);
718 return function (target, propertyKey, descriptor) {
719 var _this = this;
720 // TODO 注入到类实例定义中进行全局引用动态类的特性添加(trait功能的动态实现)
721 // 动态绑定路由类实例的上下文属性
722 target.prototype.context = function () {
723 return {
724 param: param,
725 // 是否登录的鉴权方法统一框架层面上的处理实现,此处仅仅是通用接口的约束的定义。
726 auth: function () { return __awaiter(_this, void 0, void 0, function () {
727 var auth, _a;
728 return __generator(this, function (_b) {
729 switch (_b.label) {
730 case 0:
731 if (!(param && param.auth)) return [3 /*break*/, 2];
732 auth = xgot(YAuth);
733 _a = xassert;
734 return [4 /*yield*/, auth.getLoginStatus()];
735 case 1:
736 _a.apply(void 0, [_b.sent(), ERR$UNAUTHORIZED]);
737 _b.label = 2;
738 case 2: return [2 /*return*/];
739 }
740 });
741 }); }
742 };
743 };
744 };
745}
746// 完全没有必要的多余定义,需要通过MOCK定义进行细节数据类型的显性定义处理逻辑验证。
747// // 基本数据类型的规范扩展定义,方便API接口的定义以及形参自动验证合法性,并且与数据库数据类型保持一致。
748// type INT = number // 有符号整数
749// type UINT = number // 无符号整数
750// type DECIMAL = number // 精确小数
751// type FLOAT = number // 单精度浮点数(不精确小数)
752// type DOUBLE = number// 双精度浮点数(不精确小数)
753// type BOOL = boolean
754// type STR = string
755// type DATE = string // 年月日 '2017-06-25'
756// type TIME = string // 时分秒 '00:00:00'
757// type DATETIME = string // 年月日时分秒 '2017-06-25 00:00:00'
758// 模拟数据模板定义使用教程 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
759function xmock(rules) {
760 return mockjs.mock(rules);
761}
762function xrandom(name, data) {
763 var _a;
764 mockjs.Random.extend((_a = {},
765 _a[name] = function () {
766 var args = [];
767 for (var _i = 0; _i < arguments.length; _i++) {
768 args[_i] = arguments[_i];
769 }
770 xassert(data.length > 0);
771 if (data.length == 1)
772 return data[0];
773 var max = data.length - 1;
774 var idx = xmock("@int(0," + max + ")");
775 return data[idx];
776 },
777 _a));
778}
779// 扩展一些预定义bxjs的基础随机方法或者覆盖一些mockjs中的方法
780mockjs.Random.extend({
781 // bxjs表定义的主键统一定义(约定系统中为字符串7-14字节长度算法)
782 id: function () {
783 var args = [];
784 for (var _i = 0; _i < arguments.length; _i++) {
785 args[_i] = arguments[_i];
786 }
787 return shortid.generate();
788 },
789 // 中国手机号随机生成算法(约定系统中的手机号为字符串数据类型)
790 mobile: function () {
791 var args = [];
792 for (var _i = 0; _i < arguments.length; _i++) {
793 args[_i] = arguments[_i];
794 }
795 var isps = [
796 134, 135, 136, 137, 138, 139, 147, 150, 151, 152, 157, 158, 159, 182, 183, 184, 187, 188, 178,
797 130, 131, 132, 145, 155, 156, 185, 186, 176,
798 133, 134, 153, 180, 181, 189, 177, 173,
799 176, 173, 177, 178, 170,
800 140, 141, 142, 143, 144, 146, 148, 149, 154
801 ];
802 var max = isps.length - 1;
803 var idx = xmock("@int(0," + max + ")");
804 var num = xmock("@int(100000000,199999999)");
805 return (isps[idx] * 100000000 + num % 100000000) + '';
806 },
807 // 转换为缺省中文内容提示
808 paragraph: function () {
809 var args = [];
810 for (var _i = 0; _i < arguments.length; _i++) {
811 args[_i] = arguments[_i];
812 }
813 switch (args.length) {
814 case 0:
815 return xmock('@cparagraph');
816 case 1:
817 return xmock("@cparagraph(" + args[0] + ")");
818 case 2:
819 return xmock("@cparagraph(" + args[0] + "," + args[1] + ")");
820 default:
821 xassert(false);
822 }
823 },
824 sentence: function () {
825 var args = [];
826 for (var _i = 0; _i < arguments.length; _i++) {
827 args[_i] = arguments[_i];
828 }
829 switch (args.length) {
830 case 0:
831 return xmock('@csentence');
832 case 1:
833 return xmock("@csentence(" + args[0] + ")");
834 case 2:
835 return xmock("@csentence(" + args[0] + "," + args[1] + ")");
836 default:
837 xassert(false);
838 }
839 },
840 title: function () {
841 var args = [];
842 for (var _i = 0; _i < arguments.length; _i++) {
843 args[_i] = arguments[_i];
844 }
845 switch (args.length) {
846 case 0:
847 return xmock('@ctitle');
848 case 1:
849 return xmock("@ctitle(" + args[0] + ")");
850 case 2:
851 return xmock("@ctitle(" + args[0] + "," + args[1] + ")");
852 default:
853 xassert(false);
854 }
855 },
856});
857// laravel风格JSON对象验证器封装,详细文档见 https://github.com/skaterdav85/validatorjs
858function xcheck(param, rules, messages) {
859 var obj = new validatorjs(param, rules);
860 if (obj.fails()) {
861 xthrow(ERR$PARAM, obj.errors);
862 }
863}
864// 【IoC容器管理】应用层的插件实现类绑定到BXJS统一注册的标准插件的映射关系在全局容器实例中注册
865function xbind(TYPE) {
866 var o = new TYPE();
867 return xcontainer.bind(o.id).to(require("@app/plugins/" + o.id).default);
868}
869// 【IoC容器管理】框架或应用依赖标准规范接口插件的类实例获取方法
870function xgot(TYPE) {
871 var o = new TYPE();
872 return xcontainer.get(o.id);
873}
874// 同步系统命令调用执行
875function xcmd() {
876 var args = [];
877 for (var _i = 0; _i < arguments.length; _i++) {
878 args[_i] = arguments[_i];
879 }
880 return __awaiter(this, void 0, void 0, function () {
881 var options, cmd, ret, err_3;
882 return __generator(this, function (_a) {
883 switch (_a.label) {
884 case 0:
885 _a.trys.push([0, 1, , 3]);
886 options = {};
887 options.cwd = options.cwd || process.env.__ctxPath || process.cwd();
888 xassert(_.isArray(args) && args.length > 0);
889 cmd = args.shift();
890 ret = cross_spawn.sync(cmd, args, xassign({ stdio: 'inherit' }, options));
891 xassert(ret.status === 0, ERR$UNKNOWN, ret);
892 return [2 /*return*/, ret];
893 case 1:
894 err_3 = _a.sent();
895 return [4 /*yield*/, xwarn(err_3)];
896 case 2:
897 _a.sent();
898 xthrow(err_3);
899 return [3 /*break*/, 3];
900 case 3: return [2 /*return*/];
901 }
902 });
903 });
904}
905// 对于数组嵌套回调函数的nodejs异步处理方法的统一封装
906function xmap(values, callack) {
907 return __awaiter(this, void 0, void 0, function () {
908 return __generator(this, function (_a) {
909 xassert(_.isArray(values) && _.isFunction(callack));
910 return [2 /*return*/, Promise.all(values.map(callack))];
911 });
912 });
913}
914// Refer to document: https://help.aliyun.com/document_detail/62670.html
915// 获取ACM配置信息接口的统一封装
916function xacm(group, id) {
917 return __awaiter(this, void 0, void 0, function () {
918 var cfg, acm;
919 var _this = this;
920 return __generator(this, function (_a) {
921 cfg = xconfig("plugins.acm");
922 xassert(group && cfg && cfg[group], ERR$CONFIG, { cfg: cfg });
923 acm = new ACMClient(cfg[group]);
924 return [2 /*return*/, new Promise(function (resolve, reject) { return __awaiter(_this, void 0, void 0, function () {
925 return __generator(this, function (_a) {
926 try {
927 co(function () {
928 var content, err_4;
929 return __generator(this, function (_a) {
930 switch (_a.label) {
931 case 0:
932 _a.trys.push([0, 2, , 3]);
933 group = group + ':' + global['__env__']; // 补上环境后缀支持各种开发环境的个性化配置
934 return [4 /*yield*/, acm.getConfig(id, group)];
935 case 1:
936 content = _a.sent();
937 xassert(content, ERR$CONFIG, { id: id, group: group });
938 resolve(content);
939 return [3 /*break*/, 3];
940 case 2:
941 err_4 = _a.sent();
942 xthrow(err_4, reject, { id: id, group: group, cfg: cfg[group] });
943 return [3 /*break*/, 3];
944 case 3: return [2 /*return*/];
945 }
946 });
947 });
948 }
949 catch (err) {
950 xthrow(err, reject, { id: id, group: group, cfg: cfg[group] });
951 }
952 return [2 /*return*/];
953 });
954 }); })];
955 });
956 });
957}
958// 根据当前配置的时区正确获取当前时间值(当前时区通过process.env.TZ='Asia/Shanghai'初始化配置统一解决掉对应用无感前后台保持一致性)
959function xnow(format) {
960 if (format === void 0) { format = 'YYYY-MM-DD HH:mm:ss'; }
961 return moment().format(format);
962}
963// 字符串与时间戳的相互转换处理
964function xtime(value) {
965 if (value === void 0) { value = undefined; }
966 if (value == undefined) {
967 return moment().toDate().getTime();
968 }
969 xassert(_.isString(value) || _.isSafeInteger(value));
970 if (_.isString(value)) {
971 // STRING转换为INT类型
972 return moment(value).toDate().getTime();
973 }
974 else {
975 // INT转换为STRING类型
976 return moment(value).format('YYYY-MM-DD HH:mm:ss');
977 }
978}
979// base64编码
980function xbase64encode(value) {
981 xassert(!_.isEmpty(value) && _.isString(value));
982 return new Buffer(value).toString('base64');
983}
984// base64解码
985function xbase64decode(value) {
986 xassert(!_.isEmpty(value) && _.isString(value));
987 return new Buffer(value, 'base64').toString();
988}
989// 改进npm包中的uuid v1时间序列算法确保唯一性和随机性可以稳定可靠的应用于serverless分布式高并发应用场景下
990// 改进基于时间序列的UUID算法确保serverless分布式并发场景下的全局唯一性以及使用密码机随机性改进不可预测性
991function xuuid() {
992 // 优化算法中的100纳秒时间为随机数,进一步降低冲突概率。
993 // 冲突概率分析:
994 // 1秒支撑1000并发(毫秒时间戳精度保证),
995 // 1000并发中相同毫秒时间的并发,再通过10000百纳秒随机数进行区分避免冲突,
996 // 不同机器上的并发时间戳可能会有偏移导致重复偏差时间(通过6个字节的node id随机数区分机器,2字节0x3fff随机数区分clockseq)
997 // 冲突概率基本上可以保证忽略不计避免shortid算法高并发冲突的缺陷
998 return require('uuid/v1')({ nsecs: Math.floor(Math.random() * 10000) }).replace(/\-/g, '');
999 //////////////////////////////////////////////////////////////////////////////////////
1000 // 考虑到serverless实际环境并不是合适node id使用mac地址,直接使用默认的8字节随机数替代更模拟更合适(node id + clockseq)。
1001 // // 封装正确的uuid实现算法确保唯一性(使用6个字节的机器mac地址,确保分布式机器算法执行的唯一性)
1002 // const mac = await __xgetmac__()
1003 // // 将字符串转换为buffer二进制处理
1004 // let buf = []
1005 // // MAC地址格式 ##:##:##:##:##:##
1006 // const values = mac.split(':')
1007 // xassert(values && values.length == 6)
1008 // for (let i = 0; i < 6; ++i) {
1009 // const tmpByte = parseInt(values[i], 16);
1010 // buf.push(tmpByte)
1011 // }
1012 // // 以mac地址作为机器唯一标识确保正确性
1013 // const uuid = require('uuid/v1')({node: buf})
1014 // return uuid;
1015}
1016/*
1017If you want to insure UUID uniqueness across your cluster processes, then I would suggest using v1({node:aUniqueVal}),
1018where aUniqueVal is some value you know to be unique to each cluster process.
1019https://www.npmjs.com/package/node-machine-id 生成机器id的唯一标识算法参考
1020 */
1021// // 获取mac地址
1022// async function __xgetmac__(): Promise<string> {
1023// if (!global['g_bxjs_sMacAddress']) {
1024// return new Promise<string>((resolve, reject) => {
1025// try {
1026// xassert(require('getmac').isMac(global['g_bxjs_sMacAddress']))
1027// resolve(global['g_bxjs_sMacAddress'])
1028// } catch (err) {
1029// xthrow(err, reject)
1030// }
1031// })
1032// }
1033// return new Promise<string>((resolve, reject) => {
1034// require('getmac').getMac(function (err, macAddress) {
1035// if (err) xthrow(err, reject)
1036// resolve(macAddress)
1037// })
1038// })
1039// }
1040// 请求上下文变量自动重置方法(以global变量中key为__下划线开始结束的属性自动清空为undefined,如需赋值其他缺省值需要在此函数中明确定义)
1041function xreset() {
1042 // 所有请求上下文属性的自动清空初始化处理(通过约定global的特殊属性__xxx__简化koa中的context设计机制,将这部分机制做到框架上对应用不可见)
1043 for (var _i = 0, _a = Object.keys(global); _i < _a.length; _i++) {
1044 var key = _a[_i];
1045 if (key.startsWith('__') && key.endsWith('__')) {
1046 global[key] = undefined;
1047 }
1048 }
1049 // 明确定义的一些全局变量的初始值赋值
1050 if (!global['__env__']) {
1051 global['__env__'] = 'local'; // local,daily,pre,gray,prod 在统一入口处自动识别配置(目前暂不支持gray配置尚未开发无法自动识别)
1052 }
1053 global['__config__'] = undefined;
1054 global['__session__'] = {};
1055 global['__cache__'] = {};
1056 global['__user__'] = {};
1057 global['__user_agent__'] = undefined;
1058 global['__client_ip__'] = undefined;
1059 global['__redirect_url__'] = undefined;
1060 global['__request_cookies__'] = {};
1061 global['__respond_cookies__'] = {};
1062}
1063// 首次模块加载的时候执行一次,确保应用中不可以有__xxx__参数作为全局变量在模块初始化的时候
1064xreset();
1065global['xreset'] = xreset;
1066global['xconnect'] = xconnect;
1067global['xnew'] = xnew;
1068global['xquery'] = xquery;
1069global['xcount'] = xcount;
1070global['xassign'] = xassign;
1071global['xconfig'] = xconfig;
1072global['xthrow'] = xthrow;
1073global['xassert'] = xassert;
1074global['xerror'] = xerror;
1075global['xroot'] = xroot;
1076global['xstack'] = xstack;
1077global['xwarn'] = xwarn;
1078global['xlog'] = xlog;
1079global['xpost'] = xpost;
1080global['xget'] = xget;
1081global['xsleep'] = xsleep;
1082global['xredirect'] = xredirect;
1083global['xcookie'] = xcookie;
1084global['xismobile'] = xismobile;
1085global['xsession'] = session_1.xsession;
1086global['xuser'] = session_1.xuser;
1087global['xcache'] = session_1.xcache;
1088global['xroute'] = xroute;
1089global['xmock'] = xmock;
1090global['xrandom'] = xrandom;
1091global['xcheck'] = xcheck;
1092global['xcontainer'] = new inversify_1.Container(); // 全局单实例容器初始化
1093global['xbind'] = xbind;
1094global['xgot'] = xgot;
1095global['YAuth'] = $$.YAuth; // 全局声明认证插件规范抽象类
1096global['xcmd'] = xcmd;
1097global['xmap'] = xmap;
1098global['xacm'] = xacm;
1099global['xbase64encode'] = xbase64encode;
1100global['xbase64decode'] = xbase64decode;
1101global['xnow'] = xnow;
1102global['xtime'] = xtime;
1103global['xuuid'] = xuuid;
1104//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFzZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbImJhc2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSxpQkF5M0JBOztBQXozQkEsT0FBTyxDQUFDLEdBQUcsQ0FBQyxFQUFFLEdBQUcsZUFBZSxDQUFBO0FBQ2hDLE9BQU8sQ0FBQyxHQUFHLENBQUMsNEJBQTRCLEdBQUcsR0FBRyxDQUFBO0FBQzlDLDRCQUF5QjtBQUN6Qix1Q0FBbUM7QUFDbkMseUNBQTZHO0FBQzdHLHFDQUFpRDtBQUNqRCw4QkFBK0I7QUFFL0IsSUFBTSxJQUFJLEdBQUcsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFBO0FBQzVCLElBQU0sZ0JBQWdCLEdBQUcsT0FBTyxDQUFDLG9CQUFvQixDQUFDLENBQUE7QUFDdEQsSUFBTSxNQUFNLEdBQUcsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFBO0FBQ2hDLElBQU0sWUFBWSxHQUFHLE9BQU8sQ0FBQyxlQUFlLENBQUMsQ0FBQTtBQUM3QyxJQUFNLEtBQUssR0FBRyxPQUFPLENBQUMsWUFBWSxDQUFDLENBQUE7QUFDbkMsSUFBTSxDQUFDLEdBQUcsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFBO0FBQzNCLElBQU0sTUFBTSxHQUFHLE9BQU8sQ0FBQyxRQUFRLENBQUMsQ0FBQTtBQUNoQyxJQUFNLE1BQU0sR0FBRyxPQUFPLENBQUMsUUFBUSxDQUFDLENBQUE7QUFDaEMsSUFBTSxXQUFXLEdBQUcsT0FBTyxDQUFDLGFBQWEsQ0FBQyxDQUFBO0FBQzFDLHlDQUF5QztBQUN6QyxpREFBaUQ7QUFDakQsa0NBQWtDO0FBQ2xDLCtEQUErRDtBQUMvRCxzRUFBc0U7QUFDdEUsOENBQThDO0FBQzlDLFdBQVc7QUFDWCxLQUFLO0FBQ0wsSUFBTSxhQUFhLEdBQUcsT0FBTyxDQUFDLGVBQWUsQ0FBQyxDQUFBO0FBQzlDLElBQU0sTUFBTSxHQUFHLE9BQU8sQ0FB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QyxVQUFVLENBQUMsR0FBRyxrQkFBUSxDQUFBO0FBQzdCLE1BQU0sQ0FBQyxPQUFPLENBQUMsR0FBRyxlQUFLLENBQUE7QUFDdkIsTUFBTSxDQUFDLFFBQVEsQ0FBQyxHQUFHLGdCQUFNLENBQUE7QUFDekIsTUFBTSxDQUFDLFFBQVEsQ0FBQyxHQUFHLE1BQU0sQ0FBQTtBQUN6QixNQUFNLENBQUMsT0FBTyxDQUFDLEdBQUcsS0FBSyxDQUFBO0FBQ3ZCLE1BQU0sQ0FBQyxTQUFTLENBQUMsR0FBRyxPQUFPLENBQUE7QUFDM0IsTUFBTSxDQUFDLFFBQVEsQ0FBQyxHQUFHLE1BQU0sQ0FBQTtBQUN6QixNQUFNLENBQUMsWUFBWSxDQUFDLEdBQUcsSUFBSSxxQkFBUyxFQUFFLENBQUEsQ0FBQyxhQUFhO0FBQ3BELE1BQU0sQ0FBQyxPQUFPLENBQUMsR0FBRyxLQUFLLENBQUE7QUFDdkIsTUFBTSxDQUFDLE1BQU0sQ0FBQyxHQUFHLElBQUksQ0FBQTtBQUNyQixNQUFNLENBQUMsT0FBTyxDQUFDLEdBQUcsRUFBRSxDQUFDLEtBQUssQ0FBQSxDQUFDLGdCQUFnQjtBQUMzQyxNQUFNLENBQUMsTUFBTSxDQUFDLEdBQUcsSUFBSSxDQUFBO0FBQ3JCLE1BQU0sQ0FBQyxNQUFNLENBQUMsR0FBRyxJQUFJLENBQUE7QUFDckIsTUFBTSxDQUFDLE1BQU0sQ0FBQyxHQUFHLElBQUksQ0FBQTtBQUNyQixNQUFNLENBQUMsZUFBZSxDQUFDLEdBQUcsYUFBYSxDQUFBO0FBQ3ZDLE1BQU0sQ0FBQyxlQUFlLENBQUMsR0FBRyxhQUFhLENBQUE7QUFDdkMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxHQUFHLElBQUksQ0FBQTtBQUNyQixNQUFNLENBQUMsT0FBTyxDQUFDLEdBQUcsS0FBSyxDQUFBO0FBQ3ZCLE1BQU0sQ0FBQyxPQUFPLENBQUMsR0FBRyxLQUFLLENBQUEiLCJzb3VyY2VzQ29udGVudCI6WyJwcm9jZXNzLmVudi5UWiA9ICdBc2lhL1NoYW5naGFpJ1xucHJvY2Vzcy5lbnYuTk9ERV9UTFNfUkVKRUNUX1VOQVVUSE9SSVpFRCA9ICcwJ1xuaW1wb3J0ICdyZWZsZWN0LW1ldGFkYXRhJ1xuaW1wb3J0IHtDb250YWluZXJ9IGZyb20gJ2ludmVyc2lmeSdcbmltcG9ydCB7Z2V0Q29ubmVjdGlvbk1hbmFnZXIsIENvbm5lY3Rpb24sIEJhc2VFbnRpdHksIGdldFJlcG9zaXRvcnksIFNlbGVjdFF1ZXJ5QnVpbGRlcn0gZnJvbSAnQGJ4anMvdHlwZW9ybSdcbmltcG9ydCB7eHNlc3Npb24sIHh1c2VyLCB4Y2FjaGV9IGZyb20gJy4vc2Vzc2lvbidcbmltcG9ydCAqIGFzICQkIGZyb20gJy4vcGx1Z2lucydcblxuY29uc3QgcGF0aCA9IHJlcXVpcmUoJ3BhdGgnKVxuY29uc3QgRXJyb3JTdGFja1BhcnNlciA9IHJlcXVpcmUoJ2Vycm9yLXN0YWNrLXBhcnNlcicpXG5jb25zdCBjb29raWUgPSByZXF1aXJlKCdjb29raWUnKVxuY29uc3QgTW9iaWxlRGV0ZWN0ID0gcmVxdWlyZSgnbW9iaWxlLWRldGVjdCcpXG5jb25zdCBmZXRjaCA9IHJlcXVpcmUoJ25vZGUtZmV0Y2gnKVxuY29uc3QgXyA9IHJlcXVpcmUoJ2xvZGFzaCcpXG5jb25zdCBtb21lbnQgPSByZXF1aXJlKCdtb21lbnQnKVxuY29uc3QgZXh0ZW5kID0gcmVxdWlyZSgnZXh0ZW5kJylcbmNvbnN0IHF1ZXJ5c3RyaW5nID0gcmVxdWlyZSgncXVlcnlzdHJpbmcnKVxuLy8gY29uc3QgcGFyYW1ldGVyID0gcmVxdWlyZSgncGFyYW1ldGVyJylcbi8vIGNvbnN0IHBhcmFtZXRlckNoZWNrSW5zdGFuY2UgPSBuZXcgcGFyYW1ldGVyKHtcbi8vICAgICAvLyB0cmFuc2xhdGU6IGZ1bmN0aW9uICgpIHtcbi8vICAgICAvLyAgICAgdmFyIGFyZ3MgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMpO1xuLy8gICAgIC8vICAgICAvLyBBc3N1bWUgdGhlcmUgaGF2ZSBJMThuLnQgbWV0aG9kIGZvciBjb252ZXJ0IGxhbmd1YWdlLlxuLy8gICAgIC8vICAgICByZXR1cm4gSTE4bi50LmFwcGx5KEkxOG4sIGFyZ3MpO1xuLy8gICAgIC8vIH1cbi8vIH0pXG5jb25zdCBjaXJjdWxhcl9qc29uID0gcmVxdWlyZShcImNpcmN1bGFyLWpzb25cIilcbmNvbnN0IG1vY2tqcyA9IHJlcXVpcmUoJ21vY2tqcycpXG5jb25zdCBzaG9ydGlkID0gcmVxdWlyZSgnc2hvcnRpZCcpXG5jb25zdCB2YWxpZGF0b3JqcyA9IHJlcXVpcmUoJ3ZhbGlkYXRvcmpzJylcbmNvbnN0IGNyb3NzX3NwYXduID0gcmVxdWlyZSgnY3Jvc3Mtc3Bhd24nKVxuY29uc3QgQUNNQ2xpZW50ID0gcmVxdWlyZSgnYW1iZXJfdXRmLTgnKVxuY29uc3QgY28gPSByZXF1aXJlKCdjbycpXG5cbi8vIEZJWE1FIEhBQ0vljp/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+WvueixoeeahEpTT07lrZfnrKbkuLLlhoXlrrnnmoTlrozmlbTovpPlh7rvvIlcbiAgICBsZXQgc291cmNlID0gX19nZXRfYmFzZV9mdW5jX2NhbGxlcl9zb3VyY2VfcG9zaXRpb24oKSArICdbJyArIHhub3coJ1lZWVktTU0tREQgSEg6bW06c3MuU1NTJykgKyAnXSdcbiAgICBsZXQgb3V0cHV0ID0gY2lyY3VsYXJfanNvbi5zdHJpbmdpZnkoWy4uLmFyZ3NdLCBudWxsLCA0KVxuICAgIGlmIChnbG9iYWxbJ19fZW52X18nXSAhPSAncHJvZCcgJiYgIS9eXFwvY29kZVxcL25vZGVfbW9kdWxlcy8udGVzdChfX2Rpcm5hbWUpKSB7XG4gICAgICAgIC8vIOaJk+WNsOWIsOaOp+WItuWPsOS4gOS7veaXpeW/lyjlnKjpmL/ph4zkupHpnZ7nur/kuIpGQ+eOr+Wig+S4rSlcbiAgICAgICAgY29uc29sZS5sb2cuYXBwbHkodW5kZWZpbmVkLCBbc291cmNlICsgb3V0cHV0XSlcbiAgICAgICAgLy8g5YaZ5pel5b+X5paH5Lu25YiwL3RtcOS4i+S4tOaXtuWkhOeQhuS4gOS4iyBUT0RPIOmcgOimgeaUueS4uuexu+S8vGxvZzRq55qE5pys5Zyw5pel5b+X5bqT5LuF5Zyo6Z2e57q/5LiK546v5aKD5L2/55So5pa55L6/5byA5Y+R5Y2V5py65pel5bi45py65Zmo5LiK6LCD6K+V44CCXG4gICAgICAgIGNvbnN0IGZzID0gcmVxdWlyZSgnZnMnKVxuICAgICAgICBjb25zdCBsb2dGaWxlUGF0aCA9IHByb2Nlc3MuZW52WydOT0RFX0xPR0ZJTEUnXSA/IHByb2Nlc3MuZW52WydOT0RFX0xPR0ZJTEUnXSA6ICcvdG1wL2J4anMubG9nJ1xuICAgICAgICBmcy5hcHBlbmRGaWxlU3luYyhsb2dGaWxlUGF0aCwgc291cmNlICsgb3V0cHV0ICsgXCJcXHJcXG5cIilcbiAgICB9IGVsc2Uge1xuICAgICAgICAvLyDnlJ/kuqfnjq/looPkuIvlj6rmiZPljbDliLDmjqfliLblj7Dnu5HlrprnmoRTTFPml6Xlv5fmnI3liqHlmajkuIrvvIzlubbkuJTpnIDopoHljrvpmaTmjonmjaLooYzkv6Hmga/lkKbliJnmiZPljbDkvJrkuI3mraPluLjjgIJcbiAgICAgICAgLy8g5Y676Zmk5o6J5o2i6KGM5pa55L6/5pa55L6/U0xT5LiK55qE5pel5b+X6L6T5Ye65o6S54mI5pi+56S6XG4gICAgICAgIG91dHB1dCA9IG91dHB1dC5yZXBsYWNlKC9cXHIvZywgJycpLnJlcGxhY2UoL1xcbi9nLCAnJylcbiAgICAgICAgY29uc29sZS5sb2cuYXBwbHkodW5kZWZpbmVkLCBbc291cmNlICsgb3V0cHV0XSlcbiAgICB9XG59XG5cbi8vIC8vIOWwhuivpue7humUmeivr+S/oeaBr+WPiuaXtuWPkemAgeWIsOmSiemSiee+pOS4iuWunuaXtuWPjemmiOe7mee7tOaKpOiAhVxuLy8gYXdhaXQgeHdhcm4oe1xuLy8gICAgIGNvZGUsXG4vLyAgICAgLy8gVE9ETyDlpoLkvZXorqTor4HpgJrov4fkuobojrflj5bliLDnlKjmiLfkv6Hmga/kuZ/pnIDopoHlj5HpgIHov4fljrvvvIzmlrnkvr/ogZTns7vlr7nmjqXkurrlkZjov5vooYznq4vliLvpl67popjlpITnkIblj43ppojjgIJcbi8vICAgICBtZXNzYWdlLFxuLy8gICAgIHN0YWNrLFxuLy8gICAgIHBhcmFtLFxuLy8gfSlcbi8vIOWwhuivpue7humUmeivr+S/oeaBr+WPiuaXtuWPkemAgeWIsOmSiemSiee+pOS4iuWunuaXtuWPjemmiOe7mee7tOaKpOiAhVxuLy8g6ZKJ6ZKJSU3nvqTmnLrlmajkurrmiqXorabpgJrnn6VcbmFzeW5jIGZ1bmN0aW9uIHh3YXJuKC4uLmFyZ3MpIHtcbiAgICAvLyDlvpfliLB4d2FybuaWueazleiiq+iwg+eUqOeahOS9jee9rlxuICAgIGxldCBzb3VyY2UgPSBfX2dldF9iYXNlX2Z1bmNfY2FsbGVyX3NvdXJjZV9wb3NpdGlvbigpXG5cbiAgICAvLyDlr7nkuo7lvILluLjlj4LmlbDorablkYrkv6Hmga/ov5vooYzplJnor6/lhoXlrrnmoIflh4bop6PmnpBcbiAgICBpZiAoYXJncy5sZW5ndGggPiAwICYmIGFyZ3NbMF0gaW5zdGFuY2VvZiBFcnJvcikge1xuICAgICAgICBhcmdzWzBdID0geGVycm9yKGFyZ3NbMF0pXG4gICAgfVxuXG4gICAgbGV0IG91dCA9IFtzb3VyY2UsIHhub3coJ1lZWVktTU0tREQgSEg6bW06c3MuU1NTJyksIHsuLi5hcmdzfV1cblxuICAgIC8vIOS7jumFjee9ruS/oeaBr+S4reivu+WPluaKpeitpumAmuefpeS6uuaJi+acuuWIl+ihqOWSjOWvueW6lOeahOe+pOacuuWZqOS6uueahHdlYmhvb2vnmoRhY2Nlc3NfdG9rZW7kv6Hmga9cbiAgICBsZXQgYWNjZXNzX3Rva2VuID0geGNvbmZpZygnZnJhbWV3b3JrLndhcm4uZGluZ2RpbmcuYWNjZXNzX3Rva2VuJylcbiAgICBsZXQgbW9iaWxlcyA9IHhjb25maWcoJ2ZyYW1ld29yay53YXJuLmRpbmdkaW5nLm1vYmlsZXMnKVxuICAgIGlmICghYWNjZXNzX3Rva2VuIHx8ICFtb2JpbGVzKSB7XG4gICAgICAgIGFjY2Vzc190b2tlbiA9ICcwMjBhMDllYWM1ZjJmYTMyMGFlODUxNDQyZDVlMTllMjM2OTNjNjRhZDIyNTVjODUzNTRiNGE0OWE1YTQ4ZDM1J1xuICAgICAgICBtb2JpbGVzID0gWycxNTM4MTE1MTM0NiddXG4gICAgfVxuXG4gICAgYXdhaXQgeHBvc3QoYGh0dHBzOi8vb2FwaS5kaW5ndGFsay5jb20vcm9ib3Qvc2VuZD9hY2Nlc3NfdG9rZW49JHthY2Nlc3NfdG9rZW59YCwge1xuICAgICAgICBtc2d0eXBlOiAndGV4dCcsXG4gICAgICAgIHRleHQ6IHtcbiAgICAgICAgICAgIGNvbnRlbnQ6IG91dFxuICAgICAgICB9LFxuICAgICAgICBhdDoge1xuICAgICAgICAgICAgYXRNb2JpbGVzOiBtb2JpbGVzLFxuICAgICAgICAgICAgaXNBdEFsbDogZmFsc2VcbiAgICAgICAgfVxuICAgIH0pXG5cbiAgICAvLyDnur/kuIpTTFPml6Xlv5fkuIrkuZ/kv53lrZjkuIDku71cbiAgICAvLyBjb25zb2xlLndhcm4ob3V0KVxuICAgIHhsb2cob3V0KVxufVxuXG4vLyDmjZXojrfmnKrnm5HlkKzliLDnmoTlvILluLjorrDlvZXlkI7nm7TmjqXpgIDlh7rvvIjov5DooYzloIbmoIjlt7Lnu4/noLTlnY/nm7TmjqXorrDlvZXml6Xlv5flkI7lvILluLjpgIDlh7rljbPlj6/vvIznlLHlpJbpg6jnm5Hmjqfoh6rliqjph43lkK/vvIlcbnByb2Nlc3Mub24oJ3VuY2F1Z2h0RXhjZXB0aW9uJywgYXN5bmMgZnVuY3Rpb24gKGVycikge1xuICAgIHhsb2coeGVycm9yKGVycikpXG4gICAgYXdhaXQgeHdhcm4oZXJyKVxuICAgIHByb2Nlc3MuZXhpdCgtMSlcbn0pXG5cbi8vIOiusOW9lWF3YWl0L2FzeW5j5Lit5Ye6546w5pyq5o2V6I6355qE5byC5bi46ZSZ6K+vXG5wcm9jZXNzLm9uKCd1bmhhbmRsZWRSZWplY3Rpb24nLCBhc3luYyAocmVhc29uLCBwKSA9PiB7XG4gICAgeGxvZygnVW5oYW5kbGVkIFJlamVjdGlvbiBhdDogUHJvbWlzZScsIHAsICdyZWFzb246JywgcmVhc29uKTtcbiAgICAvLyBhcHBsaWNhdGlvbiBzcGVjaWZpYyBsb2dnaW5nLCB0aHJvd2luZyBhbiBlcnJvciwgb3Igb3RoZXIgbG9naWMgaGVyZVxuICAgIGF3YWl0IHh3YXJuKHJlYXNvbiwgcClcbiAgICBwcm9jZXNzLmV4aXQoLTEpXG59KVxuXG4vLyBhc3luYy9hd2FpdOeahOmdnumYu+WhnuW8guatpeW7tui/n+aWueazle+8jOeUqOS6juiwg+ivlemYu+Whnueoi+W6j+eahOaJp+ihjOi/m+ihjOWNleatpeiwg+ivleeahOaViOaenOOAglxuY29uc3Qgc2xlZXAgPSByZXF1aXJlKCdzbGVlcC1hc3luYycpKClcblxuZXhwb3J0IGZ1bmN0aW9uIHhzbGVlcChtczogbnVtYmVyID0gLTEpIHtcbiAgICBpZiAobXMgPD0gMCkge1xuICAgICAgICBtcyA9IDUwICogMzY1ICogMjQgKiAzNjAwICogMTAwMCAvLyA1MOW5tOacgOWkp+aVsOinhuS4uuawuOS5hemYu+WhnuaWueS+v+aWreeCueWNleatpeiwg+ivlemXrumimFxuICAgIH1cbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgc2xlZXAuc2xlZXAobXMsICgpID0+IHtcbiAgICAgICAgICAgICAgICByZXNvbHZlKClcbiAgICAgICAgICAgIH0pXG4gICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgeGxvZyh4ZXJyb3IoZXJyKSlcbiAgICAgICAgICAgIHJlc29sdmUoKVxuICAgICAgICAgICAgLy8geHRocm93KGVycixyZWplY3QpXG4gICAgICAgIH1cbiAgICB9KVxufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24geHBvc3QodXJsOiBzdHJpbmcsIHBhcmFtPzogeyBbcHJvcE5hbWU6IHN0cmluZ106IGFueSB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhlYWRlcnM/OiB7IFtwcm9wTmFtZTogc3RyaW5nXTogYW55IH0sIHRpbWVvdXQ6IG51bWJlciA9IDMwMDApIHtcbiAgICAvLyBUT0RPIOe6v+S4iua1i+ivleS4jeeos+Wumui2heaXtuaaguaXtuW/veeVpeaOiemAmui/h+i/m+eoi+acgOWkp+i/kOihjOaXtumXtOWOu+aOp+WItui2heaXtuWksei0pVxuICAgIHRpbWVvdXQgPSA1MDAwIC8vIC0xIOS4jeihjOe6v+S4iuS8muiiq+mYu+WhnuS9j+WDteatu1xuICAgIGxldCByZXM6IGFueSA9IG51bGxcbiAgICBsZXQganNvbjogYW55ID0gbnVsbFxuICAgIGxldCB0ZXh0OiBhbnkgPSBudWxsXG4gICAgdHJ5IHtcbiAgICAgICAgcmVzID0gYXdhaXQgZmV0Y2godXJsLCB7XG4gICAgICAgICAgICBtZXRob2Q6ICdQT1NUJyxcbiAgICAgICAgICAgIGJvZHk6IEpTT04uc3RyaW5naWZ5KHBhcmFtKSxcbiAgICAgICAgICAgIGhlYWRlcnM6IHsnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL2pzb24nLCAuLi5oZWFkZXJzfSxcbiAgICAgICAgICAgIHRpbWVvdXQ6IHRpbWVvdXQgPD0gMCA/IDAgOiB0aW1lb3V0LCAvLyDpu5jorqQz56eS6LaF5pe25o6l5Y+j6L+U5Zue6YG/5YWN5YO15q27XG4gICAgICAgIH0pXG4gICAgICAgIHRleHQgPSBhd2FpdCByZXMudGV4dCgpIC8vIOino+aekOWHuuWujOaVtOeahOi/lOWbnuWGheWuuemBv+WFjUhUTUzku6Xlj4rpnZ7ms5XmoLzlvI/kv6Hmga/kvr/kuo7mraPnoa7miqXplJnlrprkvY3lkI7nq6/mjqXlj6PplJnor69cbiAgICAgICAganNvbiA9IEpTT04ucGFyc2UodGV4dClcbiAgICAgICAgcmV0dXJuIGpzb25cbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgeHRocm93KGVyciwge3VybCwgcGFyYW0sIGhlYWRlcnMsIHRleHR9KVxuICAgIH1cbn1cblxuLy8g6buY6K6k6LaF5pe2MzAwMOavq+enklxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHhnZXQodXJsOiBzdHJpbmcsIHBhcmFtPzogeyBbcHJvcE5hbWU6IHN0cmluZ106IGFueSB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgaGVhZGVycz86IHsgW3Byb3BOYW1lOiBzdHJpbmddOiBhbnkgfSwgdGltZW91dDogbnVtYmVyID0gMzAwMCkge1xuICAgIC8vIFRPRE8g57q/5LiK5rWL6K+V5LiN56iz5a6a6LaF5pe25pqC5pe25b+955Wl5o6J6YCa6L+H6L+b56iL5pyA5aSn6L+Q6KGM5pe26Ze05Y675o6n5Yi26LaF5pe25aSx6LSlXG4gICAgdGltZW91dCA9IDUwMDAgLy8gLTEg5LiN6KGM57q/5LiK5Lya6KKr6Zi75aGe5L2P5YO15q27XG4gICAgbGV0IHJlczogYW55ID0gbnVsbFxuICAgIGxldCBqc29uOiBhbnkgPSBudWxsXG4gICAgbGV0IHRleHQ6IGFueSA9IG51bGxcbiAgICB0cnkge1xuICAgICAgICB1cmwgPSB1cmwgKyAocGFyYW0gPyAnPycgOiAnJykgKyBxdWVyeXN0cmluZy5zdHJpbmdpZnkocGFyYW0pXG4gICAgICAgIHJlcyA9IGF3YWl0IGZldGNoKHVybCwge1xuICAgICAgICAgICAgbWV0aG9kOiAnR0VUJyxcbiAgICAgICAgICAgIGhlYWRlcnM6IHsnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL2pzb24nLCAuLi5oZWFkZXJzfSxcbiAgICAgICAgICAgIHRpbWVvdXQ6IHRpbWVvdXQgPD0gMCA/IDAgOiB0aW1lb3V0LCAvLyDpu5jorqQz56eS6LaF5pe25o6l5Y+j6L+U5Zue6YG/5YWN5YO15q27XG4gICAgICAgIH0pXG4gICAgICAgIHRleHQgPSBhd2FpdCByZXMudGV4dCgpIC8vIOino+aekOWHuuWujOaVtOeahOi/lOWbnuWGheWuuemBv+WFjUhUTUzku6Xlj4rpnZ7ms5XmoLzlvI/kv6Hmga/kvr/kuo7mraPnoa7miqXplJnlrprkvY3lkI7nq6/mjqXlj6PplJnor69cbiAgICAgICAganNvbiA9IEpTT04ucGFyc2UodGV4dClcbiAgICAgICAgcmV0dXJuIGpzb25cbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgeHRocm93KGVyciwge3VybCwgcGFyYW0sIGhlYWRlcnMsIHRleHR9KVxuICAgIH1cbn1cblxuLy8gMzAy5Li05pe26YeN5a6a5ZCR6Lez6L2s5a6e546wXG5leHBvcnQgZnVuY3Rpb24geHJlZGlyZWN0KHVybDogc3RyaW5nLCBwYXJhbTogYW55ID0ge30pIHtcbiAgICAvLyBUT0RPIOWkmuS4queoi+W6j+WunuS+i+W5tuWPkeWkhOeQhueahOaXtuWAmeWtmOWcqOaXtuW6j+mXrumimOS4jeiDveS/neivgeWFqOWxgOWPmOmHj+iiq+WHhuehrua4heepuuOAglxuICAgIC8vIOajgOafpeW6lOeUqOmHjeWkjeiuvue9rumHjeWumuWQkeWcsOWdgOacquWPiuaXtnJldHVybui/lOWbnuaOp+WItuWZqOmXrumimFxuICAgIHhhc3NlcnQoZ2xvYmFsWydfX3JlZGlyZWN0X3VybF9fJ10gPT09IHVuZGVmaW5lZClcbiAgICBpZiAocGFyYW0pIHtcbiAgICAgICAgeGFzc2VydChfLmlzUGxhaW5PYmplY3QocGFyYW0pKVxuICAgICAgICAvLyDliKDpmaRwYXJhbeS4reS4pOS4quahhuaetumihOWumuS5ieWPguaVsF9fdXJsX1/lkoxfX2FwaV9f5LiN5YWB6K646L+b6KGM5Y+C5pWw5Lyg6YCS77yI56aB5q2i5Lia5Yqh6YC76L6R5L2/55So6YG/5YWN5qGG5p625ZCO57ut5Y2H57qn5Lul5Y+K5LiO55+t572R5Z2A5Yqf6IO95Yay56qB77yJXG4gICAgICAgIGRlbGV0ZSBwYXJhbS5fX2FwaV9fXG4gICAgICAgIGRlbGV0ZSBwYXJhbS5fX3VybF9fXG4gICAgICAgIC8vIOihpemineWklueahOmZhOWKoOWPguaVsFxuICAgICAgICBpZiAoL1xcPy8udGVzdCh1cmwpKSB7XG4gICAgICAgICAgICB1cmwgKz0gJyYnXG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB1cmwgKz0gJz8nXG4gICAgICAgIH1cbiAgICAgICAgdXJsICs9IHF1ZXJ5c3RyaW5nLnN0cmluZ2lmeShwYXJhbSlcbiAgICB9XG4gICAgZ2xvYmFsWydfX3JlZGlyZWN0X3VybF9fJ10gPSB1cmxcbn1cblxuLy8g5aaC5p6c5Y+q5pyJa2V55Y+C5pWw6KGo56S66K+75Y+W5bGe5oCn77yI57y655yB5YC85Li6dW5kZWZpbmVk77yJ77yM5aaC5p6ca2V55Li656m66KGo56S66K+75Y+W5omA5pyJ55qE6K+35rGCY29va2llc+WxnuaAp++8jOWQpuWImeihqOekuuWTjeW6lOiuvue9rmNvb2tpZXNcbmV4cG9ydCBmdW5jdGlvbiB4Y29va2llKGtleT86IHN0cmluZywgdmFsdWU/OiBzdHJpbmcsIG9wdGlvbj86IHt9KTogYW55IHtcbiAgICBpZiAoIWFyZ3VtZW50cy5sZW5ndGgpIHtcbiAgICAgICAgLy8g6K+75Y+W5omA5pyJ55qE6K+35rGCY29va2llc+WxnuaAp29iamVjdFxuICAgICAgICByZXR1cm4gZ2xvYmFsWydfX3JlcXVlc3RfY29va2llc19fJ10gPyBnbG9iYWxbJ19fcmVxdWVzdF9jb29raWVzX18nXSA6IHt9XG4gICAgfSBlbHNlIGlmIChhcmd1bWVudHMubGVuZ3RoID09IDEpIHtcbiAgICAgICAgcmV0dXJuIGtleSA/IHhjb29raWUoKVtrZXldIDogdW5kZWZpbmVkXG4gICAgfSBlbHNlIHtcbiAgICAgICAgaWYgKGdsb2JhbFsnX19yZXNwb25kX2Nvb2tpZXNfXyddID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIGdsb2JhbFsnX19yZXNwb25kX2Nvb2tpZXNfXyddID0ge31cbiAgICAgICAgfVxuICAgICAgICBpZiAoa2V5KSB7XG4gICAgICAgICAgICAvLyBDT09LSUVT57y655yB5bGe5oCn6K6+572u77yI5pyJ5pWI5pe26Ze0MjTlsI/ml7blubbkuJTnu5/kuIDlhbPogZTliLDmoLnpobXpnaLkuIrojrflj5ZDT09LSUVT5YC877yJXG4gICAgICAgICAgICBvcHRpb24gPSB4YXNzaWduKHtwYXRoOiAnLycsIG1heEFnZTogMjQgKiAzNjAwfSwgb3B0aW9uKVxuICAgICAgICAgICAgZ2xvYmFsWydfX3Jlc3BvbmRfY29va2llc19fJ11ba2V5XSA9IGNvb2tpZS5zZXJpYWxpemUoa2V5LCB2YWx1ZSwgb3B0aW9uKVxuICAgICAgICB9XG4gICAgICAgIHJldHVyblxuICAgIH1cbn1cblxuLy8g5Yik5patdXNlci1hZ2VudOivt+axguaYr+WQpuS4uuenu+WKqOerr1xuZnVuY3Rpb24geGlzbW9iaWxlKCk6IGJvb2xlYW4ge1xuICAgIGNvbnN0IG1kID0gbmV3IE1vYmlsZURldGVjdChnbG9iYWxbJ19fdXNlcl9hZ2VudF9fJ10pXG4gICAgcmV0dXJuICEhbWQubW9iaWxlKClcbn1cblxuZnVuY3Rpb24geGFzc2lnbih0YXJnZXQsIHNvdXJjZSwgLi4uYXJncykge1xuICAgIGNvbnN0IHBhcmFtID0gW3RydWUsIHRhcmdldCwgc291cmNlLCAuLi5hcmdzXVxuICAgIHJldHVybiBleHRlbmQuYXBwbHkobnVsbCwgcGFyYW0pXG59XG5cbi8vIOafpeivomFwcC9jb25maWfnm67lvZXkuIvnmoTlupTnlKjphY3nva7mlbDmja5cbmZ1bmN0aW9uIHhjb25maWcocGF0aDogc3RyaW5nLCBkZWZhdWx0VmFsdWU6IGFueSA9IHVuZGVmaW5lZCkge1xuICAgIGlmIChnbG9iYWxbJ19fY29uZmlnX18nXSkge1xuICAgICAgICByZXR1cm4gXy5nZXQoZ2xvYmFsWydfX2NvbmZpZ19fJ10sIHBhdGgsIGRlZmF1bHRWYWx1ZSlcbiAgICB9XG5cbiAgICBjb25zdCBmcCA9IHJlcXVpcmUoJ3BhdGgnKVxuICAgIGNvbnN0IGZzID0gcmVxdWlyZSgnZnMnKVxuICAgIC8vIOiHquWKqOiOt+WPlmFwcC9jb25maWfnmoTnm7jlr7not6/lvoTnm67lvZXkvY3nva7lvpfliLDmoLnot6/lvoTnmoTkvY3nva5cbiAgICBsZXQgY29uZmlnX3BhdGggPSAnJ1xuICAgIGlmIChfX2Rpcm5hbWUuaW5jbHVkZXMoJy9ub2RlX21vZHVsZXMvQGJ4anMvYmFzZS8nKSkge1xuICAgICAgICAvLyDlnKjlupTnlKjnm67lvZXkuItcbiAgICAgICAgY29uZmlnX3BhdGggPSBmcC5qb2luKF9fZGlybmFtZSwgJy4uLy4uLy4uLy4uL2FwcC9jb25maWcnKVxuICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIOWcqGF4anPlupPlvIDlj5Hnm67lvZXkuItcbiAgICAgICAgY29uZmlnX3BhdGggPSBmcC5qb2luKF9fZGlybmFtZSwgJy4uL2FwcC9jb25maWcnKVxuICAgIH1cblxuICAgIC8vIOiHquWKqOivhuWIq+WIpOaWrei/kOihjOeOr+Wig2dsb2JhbFsnX19lbnZfXydd5bm25LiU5Yqg6L295a+55bqU55qEYmFzZeaVsOaNruWSjGVuduaVsOaNrlxuICAgIGNvbnN0IGNvbmZpZ19iYXNlX3BhdGggPSBjb25maWdfcGF0aCArICcvY29uZmlnLmJhc2UuJyArIGdldF9zdWZmaXhfdHNfb3JfanMoKVxuICAgIGNvbnN0IGNvbmZpZ19lbnZfcGF0aCA9IGNvbmZpZ19wYXRoICsgYC9jb25maWcuJHtnbG9iYWxbJ19fZW52X18nXX0uYCArIGdldF9zdWZmaXhfdHNfb3JfanMoKVxuICAgIGlmICghZnMuZXhpc3RzU3luYyhjb25maWdfYmFzZV9wYXRoKSkge1xuICAgICAgICByZXR1cm4gZGVmYXVsdFZhbHVlXG4gICAgfVxuICAgIGxldCBjb25maWdfYmFzZSA9IHJlcXVpcmUoY29uZmlnX2Jhc2VfcGF0aCkuZGVmYXVsdFxuICAgIGxldCBjb25maWdfZW52ID0ge31cbiAgICBpZiAoZnMuZXhpc3RzU3luYyhjb25maWdfZW52X3BhdGgpKSB7XG4gICAgICAgIGNvbmZpZ19lbnYgPSByZXF1aXJlKGNvbmZpZ19lbnZfcGF0aCkuZGVmYXVsdFxuICAgIH1cbiAgICAvLyBidWdmaXggT2JqZWN0LmFzc2lnbuS4jeaUr+aMgea3seW6puaLt+i0nemXrumimFxuICAgIC8vIGdsb2JhbFsnX19jb25maWdfXyddID0gT2JqZWN0LmFzc2lnbih7fSwgY29uZmlnX2Jhc2UsIGNvbmZpZ19lbnYpXG4gICAgLy8gZ2xvYmFsWydfX2NvbmZpZ19fJ10gPSBfLmFzc2lnbih7fSwgY29uZmlnX2VudiwgY29uZmlnX2Jhc2UpXG4gICAgZ2xvYmFsWydfX2NvbmZpZ19fJ10gPSB4YXNzaWduKHt9LCBjb25maWdfYmFzZSwgY29uZmlnX2VudilcbiAgICByZXR1cm4gXy5nZXQoZ2xvYmFsWydfX2NvbmZpZ19fJ10sIHBhdGgsIGRlZmF1bHRWYWx1ZSlcbn1cblxuYXN5bmMgZnVuY3Rpb24geGNvbm5lY3QoY2FsbGJhY2s6IChjb25uZWN0OiBDb25uZWN0aW9uKSA9PiBQcm9taXNlPGFueT4sIGNvbmZpZyA9ICdkZWZhdWx0Jykge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZShhc3luYyAocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgIGxldCBjZmcgPSB7fSBhcyBhbnlcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGNmZyA9IHhhc3NpZ24oe30sIHhjb25maWcoJ3BsdWdpbnMuZGF0YWJhc2UuZGVmYXVsdCcsIHt9KSlcbiAgICAgICAgICAgIHhhc3NlcnQoIV8uaXNFbXB0eShjZmcpLCBFUlIkUEFSQU0sIHtjb25maWd9KVxuICAgICAgICAgICAgLy8g5by65Yi26KGl5LiK57qm5a6a55qE5a6e5L2T5a2Y5pS+6Lev5b6E5a6a5LmJ5L2N572u77yI5LiN5YWB6K646YWN572u5piv57qm5a6a6KeE6IyD77yJXG4gICAgICAgICAgICBpZiAoX19kaXJuYW1lLmluY2x1ZGVzKCcvbm9kZV9tb2R1bGVzL0BieGpzL2Jhc2UvJykpIHtcbiAgICAgICAgICAgICAgICAvLyDlnKjlupTnlKjnm67lvZXkuItcbiAgICAgICAgICAgICAgICBjZmdbJ2VudGl0aWVzJ10gPSBbXG4gICAgICAgICAgICAgICAgICAgIHBhdGguam9pbihfX2Rpcm5hbWUsICcuLi8uLi8uLi8uLi9hcHAvcGx1Z2lucy9kYXRhYmFzZS9lbnRpdHkvKi4nICsgZ2V0X3N1ZmZpeF90c19vcl9qcygpKVxuICAgICAgICAgICAgICAgIF1cbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgLy8g5ZyoYXhqc+W6k+W8gOWPkeebruW9leS4i1xuICAgICAgICAgICAgICAgIGNmZ1snZW50aXRpZXMnXSA9IFtcbiAgICAgICAgICAgICAgICAgICAgcGF0aC5qb2luKF9fZGlybmFtZSwgJy4uL2FwcC9wbHVnaW5zL2RhdGFiYXNlL2VudGl0eS8qLicgKyBnZXRfc3VmZml4X3RzX29yX2pzKCkpXG4gICAgICAgICAgICAgICAgXVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8g6I635Y+W6L+e5o6l5rGg5Lit55qE6ZO+5o6lKOWFqOWxgOWPmOmHj+aooeWdl+WunuS+i+eahOS9v+eUqClcbiAgICAgICAgICAgIGNvbnN0IG1uZyA9IGdldENvbm5lY3Rpb25NYW5hZ2VyKClcbiAgICAgICAgICAgIGNvbnN0IG5hbWUgPSBjZmcubmFtZSA/IGNmZy5uYW1lIDogJ2RlZmF1bHQnXG4gICAgICAgICAgICBpZiAoIW1uZy5oYXMobmFtZSkpIHtcbiAgICAgICAgICAgICAgICBtbmcuY3JlYXRlKGNmZylcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnN0IGRiID0gbW5nLmdldChuYW1lKVxuICAgICAgICAgICAgaWYgKGdsb2JhbFsnZ19jb25uZWN0aW9uJ10gPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgIGdsb2JhbFsnZ19jb25uZWN0aW9uJ10gPSB7fVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCFkYi5pc0Nvbm5lY3RlZCkgeyAvLyBUT0RPIOmcgOimgei/m+ihjOi/nuaOpeaxoOeahOeuoeeQhlxuICAgICAgICAgICAgICAgIGdsb2JhbFsnZ19jb25uZWN0aW9uJ11bbmFtZV0gPSBkYi5jb25uZWN0KClcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGdsb2JhbFsnZ19jb25uZWN0aW9uJ11bbmFtZV0udGhlbihhc3luYyBjb25uZWN0aW9uID0+IHtcbiAgICAgICAgICAgICAgICB4YXNzZXJ0KGRiLmlzQ29ubmVjdGVkKVxuICAgICAgICAgICAgICAgIGNvbnN0IG91dCA9IGF3YWl0IGNhbGxiYWNrKGNvbm5lY3Rpb24pXG4gICAgICAgICAgICAgICAgLy8gYXdhaXQgZGIuY2xvc2UoKSAvLyB0eXBlb3Jt5rKh5pyJ6L+b6KGM6L+e5o6l5rGg55qE566h55CG5LiN6IO96L+b6KGM6ZSA5q+BXG4gICAgICAgICAgICAgICAgcmVzb2x2ZShvdXQpXG4gICAgICAgICAgICB9KS5jYXRjaChhc3luYyBlcnIgPT4ge1xuICAgICAgICAgICAgICAgIC8vIGF3YWl0IGRiLmNsb3NlKClcbiAgICAgICAgICAgICAgICB4dGhyb3coZXJyLCByZWplY3QsIHtjb25maWcsIG5hbWV9KVxuICAgICAgICAgICAgfSlcbiAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICB4dGhyb3coZXJyLCByZWplY3QsIHtjb25maWd9KVxuICAgICAgICB9XG4gICAgfSlcbn1cblxuLy8g5Yib5bu6WEJhc2VFbnRpdHnlr7nosaHlubbkuJToh6rliqjotYvlgLzliY3nq6/or7fmsYLnmoTotYvlgLzmlbDmja5cbmZ1bmN0aW9uIHhuZXc8VCBleHRlbmRzIEJhc2VFbnRpdHk+KFRZUEU6IG5ldyAoKSA9PiBULCBwYXJhbT86IGFueSwgLi4uYXJncyk6IFQge1xuICAgIC8vIOazm+Wei+WunueOsOexu+S8vOi/meS4quWKn+iDvVxuICAgIC8vIGFzc2V0ID0gbmV3IEFsaWxhbmdBc3NldCgpXG4gICAgLy8gZ2V0UmVwb3NpdG9yeShBbGlsYW5nQXNzZXQpLm1lcmdlKGFzc2V0LCBwYXJhbSBhcyBhbnkpXG4gICAgLy8gQWxpbGFuZ0Fzc2V0Lm1lcmdlKGFzc2V0LCBwYXJhbSBhcyBhbnkpXG4gICAgLy8gcmV0dXJuIGFzc2V0XG4gICAgbGV0IG9iaiA9IG5ldyBUWVBFKClcbiAgICBpZiAoXy5pc0VtcHR5KHBhcmFtKSkge1xuICAgICAgICByZXR1cm4gb2JqXG4gICAgfVxuICAgIGxldCByZXBvID0gZ2V0UmVwb3NpdG9yeTxUPihUWVBFKVxuICAgIHJlcG8ubWVyZ2UuYXBwbHkocmVwbywgW29iaiwgcGFyYW0sIC4uLmFyZ3NdKVxuICAgIHJldHVybiBvYmpcbn1cblxuLy8g5p+l6K+i5p6E6YCg5Zmo5piT55So5oCn5bCB6KOFXG5mdW5jdGlvbiB4cXVlcnk8VD4oY29ubmVjdDogQ29ubmVjdGlvbiwgVFlQRTogbmV3ICgpID0+IFQsIGFsaWFzPzogc3RyaW5nKTogU2VsZWN0UXVlcnlCdWlsZGVyPFQ+IHtcbiAgICByZXR1cm4gY29ubmVjdC5nZXRSZXBvc2l0b3J5KFRZUEUpLmNyZWF0ZVF1ZXJ5QnVpbGRlcihhbGlhcylcbn1cblxuLy8g5YiG6aG15p+l6K+i6I635Y+W5oC75pWw5Lul5Y+K5Y6f5aeL6K6w5b2V5pWw5o2uXG5hc3luYyBmdW5jdGlvbiB4Y291bnQ8VD4oc3FsOiBTZWxlY3RRdWVyeUJ1aWxkZXI8VD4sIHBhZ2U6IG51bWJlciwgc2l6ZTogbnVtYmVyKTogUHJvbWlzZTxbYW55W10gfCBudWxsLCBudW1iZXJdPiB7XG4gICAgeGFzc2VydChwYWdlID49IDEpXG4gICAgY29uc3QgW2NvdW50LCByb3dzXSA9IGF3YWl0IFByb21pc2UuYWxsKFtcbiAgICAgICAgc3FsLmdldENvdW50KCksXG4gICAgICAgIHNxbC5vZmZzZXQoKHBhZ2UgLSAxKSAqIHNpemUpLmxpbWl0KHNpemUpLmdldFJhd01hbnkoKVxuICAgIF0pXG4gICAgcmV0dXJuIFtyb3dzLCBjb3VudF1cbn1cblxuXG4vLyDot6/nlLHlj4LmlbDnmoTkv67ppbDnrKbphY3nva5cbi8vIFRPRE8g5pu05aSa5o6l5Y+j55u45YWz5Y+C5pWw55qE6YWN572u5omp5bGV77yM5L6L5aaC77ya5piv5ZCm5pSv5oyBSlNPTlBcbmZ1bmN0aW9uIHhyb3V0ZShwYXJhbTogeyBuYW1lPzogc3RyaW5nLCBkZXNjPzogc3RyaW5nLCBwYXRoPzogc3RyaW5nLCBhdXRoPzogYm9vbGVhbiwgbm93cmFwPzogYm9vbGVhbiB9KSB7XG4gICAgLy8g57y655yB5YC85aSE55CGXG4gICAgLy8gbmFtZSDmjqXlj6PlkI3np7BcbiAgICAvLyBkZXNjIOaOpeWPo+aPj+i/sFxuICAgIC8vIHBhdGgg6Lev5b6E6Lev55Sx6YeN5YaZXG4gICAgLy8gYXV0aCDmmK/lkKbpnIDopoHnmbvlvZXpibTmnYPvvIjnvLrnnIHpnIDopoHov5vooYzpibTmnYPkuLp0cnVl77yJXG4gICAgLy8gbm93cmFwIOaYr+WQpuWvueS6jkpTT07or7fmsYLov5vooYxzdWNjZXNzL2NvbnRlbnTnmoTmoIflh4bov5vooYzljIXoo4XvvIjnvLrnnIHov5vooYzljIXoo4XkuLpmYWxzZe+8iVxuICAgIHBhcmFtID0geGFzc2lnbih7bmFtZTogJycsIGRlc2M6ICcnLCBwYXRoOiAnJywgYXV0aDogdHJ1ZSwgbm93cmFwOiBmYWxzZX0sIHBhcmFtKVxuICAgIHJldHVybiBmdW5jdGlvbiAodGFyZ2V0OiBGdW5jdGlvbiwgcHJvcGVydHlLZXk6IHN0cmluZywgZGVzY3JpcHRvcjogUHJvcGVydHlEZXNjcmlwdG9yKSB7XG4gICAgICAgIC8vIFRPRE8g5rOo5YWl5Yiw57G75a6e5L6L5a6a5LmJ5Lit6L+b6KGM5YWo5bGA5byV55So5Yqo5oCB57G755qE54m55oCn5re75Yqg77yIdHJhaXTlip/og73nmoTliqjmgIHlrp7njrDvvIlcbiAgICAgICAgLy8g5Yqo5oCB57uR5a6a6Lev55Sx57G75a6e5L6L55qE5LiK5LiL5paH5bGe5oCnXG4gICAgICAgIHRhcmdldC5wcm90b3R5cGUuY29udGV4dCA9ICgpID0+IHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgcGFyYW06IHBhcmFtLCAvLyDkv53lrZjlvZPliY3mjqfliLblmajnlKjmiLflrprkuYnlj4LmlbDkv6Hmga9cbiAgICAgICAgICAgICAgICAvLyDmmK/lkKbnmbvlvZXnmoTpibTmnYPmlrnms5Xnu5/kuIDmoYbmnrblsYLpnaLkuIrnmoTlpITnkIblrp7njrDvvIzmraTlpITku4Xku4XmmK/pgJrnlKjmjqXlj6PnmoTnuqbmnZ/nmoTlrprkuYnjgIJcbiAgICAgICAgICAgICAgICBhdXRoOiBhc3luYyAoKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIC8vIOiwg+eUqOeZu+W9leWKn+iDveeahOWJjeerr+aOpeWPo+WunueOsO+8jOWPluWIsOWvueW6lOeahOWunueOsOaWueazleOAglxuICAgICAgICAgICAgICAgICAgICBpZiAocGFyYW0gJiYgcGFyYW0uYXV0aCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8g6ZyA6KaB6Ym05p2D6L+b6KGM5Lya6K+d5pyJ5pWI5oCn6L+b6KGM5ZCI5rOV5oCn5qCh6aqM5aSE55CG77yB77yBXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyDmnKrorqTor4HplJnor6/mipvlh7rlpITnkIbvvIzliY3nq6/ljZXpobXlupTnlKjmjqXlj6PmiqXplJnpgLvovpHlpITnkIbmraPnoa7plJnor6/mj5DnpLrot7PovazjgIJcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGF1dGggPSB4Z290KFlBdXRoKVxuICAgICAgICAgICAgICAgICAgICAgICAgeGFzc2VydChhd2FpdCBhdXRoLmdldExvZ2luU3RhdHVzKCksIEVSUiRVTkFVVEhPUklaRUQpXG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG59XG5cbi8vIOWujOWFqOayoeacieW/heimgeeahOWkmuS9meWumuS5ie+8jOmcgOimgemAmui/h01PQ0vlrprkuYnov5vooYznu4boioLmlbDmja7nsbvlnovnmoTmmL7mgKflrprkuYnlpITnkIbpgLvovpHpqozor4HjgIJcbi8vIC8vIOWfuuacrOaVsOaNruexu+Wei+eahOinhOiMg+aJqeWxleWumuS5ie+8jOaWueS+v0FQSeaOpeWPo+eahOWumuS5ieS7peWPiuW9ouWPguiHquWKqOmqjOivgeWQiOazleaAp++8jOW5tuS4lOS4juaVsOaNruW6k+aVsOaNruexu+Wei+S/neaMgeS4gOiHtOOAglxuLy8gdHlwZSBJTlQgPSBudW1iZXIgICAvLyDmnInnrKblj7fmlbTmlbBcbi8vIHR5cGUgVUlOVCA9IG51bWJlciAgLy8g5peg56ym5Y+35pW05pWwXG4vLyB0eXBlIERFQ0lNQUwgPSBudW1iZXIgLy8g57K+56Gu5bCP5pWwXG4vLyB0eXBlIEZMT0FUID0gbnVtYmVyIC8vIOWNleeyvuW6pua1rueCueaVsO+8iOS4jeeyvuehruWwj+aVsO+8iVxuLy8gdHlwZSBET1VCTEUgPSBudW1iZXIvLyDlj4znsr7luqbmta7ngrnmlbDvvIjkuI3nsr7noa7lsI/mlbDvvIlcbi8vIHR5cGUgQk9PTCA9IGJvb2xlYW5cbi8vIHR5cGUgU1RSID0gc3RyaW5nXG4vLyB0eXBlIERBVEUgPSBzdHJpbmcgLy8g5bm05pyI5pelICcyMDE3LTA2LTI1J1xuLy8gdHlwZSBUSU1FID0gc3RyaW5nIC8vIOaXtuWIhuenkiAnMDA6MDA6MDAnXG4vLyB0eXBlIERBVEVUSU1FID0gc3RyaW5nIC8vIOW5tOaciOaXpeaXtuWIhuenkiAnMjAxNy0wNi0yNSAwMDowMDowMCdcblxuLy8g5qih5ouf5pWw5o2u5qih5p2/5a6a5LmJ5L2/55So5pWZ56iLIGh0dHA6Ly9tb2NranMuY29tLzAuMS8jJUU2JTk1JUIwJUU2JThEJUFFJUU1JThEJUEwJUU0JUJEJThEJUU3JUFDJUE2JUU1JUFFJTlBJUU0JUI5JTg5JTIwRFBEXG5mdW5jdGlvbiB4bW9jazxUPihydWxlczogVCk6IGFueSB7XG4gICAgcmV0dXJuIG1vY2tqcy5tb2NrKHJ1bGVzKVxufVxuXG5mdW5jdGlvbiB4cmFuZG9tKG5hbWU6IHN0cmluZywgZGF0YTogYW55W10pIHtcbiAgICBtb2NranMuUmFuZG9tLmV4dGVuZCh7XG4gICAgICAgIFtuYW1lXTogKC4uLmFyZ3MpID0+IHtcbiAgICAgICAgICAgIHhhc3NlcnQoZGF0YS5sZW5ndGggPiAwKVxuICAgICAgICAgICAgaWYgKGRhdGEubGVuZ3RoID09IDEpIHJldHVybiBkYXRhWzBdXG4gICAgICAgICAgICBsZXQgbWF4ID0gZGF0YS5sZW5ndGggLSAxXG4gICAgICAgICAgICBsZXQgaWR4ID0geG1vY2soYEBpbnQoMCwke21heH0pYClcbiAgICAgICAgICAgIHJldHVybiBkYXRhW2lkeF1cbiAgICAgICAgfVxuICAgIH0pXG59XG5cbi8vIOaJqeWxleS4gOS6m+mihOWumuS5iWJ4anPnmoTln7rnoYDpmo/mnLrmlrnms5XmiJbogIXopobnm5bkuIDkupttb2NranPkuK3nmoTmlrnms5Vcbm1vY2tqcy5SYW5kb20uZXh0ZW5kKHtcbiAgICAvLyBieGpz6KGo5a6a5LmJ55qE5Li76ZSu57uf5LiA5a6a5LmJ77yI57qm5a6a57O757uf5Lit5Li65a2X56ym5LiyNy0xNOWtl+iKgumVv+W6pueul+azle+8iVxuICAgIGlkOiAoLi4uYXJncykgPT4ge1xuICAgICAgICByZXR1cm4gc2hvcnRpZC5nZW5lcmF0ZSgpXG4gICAgfSxcbiAgICAvLyDkuK3lm73miYvmnLrlj7fpmo/mnLrnlJ/miJDnrpfms5Uo57qm5a6a57O757uf5Lit55qE5omL5py65Y+35Li65a2X56ym5Liy5pWw5o2u57G75Z6LKVxuICAgIG1vYmlsZTogKC4uLmFyZ3MpID0+IHtcbiAgICAgICAgY29uc3QgaXNwcyA9IFtcbiAgICAgICAgICAgIDEzNCwgMTM1LCAxMzYsIDEzNywgMTM4LCAxMzksIDE0NywgMTUwLCAxNTEsIDE1MiwgMTU3LCAxNTgsIDE1OSwgMTgyLCAxODMsIDE4NCwgMTg3LCAxODgsIDE3OCxcbiAgICAgICAgICAgIDEzMCwgMTMxLCAxMzIsIDE0NSwgMTU1LCAxNTYsIDE4NSwgMTg2LCAxNzYsXG4gICAgICAgICAgICAxMzMsIDEzNCwgMTUzLCAxODAsIDE4MSwgMTg5LCAxNzcsIDE3MyxcbiAgICAgICAgICAgIDE3NiwgMTczLCAxNzcsIDE3OCwgMTcwLFxuICAgICAgICAgICAgMTQwLCAxNDEsIDE0MiwgMTQzLCAxNDQsIDE0NiwgMTQ4LCAxNDksIDE1NF1cbiAgICAgICAgbGV0IG1heCA9IGlzcHMubGVuZ3RoIC0gMVxuICAgICAgICBsZXQgaWR4ID0geG1vY2soYEBpbnQoMCwke21heH0pYClcbiAgICAgICAgbGV0IG51bSA9IHhtb2NrKGBAaW50KDEwMDAwMDAwMCwxOTk5OTk5OTkpYClcbiAgICAgICAgcmV0dXJuIChpc3BzW2lkeF0gKiAxMDAwMDAwMDAgKyBudW0gJSAxMDAwMDAwMDApICsgJydcbiAgICB9LFxuICAgIC8vIOi9rOaNouS4uue8uuecgeS4reaWh+WGheWuueaPkOekulxuICAgIHBhcmFncmFwaDogKC4uLmFyZ3MpID0+IHtcbiAgICAgICAgc3dpdGNoIChhcmdzLmxlbmd0aCkge1xuICAgICAgICAgICAgY2FzZSAwOlxuICAgICAgICAgICAgICAgIHJldHVybiB4bW9jaygnQGNwYXJhZ3JhcGgnKVxuICAgICAgICAgICAgY2FzZSAxOlxuICAgICAgICAgICAgICAgIHJldHVybiB4bW9jayhgQGNwYXJhZ3JhcGgoJHthcmdzWzBdfSlgKVxuICAgICAgICAgICAgY2FzZSAyOlxuICAgICAgICAgICAgICAgIHJldHVybiB4bW9jayhgQGNwYXJhZ3JhcGgoJHthcmdzWzBdfSwke2FyZ3NbMV19KWApXG4gICAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgICAgIHhhc3NlcnQoZmFsc2UpXG4gICAgICAgIH1cblxuICAgIH0sXG4gICAgc2VudGVuY2U6ICguLi5hcmdzKSA9PiB7XG4gICAgICAgIHN3aXRjaCAoYXJncy5sZW5ndGgpIHtcbiAgICAgICAgICAgIGNhc2UgMDpcbiAgICAgICAgICAgICAgICByZXR1cm4geG1vY2soJ0Bjc2VudGVuY2UnKVxuICAgICAgICAgICAgY2FzZSAxOlxuICAgICAgICAgICAgICAgIHJldHVybiB4bW9jayhgQGNzZW50ZW5jZSgke2FyZ3NbMF19KWApXG4gICAgICAgICAgICBjYXNlIDI6XG4gICAgICAgICAgICAgICAgcmV0dXJuIHhtb2NrKGBAY3NlbnRlbmNlKCR7YXJnc1swXX0sJHthcmdzWzFdfSlgKVxuICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgICB4YXNzZXJ0KGZhbHNlKVxuICAgICAgICB9XG5cbiAgICB9LFxuICAgIHRpdGxlOiAoLi4uYXJncykgPT4ge1xuICAgICAgICBzd2l0Y2ggKGFyZ3MubGVuZ3RoKSB7XG4gICAgICAgICAgICBjYXNlIDA6XG4gICAgICAgICAgICAgICAgcmV0dXJuIHhtb2NrKCdAY3RpdGxlJylcbiAgICAgICAgICAgIGNhc2UgMTpcbiAgICAgICAgICAgICAgICByZXR1cm4geG1vY2soYEBjdGl0bGUoJHthcmdzWzBdfSlgKVxuICAgICAgICAgICAgY2FzZSAyOlxuICAgICAgICAgICAgICAgIHJldHVybiB4bW9jayhgQGN0aXRsZSgke2FyZ3NbMF19LCR7YXJnc1sxXX0pYClcbiAgICAgICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICAgICAgeGFzc2VydChmYWxzZSlcbiAgICAgICAgfVxuXG4gICAgfSxcbn0pXG5cbi8vIGxhcmF2ZWzpo47moLxKU09O5a+56LGh6aqM6K+B5Zmo5bCB6KOF77yM6K+m57uG5paH5qGj6KeBIGh0dHBzOi8vZ2l0aHViLmNvbS9za2F0ZXJkYXY4NS92YWxpZGF0b3Jqc1xuZnVuY3Rpb24geGNoZWNrPFQ+KHBhcmFtOiBULCBydWxlczogVCwgbWVzc2FnZXM/OiBPYmplY3QpIHtcbiAgICBsZXQgb2JqID0gbmV3IHZhbGlkYXRvcmpzKHBhcmFtLCBydWxlcylcbiAgICBpZiAob2JqLmZhaWxzKCkpIHtcbiAgICAgICAgeHRocm93KEVSUiRQQVJBTSwgb2JqLmVycm9ycylcbiAgICB9XG59XG5cbi8vIOOAkElvQ+WuueWZqOeuoeeQhuOAkeW6lOeUqOWxgueahOaPkuS7tuWunueOsOexu+e7keWumuWIsEJYSlPnu5/kuIDms6jlhoznmoTmoIflh4bmj5Lku7bnmoTmmKDlsITlhbPns7vlnKjlhajlsYDlrrnlmajlrp7kvovkuK3ms6jlhoxcbmZ1bmN0aW9uIHhiaW5kPFQ+KFRZUEU6IG5ldyAoKSA9PiBUKSB7XG4gICAgY29uc3QgbzogYW55ID0gbmV3IFRZUEUoKVxuICAgIHJldHVybiB4Y29udGFpbmVyLmJpbmQ8VD4oby5pZCkudG8ocmVxdWlyZShgQGFwcC9wbHVnaW5zLyR7by5pZH1gKS5kZWZhdWx0KVxufVxuXG4vLyDjgJBJb0PlrrnlmajnrqHnkIbjgJHmoYbmnrbmiJblupTnlKjkvp3otZbmoIflh4bop4TojIPmjqXlj6Pmj5Lku7bnmoTnsbvlrp7kvovojrflj5bmlrnms5VcbmZ1bmN0aW9uIHhnb3Q8VD4oVFlQRTogbmV3ICgpID0+IFQpIHtcbiAgICBjb25zdCBvOiBhbnkgPSBuZXcgVFlQRSgpXG4gICAgcmV0dXJuIHhjb250YWluZXIuZ2V0PFQ+KG8uaWQpXG59XG5cbi8vIOWQjOatpeezu+e7n+WRveS7pOiwg+eUqOaJp+ihjFxuYXN5bmMgZnVuY3Rpb24geGNtZCguLi5hcmdzOiBzdHJpbmdbXSk6IFByb21pc2U8YW55PiB7XG4gICAgdHJ5IHtcbiAgICAgICAgY29uc3Qgb3B0aW9uczogYW55ID0ge31cbiAgICAgICAgb3B0aW9ucy5jd2QgPSBvcHRpb25zLmN3ZCB8fCBwcm9jZXNzLmVudi5fX2N0eFBhdGggfHwgcHJvY2Vzcy5jd2QoKTtcbiAgICAgICAgeGFzc2VydChfLmlzQXJyYXkoYXJncykgJiYgYXJncy5sZW5ndGggPiAwKVxuICAgICAgICBjb25zdCBjbWQgPSBhcmdzLnNoaWZ0KClcbiAgICAgICAgY29uc3QgcmV0ID0gY3Jvc3Nfc3Bhd24uc3luYyhjbWQsIGFyZ3MsIHhhc3NpZ24oe3N0ZGlvOiAnaW5oZXJpdCd9LCBvcHRpb25zKSlcbiAgICAgICAgeGFzc2VydChyZXQuc3RhdHVzID09PSAwLCBFUlIkVU5LTk9XTiwgcmV0KVxuICAgICAgICByZXR1cm4gcmV0XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgIGF3YWl0IHh3YXJuKGVycilcbiAgICAgICAgeHRocm93KGVycilcbiAgICB9XG59XG5cbi8vIOWvueS6juaVsOe7hOW1jOWll+Wbnuiwg+WHveaVsOeahG5vZGVqc+W8guatpeWkhOeQhuaWueazleeahOe7n+S4gOWwgeijhVxuYXN5bmMgZnVuY3Rpb24geG1hcDxUPih2YWx1ZXM6IFRbXSwgY2FsbGFjazogKHY6IFQpID0+IFByb21pc2U8YW55Pik6IFByb21pc2U8YW55W10+IHtcbiAgICB4YXNzZXJ0KF8uaXNBcnJheSh2YWx1ZXMpICYmIF8uaXNGdW5jdGlvbihjYWxsYWNrKSlcbiAgICByZXR1cm4gUHJvbWlzZS5hbGwodmFsdWVzLm1hcChjYWxsYWNrKSlcbn1cblxuLy8gUmVmZXIgdG8gZG9jdW1lbnQ6ICBodHRwczovL2hlbHAuYWxpeXVuLmNvbS9kb2N1bWVudF9kZXRhaWwvNjI2NzAuaHRtbFxuLy8g6I635Y+WQUNN6YWN572u5L+h5oGv5o6l5Y+j55qE57uf5LiA5bCB6KOFXG5hc3luYyBmdW5jdGlvbiB4YWNtKGdyb3VwOiBzdHJpbmcsIGlkOiBzdHJpbmcpIHtcbiAgICBjb25zdCBjZmcgPSB4Y29uZmlnKGBwbHVnaW5zLmFjbWApXG4gICAgeGFzc2VydChncm91cCAmJiBjZmcgJiYgY2ZnW2dyb3VwXSwgRVJSJENPTkZJRywge2NmZ30pXG4gICAgY29uc3QgYWNtID0gbmV3IEFDTUNsaWVudChjZmdbZ3JvdXBdKVxuICAgIHJldHVybiBuZXcgUHJvbWlzZShhc3luYyAocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjbyhmdW5jdGlvbiogKCkge1xuICAgICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgICAgIGdyb3VwID0gZ3JvdXAgKyAnOicgKyBnbG9iYWxbJ19fZW52X18nXSAvLyDooaXkuIrnjq/looPlkI7nvIDmlK/mjIHlkITnp43lvIDlj5Hnjq/looPnmoTkuKrmgKfljJbphY3nva5cbiAgICAgICAgICAgICAgICAgICAgY29uc3QgY29udGVudCA9IHlpZWxkIGFjbS5nZXRDb25maWcoaWQsIGdyb3VwKVxuICAgICAgICAgICAgICAgICAgICB4YXNzZXJ0KGNvbnRlbnQsIEVSUiRDT05GSUcsIHtpZCwgZ3JvdXB9KVxuICAgICAgICAgICAgICAgICAgICByZXNvbHZlKGNvbnRlbnQpXG4gICAgICAgICAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICAgICAgICAgIHh0aHJvdyhlcnIsIHJlamVjdCwge2lkLCBncm91cCwgY2ZnOiBjZmdbZ3JvdXBdfSlcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICB4dGhyb3coZXJyLCByZWplY3QsIHtpZCwgZ3JvdXAsIGNmZzogY2ZnW2dyb3VwXX0pXG4gICAgICAgIH1cbiAgICB9KVxufVxuXG4vLyDmoLnmja7lvZPliY3phY3nva7nmoTml7bljLrmraPnoa7ojrflj5blvZPliY3ml7bpl7TlgLzvvIjlvZPliY3ml7bljLrpgJrov4dwcm9jZXNzLmVudi5UWj0nQXNpYS9TaGFuZ2hhaSfliJ3lp4vljJbphY3nva7nu5/kuIDop6PlhrPmjonlr7nlupTnlKjml6DmhJ/liY3lkI7lj7Dkv53mjIHkuIDoh7TmgKfvvIlcbmZ1bmN0aW9uIHhub3coZm9ybWF0OiBzdHJpbmcgPSAnWVlZWS1NTS1ERCBISDptbTpzcycpOiBzdHJpbmcge1xuICAgIHJldHVybiBtb21lbnQoKS5mb3JtYXQoZm9ybWF0KVxufVxuXG4vLyDlrZfnrKbkuLLkuI7ml7bpl7TmiLPnmoTnm7jkupLovazmjaLlpITnkIZcbmZ1bmN0aW9uIHh0aW1lKHZhbHVlOiBzdHJpbmcgfCBudW1iZXIgPSB1bmRlZmluZWQpOiBudW1iZXIgfCBzdHJpbmcge1xuICAgIGlmICh2YWx1ZSA9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgcmV0dXJuIG1vbWVudCgpLnRvRGF0ZSgpLmdldFRpbWUoKVxuICAgIH1cbiAgICB4YXNzZXJ0KF8uaXNTdHJpbmcodmFsdWUpIHx8IF8uaXNTYWZlSW50ZWdlcih2YWx1ZSkpXG4gICAgaWYgKF8uaXNTdHJpbmcodmFsdWUpKSB7XG4gICAgICAgIC8vIFNUUklOR+i9rOaNouS4uklOVOexu+Wei1xuICAgICAgICByZXR1cm4gbW9tZW50KHZhbHVlKS50b0RhdGUoKS5nZXRUaW1lKClcbiAgICB9IGVsc2Uge1xuICAgICAgICAvLyBJTlTovazmjaLkuLpTVFJJTkfnsbvlnotcbiAgICAgICAgcmV0dXJuIG1vbWVudCh2YWx1ZSkuZm9ybWF0KCdZWVlZLU1NLUREIEhIOm1tOnNzJylcbiAgICB9XG59XG5cbi8vIGJhc2U2NOe8lueggVxuZnVuY3Rpb24geGJhc2U2NGVuY29kZSh2YWx1ZTogc3RyaW5nKSB7XG4gICAgeGFzc2VydCghXy5pc0VtcHR5KHZhbHVlKSAmJiBfLmlzU3RyaW5nKHZhbHVlKSlcbiAgICByZXR1cm4gbmV3IEJ1ZmZlcih2YWx1ZSkudG9TdHJpbmcoJ2Jhc2U2NCcpXG59XG5cbi8vIGJhc2U2NOino+eggVxuZnVuY3Rpb24geGJhc2U2NGRlY29kZSh2YWx1ZTogc3RyaW5nKSB7XG4gICAgeGFzc2VydCghXy5pc0VtcHR5KHZhbHVlKSAmJiBfLmlzU3RyaW5nKHZhbHVlKSlcbiAgICByZXR1cm4gbmV3IEJ1ZmZlcih2YWx1ZSwgJ2Jhc2U2NCcpLnRvU3RyaW5nKClcbn1cblxuLy8g5pS56L+bbnBt5YyF5Lit55qEdXVpZCB2MeaXtumXtOW6j+WIl+eul+azleehruS/neWUr+S4gOaAp+WSjOmaj+acuuaAp+WPr+S7peeos+WumuWPr+mdoOeahOW6lOeUqOS6jnNlcnZlcmxlc3PliIbluIPlvI/pq5jlubblj5HlupTnlKjlnLrmma/kuItcbi8vIOaUuei/m+WfuuS6juaXtumXtOW6j+WIl+eahFVVSUTnrpfms5Xnoa7kv51zZXJ2ZXJsZXNz5YiG5biD5byP5bm25Y+R5Zy65pmv5LiL55qE5YWo5bGA5ZSv5LiA5oCn5Lul5Y+K5L2/55So5a+G56CB5py66ZqP5py65oCn5pS56L+b5LiN5Y+v6aKE5rWL5oCnXG5mdW5jdGlvbiB4dXVpZCgpOiBzdHJpbmcge1xuICAgIC8vIOS8mOWMlueul+azleS4reeahDEwMOe6s+enkuaXtumXtOS4uumaj+acuuaVsO+8jOi/m+S4gOatpemZjeS9juWGsueqgeamgueOh+OAglxuICAgIC8vIOWGsueqgeamgueOh+WIhuaekO+8mlxuICAgIC8vICAgICAgMeenkuaUr+aSkTEwMDDlubblj5HvvIjmr6vnp5Lml7bpl7TmiLPnsr7luqbkv53or4HvvInvvIxcbiAgICAvLyAgICAgIDEwMDDlubblj5HkuK3nm7jlkIzmr6vnp5Lml7bpl7TnmoTlubblj5HvvIzlho3pgJrov4cxMDAwMOeZvue6s+enkumaj+acuuaVsOi/m+ihjOWMuuWIhumBv+WFjeWGsueqge+8jFxuICAgIC8vICAgICAg5LiN5ZCM5py65Zmo5LiK55qE5bm25Y+R5pe26Ze05oiz5Y+v6IO95Lya5pyJ5YGP56e75a+86Ie06YeN5aSN5YGP5beu5pe26Ze077yI6YCa6L+HNuS4quWtl+iKgueahG5vZGUgaWTpmo/mnLrmlbDljLrliIbmnLrlmajvvIwy5a2X6IqCMHgzZmZm6ZqP5py65pWw5Yy65YiGY2xvY2tzZXHvvIlcbiAgICAvLyDlhrLnqoHmpoLnjofln7rmnKzkuIrlj6/ku6Xkv53or4Hlv73nlaXkuI3orqHpgb/lhY1zaG9ydGlk566X5rOV6auY5bm25Y+R5Yay56qB55qE57y66Zm3XG4gICAgcmV0dXJuIHJlcXVpcmUoJ3V1aWQvdjEnKSh7bnNlY3M6IE1hdGguZmxvb3IoTWF0aC5yYW5kb20oKSAqIDEwMDAwKX0pLnJlcGxhY2UoL1xcLS9nLCAnJylcbiAgICAvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vL1xuICAgIC8vIOiAg+iZkeWIsHNlcnZlcmxlc3Plrp7pmYXnjq/looPlubbkuI3mmK/lkIjpgIJub2RlIGlk5L2/55SobWFj5Zyw5Z2A77yM55u05o6l5L2/55So6buY6K6k55qEOOWtl+iKgumaj+acuuaVsOabv+S7o+abtOaooeaLn+abtOWQiOmAgu+8iG5vZGUgaWQgKyBjbG9ja3Nlce+8ieOAglxuICAgIC8vIC8vIOWwgeijheato+ehrueahHV1aWTlrp7njrDnrpfms5Xnoa7kv53llK/kuIDmgKfvvIjkvb/nlKg25Liq5a2X6IqC55qE5py65ZmobWFj5Zyw5Z2A77yM56Gu5L+d5YiG5biD5byP5py65Zmo566X5rOV5omn6KGM55qE5ZSv5LiA5oCn77yJXG4gICAgLy8gY29uc3QgbWFjID0gYXdhaXQgX194Z2V0bWFjX18oKVxuICAgIC8vIC8vIOWwhuWtl+espuS4sui9rOaNouS4umJ1ZmZlcuS6jOi/m+WItuWkhOeQhlxuICAgIC8vIGxldCBidWYgPSBbXVxuICAgIC8vIC8vIE1BQ+WcsOWdgOagvOW8jyAjIzojIzojIzojIzojIzojI1xuICAgIC8vIGNvbnN0IHZhbHVlcyA9IG1hYy5zcGxpdCgnOicpXG4gICAgLy8geGFzc2VydCh2YWx1ZXMgJiYgdmFsdWVzLmxlbmd0aCA9PSA2KVxuICAgIC8vIGZvciAobGV0IGkgPSAwOyBpIDwgNjsgKytpKSB7XG4gICAgLy8gICAgIGNvbnN0IHRtcEJ5dGUgPSBwYXJzZUludCh2YWx1ZXNbaV0sIDE2KTtcbiAgICAvLyAgICAgYnVmLnB1c2godG1wQnl0ZSlcbiAgICAvLyB9XG4gICAgLy8gLy8g5LulbWFj5Zyw5Z2A5L2c5Li65py65Zmo5ZSv5LiA5qCH6K+G56Gu5L+d5q2j56Gu5oCnXG4gICAgLy8gY29uc3QgdXVpZCA9IHJlcXVpcmUoJ3V1aWQvdjEnKSh7bm9kZTogYnVmfSlcbiAgICAvLyByZXR1cm4gdXVpZDtcbn1cblxuLypcbklmIHlvdSB3YW50IHRvIGluc3VyZSBVVUlEIHVuaXF1ZW5lc3MgYWNyb3NzIHlvdXIgY2x1c3RlciBwcm9jZXNzZXMsIHRoZW4gSSB3b3VsZCBzdWdnZXN0IHVzaW5nIHYxKHtub2RlOmFVbmlxdWVWYWx9KSxcbndoZXJlIGFVbmlxdWVWYWwgaXMgc29tZSB2YWx1ZSB5b3Uga25vdyB0byBiZSB1bmlxdWUgdG8gZWFjaCBjbHVzdGVyIHByb2Nlc3MuXG5odHRwczovL3d3dy5ucG1qcy5jb20vcGFja2FnZS9ub2RlLW1hY2hpbmUtaWQgIOeUn+aIkOacuuWZqGlk55qE5ZSv5LiA5qCH6K+G566X5rOV5Y+C6ICDXG4gKi9cbi8vIC8vIOiOt+WPlm1hY+WcsOWdgFxuLy8gYXN5bmMgZnVuY3Rpb24gX194Z2V0bWFjX18oKTogUHJvbWlzZTxzdHJpbmc+IHtcbi8vICAgICBpZiAoIWdsb2JhbFsnZ19ieGpzX3NNYWNBZGRyZXNzJ10pIHtcbi8vICAgICAgICAgcmV0dXJuIG5ldyBQcm9taXNlPHN0cmluZz4oKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuLy8gICAgICAgICAgICAgdHJ5IHtcbi8vICAgICAgICAgICAgICAgICB4YXNzZXJ0KHJlcXVpcmUoJ2dldG1hYycpLmlzTWFjKGdsb2JhbFsnZ19ieGpzX3NNYWNBZGRyZXNzJ10pKVxuLy8gICAgICAgICAgICAgICAgIHJlc29sdmUoZ2xvYmFsWydnX2J4anNfc01hY0FkZHJlc3MnXSlcbi8vICAgICAgICAgICAgIH0gY2F0Y2ggKGVycikge1xuLy8gICAgICAgICAgICAgICAgIHh0aHJvdyhlcnIsIHJlamVjdClcbi8vICAgICAgICAgICAgIH1cbi8vICAgICAgICAgfSlcbi8vICAgICB9XG4vLyAgICAgcmV0dXJuIG5ldyBQcm9taXNlPHN0cmluZz4oKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuLy8gICAgICAgICByZXF1aXJlKCdnZXRtYWMnKS5nZXRNYWMoZnVuY3Rpb24gKGVyciwgbWFjQWRkcmVzcykge1xuLy8gICAgICAgICAgICAgaWYgKGVycikgeHRocm93KGVyciwgcmVqZWN0KVxuLy8gICAgICAgICAgICAgcmVzb2x2ZShtYWNBZGRyZXNzKVxuLy8gICAgICAgICB9KVxuLy8gICAgIH0pXG4vLyB9XG5cblxuLy8g6K+35rGC5LiK5LiL5paH5Y+Y6YeP6Ieq5Yqo6YeN572u5pa55rOV77yI5LulZ2xvYmFs5Y+Y6YeP5Lita2V55Li6X1/kuIvliJLnur/lvIDlp4vnu5PmnZ/nmoTlsZ7mgKfoh6rliqjmuIXnqbrkuLp1bmRlZmluZWTvvIzlpoLpnIDotYvlgLzlhbbku5bnvLrnnIHlgLzpnIDopoHlnKjmraTlh73mlbDkuK3mmI7noa7lrprkuYnvvIlcbmZ1bmN0aW9uIHhyZXNldCgpIHtcbiAgICAvLyDmiYDmnInor7fmsYLkuIrkuIvmloflsZ7mgKfnmoToh6rliqjmuIXnqbrliJ3lp4vljJblpITnkIbvvIjpgJrov4fnuqblrppnbG9iYWznmoTnibnmrorlsZ7mgKdfX3h4eF9f566A5YyWa29h5Lit55qEY29udGV4dOiuvuiuoeacuuWItu+8jOWwhui/memDqOWIhuacuuWItuWBmuWIsOahhuaetuS4iuWvueW6lOeUqOS4jeWPr+inge+8iVxuICAgIGZvciAobGV0IGtleSBvZiBPYmplY3Qua2V5cyhnbG9iYWwpKSB7XG4gICAgICAgIGlmIChrZXkuc3RhcnRzV2l0aCgnX18nKSAmJiBrZXkuZW5kc1dpdGgoJ19fJykpIHtcbiAgICAgICAgICAgIGdsb2JhbFtrZXldID0gdW5kZWZpbmVkXG4gICAgICAgIH1cbiAgICB9XG4gICAgLy8g5piO56Gu5a6a5LmJ55qE5LiA5Lqb5YWo5bGA5Y+Y6YeP55qE5Yid5aeL5YC86LWL5YC8XG4gICAgaWYgKCFnbG9iYWxbJ19fZW52X18nXSkge1xuICAgICAgICBnbG9iYWxbJ19fZW52X18nXSA9ICdsb2NhbCcgLy8gbG9jYWwsZGFpbHkscHJlLGdyYXkscHJvZCDlnKjnu5/kuIDlhaXlj6PlpIToh6rliqjor4bliKvphY3nva4o55uu5YmN5pqC5LiN5pSv5oyBZ3JheemFjee9ruWwmuacquW8gOWPkeaXoOazleiHquWKqOivhuWIqylcbiAgICB9XG4gICAgZ2xvYmFsWydfX2NvbmZpZ19fJ10gPSB1bmRlZmluZWRcbiAgICBnbG9iYWxbJ19fc2Vzc2lvbl9fJ10gPSB7fVxuICAgIGdsb2JhbFsnX19jYWNoZV9fJ10gPSB7fVxuICAgIGdsb2JhbFsnX191c2VyX18nXSA9IHt9XG4gICAgZ2xvYmFsWydfX3VzZXJfYWdlbnRfXyddID0gdW5kZWZpbmVkXG4gICAgZ2xvYmFsWydfX2NsaWVudF9pcF9fJ10gPSB1bmRlZmluZWRcbiAgICBnbG9iYWxbJ19fcmVkaXJlY3RfdXJsX18nXSA9IHVuZGVmaW5lZFxuICAgIGdsb2JhbFsnX19yZXF1ZXN0X2Nvb2tpZXNfXyddID0ge31cbiAgICBnbG9iYWxbJ19fcmVzcG9uZF9jb29raWVzX18nXSA9IHt9XG59XG5cbi8vIOmmluasoeaooeWdl+WKoOi9veeahOaXtuWAmeaJp+ihjOS4gOasoe+8jOehruS/neW6lOeUqOS4reS4jeWPr+S7peaciV9feHh4X1/lj4LmlbDkvZzkuLrlhajlsYDlj5jph4/lnKjmqKHlnZfliJ3lp4vljJbnmoTml7blgJlcbnhyZXNldCgpXG5cbmdsb2JhbFsneHJlc2V0J10gPSB4cmVzZXRcbmdsb2JhbFsneGNvbm5lY3QnXSA9IHhjb25uZWN0XG5nbG9iYWxbJ3huZXcnXSA9IHhuZXdcbmdsb2JhbFsneHF1ZXJ5J10gPSB4cXVlcnlcbmdsb2JhbFsneGNvdW50J10gPSB4Y291bnRcbmdsb2JhbFsneGFzc2lnbiddID0geGFzc2lnblxuZ2xvYmFsWyd4Y29uZmlnJ10gPSB4Y29uZmlnXG5nbG9iYWxbJ3h0aHJvdyddID0geHRocm93XG5nbG9iYWxbJ3hhc3NlcnQnXSA9IHhhc3NlcnRcbmdsb2JhbFsneGVycm9yJ10gPSB4ZXJyb3Jcbmdsb2JhbFsneHJvb3QnXSA9IHhyb290XG5nbG9iYWxbJ3hzdGFjayddID0geHN0YWNrXG5nbG9iYWxbJ3h3YXJuJ10gPSB4d2FyblxuZ2xvYmFsWyd4bG9nJ10gPSB4bG9nXG5nbG9iYWxbJ3hwb3N0J10gPSB4cG9zdFxuZ2xvYmFsWyd4Z2V0J10gPSB4Z2V0XG5nbG9iYWxbJ3hzbGVlcCddID0geHNsZWVwXG5nbG9iYWxbJ3hyZWRpcmVjdCddID0geHJlZGlyZWN0XG5nbG9iYWxbJ3hjb29raWUnXSA9IHhjb29raWVcbmdsb2JhbFsneGlzbW9iaWxlJ10gPSB4aXNtb2JpbGVcbmdsb2JhbFsneHNlc3Npb24nXSA9IHhzZXNzaW9uXG5nbG9iYWxbJ3h1c2VyJ10gPSB4dXNlclxuZ2xvYmFsWyd4Y2FjaGUnXSA9IHhjYWNoZVxuZ2xvYmFsWyd4cm91dGUnXSA9IHhyb3V0ZVxuZ2xvYmFsWyd4bW9jayddID0geG1vY2tcbmdsb2JhbFsneHJhbmRvbSddID0geHJhbmRvbVxuZ2xvYmFsWyd4Y2hlY2snXSA9IHhjaGVja1xuZ2xvYmFsWyd4Y29udGFpbmVyJ10gPSBuZXcgQ29udGFpbmVyKCkgLy8g5YWo5bGA5Y2V5a6e5L6L5a655Zmo5Yid5aeL5YyWXG5nbG9iYWxbJ3hiaW5kJ10gPSB4YmluZFxuZ2xvYmFsWyd4Z290J10gPSB4Z290XG5nbG9iYWxbJ1lBdXRoJ10gPSAkJC5ZQXV0aCAvLyDlhajlsYDlo7DmmI7orqTor4Hmj5Lku7bop4TojIPmir3osaHnsbtcbmdsb2JhbFsneGNtZCddID0geGNtZFxuZ2xvYmFsWyd4bWFwJ10gPSB4bWFwXG5nbG9iYWxbJ3hhY20nXSA9IHhhY21cbmdsb2JhbFsneGJhc2U2NGVuY29kZSddID0geGJhc2U2NGVuY29kZVxuZ2xvYmFsWyd4YmFzZTY0ZGVjb2RlJ10gPSB4YmFzZTY0ZGVjb2RlXG5nbG9iYWxbJ3hub3cnXSA9IHhub3dcbmdsb2JhbFsneHRpbWUnXSA9IHh0aW1lXG5nbG9iYWxbJ3h1dWlkJ10gPSB4dXVpZFxuIl19
\No newline at end of file