diff --git a/build/couchfriends.api-latest.js b/build/couchfriends.api-latest.js index 3953db5..a146753 100644 --- a/build/couchfriends.api-latest.js +++ b/build/couchfriends.api-latest.js @@ -1,3 +1,5 @@ /*! couchfriends.api 2017-03-09 */ + "use strict";function Emitter(a){if(a)return mixin(a)}function mixin(a){for(var b in Emitter.prototype)a[b]=Emitter.prototype[b];return a}"undefined"!=typeof module&&(module.exports=Emitter),Emitter.prototype.on=Emitter.prototype.addEventListener=function(a,b){return this._callbacks=this._callbacks||{},(this._callbacks["$"+a]=this._callbacks["$"+a]||[]).push(b),this},Emitter.prototype.once=function(a,b){function c(){this.off(a,c),b.apply(this,arguments)}return c.fn=b,this.on(a,c),this},Emitter.prototype.off=Emitter.prototype.removeListener=Emitter.prototype.removeAllListeners=Emitter.prototype.removeEventListener=function(a,b){if(this._callbacks=this._callbacks||{},0==arguments.length)return this._callbacks={},this;var c=this._callbacks["$"+a];if(!c)return this;if(1==arguments.length)return delete this._callbacks["$"+a],this;for(var d,e=0;ee.chunkedMTU)return void this._sendChunks(d);e.supports.sctp?e.supports.binaryBlob?this._bufferedSend(d):e.blobToArrayBuffer(d,function(a){c._bufferedSend(a)}):e.blobToBinaryString(d,function(a){c._bufferedSend(a)})}else this._bufferedSend(a)},d.prototype._bufferedSend=function(a){!this._buffering&&this._trySend(a)||(this._buffer.push(a),this.bufferSize=this._buffer.length)},d.prototype._trySend=function(a){try{this._dc.send(a)}catch(b){this._buffering=!0;var c=this;return setTimeout(function(){c._buffering=!1,c._tryBuffer()},100),!1}return!0},d.prototype._tryBuffer=function(){if(0!==this._buffer.length){var a=this._buffer[0];this._trySend(a)&&(this._buffer.shift(),this.bufferSize=this._buffer.length,this._tryBuffer())}},d.prototype._sendChunks=function(a){for(var b=e.chunk(a),c=0,d=b.length;c2&&200===this.status&&this.responseText&&b._handleStream(this)},this._http.send(null),this._setHTTPTimeout()}catch(c){e.log("XMLHttpRequest not available; defaulting to WebSockets")}},d.prototype._handleStream=function(a){var b=a.responseText.split("\n");if(a._buffer)for(;a._buffer.length>0;){var c=a._buffer.shift(),d=b[c];try{d=JSON.parse(d)}catch(f){a._buffer.shift(c);break}this.emit("message",d)}var g=b[a._index];if(g)if(a._index+=1,a._index===b.length)a._buffer||(a._buffer=[]),a._buffer.push(a._index-1);else{try{g=JSON.parse(g)}catch(f){return void e.log("Invalid server message",g)}this.emit("message",g)}},d.prototype._setHTTPTimeout=function(){var a=this;this._timeout=setTimeout(function(){var b=a._http;a._wsOpen()?b.abort():(a._startXhrStream(b._streamIndex+1),a._http.old=b)},25e3)},d.prototype._wsOpen=function(){return this._socket&&1==this._socket.readyState},d.prototype._sendQueuedMessages=function(){for(var a=0,b=this._queue.length;a0&&(h.error=h._printWith("ERROR")),h.logLevel>1&&(h.warn=h._printWith("WARNING")),h.logLevel>2&&(h.log=h._print)},setLogFunction:function(a){a.constructor!==Function?h.warn("The log function you passed in is not a function. Defaulting to regular logs."):h._print=a},_printWith:function(a){return function(){var b=Array.prototype.slice.call(arguments);b.unshift(a),h._print.apply(h,b)}},_print:function(){var a=!1,b=Array.prototype.slice.call(arguments);b.unshift("PeerJS: ");for(var c=0,d=b.length;c600?new Blob([a]).size:a.replace(/[^\u0000-\u007F]/g,f).length}var h=a("./bufferbuilder").BufferBuilder,i=a("./bufferbuilder").binaryFeatures,j={unpack:function(a){var b=new d(a);return b.unpack()},pack:function(a){var b=new e;b.pack(a);var c=b.getBuffer();return c}};b.exports=j,d.prototype.unpack=function(){var a=this.unpack_uint8();if(a<128){var b=a;return b}if((224^a)<32){var c=(224^a)-32;return c}var d;if((d=160^a)<=15)return this.unpack_raw(d);if((d=176^a)<=15)return this.unpack_string(d);if((d=144^a)<=15)return this.unpack_array(d);if((d=128^a)<=15)return this.unpack_map(d);switch(a){case 192:return null;case 193:return;case 194:return!1;case 195:return!0;case 202:return this.unpack_float();case 203:return this.unpack_double();case 204:return this.unpack_uint8();case 205:return this.unpack_uint16();case 206:return this.unpack_uint32();case 207:return this.unpack_uint64();case 208:return this.unpack_int8();case 209:return this.unpack_int16();case 210:return this.unpack_int32();case 211:return this.unpack_int64();case 212:return;case 213:return;case 214:return;case 215:return;case 216:return d=this.unpack_uint16(),this.unpack_string(d);case 217:return d=this.unpack_uint32(),this.unpack_string(d);case 218:return d=this.unpack_uint16(),this.unpack_raw(d);case 219:return d=this.unpack_uint32(),this.unpack_raw(d);case 220:return d=this.unpack_uint16(),this.unpack_array(d);case 221:return d=this.unpack_uint32(),this.unpack_array(d);case 222:return d=this.unpack_uint16(),this.unpack_map(d);case 223:return d=this.unpack_uint32(),this.unpack_map(d)}},d.prototype.unpack_uint8=function(){var a=255&this.dataView[this.index];return this.index++,a},d.prototype.unpack_uint16=function(){var a=this.read(2),b=256*(255&a[0])+(255&a[1]);return this.index+=2,b},d.prototype.unpack_uint32=function(){var a=this.read(4),b=256*(256*(256*a[0]+a[1])+a[2])+a[3];return this.index+=4,b},d.prototype.unpack_uint64=function(){var a=this.read(8),b=256*(256*(256*(256*(256*(256*(256*a[0]+a[1])+a[2])+a[3])+a[4])+a[5])+a[6])+a[7];return this.index+=8,b},d.prototype.unpack_int8=function(){var a=this.unpack_uint8();return a<128?a:a-256},d.prototype.unpack_int16=function(){var a=this.unpack_uint16();return a<32768?a:a-65536},d.prototype.unpack_int32=function(){var a=this.unpack_uint32();return a>31,c=(a>>23&255)-127,d=8388607&a|8388608;return(0==b?1:-1)*d*Math.pow(2,c-23)},d.prototype.unpack_double=function(){var a=this.unpack_uint32(),b=this.unpack_uint32(),c=a>>31,d=(a>>20&2047)-1023,e=1048575&a|1048576,f=e*Math.pow(2,d-20)+b*Math.pow(2,d-52);return(0==c?1:-1)*f},d.prototype.read=function(a){var b=this.index;if(b+a<=this.length)return this.dataView.subarray(b,b+a);throw new Error("BinaryPackFailure: read index out of range")},e.prototype.getBuffer=function(){return this.bufferBuilder.getBuffer()},e.prototype.pack=function(a){var b=typeof a;if("string"==b)this.pack_string(a);else if("number"==b)Math.floor(a)===a?this.pack_integer(a):this.pack_double(a);else if("boolean"==b)a===!0?this.bufferBuilder.append(195):a===!1&&this.bufferBuilder.append(194);else if("undefined"==b)this.bufferBuilder.append(192);else{if("object"!=b)throw new Error('Type "'+b+'" not yet supported');if(null===a)this.bufferBuilder.append(192);else{var c=a.constructor;if(c==Array)this.pack_array(a);else if(c==Blob||c==File)this.pack_bin(a);else if(c==ArrayBuffer)i.useArrayBufferView?this.pack_bin(new Uint8Array(a)):this.pack_bin(a);else if("BYTES_PER_ELEMENT"in a)i.useArrayBufferView?this.pack_bin(new Uint8Array(a.buffer)):this.pack_bin(a.buffer);else if(c==Object)this.pack_object(a);else if(c==Date)this.pack_string(a.toString());else{if("function"!=typeof a.toBinaryPack)throw new Error('Type "'+c.toString()+'" not yet supported');this.bufferBuilder.append(a.toBinaryPack())}}}this.bufferBuilder.flush()},e.prototype.pack_bin=function(a){var b=a.length||a.byteLength||a.size;if(b<=15)this.pack_uint8(160+b);else if(b<=65535)this.bufferBuilder.append(218),this.pack_uint16(b);else{if(!(b<=4294967295))throw new Error("Invalid length");this.bufferBuilder.append(219),this.pack_uint32(b)}this.bufferBuilder.append(a)},e.prototype.pack_string=function(a){var b=g(a);if(b<=15)this.pack_uint8(176+b);else if(b<=65535)this.bufferBuilder.append(216),this.pack_uint16(b);else{if(!(b<=4294967295))throw new Error("Invalid length");this.bufferBuilder.append(217),this.pack_uint32(b)}this.bufferBuilder.append(a)},e.prototype.pack_array=function(a){var b=a.length;if(b<=15)this.pack_uint8(144+b);else if(b<=65535)this.bufferBuilder.append(220),this.pack_uint16(b);else{if(!(b<=4294967295))throw new Error("Invalid length");this.bufferBuilder.append(221),this.pack_uint32(b)}for(var c=0;c>8),this.bufferBuilder.append(255&a)},e.prototype.pack_uint32=function(a){var b=4294967295&a;this.bufferBuilder.append((4278190080&b)>>>24),this.bufferBuilder.append((16711680&b)>>>16),this.bufferBuilder.append((65280&b)>>>8),this.bufferBuilder.append(255&b)},e.prototype.pack_uint64=function(a){var b=a/Math.pow(2,32),c=a%Math.pow(2,32);this.bufferBuilder.append((4278190080&b)>>>24),this.bufferBuilder.append((16711680&b)>>>16),this.bufferBuilder.append((65280&b)>>>8),this.bufferBuilder.append(255&b),this.bufferBuilder.append((4278190080&c)>>>24),this.bufferBuilder.append((16711680&c)>>>16),this.bufferBuilder.append((65280&c)>>>8),this.bufferBuilder.append(255&c)},e.prototype.pack_int8=function(a){this.bufferBuilder.append(255&a)},e.prototype.pack_int16=function(a){this.bufferBuilder.append((65280&a)>>8),this.bufferBuilder.append(255&a)},e.prototype.pack_int32=function(a){this.bufferBuilder.append(a>>>24&255),this.bufferBuilder.append((16711680&a)>>>16),this.bufferBuilder.append((65280&a)>>>8),this.bufferBuilder.append(255&a)},e.prototype.pack_int64=function(a){var b=Math.floor(a/Math.pow(2,32)),c=a%Math.pow(2,32);this.bufferBuilder.append((4278190080&b)>>>24),this.bufferBuilder.append((16711680&b)>>>16),this.bufferBuilder.append((65280&b)>>>8),this.bufferBuilder.append(255&b),this.bufferBuilder.append((4278190080&c)>>>24),this.bufferBuilder.append((16711680&c)>>>16),this.bufferBuilder.append((65280&c)>>>8),this.bufferBuilder.append(255&c)}},{"./bufferbuilder":11}],11:[function(a,b,c){function d(){this._pieces=[],this._parts=[]}var e={};e.useBlobBuilder=function(){try{return new Blob([]),!1}catch(a){return!0}}(),e.useArrayBufferView=!e.useBlobBuilder&&function(){try{return 0===new Blob([new Uint8Array([])]).size}catch(a){return!0}}(),b.exports.binaryFeatures=e;var f=b.exports.BlobBuilder;"undefined"!=typeof window&&(f=b.exports.BlobBuilder=window.WebKitBlobBuilder||window.MozBlobBuilder||window.MSBlobBuilder||window.BlobBuilder),d.prototype.append=function(a){"number"==typeof a?this._pieces.push(a):(this.flush(),this._parts.push(a))},d.prototype.flush=function(){if(this._pieces.length>0){var a=new Uint8Array(this._pieces);e.useArrayBufferView||(a=a.buffer),this._parts.push(a),this._pieces=[]}},d.prototype.getBuffer=function(){if(this.flush(),e.useBlobBuilder){for(var a=new f,b=0,c=this._parts.length;b=b.chunks.length?(e.log("Time: ",new Date-b.timer),delete this._outgoing[c]):this._processAcks()}break;case"chunk":if(b=d,!b){var i=this._received[c];if(i===!0)break;b={ack:["ack",c,0],chunks:[]},this._incoming[c]=b}var j=a[2],k=a[3];b.chunks[j]=new Uint8Array(k),j===b.ack[2]&&this._calculateNextAck(c),this._ack(c);break;default:this._handleSend(a)}},d.prototype._chunk=function(a){for(var b=[],c=a.size,d=0;d=c.length&&d.push(["end",a,c.length]),d._multiple=!0,this._handleSend(d)},d.prototype._complete=function(a){e.log("Completed called for",a);var b=this,c=this._incoming[a].chunks,d=new Blob(c);e.blobToArrayBuffer(d,function(a){b.onmessage(e.unpack(a))}),delete this._incoming[a]},d.higherBandwidthSDP=function(a){var b=navigator.appVersion.match(/Chrome\/(.*?) /);if(b&&(b=parseInt(b[1].split(".").shift()),b<31)){var c=a.split("b=AS:30"),d="b=AS:102400";if(c.length>1)return c[0]+d+c[1]}return a},d.prototype.onmessage=function(a){},b.exports.Reliable=d},{"./util":13}],13:[function(a,b,c){var d=a("js-binarypack"),e={debug:!1,inherits:function(a,b){a.super_=b,a.prototype=Object.create(b.prototype,{constructor:{value:a,enumerable:!1,writable:!0,configurable:!0}})},extend:function(a,b){for(var c in b)b.hasOwnProperty(c)&&(a[c]=b[c]);return a},pack:d.pack,unpack:d.unpack,log:function(){if(e.debug){for(var a=[],b=0;b
',document.body.appendChild(c),COUCHFRIENDS._loadAudio(),COUCHFRIENDS.connect()},document.addEventListener("DOMContentLoaded",COUCHFRIENDS.init,!1),COUCHFRIENDS._loadAudio=function(){if(0==COUCHFRIENDS.settings.ui.sound)return!1;if("function"!=typeof AudioContext)return!1;for(var a in COUCHFRIENDS._sounds)if(COUCHFRIENDS._sounds.hasOwnProperty(a)){var b=COUCHFRIENDS._sounds[a],c=new XMLHttpRequest;c.open("GET",COUCHFRIENDS._baseUrl+b.file,!0),c.responseType="arraybuffer",c.key=a,c.onload=function(){var a=new AudioContext;a.key=this.key,a.decodeAudioData(this.response,function(b){COUCHFRIENDS._sounds[a.key].play=function(){var c=a.createBufferSource();c.buffer=b,c.connect(a.destination),c.start||(c.start=c.noteOn),c.start(0)}})},c.send()}},COUCHFRIENDS.showNotification=function(a,b,c){if(c=c||{},0!=COUCHFRIENDS.settings.ui.showNotifications){var d={type:"default",sound:!0};c=Object.assign(d,c),b=b||3500,COUCHFRIENDS.settings.ui.sound&&c.sound&&COUCHFRIENDS._sounds.notification.play();var e=Date.now(),f=document.createElement("div");f.className="COUCHFRIENDS-notification COUCHFRIENDS-notification-"+c.type,f.id="COUCHFRIENDS-"+e,f.innerHTML="

"+a+"

",document.getElementById("COUCHFRIENDS-notifications").appendChild(f),setTimeout(function(){document.getElementById("COUCHFRIENDS-"+e).className="COUCHFRIENDS-notification COUCHFRIENDS-notification-"+c.type+" COUCHFRIENDS-notification-close",setTimeout(function(){var a=document.getElementById("COUCHFRIENDS-"+e);a.parentNode&&a.parentNode.removeChild(a)},1e3)},b)}},COUCHFRIENDS.showHideHowToPopup=function(){if(0==COUCHFRIENDS.settings.displayCode)return void(document.getElementById("COUCHFRIENDS-popup").style.display="none");if(COUCHFRIENDS.players.length>0||""==COUCHFRIENDS._code){if(null===document.getElementById("COUCHFRIENDS-popup").offsetParent)return;return void(document.getElementById("COUCHFRIENDS-popup").className="COUCHFRIENDS-moveBottomLeft")}var a=' Go to couchfriends.com with your phone or tablet and enter the code '+COUCHFRIENDS._code+"";document.getElementById("COUCHFRIENDS-popup").innerHTML=a,null!==document.getElementById("COUCHFRIENDS-popup").offsetParent&&(document.getElementById("COUCHFRIENDS-popup").className="COUCHFRIENDS-moveCenter")},COUCHFRIENDS._generateColor=function(){var a="#"+((1<<24)*Math.random()|0).toString(16),b=COUCHFRIENDS.settings.colorIndex;return null!=COUCHFRIENDS.settings.colors[b]?(a=COUCHFRIENDS.settings.colors[b],b++):(b=0,a=COUCHFRIENDS.settings.colors[b],b++),COUCHFRIENDS.settings.colorIndex=b,a},COUCHFRIENDS._generateCode=function(a){a=a||3;for(var b="",c="ABCDEFGHIJKLMNOPQRSTUVWXYZ",d=0;d '),b+="Achievement unlocked: "+a.name+"",COUCHFRIENDS.showNotification(b,null,{type:"achievement",sound:!1})}),COUCHFRIENDS.on("player.orientation",function(a){}),COUCHFRIENDS.on("player.identify",function(a){}),COUCHFRIENDS.on("player.click",function(a){}),COUCHFRIENDS.on("player.clickDown",function(a){}),COUCHFRIENDS.on("player.clickUp",function(a){}),COUCHFRIENDS.on("player.buttonClick",function(a){}),COUCHFRIENDS.on("player.buttonDown",function(a){}),COUCHFRIENDS.on("player.buttonUp",function(a){}); \ No newline at end of file +e+=3);return this.index+=a,f},d.prototype.unpack_array=function(a){for(var b=new Array(a),c=0;c>31,c=(a>>23&255)-127,d=8388607&a|8388608;return(0==b?1:-1)*d*Math.pow(2,c-23)},d.prototype.unpack_double=function(){var a=this.unpack_uint32(),b=this.unpack_uint32(),c=a>>31,d=(a>>20&2047)-1023,e=1048575&a|1048576,f=e*Math.pow(2,d-20)+b*Math.pow(2,d-52);return(0==c?1:-1)*f},d.prototype.read=function(a){var b=this.index;if(b+a<=this.length)return this.dataView.subarray(b,b+a);throw new Error("BinaryPackFailure: read index out of range")},e.prototype.getBuffer=function(){return this.bufferBuilder.getBuffer()},e.prototype.pack=function(a){var b=typeof a;if("string"==b)this.pack_string(a);else if("number"==b)Math.floor(a)===a?this.pack_integer(a):this.pack_double(a);else if("boolean"==b)a===!0?this.bufferBuilder.append(195):a===!1&&this.bufferBuilder.append(194);else if("undefined"==b)this.bufferBuilder.append(192);else{if("object"!=b)throw new Error('Type "'+b+'" not yet supported');if(null===a)this.bufferBuilder.append(192);else{var c=a.constructor;if(c==Array)this.pack_array(a);else if(c==Blob||c==File)this.pack_bin(a);else if(c==ArrayBuffer)i.useArrayBufferView?this.pack_bin(new Uint8Array(a)):this.pack_bin(a);else if("BYTES_PER_ELEMENT"in a)i.useArrayBufferView?this.pack_bin(new Uint8Array(a.buffer)):this.pack_bin(a.buffer);else if(c==Object)this.pack_object(a);else if(c==Date)this.pack_string(a.toString());else{if("function"!=typeof a.toBinaryPack)throw new Error('Type "'+c.toString()+'" not yet supported');this.bufferBuilder.append(a.toBinaryPack())}}}this.bufferBuilder.flush()},e.prototype.pack_bin=function(a){var b=a.length||a.byteLength||a.size;if(b<=15)this.pack_uint8(160+b);else if(b<=65535)this.bufferBuilder.append(218),this.pack_uint16(b);else{if(!(b<=4294967295))throw new Error("Invalid length");this.bufferBuilder.append(219),this.pack_uint32(b)}this.bufferBuilder.append(a)},e.prototype.pack_string=function(a){var b=g(a);if(b<=15)this.pack_uint8(176+b);else if(b<=65535)this.bufferBuilder.append(216),this.pack_uint16(b);else{if(!(b<=4294967295))throw new Error("Invalid length");this.bufferBuilder.append(217),this.pack_uint32(b)}this.bufferBuilder.append(a)},e.prototype.pack_array=function(a){var b=a.length;if(b<=15)this.pack_uint8(144+b);else if(b<=65535)this.bufferBuilder.append(220),this.pack_uint16(b);else{if(!(b<=4294967295))throw new Error("Invalid length");this.bufferBuilder.append(221),this.pack_uint32(b)}for(var c=0;c>8),this.bufferBuilder.append(255&a)},e.prototype.pack_uint32=function(a){var b=4294967295&a;this.bufferBuilder.append((4278190080&b)>>>24),this.bufferBuilder.append((16711680&b)>>>16),this.bufferBuilder.append((65280&b)>>>8),this.bufferBuilder.append(255&b)},e.prototype.pack_uint64=function(a){var b=a/Math.pow(2,32),c=a%Math.pow(2,32);this.bufferBuilder.append((4278190080&b)>>>24),this.bufferBuilder.append((16711680&b)>>>16),this.bufferBuilder.append((65280&b)>>>8),this.bufferBuilder.append(255&b),this.bufferBuilder.append((4278190080&c)>>>24),this.bufferBuilder.append((16711680&c)>>>16),this.bufferBuilder.append((65280&c)>>>8),this.bufferBuilder.append(255&c)},e.prototype.pack_int8=function(a){this.bufferBuilder.append(255&a)},e.prototype.pack_int16=function(a){this.bufferBuilder.append((65280&a)>>8),this.bufferBuilder.append(255&a)},e.prototype.pack_int32=function(a){this.bufferBuilder.append(a>>>24&255),this.bufferBuilder.append((16711680&a)>>>16),this.bufferBuilder.append((65280&a)>>>8),this.bufferBuilder.append(255&a)},e.prototype.pack_int64=function(a){var b=Math.floor(a/Math.pow(2,32)),c=a%Math.pow(2,32);this.bufferBuilder.append((4278190080&b)>>>24),this.bufferBuilder.append((16711680&b)>>>16),this.bufferBuilder.append((65280&b)>>>8),this.bufferBuilder.append(255&b),this.bufferBuilder.append((4278190080&c)>>>24),this.bufferBuilder.append((16711680&c)>>>16),this.bufferBuilder.append((65280&c)>>>8),this.bufferBuilder.append(255&c)}},{"./bufferbuilder":11}],11:[function(a,b,c){function d(){this._pieces=[],this._parts=[]}var e={};e.useBlobBuilder=function(){try{return new Blob([]),!1}catch(a){return!0}}(),e.useArrayBufferView=!e.useBlobBuilder&&function(){try{return 0===new Blob([new Uint8Array([])]).size}catch(a){return!0}}(),b.exports.binaryFeatures=e;var f=b.exports.BlobBuilder;"undefined"!=typeof window&&(f=b.exports.BlobBuilder=window.WebKitBlobBuilder||window.MozBlobBuilder||window.MSBlobBuilder||window.BlobBuilder),d.prototype.append=function(a){"number"==typeof a?this._pieces.push(a):(this.flush(),this._parts.push(a))},d.prototype.flush=function(){if(this._pieces.length>0){var a=new Uint8Array(this._pieces);e.useArrayBufferView||(a=a.buffer),this._parts.push(a),this._pieces=[]}},d.prototype.getBuffer=function(){if(this.flush(),e.useBlobBuilder){for(var a=new f,b=0,c=this._parts.length;b=b.chunks.length?(e.log("Time: ",new Date-b.timer),delete this._outgoing[c]):this._processAcks()}break;case"chunk":if(b=d,!b){var i=this._received[c];if(i===!0)break;b={ack:["ack",c,0],chunks:[]},this._incoming[c]=b}var j=a[2],k=a[3];b.chunks[j]=new Uint8Array(k),j===b.ack[2]&&this._calculateNextAck(c),this._ack(c);break;default:this._handleSend(a)}},d.prototype._chunk=function(a){for(var b=[],c=a.size,d=0;d=c.length&&d.push(["end",a,c.length]),d._multiple=!0,this._handleSend(d)},d.prototype._complete=function(a){e.log("Completed called for",a);var b=this,c=this._incoming[a].chunks,d=new Blob(c);e.blobToArrayBuffer(d,function(a){b.onmessage(e.unpack(a))}),delete this._incoming[a]},d.higherBandwidthSDP=function(a){var b=navigator.appVersion.match(/Chrome\/(.*?) /);if(b&&(b=parseInt(b[1].split(".").shift()),b<31)){var c=a.split("b=AS:30"),d="b=AS:102400";if(c.length>1)return c[0]+d+c[1]}return a},d.prototype.onmessage=function(a){},b.exports.Reliable=d},{"./util":13}],13:[function(a,b,c){var d=a("js-binarypack"),e={debug:!1,inherits:function(a,b){a.super_=b,a.prototype=Object.create(b.prototype,{constructor:{value:a,enumerable:!1,writable:!0,configurable:!0}})},extend:function(a,b){for(var c in b)b.hasOwnProperty(c)&&(a[c]=b[c]);return a},pack:d.pack,unpack:d.unpack,log:function(){if(e.debug){for(var a=[],b=0;b
',document.body.appendChild(c),COUCHFRIENDS._loadAudio(),COUCHFRIENDS.connect()},document.addEventListener("DOMContentLoaded",COUCHFRIENDS.init,!1),COUCHFRIENDS._loadAudio=function(){if(0==COUCHFRIENDS.settings.ui.sound)return!1;if("function"!=typeof AudioContext)return!1;for(var a in COUCHFRIENDS._sounds)if(COUCHFRIENDS._sounds.hasOwnProperty(a)){var b=COUCHFRIENDS._sounds[a],c=new XMLHttpRequest;c.open("GET",COUCHFRIENDS._baseUrl+b.file,!0),c.responseType="arraybuffer",c.key=a,c.onload=function(){var a=new AudioContext;a.key=this.key,a.decodeAudioData(this.response,function(b){COUCHFRIENDS._sounds[a.key].play=function(){var c=a.createBufferSource();c.buffer=b,c.connect(a.destination),c.start||(c.start=c.noteOn),c.start(0)}})},c.send()}},COUCHFRIENDS.showNotification=function(a,b,c){if(c=c||{},0!=COUCHFRIENDS.settings.ui.showNotifications){var d={type:"default",sound:!0};c=Object.assign(d,c),b=b||3500,COUCHFRIENDS.settings.ui.sound&&c.sound&&COUCHFRIENDS._sounds.notification.play();var e=Date.now(),f=document.createElement("div");f.className="COUCHFRIENDS-notification COUCHFRIENDS-notification-"+c.type,f.id="COUCHFRIENDS-"+e,f.innerHTML="

"+a+"

",document.getElementById("COUCHFRIENDS-notifications").appendChild(f),setTimeout(function(){document.getElementById("COUCHFRIENDS-"+e).className="COUCHFRIENDS-notification COUCHFRIENDS-notification-"+c.type+" COUCHFRIENDS-notification-close",setTimeout(function(){var a=document.getElementById("COUCHFRIENDS-"+e);a.parentNode&&a.parentNode.removeChild(a)},1e3)},b)}},COUCHFRIENDS.showHideHowToPopup=function(){if(0==COUCHFRIENDS.settings.displayCode)return void(document.getElementById("COUCHFRIENDS-popup").style.display="none");if(COUCHFRIENDS.players.length>0||""==COUCHFRIENDS._code){if(null===document.getElementById("COUCHFRIENDS-popup").offsetParent)return;return void(document.getElementById("COUCHFRIENDS-popup").className="COUCHFRIENDS-moveBottomLeft")}var a=' Go to couchfriends.com with your phone or tablet and enter the code '+COUCHFRIENDS._code+"";document.getElementById("COUCHFRIENDS-popup").innerHTML=a,null!==document.getElementById("COUCHFRIENDS-popup").offsetParent&&(document.getElementById("COUCHFRIENDS-popup").className="COUCHFRIENDS-moveCenter")},COUCHFRIENDS._generateColor=function(){var a="#"+((1<<24)*Math.random()|0).toString(16),b=COUCHFRIENDS.settings.colorIndex;return null!=COUCHFRIENDS.settings.colors[b]?(a=COUCHFRIENDS.settings.colors[b],b++):(b=0,a=COUCHFRIENDS.settings.colors[b],b++),COUCHFRIENDS.settings.colorIndex=b,a},COUCHFRIENDS._generateCode=function(a){a=a||3;for(var b="",c="ABCDEFGHIJKLMNOPQRSTUVWXYZ",d=0;d '),b+="Achievement unlocked: "+a.name+"",COUCHFRIENDS.showNotification(b,null,{type:"achievement",sound:!1})}),COUCHFRIENDS.on("player.orientation",function(a){}),COUCHFRIENDS.on("player.identify",function(a){}),COUCHFRIENDS.on("player.click",function(a){}),COUCHFRIENDS.on("player.clickDown",function(a){}),COUCHFRIENDS.on("player.clickUp",function(a){}),COUCHFRIENDS.on("player.buttonClick",function(a){}),COUCHFRIENDS.on("player.buttonDown",function(a){}),COUCHFRIENDS.on("player.buttonUp",function(a){}); +//# sourceMappingURL=couchfriends.api-latest.js.map \ No newline at end of file diff --git a/build/couchfriends.api-latest.js.map b/build/couchfriends.api-latest.js.map new file mode 100644 index 0000000..6b1c03b --- /dev/null +++ b/build/couchfriends.api-latest.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../src/couchfriends.api.js","../src/Emitter.js","../src/peer.js"],"names":["Emitter","obj","mixin","key","prototype","module","exports","on","addEventListener","event","fn","this","_callbacks","push","once","off","apply","arguments","removeListener","removeAllListeners","removeEventListener","length","callbacks","cb","i","splice","emit","args","slice","call","len","listeners","hasListeners","e","t","n","r","s","o","u","a","require","f","Error","code","l","1","RTCSessionDescription","window","mozRTCSessionDescription","RTCPeerConnection","mozRTCPeerConnection","webkitRTCPeerConnection","RTCIceCandidate","mozRTCIceCandidate","2","DataConnection","peer","provider","options","EventEmitter","util","extend","serialization","reliable","open","type","id","connectionId","_idPrefix","randomToken","label","metadata","_buffer","_buffering","bufferSize","_chunkedData","_payload","_peerBrowser","browser","Negotiator","startConnection","originator","Reliable","inherits","initialize","dc","_dc","dataChannel","_configureDataChannel","self","supports","sctp","binaryType","onopen","log","_reliable","debug","onmessage","msg","_handleDataMessage","onclose","close","data","datatype","constructor","Blob","blobToArrayBuffer","ab","unpack","ArrayBuffer","String","binaryStringToArrayBuffer","JSON","parse","__peerData","chunkInfo","count","total","cleanup","send","chunked","_bufferedSend","stringify","blob","pack","needsChunking","chunkedBrowsers","size","chunkedMTU","_sendChunks","binaryBlob","blobToBinaryString","str","_trySend","setTimeout","_tryBuffer","shift","blobs","chunk","ii","handleMessage","message","payload","handleSDP","sdp","handleCandidate","candidate","warn","./negotiator","./util","eventemitter3","3","Socket","MediaConnection","Peer","BinaryPack","./adapter","./dataconnection","./mediaconnection","./peer","./socket","js-binarypack","4","localStream","_stream","addStream","remoteStream","answer","stream","messages","_getMessages","5","pcs","media","queue","connection","pc","_getPeerConnection","peerConnection","config","createDataChannel","onnegotiationneeded","_makeOffer","error","signalingState","_startPeerConnection","optional","DtlsSrtpKeyAgreement","RtpDataChannels","_setupListeners","pc_id","peerId","onicecandidate","evt","socket","dst","oniceconnectionstatechange","iceConnectionState","noop","onicechange","ondatachannel","channel","getConnection","onaddstream","readyState","createOffer","offer","higherBandwidthSDP","setLocalDescription","err","emitError","constraints","_makeAnswer","createAnswer","setRemoteDescription","ice","sdpMLineIndex","addIceCandidate","6","Object","undefined","toString","host","CLOUD_HOST","port","CLOUD_PORT","path","token","defaultConfig","location","hostname","secure","isSecure","logFunction","setLogFunction","setLogLevel","audioVideo","validateId","validateKey","_delayedAbort","destroyed","disconnected","connections","_lostMessages","_initializeServerConnection","_initialize","_retrieveId","_handleMessage","_abort","disconnect","http","XMLHttpRequest","protocol","url","queryString","Date","getTime","Math","random","onerror","pathError","onreadystatechange","status","responseText","start","src","_cleanupPeer","_addConnection","_storeMessage","connect","setZeroTimeout","_lastServerId","destroy","_cleanup","peers","keys","j","jj","reconnect","listAllPeers","helpfulError","7","_queue","httpProtocol","wsProtocol","_httpUrl","_wsUrl","_startXhrStream","_startWebSocket","_socket","WebSocket","_timeout","clearTimeout","_http","abort","_sendQueuedMessages","_index","_streamIndex","old","_handleStream","_setHTTPTimeout","split","index","bufferedMessage","_wsOpen","toLowerCase","setRequestHeader","8","iceServers","dataCount","Chrome","logLevel","level","debugLevel","parseInt","isNaN","_printWith","_print","Function","prefix","copy","Array","unshift","name","console","reliablePC","reliableDC","negotiationPC","binary","exec","ctor","superCtor","super_","create","value","enumerable","writable","configurable","dest","source","hasOwnProperty","global","setZeroTimeoutPostMessage","timeouts","postMessage","messageName","stopPropagation","attachEvent","bl","chunks","ceil","end","min","b","fr","FileReader","onload","target","result","readAsArrayBuffer","readAsBinaryString","byteArray","Uint8Array","charCodeAt","buffer","substr","9","EE","context","_events","ee","a1","a2","a3","a4","a5","events","addListener","setMaxListeners","EventEmitter2","EventEmitter3","10","Unpacker","dataBuffer","dataView","byteLength","Packer","bufferBuilder","BufferBuilder","_utf8Replace","m","utf8Length","replace","binaryFeatures","unpacker","packer","getBuffer","unpack_uint8","positive_fixnum","negative_fixnum","unpack_raw","unpack_string","unpack_array","unpack_map","unpack_float","unpack_double","unpack_uint16","unpack_uint32","unpack_uint64","unpack_int8","unpack_int16","unpack_int32","unpack_int64","byte","bytes","read","uint16","uint32","uint64","uint8","pow","buf","c","fromCharCode","objects","map","sign","exp","fraction","h32","l32","hfrac","frac","subarray","pack_string","floor","pack_integer","pack_double","append","pack_array","File","pack_bin","useArrayBufferView","pack_object","toBinaryPack","flush","pack_uint8","pack_uint16","pack_uint32","ary","num","pack_int8","pack_int16","pack_int32","pack_int64","pack_uint64","LN2","frac0","frac1","b32","prop","high","low","./bufferbuilder","11","_pieces","_parts","useBlobBuilder","BlobBuilder","WebKitBlobBuilder","MozBlobBuilder","MSBlobBuilder","builder","getBlob","12","_outgoing","_incoming","_received","_window","_mtu","_interval","_count","_setupDC","_handleSend","ack","_chunk","timer","_sendWindowedChunks","_setupInterval","setInterval","_multiple","_intervalSend","_processAcks","item","indexOf","idata","odata","_ack","max","_calculateNextAck","_complete","ch","limit","sent","version","navigator","appVersion","match","parts","13","COUCHFRIENDS","REVISION","_sounds","achievement","play","file","notification","_baseUrl","players","_code","gameCode","connected","settings","colorIndex","colors","ui","displayCode","showNotifications","sound","init","head","document","getElementsByTagName","link","createElement","rel","href","appendChild","containerDiv","innerHTML","body","_loadAudio","AudioContext","request","responseType","decodeAudioData","response","createBufferSource","destination","noteOn","showNotification","duration","defaultOptions","assign","now","notificationEl","className","getElementById","node","parentNode","removeChild","showHideHowToPopup","style","display","offsetParent","_generateColor","color","_generateCode","text","possible","charAt","conn","player","topic","params","html","image"],"mappings":";;AAAA,YCeA,SAASA,SAAQC,GACb,GAAIA,EAAK,MAAOC,OAAMD,GAW1B,QAASC,OAAMD,GACX,IAAK,GAAIE,KAAOH,SAAQI,UACpBH,EAAIE,GAAOH,QAAQI,UAAUD,EAEjC,OAAOF,GA1BW,mBAAXI,UACPA,OAAOC,QAAUN,SAqCrBA,QAAQI,UAAUG,GACdP,QAAQI,UAAUI,iBAAmB,SAASC,EAAOC,GAIjD,MAHAC,MAAKC,WAAaD,KAAKC,gBACtBD,KAAKC,WAAW,IAAMH,GAASE,KAAKC,WAAW,IAAMH,QACjDI,KAAKH,GACHC,MAafX,QAAQI,UAAUU,KAAO,SAASL,EAAOC,GACrC,QAASH,KACLI,KAAKI,IAAIN,EAAOF,GAChBG,EAAGM,MAAML,KAAMM,WAKnB,MAFAV,GAAGG,GAAKA,EACRC,KAAKJ,GAAGE,EAAOF,GACRI,MAaXX,QAAQI,UAAUW,IACdf,QAAQI,UAAUc,eACdlB,QAAQI,UAAUe,mBACdnB,QAAQI,UAAUgB,oBAAsB,SAASX,EAAOC,GAIpD,GAHAC,KAAKC,WAAaD,KAAKC,eAGnB,GAAKK,UAAUI,OAEf,MADAV,MAAKC,cACED,IAIX,IAAIW,GAAYX,KAAKC,WAAW,IAAMH,EACtC,KAAKa,EAAW,MAAOX,KAGvB,IAAI,GAAKM,UAAUI,OAEf,aADOV,MAAKC,WAAW,IAAMH,GACtBE,IAKX,KAAK,GADDY,GACKC,EAAI,EAAGA,EAAIF,EAAUD,OAAQG,IAElC,GADAD,EAAKD,EAAUE,GACXD,IAAOb,GAAMa,EAAGb,KAAOA,EAAI,CAC3BY,EAAUG,OAAOD,EAAG,EACpB,OAGR,MAAOb,OAWvBX,QAAQI,UAAUsB,KAAO,SAASjB,GAC9BE,KAAKC,WAAaD,KAAKC,cACvB,IAAIe,MAAUC,MAAMC,KAAKZ,UAAW,GAC9BK,EAAYX,KAAKC,WAAW,IAAMH,EAExC,IAAIa,EAAW,CACXA,EAAYA,EAAUM,MAAM,EAC5B,KAAK,GAAIJ,GAAI,EAAGM,EAAMR,EAAUD,OAAQG,EAAIM,IAAON,EAC/CF,EAAUE,GAAGR,MAAML,KAAMgB,GAIjC,MAAOhB,OAWXX,QAAQI,UAAU2B,UAAY,SAAStB,GAEnC,MADAE,MAAKC,WAAaD,KAAKC,eAChBD,KAAKC,WAAW,IAAMH,QAWjCT,QAAQI,UAAU4B,aAAe,SAASvB,GACtC,QAAUE,KAAKoB,UAAUtB,GAAOY,QCjK4D,QAAUY,GAAEC,EAAEC,EAAEC,GAAG,QAASC,GAAEC,EAAEC,GAAG,IAAIJ,EAAEG,GAAG,CAAC,IAAIJ,EAAEI,GAAG,CAAC,GAAIE,GAAkB,kBAATC,UAAqBA,OAAQ,KAAIF,GAAGC,EAAE,MAAOA,GAAEF,GAAE,EAAI,IAAGd,EAAE,MAAOA,GAAEc,GAAE,EAAI,IAAII,GAAE,GAAIC,OAAM,uBAAuBL,EAAE,IAAK,MAAMI,GAAEE,KAAK,mBAAmBF,EAAE,GAAIG,GAAEV,EAAEG,IAAIhC,WAAY4B,GAAEI,GAAG,GAAGT,KAAKgB,EAAEvC,QAAQ,SAAS2B,GAAG,GAAIE,GAAED,EAAEI,GAAG,GAAGL,EAAG,OAAOI,GAAEF,EAAEA,EAAEF,IAAIY,EAAEA,EAAEvC,QAAQ2B,EAAEC,EAAEC,EAAEC,GAAG,MAAOD,GAAEG,GAAGhC,QAAkD,IAAI,GAA1CkB,GAAkB,kBAATiB,UAAqBA,QAAgBH,EAAE,EAAEA,EAAEF,EAAEf,OAAOiB,IAAID,EAAED,EAAEE,GAAI,OAAOD,KAAKS,GAAG,SAASL,EAAQpC,EAAOC,GACnjBD,EAAOC,QAAQyC,sBAAwBC,OAAOD,uBAC1CC,OAAOC,yBACX5C,EAAOC,QAAQ4C,kBAAoBF,OAAOE,mBACtCF,OAAOG,sBAAwBH,OAAOI,wBAC1C/C,EAAOC,QAAQ+C,gBAAkBL,OAAOK,iBACpCL,OAAOM,wBAETC,GAAG,SAASd,EAAQpC,EAAOC,GAS7B,QAASkD,GAAeC,EAAMC,EAAUC,GACpC,MAAMhD,gBAAgB6C,IACtBI,EAAa/B,KAAKlB,MAElBA,KAAKgD,QAAUE,EAAKC,QAChBC,cAAe,SACfC,UAAU,GACXL,GAGHhD,KAAKsD,MAAO,EACZtD,KAAKuD,KAAO,OACZvD,KAAK8C,KAAOA,EACZ9C,KAAK+C,SAAWA,EAEhB/C,KAAKwD,GAAKxD,KAAKgD,QAAQS,cAAgBZ,EAAea,UAAYR,EAAKS,cAEvE3D,KAAK4D,MAAQ5D,KAAKgD,QAAQY,OAAS5D,KAAKwD,GACxCxD,KAAK6D,SAAW7D,KAAKgD,QAAQa,SAC7B7D,KAAKoD,cAAgBpD,KAAKgD,QAAQI,cAClCpD,KAAKqD,SAAWrD,KAAKgD,QAAQK,SAG7BrD,KAAK8D,WACL9D,KAAK+D,YAAa,EAClB/D,KAAKgE,WAAa,EAGlBhE,KAAKiE,gBAEDjE,KAAKgD,QAAQkB,WACblE,KAAKmE,aAAenE,KAAKgD,QAAQkB,SAASE,aAG9CC,GAAWC,gBACPtE,KACAA,KAAKgD,QAAQkB,WACTK,YAAY,KApC0B,GAAI1B,GAAeC,EAAMC,EAAUC,GATrF,GAAIE,GAAOpB,EAAQ,UACfmB,EAAenB,EAAQ,iBACvBuC,EAAavC,EAAQ,gBACrB0C,EAAW1C,EAAQ,WA+CvBoB,GAAKuB,SAAS5B,EAAgBI,GAE9BJ,EAAea,UAAY,MAG3Bb,EAAepD,UAAUiF,WAAa,SAASC,GAC3C3E,KAAK4E,IAAM5E,KAAK6E,YAAcF,EAC9B3E,KAAK8E,yBAGTjC,EAAepD,UAAUqF,sBAAwB,WAC7C,GAAIC,GAAO/E,IACPkD,GAAK8B,SAASC,OACdjF,KAAK4E,IAAIM,WAAa,eAE1BlF,KAAK4E,IAAIO,OAAS,WACdjC,EAAKkC,IAAI,mCACTL,EAAKzB,MAAO,EACZyB,EAAKhE,KAAK,UAITmC,EAAK8B,SAASC,MAAQjF,KAAKqD,WAC5BrD,KAAKqF,UAAY,GAAIb,GAASxE,KAAK4E,IAAK1B,EAAKoC,QAG7CtF,KAAKqF,UACLrF,KAAKqF,UAAUE,UAAY,SAASC,GAChCT,EAAKhE,KAAK,OAAQyE,IAGtBxF,KAAK4E,IAAIW,UAAY,SAASjE,GAC1ByD,EAAKU,mBAAmBnE,IAGhCtB,KAAK4E,IAAIc,QAAU,SAASpE,GACxB4B,EAAKkC,IAAI,0BAA2BL,EAAKjC,MACzCiC,EAAKY,UAKb9C,EAAepD,UAAUgG,mBAAqB,SAASnE,GACnD,GAAIyD,GAAO/E,KACP4F,EAAOtE,EAAEsE,KACTC,EAAWD,EAAKE,WACpB,IAA2B,WAAvB9F,KAAKoD,eAAqD,gBAAvBpD,KAAKoD,cAAiC,CACzE,GAAIyC,IAAaE,KAMb,WAJA7C,GAAK8C,kBAAkBJ,EAAM,SAASK,GAClCL,EAAO1C,EAAKgD,OAAOD,GACnBlB,EAAKhE,KAAK,OAAQ6E,IAGnB,IAAIC,IAAaM,YACpBP,EAAO1C,EAAKgD,OAAON,OAChB,IAAIC,IAAaO,OAAQ,CAE5B,GAAIH,GAAK/C,EAAKmD,0BAA0BT,EACxCA,GAAO1C,EAAKgD,OAAOD,QAEO,SAAvBjG,KAAKoD,gBACZwC,EAAOU,KAAKC,MAAMX,GAKtB,IAAIA,EAAKY,WAAY,CACjB,GAAIhD,GAAKoC,EAAKY,WACVC,EAAYzG,KAAKiE,aAAaT,KAAQoC,QAAUc,MAAO,EAAGC,MAAOf,EAAKe,MAe1E,OAbAF,GAAUb,KAAKA,EAAKpE,GAAKoE,EAAKA,KAC9Ba,EAAUC,OAAS,EAEfD,EAAUE,QAAUF,EAAUC,cAEvB1G,MAAKiE,aAAaT,GAGzBoC,EAAO,GAAIG,MAAKU,EAAUb,MAC1B5F,KAAKyF,oBAAoBG,KAAMA,UAGnC5F,KAAKiE,aAAaT,GAAMiD,GAI5BzG,KAAKe,KAAK,OAAQ6E,IAQtB/C,EAAepD,UAAUkG,MAAQ,WACxB3F,KAAKsD,OAGVtD,KAAKsD,MAAO,EACZe,EAAWuC,QAAQ5G,MACnBA,KAAKe,KAAK,WAId8B,EAAepD,UAAUoH,KAAO,SAASjB,EAAMkB,GAC3C,IAAK9G,KAAKsD,KAEN,WADAtD,MAAKe,KAAK,QAAS,GAAIiB,OAAM,2FAGjC,IAAIhC,KAAKqF,UAIL,WADArF,MAAKqF,UAAUwB,KAAKjB,EAGxB,IAAIb,GAAO/E,IACX,IAA2B,SAAvBA,KAAKoD,cACLpD,KAAK+G,cAAcT,KAAKU,UAAUpB,QAC/B,IAA2B,WAAvB5F,KAAKoD,eAAqD,gBAAvBpD,KAAKoD,cAAiC,CAChF,GAAI6D,GAAO/D,EAAKgE,KAAKtB,GAIjBuB,EAAgBjE,EAAKkE,gBAAgBpH,KAAKmE,eAAiBjB,EAAKkE,gBAAgBlE,EAAKkB,QACzF,IAAI+C,IAAkBL,GAAWG,EAAKI,KAAOnE,EAAKoE,WAE9C,WADAtH,MAAKuH,YAAYN,EAKhB/D,GAAK8B,SAASC,KAIP/B,EAAK8B,SAASwC,WAOtBxH,KAAK+G,cAAcE,GAJnB/D,EAAK8C,kBAAkBiB,EAAM,SAAShB,GAClClB,EAAKgC,cAAcd,KAPvB/C,EAAKuE,mBAAmBR,EAAM,SAASS,GACnC3C,EAAKgC,cAAcW,SAY3B1H,MAAK+G,cAAcnB,IAI3B/C,EAAepD,UAAUsH,cAAgB,SAASvB,IAC1CxF,KAAK+D,YAAe/D,KAAK2H,SAASnC,KAClCxF,KAAK8D,QAAQ5D,KAAKsF,GAClBxF,KAAKgE,WAAahE,KAAK8D,QAAQpD,SAKvCmC,EAAepD,UAAUkI,SAAW,SAASnC,GACzC,IACIxF,KAAK4E,IAAIiC,KAAKrB,GAChB,MAAOlE,GACLtB,KAAK+D,YAAa,CAElB,IAAIgB,GAAO/E,IAMX,OALA4H,YAAW,WAEP7C,EAAKhB,YAAa,EAClBgB,EAAK8C,cACN,MACI,EAEX,OAAO,GAIXhF,EAAepD,UAAUoI,WAAa,WAClC,GAA4B,IAAxB7H,KAAK8D,QAAQpD,OAAjB,CAIA,GAAI8E,GAAMxF,KAAK8D,QAAQ,EAEnB9D,MAAK2H,SAASnC,KACdxF,KAAK8D,QAAQgE,QACb9H,KAAKgE,WAAahE,KAAK8D,QAAQpD,OAC/BV,KAAK6H,gBAIbhF,EAAepD,UAAU8H,YAAc,SAASN,GAE5C,IAAK,GADDc,GAAQ7E,EAAK8E,MAAMf,GACdpG,EAAI,EAAGoH,EAAKF,EAAMrH,OAAQG,EAAIoH,EAAIpH,GAAK,EAAG,CAC/C,GAAIoG,GAAOc,EAAMlH,EACjBb,MAAK6G,KAAKI,GAAM,KAIxBpE,EAAepD,UAAUyI,cAAgB,SAASC,GAC9C,GAAIC,GAAUD,EAAQC,OAEtB,QAAQD,EAAQ5E,MACZ,IAAK,SACDvD,KAAKmE,aAAeiE,EAAQhE,QAG5BC,EAAWgE,UAAUF,EAAQ5E,KAAMvD,KAAMoI,EAAQE,IACjD,MACJ,KAAK,YACDjE,EAAWkE,gBAAgBvI,KAAMoI,EAAQI,UACzC,MACJ,SACItF,EAAKuF,KAAK,6BAA8BN,EAAQ5E,KAAM,aAAcvD,KAAK8C,QAKrFpD,EAAOC,QAAUkD,IAElB6F,eAAe,EAAEC,SAAS,EAAEC,cAAgB,EAAEvF,SAAW,KAAKwF,GAAG,SAAS/G,EAAQpC,EAAOC,GACxF0C,OAAOyG,OAAShH,EAAQ,YACxBO,OAAO0G,gBAAkBjH,EAAQ,qBACjCO,OAAOQ,eAAiBf,EAAQ,oBAChCO,OAAO2G,KAAOlH,EAAQ,UACtBO,OAAOE,kBAAoBT,EAAQ,aAAaS,kBAChDF,OAAOD,sBAAwBN,EAAQ,aAAaM,sBACpDC,OAAOK,gBAAkBZ,EAAQ,aAAaY,gBAC9CL,OAAOgC,WAAavC,EAAQ,gBAC5BO,OAAOa,KAAOpB,EAAQ,UACtBO,OAAO4G,WAAanH,EAAQ,mBAE7BoH,YAAY,EAAEC,mBAAmB,EAAEC,oBAAoB,EAAEV,eAAe,EAAEW,SAAS,EAAEC,WAAW,EAAEX,SAAS,EAAEY,gBAAgB,KAAKC,GAAG,SAAS1H,EAAQpC,EAAOC,GAQ5J,QAASoJ,GAAgBjG,EAAMC,EAAUC,GACrC,MAAMhD,gBAAgB+I,IACtB9F,EAAa/B,KAAKlB,MAElBA,KAAKgD,QAAUE,EAAKC,UAAWH,GAE/BhD,KAAKsD,MAAO,EACZtD,KAAKuD,KAAO,QACZvD,KAAK8C,KAAOA,EACZ9C,KAAK+C,SAAWA,EAChB/C,KAAK6D,SAAW7D,KAAKgD,QAAQa,SAC7B7D,KAAKyJ,YAAczJ,KAAKgD,QAAQ0G,QAEhC1J,KAAKwD,GAAKxD,KAAKgD,QAAQS,cAAgBsF,EAAgBrF,UAAYR,EAAKS,mBACpE3D,KAAKyJ,aACLpF,EAAWC,gBACPtE,MACC0J,QAAS1J,KAAKyJ,YAAalF,YAAY,MAhBD,GAAIwE,GAAgBjG,EAAMC,EAAUC,GARvF,GAAIE,GAAOpB,EAAQ,UACfmB,EAAenB,EAAQ,iBACvBuC,EAAavC,EAAQ,eA2BzBoB,GAAKuB,SAASsE,EAAiB9F,GAE/B8F,EAAgBrF,UAAY,MAE5BqF,EAAgBtJ,UAAUkK,UAAY,SAASC,GAC3C1G,EAAKkC,IAAI,mBAAoBwE,GAE7B5J,KAAK4J,aAAeA,EACpB5J,KAAKe,KAAK,SAAU6I,IAIxBb,EAAgBtJ,UAAUyI,cAAgB,SAASC,GAC/C,GAAIC,GAAUD,EAAQC,OAEtB,QAAQD,EAAQ5E,MACZ,IAAK,SAEDc,EAAWgE,UAAUF,EAAQ5E,KAAMvD,KAAMoI,EAAQE,KACjDtI,KAAKsD,MAAO,CACZ,MACJ,KAAK,YACDe,EAAWkE,gBAAgBvI,KAAMoI,EAAQI,UACzC,MACJ,SACItF,EAAKuF,KAAK,6BAA8BN,EAAQ5E,KAAM,aAAcvD,KAAK8C,QAKrFiG,EAAgBtJ,UAAUoK,OAAS,SAASC,GACxC,GAAI9J,KAAKyJ,YAEL,WADAvG,GAAKuF,KAAK,uFAIdzI,MAAKgD,QAAQkB,SAASwF,QAAUI,EAEhC9J,KAAKyJ,YAAcK,EACnBzF,EAAWC,gBACPtE,KACAA,KAAKgD,QAAQkB,SAIjB,KAAK,GADD6F,GAAW/J,KAAK+C,SAASiH,aAAahK,KAAKwD,IACtC3C,EAAI,EAAGoH,EAAK8B,EAASrJ,OAAQG,EAAIoH,EAAIpH,GAAK,EAC/Cb,KAAKkI,cAAc6B,EAASlJ,GAEhCb,MAAKsD,MAAO,GAQhByF,EAAgBtJ,UAAUkG,MAAQ,WACzB3F,KAAKsD,OAGVtD,KAAKsD,MAAO,EACZe,EAAWuC,QAAQ5G,MACnBA,KAAKe,KAAK,WAGdrB,EAAOC,QAAUoJ,IAElBL,eAAe,EAAEC,SAAS,EAAEC,cAAgB,IAAIqB,GAAG,SAASnI,EAAQpC,EAAOC,GAC1E,GAAIuD,GAAOpB,EAAQ,UACfS,EAAoBT,EAAQ,aAAaS,kBACzCH,EAAwBN,EAAQ,aAAaM,sBAC7CM,EAAkBZ,EAAQ,aAAaY,gBAKvC2B,GACA6F,KACItE,QACAuE,UAGJC,SAGJ/F,GAAWX,UAAY,MAGvBW,EAAWC,gBAAkB,SAAS+F,EAAYrH,GAC9C,GAAIsH,GAAKjG,EAAWkG,mBAAmBF,EAAYrH,EAUnD,IARwB,UAApBqH,EAAW9G,MAAoBP,EAAQ0G,SAEvCY,EAAGX,UAAU3G,EAAQ0G,SAIzBW,EAAWC,GAAKD,EAAWG,eAAiBF,EAExCtH,EAAQuB,WAAY,CACpB,GAAwB,SAApB8F,EAAW9G,KAAiB,CAE5B,GAAIkH,KAQCvH,GAAK8B,SAASC,OACfwF,GAAUpH,SAAUL,EAAQK,UAEhC,IAAIsB,GAAK2F,EAAGI,kBAAkBL,EAAWzG,MAAO6G,EAChDJ,GAAW3F,WAAWC,GAGrBzB,EAAK8B,SAAS2F,qBACftG,EAAWuG,WAAWP,OAG1BhG,GAAWgE,UAAU,QAASgC,EAAYrH,EAAQsF,MAI1DjE,EAAWkG,mBAAqB,SAASF,EAAYrH,GAC5CqB,EAAW6F,IAAIG,EAAW9G,OAC3BL,EAAK2H,MAAMR,EAAW9G,KAAO,sFAG5Bc,EAAW6F,IAAIG,EAAW9G,MAAM8G,EAAWvH,QAC5CuB,EAAW6F,IAAIG,EAAW9G,MAAM8G,EAAWvH,SAE/C,IAEIwH,EAFkBjG,GAAW6F,IAAIG,EAAW9G,MAAM8G,EAAWvH,KAoBjE,OAPIE,GAAQsH,KACRA,EAAKjG,EAAW6F,IAAIG,EAAW9G,MAAM8G,EAAWvH,MAAME,EAAQsH,KAG7DA,GAA4B,WAAtBA,EAAGQ,iBACVR,EAAKjG,EAAW0G,qBAAqBV,IAElCC,GAiBXjG,EAAW0G,qBAAuB,SAASV,GACvCnH,EAAKkC,IAAI,8BAET,IAAI5B,GAAKa,EAAWX,UAAYR,EAAKS,cACjCqH,IAEoB,UAApBX,EAAW9G,MAAoBL,EAAK8B,SAASC,KAElB,UAApBoF,EAAW9G,OAElByH,GAAYA,WAAYC,sBAAsB,MAH9CD,GAAYA,WAAYE,iBAAiB,IAM7C,IAAIZ,GAAK,GAAI/H,GAAkB8H,EAAWtH,SAASC,QAAQyH,OAAQO,EAKnE,OAJA3G,GAAW6F,IAAIG,EAAW9G,MAAM8G,EAAWvH,MAAMU,GAAM8G,EAEvDjG,EAAW8G,gBAAgBd,EAAYC,EAAI9G,GAEpC8G,GAIXjG,EAAW8G,gBAAkB,SAASd,EAAYC,EAAIc,GAClD,GAAIC,GAAShB,EAAWvH,KACpBW,EAAe4G,EAAW7G,GAC1BT,EAAWsH,EAAWtH,QAG1BG,GAAKkC,IAAI,iCACTkF,EAAGgB,eAAiB,SAASC,GACrBA,EAAI/C,YACJtF,EAAKkC,IAAI,+BAAgCiF,EAAWvH,MACpDC,EAASyI,OAAO3E,MACZtD,KAAM,YACN6E,SACII,UAAW+C,EAAI/C,UACfjF,KAAM8G,EAAW9G,KACjBE,aAAc4G,EAAW7G,IAE7BiI,IAAKJ,MAKjBf,EAAGoB,2BAA6B,WAC5B,OAAQpB,EAAGqB,oBACP,IAAK,eACL,IAAK,SACDzI,EAAKkC,IAAI,8DAAgEiG,GACzEhB,EAAW1E,OACX,MACJ,KAAK,YACD2E,EAAGgB,eAAiBpI,EAAK0I,OAMrCtB,EAAGuB,YAAcvB,EAAGoB,2BAGpBxI,EAAKkC,IAAI,qCACTkF,EAAGK,oBAAsB,WACrBzH,EAAKkC,IAAI,iCACgB,UAArBkF,EAAGQ,eACHzG,EAAWuG,WAAWP,GAEtBnH,EAAKkC,IAAI,4FAKjBlC,EAAKkC,IAAI,8BAGTkF,EAAGwB,cAAgB,SAASP,GACxBrI,EAAKkC,IAAI,wBACT,IAAIT,GAAK4G,EAAIQ,QACT1B,EAAatH,EAASiJ,cAAcX,EAAQ5H,EAChD4G,GAAW3F,WAAWC,IAI1BzB,EAAKkC,IAAI,+BACTkF,EAAG2B,YAAc,SAASV,GACtBrI,EAAKkC,IAAI,yBACT,IAAI0E,GAASyB,EAAIzB,OACbO,EAAatH,EAASiJ,cAAcX,EAAQ5H,EAMxB,WAApB4G,EAAW9G,MACX8G,EAAWV,UAAUG,KAKjCzF,EAAWuC,QAAU,SAASyD,GAC1BnH,EAAKkC,IAAI,iCAAmCiF,EAAWvH,KAEvD,IAAIwH,GAAKD,EAAWC,IAEdA,GAAyB,WAAlBA,EAAG4B,YAAiD,WAAtB5B,EAAGQ,iBAC1CR,EAAG3E,QACH0E,EAAWC,GAAK,OAIxBjG,EAAWuG,WAAa,SAASP,GAC7B,GAAIC,GAAKD,EAAWC,EACpBA,GAAG6B,YAAY,SAASC,GACpBlJ,EAAKkC,IAAI,mBAEJlC,EAAK8B,SAASC,MAA4B,SAApBoF,EAAW9G,MAAmB8G,EAAWhH,WAChE+I,EAAM9D,IAAM9D,SAAS6H,mBAAmBD,EAAM9D,MAGlDgC,EAAGgC,oBAAoBF,EAAO,WAC1BlJ,EAAKkC,IAAI,8BAA+B,OAAQiF,EAAWvH,MAC3DuH,EAAWtH,SAASyI,OAAO3E,MACvBtD,KAAM,QACN6E,SACIE,IAAK8D,EACL7I,KAAM8G,EAAW9G,KACjBK,MAAOyG,EAAWzG,MAClBH,aAAc4G,EAAW7G,GACzBH,SAAUgH,EAAWhH,SACrBD,cAAeiH,EAAWjH,cAC1BS,SAAUwG,EAAWxG,SACrBO,QAASlB,EAAKkB,SAElBqH,IAAKpB,EAAWvH,QAErB,SAASyJ,GACRlC,EAAWtH,SAASyJ,UAAU,SAAUD,GACxCrJ,EAAKkC,IAAI,kCAAmCmH,MAEjD,SAASA,GACRlC,EAAWtH,SAASyJ,UAAU,SAAUD,GACxCrJ,EAAKkC,IAAI,0BAA2BmH,IACrClC,EAAWrH,QAAQyJ,cAG1BpI,EAAWqI,YAAc,SAASrC,GAC9B,GAAIC,GAAKD,EAAWC,EAEpBA,GAAGqC,aAAa,SAAS9C,GACrB3G,EAAKkC,IAAI,oBAEJlC,EAAK8B,SAASC,MAA4B,SAApBoF,EAAW9G,MAAmB8G,EAAWhH,WAChEwG,EAAOvB,IAAM9D,SAAS6H,mBAAmBxC,EAAOvB,MAGpDgC,EAAGgC,oBAAoBzC,EAAQ,WAC3B3G,EAAKkC,IAAI,+BAAgC,OAAQiF,EAAWvH,MAC5DuH,EAAWtH,SAASyI,OAAO3E,MACvBtD,KAAM,SACN6E,SACIE,IAAKuB,EACLtG,KAAM8G,EAAW9G,KACjBE,aAAc4G,EAAW7G,GACzBY,QAASlB,EAAKkB,SAElBqH,IAAKpB,EAAWvH,QAErB,SAASyJ,GACRlC,EAAWtH,SAASyJ,UAAU,SAAUD,GACxCrJ,EAAKkC,IAAI,kCAAmCmH,MAEjD,SAASA,GACRlC,EAAWtH,SAASyJ,UAAU,SAAUD,GACxCrJ,EAAKkC,IAAI,4BAA6BmH,MAK9ClI,EAAWgE,UAAY,SAAS9E,EAAM8G,EAAY/B,GAC9CA,EAAM,GAAIlG,GAAsBkG,EAChC,IAAIgC,GAAKD,EAAWC,EAEpBpH,GAAKkC,IAAI,6BAA8BkD,GACvCgC,EAAGsC,qBAAqBtE,EAAK,WACzBpF,EAAKkC,IAAI,yBAA0B7B,EAAM,OAAQ8G,EAAWvH,MAE/C,UAATS,GACAc,EAAWqI,YAAYrC,IAE5B,SAASkC,GACRlC,EAAWtH,SAASyJ,UAAU,SAAUD,GACxCrJ,EAAKkC,IAAI,mCAAoCmH,MAKrDlI,EAAWkE,gBAAkB,SAAS8B,EAAYwC,GAC9C,GAAIrE,GAAYqE,EAAIrE,UAChBsE,EAAgBD,EAAIC,aACxBzC,GAAWC,GAAGyC,gBAAgB,GAAIrK,IAC9BoK,cAAeA,EACftE,UAAWA,KAEftF,EAAKkC,IAAI,2BAA4BiF,EAAWvH,OAGpDpD,EAAOC,QAAU0E,IAElB6E,YAAY,EAAEP,SAAS,IAAIqE,GAAG,SAASlL,EAAQpC,EAAOC,GAUrD,QAASqJ,GAAKxF,EAAIR,GACd,MAAMhD,gBAAgBgJ,IACtB/F,EAAa/B,KAAKlB,MAGdwD,GAAMA,EAAGsC,aAAemH,QACxBjK,EAAUQ,EACVA,EAAK0J,QACE1J,IAEPA,EAAKA,EAAG2J,YAKZnK,EAAUE,EAAKC,QACXmC,MAAO,EACP8H,KAAMlK,EAAKmK,WACXC,KAAMpK,EAAKqK,WACX/N,IAAK,SACLgO,KAAM,IACNC,MAAOvK,EAAKS,cACZ8G,OAAQvH,EAAKwK,eACd1K,GACHhD,KAAKgD,QAAUA,EAEM,MAAjBA,EAAQoK,OACRpK,EAAQoK,KAAO/K,OAAOsL,SAASC,UAGX,MAApB5K,EAAQwK,KAAK,KACbxK,EAAQwK,KAAO,IAAMxK,EAAQwK,MAEa,MAA1CxK,EAAQwK,KAAKxK,EAAQwK,KAAK9M,OAAS,KACnCsC,EAAQwK,MAAQ,KAIGN,SAAnBlK,EAAQ6K,QAAwB7K,EAAQoK,OAASlK,EAAKmK,aACtDrK,EAAQ6K,OAAS3K,EAAK4K,YAGtB9K,EAAQ+K,aACR7K,EAAK8K,eAAehL,EAAQ+K,aAEhC7K,EAAK+K,YAAYjL,EAAQsC,OAKpBpC,EAAK8B,SAASkJ,YAAehL,EAAK8B,SAASY,KAK3C1C,EAAKiL,WAAW3K,GAKhBN,EAAKkL,YAAYpL,EAAQxD,KAK1BwD,EAAQ6K,QAA2B,iBAAjB7K,EAAQoK,SAC1BpN,MAAKqO,cAAc,kBACf,oGAMRrO,KAAKsO,WAAY,EACjBtO,KAAKuO,cAAe,EACpBvO,KAAKsD,MAAO,EAIZtD,KAAKwO,eACLxO,KAAKyO,iBAILzO,KAAK0O,mCACDlL,EACAxD,KAAK2O,YAAYnL,GAEjBxD,KAAK4O,oBA3BL5O,MAAKqO,cAAc,cAAe,YAAcrL,EAAQxD,IAAM,oBAL9DQ,MAAKqO,cAAc,aAAc,OAAS7K,EAAK,oBAL/CxD,MAAKqO,cAAc,uBAAwB,gDAlDX,GAAIrF,GAAKxF,EAAIR,GAVrD,GAAIE,GAAOpB,EAAQ,UACfmB,EAAenB,EAAQ,iBACvBgH,EAAShH,EAAQ,YACjBiH,EAAkBjH,EAAQ,qBAC1Be,EAAiBf,EAAQ,mBAkG7BoB,GAAKuB,SAASuE,EAAM/F,GAIpB+F,EAAKvJ,UAAUiP,4BAA8B,WACzC,GAAI3J,GAAO/E,IACXA,MAAKwL,OAAS,GAAI1C,GAAO9I,KAAKgD,QAAQ6K,OAAQ7N,KAAKgD,QAAQoK,KAAMpN,KAAKgD,QAAQsK,KAAMtN,KAAKgD,QAAQwK,KAAMxN,KAAKgD,QAAQxD,KACpHQ,KAAKwL,OAAO5L,GAAG,UAAW,SAASgG,GAC/Bb,EAAK8J,eAAejJ,KAExB5F,KAAKwL,OAAO5L,GAAG,QAAS,SAASiL,GAC7B9F,EAAK+J,OAAO,eAAgBjE,KAEhC7K,KAAKwL,OAAO5L,GAAG,eAAgB,WAEtBmF,EAAKwJ,eACNxJ,EAAKyH,UAAU,UAAW,8BAC1BzH,EAAKgK,gBAGb/O,KAAKwL,OAAO5L,GAAG,QAAS,WAEfmF,EAAKwJ,cACNxJ,EAAK+J,OAAO,gBAAiB,2CAMzC9F,EAAKvJ,UAAUmP,YAAc,SAAShO,GAClC,GAAImE,GAAO/E,KACPgP,EAAO,GAAIC,gBACXC,EAAWlP,KAAKgD,QAAQ6K,OAAS,WAAa,UAC9CsB,EAAMD,EAAWlP,KAAKgD,QAAQoK,KAAO,IAAMpN,KAAKgD,QAAQsK,KACxDtN,KAAKgD,QAAQwK,KAAOxN,KAAKgD,QAAQxD,IAAM,MACvC4P,EAAc,QAAS,GAAIC,OAAOC,UAAiBC,KAAKC,QAC5DL,IAAOC,EAGPJ,EAAK1L,KAAK,MAAO6L,GAAK,GACtBH,EAAKS,QAAU,SAASnO,GACpB4B,EAAK2H,MAAM,sBAAuBvJ,EAClC,IAAIoO,GAAY,EACU,OAAtB3K,EAAK/B,QAAQwK,MAAgBzI,EAAK/B,QAAQoK,OAASlK,EAAKmK,aACxDqC,EAAY,mIAIhB3K,EAAK+J,OAAO,eAAgB,uCAAyCY,IAEzEV,EAAKW,mBAAqB,WACtB,GAAwB,IAApBX,EAAK9C,WAGT,MAAoB,OAAhB8C,EAAKY,WACLZ,GAAKS,cAGT1K,GAAK4J,YAAYK,EAAKa,eAE1Bb,EAAKnI,KAAK,OAIdmC,EAAKvJ,UAAUkP,YAAc,SAASnL,GAClCxD,KAAKwD,GAAKA,EACVxD,KAAKwL,OAAOsE,MAAM9P,KAAKwD,GAAIxD,KAAKgD,QAAQyK,QAI5CzE,EAAKvJ,UAAUoP,eAAiB,SAAS1G,GACrC,GAGIkC,GAHA9G,EAAO4E,EAAQ5E,KACf6E,EAAUD,EAAQC,QAClBtF,EAAOqF,EAAQ4H,GAGnB,QAAQxM,GACJ,IAAK,OACDvD,KAAKe,KAAK,OAAQf,KAAKwD,IACvBxD,KAAKsD,MAAO,CACZ,MACJ,KAAK,QACDtD,KAAK8O,OAAO,eAAgB1G,EAAQ5C,IACpC,MACJ,KAAK,WACDxF,KAAK8O,OAAO,iBAAkB,OAAS9O,KAAKwD,GAAK,aACjD,MACJ,KAAK,cACDxD,KAAK8O,OAAO,cAAe,YAAc9O,KAAKgD,QAAQxD,IAAM,eAC5D,MAGJ,KAAK,QACD0D,EAAKkC,IAAI,8BAA+BtC,GACxC9C,KAAKgQ,aAAalN,EAClB,MAEJ,KAAK,SACD9C,KAAKwM,UAAU,mBAAoB,6BAA+B1J,EAClE,MACJ,KAAK,QACD,GAAIW,GAAe2E,EAAQ3E,YAG3B,IAFA4G,EAAarK,KAAKgM,cAAclJ,EAAMW,GAGlCP,EAAKuF,KAAK,6CAA8ChF,OAErD,CAEH,GAAqB,UAAjB2E,EAAQ7E,KACR8G,EAAa,GAAItB,GAAgBjG,EAAM9C,MACnCyD,aAAcA,EACdS,SAAUkE,EACVvE,SAAUuE,EAAQvE,WAEtB7D,KAAKiQ,eAAenN,EAAMuH,GAC1BrK,KAAKe,KAAK,OAAQsJ,OACf,CAAA,GAAqB,SAAjBjC,EAAQ7E,KAaf,WADAL,GAAKuF,KAAK,sCAAuCL,EAAQ7E,KAXzD8G,GAAa,GAAIxH,GAAeC,EAAM9C,MAClCyD,aAAcA,EACdS,SAAUkE,EACVvE,SAAUuE,EAAQvE,SAClBD,MAAOwE,EAAQxE,MACfR,cAAegF,EAAQhF,cACvBC,SAAU+E,EAAQ/E,WAEtBrD,KAAKiQ,eAAenN,EAAMuH,GAC1BrK,KAAKe,KAAK,aAAcsJ,GAO5B,IAAK,GADDN,GAAW/J,KAAKgK,aAAavG,GACxB5C,EAAI,EAAGoH,EAAK8B,EAASrJ,OAAQG,EAAIoH,EAAIpH,GAAK,EAC/CwJ,EAAWnC,cAAc6B,EAASlJ,IAG1C,KACJ,SACI,IAAKuH,EAED,WADAlF,GAAKuF,KAAK,yCAA2C3F,EAAO,YAAcS,EAI9E,IAAIC,GAAK4E,EAAQ3E,YACjB4G,GAAarK,KAAKgM,cAAclJ,EAAMU,GAElC6G,GAAcA,EAAWC,GAEzBD,EAAWnC,cAAcC,GAClB3E,EAEPxD,KAAKkQ,cAAc1M,EAAI2E,GAEvBjF,EAAKuF,KAAK,wCAAyCN,KAOnEa,EAAKvJ,UAAUyQ,cAAgB,SAASzM,EAAc0E,GAC7CnI,KAAKyO,cAAchL,KACpBzD,KAAKyO,cAAchL,OAEvBzD,KAAKyO,cAAchL,GAAcvD,KAAKiI,IAI1Ca,EAAKvJ,UAAUuK,aAAe,SAASvG,GACnC,GAAIsG,GAAW/J,KAAKyO,cAAchL,EAClC,OAAIsG,UACO/J,MAAKyO,cAAchL,GACnBsG,OAUff,EAAKvJ,UAAU0Q,QAAU,SAASrN,EAAME,GACpC,GAAIhD,KAAKuO,aAML,MALArL,GAAKuF,KAAK,qPAIVzI,MAAKwM,UAAU,eAAgB,8DAGnC,IAAInC,GAAa,GAAIxH,GAAeC,EAAM9C,KAAMgD,EAEhD,OADAhD,MAAKiQ,eAAenN,EAAMuH,GACnBA,GAOXrB,EAAKvJ,UAAUyB,KAAO,SAAS4B,EAAMgH,EAAQ9G,GACzC,GAAIhD,KAAKuO,aAKL,MAJArL,GAAKuF,KAAK,yKAGVzI,MAAKwM,UAAU,eAAgB,8DAGnC,KAAK1C,EAED,WADA5G,GAAK2H,MAAM,gFAGf7H,GAAUA,MACVA,EAAQ0G,QAAUI,CAClB,IAAI5I,GAAO,GAAI6H,GAAgBjG,EAAM9C,KAAMgD,EAE3C,OADAhD,MAAKiQ,eAAenN,EAAM5B,GACnBA,GAIX8H,EAAKvJ,UAAUwQ,eAAiB,SAASnN,EAAMuH,GACtCrK,KAAKwO,YAAY1L,KAClB9C,KAAKwO,YAAY1L,OAErB9C,KAAKwO,YAAY1L,GAAM5C,KAAKmK,IAIhCrB,EAAKvJ,UAAUuM,cAAgB,SAASlJ,EAAMU,GAC1C,GAAIgL,GAAcxO,KAAKwO,YAAY1L,EACnC,KAAK0L,EACD,MAAO,KAEX,KAAK,GAAI3N,GAAI,EAAGoH,EAAKuG,EAAY9N,OAAQG,EAAIoH,EAAIpH,IAC7C,GAAI2N,EAAY3N,GAAG2C,KAAOA,EACtB,MAAOgL,GAAY3N,EAG3B,OAAO,OAGXmI,EAAKvJ,UAAU4O,cAAgB,SAAS9K,EAAM4E,GAC1C,GAAIpD,GAAO/E,IACXkD,GAAKkN,eAAe,WAChBrL,EAAK+J,OAAOvL,EAAM4E,MAS1Ba,EAAKvJ,UAAUqP,OAAS,SAASvL,EAAM4E,GACnCjF,EAAK2H,MAAM,aACN7K,KAAKqQ,cAGNrQ,KAAK+O,aAFL/O,KAAKsQ,UAITtQ,KAAKwM,UAAUjJ,EAAM4E,IAIzBa,EAAKvJ,UAAU+M,UAAY,SAASjJ,EAAMgJ,GACtCrJ,EAAK2H,MAAM,SAAU0B,GACF,gBAARA,KACPA,EAAM,GAAIvK,OAAMuK,IAEpBA,EAAIhJ,KAAOA,EACXvD,KAAKe,KAAK,QAASwL,IASvBvD,EAAKvJ,UAAU6Q,QAAU,WAChBtQ,KAAKsO,YACNtO,KAAKuQ,WACLvQ,KAAK+O,aACL/O,KAAKsO,WAAY,IAMzBtF,EAAKvJ,UAAU8Q,SAAW,WACtB,GAAIvQ,KAAKwO,YAEL,IAAK,GADDgC,GAAQvD,OAAOwD,KAAKzQ,KAAKwO,aACpB3N,EAAI,EAAGoH,EAAKuI,EAAM9P,OAAQG,EAAIoH,EAAIpH,IACvCb,KAAKgQ,aAAaQ,EAAM3P,GAGhCb,MAAKe,KAAK,UAIdiI,EAAKvJ,UAAUuQ,aAAe,SAASlN,GAEnC,IAAK,GADD0L,GAAcxO,KAAKwO,YAAY1L,GAC1B4N,EAAI,EAAGC,EAAKnC,EAAY9N,OAAQgQ,EAAIC,EAAID,GAAK,EAClDlC,EAAYkC,GAAG/K,SAUvBqD,EAAKvJ,UAAUsP,WAAa,WACxB,GAAIhK,GAAO/E,IACXkD,GAAKkN,eAAe,WACXrL,EAAKwJ,eACNxJ,EAAKwJ,cAAe,EACpBxJ,EAAKzB,MAAO,EACRyB,EAAKyG,QACLzG,EAAKyG,OAAO7F,QAEhBZ,EAAKhE,KAAK,eAAgBgE,EAAKvB,IAC/BuB,EAAKsL,cAAgBtL,EAAKvB,GAC1BuB,EAAKvB,GAAK,SAMtBwF,EAAKvJ,UAAUmR,UAAY,WACvB,GAAI5Q,KAAKuO,eAAiBvO,KAAKsO,UAC3BpL,EAAKkC,IAAI,6CAA+CpF,KAAKqQ,eAC7DrQ,KAAKuO,cAAe,EACpBvO,KAAK0O,8BACL1O,KAAK2O,YAAY3O,KAAKqQ,mBACnB,CAAA,GAAIrQ,KAAKsO,UACZ,KAAM,IAAItM,OAAM,2EACb,IAAKhC,KAAKuO,cAAiBvO,KAAKsD,KAInC,KAAM,IAAItB,OAAM,QAAUhC,KAAKwD,GAAK,oEAFpCN,GAAK2H,MAAM,oEAYnB7B,EAAKvJ,UAAUoR,aAAe,SAASjQ,GACnCA,EAAKA,GAAM,YACX,IAAImE,GAAO/E,KACPgP,EAAO,GAAIC,gBACXC,EAAWlP,KAAKgD,QAAQ6K,OAAS,WAAa,UAC9CsB,EAAMD,EAAWlP,KAAKgD,QAAQoK,KAAO,IAAMpN,KAAKgD,QAAQsK,KACxDtN,KAAKgD,QAAQwK,KAAOxN,KAAKgD,QAAQxD,IAAM,SACvC4P,EAAc,QAAS,GAAIC,OAAOC,UAAiBC,KAAKC,QAC5DL,IAAOC,EAGPJ,EAAK1L,KAAK,MAAO6L,GAAK,GACtBH,EAAKS,QAAU,SAASnO,GACpByD,EAAK+J,OAAO,eAAgB,wCAC5BlO,OAEJoO,EAAKW,mBAAqB,WACtB,GAAwB,IAApBX,EAAK9C,WAAT,CAGA,GAAoB,MAAhB8C,EAAKY,OAAgB,CACrB,GAAIkB,GAAe,EASnB,MAPIA,GADA/L,EAAK/B,QAAQoK,OAASlK,EAAKmK,WACZ,sHAGA,2FAGnBzM,MACM,GAAIoB,OAAM,+DAAkE8O,GAElFlQ,EADuB,MAAhBoO,EAAKY,UAGTtJ,KAAKC,MAAMyI,EAAKa,iBAG3Bb,EAAKnI,KAAK,OAGdnH,EAAOC,QAAUqJ,IAElBG,mBAAmB,EAAEC,oBAAoB,EAAEE,WAAW,EAAEX,SAAS,EAAEC,cAAgB,IAAImI,GAAG,SAASjP,EAAQpC,EAAOC,GAQjH,QAASmJ,GAAO+E,EAAQT,EAAME,EAAME,EAAMhO,GACtC,KAAMQ,eAAgB8I,IAAS,MAAO,IAAIA,GAAO+E,EAAQT,EAAME,EAAME,EAAMhO,EAE3EyD,GAAa/B,KAAKlB,MAGlBA,KAAKuO,cAAe,EACpBvO,KAAKgR,SAEL,IAAIC,GAAepD,EAAS,WAAa,UACrCqD,EAAarD,EAAS,SAAW,OACrC7N,MAAKmR,SAAWF,EAAe7D,EAAO,IAAME,EAAOE,EAAOhO,EAC1DQ,KAAKoR,OAASF,EAAa9D,EAAO,IAAME,EAAOE,EAAO,cAAgBhO,EAnB1E,GAAI0D,GAAOpB,EAAQ,UACfmB,EAAenB,EAAQ,gBAqB3BoB,GAAKuB,SAASqE,EAAQ7F,GAItB6F,EAAOrJ,UAAUqQ,MAAQ,SAAStM,EAAIiK,GAClCzN,KAAKwD,GAAKA,EAEVxD,KAAKmR,UAAY,IAAM3N,EAAK,IAAMiK,EAClCzN,KAAKoR,QAAU,OAAS5N,EAAK,UAAYiK,EAEzCzN,KAAKqR,kBACLrR,KAAKsR,mBAKTxI,EAAOrJ,UAAU6R,gBAAkB,SAAS9N,GACxC,GAAIuB,GAAO/E,IAEPA,MAAKuR,UAITvR,KAAKuR,QAAU,GAAIC,WAAUxR,KAAKoR,QAElCpR,KAAKuR,QAAQhM,UAAY,SAASzF,GAC9B,IACI,GAAI8F,GAAOU,KAAKC,MAAMzG,EAAM8F,MAC9B,MAAMtE,GAEJ,WADA4B,GAAKkC,IAAI,yBAA0BtF,EAAM8F,MAG7Cb,EAAKhE,KAAK,UAAW6E,IAGzB5F,KAAKuR,QAAQ7L,QAAU,SAAS5F,GAC5BoD,EAAKkC,IAAI,kBACTL,EAAKwJ,cAAe,EACpBxJ,EAAKhE,KAAK,iBAKdf,KAAKuR,QAAQpM,OAAS,WACdJ,EAAK0M,WACLC,aAAa3M,EAAK0M,UAClB7J,WAAW,WACP7C,EAAK4M,MAAMC,QACX7M,EAAK4M,MAAQ,MACd,MAEP5M,EAAK8M,sBACL3O,EAAKkC,IAAI,kBAKjB0D,EAAOrJ,UAAU4R,gBAAkB,SAAS7P,GACxC,IACI,GAAIuD,GAAO/E,IACXA,MAAK2R,MAAQ,GAAI1C,gBACjBjP,KAAK2R,MAAMG,OAAS,EACpB9R,KAAK2R,MAAMI,aAAevQ,GAAK,EAC/BxB,KAAK2R,MAAMrO,KAAK,OAAQtD,KAAKmR,SAAW,SAAWnR,KAAK2R,MAAMI,cAAc,GAC5E/R,KAAK2R,MAAMlC,QAAU,WAGjBiC,aAAa3M,EAAK0M,UAClB1M,EAAKhE,KAAK,iBAEdf,KAAK2R,MAAMhC,mBAAqB,WACL,GAAnB3P,KAAKkM,YAAmBlM,KAAKgS,KAC7BhS,KAAKgS,IAAIJ,cACF5R,MAAKgS,KACLhS,KAAKkM,WAAa,GAAqB,MAAhBlM,KAAK4P,QAAkB5P,KAAK6P,cAC1D9K,EAAKkN,cAAcjS,OAG3BA,KAAK2R,MAAM9K,KAAK,MAChB7G,KAAKkS,kBACP,MAAM5Q,GACJ4B,EAAKkC,IAAI,4DAMjB0D,EAAOrJ,UAAUwS,cAAgB,SAASjD,GAEtC,GAAIjF,GAAWiF,EAAKa,aAAasC,MAAM,KAGvC,IAAInD,EAAKlL,QACL,KAAOkL,EAAKlL,QAAQpD,OAAS,GAAG,CAC5B,GAAI0R,GAAQpD,EAAKlL,QAAQgE,QACrBuK,EAAkBtI,EAASqI,EAC/B,KACIC,EAAkB/L,KAAKC,MAAM8L,GAC/B,MAAM/Q,GACJ0N,EAAKlL,QAAQgE,MAAMsK,EACnB,OAEJpS,KAAKe,KAAK,UAAWsR,GAI7B,GAAIlK,GAAU4B,EAASiF,EAAK8C,OAC5B,IAAI3J,EAKA,GAJA6G,EAAK8C,QAAU,EAIX9C,EAAK8C,SAAW/H,EAASrJ,OACpBsO,EAAKlL,UACNkL,EAAKlL,YAETkL,EAAKlL,QAAQ5D,KAAK8O,EAAK8C,OAAS,OAC7B,CACH,IACI3J,EAAU7B,KAAKC,MAAM4B,GACvB,MAAM7G,GAEJ,WADA4B,GAAKkC,IAAI,yBAA0B+C,GAGvCnI,KAAKe,KAAK,UAAWoH,KAKjCW,EAAOrJ,UAAUyS,gBAAkB,WAC/B,GAAInN,GAAO/E,IACXA,MAAKyR,SAAW7J,WAAW,WACvB,GAAIoK,GAAMjN,EAAK4M,KACV5M,GAAKuN,UAINN,EAAIJ,SAHJ7M,EAAKsM,gBAAgBW,EAAID,aAAe,GACxChN,EAAK4M,MAAMK,IAAMA,IAItB,OAIPlJ,EAAOrJ,UAAU6S,QAAU,WACvB,MAAOtS,MAAKuR,SAAsC,GAA3BvR,KAAKuR,QAAQrF,YAIxCpD,EAAOrJ,UAAUoS,oBAAsB,WACnC,IAAK,GAAIhR,GAAI,EAAGoH,EAAKjI,KAAKgR,OAAOtQ,OAAQG,EAAIoH,EAAIpH,GAAK,EAClDb,KAAK6G,KAAK7G,KAAKgR,OAAOnQ,KAK9BiI,EAAOrJ,UAAUoH,KAAO,SAASjB,GAC7B,IAAI5F,KAAKuO,aAAT,CAMA,IAAKvO,KAAKwD,GAEN,WADAxD,MAAKgR,OAAO9Q,KAAK0F,EAIrB,KAAKA,EAAKrC,KAEN,WADAvD,MAAKe,KAAK,QAAS,kBAIvB,IAAIoH,GAAU7B,KAAKU,UAAUpB,EAC7B,IAAI5F,KAAKsS,UACLtS,KAAKuR,QAAQ1K,KAAKsB,OACf,CACH,GAAI6G,GAAO,GAAIC,gBACXE,EAAMnP,KAAKmR,SAAW,IAAMvL,EAAKrC,KAAKgP,aAC1CvD,GAAK1L,KAAK,OAAQ6L,GAAK,GACvBH,EAAKwD,iBAAiB,eAAgB,oBACtCxD,EAAKnI,KAAKsB,MAIlBW,EAAOrJ,UAAUkG,MAAQ,YAChB3F,KAAKuO,cAAgBvO,KAAKsS,YAC3BtS,KAAKuR,QAAQ5L,QACb3F,KAAKuO,cAAe,IAI5B7O,EAAOC,QAAUmJ,IAElBH,SAAS,EAAEC,cAAgB,IAAI6J,GAAG,SAAS3Q,EAAQpC,EAAOC,GACzD,GAAI+N,IAAiBgF,aAAiBvD,IAAO,kCACzCwD,EAAY,EAEZ1J,EAAanH,EAAQ,iBACrBS,EAAoBT,EAAQ,aAAaS,kBAEzCW,GACA0I,KAAM,aAENyB,WAAY,eACZE,WAAY,IAGZnG,iBAAkBwL,OAAU,GAC5BtL,WAAY,MAGZuL,SAAU,EACV5E,YAAa,SAAS6E,GAClB,GAAIC,GAAaC,SAASF,EAAO,GAC5BG,OAAMD,SAASF,EAAO,KAIvB5P,EAAK2P,SAAWC,EAAQ,EAAI,EAH5B5P,EAAK2P,SAAWE,EAKpB7P,EAAKkC,IAAMlC,EAAKuF,KAAOvF,EAAK2H,MAAQ3H,EAAK0I,KACrC1I,EAAK2P,SAAW,IAChB3P,EAAK2H,MAAQ3H,EAAKgQ,WAAW,UAE7BhQ,EAAK2P,SAAW,IAChB3P,EAAKuF,KAAOvF,EAAKgQ,WAAW,YAE5BhQ,EAAK2P,SAAW,IAChB3P,EAAKkC,IAAMlC,EAAKiQ,SAGxBnF,eAAgB,SAASjO,GACjBA,EAAG+F,cAAgBsN,SACnBlQ,EAAKuF,KAAK,iFAEVvF,EAAKiQ,OAASpT,GAItBmT,WAAY,SAASG,GACjB,MAAO,YACH,GAAIC,GAAOC,MAAM9T,UAAUwB,MAAMC,KAAKZ,UACtCgT,GAAKE,QAAQH,GACbnQ,EAAKiQ,OAAO9S,MAAM6C,EAAMoQ,KAGhCH,OAAQ,WACJ,GAAI5G,IAAM,EACN+G,EAAOC,MAAM9T,UAAUwB,MAAMC,KAAKZ,UACtCgT,GAAKE,QAAQ,WACb,KAAK,GAAI3S,GAAI,EAAGqB,EAAIoR,EAAK5S,OAAQG,EAAIqB,EAAGrB,IAChCyS,EAAKzS,YAAcmB,SACnBsR,EAAKzS,GAAK,IAAMyS,EAAKzS,GAAG4S,KAAO,KAAOH,EAAKzS,GAAGsH,QAC9CoE,GAAM,EAGdA,GAAMmH,QAAQ7I,MAAMxK,MAAMqT,QAASJ,GAAQI,QAAQtO,IAAI/E,MAAMqT,QAASJ,IAK1E5F,cAAeA,EAIftJ,QAAS,WACL,MAAI/B,QAAOG,qBACA,UACAH,OAAOI,wBACP,SACAJ,OAAOE,kBACP,YAEA,iBAMfyC,SAAW,WACP,GAAiC,mBAAtBzC,GACP,QAGJ,IAOI+H,GAAI3F,EAPJiB,GAAO,EACPsI,GAAa,EAEb1G,GAAa,EACbvC,GAAO,EACP0F,IAAwBtI,OAAOI,uBAGnC,KACI6H,EAAK,GAAI/H,GAAkBmL,GAAgB1C,WAAYE,iBAAiB,MAC1E,MAAO5J,GACLsE,GAAO,EACPsI,GAAa,EAGjB,GAAItI,EACA,IACIjB,EAAK2F,EAAGI,kBAAkB,eAC5B,MAAOpJ,GACLsE,GAAO,EAIf,GAAIA,EAAM,CAEN,IACIjB,EAAGO,WAAa,OAChBsC,GAAa,EACf,MAAOlG,IAMT,GAAIqS,GAAa,GAAIpR,GAAkBmL,KACvC,KACI,GAAIkG,GAAaD,EAAWjJ,kBAAkB,yBAC9CzF,GAAO2O,EAAWvQ,SACpB,MAAO/B,IAETqS,EAAWhO,QAUf,GANIuI,IACAA,IAAe5D,EAAGX,YAKjBgB,GAAuB/E,EAAM,CAE9B,GAAIiO,GAAgB,GAAItR,GAAkBmL,GAAgB1C,WAAYE,iBAAiB,KACvF2I,GAAclJ,oBAAsB,WAChCA,GAAsB,EAElBzH,GAAQA,EAAK8B,WACb9B,EAAK8B,SAAS2F,qBAAsB,IAG5CkJ,EAAcnJ,kBAAkB,0BAEhC9C,WAAW,WACPiM,EAAclO,SACf,KAOP,MAJI2E,IACAA,EAAG3E,SAIHuI,WAAYA,EACZtI,KAAMA,EACN4B,WAAYA,EACZsM,OAAQ7O,EACR5B,SAAU4B,EACVA,KAAMA,EACN0F,oBAAqBA,MAM7BwD,WAAY,SAAS3K,GAEjB,OAAQA,GAAM,yCAAyCuQ,KAAKvQ,IAGhE4K,YAAa,SAAS5O,GAElB,OAAQA,GAAO,yCAAyCuU,KAAKvU,IAIjE8F,OAAO,EAEPb,SAAU,SAASuP,EAAMC,GACrBD,EAAKE,OAASD,EACdD,EAAKvU,UAAYwN,OAAOkH,OAAOF,EAAUxU,WACrCqG,aACIsO,MAAOJ,EACPK,YAAY,EACZC,UAAU,EACVC,cAAc,MAI1BpR,OAAQ,SAASqR,EAAMC,GACnB,IAAI,GAAIjV,KAAOiV,GACRA,EAAOC,eAAelV,KACrBgV,EAAKhV,GAAOiV,EAAOjV,GAG3B,OAAOgV,IAEXtN,KAAM+B,EAAW/B,KACjBhB,OAAQ+C,EAAW/C,OAEnBd,IAAK,WACD,GAAIlC,EAAKoC,MAAO,CACZ,GAAIiH,IAAM,EACN+G,EAAOC,MAAM9T,UAAUwB,MAAMC,KAAKZ,UACtCgT,GAAKE,QAAQ,WACb,KAAK,GAAI3S,GAAI,EAAGqB,EAAIoR,EAAK5S,OAAQG,EAAIqB,EAAGrB,IAChCyS,EAAKzS,YAAcmB,SACnBsR,EAAKzS,GAAK,IAAMyS,EAAKzS,GAAG4S,KAAO,KAAOH,EAAKzS,GAAGsH,QAC9CoE,GAAM,EAGdA,GAAMmH,QAAQ7I,MAAMxK,MAAMqT,QAASJ,GAAQI,QAAQtO,IAAI/E,MAAMqT,QAASJ,KAI9ElD,eAAiB,SAASuE,GAOtB,QAASC,GAA0B7U,GAC/B8U,EAAS3U,KAAKH,GACd4U,EAAOG,YAAYC,EAAa,KAGpC,QAAS7M,GAAcpI,GACfA,EAAM2U,QAAUE,GAAU7U,EAAM8F,MAAQmP,IACpCjV,EAAMkV,iBACNlV,EAAMkV,kBAENH,EAASnU,QACTmU,EAAS/M,WAjBrB,GAAI+M,MACAE,EAAc,sBAyBlB,OALIJ,GAAO9U,iBACP8U,EAAO9U,iBAAiB,UAAWqI,GAAe,GAC3CyM,EAAOM,aACdN,EAAOM,YAAY,YAAa/M,GAE7B0M,GACTvS,QAKF2F,MAAO,SAASkN,GAKZ,IAJA,GAAIC,MACA9N,EAAO6N,EAAG7N,KACVyI,EAAQsC,MAAQ,EAChBzL,EAAQ4I,KAAK6F,KAAK/N,EAAOnE,EAAKoE,YAC3BwI,EAAQzI,GAAM,CACjB,GAAIgO,GAAM9F,KAAK+F,IAAIjO,EAAMyI,EAAQ5M,EAAKoE,YAClCiO,EAAIL,EAAGjU,MAAM6O,EAAOuF,GAEpBrN,GACAxB,WAAYmM,EACZnR,EAAG4Q,MACHxM,KAAM2P,EACN5O,MAAOA,EAGXwO,GAAOjV,KAAK8H,GAEZ8H,EAAQuF,EACRjD,OAAS,EAGb,MADAO,IAAa,EACNwC,GAGXnP,kBAAmB,SAASiB,EAAMrG,GAC9B,GAAI4U,GAAK,GAAIC,WACbD,GAAGE,OAAS,SAASnK,GACjB3K,EAAG2K,EAAIoK,OAAOC,SAElBJ,EAAGK,kBAAkB5O,IAEzBQ,mBAAoB,SAASR,EAAMrG,GAC/B,GAAI4U,GAAK,GAAIC,WACbD,GAAGE,OAAS,SAASnK,GACjB3K,EAAG2K,EAAIoK,OAAOC,SAElBJ,EAAGM,mBAAmB7O,IAE1BZ,0BAA2B,SAASyN,GAEhC,IAAK,GADDiC,GAAY,GAAIC,YAAWlC,EAAOpT,QAC7BG,EAAI,EAAGA,EAAIiT,EAAOpT,OAAQG,IAC/BkV,EAAUlV,GAA4B,IAAvBiT,EAAOmC,WAAWpV,EAErC,OAAOkV,GAAUG,QAErBvS,YAAa,WACT,MAAO4L,MAAKC,SAASrC,SAAS,IAAIgJ,OAAO,IAI7CrI,SAAU,WACN,MAA6B,WAAtBH,SAASuB,UAIxBxP,GAAOC,QAAUuD,IAElBgG,YAAY,EAAEK,gBAAgB,KAAK6M,GAAG,SAAStU,EAAQpC,EAAOC,GAW7D,QAAS0W,GAAGtW,EAAIuW,EAASnW,GACrBH,KAAKD,GAAKA,EACVC,KAAKsW,QAAUA,EACftW,KAAKG,KAAOA,IAAQ,EAUxB,QAAS8C,MAQTA,EAAaxD,UAAU8W,QAAUrJ,OASjCjK,EAAaxD,UAAU2B,UAAY,SAAmBtB,GAClD,IAAKE,KAAKuW,UAAYvW,KAAKuW,QAAQzW,GAAQ,QAE3C,KAAK,GAAIe,GAAI,EAAGqB,EAAIlC,KAAKuW,QAAQzW,GAAOY,OAAQ8V,KAAS3V,EAAIqB,EAAGrB,IAC5D2V,EAAGtW,KAAKF,KAAKuW,QAAQzW,GAAOe,GAAGd,GAGnC,OAAOyW,IAUXvT,EAAaxD,UAAUsB,KAAO,SAAcjB,EAAO2W,EAAIC,EAAIC,EAAIC,EAAIC,GAC/D,IAAK7W,KAAKuW,UAAYvW,KAAKuW,QAAQzW,GAAQ,OAAO,CAElD,IAIMkB,GACAH,EAAG6P,EALLtP,EAAYpB,KAAKuW,QAAQzW,GACvBY,EAASU,EAAUV,OACnBS,EAAMb,UAAUI,OAChB8V,EAAKpV,EAAU,EAIrB,IAAI,IAAMV,EAAQ,CAGd,OAFI8V,EAAGrW,MAAMH,KAAKO,eAAeT,EAAO0W,EAAGzW,IAAI,GAEvCoB,GACJ,IAAK,GAAG,MAAOqV,GAAGzW,GAAGmB,KAAKsV,EAAGF,UAAU,CACvC,KAAK,GAAG,MAAOE,GAAGzW,GAAGmB,KAAKsV,EAAGF,QAASG,IAAK,CAC3C,KAAK,GAAG,MAAOD,GAAGzW,GAAGmB,KAAKsV,EAAGF,QAASG,EAAIC,IAAK,CAC/C,KAAK,GAAG,MAAOF,GAAGzW,GAAGmB,KAAKsV,EAAGF,QAASG,EAAIC,EAAIC,IAAK,CACnD,KAAK,GAAG,MAAOH,GAAGzW,GAAGmB,KAAKsV,EAAGF,QAASG,EAAIC,EAAIC,EAAIC,IAAK,CACvD,KAAK,GAAG,MAAOJ,GAAGzW,GAAGmB,KAAKsV,EAAGF,QAASG,EAAIC,EAAIC,EAAIC,EAAIC,IAAK,EAG/D,IAAKhW,EAAI,EAAGG,EAAO,GAAIuS,OAAMpS,EAAK,GAAIN,EAAIM,EAAKN,IAC3CG,EAAKH,EAAI,GAAKP,UAAUO,EAG5B2V,GAAGzW,GAAGM,MAAMmW,EAAGF,QAAStV,OAExB,KAAKH,EAAI,EAAGA,EAAIH,EAAQG,IAGpB,OAFIO,EAAUP,GAAGV,MAAMH,KAAKO,eAAeT,EAAOsB,EAAUP,GAAGd,IAAI,GAE3DoB,GACJ,IAAK,GAAGC,EAAUP,GAAGd,GAAGmB,KAAKE,EAAUP,GAAGyV,QAAU,MACpD,KAAK,GAAGlV,EAAUP,GAAGd,GAAGmB,KAAKE,EAAUP,GAAGyV,QAASG,EAAK,MACxD,KAAK,GAAGrV,EAAUP,GAAGd,GAAGmB,KAAKE,EAAUP,GAAGyV,QAASG,EAAIC,EAAK,MAC5D,SACI,IAAK1V,EAAM,IAAK0P,EAAI,EAAG1P,EAAO,GAAIuS,OAAMpS,EAAK,GAAIuP,EAAIvP,EAAKuP,IACtD1P,EAAK0P,EAAI,GAAKpQ,UAAUoQ,EAG5BtP,GAAUP,GAAGd,GAAGM,MAAMe,EAAUP,GAAGyV,QAAStV,GAK5D,OAAO,GAWXiC,EAAaxD,UAAUG,GAAK,SAAYE,EAAOC,EAAIuW,GAK/C,MAJKtW,MAAKuW,UAASvW,KAAKuW,YACnBvW,KAAKuW,QAAQzW,KAAQE,KAAKuW,QAAQzW,OACvCE,KAAKuW,QAAQzW,GAAOI,KAAK,GAAImW,GAAItW,EAAIuW,GAAWtW,OAEzCA,MAWXiD,EAAaxD,UAAUU,KAAO,SAAcL,EAAOC,EAAIuW,GAKnD,MAJKtW,MAAKuW,UAASvW,KAAKuW,YACnBvW,KAAKuW,QAAQzW,KAAQE,KAAKuW,QAAQzW,OACvCE,KAAKuW,QAAQzW,GAAOI,KAAK,GAAImW,GAAGtW,EAAIuW,GAAWtW,MAAM,IAE9CA,MAWXiD,EAAaxD,UAAUc,eAAiB,SAAwBT,EAAOC,EAAII,GACvE,IAAKH,KAAKuW,UAAYvW,KAAKuW,QAAQzW,GAAQ,MAAOE,KAElD,IAAIoB,GAAYpB,KAAKuW,QAAQzW,GACvBgX,IAEN,IAAI/W,EAAI,IAAK,GAAIc,GAAI,EAAGH,EAASU,EAAUV,OAAQG,EAAIH,EAAQG,IACvDO,EAAUP,GAAGd,KAAOA,GAAMqB,EAAUP,GAAGV,OAASA,GAChD2W,EAAO5W,KAAKkB,EAAUP,GAU9B,OAHIiW,GAAOpW,OAAQV,KAAKuW,QAAQzW,GAASgX,EACpC9W,KAAKuW,QAAQzW,GAAS,KAEpBE,MASXiD,EAAaxD,UAAUe,mBAAqB,SAA4BV,GACpE,MAAKE,MAAKuW,SAENzW,EAAOE,KAAKuW,QAAQzW,GAAS,KAC5BE,KAAKuW,WAEHvW,MALmBA,MAW9BiD,EAAaxD,UAAUW,IAAM6C,EAAaxD,UAAUc,eACpD0C,EAAaxD,UAAUsX,YAAc9T,EAAaxD,UAAUG,GAK5DqD,EAAaxD,UAAUuX,gBAAkB,WACrC,MAAOhX,OAMXiD,EAAaA,aAAeA,EAC5BA,EAAagU,cAAgBhU,EAC7BA,EAAaiU,cAAgBjU,EAEzB,gBAAoBvD,IAAUA,EAAOC,UACrCD,EAAOC,QAAUsD,QAGnBkU,IAAI,SAASrV,EAAQpC,EAAOC,GAmB9B,QAASyX,GAAUxR,GAEf5F,KAAKoS,MAAQ,EACbpS,KAAKqX,WAAazR,EAClB5F,KAAKsX,SAAW,GAAItB,YAAWhW,KAAKqX,YACpCrX,KAAKU,OAASV,KAAKqX,WAAWE,WAwOlC,QAASC,KACLxX,KAAKyX,cAAgB,GAAIC,GAqP7B,QAASC,GAAaC,GAClB,GAAI3V,GAAO2V,EAAE3B,WAAW,EAExB,OAAGhU,IAAQ,KAAc,KACtBA,GAAQ,MAAe,MACvBA,GAAQ,QAAiB,OACzBA,GAAQ,SAAkB,QACtB,SAGX,QAAS4V,GAAWnQ,GAChB,MAAIA,GAAIhH,OAAS,IAEN,GAAKqF,OAAM2B,IAAOL,KAElBK,EAAIoQ,QAAQ,oBAAqBH,GAAcjX,OApgB9D,GAAIgX,GAAgB5V,EAAQ,mBAAmB4V,cAC3CK,EAAiBjW,EAAQ,mBAAmBiW,eAE5C9O,GACA/C,OAAQ,SAASN,GACb,GAAIoS,GAAW,GAAIZ,GAASxR,EAC5B,OAAOoS,GAAS9R,UAEpBgB,KAAM,SAAStB,GACX,GAAIqS,GAAS,GAAIT,EACjBS,GAAO/Q,KAAKtB,EACZ,IAAIsQ,GAAS+B,EAAOC,WACpB,OAAOhC,IAIfxW,GAAOC,QAAUsJ,EAUjBmO,EAAS3X,UAAUyG,OAAS,WACxB,GAAI3C,GAAOvD,KAAKmY,cAChB,IAAI5U,EAAO,IAAK,CACZ,GAAI6U,GAAkB7U,CACtB,OAAO6U,GACJ,IAAY,IAAP7U,GAAe,GAAK,CAC5B,GAAI8U,IAA0B,IAAP9U,GAAe,EACtC,OAAO8U,GAEX,GAAIhR,EACJ,KAAKA,EAAc,IAAP9D,IAAgB,GACxB,MAAOvD,MAAKsY,WAAWjR,EACpB,KAAKA,EAAc,IAAP9D,IAAgB,GAC/B,MAAOvD,MAAKuY,cAAclR,EACvB,KAAKA,EAAc,IAAP9D,IAAgB,GAC/B,MAAOvD,MAAKwY,aAAanR,EACtB,KAAKA,EAAc,IAAP9D,IAAgB,GAC/B,MAAOvD,MAAKyY,WAAWpR,EAE3B,QAAO9D,GACH,IAAK,KACD,MAAO,KACX,KAAK,KACD,MACJ,KAAK,KACD,OAAO,CACX,KAAK,KACD,OAAO,CACX,KAAK,KACD,MAAOvD,MAAK0Y,cAChB,KAAK,KACD,MAAO1Y,MAAK2Y,eAChB,KAAK,KACD,MAAO3Y,MAAKmY,cAChB,KAAK,KACD,MAAOnY,MAAK4Y,eAChB,KAAK,KACD,MAAO5Y,MAAK6Y,eAChB,KAAK,KACD,MAAO7Y,MAAK8Y,eAChB,KAAK,KACD,MAAO9Y,MAAK+Y,aAChB,KAAK,KACD,MAAO/Y,MAAKgZ,cAChB,KAAK,KACD,MAAOhZ,MAAKiZ,cAChB,KAAK,KACD,MAAOjZ,MAAKkZ,cAChB,KAAK,KACD,MACJ,KAAK,KACD,MACJ,KAAK,KACD,MACJ,KAAK,KACD,MACJ,KAAK,KAED,MADA7R,GAAOrH,KAAK4Y,gBACL5Y,KAAKuY,cAAclR,EAC9B,KAAK,KAED,MADAA,GAAOrH,KAAK6Y,gBACL7Y,KAAKuY,cAAclR,EAC9B,KAAK,KAED,MADAA,GAAOrH,KAAK4Y,gBACL5Y,KAAKsY,WAAWjR,EAC3B,KAAK,KAED,MADAA,GAAOrH,KAAK6Y,gBACL7Y,KAAKsY,WAAWjR,EAC3B,KAAK,KAED,MADAA,GAAOrH,KAAK4Y,gBACL5Y,KAAKwY,aAAanR,EAC7B,KAAK,KAED,MADAA,GAAOrH,KAAK6Y,gBACL7Y,KAAKwY,aAAanR,EAC7B,KAAK,KAED,MADAA,GAAOrH,KAAK4Y,gBACL5Y,KAAKyY,WAAWpR,EAC3B,KAAK,KAED,MADAA,GAAOrH,KAAK6Y,gBACL7Y,KAAKyY,WAAWpR,KAInC+P,EAAS3X,UAAU0Y,aAAe,WAC9B,GAAIgB,GAAmC,IAA5BnZ,KAAKsX,SAAStX,KAAKoS,MAE9B,OADApS,MAAKoS,QACE+G,GAGX/B,EAAS3X,UAAUmZ,cAAgB,WAC/B,GAAIQ,GAAQpZ,KAAKqZ,KAAK,GAClBC,EACqB,KAAR,IAAXF,EAAM,KAAgC,IAAXA,EAAM,GAEvC,OADApZ,MAAKoS,OAAS,EACPkH,GAGXlC,EAAS3X,UAAUoZ,cAAgB,WAC/B,GAAIO,GAAQpZ,KAAKqZ,KAAK,GAClBE,EAGY,KADA,KADE,IAAZH,EAAM,GACRA,EAAM,IACNA,EAAM,IACNA,EAAM,EAEV,OADApZ,MAAKoS,OAAS,EACPmH,GAGXnC,EAAS3X,UAAUqZ,cAAgB,WAC/B,GAAIM,GAAQpZ,KAAKqZ,KAAK,GAClBG,EAOY,KADA,KADA,KADA,KADA,KADA,KADM,IAAZJ,EAAM,GACZA,EAAM,IACNA,EAAM,IACNA,EAAM,IACNA,EAAM,IACNA,EAAM,IACNA,EAAM,IACNA,EAAM,EAEV,OADApZ,MAAKoS,OAAS,EACPoH,GAIXpC,EAAS3X,UAAUsZ,YAAc,WAC7B,GAAIU,GAAQzZ,KAAKmY,cACjB,OAAQsB,GAAQ,IAASA,EAAQA,EAAQ,KAG7CrC,EAAS3X,UAAUuZ,aAAe,WAC9B,GAAIM,GAAStZ,KAAK4Y,eAClB,OAAQU,GAAS,MAAWA,EAASA,EAAS,OAGlDlC,EAAS3X,UAAUwZ,aAAe,WAC9B,GAAIM,GAASvZ,KAAK6Y,eAClB,OAAQU,GAAShK,KAAKmK,IAAI,EAAG,IAAQH,EACjCA,EAAShK,KAAKmK,IAAI,EAAG,KAG7BtC,EAAS3X,UAAUyZ,aAAe,WAC9B,GAAIM,GAASxZ,KAAK8Y,eAClB,OAAQU,GAASjK,KAAKmK,IAAI,EAAG,IAAQF,EACjCA,EAASjK,KAAKmK,IAAI,EAAG,KAG7BtC,EAAS3X,UAAU6Y,WAAa,SAASjR,GACrC,GAAKrH,KAAKU,OAASV,KAAKoS,MAAQ/K,EAC5B,KAAM,IAAIrF,OAAM,4CACJhC,KAAKoS,MAAQ,IAAM/K,EAAO,IAAMrH,KAAKU,OAErD,IAAIiZ,GAAM3Z,KAAKqX,WAAWpW,MAAMjB,KAAKoS,MAAOpS,KAAKoS,MAAQ/K,EAKzD,OAJArH,MAAKoS,OAAS/K,EAIPsS,GAGXvC,EAAS3X,UAAU8Y,cAAgB,SAASlR,GAGxC,IAFA,GACqBuS,GAAG3X,EADpBmX,EAAQpZ,KAAKqZ,KAAKhS,GAClBxG,EAAI,EAAG6G,EAAM,GACX7G,EAAIwG,GACNuS,EAAIR,EAAMvY,GACL+Y,EAAI,KACLlS,GAAOtB,OAAOyT,aAAaD,GAC3B/Y,MACY,IAAJ+Y,GAAY,IACpB3X,GAAa,IAAJ2X,IAAa,EAAmB,GAAbR,EAAMvY,EAAE,GACpC6G,GAAOtB,OAAOyT,aAAa5X,GAC3BpB,GAAK,IAELoB,GAAa,GAAJ2X,IAAW,IAAqB,GAAbR,EAAMvY,EAAE,KAAY,EAC9B,GAAbuY,EAAMvY,EAAE,GACb6G,GAAOtB,OAAOyT,aAAa5X;AAC3BpB,GAAK,EAIb,OADAb,MAAKoS,OAAS/K,EACPK,GAGX0P,EAAS3X,UAAU+Y,aAAe,SAASnR,GAEvC,IAAI,GADAyS,GAAU,GAAIvG,OAAMlM,GAChBxG,EAAI,EAAGA,EAAIwG,EAAOxG,IACtBiZ,EAAQjZ,GAAKb,KAAKkG,QAEtB,OAAO4T,IAGX1C,EAAS3X,UAAUgZ,WAAa,SAASpR,GAErC,IAAI,GADA0S,MACIlZ,EAAI,EAAGA,EAAIwG,EAAOxG,IAAI,CAC1B,GAAIrB,GAAOQ,KAAKkG,SACZkO,EAAQpU,KAAKkG,QACjB6T,GAAIva,GAAO4U,EAEf,MAAO2F,IAGX3C,EAAS3X,UAAUiZ,aAAe,WAC9B,GAAIa,GAASvZ,KAAK6Y,gBACdmB,EAAOT,GAAU,GACjBU,GAASV,GAAU,GAAM,KAAQ,IACjCW,EAAsB,QAATX,EAAsB,OACvC,QAAgB,GAARS,EAAY,GAAI,GACpBE,EAAW3K,KAAKmK,IAAI,EAAGO,EAAM,KAGrC7C,EAAS3X,UAAUkZ,cAAgB,WAC/B,GAAIwB,GAAMna,KAAK6Y,gBACXuB,EAAMpa,KAAK6Y,gBACXmB,EAAOG,GAAO,GACdF,GAASE,GAAO,GAAM,MAAS,KAC/BE,EAAgB,QAANF,EAAkB,QAC5BG,EAAOD,EAAQ9K,KAAKmK,IAAI,EAAGO,EAAM,IACjCG,EAAQ7K,KAAKmK,IAAI,EAAGO,EAAM,GAC9B,QAAgB,GAARD,EAAY,GAAI,GAAMM,GAGlClD,EAAS3X,UAAU4Z,KAAO,SAAS3Y,GAC/B,GAAIgQ,GAAI1Q,KAAKoS,KACb,IAAI1B,EAAIhQ,GAAUV,KAAKU,OACnB,MAAOV,MAAKsX,SAASiD,SAAS7J,EAAGA,EAAIhQ,EAErC,MAAM,IAAIsB,OAAM,+CAQxBwV,EAAO/X,UAAUyY,UAAY,WACzB,MAAOlY,MAAKyX,cAAcS,aAG9BV,EAAO/X,UAAUyH,KAAO,SAASkN,GAC7B,GAAI7Q,SAAa,EACjB,IAAY,UAARA,EACAvD,KAAKwa,YAAYpG,OACd,IAAY,UAAR7Q,EACHgM,KAAKkL,MAAMrG,KAAWA,EACtBpU,KAAK0a,aAAatG,GAElBpU,KAAK2a,YAAYvG,OAElB,IAAY,WAAR7Q,EACH6Q,KAAU,EACVpU,KAAKyX,cAAcmD,OAAO,KACnBxG,KAAU,GACjBpU,KAAKyX,cAAcmD,OAAO,SAE3B,IAAY,aAARrX,EACPvD,KAAKyX,cAAcmD,OAAO,SACvB,CAAA,GAAY,UAARrX,EAgCP,KAAM,IAAIvB,OAAM,SAAWuB,EAAO,sBA/BlC,IAAc,OAAV6Q,EACApU,KAAKyX,cAAcmD,OAAO,SACvB,CACH,GAAI9U,GAAcsO,EAAMtO,WACxB,IAAIA,GAAeyN,MACfvT,KAAK6a,WAAWzG,OACb,IAAItO,GAAeC,MAAQD,GAAegV,KAC7C9a,KAAK+a,SAAS3G,OACX,IAAItO,GAAeK,YACnB4R,EAAeiD,mBACdhb,KAAK+a,SAAS,GAAI/E,YAAW5B,IAE7BpU,KAAK+a,SAAS3G,OAEf,IAAI,qBAAuBA,GAC3B2D,EAAeiD,mBACdhb,KAAK+a,SAAS,GAAI/E,YAAW5B,EAAM8B,SAEnClW,KAAK+a,SAAS3G,EAAM8B,YAErB,IAAIpQ,GAAemH,OACtBjN,KAAKib,YAAY7G,OACd,IAAItO,GAAeuJ,KACtBrP,KAAKwa,YAAYpG,EAAMjH,gBACpB,CAAA,GAAiC,kBAAtBiH,GAAM8G,aAGpB,KAAM,IAAIlZ,OAAM,SAAW8D,EAAYqH,WAAa,sBAFpDnN,MAAKyX,cAAcmD,OAAOxG,EAAM8G,kBAQ5Clb,KAAKyX,cAAc0D,SAIvB3D,EAAO/X,UAAUsb,SAAW,SAAS9T,GACjC,GAAIvG,GAASuG,EAAKvG,QAAUuG,EAAKsQ,YAActQ,EAAKI,IACpD,IAAI3G,GAAU,GACVV,KAAKob,WAAW,IAAO1a,OACpB,IAAIA,GAAU,MACjBV,KAAKyX,cAAcmD,OAAO,KAC1B5a,KAAKqb,YAAY3a,OACd,CAAA,KAAIA,GAAU,YAIjB,KAAM,IAAIsB,OAAM,iBAHhBhC,MAAKyX,cAAcmD,OAAO,KAC1B5a,KAAKsb,YAAY5a,GAIrBV,KAAKyX,cAAcmD,OAAO3T,IAG9BuQ,EAAO/X,UAAU+a,YAAc,SAAS9S,GACpC,GAAIhH,GAASmX,EAAWnQ,EAExB,IAAIhH,GAAU,GACVV,KAAKob,WAAW,IAAO1a,OACpB,IAAIA,GAAU,MACjBV,KAAKyX,cAAcmD,OAAO,KAC1B5a,KAAKqb,YAAY3a,OACd,CAAA,KAAIA,GAAU,YAIjB,KAAM,IAAIsB,OAAM,iBAHhBhC,MAAKyX,cAAcmD,OAAO,KAC1B5a,KAAKsb,YAAY5a,GAIrBV,KAAKyX,cAAcmD,OAAOlT,IAG9B8P,EAAO/X,UAAUob,WAAa,SAASU,GACnC,GAAI7a,GAAS6a,EAAI7a,MACjB,IAAIA,GAAU,GACVV,KAAKob,WAAW,IAAO1a,OACpB,IAAIA,GAAU,MACjBV,KAAKyX,cAAcmD,OAAO,KAC1B5a,KAAKqb,YAAY3a,OACd,CAAA,KAAIA,GAAU,YAIjB,KAAM,IAAIsB,OAAM,iBAHhBhC,MAAKyX,cAAcmD,OAAO,KAC1B5a,KAAKsb,YAAY5a,GAIrB,IAAI,GAAIG,GAAI,EAAGA,EAAIH,EAASG,IACxBb,KAAKkH,KAAKqU,EAAI1a,KAItB2W,EAAO/X,UAAUib,aAAe,SAASc,GACrC,IAAK,IAASA,GAAOA,GAAO,IACxBxb,KAAKyX,cAAcmD,OAAa,IAANY,OACvB,IAAI,GAAQA,GAAOA,GAAO,IAC7Bxb,KAAKyX,cAAcmD,OAAO,KAC1B5a,KAAKob,WAAWI,OACb,KAAI,KAASA,GAAOA,GAAO,IAC9Bxb,KAAKyX,cAAcmD,OAAO,KAC1B5a,KAAKyb,UAAUD,OACZ,IAAK,GAAUA,GAAOA,GAAO,MAChCxb,KAAKyX,cAAcmD,OAAO,KAC1B5a,KAAKqb,YAAYG,OACd,KAAI,OAAWA,GAAOA,GAAO,MAChCxb,KAAKyX,cAAcmD,OAAO,KAC1B5a,KAAK0b,WAAWF,OACb,IAAK,GAAcA,GAAOA,GAAO,WACpCxb,KAAKyX,cAAcmD,OAAO,KAC1B5a,KAAKsb,YAAYE,OACd,KAAI,YAAeA,GAAOA,GAAO,WACpCxb,KAAKyX,cAAcmD,OAAO,KAC1B5a,KAAK2b,WAAWH,OACb,KAAI,oBAAuBA,GAAOA,GAAO,mBAC5Cxb,KAAKyX,cAAcmD,OAAO,KAC1B5a,KAAK4b,WAAWJ,OACb,CAAA,KAAI,GAAsBA,GAAOA,GAAO,qBAI3C,KAAM,IAAIxZ,OAAM,kBAHhBhC,MAAKyX,cAAcmD,OAAO,KAC1B5a,KAAK6b,YAAYL,KAMzBhE,EAAO/X,UAAUkb,YAAc,SAASa,GACpC,GAAIxB,GAAO,CACPwB,GAAM,IACNxB,EAAO,EACPwB,GAAOA,EAEX,IAAIvB,GAAO1K,KAAKkL,MAAMlL,KAAKnK,IAAIoW,GAAOjM,KAAKuM,KACvCC,EAAQP,EAAMjM,KAAKmK,IAAI,EAAGO,GAAO,EACjC+B,EAAQzM,KAAKkL,MAAMsB,EAAQxM,KAAKmK,IAAI,EAAG,KACvCuC,EAAQ1M,KAAKmK,IAAI,EAAG,IACpBS,EAAOH,GAAQ,GAAQC,EAAI,MAAS,GACnC+B,EAAQC,EAAO,QAChB7B,EAAM4B,EAAQC,CAClBjc,MAAKyX,cAAcmD,OAAO,KAC1B5a,KAAK2b,WAAWxB,GAChBna,KAAK2b,WAAWvB,IAGpB5C,EAAO/X,UAAUwb,YAAc,SAAS3b,GACpC,GAAImR,GAAOxD,OAAOwD,KAAKnR,GACnBoB,EAAS+P,EAAK/P,MAClB,IAAIA,GAAU,GACVV,KAAKob,WAAW,IAAO1a,OACpB,IAAIA,GAAU,MACjBV,KAAKyX,cAAcmD,OAAO,KAC1B5a,KAAKqb,YAAY3a,OACd,CAAA,KAAIA,GAAU,YAIjB,KAAM,IAAIsB,OAAM,iBAHhBhC,MAAKyX,cAAcmD,OAAO,KAC1B5a,KAAKsb,YAAY5a,GAIrB,IAAI,GAAIwb,KAAQ5c,GACRA,EAAIoV,eAAewH,KACnBlc,KAAKkH,KAAKgV,GACVlc,KAAKkH,KAAK5H,EAAI4c,MAK1B1E,EAAO/X,UAAU2b,WAAa,SAASI,GACnCxb,KAAKyX,cAAcmD,OAAOY,IAG9BhE,EAAO/X,UAAU4b,YAAc,SAASG,GACpCxb,KAAKyX,cAAcmD,OAAOY,GAAO,GACjCxb,KAAKyX,cAAcmD,OAAa,IAANY,IAG9BhE,EAAO/X,UAAU6b,YAAc,SAASE,GACpC,GAAIha,GAAU,WAANga,CACRxb,MAAKyX,cAAcmD,QAAY,WAAJpZ,KAAoB,IAC/CxB,KAAKyX,cAAcmD,QAAY,SAAJpZ,KAAoB,IAC/CxB,KAAKyX,cAAcmD,QAAY,MAAJpZ,KAAqB,GAChDxB,KAAKyX,cAAcmD,OAAY,IAAJpZ,IAG/BgW,EAAO/X,UAAUoc,YAAc,SAASL,GACpC,GAAIW,GAAOX,EAAMjM,KAAKmK,IAAI,EAAG,IACzB0C,EAAOZ,EAAMjM,KAAKmK,IAAI,EAAG,GAC7B1Z,MAAKyX,cAAcmD,QAAe,WAAPuB,KAAuB,IAClDnc,KAAKyX,cAAcmD,QAAe,SAAPuB,KAAuB,IAClDnc,KAAKyX,cAAcmD,QAAe,MAAPuB,KAAwB,GACnDnc,KAAKyX,cAAcmD,OAAe,IAAPuB,GAC3Bnc,KAAKyX,cAAcmD,QAAe,WAAPwB,KAAuB,IAClDpc,KAAKyX,cAAcmD,QAAe,SAAPwB,KAAuB,IAClDpc,KAAKyX,cAAcmD,QAAe,MAAPwB,KAAwB,GACnDpc,KAAKyX,cAAcmD,OAAe,IAAPwB,IAG/B5E,EAAO/X,UAAUgc,UAAY,SAASD,GAClCxb,KAAKyX,cAAcmD,OAAa,IAANY,IAG9BhE,EAAO/X,UAAUic,WAAa,SAASF,GACnCxb,KAAKyX,cAAcmD,QAAc,MAANY,IAAiB,GAC5Cxb,KAAKyX,cAAcmD,OAAa,IAANY,IAG9BhE,EAAO/X,UAAUkc,WAAa,SAASH,GACnCxb,KAAKyX,cAAcmD,OAAQY,IAAQ,GAAM,KACzCxb,KAAKyX,cAAcmD,QAAc,SAANY,KAAsB,IACjDxb,KAAKyX,cAAcmD,QAAc,MAANY,KAAsB,GACjDxb,KAAKyX,cAAcmD,OAAc,IAANY,IAG/BhE,EAAO/X,UAAUmc,WAAa,SAASJ,GACnC,GAAIW,GAAO5M,KAAKkL,MAAMe,EAAMjM,KAAKmK,IAAI,EAAG,KACpC0C,EAAOZ,EAAMjM,KAAKmK,IAAI,EAAG,GAC7B1Z,MAAKyX,cAAcmD,QAAe,WAAPuB,KAAuB,IAClDnc,KAAKyX,cAAcmD,QAAe,SAAPuB,KAAuB,IAClDnc,KAAKyX,cAAcmD,QAAe,MAAPuB,KAAwB,GACnDnc,KAAKyX,cAAcmD,OAAe,IAAPuB,GAC3Bnc,KAAKyX,cAAcmD,QAAe,WAAPwB,KAAuB,IAClDpc,KAAKyX,cAAcmD,QAAe,SAAPwB,KAAuB,IAClDpc,KAAKyX,cAAcmD,QAAe,MAAPwB,KAAwB,GACnDpc,KAAKyX,cAAcmD,OAAe,IAAPwB,MAsBhCC,kBAAkB,KAAKC,IAAI,SAASxa,EAAQpC,EAAOC,GA0BlD,QAAS+X,KACL1X,KAAKuc,WACLvc,KAAKwc,UA3BT,GAAIzE,KACJA,GAAe0E,eAAiB,WAC5B,IAEI,MADA,IAAI1W,WACG,EACT,MAAOzE,GACL,OAAO,MAIfyW,EAAeiD,oBAAsBjD,EAAe0E,gBAAkB,WAC9D,IACI,MAAiD,KAA1C,GAAK1W,OAAM,GAAIiQ,kBAAkB3O,KAC1C,MAAO/F,GACL,OAAO,MAInB5B,EAAOC,QAAQoY,eAAiBA,CAChC,IAAI2E,GAAchd,EAAOC,QAAQ+c,WACZ,oBAAVra,UACPqa,EAAchd,EAAOC,QAAQ+c,YAAcra,OAAOsa,mBAC9Cta,OAAOua,gBAAkBva,OAAOwa,eAAiBxa,OAAOqa,aAQhEhF,EAAcjY,UAAUmb,OAAS,SAAShV,GACnB,gBAATA,GACN5F,KAAKuc,QAAQrc,KAAK0F,IAElB5F,KAAKmb,QACLnb,KAAKwc,OAAOtc,KAAK0F,KAIzB8R,EAAcjY,UAAU0b,MAAQ,WAC5B,GAAInb,KAAKuc,QAAQ7b,OAAS,EAAG,CACzB,GAAIiZ,GAAM,GAAI3D,YAAWhW,KAAKuc,QAC1BxE,GAAeiD,qBACfrB,EAAMA,EAAIzD,QAEdlW,KAAKwc,OAAOtc,KAAKyZ,GACjB3Z,KAAKuc,aAIb7E,EAAcjY,UAAUyY,UAAY,WAEhC,GADAlY,KAAKmb,QACFpD,EAAe0E,eAAgB,CAE9B,IAAI,GADAK,GAAU,GAAIJ,GACV7b,EAAI,EAAGoH,EAAKjI,KAAKwc,OAAO9b,OAAQG,EAAIoH,EAAIpH,IAC5Cic,EAAQlC,OAAO5a,KAAKwc,OAAO3b,GAE/B,OAAOic,GAAQC,UAEf,MAAO,IAAIhX,MAAK/F,KAAKwc,SAI7B9c,EAAOC,QAAQ+X,cAAgBA,OAE7BsF,IAAI,SAASlb,EAAQpC,EAAOC,GAO9B,QAAS6E,GAASG,EAAIW,GAClB,MAAMtF,gBAAgBwE,IACtBxE,KAAK4E,IAAMD,EAEXzB,EAAKoC,MAAQA,EAIbtF,KAAKid,aAELjd,KAAKkd,aACLld,KAAKmd,aAGLnd,KAAKod,QAAU,IAEfpd,KAAKqd,KAAO,IAEZrd,KAAKsd,UAAY,EAGjBtd,KAAKud,OAAS,EAGdvd,KAAKgR,cAELhR,MAAKwd,YAzBmC,GAAIhZ,GAASG,GAPzD,GAAIzB,GAAOpB,EAAQ,SAoCnB0C,GAAS/E,UAAUoH,KAAO,SAASrB,GAE/B,GAAI0P,GAAKhS,EAAKgE,KAAK1B,EACnB,OAAI0P,GAAG7N,KAAOrH,KAAKqd,SACfrd,MAAKyd,aAAa,KAAMvI,KAI5BlV,KAAKid,UAAUjd,KAAKud,SAChBG,IAAK,EACLvI,OAAQnV,KAAK2d,OAAOzI,IAGpBhS,EAAKoC,QACLtF,KAAKid,UAAUjd,KAAKud,QAAQK,MAAQ,GAAIvO,OAI5CrP,KAAK6d,oBAAoB7d,KAAKud,aAC9Bvd,KAAKud,QAAU,KAInB/Y,EAAS/E,UAAUqe,eAAiB,WAGhC,GAAI/Y,GAAO/E,IACXA,MAAKyR,SAAWsM,YAAY,WAExB,GAAIvY,GAAMT,EAAKiM,OAAOlJ,OACtB,IAAItC,EAAIwY,UACJ,IAAK,GAAInd,GAAI,EAAGoH,EAAKzC,EAAI9E,OAAQG,EAAIoH,EAAIpH,GAAK,EAC1CkE,EAAKkZ,cAAczY,EAAI3E,QAG3BkE,GAAKkZ,cAAczY,IAExBxF,KAAKsd,YAGZ9Y,EAAS/E,UAAUwe,cAAgB,SAASzY,GACxC,GAAIT,GAAO/E,IACXwF,GAAMtC,EAAKgE,KAAK1B,GAChBtC,EAAKuE,mBAAmBjC,EAAK,SAASkC,GAClC3C,EAAKH,IAAIiC,KAAKa,KAES,IAAvB3C,EAAKiM,OAAOtQ,SACZgR,aAAa3M,EAAK0M,UAClB1M,EAAK0M,SAAW,OAMxBjN,EAAS/E,UAAUye,aAAe,WAC9B,IAAK,GAAI1a,KAAMxD,MAAKid,UACZjd,KAAKid,UAAUvI,eAAelR,IAC9BxD,KAAK6d,oBAAoBra,IAOrCgB,EAAS/E,UAAUge,YAAc,SAASjY,GAEtC,IAAK,GADDtF,IAAO,EACFW,EAAI,EAAGoH,EAAKjI,KAAKgR,OAAOtQ,OAAQG,EAAIoH,EAAIpH,GAAK,EAAG,CACrD,GAAIsd,GAAOne,KAAKgR,OAAOnQ,EACnBsd,KAAS3Y,EACTtF,GAAO,EACAie,EAAKH,WAAaG,EAAKC,QAAQ5Y,MAAS,IAC/CtF,GAAO,GAGXA,IACAF,KAAKgR,OAAO9Q,KAAKsF,GACZxF,KAAKyR,UACNzR,KAAK8d,mBAMjBtZ,EAAS/E,UAAU+d,SAAW,WAE1B,GAAIzY,GAAO/E,IACXA,MAAK4E,IAAIW,UAAY,SAASjE,GAC1B,GAAIkE,GAAMlE,EAAEsE,KACRC,EAAWL,EAAIM,WAGnB,IAAID,IAAaO,OAAQ,CACrB,GAAIH,GAAK/C,EAAKmD,0BAA0Bb,EACxCA,GAAMtC,EAAKgD,OAAOD,GAClBlB,EAAK8J,eAAerJ,MAMhChB,EAAS/E,UAAUoP,eAAiB,SAASrJ,GACzC,GAGII,GAHApC,EAAKgC,EAAI,GACT6Y,EAAQre,KAAKkd,UAAU1Z,GACvB8a,EAAQte,KAAKid,UAAUzZ,EAE3B,QAAQgC,EAAI,IAER,IAAK,KACD,GAAI2C,GAAU3E,CACR2E,IACFnI,KAAKuF,UAAUrC,EAAKgD,OAAOiC,GAE/B,MAEJ,KAAK,MAMD,GALAvC,EAAOyY,EAGPre,KAAKmd,UAAU3Z,GAAMgC,EAAI,IAEpBI,EACD,KAGJ5F,MAAKue,KAAK/a,EACV,MACJ,KAAK,MAED,GADAoC,EAAO0Y,EACK,CACR,GAAIZ,GAAMlY,EAAI,EAEdI,GAAK8X,IAAMnO,KAAKiP,IAAId,EAAK9X,EAAK8X,KAG1B9X,EAAK8X,KAAO9X,EAAKuP,OAAOzU,QACxBwC,EAAKkC,IAAI,SAAU,GAAIiK,MAASzJ,EAAKgY,aAC9B5d,MAAKid,UAAUzZ,IAEtBxD,KAAKke,eAIb,KAEJ,KAAK,QAGD,GADAtY,EAAOyY,GACFzY,EAAM,CACP,GAAIyP,GAAMrV,KAAKmd,UAAU3Z,EACzB,IAAI6R,KAAQ,EACR,KAEJzP,IACI8X,KAAM,MAAOla,EAAI,GACjB2R,WAEJnV,KAAKkd,UAAU1Z,GAAMoC,EAGzB,GAAIpE,GAAIgE,EAAI,GACRwC,EAAQxC,EAAI,EAChBI,GAAKuP,OAAO3T,GAAK,GAAIwU,YAAWhO,GAI5BxG,IAAMoE,EAAK8X,IAAI,IACf1d,KAAKye,kBAAkBjb,GAE3BxD,KAAKue,KAAK/a,EACV,MACJ,SAGIxD,KAAKyd,YAAYjY,KAM7BhB,EAAS/E,UAAUke,OAAS,SAASzI,GAIjC,IAHA,GAAIC,MACA9N,EAAO6N,EAAG7N,KACVyI,EAAQ,EACLA,EAAQzI,GAAM,CACjB,GAAIgO,GAAM9F,KAAK+F,IAAIjO,EAAMyI,EAAQ9P,KAAKqd,MAClC9H,EAAIL,EAAGjU,MAAM6O,EAAOuF,GACpBrN,GACAI,QAASmN,EAEbJ,GAAOjV,KAAK8H,GACZ8H,EAAQuF,EAGZ,MADAnS,GAAKkC,IAAI,UAAW+P,EAAOzU,OAAQ,WAC5ByU,GAIX3Q,EAAS/E,UAAU8e,KAAO,SAAS/a,GAC/B,GAAIka,GAAM1d,KAAKkd,UAAU1Z,GAAIka,GAGzB1d,MAAKmd,UAAU3Z,KAAQka,EAAI,KAC3B1d,KAAK0e,UAAUlb,GACfxD,KAAKmd,UAAU3Z,IAAM,GAGzBxD,KAAKyd,YAAYC,IAIrBlZ,EAAS/E,UAAUgf,kBAAoB,SAASjb,GAG5C,IAAK,GAFDoC,GAAO5F,KAAKkd,UAAU1Z,GACtB2R,EAASvP,EAAKuP,OACTtU,EAAI,EAAGoH,EAAKkN,EAAOzU,OAAQG,EAAIoH,EAAIpH,GAAK,EAE7C,GAAkBqM,SAAdiI,EAAOtU,GAEP,YADA+E,EAAK8X,IAAI,GAAK7c,EAItB+E,GAAK8X,IAAI,GAAKvI,EAAOzU,QAIzB8D,EAAS/E,UAAUoe,oBAAsB,SAASra,GAC9CN,EAAKkC,IAAI,2BAA4B5B,EAKrC,KAAK,GAJDoC,GAAO5F,KAAKid,UAAUzZ,GACtBmb,EAAK/Y,EAAKuP,OACVA,KACAyJ,EAAQrP,KAAK+F,IAAI1P,EAAK8X,IAAM1d,KAAKod,QAASuB,EAAGje,QACxCG,EAAI+E,EAAK8X,IAAK7c,EAAI+d,EAAO/d,GAAK,EAC9B8d,EAAG9d,GAAGge,MAAQhe,IAAM+E,EAAK8X,MAC1BiB,EAAG9d,GAAGge,MAAO,EACb1J,EAAOjV,MAAM,QAASsD,EAAI3C,EAAG8d,EAAG9d,GAAGuH,UAGvCxC,GAAK8X,IAAM1d,KAAKod,SAAWuB,EAAGje,QAC9ByU,EAAOjV,MAAM,MAAOsD,EAAImb,EAAGje,SAE/ByU,EAAO6I,WAAY,EACnBhe,KAAKyd,YAAYtI,IAIrB3Q,EAAS/E,UAAUif,UAAY,SAASlb,GACpCN,EAAKkC,IAAI,uBAAwB5B,EACjC,IAAIuB,GAAO/E,KACPmV,EAASnV,KAAKkd,UAAU1Z,GAAI2R,OAC5BD,EAAK,GAAInP,MAAKoP,EAClBjS,GAAK8C,kBAAkBkP,EAAI,SAASjP,GAChClB,EAAKQ,UAAUrC,EAAKgD,OAAOD,YAExBjG,MAAKkd,UAAU1Z,IAI1BgB,EAAS6H,mBAAqB,SAAS/D,GAOnC,GAAIwW,GAAUC,UAAUC,WAAWC,MAAM,iBACzC,IAAIH,IACAA,EAAU9L,SAAS8L,EAAQ,GAAG3M,MAAM,KAAKrK,SACrCgX,EAAU,IAAI,CACd,GAAII,GAAQ5W,EAAI6J,MAAM,WAClB2F,EAAU,aACd,IAAIoH,EAAMxe,OAAS,EACf,MAAOwe,GAAM,GAAKpH,EAAUoH,EAAM,GAK9C,MAAO5W,IAIX9D,EAAS/E,UAAU8F,UAAY,SAASC,KAExC9F,EAAOC,QAAQ6E,SAAWA,IAE3BmE,SAAS,KAAKwW,IAAI,SAASrd,EAAQpC,EAAOC,GACzC,GAAIsJ,GAAanH,EAAQ,iBAErBoB,GACAoC,OAAO,EAEPb,SAAU,SAASuP,EAAMC,GACrBD,EAAKE,OAASD,EACdD,EAAKvU,UAAYwN,OAAOkH,OAAOF,EAAUxU,WACrCqG,aACIsO,MAAOJ,EACPK,YAAY,EACZC,UAAU,EACVC,cAAc,MAI1BpR,OAAQ,SAASqR,EAAMC,GACnB,IAAI,GAAIjV,KAAOiV,GACRA,EAAOC,eAAelV,KACrBgV,EAAKhV,GAAOiV,EAAOjV,GAG3B,OAAOgV,IAEXtN,KAAM+B,EAAW/B,KACjBhB,OAAQ+C,EAAW/C,OAEnBd,IAAK,WACD,GAAIlC,EAAKoC,MAAO,CAEZ,IAAK,GADDgO,MACKzS,EAAI,EAAGA,EAAIP,UAAUI,OAAQG,IAClCyS,EAAKzS,GAAKP,UAAUO,EAExByS,GAAKE,QAAQ,cACbE,QAAQtO,IAAI/E,MAAMqT,QAASJ,KAInClD,eAAiB,SAASuE,GAOtB,QAASC,GAA0B7U,GAC/B8U,EAAS3U,KAAKH,GACd4U,EAAOG,YAAYC,EAAa,KAGpC,QAAS7M,GAAcpI,GACfA,EAAM2U,QAAUE,GAAU7U,EAAM8F,MAAQmP,IACpCjV,EAAMkV,iBACNlV,EAAMkV,kBAENH,EAASnU,QACTmU,EAAS/M,WAjBrB,GAAI+M,MACAE,EAAc,sBAyBlB,OALIJ,GAAO9U,iBACP8U,EAAO9U,iBAAiB,UAAWqI,GAAe,GAC3CyM,EAAOM,aACdN,EAAOM,YAAY,YAAa/M,GAE7B0M,GACT5U,MAEFgG,kBAAmB,SAASiB,EAAMrG,GAC9B,GAAI4U,GAAK,GAAIC,WACbD,GAAGE,OAAS,SAASnK,GACjB3K,EAAG2K,EAAIoK,OAAOC,SAElBJ,EAAGK,kBAAkB5O,IAEzBQ,mBAAoB,SAASR,EAAMrG,GAC/B,GAAI4U,GAAK,GAAIC,WACbD,GAAGE,OAAS,SAASnK,GACjB3K,EAAG2K,EAAIoK,OAAOC,SAElBJ,EAAGM,mBAAmB7O,IAE1BZ,0BAA2B,SAASyN,GAEhC,IAAK,GADDiC,GAAY,GAAIC,YAAWlC,EAAOpT,QAC7BG,EAAI,EAAGA,EAAIiT,EAAOpT,OAAQG,IAC/BkV,EAAUlV,GAA4B,IAAvBiT,EAAOmC,WAAWpV,EAErC,OAAOkV,GAAUG,QAErBvS,YAAa,WACT,MAAO4L,MAAKC,SAASrC,SAAS,IAAIgJ,OAAO,IAIjDzW,GAAOC,QAAUuD,IAElBqG,gBAAgB,UAAU,GF92F7B,IAAI6V,eACAC,SAAU,IAKVC,SACIC,aACIC,KAAM,WACF,OAAO,GAEXC,KAAM,mBAEVC,cACIF,KAAM,WACF,OAAO,GAEXC,KAAM,qBAMdE,SAAU,2CAIVC,WAIAC,MAAO,GACPrU,UACAsU,SAAU,GAEVlQ,QACImQ,WAAW,GAOfC,UAIIC,WAAY,EAIZC,QACI,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,WAKJrS,QAAQ,EAIRT,KAAM,sBAINE,KAAM,GAIN6S,IACIC,aAAa,EACbC,mBAAmB,EACnBC,OAAO,IAQnBlB,cAAamB,KAAO,WAChB,GAAIC,GAAOC,SAASC,qBAAqB,QAAQ,GAC7CC,EAAOF,SAASG,cAAc,OAClCD,GAAKE,IAAM,aACXF,EAAKpd,KAAO,WACZod,EAAKG,KAAO1B,aAAaO,SAAW,sBACpCgB,EAAKxW,MAAQ,MACbqW,EAAKO,YAAYJ,EACjB,IAAIK,GAAeP,SAASG,cAAc,MAC1CI,GAAaxd,GAAK,uBAClBwd,EAAaC,UAAY,iFACzBR,SAASS,KAAKH,YAAYC,GAC1B5B,aAAa+B,aACb/B,aAAajP,WAGjBsQ,SAAS5gB,iBAAiB,mBAAoBuf,aAAamB,MAAM,GAMjEnB,aAAa+B,WAAa,WAEtB,GAAsC,GAAlC/B,aAAaY,SAASG,GAAGG,MACzB,OAAO,CAEX,IAA2B,kBAAhBc,cACP,OAAO,CAGX,KAAK,GAAI5hB,KAAO4f,cAAaE,QACzB,GAAKF,aAAaE,QAAQ5K,eAAelV,GAAzC,CAGA,GAAI8gB,GAAQlB,aAAaE,QAAQ9f,GAC7B6hB,EAAU,GAAIpS,eAClBoS,GAAQ/d,KAAK,MAAO8b,aAAaO,SAAWW,EAAMb,MAAM,GACxD4B,EAAQC,aAAe,cACvBD,EAAQ7hB,IAAMA,EACd6hB,EAAQ3L,OAAS,WACb,GAAIY,GAAU,GAAI8K,aAClB9K,GAAQ9W,IAAMQ,KAAKR,IACnB8W,EAAQiL,gBAAgBvhB,KAAKwhB,SAAU,SAAUtL,GAC7CkJ,aAAaE,QAAQhJ,EAAQ9W,KAAKggB,KAAO,WACrC,GAAI/K,GAAS6B,EAAQmL,oBACrBhN,GAAOyB,OAASA,EAChBzB,EAAOtE,QAAQmG,EAAQoL,aAClBjN,EAAO3E,QACR2E,EAAO3E,MAAQ2E,EAAOkN,QAC1BlN,EAAO3E,MAAM,OAIzBuR,EAAQxa,SAYhBuY,aAAawC,iBAAmB,SAAUzZ,EAAS0Z,EAAU7e,GAEzD,GADAA,EAAUA,MACwC,GAA9Coc,aAAaY,SAASG,GAAGE,kBAA7B,CAGA,GAAIyB,IACAve,KAAM,UACN+c,OAAO,EAEXtd,GAAUiK,OAAO8U,OAAOD,EAAgB9e,GACxC6e,EAAWA,GAAY,KACnBzC,aAAaY,SAASG,GAAGG,OAAStd,EAAQsd,OAC1ClB,aAAaE,QAAQI,aAAaF,MAEtC,IAAIhc,GAAK6L,KAAK2S,MACVC,EAAiBxB,SAASG,cAAc,MAC5CqB,GAAeC,UAAY,uDAAyDlf,EAAQO,KAC5F0e,EAAeze,GAAK,gBAAkBA,EACtCye,EAAehB,UAAY,MAAQ9Y,EAAU,OAC7CsY,SAAS0B,eAAe,8BAA8BpB,YAAYkB,GAClEra,WAAW,WACP6Y,SAAS0B,eAAe,gBAAkB3e,GAAI0e,UAAY,uDAAyDlf,EAAQO,KAAO,mCAClIqE,WAAW,WACP,GAAIwa,GAAO3B,SAAS0B,eAAe,gBAAkB3e,EACjD4e,GAAKC,YACLD,EAAKC,WAAWC,YAAYF,IAEjC,MACJP,KAGPzC,aAAamD,mBAAqB,WAC9B,GAAyC,GAArCnD,aAAaY,SAASI,YAEtB,YADAK,SAAS0B,eAAe,sBAAsBK,MAAMC,QAAU,OAGlE,IAAIrD,aAAaQ,QAAQlf,OAAS,GAA2B,IAAtB0e,aAAaS,MAAa,CAC7D,GAAmE,OAA/DY,SAAS0B,eAAe,sBAAsBO,aAC9C,MAGJ,aADAjC,SAAS0B,eAAe,sBAAsBD,UAAY,+BAG9D,GAAI/Z,GAAU,iEAAmEiX,aAAaO,SAAW,gNAAkNP,aAAaS,MAAQ,WAChVY,UAAS0B,eAAe,sBAAsBlB,UAAY9Y,EACS,OAA/DsY,SAAS0B,eAAe,sBAAsBO,eAC9CjC,SAAS0B,eAAe,sBAAsBD,UAAY,4BAUlE9C,aAAauD,eAAiB,WAC1B,GAAIC,GAAQ,MAAQ,GAAK,IAAMrT,KAAKC,SAAW,GAAGrC,SAAS,IACvD8S,EAAab,aAAaY,SAASC,UAWvC,OAVgD,OAA5Cb,aAAaY,SAASE,OAAOD,IAC7B2C,EAAQxD,aAAaY,SAASE,OAAOD,GACrCA,MAGAA,EAAa,EACb2C,EAAQxD,aAAaY,SAASE,OAAOD,GACrCA,KAEJb,aAAaY,SAASC,WAAaA,EAC5B2C,GASXxD,aAAayD,cAAgB,SAAU1hB,GACnCA,EAAMA,GAAO,CAGb,KAAK,GAFD2hB,GAAO,GACPC,EAAW,6BACNliB,EAAI,EAAGA,EAAIM,EAAKN,IACrBiiB,GAAQC,EAASC,OAAOzT,KAAKkL,MAAMlL,KAAKC,SAAWuT,EAASriB,QAEhE,OAAOoiB,IAQX1D,aAAajP,QAAU,WAEnB,GAAwB,mBAAbqB,WAEP,MADA4N,cAAare,KAAK,QAAS,4CACpB,CAEX,IAAkC,IAA9Bqe,aAAaY,SAAS5S,MAA4C,IAA9BgS,aAAaY,SAAS1S,KAE1D,MADA8R,cAAare,KAAK,QAAS,2BACpB,CAEX,IAA4B,MAAxBqe,aAAa7N,SAAgD,GAA7B6N,aAAa7N,QAAQjO,KACrD,OAAO,CAEX,IAAIrB,GAAOmd,aAAayD,gBACpB/f,EAAO,GAAIkG,MAAK/G,GAChBmL,KAAMgS,aAAaY,SAAS5S,KAC5BE,KAAM8R,aAAaY,SAAS1S,KAC5BO,OAAQuR,aAAaY,SAASnS,QAElC/K,GAAKlD,GAAG,OAAQ,SAAUqC,GACtBmd,aAAare,KAAK,UAAWkB,KAEjCa,EAAKlD,GAAG,QAAS,WACbwf,aAAare,KAAK,gBAEtB+B,EAAKlD,GAAG,aAAc,SAAUqjB,GAC5B7D,aAAare,KAAK,cAAekiB,KAErC7D,aAAa7N,QAAUzO,GAQ3Bsc,aAAavY,KAAO,SAAUjB,GACX,MAAXA,EAAKpC,IACLkQ,QAAQjL,KAAK7C,EAEjB,KAAK,GAAI/E,GAAI,EAAGA,EAAIb,KAAK4f,QAAQlf,OAAQG,IACrC,GAAI+E,EAAKpC,IAAMxD,KAAK4f,QAAQ/e,GAAG2C,GAAI,CAC/BxD,KAAK4f,QAAQ/e,GAAGoiB,KAAKpc,KAAKjB,EAC1B,SAKZvG,QAAQ+f,cAQRA,aAAaxf,GAAG,QAAS,SAAUgG,GAC/BwZ,aAAawC,iBAAiBhc,EAAM,MAChCrC,KAAM,YASd6b,aAAaxf,GAAG,UAAW,SAAUqC,GACjCmd,aAAaS,MAAQ5d,EACrBmd,aAAamD,uBAMjBnD,aAAaxf,GAAG,aAAc,WAC1Bwf,aAAawC,iBAAiB,8BAA+B,MACzDre,KAAM,YASd6b,aAAaxf,GAAG,cAAe,SAAUqjB,GACrC,GAAIC,IACA1f,GAAIyf,EAAKngB,KACTmgB,KAAMA,EACNL,MAAOxD,aAAauD,iBAExBM,GAAKC,OAASA,EACdD,EAAKrjB,GAAG,OAAQ,WACZI,KAAK6G,MACDtD,KAAM,kBACNqC,MACIgd,MAAO5iB,KAAKkjB,OAAON,SAG3BxD,aAAare,KAAK,mBAAoB6hB,MAAO5iB,KAAKkjB,OAAON,MAAOM,QAAS1f,GAAIxD,KAAKkjB,OAAO1f,QAE7Fyf,EAAKrjB,GAAG,QAAS,WACbwf,aAAare,KAAK,eACdmiB,OAAQljB,KAAKkjB,WAmBrBD,EAAKrjB,GAAG,OAAQ,SAAUgG,GACtB,GAAkB,MAAdA,EAAKud,MAAT,CAGA,GAAIC,KACa,OAAbxd,EAAKA,OACLwd,EAASxd,EAAKA,MAElBwd,EAAOF,OAASljB,KAAKkjB,OACrB9D,aAAare,KAAK6E,EAAKud,MAAOC,MAElChE,aAAaQ,QAAQ1f,KAAKgjB,GAC1B9D,aAAawC,iBAAiB,sBAC9BxC,aAAamD,uBASjBnD,aAAaxf,GAAG,aAAc,SAAUgG,GACpCwZ,aAAaQ,QAAQ9e,OAAOse,aAAaQ,QAAQxB,QAAQxY,EAAKsd,QAAS,GACvE9D,aAAawC,iBAAiB,gBAC9BxC,aAAamD,uBAUjBnD,aAAaxf,GAAG,oBAAqB,SAAUgG,GAC3CwZ,aAAaE,QAAQC,YAAYC,MACjC,IAAI6D,GAAO,EACO,OAAdzd,EAAK0d,QACLD,GAAQ,aAAezd,EAAK0d,MAAQ,SAExCD,GAAQ,iCAAmCzd,EAAK6N,KAAO,YACvD2L,aAAawC,iBAAiByB,EAAM,MAChC9f,KAAM,cACN+c,OAAO,MAeflB,aAAaxf,GAAG,qBAAsB,SAAUgG,MAYhDwZ,aAAaxf,GAAG,kBAAmB,SAAUgG,MAY7CwZ,aAAaxf,GAAG,eAAgB,SAAUgG,MAY1CwZ,aAAaxf,GAAG,mBAAoB,SAAUgG,MAY9CwZ,aAAaxf,GAAG,iBAAkB,SAAUgG,MAW5CwZ,aAAaxf,GAAG,qBAAsB,SAAUgG,MAYhDwZ,aAAaxf,GAAG,oBAAqB,SAAUgG,MAY/CwZ,aAAaxf,GAAG,kBAAmB,SAAUgG","file":"couchfriends.api-latest.js","sourcesContent":["\"use strict\";\n/**\n * Couchfriends controller api. With the Couchfriends Controller API you can connect your phone or tablet to your HTML5\n * game and use it as a controller. The Controller API uses WebRTC (peer2peer) to send and receive input.\n *\n * @copyright (c) 2015 Mathieu de Ruiter, Couchfriends, Fellicht & Editors\n * @author Mathieu de Ruiter / http://www.fellicht.nl/\n *\n * For detailed information about the development with the Couchfriends API please visit https://couchfriends.com.\n * Please do not remove the header of this file.\n */\n\nvar COUCHFRIENDS = {\n REVISION: '4',\n /**\n * Array with sounds\n * @author http://opengameart.org/users/draconx\n */\n _sounds: {\n achievement: {\n play: function () {\n return false;\n }, // In case the file can't be loaded\n file: 'achievement.wav'\n },\n notification: {\n play: function () {\n return false;\n }, // In case the file can't be loaded\n file: 'notification.wav'\n }\n },\n /**\n * Url/path to assets\n */\n _baseUrl: 'https://couchfriends.com/cdn/api/assets/',\n /**\n * All connected players with their id, connection object, name\n */\n players: [],\n /**\n * The game code to join this game.\n */\n _code: '',\n socket: {}, // The Websocket object\n gameCode: '',\n // Object with current information and state over the game\n status: {\n connected: false\n }\n ,\n /**\n * Global settings for COUCHFRIENDS api\n * @type {object} settings list of settings\n */\n settings: {\n /**\n * The current color index.\n */\n colorIndex: 0,\n /**\n * Available player colors.\n */\n colors: [\n '#ff0000',\n '#00ff00',\n '#0000ff',\n '#ffff00',\n '#ff00ff',\n '#00ffff',\n '#ff9900',\n '#6d00ff',\n '#810000',\n '#008100',\n '#000081',\n '#818100',\n '#810081',\n '#008181',\n '#814c00',\n '#370081',\n '#ff7d7d',\n '#7dff7d',\n '#7d7dff',\n '#ffff7d',\n '#ff7dff',\n '#7dffff',\n '#ffcf8b',\n '#a983ff'\n ],\n /**\n * Enable SSL?\n */\n secure: true,\n /**\n * Websocket server\n */\n host: 'ws.couchfriends.com',\n /**\n * Websocket port\n */\n port: 80,\n /**\n * UI Settings\n */\n ui: {\n displayCode: true, // Show the code to join\n showNotifications: true,\n sound: true\n }\n }\n};\n\n/**\n * Init some javascript and styles to the game for dynamic overviews\n */\nCOUCHFRIENDS.init = function () {\n var head = document.getElementsByTagName('head')[0];\n var link = document.createElement('link');\n link.rel = 'stylesheet';\n link.type = 'text/css';\n link.href = COUCHFRIENDS._baseUrl + 'couchfriends.ui.css';\n link.media = 'all';\n head.appendChild(link);\n var containerDiv = document.createElement(\"div\");\n containerDiv.id = 'COUCHFRIENDS-overlay';\n containerDiv.innerHTML = '
';\n document.body.appendChild(containerDiv);\n COUCHFRIENDS._loadAudio();\n COUCHFRIENDS.connect();\n};\n\ndocument.addEventListener('DOMContentLoaded', COUCHFRIENDS.init, false);\n\n/**\n * Load all audio files\n * @private\n */\nCOUCHFRIENDS._loadAudio = function () {\n\n if (COUCHFRIENDS.settings.ui.sound == false) {\n return false;\n }\n if (typeof AudioContext != 'function') {\n return false;\n }\n\n for (var key in COUCHFRIENDS._sounds) {\n if (!COUCHFRIENDS._sounds.hasOwnProperty(key)) {\n continue;\n }\n var sound = COUCHFRIENDS._sounds[key];\n var request = new XMLHttpRequest();\n request.open('GET', COUCHFRIENDS._baseUrl + sound.file, true);\n request.responseType = 'arraybuffer';\n request.key = key;\n request.onload = function () {\n var context = new AudioContext();\n context.key = this.key;\n context.decodeAudioData(this.response, function (buffer) {\n COUCHFRIENDS._sounds[context.key].play = function () {\n var source = context.createBufferSource();\n source.buffer = buffer;\n source.connect(context.destination);\n if (!source.start)\n source.start = source.noteOn;\n source.start(0);\n }\n });\n };\n request.send();\n }\n};\n\n/**\n * Show notification and remove it after a short delay\n * @param message\n * @param duration the duration in ms\n * @param options object List with options\n * @param options.type string Type of the notification. Options: 'default', 'error', 'achievement'\n * @param options.sound boolean Play the default notification sound.\n */\nCOUCHFRIENDS.showNotification = function (message, duration, options) {\n options = options || {};\n if (COUCHFRIENDS.settings.ui.showNotifications == false) {\n return;\n }\n var defaultOptions = {\n type: 'default',\n sound: true\n };\n options = Object.assign(defaultOptions, options);\n duration = duration || 3500;\n if (COUCHFRIENDS.settings.ui.sound && options.sound) {\n COUCHFRIENDS._sounds.notification.play();\n }\n var id = Date.now();\n var notificationEl = document.createElement(\"div\");\n notificationEl.className = 'COUCHFRIENDS-notification COUCHFRIENDS-notification-' + options.type;\n notificationEl.id = 'COUCHFRIENDS-' + id;\n notificationEl.innerHTML = '

' + message + '

';\n document.getElementById('COUCHFRIENDS-notifications').appendChild(notificationEl);\n setTimeout(function () {\n document.getElementById('COUCHFRIENDS-' + id).className = 'COUCHFRIENDS-notification COUCHFRIENDS-notification-' + options.type + ' COUCHFRIENDS-notification-close';\n setTimeout(function () {\n var node = document.getElementById('COUCHFRIENDS-' + id);\n if (node.parentNode) {\n node.parentNode.removeChild(node);\n }\n }, 1000);\n }, duration);\n};\n\nCOUCHFRIENDS.showHideHowToPopup = function () {\n if (COUCHFRIENDS.settings.displayCode == false) {\n document.getElementById('COUCHFRIENDS-popup').style.display = 'none';\n return;\n }\n if (COUCHFRIENDS.players.length > 0 || COUCHFRIENDS._code == '') {\n if (document.getElementById('COUCHFRIENDS-popup').offsetParent === null) {\n return;\n }\n document.getElementById('COUCHFRIENDS-popup').className = 'COUCHFRIENDS-moveBottomLeft';\n return;\n }\n var message = ' Go to couchfriends.com with your phone or tablet and enter the code ' + COUCHFRIENDS._code + '';\n document.getElementById('COUCHFRIENDS-popup').innerHTML = message;\n if (document.getElementById('COUCHFRIENDS-popup').offsetParent !== null) {\n document.getElementById('COUCHFRIENDS-popup').className = 'COUCHFRIENDS-moveCenter';\n }\n};\n\n/**\n * Generate a \"random\" color for the player. This is handy for creating\n * unique player indications. The color is sent back to the controller.\n * @returns {string}\n * @private\n */\nCOUCHFRIENDS._generateColor = function () {\n var color = \"#\" + ((1 << 24) * Math.random() | 0).toString(16);\n var colorIndex = COUCHFRIENDS.settings.colorIndex;\n if (COUCHFRIENDS.settings.colors[colorIndex] != null) {\n color = COUCHFRIENDS.settings.colors[colorIndex];\n colorIndex++;\n }\n else {\n colorIndex = 0;\n color = COUCHFRIENDS.settings.colors[colorIndex];\n colorIndex++;\n }\n COUCHFRIENDS.settings.colorIndex = colorIndex;\n return color;\n};\n\n/**\n * Generate a code. Code should always be in capitals. Controller will uppercase all chars.\n * @param len\n * @returns {string}\n * @private\n */\nCOUCHFRIENDS._generateCode = function (len) {\n len = len || 3;\n var text = \"\";\n var possible = \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\"; // Caps only\n for (var i = 0; i < len; i++)\n text += possible.charAt(Math.floor(Math.random() * possible.length));\n\n return text;\n};\n\n/**\n * Connect function. This will connect the game to the websocket server.\n *\n * @returns {void|boolean} false on error or return void. See the .on('connect', function() { }) callback for more info.\n */\nCOUCHFRIENDS.connect = function () {\n\n if (typeof WebSocket == 'undefined') {\n COUCHFRIENDS.emit('error', 'Websockets are not supported by device.');\n return false;\n }\n if (COUCHFRIENDS.settings.host == '' || COUCHFRIENDS.settings.port == '') {\n COUCHFRIENDS.emit('error', 'Host or port is empty.');\n return false;\n }\n if (COUCHFRIENDS._socket != null && COUCHFRIENDS._socket.open == true) {\n return false;\n }\n var code = COUCHFRIENDS._generateCode();\n var peer = new Peer(code, {\n host: COUCHFRIENDS.settings.host,\n port: COUCHFRIENDS.settings.port,\n secure: COUCHFRIENDS.settings.secure\n });\n peer.on('open', function (code) {\n COUCHFRIENDS.emit('connect', code);\n });\n peer.on('close', function () {\n COUCHFRIENDS.emit('disconnect');\n });\n peer.on('connection', function (conn) {\n COUCHFRIENDS.emit('player.join', conn);\n });\n COUCHFRIENDS._socket = peer;\n};\n\n/**\n * Send data to the server/controller\n *\n * @param data Object object with data to send. See Api references for all available options.\n */\nCOUCHFRIENDS.send = function (data) {\n if (data.id == null) {\n console.warn(data);\n }\n for (var i = 0; i < this.players.length; i++) {\n if (data.id == this.players[i].id) {\n this.players[i].conn.send(data);\n break;\n }\n }\n};\n\nEmitter(COUCHFRIENDS);\n\n/**\n * Callback when an error has occurred.\n *\n * @param {object} data list with error details.\n * @param {string} data.message the error\n */\nCOUCHFRIENDS.on('error', function (data) {\n COUCHFRIENDS.showNotification(data, null, {\n type: 'error'\n })\n});\n\n/**\n * Callback after connection to the WebSocket server is successful. Best practise will be hosting a new game after\n * a successful connection.\n * @param string code. The code players can use to join.\n */\nCOUCHFRIENDS.on('connect', function (code) {\n COUCHFRIENDS._code = code;\n COUCHFRIENDS.showHideHowToPopup();\n});\n\n/**\n * Callback after the connection is lost from the WebSocket server.\n */\nCOUCHFRIENDS.on('disconnect', function () {\n COUCHFRIENDS.showNotification('Disconnected from server...', null, {\n type: 'error'\n });\n});\n\n/**\n * Callback when a player connected to the game.\n *\n * @param conn the peer connection to the player.\n */\nCOUCHFRIENDS.on('player.join', function (conn) {\n var player = {\n id: conn.peer,\n conn: conn,\n color: COUCHFRIENDS._generateColor()\n };\n conn.player = player;\n conn.on('open', function () {\n this.send({\n type: 'player.identify',\n data: {\n color: this.player.color\n }\n });\n COUCHFRIENDS.emit('player.identify', {color: this.player.color, player: {id: this.player.id}});\n });\n conn.on('close', function () {\n COUCHFRIENDS.emit('player.left', {\n player: this.player\n });\n });\n\n /**\n * Receiving data from one of the players.\n * @param data object from the controller\n * @param data.topic string The action of the player\n * player.orientation\n * player.click\n * player.clickDown\n * player.clickUp\n * player.buttonClick\n * player.buttonDown\n * player.buttonUp\n * player.identify\n *\n * @return void\n */\n conn.on('data', function (data) {\n if (data.topic == null) {\n return;\n }\n var params = {};\n if (data.data != null) {\n params = data.data;\n }\n params.player = this.player;\n COUCHFRIENDS.emit(data.topic, params);\n });\n COUCHFRIENDS.players.push(player);\n COUCHFRIENDS.showNotification('New player joined.');\n COUCHFRIENDS.showHideHowToPopup();\n});\n\n/**\n * Callback when a player disconnect from the game.\n *\n * @param {object} data list with the player information\n * @param {int} data.player the player object\n */\nCOUCHFRIENDS.on('playerLeft', function (data) {\n COUCHFRIENDS.players.splice(COUCHFRIENDS.players.indexOf(data.player), 1);\n COUCHFRIENDS.showNotification('Player left.');\n COUCHFRIENDS.showHideHowToPopup();\n});\n\n/**\n * Callback when achievement is unlocked. Displays notification and plays\n * a achievement sound.\n * @param object data\n * data.name the name of the achievement\n * data.image the url of the icon of the achievement\n */\nCOUCHFRIENDS.on('achievementUnlock', function (data) {\n COUCHFRIENDS._sounds.achievement.play();\n var html = '';\n if (data.image != null) {\n html += ' ';\n }\n html += 'Achievement unlocked: ' + data.name + '';\n COUCHFRIENDS.showNotification(html, null, {\n type: 'achievement',\n sound: false\n });\n});\n\n/**\n * Callback when a player chances the orientation of his device. Useful for movement tracking.\n *\n * For performance reasons this function will only be called if the orientation has changed since the previous frame.\n *\n * @param {object} data list with the player id and orientation\n * @param {int} data.player The player object\n * @param {float} [data.orientation.x] The x-as orientation (-1 to 1). E.g. -0.871\n * @param {float} [data.orientation.y] The y-as orientation (-1 to 1). E.g. 0.12\n * @param {float} [data.orientation.z] The z-as orientation (-1 to 1). E.g. -0.301\n */\nCOUCHFRIENDS.on('player.orientation', function (data) {\n //console.log('Player orientation changed. Player id: ' + data.id + ' Orientation: ' + data.orientation.x + ', ' + data.orientation.y + ', ' + data.orientation.z);\n});\n\n/**\n * Callback when a player changed its name or added additional information like selected color.\n *\n * @param {object} data list with the player information\n * @param {int} data.id The unique identifier of the player\n * @param {float} [data.name] The (new) name of the player. See http://couchfriends.com/pages/profile.html for possible\n * names and characters that might be included in the name.\n */\nCOUCHFRIENDS.on('player.identify', function (data) {\n //console.log('Player with id: '+ data.id +' changed its name to: ' + data.name);\n});\n\n/**\n * Callback when a player tapped canvas up and down\n *\n * @param {object} data list with the player information\n * @param {int} data.id The unique identifier of the player\n * @param {float} data.x Left position clicked in percentage\n * @param {float} data.y Top position clicked in percentage\n */\nCOUCHFRIENDS.on('player.click', function (data) {\n //console.log('Player clicked. Player id: ' + data.id + ' Click position: ' + data.x + ', ' + data.y);\n});\n\n/**\n * Callback when a player tapped canvas up and down\n *\n * @param {object} data list with the player information\n * @param {int} data.id The unique identifier of the player\n * @param {float} data.x Left position clicked in percentage\n * @param {float} data.y Top position clicked in percentage\n */\nCOUCHFRIENDS.on('player.clickDown', function (data) {\n //console.log('Player clicked. Player id: ' + data.id + ' Click position: ' + data.x + ', ' + data.y);\n});\n\n/**\n * Callback when a player tapped canvas up and down\n *\n * @param {object} data list with the player information\n * @param {int} data.id The unique identifier of the player\n * @param {float} data.x Left position clicked in percentage\n * @param {float} data.y Top position clicked in percentage\n */\nCOUCHFRIENDS.on('player.clickUp', function (data) {\n //console.log('Player clicked. Player id: ' + data.id + ' Click position: ' + data.x + ', ' + data.y);\n});\n\n/**\n * Callback when a player tapped a button\n *\n * @param {object} data list with the player and button information\n * @param {int} data.id The unique identifier of the button\n * @param {int} data.playerId The unique identifier of the player\n */\nCOUCHFRIENDS.on('player.buttonClick', function (data) {\n //console.log('Player clicked a button. Player id: ' + data.playerId + ' Button id: ' + data.id);\n});\n\n/**\n * Callback when a player tapped a button\n *\n * @param {object} data list with the player and button information\n * @param {int} data.player the player object\n * @param {object} data.button Object of the button information\n * @param {string} data.button.id The Button id\n */\nCOUCHFRIENDS.on('player.buttonDown', function (data) {\n //console.log('Player clicked a button. Player id: ' + data.playerId + ' Button id: ' + data.button.id);\n});\n\n/**\n * Callback when a player released a button\n *\n * @param {object} data list with the player and button information\n * @param {int} data.player the player object\n * @param {object} data.button Object of the button information\n * @param {string} data.button.id The Button id\n */\nCOUCHFRIENDS.on('player.buttonUp', function (data) {\n //console.log('Player clicked a button. Player id: ' + data.playerId + ' Button id: ' + data.button.id);\n});\n","\n/**\n * Expose `Emitter`.\n */\n\nif (typeof module !== 'undefined') {\n module.exports = Emitter;\n}\n\n/**\n * Initialize a new `Emitter`.\n *\n * @api public\n */\n\nfunction Emitter(obj) {\n if (obj) return mixin(obj);\n};\n\n/**\n * Mixin the emitter properties.\n *\n * @param {Object} obj\n * @return {Object}\n * @api private\n */\n\nfunction mixin(obj) {\n for (var key in Emitter.prototype) {\n obj[key] = Emitter.prototype[key];\n }\n return obj;\n}\n\n/**\n * Listen on the given `event` with `fn`.\n *\n * @param {String} event\n * @param {Function} fn\n * @return {Emitter}\n * @api public\n */\n\nEmitter.prototype.on =\n Emitter.prototype.addEventListener = function(event, fn){\n this._callbacks = this._callbacks || {};\n (this._callbacks['$' + event] = this._callbacks['$' + event] || [])\n .push(fn);\n return this;\n };\n\n/**\n * Adds an `event` listener that will be invoked a single\n * time then automatically removed.\n *\n * @param {String} event\n * @param {Function} fn\n * @return {Emitter}\n * @api public\n */\n\nEmitter.prototype.once = function(event, fn){\n function on() {\n this.off(event, on);\n fn.apply(this, arguments);\n }\n\n on.fn = fn;\n this.on(event, on);\n return this;\n};\n\n/**\n * Remove the given callback for `event` or all\n * registered callbacks.\n *\n * @param {String} event\n * @param {Function} fn\n * @return {Emitter}\n * @api public\n */\n\nEmitter.prototype.off =\n Emitter.prototype.removeListener =\n Emitter.prototype.removeAllListeners =\n Emitter.prototype.removeEventListener = function(event, fn){\n this._callbacks = this._callbacks || {};\n\n // all\n if (0 == arguments.length) {\n this._callbacks = {};\n return this;\n }\n\n // specific event\n var callbacks = this._callbacks['$' + event];\n if (!callbacks) return this;\n\n // remove all handlers\n if (1 == arguments.length) {\n delete this._callbacks['$' + event];\n return this;\n }\n\n // remove specific handler\n var cb;\n for (var i = 0; i < callbacks.length; i++) {\n cb = callbacks[i];\n if (cb === fn || cb.fn === fn) {\n callbacks.splice(i, 1);\n break;\n }\n }\n return this;\n };\n\n/**\n * Emit `event` with the given args.\n *\n * @param {String} event\n * @param {Mixed} ...\n * @return {Emitter}\n */\n\nEmitter.prototype.emit = function(event){\n this._callbacks = this._callbacks || {};\n var args = [].slice.call(arguments, 1)\n , callbacks = this._callbacks['$' + event];\n\n if (callbacks) {\n callbacks = callbacks.slice(0);\n for (var i = 0, len = callbacks.length; i < len; ++i) {\n callbacks[i].apply(this, args);\n }\n }\n\n return this;\n};\n\n/**\n * Return array of callbacks for `event`.\n *\n * @param {String} event\n * @return {Array}\n * @api public\n */\n\nEmitter.prototype.listeners = function(event){\n this._callbacks = this._callbacks || {};\n return this._callbacks['$' + event] || [];\n};\n\n/**\n * Check if this emitter has `event` handlers.\n *\n * @param {String} event\n * @return {Boolean}\n * @api public\n */\n\nEmitter.prototype.hasListeners = function(event){\n return !! this.listeners(event).length;\n};\n","/*! peerjs build:0.3.13, development. Copyright(c) 2013 Michelle Bu */(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require==\"function\"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error(\"Cannot find module '\"+o+\"'\");throw f.code=\"MODULE_NOT_FOUND\",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require==\"function\"&&require;for(var o=0;o util.chunkedMTU) {\n this._sendChunks(blob);\n return;\n }\n\n // DataChannel currently only supports strings.\n if (!util.supports.sctp) {\n util.blobToBinaryString(blob, function(str) {\n self._bufferedSend(str);\n });\n } else if (!util.supports.binaryBlob) {\n // We only do this if we really need to (e.g. blobs are not supported),\n // because this conversion is costly.\n util.blobToArrayBuffer(blob, function(ab) {\n self._bufferedSend(ab);\n });\n } else {\n this._bufferedSend(blob);\n }\n } else {\n this._bufferedSend(data);\n }\n }\n\n DataConnection.prototype._bufferedSend = function(msg) {\n if (this._buffering || !this._trySend(msg)) {\n this._buffer.push(msg);\n this.bufferSize = this._buffer.length;\n }\n }\n\n// Returns true if the send succeeds.\n DataConnection.prototype._trySend = function(msg) {\n try {\n this._dc.send(msg);\n } catch (e) {\n this._buffering = true;\n\n var self = this;\n setTimeout(function() {\n // Try again.\n self._buffering = false;\n self._tryBuffer();\n }, 100);\n return false;\n }\n return true;\n }\n\n// Try to send the first message in the buffer.\n DataConnection.prototype._tryBuffer = function() {\n if (this._buffer.length === 0) {\n return;\n }\n\n var msg = this._buffer[0];\n\n if (this._trySend(msg)) {\n this._buffer.shift();\n this.bufferSize = this._buffer.length;\n this._tryBuffer();\n }\n }\n\n DataConnection.prototype._sendChunks = function(blob) {\n var blobs = util.chunk(blob);\n for (var i = 0, ii = blobs.length; i < ii; i += 1) {\n var blob = blobs[i];\n this.send(blob, true);\n }\n }\n\n DataConnection.prototype.handleMessage = function(message) {\n var payload = message.payload;\n\n switch (message.type) {\n case 'ANSWER':\n this._peerBrowser = payload.browser;\n\n // Forward to negotiator\n Negotiator.handleSDP(message.type, this, payload.sdp);\n break;\n case 'CANDIDATE':\n Negotiator.handleCandidate(this, payload.candidate);\n break;\n default:\n util.warn('Unrecognized message type:', message.type, 'from peer:', this.peer);\n break;\n }\n }\n\n module.exports = DataConnection;\n\n},{\"./negotiator\":5,\"./util\":8,\"eventemitter3\":9,\"reliable\":12}],3:[function(require,module,exports){\n window.Socket = require('./socket');\n window.MediaConnection = require('./mediaconnection');\n window.DataConnection = require('./dataconnection');\n window.Peer = require('./peer');\n window.RTCPeerConnection = require('./adapter').RTCPeerConnection;\n window.RTCSessionDescription = require('./adapter').RTCSessionDescription;\n window.RTCIceCandidate = require('./adapter').RTCIceCandidate;\n window.Negotiator = require('./negotiator');\n window.util = require('./util');\n window.BinaryPack = require('js-binarypack');\n\n},{\"./adapter\":1,\"./dataconnection\":2,\"./mediaconnection\":4,\"./negotiator\":5,\"./peer\":6,\"./socket\":7,\"./util\":8,\"js-binarypack\":10}],4:[function(require,module,exports){\n var util = require('./util');\n var EventEmitter = require('eventemitter3');\n var Negotiator = require('./negotiator');\n\n /**\n * Wraps the streaming interface between two Peers.\n */\n function MediaConnection(peer, provider, options) {\n if (!(this instanceof MediaConnection)) return new MediaConnection(peer, provider, options);\n EventEmitter.call(this);\n\n this.options = util.extend({}, options);\n\n this.open = false;\n this.type = 'media';\n this.peer = peer;\n this.provider = provider;\n this.metadata = this.options.metadata;\n this.localStream = this.options._stream;\n\n this.id = this.options.connectionId || MediaConnection._idPrefix + util.randomToken();\n if (this.localStream) {\n Negotiator.startConnection(\n this,\n {_stream: this.localStream, originator: true}\n );\n }\n };\n\n util.inherits(MediaConnection, EventEmitter);\n\n MediaConnection._idPrefix = 'mc_';\n\n MediaConnection.prototype.addStream = function(remoteStream) {\n util.log('Receiving stream', remoteStream);\n\n this.remoteStream = remoteStream;\n this.emit('stream', remoteStream); // Should we call this `open`?\n\n };\n\n MediaConnection.prototype.handleMessage = function(message) {\n var payload = message.payload;\n\n switch (message.type) {\n case 'ANSWER':\n // Forward to negotiator\n Negotiator.handleSDP(message.type, this, payload.sdp);\n this.open = true;\n break;\n case 'CANDIDATE':\n Negotiator.handleCandidate(this, payload.candidate);\n break;\n default:\n util.warn('Unrecognized message type:', message.type, 'from peer:', this.peer);\n break;\n }\n }\n\n MediaConnection.prototype.answer = function(stream) {\n if (this.localStream) {\n util.warn('Local stream already exists on this MediaConnection. Are you answering a call twice?');\n return;\n }\n\n this.options._payload._stream = stream;\n\n this.localStream = stream;\n Negotiator.startConnection(\n this,\n this.options._payload\n )\n // Retrieve lost messages stored because PeerConnection not set up.\n var messages = this.provider._getMessages(this.id);\n for (var i = 0, ii = messages.length; i < ii; i += 1) {\n this.handleMessage(messages[i]);\n }\n this.open = true;\n };\n\n /**\n * Exposed functionality for users.\n */\n\n /** Allows user to close connection. */\n MediaConnection.prototype.close = function() {\n if (!this.open) {\n return;\n }\n this.open = false;\n Negotiator.cleanup(this);\n this.emit('close')\n };\n\n module.exports = MediaConnection;\n\n},{\"./negotiator\":5,\"./util\":8,\"eventemitter3\":9}],5:[function(require,module,exports){\n var util = require('./util');\n var RTCPeerConnection = require('./adapter').RTCPeerConnection;\n var RTCSessionDescription = require('./adapter').RTCSessionDescription;\n var RTCIceCandidate = require('./adapter').RTCIceCandidate;\n\n /**\n * Manages all negotiations between Peers.\n */\n var Negotiator = {\n pcs: {\n data: {},\n media: {}\n }, // type => {peerId: {pc_id: pc}}.\n //providers: {}, // provider's id => providers (there may be multiple providers/client.\n queue: [] // connections that are delayed due to a PC being in use.\n }\n\n Negotiator._idPrefix = 'pc_';\n\n /** Returns a PeerConnection object set up correctly (for data, media). */\n Negotiator.startConnection = function(connection, options) {\n var pc = Negotiator._getPeerConnection(connection, options);\n\n if (connection.type === 'media' && options._stream) {\n // Add the stream.\n pc.addStream(options._stream);\n }\n\n // Set the connection's PC.\n connection.pc = connection.peerConnection = pc;\n // What do we need to do now?\n if (options.originator) {\n if (connection.type === 'data') {\n // Create the datachannel.\n var config = {};\n // Dropping reliable:false support, since it seems to be crashing\n // Chrome.\n /*if (util.supports.sctp && !options.reliable) {\n // If we have canonical reliable support...\n config = {maxRetransmits: 0};\n }*/\n // Fallback to ensure older browsers don't crash.\n if (!util.supports.sctp) {\n config = {reliable: options.reliable};\n }\n var dc = pc.createDataChannel(connection.label, config);\n connection.initialize(dc);\n }\n\n if (!util.supports.onnegotiationneeded) {\n Negotiator._makeOffer(connection);\n }\n } else {\n Negotiator.handleSDP('OFFER', connection, options.sdp);\n }\n }\n\n Negotiator._getPeerConnection = function(connection, options) {\n if (!Negotiator.pcs[connection.type]) {\n util.error(connection.type + ' is not a valid connection type. Maybe you overrode the `type` property somewhere.');\n }\n\n if (!Negotiator.pcs[connection.type][connection.peer]) {\n Negotiator.pcs[connection.type][connection.peer] = {};\n }\n var peerConnections = Negotiator.pcs[connection.type][connection.peer];\n\n var pc;\n // Not multiplexing while FF and Chrome have not-great support for it.\n /*if (options.multiplex) {\n ids = Object.keys(peerConnections);\n for (var i = 0, ii = ids.length; i < ii; i += 1) {\n pc = peerConnections[ids[i]];\n if (pc.signalingState === 'stable') {\n break; // We can go ahead and use this PC.\n }\n }\n } else */\n if (options.pc) { // Simplest case: PC id already provided for us.\n pc = Negotiator.pcs[connection.type][connection.peer][options.pc];\n }\n\n if (!pc || pc.signalingState !== 'stable') {\n pc = Negotiator._startPeerConnection(connection);\n }\n return pc;\n }\n\n /*\n Negotiator._addProvider = function(provider) {\n if ((!provider.id && !provider.disconnected) || !provider.socket.open) {\n // Wait for provider to obtain an ID.\n provider.on('open', function(id) {\n Negotiator._addProvider(provider);\n });\n } else {\n Negotiator.providers[provider.id] = provider;\n }\n }*/\n\n\n /** Start a PC. */\n Negotiator._startPeerConnection = function(connection) {\n util.log('Creating RTCPeerConnection.');\n\n var id = Negotiator._idPrefix + util.randomToken();\n var optional = {};\n\n if (connection.type === 'data' && !util.supports.sctp) {\n optional = {optional: [{RtpDataChannels: true}]};\n } else if (connection.type === 'media') {\n // Interop req for chrome.\n optional = {optional: [{DtlsSrtpKeyAgreement: true}]};\n }\n\n var pc = new RTCPeerConnection(connection.provider.options.config, optional);\n Negotiator.pcs[connection.type][connection.peer][id] = pc;\n\n Negotiator._setupListeners(connection, pc, id);\n\n return pc;\n }\n\n /** Set up various WebRTC listeners. */\n Negotiator._setupListeners = function(connection, pc, pc_id) {\n var peerId = connection.peer;\n var connectionId = connection.id;\n var provider = connection.provider;\n\n // ICE CANDIDATES.\n util.log('Listening for ICE candidates.');\n pc.onicecandidate = function(evt) {\n if (evt.candidate) {\n util.log('Received ICE candidates for:', connection.peer);\n provider.socket.send({\n type: 'CANDIDATE',\n payload: {\n candidate: evt.candidate,\n type: connection.type,\n connectionId: connection.id\n },\n dst: peerId\n });\n }\n };\n\n pc.oniceconnectionstatechange = function() {\n switch (pc.iceConnectionState) {\n case 'disconnected':\n case 'failed':\n util.log('iceConnectionState is disconnected, closing connections to ' + peerId);\n connection.close();\n break;\n case 'completed':\n pc.onicecandidate = util.noop;\n break;\n }\n };\n\n // Fallback for older Chrome impls.\n pc.onicechange = pc.oniceconnectionstatechange;\n\n // ONNEGOTIATIONNEEDED (Chrome)\n util.log('Listening for `negotiationneeded`');\n pc.onnegotiationneeded = function() {\n util.log('`negotiationneeded` triggered');\n if (pc.signalingState == 'stable') {\n Negotiator._makeOffer(connection);\n } else {\n util.log('onnegotiationneeded triggered when not stable. Is another connection being established?');\n }\n };\n\n // DATACONNECTION.\n util.log('Listening for data channel');\n // Fired between offer and answer, so options should already be saved\n // in the options hash.\n pc.ondatachannel = function(evt) {\n util.log('Received data channel');\n var dc = evt.channel;\n var connection = provider.getConnection(peerId, connectionId);\n connection.initialize(dc);\n };\n\n // MEDIACONNECTION.\n util.log('Listening for remote stream');\n pc.onaddstream = function(evt) {\n util.log('Received remote stream');\n var stream = evt.stream;\n var connection = provider.getConnection(peerId, connectionId);\n // 10/10/2014: looks like in Chrome 38, onaddstream is triggered after\n // setting the remote description. Our connection object in these cases\n // is actually a DATA connection, so addStream fails.\n // TODO: This is hopefully just a temporary fix. We should try to\n // understand why this is happening.\n if (connection.type === 'media') {\n connection.addStream(stream);\n }\n };\n }\n\n Negotiator.cleanup = function(connection) {\n util.log('Cleaning up PeerConnection to ' + connection.peer);\n\n var pc = connection.pc;\n\n if (!!pc && (pc.readyState !== 'closed' || pc.signalingState !== 'closed')) {\n pc.close();\n connection.pc = null;\n }\n }\n\n Negotiator._makeOffer = function(connection) {\n var pc = connection.pc;\n pc.createOffer(function(offer) {\n util.log('Created offer.');\n\n if (!util.supports.sctp && connection.type === 'data' && connection.reliable) {\n offer.sdp = Reliable.higherBandwidthSDP(offer.sdp);\n }\n\n pc.setLocalDescription(offer, function() {\n util.log('Set localDescription: offer', 'for:', connection.peer);\n connection.provider.socket.send({\n type: 'OFFER',\n payload: {\n sdp: offer,\n type: connection.type,\n label: connection.label,\n connectionId: connection.id,\n reliable: connection.reliable,\n serialization: connection.serialization,\n metadata: connection.metadata,\n browser: util.browser\n },\n dst: connection.peer\n });\n }, function(err) {\n connection.provider.emitError('webrtc', err);\n util.log('Failed to setLocalDescription, ', err);\n });\n }, function(err) {\n connection.provider.emitError('webrtc', err);\n util.log('Failed to createOffer, ', err);\n }, connection.options.constraints);\n }\n\n Negotiator._makeAnswer = function(connection) {\n var pc = connection.pc;\n\n pc.createAnswer(function(answer) {\n util.log('Created answer.');\n\n if (!util.supports.sctp && connection.type === 'data' && connection.reliable) {\n answer.sdp = Reliable.higherBandwidthSDP(answer.sdp);\n }\n\n pc.setLocalDescription(answer, function() {\n util.log('Set localDescription: answer', 'for:', connection.peer);\n connection.provider.socket.send({\n type: 'ANSWER',\n payload: {\n sdp: answer,\n type: connection.type,\n connectionId: connection.id,\n browser: util.browser\n },\n dst: connection.peer\n });\n }, function(err) {\n connection.provider.emitError('webrtc', err);\n util.log('Failed to setLocalDescription, ', err);\n });\n }, function(err) {\n connection.provider.emitError('webrtc', err);\n util.log('Failed to create answer, ', err);\n });\n }\n\n /** Handle an SDP. */\n Negotiator.handleSDP = function(type, connection, sdp) {\n sdp = new RTCSessionDescription(sdp);\n var pc = connection.pc;\n\n util.log('Setting remote description', sdp);\n pc.setRemoteDescription(sdp, function() {\n util.log('Set remoteDescription:', type, 'for:', connection.peer);\n\n if (type === 'OFFER') {\n Negotiator._makeAnswer(connection);\n }\n }, function(err) {\n connection.provider.emitError('webrtc', err);\n util.log('Failed to setRemoteDescription, ', err);\n });\n }\n\n /** Handle a candidate. */\n Negotiator.handleCandidate = function(connection, ice) {\n var candidate = ice.candidate;\n var sdpMLineIndex = ice.sdpMLineIndex;\n connection.pc.addIceCandidate(new RTCIceCandidate({\n sdpMLineIndex: sdpMLineIndex,\n candidate: candidate\n }));\n util.log('Added ICE candidate for:', connection.peer);\n }\n\n module.exports = Negotiator;\n\n},{\"./adapter\":1,\"./util\":8}],6:[function(require,module,exports){\n var util = require('./util');\n var EventEmitter = require('eventemitter3');\n var Socket = require('./socket');\n var MediaConnection = require('./mediaconnection');\n var DataConnection = require('./dataconnection');\n\n /**\n * A peer who can initiate connections with other peers.\n */\n function Peer(id, options) {\n if (!(this instanceof Peer)) return new Peer(id, options);\n EventEmitter.call(this);\n\n // Deal with overloading\n if (id && id.constructor == Object) {\n options = id;\n id = undefined;\n } else if (id) {\n // Ensure id is a string\n id = id.toString();\n }\n //\n\n // Configurize options\n options = util.extend({\n debug: 0, // 1: Errors, 2: Warnings, 3: All logs\n host: util.CLOUD_HOST,\n port: util.CLOUD_PORT,\n key: 'peerjs',\n path: '/',\n token: util.randomToken(),\n config: util.defaultConfig\n }, options);\n this.options = options;\n // Detect relative URL host.\n if (options.host === '/') {\n options.host = window.location.hostname;\n }\n // Set path correctly.\n if (options.path[0] !== '/') {\n options.path = '/' + options.path;\n }\n if (options.path[options.path.length - 1] !== '/') {\n options.path += '/';\n }\n\n // Set whether we use SSL to same as current host\n if (options.secure === undefined && options.host !== util.CLOUD_HOST) {\n options.secure = util.isSecure();\n }\n // Set a custom log function if present\n if (options.logFunction) {\n util.setLogFunction(options.logFunction);\n }\n util.setLogLevel(options.debug);\n //\n\n // Sanity checks\n // Ensure WebRTC supported\n if (!util.supports.audioVideo && !util.supports.data ) {\n this._delayedAbort('browser-incompatible', 'The current browser does not support WebRTC');\n return;\n }\n // Ensure alphanumeric id\n if (!util.validateId(id)) {\n this._delayedAbort('invalid-id', 'ID \"' + id + '\" is invalid');\n return;\n }\n // Ensure valid key\n if (!util.validateKey(options.key)) {\n this._delayedAbort('invalid-key', 'API KEY \"' + options.key + '\" is invalid');\n return;\n }\n // Ensure not using unsecure cloud server on SSL page\n if (options.secure && options.host === '0.peerjs.com') {\n this._delayedAbort('ssl-unavailable',\n 'The cloud server currently does not support HTTPS. Please run your own PeerServer to use HTTPS.');\n return;\n }\n //\n\n // States.\n this.destroyed = false; // Connections have been killed\n this.disconnected = false; // Connection to PeerServer killed but P2P connections still active\n this.open = false; // Sockets and such are not yet open.\n //\n\n // References\n this.connections = {}; // DataConnections for this peer.\n this._lostMessages = {}; // src => [list of messages]\n //\n\n // Start the server connection\n this._initializeServerConnection();\n if (id) {\n this._initialize(id);\n } else {\n this._retrieveId();\n }\n //\n }\n\n util.inherits(Peer, EventEmitter);\n\n// Initialize the 'socket' (which is actually a mix of XHR streaming and\n// websockets.)\n Peer.prototype._initializeServerConnection = function() {\n var self = this;\n this.socket = new Socket(this.options.secure, this.options.host, this.options.port, this.options.path, this.options.key);\n this.socket.on('message', function(data) {\n self._handleMessage(data);\n });\n this.socket.on('error', function(error) {\n self._abort('socket-error', error);\n });\n this.socket.on('disconnected', function() {\n // If we haven't explicitly disconnected, emit error and disconnect.\n if (!self.disconnected) {\n self.emitError('network', 'Lost connection to server.');\n self.disconnect();\n }\n });\n this.socket.on('close', function() {\n // If we haven't explicitly disconnected, emit error.\n if (!self.disconnected) {\n self._abort('socket-closed', 'Underlying socket is already closed.');\n }\n });\n };\n\n /** Get a unique ID from the server via XHR. */\n Peer.prototype._retrieveId = function(cb) {\n var self = this;\n var http = new XMLHttpRequest();\n var protocol = this.options.secure ? 'https://' : 'http://';\n var url = protocol + this.options.host + ':' + this.options.port +\n this.options.path + this.options.key + '/id';\n var queryString = '?ts=' + new Date().getTime() + '' + Math.random();\n url += queryString;\n\n // If there's no ID we need to wait for one before trying to init socket.\n http.open('get', url, true);\n http.onerror = function(e) {\n util.error('Error retrieving ID', e);\n var pathError = '';\n if (self.options.path === '/' && self.options.host !== util.CLOUD_HOST) {\n pathError = ' If you passed in a `path` to your self-hosted PeerServer, ' +\n 'you\\'ll also need to pass in that same path when creating a new ' +\n 'Peer.';\n }\n self._abort('server-error', 'Could not get an ID from the server.' + pathError);\n };\n http.onreadystatechange = function() {\n if (http.readyState !== 4) {\n return;\n }\n if (http.status !== 200) {\n http.onerror();\n return;\n }\n self._initialize(http.responseText);\n };\n http.send(null);\n };\n\n /** Initialize a connection with the server. */\n Peer.prototype._initialize = function(id) {\n this.id = id;\n this.socket.start(this.id, this.options.token);\n };\n\n /** Handles messages from the server. */\n Peer.prototype._handleMessage = function(message) {\n var type = message.type;\n var payload = message.payload;\n var peer = message.src;\n var connection;\n\n switch (type) {\n case 'OPEN': // The connection to the server is open.\n this.emit('open', this.id);\n this.open = true;\n break;\n case 'ERROR': // Server error.\n this._abort('server-error', payload.msg);\n break;\n case 'ID-TAKEN': // The selected ID is taken.\n this._abort('unavailable-id', 'ID `' + this.id + '` is taken');\n break;\n case 'INVALID-KEY': // The given API key cannot be found.\n this._abort('invalid-key', 'API KEY \"' + this.options.key + '\" is invalid');\n break;\n\n //\n case 'LEAVE': // Another peer has closed its connection to this peer.\n util.log('Received leave message from', peer);\n this._cleanupPeer(peer);\n break;\n\n case 'EXPIRE': // The offer sent to a peer has expired without response.\n this.emitError('peer-unavailable', 'Could not connect to peer ' + peer);\n break;\n case 'OFFER': // we should consider switching this to CALL/CONNECT, but this is the least breaking option.\n var connectionId = payload.connectionId;\n connection = this.getConnection(peer, connectionId);\n\n if (connection) {\n util.warn('Offer received for existing Connection ID:', connectionId);\n //connection.handleMessage(message);\n } else {\n // Create a new connection.\n if (payload.type === 'media') {\n connection = new MediaConnection(peer, this, {\n connectionId: connectionId,\n _payload: payload,\n metadata: payload.metadata\n });\n this._addConnection(peer, connection);\n this.emit('call', connection);\n } else if (payload.type === 'data') {\n connection = new DataConnection(peer, this, {\n connectionId: connectionId,\n _payload: payload,\n metadata: payload.metadata,\n label: payload.label,\n serialization: payload.serialization,\n reliable: payload.reliable\n });\n this._addConnection(peer, connection);\n this.emit('connection', connection);\n } else {\n util.warn('Received malformed connection type:', payload.type);\n return;\n }\n // Find messages.\n var messages = this._getMessages(connectionId);\n for (var i = 0, ii = messages.length; i < ii; i += 1) {\n connection.handleMessage(messages[i]);\n }\n }\n break;\n default:\n if (!payload) {\n util.warn('You received a malformed message from ' + peer + ' of type ' + type);\n return;\n }\n\n var id = payload.connectionId;\n connection = this.getConnection(peer, id);\n\n if (connection && connection.pc) {\n // Pass it on.\n connection.handleMessage(message);\n } else if (id) {\n // Store for possible later use\n this._storeMessage(id, message);\n } else {\n util.warn('You received an unrecognized message:', message);\n }\n break;\n }\n };\n\n /** Stores messages without a set up connection, to be claimed later. */\n Peer.prototype._storeMessage = function(connectionId, message) {\n if (!this._lostMessages[connectionId]) {\n this._lostMessages[connectionId] = [];\n }\n this._lostMessages[connectionId].push(message);\n };\n\n /** Retrieve messages from lost message store */\n Peer.prototype._getMessages = function(connectionId) {\n var messages = this._lostMessages[connectionId];\n if (messages) {\n delete this._lostMessages[connectionId];\n return messages;\n } else {\n return [];\n }\n };\n\n /**\n * Returns a DataConnection to the specified peer. See documentation for a\n * complete list of options.\n */\n Peer.prototype.connect = function(peer, options) {\n if (this.disconnected) {\n util.warn('You cannot connect to a new Peer because you called ' +\n '.disconnect() on this Peer and ended your connection with the ' +\n 'server. You can create a new Peer to reconnect, or call reconnect ' +\n 'on this peer if you believe its ID to still be available.');\n this.emitError('disconnected', 'Cannot connect to new Peer after disconnecting from server.');\n return;\n }\n var connection = new DataConnection(peer, this, options);\n this._addConnection(peer, connection);\n return connection;\n };\n\n /**\n * Returns a MediaConnection to the specified peer. See documentation for a\n * complete list of options.\n */\n Peer.prototype.call = function(peer, stream, options) {\n if (this.disconnected) {\n util.warn('You cannot connect to a new Peer because you called ' +\n '.disconnect() on this Peer and ended your connection with the ' +\n 'server. You can create a new Peer to reconnect.');\n this.emitError('disconnected', 'Cannot connect to new Peer after disconnecting from server.');\n return;\n }\n if (!stream) {\n util.error('To call a peer, you must provide a stream from your browser\\'s `getUserMedia`.');\n return;\n }\n options = options || {};\n options._stream = stream;\n var call = new MediaConnection(peer, this, options);\n this._addConnection(peer, call);\n return call;\n };\n\n /** Add a data/media connection to this peer. */\n Peer.prototype._addConnection = function(peer, connection) {\n if (!this.connections[peer]) {\n this.connections[peer] = [];\n }\n this.connections[peer].push(connection);\n };\n\n /** Retrieve a data/media connection for this peer. */\n Peer.prototype.getConnection = function(peer, id) {\n var connections = this.connections[peer];\n if (!connections) {\n return null;\n }\n for (var i = 0, ii = connections.length; i < ii; i++) {\n if (connections[i].id === id) {\n return connections[i];\n }\n }\n return null;\n };\n\n Peer.prototype._delayedAbort = function(type, message) {\n var self = this;\n util.setZeroTimeout(function(){\n self._abort(type, message);\n });\n };\n\n /**\n * Destroys the Peer and emits an error message.\n * The Peer is not destroyed if it's in a disconnected state, in which case\n * it retains its disconnected state and its existing connections.\n */\n Peer.prototype._abort = function(type, message) {\n util.error('Aborting!');\n if (!this._lastServerId) {\n this.destroy();\n } else {\n this.disconnect();\n }\n this.emitError(type, message);\n };\n\n /** Emits a typed error message. */\n Peer.prototype.emitError = function(type, err) {\n util.error('Error:', err);\n if (typeof err === 'string') {\n err = new Error(err);\n }\n err.type = type;\n this.emit('error', err);\n };\n\n /**\n * Destroys the Peer: closes all active connections as well as the connection\n * to the server.\n * Warning: The peer can no longer create or accept connections after being\n * destroyed.\n */\n Peer.prototype.destroy = function() {\n if (!this.destroyed) {\n this._cleanup();\n this.disconnect();\n this.destroyed = true;\n }\n };\n\n\n /** Disconnects every connection on this peer. */\n Peer.prototype._cleanup = function() {\n if (this.connections) {\n var peers = Object.keys(this.connections);\n for (var i = 0, ii = peers.length; i < ii; i++) {\n this._cleanupPeer(peers[i]);\n }\n }\n this.emit('close');\n };\n\n /** Closes all connections to this peer. */\n Peer.prototype._cleanupPeer = function(peer) {\n var connections = this.connections[peer];\n for (var j = 0, jj = connections.length; j < jj; j += 1) {\n connections[j].close();\n }\n };\n\n /**\n * Disconnects the Peer's connection to the PeerServer. Does not close any\n * active connections.\n * Warning: The peer can no longer create or accept connections after being\n * disconnected. It also cannot reconnect to the server.\n */\n Peer.prototype.disconnect = function() {\n var self = this;\n util.setZeroTimeout(function(){\n if (!self.disconnected) {\n self.disconnected = true;\n self.open = false;\n if (self.socket) {\n self.socket.close();\n }\n self.emit('disconnected', self.id);\n self._lastServerId = self.id;\n self.id = null;\n }\n });\n };\n\n /** Attempts to reconnect with the same ID. */\n Peer.prototype.reconnect = function() {\n if (this.disconnected && !this.destroyed) {\n util.log('Attempting reconnection to server with ID ' + this._lastServerId);\n this.disconnected = false;\n this._initializeServerConnection();\n this._initialize(this._lastServerId);\n } else if (this.destroyed) {\n throw new Error('This peer cannot reconnect to the server. It has already been destroyed.');\n } else if (!this.disconnected && !this.open) {\n // Do nothing. We're still connecting the first time.\n util.error('In a hurry? We\\'re still trying to make the initial connection!');\n } else {\n throw new Error('Peer ' + this.id + ' cannot reconnect because it is not disconnected from the server!');\n }\n };\n\n /**\n * Get a list of available peer IDs. If you're running your own server, you'll\n * want to set allow_discovery: true in the PeerServer options. If you're using\n * the cloud server, email team@peerjs.com to get the functionality enabled for\n * your key.\n */\n Peer.prototype.listAllPeers = function(cb) {\n cb = cb || function() {};\n var self = this;\n var http = new XMLHttpRequest();\n var protocol = this.options.secure ? 'https://' : 'http://';\n var url = protocol + this.options.host + ':' + this.options.port +\n this.options.path + this.options.key + '/peers';\n var queryString = '?ts=' + new Date().getTime() + '' + Math.random();\n url += queryString;\n\n // If there's no ID we need to wait for one before trying to init socket.\n http.open('get', url, true);\n http.onerror = function(e) {\n self._abort('server-error', 'Could not get peers from the server.');\n cb([]);\n };\n http.onreadystatechange = function() {\n if (http.readyState !== 4) {\n return;\n }\n if (http.status === 401) {\n var helpfulError = '';\n if (self.options.host !== util.CLOUD_HOST) {\n helpfulError = 'It looks like you\\'re using the cloud server. You can email ' +\n 'team@peerjs.com to enable peer listing for your API key.';\n } else {\n helpfulError = 'You need to enable `allow_discovery` on your self-hosted ' +\n 'PeerServer to use this feature.';\n }\n cb([]);\n throw new Error('It doesn\\'t look like you have permission to list peers IDs. ' + helpfulError);\n } else if (http.status !== 200) {\n cb([]);\n } else {\n cb(JSON.parse(http.responseText));\n }\n };\n http.send(null);\n };\n\n module.exports = Peer;\n\n},{\"./dataconnection\":2,\"./mediaconnection\":4,\"./socket\":7,\"./util\":8,\"eventemitter3\":9}],7:[function(require,module,exports){\n var util = require('./util');\n var EventEmitter = require('eventemitter3');\n\n /**\n * An abstraction on top of WebSockets and XHR streaming to provide fastest\n * possible connection for peers.\n */\n function Socket(secure, host, port, path, key) {\n if (!(this instanceof Socket)) return new Socket(secure, host, port, path, key);\n\n EventEmitter.call(this);\n\n // Disconnected manually.\n this.disconnected = false;\n this._queue = [];\n\n var httpProtocol = secure ? 'https://' : 'http://';\n var wsProtocol = secure ? 'wss://' : 'ws://';\n this._httpUrl = httpProtocol + host + ':' + port + path + key;\n this._wsUrl = wsProtocol + host + ':' + port + path + 'peerjs?key=' + key;\n }\n\n util.inherits(Socket, EventEmitter);\n\n\n /** Check in with ID or get one from server. */\n Socket.prototype.start = function(id, token) {\n this.id = id;\n\n this._httpUrl += '/' + id + '/' + token;\n this._wsUrl += '&id=' + id + '&token=' + token;\n\n this._startXhrStream();\n this._startWebSocket();\n }\n\n\n /** Start up websocket communications. */\n Socket.prototype._startWebSocket = function(id) {\n var self = this;\n\n if (this._socket) {\n return;\n }\n\n this._socket = new WebSocket(this._wsUrl);\n\n this._socket.onmessage = function(event) {\n try {\n var data = JSON.parse(event.data);\n } catch(e) {\n util.log('Invalid server message', event.data);\n return;\n }\n self.emit('message', data);\n };\n\n this._socket.onclose = function(event) {\n util.log('Socket closed.');\n self.disconnected = true;\n self.emit('disconnected');\n };\n\n // Take care of the queue of connections if necessary and make sure Peer knows\n // socket is open.\n this._socket.onopen = function() {\n if (self._timeout) {\n clearTimeout(self._timeout);\n setTimeout(function(){\n self._http.abort();\n self._http = null;\n }, 5000);\n }\n self._sendQueuedMessages();\n util.log('Socket open');\n };\n }\n\n /** Start XHR streaming. */\n Socket.prototype._startXhrStream = function(n) {\n try {\n var self = this;\n this._http = new XMLHttpRequest();\n this._http._index = 1;\n this._http._streamIndex = n || 0;\n this._http.open('post', this._httpUrl + '/id?i=' + this._http._streamIndex, true);\n this._http.onerror = function() {\n // If we get an error, likely something went wrong.\n // Stop streaming.\n clearTimeout(self._timeout);\n self.emit('disconnected');\n }\n this._http.onreadystatechange = function() {\n if (this.readyState == 2 && this.old) {\n this.old.abort();\n delete this.old;\n } else if (this.readyState > 2 && this.status === 200 && this.responseText) {\n self._handleStream(this);\n }\n };\n this._http.send(null);\n this._setHTTPTimeout();\n } catch(e) {\n util.log('XMLHttpRequest not available; defaulting to WebSockets');\n }\n }\n\n\n /** Handles onreadystatechange response as a stream. */\n Socket.prototype._handleStream = function(http) {\n // 3 and 4 are loading/done state. All others are not relevant.\n var messages = http.responseText.split('\\n');\n\n // Check to see if anything needs to be processed on buffer.\n if (http._buffer) {\n while (http._buffer.length > 0) {\n var index = http._buffer.shift();\n var bufferedMessage = messages[index];\n try {\n bufferedMessage = JSON.parse(bufferedMessage);\n } catch(e) {\n http._buffer.shift(index);\n break;\n }\n this.emit('message', bufferedMessage);\n }\n }\n\n var message = messages[http._index];\n if (message) {\n http._index += 1;\n // Buffering--this message is incomplete and we'll get to it next time.\n // This checks if the httpResponse ended in a `\\n`, in which case the last\n // element of messages should be the empty string.\n if (http._index === messages.length) {\n if (!http._buffer) {\n http._buffer = [];\n }\n http._buffer.push(http._index - 1);\n } else {\n try {\n message = JSON.parse(message);\n } catch(e) {\n util.log('Invalid server message', message);\n return;\n }\n this.emit('message', message);\n }\n }\n }\n\n Socket.prototype._setHTTPTimeout = function() {\n var self = this;\n this._timeout = setTimeout(function() {\n var old = self._http;\n if (!self._wsOpen()) {\n self._startXhrStream(old._streamIndex + 1);\n self._http.old = old;\n } else {\n old.abort();\n }\n }, 25000);\n }\n\n /** Is the websocket currently open? */\n Socket.prototype._wsOpen = function() {\n return this._socket && this._socket.readyState == 1;\n }\n\n /** Send queued messages. */\n Socket.prototype._sendQueuedMessages = function() {\n for (var i = 0, ii = this._queue.length; i < ii; i += 1) {\n this.send(this._queue[i]);\n }\n }\n\n /** Exposed send for DC & Peer. */\n Socket.prototype.send = function(data) {\n if (this.disconnected) {\n return;\n }\n\n // If we didn't get an ID yet, we can't yet send anything so we should queue\n // up these messages.\n if (!this.id) {\n this._queue.push(data);\n return;\n }\n\n if (!data.type) {\n this.emit('error', 'Invalid message');\n return;\n }\n\n var message = JSON.stringify(data);\n if (this._wsOpen()) {\n this._socket.send(message);\n } else {\n var http = new XMLHttpRequest();\n var url = this._httpUrl + '/' + data.type.toLowerCase();\n http.open('post', url, true);\n http.setRequestHeader('Content-Type', 'application/json');\n http.send(message);\n }\n }\n\n Socket.prototype.close = function() {\n if (!this.disconnected && this._wsOpen()) {\n this._socket.close();\n this.disconnected = true;\n }\n }\n\n module.exports = Socket;\n\n},{\"./util\":8,\"eventemitter3\":9}],8:[function(require,module,exports){\n var defaultConfig = {'iceServers': [{ 'url': 'stun:stun.l.google.com:19302' }]};\n var dataCount = 1;\n\n var BinaryPack = require('js-binarypack');\n var RTCPeerConnection = require('./adapter').RTCPeerConnection;\n\n var util = {\n noop: function() {},\n\n CLOUD_HOST: '0.peerjs.com',\n CLOUD_PORT: 9000,\n\n // Browsers that need chunking:\n chunkedBrowsers: {'Chrome': 1},\n chunkedMTU: 16300, // The original 60000 bytes setting does not work when sending data from Firefox to Chrome, which is \"cut off\" after 16384 bytes and delivered individually.\n\n // Logging logic\n logLevel: 0,\n setLogLevel: function(level) {\n var debugLevel = parseInt(level, 10);\n if (!isNaN(parseInt(level, 10))) {\n util.logLevel = debugLevel;\n } else {\n // If they are using truthy/falsy values for debug\n util.logLevel = level ? 3 : 0;\n }\n util.log = util.warn = util.error = util.noop;\n if (util.logLevel > 0) {\n util.error = util._printWith('ERROR');\n }\n if (util.logLevel > 1) {\n util.warn = util._printWith('WARNING');\n }\n if (util.logLevel > 2) {\n util.log = util._print;\n }\n },\n setLogFunction: function(fn) {\n if (fn.constructor !== Function) {\n util.warn('The log function you passed in is not a function. Defaulting to regular logs.');\n } else {\n util._print = fn;\n }\n },\n\n _printWith: function(prefix) {\n return function() {\n var copy = Array.prototype.slice.call(arguments);\n copy.unshift(prefix);\n util._print.apply(util, copy);\n };\n },\n _print: function () {\n var err = false;\n var copy = Array.prototype.slice.call(arguments);\n copy.unshift('PeerJS: ');\n for (var i = 0, l = copy.length; i < l; i++){\n if (copy[i] instanceof Error) {\n copy[i] = '(' + copy[i].name + ') ' + copy[i].message;\n err = true;\n }\n }\n err ? console.error.apply(console, copy) : console.log.apply(console, copy);\n },\n //\n\n // Returns browser-agnostic default config\n defaultConfig: defaultConfig,\n //\n\n // Returns the current browser.\n browser: (function() {\n if (window.mozRTCPeerConnection) {\n return 'Firefox';\n } else if (window.webkitRTCPeerConnection) {\n return 'Chrome';\n } else if (window.RTCPeerConnection) {\n return 'Supported';\n } else {\n return 'Unsupported';\n }\n })(),\n //\n\n // Lists which features are supported\n supports: (function() {\n if (typeof RTCPeerConnection === 'undefined') {\n return {};\n }\n\n var data = true;\n var audioVideo = true;\n\n var binaryBlob = false;\n var sctp = false;\n var onnegotiationneeded = !!window.webkitRTCPeerConnection;\n\n var pc, dc;\n try {\n pc = new RTCPeerConnection(defaultConfig, {optional: [{RtpDataChannels: true}]});\n } catch (e) {\n data = false;\n audioVideo = false;\n }\n\n if (data) {\n try {\n dc = pc.createDataChannel('_PEERJSTEST');\n } catch (e) {\n data = false;\n }\n }\n\n if (data) {\n // Binary test\n try {\n dc.binaryType = 'blob';\n binaryBlob = true;\n } catch (e) {\n }\n\n // Reliable test.\n // Unfortunately Chrome is a bit unreliable about whether or not they\n // support reliable.\n var reliablePC = new RTCPeerConnection(defaultConfig, {});\n try {\n var reliableDC = reliablePC.createDataChannel('_PEERJSRELIABLETEST', {});\n sctp = reliableDC.reliable;\n } catch (e) {\n }\n reliablePC.close();\n }\n\n // FIXME: not really the best check...\n if (audioVideo) {\n audioVideo = !!pc.addStream;\n }\n\n // FIXME: this is not great because in theory it doesn't work for\n // av-only browsers (?).\n if (!onnegotiationneeded && data) {\n // sync default check.\n var negotiationPC = new RTCPeerConnection(defaultConfig, {optional: [{RtpDataChannels: true}]});\n negotiationPC.onnegotiationneeded = function() {\n onnegotiationneeded = true;\n // async check.\n if (util && util.supports) {\n util.supports.onnegotiationneeded = true;\n }\n };\n negotiationPC.createDataChannel('_PEERJSNEGOTIATIONTEST');\n\n setTimeout(function() {\n negotiationPC.close();\n }, 1000);\n }\n\n if (pc) {\n pc.close();\n }\n\n return {\n audioVideo: audioVideo,\n data: data,\n binaryBlob: binaryBlob,\n binary: sctp, // deprecated; sctp implies binary support.\n reliable: sctp, // deprecated; sctp implies reliable data.\n sctp: sctp,\n onnegotiationneeded: onnegotiationneeded\n };\n }()),\n //\n\n // Ensure alphanumeric ids\n validateId: function(id) {\n // Allow empty ids\n return !id || /^[A-Za-z0-9_-]+(?:[ _-][A-Za-z0-9]+)*$/.exec(id);\n },\n\n validateKey: function(key) {\n // Allow empty keys\n return !key || /^[A-Za-z0-9_-]+(?:[ _-][A-Za-z0-9]+)*$/.exec(key);\n },\n\n\n debug: false,\n\n inherits: function(ctor, superCtor) {\n ctor.super_ = superCtor;\n ctor.prototype = Object.create(superCtor.prototype, {\n constructor: {\n value: ctor,\n enumerable: false,\n writable: true,\n configurable: true\n }\n });\n },\n extend: function(dest, source) {\n for(var key in source) {\n if(source.hasOwnProperty(key)) {\n dest[key] = source[key];\n }\n }\n return dest;\n },\n pack: BinaryPack.pack,\n unpack: BinaryPack.unpack,\n\n log: function () {\n if (util.debug) {\n var err = false;\n var copy = Array.prototype.slice.call(arguments);\n copy.unshift('PeerJS: ');\n for (var i = 0, l = copy.length; i < l; i++){\n if (copy[i] instanceof Error) {\n copy[i] = '(' + copy[i].name + ') ' + copy[i].message;\n err = true;\n }\n }\n err ? console.error.apply(console, copy) : console.log.apply(console, copy);\n }\n },\n\n setZeroTimeout: (function(global) {\n var timeouts = [];\n var messageName = 'zero-timeout-message';\n\n // Like setTimeout, but only takes a function argument.\t There's\n // no time argument (always zero) and no arguments (you have to\n // use a closure).\n function setZeroTimeoutPostMessage(fn) {\n timeouts.push(fn);\n global.postMessage(messageName, '*');\n }\n\n function handleMessage(event) {\n if (event.source == global && event.data == messageName) {\n if (event.stopPropagation) {\n event.stopPropagation();\n }\n if (timeouts.length) {\n timeouts.shift()();\n }\n }\n }\n if (global.addEventListener) {\n global.addEventListener('message', handleMessage, true);\n } else if (global.attachEvent) {\n global.attachEvent('onmessage', handleMessage);\n }\n return setZeroTimeoutPostMessage;\n }(window)),\n\n // Binary stuff\n\n // chunks a blob.\n chunk: function(bl) {\n var chunks = [];\n var size = bl.size;\n var start = index = 0;\n var total = Math.ceil(size / util.chunkedMTU);\n while (start < size) {\n var end = Math.min(size, start + util.chunkedMTU);\n var b = bl.slice(start, end);\n\n var chunk = {\n __peerData: dataCount,\n n: index,\n data: b,\n total: total\n };\n\n chunks.push(chunk);\n\n start = end;\n index += 1;\n }\n dataCount += 1;\n return chunks;\n },\n\n blobToArrayBuffer: function(blob, cb){\n var fr = new FileReader();\n fr.onload = function(evt) {\n cb(evt.target.result);\n };\n fr.readAsArrayBuffer(blob);\n },\n blobToBinaryString: function(blob, cb){\n var fr = new FileReader();\n fr.onload = function(evt) {\n cb(evt.target.result);\n };\n fr.readAsBinaryString(blob);\n },\n binaryStringToArrayBuffer: function(binary) {\n var byteArray = new Uint8Array(binary.length);\n for (var i = 0; i < binary.length; i++) {\n byteArray[i] = binary.charCodeAt(i) & 0xff;\n }\n return byteArray.buffer;\n },\n randomToken: function () {\n return Math.random().toString(36).substr(2);\n },\n //\n\n isSecure: function() {\n return location.protocol === 'https:';\n }\n };\n\n module.exports = util;\n\n},{\"./adapter\":1,\"js-binarypack\":10}],9:[function(require,module,exports){\n 'use strict';\n\n /**\n * Representation of a single EventEmitter function.\n *\n * @param {Function} fn Event handler to be called.\n * @param {Mixed} context Context for function execution.\n * @param {Boolean} once Only emit once\n * @api private\n */\n function EE(fn, context, once) {\n this.fn = fn;\n this.context = context;\n this.once = once || false;\n }\n\n /**\n * Minimal EventEmitter interface that is molded against the Node.js\n * EventEmitter interface.\n *\n * @constructor\n * @api public\n */\n function EventEmitter() { /* Nothing to set */ }\n\n /**\n * Holds the assigned EventEmitters by name.\n *\n * @type {Object}\n * @private\n */\n EventEmitter.prototype._events = undefined;\n\n /**\n * Return a list of assigned event listeners.\n *\n * @param {String} event The events that should be listed.\n * @returns {Array}\n * @api public\n */\n EventEmitter.prototype.listeners = function listeners(event) {\n if (!this._events || !this._events[event]) return [];\n\n for (var i = 0, l = this._events[event].length, ee = []; i < l; i++) {\n ee.push(this._events[event][i].fn);\n }\n\n return ee;\n };\n\n /**\n * Emit an event to all registered event listeners.\n *\n * @param {String} event The name of the event.\n * @returns {Boolean} Indication if we've emitted an event.\n * @api public\n */\n EventEmitter.prototype.emit = function emit(event, a1, a2, a3, a4, a5) {\n if (!this._events || !this._events[event]) return false;\n\n var listeners = this._events[event]\n , length = listeners.length\n , len = arguments.length\n , ee = listeners[0]\n , args\n , i, j;\n\n if (1 === length) {\n if (ee.once) this.removeListener(event, ee.fn, true);\n\n switch (len) {\n case 1: return ee.fn.call(ee.context), true;\n case 2: return ee.fn.call(ee.context, a1), true;\n case 3: return ee.fn.call(ee.context, a1, a2), true;\n case 4: return ee.fn.call(ee.context, a1, a2, a3), true;\n case 5: return ee.fn.call(ee.context, a1, a2, a3, a4), true;\n case 6: return ee.fn.call(ee.context, a1, a2, a3, a4, a5), true;\n }\n\n for (i = 1, args = new Array(len -1); i < len; i++) {\n args[i - 1] = arguments[i];\n }\n\n ee.fn.apply(ee.context, args);\n } else {\n for (i = 0; i < length; i++) {\n if (listeners[i].once) this.removeListener(event, listeners[i].fn, true);\n\n switch (len) {\n case 1: listeners[i].fn.call(listeners[i].context); break;\n case 2: listeners[i].fn.call(listeners[i].context, a1); break;\n case 3: listeners[i].fn.call(listeners[i].context, a1, a2); break;\n default:\n if (!args) for (j = 1, args = new Array(len -1); j < len; j++) {\n args[j - 1] = arguments[j];\n }\n\n listeners[i].fn.apply(listeners[i].context, args);\n }\n }\n }\n\n return true;\n };\n\n /**\n * Register a new EventListener for the given event.\n *\n * @param {String} event Name of the event.\n * @param {Functon} fn Callback function.\n * @param {Mixed} context The context of the function.\n * @api public\n */\n EventEmitter.prototype.on = function on(event, fn, context) {\n if (!this._events) this._events = {};\n if (!this._events[event]) this._events[event] = [];\n this._events[event].push(new EE( fn, context || this ));\n\n return this;\n };\n\n /**\n * Add an EventListener that's only called once.\n *\n * @param {String} event Name of the event.\n * @param {Function} fn Callback function.\n * @param {Mixed} context The context of the function.\n * @api public\n */\n EventEmitter.prototype.once = function once(event, fn, context) {\n if (!this._events) this._events = {};\n if (!this._events[event]) this._events[event] = [];\n this._events[event].push(new EE(fn, context || this, true ));\n\n return this;\n };\n\n /**\n * Remove event listeners.\n *\n * @param {String} event The event we want to remove.\n * @param {Function} fn The listener that we need to find.\n * @param {Boolean} once Only remove once listeners.\n * @api public\n */\n EventEmitter.prototype.removeListener = function removeListener(event, fn, once) {\n if (!this._events || !this._events[event]) return this;\n\n var listeners = this._events[event]\n , events = [];\n\n if (fn) for (var i = 0, length = listeners.length; i < length; i++) {\n if (listeners[i].fn !== fn && listeners[i].once !== once) {\n events.push(listeners[i]);\n }\n }\n\n //\n // Reset the array, or remove it completely if we have no more listeners.\n //\n if (events.length) this._events[event] = events;\n else this._events[event] = null;\n\n return this;\n };\n\n /**\n * Remove all listeners or only the listeners for the specified event.\n *\n * @param {String} event The event want to remove all listeners for.\n * @api public\n */\n EventEmitter.prototype.removeAllListeners = function removeAllListeners(event) {\n if (!this._events) return this;\n\n if (event) this._events[event] = null;\n else this._events = {};\n\n return this;\n };\n\n//\n// Alias methods names because people roll like that.\n//\n EventEmitter.prototype.off = EventEmitter.prototype.removeListener;\n EventEmitter.prototype.addListener = EventEmitter.prototype.on;\n\n//\n// This function doesn't apply anymore.\n//\n EventEmitter.prototype.setMaxListeners = function setMaxListeners() {\n return this;\n };\n\n//\n// Expose the module.\n//\n EventEmitter.EventEmitter = EventEmitter;\n EventEmitter.EventEmitter2 = EventEmitter;\n EventEmitter.EventEmitter3 = EventEmitter;\n\n if ('object' === typeof module && module.exports) {\n module.exports = EventEmitter;\n }\n\n},{}],10:[function(require,module,exports){\n var BufferBuilder = require('./bufferbuilder').BufferBuilder;\n var binaryFeatures = require('./bufferbuilder').binaryFeatures;\n\n var BinaryPack = {\n unpack: function(data){\n var unpacker = new Unpacker(data);\n return unpacker.unpack();\n },\n pack: function(data){\n var packer = new Packer();\n packer.pack(data);\n var buffer = packer.getBuffer();\n return buffer;\n }\n };\n\n module.exports = BinaryPack;\n\n function Unpacker (data){\n // Data is ArrayBuffer\n this.index = 0;\n this.dataBuffer = data;\n this.dataView = new Uint8Array(this.dataBuffer);\n this.length = this.dataBuffer.byteLength;\n }\n\n Unpacker.prototype.unpack = function(){\n var type = this.unpack_uint8();\n if (type < 0x80){\n var positive_fixnum = type;\n return positive_fixnum;\n } else if ((type ^ 0xe0) < 0x20){\n var negative_fixnum = (type ^ 0xe0) - 0x20;\n return negative_fixnum;\n }\n var size;\n if ((size = type ^ 0xa0) <= 0x0f){\n return this.unpack_raw(size);\n } else if ((size = type ^ 0xb0) <= 0x0f){\n return this.unpack_string(size);\n } else if ((size = type ^ 0x90) <= 0x0f){\n return this.unpack_array(size);\n } else if ((size = type ^ 0x80) <= 0x0f){\n return this.unpack_map(size);\n }\n switch(type){\n case 0xc0:\n return null;\n case 0xc1:\n return undefined;\n case 0xc2:\n return false;\n case 0xc3:\n return true;\n case 0xca:\n return this.unpack_float();\n case 0xcb:\n return this.unpack_double();\n case 0xcc:\n return this.unpack_uint8();\n case 0xcd:\n return this.unpack_uint16();\n case 0xce:\n return this.unpack_uint32();\n case 0xcf:\n return this.unpack_uint64();\n case 0xd0:\n return this.unpack_int8();\n case 0xd1:\n return this.unpack_int16();\n case 0xd2:\n return this.unpack_int32();\n case 0xd3:\n return this.unpack_int64();\n case 0xd4:\n return undefined;\n case 0xd5:\n return undefined;\n case 0xd6:\n return undefined;\n case 0xd7:\n return undefined;\n case 0xd8:\n size = this.unpack_uint16();\n return this.unpack_string(size);\n case 0xd9:\n size = this.unpack_uint32();\n return this.unpack_string(size);\n case 0xda:\n size = this.unpack_uint16();\n return this.unpack_raw(size);\n case 0xdb:\n size = this.unpack_uint32();\n return this.unpack_raw(size);\n case 0xdc:\n size = this.unpack_uint16();\n return this.unpack_array(size);\n case 0xdd:\n size = this.unpack_uint32();\n return this.unpack_array(size);\n case 0xde:\n size = this.unpack_uint16();\n return this.unpack_map(size);\n case 0xdf:\n size = this.unpack_uint32();\n return this.unpack_map(size);\n }\n }\n\n Unpacker.prototype.unpack_uint8 = function(){\n var byte = this.dataView[this.index] & 0xff;\n this.index++;\n return byte;\n };\n\n Unpacker.prototype.unpack_uint16 = function(){\n var bytes = this.read(2);\n var uint16 =\n ((bytes[0] & 0xff) * 256) + (bytes[1] & 0xff);\n this.index += 2;\n return uint16;\n }\n\n Unpacker.prototype.unpack_uint32 = function(){\n var bytes = this.read(4);\n var uint32 =\n ((bytes[0] * 256 +\n bytes[1]) * 256 +\n bytes[2]) * 256 +\n bytes[3];\n this.index += 4;\n return uint32;\n }\n\n Unpacker.prototype.unpack_uint64 = function(){\n var bytes = this.read(8);\n var uint64 =\n ((((((bytes[0] * 256 +\n bytes[1]) * 256 +\n bytes[2]) * 256 +\n bytes[3]) * 256 +\n bytes[4]) * 256 +\n bytes[5]) * 256 +\n bytes[6]) * 256 +\n bytes[7];\n this.index += 8;\n return uint64;\n }\n\n\n Unpacker.prototype.unpack_int8 = function(){\n var uint8 = this.unpack_uint8();\n return (uint8 < 0x80 ) ? uint8 : uint8 - (1 << 8);\n };\n\n Unpacker.prototype.unpack_int16 = function(){\n var uint16 = this.unpack_uint16();\n return (uint16 < 0x8000 ) ? uint16 : uint16 - (1 << 16);\n }\n\n Unpacker.prototype.unpack_int32 = function(){\n var uint32 = this.unpack_uint32();\n return (uint32 < Math.pow(2, 31) ) ? uint32 :\n uint32 - Math.pow(2, 32);\n }\n\n Unpacker.prototype.unpack_int64 = function(){\n var uint64 = this.unpack_uint64();\n return (uint64 < Math.pow(2, 63) ) ? uint64 :\n uint64 - Math.pow(2, 64);\n }\n\n Unpacker.prototype.unpack_raw = function(size){\n if ( this.length < this.index + size){\n throw new Error('BinaryPackFailure: index is out of range'\n + ' ' + this.index + ' ' + size + ' ' + this.length);\n }\n var buf = this.dataBuffer.slice(this.index, this.index + size);\n this.index += size;\n\n //buf = util.bufferToString(buf);\n\n return buf;\n }\n\n Unpacker.prototype.unpack_string = function(size){\n var bytes = this.read(size);\n var i = 0, str = '', c, code;\n while(i < size){\n c = bytes[i];\n if ( c < 128){\n str += String.fromCharCode(c);\n i++;\n } else if ((c ^ 0xc0) < 32){\n code = ((c ^ 0xc0) << 6) | (bytes[i+1] & 63);\n str += String.fromCharCode(code);\n i += 2;\n } else {\n code = ((c & 15) << 12) | ((bytes[i+1] & 63) << 6) |\n (bytes[i+2] & 63);\n str += String.fromCharCode(code);\n i += 3;\n }\n }\n this.index += size;\n return str;\n }\n\n Unpacker.prototype.unpack_array = function(size){\n var objects = new Array(size);\n for(var i = 0; i < size ; i++){\n objects[i] = this.unpack();\n }\n return objects;\n }\n\n Unpacker.prototype.unpack_map = function(size){\n var map = {};\n for(var i = 0; i < size ; i++){\n var key = this.unpack();\n var value = this.unpack();\n map[key] = value;\n }\n return map;\n }\n\n Unpacker.prototype.unpack_float = function(){\n var uint32 = this.unpack_uint32();\n var sign = uint32 >> 31;\n var exp = ((uint32 >> 23) & 0xff) - 127;\n var fraction = ( uint32 & 0x7fffff ) | 0x800000;\n return (sign == 0 ? 1 : -1) *\n fraction * Math.pow(2, exp - 23);\n }\n\n Unpacker.prototype.unpack_double = function(){\n var h32 = this.unpack_uint32();\n var l32 = this.unpack_uint32();\n var sign = h32 >> 31;\n var exp = ((h32 >> 20) & 0x7ff) - 1023;\n var hfrac = ( h32 & 0xfffff ) | 0x100000;\n var frac = hfrac * Math.pow(2, exp - 20) +\n l32 * Math.pow(2, exp - 52);\n return (sign == 0 ? 1 : -1) * frac;\n }\n\n Unpacker.prototype.read = function(length){\n var j = this.index;\n if (j + length <= this.length) {\n return this.dataView.subarray(j, j + length);\n } else {\n throw new Error('BinaryPackFailure: read index out of range');\n }\n }\n\n function Packer(){\n this.bufferBuilder = new BufferBuilder();\n }\n\n Packer.prototype.getBuffer = function(){\n return this.bufferBuilder.getBuffer();\n }\n\n Packer.prototype.pack = function(value){\n var type = typeof(value);\n if (type == 'string'){\n this.pack_string(value);\n } else if (type == 'number'){\n if (Math.floor(value) === value){\n this.pack_integer(value);\n } else{\n this.pack_double(value);\n }\n } else if (type == 'boolean'){\n if (value === true){\n this.bufferBuilder.append(0xc3);\n } else if (value === false){\n this.bufferBuilder.append(0xc2);\n }\n } else if (type == 'undefined'){\n this.bufferBuilder.append(0xc0);\n } else if (type == 'object'){\n if (value === null){\n this.bufferBuilder.append(0xc0);\n } else {\n var constructor = value.constructor;\n if (constructor == Array){\n this.pack_array(value);\n } else if (constructor == Blob || constructor == File) {\n this.pack_bin(value);\n } else if (constructor == ArrayBuffer) {\n if(binaryFeatures.useArrayBufferView) {\n this.pack_bin(new Uint8Array(value));\n } else {\n this.pack_bin(value);\n }\n } else if ('BYTES_PER_ELEMENT' in value){\n if(binaryFeatures.useArrayBufferView) {\n this.pack_bin(new Uint8Array(value.buffer));\n } else {\n this.pack_bin(value.buffer);\n }\n } else if (constructor == Object){\n this.pack_object(value);\n } else if (constructor == Date){\n this.pack_string(value.toString());\n } else if (typeof value.toBinaryPack == 'function'){\n this.bufferBuilder.append(value.toBinaryPack());\n } else {\n throw new Error('Type \"' + constructor.toString() + '\" not yet supported');\n }\n }\n } else {\n throw new Error('Type \"' + type + '\" not yet supported');\n }\n this.bufferBuilder.flush();\n }\n\n\n Packer.prototype.pack_bin = function(blob){\n var length = blob.length || blob.byteLength || blob.size;\n if (length <= 0x0f){\n this.pack_uint8(0xa0 + length);\n } else if (length <= 0xffff){\n this.bufferBuilder.append(0xda) ;\n this.pack_uint16(length);\n } else if (length <= 0xffffffff){\n this.bufferBuilder.append(0xdb);\n this.pack_uint32(length);\n } else{\n throw new Error('Invalid length');\n }\n this.bufferBuilder.append(blob);\n }\n\n Packer.prototype.pack_string = function(str){\n var length = utf8Length(str);\n\n if (length <= 0x0f){\n this.pack_uint8(0xb0 + length);\n } else if (length <= 0xffff){\n this.bufferBuilder.append(0xd8) ;\n this.pack_uint16(length);\n } else if (length <= 0xffffffff){\n this.bufferBuilder.append(0xd9);\n this.pack_uint32(length);\n } else{\n throw new Error('Invalid length');\n }\n this.bufferBuilder.append(str);\n }\n\n Packer.prototype.pack_array = function(ary){\n var length = ary.length;\n if (length <= 0x0f){\n this.pack_uint8(0x90 + length);\n } else if (length <= 0xffff){\n this.bufferBuilder.append(0xdc)\n this.pack_uint16(length);\n } else if (length <= 0xffffffff){\n this.bufferBuilder.append(0xdd);\n this.pack_uint32(length);\n } else{\n throw new Error('Invalid length');\n }\n for(var i = 0; i < length ; i++){\n this.pack(ary[i]);\n }\n }\n\n Packer.prototype.pack_integer = function(num){\n if ( -0x20 <= num && num <= 0x7f){\n this.bufferBuilder.append(num & 0xff);\n } else if (0x00 <= num && num <= 0xff){\n this.bufferBuilder.append(0xcc);\n this.pack_uint8(num);\n } else if (-0x80 <= num && num <= 0x7f){\n this.bufferBuilder.append(0xd0);\n this.pack_int8(num);\n } else if ( 0x0000 <= num && num <= 0xffff){\n this.bufferBuilder.append(0xcd);\n this.pack_uint16(num);\n } else if (-0x8000 <= num && num <= 0x7fff){\n this.bufferBuilder.append(0xd1);\n this.pack_int16(num);\n } else if ( 0x00000000 <= num && num <= 0xffffffff){\n this.bufferBuilder.append(0xce);\n this.pack_uint32(num);\n } else if (-0x80000000 <= num && num <= 0x7fffffff){\n this.bufferBuilder.append(0xd2);\n this.pack_int32(num);\n } else if (-0x8000000000000000 <= num && num <= 0x7FFFFFFFFFFFFFFF){\n this.bufferBuilder.append(0xd3);\n this.pack_int64(num);\n } else if (0x0000000000000000 <= num && num <= 0xFFFFFFFFFFFFFFFF){\n this.bufferBuilder.append(0xcf);\n this.pack_uint64(num);\n } else{\n throw new Error('Invalid integer');\n }\n }\n\n Packer.prototype.pack_double = function(num){\n var sign = 0;\n if (num < 0){\n sign = 1;\n num = -num;\n }\n var exp = Math.floor(Math.log(num) / Math.LN2);\n var frac0 = num / Math.pow(2, exp) - 1;\n var frac1 = Math.floor(frac0 * Math.pow(2, 52));\n var b32 = Math.pow(2, 32);\n var h32 = (sign << 31) | ((exp+1023) << 20) |\n (frac1 / b32) & 0x0fffff;\n var l32 = frac1 % b32;\n this.bufferBuilder.append(0xcb);\n this.pack_int32(h32);\n this.pack_int32(l32);\n }\n\n Packer.prototype.pack_object = function(obj){\n var keys = Object.keys(obj);\n var length = keys.length;\n if (length <= 0x0f){\n this.pack_uint8(0x80 + length);\n } else if (length <= 0xffff){\n this.bufferBuilder.append(0xde);\n this.pack_uint16(length);\n } else if (length <= 0xffffffff){\n this.bufferBuilder.append(0xdf);\n this.pack_uint32(length);\n } else{\n throw new Error('Invalid length');\n }\n for(var prop in obj){\n if (obj.hasOwnProperty(prop)){\n this.pack(prop);\n this.pack(obj[prop]);\n }\n }\n }\n\n Packer.prototype.pack_uint8 = function(num){\n this.bufferBuilder.append(num);\n }\n\n Packer.prototype.pack_uint16 = function(num){\n this.bufferBuilder.append(num >> 8);\n this.bufferBuilder.append(num & 0xff);\n }\n\n Packer.prototype.pack_uint32 = function(num){\n var n = num & 0xffffffff;\n this.bufferBuilder.append((n & 0xff000000) >>> 24);\n this.bufferBuilder.append((n & 0x00ff0000) >>> 16);\n this.bufferBuilder.append((n & 0x0000ff00) >>> 8);\n this.bufferBuilder.append((n & 0x000000ff));\n }\n\n Packer.prototype.pack_uint64 = function(num){\n var high = num / Math.pow(2, 32);\n var low = num % Math.pow(2, 32);\n this.bufferBuilder.append((high & 0xff000000) >>> 24);\n this.bufferBuilder.append((high & 0x00ff0000) >>> 16);\n this.bufferBuilder.append((high & 0x0000ff00) >>> 8);\n this.bufferBuilder.append((high & 0x000000ff));\n this.bufferBuilder.append((low & 0xff000000) >>> 24);\n this.bufferBuilder.append((low & 0x00ff0000) >>> 16);\n this.bufferBuilder.append((low & 0x0000ff00) >>> 8);\n this.bufferBuilder.append((low & 0x000000ff));\n }\n\n Packer.prototype.pack_int8 = function(num){\n this.bufferBuilder.append(num & 0xff);\n }\n\n Packer.prototype.pack_int16 = function(num){\n this.bufferBuilder.append((num & 0xff00) >> 8);\n this.bufferBuilder.append(num & 0xff);\n }\n\n Packer.prototype.pack_int32 = function(num){\n this.bufferBuilder.append((num >>> 24) & 0xff);\n this.bufferBuilder.append((num & 0x00ff0000) >>> 16);\n this.bufferBuilder.append((num & 0x0000ff00) >>> 8);\n this.bufferBuilder.append((num & 0x000000ff));\n }\n\n Packer.prototype.pack_int64 = function(num){\n var high = Math.floor(num / Math.pow(2, 32));\n var low = num % Math.pow(2, 32);\n this.bufferBuilder.append((high & 0xff000000) >>> 24);\n this.bufferBuilder.append((high & 0x00ff0000) >>> 16);\n this.bufferBuilder.append((high & 0x0000ff00) >>> 8);\n this.bufferBuilder.append((high & 0x000000ff));\n this.bufferBuilder.append((low & 0xff000000) >>> 24);\n this.bufferBuilder.append((low & 0x00ff0000) >>> 16);\n this.bufferBuilder.append((low & 0x0000ff00) >>> 8);\n this.bufferBuilder.append((low & 0x000000ff));\n }\n\n function _utf8Replace(m){\n var code = m.charCodeAt(0);\n\n if(code <= 0x7ff) return '00';\n if(code <= 0xffff) return '000';\n if(code <= 0x1fffff) return '0000';\n if(code <= 0x3ffffff) return '00000';\n return '000000';\n }\n\n function utf8Length(str){\n if (str.length > 600) {\n // Blob method faster for large strings\n return (new Blob([str])).size;\n } else {\n return str.replace(/[^\\u0000-\\u007F]/g, _utf8Replace).length;\n }\n }\n\n},{\"./bufferbuilder\":11}],11:[function(require,module,exports){\n var binaryFeatures = {};\n binaryFeatures.useBlobBuilder = (function(){\n try {\n new Blob([]);\n return false;\n } catch (e) {\n return true;\n }\n })();\n\n binaryFeatures.useArrayBufferView = !binaryFeatures.useBlobBuilder && (function(){\n try {\n return (new Blob([new Uint8Array([])])).size === 0;\n } catch (e) {\n return true;\n }\n })();\n\n module.exports.binaryFeatures = binaryFeatures;\n var BlobBuilder = module.exports.BlobBuilder;\n if (typeof window != 'undefined') {\n BlobBuilder = module.exports.BlobBuilder = window.WebKitBlobBuilder ||\n window.MozBlobBuilder || window.MSBlobBuilder || window.BlobBuilder;\n }\n\n function BufferBuilder(){\n this._pieces = [];\n this._parts = [];\n }\n\n BufferBuilder.prototype.append = function(data) {\n if(typeof data === 'number') {\n this._pieces.push(data);\n } else {\n this.flush();\n this._parts.push(data);\n }\n };\n\n BufferBuilder.prototype.flush = function() {\n if (this._pieces.length > 0) {\n var buf = new Uint8Array(this._pieces);\n if(!binaryFeatures.useArrayBufferView) {\n buf = buf.buffer;\n }\n this._parts.push(buf);\n this._pieces = [];\n }\n };\n\n BufferBuilder.prototype.getBuffer = function() {\n this.flush();\n if(binaryFeatures.useBlobBuilder) {\n var builder = new BlobBuilder();\n for(var i = 0, ii = this._parts.length; i < ii; i++) {\n builder.append(this._parts[i]);\n }\n return builder.getBlob();\n } else {\n return new Blob(this._parts);\n }\n };\n\n module.exports.BufferBuilder = BufferBuilder;\n\n},{}],12:[function(require,module,exports){\n var util = require('./util');\n\n /**\n * Reliable transfer for Chrome Canary DataChannel impl.\n * Author: @michellebu\n */\n function Reliable(dc, debug) {\n if (!(this instanceof Reliable)) return new Reliable(dc);\n this._dc = dc;\n\n util.debug = debug;\n\n // Messages sent/received so far.\n // id: { ack: n, chunks: [...] }\n this._outgoing = {};\n // id: { ack: ['ack', id, n], chunks: [...] }\n this._incoming = {};\n this._received = {};\n\n // Window size.\n this._window = 1000;\n // MTU.\n this._mtu = 500;\n // Interval for setInterval. In ms.\n this._interval = 0;\n\n // Messages sent.\n this._count = 0;\n\n // Outgoing message queue.\n this._queue = [];\n\n this._setupDC();\n };\n\n// Send a message reliably.\n Reliable.prototype.send = function(msg) {\n // Determine if chunking is necessary.\n var bl = util.pack(msg);\n if (bl.size < this._mtu) {\n this._handleSend(['no', bl]);\n return;\n }\n\n this._outgoing[this._count] = {\n ack: 0,\n chunks: this._chunk(bl)\n };\n\n if (util.debug) {\n this._outgoing[this._count].timer = new Date();\n }\n\n // Send prelim window.\n this._sendWindowedChunks(this._count);\n this._count += 1;\n };\n\n// Set up interval for processing queue.\n Reliable.prototype._setupInterval = function() {\n // TODO: fail gracefully.\n\n var self = this;\n this._timeout = setInterval(function() {\n // FIXME: String stuff makes things terribly async.\n var msg = self._queue.shift();\n if (msg._multiple) {\n for (var i = 0, ii = msg.length; i < ii; i += 1) {\n self._intervalSend(msg[i]);\n }\n } else {\n self._intervalSend(msg);\n }\n }, this._interval);\n };\n\n Reliable.prototype._intervalSend = function(msg) {\n var self = this;\n msg = util.pack(msg);\n util.blobToBinaryString(msg, function(str) {\n self._dc.send(str);\n });\n if (self._queue.length === 0) {\n clearTimeout(self._timeout);\n self._timeout = null;\n //self._processAcks();\n }\n };\n\n// Go through ACKs to send missing pieces.\n Reliable.prototype._processAcks = function() {\n for (var id in this._outgoing) {\n if (this._outgoing.hasOwnProperty(id)) {\n this._sendWindowedChunks(id);\n }\n }\n };\n\n// Handle sending a message.\n// FIXME: Don't wait for interval time for all messages...\n Reliable.prototype._handleSend = function(msg) {\n var push = true;\n for (var i = 0, ii = this._queue.length; i < ii; i += 1) {\n var item = this._queue[i];\n if (item === msg) {\n push = false;\n } else if (item._multiple && item.indexOf(msg) !== -1) {\n push = false;\n }\n }\n if (push) {\n this._queue.push(msg);\n if (!this._timeout) {\n this._setupInterval();\n }\n }\n };\n\n// Set up DataChannel handlers.\n Reliable.prototype._setupDC = function() {\n // Handle various message types.\n var self = this;\n this._dc.onmessage = function(e) {\n var msg = e.data;\n var datatype = msg.constructor;\n // FIXME: msg is String until binary is supported.\n // Once that happens, this will have to be smarter.\n if (datatype === String) {\n var ab = util.binaryStringToArrayBuffer(msg);\n msg = util.unpack(ab);\n self._handleMessage(msg);\n }\n };\n };\n\n// Handles an incoming message.\n Reliable.prototype._handleMessage = function(msg) {\n var id = msg[1];\n var idata = this._incoming[id];\n var odata = this._outgoing[id];\n var data;\n switch (msg[0]) {\n // No chunking was done.\n case 'no':\n var message = id;\n if (!!message) {\n this.onmessage(util.unpack(message));\n }\n break;\n // Reached the end of the message.\n case 'end':\n data = idata;\n\n // In case end comes first.\n this._received[id] = msg[2];\n\n if (!data) {\n break;\n }\n\n this._ack(id);\n break;\n case 'ack':\n data = odata;\n if (!!data) {\n var ack = msg[2];\n // Take the larger ACK, for out of order messages.\n data.ack = Math.max(ack, data.ack);\n\n // Clean up when all chunks are ACKed.\n if (data.ack >= data.chunks.length) {\n util.log('Time: ', new Date() - data.timer);\n delete this._outgoing[id];\n } else {\n this._processAcks();\n }\n }\n // If !data, just ignore.\n break;\n // Received a chunk of data.\n case 'chunk':\n // Create a new entry if none exists.\n data = idata;\n if (!data) {\n var end = this._received[id];\n if (end === true) {\n break;\n }\n data = {\n ack: ['ack', id, 0],\n chunks: []\n };\n this._incoming[id] = data;\n }\n\n var n = msg[2];\n var chunk = msg[3];\n data.chunks[n] = new Uint8Array(chunk);\n\n // If we get the chunk we're looking for, ACK for next missing.\n // Otherwise, ACK the same N again.\n if (n === data.ack[2]) {\n this._calculateNextAck(id);\n }\n this._ack(id);\n break;\n default:\n // Shouldn't happen, but would make sense for message to just go\n // through as is.\n this._handleSend(msg);\n break;\n }\n };\n\n// Chunks BL into smaller messages.\n Reliable.prototype._chunk = function(bl) {\n var chunks = [];\n var size = bl.size;\n var start = 0;\n while (start < size) {\n var end = Math.min(size, start + this._mtu);\n var b = bl.slice(start, end);\n var chunk = {\n payload: b\n }\n chunks.push(chunk);\n start = end;\n }\n util.log('Created', chunks.length, 'chunks.');\n return chunks;\n };\n\n// Sends ACK N, expecting Nth blob chunk for message ID.\n Reliable.prototype._ack = function(id) {\n var ack = this._incoming[id].ack;\n\n // if ack is the end value, then call _complete.\n if (this._received[id] === ack[2]) {\n this._complete(id);\n this._received[id] = true;\n }\n\n this._handleSend(ack);\n };\n\n// Calculates the next ACK number, given chunks.\n Reliable.prototype._calculateNextAck = function(id) {\n var data = this._incoming[id];\n var chunks = data.chunks;\n for (var i = 0, ii = chunks.length; i < ii; i += 1) {\n // This chunk is missing!!! Better ACK for it.\n if (chunks[i] === undefined) {\n data.ack[2] = i;\n return;\n }\n }\n data.ack[2] = chunks.length;\n };\n\n// Sends the next window of chunks.\n Reliable.prototype._sendWindowedChunks = function(id) {\n util.log('sendWindowedChunks for: ', id);\n var data = this._outgoing[id];\n var ch = data.chunks;\n var chunks = [];\n var limit = Math.min(data.ack + this._window, ch.length);\n for (var i = data.ack; i < limit; i += 1) {\n if (!ch[i].sent || i === data.ack) {\n ch[i].sent = true;\n chunks.push(['chunk', id, i, ch[i].payload]);\n }\n }\n if (data.ack + this._window >= ch.length) {\n chunks.push(['end', id, ch.length])\n }\n chunks._multiple = true;\n this._handleSend(chunks);\n };\n\n// Puts together a message from chunks.\n Reliable.prototype._complete = function(id) {\n util.log('Completed called for', id);\n var self = this;\n var chunks = this._incoming[id].chunks;\n var bl = new Blob(chunks);\n util.blobToArrayBuffer(bl, function(ab) {\n self.onmessage(util.unpack(ab));\n });\n delete this._incoming[id];\n };\n\n// Ups bandwidth limit on SDP. Meant to be called during offer/answer.\n Reliable.higherBandwidthSDP = function(sdp) {\n // AS stands for Application-Specific Maximum.\n // Bandwidth number is in kilobits / sec.\n // See RFC for more info: http://www.ietf.org/rfc/rfc2327.txt\n\n // Chrome 31+ doesn't want us munging the SDP, so we'll let them have their\n // way.\n var version = navigator.appVersion.match(/Chrome\\/(.*?) /);\n if (version) {\n version = parseInt(version[1].split('.').shift());\n if (version < 31) {\n var parts = sdp.split('b=AS:30');\n var replace = 'b=AS:102400'; // 100 Mbps\n if (parts.length > 1) {\n return parts[0] + replace + parts[1];\n }\n }\n }\n\n return sdp;\n };\n\n// Overwritten, typically.\n Reliable.prototype.onmessage = function(msg) {};\n\n module.exports.Reliable = Reliable;\n\n},{\"./util\":13}],13:[function(require,module,exports){\n var BinaryPack = require('js-binarypack');\n\n var util = {\n debug: false,\n\n inherits: function(ctor, superCtor) {\n ctor.super_ = superCtor;\n ctor.prototype = Object.create(superCtor.prototype, {\n constructor: {\n value: ctor,\n enumerable: false,\n writable: true,\n configurable: true\n }\n });\n },\n extend: function(dest, source) {\n for(var key in source) {\n if(source.hasOwnProperty(key)) {\n dest[key] = source[key];\n }\n }\n return dest;\n },\n pack: BinaryPack.pack,\n unpack: BinaryPack.unpack,\n\n log: function () {\n if (util.debug) {\n var copy = [];\n for (var i = 0; i < arguments.length; i++) {\n copy[i] = arguments[i];\n }\n copy.unshift('Reliable: ');\n console.log.apply(console, copy);\n }\n },\n\n setZeroTimeout: (function(global) {\n var timeouts = [];\n var messageName = 'zero-timeout-message';\n\n // Like setTimeout, but only takes a function argument.\t There's\n // no time argument (always zero) and no arguments (you have to\n // use a closure).\n function setZeroTimeoutPostMessage(fn) {\n timeouts.push(fn);\n global.postMessage(messageName, '*');\n }\n\n function handleMessage(event) {\n if (event.source == global && event.data == messageName) {\n if (event.stopPropagation) {\n event.stopPropagation();\n }\n if (timeouts.length) {\n timeouts.shift()();\n }\n }\n }\n if (global.addEventListener) {\n global.addEventListener('message', handleMessage, true);\n } else if (global.attachEvent) {\n global.attachEvent('onmessage', handleMessage);\n }\n return setZeroTimeoutPostMessage;\n }(this)),\n\n blobToArrayBuffer: function(blob, cb){\n var fr = new FileReader();\n fr.onload = function(evt) {\n cb(evt.target.result);\n };\n fr.readAsArrayBuffer(blob);\n },\n blobToBinaryString: function(blob, cb){\n var fr = new FileReader();\n fr.onload = function(evt) {\n cb(evt.target.result);\n };\n fr.readAsBinaryString(blob);\n },\n binaryStringToArrayBuffer: function(binary) {\n var byteArray = new Uint8Array(binary.length);\n for (var i = 0; i < binary.length; i++) {\n byteArray[i] = binary.charCodeAt(i) & 0xff;\n }\n return byteArray.buffer;\n },\n randomToken: function () {\n return Math.random().toString(36).substr(2);\n }\n };\n\n module.exports = util;\n\n},{\"js-binarypack\":10}]},{},[3]);\n"]} \ No newline at end of file diff --git a/gruntfile.js b/gruntfile.js index b6cf5a6..a705ef1 100644 --- a/gruntfile.js +++ b/gruntfile.js @@ -5,6 +5,8 @@ module.exports = function(grunt) { pkg: grunt.file.readJSON('package.json'), uglify: { options: { + sourceMap: true, + sourceMapIncludeSources: true, banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n' }, build: { diff --git a/src/couchfriends.api.js b/src/couchfriends.api.js index 0f50efa..67e21a9 100644 --- a/src/couchfriends.api.js +++ b/src/couchfriends.api.js @@ -309,7 +309,15 @@ COUCHFRIENDS.connect = function () { * @param data Object object with data to send. See Api references for all available options. */ COUCHFRIENDS.send = function (data) { - COUCHFRIENDS._socket.send(data); + if (data.id == null) { + console.warn(data); + } + for (var i = 0; i < this.players.length; i++) { + if (data.id == this.players[i].id) { + this.players[i].conn.send(data); + break; + } + } }; Emitter(COUCHFRIENDS); @@ -363,7 +371,8 @@ COUCHFRIENDS.on('player.join', function (conn) { data: { color: this.player.color } - }) + }); + COUCHFRIENDS.emit('player.identify', {color: this.player.color, player: {id: this.player.id}}); }); conn.on('close', function () { COUCHFRIENDS.emit('player.left', {