{"version":3,"sources":["webpack://WaveSurfer/webpack/universalModuleDefinition","webpack://WaveSurfer/webpack/bootstrap","webpack://WaveSurfer/./src/util/index.js","webpack://WaveSurfer/./src/webaudio.js","webpack://WaveSurfer/./src/util/request-animation-frame.js","webpack://WaveSurfer/./src/util/observer.js","webpack://WaveSurfer/./src/peakcache.js","webpack://WaveSurfer/./src/mediaelement.js","webpack://WaveSurfer/./src/drawer.js","webpack://WaveSurfer/./src/drawer.multicanvas.js","webpack://WaveSurfer/./src/util/prevent-click.js","webpack://WaveSurfer/./node_modules/debounce/index.js","webpack://WaveSurfer/./src/util/frame.js","webpack://WaveSurfer/./src/util/style.js","webpack://WaveSurfer/./src/util/extend.js","webpack://WaveSurfer/./src/util/min.js","webpack://WaveSurfer/./src/util/max.js","webpack://WaveSurfer/./src/util/get-id.js","webpack://WaveSurfer/./src/util/ajax.js","webpack://WaveSurfer/./src/wavesurfer.js"],"names":["root","factory","exports","module","define","amd","window","installedModules","__webpack_require__","moduleId","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","prototype","hasOwnProperty","p","s","default","util","PLAYING","PAUSED","FINISHED","WebAudio","params","_this$stateBehaviors","_this$states","_classCallCheck","this","_this","_possibleConstructorReturn","__proto__","getPrototypeOf","audioContext","offlineAudioContext","stateBehaviors","_defineProperty","init","addOnAudioProcess","getPlayedPercents","duration","getDuration","getCurrentTime","startPosition","getPlayedTime","removeOnAudioProcess","fireEvent","ac","getAudioContext","lastPlay","currentTime","scheduledPause","states","analyser","buffer","filters","gainNode","mergedPeaks","offlineAc","peaks","playbackRate","scriptNode","source","splitPeaks","state","explicitDuration","Observer","AudioContext","webkitAudioContext","WaveSurferAudioContext","sampleRate","WaveSurferOfflineAudioContext","OfflineAudioContext","webkitOfflineAudioContext","createVolumeNode","createScriptNode","createAnalyserNode","setState","setPlaybackRate","audioRate","setLength","forEach","filter","disconnect","connect","_len","arguments","length","Array","_key","setFilters","disconnectFilters","reduce","prev","curr","audioScriptProcessor","createScriptProcessor","scriptBufferSize","createJavaScriptNode","destination","_this2","onaudioprocess","time","pause","createAnalyser","createGain","createGainNode","deviceId","audio","Audio","setSinkId","Promise","reject","Error","autoplay","dest","createMediaStreamDestination","src","URL","createObjectURL","stream","gain","setValueAtTime","arraybuffer","callback","errback","getOfflineAudioContext","decodeAudioData","data","channels","numberOfChannels","first","last","newBuffer","createBuffer","sampleSize","sampleStep","chan","getChannelData","start","end","min","max","j","splitChannels","isPaused","unAll","disconnectSource","closeAudioContext","close","createSource","createBufferSource","noteGrainOn","stop","noteOff","adjustedTime","seekTo","resume","play","requestAnimationFrame","webkitRequestAnimationFrame","mozRequestAnimationFrame","oRequestAnimationFrame","msRequestAnimationFrame","element","setTimeout","handlers","event","fn","push","un","e","splice","handler","on","args","apply","_len2","_key2","PeakCache","clearPeakCache","peakCacheRanges","peakCacheLength","uncachedRanges","item","pos","arr","concat","sort","a","b","uncachedRangePairs","peakCacheRangePairs","_webaudio","MediaElement","media","paused","volume","mediaType","toLowerCase","elementPosition","onPlayEnd","createTimer","onAudioProcess","url","container","preload","document","createElement","controls","mediaControls","style","width","prevMedia","querySelector","removeChild","appendChild","_load","elt","_this3","load","addEventListener","setVolume","Infinity","seekable","clearPlayEnd","promise","setPlayEnd","_this4","_onPlayEnd","_get","removeMediaElementOnDestroy","parentNode","Drawer","height","pixelRatio","lastPos","wrapper","el","styles","display","position","userSelect","webkitUserSelect","fillParent","scrollParent","overflowX","hideScrollbar","overflowY","setupWrapperEvents","noPrevent","preventDefault","clientX","targetTouches","bbox","getBoundingClientRect","nominalWidth","parentWidth","getWidth","progress","left","scrollLeft","scrollWidth","scrollbarHeight","offsetHeight","clientHeight","clientY","bottom","interact","handleEvent","setWidth","clearWave","barWidth","drawBars","drawWave","percent","recenterOnPosition","immediate","half","clientWidth","maxScroll","target","offset","Math","x","round","updateSize","minPxDelta","autoCenter","newPos","updateProgress","channelIndex","_drawer","MultiCanvas","maxCanvasWidth","maxCanvasElementWidth","hasProgressCanvas","waveColor","progressColor","halfPixel","canvases","progressWave","createWrapper","createElements","zIndex","top","overflow","boxSizing","borderRightStyle","pointerEvents","addCanvas","updateCursor","borderRightWidth","cursorWidth","borderRightColor","cursorColor","totalWidth","requiredCanvases","ceil","removeCanvas","entry","canvasWidth","updateDimensions","clearWaveForEntry","leftOffset","wave","waveCtx","getContext","progressCtx","lastEntry","pop","parentElement","elementWidth","canvas","offsetLeft","clearRect","prepareDraw","_ref","absmax","hasMinVals","offsetY","halfH","undefined","peakIndexScale","bar","step","barGap","scale","peak","floor","h","fillRect","_this5","_ref2","reflectedPeaks","len","drawLine","_this6","setFillStyles","drawLineToContext","ctx","canvasStart","canvasEnd","beginPath","moveTo","lineTo","closePath","fill","y","startCanvas","endCanvas","intersection","x1","y1","x2","y2","fillRectToContext","_this7","frame","setHeight","channelPeaks","barHeight","normalize","some","val","fillStyle","type","quality","images","map","toDataURL","preventClickHandler","stopPropagation","body","removeEventListener","values","func","wait","timeout","context","timestamp","result","later","Date","now","debounced","callNow","clear","clearTimeout","flush","_requestAnimationFrame2","_requestAnimationFrame","keys","prop","sources","smallest","Number","largest","random","toString","substring","options","instance","xhr","XMLHttpRequest","fired100","open","method","responseType","requestHeaders","header","setRequestHeader","withCredentials","lengthComputable","loaded","total","status","response","send","_observer","PluginClass","ws","WaveSurfer","defaultParams","backend","dragSelection","forceDecode","loopSelection","mediaContainer","minPxPerSec","partialRender","devicePixelRatio","screen","deviceXDPI","logicalXDPI","plugins","renderer","responsive","skipLength","backends","extend","savedVolume","isMuted","tmpEvents","currentAjax","drawer","peakCache","Backend","initialisedPluginList","isDestroyed","isReady","prevWidth","_onResize","debounce","registerPlugins","createDrawer","createBackend","createPeakCache","plugin","addPlugin","deferInit","initPlugin","staticProps","pluginStaticProp","Instance","getOwnPropertyNames","destroyPlugin","destroy","drawBuffer","supportsWebAudio","seconds","skip","seekAndCenter","recenter","_this8","isFinite","console","error","oldScrollParent","newVolume","getVolume","rate","getPlaybackRate","setMute","mute","color","getScrollX","newRanges","addRangeToPeakCache","getPeaks","drawPeaks","pxPerSec","_this9","decodeArrayBuffer","loadDecodedBuffer","blob","_this10","reader","FileReader","onProgress","loadArrayBuffer","readAsArrayBuffer","empty","preloadIgnoreReasons","Preload is not 'auto', 'none' or 'metadata'","indexOf","Peaks are not provided","Backend is not of type MediaElement","Url is not of type string","activeReasons","reason","warn","join","loadBuffer","loadMediaElement","_this11","action","once","getArrayBuffer","setPeaks","urlOrElt","_this12","loadElt","err","_this13","_this14","ajax","statusText","percentComplete","accuracy","noWindow","json","JSON","stringify","encodeURIComponent","format","getImage","abort","cancelAjax","clearTmpEvents","destroyAllPlugins"],"mappings":";;;;;CAAA,SAAAA,EAAAC,GACA,iBAAAC,SAAA,iBAAAC,OACAA,OAAAD,QAAAD,IACA,mBAAAG,eAAAC,IACAD,OAAA,gBAAAH,GACA,iBAAAC,QACAA,QAAA,WAAAD,IAEAD,EAAA,WAAAC,IARA,CASCK,OAAA,WACD,mBCTA,IAAAC,KAGA,SAAAC,EAAAC,GAGA,GAAAF,EAAAE,GACA,OAAAF,EAAAE,GAAAP,QAGA,IAAAC,EAAAI,EAAAE,IACAC,EAAAD,EACAE,GAAA,EACAT,YAUA,OANAU,EAAAH,GAAAI,KAAAV,EAAAD,QAAAC,IAAAD,QAAAM,GAGAL,EAAAQ,GAAA,EAGAR,EAAAD,QA0DA,OArDAM,EAAAM,EAAAF,EAGAJ,EAAAO,EAAAR,EAGAC,EAAAQ,EAAA,SAAAd,EAAAe,EAAAC,GACAV,EAAAW,EAAAjB,EAAAe,IACAG,OAAAC,eAAAnB,EAAAe,GAA0CK,YAAA,EAAAC,IAAAL,KAK1CV,EAAAgB,EAAA,SAAAtB,GACA,oBAAAuB,eAAAC,aACAN,OAAAC,eAAAnB,EAAAuB,OAAAC,aAAwDC,MAAA,WAExDP,OAAAC,eAAAnB,EAAA,cAAiDyB,OAAA,KAQjDnB,EAAAoB,EAAA,SAAAD,EAAAE,GAEA,GADA,EAAAA,IAAAF,EAAAnB,EAAAmB,IACA,EAAAE,EAAA,OAAAF,EACA,KAAAE,GAAA,iBAAAF,QAAAG,WAAA,OAAAH,EACA,IAAAI,EAAAX,OAAAY,OAAA,MAGA,GAFAxB,EAAAgB,EAAAO,GACAX,OAAAC,eAAAU,EAAA,WAAyCT,YAAA,EAAAK,UACzC,EAAAE,GAAA,iBAAAF,EAAA,QAAAM,KAAAN,EAAAnB,EAAAQ,EAAAe,EAAAE,EAAA,SAAAA,GAAgH,OAAAN,EAAAM,IAAqBC,KAAA,KAAAD,IACrI,OAAAF,GAIAvB,EAAA2B,EAAA,SAAAhC,GACA,IAAAe,EAAAf,KAAA2B,WACA,WAA2B,OAAA3B,EAAA,SAC3B,WAAiC,OAAAA,GAEjC,OADAK,EAAAQ,EAAAE,EAAA,IAAAA,GACAA,GAIAV,EAAAW,EAAA,SAAAiB,EAAAC,GAAsD,OAAAjB,OAAAkB,UAAAC,eAAA1B,KAAAuB,EAAAC,IAGtD7B,EAAAgC,EAAA,GAIAhC,IAAAiC,EAAA,yKClFSC,iGACAA,+FACAA,+FACAA,mGACAA,kGACAA,iGACAA,gHACAA,iGACAA,mGACAA,0JACAA,mVCVGC,0JAAZnC,EAAA,4HAGA,IAAMoC,EAAU,UACVC,EAAS,SACTC,EAAW,WAOIC,cAwFjB,SAAAA,EAAYC,GAAQ,IAAAC,EAAAC,+FAAAC,CAAAC,KAAAL,GAAA,IAAAM,mKAAAC,CAAAF,MAAAL,EAAAQ,WAAAnC,OAAAoC,eAAAT,IAAAlC,KAAAuC,OAAA,OAAAC,EApFpBI,aAAe,KAoFKJ,EAlFpBK,oBAAsB,KAkFFL,EAhFpBM,gBAgFoBC,EAAAX,KA/EfL,GACGiB,KADO,WAEHT,KAAKU,qBAETC,kBAJO,WAKH,IAAMC,EAAWZ,KAAKa,cACtB,OAAOb,KAAKc,iBAAmBF,GAAY,GAE/CE,eARO,WASH,OAAOd,KAAKe,cAAgBf,KAAKgB,mBAsEzBR,EAAAX,EAnEfJ,GACGgB,KADM,WAEFT,KAAKiB,wBAETN,kBAJM,WAKF,IAAMC,EAAWZ,KAAKa,cACtB,OAAOb,KAAKc,iBAAmBF,GAAY,GAE/CE,eARM,WASF,OAAOd,KAAKe,iBA0DJP,EAAAX,EAvDfH,GACGe,KADQ,WAEJT,KAAKiB,uBACLjB,KAAKkB,UAAU,WAEnBP,kBALQ,WAMJ,OAAO,GAEXG,eARQ,WASJ,OAAOd,KAAKa,iBA8CJhB,GAGhBI,EAAKL,OAASA,EAEdK,EAAKkB,GAAKvB,EAAOS,cAAgBJ,EAAKmB,kBAEtCnB,EAAKoB,SAAWpB,EAAKkB,GAAGG,YAExBrB,EAAKc,cAAgB,EAErBd,EAAKsB,eAAiB,KAEtBtB,EAAKuB,QAALhB,EAAAV,KACKN,EAAUxB,OAAOY,OAAOqB,EAAKM,eAAef,KADjDgB,EAAAV,EAEKL,EAASzB,OAAOY,OAAOqB,EAAKM,eAAed,KAFhDe,EAAAV,EAGKJ,EAAW1B,OAAOY,OAAOqB,EAAKM,eAAeb,KAHlDI,GAMAG,EAAKwB,SAAW,KAEhBxB,EAAKyB,OAAS,KAEdzB,EAAK0B,WAEL1B,EAAK2B,SAAW,KAEhB3B,EAAK4B,YAAc,KAEnB5B,EAAK6B,UAAY,KAEjB7B,EAAK8B,MAAQ,KAEb9B,EAAK+B,aAAe,EAEpB/B,EAAKwB,SAAW,KAEhBxB,EAAKgC,WAAa,KAElBhC,EAAKiC,OAAS,KAEdjC,EAAKkC,cAELlC,EAAKmC,MAAQ,KAEbnC,EAAKoC,iBAAmB,KA7CRpC,qUAxFcV,EAAK+C,wDAqDnC,SAAUpF,OAAOqF,eAAgBrF,OAAOsF,8DAaxC,OAJKtF,OAAOuF,yBACRvF,OAAOuF,uBAAyB,IAAKvF,OAAOqF,cACxCrF,OAAOsF,qBAERtF,OAAOuF,sEASKC,GAKnB,OAJKxF,OAAOyF,gCACRzF,OAAOyF,8BAAgC,IAAKzF,OAAO0F,qBAC/C1F,OAAO2F,2BAA2B,EAAG,EAAGH,IAEzCxF,OAAOyF,oEA4Dd3C,KAAK8C,mBACL9C,KAAK+C,mBACL/C,KAAKgD,qBAELhD,KAAKiD,SAASxD,GACdO,KAAKkD,gBAAgBlD,KAAKJ,OAAOuD,WACjCnD,KAAKoD,UAAU,+CAKXpD,KAAK2B,UACL3B,KAAK2B,QAAQ0B,QAAQ,SAAAC,GACjBA,GAAUA,EAAOC,eAErBvD,KAAK2B,QAAU,KAEf3B,KAAKyB,SAAS+B,QAAQxD,KAAK4B,4CAK1BQ,GACDpC,KAAKoC,QAAUpC,KAAKwB,OAAOY,KAC3BpC,KAAKoC,MAAQpC,KAAKwB,OAAOY,GACzBpC,KAAKoC,MAAM3B,KAAKhD,KAAKuC,2CASP,QAAAyD,EAAAC,UAAAC,OAAThC,EAASiC,MAAAH,GAAAI,EAAA,EAAAA,EAAAJ,EAAAI,IAATlC,EAASkC,GAAAH,UAAAG,GAClB7D,KAAK8D,WAAWnC,sCAWTA,GAEP3B,KAAK+D,oBAGDpC,GAAWA,EAAQgC,SACnB3D,KAAK2B,QAAUA,EAGf3B,KAAKyB,SAAS8B,aAGd5B,EACKqC,OAAO,SAACC,EAAMC,GAEX,OADAD,EAAKT,QAAQU,GACNA,GACRlE,KAAKyB,UACP+B,QAAQxD,KAAK4B,sDAMlB5B,KAAKJ,OAAOuE,qBACZnE,KAAKiC,WAAajC,KAAKJ,OAAOuE,qBAE1BnE,KAAKmB,GAAGiD,sBACRpE,KAAKiC,WAAajC,KAAKmB,GAAGiD,sBACtBzE,EAAS0E,kBAGbrE,KAAKiC,WAAajC,KAAKmB,GAAGmD,qBACtB3E,EAAS0E,kBAIrBrE,KAAKiC,WAAWuB,QAAQxD,KAAKmB,GAAGoD,yDAIhB,IAAAC,EAAAxE,KAChBA,KAAKiC,WAAWwC,eAAiB,WAC7B,IAAMC,EAAOF,EAAK1D,iBAEd4D,GAAQF,EAAK3D,eACb2D,EAAKvB,SAASvD,GACd8E,EAAKtD,UAAU,UACRwD,GAAQF,EAAKjD,eACpBiD,EAAKG,QACEH,EAAKpC,QAAUoC,EAAKhD,OAAOhC,IAClCgF,EAAKtD,UAAU,eAAgBwD,mDAOvC1E,KAAKiC,WAAWwC,eAAiB,kDAKjCzE,KAAKyB,SAAWzB,KAAKmB,GAAGyD,iBACxB5E,KAAKyB,SAAS+B,QAAQxD,KAAK4B,qDAUvB5B,KAAKmB,GAAG0D,WACR7E,KAAK4B,SAAW5B,KAAKmB,GAAG0D,aAExB7E,KAAK4B,SAAW5B,KAAKmB,GAAG2D,iBAG5B9E,KAAK4B,SAAS4B,QAAQxD,KAAKmB,GAAGoD,+CAQxBQ,GACN,GAAIA,EAAU,CAMV,IAAIC,EAAQ,IAAI9H,OAAO+H,MACvB,IAAKD,EAAME,UACP,OAAOC,QAAQC,OACX,IAAIC,MAAM,+CAGlBL,EAAMM,UAAW,EACjB,IAAIC,EAAOvF,KAAKmB,GAAGqE,+BAKnB,OAJAxF,KAAK4B,SAAS2B,aACdvD,KAAK4B,SAAS4B,QAAQ+B,GACtBP,EAAMS,IAAMC,IAAIC,gBAAgBJ,EAAKK,QAE9BZ,EAAME,UAAUH,GAEvB,OAAOI,QAAQC,OAAO,IAAIC,MAAM,qBAAuBN,sCASrDxG,GACNyB,KAAK4B,SAASiE,KAAKC,eAAevH,EAAOyB,KAAKmB,GAAGG,iDASjD,OAAOtB,KAAK4B,SAASiE,KAAKtH,gDAIZwH,EAAaC,EAAUC,GAChCjG,KAAK8B,YACN9B,KAAK8B,UAAY9B,KAAKkG,uBAClBlG,KAAKmB,GAAKnB,KAAKmB,GAAGuB,WAAa,QAGvC1C,KAAK8B,UAAUqE,gBACXJ,EACA,SAAAK,GAAA,OAAQJ,EAASI,IACjBH,oCAUClE,EAAOnB,GACZZ,KAAKqC,iBAAmBzB,EACxBZ,KAAK+B,MAAQA,oCAQP4B,GAEN,IAAI3D,KAAK6B,aAAe8B,GAAU,EAAI3D,KAAK6B,YAAY8B,OAAS,EAAI,EAApE,CAIA3D,KAAKmC,cACLnC,KAAK6B,eAGL,IAAMwE,EAAWrG,KAAK0B,OAAS1B,KAAK0B,OAAO4E,iBAAmB,EAC1D3I,SACJ,IAAKA,EAAI,EAAGA,EAAI0I,EAAU1I,IACtBqC,KAAKmC,WAAWxE,MAChBqC,KAAKmC,WAAWxE,GAAG,GAAKgG,EAAS,IAAM,EACvC3D,KAAKmC,WAAWxE,GAAG,GAAKgG,EAAS,GAAK,GAAK,EAE/C3D,KAAK6B,YAAY,GAAK8B,EAAS,IAAM,EACrC3D,KAAK6B,YAAY,GAAK8B,EAAS,GAAK,GAAK,oCAYpCA,EAAQ4C,EAAOC,GACpB,GAAIxG,KAAK+B,MACL,OAAO/B,KAAK+B,MAehB,GAZAwE,EAAQA,GAAS,EACjBC,EAAOA,GAAQ7C,EAAS,EAExB3D,KAAKoD,UAAUO,IASV3D,KAAK0B,OAAOiC,OAAQ,CACrB,IAAM8C,EAAYzG,KAAK0G,aAAa,EAAG,KAAM1G,KAAK0C,YAClD1C,KAAK0B,OAAS+E,EAAU/E,OAG5B,IAAMiF,EAAa3G,KAAK0B,OAAOiC,OAASA,EAClCiD,KAAgBD,EAAa,KAAO,EACpCN,EAAWrG,KAAK0B,OAAO4E,iBACzB3I,SAEJ,IAAKA,EAAI,EAAGA,EAAI0I,EAAU1I,IAAK,CAC3B,IAAMoE,EAAQ/B,KAAKmC,WAAWxE,GACxBkJ,EAAO7G,KAAK0B,OAAOoF,eAAenJ,GACpCL,SAEJ,IAAKA,EAAIiJ,EAAOjJ,GAAKkJ,EAAMlJ,IAAK,CAC5B,IAAMyJ,KAAWzJ,EAAIqJ,GACfK,KAASD,EAAQJ,GACnBM,EAAM,EACNC,EAAM,EACNC,SAEJ,IAAKA,EAAIJ,EAAOI,EAAIH,EAAKG,GAAKP,EAAY,CACtC,IAAMrI,EAAQsI,EAAKM,GAEf5I,EAAQ2I,IACRA,EAAM3I,GAGNA,EAAQ0I,IACRA,EAAM1I,GAIdwD,EAAM,EAAIzE,GAAK4J,EACfnF,EAAM,EAAIzE,EAAI,GAAK2J,GAEV,GAALtJ,GAAUuJ,EAAMlH,KAAK6B,YAAY,EAAIvE,MACrC0C,KAAK6B,YAAY,EAAIvE,GAAK4J,IAGrB,GAALvJ,GAAUsJ,EAAMjH,KAAK6B,YAAY,EAAIvE,EAAI,MACzC0C,KAAK6B,YAAY,EAAIvE,EAAI,GAAK2J,IAK1C,OAAOjH,KAAKJ,OAAOwH,cAAgBpH,KAAKmC,WAAanC,KAAK6B,wDAS1D,OAAO7B,KAAKoC,MAAMzB,kBAAkBlD,KAAKuC,iDAKrCA,KAAKkC,QACLlC,KAAKkC,OAAOqB,+CAQXvD,KAAKqH,YACNrH,KAAK2E,QAET3E,KAAKsH,QACLtH,KAAK0B,OAAS,KACd1B,KAAK+D,oBACL/D,KAAKuH,mBACLvH,KAAK4B,SAAS2B,aACdvD,KAAKiC,WAAWsB,aAChBvD,KAAKyB,SAAS8B,aAGVvD,KAAKJ,OAAO4H,oBAGiB,mBAAlBxH,KAAKmB,GAAGsG,OACE,UAAjBzH,KAAKmB,GAAGiB,OAERpC,KAAKmB,GAAGsG,QAGZzH,KAAKmB,GAAK,KAGLnB,KAAKJ,OAAOS,aAGbL,KAAKJ,OAAOS,aAAe,KAF3BnD,OAAOuF,uBAAyB,KAKpCvF,OAAOyF,8BAAgC,mCAS1CjB,GACD1B,KAAKe,cAAgB,EACrBf,KAAKqB,SAAWrB,KAAKmB,GAAGG,YACxBtB,KAAK0B,OAASA,EACd1B,KAAK0H,sDAKL1H,KAAKuH,mBACLvH,KAAKkC,OAASlC,KAAKmB,GAAGwG,qBAGtB3H,KAAKkC,OAAO6E,MAAQ/G,KAAKkC,OAAO6E,OAAS/G,KAAKkC,OAAO0F,YACrD5H,KAAKkC,OAAO2F,KAAO7H,KAAKkC,OAAO2F,MAAQ7H,KAAKkC,OAAO4F,QAEnD9H,KAAKkC,OAAOF,aAAa8D,eACrB9F,KAAKgC,aACLhC,KAAKmB,GAAGG,aAEZtB,KAAKkC,OAAOR,OAAS1B,KAAK0B,OAC1B1B,KAAKkC,OAAOsB,QAAQxD,KAAKyB,6CASzB,OAAOzB,KAAKoC,QAAUpC,KAAKwB,OAAOhC,yCASlC,OAAKQ,KAAK0B,OAMH1B,KAAK0B,OAAOd,SALXZ,KAAKqC,iBACErC,KAAKqC,iBAET,iCAYR0E,EAAOC,GACV,GAAKhH,KAAK0B,OAuBV,OAnBA1B,KAAKuB,eAAiB,KAET,MAATwF,IACAA,EAAQ/G,KAAKc,mBACAd,KAAKa,gBACdkG,EAAQ,GAGL,MAAPC,IACAA,EAAMhH,KAAKa,eAGfb,KAAKe,cAAgBgG,EACrB/G,KAAKqB,SAAWrB,KAAKmB,GAAGG,YAEpBtB,KAAKoC,QAAUpC,KAAKwB,OAAO9B,IAC3BM,KAAKiD,SAASxD,IAIdsH,MAAOA,EACPC,IAAKA,2CAUT,OAAQhH,KAAKmB,GAAGG,YAActB,KAAKqB,UAAYrB,KAAKgC,0CAUnD+E,EAAOC,GACR,GAAKhH,KAAK0B,OAAV,CAKA1B,KAAK0H,eAEL,IAAMK,EAAe/H,KAAKgI,OAAOjB,EAAOC,GAExCD,EAAQgB,EAAahB,MACrBC,EAAMe,EAAaf,IAEnBhH,KAAKuB,eAAiByF,EAEtBhH,KAAKkC,OAAO6E,MAAM,EAAGA,EAAOC,EAAMD,GAEb,aAAjB/G,KAAKmB,GAAGiB,OACRpC,KAAKmB,GAAG8G,QAAUjI,KAAKmB,GAAG8G,SAG9BjI,KAAKiD,SAASzD,GAEdQ,KAAKkB,UAAU,yCAOflB,KAAKuB,eAAiB,KAEtBvB,KAAKe,eAAiBf,KAAKgB,gBAC3BhB,KAAKkC,QAAUlC,KAAKkC,OAAO2F,KAAK,GAEhC7H,KAAKiD,SAASxD,GAEdO,KAAKkB,UAAU,kDAUf,OAAOlB,KAAKoC,MAAMtB,eAAerD,KAAKuC,gDAStC,OAAOA,KAAKgC,qDAQAzD,GACZA,EAAQA,GAAS,EACbyB,KAAKqH,WACLrH,KAAKgC,aAAezD,GAEpByB,KAAK2E,QACL3E,KAAKgC,aAAezD,EACpByB,KAAKkI,iBAlqBIvI,EAEV0E,iBAAmB,cAFT1E,gHCLjBzC,OAAOiL,uBACPjL,OAAOkL,6BACPlL,OAAOmL,0BACPnL,OAAOoL,wBACPpL,OAAOqL,yBACN,SAACvC,EAAUwC,GAAX,OAAuBC,WAAWzC,EAAU,IAAO,MACtDlH,KAAK5B,wWCHcoF,aAIjB,SAAAA,iGAAcvC,CAAAC,KAAAsC,GAMVtC,KAAK0I,SAAW,0CASjBC,EAAOC,GAAI,IAAA3I,EAAAD,KACLA,KAAK0I,WACN1I,KAAK0I,aAGT,IAAIA,EAAW1I,KAAK0I,SAASC,GAO7B,OANKD,IACDA,EAAW1I,KAAK0I,SAASC,OAE7BD,EAASG,KAAKD,IAIV/K,KAAM8K,EACN3C,SAAU4C,EACVE,GAAI,SAACC,EAAGH,GAAJ,OAAW3I,EAAK6I,GAAGC,EAAGH,gCAW/BD,EAAOC,GACN,GAAK5I,KAAK0I,SAAV,CAIA,IAAMA,EAAW1I,KAAK0I,SAASC,GAC3BrL,SACJ,GAAIoL,EACA,GAAIE,EACA,IAAKtL,EAAIoL,EAAS/E,OAAS,EAAGrG,GAAK,EAAGA,IAC9BoL,EAASpL,IAAMsL,GACfF,EAASM,OAAO1L,EAAG,QAI3BoL,EAAS/E,OAAS,mCAS1B3D,KAAK0I,SAAW,kCAWfC,EAAOM,GAAS,IAAAzE,EAAAxE,KASjB,OAAOA,KAAKkJ,GAAGP,EARJ,SAALC,IAAkB,QAAAnF,EAAAC,UAAAC,OAATwF,EAASvF,MAAAH,GAAAI,EAAA,EAAAA,EAAAJ,EAAAI,IAATsF,EAAStF,GAAAH,UAAAG,GAEpBoF,EAAQG,MAAM5E,EAAM2E,GAEpBV,WAAW,WACPjE,EAAKsE,GAAGH,EAAOC,IAChB,uCAWDD,GAAgB,QAAAU,EAAA3F,UAAAC,OAANwF,EAAMvF,MAAAyF,EAAA,EAAAA,EAAA,KAAAC,EAAA,EAAAA,EAAAD,EAAAC,IAANH,EAAMG,EAAA,GAAA5F,UAAA4F,GACtB,GAAKtJ,KAAK0I,SAAV,CAGA,IAAMA,EAAW1I,KAAK0I,SAASC,GAC/BD,GACIA,EAASrF,QAAQ,SAAAuF,GACbA,eAAMO,yBAzGD7G,kWCLAiH,aAIjB,SAAAA,iGAAcxJ,CAAAC,KAAAuJ,GACVvJ,KAAKwJ,oEAaLxJ,KAAKyJ,mBAMLzJ,KAAK0J,iBAAmB,8CAWR/F,EAAQoD,EAAOC,GAC3BrD,GAAU3D,KAAK0J,kBACf1J,KAAKwJ,iBACLxJ,KAAK0J,gBAAkB/F,GAO3B,IAHA,IAAIgG,KACArM,EAAI,EAGJA,EAAI0C,KAAKyJ,gBAAgB9F,QACzB3D,KAAKyJ,gBAAgBnM,GAAKyJ,GAE1BzJ,IASJ,IAHIA,EAAI,GAAK,GACTqM,EAAed,KAAK9B,GAGpBzJ,EAAI0C,KAAKyJ,gBAAgB9F,QACzB3D,KAAKyJ,gBAAgBnM,IAAM0J,GAE3B2C,EAAed,KAAK7I,KAAKyJ,gBAAgBnM,IACzCA,IAGAA,EAAI,GAAK,GACTqM,EAAed,KAAK7B,GAIxB2C,EAAiBA,EAAerG,OAAO,SAACsG,EAAMC,EAAKC,GAC/C,OAAW,GAAPD,EACOD,GAAQE,EAAID,EAAM,GAClBA,GAAOC,EAAInG,OAAS,EACpBiG,GAAQE,EAAID,EAAM,GAEtBD,GAAQE,EAAID,EAAM,IAAMD,GAAQE,EAAID,EAAM,KAMrD7J,KAAKyJ,gBAAkBzJ,KAAKyJ,gBAAgBM,OAAOJ,GACnD3J,KAAKyJ,gBAAkBzJ,KAAKyJ,gBACvBO,KAAK,SAACC,EAAGC,GAAJ,OAAUD,EAAIC,IACnB5G,OAAO,SAACsG,EAAMC,EAAKC,GAChB,OAAW,GAAPD,EACOD,GAAQE,EAAID,EAAM,GAClBA,GAAOC,EAAInG,OAAS,EACpBiG,GAAQE,EAAID,EAAM,GAEtBD,GAAQE,EAAID,EAAM,IAAMD,GAAQE,EAAID,EAAM,KAKzD,IAAMM,KACN,IAAK7M,EAAI,EAAGA,EAAIqM,EAAehG,OAAQrG,GAAK,EACxC6M,EAAmBtB,MAAMc,EAAerM,GAAIqM,EAAerM,EAAI,KAGnE,OAAO6M,2CASP,IAAMC,KACF9M,SACJ,IAAKA,EAAI,EAAGA,EAAI0C,KAAKyJ,gBAAgB9F,OAAQrG,GAAK,EAC9C8M,EAAoBvB,MAChB7I,KAAKyJ,gBAAgBnM,GACrB0C,KAAKyJ,gBAAgBnM,EAAI,KAGjC,OAAO8M,qBAvHMb,gWCLrBc,EAAAjN,EAAA,uLACAA,EAAA,QAKqBkN,cAMjB,SAAAA,EAAY1K,gGAAQG,CAAAC,KAAAsK,GAAA,IAAArK,mKAAAC,CAAAF,MAAAsK,EAAAnK,WAAAnC,OAAAoC,eAAAkK,IAAA7M,KAAAuC,KACVJ,IADU,OAGhBK,EAAKL,OAASA,EAIdK,EAAKsK,OACDjJ,YAAa,EACbV,SAAU,EACV4J,QAAQ,EACRxI,aAAc,EACdkG,KALS,aAMTvD,MANS,aAOT8F,OAAQ,GAIZxK,EAAKyK,UAAY9K,EAAO8K,UAAUC,cAElC1K,EAAK2K,gBAAkBhL,EAAOgL,gBAE9B3K,EAAK8B,MAAQ,KAEb9B,EAAK+B,aAAe,EAEpB/B,EAAKwK,OAAS,EAEdxK,EAAKyB,OAAS,KAEdzB,EAAK4K,UAAY,KA9BD5K,qUANkBN,6CA2ClCK,KAAKkD,gBAAgBlD,KAAKJ,OAAOuD,WACjCnD,KAAK8K,oDAQK,IAAAtG,EAAAxE,KAcVA,KAAKkJ,GAAG,OAbe,SAAjB6B,IACEvG,EAAK6C,aAGT7C,EAAKtD,UAAU,eAAgBsD,EAAK1D,mBAIhC5D,OAAOiL,uBACPjL,OAAOkL,6BACW2C,MAM1B/K,KAAKkJ,GAAG,QAAS,WACb1E,EAAKtD,UAAU,eAAgBsD,EAAK1D,iDAavCkK,EAAKC,EAAWlJ,EAAOmJ,GACxB,IAAMX,EAAQY,SAASC,cAAcpL,KAAK0K,WAC1CH,EAAMc,SAAWrL,KAAKJ,OAAO0L,cAC7Bf,EAAMjF,SAAWtF,KAAKJ,OAAO0F,WAAY,EACzCiF,EAAMW,QAAqB,MAAXA,EAAkB,OAASA,EAC3CX,EAAM9E,IAAMuF,EACZT,EAAMgB,MAAMC,MAAQ,OAEpB,IAAMC,EAAYR,EAAUS,cAAc1L,KAAK0K,WAC3Ce,GACAR,EAAUU,YAAYF,GAE1BR,EAAUW,YAAYrB,GAEtBvK,KAAK6L,MAAMtB,EAAOxI,mCASd+J,EAAK/J,GACT+J,EAAIT,SAAWrL,KAAKJ,OAAO0L,cAC3BQ,EAAIxG,SAAWtF,KAAKJ,OAAO0F,WAAY,EAEvCtF,KAAK6L,MAAMC,EAAK/J,iCAWdwI,EAAOxI,GAAO,IAAAgK,EAAA/L,KAGS,mBAAduK,EAAMyB,MAIbzB,EAAMyB,OAGVzB,EAAM0B,iBAAiB,QAAS,WAC5BF,EAAK7K,UAAU,QAAS,iCAG5BqJ,EAAM0B,iBAAiB,UAAW,WAC9BF,EAAK7K,UAAU,aAGnBqJ,EAAM0B,iBAAiB,QAAS,WAC5BF,EAAK7K,UAAU,YAKnBqJ,EAAM0B,iBAAiB,OAAQ,WAC3BF,EAAK7K,UAAU,UAGnBqJ,EAAM0B,iBAAiB,QAAS,WAC5BF,EAAK7K,UAAU,WAGnBlB,KAAKuK,MAAQA,EACbvK,KAAK+B,MAAQA,EACb/B,KAAK6K,UAAY,KACjB7K,KAAK0B,OAAS,KACd1B,KAAKkD,gBAAgBlD,KAAKgC,cAC1BhC,KAAKkM,UAAUlM,KAAKyK,2CASpB,OAAQzK,KAAKuK,OAASvK,KAAKuK,MAAMC,6CASjC,GAAIxK,KAAKqC,iBACL,OAAOrC,KAAKqC,iBAEhB,IAAIzB,GAAYZ,KAAK0B,QAAU1B,KAAKuK,OAAO3J,SAK3C,OAJIA,GAAYuL,MAEZvL,EAAWZ,KAAKuK,MAAM6B,SAASpF,IAAI,IAEhCpG,2CAUP,OAAOZ,KAAKuK,OAASvK,KAAKuK,MAAMjJ,wDAShC,OAAOtB,KAAKc,iBAAmBd,KAAKa,eAAiB,4CASrD,OAAOb,KAAKgC,cAAgBhC,KAAKuK,MAAMvI,qDAQ3BzD,GACZyB,KAAKgC,aAAezD,GAAS,EAC7ByB,KAAKuK,MAAMvI,aAAehC,KAAKgC,4CAQ5B+E,GACU,MAATA,IACA/G,KAAKuK,MAAMjJ,YAAcyF,GAE7B/G,KAAKqM,4CAYJtF,EAAOC,GACRhH,KAAKgI,OAAOjB,GACZ,IAAMuF,EAAUtM,KAAKuK,MAAMrC,OAG3B,OAFAlB,GAAOhH,KAAKuM,WAAWvF,GAEhBsF,kCAUP,IAAIA,SAOJ,OALItM,KAAKuK,QACL+B,EAAUtM,KAAKuK,MAAM5F,SAEzB3E,KAAKqM,eAEEC,qCAIAtF,GAAK,IAAAwF,EAAAxM,KACZA,KAAKyM,WAAa,SAAA/H,GACVA,GAAQsC,IACRwF,EAAK7H,QACL6H,EAAKxE,OAAOhB,KAGpBhH,KAAKkJ,GAAG,eAAgBlJ,KAAKyM,mDAKzBzM,KAAKyM,aACLzM,KAAK8I,GAAG,eAAgB9I,KAAKyM,YAC7BzM,KAAKyM,WAAa,uCAcjB9I,EAAQ4C,EAAOC,GACpB,OAAIxG,KAAK0B,gQACLgL,CAAApC,EAAApL,UAAAiB,WAAAnC,OAAAoC,eAAAkK,EAAApL,WAAA,WAAAc,MAAAvC,KAAAuC,KAAsB2D,EAAQ4C,EAAOC,GAElCxG,KAAK+B,4CAQNgD,GACN,OAAIA,EACK/E,KAAKuK,MAAMrF,UAKTlF,KAAKuK,MAAMrF,UAAUH,GAJjBI,QAAQC,OACX,IAAIC,MAAM,+CAMfF,QAAQC,OAAO,IAAIC,MAAM,qBAAuBN,wCASvD,OAAO/E,KAAKyK,QAAUzK,KAAKuK,MAAME,yCAQ3BlM,GACNyB,KAAKyK,OAASlM,EACdyB,KAAKuK,MAAME,OAASzK,KAAKyK,yCAQzBzK,KAAK2E,QACL3E,KAAKsH,QAGDtH,KAAKJ,OAAO+M,6BACZ3M,KAAKuK,OACLvK,KAAKuK,MAAMqC,YAEX5M,KAAKuK,MAAMqC,WAAWjB,YAAY3L,KAAKuK,OAG3CvK,KAAKuK,MAAQ,wBAxWAD,8VCNT/K,0JAAZnC,EAAA,QAMqByP,cAKjB,SAAAA,EAAY5B,EAAWrL,gGAAQG,CAAAC,KAAA6M,GAAA,IAAA5M,mKAAAC,CAAAF,MAAA6M,EAAA1M,WAAAnC,OAAAoC,eAAAyM,IAAApP,KAAAuC,OAAA,OAG3BC,EAAKgL,UAAYA,EAKjBhL,EAAKL,OAASA,EAKdK,EAAKuL,MAAQ,EAKbvL,EAAK6M,OAASlN,EAAOkN,OAAS7M,EAAKL,OAAOmN,WAE1C9M,EAAK+M,QAAU,EAKf/M,EAAKgN,QAAU,KAzBYhN,qUALCV,EAAK+C,2CAwC/B4K,EAAIC,GACN,OAAO5N,EAAKgM,MAAM2B,EAAIC,2CAQtBnN,KAAKiN,QAAUjN,KAAKiL,UAAUW,YAC1BT,SAASC,cAAc,SAG3BpL,KAAKuL,MAAMvL,KAAKiN,SACZG,QAAS,QACTC,SAAU,WACVC,WAAY,OACZC,iBAAkB,OAClBT,OAAQ9M,KAAKJ,OAAOkN,OAAS,QAG7B9M,KAAKJ,OAAO4N,YAAcxN,KAAKJ,OAAO6N,eACtCzN,KAAKuL,MAAMvL,KAAKiN,SACZzB,MAAO,OACPkC,UAAW1N,KAAKJ,OAAO+N,cAAgB,SAAW,OAClDC,UAAW,WAInB5N,KAAK6N,yDAUG9E,EAAG+E,IACVA,GAAa/E,EAAEgF,iBAEhB,IAAMC,EAAUjF,EAAEkF,cACZlF,EAAEkF,cAAc,GAAGD,QACnBjF,EAAEiF,QACFE,EAAOlO,KAAKiN,QAAQkB,wBAEpBC,EAAepO,KAAKwL,MACpB6C,EAAcrO,KAAKsO,WAErBC,SAgBJ,OAdKvO,KAAKJ,OAAO4N,YAAcY,EAAeC,GAC1CE,GACKP,EAAUE,EAAKM,OACXxO,KAAKJ,OAAOmN,WAAaqB,IAAiB,GAEpC,IACXG,EAAW,GAGfA,GACKP,EAAUE,EAAKM,KAAOxO,KAAKiN,QAAQwB,YAChCzO,KAAKiN,QAAQyB,aAAe,EAGjCH,+CAMU,IAAA/J,EAAAxE,KACjBA,KAAKiN,QAAQhB,iBAAiB,QAAS,SAAAlD,GACnC,IAAM4F,EACFnK,EAAKyI,QAAQ2B,aAAepK,EAAKyI,QAAQ4B,aAC7C,GAAuB,GAAnBF,EAAsB,CAEtB,IAAMT,EAAO1J,EAAKyI,QAAQkB,wBAC1B,GAAIpF,EAAE+F,SAAWZ,EAAKa,OAASJ,EAE3B,OAIJnK,EAAK5E,OAAOoP,UACZxK,EAAKtD,UAAU,QAAS6H,EAAGvE,EAAKyK,YAAYlG,MAIpD/I,KAAKiN,QAAQhB,iBAAiB,SAAU,SAAAlD,GAAA,OACpCvE,EAAKtD,UAAU,SAAU6H,uCAevBhH,EAAO4B,EAAQoD,EAAOC,GACvBhH,KAAKkP,SAASvL,IACf3D,KAAKmP,YAGTnP,KAAKJ,OAAOwP,SACNpP,KAAKqP,SAAStN,EAAO,EAAGgF,EAAOC,GAC/BhH,KAAKsP,SAASvN,EAAO,EAAGgF,EAAOC,yCAOhB,OAAjBhH,KAAKiN,UACLjN,KAAKiN,QAAQwB,WAAa,oCASzBc,GACL,IAAMlC,EAAWrN,KAAKiN,QAAQyB,YAAca,EAC5CvP,KAAKwP,mBAAmBnC,GAAU,8CAUnBA,EAAUoC,GACzB,IAAMhB,EAAazO,KAAKiN,QAAQwB,WAC1BiB,KAAU1P,KAAKiN,QAAQ0C,YAAc,GACrCC,EAAY5P,KAAKiN,QAAQyB,YAAc1O,KAAKiN,QAAQ0C,YACtDE,EAASxC,EAAWqC,EACpBI,EAASD,EAASpB,EAEtB,GAAiB,GAAbmB,EAAJ,CAMA,IAAKH,IAAcC,GAAQI,GAAUA,EAASJ,EAAM,CAIhDG,EAASpB,GADTqB,EAASC,KAAK7I,KADD,EACY6I,KAAK9I,IADjB,EAC2B6I,MAK5CD,EAASE,KAAK7I,IAAI,EAAG6I,KAAK9I,IAAI2I,EAAWC,MAE3BpB,IACVzO,KAAKiN,QAAQwB,WAAaoB,yCAU9B,IAAM9C,EAAa/M,KAAKJ,OAAOmN,WAC3BiD,EAAID,KAAKE,MAAMjQ,KAAKiN,QAAQwB,WAAa1B,GAO7C,GAAI/M,KAAKJ,OAAO6N,aAAc,CAC1B,IAAMmC,KACF5P,KAAKiN,QAAQyB,YAAc3B,EAC3B/M,KAAKsO,YAET0B,EAAID,KAAK9I,IAAI2I,EAAWG,KAAK7I,IAAI,EAAG8I,IAGxC,OAAOA,qCASP,OAAOD,KAAKE,MAAMjQ,KAAKiL,UAAU0E,YAAc3P,KAAKJ,OAAOmN,6CAQtDvB,GACL,OAAIxL,KAAKwL,OAASA,IAIlBxL,KAAKwL,MAAQA,EAETxL,KAAKJ,OAAO4N,YAAcxN,KAAKJ,OAAO6N,aACtCzN,KAAKuL,MAAMvL,KAAKiN,SACZzB,MAAO,KAGXxL,KAAKuL,MAAMvL,KAAKiN,SACZzB,SAAUxL,KAAKwL,MAAQxL,KAAKJ,OAAOmN,YAAc,OAIzD/M,KAAKkQ,cACE,qCAQDpD,GACN,OAAIA,GAAU9M,KAAK8M,SAGnB9M,KAAK8M,OAASA,EAEd9M,KAAKuL,MAAMvL,KAAKiN,SACZH,UAAW9M,KAAK8M,OAAS9M,KAAKJ,OAAOmN,YAAc,OAGvD/M,KAAKkQ,cACE,oCAQF3B,GACL,IAAM4B,EAAa,EAAInQ,KAAKJ,OAAOmN,WAC7BlD,EAAMkG,KAAKE,MAAM1B,EAAWvO,KAAKwL,OAAS2E,EAEhD,GAAItG,EAAM7J,KAAKgN,SAAWnD,EAAM7J,KAAKgN,SAAWmD,EAAY,CAGxD,GAFAnQ,KAAKgN,QAAUnD,EAEX7J,KAAKJ,OAAO6N,cAAgBzN,KAAKJ,OAAOwQ,WAAY,CACpD,IAAMC,KAAYrQ,KAAKiN,QAAQyB,YAAcH,GAC7CvO,KAAKwP,mBAAmBa,GAG5BrQ,KAAKsQ,eAAezG,sCAQxB7J,KAAKsH,QACDtH,KAAKiN,UACDjN,KAAKiN,QAAQL,YAAc5M,KAAKiL,WAChCjL,KAAKiL,UAAUU,YAAY3L,KAAKiN,SAEpCjN,KAAKiN,QAAU,qHAiCdlL,EAAOwO,EAAcxJ,EAAOC,qCAe5BjF,EAAOwO,EAAcxJ,EAAOC,gFAetBqG,uBA9XER,gWCNrB2D,EAAApT,EAAA,uCACYmC,0JAAZnC,EAAA,QAkBqBqT,cAKjB,SAAAA,EAAYxF,EAAWrL,gGAAQG,CAAAC,KAAAyQ,GAAA,IAAAxQ,mKAAAC,CAAAF,MAAAyQ,EAAAtQ,WAAAnC,OAAAoC,eAAAqQ,IAAAhT,KAAAuC,KACrBiL,EAAWrL,IADU,OAM3BK,EAAKyQ,eAAiB9Q,EAAO8Q,eAK7BzQ,EAAK0Q,sBAAwBZ,KAAKE,MAC9BrQ,EAAO8Q,eAAiB9Q,EAAOmN,YAQnC9M,EAAK2Q,kBAAoBhR,EAAOiR,WAAajR,EAAOkR,cAKpD7Q,EAAK8Q,UAAY,GAAMnR,EAAOmN,WAK9B9M,EAAK+Q,YAEL/Q,EAAKgR,aAAe,KAhCOhR,qUALM4M,6CA4CjC7M,KAAKkR,gBACLlR,KAAKmR,0DASLnR,KAAKiR,aAAejR,KAAKiN,QAAQrB,YAC7B5L,KAAKuL,MAAMJ,SAASC,cAAc,SAC9BiC,SAAU,WACV+D,OAAQ,EACR5C,KAAM,EACN6C,IAAK,EACLtC,OAAQ,EACRuC,SAAU,SACV9F,MAAO,IACP4B,QAAS,OACTmE,UAAW,aACXC,iBAAkB,QAClBC,cAAe,UAIvBzR,KAAK0R,YACL1R,KAAK2R,sDAOL3R,KAAKuL,MAAMvL,KAAKiR,cACZW,iBAAkB5R,KAAKJ,OAAOiS,YAAc,KAC5CC,iBAAkB9R,KAAKJ,OAAOmS,mDAalC,IANS,IAAAvN,EAAAxE,KACHgS,EAAajC,KAAKE,MAAMjQ,KAAKwL,MAAQxL,KAAKJ,OAAOmN,YACjDkF,EAAmBlC,KAAKmC,KAC1BF,EAAahS,KAAK2Q,uBAGf3Q,KAAKgR,SAASrN,OAASsO,GAC1BjS,KAAK0R,YAGT,KAAO1R,KAAKgR,SAASrN,OAASsO,GAC1BjS,KAAKmS,eAGTnS,KAAKgR,SAAS3N,QAAQ,SAAC+O,EAAO9U,GAE1B,IAAI+U,EACA7N,EAAKkM,eAAiB,EAAIX,KAAKmC,KAAK1N,EAAK5E,OAAOmN,WAAa,GAE7DzP,GAAKkH,EAAKwM,SAASrN,OAAS,IAC5B0O,EACI7N,EAAKgH,MACLhH,EAAKkM,gBAAkBlM,EAAKwM,SAASrN,OAAS,IAGtDa,EAAK8N,iBAAiBF,EAAOC,EAAa7N,EAAKsI,QAC/CtI,EAAK+N,kBAAkBH,yCAU3B,IAAMA,KACAI,EAAaxS,KAAK2Q,sBAAwB3Q,KAAKgR,SAASrN,OAE9DyO,EAAMK,KAAOzS,KAAKiN,QAAQrB,YACtB5L,KAAKuL,MAAMJ,SAASC,cAAc,WAC9BiC,SAAU,WACV+D,OAAQ,EACR5C,KAAMgE,EAAa,KACnBnB,IAAK,EACLtC,OAAQ,EACRjC,OAAQ,OACR2E,cAAe,UAGvBW,EAAMM,QAAUN,EAAMK,KAAKE,WAAW,MAElC3S,KAAK4Q,oBACLwB,EAAM7D,SAAWvO,KAAKiR,aAAarF,YAC/B5L,KAAKuL,MAAMJ,SAASC,cAAc,WAC9BiC,SAAU,WACVmB,KAAMgE,EAAa,KACnBnB,IAAK,EACLtC,OAAQ,EACRjC,OAAQ,UAGhBsF,EAAMQ,YAAcR,EAAM7D,SAASoE,WAAW,OAGlD3S,KAAKgR,SAASnI,KAAKuJ,0CASnB,IAAMS,EAAY7S,KAAKgR,SAAS8B,MAChCD,EAAUJ,KAAKM,cAAcpH,YAAYkH,EAAUJ,MAC/CzS,KAAK4Q,mBACLiC,EAAUtE,SAASwE,cAAcpH,YAAYkH,EAAUtE,mDAY9C6D,EAAO5G,EAAOsB,GAC3B,IAAMkG,EAAejD,KAAKE,MAAMzE,EAAQxL,KAAKJ,OAAOmN,YAC9CiF,EAAajC,KAAKE,MAAMjQ,KAAKwL,MAAQxL,KAAKJ,OAAOmN,YAGvDqF,EAAMrL,MAAQqL,EAAMM,QAAQO,OAAOC,WAAalB,GAAc,EAC9DI,EAAMpL,IAAMoL,EAAMrL,MAAQiM,EAAehB,EAEzCI,EAAMM,QAAQO,OAAOzH,MAAQA,EAC7B4G,EAAMM,QAAQO,OAAOnG,OAASA,EAC9B9M,KAAKuL,MAAM6G,EAAMM,QAAQO,QAAUzH,MAAOwH,EAAe,OAEzDhT,KAAKuL,MAAMvL,KAAKiR,cAAgB7D,QAAS,UAErCpN,KAAK4Q,oBACLwB,EAAMQ,YAAYK,OAAOzH,MAAQA,EACjC4G,EAAMQ,YAAYK,OAAOnG,OAASA,EAClC9M,KAAKuL,MAAM6G,EAAMQ,YAAYK,QACzBzH,MAAOwH,EAAe,4CAQtB,IAAAjH,EAAA/L,KACRA,KAAKgR,SAAS3N,QAAQ,SAAA+O,GAAA,OAASrG,EAAKwG,kBAAkBH,+CASxCA,GACdA,EAAMM,QAAQS,UACV,EACA,EACAf,EAAMM,QAAQO,OAAOzH,MACrB4G,EAAMM,QAAQO,OAAOnG,QAErB9M,KAAK4Q,mBACLwB,EAAMQ,YAAYO,UACd,EACA,EACAf,EAAMQ,YAAYK,OAAOzH,MACzB4G,EAAMQ,YAAYK,OAAOnG,yCAiB5B/K,EAAOwO,EAAcxJ,EAAOC,GAAK,IAAAwF,EAAAxM,KACtC,OAAOA,KAAKoT,YACRrR,EACAwO,EACAxJ,EACAC,EACA,SAAAqM,GAA2D,IAAxDC,EAAwDD,EAAxDC,OAAQC,EAAgDF,EAAhDE,WAAoBC,GAA4BH,EAApCvG,OAAoCuG,EAA5BG,SAASC,EAAmBJ,EAAnBI,MAAO1R,EAAYsR,EAAZtR,MAG3C,QAAc2R,IAAV3M,EAAJ,CAIA,IAAM4M,EAAiBJ,EAAa,EAAI,EAClC5P,EAAS5B,EAAM4B,OAASgQ,EACxBC,EAAMpH,EAAK5M,OAAOwP,SAAW5C,EAAK5M,OAAOmN,WAQzC8G,EAAOD,GANc,OAAvBpH,EAAK5M,OAAOkU,OACN/D,KAAK7I,IAAIsF,EAAK5M,OAAOmN,cAAe6G,EAAM,IAC1C7D,KAAK7I,IACDsF,EAAK5M,OAAOmN,WACZP,EAAK5M,OAAOkU,OAAStH,EAAK5M,OAAOmN,aAIzCgH,EAAQpQ,EAAS6I,EAAKhB,MAEtBhF,EAAOQ,EACT1J,SAEJ,IAAKA,EAJSyJ,EAIEzJ,EAAIkJ,EAAMlJ,GAAKuW,EAAM,CACjC,IAAMG,EACFjS,EAAMgO,KAAKkE,MAAM3W,EAAIyW,EAAQJ,KAAoB,EAC/CO,EAAInE,KAAKE,MAAO+D,EAAOV,EAAUG,GACvCjH,EAAK2H,SACD7W,EAAIkP,EAAKuE,UACT0C,EAAQS,EAAIV,EACZI,EAAMpH,EAAKuE,UACP,EAAJmD,wCAmBXnS,EAAOwO,EAAcxJ,EAAOC,GAAK,IAAAoN,EAAApU,KACtC,OAAOA,KAAKoT,YACRrR,EACAwO,EACAxJ,EACAC,EACA,SAAAqN,GAA2D,IAAxDf,EAAwDe,EAAxDf,OAAQC,EAAgDc,EAAhDd,WAAoBC,GAA4Ba,EAApCvH,OAAoCuH,EAA5Bb,SAASC,EAAmBY,EAAnBZ,MAAO1R,EAAYsS,EAAZtS,MAC3C,IAAKwR,EAAY,CACb,IAAMe,KACAC,EAAMxS,EAAM4B,OACdrG,SACJ,IAAKA,EAAI,EAAGA,EAAIiX,EAAKjX,IACjBgX,EAAe,EAAIhX,GAAKyE,EAAMzE,GAC9BgX,EAAe,EAAIhX,EAAI,IAAMyE,EAAMzE,GAEvCyE,EAAQuS,OAKEZ,IAAV3M,GACAqN,EAAKI,SAASzS,EAAOuR,EAAQG,EAAOD,EAASzM,EAAOC,GAIxDoN,EAAKD,SACD,EACAV,EAAQD,EAAUY,EAAKrD,UACvBqD,EAAK5I,MACL4I,EAAKrD,8CAmBZhP,EAAOuR,EAAQG,EAAOD,EAASzM,EAAOC,GAAK,IAAAyN,EAAAzU,KAChDA,KAAKgR,SAAS3N,QAAQ,SAAA+O,GAClBqC,EAAKC,cAActC,GACnBqC,EAAKE,kBACDvC,EACAA,EAAMM,QACN3Q,EACAuR,EACAG,EACAD,EACAzM,EACAC,GAEJyN,EAAKE,kBACDvC,EACAA,EAAMQ,YACN7Q,EACAuR,EACAG,EACAD,EACAzM,EACAC,+CAoBMoL,EAAOwC,EAAK7S,EAAOuR,EAAQG,EAAOD,EAASzM,EAAOC,GAChE,GAAK4N,EAAL,CAIA,IAAMjR,EAAS5B,EAAM4B,OAAS,EACxBoQ,EACF/T,KAAKJ,OAAO4N,YAAcxN,KAAKwL,OAAS7H,EAClC3D,KAAKwL,MAAQ7H,EACb,EAEJ4C,EAAQwJ,KAAKE,MAAMtM,EAASyO,EAAMrL,OAGlCP,EAAOuJ,KAAKE,MAAMtM,EAASyO,EAAMpL,KAAO,EAC9C,KAAIT,EAAQS,GAAOR,EAAOO,GAA1B,CAGA,IAAM8N,EAAc9E,KAAK9I,IAAIV,EAAOQ,GAC9B+N,EAAY/E,KAAK7I,IAAIV,EAAMQ,GAC7B1J,SACA6J,SAQJ,IANAyN,EAAIG,YACJH,EAAII,QACCH,EAActO,GAASwN,EAAQ/T,KAAK+Q,UACrC0C,EAAQD,GAGPlW,EAAIuX,EAAavX,EAAIwX,EAAWxX,IAAK,CACtC,IAAM0W,EAAOjS,EAAM,EAAIzE,IAAM,EACvB4W,EAAInE,KAAKE,MAAO+D,EAAOV,EAAUG,GACvCmB,EAAIK,QACC3X,EAAIiJ,GAASwN,EAAQ/T,KAAK+Q,UAC3B0C,EAAQS,EAAIV,GAMpB,IAAKrM,EAAI2N,EAAY,EAAG3N,GAAK0N,EAAa1N,IAAK,CAC3C,IAAM6M,EAAOjS,EAAM,EAAIoF,EAAI,IAAM,EAC3B+M,EAAInE,KAAKE,MAAO+D,EAAOV,EAAUG,GACvCmB,EAAIK,QACC9N,EAAIZ,GAASwN,EAAQ/T,KAAK+Q,UAC3B0C,EAAQS,EAAIV,GAIpBoB,EAAIM,YACJN,EAAIO,0CAWCnF,EAAGoF,EAAG5J,EAAOsB,GAClB,IAAMuI,EAActF,KAAKkE,MAAMjE,EAAIhQ,KAAK0Q,gBAClC4E,EAAYvF,KAAK9I,IACnB8I,KAAKmC,MAAMlC,EAAIxE,GAASxL,KAAK0Q,gBAAkB,EAC/C1Q,KAAKgR,SAASrN,QAEdrG,SACJ,IAAKA,EAAI+X,EAAa/X,EAAIgY,EAAWhY,IAAK,CACtC,IAAM8U,EAAQpS,KAAKgR,SAAS1T,GACtBkV,EAAalV,EAAI0C,KAAK0Q,eAEtB6E,GACFC,GAAIzF,KAAK7I,IAAI8I,EAAG1S,EAAI0C,KAAK0Q,gBACzB+E,GAAIL,EACJM,GAAI3F,KAAK9I,IACL+I,EAAIxE,EACJlO,EAAI0C,KAAK0Q,eAAiB0B,EAAMM,QAAQO,OAAOzH,OAEnDmK,GAAIP,EAAItI,GAGRyI,EAAaC,GAAKD,EAAaG,KAC/B1V,KAAK0U,cAActC,GAEnBpS,KAAK4V,kBACDxD,EAAMM,QACN6C,EAAaC,GAAKhD,EAClB+C,EAAaE,GACbF,EAAaG,GAAKH,EAAaC,GAC/BD,EAAaI,GAAKJ,EAAaE,IAGnCzV,KAAK4V,kBACDxD,EAAMQ,YACN2C,EAAaC,GAAKhD,EAClB+C,EAAaE,GACbF,EAAaG,GAAKH,EAAaC,GAC/BD,EAAaI,GAAKJ,EAAaE,0CAoBnC1T,EAAOwO,EAAcxJ,EAAOC,EAAK4B,GAAI,IAAAiN,EAAA7V,KAC7C,OAAOT,EAAKuW,MAAM,WAEd,GAAI/T,EAAM,aAAc6B,MAAO,CAC3B,IAAMyC,EAAWtE,EACjB,GAAI8T,EAAKjW,OAAOwH,cAMZ,OALAyO,EAAKE,UACD1P,EAAS1C,OACLkS,EAAKjW,OAAOkN,OACZ+I,EAAKjW,OAAOmN,YAEb1G,EAAShD,QAAQ,SAAC2S,EAAc1Y,GAAf,OACpBuY,EAAKzC,YAAY4C,EAAc1Y,EAAGyJ,EAAOC,EAAK4B,KAGtD7G,EAAQsE,EAAS,GAKrB,IAAIiN,EAAS,EAAIuC,EAAKjW,OAAOqW,UAC7B,GAAIJ,EAAKjW,OAAOsW,UAAW,CACvB,IAAMhP,EAAM3H,EAAK2H,IAAInF,GACfkF,EAAM1H,EAAK0H,IAAIlF,GACrBuR,GAAUrM,EAAMC,GAAOD,EAAMC,EAKjC,IAAMqM,KAAgB4C,KAAK1Y,KAAKsE,EAAO,SAAAqU,GAAA,OAAOA,EAAM,IAC9CtJ,EAAS+I,EAAKjW,OAAOkN,OAAS+I,EAAKjW,OAAOmN,WAIhD,OAAOnE,GACH0K,OAAQA,EACRC,WAAYA,EACZzG,OAAQA,EACR0G,QAPY1G,EAASyD,GAAgB,EAQrCkD,MAPU3G,EAAS,EAQnB/K,MAAOA,KAvCRxC,6CAsDOqV,EAAK5E,EAAGoF,EAAG5J,EAAOsB,GAC3B8H,GAGLA,EAAIT,SAASnE,EAAGoF,EAAG5J,EAAOsB,yCAShBsF,GACVA,EAAMM,QAAQ2D,UAAYrW,KAAKJ,OAAOiR,UAClC7Q,KAAK4Q,oBACLwB,EAAMQ,YAAYyD,UAAYrW,KAAKJ,OAAOkR,gDAWzCwF,EAAMC,GACX,IAAMC,EAASxW,KAAKgR,SAASyF,IAAI,SAAArE,GAAA,OAC7BA,EAAMK,KAAKiE,UAAUJ,EAAMC,KAE/B,OAAOC,EAAO7S,OAAS,EAAI6S,EAASA,EAAO,0CAQhCnJ,GACXrN,KAAKuL,MAAMvL,KAAKiR,cAAgBzF,MAAO6B,EAAW,0BAxlBrCoD,oDCnBrB,SAASkG,EAAoB5N,GACzBA,EAAE6N,kBACFzL,SAAS0L,KAAKC,oBAAoB,QAASH,GAAqB,8DAGrD,SAAsBI,GACjC5L,SAAS0L,KAAK5K,iBAAiB,QAAS0K,GAAqB,uCCSjE5Z,EAAAD,QAAA,SAAAka,EAAAC,EAAAxH,GACA,IAAAyH,EAAA/N,EAAAgO,EAAAC,EAAAC,EAGA,SAAAC,IACA,IAAA9Q,EAAA+Q,KAAAC,MAAAJ,EAEA5Q,EAAAyQ,GAAAzQ,GAAA,EACA0Q,EAAAzO,WAAA6O,EAAAL,EAAAzQ,IAEA0Q,EAAA,KACAzH,IACA4H,EAAAL,EAAA5N,MAAA+N,EAAAhO,GACAgO,EAAAhO,EAAA,OAXA,MAAA8N,MAAA,KAgBA,IAAAQ,EAAA,WACAN,EAAAnX,KACAmJ,EAAAzF,UACA0T,EAAAG,KAAAC,MACA,IAAAE,EAAAjI,IAAAyH,EAOA,OANAA,MAAAzO,WAAA6O,EAAAL,IACAS,IACAL,EAAAL,EAAA5N,MAAA+N,EAAAhO,GACAgO,EAAAhO,EAAA,MAGAkO,GAoBA,OAjBAI,EAAAE,MAAA,WACAT,IACAU,aAAAV,GACAA,EAAA,OAIAO,EAAAI,MAAA,WACAX,IACAG,EAAAL,EAAA5N,MAAA+N,EAAAhO,GACAgO,EAAAhO,EAAA,KAEAyO,aAAAV,GACAA,EAAA,OAIAO,4FCtDe,SAAeT,GAC1B,OAAO,mBAAAvT,EAAAC,UAAAC,OAAIwF,EAAJvF,MAAAH,GAAAI,EAAA,EAAAA,EAAAJ,EAAAI,IAAIsF,EAAJtF,GAAAH,UAAAG,GAAA,OAAa,EAAAiU,EAAAxY,SAAkB,kBAAM0X,eAAQ7N,OAXxD,MAAA4O,EAAA3a,EAAA,oJCQe,SAAe8P,EAAIC,GAM9B,OALAnP,OAAOga,KAAK7K,GAAQ9J,QAAQ,SAAA4U,GACpB/K,EAAG3B,MAAM0M,KAAU9K,EAAO8K,KAC1B/K,EAAG3B,MAAM0M,GAAQ9K,EAAO8K,MAGzB/K,gHCNI,SAAgB3H,GAAkB,QAAA9B,EAAAC,UAAAC,OAATuU,EAAStU,MAAAH,EAAA,EAAAA,EAAA,KAAAI,EAAA,EAAAA,EAAAJ,EAAAI,IAATqU,EAASrU,EAAA,GAAAH,UAAAG,GAM7C,OALAqU,EAAQ7U,QAAQ,SAAAnB,GACZlE,OAAOga,KAAK9V,GAAQmB,QAAQ,SAAAxE,GACxB0G,EAAK1G,GAAOqD,EAAOrD,OAGpB0G,gHCRI,SAAawR,GACxB,IAAIoB,EAAWC,OAAOjM,KAMtB,OALAnO,OAAOga,KAAKjB,GAAQ1T,QAAQ,SAAA/F,GACpByZ,EAAOzZ,GAAK6a,IACZA,EAAWpB,EAAOzZ,MAGnB6a,gHCPI,SAAapB,GACxB,IAAIsB,GAAWlM,IAMf,OALAnO,OAAOga,KAAKjB,GAAQ1T,QAAQ,SAAA/F,GACpByZ,EAAOzZ,GAAK+a,IACZA,EAAUtB,EAAOzZ,MAGlB+a,gHCRI,WACX,MACI,cACAtI,KAAKuI,SACAC,SAAS,IACTC,UAAU,iHCDR,SAAcC,GACzB,IAAMC,EAAW,IAAIpW,UACfqW,EAAM,IAAIC,eACZC,GAAW,EACfF,EAAIG,KAAKL,EAAQM,QAAU,MAAON,EAAQzN,KAAK,GAC/C2N,EAAIK,aAAeP,EAAQO,cAAgB,OAEvCP,EAAQE,MACJF,EAAQE,IAAIM,gBAEZR,EAAQE,IAAIM,eAAe5V,QAAQ,SAAA6V,GAC/BP,EAAIQ,iBAAiBD,EAAOra,IAAKqa,EAAO3a,SAG5Cka,EAAQE,IAAIS,kBAEZT,EAAIS,iBAAkB,IAwB9B,OApBAT,EAAI1M,iBAAiB,WAAY,SAAAlD,GAC7B2P,EAASxX,UAAU,WAAY6H,GAC3BA,EAAEsQ,kBAAoBtQ,EAAEuQ,QAAUvQ,EAAEwQ,QACpCV,GAAW,KAGnBF,EAAI1M,iBAAiB,OAAQ,SAAAlD,GACpB8P,GACDH,EAASxX,UAAU,WAAY6H,GAEnC2P,EAASxX,UAAU,OAAQ6H,GACvB,KAAO4P,EAAIa,QAAU,KAAOb,EAAIa,OAChCd,EAASxX,UAAU,UAAWyX,EAAIc,SAAU1Q,GAE5C2P,EAASxX,UAAU,QAAS6H,KAGpC4P,EAAI1M,iBAAiB,QAAS,SAAAlD,GAAA,OAAK2P,EAASxX,UAAU,QAAS6H,KAC/D4P,EAAIe,OACJhB,EAASC,IAAMA,EACRD,GAjDX,MAAAiB,EAAAvc,EAAA,mYCAYmC,0JAAZnC,EAAA,QACAA,EAAA,QACAA,EAAA,QACAA,EAAA,QACAA,EAAA,oUAsII,SAAAwc,EAAYC,EAAIja,GAAQG,EAAAC,KAAA4Z,qCAPjBha,yFA6CUka,cAuFjB,SAAAA,EAAYla,GAAQG,EAAAC,KAAA8Z,GAAA,IAAA7Z,EAAAC,EAAAF,MAAA8Z,EAAA3Z,WAAAnC,OAAAoC,eAAA0Z,IAAArc,KAAAuC,OAchB,GAdgBC,EArFpB8Z,eACI1Z,aAAc,KACd8C,UAAW,EACXiN,YAAY,EACZ4J,QAAS,WACT/D,UAAW,EACXnC,OAAQ,KACR7I,UAAW,KACX8G,YAAa,OACbF,YAAa,EACboI,eAAe,EACfzM,YAAY,EACZ0M,aAAa,EACbpN,OAAQ,IACRa,eAAe,EACfqB,UAAU,EACVmL,eAAe,EACfzJ,eAAgB,IAChB0J,eAAgB,KAChB9O,eAAe,EACfZ,UAAW,QACX2P,YAAa,GACbnE,WAAW,EACXoE,eAAe,EACfvN,WACI7P,OAAOqd,kBAAoBC,OAAOC,WAAaD,OAAOE,YAC1DC,WACA7J,cAAe,OACfnE,6BAA6B,EAC7BiO,SAAUnK,UACVoK,YAAY,EACZpN,cAAc,EACdqN,WAAY,EACZ1T,eAAe,EACfyJ,UAAW,OACX8H,QAkDgB1Y,EA9CpB8a,UACIzQ,uBACA3K,oBA4CgBM,EApBpBV,KAAOA,EA0BHU,EAAKL,OAASL,EAAKyb,UAAW/a,EAAK8Z,cAAena,GAGlDK,EAAKgL,UACD,iBAAmBrL,EAAOqL,UACpBE,SAASO,cAAczL,EAAKL,OAAOqL,WACnChL,EAAKL,OAAOqL,WAEjBhL,EAAKgL,UACN,MAAM,IAAI5F,MAAM,+BAgBpB,GAbkC,MAA9BpF,EAAKL,OAAOwa,eAEZna,EAAKma,eAAiBna,EAAKgL,UACiB,iBAA9BhL,EAAKL,OAAOwa,eAE1Bna,EAAKma,eAAiBjP,SAASO,cAC3BzL,EAAKL,OAAOwa,gBAIhBna,EAAKma,eAAiBna,EAAKL,OAAOwa,gBAGjCna,EAAKma,eACN,MAAM,IAAI/U,MAAM,qCAGpB,GAAIpF,EAAKL,OAAO8Q,gBAAkB,EAC9B,MAAM,IAAIrL,MAAM,yCACb,GAAIpF,EAAKL,OAAO8Q,eAAiB,GAAK,EACzC,MAAM,IAAIrL,MAAM,yCAsCpB,GA9BApF,EAAKgb,YAAc,EAMnBhb,EAAKib,SAAU,EAOfjb,EAAKkb,aAMLlb,EAAKmb,YAAc,KAEnBnb,EAAK8F,YAAc,KAEnB9F,EAAKob,OAAS,KAEdpb,EAAK+Z,QAAU,KAEf/Z,EAAKqb,UAAY,KAGmB,mBAAzBrb,EAAKL,OAAOgb,SACnB,MAAM,IAAIvV,MAAM,iCAKpBpF,EAAK4M,OAAS5M,EAAKL,OAAOgb,SAI1B3a,EAAKsb,QAAUtb,EAAK8a,SAAS9a,EAAKL,OAAOoa,SAKzC/Z,EAAKub,yBAELvb,EAAKwb,aAAc,EAEnBxb,EAAKyb,SAAU,EAKf,IAAIC,EAAY,EAWhB,OAVA1b,EAAK2b,UAAYrc,EAAKsc,SAAS,WAEvBF,GAAa1b,EAAKob,OAAOpO,QAAQ0C,aAChC1P,EAAKL,OAAO6N,eAEbkO,EAAY1b,EAAKob,OAAOpO,QAAQ0C,YAChC1P,EAAKob,OAAOna,UAAU,YAEO,iBAA3BjB,EAAKL,OAAOib,WAA0B5a,EAAKL,OAAOib,WAAa,KAEzE3a,EAAAD,wUAtMgCV,EAAK+C,iDAqD3B1C,GAEV,OADmB,IAAIka,EAAWla,GAChBa,6CA+JlB,OAJAT,KAAK8b,gBAAgB9b,KAAKJ,OAAO+a,SACjC3a,KAAK+b,eACL/b,KAAKgc,gBACLhc,KAAKic,kBACEjc,6CAWK2a,GAAS,IAAAnW,EAAAxE,KAarB,OAXA2a,EAAQtX,QAAQ,SAAA6Y,GAAA,OAAU1X,EAAK2X,UAAUD,KAGzCvB,EAAQtX,QAAQ,SAAA6Y,GAGPA,EAAOE,WACR5X,EAAK6X,WAAWH,EAAOre,QAG/BmC,KAAKkB,UAAU,qBAAsByZ,GAC9B3a,uCAWDkc,GAAQ,IAAAnQ,EAAA/L,KACd,IAAKkc,EAAOre,KACR,MAAM,IAAIwH,MAAM,gCAEpB,IAAK6W,EAAOxD,SACR,MAAM,IAAIrT,MAAJ,UACQ6W,EAAOre,KADf,wCAMNqe,EAAOI,aACPte,OAAOga,KAAKkE,EAAOI,aAAajZ,QAAQ,SAAAkZ,GAKpCxQ,EAAKwQ,GAAoBL,EAAOI,YAAYC,KAIpD,IAAMC,EAAWN,EAAOxD,SAiBxB,OAd8B1a,OAAOye,oBACjCld,EAAK+C,SAASpD,WAEImE,QAAQ,SAAAxE,GAC1B2d,EAAStd,UAAUL,GAAOU,EAAK+C,SAASpD,UAAUL,KAQtDmB,KAAKkc,EAAOre,MAAQ,IAAI2e,EAASN,EAAOtc,WAAcI,MACtDA,KAAKkB,UAAU,eAAgBgb,EAAOre,MAC/BmC,wCAWAnC,GACP,IAAKmC,KAAKnC,GACN,MAAM,IAAIwH,MAAJ,UAAoBxH,EAApB,4BASV,OAPImC,KAAKwb,sBAAsB3d,IAE3BmC,KAAK0c,cAAc7e,GAEvBmC,KAAKnC,GAAM4C,OACXT,KAAKwb,sBAAsB3d,IAAQ,EACnCmC,KAAKkB,UAAU,qBAAsBrD,GAC9BmC,2CAWGnC,GACV,IAAKmC,KAAKnC,GACN,MAAM,IAAIwH,MAAJ,UACQxH,EADR,oDAIV,IAAKmC,KAAKwb,sBAAsB3d,GAC5B,MAAM,IAAIwH,MAAJ,UACQxH,EADR,2CAIV,GAAkC,mBAAvBmC,KAAKnC,GAAM8e,QAClB,MAAM,IAAItX,MAAJ,UAAoBxH,EAApB,sCAMV,OAHAmC,KAAKnC,GAAM8e,iBACJ3c,KAAKwb,sBAAsB3d,GAClCmC,KAAKkB,UAAU,mBAAoBrD,GAC5BmC,iDASS,IAAAwM,EAAAxM,KAChBhC,OAAOga,KAAKhY,KAAKwb,uBAAuBnY,QAAQ,SAAAxF,GAAA,OAC5C2O,EAAKkQ,cAAc7e,4CAUZ,IAAAuW,EAAApU,KACXA,KAAKqb,OAAS,IAAIrb,KAAK6M,OAAO7M,KAAKiL,UAAWjL,KAAKJ,QACnDI,KAAKqb,OAAO5a,OACZT,KAAKkB,UAAU,iBAAkBlB,KAAKqb,SAEP,IAA3Brb,KAAKJ,OAAOib,aACZ3d,OAAO+O,iBAAiB,SAAUjM,KAAK4b,WAAW,GAClD1e,OAAO+O,iBAAiB,oBAAqBjM,KAAK4b,WAAW,IAGjE5b,KAAKqb,OAAOnS,GAAG,SAAU,WACrBkL,EAAKwI,aACLxI,EAAKiH,OAAO9M,SAAS6F,EAAK4F,QAAQrZ,uBAItCX,KAAKqb,OAAOnS,GAAG,QAAS,SAACH,EAAGwF,GACxB9F,WAAW,kBAAM2L,EAAKpM,OAAOuG,IAAW,KAI5CvO,KAAKqb,OAAOnS,GAAG,SAAU,SAAAH,GACjBqL,EAAKxU,OAAO0a,eACZlG,EAAKwI,aAETxI,EAAKlT,UAAU,SAAU6H,6CAUjB,IAAA0L,EAAAzU,KACRA,KAAKga,SACLha,KAAKga,QAAQ2C,UAIU,gBAAvB3c,KAAKJ,OAAOoa,UACZha,KAAKJ,OAAOoa,QAAU,gBAIC,YAAvBha,KAAKJ,OAAOoa,SACXha,KAAKub,QAAQrc,UAAU2d,iBAAiBpf,KAAK,QAE9CuC,KAAKJ,OAAOoa,QAAU,gBAG1Bha,KAAKga,QAAU,IAAIha,KAAKub,QAAQvb,KAAKJ,QACrCI,KAAKga,QAAQvZ,OACbT,KAAKkB,UAAU,kBAAmBlB,KAAKga,SAEvCha,KAAKga,QAAQ9Q,GAAG,SAAU,kBAAMuL,EAAKvT,UAAU,YAC/ClB,KAAKga,QAAQ9Q,GAAG,OAAQ,kBAAMuL,EAAKvT,UAAU,UAC7ClB,KAAKga,QAAQ9Q,GAAG,QAAS,kBAAMuL,EAAKvT,UAAU,WAE9ClB,KAAKga,QAAQ9Q,GAAG,eAAgB,SAAAxE,GAC5B+P,EAAK4G,OAAO9M,SAASkG,EAAKuF,QAAQrZ,qBAClC8T,EAAKvT,UAAU,eAAgBwD,+CAU/B1E,KAAKJ,OAAO0a,gBACZta,KAAKsb,UAAY,IAAI/R,iDAWzB,OAAOvJ,KAAKga,QAAQnZ,uDAUpB,OAAOb,KAAKga,QAAQlZ,wDASTgc,GACPA,GAAW9c,KAAKa,cAChBb,KAAKgI,OAAO,GAEZhI,KAAKgI,OAAO8U,EAAU9c,KAAKa,4CAgB9BkG,EAAOC,GAAK,IAAA6O,EAAA7V,KAEb,OADAA,KAAKkB,UAAU,cAAe,kBAAM2U,EAAK3N,KAAKnB,EAAOC,KAC9ChH,KAAKga,QAAQ9R,KAAKnB,EAAOC,mCAUhC,IAAKhH,KAAKga,QAAQ3S,WACd,OAAOrH,KAAKga,QAAQrV,4CAWxB,OAAO3E,KAAKga,QAAQ3S,WAAarH,KAAKkI,OAASlI,KAAK2E,4CAUpD,OAAQ3E,KAAKga,QAAQ3S,gDAUZyV,GACT9c,KAAK+c,MAAMD,IAAY9c,KAAKJ,OAAOkb,gDAU3BgC,GACR9c,KAAK+c,KAAKD,GAAW9c,KAAKJ,OAAOkb,yCAYhChL,GACD,IAAMlP,EAAWZ,KAAKa,eAAiB,EACnCwM,EAAWrN,KAAKc,kBAAoB,EACxCuM,EAAW0C,KAAK7I,IAAI,EAAG6I,KAAK9I,IAAIrG,EAAUyM,GAAYyC,GAAU,KAChE9P,KAAKgd,cAAc3P,EAAWzM,yCAWpB2N,GACVvO,KAAKgI,OAAOuG,GACZvO,KAAKqb,OAAO4B,SAAS1O,kCAalBA,GAAU,IAAA2O,EAAAld,KAEb,GACwB,iBAAbuO,IACN4O,SAAS5O,IACVA,EAAW,GACXA,EAAW,EAEX,OAAO6O,QAAQC,MACX,gFAGRrd,KAAKkB,UAAU,cAAe,kBAAMgc,EAAKlV,OAAOuG,KAEhD,IAAM/D,EAASxK,KAAKga,QAAQ3S,WAEvBmD,GACDxK,KAAKga,QAAQrV,QAGjB,IAAM2Y,EAAkBtd,KAAKJ,OAAO6N,aACpCzN,KAAKJ,OAAO6N,cAAe,EAC3BzN,KAAKga,QAAQhS,OAAOuG,EAAWvO,KAAKa,eACpCb,KAAKqb,OAAO9M,SAASA,GAEhB/D,GACDxK,KAAKga,QAAQ9R,OAEjBlI,KAAKJ,OAAO6N,aAAe6P,EAC3Btd,KAAKkB,UAAU,OAAQqN,kCASvBvO,KAAK2E,QACL3E,KAAKgI,OAAO,GACZhI,KAAKqb,OAAO9M,SAAS,qCAQfxJ,GACN,OAAO/E,KAAKga,QAAQ9U,UAAUH,qCAUxBwY,GACNvd,KAAKga,QAAQ9N,UAAUqR,GACvBvd,KAAKkB,UAAU,SAAUqc,uCAUzB,OAAOvd,KAAKga,QAAQwD,oDAURC,GACZzd,KAAKga,QAAQ9W,gBAAgBua,6CAS7B,OAAOzd,KAAKga,QAAQ0D,uDAYpB1d,KAAK2d,SAAS3d,KAAKkb,yCAaf0C,GAEAA,IAAS5d,KAAKkb,SAKd0C,GAGA5d,KAAKib,YAAcjb,KAAKga,QAAQwD,YAChCxd,KAAKga,QAAQ9N,UAAU,GACvBlM,KAAKkb,SAAU,EACflb,KAAKkB,UAAU,SAAU,KAIzBlB,KAAKga,QAAQ9N,UAAUlM,KAAKib,aAC5Bjb,KAAKkb,SAAU,EACflb,KAAKkB,UAAU,SAAUlB,KAAKib,cAElCjb,KAAKkB,UAAU,OAAQlB,KAAKkb,UAlBxBlb,KAAKkB,UAAU,OAAQlB,KAAKkb,2CA4BhC,OAAOlb,KAAKkb,0CAUZ,OAAOlb,KAAK0b,6CAWZ,OAAO1b,KAAKga,QAAQrY,mDASpB3B,KAAKJ,OAAO6N,cAAgBzN,KAAKJ,OAAO6N,aACxCzN,KAAK4c,yDASL5c,KAAKJ,OAAOoP,UAAYhP,KAAKJ,OAAOoP,gDASpC,OAAOhP,KAAKJ,OAAOiR,+CASVgN,GACT7d,KAAKJ,OAAOiR,UAAYgN,EACxB7d,KAAK4c,wDASL,OAAO5c,KAAKJ,OAAOkR,uDASN+M,GACb7d,KAAKJ,OAAOkR,cAAgB+M,EAC5B7d,KAAK4c,sDAUL,OAAO5c,KAAKJ,OAAOmS,mDAUR8L,GACX7d,KAAKJ,OAAOmS,YAAc8L,EAC1B7d,KAAKqb,OAAO1J,mDASZ,OAAO3R,KAAKJ,OAAOkN,yCASbA,GACN9M,KAAKJ,OAAOkN,OAASA,EACrB9M,KAAKqb,OAAOtF,UAAUjJ,EAAS9M,KAAKJ,OAAOmN,YAC3C/M,KAAK4c,kDAUL,IAAMxO,EAAe2B,KAAKE,MACtBjQ,KAAKa,cACDb,KAAKJ,OAAOya,YACZra,KAAKJ,OAAOmN,YAEdsB,EAAcrO,KAAKqb,OAAO/M,WAC5B9C,EAAQ4C,EACRrH,EAAQ/G,KAAKqb,OAAOyC,aACpB9W,EAAM+I,KAAK7I,IAAIH,EAAQsH,EAAa7C,GAGpCxL,KAAKJ,OAAO4N,cACVxN,KAAKJ,OAAO6N,cAAgBW,EAAeC,KAG7CtH,EAAQ,EACRC,EAFAwE,EAAQ6C,GAKZ,IAAItM,SACJ,GAAI/B,KAAKJ,OAAO0a,cAAe,CAC3B,IAAMyD,EAAY/d,KAAKsb,UAAU0C,oBAC7BxS,EACAzE,EACAC,GAEA1J,SACJ,IAAKA,EAAI,EAAGA,EAAIygB,EAAUpa,OAAQrG,IAC9ByE,EAAQ/B,KAAKga,QAAQiE,SACjBzS,EACAuS,EAAUzgB,GAAG,GACbygB,EAAUzgB,GAAG,IAEjB0C,KAAKqb,OAAO6C,UACRnc,EACAyJ,EACAuS,EAAUzgB,GAAG,GACbygB,EAAUzgB,GAAG,SAIrByE,EAAQ/B,KAAKga,QAAQiE,SAASzS,EAAOzE,EAAOC,GAC5ChH,KAAKqb,OAAO6C,UAAUnc,EAAOyJ,EAAOzE,EAAOC,GAE/ChH,KAAKkB,UAAU,SAAUa,EAAOyJ,gCAa/B2S,GACIA,GAIDne,KAAKJ,OAAOya,YAAc8D,EAC1Bne,KAAKJ,OAAO6N,cAAe,IAJ3BzN,KAAKJ,OAAOya,YAAcra,KAAK+Z,cAAcM,YAC7Cra,KAAKJ,OAAO6N,cAAe,GAM/BzN,KAAK4c,aACL5c,KAAKqb,OAAO9M,SAASvO,KAAKga,QAAQrZ,qBAElCX,KAAKqb,OAAO4B,SAASjd,KAAKc,iBAAmBd,KAAKa,eAClDb,KAAKkB,UAAU,OAAQid,2CASXpY,GAAa,IAAAqY,EAAApe,KACzBA,KAAKqe,kBAAkBtY,EAAa,SAAAK,GAC3BgY,EAAK3C,aACN2C,EAAKE,kBAAkBlY,+CAYjB1E,GACd1B,KAAKga,QAAQhO,KAAKtK,GAClB1B,KAAK4c,aACL5c,KAAKkB,UAAU,SACflB,KAAK0b,SAAU,mCASV6C,GAAM,IAAAC,EAAAxe,KAELye,EAAS,IAAIC,WACnBD,EAAOxS,iBAAiB,WAAY,SAAAlD,GAAA,OAAKyV,EAAKG,WAAW5V,KACzD0V,EAAOxS,iBAAiB,OAAQ,SAAAlD,GAAA,OAC5ByV,EAAKI,gBAAgB7V,EAAE8G,OAAOwH,UAElCoH,EAAOxS,iBAAiB,QAAS,kBAC7BuS,EAAKtd,UAAU,QAAS,wBAE5Bud,EAAOI,kBAAkBN,GACzBve,KAAK8e,qCA2BJ9T,EAAKjJ,EAAOmJ,EAAStK,GAGtB,GAFAZ,KAAK8e,QAED5T,EAAS,CAGT,IAAM6T,GACFC,+CACuD,KAAlD,OAAQ,WAAY,QAAQC,QAAQ/T,GACzCgU,0BAA2Bnd,EAC3Bod,sCAC4B,iBAAxBnf,KAAKJ,OAAOoa,QAChBoF,4BAA4C,iBAARpU,GAElCqU,EAAgBrhB,OAAOga,KAAK+G,GAAsBzb,OACpD,SAAAgc,GAAA,OAAUP,EAAqBO,KAE/BD,EAAc1b,SACdyZ,QAAQmC,KACJ,sEACIF,EAAcG,KAAK,WAG3BtU,EAAU,MAIlB,OAAQlL,KAAKJ,OAAOoa,SAChB,IAAK,WACD,OAAOha,KAAKyf,WAAWzU,EAAKjJ,EAAOnB,GACvC,IAAK,eACD,OAAOZ,KAAK0f,iBAAiB1U,EAAKjJ,EAAOmJ,EAAStK,uCAYnDoK,EAAKjJ,EAAOnB,GAAU,IAAA+e,EAAA3f,KACvBgM,EAAO,SAAA4T,GAIT,OAHIA,GACAD,EAAKxE,UAAUtS,KAAK8W,EAAKE,KAAK,QAASD,IAEpCD,EAAKG,eAAe9U,EAAK,SAAA5E,GAAA,OAAQuZ,EAAKf,gBAAgBxY,MAGjE,IAAIrE,EAKA,OAAOiK,IAJPhM,KAAKga,QAAQ+F,SAAShe,EAAOnB,GAC7BZ,KAAK4c,aACL5c,KAAKmb,UAAUtS,KAAK7I,KAAK6f,KAAK,cAAe7T,6CAkBpCgU,EAAUje,EAAOmJ,EAAStK,GAAU,IAAAqf,EAAAjgB,KAC7CgL,EAAMgV,EAEV,GAAwB,iBAAbA,EACPhgB,KAAKga,QAAQhO,KAAKhB,EAAKhL,KAAKoa,eAAgBrY,EAAOmJ,OAChD,CACH,IAAMY,EAAMkU,EACZhgB,KAAKga,QAAQkG,QAAQpU,EAAK/J,GAI1BiJ,EAAMc,EAAIrG,IAGdzF,KAAKmb,UAAUtS,KACX7I,KAAKga,QAAQ6F,KAAK,UAAW,WACzBI,EAAKrD,aACLqD,EAAK/e,UAAU,SACf+e,EAAKvE,SAAU,IAEnB1b,KAAKga,QAAQ6F,KAAK,QAAS,SAAAM,GAAA,OAAOF,EAAK/e,UAAU,QAASif,MAM1Dpe,GACA/B,KAAKga,QAAQ+F,SAAShe,EAAOnB,GAI3BmB,IAAS/B,KAAKJ,OAAOsa,cACvBla,KAAKga,QAAQ6C,oBAEb7c,KAAK8f,eAAe9U,EAAK,SAAAjF,GACrBka,EAAK5B,kBAAkBtY,EAAa,SAAArE,GAChCue,EAAKjG,QAAQtY,OAASA,EACtBue,EAAKjG,QAAQ+F,SAAS,MACtBE,EAAKrD,aACLqD,EAAK/e,UAAU,gEAab6E,EAAaC,GAAU,IAAAoa,EAAApgB,KACrCA,KAAK+F,YAAcA,EAEnB/F,KAAKga,QAAQqE,kBACTtY,EACA,SAAAK,GAGSga,EAAK3E,aAAe2E,EAAKra,aAAeA,IACzCC,EAASI,GACTga,EAAKra,YAAc,OAG3B,kBAAMqa,EAAKlf,UAAU,QAAS,uEAWvB8J,EAAKhF,GAAU,IAAAqa,EAAArgB,KACpBsgB,EAAO/gB,EAAK+gB,MACdtV,IAAKA,EACLgO,aAAc,cACdL,IAAK3Y,KAAKJ,OAAO+Y,MAmBrB,OAhBA3Y,KAAKob,YAAckF,EAEnBtgB,KAAKmb,UAAUtS,KACXyX,EAAKpX,GAAG,WAAY,SAAAH,GAChBsX,EAAK1B,WAAW5V,KAEpBuX,EAAKpX,GAAG,UAAW,SAAC9C,EAAM2C,GACtB/C,EAASI,GACTia,EAAKjF,YAAc,OAEvBkF,EAAKpX,GAAG,QAAS,SAAAH,GACbsX,EAAKnf,UAAU,QAAS,cAAgB6H,EAAE8G,OAAO0Q,YACjDF,EAAKjF,YAAc,QAIpBkF,qCAUAvX,GACP,IAAIyX,SAEAA,EADAzX,EAAEsQ,iBACgBtQ,EAAEuQ,OAASvQ,EAAEwQ,MAIbxQ,EAAEuQ,QAAUvQ,EAAEuQ,OAAS,KAE7CtZ,KAAKkB,UAAU,UAAW6O,KAAKE,MAAwB,IAAlBuQ,GAAwBzX,EAAE8G,0CAczDlM,EAAQ8c,EAAUC,EAAU3Z,GAClCpD,EAASA,GAAU,KACnBoD,EAAQA,GAAS,EACjB0Z,EAAWA,GAAY,IACvBC,EAAWA,IAAY,EACvB,IAAM3e,EAAQ/B,KAAKga,QAAQiE,SAASta,EAAQoD,GACtC+C,KAAS2M,IAAIhZ,KACfsE,EACA,SAAAqU,GAAA,OAAOrG,KAAKE,MAAMmG,EAAMqK,GAAYA,IAElCE,EAAOC,KAAKC,UAAU/W,GAO5B,OANK4W,GACDxjB,OAAO4b,KACH,uCACIgI,mBAAmBH,IAGxBA,sCAaCI,EAAQxK,GAQhB,OAPKwK,IACDA,EAAS,aAERxK,IACDA,EAAU,GAGPvW,KAAKqb,OAAO2F,SAASD,EAAQxK,wCAOhCvW,KAAKob,cACLpb,KAAKob,YAAYzC,IAAIsI,QACrBjhB,KAAKob,YAAc,+CAQvBpb,KAAKmb,UAAU9X,QAAQ,SAAA0F,GAAA,OAAKA,EAAED,uCAOzB9I,KAAKga,QAAQ3S,aACdrH,KAAK6H,OACL7H,KAAKga,QAAQzS,oBAEjBvH,KAAKkhB,aACLlhB,KAAKmhB,iBACLnhB,KAAKqb,OAAO9M,SAAS,GACrBvO,KAAKqb,OAAOnM,SAAS,GACrBlP,KAAKqb,OAAO6C,WAAYva,OAAQ3D,KAAKqb,OAAO/M,YAAc,qCAS1DtO,KAAKohB,oBACLphB,KAAKkB,UAAU,WACflB,KAAKkhB,aACLlhB,KAAKmhB,iBACLnhB,KAAKsH,SAC0B,IAA3BtH,KAAKJ,OAAOib,aACZ3d,OAAO4Z,oBAAoB,SAAU9W,KAAK4b,WAAW,GACrD1e,OAAO4Z,oBACH,oBACA9W,KAAK4b,WACL,IAGR5b,KAAKga,QAAQ2C,UACb3c,KAAKqb,OAAOsB,UACZ3c,KAAKyb,aAAc,EACnBzb,KAAK+F,YAAc,cAxxCN+T,EA6EVva,KAAOA,YA7EGua","file":"wavesurfer.min.js","sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine(\"WaveSurfer\", [], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"WaveSurfer\"] = factory();\n\telse\n\t\troot[\"WaveSurfer\"] = factory();\n})(window, function() {\nreturn "," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 17);\n","export { default as ajax } from './ajax';\nexport { default as getId } from './get-id';\nexport { default as max } from './max';\nexport { default as min } from './min';\nexport { default as Observer } from './observer';\nexport { default as extend } from './extend';\nexport { default as style } from './style';\nexport { default as requestAnimationFrame } from './request-animation-frame';\nexport { default as frame } from './frame';\nexport { default as debounce } from 'debounce';\nexport { default as preventClick } from './prevent-click';\n","import * as util from './util';\n\n// using consts to prevent someone writing the string wrong\nconst PLAYING = 'playing';\nconst PAUSED = 'paused';\nconst FINISHED = 'finished';\n\n/**\n * WebAudio backend\n *\n * @extends {Observer}\n */\nexport default class WebAudio extends util.Observer {\n    /** @private */\n    static scriptBufferSize = 256;\n    /** @private */\n    audioContext = null;\n    /** @private */\n    offlineAudioContext = null;\n    /** @private */\n    stateBehaviors = {\n        [PLAYING]: {\n            init() {\n                this.addOnAudioProcess();\n            },\n            getPlayedPercents() {\n                const duration = this.getDuration();\n                return this.getCurrentTime() / duration || 0;\n            },\n            getCurrentTime() {\n                return this.startPosition + this.getPlayedTime();\n            }\n        },\n        [PAUSED]: {\n            init() {\n                this.removeOnAudioProcess();\n            },\n            getPlayedPercents() {\n                const duration = this.getDuration();\n                return this.getCurrentTime() / duration || 0;\n            },\n            getCurrentTime() {\n                return this.startPosition;\n            }\n        },\n        [FINISHED]: {\n            init() {\n                this.removeOnAudioProcess();\n                this.fireEvent('finish');\n            },\n            getPlayedPercents() {\n                return 1;\n            },\n            getCurrentTime() {\n                return this.getDuration();\n            }\n        }\n    };\n\n    /**\n     * Does the browser support this backend\n     *\n     * @return {boolean}\n     */\n    supportsWebAudio() {\n        return !!(window.AudioContext || window.webkitAudioContext);\n    }\n\n    /**\n     * Get the audio context used by this backend or create one\n     *\n     * @return {AudioContext}\n     */\n    getAudioContext() {\n        if (!window.WaveSurferAudioContext) {\n            window.WaveSurferAudioContext = new (window.AudioContext ||\n                window.webkitAudioContext)();\n        }\n        return window.WaveSurferAudioContext;\n    }\n\n    /**\n     * Get the offline audio context used by this backend or create one\n     *\n     * @param {number} sampleRate\n     * @return {OfflineAudioContext}\n     */\n    getOfflineAudioContext(sampleRate) {\n        if (!window.WaveSurferOfflineAudioContext) {\n            window.WaveSurferOfflineAudioContext = new (window.OfflineAudioContext ||\n                window.webkitOfflineAudioContext)(1, 2, sampleRate);\n        }\n        return window.WaveSurferOfflineAudioContext;\n    }\n\n    /**\n     * Construct the backend\n     *\n     * @param {WavesurferParams} params\n     */\n    constructor(params) {\n        super();\n        /** @private */\n        this.params = params;\n        /** @private */\n        this.ac = params.audioContext || this.getAudioContext();\n        /**@private */\n        this.lastPlay = this.ac.currentTime;\n        /** @private */\n        this.startPosition = 0;\n        /** @private  */\n        this.scheduledPause = null;\n        /** @private */\n        this.states = {\n            [PLAYING]: Object.create(this.stateBehaviors[PLAYING]),\n            [PAUSED]: Object.create(this.stateBehaviors[PAUSED]),\n            [FINISHED]: Object.create(this.stateBehaviors[FINISHED])\n        };\n        /** @private */\n        this.analyser = null;\n        /** @private */\n        this.buffer = null;\n        /** @private */\n        this.filters = [];\n        /** @private */\n        this.gainNode = null;\n        /** @private */\n        this.mergedPeaks = null;\n        /** @private */\n        this.offlineAc = null;\n        /** @private */\n        this.peaks = null;\n        /** @private */\n        this.playbackRate = 1;\n        /** @private */\n        this.analyser = null;\n        /** @private */\n        this.scriptNode = null;\n        /** @private */\n        this.source = null;\n        /** @private */\n        this.splitPeaks = [];\n        /** @private */\n        this.state = null;\n        /** @private */\n        this.explicitDuration = null;\n    }\n\n    /**\n     * Initialise the backend, called in `wavesurfer.createBackend()`\n     */\n    init() {\n        this.createVolumeNode();\n        this.createScriptNode();\n        this.createAnalyserNode();\n\n        this.setState(PAUSED);\n        this.setPlaybackRate(this.params.audioRate);\n        this.setLength(0);\n    }\n\n    /** @private */\n    disconnectFilters() {\n        if (this.filters) {\n            this.filters.forEach(filter => {\n                filter && filter.disconnect();\n            });\n            this.filters = null;\n            // Reconnect direct path\n            this.analyser.connect(this.gainNode);\n        }\n    }\n\n    /** @private */\n    setState(state) {\n        if (this.state !== this.states[state]) {\n            this.state = this.states[state];\n            this.state.init.call(this);\n        }\n    }\n\n    /**\n     * Unpacked `setFilters()`\n     *\n     * @param {...AudioNode} filters\n     */\n    setFilter(...filters) {\n        this.setFilters(filters);\n    }\n\n    /**\n     * Insert custom Web Audio nodes into the graph\n     *\n     * @param {AudioNode[]} filters Packed filters array\n     * @example\n     * const lowpass = wavesurfer.backend.ac.createBiquadFilter();\n     * wavesurfer.backend.setFilter(lowpass);\n     */\n    setFilters(filters) {\n        // Remove existing filters\n        this.disconnectFilters();\n\n        // Insert filters if filter array not empty\n        if (filters && filters.length) {\n            this.filters = filters;\n\n            // Disconnect direct path before inserting filters\n            this.analyser.disconnect();\n\n            // Connect each filter in turn\n            filters\n                .reduce((prev, curr) => {\n                    prev.connect(curr);\n                    return curr;\n                }, this.analyser)\n                .connect(this.gainNode);\n        }\n    }\n\n    /** @private */\n    createScriptNode() {\n        if (this.params.audioScriptProcessor) {\n            this.scriptNode = this.params.audioScriptProcessor;\n        } else {\n            if (this.ac.createScriptProcessor) {\n                this.scriptNode = this.ac.createScriptProcessor(\n                    WebAudio.scriptBufferSize\n                );\n            } else {\n                this.scriptNode = this.ac.createJavaScriptNode(\n                    WebAudio.scriptBufferSize\n                );\n            }\n        }\n        this.scriptNode.connect(this.ac.destination);\n    }\n\n    /** @private */\n    addOnAudioProcess() {\n        this.scriptNode.onaudioprocess = () => {\n            const time = this.getCurrentTime();\n\n            if (time >= this.getDuration()) {\n                this.setState(FINISHED);\n                this.fireEvent('pause');\n            } else if (time >= this.scheduledPause) {\n                this.pause();\n            } else if (this.state === this.states[PLAYING]) {\n                this.fireEvent('audioprocess', time);\n            }\n        };\n    }\n\n    /** @private */\n    removeOnAudioProcess() {\n        this.scriptNode.onaudioprocess = null;\n    }\n\n    /** @private */\n    createAnalyserNode() {\n        this.analyser = this.ac.createAnalyser();\n        this.analyser.connect(this.gainNode);\n    }\n\n    /**\n     * Create the gain node needed to control the playback volume.\n     *\n     * @private\n     */\n    createVolumeNode() {\n        // Create gain node using the AudioContext\n        if (this.ac.createGain) {\n            this.gainNode = this.ac.createGain();\n        } else {\n            this.gainNode = this.ac.createGainNode();\n        }\n        // Add the gain node to the graph\n        this.gainNode.connect(this.ac.destination);\n    }\n\n    /**\n     * Set the sink id for the media player\n     *\n     * @param {string} deviceId String value representing audio device id.\n     */\n    setSinkId(deviceId) {\n        if (deviceId) {\n            /**\n             * The webaudio api doesn't currently support setting the device\n             * output. Here we create an HTMLAudioElement, connect the\n             * webaudio stream to that element and setSinkId there.\n             */\n            let audio = new window.Audio();\n            if (!audio.setSinkId) {\n                return Promise.reject(\n                    new Error('setSinkId is not supported in your browser')\n                );\n            }\n            audio.autoplay = true;\n            var dest = this.ac.createMediaStreamDestination();\n            this.gainNode.disconnect();\n            this.gainNode.connect(dest);\n            audio.src = URL.createObjectURL(dest.stream);\n\n            return audio.setSinkId(deviceId);\n        } else {\n            return Promise.reject(new Error('Invalid deviceId: ' + deviceId));\n        }\n    }\n\n    /**\n     * Set the audio volume\n     *\n     * @param {number} value A floating point value between 0 and 1.\n     */\n    setVolume(value) {\n        this.gainNode.gain.setValueAtTime(value, this.ac.currentTime);\n    }\n\n    /**\n     * Get the current volume\n     *\n     * @return {number} value A floating point value between 0 and 1.\n     */\n    getVolume() {\n        return this.gainNode.gain.value;\n    }\n\n    /** @private */\n    decodeArrayBuffer(arraybuffer, callback, errback) {\n        if (!this.offlineAc) {\n            this.offlineAc = this.getOfflineAudioContext(\n                this.ac ? this.ac.sampleRate : 44100\n            );\n        }\n        this.offlineAc.decodeAudioData(\n            arraybuffer,\n            data => callback(data),\n            errback\n        );\n    }\n\n    /**\n     * Set pre-decoded peaks\n     *\n     * @param {number[]|number[][]} peaks\n     * @param {?number} duration\n     */\n    setPeaks(peaks, duration) {\n        this.explicitDuration = duration;\n        this.peaks = peaks;\n    }\n\n    /**\n     * Set the rendered length (different from the length of the audio).\n     *\n     * @param {number} length\n     */\n    setLength(length) {\n        // No resize, we can preserve the cached peaks.\n        if (this.mergedPeaks && length == 2 * this.mergedPeaks.length - 1 + 2) {\n            return;\n        }\n\n        this.splitPeaks = [];\n        this.mergedPeaks = [];\n        // Set the last element of the sparse array so the peak arrays are\n        // appropriately sized for other calculations.\n        const channels = this.buffer ? this.buffer.numberOfChannels : 1;\n        let c;\n        for (c = 0; c < channels; c++) {\n            this.splitPeaks[c] = [];\n            this.splitPeaks[c][2 * (length - 1)] = 0;\n            this.splitPeaks[c][2 * (length - 1) + 1] = 0;\n        }\n        this.mergedPeaks[2 * (length - 1)] = 0;\n        this.mergedPeaks[2 * (length - 1) + 1] = 0;\n    }\n\n    /**\n     * Compute the max and min value of the waveform when broken into <length> subranges.\n     *\n     * @param {number} length How many subranges to break the waveform into.\n     * @param {number} first First sample in the required range.\n     * @param {number} last Last sample in the required range.\n     * @return {number[]|number[][]} Array of 2*<length> peaks or array of arrays of\n     * peaks consisting of (max, min) values for each subrange.\n     */\n    getPeaks(length, first, last) {\n        if (this.peaks) {\n            return this.peaks;\n        }\n\n        first = first || 0;\n        last = last || length - 1;\n\n        this.setLength(length);\n\n        /**\n         * The following snippet fixes a buffering data issue on the Safari\n         * browser which returned undefined It creates the missing buffer based\n         * on 1 channel, 4096 samples and the sampleRate from the current\n         * webaudio context 4096 samples seemed to be the best fit for rendering\n         * will review this code once a stable version of Safari TP is out\n         */\n        if (!this.buffer.length) {\n            const newBuffer = this.createBuffer(1, 4096, this.sampleRate);\n            this.buffer = newBuffer.buffer;\n        }\n\n        const sampleSize = this.buffer.length / length;\n        const sampleStep = ~~(sampleSize / 10) || 1;\n        const channels = this.buffer.numberOfChannels;\n        let c;\n\n        for (c = 0; c < channels; c++) {\n            const peaks = this.splitPeaks[c];\n            const chan = this.buffer.getChannelData(c);\n            let i;\n\n            for (i = first; i <= last; i++) {\n                const start = ~~(i * sampleSize);\n                const end = ~~(start + sampleSize);\n                let min = 0;\n                let max = 0;\n                let j;\n\n                for (j = start; j < end; j += sampleStep) {\n                    const value = chan[j];\n\n                    if (value > max) {\n                        max = value;\n                    }\n\n                    if (value < min) {\n                        min = value;\n                    }\n                }\n\n                peaks[2 * i] = max;\n                peaks[2 * i + 1] = min;\n\n                if (c == 0 || max > this.mergedPeaks[2 * i]) {\n                    this.mergedPeaks[2 * i] = max;\n                }\n\n                if (c == 0 || min < this.mergedPeaks[2 * i + 1]) {\n                    this.mergedPeaks[2 * i + 1] = min;\n                }\n            }\n        }\n\n        return this.params.splitChannels ? this.splitPeaks : this.mergedPeaks;\n    }\n\n    /**\n     * Get the position from 0 to 1\n     *\n     * @return {number}\n     */\n    getPlayedPercents() {\n        return this.state.getPlayedPercents.call(this);\n    }\n\n    /** @private */\n    disconnectSource() {\n        if (this.source) {\n            this.source.disconnect();\n        }\n    }\n\n    /**\n     * This is called when wavesurfer is destroyed\n     */\n    destroy() {\n        if (!this.isPaused()) {\n            this.pause();\n        }\n        this.unAll();\n        this.buffer = null;\n        this.disconnectFilters();\n        this.disconnectSource();\n        this.gainNode.disconnect();\n        this.scriptNode.disconnect();\n        this.analyser.disconnect();\n\n        // close the audioContext if closeAudioContext option is set to true\n        if (this.params.closeAudioContext) {\n            // check if browser supports AudioContext.close()\n            if (\n                typeof this.ac.close === 'function' &&\n                this.ac.state != 'closed'\n            ) {\n                this.ac.close();\n            }\n            // clear the reference to the audiocontext\n            this.ac = null;\n            // clear the actual audiocontext, either passed as param or the\n            // global singleton\n            if (!this.params.audioContext) {\n                window.WaveSurferAudioContext = null;\n            } else {\n                this.params.audioContext = null;\n            }\n            // clear the offlineAudioContext\n            window.WaveSurferOfflineAudioContext = null;\n        }\n    }\n\n    /**\n     * Loaded a decoded audio buffer\n     *\n     * @param {Object} buffer\n     */\n    load(buffer) {\n        this.startPosition = 0;\n        this.lastPlay = this.ac.currentTime;\n        this.buffer = buffer;\n        this.createSource();\n    }\n\n    /** @private */\n    createSource() {\n        this.disconnectSource();\n        this.source = this.ac.createBufferSource();\n\n        // adjust for old browsers\n        this.source.start = this.source.start || this.source.noteGrainOn;\n        this.source.stop = this.source.stop || this.source.noteOff;\n\n        this.source.playbackRate.setValueAtTime(\n            this.playbackRate,\n            this.ac.currentTime\n        );\n        this.source.buffer = this.buffer;\n        this.source.connect(this.analyser);\n    }\n\n    /**\n     * Used by `wavesurfer.isPlaying()` and `wavesurfer.playPause()`\n     *\n     * @return {boolean}\n     */\n    isPaused() {\n        return this.state !== this.states[PLAYING];\n    }\n\n    /**\n     * Used by `wavesurfer.getDuration()`\n     *\n     * @return {number}\n     */\n    getDuration() {\n        if (!this.buffer) {\n            if (this.explicitDuration) {\n                return this.explicitDuration;\n            }\n            return 0;\n        }\n        return this.buffer.duration;\n    }\n\n    /**\n     * Used by `wavesurfer.seekTo()`\n     *\n     * @param {number} start Position to start at in seconds\n     * @param {number} end Position to end at in seconds\n     * @return {{start: number, end: number}}\n     */\n    seekTo(start, end) {\n        if (!this.buffer) {\n            return;\n        }\n\n        this.scheduledPause = null;\n\n        if (start == null) {\n            start = this.getCurrentTime();\n            if (start >= this.getDuration()) {\n                start = 0;\n            }\n        }\n        if (end == null) {\n            end = this.getDuration();\n        }\n\n        this.startPosition = start;\n        this.lastPlay = this.ac.currentTime;\n\n        if (this.state === this.states[FINISHED]) {\n            this.setState(PAUSED);\n        }\n\n        return {\n            start: start,\n            end: end\n        };\n    }\n\n    /**\n     * Get the playback position in seconds\n     *\n     * @return {number}\n     */\n    getPlayedTime() {\n        return (this.ac.currentTime - this.lastPlay) * this.playbackRate;\n    }\n\n    /**\n     * Plays the loaded audio region.\n     *\n     * @param {number} start Start offset in seconds, relative to the beginning\n     * of a clip.\n     * @param {number} end When to stop relative to the beginning of a clip.\n     */\n    play(start, end) {\n        if (!this.buffer) {\n            return;\n        }\n\n        // need to re-create source on each playback\n        this.createSource();\n\n        const adjustedTime = this.seekTo(start, end);\n\n        start = adjustedTime.start;\n        end = adjustedTime.end;\n\n        this.scheduledPause = end;\n\n        this.source.start(0, start, end - start);\n\n        if (this.ac.state == 'suspended') {\n            this.ac.resume && this.ac.resume();\n        }\n\n        this.setState(PLAYING);\n\n        this.fireEvent('play');\n    }\n\n    /**\n     * Pauses the loaded audio.\n     */\n    pause() {\n        this.scheduledPause = null;\n\n        this.startPosition += this.getPlayedTime();\n        this.source && this.source.stop(0);\n\n        this.setState(PAUSED);\n\n        this.fireEvent('pause');\n    }\n\n    /**\n     * Returns the current time in seconds relative to the audioclip's\n     * duration.\n     *\n     * @return {number}\n     */\n    getCurrentTime() {\n        return this.state.getCurrentTime.call(this);\n    }\n\n    /**\n     * Returns the current playback rate. (0=no playback, 1=normal playback)\n     *\n     * @return {number}\n     */\n    getPlaybackRate() {\n        return this.playbackRate;\n    }\n\n    /**\n     * Set the audio source playback rate.\n     *\n     * @param {number} value\n     */\n    setPlaybackRate(value) {\n        value = value || 1;\n        if (this.isPaused()) {\n            this.playbackRate = value;\n        } else {\n            this.pause();\n            this.playbackRate = value;\n            this.play();\n        }\n    }\n}\n","/**\n * Returns the requestAnimationFrame function for the browser, or a shim with\n * setTimeout if none is found\n *\n * @return {function}\n */\nexport default (\n    window.requestAnimationFrame ||\n    window.webkitRequestAnimationFrame ||\n    window.mozRequestAnimationFrame ||\n    window.oRequestAnimationFrame ||\n    window.msRequestAnimationFrame ||\n    ((callback, element) => setTimeout(callback, 1000 / 60))\n).bind(window);\n","/**\n * @typedef {Object} ListenerDescriptor\n * @property {string} name The name of the event\n * @property {function} callback The callback\n * @property {function} un The function to call to remove the listener\n */\n\n/**\n * Observer class\n */\nexport default class Observer {\n    /**\n     * Instantiate Observer\n     */\n    constructor() {\n        /**\n         * @private\n         * @todo Initialise the handlers here already and remove the conditional\n         * assignment in `on()`\n         */\n        this.handlers = null;\n    }\n    /**\n     * Attach a handler function for an event.\n     *\n     * @param {string} event Name of the event to listen to\n     * @param {function} fn The callback to trigger when the event is fired\n     * @return {ListenerDescriptor}\n     */\n    on(event, fn) {\n        if (!this.handlers) {\n            this.handlers = {};\n        }\n\n        let handlers = this.handlers[event];\n        if (!handlers) {\n            handlers = this.handlers[event] = [];\n        }\n        handlers.push(fn);\n\n        // Return an event descriptor\n        return {\n            name: event,\n            callback: fn,\n            un: (e, fn) => this.un(e, fn)\n        };\n    }\n\n    /**\n     * Remove an event handler.\n     *\n     * @param {string} event Name of the event the listener that should be\n     * removed listens to\n     * @param {function} fn The callback that should be removed\n     */\n    un(event, fn) {\n        if (!this.handlers) {\n            return;\n        }\n\n        const handlers = this.handlers[event];\n        let i;\n        if (handlers) {\n            if (fn) {\n                for (i = handlers.length - 1; i >= 0; i--) {\n                    if (handlers[i] == fn) {\n                        handlers.splice(i, 1);\n                    }\n                }\n            } else {\n                handlers.length = 0;\n            }\n        }\n    }\n\n    /**\n     * Remove all event handlers.\n     */\n    unAll() {\n        this.handlers = null;\n    }\n\n    /**\n     * Attach a handler to an event. The handler is executed at most once per\n     * event type.\n     *\n     * @param {string} event The event to listen to\n     * @param {function} handler The callback that is only to be called once\n     * @return {ListenerDescriptor}\n     */\n    once(event, handler) {\n        const fn = (...args) => {\n            /*  eslint-disable no-invalid-this */\n            handler.apply(this, args);\n            /*  eslint-enable no-invalid-this */\n            setTimeout(() => {\n                this.un(event, fn);\n            }, 0);\n        };\n        return this.on(event, fn);\n    }\n\n    /**\n     * Manually fire an event\n     *\n     * @param {string} event The event to fire manually\n     * @param {...any} args The arguments with which to call the listeners\n     */\n    fireEvent(event, ...args) {\n        if (!this.handlers) {\n            return;\n        }\n        const handlers = this.handlers[event];\n        handlers &&\n            handlers.forEach(fn => {\n                fn(...args);\n            });\n    }\n}\n","/**\n * Caches the decoded peaks data to improve rendering speed for lage audio\n *\n * Is used if the option parameter `partialRender` is set to `true`\n */\nexport default class PeakCache {\n    /**\n     * Instantiate cache\n     */\n    constructor() {\n        this.clearPeakCache();\n    }\n\n    /**\n     * Empty the cache\n     */\n    clearPeakCache() {\n        /**\n         * Flat array with entries that are always in pairs to mark the\n         * beginning and end of each subrange.  This is a convenience so we can\n         * iterate over the pairs for easy set difference operations.\n         * @private\n         */\n        this.peakCacheRanges = [];\n        /**\n         * Length of the entire cachable region, used for resetting the cache\n         * when this changes (zoom events, for instance).\n         * @private\n         */\n        this.peakCacheLength = -1;\n    }\n\n    /**\n     * Add a range of peaks to the cache\n     *\n     * @param {number} length The length of the range\n     * @param {number} start The x offset of the start of the range\n     * @param {number} end The x offset of the end of the range\n     * @return {number[][]}\n     */\n    addRangeToPeakCache(length, start, end) {\n        if (length != this.peakCacheLength) {\n            this.clearPeakCache();\n            this.peakCacheLength = length;\n        }\n\n        // Return ranges that weren't in the cache before the call.\n        let uncachedRanges = [];\n        let i = 0;\n        // Skip ranges before the current start.\n        while (\n            i < this.peakCacheRanges.length &&\n            this.peakCacheRanges[i] < start\n        ) {\n            i++;\n        }\n        // If |i| is even, |start| falls after an existing range.  Otherwise,\n        // |start| falls between an existing range, and the uncached region\n        // starts when we encounter the next node in |peakCacheRanges| or\n        // |end|, whichever comes first.\n        if (i % 2 == 0) {\n            uncachedRanges.push(start);\n        }\n        while (\n            i < this.peakCacheRanges.length &&\n            this.peakCacheRanges[i] <= end\n        ) {\n            uncachedRanges.push(this.peakCacheRanges[i]);\n            i++;\n        }\n        // If |i| is even, |end| is after all existing ranges.\n        if (i % 2 == 0) {\n            uncachedRanges.push(end);\n        }\n\n        // Filter out the 0-length ranges.\n        uncachedRanges = uncachedRanges.filter((item, pos, arr) => {\n            if (pos == 0) {\n                return item != arr[pos + 1];\n            } else if (pos == arr.length - 1) {\n                return item != arr[pos - 1];\n            }\n            return item != arr[pos - 1] && item != arr[pos + 1];\n        });\n\n        // Merge the two ranges together, uncachedRanges will either contain\n        // wholly new points, or duplicates of points in peakCacheRanges.  If\n        // duplicates are detected, remove both and extend the range.\n        this.peakCacheRanges = this.peakCacheRanges.concat(uncachedRanges);\n        this.peakCacheRanges = this.peakCacheRanges\n            .sort((a, b) => a - b)\n            .filter((item, pos, arr) => {\n                if (pos == 0) {\n                    return item != arr[pos + 1];\n                } else if (pos == arr.length - 1) {\n                    return item != arr[pos - 1];\n                }\n                return item != arr[pos - 1] && item != arr[pos + 1];\n            });\n\n        // Push the uncached ranges into an array of arrays for ease of\n        // iteration in the functions that call this.\n        const uncachedRangePairs = [];\n        for (i = 0; i < uncachedRanges.length; i += 2) {\n            uncachedRangePairs.push([uncachedRanges[i], uncachedRanges[i + 1]]);\n        }\n\n        return uncachedRangePairs;\n    }\n\n    /**\n     * For testing\n     *\n     * @return {number[][]}\n     */\n    getCacheRanges() {\n        const peakCacheRangePairs = [];\n        let i;\n        for (i = 0; i < this.peakCacheRanges.length; i += 2) {\n            peakCacheRangePairs.push([\n                this.peakCacheRanges[i],\n                this.peakCacheRanges[i + 1]\n            ]);\n        }\n        return peakCacheRangePairs;\n    }\n}\n","import WebAudio from './webaudio';\nimport * as util from './util';\n\n/**\n * MediaElement backend\n */\nexport default class MediaElement extends WebAudio {\n    /**\n     * Construct the backend\n     *\n     * @param {WavesurferParams} params\n     */\n    constructor(params) {\n        super(params);\n        /** @private */\n        this.params = params;\n\n        // Dummy media to catch errors\n        /** @private */\n        this.media = {\n            currentTime: 0,\n            duration: 0,\n            paused: true,\n            playbackRate: 1,\n            play() {},\n            pause() {},\n            volume: 0\n        };\n\n        /** @private */\n        this.mediaType = params.mediaType.toLowerCase();\n        /** @private */\n        this.elementPosition = params.elementPosition;\n        /** @private */\n        this.peaks = null;\n        /** @private */\n        this.playbackRate = 1;\n        /** @private */\n        this.volume = 1;\n        /** @private */\n        this.buffer = null;\n        /** @private */\n        this.onPlayEnd = null;\n    }\n\n    /**\n     * Initialise the backend, called in `wavesurfer.createBackend()`\n     */\n    init() {\n        this.setPlaybackRate(this.params.audioRate);\n        this.createTimer();\n    }\n\n    /**\n     * Create a timer to provide a more precise `audioprocess` event.\n     *\n     * @private\n     */\n    createTimer() {\n        const onAudioProcess = () => {\n            if (this.isPaused()) {\n                return;\n            }\n            this.fireEvent('audioprocess', this.getCurrentTime());\n\n            // Call again in the next frame\n            const requestAnimationFrame =\n                window.requestAnimationFrame ||\n                window.webkitRequestAnimationFrame;\n            requestAnimationFrame(onAudioProcess);\n        };\n\n        this.on('play', onAudioProcess);\n\n        // Update the progress one more time to prevent it from being stuck in case of lower framerates\n        this.on('pause', () => {\n            this.fireEvent('audioprocess', this.getCurrentTime());\n        });\n    }\n\n    /**\n     * Create media element with url as its source,\n     * and append to container element.\n     *\n     * @param {string} url Path to media file\n     * @param {HTMLElement} container HTML element\n     * @param {number[]|number[][]} peaks Array of peak data\n     * @param {string} preload HTML 5 preload attribute value\n     */\n    load(url, container, peaks, preload) {\n        const media = document.createElement(this.mediaType);\n        media.controls = this.params.mediaControls;\n        media.autoplay = this.params.autoplay || false;\n        media.preload = preload == null ? 'auto' : preload;\n        media.src = url;\n        media.style.width = '100%';\n\n        const prevMedia = container.querySelector(this.mediaType);\n        if (prevMedia) {\n            container.removeChild(prevMedia);\n        }\n        container.appendChild(media);\n\n        this._load(media, peaks);\n    }\n\n    /**\n     * Load existing media element.\n     *\n     * @param {HTMLMediaElement} elt HTML5 Audio or Video element\n     * @param {number[]|number[][]} peaks Array of peak data\n     */\n    loadElt(elt, peaks) {\n        elt.controls = this.params.mediaControls;\n        elt.autoplay = this.params.autoplay || false;\n\n        this._load(elt, peaks);\n    }\n\n    /**\n     * Private method called by both load (from url)\n     * and loadElt (existing media element).\n     *\n     * @param {HTMLMediaElement} media HTML5 Audio or Video element\n     * @param {number[]|number[][]} peaks Array of peak data\n     * @private\n     */\n    _load(media, peaks) {\n        // load must be called manually on iOS, otherwise peaks won't draw\n        // until a user interaction triggers load --> 'ready' event\n        if (typeof media.load == 'function') {\n            // Resets the media element and restarts the media resource. Any\n            // pending events are discarded. How much media data is fetched is\n            // still affected by the preload attribute.\n            media.load();\n        }\n\n        media.addEventListener('error', () => {\n            this.fireEvent('error', 'Error loading media element');\n        });\n\n        media.addEventListener('canplay', () => {\n            this.fireEvent('canplay');\n        });\n\n        media.addEventListener('ended', () => {\n            this.fireEvent('finish');\n        });\n\n        // Listen to and relay play and pause events to enable\n        // playback control from the external media element\n        media.addEventListener('play', () => {\n            this.fireEvent('play');\n        });\n\n        media.addEventListener('pause', () => {\n            this.fireEvent('pause');\n        });\n\n        this.media = media;\n        this.peaks = peaks;\n        this.onPlayEnd = null;\n        this.buffer = null;\n        this.setPlaybackRate(this.playbackRate);\n        this.setVolume(this.volume);\n    }\n\n    /**\n     * Used by `wavesurfer.isPlaying()` and `wavesurfer.playPause()`\n     *\n     * @return {boolean}\n     */\n    isPaused() {\n        return !this.media || this.media.paused;\n    }\n\n    /**\n     * Used by `wavesurfer.getDuration()`\n     *\n     * @return {number}\n     */\n    getDuration() {\n        if (this.explicitDuration) {\n            return this.explicitDuration;\n        }\n        let duration = (this.buffer || this.media).duration;\n        if (duration >= Infinity) {\n            // streaming audio\n            duration = this.media.seekable.end(0);\n        }\n        return duration;\n    }\n\n    /**\n     * Returns the current time in seconds relative to the audioclip's\n     * duration.\n     *\n     * @return {number}\n     */\n    getCurrentTime() {\n        return this.media && this.media.currentTime;\n    }\n\n    /**\n     * Get the position from 0 to 1\n     *\n     * @return {number}\n     */\n    getPlayedPercents() {\n        return this.getCurrentTime() / this.getDuration() || 0;\n    }\n\n    /**\n     * Get the audio source playback rate.\n     *\n     * @return {number}\n     */\n    getPlaybackRate() {\n        return this.playbackRate || this.media.playbackRate;\n    }\n\n    /**\n     * Set the audio source playback rate.\n     *\n     * @param {number} value\n     */\n    setPlaybackRate(value) {\n        this.playbackRate = value || 1;\n        this.media.playbackRate = this.playbackRate;\n    }\n\n    /**\n     * Used by `wavesurfer.seekTo()`\n     *\n     * @param {number} start Position to start at in seconds\n     */\n    seekTo(start) {\n        if (start != null) {\n            this.media.currentTime = start;\n        }\n        this.clearPlayEnd();\n    }\n\n    /**\n     * Plays the loaded audio region.\n     *\n     * @param {number} start Start offset in seconds, relative to the beginning\n     * of a clip.\n     * @param {number} end When to stop, relative to the beginning of a clip.\n     * @emits MediaElement#play\n     * @return {Promise}\n     */\n    play(start, end) {\n        this.seekTo(start);\n        const promise = this.media.play();\n        end && this.setPlayEnd(end);\n\n        return promise;\n    }\n\n    /**\n     * Pauses the loaded audio.\n     *\n     * @emits MediaElement#pause\n     * @return {Promise}\n     */\n    pause() {\n        let promise;\n\n        if (this.media) {\n            promise = this.media.pause();\n        }\n        this.clearPlayEnd();\n\n        return promise;\n    }\n\n    /** @private */\n    setPlayEnd(end) {\n        this._onPlayEnd = time => {\n            if (time >= end) {\n                this.pause();\n                this.seekTo(end);\n            }\n        };\n        this.on('audioprocess', this._onPlayEnd);\n    }\n\n    /** @private */\n    clearPlayEnd() {\n        if (this._onPlayEnd) {\n            this.un('audioprocess', this._onPlayEnd);\n            this._onPlayEnd = null;\n        }\n    }\n\n    /**\n     * Compute the max and min value of the waveform when broken into\n     * <length> subranges.\n     *\n     * @param {number} length How many subranges to break the waveform into.\n     * @param {number} first First sample in the required range.\n     * @param {number} last Last sample in the required range.\n     * @return {number[]|number[][]} Array of 2*<length> peaks or array of\n     * arrays of peaks consisting of (max, min) values for each subrange.\n     */\n    getPeaks(length, first, last) {\n        if (this.buffer) {\n            return super.getPeaks(length, first, last);\n        }\n        return this.peaks || [];\n    }\n\n    /**\n     * Set the sink id for the media player\n     *\n     * @param {string} deviceId String value representing audio device id.\n     */\n    setSinkId(deviceId) {\n        if (deviceId) {\n            if (!this.media.setSinkId) {\n                return Promise.reject(\n                    new Error('setSinkId is not supported in your browser')\n                );\n            }\n            return this.media.setSinkId(deviceId);\n        }\n\n        return Promise.reject(new Error('Invalid deviceId: ' + deviceId));\n    }\n\n    /**\n     * Get the current volume\n     *\n     * @return {number} value A floating point value between 0 and 1.\n     */\n    getVolume() {\n        return this.volume || this.media.volume;\n    }\n\n    /**\n     * Set the audio volume\n     *\n     * @param {number} value A floating point value between 0 and 1.\n     */\n    setVolume(value) {\n        this.volume = value;\n        this.media.volume = this.volume;\n    }\n\n    /**\n     * This is called when wavesurfer is destroyed\n     *\n     */\n    destroy() {\n        this.pause();\n        this.unAll();\n\n        if (\n            this.params.removeMediaElementOnDestroy &&\n            this.media &&\n            this.media.parentNode\n        ) {\n            this.media.parentNode.removeChild(this.media);\n        }\n\n        this.media = null;\n    }\n}\n","import * as util from './util';\n/**\n * Parent class for renderers\n *\n * @extends {Observer}\n */\nexport default class Drawer extends util.Observer {\n    /**\n     * @param {HTMLElement} container The container node of the wavesurfer instance\n     * @param {WavesurferParams} params The wavesurfer initialisation options\n     */\n    constructor(container, params) {\n        super();\n        /** @private */\n        this.container = container;\n        /**\n         * @type {WavesurferParams}\n         * @private\n         */\n        this.params = params;\n        /**\n         * The width of the renderer\n         * @type {number}\n         */\n        this.width = 0;\n        /**\n         * The height of the renderer\n         * @type {number}\n         */\n        this.height = params.height * this.params.pixelRatio;\n        /** @private */\n        this.lastPos = 0;\n        /**\n         * The `<wave>` element which is added to the container\n         * @type {HTMLElement}\n         */\n        this.wrapper = null;\n    }\n\n    /**\n     * Alias of `util.style`\n     *\n     * @param {HTMLElement} el The element that the styles will be applied to\n     * @param {Object} styles The map of propName: attribute, both are used as-is\n     * @return {HTMLElement} el\n     */\n    style(el, styles) {\n        return util.style(el, styles);\n    }\n\n    /**\n     * Create the wrapper `<wave>` element, style it and set up the events for\n     * interaction\n     */\n    createWrapper() {\n        this.wrapper = this.container.appendChild(\n            document.createElement('wave')\n        );\n\n        this.style(this.wrapper, {\n            display: 'block',\n            position: 'relative',\n            userSelect: 'none',\n            webkitUserSelect: 'none',\n            height: this.params.height + 'px'\n        });\n\n        if (this.params.fillParent || this.params.scrollParent) {\n            this.style(this.wrapper, {\n                width: '100%',\n                overflowX: this.params.hideScrollbar ? 'hidden' : 'auto',\n                overflowY: 'hidden'\n            });\n        }\n\n        this.setupWrapperEvents();\n    }\n\n    /**\n     * Handle click event\n     *\n     * @param {Event} e Click event\n     * @param {?boolean} noPrevent Set to true to not call `e.preventDefault()`\n     * @return {number} Playback position from 0 to 1\n     */\n    handleEvent(e, noPrevent) {\n        !noPrevent && e.preventDefault();\n\n        const clientX = e.targetTouches\n            ? e.targetTouches[0].clientX\n            : e.clientX;\n        const bbox = this.wrapper.getBoundingClientRect();\n\n        const nominalWidth = this.width;\n        const parentWidth = this.getWidth();\n\n        let progress;\n\n        if (!this.params.fillParent && nominalWidth < parentWidth) {\n            progress =\n                (clientX - bbox.left) *\n                    (this.params.pixelRatio / nominalWidth) || 0;\n\n            if (progress > 1) {\n                progress = 1;\n            }\n        } else {\n            progress =\n                (clientX - bbox.left + this.wrapper.scrollLeft) /\n                    this.wrapper.scrollWidth || 0;\n        }\n\n        return progress;\n    }\n\n    /**\n     * @private\n     */\n    setupWrapperEvents() {\n        this.wrapper.addEventListener('click', e => {\n            const scrollbarHeight =\n                this.wrapper.offsetHeight - this.wrapper.clientHeight;\n            if (scrollbarHeight != 0) {\n                // scrollbar is visible.  Check if click was on it\n                const bbox = this.wrapper.getBoundingClientRect();\n                if (e.clientY >= bbox.bottom - scrollbarHeight) {\n                    // ignore mousedown as it was on the scrollbar\n                    return;\n                }\n            }\n\n            if (this.params.interact) {\n                this.fireEvent('click', e, this.handleEvent(e));\n            }\n        });\n\n        this.wrapper.addEventListener('scroll', e =>\n            this.fireEvent('scroll', e)\n        );\n    }\n\n    /**\n     * Draw peaks on the canvas\n     *\n     * @param {number[]|number[][]} peaks Can also be an array of arrays for split channel\n     * rendering\n     * @param {number} length The width of the area that should be drawn\n     * @param {number} start The x-offset of the beginning of the area that\n     * should be rendered\n     * @param {number} end The x-offset of the end of the area that should be\n     * rendered\n     */\n    drawPeaks(peaks, length, start, end) {\n        if (!this.setWidth(length)) {\n            this.clearWave();\n        }\n\n        this.params.barWidth\n            ? this.drawBars(peaks, 0, start, end)\n            : this.drawWave(peaks, 0, start, end);\n    }\n\n    /**\n     * Scroll to the beginning\n     */\n    resetScroll() {\n        if (this.wrapper !== null) {\n            this.wrapper.scrollLeft = 0;\n        }\n    }\n\n    /**\n     * Recenter the viewport at a certain percent of the waveform\n     *\n     * @param {number} percent Value from 0 to 1 on the waveform\n     */\n    recenter(percent) {\n        const position = this.wrapper.scrollWidth * percent;\n        this.recenterOnPosition(position, true);\n    }\n\n    /**\n     * Recenter the viewport on a position, either scroll there immediately or\n     * in steps of 5 pixels\n     *\n     * @param {number} position X-offset in pixels\n     * @param {boolean} immediate Set to true to immediately scroll somewhere\n     */\n    recenterOnPosition(position, immediate) {\n        const scrollLeft = this.wrapper.scrollLeft;\n        const half = ~~(this.wrapper.clientWidth / 2);\n        const maxScroll = this.wrapper.scrollWidth - this.wrapper.clientWidth;\n        let target = position - half;\n        let offset = target - scrollLeft;\n\n        if (maxScroll == 0) {\n            // no need to continue if scrollbar is not there\n            return;\n        }\n\n        // if the cursor is currently visible...\n        if (!immediate && -half <= offset && offset < half) {\n            // we'll limit the \"re-center\" rate.\n            const rate = 5;\n            offset = Math.max(-rate, Math.min(rate, offset));\n            target = scrollLeft + offset;\n        }\n\n        // limit target to valid range (0 to maxScroll)\n        target = Math.max(0, Math.min(maxScroll, target));\n        // no use attempting to scroll if we're not moving\n        if (target != scrollLeft) {\n            this.wrapper.scrollLeft = target;\n        }\n    }\n\n    /**\n     * Get the current scroll position in pixels\n     *\n     * @return {number}\n     */\n    getScrollX() {\n        const pixelRatio = this.params.pixelRatio;\n        let x = Math.round(this.wrapper.scrollLeft * pixelRatio);\n\n        // In cases of elastic scroll (safari with mouse wheel) you can\n        // scroll beyond the limits of the container\n        // Calculate and floor the scrollable extent to make sure an out\n        // of bounds value is not returned\n        // Ticket #1312\n        if (this.params.scrollParent) {\n            const maxScroll = ~~(\n                this.wrapper.scrollWidth * pixelRatio -\n                this.getWidth()\n            );\n            x = Math.min(maxScroll, Math.max(0, x));\n        }\n\n        return x;\n    }\n\n    /**\n     * Get the width of the container\n     *\n     * @return {number}\n     */\n    getWidth() {\n        return Math.round(this.container.clientWidth * this.params.pixelRatio);\n    }\n\n    /**\n     * Set the width of the container\n     *\n     * @param {number} width\n     */\n    setWidth(width) {\n        if (this.width == width) {\n            return false;\n        }\n\n        this.width = width;\n\n        if (this.params.fillParent || this.params.scrollParent) {\n            this.style(this.wrapper, {\n                width: ''\n            });\n        } else {\n            this.style(this.wrapper, {\n                width: ~~(this.width / this.params.pixelRatio) + 'px'\n            });\n        }\n\n        this.updateSize();\n        return true;\n    }\n\n    /**\n     * Set the height of the container\n     *\n     * @param {number} height\n     */\n    setHeight(height) {\n        if (height == this.height) {\n            return false;\n        }\n        this.height = height;\n\n        this.style(this.wrapper, {\n            height: ~~(this.height / this.params.pixelRatio) + 'px'\n        });\n\n        this.updateSize();\n        return true;\n    }\n\n    /**\n     * Called by wavesurfer when progress should be renderered\n     *\n     * @param {number} progress From 0 to 1\n     */\n    progress(progress) {\n        const minPxDelta = 1 / this.params.pixelRatio;\n        const pos = Math.round(progress * this.width) * minPxDelta;\n\n        if (pos < this.lastPos || pos - this.lastPos >= minPxDelta) {\n            this.lastPos = pos;\n\n            if (this.params.scrollParent && this.params.autoCenter) {\n                const newPos = ~~(this.wrapper.scrollWidth * progress);\n                this.recenterOnPosition(newPos);\n            }\n\n            this.updateProgress(pos);\n        }\n    }\n\n    /**\n     * This is called when wavesurfer is destroyed\n     */\n    destroy() {\n        this.unAll();\n        if (this.wrapper) {\n            if (this.wrapper.parentNode == this.container) {\n                this.container.removeChild(this.wrapper);\n            }\n            this.wrapper = null;\n        }\n    }\n\n    /* Renderer-specific methods */\n\n    /**\n     * Called after cursor related params have changed.\n     *\n     * @abstract\n     */\n    updateCursor() {}\n\n    /**\n     * Called when the size of the container changes so the renderer can adjust\n     *\n     * @abstract\n     */\n    updateSize() {}\n\n    /**\n     * Draw a waveform with bars\n     *\n     * @abstract\n     * @param {number[]|number[][]} peaks Can also be an array of arrays for split channel\n     * rendering\n     * @param {number} channelIndex The index of the current channel. Normally\n     * should be 0\n     * @param {number} start The x-offset of the beginning of the area that\n     * should be rendered\n     * @param {number} end The x-offset of the end of the area that should be\n     * rendered\n     */\n    drawBars(peaks, channelIndex, start, end) {}\n\n    /**\n     * Draw a waveform\n     *\n     * @abstract\n     * @param {number[]|number[][]} peaks Can also be an array of arrays for split channel\n     * rendering\n     * @param {number} channelIndex The index of the current channel. Normally\n     * should be 0\n     * @param {number} start The x-offset of the beginning of the area that\n     * should be rendered\n     * @param {number} end The x-offset of the end of the area that should be\n     * rendered\n     */\n    drawWave(peaks, channelIndex, start, end) {}\n\n    /**\n     * Clear the waveform\n     *\n     * @abstract\n     */\n    clearWave() {}\n\n    /**\n     * Render the new progress\n     *\n     * @abstract\n     * @param {number} position X-Offset of progress position in pixels\n     */\n    updateProgress(position) {}\n}\n","import Drawer from './drawer';\nimport * as util from './util';\n\n/**\n * @typedef {Object} CanvasEntry\n * @private\n * @property {HTMLElement} wave The wave node\n * @property {CanvasRenderingContext2D} waveCtx The canvas rendering context\n * @property {?HTMLElement} progress The progress wave node\n * @property {?CanvasRenderingContext2D} progressCtx The progress wave canvas\n * rendering context\n * @property {?number} start Start of the area the canvas should render, between 0 and 1\n * @property {?number} end End of the area the canvas should render, between 0 and 1\n */\n\n/**\n * MultiCanvas renderer for wavesurfer. Is currently the default and sole built\n * in renderer.\n */\nexport default class MultiCanvas extends Drawer {\n    /**\n     * @param {HTMLElement} container The container node of the wavesurfer instance\n     * @param {WavesurferParams} params The wavesurfer initialisation options\n     */\n    constructor(container, params) {\n        super(container, params);\n        /**\n         * @type {number}\n         * @private\n         */\n        this.maxCanvasWidth = params.maxCanvasWidth;\n        /**\n         * @private\n         * @type {number}\n         */\n        this.maxCanvasElementWidth = Math.round(\n            params.maxCanvasWidth / params.pixelRatio\n        );\n\n        /**\n         * Whether or not the progress wave is renderered. If the `waveColor`\n         * and `progressColor` are the same colour it is not.\n         * @type {boolean}\n         */\n        this.hasProgressCanvas = params.waveColor != params.progressColor;\n        /**\n         * @private\n         * @type {number}\n         */\n        this.halfPixel = 0.5 / params.pixelRatio;\n        /**\n         * @private\n         * @type {Array}\n         */\n        this.canvases = [];\n        /** @private */\n        this.progressWave = null;\n    }\n\n    /**\n     * Initialise the drawer\n     */\n    init() {\n        this.createWrapper();\n        this.createElements();\n    }\n\n    /**\n     * Create the canvas elements and style them\n     *\n     * @private\n     */\n    createElements() {\n        this.progressWave = this.wrapper.appendChild(\n            this.style(document.createElement('wave'), {\n                position: 'absolute',\n                zIndex: 3,\n                left: 0,\n                top: 0,\n                bottom: 0,\n                overflow: 'hidden',\n                width: '0',\n                display: 'none',\n                boxSizing: 'border-box',\n                borderRightStyle: 'solid',\n                pointerEvents: 'none'\n            })\n        );\n\n        this.addCanvas();\n        this.updateCursor();\n    }\n\n    /**\n     * Update cursor style from params.\n     */\n    updateCursor() {\n        this.style(this.progressWave, {\n            borderRightWidth: this.params.cursorWidth + 'px',\n            borderRightColor: this.params.cursorColor\n        });\n    }\n\n    /**\n     * Adjust to the updated size by adding or removing canvases\n     */\n    updateSize() {\n        const totalWidth = Math.round(this.width / this.params.pixelRatio);\n        const requiredCanvases = Math.ceil(\n            totalWidth / this.maxCanvasElementWidth\n        );\n\n        while (this.canvases.length < requiredCanvases) {\n            this.addCanvas();\n        }\n\n        while (this.canvases.length > requiredCanvases) {\n            this.removeCanvas();\n        }\n\n        this.canvases.forEach((entry, i) => {\n            // Add some overlap to prevent vertical white stripes, keep the width even for simplicity.\n            let canvasWidth =\n                this.maxCanvasWidth + 2 * Math.ceil(this.params.pixelRatio / 2);\n\n            if (i == this.canvases.length - 1) {\n                canvasWidth =\n                    this.width -\n                    this.maxCanvasWidth * (this.canvases.length - 1);\n            }\n\n            this.updateDimensions(entry, canvasWidth, this.height);\n            this.clearWaveForEntry(entry);\n        });\n    }\n\n    /**\n     * Add a canvas to the canvas list\n     *\n     * @private\n     */\n    addCanvas() {\n        const entry = {};\n        const leftOffset = this.maxCanvasElementWidth * this.canvases.length;\n\n        entry.wave = this.wrapper.appendChild(\n            this.style(document.createElement('canvas'), {\n                position: 'absolute',\n                zIndex: 2,\n                left: leftOffset + 'px',\n                top: 0,\n                bottom: 0,\n                height: '100%',\n                pointerEvents: 'none'\n            })\n        );\n        entry.waveCtx = entry.wave.getContext('2d');\n\n        if (this.hasProgressCanvas) {\n            entry.progress = this.progressWave.appendChild(\n                this.style(document.createElement('canvas'), {\n                    position: 'absolute',\n                    left: leftOffset + 'px',\n                    top: 0,\n                    bottom: 0,\n                    height: '100%'\n                })\n            );\n            entry.progressCtx = entry.progress.getContext('2d');\n        }\n\n        this.canvases.push(entry);\n    }\n\n    /**\n     * Pop one canvas from the list\n     *\n     * @private\n     */\n    removeCanvas() {\n        const lastEntry = this.canvases.pop();\n        lastEntry.wave.parentElement.removeChild(lastEntry.wave);\n        if (this.hasProgressCanvas) {\n            lastEntry.progress.parentElement.removeChild(lastEntry.progress);\n        }\n    }\n\n    /**\n     * Update the dimensions of a canvas element\n     *\n     * @private\n     * @param {CanvasEntry} entry\n     * @param {number} width The new width of the element\n     * @param {number} height The new height of the element\n     */\n    updateDimensions(entry, width, height) {\n        const elementWidth = Math.round(width / this.params.pixelRatio);\n        const totalWidth = Math.round(this.width / this.params.pixelRatio);\n\n        // Where the canvas starts and ends in the waveform, represented as a decimal between 0 and 1.\n        entry.start = entry.waveCtx.canvas.offsetLeft / totalWidth || 0;\n        entry.end = entry.start + elementWidth / totalWidth;\n\n        entry.waveCtx.canvas.width = width;\n        entry.waveCtx.canvas.height = height;\n        this.style(entry.waveCtx.canvas, { width: elementWidth + 'px' });\n\n        this.style(this.progressWave, { display: 'block' });\n\n        if (this.hasProgressCanvas) {\n            entry.progressCtx.canvas.width = width;\n            entry.progressCtx.canvas.height = height;\n            this.style(entry.progressCtx.canvas, {\n                width: elementWidth + 'px'\n            });\n        }\n    }\n\n    /**\n     * Clear the whole waveform\n     */\n    clearWave() {\n        this.canvases.forEach(entry => this.clearWaveForEntry(entry));\n    }\n\n    /**\n     * Clear one canvas\n     *\n     * @private\n     * @param {CanvasEntry} entry\n     */\n    clearWaveForEntry(entry) {\n        entry.waveCtx.clearRect(\n            0,\n            0,\n            entry.waveCtx.canvas.width,\n            entry.waveCtx.canvas.height\n        );\n        if (this.hasProgressCanvas) {\n            entry.progressCtx.clearRect(\n                0,\n                0,\n                entry.progressCtx.canvas.width,\n                entry.progressCtx.canvas.height\n            );\n        }\n    }\n\n    /**\n     * Draw a waveform with bars\n     *\n     * @param {number[]|number[][]} peaks Can also be an array of arrays for split channel\n     * rendering\n     * @param {number} channelIndex The index of the current channel. Normally\n     * should be 0. Must be an integer.\n     * @param {number} start The x-offset of the beginning of the area that\n     * should be rendered\n     * @param {number} end The x-offset of the end of the area that should be\n     * rendered\n     */\n    drawBars(peaks, channelIndex, start, end) {\n        return this.prepareDraw(\n            peaks,\n            channelIndex,\n            start,\n            end,\n            ({ absmax, hasMinVals, height, offsetY, halfH, peaks }) => {\n                // if drawBars was called within ws.empty we don't pass a start and\n                // don't want anything to happen\n                if (start === undefined) {\n                    return;\n                }\n                // Skip every other value if there are negatives.\n                const peakIndexScale = hasMinVals ? 2 : 1;\n                const length = peaks.length / peakIndexScale;\n                const bar = this.params.barWidth * this.params.pixelRatio;\n                const gap =\n                    this.params.barGap === null\n                        ? Math.max(this.params.pixelRatio, ~~(bar / 2))\n                        : Math.max(\n                              this.params.pixelRatio,\n                              this.params.barGap * this.params.pixelRatio\n                          );\n                const step = bar + gap;\n\n                const scale = length / this.width;\n                const first = start;\n                const last = end;\n                let i;\n\n                for (i = first; i < last; i += step) {\n                    const peak =\n                        peaks[Math.floor(i * scale * peakIndexScale)] || 0;\n                    const h = Math.round((peak / absmax) * halfH);\n                    this.fillRect(\n                        i + this.halfPixel,\n                        halfH - h + offsetY,\n                        bar + this.halfPixel,\n                        h * 2\n                    );\n                }\n            }\n        );\n    }\n\n    /**\n     * Draw a waveform\n     *\n     * @param {number[]|number[][]} peaks Can also be an array of arrays for split channel\n     * rendering\n     * @param {number} channelIndex The index of the current channel. Normally\n     * should be 0\n     * @param {number?} start The x-offset of the beginning of the area that\n     * should be rendered (If this isn't set only a flat line is rendered)\n     * @param {number?} end The x-offset of the end of the area that should be\n     * rendered\n     */\n    drawWave(peaks, channelIndex, start, end) {\n        return this.prepareDraw(\n            peaks,\n            channelIndex,\n            start,\n            end,\n            ({ absmax, hasMinVals, height, offsetY, halfH, peaks }) => {\n                if (!hasMinVals) {\n                    const reflectedPeaks = [];\n                    const len = peaks.length;\n                    let i;\n                    for (i = 0; i < len; i++) {\n                        reflectedPeaks[2 * i] = peaks[i];\n                        reflectedPeaks[2 * i + 1] = -peaks[i];\n                    }\n                    peaks = reflectedPeaks;\n                }\n\n                // if drawWave was called within ws.empty we don't pass a start and\n                // end and simply want a flat line\n                if (start !== undefined) {\n                    this.drawLine(peaks, absmax, halfH, offsetY, start, end);\n                }\n\n                // Always draw a median line\n                this.fillRect(\n                    0,\n                    halfH + offsetY - this.halfPixel,\n                    this.width,\n                    this.halfPixel\n                );\n            }\n        );\n    }\n\n    /**\n     * Tell the canvas entries to render their portion of the waveform\n     *\n     * @private\n     * @param {number[]} peaks Peak data\n     * @param {number} absmax Maximum peak value (absolute)\n     * @param {number} halfH Half the height of the waveform\n     * @param {number} offsetY Offset to the top\n     * @param {number} start The x-offset of the beginning of the area that\n     * should be rendered\n     * @param {number} end The x-offset of the end of the area that\n     * should be rendered\n     */\n    drawLine(peaks, absmax, halfH, offsetY, start, end) {\n        this.canvases.forEach(entry => {\n            this.setFillStyles(entry);\n            this.drawLineToContext(\n                entry,\n                entry.waveCtx,\n                peaks,\n                absmax,\n                halfH,\n                offsetY,\n                start,\n                end\n            );\n            this.drawLineToContext(\n                entry,\n                entry.progressCtx,\n                peaks,\n                absmax,\n                halfH,\n                offsetY,\n                start,\n                end\n            );\n        });\n    }\n\n    /**\n     * Render the actual waveform line on a canvas\n     *\n     * @private\n     * @param {CanvasEntry} entry\n     * @param {Canvas2DContextAttributes} ctx Essentially `entry.[wave|progress]Ctx`\n     * @param {number[]} peaks\n     * @param {number} absmax Maximum peak value (absolute)\n     * @param {number} halfH Half the height of the waveform\n     * @param {number} offsetY Offset to the top\n     * @param {number} start The x-offset of the beginning of the area that\n     * should be rendered\n     * @param {number} end The x-offset of the end of the area that\n     * should be rendered\n     */\n    drawLineToContext(entry, ctx, peaks, absmax, halfH, offsetY, start, end) {\n        if (!ctx) {\n            return;\n        }\n\n        const length = peaks.length / 2;\n        const scale =\n            this.params.fillParent && this.width != length\n                ? this.width / length\n                : 1;\n\n        const first = Math.round(length * entry.start);\n        // Use one more peak value to make sure we join peaks at ends -- unless,\n        // of course, this is the last canvas.\n        const last = Math.round(length * entry.end) + 1;\n        if (first > end || last < start) {\n            return;\n        }\n        const canvasStart = Math.min(first, start);\n        const canvasEnd = Math.max(last, end);\n        let i;\n        let j;\n\n        ctx.beginPath();\n        ctx.moveTo(\n            (canvasStart - first) * scale + this.halfPixel,\n            halfH + offsetY\n        );\n\n        for (i = canvasStart; i < canvasEnd; i++) {\n            const peak = peaks[2 * i] || 0;\n            const h = Math.round((peak / absmax) * halfH);\n            ctx.lineTo(\n                (i - first) * scale + this.halfPixel,\n                halfH - h + offsetY\n            );\n        }\n\n        // Draw the bottom edge going backwards, to make a single\n        // closed hull to fill.\n        for (j = canvasEnd - 1; j >= canvasStart; j--) {\n            const peak = peaks[2 * j + 1] || 0;\n            const h = Math.round((peak / absmax) * halfH);\n            ctx.lineTo(\n                (j - first) * scale + this.halfPixel,\n                halfH - h + offsetY\n            );\n        }\n\n        ctx.closePath();\n        ctx.fill();\n    }\n\n    /**\n     * Draw a rectangle on the waveform\n     *\n     * @param {number} x\n     * @param {number} y\n     * @param {number} width\n     * @param {number} height\n     */\n    fillRect(x, y, width, height) {\n        const startCanvas = Math.floor(x / this.maxCanvasWidth);\n        const endCanvas = Math.min(\n            Math.ceil((x + width) / this.maxCanvasWidth) + 1,\n            this.canvases.length\n        );\n        let i;\n        for (i = startCanvas; i < endCanvas; i++) {\n            const entry = this.canvases[i];\n            const leftOffset = i * this.maxCanvasWidth;\n\n            const intersection = {\n                x1: Math.max(x, i * this.maxCanvasWidth),\n                y1: y,\n                x2: Math.min(\n                    x + width,\n                    i * this.maxCanvasWidth + entry.waveCtx.canvas.width\n                ),\n                y2: y + height\n            };\n\n            if (intersection.x1 < intersection.x2) {\n                this.setFillStyles(entry);\n\n                this.fillRectToContext(\n                    entry.waveCtx,\n                    intersection.x1 - leftOffset,\n                    intersection.y1,\n                    intersection.x2 - intersection.x1,\n                    intersection.y2 - intersection.y1\n                );\n\n                this.fillRectToContext(\n                    entry.progressCtx,\n                    intersection.x1 - leftOffset,\n                    intersection.y1,\n                    intersection.x2 - intersection.x1,\n                    intersection.y2 - intersection.y1\n                );\n            }\n        }\n    }\n\n    /**\n     * Performs preparation tasks and calculations which are shared by drawBars and drawWave\n     *\n     * @private\n     * @param {number[]|number[][]} peaks Can also be an array of arrays for split channel\n     * rendering\n     * @param {number} channelIndex The index of the current channel. Normally\n     * should be 0\n     * @param {number?} start The x-offset of the beginning of the area that\n     * should be rendered (If this isn't set only a flat line is rendered)\n     * @param {number?} end The x-offset of the end of the area that should be\n     * rendered\n     * @param {function} fn The render function to call\n     */\n    prepareDraw(peaks, channelIndex, start, end, fn) {\n        return util.frame(() => {\n            // Split channels and call this function with the channelIndex set\n            if (peaks[0] instanceof Array) {\n                const channels = peaks;\n                if (this.params.splitChannels) {\n                    this.setHeight(\n                        channels.length *\n                            this.params.height *\n                            this.params.pixelRatio\n                    );\n                    return channels.forEach((channelPeaks, i) =>\n                        this.prepareDraw(channelPeaks, i, start, end, fn)\n                    );\n                }\n                peaks = channels[0];\n            }\n            // calculate maximum modulation value, either from the barHeight\n            // parameter or if normalize=true from the largest value in the peak\n            // set\n            let absmax = 1 / this.params.barHeight;\n            if (this.params.normalize) {\n                const max = util.max(peaks);\n                const min = util.min(peaks);\n                absmax = -min > max ? -min : max;\n            }\n\n            // Bar wave draws the bottom only as a reflection of the top,\n            // so we don't need negative values\n            const hasMinVals = [].some.call(peaks, val => val < 0);\n            const height = this.params.height * this.params.pixelRatio;\n            const offsetY = height * channelIndex || 0;\n            const halfH = height / 2;\n\n            return fn({\n                absmax: absmax,\n                hasMinVals: hasMinVals,\n                height: height,\n                offsetY: offsetY,\n                halfH: halfH,\n                peaks: peaks\n            });\n        })();\n    }\n\n    /**\n     * Draw the actual rectangle on a canvas\n     *\n     * @private\n     * @param {Canvas2DContextAttributes} ctx\n     * @param {number} x\n     * @param {number} y\n     * @param {number} width\n     * @param {number} height\n     */\n    fillRectToContext(ctx, x, y, width, height) {\n        if (!ctx) {\n            return;\n        }\n        ctx.fillRect(x, y, width, height);\n    }\n\n    /**\n     * Set the fill styles for a certain entry (wave and progress)\n     *\n     * @private\n     * @param {CanvasEntry} entry\n     */\n    setFillStyles(entry) {\n        entry.waveCtx.fillStyle = this.params.waveColor;\n        if (this.hasProgressCanvas) {\n            entry.progressCtx.fillStyle = this.params.progressColor;\n        }\n    }\n\n    /**\n     * Return image data of the waveform\n     *\n     * @param {string} type='image/png' An optional value of a format type.\n     * @param {number} quality=0.92 An optional value between 0 and 1.\n     * @return {string|string[]} images A data URL or an array of data URLs\n     */\n    getImage(type, quality) {\n        const images = this.canvases.map(entry =>\n            entry.wave.toDataURL(type, quality)\n        );\n        return images.length > 1 ? images : images[0];\n    }\n\n    /**\n     * Render the new progress\n     *\n     * @param {number} position X-Offset of progress position in pixels\n     */\n    updateProgress(position) {\n        this.style(this.progressWave, { width: position + 'px' });\n    }\n}\n","function preventClickHandler(e) {\n    e.stopPropagation();\n    document.body.removeEventListener('click', preventClickHandler, true);\n}\n\nexport default function preventClick(values) {\n    document.body.addEventListener('click', preventClickHandler, true);\n}\n","/**\n * Returns a function, that, as long as it continues to be invoked, will not\n * be triggered. The function will be called after it stops being called for\n * N milliseconds. If `immediate` is passed, trigger the function on the\n * leading edge, instead of the trailing. The function also has a property 'clear' \n * that is a function which will clear the timer to prevent previously scheduled executions. \n *\n * @source underscore.js\n * @see http://unscriptable.com/2009/03/20/debouncing-javascript-methods/\n * @param {Function} function to wrap\n * @param {Number} timeout in ms (`100`)\n * @param {Boolean} whether to execute at the beginning (`false`)\n * @api public\n */\n\nmodule.exports = function debounce(func, wait, immediate){\n  var timeout, args, context, timestamp, result;\n  if (null == wait) wait = 100;\n\n  function later() {\n    var last = Date.now() - timestamp;\n\n    if (last < wait && last >= 0) {\n      timeout = setTimeout(later, wait - last);\n    } else {\n      timeout = null;\n      if (!immediate) {\n        result = func.apply(context, args);\n        context = args = null;\n      }\n    }\n  };\n\n  var debounced = function(){\n    context = this;\n    args = arguments;\n    timestamp = Date.now();\n    var callNow = immediate && !timeout;\n    if (!timeout) timeout = setTimeout(later, wait);\n    if (callNow) {\n      result = func.apply(context, args);\n      context = args = null;\n    }\n\n    return result;\n  };\n\n  debounced.clear = function() {\n    if (timeout) {\n      clearTimeout(timeout);\n      timeout = null;\n    }\n  };\n  \n  debounced.flush = function() {\n    if (timeout) {\n      result = func.apply(context, args);\n      context = args = null;\n      \n      clearTimeout(timeout);\n      timeout = null;\n    }\n  };\n\n  return debounced;\n};\n","import reqAnimationFrame from './request-animation-frame';\n\n/**\n * Create a function which will be called at the next requestAnimationFrame\n * cycle\n *\n * @param {function} func The function to call\n *\n * @return {func} The function wrapped within a requestAnimationFrame\n */\nexport default function frame(func) {\n    return (...args) => reqAnimationFrame(() => func(...args));\n}\n","/**\n * Apply a map of styles to an element\n *\n * @param {HTMLElement} el The element that the styles will be applied to\n * @param {Object} styles The map of propName: attribute, both are used as-is\n *\n * @return {HTMLElement} el\n */\nexport default function style(el, styles) {\n    Object.keys(styles).forEach(prop => {\n        if (el.style[prop] !== styles[prop]) {\n            el.style[prop] = styles[prop];\n        }\n    });\n    return el;\n}\n","/**\n * Extend an object shallowly with others\n *\n * @param {Object} dest The target object\n * @param {Object[]} sources The objects to use for extending\n *\n * @return {Object} Merged object\n */\nexport default function extend(dest, ...sources) {\n    sources.forEach(source => {\n        Object.keys(source).forEach(key => {\n            dest[key] = source[key];\n        });\n    });\n    return dest;\n}\n","/**\n * Get the smallest value\n *\n * @param   {Array} values Array of numbers\n * @returns {Number}       Smallest number found\n */\nexport default function min(values) {\n    let smallest = Number(Infinity);\n    Object.keys(values).forEach(i => {\n        if (values[i] < smallest) {\n            smallest = values[i];\n        }\n    });\n    return smallest;\n}\n","/**\n * Get the largest value\n *\n * @param   {Array} values Array of numbers\n * @returns {Number} Largest number found\n */\nexport default function max(values) {\n    let largest = -Infinity;\n    Object.keys(values).forEach(i => {\n        if (values[i] > largest) {\n            largest = values[i];\n        }\n    });\n    return largest;\n}\n","/**\n * Get a random prefixed ID\n *\n * @returns {String} Random ID\n */\nexport default function getId() {\n    return (\n        'wavesurfer_' +\n        Math.random()\n            .toString(32)\n            .substring(2)\n    );\n}\n","import Observer from './observer';\n\n/**\n * Perform an ajax request\n *\n * @param {Options} options Description\n *\n * @returns {Object} Observer instance\n */\nexport default function ajax(options) {\n    const instance = new Observer();\n    const xhr = new XMLHttpRequest();\n    let fired100 = false;\n    xhr.open(options.method || 'GET', options.url, true);\n    xhr.responseType = options.responseType || 'json';\n\n    if (options.xhr) {\n        if (options.xhr.requestHeaders) {\n            // add custom request headers\n            options.xhr.requestHeaders.forEach(header => {\n                xhr.setRequestHeader(header.key, header.value);\n            });\n        }\n        if (options.xhr.withCredentials) {\n            // use credentials\n            xhr.withCredentials = true;\n        }\n    }\n\n    xhr.addEventListener('progress', e => {\n        instance.fireEvent('progress', e);\n        if (e.lengthComputable && e.loaded == e.total) {\n            fired100 = true;\n        }\n    });\n    xhr.addEventListener('load', e => {\n        if (!fired100) {\n            instance.fireEvent('progress', e);\n        }\n        instance.fireEvent('load', e);\n        if (200 == xhr.status || 206 == xhr.status) {\n            instance.fireEvent('success', xhr.response, e);\n        } else {\n            instance.fireEvent('error', e);\n        }\n    });\n    xhr.addEventListener('error', e => instance.fireEvent('error', e));\n    xhr.send();\n    instance.xhr = xhr;\n    return instance;\n}\n","import * as util from './util';\nimport MultiCanvas from './drawer.multicanvas';\nimport WebAudio from './webaudio';\nimport MediaElement from './mediaelement';\nimport PeakCache from './peakcache';\n\n/*\n * This work is licensed under a BSD-3-Clause License.\n */\n\n/** @external {HTMLElement} https://developer.mozilla.org/en/docs/Web/API/HTMLElement */\n/** @external {OfflineAudioContext} https://developer.mozilla.org/en-US/docs/Web/API/OfflineAudioContext */\n/** @external {File} https://developer.mozilla.org/en-US/docs/Web/API/File */\n/** @external {Blob} https://developer.mozilla.org/en-US/docs/Web/API/Blob */\n/** @external {CanvasRenderingContext2D} https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D */\n/** @external {MediaStreamConstraints} https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamConstraints */\n/** @external {AudioNode} https://developer.mozilla.org/de/docs/Web/API/AudioNode */\n\n/**\n * @typedef {Object} WavesurferParams\n * @property {AudioContext} audioContext=null Use your own previously\n * initialized AudioContext or leave blank.\n * @property {number} audioRate=1 Speed at which to play audio. Lower number is\n * slower.\n * @property {ScriptProcessorNode} audioScriptProcessor=null Use your own previously\n * initialized ScriptProcessorNode or leave blank.\n * @property {boolean} autoCenter=true If a scrollbar is present, center the\n * waveform around the progress\n * @property {string} backend='WebAudio' `'WebAudio'|'MediaElement'` In most cases\n * you don't have to set this manually. MediaElement is a fallback for\n * unsupported browsers.\n * @property {number} barHeight=1 The height of the wave\n * @property {number} barGap=null The optional spacing between bars of the wave,\n * if not provided will be calculated in legacy format.\n * @property {boolean} closeAudioContext=false Close and nullify all audio\n * contexts when the destroy method is called.\n * @property {!string|HTMLElement} container CSS selector or HTML element where\n * the waveform should be drawn. This is the only required parameter.\n * @property {string} cursorColor='#333' The fill color of the cursor indicating\n * the playhead position.\n * @property {number} cursorWidth=1 Measured in pixels.\n * @property {boolean} fillParent=true Whether to fill the entire container or\n * draw only according to `minPxPerSec`.\n * @property {boolean} forceDecode=false Force decoding of audio using web audio\n * when zooming to get a more detailed waveform.\n * @property {number} height=128 The height of the waveform. Measured in\n * pixels.\n * @property {boolean} hideScrollbar=false Whether to hide the horizontal\n * scrollbar when one would normally be shown.\n * @property {boolean} interact=true Whether the mouse interaction will be\n * enabled at initialization. You can switch this parameter at any time later\n * on.\n * @property {boolean} loopSelection=true (Use with regions plugin) Enable\n * looping of selected regions\n * @property {number} maxCanvasWidth=4000 Maximum width of a single canvas in\n * pixels, excluding a small overlap (2 * `pixelRatio`, rounded up to the next\n * even integer). If the waveform is longer than this value, additional canvases\n * will be used to render the waveform, which is useful for very large waveforms\n * that may be too wide for browsers to draw on a single canvas.\n * @property {boolean} mediaControls=false (Use with backend `MediaElement`)\n * this enables the native controls for the media element\n * @property {string} mediaType='audio' (Use with backend `MediaElement`)\n * `'audio'|'video'`\n * @property {number} minPxPerSec=20 Minimum number of pixels per second of\n * audio.\n * @property {boolean} normalize=false If true, normalize by the maximum peak\n * instead of 1.0.\n * @property {boolean} partialRender=false Use the PeakCache to improve\n * rendering speed of large waveforms\n * @property {number} pixelRatio=window.devicePixelRatio The pixel ratio used to\n * calculate display\n * @property {PluginDefinition[]} plugins=[] An array of plugin definitions to\n * register during instantiation, they will be directly initialised unless they\n * are added with the `deferInit` property set to true.\n * @property {string} progressColor='#555' The fill color of the part of the\n * waveform behind the cursor.\n * @property {boolean} removeMediaElementOnDestroy=true Set to false to keep the\n * media element in the DOM when the player is destroyed. This is useful when\n * reusing an existing media element via the `loadMediaElement` method.\n * @property {Object} renderer=MultiCanvas Can be used to inject a custom\n * renderer.\n * @property {boolean|number} responsive=false If set to `true` resize the\n * waveform, when the window is resized. This is debounced with a `100ms`\n * timeout by default. If this parameter is a number it represents that timeout.\n * @property {boolean} scrollParent=false Whether to scroll the container with a\n * lengthy waveform. Otherwise the waveform is shrunk to the container width\n * (see fillParent).\n * @property {number} skipLength=2 Number of seconds to skip with the\n * skipForward() and skipBackward() methods.\n * @property {boolean} splitChannels=false Render with seperate waveforms for\n * the channels of the audio\n * @property {string} waveColor='#999' The fill color of the waveform after the\n * cursor.\n * @property {object} xhr={} XHR options.\n */\n\n/**\n * @typedef {Object} PluginDefinition\n * @desc The Object used to describe a plugin\n * @example wavesurfer.addPlugin(pluginDefinition);\n * @property {string} name The name of the plugin, the plugin instance will be\n * added as a property to the wavesurfer instance under this name\n * @property {?Object} staticProps The properties that should be added to the\n * wavesurfer instance as static properties\n * @property {?boolean} deferInit Don't initialise plugin\n * automatically\n * @property {Object} params={} The plugin parameters, they are the first parameter\n * passed to the plugin class constructor function\n * @property {PluginClass} instance The plugin instance factory, is called with\n * the dependency specified in extends. Returns the plugin class.\n */\n\n/**\n * @interface PluginClass\n *\n * @desc This is the interface which is implemented by all plugin classes. Note\n * that this only turns into an observer after being passed through\n * `wavesurfer.addPlugin`.\n *\n * @extends {Observer}\n */\nclass PluginClass {\n    /**\n     * Plugin definition factory\n     *\n     * This function must be used to create a plugin definition which can be\n     * used by wavesurfer to correctly instantiate the plugin.\n     *\n     * @param  {Object} params={} The plugin params (specific to the plugin)\n     * @return {PluginDefinition} an object representing the plugin\n     */\n    create(params) {}\n    /**\n     * Construct the plugin\n     *\n     * @param {Object} ws The wavesurfer instance\n     * @param {Object} params={} The plugin params (specific to the plugin)\n     */\n    constructor(ws, params) {}\n    /**\n     * Initialise the plugin\n     *\n     * Start doing something. This is called by\n     * `wavesurfer.initPlugin(pluginName)`\n     */\n    init() {}\n    /**\n     * Destroy the plugin instance\n     *\n     * Stop doing something. This is called by\n     * `wavesurfer.destroyPlugin(pluginName)`\n     */\n    destroy() {}\n}\n\n/**\n * WaveSurfer core library class\n *\n * @extends {Observer}\n * @example\n * const params = {\n *   container: '#waveform',\n *   waveColor: 'violet',\n *   progressColor: 'purple'\n * };\n *\n * // initialise like this\n * const wavesurfer = WaveSurfer.create(params);\n *\n * // or like this ...\n * const wavesurfer = new WaveSurfer(params);\n * wavesurfer.init();\n *\n * // load audio file\n * wavesurfer.load('example/media/demo.wav');\n */\nexport default class WaveSurfer extends util.Observer {\n    /** @private */\n    defaultParams = {\n        audioContext: null,\n        audioRate: 1,\n        autoCenter: true,\n        backend: 'WebAudio',\n        barHeight: 1,\n        barGap: null,\n        container: null,\n        cursorColor: '#333',\n        cursorWidth: 1,\n        dragSelection: true,\n        fillParent: true,\n        forceDecode: false,\n        height: 128,\n        hideScrollbar: false,\n        interact: true,\n        loopSelection: true,\n        maxCanvasWidth: 4000,\n        mediaContainer: null,\n        mediaControls: false,\n        mediaType: 'audio',\n        minPxPerSec: 20,\n        normalize: false,\n        partialRender: false,\n        pixelRatio:\n            window.devicePixelRatio || screen.deviceXDPI / screen.logicalXDPI,\n        plugins: [],\n        progressColor: '#555',\n        removeMediaElementOnDestroy: true,\n        renderer: MultiCanvas,\n        responsive: false,\n        scrollParent: false,\n        skipLength: 2,\n        splitChannels: false,\n        waveColor: '#999',\n        xhr: {}\n    };\n\n    /** @private */\n    backends = {\n        MediaElement,\n        WebAudio\n    };\n\n    /**\n     * Instantiate this class, call its `init` function and returns it\n     *\n     * @param {WavesurferParams} params\n     * @return {Object} WaveSurfer instance\n     * @example const wavesurfer = WaveSurfer.create(params);\n     */\n    static create(params) {\n        const wavesurfer = new WaveSurfer(params);\n        return wavesurfer.init();\n    }\n\n    /**\n     * Functions in the `util` property are available as a prototype property to\n     * all instances\n     *\n     * @type {Object}\n     * @example\n     * const wavesurfer = WaveSurfer.create(params);\n     * wavesurfer.util.style(myElement, { background: 'blue' });\n     */\n    util = util;\n\n    /**\n     * Functions in the `util` property are available as a static property of the\n     * WaveSurfer class\n     *\n     * @type {Object}\n     * @example\n     * WaveSurfer.util.style(myElement, { background: 'blue' });\n     */\n    static util = util;\n\n    /**\n     * Initialise wavesurfer instance\n     *\n     * @param {WavesurferParams} params Instantiation options for wavesurfer\n     * @example\n     * const wavesurfer = new WaveSurfer(params);\n     * @returns {this}\n     */\n    constructor(params) {\n        super();\n        /**\n         * Extract relevant parameters (or defaults)\n         * @private\n         */\n        this.params = util.extend({}, this.defaultParams, params);\n\n        /** @private */\n        this.container =\n            'string' == typeof params.container\n                ? document.querySelector(this.params.container)\n                : this.params.container;\n\n        if (!this.container) {\n            throw new Error('Container element not found');\n        }\n\n        if (this.params.mediaContainer == null) {\n            /** @private */\n            this.mediaContainer = this.container;\n        } else if (typeof this.params.mediaContainer == 'string') {\n            /** @private */\n            this.mediaContainer = document.querySelector(\n                this.params.mediaContainer\n            );\n        } else {\n            /** @private */\n            this.mediaContainer = this.params.mediaContainer;\n        }\n\n        if (!this.mediaContainer) {\n            throw new Error('Media Container element not found');\n        }\n\n        if (this.params.maxCanvasWidth <= 1) {\n            throw new Error('maxCanvasWidth must be greater than 1');\n        } else if (this.params.maxCanvasWidth % 2 == 1) {\n            throw new Error('maxCanvasWidth must be an even number');\n        }\n\n        /**\n         * @private Used to save the current volume when muting so we can\n         * restore once unmuted\n         * @type {number}\n         */\n        this.savedVolume = 0;\n\n        /**\n         * @private The current muted state\n         * @type {boolean}\n         */\n        this.isMuted = false;\n\n        /**\n         * @private Will hold a list of event descriptors that need to be\n         * cancelled on subsequent loads of audio\n         * @type {Object[]}\n         */\n        this.tmpEvents = [];\n\n        /**\n         * @private Holds any running audio downloads\n         * @type {Observer}\n         */\n        this.currentAjax = null;\n        /** @private */\n        this.arraybuffer = null;\n        /** @private */\n        this.drawer = null;\n        /** @private */\n        this.backend = null;\n        /** @private */\n        this.peakCache = null;\n\n        // cache constructor objects\n        if (typeof this.params.renderer !== 'function') {\n            throw new Error('Renderer parameter is invalid');\n        }\n        /**\n         * @private The uninitialised Drawer class\n         */\n        this.Drawer = this.params.renderer;\n        /**\n         * @private The uninitialised Backend class\n         */\n        this.Backend = this.backends[this.params.backend];\n\n        /**\n         * @private map of plugin names that are currently initialised\n         */\n        this.initialisedPluginList = {};\n        /** @private */\n        this.isDestroyed = false;\n        /** @private */\n        this.isReady = false;\n\n        // responsive debounced event listener. If this.params.responsive is not\n        // set, this is never called. Use 100ms or this.params.responsive as\n        // timeout for the debounce function.\n        let prevWidth = 0;\n        this._onResize = util.debounce(() => {\n            if (\n                prevWidth != this.drawer.wrapper.clientWidth &&\n                !this.params.scrollParent\n            ) {\n                prevWidth = this.drawer.wrapper.clientWidth;\n                this.drawer.fireEvent('redraw');\n            }\n        }, typeof this.params.responsive === 'number' ? this.params.responsive : 100);\n\n        return this;\n    }\n\n    /**\n     * Initialise the wave\n     *\n     * @example\n     * var wavesurfer = new WaveSurfer(params);\n     * wavesurfer.init();\n     * @return {this}\n     */\n    init() {\n        this.registerPlugins(this.params.plugins);\n        this.createDrawer();\n        this.createBackend();\n        this.createPeakCache();\n        return this;\n    }\n\n    /**\n     * Add and initialise array of plugins (if `plugin.deferInit` is falsey),\n     * this function is called in the init function of wavesurfer\n     *\n     * @param {PluginDefinition[]} plugins An array of plugin definitions\n     * @emits {WaveSurfer#plugins-registered} Called with the array of plugin definitions\n     * @return {this}\n     */\n    registerPlugins(plugins) {\n        // first instantiate all the plugins\n        plugins.forEach(plugin => this.addPlugin(plugin));\n\n        // now run the init functions\n        plugins.forEach(plugin => {\n            // call init function of the plugin if deferInit is falsey\n            // in that case you would manually use initPlugins()\n            if (!plugin.deferInit) {\n                this.initPlugin(plugin.name);\n            }\n        });\n        this.fireEvent('plugins-registered', plugins);\n        return this;\n    }\n\n    /**\n     * Add a plugin object to wavesurfer\n     *\n     * @param {PluginDefinition} plugin A plugin definition\n     * @emits {WaveSurfer#plugin-added} Called with the name of the plugin that was added\n     * @example wavesurfer.addPlugin(WaveSurfer.minimap());\n     * @return {this}\n     */\n    addPlugin(plugin) {\n        if (!plugin.name) {\n            throw new Error('Plugin does not have a name!');\n        }\n        if (!plugin.instance) {\n            throw new Error(\n                `Plugin ${plugin.name} does not have an instance property!`\n            );\n        }\n\n        // staticProps properties are applied to wavesurfer instance\n        if (plugin.staticProps) {\n            Object.keys(plugin.staticProps).forEach(pluginStaticProp => {\n                /**\n                 * Properties defined in a plugin definition's `staticProps` property are added as\n                 * staticProps properties of the WaveSurfer instance\n                 */\n                this[pluginStaticProp] = plugin.staticProps[pluginStaticProp];\n            });\n        }\n\n        const Instance = plugin.instance;\n\n        // turn the plugin instance into an observer\n        const observerPrototypeKeys = Object.getOwnPropertyNames(\n            util.Observer.prototype\n        );\n        observerPrototypeKeys.forEach(key => {\n            Instance.prototype[key] = util.Observer.prototype[key];\n        });\n\n        /**\n         * Instantiated plugin classes are added as a property of the wavesurfer\n         * instance\n         * @type {Object}\n         */\n        this[plugin.name] = new Instance(plugin.params || {}, this);\n        this.fireEvent('plugin-added', plugin.name);\n        return this;\n    }\n\n    /**\n     * Initialise a plugin\n     *\n     * @param {string} name A plugin name\n     * @emits WaveSurfer#plugin-initialised\n     * @example wavesurfer.initPlugin('minimap');\n     * @return {this}\n     */\n    initPlugin(name) {\n        if (!this[name]) {\n            throw new Error(`Plugin ${name} has not been added yet!`);\n        }\n        if (this.initialisedPluginList[name]) {\n            // destroy any already initialised plugins\n            this.destroyPlugin(name);\n        }\n        this[name].init();\n        this.initialisedPluginList[name] = true;\n        this.fireEvent('plugin-initialised', name);\n        return this;\n    }\n\n    /**\n     * Destroy a plugin\n     *\n     * @param {string} name A plugin name\n     * @emits WaveSurfer#plugin-destroyed\n     * @example wavesurfer.destroyPlugin('minimap');\n     * @returns {this}\n     */\n    destroyPlugin(name) {\n        if (!this[name]) {\n            throw new Error(\n                `Plugin ${name} has not been added yet and cannot be destroyed!`\n            );\n        }\n        if (!this.initialisedPluginList[name]) {\n            throw new Error(\n                `Plugin ${name} is not active and cannot be destroyed!`\n            );\n        }\n        if (typeof this[name].destroy !== 'function') {\n            throw new Error(`Plugin ${name} does not have a destroy function!`);\n        }\n\n        this[name].destroy();\n        delete this.initialisedPluginList[name];\n        this.fireEvent('plugin-destroyed', name);\n        return this;\n    }\n\n    /**\n     * Destroy all initialised plugins. Convenience function to use when\n     * wavesurfer is removed\n     *\n     * @private\n     */\n    destroyAllPlugins() {\n        Object.keys(this.initialisedPluginList).forEach(name =>\n            this.destroyPlugin(name)\n        );\n    }\n\n    /**\n     * Create the drawer and draw the waveform\n     *\n     * @private\n     * @emits WaveSurfer#drawer-created\n     */\n    createDrawer() {\n        this.drawer = new this.Drawer(this.container, this.params);\n        this.drawer.init();\n        this.fireEvent('drawer-created', this.drawer);\n\n        if (this.params.responsive !== false) {\n            window.addEventListener('resize', this._onResize, true);\n            window.addEventListener('orientationchange', this._onResize, true);\n        }\n\n        this.drawer.on('redraw', () => {\n            this.drawBuffer();\n            this.drawer.progress(this.backend.getPlayedPercents());\n        });\n\n        // Click-to-seek\n        this.drawer.on('click', (e, progress) => {\n            setTimeout(() => this.seekTo(progress), 0);\n        });\n\n        // Relay the scroll event from the drawer\n        this.drawer.on('scroll', e => {\n            if (this.params.partialRender) {\n                this.drawBuffer();\n            }\n            this.fireEvent('scroll', e);\n        });\n    }\n\n    /**\n     * Create the backend\n     *\n     * @private\n     * @emits WaveSurfer#backend-created\n     */\n    createBackend() {\n        if (this.backend) {\n            this.backend.destroy();\n        }\n\n        // Back compat\n        if (this.params.backend == 'AudioElement') {\n            this.params.backend = 'MediaElement';\n        }\n\n        if (\n            this.params.backend == 'WebAudio' &&\n            !this.Backend.prototype.supportsWebAudio.call(null)\n        ) {\n            this.params.backend = 'MediaElement';\n        }\n\n        this.backend = new this.Backend(this.params);\n        this.backend.init();\n        this.fireEvent('backend-created', this.backend);\n\n        this.backend.on('finish', () => this.fireEvent('finish'));\n        this.backend.on('play', () => this.fireEvent('play'));\n        this.backend.on('pause', () => this.fireEvent('pause'));\n\n        this.backend.on('audioprocess', time => {\n            this.drawer.progress(this.backend.getPlayedPercents());\n            this.fireEvent('audioprocess', time);\n        });\n    }\n\n    /**\n     * Create the peak cache\n     *\n     * @private\n     */\n    createPeakCache() {\n        if (this.params.partialRender) {\n            this.peakCache = new PeakCache();\n        }\n    }\n\n    /**\n     * Get the duration of the audio clip\n     *\n     * @example const duration = wavesurfer.getDuration();\n     * @return {number} Duration in seconds\n     */\n    getDuration() {\n        return this.backend.getDuration();\n    }\n\n    /**\n     * Get the current playback position\n     *\n     * @example const currentTime = wavesurfer.getCurrentTime();\n     * @return {number} Playback position in seconds\n     */\n    getCurrentTime() {\n        return this.backend.getCurrentTime();\n    }\n\n    /**\n     * Set the current play time in seconds.\n     *\n     * @param {number} seconds A positive number in seconds. E.g. 10 means 10\n     * seconds, 60 means 1 minute\n     */\n    setCurrentTime(seconds) {\n        if (seconds >= this.getDuration()) {\n            this.seekTo(1);\n        } else {\n            this.seekTo(seconds / this.getDuration());\n        }\n    }\n\n    /**\n     * Starts playback from the current position. Optional start and end\n     * measured in seconds can be used to set the range of audio to play.\n     *\n     * @param {?number} start Position to start at\n     * @param {?number} end Position to end at\n     * @emits WaveSurfer#interaction\n     * @return {Promise}\n     * @example\n     * // play from second 1 to 5\n     * wavesurfer.play(1, 5);\n     */\n    play(start, end) {\n        this.fireEvent('interaction', () => this.play(start, end));\n        return this.backend.play(start, end);\n    }\n\n    /**\n     * Stops playback\n     *\n     * @example wavesurfer.pause();\n     * @return {Promise}\n     */\n    pause() {\n        if (!this.backend.isPaused()) {\n            return this.backend.pause();\n        }\n    }\n\n    /**\n     * Toggle playback\n     *\n     * @example wavesurfer.playPause();\n     * @return {Promise}\n     */\n    playPause() {\n        return this.backend.isPaused() ? this.play() : this.pause();\n    }\n\n    /**\n     * Get the current playback state\n     *\n     * @example const isPlaying = wavesurfer.isPlaying();\n     * @return {boolean} False if paused, true if playing\n     */\n    isPlaying() {\n        return !this.backend.isPaused();\n    }\n\n    /**\n     * Skip backward\n     *\n     * @param {?number} seconds Amount to skip back, if not specified `skipLength`\n     * is used\n     * @example wavesurfer.skipBackward();\n     */\n    skipBackward(seconds) {\n        this.skip(-seconds || -this.params.skipLength);\n    }\n\n    /**\n     * Skip forward\n     *\n     * @param {?number} seconds Amount to skip back, if not specified `skipLength`\n     * is used\n     * @example wavesurfer.skipForward();\n     */\n    skipForward(seconds) {\n        this.skip(seconds || this.params.skipLength);\n    }\n\n    /**\n     * Skip a number of seconds from the current position (use a negative value\n     * to go backwards).\n     *\n     * @param {number} offset Amount to skip back or forwards\n     * @example\n     * // go back 2 seconds\n     * wavesurfer.skip(-2);\n     */\n    skip(offset) {\n        const duration = this.getDuration() || 1;\n        let position = this.getCurrentTime() || 0;\n        position = Math.max(0, Math.min(duration, position + (offset || 0)));\n        this.seekAndCenter(position / duration);\n    }\n\n    /**\n     * Seeks to a position and centers the view\n     *\n     * @param {number} progress Between 0 (=beginning) and 1 (=end)\n     * @example\n     * // seek and go to the middle of the audio\n     * wavesurfer.seekTo(0.5);\n     */\n    seekAndCenter(progress) {\n        this.seekTo(progress);\n        this.drawer.recenter(progress);\n    }\n\n    /**\n     * Seeks to a position\n     *\n     * @param {number} progress Between 0 (=beginning) and 1 (=end)\n     * @emits WaveSurfer#interaction\n     * @emits WaveSurfer#seek\n     * @example\n     * // seek to the middle of the audio\n     * wavesurfer.seekTo(0.5);\n     */\n    seekTo(progress) {\n        // return an error if progress is not a number between 0 and 1\n        if (\n            typeof progress !== 'number' ||\n            !isFinite(progress) ||\n            progress < 0 ||\n            progress > 1\n        ) {\n            return console.error(\n                'Error calling wavesurfer.seekTo, parameter must be a number between 0 and 1!'\n            );\n        }\n        this.fireEvent('interaction', () => this.seekTo(progress));\n\n        const paused = this.backend.isPaused();\n        // avoid draw wrong position while playing backward seeking\n        if (!paused) {\n            this.backend.pause();\n        }\n        // avoid small scrolls while paused seeking\n        const oldScrollParent = this.params.scrollParent;\n        this.params.scrollParent = false;\n        this.backend.seekTo(progress * this.getDuration());\n        this.drawer.progress(progress);\n\n        if (!paused) {\n            this.backend.play();\n        }\n        this.params.scrollParent = oldScrollParent;\n        this.fireEvent('seek', progress);\n    }\n\n    /**\n     * Stops and goes to the beginning.\n     *\n     * @example wavesurfer.stop();\n     */\n    stop() {\n        this.pause();\n        this.seekTo(0);\n        this.drawer.progress(0);\n    }\n\n    /**\n     * Set the playback volume.\n     *\n     * @param {string} deviceId String value representing underlying output device\n     */\n    setSinkId(deviceId) {\n        return this.backend.setSinkId(deviceId);\n    }\n\n    /**\n     * Set the playback volume.\n     *\n     * @param {number} newVolume A value between 0 and 1, 0 being no\n     * volume and 1 being full volume.\n     * @emits WaveSurfer#volume\n     */\n    setVolume(newVolume) {\n        this.backend.setVolume(newVolume);\n        this.fireEvent('volume', newVolume);\n    }\n\n    /**\n     * Get the playback volume.\n     *\n     * @return {number} A value between 0 and 1, 0 being no\n     * volume and 1 being full volume.\n     */\n    getVolume() {\n        return this.backend.getVolume();\n    }\n\n    /**\n     * Set the playback rate.\n     *\n     * @param {number} rate A positive number. E.g. 0.5 means half the normal\n     * speed, 2 means double speed and so on.\n     * @example wavesurfer.setPlaybackRate(2);\n     */\n    setPlaybackRate(rate) {\n        this.backend.setPlaybackRate(rate);\n    }\n\n    /**\n     * Get the playback rate.\n     *\n     * @return {number}\n     */\n    getPlaybackRate() {\n        return this.backend.getPlaybackRate();\n    }\n\n    /**\n     * Toggle the volume on and off. It not currenly muted it will save the\n     * current volume value and turn the volume off. If currently muted then it\n     * will restore the volume to the saved value, and then rest the saved\n     * value.\n     *\n     * @example wavesurfer.toggleMute();\n     */\n    toggleMute() {\n        this.setMute(!this.isMuted);\n    }\n\n    /**\n     * Enable or disable muted audio\n     *\n     * @param {boolean} mute\n     * @emits WaveSurfer#volume\n     * @emits WaveSurfer#mute\n     * @example\n     * // unmute\n     * wavesurfer.setMute(false);\n     */\n    setMute(mute) {\n        // ignore all muting requests if the audio is already in that state\n        if (mute === this.isMuted) {\n            this.fireEvent('mute', this.isMuted);\n            return;\n        }\n\n        if (mute) {\n            // If currently not muted then save current volume,\n            // turn off the volume and update the mute properties\n            this.savedVolume = this.backend.getVolume();\n            this.backend.setVolume(0);\n            this.isMuted = true;\n            this.fireEvent('volume', 0);\n        } else {\n            // If currently muted then restore to the saved volume\n            // and update the mute properties\n            this.backend.setVolume(this.savedVolume);\n            this.isMuted = false;\n            this.fireEvent('volume', this.savedVolume);\n        }\n        this.fireEvent('mute', this.isMuted);\n    }\n\n    /**\n     * Get the current mute status.\n     *\n     * @example const isMuted = wavesurfer.getMute();\n     * @return {boolean}\n     */\n    getMute() {\n        return this.isMuted;\n    }\n\n    /**\n     * Get the current ready status.\n     *\n     * @example const isReady = wavesurfer.isReady();\n     * @return {boolean}\n     */\n    isReady() {\n        return this.isReady;\n    }\n\n    /**\n     * Get the list of current set filters as an array.\n     *\n     * Filters must be set with setFilters method first\n     *\n     * @return {array}\n     */\n    getFilters() {\n        return this.backend.filters || [];\n    }\n\n    /**\n     * Toggles `scrollParent` and redraws\n     *\n     * @example wavesurfer.toggleScroll();\n     */\n    toggleScroll() {\n        this.params.scrollParent = !this.params.scrollParent;\n        this.drawBuffer();\n    }\n\n    /**\n     * Toggle mouse interaction\n     *\n     * @example wavesurfer.toggleInteraction();\n     */\n    toggleInteraction() {\n        this.params.interact = !this.params.interact;\n    }\n\n    /**\n     * Get the fill color of the waveform after the cursor.\n     *\n     * @return {string} A CSS color string.\n     */\n    getWaveColor() {\n        return this.params.waveColor;\n    }\n\n    /**\n     * Set the fill color of the waveform after the cursor.\n     *\n     * @param {string} color A CSS color string.\n     * @example wavesurfer.setWaveColor('#ddd');\n     */\n    setWaveColor(color) {\n        this.params.waveColor = color;\n        this.drawBuffer();\n    }\n\n    /**\n     * Get the fill color of the waveform behind the cursor.\n     *\n     * @return {string} A CSS color string.\n     */\n    getProgressColor() {\n        return this.params.progressColor;\n    }\n\n    /**\n     * Set the fill color of the waveform behind the cursor.\n     *\n     * @param {string} color A CSS color string.\n     * @example wavesurfer.setProgressColor('#400');\n     */\n    setProgressColor(color) {\n        this.params.progressColor = color;\n        this.drawBuffer();\n    }\n\n    /**\n     * Get the fill color of the cursor indicating the playhead\n     * position.\n     *\n     * @return {string} A CSS color string.\n     */\n    getCursorColor() {\n        return this.params.cursorColor;\n    }\n\n    /**\n     * Set the fill color of the cursor indicating the playhead\n     * position.\n     *\n     * @param {string} color A CSS color string.\n     * @example wavesurfer.setCursorColor('#222');\n     */\n    setCursorColor(color) {\n        this.params.cursorColor = color;\n        this.drawer.updateCursor();\n    }\n\n    /**\n     * Get the height of the waveform.\n     *\n     * @return {number} Height measured in pixels.\n     */\n    getHeight() {\n        return this.params.height;\n    }\n\n    /**\n     * Set the height of the waveform.\n     *\n     * @param {number} height Height measured in pixels.\n     * @example wavesurfer.setHeight(200);\n     */\n    setHeight(height) {\n        this.params.height = height;\n        this.drawer.setHeight(height * this.params.pixelRatio);\n        this.drawBuffer();\n    }\n\n    /**\n     * Get the correct peaks for current wave viewport and render wave\n     *\n     * @private\n     * @emits WaveSurfer#redraw\n     */\n    drawBuffer() {\n        const nominalWidth = Math.round(\n            this.getDuration() *\n                this.params.minPxPerSec *\n                this.params.pixelRatio\n        );\n        const parentWidth = this.drawer.getWidth();\n        let width = nominalWidth;\n        let start = this.drawer.getScrollX();\n        let end = Math.max(start + parentWidth, width);\n        // Fill container\n        if (\n            this.params.fillParent &&\n            (!this.params.scrollParent || nominalWidth < parentWidth)\n        ) {\n            width = parentWidth;\n            start = 0;\n            end = width;\n        }\n\n        let peaks;\n        if (this.params.partialRender) {\n            const newRanges = this.peakCache.addRangeToPeakCache(\n                width,\n                start,\n                end\n            );\n            let i;\n            for (i = 0; i < newRanges.length; i++) {\n                peaks = this.backend.getPeaks(\n                    width,\n                    newRanges[i][0],\n                    newRanges[i][1]\n                );\n                this.drawer.drawPeaks(\n                    peaks,\n                    width,\n                    newRanges[i][0],\n                    newRanges[i][1]\n                );\n            }\n        } else {\n            peaks = this.backend.getPeaks(width, start, end);\n            this.drawer.drawPeaks(peaks, width, start, end);\n        }\n        this.fireEvent('redraw', peaks, width);\n    }\n\n    /**\n     * Horizontally zooms the waveform in and out. It also changes the parameter\n     * `minPxPerSec` and enables the `scrollParent` option. Calling the function\n     * with a falsey parameter will reset the zoom state.\n     *\n     * @param {?number} pxPerSec Number of horizontal pixels per second of\n     * audio, if none is set the waveform returns to unzoomed state\n     * @emits WaveSurfer#zoom\n     * @example wavesurfer.zoom(20);\n     */\n    zoom(pxPerSec) {\n        if (!pxPerSec) {\n            this.params.minPxPerSec = this.defaultParams.minPxPerSec;\n            this.params.scrollParent = false;\n        } else {\n            this.params.minPxPerSec = pxPerSec;\n            this.params.scrollParent = true;\n        }\n\n        this.drawBuffer();\n        this.drawer.progress(this.backend.getPlayedPercents());\n\n        this.drawer.recenter(this.getCurrentTime() / this.getDuration());\n        this.fireEvent('zoom', pxPerSec);\n    }\n\n    /**\n     * Decode buffer and load\n     *\n     * @private\n     * @param {ArrayBuffer} arraybuffer\n     */\n    loadArrayBuffer(arraybuffer) {\n        this.decodeArrayBuffer(arraybuffer, data => {\n            if (!this.isDestroyed) {\n                this.loadDecodedBuffer(data);\n            }\n        });\n    }\n\n    /**\n     * Directly load an externally decoded AudioBuffer\n     *\n     * @private\n     * @param {AudioBuffer} buffer\n     * @emits WaveSurfer#ready\n     */\n    loadDecodedBuffer(buffer) {\n        this.backend.load(buffer);\n        this.drawBuffer();\n        this.fireEvent('ready');\n        this.isReady = true;\n    }\n\n    /**\n     * Loads audio data from a Blob or File object\n     *\n     * @param {Blob|File} blob Audio data\n     * @example\n     */\n    loadBlob(blob) {\n        // Create file reader\n        const reader = new FileReader();\n        reader.addEventListener('progress', e => this.onProgress(e));\n        reader.addEventListener('load', e =>\n            this.loadArrayBuffer(e.target.result)\n        );\n        reader.addEventListener('error', () =>\n            this.fireEvent('error', 'Error reading file')\n        );\n        reader.readAsArrayBuffer(blob);\n        this.empty();\n    }\n\n    /**\n     * Loads audio and re-renders the waveform.\n     *\n     * @param {string|HTMLMediaElement} url The url of the audio file or the\n     * audio element with the audio\n     * @param {?number[]|number[][]} peaks Wavesurfer does not have to decode\n     * the audio to render the waveform if this is specified\n     * @param {?string} preload (Use with backend `MediaElement`)\n     * `'none'|'metadata'|'auto'` Preload attribute for the media element\n     * @param {?number} duration The duration of the audio. This is used to\n     * render the peaks data in the correct size for the audio duration (as\n     * befits the current minPxPerSec and zoom value) without having to decode\n     * the audio.\n     * @example\n     * // using ajax or media element to load (depending on backend)\n     * wavesurfer.load('http://example.com/demo.wav');\n     *\n     * // setting preload attribute with media element backend and supplying\n     * peaks wavesurfer.load(\n     *   'http://example.com/demo.wav',\n     *   [0.0218, 0.0183, 0.0165, 0.0198, 0.2137, 0.2888],\n     *   true,\n     * );\n     */\n    load(url, peaks, preload, duration) {\n        this.empty();\n\n        if (preload) {\n            // check whether the preload attribute will be usable and if not log\n            // a warning listing the reasons why not and nullify the variable\n            const preloadIgnoreReasons = {\n                \"Preload is not 'auto', 'none' or 'metadata'\":\n                    ['auto', 'metadata', 'none'].indexOf(preload) === -1,\n                'Peaks are not provided': !peaks,\n                'Backend is not of type MediaElement':\n                    this.params.backend !== 'MediaElement',\n                'Url is not of type string': typeof url !== 'string'\n            };\n            const activeReasons = Object.keys(preloadIgnoreReasons).filter(\n                reason => preloadIgnoreReasons[reason]\n            );\n            if (activeReasons.length) {\n                console.warn(\n                    'Preload parameter of wavesurfer.load will be ignored because:\\n\\t- ' +\n                        activeReasons.join('\\n\\t- ')\n                );\n                // stop invalid values from being used\n                preload = null;\n            }\n        }\n\n        switch (this.params.backend) {\n            case 'WebAudio':\n                return this.loadBuffer(url, peaks, duration);\n            case 'MediaElement':\n                return this.loadMediaElement(url, peaks, preload, duration);\n        }\n    }\n\n    /**\n     * Loads audio using Web Audio buffer backend.\n     *\n     * @private\n     * @param {string} url\n     * @param {?number[]|number[][]} peaks\n     * @param {?number} duration\n     */\n    loadBuffer(url, peaks, duration) {\n        const load = action => {\n            if (action) {\n                this.tmpEvents.push(this.once('ready', action));\n            }\n            return this.getArrayBuffer(url, data => this.loadArrayBuffer(data));\n        };\n\n        if (peaks) {\n            this.backend.setPeaks(peaks, duration);\n            this.drawBuffer();\n            this.tmpEvents.push(this.once('interaction', load));\n        } else {\n            return load();\n        }\n    }\n\n    /**\n     * Either create a media element, or load an existing media element.\n     *\n     * @private\n     * @param {string|HTMLMediaElement} urlOrElt Either a path to a media file, or an\n     * existing HTML5 Audio/Video Element\n     * @param {number[]|number[][]} peaks Array of peaks. Required to bypass web audio\n     * dependency\n     * @param {?boolean} preload Set to true if the preload attribute of the\n     * audio element should be enabled\n     * @param {?number} duration\n     */\n    loadMediaElement(urlOrElt, peaks, preload, duration) {\n        let url = urlOrElt;\n\n        if (typeof urlOrElt === 'string') {\n            this.backend.load(url, this.mediaContainer, peaks, preload);\n        } else {\n            const elt = urlOrElt;\n            this.backend.loadElt(elt, peaks);\n\n            // If peaks are not provided,\n            // url = element.src so we can get peaks with web audio\n            url = elt.src;\n        }\n\n        this.tmpEvents.push(\n            this.backend.once('canplay', () => {\n                this.drawBuffer();\n                this.fireEvent('ready');\n                this.isReady = true;\n            }),\n            this.backend.once('error', err => this.fireEvent('error', err))\n        );\n\n        // If no pre-decoded peaks provided or pre-decoded peaks are\n        // provided with forceDecode flag, attempt to download the\n        // audio file and decode it with Web Audio.\n        if (peaks) {\n            this.backend.setPeaks(peaks, duration);\n        }\n\n        if (\n            (!peaks || this.params.forceDecode) &&\n            this.backend.supportsWebAudio()\n        ) {\n            this.getArrayBuffer(url, arraybuffer => {\n                this.decodeArrayBuffer(arraybuffer, buffer => {\n                    this.backend.buffer = buffer;\n                    this.backend.setPeaks(null);\n                    this.drawBuffer();\n                    this.fireEvent('waveform-ready');\n                });\n            });\n        }\n    }\n\n    /**\n     * Decode an array buffer and pass data to a callback\n     *\n     * @private\n     * @param {Object} arraybuffer\n     * @param {function} callback\n     */\n    decodeArrayBuffer(arraybuffer, callback) {\n        this.arraybuffer = arraybuffer;\n\n        this.backend.decodeArrayBuffer(\n            arraybuffer,\n            data => {\n                // Only use the decoded data if we haven't been destroyed or\n                // another decode started in the meantime\n                if (!this.isDestroyed && this.arraybuffer == arraybuffer) {\n                    callback(data);\n                    this.arraybuffer = null;\n                }\n            },\n            () => this.fireEvent('error', 'Error decoding audiobuffer')\n        );\n    }\n\n    /**\n     * Load an array buffer by ajax and pass to a callback\n     *\n     * @param {string} url\n     * @param {function} callback\n     * @private\n     */\n    getArrayBuffer(url, callback) {\n        const ajax = util.ajax({\n            url: url,\n            responseType: 'arraybuffer',\n            xhr: this.params.xhr\n        });\n\n        this.currentAjax = ajax;\n\n        this.tmpEvents.push(\n            ajax.on('progress', e => {\n                this.onProgress(e);\n            }),\n            ajax.on('success', (data, e) => {\n                callback(data);\n                this.currentAjax = null;\n            }),\n            ajax.on('error', e => {\n                this.fireEvent('error', 'XHR error: ' + e.target.statusText);\n                this.currentAjax = null;\n            })\n        );\n\n        return ajax;\n    }\n\n    /**\n     * Called while the audio file is loading\n     *\n     * @private\n     * @param {Event} e\n     * @emits WaveSurfer#loading\n     */\n    onProgress(e) {\n        let percentComplete;\n        if (e.lengthComputable) {\n            percentComplete = e.loaded / e.total;\n        } else {\n            // Approximate progress with an asymptotic\n            // function, and assume downloads in the 1-3 MB range.\n            percentComplete = e.loaded / (e.loaded + 1000000);\n        }\n        this.fireEvent('loading', Math.round(percentComplete * 100), e.target);\n    }\n\n    /**\n     * Exports PCM data into a JSON array and opens in a new window.\n     *\n     * @param {number} length=1024 The scale in which to export the peaks. (Integer)\n     * @param {number} accuracy=10000 (Integer)\n     * @param {?boolean} noWindow Set to true to disable opening a new\n     * window with the JSON\n     * @param {number} start\n     * @todo Update exportPCM to work with new getPeaks signature\n     * @return {string} JSON of peaks\n     */\n    exportPCM(length, accuracy, noWindow, start) {\n        length = length || 1024;\n        start = start || 0;\n        accuracy = accuracy || 10000;\n        noWindow = noWindow || false;\n        const peaks = this.backend.getPeaks(length, start);\n        const arr = [].map.call(\n            peaks,\n            val => Math.round(val * accuracy) / accuracy\n        );\n        const json = JSON.stringify(arr);\n        if (!noWindow) {\n            window.open(\n                'data:application/json;charset=utf-8,' +\n                    encodeURIComponent(json)\n            );\n        }\n        return json;\n    }\n\n    /**\n     * Save waveform image as data URI.\n     *\n     * The default format is `image/png`. Other supported types are\n     * `image/jpeg` and `image/webp`.\n     *\n     * @param {string} format='image/png'\n     * @param {number} quality=1\n     * @return {string} data URI of image\n     */\n    exportImage(format, quality) {\n        if (!format) {\n            format = 'image/png';\n        }\n        if (!quality) {\n            quality = 1;\n        }\n\n        return this.drawer.getImage(format, quality);\n    }\n\n    /**\n     * Cancel any ajax request currently in progress\n     */\n    cancelAjax() {\n        if (this.currentAjax) {\n            this.currentAjax.xhr.abort();\n            this.currentAjax = null;\n        }\n    }\n\n    /**\n     * @private\n     */\n    clearTmpEvents() {\n        this.tmpEvents.forEach(e => e.un());\n    }\n\n    /**\n     * Display empty waveform.\n     */\n    empty() {\n        if (!this.backend.isPaused()) {\n            this.stop();\n            this.backend.disconnectSource();\n        }\n        this.cancelAjax();\n        this.clearTmpEvents();\n        this.drawer.progress(0);\n        this.drawer.setWidth(0);\n        this.drawer.drawPeaks({ length: this.drawer.getWidth() }, 0);\n    }\n\n    /**\n     * Remove events, elements and disconnect WebAudio nodes.\n     *\n     * @emits WaveSurfer#destroy\n     */\n    destroy() {\n        this.destroyAllPlugins();\n        this.fireEvent('destroy');\n        this.cancelAjax();\n        this.clearTmpEvents();\n        this.unAll();\n        if (this.params.responsive !== false) {\n            window.removeEventListener('resize', this._onResize, true);\n            window.removeEventListener(\n                'orientationchange',\n                this._onResize,\n                true\n            );\n        }\n        this.backend.destroy();\n        this.drawer.destroy();\n        this.isDestroyed = true;\n        this.arraybuffer = null;\n    }\n}\n"],"sourceRoot":""}