UNPKG

67.3 kBJavaScriptView Raw
1import { __decorate, __metadata, __awaiter } from 'tslib';
2import { forwardRef, Injectable, InjectionToken, Component, NgModule } from '@angular/core';
3import { Type, plainToClass } from 'class-transformer';
4import { Router, ActivatedRoute, RouterModule } from '@angular/router';
5import { Storage, UbudStorageModule } from '@ubud/storage';
6import { forkJoin, Observable, of } from 'rxjs';
7import { fromPromise } from 'rxjs/internal/observable/fromPromise';
8import { catchError, map, switchMap, tap, first } from 'rxjs/internal/operators';
9import { HttpClient } from '@angular/common/http';
10import { Location, PlatformLocation } from '@angular/common';
11import { ErrorObservable } from 'rxjs-compat/observable/ErrorObservable';
12
13/**
14 * @fileoverview added by tsickle
15 * @suppress {checkTypes} checked by tsc
16 */
17class Config {
18 /**
19 * @param {?=} data
20 */
21 constructor(data) {
22 this.endpoint = 'https://account.kemnaker.go.id';
23 Object.assign(this, data);
24 }
25}
26
27/**
28 * @fileoverview added by tsickle
29 * @suppress {checkTypes} checked by tsc
30 */
31class User {
32}
33__decorate([
34 Type(/** @type {?} */ (forwardRef(() => Date))),
35 __metadata("design:type", Date)
36], User.prototype, "updatedAt", void 0);
37
38/**
39 * @fileoverview added by tsickle
40 * @suppress {checkTypes} checked by tsc
41 */
42class NacoService {
43 /**
44 * @param {?} config
45 * @param {?} router
46 * @param {?} storage
47 * @param {?} http
48 * @param {?} location
49 */
50 constructor(config, router, storage, http, location) {
51 this.config = config;
52 this.router = router;
53 this.storage = storage;
54 this.http = http;
55 this.location = location;
56 this.VERSION = 'v1';
57 this.signature = null;
58 this.user = null;
59 this.refreshToken = null;
60 this.clientSecret = null;
61 }
62 /**
63 * @param {?} user
64 * @return {?}
65 */
66 setUser(user) {
67 this.user = user;
68 this.storage.set('user', user);
69 }
70 /**
71 * @return {?}
72 */
73 getUser() {
74 if (null !== this.user) {
75 return of(this.user);
76 }
77 return fromPromise(this.storage.get('user')).pipe(switchMap((user) => {
78 if (null !== user) {
79 return of(user);
80 }
81 const /** @type {?} */ uri = this.getUri('/users/me');
82 return fromPromise(this.getSignature()).pipe(switchMap((signature) => {
83 if (null === signature) {
84 return of(null);
85 }
86 const /** @type {?} */ options = {
87 headers: {
88 Authorization: `${signature.type} ${signature.token}`,
89 },
90 };
91 return this.http.get(uri, options).pipe(map((res) => {
92 if (res.data) {
93 return res.data;
94 }
95 throw new Error('There are no body to be transformed');
96 }), map((data) => {
97 const /** @type {?} */ authUser = plainToClass(User, data);
98 this.setUser(authUser);
99 return authUser;
100 }), catchError((e) => {
101 if (401 === e.status) {
102 return this.refreshUser().pipe(switchMap((refreshUser) => {
103 if (refreshUser) {
104 return of(refreshUser);
105 }
106 return ErrorObservable.create(e);
107 }));
108 }
109 return ErrorObservable.create(e);
110 }));
111 }));
112 }));
113 }
114 /**
115 * @return {?}
116 */
117 getSignature() {
118 if (null !== this.signature) {
119 return Promise.resolve(this.signature);
120 }
121 return this.storage.get('signature');
122 }
123 /**
124 * @param {?} signature
125 * @return {?}
126 */
127 setSignature(signature) {
128 this.signature = signature;
129 this.storage.set('signature', signature);
130 }
131 /**
132 * @param {?} secret
133 * @return {?}
134 */
135 setClientSecret(secret) {
136 this.clientSecret = secret;
137 this.storage.set('client_secret', secret);
138 }
139 /**
140 * @param {?} refreshToken
141 * @return {?}
142 */
143 setRefreshToken(refreshToken) {
144 this.refreshToken = refreshToken;
145 this.storage.set('refresh_token', refreshToken);
146 }
147 /**
148 * @param {?=} scopes
149 * @return {?}
150 */
151 refreshUser(scopes) {
152 this.setUser(null);
153 this.setSignature(null);
154 return forkJoin(this.getRefreshToken(), this.getClientSecret()).pipe(switchMap((results) => {
155 const /** @type {?} */ refreshToken = results[0];
156 const /** @type {?} */ clientSecret = results[1];
157 if (refreshToken && clientSecret) {
158 return this.refreshWithRefreshToken(clientSecret, refreshToken.token, scopes);
159 }
160 return this.refreshWithSilentAuth();
161 }));
162 }
163 /**
164 * @param {?} clientSecret
165 * @param {?} refreshToken
166 * @param {?=} scopes
167 * @return {?}
168 */
169 refreshWithRefreshToken(clientSecret, refreshToken, scopes) {
170 const /** @type {?} */ request = this.http.post(this.getUri('/tokens'), {
171 grant_type: 'refresh_token',
172 scopes: scopes || 'basic email',
173 client_id: this.config.clientId,
174 client_secret: clientSecret,
175 refresh_token: refreshToken,
176 });
177 return request.pipe(tap((tokens) => {
178 if (tokens && tokens.data) {
179 this.setSignature({
180 expiresIn: tokens.data.expires_in,
181 type: tokens.data.token_type,
182 token: tokens.data.access_token,
183 });
184 this.setRefreshToken({
185 type: tokens.data.token_type,
186 token: tokens.data.refresh_token,
187 });
188 }
189 }), map((tokens) => tokens && tokens.data), switchMap((hasToken) => {
190 if (hasToken) {
191 return this.getUser();
192 }
193 return of(null);
194 }));
195 }
196 /**
197 * @return {?}
198 */
199 refreshWithSilentAuth() {
200 return new Observable((observer) => {
201 const /** @type {?} */ redirectUri = this.getCurrentOrigin('auth/silent');
202 const /** @type {?} */ uri = this.login('basic email', redirectUri);
203 const /** @type {?} */ iframe = document.createElement('iframe');
204 iframe.setAttribute('src', uri);
205 iframe.style.display = 'none';
206 iframe.addEventListener('load', () => __awaiter(this, void 0, void 0, function* () {
207 try {
208 const /** @type {?} */ queryString = iframe.contentWindow.location.search.substring(1);
209 iframe.parentNode.removeChild(iframe);
210 if (queryString) {
211 const /** @type {?} */ queryParts = queryString.split('&');
212 const /** @type {?} */ params = {};
213 for (const /** @type {?} */ item of queryParts) {
214 const /** @type {?} */ itemParts = item.split('=');
215 params[itemParts[0]] = itemParts[1];
216 }
217 if (params.hasOwnProperty('access_token')) {
218 const /** @type {?} */ state = params['state'] || null;
219 if (state !== (yield this.getState())) {
220 observer.next(null);
221 return;
222 }
223 this.setSignature({
224 token: params['access_token'],
225 type: params['token_type'],
226 expiresIn: params['ttl'],
227 });
228 const /** @type {?} */ user = yield this.getUser().toPromise();
229 if (user) {
230 this.setUser(user);
231 }
232 observer.next(user);
233 }
234 else {
235 observer.next(null);
236 }
237 return;
238 }
239 observer.next(null);
240 }
241 catch (/** @type {?} */ e) {
242 observer.next(null);
243 }
244 }), false);
245 document.body.appendChild(iframe);
246 });
247 }
248 /**
249 * @param {?} scopes
250 * @param {?=} redirectUri
251 * @return {?}
252 */
253 login(scopes, redirectUri) {
254 if (!redirectUri) {
255 redirectUri = this.router.url;
256 }
257 const /** @type {?} */ state = this.generateState();
258 this.storage.set('state', state);
259 const /** @type {?} */ query = this.buildQueryString({
260 'response_type': 'token',
261 'scopes': scopes,
262 'client': this.config.clientId,
263 'state': state,
264 'continue': redirectUri,
265 });
266 return this.config.endpoint + '/auth?' + query;
267 }
268 /**
269 * @param {?=} redirectUri
270 * @return {?}
271 */
272 logout(redirectUri) {
273 this.signature = null;
274 this.user = null;
275 return new Promise(resolve => {
276 Promise.all([
277 this.storage.remove('signature'),
278 this.storage.remove('user'),
279 ]).then(() => {
280 let /** @type {?} */ endpoint = this.config.endpoint + '/auth/logout';
281 if (redirectUri) {
282 endpoint += '?continue=' + redirectUri;
283 }
284 resolve(endpoint);
285 });
286 });
287 }
288 /**
289 * @return {?}
290 */
291 getState() {
292 return this.storage.get('state');
293 }
294 /**
295 * @param {?} route
296 * @return {?}
297 */
298 buildNestedUri(route) {
299 let /** @type {?} */ uri = '';
300 if (route.routeConfig && route.routeConfig.path) {
301 uri += '/' + route.routeConfig.path;
302 }
303 if (route.children) {
304 route.children.forEach((item) => {
305 uri += this.buildNestedUri(item);
306 });
307 }
308 return uri;
309 }
310 /**
311 * @return {?}
312 */
313 getRefreshToken() {
314 if (null !== this.refreshToken) {
315 return Promise.resolve(this.refreshToken);
316 }
317 return this.storage.get('refresh_token');
318 }
319 /**
320 * @return {?}
321 */
322 getClientSecret() {
323 if (null !== this.clientSecret) {
324 return Promise.resolve(this.clientSecret);
325 }
326 return this.storage.get('client_secret');
327 }
328 /**
329 * @param {?} path
330 * @return {?}
331 */
332 getUri(path) {
333 return this.config.endpoint + '/api/' + this.VERSION + path;
334 }
335 /**
336 * @param {?=} path
337 * @return {?}
338 */
339 getCurrentOrigin(path) {
340 return window.location.origin + this.location.prepareExternalUrl(path || '');
341 }
342 /**
343 * @return {?}
344 */
345 generateState() {
346 const /** @type {?} */ possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
347 let /** @type {?} */ text = '';
348 for (let /** @type {?} */ i = 0; i < 5; i++) {
349 text += possible.charAt(Math.floor(Math.random() * possible.length));
350 }
351 return text;
352 }
353 /**
354 * @param {?} params
355 * @return {?}
356 */
357 buildQueryString(params) {
358 const /** @type {?} */ queryParams = Object.keys(params).map((key) => {
359 return encodeURIComponent(key) + '=' + encodeURIComponent(params[key]);
360 });
361 return queryParams.join('&');
362 }
363}
364NacoService.decorators = [
365 { type: Injectable },
366];
367/** @nocollapse */
368NacoService.ctorParameters = () => [
369 { type: Config },
370 { type: Router },
371 { type: Storage },
372 { type: HttpClient },
373 { type: Location }
374];
375
376/**
377 * @fileoverview added by tsickle
378 * @suppress {checkTypes} checked by tsc
379 */
380class Signature {
381}
382
383/**
384 * @fileoverview added by tsickle
385 * @suppress {checkTypes} checked by tsc
386 */
387class AuthenticatedGuard {
388 /**
389 * @param {?} naco
390 * @param {?} storage
391 * @param {?} platformLocation
392 */
393 constructor(naco, storage, platformLocation) {
394 this.naco = naco;
395 this.storage = storage;
396 this.platformLocation = platformLocation;
397 }
398 /**
399 * @param {?} route
400 * @return {?}
401 */
402 canActivate(route) {
403 return this.naco.getUser().pipe(first(), map((user) => {
404 if (null === user) {
405 const /** @type {?} */ base = this.rtrim((/** @type {?} */ (this.platformLocation)).location.href);
406 const /** @type {?} */ uri = this.naco.buildNestedUri(route.root);
407 const /** @type {?} */ next = base.replace(uri, '') + '/' + this.ltrim(uri);
408 const /** @type {?} */ origin = base.replace(uri, '');
409 this.storage.set('naco_intended_url', next).then(() => {
410 window.location.href = this.naco.login('basic email', origin + '/auth');
411 });
412 }
413 return !!user;
414 }));
415 }
416 /**
417 * @param {?} route
418 * @return {?}
419 */
420 canActivateChild(route) {
421 return this.canActivate(route);
422 }
423 /**
424 * @param {?} text
425 * @return {?}
426 */
427 ltrim(text) {
428 return text.replace(/^\/+/, '');
429 }
430 /**
431 * @param {?} text
432 * @return {?}
433 */
434 rtrim(text) {
435 return text.replace(/\/+$/, '');
436 }
437}
438AuthenticatedGuard.decorators = [
439 { type: Injectable },
440];
441/** @nocollapse */
442AuthenticatedGuard.ctorParameters = () => [
443 { type: NacoService },
444 { type: Storage },
445 { type: PlatformLocation }
446];
447
448/**
449 * @fileoverview added by tsickle
450 * @suppress {checkTypes} checked by tsc
451 */
452class AuthInterceptor {
453 /**
454 * @param {?} naco
455 */
456 constructor(naco) {
457 this.naco = naco;
458 }
459 /**
460 * @param {?} req
461 * @param {?} next
462 * @return {?}
463 */
464 intercept(req, next) {
465 return fromPromise(this.naco.getSignature()).pipe(switchMap((signature) => {
466 if (!signature) {
467 return next.handle(req);
468 }
469 return next
470 .handle(req.clone({
471 setHeaders: {
472 Authorization: `${signature.type} ${signature.token}`,
473 },
474 }))
475 .pipe(catchError((error) => {
476 if (error.status === 401) {
477 return this.naco.refreshUser().pipe(switchMap((user) => {
478 if (user) {
479 return fromPromise(this.naco.getSignature()).pipe(switchMap((newSignature) => {
480 return next.handle(req.clone({
481 setHeaders: {
482 Authorization: `${newSignature.type} ${newSignature.token}`,
483 },
484 }));
485 }));
486 }
487 return ErrorObservable.create(error);
488 }));
489 }
490 return ErrorObservable.create(error);
491 }));
492 }));
493 }
494}
495AuthInterceptor.decorators = [
496 { type: Injectable },
497];
498/** @nocollapse */
499AuthInterceptor.ctorParameters = () => [
500 { type: NacoService }
501];
502
503/**
504 * @fileoverview added by tsickle
505 * @suppress {checkTypes} checked by tsc
506 */
507/**
508 * @param {?} config
509 * @param {?} router
510 * @param {?} storage
511 * @param {?} http
512 * @param {?} location
513 * @return {?}
514 */
515function nacoFactory(config, router, storage, http, location) {
516 return new NacoService(new Config(Object.assign({}, config)), router, storage, http, location);
517}
518const /** @type {?} */ NACO_CONFIG = new InjectionToken('NACO_CONFIG');
519
520/**
521 * @fileoverview added by tsickle
522 * @suppress {checkTypes} checked by tsc
523 */
524class AuthPage {
525 /**
526 * @param {?} route
527 * @param {?} naco
528 * @param {?} storage
529 */
530 constructor(route, naco, storage) {
531 this.route = route;
532 this.naco = naco;
533 this.storage = storage;
534 this.message = 'Authenticating...';
535 this.route.queryParams.subscribe((params) => this.handle(params));
536 }
537 /**
538 * @param {?} params
539 * @return {?}
540 */
541 handle(params) {
542 if (params["state"]) {
543 this.naco.getState().then((state) => {
544 if (state !== params["state"]) {
545 this.message = 'Invalid CSRF';
546 return;
547 }
548 this.authenticate(params);
549 });
550 }
551 else {
552 this.authenticate(params);
553 }
554 }
555 /**
556 * @param {?} params
557 * @return {?}
558 */
559 authenticate(params) {
560 const /** @type {?} */ signature = {
561 expiresIn: params["expires_in"],
562 type: params["token_type"],
563 token: params["access_token"],
564 };
565 this.naco.setSignature(signature);
566 this.naco.getUser().subscribe((user) => {
567 if (null !== user) {
568 this.storage.get('naco_intended_url').then((url) => {
569 this.storage.remove('naco_intended_url').then(() => {
570 window.location.href = url ? url : '/';
571 });
572 });
573 return;
574 }
575 this.message = 'Unauthenticated!';
576 });
577 }
578}
579AuthPage.decorators = [
580 { type: Component, args: [{
581 selector: 'naker-auth-page',
582 template: '{{ message }}',
583 },] },
584];
585/** @nocollapse */
586AuthPage.ctorParameters = () => [
587 { type: ActivatedRoute },
588 { type: NacoService },
589 { type: Storage }
590];
591
592/**
593 * @fileoverview added by tsickle
594 * @suppress {checkTypes} checked by tsc
595 */
596class AuthSilentPage {
597}
598AuthSilentPage.decorators = [
599 { type: Component, args: [{
600 selector: 'naker-auth-silent',
601 template: 'Processing silent auth...',
602 },] },
603];
604
605/**
606 * @fileoverview added by tsickle
607 * @suppress {checkTypes} checked by tsc
608 */
609const /** @type {?} */ routes = [
610 {
611 path: 'auth',
612 component: AuthPage
613 },
614 {
615 path: 'auth/silent',
616 component: AuthSilentPage
617 },
618];
619const /** @type {?} */ AUTH_ROUTING = RouterModule.forChild(routes);
620
621/**
622 * @fileoverview added by tsickle
623 * @suppress {checkTypes} checked by tsc
624 */
625class NacoViewModule {
626}
627NacoViewModule.decorators = [
628 { type: NgModule, args: [{
629 imports: [
630 AUTH_ROUTING,
631 ],
632 declarations: [
633 AuthPage,
634 AuthSilentPage,
635 ],
636 },] },
637];
638
639/**
640 * @fileoverview added by tsickle
641 * @suppress {checkTypes} checked by tsc
642 */
643class NacoModule {
644 /**
645 * @param {?} config
646 * @return {?}
647 */
648 static forRoot(config) {
649 return {
650 ngModule: NacoModule,
651 providers: [
652 {
653 provide: NACO_CONFIG,
654 useValue: config,
655 },
656 {
657 provide: NacoService,
658 useFactory: nacoFactory,
659 deps: [NACO_CONFIG, Router, Storage, HttpClient, Location],
660 },
661 AuthenticatedGuard,
662 ],
663 };
664 }
665}
666NacoModule.decorators = [
667 { type: NgModule, args: [{
668 imports: [
669 UbudStorageModule,
670 NacoViewModule,
671 ],
672 },] },
673];
674
675/**
676 * @fileoverview added by tsickle
677 * @suppress {checkTypes} checked by tsc
678 */
679
680/**
681 * @fileoverview added by tsickle
682 * @suppress {checkTypes} checked by tsc
683 */
684
685export { NacoService, User, Signature, Config, AuthenticatedGuard, AuthInterceptor, NacoModule, NACO_CONFIG as ɵf, nacoFactory as ɵe, NacoViewModule as ɵa, AuthSilentPage as ɵd, AuthPage as ɵc, AUTH_ROUTING as ɵb };
686
687//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmFrZXItbmFjby5qcy5tYXAiLCJzb3VyY2VzIjpbIm5nOi8vQG5ha2VyL25hY28vZG9tYWlucy92YWx1ZXMvY29uZmlnLnRzIiwibmc6Ly9AbmFrZXIvbmFjby9kb21haW5zL21vZGVscy91c2VyLnRzIiwibmc6Ly9AbmFrZXIvbmFjby9kb21haW5zL3NlcnZpY2VzL25hY28uc2VydmljZS50cyIsIm5nOi8vQG5ha2VyL25hY28vZG9tYWlucy92YWx1ZXMvc2lnbmF0dXJlLnRzIiwibmc6Ly9AbmFrZXIvbmFjby9ndWFyZHMvYXV0aGVudGljYXRlZC5ndWFyZC50cyIsIm5nOi8vQG5ha2VyL25hY28vaW50ZXJjZXB0b3JzL2F1dGguaW50ZXJjZXB0b3IudHMiLCJuZzovL0BuYWtlci9uYWNvL2ZhY3Rvcmllcy9uYWNvLWZhY3RvcnkudHMiLCJuZzovL0BuYWtlci9uYWNvL3ZpZXdzL3BhZ2VzL2F1dGgucGFnZS50cyIsIm5nOi8vQG5ha2VyL25hY28vdmlld3MvcGFnZXMvYXV0aC1zaWxlbnQucGFnZS50cyIsIm5nOi8vQG5ha2VyL25hY28vdmlld3Mvcm91dGVzLnRzIiwibmc6Ly9AbmFrZXIvbmFjby92aWV3cy9tb2R1bGUudHMiLCJuZzovL0BuYWtlci9uYWNvL25hY28ubW9kdWxlLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCBjbGFzcyBDb25maWcge1xuICAgIHB1YmxpYyBlbmRwb2ludDogc3RyaW5nID0gJ2h0dHBzOi8vYWNjb3VudC5rZW1uYWtlci5nby5pZCc7XG4gICAgcHVibGljIGNsaWVudElkOiBzdHJpbmc7XG5cbiAgICBwdWJsaWMgY29uc3RydWN0b3IoZGF0YT86IFBhcnRpYWw8Q29uZmlnPikge1xuICAgICAgICBPYmplY3QuYXNzaWduKHRoaXMsIGRhdGEpO1xuICAgIH1cbn1cbiIsImltcG9ydCB7IGZvcndhcmRSZWYgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IFR5cGUgfSBmcm9tICdjbGFzcy10cmFuc2Zvcm1lcic7XG5cbmV4cG9ydCBjbGFzcyBVc2VyIHtcbiAgICBwdWJsaWMgaWQ6IHN0cmluZztcbiAgICBwdWJsaWMgdXNlcm5hbWU6IHN0cmluZztcbiAgICBwdWJsaWMgZW1haWw/OiBzdHJpbmc7XG4gICAgcHVibGljIG5hbWU6IHN0cmluZztcbiAgICBwdWJsaWMgc3RhdHVzOiBudW1iZXI7XG5cbiAgICBAVHlwZShmb3J3YXJkUmVmKCgpID0+IERhdGUpIGFzIGFueSlcbiAgICBwdWJsaWMgdXBkYXRlZEF0OiBEYXRlO1xufVxuIiwiaW1wb3J0IHsgSW5qZWN0YWJsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgQWN0aXZhdGVkUm91dGVTbmFwc2hvdCwgUm91dGVyIH0gZnJvbSAnQGFuZ3VsYXIvcm91dGVyJztcbmltcG9ydCB7IFN0b3JhZ2UgfSBmcm9tICdAdWJ1ZC9zdG9yYWdlJztcbmltcG9ydCB7IENvbmZpZyB9IGZyb20gJy4uL3ZhbHVlcy9jb25maWcnO1xuaW1wb3J0IHsgVXNlciB9IGZyb20gJy4uL21vZGVscy91c2VyJztcbmltcG9ydCB7IGZvcmtKb2luLCBPYnNlcnZhYmxlLCBPYnNlcnZlciwgb2YgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IFNpZ25hdHVyZSB9IGZyb20gJy4uL3ZhbHVlcy9zaWduYXR1cmUnO1xuaW1wb3J0IHsgZnJvbVByb21pc2UgfSBmcm9tICdyeGpzL2ludGVybmFsL29ic2VydmFibGUvZnJvbVByb21pc2UnO1xuaW1wb3J0IHsgY2F0Y2hFcnJvciwgbWFwLCBzd2l0Y2hNYXAsIHRhcCB9IGZyb20gJ3J4anMvaW50ZXJuYWwvb3BlcmF0b3JzJztcbmltcG9ydCB7IHBsYWluVG9DbGFzcyB9IGZyb20gJ2NsYXNzLXRyYW5zZm9ybWVyJztcbmltcG9ydCB7IEh0dHBDbGllbnQsIEh0dHBFcnJvclJlc3BvbnNlIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uL2h0dHAnO1xuaW1wb3J0IHsgTG9jYXRpb24gfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHsgRXJyb3JPYnNlcnZhYmxlIH0gZnJvbSAncnhqcy1jb21wYXQvb2JzZXJ2YWJsZS9FcnJvck9ic2VydmFibGUnO1xuXG5ASW5qZWN0YWJsZSgpXG5leHBvcnQgY2xhc3MgTmFjb1NlcnZpY2Uge1xuICAgIHB1YmxpYyByZWFkb25seSBWRVJTSU9OID0gJ3YxJztcblxuICAgIHByaXZhdGUgc2lnbmF0dXJlOiBTaWduYXR1cmUgfCBudWxsID0gbnVsbDtcbiAgICBwcml2YXRlIHVzZXI6IFVzZXIgfCBudWxsID0gbnVsbDtcbiAgICBwcml2YXRlIHJlZnJlc2hUb2tlbjogU2lnbmF0dXJlIHwgbnVsbCA9IG51bGw7XG4gICAgcHJpdmF0ZSBjbGllbnRTZWNyZXQ6IHN0cmluZyB8IG51bGwgPSBudWxsO1xuXG4gICAgcHVibGljIGNvbnN0cnVjdG9yKHByaXZhdGUgY29uZmlnOiBDb25maWcsIHByaXZhdGUgcm91dGVyOiBSb3V0ZXIsIHByaXZhdGUgc3RvcmFnZTogU3RvcmFnZSwgcHJpdmF0ZSBodHRwOiBIdHRwQ2xpZW50LCBwcml2YXRlIGxvY2F0aW9uOiBMb2NhdGlvbikge1xuICAgIH1cblxuICAgIHB1YmxpYyBzZXRVc2VyKHVzZXI6IFVzZXIgfCBudWxsKTogdm9pZCB7XG4gICAgICAgIHRoaXMudXNlciA9IHVzZXI7XG4gICAgICAgIHRoaXMuc3RvcmFnZS5zZXQoJ3VzZXInLCB1c2VyKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0VXNlcigpOiBPYnNlcnZhYmxlPFVzZXIgfCBudWxsPiB7XG4gICAgICAgIGlmIChudWxsICE9PSB0aGlzLnVzZXIpIHtcbiAgICAgICAgICAgIHJldHVybiBvZih0aGlzLnVzZXIpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGZyb21Qcm9taXNlKHRoaXMuc3RvcmFnZS5nZXQoJ3VzZXInKSkucGlwZShcbiAgICAgICAgICAgIHN3aXRjaE1hcCgodXNlcjogVXNlciB8IG51bGwpID0+IHtcbiAgICAgICAgICAgICAgICBpZiAobnVsbCAhPT0gdXNlcikge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gb2YodXNlcik7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgY29uc3QgdXJpID0gdGhpcy5nZXRVcmkoJy91c2Vycy9tZScpO1xuXG4gICAgICAgICAgICAgICAgcmV0dXJuIGZyb21Qcm9taXNlKHRoaXMuZ2V0U2lnbmF0dXJlKCkpLnBpcGUoXG4gICAgICAgICAgICAgICAgICAgIHN3aXRjaE1hcCgoc2lnbmF0dXJlOiBTaWduYXR1cmUgfCBudWxsKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAobnVsbCA9PT0gc2lnbmF0dXJlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG9mKG51bGwpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBvcHRpb25zID0ge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQXV0aG9yaXphdGlvbjogYCR7c2lnbmF0dXJlLnR5cGV9ICR7c2lnbmF0dXJlLnRva2VufWAsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLmh0dHAuZ2V0PGFueT4odXJpLCBvcHRpb25zKS5waXBlKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcCgocmVzOiBhbnkpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHJlcy5kYXRhKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gcmVzLmRhdGE7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1RoZXJlIGFyZSBubyBib2R5IHRvIGJlIHRyYW5zZm9ybWVkJyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwKChkYXRhOiBhbnkpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgYXV0aFVzZXI6IGFueSA9IHBsYWluVG9DbGFzcyhVc2VyLCBkYXRhKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnNldFVzZXIoYXV0aFVzZXIpO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBhdXRoVXNlcjtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYXRjaEVycm9yKChlOiBIdHRwRXJyb3JSZXNwb25zZSkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoNDAxID09PSBlLnN0YXR1cykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMucmVmcmVzaFVzZXIoKS5waXBlKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN3aXRjaE1hcCgocmVmcmVzaFVzZXI6IFVzZXIgfCBudWxsKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChyZWZyZXNoVXNlcikge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG9mKHJlZnJlc2hVc2VyKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBFcnJvck9ic2VydmFibGUuY3JlYXRlKGUpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBFcnJvck9ic2VydmFibGUuY3JlYXRlKGUpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH0pLFxuICAgICAgICApO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXRTaWduYXR1cmUoKTogUHJvbWlzZTxTaWduYXR1cmUgfCBudWxsPiB7XG4gICAgICAgIGlmIChudWxsICE9PSB0aGlzLnNpZ25hdHVyZSkge1xuICAgICAgICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSh0aGlzLnNpZ25hdHVyZSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gdGhpcy5zdG9yYWdlLmdldCgnc2lnbmF0dXJlJyk7XG4gICAgfVxuXG4gICAgcHVibGljIHNldFNpZ25hdHVyZShzaWduYXR1cmU6IFNpZ25hdHVyZSk6IHZvaWQge1xuICAgICAgICB0aGlzLnNpZ25hdHVyZSA9IHNpZ25hdHVyZTtcbiAgICAgICAgdGhpcy5zdG9yYWdlLnNldCgnc2lnbmF0dXJlJywgc2lnbmF0dXJlKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgc2V0Q2xpZW50U2VjcmV0KHNlY3JldDogc3RyaW5nKTogdm9pZCB7XG4gICAgICAgIHRoaXMuY2xpZW50U2VjcmV0ID0gc2VjcmV0O1xuICAgICAgICB0aGlzLnN0b3JhZ2Uuc2V0KCdjbGllbnRfc2VjcmV0Jywgc2VjcmV0KTtcbiAgICB9XG5cbiAgICBwdWJsaWMgc2V0UmVmcmVzaFRva2VuKHJlZnJlc2hUb2tlbjogU2lnbmF0dXJlKTogdm9pZCB7XG4gICAgICAgIHRoaXMucmVmcmVzaFRva2VuID0gcmVmcmVzaFRva2VuO1xuICAgICAgICB0aGlzLnN0b3JhZ2Uuc2V0KCdyZWZyZXNoX3Rva2VuJywgcmVmcmVzaFRva2VuKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgcmVmcmVzaFVzZXIoc2NvcGVzPzogc3RyaW5nKTogT2JzZXJ2YWJsZTxVc2VyIHwgbnVsbD4ge1xuICAgICAgICB0aGlzLnNldFVzZXIobnVsbCk7XG4gICAgICAgIHRoaXMuc2V0U2lnbmF0dXJlKG51bGwpO1xuXG4gICAgICAgIHJldHVybiBmb3JrSm9pbih0aGlzLmdldFJlZnJlc2hUb2tlbigpLCB0aGlzLmdldENsaWVudFNlY3JldCgpKS5waXBlKFxuICAgICAgICAgICAgc3dpdGNoTWFwKChyZXN1bHRzOiBhbnkpID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCByZWZyZXNoVG9rZW46IFNpZ25hdHVyZSA9IHJlc3VsdHNbMF07XG4gICAgICAgICAgICAgICAgY29uc3QgY2xpZW50U2VjcmV0OiBzdHJpbmcgPSByZXN1bHRzWzFdO1xuXG4gICAgICAgICAgICAgICAgaWYgKHJlZnJlc2hUb2tlbiAmJiBjbGllbnRTZWNyZXQpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMucmVmcmVzaFdpdGhSZWZyZXNoVG9rZW4oY2xpZW50U2VjcmV0LCByZWZyZXNoVG9rZW4udG9rZW4sIHNjb3Blcyk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMucmVmcmVzaFdpdGhTaWxlbnRBdXRoKCk7XG4gICAgICAgICAgICB9KSxcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgcmVmcmVzaFdpdGhSZWZyZXNoVG9rZW4oY2xpZW50U2VjcmV0OiBzdHJpbmcsIHJlZnJlc2hUb2tlbjogc3RyaW5nLCBzY29wZXM/OiBzdHJpbmcpOiBPYnNlcnZhYmxlPFVzZXIgfCBudWxsPiB7XG4gICAgICAgIGNvbnN0IHJlcXVlc3QgPSB0aGlzLmh0dHAucG9zdCh0aGlzLmdldFVyaSgnL3Rva2VucycpLCB7XG4gICAgICAgICAgICBncmFudF90eXBlOiAncmVmcmVzaF90b2tlbicsXG4gICAgICAgICAgICBzY29wZXM6IHNjb3BlcyB8fCAnYmFzaWMgZW1haWwnLFxuICAgICAgICAgICAgY2xpZW50X2lkOiB0aGlzLmNvbmZpZy5jbGllbnRJZCxcbiAgICAgICAgICAgIGNsaWVudF9zZWNyZXQ6IGNsaWVudFNlY3JldCxcbiAgICAgICAgICAgIHJlZnJlc2hfdG9rZW46IHJlZnJlc2hUb2tlbixcbiAgICAgICAgfSk7XG5cbiAgICAgICAgcmV0dXJuIHJlcXVlc3QucGlwZShcbiAgICAgICAgICAgIHRhcCgodG9rZW5zOiBhbnkpID0+IHtcbiAgICAgICAgICAgICAgICBpZiAodG9rZW5zICYmIHRva2Vucy5kYXRhKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuc2V0U2lnbmF0dXJlKHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGV4cGlyZXNJbjogdG9rZW5zLmRhdGEuZXhwaXJlc19pbixcbiAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU6IHRva2Vucy5kYXRhLnRva2VuX3R5cGUsXG4gICAgICAgICAgICAgICAgICAgICAgICB0b2tlbjogdG9rZW5zLmRhdGEuYWNjZXNzX3Rva2VuLFxuICAgICAgICAgICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgICAgICAgICB0aGlzLnNldFJlZnJlc2hUb2tlbih7XG4gICAgICAgICAgICAgICAgICAgICAgICB0eXBlOiB0b2tlbnMuZGF0YS50b2tlbl90eXBlLFxuICAgICAgICAgICAgICAgICAgICAgICAgdG9rZW46IHRva2Vucy5kYXRhLnJlZnJlc2hfdG9rZW4sXG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgbWFwKCh0b2tlbnM6IGFueSkgPT4gdG9rZW5zICYmIHRva2Vucy5kYXRhKSxcbiAgICAgICAgICAgIHN3aXRjaE1hcCgoaGFzVG9rZW46IGJvb2xlYW4pID0+IHtcbiAgICAgICAgICAgICAgICBpZiAoaGFzVG9rZW4pIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuZ2V0VXNlcigpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiBvZihudWxsKTtcbiAgICAgICAgICAgIH0pLFxuICAgICAgICApO1xuICAgIH1cblxuICAgIHB1YmxpYyByZWZyZXNoV2l0aFNpbGVudEF1dGgoKTogT2JzZXJ2YWJsZTxVc2VyIHwgbnVsbD4ge1xuICAgICAgICByZXR1cm4gbmV3IE9ic2VydmFibGU8VXNlciB8IG51bGw+KChvYnNlcnZlcjogT2JzZXJ2ZXI8VXNlciB8IG51bGw+KSA9PiB7XG4gICAgICAgICAgICBjb25zdCByZWRpcmVjdFVyaSA9IHRoaXMuZ2V0Q3VycmVudE9yaWdpbignYXV0aC9zaWxlbnQnKTtcbiAgICAgICAgICAgIGNvbnN0IHVyaSA9IHRoaXMubG9naW4oJ2Jhc2ljIGVtYWlsJywgcmVkaXJlY3RVcmkpO1xuXG4gICAgICAgICAgICBjb25zdCBpZnJhbWUgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdpZnJhbWUnKTtcbiAgICAgICAgICAgIGlmcmFtZS5zZXRBdHRyaWJ1dGUoJ3NyYycsIHVyaSk7XG4gICAgICAgICAgICBpZnJhbWUuc3R5bGUuZGlzcGxheSA9ICdub25lJztcblxuICAgICAgICAgICAgaWZyYW1lLmFkZEV2ZW50TGlzdGVuZXIoJ2xvYWQnLCBhc3luYyAoKSA9PiB7XG4gICAgICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgcXVlcnlTdHJpbmcgPSBpZnJhbWUuY29udGVudFdpbmRvdy5sb2NhdGlvbi5zZWFyY2guc3Vic3RyaW5nKDEpO1xuXG4gICAgICAgICAgICAgICAgICAgIGlmcmFtZS5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKGlmcmFtZSk7XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKHF1ZXJ5U3RyaW5nKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBxdWVyeVBhcnRzID0gcXVlcnlTdHJpbmcuc3BsaXQoJyYnKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHBhcmFtcyA9IHt9O1xuXG4gICAgICAgICAgICAgICAgICAgICAgICBmb3IgKGNvbnN0IGl0ZW0gb2YgcXVlcnlQYXJ0cykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGl0ZW1QYXJ0cyA9IGl0ZW0uc3BsaXQoJz0nKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFtc1tpdGVtUGFydHNbMF1dID0gaXRlbVBhcnRzWzFdO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAocGFyYW1zLmhhc093blByb3BlcnR5KCdhY2Nlc3NfdG9rZW4nKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHN0YXRlID0gcGFyYW1zWydzdGF0ZSddIHx8IG51bGw7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoc3RhdGUgIT09IGF3YWl0IHRoaXMuZ2V0U3RhdGUoKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvYnNlcnZlci5uZXh0KG51bGwpO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnNldFNpZ25hdHVyZSh7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRva2VuOiBwYXJhbXNbJ2FjY2Vzc190b2tlbiddLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlOiBwYXJhbXNbJ3Rva2VuX3R5cGUnXSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhwaXJlc0luOiBwYXJhbXNbJ3R0bCddLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgdXNlciA9IGF3YWl0IHRoaXMuZ2V0VXNlcigpLnRvUHJvbWlzZSgpO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHVzZXIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5zZXRVc2VyKHVzZXIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9ic2VydmVyLm5leHQodXNlcik7XG4gICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9ic2VydmVyLm5leHQobnVsbCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIG9ic2VydmVyLm5leHQobnVsbCk7XG4gICAgICAgICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICAgICAgICBvYnNlcnZlci5uZXh0KG51bGwpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0sIGZhbHNlKTtcblxuICAgICAgICAgICAgZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZChpZnJhbWUpO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBwdWJsaWMgbG9naW4oc2NvcGVzOiBzdHJpbmcsIHJlZGlyZWN0VXJpPzogc3RyaW5nKTogc3RyaW5nIHtcbiAgICAgICAgaWYgKCFyZWRpcmVjdFVyaSkge1xuICAgICAgICAgICAgcmVkaXJlY3RVcmkgPSB0aGlzLnJvdXRlci51cmw7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBzdGF0ZSA9IHRoaXMuZ2VuZXJhdGVTdGF0ZSgpO1xuXG4gICAgICAgIHRoaXMuc3RvcmFnZS5zZXQoJ3N0YXRlJywgc3RhdGUpO1xuXG4gICAgICAgIGNvbnN0IHF1ZXJ5OiBzdHJpbmcgPSB0aGlzLmJ1aWxkUXVlcnlTdHJpbmcoXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgJ3Jlc3BvbnNlX3R5cGUnOiAndG9rZW4nLFxuICAgICAgICAgICAgICAgICdzY29wZXMnOiBzY29wZXMsXG4gICAgICAgICAgICAgICAgJ2NsaWVudCc6IHRoaXMuY29uZmlnLmNsaWVudElkLFxuICAgICAgICAgICAgICAgICdzdGF0ZSc6IHN0YXRlLFxuICAgICAgICAgICAgICAgICdjb250aW51ZSc6IHJlZGlyZWN0VXJpLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgKTtcblxuICAgICAgICByZXR1cm4gdGhpcy5jb25maWcuZW5kcG9pbnQgKyAnL2F1dGg/JyArIHF1ZXJ5O1xuICAgIH1cblxuICAgIHB1YmxpYyBsb2dvdXQocmVkaXJlY3RVcmk/OiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgICAgICB0aGlzLnNpZ25hdHVyZSA9IG51bGw7XG4gICAgICAgIHRoaXMudXNlciA9IG51bGw7XG5cbiAgICAgICAgcmV0dXJuIG5ldyBQcm9taXNlKHJlc29sdmUgPT4ge1xuICAgICAgICAgICAgUHJvbWlzZS5hbGwoW1xuICAgICAgICAgICAgICAgIHRoaXMuc3RvcmFnZS5yZW1vdmUoJ3NpZ25hdHVyZScpLFxuICAgICAgICAgICAgICAgIHRoaXMuc3RvcmFnZS5yZW1vdmUoJ3VzZXInKSxcbiAgICAgICAgICAgIF0pLnRoZW4oKCkgPT4ge1xuICAgICAgICAgICAgICAgIGxldCBlbmRwb2ludCA9IHRoaXMuY29uZmlnLmVuZHBvaW50ICsgJy9hdXRoL2xvZ291dCc7XG5cbiAgICAgICAgICAgICAgICBpZiAocmVkaXJlY3RVcmkpIHtcbiAgICAgICAgICAgICAgICAgICAgZW5kcG9pbnQgKz0gJz9jb250aW51ZT0nICsgcmVkaXJlY3RVcmk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcmVzb2x2ZShlbmRwb2ludCk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgcHVibGljIGdldFN0YXRlKCk6IFByb21pc2U8c3RyaW5nIHwgbnVsbD4ge1xuICAgICAgICByZXR1cm4gdGhpcy5zdG9yYWdlLmdldCgnc3RhdGUnKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgYnVpbGROZXN0ZWRVcmkocm91dGU6IEFjdGl2YXRlZFJvdXRlU25hcHNob3QpOiBzdHJpbmcge1xuICAgICAgICBsZXQgdXJpID0gJyc7XG5cbiAgICAgICAgaWYgKHJvdXRlLnJvdXRlQ29uZmlnICYmIHJvdXRlLnJvdXRlQ29uZmlnLnBhdGgpIHtcbiAgICAgICAgICAgIHVyaSArPSAnLycgKyByb3V0ZS5yb3V0ZUNvbmZpZy5wYXRoO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHJvdXRlLmNoaWxkcmVuKSB7XG4gICAgICAgICAgICByb3V0ZS5jaGlsZHJlbi5mb3JFYWNoKChpdGVtOiBBY3RpdmF0ZWRSb3V0ZVNuYXBzaG90KSA9PiB7XG4gICAgICAgICAgICAgICAgdXJpICs9IHRoaXMuYnVpbGROZXN0ZWRVcmkoaXRlbSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB1cmk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBnZXRSZWZyZXNoVG9rZW4oKTogUHJvbWlzZTxTaWduYXR1cmUgfCBudWxsPiB7XG4gICAgICAgIGlmIChudWxsICE9PSB0aGlzLnJlZnJlc2hUb2tlbikge1xuICAgICAgICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSh0aGlzLnJlZnJlc2hUb2tlbik7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gdGhpcy5zdG9yYWdlLmdldCgncmVmcmVzaF90b2tlbicpO1xuICAgIH1cblxuICAgIHByaXZhdGUgZ2V0Q2xpZW50U2VjcmV0KCk6IFByb21pc2U8c3RyaW5nIHwgbnVsbD4ge1xuICAgICAgICBpZiAobnVsbCAhPT0gdGhpcy5jbGllbnRTZWNyZXQpIHtcbiAgICAgICAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUodGhpcy5jbGllbnRTZWNyZXQpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHRoaXMuc3RvcmFnZS5nZXQoJ2NsaWVudF9zZWNyZXQnKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGdldFVyaShwYXRoOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gdGhpcy5jb25maWcuZW5kcG9pbnQgKyAnL2FwaS8nICsgdGhpcy5WRVJTSU9OICsgcGF0aDtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0Q3VycmVudE9yaWdpbihwYXRoPzogc3RyaW5nKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuIHdpbmRvdy5sb2NhdGlvbi5vcmlnaW4gKyB0aGlzLmxvY2F0aW9uLnByZXBhcmVFeHRlcm5hbFVybChwYXRoIHx8ICcnKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGdlbmVyYXRlU3RhdGUoKTogc3RyaW5nIHtcbiAgICAgICAgY29uc3QgcG9zc2libGUgPSAnQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAxMjM0NTY3ODknO1xuICAgICAgICBsZXQgdGV4dCA9ICcnO1xuXG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgNTsgaSsrKSB7XG4gICAgICAgICAgICB0ZXh0ICs9IHBvc3NpYmxlLmNoYXJBdChNYXRoLmZsb29yKE1hdGgucmFuZG9tKCkgKiBwb3NzaWJsZS5sZW5ndGgpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB0ZXh0O1xuICAgIH1cblxuICAgIHByaXZhdGUgYnVpbGRRdWVyeVN0cmluZyhwYXJhbXM6IG9iamVjdCk6IHN0cmluZyB7XG4gICAgICAgIGNvbnN0IHF1ZXJ5UGFyYW1zID0gT2JqZWN0LmtleXMocGFyYW1zKS5tYXAoKGtleTogc3RyaW5nKSA9PiB7XG4gICAgICAgICAgICByZXR1cm4gZW5jb2RlVVJJQ29tcG9uZW50KGtleSkgKyAnPScgKyBlbmNvZGVVUklDb21wb25lbnQocGFyYW1zW2tleV0pO1xuICAgICAgICB9KTtcblxuICAgICAgICByZXR1cm4gcXVlcnlQYXJhbXMuam9pbignJicpO1xuICAgIH1cbn1cbiIsImV4cG9ydCBjbGFzcyBTaWduYXR1cmUge1xuICAgIHB1YmxpYyBleHBpcmVzSW4/OiBudW1iZXI7XG4gICAgcHVibGljIHRva2VuOiBzdHJpbmc7XG4gICAgcHVibGljIHR5cGU6IHN0cmluZztcbn1cbiIsImltcG9ydCB7IEluamVjdGFibGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IENhbkFjdGl2YXRlLCBDYW5BY3RpdmF0ZUNoaWxkIH0gZnJvbSAnQGFuZ3VsYXIvcm91dGVyJztcbmltcG9ydCB7IE5hY29TZXJ2aWNlIH0gZnJvbSAnLi4vZG9tYWlucy9zZXJ2aWNlcy9uYWNvLnNlcnZpY2UnO1xuaW1wb3J0IHsgZmlyc3QsIG1hcCB9IGZyb20gJ3J4anMvaW50ZXJuYWwvb3BlcmF0b3JzJztcbmltcG9ydCB7IFVzZXIgfSBmcm9tICcuLi9kb21haW5zL21vZGVscy91c2VyJztcbmltcG9ydCB7IE9ic2VydmFibGUgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IFN0b3JhZ2UgfSBmcm9tICdAdWJ1ZC9zdG9yYWdlJztcbmltcG9ydCB7IEFjdGl2YXRlZFJvdXRlU25hcHNob3QgfSBmcm9tICdAYW5ndWxhci9yb3V0ZXIvc3JjL3JvdXRlcl9zdGF0ZSc7XG5pbXBvcnQgeyBQbGF0Zm9ybUxvY2F0aW9uIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcblxuQEluamVjdGFibGUoKVxuZXhwb3J0IGNsYXNzIEF1dGhlbnRpY2F0ZWRHdWFyZCBpbXBsZW1lbnRzIENhbkFjdGl2YXRlLCBDYW5BY3RpdmF0ZUNoaWxkIHtcbiAgICBwdWJsaWMgY29uc3RydWN0b3IocHJpdmF0ZSBuYWNvOiBOYWNvU2VydmljZSwgcHJpdmF0ZSBzdG9yYWdlOiBTdG9yYWdlLCBwcml2YXRlIHBsYXRmb3JtTG9jYXRpb246IFBsYXRmb3JtTG9jYXRpb24pIHtcbiAgICB9XG5cbiAgICBwdWJsaWMgY2FuQWN0aXZhdGUocm91dGU6IEFjdGl2YXRlZFJvdXRlU25hcHNob3QpOiBPYnNlcnZhYmxlPGJvb2xlYW4+IHtcbiAgICAgICAgcmV0dXJuIHRoaXMubmFjby5nZXRVc2VyKCkucGlwZShcbiAgICAgICAgICAgIGZpcnN0KCksXG4gICAgICAgICAgICBtYXAoKHVzZXI6IFVzZXIgfCBudWxsKSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKG51bGwgPT09IHVzZXIpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgYmFzZSA9IHRoaXMucnRyaW0oKHRoaXMucGxhdGZvcm1Mb2NhdGlvbiBhcyBhbnkpLmxvY2F0aW9uLmhyZWYpO1xuICAgICAgICAgICAgICAgICAgICBjb25zdCB1cmkgPSB0aGlzLm5hY28uYnVpbGROZXN0ZWRVcmkocm91dGUucm9vdCk7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IG5leHQgPSBiYXNlLnJlcGxhY2UodXJpLCAnJykgKyAnLycgKyB0aGlzLmx0cmltKHVyaSk7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IG9yaWdpbiA9IGJhc2UucmVwbGFjZSh1cmksICcnKTtcblxuICAgICAgICAgICAgICAgICAgICB0aGlzLnN0b3JhZ2Uuc2V0KCduYWNvX2ludGVuZGVkX3VybCcsIG5leHQpLnRoZW4oKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgd2luZG93LmxvY2F0aW9uLmhyZWYgPSB0aGlzLm5hY28ubG9naW4oXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJ2Jhc2ljIGVtYWlsJyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcmlnaW4gKyAnL2F1dGgnLFxuICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcmV0dXJuICEhdXNlcjtcbiAgICAgICAgICAgIH0pLFxuICAgICAgICApO1xuICAgIH1cblxuICAgIHB1YmxpYyBjYW5BY3RpdmF0ZUNoaWxkKHJvdXRlOiBBY3RpdmF0ZWRSb3V0ZVNuYXBzaG90KTogT2JzZXJ2YWJsZTxib29sZWFuPiB7XG4gICAgICAgIHJldHVybiB0aGlzLmNhbkFjdGl2YXRlKHJvdXRlKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGx0cmltKHRleHQ6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgICAgIHJldHVybiB0ZXh0LnJlcGxhY2UoL15cXC8rLywnJyk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBydHJpbSh0ZXh0OiBzdHJpbmcpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gdGV4dC5yZXBsYWNlKC9cXC8rJC8sJycpO1xuICAgIH1cbn1cbiIsImltcG9ydCB7IEh0dHBFcnJvclJlc3BvbnNlLCBIdHRwRXZlbnQsIEh0dHBIYW5kbGVyLCBIdHRwSW50ZXJjZXB0b3IsIEh0dHBSZXF1ZXN0IH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uL2h0dHAnO1xuaW1wb3J0IHsgT2JzZXJ2YWJsZSB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgTmFjb1NlcnZpY2UgfSBmcm9tICcuLi9kb21haW5zL3NlcnZpY2VzL25hY28uc2VydmljZSc7XG5pbXBvcnQgeyBmcm9tUHJvbWlzZSB9IGZyb20gJ3J4anMvaW50ZXJuYWwvb2JzZXJ2YWJsZS9mcm9tUHJvbWlzZSc7XG5pbXBvcnQgeyBTaWduYXR1cmUgfSBmcm9tICcuLi9kb21haW5zL3ZhbHVlcy9zaWduYXR1cmUnO1xuaW1wb3J0IHsgY2F0Y2hFcnJvciwgc3dpdGNoTWFwIH0gZnJvbSAncnhqcy9pbnRlcm5hbC9vcGVyYXRvcnMnO1xuaW1wb3J0IHsgRXJyb3JPYnNlcnZhYmxlIH0gZnJvbSAncnhqcy1jb21wYXQvb2JzZXJ2YWJsZS9FcnJvck9ic2VydmFibGUnO1xuaW1wb3J0IHsgSW5qZWN0YWJsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuXG5ASW5qZWN0YWJsZSgpXG5leHBvcnQgY2xhc3MgQXV0aEludGVyY2VwdG9yIGltcGxlbWVudHMgSHR0cEludGVyY2VwdG9yIHtcbiAgICBwdWJsaWMgY29uc3RydWN0b3IocHJpdmF0ZSBuYWNvOiBOYWNvU2VydmljZSkge1xuICAgIH1cblxuICAgIHB1YmxpYyBpbnRlcmNlcHQocmVxOiBIdHRwUmVxdWVzdDxhbnk+LCBuZXh0OiBIdHRwSGFuZGxlcik6IE9ic2VydmFibGU8SHR0cEV2ZW50PGFueT4+IHtcbiAgICAgICAgcmV0dXJuIGZyb21Qcm9taXNlKHRoaXMubmFjby5nZXRTaWduYXR1cmUoKSkucGlwZShcbiAgICAgICAgICAgIHN3aXRjaE1hcCgoc2lnbmF0dXJlOiBTaWduYXR1cmUgfCBudWxsKSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKCFzaWduYXR1cmUpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG5leHQuaGFuZGxlKHJlcSk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcmV0dXJuIG5leHRcbiAgICAgICAgICAgICAgICAgICAgLmhhbmRsZShcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlcS5jbG9uZSh7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc2V0SGVhZGVyczoge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBBdXRob3JpemF0aW9uOiBgJHtzaWduYXR1cmUudHlwZX0gJHtzaWduYXR1cmUudG9rZW59YCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgICAgICAgLnBpcGUoXG4gICAgICAgICAgICAgICAgICAgICAgICBjYXRjaEVycm9yKChlcnJvcjogSHR0cEVycm9yUmVzcG9uc2UpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoZXJyb3Iuc3RhdHVzID09PSA0MDEpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMubmFjby5yZWZyZXNoVXNlcigpLnBpcGUoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzd2l0Y2hNYXAoKHVzZXI6IGFueSkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICh1c2VyKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBmcm9tUHJvbWlzZSh0aGlzLm5hY28uZ2V0U2lnbmF0dXJlKCkpLnBpcGUoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzd2l0Y2hNYXAoKG5ld1NpZ25hdHVyZTogU2lnbmF0dXJlKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG5leHQuaGFuZGxlKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXEuY2xvbmUoe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2V0SGVhZGVyczoge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEF1dGhvcml6YXRpb246IGAke25ld1NpZ25hdHVyZS50eXBlfSAke25ld1NpZ25hdHVyZS50b2tlbn1gLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBFcnJvck9ic2VydmFibGUuY3JlYXRlKGVycm9yKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBFcnJvck9ic2VydmFibGUuY3JlYXRlKGVycm9yKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfSksXG4gICAgICAgICk7XG4gICAgfVxufVxuIiwiaW1wb3J0IHsgTmFjb1NlcnZpY2UgfSBmcm9tICcuLi9kb21haW5zL3NlcnZpY2VzL25hY28uc2VydmljZSc7XG5pbXBvcnQgeyBDb25maWcgfSBmcm9tICcuLi9kb21haW5zL3ZhbHVlcy9jb25maWcnO1xuaW1wb3J0IHsgUm91dGVyIH0gZnJvbSAnQGFuZ3VsYXIvcm91dGVyJztcbmltcG9ydCB7IFN0b3JhZ2UgfSBmcm9tICdAdWJ1ZC9zdG9yYWdlJztcbmltcG9ydCB7IEluamVjdGlvblRva2VuIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBIdHRwQ2xpZW50IH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uL2h0dHAnO1xuaW1wb3J0IHsgTG9jYXRpb24gfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuXG5leHBvcnQgZnVuY3Rpb24gbmFjb0ZhY3RvcnkoY29uZmlnOiBvYmplY3QsIHJvdXRlcjogUm91dGVyLCBzdG9yYWdlOiBTdG9yYWdlLCBodHRwOiBIdHRwQ2xpZW50LCBsb2NhdGlvbjogTG9jYXRpb24pIHtcbiAgICByZXR1cm4gbmV3IE5hY29TZXJ2aWNlKFxuICAgICAgICBuZXcgQ29uZmlnKHsgLi4uY29uZmlnIH0pLFxuICAgICAgICByb3V0ZXIsXG4gICAgICAgIHN0b3JhZ2UsXG4gICAgICAgIGh0dHAsXG4gICAgICAgIGxvY2F0aW9uXG4gICAgKTtcbn1cblxuZXhwb3J0IGNvbnN0IE5BQ09fQ09ORklHID0gbmV3IEluamVjdGlvblRva2VuPG9iamVjdD4oJ05BQ09fQ09ORklHJyk7XG4iLCJpbXBvcnQgeyBDb21wb25lbnQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEFjdGl2YXRlZFJvdXRlLCBQYXJhbXMgfSBmcm9tICdAYW5ndWxhci9yb3V0ZXInO1xuaW1wb3J0IHsgTmFjb1NlcnZpY2UgfSBmcm9tICcuLi8uLi9kb21haW5zL3NlcnZpY2VzL25hY28uc2VydmljZSc7XG5pbXBvcnQgeyBTaWduYXR1cmUgfSBmcm9tICcuLi8uLi9kb21haW5zL3ZhbHVlcy9zaWduYXR1cmUnO1xuaW1wb3J0IHsgVXNlciB9IGZyb20gJy4uLy4uL2RvbWFpbnMvbW9kZWxzL3VzZXInO1xuaW1wb3J0IHsgU3RvcmFnZSB9IGZyb20gJ0B1YnVkL3N0b3JhZ2UnO1xuXG5AQ29tcG9uZW50KHtcbiAgICBzZWxlY3RvcjogJ25ha2VyLWF1dGgtcGFnZScsXG4gICAgdGVtcGxhdGU6ICd7eyBtZXNzYWdlIH19Jyxcbn0pXG5leHBvcnQgY2xhc3MgQXV0aFBhZ2Uge1xuICAgIHB1YmxpYyBtZXNzYWdlOiBzdHJpbmcgPSAnQXV0aGVudGljYXRpbmcuLi4nO1xuXG4gICAgcHVibGljIGNvbnN0cnVjdG9yKHByaXZhdGUgcm91dGU6IEFjdGl2YXRlZFJvdXRlLCBwcml2YXRlIG5hY286IE5hY29TZXJ2aWNlLCBwcml2YXRlIHN0b3JhZ2U6IFN0b3JhZ2UpIHtcbiAgICAgICAgdGhpcy5yb3V0ZS5xdWVyeVBhcmFtcy5zdWJzY3JpYmUoKHBhcmFtczogUGFyYW1zKSA9PiB0aGlzLmhhbmRsZShwYXJhbXMpKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgaGFuZGxlKHBhcmFtczogUGFyYW1zKTogdm9pZCB7XG4gICAgICAgIGlmIChwYXJhbXMuc3RhdGUpIHtcbiAgICAgICAgICAgIHRoaXMubmFjby5nZXRTdGF0ZSgpLnRoZW4oKHN0YXRlOiBzdHJpbmcgfCBudWxsKSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKHN0YXRlICE9PSBwYXJhbXMuc3RhdGUpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5tZXNzYWdlID0gJ0ludmFsaWQgQ1NSRic7XG5cbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHRoaXMuYXV0aGVudGljYXRlKHBhcmFtcyk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuYXV0aGVudGljYXRlKHBhcmFtcyk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIGF1dGhlbnRpY2F0ZShwYXJhbXM6IFBhcmFtcyk6IHZvaWQge1xuICAgICAgICBjb25zdCBzaWduYXR1cmU6IFNpZ25hdHVyZSA9IHtcbiAgICAgICAgICAgIGV4cGlyZXNJbjogcGFyYW1zLmV4cGlyZXNfaW4sXG4gICAgICAgICAgICB0eXBlOiBwYXJhbXMudG9rZW5fdHlwZSxcbiAgICAgICAgICAgIHRva2VuOiBwYXJhbXMuYWNjZXNzX3Rva2VuLFxuICAgICAgICB9O1xuXG4gICAgICAgIHRoaXMubmFjby5zZXRTaWduYXR1cmUoc2lnbmF0dXJlKTtcblxuICAgICAgICB0aGlzLm5hY28uZ2V0VXNlcigpLnN1YnNjcmliZSgodXNlcjogVXNlciB8IG51bGwpID0+IHtcbiAgICAgICAgICAgIGlmIChudWxsICE9PSB1c2VyKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5zdG9yYWdlLmdldCgnbmFjb19pbnRlbmRlZF91cmwnKS50aGVuKCh1cmw6IGFueSkgPT4ge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnN0b3JhZ2UucmVtb3ZlKCduYWNvX2ludGVuZGVkX3VybCcpLnRoZW4oKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgd2luZG93LmxvY2F0aW9uLmhyZWYgPSB1cmwgPyB1cmwgOiAnLyc7XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB0aGlzLm1lc3NhZ2UgPSAnVW5hdXRoZW50aWNhdGVkISc7XG4gICAgICAgIH0pO1xuICAgIH1cbn1cblxuIiwiaW1wb3J0IHsgQ29tcG9uZW50IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5cbkBDb21wb25lbnQoe1xuICAgIHNlbGVjdG9yOiAnbmFrZXItYXV0aC1zaWxlbnQnLFxuICAgIHRlbXBsYXRlOiAnUHJvY2Vzc2luZyBzaWxlbnQgYXV0aC4uLicsXG59KVxuZXhwb3J0IGNsYXNzIEF1dGhTaWxlbnRQYWdlIHtcbn1cbiIsImltcG9ydCB7IE1vZHVsZVdpdGhQcm92aWRlcnMgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IFJvdXRlck1vZHVsZSwgUm91dGVzIH0gZnJvbSAnQGFuZ3VsYXIvcm91dGVyJztcbmltcG9ydCB7IEF1dGhQYWdlIH0gZnJvbSAnLi9wYWdlcy9hdXRoLnBhZ2UnO1xuaW1wb3J0IHsgQXV0aFNpbGVudFBhZ2UgfSBmcm9tICcuL3BhZ2VzL2F1dGgtc2lsZW50LnBhZ2UnO1xuXG5jb25zdCByb3V0ZXM6IFJvdXRlcyA9IFtcbiAgICB7XG4gICAgICAgIHBhdGg6ICdhdXRoJyxcbiAgICAgICAgY29tcG9uZW50OiBBdXRoUGFnZVxuICAgIH0sXG4gICAge1xuICAgICAgICBwYXRoOiAnYXV0aC9zaWxlbnQnLFxuICAgICAgICBjb21wb25lbnQ6IEF1dGhTaWxlbnRQYWdlXG4gICAgfSxcbl07XG5cbmV4cG9ydCBjb25zdCBBVVRIX1JPVVRJTkc6IE1vZHVsZVdpdGhQcm92aWRlcnMgPSBSb3V0ZXJNb2R1bGUuZm9yQ2hpbGQocm91dGVzKTtcbiIsImltcG9ydCB7IE5nTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBBVVRIX1JPVVRJTkcgfSBmcm9tICcuL3JvdXRlcyc7XG5pbXBvcnQgeyBBdXRoUGFnZSB9IGZyb20gJy4vcGFnZXMvYXV0aC5wYWdlJztcbmltcG9ydCB7IEF1dGhTaWxlbnRQYWdlIH0gZnJvbSAnLi9wYWdlcy9hdXRoLXNpbGVudC5wYWdlJztcblxuQE5nTW9kdWxlKHtcbiAgICBpbXBvcnRzOiBbXG4gICAgICAgIEFVVEhfUk9VVElORyxcbiAgICBdLFxuICAgIGRlY2xhcmF0aW9uczogW1xuICAgICAgICBBdXRoUGFnZSxcbiAgICAgICAgQXV0aFNpbGVudFBhZ2UsXG4gICAgXSxcbn0pXG5leHBvcnQgY2xhc3MgTmFjb1ZpZXdNb2R1bGUge1xufVxuIiwiaW1wb3J0IHsgTW9kdWxlV2l0aFByb3ZpZGVycywgTmdNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IE5hY29TZXJ2aWNlIH0gZnJvbSAnLi9kb21haW5zL3NlcnZpY2VzL25hY28uc2VydmljZSc7XG5pbXBvcnQgeyBBdXRoZW50aWNhdGVkR3VhcmQgfSBmcm9tICcuL2d1YXJkcy9hdXRoZW50aWNhdGVkLmd1YXJkJztcbmltcG9ydCB7IE5BQ09fQ09ORklHLCBuYWNvRmFjdG9yeSB9IGZyb20gJy4vZmFjdG9yaWVzL25hY28tZmFjdG9yeSc7XG5pbXBvcnQgeyBSb3V0ZXIgfSBmcm9tICdAYW5ndWxhci9yb3V0ZXInO1xuaW1wb3J0IHsgU3RvcmFnZSwgVWJ1ZFN0b3JhZ2VNb2R1bGUgfSBmcm9tICdAdWJ1ZC9zdG9yYWdlJztcbmltcG9ydCB7IE5hY29WaWV3TW9kdWxlIH0gZnJvbSAnLi92aWV3cy9tb2R1bGUnO1xuaW1wb3J0IHsgSHR0cENsaWVudCB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbi9odHRwJztcbmltcG9ydCB7IExvY2F0aW9uIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcblxuQE5nTW9kdWxlKHtcbiAgICBpbXBvcnRzOiBbXG4gICAgICAgIFVidWRTdG9yYWdlTW9kdWxlLFxuICAgICAgICBOYWNvVmlld01vZHVsZSxcbiAgICBdLFxufSlcbmV4cG9ydCBjbGFzcyBOYWNvTW9kdWxlIHtcbiAgICBwdWJsaWMgc3RhdGljIGZvclJvb3QoY29uZmlnOiB7IGNsaWVudElkOiBzdHJpbmcsIGVuZHBvaW50Pzogc3RyaW5nIH0pOiBNb2R1bGVXaXRoUHJvdmlkZXJzIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIG5nTW9kdWxlOiBOYWNvTW9kdWxlLFxuICAgICAgICAgICAgcHJvdmlkZXJzOiBbXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICBwcm92aWRlOiBOQUNPX0NPTkZJRyxcbiAgICAgICAgICAgICAgICAgICAgdXNlVmFsdWU6IGNvbmZpZyxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgcHJvdmlkZTogTmFjb1NlcnZpY2UsXG4gICAgICAgICAgICAgICAgICAgIHVzZUZhY3Rvcnk6IG5hY29GYWN0b3J5LFxuICAgICAgICAgICAgICAgICAgICBkZXBzOiBbTkFDT19DT05GSUcsIFJvdXRlciwgU3RvcmFnZSwgSHR0cENsaWVudCwgTG9jYXRpb25dLFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgQXV0aGVudGljYXRlZEd1YXJkLFxuICAgICAgICAgICAgXSxcbiAgICAgICAgfTtcbiAgICB9XG59XG4iXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7OztBQUFBOzs7O2dCQUl1QixJQUFzQjt3QkFIZixnQ0FBZ0M7UUFJdEQsTUFBTSxDQUFDLE1BQU0sQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLENBQUM7O0NBRWpDOzs7Ozs7O0NDS0E7O0lBRkksSUFBSSxtQkFBQyxVQUFVLENBQUMsTUFBTSxJQUFJLENBQVEsRUFBQzs4QkFDbEIsSUFBSTs7Ozs7Ozs7Ozs7Ozs7O2dCQ1lLLE1BQWMsRUFBVSxNQUFjLEVBQVUsT0FBZ0IsRUFBVSxJQUFnQixFQUFVLFFBQWtCO1FBQXRILFdBQU0sR0FBTixNQUFNLENBQVE7UUFBVSxXQUFNLEdBQU4sTUFBTSxDQUFRO1FBQVUsWUFBTyxHQUFQLE9BQU8sQ0FBUztRQUFVLFNBQUksR0FBSixJQUFJLENBQVk7UUFBVSxhQUFRLEdBQVIsUUFBUSxDQUFVO3VCQVB2SCxJQUFJO3lCQUVRLElBQUk7b0JBQ2QsSUFBSTs0QkFDUyxJQUFJOzRCQUNQLElBQUk7Ozs7OztJQUtuQyxPQUFPLENBQUMsSUFBaUI7UUFDNUIsSUFBSSxDQUFDLElBQUksR0FBRyxJQUFJLENBQUM7UUFDakIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxDQUFDOzs7OztJQUc1QixPQUFPO1FBQ1YsSUFBSSxJQUFJLEtBQUssSUFBSSxDQUFDLElBQUksRUFBRTtZQUNwQixPQUFPLEVBQUUsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7U0FDeEI7UUFFRCxPQUFPLFdBQVcsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FDN0MsU0FBUyxDQUFDLENBQUMsSUFBaUI7WUFDeEIsSUFBSSxJQUFJLEtBQUssSUFBSSxFQUFFO2dCQUNmLE9BQU8sRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDO2FBQ25CO1lBRUQsdUJBQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDLENBQUM7WUFFckMsT0FBTyxXQUFXLENBQUMsSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDLENBQUMsSUFBSSxDQUN4QyxTQUFTLENBQUMsQ0FBQyxTQUEyQjtnQkFDbEMsSUFBSSxJQUFJLEtBQUssU0FBUyxFQUFFO29CQUNwQixPQUFPLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQztpQkFDbkI7Z0JBRUQsdUJBQU0sT0FBTyxHQUFHO29CQUNaLE9BQU8sRUFBRTt3QkFDTCxhQUFhLEVBQUUsR0FBRyxTQUFTLENBQUMsSUFBSSxJQUFJLFNBQVMsQ0FBQyxLQUFLLEVBQUU7cUJBQ3hEO2lCQUNKLENBQUM7Z0JBRUYsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBTSxHQUFHLEVBQUUsT0FBTyxDQUFDLENBQUMsSUFBSSxDQUN4QyxHQUFHLENBQUMsQ0FBQyxHQUFRO29CQUNULElBQUksR0FBRyxDQUFDLElBQUksRUFBRTt3QkFDVixPQUFPLEdBQUcsQ0FBQyxJQUFJLENBQUM7cUJBQ25CO29CQUVELE1BQU0sSUFBSSxLQUFLLENBQUMscUNBQXFDLENBQUMsQ0FBQztpQkFDMUQsQ0FBQyxFQUNGLEdBQUcsQ0FBQyxDQUFDLElBQVM7b0JBQ1YsdUJBQU0sUUFBUSxHQUFRLFlBQVksQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLENBQUM7b0JBRS9DLElBQUksQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLENBQUM7b0JBRXZCLE9BQU8sUUFBUSxDQUFDO2lCQUNuQixDQUFDLEVBQ0YsVUFBVSxDQUFDLENBQUMsQ0FBb0I7b0JBQzVCLElBQUksR0FBRyxLQUFLLENBQUMsQ0FBQyxNQUFNLEVBQUU7d0JBQ2xCLE9BQU8sSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDLElBQUksQ0FDMUIsU0FBUyxDQUFDLENBQUMsV0FBd0I7NEJBQy9CLElBQUksV0FBVyxFQUFFO2dDQUNiLE9BQU8sRUFBRSxDQUFDLFdBQVcsQ0FBQyxDQUFDOzZCQUMxQjs0QkFFRCxPQUFPLGVBQWUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUM7eUJBQ3BDLENBQUMsQ0FDTCxDQUFDO3FCQUNMO29CQUVELE9BQU8sZUFBZSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQztpQkFDcEMsQ0FBQyxDQUNMLENBQUM7YUFDTCxDQUFDLENBQ0wsQ0FBQztTQUNMLENBQUMsQ0FDTCxDQUFDOzs7OztJQUdDLFlBQVk7UUFDZixJQUFJLElBQUksS0FBSyxJQUFJLENBQUMsU0FBUyxFQUFFO1lBQ3pCLE9BQU8sT0FBTyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUM7U0FDMUM7UUFFRCxPQUFPLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLFdBQVcsQ0FBQyxDQUFDOzs7Ozs7SUFHbEMsWUFBWSxDQUFDLFNBQW9CO1FBQ3BDLElBQUksQ0FBQyxTQUFTLEdBQUcsU0FBUyxDQUFDO1FBQzNCLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLFdBQVcsRUFBRSxTQUFTLENBQUMsQ0FBQzs7Ozs7O0lBR3RDLGVBQWUsQ0FBQyxNQUFjO1FBQ2pDLElBQUksQ0FBQyxZQUFZLEdBQUcsTUFBTSxDQUFDO1FBQzNCLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLGVBQWUsRUFBRSxNQUFNLENBQUMsQ0FBQzs7Ozs7O0lBR3ZDLGVBQWUsQ0FBQyxZQUF1QjtRQUMxQyxJQUFJLENBQUMsWUFBWSxHQUFHLFlBQVksQ0FBQztRQUNqQyxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxlQUFlLEVBQUUsWUFBWSxDQUFDLENBQUM7Ozs7OztJQUc3QyxXQUFXLENBQUMsTUFBZTtRQUM5QixJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ25CLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLENBQUM7UUFFeEIsT0FBTyxRQUFRLENBQUMsSUFBSSxDQUFDLGVBQWUsRUFBRSxFQUFFLElBQUksQ0FBQyxlQUFlLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FDaEUsU0FBUyxDQUFDLENBQUMsT0FBWTtZQUNuQix1QkFBTSxZQUFZLEdBQWMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQzNDLHVCQUFNLFlBQVksR0FBVyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFFeEMsSUFBSSxZQUFZLElBQUksWUFBWSxFQUFFO2dCQUM5QixPQUFPLElBQUksQ0FBQyx1QkFBdUIsQ0FBQyxZQUFZLEVBQUUsWUFBWSxDQUFDLEtBQUssRUFBRSxNQUFNLENBQUMsQ0FBQzthQUNqRjtZQUVELE9BQU8sSUFBSSxDQUFDLHFCQUFxQixFQUFFLENBQUM7U0FDdkMsQ0FBQyxDQUNMLENBQUM7Ozs7Ozs7O0lBR0MsdUJBQXVCLENBQUMsWUFBb0IsRUFBRSxZQUFvQixFQUFFLE1BQWU7UUFDdEYsdUJBQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLEVBQUU7WUFDbkQsVUFBVSxFQUFFLGVBQWU7WUFDM0IsTUFBTSxFQUFFLE1BQU0sSUFBSSxhQUFhO1lBQy9CLFNBQVMsRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLFFBQVE7WUFDL0IsYUFBYSxFQUFFLFlBQVk7WUFDM0IsYUFBYSxFQUFFLFlBQVk7U0FDOUIsQ0FBQyxDQUFDO1FBRUgsT0FBTyxPQUFPLENBQUMsSUFBSSxDQUNmLEdBQUcsQ0FBQyxDQUFDLE1BQVc7WUFDWixJQUFJLE1BQU0sSUFBSSxNQUFNLENBQUMsSUFBSSxFQUFFO2dCQUN2QixJQUFJLENBQUMsWUFBWSxDQUFDO29CQUNkLFNBQVMsRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLFVBQVU7b0JBQ2pDLElBQUksRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLFVBQVU7b0JBQzVCLEtBQUssRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLFlBQVk7aUJBQ2xDLENBQUMsQ0FBQztnQkFFSCxJQUFJLENBQUMsZUFBZSxDQUFDO29CQUNqQixJQUFJLEVBQUUsTUFBTSxDQUFDLElBQUksQ0FBQyxVQUFVO29CQUM1QixLQUFLLEVBQUUsTUFBTSxDQUFDLElBQUksQ0FBQyxhQUFhO2lCQUNuQyxDQUFDLENBQUM7YUFDTjtTQUNKLENBQUMsRUFDRixHQUFHLENBQUMsQ0FBQyxNQUFXLEtBQUssTUFBTSxJQUFJLE1BQU0sQ0FBQyxJQUFJLENBQUMsRUFDM0MsU0FBUyxDQUFDLENBQUMsUUFBaUI7WUFDeEIsSUFBSSxRQUFRLEVBQUU7Z0JBQ1YsT0FBTyxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7YUFDekI7WUFFRCxPQUFPLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQztTQUNuQixDQUFDLENBQ0wsQ0FBQzs7Ozs7SUFHQyxxQkFBcUI7UUFDeEIsT0FBTyxJQUFJLFVBQVUsQ0FBYyxDQUFDLFFBQStCO1lBQy9ELHVCQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsYUFBYSxDQUFDLENBQUM7WUFDekQsdUJBQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsYUFBYSxFQUFFLFdBQVcsQ0FBQyxDQUFDO1lBRW5ELHVCQUFNLE1BQU0sR0FBRyxRQUFRLENBQUMsYUFBYSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1lBQ2hELE1BQU0sQ0FBQyxZQUFZLENBQUMsS0FBSyxFQUFFLEdBQUcsQ0FBQyxDQUFDO1lBQ2hDLE1BQU0sQ0FBQyxLQUFLLENBQUMsT0FBTyxHQUFHLE1BQU0sQ0FBQztZQUU5QixNQUFNLENBQUMsZ0JBQWdCLENBQUMsTUFBTSxFQUFFO2dCQUM1QixJQUFJO29CQUNBLHVCQUFNLFdBQVcsR0FBRyxNQUFNLENBQUMsYUFBYSxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDO29CQUV0RSxNQUFNLENBQUMsVUFBVSxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsQ0FBQztvQkFFdEMsSUFBSSxXQUFXLEVBQUU7d0JBQ2IsdUJBQU0sVUFBVSxHQUFHLFdBQVcsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7d0JBQzFDLHVCQUFNLE1BQU0sR0FBRyxFQUFFLENBQUM7d0JBRWxCLEtBQUssdUJBQU0sSUFBSSxJQUFJLFVBQVUsRUFBRTs0QkFDM0IsdUJBQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7NEJBRWxDLE1BQU0sQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUM7eUJBQ3ZDO3dCQUVELElBQUksTUFBTSxDQUFDLGNBQWMsQ0FBQyxjQUFjLENBQUMsRUFBRTs0QkFDdkMsdUJBQU0sS0FBSyxHQUFHLE1BQU0sQ0FBQyxPQUFPLENBQUMsSUFBSSxJQUFJLENBQUM7NEJBRXRDLElBQUksS0FBSyxNQUFLLE1BQU0sSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFBLEVBQUU7Z0NBQ2pDLFFBQVEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7Z0NBRXBCLE9BQU87NkJBQ1Y7NEJBRUQsSUFBSSxDQUFDLFlBQVksQ0FBQztnQ0FDZCxLQUFLLEVBQUUsTUFBTSxDQUFDLGNBQWMsQ0FBQztnQ0FDN0IsSUFBSSxFQUFFLE1BQU0sQ0FBQyxZQUFZLENBQUM7Z0NBQzFCLFNBQVMsRUFBRSxNQUFNLENBQUMsS0FBSyxDQUFDOzZCQUMzQixDQUFDLENBQUM7NEJBRUgsdUJBQU0sSUFBSSxHQUFHLE1BQU0sSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDLFNBQVMsRUFBRSxDQUFDOzRCQUU5QyxJQUFJLElBQUksRUFBRTtnQ0FDTixJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDOzZCQUN0Qjs0QkFFRCxRQUFRLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO3lCQUN2Qjs2QkFBTTs0QkFDSCxRQUFRLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO3lCQUN2Qjt3QkFFRCxPQUFPO3FCQUNWO29CQUVELFFBQVEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7aUJBQ3ZCO2dCQUFDLHdCQUFPLENBQUMsRUFBRTtvQkFDUixRQUFRLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO2lCQUN2QjtjQUNKLEVBQUUsS0FBSyxDQUFDLENBQUM7WUFFVixRQUFRLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsQ0FBQztTQUNyQyxDQUFDLENBQUM7Ozs7Ozs7SUFHQSxLQUFLLENBQUMsTUFBYyxFQUFFLFdBQW9CO1FBQzdDLElBQUksQ0FBQyxXQUFXLEVBQUU7WUFDZCxXQUFXLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUM7U0FDakM7UUFFRCx1QkFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLGFBQWEsRUFBRSxDQUFDO1FBRW5DLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxLQUFLLENBQUMsQ0FBQztRQUVqQyx1QkFBTSxLQUFLLEdBQVcsSUFBSSxDQUFDLGdCQUFnQixDQUN2QztZQUNJLGVBQWUsRUFBRSxPQUFPO1lBQ3hCLFFBQVEsRUFBRSxNQUFNO1lBQ2hCLFFBQVEsRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLFFBQVE7WUFDOUIsT0FBTyxFQUFFLEtBQUs7WUFDZCxVQUFVLEVBQUUsV0FBVztTQUMxQixDQUNKLENBQUM7UUFFRixPQUFPLElBQUksQ0FBQyxNQUFNLENBQUMsUUFBUSxHQUFHLFFBQVEsR0FBRyxLQUFLLENBQUM7Ozs7OztJQUc1QyxNQUFNLENBQUMsV0FBb0I7UUFDOUIsSUFBSSxDQUFDLFNBQVMsR0FBRyxJQUFJLENBQUM7UUFDdEIsSUFBSSxDQUFDLElBQUksR0FBRyxJQUFJLENBQUM7UUFFakIsT0FBTyxJQUFJLE9BQU8sQ0FBQyxPQUFPO1lBQ3RCLE9BQU8sQ0FBQyxHQUFHLENBQUM7Z0JBQ1IsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDO2dCQUNoQyxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUM7YUFDOUIsQ0FBQyxDQUFDLElBQUksQ0FBQztnQkFDSixxQkFBSSxRQUFRLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxRQUFRLEdBQUcsY0FBYyxDQUFDO2dCQUVyRCxJQUFJLFdBQVcsRUFBRTtvQkFDYixRQUFRLElBQUksWUFBWSxHQUFHLFdBQVcsQ0FBQztpQkFDMUM7Z0JBRUQsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDO2FBQ3JCLENBQUMsQ0FBQztTQUNOLENBQUMsQ0FBQzs7Ozs7SUFHQSxRQUFRO1FBQ1gsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQzs7Ozs7O0lBRzlCLGNBQWMsQ0FBQyxLQUE2QjtRQUMvQyxxQkFBSSxHQUFHLEdBQUcsRUFBRSxDQUFDO1FBRWIsSUFBSSxLQUFLLENBQUMsV0FBVyxJQUFJLEtBQUssQ0FBQyxXQUFXLENBQUMsSUFBSSxFQUFFO1lBQzdDLEdBQUcsSUFBSSxHQUFHLEdBQUcsS0FBSyxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUM7U0FDdkM7UUFFRCxJQUFJLEtBQUssQ0FBQyxRQUFRLEVBQUU7WUFDaEIsS0FBSyxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsQ0FBQyxJQUE0QjtnQkFDaEQsR0FBRyxJQUFJLElBQUksQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLENBQUM7YUFDcEMsQ0FBQyxDQUFDO1NBQ047UUFFRCxPQUFPLEdBQUcsQ0FBQzs7Ozs7SUFHUCxlQUFlO1FBQ25CLElBQUksSUFBSSxLQUFLLElBQUksQ0FBQyxZQUFZLEVBQUU7WUFDNUIsT0FBTyxPQUFPLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQztTQUM3QztRQUVELE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsZUFBZSxDQUFDLENBQUM7Ozs7O0lBR3JDLGVBQWU7UUFDbkIsSUFBSSxJQUFJLEtBQUssSUFBSSxDQUFDLFlBQVksRUFBRTtZQUM1QixPQUFPLE9BQU8sQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxDQUFDO1NBQzdDO1FBRUQsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxlQUFlLENBQUMsQ0FBQzs7Ozs7O0lBR3JDLE1BQU0sQ0FBQyxJQUFZO1FBQ3ZCLE9BQU8sSUFBSSxDQUFDLE1BQU0sQ0FBQyxRQUFRLEdBQUcsT0FBTyxHQUFHLElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSxDQUFDOzs7Ozs7SUFHekQsZ0JBQWdCLENBQUMsSUFBYTtRQUNqQyxPQUFPLE1BQU0sQ0FBQyxRQUFRLENBQUMsTUFBTSxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUMsa0JBQWtCLENBQUMsSUFBSSxJQUFJLEVBQUUsQ0FBQyxDQUFDOzs7OztJQUd6RSxhQUFhO1FBQ2pCLHVCQUFNLFFBQVEsR0FBRyxnRUFBZ0UsQ0FBQztRQUNsRixxQkFBSSxJQUFJLEdBQUcsRUFBRSxDQUFDO1FBRWQsS0FBSyxxQkFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUU7WUFDeEIsSUFBSSxJQUFJLFFBQVEsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLEdBQUcsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUM7U0FDeEU7UUFFRCxPQUFPLElBQUksQ0FBQzs7Ozs7O0lBR1IsZ0JBQWdCLENBQUMsTUFBYztRQUNuQyx1QkFBTSxXQUFXLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFXO1lBQ3BELE9BQU8sa0JBQWtCLENBQUMsR0FBRyxDQUFDLEdBQUcsR0FBRyxHQUFHLGtCQUFrQixDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO1NBQzFFLENBQUMsQ0FBQztRQUVILE9BQU8sV0FBVyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQzs7OztZQWpVcEMsVUFBVTs7OztZQVhGLE1BQU07WUFGa0IsTUFBTTtZQUM5QixPQUFPO1lBUVAsVUFBVTtZQUNWLFFBQVE7Ozs7Ozs7QUNYakI7Q0FJQzs7Ozs7O0FDSkQ7Ozs7OztnQkFZK0IsSUFBaUIsRUFBVSxPQUFnQixFQUFVLGdCQUFrQztRQUF2RixTQUFJLEdBQUosSUFBSSxDQUFhO1FBQVUsWUFBTyxHQUFQLE9BQU8sQ0FBUztRQUFVLHFCQUFnQixHQUFoQixnQkFBZ0IsQ0FBa0I7Ozs7OztJQUczRyxXQUFXLENBQUMsS0FBNkI7UUFDNUMsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDLElBQUksQ0FDM0IsS0FBSyxFQUFFLEVBQ1AsR0FBRyxDQUFDLENBQUMsSUFBaUI7WUFDbEIsSUFBSSxJQUFJLEtBQUssSUFBSSxFQUFFO2dCQUNmLHVCQUFNLElBQUksR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLG1CQUFDLElBQUksQ0FBQyxnQkFBdUIsR0FBRSxRQUFRLENBQUMsSUFBSSxDQUFDLENBQUM7Z0JBQ3RFLHVCQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUM7Z0JBQ2pELHVCQUFNLElBQUksR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsR0FBRyxHQUFHLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztnQkFDM0QsdUJBQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQyxDQUFDO2dCQUVyQyxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxtQkFBbUIsRUFBRSxJQUFJLENBQUMsQ0FBQyxJQUFJLENBQUM7b0JBQzdDLE1BQU0sQ0FBQyxRQUFRLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUNsQyxhQUFhLEVBQ2IsTUFBTSxHQUFHLE9BQU8sQ0FDbkIsQ0FBQztpQkFDTCxDQUFDLENBQUM7YUFDTjtZQUVELE9BQU8sQ0FBQyxDQUFDLElBQUksQ0FBQztTQUNqQixDQUFDLENBQ0wsQ0FBQzs7Ozs7O0lBR0MsZ0JBQWdCLENBQUMsS0FBNkI7UUFDakQsT0FBTyxJQUFJLENBQUMsV0FBVyxDQUFDLEtBQUssQ0FBQyxDQUFDOzs7Ozs7SUFHM0IsS0FBSyxDQUFDLElBQVk7UUFDdEIsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sRUFBQyxFQUFFLENBQUMsQ0FBQzs7Ozs7O0lBRzNCLEtBQUssQ0FBQyxJQUFZO1FBQ3RCLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLEVBQUMsRUFBRSxDQUFDLENBQUM7Ozs7WUFyQ3RDLFVBQVU7Ozs7WUFSRixXQUFXO1lBSVgsT0FBTztZQUVQLGdCQUFnQjs7Ozs7OztBQ056Qjs7OztnQkFTK0IsSUFBaUI7UUFBakIsU0FBSSxHQUFKLElBQUksQ0FBYTs7Ozs7OztJQUdyQyxTQUFTLENBQUMsR0FBcUIsRUFBRSxJQUFpQjtRQUNyRCxPQUFPLFdBQVcsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDLENBQUMsSUFBSSxDQUM3QyxTQUFTLENBQUMsQ0FBQyxTQUEyQjtZQUNsQyxJQUFJLENBQUMsU0FBUyxFQUFFO2dCQUNaLE9BQU8sSUFBSSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQzthQUMzQjtZQUVELE9BQU8sSUFBSTtpQkFDTixNQUFNLENBQ0gsR0FBRyxDQUFDLEtBQUssQ0FBQztnQkFDTixVQUFVLEVBQUU7b0JBQ1IsYUFBYSxFQUFFLEdBQUcsU0FBUyxDQUFDLElBQUksSUFBSSxTQUFTLENBQUMsS0FBSyxFQUFFO2lCQUN4RDthQUNKLENBQUMsQ0FDTDtpQkFDQSxJQUFJLENBQ0QsVUFBVSxDQUFDLENBQUMsS0FBd0I7Z0JBQ2hDLElBQUksS0FBSyxDQUFDLE1BQU0sS0FBSyxHQUFHLEVBQUU7b0JBQ3RCLE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQyxJQUFJLENBQy9CLFNBQVMsQ0FBQyxDQUFDLElBQVM7d0JBQ2hCLElBQUksSUFBSSxFQUFFOzRCQUNOLE9BQU8sV0FBVyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQzdDLFNBQVMsQ0FBQyxDQUFDLFlBQXVCO2dDQUM5QixPQUFPLElBQUksQ0FBQyxNQUFNLENBQ2QsR0FBRyxDQUFDLEtBQUssQ0FBQztvQ0FDTixVQUFVLEVBQUU7d0NBQ1IsYUFBYSxFQUFFLEdBQUcsWUFBWSxDQUFDLElBQUksSUFBSSxZQUFZLENBQUMsS0FBSyxFQUFFO3FDQUM5RDtpQ0FDSixDQUFDLENBQ0wsQ0FBQzs2QkFDTCxDQUFDLENBQ0wsQ0FBQzt5QkFDTDt3QkFFRCxPQUFPLGVBQWUsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUM7cUJBQ3hDLENBQUMsQ0FDTCxDQUFDO2lCQUNMO2dCQUVELE9BQU8sZUFBZSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQzthQUN4QyxDQUFDLENBQ0wsQ0FBQztTQUNULENBQUMsQ0FDTCxDQUFDOzs7O1lBaERULFVBQVU7Ozs7WUFQRixXQUFXOzs7Ozs7O0FDRnBCOzs7Ozs7OztBQVFBLHFCQUE0QixNQUFjLEVBQUUsTUFBYyxFQUFFLE9BQWdCLEVBQUUsSUFBZ0IsRUFBRSxRQUFrQjtJQUM5RyxPQUFPLElBQUksV0FBVyxDQUNsQixJQUFJLE1BQU0sbUJBQU0sTUFBTSxFQUFHLEVBQ3pCLE1BQU0sRUFDTixPQUFPLEVBQ1AsSUFBSSxFQUNKLFFBQVEsQ0FDWCxDQUFDO0NBQ0w7QUFFRCx1QkFBYSxXQUFXLEdBQUcsSUFBSSxjQUFjLENBQVMsYUFBYSxDQUFDOzs7Ozs7QUNsQnBFOzs7Ozs7Z0JBYytCLEtBQXFCLEVBQVUsSUFBaUIsRUFBVSxPQUFnQjtRQUExRSxVQUFLLEdBQUwsS0FBSyxDQUFnQjtRQUFVLFNBQUksR0FBSixJQUFJLENBQWE7UUFBVSxZQUFPLEdBQVAsT0FBTyxDQUFTO3VCQUY1RSxtQkFBbUI7UUFHeEMsSUFBSSxDQUFDLEtBQUssQ0FBQyxXQUFXLENBQUMsU0FBUyxDQUFDLENBQUMsTUFBYyxLQUFLLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQzs7Ozs7O0lBR3ZFLE1BQU0sQ0FBQyxNQUFjO1FBQ3hCLElBQUksTUFBTSxXQUFRO1lBQ2QsSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxLQUFvQjtnQkFDM0MsSUFBSSxLQUFLLEtBQUssTUFBTSxTQUFNLEVBQUU7b0JBQ3hCLElBQUksQ0FBQyxPQUFPLEdBQUcsY0FBYyxDQUFDO29CQUU5QixPQUFPO2lCQUNWO2dCQUVELElBQUksQ0FBQyxZQUFZLENBQUMsTUFBTSxDQUFDLENBQUM7YUFDN0IsQ0FBQyxDQUFDO1NBQ047YUFBTTtZQUNILElBQUksQ0FBQyxZQUFZLENBQUMsTUFBTSxDQUFDLENBQUM7U0FDN0I7Ozs7OztJQUdHLFlBQVksQ0FBQyxNQUFjO1FBQy9CLHVCQUFNLFNBQVMsR0FBYztZQUN6QixTQUFTLEVBQUUsTUFBTSxjQUFXO1lBQzVCLElBQUksRUFBRSxNQUFNLGNBQVc7WUFDdkIsS0FBSyxFQUFFLE1BQU0sZ0JBQWE7U0FDN0IsQ0FBQztRQUVGLElBQUksQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBRWxDLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUMsU0FBUyxDQUFDLENBQUMsSUFBaUI7WUFDNUMsSUFBSSxJQUFJLEtBQUssSUFBSSxFQUFFO2dCQUNmLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLG1CQUFtQixDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBUTtvQkFDaEQsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsbUJBQW1CLENBQUMsQ0FBQyxJQUFJLENBQUM7d0JBQzFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsSUFBSSxHQUFHLEdBQUcsR0FBRyxHQUFHLEdBQUcsR0FBRyxDQUFDO3FCQUMxQyxDQUFDLENBQUM7aUJBQ04sQ0FBQyxDQUFDO2dCQUVILE9BQU87YUFDVjtZQUVELElBQUksQ0FBQyxPQUFPLEdBQUcsa0JBQWtCLENBQUM7U0FDckMsQ0FBQyxDQUFDOzs7O1lBaERWLFNBQVMsU0FBQztnQkFDUCxRQUFRLEVBQUUsaUJBQWlCO2dCQUMzQixRQUFRLEVBQUUsZUFBZTthQUM1Qjs7OztZQVRRLGNBQWM7WUFDZCxXQUFXO1lBR1gsT0FBTzs7Ozs7OztBQ0xoQjs7O1lBRUMsU0FBUyxTQUFDO2dCQUNQLFFBQVEsRUFBRSxtQkFBbUI7Z0JBQzdCLFFBQVEsRUFBRSwyQkFBMkI7YUFDeEM7Ozs7Ozs7QUNKRCxBQUlBLHVCQUFNLE1BQU0sR0FBVztJQUNuQjtRQUNJLElBQUksRUFBRSxNQUFNO1FBQ1osU0FBUyxFQUFFLFFBQVE7S0FDdEI7SUFDRDtRQUNJLElBQUksRUFBRSxhQUFhO1FBQ25CLFNBQVMsRUFBRSxjQUFjO0tBQzVCO0NBQ0osQ0FBQztBQUVGLHVCQUFhLFlBQVksR0FBd0IsWUFBWSxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUM7Ozs7OztBQ2hCOUU7OztZQUtDLFFBQVEsU0FBQztnQkFDTixPQUFPLEVBQUU7b0JBQ0wsWUFBWTtpQkFDZjtnQkFDRCxZQUFZLEVBQUU7b0JBQ1YsUUFBUTtvQkFDUixjQUFjO2lCQUNqQjthQUNKOzs7Ozs7O0FDYkQ7Ozs7O0lBaUJXLE9BQU8sT0FBTyxDQUFDLE1BQStDO1FBQ2pFLE9BQU87WUFDSCxRQUFRLEVBQUUsVUFBVTtZQUNwQixTQUFTLEVBQUU7Z0JBQ1A7b0JBQ0ksT0FBTyxFQUFFLFdBQVc7b0JBQ3BCLFFBQVEsRUFBRSxNQUFNO2lCQUNuQjtnQkFDRDtvQkFDSSxPQUFPLEVBQUUsV0FBVztvQkFDcEIsVUFBVSxFQUFFLFdBQVc7b0JBQ3ZCLElBQUksRUFBRSxDQUFDLFdBQVcsRUFBRSxNQUFNLEVBQUUsT0FBTyxFQUFFLFVBQVUsRUFBRSxRQUFRLENBQUM7aUJBQzdEO2dCQUNELGtCQUFrQjthQUNyQjtTQUNKLENBQUM7Ozs7WUF0QlQsUUFBUSxTQUFDO2dCQUNOLE9BQU8sRUFBRTtvQkFDTCxpQkFBaUI7b0JBQ2pCLGNBQWM7aUJBQ2pCO2FBQ0o7Ozs7Ozs7Ozs7Ozs7OzsifQ==
\No newline at end of file