@bxjs/base
Version:
bxjs base framework & api
456 lines • 69.9 kB
JavaScript
"use strict";
var __assign = (this && this.__assign) || Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
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;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
Object.defineProperty(exports, "__esModule", { value: true });
require('source-map-support').install();
require('tsconfig-paths').register();
var init_1 = require("./init");
var _ = require('lodash');
// // 临时调试线上日志打印
// //framework/index.ts(8,13): error TS2339: Property 'setLogLevel' does not exist on type 'Console'
// exports.handler = async function (event, context, callback) {
// // console.setLogLevel('error') 不能写在此会导致编译错误阿里云自己扩展的私有方法
// console.log('xxxxx', 'yyyyy', 'zzzzzz')
// console.error('xxxxx1', 'yyyyy1', 'zzzzzz1')
// let out = '<html><body>zzzzzz</body></html>'
// let htmlResponse = {
// isBase64Encoded: true,
// statusCode: 200,
// headers: {
// "Content-type": "text/html; charset=utf-8",
// },
// // base64 encode body so it can be safely returned as JSON value
// body: new Buffer(out as string).toString('base64')
// }
// callback(null, htmlResponse)
// }
// 基于阿里云的函数计算统一入口的路由处理
exports.handler = function (event, context, __callback__) {
return __awaiter(this, void 0, void 0, function () {
var callback, evt, jsonResponse, jsonResponse, jsonResponse, urlBase, url, bIsNeedRedirect, domain, __cors__, __api__, __url__, __header__, param, out, _a, post, body, err_1, cookie, setCookie, htmlResponse, jsonResponse, err_2;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
// 重置请求上下文环境变量
xreset();
// xlog('请求的参数event',event)
// xlog('请求的参数context',context)
// TODO 增加对于定时器的功能模拟实现
// 调试打印请求的输入和输出方便准确的定位调试线上的响应信息
xlog('$$$$1111=>' + event.toString());
callback = function (context, out) {
xlog('$$$$=>', out.body ? Object.assign({}, out, { body: xbase64decode(out.body) }) : out);
__callback__(context, out);
};
evt = JSON.parse(event.toString());
console.log('请求的参数evt', evt);
// FIXME yg 定制 ----- 暂时
if (/MP_verify_KEtrfArJjFUvBw93\.txt$/.test(evt.path)) {
jsonResponse = {
isBase64Encoded: false,
statusCode: 200,
headers: {
"Content-type": "text/plain",
},
body: 'KEtrfArJjFUvBw93'
};
return [2 /*return*/, callback(null, jsonResponse)];
}
// FIXME 蜜豆游学 定制 ----- 暂时
if (/MP_verify_fQngODKLLpay3tw5\.txt$/.test(evt.path)) {
jsonResponse = {
isBase64Encoded: false,
statusCode: 200,
headers: {
"Content-type": "text/plain",
},
body: 'MP_verify_fQngODKLLpay3tw5'
};
return [2 /*return*/, callback(null, jsonResponse)];
}
console.log('特殊路径匹配:', evt.path);
// FIXME 蜜豆游学 定制 ----- 暂时
if (/va6V9xUN8j\.txt$/.test(evt.path)) {
console.log('匹配成功');
jsonResponse = {
isBase64Encoded: false,
statusCode: 200,
headers: {
"Content-type": "text/plain",
},
body: '8de0c0c23097c6e90710cb48908a9738'
};
console.log('返回结果', JSON.stringify(jsonResponse));
return [2 /*return*/, callback(null, jsonResponse)];
}
// console.log('header中的参数:',evt['headers'])
// console.log('header中的数据:',JSON.stringify(evt['headers']))
// FIXME yg ====> 特殊路径处理
if (evt.httpMethod && evt['headers']['CA-Host'] && /[a-zA-Z0-9-_.]*\.youngget\.com$/.test(evt['headers']['CA-Host']) && /^\/share\/[0-9a-zA-Z\/+=]{1,}$/.test(evt.path)) {
urlBase = evt.path.split("/share/");
url = xbase64decode(urlBase[urlBase.length - 1]);
// console.log('查看解码之后的路径:',url)
callback(null, {
statusCode: 301,
headers: {
"Location": url,
},
});
return [2 /*return*/];
}
// TODO 需要对于事件定时器进行统一的约定在应用层可扩展自定义相关定时器等事件类型
if (evt['triggerName']) {
// 对定时触发器的统一拦截处理
switch (evt['triggerName']) {
// FC线上容器的预热定时器预置到开发框架上统一集成支持
case '__axjs-preheat-timer__':
// // 获取请求参数的配置数据
// try {
// let payload = JSON.parse(evt['payload'])
// xassert(payload['url'] && payload['timeout'])
// await xpost(payload['url'], payload['param'], undefined, payload['timeout'])
// } catch (err) {
// // ignore error
// xlog(JSON.stringify(xerror(err)).replace(/\r/g, '').replace(/\n/g, ''))
// }
break;
}
callback(null, {
statusCode: 200,
});
return [2 /*return*/];
}
// else if (evt['path'] === '/__axjs-preheat-timer__') {
// // 预热api网关的空请求心跳接口实现
// return
// }
// FIXME 全站HTTPS开启将HTTP请求做重定向跳转以及主域名跳转(例如youngget.com跳转到www.youngget.com)
// 由于api网关暂不支持在nginx上配置重定向跳转,需要在框架层面上做跳转配置支持此特性,解决部分老浏览器无法自动跳转问题。
// 仅仅对根请求开放支持HTTP和HTTPS双重请求,以便于支持自动重定向跳转功能实现。
if (evt.httpMethod == 'GET') {
bIsNeedRedirect = false;
domain = evt['headers']['CA-Host'];
if (/^[0-9a-zA-Z_-]+\.[0-9a-zA-Z_-]+$/.test(domain)) {
domain = 'www.' + domain; // 将一级域名强制跳转到www二级主域名上符合国际惯例约定俗成的规范标准化
bIsNeedRedirect = true;
}
if (evt['headers']['X-Forwarded-Proto'] == 'http') {
bIsNeedRedirect = true;
}
if (bIsNeedRedirect) {
callback(null, {
statusCode: 301,
headers: {
"Location": "https://" + domain + "/",
},
});
return [2 /*return*/];
}
}
// 根据API网关设置的环境常量参数正确配置线上版本的运行环境,取代AONE的本地、日常、预发、灰度等环境部署支持开发。
// 全局变量仅仅用于放在整个应用生命周期变量
global['__env__'] = _.get(evt, 'headers.__env__', 'prod');
__cors__ = {};
// FIXME yg定制需要生产环境下支付宝回调请求是跨域的需要支持options的跨域请求(临时放开限制,需要配置允许跨域的白名单列表在API网关上设置)
// if (global['__env__'] !== 'prod' && global['__env__'] !== 'gray') {
// // 非生产环境或灰度环境,需要禁用CORS功能禁止跨域访问增加安全性。
// if (evt.headers.origin) {
// // 获取源站动态允许请求跨域 (FIXME 需要进行安全限制对来源服务器网址合法性进行安全限制,本地开发调试全部放开请求)
// __cors__['Access-Control-Allow-Origin'] = evt.headers.origin
// // __cors__['Access-Control-Allow-Origin'] = '*' // 不能设置为任意值浏览器有安全限制
// }
// __cors__['Access-Control-Allow-Credentials'] = 'true'
// __cors__['Access-Control-Allow-Headers'] = 'Origin, X-Requested-With, Content-Type, Accept'
// __cors__['Access-Control-Allow-Methods'] = 'POST, OPTIONS'
// }
if (evt.headers.origin) {
// 获取源站动态允许请求跨域 (FIXME 需要进行安全限制对来源服务器网址合法性进行安全限制,本地开发调试全部放开请求)
__cors__['Access-Control-Allow-Origin'] = evt.headers.origin;
// __cors__['Access-Control-Allow-Origin'] = '*' // 不能设置为任意值浏览器有安全限制
}
__cors__['Access-Control-Allow-Credentials'] = 'true';
__cors__['Access-Control-Allow-Headers'] = 'Origin, X-Requested-With, Content-Type, Accept';
__cors__['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS'; // 支持协议约定格式
// 支持跨域的验证请求方法的合法性规避掉过滤掉不安全的请求。
switch (evt.httpMethod) {
case 'GET':
case 'POST':
break;
case 'OPTIONS':
// if (global['__env__'] == 'prod' || global['__env__'] == 'gray') {
// // 生产和灰度环境下禁止跨域OPTIONS请求以便于增强安全性
// callback(null, {
// statusCode: 501,
// })
// } else {
// // 非生产和灰度环境下才允许支持跨域OPTIONS请求
// callback(null, {
// statusCode: 200,
// headers: {
// ...__cors__,
// },
// })
// }
// FIXME yg定制需要生产环境下支付宝回调请求是跨域的需要支持options的跨域请求(临时放开限制,需要配置允许跨域的白名单列表在API网关上设置)
callback(null, {
statusCode: 200,
headers: __assign({}, __cors__),
});
return [2 /*return*/];
default:
// 禁止任何的非法请求严格进行约定限制
callback(null, {
statusCode: 502,
});
return [2 /*return*/];
}
global['__evt__'] = event.toString(); // FIXME 需要设计上下文定义请求实例生命周期变量
__api__ = _.get(evt, 'headers.__api__', evt.path) // 最终控制器与app子目录下的ts文件保持完全的一一映射关系。
;
__url__ = evt['headers']['X-Forwarded-Proto'] + '://' + evt['headers']['CA-Host'] + evt['path'];
__header__ = evt['headers'];
param = Object.assign({ __api__: __api__, __url__: __url__, __header__: __header__ }, // header请求中的两个框架层面上的预定义参数 TODO 需要移除掉并非应用关心的内容
evt.pathParameters || {}, // 路由重写参数 domain/[a]/[b]?xxx (可被GET参数覆盖)
evt.queryParameters || {} // GET请求参数 domain/path?a=x&b=x
);
out = {};
_a = evt.httpMethod;
switch (_a) {
case 'GET': return [3 /*break*/, 1];
case 'POST': return [3 /*break*/, 2];
}
return [3 /*break*/, 6];
case 1: return [3 /*break*/, 7];
case 2:
_b.trys.push([2, 3, , 5]);
post = {};
if (_.isString(evt.body)) {
body = evt.body;
if (evt.isBase64Encoded) {
body = new Buffer(evt.body, 'base64').toString();
}
post = init_1.parse_post_param(evt['headers'], body);
}
param = Object.assign(param, post); // 用post参数覆盖掉get参数,用于灵活的设置请求参数兼容get和post两种方法方便开发调试。
return [3 /*break*/, 5];
case 3:
err_1 = _b.sent();
// xlog(err, evt.httpMethod, evt.body)
return [4 /*yield*/, xwarn(err_1)
// 400 Bad Request 客户端请求的语法错误,服务器无法理解
];
case 4:
// xlog(err, evt.httpMethod, evt.body)
_b.sent();
// 400 Bad Request 客户端请求的语法错误,服务器无法理解
callback(null, {
statusCode: 503,
});
return [2 /*return*/];
case 5: return [3 /*break*/, 7];
case 6:
// xlog(evt.httpMethod, evt.body)
// 400 Bad Request 客户端请求的语法错误,服务器无法理解
callback(null, {
statusCode: 504,
});
return [2 /*return*/];
case 7:
_b.trys.push([7, 9, , 11]);
console.log('进入try');
cookie = _.get(evt['headers'], 'Cookie', undefined);
console.log('获取cookie信息', JSON.stringify(cookie));
if (!cookie) {
cookie = _.get(evt['headers'], 'cookie', '');
}
global['__request_cookies__'] = require('cookie').parse(cookie);
console.log('赋值给__request_cookies__', global['__request_cookies__']);
// 获取use-agent请求头部信息
global['__user_agent__'] = evt['headers']['User-Agent'];
console.log('赋值给__user_agent__', global['__user_agent__']);
// 获取客户端的IP地址信息
global['__client_ip__'] = evt['headers']['X-Real-IP'];
console.log('赋值给__client_ip__', global['__client_ip__']);
// TODO WEB请求需要对404页面以及ERROR页面进行兼容处理(在framework内部进行细节的错误判断在out中透传status的http的状态吗正确错误返回)
// 404 Not Found 服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置"您所请求的资源无法找到"的个性页面
// 403 Forbidden 服务器理解请求客户端的请求,但是拒绝执行此请求(权限验证处理错误)
// console.log('查看框架是否又错')
console.log('__api__是否出错', __api__);
return [4 /*yield*/, init_1.request_process(__api__, param)];
case 8:
out = _b.sent();
console.log('返回的out值', JSON.stringify(out));
if (_.isEmpty(out)) {
// 对于nowrap的情况做特殊容错处理
out = undefined;
}
setCookie = { 'Set-Cookie': undefined };
if (!_.isEmpty(global['__respond_cookies__'])) {
setCookie['Set-Cookie'] = _.values(global['__respond_cookies__']);
}
// console.log('查看redirect_url的值',global['__redirect_url__'])
if (global['__redirect_url__']) {
// console.log('进入第一个选项')
callback(null, {
statusCode: 302,
headers: __assign({ "Location": global['__redirect_url__'] }, setCookie),
});
global['__redirect_url__'] = undefined;
}
else if (_.isString(out)) {
htmlResponse = {
isBase64Encoded: true,
statusCode: 200,
headers: __assign({ "Content-type": "text/html; charset=utf-8" }, setCookie, __cors__),
// base64 encode body so it can be safely returned as JSON value
body: new Buffer(out).toString('base64')
};
callback(null, htmlResponse);
}
else {
jsonResponse = {
isBase64Encoded: true,
statusCode: 200,
headers: __assign({ "Content-type": "application/json" }, __cors__),
// base64 encode body so it can be safely returned as JSON value
body: new Buffer(out ? JSON.stringify(out) : '').toString('base64')
};
callback(null, jsonResponse);
}
return [3 /*break*/, 11];
case 9:
err_2 = _b.sent();
// 通知框架自身实现逻辑的意外报错(框架自身不论何种情况都应该正常工作,一旦出现此问题大多数情况是框架自身问题或者流量引发的运维问题)
return [4 /*yield*/, xwarn({
__api__: __api__, __url__: __url__, param: param, message: err_2.message, stack: xstack(err_2)
})
// 500 Internal Server Error 服务器内部错误,无法完成请求
];
case 10:
// 通知框架自身实现逻辑的意外报错(框架自身不论何种情况都应该正常工作,一旦出现此问题大多数情况是框架自身问题或者流量引发的运维问题)
_b.sent();
// 500 Internal Server Error 服务器内部错误,无法完成请求
callback(null, { statusCode: 505 });
return [3 /*break*/, 11];
case 11: return [2 /*return*/];
}
});
});
};
// API参数的识别逻辑,为普通字符串路径定义与app下的ts文件路由完全一一对应,优先取HEADER中的定义,再取GET中的形参定义或者POST形参定义进行参数请求的覆盖处理。
// PARAM请求的参数处理要求为BASE64编码化的JSON字符串。
// "event": {
// "body": "ewoJImFwaSI6ICIvYS9iL2MiLAoJInBhcmFtIjogImFzZGZhc2RmYXNkZiIKfQ==", => 对应于POST请求数据
// "headers": {
// "X-Ca-Api-Gateway": "B25CD51B-5815-4775-9EAB-6D481BC1AE17",
// "__api__": "/web/mobile/test", =》 自定义转义PATH的路径信息对于SEO优化兼容处理(也可以在GET或POST请求中传递对应参数)
// "X-Forwarded-For": "42.120.74.88",
// "Content-Type": "application/json"
// },
// "httpMethod": "POST",
// "isBase64Encoded": true,
// "path": "/", =》 没有意义用于前端根据需要自己进行扩展别名映射处理,后端的控制器不以此为标准,可以对同一个控制器定义N个不同的路径标识。
// "pathParameters": {},
// "queryParameters": {} => 对应于GET请求数据
// },
// "query": {},
// "context": {
// "requestId": "B25CD51B-5815-4775-9EAB-6D481BC1AE17",
// "credentials": {
// "accessKeyId": "",
// "accessKeySecret": "",
// "securityToken": ""
// },
// "function": {
// "name": "test",
// "handler": "index.handler",
// "memory": 128,
// "timeout": 300
// },
// "services": {
// "name": "alilang",
// "logProject": "",
// "logStore": ""
// },
// "region": "cn-shanghai",
// "accountId": "1734066057689528"
// }
// }
// 最新版本event的API网关的FC返回数据格式:
// CA-Host请求域名、
// X-Forwarded-Proto
// "path": "/test", ==》》基本上可以拼接出__url__参数可以省略掉此冗余参数配置了。
// ==》》借助route.map.ts文件的映射关系定义省略掉__api__配置进一步简化网关应用。
// "httpMethod": "GET",
// "isBase64Encoded": true,
// "X-Forwarded-For": "42.120.74.103", // 客户端请求IP地址用户判定所属区域信息海外访问问题优化依赖点
// "X-Real-IP": "42.120.74.103",
// Cookie
// User-Agent =>> PC站和M站自适应问题
// Accept-Language =>> 浏览器客户端的语言类型自动适配多语言架构设计问题
// let x = {
// "body": "",
// "headers": {
// "X-Ca-Api-Gateway": "B276F77B-334E-4857-AE64-65BAFD419E2A",
// "Cookie": "cna=r5snEzzOvA0CASp4Smdq+II/; UM_distinctid=162bcd61d9111cd-080e0f43e6b60d-33697b04-13c680-162bcd61d92c86; _tb_token_=H8U7BqixF3YVR3GnhMRz; NEW2_ACR_JSESSIONID=VM566F91-K5CP8QIVMQTSAH3C4H5X1-DRIHYJHJ-QE2; _new_cr_session0=1AbLByOMHeZe3G41KYd5WcPdC%2Fi8qvGHUBTK8Fbrfx8Soi%2BHELuxxA6jros7W%2FqC1YtebgB3auEF5lu1SCzUzTkt6v%2FiFeN%2FptbvBRziYEGXSEVhWnUlBR2tfpjrXMnIcfb2%2FwnGkH4vkeMIJ1Bvuw%3D%3D; emplId=149337; hrc_sidebar=open; traceId=7d4b16de-74bc-4eac-884b-54ca0354e4aa; SSO_LANG=ZH-CN; SSO_EMPID_HASH=9db1ed21402f7c36674b5e6e6de1fc68; animate_date=201864; aa=xxxxxxx; cn_1260001221_dplus=%7B%22distinct_id%22%3A%20%22162bcd61d9111cd-080e0f43e6b60d-33697b04-13c680-162bcd61d92c86%22%2C%22sp%22%3A%20%7B%22%24_sessionid%22%3A%200%2C%22%24_sessionTime%22%3A%201528086234%2C%22%24dp%22%3A%200%2C%22%24_sessionPVTime%22%3A%201528086234%7D%7D; isg=BDw8SonyS9utyn5fedYRe-uRDdzwNAD0-51BHha9_ScJ4dxrNkWw77KQxQmZqRi3",
// "X-Forwarded-Proto": "https",
// "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36",
// "__url__": "https://toufang.alibaba-inc.com/test",
// "CA-Host": "toufang.alibaba-inc.com",
// "Cache-Control": "max-age=0",
// "upgrade-insecure-requests": "1",
// "Accept-Language": "zh-CN,zh;q=0.9",
// "__api__": "/web/test/test",
// "Accept-Encoding": "gzip, deflate, br",
// "X-Forwarded-For": "42.120.74.103",
// "X-Real-IP": "42.120.74.103",
// "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8"
// },
// "httpMethod": "GET",
// "isBase64Encoded": true,
// "path": "/test",
// "pathParameters": {},
// "queryParameters": {}
// }
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXgtY2xpZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiaW5kZXgtY2xpZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLE9BQU8sQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDLE9BQU8sRUFBRSxDQUFBO0FBQ3ZDLE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDLFFBQVEsRUFBRSxDQUFBO0FBRXBDLCtCQUF3RDtBQUV4RCxJQUFNLENBQUMsR0FBRyxPQUFPLENBQUMsUUFBUSxDQUFDLENBQUE7QUFFM0IsZ0JBQWdCO0FBQ2hCLG9HQUFvRztBQUNwRyxnRUFBZ0U7QUFDaEUsK0RBQStEO0FBQy9ELDhDQUE4QztBQUM5QyxtREFBbUQ7QUFDbkQsbURBQW1EO0FBQ25ELDJCQUEyQjtBQUMzQixpQ0FBaUM7QUFDakMsMkJBQTJCO0FBQzNCLHFCQUFxQjtBQUNyQiwwREFBMEQ7QUFDMUQsYUFBYTtBQUNiLDJFQUEyRTtBQUMzRSw2REFBNkQ7QUFDN0QsUUFBUTtBQUNSLG1DQUFtQztBQUNuQyxJQUFJO0FBRUosc0JBQXNCO0FBQ3RCLE9BQU8sQ0FBQyxPQUFPLEdBQUcsVUFBZ0IsS0FBSyxFQUFFLE9BQU8sRUFBRSxZQUFZOzs7Ozs7b0JBQzFELGNBQWM7b0JBQ2QsTUFBTSxFQUFFLENBQUE7b0JBQ1IsMkJBQTJCO29CQUMzQiwrQkFBK0I7b0JBRy9CLHNCQUFzQjtvQkFFdEIsK0JBQStCO29CQUMvQixJQUFJLENBQUMsWUFBWSxHQUFHLEtBQUssQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFBO29CQUMvQixRQUFRLEdBQUcsVUFBQyxPQUFPLEVBQUUsR0FBRzt3QkFDMUIsSUFBSSxDQUFDLFFBQVEsRUFBRSxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLEVBQUUsRUFBRSxHQUFHLEVBQUUsRUFBQyxJQUFJLEVBQUUs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Q2pDLGdDQUFnQztBQUNoQyw2QkFBNkI7QUFDN0IsYUFBYTtBQUNiLG1DQUFtQztBQUNuQywwQ0FBMEM7QUFDMUMsUUFBUTtBQUNSLElBQUk7QUFFSiw0QkFBNEI7QUFDNUIsb0JBQW9CO0FBQ3BCLHlCQUF5QjtBQUN6Qiw0REFBNEQ7QUFDNUQsMEVBQTBFO0FBQzFFLDRCQUE0QjtBQUM1QixnQ0FBZ0M7QUFDaEMsNkVBQTZFO0FBQzdFLHFDQUFxQztBQUNyQyxjQUFjO0FBQ2Qsd0NBQXdDO0FBQ3hDLHFEQUFxRDtBQUNyRCxZQUFZO0FBQ1osa0JBQWtCO0FBQ2xCLG1CQUFtQjtBQUNuQixzRUFBc0U7QUFDdEUsbTZCQUFtNkI7QUFDbjZCLHdDQUF3QztBQUN4QyxxSkFBcUo7QUFDckosNkRBQTZEO0FBQzdELGdEQUFnRDtBQUNoRCx3Q0FBd0M7QUFDeEMsNENBQTRDO0FBQzVDLCtDQUErQztBQUMvQyx1Q0FBdUM7QUFDdkMsa0RBQWtEO0FBQ2xELDhDQUE4QztBQUM5Qyx3Q0FBd0M7QUFDeEMsNEdBQTRHO0FBQzVHLFNBQVM7QUFDVCwyQkFBMkI7QUFDM0IsK0JBQStCO0FBQy9CLHVCQUF1QjtBQUN2Qiw0QkFBNEI7QUFDNUIsNEJBQTRCO0FBQzVCLElBQUkiLCJzb3VyY2VzQ29udGVudCI6WyJyZXF1aXJlKCdzb3VyY2UtbWFwLXN1cHBvcnQnKS5pbnN0YWxsKClcbnJlcXVpcmUoJ3RzY29uZmlnLXBhdGhzJykucmVnaXN0ZXIoKVxuXG5pbXBvcnQge3JlcXVlc3RfcHJvY2VzcywgcGFyc2VfcG9zdF9wYXJhbX0gZnJvbSAnLi9pbml0J1xuXG5jb25zdCBfID0gcmVxdWlyZSgnbG9kYXNoJylcblxuLy8gLy8g5Li05pe26LCD6K+V57q/5LiK5pel5b+X5omT5Y2wXG4vLyAvL2ZyYW1ld29yay9pbmRleC50cyg4LDEzKTogZXJyb3IgVFMyMzM5OiBQcm9wZXJ0eSAnc2V0TG9nTGV2ZWwnIGRvZXMgbm90IGV4aXN0IG9uIHR5cGUgJ0NvbnNvbGUnXG4vLyBleHBvcnRzLmhhbmRsZXIgPSBhc3luYyBmdW5jdGlvbiAoZXZlbnQsIGNvbnRleHQsIGNhbGxiYWNrKSB7XG4vLyAgICAgLy8gY29uc29sZS5zZXRMb2dMZXZlbCgnZXJyb3InKSDkuI3og73lhpnlnKjmraTkvJrlr7zoh7TnvJbor5HplJnor6/pmL/ph4zkupHoh6rlt7HmianlsZXnmoTnp4HmnInmlrnms5Vcbi8vICAgICBjb25zb2xlLmxvZygneHh4eHgnLCAneXl5eXknLCAnenp6enp6Jylcbi8vICAgICBjb25zb2xlLmVycm9yKCd4eHh4eDEnLCAneXl5eXkxJywgJ3p6enp6ejEnKVxuLy8gICAgIGxldCBvdXQgPSAnPGh0bWw+PGJvZHk+enp6enp6PC9ib2R5PjwvaHRtbD4nXG4vLyAgICAgbGV0IGh0bWxSZXNwb25zZSA9IHtcbi8vICAgICAgICAgaXNCYXNlNjRFbmNvZGVkOiB0cnVlLFxuLy8gICAgICAgICBzdGF0dXNDb2RlOiAyMDAsXG4vLyAgICAgICAgIGhlYWRlcnM6IHtcbi8vICAgICAgICAgICAgIFwiQ29udGVudC10eXBlXCI6IFwidGV4dC9odG1sOyBjaGFyc2V0PXV0Zi04XCIsXG4vLyAgICAgICAgIH0sXG4vLyAgICAgICAgIC8vIGJhc2U2NCBlbmNvZGUgYm9keSBzbyBpdCBjYW4gYmUgc2FmZWx5IHJldHVybmVkIGFzIEpTT04gdmFsdWVcbi8vICAgICAgICAgYm9keTogbmV3IEJ1ZmZlcihvdXQgYXMgc3RyaW5nKS50b1N0cmluZygnYmFzZTY0Jylcbi8vICAgICB9XG4vLyAgICAgY2FsbGJhY2sobnVsbCwgaHRtbFJlc3BvbnNlKVxuLy8gfVxuXG4vLyDln7rkuo7pmL/ph4zkupHnmoTlh73mlbDorqHnrpfnu5/kuIDlhaXlj6PnmoTot6/nlLHlpITnkIZcbmV4cG9ydHMuaGFuZGxlciA9IGFzeW5jIGZ1bmN0aW9uIChldmVudCwgY29udGV4dCwgX19jYWxsYmFja19fKSB7XG4gICAgLy8g6YeN572u6K+35rGC5LiK5LiL5paH546v5aKD5Y+Y6YePXG4gICAgeHJlc2V0KClcbiAgICAvLyB4bG9nKCfor7fmsYLnmoTlj4LmlbBldmVudCcsZXZlbnQpXG4gICAgLy8geGxvZygn6K+35rGC55qE5Y+C5pWwY29udGV4dCcsY29udGV4dClcblxuXG4gICAgLy8gVE9ETyDlop7liqDlr7nkuo7lrprml7blmajnmoTlip/og73mqKHmi5/lrp7njrBcblxuICAgIC8vIOiwg+ivleaJk+WNsOivt+axgueahOi+k+WFpeWSjOi+k+WHuuaWueS+v+WHhuehrueahOWumuS9jeiwg+ivlee6v+S4iueahOWTjeW6lOS/oeaBr1xuICAgIHhsb2coJyQkJCQxMTExPT4nICsgZXZlbnQudG9TdHJpbmcoKSlcbiAgICBjb25zdCBjYWxsYmFjayA9IChjb250ZXh0LCBvdXQpID0+IHtcbiAgICAgICAgeGxvZygnJCQkJD0+Jywgb3V0LmJvZHkgPyBPYmplY3QuYXNzaWduKHt9LCBvdXQsIHtib2R5OiB4YmFzZTY0ZGVjb2RlKG91dC5ib2R5KX0pIDogb3V0KVxuICAgICAgICBfX2NhbGxiYWNrX18oY29udGV4dCwgb3V0KVxuICAgIH1cblxuICAgIGxldCBldnQgPSBKU09OLnBhcnNlKGV2ZW50LnRvU3RyaW5nKCkpXG4gICAgY29uc29sZS5sb2coJ+ivt+axgueahOWPguaVsGV2dCcsZXZ0KVxuXG4gICAvLyBGSVhNRSB5ZyDlrprliLYgIC0tLS0tIOaaguaXtlxuICAgIGlmKC9NUF92ZXJpZnlfS0V0cmZBckpqRlV2Qnc5M1xcLnR4dCQvLnRlc3QoZXZ0LnBhdGgpKXtcbiAgICAgICAgbGV0IGpzb25SZXNwb25zZSA9IHtcbiAgICAgICAgICAgIGlzQmFzZTY0RW5jb2RlZDogZmFsc2UsXG4gICAgICAgICAgICBzdGF0dXNDb2RlOiAyMDAsXG4gICAgICAgICAgICBoZWFkZXJzOiB7XG4gICAgICAgICAgICAgICAgXCJDb250ZW50LXR5cGVcIjogXCJ0ZXh0L3BsYWluXCIsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgYm9keTogJ0tFdHJmQXJKakZVdkJ3OTMnXG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGNhbGxiYWNrKG51bGwsIGpzb25SZXNwb25zZSlcbiAgICB9XG4gICAgIC8vIEZJWE1FIOicnOixhua4uOWtpiDlrprliLYgIC0tLS0tIOaaguaXtlxuICAgICBpZigvTVBfdmVyaWZ5X2ZRbmdPREtMTHBheTN0dzVcXC50eHQkLy50ZXN0KGV2dC5wYXRoKSl7XG4gICAgICAgIGxldCBqc29uUmVzcG9uc2UgPSB7XG4gICAgICAgICAgICBpc0Jhc2U2NEVuY29kZWQ6IGZhbHNlLFxuICAgICAgICAgICAgc3RhdHVzQ29kZTogMjAwLFxuICAgICAgICAgICAgaGVhZGVyczoge1xuICAgICAgICAgICAgICAgIFwiQ29udGVudC10eXBlXCI6IFwidGV4dC9wbGFpblwiLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGJvZHk6ICdNUF92ZXJpZnlfZlFuZ09ES0xMcGF5M3R3NSdcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gY2FsbGJhY2sobnVsbCwganNvblJlc3BvbnNlKVxuICAgIH1cbiAgICBjb25zb2xlLmxvZygn54m55q6K6Lev5b6E5Yy56YWN77yaJyxldnQucGF0aClcbiAgICAgIC8vIEZJWE1FIOicnOixhua4uOWtpiDlrprliLYgIC0tLS0tIOaaguaXtlxuICAgIGlmKC92YTZWOXhVTjhqXFwudHh0JC8udGVzdChldnQucGF0aCkpe1xuICAgICAgICBjb25zb2xlLmxvZygn5Yy56YWN5oiQ5YqfJylcbiAgICAgICAgbGV0IGpzb25SZXNwb25zZSA9IHtcbiAgICAgICAgICAgIGlzQmFzZTY0RW5jb2RlZDogZmFsc2UsXG4gICAgICAgICAgICBzdGF0dXNDb2RlOiAyMDAsXG4gICAgICAgICAgICBoZWFkZXJzOiB7XG4gICAgICAgICAgICAgICAgXCJDb250ZW50LXR5cGVcIjogXCJ0ZXh0L3BsYWluXCIsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgYm9keTogJzhkZTBjMGMyMzA5N2M2ZTkwNzEwY2I0ODkwOGE5NzM4J1xuICAgICAgICB9XG4gICAgICAgIGNvbnNvbGUubG9nKCfov5Tlm57nu5PmnpwnLEpTT04uc3RyaW5naWZ5KGpzb25SZXNwb25zZSkpXG4gICAgICAgIHJldHVybiBjYWxsYmFjayhudWxsLCBqc29uUmVzcG9uc2UpXG4gICAgfVxuICAgIC8vIGNvbnNvbGUubG9nKCdoZWFkZXLkuK3nmoTlj4LmlbDvvJonLGV2dFsnaGVhZGVycyddKVxuICAgIC8vIGNvbnNvbGUubG9nKCdoZWFkZXLkuK3nmoTmlbDmja46JyxKU09OLnN0cmluZ2lmeShldnRbJ2hlYWRlcnMnXSkpXG4gICAgLy8gRklYTUUgeWcgID09PT0+IOeJueauiui3r+W+hOWkhOeQhlxuICAgIGlmIChldnQuaHR0cE1ldGhvZCAmJiBldnRbJ2hlYWRlcnMnXVsnQ0EtSG9zdCddICYmIC9bYS16QS1aMC05LV8uXSpcXC55b3VuZ2dldFxcLmNvbSQvLnRlc3QoZXZ0WydoZWFkZXJzJ11bJ0NBLUhvc3QnXSkgJiYgL15cXC9zaGFyZVxcL1swLTlhLXpBLVpcXC8rPV17MSx9JC8udGVzdChldnQucGF0aCkpIHtcbiAgICAgICAgbGV0IHVybEJhc2UgPSBldnQucGF0aC5zcGxpdChcIi9zaGFyZS9cIilcbiAgICAgICAgLy8gY29uc29sZS5sb2coJ+afpeeci+WIhuino+WIhuino+S5i+WQjueahOWcsOWdgCcsdXJsQmFzZSlcbiAgICAgICAgbGV0IHVybCA9IHhiYXNlNjRkZWNvZGUodXJsQmFzZVt1cmxCYXNlLmxlbmd0aCAtIDFdKVxuICAgICAgICAvLyBjb25zb2xlLmxvZygn5p+l55yL6Kej56CB5LmL5ZCO55qE6Lev5b6E77yaJyx1cmwpXG4gICAgICAgIGNhbGxiYWNrKG51bGwsIHtcbiAgICAgICAgICAgIHN0YXR1c0NvZGU6IDMwMSwgLy8g5rC45LmF6YeN5a6a5ZCRXG4gICAgICAgICAgICBoZWFkZXJzOiB7XG4gICAgICAgICAgICAgICAgXCJMb2NhdGlvblwiOiB1cmwsIC8vIOeJueauiui3r+W+hOWkhOeQhlxuICAgICAgICAgICAgfSxcbiAgICAgICAgfSlcbiAgICAgICAgcmV0dXJuXG4gICAgfVxuXG4gICAgLy8gVE9ETyDpnIDopoHlr7nkuo7kuovku7blrprml7blmajov5vooYznu5/kuIDnmoTnuqblrprlnKjlupTnlKjlsYLlj6/mianlsZXoh6rlrprkuYnnm7jlhbPlrprml7blmajnrYnkuovku7bnsbvlnotcbiAgICBpZiAoZXZ0Wyd0cmlnZ2VyTmFtZSddKSB7XG4gICAgICAgIC8vIOWvueWumuaXtuinpuWPkeWZqOeahOe7n+S4gOaLpuaIquWkhOeQhlxuICAgICAgICBzd2l0Y2ggKGV2dFsndHJpZ2dlck5hbWUnXSkge1xuICAgICAgICAgICAgLy8gRkPnur/kuIrlrrnlmajnmoTpooTng63lrprml7blmajpooTnva7liLDlvIDlj5HmoYbmnrbkuIrnu5/kuIDpm4bmiJDmlK/mjIFcbiAgICAgICAgICAgIGNhc2UgJ19fYXhqcy1wcmVoZWF0LXRpbWVyX18nOlxuICAgICAgICAgICAgICAgIC8vIC8vIOiOt+WPluivt+axguWPguaVsOeahOmFjee9ruaVsOaNrlxuICAgICAgICAgICAgICAgIC8vIHRyeSB7XG4gICAgICAgICAgICAgICAgLy8gICAgIGxldCBwYXlsb2FkID0gSlNPTi5wYXJzZShldnRbJ3BheWxvYWQnXSlcbiAgICAgICAgICAgICAgICAvLyAgICAgeGFzc2VydChwYXlsb2FkWyd1cmwnXSAmJiBwYXlsb2FkWyd0aW1lb3V0J10pXG4gICAgICAgICAgICAgICAgLy8gICAgIGF3YWl0IHhwb3N0KHBheWxvYWRbJ3VybCddLCBwYXlsb2FkWydwYXJhbSddLCB1bmRlZmluZWQsIHBheWxvYWRbJ3RpbWVvdXQnXSlcbiAgICAgICAgICAgICAgICAvLyB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgICAgICAgICAvLyAgICAgLy8gaWdub3JlIGVycm9yXG4gICAgICAgICAgICAgICAgLy8gICAgIHhsb2coSlNPTi5zdHJpbmdpZnkoeGVycm9yKGVycikpLnJlcGxhY2UoL1xcci9nLCAnJykucmVwbGFjZSgvXFxuL2csICcnKSlcbiAgICAgICAgICAgICAgICAvLyB9XG4gICAgICAgICAgICAgICAgYnJlYWtcbiAgICAgICAgfVxuICAgICAgICBjYWxsYmFjayhudWxsLCB7XG4gICAgICAgICAgICBzdGF0dXNDb2RlOiAyMDAsXG4gICAgICAgIH0pXG4gICAgICAgIHJldHVyblxuICAgIH1cbiAgICAvLyBlbHNlIGlmIChldnRbJ3BhdGgnXSA9PT0gJy9fX2F4anMtcHJlaGVhdC10aW1lcl9fJykge1xuICAgIC8vICAgICAvLyDpooTng61hcGnnvZHlhbPnmoTnqbror7fmsYLlv4Pot7PmjqXlj6Plrp7njrBcbiAgICAvLyAgICAgcmV0dXJuXG4gICAgLy8gfVxuXG4gICAgLy8gRklYTUUg5YWo56uZSFRUUFPlvIDlkK/lsIZIVFRQ6K+35rGC5YGa6YeN5a6a5ZCR6Lez6L2s5Lul5Y+K5Li75Z+f5ZCN6Lez6L2sKOS+i+WmgnlvdW5nZ2V0LmNvbei3s+i9rOWIsHd3dy55b3VuZ2dldC5jb20pXG4gICAgLy8g55Sx5LqOYXBp572R5YWz5pqC5LiN5pSv5oyB5ZyobmdpbnjkuIrphY3nva7ph43lrprlkJHot7PovazvvIzpnIDopoHlnKjmoYbmnrblsYLpnaLkuIrlgZrot7PovazphY3nva7mlK/mjIHmraTnibnmgKfvvIzop6PlhrPpg6jliIbogIHmtY/op4jlmajml6Dms5Xoh6rliqjot7Povazpl67popjjgIJcbiAgICAvLyDku4Xku4Xlr7nmoLnor7fmsYLlvIDmlL7mlK/mjIFIVFRQ5ZKMSFRUUFPlj4zph43or7fmsYLvvIzku6Xkvr/kuo7mlK/mjIHoh6rliqjph43lrprlkJHot7Povazlip/og73lrp7njrDjgIJcbiAgICBpZiAoZXZ0Lmh0dHBNZXRob2QgPT0gJ0dFVCcpIHtcbiAgICAgICAgbGV0IGJJc05lZWRSZWRpcmVjdCA9IGZhbHNlXG4gICAgICAgIGxldCBkb21haW4gPSBldnRbJ2hlYWRlcnMnXVsnQ0EtSG9zdCddXG4gICAgICAgIGlmICgvXlswLTlhLXpBLVpfLV0rXFwuWzAtOWEtekEtWl8tXSskLy50ZXN0KGRvbWFpbikpIHtcbiAgICAgICAgICAgIGRvbWFpbiA9ICd3d3cuJyArIGRvbWFpbiAvLyDlsIbkuIDnuqfln5/lkI3lvLrliLbot7PovazliLB3d3fkuoznuqfkuLvln5/lkI3kuIrnrKblkIjlm73pmYXmg6/kvovnuqblrprkv5fmiJDnmoTop4TojIPmoIflh4bljJZcbiAgICAgICAgICAgIGJJc05lZWRSZWRpcmVjdCA9IHRydWVcbiAgICAgICAgfVxuICAgICAgICBpZiAoZXZ0WydoZWFkZXJzJ11bJ1gtRm9yd2FyZGVkLVByb3RvJ10gPT0gJ2h0dHAnKSB7XG4gICAgICAgICAgICBiSXNOZWVkUmVkaXJlY3QgPSB0cnVlXG4gICAgICAgIH1cbiAgICAgICAgaWYgKGJJc05lZWRSZWRpcmVjdCkge1xuICAgICAgICAgICAgY2FsbGJhY2sobnVsbCwge1xuICAgICAgICAgICAgICAgIHN0YXR1c0NvZGU6IDMwMSwgLy8g5rC45LmF6YeN5a6a5ZCRXG4gICAgICAgICAgICAgICAgaGVhZGVyczoge1xuICAgICAgICAgICAgICAgICAgICBcIkxvY2F0aW9uXCI6IGBodHRwczovLyR7ZG9tYWlufS9gLCAvLyDlhajpg6jph43lrprlkJHliLDpppbpobXkuI3mlK/mjIHpnZ7ms5XnvZHlnYBcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIHJldHVyblxuICAgICAgICB9XG4gICAgfVxuXG4gICAgLy8g5qC55o2uQVBJ572R5YWz6K6+572u55qE546v5aKD5bi46YeP5Y+C5pWw5q2j56Gu6YWN572u57q/5LiK54mI5pys55qE6L+Q6KGM546v5aKD77yM5Y+W5LujQU9OReeahOacrOWcsOOAgeaXpeW4uOOAgemihOWPkeOAgeeBsOW6puetieeOr+Wig+mDqOe9suaUr+aMgeW8gOWPkeOAglxuICAgIC8vIOWFqOWxgOWPmOmHj+S7heS7heeUqOS6juaUvuWcqOaVtOS4quW6lOeUqOeUn+WRveWRqOacn+WPmOmHj1xuICAgIGdsb2JhbFsnX19lbnZfXyddID0gXy5nZXQoZXZ0LCAnaGVhZGVycy5fX2Vudl9fJywgJ3Byb2QnKVxuXG4gICAgY29uc3QgX19jb3JzX18gPSB7fVxuICAgIC8vIEZJWE1FIHln5a6a5Yi26ZyA6KaB55Sf5Lqn546v5aKD5LiL5pSv5LuY5a6d5Zue6LCD6K+35rGC5piv6Leo5Z+f55qE6ZyA6KaB5pSv5oyBb3B0aW9uc+eahOi3qOWfn+ivt+axgu+8iOS4tOaXtuaUvuW8gOmZkOWItu+8jOmcgOimgemFjee9ruWFgeiuuOi3qOWfn+eahOeZveWQjeWNleWIl+ihqOWcqEFQSee9keWFs+S4iuiuvue9ru+8iVxuICAgIC8vIGlmIChnbG9iYWxbJ19fZW52X18nXSAhPT0gJ3Byb2QnICYmIGdsb2JhbFsnX19lbnZfXyddICE9PSAnZ3JheScpIHtcbiAgICAvLyAgICAgLy8g6Z2e55Sf5Lqn546v5aKD5oiW54Gw5bqm546v5aKD77yM6ZyA6KaB56aB55SoQ09SU+WKn+iDveemgeatoui3qOWfn+iuv+mXruWinuWKoOWuieWFqOaAp+OAglxuICAgIC8vICAgICBpZiAoZXZ0LmhlYWRlcnMub3JpZ2luKSB7XG4gICAgLy8gICAgICAgICAvLyDojrflj5bmupDnq5nliqjmgIHlhYHorrjor7fmsYLot6jln58gKEZJWE1FIOmcgOimgei/m+ihjOWuieWFqOmZkOWItuWvueadpea6kOacjeWKoeWZqOe9keWdgOWQiOazleaAp+i/m+ihjOWuieWFqOmZkOWItu+8jOacrOWcsOW8gOWPkeiwg+ivleWFqOmDqOaUvuW8gOivt+axgilcbiAgICAvLyAgICAgICAgIF9fY29yc19fWydBY2Nlc3MtQ29udHJvbC1BbGxvdy1PcmlnaW4nXSA9IGV2dC5oZWFkZXJzLm9yaWdpblxuICAgIC8vICAgICAgICAgLy8gX19jb3JzX19bJ0FjY2Vzcy1Db250cm9sLUFsbG93LU9yaWdpbiddID0gJyonIC8vIOS4jeiDveiuvue9ruS4uuS7u+aEj+WAvOa1j+iniOWZqOacieWuieWFqOmZkOWItlxuICAgIC8vICAgICB9XG4gICAgLy8gICAgIF9fY29yc19fWydBY2Nlc3MtQ29udHJvbC1BbGxvdy1DcmVkZW50aWFscyddID0gJ3RydWUnXG4gICAgLy8gICAgIF9fY29yc19fWydBY2Nlc3MtQ29udHJvbC1BbGxvdy1IZWFkZXJzJ10gPSAnT3JpZ2luLCBYLVJlcXVlc3RlZC1XaXRoLCBDb250ZW50LVR5cGUsIEFjY2VwdCdcbiAgICAvLyAgICAgX19jb3JzX19bJ0FjY2Vzcy1Db250cm9sLUFsbG93LU1ldGhvZHMnXSA9ICdQT1NULCBPUFRJT05TJ1xuICAgIC8vIH1cbiAgICBpZiAoZXZ0LmhlYWRlcnMub3JpZ2luKSB7XG4gICAgICAgIC8vIOiOt+WPlua6kOermeWKqOaAgeWFgeiuuOivt+axgui3qOWfnyAoRklYTUUg6ZyA6KaB6L+b6KGM5a6J5YWo6ZmQ5Yi25a+55p2l5rqQ5pyN5Yqh5Zmo572R5Z2A5ZCI5rOV5oCn6L+b6KGM5a6J5YWo6ZmQ5Yi277yM5pys5Zyw5byA5Y+R6LCD6K+V5YWo6YOo5pS+5byA6K+35rGCKVxuICAgICAgICBfX2NvcnNfX1snQWNjZXNzLUNvbnRyb2wtQWxsb3ctT3JpZ2luJ10gPSBldnQuaGVhZGVycy5vcmlnaW5cbiAgICAgICAgLy8gX19jb3JzX19bJ0FjY2Vzcy1Db250cm9sLUFsbG93LU9yaWdpbiddID0gJyonIC8vIOS4jeiDveiuvue9ruS4uuS7u+aEj+WAvOa1j+iniOWZqOacieWuieWFqOmZkOWItlxuICAgIH1cbiAgICBfX2NvcnNfX1snQWNjZXNzLUNvbnRyb2wtQWxsb3ctQ3JlZGVudGlhbHMnXSA9ICd0cnVlJ1xuICAgIF9fY29yc19fWydBY2Nlc3MtQ29udHJvbC1BbGxvdy1IZWFkZXJzJ10gPSAnT3JpZ2luLCBYLVJlcXVlc3RlZC1XaXRoLCBDb250ZW50LVR5cGUsIEFjY2VwdCdcbiAgICBfX2NvcnNfX1snQWNjZXNzLUNvbnRyb2wtQWxsb3ctTWV0aG9kcyddID0gJ0dFVCwgUE9TVCwgT1BUSU9OUycgLy8g5pSv5oyB5Y2P6K6u57qm5a6a5qC85byPXG5cbiAgICAvLyDmlK/mjIHot6jln5/nmoTpqozor4Hor7fmsYLmlrnms5XnmoTlkIjms5XmgKfop4Tpgb/mjonov4fmu6TmjonkuI3lronlhajnmoTor7fmsYLjgIJcbiAgICBzd2l0Y2ggKGV2dC5odHRwTWV0aG9kKSB7XG4gICAgICAgIGNhc2UgJ0dFVCc6XG4gICAgICAgIGNhc2UgJ1BPU1QnOlxuICAgICAgICAgICAgYnJlYWtcbiAgICAgICAgY2FzZSAnT1BUSU9OUyc6XG4gICAgICAgICAgICAvLyBpZiAoZ2xvYmFsWydfX2Vudl9fJ10gPT0gJ3Byb2QnIHx8IGdsb2JhbFsnX19lbnZfXyddID09ICdncmF5Jykge1xuICAgICAgICAgICAgLy8gICAgIC8vIOeUn+S6p+WSjOeBsOW6pueOr+Wig+S4i+emgeatoui3qOWfn09QVElPTlPor7fmsYLku6Xkvr/kuo7lop7lvLrlronlhajmgKdcbiAgICAgICAgICAgIC8vICAgICBjYWxsYmFjayhudWxsLCB7XG4gICAgICAgICAgICAvLyAgICAgICAgIHN0YXR1c0NvZGU6IDUwMSxcbiAgICAgICAgICAgIC8vICAgICB9KVxuICAgICAgICAgICAgLy8gfSBlbHNlIHtcbiAgICAgICAgICAgIC8vICAgICAvLyDpnZ7nlJ/kuqflkozngbDluqbnjq/looPkuIvmiY3lhYHorrjmlK/mjIHot6jln59PUFRJT05T6K+35rGCXG4gICAgICAgICAgICAvLyAgICAgY2FsbGJhY2sobnVsbCwge1xuICAgICAgICAgICAgLy8gICAgICAgICBzdGF0dXNDb2RlOiAyMDAsXG4gICAgICAgICAgICAvLyAgICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICAgIC8vICAgICAgICAgICAgIC4uLl9fY29yc19fLFxuICAgICAgICAgICAgLy8gICAgICAgICB9LFxuICAgICAgICAgICAgLy8gICAgIH0pXG4gICAgICAgICAgICAvLyB9XG4gICAgICAgICAgICAvLyBGSVhNRSB5Z+WumuWItumcgOimgeeUn+S6p+eOr+Wig+S4i+aUr+S7mOWuneWbnuiwg+ivt+axguaYr+i3qOWfn+eahOmcgOimgeaUr+aMgW9wdGlvbnPnmoTot6jln5/or7fmsYLvvIjkuLTml7bmlL7lvIDpmZDliLbvvIzpnIDopoHphY3nva7lhYHorrjot6jln5/nmoTnmb3lkI3ljZXliJfooajlnKhBUEnnvZHlhbPkuIrorr7nva7vvIlcbiAgICAgICAgICAgIGNhbGxiYWNrKG51bGwsIHtcbiAgICAgICAgICAgICAgICBzdGF0dXNDb2RlOiAyMDAsXG4gICAgICAgICAgICAgICAgaGVhZGVyczoge1xuICAgICAgICAgICAgICAg