diff --git a/examples/docs.html b/examples/docs.html new file mode 100644 index 00000000..73389007 --- /dev/null +++ b/examples/docs.html @@ -0,0 +1,69 @@ + + + + + + + + +Docs + + + + +
+
+

Docs

+

The contemporary tendency in our society is to base our distribution on scarcity, which has vanished, and to compress our abundance into the overfed mouths of the middle and upper classes until they gag with superfluity. If democracy is to have breadth of meaning, it is necessary to adjust this inequity. It is not only moral, but it is also intelligent. We are wasting and degrading human life by clinging to archaic thinking.

+
+
+ + + + + \ No newline at end of file diff --git a/gun.js b/gun.js index cb02e16f..45156557 100644 --- a/gun.js +++ b/gun.js @@ -811,20 +811,16 @@ // Maybe... in case the in-memory key we have is a local write // we still need to trigger a pull/merge from peers. } else { - //var S = +new Date; node = Gun.obj.copy(node); - //console.log(+new Date - S, 'copy node'); } node = Gun.graph.node(node); tmp = (at||empty).ack; - //var S = +new Date; root.on('in', { '@': msg['#'], how: 'mem', put: node, $: gun }); - //console.log(+new Date - S, 'root got send'); //if(0 < tmp){ return } root.on('get', msg); } @@ -1317,7 +1313,6 @@ function use(msg){ var eve = this, as = eve.as, cat = as.at, root = cat.root, gun = msg.$, at = (gun||{})._ || {}, data = msg.put || at.put, tmp; if((tmp = root.now) && eve !== tmp[as.now]){ return eve.to.next(msg) } - //console.log("USE:", cat.id, cat.soul, cat.has, cat.get, msg, root.mum); //if(at.async && msg.root){ return } //if(at.async === 1 && cat.async !== true){ return } //if(root.stop && root.stop[at.id]){ return } root.stop && (root.stop[at.id] = true); @@ -1545,7 +1540,7 @@ as = as.as; if(!msg.$ || !msg.$._){ return } // TODO: Handle if(msg.err){ // TODO: Handle - console.log("Please report this as an issue! Put.any.err"); + Gun.log("Please report this as an issue! Put.any.err"); return; } var at = (msg.$._), data = at.put, opt = as.opt||{}, root, tmp; @@ -1554,7 +1549,7 @@ if(as.ref !== as.$){ tmp = (as.$._).get || at.get; if(!tmp){ // TODO: Handle - console.log("Please report this as an issue! Put.no.get"); // TODO: BUG!?? + Gun.log("Please report this as an issue! Put.no.get"); // TODO: BUG!?? return; } as.data = obj_put({}, tmp, as.data); @@ -1814,7 +1809,7 @@ var root, noop = function(){}, store, u; try{store = (Gun.window||noop).localStorage}catch(e){} if(!store){ - console.log("Warning: No localStorage exists to persist data to!"); + Gun.log("Warning: No localStorage exists to persist data to!"); store = {setItem: function(k,v){this[k]=v}, removeItem: function(k){delete this[k]}, getItem: function(k){return this[k]}}; } /* @@ -1920,7 +1915,6 @@ data = Gun.state.to(data, has); } //if(!data && !Gun.obj.empty(opt.peers)){ return } // if data not found, don't ack if there are peers. // Hmm, what if we have peers but we are disconnected? - //console.log("lS get", lex, data); root.on('in', {'@': msg['#'], put: Gun.graph.node(data), how: 'lS', lS: msg.$});// || root.$}); }; Gun.debug? setTimeout(to,1) : to(); @@ -1976,15 +1970,14 @@ if('[' === tmp){ try{msg = JSON.parse(raw);}catch(e){opt.log('DAM JSON parse error', e)} if(!msg){ return } - //console.log('hear batch length of', msg.length); + LOG && opt.log(+new Date, msg.length, 'in hear batch'); (function go(){ - var S = +new Date; // STATS! + var S; LOG && (S = +new Date); // STATS! var m, c = 100; // hardcoded for now? while(c-- && (m = msg.shift())){ mesh.hear(m, peer); } - //console.log(+new Date - S, 'hear batch'); - (mesh.hear.long || (mesh.hear.long = [])).push(+new Date - S); + LOG && opt.log(S, +new Date - S, 'batch heard'); if(!msg.length){ return } puff(go, 0); }()); @@ -1995,7 +1988,7 @@ }catch(e){return opt.log('DAM JSON parse error', e)} if(!msg){ return } if(!(id = msg['#'])){ id = msg['#'] = Type.text.random(9) } - if(msg.DBG_s){ console.log(+new Date - msg.DBG_s, 'to hear', id) } + if(msg.DBG_s){ opt.log(+new Date - msg.DBG_s, 'to hear', id) } if(dup.check(id)){ return } dup.track(id, true).it = msg; // GUN core also dedups, so `true` is needed. // Does GUN core need to dedup anymore? if(!(hash = msg['##']) && u !== msg.put){ hash = msg['##'] = Type.obj.hash(msg.put) } @@ -2011,9 +2004,9 @@ } return; } - //var S = +new Date; + var S; LOG && (S = +new Date); root.on('in', msg); - //!msg.nts && console.log(+new Date - S, 'msg', msg['#']); + LOG && !msg.nts && opt.log(S, +new Date - S, 'msg', msg['#']); return; } } @@ -2027,7 +2020,7 @@ if(this.to){ this.to.next(msg) } // compatible with middleware adapters. if(!msg){ return false } var id, hash, tmp, raw; - //var S = +new Date; //msg.DBG_s = msg.DBG_s || +new Date; + var S; LOG && (S = +new Date); //msg.DBG_s = msg.DBG_s || +new Date; var meta = msg._||(msg._=function(){}); if(!(id = msg['#'])){ id = msg['#'] = Type.text.random(9) } if(!(hash = msg['##']) && u !== msg.put){ hash = msg['##'] = Type.obj.hash(msg.put) } @@ -2041,15 +2034,15 @@ } } } - //console.log(+new Date - S, 'mesh say prep'); + LOG && opt.log(S, +new Date - S, 'say prep'); dup.track(id).it = msg; // track for 9 seconds, default. Earth<->Mars would need more! if(!peer){ peer = (tmp = dup.s[msg['@']]) && (tmp = tmp.it) && (tmp = tmp._) && (tmp = tmp.via) } if(!peer && mesh.way){ return mesh.way(msg) } if(!peer || !peer.id){ message = msg; if(!Type.obj.is(peer || opt.peers)){ return false } - //var S = +new Date; + var S; LOG && (S = +new Date); Type.obj.map(peer || opt.peers, each); // in case peer is a peer list. - //console.log(+new Date - S, 'mesh say loop'); + LOG && opt.log(S, +new Date - S, 'say loop'); return; } if(!peer.wire && mesh.wire){ mesh.wire(peer) } @@ -2073,10 +2066,10 @@ peer.batch = peer.tail = null; if(!tmp){ return } if(!tmp.length){ return } // if(3 > tmp.length){ return } // TODO: ^ - //var S = +new Date; + var S; LOG && (S = +new Date); try{tmp = (1 === tmp.length? tmp[0] : JSON.stringify(tmp)); }catch(e){return opt.log('DAM JSON stringify error', e)} - //console.log(+new Date - S, 'mesh flush', tmp.length); + LOG && opt.log(S, +new Date - S, 'say stringify', tmp.length); if(!tmp){ return } send(tmp, peer); } @@ -2086,14 +2079,14 @@ // for now - find better place later. function send(raw, peer){ try{ var wire = peer.wire; - //var S = +new Date; + var S; LOG && (S = +new Date); if(peer.say){ peer.say(raw); } else if(wire.send){ wire.send(raw); } - //console.log(+new Date - S, 'wire send', raw.length); + LOG && opt.log(S, +new Date - S, 'wire send', raw.length); mesh.say.d += raw.length||0; ++mesh.say.c; // STATS! }catch(e){ (peer.queue = peer.queue || []).push(raw); @@ -2143,6 +2136,7 @@ root.on('bye', peer); var tmp = +(new Date); tmp = (tmp - (peer.met||tmp)); mesh.bye.time = ((mesh.bye.time || tmp) + tmp) / 2; + LOG = console.LOG; // dirty place to cheaply update LOG settings over time. } mesh.hear['!'] = function(msg, peer){ opt.log('Error:', msg.err) } mesh.hear['?'] = function(msg, peer){ @@ -2223,6 +2217,7 @@ }()); var empty = {}, ok = true, u; + var LOG = console.LOG; try{ module.exports = Mesh }catch(e){} diff --git a/gun.min.js b/gun.min.js index 4b43f0e5..1eb09d40 100644 --- a/gun.min.js +++ b/gun.min.js @@ -1 +1 @@ -!function(){var t;"undefined"!=typeof window&&(t=window),"undefined"!=typeof global&&(t=global);var j=(t=t||{}).console||{log:function(){}};function $(o,t){return t?require(o):o.slice?$[e(o)]:function(t,n){o(t={exports:{}}),$[e(n)]=t.exports};function e(t){return t.split("/").slice(-1).toString().replace(".js","")}}if("undefined"!=typeof module)var o=module;$(function(t){var n,c,l={};function o(t,n){v(this,n)&&void 0!==this[n]||(this[n]=t)}function e(t,n){var o=this.n;if(!o||!(n===o||g(o)&&v(o,n)))return!!n||void 0}function p(t,n){2!==arguments.length?(p.r=p.r||[]).push(t):(p.r=p.r||{})[t]=n}l.fn={is:function(t){return!!t&&"function"==typeof t}},l.bi={is:function(t){return t instanceof Boolean||"boolean"==typeof t}},l.num={is:function(t){return!d(t)&&(0<=t-parseFloat(t)+1||1/0===t||-1/0===t)}},l.text={is:function(t){return"string"==typeof t}},l.text.ify=function(t){return l.text.is(t)?t:"undefined"!=typeof JSON?JSON.stringify(t):t&&t.toString?t.toString():t},l.text.random=function(t,n){var o="";for(t=t||24,n=n||"0123456789ABCDEFGHIJKLMNOPQRSTUVWXZabcdefghijklmnopqrstuvwxyz";0"]||n["<"])||e===n["="]&&(o=n["*"]||n[">"]||n["<"],t.slice(0,(o||"").length)===o||e===n["*"]&&(e!==n[">"]&&e!==n["<"]?t>=n[">"]&&t<=n["<"]:e!==n[">"]&&t>=n[">"]||e!==n["<"]&&t<=n["<"])))},l.list={is:function(t){return t instanceof Array}},l.list.slit=Array.prototype.slice,l.list.sort=function(o){return function(t,n){return t&&n?(t=t[o])<(n=n[o])?-1:n",u.drift=0,u.is=function(t,n,o){var e=n&&t&&t[k]&&t[k][u._]||o;if(e)return v(e=e[n])?e:-1/0},u.lex=function(){return u().toString(36).replace(".","")},u.ify=function(t,n,o,e,i){if(!t||!t[k]){if(!i)return;t=a.soul.ify(t,i)}var r=l(t[k],u._);return void 0!==n&&n!==k&&(v(o)&&(r[n]=o),void 0!==e&&(t[n]=e)),t},u.to=function(t,n,o){var e=(t||{})[n];return h(e)&&(e=g(e)),u.ify(o,n,u.is(t,n),e,a.soul(t))},u.map=function(i,r,a){var t=h(t=i||r)?t:null;return i=m(i=i||r)?i:null,t&&!i?(r=v(r)?r:u(),t[k]=t[k]||{},d(t,f,{o:t,s:r}),t):(a=a||h(r)?r:void 0,r=v(r)?r:u(),function(t,n,o,e){if(!i)return f.call({o:o,s:r},t,n),t;i.call(a||this||{},t,n,o,e),p(o,n)&&void 0===o[n]||f.call({o:o,s:r},t,n)})};var c=n.obj,l=c.as,p=c.has,h=c.is,d=c.map,g=c.copy,v=n.num.is,m=n.fn.is,k=a._;t.exports=u})($,"./state"),$(function(t){var a=$("./type"),u=$("./val"),s=$("./node"),i={};function r(t,n){if(!t||n!==s.soul(t)||!s.is(t,this.fn,this.as))return!0;this.cb&&(o.n=t,o.as=this.as,this.cb.call(o.as,t,n,o))}function o(t){t&&s.is(o.n,t,o.as)}function f(t,n){var o;return(o=function(t,n){var o,e=t.seen,i=e.length;for(;i--;)if(o=e[i],n.obj===o.obj)return o;e.push(n)}(t,n))?o:(n.env=t,n.soul=c,s.ify(n.obj,e,n)&&(n.link=n.link||u.link.ify(s.soul(n.node)),n.obj!==t.shell&&(t.graph[u.link.is(n.link)]=n.node)),n)}function e(t,n,o){var e,i,r=this,a=r.env;if(s._===n&&g(t,u.link._))return o._;if(e=l(t,n,o,r,a)){if(n||(r.node=r.node||o||{},g(t,s._)&&s.soul(t)&&(r.node._=b(t._)),r.node=s.soul.ify(r.node,u.link.is(r.link)),r.link=r.link||u.link.ify(s.soul(r.node))),(i=a.map)&&(i.call(a.as||{},t,n,o,r),g(o,n))){if(void 0===(t=o[n]))return void d(o,n);if(!(e=l(t,n,o,r,a)))return}if(!n)return r.node;if(!0===e)return t;if((i=f(a,{obj:t,path:r.path.concat(n)})).node)return i.link}}function c(t){var n=this,o=u.link.is(n.link),e=n.env.graph;n.link=n.link||u.link.ify(t),n.link[u.link._]=t,n.node&&n.node[s._]&&(n.node[s._][u.link._]=t),g(e,o)&&(e[t]=e[o],d(e,o))}function l(t,n,o,e,i){var r;return!!u.is(t)||(h(t)?1:(r=i.invalid)?l(t=r.call(i.as||{},t,n,o),n,o,e,i):(i.err="Invalid value at '"+e.path.concat(n).join(".")+"'!",void(a.list.is(t)&&(i.err+=" Use `.set(item)` instead of an Array."))))}function p(t,n){var o,e;if(s._!==n)(o=u.link.is(t))?(e=this.opt.seen[o])?this.obj[n]=e:this.obj[n]=this.opt.seen[o]=i.to(this.graph,o,this.opt):this.obj[n]=t;else{if(v(t,u.link._))return;this.obj[n]=b(t)}}i.is=function(t,n,o,e){return!(!t||!h(t)||v(t)||k(t,r,{cb:n,fn:o,as:e}))},i.ify=function(t,n,o){var e={path:[],obj:t};return n?"string"==typeof n?n={soul:n}:n instanceof Function&&(n.map=n):n={},n.soul&&(e.link=u.link.ify(n.soul)),n.shell=(o||{}).shell,n.graph=n.graph||{},n.seen=n.seen||[],n.as=n.as||o,f(n,e),n.root=e.node,n.graph},i.node=function(t){var n=s.soul(t);if(n)return m({},n,t)},i.to=function(t,n,o){if(t){var e={};return o=o||{seen:{}},k(t[n],p,{obj:e,graph:t,opt:o}),e}};a.fn.is;var n=a.obj,h=n.is,d=n.del,g=n.has,v=n.empty,m=n.put,k=n.map,b=n.copy;t.exports=i})($,"./graph"),$(function(t){$("./onto"),t.exports=function(t,n){if(this.on){if(!(t instanceof Function)){if(!t||!n)return;var o=t["#"]||t,e=(this.tag||empty)[o];if(!e)return;return e=this.on(o,n),clearTimeout(e.err),!0}o=n&&n["#"]||Math.random().toString(36).slice(2);if(!t)return o;var i=this.on(o,t,n);return i.err=i.err||setTimeout(function(){i.next({err:"Error: No ACK received yet.",lack:!0}),i.off()},(this.opt||{}).lack||9e3),o}}})($,"./ask"),$(function(t){var r=$("./type");var a=r.time.is;t.exports=function(e){var i={s:{}};return e=e||{max:1e3,age:9e3},i.check=function(t){var n;return!!(n=i.s[t])&&(n.pass?n.pass=!1:i.track(t))},i.track=function(t,n){var o=i.s[t]||(i.s[t]={});return o.was=a(),n&&(o.pass=!0),i.to||(i.to=setTimeout(function(){var o=a();r.obj.map(i.s,function(t,n){t&&e.age>o-t.was||r.obj.del(i.s,n)}),i.to=null},e.age+9)),o},i}})($,"./dup"),$(function(t){function c(t){return t instanceof c?(this._={gun:this,$:this}).$:this instanceof c?c.create(this._={gun:this,$:this,opt:t}):new c(t)}c.is=function(t){return t instanceof c||t&&t._&&t===t._.$||!1},c.version=.9,(c.chain=c.prototype).toJSON=function(){};var n=$("./type");function a(t){var n,o,e=this.as,i=e.at||e,r=i.$;(o=t["#"])||(o=t["#"]=h(9)),(n=i.dup).check(o)?e.out===t.out&&(t.out=void 0,this.to.next(t)):(n.track(o),i.ask(t["@"],t)||(t.get&&c.on.get(t,r),t.put&&c.on.put(t,r)),this.to.next(t),e.out||(t.out=a,i.on("out",t)))}function i(t,n,o,e){var i=this,r=c.state.is(o,n);if(!r)return i.err="Error: No state on '"+n+"' in node '"+e+"'!";var a=i.graph[e]||x,u=c.state.is(a,n,!0),s=a[n],f=c.HAM(i.machine,r,u,t,s);f.incoming?(i.put[e]=c.state.to(o,n,i.put[e]),(i.diff||(i.diff={}))[e]=c.state.to(o,n,i.diff[e]),i.souls[e]=!0):f.defer&&(i.defer=r<(i.defer||1/0)?r:i.defer)}function r(t,n){var o=this,e=o.$._,i=(e.next||x)[n];if(!i){if(!(e.opt||x).super)return void(o.souls[n]=!1);i=o.$.get(n)._}var r=o.map[n]={put:t,get:n,$:i.$},a={ctx:o,msg:r};o.async=!!e.tag.node,o.ack&&(r["@"]=o.ack),k(t,u,a),o.async&&(o.and||e.on("node",function(t){this.to.next(t),t===o.map[t.get]&&(o.souls[t.get]=!1,k(t.put,s,t),k(o.souls,function(t){if(t)return t})||o.c||(o.c=1,this.off(),k(o.map,f,o)))}),o.and=!0,e.on("node",r))}function u(t,n){var o=this.ctx,e=o.graph,i=this.msg,r=i.get,a=i.put,u=i.$._;e[r]=c.state.to(a,n,e[r]),o.async||(u.put=c.state.to(a,n,u.put))}function s(t,n){var o=this.put,e=this.$._;e.put=c.state.to(o,n,e.put)}function f(t,n){t.$&&(this.cat.stop=this.stop,t.$._.on("in",t),this.cat.stop=null)}n.obj.to(n,c),c.HAM=$("./HAM"),c.val=$("./val"),c.node=$("./node"),c.state=$("./state"),c.graph=$("./graph"),c.on=$("./onto"),c.ask=$("./ask"),c.dup=$("./dup"),c.create=function(t){t.root=t.root||t,t.graph=t.graph||{},t.on=t.on||c.on,t.ask=t.ask||c.ask,t.dup=t.dup||c.dup();var n=t.$.opt(t.opt);return t.once||(t.on("in",a,t),t.on("out",a,{at:t,out:a}),c.on("create",t),t.on("create",t)),t.once=1,n},c.on.put=function(t,n){var o=n._,e={$:n,graph:o.graph,put:{},map:{},souls:{},machine:c.state(),ack:t["@"],cat:o,stop:{}};if(c.graph.is(t.put,null,i,e)||(e.err="Error: Invalid graph!"),e.err)return o.on("in",{"@":t["#"],err:c.log(e.err)});k(e.put,r,e),e.async||k(e.map,f,e),void 0!==e.defer&&setTimeout(function(){c.on.put(t,n)},e.defer-e.machine),e.diff&&o.on("put",m(t,{put:e.diff}))},c.on.get=function(t,n){var o=n._,e=t.get,i=e[y],r=o.graph[i],a=e[_],u=(o.next||(o.next={}))[i];if(!r)return o.on("get",t);if(a){if("string"!=typeof a||!v(r,a))return o.on("get",t);r=c.state.to(r,a)}else r=c.obj.copy(r);r=c.graph.node(r),(u||x).ack,o.on("in",{"@":t["#"],how:"mem",put:r,$:n}),o.on("get",t)},c.chain.opt=function(t){t=t||{};var n=this._,o=t.peers||t;return g(t)||(t={}),g(n.opt)||(n.opt=t),p(o)&&(o=[o]),e(o)&&(o=k(o,function(t,n,o){(n={}).id=n.url=t,o(t,n)}),g(n.opt.peers)||(n.opt.peers={}),n.opt.peers=m(o,n.opt.peers)),n.opt.peers=n.opt.peers||{},k(t,function t(n,o){!v(this,o)||l.is(n)||d.empty(n)?this[o]=n:n&&n.constructor!==Object&&!e(n)||k(n,t,this[o])},n.opt),c.on("opt",n),n.opt.uuid=n.opt.uuid||function(){return b()+h(12)},this};var e=c.list.is,l=c.text,p=l.is,h=l.random,d=c.obj,g=d.is,v=d.has,m=d.to,k=d.map,b=(d.copy,c.state.lex),y=c.val.link._,_=".",x=(c.node._,c.val.link.is,{});j.only=function(t,n){return j.only.i&&t===j.only.i&&j.only.i++&&(j.log.apply(j,arguments)||n)},(c.log=function(){return c.log.off||j.log.apply(j,arguments),[].slice.call(arguments).join(" ")}).once=function(t,n,o){return(o=c.log.once)[t]=o[t]||0,o[t]++||c.log(n)},c.log.once("welcome","Hello wonderful person! :) Thanks for using GUN, feel free to ask for help on https://gitter.im/amark/gun and ask StackOverflow questions tagged with 'gun'!"),"undefined"!=typeof window&&((window.GUN=window.Gun=c).window=window);try{void 0!==o&&(o.exports=c)}catch(t){}t.exports=c})($,"./root"),$(function(t){var u=$("./root");u.chain.back=function(t,n){if(-1===(t=t||1)||1/0===t)return this._.root.$;if(1===t)return(this._.back||this._).$;var o=this._;if("string"==typeof t&&(t=t.split(".")),t instanceof Array){for(var e=0,i=t.length,r=o;e(r.acks||0)&&this.off(),r.ack&&r.ack(t,this)},r.opt),o=0,e=n.root.now;h.del(n.root,"now");var i=n.root.mum;n.root.mum={},r.ref._.on("out",{$:r.ref,put:r.out=r.env.graph,opt:r.opt,"#":t}),n.root.mum=i?h.to(i,n.root.mum):i,n.root.now=e},r),r.res&&r.res())}function n(t,n){if(t)return!0}function c(r,t,n,a){var u=this,s=f.is(r);!t&&a.path.length&&(u.res||e)(function(){for(var t=a.path,n=u.ref,o=(u.opt,0),e=t.length;o .once, apologies unexpected."),this.once(t,n)},f.chain.once=function(t,n){var o=this,e=o._,i=e.put;if(0=(e.batch||1e3))return f();i=i||setTimeout(f,e.wait||1)}),a.on("get",function(n){this.to.next(n);var o,e,i,r=n.get;function t(){if(r&&(o=r["#"])){var t=r["."];(e=s[o]||i)&&t&&(e=Gun.state.to(e,t)),a.on("in",{"@":n["#"],put:Gun.graph.node(e),how:"lS",lS:n.$})}}Gun.debug?setTimeout(t,1):t()});var n=function(t,n,o,e){s[e]=Gun.state.to(o,n,s[e])},f=function(t){var o;u=0,clearTimeout(i),i=!1;var n=r;r={},t&&(s=t);try{p.setItem(e.prefix,JSON.stringify(s))}catch(t){Gun.log(o=(t||"localStorage failure")+" Consider using GUN's IndexedDB plugin for RAD for more storage space, https://gun.eco/docs/RAD#install"),a.on("localStorage:error",{err:o,file:e.prefix,flush:s,retry:f})}(o||Gun.obj.empty(e.peers))&&Gun.obj.map(n,function(t,n){a.on("in",{"@":n,err:o,ok:0})})}}})}})($,"./adapters/localStorage"),$(function(t){var g=$("../type"),v="undefined"!=typeof setImmediate?setImmediate:setTimeout;!function(){g.text.hash=function(t){if("string"!=typeof t)return{err:1};var n=0;if(!t.length)return n;for(var o=0,e=t.length;o<"])&&(r._.to=g.obj.map(e.split(","),l)),r.dam?void((e=u.hear[r.dam])&&e(r,i,a)):void a.on("in",r)}}else{try{r=JSON.parse(t)}catch(t){s.log("DAM JSON parse error",t)}if(!r)return;(function t(){for(var n,o=+new Date,e=100;e--&&(n=r.shift());)u.hear(n,i);(u.hear.long||(u.hear.long=[])).push(+new Date-o),r.length&&v(t,0)})()}}};var c,l=function(t,n,o){o(t,!0)};function p(t){u.say(c,t)}function h(t){var n=t.batch;if(t.batch=t.tail=null,n&&n.length){try{n=1===n.length?n[0]:JSON.stringify(n)}catch(t){return s.log("DAM JSON stringify error",t)}n&&d(n,t)}}function d(n,o){try{var t=o.wire;o.say?o.say(n):t.send&&t.send(n),u.say.d+=n.length||0,++u.say.c}catch(t){(o.queue=o.queue||[]).push(n)}}u.hear.c=u.hear.d=0,u.say=function(t,n){if(this.to&&this.to.next(t),!t)return!1;var o,e,i,r,a=t._||(t._=function(){});if((o=t["#"])||(o=t["#"]=g.text.random(9)),(e=t["##"])||void 0===t.put||(e=t["##"]=g.obj.hash(t.put)),!(r=a.raw)&&(r=a.raw=u.raw(t),e&&(i=t["@"])&&(f.track(i+e).it=t,i=(f.s[i]||!0).it))){if(e===i["##"])return!1;i["##"]=e}if(f.track(o).it=t,!(n=n||(i=f.s[t["@"]])&&(i=i.it)&&(i=i._)&&(i=i.via))&&u.way)return u.way(t);if(!n||!n.id)return c=t,!!g.obj.is(n||s.peers)&&void g.obj.map(n||s.peers,p);if(!n.wire&&u.wire&&u.wire(n),o!==n.last){if(n.last=o,n===a.via)return!1;if((i=a.to)&&(i[n.url]||i[n.pid]||i[n.id]))return!1;if(n.batch){if(n.tail=(i=n.tail||0)+r.length,n.tail<=s.pack)return void n.batch.push(r);h(n)}n.batch=[],setTimeout(function(){h(n)},s.gap),d(r,n)}},u.say.c=u.say.d=0,function(){u.raw=function(t){if(!t)return"";var n,o=t._||{};if(n=o.raw)return n;if("string"==typeof t)return t;if(!t.dam){var e=0,i=[];g.obj.map(s.peers,function(t){if(i.push(t.url||t.pid||t.id),9<++e)return!0}),1<"]=i.join())}var r=a(t);return o&&(o.raw=r),r};var a=JSON.stringify}(),u.hi=function(n){var t=n.wire||{};n.id?s.peers[n.url||n.id]=n:(t=n.id=n.id||g.text.random(9),u.say({dam:"?"},s.peers[t]=n)),n.met=n.met||+new Date,t.hied||a.on(t.hied="hi",n),t=n.queue,n.queue=[],g.obj.map(t,function(t){d(t,n)})},u.bye=function(t){a.on("bye",t);var n=+new Date;n-=t.met||n,u.bye.time=((u.bye.time||n)+n)/2},u.hear["!"]=function(t,n){s.log("Error:",t.err)},u.hear["?"]=function(t,n){t.pid?n.pid||(n.pid=t.pid):u.say({dam:"?",pid:s.pid,"@":t["#"]},n)},a.on("create",function(t){t.opt.pid=t.opt.pid||g.text.random(9),this.to.next(t),t.on("out",u.say)}),a.on("bye",function(t,n){t=s.peers[t.id||t]||t,this.to.next(t),t.bye?t.bye():(n=t.wire)&&n.close&&n.close(),g.obj.del(s.peers,t.id),t.wire=null});var i={};return a.on("bye",function(t,n){this.to.next(t),(n=t.url)&&(i[n]=!0,setTimeout(function(){delete i[n]},s.lack||9e3))}),a.on("hi",function(o,e){this.to.next(o),(e=o.url)&&i[e]&&(delete i[e],g.obj.map(a.next,function(t,n){(e={})[n]=a.graph[n],u.say({"##":g.obj.hash(e),get:{"#":n}},o)}))}),u}}catch(t){}})($,"./adapters/mesh"),$(function(t){var f=$("../index");f.Mesh=$("./mesh"),f.on("opt",function(t){this.to.next(t);var e=t.opt;if(!t.once&&!1!==e.WebSocket){var n;"undefined"!=typeof window&&(n=window),"undefined"!=typeof global&&(n=global),n=n||{};var o=e.WebSocket||n.WebSocket||n.webkitWebSocket||n.mozWebSocket;if(o){e.WebSocket=o;var i=e.mesh=e.mesh||f.Mesh(t);i.wire||e.wire;i.wire=e.wire=u,setTimeout(function(){t.on("out",{dam:"hi"})},1);var r=2e3,a="undefined"!=typeof document&&document}}function u(n){try{if(!n||!n.url)return o&&o(n);var t=n.url.replace("http","ws"),o=n.wire=new e.WebSocket(t);return o.onclose=function(){e.mesh.bye(n),s(n)},o.onerror=function(t){s(n)},o.onopen=function(){e.mesh.hi(n)},o.onmessage=function(t){t&&e.mesh.hear(t.data||t,n)},o}catch(t){}}function s(n){clearTimeout(n.defer),a&&n.retry<=0||(n.retry=(n.retry||e.retry||60)-1,n.defer=setTimeout(function t(){if(a&&a.hidden)return setTimeout(t,r);u(n)},r))}})})($,"./adapters/websocket")}(); \ No newline at end of file +!function(){var t;"undefined"!=typeof window&&(t=window),"undefined"!=typeof global&&(t=global);var e=(t=t||{}).console||{log:function(){}};function j(e,t){return t?require(e):e.slice?j[o(e)]:function(t,n){e(t={exports:{}}),j[o(n)]=t.exports};function o(t){return t.split("/").slice(-1).toString().replace(".js","")}}if("undefined"!=typeof module)var $=module;j(function(t){var n,c,l={};function e(t,n){v(this,n)&&void 0!==this[n]||(this[n]=t)}function o(t,n){var e=this.n;if(!e||!(n===e||g(e)&&v(e,n)))return!!n||void 0}function p(t,n){2!==arguments.length?(p.r=p.r||[]).push(t):(p.r=p.r||{})[t]=n}l.fn={is:function(t){return!!t&&"function"==typeof t}},l.bi={is:function(t){return t instanceof Boolean||"boolean"==typeof t}},l.num={is:function(t){return!d(t)&&(0<=t-parseFloat(t)+1||1/0===t||-1/0===t)}},l.text={is:function(t){return"string"==typeof t}},l.text.ify=function(t){return l.text.is(t)?t:"undefined"!=typeof JSON?JSON.stringify(t):t&&t.toString?t.toString():t},l.text.random=function(t,n){var e="";for(t=t||24,n=n||"0123456789ABCDEFGHIJKLMNOPQRSTUVWXZabcdefghijklmnopqrstuvwxyz";0"]||n["<"])||o===n["="]&&(e=n["*"]||n[">"]||n["<"],t.slice(0,(e||"").length)===e||o===n["*"]&&(o!==n[">"]&&o!==n["<"]?t>=n[">"]&&t<=n["<"]:o!==n[">"]&&t>=n[">"]||o!==n["<"]&&t<=n["<"])))},l.list={is:function(t){return t instanceof Array}},l.list.slit=Array.prototype.slice,l.list.sort=function(e){return function(t,n){return t&&n?(t=t[e])<(n=n[e])?-1:n",u.drift=0,u.is=function(t,n,e){var o=n&&t&&t[k]&&t[k][u._]||e;if(o)return v(o=o[n])?o:-1/0},u.lex=function(){return u().toString(36).replace(".","")},u.ify=function(t,n,e,o,i){if(!t||!t[k]){if(!i)return;t=a.soul.ify(t,i)}var r=l(t[k],u._);return void 0!==n&&n!==k&&(v(e)&&(r[n]=e),void 0!==o&&(t[n]=o)),t},u.to=function(t,n,e){var o=(t||{})[n];return h(o)&&(o=g(o)),u.ify(e,n,u.is(t,n),o,a.soul(t))},u.map=function(i,r,a){var t=h(t=i||r)?t:null;return i=m(i=i||r)?i:null,t&&!i?(r=v(r)?r:u(),t[k]=t[k]||{},d(t,f,{o:t,s:r}),t):(a=a||h(r)?r:void 0,r=v(r)?r:u(),function(t,n,e,o){if(!i)return f.call({o:e,s:r},t,n),t;i.call(a||this||{},t,n,e,o),p(e,n)&&void 0===e[n]||f.call({o:e,s:r},t,n)})};var c=n.obj,l=c.as,p=c.has,h=c.is,d=c.map,g=c.copy,v=n.num.is,m=n.fn.is,k=a._;t.exports=u})(j,"./state"),j(function(t){var a=j("./type"),u=j("./val"),s=j("./node"),i={};function r(t,n){if(!t||n!==s.soul(t)||!s.is(t,this.fn,this.as))return!0;this.cb&&(e.n=t,e.as=this.as,this.cb.call(e.as,t,n,e))}function e(t){t&&s.is(e.n,t,e.as)}function f(t,n){var e;return(e=function(t,n){var e,o=t.seen,i=o.length;for(;i--;)if(e=o[i],n.obj===e.obj)return e;o.push(n)}(t,n))?e:(n.env=t,n.soul=c,s.ify(n.obj,o,n)&&(n.link=n.link||u.link.ify(s.soul(n.node)),n.obj!==t.shell&&(t.graph[u.link.is(n.link)]=n.node)),n)}function o(t,n,e){var o,i,r=this,a=r.env;if(s._===n&&g(t,u.link._))return e._;if(o=l(t,n,e,r,a)){if(n||(r.node=r.node||e||{},g(t,s._)&&s.soul(t)&&(r.node._=b(t._)),r.node=s.soul.ify(r.node,u.link.is(r.link)),r.link=r.link||u.link.ify(s.soul(r.node))),(i=a.map)&&(i.call(a.as||{},t,n,e,r),g(e,n))){if(void 0===(t=e[n]))return void d(e,n);if(!(o=l(t,n,e,r,a)))return}if(!n)return r.node;if(!0===o)return t;if((i=f(a,{obj:t,path:r.path.concat(n)})).node)return i.link}}function c(t){var n=this,e=u.link.is(n.link),o=n.env.graph;n.link=n.link||u.link.ify(t),n.link[u.link._]=t,n.node&&n.node[s._]&&(n.node[s._][u.link._]=t),g(o,e)&&(o[t]=o[e],d(o,e))}function l(t,n,e,o,i){var r;return!!u.is(t)||(h(t)?1:(r=i.invalid)?l(t=r.call(i.as||{},t,n,e),n,e,o,i):(i.err="Invalid value at '"+o.path.concat(n).join(".")+"'!",void(a.list.is(t)&&(i.err+=" Use `.set(item)` instead of an Array."))))}function p(t,n){var e,o;if(s._!==n)(e=u.link.is(t))?(o=this.opt.seen[e])?this.obj[n]=o:this.obj[n]=this.opt.seen[e]=i.to(this.graph,e,this.opt):this.obj[n]=t;else{if(v(t,u.link._))return;this.obj[n]=b(t)}}i.is=function(t,n,e,o){return!(!t||!h(t)||v(t)||k(t,r,{cb:n,fn:e,as:o}))},i.ify=function(t,n,e){var o={path:[],obj:t};return n?"string"==typeof n?n={soul:n}:n instanceof Function&&(n.map=n):n={},n.soul&&(o.link=u.link.ify(n.soul)),n.shell=(e||{}).shell,n.graph=n.graph||{},n.seen=n.seen||[],n.as=n.as||e,f(n,o),n.root=o.node,n.graph},i.node=function(t){var n=s.soul(t);if(n)return m({},n,t)},i.to=function(t,n,e){if(t){var o={};return e=e||{seen:{}},k(t[n],p,{obj:o,graph:t,opt:e}),o}};a.fn.is;var n=a.obj,h=n.is,d=n.del,g=n.has,v=n.empty,m=n.put,k=n.map,b=n.copy;t.exports=i})(j,"./graph"),j(function(t){j("./onto"),t.exports=function(t,n){if(this.on){if(!(t instanceof Function)){if(!t||!n)return;var e=t["#"]||t,o=(this.tag||empty)[e];if(!o)return;return o=this.on(e,n),clearTimeout(o.err),!0}e=n&&n["#"]||Math.random().toString(36).slice(2);if(!t)return e;var i=this.on(e,t,n);return i.err=i.err||setTimeout(function(){i.next({err:"Error: No ACK received yet.",lack:!0}),i.off()},(this.opt||{}).lack||9e3),e}}})(j,"./ask"),j(function(t){var r=j("./type");var a=r.time.is;t.exports=function(o){var i={s:{}};return o=o||{max:1e3,age:9e3},i.check=function(t){var n;return!!(n=i.s[t])&&(n.pass?n.pass=!1:i.track(t))},i.track=function(t,n){var e=i.s[t]||(i.s[t]={});return e.was=a(),n&&(e.pass=!0),i.to||(i.to=setTimeout(function(){var e=a();r.obj.map(i.s,function(t,n){t&&o.age>e-t.was||r.obj.del(i.s,n)}),i.to=null},o.age+9)),e},i}})(j,"./dup"),j(function(t){function c(t){return t instanceof c?(this._={gun:this,$:this}).$:this instanceof c?c.create(this._={gun:this,$:this,opt:t}):new c(t)}c.is=function(t){return t instanceof c||t&&t._&&t===t._.$||!1},c.version=.9,(c.chain=c.prototype).toJSON=function(){};var n=j("./type");function a(t){var n,e,o=this.as,i=o.at||o,r=i.$;(e=t["#"])||(e=t["#"]=h(9)),(n=i.dup).check(e)?o.out===t.out&&(t.out=void 0,this.to.next(t)):(n.track(e),i.ask(t["@"],t)||(t.get&&c.on.get(t,r),t.put&&c.on.put(t,r)),this.to.next(t),o.out||(t.out=a,i.on("out",t)))}function i(t,n,e,o){var i=this,r=c.state.is(e,n);if(!r)return i.err="Error: No state on '"+n+"' in node '"+o+"'!";var a=i.graph[o]||x,u=c.state.is(a,n,!0),s=a[n],f=c.HAM(i.machine,r,u,t,s);f.incoming?(i.put[o]=c.state.to(e,n,i.put[o]),(i.diff||(i.diff={}))[o]=c.state.to(e,n,i.diff[o]),i.souls[o]=!0):f.defer&&(i.defer=r<(i.defer||1/0)?r:i.defer)}function r(t,n){var e=this,o=e.$._,i=(o.next||x)[n];if(!i){if(!(o.opt||x).super)return void(e.souls[n]=!1);i=e.$.get(n)._}var r=e.map[n]={put:t,get:n,$:i.$},a={ctx:e,msg:r};e.async=!!o.tag.node,e.ack&&(r["@"]=e.ack),k(t,u,a),e.async&&(e.and||o.on("node",function(t){this.to.next(t),t===e.map[t.get]&&(e.souls[t.get]=!1,k(t.put,s,t),k(e.souls,function(t){if(t)return t})||e.c||(e.c=1,this.off(),k(e.map,f,e)))}),e.and=!0,o.on("node",r))}function u(t,n){var e=this.ctx,o=e.graph,i=this.msg,r=i.get,a=i.put,u=i.$._;o[r]=c.state.to(a,n,o[r]),e.async||(u.put=c.state.to(a,n,u.put))}function s(t,n){var e=this.put,o=this.$._;o.put=c.state.to(e,n,o.put)}function f(t,n){t.$&&(this.cat.stop=this.stop,t.$._.on("in",t),this.cat.stop=null)}n.obj.to(n,c),c.HAM=j("./HAM"),c.val=j("./val"),c.node=j("./node"),c.state=j("./state"),c.graph=j("./graph"),c.on=j("./onto"),c.ask=j("./ask"),c.dup=j("./dup"),c.create=function(t){t.root=t.root||t,t.graph=t.graph||{},t.on=t.on||c.on,t.ask=t.ask||c.ask,t.dup=t.dup||c.dup();var n=t.$.opt(t.opt);return t.once||(t.on("in",a,t),t.on("out",a,{at:t,out:a}),c.on("create",t),t.on("create",t)),t.once=1,n},c.on.put=function(t,n){var e=n._,o={$:n,graph:e.graph,put:{},map:{},souls:{},machine:c.state(),ack:t["@"],cat:e,stop:{}};if(c.graph.is(t.put,null,i,o)||(o.err="Error: Invalid graph!"),o.err)return e.on("in",{"@":t["#"],err:c.log(o.err)});k(o.put,r,o),o.async||k(o.map,f,o),void 0!==o.defer&&setTimeout(function(){c.on.put(t,n)},o.defer-o.machine),o.diff&&e.on("put",m(t,{put:o.diff}))},c.on.get=function(t,n){var e=n._,o=t.get,i=o[y],r=e.graph[i],a=o[_],u=(e.next||(e.next={}))[i];if(!r)return e.on("get",t);if(a){if("string"!=typeof a||!v(r,a))return e.on("get",t);r=c.state.to(r,a)}else r=c.obj.copy(r);r=c.graph.node(r),(u||x).ack,e.on("in",{"@":t["#"],how:"mem",put:r,$:n}),e.on("get",t)},c.chain.opt=function(t){t=t||{};var n=this._,e=t.peers||t;return g(t)||(t={}),g(n.opt)||(n.opt=t),p(e)&&(e=[e]),o(e)&&(e=k(e,function(t,n,e){(n={}).id=n.url=t,e(t,n)}),g(n.opt.peers)||(n.opt.peers={}),n.opt.peers=m(e,n.opt.peers)),n.opt.peers=n.opt.peers||{},k(t,function t(n,e){!v(this,e)||l.is(n)||d.empty(n)?this[e]=n:n&&n.constructor!==Object&&!o(n)||k(n,t,this[e])},n.opt),c.on("opt",n),n.opt.uuid=n.opt.uuid||function(){return b()+h(12)},this};var o=c.list.is,l=c.text,p=l.is,h=l.random,d=c.obj,g=d.is,v=d.has,m=d.to,k=d.map,b=(d.copy,c.state.lex),y=c.val.link._,_=".",x=(c.node._,c.val.link.is,{});e.only=function(t,n){return e.only.i&&t===e.only.i&&e.only.i++&&(e.log.apply(e,arguments)||n)},(c.log=function(){return c.log.off||e.log.apply(e,arguments),[].slice.call(arguments).join(" ")}).once=function(t,n,e){return(e=c.log.once)[t]=e[t]||0,e[t]++||c.log(n)},c.log.once("welcome","Hello wonderful person! :) Thanks for using GUN, feel free to ask for help on https://gitter.im/amark/gun and ask StackOverflow questions tagged with 'gun'!"),"undefined"!=typeof window&&((window.GUN=window.Gun=c).window=window);try{void 0!==$&&($.exports=c)}catch(t){}t.exports=c})(j,"./root"),j(function(t){var u=j("./root");u.chain.back=function(t,n){if(-1===(t=t||1)||1/0===t)return this._.root.$;if(1===t)return(this._.back||this._).$;var e=this._;if("string"==typeof t&&(t=t.split(".")),t instanceof Array){for(var o=0,i=t.length,r=e;o(r.acks||0)&&this.off(),r.ack&&r.ack(t,this)},r.opt),e=0,o=n.root.now;h.del(n.root,"now");var i=n.root.mum;n.root.mum={},r.ref._.on("out",{$:r.ref,put:r.out=r.env.graph,opt:r.opt,"#":t}),n.root.mum=i?h.to(i,n.root.mum):i,n.root.now=o},r),r.res&&r.res())}function n(t,n){if(t)return!0}function c(r,t,n,a){var u=this,s=f.is(r);!t&&a.path.length&&(u.res||o)(function(){for(var t=a.path,n=u.ref,e=(u.opt,0),o=t.length;e .once, apologies unexpected."),this.once(t,n)},f.chain.once=function(t,n){var e=this,o=e._,i=o.put;if(0=(o.batch||1e3))return f();i=i||setTimeout(f,o.wait||1)}),a.on("get",function(n){this.to.next(n);var e,o,i,r=n.get;function t(){if(r&&(e=r["#"])){var t=r["."];(o=s[e]||i)&&t&&(o=Gun.state.to(o,t)),a.on("in",{"@":n["#"],put:Gun.graph.node(o),how:"lS",lS:n.$})}}Gun.debug?setTimeout(t,1):t()});var n=function(t,n,e,o){s[o]=Gun.state.to(e,n,s[o])},f=function(t){var e;u=0,clearTimeout(i),i=!1;var n=r;r={},t&&(s=t);try{p.setItem(o.prefix,JSON.stringify(s))}catch(t){Gun.log(e=(t||"localStorage failure")+" Consider using GUN's IndexedDB plugin for RAD for more storage space, https://gun.eco/docs/RAD#install"),a.on("localStorage:error",{err:e,file:o.prefix,flush:s,retry:f})}(e||Gun.obj.empty(o.peers))&&Gun.obj.map(n,function(t,n){a.on("in",{"@":n,err:e,ok:0})})}}})}})(j,"./adapters/localStorage"),j(function(t){var v=j("../type"),m="undefined"!=typeof setImmediate?setImmediate:setTimeout;!function(){v.text.hash=function(t){if("string"!=typeof t)return{err:1};var n=0;if(!t.length)return n;for(var e=0,o=t.length;e<"])&&(r._.to=v.obj.map(o.split(","),p)),r.dam?void((o=s.hear[r.dam])&&o(r,i,u)):(k&&(a=+new Date),u.on("in",r),void(k&&!r.nts&&f.log(+new Date-a,"msg",r["#"])));var a}}};var l,p=function(t,n,e){e(t,!0)};function h(t){s.say(l,t)}function d(t){var n=t.batch;if(t.batch=t.tail=null,n&&n.length){var e;k&&(e=+new Date);try{n=1===n.length?n[0]:JSON.stringify(n)}catch(t){return f.log("DAM JSON stringify error",t)}k&&f.log(+new Date-e,"say stringify",n.length),n&&g(n,t)}}function g(n,e){try{var t,o=e.wire;k&&(t=+new Date),e.say?e.say(n):o.send&&o.send(n),k&&f.log(+new Date-t,"wire send",n.length),s.say.d+=n.length||0,++s.say.c}catch(t){(e.queue=e.queue||[]).push(n)}}s.hear.c=s.hear.d=0,s.say=function(t,n){if(this.to&&this.to.next(t),!t)return!1;var e,o,i,r;k&&(a=+new Date);var a,u=t._||(t._=function(){});if((e=t["#"])||(e=t["#"]=v.text.random(9)),(o=t["##"])||void 0===t.put||(o=t["##"]=v.obj.hash(t.put)),!(r=u.raw)&&(r=u.raw=s.raw(t),o&&(i=t["@"])&&(c.track(i+o).it=t,i=(c.s[i]||!0).it))){if(o===i["##"])return!1;i["##"]=o}if(k&&f.log(+new Date-a,"say prep"),c.track(e).it=t,!(n=n||(i=c.s[t["@"]])&&(i=i.it)&&(i=i._)&&(i=i.via))&&s.way)return s.way(t);if(!n||!n.id)return l=t,!!v.obj.is(n||f.peers)&&(k&&(a=+new Date),v.obj.map(n||f.peers,h),void(k&&f.log(+new Date-a,"say loop")));if(!n.wire&&s.wire&&s.wire(n),e!==n.last){if(n.last=e,n===u.via)return!1;if((i=u.to)&&(i[n.url]||i[n.pid]||i[n.id]))return!1;if(n.batch){if(n.tail=(i=n.tail||0)+r.length,n.tail<=f.pack)return void n.batch.push(r);d(n)}n.batch=[],setTimeout(function(){d(n)},f.gap),g(r,n)}},s.say.c=s.say.d=0,function(){s.raw=function(t){if(!t)return"";var n,e=t._||{};if(n=e.raw)return n;if("string"==typeof t)return t;if(!t.dam){var o=0,i=[];v.obj.map(f.peers,function(t){if(i.push(t.url||t.pid||t.id),9<++o)return!0}),1<"]=i.join())}var r=a(t);return e&&(e.raw=r),r};var a=JSON.stringify}(),s.hi=function(n){var t=n.wire||{};n.id?f.peers[n.url||n.id]=n:(t=n.id=n.id||v.text.random(9),s.say({dam:"?"},f.peers[t]=n)),n.met=n.met||+new Date,t.hied||u.on(t.hied="hi",n),t=n.queue,n.queue=[],v.obj.map(t,function(t){g(t,n)})},s.bye=function(t){u.on("bye",t);var n=+new Date;n-=t.met||n,s.bye.time=((s.bye.time||n)+n)/2,k=e.LOG},s.hear["!"]=function(t,n){f.log("Error:",t.err)},s.hear["?"]=function(t,n){t.pid?n.pid||(n.pid=t.pid):s.say({dam:"?",pid:f.pid,"@":t["#"]},n)},u.on("create",function(t){t.opt.pid=t.opt.pid||v.text.random(9),this.to.next(t),t.on("out",s.say)}),u.on("bye",function(t,n){t=f.peers[t.id||t]||t,this.to.next(t),t.bye?t.bye():(n=t.wire)&&n.close&&n.close(),v.obj.del(f.peers,t.id),t.wire=null});var i={};return u.on("bye",function(t,n){this.to.next(t),(n=t.url)&&(i[n]=!0,setTimeout(function(){delete i[n]},f.lack||9e3))}),u.on("hi",function(e,o){this.to.next(e),(o=e.url)&&i[o]&&(delete i[o],v.obj.map(u.next,function(t,n){(o={})[n]=u.graph[n],s.say({"##":v.obj.hash(o),get:{"#":n}},e)}))}),s}}catch(t){}})(j,"./adapters/mesh"),j(function(t){var f=j("../index");f.Mesh=j("./mesh"),f.on("opt",function(t){this.to.next(t);var o=t.opt;if(!t.once&&!1!==o.WebSocket){var n;"undefined"!=typeof window&&(n=window),"undefined"!=typeof global&&(n=global),n=n||{};var e=o.WebSocket||n.WebSocket||n.webkitWebSocket||n.mozWebSocket;if(e){o.WebSocket=e;var i=o.mesh=o.mesh||f.Mesh(t);i.wire||o.wire;i.wire=o.wire=u,setTimeout(function(){t.on("out",{dam:"hi"})},1);var r=2e3,a="undefined"!=typeof document&&document}}function u(n){try{if(!n||!n.url)return e&&e(n);var t=n.url.replace("http","ws"),e=n.wire=new o.WebSocket(t);return e.onclose=function(){o.mesh.bye(n),s(n)},e.onerror=function(t){s(n)},e.onopen=function(){o.mesh.hi(n)},e.onmessage=function(t){t&&o.mesh.hear(t.data||t,n)},e}catch(t){}}function s(n){clearTimeout(n.defer),a&&n.retry<=0||(n.retry=(n.retry||o.retry||60)-1,n.defer=setTimeout(function t(){if(a&&a.hidden)return setTimeout(t,r);u(n)},r))}})})(j,"./adapters/websocket")}(); \ No newline at end of file diff --git a/lib/meta.js b/lib/meta.js index c9fa3f9b..5b8b63c9 100644 --- a/lib/meta.js +++ b/lib/meta.js @@ -149,7 +149,7 @@ /* UI */ if(meta.css){ return } var $m = $('
').attr('id', 'meta'); - $m.append($('').text('+').addClass('meta-start')); + $m.append($('').html('☰').addClass('meta-start')); $m.append($('
').addClass('meta-menu meta-none').append('
    ')); $(document.body).append($m); css({ @@ -161,7 +161,7 @@ background: 'white', 'font-size': '18pt', 'font-family': 'Tahoma, arial', - 'box-shadow': '0px 0px 1px #000044', + //'box-shadow': '0px 0px 1px #000044', 'border-radius': '1em', 'text-align': 'center', 'z-index': 999999, diff --git a/lib/radisk.js b/lib/radisk.js index 0c1b82d4..03bdcc6a 100644 --- a/lib/radisk.js +++ b/lib/radisk.js @@ -19,7 +19,7 @@ function ename(t){ return encodeURIComponent(t).replace(/\*/g, '%2A') } function atomic(v){ return u !== v && (!v || 'object' != typeof v) } var map = Gun.obj.map; - var LOG = false; + var LOG = console.LOG; if(!opt.store){ return opt.log("ERROR: Radisk needs `opt.store` interface with `{get: fn, put: fn (, list: fn)}`!"); @@ -46,7 +46,7 @@ cb = val; var S; LOG && (S = +new Date); val = r.batch(key); - LOG && console.log(+new Date - S, 'rad mem'); + LOG && opt.log(S, +new Date - S, 'rad mem'); if(u !== val){ cb(u, r.range(val, o), o); if(atomic(val)){ return } @@ -77,6 +77,7 @@ r.thrash = function(){ var thrash = r.thrash; if(thrash.ing){ return thrash.more = true } + LOG = console.LOG; // dirty place to cheaply update LOG settings over time. thrash.more = false; thrash.ing = true; var batch = thrash.at = r.batch, i = 0; @@ -174,9 +175,9 @@ } f.write = function(){ var tmp = ename(file); - var start; LOG && (start = +new Date); // comment this out! + var S; LOG && (S = +new Date); opt.store.put(tmp, f.text, function(err){ - LOG && console.log("wrote to disk in", (+new Date) - start, tmp); // comment this out! + LOG && opt.log(S, +new Date - S, "wrote disk", tmp); if(err){ return cb(err) } r.list.add(tmp, cb); }); @@ -205,10 +206,10 @@ r.write.jsonify = function(f, file, rad, cb, o){ var raw; - var start; LOG && (start = +new Date); // comment this out! + var S; LOG && (S = +new Date); try{raw = JSON.stringify(rad.$); }catch(e){ return cb("Record too big!") } - LOG && console.log("stringified JSON in", +new Date - start); // comment this out! + LOG && opt.log(S, +new Date - S, "rad stringified JSON"); if(opt.chunk < raw.length && !o.force){ if(Radix.map(rad, f.each, true)){ return } } @@ -234,7 +235,7 @@ if(RAD && !o.next){ // cache var S; LOG && (S = +new Date); var val = RAD(key); - LOG && console.log(+new Date - S, 'rad cached'); + LOG && opt.log(S, +new Date - S, 'rad cached'); //if(u !== val){ //cb(u, val, o); if(atomic(val)){ cb(u, val, o); return } @@ -247,7 +248,7 @@ file = (u === file)? u : decodeURIComponent(file); tmp = o.next || key || (o.reverse? o.end || '\uffff' : o.start || ''); if(!file || (o.reverse? file < tmp : file > tmp)){ - LOG && console.log(+new Date - S, 'rad read lex'); S = +new Date; + LOG && opt.log(S, +new Date - S, 'rad read lex'); S = +new Date; if(o.next || o.reverse){ g.file = file } if(tmp = Q[g.file]){ tmp.push({key: key, ack: cb, file: g.file, opt: o}); @@ -268,9 +269,9 @@ g.info = info; if(disk){ RAD = g.disk = disk } disk = Q[g.file]; delete Q[g.file]; - LOG && console.log(+new Date - S, 'rad read it in, now ack to:', disk.length); S = +new Date; + LOG && opt.log(S, +new Date - S, 'rad read in, ack', disk.length); S = +new Date; map(disk, g.ack); - LOG && console.log(+new Date - S, 'rad read acked'); + LOG && opt.log(S, +new Date - S, 'rad read acked'); } g.ack = function(as){ if(!as.ack){ return } @@ -315,7 +316,7 @@ var p = function Parse(){}, info = {}; p.disk = Radix(); p.read = function(err, data){ var tmp; - LOG && console.log('read disk in', +new Date - S, ename(file)); // keep this commented out in + LOG && opt.log(S, +new Date - S, 'read disk', ename(file)); delete Q[file]; if((p.err = err) || (p.not = !data)){ return map(q, p.ack); @@ -332,12 +333,12 @@ } info.parsed = data.length; - LOG && (S = +new Date); // keep this commented out in production! + LOG && (S = +new Date); if(opt.jsonify || '{' === data[0]){ // temporary testing idea try{ var json = JSON.parse(data); p.disk.$ = json; - LOG && console.log('parsed JSON in', +new Date - S); // keep this commented out in production! + LOG && opt.log(S, +new Date - S, 'rad parsed JSON'); map(q, p.ack); return; }catch(e){ tmp = e } @@ -346,7 +347,7 @@ return map(q, p.ack); } } - LOG && (S = +new Date); // keep this commented out in production! + LOG && (S = +new Date); var tmp = p.split(data), pre = [], i, k, v; if(!tmp || 0 !== tmp[1]){ p.err = "File '"+file+"' does not have root radix! "; @@ -369,7 +370,7 @@ if(u !== k && u !== v){ p.disk(pre.join(''), v) } tmp = p.split(tmp[2]); } - LOG && console.log('parsed RAD in', +new Date - S); // keep this commented out in production! + LOG && opt.log(S, +new Date - S, 'parsed RAD'); //cb(err, p.disk); map(q, p.ack); }; @@ -389,7 +390,7 @@ if(p.err || p.not){ return cb(p.err, u, info) } cb(u, p.disk, info); } - var S; LOG && (S = +new Date); // keep this commented out in production! + var S; LOG && (S = +new Date); if(raw){ return p.read(null, raw) } opt.store.get(ename(file), p.read); } diff --git a/lib/server.js b/lib/server.js index 3ccc7b34..d2f763f4 100644 --- a/lib/server.js +++ b/lib/server.js @@ -6,6 +6,7 @@ if(u === root.opt.super){ root.opt.super = true; } + root.opt.log = root.opt.log || Gun.log; this.to.next(root); }) require('../nts'); diff --git a/lib/stats.js b/lib/stats.js index 5039f05d..5e92afba 100644 --- a/lib/stats.js +++ b/lib/stats.js @@ -39,6 +39,7 @@ Gun.on('opt', function(root){ stats.peers.count = Object.keys(root.opt.peers||{}).length; stats.node = {}; stats.node.count = Object.keys(root.graph||{}).length; + stats.all = all; var dam = root.opt.mesh; if(dam){ stats.dam = {'in': {count: dam.hear.c, done: dam.hear.d, long: dam.hear.long}, 'out': {count: dam.say.c, done: dam.say.d}}; @@ -57,3 +58,14 @@ Gun.on('opt', function(root){ }, 1000 * 15); Object.keys = Object.keys || function(o){ return Gun.obj.map(o, function(v,k,t){t(k)}) } }); + + +var log = Gun.log, all = {}, max = 1000; +Gun.log = function(a,b,c,d){ + if('number' == typeof a && 'number' == typeof b && 'string' == typeof c){ + var tmp = (all[c] || (all[c] = [])); + if(max < tmp.push([a,b])){ all[c] = [] } // reset + return; + } + return log.apply(Gun, arguments); +} \ No newline at end of file diff --git a/lib/store.js b/lib/store.js index 3384e93c..ee98f033 100644 --- a/lib/store.js +++ b/lib/store.js @@ -30,12 +30,12 @@ Gun.on('create', function(root){ val = Radisk.encode(val, null, esc)+'>'+Radisk.encode(Gun.state.is(node, key), null, esc); rad(soul+esc+key, val, (track? ack : u)); }); - //console.log(+new Date - S, 'put loop'); + Gun.log(S, +new Date - S, 'put loop'); function ack(err, ok){ acks--; if(ack.err){ return } if(ack.err = err){ - try{opt.store.stats.put.err = err}catch(e){} // STATS! + //Gun.log(); //try{opt.store.stats.put.err = err}catch(e){} // STATS! root.on('in', {'@': id, err: err}); return; } @@ -45,7 +45,7 @@ Gun.on('create', function(root){ }catch(e){} // STATS! //console.log(+new Date - S, 'put'); S = +new Date; root.on('in', {'@': id, ok: 1}); - //console.log(+new Date - S, 'put sent'); + //console.log(S, +new Date - S, 'put sent'); } }); @@ -89,7 +89,7 @@ Gun.on('create', function(root){ if(err){ opt.store.stats.get.err = err } }catch(e){} // STATS! //if(u === data && o.chunks > 1){ return } // if we already sent a chunk, ignore ending empty responses. // this causes tests to fail. - //console.log(+new Date - S, 'got'); S = +new Date; + Gun.log(S, +new Date - S, 'got'); S = +new Date; // MARK RETURN HERE!!!! Gun.log will always log unless off :/ switch to something like LOG && whatever? if(data){ if(typeof data !== 'string'){ if(o.atom){ @@ -100,11 +100,10 @@ Gun.on('create', function(root){ } if(!graph && data){ each(data, '') } } - //console.log(+new Date - S, 'got prep'); S = +new Date; + Gun.log(S, +new Date - S, 'got prep'); root.on('in', {'@': id, put: graph, '%': o.more? 1 : u, err: err? err : u, _: each}); - //console.log(+new Date - S, 'got sent'); }, o); - //console.log(+new Date - S, 'get call'); + Gun.log(S, +new Date - S, 'get call'); function each(val, has, a,b){ if(!val){ return } has = (key+has).split(esc); diff --git a/src/adapters/localStorage.js b/src/adapters/localStorage.js index 1d0e60cf..99da2e69 100644 --- a/src/adapters/localStorage.js +++ b/src/adapters/localStorage.js @@ -4,7 +4,7 @@ if(typeof Gun === 'undefined'){ return } // TODO: localStorage is Browser only. var root, noop = function(){}, store, u; try{store = (Gun.window||noop).localStorage}catch(e){} if(!store){ - console.log("Warning: No localStorage exists to persist data to!"); + Gun.log("Warning: No localStorage exists to persist data to!"); store = {setItem: function(k,v){this[k]=v}, removeItem: function(k){delete this[k]}, getItem: function(k){return this[k]}}; } /* @@ -110,7 +110,6 @@ Gun.on('create', function(root){ data = Gun.state.to(data, has); } //if(!data && !Gun.obj.empty(opt.peers)){ return } // if data not found, don't ack if there are peers. // Hmm, what if we have peers but we are disconnected? - //console.log("lS get", lex, data); root.on('in', {'@': msg['#'], put: Gun.graph.node(data), how: 'lS', lS: msg.$});// || root.$}); }; Gun.debug? setTimeout(to,1) : to(); diff --git a/src/adapters/mesh.js b/src/adapters/mesh.js index f2596529..0c4ca13e 100644 --- a/src/adapters/mesh.js +++ b/src/adapters/mesh.js @@ -19,15 +19,14 @@ function Mesh(root){ if('[' === tmp){ try{msg = JSON.parse(raw);}catch(e){opt.log('DAM JSON parse error', e)} if(!msg){ return } - //console.log('hear batch length of', msg.length); + LOG && opt.log(msg.length, 'in hear batch'); (function go(){ - var S = +new Date; // STATS! + var S; LOG && (S = +new Date); // STATS! var m, c = 100; // hardcoded for now? while(c-- && (m = msg.shift())){ mesh.hear(m, peer); } - //console.log(+new Date - S, 'hear batch'); - (mesh.hear.long || (mesh.hear.long = [])).push(+new Date - S); + LOG && opt.log(+new Date - S, 'batch heard'); if(!msg.length){ return } puff(go, 0); }()); @@ -38,7 +37,7 @@ function Mesh(root){ }catch(e){return opt.log('DAM JSON parse error', e)} if(!msg){ return } if(!(id = msg['#'])){ id = msg['#'] = Type.text.random(9) } - if(msg.DBG_s){ console.log(+new Date - msg.DBG_s, 'to hear', id) } + if(msg.DBG_s){ opt.log(+new Date - msg.DBG_s, 'to hear', id) } if(dup.check(id)){ return } dup.track(id, true).it = msg; // GUN core also dedups, so `true` is needed. // Does GUN core need to dedup anymore? if(!(hash = msg['##']) && u !== msg.put){ hash = msg['##'] = Type.obj.hash(msg.put) } @@ -54,9 +53,9 @@ function Mesh(root){ } return; } - //var S = +new Date; + var S; LOG && (S = +new Date); root.on('in', msg); - //!msg.nts && console.log(+new Date - S, 'msg', msg['#']); + LOG && !msg.nts && opt.log(+new Date - S, 'msg', msg['#']); return; } } @@ -70,7 +69,7 @@ function Mesh(root){ if(this.to){ this.to.next(msg) } // compatible with middleware adapters. if(!msg){ return false } var id, hash, tmp, raw; - //var S = +new Date; //msg.DBG_s = msg.DBG_s || +new Date; + var S; LOG && (S = +new Date); //msg.DBG_s = msg.DBG_s || +new Date; var meta = msg._||(msg._=function(){}); if(!(id = msg['#'])){ id = msg['#'] = Type.text.random(9) } if(!(hash = msg['##']) && u !== msg.put){ hash = msg['##'] = Type.obj.hash(msg.put) } @@ -84,15 +83,15 @@ function Mesh(root){ } } } - //console.log(+new Date - S, 'mesh say prep'); + LOG && opt.log(+new Date - S, 'say prep'); dup.track(id).it = msg; // track for 9 seconds, default. Earth<->Mars would need more! if(!peer){ peer = (tmp = dup.s[msg['@']]) && (tmp = tmp.it) && (tmp = tmp._) && (tmp = tmp.via) } if(!peer && mesh.way){ return mesh.way(msg) } if(!peer || !peer.id){ message = msg; if(!Type.obj.is(peer || opt.peers)){ return false } - //var S = +new Date; + var S; LOG && (S = +new Date); Type.obj.map(peer || opt.peers, each); // in case peer is a peer list. - //console.log(+new Date - S, 'mesh say loop'); + LOG && opt.log(+new Date - S, 'say loop'); return; } if(!peer.wire && mesh.wire){ mesh.wire(peer) } @@ -116,10 +115,10 @@ function Mesh(root){ peer.batch = peer.tail = null; if(!tmp){ return } if(!tmp.length){ return } // if(3 > tmp.length){ return } // TODO: ^ - //var S = +new Date; + var S; LOG && (S = +new Date); try{tmp = (1 === tmp.length? tmp[0] : JSON.stringify(tmp)); }catch(e){return opt.log('DAM JSON stringify error', e)} - //console.log(+new Date - S, 'mesh flush', tmp.length); + LOG && opt.log(+new Date - S, 'say stringify', tmp.length); if(!tmp){ return } send(tmp, peer); } @@ -129,14 +128,14 @@ function Mesh(root){ // for now - find better place later. function send(raw, peer){ try{ var wire = peer.wire; - //var S = +new Date; + var S; LOG && (S = +new Date); if(peer.say){ peer.say(raw); } else if(wire.send){ wire.send(raw); } - //console.log(+new Date - S, 'wire send', raw.length); + LOG && opt.log(+new Date - S, 'wire send', raw.length); mesh.say.d += raw.length||0; ++mesh.say.c; // STATS! }catch(e){ (peer.queue = peer.queue || []).push(raw); @@ -186,6 +185,7 @@ function Mesh(root){ root.on('bye', peer); var tmp = +(new Date); tmp = (tmp - (peer.met||tmp)); mesh.bye.time = ((mesh.bye.time || tmp) + tmp) / 2; + LOG = console.LOG; // dirty place to cheaply update LOG settings over time. } mesh.hear['!'] = function(msg, peer){ opt.log('Error:', msg.err) } mesh.hear['?'] = function(msg, peer){ @@ -266,6 +266,7 @@ function Mesh(root){ }()); var empty = {}, ok = true, u; +var LOG = console.LOG; try{ module.exports = Mesh }catch(e){} diff --git a/src/get.js b/src/get.js index 68a14167..6aa9591e 100644 --- a/src/get.js +++ b/src/get.js @@ -89,7 +89,6 @@ function soul(gun, cb, opt, as){ function use(msg){ var eve = this, as = eve.as, cat = as.at, root = cat.root, gun = msg.$, at = (gun||{})._ || {}, data = msg.put || at.put, tmp; if((tmp = root.now) && eve !== tmp[as.now]){ return eve.to.next(msg) } - //console.log("USE:", cat.id, cat.soul, cat.has, cat.get, msg, root.mum); //if(at.async && msg.root){ return } //if(at.async === 1 && cat.async !== true){ return } //if(root.stop && root.stop[at.id]){ return } root.stop && (root.stop[at.id] = true); diff --git a/src/put.js b/src/put.js index b74ee08c..ab3d48af 100644 --- a/src/put.js +++ b/src/put.js @@ -177,7 +177,7 @@ function any(soul, as, msg, eve){ as = as.as; if(!msg.$ || !msg.$._){ return } // TODO: Handle if(msg.err){ // TODO: Handle - console.log("Please report this as an issue! Put.any.err"); + Gun.log("Please report this as an issue! Put.any.err"); return; } var at = (msg.$._), data = at.put, opt = as.opt||{}, root, tmp; @@ -186,7 +186,7 @@ function any(soul, as, msg, eve){ if(as.ref !== as.$){ tmp = (as.$._).get || at.get; if(!tmp){ // TODO: Handle - console.log("Please report this as an issue! Put.no.get"); // TODO: BUG!?? + Gun.log("Please report this as an issue! Put.no.get"); // TODO: BUG!?? return; } as.data = obj_put({}, tmp, as.data); diff --git a/src/root.js b/src/root.js index af58dc83..187a3bdc 100644 --- a/src/root.js +++ b/src/root.js @@ -162,20 +162,16 @@ Gun.dup = require('./dup'); // Maybe... in case the in-memory key we have is a local write // we still need to trigger a pull/merge from peers. } else { - //var S = +new Date; node = Gun.obj.copy(node); - //console.log(+new Date - S, 'copy node'); } node = Gun.graph.node(node); tmp = (at||empty).ack; - //var S = +new Date; root.on('in', { '@': msg['#'], how: 'mem', put: node, $: gun }); - //console.log(+new Date - S, 'root got send'); //if(0 < tmp){ return } root.on('get', msg); } diff --git a/test/panic/livestream.js b/test/panic/livestream.js new file mode 100644 index 00000000..41a87161 --- /dev/null +++ b/test/panic/livestream.js @@ -0,0 +1,171 @@ +/* +This is the first in a series of basic networking correctness tests. +Each test itself might be dumb and simple, but built up together, +they prove desired end goals for behavior at scale. +1. (this file) Is a browser write is confirmed as save by multiple peers even if by daisy chain. +2. +*/ + +var config = { + IP: require('ip').address(), + port: 8765, + servers: 1, + browsers: 2, + route: { + '/': __dirname + '/index.html', + '/gun.js': __dirname + '/../../gun.js', + '/jquery.js': __dirname + '/../../examples/jquery.js', + '/livestream.html': __dirname + '/livestream.html', + } +} + +var panic = require('panic-server'); +panic.server().on('request', function(req, res){ + config.route[req.url] && require('fs').createReadStream(config.route[req.url]).pipe(res); +}).listen(config.port); + +var clients = panic.clients; +var manager = require('panic-manager')(); + +manager.start({ + clients: Array(config.servers).fill().map(function(u, i){ + return { + type: 'node', + port: config.port + (i + 1) + } + }), + panic: 'http://' + config.IP + ':' + config.port +}); + +var servers = clients.filter('Node.js'); +var bob = servers.pluck(1); +var browsers = clients.excluding(servers); +var alice = browsers.pluck(1); +var others = clients.excluding(alice); + +describe("Broadcast Video", function(){ + //this.timeout(5 * 60 * 1000); + this.timeout(10 * 60 * 1000); + + it("Servers have joined!", function(){ + return servers.atLeast(config.servers); + }); + + it("GUN started!", function(){ + var tests = [], i = 0; + servers.each(function(client){ + tests.push(client.run(function(test){ + var env = test.props; + test.async(); + try{ require('fs').unlinkSync(env.i+'data') }catch(e){} + try{ require('gun/lib/fsrm')(env.i+'data') }catch(e){} + var server = require('http').createServer(function(req, res){ + res.end("I am "+ env.i +"!"); + }); + var port = env.config.port + env.i; + var Gun = require('gun'); + var peers = [], i = env.config.servers; + while(i--){ + var tmp = (env.config.port + (i + 1)); + if(port != tmp){ // ignore ourselves + peers.push('http://'+ env.config.IP + ':' + tmp + '/gun'); + } + } + console.log(port, " connect to ", peers); + var gun = Gun({file: env.i+'data', peers: peers, web: server}); + server.listen(port, function(){ + test.done(); + }); + }, {i: i += 1, config: config})); + }); + return Promise.all(tests); + }); + + it(config.browsers +" browser(s) have joined!", function(){ + console.log("PLEASE OPEN http://"+ config.IP +":"+ config.port +" IN "+ config.browsers +" BROWSER(S)!"); + return browsers.atLeast(config.browsers); + }); + + it("Browsers load QVDev's streaming!", function(){ + var tests = [], i = 0; + browsers.each(function(client, id){ + tests.push(client.run(function(test){ + test.async(); + console.log("load?"); + function load(src, cb){ + var script = document.createElement('script'); + script.onload = cb; script.src = src; + document.head.appendChild(script); + } + load('https://cdn.jsdelivr.net/gh/QVDev/GunStreamer/js/GunRecorder.js', function(){ + load('https://cdn.jsdelivr.net/gh/QVDev/GunStreamer/js/GunStreamer.js', function(){ + test.done(); + }); + }); + $('body').append(''); + }, {i: i += 1, config: config})); + }); + return Promise.all(tests); + }); + + it("Browsers initialized gun!", function(){ + var tests = [], i = 0; + browsers.each(function(client, id){ + tests.push(client.run(function(test){ + try{ localStorage.clear() }catch(e){} + try{ indexedDB.deleteDatabase('radata') }catch(e){} + var env = test.props; + var gun = Gun('http://'+ env.config.IP + ':' + (env.config.port + 1) + '/gun'); + window.gun = gun; + }, {i: i += 1, config: config})); + }); + return Promise.all(tests); + }); + + it("Stream", function(){ + return alice.run(function(test){ + console.log("I AM ALICE"); + test.async(); + var stream = window.stream = new GunStreamer({ + url: "https://cdn.jsdelivr.net/gh/QVDev/GunStreamer/js/parser_worker.js", + gun: gun, + streamId: 'livestream', + dbRecord: 'streams' + }); + var record = window.record = new GunRecorder({ + mimeType: 'video/webm; codecs="opus,vp8"', + //audioBitsPerSecond: 6000,//Audio bits per second this is the lowest quality + //videoBitsPerSecond: 100000,//Video bits per second this is the lowest quality + cameraOptions: {video:{width: 1280, height: 720, facingMode: "environment", frameRate: 60}, audio: true}, + video_id: "video", + recordInterval: 1000, // how long each chunk? + onRecordStateChange: function(state){ /* change play/pause buttons */ }, + onDataAvailable: function(data){ console.log('r -> s', data); stream.onDataAvailable(data) } // pass recorded data to streamer + }); + record.startCamera(); + $('#video').on('playing', function(eve){ + console.log("YES!!!"); + record.record(); + }); + console.log("start recording!"); + }, {acks: config.servers}); + }); + + it("All finished!", function(done){ + console.log("Done! Cleaning things up..."); + setTimeout(function(){ + done(); + },1000); + }); + + after("Everything shut down.", function(){ + browsers.run(function(){ + //location.reload(); + //setTimeout(function(){ + //}, 15 * 1000); + }); + return servers.run(function(){ + process.exit(); + }); + }); +}); \ No newline at end of file