UNPKG

51.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 callback, evt, __cors__, __api__, __url__, __header__, param, out, _a, post, body, err_1, cookie, setCookie, htmlResponse, jsonResponse, err_2;
72 return __generator(this, function (_b) {
73 switch (_b.label) {
74 case 0:
75 // 重置请求上下文环境变量
76 xreset();
77 // TODO 增加对于定时器的功能模拟实现
78 // 调试打印请求的输入和输出方便准确的定位调试线上的响应信息
79 xlog('$$$$=>' + event.toString());
80 callback = function (context, out) {
81 xlog('$$$$=>', out.body ? Object.assign({}, out, { body: xbase64decode(out.body) }) : out);
82 __callback__(context, out);
83 };
84 evt = JSON.parse(event.toString());
85 // TODO 需要对于事件定时器进行统一的约定在应用层可扩展自定义相关定时器等事件类型
86 if (evt['triggerName']) {
87 // 对定时触发器的统一拦截处理
88 switch (evt['triggerName']) {
89 // FC线上容器的预热定时器预置到开发框架上统一集成支持
90 case '__axjs-preheat-timer__':
91 // // 获取请求参数的配置数据
92 // try {
93 // let payload = JSON.parse(evt['payload'])
94 // xassert(payload['url'] && payload['timeout'])
95 // await xpost(payload['url'], payload['param'], undefined, payload['timeout'])
96 // } catch (err) {
97 // // ignore error
98 // xlog(JSON.stringify(xerror(err)).replace(/\r/g, '').replace(/\n/g, ''))
99 // }
100 break;
101 }
102 callback(null, {
103 statusCode: 200,
104 });
105 return [2 /*return*/];
106 }
107 // else if (evt['path'] === '/__axjs-preheat-timer__') {
108 // // 预热api网关的空请求心跳接口实现
109 // return
110 // }
111 // 根据API网关设置的环境常量参数正确配置线上版本的运行环境,取代AONE的本地、日常、预发、灰度等环境部署支持开发。
112 // 全局变量仅仅用于放在整个应用生命周期变量
113 global['__env__'] = _.get(evt, 'headers.__env__', 'prod');
114 __cors__ = {};
115 if (global['__env__'] !== 'prod' && global['__env__'] !== 'gray') {
116 // 非生产环境或灰度环境,需要禁用CORS功能禁止跨域访问增加安全性。
117 if (evt.headers.origin) {
118 // 获取源站动态允许请求跨域 (FIXME 需要进行安全限制对来源服务器网址合法性进行安全限制,本地开发调试全部放开请求)
119 __cors__['Access-Control-Allow-Origin'] = evt.headers.origin;
120 // __cors__['Access-Control-Allow-Origin'] = '*' // 不能设置为任意值浏览器有安全限制
121 }
122 __cors__['Access-Control-Allow-Credentials'] = 'true';
123 __cors__['Access-Control-Allow-Headers'] = 'Origin, X-Requested-With, Content-Type, Accept';
124 __cors__['Access-Control-Allow-Methods'] = 'POST, OPTIONS';
125 }
126 // 支持跨域的验证请求方法的合法性规避掉过滤掉不安全的请求。
127 switch (evt.httpMethod) {
128 case 'GET':
129 case 'POST':
130 break;
131 case 'OPTIONS':
132 if (global['__env__'] == 'prod' || global['__env__'] == 'gray') {
133 // 生产和灰度环境下禁止跨域OPTIONS请求以便于增强安全性
134 callback(null, {
135 statusCode: 501,
136 });
137 }
138 else {
139 // 非生产和灰度环境下才允许支持跨域OPTIONS请求
140 callback(null, {
141 statusCode: 200,
142 headers: __assign({}, __cors__),
143 });
144 }
145 return [2 /*return*/];
146 default:
147 // 禁止任何的非法请求严格进行约定限制
148 callback(null, {
149 statusCode: 502,
150 });
151 return [2 /*return*/];
152 }
153 global['__evt__'] = event.toString(); // FIXME 需要设计上下文定义请求实例生命周期变量
154 __api__ = _.get(evt, 'headers.__api__', evt.path) // 最终控制器与app子目录下的ts文件保持完全的一一映射关系。
155 ;
156 __url__ = evt['headers']['X-Forwarded-Proto'] + '://' + evt['headers']['CA-Host'] + evt['path'];
157 __header__ = evt['headers'];
158 param = Object.assign({ __api__: __api__, __url__: __url__, __header__: __header__ }, // header请求中的两个框架层面上的预定义参数 TODO 需要移除掉并非应用关心的内容
159 evt.pathParameters || {}, // 路由重写参数 domain/[a]/[b]?xxx (可被GET参数覆盖)
160 evt.queryParameters || {} // GET请求参数 domain/path?a=x&b=x
161 );
162 out = {};
163 _a = evt.httpMethod;
164 switch (_a) {
165 case 'GET': return [3 /*break*/, 1];
166 case 'POST': return [3 /*break*/, 2];
167 }
168 return [3 /*break*/, 6];
169 case 1: return [3 /*break*/, 7];
170 case 2:
171 _b.trys.push([2, 3, , 5]);
172 post = {};
173 if (_.isString(evt.body)) {
174 body = evt.body;
175 if (evt.isBase64Encoded) {
176 body = new Buffer(evt.body, 'base64').toString();
177 }
178 post = init_1.parse_post_param(evt['headers'], body);
179 }
180 param = Object.assign(param, post); // 用post参数覆盖掉get参数,用于灵活的设置请求参数兼容get和post两种方法方便开发调试。
181 return [3 /*break*/, 5];
182 case 3:
183 err_1 = _b.sent();
184 xlog(err_1, evt.httpMethod, evt.body);
185 return [4 /*yield*/, xwarn(err_1)
186 // 400 Bad Request 客户端请求的语法错误,服务器无法理解
187 ];
188 case 4:
189 _b.sent();
190 // 400 Bad Request 客户端请求的语法错误,服务器无法理解
191 callback(null, {
192 statusCode: 503,
193 });
194 return [2 /*return*/];
195 case 5: return [3 /*break*/, 7];
196 case 6:
197 xlog(evt.httpMethod, evt.body);
198 // 400 Bad Request 客户端请求的语法错误,服务器无法理解
199 callback(null, {
200 statusCode: 504,
201 });
202 return [2 /*return*/];
203 case 7:
204 _b.trys.push([7, 9, , 11]);
205 cookie = _.get(evt['headers'], 'Cookie', undefined);
206 if (!cookie) {
207 cookie = _.get(evt['headers'], 'cookie', '');
208 }
209 global['__request_cookies__'] = require('cookie').parse(cookie);
210 // 获取use-agent请求头部信息
211 global['__user_agent__'] = evt['headers']['User-Agent'];
212 // 获取客户端的IP地址信息
213 global['__client_ip__'] = evt['headers']['X-Real-IP'];
214 return [4 /*yield*/, init_1.request_process(__api__, param)
215 // 处理response的cookies设置
216 ];
217 case 8:
218 // TODO WEB请求需要对404页面以及ERROR页面进行兼容处理(在framework内部进行细节的错误判断在out中透传status的http的状态吗正确错误返回)
219 // 404 Not Found 服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置"您所请求的资源无法找到"的个性页面
220 // 403 Forbidden 服务器理解请求客户端的请求,但是拒绝执行此请求(权限验证处理错误)
221 out = _b.sent();
222 setCookie = { 'Set-Cookie': undefined };
223 if (!_.isEmpty(global['__respond_cookies__'])) {
224 setCookie['Set-Cookie'] = _.values(global['__respond_cookies__']);
225 }
226 if (global['__redirect_url__']) {
227 callback(null, {
228 statusCode: 302,
229 headers: __assign({ "Location": global['__redirect_url__'] }, setCookie),
230 });
231 global['__redirect_url__'] = undefined;
232 }
233 else if (_.isString(out)) {
234 htmlResponse = {
235 isBase64Encoded: true,
236 statusCode: 200,
237 headers: __assign({ "Content-type": "text/html; charset=utf-8" }, setCookie, __cors__),
238 // base64 encode body so it can be safely returned as JSON value
239 body: new Buffer(out).toString('base64')
240 };
241 callback(null, htmlResponse);
242 }
243 else {
244 jsonResponse = {
245 isBase64Encoded: true,
246 statusCode: 200,
247 headers: __assign({ "Content-type": "application/json" }, __cors__),
248 // base64 encode body so it can be safely returned as JSON value
249 body: new Buffer(JSON.stringify(out)).toString('base64')
250 };
251 callback(null, jsonResponse);
252 }
253 return [3 /*break*/, 11];
254 case 9:
255 err_2 = _b.sent();
256 // 通知框架自身实现逻辑的意外报错(框架自身不论何种情况都应该正常工作,一旦出现此问题大多数情况是框架自身问题或者流量引发的运维问题)
257 return [4 /*yield*/, xwarn({
258 __api__: __api__, __url__: __url__, param: param, message: err_2.message, stack: xstack(err_2)
259 })
260 // 500 Internal Server Error 服务器内部错误,无法完成请求
261 ];
262 case 10:
263 // 通知框架自身实现逻辑的意外报错(框架自身不论何种情况都应该正常工作,一旦出现此问题大多数情况是框架自身问题或者流量引发的运维问题)
264 _b.sent();
265 // 500 Internal Server Error 服务器内部错误,无法完成请求
266 callback(null, { statusCode: 505 });
267 return [3 /*break*/, 11];
268 case 11: return [2 /*return*/];
269 }
270 });
271 });
272};
273// API参数的识别逻辑,为普通字符串路径定义与app下的ts文件路由完全一一对应,优先取HEADER中的定义,再取GET中的形参定义或者POST形参定义进行参数请求的覆盖处理。
274// PARAM请求的参数处理要求为BASE64编码化的JSON字符串。
275// "event": {
276// "body": "ewoJImFwaSI6ICIvYS9iL2MiLAoJInBhcmFtIjogImFzZGZhc2RmYXNkZiIKfQ==", => 对应于POST请求数据
277// "headers": {
278// "X-Ca-Api-Gateway": "B25CD51B-5815-4775-9EAB-6D481BC1AE17",
279// "__api__": "/web/mobile/test", =》 自定义转义PATH的路径信息对于SEO优化兼容处理(也可以在GET或POST请求中传递对应参数)
280// "X-Forwarded-For": "42.120.74.88",
281// "Content-Type": "application/json"
282// },
283// "httpMethod": "POST",
284// "isBase64Encoded": true,
285// "path": "/", =》 没有意义用于前端根据需要自己进行扩展别名映射处理,后端的控制器不以此为标准,可以对同一个控制器定义N个不同的路径标识。
286// "pathParameters": {},
287// "queryParameters": {} => 对应于GET请求数据
288// },
289// "query": {},
290// "context": {
291// "requestId": "B25CD51B-5815-4775-9EAB-6D481BC1AE17",
292// "credentials": {
293// "accessKeyId": "",
294// "accessKeySecret": "",
295// "securityToken": ""
296// },
297// "function": {
298// "name": "test",
299// "handler": "index.handler",
300// "memory": 128,
301// "timeout": 300
302// },
303// "services": {
304// "name": "alilang",
305// "logProject": "",
306// "logStore": ""
307// },
308// "region": "cn-shanghai",
309// "accountId": "1734066057689528"
310// }
311// }
312// 最新版本event的API网关的FC返回数据格式:
313// CA-Host请求域名、
314// X-Forwarded-Proto
315// "path": "/test", ==》》基本上可以拼接出__url__参数可以省略掉此冗余参数配置了。
316// ==》》借助route.map.ts文件的映射关系定义省略掉__api__配置进一步简化网关应用。
317// "httpMethod": "GET",
318// "isBase64Encoded": true,
319// "X-Forwarded-For": "42.120.74.103", // 客户端请求IP地址用户判定所属区域信息海外访问问题优化依赖点
320// "X-Real-IP": "42.120.74.103",
321// Cookie
322// User-Agent =>> PC站和M站自适应问题
323// Accept-Language =>> 浏览器客户端的语言类型自动适配多语言架构设计问题
324// let x = {
325// "body": "",
326// "headers": {
327// "X-Ca-Api-Gateway": "B276F77B-334E-4857-AE64-65BAFD419E2A",
328// "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",
329// "X-Forwarded-Proto": "https",
330// "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",
331// "__url__": "https://toufang.alibaba-inc.com/test",
332// "CA-Host": "toufang.alibaba-inc.com",
333// "Cache-Control": "max-age=0",
334// "upgrade-insecure-requests": "1",
335// "Accept-Language": "zh-CN,zh;q=0.9",
336// "__api__": "/web/test/test",
337// "Accept-Encoding": "gzip, deflate, br",
338// "X-Forwarded-For": "42.120.74.103",
339// "X-Real-IP": "42.120.74.103",
340// "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8"
341// },
342// "httpMethod": "GET",
343// "isBase64Encoded": true,
344// "path": "/test",
345// "pathParameters": {},
346// "queryParameters": {}
347// }
348//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXgtY2xpZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiaW5kZXgtY2xpZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLE9BQU8sQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDLE9BQU8sRUFBRSxDQUFBO0FBQ3ZDLE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDLFFBQVEsRUFBRSxDQUFBO0FBQ3BDLCtCQUF3RDtBQUV4RCxJQUFNLENBQUMsR0FBRyxPQUFPLENBQUMsUUFBUSxDQUFDLENBQUE7QUFFM0IsZ0JBQWdCO0FBQ2hCLG9HQUFvRztBQUNwRyxnRUFBZ0U7QUFDaEUsK0RBQStEO0FBQy9ELDhDQUE4QztBQUM5QyxtREFBbUQ7QUFDbkQsbURBQW1EO0FBQ25ELDJCQUEyQjtBQUMzQixpQ0FBaUM7QUFDakMsMkJBQTJCO0FBQzNCLHFCQUFxQjtBQUNyQiwwREFBMEQ7QUFDMUQsYUFBYTtBQUNiLDJFQUEyRTtBQUMzRSw2REFBNkQ7QUFDN0QsUUFBUTtBQUNSLG1DQUFtQztBQUNuQyxJQUFJO0FBRUosc0JBQXNCO0FBQ3RCLE9BQU8sQ0FBQyxPQUFPLEdBQUcsVUFBZ0IsS0FBSyxFQUFFLE9BQU8sRUFBRSxZQUFZOzs7Ozs7b0JBQzFELGNBQWM7b0JBQ2QsTUFBTSxFQUFFLENBQUE7b0JBRVIsc0JBQXNCO29CQUV0QiwrQkFBK0I7b0JBQy9CLElBQUksQ0FBQyxRQUFRLEdBQUcsS0FBSyxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUE7b0JBQzNCLFFBQVEsR0FBRyxVQUFDLE9BQU8sRUFBRSxHQUFHO3dCQUMxQixJQUFJLENBQUMsUUFBUSxFQUFFLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsRUFBRSxFQUFFLEdBQUcsRUFBRSxFQUFDLElBQUksRUFBRSxhQUFhLENBQUMsR0FBRyxDQUFDLElBQUksQ0FB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QjtBQUM3QixhQUFhO0FBQ2IsbUNBQW1DO0FBQ25DLDBDQUEwQztBQUMxQyxRQUFRO0FBQ1IsSUFBSTtBQUVKLDRCQUE0QjtBQUM1QixvQkFBb0I7QUFDcEIseUJBQXlCO0FBQ3pCLDREQUE0RDtBQUM1RCwwRUFBMEU7QUFDMUUsNEJBQTRCO0FBQzVCLGdDQUFnQztBQUNoQyw2RUFBNkU7QUFDN0UscUNBQXFDO0FBQ3JDLGNBQWM7QUFDZCx3Q0FBd0M7QUFDeEMscURBQXFEO0FBQ3JELFlBQVk7QUFDWixrQkFBa0I7QUFDbEIsbUJBQW1CO0FBQ25CLHNFQUFzRTtBQUN0RSxtNkJBQW02QjtBQUNuNkIsd0NBQXdDO0FBQ3hDLHFKQUFxSjtBQUNySiw2REFBNkQ7QUFDN0QsZ0RBQWdEO0FBQ2hELHdDQUF3QztBQUN4Qyw0Q0FBNEM7QUFDNUMsK0NBQStDO0FBQy9DLHVDQUF1QztBQUN2QyxrREFBa0Q7QUFDbEQsOENBQThDO0FBQzlDLHdDQUF3QztBQUN4Qyw0R0FBNEc7QUFDNUcsU0FBUztBQUNULDJCQUEyQjtBQUMzQiwrQkFBK0I7QUFDL0IsdUJBQXVCO0FBQ3ZCLDRCQUE0QjtBQUM1Qiw0QkFBNEI7QUFDNUIsSUFBSSIsInNvdXJjZXNDb250ZW50IjpbInJlcXVpcmUoJ3NvdXJjZS1tYXAtc3VwcG9ydCcpLmluc3RhbGwoKVxucmVxdWlyZSgndHNjb25maWctcGF0aHMnKS5yZWdpc3RlcigpXG5pbXBvcnQge3JlcXVlc3RfcHJvY2VzcywgcGFyc2VfcG9zdF9wYXJhbX0gZnJvbSAnLi9pbml0J1xuXG5jb25zdCBfID0gcmVxdWlyZSgnbG9kYXNoJylcblxuLy8gLy8g5Li05pe26LCD6K+V57q/5LiK5pel5b+X5omT5Y2wXG4vLyAvL2ZyYW1ld29yay9pbmRleC50cyg4LDEzKTogZXJyb3IgVFMyMzM5OiBQcm9wZXJ0eSAnc2V0TG9nTGV2ZWwnIGRvZXMgbm90IGV4aXN0IG9uIHR5cGUgJ0NvbnNvbGUnXG4vLyBleHBvcnRzLmhhbmRsZXIgPSBhc3luYyBmdW5jdGlvbiAoZXZlbnQsIGNvbnRleHQsIGNhbGxiYWNrKSB7XG4vLyAgICAgLy8gY29uc29sZS5zZXRMb2dMZXZlbCgnZXJyb3InKSDkuI3og73lhpnlnKjmraTkvJrlr7zoh7TnvJbor5HplJnor6/pmL/ph4zkupHoh6rlt7HmianlsZXnmoTnp4HmnInmlrnms5Vcbi8vICAgICBjb25zb2xlLmxvZygneHh4eHgnLCAneXl5eXknLCAnenp6enp6Jylcbi8vICAgICBjb25zb2xlLmVycm9yKCd4eHh4eDEnLCAneXl5eXkxJywgJ3p6enp6ejEnKVxuLy8gICAgIGxldCBvdXQgPSAnPGh0bWw+PGJvZHk+enp6enp6PC9ib2R5PjwvaHRtbD4nXG4vLyAgICAgbGV0IGh0bWxSZXNwb25zZSA9IHtcbi8vICAgICAgICAgaXNCYXNlNjRFbmNvZGVkOiB0cnVlLFxuLy8gICAgICAgICBzdGF0dXNDb2RlOiAyMDAsXG4vLyAgICAgICAgIGhlYWRlcnM6IHtcbi8vICAgICAgICAgICAgIFwiQ29udGVudC10eXBlXCI6IFwidGV4dC9odG1sOyBjaGFyc2V0PXV0Zi04XCIsXG4vLyAgICAgICAgIH0sXG4vLyAgICAgICAgIC8vIGJhc2U2NCBlbmNvZGUgYm9keSBzbyBpdCBjYW4gYmUgc2FmZWx5IHJldHVybmVkIGFzIEpTT04gdmFsdWVcbi8vICAgICAgICAgYm9keTogbmV3IEJ1ZmZlcihvdXQgYXMgc3RyaW5nKS50b1N0cmluZygnYmFzZTY0Jylcbi8vICAgICB9XG4vLyAgICAgY2FsbGJhY2sobnVsbCwgaHRtbFJlc3BvbnNlKVxuLy8gfVxuXG4vLyDln7rkuo7pmL/ph4zkupHnmoTlh73mlbDorqHnrpfnu5/kuIDlhaXlj6PnmoTot6/nlLHlpITnkIZcbmV4cG9ydHMuaGFuZGxlciA9IGFzeW5jIGZ1bmN0aW9uIChldmVudCwgY29udGV4dCwgX19jYWxsYmFja19fKSB7XG4gICAgLy8g6YeN572u6K+35rGC5LiK5LiL5paH546v5aKD5Y+Y6YePXG4gICAgeHJlc2V0KClcblxuICAgIC8vIFRPRE8g5aKe5Yqg5a+55LqO5a6a5pe25Zmo55qE5Yqf6IO95qih5ouf5a6e546wXG5cbiAgICAvLyDosIPor5XmiZPljbDor7fmsYLnmoTovpPlhaXlkozovpPlh7rmlrnkvr/lh4bnoa7nmoTlrprkvY3osIPor5Xnur/kuIrnmoTlk43lupTkv6Hmga9cbiAgICB4bG9nKCckJCQkPT4nICsgZXZlbnQudG9TdHJpbmcoKSlcbiAgICBjb25zdCBjYWxsYmFjayA9IChjb250ZXh0LCBvdXQpID0+IHtcbiAgICAgICAgeGxvZygnJCQkJD0+Jywgb3V0LmJvZHkgPyBPYmplY3QuYXNzaWduKHt9LCBvdXQsIHtib2R5OiB4YmFzZTY0ZGVjb2RlKG91dC5ib2R5KX0pIDogb3V0KVxuICAgICAgICBfX2NhbGxiYWNrX18oY29udGV4dCwgb3V0KVxuICAgIH1cblxuICAgIGxldCBldnQgPSBKU09OLnBhcnNlKGV2ZW50LnRvU3RyaW5nKCkpXG5cbiAgICAvLyBUT0RPIOmcgOimgeWvueS6juS6i+S7tuWumuaXtuWZqOi/m+ihjOe7n+S4gOeahOe6puWumuWcqOW6lOeUqOWxguWPr+aJqeWxleiHquWumuS5ieebuOWFs+WumuaXtuWZqOetieS6i+S7tuexu+Wei1xuICAgIGlmIChldnRbJ3RyaWdnZXJOYW1lJ10pIHtcbiAgICAgICAgLy8g5a+55a6a5pe26Kem5Y+R5Zmo55qE57uf5LiA5oum5oiq5aSE55CGXG4gICAgICAgIHN3aXRjaCAoZXZ0Wyd0cmlnZ2VyTmFtZSddKSB7XG4gICAgICAgICAgICAvLyBGQ+e6v+S4iuWuueWZqOeahOmihOeDreWumuaXtuWZqOmihOe9ruWIsOW8gOWPkeahhuaetuS4iue7n+S4gOmbhuaIkOaUr+aMgVxuICAgICAgICAgICAgY2FzZSAnX19heGpzLXByZWhlYXQtdGltZXJfXyc6XG4gICAgICAgICAgICAgICAgLy8gLy8g6I635Y+W6K+35rGC5Y+C5pWw55qE6YWN572u5pWw5o2uXG4gICAgICAgICAgICAgICAgLy8gdHJ5IHtcbiAgICAgICAgICAgICAgICAvLyAgICAgbGV0IHBheWxvYWQgPSBKU09OLnBhcnNlKGV2dFsncGF5bG9hZCddKVxuICAgICAgICAgICAgICAgIC8vICAgICB4YXNzZXJ0KHBheWxvYWRbJ3VybCddICYmIHBheWxvYWRbJ3RpbWVvdXQnXSlcbiAgICAgICAgICAgICAgICAvLyAgICAgYXdhaXQgeHBvc3QocGF5bG9hZFsndXJsJ10sIHBheWxvYWRbJ3BhcmFtJ10sIHVuZGVmaW5lZCwgcGF5bG9hZFsndGltZW91dCddKVxuICAgICAgICAgICAgICAgIC8vIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgICAgIC8vICAgICAvLyBpZ25vcmUgZXJyb3JcbiAgICAgICAgICAgICAgICAvLyAgICAgeGxvZyhKU09OLnN0cmluZ2lmeSh4ZXJyb3IoZXJyKSkucmVwbGFjZSgvXFxyL2csICcnKS5yZXBsYWNlKC9cXG4vZywgJycpKVxuICAgICAgICAgICAgICAgIC8vIH1cbiAgICAgICAgICAgICAgICBicmVha1xuICAgICAgICB9XG4gICAgICAgIGNhbGxiYWNrKG51bGwsIHtcbiAgICAgICAgICAgIHN0YXR1c0NvZGU6IDIwMCxcbiAgICAgICAgfSlcbiAgICAgICAgcmV0dXJuXG4gICAgfVxuICAgIC8vIGVsc2UgaWYgKGV2dFsncGF0aCddID09PSAnL19fYXhqcy1wcmVoZWF0LXRpbWVyX18nKSB7XG4gICAgLy8gICAgIC8vIOmihOeDrWFwaee9keWFs+eahOepuuivt+axguW/g+i3s+aOpeWPo+WunueOsFxuICAgIC8vICAgICByZXR1cm5cbiAgICAvLyB9XG5cbiAgICAvLyDmoLnmja5BUEnnvZHlhbPorr7nva7nmoTnjq/looPluLjph4/lj4LmlbDmraPnoa7phY3nva7nur/kuIrniYjmnKznmoTov5DooYznjq/looPvvIzlj5bku6NBT05F55qE5pys5Zyw44CB5pel5bi444CB6aKE5Y+R44CB54Gw5bqm562J546v5aKD6YOo572y5pSv5oyB5byA5Y+R44CCXG4gICAgLy8g5YWo5bGA5Y+Y6YeP5LuF5LuF55So5LqO5pS+5Zyo5pW05Liq5bqU55So55Sf5ZG95ZGo5pyf5Y+Y6YePXG4gICAgZ2xvYmFsWydfX2Vudl9fJ10gPSBfLmdldChldnQsICdoZWFkZXJzLl9fZW52X18nLCAncHJvZCcpXG5cbiAgICBjb25zdCBfX2NvcnNfXyA9IHt9XG4gICAgaWYgKGdsb2JhbFsnX19lbnZfXyddICE9PSAncHJvZCcgJiYgZ2xvYmFsWydfX2Vudl9fJ10gIT09ICdncmF5Jykge1xuICAgICAgICAvLyDpnZ7nlJ/kuqfnjq/looPmiJbngbDluqbnjq/looPvvIzpnIDopoHnpoHnlKhDT1JT5Yqf6IO956aB5q2i6Leo5Z+f6K6/6Zeu5aKe5Yqg5a6J5YWo5oCn44CCXG4gICAgICAgIGlmIChldnQuaGVhZGVycy5vcmlnaW4pIHtcbiAgICAgICAgICAgIC8vIOiOt+WPlua6kOermeWKqOaAgeWFgeiuuOivt+axgui3qOWfnyAoRklYTUUg6ZyA6KaB6L+b6KGM5a6J5YWo6ZmQ5Yi25a+55p2l5rqQ5pyN5Yqh5Zmo572R5Z2A5ZCI5rOV5oCn6L+b6KGM5a6J5YWo6ZmQ5Yi277yM5pys5Zyw5byA5Y+R6LCD6K+V5YWo6YOo5pS+5byA6K+35rGCKVxuICAgICAgICAgICAgX19jb3JzX19bJ0FjY2Vzcy1Db250cm9sLUFsbG93LU9yaWdpbiddID0gZXZ0LmhlYWRlcnMub3JpZ2luXG4gICAgICAgICAgICAvLyBfX2NvcnNfX1snQWNjZXNzLUNvbnRyb2wtQWxsb3ctT3JpZ2luJ10gPSAnKicgLy8g5LiN6IO96K6+572u5Li65Lu75oSP5YC85rWP6KeI5Zmo5pyJ5a6J5YWo6ZmQ5Yi2XG4gICAgICAgIH1cbiAgICAgICAgX19jb3JzX19bJ0FjY2Vzcy1Db250cm9sLUFsbG93LUNyZWRlbnRpYWxzJ10gPSAndHJ1ZSdcbiAgICAgICAgX19jb3JzX19bJ0FjY2Vzcy1Db250cm9sLUFsbG93LUhlYWRlcnMnXSA9ICdPcmlnaW4sIFgtUmVxdWVzdGVkLVdpdGgsIENvbnRlbnQtVHlwZSwgQWNjZXB0J1xuICAgICAgICBfX2NvcnNfX1snQWNjZXNzLUNvbnRyb2wtQWxsb3ctTWV0aG9kcyddID0gJ1BPU1QsIE9QVElPTlMnXG4gICAgfVxuXG4gICAgLy8g5pSv5oyB6Leo5Z+f55qE6aqM6K+B6K+35rGC5pa55rOV55qE5ZCI5rOV5oCn6KeE6YG/5o6J6L+H5ruk5o6J5LiN5a6J5YWo55qE6K+35rGC44CCXG4gICAgc3dpdGNoIChldnQuaHR0cE1ldGhvZCkge1xuICAgICAgICBjYXNlICdHRVQnOlxuICAgICAgICBjYXNlICdQT1NUJzpcbiAgICAgICAgICAgIGJyZWFrXG4gICAgICAgIGNhc2UgJ09QVElPTlMnOlxuICAgICAgICAgICAgaWYgKGdsb2JhbFsnX19lbnZfXyddID09ICdwcm9kJyB8fCBnbG9iYWxbJ19fZW52X18nXSA9PSAnZ3JheScpIHtcbiAgICAgICAgICAgICAgICAvLyDnlJ/kuqflkozngbDluqbnjq/looPkuIvnpoHmraLot6jln59PUFRJT05T6K+35rGC5Lul5L6/5LqO5aKe5by65a6J5YWo5oCnXG4gICAgICAgICAgICAgICAgY2FsbGJhY2sobnVsbCwge1xuICAgICAgICAgICAgICAgICAgICBzdGF0dXNDb2RlOiA1MDEsXG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgLy8g6Z2e55Sf5Lqn5ZKM54Gw5bqm546v5aKD5LiL5omN5YWB6K645pSv5oyB6Leo5Z+fT1BUSU9OU+ivt+axglxuICAgICAgICAgICAgICAgIGNhbGxiYWNrKG51bGwsIHtcbiAgICAgICAgICAgICAgICAgICAgc3RhdHVzQ29kZTogMjAwLFxuICAgICAgICAgICAgICAgICAgICBoZWFkZXJzOiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAuLi5fX2NvcnNfXyxcbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuXG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICAvLyDnpoHmraLku7vkvZXnmoTpnZ7ms5Xor7fmsYLkuKXmoLzov5vooYznuqblrprpmZDliLZcbiAgICAgICAgICAgIGNhbGxiYWNrKG51bGwsIHtcbiAgICAgICAgICAgICAgICBzdGF0dXNDb2RlOiA1MDIsXG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgcmV0dXJuXG4gICAgfVxuXG4gICAgZ2xvYmFsWydfX2V2dF9fJ10gPSBldmVudC50b1N0cmluZygpIC8vIEZJWE1FIOmcgOimgeiuvuiuoeS4iuS4i+aWh+WumuS5ieivt+axguWunuS+i+eUn+WRveWRqOacn+WPmOmHj1xuICAgIC8vIOWFiOS7pUhFQUVS5Lit55qEX19hcGlfX+Wtl+autei/m+ihjOivhuWIq++8jOWmguaenEhFQURFUuS4reayoeacieWumuS5ieWGjeS9v+eUqFVSTOi3r+W+hOWvueW6lOeahFBBVEjor4bliKvvvIzku6XmraTmlK/mjIFTRU/nrYnliY3nq6/ot6/lvoTph43lhpnpl67popjjgIJcbiAgICBsZXQgX19hcGlfXyA9IF8uZ2V0KGV2dCwgJ2hlYWRlcnMuX19hcGlfXycsIGV2dC5wYXRoKSAvLyDmnIDnu4jmjqfliLblmajkuI5hcHDlrZDnm67lvZXkuIvnmoR0c+aWh+S7tuS/neaMgeWujOWFqOeahOS4gOS4gOaYoOWwhOWFs+ezu+OAglxuICAgIC8vIOaUuei/m+S4uuagueaNrkFQSee9keWFs+eahOebuOWFs+WPguaVsOiHquWKqOaLvOaOpeWHuuadpeato+ehrueahFVSTOe9keWdgOivt+axgui3r+W+hFxuICAgIGxldCBfX3VybF9fID0gZXZ0WydoZWFkZXJzJ11bJ1gtRm9yd2FyZGVkLVByb3RvJ10gKyAnOi8vJyArIGV2dFsnaGVhZGVycyddWydDQS1Ib3N0J10gKyBldnRbJ3BhdGgnXVxuICAgIC8vIOWwhuWFqOmDqOeahEhFQURFUuS/oeaBr+mAj+S8oOWIsOW6lOeUqOS4rVxuICAgIGxldCBfX2hlYWRlcl9fID0gZXZ0WydoZWFkZXJzJ11cblxuICAgIGxldCBwYXJhbSA9IE9iamVjdC5hc3NpZ24oXG4gICAgICAgIHtfX2FwaV9fLCBfX3VybF9fLCBfX2hlYWRlcl9ffSwgLy8gaGVhZGVy6K+35rGC5Lit55qE5Lik5Liq5qGG5p625bGC6Z2i5LiK55qE6aKE5a6a5LmJ5Y+C5pWwIFRPRE8g6ZyA6KaB56e76Zmk5o6J5bm26Z2e5bqU55So5YWz5b+D55qE5YaF5a65XG4gICAgICAgIGV2dC5wYXRoUGFyYW1ldGVycyB8fCB7fSwgLy8g6Lev55Sx6YeN5YaZ5Y+C5pWwIGRvbWFpbi9bYV0vW2JdP3h4eCAo5Y+v6KKrR0VU5Y+C5pWw6KaG55uWKVxuICAgICAgICBldnQucXVlcnlQYXJhbWV0ZXJzIHx8IHt9IC8vIEdFVOivt+axguWPguaVsCBkb21haW4vcGF0aD9hPXgmYj14XG4gICAgKVxuICAgIGxldCBvdXQgPSB7fVxuXG4gICAgLy8gLy8g5p2h5Lu25pel5b+X5omT5Y2w57q/5LiK5Li05pe26Zeu6aKY5o6S5p+l5aSE55CG77yIVE9ETyDlop7liqDkuJrliqHpgLvovpHmianlsZXms6jlhaXnmoTpkqnlrZDlrp7njrDvvIlcbiAgICAvLyBsZXQgeGRlYnVnID0gYXN5bmMgKC4uLmFyZ3MpID0+IHtcbiAgICAvLyAgICAgaWYgKCFfLmluY2x1ZGVzKF9fdXJsX18sICd5LmFsaWJhYmEtaW5jLmNvbScpKSB7XG4gICAgLy8gICAgICAgICByZXR1cm5cbiAgICAvLyAgICAgfVxuICAgIC8vICAgICBhd2FpdCB4d2FybiguLi5hcmdzKVxuICAgIC8vIH1cbiAgICAvLyBnbG9iYWxbJ3hkZWJ1ZyddID0geGRlYnVnIC8vIOWFqOWxgOWPr+eUqFxuICAgIC8vIGF3YWl0IHhkZWJ1Zyh7cGFyYW0sIGV2dH0pXG5cbiAgICBzd2l0Y2ggKGV2dC5odHRwTWV0aG9kKSB7XG4gICAgICAgIGNhc2UgJ0dFVCc6XG4gICAgICAgICAgICBicmVha1xuICAgICAgICBjYXNlICdQT1NUJzpcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgLy8g6Zi/6YeM5LqRQVBJ572R5YWz55qEUE9TVOivt+axguWPguaVsOaYr0pTT07lrZfnrKbkuLLnmoRCQVNFNjTnvJbnoIHmiYDku6XpnIDopoHov5vooYzovazkuYnlpITnkIZcbiAgICAgICAgICAgICAgICBsZXQgcG9zdCA9IHt9XG4gICAgICAgICAgICAgICAgaWYgKF8uaXNTdHJpbmcoZXZ0LmJvZHkpKSB7XG4gICAgICAgICAgICAgICAgICAgIGxldCBib2R5ID0gZXZ0LmJvZHlcbiAgICAgICAgICAgICAgICAgICAgaWYgKGV2dC5pc0Jhc2U2NEVuY29kZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGJvZHkgPSBuZXcgQnVmZmVyKGV2dC5ib2R5LCAnYmFzZTY0JykudG9TdHJpbmcoKVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHBvc3QgPSBwYXJzZV9wb3N0X3BhcmFtKGV2dFsnaGVhZGVycyddLCBib2R5KVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBwYXJhbSA9IE9iamVjdC5hc3NpZ24ocGFyYW0sIHBvc3QpIC8vIOeUqHBvc3Tlj4LmlbDopobnm5bmjolnZXTlj4LmlbDvvIznlKjkuo7ngbXmtLvnmoTorr7nva7or7fmsYLlj4LmlbDlhbzlrrlnZXTlkoxwb3N05Lik56eN5pa55rOV5pa55L6/5byA5Y+R6LCD6K+V44CCXG4gICAgICAgICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgICAgICAgICB4bG9nKGVyciwgZXZ0Lmh0dHBNZXRob2QsIGV2dC5ib2R5KVxuICAgICAgICAgICAgICAgIGF3YWl0IHh3YXJuKGVycilcbiAgICAgICAgICAgICAgICAvLyA0MDBcdEJhZCBSZXF1ZXN0XHTlrqLmiLfnq6/or7fmsYLnmoTor63ms5XplJnor6/vvIzmnI3liqHlmajml6Dms5XnkIbop6NcbiAgICAgICAgICAgICAgICBjYWxsYmFjayhudWxsLCB7XG4gICAgICAgICAgICAgICAgICAgIHN0YXR1c0NvZGU6IDUwMyxcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgIHJldHVyblxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgYnJlYWtcbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgIHhsb2coZXZ0Lmh0dHBNZXRob2QsIGV2dC5ib2R5KVxuICAgICAgICAgICAgLy8gNDAwXHRCYWQgUmVxdWVzdFx05a6i5oi356uv6K+35rGC55qE6K+t5rOV6ZSZ6K+v77yM5pyN5Yqh5Zmo5peg5rOV55CG6KejXG4gICAgICAgICAgICBjYWxsYmFjayhudWxsLCB7XG4gICAgICAgICAgICAgICAgc3RhdHVzQ29kZTogNTA0LFxuICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIHJldHVyblxuICAgIH1cblxuICAgIHRyeSB7XG4gICAgICAgIC8vIOino+aekOivt+axguS4reeahGNvb2tpZXPmlbDmja7lubbovazmjaLkuLpKU09O5a+56LGh5a2Y5YKo5Yiw5YWo5bGA5Y+Y6YeP5Lit5L6/5LqO5ZCO57ut5bqU55SoeGNvb2tpZeaOpeWPo+S9v+eUqFxuICAgICAgICBsZXQgY29va2llID0gXy5nZXQoZXZ0WydoZWFkZXJzJ10sICdDb29raWUnLCB1bmRlZmluZWQpXG4gICAgICAgIGlmICghY29va2llKSB7XG4gICAgICAgICAgICBjb29raWUgPSBfLmdldChldnRbJ2hlYWRlcnMnXSwgJ2Nvb2tpZScsICcnKVxuICAgICAgICB9XG4gICAgICAgIGdsb2JhbFsnX19yZXF1ZXN0X2Nvb2tpZXNfXyddID0gcmVxdWlyZSgnY29va2llJykucGFyc2UoY29va2llKVxuXG4gICAgICAgIC8vIOiOt+WPlnVzZS1hZ2VudOivt+axguWktOmDqOS/oeaBr1xuICAgICAgICBnbG9iYWxbJ19fdXNlcl9hZ2VudF9fJ10gPSBldnRbJ2hlYWRlcnMnXVsnVXNlci1BZ2VudCddXG4gICAgICAgIC8vIOiOt+WPluWuouaIt+err+eahElQ5Zyw5Z2A5L+h5oGvXG4gICAgICAgIGdsb2JhbFsnX19jbGllbnRfaXBfXyddID0gZXZ0WydoZWFkZXJzJ11bJ1gtUmVhbC1JUCddXG5cbiAgICAgICAgLy8gVE9ETyBXRULor7fmsYLpnIDopoHlr7k0MDTpobXpnaLku6Xlj4pFUlJPUumhtemdoui/m+ihjOWFvOWuueWkhOeQhu+8iOWcqGZyYW1ld29ya+WGhemDqOi/m+ihjOe7huiKgueahOmUmeivr+WIpOaWreWcqG91dOS4remAj+S8oHN0YXR1c+eahGh0dHDnmoTnirbmgIHlkJfmraPnoa7plJnor6/ov5Tlm57vvIlcbiAgICAgICAgLy8gNDA0XHROb3QgRm91bmQg5pyN5Yqh5Zmo5peg5rOV5qC55o2u5a6i5oi356uv55qE6K+35rGC5om+5Yiw6LWE5rqQ77yI572R6aG177yJ44CC6YCa6L+H5q2k5Luj56CB77yM572R56uZ6K6+6K6h5Lq65ZGY5Y+v6K6+572uXCLmgqjmiYDor7fmsYLnmoTotYTmupDml6Dms5Xmib7liLBcIueahOS4quaAp+mhtemdolxuICAgICAgICAvLyA0MDNcdEZvcmJpZGRlblx05pyN5Yqh5Zmo55CG6Kej6K+35rGC5a6i5oi356uv55qE6K+35rGC77yM5L2G5piv5ouS57ud5omn6KGM5q2k6K+35rGC77yI5p2D6ZmQ6aqM6K+B5aSE55CG6ZSZ6K+v77yJXG4gICAgICAgIG91dCA9IGF3YWl0IHJlcXVlc3RfcHJvY2VzcyhfX2FwaV9fLCBwYXJhbSlcblxuICAgICAgICAvLyDlpITnkIZyZXNwb25zZeeahGNvb2tpZXPorr7nva5cbiAgICAgICAgbGV0IHNldENvb2tpZSA9IHsnU2V0LUNvb2tpZSc6IHVuZGVmaW5lZH1cbiAgICAgICAgaWYgKCFfLmlzRW1wdHkoZ2xvYmFsWydfX3Jlc3BvbmRfY29va2llc19fJ10pKSB7XG4gICAgICAgICAgICBzZXRDb29raWVbJ1NldC1Db29raWUnXSA9IF8udmFsdWVzKGdsb2JhbFsnX19yZXNwb25kX2Nvb2tpZXNfXyddKVxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGdsb2JhbFsnX19yZWRpcmVjdF91cmxfXyddKSB7XG4gICAgICAgICAgICBjYWxsYmFjayhudWxsLCB7XG4gICAgICAgICAgICAgICAgc3RhdHVzQ29kZTogMzAyLFxuICAgICAgICAgICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICAgICAgICAgICAgXCJMb2NhdGlvblwiOiBnbG9iYWxbJ19fcmVkaXJlY3RfdXJsX18nXSxcbiAgICAgICAgICAgICAgICAgICAgLi4uc2V0Q29va2llXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICBnbG9iYWxbJ19fcmVkaXJlY3RfdXJsX18nXSA9IHVuZGVmaW5lZFxuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKF8uaXNTdHJpbmcob3V0KSkge1xuICAgICAgICAgICAgbGV0IGh0bWxSZXNwb25zZSA9IHtcbiAgICAgICAgICAgICAgICBpc0Jhc2U2NEVuY29kZWQ6IHRydWUsXG4gICAgICAgICAgICAgICAgc3RhdHVzQ29kZTogMjAwLFxuICAgICAgICAgICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICAgICAgICAgICAgXCJDb250ZW50LXR5cGVcIjogXCJ0ZXh0L2h0bWw7IGNoYXJzZXQ9dXRmLThcIixcbiAgICAgICAgICAgICAgICAgICAgLi4uc2V0Q29va2llLFxuICAgICAgICAgICAgICAgICAgICAuLi5fX2NvcnNfXyxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIC8vIGJhc2U2NCBlbmNvZGUgYm9keSBzbyBpdCBjYW4gYmUgc2FmZWx5IHJldHVybmVkIGFzIEpTT04gdmFsdWVcbiAgICAgICAgICAgICAgICBib2R5OiBuZXcgQnVmZmVyKG91dCBhcyBzdHJpbmcpLnRvU3RyaW5nKCdiYXNlNjQnKVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY2FsbGJhY2sobnVsbCwgaHRtbFJlc3BvbnNlKVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgbGV0IGpzb25SZXNwb25zZSA9IHtcbiAgICAgICAgICAgICAgICBpc0Jhc2U2NEVuY29kZWQ6IHRydWUsXG4gICAgICAgICAgICAgICAgc3RhdHVzQ29kZTogMjAwLFxuICAgICAgICAgICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICAgICAgICAgICAgXCJDb250ZW50LXR5cGVcIjogXCJhcHBsaWNhdGlvbi9qc29uXCIsXG4gICAgICAgICAgICAgICAgICAgIC4uLl9fY29yc19fLFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgLy8gYmFzZTY0IGVuY29kZSBib2R5IHNvIGl0IGNhbiBiZSBzYWZlbHkgcmV0dXJuZWQgYXMgSlNPTiB2YWx1ZVxuICAgICAgICAgICAgICAgIGJvZHk6IG5ldyBCdWZmZXIoSlNPTi5zdHJpbmdpZnkob3V0KSkudG9TdHJpbmcoJ2Jhc2U2NCcpXG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjYWxsYmFjayhudWxsLCBqc29uUmVzcG9uc2UpXG4gICAgICAgIH1cbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgLy8g6YCa55+l5qGG5p626Ieq6Lqr5a6e546w6YC76L6R55qE5oSP5aSW5oql6ZSZ77yI5qGG5p626Ieq6Lqr5LiN6K665L2V56eN5oOF5Ya16YO95bqU6K+l5q2j5bi45bel5L2c77yM5LiA5pem5Ye6546w5q2k6Zeu6aKY5aSn5aSa5pWw5oOF5Ya15piv5qGG5p626Ieq6Lqr6Zeu6aKY5oiW6ICF5rWB6YeP5byV5Y+R55qE6L+Q57u06Zeu6aKY77yJXG4gICAgICAgIGF3YWl0IHh3YXJuKHtcbiAgICAgICAgICAgIF9fYXBpX18sIF9fdXJsX18sIHBhcmFtLCBtZXNzYWdlOiBlcnIubWVzc2FnZSwgc3RhY2s6IHhzdGFjayhlcnIpXG4gICAgICAgIH0pXG4gICAgICAgIC8vIDUwMFx0SW50ZXJuYWwgU2VydmVyIEVycm9yXHTmnI3liqHlmajlhoXpg6jplJnor6/vvIzml6Dms5XlrozmiJDor7fmsYJcbiAgICAgICAgY2FsbGJhY2sobnVsbCwge3N0YXR1c0NvZGU6IDUwNX0pXG4gICAgfVxufVxuXG4vLyAgQVBJ5Y+C5pWw55qE6K+G5Yir6YC76L6R77yM5Li65pmu6YCa5a2X56ym5Liy6Lev5b6E5a6a5LmJ5LiOYXBw5LiL55qEdHPmlofku7bot6/nlLHlrozlhajkuIDkuIDlr7nlupTvvIzkvJjlhYjlj5ZIRUFERVLkuK3nmoTlrprkuYnvvIzlho3lj5ZHRVTkuK3nmoTlvaLlj4LlrprkuYnmiJbogIVQT1NU5b2i5Y+C5a6a5LmJ6L+b6KGM5Y+C5pWw6K+35rGC55qE6KaG55uW5aSE55CG44CCXG4vLyAgUEFSQU3or7fmsYLnmoTlj4LmlbDlpITnkIbopoHmsYLkuLpCQVNFNjTnvJbnoIHljJbnmoRKU09O5a2X56ym5Liy44CCXG4vLyAgICAgXCJldmVudFwiOiB7XG4vLyAgICAgICAgIFwiYm9keVwiOiBcImV3b0pJbUZ3YVNJNklDSXZZUzlpTDJNaUxBb0pJbkJoY21GdElqb2dJbUZ6WkdaaGMyUm1ZWE5rWmlJS2ZRPT1cIiwgPT4g5a+55bqU5LqOUE9TVOivt+axguaVsOaNrlxuLy8gICAgICAgICBcImhlYWRlcnNcIjoge1xuLy8gICAgICAgICAgICAgXCJYLUNhLUFwaS1HYXRld2F5XCI6IFwiQjI1Q0Q1MUItNTgxNS00Nzc1LTlFQUItNkQ0ODFCQzFBRTE3XCIsXG4vLyAgICAgICAgICAgICBcIl9fYXBpX19cIjogXCIvd2ViL21vYmlsZS90ZXN0XCIsICAgPeOAiyDoh6rlrprkuYnovazkuYlQQVRI55qE6Lev5b6E5L+h5oGv5a+55LqOU0VP5LyY5YyW5YW85a655aSE55CG77yI5Lmf5Y+v5Lul5ZyoR0VU5oiWUE9TVOivt+axguS4reS8oOmAkuWvueW6lOWPguaVsO+8iVxuLy8gICAgICAgICAgICAgXCJYLUZvcndhcmRlZC1Gb3JcIjogXCI0Mi4xMjAuNzQuODhcIixcbi8vICAgICAgICAgICAgIFwiQ29udGVudC1UeXBlXCI6IFwiYXBwbGljYXRpb24vanNvblwiXG4vLyAgICAgICAgIH0sXG4vLyAgICAgICAgIFwiaHR0cE1ldGhvZFwiOiBcIlBPU1RcIixcbi8vICAgICAgICAgXCJpc0Jhc2U2NEVuY29kZWRcIjogdHJ1ZSxcbi8vICAgICAgICAgXCJwYXRoXCI6IFwiL1wiLCA944CLIOayoeacieaEj+S5ieeUqOS6juWJjeerr+agueaNrumcgOimgeiHquW3sei/m+ihjOaJqeWxleWIq+WQjeaYoOWwhOWkhOeQhu+8jOWQjuerr+eahOaOp+WItuWZqOS4jeS7peatpOS4uuagh+WHhu+8jOWPr+S7peWvueWQjOS4gOS4quaOp+WItuWZqOWumuS5iU7kuKrkuI3lkIznmoTot6/lvoTmoIfor4bjgIJcbi8vICAgICAgICAgXCJwYXRoUGFyYW1ldGVyc1wiOiB7fSxcbi8vICAgICAgICAgXCJxdWVyeVBhcmFtZXRlcnNcIjoge30gPT4g5a+55bqU5LqOR0VU6K+35rGC5pWw5o2uXG4vLyAgICAgfSxcbi8vICAgICBcInF1ZXJ5XCI6IHt9LFxuLy8gICAgIFwiY29udGV4dFwiOiB7XG4vLyAgICAgICAgIFwicmVxdWVzdElkXCI6IFwiQjI1Q0Q1MUItNTgxNS00Nzc1LTlFQUItNkQ0ODFCQzFBRTE3XCIsXG4vLyAgICAgICAgIFwiY3JlZGVudGlhbHNcIjoge1xuLy8gICAgICAgICAgICAgXCJhY2Nlc3NLZXlJZFwiOiBcIlwiLFxuLy8gICAgICAgICAgICAgXCJhY2Nlc3NLZXlTZWNyZXRcIjogXCJcIixcbi8vICAgICAgICAgICAgIFwic2VjdXJpdHlUb2tlblwiOiBcIlwiXG4vLyAgICAgICAgIH0sXG4vLyAgICAgICAgIFwiZnVuY3Rpb25cIjoge1xuLy8gICAgICAgICAgICAgXCJuYW1lXCI6IFwidGVzdFwiLFxuLy8gICAgICAgICAgICAgXCJoYW5kbGVyXCI6IFwiaW5kZXguaGFuZGxlclwiLFxuLy8gICAgICAgICAgICAgXCJtZW1vcnlcIjogMTI4LFxuLy8gICAgICAgICAgICAgXCJ0aW1lb3V0XCI6IDMwMFxuLy8gICAgICAgICB9LFxuLy8gICAgICAgICBcInNlcnZpY2VzXCI6IHtcbi8vICAgICAgICAgICAgIFwibmFtZVwiOiBcImFsaWxhbmdcIixcbi8vICAgICAgICAgICAgIFwibG9nUHJvamVjdFwiOiBcIlwiLFxuLy8gICAgICAgICAgICAgXCJsb2dTdG9yZVwiOiBcIlwiXG4vLyAgICAgICAgIH0sXG4vLyAgICAgICAgIFwicmVnaW9uXCI6IFwiY24tc2hhbmdoYWlcIixcbi8vICAgICAgICAgXCJhY2NvdW50SWRcIjogXCIxNzM0MDY2MDU3Njg5NTI4XCJcbi8vICAgICB9XG4vLyB9XG5cbi8vIOacgOaWsOeJiOacrGV2ZW5055qEQVBJ572R5YWz55qERkPov5Tlm57mlbDmja7moLzlvI/vvJpcbi8vICAgICAgQ0EtSG9zdOivt+axguWfn+WQjeOAgVxuLy8gICAgICBYLUZvcndhcmRlZC1Qcm90b1xuLy8gICAgICBcInBhdGhcIjogXCIvdGVzdFwiLCA9PeOAi+OAi+WfuuacrOS4iuWPr+S7peaLvOaOpeWHul9fdXJsX1/lj4LmlbDlj6/ku6XnnIHnlaXmjonmraTlhpfkvZnlj4LmlbDphY3nva7kuobjgIJcbi8vICAgICAgICAgICAgICAgICAgICAgICA9PeOAi+OAi+WAn+WKqXJvdXRlLm1hcC50c+aWh+S7tueahOaYoOWwhOWFs+ezu+WumuS5ieecgeeVpeaOiV9fYXBpX1/phY3nva7ov5vkuIDmraXnroDljJbnvZHlhbPlupTnlKjjgIJcbi8vICAgICAgXCJodHRwTWV0aG9kXCI6IFwiR0VUXCIsXG4vLyAgICAgIFwiaXNCYXNlNjRFbmNvZGVkXCI6IHRydWUsXG4vLyAgICAgIFwiWC1Gb3J3YXJkZWQtRm9yXCI6IFwiNDIuMTIwLjc0LjEwM1wiLCAvLyDlrqLmiLfnq6/or7fmsYJJUOWcsOWdgOeUqOaIt+WIpOWumuaJgOWxnuWMuuWfn+S/oeaBr+a1t+Wkluiuv+mXrumXrumimOS8mOWMluS+nei1lueCuVxuLy8gICAgICBcIlgtUmVhbC1JUFwiOiBcIjQyLjEyMC43NC4xMDNcIixcbi8vICAgICAgQ29va2llXG4vLyAgICAgIFVzZXItQWdlbnQgICAgICAgPT4+IFBD56uZ5ZKMTeermeiHqumAguW6lOmXrumimFxuLy8gICAgICBBY2NlcHQtTGFuZ3VhZ2UgID0+PiDmtY/op4jlmajlrqLmiLfnq6/nmoTor63oqIDnsbvlnovoh6rliqjpgILphY3lpJror63oqIDmnrbmnoTorr7orqHpl67pophcbi8vIGxldCB4ID0ge1xuLy8gICAgIFwiYm9keVwiOiBcIlwiLFxuLy8gICAgIFwiaGVhZGVyc1wiOiB7XG4vLyAgICAgICAgIFwiWC1DYS1BcGktR2F0ZXdheVwiOiBcIkIyNzZGNzdCLTMzNEUtNDg1Ny1BRTY0LTY1QkFGRDQxOUUyQVwiLFxuLy8gICAgICAgICBcIkNvb2tpZVwiOiBcImNuYT1yNXNuRXp6T3ZBMENBU3A0U21kcStJSS87IFVNX2Rpc3RpbmN0aWQ9MTYyYmNkNjFkOTExMWNkLTA4MGUwZjQzZTZiNjBkLTMzNjk3YjA0LTEzYzY4MC0xNjJiY2Q2MWQ5MmM4NjsgX3RiX3Rva2VuXz1IOFU3QnFpeEYzWVZSM0duaE1SejsgTkVXMl9BQ1JfSlNFU1NJT05JRD1WTTU2NkY5MS1LNUNQOFFJVk1RVFNBSDNDNEg1WDEtRFJJSFlKSEotUUUyOyBfbmV3X2NyX3Nlc3Npb24wPTFBYkxCeU9NSGVaZTNHNDFLWWQ1V2NQZEMlMkZpOHF2R0hVQlRLOEZicmZ4OFNvaSUyQkhFTHV4eEE2anJvczdXJTJGcUMxWXRlYmdCM2F1RUY1bHUxU0N6VXpUa3Q2diUyRmlGZU4lMkZwdGJ2QlJ6aVlFR1hTRVZoV25VbEJSMnRmcGpyWE1uSWNmYjIlMkZ3bkdrSDR2a2VNSUoxQnZ1dyUzRCUzRDsgZW1wbElkPTE0OTMzNzsgaHJjX3NpZGViYXI9b3BlbjsgdHJhY2VJZD03ZDRiMTZkZS03NGJjLTRlYWMtODg0Yi01NGNhMDM1NGU0YWE7IFNTT19MQU5HPVpILUNOOyBTU09fRU1QSURfSEFTSD05ZGIxZWQyMTQwMmY3YzM2Njc0YjVlNmU2ZGUxZmM2ODsgYW5pbWF0ZV9kYXRlPTIwMTg2NDsgYWE9eHh4eHh4eDsgY25fMTI2MDAwMTIyMV9kcGx1cz0lN0IlMjJkaXN0aW5jdF9pZCUyMiUzQSUyMCUyMjE2MmJjZDYxZDkxMTFjZC0wODBlMGY0M2U2YjYwZC0zMzY5N2IwNC0xM2M2ODAtMTYyYmNkNjFkOTJjODYlMjIlMkMlMjJzcCUyMiUzQSUyMCU3QiUyMiUyNF9zZXNzaW9uaWQlMjIlM0ElMjAwJTJDJTIyJTI0X3Nlc3Npb25UaW1lJTIyJTNBJTIwMTUyODA4NjIzNCUyQyUyMiUyNGRwJTIyJTNBJTIwMCUyQyUyMiUyNF9zZXNzaW9uUFZUaW1lJTIyJTNBJTIwMTUyODA4NjIzNCU3RCU3RDsgaXNnPUJEdzhTb255Uzl1dHluNWZlZFlSZS11UkRkendOQUQwLTUxQkhoYTlfU2NKNGR4ck5rV3c3N0tReFFtWnFSaTNcIixcbi8vICAgICAgICAgXCJYLUZvcndhcmRlZC1Qcm90b1wiOiBcImh0dHBzXCIsXG4vLyAgICAgICAgIFwiVXNlci1BZ2VudFwiOiBcIk1vemlsbGEvNS4wIChNYWNpbnRvc2g7IEludGVsIE1hYyBPUyBYIDEwXzEyXzYpIEFwcGxlV2ViS2l0LzUzNy4zNiAoS0hUTUwsIGxpa2UgR2Vja28pIENocm9tZS82Ni4wLjMzNTkuMTgxIFNhZmFyaS81MzcuMzZcIixcbi8vICAgICAgICAgXCJfX3VybF9fXCI6IFwiaHR0cHM6Ly90b3VmYW5nLmFsaWJhYmEtaW5jLmNvbS90ZXN0XCIsXG4vLyAgICAgICAgIFwiQ0EtSG9zdFwiOiBcInRvdWZhbmcuYWxpYmFiYS1pbmMuY29tXCIsXG4vLyAgICAgICAgIFwiQ2FjaGUtQ29udHJvbFwiOiBcIm1heC1hZ2U9MFwiLFxuLy8gICAgICAgICBcInVwZ3JhZGUtaW5zZWN1cmUtcmVxdWVzdHNcIjogXCIxXCIsXG4vLyAgICAgICAgIFwiQWNjZXB0LUxhbmd1YWdlXCI6IFwiemgtQ04semg7cT0wLjlcIixcbi8vICAgICAgICAgXCJfX2FwaV9fXCI6IFwiL3dlYi90ZXN0L3Rlc3RcIixcbi8vICAgICAgICAgXCJBY2NlcHQtRW5jb2RpbmdcIjogXCJnemlwLCBkZWZsYXRlLCBiclwiLFxuLy8gICAgICAgICBcIlgtRm9yd2FyZGVkLUZvclwiOiBcIjQyLjEyMC43NC4xMDNcIixcbi8vICAgICAgICAgXCJYLVJlYWwtSVBcIjogXCI0Mi4xMjAuNzQuMTAzXCIsXG4vLyAgICAgICAgIFwiQWNjZXB0XCI6IFwidGV4dC9odG1sLGFwcGxpY2F0aW9uL3hodG1sK3htbCxhcHBsaWNhdGlvbi94bWw7cT0wLjksaW1hZ2Uvd2VicCxpbWFnZS9hcG5nLCovKjtxPTAuOFwiXG4vLyAgICAgfSxcbi8vICAgICBcImh0dHBNZXRob2RcIjogXCJHRVRcIixcbi8vICAgICBcImlzQmFzZTY0RW5jb2RlZFwiOiB0cnVlLFxuLy8gICAgIFwicGF0aFwiOiBcIi90ZXN0XCIsXG4vLyAgICAgXCJwYXRoUGFyYW1ldGVyc1wiOiB7fSxcbi8vICAgICBcInF1ZXJ5UGFyYW1ldGVyc1wiOiB7fVxuLy8gfVxuIl19
\No newline at end of file