text: /**
   * imMatch v1.1.0pre Websocket Server https://bitbucket.org/kf99916/immatch | MIT license
   */
  !function(e,t){t(e)}("undefined"!=typeof window?window:this,function(e){"use strict";function t(){return!0}function n(){return!1}function i(e){return"["+e.toUpperCase()+"] "+Date()+" :"}!function(){var e="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".split("");Math.uuid=function(t,n){var i,r=e,s=[];if(n=n||r.length,t)for(i=0;t>i;i++)s[i]=r[0|Math.random()*n];else{var o;for(s[8]=s[13]=s[18]=s[23]="-",s[14]="4",i=0;36>i;i++)s[i]||(o=0|16*Math.random(),s[i]=r[19==i?3&o|8:o])}return s.join("")},Math.uuidFast=function(){for(var t,n=e,i=new Array(36),r=0,s=0;36>s;s++)8==s||13==s||18==s||23==s?i[s]="-":14==s?i[s]="4":(2>=r&&(r=33554432+16777216*Math.random()|0),t=15&r,r>>=4,i[s]=n[19==s?3&t|8:t]);return i.join("")},Math.uuidCompact=function(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(e){var t=16*Math.random()|0,n="x"==e?t:3&t|8;return n.toString(16)})}}(),e=require("jsdom").jsdom().parentWindow;var r=require("jquery/dist/jquery")(e),s=require("ws");Date.now=Date.now||function(){return(new Date).getTime()};var o=e.document,c=[],a=c.slice,u=c.indexOf,h=c.push,m=c.unshift,f=JSON.stringify,l=r({});return l.AffineTransform=function(e,t,n,i,r,s){return this instanceof l.AffineTransform?void this.setTransform(e,t,n,i,r,s):new l.AffineTransform(e,t,n,i,r,s)},l.AffineTransform.getScaleInstance=function(e){return(new l.AffineTransform).setToScale(e)},l.AffineTransform.getTranslationInstance=function(e){return(new l.AffineTransform).setToTranslation(e)},l.AffineTransform.getShearInstance=function(e){return(new l.AffineTransform).setToShear(e)},l.AffineTransform.getRotateInstance=function(e,t){return(new l.AffineTransform).setToRotation(e,t)},l.AffineTransform.prototype={setTransform:function(e,t,n,i,s,o){return r.isNumeric(e)&&r.isNumeric(n)&&r.isNumeric(s)&&r.isNumeric(t)&&r.isNumeric(i)&&r.isNumeric(o)?(this.m00=e,this.m01=n,this.m02=s,this.m10=t,this.m11=i,this.m12=o,this):(this.m00=this.m11=1,this.m01=this.m02=this.m10=this.m12=0,this)},clone:function(){return new l.AffineTransform(this.m00,this.m10,this.m01,this.m11,this.m02,this.m12)},scale:function(e){return this.concatenate(l.AffineTransform.getScaleInstance(e))},preScale:function(e){return this.preConcatenate(l.AffineTransform.getScaleInstance(e))},translate:function(e){return this.concatenate(l.AffineTransform.getTranslationInstance(e))},preTranslate:function(e){return this.preConcatenate(l.AffineTransform.getTranslationInstance(e))},rotate:function(e,t){return this.concatenate(l.AffineTransform.getRotateInstance(e,t))},preRotate:function(e,t){return this.preConcatenate(l.AffineTransform.getRotateInstance(e,t))},shear:function(e){return this.concatenate(l.AffineTransform.getShearInstance(e))},preShear:function(e){return this.preConcatenate(l.AffineTransform.getShearInstance(e))},concatenate:function(e){if(!(!l.isEmpty(e)&&r.isNumeric(e.m00)&&r.isNumeric(e.m01)&&r.isNumeric(e.m02)&&r.isNumeric(e.m10)&&r.isNumeric(e.m11)&&r.isNumeric(e.m12)))return this;var t=this.m00,n=this.m01;return this.m00=e.m00*t+e.m10*n,this.m01=e.m01*t+e.m11*n,this.m02+=e.m02*t+e.m12*n,t=this.m10,n=this.m11,this.m10=e.m00*t+e.m10*n,this.m11=e.m01*t+e.m11*n,this.m12+=e.m02*t+e.m12*n,this},preConcatenate:function(e){if(!(!l.isEmpty(e)&&r.isNumeric(e.m00)&&r.isNumeric(e.m01)&&r.isNumeric(e.m02)&&r.isNumeric(e.m10)&&r.isNumeric(e.m11)&&r.isNumeric(e.m12)))return this;var t=this.m00,n=this.m10;return this.m00=e.m00*t+e.m01*n,this.m10=e.m10*t+e.m11*n,t=this.m01,n=this.m11,this.m01=e.m00*t+e.m01*n,this.m11=e.m10*t+e.m11*n,t=this.m02,n=this.m12,this.m02=e.m00*t+e.m01*n+e.m02,this.m12=e.m10*t+e.m11*n+e.m12,this},transform:function(e){return l.is2DVector(e)?{x:e.x*this.m00+e.y*this.m01+this.m02,y:e.x*this.m10+e.y*this.m11+this.m12}:{x:0,y:0}},getDeterminant:function(){return this.m00*this.m11-this.m01*this.m10},isInvertible:function(){var e=this.getDeterminant();return r.isNumeric(e)&&r.isNumeric(this.m02)&&r.isNumeric(this.m12)&&0!==e},inverse:function(){if(!this.isInvertible)return this;var e=this.getDeterminant(),t=this.m00,n=this.m10,i=this.m01,r=this.m11,s=this.m02,o=this.m12;return this.m00=r/e,this.m10=-n/e,this.m01=-i/e,this.m11=t/e,this.m02=(i*o-r*s)/e,this.m12=(n*s-t*o)/e,this},createInverse:function(){return this.isInvertible?this.clone().inverse():this},setToScale:function(e){return r.isEmptyObject(e)&&(e={x:1,y:1}),this.setTransform(e.x,0,0,e.y,0,0)},setToTranslation:function(e){return r.isEmptyObject(e)&&(e={x:0,y:0}),this.setTransform(1,0,0,1,e.x,e.y)},setToShear:function(e){return r.isEmptyObject(e)&&(e={x:0,y:0}),this.setTransform(1,e.y,e.x,1,0,0)},setToRotation:function(e,t){r.isEmptyObject(t)&&(t={x:0,y:0}),e=r.isNumeric(e)?e:0;var n=Math.cos(e),i=Math.sin(e);return this.setTransform(n,i,-i,n,t.x-t.x*n+t.y*i,t.y-t.x*i-t.y*n)},toJSON:function(){return[this.m00,this.m10,this.m01,this.m11,this.m02,this.m12]},print:function(){e.console.log("[ "+this.m00+" "+this.m01+" "+this.m02+" ]"),e.console.log("[ "+this.m10+" "+this.m11+" "+this.m12+" ]"),e.console.log("[ 0 0 1 ]"),e.console.log()}},l.Cache=function(){return this instanceof l.Cache?void 0:new l.Cache},l.Cache.prototype={queue:function(e,t,n){return l.isEmpty(e)||l.isEmpty(t)?this:(this[e]=this[e]||[],h.call(this[e],t),r.isFunction(n)?(this[e].sort(n),this):this)},dequeue:function(e){var t={};return l.isEmpty(e)||r.isEmptyObject(this[e])?t:(t=this[e].shift(),l.isEmpty(t)&&delete this[e],t)},get:function(e,t){return l.isEmpty(e)||r.isEmptyObject(this[e])?[]:r.isFunction(t)?r.grep(this[e],t):this[e]},getNRemove:function(e,t){return l.isEmpty(e)||r.isEmptyObject(this[e])?[]:this.remove(e,t)},remove:function(e,t){var n=[];return l.isEmpty(e)||r.isEmptyObject(this[e])?n:r.isFunction(t)?(n=r.grep(this[e],t),this[e]=r.grep(this[e],t,!0),n):(r.extend(n,this[e]),delete this[e],n)}},r.extend(l,{isReady:n,ready:function(e){return l.isReady()?this:(r(o).ready(function(){l.loader.load(e)}),this)},is2DVector:function(e){return r.isEmptyObject(e)?!1:r.isNumeric(e.x)&&r.isNumeric(e.y)},isEmpty:function(e){return void 0===e||null===e},remove:function(e,t){return r.isEmptyObject(t)?e:(r.isArray(e)?a.call(e,t,1):r.isPlainObject(e)&&delete e[t],e)}}),e.console=e.console||{},e.console.log=console.log||function(){return arguments},e.console.debug=console.debug||function(){e.console.log.apply(e.console,arguments)},e.console.info=console.info||function(){e.console.log.apply(e.console,arguments)},e.console.warn=console.warn||function(){e.console.log.apply(e.console,arguments)},e.console.error=console.error||function(){e.console.log.apply(e.console,arguments)},r.extend(l,{debugLevel:0,infoLevel:1,warnLevel:2,errorLevel:3,logDebug:function(){return 0===arguments.length||this.logLevel>l.debugLevel?this:(m.call(arguments,i("DEBUG")),e.console.debug.apply(e.console,arguments),this)},logInfo:function(){return 0===arguments.length||this.logLevel>l.infoLevel?this:(m.call(arguments,i("INFO")),e.console.info.apply(e.console,arguments),this)},logWarn:function(){return 0===arguments.length||this.logLevel>l.warnLevel?this:(m.call(arguments,i("WARN")),e.console.warn.apply(e.console,arguments),this)},logError:function(){return 0===arguments.length||this.logLevel>l.errorLevel?this:(m.call(arguments,i("ERROR")),e.console.error.apply(e.console,arguments),this)},logLevel:l.errorLevel}),r.extend(l,{rotate:function(e,t,n){var i,s,o;return!r.isNumeric(t)||0===t||l.isEmpty(e.x)||l.isEmpty(e.y)?e:(n=n||{x:0,y:0},i={x:e.x-n.x,y:e.y-n.y},s=Math.cos(t),o=Math.sin(t),{x:n.x+i.x*s-i.y*o,y:n.y+i.x*o+i.y*s})},max:function(){var e=arguments[0],t={index:-1,value:+1/0};return r.isArrayLike(e)||(e=[],r.each(arguments,function(t,n){h.call(e,n)})),t.value=Math.max.apply(Math,e),t.index=u.call(e,t.value),t},min:function(){var e=arguments[0],t={index:-1,value:-1/0};return r.isArrayLike(e)||(e=[],r.each(arguments,function(t,n){h.call(e,n)})),t.value=Math.min.apply(Math,e),t.index=u.call(e,t.value),t},mod:function(e,t){return(e%t+t)%t},dot:function(e,t){return l.is2DVector(e)&&l.is2DVector(t)?e.x*t.x+e.y*t.y:1},rad:function(e,t){return l.is2DVector(e)&&l.is2DVector(t)?Math.atan2(e.x*t.y-t.x*e.y,l.dot(e,t)):0},norm:function(e){return Math.sqrt(l.dot(e,e))},round:function(e){return r.isNumeric(e)?~~(e+.5):e}}),e.WebSocket=e.WebSocket||{},e.WebSocket.OPEN=e.WebSocket.OPEN||1,r.extend(l,{lifetimeCandidate:2e3}),l.Device=function(e){return this instanceof l.Device?(this.id=Math.uuidFast(),void(this.webSocket=e)):new l.Device(e)},l.Device.prototype={send:function(t){if(r.isEmptyObject(t)||l.isEmpty(t.action))return l.logError("[imMatch.Device.send] The format of message is wrong! Message: ",t),this;if(this.webSocket.readyState!==e.WebSocket.OPEN)return l.logError("[imMatch.Device.send] WebSocket is not ready. ready state: "+this.webSocket.readyState),this;try{this.webSocket.send(f.call(this,t))}catch(n){l.error("[imMatch.Group.addGroup] WEbSocket failed to send message. Error Message: "+n.message)}return this}},l.Group=function(e){return this instanceof l.Group?(this.id=Math.uuidFast(),this.devices=[],this.numExchangedDoneDevices=0,this.numDevicesSynced={},void this.addDevices(e)):new l.Group(e)},l.Group.prototype={addDevices:function(e){return r.isEmptyObject(e)?this:(r.isArray(e)||(e=[e]),h.apply(this.devices,e),this)},synchronize:function(e){return r.isEmptyObject(e)?this:(this.broadcast(e),l.isEmpty(this.numDevicesSynced[e.chunk])&&(this.numDevicesSynced[e.chunk]=0),++this.numDevicesSynced[e.chunk],this.numDevicesSynced[e.chunk]!==this.devices.length?this:(delete this.numDevicesSynced[e.chunk],this.stitch()?this:(this.broadcast({action:"synchronizeDone",chunk:e.chunk}),this)))},broadcast:function(e){return r.isEmptyObject(e)?this:(r.each(this.devices,function(t,n){n.send(e)}),this)},getStitchingInfo:function(){var e,t=this,n=l.webSocketServer.caches.get("stitchingInfo");return r.each(n,function(n,i){return t.id===i[0].groupID||t.id===i[1].groupID?(e=i,!1):void 0}),e},stitch:function(){var e=this.getStitchingInfo();return r.isEmptyObject(e)?!1:(this.id===e[1].groupID&&(e=e.reverse()),this.broadcast({action:"stitching",stitchingInfo:e}),l.logInfo("[imMatch.Group.stitch][device1]",e[0],"[device2]",e[1]),!0)}},r.extend(s.Server.prototype,{groups:{},caches:new l.Cache,addGroup:function(e){var t,n;return r.isEmptyObject(e)?(l.logWarn("[ws.Server.addGroup] NO webSocket."),this):(n=new l.Device(e),t=new l.Group(n),this.groups[t.id]=t,n.send({action:"connectionSuccess",groupID:t.id,deviceID:n.id,numDevices:t.devices.length}),t)},monitorCaches:function(){var e=Date.now();return this.caches.remove("stitchingCandidate",function(t){return Math.abs(e-t.timeStamp)>l.lifetimeCandidate}),setTimeout(this.monitorCaches.bind(this),l.lifetimeCandidate),this},addCandidate:function(e){return r.isEmptyObject(e)?this:(this.caches.remove("stitchingCandidate",function(t){return e.groupID===t.groupID&&e.deviceID===t.deviceID}),this.caches.queue("stitchingCandidate",e),this)},searchMatchCandidate:function(e){var t,n=this.caches.get("stitchingCandidate");return r.isEmptyObject(e)?null:(r.each(n.reverse(),function(n,i){return e.deviceID!==i.deviceID&&Math.abs(e.timeStamp-i.timeStamp)<l.lifetimeCandidate?(t=i,!1):void 0}),t)},computeAffineFactor:function(e){e.rad=l.rad(e.orientation,{x:1,y:0});var t=l.AffineTransform.getRotateInstance(e.rad);return e.margin=t.transform(e.margin),e.point=t.transform(e.point),e.translationFactor={x:e.margin.x-e.point.x,y:e.margin.y-e.point.y},delete e.margin,delete e.point,delete e.orientation,this},response:{connection:function(e){return this.addGroup(e),this},close:function(e,t){return l.logInfo("[ws.Server.response.close] The client closes WebSocket. deviceID = "+t.deviceID+", groupID = "+t.groupID+". Message: "+e.message),this},error:function(e,t){r.error("[ws.Server.response.error] WebSocket error. Device: "+t.deviceID+", in group: "+t.groupID+". Error message: "+e.message)},tryToStitch:function(e){var t,n,i,s,o=this.searchMatchCandidate(e);return r.isEmptyObject(o)?(this.addCandidate(e),this):(t=this.groups[e.groupID],n=this.groups[o.groupID],l.isEmpty(t)||l.isEmpty(n)?(l.logError("[ws.Server.tryToStitch] group or matchGroup are empty. group:",t,"matchGroup:",n),this):r.isEmptyObject(t.getStitchingInfo())&&r.isEmptyObject(n.getStitchingInfo())?t.id===n.id?this:(t.numDevicesSynced={},n.numDevicesSynced={},i=t.devices.length,s=n.devices.length,e.orientation.x=-e.orientation.x,e.orientation.y=-e.orientation.y,this.computeAffineFactor(e),this.computeAffineFactor(o),e.numExchangedDevices=s,o.numExchangedDevices=i,this.caches.queue("stitchingInfo",[e,o]),t.stitch(),void n.stitch()):(l.logDebug("[ws.Server.tryToStitch] Groups are stitching. group:",t,"matchGroup:",n),this))},synchronize:function(e){return this.groups[e.groupID].synchronize(e),this},exchange:function(e){var t=this.groups[e.toGroupID];return r.isEmptyObject(t)?this:void t.broadcast(e)},exchangeDone:function(e){var t=this.groups[e.groupID],n=this.groups[e.toGroupID],i=t.devices.length+n.devices.length;return++t.numExchangedDoneDevices,++n.numExchangedDoneDevices,i!==t.numExchangedDoneDevices||i!==n.numExchangedDoneDevices?this:(t.numExchangedDoneDevices=0,this.caches.remove("stitchingInfo"),t.addDevices(n.devices),delete this.groups[e.toGroupID],void t.broadcast({action:"exchangeDone",groupID:t.id,numDevices:t.devices.length}))}}}),l.logLevel=l.infoLevel,l.isReady=t,l.webSocketServer=new s.Server({port:8080,host:null}),l.webSocketServer.on("connection",function(e){var t=this;this.response.connection.call(this,e),e.on("message",function(e){var n,i;return r.isEmptyObject(e)?void l.logError("[WebSocket.onmessage] The message is empty!"):(n=r.parseJSON(e),n.timeStamp=Date.now(),l.logDebug("[WebSocket.onmessage] Action Type: "+n.action,n),i=t.response[n.action],l.isEmpty(i)?void l.logWarn("[WebSocket.onmessage] Unknown action: "+n.action):void i.call(t,n))}),e.on("close",function(n){t.response.close.call(t,n,e)}),e.on("error",function(n){t.response.error.call(t,n,e)})}),l.webSocketServer.on("error",function(e){r.error("[imMatch.webSocketServer] WebSocket Server error. error message: "+e.message)}),l.webSocketServer.monitorCaches(),l});