@harbor/ui
Version:
Harbor shared UI components based on Clarity and Angular6
547 lines (546 loc) • 56 kB
JavaScript
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
import { Component, ViewChild, Input, Output, EventEmitter } from "@angular/core";
import { forkJoin, timer } from "rxjs";
import { TranslateService } from "@ngx-translate/core";
import { ListReplicationRuleComponent } from "../list-replication-rule/list-replication-rule.component";
import { CreateEditRuleComponent } from "../create-edit-rule/create-edit-rule.component";
import { ErrorHandler } from "../error-handler/error-handler";
import { ReplicationService } from "../service/replication.service";
import { RequestQueryParams } from "../service/RequestQueryParams";
import { toPromise, CustomComparator, DEFAULT_PAGE_SIZE, doFiltering, doSorting, calculatePage } from "../utils";
import { ConfirmationMessage } from "../confirmation-dialog/confirmation-message";
import { ConfirmationDialogComponent } from "../confirmation-dialog/confirmation-dialog.component";
import { operateChanges, OperationState, OperateInfo } from "../operation/operate";
import { OperationService } from "../operation/operation.service";
/** @type {?} */
const ruleStatus = [
{ key: "all", description: "REPLICATION.ALL_STATUS" },
{ key: "1", description: "REPLICATION.ENABLED" },
{ key: "0", description: "REPLICATION.DISABLED" }
];
/** @type {?} */
const jobStatus = [
{ key: "all", description: "REPLICATION.ALL" },
{ key: "pending", description: "REPLICATION.PENDING" },
{ key: "running", description: "REPLICATION.RUNNING" },
{ key: "error", description: "REPLICATION.ERROR" },
{ key: "retrying", description: "REPLICATION.RETRYING" },
{ key: "stopped", description: "REPLICATION.STOPPED" },
{ key: "finished", description: "REPLICATION.FINISHED" },
{ key: "canceled", description: "REPLICATION.CANCELED" }
];
/** @type {?} */
const optionalSearch = {
0: "REPLICATION.ADVANCED",
1: "REPLICATION.SIMPLE"
};
export class SearchOption {
constructor() {
this.ruleName = "";
this.repoName = "";
this.status = "";
this.startTime = "";
this.startTimestamp = "";
this.endTime = "";
this.endTimestamp = "";
this.page = 1;
this.pageSize = DEFAULT_PAGE_SIZE;
}
}
if (false) {
/** @type {?} */
SearchOption.prototype.ruleId;
/** @type {?} */
SearchOption.prototype.ruleName;
/** @type {?} */
SearchOption.prototype.repoName;
/** @type {?} */
SearchOption.prototype.status;
/** @type {?} */
SearchOption.prototype.startTime;
/** @type {?} */
SearchOption.prototype.startTimestamp;
/** @type {?} */
SearchOption.prototype.endTime;
/** @type {?} */
SearchOption.prototype.endTimestamp;
/** @type {?} */
SearchOption.prototype.page;
/** @type {?} */
SearchOption.prototype.pageSize;
}
export class ReplicationComponent {
/**
* @param {?} errorHandler
* @param {?} replicationService
* @param {?} operationService
* @param {?} translateService
*/
constructor(errorHandler, replicationService, operationService, translateService) {
this.errorHandler = errorHandler;
this.replicationService = replicationService;
this.operationService = operationService;
this.translateService = translateService;
this.redirect = new EventEmitter();
this.openCreateRule = new EventEmitter();
this.openEdit = new EventEmitter();
this.goToRegistry = new EventEmitter();
this.search = new SearchOption();
this.ruleStatus = ruleStatus;
this.jobStatus = jobStatus;
this.hiddenJobList = true;
this.toggleJobSearchOption = optionalSearch;
this.creationTimeComparator = new CustomComparator("creation_time", "date");
this.updateTimeComparator = new CustomComparator("update_time", "date");
// Server driven pagination
this.currentPage = 1;
this.totalCount = 0;
this.pageSize = DEFAULT_PAGE_SIZE;
this.jobsLoading = false;
}
/**
* @return {?}
*/
get showPaginationIndex() {
return this.totalCount > 0;
}
/**
* @return {?}
*/
ngOnInit() {
this.currentRuleStatus = this.ruleStatus[0];
this.currentJobStatus = this.jobStatus[0];
this.currentJobSearchOption = 0;
}
/**
* @return {?}
*/
ngOnDestroy() {
if (this.timerDelay) {
this.timerDelay.unsubscribe();
}
}
/**
* @return {?}
*/
openModal() {
this.createEditPolicyComponent.openCreateEditRule();
}
/**
* @param {?} rule
* @return {?}
*/
openEditRule(rule) {
if (rule) {
this.createEditPolicyComponent.openCreateEditRule(rule.id);
}
}
/**
* @return {?}
*/
goRegistry() {
this.goToRegistry.emit();
}
/**
* @param {?} state
* @return {?}
*/
clrLoadJobs(state) {
if (!state || !state.page || !this.search.ruleId) {
return;
}
this.currentState = state;
/** @type {?} */
let pageNumber = calculatePage(state);
if (pageNumber <= 0) {
pageNumber = 1;
}
/** @type {?} */
let params = new RequestQueryParams();
// Pagination
params.set("page", "" + pageNumber);
params.set("page_size", "" + this.pageSize);
// Search by status
if (this.search.status.trim()) {
params.set("status", this.search.status);
}
// Search by repository
if (this.search.repoName.trim()) {
params.set("repository", this.search.repoName);
}
// Search by timestamps
if (this.search.startTimestamp.trim()) {
params.set("start_time", this.search.startTimestamp);
}
if (this.search.endTimestamp.trim()) {
params.set("end_time", this.search.endTimestamp);
}
this.jobsLoading = true;
// Do filtering and sorting
this.jobs = doFiltering(this.jobs, state);
this.jobs = doSorting(this.jobs, state);
this.jobsLoading = false;
toPromise(this.replicationService.getJobs(this.search.ruleId, params))
.then(response => {
this.totalCount = response.metadata.xTotalCount;
this.jobs = response.data;
if (!this.timerDelay) {
this.timerDelay = timer(10000, 10000).subscribe(() => {
/** @type {?} */
let count = 0;
this.jobs.forEach(job => {
if (job.status === "pending" ||
job.status === "running" ||
job.status === "retrying") {
count++;
}
});
if (count > 0) {
this.clrLoadJobs(this.currentState);
}
else {
this.timerDelay.unsubscribe();
this.timerDelay = null;
}
});
}
// Do filtering and sorting
this.jobs = doFiltering(this.jobs, state);
this.jobs = doSorting(this.jobs, state);
this.jobsLoading = false;
})
.catch(error => {
this.jobsLoading = false;
this.errorHandler.error(error);
});
}
/**
* @return {?}
*/
loadFirstPage() {
/** @type {?} */
let st = this.currentState;
if (!st) {
st = {
page: {}
};
}
st.page.size = this.pageSize;
st.page.from = 0;
st.page.to = this.pageSize - 1;
this.clrLoadJobs(st);
}
/**
* @param {?} rule
* @return {?}
*/
selectOneRule(rule) {
if (rule && rule.id) {
this.hiddenJobList = false;
this.search.ruleId = rule.id || "";
this.search.repoName = "";
this.search.status = "";
this.currentJobSearchOption = 0;
this.currentJobStatus = { key: "all", description: "REPLICATION.ALL" };
this.loadFirstPage();
}
}
/**
* @param {?} rule
* @return {?}
*/
replicateManualRule(rule) {
if (rule) {
/** @type {?} */
let replicationMessage = new ConfirmationMessage("REPLICATION.REPLICATION_TITLE", "REPLICATION.REPLICATION_SUMMARY", rule.name, rule, 6 /* TARGET */, 4 /* REPLICATE_CANCEL */);
this.replicationConfirmDialog.open(replicationMessage);
}
}
/**
* @param {?} message
* @return {?}
*/
confirmReplication(message) {
if (message &&
message.source === 6 /* TARGET */ &&
message.state === 1 /* CONFIRMED */) {
/** @type {?} */
let rule = message.data;
if (rule) {
Promise.all([this.replicationOperate(rule)]).then((item) => {
this.selectOneRule(rule);
});
}
}
}
/**
* @param {?} rule
* @return {?}
*/
replicationOperate(rule) {
/** @type {?} */
let operMessage = new OperateInfo();
operMessage.name = 'OPERATION.REPLICATION';
operMessage.data["id"] = rule.id;
operMessage.state = OperationState.progressing;
operMessage.data["name"] = rule.name;
this.operationService.publishInfo(operMessage);
return toPromise(this.replicationService.replicateRule(+rule.id))
.then(response => {
this.translateService.get('BATCH.REPLICATE_SUCCESS')
.subscribe(res => operateChanges(operMessage, OperationState.success));
})
.catch(error => {
if (error && error.status === 412) {
forkJoin(this.translateService.get('BATCH.REPLICATE_FAILURE'), this.translateService.get('REPLICATION.REPLICATE_SUMMARY_FAILURE'))
.subscribe(function (res) {
operateChanges(operMessage, OperationState.failure, res[1]);
});
}
else {
this.translateService.get('BATCH.REPLICATE_FAILURE').subscribe(res => {
operateChanges(operMessage, OperationState.failure, res);
});
}
});
}
/**
* @param {?} rule
* @return {?}
*/
customRedirect(rule) {
this.redirect.emit(rule);
}
/**
* @param {?} ruleName
* @return {?}
*/
doSearchRules(ruleName) {
this.search.ruleName = ruleName;
this.listReplicationRule.retrieveRules(ruleName);
}
/**
* @param {?} $event
* @return {?}
*/
doFilterJobStatus($event) {
if ($event && $event.target && $event.target["value"]) {
/** @type {?} */
let status = $event.target["value"];
this.currentJobStatus = this.jobStatus["find"]((r) => r.key === status);
if (this.currentJobStatus.key === "all") {
status = "";
}
this.search.status = status;
this.doSearchJobs(this.search.repoName);
}
}
/**
* @param {?} repoName
* @return {?}
*/
doSearchJobs(repoName) {
this.search.repoName = repoName;
this.loadFirstPage();
}
/**
* @return {?}
*/
hideJobs() {
this.search.ruleId = 0;
this.jobs = [];
this.hiddenJobList = true;
}
/**
* @return {?}
*/
stopJobs() {
if (this.jobs && this.jobs.length) {
this.isStopOnGoing = true;
toPromise(this.replicationService.stopJobs(this.jobs[0].policy_id))
.then(res => {
this.refreshJobs();
this.isStopOnGoing = false;
})
.catch(error => this.errorHandler.error(error));
}
}
/**
* @param {?} isReady
* @return {?}
*/
reloadRules(isReady) {
if (isReady) {
this.search.ruleName = "";
this.listReplicationRule.retrieveRules(this.search.ruleName);
}
}
/**
* @return {?}
*/
refreshRules() {
this.listReplicationRule.retrieveRules();
}
/**
* @return {?}
*/
refreshJobs() {
this.currentJobStatus = this.jobStatus[0];
this.search.startTime = " ";
this.search.endTime = " ";
this.search.repoName = "";
this.search.startTimestamp = "";
this.search.endTimestamp = "";
this.search.status = "";
this.currentPage = 1;
/** @type {?} */
let st = {
page: {
from: 0,
to: this.pageSize - 1,
size: this.pageSize
}
};
this.clrLoadJobs(st);
}
/**
* @param {?} option
* @return {?}
*/
toggleSearchJobOptionalName(option) {
option === 1
? (this.currentJobSearchOption = 0)
: (this.currentJobSearchOption = 1);
}
/**
* @param {?} fromTimestamp
* @return {?}
*/
doJobSearchByStartTime(fromTimestamp) {
this.search.startTimestamp = fromTimestamp;
this.loadFirstPage();
}
/**
* @param {?} toTimestamp
* @return {?}
*/
doJobSearchByEndTime(toTimestamp) {
this.search.endTimestamp = toTimestamp;
this.loadFirstPage();
}
/**
* @param {?} jobId
* @return {?}
*/
viewLog(jobId) {
return this.replicationService.getJobBaseUrl() + "/" + jobId + "/log";
}
}
ReplicationComponent.decorators = [
{ type: Component, args: [{
selector: "hbr-replication",
template: "<div class=\"row\" style=\"position:relative;\">\n <div>\n <div class=\"row flex-items-xs-between rightPos\">\n <div class=\"flex-xs-middle option-right\">\n <hbr-filter [withDivider]=\"true\" filterPlaceholder='{{\"REPLICATION.FILTER_POLICIES_PLACEHOLDER\" | translate}}' (filterEvt)=\"doSearchRules($event)\"\n [currentValue]=\"search.ruleName\"></hbr-filter>\n <span class=\"refresh-btn\" (click)=\"refreshRules()\">\n <clr-icon shape=\"refresh\"></clr-icon>\n </span>\n </div>\n </div>\n </div>\n <div class=\"col-lg-12 col-md-12 col-sm-12 col-xs-12\">\n <hbr-list-replication-rule #listReplicationRule [projectId]=\"projectId\" [isSystemAdmin]=\"isSystemAdmin\" (replicateManual)=replicateManualRule($event)\n (selectOne)=\"selectOneRule($event)\" (hideJobs)=\"hideJobs()\" (openNewRule)=\"openModal()\" (editOne)=\"openEditRule($event)\"\n (reload)=\"reloadRules($event)\" [loading]=\"loading\" [withReplicationJob]=\"withReplicationJob\" (redirect)=\"customRedirect($event)\"></hbr-list-replication-rule>\n </div>\n <div class=\"col-lg-12 col-md-12 col-sm-12 col-xs-12\" style=\"padding-left:0px;\" [hidden]='hiddenJobList'>\n <div *ngIf=\"withReplicationJob\" class=\"col-lg-12 col-md-12 col-sm-12 col-xs-12\">\n <div class=\"row flex-items-xs-between\" style=\"height:60px;\">\n <h5 class=\"flex-items-xs-bottom option-left-down\" style=\"margin-left: 14px;\">{{'REPLICATION.REPLICATION_JOBS' | translate}}</h5>\n <div class=\"flex-items-xs-bottom option-right-down\">\n <button class=\"btn btn-link\" (click)=\"toggleSearchJobOptionalName(currentJobSearchOption)\">{{toggleJobSearchOption[currentJobSearchOption] | translate}}</button>\n <hbr-filter [withDivider]=\"true\" filterPlaceholder='{{\"REPLICATION.FILTER_JOBS_PLACEHOLDER\" | translate}}' (filterEvt)=\"doSearchJobs($event)\"\n [currentValue]=\"search.repoName\"></hbr-filter>\n <span class=\"refresh-btn\" (click)=\"refreshJobs()\">\n <clr-icon shape=\"refresh\"></clr-icon>\n </span>\n </div>\n </div>\n <div class=\"row flex-items-xs-right row-right\" [hidden]=\"currentJobSearchOption === 0\">\n <div class=\"select select-status\">\n <select (change)=\"doFilterJobStatus($event)\">\n <option *ngFor=\"let j of jobStatus\" value=\"{{j.key}}\" [selected]=\"currentJobStatus.key === j.key\">{{j.description | translate}}</option>\n </select>\n </div>\n <div class=\"flex-items-xs-middle\">\n <hbr-datetime [dateInput]=\"search.startTime\" (search)=\"doJobSearchByStartTime($event)\"></hbr-datetime>\n <hbr-datetime [dateInput]=\"search.endTime\" [oneDayOffset]=\"true\" (search)=\"doJobSearchByEndTime($event)\"></hbr-datetime>\n </div>\n </div>\n </div>\n <div *ngIf=\"withReplicationJob\" class=\"col-lg-12 col-md-12 col-sm-12 col-xs-12\">\n <clr-datagrid [clrDgLoading]=\"jobsLoading\" (clrDgRefresh)=\"clrLoadJobs($event)\">\n <clr-dg-action-bar>\n <div class=\"btn-group\">\n <button type=\"button\" class=\"btn btn-sm btn-secondary\" *ngIf=\"isSystemAdmin\" [disabled]=\"!(jobs && jobs.length>0) || isStopOnGoing\"\n (click)=\"stopJobs()\">{{'REPLICATION.STOPJOB' | translate}}</button>\n </div>\n </clr-dg-action-bar>\n <clr-dg-column [clrDgField]=\"'repository'\">{{'REPLICATION.NAME' | translate}}</clr-dg-column>\n <clr-dg-column [clrDgField]=\"'status'\">{{'REPLICATION.STATUS' | translate}}</clr-dg-column>\n <clr-dg-column [clrDgField]=\"'operation'\">{{'REPLICATION.OPERATION' | translate}}</clr-dg-column>\n <clr-dg-column [clrDgSortBy]=\"creationTimeComparator\">{{'REPLICATION.CREATION_TIME' | translate}}</clr-dg-column>\n <clr-dg-column [clrDgSortBy]=\"updateTimeComparator\">{{'REPLICATION.UPDATE_TIME' | translate}}</clr-dg-column>\n <clr-dg-column>{{'REPLICATION.LOGS' | translate}}</clr-dg-column>\n <clr-dg-placeholder>{{'REPLICATION.JOB_PLACEHOLDER' | translate }}</clr-dg-placeholder>\n <clr-dg-row *ngFor=\"let j of jobs\">\n <clr-dg-cell>{{j.repository}}</clr-dg-cell>\n <clr-dg-cell>{{j.status}}</clr-dg-cell>\n <clr-dg-cell>{{j.operation}}</clr-dg-cell>\n <clr-dg-cell>{{j.creation_time | date: 'short'}}</clr-dg-cell>\n <clr-dg-cell>{{j.update_time | date: 'short'}}</clr-dg-cell>\n <clr-dg-cell>\n <span *ngIf=\"j.status=='pending'; else elseBlock\" class=\"label\">{{'REPLICATION.NO_LOGS' | translate}}</span>\n <ng-template #elseBlock>\n <a target=\"_blank\" [href]=\"viewLog(j.id)\">\n <clr-icon shape=\"list\"></clr-icon>\n </a>\n </ng-template>\n </clr-dg-cell>\n </clr-dg-row>\n <clr-dg-footer>\n <span *ngIf=\"showPaginationIndex\">{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'REPLICATION.OF' | translate}}</span>\n {{pagination.totalItems}} {{'REPLICATION.ITEMS' | translate}}\n <clr-dg-pagination #pagination [(clrDgPage)]=\"currentPage\" [clrDgPageSize]=\"pageSize\" [clrDgTotalItems]=\"totalCount\"></clr-dg-pagination>\n </clr-dg-footer>\n </clr-datagrid>\n </div>\n </div>\n <hbr-create-edit-rule *ngIf=\"isSystemAdmin\" [withAdmiral]=\"withAdmiral\" [projectId]=\"projectId\" [projectName]=\"projectName\"\n (goToRegistry)=\"goRegistry()\" (reload)=\"reloadRules($event)\"></hbr-create-edit-rule>\n <confirmation-dialog #replicationConfirmDialog (confirmAction)=\"confirmReplication($event)\"></confirmation-dialog>\n</div>",
styles: [".refresh-btn{cursor:pointer}.refresh-btn:hover{color:#007cbb}.option-left{padding-left:16px}.option-right{padding-right:16px}.option-left-down{margin-top:36px}.option-right-down{padding-right:16px;margin-top:24px}.rightPos{position:absolute;right:35px;margin-top:5px;z-index:100;height:32px}.select-status{float:left;margin-top:6px;margin-right:5px}.row-right{padding-right:50px}"]
}] }
];
/** @nocollapse */
ReplicationComponent.ctorParameters = () => [
{ type: ErrorHandler },
{ type: ReplicationService },
{ type: OperationService },
{ type: TranslateService }
];
ReplicationComponent.propDecorators = {
projectId: [{ type: Input }],
projectName: [{ type: Input }],
isSystemAdmin: [{ type: Input }],
withAdmiral: [{ type: Input }],
withReplicationJob: [{ type: Input }],
redirect: [{ type: Output }],
openCreateRule: [{ type: Output }],
openEdit: [{ type: Output }],
goToRegistry: [{ type: Output }],
listReplicationRule: [{ type: ViewChild, args: [ListReplicationRuleComponent,] }],
createEditPolicyComponent: [{ type: ViewChild, args: [CreateEditRuleComponent,] }],
replicationConfirmDialog: [{ type: ViewChild, args: ["replicationConfirmDialog",] }]
};
if (false) {
/** @type {?} */
ReplicationComponent.prototype.projectId;
/** @type {?} */
ReplicationComponent.prototype.projectName;
/** @type {?} */
ReplicationComponent.prototype.isSystemAdmin;
/** @type {?} */
ReplicationComponent.prototype.withAdmiral;
/** @type {?} */
ReplicationComponent.prototype.withReplicationJob;
/** @type {?} */
ReplicationComponent.prototype.redirect;
/** @type {?} */
ReplicationComponent.prototype.openCreateRule;
/** @type {?} */
ReplicationComponent.prototype.openEdit;
/** @type {?} */
ReplicationComponent.prototype.goToRegistry;
/** @type {?} */
ReplicationComponent.prototype.search;
/** @type {?} */
ReplicationComponent.prototype.ruleStatus;
/** @type {?} */
ReplicationComponent.prototype.currentRuleStatus;
/** @type {?} */
ReplicationComponent.prototype.jobStatus;
/** @type {?} */
ReplicationComponent.prototype.currentJobStatus;
/** @type {?} */
ReplicationComponent.prototype.changedRules;
/** @type {?} */
ReplicationComponent.prototype.rules;
/** @type {?} */
ReplicationComponent.prototype.loading;
/** @type {?} */
ReplicationComponent.prototype.isStopOnGoing;
/** @type {?} */
ReplicationComponent.prototype.hiddenJobList;
/** @type {?} */
ReplicationComponent.prototype.jobs;
/** @type {?} */
ReplicationComponent.prototype.toggleJobSearchOption;
/** @type {?} */
ReplicationComponent.prototype.currentJobSearchOption;
/** @type {?} */
ReplicationComponent.prototype.listReplicationRule;
/** @type {?} */
ReplicationComponent.prototype.createEditPolicyComponent;
/** @type {?} */
ReplicationComponent.prototype.replicationConfirmDialog;
/** @type {?} */
ReplicationComponent.prototype.creationTimeComparator;
/** @type {?} */
ReplicationComponent.prototype.updateTimeComparator;
/** @type {?} */
ReplicationComponent.prototype.currentPage;
/** @type {?} */
ReplicationComponent.prototype.totalCount;
/** @type {?} */
ReplicationComponent.prototype.pageSize;
/** @type {?} */
ReplicationComponent.prototype.currentState;
/** @type {?} */
ReplicationComponent.prototype.jobsLoading;
/** @type {?} */
ReplicationComponent.prototype.timerDelay;
/** @type {?} */
ReplicationComponent.prototype.errorHandler;
/** @type {?} */
ReplicationComponent.prototype.replicationService;
/** @type {?} */
ReplicationComponent.prototype.operationService;
/** @type {?} */
ReplicationComponent.prototype.translateService;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVwbGljYXRpb24uY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6Im5nOi8vQGhhcmJvci91aS8iLCJzb3VyY2VzIjpbInNyYy9yZXBsaWNhdGlvbi9yZXBsaWNhdGlvbi5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7OztBQWFBLE9BQU8sRUFDTCxTQUFTLEVBRVQsU0FBUyxFQUNULEtBQUssRUFDTCxNQUFNLEVBRU4sWUFBWSxFQUNiLE1BQU0sZUFBZSxDQUFDO0FBRXZCLE9BQU8sRUFBZ0IsUUFBUSxFQUFFLEtBQUssRUFBQyxNQUFNLE1BQU0sQ0FBQztBQUdwRCxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUV2RCxPQUFPLEVBQUUsNEJBQTRCLEVBQUUsTUFBTSwwREFBMEQsQ0FBQztBQUN4RyxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSxnREFBZ0QsQ0FBQztBQUN6RixPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUFFOUQsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUFDcEUsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFPbkUsT0FBTyxFQUNMLFNBQVMsRUFDVCxnQkFBZ0IsRUFDaEIsaUJBQWlCLEVBQ2pCLFdBQVcsRUFDWCxTQUFTLEVBQ1QsYUFBYSxFQUNkLE1BQU0sVUFBVSxDQUFDO0FBT2xCLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLDZDQUE2QyxDQUFDO0FBQ2xGLE9BQU8sRUFBRSwyQkFBMkIsRUFBRSxNQUFNLHNEQUFzRCxDQUFDO0FBRW5HLE9BQU8sRUFBQyxjQUFjLEVBQUUsY0FBYyxFQUFFLFdBQVcsRUFBQyxNQUFNLHNCQUFzQixDQUFDO0FBQ2pGLE9BQU8sRUFBQyxnQkFBZ0IsRUFBQyxNQUFNLGdDQUFnQyxDQUFDOztBQUVoRSxNQUFNLFVBQVUsR0FBMkI7SUFDekMsRUFBRSxHQUFHLEVBQUUs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QW1CO1FBQ3RDLElBQUksQ0FBQyxNQUFNLENBQUMsWUFBWSxHQUFHLFdBQVcsQ0FBQztRQUN2QyxJQUFJLENBQUMsYUFBYSxFQUFFLENBQUM7S0FDdEI7Ozs7O0lBRUQsT0FBTyxDQUFDLEtBQXNCO1FBQzVCLE9BQU8sSUFBSSxDQUFDLGtCQUFrQixDQUFDLGFBQWEsRUFBRSxHQUFHLEdBQUcsR0FBRyxLQUFLLEdBQUcsTUFBTSxDQUFDO0tBQ3ZFOzs7WUF2V0YsU0FBUyxTQUFDO2dCQUNULFFBQVEsRUFBRSxpQkFBaUI7Z0JBQzNCLDhtTEFBMkM7O2FBRTVDOzs7O1lBckVRLFlBQVk7WUFFWixrQkFBa0I7WUEwQm5CLGdCQUFnQjtZQWhDZixnQkFBZ0I7Ozt3QkEyRXRCLEtBQUs7MEJBQ0wsS0FBSzs0QkFDTCxLQUFLOzBCQUNMLEtBQUs7aUNBQ0wsS0FBSzt1QkFFTCxNQUFNOzZCQUNOLE1BQU07dUJBQ04sTUFBTTsyQkFDTixNQUFNO2tDQXNCTixTQUFTLFNBQUMsNEJBQTRCO3dDQUd0QyxTQUFTLFNBQUMsdUJBQXVCO3VDQUlqQyxTQUFTLFNBQUMsMEJBQTBCIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IChjKSAyMDE3IFZNd2FyZSwgSW5jLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuLy9cbi8vIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIik7XG4vLyB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuXG4vLyBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXRcbi8vXG4vLyAgICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjBcbi8vXG4vLyBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlXG4vLyBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiBcIkFTIElTXCIgQkFTSVMsXG4vLyBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC5cbi8vIFNlZSB0aGUgTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmRcbi8vIGxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLlxuaW1wb3J0IHtcbiAgQ29tcG9uZW50LFxuICBPbkluaXQsXG4gIFZpZXdDaGlsZCxcbiAgSW5wdXQsXG4gIE91dHB1dCxcbiAgT25EZXN0cm95LFxuICBFdmVudEVtaXR0ZXJcbn0gZnJvbSBcIkBhbmd1bGFyL2NvcmVcIjtcbmltcG9ydCB7IENvbXBhcmF0b3IsIFN0YXRlIH0gZnJvbSBcIkBjbHIvYW5ndWxhclwiO1xuaW1wb3J0IHsgU3Vic2NyaXB0aW9uLCBmb3JrSm9pbiwgdGltZXJ9IGZyb20gXCJyeGpzXCI7XG5cblxuaW1wb3J0IHsgVHJhbnNsYXRlU2VydmljZSB9IGZyb20gXCJAbmd4LXRyYW5zbGF0ZS9jb3JlXCI7XG5cbmltcG9ydCB7IExpc3RSZXBsaWNhdGlvblJ1bGVDb21wb25lbnQgfSBmcm9tIFwiLi4vbGlzdC1yZXBsaWNhdGlvbi1ydWxlL2xpc3QtcmVwbGljYXRpb24tcnVsZS5jb21wb25lbnRcIjtcbmltcG9ydCB7IENyZWF0ZUVkaXRSdWxlQ29tcG9uZW50IH0gZnJvbSBcIi4uL2NyZWF0ZS1lZGl0LXJ1bGUvY3JlYXRlLWVkaXQtcnVsZS5jb21wb25lbnRcIjtcbmltcG9ydCB7IEVycm9ySGFuZGxlciB9IGZyb20gXCIuLi9lcnJvci1oYW5kbGVyL2Vycm9yLWhhbmRsZXJcIjtcblxuaW1wb3J0IHsgUmVwbGljYXRpb25TZXJ2aWNlIH0gZnJvbSBcIi4uL3NlcnZpY2UvcmVwbGljYXRpb24uc2VydmljZVwiO1xuaW1wb3J0IHsgUmVxdWVzdFF1ZXJ5UGFyYW1zIH0gZnJvbSBcIi4uL3NlcnZpY2UvUmVxdWVzdFF1ZXJ5UGFyYW1zXCI7XG5pbXBvcnQge1xuICBSZXBsaWNhdGlvblJ1bGUsXG4gIFJlcGxpY2F0aW9uSm9iLFxuICBSZXBsaWNhdGlvbkpvYkl0ZW1cbn0gZnJvbSBcIi4uL3NlcnZpY2UvaW50ZXJmYWNlXCI7XG5cbmltcG9ydCB7XG4gIHRvUHJvbWlzZSxcbiAgQ3VzdG9tQ29tcGFyYXRvcixcbiAgREVGQVVMVF9QQUdFX1NJWkUsXG4gIGRvRmlsdGVyaW5nLFxuICBkb1NvcnRpbmcsXG4gIGNhbGN1bGF0ZVBhZ2Vcbn0gZnJvbSBcIi4uL3V0aWxzXCI7XG5cbmltcG9ydCB7XG4gIENvbmZpcm1hdGlvblRhcmdldHMsXG4gIENvbmZpcm1hdGlvbkJ1dHRvbnMsXG4gIENvbmZpcm1hdGlvblN0YXRlXG59IGZyb20gXCIuLi9zaGFyZWQvc2hhcmVkLmNvbnN0XCI7XG5pbXBvcnQgeyBDb25maXJtYXRpb25NZXNzYWdlIH0gZnJvbSBcIi4uL2NvbmZpcm1hdGlvbi1kaWFsb2cvY29uZmlybWF0aW9uLW1lc3NhZ2VcIjtcbmltcG9ydCB7IENvbmZpcm1hdGlvbkRpYWxvZ0NvbXBvbmVudCB9IGZyb20gXCIuLi9jb25maXJtYXRpb24tZGlhbG9nL2NvbmZpcm1hdGlvbi1kaWFsb2cuY29tcG9uZW50XCI7XG5pbXBvcnQgeyBDb25maXJtYXRpb25BY2tub3dsZWRnZW1lbnQgfSBmcm9tIFwiLi4vY29uZmlybWF0aW9uLWRpYWxvZy9jb25maXJtYXRpb24tc3RhdGUtbWVzc2FnZVwiO1xuaW1wb3J0IHtvcGVyYXRlQ2hhbmdlcywgT3BlcmF0aW9uU3RhdGUsIE9wZXJhdGVJbmZvfSBmcm9tIFwiLi4vb3BlcmF0aW9uL29wZXJhdGVcIjtcbmltcG9ydCB7T3BlcmF0aW9uU2VydmljZX0gZnJvbSBcIi4uL29wZXJhdGlvbi9vcGVyYXRpb24uc2VydmljZVwiO1xuXG5jb25zdCBydWxlU3RhdHVzOiB7IFtrZXk6IHN0cmluZ106IGFueSB9ID0gW1xuICB7IGtleTogXCJhbGxcIiwgZGVzY3JpcHRpb246IFwiUkVQTElDQVRJT04uQUxMX1NUQVRVU1wiIH0sXG4gIHsga2V5OiBcIjFcIiwgZGVzY3JpcHRpb246IFwiUkVQTElDQVRJT04uRU5BQkxFRFwiIH0sXG4gIHsga2V5OiBcIjBcIiwgZGVzY3JpcHRpb246IFwiUkVQTElDQVRJT04uRElTQUJMRURcIiB9XG5dO1xuXG5jb25zdCBqb2JTdGF0dXM6IHsgW2tleTogc3RyaW5nXTogYW55IH0gPSBbXG4gIHsga2V5OiBcImFsbFwiLCBkZXNjcmlwdGlvbjogXCJSRVBMSUNBVElPTi5BTExcIiB9LFxuICB7IGtleTogXCJwZW5kaW5nXCIsIGRlc2NyaXB0aW9uOiBcIlJFUExJQ0FUSU9OLlBFTkRJTkdcIiB9LFxuICB7IGtleTogXCJydW5uaW5nXCIsIGRlc2NyaXB0aW9uOiBcIlJFUExJQ0FUSU9OLlJVTk5JTkdcIiB9LFxuICB7IGtleTogXCJlcnJvclwiLCBkZXNjcmlwdGlvbjogXCJSRVBMSUNBVElPTi5FUlJPUlwiIH0sXG4gIHsga2V5OiBcInJldHJ5aW5nXCIsIGRlc2NyaXB0aW9uOiBcIlJFUExJQ0FUSU9OLlJFVFJZSU5HXCIgfSxcbiAgeyBrZXk6IFwic3RvcHBlZFwiLCBkZXNjcmlwdGlvbjogXCJSRVBMSUNBVElPTi5TVE9QUEVEXCIgfSxcbiAgeyBrZXk6IFwiZmluaXNoZWRcIiwgZGVzY3JpcHRpb246IFwiUkVQTElDQVRJT04uRklOSVNIRURcIiB9LFxuICB7IGtleTogXCJjYW5jZWxlZFwiLCBkZXNjcmlwdGlvbjogXCJSRVBMSUNBVElPTi5DQU5DRUxFRFwiIH1cbl07XG5cbmNvbnN0IG9wdGlvbmFsU2VhcmNoOiB7fSA9IHtcbiAgMDogXCJSRVBMSUNBVElPTi5BRFZBTkNFRFwiLFxuICAxOiBcIlJFUExJQ0FUSU9OLlNJTVBMRVwiXG59O1xuXG5leHBvcnQgY2xhc3MgU2VhcmNoT3B0aW9uIHtcbiAgcnVsZUlkOiBudW1iZXIgfCBzdHJpbmc7XG4gIHJ1bGVOYW1lOiBzdHJpbmcgPSBcIlwiO1xuICByZXBvTmFtZTogc3RyaW5nID0gXCJcIjtcbiAgc3RhdHVzOiBzdHJpbmcgPSBcIlwiO1xuICBzdGFydFRpbWU6IHN0cmluZyA9IFwiXCI7XG4gIHN0YXJ0VGltZXN0YW1wOiBzdHJpbmcgPSBcIlwiO1xuICBlbmRUaW1lOiBzdHJpbmcgPSBcIlwiO1xuICBlbmRUaW1lc3RhbXA6IHN0cmluZyA9IFwiXCI7XG4gIHBhZ2U6IG51bWJlciA9IDE7XG4gIHBhZ2VTaXplOiBudW1iZXIgPSBERUZBVUxUX1BBR0VfU0laRTtcbn1cblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiBcImhici1yZXBsaWNhdGlvblwiLFxuICB0ZW1wbGF0ZVVybDogXCIuL3JlcGxpY2F0aW9uLmNvbXBvbmVudC5odG1sXCIsXG4gIHN0eWxlVXJsczogW1wiLi9yZXBsaWNhdGlvbi5jb21wb25lbnQuc2Nzc1wiXVxufSlcbmV4cG9ydCBjbGFzcyBSZXBsaWNhdGlvbkNvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCwgT25EZXN0cm95IHtcbiAgQElucHV0KCkgcHJvamVjdElkOiBudW1iZXIgfCBzdHJpbmc7XG4gIEBJbnB1dCgpIHByb2plY3ROYW1lOiBzdHJpbmc7XG4gIEBJbnB1dCgpIGlzU3lzdGVtQWRtaW46IGJvb2xlYW47XG4gIEBJbnB1dCgpIHdpdGhBZG1pcmFsOiBib29sZWFuO1xuICBASW5wdXQoKSB3aXRoUmVwbGljYXRpb25Kb2I6IGJvb2xlYW47XG5cbiAgQE91dHB1dCgpIHJlZGlyZWN0ID0gbmV3IEV2ZW50RW1pdHRlcjxSZXBsaWNhdGlvblJ1bGU+KCk7XG4gIEBPdXRwdXQoKSBvcGVuQ3JlYXRlUnVsZSA9IG5ldyBFdmVudEVtaXR0ZXI8YW55PigpO1xuICBAT3V0cHV0KCkgb3BlbkVkaXQgPSBuZXcgRXZlbnRFbWl0dGVyPHN0cmluZyB8IG51bWJlcj4oKTtcbiAgQE91dHB1dCgpIGdvVG9SZWdpc3RyeSA9IG5ldyBFdmVudEVtaXR0ZXI8YW55PigpO1xuXG4gIHNlYXJjaDogU2VhcmNoT3B0aW9uID0gbmV3IFNlYXJjaE9wdGlvbigpO1xuXG4gIHJ1bGVTdGF0dXMgPSBydWxlU3RhdHVzO1xuICBjdXJyZW50UnVsZVN0YXR1czogeyBrZXk6IHN0cmluZzsgZGVzY3JpcHRpb246IHN0cmluZyB9O1xuXG4gIGpvYlN0YXR1cyA9IGpvYlN0YXR1cztcbiAgY3VycmVudEpvYlN0YXR1czogeyBrZXk6IHN0cmluZzsgZGVzY3JpcHRpb246IHN0cmluZyB9O1xuXG4gIGNoYW5nZWRSdWxlczogUmVwbGljYXRpb25SdWxlW107XG5cbiAgcnVsZXM6IFJlcGxpY2F0aW9uUnVsZVtdO1xuICBsb2FkaW5nOiBib29sZWFuO1xuICBpc1N0b3BPbkdvaW5nOiBib29sZWFuO1xuICBoaWRkZW5Kb2JMaXN0ID0gdHJ1ZTtcblxuICBqb2JzOiBSZXBsaWNhdGlvbkpvYkl0ZW1bXTtcblxuICB0b2dnbGVKb2JTZWFyY2hPcHRpb24gPSBvcHRpb25hbFNlYXJjaDtcbiAgY3VycmVudEpvYlNlYXJjaE9wdGlvbjogbnVtYmVyO1xuXG4gIEBWaWV3Q2hpbGQoTGlzdFJlcGxpY2F0aW9uUnVsZUNvbXBvbmVudClcbiAgbGlzdFJlcGxpY2F0aW9uUnVsZTogTGlzdFJlcGxpY2F0aW9uUnVsZUNvbXBvbmVudDtcblxuICBAVmlld0NoaWxkKENyZWF0ZUVkaXRSdWxlQ29tcG9uZW50KVxuICBjcmVhdGVFZGl0UG9saWN5Q29tcG9uZW50OiBDcmVhdGVFZGl0UnVsZUNvbXBvbmVudDtcblxuXG4gIEBWaWV3Q2hpbGQoXCJyZXBsaWNhdGlvbkNvbmZpcm1EaWFsb2dcIilcbiAgcmVwbGljYXRpb25Db25maXJtRGlhbG9nOiBDb25maXJtYXRpb25EaWFsb2dDb21wb25lbnQ7XG5cbiAgY3JlYXRpb25UaW1lQ29tcGFyYXRvcjogQ29tcGFyYXRvcjxSZXBsaWNhdGlvbkpvYj4gPSBuZXcgQ3VzdG9tQ29tcGFyYXRvcjxcbiAgICBSZXBsaWNhdGlvbkpvYlxuICA+KFwiY3JlYXRpb25fdGltZVwiLCBcImRhdGVcIik7XG4gIHVwZGF0ZVRpbWVDb21wYXJhdG9yOiBDb21wYXJhdG9yPFJlcGxpY2F0aW9uSm9iPiA9IG5ldyBDdXN0b21Db21wYXJhdG9yPFxuICAgIFJlcGxpY2F0aW9uSm9iXG4gID4oXCJ1cGRhdGVfdGltZVwiLCBcImRhdGVcIik7XG5cbiAgLy8gU2VydmVyIGRyaXZlbiBwYWdpbmF0aW9uXG4gIGN1cnJlbnRQYWdlOiBudW1iZXIgPSAxO1xuICB0b3RhbENvdW50OiBudW1iZXIgPSAwO1xuICBwYWdlU2l6ZTogbnVtYmVyID0gREVGQVVMVF9QQUdFX1NJWkU7XG4gIGN1cnJlbnRTdGF0ZTogU3RhdGU7XG4gIGpvYnNMb2FkaW5nOiBib29sZWFuID0gZmFsc2U7XG4gIHRpbWVyRGVsYXk6IFN1YnNjcmlwdGlvbjtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIGVycm9ySGFuZGxlcjogRXJyb3JIYW5kbGVyLFxuICAgIHByaXZhdGUgcmVwbGljYXRpb25TZXJ2aWNlOiBSZXBsaWNhdGlvblNlcnZpY2UsXG4gICAgcHJpdmF0ZSBvcGVyYXRpb25TZXJ2aWNlOiBPcGVyYXRpb25TZXJ2aWNlLFxuICAgIHByaXZhdGUgdHJhbnNsYXRlU2VydmljZTogVHJhbnNsYXRlU2VydmljZSkge31cblxuICBwdWJsaWMgZ2V0IHNob3dQYWdpbmF0aW9uSW5kZXgoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMudG90YWxDb3VudCA+IDA7XG4gIH1cblxuICBuZ09uSW5pdCgpIHtcbiAgICB0aGlzLmN1cnJlbnRSdWxlU3RhdHVzID0gdGhpcy5ydWxlU3RhdHVzWzBdO1xuICAgIHRoaXMuY3VycmVudEpvYlN0YXR1cyA9IHRoaXMuam9iU3RhdHVzWzBdO1xuICAgIHRoaXMuY3VycmVudEpvYlNlYXJjaE9wdGlvbiA9IDA7XG4gIH1cblxuICBuZ09uRGVzdHJveSgpIHtcbiAgICBpZiAodGhpcy50aW1lckRlbGF5KSB7XG4gICAgICB0aGlzLnRpbWVyRGVsYXkudW5zdWJzY3JpYmUoKTtcbiAgICB9XG4gIH1cblxuICAvLyBvcGVuIHJlcGxpY2F0aW9uIHJ1bGVcbiAgb3Blbk1vZGFsKCk6IHZvaWQge1xuICAgIHRoaXMuY3JlYXRlRWRpdFBvbGljeUNvbXBvbmVudC5vcGVuQ3JlYXRlRWRpdFJ1bGUoKTtcbiAgfVxuXG4gIC8vIGVkaXQgcmVwbGljYXRpb24gcnVsZVxuICBvcGVuRWRpdFJ1bGUocnVsZTogUmVwbGljYXRpb25SdWxlKSB7XG4gICAgaWYgKHJ1bGUpIHtcbiAgICAgIHRoaXMuY3JlYXRlRWRpdFBvbGljeUNvbXBvbmVudC5vcGVuQ3JlYXRlRWRpdFJ1bGUocnVsZS5pZCk7XG4gICAgfVxuICB9XG5cbiAgZ29SZWdpc3RyeSgpOiB2b2lkIHtcbiAgICB0aGlzLmdvVG9SZWdpc3RyeS5lbWl0KCk7XG4gIH1cblxuICAvLyBTZXJ2ZXIgZHJpdmVuIGRhdGEgbG9hZGluZ1xuICBjbHJMb2FkSm9icyhzdGF0ZTogU3RhdGUpOiB2b2lkIHtcbiAgICBpZiAoIXN0YXRlIHx8ICFzdGF0ZS5wYWdlIHx8ICF0aGlzLnNlYXJjaC5ydWxlSWQpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhpcy5jdXJyZW50U3RhdGUgPSBzdGF0ZTtcblxuICAgIGxldCBwYWdlTnVtYmVyOiBudW1iZXIgPSBjYWxjdWxhdGVQYWdlKHN0YXRlKTtcbiAgICBpZiAocGFnZU51bWJlciA8PSAwKSB7XG4gICAgICBwYWdlTnVtYmVyID0gMTtcbiAgICB9XG5cbiAgICBsZXQgcGFyYW1zOiBSZXF1ZXN0UXVlcnlQYXJhbXMgPSBuZXcgUmVxdWVzdFF1ZXJ5UGFyYW1zKCk7XG4gICAgLy8gUGFnaW5hdGlvblxuICAgIHBhcmFtcy5zZXQoXCJwYWdlXCIsIFwiXCIgKyBwYWdlTnVtYmVyKTtcbiAgICBwYXJhbXMuc2V0KFwicGFnZV9zaXplXCIsIFwiXCIgKyB0aGlzLnBhZ2VTaXplKTtcbiAgICAvLyBTZWFyY2ggYnkgc3RhdHVzXG4gICAgaWYgKHRoaXMuc2VhcmNoLnN0YXR1cy50cmltKCkpIHtcbiAgICAgIHBhcmFtcy5zZXQoXCJzdGF0dXNcIiwgdGhpcy5zZWFyY2guc3RhdHVzKTtcbiAgICB9XG4gICAgLy8gU2VhcmNoIGJ5IHJlcG9zaXRvcnlcbiAgICBpZiAodGhpcy5zZWFyY2gucmVwb05hbWUudHJpbSgpKSB7XG4gICAgICBwYXJhbXMuc2V0KFwicmVwb3NpdG9yeVwiLCB0aGlzLnNlYXJjaC5yZXBvTmFtZSk7XG4gICAgfVxuICAgIC8vIFNlYXJjaCBieSB0aW1lc3RhbXBzXG4gICAgaWYgKHRoaXMuc2VhcmNoLnN0YXJ0VGltZXN0YW1wLnRyaW0oKSkge1xuICAgICAgcGFyYW1zLnNldChcInN0YXJ0X3RpbWVcIiwgdGhpcy5zZWFyY2guc3RhcnRUaW1lc3RhbXApO1xuICAgIH1cbiAgICBpZiAodGhpcy5zZWFyY2guZW5kVGltZXN0YW1wLnRyaW0oKSkge1xuICAgICAgcGFyYW1zLnNldChcImVuZF90aW1lXCIsIHRoaXMuc2VhcmNoLmVuZFRpbWVzdGFtcCk7XG4gICAgfVxuXG4gICAgdGhpcy5qb2JzTG9hZGluZyA9IHRydWU7XG5cbiAgICAvLyBEbyBmaWx0ZXJpbmcgYW5kIHNvcnRpbmdcbiAgICB0aGlzLmpvYnMgPSBkb0ZpbHRlcmluZzxSZXBsaWNhdGlvbkpvYkl0ZW0+KHRoaXMuam9icywgc3RhdGUpO1xuICAgIHRoaXMuam9icyA9IGRvU29ydGluZzxSZXBsaWNhdGlvbkpvYkl0ZW0+KHRoaXMuam9icywgc3RhdGUpO1xuXG4gICAgdGhpcy5qb2JzTG9hZGluZyA9IGZhbHNlO1xuICAgIHRvUHJvbWlzZTxSZXBsaWNhdGlvbkpvYj4oXG4gICAgICB0aGlzLnJlcGxpY2F0aW9uU2VydmljZS5nZXRKb2JzKHRoaXMuc2VhcmNoLnJ1bGVJZCwgcGFyYW1zKVxuICAgIClcbiAgICAgIC50aGVuKHJlc3BvbnNlID0+IHtcbiAgICAgICAgdGhpcy50b3RhbENvdW50ID0gcmVzcG9uc2UubWV0YWRhdGEueFRvdGFsQ291bnQ7XG4gICAgICAgIHRoaXMuam9icyA9IHJlc3BvbnNlLmRhdGE7XG5cbiAgICAgICAgaWYgKCF0aGlzLnRpbWVyRGVsYXkpIHtcbiAgICAgICAgICB0aGlzLnRpbWVyRGVsYXkgPSB0aW1lcigxMDAwMCwgMTAwMDApLnN1YnNjcmliZSgoKSA9PiB7XG4gICAgICAgICAgICBsZXQgY291bnQ6IG51bWJlciA9IDA7XG4gICAgICAgICAgICB0aGlzLmpvYnMuZm9yRWFjaChqb2IgPT4ge1xuICAgICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgam9iLnN0YXR1cyA9PT0gXCJwZW5kaW5nXCIgfHxcbiAgICAgICAgICAgICAgICBqb2Iuc3RhdHVzID09PSBcInJ1bm5pbmdcIiB8fFxuICAgICAgICAgICAgICAgIGpvYi5zdGF0dXMgPT09IFwicmV0cnlpbmdcIlxuICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICBjb3VudCsrO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIGlmIChjb3VudCA+IDApIHtcbiAgICAgICAgICAgICAgdGhpcy5jbHJMb2FkSm9icyh0aGlzLmN1cnJlbnRTdGF0ZSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICB0aGlzLnRpbWVyRGVsYXkudW5zdWJzY3JpYmUoKTtcbiAgICAgICAgICAgICAgdGhpcy50aW1lckRlbGF5ID0gbnVsbDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIERvIGZpbHRlcmluZyBhbmQgc29ydGluZ1xuICAgICAgICB0aGlzLmpvYnMgPSBkb0ZpbHRlcmluZzxSZXBsaWNhdGlvbkpvYkl0ZW0+KHRoaXMuam9icywgc3RhdGUpO1xuICAgICAgICB0aGlzLmpvYnMgPSBkb1NvcnRpbmc8UmVwbGljYXRpb25Kb2JJdGVtPih0aGlzLmpvYnMsIHN0YXRlKTtcblxuICAgICAgICB0aGlzLmpvYnNMb2FkaW5nID0gZmFsc2U7XG4gICAgICB9KVxuICAgICAgLmNhdGNoKGVycm9yID0+IHtcbiAgICAgICAgdGhpcy5qb2JzTG9hZGluZyA9IGZhbHNlO1xuICAgICAgICB0aGlzLmVycm9ySGFuZGxlci5lcnJvcihlcnJvcik7XG4gICAgICB9KTtcbiAgfVxuXG4gIGxvYWRGaXJzdFBhZ2UoKTogdm9pZCB7XG4gICAgbGV0IHN0OiBTdGF0ZSA9IHRoaXMuY3VycmVudFN0YXRlO1xuICAgIGlmICghc3QpIHtcbiAgICAgIHN0ID0ge1xuICAgICAgICBwYWdlOiB7fVxuICAgICAgfTtcbiAgICB9XG4gICAgc3QucGFnZS5zaXplID0gdGhpcy5wYWdlU2l6ZTtcbiAgICBzdC5wYWdlLmZyb20gPSAwO1xuICAgIHN0LnBhZ2UudG8gPSB0aGlzLnBhZ2VTaXplIC0gMTtcblxuICAgIHRoaXMuY2xyTG9hZEpvYnMoc3QpO1xuICB9XG5cbiAgc2VsZWN0T25lUnVsZShydWxlOiBSZXBsaWNhdGlvblJ1bGUpIHtcbiAgICBpZiAocnVsZSAmJiBydWxlLmlkKSB7XG4gICAgICB0aGlzLmhpZGRlbkpvYkxpc3QgPSBmYWxzZTtcbiAgICAgIHRoaXMuc2VhcmNoLnJ1bGVJZCA9IHJ1bGUuaWQgfHwgXCJcIjtcbiAgICAgIHRoaXMuc2VhcmNoLnJlcG9OYW1lID0gXCJcIjtcbiAgICAgIHRoaXMuc2VhcmNoLnN0YXR1cyA9IFwiXCI7XG4gICAgICB0aGlzLmN1cnJlbnRKb2JTZWFyY2hPcHRpb24gPSAwO1xuICAgICAgdGhpcy5jdXJyZW50Sm9iU3RhdHVzID0geyBrZXk6IFwiYWxsXCIsIGRlc2NyaXB0aW9uOiBcIlJFUExJQ0FUSU9OLkFMTFwiIH07XG4gICAgICB0aGlzLmxvYWRGaXJzdFBhZ2UoKTtcbiAgICB9XG4gIH1cblxuICByZXBsaWNhdGVNYW51YWxSdWxlKHJ1bGU6IFJlcGxpY2F0aW9uUnVsZSkge1xuICAgIGlmIChydWxlKSB7XG