Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@speechly/browser-client

Package Overview
Dependencies
Maintainers
6
Versions
79
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@speechly/browser-client - npm Package Compare versions

Comparing version 2.1.0-beta.4 to 2.1.0-beta.5

src/audioprocessing/EnergyThresholdVAD.ts

4

core/speechly.umd.min.js

@@ -1,4 +0,4 @@

!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).Speechly={})}(this,(function(t){"use strict";const e=new Error("Current device does not support microphone API"),i=new Error("AppId changed without project login"),n=16e3;class s{constructor(t,e){this.isFinalized=!1,this.words=[],this.entities=new Map,this.intent={intent:"",isFinal:!1},this.contextId=t,this.id=e}toSegment(){let t=0;const e=new Array(this.entities.size);return this.entities.forEach((i=>{e[t]=i,t++})),{id:this.id,contextId:this.contextId,isFinal:this.isFinalized,words:this.words,entities:e,intent:this.intent}}toString(){const t=this.toSegment(),e=t.words.filter((t=>t.value)).map((t=>({value:t.value,index:t.index}))),i=Object.assign(Object.assign({},t),{words:e});return JSON.stringify(i,null,2)}updateTranscript(t){return t.forEach((t=>{this.isFinalized&&!t.isFinal||(this.words[t.index]=t)})),this}updateEntities(t){return t.forEach((t=>{this.isFinalized&&!t.isFinal||this.entities.set(function(t){return`${t.startPosition.toString()}:${t.endPosition.toString()}`}(t),t)})),this}updateIntent(t){return this.isFinalized&&!t.isFinal||(this.intent=t),this}finalize(){return this.entities.forEach(((t,e)=>{t.isFinal||this.entities.delete(e)})),this.words=this.words.filter((t=>t.isFinal)),this.intent.isFinal||(this.intent.intent="",this.intent.isFinal=!0),this.isFinalized=!0,this}}function o(t,e,i,n){return new(i||(i=Promise))((function(s,o){function a(t){try{l(n.next(t))}catch(t){o(t)}}function d(t){try{l(n.throw(t))}catch(t){o(t)}}function l(t){var e;t.done?s(t.value):(e=t.value,e instanceof i?e:new i((function(t){t(e)}))).then(a,d)}l((n=n.apply(t,e||[])).next())}))}const a=new Error("Microphone is not initialized"),d=new Error("Microphone is already initialized"),l=new Error("Microphone consent is not given");var c,r,h;t.WebsocketResponseType=void 0,(c=t.WebsocketResponseType||(t.WebsocketResponseType={})).Started="started",c.Stopped="stopped",c.SegmentEnd="segment_end",c.Transcript="transcript",c.Entity="entity",c.Intent="intent",c.TentativeTranscript="tentative_transcript",c.TentativeEntities="tentative_entities",c.TentativeIntent="tentative_intent",t.WorkerSignal=void 0,(r=t.WorkerSignal||(t.WorkerSignal={})).Opened="WEBSOCKET_OPEN",r.Closed="WEBSOCKET_CLOSED",r.AudioProcessorReady="SOURCE_SAMPLE_RATE_SET_SUCCESS",r.VadSignalHigh="VadSignalHigh",r.VadSignalLow="VadSignalLow",t.ControllerSignal=void 0,(h=t.ControllerSignal||(t.ControllerSignal={})).connect="connect",h.initAudioProcessor="initAudioProcessor",h.adjustAudioProcessor="adjustAudioProcessor",h.SET_SHARED_ARRAY_BUFFERS="SET_SHARED_ARRAY_BUFFERS",h.CLOSE="CLOSE",h.START_CONTEXT="START_CONTEXT",h.SWITCH_CONTEXT="SWITCH_CONTEXT",h.STOP_CONTEXT="STOP_CONTEXT",h.AUDIO="AUDIO",h.startStream="startStream",h.stopStream="stopStream",h.setContextOptions="setContextOptions";const u=new Error("Current device does not support storage API"),p=new Error("Requested key was not present in storage"),b={enabled:!1,controlListening:!0,signalToNoiseDb:3,noiseGateDb:-24,noiseLearnHalftimeMillis:400,signalSearchFrames:5,signalActivation:.7,signalRelease:.2,signalSustainMillis:3e3};var m;t.DecoderState=void 0,(m=t.DecoderState||(t.DecoderState={}))[m.Failed=0]="Failed",m[m.Disconnected=1]="Disconnected",m[m.Connected=2]="Connected",m[m.Active=3]="Active";class Z{constructor(){this.stateChangeCbs=[],this.transcriptCbs=[],this.entityCbs=[],this.intentCbs=[],this.segmentChangeCbs=[],this.tentativeTranscriptCbs=[],this.tentativeEntityCbs=[],this.tentativeIntentCbs=[],this.contextStartedCbs=[],this.contextStoppedCbs=[],this.onVadStateChange=[]}}function G(t){var e;return null!==(e=y.get(t))&&void 0!==e?e:"unknown"}const y=new Map([[t.DecoderState.Failed,"Failed"],[t.DecoderState.Disconnected,"Disconnected"],[t.DecoderState.Connected,"Connected"],[t.DecoderState.Active,"Active"]]);var X,v=new Uint8Array(16);function R(){if(!X&&!(X="undefined"!=typeof crypto&&crypto.getRandomValues&&crypto.getRandomValues.bind(crypto)||"undefined"!=typeof msCrypto&&"function"==typeof msCrypto.getRandomValues&&msCrypto.getRandomValues.bind(msCrypto)))throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");return X(v)}var V=/^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i;function W(t){return"string"==typeof t&&V.test(t)}for(var S=[],C=0;C<256;++C)S.push((C+256).toString(16).substr(1));function g(t,e,i){var n=(t=t||{}).random||(t.rng||R)();if(n[6]=15&n[6]|64,n[8]=63&n[8]|128,e){i=i||0;for(var s=0;s<16;++s)e[i+s]=n[s];return e}return function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,i=(S[t[e+0]]+S[t[e+1]]+S[t[e+2]]+S[t[e+3]]+"-"+S[t[e+4]]+S[t[e+5]]+"-"+S[t[e+6]]+S[t[e+7]]+"-"+S[t[e+8]]+S[t[e+9]]+"-"+S[t[e+10]]+S[t[e+11]]+S[t[e+12]]+S[t[e+13]]+S[t[e+14]]+S[t[e+15]]).toLowerCase();if(!W(i))throw TypeError("Stringified UUID is invalid");return i}(n)}var z="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},Y={exports:{}};
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).Speechly={})}(this,(function(t){"use strict";const e=new Error("Current device does not support microphone API"),i=new Error("AppId changed without project login"),n=16e3;class s{constructor(t,e){this.isFinalized=!1,this.words=[],this.entities=new Map,this.intent={intent:"",isFinal:!1},this.contextId=t,this.id=e}toSegment(){let t=0;const e=new Array(this.entities.size);return this.entities.forEach((i=>{e[t]=i,t++})),{id:this.id,contextId:this.contextId,isFinal:this.isFinalized,words:this.words,entities:e,intent:this.intent}}toString(){const t=this.toSegment(),e=t.words.filter((t=>t.value)).map((t=>({value:t.value,index:t.index}))),i=Object.assign(Object.assign({},t),{words:e});return JSON.stringify(i,null,2)}updateTranscript(t){return t.forEach((t=>{this.isFinalized&&!t.isFinal||(this.words[t.index]=t)})),this}updateEntities(t){return t.forEach((t=>{this.isFinalized&&!t.isFinal||this.entities.set(function(t){return`${t.startPosition.toString()}:${t.endPosition.toString()}`}(t),t)})),this}updateIntent(t){return this.isFinalized&&!t.isFinal||(this.intent=t),this}finalize(){return this.entities.forEach(((t,e)=>{t.isFinal||this.entities.delete(e)})),this.words=this.words.filter((t=>t.isFinal)),this.intent.isFinal||(this.intent.intent="",this.intent.isFinal=!0),this.isFinalized=!0,this}}function o(t,e,i,n){return new(i||(i=Promise))((function(s,o){function a(t){try{l(n.next(t))}catch(t){o(t)}}function d(t){try{l(n.throw(t))}catch(t){o(t)}}function l(t){var e;t.done?s(t.value):(e=t.value,e instanceof i?e:new i((function(t){t(e)}))).then(a,d)}l((n=n.apply(t,e||[])).next())}))}const a=new Error("Microphone is not initialized"),d=new Error("Microphone is already initialized"),l=new Error("Microphone consent is not given");var c,r,h;t.WebsocketResponseType=void 0,(c=t.WebsocketResponseType||(t.WebsocketResponseType={})).Started="started",c.Stopped="stopped",c.SegmentEnd="segment_end",c.Transcript="transcript",c.Entity="entity",c.Intent="intent",c.TentativeTranscript="tentative_transcript",c.TentativeEntities="tentative_entities",c.TentativeIntent="tentative_intent",t.WorkerSignal=void 0,(r=t.WorkerSignal||(t.WorkerSignal={})).Opened="WEBSOCKET_OPEN",r.Closed="WEBSOCKET_CLOSED",r.AudioProcessorReady="SOURCE_SAMPLE_RATE_SET_SUCCESS",r.VadSignalHigh="VadSignalHigh",r.VadSignalLow="VadSignalLow",t.ControllerSignal=void 0,(h=t.ControllerSignal||(t.ControllerSignal={})).connect="connect",h.initAudioProcessor="initAudioProcessor",h.adjustAudioProcessor="adjustAudioProcessor",h.SET_SHARED_ARRAY_BUFFERS="SET_SHARED_ARRAY_BUFFERS",h.CLOSE="CLOSE",h.START_CONTEXT="START_CONTEXT",h.SWITCH_CONTEXT="SWITCH_CONTEXT",h.STOP_CONTEXT="STOP_CONTEXT",h.AUDIO="AUDIO",h.startStream="startStream",h.stopStream="stopStream",h.setContextOptions="setContextOptions";const u=new Error("Current device does not support storage API"),p=new Error("Requested key was not present in storage"),b={enabled:!1,controlListening:!0,signalToNoiseDb:3,noiseGateDb:-24,noiseLearnHalftimeMillis:400,signalSearchFrames:5,signalActivation:.7,signalRelease:.2,signalSustainMillis:3e3};var m;t.DecoderState=void 0,(m=t.DecoderState||(t.DecoderState={}))[m.Failed=0]="Failed",m[m.Disconnected=1]="Disconnected",m[m.Connected=2]="Connected",m[m.Active=3]="Active";class Z{constructor(){this.stateChangeCbs=[],this.transcriptCbs=[],this.entityCbs=[],this.intentCbs=[],this.segmentChangeCbs=[],this.tentativeTranscriptCbs=[],this.tentativeEntityCbs=[],this.tentativeIntentCbs=[],this.contextStartedCbs=[],this.contextStoppedCbs=[],this.onVadStateChange=[]}}function G(t){var e;return null!==(e=y.get(t))&&void 0!==e?e:"unknown"}const y=new Map([[t.DecoderState.Failed,"Failed"],[t.DecoderState.Disconnected,"Disconnected"],[t.DecoderState.Connected,"Connected"],[t.DecoderState.Active,"Active"]]);var W,v=new Uint8Array(16);function R(){if(!W&&!(W="undefined"!=typeof crypto&&crypto.getRandomValues&&crypto.getRandomValues.bind(crypto)||"undefined"!=typeof msCrypto&&"function"==typeof msCrypto.getRandomValues&&msCrypto.getRandomValues.bind(msCrypto)))throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");return W(v)}var X=/^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i;function V(t){return"string"==typeof t&&X.test(t)}for(var S=[],C=0;C<256;++C)S.push((C+256).toString(16).substr(1));function g(t,e,i){var n=(t=t||{}).random||(t.rng||R)();if(n[6]=15&n[6]|64,n[8]=63&n[8]|128,e){i=i||0;for(var s=0;s<16;++s)e[i+s]=n[s];return e}return function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,i=(S[t[e+0]]+S[t[e+1]]+S[t[e+2]]+S[t[e+3]]+"-"+S[t[e+4]]+S[t[e+5]]+"-"+S[t[e+6]]+S[t[e+7]]+"-"+S[t[e+8]]+S[t[e+9]]+"-"+S[t[e+10]]+S[t[e+11]]+S[t[e+12]]+S[t[e+13]]+S[t[e+14]]+S[t[e+15]]).toLowerCase();if(!V(i))throw TypeError("Stringified UUID is invalid");return i}(n)}var Y="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},z={exports:{}};
/*! http://mths.be/base64 v0.1.0 by @mathias | MIT license */
!function(t,e){!function(i){var n=e,s=t&&t.exports==n&&t,o="object"==typeof z&&z;o.global!==o&&o.window!==o||(i=o);var a=function(t){this.message=t};(a.prototype=new Error).name="InvalidCharacterError";var d=function(t){throw new a(t)},l="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",c=/[\t\n\f\r ]/g,r={encode:function(t){t=String(t),/[^\0-\xFF]/.test(t)&&d("The string to be encoded contains characters outside of the Latin1 range.");for(var e,i,n,s,o=t.length%3,a="",c=-1,r=t.length-o;++c<r;)e=t.charCodeAt(c)<<16,i=t.charCodeAt(++c)<<8,n=t.charCodeAt(++c),a+=l.charAt((s=e+i+n)>>18&63)+l.charAt(s>>12&63)+l.charAt(s>>6&63)+l.charAt(63&s);return 2==o?(e=t.charCodeAt(c)<<8,i=t.charCodeAt(++c),a+=l.charAt((s=e+i)>>10)+l.charAt(s>>4&63)+l.charAt(s<<2&63)+"="):1==o&&(s=t.charCodeAt(c),a+=l.charAt(s>>2)+l.charAt(s<<4&63)+"=="),a},decode:function(t){var e=(t=String(t).replace(c,"")).length;e%4==0&&(e=(t=t.replace(/==?$/,"")).length),(e%4==1||/[^+a-zA-Z0-9/]/.test(t))&&d("Invalid character: the string to be decoded is not correctly encoded.");for(var i,n,s=0,o="",a=-1;++a<e;)n=l.indexOf(t.charAt(a)),i=s%4?64*i+n:n,s++%4&&(o+=String.fromCharCode(255&i>>(-2*s&6)));return o},version:"0.1.0"};if(n&&!n.nodeType)if(s)s.exports=r;else for(var h in r)r.hasOwnProperty(h)&&(n[h]=r[h]);else i.base64=r}(z)}(Y,Y.exports);function N(t,e,i,n,s=Date.now){const o=function(t){const e=t.split(".")[1];let i;try{i=JSON.parse(Y.exports.decode(e))}catch(t){throw new Error("Error decoding Speechly token!")}return{appId:i.appId,projectId:i.projectId,deviceId:i.deviceId,configId:i.configId,scopes:i.scope.split(" "),issuer:i.iss,audience:i.aud,expiresAtMs:1e3*i.exp}}(t);return!(o.expiresAtMs-s()<36e5)&&(o.appId===i&&o.projectId===e&&o.deviceId===n)}class T{constructor(){this.startCbs=[],this.stopCbs=[],this.onResponseCb=()=>{},this.onCloseCb=()=>{},this.onWebsocketMessage=e=>{const i=e.data;switch(i.type){case t.WorkerSignal.Opened:null!=this.resolveInitialization&&this.resolveInitialization();break;case t.WorkerSignal.Closed:this.onCloseCb({code:e.data.code,reason:e.data.reason,wasClean:e.data.wasClean});break;case t.WorkerSignal.AudioProcessorReady:null!=this.resolveSourceSampleRateSet&&this.resolveSourceSampleRateSet();break;case t.WebsocketResponseType.Started:this.onResponseCb(i),this.startCbs.forEach((t=>{try{t(void 0,i.audio_context)}catch(t){console.error('[SpeechlyClient] Error while invoking "onStart" callback:',t)}})),this.startCbs.length=0;break;case t.WebsocketResponseType.Stopped:this.onResponseCb(i),this.stopCbs.forEach((t=>{try{t(void 0,i.audio_context)}catch(t){console.error('[SpeechlyClient] Error while invoking "onStop" callback:',t)}})),this.stopCbs.length=0;break;default:this.onResponseCb(i)}},this.worker=new"Lyogcm9sbHVwLXBsdWdpbi13ZWItd29ya2VyLWxvYWRlciAqLwp2YXIgd29ya2VyX2NvZGU9ZnVuY3Rpb24odCl7InVzZSBzdHJpY3QiO2NsYXNzIGV7c3RhdGljIGRvd25zYW1wbGUodCxlLHM9MCxpPS0xLG89MCxyPS0xKXtpZihpPDAmJihpPXQubGVuZ3RoLXMpLHI8MCYmKHI9ZS5sZW5ndGgtbykscj5pKXRocm93IG5ldyBFcnJvcihgQ2FuJ3QgZG93bnNhbXBsZTogc291cmNlIGFycmF5IGxlbmd0aCAoJHtpfSkgaXMgc2hvcnRlciB0aGFuIGRlc3RpbmF0aW9uICgke3J9KWApO2lmKDA9PT1yKXRocm93IG5ldyBFcnJvcihgQ2FuJ3QgZG93bnNhbXBsZTogc291cmNlIGFycmF5IGxlbmd0aCAoJHtpfSkgY2FuJ3QgYmUgZG93bnNhbXBsZWQgdG8gemVyby1sZW5ndGggZGVzdGluYXRpb24uYCk7aWYoMD09PWkpdGhyb3cgbmV3IEVycm9yKCJDYW4ndCBkb3duc2FtcGxlOiBzb3VyY2UgcmFuZ2UgY2FuJ3QgYmUgemVybyBsZW5ndGguIik7aWYoMT09PWkpcmV0dXJuIHZvaWQoZVswXT10WzBdKTtsZXQgYT0wO2NvbnN0IG49KHItMSkvKGktMSk7bGV0IGg9MCxsPTA7Y29uc3QgZD1zK2k7Zm9yKDtzPGQ7cysrKXtjb25zdCBpPS41LU1hdGguYWJzKGEpO2grPXRbc10qaSxsKz1pLGErPW4sYT49LjUmJihhLT0xLGVbbysrXT1oL2wsaD0wLGw9MCl9bD4wJiYoZVtvKytdPWgvbCl9c3RhdGljIGdldEVuZXJneSh0LGU9MCxzPS0xKXtpZihzPDAmJihzPXQubGVuZ3RoLWUpLHM8PTApcmV0dXJuIDA7Y29uc3QgaT1lK3M7bGV0IG89MDtmb3IoO2U8aTtlKyspbys9dFtlXSp0W2VdO3JldHVybiBNYXRoLnNxcnQoby9zKX1zdGF0aWMgZ2V0QXVkaW9QZWFrKHQsZT0wLHM9LTEpe2lmKHM8MCYmKHM9dC5sZW5ndGgtZSksczw9MClyZXR1cm4gMDtjb25zdCBpPWUrcztsZXQgbz0wO2Zvcig7ZTxpO2UrKyl0W2VdPm8mJihvPXRbZV0pO3JldHVybiBvfXN0YXRpYyBjb252ZXJ0SW50MTZUb0Zsb2F0KHQsZSxzPTAsaT0tMSxvPTApe2k8MCYmKGk9dC5sZW5ndGgvMi1zKTtjb25zdCByPU1hdGgubWluKHQubGVuZ3RoLzItcyxlLmxlbmd0aC1vKTtpZigoaT1NYXRoLm1pbihpLHIpKTw9MClyZXR1cm4gMDtsZXQgYT0yKnM7Y29uc3Qgbj1hKzIqaTtmb3IoO2E8bjspZVtvKytdPSh0W2ErK10rKHRbYSsrXTw8OCkpLzMyNzY3O3JldHVybiBpfXN0YXRpYyBjb252ZXJ0RmxvYXRUb0ludDE2KHQsZSxzPTAsaT0tMSxvPTApe2k8MCYmKGk9dC5sZW5ndGgtcyk7Y29uc3Qgcj1zK2k7Zm9yKDtzPHI7KWVbbysrXT1+figzMjc2Nyp0W3MrK10pfXN0YXRpYyBlbmVyZ3lUb0RiKHQpe3JldHVybiAxMCpNYXRoLmxvZyh0KS9lLkxPR18yX1BMVVNfTE9HXzV9c3RhdGljIGRiVG9FbmVyZ3kodCl7cmV0dXJuIE1hdGgucG93KDEwLHQvMTApfX1lLkxPR18yX1BMVVNfTE9HXzU9TWF0aC5sb2coMikrTWF0aC5sb2coNSk7Y2xhc3Mgc3tjb25zdHJ1Y3Rvcih0LGUscyl7dGhpcy5pc0FjdGl2ZT0hMSx0aGlzLnN0cmVhbVNhbXBsZVBvcz0wLHRoaXMuc2FtcGxlc1NlbnQ9MCx0aGlzLnV0dGVyYW5jZVNlcmlhbD0tMSx0aGlzLnNlbmRBdWRpbz0odCxlLHMpPT57fSx0aGlzLm9uVmFkU2lnbmFsTG93PSgpPT57fSx0aGlzLm9uVmFkU2lnbmFsSGlnaD0oKT0+e30sdGhpcy5pbnB1dFNhbXBsZVJhdGU9MTZlMyx0aGlzLmludGVybmFsU2FtcGxlUmF0ZT0xNmUzLHRoaXMuaGlzdG9yeUZyYW1lcz01LHRoaXMuZnJhbWVNaWxsaXM9MzAsdGhpcy5jdXJyZW50RnJhbWVOdW1iZXI9MCx0aGlzLmZyYW1lU2FtcGxlUG9zPTAsdGhpcy5zdHJlYW1GcmFtZVBvcz0wLHRoaXMuaXNTaWduYWxEZXRlY3RlZD0hMSx0aGlzLmlucHV0U2FtcGxlUmF0ZT10LHRoaXMuaW50ZXJuYWxTYW1wbGVSYXRlPWUsdGhpcy5oaXN0b3J5RnJhbWVzPXMsdGhpcy5mcmFtZVNhbXBsZXM9fn4odGhpcy5pbnRlcm5hbFNhbXBsZVJhdGUqdGhpcy5mcmFtZU1pbGxpcy8xZTMpLHRoaXMuc2FtcGxlUmluZ0J1ZmZlcj1uZXcgRmxvYXQzMkFycmF5KHRoaXMuZnJhbWVTYW1wbGVzKnRoaXMuaGlzdG9yeUZyYW1lcyl9c3RhcnRDb250ZXh0KCl7dGhpcy5pc0FjdGl2ZT0hMCx0aGlzLnNhbXBsZXNTZW50PTAsdGhpcy51dHRlcmFuY2VTZXJpYWwrK31zdG9wQ29udGV4dCgpe3RoaXMuZmx1c2goKSx0aGlzLmlzQWN0aXZlPSExfXJlc2V0U3RyZWFtKCl7dmFyIHQ7dGhpcy5zdHJlYW1GcmFtZVBvcz0wLHRoaXMuc3RyZWFtU2FtcGxlUG9zPTAsdGhpcy5mcmFtZVNhbXBsZVBvcz0wLHRoaXMuY3VycmVudEZyYW1lTnVtYmVyPTAsdGhpcy51dHRlcmFuY2VTZXJpYWw9LTEsbnVsbD09PSh0PXRoaXMudmFkKXx8dm9pZCAwPT09dHx8dC5yZXNldFZBRCgpfWZsdXNoKCl7dGhpcy5wcm9jZXNzQXVkaW8odGhpcy5zYW1wbGVSaW5nQnVmZmVyLDAsdGhpcy5mcmFtZVNhbXBsZVBvcywhMCl9cHJvY2Vzc0F1ZGlvKHQscz0wLGk9LTEsbz0hMSl7aWYoaTwwJiYoaT10Lmxlbmd0aCksMD09PWkpcmV0dXJuO2xldCByPXM7Y29uc3QgYT1zK2k7Zm9yKDtyPGE7KXtjb25zdCBzPXRoaXMuY3VycmVudEZyYW1lTnVtYmVyKnRoaXMuZnJhbWVTYW1wbGVzO2lmKHRoaXMuaW5wdXRTYW1wbGVSYXRlPT09dGhpcy5pbnRlcm5hbFNhbXBsZVJhdGUpe2NvbnN0IGU9TWF0aC5taW4oYS1yLHRoaXMuZnJhbWVTYW1wbGVzLXRoaXMuZnJhbWVTYW1wbGVQb3MpLGk9dGhpcy5mcmFtZVNhbXBsZVBvcytlO2Zvcig7dGhpcy5mcmFtZVNhbXBsZVBvczxpOyl0aGlzLnNhbXBsZVJpbmdCdWZmZXJbcyt0aGlzLmZyYW1lU2FtcGxlUG9zKytdPXRbcisrXX1lbHNle2NvbnN0IGk9MSp0aGlzLmlucHV0U2FtcGxlUmF0ZS90aGlzLmludGVybmFsU2FtcGxlUmF0ZSxvPU1hdGgubWluKGEtcixNYXRoLnJvdW5kKGkqKHRoaXMuZnJhbWVTYW1wbGVzLXRoaXMuZnJhbWVTYW1wbGVQb3MpKSksbj1NYXRoLm1pbihNYXRoLnJvdW5kKChhLXIpL2kpLHRoaXMuZnJhbWVTYW1wbGVzLXRoaXMuZnJhbWVTYW1wbGVQb3MpO24+MCYmZS5kb3duc2FtcGxlKHQsdGhpcy5zYW1wbGVSaW5nQnVmZmVyLHIsbyxzK3RoaXMuZnJhbWVTYW1wbGVQb3Msbikscis9byx0aGlzLmZyYW1lU2FtcGxlUG9zKz1ufWlmKHRoaXMuZnJhbWVTYW1wbGVQb3M+dGhpcy5mcmFtZVNhbXBsZXMpdGhyb3cgbmV3IEVycm9yKGB0aGlzLmZyYW1lU2FtcGxlUG9zICgke3RoaXMuZnJhbWVTYW1wbGVQb3N9KSA+IHRoaXMuZnJhbWVTYW1wbGVzICgke3RoaXMuZnJhbWVTYW1wbGVzfSlgKTtpZih0aGlzLmZyYW1lU2FtcGxlUG9zPT09dGhpcy5mcmFtZVNhbXBsZXN8fG8pe2NvbnN0IHQ9bz90aGlzLmZyYW1lU2FtcGxlUG9zOnRoaXMuZnJhbWVTYW1wbGVzO2lmKG98fHRoaXMucHJvY2Vzc0ZyYW1lKHRoaXMuc2FtcGxlUmluZ0J1ZmZlcixzLHQpLHRoaXMuaXNBY3RpdmUpe2lmKDA9PT10aGlzLnNhbXBsZXNTZW50KXtjb25zdCB0PU1hdGgubWluKHRoaXMuc3RyZWFtRnJhbWVQb3MsdGhpcy5oaXN0b3J5RnJhbWVzLTEpO2xldCBlPSh0aGlzLmN1cnJlbnRGcmFtZU51bWJlcit0aGlzLmhpc3RvcnlGcmFtZXMtdCkldGhpcy5oaXN0b3J5RnJhbWVzO2Zvcig7ZSE9PXRoaXMuY3VycmVudEZyYW1lTnVtYmVyOyl0aGlzLnNlbmRBdWRpbyh0aGlzLnNhbXBsZVJpbmdCdWZmZXIsZSp0aGlzLmZyYW1lU2FtcGxlcyx0aGlzLmZyYW1lU2FtcGxlcyksdGhpcy5zYW1wbGVzU2VudCs9dGhpcy5mcmFtZVNhbXBsZXMsZT0oZSsxKSV0aGlzLmhpc3RvcnlGcmFtZXN9dGhpcy5zZW5kQXVkaW8odGhpcy5zYW1wbGVSaW5nQnVmZmVyLHMsdCksdGhpcy5zYW1wbGVzU2VudCs9dH10aGlzLmZyYW1lU2FtcGxlUG9zPT09dGhpcy5mcmFtZVNhbXBsZXMmJih0aGlzLmZyYW1lU2FtcGxlUG9zPTAsdGhpcy5zdHJlYW1GcmFtZVBvcys9MSx0aGlzLnN0cmVhbVNhbXBsZVBvcys9dCx0aGlzLmN1cnJlbnRGcmFtZU51bWJlcj0odGhpcy5jdXJyZW50RnJhbWVOdW1iZXIrMSkldGhpcy5oaXN0b3J5RnJhbWVzKX19fXByb2Nlc3NGcmFtZSh0LGU9MCxzPS0xKXt0aGlzLmFuYWx5emVBdWRpb0ZyYW1lKHQsZSxzKSx0aGlzLmF1dG9Db250cm9sTGlzdGVuaW5nKCl9YW5hbHl6ZUF1ZGlvRnJhbWUodCxlLHMpe3ZhciBpOyhudWxsPT09KGk9dGhpcy52YWQpfHx2b2lkIDA9PT1pP3ZvaWQgMDppLnZhZE9wdGlvbnMuZW5hYmxlZCkmJnRoaXMudmFkLnByb2Nlc3NGcmFtZSh0LGUscyl9YXV0b0NvbnRyb2xMaXN0ZW5pbmcoKXt2YXIgdDsobnVsbD09PSh0PXRoaXMudmFkKXx8dm9pZCAwPT09dD92b2lkIDA6dC52YWRPcHRpb25zLmVuYWJsZWQpJiYoIXRoaXMuaXNTaWduYWxEZXRlY3RlZCYmdGhpcy52YWQuaXNTaWduYWxEZXRlY3RlZCYmKHRoaXMub25WYWRTaWduYWxIaWdoKCksdGhpcy5pc1NpZ25hbERldGVjdGVkPSEwKSx0aGlzLmlzU2lnbmFsRGV0ZWN0ZWQmJiF0aGlzLnZhZC5pc1NpZ25hbERldGVjdGVkJiYodGhpcy5vblZhZFNpZ25hbExvdygpLHRoaXMuaXNTaWduYWxEZXRlY3RlZD0hMSkpfX1jbGFzcyBpe2NvbnN0cnVjdG9yKHQpe3RoaXMuaXNTaWduYWxEZXRlY3RlZD0hMSx0aGlzLnNpZ25hbERiPS05MCx0aGlzLm5vaXNlTGV2ZWxEYj0tOTAsdGhpcy5mcmFtZU1pbGxpcz0zMCx0aGlzLmVuZXJneT0wLHRoaXMuYmFzZWxpbmVFbmVyZ3k9LTEsdGhpcy5sb3VkRnJhbWVCaXRzPTAsdGhpcy52YWRTdXN0YWluTWlsbGlzTGVmdD0wLHRoaXMudmFkT3B0aW9ucz10fWFkanVzdFZhZE9wdGlvbnModCl7dGhpcy52YWRPcHRpb25zPU9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSx0aGlzLnZhZE9wdGlvbnMpLHQpfXJlc2V0VkFEKCl7dGhpcy5pc1NpZ25hbERldGVjdGVkPSExLHRoaXMubG91ZEZyYW1lQml0cz0wLHRoaXMuZW5lcmd5PTAsdGhpcy5iYXNlbGluZUVuZXJneT0tMX1wcm9jZXNzRnJhbWUodCxzPTAsaT0tMSl7aWYoIXRoaXMudmFkT3B0aW9ucy5lbmFibGVkKXJldHVybiB2b2lkIHRoaXMucmVzZXRWQUQoKTt0aGlzLmVuZXJneT1lLmdldEVuZXJneSh0LHMsaSksdGhpcy5iYXNlbGluZUVuZXJneTwwJiYodGhpcy5iYXNlbGluZUVuZXJneT10aGlzLmVuZXJneSk7Y29uc3Qgbz10aGlzLmVuZXJneT5NYXRoLm1heChlLmRiVG9FbmVyZ3kodGhpcy52YWRPcHRpb25zLm5vaXNlR2F0ZURiKSx0aGlzLmJhc2VsaW5lRW5lcmd5KmUuZGJUb0VuZXJneSh0aGlzLnZhZE9wdGlvbnMuc2lnbmFsVG9Ob2lzZURiKSk7dGhpcy5wdXNoRnJhbWVIaXN0b3J5KG8pLHRoaXMuaXNTaWduYWxEZXRlY3RlZD10aGlzLmRldGVybWluZU5ld1NpZ25hbFN0YXRlKHRoaXMuaXNTaWduYWxEZXRlY3RlZCksdGhpcy5hZGFwdEJhY2tncm91bmROb2lzZSgpLHRoaXMuc2lnbmFsRGI9ZS5lbmVyZ3lUb0RiKHRoaXMuZW5lcmd5L3RoaXMuYmFzZWxpbmVFbmVyZ3kpLHRoaXMubm9pc2VMZXZlbERiPWUuZW5lcmd5VG9EYih0aGlzLmJhc2VsaW5lRW5lcmd5KX1kZXRlcm1pbmVOZXdTaWduYWxTdGF0ZSh0KXt0aGlzLnZhZFN1c3RhaW5NaWxsaXNMZWZ0PU1hdGgubWF4KHRoaXMudmFkU3VzdGFpbk1pbGxpc0xlZnQtdGhpcy5mcmFtZU1pbGxpcywwKTtjb25zdCBlPXRoaXMuY291bnRMb3VkRnJhbWVzKHRoaXMudmFkT3B0aW9ucy5zaWduYWxTZWFyY2hGcmFtZXMpLHM9TWF0aC5yb3VuZCh0aGlzLnZhZE9wdGlvbnMuc2lnbmFsQWN0aXZhdGlvbip0aGlzLnZhZE9wdGlvbnMuc2lnbmFsU2VhcmNoRnJhbWVzKSxpPU1hdGgucm91bmQodGhpcy52YWRPcHRpb25zLnNpZ25hbFJlbGVhc2UqdGhpcy52YWRPcHRpb25zLnNpZ25hbFNlYXJjaEZyYW1lcyk7cmV0dXJuIGU+PXM/KHRoaXMudmFkU3VzdGFpbk1pbGxpc0xlZnQ9dGhpcy52YWRPcHRpb25zLnNpZ25hbFN1c3RhaW5NaWxsaXMsITApOiEoZTw9aSYmMD09PXRoaXMudmFkU3VzdGFpbk1pbGxpc0xlZnQpJiZ0fWFkYXB0QmFja2dyb3VuZE5vaXNlKCl7aWYoIXRoaXMuaXNTaWduYWxEZXRlY3RlZCYmdGhpcy52YWRPcHRpb25zLm5vaXNlTGVhcm5IYWxmdGltZU1pbGxpcz4wKXt2YXIgdD1NYXRoLnBvdygyLC10aGlzLmZyYW1lTWlsbGlzL3RoaXMudmFkT3B0aW9ucy5ub2lzZUxlYXJuSGFsZnRpbWVNaWxsaXMpO3RoaXMuYmFzZWxpbmVFbmVyZ3k9dGhpcy5iYXNlbGluZUVuZXJneSp0K3RoaXMuZW5lcmd5KigxLXQpfX1wdXNoRnJhbWVIaXN0b3J5KHQpe3RoaXMubG91ZEZyYW1lQml0cz0odD8xOjApfHRoaXMubG91ZEZyYW1lQml0czw8MX1jb3VudExvdWRGcmFtZXModCl7bGV0IGU9MCxzPXRoaXMubG91ZEZyYW1lQml0cztmb3IoO3Q+MDspMT09KDEmcykmJmUrKyxzPj49MSx0LS07cmV0dXJuIGV9fXZhciBvLHIsYTshZnVuY3Rpb24odCl7dC5TdGFydGVkPSJzdGFydGVkIix0LlN0b3BwZWQ9InN0b3BwZWQiLHQuU2VnbWVudEVuZD0ic2VnbWVudF9lbmQiLHQuVHJhbnNjcmlwdD0idHJhbnNjcmlwdCIsdC5FbnRpdHk9ImVudGl0eSIsdC5JbnRlbnQ9ImludGVudCIsdC5UZW50YXRpdmVUcmFuc2NyaXB0PSJ0ZW50YXRpdmVfdHJhbnNjcmlwdCIsdC5UZW50YXRpdmVFbnRpdGllcz0idGVudGF0aXZlX2VudGl0aWVzIix0LlRlbnRhdGl2ZUludGVudD0idGVudGF0aXZlX2ludGVudCJ9KG98fChvPXt9KSksZnVuY3Rpb24odCl7dC5PcGVuZWQ9IldFQlNPQ0tFVF9PUEVOIix0LkNsb3NlZD0iV0VCU09DS0VUX0NMT1NFRCIsdC5BdWRpb1Byb2Nlc3NvclJlYWR5PSJTT1VSQ0VfU0FNUExFX1JBVEVfU0VUX1NVQ0NFU1MiLHQuVmFkU2lnbmFsSGlnaD0iVmFkU2lnbmFsSGlnaCIsdC5WYWRTaWduYWxMb3c9IlZhZFNpZ25hbExvdyJ9KHJ8fChyPXt9KSksZnVuY3Rpb24odCl7dC5jb25uZWN0PSJjb25uZWN0Iix0LmluaXRBdWRpb1Byb2Nlc3Nvcj0iaW5pdEF1ZGlvUHJvY2Vzc29yIix0LmFkanVzdEF1ZGlvUHJvY2Vzc29yPSJhZGp1c3RBdWRpb1Byb2Nlc3NvciIsdC5TRVRfU0hBUkVEX0FSUkFZX0JVRkZFUlM9IlNFVF9TSEFSRURfQVJSQVlfQlVGRkVSUyIsdC5DTE9TRT0iQ0xPU0UiLHQuU1RBUlRfQ09OVEVYVD0iU1RBUlRfQ09OVEVYVCIsdC5TV0lUQ0hfQ09OVEVYVD0iU1dJVENIX0NPTlRFWFQiLHQuU1RPUF9DT05URVhUPSJTVE9QX0NPTlRFWFQiLHQuQVVESU89IkFVRElPIix0LnN0YXJ0U3RyZWFtPSJzdGFydFN0cmVhbSIsdC5zdG9wU3RyZWFtPSJzdG9wU3RyZWFtIix0LnNldENvbnRleHRPcHRpb25zPSJzZXRDb250ZXh0T3B0aW9ucyJ9KGF8fChhPXt9KSk7Y29uc3Qgbj0wLGg9MSxsPTI7Y2xhc3MgZHtjb25zdHJ1Y3Rvcih0KXt0aGlzLnRhcmdldFNhbXBsZVJhdGU9MTZlMyx0aGlzLmlzQ29udGV4dFN0YXJ0ZWQ9ITEsdGhpcy5mcmFtZU1pbGxpcz0zMCx0aGlzLm91dHB1dEF1ZGlvRnJhbWU9bmV3IEludDE2QXJyYXkodGhpcy5mcmFtZU1pbGxpcyp0aGlzLnRhcmdldFNhbXBsZVJhdGUvMWUzKSx0aGlzLmRlYnVnPSExLHRoaXMub25XZWJzb2NrZXRDbG9zZT10PT57aWYoIXRoaXMud2Vic29ja2V0KXRocm93IEVycm9yKCJXZWJTb2NrZXQgaXMgdW5kZWZpbmVkIik7dGhpcy5kZWJ1ZyYmY29uc29sZS5sb2coIltXZWJTb2NrZXRDbGllbnRdIiwib25XZWJzb2NrZXRDbG9zZSIpLHRoaXMud2Vic29ja2V0LnJlbW92ZUV2ZW50TGlzdGVuZXIoIm9wZW4iLHRoaXMub25XZWJzb2NrZXRPcGVuKSx0aGlzLndlYnNvY2tldC5yZW1vdmVFdmVudExpc3RlbmVyKCJtZXNzYWdlIix0aGlzLm9uV2Vic29ja2V0TWVzc2FnZSksdGhpcy53ZWJzb2NrZXQucmVtb3ZlRXZlbnRMaXN0ZW5lcigiZXJyb3IiLHRoaXMub25XZWJzb2NrZXRFcnJvciksdGhpcy53ZWJzb2NrZXQucmVtb3ZlRXZlbnRMaXN0ZW5lcigiY2xvc2UiLHRoaXMub25XZWJzb2NrZXRDbG9zZSksdGhpcy53ZWJzb2NrZXQ9dm9pZCAwLHRoaXMud29ya2VyQ3R4LnBvc3RNZXNzYWdlKHt0eXBlOnIuQ2xvc2VkLGNvZGU6dC5jb2RlLHJlYXNvbjp0LnJlYXNvbix3YXNDbGVhbjp0Lndhc0NsZWFufSl9LHRoaXMub25XZWJzb2NrZXRPcGVuPXQ9Pnt0aGlzLmRlYnVnJiZjb25zb2xlLmxvZygiW1dlYlNvY2tldENsaWVudF0iLCJ3ZWJzb2NrZXQgb3BlbmVkIiksdGhpcy53b3JrZXJDdHgucG9zdE1lc3NhZ2Uoe3R5cGU6ci5PcGVuZWR9KX0sdGhpcy5vbldlYnNvY2tldEVycm9yPXQ9Pnt0aGlzLmRlYnVnJiZjb25zb2xlLmxvZygiW1dlYlNvY2tldENsaWVudF0iLCJ3ZWJzb2NrZXQgZXJyb3IiKX0sdGhpcy5vbldlYnNvY2tldE1lc3NhZ2U9dD0+e2xldCBlO3RyeXtlPUpTT04ucGFyc2UodC5kYXRhKX1jYXRjaCh0KXtyZXR1cm4gdm9pZCBjb25zb2xlLmVycm9yKCJbV2ViU29ja2V0Q2xpZW50XSIsImVycm9yIHBhcnNpbmcgcmVzcG9uc2UgZnJvbSB0aGUgc2VydmVyOiIsdCl9dGhpcy53b3JrZXJDdHgucG9zdE1lc3NhZ2UoZSl9LHRoaXMud29ya2VyQ3R4PXR9Y29ubmVjdCh0LGUscyxpKXt0aGlzLmRlYnVnPWksdGhpcy5kZWJ1ZyYmY29uc29sZS5sb2coIltXZWJTb2NrZXRDbGllbnRdIiwiY29ubmVjdGluZyB0byAiLHQpLHRoaXMudGFyZ2V0U2FtcGxlUmF0ZT1zLHRoaXMuaXNDb250ZXh0U3RhcnRlZD0hMSx0aGlzLndlYnNvY2tldD1uZXcgV2ViU29ja2V0KHQsZSksdGhpcy53ZWJzb2NrZXQuYWRkRXZlbnRMaXN0ZW5lcigib3BlbiIsdGhpcy5vbldlYnNvY2tldE9wZW4pLHRoaXMud2Vic29ja2V0LmFkZEV2ZW50TGlzdGVuZXIoIm1lc3NhZ2UiLHRoaXMub25XZWJzb2NrZXRNZXNzYWdlKSx0aGlzLndlYnNvY2tldC5hZGRFdmVudExpc3RlbmVyKCJlcnJvciIsdGhpcy5vbldlYnNvY2tldEVycm9yKSx0aGlzLndlYnNvY2tldC5hZGRFdmVudExpc3RlbmVyKCJjbG9zZSIsdGhpcy5vbldlYnNvY2tldENsb3NlKX1pbml0QXVkaW9Qcm9jZXNzb3IodCxvKXt0aGlzLmF1ZGlvUHJvY2Vzc29yPW5ldyBzKHQsdGhpcy50YXJnZXRTYW1wbGVSYXRlLDUpLG8mJih0aGlzLmF1ZGlvUHJvY2Vzc29yLnZhZD1uZXcgaShvKSx0aGlzLmF1ZGlvUHJvY2Vzc29yLm9uVmFkU2lnbmFsSGlnaD0oKT0+e3ZhciB0LGUscztjb25zdCBpPW51bGw9PT0oZT1udWxsPT09KHQ9dGhpcy5hdWRpb1Byb2Nlc3Nvcil8fHZvaWQgMD09PXQ/dm9pZCAwOnQudmFkKXx8dm9pZCAwPT09ZT92b2lkIDA6ZS52YWRPcHRpb25zOyhudWxsPT1pP3ZvaWQgMDppLmVuYWJsZWQpJiYobnVsbD09aT92b2lkIDA6aS5jb250cm9sTGlzdGVuaW5nKSYmKChudWxsPT09KHM9dGhpcy5kZWZhdWx0Q29udGV4dE9wdGlvbnMpfHx2b2lkIDA9PT1zP3ZvaWQgMDpzLmltbWVkaWF0ZSk/dGhpcy5zdGFydENvbnRleHQodGhpcy52YWRDb250ZXh0T3B0aW9ucyk6dGhpcy53b3JrZXJDdHgucG9zdE1lc3NhZ2Uoe3R5cGU6ci5WYWRTaWduYWxIaWdofSkpfSx0aGlzLmF1ZGlvUHJvY2Vzc29yLm9uVmFkU2lnbmFsTG93PSgpPT57dmFyIHQsZSxzO2NvbnN0IGk9bnVsbD09PShlPW51bGw9PT0odD10aGlzLmF1ZGlvUHJvY2Vzc29yKXx8dm9pZCAwPT09dD92b2lkIDA6dC52YWQpfHx2b2lkIDA9PT1lP3ZvaWQgMDplLnZhZE9wdGlvbnM7KG51bGw9PWk/dm9pZCAwOmkuZW5hYmxlZCkmJihudWxsPT1pP3ZvaWQgMDppLmNvbnRyb2xMaXN0ZW5pbmcpJiYoKG51bGw9PT0ocz10aGlzLmRlZmF1bHRDb250ZXh0T3B0aW9ucyl8fHZvaWQgMD09PXM/dm9pZCAwOnMuaW1tZWRpYXRlKT90aGlzLnN0b3BDb250ZXh0KCk6dGhpcy53b3JrZXJDdHgucG9zdE1lc3NhZ2Uoe3R5cGU6ci5WYWRTaWduYWxMb3d9KSl9KSx0aGlzLmF1ZGlvUHJvY2Vzc29yLnNlbmRBdWRpbz0odCxzLGkpPT57ZS5jb252ZXJ0RmxvYXRUb0ludDE2KHQsdGhpcy5vdXRwdXRBdWRpb0ZyYW1lLHMsaSksdGhpcy5zZW5kKHRoaXMub3V0cHV0QXVkaW9GcmFtZSl9LHZvaWQgMCE9PXRoaXMud29ya2VyQ3R4JiZ0aGlzLndvcmtlckN0eC5wb3N0TWVzc2FnZSh7dHlwZTpyLkF1ZGlvUHJvY2Vzc29yUmVhZHl9KX1hZGp1c3RBdWRpb1Byb2Nlc3Nvcih0KXtpZighdGhpcy5hdWRpb1Byb2Nlc3Nvcil0aHJvdyBuZXcgRXJyb3IoIk5vIEF1ZGlvUHJvY2Vzc29yIik7aWYodC52YWQpe2lmKCF0aGlzLmF1ZGlvUHJvY2Vzc29yLnZhZCl0aHJvdyBuZXcgRXJyb3IoIk5vIFZBRCBpbiBBdWRpb1Byb2Nlc3Nvci4gRGlkIHlvdSBkZWZpbmUgYHZhZGAgaW4gQnJvd3NlckNsaWVudCBjb25zdHJ1Y3RvciBwYXJhbWV0ZXJzPyIpO3RoaXMuYXVkaW9Qcm9jZXNzb3IudmFkLmFkanVzdFZhZE9wdGlvbnModC52YWQpfX1zZXRTaGFyZWRBcnJheUJ1ZmZlcnModCxlKXt0aGlzLmNvbnRyb2xTQUI9bmV3IEludDMyQXJyYXkodCksdGhpcy5kYXRhU0FCPW5ldyBGbG9hdDMyQXJyYXkoZSk7Y29uc3Qgcz10aGlzLmRhdGFTQUIubGVuZ3RoLzMyO3RoaXMuZGVidWcmJmNvbnNvbGUubG9nKCJbV2ViU29ja2V0Q2xpZW50XSIsIkF1ZGlvIGhhbmRsZSBpbnRlcnZhbCIscywibXMiKSxzZXRJbnRlcnZhbCh0aGlzLnByb2Nlc3NBdWRpb1NBQi5iaW5kKHRoaXMpLHMpfXN0YXJ0U3RyZWFtKHQpe2lmKCF0aGlzLmF1ZGlvUHJvY2Vzc29yKXRocm93IG5ldyBFcnJvcigiTm8gQXVkaW9Qcm9jZXNzb3IiKTt0aGlzLnZhZENvbnRleHRPcHRpb25zPXQsdGhpcy5hdWRpb1Byb2Nlc3Nvci5yZXNldFN0cmVhbSgpfXN0b3BTdHJlYW0oKXtpZighdGhpcy5hdWRpb1Byb2Nlc3Nvcil0aHJvdyBuZXcgRXJyb3IoIk5vIEF1ZGlvUHJvY2Vzc29yIik7dGhpcy5pc0NvbnRleHRTdGFydGVkJiZ0aGlzLnN0b3BDb250ZXh0KCksdGhpcy52YWRDb250ZXh0T3B0aW9ucz12b2lkIDB9cHJvY2Vzc0F1ZGlvKHQpe2lmKCF0aGlzLmF1ZGlvUHJvY2Vzc29yKXRocm93IG5ldyBFcnJvcigiTm8gQXVkaW9Qcm9jZXNzb3IiKTt0aGlzLmF1ZGlvUHJvY2Vzc29yLnByb2Nlc3NBdWRpbyh0KX1wcm9jZXNzQXVkaW9TQUIoKXtpZighdGhpcy5jb250cm9sU0FCfHwhdGhpcy5kYXRhU0FCKXRocm93IG5ldyBFcnJvcigiTm8gU2hhcmVkQXJyYXlCdWZmZXJzIik7Y29uc3QgdD10aGlzLmNvbnRyb2xTQUJbaF07aWYoMD09PXRoaXMuY29udHJvbFNBQltsXSYmdD4wKXtjb25zdCBlPXRoaXMuZGF0YVNBQi5zdWJhcnJheSgwLHQpO3RoaXMuY29udHJvbFNBQltoXT0wLHRoaXMuY29udHJvbFNBQltuXT0wLGUubGVuZ3RoPjAmJnRoaXMucHJvY2Vzc0F1ZGlvKGUpfX1zdGFydENvbnRleHQodCl7dmFyIGU7aWYoIXRoaXMuYXVkaW9Qcm9jZXNzb3IpdGhyb3cgRXJyb3IoIk5vIEF1ZGlvUHJvY2Vzc29yIik7aWYodGhpcy5pc0NvbnRleHRTdGFydGVkKXJldHVybiB2b2lkIGNvbnNvbGUuZXJyb3IoIltXZWJTb2NrZXRDbGllbnRdIiwiY2FuJ3Qgc3RhcnQgY29udGV4dDogYWN0aXZlIGNvbnRleHQgZXhpc3RzIik7dGhpcy5hdWRpb1Byb2Nlc3Nvci5zdGFydENvbnRleHQoKSx0aGlzLmlzQ29udGV4dFN0YXJ0ZWQ9ITA7bGV0IHM9bnVsbCE9PShlPXRoaXMuZGVmYXVsdENvbnRleHRPcHRpb25zKSYmdm9pZCAwIT09ZT9lOnt9O3ZvaWQgMCE9PXQmJihzPU9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSxzKSx0KSk7Y29uc3QgaT11KHMpO2kuZXZlbnQ9InN0YXJ0Iix0aGlzLnNlbmQoSlNPTi5zdHJpbmdpZnkoaSkpfXN0b3BDb250ZXh0KCl7aWYoIXRoaXMuYXVkaW9Qcm9jZXNzb3IpdGhyb3cgRXJyb3IoIk5vIEF1ZGlvUHJvY2Vzc29yIik7aWYoIXRoaXMuaXNDb250ZXh0U3RhcnRlZClyZXR1cm4gdm9pZCBjb25zb2xlLmVycm9yKCJbV2ViU29ja2V0Q2xpZW50XSIsImNhbid0IHN0b3AgY29udGV4dDogbm8gYWN0aXZlIGNvbnRleHQiKTt0aGlzLmF1ZGlvUHJvY2Vzc29yLnN0b3BDb250ZXh0KCksdGhpcy5pc0NvbnRleHRTdGFydGVkPSExO2NvbnN0IHQ9SlNPTi5zdHJpbmdpZnkoe2V2ZW50OiJzdG9wIn0pO3RoaXMuc2VuZCh0KX1zd2l0Y2hDb250ZXh0KHQpe2lmKCF0aGlzLndlYnNvY2tldCl0aHJvdyBFcnJvcigiV2ViU29ja2V0IGlzIHVuZGVmaW5lZCIpO2lmKCF0aGlzLmlzQ29udGV4dFN0YXJ0ZWQpcmV0dXJuIHZvaWQgY29uc29sZS5lcnJvcigiW1dlYlNvY2tldENsaWVudF0iLCJjYW4ndCBzd2l0Y2ggY29udGV4dDogbm8gYWN0aXZlIGNvbnRleHQiKTtpZih2b2lkIDA9PT0obnVsbD09dD92b2lkIDA6dC5hcHBJZCkpcmV0dXJuIHZvaWQgY29uc29sZS5lcnJvcigiW1dlYlNvY2tldENsaWVudF0iLCJjYW4ndCBzd2l0Y2ggY29udGV4dDogbmV3IGFwcCBpZCBpcyB1bmRlZmluZWQiKTtjb25zdCBlPUpTT04uc3RyaW5naWZ5KHtldmVudDoic3RvcCJ9KTt0aGlzLnNlbmQoZSk7Y29uc3Qgcz11KHQpO3MuZXZlbnQ9InN0YXJ0Iix0aGlzLnNlbmQoSlNPTi5zdHJpbmdpZnkocykpfWNsb3NlV2Vic29ja2V0KHQ9MTAwNSxlPSJObyBTdGF0dXMgUmVjZWl2ZWQiKXtpZih0aGlzLmRlYnVnJiZjb25zb2xlLmxvZygiW1dlYlNvY2tldENsaWVudF0iLCJXZWJzb2NrZXQgY2xvc2luZyIpLCF0aGlzLndlYnNvY2tldCl0aHJvdyBFcnJvcigiV2ViU29ja2V0IGlzIHVuZGVmaW5lZCIpO3RoaXMud2Vic29ja2V0LmNsb3NlKHQsZSl9c2VuZCh0KXtpZighdGhpcy53ZWJzb2NrZXQpdGhyb3cgbmV3IEVycm9yKCJObyBXZWJzb2NrZXQiKTtpZih0aGlzLndlYnNvY2tldC5yZWFkeVN0YXRlIT09dGhpcy53ZWJzb2NrZXQuT1BFTil0aHJvdyBuZXcgRXJyb3IoYEV4cGVjdGVkIE9QRU4gV2Vic29ja2V0IHN0YXRlLCBidXQgZ290ICR7dGhpcy53ZWJzb2NrZXQucmVhZHlTdGF0ZX1gKTt0cnl7dGhpcy53ZWJzb2NrZXQuc2VuZCh0KX1jYXRjaCh0KXtjb25zb2xlLmxvZygiW1dlYlNvY2tldENsaWVudF0iLCJzZXJ2ZXIgY29ubmVjdGlvbiBlcnJvciIsdCl9fXNldENvbnRleHRPcHRpb25zKHQpe3RoaXMuZGVmYXVsdENvbnRleHRPcHRpb25zPXR9fWNvbnN0IGM9c2VsZixtPW5ldyBkKGMpO2Z1bmN0aW9uIHUodCl7Y29uc3QgZT17b3B0aW9uczp7dGltZXpvbmU6W0ludGwuRGF0ZVRpbWVGb3JtYXQoKS5yZXNvbHZlZE9wdGlvbnMoKS50aW1lWm9uZV19fTtyZXR1cm4gdm9pZCAwPT09dHx8KGUub3B0aW9ucy52b2NhYnVsYXJ5PXQudm9jYWJ1bGFyeSxlLm9wdGlvbnMudm9jYWJ1bGFyeV9iaWFzPXQudm9jYWJ1bGFyeUJpYXMsZS5vcHRpb25zLnNpbGVuY2VfdHJpZ2dlcmVkX3NlZ21lbnRhdGlvbj10LnNpbGVuY2VUcmlnZ2VyZWRTZWdtZW50YXRpb24sdm9pZCAwIT09KG51bGw9PXQ/dm9pZCAwOnQudGltZXpvbmUpJiYoZS5vcHRpb25zLnRpbWV6b25lPW51bGw9PXQ/dm9pZCAwOnQudGltZXpvbmUpLHZvaWQgMCE9PXQuYXBwSWQmJihlLmFwcElkPXQuYXBwSWQpKSxlfXJldHVybiBjLm9ubWVzc2FnZT1mdW5jdGlvbih0KXtzd2l0Y2godC5kYXRhLnR5cGUpe2Nhc2UgYS5jb25uZWN0Om0uY29ubmVjdCh0LmRhdGEuYXBpVXJsLHQuZGF0YS5hdXRoVG9rZW4sdC5kYXRhLnRhcmdldFNhbXBsZVJhdGUsdC5kYXRhLmRlYnVnKTticmVhaztjYXNlIGEuaW5pdEF1ZGlvUHJvY2Vzc29yOm0uaW5pdEF1ZGlvUHJvY2Vzc29yKHQuZGF0YS5zb3VyY2VTYW1wbGVSYXRlLHQuZGF0YS52YWRPcHRpb25zKTticmVhaztjYXNlIGEuYWRqdXN0QXVkaW9Qcm9jZXNzb3I6bS5hZGp1c3RBdWRpb1Byb2Nlc3Nvcih0LmRhdGEucGFyYW1zKTticmVhaztjYXNlIGEuU0VUX1NIQVJFRF9BUlJBWV9CVUZGRVJTOm0uc2V0U2hhcmVkQXJyYXlCdWZmZXJzKHQuZGF0YS5jb250cm9sU0FCLHQuZGF0YS5kYXRhU0FCKTticmVhaztjYXNlIGEuQ0xPU0U6bS5jbG9zZVdlYnNvY2tldCgxZTMsIkNsb3NlIHJlcXVlc3RlZCBieSBjbGllbnQiKTticmVhaztjYXNlIGEuc3RhcnRTdHJlYW06bS5zdGFydFN0cmVhbSh0LmRhdGEub3B0aW9ucyk7YnJlYWs7Y2FzZSBhLnN0b3BTdHJlYW06bS5zdG9wU3RyZWFtKCk7YnJlYWs7Y2FzZSBhLlNUQVJUX0NPTlRFWFQ6bS5zdGFydENvbnRleHQodC5kYXRhLm9wdGlvbnMpO2JyZWFrO2Nhc2UgYS5TV0lUQ0hfQ09OVEVYVDptLnN3aXRjaENvbnRleHQodC5kYXRhLm9wdGlvbnMpO2JyZWFrO2Nhc2UgYS5TVE9QX0NPTlRFWFQ6bS5zdG9wQ29udGV4dCgpO2JyZWFrO2Nhc2UgYS5BVURJTzptLnByb2Nlc3NBdWRpbyh0LmRhdGEucGF5bG9hZCk7YnJlYWs7Y2FzZSBhLnNldENvbnRleHRPcHRpb25zOm0uc2V0Q29udGV4dE9wdGlvbnModC5kYXRhLm9wdGlvbnMpO2JyZWFrO2RlZmF1bHQ6Y29uc29sZS5sb2coIldPUktFUiIsdCl9fSx0LmNvbnRleHRPcHRpb25zVG9Nc2c9dSx0LmRlZmF1bHQ9ZCxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdH0oe30pOwoK",this.worker.addEventListener("message",this.onWebsocketMessage)}onResponse(t){this.onResponseCb=t}onClose(t){this.onCloseCb=t}initialize(e,i,n,s){return o(this,void 0,void 0,(function*(){return this.worker.postMessage({type:t.ControllerSignal.connect,apiUrl:e,authToken:i,targetSampleRate:n,debug:s}),this.startCbs=[],this.stopCbs=[],new Promise((t=>{this.resolveInitialization=t}))}))}initAudioProcessor(e,i){return o(this,void 0,void 0,(function*(){return this.worker.postMessage({type:t.ControllerSignal.initAudioProcessor,sourceSampleRate:e,vadOptions:i}),new Promise((t=>{this.resolveSourceSampleRateSet=t}))}))}adjustAudioProcessor(e){this.worker.postMessage({type:t.ControllerSignal.adjustAudioProcessor,params:e})}close(){return o(this,void 0,void 0,(function*(){return new Promise(((e,i)=>{this.worker.postMessage({type:t.ControllerSignal.CLOSE,code:1e3,message:"Client has ended the session"}),e()}))}))}startStream(e){return o(this,void 0,void 0,(function*(){this.worker.postMessage({type:t.ControllerSignal.startStream,options:e})}))}stopStream(){return o(this,void 0,void 0,(function*(){this.worker.postMessage({type:t.ControllerSignal.stopStream})}))}startContext(e){return o(this,void 0,void 0,(function*(){return new Promise(((i,n)=>{this.startCbs.push(((t,e)=>{void 0!==t?n(t):i(e)})),this.worker.postMessage({type:t.ControllerSignal.START_CONTEXT,options:e})}))}))}stopContext(){return o(this,void 0,void 0,(function*(){return new Promise(((e,i)=>{this.stopCbs.push(((t,n)=>{void 0!==t?i(t):e(n)})),this.worker.postMessage({type:t.ControllerSignal.STOP_CONTEXT})}))}))}switchContext(e){return o(this,void 0,void 0,(function*(){return new Promise(((i,n)=>{this.startCbs.push(((t,e)=>{void 0!==t?n(t):i(e)})),this.worker.postMessage({type:t.ControllerSignal.SWITCH_CONTEXT,options:e})}))}))}postMessage(t){this.worker.postMessage(t)}sendAudio(e){this.worker.postMessage({type:t.ControllerSignal.AUDIO,payload:e})}setContextOptions(e){return o(this,void 0,void 0,(function*(){this.worker.postMessage({type:t.ControllerSignal.setContextOptions,options:e})}))}}class F{constructor(){this.storage=window.localStorage}get(t){return this.storage.getItem(t)}set(t,e){this.storage.setItem(t,e)}getOrSet(t,e){let i=this.storage.getItem(t);return null===i&&(i=e(),this.storage.setItem(t,i)),i}}function x(t,e){return{intent:t.intent,isFinal:e}}const f="speechly-auth-token";class J{constructor(e){var i,o,a,d,l,c,r,h;if(this.activeContexts=new Map,this.maxReconnectAttemptCount=10,this.connectAttempt=0,this.connectPromise=null,this.cbs=[],this.state=t.DecoderState.Disconnected,this.handleWebsocketResponse=e=>{switch(this.debug&&console.log("[Decoder]","Received response",e),e.type){case t.WorkerSignal.VadSignalHigh:this.cbs.forEach((t=>t.onVadStateChange.forEach((t=>t(!0)))));break;case t.WorkerSignal.VadSignalLow:this.cbs.forEach((t=>t.onVadStateChange.forEach((t=>t(!1)))));break;case t.WebsocketResponseType.Started:this.activeContexts.set(e.audio_context,new Map),this.cbs.forEach((t=>t.contextStartedCbs.forEach((t=>t(e.audio_context)))));break;case t.WebsocketResponseType.Stopped:this.activeContexts.delete(e.audio_context),this.cbs.forEach((t=>t.contextStoppedCbs.forEach((t=>t(e.audio_context)))));break;default:this.handleSegmentUpdate(e)}},this.handleSegmentUpdate=e=>{var i;const{audio_context:n,segment_id:o,type:a}=e;let{data:d}=e;const l=this.activeContexts.get(n);if(void 0===l)return void console.warn("[Decoder]","Received response for non-existent context",n);let c=null!==(i=l.get(o))&&void 0!==i?i:new s(n,o);switch(a){case t.WebsocketResponseType.TentativeTranscript:const e=function(t){return t.words.map((({word:t,index:e,start_timestamp:i,end_timestamp:n})=>({value:t,index:e,startTimestamp:i,endTimestamp:n,isFinal:!1})))}(d),i=d.transcript;this.cbs.forEach((t=>t.tentativeTranscriptCbs.forEach((t=>t(n,o,e,i))))),c=c.updateTranscript(e);break;case t.WebsocketResponseType.Transcript:const s=function(t){return{value:t.word,index:t.index,startTimestamp:t.start_timestamp,endTimestamp:t.end_timestamp,isFinal:!0}}(d);this.cbs.forEach((t=>t.transcriptCbs.forEach((t=>t(n,o,s))))),c=c.updateTranscript([s]);break;case t.WebsocketResponseType.TentativeEntities:const a=function(t){return t.entities.map((({entity:t,value:e,start_position:i,end_position:n})=>({type:t,value:e,startPosition:i,endPosition:n,isFinal:!1})))}(d);this.cbs.forEach((t=>t.tentativeEntityCbs.forEach((t=>t(n,o,a))))),c=c.updateEntities(a);break;case t.WebsocketResponseType.Entity:const l=function(t){return{type:t.entity,value:t.value,startPosition:t.start_position,endPosition:t.end_position,isFinal:!0}}(d);this.cbs.forEach((t=>t.entityCbs.forEach((t=>t(n,o,l))))),c=c.updateEntities([l]);break;case t.WebsocketResponseType.TentativeIntent:const r=x(d,!1);this.cbs.forEach((t=>t.tentativeIntentCbs.forEach((t=>t(n,o,r))))),c=c.updateIntent(r);break;case t.WebsocketResponseType.Intent:const h=x(d,!0);this.cbs.forEach((t=>t.intentCbs.forEach((t=>t(n,o,h))))),c=c.updateIntent(h);break;case t.WebsocketResponseType.SegmentEnd:c=c.finalize()}l.set(o,c),this.activeContexts.set(n,l),this.logSegments&&console.info(c.toString()),this.cbs.forEach((t=>t.segmentChangeCbs.forEach((t=>t(c.toSegment())))))},this.handleWebsocketClosure=e=>{if(1e3===e.code)this.debug&&console.log("[Decoder]","Websocket closed",e);else{if(console.error("[Decoder]","Websocket closed due to error",e),void 0===this.deviceId)return void this.setState(t.DecoderState.Failed);this.setState(t.DecoderState.Disconnected),this.reconnect()}},this.logSegments=null!==(i=e.logSegments)&&void 0!==i&&i,this.appId=null!==(o=e.appId)&&void 0!==o?o:void 0,this.projectId=null!==(a=e.projectId)&&void 0!==a?a:void 0,this.sampleRate=null!==(d=e.sampleRate)&&void 0!==d?d:n,this.debug=null!==(l=e.debug)&&void 0!==l&&l,void 0!==this.appId&&void 0!==this.projectId)throw Error("[Decoder] You cannot use both appId and projectId at the same time");if(void 0===this.appId&&void 0===this.projectId)throw Error("[Decoder] Either an appId or a projectId is required");const u=null!==(c=e.apiUrl)&&void 0!==c?c:"https://api.speechly.com";this.apiUrl=function(t,e){const i=new URLSearchParams;return i.append("sampleRate",e.toString()),`${t}?${i.toString()}`}(u.replace("http","ws")+"/ws/v1",this.sampleRate),this.loginUrl=`${u}/login`,this.storage=null!==(r=e.storage)&&void 0!==r?r:new F,this.deviceId=this.storage.getOrSet("speechly-device-id",g),this.apiClient=new T,this.apiClient.onResponse(this.handleWebsocketResponse),this.apiClient.onClose(this.handleWebsocketClosure),(null===(h=e.connect)||void 0===h||h)&&this.connect()}getReconnectDelayMs(t){return 100*Math.pow(2,t)}sleep(t){return o(this,void 0,void 0,(function*(){return new Promise((e=>setTimeout(e,t)))}))}connect(){return o(this,void 0,void 0,(function*(){null===this.connectPromise&&(this.connectPromise=(()=>o(this,void 0,void 0,(function*(){const e=this.storage.get(f);if(null!=e&&N(e,this.projectId,this.appId,this.deviceId))this.authToken=e;else try{this.authToken=yield function(t,e,i,n,s=fetch,a=Date.now){var d;return o(this,void 0,void 0,(function*(){let o;o=void 0!==e?{projectId:e,deviceId:n}:{appId:i,deviceId:n};const l=yield s(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(o)}),c=yield l.json();if(200!==l.status)throw Error(null!==(d=c.error)&&void 0!==d?d:`Speechly API login request failed with ${l.status}`);if(void 0===c.access_token)throw Error("Invalid login response from Speechly API");if(!N(c.access_token,e,i,n,a))throw Error("Invalid token received from Speechly API");return c.access_token}))}(this.loginUrl,this.projectId,this.appId,this.deviceId),this.storage.set(f,this.authToken)}catch(e){throw this.setState(t.DecoderState.Failed),e}yield this.apiClient.initialize(this.apiUrl,this.authToken,this.sampleRate,this.debug),this.advanceState(t.DecoderState.Connected)})))()),yield this.connectPromise}))}adjustAudioProcessor(t){this.apiClient.adjustAudioProcessor(t)}close(){return o(this,void 0,void 0,(function*(){let e;try{yield this.apiClient.close()}catch(t){e=t.message}if(this.activeContexts.clear(),this.connectPromise=null,this.setState(t.DecoderState.Disconnected),void 0!==e)throw Error(e)}))}startStream(t){return o(this,void 0,void 0,(function*(){yield this.apiClient.startStream(t)}))}stopStream(){return o(this,void 0,void 0,(function*(){this.state===t.DecoderState.Active&&(yield this.stopContext(0)),yield this.apiClient.stopStream()}))}startContext(e){return o(this,void 0,void 0,(function*(){if(this.state===t.DecoderState.Failed)throw Error("[Decoder] startContext cannot be run in Failed state.");if(this.state<t.DecoderState.Connected)yield this.connect();else if(this.state>t.DecoderState.Connected)throw Error("[Decoder] Unable to complete startContext: Expected Connected state, but was in "+G(this.state)+".");let n;if(this.setState(t.DecoderState.Active),null!=this.projectId)n=yield this.apiClient.startContext(null==e?void 0:e.appId);else{if(null!=(null==e?void 0:e.appId)&&this.appId!==(null==e?void 0:e.appId))throw this.setState(t.DecoderState.Failed),i;n=yield this.apiClient.startContext()}if(this.state<t.DecoderState.Active)throw Error("[Decoder] Unable to complete startContext: Problem acquiring contextId");return n}))}sendAudio(t){this.apiClient.sendAudio(t)}stopContext(e){return o(this,void 0,void 0,(function*(){if(this.state===t.DecoderState.Failed)throw Error("[Decoder] stopContext cannot be run in unrecovable error state.");if(this.state!==t.DecoderState.Active)throw Error("[Decoder] Unable to complete stopContext: Expected Active state, but was in "+G(this.state)+".");e>0&&(yield this.sleep(e)),this.apiClient.stopContext(),this.setState(t.DecoderState.Connected)}))}switchContext(e){return o(this,void 0,void 0,(function*(){if(this.state!==t.DecoderState.Active)throw Error("[Decoder] Unable to complete switchContext: Expected Active state, but was in "+G(this.state)+".");const i=yield this.apiClient.switchContext(e);this.activeContexts.set(i,new Map)}))}registerListener(t){this.cbs.push(t)}initAudioProcessor(t,e){return o(this,void 0,void 0,(function*(){this.sampleRate=t,yield this.apiClient.initAudioProcessor(t,e)}))}useSharedArrayBuffers(t,e){this.apiClient.postMessage({type:"SET_SHARED_ARRAY_BUFFERS",controlSAB:t,dataSAB:e})}setContextOptions(t){return o(this,void 0,void 0,(function*(){yield this.apiClient.setContextOptions(t)}))}reconnect(){return o(this,void 0,void 0,(function*(){this.debug&&console.log("[Decoder]","Reconnecting...",this.connectAttempt),this.connectPromise=null,this.connectAttempt<this.maxReconnectAttemptCount?(yield this.sleep(this.getReconnectDelayMs(this.connectAttempt++)),yield this.connect()):console.error("[Decoder] Maximum reconnect count reached, giving up automatic reconnect.")}))}advanceState(t){this.state>=t||this.setState(t)}setState(t){this.state!==t&&(this.debug&&console.log("[Decoder]",G(this.state),"->",G(t)),this.state=t,this.cbs.forEach((e=>{var i;return null===(i=e.stateChangeCbs)||void 0===i?void 0:i.forEach((e=>e(t)))})))}}t.BrowserClient=class{constructor(t){var e,i;this.contextStopDelay=250,this.debug=!1,this.initialized=!1,this.isStreaming=!1,this.isStreamAutoStarted=!1,this.active=!1,this.listeningPromise=null,this.stats={maxSignalEnergy:0,sentSamples:0};const n=window.navigator.mediaDevices.getSupportedConstraints();this.nativeResamplingSupported=!0===n.sampleRate,this.isMobileSafari=["iPad Simulator","iPhone Simulator","iPod Simulator","iPad","iPhone","iPod"].indexOf(navigator.platform)>=0||navigator.userAgent.includes("Mac")&&"ontouchend"in document,this.isSafari=this.isMobileSafari||void 0!==window.safari,this.useSAB=!this.isSafari,this.vadOptions=Object.assign(Object.assign({},b),t.vad),this.debug=null===(e=t.debug)||void 0===e||e,this.callbacks=new Z,this.callbacks.onVadStateChange.push(this.onVadStateChange.bind(this)),this.decoder=null!==(i=t.decoder)&&void 0!==i?i:new J(t),this.decoder.registerListener(this.callbacks)}onVadStateChange(t){var e;this.debug&&console.log("[BrowserClient]","onVadStateChange",t),(null===(e=this.vadOptions)||void 0===e?void 0:e.controlListening)&&(t?this.active||this.start():this.active&&this.stop(0))}initialize(t){var i,s;return o(this,void 0,void 0,(function*(){if(!this.initialized){this.initialized=!0,this.debug&&console.log("[BrowserClient]","initializing"),yield this.decoder.connect();try{const t={};if(this.nativeResamplingSupported&&(t.sampleRate=n),void 0!==window.webkitAudioContext)try{this.audioContext=new window.webkitAudioContext(t)}catch(t){this.debug&&console.log("[BrowserClient]","creating audioContext without samplerate conversion",t),this.audioContext=new window.webkitAudioContext}else this.audioContext=new window.AudioContext(t),void 0!==window.webkitAudioContext&&(yield this.audioContext.resume())}catch(t){throw e}if(this.isSafari||void 0===window.AudioWorkletNode){if(this.debug&&console.log("[BrowserClient]","using ScriptProcessorNode"),void 0!==window.webkitAudioContext){const t=this.audioContext.sampleRate/n,e=4096*Math.pow(2,Math.ceil(Math.log(t)/Math.log(2)));this.audioProcessor=this.audioContext.createScriptProcessor(e,1,1)}else this.audioProcessor=this.audioContext.createScriptProcessor(void 0,1,1);this.audioProcessor.connect(this.audioContext.destination),this.audioProcessor.addEventListener("audioprocess",(t=>{this.handleAudio(t.inputBuffer.getChannelData(0))}))}else{this.debug&&console.log("[BrowserClient]","using AudioWorkletNode");const t=new Blob(["\n// Indices for the Control SAB.\nconst CONTROL = {\n 'WRITE_INDEX': 0,\n 'FRAMES_AVAILABLE': 1,\n 'LOCK': 2,\n};\n\nclass SpeechlyProcessor extends AudioWorkletProcessor {\n constructor() {\n super();\n\n this._initialized = false;\n this.debug = false;\n this.port.onmessage = this._initialize.bind(this);\n }\n\n _initialize(event) {\n this.controlSAB = new Int32Array(event.data.controlSAB);\n this.dataSAB = new Float32Array(event.data.dataSAB);\n this.debug = event.data.debug;\n if (this.debug) {\n console.log('[BrowserClient AudioWorkletNode]', 'initializing audioworklet');\n }\n this.sharedBufferSize = this.dataSAB.length;\n this.buffer = new Float32Array(0);\n this._initialized = true;\n }\n\n _transferDataToSharedBuffer(data) {\n this.controlSAB[CONTROL.LOCK] = 1;\n let inputWriteIndex = this.controlSAB[CONTROL.WRITE_INDEX];\n if (this.controlSAB[CONTROL.FRAMES_AVAILABLE] > 0) {\n if (inputWriteIndex + data.length > this.sharedBufferSize) {\n // console.log('buffer overflow')\n inputWriteIndex = 0;\n }\n }\n this.dataSAB.set(data, inputWriteIndex);\n this.controlSAB[CONTROL.WRITE_INDEX] = inputWriteIndex + data.length;\n this.controlSAB[CONTROL.FRAMES_AVAILABLE] = inputWriteIndex + data.length;\n this.controlSAB[CONTROL.LOCK] = 0;\n }\n\n _pushData(data) {\n if (this.debug) {\n const signalEnergy = getStandardDeviation(data)\n this.port.postMessage({\n type: 'STATS',\n signalEnergy: signalEnergy,\n samples: data.length,\n });\n }\n\n if (this.buffer.length > this.sharedBufferSize) {\n const dataToTransfer = this.buffer.subarray(0, this.sharedBufferSize);\n this._transferDataToSharedBuffer(dataToTransfer);\n this.buffer = this.buffer.subarray(this.sharedBufferSize);\n }\n let concat = new Float32Array(this.buffer.length + data.length);\n concat.set(this.buffer);\n concat.set(data, this.buffer.length);\n this.buffer = concat;\n }\n\n process(inputs, outputs, parameters) {\n const inputChannelData = inputs[0][0];\n if (inputChannelData !== undefined) {\n if (this.controlSAB && this.dataSAB) {\n this._pushData(inputChannelData);\n } else {\n this.port.postMessage({\n type: 'DATA',\n frames: inputChannelData\n });\n }\n }\n\n return true;\n }\n}\n\nfunction getStandardDeviation(array) {\n const n = array.length\n const mean = array.reduce((a, b) => a + b) / n\n return Math.sqrt(array.map(x => Math.pow(x - mean, 2)).reduce((a, b) => a + b) / n)\n}\n\nregisterProcessor('speechly-worklet', SpeechlyProcessor);\n"],{type:"text/javascript"}),e=window.URL.createObjectURL(t);if(yield this.audioContext.audioWorklet.addModule(e),this.speechlyNode=new AudioWorkletNode(this.audioContext,"speechly-worklet"),this.speechlyNode.connect(this.audioContext.destination),this.useSAB&&void 0!==window.SharedArrayBuffer){this.debug&&console.log("[BrowserClient]","using SharedArrayBuffer");const t=new window.SharedArrayBuffer(4*Int32Array.BYTES_PER_ELEMENT),e=new window.SharedArrayBuffer(1024*Float32Array.BYTES_PER_ELEMENT);this.decoder.useSharedArrayBuffers(t,e),this.speechlyNode.port.postMessage({type:"SET_SHARED_ARRAY_BUFFERS",controlSAB:t,dataSAB:e,debug:this.debug})}else this.debug&&console.log("[BrowserClient]","can not use SharedArrayBuffer");this.speechlyNode.port.onmessage=t=>{switch(t.data.type){case"STATS":t.data.signalEnergy>this.stats.maxSignalEnergy&&(this.stats.maxSignalEnergy=t.data.signalEnergy),this.stats.sentSamples+=parseInt(t.data.samples);break;case"DATA":this.handleAudio(t.data.frames)}}}this.debug&&console.log("[BrowserClient]","audioContext sampleRate is",null===(i=this.audioContext)||void 0===i?void 0:i.sampleRate),yield this.decoder.initAudioProcessor(null===(s=this.audioContext)||void 0===s?void 0:s.sampleRate,this.vadOptions),this.vadOptions&&(yield this.startStream()),(null==t?void 0:t.mediaStream)&&(yield this.attach(null==t?void 0:t.mediaStream))}}))}adjustAudioProcessor(t){this.decoder.adjustAudioProcessor(t)}close(){var t,e,i;return o(this,void 0,void 0,(function*(){yield this.detach(),null!==this.speechlyNode&&(null===(t=this.speechlyNode)||void 0===t||t.port.close(),null===(e=this.speechlyNode)||void 0===e||e.disconnect()),void 0!==this.audioProcessor&&(null===(i=this.audioProcessor)||void 0===i||i.disconnect()),yield this.decoder.close(),this.initialized=!1}))}attach(t){var e,i,n,s,a,d;return o(this,void 0,void 0,(function*(){if(yield this.initialize(),yield this.detach(),this.stream=null===(e=this.audioContext)||void 0===e?void 0:e.createMediaStreamSource(t),"running"!==(null===(i=this.audioContext)||void 0===i?void 0:i.state)&&(this.debug&&console.log("[BrowserClient]","audioContext resume required, state is",null===(n=this.audioContext)||void 0===n?void 0:n.state),yield null===(s=this.audioContext)||void 0===s?void 0:s.resume()),this.speechlyNode)null===(a=this.stream)||void 0===a||a.connect(this.speechlyNode);else{if(!this.audioProcessor)throw Error("[BrowserClient] cannot attach to mediaStream, not initialized");null===(d=this.stream)||void 0===d||d.connect(this.audioProcessor)}}))}detach(){return o(this,void 0,void 0,(function*(){this.active&&(yield this.stop(0)),this.stream&&(this.stream.disconnect(),this.stream=void 0)}))}uploadAudioData(t,e){var i,n,s;return o(this,void 0,void 0,(function*(){yield this.initialize();const o=yield null===(i=this.audioContext)||void 0===i?void 0:i.decodeAudioData(t);if(void 0===o)throw Error("Could not decode audioData");const a=o.getChannelData(0);if(o.numberOfChannels>1){const t=o.getChannelData(1);for(let e=0;e<a.length;e++)a[e]=(a[e]+t[e])/2}let d;yield this.startStream({immediate:!0});const l=(null===(n=this.vadOptions)||void 0===n?void 0:n.enabled)&&(null===(s=this.vadOptions)||void 0===s?void 0:s.controlListening);let c;d=l?"multiple context ids":yield this.start(e);for(let t=0;t<a.length;t+=16e3){const e=t+16e3;c=e>a.length?a.slice(t):a.slice(t,e),this.handleAudio(c)}return l||(yield this.stop(0)),yield this.stopStream(),d}))}startStream(t){return o(this,void 0,void 0,(function*(){yield this.decoder.startStream(t),this.isStreaming=!0}))}stopStream(){return o(this,void 0,void 0,(function*(){yield this.decoder.stopStream(),this.isStreaming=!1,this.isStreamAutoStarted=!1}))}queueTask(t){return o(this,void 0,void 0,(function*(){const e=this.listeningPromise;return this.listeningPromise=(()=>o(this,void 0,void 0,(function*(){return yield e,t()})))(),this.listeningPromise}))}start(t){return o(this,void 0,void 0,(function*(){return yield this.queueTask((()=>o(this,void 0,void 0,(function*(){yield this.initialize(),this.isStreaming||(yield this.startStream(t),this.isStreamAutoStarted=!0);const e=this.decoder.startContext(t);return this.active=!0,e}))))}))}stop(t=this.contextStopDelay){return o(this,void 0,void 0,(function*(){return yield this.queueTask((()=>o(this,void 0,void 0,(function*(){let e=null;try{e=yield this.decoder.stopContext(t),this.isStreaming&&this.isStreamAutoStarted&&(yield this.stopStream()),0===this.stats.sentSamples&&console.warn("[BrowserClient]","audioContext contained no audio data")}catch(t){console.warn("[BrowserClient]","stop() failed",t)}finally{this.active=!1,this.stats.sentSamples=0}return e}))))}))}handleAudio(t){this.isStreaming&&(this.stats.sentSamples+=t.length,this.decoder.sendAudio(t))}isActive(){return this.active}onSegmentChange(t){this.callbacks.segmentChangeCbs.push(t)}onTranscript(t){this.callbacks.transcriptCbs.push(t)}onEntity(t){this.callbacks.entityCbs.push(t)}onIntent(t){this.callbacks.intentCbs.push(t)}onTentativeTranscript(t){this.callbacks.tentativeTranscriptCbs.push(t)}onTentativeEntities(t){this.callbacks.tentativeEntityCbs.push(t)}onTentativeIntent(t){this.callbacks.tentativeIntentCbs.push(t)}onStateChange(t){this.callbacks.stateChangeCbs.push(t)}},t.BrowserMicrophone=class{constructor(){this.muted=!1,this.initialized=!1;try{const t=window.navigator.mediaDevices.getSupportedConstraints();this.nativeResamplingSupported=!0===t.sampleRate,this.autoGainControlSupported=!0===t.autoGainControl}catch(t){this.nativeResamplingSupported=!1,this.autoGainControlSupported=!1}}initialize(){var t;return o(this,void 0,void 0,(function*(){if(this.initialized)return;if(void 0===(null===(t=window.navigator)||void 0===t?void 0:t.mediaDevices))throw e;const i={video:!1};this.nativeResamplingSupported||this.autoGainControlSupported?i.audio={sampleRate:n,autoGainControl:this.autoGainControlSupported}:i.audio=!0;try{this.mediaStream=yield window.navigator.mediaDevices.getUserMedia(i)}catch(t){throw console.error(t),l}this.initialized=!0,this.muted=!0}))}close(){return o(this,void 0,void 0,(function*(){if(!this.initialized)throw a;this.muted=!0;this.mediaStream.getTracks().forEach((t=>t.stop())),this.mediaStream=void 0,this.initialized=!1}))}isRecording(){return!this.muted}},t.CloudDecoder=J,t.DefaultSampleRate=n,t.ErrAlreadyInitialized=d,t.ErrAppIdChangeWithoutProjectLogin=i,t.ErrDeviceNotSupported=e,t.ErrKeyNotFound=p,t.ErrNoAudioConsent=l,t.ErrNoStorageSupport=u,t.ErrNotInitialized=a,t.EventCallbacks=Z,t.SegmentState=s,t.VadDefaultOptions=b,t.stateToString=G,Object.defineProperty(t,"__esModule",{value:!0})}));
!function(t,e){!function(i){var n=e,s=t&&t.exports==n&&t,o="object"==typeof Y&&Y;o.global!==o&&o.window!==o||(i=o);var a=function(t){this.message=t};(a.prototype=new Error).name="InvalidCharacterError";var d=function(t){throw new a(t)},l="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",c=/[\t\n\f\r ]/g,r={encode:function(t){t=String(t),/[^\0-\xFF]/.test(t)&&d("The string to be encoded contains characters outside of the Latin1 range.");for(var e,i,n,s,o=t.length%3,a="",c=-1,r=t.length-o;++c<r;)e=t.charCodeAt(c)<<16,i=t.charCodeAt(++c)<<8,n=t.charCodeAt(++c),a+=l.charAt((s=e+i+n)>>18&63)+l.charAt(s>>12&63)+l.charAt(s>>6&63)+l.charAt(63&s);return 2==o?(e=t.charCodeAt(c)<<8,i=t.charCodeAt(++c),a+=l.charAt((s=e+i)>>10)+l.charAt(s>>4&63)+l.charAt(s<<2&63)+"="):1==o&&(s=t.charCodeAt(c),a+=l.charAt(s>>2)+l.charAt(s<<4&63)+"=="),a},decode:function(t){var e=(t=String(t).replace(c,"")).length;e%4==0&&(e=(t=t.replace(/==?$/,"")).length),(e%4==1||/[^+a-zA-Z0-9/]/.test(t))&&d("Invalid character: the string to be decoded is not correctly encoded.");for(var i,n,s=0,o="",a=-1;++a<e;)n=l.indexOf(t.charAt(a)),i=s%4?64*i+n:n,s++%4&&(o+=String.fromCharCode(255&i>>(-2*s&6)));return o},version:"0.1.0"};if(n&&!n.nodeType)if(s)s.exports=r;else for(var h in r)r.hasOwnProperty(h)&&(n[h]=r[h]);else i.base64=r}(Y)}(z,z.exports);function N(t,e,i,n,s=Date.now){const o=function(t){const e=t.split(".")[1];let i;try{i=JSON.parse(z.exports.decode(e))}catch(t){throw new Error("Error decoding Speechly token!")}return{appId:i.appId,projectId:i.projectId,deviceId:i.deviceId,configId:i.configId,scopes:i.scope.split(" "),issuer:i.iss,audience:i.aud,expiresAtMs:1e3*i.exp}}(t);return!(o.expiresAtMs-s()<36e5)&&(o.appId===i&&o.projectId===e&&o.deviceId===n)}class T{constructor(){this.startCbs=[],this.stopCbs=[],this.onResponseCb=()=>{},this.onCloseCb=()=>{},this.onWebsocketMessage=e=>{const i=e.data;switch(i.type){case t.WorkerSignal.Opened:null!=this.resolveInitialization&&this.resolveInitialization();break;case t.WorkerSignal.Closed:this.onCloseCb({code:e.data.code,reason:e.data.reason,wasClean:e.data.wasClean});break;case t.WorkerSignal.AudioProcessorReady:null!=this.resolveSourceSampleRateSet&&this.resolveSourceSampleRateSet();break;case t.WebsocketResponseType.Started:this.onResponseCb(i),this.startCbs.forEach((t=>{try{t(void 0,i.audio_context)}catch(t){console.error('[SpeechlyClient] Error while invoking "onStart" callback:',t)}})),this.startCbs.length=0;break;case t.WebsocketResponseType.Stopped:this.onResponseCb(i),this.stopCbs.forEach((t=>{try{t(void 0,i.audio_context)}catch(t){console.error('[SpeechlyClient] Error while invoking "onStop" callback:',t)}})),this.stopCbs.length=0;break;default:this.onResponseCb(i)}},this.worker=new"Lyogcm9sbHVwLXBsdWdpbi13ZWItd29ya2VyLWxvYWRlciAqLwp2YXIgd29ya2VyX2NvZGU9ZnVuY3Rpb24odCl7InVzZSBzdHJpY3QiO2NsYXNzIGV7c3RhdGljIGRvd25zYW1wbGUodCxlLHM9MCxpPS0xLG89MCxyPS0xKXtpZihpPDAmJihpPXQubGVuZ3RoLXMpLHI8MCYmKHI9ZS5sZW5ndGgtbykscj5pKXRocm93IG5ldyBFcnJvcihgQ2FuJ3QgZG93bnNhbXBsZTogc291cmNlIGFycmF5IGxlbmd0aCAoJHtpfSkgaXMgc2hvcnRlciB0aGFuIGRlc3RpbmF0aW9uICgke3J9KWApO2lmKDA9PT1yKXRocm93IG5ldyBFcnJvcihgQ2FuJ3QgZG93bnNhbXBsZTogc291cmNlIGFycmF5IGxlbmd0aCAoJHtpfSkgY2FuJ3QgYmUgZG93bnNhbXBsZWQgdG8gemVyby1sZW5ndGggZGVzdGluYXRpb24uYCk7aWYoMD09PWkpdGhyb3cgbmV3IEVycm9yKCJDYW4ndCBkb3duc2FtcGxlOiBzb3VyY2UgcmFuZ2UgY2FuJ3QgYmUgemVybyBsZW5ndGguIik7aWYoMT09PWkpcmV0dXJuIHZvaWQoZVswXT10WzBdKTtsZXQgYT0wO2NvbnN0IG49KHItMSkvKGktMSk7bGV0IGg9MCxjPTA7Y29uc3QgbD1zK2k7Zm9yKDtzPGw7cysrKXtjb25zdCBpPS41LU1hdGguYWJzKGEpO2grPXRbc10qaSxjKz1pLGErPW4sYT49LjUmJihhLT0xLGVbbysrXT1oL2MsaD0wLGM9MCl9Yz4wJiYoZVtvKytdPWgvYyl9c3RhdGljIGdldEVuZXJneSh0LGU9MCxzPS0xKXtpZihzPDAmJihzPXQubGVuZ3RoLWUpLHM8PTApcmV0dXJuIDA7Y29uc3QgaT1lK3M7bGV0IG89MDtmb3IoO2U8aTtlKyspbys9dFtlXSp0W2VdO3JldHVybiBNYXRoLnNxcnQoby9zKX1zdGF0aWMgZ2V0QXVkaW9QZWFrKHQsZT0wLHM9LTEpe2lmKHM8MCYmKHM9dC5sZW5ndGgtZSksczw9MClyZXR1cm4gMDtjb25zdCBpPWUrcztsZXQgbz0wO2Zvcig7ZTxpO2UrKyl0W2VdPm8mJihvPXRbZV0pO3JldHVybiBvfXN0YXRpYyBjb252ZXJ0SW50MTZUb0Zsb2F0KHQsZSxzPTAsaT0tMSxvPTApe2k8MCYmKGk9dC5sZW5ndGgvMi1zKTtjb25zdCByPU1hdGgubWluKHQubGVuZ3RoLzItcyxlLmxlbmd0aC1vKTtpZigoaT1NYXRoLm1pbihpLHIpKTw9MClyZXR1cm4gMDtsZXQgYT0yKnM7Y29uc3Qgbj1hKzIqaTtmb3IoO2E8bjspZVtvKytdPSh0W2ErK10rKHRbYSsrXTw8OCkpLzMyNzY3O3JldHVybiBpfXN0YXRpYyBjb252ZXJ0RmxvYXRUb0ludDE2KHQsZSxzPTAsaT0tMSxvPTApe2k8MCYmKGk9dC5sZW5ndGgtcyk7Y29uc3Qgcj1zK2k7Zm9yKDtzPHI7KWVbbysrXT1+figzMjc2Nyp0W3MrK10pfXN0YXRpYyBlbmVyZ3lUb0RiKHQpe3JldHVybiAxMCpNYXRoLmxvZyh0KS9lLkxPR18yX1BMVVNfTE9HXzV9c3RhdGljIGRiVG9FbmVyZ3kodCl7cmV0dXJuIE1hdGgucG93KDEwLHQvMTApfX1lLkxPR18yX1BMVVNfTE9HXzU9TWF0aC5sb2coMikrTWF0aC5sb2coNSk7Y2xhc3Mgc3tjb25zdHJ1Y3Rvcih0LGUscyl7dGhpcy5pc0FjdGl2ZT0hMSx0aGlzLnN0cmVhbVNhbXBsZVBvcz0wLHRoaXMuc2FtcGxlc1NlbnQ9MCx0aGlzLnV0dGVyYW5jZVNlcmlhbD0tMSx0aGlzLm9uU2VuZEF1ZGlvPSh0LGUscyk9Pnt9LHRoaXMub25WYWRTdGF0ZUNoYW5nZT10PT57fSx0aGlzLmlucHV0U2FtcGxlUmF0ZT0xNmUzLHRoaXMuaW50ZXJuYWxTYW1wbGVSYXRlPTE2ZTMsdGhpcy5oaXN0b3J5RnJhbWVzPTUsdGhpcy5mcmFtZU1pbGxpcz0zMCx0aGlzLmN1cnJlbnRGcmFtZU51bWJlcj0wLHRoaXMuZnJhbWVTYW1wbGVQb3M9MCx0aGlzLnN0cmVhbUZyYW1lUG9zPTAsdGhpcy53YXNTaWduYWxEZXRlY3RlZD0hMSx0aGlzLmlucHV0U2FtcGxlUmF0ZT10LHRoaXMuaW50ZXJuYWxTYW1wbGVSYXRlPWUsdGhpcy5oaXN0b3J5RnJhbWVzPXMsdGhpcy5mcmFtZVNhbXBsZXM9fn4odGhpcy5pbnRlcm5hbFNhbXBsZVJhdGUqdGhpcy5mcmFtZU1pbGxpcy8xZTMpLHRoaXMuc2FtcGxlUmluZ0J1ZmZlcj1uZXcgRmxvYXQzMkFycmF5KHRoaXMuZnJhbWVTYW1wbGVzKnRoaXMuaGlzdG9yeUZyYW1lcyl9c3RhcnRDb250ZXh0KCl7dGhpcy5pc0FjdGl2ZT0hMCx0aGlzLnNhbXBsZXNTZW50PTAsdGhpcy51dHRlcmFuY2VTZXJpYWwrK31zdG9wQ29udGV4dCgpe3RoaXMuZmx1c2goKSx0aGlzLmlzQWN0aXZlPSExfXJlc2V0U3RyZWFtKCl7dmFyIHQ7dGhpcy5zdHJlYW1GcmFtZVBvcz0wLHRoaXMuc3RyZWFtU2FtcGxlUG9zPTAsdGhpcy5mcmFtZVNhbXBsZVBvcz0wLHRoaXMuY3VycmVudEZyYW1lTnVtYmVyPTAsdGhpcy51dHRlcmFuY2VTZXJpYWw9LTEsbnVsbD09PSh0PXRoaXMudmFkKXx8dm9pZCAwPT09dHx8dC5yZXNldFZBRCgpfWZsdXNoKCl7dGhpcy5wcm9jZXNzQXVkaW8odGhpcy5zYW1wbGVSaW5nQnVmZmVyLDAsdGhpcy5mcmFtZVNhbXBsZVBvcywhMCl9Z2V0U3RyZWFtUG9zaXRpb24oKXtyZXR1cm4gdGhpcy5zdHJlYW1TYW1wbGVQb3MvdGhpcy5pbnB1dFNhbXBsZVJhdGV9cHJvY2Vzc0F1ZGlvKHQscz0wLGk9LTEsbz0hMSl7aWYoaTwwJiYoaT10Lmxlbmd0aCksMD09PWkpcmV0dXJuO2xldCByPXM7Y29uc3QgYT1zK2k7Zm9yKDtyPGE7KXtjb25zdCBzPXRoaXMuY3VycmVudEZyYW1lTnVtYmVyKnRoaXMuZnJhbWVTYW1wbGVzO2lmKHRoaXMuaW5wdXRTYW1wbGVSYXRlPT09dGhpcy5pbnRlcm5hbFNhbXBsZVJhdGUpe2NvbnN0IGU9TWF0aC5taW4oYS1yLHRoaXMuZnJhbWVTYW1wbGVzLXRoaXMuZnJhbWVTYW1wbGVQb3MpLGk9dGhpcy5mcmFtZVNhbXBsZVBvcytlO2Zvcig7dGhpcy5mcmFtZVNhbXBsZVBvczxpOyl0aGlzLnNhbXBsZVJpbmdCdWZmZXJbcyt0aGlzLmZyYW1lU2FtcGxlUG9zKytdPXRbcisrXX1lbHNle2NvbnN0IGk9MSp0aGlzLmlucHV0U2FtcGxlUmF0ZS90aGlzLmludGVybmFsU2FtcGxlUmF0ZSxvPU1hdGgubWluKGEtcixNYXRoLnJvdW5kKGkqKHRoaXMuZnJhbWVTYW1wbGVzLXRoaXMuZnJhbWVTYW1wbGVQb3MpKSksbj1NYXRoLm1pbihNYXRoLnJvdW5kKChhLXIpL2kpLHRoaXMuZnJhbWVTYW1wbGVzLXRoaXMuZnJhbWVTYW1wbGVQb3MpO24+MCYmZS5kb3duc2FtcGxlKHQsdGhpcy5zYW1wbGVSaW5nQnVmZmVyLHIsbyxzK3RoaXMuZnJhbWVTYW1wbGVQb3Msbikscis9byx0aGlzLmZyYW1lU2FtcGxlUG9zKz1ufWlmKHRoaXMuZnJhbWVTYW1wbGVQb3M+dGhpcy5mcmFtZVNhbXBsZXMpdGhyb3cgbmV3IEVycm9yKGB0aGlzLmZyYW1lU2FtcGxlUG9zICgke3RoaXMuZnJhbWVTYW1wbGVQb3N9KSA+IHRoaXMuZnJhbWVTYW1wbGVzICgke3RoaXMuZnJhbWVTYW1wbGVzfSlgKTtpZih0aGlzLmZyYW1lU2FtcGxlUG9zPT09dGhpcy5mcmFtZVNhbXBsZXN8fG8pe2NvbnN0IHQ9bz90aGlzLmZyYW1lU2FtcGxlUG9zOnRoaXMuZnJhbWVTYW1wbGVzO2lmKG98fHRoaXMucHJvY2Vzc0ZyYW1lKHRoaXMuc2FtcGxlUmluZ0J1ZmZlcixzLHQpLHRoaXMuaXNBY3RpdmUpe2lmKDA9PT10aGlzLnNhbXBsZXNTZW50KXtjb25zdCB0PU1hdGgubWluKHRoaXMuc3RyZWFtRnJhbWVQb3MsdGhpcy5oaXN0b3J5RnJhbWVzLTEpO2xldCBlPSh0aGlzLmN1cnJlbnRGcmFtZU51bWJlcit0aGlzLmhpc3RvcnlGcmFtZXMtdCkldGhpcy5oaXN0b3J5RnJhbWVzO2Zvcig7ZSE9PXRoaXMuY3VycmVudEZyYW1lTnVtYmVyOyl0aGlzLm9uU2VuZEF1ZGlvKHRoaXMuc2FtcGxlUmluZ0J1ZmZlcixlKnRoaXMuZnJhbWVTYW1wbGVzLHRoaXMuZnJhbWVTYW1wbGVzKSx0aGlzLnNhbXBsZXNTZW50Kz10aGlzLmZyYW1lU2FtcGxlcyxlPShlKzEpJXRoaXMuaGlzdG9yeUZyYW1lc310aGlzLm9uU2VuZEF1ZGlvKHRoaXMuc2FtcGxlUmluZ0J1ZmZlcixzLHQpLHRoaXMuc2FtcGxlc1NlbnQrPXR9dGhpcy5mcmFtZVNhbXBsZVBvcz09PXRoaXMuZnJhbWVTYW1wbGVzJiYodGhpcy5mcmFtZVNhbXBsZVBvcz0wLHRoaXMuc3RyZWFtRnJhbWVQb3MrPTEsdGhpcy5zdHJlYW1TYW1wbGVQb3MrPXQsdGhpcy5jdXJyZW50RnJhbWVOdW1iZXI9KHRoaXMuY3VycmVudEZyYW1lTnVtYmVyKzEpJXRoaXMuaGlzdG9yeUZyYW1lcyl9fX1wcm9jZXNzRnJhbWUodCxlPTAscz0tMSl7dmFyIGk7KG51bGw9PT0oaT10aGlzLnZhZCl8fHZvaWQgMD09PWk/dm9pZCAwOmkudmFkT3B0aW9ucy5lbmFibGVkKSYmdGhpcy5wcm9jZXNzVmFkRnJhbWUodGhpcy52YWQsdCxlLHMpfXByb2Nlc3NWYWRGcmFtZSh0LGUscz0wLGk9LTEpe3QucHJvY2Vzc0ZyYW1lKGUscyxpKSx0LmlzU2lnbmFsRGV0ZWN0ZWQhPT10aGlzLndhc1NpZ25hbERldGVjdGVkJiYodGhpcy5vblZhZFN0YXRlQ2hhbmdlKHQuaXNTaWduYWxEZXRlY3RlZCksdGhpcy53YXNTaWduYWxEZXRlY3RlZD10LmlzU2lnbmFsRGV0ZWN0ZWQpfX1jbGFzcyBpe2NvbnN0cnVjdG9yKHQpe3RoaXMuaXNTaWduYWxEZXRlY3RlZD0hMSx0aGlzLnNpZ25hbERiPS05MCx0aGlzLm5vaXNlTGV2ZWxEYj0tOTAsdGhpcy5mcmFtZU1pbGxpcz0zMCx0aGlzLmVuZXJneT0wLHRoaXMuYmFzZWxpbmVFbmVyZ3k9LTEsdGhpcy5sb3VkRnJhbWVCaXRzPTAsdGhpcy52YWRTdXN0YWluTWlsbGlzTGVmdD0wLHRoaXMudmFkT3B0aW9ucz10fWFkanVzdFZhZE9wdGlvbnModCl7dGhpcy52YWRPcHRpb25zPU9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSx0aGlzLnZhZE9wdGlvbnMpLHQpfXJlc2V0VkFEKCl7dGhpcy5pc1NpZ25hbERldGVjdGVkPSExLHRoaXMubG91ZEZyYW1lQml0cz0wLHRoaXMuZW5lcmd5PTAsdGhpcy5iYXNlbGluZUVuZXJneT0tMX1wcm9jZXNzRnJhbWUodCxzPTAsaT0tMSl7aWYoIXRoaXMudmFkT3B0aW9ucy5lbmFibGVkKXJldHVybiB2b2lkIHRoaXMucmVzZXRWQUQoKTt0aGlzLmVuZXJneT1lLmdldEVuZXJneSh0LHMsaSksdGhpcy5iYXNlbGluZUVuZXJneTwwJiYodGhpcy5iYXNlbGluZUVuZXJneT10aGlzLmVuZXJneSk7Y29uc3Qgbz10aGlzLmVuZXJneT5NYXRoLm1heChlLmRiVG9FbmVyZ3kodGhpcy52YWRPcHRpb25zLm5vaXNlR2F0ZURiKSx0aGlzLmJhc2VsaW5lRW5lcmd5KmUuZGJUb0VuZXJneSh0aGlzLnZhZE9wdGlvbnMuc2lnbmFsVG9Ob2lzZURiKSk7dGhpcy5wdXNoRnJhbWVIaXN0b3J5KG8pLHRoaXMuaXNTaWduYWxEZXRlY3RlZD10aGlzLmRldGVybWluZU5ld1NpZ25hbFN0YXRlKHRoaXMuaXNTaWduYWxEZXRlY3RlZCksdGhpcy5hZGFwdEJhY2tncm91bmROb2lzZSgpLHRoaXMuc2lnbmFsRGI9ZS5lbmVyZ3lUb0RiKHRoaXMuZW5lcmd5L3RoaXMuYmFzZWxpbmVFbmVyZ3kpLHRoaXMubm9pc2VMZXZlbERiPWUuZW5lcmd5VG9EYih0aGlzLmJhc2VsaW5lRW5lcmd5KX1kZXRlcm1pbmVOZXdTaWduYWxTdGF0ZSh0KXt0aGlzLnZhZFN1c3RhaW5NaWxsaXNMZWZ0PU1hdGgubWF4KHRoaXMudmFkU3VzdGFpbk1pbGxpc0xlZnQtdGhpcy5mcmFtZU1pbGxpcywwKTtjb25zdCBlPXRoaXMuY291bnRMb3VkRnJhbWVzKHRoaXMudmFkT3B0aW9ucy5zaWduYWxTZWFyY2hGcmFtZXMpLHM9TWF0aC5yb3VuZCh0aGlzLnZhZE9wdGlvbnMuc2lnbmFsQWN0aXZhdGlvbip0aGlzLnZhZE9wdGlvbnMuc2lnbmFsU2VhcmNoRnJhbWVzKSxpPU1hdGgucm91bmQodGhpcy52YWRPcHRpb25zLnNpZ25hbFJlbGVhc2UqdGhpcy52YWRPcHRpb25zLnNpZ25hbFNlYXJjaEZyYW1lcyk7cmV0dXJuIGU+PXM/KHRoaXMudmFkU3VzdGFpbk1pbGxpc0xlZnQ9dGhpcy52YWRPcHRpb25zLnNpZ25hbFN1c3RhaW5NaWxsaXMsITApOiEoZTw9aSYmMD09PXRoaXMudmFkU3VzdGFpbk1pbGxpc0xlZnQpJiZ0fWFkYXB0QmFja2dyb3VuZE5vaXNlKCl7aWYoIXRoaXMuaXNTaWduYWxEZXRlY3RlZCYmdGhpcy52YWRPcHRpb25zLm5vaXNlTGVhcm5IYWxmdGltZU1pbGxpcz4wKXt2YXIgdD1NYXRoLnBvdygyLC10aGlzLmZyYW1lTWlsbGlzL3RoaXMudmFkT3B0aW9ucy5ub2lzZUxlYXJuSGFsZnRpbWVNaWxsaXMpO3RoaXMuYmFzZWxpbmVFbmVyZ3k9dGhpcy5iYXNlbGluZUVuZXJneSp0K3RoaXMuZW5lcmd5KigxLXQpfX1wdXNoRnJhbWVIaXN0b3J5KHQpe3RoaXMubG91ZEZyYW1lQml0cz0odD8xOjApfHRoaXMubG91ZEZyYW1lQml0czw8MX1jb3VudExvdWRGcmFtZXModCl7bGV0IGU9MCxzPXRoaXMubG91ZEZyYW1lQml0cztmb3IoO3Q+MDspMT09KDEmcykmJmUrKyxzPj49MSx0LS07cmV0dXJuIGV9fXZhciBvLHIsYTshZnVuY3Rpb24odCl7dC5TdGFydGVkPSJzdGFydGVkIix0LlN0b3BwZWQ9InN0b3BwZWQiLHQuU2VnbWVudEVuZD0ic2VnbWVudF9lbmQiLHQuVHJhbnNjcmlwdD0idHJhbnNjcmlwdCIsdC5FbnRpdHk9ImVudGl0eSIsdC5JbnRlbnQ9ImludGVudCIsdC5UZW50YXRpdmVUcmFuc2NyaXB0PSJ0ZW50YXRpdmVfdHJhbnNjcmlwdCIsdC5UZW50YXRpdmVFbnRpdGllcz0idGVudGF0aXZlX2VudGl0aWVzIix0LlRlbnRhdGl2ZUludGVudD0idGVudGF0aXZlX2ludGVudCJ9KG98fChvPXt9KSksZnVuY3Rpb24odCl7dC5PcGVuZWQ9IldFQlNPQ0tFVF9PUEVOIix0LkNsb3NlZD0iV0VCU09DS0VUX0NMT1NFRCIsdC5BdWRpb1Byb2Nlc3NvclJlYWR5PSJTT1VSQ0VfU0FNUExFX1JBVEVfU0VUX1NVQ0NFU1MiLHQuVmFkU2lnbmFsSGlnaD0iVmFkU2lnbmFsSGlnaCIsdC5WYWRTaWduYWxMb3c9IlZhZFNpZ25hbExvdyJ9KHJ8fChyPXt9KSksZnVuY3Rpb24odCl7dC5jb25uZWN0PSJjb25uZWN0Iix0LmluaXRBdWRpb1Byb2Nlc3Nvcj0iaW5pdEF1ZGlvUHJvY2Vzc29yIix0LmFkanVzdEF1ZGlvUHJvY2Vzc29yPSJhZGp1c3RBdWRpb1Byb2Nlc3NvciIsdC5TRVRfU0hBUkVEX0FSUkFZX0JVRkZFUlM9IlNFVF9TSEFSRURfQVJSQVlfQlVGRkVSUyIsdC5DTE9TRT0iQ0xPU0UiLHQuU1RBUlRfQ09OVEVYVD0iU1RBUlRfQ09OVEVYVCIsdC5TV0lUQ0hfQ09OVEVYVD0iU1dJVENIX0NPTlRFWFQiLHQuU1RPUF9DT05URVhUPSJTVE9QX0NPTlRFWFQiLHQuQVVESU89IkFVRElPIix0LnN0YXJ0U3RyZWFtPSJzdGFydFN0cmVhbSIsdC5zdG9wU3RyZWFtPSJzdG9wU3RyZWFtIix0LnNldENvbnRleHRPcHRpb25zPSJzZXRDb250ZXh0T3B0aW9ucyJ9KGF8fChhPXt9KSk7Y29uc3Qgbj0wLGg9MSxjPTI7Y2xhc3MgbHtjb25zdHJ1Y3Rvcih0KXt0aGlzLnRhcmdldFNhbXBsZVJhdGU9MTZlMyx0aGlzLmlzQ29udGV4dFN0YXJ0ZWQ9ITEsdGhpcy5jb250ZXh0U3RhcnRUaW1lPTAsdGhpcy5pbW1lZGlhdGVNb2RlPSExLHRoaXMuZnJhbWVNaWxsaXM9MzAsdGhpcy5vdXRwdXRBdWRpb0ZyYW1lPW5ldyBJbnQxNkFycmF5KHRoaXMuZnJhbWVNaWxsaXMqdGhpcy50YXJnZXRTYW1wbGVSYXRlLzFlMyksdGhpcy5kZWJ1Zz0hMSx0aGlzLm9uV2Vic29ja2V0Q2xvc2U9dD0+e2lmKCF0aGlzLndlYnNvY2tldCl0aHJvdyBFcnJvcigiV2ViU29ja2V0IGlzIHVuZGVmaW5lZCIpO3RoaXMuZGVidWcmJmNvbnNvbGUubG9nKCJbV2ViU29ja2V0Q2xpZW50XSIsIm9uV2Vic29ja2V0Q2xvc2UiKSx0aGlzLndlYnNvY2tldC5yZW1vdmVFdmVudExpc3RlbmVyKCJvcGVuIix0aGlzLm9uV2Vic29ja2V0T3BlbiksdGhpcy53ZWJzb2NrZXQucmVtb3ZlRXZlbnRMaXN0ZW5lcigibWVzc2FnZSIsdGhpcy5vbldlYnNvY2tldE1lc3NhZ2UpLHRoaXMud2Vic29ja2V0LnJlbW92ZUV2ZW50TGlzdGVuZXIoImVycm9yIix0aGlzLm9uV2Vic29ja2V0RXJyb3IpLHRoaXMud2Vic29ja2V0LnJlbW92ZUV2ZW50TGlzdGVuZXIoImNsb3NlIix0aGlzLm9uV2Vic29ja2V0Q2xvc2UpLHRoaXMud2Vic29ja2V0PXZvaWQgMCx0aGlzLndvcmtlckN0eC5wb3N0TWVzc2FnZSh7dHlwZTpyLkNsb3NlZCxjb2RlOnQuY29kZSxyZWFzb246dC5yZWFzb24sd2FzQ2xlYW46dC53YXNDbGVhbn0pfSx0aGlzLm9uV2Vic29ja2V0T3Blbj10PT57dGhpcy5kZWJ1ZyYmY29uc29sZS5sb2coIltXZWJTb2NrZXRDbGllbnRdIiwid2Vic29ja2V0IG9wZW5lZCIpLHRoaXMud29ya2VyQ3R4LnBvc3RNZXNzYWdlKHt0eXBlOnIuT3BlbmVkfSl9LHRoaXMub25XZWJzb2NrZXRFcnJvcj10PT57dGhpcy5kZWJ1ZyYmY29uc29sZS5sb2coIltXZWJTb2NrZXRDbGllbnRdIiwid2Vic29ja2V0IGVycm9yIil9LHRoaXMub25XZWJzb2NrZXRNZXNzYWdlPXQ9PntsZXQgZTt0cnl7ZT1KU09OLnBhcnNlKHQuZGF0YSl9Y2F0Y2godCl7cmV0dXJuIHZvaWQgY29uc29sZS5lcnJvcigiW1dlYlNvY2tldENsaWVudF0iLCJlcnJvciBwYXJzaW5nIHJlc3BvbnNlIGZyb20gdGhlIHNlcnZlcjoiLHQpfXRoaXMud29ya2VyQ3R4LnBvc3RNZXNzYWdlKGUpfSx0aGlzLndvcmtlckN0eD10fWNvbm5lY3QodCxlLHMsaSl7dGhpcy5kZWJ1Zz1pLHRoaXMuZGVidWcmJmNvbnNvbGUubG9nKCJbV2ViU29ja2V0Q2xpZW50XSIsImNvbm5lY3RpbmcgdG8gIix0KSx0aGlzLnRhcmdldFNhbXBsZVJhdGU9cyx0aGlzLmlzQ29udGV4dFN0YXJ0ZWQ9ITEsdGhpcy53ZWJzb2NrZXQ9bmV3IFdlYlNvY2tldCh0LGUpLHRoaXMud2Vic29ja2V0LmFkZEV2ZW50TGlzdGVuZXIoIm9wZW4iLHRoaXMub25XZWJzb2NrZXRPcGVuKSx0aGlzLndlYnNvY2tldC5hZGRFdmVudExpc3RlbmVyKCJtZXNzYWdlIix0aGlzLm9uV2Vic29ja2V0TWVzc2FnZSksdGhpcy53ZWJzb2NrZXQuYWRkRXZlbnRMaXN0ZW5lcigiZXJyb3IiLHRoaXMub25XZWJzb2NrZXRFcnJvciksdGhpcy53ZWJzb2NrZXQuYWRkRXZlbnRMaXN0ZW5lcigiY2xvc2UiLHRoaXMub25XZWJzb2NrZXRDbG9zZSl9aW5pdEF1ZGlvUHJvY2Vzc29yKHQsbyl7dGhpcy5hdWRpb1Byb2Nlc3Nvcj1uZXcgcyh0LHRoaXMudGFyZ2V0U2FtcGxlUmF0ZSw1KSxvJiYodGhpcy5hdWRpb1Byb2Nlc3Nvci52YWQ9bmV3IGkobyksdGhpcy5hdWRpb1Byb2Nlc3Nvci5vblZhZFN0YXRlQ2hhbmdlPXQ9Pnt2YXIgZSxzO2NvbnN0IGk9bnVsbD09PShzPW51bGw9PT0oZT10aGlzLmF1ZGlvUHJvY2Vzc29yKXx8dm9pZCAwPT09ZT92b2lkIDA6ZS52YWQpfHx2b2lkIDA9PT1zP3ZvaWQgMDpzLnZhZE9wdGlvbnM7aSYmKHQmJih0aGlzLmltbWVkaWF0ZU1vZGU/aS5jb250cm9sTGlzdGVuaW5nJiZ0aGlzLnN0YXJ0Q29udGV4dCh0aGlzLmRlZmF1bHRDb250ZXh0T3B0aW9ucyk6dGhpcy53b3JrZXJDdHgucG9zdE1lc3NhZ2Uoe3R5cGU6ci5WYWRTaWduYWxIaWdofSkpLHR8fCh0aGlzLmltbWVkaWF0ZU1vZGU/aS5jb250cm9sTGlzdGVuaW5nJiZ0aGlzLnN0b3BDb250ZXh0KCk6dGhpcy53b3JrZXJDdHgucG9zdE1lc3NhZ2Uoe3R5cGU6ci5WYWRTaWduYWxMb3d9KSkpfSksdGhpcy5hdWRpb1Byb2Nlc3Nvci5vblNlbmRBdWRpbz0odCxzLGkpPT57ZS5jb252ZXJ0RmxvYXRUb0ludDE2KHQsdGhpcy5vdXRwdXRBdWRpb0ZyYW1lLHMsaSksdGhpcy5zZW5kKHRoaXMub3V0cHV0QXVkaW9GcmFtZSl9LHZvaWQgMCE9PXRoaXMud29ya2VyQ3R4JiZ0aGlzLndvcmtlckN0eC5wb3N0TWVzc2FnZSh7dHlwZTpyLkF1ZGlvUHJvY2Vzc29yUmVhZHl9KX1hZGp1c3RBdWRpb1Byb2Nlc3Nvcih0KXtpZighdGhpcy5hdWRpb1Byb2Nlc3Nvcil0aHJvdyBuZXcgRXJyb3IoIk5vIEF1ZGlvUHJvY2Vzc29yIik7aWYodm9pZCAwIT09dC5pbW1lZGlhdGUmJih0aGlzLmltbWVkaWF0ZU1vZGU9dC5pbW1lZGlhdGUpLHQudmFkKXtpZighdGhpcy5hdWRpb1Byb2Nlc3Nvci52YWQpdGhyb3cgbmV3IEVycm9yKCJObyBWQUQgaW4gQXVkaW9Qcm9jZXNzb3IuIERpZCB5b3UgZGVmaW5lIGB2YWRgIGluIEJyb3dzZXJDbGllbnQgY29uc3RydWN0b3IgcGFyYW1ldGVycz8iKTt0aGlzLmF1ZGlvUHJvY2Vzc29yLnZhZC5hZGp1c3RWYWRPcHRpb25zKHQudmFkKX19c2V0U2hhcmVkQXJyYXlCdWZmZXJzKHQsZSl7dGhpcy5jb250cm9sU0FCPW5ldyBJbnQzMkFycmF5KHQpLHRoaXMuZGF0YVNBQj1uZXcgRmxvYXQzMkFycmF5KGUpO2NvbnN0IHM9dGhpcy5kYXRhU0FCLmxlbmd0aC8zMjt0aGlzLmRlYnVnJiZjb25zb2xlLmxvZygiW1dlYlNvY2tldENsaWVudF0iLCJBdWRpbyBoYW5kbGUgaW50ZXJ2YWwiLHMsIm1zIiksc2V0SW50ZXJ2YWwodGhpcy5wcm9jZXNzQXVkaW9TQUIuYmluZCh0aGlzKSxzKX1zdGFydFN0cmVhbSgpe2lmKCF0aGlzLmF1ZGlvUHJvY2Vzc29yKXRocm93IG5ldyBFcnJvcigiTm8gQXVkaW9Qcm9jZXNzb3IiKTt0aGlzLmF1ZGlvUHJvY2Vzc29yLnJlc2V0U3RyZWFtKCl9c3RvcFN0cmVhbSgpe2lmKCF0aGlzLmF1ZGlvUHJvY2Vzc29yKXRocm93IG5ldyBFcnJvcigiTm8gQXVkaW9Qcm9jZXNzb3IiKTt0aGlzLmlzQ29udGV4dFN0YXJ0ZWQmJnRoaXMuc3RvcENvbnRleHQoKX1wcm9jZXNzQXVkaW8odCl7aWYoIXRoaXMuYXVkaW9Qcm9jZXNzb3IpdGhyb3cgbmV3IEVycm9yKCJObyBBdWRpb1Byb2Nlc3NvciIpO3RoaXMuYXVkaW9Qcm9jZXNzb3IucHJvY2Vzc0F1ZGlvKHQpfXByb2Nlc3NBdWRpb1NBQigpe2lmKCF0aGlzLmNvbnRyb2xTQUJ8fCF0aGlzLmRhdGFTQUIpdGhyb3cgbmV3IEVycm9yKCJObyBTaGFyZWRBcnJheUJ1ZmZlcnMiKTtjb25zdCB0PXRoaXMuY29udHJvbFNBQltoXTtpZigwPT09dGhpcy5jb250cm9sU0FCW2NdJiZ0PjApe2NvbnN0IGU9dGhpcy5kYXRhU0FCLnN1YmFycmF5KDAsdCk7dGhpcy5jb250cm9sU0FCW2hdPTAsdGhpcy5jb250cm9sU0FCW25dPTAsZS5sZW5ndGg+MCYmdGhpcy5wcm9jZXNzQXVkaW8oZSl9fXN0YXJ0Q29udGV4dCh0KXt2YXIgZTtpZighdGhpcy5hdWRpb1Byb2Nlc3Nvcil0aHJvdyBFcnJvcigiTm8gQXVkaW9Qcm9jZXNzb3IiKTtpZih0aGlzLmlzQ29udGV4dFN0YXJ0ZWQpcmV0dXJuIHZvaWQgY29uc29sZS5lcnJvcigiW1dlYlNvY2tldENsaWVudF0iLCJjYW4ndCBzdGFydCBjb250ZXh0OiBhY3RpdmUgY29udGV4dCBleGlzdHMiKTt0aGlzLmF1ZGlvUHJvY2Vzc29yLnN0YXJ0Q29udGV4dCgpLHRoaXMuaXNDb250ZXh0U3RhcnRlZD0hMCx0aGlzLmNvbnRleHRTdGFydFRpbWU9dGhpcy5hdWRpb1Byb2Nlc3Nvci5nZXRTdHJlYW1Qb3NpdGlvbigpO2xldCBzPW51bGwhPT0oZT10aGlzLmRlZmF1bHRDb250ZXh0T3B0aW9ucykmJnZvaWQgMCE9PWU/ZTp7fTt2b2lkIDAhPT10JiYocz1PYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30scyksdCkpO2NvbnN0IGk9UyhzKTtpLmV2ZW50PSJzdGFydCIsdGhpcy5zZW5kKEpTT04uc3RyaW5naWZ5KGkpKX1zdG9wQ29udGV4dCgpe2lmKCF0aGlzLmF1ZGlvUHJvY2Vzc29yKXRocm93IEVycm9yKCJObyBBdWRpb1Byb2Nlc3NvciIpO2lmKCF0aGlzLmlzQ29udGV4dFN0YXJ0ZWQpcmV0dXJuIHZvaWQgY29uc29sZS5lcnJvcigiW1dlYlNvY2tldENsaWVudF0iLCJjYW4ndCBzdG9wIGNvbnRleHQ6IG5vIGFjdGl2ZSBjb250ZXh0Iik7dGhpcy5hdWRpb1Byb2Nlc3Nvci5zdG9wQ29udGV4dCgpLHRoaXMuaXNDb250ZXh0U3RhcnRlZD0hMTtjb25zdCB0PUpTT04uc3RyaW5naWZ5KHtldmVudDoic3RvcCJ9KTt0aGlzLnNlbmQodCl9c3dpdGNoQ29udGV4dCh0KXtpZighdGhpcy53ZWJzb2NrZXQpdGhyb3cgRXJyb3IoIldlYlNvY2tldCBpcyB1bmRlZmluZWQiKTtpZighdGhpcy5pc0NvbnRleHRTdGFydGVkKXJldHVybiB2b2lkIGNvbnNvbGUuZXJyb3IoIltXZWJTb2NrZXRDbGllbnRdIiwiY2FuJ3Qgc3dpdGNoIGNvbnRleHQ6IG5vIGFjdGl2ZSBjb250ZXh0Iik7aWYodm9pZCAwPT09KG51bGw9PXQ/dm9pZCAwOnQuYXBwSWQpKXJldHVybiB2b2lkIGNvbnNvbGUuZXJyb3IoIltXZWJTb2NrZXRDbGllbnRdIiwiY2FuJ3Qgc3dpdGNoIGNvbnRleHQ6IG5ldyBhcHAgaWQgaXMgdW5kZWZpbmVkIik7Y29uc3QgZT1KU09OLnN0cmluZ2lmeSh7ZXZlbnQ6InN0b3AifSk7dGhpcy5zZW5kKGUpO2NvbnN0IHM9Uyh0KTtzLmV2ZW50PSJzdGFydCIsdGhpcy5zZW5kKEpTT04uc3RyaW5naWZ5KHMpKX1jbG9zZVdlYnNvY2tldCh0PTEwMDUsZT0iTm8gU3RhdHVzIFJlY2VpdmVkIil7aWYodGhpcy5kZWJ1ZyYmY29uc29sZS5sb2coIltXZWJTb2NrZXRDbGllbnRdIiwiV2Vic29ja2V0IGNsb3NpbmciKSwhdGhpcy53ZWJzb2NrZXQpdGhyb3cgRXJyb3IoIldlYlNvY2tldCBpcyB1bmRlZmluZWQiKTt0aGlzLndlYnNvY2tldC5jbG9zZSh0LGUpfXNlbmQodCl7aWYoIXRoaXMud2Vic29ja2V0KXRocm93IG5ldyBFcnJvcigiTm8gV2Vic29ja2V0Iik7aWYodGhpcy53ZWJzb2NrZXQucmVhZHlTdGF0ZSE9PXRoaXMud2Vic29ja2V0Lk9QRU4pdGhyb3cgbmV3IEVycm9yKGBFeHBlY3RlZCBPUEVOIFdlYnNvY2tldCBzdGF0ZSwgYnV0IGdvdCAke3RoaXMud2Vic29ja2V0LnJlYWR5U3RhdGV9YCk7dHJ5e3RoaXMud2Vic29ja2V0LnNlbmQodCl9Y2F0Y2godCl7Y29uc29sZS5sb2coIltXZWJTb2NrZXRDbGllbnRdIiwic2VydmVyIGNvbm5lY3Rpb24gZXJyb3IiLHQpfX1zZXRDb250ZXh0T3B0aW9ucyh0KXt0aGlzLmRlZmF1bHRDb250ZXh0T3B0aW9ucz10fX1jb25zdCBkPXNlbGYsbT1uZXcgbChkKTtmdW5jdGlvbiBTKHQpe2NvbnN0IGU9e29wdGlvbnM6e3RpbWV6b25lOltJbnRsLkRhdGVUaW1lRm9ybWF0KCkucmVzb2x2ZWRPcHRpb25zKCkudGltZVpvbmVdfX07cmV0dXJuIHZvaWQgMD09PXR8fChlLm9wdGlvbnMudm9jYWJ1bGFyeT10LnZvY2FidWxhcnksZS5vcHRpb25zLnZvY2FidWxhcnlfYmlhcz10LnZvY2FidWxhcnlCaWFzLGUub3B0aW9ucy5zaWxlbmNlX3RyaWdnZXJlZF9zZWdtZW50YXRpb249dC5zaWxlbmNlVHJpZ2dlcmVkU2VnbWVudGF0aW9uLHZvaWQgMCE9PShudWxsPT10P3ZvaWQgMDp0LnRpbWV6b25lKSYmKGUub3B0aW9ucy50aW1lem9uZT1udWxsPT10P3ZvaWQgMDp0LnRpbWV6b25lKSx2b2lkIDAhPT10LmFwcElkJiYoZS5hcHBJZD10LmFwcElkKSksZX1yZXR1cm4gZC5vbm1lc3NhZ2U9ZnVuY3Rpb24odCl7c3dpdGNoKHQuZGF0YS50eXBlKXtjYXNlIGEuY29ubmVjdDptLmNvbm5lY3QodC5kYXRhLmFwaVVybCx0LmRhdGEuYXV0aFRva2VuLHQuZGF0YS50YXJnZXRTYW1wbGVSYXRlLHQuZGF0YS5kZWJ1Zyk7YnJlYWs7Y2FzZSBhLmluaXRBdWRpb1Byb2Nlc3NvcjptLmluaXRBdWRpb1Byb2Nlc3Nvcih0LmRhdGEuc291cmNlU2FtcGxlUmF0ZSx0LmRhdGEudmFkT3B0aW9ucyk7YnJlYWs7Y2FzZSBhLmFkanVzdEF1ZGlvUHJvY2Vzc29yOm0uYWRqdXN0QXVkaW9Qcm9jZXNzb3IodC5kYXRhLnBhcmFtcyk7YnJlYWs7Y2FzZSBhLlNFVF9TSEFSRURfQVJSQVlfQlVGRkVSUzptLnNldFNoYXJlZEFycmF5QnVmZmVycyh0LmRhdGEuY29udHJvbFNBQix0LmRhdGEuZGF0YVNBQik7YnJlYWs7Y2FzZSBhLkNMT1NFOm0uY2xvc2VXZWJzb2NrZXQoMWUzLCJDbG9zZSByZXF1ZXN0ZWQgYnkgY2xpZW50Iik7YnJlYWs7Y2FzZSBhLnN0YXJ0U3RyZWFtOm0uc3RhcnRTdHJlYW0oKTticmVhaztjYXNlIGEuc3RvcFN0cmVhbTptLnN0b3BTdHJlYW0oKTticmVhaztjYXNlIGEuU1RBUlRfQ09OVEVYVDptLnN0YXJ0Q29udGV4dCh0LmRhdGEub3B0aW9ucyk7YnJlYWs7Y2FzZSBhLlNXSVRDSF9DT05URVhUOm0uc3dpdGNoQ29udGV4dCh0LmRhdGEub3B0aW9ucyk7YnJlYWs7Y2FzZSBhLlNUT1BfQ09OVEVYVDptLnN0b3BDb250ZXh0KCk7YnJlYWs7Y2FzZSBhLkFVRElPOm0ucHJvY2Vzc0F1ZGlvKHQuZGF0YS5wYXlsb2FkKTticmVhaztjYXNlIGEuc2V0Q29udGV4dE9wdGlvbnM6bS5zZXRDb250ZXh0T3B0aW9ucyh0LmRhdGEub3B0aW9ucyk7YnJlYWs7ZGVmYXVsdDpjb25zb2xlLmxvZygiV09SS0VSIix0KX19LHQuY29udGV4dE9wdGlvbnNUb01zZz1TLHQuZGVmYXVsdD1sLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0fSh7fSk7Cgo=",this.worker.addEventListener("message",this.onWebsocketMessage)}onResponse(t){this.onResponseCb=t}onClose(t){this.onCloseCb=t}initialize(e,i,n,s){return o(this,void 0,void 0,(function*(){return this.worker.postMessage({type:t.ControllerSignal.connect,apiUrl:e,authToken:i,targetSampleRate:n,debug:s}),this.startCbs=[],this.stopCbs=[],new Promise((t=>{this.resolveInitialization=t}))}))}initAudioProcessor(e,i){return o(this,void 0,void 0,(function*(){return this.worker.postMessage({type:t.ControllerSignal.initAudioProcessor,sourceSampleRate:e,vadOptions:i}),new Promise((t=>{this.resolveSourceSampleRateSet=t}))}))}adjustAudioProcessor(e){this.worker.postMessage({type:t.ControllerSignal.adjustAudioProcessor,params:e})}close(){return o(this,void 0,void 0,(function*(){return new Promise(((e,i)=>{this.worker.postMessage({type:t.ControllerSignal.CLOSE,code:1e3,message:"Client has ended the session"}),e()}))}))}startStream(){return o(this,void 0,void 0,(function*(){this.worker.postMessage({type:t.ControllerSignal.startStream})}))}stopStream(){return o(this,void 0,void 0,(function*(){this.worker.postMessage({type:t.ControllerSignal.stopStream})}))}startContext(e){return o(this,void 0,void 0,(function*(){return new Promise(((i,n)=>{this.startCbs.push(((t,e)=>{void 0!==t?n(t):i(e)})),this.worker.postMessage({type:t.ControllerSignal.START_CONTEXT,options:e})}))}))}stopContext(){return o(this,void 0,void 0,(function*(){return new Promise(((e,i)=>{this.stopCbs.push(((t,n)=>{void 0!==t?i(t):e(n)})),this.worker.postMessage({type:t.ControllerSignal.STOP_CONTEXT})}))}))}switchContext(e){return o(this,void 0,void 0,(function*(){return new Promise(((i,n)=>{this.startCbs.push(((t,e)=>{void 0!==t?n(t):i(e)})),this.worker.postMessage({type:t.ControllerSignal.SWITCH_CONTEXT,options:e})}))}))}postMessage(t){this.worker.postMessage(t)}sendAudio(e){this.worker.postMessage({type:t.ControllerSignal.AUDIO,payload:e})}setContextOptions(e){return o(this,void 0,void 0,(function*(){this.worker.postMessage({type:t.ControllerSignal.setContextOptions,options:e})}))}}class F{constructor(){this.storage=window.localStorage}get(t){return this.storage.getItem(t)}set(t,e){this.storage.setItem(t,e)}getOrSet(t,e){let i=this.storage.getItem(t);return null===i&&(i=e(),this.storage.setItem(t,i)),i}}function f(t,e){return{intent:t.intent,isFinal:e}}const L="speechly-auth-token";class x{constructor(e){var i,o,a,d,l,c,r,h;if(this.activeContexts=new Map,this.maxReconnectAttemptCount=10,this.connectAttempt=0,this.connectPromise=null,this.cbs=[],this.state=t.DecoderState.Disconnected,this.handleWebsocketResponse=e=>{switch(this.debug&&console.log("[Decoder]","Received response",e),e.type){case t.WorkerSignal.VadSignalHigh:this.cbs.forEach((t=>t.onVadStateChange.forEach((t=>t(!0)))));break;case t.WorkerSignal.VadSignalLow:this.cbs.forEach((t=>t.onVadStateChange.forEach((t=>t(!1)))));break;case t.WebsocketResponseType.Started:this.activeContexts.set(e.audio_context,new Map),this.cbs.forEach((t=>t.contextStartedCbs.forEach((t=>t(e.audio_context)))));break;case t.WebsocketResponseType.Stopped:this.cbs.forEach((t=>t.contextStoppedCbs.forEach((t=>t(e.audio_context))))),this.activeContexts.delete(e.audio_context);break;default:this.handleSegmentUpdate(e)}},this.handleSegmentUpdate=e=>{var i;const{audio_context:n,segment_id:o,type:a}=e;let{data:d}=e;const l=this.activeContexts.get(n);if(void 0===l)return void console.warn("[Decoder]","Received response for non-existent context",n);let c=null!==(i=l.get(o))&&void 0!==i?i:new s(n,o);switch(a){case t.WebsocketResponseType.TentativeTranscript:const e=function(t){return t.words.map((({word:t,index:e,start_timestamp:i,end_timestamp:n})=>({value:t,index:e,startTimestamp:i,endTimestamp:n,isFinal:!1})))}(d),i=d.transcript;this.cbs.forEach((t=>t.tentativeTranscriptCbs.forEach((t=>t(n,o,e,i))))),c=c.updateTranscript(e);break;case t.WebsocketResponseType.Transcript:const s=function(t){return{value:t.word,index:t.index,startTimestamp:t.start_timestamp,endTimestamp:t.end_timestamp,isFinal:!0}}(d);this.cbs.forEach((t=>t.transcriptCbs.forEach((t=>t(n,o,s))))),c=c.updateTranscript([s]);break;case t.WebsocketResponseType.TentativeEntities:const a=function(t){return t.entities.map((({entity:t,value:e,start_position:i,end_position:n})=>({type:t,value:e,startPosition:i,endPosition:n,isFinal:!1})))}(d);this.cbs.forEach((t=>t.tentativeEntityCbs.forEach((t=>t(n,o,a))))),c=c.updateEntities(a);break;case t.WebsocketResponseType.Entity:const l=function(t){return{type:t.entity,value:t.value,startPosition:t.start_position,endPosition:t.end_position,isFinal:!0}}(d);this.cbs.forEach((t=>t.entityCbs.forEach((t=>t(n,o,l))))),c=c.updateEntities([l]);break;case t.WebsocketResponseType.TentativeIntent:const r=f(d,!1);this.cbs.forEach((t=>t.tentativeIntentCbs.forEach((t=>t(n,o,r))))),c=c.updateIntent(r);break;case t.WebsocketResponseType.Intent:const h=f(d,!0);this.cbs.forEach((t=>t.intentCbs.forEach((t=>t(n,o,h))))),c=c.updateIntent(h);break;case t.WebsocketResponseType.SegmentEnd:c=c.finalize()}l.set(o,c),this.activeContexts.set(n,l),this.logSegments&&console.info(c.toString()),this.cbs.forEach((t=>t.segmentChangeCbs.forEach((t=>t(c.toSegment())))))},this.handleWebsocketClosure=e=>{if(1e3===e.code)this.debug&&console.log("[Decoder]","Websocket closed",e);else{if(console.error("[Decoder]","Websocket closed due to error",e),void 0===this.deviceId)return void this.setState(t.DecoderState.Failed);this.setState(t.DecoderState.Disconnected),this.reconnect()}},this.logSegments=null!==(i=e.logSegments)&&void 0!==i&&i,this.appId=null!==(o=e.appId)&&void 0!==o?o:void 0,this.projectId=null!==(a=e.projectId)&&void 0!==a?a:void 0,this.sampleRate=null!==(d=e.sampleRate)&&void 0!==d?d:n,this.debug=null!==(l=e.debug)&&void 0!==l&&l,void 0!==this.appId&&void 0!==this.projectId)throw Error("[Decoder] You cannot use both appId and projectId at the same time");if(void 0===this.appId&&void 0===this.projectId)throw Error("[Decoder] Either an appId or a projectId is required");const u=null!==(c=e.apiUrl)&&void 0!==c?c:"https://api.speechly.com";this.apiUrl=function(t,e){const i=new URLSearchParams;return i.append("sampleRate",e.toString()),`${t}?${i.toString()}`}(u.replace("http","ws")+"/ws/v1",this.sampleRate),this.loginUrl=`${u}/login`,this.storage=null!==(r=e.storage)&&void 0!==r?r:new F,this.deviceId=this.storage.getOrSet("speechly-device-id",g),this.apiClient=new T,this.apiClient.onResponse(this.handleWebsocketResponse),this.apiClient.onClose(this.handleWebsocketClosure),(null===(h=e.connect)||void 0===h||h)&&this.connect()}getReconnectDelayMs(t){return 100*Math.pow(2,t)}sleep(t){return o(this,void 0,void 0,(function*(){return new Promise((e=>setTimeout(e,t)))}))}connect(){return o(this,void 0,void 0,(function*(){null===this.connectPromise&&(this.connectPromise=(()=>o(this,void 0,void 0,(function*(){const e=this.storage.get(L);if(null!=e&&N(e,this.projectId,this.appId,this.deviceId))this.authToken=e;else try{this.authToken=yield function(t,e,i,n,s=fetch,a=Date.now){var d;return o(this,void 0,void 0,(function*(){let o;o=void 0!==e?{projectId:e,deviceId:n}:{appId:i,deviceId:n};const l=yield s(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(o)}),c=yield l.json();if(200!==l.status)throw Error(null!==(d=c.error)&&void 0!==d?d:`Speechly API login request failed with ${l.status}`);if(void 0===c.access_token)throw Error("Invalid login response from Speechly API");if(!N(c.access_token,e,i,n,a))throw Error("Invalid token received from Speechly API");return c.access_token}))}(this.loginUrl,this.projectId,this.appId,this.deviceId),this.storage.set(L,this.authToken)}catch(e){throw this.setState(t.DecoderState.Failed),e}yield this.apiClient.initialize(this.apiUrl,this.authToken,this.sampleRate,this.debug),this.advanceState(t.DecoderState.Connected)})))()),yield this.connectPromise}))}adjustAudioProcessor(t){this.apiClient.adjustAudioProcessor(t)}close(){return o(this,void 0,void 0,(function*(){let e;try{yield this.apiClient.close()}catch(t){e=t.message}if(this.activeContexts.clear(),this.connectPromise=null,this.setState(t.DecoderState.Disconnected),void 0!==e)throw Error(e)}))}startStream(){return o(this,void 0,void 0,(function*(){yield this.apiClient.startStream()}))}stopStream(){return o(this,void 0,void 0,(function*(){this.state===t.DecoderState.Active&&(yield this.stopContext(0)),yield this.apiClient.stopStream()}))}startContext(e){return o(this,void 0,void 0,(function*(){if(this.state===t.DecoderState.Failed)throw Error("[Decoder] startContext cannot be run in Failed state.");if(this.state<t.DecoderState.Connected)yield this.connect();else if(this.state>t.DecoderState.Connected)throw Error("[Decoder] Unable to complete startContext: Expected Connected state, but was in "+G(this.state)+".");let n;if(this.setState(t.DecoderState.Active),null!=this.projectId)n=yield this.apiClient.startContext(null==e?void 0:e.appId);else{if(null!=(null==e?void 0:e.appId)&&this.appId!==(null==e?void 0:e.appId))throw this.setState(t.DecoderState.Failed),i;n=yield this.apiClient.startContext()}if(this.state<t.DecoderState.Active)throw Error("[Decoder] Unable to complete startContext: Problem acquiring contextId");return n}))}sendAudio(t){this.apiClient.sendAudio(t)}stopContext(e){return o(this,void 0,void 0,(function*(){if(this.state===t.DecoderState.Failed)throw Error("[Decoder] stopContext cannot be run in unrecovable error state.");if(this.state!==t.DecoderState.Active)throw Error("[Decoder] Unable to complete stopContext: Expected Active state, but was in "+G(this.state)+".");e>0&&(yield this.sleep(e)),this.apiClient.stopContext(),this.setState(t.DecoderState.Connected)}))}switchContext(e){return o(this,void 0,void 0,(function*(){if(this.state!==t.DecoderState.Active)throw Error("[Decoder] Unable to complete switchContext: Expected Active state, but was in "+G(this.state)+".");const i=yield this.apiClient.switchContext(e);this.activeContexts.set(i,new Map)}))}registerListener(t){this.cbs.push(t)}initAudioProcessor(t,e){return o(this,void 0,void 0,(function*(){this.sampleRate=t,yield this.apiClient.initAudioProcessor(t,e)}))}useSharedArrayBuffers(t,e){this.apiClient.postMessage({type:"SET_SHARED_ARRAY_BUFFERS",controlSAB:t,dataSAB:e})}setContextOptions(t){return o(this,void 0,void 0,(function*(){yield this.apiClient.setContextOptions(t)}))}reconnect(){return o(this,void 0,void 0,(function*(){this.debug&&console.log("[Decoder]","Reconnecting...",this.connectAttempt),this.connectPromise=null,this.connectAttempt<this.maxReconnectAttemptCount?(yield this.sleep(this.getReconnectDelayMs(this.connectAttempt++)),yield this.connect()):console.error("[Decoder] Maximum reconnect count reached, giving up automatic reconnect.")}))}advanceState(t){this.state>=t||this.setState(t)}setState(t){this.state!==t&&(this.debug&&console.log("[Decoder]",G(this.state),"->",G(t)),this.state=t,this.cbs.forEach((e=>{var i;return null===(i=e.stateChangeCbs)||void 0===i?void 0:i.forEach((e=>e(t)))})))}}t.BrowserClient=class{constructor(t){var e,i;this.contextStopDelay=250,this.debug=!1,this.initialized=!1,this.isStreaming=!1,this.isStreamAutoStarted=!1,this.active=!1,this.listeningPromise=null,this.stats={maxSignalEnergy:0,sentSamples:0};const n=window.navigator.mediaDevices.getSupportedConstraints();this.nativeResamplingSupported=!0===n.sampleRate,this.isMobileSafari=["iPad Simulator","iPhone Simulator","iPod Simulator","iPad","iPhone","iPod"].indexOf(navigator.platform)>=0||navigator.userAgent.includes("Mac")&&"ontouchend"in document,this.isSafari=this.isMobileSafari||void 0!==window.safari,this.useSAB=!this.isSafari,this.vadOptions=Object.assign(Object.assign({},b),t.vad),this.debug=null===(e=t.debug)||void 0===e||e,this.callbacks=new Z,this.callbacks.onVadStateChange.push(this.autoControlListening.bind(this)),this.decoder=null!==(i=t.decoder)&&void 0!==i?i:new x(t),this.decoder.registerListener(this.callbacks)}initialize(t){var i,s;return o(this,void 0,void 0,(function*(){if(!this.initialized){this.initialized=!0,this.debug&&console.log("[BrowserClient]","initializing"),yield this.decoder.connect();try{const t={};if(this.nativeResamplingSupported&&(t.sampleRate=n),void 0!==window.webkitAudioContext)try{this.audioContext=new window.webkitAudioContext(t)}catch(t){this.debug&&console.log("[BrowserClient]","creating audioContext without samplerate conversion",t),this.audioContext=new window.webkitAudioContext}else this.audioContext=new window.AudioContext(t),void 0!==window.webkitAudioContext&&(yield this.audioContext.resume())}catch(t){throw e}if(this.isSafari||void 0===window.AudioWorkletNode){if(this.debug&&console.log("[BrowserClient]","using ScriptProcessorNode"),void 0!==window.webkitAudioContext){const t=this.audioContext.sampleRate/n,e=4096*Math.pow(2,Math.ceil(Math.log(t)/Math.log(2)));this.audioProcessor=this.audioContext.createScriptProcessor(e,1,1)}else this.audioProcessor=this.audioContext.createScriptProcessor(void 0,1,1);this.audioProcessor.connect(this.audioContext.destination),this.audioProcessor.addEventListener("audioprocess",(t=>{this.handleAudio(t.inputBuffer.getChannelData(0))}))}else{this.debug&&console.log("[BrowserClient]","using AudioWorkletNode");const t=new Blob(["\n// Indices for the Control SAB.\nconst CONTROL = {\n 'WRITE_INDEX': 0,\n 'FRAMES_AVAILABLE': 1,\n 'LOCK': 2,\n};\n\nclass SpeechlyProcessor extends AudioWorkletProcessor {\n constructor() {\n super();\n\n this._initialized = false;\n this.debug = false;\n this.port.onmessage = this._initialize.bind(this);\n }\n\n _initialize(event) {\n this.controlSAB = new Int32Array(event.data.controlSAB);\n this.dataSAB = new Float32Array(event.data.dataSAB);\n this.debug = event.data.debug;\n if (this.debug) {\n console.log('[BrowserClient AudioWorkletNode]', 'initializing audioworklet');\n }\n this.sharedBufferSize = this.dataSAB.length;\n this.buffer = new Float32Array(0);\n this._initialized = true;\n }\n\n _transferDataToSharedBuffer(data) {\n this.controlSAB[CONTROL.LOCK] = 1;\n let inputWriteIndex = this.controlSAB[CONTROL.WRITE_INDEX];\n if (this.controlSAB[CONTROL.FRAMES_AVAILABLE] > 0) {\n if (inputWriteIndex + data.length > this.sharedBufferSize) {\n // console.log('buffer overflow')\n inputWriteIndex = 0;\n }\n }\n this.dataSAB.set(data, inputWriteIndex);\n this.controlSAB[CONTROL.WRITE_INDEX] = inputWriteIndex + data.length;\n this.controlSAB[CONTROL.FRAMES_AVAILABLE] = inputWriteIndex + data.length;\n this.controlSAB[CONTROL.LOCK] = 0;\n }\n\n _pushData(data) {\n if (this.debug) {\n const signalEnergy = getStandardDeviation(data)\n this.port.postMessage({\n type: 'STATS',\n signalEnergy: signalEnergy,\n samples: data.length,\n });\n }\n\n if (this.buffer.length > this.sharedBufferSize) {\n const dataToTransfer = this.buffer.subarray(0, this.sharedBufferSize);\n this._transferDataToSharedBuffer(dataToTransfer);\n this.buffer = this.buffer.subarray(this.sharedBufferSize);\n }\n let concat = new Float32Array(this.buffer.length + data.length);\n concat.set(this.buffer);\n concat.set(data, this.buffer.length);\n this.buffer = concat;\n }\n\n process(inputs, outputs, parameters) {\n const inputChannelData = inputs[0][0];\n if (inputChannelData !== undefined) {\n if (this.controlSAB && this.dataSAB) {\n this._pushData(inputChannelData);\n } else {\n this.port.postMessage({\n type: 'DATA',\n frames: inputChannelData\n });\n }\n }\n\n return true;\n }\n}\n\nfunction getStandardDeviation(array) {\n const n = array.length\n const mean = array.reduce((a, b) => a + b) / n\n return Math.sqrt(array.map(x => Math.pow(x - mean, 2)).reduce((a, b) => a + b) / n)\n}\n\nregisterProcessor('speechly-worklet', SpeechlyProcessor);\n"],{type:"text/javascript"}),e=window.URL.createObjectURL(t);if(yield this.audioContext.audioWorklet.addModule(e),this.speechlyNode=new AudioWorkletNode(this.audioContext,"speechly-worklet"),this.speechlyNode.connect(this.audioContext.destination),this.useSAB&&void 0!==window.SharedArrayBuffer){this.debug&&console.log("[BrowserClient]","using SharedArrayBuffer");const t=new window.SharedArrayBuffer(4*Int32Array.BYTES_PER_ELEMENT),e=new window.SharedArrayBuffer(1024*Float32Array.BYTES_PER_ELEMENT);this.decoder.useSharedArrayBuffers(t,e),this.speechlyNode.port.postMessage({type:"SET_SHARED_ARRAY_BUFFERS",controlSAB:t,dataSAB:e,debug:this.debug})}else this.debug&&console.log("[BrowserClient]","can not use SharedArrayBuffer");this.speechlyNode.port.onmessage=t=>{switch(t.data.type){case"STATS":t.data.signalEnergy>this.stats.maxSignalEnergy&&(this.stats.maxSignalEnergy=t.data.signalEnergy),this.stats.sentSamples+=parseInt(t.data.samples);break;case"DATA":this.handleAudio(t.data.frames)}}}this.debug&&console.log("[BrowserClient]","audioContext sampleRate is",null===(i=this.audioContext)||void 0===i?void 0:i.sampleRate),yield this.decoder.initAudioProcessor(null===(s=this.audioContext)||void 0===s?void 0:s.sampleRate,this.vadOptions),this.vadOptions&&(yield this.startStream()),(null==t?void 0:t.mediaStream)&&(yield this.attach(null==t?void 0:t.mediaStream))}}))}adjustAudioProcessor(t){t.vad&&(this.vadOptions=Object.assign(Object.assign({},this.vadOptions),t.vad)),this.decoder.adjustAudioProcessor(t)}close(){var t,e,i;return o(this,void 0,void 0,(function*(){yield this.detach(),null!==this.speechlyNode&&(null===(t=this.speechlyNode)||void 0===t||t.port.close(),null===(e=this.speechlyNode)||void 0===e||e.disconnect()),void 0!==this.audioProcessor&&(null===(i=this.audioProcessor)||void 0===i||i.disconnect()),yield this.decoder.close(),this.initialized=!1}))}attach(t){var e,i,n,s,a,d;return o(this,void 0,void 0,(function*(){if(yield this.initialize(),yield this.detach(),this.stream=null===(e=this.audioContext)||void 0===e?void 0:e.createMediaStreamSource(t),"running"!==(null===(i=this.audioContext)||void 0===i?void 0:i.state)&&(this.debug&&console.log("[BrowserClient]","audioContext resume required, state is",null===(n=this.audioContext)||void 0===n?void 0:n.state),yield null===(s=this.audioContext)||void 0===s?void 0:s.resume()),this.speechlyNode)null===(a=this.stream)||void 0===a||a.connect(this.speechlyNode);else{if(!this.audioProcessor)throw Error("[BrowserClient] cannot attach to mediaStream, not initialized");null===(d=this.stream)||void 0===d||d.connect(this.audioProcessor)}}))}detach(){return o(this,void 0,void 0,(function*(){this.active&&(yield this.stop(0)),this.stream&&(this.stream.disconnect(),this.stream=void 0)}))}uploadAudioData(t,e){var i,n,s;return o(this,void 0,void 0,(function*(){yield this.initialize();const o=yield null===(i=this.audioContext)||void 0===i?void 0:i.decodeAudioData(t);if(void 0===o)throw Error("Could not decode audioData");const a=o.getChannelData(0);if(o.numberOfChannels>1){const t=o.getChannelData(1);for(let e=0;e<a.length;e++)a[e]=(a[e]+t[e])/2}let d;yield this.adjustAudioProcessor({immediate:!0}),yield this.startStream();const l=(null===(n=this.vadOptions)||void 0===n?void 0:n.enabled)&&(null===(s=this.vadOptions)||void 0===s?void 0:s.controlListening);let c;d=l?"multiple context ids":yield this.start(e);for(let t=0;t<a.length;t+=16e3){const e=t+16e3;c=e>a.length?a.slice(t):a.slice(t,e),this.handleAudio(c)}return l||(yield this.stop(0)),yield this.stopStream(),yield this.adjustAudioProcessor({immediate:!1}),d}))}startStream(t){return o(this,void 0,void 0,(function*(){yield this.decoder.startStream(t),this.isStreaming=!0}))}stopStream(){return o(this,void 0,void 0,(function*(){yield this.decoder.stopStream(),this.isStreaming=!1,this.isStreamAutoStarted=!1}))}queueTask(t){return o(this,void 0,void 0,(function*(){const e=this.listeningPromise;return this.listeningPromise=(()=>o(this,void 0,void 0,(function*(){return yield e,t()})))(),this.listeningPromise}))}start(t){return o(this,void 0,void 0,(function*(){this.active=!0;return yield this.queueTask((()=>o(this,void 0,void 0,(function*(){yield this.initialize(),this.isStreaming||(yield this.startStream(t),this.isStreamAutoStarted=!0);return this.decoder.startContext(t)}))))}))}stop(t=this.contextStopDelay){return o(this,void 0,void 0,(function*(){this.active=!1,yield this.queueTask((()=>o(this,void 0,void 0,(function*(){try{yield this.decoder.stopContext(t),this.isStreaming&&this.isStreamAutoStarted&&(yield this.stopStream()),0===this.stats.sentSamples&&console.warn("[BrowserClient]","audioContext contained no audio data")}catch(t){console.warn("[BrowserClient]","stop() failed",t)}finally{this.stats.sentSamples=0}}))))}))}autoControlListening(t){var e;this.debug&&console.log("[BrowserClient]","autoControlListening",t),(null===(e=this.vadOptions)||void 0===e?void 0:e.controlListening)&&(t?this.active||this.start():this.active&&this.stop(0))}handleAudio(t){this.isStreaming&&(this.stats.sentSamples+=t.length,this.decoder.sendAudio(t))}isActive(){return this.active}onStart(t){this.callbacks.contextStartedCbs.push(t)}onStop(t){this.callbacks.contextStoppedCbs.push(t)}onSegmentChange(t){this.callbacks.segmentChangeCbs.push(t)}onTranscript(t){this.callbacks.transcriptCbs.push(t)}onEntity(t){this.callbacks.entityCbs.push(t)}onIntent(t){this.callbacks.intentCbs.push(t)}onTentativeTranscript(t){this.callbacks.tentativeTranscriptCbs.push(t)}onTentativeEntities(t){this.callbacks.tentativeEntityCbs.push(t)}onTentativeIntent(t){this.callbacks.tentativeIntentCbs.push(t)}onStateChange(t){this.callbacks.stateChangeCbs.push(t)}},t.BrowserMicrophone=class{constructor(){this.muted=!1,this.initialized=!1;try{const t=window.navigator.mediaDevices.getSupportedConstraints();this.nativeResamplingSupported=!0===t.sampleRate,this.autoGainControlSupported=!0===t.autoGainControl}catch(t){this.nativeResamplingSupported=!1,this.autoGainControlSupported=!1}}initialize(){var t;return o(this,void 0,void 0,(function*(){if(this.initialized)return;if(void 0===(null===(t=window.navigator)||void 0===t?void 0:t.mediaDevices))throw e;const i={video:!1};this.nativeResamplingSupported||this.autoGainControlSupported?i.audio={sampleRate:n,autoGainControl:this.autoGainControlSupported}:i.audio=!0;try{this.mediaStream=yield window.navigator.mediaDevices.getUserMedia(i)}catch(t){throw console.error(t),l}this.initialized=!0,this.muted=!0}))}close(){return o(this,void 0,void 0,(function*(){if(!this.initialized)throw a;this.muted=!0;this.mediaStream.getTracks().forEach((t=>t.stop())),this.mediaStream=void 0,this.initialized=!1}))}isRecording(){return!this.muted}},t.CloudDecoder=x,t.DefaultSampleRate=n,t.ErrAlreadyInitialized=d,t.ErrAppIdChangeWithoutProjectLogin=i,t.ErrDeviceNotSupported=e,t.ErrKeyNotFound=p,t.ErrNoAudioConsent=l,t.ErrNoStorageSupport=u,t.ErrNotInitialized=a,t.EventCallbacks=Z,t.SegmentState=s,t.VadDefaultOptions=b,t.stateToString=G,Object.defineProperty(t,"__esModule",{value:!0})}));
//# sourceMappingURL=speechly.umd.min.js.map

