@hpe/angular-toolkit
Version:
Hewlett-Packard Enterprise : Angular toolkit for rapid project development
922 lines (910 loc) • 80.1 kB
JavaScript
import { EventEmitter, Injectable, NgModule } from '@angular/core';
import { AppEvent } from '@hpe/angular-toolkit/model';
import { __extends } from 'tslib';
import { HttpClient } from '@angular/common/http';
import { DomSanitizer } from '@angular/platform-browser';
import { throwError } from 'rxjs';
import { catchError, map, finalize } from 'rxjs/operators';
import { MessageService } from 'primeng/components/common/messageservice';
import { CommonModule } from '@angular/common';
import { MessageService as MessageService$1 } from 'primeng/api';
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
//=============================================================================
//===
//=== (C) Copyright 2018 Hewlett Packard Enterprise Development LP.
//===
//=== Use of this source code is governed by an MIT-style license that can be
//=== found in the LICENSE file
//=============================================================================
var AbstractSubscriber = /** @class */ (function () {
//-------------------------------------------------------------------------
//---
//--- Constructor
//---
//-------------------------------------------------------------------------
function AbstractSubscriber(eventBusService) {
this.eventBusService = eventBusService;
this.subscriptions = [];
}
/**
* @return {?}
*/
AbstractSubscriber.prototype.ngOnDestroy = /**
* @return {?}
*/
function () {
this.subscriptions.forEach(function (s) { return s.unsubscribe(); });
};
//-------------------------------------------------------------------------
//---
//--- API methods
//---
//-------------------------------------------------------------------------
/**
* @param {?} eventCode
* @param {?} handler
* @return {?}
*/
AbstractSubscriber.prototype.subscribeToApp = /**
* @param {?} eventCode
* @param {?} handler
* @return {?}
*/
function (eventCode, handler) {
var /** @type {?} */ s = this.eventBusService.subscribeToApp(eventCode, handler);
this.subscriptions.push(s);
return s;
};
//-------------------------------------------------------------------------
/**
* @param {?} event
* @return {?}
*/
AbstractSubscriber.prototype.emitToApp = /**
* @param {?} event
* @return {?}
*/
function (event) {
this.eventBusService.emitToApp(event);
};
//-------------------------------------------------------------------------
/**
* @param {?} handler
* @return {?}
*/
AbstractSubscriber.prototype.subscribeToError = /**
* @param {?} handler
* @return {?}
*/
function (handler) {
var /** @type {?} */ s = this.eventBusService.subscribeToError(handler);
this.subscriptions.push(s);
return s;
};
//-------------------------------------------------------------------------
/**
* @param {?} event
* @return {?}
*/
AbstractSubscriber.prototype.emitToError = /**
* @param {?} event
* @return {?}
*/
function (event) {
this.eventBusService.emitToError(event);
};
return AbstractSubscriber;
}());
//=============================================================================
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
var EventBusService = /** @class */ (function () {
//-------------------------------------------------------------------------
//---
//--- Constructor
//---
//-------------------------------------------------------------------------
function EventBusService() {
this.eventEmitterMap = new Map();
this.errorEvents = new EventEmitter();
}
/**
* @param {?} eventCode
* @param {?} handler
* @return {?}
*/
EventBusService.prototype.subscribeToApp = /**
* @param {?} eventCode
* @param {?} handler
* @return {?}
*/
function (eventCode, handler) {
var /** @type {?} */ emitter = this.eventEmitterMap.get(eventCode);
if (emitter == null) {
emitter = new EventEmitter();
this.eventEmitterMap.set(eventCode, emitter);
}
return emitter.subscribe(handler, null, null);
};
/**
* @param {?} event
* @return {?}
*/
EventBusService.prototype.emitToApp = /**
* @param {?} event
* @return {?}
*/
function (event) {
var /** @type {?} */ emitter = this.eventEmitterMap.get(event.code);
if (emitter != null) {
console.log("Emitting event : " + JSON.stringify(event));
emitter.emit(event);
}
else {
console.log("WARNING : Emitting an event without any handler : " + JSON.stringify(event));
}
//--- Emitting to global handlers
emitter = this.eventEmitterMap.get(AppEvent.ANY);
if (emitter != null) {
emitter.emit(event);
}
};
/**
* @param {?} handler
* @return {?}
*/
EventBusService.prototype.subscribeToError = /**
* @param {?} handler
* @return {?}
*/
function (handler) {
return this.errorEvents.subscribe(handler, null, null);
};
/**
* @param {?} event
* @return {?}
*/
EventBusService.prototype.emitToError = /**
* @param {?} event
* @return {?}
*/
function (event) {
console.log("Emitting error event : " + JSON.stringify(event));
this.errorEvents.emit(event);
};
EventBusService.decorators = [
{ type: Injectable },
];
/** @nocollapse */
EventBusService.ctorParameters = function () { return []; };
return EventBusService;
}());
//=============================================================================
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
/** @enum {number} */
var Status = {
LOGIN: 0,
LOADING: 1,
READY: 2,
};
Status[Status.LOGIN] = "LOGIN";
Status[Status.LOADING] = "LOADING";
Status[Status.READY] = "READY";
var ApplicationService = /** @class */ (function (_super) {
__extends(ApplicationService, _super);
//-------------------------------------------------------------------------
//---
//--- Constructor
//---
//-------------------------------------------------------------------------
function ApplicationService(eventBusService) {
var _this = _super.call(this, eventBusService) || this;
_this.status = Status.LOGIN;
_super.prototype.subscribeToApp.call(_this, AppEvent.LOGIN_SUCCESS, function (event) { return _this.onLoginSuccess(event); });
_super.prototype.subscribeToApp.call(_this, AppEvent.LOGIN_FAILED, function (event) { return _this.onLoginFailed(event); });
_super.prototype.subscribeToApp.call(_this, AppEvent.LOGOUT_SUCCESS, function (event) { return _this.onLogoutSuccess(event); });
_super.prototype.subscribeToApp.call(_this, AppEvent.LOGOUT_FAILED, function (event) { return _this.onLogoutFailed(event); });
_super.prototype.subscribeToApp.call(_this, AppEvent.INVALID_TOKEN, function (event) { return _this.onInvalidToken(event); });
_super.prototype.subscribeToApp.call(_this, AppEvent.APPLICATION_READY, function (event) { return _this.onApplicationReady(event); });
return _this;
}
/**
* @return {?}
*/
ApplicationService.prototype.isStatusLogin = /**
* @return {?}
*/
function () {
return this.status == Status.LOGIN;
};
/**
* @return {?}
*/
ApplicationService.prototype.isStatusLoading = /**
* @return {?}
*/
function () {
return this.status == Status.LOADING;
};
/**
* @return {?}
*/
ApplicationService.prototype.isStatusReady = /**
* @return {?}
*/
function () {
return this.status == Status.READY;
};
/**
* @param {?} event
* @return {?}
*/
ApplicationService.prototype.onLoginSuccess = /**
* @param {?} event
* @return {?}
*/
function (event) {
this.status = Status.LOADING;
};
/**
* @param {?} event
* @return {?}
*/
ApplicationService.prototype.onLoginFailed = /**
* @param {?} event
* @return {?}
*/
function (event) {
this.status = Status.LOGIN;
};
/**
* @param {?} event
* @return {?}
*/
ApplicationService.prototype.onLogoutSuccess = /**
* @param {?} event
* @return {?}
*/
function (event) {
this.status = Status.LOGIN;
};
/**
* @param {?} event
* @return {?}
*/
ApplicationService.prototype.onLogoutFailed = /**
* @param {?} event
* @return {?}
*/
function (event) {
this.status = Status.LOGIN;
};
/**
* @param {?} event
* @return {?}
*/
ApplicationService.prototype.onInvalidToken = /**
* @param {?} event
* @return {?}
*/
function (event) {
this.status = Status.LOGIN;
};
/**
* @param {?} event
* @return {?}
*/
ApplicationService.prototype.onApplicationReady = /**
* @param {?} event
* @return {?}
*/
function (event) {
this.status = Status.READY;
};
ApplicationService.decorators = [
{ type: Injectable },
];
/** @nocollapse */
ApplicationService.ctorParameters = function () { return [
{ type: EventBusService, },
]; };
return ApplicationService;
}(AbstractSubscriber));
//=============================================================================
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
var HttpService = /** @class */ (function () {
//-------------------------------------------------------------------------
//---
//--- Constructor
//---
//-------------------------------------------------------------------------
function HttpService(httpClient, eventBusService, domSanitizer) {
this.httpClient = httpClient;
this.eventBusService = eventBusService;
this.domSanitizer = domSanitizer;
this.openRequests = 0;
}
Object.defineProperty(HttpService.prototype, "loading", {
get: /**
* @return {?}
*/
function () {
return (this.openRequests > 0);
},
enumerable: true,
configurable: true
});
/**
* @param {?} url
* @param {?=} options
* @return {?}
*/
HttpService.prototype.getObject = /**
* @param {?} url
* @param {?=} options
* @return {?}
*/
function (url, options) {
var _this = this;
this.showLoader();
//--- "Pragma": "no-cache" for IE 11
var /** @type {?} */ header = {
"Pragma": "no-cache",
"Cache-Control": "no-cache",
"Expires": "0"
};
return this.httpClient.get(url, { params: options, headers: header }).pipe(catchError(function (error) { return _this.handleError(error); }), finalize(function () { return _this.hideLoader(); }));
};
/**
* @param {?} url
* @param {?=} options
* @return {?}
*/
HttpService.prototype.getBlob = /**
* @param {?} url
* @param {?=} options
* @return {?}
*/
function (url, options) {
var _this = this;
this.showLoader();
//--- Add timestamp to change static url to dynamic for IE 11
if (options != null) {
options.ts = Date.now();
}
return this.httpClient.get(url, { params: options, responseType: 'blob' }).pipe(map(function (e) { return _this.getSanitizedUrl(URL.createObjectURL(e)); }), catchError(function (error) { return _this.handleError(error); }), finalize(function () { return _this.hideLoader(); }));
};
/**
* @param {?} url
* @param {?} object
* @param {?=} options
* @return {?}
*/
HttpService.prototype.postObject = /**
* @param {?} url
* @param {?} object
* @param {?=} options
* @return {?}
*/
function (url, object, options) {
var _this = this;
this.showLoader();
return this.httpClient.post(url, object, options).pipe(catchError(function (error) { return _this.handleError(error); }), finalize(function () { return _this.hideLoader(); }));
};
/**
* @param {?} url
* @return {?}
*/
HttpService.prototype.getSanitizedUrl = /**
* @param {?} url
* @return {?}
*/
function (url) {
return this.domSanitizer.bypassSecurityTrustResourceUrl(url);
};
/**
* @param {?} response
* @return {?}
*/
HttpService.prototype.handleError = /**
* @param {?} response
* @return {?}
*/
function (response) {
console.log("Got the following HTTP error : " + JSON.stringify(response));
var /** @type {?} */ error;
if (response.status == 422) {
//--- Unprocessable entity
error = response.error;
}
else {
error = {
code: response.status.toString(),
error: response.error.toString()
};
}
this.eventBusService.emitToError(error);
return throwError(error);
};
/**
* @return {?}
*/
HttpService.prototype.showLoader = /**
* @return {?}
*/
function () {
if (++this.openRequests == 1) {
this.eventBusService.emitToApp(new AppEvent(AppEvent.SUBMIT_START));
}
};
/**
* @return {?}
*/
HttpService.prototype.hideLoader = /**
* @return {?}
*/
function () {
if (--this.openRequests == 0) {
this.eventBusService.emitToApp(new AppEvent(AppEvent.SUBMIT_END));
}
};
HttpService.decorators = [
{ type: Injectable },
];
/** @nocollapse */
HttpService.ctorParameters = function () { return [
{ type: HttpClient, },
{ type: EventBusService, },
{ type: DomSanitizer, },
]; };
return HttpService;
}());
//=============================================================================
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
var LabelService = /** @class */ (function () {
//-------------------------------------------------------------------------
//---
//--- Constructor
//---
//-------------------------------------------------------------------------
function LabelService(httpService) {
var _this = this;
this.httpService = httpService;
this.languages = ["en", "it"];
this.labelSet = new Map();
this.language = "en";
//--- Load language files
this.languages.forEach(function (language) {
_this.initLanguage(language);
});
}
/**
* @param {?} language
* @return {?}
*/
LabelService.prototype.setLanguage = /**
* @param {?} language
* @return {?}
*/
function (language) {
this.language = language;
};
/**
* @param {?} entity
* @param {?} code
* @return {?}
*/
LabelService.prototype.getLabel = /**
* @param {?} entity
* @param {?} code
* @return {?}
*/
function (entity, code) {
if (code == null) {
return null;
}
var /** @type {?} */ entitySet = this.getMapping(entity);
if (entitySet == null) {
return "?" + entity + "?";
}
var /** @type {?} */ label = entitySet[code];
if (label == null) {
return entity + ".?" + code + "?";
}
return label;
};
/**
* @param {?} entity
* @return {?}
*/
LabelService.prototype.getMapping = /**
* @param {?} entity
* @return {?}
*/
function (entity) {
var /** @type {?} */ labels = this.labelSet.get(this.language);
if (labels != null) {
return labels.get(entity);
}
//--- Probably, we are still loading data
return null;
};
/**
* @param {?} language
* @return {?}
*/
LabelService.prototype.initLanguage = /**
* @param {?} language
* @return {?}
*/
function (language) {
this.loadLanguageFile(language, LabelService.TOOLKIT_FILE);
this.loadLanguageFile(language, LabelService.APPLICATION_FILE);
};
/**
* @param {?} language
* @param {?} name
* @return {?}
*/
LabelService.prototype.loadLanguageFile = /**
* @param {?} language
* @param {?} name
* @return {?}
*/
function (language, name) {
var _this = this;
var /** @type {?} */ file = name + "-" + language + ".json";
this.httpService.getObject("asset/lang/" + file)
.subscribe(function (result) { return _this.processFile(language, file, result); }, function (error) { return console.log("Cannot load labels file : " + file); });
};
/**
* @param {?} language
* @param {?} file
* @param {?} data
* @return {?}
*/
LabelService.prototype.processFile = /**
* @param {?} language
* @param {?} file
* @param {?} data
* @return {?}
*/
function (language, file, data) {
console.log("Loaded labels file : " + file);
var /** @type {?} */ labels = this.labelSet.get(language);
if (labels == null) {
labels = new Map();
this.labelSet.set(language, labels);
}
for (var /** @type {?} */ key in data) {
labels.set(key, data[key]);
}
};
LabelService.TOOLKIT_FILE = "toolkit";
LabelService.APPLICATION_FILE = "application";
LabelService.decorators = [
{ type: Injectable },
];
/** @nocollapse */
LabelService.ctorParameters = function () { return [
{ type: HttpService, },
]; };
return LabelService;
}());
//=============================================================================
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
var NotificationService = /** @class */ (function () {
//-------------------------------------------------------------------------
//---
//--- Constructor
//---
//-------------------------------------------------------------------------
function NotificationService(messageService) {
this.messageService = messageService;
}
/**
* @param {?} title
* @param {?} message
* @return {?}
*/
NotificationService.prototype.showSuccess = /**
* @param {?} title
* @param {?} message
* @return {?}
*/
function (title, message) {
this.show('success', title, message);
};
/**
* @param {?} title
* @param {?} message
* @return {?}
*/
NotificationService.prototype.showInfo = /**
* @param {?} title
* @param {?} message
* @return {?}
*/
function (title, message) {
this.show('info', title, message);
};
/**
* @param {?} title
* @param {?} message
* @return {?}
*/
NotificationService.prototype.showWarn = /**
* @param {?} title
* @param {?} message
* @return {?}
*/
function (title, message) {
this.show('warn', title, message);
};
/**
* @param {?} title
* @param {?} message
* @return {?}
*/
NotificationService.prototype.showError = /**
* @param {?} title
* @param {?} message
* @return {?}
*/
function (title, message) {
this.show('error', title, message);
};
/**
* @param {?} severity
* @param {?} title
* @param {?} message
* @return {?}
*/
NotificationService.prototype.show = /**
* @param {?} severity
* @param {?} title
* @param {?} message
* @return {?}
*/
function (severity, title, message) {
this.messageService.add({
severity: severity,
summary: title,
detail: message
});
};
NotificationService.decorators = [
{ type: Injectable },
];
/** @nocollapse */
NotificationService.ctorParameters = function () { return [
{ type: MessageService, },
]; };
return NotificationService;
}());
//=============================================================================
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
var SessionService = /** @class */ (function (_super) {
__extends(SessionService, _super);
//-------------------------------------------------------------------------
//---
//--- Constructor
//---
//-------------------------------------------------------------------------
function SessionService(eventBusService, httpService) {
var _this = _super.call(this, eventBusService) || this;
_this.httpService = httpService;
_this.clearSession();
_super.prototype.subscribeToApp.call(_this, AppEvent.INVALID_TOKEN, function (event) { return _this.onInvalidToken(event); });
return _this;
}
/**
* @param {?} cred
* @return {?}
*/
SessionService.prototype.login = /**
* @param {?} cred
* @return {?}
*/
function (cred) {
var _this = this;
console.log("SessionService.login : Logging in user='" + cred.username + "'");
//--- Loads user profile from server
this.httpService.postObject("/api/session/login", cred)
.subscribe(function (result) { return _this.loginSuccess(result); }, function (error) { return _this.loginError(error); });
};
/**
* @return {?}
*/
SessionService.prototype.logout = /**
* @return {?}
*/
function () {
var _this = this;
console.log("SessionService.logout : Logging out user='" + (this.user || "???") + "'");
this.httpService.postObject("/api/session/logout", { token: this.token })
.subscribe(function (result) { return _this.logoutSuccess(); }, function (error) { return _this.logoutError(error); });
};
/**
* @return {?}
*/
SessionService.prototype.clearSession = /**
* @return {?}
*/
function () {
console.log("SessionService.clearSession: Resetting session...");
this.session = null;
this.token = null;
this.user = null;
this.profile = null;
this.permissions = new Map();
};
Object.defineProperty(SessionService.prototype, "homePage", {
get: /**
* @return {?}
*/
function () {
return (this.profile)
? this.profile.homePage
: null;
},
enumerable: true,
configurable: true
});
/**
* @param {?} name
* @return {?}
*/
SessionService.prototype.hasPermission = /**
* @param {?} name
* @return {?}
*/
function (name) {
return (this.permissions.get(name));
};
/**
* @param {?} session
* @return {?}
*/
SessionService.prototype.loginSuccess = /**
* @param {?} session
* @return {?}
*/
function (session) {
this.session = session;
this.token = session.token;
this.user = session.user;
this.profile = session.profile;
this.permissions = this.setupPermissionMap(this.profile.permissions);
_super.prototype.emitToApp.call(this, new AppEvent(AppEvent.LOGIN_SUCCESS, session));
console.log("Login successful for user=" + this.user.username);
};
/**
* @param {?} response
* @return {?}
*/
SessionService.prototype.loginError = /**
* @param {?} response
* @return {?}
*/
function (response) {
_super.prototype.emitToApp.call(this, new AppEvent(AppEvent.LOGIN_FAILED, response));
};
/**
* @return {?}
*/
SessionService.prototype.logoutSuccess = /**
* @return {?}
*/
function () {
var /** @type {?} */ username = this.user.username;
this.clearSession();
_super.prototype.emitToApp.call(this, new AppEvent(AppEvent.LOGOUT_SUCCESS, username));
console.log("Logout successful for user=" + username);
};
/**
* @param {?} response
* @return {?}
*/
SessionService.prototype.logoutError = /**
* @param {?} response
* @return {?}
*/
function (response) {
this.clearSession();
_super.prototype.emitToApp.call(this, new AppEvent(AppEvent.LOGOUT_FAILED));
};
/**
* @param {?} permissions
* @return {?}
*/
SessionService.prototype.setupPermissionMap = /**
* @param {?} permissions
* @return {?}
*/
function (permissions) {
var /** @type {?} */ map$$1 = new Map();
permissions.forEach(function (p) { return map$$1.set(p, true); });
return map$$1;
};
/**
* @param {?} event
* @return {?}
*/
SessionService.prototype.onInvalidToken = /**
* @param {?} event
* @return {?}
*/
function (event) {
this.clearSession();
};
SessionService.decorators = [
{ type: Injectable },
];
/** @nocollapse */
SessionService.ctorParameters = function () { return [
{ type: EventBusService, },
{ type: HttpService, },
]; };
return SessionService;
}(AbstractSubscriber));
//=============================================================================
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
var HpeServiceModule = /** @class */ (function () {
function HpeServiceModule() {
}
HpeServiceModule.decorators = [
{ type: NgModule, args: [{
imports: [
CommonModule
],
declarations: [],
exports: [],
providers: [
ApplicationService,
EventBusService,
HttpService,
LabelService,
NotificationService,
SessionService,
MessageService$1
],
},] },
];
return HpeServiceModule;
}());
//=============================================================================
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
//=============================================================================
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
export { HpeServiceModule, AbstractSubscriber, ApplicationService, EventBusService, HttpService, LabelService, NotificationService, SessionService };
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaHBlLWFuZ3VsYXItdG9vbGtpdC1zZXJ2aWNlLmpzLm1hcCIsInNvdXJjZXMiOlsibmc6Ly9AaHBlL2FuZ3VsYXItdG9vbGtpdC9zZXJ2aWNlL2Fic3RyYWN0LXN1YnNjcmliZXIudHMiLCJuZzovL0BocGUvYW5ndWxhci10b29sa2l0L3NlcnZpY2UvZXZlbnRidXMtc2VydmljZS50cyIsIm5nOi8vQGhwZS9hbmd1bGFyLXRvb2xraXQvc2VydmljZS9hcHBsaWNhdGlvbi1zZXJ2aWNlLnRzIiwibmc6Ly9AaHBlL2FuZ3VsYXItdG9vbGtpdC9zZXJ2aWNlL2h0dHAtc2VydmljZS50cyIsIm5nOi8vQGhwZS9hbmd1bGFyLXRvb2xraXQvc2VydmljZS9sYWJlbC1zZXJ2aWNlLnRzIiwibmc6Ly9AaHBlL2FuZ3VsYXItdG9vbGtpdC9zZXJ2aWNlL25vdGlmaWNhdGlvbi1zZXJ2aWNlLnRzIiwibmc6Ly9AaHBlL2FuZ3VsYXItdG9vbGtpdC9zZXJ2aWNlL3Nlc3Npb24tc2VydmljZS50cyIsIm5nOi8vQGhwZS9hbmd1bGFyLXRvb2xraXQvc2VydmljZS9tb2R1bGUudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLy89PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuLy89PT1cbi8vPT09IChDKSBDb3B5cmlnaHQgMjAxOCBIZXdsZXR0IFBhY2thcmQgRW50ZXJwcmlzZSBEZXZlbG9wbWVudCBMUC5cbi8vPT09XG4vLz09PSBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhbiBNSVQtc3R5bGUgbGljZW5zZSB0aGF0IGNhbiBiZVxuLy89PT0gZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZVxuLy89PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG5pbXBvcnQge09uRGVzdHJveX0gICAgZnJvbSBcIkBhbmd1bGFyL2NvcmVcIjtcbmltcG9ydCB7U3Vic2NyaXB0aW9ufSBmcm9tIFwicnhqc1wiO1xuXG5pbXBvcnQge0V2ZW50SGFuZGxlciwgRXJyb3JIYW5kbGVyLCBBcHBFdmVudCwgRXJyb3JFdmVudH0gZnJvbSBcIkBocGUvYW5ndWxhci10b29sa2l0L21vZGVsXCI7XG5cbmltcG9ydCB7RXZlbnRCdXNTZXJ2aWNlfSBmcm9tIFwiLi9ldmVudGJ1cy1zZXJ2aWNlXCI7XG5cbi8vPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuZXhwb3J0IGNsYXNzIEFic3RyYWN0U3Vic2NyaWJlciBpbXBsZW1lbnRzIE9uRGVzdHJveSB7XG5cblx0Ly8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cdC8vLS0tXG5cdC8vLS0tIFZhcmlhYmxlc1xuXHQvLy0tLVxuXHQvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuXHRwcml2YXRlIHN1YnNjcmlwdGlvbnM6IFN1YnNjcmlwdGlvbltdID0gW107XG5cblx0Ly8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cdC8vLS0tXG5cdC8vLS0tIENvbnN0cnVjdG9yXG5cdC8vLS0tXG5cdC8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cdGNvbnN0cnVjdG9yKHByaXZhdGUgZXZlbnRCdXNTZXJ2aWNlIDogRXZlbnRCdXNTZXJ2aWNlKSB7fVxuXG5cdC8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXHQvLy0tLVxuXHQvLy0tLSBMaWZlY3ljbGUgbWV0aG9kc1xuXHQvLy0tLVxuXHQvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuXHRwdWJsaWMgbmdPbkRlc3Ryb3koKSB7XG5cdFx0dGhpcy5zdWJzY3JpcHRpb25zLmZvckVhY2goIChzIDogU3Vic2NyaXB0aW9uKSA9PiBzLnVuc3Vic2NyaWJlKCkpO1xuXHR9XG5cblx0Ly8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cdC8vLS0tXG5cdC8vLS0tIEFQSSBtZXRob2RzXG5cdC8vLS0tXG5cdC8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cdHByb3RlY3RlZCBzdWJzY3JpYmVUb0FwcChldmVudENvZGUgOiBzdHJpbmcsIGhhbmRsZXIgOiBFdmVudEhhbmRsZXIpIDogU3Vic2NyaXB0aW9uIHtcblxuXHRcdGxldCBzIDogU3Vic2NyaXB0aW9uID0gdGhpcy5ldmVudEJ1c1NlcnZpY2Uuc3Vic2NyaWJlVG9BcHAoZXZlbnRDb2RlLCBoYW5kbGVyKTtcblx0XHR0aGlzLnN1YnNjcmlwdGlvbnMucHVzaChzKTtcblxuXHRcdHJldHVybiBzO1xuXHR9XG5cblx0Ly8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cblx0cHJvdGVjdGVkIGVtaXRUb0FwcChldmVudCA6IEFwcEV2ZW50KSA6IHZvaWQge1xuXHRcdHRoaXMuZXZlbnRCdXNTZXJ2aWNlLmVtaXRUb0FwcChldmVudCk7XG5cdH1cblxuXHQvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuXHRwcm90ZWN0ZWQgc3Vic2NyaWJlVG9FcnJvcihoYW5kbGVyIDogRXJyb3JIYW5kbGVyKSA6IFN1YnNjcmlwdGlvbiB7XG5cblx0XHRsZXQgcyA6IFN1YnNjcmlwdGlvbiA9IHRoaXMuZXZlbnRCdXNTZXJ2aWNlLnN1YnNjcmliZVRvRXJyb3IoaGFuZGxlcik7XG5cdFx0dGhpcy5zdWJzY3JpcHRpb25zLnB1c2gocyk7XG5cblx0XHRyZXR1cm4gcztcblx0fVxuXG5cdC8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cdHByb3RlY3RlZCBlbWl0VG9FcnJvcihldmVudCA6IEVycm9yRXZlbnQpIDogdm9pZCB7XG5cdFx0dGhpcy5ldmVudEJ1c1NlcnZpY2UuZW1pdFRvRXJyb3IoZXZlbnQpO1xuXHR9XG59XG5cbi8vPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiIsIi8vPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vPT09XG4vLz09PSAoQykgQ29weXJpZ2h0IDIwMTggSGV3bGV0dCBQYWNrYXJkIEVudGVycHJpc2UgRGV2ZWxvcG1lbnQgTFAuXG4vLz09PVxuLy89PT0gVXNlIG9mIHRoaXMgc291cmNlIGNvZGUgaXMgZ292ZXJuZWQgYnkgYW4gTUlULXN0eWxlIGxpY2Vuc2UgdGhhdCBjYW4gYmVcbi8vPT09IGZvdW5kIGluIHRoZSBMSUNFTlNFIGZpbGVcbi8vPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuaW1wb3J0IHtFdmVudEVtaXR0ZXIsIEluamVjdGFibGV9IGZyb20gXCJAYW5ndWxhci9jb3JlXCI7XG5cbmltcG9ydCB7U3Vic2NyaXB0aW9ufSBmcm9tIFwicnhqc1wiO1xuXG5pbXBvcnQge0FwcEV2ZW50LCBFcnJvckV2ZW50LCBFcnJvckhhbmRsZXIsIEV2ZW50SGFuZGxlcn0gZnJvbSBcIkBocGUvYW5ndWxhci10b29sa2l0L21vZGVsXCI7XG5cbi8vPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuQEluamVjdGFibGUoKVxuZXhwb3J0IGNsYXNzIEV2ZW50QnVzU2VydmljZSB7XG5cblx0Ly8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cdC8vLS0tXG5cdC8vLS0tIFZhcmlhYmxlc1xuXHQvLy0tLVxuXHQvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuXHRwcml2YXRlIGV2ZW50RW1pdHRlck1hcCA6IE1hcDxzdHJpbmcsIEV2ZW50RW1pdHRlcjxBcHBFdmVudD4+ID0gbmV3IE1hcCgpO1xuXHRwcml2YXRlIGVycm9yRXZlbnRzICAgICA6IEV2ZW50RW1pdHRlcjxFcnJvckV2ZW50PiA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcblxuXHQvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblx0Ly8tLS1cblx0Ly8tLS0gQ29uc3RydWN0b3Jcblx0Ly8tLS1cblx0Ly8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cblx0Y29uc3RydWN0b3IoKSB7XG5cdH1cblxuXHQvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblx0Ly8tLS1cblx0Ly8tLS0gQVBJIG1ldGhvZHNcblx0Ly8tLS1cblx0Ly8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cblx0cHVibGljIHN1YnNjcmliZVRvQXBwKGV2ZW50Q29kZSA6IHN0cmluZywgaGFuZGxlciA6IEV2ZW50SGFuZGxlcikgOiBTdWJzY3JpcHRpb24ge1xuXG5cdFx0bGV0IGVtaXR0ZXIgOiBFdmVudEVtaXR0ZXI8QXBwRXZlbnQ+ID0gdGhpcy5ldmVudEVtaXR0ZXJNYXAuZ2V0KGV2ZW50Q29kZSk7XG5cblx0XHRpZiAoZW1pdHRlciA9PSBudWxsKSB7XG5cdFx0XHRlbWl0dGVyID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuXHRcdFx0dGhpcy5ldmVudEVtaXR0ZXJNYXAuc2V0KGV2ZW50Q29kZSwgZW1pdHRlcik7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGVtaXR0ZXIuc3Vic2NyaWJlKGhhbmRsZXIsIG51bGwsIG51bGwpO1xuXHR9XG5cblx0Ly8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cblx0cHVibGljIGVtaXRUb0FwcChldmVudCA6IEFwcEV2ZW50KSA6IHZvaWQge1xuXG5cdFx0bGV0IGVtaXR0ZXIgPSB0aGlzLmV2ZW50RW1pdHRlck1hcC5nZXQoZXZlbnQuY29kZSk7XG5cblx0XHRpZiAoZW1pdHRlciAhPSBudWxsKSB7XG5cdFx0XHRjb25zb2xlLmxvZyhcIkVtaXR0aW5nIGV2ZW50IDogXCIrIEpTT04uc3RyaW5naWZ5KGV2ZW50KSk7XG5cdFx0XHRlbWl0dGVyLmVtaXQoZXZlbnQpO1xuXHRcdH1cblx0XHRlbHNlIHtcblx0XHRcdGNvbnNvbGUubG9nKFwiV0FSTklORyA6IEVtaXR0aW5nIGFuIGV2ZW50IHdpdGhvdXQgYW55IGhhbmRsZXIgOiBcIisgSlNPTi5zdHJpbmdpZnkoZXZlbnQpKTtcblx0XHR9XG5cblx0XHQvLy0tLSBFbWl0dGluZyB0byBnbG9iYWwgaGFuZGxlcnNcblxuXHRcdGVtaXR0ZXIgPSB0aGlzLmV2ZW50RW1pdHRlck1hcC5nZXQoQXBwRXZlbnQuQU5ZKTtcblxuXHRcdGlmIChlbWl0dGVyICE9IG51bGwpIHtcblx0XHRcdGVtaXR0ZXIuZW1pdChldmVudCk7XG5cdFx0fVxuXHR9XG5cblx0Ly8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cblx0cHVibGljIHN1YnNjcmliZVRvRXJyb3IoaGFuZGxlciA6IEVycm9ySGFuZGxlcikgOiBTdWJzY3JpcHRpb24ge1xuXHRcdHJldHVybiB0aGlzLmVycm9yRXZlbnRzLnN1YnNjcmliZShoYW5kbGVyLCBudWxsLCBudWxsKTtcblx0fVxuXG5cdC8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cdHB1YmxpYyBlbWl0VG9FcnJvcihldmVudCA6IEVycm9yRXZlbnQpIDogdm9pZCB7XG5cdFx0Y29uc29sZS5sb2coXCJFbWl0dGluZyBlcnJvciBldmVudCA6IFwiKyBKU09OLnN0cmluZ2lmeShldmVudCkpO1xuXHRcdHRoaXMuZXJyb3JFdmVudHMuZW1pdChldmVudCk7XG5cdH1cbn1cblxuLy89PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuIiwiLy89PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuLy89PT1cbi8vPT09IChDKSBDb3B5cmlnaHQgMjAxOCBIZXdsZXR0IFBhY2thcmQgRW50ZXJwcmlzZSBEZXZlbG9wbWVudCBMUC5cbi8vPT09XG4vLz09PSBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhbiBNSVQtc3R5bGUgbGljZW5zZSB0aGF0IGNhbiBiZVxuLy89PT0gZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZVxuLy89PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG5pbXBvcnQge0luamVjdGFibGV9ICAgICAgICAgZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQge0FwcEV2ZW50fSAgICAgICAgICAgZnJvbSBcIkBocGUvYW5ndWxhci10b29sa2l0L21vZGVsXCI7XG5cbmltcG9ydCB7QWJzdHJhY3RTdWJzY3JpYmVyfSBmcm9tIFwiLi9hYnN0cmFjdC1zdWJzY3JpYmVyXCI7XG5pbXBvcnQge0V2ZW50QnVzU2VydmljZX0gICAgZnJvbSBcIi4vZXZlbnRidXMtc2VydmljZVwiO1xuXG4vLz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbmVudW0gU3RhdHVzIHtcblx0TE9HSU4sXG5cdExPQURJTkcsXG5cdFJFQURZXG59XG5cbi8vPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuQEluamVjdGFibGUoKVxuZXhwb3J0IGNsYXNzIEFwcGxpY2F0aW9uU2VydmljZSBleHRlbmRzIEFic3RyYWN0U3Vic2NyaWJlciB7XG5cblx0Ly8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cdC8vLS0tXG5cdC8vLS0tIFZhcmlhYmxlc1xuXHQvLy0tLVxuXHQvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuXHRwcml2YXRlIHN0YXR1cyA6IFN0YXR1cyA9IFN0YXR1cy5MT0dJTjtcblxuXHQvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblx0Ly8tLS1cblx0Ly8tLS0gQ29uc3RydWN0b3Jcblx0Ly8tLS1cblx0Ly8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cblx0Y29uc3RydWN0b3IoZXZlbnRCdXNTZXJ2aWNlOiBFdmVudEJ1c1NlcnZpY2UpIHtcblxuXHRcdHN1cGVyKGV2ZW50QnVzU2VydmljZSk7XG5cblx0XHRzdXBlci5zdWJzY3JpYmVUb0FwcChBcHBFdmVudC5MT0dJTl9TVUNDRVNTLCAgICAgKGV2ZW50IDogQXBwRXZlbnQpID0+IHRoaXMub25Mb2dpblN1Y2Nlc3MgICAgKGV2ZW50KSk7XG5cdFx0c3VwZXIuc3Vic2NyaWJlVG9BcHAoQXBwRXZlbnQuTE9HSU5fRkFJTEVELCAgICAgIChldmVudCA6IEFwcEV2ZW50KSA9PiB0aGlzLm9uTG9naW5GYWlsZWQgICAgIChldmVudCkpO1xuXHRcdHN1cGVyLnN1YnNjcmliZVRvQXBwKEFwcEV2ZW50LkxPR09VVF9TVUNDRVNTLCAgICAoZXZlbnQgOiBBcHBFdmVudCkgPT4gdGhpcy5vbkxvZ291dFN1Y2Nlc3MgICAoZXZlbnQpKTtcblx0XHRzdXBlci5zdWJzY3JpYmVUb0FwcChBcHBFdmVudC5MT0dPVVRfRkFJTEVELCAgICAgKGV2ZW50IDogQXBwRXZlbnQpID0+IHRoaXMub25Mb2dvdXRGYWlsZWQgICAgKGV2ZW50KSk7XG5cdFx0c3VwZXIuc3Vic2NyaWJlVG9BcHAoQXBwRXZlbnQuSU5WQUxJRF9UT0tFTiwgICAgIChldmVudCA6IEFwcEV2ZW50KSA9PiB0aGlzLm9uSW52YWxpZFRva2VuICAgIChldmVudCkpO1xuXHRcdHN1cGVyLnN1YnNjcmliZVRvQXBwKEFwcEV2ZW50LkFQUExJQ0FUSU9OX1JFQURZLCAoZXZlbnQgOiBBcHBFdmVudCkgPT4gdGhpcy5vbkFwcGxpY2F0aW9uUmVhZHkoZXZlbnQpKTtcblx0fVxuXG5cdC8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXHQvLy0tLVxuXHQvLy0tLSBBUEkgbWV0aG9kc1xuXHQvLy0tLVxuXHQvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuXHRwdWJsaWMgaXNTdGF0dXNMb2dpbigpIDogYm9vbGVhbiB7XG5cdFx0cmV0dXJuIHRoaXMuc3RhdHVzID09IFN0YXR1cy5MT0dJTjtcblx0fVxuXG5cdC8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cdHB1YmxpYyBpc1N0YXR1c0xvYWRpbmcoKSA6IGJvb2xlYW4ge1xuXHRcdHJldHVybiB0aGlzLnN0YXR1cyA9PSBTdGF0dXMuTE9BRElORztcblx0fVxuXG5cdC8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cdHB1YmxpYyBpc1N0YXR1c1JlYWR5KCkgOiBib29sZWFuIHtcblx0XHRyZXR1cm4gdGhpcy5zdGF0dXMgPT0gU3RhdHVzLlJFQURZO1xuXHR9XG5cblx0Ly8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cdC8vLS0tXG5cdC8vLS0tIEV2ZW50c1xuXHQvLy0tLVxuXHQvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuXHRwcml2YXRlIG9uTG9naW5TdWNjZXNzKGV2ZW50IDogQXBwRXZlbnQpIHtcblx0XHR0aGlzLnN0YXR1cyA9IFN0YXR1cy5MT0FESU5HO1xuXHR9XG5cblx0Ly8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cblx0cHJpdmF0ZSBvbkxvZ2luRmFpbGVkKGV2ZW50IDogQXBwRXZlbnQpIHtcblx0XHR0aGlzLnN0YXR1cyA9IFN0YXR1cy5MT0dJTjtcblx0fVxuXG5cdC8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cdHByaXZhdGUgb25Mb2dvdXRTdWNjZXNzKGV2ZW50IDogQXBwRXZlbnQpIHtcblx0XHR0aGlzLnN0YXR1cyA9IFN0YXR1cy5MT0dJTjtcblx0fVxuXG5cdC8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cdHByaXZhdGUgb25Mb2dvdXRGYWlsZWQoZXZlbnQgOiBBcHBFdmVudCkge1xuXHRcdHRoaXMuc3RhdHVzID0gU3RhdHVzLkxPR0lOO1xuXHR9XG5cblx0Ly8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cblx0cHJpdmF0ZSBvbkludmFsaWRUb2tlbihldmVudCA6IEFwcEV2ZW50KSB7XG5cdFx0dGhpcy5zdGF0dXMgPSBTdGF0dXMuTE9HSU47XG5cdH1cblxuXHQvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuXHRwcml2YXRlIG9uQXBwbGljYXRpb25SZWFkeShldmVudCA6IEFwcEV2ZW50KSB7XG5cdFx0dGhpcy5zdGF0dXMgPSBTdGF0dXMuUkVBRFk7XG5cdH1cbn1cblxuLy89PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuIiwiLy89PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuLy89PT1cbi8vPT09IChDKSBDb3B5cmlnaHQgMjAxOCBIZXdsZXR0IFBhY2thcmQgRW50ZXJwcmlzZSBEZXZlbG9wbWVudCBMUC5cbi8vPT09XG4vLz09PSBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhbiBNSVQtc3R5bGUgbGljZW5zZSB0aGF0IGNhbiBiZVxuLy89PT0gZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZVxuLy89PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG5pbXBvcnQge0luamVjdGFibGV9ICAgZnJvbSBcIkBhbmd1bGFyL2NvcmVcIjtcbmltcG9ydCB7SHR0cENsaWVudH0gICBmcm9tIFwiQGFuZ3VsYXIvY29tbW9uL2h0dHBcIjtcbmltcG9ydCB7RG9tU2FuaXRpemVyfSBmcm9tIFwiQGFuZ3VsYXIvcGxhdGZvcm0tYnJvd3NlclwiO1xuaW1wb3J0IHtTYWZlVXJsfSAgICAgIGZyb20gXCJAYW5ndWxhci9wbGF0Zm9ybS1icm93c2VyL3NyYy9zZWN1cml0eS9kb21fc2FuaXRpemF0aW9uX3NlcnZpY2VcIjtcblxuaW1wb3J0IHtPYnNlcnZhYmxlLCB0aHJvd0Vycm9yfSAgICBmcm9tIFwicnhqc1wiO1xuaW1wb3J0IHtjYXRjaEVycm9yLCBtYXAsIGZpbmFsaXplfSBmcm9tIFwicnhqcy9vcGVyYXRvcnNcIjtcbmltcG9ydCB7QXBwRXZlbnQsIEVycm9yRXZlbnQgfSAgICAgZnJvbSBcIkBocGUvYW5ndWxhci10b29sa2l0L21vZGVsXCI7XG5cbmltcG9ydCB7RXZlbnRCdXNTZXJ2aWNlfSAgICAgICAgICAgZnJvbSBcIi4vZXZlbnRidXMtc2VydmljZVwiXG5cbi8vPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuQEluamVjdGFibGUoKVxuZXhwb3J0IGNsYXNzIEh0dHBTZXJ2aWNlIHtcblxuXHQvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblx0Ly8tLS1cblx0Ly8tLS0gVmFyaWFibGVzXG5cdC8vLS0tXG5cdC8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cdHByaXZhdGUgb3BlblJlcXVlc3RzIDogbnVtYmVyID0gMDtcblxuXHQvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblx0Ly8tLS1cblx0Ly8tLS0gQ29uc3RydWN0b3Jcblx0Ly8tLS1cblx0Ly8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cblx0Y29uc3RydWN0b3IocHJpdmF0ZSBodHRwQ2xpZW50ICAgICAgOiBIdHRwQ2xpZW50LFxuXHRcdFx0XHRwcml2YXRlIGV2ZW50QnVzU2VydmljZSA6IEV2ZW50QnVzU2VydmljZSxcblx0XHRcdFx0cHJpdmF0ZSBkb21TYW5pdGl6ZXIgICAgOiBEb21TYW5pdGl6ZXIgKSB7fVxuXG5cdC8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXHQvLy0tLVxuXHQvLy0tLSBBUEkgbWV0aG9kc1xuXHQvLy0tLVxuXHQvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuXHRwdWJsaWMgZ2V0IGxvYWRpbmcoKSA6IGJvb2xlYW4ge1xuXHRcdHJldHVybiAodGhpcy5vcGVuUmVxdWVzdHMgPiAwKTtcblx0fVxuXG5cdC8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cdHB1YmxpYyBnZXRPYmplY3QodXJsIDogc3RyaW5nLCBvcHRpb25zPyA6IGFueSk6IE9ic2VydmFibGU8YW55PiB7XG5cblx0XHR0aGlzLnNob3dMb2FkZXIoKTtcblxuXHRcdC8vLS0tIFwiUHJhZ21hXCI6IFwibm8tY2FjaGVcIiBmb3IgSUUgMTFcblxuXHRcdGxldCBoZWFkZXIgPSB7XG5cdFx0XHRcIlByYWdtYVwiICAgICAgICA6IFwibm8tY2FjaGVcIixcblx0XHRcdFwiQ2FjaGUtQ29udHJvbFwiIDogXCJuby1jYWNoZVwiLFxuXHRcdFx0XCJFeHBpcmVzXCIgICAgICAgOiBcIjBcIlxuXHRcdH07XG5cblx0XHRyZXR1cm4gdGhpcy5odHRwQ2xpZW50LmdldCh1cmwsIHsgcGFyYW1zOiBvcHRpb25zLCBoZWFkZXJzIDogaGVhZGVyIH0pLnBpcGUoXG5cdFx0XHRjYXRjaEVycm9yKChlcnJvcikgPT4gdGhpcy5oYW5kbGVFcnJvcihlcnJvcikpLFxuXHRcdFx0ZmluYWxpemUgICgoKSAgICAgID0+IHRoaXMuaGlkZUxvYWRlcigpKVxuXHRcdCk7XG5cdH1cblxuXHQvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuXHRwdWJsaWMgZ2V0QmxvYih1cmwgOiBzdHJpbmcsIG9wdGlvbnM/IDogYW55KTogT2JzZXJ2YWJsZTxhbnk+IHtcblxuXHRcdHRoaXMuc2hvd0xvYWRlcigpO1xuXG5cdFx0Ly8tLS0gQWRkIHRpbWVzdGFtcCB0byBjaGFuZ2Ugc3RhdGljIHVybCB0byBkeW5hbWljIGZvciBJRSAxMVxuXG5cdFx0aWYgKG9wdGlvbnMgIT0gbnVsbCkge1xuXHRcdFx0b3B0aW9ucy50cyA9IERhdGUubm93KCk7XG5cdFx0fVxuXG4gICAgICAgIHJldHVybiB0aGlzLmh0dHBDbGllbnQuZ2V0KHVybCwgeyBwYXJhbXM6IG9wdGlvbnMsIHJlc3BvbnNlVHlwZSA6ICdibG9iJ30pLnBpcGUoXG5cdFx0XHRtYXAoZSA9PiB0aGlzLmdldFNhbml0aXplZFVybChVUkwuY3JlYXRlT2JqZWN0VVJMKGUpKSksXG5cdFx0XHRjYXRjaEVycm9yKChlcnJvcikgPT4gdGhpcy5oYW5kbGVFcnJvcihlcnJvcikpLFxuXHRcdFx0ZmluYWxpemUoKCkgPT4gdGhpcy5oaWRlTG9hZGVyKCkpXG5cdFx0KTtcblx0fVxuXG5cdC8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cdHB1YmxpYyBwb3N0T2JqZWN0KHVybDogc3RyaW5nLCBvYmplY3Q6IGFueSwgb3B0aW9ucz86IGFueSk6IE9ic2VydmFibGU8YW55PiB7XG5cbiAgICAgICAgdGhpcy5zaG93TG9hZGVyKCk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMuaHR0cENsaWVudC5wb3N0ICh1cmwsIG9iamVjdCwgb3B0aW9ucykucGlwZShcblx0XHRcdGNhdGNoRXJyb3IoKGVycm9yKSA9PiB0aGlzLmhhbmRsZUVycm9yKGVycm9yKSksXG5cdFx0XHRmaW5hbGl6ZSAgKCgpICAgICAgPT4gdGhpcy5oaWRlTG9hZGVyKCkpXG5cdFx0KTtcblx0fVxuXG5cdC8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cdHB1YmxpYyBnZXRTYW5pdGl6ZWRVcmwodXJsIDogc3RyaW5nKTogU2FmZVVybCB7XG5cdFx0cmV0dXJuIHRoaXMuZG9tU2FuaXRpemVyLmJ5cGFzc1NlY3VyaXR5VHJ1c3RSZXNvdXJjZVVybCh1cmwpO1xuXHR9XG5cblx0Ly8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cdC8vLS0tXG5cdC8vLS0tIFByaXZhdGUgbWV0aG9kc1xuXHQvLy0tLVxuXHQvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuXHRwcml2YXRlIGhhbmRsZUVycm9yKHJlc3BvbnNlIDogYW55KSA6IE9ic2VydmFibGU8YW55PiB7XG5cblx0XHRjb25zb2xlLmxvZyhcIkdvdCB0aGUgZm9sbG93aW5nIEhUVFAgZXJyb3IgOiBcIiArIEpTT04uc3RyaW5naWZ5KHJlc3BvbnNlKSk7XG5cblx0XHRsZXQgZXJyb3IgOiBFcnJvckV2ZW50O1xuXG5cdFx0aWYgKHJlc3BvbnNlLnN0YXR1cyA9PSA0MjIpIHtcblx0XHRcdC8vLS0tIFVucHJvY2Vzc2FibGUgZW50aXR5XG5cdFx0XHRlcnJvciA9IHJlc3BvbnNlLmVycm9yO1xuXHRcdH1cblx0XHRlbHNlIHtcblx0XHRcdGVycm9yID0ge1xuXHRcdFx0XHRjb2RlIDogcmVzcG9uc2Uuc3RhdHVzLnRvU3RyaW5nKCksXG5cdFx0XHRcdGVycm9yOiByZXNwb25zZS5lcnJvci50b1N0cmluZygpXG5cdFx0XHR9O1xuXHRcdH1cblxuXHRcdHRoaXMuZXZlbnRCdXNTZXJ2aWNlLmVtaXRUb0Vycm9yKGVycm9yKTtcblxuXHRcdHJldHVybiB0aHJvd0Vycm9yKGVycm9yKTtcblx0fVxuXG5cdC8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cdHByaXZhdGUgc2hvd0xvYWRlcigpOiB2b2lkIHtcblxuXHRcdGlmICgrK3RoaXMub3BlblJlcXVlc3RzID09IDEpIHtcblx0XHRcdHRoaXMuZXZlbnRCdXNTZXJ2aWNlLmVtaXRUb0FwcChuZXcgQXBwRXZlbnQoQXBwRXZlbnQuU1VCTUlUX1NUQVJUKSk7XG5cdFx0fVxuXHR9XG5cblx0Ly8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cblx0cHJpdmF0ZSBoaWRlTG9hZGVyKCk6IHZvaWQge1xuXG5cdFx0aWYgKC0tdGhpcy5vcGVuUmVxdWVzdHMgPT0gMCkge1xuXHRcdFx0dGhpcy5ldmVudEJ1c1NlcnZpY2UuZW1pdFRvQXBwKG5ldyBBcHBFdmVudChBcHBFdmVudC5TVUJNSVRfRU5EKSk7XG5cdFx0fVxuXHR9XG59XG5cbi8vPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiIsIi8vPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vPT09XG4vLz09PSAoQykgQ29weXJpZ2h0IDIwMTggSGV3bGV0dCBQYWNrYXJkIEVudGVycHJpc2UgRGV2ZWxvcG1lbnQgTFAuXG4vLz09PVxuLy89PT0gVXNlIG9mIHRoaXMgc291cmNlIGNvZGUgaXMgZ292ZXJuZWQgYnkgYW4gTUlULXN0eWxlIGxpY2Vuc2UgdGhhdCBjYW4gYmVcbi8vPT09IGZvdW5kIGluIHRoZSBMSUNFTlNFIGZpbGVcbi8vPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuaW1wb3J0IHtJbmplY3RhYmxlfSAgZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5cbmltcG9ydCB7SHR0cFNlcnZpY2V9IGZyb20gXCIuL2h0dHAtc2VydmljZVwiO1xuXG4vLz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbkBJbmplY3RhYmxlKClcbmV4cG9ydCBjbGFzcyBMYWJlbFNlcnZpY2Uge1xuXG5cdC8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXHQvLy0tLVxuXHQvLy0tLSBWYXJpYWJsZXNcblx0Ly8tLS1cblx0Ly8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cblx0cHJpdmF0ZSBzdGF0aWMgVE9PTEtJVF9GSUxFICAgICA6IHN0cmluZyA9IFwidG9vbGtpdFwiO1xuXHRwcml2YXRlIHN0YXRpYyBBUFBMSUNBVElPTl9GSUxFIDogc3RyaW5nID0gXCJhcHBsaWNhdGlvblwiO1xuXG5cdC8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cdHByaXZhdGUgbGFiZWxTZXQgOiBNYXA8U3RyaW5nLCBNYXA8c3RyaW5nLCBhbnk+Pjtcblx0cHJpdmF0ZSBsYW5ndWFnZSA6IHN0cmluZztcblxuXHQvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuXHRwcml2YXRlIGxhbmd1YWdlcyA6IHN0cmluZ1tdID0gWyBcImVuXCIsIFwiaXRcIiBdO1xuXG5cdC8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXHQvLy0tLVxuXHQvLy0tLSBDb25zdHJ1Y3RvclxuXHQvLy0tLVxuXHQvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuXHRjb25zdHJ1Y3Rvcihwcml2YXRlIGh0dHBTZXJ2aWNlIDogSHR0cFNlcnZpY2UpIHtcblxuXHRcdHRoaXMubGFiZWxTZXQgPSBuZXcgTWFwKCk7XG5cdFx0dGhpcy5sYW5ndWFnZSA9IFwiZW5cIjtcblxuXHRcdC8vLS0tIExvYWQgbGFuZ3VhZ2UgZmlsZXNcblxuXHRcdHRoaXMubGFuZ3VhZ2VzLmZvckVhY2goIChsYW5ndWFnZSA6IHN0cmluZykgPT4ge1xuXHRcdFx0dGhpcy5pbml0TGFuZ3VhZ2UobGFuZ3VhZ2UpO1xuXHRcdH0pO1xuXHR9XG5cblx0Ly8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cdC8vLS0tXG5cdC8vLS0tIEFQSSBtZXRob2RzXG5cdC8vLS0tXG5cdC8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cdHB1YmxpYyBzZXRMYW5ndWFnZShsYW5ndWFnZSA6IHN0cmluZykgOiB2b2lkIHtcblx0XHR0aGlzLmxhbmd1YWdlID0gbGFuZ3VhZ2U7XG5cdH1cblxuXHQvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuXHRwdWJsaWMgZ2V0TGFiZWwoZW50aXR5IDogc3RyaW5nLCBjb2RlIDogc3RyaW5nKSA6IGFueSB7XG5cblx0XHRpZ