UNPKG

ang-music-player

Version:

Angular Music/Audio Player component for web applications. Easy and HIGHLY customisable.

145 lines (144 loc) 25 kB
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