@@ -1,4 +0,4 @@

import EnergyTresholdVAD from './EnergyTresholdVAD';
import EnergyThresholdVAD from './EnergyThresholdVAD';
declare class AudioProcessor {
vad?: EnergyTresholdVAD;
vad?: EnergyThresholdVAD;
/**

@@ -14,5 +14,4 @@ * Returns true when StartContext is called and expecting StopContext next

utteranceSerial: number;
sendAudio: (samples: Float32Array, startIndex: number, length: number) => void;
onVadSignalLow: () => void;
onVadSignalHigh: () => void;
onSendAudio: (samples: Float32Array, startIndex: number, length: number) => void;
onVadStateChange: (isSignalDetected: boolean) => void;
private readonly inputSampleRate;

@@ -27,3 +26,3 @@ private readonly internalSampleRate;

private streamFramePos;
private isSignalDetected;
private wasSignalDetected;
constructor(inputSampleRate: number, outputSampleRate: number, historyFrames: number);

@@ -35,2 +34,6 @@ startContext(): void;

/**
* @returns current position in stream in seconds
*/
getStreamPosition(): number;
/**
* Process speech audio samples from a microphone or other audio source.

@@ -56,5 +59,4 @@ *

private processFrame;
private analyzeAudioFrame;
private autoControlListening;
private processVadFrame;
}
export default AudioProcessor;

@@ -17,3 +17,3 @@ import { DecoderState, DecoderOptions, ContextOptions, AudioProcessorParameters } from './types';

private readonly callbacks;
private readonly vadOptions?;
private vadOptions;
private audioContext?;

@@ -35,3 +35,2 @@ private initialized;

constructor(options: DecoderOptions);
onVadStateChange(active: boolean): void;
/**

@@ -87,3 +86,3 @@ * Create an AudioContext for resampling audio.

* @param options - any custom options for the audio processing.
* @returns The contextId of the active audio context.
* @returns The contextId of the active audio context
*/

@@ -94,6 +93,5 @@ start(options?: ContextOptions): Promise<string>;

* If there is no active audio context, a warning is logged to console.
*
* @returns The contextId of the stopped context, or null if no context is active.
*/
stop(stopDelayMs?: number): Promise<string | null>;
stop(stopDelayMs?: number): Promise<void>;
private autoControlListening;
private handleAudio;

@@ -105,2 +103,12 @@ /**

/**
* Adds a listener for start events
* @param cb - the callback to invoke on context start
*/
onStart(cb: (contextId: string) => void): void;
/**
* Adds a listener for stop events
* @param cb - the callback to invoke on context stop
*/
onStop(cb: (contextId: string) => void): void;
/**
* Adds a listener for current segment change events.

@@ -107,0 +115,0 @@ * @param cb - the callback to invoke on segment change events.

@@ -45,3 +45,3 @@ import { DecoderOptions, DecoderState, EventCallbacks, ContextOptions, VadOptions, AudioProcessorParameters } from './types';

close(): Promise<void>;
startStream(defaultContextOptions?: ContextOptions): Promise<void>;
startStream(): Promise<void>;
stopStream(): Promise<void>;

@@ -48,0 +48,0 @@ /**

@@ -105,5 +105,11 @@ import { Segment, Word, Entity, Intent } from '../speechly';

controlListening: boolean;
/**
* Set audio worker
* to ‘immediate audio processor’ mode where it can control start/stop context internally at its own pace.
*/
immediate?: boolean;
}
export interface AudioProcessorParameters {
vad?: Partial<VadOptions>;
immediate?: boolean;
}

