1 line
165 KiB
JavaScript
1 line
165 KiB
JavaScript
var PlayerState;!function(PlayerState){PlayerState[PlayerState.PREBUFFERING=0]="PREBUFFERING",PlayerState[PlayerState.PLAYING=1]="PLAYING",PlayerState[PlayerState.BUFFERING=2]="BUFFERING",PlayerState[PlayerState.STOPPING=3]="STOPPING",PlayerState[PlayerState.STOPPED=4]="STOPPED"}(PlayerState||(PlayerState={}));class AudioController{constructor(){this.playerState=PlayerState.STOPPED,this.audioCache=[],this.playingAudioCache=[],this._volume=1,this._codecCache=[],this._timeIndex=0,this.allowBuffering=!0,this.speakerContext=AudioController.globalContext,this.onSpeaking=function(){},this.onSilence=function(){}}static get globalContext(){return this._globalContext?this._globalContext:(this._globalContext=new AudioContext,this._globalContext)}static initializeAudioController(){}initialize(){AudioController._audioInstances.push(this)}close(){AudioController._audioInstances.remove(this)}playBuffer(buffer){switch(buffer.sampleRate!=this.speakerContext.sampleRate&&console.warn("[AudioController] Source sample rate isn't equal to playback sample rate! ("+buffer.sampleRate+" | "+this.speakerContext.sampleRate+")"),this.applayVolume(buffer),this.audioCache.push(buffer),this.playerState!=PlayerState.STOPPED&&this.playerState!=PlayerState.STOPPING||(console.log("[Audio] Starting new playback"),this.playerState=PlayerState.PREBUFFERING),this.playerState){case PlayerState.PREBUFFERING:case PlayerState.BUFFERING:if(this.audioCache.length<3){if(this.playerState!=PlayerState.BUFFERING)break;if(this.allowBuffering)break}this.playerState==PlayerState.PREBUFFERING?(console.log("[Audio] Prebuffering succeeded (Replaying now)"),this.onSpeaking()):this.allowBuffering&&console.log("[Audio] Buffering succeeded (Replaying now)"),this.playerState=PlayerState.PLAYING;case PlayerState.PLAYING:this.playQueue()}}playQueue(){let buffer;for(;buffer=this.audioCache.pop_front();){this._timeIndex<this.speakerContext.currentTime&&(this._timeIndex=this.speakerContext.currentTime);let player=this.speakerContext.createBufferSource();player.buffer=buffer,player.onended=(()=>this.removeNode(player)),this.playingAudioCache.push(player),player.connect(this.speakerContext.destination),player.start(this._timeIndex),this._timeIndex+=buffer.duration}}removeNode(node){this.playingAudioCache.remove(node),this.testBufferQueue()}stopAudio(now=!1){if(this.playerState=PlayerState.STOPPING,now){this.playerState=PlayerState.STOPPED,this.audioCache=[];for(let entry of this.playingAudioCache)entry.stop(0);this.playingAudioCache=[]}this.testBufferQueue()}testBufferQueue(){0==this.audioCache.length&&0==this.playingAudioCache.length&&(this.playerState!=PlayerState.STOPPING?(this.playerState=PlayerState.BUFFERING,this.allowBuffering||console.warn("[Audio] Detected a buffer underflow!")):(this.playerState=PlayerState.STOPPED,this.onSilence()))}get volume(){return this._volume}set volume(val){if(this._volume!=val){this._volume=val;for(let buffer of this.audioCache)this.applayVolume(buffer)}}applayVolume(buffer){for(let channel=0;channel<buffer.numberOfChannels;channel++){let data=buffer.getChannelData(channel);for(let sample=0;sample<data.length;sample++){let lane=data[sample];lane*=this._volume,data[sample]=lane}}}codecCache(codec){for(;this._codecCache.length<=codec;)this._codecCache.push(new CodecClientCache);return this._codecCache[codec]}}function concatenate(resultConstructor,...arrays){let totalLength=0;for(const arr of arrays)totalLength+=arr.length;const result=new resultConstructor(totalLength);let offset=0;for(const arr of arrays)result.set(arr,offset),offset+=arr.length;return result}function formatDate(secs){let years=Math.floor(secs/31536e3),days=Math.floor(secs/86400)%365,hours=Math.floor(secs/3600)%24,minutes=Math.floor(secs/60)%60,seconds=Math.floor(secs%60),result="";return years>0&&(result+=years+" years "),(years>0||days>0)&&(result+=days+" days "),(years>0||days>0||hours>0)&&(result+=hours+" hours "),(years>0||days>0||hours>0||minutes>0)&&(result+=minutes+" minutes "),years>0||days>0||hours>0||minutes>0||seconds>0?result+=seconds+" seconds ":result="now ",result.substr(0,result.length-1)}AudioController._audioInstances=[],AudioController._timeIndex=0,Array.prototype.remove||(Array.prototype.remove=function(elem){const index=this.indexOf(elem,0);return index>-1&&(this.splice(index,1),!0)}),Array.prototype.pop_front||(Array.prototype.pop_front=function(){if(0!=this.length)return this.splice(0,1)[0]}),Array.prototype.last||(Array.prototype.last=function(){if(0!=this.length)return this[this.length-1]}),"undefined"!=typeof $&&($.spawn||($.spawn=function(tagName){return $(document.createElement(tagName))})),String.prototype.format||(String.prototype.format=function(){const args=arguments;let array=1==args.length&&$.isArray(args[0]);return this.replace(/\{\{|\}\}|\{(\d+)\}/g,function(m,n){return"{{"==m?"{":"}}"==m?"}":array?args[0][n]:args[n]})});class BufferChunk{constructor(buffer){this.buffer=buffer,this.index=0}copyRangeTo(target,maxLength,offset){let copy=Math.min(this.buffer.length-this.index,maxLength);for(let channel=0;channel<this.buffer.numberOfChannels;channel++)target.getChannelData(channel).set(this.buffer.getChannelData(channel).subarray(this.index,this.index+copy),offset);return copy}}class CodecClientCache{constructor(){this._chunks=[]}bufferedSamples(max=0){let value=0;for(let i=0;i<this._chunks.length&&value<max;i++)value+=this._chunks[i].buffer.length-this._chunks[i].index;return value}}$(document).on("mousedown",function(e){0==$(e.target).parents(".modal").length&&$(".modal:visible").last().find(".close").trigger("click")});const ModalFunctions={divify:function(val){return val.length>1?$.spawn("div").append(val):val},jqueriefy:function(val){switch($.isFunction(val)&&(val=val()),typeof val){case"string":return $("<div>"+val+"</div>");case"object":return val;case"undefined":return console.warn("Got undefined type!"),$.spawn("div");default:return console.error("Invalid type "+typeof val),$()}},warpProperties(data){if(data instanceof ModalProperties)return data;{let props=new ModalProperties;for(let key in data)props[key]=data[key];return props}}};class ModalProperties{constructor(){this.header=(()=>"HEADER"),this.body=(()=>"BODY"),this.footer=(()=>"FOOTER"),this.closeListener=(()=>{}),this.width="60%",this.hight="auto",this.closeable=!0}registerCloseListener(listener){return this.closeListener?$.isArray(this.closeListener)?this.closeListener.push(listener):this.closeListener=[this.closeListener,listener]:this.closeListener=listener,this}triggerClose(){if($.isArray(this.closeListener))for(let listener of this.closeListener)listener();else this.closeListener()}}class Modal{constructor(props){this.properties=props}get htmlTag(){return this._htmlTag||this._create(),this._htmlTag}_create(){let modal=$.spawn("div");modal.addClass("modal");let content=$.spawn("div");content.addClass("modal-content"),content.css("width",this.properties.width);let header=ModalFunctions.divify(ModalFunctions.jqueriefy(this.properties.header)).addClass("modal-header");this.properties.closeable&&header.append('<span class="close">×</span>');let body=ModalFunctions.divify(ModalFunctions.jqueriefy(this.properties.body)).addClass("modal-body"),footer=ModalFunctions.divify(ModalFunctions.jqueriefy(this.properties.footer)).addClass("modal-footer");content.append(header),content.append(body),content.append(footer),modal.append(content),modal.find(".close").click(function(){this.properties.closeable&&this.close()}.bind(this)),this._htmlTag=modal}open(){this.htmlTag.appendTo($("body")),this.htmlTag.show()}close(){const _this=this;this.htmlTag.animate({opacity:0},()=>{_this.htmlTag.detach()}),this.properties.triggerClose()}}function createModal(data){return new Modal(ModalFunctions.warpProperties(data))}class InputModalProperties extends ModalProperties{}function createInputModal(headMessage,question,validator,callback,props={}){props=ModalFunctions.warpProperties(props);let head=$.spawn("div");head.css("border-bottom","grey solid"),head.css("border-width","1px"),ModalFunctions.jqueriefy(headMessage).appendTo(head);let body=$.spawn("div");ModalFunctions.divify(ModalFunctions.jqueriefy(question)).appendTo(body);let input=$.spawn("input");input.css("width","100%"),input.appendTo(body),console.log(input);let footer=$.spawn("div");footer.addClass("modal-button-group"),footer.css("margin-top","5px");let buttonCancel=$.spawn("button");buttonCancel.text("Cancel");let buttonOk=$.spawn("button");buttonOk.text("Ok"),footer.append(buttonCancel),footer.append(buttonOk),input.on("keydown",function(event){13==event.keyCode&&buttonOk.trigger("click")});input.on("keyup",function(){let text=input.val().toString();(!props.maxLength||text.length<=props.maxLength)&&validator(text)?(input.removeClass("invalid_input"),buttonOk.removeAttr("disabled")):(input.hasClass("invalid_input")||input.addClass("invalid_input"),buttonOk.attr("disabled","true"))});let modal,callbackCalled=!1,wrappedCallback=function(flag){callbackCalled||(callbackCalled=!0,callback(flag))};return buttonOk.on("click",()=>{wrappedCallback(input.val().toString()),modal.close()}),buttonCancel.on("click",()=>{wrappedCallback(!1),modal.close()}),props.header=head,props.body=body,props.footer=footer,props.closeListener=(()=>wrappedCallback(!1)),modal=createModal(props)}function createErrorModal(header,message,props={footer:""}){props=ModalFunctions.warpProperties(props);let head=$.spawn("div");return head.addClass("modal-head-error"),ModalFunctions.divify(ModalFunctions.jqueriefy(header)).appendTo(head),props.header=head,props.body=ModalFunctions.divify(ModalFunctions.jqueriefy(message)),props.footer=ModalFunctions.divify(ModalFunctions.jqueriefy("")),createModal(props)}class VoiceActivityDetector{initialise(){}finalize(){}initialiseNewStream(old,_new){}changeHandle(handle,triggerNewStream){const oldStream=this.handle?this.handle.getMicrophoneStream():void 0;this.handle=handle,triggerNewStream&&this.initialiseNewStream(oldStream,handle?handle.getMicrophoneStream():void 0)}}class VoiceRecorder{constructor(handle){this.on_data=(data=>{}),this.on_end=(()=>{}),this._recording=!1,this.microphoneStream=void 0,this.mediaStream=void 0,this._chunkCount=0,this.handle=handle,this.userMedia=navigator.getUserMedia||navigator.webkitGetUserMedia||navigator.mozGetUserMedia,this._deviceId=settings.global("microphone_id","default"),this.audioContext=AudioController.globalContext,this.processor=this.audioContext.createScriptProcessor(VoiceRecorder.BUFFER_SIZE,VoiceRecorder.CHANNELS,VoiceRecorder.CHANNELS),this.processor.addEventListener("audioprocess",ev=>{this.microphoneStream&&this.vadHandler.shouldRecord(ev.inputBuffer)?this.on_data(ev.inputBuffer,0==this._chunkCount++):(0!=this._chunkCount&&this.on_end(),this._chunkCount=0)}),this.mute=this.audioContext.createGain(),this.mute.gain.setValueAtTime(0,0),this.processor.connect(this.mute),this.mute.connect(this.audioContext.destination),this.setVADHander(new PassThroughVAD)}avariable(){return!!this.userMedia}recording(){return this._recording}getMediaStream(){return this.mediaStream}getDestinationContext(){return this.mute}getMicrophoneStream(){return this.microphoneStream}reinitialiseVAD(){let type=settings.global("vad_type","vad");if("ppt"==type){let keyCode=parseInt(settings.global("vad_ppt_key",84..toString()));this.getVADHandler()instanceof PushToTalkVAD?this.getVADHandler().key=keyCode:this.setVADHander(new PushToTalkVAD(keyCode))}else if("pt"==type)this.getVADHandler()instanceof PassThroughVAD||this.setVADHander(new PassThroughVAD);else if("vad"==type){this.getVADHandler()instanceof VoiceActivityDetectorVAD||this.setVADHander(new VoiceActivityDetectorVAD);let threshold=parseInt(settings.global("vad_threshold","50"));this.getVADHandler().percentageThreshold=threshold}else console.warn("Invalid VAD handler! ("+type+")")}setVADHander(handler){this.vadHandler&&(this.vadHandler.changeHandle(null,!0),this.vadHandler.finalize()),this.vadHandler=handler,this.vadHandler.changeHandle(this,!1),this.vadHandler.initialise(),this.vadHandler.initialiseNewStream(void 0,this.microphoneStream)}getVADHandler(){return this.vadHandler}update(flag){this._recording!=flag&&(flag?this.start(this._deviceId):this.stop())}changeDevice(device){this._deviceId!=device&&(this._deviceId=device,settings.changeGlobal("microphone_id",device),this._recording&&(this.stop(),this.start(device)))}start(device){this._deviceId=device,console.log("Attempt recording!"),this._recording=!0,this.userMedia({audio:!0,deviceId:device},this.on_microphone.bind(this),error=>{createErrorModal("Could not resolve microphone!","Could not resolve microphone!<br>Message: "+error).open(),console.error("Could not get microphone!"),console.error(error)})}stop(){console.log("Stop recording!"),this._recording=!1,this.microphoneStream&&this.microphoneStream.disconnect(),this.microphoneStream=void 0,this.mediaStream&&(this.mediaStream.stop?this.mediaStream.stop():this.mediaStream.getTracks().forEach(value=>{value.stop()})),this.mediaStream=void 0}on_microphone(stream){this.microphoneStream&&this.stop(),console.log("Start recording!"),this.mediaStream=stream;const oldStream=this.microphoneStream;this.microphoneStream=this.audioContext.createMediaStreamSource(stream),this.microphoneStream.connect(this.processor),this.vadHandler.initialiseNewStream(oldStream,this.microphoneStream)}}VoiceRecorder.CHANNEL=0,VoiceRecorder.CHANNELS=1,VoiceRecorder.BUFFER_SIZE=1024;class MuteVAD extends VoiceActivityDetector{shouldRecord(buffer){return!1}}class PassThroughVAD extends VoiceActivityDetector{shouldRecord(buffer){return!0}}class VoiceActivityDetectorVAD extends VoiceActivityDetector{constructor(){super(...arguments),this.continuesCount=0,this.maxContinuesCount=12,this.percentageThreshold=50,this.percentage_listener=($=>{})}initialise(){return this.analyzer=AudioController.globalContext.createAnalyser(),this.analyzer.smoothingTimeConstant=1,this.buffer=new Uint8Array(this.analyzer.fftSize),super.initialise()}initialiseNewStream(old,_new){this.analyzer&&this.analyzer.disconnect(),_new&&_new.connect(this.analyzer)}shouldRecord(buffer){let usage=this.calculateUsage();return $.isFunction(this.percentage_listener)&&this.percentage_listener(usage),usage>=this.percentageThreshold?this.continuesCount=0:this.continuesCount++,this.continuesCount<this.maxContinuesCount}calculateUsage(){let float,rms,total=0;this.analyzer.getByteTimeDomainData(this.buffer);for(let index=0;index<this.analyzer.fftSize;index++)total+=(float=this.buffer[index++]/127-1)*float;rms=Math.sqrt(total/this.analyzer.fftSize);let db=Math.log(rms)/Math.log(10)*20;return 100+1.92*(db=Math.max(-192,Math.min(db,0)))}}class PushToTalkVAD extends VoiceActivityDetector{constructor(key){super(),this._pushed=!1,this._evListenerDown=(e=>{e.key==String.fromCharCode(this._key)&&(this.pushed=!0)}),this._evListenerUp=(e=>{e.key==String.fromCharCode(this._key)&&(this.pushed=!1)}),this._key=key}initialise(){return document.addEventListener("keydown",this._evListenerDown),document.addEventListener("keyup",this._evListenerUp),super.initialise()}finalize(){return document.removeEventListener("keydown",this._evListenerDown),document.removeEventListener("keyup",this._evListenerUp),super.finalize()}set pushed(flag){this._pushed=flag}set key(key){this._key=key,this._pushed=!1}shouldRecord(buffer){return this._pushed}}class CodecPoolEntry{}class CodecPool{constructor(handle,index,name,creator){this.entries=[],this.maxInstances=2,this._supported=!0,this.creator=creator,this.handle=handle,this.codecIndex=index,this.name=name}initialize(cached){for(let i=0;i<cached;i++)this.ownCodec(i+1).then(codec=>{console.log("Release again! (%o)",codec),this.releaseCodec(i+1)}).catch(error=>{this._supported&&createErrorModal("Could not load codec driver","Could not load or initialize codec "+this.name+"<br>Error: <code>"+JSON.stringify(error)+"</code>").open(),this._supported=!1,console.error(error)})}supported(){return null!=this.creator&&this._supported}ownCodec(clientId,create=!0){return new Promise((resolve,reject)=>{if(!this.creator||!this._supported)return void reject("unsupported codec!");let freeSlot=0;for(let index=0;index<this.entries.length;index++){if(this.entries[index].owner==clientId)return this.entries[index].last_access=(new Date).getTime(),void(this.entries[index].instance.initialized()?resolve(this.entries[index].instance):this.entries[index].instance.initialise().then(flag=>{console.error(flag),this.ownCodec(clientId,!1).then(resolve).catch(reject)}).catch(error=>{console.error("Could not initialize codec!\nError: %o",error),reject("Could not initialize codec!")}));0==freeSlot&&0==this.entries[index].owner&&(freeSlot=index)}if(create){if(0==freeSlot){freeSlot=this.entries.length;let entry=new CodecPoolEntry;entry.instance=this.creator(),entry.instance.on_encoded_data=(buffer=>this.handle.sendVoicePacket(buffer,this.codecIndex)),this.entries.push(entry)}this.entries[freeSlot].owner=clientId,this.entries[freeSlot].last_access=(new Date).getTime(),this.entries[freeSlot].instance.initialized()?(this.entries[freeSlot].instance.reset(),resolve(this.entries[freeSlot].instance)):this.ownCodec(clientId,!1).then(resolve).catch(reject)}else resolve(void 0)})}releaseCodec(clientId){for(let index=0;index<this.entries.length;index++)this.entries[index].owner==clientId&&(this.entries[index].owner=0)}}class VoiceConnection{constructor(client){this.codecPool=[new CodecPool(this,0,"Spex A",void 0),new CodecPool(this,1,"Spex B",void 0),new CodecPool(this,2,"Spex C",void 0),new CodecPool(this,3,"CELT Mono",void 0),new CodecPool(this,4,"Opus Voice",()=>new CodecWrapper(CodecWorkerType.WORKER_OPUS,1)),new CodecPool(this,5,"Opus Music",()=>new CodecWrapper(CodecWorkerType.WORKER_OPUS,2))],this.vpacketId=0,this.chunkVPacketId=0,this.client=client,this.voiceRecorder=new VoiceRecorder(this),this.voiceRecorder.on_data=this.handleVoiceData.bind(this),this.voiceRecorder.on_end=this.handleVoiceEnded.bind(this),this.voiceRecorder.reinitialiseVAD(),this.codecPool[4].initialize(2),this.codecPool[5].initialize(2)}codecSupported(type){return this.codecPool.length>type&&this.codecPool[type].supported()}sendVoicePacket(data,codec){if(this.dataChannel){this.vpacketId++,this.vpacketId>65535&&(this.vpacketId=0);let packet=new Uint8Array(data.byteLength+2+3);packet[0]=this.chunkVPacketId++<5?1:0,packet[1]=0,packet[2]=this.vpacketId>>8&255,packet[3]=this.vpacketId>>0&255,packet[4]=codec,packet.set(data,5),this.dataChannel.send(packet)}else console.warn("Could not transfer audio (not connected)")}createSession(){this.rtcPeerConnection=new RTCPeerConnection({});this.dataChannel=this.rtcPeerConnection.createDataChannel("main",{ordered:!1,maxRetransmits:0}),this.dataChannel.onmessage=this.onDataChannelMessage.bind(this),this.dataChannel.onopen=this.onDataChannelOpen.bind(this),this.dataChannel.binaryType="arraybuffer";let sdpConstraints={offerToReceiveAudio:0,offerToReceiveVideo:0};this.rtcPeerConnection.onicecandidate=this.onIceCandidate.bind(this),this.rtcPeerConnection.createOffer(this.onOfferCreated.bind(this),()=>{console.error("Could not create ice offer!")},sdpConstraints)}dropSession(){this.dataChannel&&this.dataChannel.close(),this.rtcPeerConnection&&this.rtcPeerConnection.close()}handleControlPacket(json){"create"===json.request?this.rtcPeerConnection.setRemoteDescription(new RTCSessionDescription({type:"answer",sdp:json.sdp})):"ice"===json.request&&this.rtcPeerConnection.addIceCandidate(new RTCIceCandidate({candidate:json.candidate,sdpMid:json.session,sdpMLineIndex:json.line}))}onIceCandidate(event){console.log("Got ice candidate! Event:"),console.log(event),event&&event.candidate&&this.client.serverConnection.sendData(JSON.stringify({type:"WebRTC",request:"ice",candidate:event.candidate.candidate,line:event.candidate.sdpMLineIndex,session:event.candidate.sdpMid}))}onOfferCreated(localSession){console.log("Offer created and accepted"),this.rtcPeerConnection.setLocalDescription(localSession),this.client.serverConnection.sendData(JSON.stringify({type:"WebRTC",request:"create",session:localSession}))}onDataChannelOpen(channel){console.log("Got new data channel!")}onDataChannelMessage(message){if(this.client.controlBar.muteOutput)return;let bin=new Uint8Array(message.data),clientId=bin[2]<<8|bin[3],codec=(bin[0],bin[1],bin[4]),client=this.client.channelTree.findClient(clientId);if(!client)return void console.error("Having voice from unknown client? (ClientID: "+clientId+")");let encodedData,codecPool=this.codecPool[codec];codecPool?0==(encodedData=message.data.subarray?message.data.subarray(5):new Uint8Array(message.data,5)).length?(client.getAudioController().stopAudio(),codecPool.releaseCodec(clientId)):codecPool.ownCodec(clientId).then(decoder=>decoder.decodeSamples(client.getAudioController().codecCache(codec),encodedData)).then(buffer=>client.getAudioController().playBuffer(buffer)).catch(error=>{console.error("Could not playback client's ("+clientId+") audio ("+error+")")}):console.error("Could not playback codec "+codec)}handleVoiceData(data,head){if(this.voiceRecorder)return!!this.client.connected&&void(this.client.controlBar.muteInput||(head&&(this.chunkVPacketId=0,this.client.getClient().speaking=!0),this.codecPool[4].ownCodec(this.client.getClientId()).then(encoder=>encoder.encodeSamples(this.client.getClient().getAudioController().codecCache(4),data))))}handleVoiceEnded(){this.voiceRecorder&&(console.log("Voice ended"),this.client.getClient().speaking=!1,this.sendVoicePacket(new Uint8Array(0),4))}}$(document).bind("mousedown",function(e){0==$(e.target).parents(".contextMenu").length&&despawnContextMenu()});let contextMenuCloseFn=void 0;function despawnContextMenu(){let menue=$(".contextMenu");menue.is(":visible")&&(menue.hide(100),contextMenuCloseFn&&contextMenuCloseFn())}var MenuEntryType,sha,helpers,ChannelType,PermissionType,GroupType,GroupTarget;!function(MenuEntryType){MenuEntryType[MenuEntryType.CLOSE=0]="CLOSE",MenuEntryType[MenuEntryType.ENTRY=1]="ENTRY",MenuEntryType[MenuEntryType.HR=2]="HR",MenuEntryType[MenuEntryType.EMPTY=3]="EMPTY"}(MenuEntryType||(MenuEntryType={}));class MenuEntry{static HR(){return{callback:()=>{},type:MenuEntryType.HR,name:"",icon:""}}static EMPTY(){return{callback:()=>{},type:MenuEntryType.EMPTY,name:"",icon:""}}static CLOSE(callback){return{callback:callback,type:MenuEntryType.EMPTY,name:"",icon:""}}}function spawnMenu(x,y,...entries){const menu=$("#contextMenu");menu.empty(),menu.hide(),contextMenuCloseFn=void 0;for(let entry of entries)if(entry.type==MenuEntryType.HR)menu.append("<hr>");else if(entry.type==MenuEntryType.CLOSE)contextMenuCloseFn=entry.callback;else if(entry.type==MenuEntryType.ENTRY){let icon=$.isFunction(entry.icon)?entry.icon():entry.icon;icon=0==icon.length?"icon_empty":"icon "+icon;let tag=$.spawn("li");tag.append("<div class='"+icon+"'></div>"),tag.append("<div>"+($.isFunction(entry.name)?entry.name():entry.name)+"</div>"),menu.append(tag),entry.disabled||entry.invalidPermission?tag.addClass("disabled"):tag.click(function(){$.isFunction(entry.callback)&&entry.callback(),despawnContextMenu()})}menu.show(100),menu.css({top:y+"px",left:x+"px"})}!function(sha){sha.sha1=function(message){let buffer=message instanceof ArrayBuffer?message:(new TextEncoder).encode(message);return crypto.subtle.digest("SHA-1",buffer)}}(sha||(sha={})),function(helpers){helpers.hashPassword=function(password){return new Promise((resolve,reject)=>{sha.sha1(password).then(result=>{resolve(btoa(String.fromCharCode.apply(null,new Uint8Array(result))))})})}}(helpers||(helpers={})),function(ChannelType){ChannelType[ChannelType.PERMANENT=0]="PERMANENT",ChannelType[ChannelType.SEMI_PERMANENT=1]="SEMI_PERMANENT",ChannelType[ChannelType.TEMPORARY=2]="TEMPORARY"}(ChannelType||(ChannelType={})),function(ChannelType){ChannelType.normalize=function(mode){let value=ChannelType[mode];return(value=value.toLowerCase())[0].toUpperCase()+value.substr(1)}}(ChannelType||(ChannelType={}));class ChannelProperties{constructor(){this.channel_order=0,this.channel_name="",this.channel_topic="",this.channel_password="",this.channel_description="",this.channel_codec=4,this.channel_codec_quality=0,this.channel_codec_is_unencrypted=!1,this.channel_maxclients=-1,this.channel_maxfamilyclients=-1,this.channel_needed_talk_power=1,this.channel_flag_permanent=!1,this.channel_flag_semi_permanent=!1,this.channel_flag_default=!1,this.channel_flag_password=!1,this.channel_flag_maxclients_unlimited=!1,this.channel_flag_maxfamilyclients_inherited=!1,this.channel_flag_maxfamilyclients_unlimited=!1}}class ChannelEntry{constructor(channelId,channelName,parent=null,prevChannel=null){this.properties=new ChannelProperties,this.properties=new ChannelProperties,this.channelId=channelId,this._formatedChannelName=channelName,this.parent=parent,this.prevChannel=prevChannel,this.channelTree=null,this.initializeTag(),this.__updateChannelName()}channelName(){return this.properties.channel_name}formatedChannelName(){return this._formatedChannelName?this._formatedChannelName:this.properties.channel_name}parentChannel(){return this.parent}hasParent(){return null!=this.parent}getChannelId(){return this.channelId}channelClass(){return"channel_full"}siblings(deep=!1){const result=[];if(null==this.channelTree)return[];const self=this;return this.channelTree.channels.forEach(function(entry){let current=entry;if(deep)for(;current;){if(current.parentChannel()==self){result.push(entry);break}current=current.parentChannel()}else current.parentChannel()==self&&result.push(entry)}),result}clients(deep=!1){const result=[];if(null==this.channelTree)return[];const self=this;return this.channelTree.clients.forEach(function(entry){let current=entry.currentChannel();if(deep)for(;current;){if(current.parentChannel()==self){result.push(entry);break}current=current.parentChannel()}else current==self&&result.push(entry)}),result}initializeTag(){let rootTag=$.spawn("div");rootTag.attr("id","channel_"+this.getChannelId()),rootTag.addClass("channel"),this._tag_channel=$.spawn("div"),this._tag_channel.addClass("channelLine"),this._tag_channel.addClass(this._channelAlign);let channelType=$.spawn("div");channelType.addClass("channel_only_normal channel_type icon client-channel_green_subscribed"),this._tag_channel.append(channelType),this._tag_channel.append($.spawn("div").addClass("channel_name_container").append($.spawn("a").addClass("channel_name").text(this.channelName())));let iconTag=$.spawn("span").addClass("icons");iconTag.appendTo(this._tag_channel),iconTag.append($.spawn("div").addClass("channel_only_normal").append($.spawn("div").addClass("icon_entry icon_default icon client-channel_default").attr("title","Default channel"))),iconTag.append($.spawn("div").addClass("channel_only_normal").append($.spawn("div").addClass("icon_entry icon_password icon client-register").attr("title","The channel is password protected"))),iconTag.append($.spawn("div").addClass("channel_only_normal").append($.spawn("div").addClass("icon_entry icon_music icon client-music").attr("title","Music quality"))),iconTag.append($.spawn("div").addClass("channel_only_normal").addClass("icon_entry channel_icon").attr("title","Channel icon"));let container=$.spawn("div"),noSound=$.spawn("div").addClass("icon_entry icon_no_sound icon client-conflict-icon").attr("title","You don't support the channel codec");$.spawn("div").width(10).height(14).css("background","red").css("position","absolute").css("top","1px").css("left","3px").appendTo(container),noSound.appendTo(container),iconTag.append(container),this._tag_siblings=$.spawn("div").addClass("siblings");let tag_siblings_box=$.spawn("div").css("position","absolute").css("width","calc(100% - 16px)").css("margin","0px");this._tag_siblings.appendTo(tag_siblings_box),this._tag_clients=$.spawn("div").addClass("clients");let tag_clients_box=$.spawn("div").css("position","absolute").css("width","calc(100% - 16px)").css("margin","0px");this._tag_clients.appendTo(tag_clients_box),this._tag_root=rootTag,tag_clients_box.appendTo(this._tag_root),tag_siblings_box.appendTo(this._tag_root),this._tag_channel.appendTo(this._tag_root)}rootTag(){return this._tag_root}channelTag(){return this._tag_channel}siblingTag(){return this._tag_siblings}clientTag(){return this._tag_clients}adjustSize(parent=!0){const size=this.originalHeight;let subSize=0,clientSize=0;this.siblings(!1).forEach(function(e){subSize+=e.rootTag().outerHeight(!0)}),this.clients(!1).forEach(function(e){clientSize+=e.tag.outerHeight(!0)}),this._tag_root.css({height:size+subSize+clientSize}),this._tag_siblings.css("margin-top",clientSize+16+"px"),this._tag_clients.css({height:clientSize}),parent&&this.parentChannel()&&this.parentChannel().adjustSize(parent)}initializeListener(){const _this=this;this.channelTag().click(function(){_this.channelTree.onSelect(_this)}),this.channelTag().dblclick(()=>this.joinChannel()),settings.static(Settings.KEY_DISABLE_CONTEXT_MENU,!1)||this.channelTag().on("contextmenu",function(event){event.preventDefault(),_this.channelTree.onSelect(_this),_this.showContextMenu(event.pageX,event.pageY,()=>{_this.channelTree.onSelect(void 0)})})}showContextMenu(x,y,on_close){let channelCreate=this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_CREATE_TEMPORARY).granted(1)||this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_CREATE_SEMI_PERMANENT).granted(1)||this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_CREATE_PERMANENT).granted(1),channelModify=this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_MODIFY_MAKE_DEFAULT).granted(1)||this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_MODIFY_MAKE_PERMANENT).granted(1)||this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_MODIFY_MAKE_SEMI_PERMANENT).granted(1)||this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_MODIFY_MAKE_TEMPORARY).granted(1)||this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_MODIFY_NAME).granted(1)||this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_MODIFY_TOPIC).granted(1)||this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_MODIFY_DESCRIPTION).granted(1)||this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_MODIFY_PASSWORD).granted(1)||this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_MODIFY_CODEC).granted(1)||this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_MODIFY_CODEC_QUALITY).granted(1)||this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_MODIFY_CODEC_LATENCY_FACTOR).granted(1)||this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_MODIFY_MAXCLIENTS).granted(1)||this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_MODIFY_MAXFAMILYCLIENTS).granted(1)||this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_MODIFY_SORTORDER).granted(1)||this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_MODIFY_NEEDED_TALK_POWER).granted(1)||this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_MODIFY_MAKE_CODEC_ENCRYPTED).granted(1)||this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_MODIFY_TEMP_DELETE_DELAY).granted(1)||this.channelTree.client.permissions.neededPermission(PermissionType.B_ICON_MANAGE).granted(1),flagDelete=!0;this.clients(!0).length>0&&(flagDelete=this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_DELETE_FLAG_FORCE).granted(1)),flagDelete&&(flagDelete=this.properties.channel_flag_permanent?this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_DELETE_PERMANENT).granted(1):this.properties.channel_flag_semi_permanent?this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_DELETE_PERMANENT).granted(1):this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_DELETE_TEMPORARY).granted(1)),spawnMenu(x,y,{type:MenuEntryType.ENTRY,icon:"client-channel_switch",name:"<b>Switch to channel</b>",callback:()=>{this.joinChannel()}},MenuEntry.HR(),{type:MenuEntryType.ENTRY,icon:"client-channel_edit",name:"Edit channel",invalidPermission:!channelModify,callback:()=>{Modals.createChannelModal(this,void 0,changes=>{changes&&(changes.cid=this.channelId,log.info(LogCategory.CHANNEL,"Changed channel properties of channel %s: %o",this.channelName(),changes))})}},{type:MenuEntryType.ENTRY,icon:"client-channel_delete",name:"Delete channel",invalidPermission:!flagDelete,callback:()=>this.channelTree.client.serverConnection.sendCommand("channeldelete",{cid:this.channelId})},MenuEntry.HR(),{type:MenuEntryType.ENTRY,icon:"client-channel_create_sub",name:"Create sub channel",invalidPermission:!(channelCreate&&this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_CREATE_CHILD).granted(1)),callback:()=>this.channelTree.spawnCreateChannel(this)},{type:MenuEntryType.ENTRY,icon:"client-channel_create",name:"Create channel",invalidPermission:!channelCreate,callback:()=>this.channelTree.spawnCreateChannel()},MenuEntry.CLOSE(on_close))}__updateChannelName(){this._formatedChannelName=void 0;parseType:if(null==this.parentChannel()&&"["==this.properties.channel_name.charAt(0)){let end=this.properties.channel_name.indexOf("]");if(-1==end)break parseType;let options=this.properties.channel_name.substr(1,end-1);if(-1==options.indexOf("spacer"))break parseType;if(options=options.substr(0,options.indexOf("spacer")),console.log("Channel options: '"+options+"'"),0==options.length?options="l":options.length>1&&(options=options[0]),"r"!=options&&"l"!=options&&"c"!=options&&"*"!=options)break parseType;this._channelAlign=options,this._formatedChannelName=this.properties.channel_name.substr(end+1),console.log("Got channel name: "+this._formatedChannelName)}let self=this.channelTag(),channelName=self.find(".channel_name");if(channelName.text(this.formatedChannelName()),channelName.parent().removeClass("l r c *"),(this._formatedChannelName?$.fn.hide:$.fn.show).apply(self.find(".channel_only_normal")),this._formatedChannelName&&(channelName.parent().addClass(this._channelAlign),"*"==this._channelAlign)){let lastSuccess="",index=0;do{channelName.text((lastSuccess=channelName.text())+this.formatedChannelName()),console.log(channelName.parent().width()+" : "+channelName.width()+" : "+channelName.innerWidth()+" : "+channelName.outerWidth())}while(channelName.parent().width()>=channelName.width()&&++index<255);255==index&&console.warn(LogCategory.CHANNEL,"Repeating spacer took too much repeats!"),lastSuccess.length>0&&(channelName.text(lastSuccess),self.addClass("c"))}console.log("Align: "+this._channelAlign)}updateVariables(...variables){let group=log.group(log.LogType.DEBUG,LogCategory.CHANNEL,"Update properties (%i) of %s (%i)",variables.length,this.channelName(),this.getChannelId());for(let variable of variables){let key=variable.key,value=variable.value;if("number"==typeof this.properties[key]&&(this.properties[key]=parseInt(value)),"boolean"==typeof this.properties[key]?this.properties[key]="true"==value||"1"==value:this.properties[key]=value,group.log("Updating property "+key+" = '%s' -> %o",value,this.properties[key]),"channel_name"==key)this.__updateChannelName();else if("channel_order"==key){let order=this.channelTree.findChannel(this.properties.channel_order);this.channelTree.moveChannel(this,order,this.parent)}else if("channel_icon_id"==key){let tag=this.channelTag().find(".icons .channel_icon");(this.properties.channel_icon_id>0?$.fn.show:$.fn.hide).apply(tag),this.properties.channel_icon_id>0&&(tag.children().detach(),this.channelTree.client.fileManager.icons.generateTag(this.properties.channel_icon_id).appendTo(tag))}else"channel_codec"==key?((5==this.properties.channel_codec||3==this.properties.channel_codec?$.fn.show:$.fn.hide).apply(this.channelTag().find(".icons .icon_music")),(this.channelTree.client.voiceConnection.codecSupported(this.properties.channel_codec)?$.fn.hide:$.fn.show).apply(this.channelTag().find(".icons .icon_no_sound"))):"channel_flag_default"==key?(this.properties.channel_flag_default?$.fn.show:$.fn.hide).apply(this.channelTag().find(".icons .icon_default")):"channel_flag_password"==key&&(this.properties.channel_flag_password?$.fn.show:$.fn.hide).apply(this.channelTag().find(".icons .icon_password"));"channel_maxclients"!=key&&"channel_maxfamilyclients"!=key&&"channel_flag_private"!=key&&"channel_flag_password"!=key||this.updateChannelTypeIcon()}group.end()}updateChannelTypeIcon(){let type,tag=this.channelTag().find(".channel_type");tag.removeAttr("class"),tag.addClass("channel_only_normal channel_type icon"),type=1!=this.properties.channel_flag_password||this._cachedPassword?!this.properties.channel_flag_maxclients_unlimited&&this.clients().length>=this.properties.channel_maxclients||!this.properties.channel_flag_maxfamilyclients_unlimited&&this.properties.channel_maxfamilyclients>=0&&this.clients(!0).length>=this.properties.channel_maxfamilyclients?"red":"green":"yellow",tag.addClass("client-channel_"+type+"_subscribed")}createChatTag(braces=!1){let tag=$.spawn("div");return tag.css("display","table"),tag.css("cursor","pointer"),tag.css("font-weight","bold"),tag.css("color","darkblue"),braces?tag.text('"'+this.channelName()+'"'):tag.text(this.channelName()),tag.attr("oncontextmenu","chat_channel_contextmenu(this, ...arguments);"),tag.attr("channelId",this.channelId),tag.attr("channelName",this.channelName()),tag.wrap("<p/>").parent()}channelType(){return 1==this.properties.channel_flag_permanent?ChannelType.PERMANENT:1==this.properties.channel_flag_semi_permanent?ChannelType.SEMI_PERMANENT:ChannelType.TEMPORARY}joinChannel(){1!=this.properties.channel_flag_password||this._cachedPassword||this.channelTree.client.permissions.neededPermission(PermissionType.B_CHANNEL_JOIN_IGNORE_PASSWORD).granted(1)?this.channelTree.client.getServerConnection().joinChannel(this,this._cachedPassword).catch(error=>{error instanceof CommandResult&&781==error.id&&(this._cachedPassword=void 0,this.updateChannelTypeIcon())}):createInputModal("Channel password","Channel password:",()=>!0,text=>{typeof text!=typeof!0&&helpers.hashPassword(text).then(result=>{this._cachedPassword=result,this.joinChannel(),this.updateChannelTypeIcon()})}).open()}}function chat_channel_contextmenu(_element,event){event.preventDefault();let element=$(_element);console.log("Context menue for "+element.attr("channelName"));let chid=Number.parseInt(element.attr("channelId")),channel=globalClient.channelTree.findChannel(chid);channel&&channel.showContextMenu(event.pageX,event.pageY)}!function(Modals){Modals.spawnChangeVolume=function(current,callback){let updateCallback;const connectModal=createModal({header:function(){let header=$.spawn("div");return header.text("Change volume"),header},body:function(){let tag=$("#tmpl_change_volume").tmpl();return tag.find(".volume_slider").on("change",_=>updateCallback(tag.find(".volume_slider").val())),tag.find(".volume_slider").on("input",_=>updateCallback(tag.find(".volume_slider").val())),tag},footer:function(){let tag=$.spawn("div");tag.css("text-align","right"),tag.css("margin-top","3px"),tag.css("margin-bottom","6px"),tag.addClass("modal-button-group");let buttonReset=$.spawn("button");buttonReset.text("Reset"),buttonReset.on("click",function(){updateCallback(100)}),tag.append(buttonReset);let buttonCancel=$.spawn("button");buttonCancel.text("Cancel"),buttonCancel.on("click",function(){updateCallback(100*current),connectModal.close()}),tag.append(buttonCancel);let buttonOk=$.spawn("button");return buttonOk.text("OK"),buttonOk.on("click",function(){connectModal.close()}),tag.append(buttonOk),tag},width:600});updateCallback=(value=>{connectModal.htmlTag.find(".volume_slider").val(value);let number=value-100;connectModal.htmlTag.find(".display_volume").html((0==number?"±":number>0?"+":"")+number+" %"),callback(value/100)}),connectModal.open(),updateCallback(100*current)}}(Modals||(Modals={}));class ClientProperties{constructor(){this.client_version="",this.client_platform="",this.client_nickname="unknown",this.client_unique_identifier="unknown",this.client_description="",this.client_servergroups="",this.client_channel_group_id=0,this.client_lastconnected=0,this.client_flag_avatar="",this.client_output_muted=!1,this.client_away_message="",this.client_away=!1,this.client_input_hardware=!1,this.client_input_muted=!1,this.client_is_channel_commander=!1}}class ClientEntry{constructor(clientId,clientName){this.properties=new ClientProperties,this.lastVariableUpdate=0,this._speaking=!1,this._clientId=clientId,this.properties.client_nickname=clientName,this.channelTree=null,this._channel=null,this.audioController=new AudioController;const _this=this;this.audioController.onSpeaking=function(){_this.speaking=!0},this.audioController.onSilence=function(){_this.speaking=!1},this.audioController.initialize()}currentChannel(){return this._channel}clientNickName(){return this.properties.client_nickname}clientUid(){return this.properties.client_unique_identifier}clientId(){return this._clientId}getAudioController(){return this.audioController}initializeListener(){const _this=this;this.tag.click(event=>{_this.channelTree.onSelect(_this)}),settings.static(Settings.KEY_DISABLE_CONTEXT_MENU,!1)||this.tag.on("contextmenu",function(event){return event.preventDefault(),_this.channelTree.onSelect(_this),_this.showContextMenu(event.pageX,event.pageY,()=>{_this.channelTree.onSelect(void 0)}),!1})}showContextMenu(x,y,on_close){const _this=this;spawnMenu(x,y,{type:MenuEntryType.ENTRY,icon:"client-change_nickname",name:"<b>Open text chat</b>",callback:function(){chat.activeChat=_this.chat(!0),chat.focus()}},{type:MenuEntryType.ENTRY,icon:"client-poke",name:"Poke client",callback:function(){createInputModal("Poke client","Poke message:<br>",text=>!0,result=>{result&&(console.log("Poking client "+_this.clientNickName()+" with message "+result),_this.channelTree.client.serverConnection.sendCommand("clientpoke",{clid:_this.clientId(),msg:result}))},{width:400,maxLength:512}).open()}},{type:MenuEntryType.ENTRY,icon:"client-edit",name:"Change description",callback:function(){createInputModal("Change client description","New description:<br>",text=>!0,result=>{result&&(console.log("Changing "+_this.clientNickName()+"'s description to "+result),_this.channelTree.client.serverConnection.sendCommand("clientedit",{clid:_this.clientId(),client_description:result}))},{width:400,maxLength:1024}).open()}},MenuEntry.HR(),{type:MenuEntryType.ENTRY,icon:"client-move_client_to_own_channel",name:"Move client to your channel",callback:()=>{this.channelTree.client.serverConnection.sendCommand("clientmove",{clid:this.clientId(),cid:this.channelTree.client.getClient().currentChannel().getChannelId()})}},{type:MenuEntryType.ENTRY,icon:"client-kick_channel",name:"Kick client from channel",callback:function(){createInputModal("Kick client from channel","Kick reason:<br>",text=>!0,result=>{result&&(console.log("Kicking client "+_this.clientNickName()+" from channel with reason "+result),_this.channelTree.client.serverConnection.sendCommand("clientkick",{clid:_this.clientId(),reasonid:ViewReasonId.VREASON_CHANNEL_KICK,reasonmsg:result}))},{width:400,maxLength:255}).open()}},{type:MenuEntryType.ENTRY,icon:"client-kick_server",name:"Kick client fom server",callback:function(){createInputModal("Kick client from server","Kick reason:<br>",text=>!0,result=>{result&&(console.log("Kicking client "+_this.clientNickName()+" from server with reason "+result),_this.channelTree.client.serverConnection.sendCommand("clientkick",{clid:_this.clientId(),reasonid:ViewReasonId.VREASON_SERVER_KICK,reasonmsg:result}))},{width:400,maxLength:255}).open()}},{type:MenuEntryType.ENTRY,icon:"client-ban_client",name:"Ban client",disabled:!0,callback:()=>{}},MenuEntry.HR(),{type:MenuEntryType.ENTRY,icon:"client-volume",name:"Change Volume",callback:()=>{Modals.spawnChangeVolume(this.audioController.volume,volume=>{settings.changeServer("volume_client_"+this.clientUid(),volume),this.audioController.volume=volume,globalClient.selectInfo.currentSelected==this&&globalClient.selectInfo.update()})}},MenuEntry.CLOSE(on_close))}get tag(){if(this._tag)return this._tag;let tag=$.spawn("div");tag.attr("id","client_"+this.clientId()),tag.addClass("client"),tag.append($.spawn("div").addClass("icon_empty")),tag.append($.spawn("div").addClass("icon_client_state").attr("title","Client state")),tag.append($.spawn("div").addClass("name").text(this.clientNickName())),tag.append($.spawn("div").addClass("away").text(this.clientNickName()));let clientIcons=$.spawn("span");return tag.append(clientIcons),this._tag=tag}static chatTag(id,name,uid,braces=!1){let tag=$.spawn("div");return tag.css("cursor","pointer"),tag.css("font-weight","bold"),tag.css("color","darkblue"),tag.css("display","table"),braces?tag.text('"'+name+'"'):tag.text(name),tag.attr("oncontextmenu","chat_client_contextmenu(this, ...arguments);"),tag.attr("clientId",id),tag.attr("clientUid",uid),tag.attr("clientName",name),tag.wrap("<p/>").parent()}createChatTag(braces=!1){return ClientEntry.chatTag(this.clientId(),this.clientNickName(),this.clientUid(),braces)}set speaking(flag){flag!=this._speaking&&(this._speaking=flag,this.updateClientIcon())}updateClientIcon(){let icon="",clicon="";this.properties.client_away?icon="client-away":this.properties.client_output_muted?icon="client-hardware_output_muted":this.properties.client_input_hardware?this.properties.client_input_muted?icon="client-input_muted":clicon=this._speaking?this.properties.client_is_channel_commander?"client_cc_talk":"client_talk":this.properties.client_is_channel_commander?"client_cc_idle":"client_idle":icon="client-hardware_input_muted",clicon.length>0?this.tag.find(".icon_client_state").attr("class","icon_client_state clicon "+clicon):icon.length>0?this.tag.find(".icon_client_state").attr("class","icon_client_state icon "+icon):this.tag.find(".icon_client_state").attr("class","icon_client_state icon_empty")}updateAwayMessage(){let tag=this.tag.find(".away");1==this.properties.client_away&&this.properties.client_away_message?(tag.text("["+this.properties.client_away_message+"]"),tag.show()):tag.hide()}updateVariables(...variables){let group=log.group(log.LogType.DEBUG,LogCategory.CLIENT,"Update properties (%i) of %s (%i)",variables.length,this.clientNickName(),this.clientId());for(let variable of variables){if("boolean"==typeof this.properties[variable.key]?this.properties[variable.key]="true"==variable.value||"1"==variable.value:"number"==typeof this.properties[variable.key]?this.properties[variable.key]=parseInt(variable.value):this.properties[variable.key]=variable.value,group.log("Updating client "+this.clientId()+". Key "+variable.key+" Value: '"+variable.value+"' ("+typeof this.properties[variable.key]+")"),"client_nickname"==variable.key){this.tag.find(".name").text(variable.value);let chat=this.chat(!1);chat&&(chat.name=variable.value)}"client_away"!=variable.key&&"client_output_muted"!=variable.key&&"client_input_hardware"!=variable.key&&"client_input_muted"!=variable.key&&"client_is_channel_commander"!=variable.key||this.updateClientIcon(),"client_away_message"!=variable.key&&"client_away"!=variable.key||this.updateAwayMessage(),"client_unique_identifier"==variable.key&&(this.audioController.volume=parseFloat(settings.server("volume_client_"+this.clientUid(),"1")),console.error("Updated volume from config "+this.audioController.volume+" - volume_client_"+this.clientUid()+" - "+settings.server("volume_client_"+this.clientUid(),"1")),console.log(this.avatarId()))}group.end()}updateClientVariables(){(0==this.lastVariableUpdate||(new Date).getTime()-6e5>this.lastVariableUpdate)&&(this.lastVariableUpdate=(new Date).getTime(),this.channelTree.client.serverConnection.sendCommand("clientgetvariables",{clid:this.clientId()}))}chat(create=!1){let chatName="client_"+this.clientUid()+":"+this.clientId(),c=chat.findChat(chatName);if(!c&&create){(c=chat.createChat(chatName)).closeable=!0,c.name=this.clientNickName();const _this=this;c.onMessageSend=function(text){_this.channelTree.client.serverConnection.sendMessage(text,ChatType.CLIENT,_this)},c.onClose=function(){return _this.channelTree.client.serverConnection.sendCommand("clientchatclosed",{clid:_this.clientId()}),!0}}return c}updateGroupIcon(group){this.tag.find(".icon_group_"+group.id).detach(),group.properties.iconid>0&&this.tag.find("span").append(this.channelTree.client.fileManager.icons.generateTag(group.properties.iconid).addClass("icon_group_"+group.id))}assignedServerGroupIds(){let result=[];for(let id of this.properties.client_servergroups.split(","))0!=id.length&&result.push(Number.parseInt(id));return result}assignedChannelGroup(){return this.properties.client_channel_group_id}groupAssigned(group){if(group.target==GroupTarget.SERVER){for(let id of this.assignedServerGroupIds())if(id==group.id)return!0;return!1}return group.id==this.assignedChannelGroup()}onDelete(){this.audioController.close(),this.audioController=void 0}calculateOnlineTime(){return(new Date).getTime()/1e3-this.properties.client_lastconnected}avatarId(){try{let raw=atob(this.properties.client_unique_identifier),input=hex.encode(function(str){let buf=new ArrayBuffer(str.length),bufView=new Uint8Array(buf);for(let i=0,strLen=str.length;i<strLen;i++)bufView[i]=str.charCodeAt(i);return buf}(raw)),result="";for(let index=0;index<input.length;index++){let c=input.charAt(index),offset=0;c>="0"&&c<="9"?offset=c.charCodeAt(0)-"0".charCodeAt(0):c>="A"&&c<="F"?offset=c.charCodeAt(0)-"A".charCodeAt(0)+10:c>="a"&&c<="f"&&(offset=c.charCodeAt(0)-"a".charCodeAt(0)+10),result+=String.fromCharCode("a".charCodeAt(0)+offset)}return result}catch(e){return}}}class LocalClientEntry extends ClientEntry{constructor(handle){super(0,"local client"),this.handle=handle}showContextMenu(x,y,on_close){const _self=this;spawnMenu(x,y,{name:"<b>Change name</b>",icon:"client-change_nickname",callback:()=>_self.openRename(),type:MenuEntryType.ENTRY},{name:"Change description",icon:"client-edit",callback:()=>{createInputModal("Change own description","New description:<br>",text=>!0,result=>{result&&(console.log("Changing own description to "+result),_self.channelTree.client.serverConnection.sendCommand("clientedit",{clid:_self.clientId(),client_description:result}))},{width:400,maxLength:1024}).open()},type:MenuEntryType.ENTRY},MenuEntry.CLOSE(on_close))}initializeListener(){super.initializeListener(),this.tag.find(".name").addClass("own_name");const _self=this;this.tag.dblclick(function(){_self.openRename()})}openRename(){const _self=this,elm=this.tag.find(".name");elm.attr("contenteditable","true"),elm.removeClass("own_name"),elm.css("background-color","white"),elm.focus(),_self.renaming=!0,elm.keypress(function(e){if(13==e.keyCode)return $(this).trigger("focusout"),!1}),elm.focusout(function(e){if(!_self.renaming)return;_self.renaming=!1,elm.css("background-color",""),elm.removeAttr("contenteditable"),elm.addClass("own_name");let text=elm.text().toString();_self.clientNickName()!=text&&(elm.text(_self.clientNickName()),_self.handle.serverConnection.updateClient("client_nickname",text).then(e=>{chat.serverChat().appendMessage("Nickname successfully changed")}).catch(e=>{chat.serverChat().appendError("Could not change nickname ("+e.extra_message+")"),_self.openRename()}))})}}function chat_client_contextmenu(_element,event){event.preventDefault();let element=$(_element);console.log("Context menue for "+element.attr("clientName"));let clid=Number.parseInt(element.attr("clientId")),client=globalClient.channelTree.findClient(clid);client&&client.clientUid()==element.attr("clientUid")&&client.showContextMenu(event.pageX,event.pageY)}!function(Modals){Modals.createChannelModal=function(channel,parent,callback){let properties={};const modal=createModal({header:channel?"Edit channel":"Create channel",body:()=>{let template=$("#tmpl_channel_edit").tmpl(channel?channel.properties:new ChannelProperties);return(template=$.spawn("div").append(template)).tabify()},footer:()=>{let footer=$.spawn("div");footer.addClass("modal-button-group"),footer.css("margin","5px");let buttonCancel=$.spawn("button");buttonCancel.text("Cancel").addClass("button_cancel");let buttonOk=$.spawn("button");return buttonOk.text("Ok").addClass("button_ok"),footer.append(buttonCancel),footer.append(buttonOk),footer},width:500});!function(properties,tag,button,create){let updateButton=()=>{0==tag.find(".input_error").length?button.removeAttr("disabled"):button.attr("disabled","true")};tag.find(".channel_name").change(function(){properties.channel_name=this.value,$(this).removeClass("input_error"),(this.value.length<1||this.value.length>40)&&$(this).addClass("input_error"),updateButton()}).prop("disabled",!create&&!globalClient.permissions.neededPermission(PermissionType.B_CHANNEL_MODIFY_NAME).granted(1)),tag.find(".channel_password").change(function(){properties.channel_flag_password=0!=this.value.length,properties.channel_flag_password&&helpers.hashPassword(this.value).then(pass=>properties.channel_password=pass),$(this).removeClass("input_error"),properties.channel_flag_password||globalClient.permissions.neededPermission(PermissionType.B_CHANNEL_CREATE_MODIFY_WITH_FORCE_PASSWORD).granted(1)&&$(this).addClass("input_error"),updateButton()}).prop("disabled",!globalClient.permissions.neededPermission(create?PermissionType.B_CHANNEL_CREATE_WITH_PASSWORD:PermissionType.B_CHANNEL_MODIFY_PASSWORD).granted(1)),tag.find(".channel_topic").change(function(){properties.channel_topic=this.value}).prop("disabled",!globalClient.permissions.neededPermission(create?PermissionType.B_CHANNEL_CREATE_WITH_TOPIC:PermissionType.B_CHANNEL_MODIFY_TOPIC).granted(1)),tag.find(".channel_description").change(function(){properties.channel_description=this.value}).prop("disabled",!globalClient.permissions.neededPermission(create?PermissionType.B_CHANNEL_CREATE_WITH_DESCRIPTION:PermissionType.B_CHANNEL_MODIFY_DESCRIPTION).granted(1)),create&&(tag.find(".channel_name").trigger("change"),tag.find(".channel_password").trigger("change"))}(properties,modal.htmlTag.find(".channel_general_properties"),modal.htmlTag.find(".button_ok"),!channel),function(properties,tag,button,parent,create){tag.find('input[name="channel_type"]').change(function(){switch(this.value){case"semi":properties.channel_flag_permanent=!1,properties.channel_flag_semi_permanent=!0;break;case"perm":properties.channel_flag_permanent=!0,properties.channel_flag_semi_permanent=!1;break;default:properties.channel_flag_permanent=!1,properties.channel_flag_semi_permanent=!1}}),tag.find('input[name="channel_type"][value="temp"]').prop("disabled",!globalClient.permissions.neededPermission(create?PermissionType.B_CHANNEL_CREATE_TEMPORARY:PermissionType.B_CHANNEL_MODIFY_MAKE_TEMPORARY).granted(1)),tag.find('input[name="channel_type"][value="semi"]').prop("disabled",!globalClient.permissions.neededPermission(create?PermissionType.B_CHANNEL_CREATE_SEMI_PERMANENT:PermissionType.B_CHANNEL_MODIFY_MAKE_SEMI_PERMANENT).granted(1)),tag.find('input[name="channel_type"][value="perm"]').prop("disabled",!globalClient.permissions.neededPermission(create?PermissionType.B_CHANNEL_CREATE_PERMANENT:PermissionType.B_CHANNEL_MODIFY_MAKE_PERMANENT).granted(1)),tag.find('input[name="channel_type"]:not(:disabled)').last().prop("checked",!0).trigger("change"),tag.find('input[name="channel_default"]').change(function(){console.log(this.checked),properties.channel_flag_default=this.checked;let elements=tag.find('input[name="channel_type"]');this.checked?(elements.prop("enabled",!1),elements.prop("checked",!1),tag.find('input[name="channel_type"][value="perm"]').prop("checked",!0).trigger("change")):elements.removeProp("enabled")}).prop("disabled",!globalClient.permissions.neededPermission(create?PermissionType.B_CHANNEL_CREATE_PERMANENT:PermissionType.B_CHANNEL_MODIFY_MAKE_PERMANENT).granted(1)||!globalClient.permissions.neededPermission(create?PermissionType.B_CHANNEL_CREATE_WITH_DEFAULT:PermissionType.B_CHANNEL_MODIFY_MAKE_DEFAULT).granted(1)),tag.find('input[name="talk_power"]').change(function(){properties.channel_needed_talk_power=parseInt(this.value)}).prop("disabled",!globalClient.permissions.neededPermission(create?PermissionType.B_CHANNEL_CREATE_WITH_NEEDED_TALK_POWER:PermissionType.B_CHANNEL_MODIFY_NEEDED_TALK_POWER).granted(1));let orderTag=tag.find(".order_id");for(let channel of parent?parent.siblings():globalClient.channelTree.rootChannel())$.spawn("option").attr("channelId",channel.channelId.toString()).text(channel.channelName()).appendTo(orderTag);orderTag.change(function(){let selected=$(this.options.item(this.selectedIndex));properties.channel_order=parseInt(selected.attr("channelId"))}).prop("disabled",!globalClient.permissions.neededPermission(create?PermissionType.B_CHANNEL_CREATE_WITH_SORTORDER:PermissionType.B_CHANNEL_MODIFY_SORTORDER).granted(1)),orderTag.find("option").last().prop("selected",!0)}(properties,modal.htmlTag.find(".settings_standard"),modal.htmlTag.find(".button_ok"),parent,!channel),modal.htmlTag.find(".button_ok").click(()=>{modal.close(),callback(properties)}),modal.htmlTag.find(".button_cancel").click(()=>{modal.close(),callback()}),modal.open()}}(Modals||(Modals={}));class ChannelTree{constructor(client,htmlTree){if(this.client=client,this.htmlTree=htmlTree,this.reset(),!settings.static(Settings.KEY_DISABLE_CONTEXT_MENU,!1)){let _this=this;this.htmlTree.parent().on("contextmenu",function(event){event.isDefaultPrevented()||(event.preventDefault(),_this.onSelect(void 0),_this.showContextMenu(event.pageX,event.pageY))})}}showContextMenu(x,y,on_close){let channelCreate=this.client.permissions.neededPermission(PermissionType.B_CHANNEL_CREATE_TEMPORARY).granted(1)||this.client.permissions.neededPermission(PermissionType.B_CHANNEL_CREATE_SEMI_PERMANENT).granted(1)||this.client.permissions.neededPermission(PermissionType.B_CHANNEL_CREATE_PERMANENT).granted(1);spawnMenu(x,y,{type:MenuEntryType.ENTRY,icon:"client-channel_create",name:"Create channel",invalidPermission:!channelCreate,callback:()=>this.spawnCreateChannel()},MenuEntry.CLOSE(on_close))}initialiseHead(serverName){this.server=new ServerEntry(this,serverName),this.server.htmlTag.appendTo(this.htmlTree),this.server.initializeListener()}__deleteAnimation(element){let tag=element instanceof ChannelEntry?element.rootTag():element.tag;this.htmlTree.find(tag).fadeOut("slow",()=>{tag.remove(),element instanceof ChannelEntry?element.parentChannel()&&element.parentChannel().adjustSize(!0):element instanceof ClientEntry&&element.currentChannel().adjustSize(!0)})}rootChannel(){return this.channels.filter(e=>null==e.parent)}deleteChannel(channel){const _this=this;for(let index=0;index<this.channels.length;index++){let entry=this.channels[index],currentEntry=this.channels[index];for(;null!=currentEntry&&null!=currentEntry;){if(currentEntry==channel){_this.channels.remove(entry),_this.__deleteAnimation(entry),entry.channelTree=null,index--;break}currentEntry=currentEntry.parentChannel()}}this.channels.remove(channel),this.__deleteAnimation(channel),channel.channelTree=null}insertChannel(channel){channel.channelTree=this,this.channels.push(channel);let elm=void 0,tag=this.htmlTree,prevChannel=null;if(channel.hasParent()){let parent=channel.parentChannel(),siblings=parent.siblings();0==siblings.length?(elm=parent.rootTag(),prevChannel=null):elm=(prevChannel=siblings.last()).tag,tag=parent.siblingTag()}channel.prevChannel=prevChannel;let entry=channel.rootTag().css({display:"none"}).fadeIn("slow");entry.appendTo(tag),channel.originalHeight=entry.outerHeight(!1),null!=elm&&elm.after(entry),channel.adjustSize(!0),channel.initializeListener()}findChannel(channelId){for(let index=0;index<this.channels.length;index++)if(this.channels[index].getChannelId()==channelId)return this.channels[index]}moveChannel(channel,prevChannel,parent){if(null!=prevChannel&&prevChannel.parent!=parent)return void console.error("Invalid channel move (different parents! ("+prevChannel.parent+"|"+parent+")");let oldParent=channel.parentChannel();if(channel.prevChannel=prevChannel,channel.parent=parent,prevChannel)prevChannel.rootTag().after(channel.rootTag());else if(parent){let siblings=parent.siblings();if(siblings.length<=1){channel.rootTag().appendTo($(parent.siblingTag()))}else channel.prevChannel=siblings[siblings.length-2],channel.prevChannel.rootTag().after(channel.rootTag())}else this.htmlTree.find(".server").after(channel.rootTag());oldParent&&oldParent.adjustSize(),channel&&channel.adjustSize()}deleteClient(client){this.clients.remove(client),this.__deleteAnimation(client),client.onDelete()}insertClient(client,channel){let newClient=this.findClient(client.clientId());return newClient?client=newClient:this.clients.push(client),client.channelTree=this,client._channel=channel,client.tag.css({display:"none"}).fadeIn("slow").appendTo(channel.clientTag()),channel.adjustSize(!0),client.initializeListener(),channel.updateChannelTypeIcon(),client}registerClient(client){this.clients.push(client),client.channelTree=this,client.initializeListener()}moveClient(client,channel){let oldChannel=client.currentChannel();client._channel=channel;let tag=client.tag;tag.detach(),tag.appendTo(client.currentChannel().clientTag()),oldChannel&&(oldChannel.adjustSize(),oldChannel.updateChannelTypeIcon()),client.currentChannel()&&(client.currentChannel().adjustSize(),client.currentChannel().updateChannelTypeIcon())}findClient(clientId){for(let index=0;index<this.clients.length;index++)if(this.clients[index].clientId()==clientId)return this.clients[index];return null}onSelect(entry){this.htmlTree.find(".selected").each(function(idx,e){$(e).removeClass("selected")}),entry instanceof ChannelEntry?entry.rootTag().find("> .channelLine").addClass("selected"):entry instanceof ClientEntry?entry.tag.addClass("selected"):entry instanceof ServerEntry&&entry.htmlTag.addClass("selected"),this.client.selectInfo.currentSelected=entry}clientsByGroup(group){let result=[];for(let client of this.clients)client.groupAssigned(group)&&result.push(client);return result}clientsByChannel(channel){let result=[];for(let client of this.clients)client.currentChannel()==channel&&result.push(client);return result}reset(){this.server=null,this.clients=[],this.channels=[],this.htmlTree.empty()}spawnCreateChannel(parent){Modals.createChannelModal(void 0,parent,properties=>{properties&&(properties.cpid=parent?parent.channelId:0,log.debug(LogCategory.CHANNEL,"Creating new channel with properties: %o",properties),this.client.serverConnection.sendCommand("channelcreate",properties))})}}class CommandResult{constructor(json){this.json=json,this.id=json.id,this.message=json.msg,this.extra_message="",json.extra_msg&&(this.extra_message=json.extra_msg),this.success=0==this.id}}class ReturnListener{}class ServerConnection{constructor(client){this._connectionState=ConnectionState.UNCONNECTED,this._connectTimeoutHandler=void 0,this._connected=!1,this.on_connect=(()=>{console.log("Socket connected"),chat.serverChat().appendMessage("Logging in..."),this._handshakeHandler.startHandshake()}),this._client=client,this._socket=null,this.commandHandler=new ConnectionCommandHandler(this),this._retCodeIdx=0,this._retListener=[]}generateReturnCode(){return(this._retCodeIdx++).toString()}startConnection(host,port,handshake,timeout=1e3){this._connectTimeoutHandler&&(clearTimeout(this._connectTimeoutHandler),this._connectTimeoutHandler=null,this.disconnect()),this.updateConnectionState(ConnectionState.CONNECTING),this._remoteHost=host,this._remotePort=port,this._handshakeHandler=handshake,this._handshakeHandler.setConnection(this),this._connected=!1,chat.serverChat().appendMessage("Connecting to "+host+":"+port);const self=this;try{let sockCpy;if(this._connectTimeoutHandler=setTimeout(()=>{this.disconnect(),this._client.handleDisconnect(DisconnectReason.CONNECT_FAILURE)},timeout),this._socket=sockCpy=new WebSocket("wss:"+this._remoteHost+":"+this._remotePort),clearTimeout(this._connectTimeoutHandler),this._connectTimeoutHandler=null,this._socket!=sockCpy)return;this._socket.onopen=(()=>{this._socket==sockCpy&&(this._connected=!0,this.on_connect())}),this._socket.onclose=(event=>{this._socket==sockCpy&&this._client.handleDisconnect(this._connected?DisconnectReason.CONNECTION_CLOSED:DisconnectReason.CONNECT_FAILURE,{code:event.code,reason:event.reason,event:event})}),this._socket.onerror=(e=>{this._socket==sockCpy&&(console.log("Got error: ("+self._socket.readyState+")"),console.log(e))}),this._socket.onmessage=(msg=>{this._socket==sockCpy&&self.handleWebSocketMessage(msg.data)}),this.updateConnectionState(ConnectionState.INITIALISING)}catch(e){this.disconnect(),this._client.handleDisconnect(DisconnectReason.CONNECT_FAILURE,e)}}updateConnectionState(state){this._connectionState=state}disconnect(){if(this._connectionState==ConnectionState.UNCONNECTED)return!1;this.updateConnectionState(ConnectionState.UNCONNECTED),this._socket&&this._socket.close(3255,"request disconnect"),this._socket=null;for(let future of this._retListener)future.reject("Connection closed");return this._retListener=[],this._retCodeIdx=0,this._connected=!1,!0}handleWebSocketMessage(data){if("string"==typeof data){let json;try{json=JSON.parse(data)}catch(e){return console.error("Could not parse message json!"),void alert(e)}if(void 0===json.type)return void console.log("Missing data type!");"command"===json.type?this.handleCommand(json):"WebRTC"===json.type?this._client.voiceConnection.handleControlPacket(json):console.log("Unknown command type "+json.type)}}handleCommand(json){let group=log.group(log.LogType.DEBUG,LogCategory.NETWORKING,"Handling command '%s'",json.command);group.log("Handling command '"+json.command+"'"),group.group(log.LogType.TRACE,"Json:").collapsed(!0).log("%o",json).end();try{let fn=this.commandHandler[json.command];if(void 0===fn)return void group.log("Missing command '"+json.command+"'");fn.call(this.commandHandler,json.data)}finally{group.end()}}sendData(data){this._socket.send(data)}commandiefy(input){return JSON.stringify(input,(key,value)=>{switch(typeof value){case"boolean":return 1==value?"1":"0";case"function":return value();default:return value}})}sendCommand(command,data={},logResult=!0){const _this=this;let result=new Promise((resolve,failed)=>{let _data=$.isArray(data)?data:[data],retCode=void 0!==_data[0].return_code?_data[0].return_code:_this.generateReturnCode();_data[0].return_code=retCode;let listener=new ReturnListener;listener.resolve=resolve,listener.reject=failed,listener.code=retCode,listener.timeout=setTimeout(()=>{_this._retListener.remove(listener),listener.reject("timeout")},1500),this._retListener.push(listener),this._socket.send(this.commandiefy({type:"command",command:command,data:_data}))});return new Promise((resolve,failed)=>{result.then(resolve).catch(ex=>{if(logResult)if(ex instanceof CommandResult){let res=ex;res.success||chat.serverChat().appendError(0==res.extra_message.length?res.message:res.extra_message)}else"string"==typeof ex?chat.serverChat().appendError("Command execution resuluts in "+ex):(console.error("Invalid promise result type: "+typeof ex+". Result:"),console.error(ex));failed(ex)})})}get connected(){return this._socket&&this._socket.readyState==WebSocket.OPEN}joinChannel(channel,password=""){return this.sendCommand("clientmove",[{clid:this._client.getClientId(),cid:channel.getChannelId(),cpw:password}])}sendMessage(message,type,target){return type==ChatType.SERVER?this.sendCommand("sendtextmessage",{targetmode:3,target:0,msg:message}):type==ChatType.CHANNEL?this.sendCommand("sendtextmessage",{targetmode:2,target:target.getChannelId(),msg:message}):type==ChatType.CLIENT?this.sendCommand("sendtextmessage",{targetmode:1,target:target.clientId(),msg:message}):void 0}updateClient(key,value){let data={};return data[key]=value,this.sendCommand("clientupdate",data)}}class HandshakeHandler{constructor(identity,name){this.identity=identity,this.name=name}setConnection(con){this.connection=con,this.connection.commandHandler.handshakeidentityproof=this.handleCommandHandshakeIdentityProof.bind(this)}startHandshake(){let data={intention:0,authentication_method:this.identity.type()};this.identity.type()==IdentitifyType.TEAMSPEAK?data.publicKey=this.identity.publicKey():this.identity.type()==IdentitifyType.TEAFORO&&(data.data=this.identity.identityDataJson),this.connection.sendCommand("handshakebegin",data).catch(error=>{console.log(error)})}handleCommandHandshakeIdentityProof(json){let proof;this.identity.type()==IdentitifyType.TEAMSPEAK?proof=this.identity.signMessage(json[0].message):this.identity.type()==IdentitifyType.TEAFORO&&(proof=this.identity.identitySign),this.connection.sendCommand("handshakeindentityproof",{proof:proof}).then(()=>{this.connection.sendCommand("clientinit",{client_nickname:this.name?this.name:this.identity.name(),client_platform:navigator.platform,client_version:navigator.userAgent,client_browser_engine:navigator.product})}).catch(error=>{console.error("Got login error"),console.log(error)})}}class ConnectionCommandHandler{constructor(connection){this.connection=connection,this.error=this.handleCommandResult,this.channellist=this.handleCommandChannelList,this.notifychannelcreated=this.handleCommandChannelCreate,this.notifychanneldeleted=this.handleCommandChannelDelete,this.notifycliententerview=this.handleCommandClientEnterView,this.notifyclientleftview=this.handleCommandClientLeftView,this.notifyclientmoved=this.handleNotifyClientMoved,this.initserver=this.handleCommandServerInit,this.notifychannelmoved=this.handleNotifyChannelMoved,this.notifychanneledited=this.handleNotifyChannelEdited,this.notifytextmessage=this.handleNotifyTextMessage,this.notifyclientupdated=this.handleNotifyClientUpdated,this.notifyserveredited=this.handleNotifyServerEdited,this.notifyserverupdated=this.handleNotifyServerUpdated}handleCommandResult(json){let code=(json=json[0]).return_code;if(0==code.length)return void console.log("Invalid return code! ("+json+")");let retListeners=this.connection._retListener;for(let e of retListeners){if(e.code!=code)continue;retListeners.remove(e);let result=new CommandResult(json);result.success?e.resolve(result):e.reject(result);break}}handleCommandServerInit(json){console.log("Setting up voice "),this.connection._client.voiceConnection.createSession(),json=json[0],this.connection._client.clientId=parseInt(json.aclid),this.connection._client.getClient().updateVariables({key:"client_nickname",value:json.acn});for(let key in json)"aclid"!==key&&"acn"!==key&&this.connection._client.channelTree.server.updateProperty(key,json[key]);chat.serverChat().name=this.connection._client.channelTree.server.properties.virtualserver_name,chat.serverChat().appendMessage("Connected as {0}",!0,this.connection._client.getClient().createChatTag(!0)),globalClient.onConnected()}createChannelFromJson(json,ignoreOrder=!1){let tree=this.connection._client.channelTree,channel=new ChannelEntry(parseInt(json.cid),json.channel_name,tree.findChannel(json.cpid));if(tree.insertChannel(channel),"0"!==json.channel_order){let prev=tree.findChannel(json.channel_order);if(!prev&&0!=json.channel_order&&!ignoreOrder)return void console.error("Invalid channel order id!");let parent=tree.findChannel(json.cpid);if(!parent&&0!=json.cpid)return void console.error("Invalid channel parent");tree.moveChannel(channel,prev,parent)}if(ignoreOrder)for(let ch of tree.channels)ch.properties.channel_order==channel.channelId&&tree.moveChannel(ch,channel,channel.parent);let updates=[];for(let key in json)"cid"!==key&&"cpid"!==key&&"invokerid"!==key&&"invokername"!==key&&"invokeruid"!==key&&"reasonid"!==key&&updates.push({key:key,value:json[key]});channel.updateVariables(...updates)}handleCommandChannelList(json){console.log("Got "+json.length+" new channels");for(let index=0;index<json.length;index++)this.createChannelFromJson(json[index],!0)}handleCommandChannelCreate(json){this.createChannelFromJson(json[0])}handleCommandChannelDelete(json){let tree=this.connection._client.channelTree;console.log("Got "+json.length+" channel deletions");for(let index=0;index<json.length;index++){let channel=tree.findChannel(json[index].cid);channel?tree.deleteChannel(channel):console.error("Invalid channel onDelete (Unknown channel)")}}handleCommandClientEnterView(json){json=json[0];let client,tree=this.connection._client.channelTree,channel=tree.findChannel(json.ctid),old_channel=tree.findChannel(json.cfid);(client=tree.findClient(json.clid))?(client==this.connection._client.getClient()&&(chat.channelChat().name=channel.channelName()),tree.moveClient(client,channel)):(client=new ClientEntry(parseInt(json.clid),json.client_nickname),client=tree.insertClient(client,channel)),json.reasonid==ViewReasonId.VREASON_USER_ACTION&&(old_channel?chat.serverChat().appendMessage("{0} appeared from {1} to {2}",!0,client.createChatTag(!0),old_channel.createChatTag(!0),channel.createChatTag(!0)):chat.serverChat().appendMessage("{0} connected to channel {1}",!0,client.createChatTag(!0),channel.createChatTag(!0)));let updates=[];for(let key in json)"cfid"!=key&&"ctid"!=key&&"invokerid"!==key&&"invokername"!==key&&"invokeruid"!==key&&"reasonid"!==key&&updates.push({key:key,value:json[key]});client.updateVariables(...updates)}handleCommandClientLeftView(json){json=json[0];let tree=this.connection._client.channelTree,client=tree.findClient(json.clid);if(!client)return console.error("Unknown client left!"),0;if(client==this.connection._client.getClient())return void(json.reasonid==ViewReasonId.VREASON_BAN?this.connection._client.handleDisconnect(DisconnectReason.CLIENT_BANNED,json):json.reasonid==ViewReasonId.VREASON_SERVER_KICK?this.connection._client.handleDisconnect(DisconnectReason.CLIENT_KICKED,json):json.reasonid==ViewReasonId.VREASON_SERVER_SHUTDOWN?this.connection._client.handleDisconnect(DisconnectReason.SERVER_CLOSED,json):json.reasonid==ViewReasonId.VREASON_SERVER_STOPPED?this.connection._client.handleDisconnect(DisconnectReason.SERVER_CLOSED,json):this.connection._client.handleDisconnect(DisconnectReason.UNKNOWN,json));let channel_from=tree.findChannel(json.cfid),channel_to=tree.findChannel(json.ctid);if(json.reasonid==ViewReasonId.VREASON_USER_ACTION)chat.serverChat().appendMessage("{0} disappeared from {1} to {2}",!0,client.createChatTag(!0),channel_from.createChatTag(!0),channel_to.createChatTag(!0));else if(json.reasonid==ViewReasonId.VREASON_SERVER_LEFT)chat.serverChat().appendMessage("{0} left the server ({1})",!0,client.createChatTag(!0),json.reasonmsg);else if(json.reasonid==ViewReasonId.VREASON_SERVER_KICK)chat.serverChat().appendError("{0} was kicked from the server by {1}. ({2})",client.createChatTag(!0),ClientEntry.chatTag(json.invokerid,json.invokername,json.invokeruid),json.reasonmsg);else if(json.reasonid==ViewReasonId.VREASON_BAN){let duration="permanently";json.bantime&&(duration="for "+formatDate(Number.parseInt(json.bantime))),chat.serverChat().appendError("{0} was banned {1} by {2}. ({3})",client.createChatTag(!0),duration,ClientEntry.chatTag(json.invokerid,json.invokername,json.invokeruid),json.reasonmsg)}else console.error("Unknown client left reason!");tree.deleteClient(client)}handleNotifyClientMoved(json){json=json[0];let tree=this.connection._client.channelTree,client=tree.findClient(json.clid),channel_to=tree.findChannel(json.ctid),channel_from=tree.findChannel(json.cfid);if(!client)return console.error("Unknown client move (Client)!"),0;if(!channel_to)return console.error("Unknown client move (Channel to)!"),0;if(channel_from||console.error("Unknown client move (Channel from)!"),client instanceof LocalClientEntry){chat.channelChat().name=channel_to.channelName();for(let entry of client.channelTree.clientsByChannel(client.currentChannel()))entry!==client&&entry.getAudioController().stopAudio(!0)}tree.moveClient(client,channel_to),json.reasonid==ViewReasonId.VREASON_MOVED?chat.serverChat().appendMessage("{0} was moved from channel {1} to {2} by {3}",!0,client.createChatTag(!0),channel_from?channel_from.createChatTag(!0):void 0,channel_to.createChatTag(!0),ClientEntry.chatTag(json.invokerid,json.invokername,json.invokeruid)):json.reasonid==ViewReasonId.VREASON_USER_ACTION&&chat.serverChat().appendMessage("{0} switched from channel {1} to {2}",!0,client.createChatTag(!0),channel_from?channel_from.createChatTag(!0):void 0,channel_to.createChatTag(!0))}handleNotifyChannelMoved(json){json=json[0];for(let key in json)console.log("Key: "+key+" Value: "+json[key]);let tree=this.connection._client.channelTree,channel=tree.findChannel(json.cid);if(!channel)return console.error("Unknown channel move (Channel)!"),0;let prev=tree.findChannel(json.order);if(!prev&&0!=json.order)return console.error("Unknown channel move (prev)!"),0;let parent=tree.findChannel(json.cpid);if(!parent&&0!=json.cpid)return console.error("Unknown channel move (parent)!"),0;tree.moveChannel(channel,prev,parent)}handleNotifyChannelEdited(json){json=json[0];let channel=this.connection._client.channelTree.findChannel(json.cid);if(!channel)return console.error("Unknown channel edit (Channel)!"),0;let updates=[];for(let key in json)"cid"!==key&&"invokerid"!==key&&"invokername"!==key&&"invokeruid"!==key&&"reasonid"!==key&&updates.push({key:key,value:json[key]});channel.updateVariables(...updates)}handleNotifyTextMessage(json){let mode=(json=json[0]).targetmode;if(1==mode){let invoker=this.connection._client.channelTree.findClient(json.invokerid),target=this.connection._client.channelTree.findClient(json.target);if(!invoker)return void console.error("Got private message from invalid client!");if(!target)return void console.error("Got private message from invalid client!");invoker==this.connection._client.getClient()?target.chat(!0).appendMessage("<< "+json.msg):invoker.chat(!0).appendMessage(">> "+json.msg)}else 2==mode?chat.channelChat().appendMessage("{0} >> {1}",!0,ClientEntry.chatTag(json.invokerid,json.invokername,json.invokeruid,!0),json.msg):3==mode&&chat.serverChat().appendMessage("{0} >> {1}",!0,ClientEntry.chatTag(json.invokerid,json.invokername,json.invokeruid,!0),json.msg)}handleNotifyClientUpdated(json){json=json[0];let client=this.connection._client.channelTree.findClient(json.clid);if(!client)return void console.error("Tried to update an non existing client");let updates=[];for(let key in json)"clid"!=key&&updates.push({key:key,value:json[key]});client.updateVariables(...updates),this.connection._client.selectInfo.currentSelected==client&&this.connection._client.selectInfo.update()}handleNotifyServerEdited(json){json=json[0];for(let key in json)"invokerid"!==key&&"invokername"!==key&&"invokeruid"!==key&&"reasonid"!==key&&this.connection._client.channelTree.server.updateProperty(key,json[key])}handleNotifyServerUpdated(json){json=json[0];for(let key in json)"invokerid"!==key&&"invokername"!==key&&"invokeruid"!==key&&"reasonid"!==key&&this.connection._client.channelTree.server.updateProperty(key,json[key]);let info=this.connection._client.selectInfo;info.currentSelected instanceof ServerEntry&&info.update()}}if("undefined"!=typeof customElements){class X_Properties extends HTMLElement{}class X_Property extends HTMLElement{}customElements.define("x-properties",X_Properties,{extends:"div"}),customElements.define("x-property",X_Property,{extends:"div"})}class Settings{constructor(){this.cacheGlobal={},this.cacheServer={},this.updated=!1,this._staticPropsTag=$("#properties"),this.cacheGlobal=JSON.parse(localStorage.getItem("settings.global")),this.cacheGlobal||(this.cacheGlobal={});const _this=this;this.saveWorker=setInterval(()=>{_this.updated&&_this.save()},5e3),this.initializeStatic()}initializeStatic(){location.search.substr(1).split("&").forEach(part=>{let item=part.split("=");$("<x-property></x-property>").attr("key",item[0]).attr("value",item[1]).appendTo(this._staticPropsTag)})}static transformStO(input,_default){return void 0===input?_default:"string"==typeof _default?input:"number"==typeof _default?parseInt(input):"boolean"==typeof _default?"1"==input||"true"==input:void 0===_default?input:JSON.parse(input)}static transformOtS(input){return"string"==typeof input?input:"number"==typeof input?input.toString():"boolean"==typeof input?input?"1":"0":void 0!==input?JSON.stringify(input):void 0}global(key,_default){let result=this.cacheGlobal[key];return Settings.transformStO(result,_default)}server(key,_default){let result=this.cacheServer[key];return Settings.transformStO(result,_default)}static(key,_default){let result=this._staticPropsTag.find("[key='"+key+"']");return console.log("%d | %o",result.length,result),Settings.transformStO(result.length>0?decodeURIComponent(result.last().attr("value")):void 0,_default)}changeGlobal(key,value){this.cacheGlobal[key]!=value&&(this.updated=!0,this.cacheGlobal[key]=Settings.transformOtS(value),Settings.UPDATE_DIRECT&&this.save())}changeServer(key,value){this.cacheServer[key]!=value&&(this.updated=!0,this.cacheServer[key]=Settings.transformOtS(value),Settings.UPDATE_DIRECT&&this.save())}setServer(server){if(this.currentServer&&(this.save(),this.cacheServer={},this.currentServer=void 0),this.currentServer=server,this.currentServer){let serverId=this.currentServer.properties.virtualserver_unique_identifier;this.cacheServer=JSON.parse(localStorage.getItem("settings.server_"+serverId)),this.cacheServer||(this.cacheServer={})}}save(){if(this.updated=!1,this.currentServer){let serverId=this.currentServer.properties.virtualserver_unique_identifier,server=JSON.stringify(this.cacheServer);localStorage.setItem("settings.server_"+serverId,server)}let global=JSON.stringify(this.cacheGlobal);localStorage.setItem("settings.global",global)}deleteStatic(key){let result=this._staticPropsTag.find("[key='"+key+"']");0!=result.length&&result.detach()}}Settings.KEY_DISABLE_CONTEXT_MENU="disableContextMenu",Settings.KEY_DISABLE_UNLOAD_DIALOG="disableUnloadDialog",Settings.UPDATE_DIRECT=!0;class InfoBar{constructor(client,htmlTag){this.timers=[],this.intervals=[],this.handle=client,this._htmlTag=htmlTag}createInfoTable(infos){let table=$("<table/>");for(let e in infos){console.log("Display info "+e);let entry=$("<tr/>");entry.append("<td class='info_key'>"+e+":</td>"),entry.append("<td>"+infos[e]+"</td>"),table.append(entry)}return table}set currentSelected(entry){this._currentSelected!=entry&&(this._currentSelected=entry,this.buildBar())}get currentSelected(){return this._currentSelected}update(){this.buildBar()}updateServerTimings(){this._htmlTag.find(".uptime").text(formatDate(this._currentSelected.calculateUptime()))}updateClientTimings(){this._htmlTag.find(".online").text(formatDate(this._currentSelected.calculateOnlineTime()))}buildBar(){if(this._htmlTag.empty(),this._currentSelected){for(let timer of this.timers)clearTimeout(timer);for(let timer of this.intervals)clearInterval(timer);if(this._currentSelected instanceof ServerEntry){this._currentSelected.shouldUpdateProperties()&&this._currentSelected.updateProperties();let version=this._currentSelected.properties.virtualserver_version;version.startsWith("TeaSpeak ")&&(version=version.substr("TeaSpeak ".length)),this._htmlTag.append(this.createInfoTable({Name:this._currentSelected.properties.virtualserver_name,Address:"unknown",Type:"TeaSpeak",Version:version+" on "+this._currentSelected.properties.virtualserver_platform,Uptime:"<a class='uptime'>"+formatDate(this._currentSelected.calculateUptime())+"</a>","Current Channels":this._currentSelected.properties.virtualserver_channelsonline,"Current Clients":this._currentSelected.properties.virtualserver_clientsonline,"Current Queries":this._currentSelected.properties.virtualserver_queryclientsonline})),this._htmlTag.append($.spawn("div").css("height","100%"));let requestUpdate=$.spawn("button");requestUpdate.css("min-height","16px"),requestUpdate.css("bottom",0),requestUpdate.text("update info"),this._currentSelected.shouldUpdateProperties()?requestUpdate.css("color","green"):(requestUpdate.attr("disabled","true"),requestUpdate.css("color","red")),this._htmlTag.append(requestUpdate);const _server=this._currentSelected,_this=this;requestUpdate.click(function(){_server.updateProperties(),_this.buildBar()}),this.timers.push(setTimeout(function(){requestUpdate.css("color","green"),requestUpdate.removeAttr("disabled")},_server.nextInfoRequest-(new Date).getTime())),this.intervals.push(setInterval(this.updateServerTimings.bind(this),1e3))}else if(this._currentSelected instanceof ChannelEntry){let props=this._currentSelected.properties;this._htmlTag.append(this.createInfoTable({Name:this._currentSelected.createChatTag().html(),Topic:this._currentSelected.properties.channel_topic,Codec:this._currentSelected.properties.channel_codec,"Codec Quality":this._currentSelected.properties.channel_codec_quality,Type:ChannelType.normalize(this._currentSelected.channelType()),"Current clients":this._currentSelected.channelTree.clientsByChannel(this._currentSelected).length+" / "+(-1==props.channel_maxclients?"Unlimited":props.channel_maxclients),"Subscription Status":"unknown","Voice Data Encryption":"unknown"}))}else if(this._currentSelected instanceof ClientEntry){this._currentSelected.updateVariables();let version=this._currentSelected.properties.client_version;version||(version="");let infos={Name:this._currentSelected.createChatTag().html(),Description:this._currentSelected.properties.client_description,Version:"<a title='"+ChatMessage.formatMessage(version)+"'>"+version.split(" ")[0]+"</a> on "+this._currentSelected.properties.client_platform,"Online since":"<a class='online'>"+formatDate(this._currentSelected.calculateOnlineTime())+"</a>",Volume:100*this._currentSelected.audioController.volume+" %"};this._currentSelected.properties.client_teaforum_id>0&&(infos["TeaSpeak Account"]="<a href='//forum.teaspeak.de/index.php?members/{1}/' target='_blank'>{0}</a>".format(this._currentSelected.properties.client_teaforum_name,this._currentSelected.properties.client_teaforum_id)),this._htmlTag.append(this.createInfoTable(infos));{let serverGroups=$.spawn("div");serverGroups.css("display","flex").css("flex-direction","column");let header=$.spawn("div");header.css("display","flex").css("margin-top","5px").css("align-items","center"),$.spawn("div").addClass("icon client-permission_server_groups").appendTo(header),$.spawn("div").text("Server groups:").css("margin-left","3px").css("font-weight","bold").appendTo(header),header.appendTo(serverGroups);for(let groupId of this._currentSelected.assignedServerGroupIds()){let group=this.handle.groups.serverGroup(groupId);if(!group)continue;let groupTag=$.spawn("div");groupTag.css("display","flex").css("margin-top","1px").css("margin-left","10px").css("align-items","center"),this.handle.fileManager.icons.generateTag(group.properties.iconid).appendTo(groupTag),$.spawn("div").text(group.name).css("margin-left","3px").appendTo(groupTag),groupTag.appendTo(serverGroups)}this._htmlTag.append(serverGroups)}{let channelGroup=$.spawn("div");channelGroup.css("display","flex").css("flex-direction","column");let header=$.spawn("div");header.css("display","flex").css("margin-top","10px").css("align-items","center"),$.spawn("div").addClass("icon client-permission_channel").appendTo(header),$.spawn("div").text("Channel group:").css("margin-left","3px").css("font-weight","bold").appendTo(header),header.appendTo(channelGroup);let group=this.handle.groups.channelGroup(this._currentSelected.assignedChannelGroup());if(group){let groupTag=$.spawn("div");groupTag.css("display","flex").css("margin-top","1px").css("margin-left","10px").css("align-items","center"),this.handle.fileManager.icons.generateTag(group.properties.iconid).appendTo(groupTag),$.spawn("div").text(group.name).css("margin-left","3px").appendTo(groupTag),groupTag.appendTo(channelGroup)}this._htmlTag.append(channelGroup)}this._currentSelected.properties.client_flag_avatar.length>0&&this.handle.fileManager.avatars.generateTag(this._currentSelected).appendTo(this._htmlTag),this.intervals.push(setInterval(this.updateClientTimings.bind(this),1e3))}}}}!function(PermissionType){PermissionType.B_SERVERINSTANCE_HELP_VIEW="b_serverinstance_help_view",PermissionType.B_SERVERINSTANCE_VERSION_VIEW="b_serverinstance_version_view",PermissionType.B_SERVERINSTANCE_INFO_VIEW="b_serverinstance_info_view",PermissionType.B_SERVERINSTANCE_VIRTUALSERVER_LIST="b_serverinstance_virtualserver_list",PermissionType.B_SERVERINSTANCE_BINDING_LIST="b_serverinstance_binding_list",PermissionType.B_SERVERINSTANCE_PERMISSION_LIST="b_serverinstance_permission_list",PermissionType.B_SERVERINSTANCE_PERMISSION_FIND="b_serverinstance_permission_find",PermissionType.B_VIRTUALSERVER_CREATE="b_virtualserver_create",PermissionType.B_VIRTUALSERVER_DELETE="b_virtualserver_delete",PermissionType.B_VIRTUALSERVER_START_ANY="b_virtualserver_start_any",PermissionType.B_VIRTUALSERVER_STOP_ANY="b_virtualserver_stop_any",PermissionType.B_VIRTUALSERVER_CHANGE_MACHINE_ID="b_virtualserver_change_machine_id",PermissionType.B_VIRTUALSERVER_CHANGE_TEMPLATE="b_virtualserver_change_template",PermissionType.B_SERVERQUERY_LOGIN="b_serverquery_login",PermissionType.B_SERVERINSTANCE_TEXTMESSAGE_SEND="b_serverinstance_textmessage_send",PermissionType.B_SERVERINSTANCE_LOG_VIEW="b_serverinstance_log_view",PermissionType.B_SERVERINSTANCE_LOG_ADD="b_serverinstance_log_add",PermissionType.B_SERVERINSTANCE_STOP="b_serverinstance_stop",PermissionType.B_SERVERINSTANCE_MODIFY_SETTINGS="b_serverinstance_modify_settings",PermissionType.B_SERVERINSTANCE_MODIFY_QUERYGROUP="b_serverinstance_modify_querygroup",PermissionType.B_SERVERINSTANCE_MODIFY_TEMPLATES="b_serverinstance_modify_templates",PermissionType.B_VIRTUALSERVER_SELECT="b_virtualserver_select",PermissionType.B_VIRTUALSERVER_INFO_VIEW="b_virtualserver_info_view",PermissionType.B_VIRTUALSERVER_CONNECTIONINFO_VIEW="b_virtualserver_connectioninfo_view",PermissionType.B_VIRTUALSERVER_CHANNEL_LIST="b_virtualserver_channel_list",PermissionType.B_VIRTUALSERVER_CHANNEL_SEARCH="b_virtualserver_channel_search",PermissionType.B_VIRTUALSERVER_CLIENT_LIST="b_virtualserver_client_list",PermissionType.B_VIRTUALSERVER_CLIENT_SEARCH="b_virtualserver_client_search",PermissionType.B_VIRTUALSERVER_CLIENT_DBLIST="b_virtualserver_client_dblist",PermissionType.B_VIRTUALSERVER_CLIENT_DBSEARCH="b_virtualserver_client_dbsearch",PermissionType.B_VIRTUALSERVER_CLIENT_DBINFO="b_virtualserver_client_dbinfo",PermissionType.B_VIRTUALSERVER_PERMISSION_FIND="b_virtualserver_permission_find",PermissionType.B_VIRTUALSERVER_CUSTOM_SEARCH="b_virtualserver_custom_search",PermissionType.B_VIRTUALSERVER_START="b_virtualserver_start",PermissionType.B_VIRTUALSERVER_STOP="b_virtualserver_stop",PermissionType.B_VIRTUALSERVER_TOKEN_LIST="b_virtualserver_token_list",PermissionType.B_VIRTUALSERVER_TOKEN_ADD="b_virtualserver_token_add",PermissionType.B_VIRTUALSERVER_TOKEN_USE="b_virtualserver_token_use",PermissionType.B_VIRTUALSERVER_TOKEN_DELETE="b_virtualserver_token_delete",PermissionType.B_VIRTUALSERVER_LOG_VIEW="b_virtualserver_log_view",PermissionType.B_VIRTUALSERVER_LOG_ADD="b_virtualserver_log_add",PermissionType.B_VIRTUALSERVER_JOIN_IGNORE_PASSWORD="b_virtualserver_join_ignore_password",PermissionType.B_VIRTUALSERVER_NOTIFY_REGISTER="b_virtualserver_notify_register",PermissionType.B_VIRTUALSERVER_NOTIFY_UNREGISTER="b_virtualserver_notify_unregister",PermissionType.B_VIRTUALSERVER_SNAPSHOT_CREATE="b_virtualserver_snapshot_create",PermissionType.B_VIRTUALSERVER_SNAPSHOT_DEPLOY="b_virtualserver_snapshot_deploy",PermissionType.B_VIRTUALSERVER_PERMISSION_RESET="b_virtualserver_permission_reset",PermissionType.B_VIRTUALSERVER_MODIFY_NAME="b_virtualserver_modify_name",PermissionType.B_VIRTUALSERVER_MODIFY_WELCOMEMESSAGE="b_virtualserver_modify_welcomemessage",PermissionType.B_VIRTUALSERVER_MODIFY_MAXCLIENTS="b_virtualserver_modify_maxclients",PermissionType.B_VIRTUALSERVER_MODIFY_RESERVED_SLOTS="b_virtualserver_modify_reserved_slots",PermissionType.B_VIRTUALSERVER_MODIFY_PASSWORD="b_virtualserver_modify_password",PermissionType.B_VIRTUALSERVER_MODIFY_DEFAULT_SERVERGROUP="b_virtualserver_modify_default_servergroup",PermissionType.B_VIRTUALSERVER_MODIFY_DEFAULT_CHANNELGROUP="b_virtualserver_modify_default_channelgroup",PermissionType.B_VIRTUALSERVER_MODIFY_DEFAULT_CHANNELADMINGROUP="b_virtualserver_modify_default_channeladmingroup",PermissionType.B_VIRTUALSERVER_MODIFY_CHANNEL_FORCED_SILENCE="b_virtualserver_modify_channel_forced_silence",PermissionType.B_VIRTUALSERVER_MODIFY_COMPLAIN="b_virtualserver_modify_complain",PermissionType.B_VIRTUALSERVER_MODIFY_ANTIFLOOD="b_virtualserver_modify_antiflood",PermissionType.B_VIRTUALSERVER_MODIFY_FT_SETTINGS="b_virtualserver_modify_ft_settings",PermissionType.B_VIRTUALSERVER_MODIFY_FT_QUOTAS="b_virtualserver_modify_ft_quotas",PermissionType.B_VIRTUALSERVER_MODIFY_HOSTMESSAGE="b_virtualserver_modify_hostmessage",PermissionType.B_VIRTUALSERVER_MODIFY_HOSTBANNER="b_virtualserver_modify_hostbanner",PermissionType.B_VIRTUALSERVER_MODIFY_HOSTBUTTON="b_virtualserver_modify_hostbutton",PermissionType.B_VIRTUALSERVER_MODIFY_PORT="b_virtualserver_modify_port",PermissionType.B_VIRTUALSERVER_MODIFY_HOST="b_virtualserver_modify_host",PermissionType.B_VIRTUALSERVER_MODIFY_AUTOSTART="b_virtualserver_modify_autostart",PermissionType.B_VIRTUALSERVER_MODIFY_NEEDED_IDENTITY_SECURITY_LEVEL="b_virtualserver_modify_needed_identity_security_level",PermissionType.B_VIRTUALSERVER_MODIFY_PRIORITY_SPEAKER_DIMM_MODIFICATOR="b_virtualserver_modify_priority_speaker_dimm_modificator",PermissionType.B_VIRTUALSERVER_MODIFY_LOG_SETTINGS="b_virtualserver_modify_log_settings",PermissionType.B_VIRTUALSERVER_MODIFY_MIN_CLIENT_VERSION="b_virtualserver_modify_min_client_version",PermissionType.B_VIRTUALSERVER_MODIFY_ICON_ID="b_virtualserver_modify_icon_id",PermissionType.B_VIRTUALSERVER_MODIFY_WEBLIST="b_virtualserver_modify_weblist",PermissionType.B_VIRTUALSERVER_MODIFY_CODEC_ENCRYPTION_MODE="b_virtualserver_modify_codec_encryption_mode",PermissionType.B_VIRTUALSERVER_MODIFY_TEMPORARY_PASSWORDS="b_virtualserver_modify_temporary_passwords",PermissionType.B_VIRTUALSERVER_MODIFY_TEMPORARY_PASSWORDS_OWN="b_virtualserver_modify_temporary_passwords_own",PermissionType.B_VIRTUALSERVER_MODIFY_CHANNEL_TEMP_DELETE_DELAY_DEFAULT="b_virtualserver_modify_channel_temp_delete_delay_default",PermissionType.B_VIRTUALSERVER_MODIFY_MUSIC_BOT_LIMIT="b_virtualserver_modify_music_bot_limit",PermissionType.I_CHANNEL_MIN_DEPTH="i_channel_min_depth",PermissionType.I_CHANNEL_MAX_DEPTH="i_channel_max_depth",PermissionType.B_CHANNEL_GROUP_INHERITANCE_END="b_channel_group_inheritance_end",PermissionType.I_CHANNEL_PERMISSION_MODIFY_POWER="i_channel_permission_modify_power",PermissionType.I_CHANNEL_NEEDED_PERMISSION_MODIFY_POWER="i_channel_needed_permission_modify_power",PermissionType.B_CHANNEL_INFO_VIEW="b_channel_info_view",PermissionType.B_CHANNEL_CREATE_CHILD="b_channel_create_child",PermissionType.B_CHANNEL_CREATE_PERMANENT="b_channel_create_permanent",PermissionType.B_CHANNEL_CREATE_SEMI_PERMANENT="b_channel_create_semi_permanent",PermissionType.B_CHANNEL_CREATE_TEMPORARY="b_channel_create_temporary",PermissionType.B_CHANNEL_CREATE_PRIVATE="b_channel_create_private",PermissionType.B_CHANNEL_CREATE_WITH_TOPIC="b_channel_create_with_topic",PermissionType.B_CHANNEL_CREATE_WITH_DESCRIPTION="b_channel_create_with_description",PermissionType.B_CHANNEL_CREATE_WITH_PASSWORD="b_channel_create_with_password",PermissionType.B_CHANNEL_CREATE_MODIFY_WITH_CODEC_SPEEX8="b_channel_create_modify_with_codec_speex8",PermissionType.B_CHANNEL_CREATE_MODIFY_WITH_CODEC_SPEEX16="b_channel_create_modify_with_codec_speex16",PermissionType.B_CHANNEL_CREATE_MODIFY_WITH_CODEC_SPEEX32="b_channel_create_modify_with_codec_speex32",PermissionType.B_CHANNEL_CREATE_MODIFY_WITH_CODEC_CELTMONO48="b_channel_create_modify_with_codec_celtmono48",PermissionType.B_CHANNEL_CREATE_MODIFY_WITH_CODEC_OPUSVOICE="b_channel_create_modify_with_codec_opusvoice",PermissionType.B_CHANNEL_CREATE_MODIFY_WITH_CODEC_OPUSMUSIC="b_channel_create_modify_with_codec_opusmusic",PermissionType.I_CHANNEL_CREATE_MODIFY_WITH_CODEC_MAXQUALITY="i_channel_create_modify_with_codec_maxquality",PermissionType.I_CHANNEL_CREATE_MODIFY_WITH_CODEC_LATENCY_FACTOR_MIN="i_channel_create_modify_with_codec_latency_factor_min",PermissionType.B_CHANNEL_CREATE_WITH_MAXCLIENTS="b_channel_create_with_maxclients",PermissionType.B_CHANNEL_CREATE_WITH_MAXFAMILYCLIENTS="b_channel_create_with_maxfamilyclients",PermissionType.B_CHANNEL_CREATE_WITH_SORTORDER="b_channel_create_with_sortorder",PermissionType.B_CHANNEL_CREATE_WITH_DEFAULT="b_channel_create_with_default",PermissionType.B_CHANNEL_CREATE_WITH_NEEDED_TALK_POWER="b_channel_create_with_needed_talk_power",PermissionType.B_CHANNEL_CREATE_MODIFY_WITH_FORCE_PASSWORD="b_channel_create_modify_with_force_password",PermissionType.I_CHANNEL_CREATE_MODIFY_WITH_TEMP_DELETE_DELAY="i_channel_create_modify_with_temp_delete_delay",PermissionType.B_CHANNEL_MODIFY_PARENT="b_channel_modify_parent",PermissionType.B_CHANNEL_MODIFY_MAKE_DEFAULT="b_channel_modify_make_default",PermissionType.B_CHANNEL_MODIFY_MAKE_PERMANENT="b_channel_modify_make_permanent",PermissionType.B_CHANNEL_MODIFY_MAKE_SEMI_PERMANENT="b_channel_modify_make_semi_permanent",PermissionType.B_CHANNEL_MODIFY_MAKE_TEMPORARY="b_channel_modify_make_temporary",PermissionType.B_CHANNEL_MODIFY_NAME="b_channel_modify_name",PermissionType.B_CHANNEL_MODIFY_TOPIC="b_channel_modify_topic",PermissionType.B_CHANNEL_MODIFY_DESCRIPTION="b_channel_modify_description",PermissionType.B_CHANNEL_MODIFY_PASSWORD="b_channel_modify_password",PermissionType.B_CHANNEL_MODIFY_CODEC="b_channel_modify_codec",PermissionType.B_CHANNEL_MODIFY_CODEC_QUALITY="b_channel_modify_codec_quality",PermissionType.B_CHANNEL_MODIFY_CODEC_LATENCY_FACTOR="b_channel_modify_codec_latency_factor",PermissionType.B_CHANNEL_MODIFY_MAXCLIENTS="b_channel_modify_maxclients",PermissionType.B_CHANNEL_MODIFY_MAXFAMILYCLIENTS="b_channel_modify_maxfamilyclients",PermissionType.B_CHANNEL_MODIFY_SORTORDER="b_channel_modify_sortorder",PermissionType.B_CHANNEL_MODIFY_NEEDED_TALK_POWER="b_channel_modify_needed_talk_power",PermissionType.I_CHANNEL_MODIFY_POWER="i_channel_modify_power",PermissionType.I_CHANNEL_NEEDED_MODIFY_POWER="i_channel_needed_modify_power",PermissionType.B_CHANNEL_MODIFY_MAKE_CODEC_ENCRYPTED="b_channel_modify_make_codec_encrypted",PermissionType.B_CHANNEL_MODIFY_TEMP_DELETE_DELAY="b_channel_modify_temp_delete_delay",PermissionType.B_CHANNEL_DELETE_PERMANENT="b_channel_delete_permanent",PermissionType.B_CHANNEL_DELETE_SEMI_PERMANENT="b_channel_delete_semi_permanent",PermissionType.B_CHANNEL_DELETE_TEMPORARY="b_channel_delete_temporary",PermissionType.B_CHANNEL_DELETE_FLAG_FORCE="b_channel_delete_flag_force",PermissionType.I_CHANNEL_DELETE_POWER="i_channel_delete_power",PermissionType.I_CHANNEL_NEEDED_DELETE_POWER="i_channel_needed_delete_power",PermissionType.B_CHANNEL_JOIN_PERMANENT="b_channel_join_permanent",PermissionType.B_CHANNEL_JOIN_SEMI_PERMANENT="b_channel_join_semi_permanent",PermissionType.B_CHANNEL_JOIN_TEMPORARY="b_channel_join_temporary",PermissionType.B_CHANNEL_JOIN_IGNORE_PASSWORD="b_channel_join_ignore_password",PermissionType.B_CHANNEL_JOIN_IGNORE_MAXCLIENTS="b_channel_join_ignore_maxclients",PermissionType.I_CHANNEL_JOIN_POWER="i_channel_join_power",PermissionType.I_CHANNEL_NEEDED_JOIN_POWER="i_channel_needed_join_power",PermissionType.I_CHANNEL_SUBSCRIBE_POWER="i_channel_subscribe_power",PermissionType.I_CHANNEL_NEEDED_SUBSCRIBE_POWER="i_channel_needed_subscribe_power",PermissionType.I_CHANNEL_DESCRIPTION_VIEW_POWER="i_channel_description_view_power",PermissionType.I_CHANNEL_NEEDED_DESCRIPTION_VIEW_POWER="i_channel_needed_description_view_power",PermissionType.I_ICON_ID="i_icon_id",PermissionType.I_MAX_ICON_FILESIZE="i_max_icon_filesize",PermissionType.B_ICON_MANAGE="b_icon_manage",PermissionType.B_GROUP_IS_PERMANENT="b_group_is_permanent",PermissionType.I_GROUP_AUTO_UPDATE_TYPE="i_group_auto_update_type",PermissionType.I_GROUP_AUTO_UPDATE_MAX_VALUE="i_group_auto_update_max_value",PermissionType.I_GROUP_SORT_ID="i_group_sort_id",PermissionType.I_GROUP_SHOW_NAME_IN_TREE="i_group_show_name_in_tree",PermissionType.B_VIRTUALSERVER_SERVERGROUP_LIST="b_virtualserver_servergroup_list",PermissionType.B_VIRTUALSERVER_SERVERGROUP_PERMISSION_LIST="b_virtualserver_servergroup_permission_list",PermissionType.B_VIRTUALSERVER_SERVERGROUP_CLIENT_LIST="b_virtualserver_servergroup_client_list",PermissionType.B_VIRTUALSERVER_CHANNELGROUP_LIST="b_virtualserver_channelgroup_list",PermissionType.B_VIRTUALSERVER_CHANNELGROUP_PERMISSION_LIST="b_virtualserver_channelgroup_permission_list",PermissionType.B_VIRTUALSERVER_CHANNELGROUP_CLIENT_LIST="b_virtualserver_channelgroup_client_list",PermissionType.B_VIRTUALSERVER_CLIENT_PERMISSION_LIST="b_virtualserver_client_permission_list",PermissionType.B_VIRTUALSERVER_CHANNEL_PERMISSION_LIST="b_virtualserver_channel_permission_list",PermissionType.B_VIRTUALSERVER_CHANNELCLIENT_PERMISSION_LIST="b_virtualserver_channelclient_permission_list",PermissionType.B_VIRTUALSERVER_SERVERGROUP_CREATE="b_virtualserver_servergroup_create",PermissionType.B_VIRTUALSERVER_CHANNELGROUP_CREATE="b_virtualserver_channelgroup_create",PermissionType.I_SERVER_GROUP_MODIFY_POWER="i_server_group_modify_power",PermissionType.I_SERVER_GROUP_NEEDED_MODIFY_POWER="i_server_group_needed_modify_power",PermissionType.I_SERVER_GROUP_MEMBER_ADD_POWER="i_server_group_member_add_power",PermissionType.I_SERVER_GROUP_NEEDED_MEMBER_ADD_POWER="i_server_group_needed_member_add_power",PermissionType.I_SERVER_GROUP_MEMBER_REMOVE_POWER="i_server_group_member_remove_power",PermissionType.I_SERVER_GROUP_NEEDED_MEMBER_REMOVE_POWER="i_server_group_needed_member_remove_power",PermissionType.I_CHANNEL_GROUP_MODIFY_POWER="i_channel_group_modify_power",PermissionType.I_CHANNEL_GROUP_NEEDED_MODIFY_POWER="i_channel_group_needed_modify_power",PermissionType.I_CHANNEL_GROUP_MEMBER_ADD_POWER="i_channel_group_member_add_power",PermissionType.I_CHANNEL_GROUP_NEEDED_MEMBER_ADD_POWER="i_channel_group_needed_member_add_power",PermissionType.I_CHANNEL_GROUP_MEMBER_REMOVE_POWER="i_channel_group_member_remove_power",PermissionType.I_CHANNEL_GROUP_NEEDED_MEMBER_REMOVE_POWER="i_channel_group_needed_member_remove_power",PermissionType.I_GROUP_MEMBER_ADD_POWER="i_group_member_add_power",PermissionType.I_GROUP_NEEDED_MEMBER_ADD_POWER="i_group_needed_member_add_power",PermissionType.I_GROUP_MEMBER_REMOVE_POWER="i_group_member_remove_power",PermissionType.I_GROUP_NEEDED_MEMBER_REMOVE_POWER="i_group_needed_member_remove_power",PermissionType.I_GROUP_MODIFY_POWER="i_group_modify_power",PermissionType.I_GROUP_NEEDED_MODIFY_POWER="i_group_needed_modify_power",PermissionType.I_DISPLAYED_GROUP_MEMBER_ADD_POWER="i_displayed_group_member_add_power",PermissionType.I_DISPLAYED_GROUP_NEEDED_MEMBER_ADD_POWER="i_displayed_group_needed_member_add_power",PermissionType.I_DISPLAYED_GROUP_MEMBER_REMOVE_POWER="i_displayed_group_member_remove_power",PermissionType.I_DISPLAYED_GROUP_NEEDED_MEMBER_REMOVE_POWER="i_displayed_group_needed_member_remove_power",PermissionType.I_DISPLAYED_GROUP_MODIFY_POWER="i_displayed_group_modify_power",PermissionType.I_DISPLAYED_GROUP_NEEDED_MODIFY_POWER="i_displayed_group_needed_modify_power",PermissionType.I_PERMISSION_MODIFY_POWER="i_permission_modify_power",PermissionType.B_PERMISSION_MODIFY_POWER_IGNORE="b_permission_modify_power_ignore",PermissionType.B_VIRTUALSERVER_SERVERGROUP_DELETE="b_virtualserver_servergroup_delete",PermissionType.B_VIRTUALSERVER_CHANNELGROUP_DELETE="b_virtualserver_channelgroup_delete",PermissionType.I_CLIENT_PERMISSION_MODIFY_POWER="i_client_permission_modify_power",PermissionType.I_CLIENT_NEEDED_PERMISSION_MODIFY_POWER="i_client_needed_permission_modify_power",PermissionType.I_CLIENT_MAX_CLONES_UID="i_client_max_clones_uid",PermissionType.I_CLIENT_MAX_IDLETIME="i_client_max_idletime",PermissionType.I_CLIENT_MAX_AVATAR_FILESIZE="i_client_max_avatar_filesize",PermissionType.I_CLIENT_MAX_CHANNEL_SUBSCRIPTIONS="i_client_max_channel_subscriptions",PermissionType.B_CLIENT_IS_PRIORITY_SPEAKER="b_client_is_priority_speaker",PermissionType.B_CLIENT_SKIP_CHANNELGROUP_PERMISSIONS="b_client_skip_channelgroup_permissions",PermissionType.B_CLIENT_FORCE_PUSH_TO_TALK="b_client_force_push_to_talk",PermissionType.B_CLIENT_IGNORE_BANS="b_client_ignore_bans",PermissionType.B_CLIENT_IGNORE_ANTIFLOOD="b_client_ignore_antiflood",PermissionType.B_CLIENT_ISSUE_CLIENT_QUERY_COMMAND="b_client_issue_client_query_command",PermissionType.B_CLIENT_USE_RESERVED_SLOT="b_client_use_reserved_slot",PermissionType.B_CLIENT_USE_CHANNEL_COMMANDER="b_client_use_channel_commander",PermissionType.B_CLIENT_REQUEST_TALKER="b_client_request_talker",PermissionType.B_CLIENT_AVATAR_DELETE_OTHER="b_client_avatar_delete_other",PermissionType.B_CLIENT_IS_STICKY="b_client_is_sticky",PermissionType.B_CLIENT_IGNORE_STICKY="b_client_ignore_sticky",PermissionType.B_CLIENT_MUSIC_CHANNEL_LIST="b_client_music_channel_list",PermissionType.B_CLIENT_MUSIC_SERVER_LIST="b_client_music_server_list",PermissionType.I_CLIENT_MUSIC_INFO="i_client_music_info",PermissionType.I_CLIENT_MUSIC_NEEDED_INFO="i_client_music_needed_info",PermissionType.B_CLIENT_INFO_VIEW="b_client_info_view",PermissionType.B_CLIENT_PERMISSIONOVERVIEW_VIEW="b_client_permissionoverview_view",PermissionType.B_CLIENT_PERMISSIONOVERVIEW_OWN="b_client_permissionoverview_own",PermissionType.B_CLIENT_REMOTEADDRESS_VIEW="b_client_remoteaddress_view",PermissionType.I_CLIENT_SERVERQUERY_VIEW_POWER="i_client_serverquery_view_power",PermissionType.I_CLIENT_NEEDED_SERVERQUERY_VIEW_POWER="i_client_needed_serverquery_view_power",PermissionType.B_CLIENT_CUSTOM_INFO_VIEW="b_client_custom_info_view",PermissionType.I_CLIENT_KICK_FROM_SERVER_POWER="i_client_kick_from_server_power",PermissionType.I_CLIENT_NEEDED_KICK_FROM_SERVER_POWER="i_client_needed_kick_from_server_power",PermissionType.I_CLIENT_KICK_FROM_CHANNEL_POWER="i_client_kick_from_channel_power",PermissionType.I_CLIENT_NEEDED_KICK_FROM_CHANNEL_POWER="i_client_needed_kick_from_channel_power",PermissionType.I_CLIENT_BAN_POWER="i_client_ban_power",PermissionType.I_CLIENT_NEEDED_BAN_POWER="i_client_needed_ban_power",PermissionType.I_CLIENT_MOVE_POWER="i_client_move_power",PermissionType.I_CLIENT_NEEDED_MOVE_POWER="i_client_needed_move_power",PermissionType.I_CLIENT_COMPLAIN_POWER="i_client_complain_power",PermissionType.I_CLIENT_NEEDED_COMPLAIN_POWER="i_client_needed_complain_power",PermissionType.B_CLIENT_COMPLAIN_LIST="b_client_complain_list",PermissionType.B_CLIENT_COMPLAIN_DELETE_OWN="b_client_complain_delete_own",PermissionType.B_CLIENT_COMPLAIN_DELETE="b_client_complain_delete",PermissionType.B_CLIENT_BAN_LIST="b_client_ban_list",PermissionType.B_CLIENT_BAN_LIST_GLOBAL="b_client_ban_list_global",PermissionType.B_CLIENT_BAN_CREATE="b_client_ban_create",PermissionType.B_CLIENT_BAN_CREATE_GLOBAL="b_client_ban_create_global",PermissionType.B_CLIENT_BAN_EDIT="b_client_ban_edit",PermissionType.B_CLIENT_BAN_EDIT_GLOBAL="b_client_ban_edit_global",PermissionType.B_CLIENT_BAN_DELETE_OWN="b_client_ban_delete_own",PermissionType.B_CLIENT_BAN_DELETE="b_client_ban_delete",PermissionType.B_CLIENT_BAN_DELETE_OWN_GLOBAL="b_client_ban_delete_own_global",PermissionType.B_CLIENT_BAN_DELETE_GLOBAL="b_client_ban_delete_global",PermissionType.I_CLIENT_BAN_MAX_BANTIME="i_client_ban_max_bantime",PermissionType.I_CLIENT_PRIVATE_TEXTMESSAGE_POWER="i_client_private_textmessage_power",PermissionType.I_CLIENT_NEEDED_PRIVATE_TEXTMESSAGE_POWER="i_client_needed_private_textmessage_power",PermissionType.B_CLIENT_SERVER_TEXTMESSAGE_SEND="b_client_server_textmessage_send",PermissionType.B_CLIENT_CHANNEL_TEXTMESSAGE_SEND="b_client_channel_textmessage_send",PermissionType.B_CLIENT_OFFLINE_TEXTMESSAGE_SEND="b_client_offline_textmessage_send",PermissionType.I_CLIENT_TALK_POWER="i_client_talk_power",PermissionType.I_CLIENT_NEEDED_TALK_POWER="i_client_needed_talk_power",PermissionType.I_CLIENT_POKE_POWER="i_client_poke_power",PermissionType.I_CLIENT_NEEDED_POKE_POWER="i_client_needed_poke_power",PermissionType.B_CLIENT_SET_FLAG_TALKER="b_client_set_flag_talker",PermissionType.I_CLIENT_WHISPER_POWER="i_client_whisper_power",PermissionType.I_CLIENT_NEEDED_WHISPER_POWER="i_client_needed_whisper_power",PermissionType.B_CLIENT_MODIFY_DESCRIPTION="b_client_modify_description",PermissionType.B_CLIENT_MODIFY_OWN_DESCRIPTION="b_client_modify_own_description",PermissionType.B_CLIENT_MODIFY_DBPROPERTIES="b_client_modify_dbproperties",PermissionType.B_CLIENT_DELETE_DBPROPERTIES="b_client_delete_dbproperties",PermissionType.B_CLIENT_CREATE_MODIFY_SERVERQUERY_LOGIN="b_client_create_modify_serverquery_login",PermissionType.B_CLIENT_MUSIC_CREATE="b_client_music_create",PermissionType.I_CLIENT_MUSIC_LIMIT="i_client_music_limit",PermissionType.I_CLIENT_MUSIC_DELETE_POWER="i_client_music_delete_power",PermissionType.I_CLIENT_MUSIC_NEEDED_DELETE_POWER="i_client_music_needed_delete_power",PermissionType.I_CLIENT_MUSIC_PLAY_POWER="i_client_music_play_power",PermissionType.I_CLIENT_MUSIC_NEEDED_PLAY_POWER="i_client_music_needed_play_power",PermissionType.I_CLIENT_MUSIC_RENAME_POWER="i_client_music_rename_power",PermissionType.I_CLIENT_MUSIC_NEEDED_RENAME_POWER="i_client_music_needed_rename_power",PermissionType.B_FT_IGNORE_PASSWORD="b_ft_ignore_password",PermissionType.B_FT_TRANSFER_LIST="b_ft_transfer_list",PermissionType.I_FT_FILE_UPLOAD_POWER="i_ft_file_upload_power",PermissionType.I_FT_NEEDED_FILE_UPLOAD_POWER="i_ft_needed_file_upload_power",PermissionType.I_FT_FILE_DOWNLOAD_POWER="i_ft_file_download_power",PermissionType.I_FT_NEEDED_FILE_DOWNLOAD_POWER="i_ft_needed_file_download_power",PermissionType.I_FT_FILE_DELETE_POWER="i_ft_file_delete_power",PermissionType.I_FT_NEEDED_FILE_DELETE_POWER="i_ft_needed_file_delete_power",PermissionType.I_FT_FILE_RENAME_POWER="i_ft_file_rename_power",PermissionType.I_FT_NEEDED_FILE_RENAME_POWER="i_ft_needed_file_rename_power",PermissionType.I_FT_FILE_BROWSE_POWER="i_ft_file_browse_power",PermissionType.I_FT_NEEDED_FILE_BROWSE_POWER="i_ft_needed_file_browse_power",PermissionType.I_FT_DIRECTORY_CREATE_POWER="i_ft_directory_create_power",PermissionType.I_FT_NEEDED_DIRECTORY_CREATE_POWER="i_ft_needed_directory_create_power",PermissionType.I_FT_QUOTA_MB_DOWNLOAD_PER_CLIENT="i_ft_quota_mb_download_per_client",PermissionType.I_FT_QUOTA_MB_UPLOAD_PER_CLIENT="i_ft_quota_mb_upload_per_client"}(PermissionType||(PermissionType={}));class PermissionInfo{}class GrantedPermission{constructor(type,value){this.type=type,this.value=value}granted(requiredValue,required=!0){let result=!1;return-2==this.value&&(result=!required),result=-1==this.value||this.value>=requiredValue,log.trace(LogCategory.PERMISSIONS,"Test needed required: %o | %i | %o => "+result,this,requiredValue,required),result}hasValue(){return-2!=this.value}}class NeededGrantedPermission extends GrantedPermission{constructor(type,value){super(type,value),this.changeListener=[]}}class PermissionManager{constructor(client){this.permissionList=[],this.neededPermissions=[],this.initializedListener=[],this.handle=client,this.handle.serverConnection.commandHandler.notifyclientneededpermissions=this.onNeededPermissions.bind(this),this.handle.serverConnection.commandHandler.notifypermissionlist=this.onPermissionList.bind(this)}initialized(){return this.permissionList.length>0}requestPermissionList(){this.handle.serverConnection.sendCommand("permissionlist")}onPermissionList(json){this.permissionList=[];let group=log.group(log.LogType.TRACE,LogCategory.PERMISSIONS,"Permission mapping");for(let e of json){if(e.group_id_end)continue;let perm=new PermissionInfo;perm.name=e.permname,perm.id=parseInt(e.permid),perm.description=e.permdesc,group.log("%i <> %s -> %s",perm.id,perm.name,perm.description),this.permissionList.push(perm)}group.end(),log.info(LogCategory.PERMISSIONS,"Got %i permissions",this.permissionList.length),this._cacheNeededPermissions&&this.onNeededPermissions(this._cacheNeededPermissions);for(let listener of this.initializedListener)listener(!0)}onNeededPermissions(json){if(0==this.permissionList.length)return log.warn(LogCategory.PERMISSIONS,"Got needed permissions but don't have a permission list!"),void(this._cacheNeededPermissions=json);this._cacheNeededPermissions=void 0;let copy=this.neededPermissions.slice(),addcount=0,group=log.group(log.LogType.TRACE,LogCategory.PERMISSIONS,"Got "+json.length+" needed permissions.");for(let e of json){let entry=void 0;for(let p of copy)if(p.type.id==e.permid){entry=p,copy.remove(p);break}if(!entry){let info=this.resolveInfo(e.permid);if(!info){log.warn(LogCategory.PERMISSIONS,"Could not resolve perm for id %s (%o|%o)",e.permid,e,info);continue}entry=new NeededGrantedPermission(info,-2),this.neededPermissions.push(entry),addcount++}if(entry.value!=parseInt(e.permvalue)){entry.value=parseInt(e.permvalue),group.log("Update needed permission "+entry.type.name+" to "+entry.value);for(let listener of entry.changeListener)listener(entry.value)}}group.end(),log.debug(LogCategory.PERMISSIONS,"Dropping "+copy.length+" needed permissions and added "+addcount+" permissions.");for(let e of copy){e.value=-2;for(let listener of e.changeListener)listener(e.value)}}resolveInfo(key){for(let perm of this.permissionList)if(perm.id==key||perm.name==key)return perm}neededPermission(key){for(let perm of this.neededPermissions)if(perm.type.id==key||perm.type.name==key||perm.type==key)return perm;log.debug(LogCategory.PERMISSIONS,"Could not resolve grant permission %o. Creating a new one.",key);let info=key instanceof PermissionInfo?key:this.resolveInfo(key);if(!info)return void log.warn(LogCategory.PERMISSIONS,"Requested needed permission with invalid key! (%o)",key);let result=new NeededGrantedPermission(info,-2);return this.neededPermissions.push(result),result}}!function(GroupType){GroupType[GroupType.QUERY=0]="QUERY",GroupType[GroupType.TEMPLATE=1]="TEMPLATE",GroupType[GroupType.NORMAL=2]="NORMAL"}(GroupType||(GroupType={})),function(GroupTarget){GroupTarget[GroupTarget.SERVER=0]="SERVER",GroupTarget[GroupTarget.CHANNEL=1]="CHANNEL"}(GroupTarget||(GroupTarget={}));class Group{constructor(handle,id,target,type,name){this.properties={iconid:0},this.requiredModifyPower=0,this.requiredMemberAddPower=0,this.requiredMemberRemovePower=0,this.handle=handle,this.id=id,this.target=target,this.type=type,this.name=name}updateProperty(key,value){if(this.properties[key]=value,"iconid"==key){const _this=this;console.log("Icon id "+_this.properties.iconid),this.handle.handle.channelTree.clientsByGroup(this).forEach(client=>{client.updateGroupIcon(_this)})}}}class GroupManager{constructor(client){this.serverGroups=[],this.channelGroups=[],this.handle=client,this.handle.serverConnection.commandHandler.notifyservergrouplist=this.onServerGroupList.bind(this),this.handle.serverConnection.commandHandler.notifychannelgrouplist=this.onServerGroupList.bind(this)}requestGroups(){this.handle.serverConnection.sendCommand("servergrouplist"),this.handle.serverConnection.sendCommand("channelgrouplist")}serverGroup(id){for(let group of this.serverGroups)if(group.id==id)return group}channelGroup(id){for(let group of this.channelGroups)if(group.id==id)return group}onServerGroupList(json){let target;if(json[0].sgid)target=GroupTarget.SERVER;else{if(!json[0].cgid)return void console.error("Could not resolve group target! => "+json[0]);target=GroupTarget.CHANNEL}target==GroupTarget.SERVER?this.serverGroups=[]:this.channelGroups=[];for(let groupData of json){let type;switch(Number.parseInt(groupData.type)){case 0:type=GroupType.TEMPLATE;break;case 1:type=GroupType.NORMAL;break;case 2:type=GroupType.QUERY;break;default:console.error("Invalid group type: "+groupData.type+" for group "+groupData.name);continue}let group=new Group(this,target==GroupTarget.SERVER?groupData.sgid:groupData.cgid,target,type,groupData.name);for(let key in groupData)"sgid"!=key&&"cgid"!=key&&"type"!=key&&"name"!=key&&group.updateProperty(key,groupData[key]);group.requiredMemberRemovePower=groupData.n_member_removep,group.requiredMemberAddPower=groupData.n_member_addp,group.requiredModifyPower=groupData.n_modifyp,target==GroupTarget.SERVER?this.serverGroups.push(group):this.channelGroups.push(group)}console.log("Got "+json.length+" new "+target+" groups:")}}if("undefined"!=typeof customElements){class X_Tab extends HTMLElement{}class X_Entry extends HTMLElement{}class X_Tag extends HTMLElement{}class X_Content extends HTMLElement{}customElements.define("x-tab",X_Tab,{extends:"div"}),customElements.define("x-entry",X_Entry,{extends:"div"}),customElements.define("x-tag",X_Tag,{extends:"div"}),customElements.define("x-content",X_Content,{extends:"div"})}else console.warn("Could not defied tab customElements!");var DisconnectReason,ConnectionState,ViewReasonId,IdentitifyType,TSIdentityHelper,ChatType,LogCategory,log,Modals,CodecWorkerType,TabFunctions={tabify(template){console.log("Tabify:"),console.log(template);let tag=$.spawn("div");tag.addClass("tab");let header=$.spawn("div");header.addClass("tab-header");let content=$.spawn("div");content.addClass("tab-content");let silentContent=$.spawn("div");return silentContent.addClass("tab-content-invisible"),template.find("x-entry").each(function(){let hentry=$.spawn("div");hentry.addClass("entry"),hentry.append($(this).find("x-tag").clone(!0,!0));const _entryContent=$(this).find("x-content").clone(!0,!0);silentContent.append(_entryContent),hentry.on("click",function(){hentry.hasClass("selected")||(tag.find(".tab-header .selected").removeClass("selected"),hentry.addClass("selected"),content.children().appendTo(silentContent),console.log(silentContent),content.empty(),content.append(_entryContent))}),console.log(this),header.append(hentry)}),header.find(".entry").first().trigger("click"),tag.append(header),tag.append(content),tag.append(silentContent),tag}};$.fn.asTabWidget||($.fn.asTabWidget=function(){if("X-TAB"==$(this).prop("tagName"))return TabFunctions.tabify($(this));throw"Invalid tag! "+$(this).prop("tagName")}),$.fn.tabify||($.fn.tabify=function(){try{let self=this.asTabWidget();this.replaceWith(self)}catch(object){}return this.find("x-tab").each(function(){$(this).replaceWith($(this).asTabWidget())}),this}),function(Modals){Modals.spawnSettingsModal=function(){let modal;(modal=createModal({header:"Settings",body:()=>{let template=$("#tmpl_settings").tmpl();return template=$.spawn("div").append(template),function(modal,tag){!function(modal,tag){let currentVAD=settings.global("vad_type");tag.find('input[type=radio][name="vad_type"]').change(function(){switch(tag.find(".vad_settings .vad_type").text($(this).attr("display")),tag.find(".vad_settings .vad_type_settings").hide(),tag.find(".vad_settings .vad_type_"+this.value).show(),settings.changeGlobal("vad_type",this.value),globalClient.voiceConnection.voiceRecorder.reinitialiseVAD(),this.value){case"ppt":let keyCode=parseInt(settings.global("vad_ppt_key",84..toString()));tag.find(".vat_ppt_key").text(String.fromCharCode(keyCode));break;case"vad":let slider=tag.find(".vad_vad_slider"),vad=globalClient.voiceConnection.voiceRecorder.getVADHandler();slider.val(vad.percentageThreshold),slider.trigger("change"),globalClient.voiceConnection.voiceRecorder.update(!0),vad.percentage_listener=(per=>{tag.find(".vad_vad_bar_filler").css("width",per+"%")})}}),currentVAD||(currentVAD="ppt");let elm=tag.find('input[type=radio][name="vad_type"][value="'+currentVAD+'"]');elm.attr("checked","true"),tag.find(".vat_ppt_key").click(function(){let modal=createModal({body:"",header:()=>{let head=$.spawn("div");return head.text("Type the key you wish"),head.css("background-color","blue"),head},footer:""});$(document).one("keypress",function(e){console.log("Got key "+e.keyCode),modal.close(),settings.changeGlobal("vad_ppt_key",e.keyCode.toString()),globalClient.voiceConnection.voiceRecorder.reinitialiseVAD(),tag.find(".vat_ppt_key").text(String.fromCharCode(e.keyCode))}),modal.open()});let slider=tag.find(".vad_vad_slider");slider.on("input change",()=>{settings.changeGlobal("vad_threshold",slider.val().toString());let vad=globalClient.voiceConnection.voiceRecorder.getVADHandler();vad instanceof VoiceActivityDetectorVAD&&(vad.percentageThreshold=slider.val()),tag.find(".vad_vad_slider_value").text(slider.val().toString())}),modal.properties.registerCloseListener(()=>{let vad=globalClient.voiceConnection.voiceRecorder.getVADHandler();vad instanceof VoiceActivityDetectorVAD&&(vad.percentage_listener=void 0)}),elm.trigger("change"),console.log(tag);let mselect=tag.find(".voice_microphone_select");console.log(mselect);let mselectError=tag.find(".voice_microphone_select_error");navigator.mediaDevices.enumerateDevices().then(devices=>{let currentDeviceId,currentStream=globalClient.voiceConnection.voiceRecorder.getMediaStream();if(currentStream){let audio=currentStream.getAudioTracks()[0];currentDeviceId=audio.getSettings().deviceId}console.log("Got "+devices.length+" devices:");for(let device of devices)if(console.log(device),"audioinput"==device.kind){let dtag=$.spawn("option");dtag.attr("device-id",device.deviceId),dtag.attr("device-group",device.groupId),dtag.text(device.label),mselect.append(dtag),currentDeviceId&&device.deviceId==currentDeviceId&&mselect.attr("selected","")}}).catch(error=>{console.error("Could not enumerate over devices!"),console.error(error),mselectError.text("Could not get device list!").show()}),mselect.change(event=>{let deviceSelected=mselect.find("option:selected"),deviceId=deviceSelected.attr("device-id");console.log("Selected device: "+deviceId),globalClient.voiceConnection.voiceRecorder.changeDevice(deviceId)})}(modal,tag.find(".settings_voice"))}(modal,template=template.tabify()),template},footer:()=>{let footer=$.spawn("div");footer.addClass("modal-button-group"),footer.css("margin-top","5px"),footer.css("margin-bottom","5px"),footer.css("text-align","right");let buttonOk=$.spawn("button");return buttonOk.text("Ok"),buttonOk.click(()=>modal.close()),footer.append(buttonOk),footer},width:750})).open()}}(Modals||(Modals={}));class ControlBar{constructor(handle,htmlTag){this.handle=handle,this.htmlTag=htmlTag}initialise(){this.htmlTag.find(".btn_connect").click(this.onConnect.bind(this)),this.htmlTag.find(".btn_client_away").click(this.onAway.bind(this)),this.htmlTag.find(".btn_mute_input").click(this.onInputMute.bind(this)),this.htmlTag.find(".btn_mute_output").click(this.onOutputMute.bind(this)),this.htmlTag.find(".btn_open_settings").click(this.onOpenSettings.bind(this)),this.muteInput="1"==settings.global("mute_input"),this.muteOutput="1"==settings.global("mute_output")}onAway(){this.away=!this._away}onInputMute(){this.muteInput=!this._muteInput}onOutputMute(){this.muteOutput=!this._muteOutput}set muteInput(flag){if(this._muteInput==flag)return;this._muteInput=flag;let tag=this.htmlTag.find(".btn_mute_input");flag?(tag.hasClass("activated")||tag.addClass("activated"),tag.find(".icon_x32").attr("class","icon_x32 client-input_muted")):(tag.hasClass("activated")&&tag.removeClass("activated"),tag.find(".icon_x32").attr("class","icon_x32 client-capture")),this.handle.serverConnection.connected&&this.handle.serverConnection.sendCommand("clientupdate",{client_input_muted:this._muteInput}),settings.changeGlobal("mute_input",this._muteInput),this.updateMicrophoneRecordState()}get muteOutput(){return this._muteOutput}set muteOutput(flag){if(this._muteOutput==flag)return;this._muteOutput=flag;let tag=this.htmlTag.find(".btn_mute_output");flag?(tag.hasClass("activated")||tag.addClass("activated"),tag.find(".icon_x32").attr("class","icon_x32 client-output_muted")):(tag.hasClass("activated")&&tag.removeClass("activated"),tag.find(".icon_x32").attr("class","icon_x32 client-volume")),this.handle.serverConnection.connected&&this.handle.serverConnection.sendCommand("clientupdate",{client_output_muted:this._muteOutput}),settings.changeGlobal("mute_output",this._muteOutput),this.updateMicrophoneRecordState()}set away(value){if("boolean"==typeof value){if(this._away==value)return;this._away=value,this._awayMessage=""}else this._awayMessage=value,this._away=!0;let tag=this.htmlTag.find(".btn_client_away");this._away?tag.hasClass("activated")||tag.addClass("activated"):tag.hasClass("activated")&&tag.removeClass("activated"),this.handle.serverConnection.connected&&this.handle.serverConnection.sendCommand("clientupdate",{client_away:this._away,client_away_message:this._awayMessage}),this.updateMicrophoneRecordState()}updateMicrophoneRecordState(){let enabled=!this._muteInput&&!this._muteOutput&&!this._away;this.handle.voiceConnection.voiceRecorder.update(enabled)}updateProperties(){this.handle.serverConnection.connected&&this.handle.serverConnection.sendCommand("clientupdate",{client_input_muted:this._muteInput,client_output_muted:this._muteOutput,client_away:this._away,client_away_message:this._awayMessage})}onOpenSettings(){Modals.spawnSettingsModal()}onConnect(){Modals.spawnConnectModal(settings.static("connect_default_host","ts.TeaSpeak.de"))}}!function(DisconnectReason){DisconnectReason[DisconnectReason.REQUESTED=0]="REQUESTED",DisconnectReason[DisconnectReason.CONNECT_FAILURE=1]="CONNECT_FAILURE",DisconnectReason[DisconnectReason.CONNECTION_CLOSED=2]="CONNECTION_CLOSED",DisconnectReason[DisconnectReason.CONNECTION_FATAL_ERROR=3]="CONNECTION_FATAL_ERROR",DisconnectReason[DisconnectReason.CONNECTION_PING_TIMEOUT=4]="CONNECTION_PING_TIMEOUT",DisconnectReason[DisconnectReason.CLIENT_KICKED=5]="CLIENT_KICKED",DisconnectReason[DisconnectReason.CLIENT_BANNED=6]="CLIENT_BANNED",DisconnectReason[DisconnectReason.SERVER_CLOSED=7]="SERVER_CLOSED",DisconnectReason[DisconnectReason.UNKNOWN=8]="UNKNOWN"}(DisconnectReason||(DisconnectReason={})),function(ConnectionState){ConnectionState[ConnectionState.UNCONNECTED=0]="UNCONNECTED",ConnectionState[ConnectionState.CONNECTING=1]="CONNECTING",ConnectionState[ConnectionState.INITIALISING=2]="INITIALISING",ConnectionState[ConnectionState.CONNECTED=3]="CONNECTED",ConnectionState[ConnectionState.DISCONNECTING=4]="DISCONNECTING"}(ConnectionState||(ConnectionState={})),function(ViewReasonId){ViewReasonId[ViewReasonId.VREASON_USER_ACTION=0]="VREASON_USER_ACTION",ViewReasonId[ViewReasonId.VREASON_MOVED=1]="VREASON_MOVED",ViewReasonId[ViewReasonId.VREASON_SYSTEM=2]="VREASON_SYSTEM",ViewReasonId[ViewReasonId.VREASON_TIMEOUT=3]="VREASON_TIMEOUT",ViewReasonId[ViewReasonId.VREASON_CHANNEL_KICK=4]="VREASON_CHANNEL_KICK",ViewReasonId[ViewReasonId.VREASON_SERVER_KICK=5]="VREASON_SERVER_KICK",ViewReasonId[ViewReasonId.VREASON_BAN=6]="VREASON_BAN",ViewReasonId[ViewReasonId.VREASON_SERVER_STOPPED=7]="VREASON_SERVER_STOPPED",ViewReasonId[ViewReasonId.VREASON_SERVER_LEFT=8]="VREASON_SERVER_LEFT",ViewReasonId[ViewReasonId.VREASON_CHANNEL_UPDATED=9]="VREASON_CHANNEL_UPDATED",ViewReasonId[ViewReasonId.VREASON_EDITED=10]="VREASON_EDITED",ViewReasonId[ViewReasonId.VREASON_SERVER_SHUTDOWN=11]="VREASON_SERVER_SHUTDOWN"}(ViewReasonId||(ViewReasonId={}));class TSClient{constructor(){this._clientId=0,this.selectInfo=new InfoBar(this,$("#select_info")),this.channelTree=new ChannelTree(this,$("#channelTree")),this.serverConnection=new ServerConnection(this),this.fileManager=new FileManager(this),this.permissions=new PermissionManager(this),this.groups=new GroupManager(this),this.voiceConnection=new VoiceConnection(this),this._ownEntry=new LocalClientEntry(this),this.controlBar=new ControlBar(this,$("#control_bar")),this.channelTree.registerClient(this._ownEntry)}setup(){this.controlBar.initialise()}startConnection(addr,identity,name){this.serverConnection&&this.handleDisconnect(DisconnectReason.REQUESTED);let port,host,idx=addr.lastIndexOf(":");-1!=idx?(port=parseInt(addr.substr(idx+1)),host=addr.substr(0,idx)):(host=addr,port=9987),console.log("Start connection to "+host+":"+port),this.channelTree.initialiseHead(addr),this.serverConnection.startConnection(host,port,new HandshakeHandler(identity,name))}getClient(){return this._ownEntry}getClientId(){return this._clientId}set clientId(id){this._clientId=id,this._ownEntry._clientId=id}get clientId(){return this._clientId}getServerConnection(){return this.serverConnection}onConnected(){console.log("Client connected!"),this.channelTree.registerClient(this._ownEntry),settings.setServer(this.channelTree.server),this.permissions.requestPermissionList(),this.serverConnection.sendCommand("channelsubscribeall"),0==this.groups.serverGroups.length&&this.groups.requestGroups(),this.controlBar.updateProperties()}get connected(){return!!this.serverConnection&&this.serverConnection.connected}handleDisconnect(type,data={}){switch(type){case DisconnectReason.REQUESTED:break;case DisconnectReason.CONNECT_FAILURE:console.error("Could not connect to remote host! Exception"),console.error(data),createErrorModal("Could not connect","Could not connect to remote host (Connection refused)<br>If you're shure that the remot host is up, than you may not allow unsigned certificates.<br>Click <a href='https://"+this.serverConnection._remoteHost+":"+this.serverConnection._remotePort+"'>here</a> to accept the remote certificate").open();break;case DisconnectReason.CONNECTION_CLOSED:console.error("Lost connection to remote server!"),createErrorModal("Connection closed","The connection was closed by remote host").open();break;case DisconnectReason.CONNECTION_PING_TIMEOUT:console.error("Connection ping timeout"),createErrorModal("Connection lost","Lost connection to remote host (Ping timeout)<br>Even possible?").open();break;case DisconnectReason.SERVER_CLOSED:chat.serverChat().appendError("Server closed ({0})",data.reasonmsg),createErrorModal("Server closed","The server is closed.<br>Reason: "+data.reasonmsg).open();break;default:console.error("Got uncaught disconnect!"),console.error("Type: "+type+" Data:"),console.error(data)}this.selectInfo.currentSelected=null,this.channelTree.reset(),this.voiceConnection.dropSession(),this.serverConnection&&this.serverConnection.disconnect()}}class FileEntry{}class FileListRequest{}class DownloadFileTransfer{constructor(handle,id){this.currentSize=0,this.on_start=(()=>{}),this.on_complete=(()=>{}),this.on_fail=(_=>{}),this.on_data=(_=>{}),this.transferId=id,this._handle=handle}startTransfer(){this.remoteHost&&this.remotePort&&this.transferKey&&this.totalSize?(console.debug("Create new file download to "+this.remoteHost+":"+this.remotePort+" (Key: "+this.transferKey+", Expect "+this.totalSize+" bytes)"),this._active=!0,this._socket=new WebSocket("wss://"+this.remoteHost+":"+this.remotePort),this._socket.onopen=this.onOpen.bind(this),this._socket.onclose=this.onClose.bind(this),this._socket.onmessage=this.onMessage.bind(this),this._socket.onerror=this.onError.bind(this)):this.on_fail("Missing data!")}onOpen(){this._active&&(this._socket.send(this.transferKey),this.on_start())}onMessage(data){if(!this._active)return void console.error("Got data, but socket closed?");this._parseActive=!0;let fileReader=new FileReader;fileReader.onload=(event=>{this.onBinaryData(new Uint8Array(event.target.result)),this._parseActive=!1}),fileReader.readAsArrayBuffer(data.data)}onBinaryData(data){this.currentSize+=data.length,this.on_data(data),this.currentSize==this.totalSize&&(this._succeed=!0,this.on_complete(),this.disconnect())}onError(){this._active&&(this.on_fail("an error occurent"),this.disconnect())}onClose(){this._active&&(this._parseActive||this.on_fail("unexpected close (remote closed)"),this.disconnect())}disconnect(){this._active=!1}}class FileManager{constructor(client){this.listRequests=[],this.pendingDownloadTransfers=[],this.downloadCounter=0,this.handle=client,this.icons=new IconManager(this),this.avatars=new AvatarManager(this),this.handle.serverConnection.commandHandler.notifyfilelist=this.notifyFileList.bind(this),this.handle.serverConnection.commandHandler.notifyfilelistfinished=this.notifyFileListFinished.bind(this),this.handle.serverConnection.commandHandler.notifystartdownload=this.notifyStartDownload.bind(this)}requestFileList(path,channel,password){const _this=this;return new Promise((accept,reject)=>{let req=new FileListRequest;req.path=path,req.entries=[],req.callback=accept,_this.listRequests.push(req),_this.handle.serverConnection.sendCommand("ftgetfilelist",{path:path,cid:channel?channel.channelId:"0",cpw:password||""}).then(()=>{}).catch(reason=>{_this.listRequests.remove(req),reason instanceof CommandResult&&1281==reason.id?accept([]):reject(reason)})})}notifyFileList(json){let entry=void 0;for(let e of this.listRequests)if(e.path==json[0].path){entry=e;break}if(entry)for(let e of json)entry.entries.push(e);else console.error("Invalid file list entry. Path: "+json[0].path)}notifyFileListFinished(json){let entry=void 0;for(let e of this.listRequests)if(e.path==json[0].path){entry=e,this.listRequests.remove(e);break}entry?entry.callback(entry.entries):console.error("Invalid file list entry finish. Path: "+json[0].path)}requestFileDownload(path,file,channel,password){const _this=this;let transfer=new DownloadFileTransfer(this,this.downloadCounter++);return this.pendingDownloadTransfers.push(transfer),new Promise((resolve,reject)=>{transfer._promiseCallback=resolve,_this.handle.serverConnection.sendCommand("ftinitdownload",{path:path,name:file,cid:channel?channel.channelId:"0",cpw:password||"",clientftfid:transfer.transferId}).catch(reason=>{_this.pendingDownloadTransfers.remove(transfer),reject(reason)})})}notifyStartDownload(json){let transfer;json=json[0];for(let e of this.pendingDownloadTransfers)if(e.transferId==json.clientftfid){transfer=e;break}transfer.serverTransferId=json.serverftfid,transfer.transferKey=json.ftkey,transfer.totalSize=json.size,transfer.remotePort=json.port,transfer.remoteHost=json.ip.replace(/,/g,""),"0.0.0.0"!=transfer.remoteHost&&"127.168.0.0"!=transfer.remoteHost||(transfer.remoteHost=this.handle.serverConnection._remoteHost),transfer._promiseCallback(transfer),this.pendingDownloadTransfers.remove(transfer)}}class Icon{}class IconManager{constructor(handle){this.handle=handle}iconList(){return this.handle.requestFileList("/icons")}downloadIcon(id){return this.handle.requestFileDownload("","/icon_"+id)}resolveCached(id){let icon=localStorage.getItem("icon_"+id);if(icon){let i=JSON.parse(icon);if(i.base64.length>0)return i}}loadIcon(id){const _this=this;return new Promise((resolve,reject)=>{let icon=this.resolveCached(id);icon?resolve(icon):_this.downloadIcon(id).then(ft=>{let array=new Uint8Array(0);ft.on_fail=(reason=>{console.error("Could not download icon "+id+" -> "+reason),chat.serverChat().appendError("Fail to download icon {0}. ({1})",id,JSON.stringify(reason)),reject(reason)}),ft.on_start=(()=>{}),ft.on_data=(data=>{array=concatenate(Uint8Array,array,data)}),ft.on_complete=(()=>{let base64=btoa(String.fromCharCode.apply(null,array)),icon=new Icon;icon.base64=base64,icon.id=id,icon.name="icon_"+id,localStorage.setItem("icon_"+id,JSON.stringify(icon)),resolve(icon)}),ft.startTransfer()}).catch(reason=>{console.error("Error while downloading icon! ("+JSON.stringify(reason)+")"),chat.serverChat().appendError("Failed to request download for icon {0}. ({1})",id,JSON.stringify(reason)),reject(reason)})})}generateTag(id){if(0==id)return $("<div class='icon_empty'></div>");if(id<1e3)return $("<div class='icon client-group_"+id+"'></div>");let tag=$.spawn("div");tag.addClass("icon_empty");let img=$.spawn("img");img.attr("width",16).attr("height",16).attr("alt","");let icon=this.resolveCached(id);if(icon)img.attr("src","data:image/png;base64,"+icon.base64),tag.append(img);else{img.attr("src","file://null");let loader=$.spawn("div");loader.addClass("icon_loading"),tag.append(loader),this.loadIcon(id).then(icon=>{img.attr("src","data:image/png;base64,"+icon.base64),console.debug("Icon "+id+" loaded :)"),img.css("opacity",0),tag.append(img),loader.animate({opacity:0},50,function(){$(this).detach(),img.animate({opacity:1},150)})}).catch(reason=>{console.error("Could not load icon "+id+". Reason: "+reason),loader.removeClass("icon_loading").addClass("icon client-warning").attr("tag","Could not load icon "+id)})}return tag}}class Avatar{}class AvatarManager{constructor(handle){this.handle=handle}downloadAvatar(client){return this.handle.requestFileDownload("","/avatar_"+client.avatarId())}resolveCached(client){let avatar=localStorage.getItem("avatar_"+client.properties.client_unique_identifier);if(avatar){let i=JSON.parse(avatar);if(i.base64.length>0&&i.avatarId==client.properties.client_flag_avatar)return i}}loadAvatar(client){const _this=this;return new Promise((resolve,reject)=>{let avatar=this.resolveCached(client);avatar?resolve(avatar):_this.downloadAvatar(client).then(ft=>{let array=new Uint8Array(0);ft.on_fail=(reason=>{console.error("Could not download avatar "+client.properties.client_flag_avatar+" -> "+reason),chat.serverChat().appendError("Fail to download avatar for {0}. ({1})",client.clientNickName(),JSON.stringify(reason)),reject(reason)}),ft.on_start=(()=>{}),ft.on_data=(data=>{array=concatenate(Uint8Array,array,data)}),ft.on_complete=(()=>{let base64=btoa(String.fromCharCode.apply(null,array)),avatar=new Avatar;avatar.base64=base64,avatar.clientUid=client.clientUid(),avatar.avatarId=client.properties.client_flag_avatar,localStorage.setItem("avatar_"+client.properties.client_unique_identifier,JSON.stringify(avatar)),resolve(avatar)}),ft.startTransfer()}).catch(reason=>{console.error("Error while downloading avatar! ("+JSON.stringify(reason)+")"),chat.serverChat().appendError("Failed to request avatar download for {0}. ({1})",client.clientNickName(),JSON.stringify(reason)),reject(reason)})})}generateTag(client){let tag=$.spawn("div"),img=$.spawn("img");img.attr("alt","");let avatar=this.resolveCached(client);if(avatar)img.attr("src","data:image/png;base64,"+avatar.base64),tag.append(img);else{img.attr("src","file://null");let loader=$.spawn("div");loader.addClass("avatar_loading"),tag.append(loader),this.loadAvatar(client).then(avatar=>{img.attr("src","data:image/png;base64,"+avatar.base64),console.debug("Avatar "+client.clientNickName()+" loaded :)"),img.css("opacity",0),tag.append(img),loader.animate({opacity:0},50,function(){$(this).detach(),img.animate({opacity:1},150)})}).catch(reason=>{console.error("Could not load avatar for "+client.clientNickName()+". Reason: "+reason),loader.removeClass("avatar_loading").addClass("icon client-warning").attr("tag","Could not load avatar "+client.clientNickName())})}return tag}}!function(IdentitifyType){IdentitifyType[IdentitifyType.TEAFORO=0]="TEAFORO",IdentitifyType[IdentitifyType.TEAMSPEAK=1]="TEAMSPEAK"}(IdentitifyType||(IdentitifyType={})),function(TSIdentityHelper){var Pointer_stringify=Module.Pointer_stringify;let functionLastError,functionDestroyString,functionDestroyIdentity;function unwarpString(str){if(""==str)return"";let message=Pointer_stringify(str);return functionDestroyString(str),message}TSIdentityHelper.setup=function(){return functionDestroyString=Module.cwrap("destroy_string","pointer",[]),functionLastError=Module.cwrap("last_error_message",null,["string"]),TSIdentityHelper.funcationParseIdentity=Module.cwrap("parse_identity","pointer",["string"]),TSIdentityHelper.funcationParseIdentityByFile=Module.cwrap("parse_identity_file","pointer",["string"]),functionDestroyIdentity=Module.cwrap("delete_identity",null,["pointer"]),TSIdentityHelper.funcationCalculateSecurityLevel=Module.cwrap("identity_security_level","pointer",["pointer"]),TSIdentityHelper.funcationExportIdentity=Module.cwrap("identity_export","pointer",["pointer"]),TSIdentityHelper.funcationPublicKey=Module.cwrap("identity_key_public","pointer",["pointer"]),TSIdentityHelper.funcationSignMessage=Module.cwrap("identity_sign","pointer",["pointer","string","number"]),TSIdentityHelper.functionUid=Module.cwrap("identity_uid","pointer",["pointer"]),0==Module.cwrap("tomcrypt_initialize","number",[])()},TSIdentityHelper.last_error=function(){return unwarpString(functionLastError())},TSIdentityHelper.unwarpString=unwarpString,TSIdentityHelper.loadIdentity=function(key){let handle=TSIdentityHelper.funcationParseIdentity(key);if(handle)return new TeamSpeakIdentity(handle,"TeaWeb user")},TSIdentityHelper.loadIdentityFromFileContains=function(contains){let handle=TSIdentityHelper.funcationParseIdentityByFile(contains);if(handle)return new TeamSpeakIdentity(handle,"TeaWeb user")}}(TSIdentityHelper||(TSIdentityHelper={}));class TeamSpeakIdentity{constructor(handle,name){this.handle=handle,this._name=name}securityLevel(){return parseInt(TSIdentityHelper.unwarpString(TSIdentityHelper.funcationCalculateSecurityLevel(this.handle)))}name(){return this._name}uid(){return TSIdentityHelper.unwarpString(TSIdentityHelper.functionUid(this.handle))}type(){return IdentitifyType.TEAMSPEAK}signMessage(message){return TSIdentityHelper.unwarpString(TSIdentityHelper.funcationSignMessage(this.handle,message,message.length))}exported(){return TSIdentityHelper.unwarpString(TSIdentityHelper.funcationExportIdentity(this.handle))}publicKey(){return TSIdentityHelper.unwarpString(TSIdentityHelper.funcationPublicKey(this.handle))}}class TeaForumIdentity{constructor(data,sign){this.identityDataJson=data,this.identityData=JSON.parse(this.identityDataJson),this.identitySign=sign}name(){return this.identityData.user_name}uid(){return"TeaForo#"+this.identityData.user_id}type(){return IdentitifyType.TEAFORO}}!function(ChatType){ChatType[ChatType.GENERAL=0]="GENERAL",ChatType[ChatType.SERVER=1]="SERVER",ChatType[ChatType.CHANNEL=2]="CHANNEL",ChatType[ChatType.CLIENT=3]="CLIENT"}(ChatType||(ChatType={}));class ChatMessage{constructor(message){this.date=new Date,this.message=message}num(num){let str=num.toString();for(;str.length<2;)str="0"+str;return str}get htmlTag(){if(this._htmlTag)return this._htmlTag;let tag=$.spawn("div");tag.addClass("message");let dateTag=$.spawn("div");dateTag.text("<"+this.num(this.date.getUTCHours())+":"+this.num(this.date.getUTCMinutes())+":"+this.num(this.date.getUTCSeconds())+"> "),dateTag.css("margin-right","4px"),dateTag.css("color","dodgerblue");let messageTag=$.spawn("div");return messageTag.html(this.message),messageTag.css("color","blue"),this._htmlTag=tag,tag.append(dateTag),tag.append(messageTag),tag.hide(),tag}static formatMessage(message){const div=document.createElement("div");return div.innerText=message,message=div.innerHTML,console.log(message+"->"+div.innerHTML),message}}class ChatEntry{constructor(handle,type,key){this.handle=handle,this.type=type,this.key=key,this._name=key,this.history=[],this.onClose=function(){return!0}}appendError(message,...args){this.appendMessage("<a style='color: red'>{0}</a>".format(ChatMessage.formatMessage(message).format(...args)),!1)}appendMessage(message,fmt=!0,...args){let parms=[];for(let index=2;index<arguments.length;index++)"string"==typeof arguments[index]?arguments[index]=ChatMessage.formatMessage(arguments[index]):arguments[index]instanceof jQuery?arguments[index]=arguments[index].html():(console.error("Invalid type "+typeof arguments[index]+"|"+arguments[index].prototype),arguments[index]=arguments[index].toString()),parms.push(arguments[index]);let msg=fmt?ChatMessage.formatMessage(message):message;msg=msg.format(parms);let elm=new ChatMessage(msg);for(this.history.push(elm);this.history.length>100;){this.history.pop_front().htmlTag.animate({opacity:0},200,function(){$(this).detach()})}if(this.handle.activeChat===this){let box=$(this.handle.htmlTag).find(".messages"),mbox=$(this.handle.htmlTag).find(".message_box"),bottom=box.scrollTop()+box.height()+1>=mbox.height();mbox.append(elm.htmlTag),elm.htmlTag.show().css("opacity","0").animate({opacity:1},100),bottom&&box.scrollTop(mbox.height())}else this.unread=!0}displayHistory(){this.unread=!1;let box=$(this.handle.htmlTag).find(".messages"),mbox=$(this.handle.htmlTag).find(".message_box");mbox.empty();for(let e of this.history)mbox.append(e.htmlTag),e.htmlTag.is(":hidden")&&e.htmlTag.show();box.scrollTop(mbox.height())}get htmlTag(){if(this._htmlTag)return this._htmlTag;let tag=$.spawn("div");tag.addClass("chat"),tag.append('<div class="chatIcon icon clicon '+this.chatIcon()+'"></div>'),tag.append("<a class='name'>"+this._name+"</a>");let closeTag=$.spawn("div");closeTag.addClass("btn_close icon client-tab_close_button"),this._closeable||closeTag.hide(),tag.append(closeTag);const _this=this;return tag.click(function(){_this.handle.activeChat=_this}),tag.on("contextmenu",function(e){e.preventDefault();let actions=[];actions.push({type:MenuEntryType.ENTRY,icon:"",name:"Clear",callback:()=>{_this.history=[],_this.displayHistory()}}),_this.closeable&&actions.push({type:MenuEntryType.ENTRY,icon:"client-tab_close_button",name:"Close",callback:()=>{chat.deleteChat(_this)}}),actions.push({type:MenuEntryType.ENTRY,icon:"client-tab_close_button",name:"Close all private tabs",callback:()=>{}}),spawnMenu(e.pageX,e.pageY,...actions)}),closeTag.click(function(){$.isFunction(_this.onClose)&&!_this.onClose()||_this.handle.deleteChat(_this)}),this._htmlTag=tag,tag}set name(newName){console.log("Change name!"),this._name=newName,this.htmlTag.find(".name").text(this._name)}set closeable(flag){this._closeable!=flag&&(this._closeable=flag,console.log("Set closeable: "+this._closeable),flag?this.htmlTag.find(".btn_close").show():this.htmlTag.find(".btn_close").hide())}set unread(flag){this._unread!=flag&&(this._unread=flag,this.htmlTag.find(".chatIcon").attr("class","chatIcon icon clicon "+this.chatIcon()),flag?this.htmlTag.find(".name").css("color","blue"):this.htmlTag.find(".name").css("color","black"))}chatIcon(){if(this._unread)switch(this.type){case ChatType.CLIENT:return"client-new_chat"}switch(this.type){case ChatType.SERVER:return"client-server_log";case ChatType.CHANNEL:return"client-channel_chat";case ChatType.CLIENT:return"client-player_chat";case ChatType.GENERAL:return"client-channel_chat"}return""}}class ChatBox{constructor(htmlTag){this.htmlTag=htmlTag,this.htmlTag.find(".input button").click(this.onSend.bind(this)),this.htmlTag.find(".input_box").keypress(event=>{if(13==event.keyCode&&!event.shiftKey)return this.onSend(),!1}).on("input",event=>{let text=$(event.target).val().toString();this.testMessage(text)?this.htmlTag.find(".input button").removeAttr("disabled"):this.htmlTag.find(".input button").attr("disabled","true")}).trigger("input"),this.chats=[],this._activeChat=void 0,this.createChat("chat_server",ChatType.SERVER).onMessageSend=(text=>{globalClient.serverConnection?globalClient.serverConnection.sendMessage(text,ChatType.SERVER):chat.serverChat().appendError("Could not send chant message (Not connected)")}),this.createChat("chat_channel",ChatType.CHANNEL).onMessageSend=(text=>{globalClient.serverConnection?globalClient.serverConnection.sendMessage(text,ChatType.CHANNEL,globalClient.getClient().currentChannel()):chat.channelChat().appendError("Could not send chant message (Not connected)")}),globalClient.permissions.initializedListener.push(flag=>{flag&&this.activeChat0(this._activeChat)})}createChat(key,type=ChatType.CLIENT){let chat=new ChatEntry(this,type,key);return this.chats.push(chat),this.htmlTag.find(".chats").append(chat.htmlTag),this._activeChat||(this.activeChat=chat),chat}findChat(key){for(let e of this.chats)if(e.key==key)return e}deleteChat(chat){this.chats.remove(chat),chat.htmlTag.detach(),this._activeChat===chat&&(this.chats.length>0?this.activeChat=this.chats.last():this.activeChat=void 0)}onSend(){let textBox=$(this.htmlTag).find(".input_box"),text=textBox.val().toString();this.testMessage(text)&&(textBox.val(""),$(this.htmlTag).find(".input_box").trigger("input"),this._activeChat&&$.isFunction(this._activeChat.onMessageSend)&&this._activeChat.onMessageSend(text))}set activeChat(chat){-1!==this.chats.indexOf(chat)&&this._activeChat!=chat&&this.activeChat0(chat)}activeChat0(chat){this._activeChat=chat;for(let e of this.chats)e.htmlTag.removeClass("active");let flagAllowSend=!1;if(this._activeChat&&(this._activeChat.htmlTag.addClass("active"),this._activeChat.displayHistory(),globalClient&&globalClient.permissions&&globalClient.permissions.initialized()))switch(this._activeChat.type){case ChatType.CLIENT:flagAllowSend=!0;break;case ChatType.SERVER:flagAllowSend=globalClient.permissions.neededPermission(PermissionType.B_CLIENT_SERVER_TEXTMESSAGE_SEND).granted(1);break;case ChatType.CHANNEL:flagAllowSend=globalClient.permissions.neededPermission(PermissionType.B_CLIENT_CHANNEL_TEXTMESSAGE_SEND).granted(1)}this.htmlTag.find(".input_box").prop("disabled",!flagAllowSend)}get activeChat(){return this._activeChat}channelChat(){return this.findChat("chat_channel")}serverChat(){return this.findChat("chat_server")}focus(){$(this.htmlTag).find(".input_box").focus()}testMessage(message){return(message=message.replace(/ /gi,"").replace(/<br>/gi,"").replace(/\n/gi,"").replace(/<br\/>/gi,"")).length>0}}!function(LogCategory){LogCategory[LogCategory.CHANNEL=0]="CHANNEL",LogCategory[LogCategory.CLIENT=1]="CLIENT",LogCategory[LogCategory.PERMISSIONS=2]="PERMISSIONS",LogCategory[LogCategory.GENERAL=3]="GENERAL",LogCategory[LogCategory.NETWORKING=4]="NETWORKING"}(LogCategory||(LogCategory={})),function(log_1){let LogType;!function(LogType){LogType[LogType.TRACE=0]="TRACE",LogType[LogType.DEBUG=1]="DEBUG",LogType[LogType.INFO=2]="INFO",LogType[LogType.WARNING=3]="WARNING",LogType[LogType.ERROR=4]="ERROR"}(LogType=log_1.LogType||(log_1.LogType={}));let category_mapping=new Map([[LogCategory.CHANNEL,"Channel "],[LogCategory.CLIENT,"Client "],[LogCategory.PERMISSIONS,"Permission "],[LogCategory.GENERAL,"General "],[LogCategory.NETWORKING,"Network "]]);function logDirect(type,message,...optionalParams){switch(type){case LogType.TRACE:case LogType.DEBUG:console.debug(message,...optionalParams);break;case LogType.INFO:console.log(message,...optionalParams);break;case LogType.WARNING:console.warn(message,...optionalParams);break;case LogType.ERROR:console.error(message,...optionalParams)}}function log(type,category,message,...optionalParams){optionalParams.unshift(category_mapping.get(category)),logDirect(type,message="[%s] "+message,...optionalParams)}log_1.log=log,log_1.trace=function(category,message,...optionalParams){log(LogType.TRACE,category,message,...optionalParams)},log_1.debug=function(category,message,...optionalParams){log(LogType.DEBUG,category,message,...optionalParams)},log_1.info=function(category,message,...optionalParams){log(LogType.INFO,category,message,...optionalParams)},log_1.warn=function(category,message,...optionalParams){log(LogType.WARNING,category,message,...optionalParams)},log_1.error=function(category,message,...optionalParams){log(LogType.ERROR,category,message,...optionalParams)},log_1.group=function(level,category,name,...optionalParams){return name="[%s] "+name,optionalParams.unshift(category_mapping.get(category)),new Group(level,category,name,optionalParams)};class Group{constructor(level,category,name,optionalParams,owner){this.owner=void 0,this._collapsed=!0,this.initialized=!1,this.level=level,this.category=category,this.name=name,this.optionalParams=optionalParams}group(level,name,...optionalParams){return new Group(level,this.category,name,optionalParams,this)}collapsed(flag=!0){return this._collapsed=flag,this}log(message,...optionalParams){return this.initialized||(this._collapsed&&console.groupCollapsed?console.groupCollapsed(this.name,...this.optionalParams):console.group(this.name,...this.optionalParams),this.initialized=!0),logDirect(this.level,message,...optionalParams),this}end(){this.initialized&&console.groupEnd()}}log_1.Group=Group}(log||(log={})),function(Modals){Modals.spawnConnectModal=function(defaultHost="ts.TeaSpeak.de"){let connectIdentity;const connectModal=createModal({header:function(){let header=$.spawn("div");return header.text("Create a new connection"),header},body:function(){let tag=$("#tmpl_connect").contents().clone(),updateFields=function(){connectIdentity?tag.find(".connect_nickname").attr("placeholder",connectIdentity.name()):tag.find(".connect_nickname").attr("");let button=tag.parents(".modal-content").find(".connect_connect_button"),field_address=tag.find(".connect_address"),address=field_address.val().toString(),flag_address=!!address.match(Regex.IP_V4)||!!address.match(Regex.DOMAIN),field_nickname=tag.find(".connect_nickname"),nickname=field_nickname.val().toString(),flag_nickname=0==nickname.length||nickname.length>=3&&nickname.length<=32;flag_address?field_address.hasClass("invalid_input")&&field_address.removeClass("invalid_input"):field_address.hasClass("invalid_input")||field_address.addClass("invalid_input"),flag_nickname?field_nickname.hasClass("invalid_input")&&field_nickname.removeClass("invalid_input"):field_nickname.hasClass("invalid_input")||field_nickname.addClass("invalid_input"),flag_nickname&&flag_address&&connectIdentity?button.removeAttr("disabled"):button.attr("disabled","true")};return tag.find(".connect_address").val(defaultHost),tag.find(".connect_address").on("keyup",()=>updateFields()),tag.find(".connect_nickname").on("keyup",()=>updateFields()),tag.find(".identity_select").on("change",function(){settings.changeGlobal("connect_identity_type",this.value),tag.find(".error_message").hide(),tag.find(".identity_config:not(.identity_config_"+this.value+")").hide(),tag.find(".identity_config_"+this.value).show().trigger("shown")}),tag.find(".identity_select").val(settings.global("connect_identity_type","forum")),setTimeout(()=>tag.find(".identity_select").trigger("change"),0),tag.find(".identity_file").change(function(){const reader=new FileReader;reader.onload=function(){connectIdentity=TSIdentityHelper.loadIdentityFromFileContains(reader.result),console.log(connectIdentity.uid()),connectIdentity?(tag.find(".identity_string").val(connectIdentity.exported()),settings.changeGlobal("connect_identity_teamspeak_identity",connectIdentity.exported())):tag.find(".error_message").text("Could not read identity! "+TSIdentityHelper.last_error()),(connectIdentity?tag.hide:tag.show).apply(tag.find(".error_message")),updateFields()},reader.onerror=(ev=>{tag.find(".error_message").text("Could not read identity file!").show(),updateFields()}),reader.readAsText(this.files[0])}),tag.find(".identity_string").on("change",function(){0==this.value.length?tag.find(".error_message").text("Please select an identity!"):(connectIdentity=TSIdentityHelper.loadIdentity(this.value))?settings.changeGlobal("connect_identity_teamspeak_identity",this.value):tag.find(".error_message").text("Could not parse identity! "+TSIdentityHelper.last_error()),(connectIdentity?tag.hide:tag.show).apply(tag.find(".error_message")),tag.find(".identity_file").val(""),updateFields()}),tag.find(".identity_string").val(settings.global("connect_identity_teamspeak_identity","")),tag.find(".identity_config_teamspeak").on("shown",ev=>{tag.find(".identity_string").trigger("change")}),forumIdentity||tag.find(".identity_config_forum").html("You cant use your TeaSpeak forum account.<br>You're not connected!"),tag.find(".identity_config_forum").on("shown",ev=>{connectIdentity=forumIdentity,updateFields()}),tag},footer:function(){let tag=$.spawn("div");tag.css("text-align","right"),tag.css("margin-top","3px"),tag.css("margin-bottom","6px"),tag.addClass("modal-button-group");let button=$.spawn("button");return button.addClass("connect_connect_button"),button.text("Connect"),button.on("click",function(){connectModal.close();let address=tag.parents(".modal-content").find(".connect_address").val().toString();globalClient.startConnection(address,connectIdentity,tag.parents(".modal-content").find(".connect_nickname").val().toString())}),tag.append(button),tag},width:600});connectModal.open()};let Regex={DOMAIN:/^(localhost|((([a-zA-Z0-9_-]{0,63}\.){0,253})?[a-zA-Z0-9_-]{0,63}\.[a-zA-Z]{2,5}))(|:(6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|6[0-4][0-9]{3}|[0-5]?[0-9]{1,4}))$/,IP_V4:/(^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))(|:(6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|6[0-4][0-9]{3}|[0-5]?[0-9]{1,4}))$/,IP_V6:/(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))/,IP:/^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$|^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])$|^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/}}(Modals||(Modals={}));class BasicCodec{constructor(codecSampleRate){this.on_encoded_data=($=>{}),this.channelCount=1,this.samplesPerUnit=960,this.channelCount=1,this.samplesPerUnit=960,this._audioContext=new OfflineAudioContext(1,1024,44100),this._codecSampleRate=codecSampleRate,this._decodeResampler=new AudioResampler(AudioController.globalContext.sampleRate),this._encodeResampler=new AudioResampler(codecSampleRate)}encodeSamples(cache,pcm){this._encodeResampler.resample(pcm).then(buffer=>this.encodeSamples0(cache,buffer)).catch(error=>console.error("Could not resample PCM data for codec. Error:"+error))}encodeSamples0(cache,buffer){for(cache._chunks.push(new BufferChunk(buffer));cache.bufferedSamples(this.samplesPerUnit)>=this.samplesPerUnit;){let buffer=this._audioContext.createBuffer(this.channelCount,this.samplesPerUnit,this._codecSampleRate),index=0;for(;index<this.samplesPerUnit;){let buf=cache._chunks[0],cpyBytes=buf.copyRangeTo(buffer,this.samplesPerUnit-index,index);index+=cpyBytes,buf.index+=cpyBytes,buf.index==buf.buffer.length&&cache._chunks.pop_front()}let encodeBegin=(new Date).getTime();this.encode(buffer).then(result=>{result instanceof Uint8Array?((new Date).getTime()-20>encodeBegin&&console.error("Required time: %d",(new Date).getTime()-encodeBegin),this.on_encoded_data(result)):console.error("[Codec]["+this.name()+"] Could not encode buffer. Result: "+result)})}return!0}decodeSamples(cache,data){return this.decode(data).then(buffer=>this._decodeResampler.resample(buffer))}}!function(CodecWorkerType){CodecWorkerType[CodecWorkerType.WORKER_OPUS=0]="WORKER_OPUS"}(CodecWorkerType||(CodecWorkerType={}));class CodecWrapper extends BasicCodec{constructor(type,channelCount){super(48e3),this._workerListener=[],this._workerCallbackToken="callback_token",this._workerTokeIndex=0,this._initialized=!1,this.type=type,this.channelCount=channelCount}name(){return"Worker for "+CodecWorkerType[this.type]+" Channels "+this.channelCount}initialise(){return this._initializePromise?this._initializePromise:this._initializePromise=this.spawnWorker().then(()=>new Promise((resolve,reject)=>{const token=this.generateToken();this.sendWorkerMessage({command:"initialise",type:this.type,channelCount:this.channelCount,token:token}),this._workerListener.push({token:token,resolve:data=>{console.log("Init result: %o",data),this._initialized=1==data.success,1==data.success?resolve():reject(data.message)}})}))}initialized(){return this._initialized}deinitialise(){this.sendWorkerMessage({command:"deinitialise"})}decode(data){let token=this.generateToken(),result=new Promise((resolve,reject)=>{this._workerListener.push({token:token,resolve:data=>{if(data.success){let array=new Float32Array(data.dataLength);for(let index=0;index<array.length;index++)array[index]=data.data[index];let audioBuf=this._audioContext.createBuffer(this.channelCount,array.length/this.channelCount,this._codecSampleRate);for(let channel=0;channel<this.channelCount;channel++)for(let offset=0;offset<audioBuf.length;offset++)audioBuf.getChannelData(channel)[offset]=array[channel*audioBuf.length+offset];resolve(audioBuf)}else reject(data.message)}})});return this.sendWorkerMessage({command:"decodeSamples",token:token,data:data,dataLength:data.length}),result}encode(data){let token=this.generateToken(),result=new Promise((resolve,reject)=>{this._workerListener.push({token:token,resolve:data=>{if(data.success){let array=new Uint8Array(data.dataLength);for(let index=0;index<array.length;index++)array[index]=data.data[index];resolve(array)}else reject(data.message)}})}),buffer=new Float32Array(this.channelCount*data.length);for(let offset=0;offset<data.length;offset++)for(let channel=0;channel<this.channelCount;channel++)buffer[offset*this.channelCount+channel]=data.getChannelData(channel)[offset];return this.sendWorkerMessage({command:"encodeSamples",token:token,data:buffer,dataLength:buffer.length}),result}reset(){return this.sendWorkerMessage({command:"reset"}),!0}generateToken(){return this._workerTokeIndex+++"_token"}sendWorkerMessage(message,transfare){this._worker.postMessage(JSON.stringify(message),transfare)}onWorkerMessage(message){if(message.token){if(message.token==this._workerCallbackToken)return"loaded"==message.type?(console.log("[Codec] Got worker init response: Success: %o Message: %o",message.success,message.message),message.success?this._workerCallbackResolve&&this._workerCallbackResolve():this._workerCallbackReject&&this._workerCallbackReject(message.message),this._workerCallbackReject=void 0,void(this._workerCallbackResolve=void 0)):void console.log("Costume callback! (%o)",message);for(let entry of this._workerListener)if(entry.token==message.token)return entry.resolve(message),void this._workerListener.remove(entry);console.error("Could not find worker token entry! ("+message.token+")")}else console.error("Invalid worker token!")}spawnWorker(){return new Promise((resolve,reject)=>{this._workerCallbackReject=reject,this._workerCallbackResolve=resolve,this._worker=new Worker(settings.static("worker_directory","js/workers/")+"WorkerCodec.js"),this._worker.onmessage=(event=>this.onWorkerMessage(JSON.parse(event.data)))})}}let settings,globalClient,chat,forumIdentity;function main(){AudioController.initializeAudioController(),TSIdentityHelper.setup()?(settings=new Settings,globalClient=new TSClient,settings.static("forum_user_data")&&(forumIdentity=new TeaForumIdentity(settings.static("forum_user_data"),settings.static("forum_user_sign"))),chat=new ChatBox($("#chat")),globalClient.setup(),settings.static(Settings.KEY_DISABLE_UNLOAD_DIALOG,!1)||window.addEventListener("beforeunload",function(event){globalClient.serverConnection&&globalClient.serverConnection.connected&&(event.returnValue="Are you really sure?<br>You're still connected!")}),settings.static("default_connect_url")&&(settings.static("default_connect_type","forum")?globalClient.startConnection(settings.static("default_connect_url"),forumIdentity):Modals.spawnConnectModal(settings.static("default_connect_url")))):console.error("Could not setup the TeamSpeak identity parser!")}app.loadedListener.push(()=>main());class RawCodec extends BasicCodec{constructor(codecSampleRate){super(codecSampleRate),this.bufferSize=16384}name(){return"raw"}initialise(){return this.converterRaw=Module._malloc(this.bufferSize),this.converter=new Uint8Array(Module.HEAPU8.buffer,this.converterRaw,this.bufferSize),new Promise(resolve=>resolve())}initialized(){return!0}deinitialise(){}decode(data){return new Promise((resolve,reject)=>{this.converter.set(data);let buf=Module.HEAPF32.slice(this.converter.byteOffset/4,this.converter.byteOffset/4+data.length/4),audioBuf=this._audioContext.createBuffer(1,data.length/4,this._codecSampleRate);audioBuf.copyToChannel(buf,0),resolve(audioBuf)})}encode(data){return new Promise(resolve=>resolve(new Uint8Array(data.getChannelData(0))))}reset(){return!0}}var hex;!function(hex){hex.encode=function(buffer){let hexCodes=[],view=new DataView(buffer);for(let i=0;i<view.byteLength%4;i++){let padding="00000000",paddedValue=(padding+view.getUint32(4*i).toString(16)).slice(-padding.length);hexCodes.push(paddedValue)}for(let i=view.byteLength%4*4;i<view.byteLength;i++){let value=view.getUint8(i).toString(16),padding="00";hexCodes.push((padding+value).slice(-padding.length))}return hexCodes.join("")}}(hex||(hex={}));class ServerEntry{constructor(tree,name){this.properties={virtualserver_name:"",virtualserver_icon_id:0,virtualserver_version:"unknown",virtualserver_platform:"unknown",virtualserver_unique_identifier:"",virtualserver_clientsonline:0,virtualserver_queryclientsonline:0,virtualserver_channelsonline:0,virtualserver_uptime:0,virtualserver_maxclients:0},this.lastInfoRequest=0,this.nextInfoRequest=0,this.channelTree=tree,this.properties.virtualserver_name=name}get htmlTag(){if(this._htmlTag)return this._htmlTag;let tag=$.spawn("div");tag.attr("id","server"),tag.addClass("server"),tag.append($.spawn("div").addClass("server_type icon client-server_green")),tag.append("<a class='name'>"+this.properties.virtualserver_name+"</a>");const serverIcon=$("<span/>");return serverIcon.append("<div class='icon_property icon_empty'></div>"),tag.append(serverIcon),this._htmlTag=tag}initializeListener(){const _this=this;this._htmlTag.click(function(){_this.channelTree.onSelect(_this)}),settings.static(Settings.KEY_DISABLE_CONTEXT_MENU,!1)||this.htmlTag.on("contextmenu",function(event){event.preventDefault(),_this.channelTree.onSelect(_this),_this.spawnContextMenu(event.pageX,event.pageY,()=>{_this.channelTree.onSelect(void 0)})})}spawnContextMenu(x,y,on_close=(()=>{})){spawnMenu(x,y,{type:MenuEntryType.ENTRY,icon:"",name:"test",callback:()=>{}},MenuEntry.CLOSE(on_close))}updateProperty(key,value){console.log("Updating property "+key+" => '"+value+"' for the server"),this.properties[key]=value,"virtualserver_name"==key?this.htmlTag.find(".name").text(value):"virtualserver_icon_id"==key&&this.channelTree.client.fileManager&&this.channelTree.client.fileManager.icons&&this.htmlTag.find(".icon_property").replaceWith(this.channelTree.client.fileManager.icons.generateTag(this.properties.virtualserver_icon_id).addClass("icon_property"))}updateProperties(){this.lastInfoRequest=(new Date).getTime(),this.nextInfoRequest=this.lastInfoRequest+1e4,this.channelTree.client.serverConnection.sendCommand("servergetvariables")}shouldUpdateProperties(){return this.nextInfoRequest<(new Date).getTime()}calculateUptime(){return 0==this.properties.virtualserver_uptime||0==this.lastInfoRequest?Number.parseInt(this.properties.virtualserver_uptime):Number.parseInt(this.properties.virtualserver_uptime)+((new Date).getTime()-this.lastInfoRequest)/1e3}}class AudioResampler{constructor(targetSampleRate=44100){if(this.targetSampleRate=targetSampleRate,this.targetSampleRate<3e3||this.targetSampleRate>384e3)throw"The target sample rate is outside the range [3000, 384000]."}resample(buffer){if(buffer.sampleRate==this.targetSampleRate)return new Promise(resolve=>resolve(buffer));let context,source=(context=new OfflineAudioContext(buffer.numberOfChannels,Math.ceil(buffer.length*this.targetSampleRate/buffer.sampleRate),this.targetSampleRate)).createBufferSource();return source.buffer=buffer,source.connect(context.destination),source.start(0),context.startRendering()}} |