ang-music-player
Version:
Angular Music/Audio Player component for web applications. Easy and HIGHLY customisable.
145 lines (144 loc) • 25 kB
JavaScript
import { Component, Output, Input, EventEmitter } from '@angular/core';
import { AudioPlyerOptions } from '../audioPlayer';
export class AngMusicPlayerComponent extends AudioPlyerOptions {
constructor() {
super();
this.audioList = [];
this.next = true;
this.previous = true;
this.shuffle = true;
this.repeat = true;
this.scrollTitle = false;
this.playButtonColor = "rgb(76, 130, 175)";
this.pauseButtonColor = "rgb(76, 130, 175)";
this.nextButtonColor = "rgb(76, 130, 175)";
this.previousButtonColor = "rgb(76, 130, 175)";
this.repeatButtonColor = "rgb(76, 130, 175)";
this.activeRepeatButtonColor = "rgb(76, 130, 175)";
this.volumeButtonColor = "rgb(76, 130, 175)";
this.muteButtonColor = "rgb(76, 130, 175)";
this.nextEvent = new EventEmitter();
this.previousEvent = new EventEmitter();
this.repeatEvent = new EventEmitter();
this.shuffleEvent = new EventEmitter();
this.seekEvent = new EventEmitter();
this.currentAudioIndex = 0;
this.repeatActive = false;
this.isError = false;
this.isShuffle = false;
}
ngOnInit() {
this.options();
this.initiateAudioPlayer();
//check audio is ended for next song
this.isAudioEnded.subscribe(data => {
if (!this.isRepeat && this.audioList.length > 0) {
this.nextAudio();
}
});
}
nextAudio() {
if (this.audioList.length - 1 != this.currentAudioIndex) {
this.currentAudioIndex += 1;
this.selectedAudio = this.audioList[this.currentAudioIndex];
this.getAudioLength();
if (this.isAudioPlaying) {
this.play();
}
this.nextEvent.emit();
}
else {
this.pause();
}
}
previousAudio() {
if (this.currentAudioIndex != 0) {
this.currentAudioIndex -= 1;
this.selectedAudio = this.audioList[this.currentAudioIndex];
this.getAudioLength();
if (this.isAudioPlaying) {
this.play();
}
this.previousEvent.emit();
}
}
seekAudio(seekAudioValue) {
if (this.audioVolume != 0) {
this.isMute = false;
}
this.audioPlayer.nativeElement.currentTime = seekAudioValue.target.value;
this.seekEvent.emit();
}
repeatAudio() {
this.isRepeat = !this.isRepeat;
this.repeatActive = !this.repeatActive;
this.audioPlayer.nativeElement.loop = this.isRepeat;
this.repeatEvent.emit();
}
/* shuffleAudio() {
this.isShuffle = !this.isShuffle;
if (this.isShuffle) {
let randomItem = Math.floor(Math.random() * this.audioList.length);
console.log(randomItem);
}
this.shuffleEvent.emit();
} */
volumeChange(volume) {
this.audioPlayer.nativeElement.volume = volume.target.value / 100;
}
muteAudio() {
if (this.isMute) {
this.audioPlayer.nativeElement.volume = 0.5;
this.isMute = false;
}
else {
this.audioPlayer.nativeElement.volume = 0;
this.isMute = true;
}
}
initiateAudioPlayer() {
if (this.audioList.length <= 0) {
this.isError = true;
}
else {
this.selectedAudio = this.audioList[this.currentAudioIndex];
}
}
}
AngMusicPlayerComponent.decorators = [
{ type: Component, args: [{
selector: 'ang-music-player',
template: "<audio controls #audioPlayer [src]=\"selectedAudio?.url\"> </audio>\r\n\r\n<div class=\"wrapper\" [ngStyle]=\"{ 'background-color': backgroundColor , 'width': width, 'height': height }\">\r\n\r\n <!-- loader and error -->\r\n <div class=\"loader\" *ngIf=\"!isAudioLoaded && !isError\"> Loading....</div>\r\n <div class=\"error\" *ngIf=\"isError\">No audio Found !</div>\r\n\r\n <div *ngIf=\"selectedAudio?.cover && isAudioLoaded\" class=\"cover\">\r\n <img [src]=\"selectedAudio?.cover\">\r\n </div>\r\n\r\n <div class=\"container\" *ngIf=\"isAudioLoaded\">\r\n <div class=\"details\">\r\n <div class=\"slidecontainer\">\r\n <input type=\"range\" max=\"{{totalAudioLength}}\" value=\"{{currentAudioTime}}\"\r\n [ngStyle]=\"{ 'background': timeSliderColor }\" (input)=\"seekAudio($event)\" class=\"slider\" id=\"myRange\">\r\n <div class=\"time-line\" [ngStyle]=\"{ 'color' : audioTimeColor }\">\r\n <div>{{ currentAudioTime | timeConversion}}</div>\r\n <div>{{ totalAudioLength | timeConversion}}</div>\r\n </div>\r\n </div>\r\n <marquee *ngIf=\"scrollTitle\" [ngStyle]=\"{ 'color' : audioTitleColor }\">\r\n <p class=\"title\"> {{selectedAudio?.title}}</p>\r\n </marquee>\r\n <p class=\"title\" [ngStyle]=\"{ 'color' : audioTitleColor }\" *ngIf=\"!scrollTitle\"> {{selectedAudio?.title}}</p>\r\n </div>\r\n <div class=\"controls\">\r\n\r\n <!-- repeat button starts -->\r\n <!-- not active -->\r\n <svg id=\"Layer_1\" *ngIf=\"repeat && !isRepeat\" (click)=\"repeatAudio()\" data-name=\"Layer 1\"\r\n xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 64 64\" [ngStyle]=\"{ 'fill' : repeatButtonColor }\">\r\n <title>repeat-on</title>\r\n <path class=\"cls-1\"\r\n d=\"M13.78,64a1.14,1.14,0,0,1-.8-.3L.26,51.3a1.07,1.07,0,0,1-.1-1.4l.1-.1L13,37.5a1.06,1.06,0,0,1,1.2-.2,1.2,1.2,0,0,1,.7,1v7.6H49.72a1.84,1.84,0,0,0,1.8-1.7V35.6a.91.91,0,0,1,.3-.7l8.51-8.3a1.06,1.06,0,0,1,1.2-.2,1.2,1.2,0,0,1,.7,1V46c0,6.7-3.6,10.2-10.51,10.2H14.88v6.7a1,1,0,0,1-.7,1A.6.6,0,0,1,13.78,64Z\"\r\n transform=\"translate(0.05 0)\" />\r\n <path class=\"cls-1\"\r\n d=\"M3,37.8a.6.6,0,0,1-.4-.1,1.09,1.09,0,0,1-.7-1V18C2,11.3,5.57,7.8,12.48,7.8H49.22V1.1a1.2,1.2,0,0,1,.7-1A.94.94,0,0,1,51,.3L63.64,12.7a1.07,1.07,0,0,1,.1,1.4l-.1.1L51,26.5a1.06,1.06,0,0,1-1.2.2,1.09,1.09,0,0,1-.7-1V18.1H14.38a1.69,1.69,0,0,0-1.7,1.7v8.6a1.14,1.14,0,0,1-.3.8L3.87,37.5A3.18,3.18,0,0,1,3,37.8Z\"\r\n transform=\"translate(0.05 0)\" />\r\n </svg>\r\n\r\n <!-- active -->\r\n <svg id=\"Layer_1\" *ngIf=\"repeat && isRepeat\" (click)=\"repeatAudio()\" data-name=\"Layer 1\"\r\n xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 63.98 64.03\" [ngStyle]=\"{ 'fill' : activeRepeatButtonColor }\">\r\n <style>\r\n .cls{\r\n fill: green\r\n }\r\n </style>\r\n <title>repeat-off</title>\r\n <path class=\"cls\"\r\n d=\"M13.78,64a1.13,1.13,0,0,1-.78-.31L.31,51.34a1,1,0,0,1-.07-1.41l.07-.07L13,37.49a1.09,1.09,0,0,1,1.19-.23,1,1,0,0,1,.66,1v7.63H49.64a1.73,1.73,0,0,0,1.75-1.69V35.59a1,1,0,0,1,.31-.74l8.49-8.28a1.12,1.12,0,0,1,1.18-.23,1.07,1.07,0,0,1,.67,1V46c0,6.68-3.63,10.21-10.51,10.21H14.86V63a1,1,0,0,1-.67,1A1,1,0,0,1,13.78,64Z\"\r\n transform=\"translate(0.02 0.03)\" />\r\n <path class=\"cls\"\r\n d=\"M3.05,37.75a1,1,0,0,1-.41-.09,1,1,0,0,1-.67-1V18C2,11.3,5.59,7.78,12.48,7.78H49.15V1.05a1.08,1.08,0,0,1,.67-1A1.1,1.1,0,0,1,51,.29L63.64,12.65a1,1,0,0,1,.07,1.41l-.07.07L51,26.49a1.08,1.08,0,0,1-1.18.23,1,1,0,0,1-.67-1v-7.6H14.36a1.71,1.71,0,0,0-1.72,1.69v8.61a1,1,0,0,1-.32.75l-8.5,8.26A1.06,1.06,0,0,1,3.05,37.75Z\"\r\n transform=\"translate(0.02 0.03)\" />\r\n </svg>\r\n <!-- repeat active ends -->\r\n\r\n <!-- previous button starts -->\r\n <svg id=\"Layer_1\" *ngIf=\"previous\" (click)=\"previousAudio()\" data-name=\"Layer 1\"\r\n xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 65 65.7\" [ngStyle]=\"{ 'fill' : previousButtonColor }\">\r\n <title>previous</title>\r\n <polygon class=\"cls-1\" points=\"64.5 0.85 7.05 32.85 64.5 64.85 64.5 0.85\" />\r\n <rect class=\"cls-1\" x=\"0.5\" y=\"0.85\" width=\"13.52\" height=\"64\" />\r\n </svg>\r\n <!-- previous button ends -->\r\n\r\n <!-- play button starts -->\r\n <svg id=\"Layer_1\" (click)=\"play()\" *ngIf=\"!isAudioPlaying\" data-name=\"Layer 1\" xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 64 64\" [ngStyle]=\"{ 'fill' : playButtonColor }\">\r\n <title>play</title>\r\n <path class=\"cls-1\"\r\n d=\"M21.65,79.51A3.48,3.48,0,0,1,18,76.22V18.79a3.47,3.47,0,0,1,3.64-3.28L80.8,45s2.73,2.47,0,4.93S21.65,79.51,21.65,79.51Z\"\r\n transform=\"translate(-18.01 -15.51)\" />\r\n </svg>\r\n <!-- play button ends -->\r\n\r\n <!-- pause button starts -->\r\n <svg id=\"Layer_1\" (click)=\"pause()\" *ngIf=\"isAudioPlaying\" data-name=\"Layer 1\" xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 64 64\" [ngStyle]=\"{ 'fill' : pauseButtonColor }\">\r\n <title>pause</title>\r\n <g id=\"pause\">\r\n <path class=\"cls-1\" d=\"M16,82H37.33V18H16ZM58.67,18V82H80V18Z\" transform=\"translate(-16 -18)\" />\r\n </g>\r\n </svg>\r\n <!-- pause button ends -->\r\n\r\n <!-- next button starts -->\r\n <svg id=\"Layer_1\" *ngIf=\"next\" (click)=\"nextAudio()\" data-name=\"Layer 1\" xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 64 64\" [ngStyle]=\"{ 'fill' : nextButtonColor }\">\r\n <title>next</title>\r\n <polygon class=\"cls-1\" points=\"0 64 57.45 32 0 0 0 64\" />\r\n <rect class=\"cls-1\" x=\"50.48\" width=\"13.52\" height=\"64\" />\r\n </svg>\r\n <!-- next button ends -->\r\n\r\n <!-- <div class=\"shuffle\" *ngIf=\"shuffle\" [ngClass]=\"{'shuffle-active': isShuffle}\" (click)=\"shuffleAudio()\"></div> -->\r\n\r\n <!-- volume button starts -->\r\n <div class=\"volume-container\">\r\n <!-- with volume -->\r\n <svg id=\"volume\" *ngIf=\"!isMute\" (click)=\"muteAudio()\" data-name=\"Layer 1\" xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 64 64\" [ngStyle]=\"{ 'fill' : pauseButtonColor }\">\r\n <defs>\r\n <style>\r\n .cls-2 {\r\n fill: none;\r\n }\r\n\r\n </style>\r\n </defs>\r\n <title>volume-high</title>\r\n <path class=\"cls-1\"\r\n d=\"M2.67,22.39V44.28H16.89L34.67,62.52V4.14L16.89,22.39Zm48,10.94a16.46,16.46,0,0,0-8.89-14.7V48A16.37,16.37,0,0,0,50.67,33.33Zm-8.89-32V8.85A25.49,25.49,0,0,1,59.56,33.33,25.5,25.5,0,0,1,41.78,57.82v7.51a32.65,32.65,0,0,0,24.89-32A32.66,32.66,0,0,0,41.78,1.33Z\"\r\n transform=\"translate(-2.67 -1.33)\" />\r\n <path class=\"cls-2\" d=\"M22.67,21.33h24v24h-24Z\" transform=\"translate(-2.67 -1.33)\" />\r\n </svg>\r\n\r\n <!-- mute -->\r\n <svg id=\"Capa_1\" *ngIf=\"isMute\" (click)=\"muteAudio()\" data-name=\"Capa 1\" xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 64 64\" [ngStyle]=\"{ 'fill' : muteButtonColor }\">\r\n <title>mute</title>\r\n <g id=\"volume-off\">\r\n <path class=\"cls-1\"\r\n d=\"M59,39.83a15.35,15.35,0,0,0-8.89-14.14v7.78L59,42.31Zm8.89,0A26.37,26.37,0,0,1,66.12,49l5.34,5.3A29.71,29.71,0,0,0,75,39.48,31.94,31.94,0,0,0,50.12,8.36v7.43C60.43,19.33,67.9,28.52,67.9,39.83ZM15.63,8,11,12.61,27.72,29.23H11V50.44H25.23L43,68.12V44.43L58.3,59.64a30,30,0,0,1-8.18,4.24V71.3a30.44,30.44,0,0,0,13.16-6.36L70.39,72,75,67.41,43,35.59ZM43,11.55,35.54,19,43,26.4Z\"\r\n transform=\"translate(-11.01 -8.01)\" />\r\n </g>\r\n </svg>\r\n\r\n <!-- volume button ends -->\r\n <div class=\"volume-control\">\r\n <input type=\"range\" max=\"100\" value=\"{{audioVolume}}\" (click)=\"$event.stopPropagation();\"\r\n (input)=\"volumeChange($event)\" [ngStyle]=\"{ 'background': volumeSliderColor }\" class=\"slider\"\r\n id=\"volumeRange\">\r\n </div>\r\n </div>\r\n\r\n </div>\r\n </div>\r\n</div>\r\n",
styles: ["@import url(\"https://fonts.googleapis.com/css?family=Raleway&display=swap\");audio{display:none}.wrapper{align-items:center;background:#000;border-radius:15px;display:flex;font-family:Raleway,sans-serif;height:130px;width:500px}.wrapper .cover img{border-radius:50%;margin-left:10px;max-height:100px;max-width:100px}.wrapper .loader{color:#fff}.wrapper .error,.wrapper .loader{margin:0 auto;position:relative;text-align:center}.wrapper .error{color:#ff3737}.wrapper .container{padding:5px;width:100%}.wrapper .container .details{text-align:center}.wrapper .container .details .title{color:#4c82af;margin:7px 0 15px}.wrapper .container .controls{display:flex;flex-basis:auto;flex-direction:row;flex-wrap:wrap;justify-content:space-around;margin-top:8px}.wrapper .container .controls svg{cursor:pointer;height:25px;margin:0 20px;width:25px}.wrapper .container .volume-container{position:relative}.wrapper .container .volume-container .volume-control{display:none;height:32px;left:-9px;position:absolute;top:-62px;transform:rotate(270deg);width:90px;z-index:1000}.wrapper .container .volume-container:hover .volume-control{display:block}.slidecontainer{align-items:center;display:flex;flex-direction:column;width:100%}.slidecontainer .time-line{color:#4c82af;display:flex;justify-content:space-between;margin:7px 0 2px;width:87%}.slider{-webkit-appearance:none;background:#fff;border-radius:5px;height:2px;opacity:1;outline:none;transition:opacity .2s;width:87%;z-index:1000}.slider::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;background:#4c82af;border-radius:50%;cursor:pointer;height:15px;width:15px}.slider::-moz-range-thumb{background:#4c82af;border-radius:50%;cursor:pointer;height:15px;width:15px}"]
},] }
];
AngMusicPlayerComponent.ctorParameters = () => [];
AngMusicPlayerComponent.propDecorators = {
width: [{ type: Input }],
height: [{ type: Input }],
backgroundColor: [{ type: Input }],
audioTimeColor: [{ type: Input }],
audioTitleColor: [{ type: Input }],
volumeSliderColor: [{ type: Input }],
timeSliderColor: [{ type: Input }],
audioList: [{ type: Input }],
next: [{ type: Input }],
previous: [{ type: Input }],
shuffle: [{ type: Input }],
repeat: [{ type: Input }],
scrollTitle: [{ type: Input }],
playButtonColor: [{ type: Input }],
pauseButtonColor: [{ type: Input }],
nextButtonColor: [{ type: Input }],
previousButtonColor: [{ type: Input }],
repeatButtonColor: [{ type: Input }],
activeRepeatButtonColor: [{ type: Input }],
volumeButtonColor: [{ type: Input }],
muteButtonColor: [{ type: Input }],
nextEvent: [{ type: Output }],
previousEvent: [{ type: Output }],
repeatEvent: [{ type: Output }],
shuffleEvent: [{ type: Output }],
seekEvent: [{ type: Output }]
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYW5nLW11c2ljLXBsYXllci5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiRTovUFJPSkVDVFMvYW5ndWxhci1hdWRpby1wbGF5ZXIvcHJvamVjdHMvYW5nLW11c2ljLXBsYXllci9zcmMvIiwic291cmNlcyI6WyJsaWIvY29tcG9uZW50L2FuZy1tdXNpYy1wbGF5ZXIuY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQVUsTUFBTSxFQUFFLEtBQUssRUFBRSxZQUFZLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDL0UsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFPbkQsTUFBTSxPQUFPLHVCQUF3QixTQUFRLGlCQUFpQjtJQW1DNUQ7UUFDRSxLQUFLLEVBQUUsQ0FBQztRQTVCRCxjQUFTLEdBQUcsRUFBRSxDQUFDO1FBQ2YsU0FBSSxHQUFHLElBQUksQ0FBQztRQUNaLGFBQVEsR0FBRyxJQUFJLENBQUM7UUFDaEIsWUFBTyxHQUFHLElBQUksQ0FBQztRQUNmLFdBQU0sR0FBRyxJQUFJLENBQUM7UUFDZCxnQkFBVyxHQUFHLEtBQUssQ0FBQztRQUNwQixvQkFBZSxHQUFHLG1CQUFtQixDQUFDO1FBQ3RDLHFCQUFnQixHQUFHLG1CQUFtQixDQUFDO1FBQ3ZDLG9CQUFlLEdBQUcsbUJBQW1CLENBQUM7UUFDdEMsd0JBQW1CLEdBQUcsbUJBQW1CLENBQUM7UUFDMUMsc0JBQWlCLEdBQUcsbUJBQW1CLENBQUM7UUFDeEMsNEJBQXVCLEdBQUcsbUJBQW1CLENBQUM7UUFDOUMsc0JBQWlCLEdBQUcsbUJBQW1CLENBQUM7UUFDeEMsb0JBQWUsR0FBRyxtQkFBbUIsQ0FBQztRQUNyQyxjQUFTLEdBQUcsSUFBSSxZQUFZLEVBQUUsQ0FBQztRQUMvQixrQkFBYSxHQUFHLElBQUksWUFBWSxFQUFFLENBQUM7UUFDbkMsZ0JBQVcsR0FBRyxJQUFJLFlBQVksRUFBRSxDQUFDO1FBQ2pDLGlCQUFZ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QUNmLElBQUksQ0FBQyxXQUFXLENBQUMsYUFBYSxDQUFDLE1BQU0sR0FBRyxHQUFHLENBQUM7WUFDNUMsSUFBSSxDQUFDLE1BQU0sR0FBRyxLQUFLLENBQUM7U0FDckI7YUFBTTtZQUNMLElBQUksQ0FBQyxXQUFXLENBQUMsYUFBYSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUM7WUFDMUMsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLENBQUM7U0FDcEI7SUFDSCxDQUFDO0lBRUQsbUJBQW1CO1FBQ2pCLElBQUksSUFBSSxDQUFDLFNBQVMsQ0FBQyxNQUFNLElBQUksQ0FBQyxFQUFFO1lBQzlCLElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSxDQUFDO1NBQ3JCO2FBQU07WUFDTCxJQUFJLENBQUMsYUFBYSxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLGlCQUFpQixDQUFDLENBQUM7U0FDN0Q7SUFDSCxDQUFDOzs7WUE5SEYsU0FBUyxTQUFDO2dCQUNULFFBQVEsRUFBRSxrQkFBa0I7Z0JBQzVCLCtyUUFBZ0Q7O2FBRWpEOzs7O29CQUVFLEtBQUs7cUJBQ0wsS0FBSzs4QkFDTCxLQUFLOzZCQUNMLEtBQUs7OEJBQ0wsS0FBSztnQ0FDTCxLQUFLOzhCQUNMLEtBQUs7d0JBQ0wsS0FBSzttQkFDTCxLQUFLO3VCQUNMLEtBQUs7c0JBQ0wsS0FBSztxQkFDTCxLQUFLOzBCQUNMLEtBQUs7OEJBQ0wsS0FBSzsrQkFDTCxLQUFLOzhCQUNMLEtBQUs7a0NBQ0wsS0FBSztnQ0FDTCxLQUFLO3NDQUNMLEtBQUs7Z0NBQ0wsS0FBSzs4QkFDTCxLQUFLO3dCQUNMLE1BQU07NEJBQ04sTUFBTTswQkFDTixNQUFNOzJCQUNOLE1BQU07d0JBQ04sTUFBTSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgT25Jbml0LCBPdXRwdXQsIElucHV0LCBFdmVudEVtaXR0ZXIgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgQXVkaW9QbHllck9wdGlvbnMgfSBmcm9tICcuLi9hdWRpb1BsYXllcic7XHJcblxyXG5AQ29tcG9uZW50KHtcclxuICBzZWxlY3RvcjogJ2FuZy1tdXNpYy1wbGF5ZXInLFxyXG4gIHRlbXBsYXRlVXJsOiAnLi9hbmctbXVzaWMtcGxheWVyLmNvbXBvbmVudC5odG1sJyxcclxuICBzdHlsZVVybHM6IFsnLi9hbmctbXVzaWMtcGxheWVyLmNvbXBvbmVudC5zY3NzJ11cclxufSlcclxuZXhwb3J0IGNsYXNzIEFuZ011c2ljUGxheWVyQ29tcG9uZW50IGV4dGVuZHMgQXVkaW9QbHllck9wdGlvbnMgaW1wbGVtZW50cyBPbkluaXQge1xyXG4gIEBJbnB1dCgpIHdpZHRoOyBcclxuICBASW5wdXQoKSBoZWlnaHQ7IFxyXG4gIEBJbnB1dCgpIGJhY2tncm91bmRDb2xvcjsgXHJcbiAgQElucHV0KCkgYXVkaW9UaW1lQ29sb3I7XHJcbiAgQElucHV0KCkgYXVkaW9UaXRsZUNvbG9yOyBcclxuICBASW5wdXQoKSB2b2x1bWVTbGlkZXJDb2xvcjsgXHJcbiAgQElucHV0KCkgdGltZVNsaWRlckNvbG9yO1xyXG4gIEBJbnB1dCgpIGF1ZGlvTGlzdCA9IFtdO1xyXG4gIEBJbnB1dCgpIG5leHQgPSB0cnVlO1xyXG4gIEBJbnB1dCgpIHByZXZpb3VzID0gdHJ1ZTtcclxuICBASW5wdXQoKSBzaHVmZmxlID0gdHJ1ZTtcclxuICBASW5wdXQoKSByZXBlYXQgPSB0cnVlO1xyXG4gIEBJbnB1dCgpIHNjcm9sbFRpdGxlID0gZmFsc2U7XHJcbiAgQElucHV0KCkgcGxheUJ1dHRvbkNvbG9yID0gXCJyZ2IoNzYsIDEzMCwgMTc1KVwiO1xyXG4gIEBJbnB1dCgpIHBhdXNlQnV0dG9uQ29sb3IgPSBcInJnYig3NiwgMTMwLCAxNzUpXCI7XHJcbiAgQElucHV0KCkgbmV4dEJ1dHRvbkNvbG9yID0gXCJyZ2IoNzYsIDEzMCwgMTc1KVwiO1xyXG4gIEBJbnB1dCgpIHByZXZpb3VzQnV0dG9uQ29sb3IgPSBcInJnYig3NiwgMTMwLCAxNzUpXCI7XHJcbiAgQElucHV0KCkgcmVwZWF0QnV0dG9uQ29sb3IgPSBcInJnYig3NiwgMTMwLCAxNzUpXCI7XHJcbiAgQElucHV0KCkgYWN0aXZlUmVwZWF0QnV0dG9uQ29sb3IgPSBcInJnYig3NiwgMTMwLCAxNzUpXCI7XHJcbiAgQElucHV0KCkgdm9sdW1lQnV0dG9uQ29sb3IgPSBcInJnYig3NiwgMTMwLCAxNzUpXCI7XHJcbiAgQElucHV0KCkgbXV0ZUJ1dHRvbkNvbG9yID0gXCJyZ2IoNzYsIDEzMCwgMTc1KVwiO1xyXG4gIEBPdXRwdXQoKSBuZXh0RXZlbnQgPSBuZXcgRXZlbnRFbWl0dGVyKCk7XHJcbiAgQE91dHB1dCgpIHByZXZpb3VzRXZlbnQgPSBuZXcgRXZlbnRFbWl0dGVyKCk7XHJcbiAgQE91dHB1dCgpIHJlcGVhdEV2ZW50ID0gbmV3IEV2ZW50RW1pdHRlcigpO1xyXG4gIEBPdXRwdXQoKSBzaHVmZmxlRXZlbnQgPSBuZXcgRXZlbnRFbWl0dGVyKCk7XHJcbiAgQE91dHB1dCgpIHNlZWtFdmVudCA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcclxuXHJcbiAgc2VsZWN0ZWRBdWRpbztcclxuICBjdXJyZW50QXVkaW9JbmRleCA9IDA7XHJcbiAgcmVwZWF0QWN0aXZlID0gZmFsc2U7XHJcbiAgaXNFcnJvciA9IGZhbHNlO1xyXG4gIGlzU2h1ZmZsZSA9IGZhbHNlO1xyXG4gIHZvbHVtZUJlZm9yZU11dGU7XHJcblxyXG4gIGNvbnN0cnVjdG9yKCkge1xyXG4gICAgc3VwZXIoKTtcclxuICB9XHJcblxyXG4gIG5nT25Jbml0KCkge1xyXG4gICAgdGhpcy5vcHRpb25zKCk7XHJcbiAgICB0aGlzLmluaXRpYXRlQXVkaW9QbGF5ZXIoKTtcclxuICAgIC8vY2hlY2sgYXVkaW8gaXMgZW5kZWQgZm9yIG5leHQgc29uZ1xyXG4gICAgdGhpcy5pc0F1ZGlvRW5kZWQuc3Vic2NyaWJlKGRhdGEgPT4ge1xyXG4gICAgICBpZiAoIXRoaXMuaXNSZXBlYXQgJiYgdGhpcy5hdWRpb0xpc3QubGVuZ3RoID4gMCkge1xyXG4gICAgICAgIHRoaXMubmV4dEF1ZGlvKCk7XHJcbiAgICAgIH1cclxuICAgIH0pXHJcbiAgfVxyXG5cclxuICBuZXh0QXVkaW8oKSB7XHJcbiAgICBpZiAodGhpcy5hdWRpb0xpc3QubGVuZ3RoIC0gMSAhPSB0aGlzLmN1cnJlbnRBdWRpb0luZGV4KSB7XHJcbiAgICAgIHRoaXMuY3VycmVudEF1ZGlvSW5kZXggKz0gMTtcclxuICAgICAgdGhpcy5zZWxlY3RlZEF1ZGlvID0gdGhpcy5hdWRpb0xpc3RbdGhpcy5jdXJyZW50QXVkaW9JbmRleF07XHJcbiAgICAgIHRoaXMuZ2V0QXVkaW9MZW5ndGgoKTtcclxuICAgICAgaWYgKHRoaXMuaXNBdWRpb1BsYXlpbmcpIHtcclxuICAgICAgICB0aGlzLnBsYXkoKTtcclxuICAgICAgfVxyXG4gICAgICB0aGlzLm5leHRFdmVudC5lbWl0KCk7XHJcbiAgICB9ZWxzZXtcclxuICAgICAgdGhpcy5wYXVzZSgpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHJldmlvdXNBdWRpbygpIHtcclxuICAgIGlmICh0aGlzLmN1cnJlbnRBdWRpb0luZGV4ICE9IDApIHtcclxuICAgICAgdGhpcy5jdXJyZW50QXVkaW9JbmRleCAtPSAxO1xyXG4gICAgICB0aGlzLnNlbGVjdGVkQXVkaW8gPSB0aGlzLmF1ZGlvTGlzdFt0aGlzLmN1cnJlbnRBdWRpb0luZGV4XTtcclxuICAgICAgdGhpcy5nZXRBdWRpb0xlbmd0aCgpO1xyXG4gICAgICBpZiAodGhpcy5pc0F1ZGlvUGxheWluZykge1xyXG4gICAgICAgIHRoaXMucGxheSgpO1xyXG4gICAgICB9XHJcbiAgICAgIHRoaXMucHJldmlvdXNFdmVudC5lbWl0KCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBzZWVrQXVkaW8oc2Vla0F1ZGlvVmFsdWUpIHtcclxuICAgIGlmICh0aGlzLmF1ZGlvVm9sdW1lICE9IDApIHtcclxuICAgICAgdGhpcy5pc011dGUgPSBmYWxzZTtcclxuICAgIH1cclxuICAgIHRoaXMuYXVkaW9QbGF5ZXIubmF0aXZlRWxlbWVudC5jdXJyZW50VGltZSA9IHNlZWtBdWRpb1ZhbHVlLnRhcmdldC52YWx1ZTtcclxuICAgIHRoaXMuc2Vla0V2ZW50LmVtaXQoKTtcclxuICB9XHJcblxyXG4gIHJlcGVhdEF1ZGlvKCkge1xyXG4gICAgdGhpcy5pc1JlcGVhdCA9ICF0aGlzLmlzUmVwZWF0O1xyXG4gICAgdGhpcy5yZXBlYXRBY3RpdmUgPSAhdGhpcy5yZXBlYXRBY3RpdmU7XHJcbiAgICB0aGlzLmF1ZGlvUGxheWVyLm5hdGl2ZUVsZW1lbnQubG9vcCA9IHRoaXMuaXNSZXBlYXQ7XHJcbiAgICB0aGlzLnJlcGVhdEV2ZW50LmVtaXQoKTtcclxuICB9XHJcblxyXG4vKiAgIHNodWZmbGVBdWRpbygpIHtcclxuICAgIHRoaXMuaXNTaHVmZmxlID0gIXRoaXMuaXNTaHVmZmxlO1xyXG4gICAgaWYgKHRoaXMuaXNTaHVmZmxlKSB7XHJcbiAgICBsZXQgcmFuZG9tSXRlbSA9IE1hdGguZmxvb3IoTWF0aC5yYW5kb20oKSAqIHRoaXMuYXVkaW9MaXN0Lmxlbmd0aCk7XHJcbiAgICBjb25zb2xlLmxvZyhyYW5kb21JdGVtKTtcclxuICAgIFxyXG4gICAgfVxyXG4gICAgdGhpcy5zaHVmZmxlRXZlbnQuZW1pdCgpO1xyXG4gIH0gKi9cclxuXHJcbiAgdm9sdW1lQ2hhbmdlKHZvbHVtZSkge1xyXG4gICAgdGhpcy5hdWRpb1BsYXllci5uYXRpdmVFbGVtZW50LnZvbHVtZSA9IHZvbHVtZS50YXJnZXQudmFsdWUgLyAxMDA7XHJcbiAgfVxyXG5cclxuICBtdXRlQXVkaW8oKSB7XHJcbiAgICBpZiAodGhpcy5pc011dGUpIHtcclxuICAgICAgdGhpcy5hdWRpb1BsYXllci5uYXRpdmVFbGVtZW50LnZvbHVtZSA9IDAuNTtcclxuICAgICAgdGhpcy5pc011dGUgPSBmYWxzZTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHRoaXMuYXVkaW9QbGF5ZXIubmF0aXZlRWxlbWVudC52b2x1bWUgPSAwO1xyXG4gICAgICB0aGlzLmlzTXV0ZSA9IHRydWU7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBpbml0aWF0ZUF1ZGlvUGxheWVyKCkge1xyXG4gICAgaWYgKHRoaXMuYXVkaW9MaXN0Lmxlbmd0aCA8PSAwKSB7XHJcbiAgICAgIHRoaXMuaXNFcnJvciA9IHRydWU7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICB0aGlzLnNlbGVjdGVkQXVkaW8gPSB0aGlzLmF1ZGlvTGlzdFt0aGlzLmN1cnJlbnRBdWRpb0luZGV4XTtcclxuICAgIH1cclxuICB9XHJcbn1cclxuIl19