UNPKG

50.2 kBJavaScriptView Raw
1"use strict";
2var __assign = (this && this.__assign) || Object.assign || function(t) {
3 for (var s, i = 1, n = arguments.length; i < n; i++) {
4 s = arguments[i];
5 for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
6 t[p] = s[p];
7 }
8 return t;
9};
10var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
11 return new (P || (P = Promise))(function (resolve, reject) {
12 function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
13 function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
14 function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
15 step((generator = generator.apply(thisArg, _arguments || [])).next());
16 });
17};
18var __generator = (this && this.__generator) || function (thisArg, body) {
19 var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
20 return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
21 function verb(n) { return function (v) { return step([n, v]); }; }
22 function step(op) {
23 if (f) throw new TypeError("Generator is already executing.");
24 while (_) try {
25 if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
26 if (y = 0, t) op = [op[0] & 2, t.value];
27 switch (op[0]) {
28 case 0: case 1: t = op; break;
29 case 4: _.label++; return { value: op[1], done: false };
30 case 5: _.label++; y = op[1]; op = [0]; continue;
31 case 7: op = _.ops.pop(); _.trys.pop(); continue;
32 default:
33 if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
34 if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
35 if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
36 if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
37 if (t[2]) _.ops.pop();
38 _.trys.pop(); continue;
39 }
40 op = body.call(thisArg, _);
41 } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
42 if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
43 }
44};
45Object.defineProperty(exports, "__esModule", { value: true });
46require('source-map-support').install();
47require('tsconfig-paths').register();
48var init_1 = require("./init");
49var _ = require('lodash');
50// // 临时调试线上日志打印
51// //framework/index.ts(8,13): error TS2339: Property 'setLogLevel' does not exist on type 'Console'
52// exports.handler = async function (event, context, callback) {
53// // console.setLogLevel('error') 不能写在此会导致编译错误阿里云自己扩展的私有方法
54// console.log('xxxxx', 'yyyyy', 'zzzzzz')
55// console.error('xxxxx1', 'yyyyy1', 'zzzzzz1')
56// let out = '<html><body>zzzzzz</body></html>'
57// let htmlResponse = {
58// isBase64Encoded: true,
59// statusCode: 200,
60// headers: {
61// "Content-type": "text/html; charset=utf-8",
62// },
63// // base64 encode body so it can be safely returned as JSON value
64// body: new Buffer(out as string).toString('base64')
65// }
66// callback(null, htmlResponse)
67// }
68// 基于阿里云的函数计算统一入口的路由处理
69exports.handler = function (event, context, callback) {
70 return __awaiter(this, void 0, void 0, function () {
71 var evt, __cors__, _a, payload, err_1, __api__, __url__, __header__, param, out, _b, post, body, err_2, cookie, setCookie, htmlResponse, jsonResponse, err_3;
72 return __generator(this, function (_c) {
73 switch (_c.label) {
74 case 0:
75 // TODO 增加对于定时器的功能模拟实现
76 // xlog('$$$$=>' + event.toString())
77 // TODO 去除掉换行方便方便SLS上的日志输出排版显示
78 xlog('$$$$=>' + event.toString().replace(/\r/g, '').replace(/\n/g, ''));
79 evt = JSON.parse(event.toString());
80 // 根据API网关设置的环境常量参数正确配置线上版本的运行环境,取代AONE的本地、日常、预发、灰度等环境部署支持开发。
81 // 全局变量仅仅用于放在整个应用生命周期变量
82 global['__env__'] = _.get(evt, 'headers.__env__', 'prod');
83 __cors__ = {};
84 if (global['__env__'] !== 'prod' && global['__env__'] !== 'gray') {
85 // 非生产环境或灰度环境,需要禁用CORS功能禁止跨域访问增加安全性。
86 if (evt.headers.origin) {
87 // 获取源站动态允许请求跨域 (FIXME 需要进行安全限制对来源服务器网址合法性进行安全限制,本地开发调试全部放开请求)
88 __cors__['Access-Control-Allow-Origin'] = evt.headers.origin;
89 // __cors__['Access-Control-Allow-Origin'] = '*' // 不能设置为任意值浏览器有安全限制
90 }
91 __cors__['Access-Control-Allow-Credentials'] = 'true';
92 __cors__['Access-Control-Allow-Headers'] = 'Origin, X-Requested-With, Content-Type, Accept';
93 __cors__['Access-Control-Allow-Methods'] = 'POST, OPTIONS';
94 }
95 // 支持跨域的验证请求方法的合法性规避掉过滤掉不安全的请求。
96 switch (evt.httpMethod) {
97 case 'GET':
98 case 'POST':
99 break;
100 case 'OPTIONS':
101 if (global['__env__'] == 'prod' || global['__env__'] == 'gray') {
102 // 生产和灰度环境下禁止跨域OPTIONS请求以便于增强安全性
103 callback(null, {
104 statusCode: 400,
105 });
106 }
107 else {
108 // 非生产和灰度环境下才允许支持跨域OPTIONS请求
109 callback(null, {
110 statusCode: 200,
111 headers: __assign({}, __cors__),
112 });
113 }
114 return [2 /*return*/];
115 default:
116 // 禁止任何的非法请求严格进行约定限制
117 callback(null, {
118 statusCode: 400,
119 });
120 return [2 /*return*/];
121 }
122 if (!evt['triggerName']) return [3 /*break*/, 6];
123 _a = evt['triggerName'];
124 switch (_a) {
125 case '__axjs-preheat-timer__': return [3 /*break*/, 1];
126 }
127 return [3 /*break*/, 5];
128 case 1:
129 _c.trys.push([1, 3, , 4]);
130 payload = JSON.parse(evt['payload']);
131 xassert(payload['url'] && payload['timeout']);
132 return [4 /*yield*/, xpost(payload['url'], payload['param'], undefined, payload['timeout'])];
133 case 2:
134 _c.sent();
135 return [3 /*break*/, 4];
136 case 3:
137 err_1 = _c.sent();
138 // ignore error
139 xlog(JSON.stringify(xerror(err_1)).replace(/\r/g, '').replace(/\n/g, ''));
140 return [3 /*break*/, 4];
141 case 4: return [3 /*break*/, 5];
142 case 5: return [2 /*return*/];
143 case 6:
144 if (evt['path'] === '/__axjs-preheat-timer__') {
145 // 预热api网关的空请求心跳接口实现
146 return [2 /*return*/];
147 }
148 _c.label = 7;
149 case 7:
150 global['__evt__'] = event.toString(); // FIXME 需要设计上下文定义请求实例生命周期变量
151 __api__ = _.get(evt, 'headers.__api__', evt.path) // 最终控制器与app子目录下的ts文件保持完全的一一映射关系。
152 ;
153 __url__ = evt['headers']['X-Forwarded-Proto'] + '://' + evt['headers']['CA-Host'] + evt['path'];
154 __header__ = evt['headers'];
155 param = Object.assign({ __api__: __api__, __url__: __url__, __header__: __header__ }, // header请求中的两个框架层面上的预定义参数 TODO 需要移除掉并非应用关心的内容
156 evt.pathParameters || {}, // 路由重写参数 domain/[a]/[b]?xxx (可被GET参数覆盖)
157 evt.queryParameters || {} // GET请求参数 domain/path?a=x&b=x
158 );
159 out = {};
160 _b = evt.httpMethod;
161 switch (_b) {
162 case 'GET': return [3 /*break*/, 8];
163 case 'POST': return [3 /*break*/, 9];
164 }
165 return [3 /*break*/, 13];
166 case 8: return [3 /*break*/, 14];
167 case 9:
168 _c.trys.push([9, 10, , 12]);
169 post = {};
170 if (_.isString(evt.body)) {
171 body = evt.body;
172 if (evt.isBase64Encoded) {
173 body = new Buffer(evt.body, 'base64').toString();
174 }
175 post = init_1.parse_post_param(evt['headers'], body);
176 }
177 param = Object.assign(param, post); // 用post参数覆盖掉get参数,用于灵活的设置请求参数兼容get和post两种方法方便开发调试。
178 return [3 /*break*/, 12];
179 case 10:
180 err_2 = _c.sent();
181 xlog(err_2, evt.httpMethod, evt.body);
182 return [4 /*yield*/, xwarn(err_2)
183 // 400 Bad Request 客户端请求的语法错误,服务器无法理解
184 ];
185 case 11:
186 _c.sent();
187 // 400 Bad Request 客户端请求的语法错误,服务器无法理解
188 callback(null, {
189 statusCode: 400,
190 });
191 return [2 /*return*/];
192 case 12: return [3 /*break*/, 14];
193 case 13:
194 xlog(evt.httpMethod, evt.body);
195 // 400 Bad Request 客户端请求的语法错误,服务器无法理解
196 callback(null, {
197 statusCode: 400,
198 });
199 return [2 /*return*/];
200 case 14:
201 _c.trys.push([14, 16, , 18]);
202 cookie = _.get(evt['headers'], 'Cookie', undefined);
203 if (!cookie) {
204 cookie = _.get(evt['headers'], 'cookie', '');
205 }
206 global['__request_cookies__'] = require('cookie').parse(cookie);
207 // 获取use-agent请求头部信息
208 global['__user_agent__'] = evt['headers']['User-Agent'];
209 // 获取客户端的IP地址信息
210 global['__client_ip__'] = evt['headers']['X-Real-IP'];
211 return [4 /*yield*/, init_1.request_process(__api__, param)
212 // 处理response的cookies设置
213 ];
214 case 15:
215 // TODO WEB请求需要对404页面以及ERROR页面进行兼容处理(在framework内部进行细节的错误判断在out中透传status的http的状态吗正确错误返回)
216 // 404 Not Found 服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置"您所请求的资源无法找到"的个性页面
217 // 403 Forbidden 服务器理解请求客户端的请求,但是拒绝执行此请求(权限验证处理错误)
218 out = _c.sent();
219 setCookie = { 'Set-Cookie': undefined };
220 if (!_.isEmpty(global['__respond_cookies__'])) {
221 setCookie['Set-Cookie'] = _.values(global['__respond_cookies__']);
222 }
223 if (global['__redirect_url__']) {
224 callback(null, {
225 statusCode: 302,
226 headers: __assign({ "Location": global['__redirect_url__'] }, setCookie),
227 });
228 global['__redirect_url__'] = undefined;
229 }
230 else if (_.isString(out)) {
231 htmlResponse = {
232 isBase64Encoded: true,
233 statusCode: 200,
234 headers: __assign({ "Content-type": "text/html; charset=utf-8" }, setCookie, __cors__),
235 // base64 encode body so it can be safely returned as JSON value
236 body: new Buffer(out).toString('base64')
237 };
238 callback(null, htmlResponse);
239 }
240 else {
241 jsonResponse = {
242 isBase64Encoded: true,
243 statusCode: 200,
244 headers: __assign({ "Content-type": "application/json" }, __cors__),
245 // base64 encode body so it can be safely returned as JSON value
246 body: new Buffer(JSON.stringify(out)).toString('base64')
247 };
248 callback(null, jsonResponse);
249 }
250 return [3 /*break*/, 18];
251 case 16:
252 err_3 = _c.sent();
253 // 通知框架自身实现逻辑的意外报错(框架自身不论何种情况都应该正常工作,一旦出现此问题大多数情况是框架自身问题或者流量引发的运维问题)
254 return [4 /*yield*/, xwarn({
255 __api__: __api__, __url__: __url__, param: param, message: err_3.message, stack: xstack(err_3)
256 })
257 // 500 Internal Server Error 服务器内部错误,无法完成请求
258 ];
259 case 17:
260 // 通知框架自身实现逻辑的意外报错(框架自身不论何种情况都应该正常工作,一旦出现此问题大多数情况是框架自身问题或者流量引发的运维问题)
261 _c.sent();
262 // 500 Internal Server Error 服务器内部错误,无法完成请求
263 callback(null, { statusCode: 500 });
264 return [3 /*break*/, 18];
265 case 18: return [2 /*return*/];
266 }
267 });
268 });
269};
270// API参数的识别逻辑,为普通字符串路径定义与app下的ts文件路由完全一一对应,优先取HEADER中的定义,再取GET中的形参定义或者POST形参定义进行参数请求的覆盖处理。
271// PARAM请求的参数处理要求为BASE64编码化的JSON字符串。
272// "event": {
273// "body": "ewoJImFwaSI6ICIvYS9iL2MiLAoJInBhcmFtIjogImFzZGZhc2RmYXNkZiIKfQ==", => 对应于POST请求数据
274// "headers": {
275// "X-Ca-Api-Gateway": "B25CD51B-5815-4775-9EAB-6D481BC1AE17",
276// "__api__": "/web/mobile/test", =》 自定义转义PATH的路径信息对于SEO优化兼容处理(也可以在GET或POST请求中传递对应参数)
277// "X-Forwarded-For": "42.120.74.88",
278// "Content-Type": "application/json"
279// },
280// "httpMethod": "POST",
281// "isBase64Encoded": true,
282// "path": "/", =》 没有意义用于前端根据需要自己进行扩展别名映射处理,后端的控制器不以此为标准,可以对同一个控制器定义N个不同的路径标识。
283// "pathParameters": {},
284// "queryParameters": {} => 对应于GET请求数据
285// },
286// "query": {},
287// "context": {
288// "requestId": "B25CD51B-5815-4775-9EAB-6D481BC1AE17",
289// "credentials": {
290// "accessKeyId": "",
291// "accessKeySecret": "",
292// "securityToken": ""
293// },
294// "function": {
295// "name": "test",
296// "handler": "index.handler",
297// "memory": 128,
298// "timeout": 300
299// },
300// "services": {
301// "name": "alilang",
302// "logProject": "",
303// "logStore": ""
304// },
305// "region": "cn-shanghai",
306// "accountId": "1734066057689528"
307// }
308// }
309// 最新版本event的API网关的FC返回数据格式:
310// CA-Host请求域名、
311// X-Forwarded-Proto
312// "path": "/test", ==》》基本上可以拼接出__url__参数可以省略掉此冗余参数配置了。
313// ==》》借助route.map.ts文件的映射关系定义省略掉__api__配置进一步简化网关应用。
314// "httpMethod": "GET",
315// "isBase64Encoded": true,
316// "X-Forwarded-For": "42.120.74.103", // 客户端请求IP地址用户判定所属区域信息海外访问问题优化依赖点
317// "X-Real-IP": "42.120.74.103",
318// Cookie
319// User-Agent =>> PC站和M站自适应问题
320// Accept-Language =>> 浏览器客户端的语言类型自动适配多语言架构设计问题
321// let x = {
322// "body": "",
323// "headers": {
324// "X-Ca-Api-Gateway": "B276F77B-334E-4857-AE64-65BAFD419E2A",
325// "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",
326// "X-Forwarded-Proto": "https",
327// "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",
328// "__url__": "https://toufang.alibaba-inc.com/test",
329// "CA-Host": "toufang.alibaba-inc.com",
330// "Cache-Control": "max-age=0",
331// "upgrade-insecure-requests": "1",
332// "Accept-Language": "zh-CN,zh;q=0.9",
333// "__api__": "/web/test/test",
334// "Accept-Encoding": "gzip, deflate, br",
335// "X-Forwarded-For": "42.120.74.103",
336// "X-Real-IP": "42.120.74.103",
337// "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8"
338// },
339// "httpMethod": "GET",
340// "isBase64Encoded": true,
341// "path": "/test",
342// "pathParameters": {},
343// "queryParameters": {}
344// }
345//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJpbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSxPQUFPLENBQUMsb0JBQW9CLENBQUMsQ0FBQyxPQUFPLEVBQUUsQ0FBQTtBQUN2QyxPQUFPLENBQUMsZ0JBQWdCLENBQUMsQ0FBQyxRQUFRLEVBQUUsQ0FBQTtBQUNwQywrQkFBd0Q7QUFFeEQsSUFBTSxDQUFDLEdBQUcsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFBO0FBRTNCLGdCQUFnQjtBQUNoQixvR0FBb0c7QUFDcEcsZ0VBQWdFO0FBQ2hFLCtEQUErRDtBQUMvRCw4Q0FBOEM7QUFDOUMsbURBQW1EO0FBQ25ELG1EQUFtRDtBQUNuRCwyQkFBMkI7QUFDM0IsaUNBQWlDO0FBQ2pDLDJCQUEyQjtBQUMzQixxQkFBcUI7QUFDckIsMERBQTBEO0FBQzFELGFBQWE7QUFDYiwyRUFBMkU7QUFDM0UsNkRBQTZEO0FBQzdELFFBQVE7QUFDUixtQ0FBbUM7QUFDbkMsSUFBSTtBQUVKLHNCQUFzQjtBQUN0QixPQUFPLENBQUMsT0FBTyxHQUFHLFVBQWdCLEtBQUssRUFBRSxPQUFPLEVBQUUsUUFBUTs7Ozs7O29CQUN0RCxzQkFBc0I7b0JBQ3RCLG9DQUFvQztvQkFDcEMsOEJBQThCO29CQUM5QixJQUFJLENBQUMsUUFBUSxHQUFHLEtBQUssQ0FBQyxRQUFRLEVBQUUsQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQTtvQkFFbkUsR0FBRyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUE7b0JBRXRDLDZEQUE2RDtvQkFDN0QsdUJBQXVCO29CQUN2QixNQUFNLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdB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LDZCQUE2QjtBQUM3QixhQUFhO0FBQ2IsbUNBQW1DO0FBQ25DLDBDQUEwQztBQUMxQyxRQUFRO0FBQ1IsSUFBSTtBQUVKLDRCQUE0QjtBQUM1QixvQkFBb0I7QUFDcEIseUJBQXlCO0FBQ3pCLDREQUE0RDtBQUM1RCwwRUFBMEU7QUFDMUUsNEJBQTRCO0FBQzVCLGdDQUFnQztBQUNoQyw2RUFBNkU7QUFDN0UscUNBQXFDO0FBQ3JDLGNBQWM7QUFDZCx3Q0FBd0M7QUFDeEMscURBQXFEO0FBQ3JELFlBQVk7QUFDWixrQkFBa0I7QUFDbEIsbUJBQW1CO0FBQ25CLHNFQUFzRTtBQUN0RSxtNkJBQW02QjtBQUNuNkIsd0NBQXdDO0FBQ3hDLHFKQUFxSjtBQUNySiw2REFBNkQ7QUFDN0QsZ0RBQWdEO0FBQ2hELHdDQUF3QztBQUN4Qyw0Q0FBNEM7QUFDNUMsK0NBQStDO0FBQy9DLHVDQUF1QztBQUN2QyxrREFBa0Q7QUFDbEQsOENBQThDO0FBQzlDLHdDQUF3QztBQUN4Qyw0R0FBNEc7QUFDNUcsU0FBUztBQUNULDJCQUEyQjtBQUMzQiwrQkFBK0I7QUFDL0IsdUJBQXVCO0FBQ3ZCLDRCQUE0QjtBQUM1Qiw0QkFBNEI7QUFDNUIsSUFBSSIsInNvdXJjZXNDb250ZW50IjpbInJlcXVpcmUoJ3NvdXJjZS1tYXAtc3VwcG9ydCcpLmluc3RhbGwoKVxucmVxdWlyZSgndHNjb25maWctcGF0aHMnKS5yZWdpc3RlcigpXG5pbXBvcnQge3JlcXVlc3RfcHJvY2VzcywgcGFyc2VfcG9zdF9wYXJhbX0gZnJvbSAnLi9pbml0J1xuXG5jb25zdCBfID0gcmVxdWlyZSgnbG9kYXNoJylcblxuLy8gLy8g5Li05pe26LCD6K+V57q/5LiK5pel5b+X5omT5Y2wXG4vLyAvL2ZyYW1ld29yay9pbmRleC50cyg4LDEzKTogZXJyb3IgVFMyMzM5OiBQcm9wZXJ0eSAnc2V0TG9nTGV2ZWwnIGRvZXMgbm90IGV4aXN0IG9uIHR5cGUgJ0NvbnNvbGUnXG4vLyBleHBvcnRzLmhhbmRsZXIgPSBhc3luYyBmdW5jdGlvbiAoZXZlbnQsIGNvbnRleHQsIGNhbGxiYWNrKSB7XG4vLyAgICAgLy8gY29uc29sZS5zZXRMb2dMZXZlbCgnZXJyb3InKSDkuI3og73lhpnlnKjmraTkvJrlr7zoh7TnvJbor5HplJnor6/pmL/ph4zkupHoh6rlt7HmianlsZXnmoTnp4HmnInmlrnms5Vcbi8vICAgICBjb25zb2xlLmxvZygneHh4eHgnLCAneXl5eXknLCAnenp6enp6Jylcbi8vICAgICBjb25zb2xlLmVycm9yKCd4eHh4eDEnLCAneXl5eXkxJywgJ3p6enp6ejEnKVxuLy8gICAgIGxldCBvdXQgPSAnPGh0bWw+PGJvZHk+enp6enp6PC9ib2R5PjwvaHRtbD4nXG4vLyAgICAgbGV0IGh0bWxSZXNwb25zZSA9IHtcbi8vICAgICAgICAgaXNCYXNlNjRFbmNvZGVkOiB0cnVlLFxuLy8gICAgICAgICBzdGF0dXNDb2RlOiAyMDAsXG4vLyAgICAgICAgIGhlYWRlcnM6IHtcbi8vICAgICAgICAgICAgIFwiQ29udGVudC10eXBlXCI6IFwidGV4dC9odG1sOyBjaGFyc2V0PXV0Zi04XCIsXG4vLyAgICAgICAgIH0sXG4vLyAgICAgICAgIC8vIGJhc2U2NCBlbmNvZGUgYm9keSBzbyBpdCBjYW4gYmUgc2FmZWx5IHJldHVybmVkIGFzIEpTT04gdmFsdWVcbi8vICAgICAgICAgYm9keTogbmV3IEJ1ZmZlcihvdXQgYXMgc3RyaW5nKS50b1N0cmluZygnYmFzZTY0Jylcbi8vICAgICB9XG4vLyAgICAgY2FsbGJhY2sobnVsbCwgaHRtbFJlc3BvbnNlKVxuLy8gfVxuXG4vLyDln7rkuo7pmL/ph4zkupHnmoTlh73mlbDorqHnrpfnu5/kuIDlhaXlj6PnmoTot6/nlLHlpITnkIZcbmV4cG9ydHMuaGFuZGxlciA9IGFzeW5jIGZ1bmN0aW9uIChldmVudCwgY29udGV4dCwgY2FsbGJhY2spIHtcbiAgICAvLyBUT0RPIOWinuWKoOWvueS6juWumuaXtuWZqOeahOWKn+iDveaooeaLn+WunueOsFxuICAgIC8vIHhsb2coJyQkJCQ9PicgKyBldmVudC50b1N0cmluZygpKVxuICAgIC8vIFRPRE8g5Y676Zmk5o6J5o2i6KGM5pa55L6/5pa55L6/U0xT5LiK55qE5pel5b+X6L6T5Ye65o6S54mI5pi+56S6XG4gICAgeGxvZygnJCQkJD0+JyArIGV2ZW50LnRvU3RyaW5nKCkucmVwbGFjZSgvXFxyL2csICcnKS5yZXBsYWNlKC9cXG4vZywgJycpKVxuXG4gICAgbGV0IGV2dCA9IEpTT04ucGFyc2UoZXZlbnQudG9TdHJpbmcoKSlcblxuICAgIC8vIOagueaNrkFQSee9keWFs+iuvue9rueahOeOr+Wig+W4uOmHj+WPguaVsOato+ehrumFjee9rue6v+S4iueJiOacrOeahOi/kOihjOeOr+Wig++8jOWPluS7o0FPTkXnmoTmnKzlnLDjgIHml6XluLjjgIHpooTlj5HjgIHngbDluqbnrYnnjq/looPpg6jnvbLmlK/mjIHlvIDlj5HjgIJcbiAgICAvLyDlhajlsYDlj5jph4/ku4Xku4XnlKjkuo7mlL7lnKjmlbTkuKrlupTnlKjnlJ/lkb3lkajmnJ/lj5jph49cbiAgICBnbG9iYWxbJ19fZW52X18nXSA9IF8uZ2V0KGV2dCwgJ2hlYWRlcnMuX19lbnZfXycsICdwcm9kJylcblxuICAgIGNvbnN0IF9fY29yc19fID0ge31cbiAgICBpZiAoZ2xvYmFsWydfX2Vudl9fJ10gIT09ICdwcm9kJyAmJiBnbG9iYWxbJ19fZW52X18nXSAhPT0gJ2dyYXknKSB7XG4gICAgICAgIC8vIOmdnueUn+S6p+eOr+Wig+aIlueBsOW6pueOr+Wig++8jOmcgOimgeemgeeUqENPUlPlip/og73npoHmraLot6jln5/orr/pl67lop7liqDlronlhajmgKfjgIJcbiAgICAgICAgaWYgKGV2dC5oZWFkZXJzLm9yaWdpbikge1xuICAgICAgICAgICAgLy8g6I635Y+W5rqQ56uZ5Yqo5oCB5YWB6K646K+35rGC6Leo5Z+fIChGSVhNRSDpnIDopoHov5vooYzlronlhajpmZDliLblr7nmnaXmupDmnI3liqHlmajnvZHlnYDlkIjms5XmgKfov5vooYzlronlhajpmZDliLbvvIzmnKzlnLDlvIDlj5HosIPor5Xlhajpg6jmlL7lvIDor7fmsYIpXG4gICAgICAgICAgICBfX2NvcnNfX1snQWNjZXNzLUNvbnRyb2wtQWxsb3ctT3JpZ2luJ10gPSBldnQuaGVhZGVycy5vcmlnaW5cbiAgICAgICAgICAgIC8vIF9fY29yc19fWydBY2Nlc3MtQ29udHJvbC1BbGxvdy1PcmlnaW4nXSA9ICcqJyAvLyDkuI3og73orr7nva7kuLrku7vmhI/lgLzmtY/op4jlmajmnInlronlhajpmZDliLZcbiAgICAgICAgfVxuICAgICAgICBfX2NvcnNfX1snQWNjZXNzLUNvbnRyb2wtQWxsb3ctQ3JlZGVudGlhbHMnXSA9ICd0cnVlJ1xuICAgICAgICBfX2NvcnNfX1snQWNjZXNzLUNvbnRyb2wtQWxsb3ctSGVhZGVycyddID0gJ09yaWdpbiwgWC1SZXF1ZXN0ZWQtV2l0aCwgQ29udGVudC1UeXBlLCBBY2NlcHQnXG4gICAgICAgIF9fY29yc19fWydBY2Nlc3MtQ29udHJvbC1BbGxvdy1NZXRob2RzJ10gPSAnUE9TVCwgT1BUSU9OUydcbiAgICB9XG5cbiAgICAvLyDmlK/mjIHot6jln5/nmoTpqozor4Hor7fmsYLmlrnms5XnmoTlkIjms5XmgKfop4Tpgb/mjonov4fmu6TmjonkuI3lronlhajnmoTor7fmsYLjgIJcbiAgICBzd2l0Y2ggKGV2dC5odHRwTWV0aG9kKSB7XG4gICAgICAgIGNhc2UgJ0dFVCc6XG4gICAgICAgIGNhc2UgJ1BPU1QnOlxuICAgICAgICAgICAgYnJlYWtcbiAgICAgICAgY2FzZSAnT1BUSU9OUyc6XG4gICAgICAgICAgICBpZiAoZ2xvYmFsWydfX2Vudl9fJ10gPT0gJ3Byb2QnIHx8IGdsb2JhbFsnX19lbnZfXyddID09ICdncmF5Jykge1xuICAgICAgICAgICAgICAgIC8vIOeUn+S6p+WSjOeBsOW6pueOr+Wig+S4i+emgeatoui3qOWfn09QVElPTlPor7fmsYLku6Xkvr/kuo7lop7lvLrlronlhajmgKdcbiAgICAgICAgICAgICAgICBjYWxsYmFjayhudWxsLCB7XG4gICAgICAgICAgICAgICAgICAgIHN0YXR1c0NvZGU6IDQwMCxcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAvLyDpnZ7nlJ/kuqflkozngbDluqbnjq/looPkuIvmiY3lhYHorrjmlK/mjIHot6jln59PUFRJT05T6K+35rGCXG4gICAgICAgICAgICAgICAgY2FsbGJhY2sobnVsbCwge1xuICAgICAgICAgICAgICAgICAgICBzdGF0dXNDb2RlOiAyMDAsXG4gICAgICAgICAgICAgICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC4uLl9fY29yc19fLFxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm5cbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgIC8vIOemgeatouS7u+S9leeahOmdnuazleivt+axguS4peagvOi/m+ihjOe6puWumumZkOWItlxuICAgICAgICAgICAgY2FsbGJhY2sobnVsbCwge1xuICAgICAgICAgICAgICAgIHN0YXR1c0NvZGU6IDQwMCxcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICByZXR1cm5cbiAgICB9XG5cbiAgICAvLyBUT0RPIOmcgOimgeWvueS6juS6i+S7tuWumuaXtuWZqOi/m+ihjOe7n+S4gOeahOe6puWumuWcqOW6lOeUqOWxguWPr+aJqeWxleiHquWumuS5ieebuOWFs+WumuaXtuWZqOetieS6i+S7tuexu+Wei1xuICAgIGlmIChldnRbJ3RyaWdnZXJOYW1lJ10pIHtcbiAgICAgICAgLy8g5a+55a6a5pe26Kem5Y+R5Zmo55qE57uf5LiA5oum5oiq5aSE55CGXG4gICAgICAgIHN3aXRjaCAoZXZ0Wyd0cmlnZ2VyTmFtZSddKSB7XG4gICAgICAgICAgICBjYXNlICdfX2F4anMtcHJlaGVhdC10aW1lcl9fJzpcbiAgICAgICAgICAgICAgICAvLyDojrflj5bor7fmsYLlj4LmlbDnmoTphY3nva7mlbDmja5cbiAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICBsZXQgcGF5bG9hZCA9IEpTT04ucGFyc2UoZXZ0WydwYXlsb2FkJ10pXG4gICAgICAgICAgICAgICAgICAgIHhhc3NlcnQocGF5bG9hZFsndXJsJ10gJiYgcGF5bG9hZFsndGltZW91dCddKVxuICAgICAgICAgICAgICAgICAgICBhd2FpdCB4cG9zdChwYXlsb2FkWyd1cmwnXSwgcGF5bG9hZFsncGFyYW0nXSwgdW5kZWZpbmVkLCBwYXlsb2FkWyd0aW1lb3V0J10pXG4gICAgICAgICAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIGlnbm9yZSBlcnJvclxuICAgICAgICAgICAgICAgICAgICB4bG9nKEpTT04uc3RyaW5naWZ5KHhlcnJvcihlcnIpKS5yZXBsYWNlKC9cXHIvZywgJycpLnJlcGxhY2UoL1xcbi9nLCAnJykpXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGJyZWFrXG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuXG4gICAgfSBlbHNlIGlmIChldnRbJ3BhdGgnXSA9PT0gJy9fX2F4anMtcHJlaGVhdC10aW1lcl9fJykge1xuICAgICAgICAvLyDpooTng61hcGnnvZHlhbPnmoTnqbror7fmsYLlv4Pot7PmjqXlj6Plrp7njrBcbiAgICAgICAgcmV0dXJuXG4gICAgfVxuICAgIGdsb2JhbFsnX19ldnRfXyddID0gZXZlbnQudG9TdHJpbmcoKSAvLyBGSVhNRSDpnIDopoHorr7orqHkuIrkuIvmloflrprkuYnor7fmsYLlrp7kvovnlJ/lkb3lkajmnJ/lj5jph49cbiAgICAvLyDlhYjku6VIRUFFUuS4reeahF9fYXBpX1/lrZfmrrXov5vooYzor4bliKvvvIzlpoLmnpxIRUFERVLkuK3msqHmnInlrprkuYnlho3kvb/nlKhVUkzot6/lvoTlr7nlupTnmoRQQVRI6K+G5Yir77yM5Lul5q2k5pSv5oyBU0VP562J5YmN56uv6Lev5b6E6YeN5YaZ6Zeu6aKY44CCXG4gICAgbGV0IF9fYXBpX18gPSBfLmdldChldnQsICdoZWFkZXJzLl9fYXBpX18nLCBldnQucGF0aCkgLy8g5pyA57uI5o6n5Yi25Zmo5LiOYXBw5a2Q55uu5b2V5LiL55qEdHPmlofku7bkv53mjIHlrozlhajnmoTkuIDkuIDmmKDlsITlhbPns7vjgIJcbiAgICAvLyDmlLnov5vkuLrmoLnmja5BUEnnvZHlhbPnmoTnm7jlhbPlj4LmlbDoh6rliqjmi7zmjqXlh7rmnaXmraPnoa7nmoRVUkznvZHlnYDor7fmsYLot6/lvoRcbiAgICBsZXQgX191cmxfXyA9IGV2dFsnaGVhZGVycyddWydYLUZvcndhcmRlZC1Qcm90byddICsgJzovLycgKyBldnRbJ2hlYWRlcnMnXVsnQ0EtSG9zdCddICsgZXZ0WydwYXRoJ11cbiAgICAvLyDlsIblhajpg6jnmoRIRUFERVLkv6Hmga/pgI/kvKDliLDlupTnlKjkuK1cbiAgICBsZXQgX19oZWFkZXJfXyA9IGV2dFsnaGVhZGVycyddXG5cbiAgICBsZXQgcGFyYW0gPSBPYmplY3QuYXNzaWduKFxuICAgICAgICB7X19hcGlfXywgX191cmxfXywgX19oZWFkZXJfX30sIC8vIGhlYWRlcuivt+axguS4reeahOS4pOS4quahhuaetuWxgumdouS4iueahOmihOWumuS5ieWPguaVsCBUT0RPIOmcgOimgeenu+mZpOaOieW5tumdnuW6lOeUqOWFs+W/g+eahOWGheWuuVxuICAgICAgICBldnQucGF0aFBhcmFtZXRlcnMgfHwge30sIC8vIOi3r+eUsemHjeWGmeWPguaVsCBkb21haW4vW2FdL1tiXT94eHggKOWPr+iiq0dFVOWPguaVsOimhueblilcbiAgICAgICAgZXZ0LnF1ZXJ5UGFyYW1ldGVycyB8fCB7fSAvLyBHRVTor7fmsYLlj4LmlbAgZG9tYWluL3BhdGg/YT14JmI9eFxuICAgIClcbiAgICBsZXQgb3V0ID0ge31cblxuICAgIC8vIC8vIOadoeS7tuaXpeW/l+aJk+WNsOe6v+S4iuS4tOaXtumXrumimOaOkuafpeWkhOeQhu+8iFRPRE8g5aKe5Yqg5Lia5Yqh6YC76L6R5omp5bGV5rOo5YWl55qE6ZKp5a2Q5a6e546w77yJXG4gICAgLy8gbGV0IHhkZWJ1ZyA9IGFzeW5jICguLi5hcmdzKSA9PiB7XG4gICAgLy8gICAgIGlmICghXy5pbmNsdWRlcyhfX3VybF9fLCAneS5hbGliYWJhLWluYy5jb20nKSkge1xuICAgIC8vICAgICAgICAgcmV0dXJuXG4gICAgLy8gICAgIH1cbiAgICAvLyAgICAgYXdhaXQgeHdhcm4oLi4uYXJncylcbiAgICAvLyB9XG4gICAgLy8gZ2xvYmFsWyd4ZGVidWcnXSA9IHhkZWJ1ZyAvLyDlhajlsYDlj6/nlKhcbiAgICAvLyBhd2FpdCB4ZGVidWcoe3BhcmFtLCBldnR9KVxuXG4gICAgc3dpdGNoIChldnQuaHR0cE1ldGhvZCkge1xuICAgICAgICBjYXNlICdHRVQnOlxuICAgICAgICAgICAgYnJlYWtcbiAgICAgICAgY2FzZSAnUE9TVCc6XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIC8vIOmYv+mHjOS6kUFQSee9keWFs+eahFBPU1Tor7fmsYLlj4LmlbDmmK9KU09O5a2X56ym5Liy55qEQkFTRTY057yW56CB5omA5Lul6ZyA6KaB6L+b6KGM6L2s5LmJ5aSE55CGXG4gICAgICAgICAgICAgICAgbGV0IHBvc3QgPSB7fVxuICAgICAgICAgICAgICAgIGlmIChfLmlzU3RyaW5nKGV2dC5ib2R5KSkge1xuICAgICAgICAgICAgICAgICAgICBsZXQgYm9keSA9IGV2dC5ib2R5XG4gICAgICAgICAgICAgICAgICAgIGlmIChldnQuaXNCYXNlNjRFbmNvZGVkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBib2R5ID0gbmV3IEJ1ZmZlcihldnQuYm9keSwgJ2Jhc2U2NCcpLnRvU3RyaW5nKClcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBwb3N0ID0gcGFyc2VfcG9zdF9wYXJhbShldnRbJ2hlYWRlcnMnXSwgYm9keSlcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcGFyYW0gPSBPYmplY3QuYXNzaWduKHBhcmFtLCBwb3N0KSAvLyDnlKhwb3N05Y+C5pWw6KaG55uW5o6JZ2V05Y+C5pWw77yM55So5LqO54G15rS755qE6K6+572u6K+35rGC5Y+C5pWw5YW85a65Z2V05ZKMcG9zdOS4pOenjeaWueazleaWueS+v+W8gOWPkeiwg+ivleOAglxuICAgICAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICAgICAgeGxvZyhlcnIsIGV2dC5odHRwTWV0aG9kLCBldnQuYm9keSlcbiAgICAgICAgICAgICAgICBhd2FpdCB4d2FybihlcnIpXG4gICAgICAgICAgICAgICAgLy8gNDAwXHRCYWQgUmVxdWVzdFx05a6i5oi356uv6K+35rGC55qE6K+t5rOV6ZSZ6K+v77yM5pyN5Yqh5Zmo5peg5rOV55CG6KejXG4gICAgICAgICAgICAgICAgY2FsbGJhY2sobnVsbCwge1xuICAgICAgICAgICAgICAgICAgICBzdGF0dXNDb2RlOiA0MDAsXG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICByZXR1cm5cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGJyZWFrXG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICB4bG9nKGV2dC5odHRwTWV0aG9kLCBldnQuYm9keSlcbiAgICAgICAgICAgIC8vIDQwMFx0QmFkIFJlcXVlc3RcdOWuouaIt+err+ivt+axgueahOivreazlemUmeivr++8jOacjeWKoeWZqOaXoOazleeQhuino1xuICAgICAgICAgICAgY2FsbGJhY2sobnVsbCwge1xuICAgICAgICAgICAgICAgIHN0YXR1c0NvZGU6IDQwMCxcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICByZXR1cm5cbiAgICB9XG5cbiAgICB0cnkge1xuICAgICAgICAvLyDop6PmnpDor7fmsYLkuK3nmoRjb29raWVz5pWw5o2u5bm26L2s5o2i5Li6SlNPTuWvueixoeWtmOWCqOWIsOWFqOWxgOWPmOmHj+S4reS+v+S6juWQjue7reW6lOeUqHhjb29raWXmjqXlj6Pkvb/nlKhcbiAgICAgICAgbGV0IGNvb2tpZSA9IF8uZ2V0KGV2dFsnaGVhZGVycyddLCAnQ29va2llJywgdW5kZWZpbmVkKVxuICAgICAgICBpZiAoIWNvb2tpZSkge1xuICAgICAgICAgICAgY29va2llID0gXy5nZXQoZXZ0WydoZWFkZXJzJ10sICdjb29raWUnLCAnJylcbiAgICAgICAgfVxuICAgICAgICBnbG9iYWxbJ19fcmVxdWVzdF9jb29raWVzX18nXSA9IHJlcXVpcmUoJ2Nvb2tpZScpLnBhcnNlKGNvb2tpZSlcblxuICAgICAgICAvLyDojrflj5Z1c2UtYWdlbnTor7fmsYLlpLTpg6jkv6Hmga9cbiAgICAgICAgZ2xvYmFsWydfX3VzZXJfYWdlbnRfXyddID0gZXZ0WydoZWFkZXJzJ11bJ1VzZXItQWdlbnQnXVxuICAgICAgICAvLyDojrflj5blrqLmiLfnq6/nmoRJUOWcsOWdgOS/oeaBr1xuICAgICAgICBnbG9iYWxbJ19fY2xpZW50X2lwX18nXSA9IGV2dFsnaGVhZGVycyddWydYLVJlYWwtSVAnXVxuXG4gICAgICAgIC8vIFRPRE8gV0VC6K+35rGC6ZyA6KaB5a+5NDA06aG16Z2i5Lul5Y+KRVJST1LpobXpnaLov5vooYzlhbzlrrnlpITnkIbvvIjlnKhmcmFtZXdvcmvlhoXpg6jov5vooYznu4boioLnmoTplJnor6/liKTmlq3lnKhvdXTkuK3pgI/kvKBzdGF0dXPnmoRodHRw55qE54q25oCB5ZCX5q2j56Gu6ZSZ6K+v6L+U5Zue77yJXG4gICAgICAgIC8vIDQwNFx0Tm90IEZvdW5kIOacjeWKoeWZqOaXoOazleagueaNruWuouaIt+err+eahOivt+axguaJvuWIsOi1hOa6kO+8iOe9kemhte+8ieOAgumAmui/h+atpOS7o+egge+8jOe9keermeiuvuiuoeS6uuWRmOWPr+iuvue9rlwi5oKo5omA6K+35rGC55qE6LWE5rqQ5peg5rOV5om+5YiwXCLnmoTkuKrmgKfpobXpnaJcbiAgICAgICAgLy8gNDAzXHRGb3JiaWRkZW5cdOacjeWKoeWZqOeQhuino+ivt+axguWuouaIt+err+eahOivt+axgu+8jOS9huaYr+aLkue7neaJp+ihjOatpOivt+axgu+8iOadg+mZkOmqjOivgeWkhOeQhumUmeivr++8iVxuICAgICAgICBvdXQgPSBhd2FpdCByZXF1ZXN0X3Byb2Nlc3MoX19hcGlfXywgcGFyYW0pXG5cbiAgICAgICAgLy8g5aSE55CGcmVzcG9uc2XnmoRjb29raWVz6K6+572uXG4gICAgICAgIGxldCBzZXRDb29raWUgPSB7J1NldC1Db29raWUnOiB1bmRlZmluZWR9XG4gICAgICAgIGlmICghXy5pc0VtcHR5KGdsb2JhbFsnX19yZXNwb25kX2Nvb2tpZXNfXyddKSkge1xuICAgICAgICAgICAgc2V0Q29va2llWydTZXQtQ29va2llJ10gPSBfLnZhbHVlcyhnbG9iYWxbJ19fcmVzcG9uZF9jb29raWVzX18nXSlcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChnbG9iYWxbJ19fcmVkaXJlY3RfdXJsX18nXSkge1xuICAgICAgICAgICAgY2FsbGJhY2sobnVsbCwge1xuICAgICAgICAgICAgICAgIHN0YXR1c0NvZGU6IDMwMixcbiAgICAgICAgICAgICAgICBoZWFkZXJzOiB7XG4gICAgICAgICAgICAgICAgICAgIFwiTG9jYXRpb25cIjogZ2xvYmFsWydfX3JlZGlyZWN0X3VybF9fJ10sXG4gICAgICAgICAgICAgICAgICAgIC4uLnNldENvb2tpZVxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgZ2xvYmFsWydfX3JlZGlyZWN0X3VybF9fJ10gPSB1bmRlZmluZWRcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmIChfLmlzU3RyaW5nKG91dCkpIHtcbiAgICAgICAgICAgIGxldCBodG1sUmVzcG9uc2UgPSB7XG4gICAgICAgICAgICAgICAgaXNCYXNlNjRFbmNvZGVkOiB0cnVlLFxuICAgICAgICAgICAgICAgIHN0YXR1c0NvZGU6IDIwMCxcbiAgICAgICAgICAgICAgICBoZWFkZXJzOiB7XG4gICAgICAgICAgICAgICAgICAgIFwiQ29udGVudC10eXBlXCI6IFwidGV4dC9odG1sOyBjaGFyc2V0PXV0Zi04XCIsXG4gICAgICAgICAgICAgICAgICAgIC4uLnNldENvb2tpZSxcbiAgICAgICAgICAgICAgICAgICAgLi4uX19jb3JzX18sXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAvLyBiYXNlNjQgZW5jb2RlIGJvZHkgc28gaXQgY2FuIGJlIHNhZmVseSByZXR1cm5lZCBhcyBKU09OIHZhbHVlXG4gICAgICAgICAgICAgICAgYm9keTogbmV3IEJ1ZmZlcihvdXQgYXMgc3RyaW5nKS50b1N0cmluZygnYmFzZTY0JylcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNhbGxiYWNrKG51bGwsIGh0bWxSZXNwb25zZSlcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGxldCBqc29uUmVzcG9uc2UgPSB7XG4gICAgICAgICAgICAgICAgaXNCYXNlNjRFbmNvZGVkOiB0cnVlLFxuICAgICAgICAgICAgICAgIHN0YXR1c0NvZGU6IDIwMCxcbiAgICAgICAgICAgICAgICBoZWFkZXJzOiB7XG4gICAgICAgICAgICAgICAgICAgIFwiQ29udGVudC10eXBlXCI6IFwiYXBwbGljYXRpb24vanNvblwiLFxuICAgICAgICAgICAgICAgICAgICAuLi5fX2NvcnNfXyxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIC8vIGJhc2U2NCBlbmNvZGUgYm9keSBzbyBpdCBjYW4gYmUgc2FmZWx5IHJldHVybmVkIGFzIEpTT04gdmFsdWVcbiAgICAgICAgICAgICAgICBib2R5OiBuZXcgQnVmZmVyKEpTT04uc3RyaW5naWZ5KG91dCkpLnRvU3RyaW5nKCdiYXNlNjQnKVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY2FsbGJhY2sobnVsbCwganNvblJlc3BvbnNlKVxuICAgICAgICB9XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgIC8vIOmAmuefpeahhuaetuiHqui6q+WunueOsOmAu+i+keeahOaEj+WkluaKpemUme+8iOahhuaetuiHqui6q+S4jeiuuuS9leenjeaDheWGtemDveW6lOivpeato+W4uOW3peS9nO+8jOS4gOaXpuWHuueOsOatpOmXrumimOWkp+WkmuaVsOaDheWGteaYr+ahhuaetuiHqui6q+mXrumimOaIluiAhea1gemHj+W8leWPkeeahOi/kOe7tOmXrumimO+8iVxuICAgICAgICBhd2FpdCB4d2Fybih7XG4gICAgICAgICAgICBfX2FwaV9fLCBfX3VybF9fLCBwYXJhbSwgbWVzc2FnZTogZXJyLm1lc3NhZ2UsIHN0YWNrOiB4c3RhY2soZXJyKVxuICAgICAgICB9KVxuICAgICAgICAvLyA1MDBcdEludGVybmFsIFNlcnZlciBFcnJvclx05pyN5Yqh5Zmo5YaF6YOo6ZSZ6K+v77yM5peg5rOV5a6M5oiQ6K+35rGCXG4gICAgICAgIGNhbGxiYWNrKG51bGwsIHtzdGF0dXNDb2RlOiA1MDB9KVxuICAgIH1cbn1cblxuLy8gIEFQSeWPguaVsOeahOivhuWIq+mAu+i+ke+8jOS4uuaZrumAmuWtl+espuS4sui3r+W+hOWumuS5ieS4jmFwcOS4i+eahHRz5paH5Lu26Lev55Sx5a6M5YWo5LiA5LiA5a+55bqU77yM5LyY5YWI5Y+WSEVBREVS5Lit55qE5a6a5LmJ77yM5YaN5Y+WR0VU5Lit55qE5b2i5Y+C5a6a5LmJ5oiW6ICFUE9TVOW9ouWPguWumuS5iei/m+ihjOWPguaVsOivt+axgueahOimhuebluWkhOeQhuOAglxuLy8gIFBBUkFN6K+35rGC55qE5Y+C5pWw5aSE55CG6KaB5rGC5Li6QkFTRTY057yW56CB5YyW55qESlNPTuWtl+espuS4suOAglxuLy8gICAgIFwiZXZlbnRcIjoge1xuLy8gICAgICAgICBcImJvZHlcIjogXCJld29KSW1Gd2FTSTZJQ0l2WVM5aUwyTWlMQW9KSW5CaGNtRnRJam9nSW1GelpHWmhjMlJtWVhOa1ppSUtmUT09XCIsID0+IOWvueW6lOS6jlBPU1Tor7fmsYLmlbDmja5cbi8vICAgICAgICAgXCJoZWFkZXJzXCI6IHtcbi8vICAgICAgICAgICAgIFwiWC1DYS1BcGktR2F0ZXdheVwiOiBcIkIyNUNENTFCLTU4MTUtNDc3NS05RUFCLTZENDgxQkMxQUUxN1wiLFxuLy8gICAgICAgICAgICAgXCJfX2FwaV9fXCI6IFwiL3dlYi9tb2JpbGUvdGVzdFwiLCAgID3jgIsg6Ieq5a6a5LmJ6L2s5LmJUEFUSOeahOi3r+W+hOS/oeaBr+WvueS6jlNFT+S8mOWMluWFvOWuueWkhOeQhu+8iOS5n+WPr+S7peWcqEdFVOaIllBPU1Tor7fmsYLkuK3kvKDpgJLlr7nlupTlj4LmlbDvvIlcbi8vICAgICAgICAgICAgIFwiWC1Gb3J3YXJkZWQtRm9yXCI6IFwiNDIuMTIwLjc0Ljg4XCIsXG4vLyAgICAgICAgICAgICBcIkNvbnRlbnQtVHlwZVwiOiBcImFwcGxpY2F0aW9uL2pzb25cIlxuLy8gICAgICAgICB9LFxuLy8gICAgICAgICBcImh0dHBNZXRob2RcIjogXCJQT1NUXCIsXG4vLyAgICAgICAgIFwiaXNCYXNlNjRFbmNvZGVkXCI6IHRydWUsXG4vLyAgICAgICAgIFwicGF0aFwiOiBcIi9cIiwgPeOAiyDmsqHmnInmhI/kuYnnlKjkuo7liY3nq6/moLnmja7pnIDopoHoh6rlt7Hov5vooYzmianlsZXliKvlkI3mmKDlsITlpITnkIbvvIzlkI7nq6/nmoTmjqfliLblmajkuI3ku6XmraTkuLrmoIflh4bvvIzlj6/ku6Xlr7nlkIzkuIDkuKrmjqfliLblmajlrprkuYlO5Liq5LiN5ZCM55qE6Lev5b6E5qCH6K+G44CCXG4vLyAgICAgICAgIFwicGF0aFBhcmFtZXRlcnNcIjoge30sXG4vLyAgICAgICAgIFwicXVlcnlQYXJhbWV0ZXJzXCI6IHt9ID0+IOWvueW6lOS6jkdFVOivt+axguaVsOaNrlxuLy8gICAgIH0sXG4vLyAgICAgXCJxdWVyeVwiOiB7fSxcbi8vICAgICBcImNvbnRleHRcIjoge1xuLy8gICAgICAgICBcInJlcXVlc3RJZFwiOiBcIkIyNUNENTFCLTU4MTUtNDc3NS05RUFCLTZENDgxQkMxQUUxN1wiLFxuLy8gICAgICAgICBcImNyZWRlbnRpYWxzXCI6IHtcbi8vICAgICAgICAgICAgIFwiYWNjZXNzS2V5SWRcIjogXCJcIixcbi8vICAgICAgICAgICAgIFwiYWNjZXNzS2V5U2VjcmV0XCI6IFwiXCIsXG4vLyAgICAgICAgICAgICBcInNlY3VyaXR5VG9rZW5cIjogXCJcIlxuLy8gICAgICAgICB9LFxuLy8gICAgICAgICBcImZ1bmN0aW9uXCI6IHtcbi8vICAgICAgICAgICAgIFwibmFtZVwiOiBcInRlc3RcIixcbi8vICAgICAgICAgICAgIFwiaGFuZGxlclwiOiBcImluZGV4LmhhbmRsZXJcIixcbi8vICAgICAgICAgICAgIFwibWVtb3J5XCI6IDEyOCxcbi8vICAgICAgICAgICAgIFwidGltZW91dFwiOiAzMDBcbi8vICAgICAgICAgfSxcbi8vICAgICAgICAgXCJzZXJ2aWNlc1wiOiB7XG4vLyAgICAgICAgICAgICBcIm5hbWVcIjogXCJhbGlsYW5nXCIsXG4vLyAgICAgICAgICAgICBcImxvZ1Byb2plY3RcIjogXCJcIixcbi8vICAgICAgICAgICAgIFwibG9nU3RvcmVcIjogXCJcIlxuLy8gICAgICAgICB9LFxuLy8gICAgICAgICBcInJlZ2lvblwiOiBcImNuLXNoYW5naGFpXCIsXG4vLyAgICAgICAgIFwiYWNjb3VudElkXCI6IFwiMTczNDA2NjA1NzY4OTUyOFwiXG4vLyAgICAgfVxuLy8gfVxuXG4vLyDmnIDmlrDniYjmnKxldmVudOeahEFQSee9keWFs+eahEZD6L+U5Zue5pWw5o2u5qC85byP77yaXG4vLyAgICAgIENBLUhvc3Tor7fmsYLln5/lkI3jgIFcbi8vICAgICAgWC1Gb3J3YXJkZWQtUHJvdG9cbi8vICAgICAgXCJwYXRoXCI6IFwiL3Rlc3RcIiwgPT3jgIvjgIvln7rmnKzkuIrlj6/ku6Xmi7zmjqXlh7pfX3VybF9f5Y+C5pWw5Y+v5Lul55yB55Wl5o6J5q2k5YaX5L2Z5Y+C5pWw6YWN572u5LqG44CCXG4vLyAgICAgICAgICAgICAgICAgICAgICAgPT3jgIvjgIvlgJ/liqlyb3V0ZS5tYXAudHPmlofku7bnmoTmmKDlsITlhbPns7vlrprkuYnnnIHnlaXmjolfX2FwaV9f6YWN572u6L+b5LiA5q2l566A5YyW572R5YWz5bqU55So44CCXG4vLyAgICAgIFwiaHR0cE1ldGhvZFwiOiBcIkdFVFwiLFxuLy8gICAgICBcImlzQmFzZTY0RW5jb2RlZFwiOiB0cnVlLFxuLy8gICAgICBcIlgtRm9yd2FyZGVkLUZvclwiOiBcIjQyLjEyMC43NC4xMDNcIiwgLy8g5a6i5oi356uv6K+35rGCSVDlnLDlnYDnlKjmiLfliKTlrprmiYDlsZ7ljLrln5/kv6Hmga/mtbflpJborr/pl67pl67popjkvJjljJbkvp3otZbngrlcbi8vICAgICAgXCJYLVJlYWwtSVBcIjogXCI0Mi4xMjAuNzQuMTAzXCIsXG4vLyAgICAgIENvb2tpZVxuLy8gICAgICBVc2VyLUFnZW50ICAgICAgID0+PiBQQ+ermeWSjE3nq5noh6rpgILlupTpl67pophcbi8vICAgICAgQWNjZXB0LUxhbmd1YWdlICA9Pj4g5rWP6KeI5Zmo5a6i5oi356uv55qE6K+t6KiA57G75Z6L6Ieq5Yqo6YCC6YWN5aSa6K+t6KiA5p625p6E6K6+6K6h6Zeu6aKYXG4vLyBsZXQgeCA9IHtcbi8vICAgICBcImJvZHlcIjogXCJcIixcbi8vICAgICBcImhlYWRlcnNcIjoge1xuLy8gICAgICAgICBcIlgtQ2EtQXBpLUdhdGV3YXlcIjogXCJCMjc2Rjc3Qi0zMzRFLTQ4NTctQUU2NC02NUJBRkQ0MTlFMkFcIixcbi8vICAgICAgICAgXCJDb29raWVcIjogXCJjbmE9cjVzbkV6ek92QTBDQVNwNFNtZHErSUkvOyBVTV9kaXN0aW5jdGlkPTE2MmJjZDYxZDkxMTFjZC0wODBlMGY0M2U2YjYwZC0zMzY5N2IwNC0xM2M2ODAtMTYyYmNkNjFkOTJjODY7IF90Yl90b2tlbl89SDhVN0JxaXhGM1lWUjNHbmhNUno7IE5FVzJfQUNSX0pTRVNTSU9OSUQ9Vk01NjZGOTEtSzVDUDhRSVZNUVRTQUgzQzRINVgxLURSSUhZSkhKLVFFMjsgX25ld19jcl9zZXNzaW9uMD0xQWJMQnlPTUhlWmUzRzQxS1lkNVdjUGRDJTJGaThxdkdIVUJUSzhGYnJmeDhTb2klMkJIRUx1eHhBNmpyb3M3VyUyRnFDMVl0ZWJnQjNhdUVGNWx1MVNDelV6VGt0NnYlMkZpRmVOJTJGcHRidkJSemlZRUdYU0VWaFduVWxCUjJ0ZnBqclhNbkljZmIyJTJGd25Ha0g0dmtlTUlKMUJ2dXclM0QlM0Q7IGVtcGxJZD0xNDkzMzc7IGhyY19zaWRlYmFyPW9wZW47IHRyYWNlSWQ9N2Q0YjE2ZGUtNzRiYy00ZWFjLTg4NGItNTRjYTAzNTRlNGFhOyBTU09fTEFORz1aSC1DTjsgU1NPX0VNUElEX0hBU0g9OWRiMWVkMjE0MDJmN2MzNjY3NGI1ZTZlNmRlMWZjNjg7IGFuaW1hdGVfZGF0ZT0yMDE4NjQ7IGFhPXh4eHh4eHg7IGNuXzEyNjAwMDEyMjFfZHBsdXM9JTdCJTIyZGlzdGluY3RfaWQlMjIlM0ElMjAlMjIxNjJiY2Q2MWQ5MTExY2QtMDgwZTBmNDNlNmI2MGQtMzM2OTdiMDQtMTNjNjgwLTE2MmJjZDYxZDkyYzg2JTIyJTJDJTIyc3AlMjIlM0ElMjAlN0IlMjIlMjRfc2Vzc2lvbmlkJTIyJTNBJTIwMCUyQyUyMiUyNF9zZXNzaW9uVGltZSUyMiUzQSUyMDE1MjgwODYyMzQlMkMlMjIlMjRkcCUyMiUzQSUyMDAlMkMlMjIlMjRfc2Vzc2lvblBWVGltZSUyMiUzQSUyMDE1MjgwODYyMzQlN0QlN0Q7IGlzZz1CRHc4U29ueVM5dXR5bjVmZWRZUmUtdVJEZHp3TkFEMC01MUJIaGE5X1NjSjRkeHJOa1d3NzdLUXhRbVpxUmkzXCIsXG4vLyAgICAgICAgIFwiWC1Gb3J3YXJkZWQtUHJvdG9cIjogXCJodHRwc1wiLFxuLy8gICAgICAgICBcIlVzZXItQWdlbnRcIjogXCJNb3ppbGxhLzUuMCAoTWFjaW50b3NoOyBJbnRlbCBNYWMgT1MgWCAxMF8xMl82KSBBcHBsZVdlYktpdC81MzcuMzYgKEtIVE1MLCBsaWtlIEdlY2tvKSBDaHJvbWUvNjYuMC4zMzU5LjE4MSBTYWZhcmkvNTM3LjM2XCIsXG4vLyAgICAgICAgIFwiX191cmxfX1wiOiBcImh0dHBzOi8vdG91ZmFuZy5hbGliYWJhLWluYy5jb20vdGVzdFwiLFxuLy8gICAgICAgICBcIkNBLUhvc3RcIjogXCJ0b3VmYW5nLmFsaWJhYmEtaW5jLmNvbVwiLFxuLy8gICAgICAgICBcIkNhY2hlLUNvbnRyb2xcIjogXCJtYXgtYWdlPTBcIixcbi8vICAgICAgICAgXCJ1cGdyYWRlLWluc2VjdXJlLXJlcXVlc3RzXCI6IFwiMVwiLFxuLy8gICAgICAgICBcIkFjY2VwdC1MYW5ndWFnZVwiOiBcInpoLUNOLHpoO3E9MC45XCIsXG4vLyAgICAgICAgIFwiX19hcGlfX1wiOiBcIi93ZWIvdGVzdC90ZXN0XCIsXG4vLyAgICAgICAgIFwiQWNjZXB0LUVuY29kaW5nXCI6IFwiZ3ppcCwgZGVmbGF0ZSwgYnJcIixcbi8vICAgICAgICAgXCJYLUZvcndhcmRlZC1Gb3JcIjogXCI0Mi4xMjAuNzQuMTAzXCIsXG4vLyAgICAgICAgIFwiWC1SZWFsLUlQXCI6IFwiNDIuMTIwLjc0LjEwM1wiLFxuLy8gICAgICAgICBcIkFjY2VwdFwiOiBcInRleHQvaHRtbCxhcHBsaWNhdGlvbi94aHRtbCt4bWwsYXBwbGljYXRpb24veG1sO3E9MC45LGltYWdlL3dlYnAsaW1hZ2UvYXBuZywqLyo7cT0wLjhcIlxuLy8gICAgIH0sXG4vLyAgICAgXCJodHRwTWV0aG9kXCI6IFwiR0VUXCIsXG4vLyAgICAgXCJpc0Jhc2U2NEVuY29kZWRcIjogdHJ1ZSxcbi8vICAgICBcInBhdGhcIjogXCIvdGVzdFwiLFxuLy8gICAgIFwicGF0aFBhcmFtZXRlcnNcIjoge30sXG4vLyAgICAgXCJxdWVyeVBhcmFtZXRlcnNcIjoge31cbi8vIH1cbiJdfQ==
\No newline at end of file