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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJpbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSxPQUFPLENBQUMsb0JBQW9CLENBQUMsQ0FBQyxPQUFPLEVBQUUsQ0FBQTtBQUN2QyxPQUFPLENBQUMsZ0JBQWdCLENBQUMsQ0FBQyxRQUFRLEVBQUUsQ0FBQTtBQUNwQywrQkFBd0Q7QUFFeEQsSUFBTSxDQUFDLEdBQUcsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFBO0FBRTNCLGdCQUFnQjtBQUNoQixvR0FBb0c7QUFDcEcsZ0VBQWdFO0FBQ2hFLCtEQUErRDtBQUMvRCw4Q0FBOEM7QUFDOUMsbURBQW1EO0FBQ25ELG1EQUFtRDtBQUNuRCwyQkFBMkI7QUFDM0IsaUNBQWlDO0FBQ2pDLDJCQUEyQjtBQUMzQixxQkFBcUI7QUFDckIsMERBQTBEO0FBQzFELGFBQWE7QUFDYiwyRUFBMkU7QUFDM0UsNkRBQTZEO0FBQzdELFFBQVE7QUFDUixtQ0FBbUM7QUFDbkMsSUFBSTtBQUVKLHNCQUFzQjtBQUN0QixPQUFPLENBQUMsT0FBTyxHQUFHLFVBQWdCLEtBQUssRUFBRSxPQUFPLEVBQUUsUUFBUTs7Ozs7O29CQU1sRCxHQUFHLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsUUFBUSxFQUFFLENBQUMsQ0FBQTtvQkFFdEMsNkRBQTZEO29CQUM3RCx1QkFBdUI7b0JBQ3ZCLE1BQU0sQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxpQkFBaUIsRUFBRSxNQUFNLENBQUMsQ0FBQTtvQkFFbkQsUUFBUSxHQUFHLEVBQUUsQ0FBQTtvQkFDbkIsSUFBSSxNQUFNLENBQUMsU0FBUyxDQUFDLEtBQUssTUFBTSxJQUFJLE1BQU0sQ0FBQyxTQUFTLENBQUMsS0FBSyxNQUFNLEVBQUU7d0JBQzlELG9DQUFvQzt3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QUM3RSxxQ0FBcUM7QUFDckMsY0FBYztBQUNkLHdDQUF3QztBQUN4QyxxREFBcUQ7QUFDckQsWUFBWTtBQUNaLGtCQUFrQjtBQUNsQixtQkFBbUI7QUFDbkIsc0VBQXNFO0FBQ3RFLG02QkFBbTZCO0FBQ242Qix3Q0FBd0M7QUFDeEMscUpBQXFKO0FBQ3JKLDZEQUE2RDtBQUM3RCxnREFBZ0Q7QUFDaEQsd0NBQXdDO0FBQ3hDLDRDQUE0QztBQUM1QywrQ0FBK0M7QUFDL0MsdUNBQXVDO0FBQ3ZDLGtEQUFrRDtBQUNsRCw4Q0FBOEM7QUFDOUMsd0NBQXdDO0FBQ3hDLDRHQUE0RztBQUM1RyxTQUFTO0FBQ1QsMkJBQTJCO0FBQzNCLCtCQUErQjtBQUMvQix1QkFBdUI7QUFDdkIsNEJBQTRCO0FBQzVCLDRCQUE0QjtBQUM1QixJQUFJIiwic291cmNlc0NvbnRlbnQiOlsicmVxdWlyZSgnc291cmNlLW1hcC1zdXBwb3J0JykuaW5zdGFsbCgpXG5yZXF1aXJlKCd0c2NvbmZpZy1wYXRocycpLnJlZ2lzdGVyKClcbmltcG9ydCB7cmVxdWVzdF9wcm9jZXNzLCBwYXJzZV9wb3N0X3BhcmFtfSBmcm9tICcuL2luaXQnXG5cbmNvbnN0IF8gPSByZXF1aXJlKCdsb2Rhc2gnKVxuXG4vLyAvLyDkuLTml7bosIPor5Xnur/kuIrml6Xlv5fmiZPljbBcbi8vIC8vZnJhbWV3b3JrL2luZGV4LnRzKDgsMTMpOiBlcnJvciBUUzIzMzk6IFByb3BlcnR5ICdzZXRMb2dMZXZlbCcgZG9lcyBub3QgZXhpc3Qgb24gdHlwZSAnQ29uc29sZSdcbi8vIGV4cG9ydHMuaGFuZGxlciA9IGFzeW5jIGZ1bmN0aW9uIChldmVudCwgY29udGV4dCwgY2FsbGJhY2spIHtcbi8vICAgICAvLyBjb25zb2xlLnNldExvZ0xldmVsKCdlcnJvcicpIOS4jeiDveWGmeWcqOatpOS8muWvvOiHtOe8luivkemUmeivr+mYv+mHjOS6keiHquW3seaJqeWxleeahOengeacieaWueazlVxuLy8gICAgIGNvbnNvbGUubG9nKCd4eHh4eCcsICd5eXl5eScsICd6enp6enonKVxuLy8gICAgIGNvbnNvbGUuZXJyb3IoJ3h4eHh4MScsICd5eXl5eTEnLCAnenp6enp6MScpXG4vLyAgICAgbGV0IG91dCA9ICc8aHRtbD48Ym9keT56enp6eno8L2JvZHk+PC9odG1sPidcbi8vICAgICBsZXQgaHRtbFJlc3BvbnNlID0ge1xuLy8gICAgICAgICBpc0Jhc2U2NEVuY29kZWQ6IHRydWUsXG4vLyAgICAgICAgIHN0YXR1c0NvZGU6IDIwMCxcbi8vICAgICAgICAgaGVhZGVyczoge1xuLy8gICAgICAgICAgICAgXCJDb250ZW50LXR5cGVcIjogXCJ0ZXh0L2h0bWw7IGNoYXJzZXQ9dXRmLThcIixcbi8vICAgICAgICAgfSxcbi8vICAgICAgICAgLy8gYmFzZTY0IGVuY29kZSBib2R5IHNvIGl0IGNhbiBiZSBzYWZlbHkgcmV0dXJuZWQgYXMgSlNPTiB2YWx1ZVxuLy8gICAgICAgICBib2R5OiBuZXcgQnVmZmVyKG91dCBhcyBzdHJpbmcpLnRvU3RyaW5nKCdiYXNlNjQnKVxuLy8gICAgIH1cbi8vICAgICBjYWxsYmFjayhudWxsLCBodG1sUmVzcG9uc2UpXG4vLyB9XG5cbi8vIOWfuuS6jumYv+mHjOS6keeahOWHveaVsOiuoeeul+e7n+S4gOWFpeWPo+eahOi3r+eUseWkhOeQhlxuZXhwb3J0cy5oYW5kbGVyID0gYXN5bmMgZnVuY3Rpb24gKGV2ZW50LCBjb250ZXh0LCBjYWxsYmFjaykge1xuICAgIC8vIFRPRE8g5aKe5Yqg5a+55LqO5a6a5pe25Zmo55qE5Yqf6IO95qih5ouf5a6e546wXG4gICAgLy8geGxvZygnJCQkJD0+JyArIGV2ZW50LnRvU3RyaW5nKCkpXG4gICAgLy8gVE9ETyDljrvpmaTmjonmjaLooYzmlrnkvr/mlrnkvr9TTFPkuIrnmoTml6Xlv5fovpPlh7rmjpLniYjmmL7npLpcbiAgICAvLyB4bG9nKCckJCQkPT4nICsgZXZlbnQudG9TdHJpbmcoKS5yZXBsYWNlKC9cXHIvZywgJycpLnJlcGxhY2UoL1xcbi9nLCAnJykpXG5cbiAgICBsZXQgZXZ0ID0gSlNPTi5wYXJzZShldmVudC50b1N0cmluZygpKVxuXG4gICAgLy8g5qC55o2uQVBJ572R5YWz6K6+572u55qE546v5aKD5bi46YeP5Y+C5pWw5q2j56Gu6YWN572u57q/5LiK54mI5pys55qE6L+Q6KGM546v5aKD77yM5Y+W5LujQU9OReeahOacrOWcsOOAgeaXpeW4uOOAgemihOWPkeOAgeeBsOW6puetieeOr+Wig+mDqOe9suaUr+aMgeW8gOWPkeOAglxuICAgIC8vIOWFqOWxgOWPmOmHj+S7heS7heeUqOS6juaUvuWcqOaVtOS4quW6lOeUqOeUn+WRveWRqOacn+WPmOmHj1xuICAgIGdsb2JhbFsnX19lbnZfXyddID0gXy5nZXQoZXZ0LCAnaGVhZGVycy5fX2Vudl9fJywgJ3Byb2QnKVxuXG4gICAgY29uc3QgX19jb3JzX18gPSB7fVxuICAgIGlmIChnbG9iYWxbJ19fZW52X18nXSAhPT0gJ3Byb2QnICYmIGdsb2JhbFsnX19lbnZfXyddICE9PSAnZ3JheScpIHtcbiAgICAgICAgLy8g6Z2e55Sf5Lqn546v5aKD5oiW54Gw5bqm546v5aKD77yM6ZyA6KaB56aB55SoQ09SU+WKn+iDveemgeatoui3qOWfn+iuv+mXruWinuWKoOWuieWFqOaAp+OAglxuICAgICAgICBpZiAoZXZ0LmhlYWRlcnMub3JpZ2luKSB7XG4gICAgICAgICAgICAvLyDojrflj5bmupDnq5nliqjmgIHlhYHorrjor7fmsYLot6jln58gKEZJWE1FIOmcgOimgei/m+ihjOWuieWFqOmZkOWItuWvueadpea6kOacjeWKoeWZqOe9keWdgOWQiOazleaAp+i/m+ihjOWuieWFqOmZkOWItu+8jOacrOWcsOW8gOWPkeiwg+ivleWFqOmDqOaUvuW8gOivt+axgilcbiAgICAgICAgICAgIF9fY29yc19fWydBY2Nlc3MtQ29udHJvbC1BbGxvdy1PcmlnaW4nXSA9IGV2dC5oZWFkZXJzLm9yaWdpblxuICAgICAgICAgICAgLy8gX19jb3JzX19bJ0FjY2Vzcy1Db250cm9sLUFsbG93LU9yaWdpbiddID0gJyonIC8vIOS4jeiDveiuvue9ruS4uuS7u+aEj+WAvOa1j+iniOWZqOacieWuieWFqOmZkOWItlxuICAgICAgICB9XG4gICAgICAgIF9fY29yc19fWydBY2Nlc3MtQ29udHJvbC1BbGxvdy1DcmVkZW50aWFscyddID0gJ3RydWUnXG4gICAgICAgIF9fY29yc19fWydBY2Nlc3MtQ29udHJvbC1BbGxvdy1IZWFkZXJzJ10gPSAnT3JpZ2luLCBYLVJlcXVlc3RlZC1XaXRoLCBDb250ZW50LVR5cGUsIEFjY2VwdCdcbiAgICAgICAgX19jb3JzX19bJ0FjY2Vzcy1Db250cm9sLUFsbG93LU1ldGhvZHMnXSA9ICdQT1NULCBPUFRJT05TJ1xuICAgIH1cblxuICAgIC8vIOaUr+aMgei3qOWfn+eahOmqjOivgeivt+axguaWueazleeahOWQiOazleaAp+inhOmBv+aOiei/h+a7pOaOieS4jeWuieWFqOeahOivt+axguOAglxuICAgIHN3aXRjaCAoZXZ0Lmh0dHBNZXRob2QpIHtcbiAgICAgICAgY2FzZSAnR0VUJzpcbiAgICAgICAgY2FzZSAnUE9TVCc6XG4gICAgICAgICAgICBicmVha1xuICAgICAgICBjYXNlICdPUFRJT05TJzpcbiAgICAgICAgICAgIGlmIChnbG9iYWxbJ19fZW52X18nXSA9PSAncHJvZCcgfHwgZ2xvYmFsWydfX2Vudl9fJ10gPT0gJ2dyYXknKSB7XG4gICAgICAgICAgICAgICAgLy8g55Sf5Lqn5ZKM54Gw5bqm546v5aKD5LiL56aB5q2i6Leo5Z+fT1BUSU9OU+ivt+axguS7peS+v+S6juWinuW8uuWuieWFqOaAp1xuICAgICAgICAgICAgICAgIGNhbGxiYWNrKG51bGwsIHtcbiAgICAgICAgICAgICAgICAgICAgc3RhdHVzQ29kZTogNTAxLFxuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIC8vIOmdnueUn+S6p+WSjOeBsOW6pueOr+Wig+S4i+aJjeWFgeiuuOaUr+aMgei3qOWfn09QVElPTlPor7fmsYJcbiAgICAgICAgICAgICAgICBjYWxsYmFjayhudWxsLCB7XG4gICAgICAgICAgICAgICAgICAgIHN0YXR1c0NvZGU6IDIwMCxcbiAgICAgICAgICAgICAgICAgICAgaGVhZGVyczoge1xuICAgICAgICAgICAgICAgICAgICAgICAgLi4uX19jb3JzX18sXG4gICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVyblxuICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgLy8g56aB5q2i5Lu75L2V55qE6Z2e5rOV6K+35rGC5Lil5qC86L+b6KGM57qm5a6a6ZmQ5Yi2XG4gICAgICAgICAgICBjYWxsYmFjayhudWxsLCB7XG4gICAgICAgICAgICAgICAgc3RhdHVzQ29kZTogNTAyLFxuICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIHJldHVyblxuICAgIH1cblxuICAgIC8vIFRPRE8g6ZyA6KaB5a+55LqO5LqL5Lu25a6a5pe25Zmo6L+b6KGM57uf5LiA55qE57qm5a6a5Zyo5bqU55So5bGC5Y+v5omp5bGV6Ieq5a6a5LmJ55u45YWz5a6a5pe25Zmo562J5LqL5Lu257G75Z6LXG4gICAgaWYgKGV2dFsndHJpZ2dlck5hbWUnXSkge1xuICAgICAgICAvLyDlr7nlrprml7bop6blj5HlmajnmoTnu5/kuIDmi6bmiKrlpITnkIZcbiAgICAgICAgc3dpdGNoIChldnRbJ3RyaWdnZXJOYW1lJ10pIHtcbiAgICAgICAgICAgIGNhc2UgJ19fYXhqcy1wcmVoZWF0LXRpbWVyX18nOlxuICAgICAgICAgICAgICAgIC8vIOiOt+WPluivt+axguWPguaVsOeahOmFjee9ruaVsOaNrlxuICAgICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgICAgIGxldCBwYXlsb2FkID0gSlNPTi5wYXJzZShldnRbJ3BheWxvYWQnXSlcbiAgICAgICAgICAgICAgICAgICAgeGFzc2VydChwYXlsb2FkWyd1cmwnXSAmJiBwYXlsb2FkWyd0aW1lb3V0J10pXG4gICAgICAgICAgICAgICAgICAgIGF3YWl0IHhwb3N0KHBheWxvYWRbJ3VybCddLCBwYXlsb2FkWydwYXJhbSddLCB1bmRlZmluZWQsIHBheWxvYWRbJ3RpbWVvdXQnXSlcbiAgICAgICAgICAgICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gaWdub3JlIGVycm9yXG4gICAgICAgICAgICAgICAgICAgIHhsb2coSlNPTi5zdHJpbmdpZnkoeGVycm9yKGVycikpLnJlcGxhY2UoL1xcci9nLCAnJykucmVwbGFjZSgvXFxuL2csICcnKSlcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgYnJlYWtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm5cbiAgICB9IGVsc2UgaWYgKGV2dFsncGF0aCddID09PSAnL19fYXhqcy1wcmVoZWF0LXRpbWVyX18nKSB7XG4gICAgICAgIC8vIOmihOeDrWFwaee9keWFs+eahOepuuivt+axguW/g+i3s+aOpeWPo+WunueOsFxuICAgICAgICByZXR1cm5cbiAgICB9XG4gICAgZ2xvYmFsWydfX2V2dF9fJ10gPSBldmVudC50b1N0cmluZygpIC8vIEZJWE1FIOmcgOimgeiuvuiuoeS4iuS4i+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