@dicdikshaorg/video-player-v9
Version:
Contains Video player library components powered by angular. These components are designed to be used in sunbird consumption platforms *(mobile app, web portal, offline desktop app)* to drive reusability, maintainability hence reducing the redundant devel
445 lines • 42 kB
JavaScript
/**
* @fileoverview added by tsickle
* Generated from: lib/services/viewer.service.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
import { __awaiter } from "tslib";
import { HttpClient } from '@angular/common/http';
import { EventEmitter, Injectable, Optional } from '@angular/core';
import { SunbirdVideoPlayerService } from '../sunbird-video-player.service';
import { UtilService } from './util.service';
import { errorCode, errorMessage } from '@project-sunbird/sunbird-player-sdk-v9';
import { QuestionCursor } from '@project-sunbird/sunbird-quml-player-v9';
import { of } from 'rxjs';
import { map } from 'rxjs/operators';
import * as _ from 'lodash-es';
import * as i0 from "@angular/core";
import * as i1 from "../sunbird-video-player.service";
import * as i2 from "./util.service";
import * as i3 from "@angular/common/http";
import * as i4 from "@project-sunbird/sunbird-quml-player-v9";
export class ViewerService {
/**
* @param {?} videoPlayerService
* @param {?} utilService
* @param {?} http
* @param {?} questionCursor
*/
constructor(videoPlayerService, utilService, http, questionCursor) {
this.videoPlayerService = videoPlayerService;
this.utilService = utilService;
this.http = http;
this.questionCursor = questionCursor;
this.endPageSeen = false;
this.timeSpent = '0:0';
this.version = '1.0';
this.playerEvent = new EventEmitter();
this.sidebarMenuEvent = new EventEmitter();
this.isAvailableLocally = false;
this.interceptionResponses = {};
this.showScore = false;
this.scoreObtained = 0;
this.contentMap = {};
this.isEndEventRaised = false;
this.PlayerLoadStartedAt = new Date().getTime();
}
/**
* @param {?} __0
* @return {?}
*/
initialize({ context, config, metadata }) {
this.contentName = metadata.name;
this.isAvailableLocally = metadata.isAvailableLocally;
this.streamingUrl = metadata.streamingUrl;
this.artifactUrl = metadata.artifactUrl;
this.mimeType = metadata.streamingUrl ? 'application/x-mpegURL' : metadata.mimeType;
this.artifactMimeType = metadata.mimeType;
this.isAvailableLocally = metadata.isAvailableLocally;
this.traceId = config.traceId;
this.interceptionPoints = metadata.interceptionPoints;
if (context.userData) {
const { userData: { firstName, lastName } } = context;
this.userName = firstName === lastName ? firstName : `${firstName} ${lastName}`;
}
this.metaData = {
actions: [],
volume: [],
playBackSpeeds: [],
totalDuration: 0,
muted: undefined,
currentDuration: undefined,
transcripts: []
};
this.transcripts = metadata.transcripts ? metadata.transcripts : [];
this.showDownloadPopup = false;
this.endPageSeen = false;
if (this.isAvailableLocally) {
/** @type {?} */
const basePath = (metadata.streamingUrl) ? (metadata.streamingUrl) : (metadata.basePath || metadata.baseDir);
this.streamingUrl = `${basePath}/${metadata.artifactUrl}`;
this.mimeType = metadata.mimeType;
}
}
/**
* @param {?} selectedTranscripts
* @return {?}
*/
handleTranscriptsData(selectedTranscripts) {
this.metaData.transcripts = selectedTranscripts;
if (!_.isArray(this.transcripts)) {
this.raiseExceptionLog('INVALID_TRANSCRIPT_DATATYPE', 'TRANSCRIPT', new Error('Transcript data should be array'), this.traceId);
return [];
}
else {
_.forEach(this.transcripts, (/**
* @param {?} value
* @return {?}
*/
(value) => {
if (!(_.some(this.transcripts, { language: value.language, artifactUrl: value.artifactUrl,
languageCode: value.languageCode, identifier: value.identifier }))) {
this.raiseExceptionLog('TRANSCRIPT_DATA_MISSING', 'TRANSCRIPT', new Error('Transcript object dose not have required fields'), this.traceId);
return [];
}
else if (!_.isEmpty(selectedTranscripts) &&
(_.last(selectedTranscripts) !== 'off' && _.last(selectedTranscripts) === value.languageCode)) {
value.default = true;
}
}));
}
return this.transcripts;
}
/**
* @return {?}
*/
getPlayerOptions() {
return __awaiter(this, void 0, void 0, function* () {
if (!this.streamingUrl) {
return [{ src: this.artifactUrl, type: this.artifactMimeType }];
}
else {
/** @type {?} */
const data = yield this.http.head(this.streamingUrl, { responseType: 'blob' }).toPromise().catch((/**
* @param {?} error
* @return {?}
*/
error => {
// tslint:disable-next-line:max-line-length
this.raiseExceptionLog(errorCode.streamingUrlSupport, errorMessage.streamingUrlSupport, new Error(`Streaming Url Not Supported ${this.streamingUrl}`), this.traceId);
}));
if (data) {
return [{ src: this.streamingUrl, type: this.mimeType }];
}
else {
return [{ src: this.artifactUrl, type: this.artifactMimeType }];
}
}
});
}
/**
* @return {?}
*/
getMarkers() {
var _a, _b;
if ((_b = (_a = this) === null || _a === void 0 ? void 0 : _a.interceptionPoints) === null || _b === void 0 ? void 0 : _b.items) {
try {
/** @type {?} */
const interceptionPoints = this.interceptionPoints;
this.showScore = true;
return interceptionPoints.items.map((/**
* @param {?} __0
* @return {?}
*/
({ interceptionPoint, identifier, type }) => {
return { time: interceptionPoint, type, identifier, duration: 3 };
}));
}
catch (error) {
console.log(error);
this.raiseExceptionLog('CPV2_CONT_INTERCEPTION_PARSE', 'error parsing the inteception points string', error, '');
this.showScore = false;
}
}
return null;
}
/**
* @param {?} identifier
* @return {?}
*/
getQuestionSet(identifier) {
/** @type {?} */
const content = this.contentMap[identifier];
if (!content) {
if (!this.questionCursor) {
return null;
}
else {
return this.questionCursor.getQuestionSet(identifier)
.pipe(map((/**
* @param {?} response
* @return {?}
*/
(response) => {
this.contentMap[identifier] = response.questionSet;
return this.contentMap[identifier];
})));
}
}
else {
return of(content);
}
}
/**
* @return {?}
*/
preFetchContent() {
/** @type {?} */
const nextMarker = this.getNextMarker();
if (nextMarker) {
/** @type {?} */
const identifier = nextMarker.identifier;
this.getQuestionSet(nextMarker.identifier);
}
}
/**
* @return {?}
*/
getNextMarker() {
/** @type {?} */
const currentTime = this.playerInstance.currentTime();
/** @type {?} */
const markersList = this.getMarkers();
if (!markersList) {
return null;
}
return markersList.find((/**
* @param {?} marker
* @return {?}
*/
marker => {
/** @type {?} */
const markerTime = marker.time;
return markerTime > currentTime;
}));
}
/**
* @param {?} event
* @return {?}
*/
raiseStartEvent(event) {
/** @type {?} */
const duration = new Date().getTime() - this.PlayerLoadStartedAt;
/** @type {?} */
const startEvent = {
eid: 'START',
ver: this.version,
edata: {
type: 'START',
mode: 'play',
duration
},
metaData: this.metaData
};
this.playerEvent.emit(startEvent);
this.videoPlayerService.start(duration);
this.PlayerLoadStartedAt = new Date().getTime();
}
/**
* @return {?}
*/
calculateScore() {
this.scoreObtained = Object.values(this.interceptionResponses).reduce((
// tslint:disable-next-line:no-string-literal
/**
* @param {?} acc
* @param {?} response
* @return {?}
*/
(acc, response) => acc + response['score']), 0);
}
/**
* @return {?}
*/
raiseEndEvent() {
if (!this.isEndEventRaised) {
this.calculateScore();
/** @type {?} */
const duration = new Date().getTime() - this.PlayerLoadStartedAt;
/** @type {?} */
const endEvent = {
eid: 'END',
ver: this.version,
edata: {
type: 'END',
currentTime: this.currentlength,
totalTime: this.totalLength,
duration
},
metaData: this.metaData
};
this.playerEvent.emit(endEvent);
this.timeSpent = this.utilService.getTimeSpentText(this.visitedLength);
this.videoPlayerService.end(duration, this.totalLength, this.currentlength, this.endPageSeen, this.totalSeekedLength, this.visitedLength / 1000, this.scoreObtained);
this.isEndEventRaised = true;
}
}
/**
* @param {?} type
* @param {?=} extraValues
* @return {?}
*/
raiseHeartBeatEvent(type, extraValues) {
if (type === 'REPLAY') {
this.interceptionResponses = {};
this.showScore = false;
this.scoreObtained = 0;
}
/** @type {?} */
const hearBeatEvent = {
eid: 'HEARTBEAT',
ver: this.version,
edata: {
type,
currentPage: 'videostage',
extra: extraValues
},
metaData: this.metaData
};
this.playerEvent.emit(hearBeatEvent);
this.videoPlayerService.heartBeat(hearBeatEvent);
/** @type {?} */
const interactItems = ['PLAY', 'PAUSE', 'EXIT', 'VOLUME_CHANGE', 'DRAG',
'RATE_CHANGE', 'CLOSE_DOWNLOAD', 'DOWNLOAD', 'NAVIGATE_TO_PAGE',
'NEXT', 'OPEN_MENU', 'PREVIOUS', 'CLOSE_MENU', 'DOWNLOAD_MENU', 'DOWNLOAD_POPUP_CLOSE', 'DOWNLOAD_POPUP_CANCEL',
'SHARE', 'REPLAY', 'FORWARD', 'BACKWARD', 'FULLSCREEN', 'NEXT_CONTENT_PLAY', 'TRANSCRIPT_LANGUAGE_OFF',
'TRANSCRIPT_LANGUAGE_SELECTED', 'VIDEO_MARKER_SELECTED'
];
if (interactItems.includes(type)) {
this.videoPlayerService.interact(type.toLowerCase(), 'videostage', extraValues);
}
}
/**
* @param {?} pageId
* @param {?=} cdata
* @return {?}
*/
raiseImpressionEvent(pageId, cdata = {}) {
this.videoPlayerService.impression(pageId, cdata);
}
// tslint:disable-next-line:no-shadowed-variable
/**
* @param {?} errorCode
* @param {?} errorType
* @param {?} stacktrace
* @param {?} traceId
* @return {?}
*/
raiseExceptionLog(errorCode, errorType, stacktrace, traceId) {
/** @type {?} */
const exceptionLogEvent = {
eid: 'ERROR',
edata: {
err: errorCode,
errtype: errorType,
requestid: traceId || '',
stacktrace: (stacktrace && stacktrace.toString()) || '',
}
};
this.playerEvent.emit(exceptionLogEvent);
this.videoPlayerService.error(errorCode, errorType, stacktrace);
}
}
ViewerService.decorators = [
{ type: Injectable, args: [{
providedIn: 'root'
},] }
];
/** @nocollapse */
ViewerService.ctorParameters = () => [
{ type: SunbirdVideoPlayerService },
{ type: UtilService },
{ type: HttpClient },
{ type: QuestionCursor, decorators: [{ type: Optional }] }
];
/** @nocollapse */ ViewerService.ɵprov = i0.ɵɵdefineInjectable({ factory: function ViewerService_Factory() { return new ViewerService(i0.ɵɵinject(i1.SunbirdVideoPlayerService), i0.ɵɵinject(i2.UtilService), i0.ɵɵinject(i3.HttpClient), i0.ɵɵinject(i4.QuestionCursor, 8)); }, token: ViewerService, providedIn: "root" });
if (false) {
/** @type {?} */
ViewerService.prototype.endPageSeen;
/** @type {?} */
ViewerService.prototype.timeSpent;
/**
* @type {?}
* @private
*/
ViewerService.prototype.version;
/** @type {?} */
ViewerService.prototype.playerEvent;
/** @type {?} */
ViewerService.prototype.contentName;
/** @type {?} */
ViewerService.prototype.showDownloadPopup;
/** @type {?} */
ViewerService.prototype.streamingUrl;
/** @type {?} */
ViewerService.prototype.mimeType;
/** @type {?} */
ViewerService.prototype.artifactMimeType;
/** @type {?} */
ViewerService.prototype.userName;
/** @type {?} */
ViewerService.prototype.metaData;
/** @type {?} */
ViewerService.prototype.PlayerLoadStartedAt;
/** @type {?} */
ViewerService.prototype.totalLength;
/** @type {?} */
ViewerService.prototype.currentlength;
/** @type {?} */
ViewerService.prototype.totalSeekedLength;
/** @type {?} */
ViewerService.prototype.artifactUrl;
/** @type {?} */
ViewerService.prototype.visitedLength;
/** @type {?} */
ViewerService.prototype.sidebarMenuEvent;
/** @type {?} */
ViewerService.prototype.traceId;
/** @type {?} */
ViewerService.prototype.isAvailableLocally;
/** @type {?} */
ViewerService.prototype.interceptionPoints;
/** @type {?} */
ViewerService.prototype.interceptionResponses;
/** @type {?} */
ViewerService.prototype.showScore;
/** @type {?} */
ViewerService.prototype.scoreObtained;
/** @type {?} */
ViewerService.prototype.maxScore;
/** @type {?} */
ViewerService.prototype.playerInstance;
/** @type {?} */
ViewerService.prototype.contentMap;
/** @type {?} */
ViewerService.prototype.isEndEventRaised;
/** @type {?} */
ViewerService.prototype.transcripts;
/**
* @type {?}
* @private
*/
ViewerService.prototype.videoPlayerService;
/**
* @type {?}
* @private
*/
ViewerService.prototype.utilService;
/**
* @type {?}
* @private
*/
ViewerService.prototype.http;
/** @type {?} */
ViewerService.prototype.questionCursor;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmlld2VyLnNlcnZpY2UuanMiLCJzb3VyY2VSb290Ijoibmc6Ly9AZGljZGlrc2hhb3JnL3ZpZGVvLXBsYXllci12OS8iLCJzb3VyY2VzIjpbImxpYi9zZXJ2aWNlcy92aWV3ZXIuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDbEQsT0FBTyxFQUFFLFlBQVksRUFBRSxVQUFVLEVBQUUsUUFBUSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBRW5FLE9BQU8sRUFBRSx5QkFBeUIsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBQzVFLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUM3QyxPQUFPLEVBQUUsU0FBUyxFQUFHLFlBQVksRUFBRSxNQUFNLHdDQUF3QyxDQUFDO0FBQ2xGLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSx5Q0FBeUMsQ0FBQztBQUN6RSxPQUFPLEVBQUUsRUFBRSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQzFCLE9BQU8sRUFBRSxHQUFHLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUNyQyxPQUFPLEtBQUssQ0FBQyxNQUFNLFdBQVcsQ0FBQzs7Ozs7O0FBSy9CLE1BQU0sT0FBTyxhQUFhOzs7Ozs7O0lBK0J4QixZQUFvQixrQkFBNkMsRUFDN0MsV0FBd0IsRUFDeEIsSUFBZ0IsRUFDTCxjQUE4QjtRQUh6Qyx1QkFBa0IsR0FBbEIsa0JBQWtCLENBQTJCO1FBQzdDLGdCQUFXLEdBQVgsV0FBVyxDQUFhO1FBQ3hCLFNBQUksR0FBSixJQUFJLENBQVk7UUFDTCxtQkFBYyxHQUFkLGNBQWMsQ0FBZ0I7UUFoQ3RELGdCQUFXLEdBQUcsS0FBSyxDQUFDO1FBQ3BCLGNBQVMsR0FBRyxLQUFLLENBQUM7UUFDakIsWUFBTyxHQUFHLEtBQUssQ0FBQztRQUNqQixnQkFBVyxHQUFHLElBQUksWUFBWSxFQUFPLENBQUM7UUFjdEMscUJBQWdC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OztJQUN2QyxrQ0FBeUI7O0lBQ3pCLHNDQUE4Qjs7SUFDOUIsaUNBQXdCOztJQUN4Qix1Q0FBMkI7O0lBQzNCLG1DQUF1Qjs7SUFDdkIseUNBQWdDOztJQUNoQyxvQ0FBZ0M7Ozs7O0lBQ3BCLDJDQUFxRDs7Ozs7SUFDckQsb0NBQWdDOzs7OztJQUNoQyw2QkFBd0I7O0lBQ3hCLHVDQUFpRCIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEh0dHBDbGllbnQgfSBmcm9tICdAYW5ndWxhci9jb21tb24vaHR0cCc7XHJcbmltcG9ydCB7IEV2ZW50RW1pdHRlciwgSW5qZWN0YWJsZSwgT3B0aW9uYWwgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgUGxheWVyQ29uZmlnLCBUcmFuc2NyaXB0cyB9IGZyb20gJy4uL3BsYXllckludGVyZmFjZXMnO1xyXG5pbXBvcnQgeyBTdW5iaXJkVmlkZW9QbGF5ZXJTZXJ2aWNlIH0gZnJvbSAnLi4vc3VuYmlyZC12aWRlby1wbGF5ZXIuc2VydmljZSc7XHJcbmltcG9ydCB7IFV0aWxTZXJ2aWNlIH0gZnJvbSAnLi91dGlsLnNlcnZpY2UnO1xyXG5pbXBvcnQgeyBlcnJvckNvZGUgLCBlcnJvck1lc3NhZ2UgfSBmcm9tICdAcHJvamVjdC1zdW5iaXJkL3N1bmJpcmQtcGxheWVyLXNkay12OSc7XHJcbmltcG9ydCB7IFF1ZXN0aW9uQ3Vyc29yIH0gZnJvbSAnQHByb2plY3Qtc3VuYmlyZC9zdW5iaXJkLXF1bWwtcGxheWVyLXY5JztcclxuaW1wb3J0IHsgb2YgfSBmcm9tICdyeGpzJztcclxuaW1wb3J0IHsgbWFwIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xyXG5pbXBvcnQgKiBhcyBfIGZyb20gJ2xvZGFzaC1lcyc7XHJcblxyXG5ASW5qZWN0YWJsZSh7XHJcbiAgcHJvdmlkZWRJbjogJ3Jvb3QnXHJcbn0pXHJcbmV4cG9ydCBjbGFzcyBWaWV3ZXJTZXJ2aWNlIHtcclxuXHJcbiAgcHVibGljIGVuZFBhZ2VTZWVuID0gZmFsc2U7XHJcbiAgcHVibGljIHRpbWVTcGVudCA9ICcwOjAnO1xyXG4gIHByaXZhdGUgdmVyc2lvbiA9ICcxLjAnO1xyXG4gIHB1YmxpYyBwbGF5ZXJFdmVudCA9IG5ldyBFdmVudEVtaXR0ZXI8YW55PigpO1xyXG4gIHB1YmxpYyBjb250ZW50TmFtZTogc3RyaW5nO1xyXG4gIHB1YmxpYyBzaG93RG93bmxvYWRQb3B1cDogYm9vbGVhbjtcclxuICBwdWJsaWMgc3RyZWFtaW5nVXJsOiBzdHJpbmc7XHJcbiAgcHVibGljIG1pbWVUeXBlOiBzdHJpbmc7XHJcbiAgcHVibGljIGFydGlmYWN0TWltZVR5cGU6IHN0cmluZztcclxuICBwdWJsaWMgdXNlck5hbWU6IHN0cmluZztcclxuICBwdWJsaWMgbWV0YURhdGE6IGFueTtcclxuICBwdWJsaWMgUGxheWVyTG9hZFN0YXJ0ZWRBdDogbnVtYmVyO1xyXG4gIHB1YmxpYyB0b3RhbExlbmd0aDtcclxuICBwdWJsaWMgY3VycmVudGxlbmd0aDtcclxuICBwdWJsaWMgdG90YWxTZWVrZWRMZW5ndGg7XHJcbiAgcHVibGljIGFydGlmYWN0VXJsO1xyXG4gIHB1YmxpYyB2aXNpdGVkTGVuZ3RoO1xyXG4gIHB1YmxpYyBzaWRlYmFyTWVudUV2ZW50ID0gbmV3IEV2ZW50RW1pdHRlcjxhbnk+KCk7XHJcbiAgcHVibGljIHRyYWNlSWQ6IHN0cmluZztcclxuICBwdWJsaWMgaXNBdmFpbGFibGVMb2NhbGx5ID0gZmFsc2U7XHJcbiAgcHVibGljIGludGVyY2VwdGlvblBvaW50czogYW55O1xyXG4gIHB1YmxpYyBpbnRlcmNlcHRpb25SZXNwb25zZXM6IGFueSA9IHt9O1xyXG4gIHB1YmxpYyBzaG93U2NvcmUgPSBmYWxzZTtcclxuICBwdWJsaWMgc2NvcmVPYnRhaW5lZDogYW55ID0gMDtcclxuICBwdWJsaWMgbWF4U2NvcmU6IG51bWJlcjtcclxuICBwdWJsaWMgcGxheWVySW5zdGFuY2U6IGFueTtcclxuICBwdWJsaWMgY29udGVudE1hcCA9IHt9O1xyXG4gIHB1YmxpYyBpc0VuZEV2ZW50UmFpc2VkID0gZmFsc2U7XHJcbiAgcHVibGljIHRyYW5zY3JpcHRzOiBUcmFuc2NyaXB0cztcclxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIHZpZGVvUGxheWVyU2VydmljZTogU3VuYmlyZFZpZGVvUGxheWVyU2VydmljZSxcclxuICAgICAgICAgICAgICBwcml2YXRlIHV0aWxTZXJ2aWNlOiBVdGlsU2VydmljZSxcclxuICAgICAgICAgICAgICBwcml2YXRlIGh0dHA6IEh0dHBDbGllbnQsXHJcbiAgICAgICAgICAgICAgQE9wdGlvbmFsKCkgcHVibGljIHF1ZXN0aW9uQ3Vyc29yOiBRdWVzdGlvbkN1cnNvcikge1xyXG4gICAgdGhpcy5QbGF5ZXJMb2FkU3RhcnRlZEF0ID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XHJcbiAgfVxyXG5cclxuICBpbml0aWFsaXplKHsgY29udGV4dCwgY29uZmlnLCBtZXRhZGF0YSB9OiBQbGF5ZXJDb25maWcpIHtcclxuICAgIHRoaXMuY29udGVudE5hbWUgPSBtZXRhZGF0YS5uYW1lO1xyXG4gICAgdGhpcy5pc0F2YWlsYWJsZUxvY2FsbHkgPSBtZXRhZGF0YS5pc0F2YWlsYWJsZUxvY2FsbHk7XHJcbiAgICB0aGlzLnN0cmVhbWluZ1VybCA9IG1ldGFkYXRhLnN0cmVhbWluZ1VybDtcclxuICAgIHRoaXMuYXJ0aWZhY3RVcmwgPSBtZXRhZGF0YS5hcnRpZmFjdFVybDtcclxuICAgIHRoaXMubWltZVR5cGUgPSBtZXRhZGF0YS5zdHJlYW1pbmdVcmwgPyAnYXBwbGljYXRpb24veC1tcGVnVVJMJyA6IG1ldGFkYXRhLm1pbWVUeXBlO1xyXG4gICAgdGhpcy5hcnRpZmFjdE1pbWVUeXBlID0gbWV0YWRhdGEubWltZVR5cGU7XHJcbiAgICB0aGlzLmlzQXZhaWxhYmxlTG9jYWxseSA9IG1ldGFkYXRhLmlzQXZhaWxhYmxlTG9jYWxseTtcclxuICAgIHRoaXMudHJhY2VJZCA9IGNvbmZpZy50cmFjZUlkO1xyXG4gICAgdGhpcy5pbnRlcmNlcHRpb25Qb2ludHMgPSBtZXRhZGF0YS5pbnRlcmNlcHRpb25Qb2ludHM7XHJcbiAgICBpZiAoY29udGV4dC51c2VyRGF0YSkge1xyXG4gICAgICBjb25zdCB7IHVzZXJEYXRhOiB7IGZpcnN0TmFtZSwgbGFzdE5hbWUgfSB9ID0gY29udGV4dDtcclxuICAgICAgdGhpcy51c2VyTmFtZSA9IGZpcnN0TmFtZSA9PT0gbGFzdE5hbWUgPyBmaXJzdE5hbWUgOiBgJHtmaXJzdE5hbWV9ICR7bGFzdE5hbWV9YDtcclxuICAgIH1cclxuICAgIHRoaXMubWV0YURhdGEgPSB7XHJcbiAgICAgIGFjdGlvbnM6IFtcclxuICAgICAgXSxcclxuICAgICAgdm9sdW1lOiBbXSxcclxuICAgICAgcGxheUJhY2tTcGVlZHM6IFtdLFxyXG4gICAgICB0b3RhbER1cmF0aW9uOiAwLFxyXG4gICAgICBtdXRlZDogdW5kZWZpbmVkLFxyXG4gICAgICBjdXJyZW50RHVyYXRpb246IHVuZGVmaW5lZCxcclxuICAgICAgdHJhbnNjcmlwdHM6IFtdXHJcbiAgICB9O1xyXG4gICAgdGhpcy50cmFuc2NyaXB0cyA9IG1ldGFkYXRhLnRyYW5zY3JpcHRzID8gbWV0YWRhdGEudHJhbnNjcmlwdHMgOiBbXTtcclxuICAgIHRoaXMuc2hvd0Rvd25sb2FkUG9wdXAgPSBmYWxzZTtcclxuICAgIHRoaXMuZW5kUGFnZVNlZW4gPSBmYWxzZTtcclxuICAgIGlmICh0aGlzLmlzQXZhaWxhYmxlTG9jYWxseSkge1xyXG4gICAgICBjb25zdCBiYXNlUGF0aCA9IChtZXRhZGF0YS5zdHJlYW1pbmdVcmwpID8gKG1ldGFkYXRhLnN0cmVhbWluZ1VybCkgOiAobWV0YWRhdGEuYmFzZVBhdGggfHwgbWV0YWRhdGEuYmFzZURpcik7XHJcbiAgICAgIHRoaXMuc3RyZWFtaW5nVXJsID0gYCR7YmFzZVBhdGh9LyR7bWV0YWRhdGEuYXJ0aWZhY3RVcmx9YDtcclxuICAgICAgdGhpcy5taW1lVHlwZSA9IG1ldGFkYXRhLm1pbWVUeXBlO1xyXG4gICAgfVxyXG4gIH1cclxuICBoYW5kbGVUcmFuc2NyaXB0c0RhdGEoc2VsZWN0ZWRUcmFuc2NyaXB0cykge1xyXG4gICAgdGhpcy5tZXRhRGF0YS50cmFuc2NyaXB0cyA9IHNlbGVjdGVkVHJhbnNjcmlwdHM7XHJcbiAgICBpZiAoIV8uaXNBcnJheSh0aGlzLnRyYW5zY3JpcHRzKSkge1xyXG4gICAgICB0aGlzLnJhaXNlRXhjZXB0aW9uTG9nKCdJTlZBTElEX1RSQU5TQ1JJUFRfREFUQVRZUEUnLCAnVFJBTlNDUklQVCcsIG5ldyBFcnJvcignVHJhbnNjcmlwdCBkYXRhIHNob3VsZCBiZSBhcnJheScpLCB0aGlzLnRyYWNlSWQpO1xyXG4gICAgICByZXR1cm4gW107XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgIF8uZm9yRWFjaCh0aGlzLnRyYW5zY3JpcHRzLCAodmFsdWUpID0+IHtcclxuICAgICAgICBpZiAoIShfLnNvbWUodGhpcy50cmFuc2NyaXB0cywgeyBsYW5ndWFnZTogdmFsdWUubGFuZ3VhZ2UsIGFydGlmYWN0VXJsOiB2YWx1ZS5hcnRpZmFjdFVybCAsXHJcbiAgICAgICAgICBsYW5ndWFnZUNvZGU6IHZhbHVlLmxhbmd1YWdlQ29kZSwgaWRlbnRpZmllcjogdmFsdWUuaWRlbnRpZmllcn0pKSkge1xyXG4gICAgICAgICAgdGhpcy5yYWlzZUV4Y2VwdGlvbkxvZygnVFJBTlNDUklQVF9EQVRBX01JU1NJTkcnLCAnVFJBTlNDUklQVCcsXHJcbiAgICAgICAgICAgbmV3IEVycm9yKCdUcmFuc2NyaXB0IG9iamVjdCBkb3NlIG5vdCBoYXZlIHJlcXVpcmVkIGZpZWxkcycpLCB0aGlzLnRyYWNlSWQpO1xyXG4gICAgICAgICAgcmV0dXJuIFtdO1xyXG4gICAgICAgIH0gZWxzZSBpZiAoIV8uaXNFbXB0eShzZWxlY3RlZFRyYW5zY3JpcHRzKSAmJlxyXG4gICAgICAgICAgKCBfLmxhc3Qoc2VsZWN0ZWRUcmFuc2NyaXB0cykgIT09ICdvZmYnICYmICBfLmxhc3Qoc2VsZWN0ZWRUcmFuc2NyaXB0cykgPT09IHZhbHVlLmxhbmd1YWdlQ29kZSkpIHtcclxuICAgICAgICAgIHZhbHVlLmRlZmF1bHQgPSB0cnVlO1xyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gdGhpcy50cmFuc2NyaXB0cztcclxuICB9XHJcbiAgYXN5bmMgZ2V0UGxheWVyT3B0aW9ucygpIHtcclxuICAgIGlmICghdGhpcy5zdHJlYW1pbmdVcmwpIHtcclxuICAgICAgcmV0dXJuIFt7IHNyYzogdGhpcy5hcnRpZmFjdFVybCwgdHlwZTogdGhpcy5hcnRpZmFjdE1pbWVUeXBlIH1dO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgY29uc3QgZGF0YSA9IGF3YWl0IHRoaXMuaHR0cC5oZWFkKHRoaXMuc3RyZWFtaW5nVXJsLCB7IHJlc3BvbnNlVHlwZTogJ2Jsb2InIH0pLnRvUHJvbWlzZSgpLmNhdGNoKGVycm9yID0+IHtcclxuICAgICAgICAvLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmU6bWF4LWxpbmUtbGVuZ3RoXHJcbiAgICAgICAgdGhpcy5yYWlzZUV4Y2VwdGlvbkxvZyhlcnJvckNvZGUuc3RyZWFtaW5nVXJsU3VwcG9ydCAsIGVycm9yTWVzc2FnZS5zdHJlYW1pbmdVcmxTdXBwb3J0ICwgbmV3IEVycm9yKGBTdHJlYW1pbmcgVXJsIE5vdCBTdXBwb3J0ZWQgICR7dGhpcy5zdHJlYW1pbmdVcmx9YCksIHRoaXMudHJhY2VJZCk7XHJcbiAgICAgIH0pO1xyXG4gICAgICBpZiAoZGF0YSkge1xyXG4gICAgICAgIHJldHVybiBbeyBzcmM6IHRoaXMuc3RyZWFtaW5nVXJsLCB0eXBlOiB0aGlzLm1pbWVUeXBlIH1dO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHJldHVybiBbeyBzcmM6IHRoaXMuYXJ0aWZhY3RVcmwsIHR5cGU6IHRoaXMuYXJ0aWZhY3RNaW1lVHlwZSB9XTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgZ2V0TWFya2VycygpICB7XHJcbiAgICBpZiAodGhpcz8uaW50ZXJjZXB0aW9uUG9pbnRzPy5pdGVtcykge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGNvbnN0IGludGVyY2VwdGlvblBvaW50cyA9IHRoaXMuaW50ZXJjZXB0aW9uUG9pbnRzO1xyXG4gICAgICAgIHRoaXMuc2hvd1Njb3JlID0gdHJ1ZTtcclxuICAgICAgICByZXR1cm4gaW50ZXJjZXB0aW9uUG9pbnRzLml0ZW1zLm1hcCgoe2ludGVyY2VwdGlvblBvaW50LCBpZGVudGlmaWVyLCB0eXBlfSkgPT4ge1xyXG4gICAgICAgIHJldHVybiB7IHRpbWU6IGludGVyY2VwdGlvblBvaW50LCB0eXBlLCBpZGVudGlmaWVyLCBkdXJhdGlvbjogMyB9O1xyXG4gICAgICAgIH0pO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGNvbnNvbGUubG9nKGVycm9yKTtcclxuICAgICAgICB0aGlzLnJhaXNlRXhjZXB0aW9uTG9nKCdDUFYyX0NPTlRfSU5URVJDRVBUSU9OX1BBUlNFJywgJ2Vycm9yIHBhcnNpbmcgdGhlIGludGVjZXB0aW9uIHBvaW50cyBzdHJpbmcnLCBlcnJvciwgJycpO1xyXG4gICAgICAgIHRoaXMuc2hvd1Njb3JlID0gZmFsc2U7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICAgIHJldHVybiBudWxsO1xyXG4gIH1cclxuXHJcblxyXG4gIGdldFF1ZXN0aW9uU2V0KGlkZW50aWZpZXIpIHtcclxuICAgIGNvbnN0IGNvbnRlbnQgPSB0aGlzLmNvbnRlbnRNYXBbaWRlbnRpZmllcl07XHJcbiAgICBpZiAoIWNvbnRlbnQpIHtcclxuICAgICAgaWYgKCF0aGlzLnF1ZXN0aW9uQ3Vyc29yKSB7XHJcbiAgICAgICAgcmV0dXJuIG51bGw7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgcmV0dXJuIHRoaXMucXVlc3Rpb25DdXJzb3IuZ2V0UXVlc3Rpb25TZXQoaWRlbnRpZmllcilcclxuICAgICAucGlwZShtYXAoKHJlc3BvbnNlKSA9PiB7XHJcbiAgICAgICAgdGhpcy5jb250ZW50TWFwW2lkZW50aWZpZXJdID0gcmVzcG9uc2UucXVlc3Rpb25TZXQ7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuY29udGVudE1hcFtpZGVudGlmaWVyXTtcclxuICAgICAgIH0pKTtcclxuICAgICAgfVxyXG4gICAgfSBlbHNlIHtcclxuICAgICAgcmV0dXJuIG9mKGNvbnRlbnQpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHJlRmV0Y2hDb250ZW50KCkge1xyXG4gICAgY29uc3QgbmV4dE1hcmtlciA9IHRoaXMuZ2V0TmV4dE1hcmtlcigpO1xyXG4gICAgaWYgKG5leHRNYXJrZXIpIHtcclxuICAgICAgY29uc3QgaWRlbnRpZmllciA9IG5leHRNYXJrZXIuaWRlbnRpZmllcjtcclxuICAgICAgdGhpcy5nZXRRdWVzdGlvblNldChuZXh0TWFya2VyLmlkZW50aWZpZXIpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgZ2V0TmV4dE1hcmtlcigpIHtcclxuICAgIGNvbnN0IGN1cnJlbnRUaW1lID0gdGhpcy5wbGF5ZXJJbnN0YW5jZS5jdXJyZW50VGltZSgpO1xyXG4gICAgY29uc3QgbWFya2Vyc0xpc3QgPSB0aGlzLmdldE1hcmtlcnMoKTtcclxuICAgIGlmICghbWFya2Vyc0xpc3QpIHsgcmV0dXJuIG51bGw7IH1cclxuXHJcbiAgICByZXR1cm4gbWFya2Vyc0xpc3QuZmluZChtYXJrZXIgPT4ge1xyXG4gICAgICBjb25zdCBtYXJrZXJUaW1lID0gbWFya2VyLnRpbWU7XHJcbiAgICAgIHJldHVybiBtYXJrZXJUaW1lID4gY3VycmVudFRpbWU7XHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIHJhaXNlU3RhcnRFdmVudChldmVudCkge1xyXG4gICAgY29uc3QgZHVyYXRpb24gPSBuZXcgRGF0ZSgpLmdldFRpbWUoKSAtIHRoaXMuUGxheWVyTG9hZFN0YXJ0ZWRBdDtcclxuICAgIGNvbnN0IHN0YXJ0RXZlbnQgPSB7XHJcbiAgICAgIGVpZDogJ1NUQVJUJyxcclxuICAgICAgdmVyOiB0aGlzLnZlcnNpb24sXHJcbiAgICAgIGVkYXRhOiB7XHJcbiAgICAgICAgdHlwZTogJ1NUQVJUJyxcclxuICAgICAgICBtb2RlOiAncGxheScsXHJcbiAgICAgICAgZHVyYXRpb25cclxuICAgICAgfSxcclxuICAgICAgbWV0YURhdGE6IHRoaXMubWV0YURhdGFcclxuICAgIH07XHJcbiAgICB0aGlzLnBsYXllckV2ZW50LmVtaXQoc3RhcnRFdmVudCk7XHJcbiAgICB0aGlzLnZpZGVvUGxheWVyU2VydmljZS5zdGFydChkdXJhdGlvbik7XHJcbiAgICB0aGlzLlBsYXllckxvYWRTdGFydGVkQXQgPSBuZXcgRGF0ZSgpLmdldFRpbWUoKTtcclxuICB9XHJcblxyXG4gIGNhbGN1bGF0ZVNjb3JlKCkge1xyXG4gICAgdGhpcy5zY29yZU9idGFpbmVkID0gIE9iamVjdC52YWx1ZXModGhpcy5pbnRlcmNlcHRpb25SZXNwb25zZXMpLnJlZHVjZShcclxuICAgICAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lOm5vLXN0cmluZy1saXRlcmFsXHJcbiAgICAgIChhY2MsIHJlc3BvbnNlKSA9PiBhY2MgKyByZXNwb25zZVsnc2NvcmUnXSAsIDApO1xyXG4gIH1cclxuXHJcbiAgcmFpc2VFbmRFdmVudCgpIHtcclxuICAgIGlmICghdGhpcy5pc0VuZEV2ZW50UmFpc2VkKSB7XHJcbiAgICAgIHRoaXMuY2FsY3VsYXRlU2NvcmUoKTtcclxuICAgICAgY29uc3QgZHVyYXRpb24gPSBuZXcgRGF0ZSgpLmdldFRpbWUoKSAtIHRoaXMuUGxheWVyTG9hZFN0YXJ0ZWRBdDtcclxuICAgICAgY29uc3QgZW5kRXZlbnQgPSB7XHJcbiAgICAgICAgZWlkOiAnRU5EJyxcclxuICAgICAgICB2ZXI6IHRoaXMudmVyc2lvbixcclxuICAgICAgICBlZGF0YToge1xyXG4gICAgICAgICAgdHlwZTogJ0VORCcsXHJcbiAgICAgICAgICBjdXJyZW50VGltZTogdGhpcy5jdXJyZW50bGVuZ3RoLFxyXG4gICAgICAgICAgdG90YWxUaW1lOiB0aGlzLnRvdGFsTGVuZ3RoLFxyXG4gICAgICAgICAgZHVyYXRpb25cclxuICAgICAgICB9LFxyXG4gICAgICAgIG1ldGFEYXRhOiB0aGlzLm1ldGFEYXRhXHJcbiAgICAgIH07XHJcbiAgICAgIHRoaXMucGxheWVyRXZlbnQuZW1pdChlbmRFdmVudCk7XHJcbiAgICAgIHRoaXMudGltZVNwZW50ID0gdGhpcy51dGlsU2VydmljZS5nZXRUaW1lU3BlbnRUZXh0KHRoaXMudmlzaXRlZExlbmd0aCk7XHJcbiAgICAgIHRoaXMudmlkZW9QbGF5ZXJTZXJ2aWNlLmVuZChcclxuICAgICAgICBkdXJhdGlvbixcclxuICAgICAgICB0aGlzLnRvdGFsTGVuZ3RoLFxyXG4gICAgICAgIHRoaXMuY3VycmVudGxlbmd0aCxcclxuICAgICAgICB0aGlzLmVuZFBhZ2VTZWVuLFxyXG4gICAgICAgIHRoaXMudG90YWxTZWVrZWRMZW5ndGgsXHJcbiAgICAgICAgdGhpcy52aXNpdGVkTGVuZ3RoIC8gMTAwMCxcclxuICAgICAgICB0aGlzLnNjb3JlT2J0YWluZWRcclxuICAgICAgKTtcclxuICAgICAgdGhpcy5pc0VuZEV2ZW50UmFpc2VkID0gdHJ1ZTtcclxuICAgIH1cclxuICB9XHJcblxyXG5cclxuICByYWlzZUhlYXJ0QmVhdEV2ZW50KHR5cGU6IHN0cmluZywgZXh0cmFWYWx1ZXM/KSB7XHJcbiAgICBpZiAodHlwZSA9PT0gJ1JFUExBWScpIHtcclxuICAgICAgdGhpcy5pbnRlcmNlcHRpb25SZXNwb25zZXMgPSB7fTtcclxuICAgICAgdGhpcy5zaG93U2NvcmUgPSBmYWxzZTtcclxuICAgICAgdGhpcy5zY29yZU9idGFpbmVkID0gMDtcclxuICAgIH1cclxuICAgIGNvbnN0IGhlYXJCZWF0RXZlbnQgPSB7XHJcbiAgICAgIGVpZDogJ0hFQVJUQkVBVCcsXHJcbiAgICAgIHZlcjogdGhpcy52ZXJzaW9uLFxyXG4gICAgICBlZGF0YToge1xyXG4gICAgICAgIHR5cGUsXHJcbiAgICAgICAgY3VycmVudFBhZ2U6ICd2aWRlb3N0YWdlJyxcclxuICAgICAgICBleHRyYTogZXh0cmFWYWx1ZXNcclxuICAgICAgfSxcclxuICAgICAgbWV0YURhdGE6IHRoaXMubWV0YURhdGFcclxuICAgIH07XHJcbiAgICB0aGlzLnBsYXllckV2ZW50LmVtaXQoaGVhckJlYXRFdmVudCk7XHJcbiAgICB0aGlzLnZpZGVvUGxheWVyU2VydmljZS5oZWFydEJlYXQoaGVhckJlYXRFdmVudCk7XHJcbiAgICBjb25zdCBpbnRlcmFjdEl0ZW1zID0gWydQTEFZJywgJ1BBVVNFJywgJ0VYSVQnLCAnVk9MVU1FX0NIQU5HRScsICdEUkFHJyxcclxuICAgICAgJ1JBVEVfQ0hBTkdFJywgJ0NMT1NFX0RPV05MT0FEJywgJ0RPV05MT0FEJywgJ05BVklHQVRFX1RPX1BBR0UnLFxyXG4gICAgICAnTkVYVCcsICdPUEVOX01FTlUnLCAnUFJFVklPVVMnLCAnQ0xPU0VfTUVOVScsICdET1dOTE9BRF9NRU5VJywgJ0RPV05MT0FEX1BPUFVQX0NMT1NFJywgJ0RPV05MT0FEX1BPUFVQX0NBTkNFTCcsXHJcbiAgICAgICdTSEFSRScsICdSRVBMQVknLCAnRk9SV0FSRCcsICdCQUNLV0FSRCcsICdGVUxMU0NSRUVOJywgJ05FWFRfQ09OVEVOVF9QTEFZJywgJ1RSQU5TQ1JJUFRfTEFOR1VBR0VfT0ZGJyxcclxuICAgICAgJ1RSQU5TQ1JJUFRfTEFOR1VBR0VfU0VMRUNURUQnLCAnVklERU9fTUFSS0VSX1NFTEVDVEVEJ1xyXG4gICAgXTtcclxuICAgIGlmIChpbnRlcmFjdEl0ZW1zLmluY2x1ZGVzKHR5cGUpKSB7XHJcbiAgICAgIHRoaXMudmlkZW9QbGF5ZXJTZXJ2aWNlLmludGVyYWN0KHR5cGUudG9Mb3dlckNhc2UoKSwgJ3ZpZGVvc3RhZ2UnLCBleHRyYVZhbHVlcyk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICByYWlzZUltcHJlc3Npb25FdmVudChwYWdlSWQ6IHN0cmluZywgY2RhdGE6IGFueSA9IHt9KSB7XHJcbiAgICB0aGlzLnZpZGVvUGxheWVyU2VydmljZS5pbXByZXNzaW9uKHBhZ2VJZCwgY2RhdGEpO1xyXG4gIH1cclxuXHJcbiAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lOm5vLXNoYWRvd2VkLXZhcmlhYmxlXHJcbiAgcmFpc2VFeGNlcHRpb25Mb2coZXJyb3JDb2RlOiBzdHJpbmcsIGVycm9yVHlwZTogc3RyaW5nLCBzdGFja3RyYWNlLCB0cmFjZUlkKSB7XHJcbiAgICBjb25zdCBleGNlcHRpb25Mb2dFdmVudCA9IHtcclxuICAgICAgZWlkOiAnRVJST1InLFxyXG4gICAgICBlZGF0YToge1xyXG4gICAgICAgIGVycjogZXJyb3JDb2RlLFxyXG4gICAgICAgIGVycnR5cGU6IGVycm9yVHlwZSxcclxuICAgICAgICByZXF1ZXN0aWQ6IHRyYWNlSWQgfHwgJycsXHJcbiAgICAgICAgc3RhY2t0cmFjZTogKHN0YWNrdHJhY2UgJiYgc3RhY2t0cmFjZS50b1N0cmluZygpKSB8fCAnJyxcclxuICAgICAgfVxyXG4gICAgfTtcclxuICAgIHRoaXMucGxheWVyRXZlbnQuZW1pdChleGNlcHRpb25Mb2dFdmVudCk7XHJcbiAgICB0aGlzLnZpZGVvUGxheWVyU2VydmljZS5lcnJvcihlcnJvckNvZGUgLCBlcnJvclR5cGUgLCBzdGFja3RyYWNlKTtcclxuICB9XHJcblxyXG59XHJcbiJdfQ==