UNPKG

49.7 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 evt = JSON.parse(event.toString());
76 // 根据API网关设置的环境常量参数正确配置线上版本的运行环境,取代AONE的本地、日常、预发、灰度等环境部署支持开发。
77 // 全局变量仅仅用于放在整个应用生命周期变量
78 global['__env__'] = _.get(evt, 'headers.__env__', 'prod');
79 __cors__ = {};
80 if (global['__env__'] !== 'prod' && global['__env__'] !== 'gray') {
81 // 非生产环境或灰度环境,需要禁用CORS功能禁止跨域访问增加安全性。
82 if (evt.headers.origin) {
83 // 获取源站动态允许请求跨域 (FIXME 需要进行安全限制对来源服务器网址合法性进行安全限制,本地开发调试全部放开请求)
84 __cors__['Access-Control-Allow-Origin'] = evt.headers.origin;
85 // __cors__['Access-Control-Allow-Origin'] = '*' // 不能设置为任意值浏览器有安全限制
86 }
87 __cors__['Access-Control-Allow-Credentials'] = 'true';
88 __cors__['Access-Control-Allow-Headers'] = 'Origin, X-Requested-With, Content-Type, Accept';
89 __cors__['Access-Control-Allow-Methods'] = 'POST, OPTIONS';
90 }
91 // 支持跨域的验证请求方法的合法性规避掉过滤掉不安全的请求。
92 switch (evt.httpMethod) {
93 case 'GET':
94 case 'POST':
95 break;
96 case 'OPTIONS':
97 if (global['__env__'] == 'prod' || global['__env__'] == 'gray') {
98 // 生产和灰度环境下禁止跨域OPTIONS请求以便于增强安全性
99 callback(null, {
100 statusCode: 501,
101 });
102 }
103 else {
104 // 非生产和灰度环境下才允许支持跨域OPTIONS请求
105 callback(null, {
106 statusCode: 200,
107 headers: __assign({}, __cors__),
108 });
109 }
110 return [2 /*return*/];
111 default:
112 // 禁止任何的非法请求严格进行约定限制
113 callback(null, {
114 statusCode: 502,
115 });
116 return [2 /*return*/];
117 }
118 if (!evt['triggerName']) return [3 /*break*/, 6];
119 _a = evt['triggerName'];
120 switch (_a) {
121 case '__axjs-preheat-timer__': return [3 /*break*/, 1];
122 }
123 return [3 /*break*/, 5];
124 case 1:
125 _c.trys.push([1, 3, , 4]);
126 payload = JSON.parse(evt['payload']);
127 xassert(payload['url'] && payload['timeout']);
128 return [4 /*yield*/, xpost(payload['url'], payload['param'], undefined, payload['timeout'])];
129 case 2:
130 _c.sent();
131 return [3 /*break*/, 4];
132 case 3:
133 err_1 = _c.sent();
134 // ignore error
135 xlog(JSON.stringify(xerror(err_1)).replace(/\r/g, '').replace(/\n/g, ''));
136 return [3 /*break*/, 4];
137 case 4: return [3 /*break*/, 5];
138 case 5: return [2 /*return*/];
139 case 6:
140 if (evt['path'] === '/__axjs-preheat-timer__') {
141 // 预热api网关的空请求心跳接口实现
142 return [2 /*return*/];
143 }
144 _c.label = 7;
145 case 7:
146 global['__evt__'] = event.toString(); // FIXME 需要设计上下文定义请求实例生命周期变量
147 __api__ = _.get(evt, 'headers.__api__', evt.path) // 最终控制器与app子目录下的ts文件保持完全的一一映射关系。
148 ;
149 __url__ = evt['headers']['X-Forwarded-Proto'] + '://' + evt['headers']['CA-Host'] + evt['path'];
150 __header__ = evt['headers'];
151 param = Object.assign({ __api__: __api__, __url__: __url__, __header__: __header__ }, // header请求中的两个框架层面上的预定义参数 TODO 需要移除掉并非应用关心的内容
152 evt.pathParameters || {}, // 路由重写参数 domain/[a]/[b]?xxx (可被GET参数覆盖)
153 evt.queryParameters || {} // GET请求参数 domain/path?a=x&b=x
154 );
155 out = {};
156 _b = evt.httpMethod;
157 switch (_b) {
158 case 'GET': return [3 /*break*/, 8];
159 case 'POST': return [3 /*break*/, 9];
160 }
161 return [3 /*break*/, 13];
162 case 8: return [3 /*break*/, 14];
163 case 9:
164 _c.trys.push([9, 10, , 12]);
165 post = {};
166 if (_.isString(evt.body)) {
167 body = evt.body;
168 if (evt.isBase64Encoded) {
169 body = new Buffer(evt.body, 'base64').toString();
170 }
171 post = init_1.parse_post_param(evt['headers'], body);
172 }
173 param = Object.assign(param, post); // 用post参数覆盖掉get参数,用于灵活的设置请求参数兼容get和post两种方法方便开发调试。
174 return [3 /*break*/, 12];
175 case 10:
176 err_2 = _c.sent();
177 xlog(err_2, evt.httpMethod, evt.body);
178 return [4 /*yield*/, xwarn(err_2)
179 // 400 Bad Request 客户端请求的语法错误,服务器无法理解
180 ];
181 case 11:
182 _c.sent();
183 // 400 Bad Request 客户端请求的语法错误,服务器无法理解
184 callback(null, {
185 statusCode: 503,
186 });
187 return [2 /*return*/];
188 case 12: return [3 /*break*/, 14];
189 case 13:
190 xlog(evt.httpMethod, evt.body);
191 // 400 Bad Request 客户端请求的语法错误,服务器无法理解
192 callback(null, {
193 statusCode: 504,
194 });
195 return [2 /*return*/];
196 case 14:
197 _c.trys.push([14, 16, , 18]);
198 cookie = _.get(evt['headers'], 'Cookie', undefined);
199 if (!cookie) {
200 cookie = _.get(evt['headers'], 'cookie', '');
201 }
202 global['__request_cookies__'] = require('cookie').parse(cookie);
203 // 获取use-agent请求头部信息
204 global['__user_agent__'] = evt['headers']['User-Agent'];
205 // 获取客户端的IP地址信息
206 global['__client_ip__'] = evt['headers']['X-Real-IP'];
207 return [4 /*yield*/, init_1.request_process(__api__, param)
208 // 处理response的cookies设置
209 ];
210 case 15:
211 // TODO WEB请求需要对404页面以及ERROR页面进行兼容处理(在framework内部进行细节的错误判断在out中透传status的http的状态吗正确错误返回)
212 // 404 Not Found 服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置"您所请求的资源无法找到"的个性页面
213 // 403 Forbidden 服务器理解请求客户端的请求,但是拒绝执行此请求(权限验证处理错误)
214 out = _c.sent();
215 setCookie = { 'Set-Cookie': undefined };
216 if (!_.isEmpty(global['__respond_cookies__'])) {
217 setCookie['Set-Cookie'] = _.values(global['__respond_cookies__']);
218 }
219 if (global['__redirect_url__']) {
220 callback(null, {
221 statusCode: 302,
222 headers: __assign({ "Location": global['__redirect_url__'] }, setCookie),
223 });
224 global['__redirect_url__'] = undefined;
225 }
226 else if (_.isString(out)) {
227 htmlResponse = {
228 isBase64Encoded: true,
229 statusCode: 200,
230 headers: __assign({ "Content-type": "text/html; charset=utf-8" }, setCookie, __cors__),
231 // base64 encode body so it can be safely returned as JSON value
232 body: new Buffer(out).toString('base64')
233 };
234 callback(null, htmlResponse);
235 }
236 else {
237 jsonResponse = {
238 isBase64Encoded: true,
239 statusCode: 200,
240 headers: __assign({ "Content-type": "application/json" }, __cors__),
241 // base64 encode body so it can be safely returned as JSON value
242 body: new Buffer(JSON.stringify(out)).toString('base64')
243 };
244 callback(null, jsonResponse);
245 }
246 return [3 /*break*/, 18];
247 case 16:
248 err_3 = _c.sent();
249 // 通知框架自身实现逻辑的意外报错(框架自身不论何种情况都应该正常工作,一旦出现此问题大多数情况是框架自身问题或者流量引发的运维问题)
250 return [4 /*yield*/, xwarn({
251 __api__: __api__, __url__: __url__, param: param, message: err_3.message, stack: xstack(err_3)
252 })
253 // 500 Internal Server Error 服务器内部错误,无法完成请求
254 ];
255 case 17:
256 // 通知框架自身实现逻辑的意外报错(框架自身不论何种情况都应该正常工作,一旦出现此问题大多数情况是框架自身问题或者流量引发的运维问题)
257 _c.sent();
258 // 500 Internal Server Error 服务器内部错误,无法完成请求
259 callback(null, { statusCode: 505 });
260 return [3 /*break*/, 18];
261 case 18: return [2 /*return*/];
262 }
263 });
264 });
265};
266// API参数的识别逻辑,为普通字符串路径定义与app下的ts文件路由完全一一对应,优先取HEADER中的定义,再取GET中的形参定义或者POST形参定义进行参数请求的覆盖处理。
267// PARAM请求的参数处理要求为BASE64编码化的JSON字符串。
268// "event": {
269// "body": "ewoJImFwaSI6ICIvYS9iL2MiLAoJInBhcmFtIjogImFzZGZhc2RmYXNkZiIKfQ==", => 对应于POST请求数据
270// "headers": {
271// "X-Ca-Api-Gateway": "B25CD51B-5815-4775-9EAB-6D481BC1AE17",
272// "__api__": "/web/mobile/test", =》 自定义转义PATH的路径信息对于SEO优化兼容处理(也可以在GET或POST请求中传递对应参数)
273// "X-Forwarded-For": "42.120.74.88",
274// "Content-Type": "application/json"
275// },
276// "httpMethod": "POST",
277// "isBase64Encoded": true,
278// "path": "/", =》 没有意义用于前端根据需要自己进行扩展别名映射处理,后端的控制器不以此为标准,可以对同一个控制器定义N个不同的路径标识。
279// "pathParameters": {},
280// "queryParameters": {} => 对应于GET请求数据
281// },
282// "query": {},
283// "context": {
284// "requestId": "B25CD51B-5815-4775-9EAB-6D481BC1AE17",
285// "credentials": {
286// "accessKeyId": "",
287// "accessKeySecret": "",
288// "securityToken": ""
289// },
290// "function": {
291// "name": "test",
292// "handler": "index.handler",
293// "memory": 128,
294// "timeout": 300
295// },
296// "services": {
297// "name": "alilang",
298// "logProject": "",
299// "logStore": ""
300// },
301// "region": "cn-shanghai",
302// "accountId": "1734066057689528"
303// }
304// }
305// 最新版本event的API网关的FC返回数据格式:
306// CA-Host请求域名、
307// X-Forwarded-Proto
308// "path": "/test", ==》》基本上可以拼接出__url__参数可以省略掉此冗余参数配置了。
309// ==》》借助route.map.ts文件的映射关系定义省略掉__api__配置进一步简化网关应用。
310// "httpMethod": "GET",
311// "isBase64Encoded": true,
312// "X-Forwarded-For": "42.120.74.103", // 客户端请求IP地址用户判定所属区域信息海外访问问题优化依赖点
313// "X-Real-IP": "42.120.74.103",
314// Cookie
315// User-Agent =>> PC站和M站自适应问题
316// Accept-Language =>> 浏览器客户端的语言类型自动适配多语言架构设计问题
317// let x = {
318// "body": "",
319// "headers": {
320// "X-Ca-Api-Gateway": "B276F77B-334E-4857-AE64-65BAFD419E2A",
321// "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",
322// "X-Forwarded-Proto": "https",
323// "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",
324// "__url__": "https://toufang.alibaba-inc.com/test",
325// "CA-Host": "toufang.alibaba-inc.com",
326// "Cache-Control": "max-age=0",
327// "upgrade-insecure-requests": "1",
328// "Accept-Language": "zh-CN,zh;q=0.9",
329// "__api__": "/web/test/test",
330// "Accept-Encoding": "gzip, deflate, br",
331// "X-Forwarded-For": "42.120.74.103",
332// "X-Real-IP": "42.120.74.103",
333// "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8"
334// },
335// "httpMethod": "GET",
336// "isBase64Encoded": true,
337// "path": "/test",
338// "pathParameters": {},
339// "queryParameters": {}
340// }
341//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguYmFrLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiaW5kZXguYmFrLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLE9BQU8sQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDLE9BQU8sRUFBRSxDQUFBO0FBQ3ZDLE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDLFFBQVEsRUFBRSxDQUFBO0FBQ3BDLCtCQUF3RDtBQUV4RCxJQUFNLENBQUMsR0FBRyxPQUFPLENBQUMsUUFBUSxDQUFDLENBQUE7QUFFM0IsZ0JBQWdCO0FBQ2hCLG9HQUFvRztBQUNwRyxnRUFBZ0U7QUFDaEUsK0RBQStEO0FBQy9ELDhDQUE4QztBQUM5QyxtREFBbUQ7QUFDbkQsbURBQW1EO0FBQ25ELDJCQUEyQjtBQUMzQixpQ0FBaUM7QUFDakMsMkJBQTJCO0FBQzNCLHFCQUFxQjtBQUNyQiwwREFBMEQ7QUFDMUQsYUFBYTtBQUNiLDJFQUEyRTtBQUMzRSw2REFBNkQ7QUFDN0QsUUFBUTtBQUNSLG1DQUFtQztBQUNuQyxJQUFJO0FBRUosc0JBQXNCO0FBQ3RCLE9BQU8sQ0FBQyxPQUFPLEdBQUcsVUFBZ0IsS0FBSyxFQUFFLE9BQU8sRUFBRSxRQUFROzs7Ozs7b0JBTWxELEdBQUcsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFBO29CQUV0Qyw2REFBNkQ7b0JBQzdELHVCQUF1QjtvQkFDdkIsTUFBTSxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sQ0FBQyxDQUFBO29CQUVuRCxRQUFRLEdBQUcsRUFBRSxDQUFBO29CQUNuQixJQUFJLE1BQU0sQ0FBQyxTQUFTLENBQUMsS0FBSyxNQUFNLElBQUksTUFBTSxDQUFDLFNBQVMsQ0FBQyxLQUFLLE1BQU0sRUFBRTt3QkFDOUQs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NkVBQTZFO0FBQzdFLHFDQUFxQztBQUNyQyxjQUFjO0FBQ2Qsd0NBQXdDO0FBQ3hDLHFEQUFxRDtBQUNyRCxZQUFZO0FBQ1osa0JBQWtCO0FBQ2xCLG1CQUFtQjtBQUNuQixzRUFBc0U7QUFDdEUsbTZCQUFtNkI7QUFDbjZCLHdDQUF3QztBQUN4QyxxSkFBcUo7QUFDckosNkRBQTZEO0FBQzdELGdEQUFnRDtBQUNoRCx3Q0FBd0M7QUFDeEMsNENBQTRDO0FBQzVDLCtDQUErQztBQUMvQyx1Q0FBdUM7QUFDdkMsa0RBQWtEO0FBQ2xELDhDQUE4QztBQUM5Qyx3Q0FBd0M7QUFDeEMsNEdBQTRHO0FBQzVHLFNBQVM7QUFDVCwyQkFBMkI7QUFDM0IsK0JBQStCO0FBQy9CLHVCQUF1QjtBQUN2Qiw0QkFBNEI7QUFDNUIsNEJBQTRCO0FBQzVCLElBQUkiLCJzb3VyY2VzQ29udGVudCI6WyJyZXF1aXJlKCdzb3VyY2UtbWFwLXN1cHBvcnQnKS5pbnN0YWxsKClcbnJlcXVpcmUoJ3RzY29uZmlnLXBhdGhzJykucmVnaXN0ZXIoKVxuaW1wb3J0IHtyZXF1ZXN0X3Byb2Nlc3MsIHBhcnNlX3Bvc3RfcGFyYW19IGZyb20gJy4vaW5pdCdcblxuY29uc3QgXyA9IHJlcXVpcmUoJ2xvZGFzaCcpXG5cbi8vIC8vIOS4tOaXtuiwg+ivlee6v+S4iuaXpeW/l+aJk+WNsFxuLy8gLy9mcmFtZXdvcmsvaW5kZXgudHMoOCwxMyk6IGVycm9yIFRTMjMzOTogUHJvcGVydHkgJ3NldExvZ0xldmVsJyBkb2VzIG5vdCBleGlzdCBvbiB0eXBlICdDb25zb2xlJ1xuLy8gZXhwb3J0cy5oYW5kbGVyID0gYXN5bmMgZnVuY3Rpb24gKGV2ZW50LCBjb250ZXh0LCBjYWxsYmFjaykge1xuLy8gICAgIC8vIGNvbnNvbGUuc2V0TG9nTGV2ZWwoJ2Vycm9yJykg5LiN6IO95YaZ5Zyo5q2k5Lya5a+86Ie057yW6K+R6ZSZ6K+v6Zi/6YeM5LqR6Ieq5bex5omp5bGV55qE56eB5pyJ5pa55rOVXG4vLyAgICAgY29uc29sZS5sb2coJ3h4eHh4JywgJ3l5eXl5JywgJ3p6enp6eicpXG4vLyAgICAgY29uc29sZS5lcnJvcigneHh4eHgxJywgJ3l5eXl5MScsICd6enp6enoxJylcbi8vICAgICBsZXQgb3V0ID0gJzxodG1sPjxib2R5Pnp6enp6ejwvYm9keT48L2h0bWw+J1xuLy8gICAgIGxldCBodG1sUmVzcG9uc2UgPSB7XG4vLyAgICAgICAgIGlzQmFzZTY0RW5jb2RlZDogdHJ1ZSxcbi8vICAgICAgICAgc3RhdHVzQ29kZTogMjAwLFxuLy8gICAgICAgICBoZWFkZXJzOiB7XG4vLyAgICAgICAgICAgICBcIkNvbnRlbnQtdHlwZVwiOiBcInRleHQvaHRtbDsgY2hhcnNldD11dGYtOFwiLFxuLy8gICAgICAgICB9LFxuLy8gICAgICAgICAvLyBiYXNlNjQgZW5jb2RlIGJvZHkgc28gaXQgY2FuIGJlIHNhZmVseSByZXR1cm5lZCBhcyBKU09OIHZhbHVlXG4vLyAgICAgICAgIGJvZHk6IG5ldyBCdWZmZXIob3V0IGFzIHN0cmluZykudG9TdHJpbmcoJ2Jhc2U2NCcpXG4vLyAgICAgfVxuLy8gICAgIGNhbGxiYWNrKG51bGwsIGh0bWxSZXNwb25zZSlcbi8vIH1cblxuLy8g5Z+65LqO6Zi/6YeM5LqR55qE5Ye95pWw6K6h566X57uf5LiA5YWl5Y+j55qE6Lev55Sx5aSE55CGXG5leHBvcnRzLmhhbmRsZXIgPSBhc3luYyBmdW5jdGlvbiAoZXZlbnQsIGNvbnRleHQsIGNhbGxiYWNrKSB7XG4gICAgLy8gVE9ETyDlop7liqDlr7nkuo7lrprml7blmajnmoTlip/og73mqKHmi5/lrp7njrBcbiAgICAvLyB4bG9nKCckJCQkPT4nICsgZXZlbnQudG9TdHJpbmcoKSlcbiAgICAvLyBUT0RPIOWOu+mZpOaOieaNouihjOaWueS+v+aWueS+v1NMU+S4iueahOaXpeW/l+i+k+WHuuaOkueJiOaYvuekulxuICAgIC8vIHhsb2coJyQkJCQ9PicgKyBldmVudC50b1N0cmluZygpLnJlcGxhY2UoL1xcci9nLCAnJykucmVwbGFjZSgvXFxuL2csICcnKSlcblxuICAgIGxldCBldnQgPSBKU09OLnBhcnNlKGV2ZW50LnRvU3RyaW5nKCkpXG5cbiAgICAvLyDmoLnmja5BUEnnvZHlhbPorr7nva7nmoTnjq/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+axglxuICAgICAgICAgICAgICAgIGNhbGxiYWNrKG51bGwsIHtcbiAgICAgICAgICAgICAgICAgICAgc3RhdHVzQ29kZTogMjAwLFxuICAgICAgICAgICAgICAgICAgICBoZWFkZXJzOiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAuLi5fX2NvcnNfXyxcbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuXG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICAvLyDnpoHmraLku7vkvZXnmoTpnZ7ms5Xor7fmsYLkuKXmoLzov5vooYznuqblrprpmZDliLZcbiAgICAgICAgICAgIGNhbGxiYWNrKG51bGwsIHtcbiAgICAgICAgICAgICAgICBzdGF0dXNDb2RlOiA1MDIsXG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgcmV0dXJuXG4gICAgfVxuXG4gICAgLy8gVE9ETyDpnIDopoHlr7nkuo7kuovku7blrprml7blmajov5vooYznu5/kuIDnmoTnuqblrprlnKjlupTnlKjlsYLlj6/mianlsZXoh6rlrprkuYnnm7jlhbPlrprml7blmajnrYnkuovku7bnsbvlnotcbiAgICBpZiAoZXZ0Wyd0cmlnZ2VyTmFtZSddKSB7XG4gICAgICAgIC8vIOWvueWumuaXtuinpuWPkeWZqOeahOe7n+S4gOaLpuaIquWkhOeQhlxuICAgICAgICBzd2l0Y2ggKGV2dFsndHJpZ2dlck5hbWUnXSkge1xuICAgICAgICAgICAgY2FzZSAnX19heGpzLXByZWhlYXQtdGltZXJfXyc6XG4gICAgICAgICAgICAgICAgLy8g6I635Y+W6K+35rGC5Y+C5pWw55qE6YWN572u5pWw5o2uXG4gICAgICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICAgICAgbGV0IHBheWxvYWQgPSBKU09OLnBhcnNlKGV2dFsncGF5bG9hZCddKVxuICAgICAgICAgICAgICAgICAgICB4YXNzZXJ0KHBheWxvYWRbJ3VybCddICYmIHBheWxvYWRbJ3RpbWVvdXQnXSlcbiAgICAgICAgICAgICAgICAgICAgYXdhaXQgeHBvc3QocGF5bG9hZFsndXJsJ10sIHBheWxvYWRbJ3BhcmFtJ10sIHVuZGVmaW5lZCwgcGF5bG9hZFsndGltZW91dCddKVxuICAgICAgICAgICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgICAgICAgICAvLyBpZ25vcmUgZXJyb3JcbiAgICAgICAgICAgICAgICAgICAgeGxvZyhKU09OLnN0cmluZ2lmeSh4ZXJyb3IoZXJyKSkucmVwbGFjZSgvXFxyL2csICcnKS5yZXBsYWNlKC9cXG4vZywgJycpKVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBicmVha1xuICAgICAgICB9XG4gICAgICAgIHJldHVyblxuICAgIH0gZWxzZSBpZiAoZXZ0WydwYXRoJ10gPT09ICcvX19heGpzLXByZWhlYXQtdGltZXJfXycpIHtcbiAgICAgICAgLy8g6aKE54OtYXBp572R5YWz55qE56m66K+35rGC5b+D6Lez5o6l5Y+j5a6e546wXG4gICAgICAgIHJldHVyblxuICAgIH1cbiAgICBnbG9iYWxbJ19fZXZ0X18nXSA9IGV2ZW50LnRvU3RyaW5nKCkgLy8gRklYTUUg6ZyA6KaB6K6+6K6h5LiK5LiL5paH5a6a5LmJ6K+35rGC5a6e5L6L55Sf5ZG95ZGo5pyf5Y+Y6YePXG4gICAgLy8g5YWI5LulSEVBRVLkuK3nmoRfX2FwaV9f5a2X5q616L+b6KGM6K+G5Yir77yM5aaC5p6cSEVBREVS5Lit5rKh5pyJ5a6a5LmJ5YaN5L2/55SoVVJM6Lev5b6E5a+55bqU55qEUEFUSOivhuWIq++8jOS7peatpOaUr+aMgVNFT+etieWJjeerr+i3r+W+hOmHjeWGmemXrumimOOAglxuICAgIGxldCBfX2FwaV9fID0gXy5nZXQoZXZ0LCAnaGVhZGVycy5fX2FwaV9fJywgZXZ0LnBhdGgpIC8vIOacgOe7iOaOp+WItuWZqOS4jmFwcOWtkOebruW9leS4i+eahHRz5paH5Lu25L+d5oyB5a6M5YWo55qE5LiA5LiA5pig5bCE5YWz57O744CCXG4gICAgLy8g5pS56L+b5Li65qC55o2uQVBJ572R5YWz55qE55u45YWz5Y+C5pWw6Ieq5Yqo5ou85o6l5Ye65p2l5q2j56Gu55qEVVJM572R5Z2A6K+35rGC6Lev5b6EXG4gICAgbGV0IF9fdXJsX18gPSBldnRbJ2hlYWRlcnMnXVsnWC1Gb3J3YXJkZWQtUHJvdG8nXSArICc6Ly8nICsgZXZ0WydoZWFkZXJzJ11bJ0NBLUhvc3QnXSArIGV2dFsncGF0aCddXG4gICAgLy8g5bCG5YWo6YOo55qESEVBREVS5L+h5oGv6YCP5Lyg5Yiw5bqU55So5LitXG4gICAgbGV0IF9faGVhZGVyX18gPSBldnRbJ2hlYWRlcnMnXVxuXG4gICAgbGV0IHBhcmFtID0gT2JqZWN0LmFzc2lnbihcbiAgICAgICAge19fYXBpX18sIF9fdXJsX18sIF9faGVhZGVyX199LCAvLyBoZWFkZXLor7fmsYLkuK3nmoTkuKTkuKrmoYbmnrblsYLpnaLkuIrnmoTpooTlrprkuYnlj4LmlbAgVE9ETyDpnIDopoHnp7vpmaTmjonlubbpnZ7lupTnlKjlhbPlv4PnmoTlhoXlrrlcbiAgICAgICAgZXZ0LnBhdGhQYXJhbWV0ZXJzIHx8IHt9LCAvLyDot6/nlLHph43lhpnlj4LmlbAgZG9tYWluL1thXS9bYl0/eHh4ICjlj6/ooqtHRVTlj4LmlbDopobnm5YpXG4gICAgICAgIGV2dC5xdWVyeVBhcmFtZXRlcnMgfHwge30gLy8gR0VU6K+35rGC5Y+C5pWwIGRvbWFpbi9wYXRoP2E9eCZiPXhcbiAgICApXG4gICAgbGV0IG91dCA9IHt9XG5cbiAgICAvLyAvLyDmnaHku7bml6Xlv5fmiZPljbDnur/kuIrkuLTml7bpl67popjmjpLmn6XlpITnkIbvvIhUT0RPIOWinuWKoOS4muWKoemAu+i+keaJqeWxleazqOWFpeeahOmSqeWtkOWunueOsO+8iVxuICAgIC8vIGxldCB4ZGVidWcgPSBhc3luYyAoLi4uYXJncykgPT4ge1xuICAgIC8vICAgICBpZiAoIV8uaW5jbHVkZXMoX191cmxfXywgJ3kuYWxpYmFiYS1pbmMuY29tJykpIHtcbiAgICAvLyAgICAgICAgIHJldHVyblxuICAgIC8vICAgICB9XG4gICAgLy8gICAgIGF3YWl0IHh3YXJuKC4uLmFyZ3MpXG4gICAgLy8gfVxuICAgIC8vIGdsb2JhbFsneGRlYnVnJ10gPSB4ZGVidWcgLy8g5YWo5bGA5Y+v55SoXG4gICAgLy8gYXdhaXQgeGRlYnVnKHtwYXJhbSwgZXZ0fSlcblxuICAgIHN3aXRjaCAoZXZ0Lmh0dHBNZXRob2QpIHtcbiAgICAgICAgY2FzZSAnR0VUJzpcbiAgICAgICAgICAgIGJyZWFrXG4gICAgICAgIGNhc2UgJ1BPU1QnOlxuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICAvLyDpmL/ph4zkupFBUEnnvZHlhbPnmoRQT1NU6K+35rGC5Y+C5pWw5pivSlNPTuWtl+espuS4sueahEJBU0U2NOe8lueggeaJgOS7pemcgOimgei/m+ihjOi9rOS5ieWkhOeQhlxuICAgICAgICAgICAgICAgIGxldCBwb3N0ID0ge31cbiAgICAgICAgICAgICAgICBpZiAoXy5pc1N0cmluZyhldnQuYm9keSkpIHtcbiAgICAgICAgICAgICAgICAgICAgbGV0IGJvZHkgPSBldnQuYm9keVxuICAgICAgICAgICAgICAgICAgICBpZiAoZXZ0LmlzQmFzZTY0RW5jb2RlZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgYm9keSA9IG5ldyBCdWZmZXIoZXZ0LmJvZHksICdiYXNlNjQnKS50b1N0cmluZygpXG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgcG9zdCA9IHBhcnNlX3Bvc3RfcGFyYW0oZXZ0WydoZWFkZXJzJ10sIGJvZHkpXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHBhcmFtID0gT2JqZWN0LmFzc2lnbihwYXJhbSwgcG9zdCkgLy8g55SocG9zdOWPguaVsOimhuebluaOiWdldOWPguaVsO+8jOeUqOS6jueBtea0u+eahOiuvue9ruivt+axguWPguaVsOWFvOWuuWdldOWSjHBvc3TkuKTnp43mlrnms5Xmlrnkvr/lvIDlj5HosIPor5XjgIJcbiAgICAgICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgICAgIHhsb2coZXJyLCBldnQuaHR0cE1ldGhvZCwgZXZ0LmJvZHkpXG4gICAgICAgICAgICAgICAgYXdhaXQgeHdhcm4oZXJyKVxuICAgICAgICAgICAgICAgIC8vIDQwMFx0QmFkIFJlcXVlc3RcdOWuouaIt+err+ivt+axgueahOivreazlemUmeivr++8jOacjeWKoeWZqOaXoOazleeQhuino1xuICAgICAgICAgICAgICAgIGNhbGxiYWNrKG51bGwsIHtcbiAgICAgICAgICAgICAgICAgICAgc3RhdHVzQ29kZTogNTAzLFxuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgcmV0dXJuXG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBicmVha1xuICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgeGxvZyhldnQuaHR0cE1ldGhvZCwgZXZ0LmJvZHkpXG4gICAgICAgICAgICAvLyA0MDBcdEJhZCBSZXF1ZXN0XHTlrqLmiLfnq6/or7fmsYLnmoTor63ms5XplJnor6/vvIzmnI3liqHlmajml6Dms5XnkIbop6NcbiAgICAgICAgICAgIGNhbGxiYWNrKG51bGwsIHtcbiAgICAgICAgICAgICAgICBzdGF0dXNDb2RlOiA1MDQsXG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgcmV0dXJuXG4gICAgfVxuXG4gICAgdHJ5IHtcbiAgICAgICAgLy8g6Kej5p6Q6K+35rGC5Lit55qEY29va2llc+aVsOaNruW5tui9rOaNouS4ukpTT07lr7nosaHlrZjlgqjliLDlhajlsYDlj5jph4/kuK3kvr/kuo7lkI7nu63lupTnlKh4Y29va2ll5o6l5Y+j5L2/55SoXG4gICAgICAgIGxldCBjb29raWUgPSBfLmdldChldnRbJ2hlYWRlcnMnXSwgJ0Nvb2tpZScsIHVuZGVmaW5lZClcbiAgICAgICAgaWYgKCFjb29raWUpIHtcbiAgICAgICAgICAgIGNvb2tpZSA9IF8uZ2V0KGV2dFsnaGVhZGVycyddLCAnY29va2llJywgJycpXG4gICAgICAgIH1cbiAgICAgICAgZ2xvYmFsWydfX3JlcXVlc3RfY29va2llc19fJ10gPSByZXF1aXJlKCdjb29raWUnKS5wYXJzZShjb29raWUpXG5cbiAgICAgICAgLy8g6I635Y+WdXNlLWFnZW506K+35rGC5aS06YOo5L+h5oGvXG4gICAgICAgIGdsb2JhbFsnX191c2VyX2FnZW50X18nXSA9IGV2dFsnaGVhZGVycyddWydVc2VyLUFnZW50J11cbiAgICAgICAgLy8g6I635Y+W5a6i5oi356uv55qESVDlnLDlnYDkv6Hmga9cbiAgICAgICAgZ2xvYmFsWydfX2NsaWVudF9pcF9fJ10gPSBldnRbJ2hlYWRlcnMnXVsnWC1SZWFsLUlQJ11cblxuICAgICAgICAvLyBUT0RPIFdFQuivt+axgumcgOimgeWvuTQwNOmhtemdouS7peWPikVSUk9S6aG16Z2i6L+b6KGM5YW85a655aSE55CG77yI5ZyoZnJhbWV3b3Jr5YaF6YOo6L+b6KGM57uG6IqC55qE6ZSZ6K+v5Yik5pat5Zyob3V05Lit6YCP5Lygc3RhdHVz55qEaHR0cOeahOeKtuaAgeWQl+ato+ehrumUmeivr+i/lOWbnu+8iVxuICAgICAgICAvLyA0MDRcdE5vdCBGb3VuZCDmnI3liqHlmajml6Dms5XmoLnmja7lrqLmiLfnq6/nmoTor7fmsYLmib7liLDotYTmupDvvIjnvZHpobXvvInjgILpgJrov4fmraTku6PnoIHvvIznvZHnq5norr7orqHkurrlkZjlj6/orr7nva5cIuaCqOaJgOivt+axgueahOi1hOa6kOaXoOazleaJvuWIsFwi55qE5Liq5oCn6aG16Z2iXG4gICAgICAgIC8vIDQwM1x0Rm9yYmlkZGVuXHTmnI3liqHlmajnkIbop6Por7fmsYLlrqLmiLfnq6/nmoTor7fmsYLvvIzkvYbmmK/mi5Lnu53miafooYzmraTor7fmsYLvvIjmnYPpmZDpqozor4HlpITnkIbplJnor6/vvIlcbiAgICAgICAgb3V0ID0gYXdhaXQgcmVxdWVzdF9wcm9jZXNzKF9fYXBpX18sIHBhcmFtKVxuXG4gICAgICAgIC8vIOWkhOeQhnJlc3BvbnNl55qEY29va2llc+iuvue9rlxuICAgICAgICBsZXQgc2V0Q29va2llID0geydTZXQtQ29va2llJzogdW5kZWZpbmVkfVxuICAgICAgICBpZiAoIV8uaXNFbXB0eShnbG9iYWxbJ19fcmVzcG9uZF9jb29raWVzX18nXSkpIHtcbiAgICAgICAgICAgIHNldENvb2tpZVsnU2V0LUNvb2tpZSddID0gXy52YWx1ZXMoZ2xvYmFsWydfX3Jlc3BvbmRfY29va2llc19fJ10pXG4gICAgICAgIH1cblxuICAgICAgICBpZiAoZ2xvYmFsWydfX3JlZGlyZWN0X3VybF9fJ10pIHtcbiAgICAgICAgICAgIGNhbGxiYWNrKG51bGwsIHtcbiAgICAgICAgICAgICAgICBzdGF0dXNDb2RlOiAzMDIsXG4gICAgICAgICAgICAgICAgaGVhZGVyczoge1xuICAgICAgICAgICAgICAgICAgICBcIkxvY2F0aW9uXCI6IGdsb2JhbFsnX19yZWRpcmVjdF91cmxfXyddLFxuICAgICAgICAgICAgICAgICAgICAuLi5zZXRDb29raWVcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIGdsb2JhbFsnX19yZWRpcmVjdF91cmxfXyddID0gdW5kZWZpbmVkXG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoXy5pc1N0cmluZyhvdXQpKSB7XG4gICAgICAgICAgICBsZXQgaHRtbFJlc3BvbnNlID0ge1xuICAgICAgICAgICAgICAgIGlzQmFzZTY0RW5jb2RlZDogdHJ1ZSxcbiAgICAgICAgICAgICAgICBzdGF0dXNDb2RlOiAyMDAsXG4gICAgICAgICAgICAgICAgaGVhZGVyczoge1xuICAgICAgICAgICAgICAgICAgICBcIkNvbnRlbnQtdHlwZVwiOiBcInRleHQvaHRtbDsgY2hhcnNldD11dGYtOFwiLFxuICAgICAgICAgICAgICAgICAgICAuLi5zZXRDb29raWUsXG4gICAgICAgICAgICAgICAgICAgIC4uLl9fY29yc19fLFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgLy8gYmFzZTY0IGVuY29kZSBib2R5IHNvIGl0IGNhbiBiZSBzYWZlbHkgcmV0dXJuZWQgYXMgSlNPTiB2YWx1ZVxuICAgICAgICAgICAgICAgIGJvZHk6IG5ldyBCdWZmZXIob3V0IGFzIHN0cmluZykudG9TdHJpbmcoJ2Jhc2U2NCcpXG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjYWxsYmFjayhudWxsLCBodG1sUmVzcG9uc2UpXG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBsZXQganNvblJlc3BvbnNlID0ge1xuICAgICAgICAgICAgICAgIGlzQmFzZTY0RW5jb2RlZDogdHJ1ZSxcbiAgICAgICAgICAgICAgICBzdGF0dXNDb2RlOiAyMDAsXG4gICAgICAgICAgICAgICAgaGVhZGVyczoge1xuICAgICAgICAgICAgICAgICAgICBcIkNvbnRlbnQtdHlwZVwiOiBcImFwcGxpY2F0aW9uL2pzb25cIixcbiAgICAgICAgICAgICAgICAgICAgLi4uX19jb3JzX18sXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAvLyBiYXNlNjQgZW5jb2RlIGJvZHkgc28gaXQgY2FuIGJlIHNhZmVseSByZXR1cm5lZCBhcyBKU09OIHZhbHVlXG4gICAgICAgICAgICAgICAgYm9keTogbmV3IEJ1ZmZlcihKU09OLnN0cmluZ2lmeShvdXQpKS50b1N0cmluZygnYmFzZTY0JylcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNhbGxiYWNrKG51bGwsIGpzb25SZXNwb25zZSlcbiAgICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAvLyDpgJrnn6XmoYbmnrboh6rouqvlrp7njrDpgLvovpHnmoTmhI/lpJbmiqXplJnvvIjmoYbmnrboh6rouqvkuI3orrrkvZXnp43mg4XlhrXpg73lupTor6XmraPluLjlt6XkvZzvvIzkuIDml6blh7rnjrDmraTpl67popjlpKflpJrmlbDmg4XlhrXmmK/moYbmnrboh6rouqvpl67popjmiJbogIXmtYHph4/lvJXlj5HnmoTov5Dnu7Tpl67popjvvIlcbiAgICAgICAgYXdhaXQgeHdhcm4oe1xuICAgICAgICAgICAgX19hcGlfXywgX191cmxfXywgcGFyYW0sIG1lc3NhZ2U6IGVyci5tZXNzYWdlLCBzdGFjazogeHN0YWNrKGVycilcbiAgICAgICAgfSlcbiAgICAgICAgLy8gNTAwXHRJbnRlcm5hbCBTZXJ2ZXIgRXJyb3JcdOacjeWKoeWZqOWGhemDqOmUmeivr++8jOaXoOazleWujOaIkOivt+axglxuICAgICAgICBjYWxsYmFjayhudWxsLCB7c3RhdHVzQ29kZTogNTA1fSlcbiAgICB9XG59XG5cbi8vICBBUEnlj4LmlbDnmoTor4bliKvpgLvovpHvvIzkuLrmma7pgJrlrZfnrKbkuLLot6/lvoTlrprkuYnkuI5hcHDkuIvnmoR0c+aWh+S7tui3r+eUseWujOWFqOS4gOS4gOWvueW6lO+8jOS8mOWFiOWPlkhFQURFUuS4reeahOWumuS5ie+8jOWGjeWPlkdFVOS4reeahOW9ouWPguWumuS5ieaIluiAhVBPU1TlvaLlj4LlrprkuYnov5vooYzlj4LmlbDor7fmsYLnmoTopobnm5blpITnkIbjgIJcbi8vICBQQVJBTeivt+axgueahOWPguaVsOWkhOeQhuimgeaxguS4ukJBU0U2NOe8lueggeWMlueahEpTT07lrZfnrKbkuLLjgIJcbi8vICAgICBcImV2ZW50XCI6IHtcbi8vICAgICAgICAgXCJib2R5XCI6IFwiZXdvSkltRndhU0k2SUNJdllTOWlMMk1pTEFvSkluQmhjbUZ0SWpvZ0ltRnpaR1poYzJSbVlYTmtaaUlLZlE9PVwiLCA9PiDlr7nlupTkuo5QT1NU6K+35rGC5pWw5o2uXG4vLyAgICAgICAgIFwiaGVhZGVyc1wiOiB7XG4vLyAgICAgICAgICAgICBcIlgtQ2EtQXBpLUdhdGV3YXlcIjogXCJCMjVDRDUxQi01ODE1LTQ3NzUtOUVBQi02RDQ4MUJDMUFFMTdcIixcbi8vICAgICAgICAgICAgIFwiX19hcGlfX1wiOiBcIi93ZWIvbW9iaWxlL3Rlc3RcIiwgICA944CLIOiHquWumuS5iei9rOS5iVBBVEjnmoTot6/lvoTkv6Hmga/lr7nkuo5TRU/kvJjljJblhbzlrrnlpITnkIbvvIjkuZ/lj6/ku6XlnKhHRVTmiJZQT1NU6K+35rGC5Lit5Lyg6YCS5a+55bqU5Y+C5pWw77yJXG4vLyAgICAgICAgICAgICBcIlgtRm9yd2FyZGVkLUZvclwiOiBcIjQyLjEyMC43NC44OFwiLFxuLy8gICAgICAgICAgICAgXCJDb250ZW50LVR5cGVcIjogXCJhcHBsaWNhdGlvbi9qc29uXCJcbi8vICAgICAgICAgfSxcbi8vICAgICAgICAgXCJodHRwTWV0aG9kXCI6IFwiUE9TVFwiLFxuLy8gICAgICAgICBcImlzQmFzZTY0RW5jb2RlZFwiOiB0cnVlLFxuLy8gICAgICAgICBcInBhdGhcIjogXCIvXCIsID3jgIsg5rKh5pyJ5oSP5LmJ55So5LqO5YmN56uv5qC55o2u6ZyA6KaB6Ieq5bex6L+b6KGM5omp5bGV5Yir5ZCN5pig5bCE5aSE55CG77yM5ZCO56uv55qE5o6n5Yi25Zmo5LiN5Lul5q2k5Li65qCH5YeG77yM5Y+v5Lul5a+55ZCM5LiA5Liq5o6n5Yi25Zmo5a6a5LmJTuS4quS4jeWQjOeahOi3r+W+hOagh+ivhuOAglxuLy8gICAgICAgICBcInBhdGhQYXJhbWV0ZXJzXCI6IHt9LFxuLy8gICAgICAgICBcInF1ZXJ5UGFyYW1ldGVyc1wiOiB7fSA9PiDlr7nlupTkuo5HRVTor7fmsYLmlbDmja5cbi8vICAgICB9LFxuLy8gICAgIFwicXVlcnlcIjoge30sXG4vLyAgICAgXCJjb250ZXh0XCI6IHtcbi8vICAgICAgICAgXCJyZXF1ZXN0SWRcIjogXCJCMjVDRDUxQi01ODE1LTQ3NzUtOUVBQi02RDQ4MUJDMUFFMTdcIixcbi8vICAgICAgICAgXCJjcmVkZW50aWFsc1wiOiB7XG4vLyAgICAgICAgICAgICBcImFjY2Vzc0tleUlkXCI6IFwiXCIsXG4vLyAgICAgICAgICAgICBcImFjY2Vzc0tleVNlY3JldFwiOiBcIlwiLFxuLy8gICAgICAgICAgICAgXCJzZWN1cml0eVRva2VuXCI6IFwiXCJcbi8vICAgICAgICAgfSxcbi8vICAgICAgICAgXCJmdW5jdGlvblwiOiB7XG4vLyAgICAgICAgICAgICBcIm5hbWVcIjogXCJ0ZXN0XCIsXG4vLyAgICAgICAgICAgICBcImhhbmRsZXJcIjogXCJpbmRleC5oYW5kbGVyXCIsXG4vLyAgICAgICAgICAgICBcIm1lbW9yeVwiOiAxMjgsXG4vLyAgICAgICAgICAgICBcInRpbWVvdXRcIjogMzAwXG4vLyAgICAgICAgIH0sXG4vLyAgICAgICAgIFwic2VydmljZXNcIjoge1xuLy8gICAgICAgICAgICAgXCJuYW1lXCI6IFwiYWxpbGFuZ1wiLFxuLy8gICAgICAgICAgICAgXCJsb2dQcm9qZWN0XCI6IFwiXCIsXG4vLyAgICAgICAgICAgICBcImxvZ1N0b3JlXCI6IFwiXCJcbi8vICAgICAgICAgfSxcbi8vICAgICAgICAgXCJyZWdpb25cIjogXCJjbi1zaGFuZ2hhaVwiLFxuLy8gICAgICAgICBcImFjY291bnRJZFwiOiBcIjE3MzQwNjYwNTc2ODk1MjhcIlxuLy8gICAgIH1cbi8vIH1cblxuLy8g5pyA5paw54mI5pysZXZlbnTnmoRBUEnnvZHlhbPnmoRGQ+i/lOWbnuaVsOaNruagvOW8j++8mlxuLy8gICAgICBDQS1Ib3N06K+35rGC5Z+f5ZCN44CBXG4vLyAgICAgIFgtRm9yd2FyZGVkLVByb3RvXG4vLyAgICAgIFwicGF0aFwiOiBcIi90ZXN0XCIsID0944CL44CL5Z+65pys5LiK5Y+v5Lul5ou85o6l5Ye6X191cmxfX+WPguaVsOWPr+S7peecgeeVpeaOieatpOWGl+S9meWPguaVsOmFjee9ruS6huOAglxuLy8gICAgICAgICAgICAgICAgICAgICAgID0944CL44CL5YCf5Yqpcm91dGUubWFwLnRz5paH5Lu255qE5pig5bCE5YWz57O75a6a5LmJ55yB55Wl5o6JX19hcGlfX+mFjee9rui/m+S4gOatpeeugOWMlue9keWFs+W6lOeUqOOAglxuLy8gICAgICBcImh0dHBNZXRob2RcIjogXCJHRVRcIixcbi8vICAgICAgXCJpc0Jhc2U2NEVuY29kZWRcIjogdHJ1ZSxcbi8vICAgICAgXCJYLUZvcndhcmRlZC1Gb3JcIjogXCI0Mi4xMjAuNzQuMTAzXCIsIC8vIOWuouaIt+err+ivt+axgklQ5Zyw5Z2A55So5oi35Yik5a6a5omA5bGe5Yy65Z+f5L+h5oGv5rW35aSW6K6/6Zeu6Zeu6aKY5LyY5YyW5L6d6LWW54K5XG4vLyAgICAgIFwiWC1SZWFsLUlQXCI6IFwiNDIuMTIwLjc0LjEwM1wiLFxuLy8gICAgICBDb29raWVcbi8vICAgICAgVXNlci1BZ2VudCAgICAgICA9Pj4gUEPnq5nlkoxN56uZ6Ieq6YCC5bqU6Zeu6aKYXG4vLyAgICAgIEFjY2VwdC1MYW5ndWFnZSAgPT4+IOa1j+iniOWZqOWuouaIt+err+eahOivreiogOexu+Wei+iHquWKqOmAgumFjeWkmuivreiogOaetuaehOiuvuiuoemXrumimFxuLy8gbGV0IHggPSB7XG4vLyAgICAgXCJib2R5XCI6IFwiXCIsXG4vLyAgICAgXCJoZWFkZXJzXCI6IHtcbi8vICAgICAgICAgXCJYLUNhLUFwaS1HYXRld2F5XCI6IFwiQjI3NkY3N0ItMzM0RS00ODU3LUFFNjQtNjVCQUZENDE5RTJBXCIsXG4vLyAgICAgICAgIFwiQ29va2llXCI6IFwiY25hPXI1c25FenpPdkEwQ0FTcDRTbWRxK0lJLzsgVU1fZGlzdGluY3RpZD0xNjJiY2Q2MWQ5MTExY2QtMDgwZTBmNDNlNmI2MGQtMzM2OTdiMDQtMTNjNjgwLTE2MmJjZDYxZDkyYzg2OyBfdGJfdG9rZW5fPUg4VTdCcWl4RjNZVlIzR25oTVJ6OyBORVcyX0FDUl9KU0VTU0lPTklEPVZNNTY2RjkxLUs1Q1A4UUlWTVFUU0FIM0M0SDVYMS1EUklIWUpISi1RRTI7IF9uZXdfY3Jfc2Vzc2lvbjA9MUFiTEJ5T01IZVplM0c0MUtZZDVXY1BkQyUyRmk4cXZHSFVCVEs4RmJyZng4U29pJTJCSEVMdXh4QTZqcm9zN1clMkZxQzFZdGViZ0IzYXVFRjVsdTFTQ3pVelRrdDZ2JTJGaUZlTiUyRnB0YnZCUnppWUVHWFNFVmhXblVsQlIydGZwanJYTW5JY2ZiMiUyRnduR2tINHZrZU1JSjFCdnV3JTNEJTNEOyBlbXBsSWQ9MTQ5MzM3OyBocmNfc2lkZWJhcj1vcGVuOyB0cmFjZUlkPTdkNGIxNmRlLTc0YmMtNGVhYy04ODRiLTU0Y2EwMzU0ZTRhYTsgU1NPX0xBTkc9WkgtQ047IFNTT19FTVBJRF9IQVNIPTlkYjFlZDIxNDAyZjdjMzY2NzRiNWU2ZTZkZTFmYzY4OyBhbmltYXRlX2RhdGU9MjAxODY0OyBhYT14eHh4eHh4OyBjbl8xMjYwMDAxMjIxX2RwbHVzPSU3QiUyMmRpc3RpbmN0X2lkJTIyJTNBJTIwJTIyMTYyYmNkNjFkOTExMWNkLTA4MGUwZjQzZTZiNjBkLTMzNjk3YjA0LTEzYzY4MC0xNjJiY2Q2MWQ5MmM4NiUyMiUyQyUyMnNwJTIyJTNBJTIwJTdCJTIyJTI0X3Nlc3Npb25pZCUyMiUzQSUyMDAlMkMlMjIlMjRfc2Vzc2lvblRpbWUlMjIlM0ElMjAxNTI4MDg2MjM0JTJDJTIyJTI0ZHAlMjIlM0ElMjAwJTJDJTIyJTI0X3Nlc3Npb25QVlRpbWUlMjIlM0ElMjAxNTI4MDg2MjM0JTdEJTdEOyBpc2c9QkR3OFNvbnlTOXV0eW41ZmVkWVJlLXVSRGR6d05BRDAtNTFCSGhhOV9TY0o0ZHhyTmtXdzc3S1F4UW1acVJpM1wiLFxuLy8gICAgICAgICBcIlgtRm9yd2FyZGVkLVByb3RvXCI6IFwiaHR0cHNcIixcbi8vICAgICAgICAgXCJVc2VyLUFnZW50XCI6IFwiTW96aWxsYS81LjAgKE1hY2ludG9zaDsgSW50ZWwgTWFjIE9TIFggMTBfMTJfNikgQXBwbGVXZWJLaXQvNTM3LjM2IChLSFRNTCwgbGlrZSBHZWNrbykgQ2hyb21lLzY2LjAuMzM1OS4xODEgU2FmYXJpLzUzNy4zNlwiLFxuLy8gICAgICAgICBcIl9fdXJsX19cIjogXCJodHRwczovL3RvdWZhbmcuYWxpYmFiYS1pbmMuY29tL3Rlc3RcIixcbi8vICAgICAgICAgXCJDQS1Ib3N0XCI6IFwidG91ZmFuZy5hbGliYWJhLWluYy5jb21cIixcbi8vICAgICAgICAgXCJDYWNoZS1Db250cm9sXCI6IFwibWF4LWFnZT0wXCIsXG4vLyAgICAgICAgIFwidXBncmFkZS1pbnNlY3VyZS1yZXF1ZXN0c1wiOiBcIjFcIixcbi8vICAgICAgICAgXCJBY2NlcHQtTGFuZ3VhZ2VcIjogXCJ6aC1DTix6aDtxPTAuOVwiLFxuLy8gICAgICAgICBcIl9fYXBpX19cIjogXCIvd2ViL3Rlc3QvdGVzdFwiLFxuLy8gICAgICAgICBcIkFjY2VwdC1FbmNvZGluZ1wiOiBcImd6aXAsIGRlZmxhdGUsIGJyXCIsXG4vLyAgICAgICAgIFwiWC1Gb3J3YXJkZWQtRm9yXCI6IFwiNDIuMTIwLjc0LjEwM1wiLFxuLy8gICAgICAgICBcIlgtUmVhbC1JUFwiOiBcIjQyLjEyMC43NC4xMDNcIixcbi8vICAgICAgICAgXCJBY2NlcHRcIjogXCJ0ZXh0L2h0bWwsYXBwbGljYXRpb24veGh0bWwreG1sLGFwcGxpY2F0aW9uL3htbDtxPTAuOSxpbWFnZS93ZWJwLGltYWdlL2FwbmcsKi8qO3E9MC44XCJcbi8vICAgICB9LFxuLy8gICAgIFwiaHR0cE1ldGhvZFwiOiBcIkdFVFwiLFxuLy8gICAgIFwiaXNCYXNlNjRFbmNvZGVkXCI6IHRydWUsXG4vLyAgICAgXCJwYXRoXCI6IFwiL3Rlc3RcIixcbi8vICAgICBcInBhdGhQYXJhbWV0ZXJzXCI6IHt9LFxuLy8gICAgIFwicXVlcnlQYXJhbWV0ZXJzXCI6IHt9XG4vLyB9XG4iXX0=
\No newline at end of file