/* 

self-served copy...

*/


self.addEventListener = self.addEventListener || function(name,meth,bub){ window.attachEvent("on"+name, meth, true); };
if(location.protocol!="data:" && !self.sessionStorage){  self.sessionStorage={}; }


(function zapitup(self){ // zap.js v1.1, by widgets inc. (c)2011-2014   Orig: 23,999	  Min'd: 15,784 
 "use strict";
	var myDef= ("\v"!="v" ) ? Object.defineProperty : function(ob, prop, def){ ob[prop] = def.value || def.get();  }; 


	var DEFAULTS={ // config options. These appear as static properties on Zap. Over-ride before calling Zap() to customize behavior.
		url:		"http://api.zapjs.com/",	// don't change this
		instances: 	Zap.instances || [],		// allows "shutdown" of all connections if needed
		maxGET:		Zap.maxGET || 30000,		// maximum number of chars in a GET request
		httpResetDelay: Zap.httpResetDelay || 15,	// how long to wait between messages in long-polling (legacy) mode
		autoConnect:	true,			// connect as soon as a new instance is spawned?
		autoResume:	false,				// attempt to fetch messages that were sent before connecting?
		retryCounter:	125,				// how many time to attempt re-connection after getting disconnected?
		retryDelay:	3500,				// how long to wait (in ms) between each re-connection attempt?
		notificationDuration:	3200,	// how long to show (in ms) desktop and html-based notification for ? (if not specified)
		debug:		false,				// show extra console activity to assist debugging?
		blnRemoteEvents:  false,		// if enabled, you can bind to native DOM events on other devices in your channel by uid. 
								// this option is disabled by default for security, don't use it in public non-authenticated enviroments.
								// on private channels or with white-liste UIDs, it can be incredibly powerful.
								// ex: bind the clicking of a button on phone A to a event hander on phone B, setup from the phone B.

		transports:	{				// which transport mechanisms should be enlisted (if on device)?
			socket: true,				// websockets for most recent browsers
			eventsource: true,			// server-sent DOM events for older iOS and Opera 10+11
			ajax2: true,				// XMLHttpRequest long-poll for IE8/9
			frame: ("\v"!="v" ),			// forever frame (comet) transport for old-school support
			jsonp: true				// script-tag transport for old-school support
		}
	};

	// publish Zap to the scope provided:
	self.Zap = Zap;	

	// setup static class properties right away to use with global config and shortcuts:
	Zap.url = "http://api.zapjs.com/"; // "http://50.116.36.123/"; // "{ZAPURL}";
	Zap.instances = Zap.instances || [];
	Zap.Events = Events;
	if(location.protocol!="data:"){ Zap.lastEvent = +sessionStorage.zapLastEvent || 0; }else{ Zap.lastEvent = 0; }
	Zap.getServerTime=function(){return new Date(Date.now() - (Zap.serverOffset||0) )};

	



// provides most possible ES5 and 6 methods. updated 2013-10-32. dandavis. [CCBY2]
(function() { // native method patcher
	var O=Object;

	// legacy-safe Object.defineProperty, for setting 'hidden' properties:
	function odp(ob, prop, val){
		if(ob[prop]) return odp;		
		if(O.defineProperty && "v"!=="\v"){
			O.defineProperty(ob, prop, {value:val});
		}else{
			ob[prop]=val;
		}
	  return odp;
	}	

	function contains(value) {return this.indexOf(value) !== -1; }

	var B = "length",
		C = "slice",
		D = "call",
		F = "replace",
		P="prototype", 
		SP=String[P], 
		AP=Array[P];

odp
(Function.prototype,	"bind", 	function (oThis) {
    var aArgs = Array.prototype.slice.call(arguments, 1), 
        fToBind = this;
		return function bound(){  
		    var lateArgs=Array.prototype.slice.call(arguments, 0);
		    return fToBind.apply( 
				oThis, 
				aArgs.concat(lateArgs)
			);  
		};
})

(O ,	"keys",		function(obj){var o=[],k;for(k in obj)has(obj,k)&&o.push(k);return o;})
(O , 	"is",    	function (a,b){return isNaN(a)&&isNaN(b)?!0:a===b})
(O,		"create",	(function(){function a(){}return function(b){a.prototype=b;return new a}})())
(O,		"isnt",  	function(v1,v2){return !Object.is(v1,v2);})
(O,		"getPrototypeOf",	function(o){return o.__proto__ || o.constructor.prototype;})
(O,		"getOwnPropertyNames",	O.keys )
(O,		"getPropertyNames", function(a){var b=[];do b.push.apply(b,Object.getOwnPropertyNames(a)),a=Object.getPrototypeOf(a);while(a);a={};for(var c=0,d=b.length;c<d;c++)a[b[c]]=1;return Object.keys(a)})	  

(SP,	"repeat",	function(n){return Array(n+1).join(this);})
(SP, 	"trim",     function trim(){return this[F](/^\s+|\s+$/g,"")})
(SP, 	"trimLeft",	function(){return this[F](/^\s+/,"")})
(SP, 	"trimRight",function(){return this[F](/\s+$/,"")})
(SP,	"endsWith",	function(s){return this.lastIndexOf(s)+s.length===this.length;})
(SP,	"startsWith",function(s){return this.indexOf(s)===0;})
(SP, 	"contains",	contains)

(AP, 	"forEach",	function (c,e){this[C]().map(c,e)})
(AP, 	"map",		function (k,e){for(var a=this[C](),d=a[B],b=0,c=[];b<d;b++)b in a&&(c[b]=k[D](e,a[b],b,a));return c})
(AP, 	"filter", 	function (k,e){for(var a=this[C](),d=a[B],b=0,c=[],f=0;b<d;b++)b in a&&k[D](e,a[b],b,a)&&(c[f++]=a[b]);return c})
(AP, 	"every",  	function (c,e){var a=this[C](),d=a[B];return d&&a.filter(c,e)[B]==d})
(AP, 	"some",   	function (c,e){for(var me=this.slice(),d=me[B],b=1;d--;)if(d in me&&c[D](e,me[d],d,me)&&!--b)return!0;return!1})
(AP, 	"indexOf",	function (c,e){for(var a=this[C](),d=a[B],b=e||0;b<d;b++)if(b in a&&a[b]===c)return b;return-1})
(AP, 	"reduce", 	function (c,e){for(var a=this[C](),d=a[B],b=0,f=e||a[b++];b<d;b++)f=c[D](null,f,a[b],b,a);return f})
(AP, 	"reduceRight",function (c,e){for(var a=this[C](),d=a[B]-1,b=e||a[d--];-1<d;d--)b=c[D](null,b,a[d],d,a);return b})
(AP, 	"find",		function(d,e){for(var b=this.slice(),f=b.length,a=0,c;a<f;a++)if(a in b&&(c=d.call(e,b[a],a,b)))return c;return!1})
(AP, 	"findIndex",function(d,e){for(var b=this.slice(),f=b.length,a=0,c;a<f;a++)if(a in b&&d.call(e,b[a],a,b))return a;return -1})
(AP, 	"contains",	contains)
(AP, 	"fill",		function(value){
  var a=arguments,M=Math,max=M.max,min=M.min,o=Object(this),l=max(o.length,0),s=+a[1]||0,e=a.length==3?a[2] : l;
   if(s<0){ s=max(l+s, 0); }else{ s=min(l, s);  }
   if(e<0){ e=max(l+e, 0); }else{ e=min(l, e);  }
   while( s < e ){ o[s++]=value; }
 return o;
})


(Array, "isArray",	function(a){ return ({}).toString.call(a)==="[object Array]"})
(Array, "of",	function(){return Array.from(arguments);})
(Array, "from",	eval.call.bind([].slice))

(Date,	"now",  	function now() {return +new Date();})

;

}()); // end native method patcher

	
	
	
	
	
	
	
	
	
	
	
	
	
	

	var has=Function.call.bind(({}).hasOwnProperty);


	function Zap(strURL) {
	
			
		Events.call(this);

		//var zi=Zap.instances[Zap.instances.length-1];
		//if(zi && zi.chan == )
		Zap.instances.push(this);


		if (!strURL.match(/^http/im)) {
			strURL = Zap.url + strURL + "/";
		} // enforce an http starting for the server
		if (strURL.slice(-1) !== "?") {
			strURL += "?";
		} // enforce a querystring ending for the server


		// internal state:
		var DATA = {}, 			// a private store of data used for .set() and .get() functionality.
		chan = unescape(strURL.split("?")[0].split("/").filter(String).slice(-1)[0]).trim(),
			base = unescape(strURL.split("?")[0]).split(chan)[0].trim(),
			isConnected = false, 	// a private state indicator
			ev = this,		// the eventual return; the "instance"
			bundle = {		// recycled-send object (reduced garbage collection pattern)
				chan: chan,
				type: "message",
				data: null
			}, 	// end default bundle
			emit=ev.emit.bind(ev);	// a copy of emit for private use

		this.readyState = -1;		// the network connection state tracker


		Zap.instances.push(ev);
		this._data = DATA;

		// define read-only properties on instance:
		define(this, "chan", chan); 	// channel id
		define(this, "_log", [{
			id: Date.now(),		// log boot time
			data: {			// holds all messages
				data: "booted"
			}
		}]); // an array of log events
		define(this, "URL", strURL); // event server URL
		define(this, "sendOnChannel", _sendOnChannel);

		// patch IE6 to survive feature detection routine:
		self.XMLHttpRequest = self.XMLHttpRequest || String;

		var ua = navigator.userAgent,			
			// black-list known old versions of safari and opera that had buggy websocket implementations (feature-detection lies about this capability!):
			badSocket = ua.match(/CPU OS \(?[543]_\d like Mac OS X/) || ua.match(/Version\/[45]\.[\d\.]+[\w\W]+Safari/) || ua.match(/((Presto)|(Opera))[\w\W]+1[120]\./);


			this.findSource=function _findSource(){
				
				// find/assign the best usable event reconnect to be used for IO:
				ev.reconnect = (function _findBestSource() {

				if (Zap.transports.socket && self.WebSocket && !badSocket) {
					return socketSourcer;
				} // end if WebSockets enabled and available ?
			
				if (Zap.transports.eventsource && self.EventSource) {
					return eventSourcer;
				} // end if EventSource enabled and available ?
			
				if (Zap.transports.ajax2 ){  // && has(new XMLHttpRequest(), "withCredentials")) {
					return ajaxSourcer;
				} // end if http1.1 XHR long-polling enabled and available ?

				if (Zap.transports.frame) {
					return frameSourcer;
				} // end if forever frame enabled ?

		
				if (Zap.transports.jsonp) {
					return JSONpSourcer;
				} // end if JSON enabled ? (it's always available)
			
				throw new Error("No Valid Transports Found, enable more options on window.Zap.transports, and try again.");

			}());// end reconnect finder
		


			//if auto-resume, do that before auto-connecting to make sure messages land in order
			if (Zap.autoResume){
				setTimeout(function(){
					ev.resume( function(){
						if(Zap.autoConnect !== false){ setTimeout(ev.reconnect, Zap.httpResetDelay || 0); }
					});
				}, 40);
				console.log("setting timer to resume");
				 if( ev.readyState!==1 ){ ev.reconnect(); }
				 setTimeout(function(){  if( ev.readyState==1 ){ev.resume();}}, 333 );
			};

		};//end this.findSource();
		
		this.findSource();


		// wait the delay to establish a connection to ensure all the event handlers are bound by the time it opens(): 
		if (!Zap.autoResume && Zap.autoConnect !== false){ setTimeout(ev.reconnect, Zap.httpResetDelay || 0); }


	if(location.protocol!="data:"){
		this.uid = sessionStorage.ZapId || (sessionStorage.ZapId = Math.random().toString(36).replace(/\W/g, ""));
	}else{
		this.uid = Math.random().toString(36).replace(/\W/g, "");
	}


		var zap_api = { // high-level events that ride on top of low-level transports like events source or poll ajax:


			"events": { // "special" events:


				"_open": {
					// "eventTitle": "the client has connected to the channel server",
					"name": "open",
					"fn": function _open(e) {
						this.emit("open", {
							chan: chan,
							type: "open",
							id: Date.now(),
							url: strURL
						});
					},
					"args": ["e"],
					"role": "event"
				},
				"set": {
					// "eventTitle": "an incoming value is being stored",
					"name": "set",
					"fn": function _set(e) {
					
					
					var d= e.data.data,
					  key= e.data.owner, 
					  cfg= d.$config||{},
					value= d.data;			
					
					
					
					if( key==ev.uid ){ return; }
					
					
					if(Zap.debug) { console.log("set", e, d, key, cfg, value); }
					
					
					console.log("SET",  key, ev.uid, e);
			
			
					Zap.storage.save(d, console.log.bind(console));
					
						
					
						// if(key && value!==undefined){ strongbox.set( key,   DATA[key] = value); }
						
						
						
						/*
						define a few options for zap.set-based items:
						persist - keep the data between tab openings?
						broadcast - tell everyone when the data changes or is created?
						sync - ask for unknowns upon boot?
						log - record changes to an observation log? (object.observe/redis like)
						json - false - don't json encode the data
						expires - Date - when should this item be removed?
						*/


						
						
						
						
					},
					"args": ["strName", "objData"],
					"r
;