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.TZ = 'Asia/Shanghai';
|
48 | process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
49 | require("reflect-metadata");
|
50 | var inversify_1 = require("inversify");
|
51 | var typeorm_1 = require("@bxjs/typeorm");
|
52 | var session_1 = require("./session");
|
53 | var $$ = require("./plugins");
|
54 | var path = require('path');
|
55 | var ErrorStackParser = require('error-stack-parser');
|
56 | var cookie = require('cookie');
|
57 | var MobileDetect = require('mobile-detect');
|
58 | var fetch = require('node-fetch');
|
59 | var _ = require('lodash');
|
60 | var moment = require('moment');
|
61 | var extend = require('extend');
|
62 | var 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 | // })
|
71 | var circular_json = require("circular-json");
|
72 | var mockjs = require('mockjs');
|
73 | var shortid = require('shortid');
|
74 | var validatorjs = require('validatorjs');
|
75 | var cross_spawn = require('cross-spawn');
|
76 | var ACMClient = require('amber_utf-8');
|
77 | var co = require('co');
|
78 | // FIXME HACK原生方法JSON转换不可逆的BUG(JAVA端传来的富文本字段内容含有\n\t字符串中的字符生成JSON字符串无法正常解析报错)
|
79 | var raw_stringify = JSON.stringify;
|
80 | function 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 | }
|
89 | JSON.stringify = new_stringify;
|
90 | // ts-node本地调试需要加载对应的源代码后缀名称
|
91 | function 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 | }
|
99 | exports.get_suffix_ts_or_js = get_suffix_ts_or_js;
|
100 | // 准确定位错误码位置,间接得到函数调用位置地址信息,结合符号报表的正确解析处理完美得到错误定位信息,准确代码调试。
|
101 | function __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 | // 获取异常调用栈用于辅助错误提示定位
|
132 | function 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 | }
|
152 | exports.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
|
163 | function 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 | }
|
183 | exports.xerror = xerror;
|
184 | // 用于获取错误栈的root cause根本原因(第一个被拦截的错误发生位置)
|
185 | function 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 | }
|
204 | exports.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 | // }
|
218 | function 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 | }
|
273 | exports.xthrow = xthrow;
|
274 | function 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 | }
|
282 | exports.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 | // }
|
293 | function 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 | }
|
316 | exports.xlog = xlog;
|
317 | // // 将详细错误信息及时发送到钉钉群上实时反馈给维护者
|
318 | // await xwarn({
|
319 | // code,
|
320 | // // TODO 如何认证通过了获取到用户信息也需要发送过去,方便联系对接人员进行立刻问题处理反馈。
|
321 | // message,
|
322 | // stack,
|
323 | // param,
|
324 | // })
|
325 | // 将详细错误信息及时发送到钉钉群上实时反馈给维护者
|
326 | // 钉钉IM群机器人报警通知
|
327 | function 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 | // 捕获未监听到的异常记录后直接退出(运行堆栈已经破坏直接记录日志后异常退出即可,由外部监控自动重启)
|
373 | process.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中出现未捕获的异常错误
|
389 | process.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的非阻塞异步延迟方法,用于调试阻塞程序的执行进行单步调试的效果。
|
405 | var sleep = require('sleep-async')();
|
406 | function 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 | }
|
424 | exports.xsleep = xsleep;
|
425 | function 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 | }
|
462 | exports.xpost = xpost;
|
463 | // 默认超时3000毫秒
|
464 | function 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 | }
|
501 | exports.xget = xget;
|
502 | // 302临时重定向跳转实现
|
503 | function 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 | }
|
524 | exports.xredirect = xredirect;
|
525 | // 如果只有key参数表示读取属性(缺省值为undefined),如果key为空表示读取所有的请求cookies属性,否则表示响应设置cookies
|
526 | function 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 | }
|
546 | exports.xcookie = xcookie;
|
547 | // 判断user-agent请求是否为移动端
|
548 | function xismobile() {
|
549 | var md = new MobileDetect(global['__user_agent__']);
|
550 | return !!md.mobile();
|
551 | }
|
552 | function 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目录下的应用配置数据
|
561 | function 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 | }
|
595 | function 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对象并且自动赋值前端请求的赋值数据
|
667 | function 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 | // 查询构造器易用性封装
|
686 | function xquery(connect, TYPE, alias) {
|
687 | return connect.getRepository(TYPE).createQueryBuilder(alias);
|
688 | }
|
689 | // 分页查询获取总数以及原始记录数据
|
690 | function 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
|
710 | function 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
|
759 | function xmock(rules) {
|
760 | return mockjs.mock(rules);
|
761 | }
|
762 | function 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中的方法
|
780 | mockjs.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
|
858 | function 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统一注册的标准插件的映射关系在全局容器实例中注册
|
865 | function xbind(TYPE) {
|
866 | var o = new TYPE();
|
867 | return xcontainer.bind(o.id).to(require("@app/plugins/" + o.id).default);
|
868 | }
|
869 | // 【IoC容器管理】框架或应用依赖标准规范接口插件的类实例获取方法
|
870 | function xgot(TYPE) {
|
871 | var o = new TYPE();
|
872 | return xcontainer.get(o.id);
|
873 | }
|
874 | // 同步系统命令调用执行
|
875 | function 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异步处理方法的统一封装
|
906 | function 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配置信息接口的统一封装
|
916 | function 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'初始化配置统一解决掉对应用无感前后台保持一致性)
|
959 | function xnow(format) {
|
960 | if (format === void 0) { format = 'YYYY-MM-DD HH:mm:ss'; }
|
961 | return moment().format(format);
|
962 | }
|
963 | // 字符串与时间戳的相互转换处理
|
964 | function 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编码
|
980 | function xbase64encode(value) {
|
981 | xassert(!_.isEmpty(value) && _.isString(value));
|
982 | return new Buffer(value).toString('base64');
|
983 | }
|
984 | // base64解码
|
985 | function xbase64decode(value) {
|
986 | xassert(!_.isEmpty(value) && _.isString(value));
|
987 | return new Buffer(value, 'base64').toString();
|
988 | }
|
989 | // 改进npm包中的uuid v1时间序列算法确保唯一性和随机性可以稳定可靠的应用于serverless分布式高并发应用场景下
|
990 | // 改进基于时间序列的UUID算法确保serverless分布式并发场景下的全局唯一性以及使用密码机随机性改进不可预测性
|
991 | function 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 | /*
|
1017 | If you want to insure UUID uniqueness across your cluster processes, then I would suggest using v1({node:aUniqueVal}),
|
1018 | where aUniqueVal is some value you know to be unique to each cluster process.
|
1019 | https://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,如需赋值其他缺省值需要在此函数中明确定义)
|
1041 | function 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__参数作为全局变量在模块初始化的时候
|
1064 | xreset();
|
1065 | global['xreset'] = xreset;
|
1066 | global['xconnect'] = xconnect;
|
1067 | global['xnew'] = xnew;
|
1068 | global['xquery'] = xquery;
|
1069 | global['xcount'] = xcount;
|
1070 | global['xassign'] = xassign;
|
1071 | global['xconfig'] = xconfig;
|
1072 | global['xthrow'] = xthrow;
|
1073 | global['xassert'] = xassert;
|
1074 | global['xerror'] = xerror;
|
1075 | global['xroot'] = xroot;
|
1076 | global['xstack'] = xstack;
|
1077 | global['xwarn'] = xwarn;
|
1078 | global['xlog'] = xlog;
|
1079 | global['xpost'] = xpost;
|
1080 | global['xget'] = xget;
|
1081 | global['xsleep'] = xsleep;
|
1082 | global['xredirect'] = xredirect;
|
1083 | global['xcookie'] = xcookie;
|
1084 | global['xismobile'] = xismobile;
|
1085 | global['xsession'] = session_1.xsession;
|
1086 | global['xuser'] = session_1.xuser;
|
1087 | global['xcache'] = session_1.xcache;
|
1088 | global['xroute'] = xroute;
|
1089 | global['xmock'] = xmock;
|
1090 | global['xrandom'] = xrandom;
|
1091 | global['xcheck'] = xcheck;
|
1092 | global['xcontainer'] = new inversify_1.Container(); // 全局单实例容器初始化
|
1093 | global['xbind'] = xbind;
|
1094 | global['xgot'] = xgot;
|
1095 | global['YAuth'] = $$.YAuth; // 全局声明认证插件规范抽象类
|
1096 | global['xcmd'] = xcmd;
|
1097 | global['xmap'] = xmap;
|
1098 | global['xacm'] = xacm;
|
1099 | global['xbase64encode'] = xbase64encode;
|
1100 | global['xbase64decode'] = xbase64decode;
|
1101 | global['xnow'] = xnow;
|
1102 | global['xtime'] = xtime;
|
1103 | global['xuuid'] = xuuid;
|
1104 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFzZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbImJhc2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSxpQkF5M0JBOztBQXozQkEsT0FBTyxDQUFDLEdBQUcsQ0FBQyxFQUFFLEdBQUcsZUFBZSxDQUFBO0FBQ2hDLE9BQU8sQ0FBQyxHQUFHLENBQUMsNEJBQTRCLEdBQUcsR0FBRyxDQUFBO0FBQzlDLDRCQUF5QjtBQUN6Qix1Q0FBbUM7QUFDbkMseUNBQTZHO0FBQzdHLHFDQUFpRDtBQUNqRCw4QkFBK0I7QUFFL0IsSUFBTSxJQUFJLEdBQUcsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFBO0FBQzVCLElBQU0sZ0JBQWdCLEdBQUcsT0FBTyxDQUFDLG9CQUFvQixDQUFDLENBQUE7QUFDdEQsSUFBTSxNQUFNLEdBQUcsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFBO0FBQ2hDLElBQU0sWUFBWSxHQUFHLE9BQU8sQ0FBQyxlQUFlLENBQUMsQ0FBQTtBQUM3QyxJQUFNLEtBQUssR0FBRyxPQUFPLENBQUMsWUFBWSxDQUFDLENBQUE7QUFDbkMsSUFBTSxDQUFDLEdBQUcsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFBO0FBQzNCLElBQU0sTUFBTSxHQUFHLE9BQU8sQ0FBQyxRQUFRLENBQUMsQ0FBQTtBQUNoQyxJQUFNLE1BQU0sR0FBRyxPQUFPLENBQUMsUUFBUSxDQUFDLENBQUE7QUFDaEMsSUFBTSxXQUFXLEdBQUcsT0FBTyxDQUFDLGFBQWEsQ0FBQyxDQUFBO0FBQzFDLHlDQUF5QztBQUN6QyxpREFBaUQ7QUFDakQsa0NBQWtDO0FBQ2xDLCtEQUErRDtBQUMvRCxzRUFBc0U7QUFDdEUsOENBQThDO0FBQzlDLFdBQVc7QUFDWCxLQUFLO0FBQ0wsSUFBTSxhQUFhLEdBQUcsT0FBTyxDQUFDLGVBQWUsQ0FBQyxDQUFBO0FBQzlDLElBQU0sTUFBTSxHQUFHLE9BQU8sQ0FBQyxRQUFRLENBQUMsQ0FBQTtBQUNoQyxJQUFNLE9BQU8sR0FBRyxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUE7QUFDbEMsSUFBTSxXQUFXLEdBQUcsT0FBTyxDQUFDLGFBQWEsQ0FBQyxDQUFBO0FBQzFDLElBQU0sV0FBVyxHQUFHLE9BQU8sQ0FBQyxhQUFhLENBQUMsQ0FBQTtBQUMxQyxJQUFNLFNBQVMsR0FBRyxPQUFPLENBQUMsYUFBYSxDQUFDLENBQUE7QUFDeEMsSUFBTSxFQUFFLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFBO0FBRXhCLDZFQUE2RTtBQUM3RSxJQUFNLGFBQWEsR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFBO0FBRXBDLHVCQUF1QixLQUFVLEVBQUUsUUFBMkMsRUFDdkQsS0FBdUI7SUFDMUMsSUFBSSxHQUFHLEdBQUcsYUFBYSxDQUFDLEtBQUssRUFBRSxRQUFRLEVBQUUsS0FBSyxDQUFDLENBQUE7SUFDL0MsSUFBSSxDQUFDLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxFQUFFO1FBQ2pCLEdBQUcsR0FBRyxHQUFHLENBQUMsT0FBTyxDQUFDLE1BQU0sRUFBRSxPQUFPLENBQUM7YUFDN0IsT0FBTyxDQUFDLE1BQU0sRUFBRSxPQUFPLENBQUM7YUFDeEIsT0FBTyxDQUFDLE1BQU0sRUFBRSxPQUFPLENBQUMsQ0FBQSxDQUFDLHVCQUF1QjtLQUN4RDtJQUNELE9BQU8sR0FBRyxDQUFBO0FBQ2QsQ0FBQztBQUVELElBQUksQ0FBQyxTQUFTLEdBQUcsYUFBb0IsQ0FBQTtBQUVyQyw0QkFBNEI7QUFDNUI7SUFDSSxJQUFJLE1BQU0sQ0FBQyxTQUFTLENBQUMsSUFBSSxPQUFPLElBQUksQ0FBQyx1QkFBdUIsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLEVBQUU7UUFDMUUsT0FBTyxJQUFJLENBQUE7S0FDZDtTQUFNO1FBQ0gsT0FBTyxJQUFJLENBQUE7S0FDZDtBQUNMLENBQUM7QUFORCxrREFNQztBQUVELDJEQUEyRDtBQUMzRCxnREFBZ0QsUUFBb0I7SUFBcEIseUJBQUEsRUFBQSxZQUFvQjtJQUNoRSxJQUFJO1FBQ0EsTUFBTSxJQUFJLEtBQUssRUFBRSxDQUFBO0tBQ3BCO0lBQUMsT0FBTyxHQUFHLEVBQUU7UUFDVixJQUFJLEdBQUcsR0FBRyxnQkFBZ0IsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUE7UUFDckMsSUFBSSxHQUFHLEdBQUcsQ0FBQyxDQUFBO1FBQ1gsaUJBQWlCO1FBQ2pCLElBQUksd0JBQXdCLEdBQUcsQ0FBQyxDQUFBO1FBQ2hDLE9BQU8sR0FBRyxHQUFHLEdBQUcsQ0FBQyxNQUFNLEVBQUUsR0FBRyxFQUFFLEVBQUU7WUFDNUIsSUFBSSxPQUFPLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxRQUFRLENBQUMsRUFBRTtnQkFDakMsd0JBQXdCLElBQUksQ0FBQyxDQUFBO2FBQ2hDO1lBQ0QsSUFBSSx3QkFBd0IsSUFBSSxRQUFRLEVBQUU7Z0JBQ3RDLE1BQUs7YUFDUjtTQUNKO1FBQ0QsSUFBSSx3QkFBd0IsSUFBSSxRQUFRLEVBQUU7WUFDdEMsT0FBTyxHQUFHLEdBQUcsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxHQUFHLEdBQUcsR0FBRyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUMsWUFBWSxDQUFDLEdBQUcsR0FBRyxDQUFBO1NBQ3pFO2FBQU07WUFDSCxpQ0FBaUM7WUFDakMscUJBQXFCO1lBQ3JCLE9BQU8sQ0FBQyxLQUFLLENBQUMsYUFBYSxDQUFDLFNBQVMsQ0FBQyxHQUFHLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztpQkFDOUMsT0FBTyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUE7WUFDM0MsT0FBTyxHQUFHLENBQUE7U0FDYjtLQUVKO0FBQ0wsQ0FBQztBQUVELG9CQUFvQjtBQUNwQixnQkFBdUIsR0FBRyxFQUFFLE9BQWM7SUFBZCx3QkFBQSxFQUFBLGNBQWM7SUFDdEMsSUFBSTtRQUNBLGtDQUFrQztRQUNsQyxJQUFJLEtBQUssR0FBRyxnQkFBZ0IsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUE7UUFDdkMsSUFBSSxPQUFPLEVBQUU7WUFDVCxJQUFJLE9BQU8sR0FBYSxFQUFFLENBQUE7WUFDMUIsS0FBYyxVQUFLLEVBQUwsZUFBSyxFQUFMLG1CQUFLLEVBQUwsSUFBSyxFQUFFO2dCQUFoQixJQUFJLENBQUMsY0FBQTtnQkFDTixPQUFPLENBQUMsSUFBSSxDQUFJLENBQUMsQ0FBQyxVQUFVLENBQUMsU0FBSSxDQUFDLENBQUMsWUFBWSxDQUFHLENBQUMsQ0FBQTthQUN0RDtZQUNELE9BQU8sT0FBTyxDQUFBO1NBQ2pCO1FBQ0QsT0FBTyxLQUFLLENBQUE7S0FDZjtJQUFDLE9BQU8sSUFBSSxFQUFFO1FBQ1gsSUFBSSxNQUFNLEdBQUcsc0NBQXNDLEVBQUUsQ0FBQTtRQUNyRCxPQUFPLGdDQUE4QixNQUFNLE1BQUcsQ0FBQTtLQUNqRDtBQUNMLENBQUM7QUFoQkQsd0JBZ0JDO0FBRUQsbUVBQW1FO0FBQ25FLFlBQVk7QUFDWix5QkFBeUI7QUFDekIscUJBQXFCO0FBQ3JCLGlCQUFpQjtBQUNqQiwrR0FBK0c7QUFDL0csU0FBUztBQUNULDZlQUE2ZTtBQUM3ZSxJQUFJO0FBRUosNENBQTRDO0FBQzVDLGdCQUF1QixHQUFHLEVBQUUsT0FBYTtJQUNyQyxPQUFPLENBQUMsR0FBRyxZQUFZLEtBQUssQ0FBQyxDQUFBO0lBQzdCLElBQUk7UUFDQSxjQUFjO1FBQ2QsSUFBSSxNQUFJLEdBQVEsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUE7UUFDdkMsSUFBSSxNQUFJLENBQUMsSUFBSSxJQUFJLE1BQUksQ0FBQyxHQUFHLElBQUksTUFBTSxDQUFDLE1BQUksQ0FBQyxJQUFJLENBQUMsRUFBRTtZQUM1QyxPQUFPLE1BQUksQ0FBQTtTQUNkO0tBQ0o7SUFBQyxPQUFPLEdBQUcsRUFBRTtRQUNWLHFCQUFxQjtLQUN4QjtJQUNELGlCQUFpQjtJQUNqQixJQUFJLEdBQUcsR0FBRyxNQUFNLENBQUMsV0FBVyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUEsQ0FBQyxzQkFBc0I7SUFDMUQsSUFBSSxJQUFJLEdBQUcsV0FBVyxDQUFBO0lBQ3RCLElBQUksS0FBSyxHQUFRLEVBQUMsR0FBRyxFQUFFLEdBQUcsQ0FBQyxPQUFPLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBQyxDQUFBLENBQUMseUNBQXlDO0lBQzdGLElBQUksS0FBSyxHQUFHLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQTtJQUN2QixJQUFJLElBQUksR0FBRyxFQUFDLEdBQUcsS0FBQSxFQUFFLElBQUksTUFBQSxFQUFFLEtBQUssT0FBQSxFQUFFLEtBQUssT0FBQSxFQUFDLENBQUE7SUFDcEMsT0FBTyxJQUFJLENBQUE7QUFDZixDQUFDO0FBbEJELHdCQWtCQztBQUVELHdDQUF3QztBQUN4QyxlQUFzQixHQUFVO0lBQzVCLE9BQU8sQ0FBQyxHQUFHLFlBQVksS0FBSyxDQUFDLENBQUE7SUFDekIsSUFBQSxnQkFBdUMsRUFBdEMsWUFBRyxFQUFFLGdCQUFLLEVBQUUsY0FBSSxFQUFFLGdCQUFLLENBQWU7SUFFM0MsdUJBQXVCO0lBQ3ZCLE9BQU8sS0FBSyxJQUFJLEtBQUssQ0FBQyxHQUFHLEdBQUc7UUFDeEIsSUFBSTtZQUNBLElBQUksSUFBSSxHQUFRLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFBO1lBQ3JDLEtBQUssR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFBO1NBQ3JCO1FBQUMsT0FBTyxHQUFHLEVBQUU7WUFDVixHQUFHLEdBQUcsS0FBSyxDQUFDLEdBQUcsQ0FBQTtZQUNmLElBQUksR0FBRyxLQUFLLENBQUMsSUFBSSxDQUFBO1lBQ2pCLEtBQUssR0FBRyxLQUFLLENBQUMsS0FBSyxDQUFBO1lBQ25CLEtBQUssR0FBRyxLQUFLLENBQUMsS0FBSyxDQUFBO1lBQ25CLE1BQUs7U0FDUjtLQUNKO0lBQ0QsT0FBTyxFQUFDLEdBQUcsS0FBQSxFQUFFLElBQUksTUFBQSxFQUFFLEtBQUssT0FBQSxFQUFFLEtBQUssT0FBQSxFQUFDLENBQUE7QUFDcEMsQ0FBQztBQWxCRCxzQkFrQkM7QUFFRCx5QkFBeUI7QUFDekIsaURBQWlEO0FBQ2pELDJCQUEyQjtBQUMzQiw4REFBOEQ7QUFDOUQsZ0RBQWdEO0FBQ2hELDRCQUE0QjtBQUM1Qix5RUFBeUU7QUFDekUsNEJBQTRCO0FBQzVCLDBDQUEwQztBQUMxQyxrQ0FBa0M7QUFDbEMsYUFBYTtBQUNiLFNBQVM7QUFDVCxJQUFJO0FBQ0osZ0JBQXVCLElBQWtDLEVBQUUsS0FBc0IsRUFBRSxZQUE2QjtJQUF6RixxQkFBQSxFQUFBLGtCQUFrQztJQUFFLHNCQUFBLEVBQUEsaUJBQXNCO0lBQUUsNkJBQUEsRUFBQSx3QkFBNkI7SUFDNUcseUNBQXlDO0lBQ3pDLElBQUksTUFBTSxHQUFRLENBQUMsQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFBO0lBQ3pELElBQUksTUFBTTtRQUFFLEtBQUssR0FBRyxZQUFZLENBQUE7SUFDaEMsSUFBSSxJQUFJLEdBQVEsRUFBRSxDQUFBO0lBQ2xCLElBQUksTUFBTSxHQUFHLHNDQUFzQyxFQUFFLENBQUE7SUFFckQsSUFBSSxJQUFJLFlBQVksS0FBSyxFQUFFO1FBQ3ZCLElBQUk7WUFDQSxJQUFJLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUE7WUFDL0IsOENBQThDO1lBQzlDLElBQUksQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsRUFBRTtnQkFDeEIsSUFBSSxDQUFDLEtBQUssR0FBRyxFQUFFLENBQUE7YUFDbEI7WUFDRCxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQTtTQUMxQjtRQUFDLE9BQU8sR0FBRyxFQUFFO1lBQ1YsU0FBUztTQUNaO1FBQ0QsYUFBYTtRQUNiLElBQUksSUFBSSxDQUFDLElBQUksSUFBSSxJQUFJLENBQUMsR0FBRyxJQUFJLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUU7WUFDNUMsMkNBQTJDO1lBQzNDLElBQUksQ0FBQyxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsRUFBRTtnQkFDdEIsb0JBQW9CO2dCQUNwQixJQUFJLEdBQUcsR0FBRyxJQUFJLEtBQUssQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUE7Z0JBQ3pDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQTtnQkFDWCxPQUFNO2FBQ1Q7aUJBQU07Z0JBQ0gsTUFBTSxJQUFJLEtBQUssQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUE7YUFDeEM7U0FDSjtRQUNELHNCQUFzQjtRQUN0QixJQUFJLEdBQUcsTUFBTSxDQUFDLElBQUksRUFBRSxLQUFLLENBQUMsQ0FBQTtRQUMxQixJQUFJLENBQUMsSUFBSSxHQUFHLFdBQVcsQ0FBQTtRQUN2QixJQUFJLENBQUMsR0FBRyxHQUFHLE1BQU0sQ0FBQyxXQUFXLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQSxDQUFDLDJCQUEyQjtRQUNoRSxJQUFJLENBQUMsS0FBSyxHQUFHLEVBQUMsR0FBRyxFQUFFLElBQUksQ0FBQyxPQUFPLEVBQUUsS0FBSyxPQUFBLEVBQUUsS0FBSyxFQUFFLENBQUMsTUFBTSxDQUFDLEVBQUMsQ0FBQTtLQUMzRDtTQUFNO1FBQ0gsbUJBQW1CO1FBQ25CLElBQUksR0FBRyxFQUFDLElBQUksTUFBQSxFQUFFLEdBQUcsRUFBRSxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUMsSUFBYyxDQUFDLENBQUMsSUFBSSxDQUFDLEVBQUUsS0FBSyxPQUFBLEVBQUUsS0FBSyxFQUFFLENBQUMsTUFBTSxDQUFDLEVBQUMsQ0FBQTtLQUNyRjtJQUVELCtCQUErQjtJQUMvQixJQUFJLENBQUMsQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUFDLEVBQUU7UUFDdEIsb0JBQW9CO1FBQ3BCLE1BQU0sQ0FBQyxJQUFJLEtBQUssQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQTtLQUMxQztTQUFNO1FBQ0gsa0JBQWtCO1FBQ2xCLE1BQU0sSUFBSSxLQUFLLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFBO0tBQ3hDO0FBQ0wsQ0FBQztBQWhERCx3QkFnREM7QUFFRCxpQkFBd0IsSUFBUyxFQUFFLElBQXlCLEVBQUUsS0FBVztJQUF0QyxxQkFBQSxFQUFBLGlCQUF5QjtJQUN4RCxJQUFJLE1BQU0sR0FBRyxzQ0FBc0MsRUFBRSxDQUFBO0lBQ3JELElBQUksS0FBSyxHQUFHLENBQUMsTUFBTSxDQUFDLENBQUE7SUFDcEIsSUFBSSxDQUFDLElBQUk7UUFBRSxNQUFNLElBQUksS0FBSyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsRUFBQyxJQUFJLE1BQUEsRUFBRSxHQUFHLEVBQUUsTUFBTSxDQUFDLFFBQVEsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLElBQUksQ0FBQyxFQUFFLEtBQUssT0FBQSxFQUFFLEtBQUssT0FBQSxFQUFDLENBQUMsQ0FBQyxDQUFBO0lBQ25HLE9BQU8sSUFBSSxDQUFBO0FBQ2YsQ0FBQztBQUxELDBCQUtDO0FBRUQsdUVBQXVFO0FBQ3ZFLHlGQUF5RjtBQUN6RixtR0FBbUc7QUFDbkcsaUVBQWlFO0FBQ2pFLCtCQUErQjtBQUMvQixzQkFBc0I7QUFDdEIsZUFBZTtBQUNmLG9DQUFvQztBQUNwQyxRQUFRO0FBQ1IsSUFBSTtBQUVKO0lBQXFCLGNBQU87U0FBUCxVQUFPLEVBQVAscUJBQU8sRUFBUCxJQUFPO1FBQVAseUJBQU87O0lBQ3hCLHNDQUFzQztJQUN0QyxJQUFJLE1BQU0sR0FBRyxzQ0FBc0MsRUFBRSxHQUFHLEdBQUcsR0FBRyxJQUFJLENBQUMseUJBQXlCLENBQUMsR0FBRyxHQUFHLENBQUE7SUFDbkcsSUFBSSxNQUFNLEdBQUcsYUFBYSxDQUFDLFNBQVMsQ0FBSyxJQUFJLFVBQUcsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFBO0lBQ3hELElBQUksTUFBTSxDQUFDLFNBQVMsQ0FBQyxJQUFJLE1BQU0sSUFBSSxDQUFDLHVCQUF1QixDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsRUFBRTtRQUN6RSwyQkFBMkI7UUFDM0IsT0FBTyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsU0FBUyxFQUFFLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUE7UUFDL0Msa0VBQWtFO1FBQ2xFLElBQU0sRUFBRSxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQTtRQUN4QixJQUFNLFdBQVcsR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFDLGNBQWMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLGNBQWMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxlQUFlLENBQUE7UUFDL0YsRUFBRSxDQUFDLGNBQWMsQ0FBQyxXQUFXLEVBQUUsTUFBTSxHQUFHLE1BQU0sR0FBRyxNQUFNLENBQUMsQ0FBQTtLQUMzRDtTQUFNO1FBQ0gsZ0RBQWdEO1FBQ2hELHlCQUF5QjtRQUN6QixNQUFNLEdBQUcsTUFBTSxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQTtRQUNyRCxPQUFPLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxTQUFTLEVBQUUsQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDLENBQUMsQ0FBQTtLQUNsRDtBQUNMLENBQUM7QUFqQkQsb0JBaUJDO0FBRUQsOEJBQThCO0FBQzlCLGdCQUFnQjtBQUNoQixZQUFZO0FBQ1osd0RBQXdEO0FBQ3hELGVBQWU7QUFDZixhQUFhO0FBQ2IsYUFBYTtBQUNiLEtBQUs7QUFDTCwyQkFBMkI7QUFDM0IsZUFBZTtBQUNmO0lBQXFCLGNBQU87U0FBUCxVQUFPLEVBQVAscUJBQU8sRUFBUCxJQUFPO1FBQVAseUJBQU87Ozs7Ozs7b0JBRXBCLE1BQU0sR0FBRyxzQ0FBc0MsRUFBRSxDQUFBO29CQUVyRCx1QkFBdUI7b0JBQ3ZCLElBQUksSUFBSSxDQUFDLE1BQU0sR0FBRyxDQUFDLElBQUksSUFBSSxDQUFDLENBQUMsQ0FBQyxZQUFZLEtBQUssRUFBRTt3QkFDN0MsSUFBSSxDQUFDLENBQUMsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQTtxQkFDNUI7b0JBRUcsR0FBRyxHQUFHLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyx5QkFBeUIsQ0FBQyxlQUFNLElBQUksRUFBRSxDQUFBO29CQUcxRCxZQUFZLEdBQUcsT0FBTyxDQUFDLHNDQUFzQyxDQUFDLENBQUE7b0JBQzlELE9BQU8sR0FBRyxPQUFPLENBQUMsaUNBQWlDLENBQUMsQ0FBQTtvQkFDeEQsSUFBSSxDQUFDLFlBQVksSUFBSSxDQUFDLE9BQU8sRUFBRTt3QkFDM0IsWUFBWSxHQUFHLGtFQUFrRSxDQUFBO3dCQUNqRixPQUFPLEdBQUcsQ0FBQyxhQUFhLENBQUMsQ0FBQTtxQkFDNUI7b0JBRUQscUJBQU0sS0FBSyxDQUFDLHVEQUFxRCxZQUFjLEVBQUU7NEJBQzdFLE9BQU8sRUFBRSxNQUFNOzRCQUNmLElBQUksRUFBRTtnQ0FDRixPQUFPLEVBQUUsR0FBRzs2QkFDZjs0QkFDRCxFQUFFLEVBQUU7Z0NBQ0EsU0FBUyxFQUFFLE9BQU87Z0NBQ2xCLE9BQU8sRUFBRSxLQUFLOzZCQUNqQjt5QkFDSixDQUFDO3dCQUVGLGdCQUFnQjt3QkFDaEIsb0JBQW9CO3NCQUhsQjs7b0JBVEYsU0FTRSxDQUFBO29CQUVGLGdCQUFnQjtvQkFDaEIsb0JBQW9CO29CQUNwQixJQUFJLENBQUMsR0FBRyxDQUFDLENBQUE7Ozs7O0NBQ1o7QUFFRCxvREFBb0Q7QUFDcEQsT0FBTyxDQUFDLEVBQUUsQ0FBQyxtQkFBbUIsRUFBRSxVQUFnQixHQUFHOzs7OztvQkFDL0MsSUFBSSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFBO29CQUNqQixxQkFBTSxLQUFLLENBQUMsR0FBRyxDQUFDLEVBQUE7O29CQUFoQixTQUFnQixDQUFBO29CQUNoQixPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUE7Ozs7O0NBQ25CLENBQUMsQ0FBQTtBQUVGLDJCQUEyQjtBQUMzQixPQUFPLENBQUMsRUFBRSxDQUFDLG9CQUFvQixFQUFFLFVBQU8sTUFBTSxFQUFFLENBQUM7Ozs7Z0JBQzdDLElBQUksQ0FBQyxpQ0FBaUMsRUFBRSxDQUFDLEVBQUUsU0FBUyxFQUFFLE1BQU0sQ0FBQyxDQUFDO2dCQUM5RCx1RUFBdUU7Z0JBQ3ZFLHFCQUFNLEtBQUssQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDLEVBQUE7O2dCQUR0Qix1RUFBdUU7Z0JBQ3ZFLFNBQXNCLENBQUE7Z0JBQ3RCLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQTs7OztLQUNuQixDQUFDLENBQUE7QUFFRiw4Q0FBOEM7QUFDOUMsSUFBTSxLQUFLLEdBQUcsT0FBTyxDQUFDLGFBQWEsQ0FBQyxFQUFFLENBQUE7QUFFdEMsZ0JBQXVCLEVBQWU7SUFBZixtQkFBQSxFQUFBLE1BQWMsQ0FBQztJQUNsQyxJQUFJLEVBQUUsSUFBSSxDQUFDLEVBQUU7UUFDVCxFQUFFLEdBQUcsRUFBRSxHQUFHLEdBQUcsR0FBRyxFQUFFLEdBQUcsSUFBSSxHQUFHLElBQUksQ0FBQSxDQUFDLHlCQUF5QjtLQUM3RDtJQUNELE9BQU8sSUFBSSxPQUFPLENBQUMsVUFBQyxPQUFPLEVBQUUsTUFBTTtRQUMvQixJQUFJO1lBQ0EsS0FBSyxDQUFDLEtBQUssQ0FBQyxFQUFFLEVBQUU7Z0JBQ1osT0FBTyxFQUFFLENBQUE7WUFDYixDQUFDLENBQUMsQ0FBQTtTQUNMO1FBQUMsT0FBTyxHQUFHLEVBQUU7WUFDVixJQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUE7WUFDakIsT0FBTyxFQUFFLENBQUE7WUFDVCxxQkFBcUI7U0FDeEI7SUFDTCxDQUFDLENBQUMsQ0FBQTtBQUNOLENBQUM7QUFmRCx3QkFlQztBQUVELGVBQTRCLEdBQVcsRUFBRSxLQUFtQyxFQUNoRCxPQUFxQyxFQUFFLE9BQXNCO0lBQXRCLHdCQUFBLEVBQUEsY0FBc0I7Ozs7OztvQkFDckYsdUNBQXVDO29CQUN2QyxPQUFPLEdBQUcsSUFBSSxDQUFBLENBQUMsaUJBQWlCO29CQUM1QixHQUFHLEdBQVEsSUFBSSxDQUFBO29CQUNmLElBQUksR0FBUSxJQUFJLENBQUE7b0JBQ2hCLElBQUksR0FBUSxJQUFJLENBQUE7Ozs7b0JBRVYscUJBQU0sS0FBSyxDQUFDLEdBQUcsRUFBRTs0QkFDbkIsTUFBTSxFQUFFLE1BQU07NEJBQ2QsSUFBSSxFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDOzRCQUMzQixPQUFPLGFBQUcsY0FBYyxFQUFFLGtCQUFrQixJQUFLLE9BQU8sQ0FBQzs0QkFDekQsT0FBTyxFQUFFLE9BQU8sSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTzt5QkFDdEMsQ0FBQyxFQUFBOztvQkFMRixHQUFHLEdBQUcsU0FLSixDQUFBO29CQUNLLHFCQUFNLEdBQUcsQ0FBQyxJQUFJLEVBQUUsRUFBQSxDQUFDLHlDQUF5Qzs7b0JBQWpFLElBQUksR0FBRyxTQUFnQixDQUFBLENBQUMseUNBQXlDO29CQUNqRSxJQUFJLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQTtvQkFDdkIsc0JBQU8sSUFBSSxFQUFBOzs7b0JBRVgsTUFBTSxDQUFDLEtBQUcsRUFBRSxFQUFDLEdBQUcsS0FBQSxFQUFFLEtBQUssT0FBQSxFQUFFLE9BQU8sU0FBQSxFQUFFLElBQUksTUFBQSxFQUFDLENBQUMsQ0FBQTs7Ozs7O0NBRS9DO0FBcEJELHNCQW9CQztBQUVELGFBQWE7QUFDYixjQUEyQixHQUFXLEVBQUUsS0FBbUMsRUFDaEQsT0FBcUMsRUFBRSxPQUFzQjtJQUF0Qix3QkFBQSxFQUFBLGNBQXNCOzs7Ozs7b0JBQ3BGLHVDQUF1QztvQkFDdkMsT0FBTyxHQUFHLElBQUksQ0FBQSxDQUFDLGlCQUFpQjtvQkFDNUIsR0FBRyxHQUFRLElBQUksQ0FBQTtvQkFDZixJQUFJLEdBQVEsSUFBSSxDQUFBO29CQUNoQixJQUFJLEdBQVEsSUFBSSxDQUFBOzs7O29CQUVoQixHQUFHLEdBQUcsR0FBRyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxHQUFHLFdBQVcsQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLENBQUE7b0JBQ3ZELHFCQUFNLEtBQUssQ0FBQyxHQUFHLEVBQUU7NEJBQ25CLE1BQU0sRUFBRSxLQUFLOzRCQUNiLE9BQU8sYUFBRyxjQUFjLEVBQUUsa0JBQWtCLElBQUssT0FBTyxDQUFDOzRCQUN6RCxPQUFPLEVBQUUsT0FBTyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPO3lCQUN0QyxDQUFDLEVBQUE7O29CQUpGLEdBQUcsR0FBRyxTQUlKLENBQUE7b0JBQ0sscUJBQU0sR0FBRyxDQUFDLElBQUksRUFBRSxFQUFBLENBQUMseUNBQXlDOztvQkFBakUsSUFBSSxHQUFHLFNBQWdCLENBQUEsQ0FBQyx5Q0FBeUM7b0JBQ2pFLElBQUksR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFBO29CQUN2QixzQkFBTyxJQUFJLEVBQUE7OztvQkFFWCxNQUFNLENBQUMsS0FBRyxFQUFFLEVBQUMsR0FBRyxLQUFBLEVBQUUsS0FBSyxPQUFBLEVBQUUsT0FBTyxTQUFBLEVBQUUsSUFBSSxNQUFBLEVBQUMsQ0FBQyxDQUFBOzs7Ozs7Q0FFL0M7QUFwQkQsb0JBb0JDO0FBRUQsZUFBZTtBQUNmLG1CQUEwQixHQUFXLEVBQUUsS0FBZTtJQUFmLHNCQUFBLEVBQUEsVUFBZTtJQUNsRCx5Q0FBeUM7SUFDekMsZ0NBQWdDO0lBQ2hDLE9BQU8sQ0FBQyxNQUFNLENBQUMsa0JBQWtCLENBQUMsS0FBSyxTQUFTLENBQUMsQ0FBQTtJQUNqRCxJQUFJLEtBQUssRUFBRTtRQUNQLE9BQU8sQ0FBQyxDQUFDLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUE7UUFDL0Isd0VBQXdFO1FBQ3hFLE9BQU8sS0FBSyxDQUFDLE9BQU8sQ0FBQTtRQUNwQixPQUFPLEtBQUssQ0FBQyxPQUFPLENBQUE7UUFDcEIsV0FBVztRQUNYLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRTtZQUNoQixHQUFHLElBQUksR0FBRyxDQUFBO1NBQ2I7YUFBTTtZQUNILEdBQUcsSUFBSSxHQUFHLENBQUE7U0FDYjtRQUNELEdBQUcsSUFBSSxXQUFXLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxDQUFBO0tBQ3RDO0lBQ0QsTUFBTSxDQUFDLGtCQUFrQixDQUFDLEdBQUcsR0FBRyxDQUFBO0FBQ3BDLENBQUM7QUFsQkQsOEJBa0JDO0FBRUQsMkVBQTJFO0FBQzNFLGlCQUF3QixHQUFZLEVBQUUsS0FBYyxFQUFFLE1BQVc7SUFDN0QsSUFBSSxDQUFDLFNBQVMsQ0FBQyxNQUFNLEVBQUU7UUFDbkIseUJBQXlCO1FBQ3pCLE9BQU8sTUFBTSxDQUFDLHFCQUFxQixDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUE7S0FDNUU7U0FBTSxJQUFJLFNBQVMsQ0FBQyxNQUFNLElBQUksQ0FBQyxFQUFFO1FBQzlCLE9BQU8sR0FBRyxDQUFDLENBQUMsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFBO0tBQzFDO1NBQU07UUFDSCxJQUFJLE1BQU0sQ0FBQyxxQkFBcUIsQ0FBQyxLQUFLLFNBQVMsRUFBRTtZQUM3QyxNQUFNLENBQUMscUJBQXFCLENBQUMsR0FBRyxFQUFFLENBQUE7U0FDckM7UUFDRCxJQUFJLEdBQUcsRUFBRTtZQUNMLCtDQUErQztZQUMvQyxNQUFNLEdBQUcsT0FBTyxDQUFDLEVBQUMsSUFBSSxFQUFFLEdBQUcsRUFBRSxNQUFNLEVBQUUsRUFBRSxHQUFHLElBQUksRUFBQyxFQUFFLE1BQU0sQ0FBQyxDQUFBO1lBQ3hELE1BQU0sQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxTQUFTLENBQUMsR0FBRyxFQUFFLEtBQUssRUFBRSxNQUFNLENBQUMsQ0FBQTtTQUM1RTtRQUNELE9BQU07S0FDVDtBQUNMLENBQUM7QUFqQkQsMEJBaUJDO0FBRUQsdUJBQXVCO0FBQ3ZCO0lBQ0ksSUFBTSxFQUFFLEdBQUcsSUFBSSxZQUFZLENBQUMsTUFBTSxDQUFDLGdCQUFnQixDQUFDLENBQUMsQ0FBQTtJQUNyRCxPQUFPLENBQUMsQ0FBQyxFQUFFLENBQUMsTUFBTSxFQUFFLENBQUE7QUFDeEIsQ0FBQztBQUVELGlCQUFpQixNQUFNLEVBQUUsTUFBTTtJQUFFLGNBQU87U0FBUCxVQUFPLEVBQVAscUJBQU8sRUFBUCxJQUFPO1FBQVAsNkJBQU87O0lBQ3BDLElBQU0sS0FBSyxJQUFJLElBQUksRUFBRSxNQUFNLEVBQUUsTUFBTSxTQUFLLElBQUksQ0FBQyxDQUFBO0lBQzdDLE9BQU8sTUFBTSxDQUFDLEtBQUssQ0FBQyxJQUFJLEVBQUUsS0FBSyxDQUFDLENBQUE7QUFDcEMsQ0FBQztBQUVELHlCQUF5QjtBQUN6QixpQkFBaUIsSUFBWSxFQUFFLFlBQTZCO0lBQTdCLDZCQUFBLEVBQUEsd0JBQTZCO0lBQ3hELElBQUksTUFBTSxDQUFDLFlBQVksQ0FBQyxFQUFFO1FBQ3RCLE9BQU8sQ0FBQyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsWUFBWSxDQUFDLEVBQUUsSUFBSSxFQUFFLFlBQVksQ0FBQyxDQUFBO0tBQ3pEO0lBRUQsSUFBTSxFQUFFLEdBQUcsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFBO0lBQzFCLElBQU0sRUFBRSxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQTtJQUN4QixrQ0FBa0M7SUFDbEMsSUFBSSxXQUFXLEdBQUcsRUFBRSxDQUFBO0lBQ3BCLElBQUksU0FBUyxDQUFDLFFBQVEsQ0FBQywyQkFBMkIsQ0FBQyxFQUFFO1FBQ2pELFNBQVM7UUFDVCxXQUFXLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsd0JBQXdCLENBQUMsQ0FBQTtLQUM3RDtTQUFNO1FBQ0gsY0FBYztRQUNkLFdBQVcsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxlQUFlLENBQUMsQ0FBQTtLQUNwRDtJQUVELGlEQUFpRDtJQUNqRCxJQUFNLGdCQUFnQixHQUFHLFdBQVcsR0FBRyxlQUFlLEdBQUcsbUJBQW1CLEVBQUUsQ0FBQTtJQUM5RSxJQUFNLGVBQWUsR0FBRyxXQUFXLElBQUcsYUFBVyxNQUFNLENBQUMsU0FBUyxDQUFDLE1BQUcsQ0FBQSxHQUFHLG1CQUFtQixFQUFFLENBQUE7SUFDN0YsSUFBSSxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsZ0JBQWdCLENBQUMsRUFBRTtRQUNsQyxPQUFPLFlBQVksQ0FBQTtLQUN0QjtJQUNELElBQUksV0FBVyxHQUFHLE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDLE9BQU8sQ0FBQTtJQUNuRCxJQUFJLFVBQVUsR0FBRyxFQUFFLENBQUE7SUFDbkIsSUFBSSxFQUFFLENBQUMsVUFBVSxDQUFDLGVBQWUsQ0FBQyxFQUFFO1FBQ2hDLFVBQVUsR0FBRyxPQUFPLENBQUMsZUFBZSxDQUFDLENBQUMsT0FBTyxDQUFBO0tBQ2hEO0lBQ0QsZ0NBQWdDO0lBQ2hDLG9FQUFvRTtJQUNwRSwrREFBK0Q7SUFDL0QsTUFBTSxDQUFDLFlBQVksQ0FBQyxHQUFHLE9BQU8sQ0FBQyxFQUFFLEVBQUUsV0FBVyxFQUFFLFVBQVUsQ0FBQyxDQUFBO0lBQzNELE9BQU8sQ0FBQyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsWUFBWSxDQUFDLEVBQUUsSUFBSSxFQUFFLFlBQVksQ0FBQyxDQUFBO0FBQzFELENBQUM7QUFFRCxrQkFBd0IsUUFBK0MsRUFBRSxNQUFrQjtJQUFsQix1QkFBQSxFQUFBLGtCQUFrQjs7OztZQUN2RixzQkFBTyxJQUFJLE9BQU8sQ0FBQyxVQUFPLE9BQU8sRUFBRSxNQUFNOzs7O3dCQUNqQyxHQUFHLEdBQUcsRUFBUyxDQUFBO3dCQUNuQixJQUFJOzRCQUNBLEdBQUcsR0FBRyxPQUFPLENBQUMsRUFBRSxFQUFFLE9BQU8sQ0FBQywwQkFBMEIsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFBOzRCQUMxRCxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxFQUFFLFNBQVMsRUFBRSxFQUFDLE1BQU0sUUFBQSxFQUFDLENBQUMsQ0FBQTs0QkFDN0MsZ0NBQWdDOzRCQUNoQyxJQUFJLFNBQVMsQ0FBQyxRQUFRLENBQUMsMkJBQTJCLENBQUMsRUFBRTtnQ0FDakQsU0FBUztnQ0FDVCxHQUFHLENBQUMsVUFBVSxDQUFDLEdBQUc7b0NBQ2QsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsNENBQTRDLEdBQUcsbUJBQW1CLEVBQUUsQ0FBQztpQ0FDN0YsQ0FBQTs2QkFDSjtpQ0FBTTtnQ0FDSCxjQUFjO2dDQUNkLEdBQUcsQ0FBQyxVQUFVLENBQUMsR0FBRztvQ0FDZCxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxtQ0FBbUMsR0FBRyxtQkFBbUIsRUFBRSxDQUFDO2lDQUNwRixDQUFBOzZCQUNKOzRCQUVLLEdBQUcsR0FBRyw4QkFBb0IsRUFBRSxDQUFBOzRCQUM1QixTQUFPLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQTs0QkFDNUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsTUFBSSxDQUFDLEVBQUU7Z0NBQ2hCLEdBQUcsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUE7NkJBQ2xCOzRCQUNLLE9BQUssR0FBRyxDQUFDLEdBQUcsQ0FBQyxNQUFJLENBQUMsQ0FBQTs0QkFDeEIsSUFBSSxNQUFNLENBQUMsY0FBYyxDQUFDLEtBQUssU0FBUyxFQUFFO2dDQUN0QyxNQUFNLENBQUMsY0FBYyxDQUFDLEdBQUcsRUFBRSxDQUFBOzZCQUM5Qjs0QkFDRCxJQUFJLENBQUMsSUFBRSxDQUFDLFdBQVcsRUFBRSxFQUFFLGtCQUFrQjtnQ0FDckMsTUFBTSxDQUFDLGNBQWMsQ0FBQyxDQUFDLE1BQUksQ0FBQyxHQUFHLElBQUUsQ0FBQyxPQUFPLEVBQUUsQ0FBQTs2QkFDOUM7NEJBQ0QsTUFBTSxDQUFDLGNBQWMsQ0FBQyxDQUFDLE1BQUksQ0FBQyxDQUFDLElBQUksQ0FBQyxVQUFNLFVBQVU7Ozs7OzRDQUM5QyxPQUFPLENBQUMsSUFBRSxDQUFDLFdBQVcsQ0FBQyxDQUFBOzRDQUNYLHFCQUFNLFFBQVEsQ0FBQyxVQUFVLENBQUM7Z0RBQ3RDLDhDQUE4Qzs4Q0FEUjs7NENBQWhDLEdBQUcsR0FBRyxTQUEwQjs0Q0FDdEMsOENBQThDOzRDQUM5QyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUE7Ozs7aUNBQ2YsQ0FBQyxDQUFDLEtBQUssQ0FBQyxVQUFNLEdBQUc7O29DQUNkLG1CQUFtQjtvQ0FDbkIsTUFBTSxDQUFDLEdBQUcsRUFBRSxNQUFNLEVBQUUsRUFBQyxNQUFNLFFBQUEsRUFBRSxJQUFJLFFBQUEsRUFBQyxDQUFDLENBQUE7OztpQ0FDdEMsQ0FBQyxDQUFBO3lCQUNMO3dCQUFDLE9BQU8sR0FBRyxFQUFFOzRCQUNWLE1BQU0sQ0FBQyxHQUFHLEVBQUUsTUFBTSxFQUFFLEVBQUMsTUFBTSxRQUFBLEVBQUMsQ0FBQyxDQUFBO3lCQUNoQzs7O3FCQUNKLENBQUMsRUFBQTs7O0NBQ0w7QUFFRCxpQ0FBaUM7QUFDakMsY0FBb0MsSUFBaUIsRUFBRSxLQUFXO0lBQUUsY0FBTztTQUFQLFVBQU8sRUFBUCxxQkFBTyxFQUFQLElBQU87UUFBUCw2QkFBTzs7SUFDdkUsYUFBYTtJQUNiLDZCQUE2QjtJQUM3Qix5REFBeUQ7SUFDekQsMENBQTBDO0lBQzFDLGVBQWU7SUFDZixJQUFJLEdBQUcsR0FBRyxJQUFJLElBQUksRUFBRSxDQUFBO0lBQ3BCLElBQUksQ0FBQyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsRUFBRTtRQUNsQixPQUFPLEdBQUcsQ0FBQTtLQUNiO0lBQ0QsSUFBSSxJQUFJLEdBQUcsdUJBQWEsQ0FBSSxJQUFJLENBQUMsQ0FBQTtJQUNqQyxJQUFJLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxJQUFJLEdBQUcsR0FBRyxFQUFFLEtBQUssU0FBSyxJQUFJLEVBQUUsQ0FBQTtJQUM3QyxPQUFPLEdBQUcsQ0FBQTtBQUNkLENBQUM7QUFFRCxhQUFhO0FBQ2IsZ0JBQW1CLE9BQW1CLEVBQUUsSUFBaUIsRUFBRSxLQUFjO0lBQ3JFLE9BQU8sT0FBTyxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsQ0FBQyxrQkFBa0IsQ0FBQyxLQUFLLENBQUMsQ0FBQTtBQUNoRSxDQUFDO0FBRUQsbUJBQW1CO0FBQ25CLGdCQUF5QixHQUEwQixFQUFFLElBQVksRUFBRSxJQUFZOzs7Ozs7b0JBQzNFLE9BQU8sQ0FBQyxJQUFJLElBQUksQ0FBQyxDQUFDLENBQUE7b0JBQ0kscUJBQU0sT0FBTyxDQUFDLEdBQUcsQ0FBQzs0QkFDcEMsR0FBRyxDQUFDLFFBQVEsRUFBRTs0QkFDZCxHQUFHLENBQUMsTUFBTSxDQUFDLENBQUMsSUFBSSxHQUFHLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQyxVQUFVLEVBQUU7eUJBQ3pELENBQUMsRUFBQTs7b0JBSEksS0FBZ0IsU0FHcEIsRUFISyxLQUFLLFFBQUEsRUFBRSxJQUFJLFFBQUE7b0JBSWxCLHNCQUFPLENBQUMsSUFBSSxFQUFFLEtBQUssQ0FBQyxFQUFBOzs7O0NBQ3ZCO0FBR0QsYUFBYTtBQUNiLGtDQUFrQztBQUNsQyxnQkFBZ0IsS0FBd0Y7SUFDcEcsUUFBUTtJQUNSLFlBQVk7SUFDWixZQUFZO0lBQ1osY0FBYztJQUNkLCtCQUErQjtJQUMvQiwwREFBMEQ7SUFDMUQsS0FBSyxHQUFHLE9BQU8sQ0FBQyxFQUFDLElBQUksRUFBRSxFQUFFLEVBQUUsSUFBSSxFQUFFLEVBQUUsRUFBRSxJQUFJLEVBQUUsRUFBRSxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBQyxFQUFFLEtBQUssQ0FBQyxDQUFBO0lBQ2pGLE9BQU8sVUFBVSxNQUFnQixFQUFFLFdBQW1CLEVBQUUsVUFBOEI7UUFBL0UsaUJBa0JOO1FBakJHLDZDQUE2QztRQUM3QyxrQkFBa0I7UUFDbEIsTUFBTSxDQUFDLFNBQVMsQ0FBQyxPQUFPLEdBQUc7WUFDdkIsT0FBTztnQkFDSCxLQUFLLEVBQUUsS0FBSztnQkFDWix5Q0FBeUM7Z0JBQ3pDLElBQUksRUFBRTs7Ozs7cUNBRUUsQ0FBQSxLQUFLLElBQUksS0FBSyxDQUFDLElBQUksQ0FBQSxFQUFuQix3QkFBbUI7Z0NBR2IsSUFBSSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQTtnQ0FDeEIsS0FBQSxPQUFPLENBQUE7Z0NBQUMscUJBQU0sSUFBSSxDQUFDLGNBQWMsRUFBRSxFQUFBOztnQ0FBbkMsa0JBQVEsU0FBMkIsRUFBRSxnQkFBZ0IsRUFBQyxDQUFBOzs7OztxQkFFN0Q7YUFDSixDQUFBO1FBQ0wsQ0FBQyxDQUFBO0lBQ0wsQ0FBQyxDQUFBO0FBQ0wsQ0FBQztBQUVELDZDQUE2QztBQUM3Qyx5REFBeUQ7QUFDekQsK0JBQStCO0FBQy9CLCtCQUErQjtBQUMvQixnQ0FBZ0M7QUFDaEMsdUNBQXVDO0FBQ3ZDLHVDQUF1QztBQUN2QyxzQkFBc0I7QUFDdEIsb0JBQW9CO0FBQ3BCLHlDQUF5QztBQUN6Qyx1Q0FBdUM7QUFDdkMseURBQXlEO0FBRXpELDRHQUE0RztBQUM1RyxlQUFrQixLQUFRO0lBQ3RCLE9BQU8sTUFBTSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQTtBQUM3QixDQUFDO0FBRUQsaUJBQWlCLElBQVksRUFBRSxJQUFXOztJQUN0QyxNQUFNLENBQUMsTUFBTSxDQUFDLE1BQU07UUFDaEIsR0FBQyxJQUFJLElBQUc7WUFBQyxjQUFPO2lCQUFQLFVBQU8sRUFBUCxxQkFBTyxFQUFQLElBQU87Z0JBQVAseUJBQU87O1lBQ1osT0FBTyxDQUFDLElBQUksQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUE7WUFDeEIsSUFBSSxJQUFJLENBQUMsTUFBTSxJQUFJLENBQUM7Z0JBQUUsT0FBTyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUE7WUFDcEMsSUFBSSxHQUFHLEdBQUcsSUFBSSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUE7WUFDekIsSUFBSSxHQUFHLEdBQUcsS0FBSyxDQUFDLFlBQVUsR0FBRyxNQUFHLENBQUMsQ0FBQTtZQUNqQyxPQUFPLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQTtRQUNwQixDQUFDO1lBQ0gsQ0FBQTtBQUNOLENBQUM7QUFFRCxxQ0FBcUM7QUFDckMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUM7SUFDakIsc0NBQXNDO0lBQ3RDLEVBQUUsRUFBRTtRQUFDLGNBQU87YUFBUCxVQUFPLEVBQVAscUJBQU8sRUFBUCxJQUFPO1lBQVAseUJBQU87O1FBQ1IsT0FBTyxPQUFPLENBQUMsUUFBUSxFQUFFLENBQUE7SUFDN0IsQ0FBQztJQUNELGlDQUFpQztJQUNqQyxNQUFNLEVBQUU7UUFBQyxjQUFPO2FBQVAsVUFBTyxFQUFQLHFCQUFPLEVBQVAsSUFBTztZQUFQLHlCQUFPOztRQUNaLElBQU0sSUFBSSxHQUFHO1lBQ1QsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRztZQUM3RixHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUc7WUFDM0MsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUc7WUFDdEMsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUc7WUFDdkIsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHO1NBQUMsQ0FBQTtRQUNoRCxJQUFJLEdBQUcsR0FBRyxJQUFJLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQTtRQUN6QixJQUFJLEdBQUcsR0FBRyxLQUFLLENBQUMsWUFBVSxHQUFHLE1BQUcsQ0FBQyxDQUFBO1FBQ2pDLElBQUksR0FBRyxHQUFHLEtBQUssQ0FBQywyQkFBMkIsQ0FBQyxDQUFBO1FBQzVDLE9BQU8sQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsU0FBUyxHQUFHLEdBQUcsR0FBRyxTQUFTLENBQUMsR0FBRyxFQUFFLENBQUE7SUFDekQsQ0FBQztJQUNELGNBQWM7SUFDZCxTQUFTLEVBQUU7UUFBQyxjQUFPO2FBQVAsVUFBTyxFQUFQLHFCQUFPLEVBQVAsSUFBTztZQUFQLHlCQUFPOztRQUNmLFFBQVEsSUFBSSxDQUFDLE1BQU0sRUFBRTtZQUNqQixLQUFLLENBQUM7Z0JBQ0YsT0FBTyxLQUFLLENBQUMsYUFBYSxDQUFDLENBQUE7WUFDL0IsS0FBSyxDQUFDO2dCQUNGLE9BQU8sS0FBSyxDQUFDLGlCQUFlLElBQUksQ0FBQyxDQUFDLENBQUMsTUFBRyxDQUFDLENBQUE7WUFDM0MsS0FBSyxDQUFDO2dCQUNGLE9BQU8sS0FBSyxDQUFDLGlCQUFlLElBQUksQ0FBQyxDQUFDLENBQUMsU0FBSSxJQUFJLENBQUMsQ0FBQyxDQUFDLE1BQUcsQ0FBQyxDQUFBO1lBQ3REO2dCQUNJLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQTtTQUNyQjtJQUVMLENBQUM7SUFDRCxRQUFRLEVBQUU7UUFBQyxjQUFPO2FBQVAsVUFBTyxFQUFQLHFCQUFPLEVBQVAsSUFBTztZQUFQLHlCQUFPOztRQUNkLFFBQVEsSUFBSSxDQUFDLE1BQU0sRUFBRTtZQUNqQixLQUFLLENBQUM7Z0JBQ0YsT0FBTyxLQUFLLENBQUMsWUFBWSxDQUFDLENBQUE7WUFDOUIsS0FBSyxDQUFDO2dCQUNGLE9BQU8sS0FBSyxDQUFDLGdCQUFjLElBQUksQ0FBQyxDQUFDLENBQUMsTUFBRyxDQUFDLENBQUE7WUFDMUMsS0FBSyxDQUFDO2dCQUNGLE9BQU8sS0FBSyxDQUFDLGdCQUFjLElBQUksQ0FBQyxDQUFDLENBQUMsU0FBSSxJQUFJLENBQUMsQ0FBQyxDQUFDLE1BQUcsQ0FBQyxDQUFBO1lBQ3JEO2dCQUNJLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQTtTQUNyQjtJQUVMLENBQUM7SUFDRCxLQUFLLEVBQUU7UUFBQyxjQUFPO2FBQVAsVUFBTyxFQUFQLHFCQUFPLEVBQVAsSUFBTztZQUFQLHlCQUFPOztRQUNYLFFBQVEsSUFBSSxDQUFDLE1BQU0sRUFBRTtZQUNqQixLQUFLLENBQUM7Z0JBQ0YsT0FBTyxLQUFLLENBQUMsU0FBUyxDQUFDLENBQUE7WUFDM0IsS0FBSyxDQUFDO2dCQUNGLE9BQU8sS0FBSyxDQUFDLGFBQVcsSUFBSSxDQUFDLENBQUMsQ0FBQyxNQUFHLENBQUMsQ0FBQTtZQUN2QyxLQUFLLENBQUM7Z0JBQ0YsT0FBTyxLQUFLLENBQUMsYUFBVyxJQUFJLENBQUMsQ0FBQyxDQUFDLFNBQUksSUFBSSxDQUFDLENBQUMsQ0FBQyxNQUFHLENBQUMsQ0FBQTtZQUNsRDtnQkFDSSxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUE7U0FDckI7SUFFTCxDQUFDO0NBQ0osQ0FBQyxDQUFBO0FBRUYsd0VBQXdFO0FBQ3hFLGdCQUFtQixLQUFRLEVBQUUsS0FBUSxFQUFFLFFBQWlCO0lBQ3BELElBQUksR0FBRyxHQUFHLElBQUksV0FBVyxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsQ0FBQTtJQUN2QyxJQUFJLEdBQUcsQ0FBQyxLQUFLLEVBQUUsRUFBRTtRQUNiLE1BQU0sQ0FBQyxTQUFTLEVBQUUsR0FBRyxDQUFDLE1BQU0sQ0FBQyxDQUFBO0tBQ2hDO0FBQ0wsQ0FBQztBQUVELG9EQUFvRDtBQUNwRCxlQUFrQixJQUFpQjtJQUMvQixJQUFNLENBQUMsR0FBUSxJQUFJLElBQUksRUFBRSxDQUFBO0lBQ3pCLE9BQU8sVUFBVSxDQUFDLElBQUksQ0FBSSxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsRUFBRSxDQUFDLE9BQU8sQ0FBQyxrQkFBZ0IsQ0FBQyxDQUFDLEVBQUksQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFBO0FBQy9FLENBQUM7QUFFRCxtQ0FBbUM7QUFDbkMsY0FBaUIsSUFBaUI7SUFDOUIsSUFBTSxDQUFDLEdBQVEsSUFBSSxJQUFJLEVBQUUsQ0FBQTtJQUN6QixPQUFPLFVBQVUsQ0FBQyxHQUFHLENBQUksQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFBO0FBQ2xDLENBQUM7QUFFRCxhQUFhO0FBQ2I7SUFBb0IsY0FBaUI7U0FBakIsVUFBaUIsRUFBakIscUJBQWlCLEVBQWpCLElBQWlCO1FBQWpCLHlCQUFpQjs7Ozs7Ozs7b0JBRXZCLE9BQU8sR0FBUSxFQUFFLENBQUE7b0JBQ3ZCLE9BQU8sQ0FBQyxHQUFHLEdBQUcsT0FBTyxDQUFDLEdBQUcsSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLFNBQVMsSUFBSSxPQUFPLENBQUMsR0FBRyxFQUFFLENBQUM7b0JBQ3BFLE9BQU8sQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLElBQUksQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUE7b0JBQ3JDLEdBQUcsR0FBRyxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUE7b0JBQ2xCLEdBQUcsR0FBRyxXQUFXLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxJQUFJLEVBQUUsT0FBTyxDQUFDLEVBQUMsS0FBSyxFQUFFLFNBQVMsRUFBQyxFQUFFLE9BQU8sQ0FBQyxDQUFDLENBQUE7b0JBQzdFLE9BQU8sQ0FBQyxHQUFHLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxXQUFXLEVBQUUsR0FBRyxDQUFDLENBQUE7b0JBQzNDLHNCQUFPLEdBQUcsRUFBQTs7O29CQUVWLHFCQUFNLEtBQUssQ0FBQyxLQUFHLENBQUMsRUFBQTs7b0JBQWhCLFNBQWdCLENBQUE7b0JBQ2hCLE1BQU0sQ0FBQyxLQUFHLENBQUMsQ0FBQTs7Ozs7O0NBRWxCO0FBRUQsK0JBQStCO0FBQy9CLGNBQXVCLE1BQVcsRUFBRSxPQUErQjs7O1lBQy9ELE9BQU8sQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQyxVQUFVLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQTtZQUNuRCxzQkFBTyxPQUFPLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUMsRUFBQTs7O0NBQzFDO0FBRUQseUVBQXlFO0FBQ3pFLG1CQUFtQjtBQUNuQixjQUFvQixLQUFhLEVBQUUsRUFBVTs7Ozs7WUFDbkMsR0FBRyxHQUFHLE9BQU8sQ0FBQyxhQUFhLENBQUMsQ0FBQTtZQUNsQyxPQUFPLENBQUMsS0FBSyxJQUFJLEdBQUcsSUFBSSxHQUFHLENBQUMsS0FBSyxDQUFDLEVBQUUsVUFBVSxFQUFFLEVBQUMsR0FBRyxLQUFBLEVBQUMsQ0FBQyxDQUFBO1lBQ2hELEdBQUcsR0FBRyxJQUFJLFNBQVMsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQTtZQUNyQyxzQkFBTyxJQUFJLE9BQU8sQ0FBQyxVQUFPLE9BQU8sRUFBRSxNQUFNOzt3QkFDckMsSUFBSTs0QkFDQSxFQUFFLENBQUM7Ozs7Ozs0Q0FFSyxLQUFLLEdBQUcsS0FBSyxHQUFHLEdBQUcsR0FBRyxNQUFNLENBQUMsU0FBUyxDQUFDLENBQUEsQ0FBQyx1QkFBdUI7NENBQy9DLHFCQUFNLEdBQUcsQ0FBQyxTQUFTLENBQUMsRUFBRSxFQUFFLEtBQUssQ0FBQyxFQUFBOzs0Q0FBeEMsT0FBTyxHQUFHLFNBQThCOzRDQUM5QyxPQUFPLENBQUMsT0FBTyxFQUFFLFVBQVUsRUFBRSxFQUFDLEVBQUUsSUFBQSxFQUFFLEtBQUssT0FBQSxFQUFDLENBQUMsQ0FBQTs0Q0FDekMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUFBOzs7OzRDQUVoQixNQUFNLENBQUMsS0FBRyxFQUFFLE1BQU0sRUFBRSxFQUFDLEVBQUUsSUFBQSxFQUFFLEtBQUssT0FBQSxFQUFFLEdBQUcsRUFBRSxHQUFHLENBQUMsS0FBSyxDQUFDLEVBQUMsQ0FBQyxDQUFBOzs7Ozs2QkFFeEQsQ0FBQyxDQUFDO3lCQUNOO3dCQUFDLE9BQU8sR0FBRyxFQUFFOzRCQUNWLE1BQU0sQ0FBQyxHQUFHLEVBQUUsTUFBTSxFQUFFLEVBQUMsRUFBRSxJQUFBLEVBQUUsS0FBSyxPQUFBLEVBQUUsR0FBRyxFQUFFLEdBQUcsQ0FBQyxLQUFLLENBQUMsRUFBQyxDQUFDLENBQUE7eUJBQ3BEOzs7cUJBQ0osQ0FBQyxFQUFBOzs7Q0FDTDtBQUVELGtGQUFrRjtBQUNsRixjQUFjLE1BQXNDO0lBQXRDLHVCQUFBLEVBQUEsOEJBQXNDO0lBQ2hELE9BQU8sTUFBTSxFQUFFLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFBO0FBQ2xDLENBQUM7QUFFRCxpQkFBaUI7QUFDakIsZUFBZSxLQUFrQztJQUFsQyxzQkFBQSxFQUFBLGlCQUFrQztJQUM3QyxJQUFJLEtBQUssSUFBSSxTQUFTLEVBQUU7UUFDcEIsT0FBTyxNQUFNLEVBQUUsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxPQUFPLEVBQUUsQ0FBQTtLQUNyQztJQUNELE9BQU8sQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQyxhQUFhLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQTtJQUNwRCxJQUFJLENBQUMsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLEVBQUU7UUFDbkIsaUJBQWlCO1FBQ2pCLE9BQU8sTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLE9BQU8sRUFBRSxDQUFBO0tBQzFDO1NBQU07UUFDSCxpQkFBaUI7UUFDakIsT0FBTyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsTUFBTSxDQUFDLHFCQUFxQixDQUFDLENBQUE7S0FDckQ7QUFDTCxDQUFDO0FBRUQsV0FBVztBQUNYLHVCQUF1QixLQUFhO0lBQ2hDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFBO0lBQy9DLE9BQU8sSUFBSSxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxDQUFBO0FBQy9DLENBQUM7QUFFRCxXQUFXO0FBQ1gsdUJBQXVCLEtBQWE7SUFDaEMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUE7SUFDL0MsT0FBTyxJQUFJLE1BQU0sQ0FBQyxLQUFLLEVBQUUsUUFBUSxDQUFDLENBQUMsUUFBUSxFQUFFLENBQUE7QUFDakQsQ0FBQztBQUVELGdFQUFnRTtBQUNoRSw2REFBNkQ7QUFDN0Q7SUFDSSwrQkFBK0I7SUFDL0IsVUFBVTtJQUNWLDhCQUE4QjtJQUM5QixnREFBZ0Q7SUFDaEQsK0VBQStFO0lBQy9FLHFDQUFxQztJQUNyQyxPQUFPLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQyxFQUFDLEtBQUssRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsR0FBRyxLQUFLLENBQUMsRUFBQyxDQUFDLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQTtJQUN4RixzRkFBc0Y7SUFDdEYsa0ZBQWtGO0lBQ2xGLHdEQUF3RDtJQUN4RCxrQ0FBa0M7SUFDbEMsd0JBQXdCO0lBQ3hCLGVBQWU7SUFDZiwrQkFBK0I7SUFDL0IsZ0NBQWdDO0lBQ2hDLHdDQUF3QztJQUN4QyxnQ0FBZ0M7SUFDaEMsK0NBQStDO0lBQy9DLHdCQUF3QjtJQUN4QixJQUFJO0lBQ0oseUJBQXlCO0lBQ3pCLCtDQUErQztJQUMvQyxlQUFlO0FBQ25CLENBQUM7QUFFRDs7OztHQUlHO0FBQ0gsYUFBYTtBQUNiLGtEQUFrRDtBQUNsRCwyQ0FBMkM7QUFDM0MsNERBQTREO0FBQzVELG9CQUFvQjtBQUNwQixpRkFBaUY7QUFDakYsd0RBQXdEO0FBQ3hELDhCQUE4QjtBQUM5QixzQ0FBc0M7QUFDdEMsZ0JBQWdCO0FBQ2hCLGFBQWE7QUFDYixRQUFRO0FBQ1Isd0RBQXdEO0FBQ3hELGdFQUFnRTtBQUNoRSwyQ0FBMkM7QUFDM0Msa0NBQWtDO0FBQ2xDLGFBQWE7QUFDYixTQUFTO0FBQ1QsSUFBSTtBQUdKLCtFQUErRTtBQUMvRTtJQUNJLGtGQUFrRjtJQUNsRixLQUFnQixVQUFtQixFQUFuQixLQUFBLE1BQU0sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLEVBQW5CLGNBQW1CLEVBQW5CLElBQW1CLEVBQUU7UUFBaEMsSUFBSSxHQUFHLFNBQUE7UUFDUixJQUFJLEdBQUcsQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLElBQUksR0FBRyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsRUFBRTtZQUM1QyxNQUFNLENBQUMsR0FBRyxDQUFDLEdBQUcsU0FBUyxDQUFBO1NBQzFCO0tBQ0o7SUFDRCxvQkFBb0I7SUFDcEIsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsRUFBRTtRQUNwQixNQUFNLENBQUMsU0FBUyxDQUFDLEdBQUcsT0FBTyxDQUFBLENBQUMsaUVBQWlFO0tBQ2hHO0lBQ0QsTUFBTSxDQUFDLFlBQVksQ0FBQyxHQUFHLFNBQVMsQ0FBQTtJQUNoQyxNQUFNLENBQUMsYUFBYSxDQUFDLEdBQUcsRUFBRSxDQUFBO0lBQzFCLE1BQU0sQ0FBQyxXQUFXLENBQUMsR0FBRyxFQUFFLENBQUE7SUFDeEIsTUFBTSxDQUFDLFVBQVUsQ0FBQyxHQUFHLEVBQUUsQ0FBQTtJQUN2QixNQUFNLENBQUMsZ0JBQWdCLENBQUMsR0FBRyxTQUFTLENBQUE7SUFDcEMsTUFBTSxDQUFDLGVBQWUsQ0FBQyxHQUFHLFNBQVMsQ0FBQTtJQUNuQyxNQUFNLENBQUMsa0JBQWtCLENBQUMsR0FBRyxTQUFTLENBQUE7SUFDdEMsTUFBTSxDQUFDLHFCQUFxQixDQUFDLEdBQUcsRUFBRSxDQUFBO0lBQ2xDLE1BQU0sQ0FBQyxxQkFBcUIsQ0FBQyxHQUFHLEVBQUUsQ0FBQTtBQUN0QyxDQUFDO0FBRUQsa0RBQWtEO0FBQ2xELE1BQU0sRUFBRSxDQUFBO0FBRVIsTUFBTSxDQUFDLFFBQVEsQ0FBQyxHQUFHLE1BQU0sQ0FBQTtBQUN6QixNQUFNLENBQUMsVUFBVSxDQUFDLEdBQUcsUUFBUSxDQUFBO0FBQzdCLE1BQU0sQ0FBQyxNQUFNLENBQUMsR0FBRyxJQUFJLENBQUE7QUFDckIsTUFBTSxDQUFDLFFBQVEsQ0FBQyxHQUFHLE1BQU0sQ0FBQTtBQUN6QixNQUFNLENBQUMsUUFBUSxDQUFDLEdBQUcsTUFBTSxDQUFBO0FBQ3pCLE1BQU0sQ0FBQyxTQUFTLENBQUMsR0FBRyxPQUFPLENBQUE7QUFDM0IsTUFBTSxDQUFDLFNBQVMsQ0FBQyxHQUFHLE9BQU8sQ0FBQTtBQUMzQixNQUFNLENBQUMsUUFBUSxDQUFDLEdBQUcsTUFBTSxDQUFBO0FBQ3pCLE1BQU0sQ0FBQyxTQUFTLENBQUMsR0FBRyxPQUFPLENBQUE7QUFDM0IsTUFBTSxDQUFDLFFBQVEsQ0FBQyxHQUFHLE1BQU0sQ0FBQTtBQUN6QixNQUFNLENBQUMsT0FBTyxDQUFDLEdBQUcsS0FBSyxDQUFBO0FBQ3ZCLE1BQU0sQ0FBQyxRQUFRLENBQUMsR0FBRyxNQUFNLENBQUE7QUFDekIsTUFBTSxDQUFDLE9BQU8sQ0FBQyxHQUFHLEtBQUssQ0FBQTtBQUN2QixNQUFNLENBQUMsTUFBTSxDQUFDLEdBQUcsSUFBSSxDQUFBO0FBQ3JCLE1BQU0sQ0FBQyxPQUFPLENBQUMsR0FBRyxLQUFLLENBQUE7QUFDdkIsTUFBTSxDQUFDLE1BQU0sQ0FBQyxHQUFHLElBQUksQ0FBQTtBQUNyQixNQUFNLENBQUMsUUFBUSxDQUFDLEdBQUcsTUFBTSxDQUFBO0FBQ3pCLE1BQU0sQ0FBQyxXQUFXLENBQUMsR0FBRyxTQUFTLENBQUE7QUFDL0IsTUFBTSxDQUFDLFNBQVMsQ0FBQyxHQUFHLE9BQU8sQ0FBQTtBQUMzQixNQUFNLENBQUMsV0FBVyxDQUFDLEdBQUcsU0FBUyxDQUFBO0FBQy9CLE1BQU0sQ0FBQyxVQUFVLENBQUMsR0FBRyxrQkFBUSxDQUFBO0FBQzdCLE1BQU0sQ0FBQyxPQUFPLENBQUMsR0FBRyxlQUFLLENBQUE7QUFDdkIsTUFBTSxDQUFDLFFBQVEsQ0FBQyxHQUFHLGdCQUFNLENBQUE7QUFDekIsTUFBTSxDQUFDLFFBQVEsQ0FBQyxHQUFHLE1BQU0sQ0FBQTtBQUN6QixNQUFNLENBQUMsT0FBTyxDQUFDLEdBQUcsS0FBSyxDQUFBO0FBQ3ZCLE1BQU0sQ0FBQyxTQUFTLENBQUMsR0FBRyxPQUFPLENBQUE7QUFDM0IsTUFBTSxDQUFDLFFBQVEsQ0FBQyxHQUFHLE1BQU0sQ0FBQTtBQUN6QixNQUFNLENBQUMsWUFBWSxDQUFDLEdBQUcsSUFBSSxxQkFBUyxFQUFFLENBQUEsQ0FBQyxhQUFhO0FBQ3BELE1BQU0sQ0FBQyxPQUFPLENBQUMsR0FBRyxLQUFLLENBQUE7QUFDdkIsTUFBTSxDQUFDLE1BQU0sQ0FBQyxHQUFHLElBQUksQ0FBQTtBQUNyQixNQUFNLENBQUMsT0FBTyxDQUFDLEdBQUcsRUFBRSxDQUFDLEtBQUssQ0FBQSxDQUFDLGdCQUFnQjtBQUMzQyxNQUFNLENBQUMsTUFBTSxDQUFDLEdBQUcsSUFBSSxDQUFBO0FBQ3JCLE1BQU0sQ0FBQyxNQUFNLENBQUMsR0FBRyxJQUFJLENBQUE7QUFDckIsTUFBTSxDQUFDLE1BQU0sQ0FBQyxHQUFHLElBQUksQ0FBQTtBQUNyQixNQUFNLENBQUMsZUFBZSxDQUFDLEdBQUcsYUFBYSxDQUFBO0FBQ3ZDLE1BQU0sQ0FBQyxlQUFlLENBQUMsR0FBRyxhQUFhLENBQUE7QUFDdkMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxHQUFHLElBQUksQ0FBQTtBQUNyQixNQUFNLENBQUMsT0FBTyxDQUFDLEdBQUcsS0FBSyxDQUFBO0FBQ3ZCLE1BQU0sQ0FBQyxPQUFPLENBQUMsR0FBRyxLQUFLLENBQUEiLCJzb3VyY2VzQ29udGVudCI6WyJwcm9jZXNzLmVudi5UWiA9ICdBc2lhL1NoYW5naGFpJ1xucHJvY2Vzcy5lbnYuTk9ERV9UTFNfUkVKRUNUX1VOQVVUSE9SSVpFRCA9ICcwJ1xuaW1wb3J0ICdyZWZsZWN0LW1ldGFkYXRhJ1xuaW1wb3J0IHtDb250YWluZXJ9IGZyb20gJ2ludmVyc2lmeSdcbmltcG9ydCB7Z2V0Q29ubmVjdGlvbk1hbmFnZXIsIENvbm5lY3Rpb24sIEJhc2VFbnRpdHksIGdldFJlcG9zaXRvcnksIFNlbGVjdFF1ZXJ5QnVpbGRlcn0gZnJvbSAnQGJ4anMvdHlwZW9ybSdcbmltcG9ydCB7eHNlc3Npb24sIHh1c2VyLCB4Y2FjaGV9IGZyb20gJy4vc2Vzc2lvbidcbmltcG9ydCAqIGFzICQkIGZyb20gJy4vcGx1Z2lucydcblxuY29uc3QgcGF0aCA9IHJlcXVpcmUoJ3BhdGgnKVxuY29uc3QgRXJyb3JTdGFja1BhcnNlciA9IHJlcXVpcmUoJ2Vycm9yLXN0YWNrLXBhcnNlcicpXG5jb25zdCBjb29raWUgPSByZXF1aXJlKCdjb29raWUnKVxuY29uc3QgTW9iaWxlRGV0ZWN0ID0gcmVxdWlyZSgnbW9iaWxlLWRldGVjdCcpXG5jb25zdCBmZXRjaCA9IHJlcXVpcmUoJ25vZGUtZmV0Y2gnKVxuY29uc3QgXyA9IHJlcXVpcmUoJ2xvZGFzaCcpXG5jb25zdCBtb21lbnQgPSByZXF1aXJlKCdtb21lbnQnKVxuY29uc3QgZXh0ZW5kID0gcmVxdWlyZSgnZXh0ZW5kJylcbmNvbnN0IHF1ZXJ5c3RyaW5nID0gcmVxdWlyZSgncXVlcnlzdHJpbmcnKVxuLy8gY29uc3QgcGFyYW1ldGVyID0gcmVxdWlyZSgncGFyYW1ldGVyJylcbi8vIGNvbnN0IHBhcmFtZXRlckNoZWNrSW5zdGFuY2UgPSBuZXcgcGFyYW1ldGVyKHtcbi8vICAgICAvLyB0cmFuc2xhdGU6IGZ1bmN0aW9uICgpIHtcbi8vICAgICAvLyAgICAgdmFyIGFyZ3MgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMpO1xuLy8gICAgIC8vICAgICAvLyBBc3N1bWUgdGhlcmUgaGF2ZSBJMThuLnQgbWV0aG9kIGZvciBjb252ZXJ0IGxhbmd1YWdlLlxuLy8gICAgIC8vICAgICByZXR1cm4gSTE4bi50LmFwcGx5KEkxOG4sIGFyZ3MpO1xuLy8gICAgIC8vIH1cbi8vIH0pXG5jb25zdCBjaXJjdWxhcl9qc29uID0gcmVxdWlyZShcImNpcmN1bGFyLWpzb25cIilcbmNvbnN0IG1vY2tqcyA9IHJlcXVpcmUoJ21vY2tqcycpXG5jb25zdCBzaG9ydGlkID0gcmVxdWlyZSgnc2hvcnRpZCcpXG5jb25zdCB2YWxpZGF0b3JqcyA9IHJlcXVpcmUoJ3ZhbGlkYXRvcmpzJylcbmNvbnN0IGNyb3NzX3NwYXduID0gcmVxdWlyZSgnY3Jvc3Mtc3Bhd24nKVxuY29uc3QgQUNNQ2xpZW50ID0gcmVxdWlyZSgnYW1iZXJfdXRmLTgnKVxuY29uc3QgY28gPSByZXF1aXJlKCdjbycpXG5cbi8vIEZJWE1FIEhBQ0vljp/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 |