@@ -151,7 +157,2 @@ /**

/**
* BrowserClient.uploadAudioData internally uses this to set audio worker
* to ‘immediate audio processor’ mode where it can control start/stop context at its own pace.
*/
immediate?: boolean;
/**
* Inference time vocabulary.

@@ -158,0 +159,0 @@ */

@@ -243,3 +243,3 @@ import { AudioProcessorParameters, ContextOptions, VadOptions } from '../client';

postMessage(message: Object): void;
startStream(defaultContextOptions?: ContextOptions): Promise<void>;
startStream(): Promise<void>;
stopStream(): Promise<void>;

@@ -246,0 +246,0 @@ /**

@@ -22,3 +22,3 @@ import { APIClient, ResponseCallback, CloseCallback } from './types';

close(): Promise<void>;
startStream(defaultContextOptions?: ContextOptions): Promise<void>;
startStream(): Promise<void>;
stopStream(): Promise<void>;

@@ -25,0 +25,0 @@ startContext(options?: ContextOptions): Promise<string>;

@@ -6,2 +6,3 @@ import { AudioProcessorParameters, ContextOptions, VadOptions } from '../client';

private isContextStarted;
private contextStartTime;
private websocket?;

@@ -11,2 +12,3 @@ private audioProcessor?;

private dataSAB?;
private immediateMode;
private readonly frameMillis;

@@ -16,3 +18,2 @@ private readonly outputAudioFrame;

private defaultContextOptions?;
private vadContextOptions?;
constructor(ctx: Worker);

@@ -27,3 +28,3 @@ connect(apiUrl: string, authToken: string, targetSampleRate: number, debug: boolean): void;

setSharedArrayBuffers(controlSAB: number, dataSAB: number): void;
startStream(vadContextOptions?: ContextOptions): void;
startStream(): void;
stopStream(): void;

@@ -30,0 +31,0 @@ /**

{
"name": "@speechly/browser-client",
"version": "2.1.0-beta.4",
"version": "2.1.0-beta.5",
"description": "Browser client for Speechly API",

@@ -5,0 +5,0 @@ "keywords": [

import AudioTools from './AudioTools'
import EnergyTresholdVAD from './EnergyTresholdVAD'
import EnergyThresholdVAD from './EnergyThresholdVAD'
class AudioProcessor {
public vad?: EnergyTresholdVAD
public vad?: EnergyThresholdVAD

@@ -18,5 +18,4 @@ /**

public utteranceSerial = -1
public sendAudio = (samples: Float32Array, startIndex: number, length: number): void => {}
public onVadSignalLow = (): void => {}
public onVadSignalHigh = (): void => {}
public onSendAudio = (samples: Float32Array, startIndex: number, length: number): void => {}
public onVadStateChange = (isSignalDetected: boolean): void => {}

@@ -34,3 +33,3 @@ private readonly inputSampleRate: number = 16000

private streamFramePos: number = 0
private isSignalDetected: boolean = false
private wasSignalDetected: boolean = false

@@ -71,2 +70,9 @@ constructor(inputSampleRate: number, outputSampleRate: number, historyFrames: number) {

/**
* @returns current position in stream in seconds
*/
public getStreamPosition(): number {
return this.streamSamplePos / this.inputSampleRate
}
/**
* Process speech audio samples from a microphone or other audio source.

@@ -137,3 +143,3 @@ *

while (historyFrameIndex !== this.currentFrameNumber) {
this.sendAudio(this.sampleRingBuffer, historyFrameIndex * this.frameSamples, this.frameSamples)
this.onSendAudio(this.sampleRingBuffer, historyFrameIndex * this.frameSamples, this.frameSamples)
this.samplesSent += this.frameSamples

@@ -143,3 +149,3 @@ historyFrameIndex = (historyFrameIndex + 1) % this.historyFrames

}
this.sendAudio(this.sampleRingBuffer, frameBase, subFrameSamples)
this.onSendAudio(this.sampleRingBuffer, frameBase, subFrameSamples)
this.samplesSent += subFrameSamples

@@ -159,23 +165,12 @@ }

private processFrame(floats: Float32Array, start = 0, length = -1): void {
this.analyzeAudioFrame(floats, start, length)
this.autoControlListening()
}
private analyzeAudioFrame(waveData: Float32Array, s: number, frameSamples: number): void {
if (this.vad?.vadOptions.enabled) {
this.vad.processFrame(waveData, s, frameSamples)
this.processVadFrame(this.vad, floats, start, length)
}
}
private autoControlListening(): void {
if (this.vad?.vadOptions.enabled) {
if (!this.isSignalDetected && this.vad.isSignalDetected) {
this.onVadSignalHigh()
this.isSignalDetected = true
}
if (this.isSignalDetected && !this.vad.isSignalDetected) {
this.onVadSignalLow()
this.isSignalDetected = false
}
private processVadFrame(vad: EnergyThresholdVAD, floats: Float32Array, start = 0, length = -1): void {
vad.processFrame(floats, start, length)
if (vad.isSignalDetected !== this.wasSignalDetected) {
this.onVadStateChange(vad.isSignalDetected)
this.wasSignalDetected = vad.isSignalDetected
}

@@ -182,0 +177,0 @@ }

@@ -21,3 +21,3 @@ import { DecoderState, EventCallbacks, DecoderOptions, ContextOptions, VadOptions, VadDefaultOptions, AudioProcessorParameters } from './types'

private readonly callbacks: EventCallbacks
private readonly vadOptions?: VadOptions
private vadOptions: VadOptions

@@ -56,3 +56,3 @@ private audioContext?: AudioContext

this.callbacks = new EventCallbacks()
this.callbacks.onVadStateChange.push(this.onVadStateChange.bind(this))
this.callbacks.onVadStateChange.push(this.autoControlListening.bind(this))
this.decoder = options.decoder ?? new CloudDecoder(options)

@@ -62,17 +62,2 @@ this.decoder.registerListener(this.callbacks)

onVadStateChange(active: boolean): void {
if (this.debug) {
console.log('[BrowserClient]', 'onVadStateChange', active)
}
if (this.vadOptions?.controlListening) {
if (active) {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
if (!this.active) this.start()
} else {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
if (this.active) this.stop(0)
}
}
}
/**

@@ -213,2 +198,5 @@ * Create an AudioContext for resampling audio.

adjustAudioProcessor(ap: AudioProcessorParameters): void {
if (ap.vad) {
this.vadOptions = { ...this.vadOptions, ...ap.vad }
}
this.decoder.adjustAudioProcessor(ap)

@@ -295,6 +283,8 @@ }

await this.startStream({ immediate: true })
await this.adjustAudioProcessor({ immediate: true })
await this.startStream()
let contextId: string
const vadActive = this.vadOptions?.enabled && this.vadOptions?.controlListening
if (!vadActive) {

@@ -322,2 +312,3 @@ contextId = await this.start(options)

await this.stopStream()
await this.adjustAudioProcessor({ immediate: false })

@@ -361,5 +352,7 @@ return contextId

* @param options - any custom options for the audio processing.
* @returns The contextId of the active audio context.
* @returns The contextId of the active audio context
*/
async start(options?: ContextOptions): Promise<string> {
this.active = true
const promise = await this.queueTask(async () => {

@@ -373,3 +366,2 @@ await this.initialize()

const startPromise = this.decoder.startContext(options)
this.active = true
return startPromise

@@ -383,10 +375,9 @@ })

* If there is no active audio context, a warning is logged to console.
*
* @returns The contextId of the stopped context, or null if no context is active.
*/
async stop(stopDelayMs = this.contextStopDelay): Promise<string | null> {
const contextId = await this.queueTask(async () => {
let contextId = null
async stop(stopDelayMs = this.contextStopDelay): Promise<void> {
this.active = false
await this.queueTask(async () => {
try {
contextId = await this.decoder.stopContext(stopDelayMs)
await this.decoder.stopContext(stopDelayMs)
if (this.isStreaming && this.isStreamAutoStarted) {

@@ -403,10 +394,22 @@ // Automatically control streaming for backwards compability

} finally {
this.active = false
this.stats.sentSamples = 0
}
return contextId
})
return contextId
}
private autoControlListening(vadActive: boolean): void {
if (this.debug) {
console.log('[BrowserClient]', 'autoControlListening', vadActive)
}
if (this.vadOptions?.controlListening) {
if (vadActive) {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
if (!this.active) this.start()
} else {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
if (this.active) this.stop(0)
}
}
}
private handleAudio(array: Float32Array): void {

@@ -427,2 +430,18 @@ if (this.isStreaming) {

/**
* Adds a listener for start events
* @param cb - the callback to invoke on context start
*/
onStart(cb: (contextId: string) => void): void {
this.callbacks.contextStartedCbs.push(cb)
}
/**
* Adds a listener for stop events
* @param cb - the callback to invoke on context stop
*/
onStop(cb: (contextId: string) => void): void {
this.callbacks.contextStoppedCbs.push(cb)
}
/**
* Adds a listener for current segment change events.

@@ -429,0 +448,0 @@ * @param cb - the callback to invoke on segment change events.

@@ -160,4 +160,4 @@ import { v4 as uuidv4 } from 'uuid'

async startStream(defaultContextOptions?: ContextOptions): Promise<void> {
await this.apiClient.startStream(defaultContextOptions)
async startStream(): Promise<void> {
await this.apiClient.startStream()
}

@@ -294,4 +294,4 @@

case WebsocketResponseType.Stopped: {
this.cbs.forEach(cb => cb.contextStoppedCbs.forEach(f => f(response.audio_context)))
this.activeContexts.delete(response.audio_context)
this.cbs.forEach(cb => cb.contextStoppedCbs.forEach(f => f(response.audio_context)))
break

@@ -298,0 +298,0 @@ }

@@ -125,2 +125,8 @@ import { Segment, Word, Entity, Intent } from '../speechly'

controlListening: boolean
/**
* Set audio worker
* to ‘immediate audio processor’ mode where it can control start/stop context internally at its own pace.
*/
immediate?: boolean
}

@@ -130,2 +136,3 @@

vad?: Partial<VadOptions>
immediate?: boolean
}

@@ -189,8 +196,2 @@

/**
* BrowserClient.uploadAudioData internally uses this to set audio worker
* to ‘immediate audio processor’ mode where it can control start/stop context at its own pace.
*/
immediate?: boolean
/**
* Inference time vocabulary.

@@ -197,0 +198,0 @@ */

@@ -273,3 +273,3 @@ import { AudioProcessorParameters, ContextOptions, VadOptions } from '../client'

startStream(defaultContextOptions?: ContextOptions): Promise<void>
startStream(): Promise<void>

@@ -276,0 +276,0 @@ stopStream(): Promise<void>

@@ -84,4 +84,4 @@ import { APIClient, ResponseCallback, CloseCallback, WebsocketResponse, WebsocketResponseType, WorkerSignal, ControllerSignal } from './types'

async startStream(defaultContextOptions?: ContextOptions): Promise<void> {
this.worker.postMessage({ type: ControllerSignal.startStream, options: defaultContextOptions })
async startStream(): Promise<void> {
this.worker.postMessage({ type: ControllerSignal.startStream })
}

@@ -88,0 +88,0 @@

import AudioProcessor from '../audioprocessing/AudioProcessor'
import EnergyTresholdVAD from '../audioprocessing/EnergyTresholdVAD'
import EnergyThresholdVAD from '../audioprocessing/EnergyThresholdVAD'
import AudioTools from '../audioprocessing/AudioTools'

@@ -47,2 +47,3 @@ import { ControllerSignal, WebsocketResponseType, WorkerSignal } from './types'

private isContextStarted: boolean = false
private contextStartTime: number = 0
private websocket?: WebSocket

@@ -53,2 +54,3 @@ private audioProcessor?: AudioProcessor

private immediateMode = false
private readonly frameMillis = 30

@@ -59,4 +61,3 @@ private readonly outputAudioFrame: Int16Array = new Int16Array(this.frameMillis * this.targetSampleRate / 1000)

private defaultContextOptions?: ContextOptions // setContextOptions modifies
private vadContextOptions?: ContextOptions // startStream modifies
private defaultContextOptions?: ContextOptions

@@ -85,23 +86,22 @@ constructor(ctx: Worker) {

if (vadOptions) {
this.audioProcessor.vad = new EnergyTresholdVAD(vadOptions)
this.audioProcessor.vad = new EnergyThresholdVAD(vadOptions)
this.audioProcessor.onVadSignalHigh = () => {
this.audioProcessor.onVadStateChange = (isSignalDetected: boolean) => {
const currentVadOptions = this.audioProcessor?.vad?.vadOptions
if (!(currentVadOptions?.enabled && currentVadOptions?.controlListening)) return
if (!currentVadOptions) return
if (this.defaultContextOptions?.immediate) {
this.startContext(this.vadContextOptions)
} else {
this.workerCtx.postMessage({ type: WorkerSignal.VadSignalHigh })
if (isSignalDetected) {
if (!this.immediateMode) {
this.workerCtx.postMessage({ type: WorkerSignal.VadSignalHigh })
} else if (currentVadOptions.controlListening) {
this.startContext(this.defaultContextOptions)
}
}
}
this.audioProcessor.onVadSignalLow = () => {
const currentVadOptions = this.audioProcessor?.vad?.vadOptions
if (!(currentVadOptions?.enabled && currentVadOptions?.controlListening)) return
if (this.defaultContextOptions?.immediate) {
this.stopContext()
} else {
this.workerCtx.postMessage({ type: WorkerSignal.VadSignalLow })
if (!isSignalDetected) {
if (!this.immediateMode) {
this.workerCtx.postMessage({ type: WorkerSignal.VadSignalLow })
} else if (currentVadOptions.controlListening) {
this.stopContext()
}
}

@@ -111,3 +111,3 @@ }

this.audioProcessor.sendAudio = (floats: Float32Array, startIndex: number, length: number) => {
this.audioProcessor.onSendAudio = (floats: Float32Array, startIndex: number, length: number) => {
AudioTools.convertFloatToInt16(floats, this.outputAudioFrame, startIndex, length)

@@ -130,2 +130,6 @@ this.send(this.outputAudioFrame)

if (ap.immediate !== undefined) {
this.immediateMode = ap.immediate
}
if (ap.vad) {

@@ -149,3 +153,3 @@ if (!this.audioProcessor.vad) {

startStream(vadContextOptions?: ContextOptions): void {
startStream(): void {
if (!this.audioProcessor) {

@@ -155,3 +159,2 @@ throw new Error('No AudioProcessor')

this.vadContextOptions = vadContextOptions
this.audioProcessor.resetStream()

@@ -169,4 +172,2 @@ }

}
this.vadContextOptions = undefined
}

@@ -216,2 +217,3 @@

this.isContextStarted = true
this.contextStartTime = this.audioProcessor.getStreamPosition()

@@ -372,3 +374,3 @@ let options: ContextOptions = this.defaultContextOptions ?? {}

case ControllerSignal.startStream:
websocketClient.startStream(e.data.options)
websocketClient.startStream()
break

@@ -375,0 +377,0 @@ case ControllerSignal.stopStream:

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc