faye 0.3.1 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of faye might be problematic. Click here for more details.

data/jake.yml CHANGED
@@ -14,6 +14,8 @@ packages:
14
14
  - util/class
15
15
  - util/deferrable
16
16
  - util/observable
17
+ - util/logging
18
+ - timeouts
17
19
  - channel
18
20
  - namespace
19
21
  - transport
@@ -25,8 +27,8 @@ packages:
25
27
  - server
26
28
  - connection
27
29
  - error
28
- - transports/node
29
30
  - node_adapter
31
+ - transports/node
30
32
  faye-client:
31
33
  extends: core
32
34
  files:
@@ -1 +1 @@
1
- if(!this.Faye)Faye={};Faye.extend=function(a,b,c){if(!b)return a;for(var d in b){if(!b.hasOwnProperty(d))continue;if(a.hasOwnProperty(d)&&c===false)continue;if(a[d]!==b[d])a[d]=b[d]}return a};Faye.extend(Faye,{VERSION:'0.3.1',BAYEUX_VERSION:'1.0',ID_LENGTH:128,JSONP_CALLBACK:'jsonpcallback',CONNECTION_TYPES:["long-polling","callback-polling"],ENV:this,random:function(a){a=a||this.ID_LENGTH;if(a>32){var b=Math.ceil(a/32),c='';while(b--)c+=this.random(32);return c}var d=Math.pow(2,a);return Math.floor(Math.random()*d).toString(16)},Grammar:{LOWALPHA:/^[a-z]$/,UPALPHA:/^[A-Z]$/,ALPHA:/^([a-z]|[A-Z])$/,DIGIT:/^[0-9]$/,ALPHANUM:/^(([a-z]|[A-Z])|[0-9])$/,MARK:/^(\-|\_|\!|\~|\(|\)|\$|\@)$/,STRING:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*$/,TOKEN:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+$/,INTEGER:/^([0-9])+$/,CHANNEL_SEGMENT:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+$/,CHANNEL_SEGMENTS:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+(\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+)*$/,CHANNEL_NAME:/^\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+(\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+)*$/,WILD_CARD:/^\*{1,2}$/,CHANNEL_PATTERN:/^(\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+)*\/\*{1,2}$/,VERSION_ELEMENT:/^(([a-z]|[A-Z])|[0-9])(((([a-z]|[A-Z])|[0-9])|\-|\_))*$/,VERSION:/^([0-9])+(\.(([a-z]|[A-Z])|[0-9])(((([a-z]|[A-Z])|[0-9])|\-|\_))*)*$/,CLIENT_ID:/^((([a-z]|[A-Z])|[0-9]))+$/,ID:/^((([a-z]|[A-Z])|[0-9]))+$/,ERROR_MESSAGE:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*$/,ERROR_ARGS:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*(,(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*)*$/,ERROR_CODE:/^[0-9][0-9][0-9]$/,ERROR:/^([0-9][0-9][0-9]:(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*(,(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*)*:(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*|[0-9][0-9][0-9]::(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*)$/},commonElement:function(a,b){for(var c=0,d=a.length;c<d;c++){if(this.indexOf(b,a[c])!==-1)return a[c]}return null},indexOf:function(a,b){for(var c=0,d=a.length;c<d;c++){if(a[c]===b)return c}return-1},each:function(a,b,c){if(a instanceof Array){for(var d=0,f=a.length;d<f;d++){if(a[d]!==undefined)b.call(c||null,a[d],d)}}else{for(var g in a){if(a.hasOwnProperty(g))b.call(c||null,g,a[g])}}},filter:function(a,b,c){var d=[];this.each(a,function(){if(b.apply(c,arguments))d.push(arguments[0])});return d},size:function(a){var b=0;this.each(a,function(){b+=1});return b},enumEqual:function(c,d){if(d instanceof Array){if(!(c instanceof Array))return false;var f=c.length;if(f!==d.length)return false;while(f--){if(c[f]!==d[f])return false}return true}else{if(!(c instanceof Object))return false;if(this.size(d)!==this.size(c))return false;var g=true;this.each(c,function(a,b){g=g&&(d[a]===b)});return g}}});Faye.Class=function(a,b){if(typeof a!=='function'){b=a;a=Object}var c=function(){if(!this.initialize)return this;return this.initialize.apply(this,arguments)||this};var d=function(){};d.prototype=a.prototype;c.prototype=new d();Faye.extend(c.prototype,b);return c};Faye.Deferrable={callback:function(a,b){if(this._t==='succeeded')return a.apply(b,this._m);this._9=this._9||[];this._9.push([a,b])},setDeferredStatus:function(){var b=Array.prototype.slice.call(arguments),c=b.shift();this._t=c;this._m=b;if(c!=='succeeded')return;if(!this._9)return;Faye.each(this._9,function(a){a[0].apply(a[1],this._m)},this);this._9=[]}};Faye.Observable={on:function(a,b,c){this._0=this._0||{};var d=this._0[a]=this._0[a]||[];d.push([b,c])},stopObserving:function(a,b,c){if(!this._0||!this._0[a])return;if(!b){delete this._0[a];return}var d=this._0[a],f=d.length;while(f--){if(b&&d[f][0]!==b)continue;if(c&&d[f][1]!==c)continue;d.splice(f,1)}},fire:function(){var b=Array.prototype.slice.call(arguments),c=b.shift();if(!this._0||!this._0[c])return;Faye.each(this._0[c],function(a){a[0].apply(a[1],b.slice())})}};Faye.Channel=Faye.Class({initialize:function(a){this.__id=this.name=a},push:function(a){this.fire('message',a)}});Faye.extend(Faye.Channel.prototype,Faye.Observable);Faye.extend(Faye.Channel,{HANDSHAKE:'/meta/handshake',CONNECT:'/meta/connect',SUBSCRIBE:'/meta/subscribe',UNSUBSCRIBE:'/meta/unsubscribe',DISCONNECT:'/meta/disconnect',META:'meta',SERVICE:'service',isValid:function(a){return Faye.Grammar.CHANNEL_NAME.test(a)||Faye.Grammar.CHANNEL_PATTERN.test(a)},parse:function(a){if(!this.isValid(a))return null;return a.split('/').slice(1)},isMeta:function(a){var b=this.parse(a);return b?(b[0]===this.META):null},isService:function(a){var b=this.parse(a);return b?(b[0]===this.SERVICE):null},isSubscribable:function(a){if(!this.isValid(a))return null;return!this.isMeta(a)&&!this.isService(a)},Tree:Faye.Class({initialize:function(a){this._1=a;this._5={}},eachChild:function(c,d){Faye.each(this._5,function(a,b){c.call(d,a,b)})},each:function(c,d,f){this.eachChild(function(a,b){a=c.concat(a);b.each(a,d,f)});if(this._1!==undefined)d.call(f,c,this._1)},map:function(c,d){var f=[];this.each([],function(a,b){f.push(c.call(d,a,b))});return f},get:function(a){var b=this.traverse(a);return b?b._1:null},set:function(a,b){var c=this.traverse(a,true);if(c)c._1=b},traverse:function(a,b){if(typeof a==='string')a=Faye.Channel.parse(a);if(a===null)return null;if(a.length===0)return this;var c=this._5[a[0]];if(!c&&!b)return null;if(!c)c=this._5[a[0]]=new Faye.Channel.Tree();return c.traverse(a.slice(1),b)},findOrCreate:function(a){var b=this.get(a);if(b)return b;b=new Faye.Channel(a);this.set(a,b);return b},glob:function(f){if(typeof f==='string')f=Faye.Channel.parse(f);if(f===null)return[];if(f.length===0)return(this._1===undefined)?[]:[this._1];var g=[];if(Faye.enumEqual(f,['*'])){Faye.each(this._5,function(a,b){if(b._1!==undefined)g.push(b._1)});return g}if(Faye.enumEqual(f,['**'])){g=this.map(function(a,b){return b});if(this._1!==undefined)g.pop();return g}Faye.each(this._5,function(b,c){if(b!==f[0]&&b!=='*')return;var d=c.glob(f.slice(1));Faye.each(d,function(a){g.push(a)})});if(this._5['**'])g.push(this._5['**']._1);return g}})});Faye.Namespace=Faye.Class({initialize:function(){this._n={}},generate:function(){var a=Faye.random();while(this._n.hasOwnProperty(a))a=Faye.random();return this._n[a]=a}});Faye.Transport=Faye.extend(Faye.Class({initialize:function(a,b){this._f=a;this._6=b},send:function(c,d,f){if(!(c instanceof Array)&&!c.id)c.id=this._f._o.generate();this.request(c,function(b){if(!d)return;Faye.each([].concat(b),function(a){if(a.id===c.id)d.call(f,a);if(a.advice)this._f.handleAdvice(a.advice);if(a.data&&a.channel)this._f.sendToSubscribers(a)},this)},this)}}),{get:function(c,d){var f=c._6;if(d===undefined)d=this.supportedConnectionTypes();var g=null;Faye.each(this._g,function(a,b){if(Faye.indexOf(d,a)<0)return;if(g)return;if(b.isUsable(f))g=b});if(!g)throw'Could not find a usable connection type for '+f;return new g(c,f)},register:function(a,b){this._g[a]=b;b.prototype.connectionType=a},_g:{},supportedConnectionTypes:function(){var c=[],d;Faye.each(this._g,function(a,b){c.push(a)});return c}});Faye.Client=Faye.Class({UNCONNECTED:1,CONNECTING:2,CONNECTED:3,DISCONNECTED:4,HANDSHAKE:'handshake',RETRY:'retry',NONE:'none',DEFAULT_ENDPOINT:'/bayeux',MAX_DELAY:0.1,INTERVAL:1000.0,initialize:function(a){this._6=a||this.DEFAULT_ENDPOINT;this._4=Faye.Transport.get(this);this._2=this.UNCONNECTED;this._o=new Faye.Namespace();this._h=[];this._a=new Faye.Channel.Tree();this._p=[];this._7={reconnect:this.RETRY,interval:this.INTERVAL};if(!Faye.Event)return;Faye.Event.on(Faye.ENV,'beforeunload',this.disconnect,this)},handshake:function(b,c){if(this._7.reconnect===this.NONE)return;if(this._2!==this.UNCONNECTED)return;this._2=this.CONNECTING;var d=this;this._4.send({channel:Faye.Channel.HANDSHAKE,version:Faye.BAYEUX_VERSION,supportedConnectionTypes:Faye.Transport.supportedConnectionTypes()},function(a){if(!a.successful){setTimeout(function(){d.handshake(b,c)},this._7.interval);return this._2=this.UNCONNECTED}this._2=this.CONNECTED;this._8=a.clientId;this._4=Faye.Transport.get(this,a.supportedConnectionTypes);if(b)b.call(c)},this)},connect:function(b,c){if(this._7.reconnect===this.NONE)return;if(this._2===this.DISCONNECTED)return;if(this._7.reconnect===this.HANDSHAKE||this._2===this.UNCONNECTED)return this.handshake(function(){this.connect(b,c)},this);if(this._2===this.CONNECTING)return this.callback(b,c);if(this._2!==this.CONNECTED)return;this.setDeferredStatus('succeeded');this.setDeferredStatus('deferred');if(b)b.call(c);if(this._i)return;this._i=this._o.generate();var d=this;this._4.send({channel:Faye.Channel.CONNECT,clientId:this._8,connectionType:this._4.connectionType,id:this._i},function(a){delete this._i;setTimeout(function(){d.connect()},this._7.interval)},this)},disconnect:function(){if(this._2!==this.CONNECTED)return;this._2=this.DISCONNECTED;this._4.send({channel:Faye.Channel.DISCONNECT,clientId:this._8});this._a=new Faye.Channel.Tree()},subscribe:function(c,d,f){this.connect(function(){c=[].concat(c);this._j(c);this._4.send({channel:Faye.Channel.SUBSCRIBE,clientId:this._8,subscription:c},function(b){if(!b.successful)return;c=[].concat(b.subscription);Faye.each(c,function(a){this._a.set(a,[d,f])},this)},this)},this)},unsubscribe:function(c,d,f){this.connect(function(){c=[].concat(c);this._j(c);this._4.send({channel:Faye.Channel.UNSUBSCRIBE,clientId:this._8,subscription:c},function(b){if(!b.successful)return;c=[].concat(b.subscription);Faye.each(c,function(a){this._a.set(a,null)},this)},this)},this)},publish:function(b,c){this.connect(function(){this._j([b]);this._u({channel:b,data:c,clientId:this._8});if(this._q)return;var a=this;this._q=setTimeout(function(){delete a._q;a._v()},this.MAX_DELAY*1000)},this)},handleAdvice:function(a){Faye.extend(this._7,a);if(this._7.reconnect===this.HANDSHAKE)this._8=null},sendToSubscribers:function(b){var c=this._a.glob(b.channel);Faye.each(c,function(a){if(!a)return;a[0].call(a[1],b.data)})},_u:function(a){this._h.push(a)},_v:function(){this._4.send(this._h);this._h=[]},_j:function(b){Faye.each(b,function(a){if(!Faye.Channel.isValid(a))throw'"'+a+'" is not a valid channel name';if(!Faye.Channel.isSubscribable(a))throw'Clients may not subscribe to channel "'+a+'"';})}});Faye.extend(Faye.Client.prototype,Faye.Deferrable);Faye.Event={_b:[],on:function(a,b,c,d){var f=function(){c.call(d)};if(a.addEventListener)a.addEventListener(b,f,false);else a.attachEvent('on'+b,f);this._b.push({_c:a,_k:b,_w:c,_d:d,_r:f})},detach:function(a,b,c,d){var f=this._b.length,g;while(f--){g=this._b[f];if((a&&a!==g._c)||(b&&b!==g._k)||(c&&c!==g._w)||(d&&d!==g._d))continue;if(g._c.removeEventListener)g._c.removeEventListener(g._k,g._r,false);else g._c.detachEvent('on'+g._k,g._r);this._b.splice(f,1);g=null}}};Faye.Event.on(Faye.ENV,'unload',Faye.Event.detach,Faye.Event);Faye.URI=Faye.extend(Faye.Class({queryString:function(){var c=[],d;Faye.each(this.params,function(a,b){c.push(encodeURIComponent(a)+'='+encodeURIComponent(b))});return c.join('&')},isLocal:function(){var a=Faye.URI.parse(Faye.ENV.location.href);var b=(a.hostname!==this.hostname)||(a.port!==this.port)||(a.protocol!==this.protocol);return!b},toURL:function(){return this.protocol+this.hostname+':'+this.port+this.pathname+'?'+this.queryString()}}),{parse:function(d,f){if(typeof d!=='string')return d;var g=new this();var k=function(b,c){d=d.replace(c,function(a){if(a)g[b]=a;return''})};k('protocol',/^https?\:\/+/);k('hostname',/^[^\/\:]+/);k('port',/^:[0-9]+/);Faye.extend(g,{protocol:'http://',hostname:Faye.ENV.location.hostname,port:Faye.ENV.location.port},false);if(!g.port)g.port=(g.protocol==='https://')?'443':'80';g.port=g.port.replace(/\D/g,'');var i=d.split('?'),h=i.shift(),l=i.join('?'),n=l?l.split('&'):[],o=n.length,j={};while(o--){i=n[o].split('=');j[decodeURIComponent(i[0]||'')]=decodeURIComponent(i[1]||'')}Faye.extend(j,f);g.pathname=h;g.params=j;return g}});Faye.XHR={request:function(a,b,c,d,f){var g=new this.Request(a,b,c,d,f);g.send();return g},getXhrObject:function(){return Faye.ENV.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest()},Request:Faye.Class({initialize:function(a,b,c,d,f){this._e=a.toUpperCase();this._6=Faye.URI.parse(b,c);this._p=(typeof d==='function')?{success:d}:d;this._d=f||null;this._3=null},send:function(){if(this._l)return;var a=this._6.pathname,b=this._6.queryString();if(this._e==='GET')a+='?'+b;var c=this._e==='POST'?b:'';this._l=true;this._3=Faye.XHR.getXhrObject();this._3.open(this._e,a,true);if(this._e==='POST')this._3.setRequestHeader('Content-Type','application/x-www-form-urlencoded');var d=this,f=function(){if(d._3.readyState!==4)return;if(g){clearInterval(g);g=null}Faye.Event.detach(Faye.ENV,'beforeunload',d.abort,d);d._l=false;d._x();d=null};var g=setInterval(f,10);Faye.Event.on(Faye.ENV,'beforeunload',this.abort,this);this._3.send(c)},abort:function(){this._3.abort()},_x:function(){var a=this._p;if(!a)return;return this.success()?a.success&&a.success.call(this._d,this):a.failure&&a.failure.call(this._d,this)},waiting:function(){return!!this._l},complete:function(){return this._3&&!this.waiting()},success:function(){if(!this.complete())return false;var a=this._3.status;return(a>=200&&a<300)||a===304||a===1223},failure:function(){if(!this.complete())return false;return!this.success()},text:function(){if(!this.complete())return null;return this._3.responseText},status:function(){if(!this.complete())return null;return this._3.status}})};if(!this.JSON){JSON={}}(function(){function l(a){return a<10?'0'+a:a}if(typeof Date.prototype.toJSON!=='function'){Date.prototype.toJSON=function(a){return this.getUTCFullYear()+'-'+l(this.getUTCMonth()+1)+'-'+l(this.getUTCDate())+'T'+l(this.getUTCHours())+':'+l(this.getUTCMinutes())+':'+l(this.getUTCSeconds())+'Z'};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(a){return this.valueOf()}}var n=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,o=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,j,p,s={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'},m;function r(c){o.lastIndex=0;return o.test(c)?'"'+c.replace(o,function(a){var b=s[a];return typeof b==='string'?b:'\\u'+('0000'+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+c+'"'}function q(a,b){var c,d,f,g,k=j,i,h=b[a];if(h&&typeof h==='object'&&typeof h.toJSON==='function'){h=h.toJSON(a)}if(typeof m==='function'){h=m.call(b,a,h)}switch(typeof h){case'string':return r(h);case'number':return isFinite(h)?String(h):'null';case'boolean':case'null':return String(h);case'object':if(!h){return'null'}j+=p;i=[];if(Object.prototype.toString.apply(h)==='[object Array]'){g=h.length;for(c=0;c<g;c+=1){i[c]=q(c,h)||'null'}f=i.length===0?'[]':j?'[\n'+j+i.join(',\n'+j)+'\n'+k+']':'['+i.join(',')+']';j=k;return f}if(m&&typeof m==='object'){g=m.length;for(c=0;c<g;c+=1){d=m[c];if(typeof d==='string'){f=q(d,h);if(f){i.push(r(d)+(j?': ':':')+f)}}}}else{for(d in h){if(Object.hasOwnProperty.call(h,d)){f=q(d,h);if(f){i.push(r(d)+(j?': ':':')+f)}}}}f=i.length===0?'{}':j?'{\n'+j+i.join(',\n'+j)+'\n'+k+'}':'{'+i.join(',')+'}';j=k;return f}}if(typeof JSON.stringify!=='function'){JSON.stringify=function(a,b,c){var d;j='';p='';if(typeof c==='number'){for(d=0;d<c;d+=1){p+=' '}}else if(typeof c==='string'){p=c}m=b;if(b&&typeof b!=='function'&&(typeof b!=='object'||typeof b.length!=='number')){throw new Error('JSON.stringify');}return q('',{'':a})}}if(typeof JSON.parse!=='function'){JSON.parse=function(g,k){var i;function h(a,b){var c,d,f=a[b];if(f&&typeof f==='object'){for(c in f){if(Object.hasOwnProperty.call(f,c)){d=h(f,c);if(d!==undefined){f[c]=d}else{delete f[c]}}}}return k.call(a,b,f)}n.lastIndex=0;if(n.test(g)){g=g.replace(n,function(a){return'\\u'+('0000'+a.charCodeAt(0).toString(16)).slice(-4)})}if(/^[\],:{}\s]*$/.test(g.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,'@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']').replace(/(?:^|:|,)(?:\s*\[)+/g,''))){i=eval('('+g+')');return typeof k==='function'?h({'':i},''):i}throw new SyntaxError('JSON.parse');}}}());Faye.XHRTransport=Faye.Class(Faye.Transport,{request:function(b,c,d){var f={message:JSON.stringify(b)};Faye.XHR.request('post',this._6,f,function(a){if(c)c.call(d,JSON.parse(a.text()))})}});Faye.XHRTransport.isUsable=function(a){return Faye.URI.parse(a).isLocal()};Faye.Transport.register('long-polling',Faye.XHRTransport);Faye.JSONPTransport=Faye.extend(Faye.Class(Faye.Transport,{request:function(b,c,d){var f={message:JSON.stringify(b)},g=document.getElementsByTagName('head')[0],k=document.createElement('script'),i=Faye.JSONPTransport.getCallbackName(),h=Faye.URI.parse(this._6,f);Faye.ENV[i]=function(a){Faye.ENV[i]=undefined;try{delete Faye.ENV[i]}catch(e){}g.removeChild(k);if(c)c.call(d,a)};h.params.jsonp=i;k.type='text/javascript';k.src=h.toURL();g.appendChild(k)}}),{_s:0,getCallbackName:function(){this._s+=1;return'__jsonp'+this._s+'__'}});Faye.JSONPTransport.isUsable=function(a){return true};Faye.Transport.register('callback-polling',Faye.JSONPTransport);
1
+ if(!this.Faye)Faye={};Faye.extend=function(a,b,c){if(!b)return a;for(var d in b){if(!b.hasOwnProperty(d))continue;if(a.hasOwnProperty(d)&&c===false)continue;if(a[d]!==b[d])a[d]=b[d]}return a};Faye.extend(Faye,{VERSION:'0.3.2',BAYEUX_VERSION:'1.0',ID_LENGTH:128,JSONP_CALLBACK:'jsonpcallback',CONNECTION_TYPES:["long-polling","callback-polling"],ENV:this,random:function(a){a=a||this.ID_LENGTH;if(a>32){var b=Math.ceil(a/32),c='';while(b--)c+=this.random(32);return c}var d=Math.pow(2,a);return Math.floor(Math.random()*d).toString(16)},Grammar:{LOWALPHA:/^[a-z]$/,UPALPHA:/^[A-Z]$/,ALPHA:/^([a-z]|[A-Z])$/,DIGIT:/^[0-9]$/,ALPHANUM:/^(([a-z]|[A-Z])|[0-9])$/,MARK:/^(\-|\_|\!|\~|\(|\)|\$|\@)$/,STRING:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*$/,TOKEN:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+$/,INTEGER:/^([0-9])+$/,CHANNEL_SEGMENT:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+$/,CHANNEL_SEGMENTS:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+(\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+)*$/,CHANNEL_NAME:/^\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+(\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+)*$/,WILD_CARD:/^\*{1,2}$/,CHANNEL_PATTERN:/^(\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+)*\/\*{1,2}$/,VERSION_ELEMENT:/^(([a-z]|[A-Z])|[0-9])(((([a-z]|[A-Z])|[0-9])|\-|\_))*$/,VERSION:/^([0-9])+(\.(([a-z]|[A-Z])|[0-9])(((([a-z]|[A-Z])|[0-9])|\-|\_))*)*$/,CLIENT_ID:/^((([a-z]|[A-Z])|[0-9]))+$/,ID:/^((([a-z]|[A-Z])|[0-9]))+$/,ERROR_MESSAGE:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*$/,ERROR_ARGS:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*(,(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*)*$/,ERROR_CODE:/^[0-9][0-9][0-9]$/,ERROR:/^([0-9][0-9][0-9]:(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*(,(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*)*:(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*|[0-9][0-9][0-9]::(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*)$/},commonElement:function(a,b){for(var c=0,d=a.length;c<d;c++){if(this.indexOf(b,a[c])!==-1)return a[c]}return null},indexOf:function(a,b){for(var c=0,d=a.length;c<d;c++){if(a[c]===b)return c}return-1},each:function(a,b,c){if(a instanceof Array){for(var d=0,f=a.length;d<f;d++){if(a[d]!==undefined)b.call(c||null,a[d],d)}}else{for(var g in a){if(a.hasOwnProperty(g))b.call(c||null,g,a[g])}}},filter:function(a,b,c){var d=[];this.each(a,function(){if(b.apply(c,arguments))d.push(arguments[0])});return d},size:function(a){var b=0;this.each(a,function(){b+=1});return b},enumEqual:function(c,d){if(d instanceof Array){if(!(c instanceof Array))return false;var f=c.length;if(f!==d.length)return false;while(f--){if(c[f]!==d[f])return false}return true}else{if(!(c instanceof Object))return false;if(this.size(d)!==this.size(c))return false;var g=true;this.each(c,function(a,b){g=g&&(d[a]===b)});return g}},toJSON:function(a){if(this.stringify)return this.stringify(a,function(key,value){return(this[key]instanceof Array)?this[key]:value});return JSON.stringify(a)},timestamp:function(){var b=new Date(),c=b.getFullYear(),d=b.getMonth()+1,f=b.getDate(),g=b.getHours(),j=b.getMinutes(),i=b.getSeconds();var h=function(a){return a<10?'0'+a:String(a)};return h(c)+'-'+h(d)+'-'+h(f)+' '+h(g)+':'+h(j)+':'+h(i)}});Faye.Class=function(a,b){if(typeof a!=='function'){b=a;a=Object}var c=function(){if(!this.initialize)return this;return this.initialize.apply(this,arguments)||this};var d=function(){};d.prototype=a.prototype;c.prototype=new d();Faye.extend(c.prototype,b);return c};Faye.Deferrable={callback:function(a,b){if(this._w==='succeeded')return a.apply(b,this._o);this._a=this._a||[];this._a.push([a,b])},setDeferredStatus:function(){var b=Array.prototype.slice.call(arguments),c=b.shift();this._w=c;this._o=b;if(c!=='succeeded')return;if(!this._a)return;Faye.each(this._a,function(a){a[0].apply(a[1],this._o)},this);this._a=[]}};Faye.Observable={on:function(a,b,c){this._2=this._2||{};var d=this._2[a]=this._2[a]||[];d.push([b,c])},stopObserving:function(a,b,c){if(!this._2||!this._2[a])return;if(!b){delete this._2[a];return}var d=this._2[a],f=d.length;while(f--){if(b&&d[f][0]!==b)continue;if(c&&d[f][1]!==c)continue;d.splice(f,1)}},fire:function(){var b=Array.prototype.slice.call(arguments),c=b.shift();if(!this._2||!this._2[c])return;Faye.each(this._2[c],function(a){a[0].apply(a[1],b.slice())})}};Faye.Logging={LOG_LEVELS:{error:3,warn:2,info:1,debug:0},logLevel:'error',log:function(a,b){if(!Faye.logger)return;var c=Faye.Logging.LOG_LEVELS;if(c[Faye.Logging.logLevel]>c[b])return;var d='['+b.toUpperCase()+'] [Faye',f=null;for(var g in Faye){if(f)continue;if(typeof Faye[g]!=='function')continue;if(this instanceof Faye[g])f=g}if(f)d+='.'+f;d+='] ';Faye.logger(Faye.timestamp()+' '+d+a)},error:function(a){this.log(a,'error')},warn:function(a){this.log(a,'warn')},info:function(a){this.log(a,'info')},debug:function(a){this.log(a,'debug')}};Faye.Timeouts={addTimeout:function(a,b,c,d){this._6=this._6||{};if(this._6.hasOwnProperty(a))return;var f=this;this._6[a]=setTimeout(function(){delete f._6[a];c.call(d)},1000*b)},removeTimeout:function(a){this._6=this._6||{};var b=this._6[a];if(!b)return;clearTimeout(b);delete this._6[a]}};Faye.Channel=Faye.Class({initialize:function(a){this.__id=this.name=a},push:function(a){this.fire('message',a)}});Faye.extend(Faye.Channel.prototype,Faye.Observable);Faye.extend(Faye.Channel,{HANDSHAKE:'/meta/handshake',CONNECT:'/meta/connect',SUBSCRIBE:'/meta/subscribe',UNSUBSCRIBE:'/meta/unsubscribe',DISCONNECT:'/meta/disconnect',META:'meta',SERVICE:'service',isValid:function(a){return Faye.Grammar.CHANNEL_NAME.test(a)||Faye.Grammar.CHANNEL_PATTERN.test(a)},parse:function(a){if(!this.isValid(a))return null;return a.split('/').slice(1)},isMeta:function(a){var b=this.parse(a);return b?(b[0]===this.META):null},isService:function(a){var b=this.parse(a);return b?(b[0]===this.SERVICE):null},isSubscribable:function(a){if(!this.isValid(a))return null;return!this.isMeta(a)&&!this.isService(a)},Tree:Faye.Class({initialize:function(a){this._3=a;this._8={}},eachChild:function(c,d){Faye.each(this._8,function(a,b){c.call(d,a,b)})},each:function(c,d,f){this.eachChild(function(a,b){a=c.concat(a);b.each(a,d,f)});if(this._3!==undefined)d.call(f,c,this._3)},getKeys:function(){return this.map(function(a,b){return'/'+a.join('/')})},map:function(c,d){var f=[];this.each([],function(a,b){f.push(c.call(d,a,b))});return f},get:function(a){var b=this.traverse(a);return b?b._3:null},set:function(a,b){var c=this.traverse(a,true);if(c)c._3=b},traverse:function(a,b){if(typeof a==='string')a=Faye.Channel.parse(a);if(a===null)return null;if(a.length===0)return this;var c=this._8[a[0]];if(!c&&!b)return null;if(!c)c=this._8[a[0]]=new Faye.Channel.Tree();return c.traverse(a.slice(1),b)},findOrCreate:function(a){var b=this.get(a);if(b)return b;b=new Faye.Channel(a);this.set(a,b);return b},glob:function(f){if(typeof f==='string')f=Faye.Channel.parse(f);if(f===null)return[];if(f.length===0)return(this._3===undefined)?[]:[this._3];var g=[];if(Faye.enumEqual(f,['*'])){Faye.each(this._8,function(a,b){if(b._3!==undefined)g.push(b._3)});return g}if(Faye.enumEqual(f,['**'])){g=this.map(function(a,b){return b});if(this._3!==undefined)g.pop();return g}Faye.each(this._8,function(b,c){if(b!==f[0]&&b!=='*')return;var d=c.glob(f.slice(1));Faye.each(d,function(a){g.push(a)})});if(this._8['**'])g.push(this._8['**']._3);return g}})});Faye.Namespace=Faye.Class({initialize:function(){this._p={}},generate:function(){var a=Faye.random();while(this._p.hasOwnProperty(a))a=Faye.random();return this._p[a]=a}});Faye.Transport=Faye.extend(Faye.Class({initialize:function(a,b){this.debug('Created new transport for '+b);this._b=a;this._4=b},send:function(f,g,j){if(!(f instanceof Array)&&!f.id)f.id=this._b._q.generate();this.debug('Client '+this._b._0+' sending message to '+this._4+': '+Faye.toJSON(f));this.request(f,function(b){this.debug('Client '+this._b._0+' received from '+this._4+': '+Faye.toJSON(b));if(!g)return;var c=[],d=true;Faye.each([].concat(b),function(a){if(a.id===f.id){if(g.call(j,a)===false)d=false}if(a.advice)this._b.handleAdvice(a.advice);if(a.data&&a.channel)c.push(a)},this);if(d)this._b.deliverMessages(c)},this)}}),{get:function(c,d){var f=c._4;if(d===undefined)d=this.supportedConnectionTypes();var g=null;Faye.each(this._i,function(a,b){if(Faye.indexOf(d,a)<0)return;if(g)return;if(b.isUsable(f))g=b});if(!g)throw'Could not find a usable connection type for '+f;return new g(c,f)},register:function(a,b){this._i[a]=b;b.prototype.connectionType=a},_i:{},supportedConnectionTypes:function(){var c=[],d;Faye.each(this._i,function(a,b){c.push(a)});return c}});Faye.extend(Faye.Transport.prototype,Faye.Logging);Faye.Client=Faye.Class({UNCONNECTED:1,CONNECTING:2,CONNECTED:3,DISCONNECTED:4,HANDSHAKE:'handshake',RETRY:'retry',NONE:'none',CONNECTION_TIMEOUT:60.0,DEFAULT_ENDPOINT:'/bayeux',MAX_DELAY:0.1,INTERVAL:1000.0,initialize:function(a,b){this.info('New client created for '+a);this._4=a||this.DEFAULT_ENDPOINT;this._x=b||{};this._r=this._x.timeout||this.CONNECTION_TIMEOUT;this._7=Faye.Transport.get(this);this._1=this.UNCONNECTED;this._q=new Faye.Namespace();this._j=[];this._c=new Faye.Channel.Tree();this._s=[];this._9={reconnect:this.RETRY,interval:this.INTERVAL};if(!Faye.Event)return;Faye.Event.on(Faye.ENV,'beforeunload',this.disconnect,this)},handshake:function(b,c){if(this._9.reconnect===this.NONE)return;if(this._1!==this.UNCONNECTED)return;this._1=this.CONNECTING;var d=this;this.info('Initiating handshake with '+this._4);this._7.send({channel:Faye.Channel.HANDSHAKE,version:Faye.BAYEUX_VERSION,supportedConnectionTypes:Faye.Transport.supportedConnectionTypes()},function(a){if(!a.successful){this.info('Handshake unsuccessful');setTimeout(function(){d.handshake(b,c)},this._9.interval);return this._1=this.UNCONNECTED}this._1=this.CONNECTED;this._0=a.clientId;this._7=Faye.Transport.get(this,a.supportedConnectionTypes);this.info('Handshake successful: '+this._0);if(b)b.call(c)},this)},connect:function(b,c){if(this._9.reconnect===this.NONE)return;if(this._1===this.DISCONNECTED)return;if(this._9.reconnect===this.HANDSHAKE||this._1===this.UNCONNECTED){this._t();return this.handshake(function(){this.connect(b,c)},this)}if(this._1===this.CONNECTING)return this.callback(b,c);if(this._1!==this.CONNECTED)return;this.info('Calling deferred actions for '+this._0);this.setDeferredStatus('succeeded');this.setDeferredStatus('deferred');if(b)b.call(c);if(this._d)return;this._d=this._q.generate();var d=this;this.info('Initiating connection for '+this._0);this._7.send({channel:Faye.Channel.CONNECT,clientId:this._0,connectionType:this._7.connectionType,id:this._d},this._k(function(a){delete this._d;this.removeTimeout('reconnect');this.info('Closed connection for '+this._0);setTimeout(function(){d.connect()},this._9.interval)}));this._t()},disconnect:function(){if(this._1!==this.CONNECTED)return;this._1=this.DISCONNECTED;this.info('Disconnecting '+this._0);this._7.send({channel:Faye.Channel.DISCONNECT,clientId:this._0});this.info('Clearing channel listeners for '+this._0);this._c=new Faye.Channel.Tree()},subscribe:function(c,d,f){this.connect(function(){c=[].concat(c);this._l(c);this.info('Client '+this._0+' attempting to subscribe to ['+c.join(', ')+']');this._7.send({channel:Faye.Channel.SUBSCRIBE,clientId:this._0,subscription:c},this._k(function(b){if(!b.successful||!d)return;this.info('Subscription acknowledged for '+this._0+' to ['+c.join(', ')+']');c=[].concat(b.subscription);Faye.each(c,function(a){this._c.set(a,[d,f])},this)}))},this)},unsubscribe:function(c,d,f){this.connect(function(){c=[].concat(c);this._l(c);this.info('Client '+this._0+' attempting to unsubscribe from ['+c.join(', ')+']');this._7.send({channel:Faye.Channel.UNSUBSCRIBE,clientId:this._0,subscription:c},this._k(function(b){if(!b.successful)return;this.info('Unsubscription acknowledged for '+this._0+' from ['+c.join(', ')+']');c=[].concat(b.subscription);Faye.each(c,function(a){this._c.set(a,null)},this)}))},this)},publish:function(a,b){this.connect(function(){this._l([a]);this.info('Client '+this._0+' queueing published message to '+a+': '+Faye.toJSON(b));this._y({channel:a,data:b,clientId:this._0});this.addTimeout('publish',this.MAX_DELAY,this._z,this)},this)},handleAdvice:function(a){Faye.extend(this._9,a);if(this._9.reconnect===this.HANDSHAKE)this._0=null},deliverMessages:function(d){Faye.each(d,function(b){this.info('Client '+this._0+' calling listeners for '+b.channel+' with '+Faye.toJSON(b.data));var c=this._c.glob(b.channel);Faye.each(c,function(a){if(!a)return;a[0].call(a[1],b.data)})},this)},_t:function(){this.addTimeout('reconnect',this._r,function(){delete this._d;delete this._0;this._1=this.UNCONNECTED;this.info('Server took >'+this._r+'s to reply to connection for '+this._0+': attempting to reconnect');this.subscribe(this._c.getKeys())},this)},_y:function(a){this._j.push(a)},_z:function(){this._7.send(this._j);this._j=[]},_l:function(b){Faye.each(b,function(a){if(!Faye.Channel.isValid(a))throw'"'+a+'" is not a valid channel name';if(!Faye.Channel.isSubscribable(a))throw'Clients may not subscribe to channel "'+a+'"';})},_k:function(b){var c=this;return function(a){if(a.clientId!==c._0)return false;b.call(c,a);return true}}});Faye.extend(Faye.Client.prototype,Faye.Deferrable);Faye.extend(Faye.Client.prototype,Faye.Timeouts);Faye.extend(Faye.Client.prototype,Faye.Logging);Faye.Event={_e:[],on:function(a,b,c,d){var f=function(){c.call(d)};if(a.addEventListener)a.addEventListener(b,f,false);else a.attachEvent('on'+b,f);this._e.push({_f:a,_m:b,_A:c,_g:d,_u:f})},detach:function(a,b,c,d){var f=this._e.length,g;while(f--){g=this._e[f];if((a&&a!==g._f)||(b&&b!==g._m)||(c&&c!==g._A)||(d&&d!==g._g))continue;if(g._f.removeEventListener)g._f.removeEventListener(g._m,g._u,false);else g._f.detachEvent('on'+g._m,g._u);this._e.splice(f,1);g=null}}};Faye.Event.on(Faye.ENV,'unload',Faye.Event.detach,Faye.Event);Faye.URI=Faye.extend(Faye.Class({queryString:function(){var c=[],d;Faye.each(this.params,function(a,b){c.push(encodeURIComponent(a)+'='+encodeURIComponent(b))});return c.join('&')},isLocal:function(){var a=Faye.URI.parse(Faye.ENV.location.href);var b=(a.hostname!==this.hostname)||(a.port!==this.port)||(a.protocol!==this.protocol);return!b},toURL:function(){return this.protocol+this.hostname+':'+this.port+this.pathname+'?'+this.queryString()}}),{parse:function(d,f){if(typeof d!=='string')return d;var g=new this();var j=function(b,c){d=d.replace(c,function(a){if(a)g[b]=a;return''})};j('protocol',/^https?\:\/+/);j('hostname',/^[^\/\:]+/);j('port',/^:[0-9]+/);Faye.extend(g,{protocol:'http://',hostname:Faye.ENV.location.hostname,port:Faye.ENV.location.port},false);if(!g.port)g.port=(g.protocol==='https://')?'443':'80';g.port=g.port.replace(/\D/g,'');var i=d.split('?'),h=i.shift(),l=i.join('?'),n=l?l.split('&'):[],o=n.length,k={};while(o--){i=n[o].split('=');k[decodeURIComponent(i[0]||'')]=decodeURIComponent(i[1]||'')}if(typeof f==='object')Faye.extend(k,f);g.pathname=h;g.params=k;return g}});Faye.XHR={request:function(a,b,c,d,f){var g=new this.Request(a,b,c,d,f);g.send();return g},getXhrObject:function(){return Faye.ENV.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest()},Request:Faye.Class({initialize:function(a,b,c,d,f){this._h=a.toUpperCase();this._4=Faye.URI.parse(b,c);this._B=(typeof c==='string')?c:null;this._s=(typeof d==='function')?{success:d}:d;this._g=f||null;this._5=null},send:function(){if(this._n)return;var a=this._4.pathname,b=this._4.queryString();if(this._h==='GET')a+='?'+b;var c=(this._h==='POST')?(this._B||b):'';this._n=true;this._5=Faye.XHR.getXhrObject();this._5.open(this._h,a,true);if(this._h==='POST')this._5.setRequestHeader('Content-Type','application/json');var d=this,f=function(){if(d._5.readyState!==4)return;if(g){clearInterval(g);g=null}Faye.Event.detach(Faye.ENV,'beforeunload',d.abort,d);d._n=false;d._C();d=null};var g=setInterval(f,10);Faye.Event.on(Faye.ENV,'beforeunload',this.abort,this);this._5.send(c)},abort:function(){this._5.abort()},_C:function(){var a=this._s;if(!a)return;return this.success()?a.success&&a.success.call(this._g,this):a.failure&&a.failure.call(this._g,this)},waiting:function(){return!!this._n},complete:function(){return this._5&&!this.waiting()},success:function(){if(!this.complete())return false;var a=this._5.status;return(a>=200&&a<300)||a===304||a===1223},failure:function(){if(!this.complete())return false;return!this.success()},text:function(){if(!this.complete())return null;return this._5.responseText},status:function(){if(!this.complete())return null;return this._5.status}})};if(!this.JSON){JSON={}}(function(){function l(a){return a<10?'0'+a:a}if(typeof Date.prototype.toJSON!=='function'){Date.prototype.toJSON=function(a){return this.getUTCFullYear()+'-'+l(this.getUTCMonth()+1)+'-'+l(this.getUTCDate())+'T'+l(this.getUTCHours())+':'+l(this.getUTCMinutes())+':'+l(this.getUTCSeconds())+'Z'};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(a){return this.valueOf()}}var n=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,o=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,k,p,s={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'},m;function r(c){o.lastIndex=0;return o.test(c)?'"'+c.replace(o,function(a){var b=s[a];return typeof b==='string'?b:'\\u'+('0000'+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+c+'"'}function q(a,b){var c,d,f,g,j=k,i,h=b[a];if(h&&typeof h==='object'&&typeof h.toJSON==='function'){h=h.toJSON(a)}if(typeof m==='function'){h=m.call(b,a,h)}switch(typeof h){case'string':return r(h);case'number':return isFinite(h)?String(h):'null';case'boolean':case'null':return String(h);case'object':if(!h){return'null'}k+=p;i=[];if(Object.prototype.toString.apply(h)==='[object Array]'){g=h.length;for(c=0;c<g;c+=1){i[c]=q(c,h)||'null'}f=i.length===0?'[]':k?'[\n'+k+i.join(',\n'+k)+'\n'+j+']':'['+i.join(',')+']';k=j;return f}if(m&&typeof m==='object'){g=m.length;for(c=0;c<g;c+=1){d=m[c];if(typeof d==='string'){f=q(d,h);if(f){i.push(r(d)+(k?': ':':')+f)}}}}else{for(d in h){if(Object.hasOwnProperty.call(h,d)){f=q(d,h);if(f){i.push(r(d)+(k?': ':':')+f)}}}}f=i.length===0?'{}':k?'{\n'+k+i.join(',\n'+k)+'\n'+j+'}':'{'+i.join(',')+'}';k=j;return f}}Faye.stringify=function(a,b,c){var d;k='';p='';if(typeof c==='number'){for(d=0;d<c;d+=1){p+=' '}}else if(typeof c==='string'){p=c}m=b;if(b&&typeof b!=='function'&&(typeof b!=='object'||typeof b.length!=='number')){throw new Error('JSON.stringify');}return q('',{'':a})};if(typeof JSON.stringify!=='function'){JSON.stringify=Faye.stringify}if(typeof JSON.parse!=='function'){JSON.parse=function(g,j){var i;function h(a,b){var c,d,f=a[b];if(f&&typeof f==='object'){for(c in f){if(Object.hasOwnProperty.call(f,c)){d=h(f,c);if(d!==undefined){f[c]=d}else{delete f[c]}}}}return j.call(a,b,f)}n.lastIndex=0;if(n.test(g)){g=g.replace(n,function(a){return'\\u'+('0000'+a.charCodeAt(0).toString(16)).slice(-4)})}if(/^[\],:{}\s]*$/.test(g.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,'@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']').replace(/(?:^|:|,)(?:\s*\[)+/g,''))){i=eval('('+g+')');return typeof j==='function'?h({'':i},''):i}throw new SyntaxError('JSON.parse');}}}());Faye.XHRTransport=Faye.Class(Faye.Transport,{request:function(b,c,d){Faye.XHR.request('post',this._4,Faye.toJSON(b),function(a){if(c)c.call(d,JSON.parse(a.text()))})}});Faye.XHRTransport.isUsable=function(a){return Faye.URI.parse(a).isLocal()};Faye.Transport.register('long-polling',Faye.XHRTransport);Faye.JSONPTransport=Faye.extend(Faye.Class(Faye.Transport,{request:function(b,c,d){var f={message:Faye.toJSON(b)},g=document.getElementsByTagName('head')[0],j=document.createElement('script'),i=Faye.JSONPTransport.getCallbackName(),h=Faye.URI.parse(this._4,f);Faye.ENV[i]=function(a){Faye.ENV[i]=undefined;try{delete Faye.ENV[i]}catch(e){}g.removeChild(j);if(c)c.call(d,a)};h.params.jsonp=i;j.type='text/javascript';j.src=h.toURL();g.appendChild(j)}}),{_v:0,getCallbackName:function(){this._v+=1;return'__jsonp'+this._v+'__'}});Faye.JSONPTransport.isUsable=function(a){return true};Faye.Transport.register('callback-polling',Faye.JSONPTransport);
@@ -5,7 +5,7 @@ require 'rubygems'
5
5
  require 'eventmachine'
6
6
 
7
7
  module Faye
8
- VERSION = '0.3.1'
8
+ VERSION = '0.3.2'
9
9
 
10
10
  ROOT = File.expand_path(File.dirname(__FILE__))
11
11
 
@@ -14,7 +14,10 @@ module Faye
14
14
  JSONP_CALLBACK = 'jsonpcallback'
15
15
  CONNECTION_TYPES = %w[long-polling callback-polling]
16
16
 
17
- %w[grammar namespace server channel connection error client transport].each do |lib|
17
+ %w[ timeouts grammar namespace
18
+ server channel connection
19
+ error client transport
20
+ ].each do |lib|
18
21
  require File.join(ROOT, 'faye', lib)
19
22
  end
20
23
 
@@ -67,6 +67,10 @@ module Faye
67
67
  yield(prefix, @value) unless @value.nil?
68
68
  end
69
69
 
70
+ def keys
71
+ map { |key, value| '/' + key * '/' }
72
+ end
73
+
70
74
  def [](name)
71
75
  subtree = traverse(name)
72
76
  subtree ? subtree.value : nil
@@ -1,23 +1,26 @@
1
1
  module Faye
2
2
  class Client
3
3
  include EventMachine::Deferrable
4
+ include Timeouts
4
5
 
5
- extend Forwardable
6
- def_delegators :EventMachine, :add_timer, :cancel_timer
6
+ UNCONNECTED = 1
7
+ CONNECTING = 2
8
+ CONNECTED = 3
9
+ DISCONNECTED = 4
7
10
 
8
- UNCONNECTED = 1
9
- CONNECTING = 2
10
- CONNECTED = 3
11
- DISCONNECTED = 4
11
+ HANDSHAKE = 'handshake'
12
+ RETRY = 'retry'
13
+ NONE = 'none'
12
14
 
13
- HANDSHAKE = 'handshake'
14
- RETRY = 'retry'
15
- NONE = 'none'
15
+ CONNECTION_TIMEOUT = 60.0
16
16
 
17
17
  attr_reader :endpoint, :namespace
18
18
 
19
- def initialize(endpoint = nil)
20
- @endpoint = endpoint || RackAdapter::DEFAULT_ENDPOINT
19
+ def initialize(endpoint = nil, options = {})
20
+ @endpoint = endpoint || RackAdapter::DEFAULT_ENDPOINT
21
+ @options = options
22
+ @timeout = @options[:timeout] || CONNECTION_TIMEOUT
23
+
21
24
  @transport = Transport.get(self)
22
25
  @state = UNCONNECTED
23
26
  @namespace = Namespace.new
@@ -60,7 +63,7 @@ module Faye
60
63
  }) do |response|
61
64
 
62
65
  unless response['successful']
63
- add_timer(@advice['interval'] / 1000.0) { handshake(&block) }
66
+ EventMachine.add_timer(@advice['interval'] / 1000.0) { handshake(&block) }
64
67
  return @state = UNCONNECTED
65
68
  end
66
69
 
@@ -86,6 +89,7 @@ module Faye
86
89
  @state == DISCONNECTED
87
90
 
88
91
  if @advice['reconnect'] == HANDSHAKE or @state == UNCONNECTED
92
+ begin_reconnect_timeout
89
93
  return handshake { connect(&block) }
90
94
  end
91
95
 
@@ -105,10 +109,13 @@ module Faye
105
109
  'connectionType' => @transport.connection_type,
106
110
  'id' => @connection_id
107
111
 
108
- }) do |response|
112
+ }, &verify_client_id { |response|
109
113
  @connection_id = nil
110
- add_timer(@advice['interval'] / 1000.0) { connect }
111
- end
114
+ remove_timeout(:reconnect)
115
+ EventMachine.add_timer(@advice['interval'] / 1000.0) { connect }
116
+ })
117
+
118
+ begin_reconnect_timeout
112
119
  end
113
120
 
114
121
  # Request Response
@@ -150,12 +157,12 @@ module Faye
150
157
  'clientId' => @client_id,
151
158
  'subscription' => channels
152
159
 
153
- }) do |response|
154
- if response['successful']
160
+ }, &verify_client_id { |response|
161
+ if response['successful'] and block
155
162
  channels = [response['subscription']].flatten
156
163
  channels.each { |channel| @channels[channel] = block }
157
164
  end
158
- end
165
+ })
159
166
  }
160
167
  end
161
168
 
@@ -179,12 +186,12 @@ module Faye
179
186
  'clientId' => @client_id,
180
187
  'subscription' => channels
181
188
 
182
- }) do |response|
189
+ }, &verify_client_id { |response|
183
190
  if response['successful']
184
191
  channels = [response['subscription']].flatten
185
192
  channels.each { |channel| @channels[channel] = nil }
186
193
  end
187
- end
194
+ })
188
195
  }
189
196
  end
190
197
 
@@ -204,12 +211,7 @@ module Faye
204
211
  'clientId' => @client_id
205
212
  })
206
213
 
207
- return if @timeout
208
-
209
- @timeout = add_timer(Connection::MAX_DELAY) do
210
- @timeout = nil
211
- flush!
212
- end
214
+ add_timeout(:publish, Connection::MAX_DELAY) { flush! }
213
215
  }
214
216
  end
215
217
 
@@ -218,13 +220,24 @@ module Faye
218
220
  @client_id = nil if @advice['reconnect'] == HANDSHAKE
219
221
  end
220
222
 
221
- def send_to_subscribers(message)
222
- channels = @channels.glob(message['channel'])
223
- channels.each { |callback| callback.call(message['data']) }
223
+ def deliver_messages(messages)
224
+ messages.each do |message|
225
+ channels = @channels.glob(message['channel'])
226
+ channels.each { |callback| callback.call(message['data']) }
227
+ end
224
228
  end
225
229
 
226
230
  private
227
231
 
232
+ def begin_reconnect_timeout
233
+ add_timeout(:reconnect, @timeout) do
234
+ @connection_id = nil
235
+ @client_id = nil
236
+ @state = UNCONNECTED
237
+ subscribe(@channels.keys)
238
+ end
239
+ end
240
+
228
241
  def enqueue(message)
229
242
  @outbox << message
230
243
  end
@@ -241,6 +254,17 @@ module Faye
241
254
  end
242
255
  end
243
256
 
257
+ def verify_client_id(&block)
258
+ lambda do |response|
259
+ if response['clientId'] != @client_id
260
+ false
261
+ else
262
+ block.call(response)
263
+ true
264
+ end
265
+ end
266
+ end
267
+
244
268
  end
245
269
  end
246
270
 
@@ -2,9 +2,7 @@ module Faye
2
2
  class Connection
3
3
  include EventMachine::Deferrable
4
4
  include Observable
5
-
6
- extend Forwardable
7
- def_delegators :EventMachine, :add_timer, :cancel_timer
5
+ include Timeouts
8
6
 
9
7
  MAX_DELAY = 0.1
10
8
  INTERVAL = 1.0
@@ -13,20 +11,18 @@ module Faye
13
11
  attr_reader :id
14
12
 
15
13
  def initialize(id, options = {})
16
- @id = id
17
- @options = options
18
- @channels = Set.new
19
- @inbox = Set.new
20
- end
21
-
22
- def timeout
23
- @options[:timeout] || TIMEOUT
14
+ @id = id
15
+ @options = options
16
+ @timeout = @options[:timeout] || TIMEOUT
17
+ @channels = Set.new
18
+ @inbox = Set.new
19
+ @connected = false
24
20
  end
25
21
 
26
22
  def update(message, event)
27
23
  return unless message == :message
28
24
  @inbox.add(event)
29
- begin_delivery_timeout! if @connected
25
+ begin_delivery_timeout!
30
26
  end
31
27
 
32
28
  def subscribe(channel)
@@ -45,11 +41,7 @@ module Faye
45
41
  return if @connected
46
42
 
47
43
  @connected = true
48
-
49
- if @deletion_timeout
50
- cancel_timer(@deletion_timeout)
51
- @deletion_timeout = nil
52
- end
44
+ remove_timeout(:deletion)
53
45
 
54
46
  begin_delivery_timeout!
55
47
  begin_connection_timeout!
@@ -74,34 +66,21 @@ module Faye
74
66
  private
75
67
 
76
68
  def begin_delivery_timeout!
77
- return unless @delivery_timeout.nil? and @connected and not @inbox.empty?
78
- @delivery_timeout = add_timer(MAX_DELAY) { flush! }
69
+ return unless @connected and not @inbox.empty?
70
+ add_timeout(:delivery, MAX_DELAY) { flush! }
79
71
  end
80
72
 
81
73
  def begin_connection_timeout!
82
- return unless @connection_timeout.nil? and @connected
83
- @connection_timeout = add_timer(timeout) { flush! }
74
+ return unless @connected
75
+ add_timeout(:connection, @timeout) { flush! }
84
76
  end
85
77
 
86
78
  def release_connection!
87
- if @connection_timeout
88
- cancel_timer(@connection_timeout)
89
- @connection_timeout = nil
90
- end
91
-
92
- if @delivery_timeout
93
- cancel_timer(@delivery_timeout)
94
- @delivery_timeout = nil
95
- end
96
-
79
+ remove_timeout(:connection)
80
+ remove_timeout(:delivery)
97
81
  @connected = false
98
- schedule_for_deletion!
99
- end
100
-
101
- def schedule_for_deletion!
102
- return if @deletion_timeout
103
82
 
104
- @deletion_timeout = add_timer(10 * INTERVAL) do
83
+ add_timeout(:deletion, 10 * INTERVAL) do
105
84
  changed(true)
106
85
  notify_observers(:stale_client, self)
107
86
  end
@@ -1,5 +1,6 @@
1
1
  require 'rubygems'
2
2
  require 'rack'
3
+ require 'thin'
3
4
  require 'json'
4
5
 
5
6
  module Faye
@@ -11,7 +12,7 @@ module Faye
11
12
  DEFAULT_ENDPOINT = '/bayeux'
12
13
  SCRIPT_PATH = File.join(ROOT, 'faye-client-min.js')
13
14
 
14
- TYPE_JSON = {'Content-Type' => 'text/json'}
15
+ TYPE_JSON = {'Content-Type' => 'application/json'}
15
16
  TYPE_SCRIPT = {'Content-Type' => 'text/javascript'}
16
17
  TYPE_TEXT = {'Content-Type' => 'text/plain'}
17
18
 
@@ -19,9 +20,9 @@ module Faye
19
20
  @app = app if app.respond_to?(:call)
20
21
  @options = [app, options].grep(Hash).first || {}
21
22
 
22
- @endpoint = @options[:mount] || DEFAULT_ENDPOINT
23
- @script = @endpoint + '.js'
24
- @server = Server.new(@options)
23
+ @endpoint = @options[:mount] || DEFAULT_ENDPOINT
24
+ @endpoint_re = Regexp.new('^' + @endpoint + '(/[^/]+)*(\\.js)?$')
25
+ @server = Server.new(@options)
25
26
  end
26
27
 
27
28
  def get_client
@@ -34,32 +35,33 @@ module Faye
34
35
  end
35
36
 
36
37
  def call(env)
38
+ ensure_reactor_running!
37
39
  request = Rack::Request.new(env)
38
- case request.path_info
39
40
 
40
- when @endpoint then
41
- begin
42
- message = JSON.parse(request.params['message'])
43
- jsonp = request.params['jsonp'] || JSONP_CALLBACK
44
-
45
- @server.flush_connection(message) if request.get?
46
-
47
- on_response(env, message) do |replies|
48
- response = JSON.unparse(replies)
49
- response = "#{ jsonp }(#{ response });" if request.get?
50
- response
51
- end
52
- rescue
53
- [400, TYPE_TEXT, 'Bad request']
54
- end
41
+ unless request.path_info =~ @endpoint_re
42
+ env['faye.client'] = get_client
43
+ return @app ? @app.call(env) :
44
+ [404, TYPE_TEXT, ["Sure you're not looking for #{@endpoint} ?"]]
45
+ end
55
46
 
56
- when @script then
57
- [200, TYPE_SCRIPT, File.new(SCRIPT_PATH)]
47
+ if request.path_info =~ /\.js$/
48
+ return [200, TYPE_SCRIPT, File.new(SCRIPT_PATH)]
49
+ end
58
50
 
59
- else
60
- env['faye.client'] = get_client
61
- @app ? @app.call(env) :
62
- [404, TYPE_TEXT, ["Sure you're not looking for #{@endpoint} ?"]]
51
+ begin
52
+ json_msg = request.post? ? request.body.read : request.params['message']
53
+ message = JSON.parse(json_msg)
54
+ jsonp = request.params['jsonp'] || JSONP_CALLBACK
55
+
56
+ @server.flush_connection(message) if request.get?
57
+
58
+ on_response(env, message) do |replies|
59
+ response = JSON.unparse(replies)
60
+ response = "#{ jsonp }(#{ response });" if request.get?
61
+ response
62
+ end
63
+ rescue
64
+ [400, TYPE_TEXT, 'Bad request']
63
65
  end
64
66
  end
65
67
 
@@ -70,8 +72,6 @@ module Faye
70
72
  type = request.get? ? TYPE_SCRIPT : TYPE_JSON
71
73
  callback = env['async.callback']
72
74
 
73
- EM.run unless EM.reactor_running?
74
-
75
75
  if callback
76
76
  body = DeferredBody.new
77
77
  callback.call [200, type, body]
@@ -85,6 +85,11 @@ module Faye
85
85
  [200, type, [response]]
86
86
  end
87
87
 
88
+ def ensure_reactor_running!
89
+ Thread.new { EM.run } unless EM.reactor_running?
90
+ while not EM.reactor_running?; end
91
+ end
92
+
88
93
  class DeferredBody
89
94
  include EventMachine::Deferrable
90
95
  alias :each :callback
@@ -54,20 +54,16 @@ module Faye
54
54
  end
55
55
 
56
56
  def handle(message, local = false, &callback)
57
- client_id = message['clientId']
58
- channel = message['channel']
59
-
57
+ channel = message['channel']
60
58
  @channels.glob(channel).each { |c| c << message }
61
59
 
62
60
  if Channel.meta?(channel)
63
61
  response = __send__(Channel.parse(channel)[1], message, local)
64
62
 
65
- client_id ||= response['clientId']
63
+ client_id = response['clientId']
66
64
  response['advice'] ||= {}
67
65
  response['advice']['reconnect'] ||= @clients.has_key?(client_id) ? 'retry' : 'handshake'
68
- response['advice']['interval'] ||= Connection::INTERVAL * 1000
69
-
70
- response['id'] = message['id']
66
+ response['advice']['interval'] ||= (Connection::INTERVAL * 1000).floor
71
67
 
72
68
  return callback[response] unless response['channel'] == Channel::CONNECT and
73
69
  response['successful'] == true
@@ -79,9 +75,19 @@ module Faye
79
75
 
80
76
  return callback[[]] if message['clientId'].nil? or Channel.service?(channel)
81
77
 
82
- callback[ { 'channel' => channel,
83
- 'successful' => true,
84
- 'id' => message['id'] } ]
78
+ response = make_response(message)
79
+ response['successful'] = true
80
+ callback[response]
81
+ end
82
+
83
+ def make_response(message)
84
+ response = {}
85
+ %w[id clientId channel].each do |field|
86
+ if message[field]
87
+ response[field] = message[field]
88
+ end
89
+ end
90
+ response
85
91
  end
86
92
 
87
93
  # MUST contain * version
@@ -90,9 +96,8 @@ module Faye
90
96
  # * ext
91
97
  # * id
92
98
  def handshake(message, local = false)
93
- response = { 'channel' => Channel::HANDSHAKE,
94
- 'version' => BAYEUX_VERSION,
95
- 'id' => message['id'] }
99
+ response = make_response(message)
100
+ response['version'] = BAYEUX_VERSION
96
101
 
97
102
  response['error'] = Error.parameter_missing('version') if message['version'].nil?
98
103
 
@@ -121,8 +126,7 @@ module Faye
121
126
  # MAY contain * ext
122
127
  # * id
123
128
  def connect(message, local = false)
124
- response = { 'channel' => Channel::CONNECT,
125
- 'id' => message['id'] }
129
+ response = make_response(message)
126
130
 
127
131
  client_id = message['clientId']
128
132
  client = client_id ? @clients[client_id] : nil
@@ -132,6 +136,7 @@ module Faye
132
136
  response['error'] = Error.parameter_missing('connectionType') if message['connectionType'].nil?
133
137
 
134
138
  response['successful'] = response['error'].nil?
139
+ response.delete('clientId') unless response['successful']
135
140
  return response unless response['successful']
136
141
 
137
142
  response['clientId'] = client.id
@@ -142,8 +147,7 @@ module Faye
142
147
  # MAY contain * ext
143
148
  # * id
144
149
  def disconnect(message, local = false)
145
- response = { 'channel' => Channel::DISCONNECT,
146
- 'id' => message['id'] }
150
+ response = make_response(message)
147
151
 
148
152
  client_id = message['clientId']
149
153
  client = client_id ? @clients[client_id] : nil
@@ -152,6 +156,7 @@ module Faye
152
156
  response['error'] = Error.parameter_missing('clientId') if client_id.nil?
153
157
 
154
158
  response['successful'] = response['error'].nil?
159
+ response.delete('clientId') unless response['successful']
155
160
  return response unless response['successful']
156
161
 
157
162
  destroy_client(client)
@@ -165,9 +170,7 @@ module Faye
165
170
  # MAY contain * ext
166
171
  # * id
167
172
  def subscribe(message, local = false)
168
- response = { 'channel' => Channel::SUBSCRIBE,
169
- 'clientId' => message['clientId'],
170
- 'id' => message['id'] }
173
+ response = make_response(message)
171
174
 
172
175
  client_id = message['clientId']
173
176
  client = client_id ? @clients[client_id] : nil
@@ -200,9 +203,7 @@ module Faye
200
203
  # MAY contain * ext
201
204
  # * id
202
205
  def unsubscribe(message, local = false)
203
- response = { 'channel' => Channel::UNSUBSCRIBE,
204
- 'clientId' => message['clientId'],
205
- 'id' => message['id'] }
206
+ response = make_response(message)
206
207
 
207
208
  client_id = message['clientId']
208
209
  client = client_id ? @clients[client_id] : nil