1 | ;
|
2 | var __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 | };
|
10 | var __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 | };
|
18 | var __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 | };
|
45 | Object.defineProperty(exports, "__esModule", { value: true });
|
46 | require('source-map-support').install();
|
47 | require('tsconfig-paths').register();
|
48 | var init_1 = require("./init");
|
49 | var _ = 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 | // 基于阿里云的函数计算统一入口的路由处理
|
69 | exports.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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguYmFrLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiaW5kZXguYmFrLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLE9BQU8sQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDLE9BQU8sRUFBRSxDQUFBO0FBQ3ZDLE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDLFFBQVEsRUFBRSxDQUFBO0FBQ3BDLCtCQUF3RDtBQUV4RCxJQUFNLENBQUMsR0FBRyxPQUFPLENBQUMsUUFBUSxDQUFDLENBQUE7QUFFM0IsZ0JBQWdCO0FBQ2hCLG9HQUFvRztBQUNwRyxnRUFBZ0U7QUFDaEUsK0RBQStEO0FBQy9ELDhDQUE4QztBQUM5QyxtREFBbUQ7QUFDbkQsbURBQW1EO0FBQ25ELDJCQUEyQjtBQUMzQixpQ0FBaUM7QUFDakMsMkJBQTJCO0FBQzNCLHFCQUFxQjtBQUNyQiwwREFBMEQ7QUFDMUQsYUFBYTtBQUNiLDJFQUEyRTtBQUMzRSw2REFBNkQ7QUFDN0QsUUFBUTtBQUNSLG1DQUFtQztBQUNuQyxJQUFJO0FBRUosc0JBQXNCO0FBQ3RCLE9BQU8sQ0FBQyxPQUFPLEdBQUcsVUFBZ0IsS0FBSyxFQUFFLE9BQU8sRUFBRSxRQUFROzs7Ozs7b0JBTWxELEdBQUcsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFBO29CQUV0Qyw2REFBNkQ7b0JBQzdELHVCQUF1QjtvQkFDdkIsTUFBTSxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sQ0FBQyxDQUFBO29CQUVuRCxRQUFRLEdBQUcsRUFBRSxDQUFBO29CQUNuQixJQUFJLE1BQU0sQ0FBQyxTQUFTLENBQUMsS0FBSyxNQUFNLElBQUksTUFBTSxDQUFDLFNBQVMsQ0FBQyxLQUFLLE1BQU0sRUFBRTt3QkFDOUQsb0NBQW9DO3dCQUNwQyxJQUFJLEdBQUcsQ0FBQyxPQUFPLENBQUMsTUFBTSxFQUFFOzRCQUNwQiw4REFBOEQ7NEJBQzlELFFBQVEsQ0FBQyw2QkFBNkIsQ0FBQyxHQUFHLEdBQUcsQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFBOzRCQUM1RCxvRUFBb0U7eUJBQ3ZFO3dCQUNELFFBQVEsQ0FBQyxrQ0FBa0MsQ0FBQyxHQUFHLE1BQU0sQ0FBQTt3QkFDckQsUUFBUSxDQUFDLDhCQUE4QixDQUFDLEdBQUcsZ0RBQWdELENBQUE7d0JBQzNGLFFBQVEsQ0FBQyw4QkFBOEIsQ0FBQyxHQUFHLGVBQWUsQ0FBQTtxQkFDN0Q7b0JBRUQsK0JBQStCO29CQUMvQixRQUFRLEdBQUcsQ0FBQyxVQUFVLEVBQUU7d0JBQ3BCLEtBQUssS0FBSyxDQUFDO3dCQUNYLEtBQUssTUFBTTs0QkFDUCxNQUFLO3dCQUNULEtBQUssU0FBUzs0QkFDVixJQUFJLE1BQU0sQ0FBQyxTQUFTLENBQUMsSUFBSSxNQUFNLElBQUksTUFBTSxDQUFDLFNBQVMsQ0FBQyxJQUFJLE1BQU0sRUFBRTtnQ0FDNUQsZ0NBQWdDO2dDQUNoQyxRQUFRLENBQUMsSUFBSSxFQUFFO29DQUNYLFVBQVUsRUFBRSxHQUFHO2lDQUNsQixDQUFDLENBQUE7NkJBQ0w7aUNBQU07Z0NBQ0gsNEJBQTRCO2dDQUM1QixRQUFRLENBQUMsSUFBSSxFQUFFO29DQUNYLFVBQVUsRUFBRSxHQUFHO29DQUNmLE9BQU8sZUFDQSxRQUFRLENBQ2Q7aUNBQ0osQ0FBQyxDQUFBOzZCQUNMOzRCQUNELHNCQUFNO3dCQUNWOzRCQUNJLG9CQUFvQjs0QkFDcEIsUUFBUSxDQUFDLElBQUksRUFBRTtnQ0FDWCxVQUFVLEVBQUUsR0FBRzs2QkFDbEIsQ0FBQyxDQUFBOzRCQUNGLHNCQUFNO3FCQUNiO3lCQUdHLEdBQUcsQ0FBQyxhQUFhLENBQUMsRUFBbEIsd0JBQWtCO29CQUVWLEtBQUEsR0FBRyxDQUFDLGFBQWEsQ0FBQyxDQUFBOzs2QkFDakIsd0JBQXdCLENBQUMsQ0FBekIsd0JBQXdCOzs7OztvQkFHakIsT0FBTyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUE7b0JBQ3hDLE9BQU8sQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLElBQUksT0FBTyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUE7b0JBQzdDLHFCQUFNLEtBQUssQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLEVBQUUsT0FBTyxDQUFDLE9BQU8sQ0FBQyxFQUFFLFNBQVMsRUFBRSxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUMsRUFBQTs7b0JBQTVFLFNBQTRFLENBQUE7Ozs7b0JBRTVFLGVBQWU7b0JBQ2YsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLEtBQUcsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUE7O3dCQUUzRSx3QkFBSzt3QkFFYixzQkFBTTs7b0JBQ0gsSUFBSSxHQUFHLENBQUMsTUFBTSxDQUFDLEtBQUsseUJBQXlCLEVBQUU7d0JBQ2xELG9CQUFvQjt3QkFDcEIsc0JBQU07cUJBQ1Q7OztvQkFDRCxNQUFNLENBQUMsU0FBUyxDQUFDLEdBQUcsS0FBSyxDQUFDLFFBQVEsRUFBRSxDQUFBLENBQUMsNEJBQTRCO29CQUU3RCxPQUFPLEdBQUcsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsaUJBQWlCLEVBQUUsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDLGlDQUFpQztvQkFBbEMsQ0FBQTtvQkFFakQsT0FBTyxHQUFHLEdBQUcsQ0FBQyxTQUFTLENBQUMsQ0FBQyxtQkFBbUIsQ0FBQyxHQUFHLEtBQUssR0FBRyxHQUFHLENBQUMsU0FBUyxDQUFDLENBQUMsU0FBUyxDQUFDLEdBQUcsR0FBRyxDQUFDLE1BQU0sQ0FBQyxDQUFBO29CQUUvRixVQUFVLEdBQUcsR0FBRyxDQUFDLFNBQVMsQ0FBQyxDQUFBO29CQUUzQixLQUFLLEdBQUcsTUFBTSxDQUFDLE1BQU0sQ0FDckIsRUFBQyxPQUFPLFNBQUEsRUFBRSxPQUFPLFNBQUEsRUFBRSxVQUFVLFlBQUEsRUFBQyxFQUFFLDhDQUE4QztvQkFDOUUsR0FBRyxDQUFDLGNBQWMsSUFBSSxFQUFFLEVBQUUsd0NBQXdDO29CQUNsRSxHQUFHLENBQUMsZUFBZSxJQUFJLEVBQUUsQ0FBQyw4QkFBOEI7cUJBQzNELENBQUE7b0JBQ0csR0FBRyxHQUFHLEVBQUUsQ0FBQTtvQkFZSixLQUFBLEdBQUcsQ0FBQyxVQUFVLENBQUE7OzZCQUNiLEtBQUssQ0FBQyxDQUFOLHdCQUFLOzZCQUVMLE1BQU0sQ0FBQyxDQUFQLHdCQUFNOzs7d0JBRFAseUJBQUs7OztvQkFJRyxJQUFJLEdBQUcsRUFBRSxDQUFBO29CQUNiLElBQUksQ0FBQyxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUU7d0JBQ2xCLElBQUksR0FBRyxHQUFHLENBQUMsSUFBSSxDQUFBO3dCQUNuQixJQUFJLEdBQUcsQ0FBQyxlQUFlLEVBQUU7NEJBQ3JCLElBQUksR0FBRyxJQUFJLE1BQU0sQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLFFBQVEsQ0FBQyxDQUFDLFFBQVEsRUFBRSxDQUFBO3lCQUNuRDt3QkFDRCxJQUFJLEdBQUcsdUJBQWdCLENBQUMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxFQUFFLElBQUksQ0FBQyxDQUFBO3FCQUNoRDtvQkFDRCxLQUFLLEdBQUcsTUFBTSxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUUsSUFBSSxDQUFDLENBQUEsQ0FBQyxtREFBbUQ7Ozs7b0JBRXRGLElBQUksQ0FBQyxLQUFHLEVBQUUsR0FBRyxDQUFDLFVBQVUsRUFBRSxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUE7b0JBQ25DLHFCQUFNLEtBQUssQ0FBQyxLQUFHLENBQUM7d0JBQ2hCLHFDQUFxQztzQkFEckI7O29CQUFoQixTQUFnQixDQUFBO29CQUNoQixxQ0FBcUM7b0JBQ3JDLFFBQVEsQ0FBQyxJQUFJLEVBQUU7d0JBQ1gsVUFBVSxFQUFFLEdBQUc7cUJBQ2xCLENBQUMsQ0FBQTtvQkFDRixzQkFBTTt5QkFFVix5QkFBSzs7b0JBRUwsSUFBSSxDQUFDLEdBQUcsQ0FBQyxVQUFVLEVBQUUsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFBO29CQUM5QixxQ0FBcUM7b0JBQ3JDLFFBQVEsQ0FBQyxJQUFJLEVBQUU7d0JBQ1gsVUFBVSxFQUFFLEdBQUc7cUJBQ2xCLENBQUMsQ0FBQTtvQkFDRixzQkFBTTs7O29CQUtOLE1BQU0sR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxTQUFTLENBQUMsRUFBRSxRQUFRLEVBQUUsU0FBUyxDQUFDLENBQUE7b0JBQ3ZELElBQUksQ0FBQyxNQUFNLEVBQUU7d0JBQ1QsTUFBTSxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxFQUFFLFFBQVEsRUFBRSxFQUFFLENBQUMsQ0FBQTtxQkFDL0M7b0JBQ0QsTUFBTSxDQUFDLHFCQUFxQixDQUFDLEdBQUcsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQTtvQkFFL0Qsb0JBQW9CO29CQUNwQixNQUFNLENBQUMsZ0JBQWdCLENBQUMsR0FBRyxHQUFHLENBQUMsU0FBUyxDQUFDLENBQUMsWUFBWSxDQUFDLENBQUE7b0JBQ3ZELGVBQWU7b0JBQ2YsTUFBTSxDQUFDLGVBQWUsQ0FBQyxHQUFHLEdBQUcsQ0FBQyxTQUFTLENBQUMsQ0FBQyxXQUFXLENBQUMsQ0FBQTtvQkFLL0MscUJBQU0sc0JBQWUsQ0FBQyxPQUFPLEVBQUUsS0FBSyxDQUFDO3dCQUUzQyx1QkFBdUI7c0JBRm9COztvQkFIM0MsdUZBQXVGO29CQUN2Rix3RUFBd0U7b0JBQ3hFLGtEQUFrRDtvQkFDbEQsR0FBRyxHQUFHLFNBQXFDLENBQUE7b0JBR3ZDLFNBQVMsR0FBRyxFQUFDLFlBQVksRUFBRSxTQUFTLEVBQUMsQ0FBQTtvQkFDekMsSUFBSSxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLHFCQUFxQixDQUFDLENBQUMsRUFBRTt3QkFDM0MsU0FBUyxDQUFDLFlBQVksQ0FBQyxHQUFHLENBQUMsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLHFCQUFxQixDQUFDLENBQUMsQ0FBQTtxQkFDcEU7b0JBRUQsSUFBSSxNQUFNLENBQUMsa0JBQWtCLENBQUMsRUFBRTt3QkFDNUIsUUFBUSxDQUFDLElBQUksRUFBRTs0QkFDWCxVQUFVLEVBQUUsR0FBRzs0QkFDZixPQUFPLGFBQ0gsVUFBVSxFQUFFLE1BQU0sQ0FBQyxrQkFBa0IsQ0FBQyxJQUNuQyxTQUFTLENBQ2Y7eUJBQ0osQ0FBQyxDQUFBO3dCQUNGLE1BQU0sQ0FBQyxrQkFBa0IsQ0FBQyxHQUFHLFNBQVMsQ0FBQTtxQkFDekM7eUJBQ0ksSUFBSSxDQUFDLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxFQUFFO3dCQUNsQixZQUFZLEdBQUc7NEJBQ2YsZUFBZSxFQUFFLElBQUk7NEJBQ3JCLFVBQVUsRUFBRSxHQUFHOzRCQUNmLE9BQU8sYUFDSCxjQUFjLEVBQUUsMEJBQTBCLElBQ3ZDLFNBQVMsRUFDVCxRQUFRLENBQ2Q7NEJBQ0QsZ0VBQWdFOzRCQUNoRSxJQUFJLEVBQUUsSUFBSSxNQUFNLENBQUMsR0FBYSxDQUFDLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQzt5QkFDckQsQ0FBQTt3QkFDRCxRQUFRLENBQUMsSUFBSSxFQUFFLFlBQVksQ0FBQyxDQUFBO3FCQUMvQjt5QkFBTTt3QkFDQyxZQUFZLEdBQUc7NEJBQ2YsZUFBZSxFQUFFLElBQUk7NEJBQ3JCLFVBQVUsRUFBRSxHQUFHOzRCQUNmLE9BQU8sYUFDSCxjQUFjLEVBQUUsa0JBQWtCLElBQy9CLFFBQVEsQ0FDZDs0QkFDRCxnRUFBZ0U7NEJBQ2hFLElBQUksRUFBRSxJQUFJLE1BQU0sQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQzt5QkFDM0QsQ0FBQTt3QkFDRCxRQUFRLENBQUMsSUFBSSxFQUFFLFlBQVksQ0FBQyxDQUFBO3FCQUMvQjs7OztvQkFFRCxvRUFBb0U7b0JBQ3BFLHFCQUFNLEtBQUssQ0FBQzs0QkFDUixPQUFPLFNBQUEsRUFBRSxPQUFPLFNBQUEsRUFBRSxLQUFLLE9BQUEsRUFBRSxPQUFPLEVBQUUsS0FBRyxDQUFDLE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxDQUFDLEtBQUcsQ0FBQzt5QkFDcEUsQ0FBQzt3QkFDRiwyQ0FBMkM7c0JBRHpDOztvQkFIRixvRUFBb0U7b0JBQ3BFLFNBRUUsQ0FBQTtvQkFDRiwyQ0FBMkM7b0JBQzNDLFFBQVEsQ0FBQyxJQUFJLEVBQUUsRUFBQyxVQUFVLEVBQUUsR0FBRyxFQUFDLENBQUMsQ0FBQTs7Ozs7O0NBRXhDLENBQUE7QUFFRCwyRkFBMkY7QUFDM0YscUNBQXFDO0FBQ3JDLGlCQUFpQjtBQUNqQixxR0FBcUc7QUFDckcsdUJBQXVCO0FBQ3ZCLDBFQUEwRTtBQUMxRSxtR0FBbUc7QUFDbkcsaURBQWlEO0FBQ2pELGlEQUFpRDtBQUNqRCxhQUFhO0FBQ2IsZ0NBQWdDO0FBQ2hDLG1DQUFtQztBQUNuQyxzRkFBc0Y7QUFDdEYsZ0NBQWdDO0FBQ2hDLDhDQUE4QztBQUM5QyxTQUFTO0FBQ1QsbUJBQW1CO0FBQ25CLG1CQUFtQjtBQUNuQiwrREFBK0Q7QUFDL0QsMkJBQTJCO0FBQzNCLGlDQUFpQztBQUNqQyxxQ0FBcUM7QUFDckMsa0NBQWtDO0FBQ2xDLGFBQWE7QUFDYix3QkFBd0I7QUFDeEIsOEJBQThCO0FBQzlCLDBDQUEwQztBQUMxQyw2QkFBNkI7QUFDN0IsNkJBQTZCO0FBQzdCLGFBQWE7QUFDYix3QkFBd0I7QUFDeEIsaUNBQWlDO0FBQ2pDLGdDQUFnQztBQUNoQyw2QkFBNkI7QUFDN0IsYUFBYTtBQUNiLG1DQUFtQztBQUNuQywwQ0FBMEM7QUFDMUMsUUFBUTtBQUNSLElBQUk7QUFFSiw0QkFBNEI7QUFDNUIsb0JBQW9CO0FBQ3BCLHlCQUF5QjtBQUN6Qiw0REFBNEQ7QUFDNUQsMEVBQTBFO0FBQzFFLDRCQUE0QjtBQUM1QixnQ0FBZ0M7QUFDaEMsNkVBQTZFO0FBQzdFLHFDQUFxQztBQUNyQyxjQUFjO0FBQ2Qsd0NBQXdDO0FBQ3hDLHFEQUFxRDtBQUNyRCxZQUFZO0FBQ1osa0JBQWtCO0FBQ2xCLG1CQUFtQjtBQUNuQixzRUFBc0U7QUFDdEUsbTZCQUFtNkI7QUFDbjZCLHdDQUF3QztBQUN4QyxxSkFBcUo7QUFDckosNkRBQTZEO0FBQzdELGdEQUFnRDtBQUNoRCx3Q0FBd0M7QUFDeEMsNENBQTRDO0FBQzVDLCtDQUErQztBQUMvQyx1Q0FBdUM7QUFDdkMsa0RBQWtEO0FBQ2xELDhDQUE4QztBQUM5Qyx3Q0FBd0M7QUFDeEMsNEdBQTRHO0FBQzVHLFNBQVM7QUFDVCwyQkFBMkI7QUFDM0IsK0JBQStCO0FBQy9CLHVCQUF1QjtBQUN2Qiw0QkFBNEI7QUFDNUIsNEJBQTRCO0FBQzVCLElBQUkiLCJzb3VyY2VzQ29udGVudCI6WyJyZXF1aXJlKCdzb3VyY2UtbWFwLXN1cHBvcnQnKS5pbnN0YWxsKClcbnJlcXVpcmUoJ3RzY29uZmlnLXBhdGhzJykucmVnaXN0ZXIoKVxuaW1wb3J0IHtyZXF1ZXN0X3Byb2Nlc3MsIHBhcnNlX3Bvc3RfcGFyYW19IGZyb20gJy4vaW5pdCdcblxuY29uc3QgXyA9IHJlcXVpcmUoJ2xvZGFzaCcpXG5cbi8vIC8vIOS4tOaXtuiwg+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 |