From be484f83c563349bb66c6dbfcd85414d295be786 Mon Sep 17 00:00:00 2001 From: francisc0j0shua Date: Thu, 12 Apr 2018 19:35:34 +0200 Subject: [PATCH 001/221] Typos in README Just some typos. :smiley: Thanks for all your fantastic work on this project. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a0b470dc..b4cd2e69 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ GUN is a realtime, distributed, offline-first, graph database engine. Doing **[2 ## Why? - - **Realtime** - You might use socketio for realtime updates, but what happens if you reload the page? GUN solves *state synchronization* for you, no matter what, on reloads, across all your users, and even on conflicting updates. + - **Realtime** - You might use Socket.IO for realtime updates, but what happens if you reload the page? GUN solves *state synchronization* for you, no matter what, on reloads, across all your users, and even on conflicting updates. - **Distributed** - GUN is peer-to-peer by design, meaning you have no centralized database server to maintain or that could crash. This lets you sleep through the night without worrying about database DevOps - we call it "NoDB". From there, you can build decentralized, federated, or centralized apps. - **Offline-first** - GUN works even if your internet or cell reception doesn't. Users can still plug away and save data as normal, and then when the network comes back online GUN will automatically synchronize all the changes and handle any conflicts for you. - **Graph** - Most databases force you to bend over backwards to match their storage constraints. But graphs are different, they let you have any data structure you want. Whether that be traditional tables with relations, document oriented trees, or tons of circular references. You choose. @@ -204,7 +204,7 @@ Or, if you prefer your Docker image with metadata labels (Linux/Mac only): ```bash npm run docker -docker run -p 8080:8080 usenameHere/gun:git +docker run -p 8080:8080 username/gun:git ``` Then visit [http://localhost:8080](http://localhost:8080) in your browser. From 44de63dc55668ece95ac277869e91f36e20ab9b9 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Fri, 13 Apr 2018 16:50:54 -0700 Subject: [PATCH 002/221] oops ack critical fix! --- examples/contact/index.html | 2 +- gun.js | 2 +- sea.js | 18 +++++++++--------- test/common.js | 10 +++++++++- 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/examples/contact/index.html b/examples/contact/index.html index 9d119274..704af2a9 100644 --- a/examples/contact/index.html +++ b/examples/contact/index.html @@ -167,7 +167,7 @@ if(!at.put || !at.put.users){ return } var no; Gun.node.is(at.put.users, function(val, key){ - Gun.SEA.read(val, false, function(val){ + Gun.SEA.verify(val, false, function(val){ //Gun.SEA.read(val, false, function(val){ if('alias/'+key === Gun.val.rel.is(val)){ return } no = true; diff --git a/gun.js b/gun.js index d2b6b076..42858394 100644 --- a/gun.js +++ b/gun.js @@ -1281,7 +1281,7 @@ if(typeof cb === 'string'){ as.soul = cb; } else { - as.ack = cb; + as.ack = as.ack || cb; } if(at.soul){ as.soul = at.soul; diff --git a/sea.js b/sea.js index cfbdd039..f78cf3f5 100644 --- a/sea.js +++ b/sea.js @@ -703,6 +703,13 @@ const { epub } = at.put // TODO: 'salt' needed? err = null + if(typeof window !== 'undefined'){ + var tmp = window.sessionStorage; + if(tmp && gunRoot._.opt.remember){ + window.sessionStorage.alias = alias; + window.sessionStorage.tmp = pass; + } + } return Object.assign(props, { priv, salt, epub, epriv }) } catch (e) { err = 'Failed to decrypt secret!' @@ -821,13 +828,6 @@ // persist authentication //await authPersist(user._, key.proof, opts) // temporarily disabled // emit an auth event, useful for page redirects and stuff. - if(typeof window !== 'undefined'){ - var tmp = window.sessionStorage; - if(tmp && gunRoot._.opt.remember){ - window.sessionStorage.alias = alias; - window.sessionStorage.tmp = key; - } - } try { gunRoot._.on('auth', user._) } catch (e) { @@ -1141,8 +1141,8 @@ const salt = Gun.text.random(64); const encSigAuth = await SEA.work(newpass, salt) .then((key) => - SEA.encrypt({ priv, epriv }, { pub, key, set: true }) - .then((auth) => SEA.sign({ salt, auth }, keys)) + SEA.encrypt({ priv, epriv }, key) + .then((auth) => SEA.sign({ek: auth, s: salt}, keys)) ) const signedEpub = await SEA.sign(epub, keys) const signedAlias = await SEA.sign(alias, keys) diff --git a/test/common.js b/test/common.js index 971bd745..96578284 100644 --- a/test/common.js +++ b/test/common.js @@ -3784,10 +3784,18 @@ describe('Gun', function(){ //console.log("put", put); //console.log("------", turns, "-------"); //3 === turns && (console.debug.i = 1); - console.debug(1, 'save', {history: put}); + //console.debug(1, 'save', {history: put}); gun.put({history: put}); }, 1); }); + + it('Check put callback', function(done){ + var gun = Gun(); + + gun.get('c/p/c').get('a').put('lol', function(ack){ + done(); + }); + }); return; it('Nested listener should be called', function(done){ From d42ed3ff9527b069afac46dc8bee60dbe4b1205f Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Thu, 19 Apr 2018 04:06:43 -0700 Subject: [PATCH 003/221] secret --- gun.min.js | 2 +- package.json | 2 +- sea.js | 77 ++++++++++++++++++++++++++++++---------------------- src/put.js | 2 +- 4 files changed, 48 insertions(+), 35 deletions(-) diff --git a/gun.min.js b/gun.min.js index 868cc1e8..8efc3789 100644 --- a/gun.min.js +++ b/gun.min.js @@ -1 +1 @@ -!function(){function t(n){function o(t){return t.split("/").slice(-1).toString().replace(".js","")}return n.slice?t[o(n)]:function(e,i){n(e={exports:{}}),t[o(i)]=e.exports}}var n;"undefined"!=typeof window&&(n=window),"undefined"!=typeof global&&(n=global);var o=(n=n||{}).console||{log:function(){}};if("undefined"!=typeof module)var e=module;t(function(t){var n={};n.fns=n.fn={is:function(t){return!!t&&"function"==typeof t}},n.bi={is:function(t){return t instanceof Boolean||"boolean"==typeof t}},n.num={is:function(t){return!e(t)&&(t-parseFloat(t)+1>=0||1/0===t||-1/0===t)}},n.text={is:function(t){return"string"==typeof t}},n.text.ify=function(t){return n.text.is(t)?t:"undefined"!=typeof JSON?JSON.stringify(t):t&&t.toString?t.toString():t},n.text.random=function(t,n){var o="";for(t=t||24,n=n||"0123456789ABCDEFGHIJKLMNOPQRSTUVWXZabcdefghijklmnopqrstuvwxyz";t>0;)o+=n.charAt(Math.floor(Math.random()*n.length)),t--;return o},n.text.match=function(t,o){var e=!1;if(t=t||"",o=n.text.is(o)?{"=":o}:o||{},n.obj.has(o,"~")&&(t=t.toLowerCase(),o["="]=(o["="]||o["~"]).toLowerCase()),n.obj.has(o,"="))return t===o["="];if(n.obj.has(o,"*")){if(t.slice(0,o["*"].length)!==o["*"])return!1;e=!0,t=t.slice(o["*"].length)}if(n.obj.has(o,"!")){if(t.slice(-o["!"].length)!==o["!"])return!1;e=!0}if(n.obj.has(o,"+")&&n.list.map(n.list.is(o["+"])?o["+"]:[o["+"]],function(n){if(!(t.indexOf(n)>=0))return!0;e=!0}))return!1;if(n.obj.has(o,"-")&&n.list.map(n.list.is(o["-"])?o["-"]:[o["-"]],function(n){if(!(t.indexOf(n)<0))return!0;e=!0}))return!1;if(n.obj.has(o,">")){if(!(t>o[">"]))return!1;e=!0}if(n.obj.has(o,"<")){if(!(to?1:0):0}},n.list.map=function(t,n,o){return a(t,n,o)},n.list.index=1,n.obj={is:function(t){return!!t&&(t instanceof Object&&t.constructor===Object||"Object"===Object.prototype.toString.call(t).match(/^\[object (\w+)\]$/)[1])}},n.obj.put=function(t,n,o){return(t||{})[n]=o,t},n.obj.has=function(t,n){return t&&Object.prototype.hasOwnProperty.call(t,n)},n.obj.del=function(t,n){if(t)return t[n]=null,delete t[n],t},n.obj.as=function(t,n,o,e){return t[n]=t[n]||(e===o?{}:o)},n.obj.ify=function(t){if(r(t))return t;try{t=JSON.parse(t)}catch(n){t={}}return t},function(){function t(t,n){u(this,n)&&o!==this[n]||(this[n]=t)}var o;n.obj.to=function(n,o){return o=o||{},a(n,t,o),o}}(),n.obj.copy=function(t){return t?JSON.parse(JSON.stringify(t)):t},function(){function t(t,n){var o=this.n;if(!o||!(n===o||r(o)&&u(o,n)))return!!n||void 0}n.obj.empty=function(n,o){return!n||!a(n,t,{n:o})}}(),function(){function t(n,o){if(2===arguments.length)return t.r=t.r||{},void(t.r[n]=o);t.r=t.r||[],t.r.push(n)}var i=Object.keys;n.obj.map=function(a,s,f){var c,l,p,g,h,d=0,v=o(s);if(t.r=null,i&&r(a)&&(g=i(a),h=!0),e(a)||g)for(l=(g||a).length;d",o.drift=0,o.is=function(t,n,e){var i=n&&t&&t[y]&&t[y][o._]||e;if(i)return m(i=i[n])?i:-1/0},o.lex=function(){return o().toString(36).replace(".","")},o.ify=function(t,n,e,r,u){if(!t||!t[y]){if(!u)return;t=i.soul.ify(t,u)}var a=g(t[y],o._);return l!==n&&n!==y&&(m(e)&&(a[n]=e),l!==r&&(t[n]=r)),t},o.to=function(t,n,e){var r=t[n];return d(r)&&(r=b(r)),o.ify(e,n,o.is(t,n),r,i.soul(t))},function(){function t(t,n){y!==n&&o.ify(this.o,n,this.s)}o.map=function(n,e,i){var r,u=d(u=n||e)?u:null;return n=_(n=n||e)?n:null,u&&!n?(e=m(e)?e:o(),u[y]=u[y]||{},v(u,t,{o:u,s:e}),u):(i=i||d(e)?e:r,e=m(e)?e:o(),function(o,u,a,s){if(!n)return t.call({o:a,s:e},o,u),o;n.call(i||this||{},o,u,a,s),h(a,u)&&r===a[u]||t.call({o:a,s:e},o,u)})}}();var l,p=e.obj,g=p.as,h=p.has,d=p.is,v=p.map,b=p.copy,m=e.num.is,_=e.fn.is,y=i._;n.exports=o})(t,"./state"),t(function(n){var o=t("./type"),e=t("./val"),i=t("./node"),r={};!function(){function t(t,o){if(!t||o!==i.soul(t)||!i.is(t,this.fn,this.as))return!0;this.cb&&(n.n=t,n.as=this.as,this.cb.call(n.as,t,o,n))}function n(t){t&&i.is(n.n,t,n.as)}r.is=function(n,o,e,i){return!(!n||!s(n)||l(n))&&!g(n,t,{cb:o,fn:e,as:i})}}(),function(){function t(t,o){var r;return(r=p(t,o))?r:(o.env=t,o.soul=a,i.ify(o.obj,n,o)&&(t.graph[e.rel.is(o.rel)]=o.node),o)}function n(n,o,r){var a,s,p=this,g=p.env;if(i._===o&&c(n,e.rel._))return r._;if(a=l(n,o,r,p,g)){if(o||(p.node=p.node||r||{},c(n,i._)&&(p.node._=h(n._)),p.node=i.soul.ify(p.node,e.rel.is(p.rel)),p.rel=p.rel||e.rel.ify(i.soul(p.node))),(s=g.map)&&(s.call(g.as||{},n,o,r,p),c(r,o))){if(n=r[o],u===n)return void f(r,o);if(!(a=l(n,o,r,p,g)))return}if(!o)return p.node;if(!0===a)return n;if((s=t(g,{obj:n,path:p.path.concat(o)})).node)return s.rel}}function a(t){var n=this,o=e.rel.is(n.rel),r=n.env.graph;n.rel=n.rel||e.rel.ify(t),n.rel[e.rel._]=t,n.node&&n.node[i._]&&(n.node[i._][e.rel._]=t),c(r,o)&&(r[t]=r[o],f(r,o))}function l(t,n,i,r,u){var a;return!!e.is(t)||(s(t)?1:(a=u.invalid)?(t=a.call(u.as||{},t,n,i),l(t,n,i,r,u)):(u.err="Invalid value at '"+r.path.concat(n).join(".")+"'!",void(o.list.is(t)&&(u.err+=" Use `.set(item)` instead of an Array."))))}function p(t,n){for(var o,e=t.seen,i=e.length;i--;)if(o=e[i],n.obj===o.obj)return o;e.push(n)}r.ify=function(n,o,i){var r={path:[],obj:n};return o?"string"==typeof o?o={soul:o}:o instanceof Function&&(o.map=o):o={},o.soul&&(r.rel=e.rel.ify(o.soul)),o.graph=o.graph||{},o.seen=o.seen||[],o.as=o.as||i,t(o,r),o.root=r.node,o.graph}}(),r.node=function(t){var n=i.soul(t);if(n)return p({},n,t)},function(){function t(t,n){var o,u;if(i._!==n)(o=e.rel.is(t))?(u=this.opt.seen[o])?this.obj[n]=u:this.obj[n]=this.opt.seen[o]=r.to(this.graph,o,this.opt):this.obj[n]=t;else{if(l(t,e.rel._))return;this.obj[n]=h(t)}}r.to=function(n,o,e){if(n){var i={};return e=e||{seen:{}},g(n[o],t,{obj:i,graph:n,opt:e}),i}}}();o.fn.is;var u,a=o.obj,s=a.is,f=a.del,c=a.has,l=a.empty,p=a.put,g=a.map,h=a.copy;n.exports=r})(t,"./graph"),t(function(n){t("./onto"),n.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."}),i.off()},(this.opt||{}).lack||9e3),o}}})(t,"./ask"),t(function(n){var o=t("./type"),e=o.time.is;n.exports=function(t){var n={s:{}};return t=t||{max:1e3,age:9e3},n.check=function(t){var o;return!!(o=n.s[t])&&(o.pass?o.pass=!1:n.track(t))},n.track=function(i,r){var u=n.s[i]||(n.s[i]={});return u.was=e(),r&&(u.pass=!0),n.to||(n.to=setTimeout(function(){var i=e();o.obj.map(n.s,function(e,r){t.age>i-e.was||o.obj.del(n.s,r)}),n.to=null},t.age+9)),u},n}})(t,"./dup"),t(function(n){function i(t){return t instanceof i?(this._={gun:this}).gun:this instanceof i?i.create(this._={gun:this,opt:t}):new i(t)}i.is=function(t){return t instanceof i},i.version=.9,i.chain=i.prototype,i.chain.toJSON=function(){};var r=t("./type");r.obj.to(r,i),i.HAM=t("./HAM"),i.val=t("./val"),i.node=t("./node"),i.state=t("./state"),i.graph=t("./graph"),i.on=t("./onto"),i.ask=t("./ask"),i.dup=t("./dup"),function(){function t(t){var n,o,e=this.as,r=e.gun;(o=t["#"])||(o=t["#"]=c(9)),(n=e.dup).check(o)||(n.track(o),e.ask(t["@"],t)||(t.get&&i.on.get(t,r),t.put&&i.on.put(t,r)),e.on("out",t))}i.create=function(n){n.root=n.root||n,n.graph=n.graph||{},n.on=n.on||i.on,n.ask=n.ask||i.ask,n.dup=n.dup||i.dup();var o=n.gun.opt(n.opt);return n.once||(n.on("in",t,n),n.on("out",t,n)),n.once=1,o}}(),function(){function t(t,n,o,e){var r=this,u=i.state.is(o,n);if(!u)return r.err="Error: No state on '"+n+"' in node '"+e+"'!";var a=r.graph[e]||_,s=i.state.is(a,n,!0),f=a[n],c=i.HAM(r.machine,u,s,t,f);c.incoming?(r.put[e]=i.state.to(o,n,r.put[e]),(r.diff||(r.diff={}))[e]=i.state.to(o,n,r.diff[e]),r.souls[e]=!0):c.defer&&(r.defer=u<(r.defer||1/0)?u:r.defer)}function n(t,n){var i=this,u=i.gun._,a=(u.next||_)[n];if(a){var s=i.map[n]={put:t,get:n,gun:a.gun},f={ctx:i,msg:s};i.async=!!u.tag.node,i.ack&&(s["@"]=i.ack),d(t,o,f),i.async&&(i.and||u.on("node",function(t){this.to.next(t),t===i.map[t.get]&&(i.souls[t.get]=!1,d(t.put,e,t),d(i.souls,function(t){if(t)return t})||i.c||(i.c=1,this.off(),u.stop={},d(i.map,r,i)))}),i.and=!0,u.on("node",s))}else i.souls[n]=!1}function o(t,n){var o=this.ctx,e=o.graph,r=this.msg,u=r.get,a=r.put,s=r.gun._;e[u]=i.state.to(a,n,e[u]),o.async||(s.put=i.state.to(a,n,s.put))}function e(t,n){var o=this,e=o.put,r=o.gun._;r.put=i.state.to(e,n,r.put)}function r(t,n){t.gun&&t.gun._.on("in",t)}i.on.put=function(o,e){var a=e._,s={gun:e,graph:a.graph,put:{},map:{},souls:{},machine:i.state(),ack:o["@"]};if(i.graph.is(o.put,null,t,s)||(s.err="Error: Invalid graph!"),s.err)return a.on("in",{"@":o["#"],err:i.log(s.err)});d(s.put,n,s),s.async||(a.stop={},d(s.map,r,s)),u!==s.defer&&setTimeout(function(){i.on.put(o,e)},s.defer-s.machine),s.diff&&a.on("put",h(o,{put:s.diff}))},i.on.get=function(t,n){var o=n._,e=t.get[b],r=o.graph[e],u=t.get[m],a=(o.next||(o.next={}))[e];if(!r||!a)return o.on("get",t);if(u){if(!g(r,u))return o.on("get",t);r=i.state.to(r,u)}else r=i.obj.copy(r);r=i.graph.node(r),o.on("in",{"@":t["#"],how:"mem",put:r,gun:n}),o.on("get",t)}}(),i.chain.opt=function(t){t=t||{};var n=this,o=n._,e=t.peers||t;return p(t)||(t={}),p(o.opt)||(o.opt=t),f(e)&&(e=[e]),a(e)&&(e=d(e,function(t,n,o){o(t,{url:t})}),p(o.opt.peers)||(o.opt.peers={}),o.opt.peers=h(e,o.opt.peers)),o.opt.peers=o.opt.peers||{},h(t,o.opt),i.on("opt",o),o.opt.uuid=o.opt.uuid||function(){return v()+c(12)},n};var u,a=i.list.is,s=i.text,f=s.is,c=s.random,l=i.obj,p=l.is,g=l.has,h=l.to,d=l.map,v=(l.copy,i.state.lex),b=i.val.rel._,m=".",_=(i.node._,i.val.rel.is,{});o.debug=function(t,n){return o.debug.i&&t===o.debug.i&&o.debug.i++&&(o.log.apply(o,arguments)||n)},i.log=function(){return!i.log.off&&o.log.apply(o,arguments),[].slice.call(arguments).join(" ")},i.log.once=function(t,n,o){return(o=i.log.once)[t]=o[t]||0,o[t]++||i.log(n)},i.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=i);try{void 0!==e&&(e.exports=i)}catch(t){}n.exports=i})(t,"./root"),t(function(n){var o=t("./root");o.chain.back=function(t,n){if(-1===(t=t||1)||1/0===t)return this._.root.gun;if(1===t)return(this._.back||this._).gun;var r=this,u=r._;if("string"==typeof t&&(t=t.split(".")),!(t instanceof Array)){if(t instanceof Function){for(var a,s={back:u};(s=s.back)&&!(a=t(s,n)););return a}return o.num.is(t)?(u.back||u).gun.back(t-1):this}var f=0,c=t.length,s=u;for(f;f .once, apologies unexpected."),this.once(t,n)},i.chain.once=function(t,n){var o=this,u=o._,a=u.put;if(0=(n.batch||1e3))return s();o||(o=setTimeout(s,n.wait||1))}),t.on("get",function(o){this.to.next(o);var e,i,r=o.get;if(r&&(e=r["#"])){var a=r["."];(i=u[e]||void 0)&&a&&(i=Gun.state.to(i,a)),(i||Gun.obj.empty(n.peers))&&t.on("in",{"@":o["#"],put:Gun.graph.node(i),how:"lS"})}});var a=function(t,n,o,e){u[e]=Gun.state.to(o,n,u[e])},s=function(){var a;r=0,clearTimeout(o),o=!1;var s=i;i={};try{e.setItem(n.file,JSON.stringify(u))}catch(t){Gun.log(a=t||"localStorage failure")}(a||Gun.obj.empty(n.peers))&&Gun.obj.map(s,function(n,o){t.on("in",{"@":o,err:a,ok:0})})}}})}})(t,"./adapters/localStorage"),t(function(n){function o(t){var n=function(){};return n.out=function(o){var e;if(this.to&&this.to.next(o),(e=o["@"])&&(e=t.dup.s[e])&&(e=e.it)&&e.mesh)return n.say(o,e.mesh.via),void(e["##"]=o["##"]);n.say(o)},n.hear=function(o,i){if(o){var r,u,a=t.dup,s=o[0];try{o=JSON.parse(o)}catch(t){}if("{"===s){if(a.check(r=o["#"]))return;if(a.track(r,!0).it=o,(s=o["@"])&&o.put&&(u=o["##"]||(o["##"]=n.hash(o)),(s+=u)!=r)){if(a.check(s))return;(s=a.s)[u]=s[r]}return(o.mesh=function(){}).via=i,(s=o["><"])&&(o.mesh.to=e.obj.map(s.split(","),function(t,n,o){o(t,!0)})),void t.on("in",o)}if("["!==s);else for(var f,c=0;f=o[c++];)n.hear(f,i)}},function(){function o(t,n){var o=n.wire;try{o.send?o.readyState===o.OPEN?o.send(t):(n.queue=n.queue||[]).push(t):n.say&&n.say(t)}catch(o){(n.queue=n.queue||[]).push(t)}}n.say=function(i,u){if(u){var a,s,f;(u.wire||t.opt.wire&&t.opt.wire(u))&&(s=i.mesh||r,u!==s.via&&((f=s.raw)||(f=n.raw(i)),(a=i["@"])&&(a=t.dup.s[a])&&(a=a.it)&&a.get&&a["##"]&&a["##"]===i["##"]||(a=s.to)&&(a[u.url]||a[u.id])||(u.batch?u.batch.push(f):(u.batch=[],setTimeout(function(){var t=u.batch;t&&(u.batch=null,t.length&&o(JSON.stringify(t),u))},t.opt.wait||1),o(f,u)))))}else e.obj.map(t.opt.peers,function(t){n.say(i,t)})}}(),function(){function r(t,n){var o;return n instanceof Object?(e.obj.map(Object.keys(n).sort(),u,{to:o={},on:n}),o):n}function u(t){this.to[t]=this.on[t]}n.raw=function(o){if(!o)return"";var u,f,c,l=t.dup,p=o.mesh||{};if(c=p.raw)return c;if("string"==typeof o)return o;o["@"]&&(c=o.put)&&((f=o["##"])||(u=a(c,r)||"",f=n.hash(o,u),o["##"]=f),(c=l.s)[f=o["@"]+f]=c[o["#"]],o["#"]=f,u&&((o=e.obj.to(o)).put=s));var g=0,h=[];e.obj.map(t.opt.peers,function(t){if(h.push(t.url||t.id),++g>9)return!0}),o["><"]=h.join();var d=a(o);return i!==u&&(d=d.replace('"'+s+'"',u)),p&&(p.raw=d),d},n.hash=function(t,n){return o.hash(n||a(t.put,r)||"")||t["#"]||e.text.random(9)};var a=JSON.stringify,s=":])([:"}(),n.hi=function(o){t.on("hi",o);var i=o.queue;o.queue=[],e.obj.map(i,function(t){n.say(t,o)})},n}var e=t("../type");o.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=0||1/0===t||-1/0===t)}},n.text={is:function(t){return"string"==typeof t}},n.text.ify=function(t){return n.text.is(t)?t:"undefined"!=typeof JSON?JSON.stringify(t):t&&t.toString?t.toString():t},n.text.random=function(t,n){var o="";for(t=t||24,n=n||"0123456789ABCDEFGHIJKLMNOPQRSTUVWXZabcdefghijklmnopqrstuvwxyz";t>0;)o+=n.charAt(Math.floor(Math.random()*n.length)),t--;return o},n.text.match=function(t,o){var e=!1;if(t=t||"",o=n.text.is(o)?{"=":o}:o||{},n.obj.has(o,"~")&&(t=t.toLowerCase(),o["="]=(o["="]||o["~"]).toLowerCase()),n.obj.has(o,"="))return t===o["="];if(n.obj.has(o,"*")){if(t.slice(0,o["*"].length)!==o["*"])return!1;e=!0,t=t.slice(o["*"].length)}if(n.obj.has(o,"!")){if(t.slice(-o["!"].length)!==o["!"])return!1;e=!0}if(n.obj.has(o,"+")&&n.list.map(n.list.is(o["+"])?o["+"]:[o["+"]],function(n){if(!(t.indexOf(n)>=0))return!0;e=!0}))return!1;if(n.obj.has(o,"-")&&n.list.map(n.list.is(o["-"])?o["-"]:[o["-"]],function(n){if(!(t.indexOf(n)<0))return!0;e=!0}))return!1;if(n.obj.has(o,">")){if(!(t>o[">"]))return!1;e=!0}if(n.obj.has(o,"<")){if(!(to?1:0):0}},n.list.map=function(t,n,o){return a(t,n,o)},n.list.index=1,n.obj={is:function(t){return!!t&&(t instanceof Object&&t.constructor===Object||"Object"===Object.prototype.toString.call(t).match(/^\[object (\w+)\]$/)[1])}},n.obj.put=function(t,n,o){return(t||{})[n]=o,t},n.obj.has=function(t,n){return t&&Object.prototype.hasOwnProperty.call(t,n)},n.obj.del=function(t,n){if(t)return t[n]=null,delete t[n],t},n.obj.as=function(t,n,o,e){return t[n]=t[n]||(e===o?{}:o)},n.obj.ify=function(t){if(r(t))return t;try{t=JSON.parse(t)}catch(n){t={}}return t},function(){function t(t,n){u(this,n)&&o!==this[n]||(this[n]=t)}var o;n.obj.to=function(n,o){return o=o||{},a(n,t,o),o}}(),n.obj.copy=function(t){return t?JSON.parse(JSON.stringify(t)):t},function(){function t(t,n){var o=this.n;if(!o||!(n===o||r(o)&&u(o,n)))return!!n||void 0}n.obj.empty=function(n,o){return!n||!a(n,t,{n:o})}}(),function(){function t(n,o){if(2===arguments.length)return t.r=t.r||{},void(t.r[n]=o);t.r=t.r||[],t.r.push(n)}var i=Object.keys;n.obj.map=function(a,s,f){var c,l,p,g,h,d=0,v=o(s);if(t.r=null,i&&r(a)&&(g=i(a),h=!0),e(a)||g)for(l=(g||a).length;d",o.drift=0,o.is=function(t,n,e){var i=n&&t&&t[k]&&t[k][o._]||e;if(i)return m(i=i[n])?i:-1/0},o.lex=function(){return o().toString(36).replace(".","")},o.ify=function(t,n,e,r,u){if(!t||!t[k]){if(!u)return;t=i.soul.ify(t,u)}var a=g(t[k],o._);return l!==n&&n!==k&&(m(e)&&(a[n]=e),l!==r&&(t[n]=r)),t},o.to=function(t,n,e){var r=t[n];return d(r)&&(r=b(r)),o.ify(e,n,o.is(t,n),r,i.soul(t))},function(){function t(t,n){k!==n&&o.ify(this.o,n,this.s)}o.map=function(n,e,i){var r,u=d(u=n||e)?u:null;return n=_(n=n||e)?n:null,u&&!n?(e=m(e)?e:o(),u[k]=u[k]||{},v(u,t,{o:u,s:e}),u):(i=i||d(e)?e:r,e=m(e)?e:o(),function(o,u,a,s){if(!n)return t.call({o:a,s:e},o,u),o;n.call(i||this||{},o,u,a,s),h(a,u)&&r===a[u]||t.call({o:a,s:e},o,u)})}}();var l,p=e.obj,g=p.as,h=p.has,d=p.is,v=p.map,b=p.copy,m=e.num.is,_=e.fn.is,k=i._;n.exports=o})(t,"./state"),t(function(n){var o=t("./type"),e=t("./val"),i=t("./node"),r={};!function(){function t(t,o){if(!t||o!==i.soul(t)||!i.is(t,this.fn,this.as))return!0;this.cb&&(n.n=t,n.as=this.as,this.cb.call(n.as,t,o,n))}function n(t){t&&i.is(n.n,t,n.as)}r.is=function(n,o,e,i){return!(!n||!s(n)||l(n))&&!g(n,t,{cb:o,fn:e,as:i})}}(),function(){function t(t,o){var r;return(r=p(t,o))?r:(o.env=t,o.soul=a,i.ify(o.obj,n,o)&&(t.graph[e.rel.is(o.rel)]=o.node),o)}function n(n,o,r){var a,s,p=this,g=p.env;if(i._===o&&c(n,e.rel._))return r._;if(a=l(n,o,r,p,g)){if(o||(p.node=p.node||r||{},c(n,i._)&&(p.node._=h(n._)),p.node=i.soul.ify(p.node,e.rel.is(p.rel)),p.rel=p.rel||e.rel.ify(i.soul(p.node))),(s=g.map)&&(s.call(g.as||{},n,o,r,p),c(r,o))){if(n=r[o],u===n)return void f(r,o);if(!(a=l(n,o,r,p,g)))return}if(!o)return p.node;if(!0===a)return n;if((s=t(g,{obj:n,path:p.path.concat(o)})).node)return s.rel}}function a(t){var n=this,o=e.rel.is(n.rel),r=n.env.graph;n.rel=n.rel||e.rel.ify(t),n.rel[e.rel._]=t,n.node&&n.node[i._]&&(n.node[i._][e.rel._]=t),c(r,o)&&(r[t]=r[o],f(r,o))}function l(t,n,i,r,u){var a;return!!e.is(t)||(s(t)?1:(a=u.invalid)?(t=a.call(u.as||{},t,n,i),l(t,n,i,r,u)):(u.err="Invalid value at '"+r.path.concat(n).join(".")+"'!",void(o.list.is(t)&&(u.err+=" Use `.set(item)` instead of an Array."))))}function p(t,n){for(var o,e=t.seen,i=e.length;i--;)if(o=e[i],n.obj===o.obj)return o;e.push(n)}r.ify=function(n,o,i){var r={path:[],obj:n};return o?"string"==typeof o?o={soul:o}:o instanceof Function&&(o.map=o):o={},o.soul&&(r.rel=e.rel.ify(o.soul)),o.graph=o.graph||{},o.seen=o.seen||[],o.as=o.as||i,t(o,r),o.root=r.node,o.graph}}(),r.node=function(t){var n=i.soul(t);if(n)return p({},n,t)},function(){function t(t,n){var o,u;if(i._!==n)(o=e.rel.is(t))?(u=this.opt.seen[o])?this.obj[n]=u:this.obj[n]=this.opt.seen[o]=r.to(this.graph,o,this.opt):this.obj[n]=t;else{if(l(t,e.rel._))return;this.obj[n]=h(t)}}r.to=function(n,o,e){if(n){var i={};return e=e||{seen:{}},g(n[o],t,{obj:i,graph:n,opt:e}),i}}}();o.fn.is;var u,a=o.obj,s=a.is,f=a.del,c=a.has,l=a.empty,p=a.put,g=a.map,h=a.copy;n.exports=r})(t,"./graph"),t(function(n){t("./onto"),n.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."}),i.off()},(this.opt||{}).lack||9e3),o}}})(t,"./ask"),t(function(n){var o=t("./type"),e=o.time.is;n.exports=function(t){var n={s:{}};return t=t||{max:1e3,age:9e3},n.check=function(t){var o;return!!(o=n.s[t])&&(o.pass?o.pass=!1:n.track(t))},n.track=function(i,r){var u=n.s[i]||(n.s[i]={});return u.was=e(),r&&(u.pass=!0),n.to||(n.to=setTimeout(function(){var i=e();o.obj.map(n.s,function(e,r){t.age>i-e.was||o.obj.del(n.s,r)}),n.to=null},t.age+9)),u},n}})(t,"./dup"),t(function(n){function i(t){return t instanceof i?(this._={gun:this}).gun:this instanceof i?i.create(this._={gun:this,opt:t}):new i(t)}i.is=function(t){return t instanceof i},i.version=.9,i.chain=i.prototype,i.chain.toJSON=function(){};var r=t("./type");r.obj.to(r,i),i.HAM=t("./HAM"),i.val=t("./val"),i.node=t("./node"),i.state=t("./state"),i.graph=t("./graph"),i.on=t("./onto"),i.ask=t("./ask"),i.dup=t("./dup"),function(){function t(t){var n,o,e=this.as,r=e.gun;(o=t["#"])||(o=t["#"]=c(9)),(n=e.dup).check(o)||(n.track(o),e.ask(t["@"],t)||(t.get&&i.on.get(t,r),t.put&&i.on.put(t,r)),e.on("out",t))}i.create=function(n){n.root=n.root||n,n.graph=n.graph||{},n.on=n.on||i.on,n.ask=n.ask||i.ask,n.dup=n.dup||i.dup();var o=n.gun.opt(n.opt);return n.once||(n.on("in",t,n),n.on("out",t,n)),n.once=1,o}}(),function(){function t(t,n,o,e){var r=this,u=i.state.is(o,n);if(!u)return r.err="Error: No state on '"+n+"' in node '"+e+"'!";var a=r.graph[e]||_,s=i.state.is(a,n,!0),f=a[n],c=i.HAM(r.machine,u,s,t,f);c.incoming?(r.put[e]=i.state.to(o,n,r.put[e]),(r.diff||(r.diff={}))[e]=i.state.to(o,n,r.diff[e]),r.souls[e]=!0):c.defer&&(r.defer=u<(r.defer||1/0)?u:r.defer)}function n(t,n){var i=this,u=i.gun._,a=(u.next||_)[n];if(a){var s=i.map[n]={put:t,get:n,gun:a.gun},f={ctx:i,msg:s};i.async=!!u.tag.node,i.ack&&(s["@"]=i.ack),d(t,o,f),i.async&&(i.and||u.on("node",function(t){this.to.next(t),t===i.map[t.get]&&(i.souls[t.get]=!1,d(t.put,e,t),d(i.souls,function(t){if(t)return t})||i.c||(i.c=1,this.off(),u.stop={},d(i.map,r,i)))}),i.and=!0,u.on("node",s))}else i.souls[n]=!1}function o(t,n){var o=this.ctx,e=o.graph,r=this.msg,u=r.get,a=r.put,s=r.gun._;e[u]=i.state.to(a,n,e[u]),o.async||(s.put=i.state.to(a,n,s.put))}function e(t,n){var o=this,e=o.put,r=o.gun._;r.put=i.state.to(e,n,r.put)}function r(t,n){t.gun&&t.gun._.on("in",t)}i.on.put=function(o,e){var a=e._,s={gun:e,graph:a.graph,put:{},map:{},souls:{},machine:i.state(),ack:o["@"]};if(i.graph.is(o.put,null,t,s)||(s.err="Error: Invalid graph!"),s.err)return a.on("in",{"@":o["#"],err:i.log(s.err)});d(s.put,n,s),s.async||(a.stop={},d(s.map,r,s)),u!==s.defer&&setTimeout(function(){i.on.put(o,e)},s.defer-s.machine),s.diff&&a.on("put",h(o,{put:s.diff}))},i.on.get=function(t,n){var o=n._,e=t.get[b],r=o.graph[e],u=t.get[m],a=(o.next||(o.next={}))[e];if(!r||!a)return o.on("get",t);if(u){if(!g(r,u))return o.on("get",t);r=i.state.to(r,u)}else r=i.obj.copy(r);r=i.graph.node(r),o.on("in",{"@":t["#"],how:"mem",put:r,gun:n}),o.on("get",t)}}(),i.chain.opt=function(t){t=t||{};var n=this,o=n._,e=t.peers||t;return p(t)||(t={}),p(o.opt)||(o.opt=t),f(e)&&(e=[e]),a(e)&&(e=d(e,function(t,n,o){o(t,{url:t})}),p(o.opt.peers)||(o.opt.peers={}),o.opt.peers=h(e,o.opt.peers)),o.opt.peers=o.opt.peers||{},h(t,o.opt),i.on("opt",o),o.opt.uuid=o.opt.uuid||function(){return v()+c(12)},n};var u,a=i.list.is,s=i.text,f=s.is,c=s.random,l=i.obj,p=l.is,g=l.has,h=l.to,d=l.map,v=(l.copy,i.state.lex),b=i.val.rel._,m=".",_=(i.node._,i.val.rel.is,{});o.debug=function(t,n){return o.debug.i&&t===o.debug.i&&o.debug.i++&&(o.log.apply(o,arguments)||n)},i.log=function(){return!i.log.off&&o.log.apply(o,arguments),[].slice.call(arguments).join(" ")},i.log.once=function(t,n,o){return(o=i.log.once)[t]=o[t]||0,o[t]++||i.log(n)},i.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=i);try{void 0!==e&&(e.exports=i)}catch(t){}n.exports=i})(t,"./root"),t(function(n){var o=t("./root");o.chain.back=function(t,n){if(-1===(t=t||1)||1/0===t)return this._.root.gun;if(1===t)return(this._.back||this._).gun;var r=this,u=r._;if("string"==typeof t&&(t=t.split(".")),!(t instanceof Array)){if(t instanceof Function){for(var a,s={back:u};(s=s.back)&&!(a=t(s,n)););return a}return o.num.is(t)?(u.back||u).gun.back(t-1):this}var f=0,c=t.length,s=u;for(f;f .once, apologies unexpected."),this.once(t,n)},i.chain.once=function(t,n){var o=this,u=o._,a=u.put;if(0=(n.batch||1e3))return s();o||(o=setTimeout(s,n.wait||1))}),t.on("get",function(o){this.to.next(o);var e,i,r=o.get;if(r&&(e=r["#"])){var a=r["."];(i=u[e]||void 0)&&a&&(i=Gun.state.to(i,a)),(i||Gun.obj.empty(n.peers))&&t.on("in",{"@":o["#"],put:Gun.graph.node(i),how:"lS"})}});var a=function(t,n,o,e){u[e]=Gun.state.to(o,n,u[e])},s=function(){var a;r=0,clearTimeout(o),o=!1;var s=i;i={};try{e.setItem(n.file,JSON.stringify(u))}catch(t){Gun.log(a=t||"localStorage failure")}(a||Gun.obj.empty(n.peers))&&Gun.obj.map(s,function(n,o){t.on("in",{"@":o,err:a,ok:0})})}}})}})(t,"./adapters/localStorage"),t(function(n){function o(t){var n=function(){};return n.out=function(o){var e;if(this.to&&this.to.next(o),(e=o["@"])&&(e=t.dup.s[e])&&(e=e.it)&&e.mesh)return n.say(o,e.mesh.via),void(e["##"]=o["##"]);n.say(o)},n.hear=function(o,i){if(o){var r,u,a=t.dup,s=o[0];try{o=JSON.parse(o)}catch(t){}if("{"===s){if(a.check(r=o["#"]))return;if(a.track(r,!0).it=o,(s=o["@"])&&o.put&&(u=o["##"]||(o["##"]=n.hash(o)),(s+=u)!=r)){if(a.check(s))return;(s=a.s)[u]=s[r]}return(o.mesh=function(){}).via=i,(s=o["><"])&&(o.mesh.to=e.obj.map(s.split(","),function(t,n,o){o(t,!0)})),void t.on("in",o)}if("["!==s);else for(var f,c=0;f=o[c++];)n.hear(f,i)}},function(){function o(t,n){var o=n.wire;try{o.send?o.readyState===o.OPEN?o.send(t):(n.queue=n.queue||[]).push(t):n.say&&n.say(t)}catch(o){(n.queue=n.queue||[]).push(t)}}n.say=function(i,u){if(u){var a,s,f;(u.wire||t.opt.wire&&t.opt.wire(u))&&(s=i.mesh||r,u!==s.via&&((f=s.raw)||(f=n.raw(i)),(a=i["@"])&&(a=t.dup.s[a])&&(a=a.it)&&a.get&&a["##"]&&a["##"]===i["##"]||(a=s.to)&&(a[u.url]||a[u.id])||(u.batch?u.batch.push(f):(u.batch=[],setTimeout(function(){var t=u.batch;t&&(u.batch=null,t.length&&o(JSON.stringify(t),u))},t.opt.wait||1),o(f,u)))))}else e.obj.map(t.opt.peers,function(t){n.say(i,t)})}}(),function(){function r(t,n){var o;return n instanceof Object?(e.obj.map(Object.keys(n).sort(),u,{to:o={},on:n}),o):n}function u(t){this.to[t]=this.on[t]}n.raw=function(o){if(!o)return"";var u,f,c,l=t.dup,p=o.mesh||{};if(c=p.raw)return c;if("string"==typeof o)return o;o["@"]&&(c=o.put)&&((f=o["##"])||(u=a(c,r)||"",f=n.hash(o,u),o["##"]=f),(c=l.s)[f=o["@"]+f]=c[o["#"]],o["#"]=f,u&&((o=e.obj.to(o)).put=s));var g=0,h=[];e.obj.map(t.opt.peers,function(t){if(h.push(t.url||t.id),++g>9)return!0}),o["><"]=h.join();var d=a(o);return i!==u&&(d=d.replace('"'+s+'"',u)),p&&(p.raw=d),d},n.hash=function(t,n){return o.hash(n||a(t.put,r)||"")||t["#"]||e.text.random(9)};var a=JSON.stringify,s=":])([:"}(),n.hi=function(o){t.on("hi",o);var i=o.queue;o.queue=[],e.obj.map(i,function(t){n.say(t,o)})},n}var e=t("../type");o.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 { try { + const pub = key.epub || key + const epub = pair.epub + const epriv = pair.epriv + const ecdhSubtle = shim.ossl || shim.subtle + const pubKeyData = keysToEcdhJwk(pub) + const props = { + ...S.ecdh, + public: await ecdhSubtle.importKey(...pubKeyData, true, []) + } + const privKeyData = keysToEcdhJwk(epub, epriv) + const derived = await ecdhSubtle.importKey(...privKeyData, false, ['deriveKey']) + .then(async (privKey) => { + // privateKey scope doesn't leak out from here! + const derivedKey = await ecdhSubtle.deriveKey(props, privKey, { name: 'AES-CBC', length: 256 }, true, [ 'encrypt', 'decrypt' ]) + return ecdhSubtle.exportKey('jwk', derivedKey).then(({ k }) => k) + }) + const r = derived; + if(cb){ cb(r) } + return r; + } catch(e) { + SEA.err = e; + if(cb){ cb() } + return; + }} + + const keysToEcdhJwk = (pub, d) => { // d === priv + //const [ x, y ] = Buffer.from(pub, 'base64').toString('utf8').split(':') // old + const [ x, y ] = pub.split('.') // new + const jwk = d ? { d } : {} + return [ // Use with spread returned value... + 'jwk', + { ...jwk, x, y, kty: 'EC', crv: 'P-256', ext: true }, // ??? refactor + S.ecdh + ] + } + + module.exports = SEA.secret; + })(USE, './secret'); + ;USE(function(module){ // Old Code... const { @@ -569,38 +614,6 @@ throw e } } - // Derive shared secret from other's pub and my epub/epriv - SEA.derive = async (pub, { epub, epriv }) => { - try { - const ecdhSubtle = ossl || subtle - const keysToEcdhJwk = (pub, d) => { // d === priv - const [ x, y ] = Buffer.from(pub, 'base64').toString('utf8').split(':') - const jwk = d ? { d } : {} - return [ // Use with spread returned value... - 'jwk', - { ...jwk, x, y, kty: 'EC', crv: 'P-256', ext: true }, - ecdhKeyProps - ] - } - const pubKeyData = keysToEcdhJwk(pub) - const props = { - ...ecdhKeyProps, - public: await ecdhSubtle.importKey(...pubKeyData, true, []) - } - const privKeyData = keysToEcdhJwk(epub, epriv) - const derived = await ecdhSubtle.importKey(...privKeyData, false, ['deriveKey']) - .then(async (privKey) => { - // privateKey scope doesn't leak out from here! - const derivedKey = await ecdhSubtle.deriveKey(props, privKey, { name: 'AES-CBC', length: 256 }, true, [ 'encrypt', 'decrypt' ]) - return ecdhSubtle.exportKey('jwk', derivedKey).then(({ k }) => k) - }) - return derived - } catch (e) { - console.log(e) - throw e - } - } - // all done! // Obviously it is missing MANY necessary features. This is only an alpha release. // Please experiment with it, audit what I've done so far, and complain about what needs to be added. diff --git a/src/put.js b/src/put.js index a541aeb8..b277f14d 100644 --- a/src/put.js +++ b/src/put.js @@ -11,7 +11,7 @@ Gun.chain.put = function(data, cb, as){ if(typeof cb === 'string'){ as.soul = cb; } else { - as.ack = cb; + as.ack = as.ack || cb; } if(at.soul){ as.soul = at.soul; From c1c00595b83ad84a6fd4dafe79f556ad0d4172c7 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Thu, 19 Apr 2018 04:13:55 -0700 Subject: [PATCH 004/221] secret, clean --- lib/cryptomodules.js | 2005 +----------------------------------------- lib/s3.js | 102 --- lib/serve.mjs | 41 - lib/server.mjs | 7 - sea/authenticate.js | 7 + sea/login.js | 7 - sea/sea.js | 32 - sea/secret.js | 44 + sea/user.js | 4 +- 9 files changed, 54 insertions(+), 2195 deletions(-) delete mode 100644 lib/s3.js delete mode 100644 lib/serve.mjs delete mode 100644 lib/server.mjs create mode 100644 sea/secret.js diff --git a/lib/cryptomodules.js b/lib/cryptomodules.js index dd5ccc49..a45dab32 100644 --- a/lib/cryptomodules.js +++ b/lib/cryptomodules.js @@ -1,2004 +1 @@ -(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.buffer = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 0) { - throw new Error('Invalid string. Length must be a multiple of 4') - } - - // the number of equal signs (place holders) - // if there are two placeholders, than the two characters before it - // represent one byte - // if there is only one, then the three characters before it represent 2 bytes - // this is just a cheap hack to not do indexOf twice - return b64[len - 2] === '=' ? 2 : b64[len - 1] === '=' ? 1 : 0 -} - -function byteLength (b64) { - // base64 is 4/3 + up to two characters of the original data - return b64.length * 3 / 4 - placeHoldersCount(b64) -} - -function toByteArray (b64) { - var i, j, l, tmp, placeHolders, arr - var len = b64.length - placeHolders = placeHoldersCount(b64) - - arr = new Arr(len * 3 / 4 - placeHolders) - - // if there are placeholders, only get up to the last complete 4 chars - l = placeHolders > 0 ? len - 4 : len - - var L = 0 - - for (i = 0, j = 0; i < l; i += 4, j += 3) { - tmp = (revLookup[b64.charCodeAt(i)] << 18) | (revLookup[b64.charCodeAt(i + 1)] << 12) | (revLookup[b64.charCodeAt(i + 2)] << 6) | revLookup[b64.charCodeAt(i + 3)] - arr[L++] = (tmp >> 16) & 0xFF - arr[L++] = (tmp >> 8) & 0xFF - arr[L++] = tmp & 0xFF - } - - if (placeHolders === 2) { - tmp = (revLookup[b64.charCodeAt(i)] << 2) | (revLookup[b64.charCodeAt(i + 1)] >> 4) - arr[L++] = tmp & 0xFF - } else if (placeHolders === 1) { - tmp = (revLookup[b64.charCodeAt(i)] << 10) | (revLookup[b64.charCodeAt(i + 1)] << 4) | (revLookup[b64.charCodeAt(i + 2)] >> 2) - arr[L++] = (tmp >> 8) & 0xFF - arr[L++] = tmp & 0xFF - } - - return arr -} - -function tripletToBase64 (num) { - return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F] -} - -function encodeChunk (uint8, start, end) { - var tmp - var output = [] - for (var i = start; i < end; i += 3) { - tmp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2]) - output.push(tripletToBase64(tmp)) - } - return output.join('') -} - -function fromByteArray (uint8) { - var tmp - var len = uint8.length - var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes - var output = '' - var parts = [] - var maxChunkLength = 16383 // must be multiple of 3 - - // go through the array every three bytes, we'll deal with trailing stuff later - for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) { - parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength))) - } - - // pad the end with zeros, but make sure to not forget the extra bytes - if (extraBytes === 1) { - tmp = uint8[len - 1] - output += lookup[tmp >> 2] - output += lookup[(tmp << 4) & 0x3F] - output += '==' - } else if (extraBytes === 2) { - tmp = (uint8[len - 2] << 8) + (uint8[len - 1]) - output += lookup[tmp >> 10] - output += lookup[(tmp >> 4) & 0x3F] - output += lookup[(tmp << 2) & 0x3F] - output += '=' - } - - parts.push(output) - - return parts.join('') -} - -},{}],2:[function(require,module,exports){ -exports.read = function (buffer, offset, isLE, mLen, nBytes) { - var e, m - var eLen = nBytes * 8 - mLen - 1 - var eMax = (1 << eLen) - 1 - var eBias = eMax >> 1 - var nBits = -7 - var i = isLE ? (nBytes - 1) : 0 - var d = isLE ? -1 : 1 - var s = buffer[offset + i] - - i += d - - e = s & ((1 << (-nBits)) - 1) - s >>= (-nBits) - nBits += eLen - for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {} - - m = e & ((1 << (-nBits)) - 1) - e >>= (-nBits) - nBits += mLen - for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {} - - if (e === 0) { - e = 1 - eBias - } else if (e === eMax) { - return m ? NaN : ((s ? -1 : 1) * Infinity) - } else { - m = m + Math.pow(2, mLen) - e = e - eBias - } - return (s ? -1 : 1) * m * Math.pow(2, e - mLen) -} - -exports.write = function (buffer, value, offset, isLE, mLen, nBytes) { - var e, m, c - var eLen = nBytes * 8 - mLen - 1 - var eMax = (1 << eLen) - 1 - var eBias = eMax >> 1 - var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0) - var i = isLE ? 0 : (nBytes - 1) - var d = isLE ? 1 : -1 - var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0 - - value = Math.abs(value) - - if (isNaN(value) || value === Infinity) { - m = isNaN(value) ? 1 : 0 - e = eMax - } else { - e = Math.floor(Math.log(value) / Math.LN2) - if (value * (c = Math.pow(2, -e)) < 1) { - e-- - c *= 2 - } - if (e + eBias >= 1) { - value += rt / c - } else { - value += rt * Math.pow(2, 1 - eBias) - } - if (value * c >= 2) { - e++ - c /= 2 - } - - if (e + eBias >= eMax) { - m = 0 - e = eMax - } else if (e + eBias >= 1) { - m = (value * c - 1) * Math.pow(2, mLen) - e = e + eBias - } else { - m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen) - e = 0 - } - } - - for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {} - - e = (e << mLen) | m - eLen += mLen - for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {} - - buffer[offset + i - d] |= s * 128 -} - -},{}],3:[function(require,module,exports){ -var toString = {}.toString; - -module.exports = Array.isArray || function (arr) { - return toString.call(arr) == '[object Array]'; -}; - -},{}],"buffer":[function(require,module,exports){ -(function (global){ -/*! - * The buffer module from node.js, for the browser. - * - * @author Feross Aboukhadijeh - * @license MIT - */ -/* eslint-disable no-proto */ - -'use strict' - -var base64 = require('base64-js') -var ieee754 = require('ieee754') -var isArray = require('isarray') - -exports.Buffer = Buffer -exports.SlowBuffer = SlowBuffer -exports.INSPECT_MAX_BYTES = 50 - -/** - * If `Buffer.TYPED_ARRAY_SUPPORT`: - * === true Use Uint8Array implementation (fastest) - * === false Use Object implementation (most compatible, even IE6) - * - * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+, - * Opera 11.6+, iOS 4.2+. - * - * Due to various browser bugs, sometimes the Object implementation will be used even - * when the browser supports typed arrays. - * - * Note: - * - * - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances, - * See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438. - * - * - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function. - * - * - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of - * incorrect length in some situations. - - * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they - * get the Object implementation, which is slower but behaves correctly. - */ -Buffer.TYPED_ARRAY_SUPPORT = global.TYPED_ARRAY_SUPPORT !== undefined - ? global.TYPED_ARRAY_SUPPORT - : typedArraySupport() - -/* - * Export kMaxLength after typed array support is determined. - */ -exports.kMaxLength = kMaxLength() - -function typedArraySupport () { - try { - var arr = new Uint8Array(1) - arr.__proto__ = {__proto__: Uint8Array.prototype, foo: function () { return 42 }} - return arr.foo() === 42 && // typed array instances can be augmented - typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray` - arr.subarray(1, 1).byteLength === 0 // ie10 has broken `subarray` - } catch (e) { - return false - } -} - -function kMaxLength () { - return Buffer.TYPED_ARRAY_SUPPORT - ? 0x7fffffff - : 0x3fffffff -} - -function createBuffer (that, length) { - if (kMaxLength() < length) { - throw new RangeError('Invalid typed array length') - } - if (Buffer.TYPED_ARRAY_SUPPORT) { - // Return an augmented `Uint8Array` instance, for best performance - that = new Uint8Array(length) - that.__proto__ = Buffer.prototype - } else { - // Fallback: Return an object instance of the Buffer class - if (that === null) { - that = new Buffer(length) - } - that.length = length - } - - return that -} - -/** - * The Buffer constructor returns instances of `Uint8Array` that have their - * prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of - * `Uint8Array`, so the returned instances will have all the node `Buffer` methods - * and the `Uint8Array` methods. Square bracket notation works as expected -- it - * returns a single octet. - * - * The `Uint8Array` prototype remains unmodified. - */ - -function Buffer (arg, encodingOrOffset, length) { - if (!Buffer.TYPED_ARRAY_SUPPORT && !(this instanceof Buffer)) { - return new Buffer(arg, encodingOrOffset, length) - } - - // Common case. - if (typeof arg === 'number') { - if (typeof encodingOrOffset === 'string') { - throw new Error( - 'If encoding is specified then the first argument must be a string' - ) - } - return allocUnsafe(this, arg) - } - return from(this, arg, encodingOrOffset, length) -} - -Buffer.poolSize = 8192 // not used by this implementation - -// TODO: Legacy, not needed anymore. Remove in next major version. -Buffer._augment = function (arr) { - arr.__proto__ = Buffer.prototype - return arr -} - -function from (that, value, encodingOrOffset, length) { - if (typeof value === 'number') { - throw new TypeError('"value" argument must not be a number') - } - - if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) { - return fromArrayBuffer(that, value, encodingOrOffset, length) - } - - if (typeof value === 'string') { - return fromString(that, value, encodingOrOffset) - } - - return fromObject(that, value) -} - -/** - * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError - * if value is a number. - * Buffer.from(str[, encoding]) - * Buffer.from(array) - * Buffer.from(buffer) - * Buffer.from(arrayBuffer[, byteOffset[, length]]) - **/ -Buffer.from = function (value, encodingOrOffset, length) { - return from(null, value, encodingOrOffset, length) -} - -if (Buffer.TYPED_ARRAY_SUPPORT) { - Buffer.prototype.__proto__ = Uint8Array.prototype - Buffer.__proto__ = Uint8Array - if (typeof Symbol !== 'undefined' && Symbol.species && - Buffer[Symbol.species] === Buffer) { - // Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97 - Object.defineProperty(Buffer, Symbol.species, { - value: null, - configurable: true - }) - } -} - -function assertSize (size) { - if (typeof size !== 'number') { - throw new TypeError('"size" argument must be a number') - } else if (size < 0) { - throw new RangeError('"size" argument must not be negative') - } -} - -function alloc (that, size, fill, encoding) { - assertSize(size) - if (size <= 0) { - return createBuffer(that, size) - } - if (fill !== undefined) { - // Only pay attention to encoding if it's a string. This - // prevents accidentally sending in a number that would - // be interpretted as a start offset. - return typeof encoding === 'string' - ? createBuffer(that, size).fill(fill, encoding) - : createBuffer(that, size).fill(fill) - } - return createBuffer(that, size) -} - -/** - * Creates a new filled Buffer instance. - * alloc(size[, fill[, encoding]]) - **/ -Buffer.alloc = function (size, fill, encoding) { - return alloc(null, size, fill, encoding) -} - -function allocUnsafe (that, size) { - assertSize(size) - that = createBuffer(that, size < 0 ? 0 : checked(size) | 0) - if (!Buffer.TYPED_ARRAY_SUPPORT) { - for (var i = 0; i < size; ++i) { - that[i] = 0 - } - } - return that -} - -/** - * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance. - * */ -Buffer.allocUnsafe = function (size) { - return allocUnsafe(null, size) -} -/** - * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance. - */ -Buffer.allocUnsafeSlow = function (size) { - return allocUnsafe(null, size) -} - -function fromString (that, string, encoding) { - if (typeof encoding !== 'string' || encoding === '') { - encoding = 'utf8' - } - - if (!Buffer.isEncoding(encoding)) { - throw new TypeError('"encoding" must be a valid string encoding') - } - - var length = byteLength(string, encoding) | 0 - that = createBuffer(that, length) - - var actual = that.write(string, encoding) - - if (actual !== length) { - // Writing a hex string, for example, that contains invalid characters will - // cause everything after the first invalid character to be ignored. (e.g. - // 'abxxcd' will be treated as 'ab') - that = that.slice(0, actual) - } - - return that -} - -function fromArrayLike (that, array) { - var length = array.length < 0 ? 0 : checked(array.length) | 0 - that = createBuffer(that, length) - for (var i = 0; i < length; i += 1) { - that[i] = array[i] & 255 - } - return that -} - -function fromArrayBuffer (that, array, byteOffset, length) { - array.byteLength // this throws if `array` is not a valid ArrayBuffer - - if (byteOffset < 0 || array.byteLength < byteOffset) { - throw new RangeError('\'offset\' is out of bounds') - } - - if (array.byteLength < byteOffset + (length || 0)) { - throw new RangeError('\'length\' is out of bounds') - } - - if (byteOffset === undefined && length === undefined) { - array = new Uint8Array(array) - } else if (length === undefined) { - array = new Uint8Array(array, byteOffset) - } else { - array = new Uint8Array(array, byteOffset, length) - } - - if (Buffer.TYPED_ARRAY_SUPPORT) { - // Return an augmented `Uint8Array` instance, for best performance - that = array - that.__proto__ = Buffer.prototype - } else { - // Fallback: Return an object instance of the Buffer class - that = fromArrayLike(that, array) - } - return that -} - -function fromObject (that, obj) { - if (Buffer.isBuffer(obj)) { - var len = checked(obj.length) | 0 - that = createBuffer(that, len) - - if (that.length === 0) { - return that - } - - obj.copy(that, 0, 0, len) - return that - } - - if (obj) { - if ((typeof ArrayBuffer !== 'undefined' && - obj.buffer instanceof ArrayBuffer) || 'length' in obj) { - if (typeof obj.length !== 'number' || isnan(obj.length)) { - return createBuffer(that, 0) - } - return fromArrayLike(that, obj) - } - - if (obj.type === 'Buffer' && isArray(obj.data)) { - return fromArrayLike(that, obj.data) - } - } - - throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.') -} - -function checked (length) { - // Note: cannot use `length < kMaxLength()` here because that fails when - // length is NaN (which is otherwise coerced to zero.) - if (length >= kMaxLength()) { - throw new RangeError('Attempt to allocate Buffer larger than maximum ' + - 'size: 0x' + kMaxLength().toString(16) + ' bytes') - } - return length | 0 -} - -function SlowBuffer (length) { - if (+length != length) { // eslint-disable-line eqeqeq - length = 0 - } - return Buffer.alloc(+length) -} - -Buffer.isBuffer = function isBuffer (b) { - return !!(b != null && b._isBuffer) -} - -Buffer.compare = function compare (a, b) { - if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) { - throw new TypeError('Arguments must be Buffers') - } - - if (a === b) return 0 - - var x = a.length - var y = b.length - - for (var i = 0, len = Math.min(x, y); i < len; ++i) { - if (a[i] !== b[i]) { - x = a[i] - y = b[i] - break - } - } - - if (x < y) return -1 - if (y < x) return 1 - return 0 -} - -Buffer.isEncoding = function isEncoding (encoding) { - switch (String(encoding).toLowerCase()) { - case 'hex': - case 'utf8': - case 'utf-8': - case 'ascii': - case 'latin1': - case 'binary': - case 'base64': - case 'ucs2': - case 'ucs-2': - case 'utf16le': - case 'utf-16le': - return true - default: - return false - } -} - -Buffer.concat = function concat (list, length) { - if (!isArray(list)) { - throw new TypeError('"list" argument must be an Array of Buffers') - } - - if (list.length === 0) { - return Buffer.alloc(0) - } - - var i - if (length === undefined) { - length = 0 - for (i = 0; i < list.length; ++i) { - length += list[i].length - } - } - - var buffer = Buffer.allocUnsafe(length) - var pos = 0 - for (i = 0; i < list.length; ++i) { - var buf = list[i] - if (!Buffer.isBuffer(buf)) { - throw new TypeError('"list" argument must be an Array of Buffers') - } - buf.copy(buffer, pos) - pos += buf.length - } - return buffer -} - -function byteLength (string, encoding) { - if (Buffer.isBuffer(string)) { - return string.length - } - if (typeof ArrayBuffer !== 'undefined' && typeof ArrayBuffer.isView === 'function' && - (ArrayBuffer.isView(string) || string instanceof ArrayBuffer)) { - return string.byteLength - } - if (typeof string !== 'string') { - string = '' + string - } - - var len = string.length - if (len === 0) return 0 - - // Use a for loop to avoid recursion - var loweredCase = false - for (;;) { - switch (encoding) { - case 'ascii': - case 'latin1': - case 'binary': - return len - case 'utf8': - case 'utf-8': - case undefined: - return utf8ToBytes(string).length - case 'ucs2': - case 'ucs-2': - case 'utf16le': - case 'utf-16le': - return len * 2 - case 'hex': - return len >>> 1 - case 'base64': - return base64ToBytes(string).length - default: - if (loweredCase) return utf8ToBytes(string).length // assume utf8 - encoding = ('' + encoding).toLowerCase() - loweredCase = true - } - } -} -Buffer.byteLength = byteLength - -function slowToString (encoding, start, end) { - var loweredCase = false - - // No need to verify that "this.length <= MAX_UINT32" since it's a read-only - // property of a typed array. - - // This behaves neither like String nor Uint8Array in that we set start/end - // to their upper/lower bounds if the value passed is out of range. - // undefined is handled specially as per ECMA-262 6th Edition, - // Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization. - if (start === undefined || start < 0) { - start = 0 - } - // Return early if start > this.length. Done here to prevent potential uint32 - // coercion fail below. - if (start > this.length) { - return '' - } - - if (end === undefined || end > this.length) { - end = this.length - } - - if (end <= 0) { - return '' - } - - // Force coersion to uint32. This will also coerce falsey/NaN values to 0. - end >>>= 0 - start >>>= 0 - - if (end <= start) { - return '' - } - - if (!encoding) encoding = 'utf8' - - while (true) { - switch (encoding) { - case 'hex': - return hexSlice(this, start, end) - - case 'utf8': - case 'utf-8': - return utf8Slice(this, start, end) - - case 'ascii': - return asciiSlice(this, start, end) - - case 'latin1': - case 'binary': - return latin1Slice(this, start, end) - - case 'base64': - return base64Slice(this, start, end) - - case 'ucs2': - case 'ucs-2': - case 'utf16le': - case 'utf-16le': - return utf16leSlice(this, start, end) - - default: - if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) - encoding = (encoding + '').toLowerCase() - loweredCase = true - } - } -} - -// The property is used by `Buffer.isBuffer` and `is-buffer` (in Safari 5-7) to detect -// Buffer instances. -Buffer.prototype._isBuffer = true - -function swap (b, n, m) { - var i = b[n] - b[n] = b[m] - b[m] = i -} - -Buffer.prototype.swap16 = function swap16 () { - var len = this.length - if (len % 2 !== 0) { - throw new RangeError('Buffer size must be a multiple of 16-bits') - } - for (var i = 0; i < len; i += 2) { - swap(this, i, i + 1) - } - return this -} - -Buffer.prototype.swap32 = function swap32 () { - var len = this.length - if (len % 4 !== 0) { - throw new RangeError('Buffer size must be a multiple of 32-bits') - } - for (var i = 0; i < len; i += 4) { - swap(this, i, i + 3) - swap(this, i + 1, i + 2) - } - return this -} - -Buffer.prototype.swap64 = function swap64 () { - var len = this.length - if (len % 8 !== 0) { - throw new RangeError('Buffer size must be a multiple of 64-bits') - } - for (var i = 0; i < len; i += 8) { - swap(this, i, i + 7) - swap(this, i + 1, i + 6) - swap(this, i + 2, i + 5) - swap(this, i + 3, i + 4) - } - return this -} - -Buffer.prototype.toString = function toString () { - var length = this.length | 0 - if (length === 0) return '' - if (arguments.length === 0) return utf8Slice(this, 0, length) - return slowToString.apply(this, arguments) -} - -Buffer.prototype.equals = function equals (b) { - if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer') - if (this === b) return true - return Buffer.compare(this, b) === 0 -} - -Buffer.prototype.inspect = function inspect () { - var str = '' - var max = exports.INSPECT_MAX_BYTES - if (this.length > 0) { - str = this.toString('hex', 0, max).match(/.{2}/g).join(' ') - if (this.length > max) str += ' ... ' - } - return '' -} - -Buffer.prototype.compare = function compare (target, start, end, thisStart, thisEnd) { - if (!Buffer.isBuffer(target)) { - throw new TypeError('Argument must be a Buffer') - } - - if (start === undefined) { - start = 0 - } - if (end === undefined) { - end = target ? target.length : 0 - } - if (thisStart === undefined) { - thisStart = 0 - } - if (thisEnd === undefined) { - thisEnd = this.length - } - - if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) { - throw new RangeError('out of range index') - } - - if (thisStart >= thisEnd && start >= end) { - return 0 - } - if (thisStart >= thisEnd) { - return -1 - } - if (start >= end) { - return 1 - } - - start >>>= 0 - end >>>= 0 - thisStart >>>= 0 - thisEnd >>>= 0 - - if (this === target) return 0 - - var x = thisEnd - thisStart - var y = end - start - var len = Math.min(x, y) - - var thisCopy = this.slice(thisStart, thisEnd) - var targetCopy = target.slice(start, end) - - for (var i = 0; i < len; ++i) { - if (thisCopy[i] !== targetCopy[i]) { - x = thisCopy[i] - y = targetCopy[i] - break - } - } - - if (x < y) return -1 - if (y < x) return 1 - return 0 -} - -// Finds either the first index of `val` in `buffer` at offset >= `byteOffset`, -// OR the last index of `val` in `buffer` at offset <= `byteOffset`. -// -// Arguments: -// - buffer - a Buffer to search -// - val - a string, Buffer, or number -// - byteOffset - an index into `buffer`; will be clamped to an int32 -// - encoding - an optional encoding, relevant is val is a string -// - dir - true for indexOf, false for lastIndexOf -function bidirectionalIndexOf (buffer, val, byteOffset, encoding, dir) { - // Empty buffer means no match - if (buffer.length === 0) return -1 - - // Normalize byteOffset - if (typeof byteOffset === 'string') { - encoding = byteOffset - byteOffset = 0 - } else if (byteOffset > 0x7fffffff) { - byteOffset = 0x7fffffff - } else if (byteOffset < -0x80000000) { - byteOffset = -0x80000000 - } - byteOffset = +byteOffset // Coerce to Number. - if (isNaN(byteOffset)) { - // byteOffset: it it's undefined, null, NaN, "foo", etc, search whole buffer - byteOffset = dir ? 0 : (buffer.length - 1) - } - - // Normalize byteOffset: negative offsets start from the end of the buffer - if (byteOffset < 0) byteOffset = buffer.length + byteOffset - if (byteOffset >= buffer.length) { - if (dir) return -1 - else byteOffset = buffer.length - 1 - } else if (byteOffset < 0) { - if (dir) byteOffset = 0 - else return -1 - } - - // Normalize val - if (typeof val === 'string') { - val = Buffer.from(val, encoding) - } - - // Finally, search either indexOf (if dir is true) or lastIndexOf - if (Buffer.isBuffer(val)) { - // Special case: looking for empty string/buffer always fails - if (val.length === 0) { - return -1 - } - return arrayIndexOf(buffer, val, byteOffset, encoding, dir) - } else if (typeof val === 'number') { - val = val & 0xFF // Search for a byte value [0-255] - if (Buffer.TYPED_ARRAY_SUPPORT && - typeof Uint8Array.prototype.indexOf === 'function') { - if (dir) { - return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset) - } else { - return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset) - } - } - return arrayIndexOf(buffer, [ val ], byteOffset, encoding, dir) - } - - throw new TypeError('val must be string, number or Buffer') -} - -function arrayIndexOf (arr, val, byteOffset, encoding, dir) { - var indexSize = 1 - var arrLength = arr.length - var valLength = val.length - - if (encoding !== undefined) { - encoding = String(encoding).toLowerCase() - if (encoding === 'ucs2' || encoding === 'ucs-2' || - encoding === 'utf16le' || encoding === 'utf-16le') { - if (arr.length < 2 || val.length < 2) { - return -1 - } - indexSize = 2 - arrLength /= 2 - valLength /= 2 - byteOffset /= 2 - } - } - - function read (buf, i) { - if (indexSize === 1) { - return buf[i] - } else { - return buf.readUInt16BE(i * indexSize) - } - } - - var i - if (dir) { - var foundIndex = -1 - for (i = byteOffset; i < arrLength; i++) { - if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) { - if (foundIndex === -1) foundIndex = i - if (i - foundIndex + 1 === valLength) return foundIndex * indexSize - } else { - if (foundIndex !== -1) i -= i - foundIndex - foundIndex = -1 - } - } - } else { - if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength - for (i = byteOffset; i >= 0; i--) { - var found = true - for (var j = 0; j < valLength; j++) { - if (read(arr, i + j) !== read(val, j)) { - found = false - break - } - } - if (found) return i - } - } - - return -1 -} - -Buffer.prototype.includes = function includes (val, byteOffset, encoding) { - return this.indexOf(val, byteOffset, encoding) !== -1 -} - -Buffer.prototype.indexOf = function indexOf (val, byteOffset, encoding) { - return bidirectionalIndexOf(this, val, byteOffset, encoding, true) -} - -Buffer.prototype.lastIndexOf = function lastIndexOf (val, byteOffset, encoding) { - return bidirectionalIndexOf(this, val, byteOffset, encoding, false) -} - -function hexWrite (buf, string, offset, length) { - offset = Number(offset) || 0 - var remaining = buf.length - offset - if (!length) { - length = remaining - } else { - length = Number(length) - if (length > remaining) { - length = remaining - } - } - - // must be an even number of digits - var strLen = string.length - if (strLen % 2 !== 0) throw new TypeError('Invalid hex string') - - if (length > strLen / 2) { - length = strLen / 2 - } - for (var i = 0; i < length; ++i) { - var parsed = parseInt(string.substr(i * 2, 2), 16) - if (isNaN(parsed)) return i - buf[offset + i] = parsed - } - return i -} - -function utf8Write (buf, string, offset, length) { - return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length) -} - -function asciiWrite (buf, string, offset, length) { - return blitBuffer(asciiToBytes(string), buf, offset, length) -} - -function latin1Write (buf, string, offset, length) { - return asciiWrite(buf, string, offset, length) -} - -function base64Write (buf, string, offset, length) { - return blitBuffer(base64ToBytes(string), buf, offset, length) -} - -function ucs2Write (buf, string, offset, length) { - return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length) -} - -Buffer.prototype.write = function write (string, offset, length, encoding) { - // Buffer#write(string) - if (offset === undefined) { - encoding = 'utf8' - length = this.length - offset = 0 - // Buffer#write(string, encoding) - } else if (length === undefined && typeof offset === 'string') { - encoding = offset - length = this.length - offset = 0 - // Buffer#write(string, offset[, length][, encoding]) - } else if (isFinite(offset)) { - offset = offset | 0 - if (isFinite(length)) { - length = length | 0 - if (encoding === undefined) encoding = 'utf8' - } else { - encoding = length - length = undefined - } - // legacy write(string, encoding, offset, length) - remove in v0.13 - } else { - throw new Error( - 'Buffer.write(string, encoding, offset[, length]) is no longer supported' - ) - } - - var remaining = this.length - offset - if (length === undefined || length > remaining) length = remaining - - if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) { - throw new RangeError('Attempt to write outside buffer bounds') - } - - if (!encoding) encoding = 'utf8' - - var loweredCase = false - for (;;) { - switch (encoding) { - case 'hex': - return hexWrite(this, string, offset, length) - - case 'utf8': - case 'utf-8': - return utf8Write(this, string, offset, length) - - case 'ascii': - return asciiWrite(this, string, offset, length) - - case 'latin1': - case 'binary': - return latin1Write(this, string, offset, length) - - case 'base64': - // Warning: maxLength not taken into account in base64Write - return base64Write(this, string, offset, length) - - case 'ucs2': - case 'ucs-2': - case 'utf16le': - case 'utf-16le': - return ucs2Write(this, string, offset, length) - - default: - if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) - encoding = ('' + encoding).toLowerCase() - loweredCase = true - } - } -} - -Buffer.prototype.toJSON = function toJSON () { - return { - type: 'Buffer', - data: Array.prototype.slice.call(this._arr || this, 0) - } -} - -function base64Slice (buf, start, end) { - if (start === 0 && end === buf.length) { - return base64.fromByteArray(buf) - } else { - return base64.fromByteArray(buf.slice(start, end)) - } -} - -function utf8Slice (buf, start, end) { - end = Math.min(buf.length, end) - var res = [] - - var i = start - while (i < end) { - var firstByte = buf[i] - var codePoint = null - var bytesPerSequence = (firstByte > 0xEF) ? 4 - : (firstByte > 0xDF) ? 3 - : (firstByte > 0xBF) ? 2 - : 1 - - if (i + bytesPerSequence <= end) { - var secondByte, thirdByte, fourthByte, tempCodePoint - - switch (bytesPerSequence) { - case 1: - if (firstByte < 0x80) { - codePoint = firstByte - } - break - case 2: - secondByte = buf[i + 1] - if ((secondByte & 0xC0) === 0x80) { - tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F) - if (tempCodePoint > 0x7F) { - codePoint = tempCodePoint - } - } - break - case 3: - secondByte = buf[i + 1] - thirdByte = buf[i + 2] - if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) { - tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F) - if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) { - codePoint = tempCodePoint - } - } - break - case 4: - secondByte = buf[i + 1] - thirdByte = buf[i + 2] - fourthByte = buf[i + 3] - if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) { - tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F) - if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) { - codePoint = tempCodePoint - } - } - } - } - - if (codePoint === null) { - // we did not generate a valid codePoint so insert a - // replacement char (U+FFFD) and advance only 1 byte - codePoint = 0xFFFD - bytesPerSequence = 1 - } else if (codePoint > 0xFFFF) { - // encode to utf16 (surrogate pair dance) - codePoint -= 0x10000 - res.push(codePoint >>> 10 & 0x3FF | 0xD800) - codePoint = 0xDC00 | codePoint & 0x3FF - } - - res.push(codePoint) - i += bytesPerSequence - } - - return decodeCodePointsArray(res) -} - -// Based on http://stackoverflow.com/a/22747272/680742, the browser with -// the lowest limit is Chrome, with 0x10000 args. -// We go 1 magnitude less, for safety -var MAX_ARGUMENTS_LENGTH = 0x1000 - -function decodeCodePointsArray (codePoints) { - var len = codePoints.length - if (len <= MAX_ARGUMENTS_LENGTH) { - return String.fromCharCode.apply(String, codePoints) // avoid extra slice() - } - - // Decode in chunks to avoid "call stack size exceeded". - var res = '' - var i = 0 - while (i < len) { - res += String.fromCharCode.apply( - String, - codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH) - ) - } - return res -} - -function asciiSlice (buf, start, end) { - var ret = '' - end = Math.min(buf.length, end) - - for (var i = start; i < end; ++i) { - ret += String.fromCharCode(buf[i] & 0x7F) - } - return ret -} - -function latin1Slice (buf, start, end) { - var ret = '' - end = Math.min(buf.length, end) - - for (var i = start; i < end; ++i) { - ret += String.fromCharCode(buf[i]) - } - return ret -} - -function hexSlice (buf, start, end) { - var len = buf.length - - if (!start || start < 0) start = 0 - if (!end || end < 0 || end > len) end = len - - var out = '' - for (var i = start; i < end; ++i) { - out += toHex(buf[i]) - } - return out -} - -function utf16leSlice (buf, start, end) { - var bytes = buf.slice(start, end) - var res = '' - for (var i = 0; i < bytes.length; i += 2) { - res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256) - } - return res -} - -Buffer.prototype.slice = function slice (start, end) { - var len = this.length - start = ~~start - end = end === undefined ? len : ~~end - - if (start < 0) { - start += len - if (start < 0) start = 0 - } else if (start > len) { - start = len - } - - if (end < 0) { - end += len - if (end < 0) end = 0 - } else if (end > len) { - end = len - } - - if (end < start) end = start - - var newBuf - if (Buffer.TYPED_ARRAY_SUPPORT) { - newBuf = this.subarray(start, end) - newBuf.__proto__ = Buffer.prototype - } else { - var sliceLen = end - start - newBuf = new Buffer(sliceLen, undefined) - for (var i = 0; i < sliceLen; ++i) { - newBuf[i] = this[i + start] - } - } - - return newBuf -} - -/* - * Need to make sure that buffer isn't trying to write out of bounds. - */ -function checkOffset (offset, ext, length) { - if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint') - if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length') -} - -Buffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) { - offset = offset | 0 - byteLength = byteLength | 0 - if (!noAssert) checkOffset(offset, byteLength, this.length) - - var val = this[offset] - var mul = 1 - var i = 0 - while (++i < byteLength && (mul *= 0x100)) { - val += this[offset + i] * mul - } - - return val -} - -Buffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) { - offset = offset | 0 - byteLength = byteLength | 0 - if (!noAssert) { - checkOffset(offset, byteLength, this.length) - } - - var val = this[offset + --byteLength] - var mul = 1 - while (byteLength > 0 && (mul *= 0x100)) { - val += this[offset + --byteLength] * mul - } - - return val -} - -Buffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) { - if (!noAssert) checkOffset(offset, 1, this.length) - return this[offset] -} - -Buffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 2, this.length) - return this[offset] | (this[offset + 1] << 8) -} - -Buffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 2, this.length) - return (this[offset] << 8) | this[offset + 1] -} - -Buffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 4, this.length) - - return ((this[offset]) | - (this[offset + 1] << 8) | - (this[offset + 2] << 16)) + - (this[offset + 3] * 0x1000000) -} - -Buffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 4, this.length) - - return (this[offset] * 0x1000000) + - ((this[offset + 1] << 16) | - (this[offset + 2] << 8) | - this[offset + 3]) -} - -Buffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) { - offset = offset | 0 - byteLength = byteLength | 0 - if (!noAssert) checkOffset(offset, byteLength, this.length) - - var val = this[offset] - var mul = 1 - var i = 0 - while (++i < byteLength && (mul *= 0x100)) { - val += this[offset + i] * mul - } - mul *= 0x80 - - if (val >= mul) val -= Math.pow(2, 8 * byteLength) - - return val -} - -Buffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) { - offset = offset | 0 - byteLength = byteLength | 0 - if (!noAssert) checkOffset(offset, byteLength, this.length) - - var i = byteLength - var mul = 1 - var val = this[offset + --i] - while (i > 0 && (mul *= 0x100)) { - val += this[offset + --i] * mul - } - mul *= 0x80 - - if (val >= mul) val -= Math.pow(2, 8 * byteLength) - - return val -} - -Buffer.prototype.readInt8 = function readInt8 (offset, noAssert) { - if (!noAssert) checkOffset(offset, 1, this.length) - if (!(this[offset] & 0x80)) return (this[offset]) - return ((0xff - this[offset] + 1) * -1) -} - -Buffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 2, this.length) - var val = this[offset] | (this[offset + 1] << 8) - return (val & 0x8000) ? val | 0xFFFF0000 : val -} - -Buffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 2, this.length) - var val = this[offset + 1] | (this[offset] << 8) - return (val & 0x8000) ? val | 0xFFFF0000 : val -} - -Buffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 4, this.length) - - return (this[offset]) | - (this[offset + 1] << 8) | - (this[offset + 2] << 16) | - (this[offset + 3] << 24) -} - -Buffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 4, this.length) - - return (this[offset] << 24) | - (this[offset + 1] << 16) | - (this[offset + 2] << 8) | - (this[offset + 3]) -} - -Buffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 4, this.length) - return ieee754.read(this, offset, true, 23, 4) -} - -Buffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 4, this.length) - return ieee754.read(this, offset, false, 23, 4) -} - -Buffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 8, this.length) - return ieee754.read(this, offset, true, 52, 8) -} - -Buffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 8, this.length) - return ieee754.read(this, offset, false, 52, 8) -} - -function checkInt (buf, value, offset, ext, max, min) { - if (!Buffer.isBuffer(buf)) throw new TypeError('"buffer" argument must be a Buffer instance') - if (value > max || value < min) throw new RangeError('"value" argument is out of bounds') - if (offset + ext > buf.length) throw new RangeError('Index out of range') -} - -Buffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) { - value = +value - offset = offset | 0 - byteLength = byteLength | 0 - if (!noAssert) { - var maxBytes = Math.pow(2, 8 * byteLength) - 1 - checkInt(this, value, offset, byteLength, maxBytes, 0) - } - - var mul = 1 - var i = 0 - this[offset] = value & 0xFF - while (++i < byteLength && (mul *= 0x100)) { - this[offset + i] = (value / mul) & 0xFF - } - - return offset + byteLength -} - -Buffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) { - value = +value - offset = offset | 0 - byteLength = byteLength | 0 - if (!noAssert) { - var maxBytes = Math.pow(2, 8 * byteLength) - 1 - checkInt(this, value, offset, byteLength, maxBytes, 0) - } - - var i = byteLength - 1 - var mul = 1 - this[offset + i] = value & 0xFF - while (--i >= 0 && (mul *= 0x100)) { - this[offset + i] = (value / mul) & 0xFF - } - - return offset + byteLength -} - -Buffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0) - if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value) - this[offset] = (value & 0xff) - return offset + 1 -} - -function objectWriteUInt16 (buf, value, offset, littleEndian) { - if (value < 0) value = 0xffff + value + 1 - for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; ++i) { - buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>> - (littleEndian ? i : 1 - i) * 8 - } -} - -Buffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value & 0xff) - this[offset + 1] = (value >>> 8) - } else { - objectWriteUInt16(this, value, offset, true) - } - return offset + 2 -} - -Buffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value >>> 8) - this[offset + 1] = (value & 0xff) - } else { - objectWriteUInt16(this, value, offset, false) - } - return offset + 2 -} - -function objectWriteUInt32 (buf, value, offset, littleEndian) { - if (value < 0) value = 0xffffffff + value + 1 - for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; ++i) { - buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff - } -} - -Buffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset + 3] = (value >>> 24) - this[offset + 2] = (value >>> 16) - this[offset + 1] = (value >>> 8) - this[offset] = (value & 0xff) - } else { - objectWriteUInt32(this, value, offset, true) - } - return offset + 4 -} - -Buffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value >>> 24) - this[offset + 1] = (value >>> 16) - this[offset + 2] = (value >>> 8) - this[offset + 3] = (value & 0xff) - } else { - objectWriteUInt32(this, value, offset, false) - } - return offset + 4 -} - -Buffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) { - var limit = Math.pow(2, 8 * byteLength - 1) - - checkInt(this, value, offset, byteLength, limit - 1, -limit) - } - - var i = 0 - var mul = 1 - var sub = 0 - this[offset] = value & 0xFF - while (++i < byteLength && (mul *= 0x100)) { - if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) { - sub = 1 - } - this[offset + i] = ((value / mul) >> 0) - sub & 0xFF - } - - return offset + byteLength -} - -Buffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) { - var limit = Math.pow(2, 8 * byteLength - 1) - - checkInt(this, value, offset, byteLength, limit - 1, -limit) - } - - var i = byteLength - 1 - var mul = 1 - var sub = 0 - this[offset + i] = value & 0xFF - while (--i >= 0 && (mul *= 0x100)) { - if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) { - sub = 1 - } - this[offset + i] = ((value / mul) >> 0) - sub & 0xFF - } - - return offset + byteLength -} - -Buffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80) - if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value) - if (value < 0) value = 0xff + value + 1 - this[offset] = (value & 0xff) - return offset + 1 -} - -Buffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value & 0xff) - this[offset + 1] = (value >>> 8) - } else { - objectWriteUInt16(this, value, offset, true) - } - return offset + 2 -} - -Buffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value >>> 8) - this[offset + 1] = (value & 0xff) - } else { - objectWriteUInt16(this, value, offset, false) - } - return offset + 2 -} - -Buffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value & 0xff) - this[offset + 1] = (value >>> 8) - this[offset + 2] = (value >>> 16) - this[offset + 3] = (value >>> 24) - } else { - objectWriteUInt32(this, value, offset, true) - } - return offset + 4 -} - -Buffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) - if (value < 0) value = 0xffffffff + value + 1 - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value >>> 24) - this[offset + 1] = (value >>> 16) - this[offset + 2] = (value >>> 8) - this[offset + 3] = (value & 0xff) - } else { - objectWriteUInt32(this, value, offset, false) - } - return offset + 4 -} - -function checkIEEE754 (buf, value, offset, ext, max, min) { - if (offset + ext > buf.length) throw new RangeError('Index out of range') - if (offset < 0) throw new RangeError('Index out of range') -} - -function writeFloat (buf, value, offset, littleEndian, noAssert) { - if (!noAssert) { - checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38) - } - ieee754.write(buf, value, offset, littleEndian, 23, 4) - return offset + 4 -} - -Buffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) { - return writeFloat(this, value, offset, true, noAssert) -} - -Buffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) { - return writeFloat(this, value, offset, false, noAssert) -} - -function writeDouble (buf, value, offset, littleEndian, noAssert) { - if (!noAssert) { - checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308) - } - ieee754.write(buf, value, offset, littleEndian, 52, 8) - return offset + 8 -} - -Buffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) { - return writeDouble(this, value, offset, true, noAssert) -} - -Buffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) { - return writeDouble(this, value, offset, false, noAssert) -} - -// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length) -Buffer.prototype.copy = function copy (target, targetStart, start, end) { - if (!start) start = 0 - if (!end && end !== 0) end = this.length - if (targetStart >= target.length) targetStart = target.length - if (!targetStart) targetStart = 0 - if (end > 0 && end < start) end = start - - // Copy 0 bytes; we're done - if (end === start) return 0 - if (target.length === 0 || this.length === 0) return 0 - - // Fatal error conditions - if (targetStart < 0) { - throw new RangeError('targetStart out of bounds') - } - if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds') - if (end < 0) throw new RangeError('sourceEnd out of bounds') - - // Are we oob? - if (end > this.length) end = this.length - if (target.length - targetStart < end - start) { - end = target.length - targetStart + start - } - - var len = end - start - var i - - if (this === target && start < targetStart && targetStart < end) { - // descending copy from end - for (i = len - 1; i >= 0; --i) { - target[i + targetStart] = this[i + start] - } - } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) { - // ascending copy from start - for (i = 0; i < len; ++i) { - target[i + targetStart] = this[i + start] - } - } else { - Uint8Array.prototype.set.call( - target, - this.subarray(start, start + len), - targetStart - ) - } - - return len -} - -// Usage: -// buffer.fill(number[, offset[, end]]) -// buffer.fill(buffer[, offset[, end]]) -// buffer.fill(string[, offset[, end]][, encoding]) -Buffer.prototype.fill = function fill (val, start, end, encoding) { - // Handle string cases: - if (typeof val === 'string') { - if (typeof start === 'string') { - encoding = start - start = 0 - end = this.length - } else if (typeof end === 'string') { - encoding = end - end = this.length - } - if (val.length === 1) { - var code = val.charCodeAt(0) - if (code < 256) { - val = code - } - } - if (encoding !== undefined && typeof encoding !== 'string') { - throw new TypeError('encoding must be a string') - } - if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) { - throw new TypeError('Unknown encoding: ' + encoding) - } - } else if (typeof val === 'number') { - val = val & 255 - } - - // Invalid ranges are not set to a default, so can range check early. - if (start < 0 || this.length < start || this.length < end) { - throw new RangeError('Out of range index') - } - - if (end <= start) { - return this - } - - start = start >>> 0 - end = end === undefined ? this.length : end >>> 0 - - if (!val) val = 0 - - var i - if (typeof val === 'number') { - for (i = start; i < end; ++i) { - this[i] = val - } - } else { - var bytes = Buffer.isBuffer(val) - ? val - : utf8ToBytes(new Buffer(val, encoding).toString()) - var len = bytes.length - for (i = 0; i < end - start; ++i) { - this[i + start] = bytes[i % len] - } - } - - return this -} - -// HELPER FUNCTIONS -// ================ - -var INVALID_BASE64_RE = /[^+\/0-9A-Za-z-_]/g - -function base64clean (str) { - // Node strips out invalid characters like \n and \t from the string, base64-js does not - str = stringtrim(str).replace(INVALID_BASE64_RE, '') - // Node converts strings with length < 2 to '' - if (str.length < 2) return '' - // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not - while (str.length % 4 !== 0) { - str = str + '=' - } - return str -} - -function stringtrim (str) { - if (str.trim) return str.trim() - return str.replace(/^\s+|\s+$/g, '') -} - -function toHex (n) { - if (n < 16) return '0' + n.toString(16) - return n.toString(16) -} - -function utf8ToBytes (string, units) { - units = units || Infinity - var codePoint - var length = string.length - var leadSurrogate = null - var bytes = [] - - for (var i = 0; i < length; ++i) { - codePoint = string.charCodeAt(i) - - // is surrogate component - if (codePoint > 0xD7FF && codePoint < 0xE000) { - // last char was a lead - if (!leadSurrogate) { - // no lead yet - if (codePoint > 0xDBFF) { - // unexpected trail - if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) - continue - } else if (i + 1 === length) { - // unpaired lead - if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) - continue - } - - // valid lead - leadSurrogate = codePoint - - continue - } - - // 2 leads in a row - if (codePoint < 0xDC00) { - if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) - leadSurrogate = codePoint - continue - } - - // valid surrogate pair - codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000 - } else if (leadSurrogate) { - // valid bmp char, but last char was a lead - if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) - } - - leadSurrogate = null - - // encode utf8 - if (codePoint < 0x80) { - if ((units -= 1) < 0) break - bytes.push(codePoint) - } else if (codePoint < 0x800) { - if ((units -= 2) < 0) break - bytes.push( - codePoint >> 0x6 | 0xC0, - codePoint & 0x3F | 0x80 - ) - } else if (codePoint < 0x10000) { - if ((units -= 3) < 0) break - bytes.push( - codePoint >> 0xC | 0xE0, - codePoint >> 0x6 & 0x3F | 0x80, - codePoint & 0x3F | 0x80 - ) - } else if (codePoint < 0x110000) { - if ((units -= 4) < 0) break - bytes.push( - codePoint >> 0x12 | 0xF0, - codePoint >> 0xC & 0x3F | 0x80, - codePoint >> 0x6 & 0x3F | 0x80, - codePoint & 0x3F | 0x80 - ) - } else { - throw new Error('Invalid code point') - } - } - - return bytes -} - -function asciiToBytes (str) { - var byteArray = [] - for (var i = 0; i < str.length; ++i) { - // Node's code seems to be doing this and not & 0x7F.. - byteArray.push(str.charCodeAt(i) & 0xFF) - } - return byteArray -} - -function utf16leToBytes (str, units) { - var c, hi, lo - var byteArray = [] - for (var i = 0; i < str.length; ++i) { - if ((units -= 2) < 0) break - - c = str.charCodeAt(i) - hi = c >> 8 - lo = c % 256 - byteArray.push(lo) - byteArray.push(hi) - } - - return byteArray -} - -function base64ToBytes (str) { - return base64.toByteArray(base64clean(str)) -} - -function blitBuffer (src, dst, offset, length) { - for (var i = 0; i < length; ++i) { - if ((i + offset >= dst.length) || (i >= src.length)) break - dst[i + offset] = src[i] - } - return i -} - -function isnan (val) { - return val !== val // eslint-disable-line no-self-compare -} - -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"base64-js":1,"ieee754":2,"isarray":3}]},{},[])("buffer") -});(function(factory){if(typeof exports==="object"){module.exports=factory()}else if(typeof define==="function"&&define.amd){define(factory)}else{var glob;try{glob=window}catch(e){glob=self}glob.SparkMD5=factory()}})(function(undefined){"use strict";var add32=function(a,b){return a+b&4294967295},hex_chr=["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"];function cmn(q,a,b,x,s,t){a=add32(add32(a,q),add32(x,t));return add32(a<>>32-s,b)}function md5cycle(x,k){var a=x[0],b=x[1],c=x[2],d=x[3];a+=(b&c|~b&d)+k[0]-680876936|0;a=(a<<7|a>>>25)+b|0;d+=(a&b|~a&c)+k[1]-389564586|0;d=(d<<12|d>>>20)+a|0;c+=(d&a|~d&b)+k[2]+606105819|0;c=(c<<17|c>>>15)+d|0;b+=(c&d|~c&a)+k[3]-1044525330|0;b=(b<<22|b>>>10)+c|0;a+=(b&c|~b&d)+k[4]-176418897|0;a=(a<<7|a>>>25)+b|0;d+=(a&b|~a&c)+k[5]+1200080426|0;d=(d<<12|d>>>20)+a|0;c+=(d&a|~d&b)+k[6]-1473231341|0;c=(c<<17|c>>>15)+d|0;b+=(c&d|~c&a)+k[7]-45705983|0;b=(b<<22|b>>>10)+c|0;a+=(b&c|~b&d)+k[8]+1770035416|0;a=(a<<7|a>>>25)+b|0;d+=(a&b|~a&c)+k[9]-1958414417|0;d=(d<<12|d>>>20)+a|0;c+=(d&a|~d&b)+k[10]-42063|0;c=(c<<17|c>>>15)+d|0;b+=(c&d|~c&a)+k[11]-1990404162|0;b=(b<<22|b>>>10)+c|0;a+=(b&c|~b&d)+k[12]+1804603682|0;a=(a<<7|a>>>25)+b|0;d+=(a&b|~a&c)+k[13]-40341101|0;d=(d<<12|d>>>20)+a|0;c+=(d&a|~d&b)+k[14]-1502002290|0;c=(c<<17|c>>>15)+d|0;b+=(c&d|~c&a)+k[15]+1236535329|0;b=(b<<22|b>>>10)+c|0;a+=(b&d|c&~d)+k[1]-165796510|0;a=(a<<5|a>>>27)+b|0;d+=(a&c|b&~c)+k[6]-1069501632|0;d=(d<<9|d>>>23)+a|0;c+=(d&b|a&~b)+k[11]+643717713|0;c=(c<<14|c>>>18)+d|0;b+=(c&a|d&~a)+k[0]-373897302|0;b=(b<<20|b>>>12)+c|0;a+=(b&d|c&~d)+k[5]-701558691|0;a=(a<<5|a>>>27)+b|0;d+=(a&c|b&~c)+k[10]+38016083|0;d=(d<<9|d>>>23)+a|0;c+=(d&b|a&~b)+k[15]-660478335|0;c=(c<<14|c>>>18)+d|0;b+=(c&a|d&~a)+k[4]-405537848|0;b=(b<<20|b>>>12)+c|0;a+=(b&d|c&~d)+k[9]+568446438|0;a=(a<<5|a>>>27)+b|0;d+=(a&c|b&~c)+k[14]-1019803690|0;d=(d<<9|d>>>23)+a|0;c+=(d&b|a&~b)+k[3]-187363961|0;c=(c<<14|c>>>18)+d|0;b+=(c&a|d&~a)+k[8]+1163531501|0;b=(b<<20|b>>>12)+c|0;a+=(b&d|c&~d)+k[13]-1444681467|0;a=(a<<5|a>>>27)+b|0;d+=(a&c|b&~c)+k[2]-51403784|0;d=(d<<9|d>>>23)+a|0;c+=(d&b|a&~b)+k[7]+1735328473|0;c=(c<<14|c>>>18)+d|0;b+=(c&a|d&~a)+k[12]-1926607734|0;b=(b<<20|b>>>12)+c|0;a+=(b^c^d)+k[5]-378558|0;a=(a<<4|a>>>28)+b|0;d+=(a^b^c)+k[8]-2022574463|0;d=(d<<11|d>>>21)+a|0;c+=(d^a^b)+k[11]+1839030562|0;c=(c<<16|c>>>16)+d|0;b+=(c^d^a)+k[14]-35309556|0;b=(b<<23|b>>>9)+c|0;a+=(b^c^d)+k[1]-1530992060|0;a=(a<<4|a>>>28)+b|0;d+=(a^b^c)+k[4]+1272893353|0;d=(d<<11|d>>>21)+a|0;c+=(d^a^b)+k[7]-155497632|0;c=(c<<16|c>>>16)+d|0;b+=(c^d^a)+k[10]-1094730640|0;b=(b<<23|b>>>9)+c|0;a+=(b^c^d)+k[13]+681279174|0;a=(a<<4|a>>>28)+b|0;d+=(a^b^c)+k[0]-358537222|0;d=(d<<11|d>>>21)+a|0;c+=(d^a^b)+k[3]-722521979|0;c=(c<<16|c>>>16)+d|0;b+=(c^d^a)+k[6]+76029189|0;b=(b<<23|b>>>9)+c|0;a+=(b^c^d)+k[9]-640364487|0;a=(a<<4|a>>>28)+b|0;d+=(a^b^c)+k[12]-421815835|0;d=(d<<11|d>>>21)+a|0;c+=(d^a^b)+k[15]+530742520|0;c=(c<<16|c>>>16)+d|0;b+=(c^d^a)+k[2]-995338651|0;b=(b<<23|b>>>9)+c|0;a+=(c^(b|~d))+k[0]-198630844|0;a=(a<<6|a>>>26)+b|0;d+=(b^(a|~c))+k[7]+1126891415|0;d=(d<<10|d>>>22)+a|0;c+=(a^(d|~b))+k[14]-1416354905|0;c=(c<<15|c>>>17)+d|0;b+=(d^(c|~a))+k[5]-57434055|0;b=(b<<21|b>>>11)+c|0;a+=(c^(b|~d))+k[12]+1700485571|0;a=(a<<6|a>>>26)+b|0;d+=(b^(a|~c))+k[3]-1894986606|0;d=(d<<10|d>>>22)+a|0;c+=(a^(d|~b))+k[10]-1051523|0;c=(c<<15|c>>>17)+d|0;b+=(d^(c|~a))+k[1]-2054922799|0;b=(b<<21|b>>>11)+c|0;a+=(c^(b|~d))+k[8]+1873313359|0;a=(a<<6|a>>>26)+b|0;d+=(b^(a|~c))+k[15]-30611744|0;d=(d<<10|d>>>22)+a|0;c+=(a^(d|~b))+k[6]-1560198380|0;c=(c<<15|c>>>17)+d|0;b+=(d^(c|~a))+k[13]+1309151649|0;b=(b<<21|b>>>11)+c|0;a+=(c^(b|~d))+k[4]-145523070|0;a=(a<<6|a>>>26)+b|0;d+=(b^(a|~c))+k[11]-1120210379|0;d=(d<<10|d>>>22)+a|0;c+=(a^(d|~b))+k[2]+718787259|0;c=(c<<15|c>>>17)+d|0;b+=(d^(c|~a))+k[9]-343485551|0;b=(b<<21|b>>>11)+c|0;x[0]=a+x[0]|0;x[1]=b+x[1]|0;x[2]=c+x[2]|0;x[3]=d+x[3]|0}function md5blk(s){var md5blks=[],i;for(i=0;i<64;i+=4){md5blks[i>>2]=s.charCodeAt(i)+(s.charCodeAt(i+1)<<8)+(s.charCodeAt(i+2)<<16)+(s.charCodeAt(i+3)<<24)}return md5blks}function md5blk_array(a){var md5blks=[],i;for(i=0;i<64;i+=4){md5blks[i>>2]=a[i]+(a[i+1]<<8)+(a[i+2]<<16)+(a[i+3]<<24)}return md5blks}function md51(s){var n=s.length,state=[1732584193,-271733879,-1732584194,271733878],i,length,tail,tmp,lo,hi;for(i=64;i<=n;i+=64){md5cycle(state,md5blk(s.substring(i-64,i)))}s=s.substring(i-64);length=s.length;tail=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];for(i=0;i>2]|=s.charCodeAt(i)<<(i%4<<3)}tail[i>>2]|=128<<(i%4<<3);if(i>55){md5cycle(state,tail);for(i=0;i<16;i+=1){tail[i]=0}}tmp=n*8;tmp=tmp.toString(16).match(/(.*?)(.{0,8})$/);lo=parseInt(tmp[2],16);hi=parseInt(tmp[1],16)||0;tail[14]=lo;tail[15]=hi;md5cycle(state,tail);return state}function md51_array(a){var n=a.length,state=[1732584193,-271733879,-1732584194,271733878],i,length,tail,tmp,lo,hi;for(i=64;i<=n;i+=64){md5cycle(state,md5blk_array(a.subarray(i-64,i)))}a=i-64>2]|=a[i]<<(i%4<<3)}tail[i>>2]|=128<<(i%4<<3);if(i>55){md5cycle(state,tail);for(i=0;i<16;i+=1){tail[i]=0}}tmp=n*8;tmp=tmp.toString(16).match(/(.*?)(.{0,8})$/);lo=parseInt(tmp[2],16);hi=parseInt(tmp[1],16)||0;tail[14]=lo;tail[15]=hi;md5cycle(state,tail);return state}function rhex(n){var s="",j;for(j=0;j<4;j+=1){s+=hex_chr[n>>j*8+4&15]+hex_chr[n>>j*8&15]}return s}function hex(x){var i;for(i=0;i>16)+(y>>16)+(lsw>>16);return msw<<16|lsw&65535}}if(typeof ArrayBuffer!=="undefined"&&!ArrayBuffer.prototype.slice){(function(){function clamp(val,length){val=val|0||0;if(val<0){return Math.max(val+length,0)}return Math.min(val,length)}ArrayBuffer.prototype.slice=function(from,to){var length=this.byteLength,begin=clamp(from,length),end=length,num,target,targetArray,sourceArray;if(to!==undefined){end=clamp(to,length)}if(begin>end){return new ArrayBuffer(0)}num=end-begin;target=new ArrayBuffer(num);targetArray=new Uint8Array(target);sourceArray=new Uint8Array(this,begin,num);targetArray.set(sourceArray);return target}})()}function toUtf8(str){if(/[\u0080-\uFFFF]/.test(str)){str=unescape(encodeURIComponent(str))}return str}function utf8Str2ArrayBuffer(str,returnUInt8Array){var length=str.length,buff=new ArrayBuffer(length),arr=new Uint8Array(buff),i;for(i=0;i>2]|=buff.charCodeAt(i)<<(i%4<<3)}this._finish(tail,length);ret=hex(this._hash);if(raw){ret=hexToBinaryString(ret)}this.reset();return ret};SparkMD5.prototype.reset=function(){this._buff="";this._length=0;this._hash=[1732584193,-271733879,-1732584194,271733878];return this};SparkMD5.prototype.getState=function(){return{buff:this._buff,length:this._length,hash:this._hash}};SparkMD5.prototype.setState=function(state){this._buff=state.buff;this._length=state.length;this._hash=state.hash;return this};SparkMD5.prototype.destroy=function(){delete this._hash;delete this._buff;delete this._length};SparkMD5.prototype._finish=function(tail,length){var i=length,tmp,lo,hi;tail[i>>2]|=128<<(i%4<<3);if(i>55){md5cycle(this._hash,tail);for(i=0;i<16;i+=1){tail[i]=0}}tmp=this._length*8;tmp=tmp.toString(16).match(/(.*?)(.{0,8})$/);lo=parseInt(tmp[2],16);hi=parseInt(tmp[1],16)||0;tail[14]=lo;tail[15]=hi;md5cycle(this._hash,tail)};SparkMD5.hash=function(str,raw){return SparkMD5.hashBinary(toUtf8(str),raw)};SparkMD5.hashBinary=function(content,raw){var hash=md51(content),ret=hex(hash);return raw?hexToBinaryString(ret):ret};SparkMD5.ArrayBuffer=function(){this.reset()};SparkMD5.ArrayBuffer.prototype.append=function(arr){var buff=concatenateArrayBuffers(this._buff.buffer,arr,true),length=buff.length,i;this._length+=arr.byteLength;for(i=64;i<=length;i+=64){md5cycle(this._hash,md5blk_array(buff.subarray(i-64,i)))}this._buff=i-64>2]|=buff[i]<<(i%4<<3)}this._finish(tail,length);ret=hex(this._hash);if(raw){ret=hexToBinaryString(ret)}this.reset();return ret};SparkMD5.ArrayBuffer.prototype.reset=function(){this._buff=new Uint8Array(0);this._length=0;this._hash=[1732584193,-271733879,-1732584194,271733878];return this};SparkMD5.ArrayBuffer.prototype.getState=function(){var state=SparkMD5.prototype.getState.call(this);state.buff=arrayBuffer2Utf8Str(state.buff);return state};SparkMD5.ArrayBuffer.prototype.setState=function(state){state.buff=utf8Str2ArrayBuffer(state.buff,true);return SparkMD5.prototype.setState.call(this,state)};SparkMD5.ArrayBuffer.prototype.destroy=SparkMD5.prototype.destroy;SparkMD5.ArrayBuffer.prototype._finish=SparkMD5.prototype._finish;SparkMD5.ArrayBuffer.hash=function(arr,raw){var hash=md51_array(new Uint8Array(arr)),ret=hex(hash);return raw?hexToBinaryString(ret):ret};return SparkMD5}); +;console.log("cryptomodules no longer needed"); \ No newline at end of file diff --git a/lib/s3.js b/lib/s3.js deleted file mode 100644 index 4a0ccc1a..00000000 --- a/lib/s3.js +++ /dev/null @@ -1,102 +0,0 @@ -;(function(){ - - var Gun = require('../gun'); - var S3 = require('./aws'); - - // TODO: BUG! Mark, upgrade S3 in v0.8.X! And try to integrate with Radix Storage Engine!!! - - Gun.on('opt', function(ctx){ - this.to.next(ctx); - var opt = ctx.opt; - if(ctx.once){ return } - if(!process.env.AWS_S3_BUCKET){ return } - console.log("S3 STORAGE ENGINE IS BROKEN IN 0.8! DO NOT USE UNTIL FIXED!"); - var s3 = opt.store || S3(opt.s3 = opt.s3 || {}); - opt.s3.store = s3; - if(!s3 || !s3.config){ return Gun.log("No S3 config!") } - opt.file = opt.file || opt.prefix || ''; - opt.batch = opt.batch || 10; - opt.throttle = opt.throttle || process.env.AWS_S3_THROTTLE || 15; - opt.disconnect = opt.disconnect || 5; - ctx.on('get', function(at){ - this.to.next(at); - var id = at['#'], soul = at.get['#'], field = at.get['.']; - var key = opt.prefix+soul; - s3.GET(key, function(err, data, text, meta){ - meta = meta || {}; - if(err && err.statusCode == 404){ - err = null; // we want a difference between 'unfound' (data is null) and 'error' (auth is wrong). - } - if(!data){ - data = root._.graph[soul] || async[soul]; - } - if(data && !Gun.node.soul(data)){ - err = {err: Gun.log('No soul on S3 node data!')}; - } - if(err){ - root.on('in', {'@': id, err: err}); - return - } - var node = data; - graph[soul] = true; - if(data && field){ - node = Gun.state.ify({}, field, Gun.state.is(node, field), node[field], soul); - } - console.log("got", soul, node); - root.on('in', {'@': id, put: Gun.graph.node(node)}); - }); - }); - ctx.on('put', function(at){ - this.to.next(at); - var id = at['#'], check = {}, next = s3.next, err, u; - Gun.graph.is(at.put, null, function(val, key, node, soul){ - batch[soul] = Gun.state.to(node, key, disk[soul]); - }); - if(!at['@']){ acks[at['#']] = true; } // only ack non-acks. - s3.batching += 1; - if(opt.batch < s3.batching){ - return now(); - } - if(!opt.throttle){ - return now(); - } - s3.wait = s3.wait || setTimeout(now, opt.throttle * 1000); // in seconds - }); - function now(){ - clearTimeout(s3.wait); - var keep = batch; - batch = {}; - s3.batching = 0; - var now = s3.next; - s3.next = Gun.time.is(); - s3.wait = null; - Gun.obj.map(keep, function put(exists, soul, count){ - console.log("s3ving...", soul); - var node = root._.graph[soul] || async[soul]; // the batch does not actually have the nodes, but what happens when we do cold data? Could this be gone? - s3.PUT(opt.prefix+soul, node, function(err, reply){ - if(count < 5 && (err || !reply)){ - put(exists, soul, (count || 0) + 1); // naive implementation of retry TODO: BUG: need backoff and anti-infinite-loop! - return; - } - //console.log("S3VED", soul); - s3.on(now + ':' + soul, [err, reply]); - }); - }); - } - var graph = {}, batch = {}, acks = {}, ids = {}, async = {}; - var count = 0; - s3.next = s3.next || Gun.time.is(); - s3.on = s3.on || Gun.on; - }); - - ;(function(){return; - global.Gun = require('../gun'); - - process.env.AWS_S3_BUCKET = 'test-s3'; - process.env.AWS_ACCESS_KEY_ID = 'asdf'; - process.env.AWS_SECRET_ACCESS_KEY = 'fdsa'; - process.env.fakes3 = 'http://localhost:4567'; - process.env.AWS_S3_THROTTLE = 0; - require('../test/abc'); - }()); -}()); diff --git a/lib/serve.mjs b/lib/serve.mjs deleted file mode 100644 index c3a54d56..00000000 --- a/lib/serve.mjs +++ /dev/null @@ -1,41 +0,0 @@ - -import fs from 'fs' - -let dirname // TODO: where did __dirname go ? - -const serve = (req, res, nxt) => { - if (!req || !res) { - return false - } - - const next = nxt || serve - - if (!req.url) { - return next() - } - - if (0 <= req.url.indexOf('gun.js')) { - res.writeHead(200, { 'Content-Type': 'text/javascript' }) - res.end(serve.js = serve.js || fs.readFileSync(dirname + '/gun.js')) - return true - } - - if (0 <= req.url.indexOf('gun/')) { - res.writeHead(200, { 'Content-Type': 'text/javascript' }) - var path = dirname + '/' + req.url.split('/').slice(2).join('/'), file - try { - file = fs.readFileSync(path) - } catch(e) {} // eslint-disable-line no-empty - if (file) { - res.end(file) - return true - } - } - - return next() -} - -export default (dir) => { - dirname = dir - return serve -} diff --git a/lib/server.mjs b/lib/server.mjs deleted file mode 100644 index 8c3cc007..00000000 --- a/lib/server.mjs +++ /dev/null @@ -1,7 +0,0 @@ - -import serve from './serve' - -export default (Gun, dir) => { // TODO: where did __dirname go ? - Gun.serve = serve(dir) - return Gun -} diff --git a/sea/authenticate.js b/sea/authenticate.js index 9a9f7b6f..54b070d2 100644 --- a/sea/authenticate.js +++ b/sea/authenticate.js @@ -39,6 +39,13 @@ const { epub } = at.put // TODO: 'salt' needed? err = null + if(typeof window !== 'undefined'){ + var tmp = window.sessionStorage; + if(tmp && gunRoot._.opt.remember){ + window.sessionStorage.alias = alias; + window.sessionStorage.tmp = pass; + } + } return Object.assign(props, { priv, salt, epub, epriv }) } catch (e) { err = 'Failed to decrypt secret!' diff --git a/sea/login.js b/sea/login.js index 877378e5..b0e75321 100644 --- a/sea/login.js +++ b/sea/login.js @@ -14,13 +14,6 @@ // persist authentication //await authPersist(user._, key.proof, opts) // temporarily disabled // emit an auth event, useful for page redirects and stuff. - if(typeof window !== 'undefined'){ - var tmp = window.sessionStorage; - if(tmp && gunRoot._.opt.remember){ - window.sessionStorage.alias = alias; - window.sessionStorage.tmp = key; - } - } try { gunRoot._.on('auth', user._) } catch (e) { diff --git a/sea/sea.js b/sea/sea.js index dc1413b0..c384e9f8 100644 --- a/sea/sea.js +++ b/sea/sea.js @@ -65,38 +65,6 @@ throw e } } - // Derive shared secret from other's pub and my epub/epriv - SEA.derive = async (pub, { epub, epriv }) => { - try { - const ecdhSubtle = ossl || subtle - const keysToEcdhJwk = (pub, d) => { // d === priv - const [ x, y ] = Buffer.from(pub, 'base64').toString('utf8').split(':') - const jwk = d ? { d } : {} - return [ // Use with spread returned value... - 'jwk', - { ...jwk, x, y, kty: 'EC', crv: 'P-256', ext: true }, - ecdhKeyProps - ] - } - const pubKeyData = keysToEcdhJwk(pub) - const props = { - ...ecdhKeyProps, - public: await ecdhSubtle.importKey(...pubKeyData, true, []) - } - const privKeyData = keysToEcdhJwk(epub, epriv) - const derived = await ecdhSubtle.importKey(...privKeyData, false, ['deriveKey']) - .then(async (privKey) => { - // privateKey scope doesn't leak out from here! - const derivedKey = await ecdhSubtle.deriveKey(props, privKey, { name: 'AES-CBC', length: 256 }, true, [ 'encrypt', 'decrypt' ]) - return ecdhSubtle.exportKey('jwk', derivedKey).then(({ k }) => k) - }) - return derived - } catch (e) { - console.log(e) - throw e - } - } - // all done! // Obviously it is missing MANY necessary features. This is only an alpha release. // Please experiment with it, audit what I've done so far, and complain about what needs to be added. diff --git a/sea/secret.js b/sea/secret.js new file mode 100644 index 00000000..998196cb --- /dev/null +++ b/sea/secret.js @@ -0,0 +1,44 @@ + + var SEA = require('./root'); + var shim = require('./shim'); + var S = require('./settings'); + // Derive shared secret from other's pub and my epub/epriv + SEA.secret = async (key, pair, cb) => { try { + const pub = key.epub || key + const epub = pair.epub + const epriv = pair.epriv + const ecdhSubtle = shim.ossl || shim.subtle + const pubKeyData = keysToEcdhJwk(pub) + const props = { + ...S.ecdh, + public: await ecdhSubtle.importKey(...pubKeyData, true, []) + } + const privKeyData = keysToEcdhJwk(epub, epriv) + const derived = await ecdhSubtle.importKey(...privKeyData, false, ['deriveKey']) + .then(async (privKey) => { + // privateKey scope doesn't leak out from here! + const derivedKey = await ecdhSubtle.deriveKey(props, privKey, { name: 'AES-CBC', length: 256 }, true, [ 'encrypt', 'decrypt' ]) + return ecdhSubtle.exportKey('jwk', derivedKey).then(({ k }) => k) + }) + const r = derived; + if(cb){ cb(r) } + return r; + } catch(e) { + SEA.err = e; + if(cb){ cb() } + return; + }} + + const keysToEcdhJwk = (pub, d) => { // d === priv + //const [ x, y ] = Buffer.from(pub, 'base64').toString('utf8').split(':') // old + const [ x, y ] = pub.split('.') // new + const jwk = d ? { d } : {} + return [ // Use with spread returned value... + 'jwk', + { ...jwk, x, y, kty: 'EC', crv: 'P-256', ext: true }, // ??? refactor + S.ecdh + ] + } + + module.exports = SEA.secret; + \ No newline at end of file diff --git a/sea/user.js b/sea/user.js index c3176dce..b2d80f9c 100644 --- a/sea/user.js +++ b/sea/user.js @@ -138,8 +138,8 @@ const salt = Gun.text.random(64); const encSigAuth = await SEA.work(newpass, salt) .then((key) => - SEA.encrypt({ priv, epriv }, { pub, key, set: true }) - .then((auth) => SEA.sign({ salt, auth }, keys)) + SEA.encrypt({ priv, epriv }, key) + .then((auth) => SEA.sign({ek: auth, s: salt}, keys)) ) const signedEpub = await SEA.sign(epub, keys) const signedAlias = await SEA.sign(alias, keys) From a173c04a3c721b476e0cb08af6d6d30d9e9eaaf1 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Sat, 21 Apr 2018 00:48:35 -0700 Subject: [PATCH 005/221] fix user API --- gun.js | 8 +- sea.js | 499 ++++++++++++++++++++++++++----------------------- test/user.html | 1 - 3 files changed, 265 insertions(+), 243 deletions(-) diff --git a/gun.js b/gun.js index 42858394..553c0662 100644 --- a/gun.js +++ b/gun.js @@ -657,7 +657,7 @@ return Gun.create(this._ = {gun: this, opt: o}); } - Gun.is = function(gun){ return (gun instanceof Gun) } + Gun.is = function(gun){ return (gun instanceof Gun) || (gun && gun._ && gun._.gun && true) || false } Gun.version = 0.9; @@ -923,11 +923,11 @@ // is complicated and was extremely hard to build. If you port GUN to another // language, consider implementing an easier API to build. var Gun = USE('./root'); - Gun.chain.chain = function(){ - var at = this._, chain = new this.constructor(this), cat = chain._, root; + Gun.chain.chain = function(sub){ + var gun = this, at = gun._, chain = new (sub || gun).constructor(gun), cat = chain._, root; cat.root = root = at.root; cat.id = ++root.once; - cat.back = this._; + cat.back = gun._; cat.on = Gun.on; cat.on('in', input, cat); // For 'in' if I add my own listeners to each then I MUST do it before in gets called. If I listen globally for all incoming data instead though, regardless of individual listeners, I can transform the data there and then as well. cat.on('out', output, cat); // However for output, there isn't really the global option. I must listen by adding my own listener individually BEFORE this one is ever called. diff --git a/sea.js b/sea.js index 8c1218ba..2a2de402 100644 --- a/sea.js +++ b/sea.js @@ -831,7 +831,9 @@ const finalizeLogin = async (alias, key, gunRoot, opts) => { const { user } = gunRoot._ // add our credentials in-memory only to our root gun instance + //var tmp = user._.tag; user._ = key.at.gun._ + //user._.tag = tmp || user._.tag; // so that way we can use the credentials to encrypt/decrypt data // that is input/output through gun (see below) const { pub, priv, epub, epriv } = key @@ -1015,11 +1017,43 @@ })(USE, './leave'); ;USE(function(module){ - // How does it work? - // TODO: Bug! Need to include SEA! - //const Gun = (typeof window !== 'undefined' ? window : global).Gun || USE('gun/gun') + var Gun = USE('./sea').Gun; + Gun.chain.then = function(cb){ + var gun = this, p = (new Promise(function(res, rej){ + gun.once(res); + })); + return cb? p.then(cb) : p; + } + })(USE, './then'); + + ;USE(function(module){ + var SEA = USE('./sea'); + var Gun = SEA.Gun; + var then = USE('./then'); + + function User(){ + this._ = {gun: this} + Gun.call() + } + User.prototype = (function(){ function F(){}; F.prototype = Gun.chain; return new F() }()) // Object.create polyfill + User.prototype.constructor = User; + + // let's extend the gun chain with a `user` function. + // only one user can be logged in at a time, per gun instance. + Gun.chain.user = function(pub){ + var gun = this, root = gun.back(-1); + if(pub){ return root.get('pub/'+pub) } + return root.back('user') || ((root._).user = gun.chain(new User)); + } + module.exports = User; + })(USE, './user'); + + ;USE(function(module){ + // TODO: This needs to be split into all separate functions. + // Not just everything thrown into 'create'. const SEA = USE('./sea') + const User = USE('./user') const authRecall = USE('./recall') const authsettings = USE('./settings') const authenticate = USE('./authenticate') @@ -1028,250 +1062,239 @@ const { recall: _initial_authsettings } = USE('./settings') const Gun = SEA.Gun; - // let's extend the gun chain with a `user` function. - // only one user can be logged in at a time, per gun instance. - Gun.chain.user = function() { - const gunRoot = this.back(-1) // always reference the root gun instance. - const user = gunRoot._.user || (gunRoot._.user = gunRoot.chain()); // create a user context. - // then methods... - [ 'create', // factory - 'auth', // login - 'leave', // logout - 'delete', // account delete - 'recall', // existing auth boostrap - 'alive' // keep/check auth validity - ].map((method)=> user[method] = User[method]) - return user // return the user! - } var u; - function User(){} // Well first we have to actually create a user. That is what this function does. - Object.assign(User, { - async create(username, pass, cb) { - const gunRoot = this.back(-1) - var gun = this, cat = (gun._); - cb = cb || function(){}; - if(cat.ing){ - cb({err: Gun.log("User is already being created or authenticated!"), wait: true}); - return gun; - } - cat.ing = true; - var p = new Promise((resolve, reject) => { // Because no Promises or async - // Because more than 1 user might have the same username, we treat the alias as a list of those users. - if(cb){ resolve = reject = cb } - gunRoot.get(`alias/${username}`).get(async (at, ev) => { - ev.off() - if (at.put) { - // If we can enforce that a user name is already taken, it might be nice to try, but this is not guaranteed. - const err = 'User already created!' - Gun.log(err) - cat.ing = false; - gun.leave(); - return reject({ err }) - } - const salt = Gun.text.random(64) - // pseudo-randomly create a salt, then use CryptoJS's PBKDF2 function to extend the password with it. - try { - const proof = await SEA.work(pass, salt) - // this will take some short amount of time to produce a proof, which slows brute force attacks. - const pairs = await SEA.pair() - // now we have generated a brand new ECDSA key pair for the user account. - const { pub, priv, epriv } = pairs - // the user's public key doesn't need to be signed. But everything else needs to be signed with it! - const alias = await SEA.sign(username, pairs) - if(u === alias){ throw SEA.err } - const epub = await SEA.sign(pairs.epub, pairs) - if(u === epub){ throw SEA.err } - // to keep the private key safe, we AES encrypt it with the proof of work! - const auth = await SEA.encrypt({ priv, epriv }, proof) - .then((auth) => // TODO: So signedsalt isn't needed? - // SEA.sign(salt, pairs).then((signedsalt) => - SEA.sign({ek: auth, s: salt}, pairs) - // ) - ).catch((e) => { Gun.log('SEA.en or SEA.write calls failed!'); cat.ing = false; gun.leave(); reject(e) }) - const user = { alias, pub, epub, auth } - const tmp = `pub/${pairs.pub}` - // awesome, now we can actually save the user with their public key as their ID. - try{ - - gunRoot.get(tmp).put(user) - }catch(e){console.log(e)} - // next up, we want to associate the alias with the public key. So we add it to the alias list. - gunRoot.get(`alias/${username}`).put(Gun.obj.put({}, tmp, Gun.val.rel.ify(tmp))) - // callback that the user has been created. (Note: ok = 0 because we didn't wait for disk to ack) - setTimeout(() => { cat.ing = false; resolve({ ok: 0, pub: pairs.pub}) }, 10) // TODO: BUG! If `.auth` happens synchronously after `create` finishes, auth won't work. This setTimeout is a temporary hack until we can properly fix it. - } catch (e) { - Gun.log('SEA.create failed!') - cat.ing = false; - gun.leave(); - reject(e) - } - }) - }) - return gun // gun chain commands must return gun chains! - }, - // now that we have created a user, we want to authenticate them! - async auth(alias, pass, cb, opt) { - const opts = opt || (typeof cb !== 'function' && cb) - let { pin, newpass } = opts || {} - const gunRoot = this.back(-1) - cb = typeof cb === 'function' ? cb : () => {} - newpass = newpass || (opts||{}).change; - var gun = this, cat = (gun._); - if(cat.ing){ - cb({err: "User is already being created or authenticated!", wait: true}); - return gun; - } - cat.ing = true; - - if (!pass && pin) { - try { - var r = await authRecall(gunRoot, { alias, pin }) - return cat.ing = false, cb(r), gun; - } catch (e) { - var err = { err: 'Auth attempt failed! Reason: No session data for alias & PIN' } - return cat.ing = false, gun.leave(), cb(err), gun; - } - } - - const putErr = (msg) => (e) => { - const { message, err = message || '' } = e - Gun.log(msg) - var error = { err: `${msg} Reason: ${err}` } - return cat.ing = false, gun.leave(), cb(error), gun; - } - - try { - const keys = await authenticate(alias, pass, gunRoot) - if (!keys) { - return putErr('Auth attempt failed!')({ message: 'No keys' }) - } - const { pub, priv, epub, epriv } = keys - // we're logged in! - if (newpass) { - // password update so encrypt private key using new pwd + salt - try { - const salt = Gun.text.random(64); - const encSigAuth = await SEA.work(newpass, salt) - .then((key) => - SEA.encrypt({ priv, epriv }, key) - .then((auth) => SEA.sign({ek: auth, s: salt}, keys)) - ) - const signedEpub = await SEA.sign(epub, keys) - const signedAlias = await SEA.sign(alias, keys) - const user = { - pub, - alias: signedAlias, - auth: encSigAuth, - epub: signedEpub - } - // awesome, now we can update the user using public key ID. - gunRoot.get(`pub/${user.pub}`).put(user) - // then we're done - const login = finalizeLogin(alias, keys, gunRoot, { pin }) - login.catch(putErr('Failed to finalize login with new password!')) - return cat.ing = false, cb(await login), gun - } catch (e) { - return putErr('Password set attempt failed!')(e) - } - } else { - const login = finalizeLogin(alias, keys, gunRoot, { pin }) - login.catch(putErr('Finalizing login failed!')) - return cat.ing = false, cb(await login), gun; - } - } catch (e) { - return putErr('Auth attempt failed!')(e) - } + User.prototype.create = function(username, pass, cb){ + // TODO: Needs to be cleaned up!!! + const gunRoot = this.back(-1) + var gun = this, cat = (gun._); + cb = cb || function(){}; + if(cat.ing){ + cb({err: Gun.log("User is already being created or authenticated!"), wait: true}); return gun; - }, - async leave() { - return await authLeave(this.back(-1)) - }, - // If authenticated user wants to delete his/her account, let's support it! - async delete(alias, pass) { - const gunRoot = this.back(-1) - try { - const { pub } = await authenticate(alias, pass, gunRoot) - await authLeave(gunRoot, alias) - // Delete user data - gunRoot.get(`pub/${pub}`).put(null) - // Wipe user data from memory - const { user = { _: {} } } = gunRoot._; - // TODO: is this correct way to 'logout' user from Gun.User ? - [ 'alias', 'sea', 'pub' ].map((key) => delete user._[key]) - user._.is = user.is = {} - gunRoot.user() - return { ok: 0 } // TODO: proper return codes??? - } catch (e) { - Gun.log('User.delete failed! Error:', e) - throw e // TODO: proper error codes??? + } + cat.ing = true; + var resolve = function(){}, reject = resolve; + // Because more than 1 user might have the same username, we treat the alias as a list of those users. + if(cb){ resolve = reject = cb } + gunRoot.get(`alias/${username}`).get(async (at, ev) => { + ev.off() + if (at.put) { + // If we can enforce that a user name is already taken, it might be nice to try, but this is not guaranteed. + const err = 'User already created!' + Gun.log(err) + cat.ing = false; + gun.leave(); + return reject({ err }) } - }, - // If authentication is to be remembered over reloads or browser closing, - // set validity time in minutes. - async recall(setvalidity, options) { - const gunRoot = this.back(-1) + const salt = Gun.text.random(64) + // pseudo-randomly create a salt, then use CryptoJS's PBKDF2 function to extend the password with it. + try { + const proof = await SEA.work(pass, salt) + // this will take some short amount of time to produce a proof, which slows brute force attacks. + const pairs = await SEA.pair() + // now we have generated a brand new ECDSA key pair for the user account. + const { pub, priv, epriv } = pairs + // the user's public key doesn't need to be signed. But everything else needs to be signed with it! + const alias = await SEA.sign(username, pairs) + if(u === alias){ throw SEA.err } + const epub = await SEA.sign(pairs.epub, pairs) + if(u === epub){ throw SEA.err } + // to keep the private key safe, we AES encrypt it with the proof of work! + const auth = await SEA.encrypt({ priv, epriv }, proof) + .then((auth) => // TODO: So signedsalt isn't needed? + // SEA.sign(salt, pairs).then((signedsalt) => + SEA.sign({ek: auth, s: salt}, pairs) + // ) + ).catch((e) => { Gun.log('SEA.en or SEA.write calls failed!'); cat.ing = false; gun.leave(); reject(e) }) + const user = { alias, pub, epub, auth } + const tmp = `pub/${pairs.pub}` + // awesome, now we can actually save the user with their public key as their ID. + try{ - let validity - let opts - - var o = setvalidity; - if(o && o.sessionStorage){ - if(typeof window !== 'undefined'){ - var tmp = window.sessionStorage; - if(tmp){ - gunRoot._.opt.remember = true; - if(tmp.alias && tmp.tmp){ - gunRoot.user().auth(tmp.alias, tmp.tmp); + gunRoot.get(tmp).put(user) + }catch(e){console.log(e)} + // next up, we want to associate the alias with the public key. So we add it to the alias list. + gunRoot.get(`alias/${username}`).put(Gun.obj.put({}, tmp, Gun.val.rel.ify(tmp))) + // callback that the user has been created. (Note: ok = 0 because we didn't wait for disk to ack) + setTimeout(() => { cat.ing = false; resolve({ ok: 0, pub: pairs.pub}) }, 10) // TODO: BUG! If `.auth` happens synchronously after `create` finishes, auth won't work. This setTimeout is a temporary hack until we can properly fix it. + } catch (e) { + Gun.log('SEA.create failed!') + cat.ing = false; + gun.leave(); + reject(e) + } + }) + return gun; // gun chain commands must return gun chains! + } + // now that we have created a user, we want to authenticate them! + User.prototype.auth = function(alias, pass, cb, opt){ + // TODO: Needs to be cleaned up!!!! + const opts = opt || (typeof cb !== 'function' && cb) + let { pin, newpass } = opts || {} + const gunRoot = this.back(-1) + cb = typeof cb === 'function' ? cb : () => {} + newpass = newpass || (opts||{}).change; + var gun = this, cat = (gun._); + if(cat.ing){ + cb({err: "User is already being created or authenticated!", wait: true}); + return gun; + } + cat.ing = true; + + if (!pass && pin) { (async function(){ + try { + var r = await authRecall(gunRoot, { alias, pin }) + return cat.ing = false, cb(r), gun; + } catch (e) { + var err = { err: 'Auth attempt failed! Reason: No session data for alias & PIN' } + return cat.ing = false, gun.leave(), cb(err), gun; + }}()) + return gun; + } + + const putErr = (msg) => (e) => { + const { message, err = message || '' } = e + Gun.log(msg) + var error = { err: `${msg} Reason: ${err}` } + return cat.ing = false, gun.leave(), cb(error), gun; + } + + (async function(){ try { + const keys = await authenticate(alias, pass, gunRoot) + if (!keys) { + return putErr('Auth attempt failed!')({ message: 'No keys' }) + } + const { pub, priv, epub, epriv } = keys + // we're logged in! + if (newpass) { + // password update so encrypt private key using new pwd + salt + try { + const salt = Gun.text.random(64); + const encSigAuth = await SEA.work(newpass, salt) + .then((key) => + SEA.encrypt({ priv, epriv }, key) + .then((auth) => SEA.sign({ek: auth, s: salt}, keys)) + ) + const signedEpub = await SEA.sign(epub, keys) + const signedAlias = await SEA.sign(alias, keys) + const user = { + pub, + alias: signedAlias, + auth: encSigAuth, + epub: signedEpub + } + // awesome, now we can update the user using public key ID. + gunRoot.get(`pub/${user.pub}`).put(user) + // then we're done + const login = finalizeLogin(alias, keys, gunRoot, { pin }) + login.catch(putErr('Failed to finalize login with new password!')) + return cat.ing = false, cb(await login), gun + } catch (e) { + return putErr('Password set attempt failed!')(e) + } + } else { + const login = finalizeLogin(alias, keys, gunRoot, { pin }) + login.catch(putErr('Finalizing login failed!')) + return cat.ing = false, cb(await login), gun; + } + } catch (e) { + return putErr('Auth attempt failed!')(e) + } }()); + return gun; + } + User.prototype.pair = function(){ + var user = this; + if(!user.is){ return false } + return user._.sea; + } + User.prototype.leave = async function(){ + return await authLeave(this.back(-1)) + } + // If authenticated user wants to delete his/her account, let's support it! + User.prototype.delete = async function(alias, pass){ + const gunRoot = this.back(-1) + try { + const { pub } = await authenticate(alias, pass, gunRoot) + await authLeave(gunRoot, alias) + // Delete user data + gunRoot.get(`pub/${pub}`).put(null) + // Wipe user data from memory + const { user = { _: {} } } = gunRoot._; + // TODO: is this correct way to 'logout' user from Gun.User ? + [ 'alias', 'sea', 'pub' ].map((key) => delete user._[key]) + user._.is = user.is = {} + gunRoot.user() + return { ok: 0 } // TODO: proper return codes??? + } catch (e) { + Gun.log('User.delete failed! Error:', e) + throw e // TODO: proper error codes??? + } + } + // If authentication is to be remembered over reloads or browser closing, + // set validity time in minutes. + User.prototype.recall = async function(setvalidity, options){ + const gunRoot = this.back(-1) + + let validity + let opts + + var o = setvalidity; + if(o && o.sessionStorage){ + if(typeof window !== 'undefined'){ + var tmp = window.sessionStorage; + if(tmp){ + gunRoot._.opt.remember = true; + if(tmp.alias && tmp.tmp){ + gunRoot.user().auth(tmp.alias, tmp.tmp); + } } } + return this; + } + + if (!Gun.val.is(setvalidity)) { + opts = setvalidity + validity = _initial_authsettings.validity + } else { + opts = options + validity = setvalidity * 60 // minutes to seconds + } + + try { + // opts = { hook: function({ iat, exp, alias, proof }) } + // iat == Date.now() when issued, exp == seconds to expire from iat + // How this works: + // called when app bootstraps, with wanted options + // IF authsettings.validity === 0 THEN no remember-me, ever + // IF PIN then signed 'remember' to window.sessionStorage and 'auth' to IndexedDB + authsettings.validity = typeof validity !== 'undefined' + ? validity : _initial_authsettings.validity + authsettings.hook = (Gun.obj.has(opts, 'hook') && typeof opts.hook === 'function') + ? opts.hook : _initial_authsettings.hook + // All is good. Should we do something more with actual recalled data? + return await authRecall(gunRoot) + } catch (e) { + const err = 'No session!' + Gun.log(err) + // NOTE! It's fine to resolve recall with reason why not successful + // instead of rejecting... + return { err: (e && e.err) || err } } - return this; } - - if (!Gun.val.is(setvalidity)) { - opts = setvalidity - validity = _initial_authsettings.validity - } else { - opts = options - validity = setvalidity * 60 // minutes to seconds - } - - try { - // opts = { hook: function({ iat, exp, alias, proof }) } - // iat == Date.now() when issued, exp == seconds to expire from iat - // How this works: - // called when app bootstraps, with wanted options - // IF authsettings.validity === 0 THEN no remember-me, ever - // IF PIN then signed 'remember' to window.sessionStorage and 'auth' to IndexedDB - authsettings.validity = typeof validity !== 'undefined' - ? validity : _initial_authsettings.validity - authsettings.hook = (Gun.obj.has(opts, 'hook') && typeof opts.hook === 'function') - ? opts.hook : _initial_authsettings.hook - // All is good. Should we do something more with actual recalled data? - return await authRecall(gunRoot) - } catch (e) { - const err = 'No session!' - Gun.log(err) - // NOTE! It's fine to resolve recall with reason why not successful - // instead of rejecting... - return { err: (e && e.err) || err } - } - }, - async alive() { - const gunRoot = this.back(-1) - try { - // All is good. Should we do something more with actual recalled data? - await authRecall(gunRoot) - return gunRoot._.user._ - } catch (e) { - const err = 'No session!' - Gun.log(err) - throw { err } - } + User.prototype.alive = async function(){ + const gunRoot = this.back(-1) + try { + // All is good. Should we do something more with actual recalled data? + await authRecall(gunRoot) + return gunRoot._.user._ + } catch (e) { + const err = 'No session!' + Gun.log(err) + throw { err } } - }) - Gun.chain.trust = function(user) { + } + User.prototype.trust = async function(user){ // TODO: BUG!!! SEA `node` read listener needs to be async, which means core needs to be async too. //gun.get('alice').get('age').trust(bob); if (Gun.is(user)) { @@ -1281,7 +1304,7 @@ } } module.exports = User - })(USE, './user'); + })(USE, './create'); ;USE(function(module){ const Gun = (typeof window !== 'undefined' ? window : global).Gun || USE('gun/gun') diff --git a/test/user.html b/test/user.html index 4837bf66..30de03f8 100644 --- a/test/user.html +++ b/test/user.html @@ -17,7 +17,6 @@ - - + \ No newline at end of file diff --git a/test/old/performance.js b/test/old/performance.js new file mode 100644 index 00000000..3243db11 --- /dev/null +++ b/test/old/performance.js @@ -0,0 +1,138 @@ +describe('Performance', function(){ return; // performance tests + var console = root.console || {log: function(){}}; + function perf(fn, i){ + i = i || 1000; + while(--i){ + fn(i); + } + } + perf.now = this.performance? function(){ return performance.now() } : function(){ return Gun.time.now()/1000 }; + (function(){ + var t1 = perf.now(); + var obj = {1: 'a', 2: 'b', 3: 'c', 4: 'd', 5: 'e', 6: 'f', 7: 'g', 8: 'h', 9: 'i'}; + Object.keys && perf(function(){ + var l = Object.keys(obj), ll = l.length, i = 0, s = ''; + for(; i < ll; i++){ + var v = l[i]; + s += v; + } + }); + console.log('map: native', (t1 = (perf.now() - t1)/1000) + 's'); + + var t2 = perf.now(); + var obj = {1: 'a', 2: 'b', 3: 'c', 4: 'd', 5: 'e', 6: 'f', 7: 'g', 8: 'h', 9: 'i'}; + perf(function(){ + var s = ''; + Gun.obj.map(obj, function(v){ + s += v; + }) + }); + console.log('map: gun', (t2 = (perf.now() - t2)/1000) + 's', (t2 / t1).toFixed(1)+'x', 'slower.'); + }()); + (function(){ + if(!Gun.store){ + var tab = Gun().tab; + if(!tab){ return } + Gun.store = tab.store; + } + root.localStorage && root.localStorage.clear(); + var it = 1000; + var t1 = perf.now(); + perf(function(i){ + var obj = {'i': i, 'v': Gun.text.random(100)}; + Gun.store.put('test/native/' + i, obj); + }, it); + console.log('store: native', (t1 = (perf.now() - t1)/1000) + 's'); + + root.localStorage && root.localStorage.clear(); + var gun = Gun({wire: {get:function(l,cb){cb()},put:function(g,cb){ + Gun.is.graph(g, function(node, soul){ + Gun.store.put(soul, node); + }); + cb(null); + }}}); + var t2 = perf.now(); + perf(function(i){ + var obj = {'i': i, 'v': Gun.text.random(100)}; + gun.put(obj); + }, it); + console.log('store: gun', (t2 = (perf.now() - t2)/1000) + 's', (t2 / t1).toFixed(1)+'x', 'slower.'); + root.localStorage && root.localStorage.clear(); + }()); + (function(){ // setTimeout + if(!Gun.store){ + var tab = Gun().tab; + if(!tab){ return } + Gun.store = tab.store; + } + root.localStorage && root.localStorage.clear(); + var t1 = perf.now(); + i = i || 1000; + while(--i){ + var obj = {'i': i, 'v': Gun.text.random(100)}; + Gun.store.put('test/native/' + i, obj); + } + console.log('store: native', (t1 = (perf.now() - t1)/1000) + 's'); + + root.localStorage && root.localStorage.clear(); + var gun = Gun({wire: {get:function(l,cb){cb()},put:function(g,cb){ + Gun.is.graph(g, function(node, soul){ + Gun.store.put(soul, node); + }); + cb(null); + }}}); + var t2 = perf.now(); + perf(function(i){ + var obj = {'i': i, 'v': Gun.text.random(100)}; + gun.put(obj); + }, it); + console.log('store: gun', (t2 = (perf.now() - t2)/1000) + 's', (t2 / t1).toFixed(1)+'x', 'slower.'); + root.localStorage && root.localStorage.clear(); + }()); + (function(){ + var t1 = perf.now(); + var on = Gun.on.create(), c = 0, o = []; + perf(function(i){ + o.push(function(n){ + c += 1; + }); + var ii = 0, l = o.length; + for(; ii < l; ii++){ + o[ii](i); + } + }); + console.log('on: native', (t1 = (perf.now() - t1)/1000) + 's'); + + var on = Gun.on.create(), c = 0; + var t2 = perf.now(); + perf(function(i){ + on('change').event(function(n){ + c += 1; + }); + on('change').emit(i); + }); + console.log('on: gun', (t2 = (perf.now() - t2)/1000) + 's', (t2 / t1).toFixed(1)+'x', 'slower.'); + }());return; + (function(){ // always do this last! + var t1 = perf.now(); + perf(function(i){ + setTimeout(function(){ + if(i === 1){ + cb1(); + } + },0); + }); var cb1 = function(){ + console.log('setTimeout: native', (t1 = (perf.now() - t1)/1000) + 's', (t1 / t2).toFixed(1)+'x', 'slower.'); + } + var t2 = perf.now(); + perf(function(i){ + setImmediate(function(){ + if(i === 1){ + cb2(); + } + }); + }); var cb2 = function(){ + console.log('setImmediate: gun', (t2 = (perf.now() - t2)/1000) + 's', (t2 / t1).toFixed(1)+'x', 'slower.'); + } + }()); +}); \ No newline at end of file diff --git a/test/panic/speak.js b/test/panic/speak.js index 7af18e66..130e7c38 100644 --- a/test/panic/speak.js +++ b/test/panic/speak.js @@ -172,7 +172,7 @@ describe("Stress test GUN with SEA users causing PANIC!", function(){ var no; Gun.node.is(at.put.users, function(val, key){ Gun.SEA.read(val, false, function(val){ - if('alias/'+key === Gun.val.rel.is(val)){ return } + if('alias/'+key === Gun.val.link.is(val)){ return } no = true; }) if(no){ return no } diff --git a/test/say.html b/test/say.html index 316e6fb6..27d1ccb8 100644 --- a/test/say.html +++ b/test/say.html @@ -15,7 +15,7 @@ var no; Gun.node.is(at.put.users, function(val, key){ Gun.SEA.read(val, false, function(val){ - if('alias/'+key === Gun.val.rel.is(val)){ return } + if('alias/'+key === Gun.val.link.is(val)){ return } no = true; }) if(no){ return no } From 63811d12fccf8dee8e0632352fd8f33ed8f9660f Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Tue, 19 Jun 2018 15:59:11 -0700 Subject: [PATCH 047/221] chain != gun, ? chain = user etc., .gun -> $ chain --- gun.js | 178 ++++++++++++++++++++++++------------------------ test/common.js | 127 +++++++++++++++++----------------- test/mocha.html | 1 + 3 files changed, 153 insertions(+), 153 deletions(-) diff --git a/gun.js b/gun.js index 2f892388..427d3b3a 100644 --- a/gun.js +++ b/gun.js @@ -652,12 +652,12 @@ ;USE(function(module){ function Gun(o){ - if(o instanceof Gun){ return (this._ = {gun: this}).gun } + if(o instanceof Gun){ return (this._ = {gun: this, $: this}).$ } if(!(this instanceof Gun)){ return new Gun(o) } - return Gun.create(this._ = {gun: this, opt: o}); + return Gun.create(this._ = {gun: this, $: this, opt: o}); } - Gun.is = function(gun){ return (gun instanceof Gun) || (gun && gun._ && gun._.gun && true) || false } + Gun.is = function($){ return ($ instanceof Gun) || ($ && $._ && ($ === $._.$)) || false } Gun.version = 0.9; @@ -682,7 +682,7 @@ at.on = at.on || Gun.on; at.ask = at.ask || Gun.ask; at.dup = at.dup || Gun.dup(); - var gun = at.gun.opt(at.opt); + var gun = at.$.opt(at.opt); if(!at.once){ at.on('in', root, at); at.on('out', root, {at: at, out: root}); @@ -694,8 +694,7 @@ } function root(msg){ //console.log("add to.next(at)"); // TODO: MISSING FEATURE!!! - var ev = this, as = ev.as, at = as.at || as, gun = at.gun, dup, tmp; - //if(!msg.gun){ msg.gun = at.gun } + var ev = this, as = ev.as, at = as.at || as, gun = at.$, dup, tmp; if(!(tmp = msg['#'])){ tmp = msg['#'] = text_rand(9) } if((dup = at.dup).check(tmp)){ if(as.out === msg.out){ @@ -705,15 +704,12 @@ return; } dup.track(tmp); - //msg = obj_to(msg);//, {gun: at.gun}); // can we delete this now? if(!at.ask(msg['@'], msg)){ if(msg.get){ - Gun.on.get(msg, gun); - //at.on('get', get(msg)); + Gun.on.get(msg, gun); //at.on('get', get(msg)); } if(msg.put){ - Gun.on.put(msg, gun); - //at.on('put', put(msg)); + Gun.on.put(msg, gun); //at.on('put', put(msg)); } } ev.to.next(msg); @@ -726,7 +722,7 @@ ;(function(){ Gun.on.put = function(msg, gun){ - var at = gun._, ctx = {gun: gun, graph: at.graph, put: {}, map: {}, souls: {}, machine: Gun.state(), ack: msg['@'], cat: at, stop: {}}; + var at = gun._, ctx = {$: gun, graph: at.graph, put: {}, map: {}, souls: {}, machine: Gun.state(), ack: msg['@'], cat: at, stop: {}}; if(!Gun.graph.is(msg.put, null, verify, ctx)){ ctx.err = "Error: Invalid graph!" } if(ctx.err){ return at.on('in', {'@': msg['#'], err: Gun.log(ctx.err) }) } obj_map(ctx.put, merge, ctx); @@ -755,18 +751,18 @@ ctx.souls[soul] = true; } function merge(node, soul){ - var ctx = this, cat = ctx.gun._, at = (cat.next || empty)[soul]; + var ctx = this, cat = ctx.$._, at = (cat.next || empty)[soul]; if(!at){ if(!(cat.opt||empty).super){ ctx.souls[soul] = false; return; } - at = (ctx.gun.get(soul)._); + at = (ctx.$.get(soul)._); } var msg = ctx.map[soul] = { put: node, get: soul, - gun: at.gun + $: at.$ }, as = {ctx: ctx, msg: msg}; ctx.async = !!cat.tag.node; if(ctx.ack){ msg['@'] = ctx.ack } @@ -789,20 +785,20 @@ cat.on('node', msg); // each node on the current context's graph needs to be emitted though. } function each(val, key){ - var ctx = this.ctx, graph = ctx.graph, msg = this.msg, soul = msg.get, node = msg.put, at = (msg.gun._), tmp; + var ctx = this.ctx, graph = ctx.graph, msg = this.msg, soul = msg.get, node = msg.put, at = (msg.$._), tmp; graph[soul] = Gun.state.to(node, key, graph[soul]); if(ctx.async){ return } at.put = Gun.state.to(node, key, at.put); } function patch(val, key){ - var msg = this, node = msg.put, at = (msg.gun._); + var msg = this, node = msg.put, at = (msg.$._); at.put = Gun.state.to(node, key, at.put); } function map(msg, soul){ - if(!msg.gun){ return } + if(!msg.$){ return } this.cat.stop = this.stop; // temporary fix till a better solution? //console.log("MAP |||-->", soul); - (msg.gun._).on('in', msg); + (msg.$._).on('in', msg); this.cat.stop = null; // temporary fix till a better solution? } @@ -825,7 +821,7 @@ '@': msg['#'], how: 'mem', put: node, - gun: gun + $: gun }); //if(0 < tmp){ // return; @@ -895,10 +891,10 @@ Gun.chain.back = function(n, opt){ var tmp; n = n || 1; if(-1 === n || Infinity === n){ - return this._.root.gun; + return this._.root.$; } else if(1 === n){ - return (this._.back || this._).gun; + return (this._.back || this._).$; } var gun = this, at = gun._; if(typeof n === 'string'){ @@ -913,7 +909,7 @@ return opt? gun : tmp; } else if((tmp = at.back)){ - return tmp.gun.back(n, opt); + return tmp.$.back(n, opt); } return; } @@ -924,7 +920,7 @@ return yes; } if(Gun.num.is(n)){ - return (at.back || at).gun.back(n - 1); + return (at.back || at).$.back(n - 1); } return this; } @@ -949,8 +945,8 @@ function output(msg){ var put, get, at = this.as, back = at.back, root = at.root; - if(!msg.I){ msg.I = at.gun } - if(!msg.gun){ msg.gun = at.gun } + if(!msg.I){ msg.I = at.$ } + if(!msg.$){ msg.$ = at.$ } this.to.next(msg); if(get = msg.get){ /*if(u !== at.put){ @@ -960,19 +956,19 @@ if(get['#'] || at.soul){ get['#'] = get['#'] || at.soul; msg['#'] || (msg['#'] = text_rand(9)); - back = (root.gun.get(get['#'])._); + back = (root.$.get(get['#'])._); if(!(get = get['.'])){ if(obj_has(back, 'put')){ //if(u !== back.put){ back.on('in', back); } if(back.ack){ return } - msg.gun = back.gun; + msg.$ = back.$; back.ack = -1; } else if(obj_has(back.put, get)){ back.on('in', { - gun: back.gun, + $: back.$, put: Gun.state.to(back.put, get), get: back.get }); @@ -984,18 +980,18 @@ if(root.now){ root.now[at.id] = root.now[at.id] || true; at.pass = {} } if(get['.']){ if(at.get){ - msg = {get: {'.': at.get}, gun: at.gun}; - (back.ask || (back.ask = {}))[at.get] = msg.gun._; // TODO: PERFORMANCE? More elegant way? + msg = {get: {'.': at.get}, $: at.$}; + (back.ask || (back.ask = {}))[at.get] = msg.$._; // TODO: PERFORMANCE? More elegant way? return back.on('out', msg); } - msg = {get: {}, gun: at.gun}; + msg = {get: {}, $: at.$}; return back.on('out', msg); } at.ack = at.ack || -1; if(at.get){ - msg.gun = at.gun; + msg.$ = at.$; get['.'] = at.get; - (back.ask || (back.ask = {}))[at.get] = msg.gun._; // TODO: PERFORMANCE? More elegant way? + (back.ask || (back.ask = {}))[at.get] = msg.$._; // TODO: PERFORMANCE? More elegant way? return back.on('out', msg); } } @@ -1003,12 +999,12 @@ } function input(msg){ - var ev = this, cat = ev.as, gun = msg.gun, at = (gun||empty)._ || empty, change = msg.put, rel, tmp; + var ev = this, cat = ev.as, gun = msg.$, at = (gun||empty)._ || empty, change = msg.put, rel, tmp; if(cat.get && msg.get !== cat.get){ msg = obj_to(msg, {get: cat.get}); } if(cat.has && at !== cat){ - msg = obj_to(msg, {gun: cat.gun}); + msg = obj_to(msg, {$: cat.$}); if(at.ack){ cat.ack = at.ack; //cat.ack = cat.ack || at.ack; @@ -1053,7 +1049,7 @@ cat.put = at.put; }; if((rel = Gun.node.soul(change)) && at.has){ - at.put = (cat.root.gun.get(rel)._).put; + at.put = (cat.root.$.get(rel)._).put; } ev.to.next(msg); echo(cat, msg, ev); @@ -1067,7 +1063,7 @@ function relate(at, msg, from, rel){ if(!rel || node_ === at.get){ return } - var tmp = (at.root.gun.get(rel)._); + var tmp = (at.root.$.get(rel)._); if(at.has){ from = tmp; } else @@ -1075,7 +1071,7 @@ relate(from, msg, from, rel); } if(from === at){ return } - if(!from.gun){ from = {} } + if(!from.$){ from = {} } (from.echo || (from.echo = {}))[at.id] = at; if(at.has && !(at.map||empty)[from.id]){ // if we haven't seen this before. not(at, msg); @@ -1127,20 +1123,20 @@ if(!(at = next[key])){ return; } - //if(data && data[_soul] && (tmp = Gun.val.rel.is(data)) && (tmp = (cat.root.gun.get(tmp)._)) && obj_has(tmp, 'put')){ + //if(data && data[_soul] && (tmp = Gun.val.rel.is(data)) && (tmp = (cat.root.$.get(tmp)._)) && obj_has(tmp, 'put')){ // data = tmp.put; //} if(at.has){ if(!(data && data[_soul] && Gun.val.rel.is(data) === Gun.node.soul(at.put))){ at.put = data; } - chain = at.gun; + chain = at.$; } else - if(via.gun){ chain = via.gun.get(key) } + if(via.$){ chain = via.$.get(key) } at.on('in', { put: data, get: key, - gun: chain, + $: chain, via: via }); } @@ -1165,13 +1161,13 @@ } neat.on('in', { get: key, - gun: neat.gun, + $: neat.$, put: u }); }); } function ask(at, soul){ - var tmp = (at.root.gun.get(soul)._); + var tmp = (at.root.$.get(soul)._); if(at.ack){ tmp.on('out', {get: {'#': soul}}); if(!at.ask){ return } // TODO: PERFORMANCE? More elegant way? @@ -1182,7 +1178,7 @@ Gun.obj.del(at, 'ask'); // TODO: PERFORMANCE? More elegant way? } function ack(msg, ev){ - var as = this.as, get = as.get || empty, at = as.gun._, tmp = (msg.put||empty)[get['#']]; + var as = this.as, get = as.get || empty, at = as.$._, tmp = (msg.put||empty)[get['#']]; if(at.ack){ at.ack = (at.ack + 1) || 1 } if(!msg.put /*|| node_ == get['.']*/ || (get['.'] && !obj_has(tmp, at.get))){ if(at.put !== u){ return } @@ -1190,20 +1186,20 @@ at.on('in', { get: at.get, put: at.put = u, - gun: at.gun, + $: at.$, '@': msg['@'] }) return; } if(node_ == get['.']){ // is this a security concern? - at.on('in', {get: at.get, put: Gun.val.link.ify(get['#']), gun: at.gun, '@': msg['@']}); + at.on('in', {get: at.get, put: Gun.val.link.ify(get['#']), $: at.$, '@': msg['@']}); return; } - //if(/*!msg.gun &&*/ !get['.'] && get['#']){ at.ack = (at.ack + 1) || 1 } + //if(/*!msg.$ &&*/ !get['.'] && get['#']){ at.ack = (at.ack + 1) || 1 } //msg = obj_to(msg); - msg.gun = at.root.gun; + msg.$ = at.root.$; //Gun.on('put', at); - Gun.on.put(msg, at.root.gun); + Gun.on.put(msg, at.root.$); } var empty = {}, u; var obj = Gun.obj, obj_has = obj.has, obj_put = obj.put, obj_del = obj.del, obj_to = obj.to, obj_map = obj.map; @@ -1221,7 +1217,7 @@ if(!(gun = next[key])){ gun = cache(key, back); } - gun = gun.gun; + gun = gun.$; } else if(key instanceof Function){ gun = this; @@ -1258,7 +1254,7 @@ var cat = back._, next = cat.next, gun = back.chain(), at = gun._; if(!next){ next = cat.next = {} } next[at.get = key] = at; - if(back === cat.root.gun){ + if(back === cat.root.$){ at.soul = key; } else if(cat.soul || cat.has){ @@ -1270,7 +1266,8 @@ return at; } function use(msg){ - var ev = this, as = ev.as, gun = msg.gun, at = (gun||{})._ || {}, root = at.root, data = msg.put, tmp; + var ev = this, as = ev.as, gun = msg.$, at = (gun||{})._ || {}, root = at.root, data = msg.put, tmp; + //(root.stop && root.stop && (root.stop.ID = Gun.text.random(2))); console.log("???", msg, root && root.stop); if(root && (tmp = root.stop)){ if(tmp[at.id]){ return } tmp[at.id] = msg.root; } // temporary fix till a better solution? if(root && (tmp = root.now) && ev !== tmp[as.now]){ return ev.to.next(msg); @@ -1279,7 +1276,7 @@ data = at.put; } if((tmp = data) && tmp[rel._] && (tmp = rel.is(tmp)) && root){ - tmp = (root.gun.get(tmp)._); + tmp = (root.$.get(tmp)._); if(u !== tmp.put){ msg = obj_to(msg, {put: tmp.put}); } @@ -1299,10 +1296,10 @@ // #soul.has=value>state // ~who#where.where=what>when@was // TODO: BUG! Put probably cannot handle plural chains! - var gun = this, at = (gun._), root = at.root.gun, tmp; + var gun = this, at = (gun._), root = at.root.$, tmp; as = as || {}; as.data = data; - as.via = as.gun = as.via || as.gun || gun; + as.via = as.$ = as.via || as.$ || gun; if(typeof cb === 'string'){ as.soul = cb; } else { @@ -1321,25 +1318,25 @@ if(!as.soul){ // polyfill async uuid for SEA as.via.back('opt.uuid')(function(err, soul){ // TODO: improve perf without anonymous callback if(err){ return Gun.log(err) } // TODO: Handle error! - (as.ref||as.gun).put(as.data, as.soul = soul, as); + (as.ref||as.$).put(as.data, as.soul = soul, as); }); return gun; } - as.gun = gun = root.get(as.soul); - as.ref = as.gun; + as.$ = gun = root.get(as.soul); + as.ref = as.$; ify(as); return gun; } if(Gun.is(data)){ data.get('_').get(function(at, ev, tmp){ ev.off(); - if(!(tmp = at.gun) || !(tmp = tmp._.back) || !tmp.soul){ + if(!(tmp = at.$) || !(tmp = tmp._.back) || !tmp.soul){ return Gun.log("The reference you are saving is a", typeof at.put, '"'+ as.put +'", not a node (object)!'); } gun.put(Gun.val.rel.ify(tmp.soul), cb, as); }); return gun; } - as.ref = as.ref || (root._ === (tmp = at.back))? gun : tmp.gun; + as.ref = as.ref || (root._ === (tmp = at.back))? gun : tmp.$; if(as.ref._.soul && Gun.val.is(as.data) && at.get){ as.data = obj_put({}, at.get, as.data); as.ref.put(as.data, as.soul, as); @@ -1349,7 +1346,7 @@ if(!as.out){ // TODO: Perf idea! Make a global lock, that blocks everything while it is on, but if it is on the lock it does the expensive lookup to see if it is a dependent write or not and if not then it proceeds full speed. Meh? For write heavy async apps that would be terrible. as.res = as.res || stun; // Gun.on.stun(as.ref); // TODO: BUG! Deal with locking? - as.gun._.stun = as.ref._.stun; + as.$._.stun = as.ref._.stun; } return gun; }; @@ -1387,7 +1384,7 @@ if(!as.graph || obj_map(as.stun, no)){ return } as.res = as.res || function(cb){ if(cb){ cb() } }; as.res(function(){ - var cat = (as.gun.back(-1)._), ask = cat.ask(function(ack){ + var cat = (as.$.back(-1)._), ask = cat.ask(function(ack){ cat.root.on('ack', ack); this.off(); // One response is good enough for us currently. Later we may want to adjust this. if(!as.ack){ return } @@ -1400,7 +1397,7 @@ var tmp = cat.root.now; obj.del(cat.root, 'now'); cat.root.PUT = true; (as.ref._).now = true; (as.ref._).on('out', { - gun: as.ref, put: as.out = as.env.graph, opt: as.opt, '#': ask + $: as.ref, put: as.out = as.env.graph, opt: as.opt, '#': ask }); obj.del((as.ref._), 'now'); obj.del((cat.root), 'PUT'); @@ -1436,17 +1433,17 @@ return; } (as.stun = as.stun || {})[path] = true; - ref.get('_').get(soul, {as: {at: at, as: as}}); + ref.get('_').get(soul, {as: {at: at, as: as, p:path}}); }, {as: as, at: at}); } function soul(msg, ev){ var as = this.as, cat = as.at; as = as.as; //ev.stun(); // TODO: BUG!? - if(!msg.gun || !msg.gun._.back){ return } // TODO: Handle - var at = msg.gun._, at_ = at; + if(!msg.$ || !msg.$._.back){ return } // TODO: Handle + var at = msg.$._, at_ = at; var _id = (msg.put||empty)['#']; ev.off(); - at = (msg.gun._.back); // go up 1! + at = (msg.$._.back); // go up 1! var id = id || Gun.node.soul(cat.obj) || Gun.node.soul(at.put) || Gun.val.rel.is(at.put) || _id || at_._id || (as.via.back('opt.uuid') || Gun.text.random)(); // TODO: BUG!? Do we really want the soul of the object given to us? Could that be dangerous? if(!id){ // polyfill async uuid for SEA at.via.back('opt.uuid')(function(err, id){ // TODO: improve perf without anonymous callback @@ -1459,7 +1456,7 @@ } function solve(at, id, cat, as){ - at.gun.back(-1).get(id); + at.$.back(-1).get(id); cat.soul(id); as.stun[cat.path] = false; as.batch(); @@ -1467,16 +1464,16 @@ function any(at, ev){ var as = this.as; - if(!at.gun || !at.gun._){ return } // TODO: Handle + if(!at.$ || !at.$._){ return } // TODO: Handle if(at.err){ // TODO: Handle console.log("Please report this as an issue! Put.any.err"); return; } - var cat = (at.gun._.back), data = cat.put, opt = as.opt||{}, root, tmp; + var cat = (at.$._.back), data = cat.put, opt = as.opt||{}, root, tmp; if((tmp = as.ref) && tmp._.now){ return } ev.off(); - if(as.ref !== as.gun){ - tmp = (as.gun._).get || cat.get; + if(as.ref !== as.$){ + tmp = (as.$._).get || cat.get; if(!tmp){ // TODO: Handle console.log("Please report this as an issue! Put.no.get"); // TODO: BUG!?? return; @@ -1487,13 +1484,13 @@ if(u === data){ if(!cat.get){ return } // TODO: Handle if(!cat.soul){ - tmp = cat.gun.back(function(at){ + tmp = cat.$.back(function(at){ if(at.soul){ return at.soul } as.data = obj_put({}, at.get, as.data); }); } tmp = tmp || cat.get; - cat = (cat.root.gun.get(tmp)._); + cat = (cat.root.$.get(tmp)._); as.not = as.soul = tmp; data = as.data; } @@ -1501,7 +1498,7 @@ if(as.path && obj_is(as.data)){ // Apparently necessary as.soul = (opt.uuid || as.via.back('opt.uuid') || Gun.text.random)(); } else { - //as.data = obj_put({}, as.gun._.get, as.data); + //as.data = obj_put({}, as.$._.get, as.data); if(node_ == at.get){ as.soul = (at.put||empty)['#'] || at._id; } @@ -1538,7 +1535,7 @@ if(typeof tag === 'string'){ if(!arg){ return at.on(tag) } act = at.on(tag, arg, eas || at, as); - if(eas && eas.gun){ + if(eas && eas.$){ (eas.subs || (eas.subs = [])).push(act); } off = function() { @@ -1558,12 +1555,12 @@ } function ok(msg, ev){ var opt = this; - var gun = msg.gun, at = (gun||{})._ || {}, data = at.put || msg.put, tmp = opt.last, id = (at.id||'')+msg.get, tmp; + var gun = msg.$, at = (gun||{})._ || {}, data = at.put || msg.put, tmp = opt.last, id = (at.id||'')+msg.get, tmp; if(u === data){ return; } if(data && data[rel._] && (tmp = rel.is(data)) && at.root){ - tmp = (at.root.gun.get(tmp)._); + tmp = (at.root.$.get(tmp)._); if(u === tmp.put){ return; } @@ -1613,14 +1610,14 @@ } function val(msg, ev, to){ - var opt = this.as, cat = opt.cat, gun = msg.gun, coat = gun._, data = coat.put || msg.put, tmp; + var opt = this.as, cat = opt.cat, gun = msg.$, coat = gun._, data = coat.put || msg.put, tmp; if(u === data){ //return; } //if(coat.soul && !(0 < coat.ack)){ return } if(tmp = Gun.node.soul(data) || rel.is(data)){ //if(data && data[rel._] && (tmp = rel.is(data))){ - tmp = (cat.root.gun.get(tmp)._); + tmp = (cat.root.$.get(tmp)._); if(u === tmp.put){//} || !(0 < tmp.ack)){ return; } @@ -1640,7 +1637,7 @@ if((opt.seen = opt.seen || {})[coat.id]){ return } opt.seen[coat.id] = true; } - opt.ok.call(msg.gun || opt.gun, data, msg.get); + opt.ok.call(msg.$ || opt.$, data, msg.get); } Gun.chain.off = function(){ @@ -1667,13 +1664,13 @@ if(tmp = at.map){ obj_map(tmp, function(at){ if(at.link){ - cat.root.gun.get(at.link).off(); + cat.root.$.get(at.link).off(); } }); } if(tmp = at.next){ obj_map(tmp, function(neat){ - neat.gun.off(); + neat.$.off(); }); } at.on('off', {}); @@ -1716,7 +1713,7 @@ } function each(v,k){ if(n_ === k){ return } - var msg = this.msg, gun = msg.gun, at = this.at, tmp = (gun.get(k)._); + var msg = this.msg, gun = msg.$, at = this.at, tmp = (gun.get(k)._); (tmp.echo || (tmp.echo = {}))[at.id] = at; } var obj_map = Gun.obj.map, noop = function(){}, event = {stun: noop, off: noop}, n_ = Gun.node._, u; @@ -1732,18 +1729,19 @@ if(!Gun.is(item)){ var id = gun.back('opt.uuid')(); if(id && Gun.obj.is(item)){ - return gun.set(gun._.root.gun.put(item, id), cb, opt); + return gun.set(gun._.root.$.put(item, id), cb, opt); } return gun.get((Gun.state.lex() + Gun.text.random(7))).put(item, cb, opt); } item.get('_').get(function(at, ev){ - if(!at.gun || !at.gun._.back){ return } + if(!at.$ || !at.$._.back){ return } ev.off(); var soul = (at.put||{})['#']; - at = (at.gun._.back); + at = (at.$._.back); var put = {}, node = at.put; soul = at.soul || Gun.node.soul(node) || soul; if(!soul){ return cb.call(gun, {err: Gun.log('Only a node can be linked! Not "' + node + '"!')}) } + console.log("SET?", soul); gun.put(Gun.obj.put(put, soul, Gun.val.rel.ify(soul)), cb, opt); },{wait:0}); return item; @@ -1782,7 +1780,7 @@ }); }); setTimeout(function(){ - root.on('out', {put: send, '#': root.ask(ack), I: root.gun}); + root.on('out', {put: send, '#': root.ask(ack), I: root.$}); },10); }); } diff --git a/test/common.js b/test/common.js index d142abaf..003fb08a 100644 --- a/test/common.js +++ b/test/common.js @@ -1381,7 +1381,7 @@ describe('Gun', function(){ - Proxying event across maps. */ var s = Gun.state.map();s.soul = 'u/m'; - gun.on('put', {gun: gun, put: Gun.graph.ify({ + gun.on('put', {$: gun, put: Gun.graph.ify({ alice: { age: 26, name: "Alice", @@ -1417,7 +1417,7 @@ describe('Gun', function(){ it('uncached synchronous map get on', function(done){ var s = Gun.state.map();s.soul = 'u/m/p'; - gun.on('put', {gun: gun, put: Gun.graph.ify({ + gun.on('put', {$: gun, put: Gun.graph.ify({ alice: { age: 26, name: "alice", @@ -1449,7 +1449,7 @@ describe('Gun', function(){ it('uncached synchronous map get on node', function(done){ var s = Gun.state.map();s.soul = 'u/m/p/n'; - gun.on('put', {gun: gun, put: Gun.graph.ify({ + gun.on('put', {$: gun, put: Gun.graph.ify({ alice: { age: 26, name: "alice", @@ -1484,7 +1484,7 @@ describe('Gun', function(){ it('uncached synchronous map get on node get', function(done){ var gun = Gun(); var s = Gun.state.map();s.soul = 'u/m/p/n/p'; - gun.on('put', {gun: gun, put: Gun.graph.ify({ + gun.on('put', {$: gun, put: Gun.graph.ify({ alice: { age: 26, name: "alice", @@ -1523,7 +1523,7 @@ describe('Gun', function(){ it('uncached synchronous map on mutate', function(done){ var s = Gun.state.map();s.soul = 'u/m/mutate'; - gun.on('put', {gun: gun, put: Gun.graph.ify({ + gun.on('put', {$: gun, put: Gun.graph.ify({ alice: { age: 26, name: "Alice", @@ -1558,7 +1558,7 @@ describe('Gun', function(){ it('uncached synchronous map on mutate node', function(done){ var s = Gun.state.map();s.soul = 'u/m/mutate/n'; - gun.on('put', {gun: gun, put: Gun.graph.ify({ + gun.on('put', {$: gun, put: Gun.graph.ify({ alice: {_:{'#':'umaliceo'}, age: 26, name: "Alice", @@ -1605,7 +1605,7 @@ describe('Gun', function(){ it('uncached synchronous map on mutate node uncached', function(done){ var s = Gun.state.map();s.soul = 'u/m/mutate/n/u'; - gun.on('put', {gun: gun, put: Gun.graph.ify({ + gun.on('put', {$: gun, put: Gun.graph.ify({ alice: {_:{'#':'umaliceo1'}, age: 26, name: "Alice", @@ -1637,7 +1637,7 @@ describe('Gun', function(){ }); setTimeout(function(){ var s = Gun.state.map();s.soul = 'u/m/m/n/u/soul'; - gun.on('put', {gun: gun, put: Gun.graph.ify({ + gun.on('put', {$: gun, put: Gun.graph.ify({ name: 'Alice Zzxyz' }, s)}); //console.debug.i=1;console.log("---------------"); @@ -1662,7 +1662,7 @@ describe('Gun', function(){ it('uncached synchronous map on get mutate node uncached', function(done){ var s = Gun.state.map();s.soul = 'u/m/p/mutate/n/u'; - gun.on('put', {gun: gun, put: Gun.graph.ify({ + gun.on('put', {$: gun, put: Gun.graph.ify({ alice: {_:{'#':'umaliceo2'}, age: 26, name: "Alice", @@ -1695,7 +1695,7 @@ describe('Gun', function(){ }); setTimeout(function(){ var s = Gun.state.map();s.soul = 'u/m/p/m/n/u/soul'; - gun.on('put', {gun: gun, put: Gun.graph.ify({ + gun.on('put', {$: gun, put: Gun.graph.ify({ name: 'Alice Zzxyz', age: 34 }, s)}); gun.get('u/m/p/mutate/n/u').put({ @@ -1712,7 +1712,7 @@ describe('Gun', function(){ it('uncached synchronous map on get node mutate node uncached', function(done){ var s = Gun.state.map();s.soul = 'u/m/p/n/mutate/n/u'; - gun.on('put', {gun: gun, put: Gun.graph.ify({ + gun.on('put', {$: gun, put: Gun.graph.ify({ alice: {_:{'#':'umaliceo3'}, age: 26, name: "Alice", @@ -1743,7 +1743,7 @@ describe('Gun', function(){ }); setTimeout(function(){ var s = Gun.state.map();s.soul = 'alice/fuzz/soul'; - gun.on('put', {gun: gun, put: Gun.graph.ify({ + gun.on('put', {$: gun, put: Gun.graph.ify({ name: 'Alice Zzxyz', age: 34, pet: {c:3, name: "Fuzzball"} }, s)}); @@ -2828,7 +2828,7 @@ describe('Gun', function(){ var user = {bob: bob}; bob.pet = cat; cat.slave = bob; - gun.on('put', {gun: gun, put: Gun.graph.ify(user, s)}); + gun.on('put', {$: gun, put: Gun.graph.ify(user, s)}); gun.get(s.soul).get('bob').get('pet').get('slave').val(function(data){ //clearTimeout(done.to); //setTimeout(function(){ @@ -3066,7 +3066,7 @@ describe('Gun', function(){ it('get get get any parallel', function(done){ var s = Gun.state.map();s.soul = 'parallel'; - gun.on('put', {gun: gun, put: Gun.graph.ify({ + gun.on('put', {$: gun, put: Gun.graph.ify({ bob: { age: 29, name: "Bob!" @@ -3074,14 +3074,14 @@ describe('Gun', function(){ }, s)}); gun.get('parallel').get('bob').get('age').get(function(at, ev){ var err = at.err, data = at.put, field = at.get; - //console.log("***** age", data, at.gun._.ack);//return; + //console.log("***** age", data, at.$._.ack);//return; expect(data).to.be(29); expect(field).to.be('age'); done.age = true; }); gun.get('parallel').get('bob').get('name').get(function(at, ev){ var err = at.err, data = at.put, field = at.get; - //console.log("*********** name", data, at.gun._.ack);//return; + //console.log("*********** name", data, at.$._.ack);//return; expect(data).to.be('Bob!'); expect(field).to.be('name'); done.name = true; @@ -3093,7 +3093,7 @@ describe('Gun', function(){ it('get get get any later', function(done){ var s = Gun.state.map();s.soul = 'parallel/later'; - gun.on('put', {gun: gun, put: Gun.graph.ify({ + gun.on('put', {$: gun, put: Gun.graph.ify({ bob: {_:{'#':'ddfsa'}, age: 29, name: "Bob!" @@ -3165,18 +3165,18 @@ describe('Gun', function(){ it('get any any', function(done){ var s = Gun.state.map();s.soul = 'full'; - gun.on('put', {gun: gun, put: Gun.graph.ify({ + gun.on('put', {$: gun, put: Gun.graph.ify({ hello: 'world', goodbye: 'mars' }, s)}); gun.get('full').get(function(at, ev){ - var err = at.err, data = at.gun._.put || at.put, field = at.get; + var err = at.err, data = at.$._.put || at.put, field = at.get; //console.log("*****1", data); expect(data.hello).to.be('world'); expect(data.goodbye).to.be('mars'); }); gun.get('full').get(function(at, ev){ - var err = at.err, data = at.gun._.put || at.put, field = at.get; + var err = at.err, data = at.$._.put || at.put, field = at.get; //console.log("*****1", data); expect(data.hello).to.be('world'); expect(data.goodbye).to.be('mars'); @@ -3187,19 +3187,19 @@ describe('Gun', function(){ it('get any any later', function(done){ var s = Gun.state.map();s.soul = 'full/later'; - gun.on('put', {gun: gun, put: Gun.graph.ify({ + gun.on('put', {$: gun, put: Gun.graph.ify({ hello: 'world', goodbye: 'mars' }, s)}); gun.get('full/later').get(function(at, ev){ - var err = at.err, data = at.gun._.put || at.put, field = at.get; + var err = at.err, data = at.$._.put || at.put, field = at.get; //console.log("*****", data); expect(data.hello).to.be('world'); expect(data.goodbye).to.be('mars'); }); setTimeout(function(){ gun.get('full/later').get(function(at, ev){ - var err = at.err, data = at.gun._.put || at.put, field = at.get; + var err = at.err, data = at.$._.put || at.put, field = at.get; //console.log("*****2", field, data); expect(data.hello).to.be('world'); expect(data.goodbye).to.be('mars'); @@ -3279,7 +3279,7 @@ describe('Gun', function(){ var gun = Gun(); var s = Gun.state.map();s.soul = 'mult/times/part'; - gun.on('put', {gun: gun, put: Gun.graph.ify({ + gun.on('put', {$: gun, put: Gun.graph.ify({ alias: { mark: { pub: {_:{'#':'PUB'}, @@ -3412,12 +3412,12 @@ describe('Gun', function(){ ctx.on('out', function(msg){ this.to.next(msg); var onGun = ctx; - if(onGun.gun === b) { + if(onGun.$ === b) { if(d){ //console.log("b can send to d....", Gun.obj.copy(msg)); d.on("in", msg); } - } else if(onGun.gun === d){ + } else if(onGun.$ === d){ //console.log("d sends to b....", Gun.obj.copy(msg)); b.on("in", msg); } @@ -3486,7 +3486,7 @@ describe('Gun', function(){ it('If chain cannot be called, ack', function(done){ var gun = Gun(), u; - gun.on('put', {gun: gun, put: Gun.graph.ify({ + gun.on('put', {$: gun, put: Gun.graph.ify({ wat: 1, a: true }, 'nl/app')}); @@ -3510,7 +3510,7 @@ describe('Gun', function(){ it('Chain on known nested object should ack', function(done){ var gun = Gun(), u; - gun.on('put', {gun: gun, put: Gun.graph.ify({ + gun.on('put', {$: gun, put: Gun.graph.ify({ bar: { wat: 1 } @@ -3564,7 +3564,7 @@ describe('Gun', function(){ this.timeout(1000 * 9); var gun = Gun(); - gun.get('users').put({ + gun.get('users/mm').put({ alice: {_:{'#':'alias/alice'}, 'pub/asdf': {_:{'#':'pub/asdf'}, pub: 'asdf' @@ -3579,8 +3579,9 @@ describe('Gun', function(){ var check = {}, c = 0, end; //console.log(check); - gun.get('users').map().map() + gun.get('users/mm').map().map() .get('who').get('said').map().on(function(msg){ + console.log("------>", msg.num); if(check[msg.num]){ //console.log("!!!!", msg.num, "!!!!"); } @@ -3597,7 +3598,7 @@ describe('Gun', function(){ function run(i){ - //console.log("----", i, "----"); + console.log("----", i, "----"); //2 === i && (console.debug.i = 1) && console.debug(1, '======= what happens?'); said.set({ what: i + " Hello world!", @@ -3725,18 +3726,18 @@ describe('Gun', function(){ if(!obj.tags){ console.warn('Not tagged to anything!'); context._.valid = false; - chain._.on('in', {get: key, gun: this}); + chain._.on('in', {get: key, $: this}); return false; } else { _tags = Gun.obj.ify(obj.tags); if(Array.isArray(filter)){ context._.valid = filter.every(function(f){ return ( _tags[f] && _tags[f]==1) }); if(context._.valid){ - chain._.on('in', {get: key, put: obj, gun: this}); + chain._.on('in', {get: key, put: obj, $: this}); return context; } else { console.log("that was wrong"); - chain._.on('in', {get: key, put: undefined, gun: this}); + chain._.on('in', {get: key, put: undefined, $: this}); } return false; } else { @@ -3825,7 +3826,7 @@ describe('Gun', function(){ it('get get any parallel', function(done){ var s = Gun.state.map();s.soul = 'parallel/get/get'; - Gun.on('put', {gun: gun, put: Gun.graph.ify({ + Gun.on('put', {$: gun, put: Gun.graph.ify({ bob: { age: 29, name: "Bob!" @@ -3846,7 +3847,7 @@ describe('Gun', function(){ it('get get any parallel later', function(done){ var s = Gun.state.map();s.soul = 'parallel/get/get/later'; - Gun.on('put', {gun: gun, put: Gun.graph.ify({ + Gun.on('put', {$: gun, put: Gun.graph.ify({ bob: { age: 29, name: "Bob!" @@ -3869,7 +3870,7 @@ describe('Gun', function(){ it('get get any none', function(done){ var s = Gun.state.map();s.soul = 'get/get/none'; - Gun.on('put', {gun: gun, put: Gun.graph.ify({ + Gun.on('put', {$: gun, put: Gun.graph.ify({ alice: { age: 31, name: "alice" @@ -3897,7 +3898,7 @@ describe('Gun', function(){ it('get get any none later', function(done){ var s = Gun.state.map();s.soul = 'get/get/none/later'; - Gun.on('put', {gun: gun, put: Gun.graph.ify({ + Gun.on('put', {$: gun, put: Gun.graph.ify({ alice: { age: 31, name: "alice" @@ -3923,7 +3924,7 @@ describe('Gun', function(){ it('get get primitive get any', function(done){ var s = Gun.state.map();s.soul = 'get/get/prim'; - Gun.on('put', {gun: gun, put: Gun.graph.ify({ + Gun.on('put', {$: gun, put: Gun.graph.ify({ bob: "is awesome" }, s)}); gun.get('get/get/prim').path('bob').path('age').any(function(err, data, field, at, ev){ @@ -3939,7 +3940,7 @@ describe('Gun', function(){ it('get put any', function(done){ var s = Gun.state.map();s.soul = 'get/put/any'; - Gun.on('put', {gun: gun, put: Gun.graph.ify({ + Gun.on('put', {$: gun, put: Gun.graph.ify({ here: "we go" }, s)}); //console.debug.i=1;console.log("---------------"); @@ -3953,7 +3954,7 @@ describe('Gun', function(){ return; it('get any, get put any', function(done){ var s = Gun.state.map();s.soul = 'get/any/get/put/any'; - Gun.on('put', {gun: gun, put: Gun.graph.ify({ + Gun.on('put', {$: gun, put: Gun.graph.ify({ here: "we go" }, s)}); gun.get('get/any/get/put/any') @@ -3982,7 +3983,7 @@ describe('Gun', function(){ it('mutate pointer to primitive deep on', function(done){ var s = Gun.state.map();s.soul = 'change/pointer'; - Gun.on('put', {gun: gun, put: Gun.graph.ify({ + Gun.on('put', {$: gun, put: Gun.graph.ify({ bob: { age: 29, name: "Bob!", @@ -4031,7 +4032,7 @@ describe('Gun', function(){ it('get only soul', function(done){ var s = Gun.state.map();s.soul = 'only/soul'; - Gun.on('put', {gun: gun, put: Gun.graph.ify({ + Gun.on('put', {$: gun, put: Gun.graph.ify({ bob: { age: 29, name: "Bob!", @@ -4049,7 +4050,7 @@ describe('Gun', function(){ it('get path only soul', function(done){ var s = Gun.state.map();s.soul = 'only/p/soul'; - Gun.on('put', {gun: gun, put: Gun.graph.ify({ + Gun.on('put', {$: gun, put: Gun.graph.ify({ bob: { age: 29, name: "Bob!", @@ -4069,7 +4070,7 @@ describe('Gun', function(){ it('mutate pointer to self', function(done){ var s = Gun.state.map();s.soul = 'change/pointer/point'; - Gun.on('put', {gun: gun, put: Gun.graph.ify({ + Gun.on('put', {$: gun, put: Gun.graph.ify({ bob: { age: 29, name: "Bob!", @@ -4100,7 +4101,7 @@ describe('Gun', function(){ }); it('mutate pointer to self deep', function(done){ var s = Gun.state.map();s.soul = 'change/pointer/point/deep'; - Gun.on('put', {gun: gun, put: Gun.graph.ify({ + Gun.on('put', {$: gun, put: Gun.graph.ify({ bob: { age: 29, name: "Bob!", @@ -4131,7 +4132,7 @@ describe('Gun', function(){ it('mutate pointer to primitive after any', function(done){ var s = Gun.state.map();s.soul = 'change/pointer/to/prime'; - Gun.on('put', {gun: gun, put: Gun.graph.ify({ + Gun.on('put', {$: gun, put: Gun.graph.ify({ bob: {_: {'#': 'asdffdsa'}, age: 29, name: "Bob!", @@ -4166,7 +4167,7 @@ describe('Gun', function(){ it('mutate pointer to primitive after any deep', function(done){ var s = Gun.state.map();s.soul = 'change/pointer/to/prime/deep'; - Gun.on('put', {gun: gun, put: Gun.graph.ify({ + Gun.on('put', {$: gun, put: Gun.graph.ify({ bob: { age: 29, name: "Bob!", @@ -4200,7 +4201,7 @@ describe('Gun', function(){ return; it.only('mutate pointer to another pointer after any', function(done){ var s = Gun.state.map();s.soul = 'change/pointer/to/pointer'; - Gun.on('put', {gun: gun, put: Gun.graph.ify({ + Gun.on('put', {$: gun, put: Gun.graph.ify({ bob: {_: {'#': 'dafssfad'}, age: 29, name: "Bob!", @@ -4802,7 +4803,7 @@ describe('Gun', function(){ it('any any not', function(done){ var s = Gun.state.map(); s.soul = 'a'; - Gun.on('put', {gun: gun, put: Gun.graph.ify({b: 1, c: 2}, s)}); + Gun.on('put', {$: gun, put: Gun.graph.ify({b: 1, c: 2}, s)}); function cb(e,d,f,a){ if('b' === f && 1 === d){ done.b = true; @@ -6233,13 +6234,13 @@ describe('Gun', function(){ gun1.val(function(val){ expect(val.hello).to.be('world!'); expect(val.hi).to.be('mars!'); - done.gun1 = true; + done.g1 = true; }); //return; gun2.val(function(val){ expect(val.hello).to.be('world!'); expect(val.hi).to.be('mars!'); - expect(done.gun1).to.be.ok(); + expect(done.g1).to.be.ok(); Gun({}); done(); }); @@ -7149,7 +7150,7 @@ describe('Gun', function(){ gun._.at('soul').event( //( function($){ - var chain = $.gun || gun; + var chain = $.$ || gun; var ctx = {}, obj = val, $ = Gun.obj.copy($); var hash = $.field? $.soul + $.field : ($.from? $.from + ($.at || '') : $.soul); if(call[hash]){ return } @@ -7555,12 +7556,12 @@ describe('Gun', function(){ },5); } }} - peers.gun = Gun(gopt); + peers.g = Gun(gopt); function reload(){ - peers.localStorage = Gun.obj.copy(peers.gun.__.graph); - peers.gun2 = Gun(gopt); + peers.localStorage = Gun.obj.copy(peers.g.__.graph); + peers.g2 = Gun(gopt); } - var ref = peers.gun.get('example/json/data/test'); + var ref = peers.g.get('example/json/data/test'); setTimeout(function(){ ref.path('hello').put("value"); setTimeout(function(){ @@ -7568,7 +7569,7 @@ describe('Gun', function(){ reload(); setTimeout(function(){ Gun.log.debug = 1; console.log("~~~~~~~~~~~~~~~~~~~"); - var ref = peers.gun2.get('example/json/data/test'); + var ref = peers.g2.get('example/json/data/test'); ref.on(function(data){ console.log("on!", data); }); @@ -7641,7 +7642,7 @@ describe('Gun', function(){ it("gun set", function(done){ var gun = Gun(); - var users = gun.get('users'); + var users = gun.get('users/s'); var alice = gun.put({name: 'alice', birth: Math.random()}).key('person/alice'); var bob = gun.put({name: 'bob', birth: Math.random()}).key('person/bob'); var carl = gun.put({name: 'carl', birth: Math.random()}).key('person/carl'); @@ -7729,9 +7730,9 @@ describe('Gun', function(){ it.skip("chaining val", function(done){ // Not implemented yet! var gun = Gun(); - gun.get('users').set(gun.put({name: 'alice'})); - gun.get('users').set(gun.put({name: 'bob'}));; - gun.get('users').val().map(function(person){ + gun.get('users/cv').set(gun.put({name: 'alice'})); + gun.get('users/cv').set(gun.put({name: 'bob'}));; + gun.get('users/cv').val().map(function(person){ if(person.name === 'alice'){ done.alice = true; } @@ -7742,7 +7743,7 @@ describe('Gun', function(){ done.carl = true; } }); - gun.get('users').set(gun.put({name: 'carl'})); + gun.get('users/cv').set(gun.put({name: 'carl'})); setTimeout(function(){ console.log('wha?', done.alice, done.bob, done.carl); expect(done.alice).to.be.ok(); diff --git a/test/mocha.html b/test/mocha.html index 0ee65c5f..284c8123 100644 --- a/test/mocha.html +++ b/test/mocha.html @@ -21,6 +21,7 @@ - - - -
- This is example of simple Vue plugin. It works exatcly same as the Vue instance data property, but the name is gunData.
- The cool part is that every property in the gunData is realtime synced via gunDB to every other page viewer!
- - - - - - -
- Vue instance data: -
{{ $data }}
-
- test
- arr[1]
- obj.a
- deepObj.level1.prop
- deepObj.level1.arr[1]
-
-
-
-
-
-
-
-
- -
-
- + + + +
+ This is example of simple Vue plugin. It works exatcly same as the Vue instance data property, but the name is gunData.
+ The cool part is that every property in the gunData is realtime synced via gunDB to every other page viewer!
+ + + + + + +
+ Vue instance data: +

+        
+ test
+ arr[1]
+ obj.a
+ deepObj.level1.prop
+ deepObj.level1.arr[1]
+
+
+
+
+
+
+
+
+ +
+
+ - - + + + From c5d42a677d019f18db7162d575b370451a29cb1d Mon Sep 17 00:00:00 2001 From: hillct Date: Sun, 8 Jul 2018 19:21:04 -0400 Subject: [PATCH 066/221] Docker build adjustments --- Dockerfile | 2 +- package-lock.json | 255 ++++++++++++++++++++++++---------------------- 2 files changed, 136 insertions(+), 121 deletions(-) diff --git a/Dockerfile b/Dockerfile index be214ded..c11fc7a3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:edge +FROM alpine:latest # Build-time metadata as defined at http://label-schema.org ARG BUILD_DATE ARG VCS_REF diff --git a/package-lock.json b/package-lock.json index 2ad1e7e2..cefd2123 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "gun", - "version": "0.9.999", + "version": "0.9.9993", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -10,9 +10,9 @@ "integrity": "sha512-ywlelg2ePNpX4IlN+A3qXySzKBAZmI2ZxMdDL3amJLCTYhYhemYcv6Aa+PTETojUfB+k4z4X4970q/jjSzyLvw==", "dev": true, "requires": { - "asn1.js": "^4.9.1", - "base64url": "^2.0.0", - "elliptic": "^6.4.0" + "asn1.js": "4.10.1", + "base64url": "2.0.0", + "elliptic": "6.4.0" } }, "@trust/webcrypto": { @@ -21,10 +21,10 @@ "integrity": "sha512-aix+LOG/3Ku3MzClfVxVH88QbSdIL1HcBQ+gjXL/VnX05uyORf28CaQZOvsoEcCzGnWIVBUNwE2gxLBapWANWw==", "dev": true, "requires": { - "@trust/keyto": "^0.3.1", - "base64url": "^2.0.0", - "node-rsa": "^0.4.0", - "text-encoding": "^0.6.1" + "@trust/keyto": "0.3.2", + "base64url": "2.0.0", + "node-rsa": "0.4.2", + "text-encoding": "0.6.4" } }, "accepts": { @@ -33,7 +33,7 @@ "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", "dev": true, "requires": { - "mime-types": "~2.1.18", + "mime-types": "2.1.18", "negotiator": "0.6.1" } }, @@ -67,9 +67,9 @@ "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", "dev": true, "requires": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" + "bn.js": "4.11.8", + "inherits": "2.0.3", + "minimalistic-assert": "1.0.1" } }, "async-limiter": { @@ -81,6 +81,7 @@ "version": "2.238.1", "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.238.1.tgz", "integrity": "sha1-o1/ewSLtkV2kkIQOiCgzbaW+Tn8=", + "dev": true, "requires": { "buffer": "4.9.1", "events": "1.1.1", @@ -115,7 +116,8 @@ "base64-js": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", - "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==" + "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==", + "dev": true }, "base64id": { "version": "1.0.0", @@ -163,15 +165,15 @@ "dev": true, "requires": { "bytes": "3.0.0", - "content-type": "~1.0.4", + "content-type": "1.0.4", "debug": "2.6.9", - "depd": "~1.1.1", - "http-errors": "~1.6.2", + "depd": "1.1.2", + "http-errors": "1.6.3", "iconv-lite": "0.4.19", - "on-finished": "~2.3.0", + "on-finished": "2.3.0", "qs": "6.5.1", "raw-body": "2.3.2", - "type-is": "~1.6.15" + "type-is": "1.6.16" } }, "brace-expansion": { @@ -180,7 +182,7 @@ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "requires": { - "balanced-match": "^1.0.0", + "balanced-match": "1.0.0", "concat-map": "0.0.1" } }, @@ -200,10 +202,11 @@ "version": "4.9.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", + "dev": true, "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" + "base64-js": "1.3.0", + "ieee754": "1.1.8", + "isarray": "1.0.0" } }, "bytes": { @@ -311,13 +314,13 @@ "integrity": "sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8=", "dev": true, "requires": { - "bn.js": "^4.4.0", - "brorand": "^1.0.1", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.0" + "bn.js": "4.11.8", + "brorand": "1.1.0", + "hash.js": "1.1.3", + "hmac-drbg": "1.0.1", + "inherits": "2.0.3", + "minimalistic-assert": "1.0.1", + "minimalistic-crypto-utils": "1.0.1" } }, "encodeurl": { @@ -337,7 +340,7 @@ "cookie": "0.3.1", "debug": "2.3.3", "engine.io-parser": "1.3.2", - "ws": "~1.1.5" + "ws": "1.1.5" }, "dependencies": { "accepts": { @@ -346,7 +349,7 @@ "integrity": "sha1-w8p0NJOGSMPg2cHjKN1otiLChMo=", "dev": true, "requires": { - "mime-types": "~2.1.11", + "mime-types": "2.1.18", "negotiator": "0.6.1" } }, @@ -377,8 +380,8 @@ "integrity": "sha512-o3KqipXNUdS7wpQzBHSe180lBGO60SoK0yVo3CYJgb2MkobuWuBX6dhkYP5ORCLd55y+SaflMOV5fqAB53ux4w==", "dev": true, "requires": { - "options": ">=0.0.5", - "ultron": "1.0.x" + "options": "0.0.6", + "ultron": "1.0.2" } } } @@ -398,7 +401,7 @@ "parsejson": "0.0.3", "parseqs": "0.0.5", "parseuri": "0.0.5", - "ws": "~1.1.5", + "ws": "1.1.5", "xmlhttprequest-ssl": "1.5.3", "yeast": "0.1.2" }, @@ -430,8 +433,8 @@ "integrity": "sha512-o3KqipXNUdS7wpQzBHSe180lBGO60SoK0yVo3CYJgb2MkobuWuBX6dhkYP5ORCLd55y+SaflMOV5fqAB53ux4w==", "dev": true, "requires": { - "options": ">=0.0.5", - "ultron": "1.0.x" + "options": "0.0.6", + "ultron": "1.0.2" } } } @@ -471,7 +474,8 @@ "events": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", - "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=" + "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=", + "dev": true }, "express": { "version": "4.16.3", @@ -479,36 +483,36 @@ "integrity": "sha1-avilAjUNsyRuzEvs9rWjTSL37VM=", "dev": true, "requires": { - "accepts": "~1.3.5", + "accepts": "1.3.5", "array-flatten": "1.1.1", "body-parser": "1.18.2", "content-disposition": "0.5.2", - "content-type": "~1.0.4", + "content-type": "1.0.4", "cookie": "0.3.1", "cookie-signature": "1.0.6", "debug": "2.6.9", - "depd": "~1.1.2", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", + "depd": "1.1.2", + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "etag": "1.8.1", "finalhandler": "1.1.1", "fresh": "0.5.2", "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "~2.3.0", - "parseurl": "~1.3.2", + "methods": "1.1.2", + "on-finished": "2.3.0", + "parseurl": "1.3.2", "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.3", + "proxy-addr": "2.0.3", "qs": "6.5.1", - "range-parser": "~1.2.0", + "range-parser": "1.2.0", "safe-buffer": "5.1.1", "send": "0.16.2", "serve-static": "1.13.2", "setprototypeof": "1.1.0", - "statuses": "~1.4.0", - "type-is": "~1.6.16", + "statuses": "1.4.0", + "type-is": "1.6.16", "utils-merge": "1.0.1", - "vary": "~1.1.2" + "vary": "1.1.2" }, "dependencies": { "safe-buffer": { @@ -526,12 +530,12 @@ "dev": true, "requires": { "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.2", - "statuses": "~1.4.0", - "unpipe": "~1.0.0" + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "on-finished": "2.3.0", + "parseurl": "1.3.2", + "statuses": "1.4.0", + "unpipe": "1.0.0" } }, "forwarded": { @@ -558,12 +562,12 @@ "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" } }, "growl": { @@ -607,8 +611,8 @@ "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", "dev": true, "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.0" + "inherits": "2.0.3", + "minimalistic-assert": "1.0.1" } }, "he": { @@ -623,9 +627,9 @@ "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", "dev": true, "requires": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" + "hash.js": "1.1.3", + "minimalistic-assert": "1.0.1", + "minimalistic-crypto-utils": "1.0.1" } }, "http-errors": { @@ -634,10 +638,10 @@ "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", "dev": true, "requires": { - "depd": "~1.1.2", + "depd": "1.1.2", "inherits": "2.0.3", "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" + "statuses": "1.4.0" } }, "iconv-lite": { @@ -649,7 +653,8 @@ "ieee754": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz", - "integrity": "sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q=" + "integrity": "sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q=", + "dev": true }, "indexof": { "version": "0.0.1", @@ -663,8 +668,8 @@ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { - "once": "^1.3.0", - "wrappy": "1" + "once": "1.4.0", + "wrappy": "1.0.2" } }, "inherits": { @@ -694,12 +699,14 @@ "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true }, "jmespath": { "version": "0.15.0", "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", - "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=" + "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=", + "dev": true }, "json3": { "version": "3.3.2", @@ -710,7 +717,8 @@ "lodash": { "version": "4.17.10", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", - "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==" + "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==", + "dev": true }, "media-typer": { "version": "0.3.0", @@ -748,7 +756,7 @@ "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", "dev": true, "requires": { - "mime-db": "~1.33.0" + "mime-db": "1.33.0" } }, "minimalistic-assert": { @@ -769,7 +777,7 @@ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { - "brace-expansion": "^1.1.7" + "brace-expansion": "1.1.11" } }, "minimist": { @@ -865,7 +873,7 @@ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { - "wrappy": "1" + "wrappy": "1.0.2" } }, "options": { @@ -880,10 +888,10 @@ "integrity": "sha1-4+yr3DQn6vELowviJZAaehGasXM=", "dev": true, "requires": { - "bluebird": "^3.4.6", - "is-promise": "^2.1.0", + "bluebird": "3.5.1", + "is-promise": "2.1.0", "platform": "1.3.1", - "socket.io-client": "^1.4.5" + "socket.io-client": "1.7.4" } }, "panic-manager": { @@ -892,10 +900,10 @@ "integrity": "sha1-0tvHdgIAMsWwEw0QW/vqewZnMh4=", "dev": true, "requires": { - "isarray": "^2.0.0", - "panic-client": "^1.0.0", - "socket.io": "^1.4.8", - "socket.io-client": "^1.4.8" + "isarray": "2.0.4", + "panic-client": "1.0.2", + "socket.io": "1.7.4", + "socket.io-client": "1.7.4" }, "dependencies": { "isarray": { @@ -912,9 +920,9 @@ "integrity": "sha512-TcR6M4LaqKjHvAKoAi46w2Y11KPJiMchAEqu00+tlOBxHR8AYvUCBvDLw4+j3MymApVHHWtluOzDaWxEYeGuVw==", "dev": true, "requires": { - "bluebird": "^3.3.5", - "panic-client": "^1.0.0", - "socket.io": "^1.4.5" + "bluebird": "3.5.1", + "panic-client": "1.0.2", + "socket.io": "1.7.4" } }, "parsejson": { @@ -923,7 +931,7 @@ "integrity": "sha1-q343WfIJ7OmUN5c/fQ8fZK4OZKs=", "dev": true, "requires": { - "better-assert": "~1.0.0" + "better-assert": "1.0.2" } }, "parseqs": { @@ -932,7 +940,7 @@ "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", "dev": true, "requires": { - "better-assert": "~1.0.0" + "better-assert": "1.0.2" } }, "parseuri": { @@ -941,7 +949,7 @@ "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", "dev": true, "requires": { - "better-assert": "~1.0.0" + "better-assert": "1.0.2" } }, "parseurl": { @@ -974,14 +982,15 @@ "integrity": "sha512-jQTChiCJteusULxjBp8+jftSQE5Obdl3k4cnmLA6WXtK6XFuWRnvVL7aCiBqaLPM8c4ph0S4tKna8XvmIwEnXQ==", "dev": true, "requires": { - "forwarded": "~0.1.2", + "forwarded": "0.1.2", "ipaddr.js": "1.6.0" } }, "punycode": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + "dev": true }, "qs": { "version": "6.5.1", @@ -992,7 +1001,8 @@ "querystring": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "dev": true }, "range-parser": { "version": "1.2.0", @@ -1027,7 +1037,7 @@ "depd": "1.1.1", "inherits": "2.0.3", "setprototypeof": "1.0.3", - "statuses": ">= 1.3.1 < 2" + "statuses": "1.4.0" } }, "setprototypeof": { @@ -1041,7 +1051,8 @@ "sax": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", - "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=" + "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=", + "dev": true }, "send": { "version": "0.16.2", @@ -1050,18 +1061,18 @@ "dev": true, "requires": { "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", + "depd": "1.1.2", + "destroy": "1.0.4", + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "etag": "1.8.1", "fresh": "0.5.2", - "http-errors": "~1.6.2", + "http-errors": "1.6.3", "mime": "1.4.1", "ms": "2.0.0", - "on-finished": "~2.3.0", - "range-parser": "~1.2.0", - "statuses": "~1.4.0" + "on-finished": "2.3.0", + "range-parser": "1.2.0", + "statuses": "1.4.0" } }, "serve-static": { @@ -1070,9 +1081,9 @@ "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", "dev": true, "requires": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.2", + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "parseurl": "1.3.2", "send": "0.16.2" } }, @@ -1089,7 +1100,7 @@ "dev": true, "requires": { "debug": "2.3.3", - "engine.io": "~1.8.4", + "engine.io": "1.8.5", "has-binary": "0.1.7", "object-assign": "4.1.0", "socket.io-adapter": "0.5.0", @@ -1151,7 +1162,7 @@ "component-bind": "1.0.0", "component-emitter": "1.2.1", "debug": "2.3.3", - "engine.io-client": "~1.8.4", + "engine.io-client": "1.8.5", "has-binary": "0.1.7", "indexof": "0.0.1", "object-component": "0.0.3", @@ -1236,7 +1247,7 @@ "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", "dev": true, "requires": { - "has-flag": "^2.0.0" + "has-flag": "2.0.0" } }, "text-encoding": { @@ -1258,7 +1269,7 @@ "dev": true, "requires": { "media-typer": "0.3.0", - "mime-types": "~2.1.18" + "mime-types": "2.1.18" } }, "uglify-js": { @@ -1267,8 +1278,8 @@ "integrity": "sha512-hS7+TDiqIqvWScCcKRybCQzmMnEzJ4ryl9ErRmW4GFyG48p0/dKZiy/5mVLbsFzU8CCnCgQdxMiJzZythvLzCg==", "dev": true, "requires": { - "commander": "~2.15.0", - "source-map": "~0.6.1" + "commander": "2.15.1", + "source-map": "0.6.1" }, "dependencies": { "commander": { @@ -1289,6 +1300,7 @@ "version": "0.10.3", "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", "integrity": "sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=", + "dev": true, "requires": { "punycode": "1.3.2", "querystring": "0.2.0" @@ -1303,7 +1315,8 @@ "uuid": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", - "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==" + "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==", + "dev": true }, "vary": { "version": "1.1.2", @@ -1322,7 +1335,7 @@ "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.0.tgz", "integrity": "sha512-c18dMeW+PEQdDFzkhDsnBAlS4Z8KGStBQQUcQ5mf7Nf689jyGk0594L+i9RaQuf4gog6SvWLJorz2NfSaqxZ7w==", "requires": { - "async-limiter": "~1.0.0" + "async-limiter": "1.0.0" } }, "wtf-8": { @@ -1335,17 +1348,19 @@ "version": "0.4.17", "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.17.tgz", "integrity": "sha1-F76T6q4/O3eTWceVtBlwWogX6Gg=", + "dev": true, "requires": { - "sax": ">=0.6.0", - "xmlbuilder": "^4.1.0" + "sax": "1.2.1", + "xmlbuilder": "4.2.1" } }, "xmlbuilder": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-4.2.1.tgz", "integrity": "sha1-qlijBBoGb5DqoWwvU4n/GfP0YaU=", + "dev": true, "requires": { - "lodash": "^4.0.0" + "lodash": "4.17.10" } }, "xmlhttprequest-ssl": { From 9474753a8ef64a105766566678b9839157ea23b5 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Mon, 9 Jul 2018 18:21:15 -0700 Subject: [PATCH 067/221] make Radisk available in browser for @fuchidahiro --- examples/style.css | 8 +- lib/load.js | 4 +- lib/open.js | 2 +- lib/radisk.js | 644 ++++++++++++++++++++++--------------------- lib/radix.js | 20 +- lib/rfs.js | 61 ++++ lib/store.js | 99 +------ lib/time.js | 2 +- lib/upload.js | 6 +- test/panic/radisk.js | 22 +- test/radisk.html | 34 +++ 11 files changed, 473 insertions(+), 429 deletions(-) create mode 100644 lib/rfs.js create mode 100644 test/radisk.html diff --git a/examples/style.css b/examples/style.css index 8ce1791e..6f7896aa 100644 --- a/examples/style.css +++ b/examples/style.css @@ -44,6 +44,11 @@ ul, li { } .model, .none { display: none } +.hide { + opacity: 0; + visibility: hidden; + transition: all 2s; +} .page { width: 100%; @@ -81,8 +86,7 @@ ul, li { padding: 3%; } .gully { - margin-top: 2em; - margin-bottom: 2em; + margin-bottom: 1%; } .sit { margin-bottom: 0; } diff --git a/lib/load.js b/lib/load.js index f34f9ca5..b84b2d0c 100644 --- a/lib/load.js +++ b/lib/load.js @@ -1,9 +1,9 @@ if(typeof window !== "undefined"){ var Gun = window.Gun; } else { - var Gun = require('gun/gun'); + var Gun = require('../gun'); } -Gun.chain.open || require('gun/lib/open'); +Gun.chain.open || require('./open'); Gun.chain.load = function(cb, opt, at){ (opt = opt || {}).off = !0; diff --git a/lib/open.js b/lib/open.js index 7191bff5..2b4e5642 100644 --- a/lib/open.js +++ b/lib/open.js @@ -1,7 +1,7 @@ if(typeof window !== "undefined"){ var Gun = window.Gun; } else { - var Gun = require('gun/gun'); + var Gun = require('../gun'); } Gun.chain.open = function(cb, opt, at){ diff --git a/lib/radisk.js b/lib/radisk.js index d2509975..8a5ff699 100644 --- a/lib/radisk.js +++ b/lib/radisk.js @@ -1,342 +1,350 @@ -var fs = require('fs'); -var Gun = require('../gun'); -var Radix = require('./radix'); +;(function(){ -function Radisk(opt){ + function Radisk(opt){ - opt = opt || {}; - opt.file = String(opt.file || 'radata'); - opt.until = opt.until || opt.wait || 1000; // default for HDDs - opt.batch = opt.batch || 10 * 1000; - opt.chunk = opt.chunk || (1024 * 1024 * 10); // 10MB - opt.code = opt.code || {}; - opt.code.from = opt.code.from || '!'; + opt = opt || {}; + opt.file = String(opt.file || 'radata'); + opt.until = opt.until || opt.wait || 1000; // default for HDDs + opt.batch = opt.batch || 10 * 1000; + opt.chunk = opt.chunk || (1024 * 1024 * 10); // 10MB + opt.code = opt.code || {}; + opt.code.from = opt.code.from || '!'; - function ename(t){ return encodeURIComponent(t).replace(/\*/g, '%2A') } + function ename(t){ return encodeURIComponent(t).replace(/\*/g, '%2A') } - if(!opt.store){ - return Gun.log("ERROR: Radisk needs `opt.store` interface with `{get: fn, put: fn, list: fn}`!"); - } - if(!opt.store.put){ - return Gun.log("ERROR: Radisk needs `store.put` interface with `(file, data, cb)`!"); - } - if(!opt.store.get){ - return Gun.log("ERROR: Radisk needs `store.get` interface with `(file, cb)`!"); - } - if(!opt.store.list){ - return Gun.log("ERROR: Radisk needs a streaming `store.list` interface with `(cb)`!"); - } + if(!opt.store){ + return Gun.log("ERROR: Radisk needs `opt.store` interface with `{get: fn, put: fn, list: fn}`!"); + } + if(!opt.store.put){ + return Gun.log("ERROR: Radisk needs `store.put` interface with `(file, data, cb)`!"); + } + if(!opt.store.get){ + return Gun.log("ERROR: Radisk needs `store.get` interface with `(file, cb)`!"); + } + if(!opt.store.list){ + return Gun.log("ERROR: Radisk needs a streaming `store.list` interface with `(cb)`!"); + } - /* - Any and all storage adapters should... - 1. Because writing to disk takes time, we should batch data to disk. This improves performance, and reduces potential disk corruption. - 2. If a batch exceeds a certain number of writes, we should immediately write to disk when physically possible. This caps total performance, but reduces potential loss. - */ - var r = function(key, val, cb){ - key = ''+key; - if(val instanceof Function){ - cb = val; - val = r.batch(key); - if(u !== val){ - return cb(u, val); + /* + Any and all storage adapters should... + 1. Because writing to disk takes time, we should batch data to disk. This improves performance, and reduces potential disk corruption. + 2. If a batch exceeds a certain number of writes, we should immediately write to disk when physically possible. This caps total performance, but reduces potential loss. + */ + var r = function(key, val, cb){ + key = ''+key; + if(val instanceof Function){ + cb = val; + val = r.batch(key); + if(u !== val){ + return cb(u, val); + } + if(r.thrash.at){ + val = r.thrash.at(key); + if(u !== val){ + return cb(u, val); + } + } + //console.log("READ FROM DISK"); + return r.read(key, cb); } - if(r.thrash.at){ - val = r.thrash.at(key); + r.batch(key, val); + if(cb){ r.batch.acks.push(cb) } + if(++r.batch.ed >= opt.batch){ return r.thrash() } // (2) + clearTimeout(r.batch.to); // (1) + r.batch.to = setTimeout(r.thrash, opt.until || 1); + } + + r.batch = Radix(); + r.batch.acks = []; + r.batch.ed = 0; + + r.thrash = function(){ + var thrash = r.thrash; + if(thrash.ing){ return thrash.more = true } + thrash.more = false; + thrash.ing = true; + var batch = thrash.at = r.batch, i = 0; + clearTimeout(r.batch.to); + r.batch = null; + r.batch = Radix(); + r.batch.acks = []; + r.batch.ed = 0; + r.save(batch, function(err, ok){ + if(++i > 1){ return } + if(err){ Gun.log(err) } + Gun.obj.map(batch.acks, function(cb){ cb(err, ok) }); + thrash.at = null; + thrash.ing = false; + if(thrash.more){ thrash() } + }); + } + + /* + 1. Find the first radix item in memory. + 2. Use that as the starting index in the directory of files. + 3. Find the first file that is lexically larger than it, + 4. Read the previous file to that into memory + 5. Scan through the in memory radix for all values lexically less than the limit. + 6. Merge and write all of those to the in-memory file and back to disk. + 7. If file to large, split. More details needed here. + */ + r.save = function(rad, cb){ + var s = function Span(){}; + s.find = function(tree, key){ + if(key < s.start){ return } + s.start = key; + opt.store.list(s.lex); + return true; + } + s.lex = function(file){ + file = (u === file)? u : decodeURIComponent(file); + if(!file || file > s.start){ + s.mix(s.file || opt.code.from, s.start, s.end = file); + return true; + } + s.file = file; + } + s.mix = function(file, start, end){ + s.start = s.end = s.file = u; + r.parse(file, function(err, disk){ + if(err){ return cb(err) } + Radix.map(rad, function(val, key){ + if(key < start){ return } + if(end && end < key){ return s.start = key } + // PLUGIN: consider adding HAM as an extra layer of protection + disk(key, val); // merge batch[key] -> disk[key] + }); + r.write(file, disk, s.next); + }); + } + s.next = function(err, ok){ + if(s.err = err){ return cb(err) } + if(s.start){ return Radix.map(rad, s.find) } + cb(err, ok); + } + Radix.map(rad, s.find); + } + + /* + Any storage engine at some point will have to do a read in order to write. + This is true of even systems that use an append only log, if they support updates. + Therefore it is unavoidable that a read will have to happen, + the question is just how long you delay it. + */ + r.write = function(file, rad, cb){ + var f = function Fractal(){}; + f.text = ''; + f.count = 0; + f.file = file; + f.each = function(val, key, k, pre){ + f.count++; + var enc = Radisk.encode(pre.length) +'#'+ Radisk.encode(k) + (u === val? '' : '='+ Radisk.encode(val)) +'\n'; + if(opt.chunk < f.text.length + enc.length){ + f.text = ''; + f.limit = Math.ceil(f.count/2); + f.count = 0; + f.sub = Radix(); + Radix.map(rad, f.slice); + return true; + } + f.text += enc; + } + f.write = function(){ opt.store.put(ename(file), f.text, cb) } + f.slice = function(val, key){ + if(key < f.file){ return } + if(f.limit < (++f.count)){ + var name = f.file; + f.file = key; + f.count = 0; + r.write(name, f.sub, f.next); + return true; + } + f.sub(key, val); + } + f.next = function(err){ + if(err){ return cb(err) } + f.sub = Radix(); + if(!Radix.map(rad, f.slice)){ + r.write(f.file, f.sub, cb); + } + } + if(!Radix.map(rad, f.each, true)){ f.write() } + } + + r.read = function(key, cb){ + // TODO: BUG!!! If a node spans multiple file chunks, it won't return all! + // TODO: BUG!!! If a node spans multiple file chunks, it won't return all! + // TODO: BUG!!! If a node spans multiple file chunks, it won't return all! + // TODO: BUG!!! If a node spans multiple file chunks, it won't return all! + // TODO: BUG!!! If a node spans multiple file chunks, it won't return all! + // TODO: BUG!!! If a node spans multiple file chunks, it won't return all! + // TODO: BUG!!! If a node spans multiple file chunks, it won't return all! + if(RAD){ // cache + var val = RAD(key); if(u !== val){ return cb(u, val); } } - //console.log("READ FROM DISK"); - return r.read(key, cb); - } - r.batch(key, val); - if(cb){ r.batch.acks.push(cb) } - if(++r.batch.ed >= opt.batch){ return r.thrash() } // (2) - clearTimeout(r.batch.to); // (1) - r.batch.to = setTimeout(r.thrash, opt.until || 1); - } - - r.batch = Radix(); - r.batch.acks = []; - r.batch.ed = 0; - - r.thrash = function(){ - var thrash = r.thrash; - if(thrash.ing){ return thrash.more = true } - thrash.more = false; - thrash.ing = true; - var batch = thrash.at = r.batch, i = 0; - clearTimeout(r.batch.to); - r.batch = null; - r.batch = Radix(); - r.batch.acks = []; - r.batch.ed = 0; - r.save(batch, function(err, ok){ - if(++i > 1){ return } - if(err){ Gun.log(err) } - Gun.obj.map(batch.acks, function(cb){ cb(err, ok) }); - thrash.at = null; - thrash.ing = false; - if(thrash.more){ thrash() } - }); - } - - /* - 1. Find the first radix item in memory. - 2. Use that as the starting index in the directory of files. - 3. Find the first file that is lexically larger than it, - 4. Read the previous file to that into memory - 5. Scan through the in memory radix for all values lexically less than the limit. - 6. Merge and write all of those to the in-memory file and back to disk. - 7. If file to large, split. More details needed here. - */ - r.save = function(rad, cb){ - var s = function Span(){}; - s.find = function(tree, key){ - if(key < s.start){ return } - s.start = key; - opt.store.list(s.lex); - return true; - } - s.lex = function(file){ - file = (u === file)? u : decodeURIComponent(file); - if(!file || file > s.start){ - s.mix(s.file || opt.code.from, s.start, s.end = file); - return true; - } - s.file = file; - } - s.mix = function(file, start, end){ - s.start = s.end = s.file = u; - r.parse(file, function(err, disk){ - if(err){ return cb(err) } - Radix.map(rad, function(val, key){ - if(key < start){ return } - if(end && end < key){ return s.start = key } - // PLUGIN: consider adding HAM as an extra layer of protection - disk(key, val); // merge batch[key] -> disk[key] - }); - r.write(file, disk, s.next); - }); - } - s.next = function(err, ok){ - if(s.err = err){ return cb(err) } - if(s.start){ return Radix.map(rad, s.find) } - cb(err, ok); - } - Radix.map(rad, s.find); - } - - /* - Any storage engine at some point will have to do a read in order to write. - This is true of even systems that use an append only log, if they support updates. - Therefore it is unavoidable that a read will have to happen, - the question is just how long you delay it. - */ - r.write = function(file, rad, cb){ - var f = function Fractal(){}; - f.text = ''; - f.count = 0; - f.file = file; - f.each = function(val, key, k, pre){ - f.count++; - var enc = Radisk.encode(pre.length) +'#'+ Radisk.encode(k) + (u === val? '' : '='+ Radisk.encode(val)) +'\n'; - if(opt.chunk < f.text.length + enc.length){ - f.text = ''; - f.limit = Math.ceil(f.count/2); - f.count = 0; - f.sub = Radix(); - Radix.map(rad, f.slice); - return true; - } - f.text += enc; - } - f.write = function(){ opt.store.put(ename(file), f.text, cb) } - f.slice = function(val, key){ - if(key < f.file){ return } - if(f.limit < (++f.count)){ - var name = f.file; - f.file = key; - f.count = 0; - r.write(name, f.sub, f.next); - return true; - } - f.sub(key, val); - } - f.next = function(err){ - if(err){ return cb(err) } - f.sub = Radix(); - if(!Radix.map(rad, f.slice)){ - r.write(f.file, f.sub, cb); - } - } - if(!Radix.map(rad, f.each, true)){ f.write() } - } - - r.read = function(key, cb){ - // TODO: BUG!!! If a node spans multiple file chunks, it won't return all! - // TODO: BUG!!! If a node spans multiple file chunks, it won't return all! - // TODO: BUG!!! If a node spans multiple file chunks, it won't return all! - // TODO: BUG!!! If a node spans multiple file chunks, it won't return all! - // TODO: BUG!!! If a node spans multiple file chunks, it won't return all! - // TODO: BUG!!! If a node spans multiple file chunks, it won't return all! - // TODO: BUG!!! If a node spans multiple file chunks, it won't return all! - if(RAD){ // cache - var val = RAD(key); - if(u !== val){ - return cb(u, val); - } - } - var g = function Get(){}, tmp; - g.lex = function(file){ - file = (u === file)? u : decodeURIComponent(file); - if(!file || file > key){ - if(tmp = q[g.file]){ - tmp.push({key: key, ack: cb}); + var g = function Get(){}, tmp; + g.lex = function(file){ + file = (u === file)? u : decodeURIComponent(file); + if(!file || file > key){ + if(tmp = q[g.file]){ + tmp.push({key: key, ack: cb}); + return true; + } + q[g.file] = [{key: key, ack: cb}]; + r.parse(g.file, g.it); return true; } - q[g.file] = [{key: key, ack: cb}]; - r.parse(g.file, g.it); - return true; + g.file = file; } - g.file = file; + g.it = function(err, disk){ + if(g.err = err){ Gun.log(err) } + if(disk){ RAD = disk } + disk = q[g.file]; Gun.obj.del(q, g.file); + Gun.obj.map(disk, g.ack); + } + g.ack = function(as){ + if(!as.ack){ return } + as.ack(g.err, (RAD || noop)(as.key)); + } + opt.store.list(g.lex); } - g.it = function(err, disk){ - if(g.err = err){ Gun.log(err) } - if(disk){ RAD = disk } - disk = q[g.file]; Gun.obj.del(q, g.file); - Gun.obj.map(disk, g.ack); + /* + Let us start by assuming we are the only process that is + changing the directory or bucket. Not because we do not want + to be multi-process/machine, but because we want to experiment + with how much performance and scale we can get out of only one. + Then we can work on the harder problem of being multi-process. + */ + r.parse = function(file, cb){ + var p = function Parse(){}, s = String.fromCharCode(31); + p.disk = Radix(); + p.read = function(err, data){ var tmp; + if(err){ return cb(err) } + if(!data){ return cb(u, p.disk) } + var tmp = p.split(data), pre = [], i, k, v; + while(tmp){ + k = v = u; + i = tmp[1]; + tmp = p.split(tmp[2])||''; + if('#' == tmp[0]){ + k = tmp[1]; + pre = pre.slice(0,i); + if(i <= pre.length){ + pre.push(k); + } + } + tmp = p.split(tmp[2])||''; + if('\n' == tmp[0]){ continue } + if('=' == tmp[0]){ v = tmp[1] } + if(u !== k && u !== v){ p.disk(pre.join(''), v) } + tmp = p.split(tmp[2]); + } + cb(u, p.disk); + }; + p.split = function(t){ + if(!t){ return } + var l = [], o = {}, i = -1, a = '', b, c; + while(c = t[++i]){ + if(s === c){ break } + a += c; + } + if(!c){ return } + l[0] = a; + l[1] = b = Radisk.decode(t.slice(i), o); + l[2] = t.slice(i + o.i); + return l; + } + opt.store.get(ename(file), p.read); } - g.ack = function(as){ - if(!as.ack){ return } - as.ack(g.err, (RAD || noop)(as.key)); - } - opt.store.list(g.lex); + + var q = {}, noop = function(){}, RAD, u; + return r; } - /* - Let us start by assuming we are the only process that is - changing the directory or bucket. Not because we do not want - to be multi-process/machine, but because we want to experiment - with how much performance and scale we can get out of only one. - Then we can work on the harder problem of being multi-process. - */ - r.parse = function(file, cb){ - var p = function Parse(){}, s = String.fromCharCode(31); - p.disk = Radix(); - p.read = function(err, data){ var tmp; - if(err){ return cb(err) } - if(!data){ return cb(u, p.disk) } - var tmp = p.split(data), pre = [], i, k, v; - while(tmp){ - k = v = u; - i = tmp[1]; - tmp = p.split(tmp[2])||''; - if('#' == tmp[0]){ - k = tmp[1]; - pre = pre.slice(0,i); - if(i <= pre.length){ - pre.push(k); + + + ;(function(){ + s = String.fromCharCode(31); + Radisk.encode = function(d, o){ + var t = s, tmp; + if(typeof d == 'string'){ + var i = -1, c; + while(c = d[++i]){ + if(s === c){ + t += s; } } - tmp = p.split(tmp[2])||''; - if('\n' == tmp[0]){ continue } - if('=' == tmp[0]){ v = tmp[1] } - if(u !== k && u !== v){ p.disk(pre.join(''), v) } - tmp = p.split(tmp[2]); - } - cb(u, p.disk); - }; - p.split = function(t){ - if(!t){ return } - var l = [], o = {}, i = -1, a = '', b, c; - while(c = t[++i]){ - if(s === c){ break } - a += c; - } - if(!c){ return } - l[0] = a; - l[1] = b = Radisk.decode(t.slice(i), o); - l[2] = t.slice(i + o.i); - return l; - } - opt.store.get(ename(file), p.read); - } - - var q = {}, noop = function(){}, RAD, u; - return r; -} - - -;(function(){ - s = String.fromCharCode(31); - Radisk.encode = function(d, o){ - var t = s, tmp; - if(typeof d == 'string'){ - var i = -1, c; - while(c = d[++i]){ - if(s === c){ - t += s; - } - } - return t + '"' + d + s; - } else - if(d && d['#'] && (tmp = Gun.val.link.is(d))){ - return t + '#' + tmp + t; - } else - if(Gun.num.is(d)){ - return t + '+' + (d||0) + t; - } else - if(null === d){ - return t + ' ' + t; - } else - if(true === d){ - return t + '+' + t; - } else - if(false === d){ - return t + '-' + t; - }// else - //if(binary){} - } - Radisk.decode = function(t, o){ - var d = '', i = -1, n = 0, c, p; - if(s !== t[0]){ return } - while(c = t[++i]){ - if(p){ - if(s === c){ - if(--n <= 0){ - break; - } - } - d += c; + return t + '"' + d + s; } else - if(s === c){ - ++n; - } else { - p = c || true; + if(d && d['#'] && (tmp = Gun.val.link.is(d))){ + return t + '#' + tmp + t; + } else + if(Gun.num.is(d)){ + return t + '+' + (d||0) + t; + } else + if(null === d){ + return t + ' ' + t; + } else + if(true === d){ + return t + '+' + t; + } else + if(false === d){ + return t + '-' + t; + }// else + //if(binary){} + } + Radisk.decode = function(t, o){ + var d = '', i = -1, n = 0, c, p; + if(s !== t[0]){ return } + while(c = t[++i]){ + if(p){ + if(s === c){ + if(--n <= 0){ + break; + } + } + d += c; + } else + if(s === c){ + ++n; + } else { + p = c || true; + } + } + if(o){ o.i = i+1 } + if('"' === p){ + return d; + } else + if('#' === p){ + return Gun.val.link.ify(d); + } else + if('+' === p){ + if(0 === d.length){ + return true; + } + return parseFloat(d); + } else + if(' ' === p){ + return null; + } else + if('-' === p){ + return false; } } - if(o){ o.i = i+1 } - if('"' === p){ - return d; - } else - if('#' === p){ - return Gun.val.link.ify(d); - } else - if('+' === p){ - if(0 === d.length){ - return true; - } - return parseFloat(d); - } else - if(' ' === p){ - return null; - } else - if('-' === p){ - return false; - } + }()); + + if(typeof window !== "undefined"){ + var Gun = window.Gun; + var Radix = window.Radix; + window.Radisk = Radisk; + } else { + var Gun = require('../gun'); + var Radix = require('./radix'); + try{ module.exports = Radisk }catch(e){} } -}()); -Radisk.Radix = Radix; + Radisk.Radix = Radix; -module.exports = Radisk; \ No newline at end of file +}()); \ No newline at end of file diff --git a/lib/radix.js b/lib/radix.js index 1fef14cb..ae8731db 100644 --- a/lib/radix.js +++ b/lib/radix.js @@ -1,8 +1,4 @@ -var Gun = require('../gun'); ;(function(){ - var map = Gun.obj.map, no = {}, u; - - var $ = String.fromCharCode(30), _ = String.fromCharCode(29); function Radix(){ var radix = function(key, val, t){ @@ -46,6 +42,7 @@ var Gun = require('../gun'); } return radix; }; + Radix.map = function map(radix, cb, opt, pre){ pre = pre || []; var t = radix[_] || radix, keys = Object.keys(t).sort(), i = 0, l = keys.length; for(;i < l; i++){ var key = keys[i], tree = t[key], tmp; @@ -64,7 +61,18 @@ var Gun = require('../gun'); } } }; + Object.keys = Object.keys || function(o){ return map(o, function(v,k,t){t(k)}) } + + if(typeof window !== "undefined"){ + var Gun = window.Gun; + window.Radix = Radix; + } else { + var Gun = require('../gun'); + try{ module.exports = Radix }catch(e){} + } - module.exports = Radix; -}()); + var map = Gun.obj.map, no = {}, u; + var $ = String.fromCharCode(30), _ = String.fromCharCode(29); + +}()); \ No newline at end of file diff --git a/lib/rfs.js b/lib/rfs.js new file mode 100644 index 00000000..b92293a0 --- /dev/null +++ b/lib/rfs.js @@ -0,0 +1,61 @@ +function Store(opt){ + opt = opt || {}; + opt.file = String(opt.file || 'radata'); + + var Gun = require('../gun'), fs = require('fs'), u; + var store = function Store(){}; + store.put = function(file, data, cb){ + var random = Math.random().toString(36).slice(-3) + fs.writeFile(opt.file+'-'+random+'.tmp', data, function(err, ok){ + if(err){ return cb(err) } + move(opt.file+'-'+random+'.tmp', opt.file+'/'+file, cb); + }); + }; + store.get = function(file, cb){ + fs.readFile(opt.file+'/'+file, function(err, data){ + if(err){ + if('ENOENT' === (err.code||'').toUpperCase()){ + return cb(null); + } + Gun.log("ERROR:", err) + } + if(data){ data = data.toString() } + cb(err, data); + }); + }; + store.list = function(cb, match){ + fs.readdir(opt.file, function(err, dir){ + Gun.obj.map(dir, cb) || cb(); // Stream interface requires a final call to know when to be done. + }); + }; + if(!fs.existsSync(opt.file)){ fs.mkdirSync(opt.file) } + //store.list(function(){ return true }); + + function move(oldPath, newPath, cb) { + fs.rename(oldPath, newPath, function (err) { + if (err) { + if (err.code === 'EXDEV') { + var readStream = fs.createReadStream(oldPath); + var writeStream = fs.createWriteStream(newPath); + + readStream.on('error', cb); + writeStream.on('error', cb); + + readStream.on('close', function () { + fs.unlink(oldPath, cb); + }); + + readStream.pipe(writeStream); + } else { + cb(err); + } + } else { + cb(); + } + }); + }; + + return store; +} + +module.exports = Store; \ No newline at end of file diff --git a/lib/store.js b/lib/store.js index bdf031e2..5445ca14 100644 --- a/lib/store.js +++ b/lib/store.js @@ -1,17 +1,21 @@ -var Gun = require('../gun'); -var Radisk = require('./radisk'); -var fs = require('fs'); -var Radix = Radisk.Radix; -var u; +if(typeof window === "undefined"){ + var Gun = require('../gun'); +} Gun.on('opt', function(ctx){ this.to.next(ctx); - var opt = ctx.opt; + var opt = ctx.opt, u; + if(typeof window !== "undefined"){ + opt.window = window; + } if(ctx.once){ return } - if(false !== opt.localStorage && !process.env.AWS_S3_BUCKET){ return } // TODO: Remove this after migration. + if(false !== opt.localStorage && !(!opt.window && process.env.AWS_S3_BUCKET)){ return } // TODO: Remove this after migration. if(false === opt.radisk){ return } console.log("BUG WARNING: Radix Storage Engine (RAD) has a known rare edge case, if data gets split between file chunks, a GET may only return the first chunk!!!"); - opt.store = opt.store || Store(opt); + var Radisk = (opt.window && opt.window.Radisk) || require('./radisk'); + var Radix = Radisk.Radix; + + opt.store = opt.store || (!opt.window && require('./rfs')(opt)); var rad = Radisk(opt); ctx.on('put', function(at){ @@ -52,81 +56,4 @@ Gun.on('opt', function(ctx){ } }); -}); - -function Store(opt){ - opt = opt || {}; - opt.file = String(opt.file || 'radata'); - - var store = function Store(){}; - store.put = function(file, data, cb){ - var random = Math.random().toString(36).slice(-3) - fs.writeFile(opt.file+'-'+random+'.tmp', data, function(err, ok){ - if(err){ return cb(err) } - move(opt.file+'-'+random+'.tmp', opt.file+'/'+file, cb); - }); - }; - store.get = function(file, cb){ - fs.readFile(opt.file+'/'+file, function(err, data){ - if(err){ - if('ENOENT' === (err.code||'').toUpperCase()){ - return cb(null); - } - Gun.log("ERROR:", err) - } - if(data){ data = data.toString() } - cb(err, data); - }); - }; - store.list = function(cb, match){ - fs.readdir(opt.file, function(err, dir){ - Gun.obj.map(dir, cb) || cb(); // Stream interface requires a final call to know when to be done. - }); - }; - if(!fs.existsSync(opt.file)){ fs.mkdirSync(opt.file) } - //store.list(function(){ return true }); - return store; -} - -function move(oldPath, newPath, cb) { - fs.rename(oldPath, newPath, function (err) { - if (err) { - if (err.code === 'EXDEV') { - var readStream = fs.createReadStream(oldPath); - var writeStream = fs.createWriteStream(newPath); - - readStream.on('error', cb); - writeStream.on('error', cb); - - readStream.on('close', function () { - fs.unlink(oldPath, cb); - }); - - readStream.pipe(writeStream); - } else { - cb(err); - } - } else { - cb(); - } - }); -}; - -module.exports = Store; - - -;(function(){ - return; - process.env.AWS_S3_BUCKET = 'test-s3'; - process.env.AWS_ACCESS_KEY_ID = 'asdf'; - process.env.AWS_SECRET_ACCESS_KEY = 'fdsa'; - process.env.fakes3 = 'http://localhost:4567'; - process.env.AWS_S3_THROTTLE = 0; - - return; - global.Gun = require('../gun'); - //require('./rs3'); - - - require('../test/abc'); -}()); \ No newline at end of file +}); \ No newline at end of file diff --git a/lib/time.js b/lib/time.js index 58983601..75b431f7 100644 --- a/lib/time.js +++ b/lib/time.js @@ -1,5 +1,5 @@ if(typeof window === "undefined"){ //Not in the browser, Include from node - var Gun = require('gun/gun'); + var Gun = require('../gun'); } ;(function(){ diff --git a/lib/upload.js b/lib/upload.js index 87985fd2..6cdadd21 100644 --- a/lib/upload.js +++ b/lib/upload.js @@ -27,7 +27,11 @@ var file = (((e.event || e).target || e).result || e), img = new Image(); img.src = file; img.onload = function(){ - if(!h && img.width > w){ h = img.height * (w / img.width) } + if(img.width < w && img.height < (h||Infinity)){ + e.base64 = file; + return cb(e || file); + } + if(!h){ h = img.height * (w / img.width) } var canvas = document.createElement('canvas'), ctx = canvas.getContext('2d'); canvas.width = w; canvas.height = h; diff --git a/test/panic/radisk.js b/test/panic/radisk.js index c0e7fd1f..c48149e4 100644 --- a/test/panic/radisk.js +++ b/test/panic/radisk.js @@ -3,10 +3,12 @@ var config = { port: 8080, servers: 2, browsers: 2, - each: 2000, + each: 100, burst: 50, wait: 1, dir: __dirname, + chunk: 1024 * 10, + notrad: false, route: { '/': __dirname + '/index.html', '/gun.js': __dirname + '/../../gun.js', @@ -50,25 +52,19 @@ describe("Make sure the Radix Storage Engine (RSE) works.", function(){ it("GUN started!", function(){ return server.run(function(test){ var env = test.props; - console.log("????", process.argv); test.async(); if(require('fs').existsSync('radata')){ console.log("Please delete previous data first!"); explode; return; } - /*setInterval(function(){ - var mem = process.memoryUsage(); - var u = Math.round(mem.heapUsed / 1024 / 1024 * 100) / 100; - console.log(u, 'MB of', Math.round(mem.heapTotal / 1024 / 1024 * 100) / 100); - }, 1000);*/ var port = env.config.port + env.i; var server = require('http').createServer(function(req, res){ res.end("I am "+ env.i +"!"); }); var Gun = require('gun'); //require('gun/lib/store'); - var gun = Gun({web: server, localStorage: false, until: 1, memory: 50, chunk: 1024 * 100}); + var gun = Gun({web: server, localStorage: env.config.notrad, until: 1, memory: 50, chunk: env.config.chunk, file: 'radata'}); server.listen(port, function(){ test.done(); }); @@ -86,7 +82,7 @@ describe("Make sure the Radix Storage Engine (RSE) works.", function(){ console.log("I AM ALICE"); localStorage.clear(); var env = test.props; - var gun = Gun({peers: 'http://'+ env.config.IP + ':' + (env.config.port + 1) + '/gun', localStorage: false}); + var gun = Gun({peers: 'http://'+ env.config.IP + ':' + (env.config.port + 1) + '/gun', localStorage: env.config.notrad}); window.gun = gun; var n = Gun.time.is(), i = 0, c = 0, b = env.config.burst, l = env.config.each; @@ -154,7 +150,7 @@ describe("Make sure the Radix Storage Engine (RSE) works.", function(){ }); var Gun = require('gun'); //require('gun/lib/store'); - var gun = Gun({web: server, localStorage: false, until: 1, memory: 50, chunk: 1024 * 100}); + var gun = Gun({web: server, localStorage: env.config.notrad, until: 1, memory: 50, chunk: env.config.notrad, file: 'radata'}); server.listen(port, function(){ test.done(); }); @@ -167,11 +163,12 @@ describe("Make sure the Radix Storage Engine (RSE) works.", function(){ console.log("I AM BOB"); localStorage.clear(); var env = test.props; - var gun = Gun({peers: 'http://'+ env.config.IP + ':' + (env.config.port + 2) + '/gun', localStorage: false}); + var gun = Gun({peers: 'http://'+ env.config.IP + ':' + (env.config.port + 2) + '/gun', localStorage: env.config.notrad}); window.gun = gun; var n = Gun.time.is(), i = 0, c = 0, b = env.config.burst, l = env.config.each; var raw = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + window.FOO = []; function check(i){ if(i > l){ @@ -183,7 +180,8 @@ describe("Make sure the Radix Storage Engine (RSE) works.", function(){ if((raw+i) !== data.hello){ return test.fail('wrong ' + i) } if(d){ return } d = true; //!(c % b) && - console.log(c+'/'+l);//, '@'+Math.floor(b/((-n + (n = Gun.time.is()))/1000))+'/sec')); + window.FOO.push(i); + console.log(c+'/'+l, 'yeah?', i, Gun.node.soul(data));//, '@'+Math.floor(b/((-n + (n = Gun.time.is()))/1000))+'/sec')); window.GOT = c++; //localStorage.clear(); ref.off(); diff --git a/test/radisk.html b/test/radisk.html new file mode 100644 index 00000000..0083af92 --- /dev/null +++ b/test/radisk.html @@ -0,0 +1,34 @@ +

Radisk

+ + + + + + + + \ No newline at end of file From 314d5af7ef51c4e01e82cc40e758813282b3d06a Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Tue, 10 Jul 2018 09:40:51 -0700 Subject: [PATCH 068/221] update path for @mitra42 --- lib/path.js | 21 ++++++++------------- package.json | 2 +- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/lib/path.js b/lib/path.js index d034cdbf..780d0f46 100644 --- a/lib/path.js +++ b/lib/path.js @@ -1,18 +1,15 @@ if(typeof window !== "undefined"){ var Gun = window.Gun; } else { - var Gun = require('gun/gun'); + var Gun = require('../gun'); } -Gun.chain.path = function(field, cb, opt){ +Gun.chain.path = function(field, opt){ var back = this, gun = back, tmp; - opt = opt || {}; opt.path = true; - if(gun === gun.back(-1)){if(cb){cb({err: Gun.log("Can't do that on root instance.")})}return gun} if(typeof field === 'string'){ - tmp = field.split(opt.split || '.'); + tmp = field.split(opt || '.'); if(1 === tmp.length){ - gun = back.get(field, cb, opt); - gun._.opt = opt; + gun = back.get(field); return gun; } field = tmp; @@ -22,19 +19,17 @@ Gun.chain.path = function(field, cb, opt){ gun = back; var i = 0, l = field.length; for(i; i < l; i++){ - gun = gun.get(field[i], (i+1 === l)? cb : null, opt); + //gun = gun.get(field[i], (i+1 === l)? cb : null, opt); + gun = gun.get(field[i]); } - //gun.back = back; // TODO: API change! } else { - gun = back.get(field[0], cb, opt); + gun = back.get(field[0]); } - gun._.opt = opt; return gun; } if(!field && 0 != field){ return back; } - gun = back.get(''+field, cb, opt); - gun._.opt = opt; + gun = back.get(''+field); return gun; } \ No newline at end of file diff --git a/package.json b/package.json index 4e1f9f53..7bb359a0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gun", - "version": "0.9.9993", + "version": "0.9.9994", "description": "A realtime, decentralized, offline-first, graph data synchronization engine.", "main": "index.js", "browser": "gun.min.js", From 86c4017aca86dbc465ad89096d98fbb58db0edba Mon Sep 17 00:00:00 2001 From: Jonathan Dunlap Date: Fri, 13 Jul 2018 12:29:10 -0700 Subject: [PATCH 069/221] new sea test --- package.json | 2 +- test/sea/sea2.js | 60 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 test/sea/sea2.js diff --git a/package.json b/package.json index 7bb359a0..2da08e66 100644 --- a/package.json +++ b/package.json @@ -53,9 +53,9 @@ "devDependencies": { "@trust/webcrypto": "^0.7.1", "aws-sdk": ">=2.153.0", + "concat-map": "^0.0.1", "express": ">=4.15.2", "ip": "^1.1.5", - "concat-map": "^0.0.1", "mocha": ">=3.2.0", "panic-manager": "^1.2.0", "panic-server": "^1.1.1", diff --git a/test/sea/sea2.js b/test/sea/sea2.js new file mode 100644 index 00000000..a920f579 --- /dev/null +++ b/test/sea/sea2.js @@ -0,0 +1,60 @@ +/* global Gun,describe,expect,it,beforeEach */ +/*eslint max-len: ["error", 95, { "ignoreComments": true }]*/ +/*eslint semi: ["error", "always", { "omitLastInOneLineBlock": true}]*/ +/*eslint object-curly-spacing: ["error", "never"]*/ +/*eslint node/no-deprecated-api: [error, {ignoreModuleItems: ["new buffer.Buffer()"]}] */ + +var root; +var Gun; +(function(env){ + root = env.window ? env.window : global; + env.window && root.localStorage && root.localStorage.clear(); + try{ require('fs').unlinkSync('data.json') }catch(e){} + //root.Gun = root.Gun || require('../gun'); + if(root.Gun){ + //Gun = root.Gun = root.Gun; + } else { + var expect = global.expect = require("../expect"); + root.Gun = require('../../gun'); + //Gun.serve = require('../../lib/serve'); + //require('./s3'); + //require('./uws'); + //require('./wsp/server'); + require('../../lib/file'); + require('../../sea.js'); + } +}(this)); + +;(function(){ +Gun = root.Gun +const SEA = Gun.SEA + +if(!SEA){ return } + +describe('SEA', function(){ + var user; + var gun; + it('is instantiable', done => { + gun = Gun({ localStorage: true, radisk: false }) + user = gun.user() + done() + }) + + it('register users', async done => { + user.create('bob', 'test123', err => { + console.log('sea', SEA.err) + expect(err).toHaveProperty('ok') + setTimeout(done, 30) + }) + }) + + it('login users', async done => { + user.auth('bob', 'test123', err => { + expect(err).toHaveProperty('ok') + done() + }) + }) + +}) + +})() From 91babdb221bfe5d09d00d987b5bc41d7d5675261 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Fri, 13 Jul 2018 12:59:56 -0700 Subject: [PATCH 070/221] progress with @jadbox who setup the tests! --- sea.js | 19 ++++++++++++++++--- test/sea/sea2.js | 11 ++++++----- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/sea.js b/sea.js index 71ee0259..569f777d 100644 --- a/sea.js +++ b/sea.js @@ -382,9 +382,11 @@ var shim = USE('./shim'); var S = USE('./settings'); var sha256hash = USE('./sha256'); + var u; SEA.sign = async (data, pair, cb) => { try { - if(data.slice + // TODO: how should undefined be handled? + if((u !== data) && data.slice && 'SEA{' === data.slice(0,4) && '"m":' === data.slice(4,8)){ // TODO: This would prevent pair2 signing pair1's signature. @@ -1150,13 +1152,24 @@ const epub = await SEA.sign(pairs.epub, pairs) if(u === epub){ throw SEA.err } // to keep the private key safe, we AES encrypt it with the proof of work! - const auth = await SEA.encrypt({ priv: priv, epriv: epriv }, proof) + var auth = {}; + auth.priv = priv; + if(epriv){ + auth.epriv = epriv; + } + auth = await SEA.encrypt(auth, proof) .then((auth) => // TODO: So signedsalt isn't needed? // SEA.sign(salt, pairs).then((signedsalt) => SEA.sign({ek: auth, s: salt}, pairs) // ) ).catch((e) => { Gun.log('SEA.en or SEA.write calls failed!'); cat.ing = false; gun.leave(); reject(e) }) - const user = { alias: alias, pub: pub, epub: epub, auth: auth } + const user = {}; + user.alias = alias; + user.pub = pub; + user.auth = auth; + if(epub){ + user.epub = epub; + } const tmp = '~'+pairs.pub; // awesome, now we can actually save the user with their public key as their ID. try{ diff --git a/test/sea/sea2.js b/test/sea/sea2.js index a920f579..6a7cbdfa 100644 --- a/test/sea/sea2.js +++ b/test/sea/sea2.js @@ -41,16 +41,17 @@ describe('SEA', function(){ }) it('register users', async done => { - user.create('bob', 'test123', err => { - console.log('sea', SEA.err) - expect(err).toHaveProperty('ok') + user.create('bob', 'test123', ack => { + expect(ack.err).to.not.be.ok(); setTimeout(done, 30) }) }) it('login users', async done => { - user.auth('bob', 'test123', err => { - expect(err).toHaveProperty('ok') + console.log("------------------"); + user.auth('bob', 'test123', ack => { + console.log("?????", ack, SEA.err); + expect(ack.err).to.not.be.ok(); done() }) }) From cada32bab37dfbf314b6cc397e048795a288901d Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Mon, 16 Jul 2018 00:37:57 -0700 Subject: [PATCH 071/221] RAD improvements!!! --- lib/radisk.js | 32 +++++++++++++++----------------- lib/radix.js | 5 +++++ lib/store.js | 23 +++++++++++++---------- lib/time.js | 6 ++++-- test/radisk.html | 37 ++++++++++++++++++++++++++----------- 5 files changed, 63 insertions(+), 40 deletions(-) diff --git a/lib/radisk.js b/lib/radisk.js index 8a5ff699..2ba43142 100644 --- a/lib/radisk.js +++ b/lib/radisk.js @@ -44,7 +44,6 @@ return cb(u, val); } } - //console.log("READ FROM DISK"); return r.read(key, cb); } r.batch(key, val); @@ -71,7 +70,7 @@ r.batch.ed = 0; r.save(batch, function(err, ok){ if(++i > 1){ return } - if(err){ Gun.log(err) } + if(err){ Gun.log('err', err) } Gun.obj.map(batch.acks, function(cb){ cb(err, ok) }); thrash.at = null; thrash.ing = false; @@ -139,7 +138,7 @@ f.each = function(val, key, k, pre){ f.count++; var enc = Radisk.encode(pre.length) +'#'+ Radisk.encode(k) + (u === val? '' : '='+ Radisk.encode(val)) +'\n'; - if(opt.chunk < f.text.length + enc.length){ + if((opt.chunk < f.text.length + enc.length) && !(1 >= rad.count)){ f.text = ''; f.limit = Math.ceil(f.count/2); f.count = 0; @@ -171,15 +170,8 @@ if(!Radix.map(rad, f.each, true)){ f.write() } } - r.read = function(key, cb){ - // TODO: BUG!!! If a node spans multiple file chunks, it won't return all! - // TODO: BUG!!! If a node spans multiple file chunks, it won't return all! - // TODO: BUG!!! If a node spans multiple file chunks, it won't return all! - // TODO: BUG!!! If a node spans multiple file chunks, it won't return all! - // TODO: BUG!!! If a node spans multiple file chunks, it won't return all! - // TODO: BUG!!! If a node spans multiple file chunks, it won't return all! - // TODO: BUG!!! If a node spans multiple file chunks, it won't return all! - if(RAD){ // cache + r.read = function(key, cb, next){ + if(RAD && !next){ // cache var val = RAD(key); if(u !== val){ return cb(u, val); @@ -188,26 +180,32 @@ var g = function Get(){}, tmp; g.lex = function(file){ file = (u === file)? u : decodeURIComponent(file); - if(!file || file > key){ + if(!file || file > (next || key)){ + if(next){ g.file = file } if(tmp = q[g.file]){ - tmp.push({key: key, ack: cb}); + tmp.push({key: key, ack: cb, file: g.file}); return true; } - q[g.file] = [{key: key, ack: cb}]; + q[g.file] = [{key: key, ack: cb, file: g.file}]; r.parse(g.file, g.it); return true; } g.file = file; } g.it = function(err, disk){ - if(g.err = err){ Gun.log(err) } + if(g.err = err){ Gun.log('err', err) } if(disk){ RAD = disk } disk = q[g.file]; Gun.obj.del(q, g.file); Gun.obj.map(disk, g.ack); } g.ack = function(as){ if(!as.ack){ return } - as.ack(g.err, (RAD || noop)(as.key)); + var tmp = as.key, data = (RAD || noop)(tmp), last = (RAD||{}).last; + if(data){ as.ack(g.err, data) } + else if(!as.file){ return as.ack(g.err, u) } + if(!last || last === tmp){ return } // is this correct? + if(last > tmp && 0 > last.indexOf(tmp)){ return } + r.read(tmp, as.ack, as.file); } opt.store.list(g.lex); } diff --git a/lib/radix.js b/lib/radix.js index ae8731db..22264e76 100644 --- a/lib/radix.js +++ b/lib/radix.js @@ -2,6 +2,11 @@ function Radix(){ var radix = function(key, val, t){ + key = ''+key; + if(!t && u !== val){ + radix.last = (key < radix.last)? radix.last : key; + radix.count = (radix.count || 0) + 1; + } t = t || radix[_] || (radix[_] = {}); var i = 0, l = key.length-1, k = key[i], at, tmp; while(!(at = t[k]) && i < l){ diff --git a/lib/store.js b/lib/store.js index 5445ca14..82b7cd44 100644 --- a/lib/store.js +++ b/lib/store.js @@ -1,4 +1,6 @@ -if(typeof window === "undefined"){ +if(typeof window !== "undefined"){ + var Gun = window.Gun; +} else { var Gun = require('../gun'); } @@ -18,10 +20,11 @@ Gun.on('opt', function(ctx){ opt.store = opt.store || (!opt.window && require('./rfs')(opt)); var rad = Radisk(opt); - ctx.on('put', function(at){ - this.to.next(at); - var id = at['#'], track = !at['@'], acks = track? 0 : u; // only ack non-acks. - Gun.graph.is(at.put, null, function(val, key, node, soul){ + ctx.on('put', function(msg){ + this.to.next(msg); + var id = msg['#'], track = !msg['@'], acks = track? 0 : u; // only ack non-acks. + if(msg.rad && !track){ return } // don't save our own acks + Gun.graph.is(msg.put, null, function(val, key, node, soul){ if(track){ ++acks } val = Radisk.encode(val)+'>'+Radisk.encode(Gun.state.is(node, key)); rad(soul+'.'+key, val, (track? ack : u)); @@ -30,7 +33,7 @@ Gun.on('opt', function(ctx){ acks--; if(ack.err){ return } if(ack.err = err){ - ctx.on('in', {'@': id, err: Gun.log(err)}); + ctx.on('in', {'@': id, err: err}); return; } if(acks){ return } @@ -38,15 +41,15 @@ Gun.on('opt', function(ctx){ } }); - ctx.on('get', function(at){ - this.to.next(at); - var id = at['#'], soul = at.get['#'], key = at.get['.']||'', tmp = soul+'.'+key, node; + ctx.on('get', function(msg){ + this.to.next(msg); + var id = msg['#'], soul = msg.get['#'], key = msg.get['.']||'', tmp = soul+'.'+key, node; rad(tmp, function(err, val){ if(val){ Radix.map(val, each); if(!node){ each(val, key) } } - ctx.on('in', {'@': id, put: Gun.graph.node(node), err: err? err : u}); + ctx.on('in', {'@': id, '#': key, put: Gun.graph.node(node), err: err? err : u, rad: Radix}); }); function each(val, key){ tmp = val.lastIndexOf('>'); diff --git a/lib/time.js b/lib/time.js index 75b431f7..9025ab1f 100644 --- a/lib/time.js +++ b/lib/time.js @@ -1,4 +1,6 @@ -if(typeof window === "undefined"){ //Not in the browser, Include from node +if(typeof window !== "undefined"){ + var Gun = window.Gun; +} else { var Gun = require('../gun'); } @@ -60,7 +62,7 @@ if(typeof window === "undefined"){ //Not in the browser, Include from node function travel(cb, opt, b, gun){ var root = gun.back(-1), tmp; (opt = Gun.num.is(opt)? {last: opt} : opt || {}).seen = opt.seen || {}; - var t = now(); + var t = now(opt.start); gun.on(function(data, key, msg, eve){ var at = msg.$._, id = at.link || at.soul || Gun.node.soul(data); if(!id){ return } diff --git a/test/radisk.html b/test/radisk.html index 0083af92..4f51f9d9 100644 --- a/test/radisk.html +++ b/test/radisk.html @@ -6,29 +6,44 @@ + + +

+ + + \ No newline at end of file From 7a8fceba071bcac55cbfb707d768cf603b764f18 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Mon, 16 Jul 2018 17:59:33 -0700 Subject: [PATCH 072/221] RAD test improvements --- gun.js | 5 +++-- lib/radisk.js | 15 ++++++++++++++- package.json | 2 +- test/panic/radisk.js | 35 +++++++++++++++++++---------------- 4 files changed, 37 insertions(+), 20 deletions(-) diff --git a/gun.js b/gun.js index 687ef142..d02a6267 100644 --- a/gun.js +++ b/gun.js @@ -610,7 +610,7 @@ if(!cb){ return id } var to = this.on(id, cb, as); to.err = to.err || setTimeout(function(){ - to.next({err: "Error: No ACK received yet."}); + to.next({err: "Error: No ACK received yet.", lack: true}); to.off(); }, (this.opt||{}).lack || 9000); return id; @@ -1428,7 +1428,8 @@ as.res(function(){ var cat = (as.$.back(-1)._), ask = cat.ask(function(ack){ cat.root.on('ack', ack); - this.off(); // One response is good enough for us currently. Later we may want to adjust this. + if(ack.err){ Gun.log(ack) } + if(!ack.lack){ this.off() } // One response is good enough for us currently. Later we may want to adjust this. if(!as.ack){ return } as.ack(ack, this); }, as.opt); diff --git a/lib/radisk.js b/lib/radisk.js index 2ba43142..30be77de 100644 --- a/lib/radisk.js +++ b/lib/radisk.js @@ -4,7 +4,7 @@ opt = opt || {}; opt.file = String(opt.file || 'radata'); - opt.until = opt.until || opt.wait || 1000; // default for HDDs + opt.until = opt.until || opt.wait || 9; opt.batch = opt.batch || 10 * 1000; opt.chunk = opt.chunk || (1024 * 1024 * 10); // 10MB opt.code = opt.code || {}; @@ -36,11 +36,13 @@ cb = val; val = r.batch(key); if(u !== val){ + // if a node is requested and some of it is cached... the other parts might not be. return cb(u, val); } if(r.thrash.at){ val = r.thrash.at(key); if(u !== val){ + // if a node is requested and some of it is cached... the other parts might not be. return cb(u, val); } } @@ -174,6 +176,7 @@ if(RAD && !next){ // cache var val = RAD(key); if(u !== val){ + // if a node is requested and some of it is cached... the other parts might not be. return cb(u, val); } } @@ -209,6 +212,16 @@ } opt.store.list(g.lex); } + + var lq; + r.list = function(cb){ + if(lq){ return lq.push(cb) } + lq = [cb]; + opt.store.list(); + } + r.list.it = function(file){ + + } /* Let us start by assuming we are the only process that is changing the directory or bucket. Not because we do not want diff --git a/package.json b/package.json index 7bb359a0..9b5267bc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gun", - "version": "0.9.9994", + "version": "0.9.9995", "description": "A realtime, decentralized, offline-first, graph data synchronization engine.", "main": "index.js", "browser": "gun.min.js", diff --git a/test/panic/radisk.js b/test/panic/radisk.js index c48149e4..0799dd28 100644 --- a/test/panic/radisk.js +++ b/test/panic/radisk.js @@ -3,11 +3,11 @@ var config = { port: 8080, servers: 2, browsers: 2, - each: 100, - burst: 50, + each: 100000, + burst: 10, wait: 1, dir: __dirname, - chunk: 1024 * 10, + chunk: 1024 * 100, notrad: false, route: { '/': __dirname + '/index.html', @@ -64,7 +64,7 @@ describe("Make sure the Radix Storage Engine (RSE) works.", function(){ }); var Gun = require('gun'); //require('gun/lib/store'); - var gun = Gun({web: server, localStorage: env.config.notrad, until: 1, memory: 50, chunk: env.config.chunk, file: 'radata'}); + var gun = Gun({web: server, localStorage: env.config.notrad, chunk: env.config.chunk, file: 'radata'}); server.listen(port, function(){ test.done(); }); @@ -82,11 +82,11 @@ describe("Make sure the Radix Storage Engine (RSE) works.", function(){ console.log("I AM ALICE"); localStorage.clear(); var env = test.props; - var gun = Gun({peers: 'http://'+ env.config.IP + ':' + (env.config.port + 1) + '/gun', localStorage: env.config.notrad}); + var gun = Gun({peers: 'http://'+ env.config.IP + ':' + (env.config.port + 1) + '/gun', localStorage: env.config.notrad, lack: 1000 * 60 * 60}); window.gun = gun; var n = Gun.time.is(), i = 0, c = 0, b = env.config.burst, l = env.config.each; - var raw = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + var raw = Gun.text.random(200, 'a');// "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" function save(i){ if(i > l){ @@ -95,6 +95,13 @@ describe("Make sure the Radix Storage Engine (RSE) works.", function(){ var d; var ref = window.gun.get('asdf'+i); ref.put({hello: raw + i}, function(ack){ + if(ack.err){ + if(ack.lack){ + return test.fail("ACK timed out, turn your lack of ack up or thruput down."); + } + return test.fail(ack.err); + } + //console.log('ack?', ack.rad); if(d){ return } d = true; c++; !(i % b) && console.log(i+'/'+l);//, '@'+Math.floor(b/((-n + (n = Gun.time.is()))/1000))+'/sec'); @@ -126,7 +133,7 @@ describe("Make sure the Radix Storage Engine (RSE) works.", function(){ setTimeout(function(){ process.exit(); test.done(); - }, 10 * 1000); + }, 100); }); }); @@ -150,7 +157,7 @@ describe("Make sure the Radix Storage Engine (RSE) works.", function(){ }); var Gun = require('gun'); //require('gun/lib/store'); - var gun = Gun({web: server, localStorage: env.config.notrad, until: 1, memory: 50, chunk: env.config.notrad, file: 'radata'}); + var gun = Gun({web: server, localStorage: env.config.notrad, chunk: env.config.notrad, file: 'radata', lack: 1000 * 60 * 60}); server.listen(port, function(){ test.done(); }); @@ -167,8 +174,7 @@ describe("Make sure the Radix Storage Engine (RSE) works.", function(){ window.gun = gun; var n = Gun.time.is(), i = 0, c = 0, b = env.config.burst, l = env.config.each; - var raw = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - window.FOO = []; + var raw = Gun.text.random(200, 'a');// "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; function check(i){ if(i > l){ @@ -179,13 +185,10 @@ describe("Make sure the Radix Storage Engine (RSE) works.", function(){ ref.on(function(data){ if((raw+i) !== data.hello){ return test.fail('wrong ' + i) } if(d){ return } d = true; - //!(c % b) && - window.FOO.push(i); - console.log(c+'/'+l, 'yeah?', i, Gun.node.soul(data));//, '@'+Math.floor(b/((-n + (n = Gun.time.is()))/1000))+'/sec')); - window.GOT = c++; - //localStorage.clear(); + c++; + !(i % 1000) && console.log(i+'/'+l); + //console.log(i+'/'+l); ref.off(); - //console.log("gl:", Object.keys(window.gun._.graph).length); if(c < l){ return } console.log("DONE!", c+'/'+l); test.done(); From f7b422c69079180e44e371afba557da3d81f49fe Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Tue, 17 Jul 2018 12:20:37 -0700 Subject: [PATCH 073/221] default require Gun --- lib/bye.js | 7 +- lib/erase.js | 2 +- lib/evict.js | 3 +- lib/forget.js | 3 +- lib/gunwrapper.js | 15 --- lib/load.js | 6 +- lib/open.js | 6 +- lib/path.js | 6 +- lib/server.js | 3 - lib/set.js | 35 ------ lib/store.js | 6 +- lib/then.js | 4 +- lib/time.js | 9 +- lib/unset.js | 6 +- lib/wsp/Peer.js | 190 ------------------------------ lib/wsp/Pool.js | 101 ---------------- lib/wsp/client.js | 103 ----------------- lib/wsp/duplicate.js | 90 --------------- lib/wsp/server-push.js | 98 ---------------- lib/wsp/server.js | 257 ----------------------------------------- lib/wsp/ws.js | 40 ------- 21 files changed, 14 insertions(+), 976 deletions(-) delete mode 100644 lib/gunwrapper.js delete mode 100644 lib/set.js delete mode 100644 lib/wsp/Peer.js delete mode 100644 lib/wsp/Pool.js delete mode 100644 lib/wsp/client.js delete mode 100644 lib/wsp/duplicate.js delete mode 100644 lib/wsp/server-push.js delete mode 100644 lib/wsp/server.js delete mode 100644 lib/wsp/ws.js diff --git a/lib/bye.js b/lib/bye.js index 1aa2c65e..dc3ea64a 100644 --- a/lib/bye.js +++ b/lib/bye.js @@ -1,12 +1,9 @@ -if(typeof window !== "undefined"){ - var Gun = window.Gun; -} else { - var Gun = require('../gun'); -} +var Gun = (typeof window !== "undefined")? window.Gun : require('../gun'); Gun.on('opt', function(ctx){ this.to.next(ctx); if(ctx.once){ return } + console.log("WARNING: `lib/bye` is out of date!"); ctx.on('in', function(msg){ if(!msg.peer || !msg.BYE){ return this.to.next(msg) } var peer = msg.peer(); diff --git a/lib/erase.js b/lib/erase.js index c6509325..73bd271c 100644 --- a/lib/erase.js +++ b/lib/erase.js @@ -1,4 +1,4 @@ -var Gun = Gun || require('../gun'); +var Gun = (typeof window !== "undefined")? window.Gun : require('../gun'); Gun.on('opt', function(ctx){ this.to.next(ctx); diff --git a/lib/evict.js b/lib/evict.js index 77fa268c..24a294f1 100644 --- a/lib/evict.js +++ b/lib/evict.js @@ -1,6 +1,5 @@ ;(function(){ - var Gun = (typeof window !== 'undefined')? window.Gun : require('../gun'); - + var Gun = (typeof window !== "undefined")? window.Gun : require('../gun'); var ev = {}, empty = {}, u; Gun.on('opt', function(root){ this.to.next(root); diff --git a/lib/forget.js b/lib/forget.js index effd74db..75283ae9 100644 --- a/lib/forget.js +++ b/lib/forget.js @@ -1,6 +1,5 @@ ;(function(){ - - var Gun = (this||{}).Gun || require('../gun'); + var Gun = (typeof window !== "undefined")? window.Gun : require('../gun'); Gun.on('opt', function(ctx){ once(ctx); diff --git a/lib/gunwrapper.js b/lib/gunwrapper.js deleted file mode 100644 index 1c256edf..00000000 --- a/lib/gunwrapper.js +++ /dev/null @@ -1,15 +0,0 @@ - -// This does all old-fashion require stuff before '@std/mjs' steps in... -const Gun = require('../gun') -require('../nts') -require('./s3') -try { - require('./ws') -} catch(e) { - require('./wsp/server') -} -require('./verify') -require('./file') -require('./bye') - -module.exports = Gun diff --git a/lib/load.js b/lib/load.js index b84b2d0c..d888fe34 100644 --- a/lib/load.js +++ b/lib/load.js @@ -1,8 +1,4 @@ -if(typeof window !== "undefined"){ - var Gun = window.Gun; -} else { - var Gun = require('../gun'); -} +var Gun = (typeof window !== "undefined")? window.Gun : require('../gun'); Gun.chain.open || require('./open'); Gun.chain.load = function(cb, opt, at){ diff --git a/lib/open.js b/lib/open.js index 2b4e5642..499139fa 100644 --- a/lib/open.js +++ b/lib/open.js @@ -1,8 +1,4 @@ -if(typeof window !== "undefined"){ - var Gun = window.Gun; -} else { - var Gun = require('../gun'); -} +var Gun = (typeof window !== "undefined")? window.Gun : require('../gun'); Gun.chain.open = function(cb, opt, at){ opt = opt || {}; diff --git a/lib/path.js b/lib/path.js index 780d0f46..71fd3337 100644 --- a/lib/path.js +++ b/lib/path.js @@ -1,8 +1,4 @@ -if(typeof window !== "undefined"){ - var Gun = window.Gun; -} else { - var Gun = require('../gun'); -} +var Gun = (typeof window !== "undefined")? window.Gun : require('../gun'); Gun.chain.path = function(field, opt){ var back = this, gun = back, tmp; diff --git a/lib/server.js b/lib/server.js index 9ecc84e3..a209f099 100644 --- a/lib/server.js +++ b/lib/server.js @@ -11,11 +11,8 @@ require('../nts'); require('./store'); require('./rs3'); - //try{require('./ws');}catch(e){require('./wsp/server');} require('./wire'); - require('./verify'); require('./file'); - require('./bye'); require('./evict'); if('debug' === process.env.GUN_ENV){ require('./debug') } module.exports = Gun; diff --git a/lib/set.js b/lib/set.js deleted file mode 100644 index 47b0653c..00000000 --- a/lib/set.js +++ /dev/null @@ -1,35 +0,0 @@ -var Gun = Gun || require('../gun'); - -/* -Gun.chain.set = function(obj, cb, opt){ - var set = this; - opt = opt || {}; - cb = cb || function(){}; - set = set.put({}); // insert assumes a graph node. So either create it or merge with the existing one. - var error, item = set.chain().put(obj, function(err){ // create the new item in its own context. - error = err; // if this happens, it should get called before the .val - }).val(function(val){ - if(error){ return cb.call(set, error) } // which in case it is, allows us to fail fast. - var add = {}, soul = Gun.is.soul.on(val); - if(!soul){ return cb.call(set, {err: Gun.log("No soul!")}) } - add[soul] = val; // other wise, let's then - set.put(add, cb); // merge with the graph node. - }); - return item; -};*/ - -Gun.chain.set = function(val, cb, opt){ - var gun = this, ctx = {}, drift = Gun.time.now(); - cb = cb || function(){}; - opt = opt || {}; - - if(!gun._.back){ gun = gun.put({}) } - gun = gun.not(function(next, key){ - return key? this.put({}).key(key) : this.put({}); - }); - if(!val && !Gun.is.value(val)){ return gun } - - var obj = {}; - obj['I' + drift + 'R' + Gun.text.random(5)] = val; - return gun.put(obj, cb); -} \ No newline at end of file diff --git a/lib/store.js b/lib/store.js index 82b7cd44..8485b0be 100644 --- a/lib/store.js +++ b/lib/store.js @@ -1,8 +1,4 @@ -if(typeof window !== "undefined"){ - var Gun = window.Gun; -} else { - var Gun = require('../gun'); -} +var Gun = (typeof window !== "undefined")? window.Gun : require('../gun'); Gun.on('opt', function(ctx){ this.to.next(ctx); diff --git a/lib/then.js b/lib/then.js index 94e7c80e..b0034094 100644 --- a/lib/then.js +++ b/lib/then.js @@ -1,9 +1,9 @@ -var Gun = Gun || require('../gun'); +var Gun = (typeof window !== "undefined")? window.Gun : require('../gun'); Gun.chain.promise = function(cb) { var gun = this, cb = cb || function(ctx) { return ctx }; return (new Promise(function(res, rej) { - gun.val(function(data, key){ + gun.once(function(data, key){ res({put: data, get: key, gun: this}); }); })).then(cb); diff --git a/lib/time.js b/lib/time.js index 9025ab1f..b4d8d951 100644 --- a/lib/time.js +++ b/lib/time.js @@ -1,10 +1,5 @@ -if(typeof window !== "undefined"){ - var Gun = window.Gun; -} else { - var Gun = require('../gun'); -} - ;(function(){ + var Gun = (typeof window !== "undefined")? window.Gun : require('../gun'); var ify = Gun.node.ify, u; Gun.chain.time = function(data, a, b){ if(data instanceof Function){ @@ -140,4 +135,4 @@ if(typeof window !== "undefined"){ at = at.slice(-7); return new Date(Date.UTC(at[0], parseFloat(at[1])-1, at[2], at[3], at[4], at[5], at[6])); } -}()); +}()); \ No newline at end of file diff --git a/lib/unset.js b/lib/unset.js index 65ae287c..98dae1a9 100644 --- a/lib/unset.js +++ b/lib/unset.js @@ -1,8 +1,4 @@ -if(typeof window !== "undefined"){ - var Gun = window.Gun; -} else { - var Gun = require('gun/gun'); -} +var Gun = (typeof window !== "undefined")? window.Gun : require('../gun'); const rel_ = Gun.val.link._; // '#' const node_ = Gun.node._; // '_' diff --git a/lib/wsp/Peer.js b/lib/wsp/Peer.js deleted file mode 100644 index 2b9dffed..00000000 --- a/lib/wsp/Peer.js +++ /dev/null @@ -1,190 +0,0 @@ -/* eslint-disable no-underscore-dangle */ -'use strict'; - -var WebSocket = require('ws'); -var Emitter = require('events'); -var util = require('util'); - -/** - * Calculates backoff instances. - * @param {Object} [options] - Override the default settings. - * @param {Object} options.time=50 - Initial backoff time. - * @param {Object} options.factor=2 - How much to multiply the time by. - * @param {Object} options.max=1min - Maximum backoff time. - * @class - */ -function Backoff (options) { - this.options = options || {}; - - // Sets the initial backoff settings. - this.reset(); -} - -/** - * Increments the time by the factor. - * @return {Number} - The next backoff time. - */ -Backoff.prototype.next = function () { - var next = this.time * this.factor; - - if (next > this.max) { - this.time = this.max; - return this.max; - } - - this.time = next; - - return this.time; -}; - -/** - * Resets the backoff state to it's original condition. - * @return {Backoff} - The context. - */ -Backoff.prototype.reset = function () { - var options = this.options; - - this.time = options.time || 50; - this.factor = options.factor || 2; - this.max = options.max || 1 * 60 * 1000; - - return this; -}; - -/** - * Schedules the next connection, according to the backoff. - * @param {Peer} peer - A peer instance. - * @return {Timeout} - The timeout value from `setTimeout`. - */ -function scheduleReconnect (peer) { - var backoff = peer.backoff; - var time = backoff.time; - backoff.next(); - - var reconnect = peer.connect.bind(peer); - - return setTimeout(reconnect, time); -} - -/** - * Handles reconnections and defers messages until the socket is ready. - * @param {String} url - The address to connect to. - * @param {Object} [options] - Override how the socket is managed. - * @param {Object} options.backoff - Backoff options (see the constructor). - * @class - */ -function Peer (url, options) { - if (!(this instanceof Peer)) { - return new Peer(url, options); - } - - // Extend EventEmitter. - Emitter.call(this); - this.setMaxListeners(Infinity); - - this.options = options || {}; - - // Messages sent before the socket is ready. - this.deferredMsgs = []; - - this.url = Peer.formatURL(url); - this.backoff = new Backoff(this.options.backoff); - - // Set up the websocket. - this.connect(); - - var peer = this; - var reconnect = scheduleReconnect.bind(null, peer); - - // Handle reconnection. - this.on('close', reconnect); - this.on('error', function (error) { - if (error.code === 'ECONNREFUSED') { - reconnect(); - } - }); - - // Send deferred messages. - this.on('open', function () { - peer.drainQueue(); - peer.backoff.reset(); - }); - -} - -/** - * Turns http URLs into WebSocket URLs. - * @param {String} url - The url to format. - * @return {String} - A correctly formatted WebSocket URL. - */ -Peer.formatURL = function (url) { - - // Works for `https` and `wss` URLs, too. - return url.replace(/^http/, 'ws'); -}; - -util.inherits(Peer, Emitter); -var API = Peer.prototype; - -/** - * Attempts a websocket connection. - * @return {WebSocket} - The new websocket instance. - */ -API.connect = function () { - var url = this.url; - - // Open a new websocket. - var socket = new WebSocket(url, this.options.wsc.protocols, this.options.wsc); - - // Re-use the previous listeners. - socket._events = this._events; - - this.socket = socket; - - return socket; -}; - -/** - * Sends all the messages in the deferred queue. - * @return {Peer} - The context. - */ -API.drainQueue = function () { - var peer = this; - - this.deferredMsgs.forEach(function (msg) { - peer.send(msg); - }); - - // Reset the queue. - this.deferredMsgs = []; - - return this; -}; - -/** - * Send data through the socket, or add it to a queue - * of deferred messages if it's not ready yet. - * @param {Mixed} msg - String, or anything that JSON can handle. - * @return {Peer} - The context. - */ -API.send = function (msg) { - var socket = this.socket; - var state = socket.readyState; - var ready = socket.OPEN; - - // Make sure it's a string. - if (typeof msg !== 'string') { - msg = JSON.stringify(msg); - } - - // Make sure the socket is ready. - if (state === ready) { - socket.send(msg); - } else { - this.deferredMsgs.push(msg); - } - - return this; -}; - -module.exports = Peer; diff --git a/lib/wsp/Pool.js b/lib/wsp/Pool.js deleted file mode 100644 index 542c0482..00000000 --- a/lib/wsp/Pool.js +++ /dev/null @@ -1,101 +0,0 @@ -'use strict'; - -/** - * Simpler interface over a collection of sockets. Works with - * WebSocket clients, or sockets from a WebSocket server. - * @class - */ -function Pool () { - if (!(this instanceof Pool)) { - return new Pool(); - } - - // Maps IDs to sockets. - this.sockets = {}; -} - -var API = Pool.prototype; - -/** - * Returns the socket by the given ID. - * @param {String} id - The unique socket ID. - * @return {WebSocket|Null} - The WebSocket, if found. - */ -API.get = function (id) { - return this.sockets[id] || null; -}; - -/** - * Adds a socket to the pool. - * @param {String} id - The socket ID. - * @param {WebSocket} socket - A websocket instance. - * @return {Pool} - The context. - */ -API.add = function (id, socket) { - this.sockets[id] = socket; - - return this; -}; - -/** - * Removes a socket from the pool. - * @param {String} id - The ID of the socket to remove. - * @return {Boolean} - Whether the pool contained the socket. - */ -API.remove = function (id) { - var sockets = this.sockets; - var hasSocket = sockets.hasOwnProperty(id); - - if (hasSocket) { - delete sockets[id]; - } - - return hasSocket; -}; - -/** - * Creates a filtered pool of sockets. Works the same as Array#filter. - * @param {Function} fn - Called for each socket in the pool. - * @param {Mixed} [_this] - The `this` context to use when invoking - * the callback. - * @return {Pool} - A new, filtered socket pool. - */ -API.filter = function (fn, _this) { - var filtered = Pool(); - var pool = this; - - _this = _this || pool; - - Object.keys(this.sockets).forEach(function (id) { - var socket = pool.sockets[id]; - - var shouldAdd = fn.call(_this, socket, id, pool); - - // Add it to the new pool. - if (shouldAdd) { - filtered.add(id, socket); - } - }); - - return filtered; -}; - -/** - * Send a message through each socket in the pool. - * @param {String} msg - The message to send. - * @return {Number} - How many sockets the message was sent to. - */ -API.send = function (msg) { - var pool = this; - - var ids = Object.keys(this.sockets); - - ids.forEach(function (id) { - var socket = pool.sockets[id]; - socket.send(msg); - }); - - return ids.length; -}; - -module.exports = Pool; diff --git a/lib/wsp/client.js b/lib/wsp/client.js deleted file mode 100644 index 3cdb3850..00000000 --- a/lib/wsp/client.js +++ /dev/null @@ -1,103 +0,0 @@ -/* - eslint-disable - no-warning-comments, - no-underscore-dangle, -*/ -'use strict'; - -var Gun = require('../../gun'); -var Socket = require('./Peer'); -var Pool = require('./Pool'); - -// Maps URLs to sockets. -// Shared between all gun instances. -var sockets = Pool(); -var sid = Gun.text.random(); - -/** - * Take a map of URLs pointing to options and ensure the - * urls are using the WS protocol. - * @param {Object} peers - Any object with URLs as keys. - * @return {Object} - Object with normalized URL keys. - */ -function normalizeURLs (peers) { - var formatted = {}; - - Object.keys(peers).forEach(function (url) { - var options = peers[url]; - var id = Socket.formatURL(url); - formatted[id] = options; - }); - - return formatted; -} - -/** - * Turns a map of URLs into a socket pool. - * @param {Object} peers - Any object with URLs as keys. - * @return {Pool} - A pool of sockets corresponding to the URLs. - */ -function getSocketSubset (peers) { - var urls = normalizeURLs(peers); - - return sockets.filter(function (socket) { - return urls.hasOwnProperty(socket.url); - }); -} - -Gun.on('out', function (ctx) { - this.to.next(ctx); - var gun = ctx.gun; - var opt = ctx.opt || {}; - var peers = opt.peers || gun.back('opt.peers'); - var headers = opt.headers || gun.back('opt.headers') || {}; - - if (!peers) { - return; - } - - var subset = getSocketSubset(peers); - - headers['gun-sid'] = sid; - subset.send({ - headers: headers, - body: ctx, - }); -}); - -// Open any new sockets listed, -// adding them to the global pool. -Gun.on('opt', function (context) { - var gun = context.gun; - var root = gun.back(Infinity); - - var peers = gun.back('opt.peers') || {}; - - Gun.obj.map(peers, function (options, url) { - if (sockets[url]) { - return; - } - if (!options.wsc){ options.wsc = gun.back('opt.wsc') || { protocols:null }; } - - var socket = Socket(url, options); - sockets.add(url, socket); - - socket.on('message', function (msg) { - var request; - - try { - request = JSON.parse(msg); - } catch (error) { - return; - } - - // Validate the request. - if (!request || !request.body) { - return; - } - - root.on('in', request.body); - }); - }); - this.to.next(context); -}); diff --git a/lib/wsp/duplicate.js b/lib/wsp/duplicate.js deleted file mode 100644 index 9080fee7..00000000 --- a/lib/wsp/duplicate.js +++ /dev/null @@ -1,90 +0,0 @@ -'use strict'; - -var Gun = require('../../gun'); - -var cache = {}; -var timeout = null; - -/** - * Remove all entries in the cache older than 5 minutes. - * Reschedules itself to run again when the oldest item - * might be too old. - * @return {undefined} - */ -function gc () { - var now = Date.now(); - var oldest = now; - var maxAge = 5 * 60 * 1000; - - Gun.obj.map(cache, function (time, id) { - oldest = Math.min(now, time); - - if ((now - time) < maxAge) { - return; - } - - delete cache[id]; - }); - - var done = Gun.obj.empty(cache); - - // Disengage GC. - if (done) { - timeout = null; - return; - } - - // Just how old? - var elapsed = now - oldest; - - // How long before it's too old? - var nextGC = maxAge - elapsed; - - // Schedule the next GC event. - timeout = setTimeout(gc, nextGC); -} - -/** - * Checks a memory-efficient cache to see if a string has been seen before. - * @param {String} id - A string to keep track of. - * @return {Boolean} - Whether it's been seen recently. - */ -function duplicate (id) { - - // Have we seen this ID recently? - var existing = cache.hasOwnProperty(id); - - // Add it to the cache. - duplicate.track(id); - - return existing; -} - -/** - * Starts tracking an ID as a possible future duplicate. - * @param {String} id - The ID to track. - * @return {String} - The same ID. - */ -duplicate.track = function (id) { - cache[id] = Date.now(); - - // Engage GC. - if (!timeout) { - gc(); - } - - return id; -}; - -/** - * Generate a new ID and start tracking it. - * @param {Number} [chars] - The number of characters to use. - * @return {String} - The newly created ID. - */ -duplicate.track.newID = function (chars) { - var id = Gun.text.random(chars); - - return duplicate.track(id); -}; - -module.exports = duplicate; diff --git a/lib/wsp/server-push.js b/lib/wsp/server-push.js deleted file mode 100644 index 772cd452..00000000 --- a/lib/wsp/server-push.js +++ /dev/null @@ -1,98 +0,0 @@ -'use strict'; -var Gun = require('../../gun.js'); - -/** - * Whether the gun instance is attached to a socket server. - * @param {Gun} gun - The gun instance in question. - * @param {WebSocket.Server} server - A socket server gun might be attached to. - * @return {Boolean} - Whether it's attached. - */ -function isUsingServer (gun, server) { - var servers = gun.back(-1)._.servers; - - return servers ? servers.indexOf(server) !== -1 : false; -} - -/** - * Calls a function when (or if) a socket is ready for messages. - * @param {WebSocket} socket - A websocket connection. - * @param {Function} cb - Called if or when the socket is ready. - * @return {Boolean} - Whether the socket is able to take messages. - */ -function ready (socket, cb) { - var state = socket.readyState; - - // The socket is ready. - if (state === socket.OPEN) { - cb(); - return true; - } - - // Still opening. - if (state === socket.OPENING) { - socket.once('open', cb); - } - - // Nope, closing or closed. - return false; -} - -/** - * Send a message to a group of clients. - * @param {Obejct} msg - An http envelope-like message. - * @param {Object} clients - IDs mapped to socket instances. - * @return {undefined} - */ -function send (msg, clients) { - Gun.obj.map(clients, function (client) { - ready(client, function () { - var serialized = JSON.stringify(msg); - client.send(serialized); - }); - }); -} - -/** * Attaches server push middleware to gun. - * @param {Gun} gun - The gun instance to attach to. - * @param {WebSocket.Server} server - A websocket server instance. - * @return {server} - The socket server. - */ -function attach (gun, server) { - var root = gun.back(-1); - root._.servers = root._.servers || []; - root._.servers.push(server); - var pool = {}; - var sid = Gun.text.random(); - server.on('connection', function (socket) { - socket.id = socket.id || Gun.text.random(10); - pool[socket.id] = socket; - /* - socket.on('message', function (message) { - var data = Gun.obj.ify(message); - - if (!data || !data.body) { - return; - } - root.on('in', data.body); - }); - */ - socket.once('close', function () { - delete pool[socket.id]; - }); - }); - - Gun.on('out', function (context) { - this.to.next(context); - if (!isUsingServer(context.gun, server) || Gun.obj.empty(pool)) { - return; - } - - var msg = { - headers: { 'gun-sid': sid }, - body: context, - }; - send(msg, pool); - }); -} - -module.exports = attach; diff --git a/lib/wsp/server.js b/lib/wsp/server.js deleted file mode 100644 index c7fb528c..00000000 --- a/lib/wsp/server.js +++ /dev/null @@ -1,257 +0,0 @@ -/* eslint-disable require-jsdoc, no-underscore-dangle */ -'use strict'; -var Gun = require('../../gun'); -var http = require('../http'); -var url = require('url'); -var WS = require('ws'); -var WSS = WS.Server; -var attach = require('./server-push'); - -// Handles server to server sync. -require('./client.js'); - -Gun.on('opt', function (at) { - this.to.next(at); - var gun = at.gun, opt = at.opt; - gun.__ = at.root; - gun.__.opt.ws = opt.ws = gun.__.opt.ws || opt.ws || {}; - gun.__.opt.ws.path = gun.__.opt.ws.path || '/gun'; - - if(gun.__.opt.web){ - setTimeout(function(){ - if(gun.__.opt.web.use){ - gun.__.opt.web.use(Gun.serve); - } - start(gun.__.opt.web); - },1); - } - function start (server, port, app) { - if (app && app.use) { - app.use(gun.wsp.server); - } - server = gun.__.opt.ws.server = gun.__.opt.ws.server || gun.__.opt.web || opt.ws.server || server; - - if (!gun.wsp.ws) { - //console.log("????????", gun.__.opt.ws); - gun.wsp.ws = new WSS(gun.__.opt.ws); - attach(gun, gun.wsp.ws); - } - - require('./ws')(gun.wsp.ws, function (req, res) { - var ws = this; - req.headers['gun-sid'] = ws.sid = ws.sid ? ws.sid : req.headers['gun-sid']; - ws.sub = ws.sub || gun.wsp.on('network', function (msg) { - var ev = this; ev.to.next(msg); - if (!ws || !ws.send || !ws._socket || !ws._socket.writable) { return ev.off(); } - if (!msg || (msg.headers && msg.headers['gun-sid'] === ws.sid)) { return; } - if (msg && msg.headers) { delete msg.headers['ws-rid']; } - // TODO: BUG? ^ What if other peers want to ack? Do they use the ws-rid or a gun declared id? - try { ws.send(Gun.text.ify(msg)); - } catch (e) {} // juuuust in case. - }); - gun.wsp.wire(req, res); - }, {headers: {'ws-rid': 1, 'gun-sid': 1}}); - gun.__.opt.ws.port = gun.__.opt.ws.port || opt.ws.port || port || 80; - } - var wsp = gun.wsp = gun.wsp || function (server) { - console.log("WARNING: gun.wsp(server) should be switched to Gun({web: server}) by v0.7!") - if (!server) { return gun; } - if (Gun.fns.is(server.address)) { - if (server.address()) { - start(server, server.address().port); - return gun; - } - } - if (Gun.fns.is(server.get) && server.get('port')) { - start(server, server.get('port')); - return gun; - } - var listen = server.listen; - server.listen = function (port) { - var serve = listen.apply(server, arguments); - start(serve, port, server); - return serve; - }; - return gun; - }; - gun.wsp.on = gun.wsp.on || Gun.on; - gun.wsp.regex = gun.wsp.regex || opt.route || opt.path || /^\/gun/i; - gun.wsp.poll = gun.wsp.poll || opt.poll || 1; - gun.wsp.pull = gun.wsp.pull || opt.pull || gun.wsp.poll * 1000; - gun.wsp.server = gun.wsp.server || function (req, res, next) { // http - next = next || function () {}; - if (!req || !res) { return next(), false; } - if (!req.url) { return next(), false; } - if (!req.method) { return next(), false; } - var msg = {}; - msg.url = url.parse(req.url, true); - if (!gun.wsp.regex.test(msg.url.pathname)) { return next(), false; } // TODO: BUG! If the option isn't a regex then this will fail! - if (msg.url.pathname.replace(gun.wsp.regex, '').slice(0, 3).toLowerCase() === '.js') { - res.writeHead(200, {'Content-Type': 'text/javascript'}); - res.end(gun.wsp.js = gun.wsp.js || require('fs').readFileSync(__dirname + '/../../gun.js')); // gun server is caching the gun library for the client - return true; - } - - if (!req.upgrade) { - next(); - return false; - } - - return http(req, res, function (req, res) { - if (!req) { return next(); } - var stream, cb = res = require('../jsonp')(req, res); - if (req.headers && (stream = req.headers['gun-sid'])) { - stream = (gun.wsp.peers = gun.wsp.peers || {})[stream] = gun.wsp.peers[stream] || {sid: stream}; - stream.drain = stream.drain || function (res) { - if (!res || !stream || !stream.queue || !stream.queue.length) { return; } - res({headers: {'gun-sid': stream.sid}, body: stream.queue }); - stream.off = setTimeout(function () { stream = null; }, gun.wsp.pull); - stream.reply = stream.queue = null; - return true; - }; - stream.sub = stream.sub || gun.wsp.on('network', function (req) { - var ev = this; ev.to.next(req); - if (!stream) { return ev.off(); } // self cleans up after itself! - if (!req || (req.headers && req.headers['gun-sid'] === stream.sid)) { return; } - (stream.queue = stream.queue || []).push(req); - stream.drain(stream.reply); - }); - cb = function (r) { (r.headers || {}).poll = gun.wsp.poll; res(r); }; - clearTimeout(stream.off); - if (req.headers.pull) { - if (stream.drain(cb)) { return; } - return stream.reply = cb; - } - } - gun.wsp.wire(req, cb); - }), true; - }; - if ((gun.__.opt.maxSockets = opt.maxSockets || gun.__.opt.maxSockets) !== false) { - require('https').globalAgent.maxSockets = require('http').globalAgent.maxSockets = gun.__.opt.maxSockets || Infinity; - } - gun.wsp.msg = gun.wsp.msg || function (id) { - if (!id) { - return gun.wsp.msg.debounce[id = Gun.text.random(9)] = Gun.time.is(), id; - } - clearTimeout(gun.wsp.msg.clear); - gun.wsp.msg.clear = setTimeout(function () { - var now = Gun.time.is(); - Gun.obj.map(gun.wsp.msg.debounce, function (t, id) { - if ((now - t) < (1000 * 60 * 5)) { return; } - Gun.obj.del(gun.wsp.msg.debounce, id); - }); - }, 500); - if (id = gun.wsp.msg.debounce[id]) { - return gun.wsp.msg.debounce[id] = Gun.time.is(), id; - } - gun.wsp.msg.debounce[id] = Gun.time.is(); - return; - }; - gun.wsp.msg.debounce = gun.wsp.msg.debounce || {}; - gun.wsp.wire = gun.wsp.wire || (function () { - // all streams, technically PATCH but implemented as - // PUT or POST, are forwarded to other trusted peers - // except for the ones that are listed in the message - // as having already been sent to. - // all states, implemented with GET, are replied to the - // source that asked for it. - function tran (req, res) { - if (!req || !res || !req.body || !req.headers) { - return; - } - if (req.url) { - req.url = url.format(req.url); - } - // var msg = req.body; - gun.on('in', req.body); - // // AUTH for non-replies. - // if(gun.wsp.msg(msg['#'])){ return } - // gun.wsp.on('network', Gun.obj.copy(req)); - // if(msg['@']){ return } // no need to process. - // if(msg['$'] && msg['$']['#']){ return tran.get(req, res) } - // //if(Gun.is.lex(msg['$'])){ return tran.get(req, res) } - // else { return tran.put(req, res) } - // cb({body: {hello: 'world'}}); - // // TODO: BUG! server put should push. - } - tran.get = function (req, cb) { - var body = req.body; - var lex = body.$; - var reply = { - headers: { 'Content-Type': tran.json }, - }; - - var graph = gun.back(Infinity)._.graph; - var node = graph[lex['#']]; - var result = Gun.graph.ify(node); - - if (node) { - cb({ - headers: reply.headers, - body: { - '#': gun.wsp.msg(), - '@': body['#'], - '$': result, - }, - }); - - return; - } - - gun.on('out', { - gun: gun, - get: lex, - req: 1, - '#': body['#'] || Gun.on.ask(function (at, ev) { - ev.off(); - var graph = at.put; - return cb({ - headers: reply.headers, - body: { - '#': gun.wsp.msg(), - '@': body['#'], - '$': graph, - '!': at.err, - }, - }); - }), - }); - }; - - tran.put = function (req, cb) { - // NOTE: It is highly recommended you do your own PUT/POSTs - // through your own API that then saves to gun manually. - // This will give you much more fine-grain control over - // security, transactions, and what not. - var body = req.body; - var graph = body.$; - var reply = { - headers: { 'Content-Type': tran.json }, - }; - - gun.on('out', { - gun: gun, - put: graph, - '#': Gun.on.ask(function (ack, ev) { - ev.off(); - return cb({ - headers: reply.headers, - body: { - '#': gun.wsp.msg(), - '@': body['#'], - '$': ack, - '!': ack.err, - }, - }); - }), - }); - }; - - tran.json = 'application/json'; - return tran; - }()); - - if (opt.server) { - wsp(opt.server); - } -}); diff --git a/lib/wsp/ws.js b/lib/wsp/ws.js deleted file mode 100644 index 57916afd..00000000 --- a/lib/wsp/ws.js +++ /dev/null @@ -1,40 +0,0 @@ -var Gun = require('../../gun') -, url = require('url'); -module.exports = function(wss, server, opt){ - wss.on('connection', function(ws){ - var req = {}; - ws.upgradeReq = ws.upgradeReq || {}; - req.url = url.parse(ws.upgradeReq.url||''); - req.method = (ws.upgradeReq.method||'').toLowerCase(); - req.headers = ws.upgradeReq.headers || {}; - //Gun.log("wsReq", req); - ws.on('message', function(msg){ - msg = Gun.obj.ify(msg); - msg.url = msg.url || {}; - msg.url.pathname = (req.url.pathname||'') + (msg.url.pathname||''); - Gun.obj.map(req.url, function(val, i){ - msg.url[i] = msg.url[i] || val; // reattach url - }); - msg.method = msg.method || msg.body? 'put' : 'get'; - msg.headers = msg.headers || {}; - Gun.obj.map(opt.headers || req.headers, function(val, i){ - msg.headers[i] = msg.headers[i]; // reattach headers - }); - server.call(ws, msg, function(reply){ - if(!ws || !ws.send || !ws._socket || !ws._socket.writable){ return } - reply = reply || {}; - if(msg && msg.headers && msg.headers['ws-rid']){ - (reply.headers = reply.headers || {})['ws-rid'] = msg.headers['ws-rid']; - } - try{ws.send(Gun.text.ify(reply)); - }catch(e){} // juuuust in case. - }); - }); - ws.off = function(m){ - //Gun.log("ws.off", m); - ws.send = null; - } - ws.on('close', ws.off); - ws.on('error', ws.off); - }); -} \ No newline at end of file From 6164d4c75341d6434bc5c7e31e2e483aaa1352fa Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Tue, 17 Jul 2018 15:50:42 -0700 Subject: [PATCH 074/221] adjust defaults --- examples/http.js | 4 +-- lib/bye.js | 12 +++---- lib/erase.js | 12 +++---- lib/file.js | 21 +++++------ lib/forget.js | 14 ++++---- lib/radisk.js | 86 +++++++++++++++++++++++++++++++++++--------- lib/rs3.js | 9 +++-- lib/store.js | 23 ++++++------ test/panic/radisk.js | 4 +-- 9 files changed, 119 insertions(+), 66 deletions(-) diff --git a/examples/http.js b/examples/http.js index e0dc12eb..defc3122 100644 --- a/examples/http.js +++ b/examples/http.js @@ -1,4 +1,4 @@ -var port = process.env.OPENSHIFT_NODEJS_PORT || process.env.VCAP_APP_PORT || process.env.PORT || process.argv[2] || 8080; +var port = process.env.OPENSHIFT_NODEJS_PORT || process.env.VCAP_APP_PORT || process.env.PORT || process.argv[2] || 8080 || 8765; var Gun = require('../'); @@ -19,4 +19,4 @@ var gun = Gun({ server.listen(port); -console.log('Server started on port ' + port + ' with /gun'); +console.log('Server started on port ' + port + ' with /gun'); \ No newline at end of file diff --git a/lib/bye.js b/lib/bye.js index dc3ea64a..e3f34aaa 100644 --- a/lib/bye.js +++ b/lib/bye.js @@ -1,18 +1,18 @@ var Gun = (typeof window !== "undefined")? window.Gun : require('../gun'); -Gun.on('opt', function(ctx){ - this.to.next(ctx); - if(ctx.once){ return } +Gun.on('opt', function(root){ + this.to.next(root); + if(root.once){ return } console.log("WARNING: `lib/bye` is out of date!"); - ctx.on('in', function(msg){ + root.on('in', function(msg){ if(!msg.peer || !msg.BYE){ return this.to.next(msg) } var peer = msg.peer(); (peer.bye = peer.bye || []).push(msg.BYE); }) - ctx.on('bye', function(peer){ + root.on('bye', function(peer){ this.to.next(peer); if(!peer.bye){ return } - var gun = ctx.gun; + var gun = root.gun; Gun.obj.map(peer.bye, function(data){ Gun.obj.map(data, function(put, soul){ gun.get(soul).put(put); diff --git a/lib/erase.js b/lib/erase.js index 73bd271c..4b4cd1be 100644 --- a/lib/erase.js +++ b/lib/erase.js @@ -1,13 +1,13 @@ var Gun = (typeof window !== "undefined")? window.Gun : require('../gun'); -Gun.on('opt', function(ctx){ - this.to.next(ctx); - if(ctx.once){ return } - ctx.on('put', function(msg){ +Gun.on('opt', function(root){ + this.to.next(root); + if(root.once){ return } + root.on('put', function(msg){ Gun.graph.is(msg.put, null, function(val, key, node, soul){ if(null !== val){ return } // TODO: Refactor this to use `.off()`? - var tmp = ctx.graph[soul]; + var tmp = root.graph[soul]; if(tmp){ delete tmp[key]; } @@ -15,7 +15,7 @@ Gun.on('opt', function(ctx){ if(tmp){ delete tmp[key]; } - tmp = ctx.next; + tmp = root.next; if(tmp && (tmp = tmp[soul]) && (tmp = tmp.put)){ delete tmp[key]; tmp = tmp._ && tmp._['>']; diff --git a/lib/file.js b/lib/file.js index 18881334..74ec7f01 100644 --- a/lib/file.js +++ b/lib/file.js @@ -6,14 +6,15 @@ var Gun = require('../gun'), fs = require('fs'); -Gun.on('opt', function(ctx){ - this.to.next(ctx); - var opt = ctx.opt; - if(ctx.once){ return } +Gun.on('create', function(root){ + this.to.next(root); + var opt = root.opt; + //if(true !== opt.localStorage){ return } if(false === opt.localStorage){ return } + if(process.env.RAD_ENV){ return } if(process.env.AWS_S3_BUCKET){ return } opt.file = String(opt.file || 'data.json'); - var graph = ctx.graph, acks = {}, count = 0, to; + var graph = root.graph, acks = {}, count = 0, to; var disk = Gun.obj.ify((fs.existsSync || require('path').existsSync)(opt.file)? fs.readFileSync(opt.file).toString() : null) || {}; @@ -24,7 +25,7 @@ Gun.on('opt', function(ctx){ 'intended for local development testing only!' ); - ctx.on('put', function(at){ + root.on('put', function(at){ this.to.next(at); Gun.graph.is(at.put, null, map); if(!at['@']){ acks[at['#']] = true; } // only ack non-acks. @@ -36,7 +37,7 @@ Gun.on('opt', function(ctx){ to = setTimeout(flush, opt.wait || 1); }); - ctx.on('get', function(at){ + root.on('get', function(at){ this.to.next(at); var lex = at.get, soul, data, opt, u; //setTimeout(function(){ @@ -48,7 +49,7 @@ Gun.on('opt', function(ctx){ if(data && field){ data = Gun.state.to(data, field); } - ctx.on('in', {'@': at['#'], put: Gun.graph.node(data)}); + root.on('in', {'@': at['#'], put: Gun.graph.node(data)}); //},11); }); @@ -68,7 +69,7 @@ Gun.on('opt', function(ctx){ var tmp = count; count = 0; Gun.obj.map(ack, function(yes, id){ - ctx.on('in', { + root.on('in', { '@': id, err: err, ok: err? u : 1 @@ -84,7 +85,7 @@ Gun.on('opt', function(ctx){ if(!Gun.text.match(soul, rgx)){ return } if(has){ node = Gun.state.to(node, has) } (put = {})[soul] = node; - ctx.on('in', {put: put, '@': at['#']}); + root.on('in', {put: put, '@': at['#']}); }); } }); \ No newline at end of file diff --git a/lib/forget.js b/lib/forget.js index 75283ae9..7cedd03f 100644 --- a/lib/forget.js +++ b/lib/forget.js @@ -1,15 +1,15 @@ ;(function(){ var Gun = (typeof window !== "undefined")? window.Gun : require('../gun'); - Gun.on('opt', function(ctx){ - once(ctx); - this.to.next(ctx); + Gun.on('opt', function(root){ + once(root); + this.to.next(root); }); - function once(ctx){ - if(ctx.once){ return } - var forget = ctx.opt.forget = ctx.opt.forget || {}; - ctx.on('put', function(msg){ + function once(root){ + if(root.once){ return } + var forget = root.opt.forget = root.opt.forget || {}; + root.on('put', function(msg){ Gun.graph.is(msg.put, function(node, soul){ if(!Gun.obj.has(forget, soul)){ return } delete msg.put[soul]; diff --git a/lib/radisk.js b/lib/radisk.js index 30be77de..2cfe7506 100644 --- a/lib/radisk.js +++ b/lib/radisk.js @@ -22,7 +22,7 @@ return Gun.log("ERROR: Radisk needs `store.get` interface with `(file, cb)`!"); } if(!opt.store.list){ - return Gun.log("ERROR: Radisk needs a streaming `store.list` interface with `(cb)`!"); + Gun.log("WARNING: `store.list` interface might be needed!"); } /* @@ -94,7 +94,7 @@ s.find = function(tree, key){ if(key < s.start){ return } s.start = key; - opt.store.list(s.lex); + r.list(s.lex); return true; } s.lex = function(file){ @@ -109,6 +109,7 @@ s.start = s.end = s.file = u; r.parse(file, function(err, disk){ if(err){ return cb(err) } + disk = disk || Radix(); Radix.map(rad, function(val, key){ if(key < start){ return } if(end && end < key){ return s.start = key } @@ -132,7 +133,7 @@ Therefore it is unavoidable that a read will have to happen, the question is just how long you delay it. */ - r.write = function(file, rad, cb){ + r.write = function(file, rad, cb, force){ var f = function Fractal(){}; f.text = ''; f.count = 0; @@ -140,7 +141,7 @@ f.each = function(val, key, k, pre){ f.count++; var enc = Radisk.encode(pre.length) +'#'+ Radisk.encode(k) + (u === val? '' : '='+ Radisk.encode(val)) +'\n'; - if((opt.chunk < f.text.length + enc.length) && !(1 >= rad.count)){ + if((opt.chunk < f.text.length + enc.length) && !(1 >= rad.count) && !force){ f.text = ''; f.limit = Math.ceil(f.count/2); f.count = 0; @@ -150,7 +151,13 @@ } f.text += enc; } - f.write = function(){ opt.store.put(ename(file), f.text, cb) } + f.write = function(){ + var tmp = ename(file); + r.list.add(tmp, function(err, ok){ + if(err){ return cb(err) } + opt.store.put(tmp, f.text, cb); + }); + } f.slice = function(val, key){ if(key < f.file){ return } if(f.limit < (++f.count)){ @@ -210,18 +217,65 @@ if(last > tmp && 0 > last.indexOf(tmp)){ return } r.read(tmp, as.ack, as.file); } - opt.store.list(g.lex); + r.list(g.lex); } - var lq; - r.list = function(cb){ - if(lq){ return lq.push(cb) } - lq = [cb]; - opt.store.list(); - } - r.list.it = function(file){ - - } + ;(function(){ + var dir, dq, f = String.fromCharCode(28), ef = ename(f); + r.list = function(cb){ + if(dir){ + Radix.map(dir, function(val, key){ + return cb(key); + }) || cb(); + return; + } + if(dq){ return dq.push(cb) } + dq = [cb]; + r.parse(f, r.list.init); + } + r.list.add = function(file, cb){ + var has = dir(file); + if(has || file === ef){ + return cb(u, 1); + } + dir(file, true); + r.write(f, dir, function(err, ok){ + if(err){ return cb(err) } + cb(u, 1); + }, true); + } + r.list.init = function(err, disk){ + if(err){ + Gun.log('list', err); + setTimeout(function(){ r.parse(f, r.list.init) }, 1000); + return; + } + if(disk){ + r.list.drain(disk); + return; + } + if(!opt.store.list){ + r.list.drain(Radix()); + return; + } + // import directory. + opt.store.list(function(file){ + dir = dir || Radix(); + if(!file){ return r.list.drain(dir) } + r.list.add(file, noop); + }); + } + r.list.drain = function(rad){ + r.list.dir = dir = rad; + var tmp = dq; + dq = null; + Gun.list.map(tmp, function(cb){ + Radix.map(dir, function(val, key){ + return cb(key); + }) || cb(); + }); + } + }()); /* Let us start by assuming we are the only process that is changing the directory or bucket. Not because we do not want @@ -234,7 +288,7 @@ p.disk = Radix(); p.read = function(err, data){ var tmp; if(err){ return cb(err) } - if(!data){ return cb(u, p.disk) } + if(!data){ return cb(u, u) } var tmp = p.split(data), pre = [], i, k, v; while(tmp){ k = v = u; diff --git a/lib/rs3.js b/lib/rs3.js index aa3ed870..ac63343f 100644 --- a/lib/rs3.js +++ b/lib/rs3.js @@ -4,12 +4,11 @@ var fs = require('fs'); var Radix = Radisk.Radix; var u, AWS; -Gun.on('opt', function(ctx){ - this.to.next(ctx); - var opt = ctx.opt; - if(ctx.once){ return } +Gun.on('create', function(root){ + this.to.next(root); + var opt = root.opt; if(!process.env.AWS_S3_BUCKET){ return } - opt.batch = opt.batch || (1000 * 10); + opt.batch = opt.batch || (1000 * 1); opt.until = opt.until || (1000 * 15); opt.chunk = opt.chunk || (1024 * 1024 * 10); // 10MB diff --git a/lib/store.js b/lib/store.js index 8485b0be..18ef10ce 100644 --- a/lib/store.js +++ b/lib/store.js @@ -1,22 +1,21 @@ var Gun = (typeof window !== "undefined")? window.Gun : require('../gun'); -Gun.on('opt', function(ctx){ - this.to.next(ctx); - var opt = ctx.opt, u; +Gun.on('create', function(root){ + this.to.next(root); + var opt = root.opt, u; if(typeof window !== "undefined"){ opt.window = window; } - if(ctx.once){ return } - if(false !== opt.localStorage && !(!opt.window && process.env.AWS_S3_BUCKET)){ return } // TODO: Remove this after migration. - if(false === opt.radisk){ return } - console.log("BUG WARNING: Radix Storage Engine (RAD) has a known rare edge case, if data gets split between file chunks, a GET may only return the first chunk!!!"); + if(true !== opt.radisk && (!opt.window && !process.env.RAD_ENV && !process.env.AWS_S3_BUCKET)){ return } + //if(true !== opt.radisk){ return } + //if(false === opt.radisk){ return } var Radisk = (opt.window && opt.window.Radisk) || require('./radisk'); var Radix = Radisk.Radix; opt.store = opt.store || (!opt.window && require('./rfs')(opt)); var rad = Radisk(opt); - ctx.on('put', function(msg){ + root.on('put', function(msg){ this.to.next(msg); var id = msg['#'], track = !msg['@'], acks = track? 0 : u; // only ack non-acks. if(msg.rad && !track){ return } // don't save our own acks @@ -29,15 +28,15 @@ Gun.on('opt', function(ctx){ acks--; if(ack.err){ return } if(ack.err = err){ - ctx.on('in', {'@': id, err: err}); + root.on('in', {'@': id, err: err}); return; } if(acks){ return } - ctx.on('in', {'@': id, ok: 1}); + root.on('in', {'@': id, ok: 1}); } }); - ctx.on('get', function(msg){ + root.on('get', function(msg){ this.to.next(msg); var id = msg['#'], soul = msg.get['#'], key = msg.get['.']||'', tmp = soul+'.'+key, node; rad(tmp, function(err, val){ @@ -45,7 +44,7 @@ Gun.on('opt', function(ctx){ Radix.map(val, each); if(!node){ each(val, key) } } - ctx.on('in', {'@': id, '#': key, put: Gun.graph.node(node), err: err? err : u, rad: Radix}); + root.on('in', {'@': id, '#': key, put: Gun.graph.node(node), err: err? err : u, rad: Radix}); }); function each(val, key){ tmp = val.lastIndexOf('>'); diff --git a/test/panic/radisk.js b/test/panic/radisk.js index 0799dd28..8825798e 100644 --- a/test/panic/radisk.js +++ b/test/panic/radisk.js @@ -7,7 +7,7 @@ var config = { burst: 10, wait: 1, dir: __dirname, - chunk: 1024 * 100, + chunk: 1024 * 1024 * 10, notrad: false, route: { '/': __dirname + '/index.html', @@ -41,7 +41,7 @@ var browsers = clients.excluding(servers); var alice = browsers.pluck(1); var bob = browsers.excluding(alice).pluck(1); -describe("Make sure the Radix Storage Engine (RSE) works.", function(){ +describe("Make sure the Radix Storage Engine (RAD) works.", function(){ //this.timeout(5 * 60 * 1000); this.timeout(100 * 60 * 1000); From 0a6e4cf262a7ec6e0a6eac0addc6fa39c4a006a9 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Tue, 17 Jul 2018 15:59:21 -0700 Subject: [PATCH 075/221] cleanup --- test/panic/holy-grail.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/panic/holy-grail.js b/test/panic/holy-grail.js index 3acb4be0..846d4194 100644 --- a/test/panic/holy-grail.js +++ b/test/panic/holy-grail.js @@ -55,7 +55,7 @@ describe("The Holy Grail Test!", function(){ res.end("I am "+ env.i +"!"); }); var Gun = require('gun'); - var gun = Gun({file: env.i+'data', web: server, localStorage: false}); + var gun = Gun({file: env.i+'data', web: server}); server.listen(port, function(){ test.done(); }); @@ -181,7 +181,7 @@ describe("The Holy Grail Test!", function(){ res.end("I am "+ env.i +"!"); }); var Gun = require('gun'); - var gun = Gun({file: env.i+'data', web: server, localStorage: false}); + var gun = Gun({file: env.i+'data', web: server}); server.listen(port, function(){ test.done(); }); From d9c7b48c9719a47b86b9b4c8c74344c79fef109b Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Tue, 17 Jul 2018 16:06:44 -0700 Subject: [PATCH 076/221] radisk settings --- lib/store.js | 2 +- test/panic/radisk.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/store.js b/lib/store.js index 18ef10ce..a5d4294c 100644 --- a/lib/store.js +++ b/lib/store.js @@ -6,7 +6,7 @@ Gun.on('create', function(root){ if(typeof window !== "undefined"){ opt.window = window; } - if(true !== opt.radisk && (!opt.window && !process.env.RAD_ENV && !process.env.AWS_S3_BUCKET)){ return } + if(true !== opt.radisk && (!opt.window && !process.env.RAD_ENV && !process.env.AWS_S3_BUCKET) && false !== opt.localStorage){ return } //if(true !== opt.radisk){ return } //if(false === opt.radisk){ return } var Radisk = (opt.window && opt.window.Radisk) || require('./radisk'); diff --git a/test/panic/radisk.js b/test/panic/radisk.js index 8825798e..f825fb4b 100644 --- a/test/panic/radisk.js +++ b/test/panic/radisk.js @@ -64,7 +64,7 @@ describe("Make sure the Radix Storage Engine (RAD) works.", function(){ }); var Gun = require('gun'); //require('gun/lib/store'); - var gun = Gun({web: server, localStorage: env.config.notrad, chunk: env.config.chunk, file: 'radata'}); + var gun = Gun({web: server, localStorage: env.config.notrad, chunk: env.config.chunk, file: 'radata', radisk: true}); server.listen(port, function(){ test.done(); }); @@ -157,7 +157,7 @@ describe("Make sure the Radix Storage Engine (RAD) works.", function(){ }); var Gun = require('gun'); //require('gun/lib/store'); - var gun = Gun({web: server, localStorage: env.config.notrad, chunk: env.config.notrad, file: 'radata', lack: 1000 * 60 * 60}); + var gun = Gun({web: server, localStorage: env.config.notrad, chunk: env.config.notrad, file: 'radata', lack: 1000 * 60 * 60, radisk: true}); server.listen(port, function(){ test.done(); }); From 3488e3cb2a35820eeca6d16e09666b755e4cb330 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Tue, 17 Jul 2018 17:02:40 -0700 Subject: [PATCH 077/221] Update Procfile --- Procfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Procfile b/Procfile index a5ffa97a..875fe822 100644 --- a/Procfile +++ b/Procfile @@ -1 +1 @@ -web: node --optimize_for_size --max_old_space_size=460 --gc_interval=100 examples/http.js \ No newline at end of file +web: node --optimize_for_size --gc_interval=100 examples/http.js From 60de87da27d5d01ead66ed90916667309a2f8185 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Fri, 20 Jul 2018 22:36:44 -0700 Subject: [PATCH 078/221] almost there --- gun.min.js | 2 +- lib/radisk.js | 248 +++++++++++++++++++++--------------------- lib/radix.js | 8 +- lib/rfs.js | 34 +++++- lib/store.js | 8 +- src/ask.js | 2 +- src/put.js | 3 +- test/panic/b2s2s2b.js | 9 +- test/panic/scale.js | 1 - test/ptsd/radix.html | 38 +++++++ test/ptsd/radix.js | 73 +++++++++++++ 11 files changed, 284 insertions(+), 142 deletions(-) create mode 100644 test/ptsd/radix.html create mode 100644 test/ptsd/radix.js diff --git a/gun.min.js b/gun.min.js index 05bd4c2e..267b6d6d 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 b=(t=t||{}).console||{log:function(){}};function _(o){return 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 f=module;_(function(t){var p={fn:{is:function(t){return!!t&&"function"==typeof t}}};p.bi={is:function(t){return t instanceof Boolean||"boolean"==typeof t}},p.num={is:function(t){return!d(t)&&(0<=t-parseFloat(t)+1||1/0===t||-1/0===t)}},p.text={is:function(t){return"string"==typeof t}},p.text.ify=function(t){return p.text.is(t)?t:"undefined"!=typeof JSON?JSON.stringify(t):t&&t.toString?t.toString():t},p.text.random=function(t,n){var o="";for(t=t||24,n=n||"0123456789ABCDEFGHIJKLMNOPQRSTUVWXZabcdefghijklmnopqrstuvwxyz";0")){if(!(n>t[">"]))return!1;o=!0}if(p.obj.has(t,"<")){if(!(n",s.drift=0,s.is=function(t,n,o){var e=n&&t&&t[m]&&t[m][s._]||o;if(e)return g(e=e[n])?e:-1/0},s.lex=function(){return s().toString(36).replace(".","")},s.ify=function(t,n,o,e,i){if(!t||!t[m]){if(!i)return;t=a.soul.ify(t,i)}var r=c(t[m],s._);return void 0!==n&&n!==m&&(g(o)&&(r[n]=o),void 0!==e&&(t[n]=e)),t},s.to=function(t,n,o){var e=t[n];return p(e)&&(e=d(e)),s.ify(o,n,s.is(t,n),e,a.soul(t))},function(){function u(t,n){m!==n&&s.ify(this.o,n,this.s)}s.map=function(i,r,a){var t=p(t=i||r)?t:null;return i=v(i=i||r)?i:null,t&&!i?(r=g(r)?r:s(),t[m]=t[m]||{},h(t,u,{o:t,s:r}),t):(a=a||p(r)?r:void 0,r=g(r)?r:s(),function(t,n,o,e){if(!i)return u.call({o:o,s:r},t,n),t;i.call(a||this||{},t,n,o,e),l(o,n)&&void 0===o[n]||u.call({o:o,s:r},t,n)})}}();var f=n.obj,c=f.as,l=f.has,p=f.is,h=f.map,d=f.copy,g=n.num.is,v=n.fn.is,m=a._;t.exports=s})(_,"./state"),_(function(t){var a=_("./type"),f=_("./val"),c=_("./node"),r={};!function(){function i(t,n){if(!t||n!==c.soul(t)||!c.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&&c.is(o.n,t,o.as)}r.is=function(t,n,o,e){return!(!t||!l(t)||u(t))&&!s(t,i,{cb:n,fn:o,as:e})}}(),function(){function u(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=i,c.ify(n.obj,e,n)&&(t.graph[f.rel.is(n.rel)]=n.node),n)}function e(t,n,o){var e,i,r=this,a=r.env;if(c._===n&&h(t,f.rel._))return o._;if(e=s(t,n,o,r,a)){if(n||(r.node=r.node||o||{},h(t,c._)&&c.soul(t)&&(r.node._=d(t._)),r.node=c.soul.ify(r.node,f.rel.is(r.rel)),r.rel=r.rel||f.rel.ify(c.soul(r.node))),(i=a.map)&&(i.call(a.as||{},t,n,o,r),h(o,n))){if(void 0===(t=o[n]))return void p(o,n);if(!(e=s(t,n,o,r,a)))return}if(!n)return r.node;if(!0===e)return t;if((i=u(a,{obj:t,path:r.path.concat(n)})).node)return i.rel}}function i(t){var n=this,o=f.link.is(n.rel),e=n.env.graph;n.rel=n.rel||f.rel.ify(t),n.rel[f.rel._]=t,n.node&&n.node[c._]&&(n.node[c._][f.rel._]=t),h(e,o)&&(e[t]=e[o],p(e,o))}function s(t,n,o,e,i){var r;return!!f.is(t)||(l(t)?1:(r=i.invalid)?s(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."))))}r.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.rel=f.rel.ify(n.soul)),n.graph=n.graph||{},n.seen=n.seen||[],n.as=n.as||o,u(n,e),n.root=e.node,n.graph}}(),r.node=function(t){var n=c.soul(t);if(n)return o({},n,t)},function(){function i(t,n){var o,e;if(c._!==n)(o=f.rel.is(t))?(e=this.opt.seen[o])?this.obj[n]=e:this.obj[n]=this.opt.seen[o]=r.to(this.graph,o,this.opt):this.obj[n]=t;else{if(u(t,f.rel._))return;this.obj[n]=d(t)}}r.to=function(t,n,o){if(t){var e={};return o=o||{seen:{}},s(t[n],i,{obj:e,graph:t,opt:o}),e}}}();a.fn.is;var n=a.obj,l=n.is,p=n.del,h=n.has,u=n.empty,o=n.put,s=n.map,d=n.copy;t.exports=r})(_,"./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."}),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){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");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"),function(){function a(t){var n,o,e=this.as,i=e.at||e,r=i.$;(o=t["#"])||(o=t["#"]=u(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)))}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}}(),function(){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]||v,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||v)[n];if(!i){if(!(e.opt||v).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),h(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,h(t.put,s,t),h(o.souls,function(t){if(t)return t})||o.c||(o.c=1,this.off(),h(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)}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)});h(e.put,r,e),e.async||h(e.map,f,e),void 0!==e.defer&&setTimeout(function(){c.on.put(t,n)},e.defer-e.machine),e.diff&&o.on("put",p(t,{put:e.diff}))},c.on.get=function(t,n){var o=n._,e=t.get[d],i=o.graph[e],r=t.get[g],a=(o.next||(o.next={}))[e];if(!i||!a)return o.on("get",t);if(r){if(!l(i,r))return o.on("get",t);i=c.state.to(i,r)}else i=c.obj.copy(i);i=c.graph.node(i),a.ack,o.on("in",{"@":t["#"],how:"mem",put:i,$:n}),o.on("get",t)}}(),c.chain.opt=function(t){t=t||{};var n=this._,o=t.peers||t;return a(t)||(t={}),a(n.opt)||(n.opt=t),i(o)&&(o=[o]),e(o)&&(o=h(o,function(t,n,o){o(t,{url:t})}),a(n.opt.peers)||(n.opt.peers={}),n.opt.peers=p(o,n.opt.peers)),n.opt.peers=n.opt.peers||{},p(t,n.opt),c.on("opt",n),n.opt.uuid=n.opt.uuid||function(){return s()+u(12)},this};var e=c.list.is,o=c.text,i=o.is,u=o.random,r=c.obj,a=r.is,l=r.has,p=r.to,h=r.map,s=(r.copy,c.state.lex),d=c.val.rel._,g=".",v=(c.node._,c.val.link.is,{});b.debug=function(t,n){return b.debug.i&&t===b.debug.i&&b.debug.i++&&(b.log.apply(b,arguments)||n)},(c.log=function(){return!c.log.off&&b.log.apply(b,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=c);try{void 0!==f&&(f.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 .once, apologies unexpected."),this.once(t,n)},a.chain.once=function(t,n){var o=this,e=o._,i=e.put;if(0=(a.batch||1e3))return f();e||(e=setTimeout(f,a.wait||1))}),r.on("get",function(n){this.to.next(n);var o,e,i=n.get;function t(){if(i&&(o=i["#"])){var t=i["."];(e=s[o]||void 0)&&t&&(e=Gun.state.to(e,t)),(e||Gun.obj.empty(a.peers))&&r.on("in",{"@":n["#"],put:Gun.graph.node(e),how:"lS",lS:n.I})}}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(e),e=!1;var n=i;i={},t&&(s=t);try{c.setItem(a.file,JSON.stringify(s))}catch(t){Gun.log(o=t||"localStorage failure"),r.on("localStorage:error",{err:o,file:a.file,flush:s,retry:f})}(o||Gun.obj.empty(a.peers))&&Gun.obj.map(n,function(t,n){r.on("in",{"@":n,err:o,ok:0})})}}})}})(_,"./adapters/localStorage"),_(function(t){var d=_("../type");function o(p){var h=function(){};return h.out=function(t){var n;if(this.to&&this.to.next(t),(n=t["@"])&&(n=p.dup.s[n])&&(n=n.it)&&n.mesh)return h.say(t,n.mesh.via),void(n["##"]=t["##"]);h.say(t)},h.hear=function(t,n){if(t){var o,e,i,r=p.dup,a=t[0];try{i=JSON.parse(t)}catch(t){}if("{"===a){if(!i)return;if(r.check(o=i["#"]))return;if((a=(r.track(o,!0).it=i)["@"])&&i.put&&(a+=e=i["##"]||(i["##"]=h.hash(i)))!=o){if(r.check(a))return;(a=r.s)[e]=a[o]}return(i.mesh=function(){}).via=n,(a=i["><"])&&(i.mesh.to=d.obj.map(a.split(","),function(t,n,o){o(t,!0)})),void p.on("in",i)}if("["!==a);else{if(!i)return;for(var u,s=0;u=i[s++];)h.hear(u,n)}}},function(){function r(n,o){var t=o.wire;try{t.send?t.readyState===t.OPEN?t.send(n):(o.queue=o.queue||[]).push(n):o.say&&o.say(n)}catch(t){(o.queue=o.queue||[]).push(n)}}h.say=function(n,o){var t,e,i;o?(o.wire||p.opt.wire&&p.opt.wire(o))&&(e=n.mesh||a,o!==e.via&&((i=e.raw)||(i=h.raw(n)),(t=n["@"])&&(t=p.dup.s[t])&&(t=t.it)&&t.get&&t["##"]&&t["##"]===n["##"]||(t=e.to)&&(t[o.url]||t[o.id])||(o.batch?o.batch.push(i):(o.batch=[],setTimeout(function(){var t=o.batch;t&&(o.batch=null,t.length&&r(JSON.stringify(t),o))},p.opt.gap||p.opt.wait||1),r(i,o))))):d.obj.map(p.opt.peers,function(t){h.say(n,t)})}}(),function(){function f(t,n){var o;return n instanceof Object?(d.obj.map(Object.keys(n).sort(),e,{to:o={},on:n}),o):n}function e(t){this.to[t]=this.on[t]}h.raw=function(t){if(!t)return"";var n,o,e,i=p.dup,r=t.mesh||{};if(e=r.raw)return e;if("string"==typeof t)return t;t["@"]&&(e=t.put)&&((o=t["##"])||(n=c(e,f)||"",o=h.hash(t,n),t["##"]=o),(e=i.s)[o=t["@"]+o]=e[t["#"]],t["#"]=o||t["#"],n&&((t=d.obj.to(t)).put=l));var a=0,u=[];d.obj.map(p.opt.peers,function(t){if(u.push(t.url||t.id),9<++a)return!0}),t["><"]=u.join();var s=c(t);return g!==n&&(s=s.replace('"'+l+'"',n)),r&&(r.raw=s),s},h.hash=function(t,n){return o.hash(n||c(t.put,f)||"")||t["#"]||d.text.random(9)};var c=JSON.stringify,l=":])([:"}(),h.hi=function(n){p.on("hi",n);var t=n.queue;n.queue=[],d.obj.map(t,function(t){h.say(t,n)})},h}o.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")){if(!(n>t[">"]))return!1;o=!0}if(p.obj.has(t,"<")){if(!(n",s.drift=0,s.is=function(t,n,o){var e=n&&t&&t[m]&&t[m][s._]||o;if(e)return g(e=e[n])?e:-1/0},s.lex=function(){return s().toString(36).replace(".","")},s.ify=function(t,n,o,e,i){if(!t||!t[m]){if(!i)return;t=a.soul.ify(t,i)}var r=c(t[m],s._);return void 0!==n&&n!==m&&(g(o)&&(r[n]=o),void 0!==e&&(t[n]=e)),t},s.to=function(t,n,o){var e=t[n];return p(e)&&(e=d(e)),s.ify(o,n,s.is(t,n),e,a.soul(t))},function(){function u(t,n){m!==n&&s.ify(this.o,n,this.s)}s.map=function(i,r,a){var t=p(t=i||r)?t:null;return i=v(i=i||r)?i:null,t&&!i?(r=g(r)?r:s(),t[m]=t[m]||{},h(t,u,{o:t,s:r}),t):(a=a||p(r)?r:void 0,r=g(r)?r:s(),function(t,n,o,e){if(!i)return u.call({o:o,s:r},t,n),t;i.call(a||this||{},t,n,o,e),l(o,n)&&void 0===o[n]||u.call({o:o,s:r},t,n)})}}();var f=n.obj,c=f.as,l=f.has,p=f.is,h=f.map,d=f.copy,g=n.num.is,v=n.fn.is,m=a._;t.exports=s})(_,"./state"),_(function(t){var a=_("./type"),f=_("./val"),c=_("./node"),r={};!function(){function i(t,n){if(!t||n!==c.soul(t)||!c.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&&c.is(o.n,t,o.as)}r.is=function(t,n,o,e){return!(!t||!l(t)||u(t))&&!s(t,i,{cb:n,fn:o,as:e})}}(),function(){function u(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=i,c.ify(n.obj,e,n)&&(t.graph[f.rel.is(n.rel)]=n.node),n)}function e(t,n,o){var e,i,r=this,a=r.env;if(c._===n&&h(t,f.rel._))return o._;if(e=s(t,n,o,r,a)){if(n||(r.node=r.node||o||{},h(t,c._)&&c.soul(t)&&(r.node._=d(t._)),r.node=c.soul.ify(r.node,f.rel.is(r.rel)),r.rel=r.rel||f.rel.ify(c.soul(r.node))),(i=a.map)&&(i.call(a.as||{},t,n,o,r),h(o,n))){if(void 0===(t=o[n]))return void p(o,n);if(!(e=s(t,n,o,r,a)))return}if(!n)return r.node;if(!0===e)return t;if((i=u(a,{obj:t,path:r.path.concat(n)})).node)return i.rel}}function i(t){var n=this,o=f.link.is(n.rel),e=n.env.graph;n.rel=n.rel||f.rel.ify(t),n.rel[f.rel._]=t,n.node&&n.node[c._]&&(n.node[c._][f.rel._]=t),h(e,o)&&(e[t]=e[o],p(e,o))}function s(t,n,o,e,i){var r;return!!f.is(t)||(l(t)?1:(r=i.invalid)?s(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."))))}r.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.rel=f.rel.ify(n.soul)),n.graph=n.graph||{},n.seen=n.seen||[],n.as=n.as||o,u(n,e),n.root=e.node,n.graph}}(),r.node=function(t){var n=c.soul(t);if(n)return o({},n,t)},function(){function i(t,n){var o,e;if(c._!==n)(o=f.rel.is(t))?(e=this.opt.seen[o])?this.obj[n]=e:this.obj[n]=this.opt.seen[o]=r.to(this.graph,o,this.opt):this.obj[n]=t;else{if(u(t,f.rel._))return;this.obj[n]=d(t)}}r.to=function(t,n,o){if(t){var e={};return o=o||{seen:{}},s(t[n],i,{obj:e,graph:t,opt:o}),e}}}();a.fn.is;var n=a.obj,l=n.is,p=n.del,h=n.has,u=n.empty,o=n.put,s=n.map,d=n.copy;t.exports=r})(_,"./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){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");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"),function(){function a(t){var n,o,e=this.as,i=e.at||e,r=i.$;(o=t["#"])||(o=t["#"]=u(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)))}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}}(),function(){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]||v,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||v)[n];if(!i){if(!(e.opt||v).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),h(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,h(t.put,s,t),h(o.souls,function(t){if(t)return t})||o.c||(o.c=1,this.off(),h(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)}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)});h(e.put,r,e),e.async||h(e.map,f,e),void 0!==e.defer&&setTimeout(function(){c.on.put(t,n)},e.defer-e.machine),e.diff&&o.on("put",p(t,{put:e.diff}))},c.on.get=function(t,n){var o=n._,e=t.get[d],i=o.graph[e],r=t.get[g],a=(o.next||(o.next={}))[e];if(!i||!a)return o.on("get",t);if(r){if(!l(i,r))return o.on("get",t);i=c.state.to(i,r)}else i=c.obj.copy(i);i=c.graph.node(i),a.ack,o.on("in",{"@":t["#"],how:"mem",put:i,$:n}),o.on("get",t)}}(),c.chain.opt=function(t){t=t||{};var n=this._,o=t.peers||t;return a(t)||(t={}),a(n.opt)||(n.opt=t),i(o)&&(o=[o]),e(o)&&(o=h(o,function(t,n,o){o(t,{url:t})}),a(n.opt.peers)||(n.opt.peers={}),n.opt.peers=p(o,n.opt.peers)),n.opt.peers=n.opt.peers||{},p(t,n.opt),c.on("opt",n),n.opt.uuid=n.opt.uuid||function(){return s()+u(12)},this};var e=c.list.is,o=c.text,i=o.is,u=o.random,r=c.obj,a=r.is,l=r.has,p=r.to,h=r.map,s=(r.copy,c.state.lex),d=c.val.rel._,g=".",v=(c.node._,c.val.link.is,{});b.debug=function(t,n){return b.debug.i&&t===b.debug.i&&b.debug.i++&&(b.log.apply(b,arguments)||n)},(c.log=function(){return!c.log.off&&b.log.apply(b,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=c);try{void 0!==f&&(f.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 .once, apologies unexpected."),this.once(t,n)},a.chain.once=function(t,n){var o=this,e=o._,i=e.put;if(0=(a.batch||1e3))return f();e||(e=setTimeout(f,a.wait||1))}),r.on("get",function(n){this.to.next(n);var o,e,i=n.get;function t(){if(i&&(o=i["#"])){var t=i["."];(e=s[o]||void 0)&&t&&(e=Gun.state.to(e,t)),(e||Gun.obj.empty(a.peers))&&r.on("in",{"@":n["#"],put:Gun.graph.node(e),how:"lS",lS:n.I})}}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(e),e=!1;var n=i;i={},t&&(s=t);try{c.setItem(a.file,JSON.stringify(s))}catch(t){Gun.log(o=t||"localStorage failure"),r.on("localStorage:error",{err:o,file:a.file,flush:s,retry:f})}(o||Gun.obj.empty(a.peers))&&Gun.obj.map(n,function(t,n){r.on("in",{"@":n,err:o,ok:0})})}}})}})(_,"./adapters/localStorage"),_(function(t){var d=_("../type");function o(p){var h=function(){};return h.out=function(t){var n;if(this.to&&this.to.next(t),(n=t["@"])&&(n=p.dup.s[n])&&(n=n.it)&&n.mesh)return h.say(t,n.mesh.via),void(n["##"]=t["##"]);h.say(t)},h.hear=function(t,n){if(t){var o,e,i,r=p.dup,a=t[0];try{i=JSON.parse(t)}catch(t){}if("{"===a){if(!i)return;if(r.check(o=i["#"]))return;if((a=(r.track(o,!0).it=i)["@"])&&i.put&&(a+=e=i["##"]||(i["##"]=h.hash(i)))!=o){if(r.check(a))return;(a=r.s)[e]=a[o]}return(i.mesh=function(){}).via=n,(a=i["><"])&&(i.mesh.to=d.obj.map(a.split(","),function(t,n,o){o(t,!0)})),void p.on("in",i)}if("["!==a);else{if(!i)return;for(var u,s=0;u=i[s++];)h.hear(u,n)}}},function(){function r(n,o){var t=o.wire;try{t.send?t.readyState===t.OPEN?t.send(n):(o.queue=o.queue||[]).push(n):o.say&&o.say(n)}catch(t){(o.queue=o.queue||[]).push(n)}}h.say=function(n,o){var t,e,i;o?(o.wire||p.opt.wire&&p.opt.wire(o))&&(e=n.mesh||a,o!==e.via&&((i=e.raw)||(i=h.raw(n)),(t=n["@"])&&(t=p.dup.s[t])&&(t=t.it)&&t.get&&t["##"]&&t["##"]===n["##"]||(t=e.to)&&(t[o.url]||t[o.id])||(o.batch?o.batch.push(i):(o.batch=[],setTimeout(function(){var t=o.batch;t&&(o.batch=null,t.length&&r(JSON.stringify(t),o))},p.opt.gap||p.opt.wait||1),r(i,o))))):d.obj.map(p.opt.peers,function(t){h.say(n,t)})}}(),function(){function f(t,n){var o;return n instanceof Object?(d.obj.map(Object.keys(n).sort(),e,{to:o={},on:n}),o):n}function e(t){this.to[t]=this.on[t]}h.raw=function(t){if(!t)return"";var n,o,e,i=p.dup,r=t.mesh||{};if(e=r.raw)return e;if("string"==typeof t)return t;t["@"]&&(e=t.put)&&((o=t["##"])||(n=c(e,f)||"",o=h.hash(t,n),t["##"]=o),(e=i.s)[o=t["@"]+o]=e[t["#"]],t["#"]=o||t["#"],n&&((t=d.obj.to(t)).put=l));var a=0,u=[];d.obj.map(p.opt.peers,function(t){if(u.push(t.url||t.id),9<++a)return!0}),t["><"]=u.join();var s=c(t);return g!==n&&(s=s.replace('"'+l+'"',n)),r&&(r.raw=s),s},h.hash=function(t,n){return o.hash(n||c(t.put,f)||"")||t["#"]||d.text.random(9)};var c=JSON.stringify,l=":])([:"}(),h.hi=function(n){p.on("hi",n);var t=n.queue;n.queue=[],d.obj.map(t,function(t){h.say(t,n)})},h}o.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 1){ return } if(err){ Gun.log('err', err) } - Gun.obj.map(batch.acks, function(cb){ cb(err, ok) }); + map(batch.acks, function(cb){ cb(err, ok) }); thrash.at = null; thrash.ing = false; if(thrash.more){ thrash() } @@ -139,23 +139,23 @@ f.count = 0; f.file = file; f.each = function(val, key, k, pre){ - f.count++; + if(u !== val){ f.count++ } var enc = Radisk.encode(pre.length) +'#'+ Radisk.encode(k) + (u === val? '' : '='+ Radisk.encode(val)) +'\n'; - if((opt.chunk < f.text.length + enc.length) && !(1 >= rad.count) && !force){ + if((opt.chunk < f.text.length + enc.length) && (1 < f.count) && !force){ f.text = ''; f.limit = Math.ceil(f.count/2); f.count = 0; f.sub = Radix(); - Radix.map(rad, f.slice); + Radix.map(rad, f.slice) return true; } f.text += enc; } f.write = function(){ var tmp = ename(file); - r.list.add(tmp, function(err, ok){ + opt.store.put(tmp, f.text, function(err){ if(err){ return cb(err) } - opt.store.put(tmp, f.text, cb); + r.list.add(tmp, cb); }); } f.slice = function(val, key){ @@ -164,7 +164,7 @@ var name = f.file; f.file = key; f.count = 0; - r.write(name, f.sub, f.next); + r.write(name, f.sub, f.next, force); return true; } f.sub(key, val); @@ -173,55 +173,118 @@ if(err){ return cb(err) } f.sub = Radix(); if(!Radix.map(rad, f.slice)){ - r.write(f.file, f.sub, cb); + r.write(f.file, f.sub, cb, force); } } if(!Radix.map(rad, f.each, true)){ f.write() } } - r.read = function(key, cb, next){ - if(RAD && !next){ // cache - var val = RAD(key); - if(u !== val){ - // if a node is requested and some of it is cached... the other parts might not be. - return cb(u, val); + ;(function(){ + var Q = {}; + r.read = function(key, cb, next){ + if(RAD && !next){ // cache + var val = RAD(key); + if(u !== val){ + // if a node is requested and some of it is cached... the other parts might not be. + return cb(u, val); + } } - } - var g = function Get(){}, tmp; - g.lex = function(file){ - file = (u === file)? u : decodeURIComponent(file); - if(!file || file > (next || key)){ - if(next){ g.file = file } - if(tmp = q[g.file]){ - tmp.push({key: key, ack: cb, file: g.file}); + var g = function Get(){}, tmp; + g.lex = function(file){ + file = (u === file)? u : decodeURIComponent(file); + if(!file || file > (next || key)){ + if(next){ g.file = file } + if(tmp = Q[g.file]){ + tmp.push({key: key, ack: cb, file: g.file}); + return true; + } + Q[g.file] = [{key: key, ack: cb, file: g.file}]; + r.parse(g.file, g.it); return true; } - q[g.file] = [{key: key, ack: cb, file: g.file}]; - r.parse(g.file, g.it); - return true; + g.file = file; } - g.file = file; + g.it = function(err, disk){ + if(g.err = err){ Gun.log('err', err) } + if(disk){ RAD = g.disk = disk } + disk = Q[g.file]; delete Q[g.file]; + map(disk, g.ack); + } + g.ack = function(as){ + if(!as.ack){ return } + var tmp = as.key, rad = g.disk || noop, data = rad(tmp), last = rad.last; + if(data){ as.ack(g.err, data) } + else if(!as.file){ return as.ack(g.err, u) } + if(!last || last === tmp){ return } // is this correct? + if(last > tmp && 0 > last.indexOf(tmp)){ return } + r.read(tmp, as.ack, as.file); + } + r.list(g.lex); } - g.it = function(err, disk){ - if(g.err = err){ Gun.log('err', err) } - if(disk){ RAD = disk } - disk = q[g.file]; Gun.obj.del(q, g.file); - Gun.obj.map(disk, g.ack); - } - g.ack = function(as){ - if(!as.ack){ return } - var tmp = as.key, data = (RAD || noop)(tmp), last = (RAD||{}).last; - if(data){ as.ack(g.err, data) } - else if(!as.file){ return as.ack(g.err, u) } - if(!last || last === tmp){ return } // is this correct? - if(last > tmp && 0 > last.indexOf(tmp)){ return } - r.read(tmp, as.ack, as.file); - } - r.list(g.lex); - } + }()); ;(function(){ - var dir, dq, f = String.fromCharCode(28), ef = ename(f); + /* + Let us start by assuming we are the only process that is + changing the directory or bucket. Not because we do not want + to be multi-process/machine, but because we want to experiment + with how much performance and scale we can get out of only one. + Then we can work on the harder problem of being multi-process. + */ + var Q = {}, s = String.fromCharCode(31); + r.parse = function(file, cb){ var q; + if(q = Q[file]){ return q.push(cb) } q = Q[file] = [cb]; + var p = function Parse(){}; + p.disk = Radix(); + p.read = function(err, data){ var tmp; + delete Q[file]; + if((p.err = err) || (p.not = !data)){ + //return cb(err, u);//map(q, p.ack); + return map(q, p.ack); + } + var tmp = p.split(data), pre = [], i, k, v; + while(tmp){ + k = v = u; + i = tmp[1]; + tmp = p.split(tmp[2])||''; + if('#' == tmp[0]){ + k = tmp[1]; + pre = pre.slice(0,i); + if(i <= pre.length){ + pre.push(k); + } + } + tmp = p.split(tmp[2])||''; + if('\n' == tmp[0]){ continue } + if('=' == tmp[0]){ v = tmp[1] } + if(u !== k && u !== v){ p.disk(pre.join(''), v) } + tmp = p.split(tmp[2]); + } + //cb(err, p.disk); + map(q, p.ack); + }; + p.split = function(t){ + if(!t){ return } + var l = [], o = {}, i = -1, a = '', b, c; + i = t.indexOf(s); + if(!t[i]){ return } + a = t.slice(0, i); + l[0] = a; + l[1] = b = Radisk.decode(t.slice(i), o); + l[2] = t.slice(i + o.i); + return l; + } + p.ack = function(cb){ + if(!cb){ return } + if(p.err || p.not){ return cb(p.err, u) } + cb(u, p.disk); + } + opt.store.get(ename(file), p.read); + } + }()); + + ;(function(){ + var dir, q, f = String.fromCharCode(28), ef = ename(f); r.list = function(cb){ if(dir){ Radix.map(dir, function(val, key){ @@ -229,8 +292,7 @@ }) || cb(); return; } - if(dq){ return dq.push(cb) } - dq = [cb]; + if(q){ return q.push(cb) } q = [cb]; r.parse(f, r.list.init); } r.list.add = function(file, cb){ @@ -265,10 +327,9 @@ r.list.add(file, noop); }); } - r.list.drain = function(rad){ + r.list.drain = function(rad, tmp){ r.list.dir = dir = rad; - var tmp = dq; - dq = null; + tmp = q; q = null; Gun.list.map(tmp, function(cb){ Radix.map(dir, function(val, key){ return cb(key); @@ -276,71 +337,20 @@ }); } }()); - /* - Let us start by assuming we are the only process that is - changing the directory or bucket. Not because we do not want - to be multi-process/machine, but because we want to experiment - with how much performance and scale we can get out of only one. - Then we can work on the harder problem of being multi-process. - */ - r.parse = function(file, cb){ - var p = function Parse(){}, s = String.fromCharCode(31); - p.disk = Radix(); - p.read = function(err, data){ var tmp; - if(err){ return cb(err) } - if(!data){ return cb(u, u) } - var tmp = p.split(data), pre = [], i, k, v; - while(tmp){ - k = v = u; - i = tmp[1]; - tmp = p.split(tmp[2])||''; - if('#' == tmp[0]){ - k = tmp[1]; - pre = pre.slice(0,i); - if(i <= pre.length){ - pre.push(k); - } - } - tmp = p.split(tmp[2])||''; - if('\n' == tmp[0]){ continue } - if('=' == tmp[0]){ v = tmp[1] } - if(u !== k && u !== v){ p.disk(pre.join(''), v) } - tmp = p.split(tmp[2]); - } - cb(u, p.disk); - }; - p.split = function(t){ - if(!t){ return } - var l = [], o = {}, i = -1, a = '', b, c; - while(c = t[++i]){ - if(s === c){ break } - a += c; - } - if(!c){ return } - l[0] = a; - l[1] = b = Radisk.decode(t.slice(i), o); - l[2] = t.slice(i + o.i); - return l; - } - opt.store.get(ename(file), p.read); - } - var q = {}, noop = function(){}, RAD, u; + var noop = function(){}, RAD, u; return r; } + ;(function(){ - s = String.fromCharCode(31); - Radisk.encode = function(d, o){ + var _ = String.fromCharCode(31), u; + Radisk.encode = function(d, o, s){ s = s || _; var t = s, tmp; if(typeof d == 'string'){ - var i = -1, c; - while(c = d[++i]){ - if(s === c){ - t += s; - } - } + var i = d.indexOf(s); + while(i != -1){ t += s; i = d.indexOf(s, i+1) } return t + '"' + d + s; } else if(d && d['#'] && (tmp = Gun.val.link.is(d))){ @@ -360,24 +370,14 @@ }// else //if(binary){} } - Radisk.decode = function(t, o){ + Radisk.decode = function(t, o, s){ s = s || _; var d = '', i = -1, n = 0, c, p; if(s !== t[0]){ return } - while(c = t[++i]){ - if(p){ - if(s === c){ - if(--n <= 0){ - break; - } - } - d += c; - } else - if(s === c){ - ++n; - } else { - p = c || true; - } - } + while(s === t[++i]){ ++n } + p = t[c = n] || true; + while(--n >= 0){ i = t.indexOf(s, i+1) } + if(i == -1){ i = t.length } + d = t.slice(c+1, i); if(o){ o.i = i+1 } if('"' === p){ return d; diff --git a/lib/radix.js b/lib/radix.js index 22264e76..539aff7a 100644 --- a/lib/radix.js +++ b/lib/radix.js @@ -5,7 +5,7 @@ key = ''+key; if(!t && u !== val){ radix.last = (key < radix.last)? radix.last : key; - radix.count = (radix.count || 0) + 1; + radix.sort = null; } t = t || radix[_] || (radix[_] = {}); var i = 0, l = key.length-1, k = key[i], at, tmp; @@ -42,6 +42,7 @@ if(u === val){ return (u === (tmp = at[$]))? at[_] : tmp } at[$] = val; } else { + if(u !== val){ at.sort = null } return radix(key.slice(++i), val, at[_] || (at[_] = {})); } } @@ -49,7 +50,7 @@ }; Radix.map = function map(radix, cb, opt, pre){ pre = pre || []; - var t = radix[_] || radix, keys = Object.keys(t).sort(), i = 0, l = keys.length; + var t = radix[_] || radix, keys = radix.sort || (radix.sort = Object.keys(t).sort()), i = 0, l = keys.length; for(;i < l; i++){ var key = keys[i], tree = t[key], tmp; if(u !== (tmp = tree[$])){ tmp = cb(tmp, pre.join('') + key, key, pre); @@ -60,7 +61,8 @@ } if(tmp = tree[_]){ pre.push(key); - tmp = map(tmp, cb, opt, pre); + tmp = map(tree, cb, opt, pre); + //tmp = map(tmp, cb, opt, pre); if(u !== tmp){ return tmp } pre.pop(); } diff --git a/lib/rfs.js b/lib/rfs.js index b92293a0..24e04bb8 100644 --- a/lib/rfs.js +++ b/lib/rfs.js @@ -4,11 +4,13 @@ function Store(opt){ var Gun = require('../gun'), fs = require('fs'), u; var store = function Store(){}; + store.put = function(file, data, cb){ - var random = Math.random().toString(36).slice(-3) - fs.writeFile(opt.file+'-'+random+'.tmp', data, function(err, ok){ + var random = Math.random().toString(36).slice(-3); + var tmp = opt.file+'-'+file+'-'+random+'.tmp'; + fs.writeFile(tmp, data, function(err, ok){ if(err){ return cb(err) } - move(opt.file+'-'+random+'.tmp', opt.file+'/'+file, cb); + move(tmp, opt.file+'/'+file, cb); }); }; store.get = function(file, cb){ @@ -58,4 +60,30 @@ function Store(opt){ return store; } +function Mem(opt){ + opt = opt || {}; + opt.file = String(opt.file || 'radata'); + var storage = {}; + var Gun = require('../gun'); + var store = function Store(){}, u; + store.put = function(file, data, cb){ + setTimeout(function(){ + storage[file] = data; + cb(null, 1); + }, 1); + }; + store.get = function(file, cb){ + setTimeout(function(){ + var tmp = storage[file] || u; + cb(null, tmp); + }, 1); + }; + store.list = function(cb, match){ + setTimeout(function(){ + Gun.obj.map(Object.keys(storage), cb) || cb(); + }, 1); + }; + return store; +} + module.exports = Store; \ No newline at end of file diff --git a/lib/store.js b/lib/store.js index a5d4294c..3251e29a 100644 --- a/lib/store.js +++ b/lib/store.js @@ -13,7 +13,7 @@ Gun.on('create', function(root){ var Radix = Radisk.Radix; opt.store = opt.store || (!opt.window && require('./rfs')(opt)); - var rad = Radisk(opt); + var rad = Radisk(opt), esc = String.fromCharCode(27); root.on('put', function(msg){ this.to.next(msg); @@ -21,7 +21,7 @@ Gun.on('create', function(root){ if(msg.rad && !track){ return } // don't save our own acks Gun.graph.is(msg.put, null, function(val, key, node, soul){ if(track){ ++acks } - val = Radisk.encode(val)+'>'+Radisk.encode(Gun.state.is(node, key)); + val = Radisk.encode(val, null, esc)+'>'+Radisk.encode(Gun.state.is(node, key), null, esc); rad(soul+'.'+key, val, (track? ack : u)); }); function ack(err, ok){ @@ -48,8 +48,8 @@ Gun.on('create', function(root){ }); function each(val, key){ tmp = val.lastIndexOf('>'); - var state = Radisk.decode(val.slice(tmp+1)); - val = Radisk.decode(val.slice(0,tmp)); + var state = Radisk.decode(val.slice(tmp+1), null, esc); + val = Radisk.decode(val.slice(0,tmp), null, esc); node = Gun.state.ify(node, key, state, val, soul); } }); diff --git a/src/ask.js b/src/ask.js index abbe7540..fef9b151 100644 --- a/src/ask.js +++ b/src/ask.js @@ -15,7 +15,7 @@ module.exports = function ask(cb, as){ if(!cb){ return id } var to = this.on(id, cb, as); to.err = to.err || setTimeout(function(){ - to.next({err: "Error: No ACK received yet."}); + to.next({err: "Error: No ACK received yet.", lack: true}); to.off(); }, (this.opt||{}).lack || 9000); return id; diff --git a/src/put.js b/src/put.js index eea9e437..52c1dd2c 100644 --- a/src/put.js +++ b/src/put.js @@ -94,7 +94,8 @@ function batch(){ var as = this; as.res(function(){ var cat = (as.$.back(-1)._), ask = cat.ask(function(ack){ cat.root.on('ack', ack); - this.off(); // One response is good enough for us currently. Later we may want to adjust this. + if(ack.err){ Gun.log(ack) } + if(!ack.lack){ this.off() } // One response is good enough for us currently. Later we may want to adjust this. if(!as.ack){ return } as.ack(ack, this); }, as.opt); diff --git a/test/panic/b2s2s2b.js b/test/panic/b2s2s2b.js index 4f9b0778..03c22fea 100644 --- a/test/panic/b2s2s2b.js +++ b/test/panic/b2s2s2b.js @@ -3,9 +3,10 @@ var config = { port: 8080, servers: 2, browsers: 2, - each: 12000, - burst: 1000, + each: 100000, + burst: 2, wait: 1, + notrad: true, route: { '/': __dirname + '/index.html', '/gun.js': __dirname + '/../../gun.js', @@ -62,7 +63,7 @@ describe("Load test "+ config.browsers +" browser(s) across "+ config.servers +" } } console.log(port, " connect to ", peers); - var gun = Gun({file: env.i+'data', peers: peers, web: server, localStorage: false}); + var gun = Gun({file: env.i+'data', peers: peers, web: server, localStorage: env.config.notrad}); server.listen(port, function(){ test.done(); }); @@ -96,7 +97,7 @@ describe("Load test "+ config.browsers +" browser(s) across "+ config.servers +" }); browsers.each(function(client, id){ tests.push(client.run(function(test){ - Gun.state.drift = Math.random() * 10000; + //Gun.state.drift = Math.random() * 10000; localStorage.clear(); var env = test.props; test.async(); diff --git a/test/panic/scale.js b/test/panic/scale.js index c0c06d24..9c1a0587 100644 --- a/test/panic/scale.js +++ b/test/panic/scale.js @@ -10,7 +10,6 @@ var config = { '/': __dirname + '/index.html', '/gun.js': __dirname + '/../../gun.js', '/jquery.js': __dirname + '/../../examples/jquery.js', - '/cryptomodules.js': __dirname + '/../../lib/cryptomodules.js', '/sea.js': __dirname + '/../../sea.js' } } diff --git a/test/ptsd/radix.html b/test/ptsd/radix.html new file mode 100644 index 00000000..2a3548e2 --- /dev/null +++ b/test/ptsd/radix.html @@ -0,0 +1,38 @@ + + + PTSD + + + + +
+

PTSD

+
+

Setup code

+ + +
+
+

Test cases

+ + + + + + +
CaseResult
+ + Add test case +
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/test/ptsd/radix.js b/test/ptsd/radix.js new file mode 100644 index 00000000..81a8227d --- /dev/null +++ b/test/ptsd/radix.js @@ -0,0 +1,73 @@ +;(function(){ + // Performance Testing Stress Development + // Performance Testing Style Development + // Performance Testing Speed Development + // Performance Testing Superior Development + // Performance Testing Snippet Development + // Performance Testing Skilled Development + // Performance Testing Steady Development + // Performance Testing Stepwise Development + // Performance Testing Strong Development + // Performance Testing Specified Development + // Performance Testing Stipulated Development + // Performance Testing Systematic Development + if(!this.stool){ return } + setTimeout(function(){ + stool.run(); + },1); + stool.setup(window.setup = function(){ + window.BigText = Gun.text.random(1024, 'abcdef'); + window.MedText = Gun.text.random(200, 'abcdef'); + window.jsonText = JSON.stringify(window.BigText); + window.radText = Radisk.encode(window.BigText); + }); + stool.add('JSON encode string', function(){ + JSON.stringify(window.BigText); + }); + stool.add('RAD encode string', function(){ + Radisk.encode(window.BigText); + }); + stool.add('JSON decode string', function(){ + JSON.parse(window.jsonText); + }); + stool.add('RAD decode string', function(){ + Radisk.decode(window.radText); + }); + return; + stool.add('JSON null', function(){ + JSON.parse(JSON.stringify(null)); + }); + stool.add('RAD null', function(){ + Radisk.decode(Radisk.encode(null)); + }); + stool.add('JSON false', function(){ + JSON.parse(JSON.stringify(false)); + }); + stool.add('RAD false', function(){ + Radisk.decode(Radisk.encode(false)); + }); + stool.add('JSON true', function(){ + JSON.parse(JSON.stringify(true)); + }); + stool.add('RAD true', function(){ + Radisk.decode(Radisk.encode(true)); + }); + stool.add('JSON number', function(){ + JSON.parse(JSON.stringify(23)); + }); + stool.add('RAD number', function(){ + Radisk.decode(Radisk.encode(23)); + }); + stool.add('JSON text', function(){ + JSON.parse(JSON.stringify("hello world")); + }); + stool.add('RAD text', function(){ + Radisk.decode(Radisk.encode("hello world")); + }); + stool.add('JSON text big', function(){ + JSON.parse(JSON.stringify(window.BigText)); + }); + stool.add('RAD text big', function(){ + Radisk.decode(Radisk.encode(window.BigText)); + }); +}()); \ No newline at end of file From 6c72b1963e77c0ae0c296ceabd11383513cbda57 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Sat, 21 Jul 2018 18:49:47 -0700 Subject: [PATCH 079/221] better configured RAD test --- test/panic/radisk.js | 84 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 72 insertions(+), 12 deletions(-) diff --git a/test/panic/radisk.js b/test/panic/radisk.js index f825fb4b..c0066f53 100644 --- a/test/panic/radisk.js +++ b/test/panic/radisk.js @@ -2,10 +2,10 @@ var config = { IP: require('ip').address(), port: 8080, servers: 2, - browsers: 2, - each: 100000, - burst: 10, - wait: 1, + browsers: 3, + each: 1000000, + burst: 25, + wait: 25, dir: __dirname, chunk: 1024 * 1024 * 10, notrad: false, @@ -40,10 +40,11 @@ var spawn = servers.excluding(server).pluck(1); var browsers = clients.excluding(servers); var alice = browsers.pluck(1); var bob = browsers.excluding(alice).pluck(1); +var carl = browsers.excluding(new panic.ClientList([alice, bob])).pluck(1); describe("Make sure the Radix Storage Engine (RAD) works.", function(){ //this.timeout(5 * 60 * 1000); - this.timeout(100 * 60 * 1000); + this.timeout(5 * 60 * 60 * 1000); it("Servers have joined!", function(){ return servers.atLeast(config.servers); @@ -64,7 +65,7 @@ describe("Make sure the Radix Storage Engine (RAD) works.", function(){ }); var Gun = require('gun'); //require('gun/lib/store'); - var gun = Gun({web: server, localStorage: env.config.notrad, chunk: env.config.chunk, file: 'radata', radisk: true}); + var gun = Gun({web: server, localStorage: env.config.notrad, chunk: env.config.chunk, file: 'radata'}); server.listen(port, function(){ test.done(); }); @@ -82,7 +83,7 @@ describe("Make sure the Radix Storage Engine (RAD) works.", function(){ console.log("I AM ALICE"); localStorage.clear(); var env = test.props; - var gun = Gun({peers: 'http://'+ env.config.IP + ':' + (env.config.port + 1) + '/gun', localStorage: env.config.notrad, lack: 1000 * 60 * 60}); + var gun = Gun({peers: 'http://'+ env.config.IP + ':' + (env.config.port + 1) + '/gun', localStorage: false, lack: 1000 * 60 * 60}); window.gun = gun; var n = Gun.time.is(), i = 0, c = 0, b = env.config.burst, l = env.config.each; @@ -97,6 +98,7 @@ describe("Make sure the Radix Storage Engine (RAD) works.", function(){ ref.put({hello: raw + i}, function(ack){ if(ack.err){ if(ack.lack){ + console.log("!!!???", i); return test.fail("ACK timed out, turn your lack of ack up or thruput down."); } return test.fail(ack.err); @@ -104,17 +106,18 @@ describe("Make sure the Radix Storage Engine (RAD) works.", function(){ //console.log('ack?', ack.rad); if(d){ return } d = true; c++; - !(i % b) && console.log(i+'/'+l);//, '@'+Math.floor(b/((-n + (n = Gun.time.is()))/1000))+'/sec'); + !(i % (b * 4)) && console.log(i+'/'+l);//, '@'+Math.floor(b/((-n + (n = Gun.time.is()))/1000))+'/sec'); //localStorage.clear(); ref.off(); //console.log("gl:", Object.keys(window.gun._.graph).length); if(c < l){ return } + console.log("DONE!", c+'/'+l); setTimeout(function(){ test.done(); setTimeout(function(){ location = 'http://asdf'; }, 1500) - }, 1000); + }, 1); }); } function burst(){ @@ -157,7 +160,7 @@ describe("Make sure the Radix Storage Engine (RAD) works.", function(){ }); var Gun = require('gun'); //require('gun/lib/store'); - var gun = Gun({web: server, localStorage: env.config.notrad, chunk: env.config.notrad, file: 'radata', lack: 1000 * 60 * 60, radisk: true}); + var gun = Gun({web: server, localStorage: env.config.notrad, chunk: env.config.notrad, file: 'radata', lack: 1000 * 60 * 60}); server.listen(port, function(){ test.done(); }); @@ -165,16 +168,19 @@ describe("Make sure the Radix Storage Engine (RAD) works.", function(){ }); it("Bob read data", function(){ + this.timeout(1000 * 60 * 60 * 5); + //return alice.run(function(test){ return bob.run(function(test){ test.async(); console.log("I AM BOB"); localStorage.clear(); var env = test.props; - var gun = Gun({peers: 'http://'+ env.config.IP + ':' + (env.config.port + 2) + '/gun', localStorage: env.config.notrad}); + var gun = Gun({peers: 'http://'+ env.config.IP + ':' + (env.config.port + 2) + '/gun', localStorage: false}); window.gun = gun; - var n = Gun.time.is(), i = 0, c = 0, b = env.config.burst, l = env.config.each; + var n = Gun.time.is(), i = 0, c = 0, b = env.config.burst, l = env.config.each/2; var raw = Gun.text.random(200, 'a');// "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; + $('body').append($("
")); var $log = $('#log'); function check(i){ if(i > l){ @@ -187,10 +193,64 @@ describe("Make sure the Radix Storage Engine (RAD) works.", function(){ if(d){ return } d = true; c++; !(i % 1000) && console.log(i+'/'+l); + !(i % 1000) && $log.prepend('

'+i+'/'+l+'

'); //console.log(i+'/'+l); ref.off(); if(c < l){ return } console.log("DONE!", c+'/'+l); + $log.prepend('

DONE! '+i+'/'+l+'

'); + setTimeout(function(){ + test.done(); + setTimeout(function(){ + location = 'http://asdf'; + }, 1500) + }, 1); + }); + } + function burst(){ + if(i > l){ + return; + } + for(var j = 0; j <= b; j++){ + check(++i); + } + setTimeout(burst, env.config.wait); + } + burst(); + }, {i: 1, config: config}); + }); + + it("Carl read data", function(){ + this.timeout(1000 * 60 * 60 * 5); + //return alice.run(function(test){ + return carl.run(function(test){ + test.async(); + console.log("I AM CARL"); + localStorage.clear(); + var env = test.props; + var gun = Gun({peers: 'http://'+ env.config.IP + ':' + (env.config.port + 2) + '/gun', localStorage: false}); + window.gun = gun; + var n = Gun.time.is(), i = env.config.each / 2, c = 0, b = env.config.burst, l = env.config.each; + var raw = Gun.text.random(200, 'a');// "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; + $('body').append($("
")); var $log = $('#log'); + + function check(i){ + if(i > l){ + return; + } + var d; + var ref = window.gun.get('asdf' + i); + ref.on(function(data){ + if((raw+i) !== data.hello){ return test.fail('wrong ' + i) } + if(d){ return } d = true; + c++; + !(i % 1000) && console.log(i+'/'+l); + !(i % 1000) && $log.prepend('

'+i+'/'+l+'

'); + //console.log(i+'/'+l); + ref.off(); + if(c < (l / 2)){ return } + console.log("DONE!", c+'/'+l); + $log.prepend('

DONE! '+i+'/'+l+'

'); test.done(); }); } From 7e8d126e8c67d68fb09fccda8153d34ff7f447c3 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Sun, 22 Jul 2018 00:11:50 -0700 Subject: [PATCH 080/221] default to RAD! --- gun.js | 2 +- lib/file.js | 6 +++--- lib/radisk.js | 4 ++-- lib/rfs.js | 12 ++++++------ lib/server.js | 2 +- lib/store.js | 6 +++--- package.json | 2 +- test/common.js | 16 ++++++++++------ 8 files changed, 27 insertions(+), 23 deletions(-) diff --git a/gun.js b/gun.js index d02a6267..b56991d5 100644 --- a/gun.js +++ b/gun.js @@ -1644,7 +1644,7 @@ data = tmp.put; } if((tmp = eve.wait) && (tmp = tmp[at.id])){ clearTimeout(tmp) } - if(!to && (at.soul || at.link || (link && !(0 < link.ack)))){ + if(!to && (u === data || at.soul || at.link || (link && !(0 < link.ack)))){ tmp = (eve.wait = {})[at.id] = setTimeout(function(){ val.call({as:opt}, msg, eve, tmp || 1); }, opt.wait || 99); diff --git a/lib/file.js b/lib/file.js index 74ec7f01..4298e5d0 100644 --- a/lib/file.js +++ b/lib/file.js @@ -9,10 +9,10 @@ fs = require('fs'); Gun.on('create', function(root){ this.to.next(root); var opt = root.opt; - //if(true !== opt.localStorage){ return } + if(true !== opt.localStorage){ return } if(false === opt.localStorage){ return } - if(process.env.RAD_ENV){ return } - if(process.env.AWS_S3_BUCKET){ return } + //if(process.env.RAD_ENV){ return } + //if(process.env.AWS_S3_BUCKET){ return } opt.file = String(opt.file || 'data.json'); var graph = root.graph, acks = {}, count = 0, to; var disk = Gun.obj.ify((fs.existsSync || require('path').existsSync)(opt.file)? diff --git a/lib/radisk.js b/lib/radisk.js index 079dc2d0..7bbb43c2 100644 --- a/lib/radisk.js +++ b/lib/radisk.js @@ -215,8 +215,8 @@ var tmp = as.key, rad = g.disk || noop, data = rad(tmp), last = rad.last; if(data){ as.ack(g.err, data) } else if(!as.file){ return as.ack(g.err, u) } - if(!last || last === tmp){ return } // is this correct? - if(last > tmp && 0 > last.indexOf(tmp)){ return } + if(!last || last === tmp){ return as.ack(g.err, u) } // is this correct? + if(last > tmp && 0 > last.indexOf(tmp)){ return as.ack(g.err, u) } r.read(tmp, as.ack, as.file); } r.list(g.lex); diff --git a/lib/rfs.js b/lib/rfs.js index 24e04bb8..b86aa3a8 100644 --- a/lib/rfs.js +++ b/lib/rfs.js @@ -1,8 +1,9 @@ +var Gun = (typeof window !== "undefined")? window.Gun : require('../gun'); + function Store(opt){ opt = opt || {}; opt.file = String(opt.file || 'radata'); - - var Gun = require('../gun'), fs = require('fs'), u; + var fs = require('fs'), u; var store = function Store(){}; store.put = function(file, data, cb){ @@ -63,11 +64,10 @@ function Store(opt){ function Mem(opt){ opt = opt || {}; opt.file = String(opt.file || 'radata'); - var storage = {}; - var Gun = require('../gun'); + var storage = Mem.storage || (Mem.storage = {}); var store = function Store(){}, u; store.put = function(file, data, cb){ - setTimeout(function(){ + setTimeout(function(){ storage[file] = data; cb(null, 1); }, 1); @@ -86,4 +86,4 @@ function Mem(opt){ return store; } -module.exports = Store; \ No newline at end of file +module.exports = Store;//Gun.TESTING? Mem : Store; \ No newline at end of file diff --git a/lib/server.js b/lib/server.js index a209f099..a893322e 100644 --- a/lib/server.js +++ b/lib/server.js @@ -1,7 +1,7 @@ ;(function(){ var Gun = require('../gun'), u; Gun.serve = require('./serve'); - process.env.GUN_ENV = process.env.GUN_ENV || 'debug'; + //process.env.GUN_ENV = process.env.GUN_ENV || 'debug'; Gun.on('opt', function(root){ this.to.next(root); if(root.once){ return } diff --git a/lib/store.js b/lib/store.js index 3251e29a..a3ea547a 100644 --- a/lib/store.js +++ b/lib/store.js @@ -6,9 +6,9 @@ Gun.on('create', function(root){ if(typeof window !== "undefined"){ opt.window = window; } - if(true !== opt.radisk && (!opt.window && !process.env.RAD_ENV && !process.env.AWS_S3_BUCKET) && false !== opt.localStorage){ return } + //if(true !== opt.radisk && (!opt.window && !process.env.RAD_ENV && !process.env.AWS_S3_BUCKET) && false !== opt.localStorage){ return } //if(true !== opt.radisk){ return } - //if(false === opt.radisk){ return } + if(false === opt.radisk){ return } var Radisk = (opt.window && opt.window.Radisk) || require('./radisk'); var Radix = Radisk.Radix; @@ -44,7 +44,7 @@ Gun.on('create', function(root){ Radix.map(val, each); if(!node){ each(val, key) } } - root.on('in', {'@': id, '#': key, put: Gun.graph.node(node), err: err? err : u, rad: Radix}); + root.on('in', {'@': id, put: Gun.graph.node(node), err: err? err : u, rad: Radix}); }); function each(val, key){ tmp = val.lastIndexOf('>'); diff --git a/package.json b/package.json index 9b5267bc..3b23c305 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gun", - "version": "0.9.9995", + "version": "0.9.9996", "description": "A realtime, decentralized, offline-first, graph data synchronization engine.", "main": "index.js", "browser": "gun.min.js", diff --git a/test/common.js b/test/common.js index f563fe18..49a3a491 100644 --- a/test/common.js +++ b/test/common.js @@ -11,13 +11,14 @@ describe('Gun', function(){ //root.Gun = root.Gun || require('../gun'); if(root.Gun){ root.Gun = root.Gun; + root.Gun.TESTING = true; } else { root.Gun = require('../gun'); + root.Gun.TESTING = true; Gun.serve = require('../lib/serve'); - //require('./s3'); - //require('./uws'); - //require('./wsp/server'); - require('../lib/file'); + //require('../lib/file'); + require('../lib/store'); + require('../lib/rfs'); } }(this)); //Gun.log.squelch = true; @@ -2892,7 +2893,7 @@ describe('Gun', function(){ var gun = Gun().get('chat/asdf'); var check = {}, count = {}; - gun.map().val(function(v,f){ + gun.map().once(function(v,f){ check[f] = v; count[f] = (count[f] || 0) + 1; //console.log("**************", f, v); @@ -2993,6 +2994,7 @@ describe('Gun', function(){ it('get get get set root get put', function(done){ var gun = Gun().get('app'); + //console.debug.i=1;console.log('---------------'); gun.get('alias').get('mark').set( gun.back(-1).get('pub').put({ alias: 'mark', @@ -3004,7 +3006,9 @@ describe('Gun', function(){ ); //return; setTimeout(function(){ + //console.debug.i=1;console.log('---------------'); gun.get(function(at){ + //console.log("*", at.put);//return; done.app = done.app || at.put.alias; }); gun.back(-1).get('pub').get(function(at){ @@ -3016,7 +3020,7 @@ describe('Gun', function(){ done.alias = done.alias || at.put.mark; //!console.debug.i&&(console.debug.i=1)&&console.log("---------------------"); }).get('mark').on(function(data){ - //console.log("************", at.put);//return; + //console.log("************", data);//return; clearTimeout(done.to); done.to = setTimeout(function(){ done.mark = done.mark || data.pub; From 4af5aa4709ae5eef0bf6883850b8a5063685b1ac Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Sun, 22 Jul 2018 00:12:33 -0700 Subject: [PATCH 081/221] unbuild making RAD default! --- gun.min.js | 2 +- src/on.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gun.min.js b/gun.min.js index 267b6d6d..ea97da58 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 b=(t=t||{}).console||{log:function(){}};function _(o){return 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 f=module;_(function(t){var p={fn:{is:function(t){return!!t&&"function"==typeof t}}};p.bi={is:function(t){return t instanceof Boolean||"boolean"==typeof t}},p.num={is:function(t){return!d(t)&&(0<=t-parseFloat(t)+1||1/0===t||-1/0===t)}},p.text={is:function(t){return"string"==typeof t}},p.text.ify=function(t){return p.text.is(t)?t:"undefined"!=typeof JSON?JSON.stringify(t):t&&t.toString?t.toString():t},p.text.random=function(t,n){var o="";for(t=t||24,n=n||"0123456789ABCDEFGHIJKLMNOPQRSTUVWXZabcdefghijklmnopqrstuvwxyz";0")){if(!(n>t[">"]))return!1;o=!0}if(p.obj.has(t,"<")){if(!(n",s.drift=0,s.is=function(t,n,o){var e=n&&t&&t[m]&&t[m][s._]||o;if(e)return g(e=e[n])?e:-1/0},s.lex=function(){return s().toString(36).replace(".","")},s.ify=function(t,n,o,e,i){if(!t||!t[m]){if(!i)return;t=a.soul.ify(t,i)}var r=c(t[m],s._);return void 0!==n&&n!==m&&(g(o)&&(r[n]=o),void 0!==e&&(t[n]=e)),t},s.to=function(t,n,o){var e=t[n];return p(e)&&(e=d(e)),s.ify(o,n,s.is(t,n),e,a.soul(t))},function(){function u(t,n){m!==n&&s.ify(this.o,n,this.s)}s.map=function(i,r,a){var t=p(t=i||r)?t:null;return i=v(i=i||r)?i:null,t&&!i?(r=g(r)?r:s(),t[m]=t[m]||{},h(t,u,{o:t,s:r}),t):(a=a||p(r)?r:void 0,r=g(r)?r:s(),function(t,n,o,e){if(!i)return u.call({o:o,s:r},t,n),t;i.call(a||this||{},t,n,o,e),l(o,n)&&void 0===o[n]||u.call({o:o,s:r},t,n)})}}();var f=n.obj,c=f.as,l=f.has,p=f.is,h=f.map,d=f.copy,g=n.num.is,v=n.fn.is,m=a._;t.exports=s})(_,"./state"),_(function(t){var a=_("./type"),f=_("./val"),c=_("./node"),r={};!function(){function i(t,n){if(!t||n!==c.soul(t)||!c.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&&c.is(o.n,t,o.as)}r.is=function(t,n,o,e){return!(!t||!l(t)||u(t))&&!s(t,i,{cb:n,fn:o,as:e})}}(),function(){function u(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=i,c.ify(n.obj,e,n)&&(t.graph[f.rel.is(n.rel)]=n.node),n)}function e(t,n,o){var e,i,r=this,a=r.env;if(c._===n&&h(t,f.rel._))return o._;if(e=s(t,n,o,r,a)){if(n||(r.node=r.node||o||{},h(t,c._)&&c.soul(t)&&(r.node._=d(t._)),r.node=c.soul.ify(r.node,f.rel.is(r.rel)),r.rel=r.rel||f.rel.ify(c.soul(r.node))),(i=a.map)&&(i.call(a.as||{},t,n,o,r),h(o,n))){if(void 0===(t=o[n]))return void p(o,n);if(!(e=s(t,n,o,r,a)))return}if(!n)return r.node;if(!0===e)return t;if((i=u(a,{obj:t,path:r.path.concat(n)})).node)return i.rel}}function i(t){var n=this,o=f.link.is(n.rel),e=n.env.graph;n.rel=n.rel||f.rel.ify(t),n.rel[f.rel._]=t,n.node&&n.node[c._]&&(n.node[c._][f.rel._]=t),h(e,o)&&(e[t]=e[o],p(e,o))}function s(t,n,o,e,i){var r;return!!f.is(t)||(l(t)?1:(r=i.invalid)?s(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."))))}r.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.rel=f.rel.ify(n.soul)),n.graph=n.graph||{},n.seen=n.seen||[],n.as=n.as||o,u(n,e),n.root=e.node,n.graph}}(),r.node=function(t){var n=c.soul(t);if(n)return o({},n,t)},function(){function i(t,n){var o,e;if(c._!==n)(o=f.rel.is(t))?(e=this.opt.seen[o])?this.obj[n]=e:this.obj[n]=this.opt.seen[o]=r.to(this.graph,o,this.opt):this.obj[n]=t;else{if(u(t,f.rel._))return;this.obj[n]=d(t)}}r.to=function(t,n,o){if(t){var e={};return o=o||{seen:{}},s(t[n],i,{obj:e,graph:t,opt:o}),e}}}();a.fn.is;var n=a.obj,l=n.is,p=n.del,h=n.has,u=n.empty,o=n.put,s=n.map,d=n.copy;t.exports=r})(_,"./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){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");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"),function(){function a(t){var n,o,e=this.as,i=e.at||e,r=i.$;(o=t["#"])||(o=t["#"]=u(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)))}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}}(),function(){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]||v,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||v)[n];if(!i){if(!(e.opt||v).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),h(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,h(t.put,s,t),h(o.souls,function(t){if(t)return t})||o.c||(o.c=1,this.off(),h(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)}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)});h(e.put,r,e),e.async||h(e.map,f,e),void 0!==e.defer&&setTimeout(function(){c.on.put(t,n)},e.defer-e.machine),e.diff&&o.on("put",p(t,{put:e.diff}))},c.on.get=function(t,n){var o=n._,e=t.get[d],i=o.graph[e],r=t.get[g],a=(o.next||(o.next={}))[e];if(!i||!a)return o.on("get",t);if(r){if(!l(i,r))return o.on("get",t);i=c.state.to(i,r)}else i=c.obj.copy(i);i=c.graph.node(i),a.ack,o.on("in",{"@":t["#"],how:"mem",put:i,$:n}),o.on("get",t)}}(),c.chain.opt=function(t){t=t||{};var n=this._,o=t.peers||t;return a(t)||(t={}),a(n.opt)||(n.opt=t),i(o)&&(o=[o]),e(o)&&(o=h(o,function(t,n,o){o(t,{url:t})}),a(n.opt.peers)||(n.opt.peers={}),n.opt.peers=p(o,n.opt.peers)),n.opt.peers=n.opt.peers||{},p(t,n.opt),c.on("opt",n),n.opt.uuid=n.opt.uuid||function(){return s()+u(12)},this};var e=c.list.is,o=c.text,i=o.is,u=o.random,r=c.obj,a=r.is,l=r.has,p=r.to,h=r.map,s=(r.copy,c.state.lex),d=c.val.rel._,g=".",v=(c.node._,c.val.link.is,{});b.debug=function(t,n){return b.debug.i&&t===b.debug.i&&b.debug.i++&&(b.log.apply(b,arguments)||n)},(c.log=function(){return!c.log.off&&b.log.apply(b,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=c);try{void 0!==f&&(f.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 .once, apologies unexpected."),this.once(t,n)},a.chain.once=function(t,n){var o=this,e=o._,i=e.put;if(0=(a.batch||1e3))return f();e||(e=setTimeout(f,a.wait||1))}),r.on("get",function(n){this.to.next(n);var o,e,i=n.get;function t(){if(i&&(o=i["#"])){var t=i["."];(e=s[o]||void 0)&&t&&(e=Gun.state.to(e,t)),(e||Gun.obj.empty(a.peers))&&r.on("in",{"@":n["#"],put:Gun.graph.node(e),how:"lS",lS:n.I})}}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(e),e=!1;var n=i;i={},t&&(s=t);try{c.setItem(a.file,JSON.stringify(s))}catch(t){Gun.log(o=t||"localStorage failure"),r.on("localStorage:error",{err:o,file:a.file,flush:s,retry:f})}(o||Gun.obj.empty(a.peers))&&Gun.obj.map(n,function(t,n){r.on("in",{"@":n,err:o,ok:0})})}}})}})(_,"./adapters/localStorage"),_(function(t){var d=_("../type");function o(p){var h=function(){};return h.out=function(t){var n;if(this.to&&this.to.next(t),(n=t["@"])&&(n=p.dup.s[n])&&(n=n.it)&&n.mesh)return h.say(t,n.mesh.via),void(n["##"]=t["##"]);h.say(t)},h.hear=function(t,n){if(t){var o,e,i,r=p.dup,a=t[0];try{i=JSON.parse(t)}catch(t){}if("{"===a){if(!i)return;if(r.check(o=i["#"]))return;if((a=(r.track(o,!0).it=i)["@"])&&i.put&&(a+=e=i["##"]||(i["##"]=h.hash(i)))!=o){if(r.check(a))return;(a=r.s)[e]=a[o]}return(i.mesh=function(){}).via=n,(a=i["><"])&&(i.mesh.to=d.obj.map(a.split(","),function(t,n,o){o(t,!0)})),void p.on("in",i)}if("["!==a);else{if(!i)return;for(var u,s=0;u=i[s++];)h.hear(u,n)}}},function(){function r(n,o){var t=o.wire;try{t.send?t.readyState===t.OPEN?t.send(n):(o.queue=o.queue||[]).push(n):o.say&&o.say(n)}catch(t){(o.queue=o.queue||[]).push(n)}}h.say=function(n,o){var t,e,i;o?(o.wire||p.opt.wire&&p.opt.wire(o))&&(e=n.mesh||a,o!==e.via&&((i=e.raw)||(i=h.raw(n)),(t=n["@"])&&(t=p.dup.s[t])&&(t=t.it)&&t.get&&t["##"]&&t["##"]===n["##"]||(t=e.to)&&(t[o.url]||t[o.id])||(o.batch?o.batch.push(i):(o.batch=[],setTimeout(function(){var t=o.batch;t&&(o.batch=null,t.length&&r(JSON.stringify(t),o))},p.opt.gap||p.opt.wait||1),r(i,o))))):d.obj.map(p.opt.peers,function(t){h.say(n,t)})}}(),function(){function f(t,n){var o;return n instanceof Object?(d.obj.map(Object.keys(n).sort(),e,{to:o={},on:n}),o):n}function e(t){this.to[t]=this.on[t]}h.raw=function(t){if(!t)return"";var n,o,e,i=p.dup,r=t.mesh||{};if(e=r.raw)return e;if("string"==typeof t)return t;t["@"]&&(e=t.put)&&((o=t["##"])||(n=c(e,f)||"",o=h.hash(t,n),t["##"]=o),(e=i.s)[o=t["@"]+o]=e[t["#"]],t["#"]=o||t["#"],n&&((t=d.obj.to(t)).put=l));var a=0,u=[];d.obj.map(p.opt.peers,function(t){if(u.push(t.url||t.id),9<++a)return!0}),t["><"]=u.join();var s=c(t);return g!==n&&(s=s.replace('"'+l+'"',n)),r&&(r.raw=s),s},h.hash=function(t,n){return o.hash(n||c(t.put,f)||"")||t["#"]||d.text.random(9)};var c=JSON.stringify,l=":])([:"}(),h.hi=function(n){p.on("hi",n);var t=n.queue;n.queue=[],d.obj.map(t,function(t){h.say(t,n)})},h}o.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=0||1/0===t||-(1/0)===t)}},n.text={is:function(t){return"string"==typeof t}},n.text.ify=function(t){return n.text.is(t)?t:"undefined"!=typeof JSON?JSON.stringify(t):t&&t.toString?t.toString():t},n.text.random=function(t,n){var o="";for(t=t||24,n=n||"0123456789ABCDEFGHIJKLMNOPQRSTUVWXZabcdefghijklmnopqrstuvwxyz";t>0;)o+=n.charAt(Math.floor(Math.random()*n.length)),t--;return o},n.text.match=function(t,o){function e(t,n){for(var o,e=-1,i=0;o=n[i++];)if(!~(e=t.indexOf(o,e+1)))return!1;return!0}var i=!1;if(t=t||"",o=n.text.is(o)?{"=":o}:o||{},n.obj.has(o,"~")&&(t=t.toLowerCase(),o["="]=(o["="]||o["~"]).toLowerCase()),n.obj.has(o,"="))return t===o["="];if(n.obj.has(o,"*")){if(t.slice(0,o["*"].length)!==o["*"])return!1;i=!0,t=t.slice(o["*"].length)}if(n.obj.has(o,"!")){if(t.slice(-o["!"].length)!==o["!"])return!1;i=!0}if(n.obj.has(o,"+")&&n.list.map(n.list.is(o["+"])?o["+"]:[o["+"]],function(n){return t.indexOf(n)>=0?void(i=!0):!0}))return!1;if(n.obj.has(o,"-")&&n.list.map(n.list.is(o["-"])?o["-"]:[o["-"]],function(n){return t.indexOf(n)<0?void(i=!0):!0}))return!1;if(n.obj.has(o,">")){if(!(t>o[">"]))return!1;i=!0}if(n.obj.has(o,"<")){if(!(tn?-1:n>o?1:0):0}},n.list.map=function(t,n,o){return a(t,n,o)},n.list.index=1,n.obj={is:function(t){return t?t instanceof Object&&t.constructor===Object||"Object"===Object.prototype.toString.call(t).match(/^\[object (\w+)\]$/)[1]:!1}},n.obj.put=function(t,n,o){return(t||{})[n]=o,t},n.obj.has=function(t,n){return t&&Object.prototype.hasOwnProperty.call(t,n)},n.obj.del=function(t,n){return t?(t[n]=null,delete t[n],t):void 0},n.obj.as=function(t,n,o,e){return t[n]=t[n]||(e===o?{}:o)},n.obj.ify=function(t){if(r(t))return t;try{t=JSON.parse(t)}catch(n){t={}}return t},function(){function t(t,n){u(this,n)&&o!==this[n]||(this[n]=t)}var o;n.obj.to=function(n,o){return o=o||{},a(n,t,o),o}}(),n.obj.copy=function(t){return t?JSON.parse(JSON.stringify(t)):t},function(){function t(t,n){var o=this.n;if(!o||!(n===o||r(o)&&u(o,n)))return n?!0:void 0}n.obj.empty=function(n,o){return n&&a(n,t,{n:o})?!1:!0}}(),function(){function t(n,o){return 2===arguments.length?(t.r=t.r||{},void(t.r[n]=o)):(t.r=t.r||[],void t.r.push(n))}var i=Object.keys;n.obj.map=function(a,s,f){var c,l,p,h,d,v=0,g=o(s);if(t.r=null,i&&r(a)&&(h=i(a),d=!0),e(a)||h)for(l=(h||a).length;l>v;v++){var m=v+n.list.index;if(g){if(p=d?s.call(f||this,a[h[v]],h[v],t):s.call(f||this,a[v],m,t),p!==c)return p}else if(s===a[d?h[v]:v])return h?h[v]:m}else for(v in a)if(g){if(u(a,v)&&(p=f?s.call(f,a[v],v,t):s(a[v],v,t),p!==c))return p}else if(s===a[v])return v;return g?t.r:n.list.index?0:-1}}(),n.time={},n.time.is=function(t){return t?t instanceof Date:+(new Date).getTime()};var o=n.fn.is,e=n.list.is,i=n.obj,r=i.is,u=i.has,a=i.map;t.exports=n})(t,"./type"),t(function(t){t.exports=function n(t,o,e){if(!t)return{to:n};var i,t=(this.tag||(this.tag={}))[t]||(this.tag[t]={tag:t,to:n._={next:function(t){var n;(n=this.to)&&n.next(t)}}});if(o instanceof Function){var r={off:n.off||(n.off=function(){return this.next===n._.next?!0:(this===this.the.last&&(this.the.last=this.back),this.to.back=this.back,this.next=n._.next,this.back.to=this.to,void(this.the.last===this.the&&delete this.on.tag[this.the.tag]))}),to:n._,next:o,the:t,on:this,as:e};return(r.back=t.last||t).to=r,t.last=r}return(t=t.to)&&i!==o&&t.next(o),t}})(t,"./onto"),t(function(t){function n(t,n,e,i,r){if(n>t)return{defer:!0};if(e>n)return{historical:!0};if(n>e)return{converge:!0,incoming:!0};if(n===e){if(i=o(i)||"",r=o(r)||"",i===r)return{state:!0};if(r>i)return{converge:!0,current:!0};if(i>r)return{converge:!0,incoming:!0}}return{err:"Invalid CRDT Data: "+i+" to "+r+" at "+n+" to "+e+"!"}}if("undefined"==typeof JSON)throw new Error("JSON is not included in this browser. Please load it first: ajax.cdnjs.com/ajax/libs/json2/20110223/json2.js");var o=JSON.stringify;t.exports=n})(t,"./HAM"),t(function(n){var o=t("./type"),e={};e.is=function(t){return t===i?!1:null===t?!0:t===1/0?!1:s(t)||u(t)||a(t)?!0:e.rel.is(t)||!1},e.link=e.rel={_:"#"},function(){function t(t,n){var o=this;return o.id?o.id=!1:n==r&&s(t)?void(o.id=t):o.id=!1}e.rel.is=function(n){if(n&&n[r]&&!n._&&c(n)){var o={};if(p(n,t,o),o.id)return o.id}return!1}}(),e.rel.ify=function(t){return l({},r,t)},o.obj.has._=".";var i,r=e.link._,u=o.bi.is,a=o.num.is,s=o.text.is,f=o.obj,c=f.is,l=f.put,p=f.map;n.exports=e})(t,"./val"),t(function(n){var o=t("./type"),e=t("./val"),i={_:"_"};i.soul=function(t,n){return t&&t._&&t._[n||p]},i.soul.ify=function(t,n){return n="string"==typeof n?{soul:n}:n||{},t=t||{},t._=t._||{},t._[p]=n.soul||t._[p]||l(),t},i.soul._=e.link._,function(){function t(t,n){return n!==i._?e.is(t)?void(this.cb&&this.cb.call(this.as,t,n,this.n,this.s)):!0:void 0}i.is=function(n,o,e){var r;return a(n)&&(r=i.soul(n))?!f(n,t,{as:e,cb:o,s:r,n:n}):!1}}(),function(){function t(t,n){var o,i,r=this.o;return r.map?(o=r.map.call(this.as,t,""+n,r.node),void(i===o?s(r.node,n):r.node&&(r.node[n]=o))):void(e.is(t)&&(r.node[n]=t))}i.ify=function(n,o,e){return o?"string"==typeof o?o={soul:o}:o instanceof Function&&(o={map:o}):o={},o.map&&(o.node=o.map.call(e,n,r,o.node||{})),(o.node=i.soul.ify(o.node||{},o))&&f(n,t,{o:o,as:e}),o.node}}();var r,u=o.obj,a=u.is,s=u.del,f=u.map,c=o.text,l=c.random,p=i.soul._;n.exports=i})(t,"./node"),t(function(n){function o(){var t;return t=r(),t>u?(a=0,u=t+o.drift):u=t+(a+=1)/s+o.drift}{var e=t("./type"),i=t("./node"),r=e.time.is,u=-(1/0),a=0,s=1e3,f="undefined"!=typeof performance?performance.timing&&performance:!1;f&&f.timing&&f.timing.navigationStart||(f=!1)}o._=">",o.drift=0,o.is=function(t,n,e){var i=n&&t&&t[_]&&t[_][o._]||e;if(i)return b(i=i[n])?i:-(1/0)},o.lex=function(){return o().toString(36).replace(".","")},o.ify=function(t,n,e,r,u){if(!t||!t[_]){if(!u)return;t=i.soul.ify(t,u)}var a=p(t[_],o._);return c!==n&&n!==_&&(b(e)&&(a[n]=e),c!==r&&(t[n]=r)),t},o.to=function(t,n,e){var r=t[n];return d(r)&&(r=g(r)),o.ify(e,n,o.is(t,n),r,i.soul(t))},function(){function t(t,n){_!==n&&o.ify(this.o,n,this.s)}o.map=function(n,e,i){var r,u=d(u=n||e)?u:null;return n=y(n=n||e)?n:null,u&&!n?(e=b(e)?e:o(),u[_]=u[_]||{},v(u,t,{o:u,s:e}),u):(i=i||d(e)?e:r,e=b(e)?e:o(),function(o,u,a,s){return n?(n.call(i||this||{},o,u,a,s),void(h(a,u)&&r===a[u]||t.call({o:a,s:e},o,u))):(t.call({o:a,s:e},o,u),o)})}}();var c,l=e.obj,p=l.as,h=l.has,d=l.is,v=l.map,g=l.copy,m=e.num,b=m.is,k=e.fn,y=k.is,_=i._;n.exports=o})(t,"./state"),t(function(n){var o=t("./type"),e=t("./val"),i=t("./node"),r={};!function(){function t(t,o){return t&&o===i.soul(t)&&i.is(t,this.fn,this.as)?void(this.cb&&(n.n=t,n.as=this.as,this.cb.call(n.as,t,o,n))):!0}function n(t){t&&i.is(n.n,t,n.as)}r.is=function(n,o,e,i){return n&&s(n)&&!l(n)?!h(n,t,{cb:o,fn:e,as:i}):!1}}(),function(){function t(t,o){var r;return(r=p(t,o))?r:(o.env=t,o.soul=a,i.ify(o.obj,n,o)&&(t.graph[e.rel.is(o.rel)]=o.node),o)}function n(n,o,r){var a,s,p=this,h=p.env;if(i._===o&&c(n,e.rel._))return r._;if(a=l(n,o,r,p,h)){if(o||(p.node=p.node||r||{},c(n,i._)&&i.soul(n)&&(p.node._=d(n._)),p.node=i.soul.ify(p.node,e.rel.is(p.rel)),p.rel=p.rel||e.rel.ify(i.soul(p.node))),(s=h.map)&&(s.call(h.as||{},n,o,r,p),c(r,o))){if(n=r[o],u===n)return void f(r,o);if(!(a=l(n,o,r,p,h)))return}if(!o)return p.node;if(!0===a)return n;if(s=t(h,{obj:n,path:p.path.concat(o)}),s.node)return s.rel}}function a(t){var n=this,o=e.link.is(n.rel),r=n.env.graph;n.rel=n.rel||e.rel.ify(t),n.rel[e.rel._]=t,n.node&&n.node[i._]&&(n.node[i._][e.rel._]=t),c(r,o)&&(r[t]=r[o],f(r,o))}function l(t,n,i,r,u){var a;return e.is(t)?!0:s(t)?1:(a=u.invalid)?(t=a.call(u.as||{},t,n,i),l(t,n,i,r,u)):(u.err="Invalid value at '"+r.path.concat(n).join(".")+"'!",void(o.list.is(t)&&(u.err+=" Use `.set(item)` instead of an Array.")))}function p(t,n){for(var o,e=t.seen,i=e.length;i--;)if(o=e[i],n.obj===o.obj)return o;e.push(n)}r.ify=function(n,o,i){var r={path:[],obj:n};return o?"string"==typeof o?o={soul:o}:o instanceof Function&&(o.map=o):o={},o.soul&&(r.rel=e.rel.ify(o.soul)),o.graph=o.graph||{},o.seen=o.seen||[],o.as=o.as||i,t(o,r),o.root=r.node,o.graph}}(),r.node=function(t){var n=i.soul(t);if(n)return p({},n,t)},function(){function t(t,n){var o,u;if(i._===n){if(l(t,e.rel._))return;return void(this.obj[n]=d(t))}return(o=e.rel.is(t))?(u=this.opt.seen[o])?void(this.obj[n]=u):void(this.obj[n]=this.opt.seen[o]=r.to(this.graph,o,this.opt)):void(this.obj[n]=t)}r.to=function(n,o,e){if(n){var i={};return e=e||{seen:{}},h(n[o],t,{obj:i,graph:n,opt:e}),i}}}();var u,a=(o.fn.is,o.obj),s=a.is,f=a.del,c=a.has,l=a.empty,p=a.put,h=a.map,d=a.copy;n.exports=r})(t,"./graph"),t(function(n){t("./onto"),n.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}var 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}}})(t,"./ask"),t(function(n){function o(t){var n={s:{}};return t=t||{max:1e3,age:9e3},n.check=function(t){var o;return(o=n.s[t])?o.pass?o.pass=!1:n.track(t):!1},n.track=function(o,r){var u=n.s[o]||(n.s[o]={});return u.was=i(),r&&(u.pass=!0),n.to||(n.to=setTimeout(function(){var o=i();e.obj.map(n.s,function(i,r){t.age>o-i.was||e.obj.del(n.s,r)}),n.to=null},t.age+9)),u},n}var e=t("./type"),i=e.time.is;n.exports=o})(t,"./dup"),t(function(n){function i(t){return t instanceof i?(this._={gun:this,$:this}).$:this instanceof i?i.create(this._={gun:this,$:this,opt:t}):new i(t)}i.is=function(t){return t instanceof i||t&&t._&&t===t._.$||!1},i.version=.9,i.chain=i.prototype,i.chain.toJSON=function(){};var r=t("./type");r.obj.to(r,i),i.HAM=t("./HAM"),i.val=t("./val"),i.node=t("./node"),i.state=t("./state"),i.graph=t("./graph"),i.on=t("./onto"),i.ask=t("./ask"),i.dup=t("./dup"),function(){function t(n){var o,e,r=this,a=r.as,s=a.at||a,f=s.$;return(e=n["#"])||(e=n["#"]=c(9)),(o=s.dup).check(e)?void(a.out===n.out&&(n.out=u,r.to.next(n))):(o.track(e),s.ask(n["@"],n)||(n.get&&i.on.get(n,f),n.put&&i.on.put(n,f)),r.to.next(n),void(a.out||(n.out=t,s.on("out",n))))}i.create=function(n){n.root=n.root||n,n.graph=n.graph||{},n.on=n.on||i.on,n.ask=n.ask||i.ask,n.dup=n.dup||i.dup();var o=n.$.opt(n.opt);return n.once||(n.on("in",t,n),n.on("out",t,{at:n,out:t}),i.on("create",n),n.on("create",n)),n.once=1,o}}(),function(){function t(t,n,o,e){var r=this,u=i.state.is(o,n);if(!u)return r.err="Error: No state on '"+n+"' in node '"+e+"'!";var a=r.graph[e]||k,s=i.state.is(a,n,!0),f=a[n],c=i.HAM(r.machine,u,s,t,f);return c.incoming?(r.put[e]=i.state.to(o,n,r.put[e]),(r.diff||(r.diff={}))[e]=i.state.to(o,n,r.diff[e]),void(r.souls[e]=!0)):void(c.defer&&(r.defer=u<(r.defer||1/0)?u:r.defer))}function n(t,n){var i=this,u=i.$._,a=(u.next||k)[n];if(!a){if(!(u.opt||k)["super"])return void(i.souls[n]=!1);a=i.$.get(n)._}var s=i.map[n]={put:t,get:n,$:a.$},f={ctx:i,msg:s};i.async=!!u.tag.node,i.ack&&(s["@"]=i.ack),v(t,o,f),i.async&&(i.and||u.on("node",function(t){this.to.next(t),t===i.map[t.get]&&(i.souls[t.get]=!1,v(t.put,e,t),v(i.souls,function(t){return t?t:void 0})||i.c||(i.c=1,this.off(),v(i.map,r,i)))}),i.and=!0,u.on("node",s))}function o(t,n){var o=this.ctx,e=o.graph,r=this.msg,u=r.get,a=r.put,s=r.$._;e[u]=i.state.to(a,n,e[u]),o.async||(s.put=i.state.to(a,n,s.put))}function e(t,n){var o=this,e=o.put,r=o.$._;r.put=i.state.to(e,n,r.put)}function r(t){t.$&&(this.cat.stop=this.stop,t.$._.on("in",t),this.cat.stop=null)}i.on.put=function(o,e){var a=e._,s={$:e,graph:a.graph,put:{},map:{},souls:{},machine:i.state(),ack:o["@"],cat:a,stop:{}};return i.graph.is(o.put,null,t,s)||(s.err="Error: Invalid graph!"),s.err?a.on("in",{"@":o["#"],err:i.log(s.err)}):(v(s.put,n,s),s.async||v(s.map,r,s),u!==s.defer&&setTimeout(function(){i.on.put(o,e)},s.defer-s.machine),void(s.diff&&a.on("put",d(o,{put:s.diff}))))},i.on.get=function(t,n){var o,e=n._,r=t.get[m],u=e.graph[r],a=t.get[b],s=e.next||(e.next={}),f=s[r];if(!u||!f)return e.on("get",t);if(a){if(!h(u,a))return e.on("get",t);u=i.state.to(u,a)}else u=i.obj.copy(u);u=i.graph.node(u),o=f.ack,e.on("in",{"@":t["#"],how:"mem",put:u,$:n}),e.on("get",t)}}(),function(){i.chain.opt=function(t){t=t||{};var n=this,o=n._,e=t.peers||t;return p(t)||(t={}),p(o.opt)||(o.opt=t),f(e)&&(e=[e]),a(e)&&(e=v(e,function(t,n,o){o(t,{url:t})}),p(o.opt.peers)||(o.opt.peers={}),o.opt.peers=d(e,o.opt.peers)),o.opt.peers=o.opt.peers||{},d(t,o.opt),i.on("opt",o),o.opt.uuid=o.opt.uuid||function(){return g()+c(12)},n}}();var u,a=i.list.is,s=i.text,f=s.is,c=s.random,l=i.obj,p=l.is,h=l.has,d=l.to,v=l.map,g=(l.copy,i.state.lex),m=i.val.rel._,b=".",k=(i.node._,i.val.link.is,{});o.debug=function(t,n){return o.debug.i&&t===o.debug.i&&o.debug.i++&&(o.log.apply(o,arguments)||n)},i.log=function(){return!i.log.off&&o.log.apply(o,arguments),[].slice.call(arguments).join(" ")},i.log.once=function(t,n,o){return(o=i.log.once)[t]=o[t]||0,o[t]++||i.log(n)},i.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=i);try{"undefined"!=typeof e&&(e.exports=i)}catch(y){}n.exports=i})(t,"./root"),t(function(){var n=t("./root");n.chain.back=function(t,i){var r;if(t=t||1,-1===t||1/0===t)return this._.root.$;if(1===t)return(this._.back||this._).$;var u=this,a=u._;if("string"==typeof t&&(t=t.split(".")),!(t instanceof Array)){if(t instanceof Function){for(var s,r={back:a};(r=r.back)&&o===(s=t(r,i)););return s}return n.num.is(t)?(a.back||a).$.back(t-1):this}var f=0,c=t.length,r=a;for(f;c>f;f++)r=(r||e)[t[f]];return o!==r?i?u:r:(r=a.back)?r.$.back(t,i):void 0};var o,e={}})(t,"./back"),t(function(){function n(t){var n,o,e,i=this.as,r=i.back,u=i.root;if(t.I||(t.I=i.$),t.$||(t.$=i.$),this.to.next(t),o=t.get){if(o["#"]||i.soul){if(o["#"]=o["#"]||i.soul,t["#"]||(t["#"]=b(9)),r=u.$.get(o["#"])._,o=o["."]){if(d(r.put,o)&&(n=r.$.get(o)._,(e=n.ack)||(n.ack=-1),r.on("in",{$:r.$,put:c.state.to(r.put,o),get:r.get}),e))return}else{if(e=r.ack,e||(r.ack=-1),d(r,"put")&&r.on("in",r),e)return;t.$=r.$}return u.ask(f,t),u.on("in",t)}if(u.now&&(u.now[i.id]=u.now[i.id]||!0,i.pass={}),o["."])return i.get?(t={get:{".":i.get},$:i.$},r.ask||(r.ask={}),r.ask[i.get]=t.$._,r.on("out",t)):(t={get:{},$:i.$},r.on("out",t));if(i.ack=i.ack||-1,i.get)return t.$=i.$,o["."]=i.get,(r.ask||(r.ask={}))[i.get]=t.$._,r.on("out",t)}return r.on("out",t)}function o(t){var n,o,r=this,s=r.as,f=s.root,h=t.$,b=(h||p)._||p,k=t.put;if(s.get&&t.get!==s.get&&(t=g(t,{get:s.get})),s.has&&b!==s&&(t=g(t,{$:s.$}),b.ack&&(s.ack=b.ack)),l===k){if(o=b.put,r.to.next(t),s.soul)return;if(l===o&&l!==b.put)return;return i(s,t,r),s.has&&a(s,t),v(b.echo,s.id),void v(s.map,b.id)}if(s.soul)return r.to.next(t),i(s,t,r),void(s.next&&m(k,u,{msg:t,cat:s}));if(!(n=c.val.link.is(k)))return c.val.is(k)?(s.has||s.soul?a(s,t):(b.has||b.soul)&&((b.echo||(b.echo={}))[s.id]=b.echo[b.id]||s,(s.map||(s.map={}))[b.id]=s.map[b.id]||{at:b}),r.to.next(t),void i(s,t,r)):(s.has&&b!==s&&d(b,"put")&&(s.put=b.put),(n=c.node.soul(k))&&b.has&&(b.put=s.root.$.get(n)._.put),o=(f.stop||{})[b.id],r.to.next(t),e(s,t,b,n),i(s,t,r),void(s.next&&m(k,u,{msg:t,cat:s})));f.stop;o=f.stop||{},o=o[b.id]||(o[b.id]={}),o.is=o.is||b.put,o[s.id]=b.put||!0,r.to.next(t),e(s,t,b,n),i(s,t,r)}function e(t,n,o,i){if(i&&k!==t.get){var r=t.root.$.get(i)._;t.has?o=r:o.has&&e(o,n,o,i),o!==t&&(o.$||(o={}),(o.echo||(o.echo={}))[t.id]=o.echo[t.id]||t,t.has&&!(t.map||p)[o.id]&&a(t,n),r=o.id?(t.map||(t.map={}))[o.id]=t.map[o.id]||{at:o}:{},(i!==r.link||r.pass||t.pass)&&(t.pass&&(c.obj.map(t.map,function(t){t.pass=!0}),v(t,"pass")),r.pass&&v(r,"pass"),t.has&&(t.link=i),s(t,r.link=i)))}}function i(t,n){t.echo&&m(t.echo,r,n)}function r(t){t&&t.on&&t.on("in",this)}function u(t,n){var o,e,i,r=this.cat,u=r.next||p,a=this.msg;(k!==n||u[n])&&(e=u[n])&&(e.has?(l!==e.put&&c.val.link.is(t)||(e.put=t),o=e.$):(i=a.$)&&(i=(o=a.$.get(n))._,l!==i.put&&c.val.link.is(t)||(i.put=t)),e.on("in",{put:t,get:n,$:o,via:a}))}function a(t,n){if(t.has||t.soul){{var o=t.map;t.root}t.map=null,t.has&&(t.link=null),(t.pass||n["@"]||null!==o)&&(l===o&&c.val.link.is(t.put)||(m(o,function(n){(n=n.at)&&v(n.echo,t.id)}),o=t.put,m(t.next,function(n,e){return l===o&&l!==t.put?!0:(n.put=l,n.ack&&(n.ack=-1),void n.on("in",{get:e,$:n.$,put:l}))})))}}function s(t,n){var o=t.root.$.get(n)._;(!t.ack||(o.on("out",{get:{"#":n}}),t.ask))&&(o=t.ask,c.obj.del(t,"ask"),m(o||t.next,function(t,o){t.on("out",{get:{"#":n,".":o}})}),c.obj.del(t,"ask"))}function f(t){var n=this.as,o=n.get||p,e=n.$._,i=(t.put||p)[o["#"]];if(e.ack&&(e.ack=e.ack+1||1),!t.put||o["."]&&!d(i,e.get)){if(e.put!==l)return;return void e.on("in",{get:e.get,put:e.put=l,$:e.$,"@":t["@"]})}return k==o["."]?void e.on("in",{get:e.get,put:c.val.link.ify(o["#"]),$:e.$,"@":t["@"]}):(t.$=e.root.$,void c.on.put(t,e.root.$))}var c=t("./root");c.chain.chain=function(t){var e,i=this,r=i._,u=new(t||i).constructor(i),a=u._;return a.root=e=r.root,a.id=++e.once,a.back=i._,a.on=c.on,a.on("in",o,a),a.on("out",n,a),u};var l,p={},h=c.obj,d=h.has,v=(h.put,h.del),g=h.to,m=h.map,b=c.text.random,k=(c.val.rel._,c.node._)})(t,"./chain"),t(function(){function n(t,n){var o=n._,e=o.next,i=n.chain(),r=i._;return e||(e=o.next={}),e[r.get=t]=r,n===o.root.$?r.soul=t:(o.soul||o.has)&&(r.has=t),r}function o(t,n,o,e){var i,r=t._;return(i=r.soul)?(n(i,e,r),t):(i=r.link)?(n(i,e,r),t):(t.get(function(t,o){o.rid(t);var r=(r=t.$)&&r._||{};i=r.link||r.soul||c.is(t.put)||l(t.put),n(i,e,t,o)},{out:{get:{".":!0}}}),t)}function e(t){var n,o=this,e=o.as,i=e.at,r=i.root,a=t.$,f=(a||{})._||{},l=t.put||f.put;if((n=r.now)&&o!==n[e.now])return o.to.next(t);if(o.seen&&f.id&&o.seen[f.id])return o.to.next(t);if((n=l)&&n[c._]&&(n=c.is(n))&&(n=(t.$$=f.root.gun.get(n))._,u!==n.put&&(t=s(t,{put:l=n.put}))),(n=r.mum)&&f.id){if(n[f.id])return;u===l||c.is(l)||(n[f.id]=!0)}return e.use(t,o),o.stun?void(o.stun=null):void o.to.next(t)}function i(t){var n=this.on;if(!t||n.soul||n.has)return this.off();if(t=(t=(t=t.$||t)._||t).id){{var o,e;n.map}return(o=(e=this.seen||(this.seen={}))[t])?!0:void(e[t]=!0)}}var r=t("./root");r.chain.get=function(t,u,a){var s,l;if("string"!=typeof t){if(t instanceof Function){if(!0===u)return o(this,t,u,a);s=this;var h,d=s._,v=d.root,l=v.now;a=u||{},a.at=d,a.use=t,a.out=a.out||{},a.out.get=a.out.get||{},(h=d.on("in",e,a)).rid=i,(v.now={$:1})[a.now=d.id]=h;var g=v.mum;return v.mum={},d.on("out",a.out),v.mum=g,v.now=l,s}return f(t)?this.get(""+t,u,a):(l=c.is(t))?this.get(l,u,a):((a=this.chain())._.err={err:r.log("Invalid get request!",t)},u&&u.call(a,a._.err),a)}var m=this,b=m._,k=b.next||p;return(s=k[t])||(s=n(t,m)),s=s.$,(l=b.stun)&&(s._.stun=s._.stun||l),u&&u instanceof Function&&s.get(u,a),s};var u,a=r.obj,s=(a.has,r.obj.to),f=r.num.is,c=r.val.link,l=r.node.soul,p=(r.node._,{})})(t,"./get"),t(function(){function n(t){t.batch=i;var n=t.opt||{},o=t.env=c.state.map(u,n.state);return o.soul=t.soul,t.graph=c.graph.ify(t.data,o,t),o.err?((t.ack||m).call(t,t.out={err:c.log(o.err)}),void(t.res&&t.res())):void t.batch()}function e(t){return void(t&&t())}function i(){var t=this;t.graph&&!v(t.stun,r)&&(t.res=t.res||function(t){t&&t()},t.res(function(){var n=t.$.back(-1)._,o=n.ask(function(o){n.root.on("ack",o),o.err&&c.log(o),o.lack||this.off(),t.ack&&t.ack(o,this)},t.opt),e=n.root.now;p.del(n.root,"now");var i=n.root.mum;n.root.mum={},t.ref._.on("out",{$:t.ref,put:t.out=t.env.graph,opt:t.opt,"#":o}),n.root.mum=i?p.to(i,n.root.mum):i,n.root.now=e},t),t.res&&t.res())}function r(t){return t?!0:void 0}function u(t,n,o,e){var i=this,r=c.is(t);!n&&e.path.length&&(i.res||b)(function(){var n=e.path,o=i.ref,u=(i.opt,0),s=n.length;for(u;s>u;u++)o=o.get(n[u]);r&&(o=t);var f=o._.dub;return f||(f=c.node.soul(e.obj))?(o.back(-1).get(f),void e.soul(f)):((i.stun=i.stun||{})[n]=!0,void o.get(a,!0,{as:{at:e,as:i,p:n}}))},{as:i,at:e})}function a(t,n,o,e){var n=n.as,i=n.at;n=n.as;var r=((o||{}).$||{})._||{};return t=r.dub=r.dub||t||c.node.soul(i.obj)||c.node.soul(o.put||r.put)||c.val.rel.is(o.put||r.put)||(n.via.back("opt.uuid")||c.text.random)(),e&&(e.stun=!0),t?void s(r,r.dub=t,i,n):void r.via.back("opt.uuid")(function(t,o){return t?c.log(t):void s(r,r.dub=r.dub||o,i,n)})}function s(t,n,o,e){t.$.back(-1).get(n),o.soul(n),e.stun[o.path]=!1,e.batch()}function f(t,n,e,i){if(n=n.as,e.$&&e.$._){if(e.err)return void o.log("Please report this as an issue! Put.any.err");var r,u=e.$._,a=u.put,s=n.opt||{};if(!(r=n.ref)||!r._.now){if(i&&(i.stun=!0),n.ref!==n.$){if(r=n.$._.get||u.get,!r)return void o.log("Please report this as an issue! Put.no.get");n.data=d({},r,n.data),r=null}if(l===a){if(!u.get)return;t||(r=u.$.back(function(t){return t.link||t.soul?t.link||t.soul:void(n.data=d({},t.get,n.data))})),r=r||u.get,u=u.root.$.get(r)._,n.soul=r,a=n.data}return n.not||(n.soul=n.soul||t)||(n.path&&h(n.data)?n.soul=(s.uuid||n.via.back("opt.uuid")||c.text.random)():(k==u.get&&(n.soul=(u.put||g)["#"]||u.dub),n.soul=n.soul||u.soul||u.soul||(s.uuid||n.via.back("opt.uuid")||c.text.random)()),n.soul)?void n.ref.put(n.data,n.soul,n):void n.via.back("opt.uuid")(function(t,o){return t?c.log(t):void n.ref.put(n.data,n.soul=o,n)})}}}var c=t("./root");c.chain.put=function(t,o,i){var r,u=this,a=u._,s=a.root.$;return i=i||{},i.data=t,i.via=i.$=i.via||i.$||u,"string"==typeof o?i.soul=o:i.ack=i.ack||o,a.soul&&(i.soul=a.soul),i.soul||s===u?h(i.data)?(i.soul=i.soul||(i.not=c.node.soul(i.data)||(i.via.back("opt.uuid")||c.text.random)()),i.soul?(i.$=u=s.get(i.soul),i.ref=i.$,n(i),u):(i.via.back("opt.uuid")(function(t,n){return t?c.log(t):void(i.ref||i.$).put(i.data,i.soul=n,i)}),u)):((i.ack||m).call(i,i.out={err:c.log("Data saved to the root level of the graph must be a node (an object), not a",typeof i.data,'of "'+i.data+'"!')}),i.res&&i.res(),u):c.is(t)?(t.get(function(t,n,e){return!t&&c.val.is(e.put)?c.log("The reference you are saving is a",typeof e.put,'"'+e.put+'", not a node (object)!'):void u.put(c.val.rel.ify(t),o,i)},!0),u):(i.ref=i.ref||s._===(r=a.back)?u:r.$,i.ref._.soul&&c.val.is(i.data)&&a.get?(i.data=d({},a.get,i.data),i.ref.put(i.data,i.soul,i),u):(i.ref.get(f,!0,{as:i}),i.out||(i.res=i.res||e,i.$._.stun=i.ref._.stun),u))};var l,p=c.obj,h=p.is,d=p.put,v=p.map,g={},m=function(){},b=function(t,n){t.call(n||g)},k=c.node._})(t,"./put"),t(function(n){var o=t("./root");t("./chain"),t("./back"),t("./put"),t("./get"),n.exports=o})(t,"./index"),t(function(){function n(t,n){{var o,e=this,r=t.$,u=(r||{})._||{},a=u.put||t.put;e.at}if(i!==a){if(o=t.$$){if(o=t.$$._,i===o.put)return;a=o.put}e.change&&(a=t.put),e.as?e.ok.call(e.as,t,n):e.ok.call(r,a,t.get,t,n)}}function o(t,n,e){var r,u,a=this.as,s=(a.at,t.$),f=s._,c=f.put||t.put;if(u=t.$$){if(r=u=t.$$._,i===u.put)return;c=u.put}return(u=n.wait)&&(u=u[f.id])&&clearTimeout(u),e||i!==c&&!f.soul&&!f.link&&(!r||0 .once, apologies unexpected."),this.once(t,n)},e.chain.once=function(t,n){var r=this,u=r._,a=u.put;if(0=(n.batch||1e3)?s():void(e||(e=setTimeout(s,n.wait||1)))}),t.on("get",function(o){function e(){if(s&&(i=s["#"])){var e=s["."];r=u[i]||a,r&&e&&(r=Gun.state.to(r,e)),(r||Gun.obj.empty(n.peers))&&t.on("in",{"@":o["#"],put:Gun.graph.node(r),how:"lS",lS:o.I})}}this.to.next(o);var i,r,a,s=o.get;Gun.debug?setTimeout(e,1):e()});var a=function(t,n,o,e){u[e]=Gun.state.to(o,n,u[e])},s=function(a){var f;r=0,clearTimeout(e),e=!1;var c=i;i={},a&&(u=a);try{o.setItem(n.file,JSON.stringify(u))}catch(l){Gun.log(f=l||"localStorage failure"),t.on("localStorage:error",{err:f,file:n.file,flush:u,retry:s})}(f||Gun.obj.empty(n.peers))&&Gun.obj.map(c,function(n,o){t.on("in",{"@":o,err:f,ok:0})})}}})}})(t,"./adapters/localStorage"),t(function(n){function o(t){var n=function(){};return n.out=function(o){var e;return this.to&&this.to.next(o),(e=o["@"])&&(e=t.dup.s[e])&&(e=e.it)&&e.mesh?(n.say(o,e.mesh.via),void(e["##"]=o["##"])):void n.say(o)},n.hear=function(o,i){if(o){var r,u,a,s=t.dup,f=o[0];try{a=JSON.parse(o)}catch(c){}if("{"===f){if(!a)return;if(s.check(r=a["#"]))return;if(s.track(r,!0).it=a,(f=a["@"])&&a.put&&(u=a["##"]||(a["##"]=n.hash(a)),(f+=u)!=r)){if(s.check(f))return;(f=s.s)[u]=f[r]}return(a.mesh=function(){}).via=i,(f=a["><"])&&(a.mesh.to=e.obj.map(f.split(","),function(t,n,o){o(t,!0)})),void t.on("in",a)}if("["!==f);else{if(!a)return;for(var l,p=0;l=a[p++];)n.hear(l,i)}}},function(){function o(t,n){var o=n.wire;try{o.send?o.readyState===o.OPEN?o.send(t):(n.queue=n.queue||[]).push(t):n.say&&n.say(t)}catch(e){(n.queue=n.queue||[]).push(t)}}n.say=function(i,u){if(!u)return void e.obj.map(t.opt.peers,function(t){n.say(i,t)});var a,s,f,c=u.wire||t.opt.wire&&t.opt.wire(u);if(c&&(s=i.mesh||r,u!==s.via&&((f=s.raw)||(f=n.raw(i)),!((a=i["@"])&&(a=t.dup.s[a])&&(a=a.it)&&a.get&&a["##"]&&a["##"]===i["##"]||(a=s.to)&&(a[u.url]||a[u.id]))))){if(u.batch)return void u.batch.push(f);u.batch=[],setTimeout(function(){var t=u.batch;t&&(u.batch=null,t.length&&o(JSON.stringify(t),u))},t.opt.gap||t.opt.wait||1),o(f,u)}}}(),function(){function r(t,n){var o;return n instanceof Object?(e.obj.map(Object.keys(n).sort(),u,{to:o={},on:n}),o):n}function u(t){this.to[t]=this.on[t]}n.raw=function(o){if(!o)return"";var u,f,c,l=t.dup,p=o.mesh||{};if(c=p.raw)return c;if("string"==typeof o)return o;o["@"]&&(c=o.put)&&((f=o["##"])||(u=a(c,r)||"",f=n.hash(o,u),o["##"]=f),(c=l.s)[f=o["@"]+f]=c[o["#"]],o["#"]=f||o["#"],u&&((o=e.obj.to(o)).put=s));var h=0,d=[];e.obj.map(t.opt.peers,function(t){return d.push(t.url||t.id),++h>9?!0:void 0}),o["><"]=d.join();var v=a(o);return i!==u&&(v=v.replace('"'+s+'"',u)),p&&(p.raw=v),v},n.hash=function(t,n){return o.hash(n||a(t.put,r)||"")||t["#"]||e.text.random(9)};var a=JSON.stringify,s=":])([:"}(),n.hi=function(o){t.on("hi",o);var i=o.queue;o.queue=[],e.obj.map(i,function(t){n.say(t,o)})},n}var e=t("../type");o.hash=function(t){if("string"!=typeof t)return{err:1};var n=0;if(!t.length)return n;for(var o,e=0,i=t.length;i>e;++e)o=t.charCodeAt(e),n=(n<<5)-n+o,n|=0;return n};var i,r={};Object.keys=Object.keys||function(t){return map(t,function(t,n,o){o(n)})};try{n.exports=o}catch(u){}})(t,"./adapters/mesh"),t(function(){var n=t("../index");n.Mesh=t("./mesh"),n.on("opt",function(t){function o(n){if(n&&n.url){var o=n.url.replace("http","ws"),u=n.wire=new i.WebSocket(o);return u.onclose=function(){t.on("bye",n),e(n)},u.onerror=function(t){e(n),t&&"ECONNREFUSED"===t.code},u.onopen=function(){a.hi(n)},u.onmessage=function(t){t&&(r.inLength=(r.inLength||0)+(t.data||t).length,a.hear(t.data||t,n))},u}}function e(t){clearTimeout(t.defer),t.defer=setTimeout(function(){o(t)},2e3)}this.to.next(t);var i=t.opt;if(!t.once&&!1!==i.WebSocket){var r;"undefined"!=typeof window&&(r=window),"undefined"!=typeof global&&(r=global),r=r||{};var u=i.WebSocket||r.WebSocket||r.webkitWebSocket||r.mozWebSocket;if(u){i.WebSocket=u;var a=i.mesh=i.mesh||n.Mesh(t);t.on("create",function(n){this.to.next(n),t.on("out",a.out)}),i.wire=i.wire||o}}})})(t,"./adapters/websocket")}(); \ No newline at end of file diff --git a/src/on.js b/src/on.js index 9979c8e0..80d7dfe3 100644 --- a/src/on.js +++ b/src/on.js @@ -84,7 +84,7 @@ function val(msg, eve, to){ data = tmp.put; } if((tmp = eve.wait) && (tmp = tmp[at.id])){ clearTimeout(tmp) } - if(!to && (at.soul || at.link || (link && !(0 < link.ack)))){ + if(!to && (u === data || at.soul || at.link || (link && !(0 < link.ack)))){ tmp = (eve.wait = {})[at.id] = setTimeout(function(){ val.call({as:opt}, msg, eve, tmp || 1); }, opt.wait || 99); From e0e846113e8b7ed2079c4233f0df345f1a7318a0 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Sun, 22 Jul 2018 09:23:13 -0700 Subject: [PATCH 082/221] check which gun is running --- lib/later.js | 2 +- lib/not.js | 2 +- lib/radisk.js | 1 + lib/shim.js | 10 +- package-lock.json | 220 +++++++++++++++++++++---------------------- test/panic/radisk.js | 4 +- 6 files changed, 118 insertions(+), 121 deletions(-) diff --git a/lib/later.js b/lib/later.js index 0fd65062..62a0d491 100644 --- a/lib/later.js +++ b/lib/later.js @@ -1,5 +1,5 @@ var Gun = Gun || require('../gun'); -Gun.chain.open || require('gun/lib/open'); +Gun.chain.open || require('./open'); Gun.chain.later = function(cb, age){ var gun = this; diff --git a/lib/not.js b/lib/not.js index 133c4fee..7a5255ab 100644 --- a/lib/not.js +++ b/lib/not.js @@ -1,7 +1,7 @@ if(typeof window !== "undefined"){ var Gun = window.Gun; } else { - var Gun = require('gun/gun'); + var Gun = require('../gun'); } var u; diff --git a/lib/radisk.js b/lib/radisk.js index 7bbb43c2..e9c6dc48 100644 --- a/lib/radisk.js +++ b/lib/radisk.js @@ -72,6 +72,7 @@ r.batch.acks = []; r.batch.ed = 0; r.save(batch, function(err, ok){ + if(++i > 1){ return } if(err){ Gun.log('err', err) } map(batch.acks, function(cb){ cb(err, ok) }); thrash.at = null; diff --git a/lib/shim.js b/lib/shim.js index 27c8e243..c33e73dc 100644 --- a/lib/shim.js +++ b/lib/shim.js @@ -1,10 +1,6 @@ -if(typeof window !== "undefined"){ - var Gun = window.Gun; -} else { - var Gun = require('gun/gun'); -} +var Gun = (typeof window !== "undefined")? window.Gun : require('../gun'); -Gun.chain.open || require('gun/lib/open'); +Gun.chain.open || require('./open'); var _on = Gun.chain.on; Gun.chain.on = function(a,b,c){ @@ -14,7 +10,7 @@ Gun.chain.on = function(a,b,c){ return _on.call(this, a,b,c); } -Gun.chain.bye || require('gun/lib/bye'); +Gun.chain.bye || require('./bye'); Gun.chain.onDisconnect = Gun.chain.bye; Gun.chain.connected = function(cb){ var root = this.back(-1), last; diff --git a/package-lock.json b/package-lock.json index cefd2123..486044a6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "gun", - "version": "0.9.9993", + "version": "0.9.9996", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -10,9 +10,9 @@ "integrity": "sha512-ywlelg2ePNpX4IlN+A3qXySzKBAZmI2ZxMdDL3amJLCTYhYhemYcv6Aa+PTETojUfB+k4z4X4970q/jjSzyLvw==", "dev": true, "requires": { - "asn1.js": "4.10.1", - "base64url": "2.0.0", - "elliptic": "6.4.0" + "asn1.js": "^4.9.1", + "base64url": "^2.0.0", + "elliptic": "^6.4.0" } }, "@trust/webcrypto": { @@ -21,10 +21,10 @@ "integrity": "sha512-aix+LOG/3Ku3MzClfVxVH88QbSdIL1HcBQ+gjXL/VnX05uyORf28CaQZOvsoEcCzGnWIVBUNwE2gxLBapWANWw==", "dev": true, "requires": { - "@trust/keyto": "0.3.2", - "base64url": "2.0.0", - "node-rsa": "0.4.2", - "text-encoding": "0.6.4" + "@trust/keyto": "^0.3.1", + "base64url": "^2.0.0", + "node-rsa": "^0.4.0", + "text-encoding": "^0.6.1" } }, "accepts": { @@ -33,7 +33,7 @@ "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", "dev": true, "requires": { - "mime-types": "2.1.18", + "mime-types": "~2.1.18", "negotiator": "0.6.1" } }, @@ -67,9 +67,9 @@ "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", "dev": true, "requires": { - "bn.js": "4.11.8", - "inherits": "2.0.3", - "minimalistic-assert": "1.0.1" + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" } }, "async-limiter": { @@ -165,15 +165,15 @@ "dev": true, "requires": { "bytes": "3.0.0", - "content-type": "1.0.4", + "content-type": "~1.0.4", "debug": "2.6.9", - "depd": "1.1.2", - "http-errors": "1.6.3", + "depd": "~1.1.1", + "http-errors": "~1.6.2", "iconv-lite": "0.4.19", - "on-finished": "2.3.0", + "on-finished": "~2.3.0", "qs": "6.5.1", "raw-body": "2.3.2", - "type-is": "1.6.16" + "type-is": "~1.6.15" } }, "brace-expansion": { @@ -182,7 +182,7 @@ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "requires": { - "balanced-match": "1.0.0", + "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, @@ -204,9 +204,9 @@ "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", "dev": true, "requires": { - "base64-js": "1.3.0", - "ieee754": "1.1.8", - "isarray": "1.0.0" + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" } }, "bytes": { @@ -314,13 +314,13 @@ "integrity": "sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8=", "dev": true, "requires": { - "bn.js": "4.11.8", - "brorand": "1.1.0", - "hash.js": "1.1.3", - "hmac-drbg": "1.0.1", - "inherits": "2.0.3", - "minimalistic-assert": "1.0.1", - "minimalistic-crypto-utils": "1.0.1" + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.0" } }, "encodeurl": { @@ -340,7 +340,7 @@ "cookie": "0.3.1", "debug": "2.3.3", "engine.io-parser": "1.3.2", - "ws": "1.1.5" + "ws": "~1.1.5" }, "dependencies": { "accepts": { @@ -349,7 +349,7 @@ "integrity": "sha1-w8p0NJOGSMPg2cHjKN1otiLChMo=", "dev": true, "requires": { - "mime-types": "2.1.18", + "mime-types": "~2.1.11", "negotiator": "0.6.1" } }, @@ -380,8 +380,8 @@ "integrity": "sha512-o3KqipXNUdS7wpQzBHSe180lBGO60SoK0yVo3CYJgb2MkobuWuBX6dhkYP5ORCLd55y+SaflMOV5fqAB53ux4w==", "dev": true, "requires": { - "options": "0.0.6", - "ultron": "1.0.2" + "options": ">=0.0.5", + "ultron": "1.0.x" } } } @@ -401,7 +401,7 @@ "parsejson": "0.0.3", "parseqs": "0.0.5", "parseuri": "0.0.5", - "ws": "1.1.5", + "ws": "~1.1.5", "xmlhttprequest-ssl": "1.5.3", "yeast": "0.1.2" }, @@ -433,8 +433,8 @@ "integrity": "sha512-o3KqipXNUdS7wpQzBHSe180lBGO60SoK0yVo3CYJgb2MkobuWuBX6dhkYP5ORCLd55y+SaflMOV5fqAB53ux4w==", "dev": true, "requires": { - "options": "0.0.6", - "ultron": "1.0.2" + "options": ">=0.0.5", + "ultron": "1.0.x" } } } @@ -483,36 +483,36 @@ "integrity": "sha1-avilAjUNsyRuzEvs9rWjTSL37VM=", "dev": true, "requires": { - "accepts": "1.3.5", + "accepts": "~1.3.5", "array-flatten": "1.1.1", "body-parser": "1.18.2", "content-disposition": "0.5.2", - "content-type": "1.0.4", + "content-type": "~1.0.4", "cookie": "0.3.1", "cookie-signature": "1.0.6", "debug": "2.6.9", - "depd": "1.1.2", - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "etag": "1.8.1", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", "finalhandler": "1.1.1", "fresh": "0.5.2", "merge-descriptors": "1.0.1", - "methods": "1.1.2", - "on-finished": "2.3.0", - "parseurl": "1.3.2", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", "path-to-regexp": "0.1.7", - "proxy-addr": "2.0.3", + "proxy-addr": "~2.0.3", "qs": "6.5.1", - "range-parser": "1.2.0", + "range-parser": "~1.2.0", "safe-buffer": "5.1.1", "send": "0.16.2", "serve-static": "1.13.2", "setprototypeof": "1.1.0", - "statuses": "1.4.0", - "type-is": "1.6.16", + "statuses": "~1.4.0", + "type-is": "~1.6.16", "utils-merge": "1.0.1", - "vary": "1.1.2" + "vary": "~1.1.2" }, "dependencies": { "safe-buffer": { @@ -530,12 +530,12 @@ "dev": true, "requires": { "debug": "2.6.9", - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "on-finished": "2.3.0", - "parseurl": "1.3.2", - "statuses": "1.4.0", - "unpipe": "1.0.0" + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.4.0", + "unpipe": "~1.0.0" } }, "forwarded": { @@ -562,12 +562,12 @@ "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, "growl": { @@ -611,8 +611,8 @@ "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", "dev": true, "requires": { - "inherits": "2.0.3", - "minimalistic-assert": "1.0.1" + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.0" } }, "he": { @@ -627,9 +627,9 @@ "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", "dev": true, "requires": { - "hash.js": "1.1.3", - "minimalistic-assert": "1.0.1", - "minimalistic-crypto-utils": "1.0.1" + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" } }, "http-errors": { @@ -638,10 +638,10 @@ "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", "dev": true, "requires": { - "depd": "1.1.2", + "depd": "~1.1.2", "inherits": "2.0.3", "setprototypeof": "1.1.0", - "statuses": "1.4.0" + "statuses": ">= 1.4.0 < 2" } }, "iconv-lite": { @@ -668,8 +668,8 @@ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" + "once": "^1.3.0", + "wrappy": "1" } }, "inherits": { @@ -756,7 +756,7 @@ "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", "dev": true, "requires": { - "mime-db": "1.33.0" + "mime-db": "~1.33.0" } }, "minimalistic-assert": { @@ -777,7 +777,7 @@ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { - "brace-expansion": "1.1.11" + "brace-expansion": "^1.1.7" } }, "minimist": { @@ -873,7 +873,7 @@ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { - "wrappy": "1.0.2" + "wrappy": "1" } }, "options": { @@ -888,10 +888,10 @@ "integrity": "sha1-4+yr3DQn6vELowviJZAaehGasXM=", "dev": true, "requires": { - "bluebird": "3.5.1", - "is-promise": "2.1.0", + "bluebird": "^3.4.6", + "is-promise": "^2.1.0", "platform": "1.3.1", - "socket.io-client": "1.7.4" + "socket.io-client": "^1.4.5" } }, "panic-manager": { @@ -900,10 +900,10 @@ "integrity": "sha1-0tvHdgIAMsWwEw0QW/vqewZnMh4=", "dev": true, "requires": { - "isarray": "2.0.4", - "panic-client": "1.0.2", - "socket.io": "1.7.4", - "socket.io-client": "1.7.4" + "isarray": "^2.0.0", + "panic-client": "^1.0.0", + "socket.io": "^1.4.8", + "socket.io-client": "^1.4.8" }, "dependencies": { "isarray": { @@ -920,9 +920,9 @@ "integrity": "sha512-TcR6M4LaqKjHvAKoAi46w2Y11KPJiMchAEqu00+tlOBxHR8AYvUCBvDLw4+j3MymApVHHWtluOzDaWxEYeGuVw==", "dev": true, "requires": { - "bluebird": "3.5.1", - "panic-client": "1.0.2", - "socket.io": "1.7.4" + "bluebird": "^3.3.5", + "panic-client": "^1.0.0", + "socket.io": "^1.4.5" } }, "parsejson": { @@ -931,7 +931,7 @@ "integrity": "sha1-q343WfIJ7OmUN5c/fQ8fZK4OZKs=", "dev": true, "requires": { - "better-assert": "1.0.2" + "better-assert": "~1.0.0" } }, "parseqs": { @@ -940,7 +940,7 @@ "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", "dev": true, "requires": { - "better-assert": "1.0.2" + "better-assert": "~1.0.0" } }, "parseuri": { @@ -949,7 +949,7 @@ "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", "dev": true, "requires": { - "better-assert": "1.0.2" + "better-assert": "~1.0.0" } }, "parseurl": { @@ -982,7 +982,7 @@ "integrity": "sha512-jQTChiCJteusULxjBp8+jftSQE5Obdl3k4cnmLA6WXtK6XFuWRnvVL7aCiBqaLPM8c4ph0S4tKna8XvmIwEnXQ==", "dev": true, "requires": { - "forwarded": "0.1.2", + "forwarded": "~0.1.2", "ipaddr.js": "1.6.0" } }, @@ -1037,7 +1037,7 @@ "depd": "1.1.1", "inherits": "2.0.3", "setprototypeof": "1.0.3", - "statuses": "1.4.0" + "statuses": ">= 1.3.1 < 2" } }, "setprototypeof": { @@ -1061,18 +1061,18 @@ "dev": true, "requires": { "debug": "2.6.9", - "depd": "1.1.2", - "destroy": "1.0.4", - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "etag": "1.8.1", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", "fresh": "0.5.2", - "http-errors": "1.6.3", + "http-errors": "~1.6.2", "mime": "1.4.1", "ms": "2.0.0", - "on-finished": "2.3.0", - "range-parser": "1.2.0", - "statuses": "1.4.0" + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" } }, "serve-static": { @@ -1081,9 +1081,9 @@ "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", "dev": true, "requires": { - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "parseurl": "1.3.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.2", "send": "0.16.2" } }, @@ -1100,7 +1100,7 @@ "dev": true, "requires": { "debug": "2.3.3", - "engine.io": "1.8.5", + "engine.io": "~1.8.4", "has-binary": "0.1.7", "object-assign": "4.1.0", "socket.io-adapter": "0.5.0", @@ -1162,7 +1162,7 @@ "component-bind": "1.0.0", "component-emitter": "1.2.1", "debug": "2.3.3", - "engine.io-client": "1.8.5", + "engine.io-client": "~1.8.4", "has-binary": "0.1.7", "indexof": "0.0.1", "object-component": "0.0.3", @@ -1247,7 +1247,7 @@ "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", "dev": true, "requires": { - "has-flag": "2.0.0" + "has-flag": "^2.0.0" } }, "text-encoding": { @@ -1269,7 +1269,7 @@ "dev": true, "requires": { "media-typer": "0.3.0", - "mime-types": "2.1.18" + "mime-types": "~2.1.18" } }, "uglify-js": { @@ -1278,8 +1278,8 @@ "integrity": "sha512-hS7+TDiqIqvWScCcKRybCQzmMnEzJ4ryl9ErRmW4GFyG48p0/dKZiy/5mVLbsFzU8CCnCgQdxMiJzZythvLzCg==", "dev": true, "requires": { - "commander": "2.15.1", - "source-map": "0.6.1" + "commander": "~2.15.0", + "source-map": "~0.6.1" }, "dependencies": { "commander": { @@ -1335,7 +1335,7 @@ "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.0.tgz", "integrity": "sha512-c18dMeW+PEQdDFzkhDsnBAlS4Z8KGStBQQUcQ5mf7Nf689jyGk0594L+i9RaQuf4gog6SvWLJorz2NfSaqxZ7w==", "requires": { - "async-limiter": "1.0.0" + "async-limiter": "~1.0.0" } }, "wtf-8": { @@ -1350,8 +1350,8 @@ "integrity": "sha1-F76T6q4/O3eTWceVtBlwWogX6Gg=", "dev": true, "requires": { - "sax": "1.2.1", - "xmlbuilder": "4.2.1" + "sax": ">=0.6.0", + "xmlbuilder": "^4.1.0" } }, "xmlbuilder": { @@ -1360,7 +1360,7 @@ "integrity": "sha1-qlijBBoGb5DqoWwvU4n/GfP0YaU=", "dev": true, "requires": { - "lodash": "4.17.10" + "lodash": "^4.0.0" } }, "xmlhttprequest-ssl": { diff --git a/test/panic/radisk.js b/test/panic/radisk.js index c0066f53..3c0dc978 100644 --- a/test/panic/radisk.js +++ b/test/panic/radisk.js @@ -15,6 +15,7 @@ var config = { '/jquery.js': __dirname + '/../../examples/jquery.js' } } +config.gundir = require('path').resolve(config.dir, '../../')+'/'; var panic = require('panic-server'); panic.server().on('request', function(req, res){ @@ -63,8 +64,8 @@ describe("Make sure the Radix Storage Engine (RAD) works.", function(){ var server = require('http').createServer(function(req, res){ res.end("I am "+ env.i +"!"); }); + console.log('??? ===', require('gun/package.json').version); var Gun = require('gun'); - //require('gun/lib/store'); var gun = Gun({web: server, localStorage: env.config.notrad, chunk: env.config.chunk, file: 'radata'}); server.listen(port, function(){ test.done(); @@ -159,7 +160,6 @@ describe("Make sure the Radix Storage Engine (RAD) works.", function(){ res.end("I am "+ env.i +"!"); }); var Gun = require('gun'); - //require('gun/lib/store'); var gun = Gun({web: server, localStorage: env.config.notrad, chunk: env.config.notrad, file: 'radata', lack: 1000 * 60 * 60}); server.listen(port, function(){ test.done(); From 0593bd1b7e27bb3f30c390c148ad6ee2b1a7fded Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Sun, 22 Jul 2018 09:52:38 -0700 Subject: [PATCH 083/221] log into first decrypted SEA account --- package.json | 2 +- sea.js | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 3b23c305..9d60c69f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gun", - "version": "0.9.9996", + "version": "0.9.9997", "description": "A realtime, decentralized, offline-first, graph data synchronization engine.", "main": "index.js", "browser": "gun.min.js", diff --git a/sea.js b/sea.js index 71ee0259..d49165d3 100644 --- a/sea.js +++ b/sea.js @@ -716,7 +716,7 @@ let err // then attempt to log into each one until we find ours! // (if two users have the same username AND the same password... that would be bad) - const [ user ] = await Promise.all(aliases.map(async ({ at: at, pub: pub }) => { + const users = await Promise.all(aliases.map(async ({ at: at, pub: pub }, i) => { // attempt to PBKDF2 extend the password with the salt. (Verifying the signature gives us the plain text salt.) const auth = parseProps(at.put.auth) // NOTE: aliasquery uses `gun.get` which internally SEA.read verifies the data for us, so we do not need to re-verify it here. @@ -731,7 +731,7 @@ const salt = auth.salt const sea = await SEA.decrypt(auth.ek, proof) if (!sea) { - err = 'Failed to decrypt secret!' + err = 'Failed to decrypt secret! ' + i +'/'+aliases.length; return } // now we have AES decrypted the private key, from when we encrypted it with the proof at registration. @@ -754,7 +754,7 @@ throw { err } } })) - + var user = Gun.list.map(users, function(acc){ if(acc){ return acc } }) if (!user) { throw { err: err || 'Public key does not exist!' } } @@ -1111,7 +1111,7 @@ var u; // Well first we have to actually create a user. That is what this function does. - User.prototype.create = function(username, pass, cb){ + User.prototype.create = function(username, pass, cb, opt){ // TODO: Needs to be cleaned up!!! const gunRoot = this.back(-1) var gun = this, cat = (gun._); @@ -1121,12 +1121,13 @@ return gun; } cat.ing = true; + opt = opt || {}; var resolve = function(){}, reject = resolve; // Because more than 1 user might have the same username, we treat the alias as a list of those users. if(cb){ resolve = reject = cb } gunRoot.get('~@'+username).get(async (at, ev) => { ev.off() - if (at.put) { + if (at.put && !opt.already) { // If we can enforce that a user name is already taken, it might be nice to try, but this is not guaranteed. const err = 'User already created!' Gun.log(err) From 0437235f3dddd565c82855df3621cd5c8ea7cb83 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Mon, 30 Jul 2018 08:28:23 -0700 Subject: [PATCH 084/221] social --- examples/pop.png | Bin 0 -> 29515 bytes examples/social.html | 724 +++++++++++++++++++++++++++++++++++++++++++ gun.min.js | 2 +- package.json | 2 +- 4 files changed, 726 insertions(+), 2 deletions(-) create mode 100644 examples/pop.png create mode 100644 examples/social.html diff --git a/examples/pop.png b/examples/pop.png new file mode 100644 index 0000000000000000000000000000000000000000..96bdfb80a9c709eba90ae82f618afb9b6d1abbe1 GIT binary patch literal 29515 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 Llc{`Z`u=|bH8I_? literal 0 HcmV?d00001 diff --git a/examples/social.html b/examples/social.html new file mode 100644 index 00000000..10b8382a --- /dev/null +++ b/examples/social.html @@ -0,0 +1,724 @@ + + + + + + + + + + + + + + + + + + + + + +
+ +
+
Welcome,
+
+ +
+
+ +
+
+ + +
+ By logging in or up, you agree to the Terms of Service. +

Forgot password?

+
+ +
+ +
+ + +
+

Forgot Password

+
+
    +
  • +
  • +

    What was your first pet's name, the type of animal they were, and your favorite quirk about them? +

    +
  • +
  • +

    Where was your first kiss? Describe what they looked like. +

    +
  • +
  • +
  • +
+
+ +
+
+ +
+ + +
+

Settings

+

Your username is .

+

+ Drop in a new profile photo: +

+
+

Because no server can reset your password, you must fill out a "forgot password" recovery form. + We recommend you use simple, grammatically correct, memorable sentences for your answers. + Keep each sentence less than 50 letters so that it will be easy for you to reconstruct - + the length of your reply will be stored as a hint to help.

+
    +
  1. +

    What was your first pet's name, the type of animal they were, and your favorite quirk about them? +

    +
  2. +
  3. +

    Where was your first kiss? Describe what they looked like. +

    +
  4. +
  5. +

    The reminder of what your password is:

    +

    +
  6. +
  7. + +
  8. +
+
+
+ +

We recommend you use a memorable and grammatically correct sentence as your passphrase. + Then write it down on paper and store it some place safe that will be easy for you to find. Here are some tips:

+
    +
  • - What gives you purpose and meaning in your life?
  • +
  • - Say something nice about an important person in your life.
  • +
  • - If you could work on your hobby full time, what goals would you have?
  • +
  • - Try to combine all of them into a rhyme, or something funny that makes you laugh.
  • +
  • + + +
  • +
  • - Ex, "Uncle Ben taught me to fight for what is right, I might have a spider bite."
  • +
  • - Ex, "I am quite better than the Dark Knight, despite any Kryptonite."
  • +
  • - Ex, "Give me a cause for these claws, I have no paws and no laws."
  • +
  • - Ex, "My suite is made of red supplements, with hidden jet compartments."
  • +
+
+

You are currently connected to 2 peers.

+ +
+ +
+ +
+ +
+ +
+ +

Welcome!

+ +
+
+ +
+
    +
+
+
  • +
    +
  • +
    +
    + +
    + +
    + + + + +
    + +
    + +

    Hello world!

    +
    + + + + + \ No newline at end of file diff --git a/gun.min.js b/gun.min.js index ea97da58..ba252adf 100644 --- a/gun.min.js +++ b/gun.min.js @@ -1 +1 @@ -!function(){function t(n){function o(t){return t.split("/").slice(-1).toString().replace(".js","")}return n.slice?t[o(n)]:function(e,i){n(e={exports:{}}),t[o(i)]=e.exports}}var n;"undefined"!=typeof window&&(n=window),"undefined"!=typeof global&&(n=global),n=n||{};var o=n.console||{log:function(){}};if("undefined"!=typeof module)var e=module;t(function(t){var n={};n.fn={is:function(t){return!!t&&"function"==typeof t}},n.bi={is:function(t){return t instanceof Boolean||"boolean"==typeof t}},n.num={is:function(t){return!e(t)&&(t-parseFloat(t)+1>=0||1/0===t||-(1/0)===t)}},n.text={is:function(t){return"string"==typeof t}},n.text.ify=function(t){return n.text.is(t)?t:"undefined"!=typeof JSON?JSON.stringify(t):t&&t.toString?t.toString():t},n.text.random=function(t,n){var o="";for(t=t||24,n=n||"0123456789ABCDEFGHIJKLMNOPQRSTUVWXZabcdefghijklmnopqrstuvwxyz";t>0;)o+=n.charAt(Math.floor(Math.random()*n.length)),t--;return o},n.text.match=function(t,o){function e(t,n){for(var o,e=-1,i=0;o=n[i++];)if(!~(e=t.indexOf(o,e+1)))return!1;return!0}var i=!1;if(t=t||"",o=n.text.is(o)?{"=":o}:o||{},n.obj.has(o,"~")&&(t=t.toLowerCase(),o["="]=(o["="]||o["~"]).toLowerCase()),n.obj.has(o,"="))return t===o["="];if(n.obj.has(o,"*")){if(t.slice(0,o["*"].length)!==o["*"])return!1;i=!0,t=t.slice(o["*"].length)}if(n.obj.has(o,"!")){if(t.slice(-o["!"].length)!==o["!"])return!1;i=!0}if(n.obj.has(o,"+")&&n.list.map(n.list.is(o["+"])?o["+"]:[o["+"]],function(n){return t.indexOf(n)>=0?void(i=!0):!0}))return!1;if(n.obj.has(o,"-")&&n.list.map(n.list.is(o["-"])?o["-"]:[o["-"]],function(n){return t.indexOf(n)<0?void(i=!0):!0}))return!1;if(n.obj.has(o,">")){if(!(t>o[">"]))return!1;i=!0}if(n.obj.has(o,"<")){if(!(tn?-1:n>o?1:0):0}},n.list.map=function(t,n,o){return a(t,n,o)},n.list.index=1,n.obj={is:function(t){return t?t instanceof Object&&t.constructor===Object||"Object"===Object.prototype.toString.call(t).match(/^\[object (\w+)\]$/)[1]:!1}},n.obj.put=function(t,n,o){return(t||{})[n]=o,t},n.obj.has=function(t,n){return t&&Object.prototype.hasOwnProperty.call(t,n)},n.obj.del=function(t,n){return t?(t[n]=null,delete t[n],t):void 0},n.obj.as=function(t,n,o,e){return t[n]=t[n]||(e===o?{}:o)},n.obj.ify=function(t){if(r(t))return t;try{t=JSON.parse(t)}catch(n){t={}}return t},function(){function t(t,n){u(this,n)&&o!==this[n]||(this[n]=t)}var o;n.obj.to=function(n,o){return o=o||{},a(n,t,o),o}}(),n.obj.copy=function(t){return t?JSON.parse(JSON.stringify(t)):t},function(){function t(t,n){var o=this.n;if(!o||!(n===o||r(o)&&u(o,n)))return n?!0:void 0}n.obj.empty=function(n,o){return n&&a(n,t,{n:o})?!1:!0}}(),function(){function t(n,o){return 2===arguments.length?(t.r=t.r||{},void(t.r[n]=o)):(t.r=t.r||[],void t.r.push(n))}var i=Object.keys;n.obj.map=function(a,s,f){var c,l,p,h,d,v=0,g=o(s);if(t.r=null,i&&r(a)&&(h=i(a),d=!0),e(a)||h)for(l=(h||a).length;l>v;v++){var m=v+n.list.index;if(g){if(p=d?s.call(f||this,a[h[v]],h[v],t):s.call(f||this,a[v],m,t),p!==c)return p}else if(s===a[d?h[v]:v])return h?h[v]:m}else for(v in a)if(g){if(u(a,v)&&(p=f?s.call(f,a[v],v,t):s(a[v],v,t),p!==c))return p}else if(s===a[v])return v;return g?t.r:n.list.index?0:-1}}(),n.time={},n.time.is=function(t){return t?t instanceof Date:+(new Date).getTime()};var o=n.fn.is,e=n.list.is,i=n.obj,r=i.is,u=i.has,a=i.map;t.exports=n})(t,"./type"),t(function(t){t.exports=function n(t,o,e){if(!t)return{to:n};var i,t=(this.tag||(this.tag={}))[t]||(this.tag[t]={tag:t,to:n._={next:function(t){var n;(n=this.to)&&n.next(t)}}});if(o instanceof Function){var r={off:n.off||(n.off=function(){return this.next===n._.next?!0:(this===this.the.last&&(this.the.last=this.back),this.to.back=this.back,this.next=n._.next,this.back.to=this.to,void(this.the.last===this.the&&delete this.on.tag[this.the.tag]))}),to:n._,next:o,the:t,on:this,as:e};return(r.back=t.last||t).to=r,t.last=r}return(t=t.to)&&i!==o&&t.next(o),t}})(t,"./onto"),t(function(t){function n(t,n,e,i,r){if(n>t)return{defer:!0};if(e>n)return{historical:!0};if(n>e)return{converge:!0,incoming:!0};if(n===e){if(i=o(i)||"",r=o(r)||"",i===r)return{state:!0};if(r>i)return{converge:!0,current:!0};if(i>r)return{converge:!0,incoming:!0}}return{err:"Invalid CRDT Data: "+i+" to "+r+" at "+n+" to "+e+"!"}}if("undefined"==typeof JSON)throw new Error("JSON is not included in this browser. Please load it first: ajax.cdnjs.com/ajax/libs/json2/20110223/json2.js");var o=JSON.stringify;t.exports=n})(t,"./HAM"),t(function(n){var o=t("./type"),e={};e.is=function(t){return t===i?!1:null===t?!0:t===1/0?!1:s(t)||u(t)||a(t)?!0:e.rel.is(t)||!1},e.link=e.rel={_:"#"},function(){function t(t,n){var o=this;return o.id?o.id=!1:n==r&&s(t)?void(o.id=t):o.id=!1}e.rel.is=function(n){if(n&&n[r]&&!n._&&c(n)){var o={};if(p(n,t,o),o.id)return o.id}return!1}}(),e.rel.ify=function(t){return l({},r,t)},o.obj.has._=".";var i,r=e.link._,u=o.bi.is,a=o.num.is,s=o.text.is,f=o.obj,c=f.is,l=f.put,p=f.map;n.exports=e})(t,"./val"),t(function(n){var o=t("./type"),e=t("./val"),i={_:"_"};i.soul=function(t,n){return t&&t._&&t._[n||p]},i.soul.ify=function(t,n){return n="string"==typeof n?{soul:n}:n||{},t=t||{},t._=t._||{},t._[p]=n.soul||t._[p]||l(),t},i.soul._=e.link._,function(){function t(t,n){return n!==i._?e.is(t)?void(this.cb&&this.cb.call(this.as,t,n,this.n,this.s)):!0:void 0}i.is=function(n,o,e){var r;return a(n)&&(r=i.soul(n))?!f(n,t,{as:e,cb:o,s:r,n:n}):!1}}(),function(){function t(t,n){var o,i,r=this.o;return r.map?(o=r.map.call(this.as,t,""+n,r.node),void(i===o?s(r.node,n):r.node&&(r.node[n]=o))):void(e.is(t)&&(r.node[n]=t))}i.ify=function(n,o,e){return o?"string"==typeof o?o={soul:o}:o instanceof Function&&(o={map:o}):o={},o.map&&(o.node=o.map.call(e,n,r,o.node||{})),(o.node=i.soul.ify(o.node||{},o))&&f(n,t,{o:o,as:e}),o.node}}();var r,u=o.obj,a=u.is,s=u.del,f=u.map,c=o.text,l=c.random,p=i.soul._;n.exports=i})(t,"./node"),t(function(n){function o(){var t;return t=r(),t>u?(a=0,u=t+o.drift):u=t+(a+=1)/s+o.drift}{var e=t("./type"),i=t("./node"),r=e.time.is,u=-(1/0),a=0,s=1e3,f="undefined"!=typeof performance?performance.timing&&performance:!1;f&&f.timing&&f.timing.navigationStart||(f=!1)}o._=">",o.drift=0,o.is=function(t,n,e){var i=n&&t&&t[_]&&t[_][o._]||e;if(i)return b(i=i[n])?i:-(1/0)},o.lex=function(){return o().toString(36).replace(".","")},o.ify=function(t,n,e,r,u){if(!t||!t[_]){if(!u)return;t=i.soul.ify(t,u)}var a=p(t[_],o._);return c!==n&&n!==_&&(b(e)&&(a[n]=e),c!==r&&(t[n]=r)),t},o.to=function(t,n,e){var r=t[n];return d(r)&&(r=g(r)),o.ify(e,n,o.is(t,n),r,i.soul(t))},function(){function t(t,n){_!==n&&o.ify(this.o,n,this.s)}o.map=function(n,e,i){var r,u=d(u=n||e)?u:null;return n=y(n=n||e)?n:null,u&&!n?(e=b(e)?e:o(),u[_]=u[_]||{},v(u,t,{o:u,s:e}),u):(i=i||d(e)?e:r,e=b(e)?e:o(),function(o,u,a,s){return n?(n.call(i||this||{},o,u,a,s),void(h(a,u)&&r===a[u]||t.call({o:a,s:e},o,u))):(t.call({o:a,s:e},o,u),o)})}}();var c,l=e.obj,p=l.as,h=l.has,d=l.is,v=l.map,g=l.copy,m=e.num,b=m.is,k=e.fn,y=k.is,_=i._;n.exports=o})(t,"./state"),t(function(n){var o=t("./type"),e=t("./val"),i=t("./node"),r={};!function(){function t(t,o){return t&&o===i.soul(t)&&i.is(t,this.fn,this.as)?void(this.cb&&(n.n=t,n.as=this.as,this.cb.call(n.as,t,o,n))):!0}function n(t){t&&i.is(n.n,t,n.as)}r.is=function(n,o,e,i){return n&&s(n)&&!l(n)?!h(n,t,{cb:o,fn:e,as:i}):!1}}(),function(){function t(t,o){var r;return(r=p(t,o))?r:(o.env=t,o.soul=a,i.ify(o.obj,n,o)&&(t.graph[e.rel.is(o.rel)]=o.node),o)}function n(n,o,r){var a,s,p=this,h=p.env;if(i._===o&&c(n,e.rel._))return r._;if(a=l(n,o,r,p,h)){if(o||(p.node=p.node||r||{},c(n,i._)&&i.soul(n)&&(p.node._=d(n._)),p.node=i.soul.ify(p.node,e.rel.is(p.rel)),p.rel=p.rel||e.rel.ify(i.soul(p.node))),(s=h.map)&&(s.call(h.as||{},n,o,r,p),c(r,o))){if(n=r[o],u===n)return void f(r,o);if(!(a=l(n,o,r,p,h)))return}if(!o)return p.node;if(!0===a)return n;if(s=t(h,{obj:n,path:p.path.concat(o)}),s.node)return s.rel}}function a(t){var n=this,o=e.link.is(n.rel),r=n.env.graph;n.rel=n.rel||e.rel.ify(t),n.rel[e.rel._]=t,n.node&&n.node[i._]&&(n.node[i._][e.rel._]=t),c(r,o)&&(r[t]=r[o],f(r,o))}function l(t,n,i,r,u){var a;return e.is(t)?!0:s(t)?1:(a=u.invalid)?(t=a.call(u.as||{},t,n,i),l(t,n,i,r,u)):(u.err="Invalid value at '"+r.path.concat(n).join(".")+"'!",void(o.list.is(t)&&(u.err+=" Use `.set(item)` instead of an Array.")))}function p(t,n){for(var o,e=t.seen,i=e.length;i--;)if(o=e[i],n.obj===o.obj)return o;e.push(n)}r.ify=function(n,o,i){var r={path:[],obj:n};return o?"string"==typeof o?o={soul:o}:o instanceof Function&&(o.map=o):o={},o.soul&&(r.rel=e.rel.ify(o.soul)),o.graph=o.graph||{},o.seen=o.seen||[],o.as=o.as||i,t(o,r),o.root=r.node,o.graph}}(),r.node=function(t){var n=i.soul(t);if(n)return p({},n,t)},function(){function t(t,n){var o,u;if(i._===n){if(l(t,e.rel._))return;return void(this.obj[n]=d(t))}return(o=e.rel.is(t))?(u=this.opt.seen[o])?void(this.obj[n]=u):void(this.obj[n]=this.opt.seen[o]=r.to(this.graph,o,this.opt)):void(this.obj[n]=t)}r.to=function(n,o,e){if(n){var i={};return e=e||{seen:{}},h(n[o],t,{obj:i,graph:n,opt:e}),i}}}();var u,a=(o.fn.is,o.obj),s=a.is,f=a.del,c=a.has,l=a.empty,p=a.put,h=a.map,d=a.copy;n.exports=r})(t,"./graph"),t(function(n){t("./onto"),n.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}var 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}}})(t,"./ask"),t(function(n){function o(t){var n={s:{}};return t=t||{max:1e3,age:9e3},n.check=function(t){var o;return(o=n.s[t])?o.pass?o.pass=!1:n.track(t):!1},n.track=function(o,r){var u=n.s[o]||(n.s[o]={});return u.was=i(),r&&(u.pass=!0),n.to||(n.to=setTimeout(function(){var o=i();e.obj.map(n.s,function(i,r){t.age>o-i.was||e.obj.del(n.s,r)}),n.to=null},t.age+9)),u},n}var e=t("./type"),i=e.time.is;n.exports=o})(t,"./dup"),t(function(n){function i(t){return t instanceof i?(this._={gun:this,$:this}).$:this instanceof i?i.create(this._={gun:this,$:this,opt:t}):new i(t)}i.is=function(t){return t instanceof i||t&&t._&&t===t._.$||!1},i.version=.9,i.chain=i.prototype,i.chain.toJSON=function(){};var r=t("./type");r.obj.to(r,i),i.HAM=t("./HAM"),i.val=t("./val"),i.node=t("./node"),i.state=t("./state"),i.graph=t("./graph"),i.on=t("./onto"),i.ask=t("./ask"),i.dup=t("./dup"),function(){function t(n){var o,e,r=this,a=r.as,s=a.at||a,f=s.$;return(e=n["#"])||(e=n["#"]=c(9)),(o=s.dup).check(e)?void(a.out===n.out&&(n.out=u,r.to.next(n))):(o.track(e),s.ask(n["@"],n)||(n.get&&i.on.get(n,f),n.put&&i.on.put(n,f)),r.to.next(n),void(a.out||(n.out=t,s.on("out",n))))}i.create=function(n){n.root=n.root||n,n.graph=n.graph||{},n.on=n.on||i.on,n.ask=n.ask||i.ask,n.dup=n.dup||i.dup();var o=n.$.opt(n.opt);return n.once||(n.on("in",t,n),n.on("out",t,{at:n,out:t}),i.on("create",n),n.on("create",n)),n.once=1,o}}(),function(){function t(t,n,o,e){var r=this,u=i.state.is(o,n);if(!u)return r.err="Error: No state on '"+n+"' in node '"+e+"'!";var a=r.graph[e]||k,s=i.state.is(a,n,!0),f=a[n],c=i.HAM(r.machine,u,s,t,f);return c.incoming?(r.put[e]=i.state.to(o,n,r.put[e]),(r.diff||(r.diff={}))[e]=i.state.to(o,n,r.diff[e]),void(r.souls[e]=!0)):void(c.defer&&(r.defer=u<(r.defer||1/0)?u:r.defer))}function n(t,n){var i=this,u=i.$._,a=(u.next||k)[n];if(!a){if(!(u.opt||k)["super"])return void(i.souls[n]=!1);a=i.$.get(n)._}var s=i.map[n]={put:t,get:n,$:a.$},f={ctx:i,msg:s};i.async=!!u.tag.node,i.ack&&(s["@"]=i.ack),v(t,o,f),i.async&&(i.and||u.on("node",function(t){this.to.next(t),t===i.map[t.get]&&(i.souls[t.get]=!1,v(t.put,e,t),v(i.souls,function(t){return t?t:void 0})||i.c||(i.c=1,this.off(),v(i.map,r,i)))}),i.and=!0,u.on("node",s))}function o(t,n){var o=this.ctx,e=o.graph,r=this.msg,u=r.get,a=r.put,s=r.$._;e[u]=i.state.to(a,n,e[u]),o.async||(s.put=i.state.to(a,n,s.put))}function e(t,n){var o=this,e=o.put,r=o.$._;r.put=i.state.to(e,n,r.put)}function r(t){t.$&&(this.cat.stop=this.stop,t.$._.on("in",t),this.cat.stop=null)}i.on.put=function(o,e){var a=e._,s={$:e,graph:a.graph,put:{},map:{},souls:{},machine:i.state(),ack:o["@"],cat:a,stop:{}};return i.graph.is(o.put,null,t,s)||(s.err="Error: Invalid graph!"),s.err?a.on("in",{"@":o["#"],err:i.log(s.err)}):(v(s.put,n,s),s.async||v(s.map,r,s),u!==s.defer&&setTimeout(function(){i.on.put(o,e)},s.defer-s.machine),void(s.diff&&a.on("put",d(o,{put:s.diff}))))},i.on.get=function(t,n){var o,e=n._,r=t.get[m],u=e.graph[r],a=t.get[b],s=e.next||(e.next={}),f=s[r];if(!u||!f)return e.on("get",t);if(a){if(!h(u,a))return e.on("get",t);u=i.state.to(u,a)}else u=i.obj.copy(u);u=i.graph.node(u),o=f.ack,e.on("in",{"@":t["#"],how:"mem",put:u,$:n}),e.on("get",t)}}(),function(){i.chain.opt=function(t){t=t||{};var n=this,o=n._,e=t.peers||t;return p(t)||(t={}),p(o.opt)||(o.opt=t),f(e)&&(e=[e]),a(e)&&(e=v(e,function(t,n,o){o(t,{url:t})}),p(o.opt.peers)||(o.opt.peers={}),o.opt.peers=d(e,o.opt.peers)),o.opt.peers=o.opt.peers||{},d(t,o.opt),i.on("opt",o),o.opt.uuid=o.opt.uuid||function(){return g()+c(12)},n}}();var u,a=i.list.is,s=i.text,f=s.is,c=s.random,l=i.obj,p=l.is,h=l.has,d=l.to,v=l.map,g=(l.copy,i.state.lex),m=i.val.rel._,b=".",k=(i.node._,i.val.link.is,{});o.debug=function(t,n){return o.debug.i&&t===o.debug.i&&o.debug.i++&&(o.log.apply(o,arguments)||n)},i.log=function(){return!i.log.off&&o.log.apply(o,arguments),[].slice.call(arguments).join(" ")},i.log.once=function(t,n,o){return(o=i.log.once)[t]=o[t]||0,o[t]++||i.log(n)},i.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=i);try{"undefined"!=typeof e&&(e.exports=i)}catch(y){}n.exports=i})(t,"./root"),t(function(){var n=t("./root");n.chain.back=function(t,i){var r;if(t=t||1,-1===t||1/0===t)return this._.root.$;if(1===t)return(this._.back||this._).$;var u=this,a=u._;if("string"==typeof t&&(t=t.split(".")),!(t instanceof Array)){if(t instanceof Function){for(var s,r={back:a};(r=r.back)&&o===(s=t(r,i)););return s}return n.num.is(t)?(a.back||a).$.back(t-1):this}var f=0,c=t.length,r=a;for(f;c>f;f++)r=(r||e)[t[f]];return o!==r?i?u:r:(r=a.back)?r.$.back(t,i):void 0};var o,e={}})(t,"./back"),t(function(){function n(t){var n,o,e,i=this.as,r=i.back,u=i.root;if(t.I||(t.I=i.$),t.$||(t.$=i.$),this.to.next(t),o=t.get){if(o["#"]||i.soul){if(o["#"]=o["#"]||i.soul,t["#"]||(t["#"]=b(9)),r=u.$.get(o["#"])._,o=o["."]){if(d(r.put,o)&&(n=r.$.get(o)._,(e=n.ack)||(n.ack=-1),r.on("in",{$:r.$,put:c.state.to(r.put,o),get:r.get}),e))return}else{if(e=r.ack,e||(r.ack=-1),d(r,"put")&&r.on("in",r),e)return;t.$=r.$}return u.ask(f,t),u.on("in",t)}if(u.now&&(u.now[i.id]=u.now[i.id]||!0,i.pass={}),o["."])return i.get?(t={get:{".":i.get},$:i.$},r.ask||(r.ask={}),r.ask[i.get]=t.$._,r.on("out",t)):(t={get:{},$:i.$},r.on("out",t));if(i.ack=i.ack||-1,i.get)return t.$=i.$,o["."]=i.get,(r.ask||(r.ask={}))[i.get]=t.$._,r.on("out",t)}return r.on("out",t)}function o(t){var n,o,r=this,s=r.as,f=s.root,h=t.$,b=(h||p)._||p,k=t.put;if(s.get&&t.get!==s.get&&(t=g(t,{get:s.get})),s.has&&b!==s&&(t=g(t,{$:s.$}),b.ack&&(s.ack=b.ack)),l===k){if(o=b.put,r.to.next(t),s.soul)return;if(l===o&&l!==b.put)return;return i(s,t,r),s.has&&a(s,t),v(b.echo,s.id),void v(s.map,b.id)}if(s.soul)return r.to.next(t),i(s,t,r),void(s.next&&m(k,u,{msg:t,cat:s}));if(!(n=c.val.link.is(k)))return c.val.is(k)?(s.has||s.soul?a(s,t):(b.has||b.soul)&&((b.echo||(b.echo={}))[s.id]=b.echo[b.id]||s,(s.map||(s.map={}))[b.id]=s.map[b.id]||{at:b}),r.to.next(t),void i(s,t,r)):(s.has&&b!==s&&d(b,"put")&&(s.put=b.put),(n=c.node.soul(k))&&b.has&&(b.put=s.root.$.get(n)._.put),o=(f.stop||{})[b.id],r.to.next(t),e(s,t,b,n),i(s,t,r),void(s.next&&m(k,u,{msg:t,cat:s})));f.stop;o=f.stop||{},o=o[b.id]||(o[b.id]={}),o.is=o.is||b.put,o[s.id]=b.put||!0,r.to.next(t),e(s,t,b,n),i(s,t,r)}function e(t,n,o,i){if(i&&k!==t.get){var r=t.root.$.get(i)._;t.has?o=r:o.has&&e(o,n,o,i),o!==t&&(o.$||(o={}),(o.echo||(o.echo={}))[t.id]=o.echo[t.id]||t,t.has&&!(t.map||p)[o.id]&&a(t,n),r=o.id?(t.map||(t.map={}))[o.id]=t.map[o.id]||{at:o}:{},(i!==r.link||r.pass||t.pass)&&(t.pass&&(c.obj.map(t.map,function(t){t.pass=!0}),v(t,"pass")),r.pass&&v(r,"pass"),t.has&&(t.link=i),s(t,r.link=i)))}}function i(t,n){t.echo&&m(t.echo,r,n)}function r(t){t&&t.on&&t.on("in",this)}function u(t,n){var o,e,i,r=this.cat,u=r.next||p,a=this.msg;(k!==n||u[n])&&(e=u[n])&&(e.has?(l!==e.put&&c.val.link.is(t)||(e.put=t),o=e.$):(i=a.$)&&(i=(o=a.$.get(n))._,l!==i.put&&c.val.link.is(t)||(i.put=t)),e.on("in",{put:t,get:n,$:o,via:a}))}function a(t,n){if(t.has||t.soul){{var o=t.map;t.root}t.map=null,t.has&&(t.link=null),(t.pass||n["@"]||null!==o)&&(l===o&&c.val.link.is(t.put)||(m(o,function(n){(n=n.at)&&v(n.echo,t.id)}),o=t.put,m(t.next,function(n,e){return l===o&&l!==t.put?!0:(n.put=l,n.ack&&(n.ack=-1),void n.on("in",{get:e,$:n.$,put:l}))})))}}function s(t,n){var o=t.root.$.get(n)._;(!t.ack||(o.on("out",{get:{"#":n}}),t.ask))&&(o=t.ask,c.obj.del(t,"ask"),m(o||t.next,function(t,o){t.on("out",{get:{"#":n,".":o}})}),c.obj.del(t,"ask"))}function f(t){var n=this.as,o=n.get||p,e=n.$._,i=(t.put||p)[o["#"]];if(e.ack&&(e.ack=e.ack+1||1),!t.put||o["."]&&!d(i,e.get)){if(e.put!==l)return;return void e.on("in",{get:e.get,put:e.put=l,$:e.$,"@":t["@"]})}return k==o["."]?void e.on("in",{get:e.get,put:c.val.link.ify(o["#"]),$:e.$,"@":t["@"]}):(t.$=e.root.$,void c.on.put(t,e.root.$))}var c=t("./root");c.chain.chain=function(t){var e,i=this,r=i._,u=new(t||i).constructor(i),a=u._;return a.root=e=r.root,a.id=++e.once,a.back=i._,a.on=c.on,a.on("in",o,a),a.on("out",n,a),u};var l,p={},h=c.obj,d=h.has,v=(h.put,h.del),g=h.to,m=h.map,b=c.text.random,k=(c.val.rel._,c.node._)})(t,"./chain"),t(function(){function n(t,n){var o=n._,e=o.next,i=n.chain(),r=i._;return e||(e=o.next={}),e[r.get=t]=r,n===o.root.$?r.soul=t:(o.soul||o.has)&&(r.has=t),r}function o(t,n,o,e){var i,r=t._;return(i=r.soul)?(n(i,e,r),t):(i=r.link)?(n(i,e,r),t):(t.get(function(t,o){o.rid(t);var r=(r=t.$)&&r._||{};i=r.link||r.soul||c.is(t.put)||l(t.put),n(i,e,t,o)},{out:{get:{".":!0}}}),t)}function e(t){var n,o=this,e=o.as,i=e.at,r=i.root,a=t.$,f=(a||{})._||{},l=t.put||f.put;if((n=r.now)&&o!==n[e.now])return o.to.next(t);if(o.seen&&f.id&&o.seen[f.id])return o.to.next(t);if((n=l)&&n[c._]&&(n=c.is(n))&&(n=(t.$$=f.root.gun.get(n))._,u!==n.put&&(t=s(t,{put:l=n.put}))),(n=r.mum)&&f.id){if(n[f.id])return;u===l||c.is(l)||(n[f.id]=!0)}return e.use(t,o),o.stun?void(o.stun=null):void o.to.next(t)}function i(t){var n=this.on;if(!t||n.soul||n.has)return this.off();if(t=(t=(t=t.$||t)._||t).id){{var o,e;n.map}return(o=(e=this.seen||(this.seen={}))[t])?!0:void(e[t]=!0)}}var r=t("./root");r.chain.get=function(t,u,a){var s,l;if("string"!=typeof t){if(t instanceof Function){if(!0===u)return o(this,t,u,a);s=this;var h,d=s._,v=d.root,l=v.now;a=u||{},a.at=d,a.use=t,a.out=a.out||{},a.out.get=a.out.get||{},(h=d.on("in",e,a)).rid=i,(v.now={$:1})[a.now=d.id]=h;var g=v.mum;return v.mum={},d.on("out",a.out),v.mum=g,v.now=l,s}return f(t)?this.get(""+t,u,a):(l=c.is(t))?this.get(l,u,a):((a=this.chain())._.err={err:r.log("Invalid get request!",t)},u&&u.call(a,a._.err),a)}var m=this,b=m._,k=b.next||p;return(s=k[t])||(s=n(t,m)),s=s.$,(l=b.stun)&&(s._.stun=s._.stun||l),u&&u instanceof Function&&s.get(u,a),s};var u,a=r.obj,s=(a.has,r.obj.to),f=r.num.is,c=r.val.link,l=r.node.soul,p=(r.node._,{})})(t,"./get"),t(function(){function n(t){t.batch=i;var n=t.opt||{},o=t.env=c.state.map(u,n.state);return o.soul=t.soul,t.graph=c.graph.ify(t.data,o,t),o.err?((t.ack||m).call(t,t.out={err:c.log(o.err)}),void(t.res&&t.res())):void t.batch()}function e(t){return void(t&&t())}function i(){var t=this;t.graph&&!v(t.stun,r)&&(t.res=t.res||function(t){t&&t()},t.res(function(){var n=t.$.back(-1)._,o=n.ask(function(o){n.root.on("ack",o),o.err&&c.log(o),o.lack||this.off(),t.ack&&t.ack(o,this)},t.opt),e=n.root.now;p.del(n.root,"now");var i=n.root.mum;n.root.mum={},t.ref._.on("out",{$:t.ref,put:t.out=t.env.graph,opt:t.opt,"#":o}),n.root.mum=i?p.to(i,n.root.mum):i,n.root.now=e},t),t.res&&t.res())}function r(t){return t?!0:void 0}function u(t,n,o,e){var i=this,r=c.is(t);!n&&e.path.length&&(i.res||b)(function(){var n=e.path,o=i.ref,u=(i.opt,0),s=n.length;for(u;s>u;u++)o=o.get(n[u]);r&&(o=t);var f=o._.dub;return f||(f=c.node.soul(e.obj))?(o.back(-1).get(f),void e.soul(f)):((i.stun=i.stun||{})[n]=!0,void o.get(a,!0,{as:{at:e,as:i,p:n}}))},{as:i,at:e})}function a(t,n,o,e){var n=n.as,i=n.at;n=n.as;var r=((o||{}).$||{})._||{};return t=r.dub=r.dub||t||c.node.soul(i.obj)||c.node.soul(o.put||r.put)||c.val.rel.is(o.put||r.put)||(n.via.back("opt.uuid")||c.text.random)(),e&&(e.stun=!0),t?void s(r,r.dub=t,i,n):void r.via.back("opt.uuid")(function(t,o){return t?c.log(t):void s(r,r.dub=r.dub||o,i,n)})}function s(t,n,o,e){t.$.back(-1).get(n),o.soul(n),e.stun[o.path]=!1,e.batch()}function f(t,n,e,i){if(n=n.as,e.$&&e.$._){if(e.err)return void o.log("Please report this as an issue! Put.any.err");var r,u=e.$._,a=u.put,s=n.opt||{};if(!(r=n.ref)||!r._.now){if(i&&(i.stun=!0),n.ref!==n.$){if(r=n.$._.get||u.get,!r)return void o.log("Please report this as an issue! Put.no.get");n.data=d({},r,n.data),r=null}if(l===a){if(!u.get)return;t||(r=u.$.back(function(t){return t.link||t.soul?t.link||t.soul:void(n.data=d({},t.get,n.data))})),r=r||u.get,u=u.root.$.get(r)._,n.soul=r,a=n.data}return n.not||(n.soul=n.soul||t)||(n.path&&h(n.data)?n.soul=(s.uuid||n.via.back("opt.uuid")||c.text.random)():(k==u.get&&(n.soul=(u.put||g)["#"]||u.dub),n.soul=n.soul||u.soul||u.soul||(s.uuid||n.via.back("opt.uuid")||c.text.random)()),n.soul)?void n.ref.put(n.data,n.soul,n):void n.via.back("opt.uuid")(function(t,o){return t?c.log(t):void n.ref.put(n.data,n.soul=o,n)})}}}var c=t("./root");c.chain.put=function(t,o,i){var r,u=this,a=u._,s=a.root.$;return i=i||{},i.data=t,i.via=i.$=i.via||i.$||u,"string"==typeof o?i.soul=o:i.ack=i.ack||o,a.soul&&(i.soul=a.soul),i.soul||s===u?h(i.data)?(i.soul=i.soul||(i.not=c.node.soul(i.data)||(i.via.back("opt.uuid")||c.text.random)()),i.soul?(i.$=u=s.get(i.soul),i.ref=i.$,n(i),u):(i.via.back("opt.uuid")(function(t,n){return t?c.log(t):void(i.ref||i.$).put(i.data,i.soul=n,i)}),u)):((i.ack||m).call(i,i.out={err:c.log("Data saved to the root level of the graph must be a node (an object), not a",typeof i.data,'of "'+i.data+'"!')}),i.res&&i.res(),u):c.is(t)?(t.get(function(t,n,e){return!t&&c.val.is(e.put)?c.log("The reference you are saving is a",typeof e.put,'"'+e.put+'", not a node (object)!'):void u.put(c.val.rel.ify(t),o,i)},!0),u):(i.ref=i.ref||s._===(r=a.back)?u:r.$,i.ref._.soul&&c.val.is(i.data)&&a.get?(i.data=d({},a.get,i.data),i.ref.put(i.data,i.soul,i),u):(i.ref.get(f,!0,{as:i}),i.out||(i.res=i.res||e,i.$._.stun=i.ref._.stun),u))};var l,p=c.obj,h=p.is,d=p.put,v=p.map,g={},m=function(){},b=function(t,n){t.call(n||g)},k=c.node._})(t,"./put"),t(function(n){var o=t("./root");t("./chain"),t("./back"),t("./put"),t("./get"),n.exports=o})(t,"./index"),t(function(){function n(t,n){{var o,e=this,r=t.$,u=(r||{})._||{},a=u.put||t.put;e.at}if(i!==a){if(o=t.$$){if(o=t.$$._,i===o.put)return;a=o.put}e.change&&(a=t.put),e.as?e.ok.call(e.as,t,n):e.ok.call(r,a,t.get,t,n)}}function o(t,n,e){var r,u,a=this.as,s=(a.at,t.$),f=s._,c=f.put||t.put;if(u=t.$$){if(r=u=t.$$._,i===u.put)return;c=u.put}return(u=n.wait)&&(u=u[f.id])&&clearTimeout(u),e||i!==c&&!f.soul&&!f.link&&(!r||0 .once, apologies unexpected."),this.once(t,n)},e.chain.once=function(t,n){var r=this,u=r._,a=u.put;if(0=(n.batch||1e3)?s():void(e||(e=setTimeout(s,n.wait||1)))}),t.on("get",function(o){function e(){if(s&&(i=s["#"])){var e=s["."];r=u[i]||a,r&&e&&(r=Gun.state.to(r,e)),(r||Gun.obj.empty(n.peers))&&t.on("in",{"@":o["#"],put:Gun.graph.node(r),how:"lS",lS:o.I})}}this.to.next(o);var i,r,a,s=o.get;Gun.debug?setTimeout(e,1):e()});var a=function(t,n,o,e){u[e]=Gun.state.to(o,n,u[e])},s=function(a){var f;r=0,clearTimeout(e),e=!1;var c=i;i={},a&&(u=a);try{o.setItem(n.file,JSON.stringify(u))}catch(l){Gun.log(f=l||"localStorage failure"),t.on("localStorage:error",{err:f,file:n.file,flush:u,retry:s})}(f||Gun.obj.empty(n.peers))&&Gun.obj.map(c,function(n,o){t.on("in",{"@":o,err:f,ok:0})})}}})}})(t,"./adapters/localStorage"),t(function(n){function o(t){var n=function(){};return n.out=function(o){var e;return this.to&&this.to.next(o),(e=o["@"])&&(e=t.dup.s[e])&&(e=e.it)&&e.mesh?(n.say(o,e.mesh.via),void(e["##"]=o["##"])):void n.say(o)},n.hear=function(o,i){if(o){var r,u,a,s=t.dup,f=o[0];try{a=JSON.parse(o)}catch(c){}if("{"===f){if(!a)return;if(s.check(r=a["#"]))return;if(s.track(r,!0).it=a,(f=a["@"])&&a.put&&(u=a["##"]||(a["##"]=n.hash(a)),(f+=u)!=r)){if(s.check(f))return;(f=s.s)[u]=f[r]}return(a.mesh=function(){}).via=i,(f=a["><"])&&(a.mesh.to=e.obj.map(f.split(","),function(t,n,o){o(t,!0)})),void t.on("in",a)}if("["!==f);else{if(!a)return;for(var l,p=0;l=a[p++];)n.hear(l,i)}}},function(){function o(t,n){var o=n.wire;try{o.send?o.readyState===o.OPEN?o.send(t):(n.queue=n.queue||[]).push(t):n.say&&n.say(t)}catch(e){(n.queue=n.queue||[]).push(t)}}n.say=function(i,u){if(!u)return void e.obj.map(t.opt.peers,function(t){n.say(i,t)});var a,s,f,c=u.wire||t.opt.wire&&t.opt.wire(u);if(c&&(s=i.mesh||r,u!==s.via&&((f=s.raw)||(f=n.raw(i)),!((a=i["@"])&&(a=t.dup.s[a])&&(a=a.it)&&a.get&&a["##"]&&a["##"]===i["##"]||(a=s.to)&&(a[u.url]||a[u.id]))))){if(u.batch)return void u.batch.push(f);u.batch=[],setTimeout(function(){var t=u.batch;t&&(u.batch=null,t.length&&o(JSON.stringify(t),u))},t.opt.gap||t.opt.wait||1),o(f,u)}}}(),function(){function r(t,n){var o;return n instanceof Object?(e.obj.map(Object.keys(n).sort(),u,{to:o={},on:n}),o):n}function u(t){this.to[t]=this.on[t]}n.raw=function(o){if(!o)return"";var u,f,c,l=t.dup,p=o.mesh||{};if(c=p.raw)return c;if("string"==typeof o)return o;o["@"]&&(c=o.put)&&((f=o["##"])||(u=a(c,r)||"",f=n.hash(o,u),o["##"]=f),(c=l.s)[f=o["@"]+f]=c[o["#"]],o["#"]=f||o["#"],u&&((o=e.obj.to(o)).put=s));var h=0,d=[];e.obj.map(t.opt.peers,function(t){return d.push(t.url||t.id),++h>9?!0:void 0}),o["><"]=d.join();var v=a(o);return i!==u&&(v=v.replace('"'+s+'"',u)),p&&(p.raw=v),v},n.hash=function(t,n){return o.hash(n||a(t.put,r)||"")||t["#"]||e.text.random(9)};var a=JSON.stringify,s=":])([:"}(),n.hi=function(o){t.on("hi",o);var i=o.queue;o.queue=[],e.obj.map(i,function(t){n.say(t,o)})},n}var e=t("../type");o.hash=function(t){if("string"!=typeof t)return{err:1};var n=0;if(!t.length)return n;for(var o,e=0,i=t.length;i>e;++e)o=t.charCodeAt(e),n=(n<<5)-n+o,n|=0;return n};var i,r={};Object.keys=Object.keys||function(t){return map(t,function(t,n,o){o(n)})};try{n.exports=o}catch(u){}})(t,"./adapters/mesh"),t(function(){var n=t("../index");n.Mesh=t("./mesh"),n.on("opt",function(t){function o(n){if(n&&n.url){var o=n.url.replace("http","ws"),u=n.wire=new i.WebSocket(o);return u.onclose=function(){t.on("bye",n),e(n)},u.onerror=function(t){e(n),t&&"ECONNREFUSED"===t.code},u.onopen=function(){a.hi(n)},u.onmessage=function(t){t&&(r.inLength=(r.inLength||0)+(t.data||t).length,a.hear(t.data||t,n))},u}}function e(t){clearTimeout(t.defer),t.defer=setTimeout(function(){o(t)},2e3)}this.to.next(t);var i=t.opt;if(!t.once&&!1!==i.WebSocket){var r;"undefined"!=typeof window&&(r=window),"undefined"!=typeof global&&(r=global),r=r||{};var u=i.WebSocket||r.WebSocket||r.webkitWebSocket||r.mozWebSocket;if(u){i.WebSocket=u;var a=i.mesh=i.mesh||n.Mesh(t);t.on("create",function(n){this.to.next(n),t.on("out",a.out)}),i.wire=i.wire||o}}})})(t,"./adapters/websocket")}(); \ No newline at end of file +!function(){var t;"undefined"!=typeof window&&(t=window),"undefined"!=typeof global&&(t=global);var b=(t=t||{}).console||{log:function(){}};function _(o){return 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 f=module;_(function(t){var p={fn:{is:function(t){return!!t&&"function"==typeof t}}};p.bi={is:function(t){return t instanceof Boolean||"boolean"==typeof t}},p.num={is:function(t){return!d(t)&&(0<=t-parseFloat(t)+1||1/0===t||-1/0===t)}},p.text={is:function(t){return"string"==typeof t}},p.text.ify=function(t){return p.text.is(t)?t:"undefined"!=typeof JSON?JSON.stringify(t):t&&t.toString?t.toString():t},p.text.random=function(t,n){var o="";for(t=t||24,n=n||"0123456789ABCDEFGHIJKLMNOPQRSTUVWXZabcdefghijklmnopqrstuvwxyz";0")){if(!(n>t[">"]))return!1;o=!0}if(p.obj.has(t,"<")){if(!(n",s.drift=0,s.is=function(t,n,o){var e=n&&t&&t[m]&&t[m][s._]||o;if(e)return g(e=e[n])?e:-1/0},s.lex=function(){return s().toString(36).replace(".","")},s.ify=function(t,n,o,e,i){if(!t||!t[m]){if(!i)return;t=a.soul.ify(t,i)}var r=c(t[m],s._);return void 0!==n&&n!==m&&(g(o)&&(r[n]=o),void 0!==e&&(t[n]=e)),t},s.to=function(t,n,o){var e=t[n];return p(e)&&(e=d(e)),s.ify(o,n,s.is(t,n),e,a.soul(t))},function(){function u(t,n){m!==n&&s.ify(this.o,n,this.s)}s.map=function(i,r,a){var t=p(t=i||r)?t:null;return i=v(i=i||r)?i:null,t&&!i?(r=g(r)?r:s(),t[m]=t[m]||{},h(t,u,{o:t,s:r}),t):(a=a||p(r)?r:void 0,r=g(r)?r:s(),function(t,n,o,e){if(!i)return u.call({o:o,s:r},t,n),t;i.call(a||this||{},t,n,o,e),l(o,n)&&void 0===o[n]||u.call({o:o,s:r},t,n)})}}();var f=n.obj,c=f.as,l=f.has,p=f.is,h=f.map,d=f.copy,g=n.num.is,v=n.fn.is,m=a._;t.exports=s})(_,"./state"),_(function(t){var a=_("./type"),f=_("./val"),c=_("./node"),r={};!function(){function i(t,n){if(!t||n!==c.soul(t)||!c.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&&c.is(o.n,t,o.as)}r.is=function(t,n,o,e){return!(!t||!l(t)||u(t))&&!s(t,i,{cb:n,fn:o,as:e})}}(),function(){function u(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=i,c.ify(n.obj,e,n)&&(t.graph[f.rel.is(n.rel)]=n.node),n)}function e(t,n,o){var e,i,r=this,a=r.env;if(c._===n&&h(t,f.rel._))return o._;if(e=s(t,n,o,r,a)){if(n||(r.node=r.node||o||{},h(t,c._)&&c.soul(t)&&(r.node._=d(t._)),r.node=c.soul.ify(r.node,f.rel.is(r.rel)),r.rel=r.rel||f.rel.ify(c.soul(r.node))),(i=a.map)&&(i.call(a.as||{},t,n,o,r),h(o,n))){if(void 0===(t=o[n]))return void p(o,n);if(!(e=s(t,n,o,r,a)))return}if(!n)return r.node;if(!0===e)return t;if((i=u(a,{obj:t,path:r.path.concat(n)})).node)return i.rel}}function i(t){var n=this,o=f.link.is(n.rel),e=n.env.graph;n.rel=n.rel||f.rel.ify(t),n.rel[f.rel._]=t,n.node&&n.node[c._]&&(n.node[c._][f.rel._]=t),h(e,o)&&(e[t]=e[o],p(e,o))}function s(t,n,o,e,i){var r;return!!f.is(t)||(l(t)?1:(r=i.invalid)?s(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."))))}r.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.rel=f.rel.ify(n.soul)),n.graph=n.graph||{},n.seen=n.seen||[],n.as=n.as||o,u(n,e),n.root=e.node,n.graph}}(),r.node=function(t){var n=c.soul(t);if(n)return o({},n,t)},function(){function i(t,n){var o,e;if(c._!==n)(o=f.rel.is(t))?(e=this.opt.seen[o])?this.obj[n]=e:this.obj[n]=this.opt.seen[o]=r.to(this.graph,o,this.opt):this.obj[n]=t;else{if(u(t,f.rel._))return;this.obj[n]=d(t)}}r.to=function(t,n,o){if(t){var e={};return o=o||{seen:{}},s(t[n],i,{obj:e,graph:t,opt:o}),e}}}();a.fn.is;var n=a.obj,l=n.is,p=n.del,h=n.has,u=n.empty,o=n.put,s=n.map,d=n.copy;t.exports=r})(_,"./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){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");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"),function(){function a(t){var n,o,e=this.as,i=e.at||e,r=i.$;(o=t["#"])||(o=t["#"]=u(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)))}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}}(),function(){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]||v,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||v)[n];if(!i){if(!(e.opt||v).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),h(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,h(t.put,s,t),h(o.souls,function(t){if(t)return t})||o.c||(o.c=1,this.off(),h(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)}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)});h(e.put,r,e),e.async||h(e.map,f,e),void 0!==e.defer&&setTimeout(function(){c.on.put(t,n)},e.defer-e.machine),e.diff&&o.on("put",p(t,{put:e.diff}))},c.on.get=function(t,n){var o=n._,e=t.get[d],i=o.graph[e],r=t.get[g],a=(o.next||(o.next={}))[e];if(!i||!a)return o.on("get",t);if(r){if(!l(i,r))return o.on("get",t);i=c.state.to(i,r)}else i=c.obj.copy(i);i=c.graph.node(i),a.ack,o.on("in",{"@":t["#"],how:"mem",put:i,$:n}),o.on("get",t)}}(),c.chain.opt=function(t){t=t||{};var n=this._,o=t.peers||t;return a(t)||(t={}),a(n.opt)||(n.opt=t),i(o)&&(o=[o]),e(o)&&(o=h(o,function(t,n,o){o(t,{url:t})}),a(n.opt.peers)||(n.opt.peers={}),n.opt.peers=p(o,n.opt.peers)),n.opt.peers=n.opt.peers||{},p(t,n.opt),c.on("opt",n),n.opt.uuid=n.opt.uuid||function(){return s()+u(12)},this};var e=c.list.is,o=c.text,i=o.is,u=o.random,r=c.obj,a=r.is,l=r.has,p=r.to,h=r.map,s=(r.copy,c.state.lex),d=c.val.rel._,g=".",v=(c.node._,c.val.link.is,{});b.debug=function(t,n){return b.debug.i&&t===b.debug.i&&b.debug.i++&&(b.log.apply(b,arguments)||n)},(c.log=function(){return!c.log.off&&b.log.apply(b,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=c);try{void 0!==f&&(f.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 .once, apologies unexpected."),this.once(t,n)},a.chain.once=function(t,n){var o=this,e=o._,i=e.put;if(0=(a.batch||1e3))return f();e||(e=setTimeout(f,a.wait||1))}),r.on("get",function(n){this.to.next(n);var o,e,i=n.get;function t(){if(i&&(o=i["#"])){var t=i["."];(e=s[o]||void 0)&&t&&(e=Gun.state.to(e,t)),(e||Gun.obj.empty(a.peers))&&r.on("in",{"@":n["#"],put:Gun.graph.node(e),how:"lS",lS:n.I})}}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(e),e=!1;var n=i;i={},t&&(s=t);try{c.setItem(a.file,JSON.stringify(s))}catch(t){Gun.log(o=t||"localStorage failure"),r.on("localStorage:error",{err:o,file:a.file,flush:s,retry:f})}(o||Gun.obj.empty(a.peers))&&Gun.obj.map(n,function(t,n){r.on("in",{"@":n,err:o,ok:0})})}}})}})(_,"./adapters/localStorage"),_(function(t){var d=_("../type");function o(p){var h=function(){};return h.out=function(t){var n;if(this.to&&this.to.next(t),(n=t["@"])&&(n=p.dup.s[n])&&(n=n.it)&&n.mesh)return h.say(t,n.mesh.via),void(n["##"]=t["##"]);h.say(t)},h.hear=function(t,n){if(t){var o,e,i,r=p.dup,a=t[0];try{i=JSON.parse(t)}catch(t){}if("{"===a){if(!i)return;if(r.check(o=i["#"]))return;if((a=(r.track(o,!0).it=i)["@"])&&i.put&&(a+=e=i["##"]||(i["##"]=h.hash(i)))!=o){if(r.check(a))return;(a=r.s)[e]=a[o]}return(i.mesh=function(){}).via=n,(a=i["><"])&&(i.mesh.to=d.obj.map(a.split(","),function(t,n,o){o(t,!0)})),void p.on("in",i)}if("["!==a);else{if(!i)return;for(var u,s=0;u=i[s++];)h.hear(u,n)}}},function(){function r(n,o){var t=o.wire;try{t.send?t.readyState===t.OPEN?t.send(n):(o.queue=o.queue||[]).push(n):o.say&&o.say(n)}catch(t){(o.queue=o.queue||[]).push(n)}}h.say=function(n,o){var t,e,i;o?(o.wire||p.opt.wire&&p.opt.wire(o))&&(e=n.mesh||a,o!==e.via&&((i=e.raw)||(i=h.raw(n)),(t=n["@"])&&(t=p.dup.s[t])&&(t=t.it)&&t.get&&t["##"]&&t["##"]===n["##"]||(t=e.to)&&(t[o.url]||t[o.id])||(o.batch?o.batch.push(i):(o.batch=[],setTimeout(function(){var t=o.batch;t&&(o.batch=null,t.length&&r(JSON.stringify(t),o))},p.opt.gap||p.opt.wait||1),r(i,o))))):d.obj.map(p.opt.peers,function(t){h.say(n,t)})}}(),function(){function f(t,n){var o;return n instanceof Object?(d.obj.map(Object.keys(n).sort(),e,{to:o={},on:n}),o):n}function e(t){this.to[t]=this.on[t]}h.raw=function(t){if(!t)return"";var n,o,e,i=p.dup,r=t.mesh||{};if(e=r.raw)return e;if("string"==typeof t)return t;t["@"]&&(e=t.put)&&((o=t["##"])||(n=c(e,f)||"",o=h.hash(t,n),t["##"]=o),(e=i.s)[o=t["@"]+o]=e[t["#"]],t["#"]=o||t["#"],n&&((t=d.obj.to(t)).put=l));var a=0,u=[];d.obj.map(p.opt.peers,function(t){if(u.push(t.url||t.id),9<++a)return!0}),t["><"]=u.join();var s=c(t);return g!==n&&(s=s.replace('"'+l+'"',n)),r&&(r.raw=s),s},h.hash=function(t,n){return o.hash(n||c(t.put,f)||"")||t["#"]||d.text.random(9)};var c=JSON.stringify,l=":])([:"}(),h.hi=function(n){p.on("hi",n);var t=n.queue;n.queue=[],d.obj.map(t,function(t){h.say(t,n)})},h}o.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 Date: Mon, 30 Jul 2018 08:53:00 -0700 Subject: [PATCH 085/221] CHANGE DEFAULT PORT TO 8765 --- Dockerfile | 1 + README.md | 8 +- examples/angular/server.js | 2 +- examples/express.js | 2 +- examples/hapi.js | 2 +- examples/http-external-ws.js | 2 +- examples/http.js | 2 +- examples/install.sh | 2 +- examples/react/server.js | 4 +- examples/social.html | 4 +- examples/vue/index.html | 2 +- lib/tmp.test.sql.js | 2 +- package.json | 2 +- test/debug/deep-set.html | 2 +- test/gun.html | 3 +- test/https/test.js | 2 +- test/panic/b2s2s2b.js | 2 +- test/panic/curl-server.js | 2 +- test/panic/e2e/distributed.js | 6 +- test/panic/e2e/holy/grail.js | 2 +- test/panic/e2e/holy/index.html | 2 +- test/panic/e2e/holy/ports.json | 2 +- test/panic/holy-grail.js | 2 +- test/panic/load.js | 2 +- test/panic/radisk.js | 2 +- test/panic/s2s-all-delayed-peer-add.js | 2 +- test/panic/s2s-all.js | 2 +- test/panic/scale.js | 2 +- test/panic/set.js | 2 +- test/panic/speak.js | 2 +- test/panic/users.js | 2 +- test/panic/who.js | 2 +- test/ptsd/spam.js | 2 +- test/server/http.js | 4 +- test/server/node-client.js | 2 +- test/server/node-write.js | 2 +- test/tmp/bigsync.js | 31 ++++++ test/tmp/contact.html | 87 +++++++++++++++ test/tmp/li.html | 142 +++++++++++++++++++++++++ test/tmp/nab.html | 101 ++++++++++++++++++ test/{ => tmp}/radisk.html | 10 +- test/{ => tmp}/say.html | 0 test/tmp/tables.html | 130 ++++++++++++++++++++++ test/tmp/time.html | 60 +++++++++++ test/{ => tmp}/user.html | 6 +- 45 files changed, 603 insertions(+), 52 deletions(-) create mode 100644 test/tmp/bigsync.js create mode 100644 test/tmp/contact.html create mode 100644 test/tmp/li.html create mode 100644 test/tmp/nab.html rename test/{ => tmp}/radisk.html (85%) rename test/{ => tmp}/say.html (100%) create mode 100644 test/tmp/tables.html create mode 100644 test/tmp/time.html rename test/{ => tmp}/user.html (87%) diff --git a/Dockerfile b/Dockerfile index c11fc7a3..7eb3a7cd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -22,4 +22,5 @@ RUN apk update && apk upgrade \ && npm install \ && apk del .build-dependencies && rm -rf /var/cache/* /tmp/npm* EXPOSE 8080 +EXPOSE 8765 CMD ["npm","start"] diff --git a/README.md b/README.md index 6e5b1cd0..81bb0b3b 100644 --- a/README.md +++ b/README.md @@ -188,7 +188,7 @@ Then visit the URL in the output of the 'now --npm' step, in your browser. Pull from the [Docker Hub](https://hub.docker.com/r/gundb/gun/) [![](https://images.microbadger.com/badges/commit/gundb/gun.svg)](https://microbadger.com/images/gundb/gun). Or: ```bash -docker run -p 8080:8080 gundb/gun +docker run -p 8765:8765 gundb/gun ``` Or build the [Docker](https://docs.docker.com/engine/installation/) image locally: @@ -197,17 +197,17 @@ Or build the [Docker](https://docs.docker.com/engine/installation/) image locall git clone https://github.com/amark/gun.git cd gun docker build -t myrepo/gundb:v1 . -docker run -p 8080:8080 myrepo/gundb:v1 +docker run -p 8765:8765 myrepo/gundb:v1 ``` Or, if you prefer your Docker image with metadata labels (Linux/Mac only): ```bash npm run docker -docker run -p 8080:8080 username/gun:git +docker run -p 8765:8765 username/gun:git ``` -Then visit [http://localhost:8080](http://localhost:8080) in your browser. +Then visit [http://localhost:8765](http://localhost:8765) in your browser. ## License diff --git a/examples/angular/server.js b/examples/angular/server.js index f1d1c55e..f8a1978b 100644 --- a/examples/angular/server.js +++ b/examples/angular/server.js @@ -1,4 +1,4 @@ -var port = process.env.OPENSHIFT_NODEJS_PORT || process.env.VCAP_APP_PORT || process.env.PORT || process.argv[2] || 8080; +var port = process.env.OPENSHIFT_NODEJS_PORT || process.env.VCAP_APP_PORT || process.env.PORT || process.argv[2] || 8765; var host = process.env.OPENSHIFT_NODEJS_HOST || process.env.VCAP_APP_HOST || process.env.HOST || 'localhost'; var express = require('express'); diff --git a/examples/express.js b/examples/express.js index 04225202..81e689c3 100644 --- a/examples/express.js +++ b/examples/express.js @@ -1,5 +1,5 @@ console.log("If module not found, install express globally `npm i express -g`!"); -var port = process.env.OPENSHIFT_NODEJS_PORT || process.env.VCAP_APP_PORT || process.env.PORT || process.argv[2] || 8080; +var port = process.env.OPENSHIFT_NODEJS_PORT || process.env.VCAP_APP_PORT || process.env.PORT || process.argv[2] || 8765; var express = require('express'); var Gun = require('..'); diff --git a/examples/hapi.js b/examples/hapi.js index d40b9af1..a4bcca9e 100644 --- a/examples/hapi.js +++ b/examples/hapi.js @@ -5,7 +5,7 @@ const Inert = require('inert') const Gun = require('..') const server = new Hapi.Server({ - port: 8080, + port: 8765, host: 'localhost', routes: { files: { diff --git a/examples/http-external-ws.js b/examples/http-external-ws.js index f59819e3..c0d909d2 100644 --- a/examples/http-external-ws.js +++ b/examples/http-external-ws.js @@ -1,4 +1,4 @@ -var port = process.env.OPENSHIFT_NODEJS_PORT || process.env.VCAP_APP_PORT || process.env.PORT || process.argv[2] || 8080; +var port = process.env.OPENSHIFT_NODEJS_PORT || process.env.VCAP_APP_PORT || process.env.PORT || process.argv[2] || 8765; var Gun = require('../'); diff --git a/examples/http.js b/examples/http.js index defc3122..c915028a 100644 --- a/examples/http.js +++ b/examples/http.js @@ -1,4 +1,4 @@ -var port = process.env.OPENSHIFT_NODEJS_PORT || process.env.VCAP_APP_PORT || process.env.PORT || process.argv[2] || 8080 || 8765; +var port = process.env.OPENSHIFT_NODEJS_PORT || process.env.VCAP_APP_PORT || process.env.PORT || process.argv[2] || 8765; var Gun = require('../'); diff --git a/examples/install.sh b/examples/install.sh index e38f6e25..f88f0661 100644 --- a/examples/install.sh +++ b/examples/install.sh @@ -24,4 +24,4 @@ npm install gun # to run the gun examples: cd ./node_modules/gun npm install . -sudo /usr/local/bin/node ./examples/http.js 80 # change `80` to `8080` for development purposes. +sudo /usr/local/bin/node ./examples/http.js 80 # change `80` to `8765` for development purposes. diff --git a/examples/react/server.js b/examples/react/server.js index 20f87ad0..60f5ff62 100644 --- a/examples/react/server.js +++ b/examples/react/server.js @@ -1,5 +1,5 @@ console.log("If modules not found, run `npm install` in /example folder!"); -var port = process.env.OPENSHIFT_NODEJS_PORT || process.env.VCAP_APP_PORT || process.env.PORT || process.argv[2] || 8081; +var port = process.env.OPENSHIFT_NODEJS_PORT || process.env.VCAP_APP_PORT || process.env.PORT || process.argv[2] || 8765; var host = process.env.OPENSHIFT_NODEJS_HOST || process.env.VCAP_APP_HOST || process.env.HOST || 'localhost'; var express = require('express'); @@ -15,7 +15,7 @@ var gun = Gun({ }); app.use(Gun.serve); -app.use(proxy(host + ':8080')); +app.use(proxy(host + ':8765')); server.listen(port); console.log('Server started on port ' + port + ' with /gun'); diff --git a/examples/social.html b/examples/social.html index 10b8382a..9ff941d8 100644 --- a/examples/social.html +++ b/examples/social.html @@ -37,8 +37,8 @@ ;(() => { function S(){}; window.S = S; - S.gun = Gun(location.host? location.origin+'/gun' : 'http://localhost:8080/gun'); - //S.gun = Gun('http://localhost:8080/gun'); + S.gun = Gun(location.host? location.origin+'/gun' : 'http://localhost:8765/gun'); + //S.gun = Gun('http://localhost:8765/gun'); //S.gun = Gun(); S.app = S.gun.get('examples/social/1'); S.user = S.gun.user(); diff --git a/examples/vue/index.html b/examples/vue/index.html index 0ef5bb68..c7c51c7b 100644 --- a/examples/vue/index.html +++ b/examples/vue/index.html @@ -103,7 +103,7 @@ /********************** SIMPLE NODE GUN SERVER EXAMPLE FOR BACKEND **********************/ // var http = require('http'), Gun = require('gun'); - // Gun({ web: http.createServer().listen(8080) }); + // Gun({ web: http.createServer().listen(8765) }); /********************** MODIFY WITH OUR OWN SERVER ADDRESS **********************/ // Vue.use(GunData, 'http://REPLACE.WITH.YOUR.GUN.SERVER:SERVERPORT/gun'); diff --git a/lib/tmp.test.sql.js b/lib/tmp.test.sql.js index 1f9058ed..b7d5b664 100644 --- a/lib/tmp.test.sql.js +++ b/lib/tmp.test.sql.js @@ -32,7 +32,7 @@ test._.stack.push(fn); return test; } - var gun = window.gun = Gun(); //Gun('http://localhost:8080/gun'); + var gun = window.gun = Gun(); window.SPAM = function(read){ // TODO: BUG? gun-sid in transport layer not correct? //localStorage.clear(); var start = Gun.time.is(); diff --git a/package.json b/package.json index dea84732..f121ee42 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "index.js", "browser": "gun.min.js", "scripts": { - "start": "node examples/http.js 8080", + "start": "node examples/http.js 8765", "prepublishOnly": "npm run unbuild", "test": "mocha", "testsea": "mocha test/sea.js", diff --git a/test/debug/deep-set.html b/test/debug/deep-set.html index e0a5dade..35e6ec93 100644 --- a/test/debug/deep-set.html +++ b/test/debug/deep-set.html @@ -3,7 +3,7 @@ ;(function(){ //localStorage.clear(); - var gun = window.gun = Gun('http://localhost:8080/gun'); + var gun = window.gun = Gun('http://localhost:8765/gun'); var user = window.user = gun.get('pub/alice'); return; user.put({pub: 'alice'}, write); diff --git a/test/gun.html b/test/gun.html index 47f6f986..0109c8ee 100644 --- a/test/gun.html +++ b/test/gun.html @@ -1,6 +1,5 @@ - \ No newline at end of file diff --git a/test/https/test.js b/test/https/test.js index de78a980..6eb7bf04 100644 --- a/test/https/test.js +++ b/test/https/test.js @@ -1,5 +1,5 @@ module.exports = function(port, file, cb, inject){ - port = port || process.env.OPENSHIFT_NODEJS_PORT || process.env.VCAP_APP_PORT || process.env.PORT || process.argv[2] || 8080; + port = port || process.env.OPENSHIFT_NODEJS_PORT || process.env.VCAP_APP_PORT || process.env.PORT || process.argv[2] || 8765; var fs = require('fs'); var Gun = require(__dirname+'/../../'); diff --git a/test/panic/b2s2s2b.js b/test/panic/b2s2s2b.js index 03c22fea..631c2f09 100644 --- a/test/panic/b2s2s2b.js +++ b/test/panic/b2s2s2b.js @@ -1,6 +1,6 @@ var config = { IP: require('ip').address(), - port: 8080, + port: 8765, servers: 2, browsers: 2, each: 100000, diff --git a/test/panic/curl-server.js b/test/panic/curl-server.js index 0397b96b..e45051da 100644 --- a/test/panic/curl-server.js +++ b/test/panic/curl-server.js @@ -1,6 +1,6 @@ var config = { IP: require('ip').address(), - port: 8080, + port: 8765, servers: 2, dir: __dirname } diff --git a/test/panic/e2e/distributed.js b/test/panic/e2e/distributed.js index 4005787f..0ec86045 100644 --- a/test/panic/e2e/distributed.js +++ b/test/panic/e2e/distributed.js @@ -22,17 +22,17 @@ describe('PANIC!', function(){ panic.server(server); gun.wsp(server); - server.listen(8080); + server.listen(8765); var clients = panic.clients; var wd = require('selenium-webdriver'); var ff1 = new wd.Builder() .forBrowser('firefox').build() - .get('http://localhost:8080/panic.html'); + .get('http://localhost:8765/panic.html'); var ff2 = new wd.Builder() .forBrowser('firefox').build() - .get('http://localhost:8080/panic.html'); + .get('http://localhost:8765/panic.html'); function min(n, done, list){ list = list || clients; diff --git a/test/panic/e2e/holy/grail.js b/test/panic/e2e/holy/grail.js index eb49f46f..7adac50d 100644 --- a/test/panic/e2e/holy/grail.js +++ b/test/panic/e2e/holy/grail.js @@ -47,7 +47,7 @@ var bob = browsers.excluding(alice).pluck(1); var serverPath = path.join(__dirname, 'gun-server.js'); -// start the server on :8080 +// start the server on :8765 spawn('node', [serverPath]); function waitFor (num, list) { diff --git a/test/panic/e2e/holy/index.html b/test/panic/e2e/holy/index.html index 5a8a87bb..6cf66963 100644 --- a/test/panic/e2e/holy/index.html +++ b/test/panic/e2e/holy/index.html @@ -7,7 +7,7 @@ - + + + + + \ No newline at end of file diff --git a/test/tmp/li.html b/test/tmp/li.html new file mode 100644 index 00000000..df801459 --- /dev/null +++ b/test/tmp/li.html @@ -0,0 +1,142 @@ + + +
    +
    + +
    +
    + +
    +
    +
    +
    +

    Login

    + + + + +
    + + +
    +

    Profile

    +

    Data is privately encrypted by default. "+" to grant access, "x" to revoke access.

    +
    +
    +
    +
    +
    +
    +
    + +
    + Public Key: +
    + + + + + + + + \ No newline at end of file diff --git a/test/tmp/nab.html b/test/tmp/nab.html new file mode 100644 index 00000000..a5c4b368 --- /dev/null +++ b/test/tmp/nab.html @@ -0,0 +1,101 @@ +

    notabug

    + + + + + + + +

    homepage

    +
      +
    + + + + + + + + \ No newline at end of file diff --git a/test/radisk.html b/test/tmp/radisk.html similarity index 85% rename from test/radisk.html rename to test/tmp/radisk.html index 4f51f9d9..d2142a38 100644 --- a/test/radisk.html +++ b/test/tmp/radisk.html @@ -1,10 +1,10 @@

    Radisk

    - - - - - + + + + + diff --git a/test/say.html b/test/tmp/say.html similarity index 100% rename from test/say.html rename to test/tmp/say.html diff --git a/test/tmp/tables.html b/test/tmp/tables.html new file mode 100644 index 00000000..dae5a90a --- /dev/null +++ b/test/tmp/tables.html @@ -0,0 +1,130 @@ +

    Tables

    + +
    + + + + +
    + + +

      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/test/tmp/time.html b/test/tmp/time.html new file mode 100644 index 00000000..7bf617ec --- /dev/null +++ b/test/tmp/time.html @@ -0,0 +1,60 @@ +

      User

      + +
      + + + + +
      + +
        + +
        + + +
        + + + + + + + + \ No newline at end of file diff --git a/test/user.html b/test/tmp/user.html similarity index 87% rename from test/user.html rename to test/tmp/user.html index 30de03f8..a7f52dfb 100644 --- a/test/user.html +++ b/test/tmp/user.html @@ -14,9 +14,9 @@ - - - + + + + + + + + + \ No newline at end of file From 443be3b222fef7618b67808c0e382d366e7c25c5 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Sat, 18 Aug 2018 16:19:23 -0700 Subject: [PATCH 093/221] Index space in alpha! --- test/tmp/space.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/tmp/space.html b/test/tmp/space.html index c083ed23..72a7f15e 100644 --- a/test/tmp/space.html +++ b/test/tmp/space.html @@ -7,10 +7,11 @@
          +Note: No data is indexed by default, you need to add some! + - ``` -- Or try something mind blowing, like saving circular references to a table of documents! ([play](http://jsbin.com/wefozepume/edit?js,console)) +- Or try something **mind blowing**, like saving circular references to a table of documents! ([play](http://jsbin.com/wefozepume/edit?js,console)) ```javascript var cat = {name: "Fluffy", species: "kitty"}; var mark = {boss: cat}; @@ -65,7 +65,7 @@ cat.slave = mark; gun.get('mark').put(mark); // access the data as if it is a document. -gun.get('mark').get('boss').get('name').val(function(data, key){ +gun.get('mark').get('boss').get('name').once(function(data, key){ // `val` grabs the data once, no subscriptions. console.log("Mark's boss is", data); }); @@ -88,7 +88,15 @@ gun.get('list').map().once(function(data, key){ gun.get('list').set({type: "cucumber", goal: "scare cat"}); ``` -## Support +Want to keep building more? **Jump to [THE DOCUMENTATION](#documentation)!** + +# What is GUN? + +First & foremost, GUN is **a community of the nicest and most helpful people** out there. So [I want to invite you](https://gitter.im/amark/gun) to come tell us about what **you** are working on & wanting to build (new or old school alike! Just be nice as well.) and ask us your questions directly. :) + +On that note, let's get some official shout outs covered first: + +### Support

          Thanks to:
          @@ -109,6 +117,19 @@ Thanks to:
          - Found a bug? Report at: https://github.com/amark/gun/issues ; - **Need help**? Chat with us: https://gitter.im/amark/gun . +### History + +[GUN](https://gun.eco) was created by [Mark Nadal](https://twitter.com/marknadal) in 2014 after he had spent 4 years trying to get his collaborative web app to scale up with traditional databases. + + After he realized [Master-Slave database architecture causes one big bottleneck](https://gun.eco/distributed/matters.html), he (as a complete newbie outsider) naively decided **to question the status quo** and shake things up with controversial, heretical, and contrarian experiments: + +**The NoDB** - no master, no servers, no "single source of truth", not built with a real programming language or real hardware, no DevOps, no locking, not *just* SQL or NoSQL but both (**all** - graphs, documents, tables, key/value). + +The goal was to build a P2P database that could survive living inside **any** browser, and could correctly sync data between **any** device after assuming **any** offline-first activity. + + + +Technically, **GUN is a graph synchronization protocol** with a *lightweight embedded engine*, capable of doing *[20M+ API ops/sec](https://gun.eco/docs/100000-ops-sec-in-IE6-on-2GB-Atom-CPU)* in **just ~9KB gzipped size**. ## Documentation From 9781877db822e7cfc52d0cdbd6a4ded7b54ac571 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Thu, 23 Aug 2018 23:49:25 -0700 Subject: [PATCH 097/221] fix 1 of @mmalmi 's found bug. --- test/tmp/li.html => examples/simple/show.html | 0 {test/tmp => examples/simple}/space.html | 0 {test/tmp => examples/simple}/tables.html | 0 {test/tmp => examples/simple}/user.html | 0 gun.js | 14 +++-------- package.json | 2 +- sea.js | 5 ++-- test/common.js | 24 +++++++++++++++++++ 8 files changed, 30 insertions(+), 15 deletions(-) rename test/tmp/li.html => examples/simple/show.html (100%) rename {test/tmp => examples/simple}/space.html (100%) rename {test/tmp => examples/simple}/tables.html (100%) rename {test/tmp => examples/simple}/user.html (100%) diff --git a/test/tmp/li.html b/examples/simple/show.html similarity index 100% rename from test/tmp/li.html rename to examples/simple/show.html diff --git a/test/tmp/space.html b/examples/simple/space.html similarity index 100% rename from test/tmp/space.html rename to examples/simple/space.html diff --git a/test/tmp/tables.html b/examples/simple/tables.html similarity index 100% rename from test/tmp/tables.html rename to examples/simple/tables.html diff --git a/test/tmp/user.html b/examples/simple/user.html similarity index 100% rename from test/tmp/user.html rename to examples/simple/user.html diff --git a/gun.js b/gun.js index d467fdfb..f395a6d0 100644 --- a/gun.js +++ b/gun.js @@ -967,7 +967,6 @@ at.on('in', at); return; }*/ - //console.log("out!", at.get, get); if(get['#'] || at.soul){ get['#'] = get['#'] || at.soul; msg['#'] || (msg['#'] = text_rand(9)); @@ -1107,13 +1106,12 @@ not(at, msg); } tmp = from.id? ((at.map || (at.map = {}))[from.id] = at.map[from.id] || {at: from}) : {}; - //console.log("REL?", at.id, at.get, rel === tmp.link, tmp.pass || at.pass); if(rel === tmp.link){ if(!(tmp.pass || at.pass)){ return; } } - if(at.pass){ + if(at.pass){ Gun.obj.map(at.map, function(tmp){ tmp.pass = true }) obj_del(at, 'pass'); } @@ -1730,10 +1728,8 @@ gun.map().on(function(data, key, at, ev){ var next = (cb||noop).call(this, data, key, at, ev); if(u === next){ return } - if(data === next || Gun.is(next)){ - chain._.on('in', next._); - return; - } + if(data === next){ return chain._.on('in', at) } + if(Gun.is(next)){ return chain._.on('in', next._) } chain._.on('in', {get: key, put: next}); }); return chain; @@ -2024,11 +2020,7 @@ var wire = peer.wire; try{ if(wire.send){ - if(wire.readyState === wire.OPEN){ wire.send(raw); - } else { - (peer.queue = peer.queue || []).push(raw); - } } else if(peer.say){ peer.say(raw); diff --git a/package.json b/package.json index f121ee42..30df1026 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gun", - "version": "0.9.9998", + "version": "0.9.9999", "description": "A realtime, decentralized, offline-first, graph data synchronization engine.", "main": "index.js", "browser": "gun.min.js", diff --git a/sea.js b/sea.js index 79e3dced..fc83ff5c 100644 --- a/sea.js +++ b/sea.js @@ -1067,9 +1067,8 @@ var Gun = SEA.Gun; var then = USE('./then'); - function User(){ - this._ = {$: this} - Gun.call() + function User(root){ + this._ = {$: this}; } User.prototype = (function(){ function F(){}; F.prototype = Gun.chain; return new F() }()) // Object.create polyfill User.prototype.constructor = User; diff --git a/test/common.js b/test/common.js index 49a3a491..d933b469 100644 --- a/test/common.js +++ b/test/common.js @@ -3366,6 +3366,30 @@ describe('Gun', function(){ list.set({name: 'dave', age: 25}); }); + it('once map function once', function(done){ + var gun = Gun(), s = 'o/mf/o', u; + var app = gun.get(s); + var list = app.get('list'); + + var check = {}; + gun.get('user').get('alice').put({name:'Alice', email:'alice@example.com'}) + gun.get('user').get('bob').put({name:'Bob', email:'bob@example.com'}) + gun.get('user').get('carl').put({name:'Carl', email:'carl@example.com'}) + + gun.get('user').once().map(v => { + //console.log('this gets called', v); + return v + }).once((v, k) => { + //console.log('this is never called', k, v); + check[k] = (check[k] || 0) + 1; + if(1 === check.alice && 1 === check.bob && 1 === check.carl){ + if(done.c){return}done.c=1; + done(); + } + }); + + }); + it('val and then map', function(done){ var gun = Gun(), s = 'val/then/map', u; var list = gun.get(s); From 84a000f83907a6c03037d8eb99f12d5806124d1b Mon Sep 17 00:00:00 2001 From: Robert Heessels Date: Fri, 24 Aug 2018 10:45:44 +0200 Subject: [PATCH 098/221] First version of RAD IndexedDB. --- lib/rindexed.js | 87 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 lib/rindexed.js diff --git a/lib/rindexed.js b/lib/rindexed.js new file mode 100644 index 00000000..5bd340db --- /dev/null +++ b/lib/rindexed.js @@ -0,0 +1,87 @@ +function Store(opt){ + opt = opt || {}; + opt.file = String(opt.file || 'radata'); + var db = null; + + // Initialize indexedDB. Version 1. + const request = window.indexedDB.open(opt.file, 1) + + // Create schema. onupgradeneeded is called only when DB is first created or when the DB version increases. + request.onupgradeneeded = function(event){ + const db = event.target.result; + db.createObjectStore(opt.file); + } + + // onsuccess is called when the DB is ready. + request.onsuccess = function(){ + db = request.result; + } + + request.onerror = function(event){ + console.log('ERROR: RAD IndexedDB generic error:', event); + }; + + var store = function Store(){}, u; + + store.put = function(file, data, cb){ + cb = cb || function(){}; + if(!db){ + const es = 'ERROR: RAD IndexedDB not yet ready.' + console.log(es); + cb(es, undefined); + } else { + // Start a transaction. The transaction will be automaticallt closed when the last success/error handler took no new action. + const transaction = db.transaction([opt.file], 'readwrite'); + + // Add or update data. + const radStore = transaction.objectStore(opt.file); + const putRequest = radStore.put(data, file); + putRequest.onsuccess = radStore.onsuccess = transaction.onsuccess = function(){ + console.log('RAD IndexedDB put transaction was succesful.'); + cb(null, 1); + }; + putRequest.onabort = radStore.onabort = transaction.onabort = function(){ + const es = 'ERROR: RAD IndexedDB put transaction was aborted.'; + console.log(es); + cb(es, undefined); + }; + putRequest.onerror = radStore.onerror = transaction.onerror = function(event){ + const es = 'ERROR: RAD IndexedDB put transaction was in error: ' + JSON.stringify(event) + console.log(es); + cb(es, undefined); + }; + } + }; + + store.get = function(file, cb){ + cb = cb || function(){}; + if(!db){ + const es = 'ERROR: RAD IndexedDB not yet ready.'; + console.log(es); + cb(es, undefined); + } else { + // Start a transaction. The transaction will be automaticallt closed when the last success/error handler took no new action. + const transaction = db.transaction([opt.file], 'readwrite'); + + // Read data. + const radStore = transaction.objectStore(opt.file); + const getRequest = radStore.get(file); + getRequest.onsuccess = function(){ + console.log('RAD IndexedDB get transaction was succesful.'); + cb(null, getRequest.result); + }; + getRequest.onabort = function(){ + const es = 'ERROR: RAD IndexedDB get transaction was aborted.'; + console.log(es); + cb(es, undefined); + }; + getRequest.onerror = function(event){ + const es = 'ERROR: RAD IndexedDB get transaction was in error: ' + JSON.stringify(event) + console.log(es); + cb(es, undefined); + }; + } + }; + + return store; +} From 90feaa53972ce86c208327de9d198794e10da800 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Fri, 24 Aug 2018 02:04:58 -0700 Subject: [PATCH 099/221] SEA tweaks --- sea.js | 19 ++++++++++--------- test/panic/who.js | 20 ++++++++------------ 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/sea.js b/sea.js index fc83ff5c..2a5e907f 100644 --- a/sea.js +++ b/sea.js @@ -24,7 +24,7 @@ // THIS IS AN EARLY ALPHA! function SEA(){} - if(typeof window !== "undefined"){ SEA.window = window } + if(typeof window !== "undefined"){ (SEA.window = window).SEA = SEA } module.exports = SEA; })(USE, './root'); @@ -174,7 +174,7 @@ }); try{ const WebCrypto = require('node-webcrypto-ossl') - api.ossl = new WebCrypto({directory: 'key_storage'}).subtle // ECDH + api.ossl = new WebCrypto({directory: 'ossl'}).subtle // ECDH }catch(e){ console.log("node-webcrypto-ossl is optionally needed for ECDH, please install if needed."); } @@ -240,16 +240,14 @@ })(USE, './parse'); ;USE(function(module){ - const { - subtle, ossl = subtle, random: getRandomBytes, TextEncoder, TextDecoder - } = USE('./shim') + const shim = USE('./shim'); const Buffer = USE('./buffer') const parse = USE('./parse') const { pbkdf2 } = USE('./settings') // This internal func returns SHA-256 hashed data for signing const sha256hash = async (mm) => { const m = parse(mm) - const hash = await ossl.digest({name: pbkdf2.hash}, new TextEncoder().encode(m)) + const hash = await shim.subtle.digest({name: pbkdf2.hash}, new shim.TextEncoder().encode(m)) return Buffer.from(hash) } module.exports = sha256hash @@ -368,7 +366,8 @@ const r = { pub: sa.pub, priv: sa.priv, /* pubId, */ epub: dh.epub, epriv: dh.epriv } if(cb){ try{ cb(r) }catch(e){console.log(e)} } return r; - } catch(e) { + } catch(e) { + console.log(e); SEA.err = e; if(cb){ cb() } return; @@ -404,7 +403,8 @@ if(cb){ try{ cb(r) }catch(e){console.log(e)} } return r; - } catch(e) { + } catch(e) { + console.log(e); SEA.err = e; if(cb){ cb() } return; @@ -441,7 +441,8 @@ if(cb){ try{ cb(r) }catch(e){console.log(e)} } return r; - } catch(e) { + } catch(e) { + console.log(e); SEA.err = e; if(cb){ cb() } return; diff --git a/test/panic/who.js b/test/panic/who.js index a6f9e3e3..1deaa5d5 100644 --- a/test/panic/who.js +++ b/test/panic/who.js @@ -7,7 +7,6 @@ var config = { '/': __dirname + '/index.html', '/gun.js': __dirname + '/../../gun.js', '/jquery.js': __dirname + '/../../examples/jquery.js', - '/cryptomodules.js': __dirname + '/../../lib/cryptomodules.js', '/sea.js': __dirname + '/../../sea.js' } } @@ -57,6 +56,7 @@ describe("Make sure SEA syncs correctly", function(){ res.end("I am "+ env.i +"!"); }); var Gun = require('gun'); + require('gun/sea'); var gun = Gun({file: env.i+'data', web: server}); server.listen(port, function(){ test.done(); @@ -80,10 +80,8 @@ describe("Make sure SEA syncs correctly", function(){ script.onload = cb; script.src = src; document.head.appendChild(script); } - load('cryptomodules.js', function(){ - load('sea.js', function(){ - test.done(); - }); + load('sea.js', function(){ + test.done(); }); }, {i: i += 1, config: config})); }); @@ -140,8 +138,8 @@ describe("Make sure SEA syncs correctly", function(){ return bob.run(function(test){ test.async(); - window.gun.get('alias/alice').map().val(function(data){ - window.ref = gun.get('pub/'+data.pub); + window.gun.get('~@alice').map().once(function(data){ + window.ref = gun.get('~'+data.pub); test.done(); }); }); @@ -152,7 +150,7 @@ describe("Make sure SEA syncs correctly", function(){ test.async(); window.count = []; - ref.get('who').get('said').map().val(function(data){ + ref.get('who').get('said').map().once(function(data){ console.log("read...", data); window.count.push(data); if(window.count.length - 1){ return } @@ -181,10 +179,8 @@ describe("Make sure SEA syncs correctly", function(){ script.onload = cb; script.src = src; document.head.appendChild(script); } - load('cryptomodules.js', function(){ - load('sea.js', function(){ - test.done(); - }); + load('sea.js', function(){ + test.done(); }); }, {i: 1, config: config}); }); From aee20ebbc3aba93bf0564ff4436fdce524ca8a24 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Fri, 24 Aug 2018 03:06:12 -0700 Subject: [PATCH 100/221] RAD indexedDB! --- gun.js | 35 ++++---- lib/rindexed.js | 180 ++++++++++++++++++++++------------------ test/tmp/indexedDB.html | 25 ++++++ 3 files changed, 139 insertions(+), 101 deletions(-) create mode 100644 test/tmp/indexedDB.html diff --git a/gun.js b/gun.js index f395a6d0..67791109 100644 --- a/gun.js +++ b/gun.js @@ -883,7 +883,7 @@ Gun.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'!"); ;"Please do not remove these messages unless you are paying for a monthly sponsorship, thanks!"; - if(typeof window !== "undefined"){ window.Gun = Gun } + if(typeof window !== "undefined"){ (window.Gun = Gun).window = window } try{ if(typeof common !== "undefined"){ common.exports = Gun } }catch(e){} module.exports = Gun; @@ -1787,24 +1787,21 @@ // See the next 'opt' code below for actual saving of data. var ev = this.to, opt = root.opt; if(root.once){ return ev.next(root) } - if(false === opt.localStorage){ return ev.next(root) } - opt.file = opt.file || 'gun/'; - var gap = Gun.obj.ify(store.getItem('gap/'+opt.file)) || {}; + //if(false === opt.localStorage){ return ev.next(root) } // we want offline resynce queue regardless! + opt.prefix = opt.file || 'gun/'; + var gap = Gun.obj.ify(store.getItem('gap/'+opt.prefix)) || {}; var empty = Gun.obj.empty, id, to, go; // add re-sync command. if(!empty(gap)){ - root.on('localStorage', function(disk){ - this.off(); - var send = {} - Gun.obj.map(gap, function(node, soul){ - Gun.obj.map(node, function(val, key){ - send[soul] = Gun.state.to(disk[soul], key, send[soul]); - }); + var disk = Gun.obj.ify(store.getItem(opt.prefix)) || {}, send = {}; + Gun.obj.map(gap, function(node, soul){ + Gun.obj.map(node, function(val, key){ + send[soul] = Gun.state.to(disk[soul], key, send[soul]); }); - setTimeout(function(){ - root.on('out', {put: send, '#': root.ask(ack), I: root.$}); - },10); }); + setTimeout(function(){ + root.on('out', {put: send, '#': root.ask(ack), I: root.$}); + },10); } root.on('out', function(msg){ @@ -1842,7 +1839,7 @@ var flush = function(){ clearTimeout(to); to = false; - try{store.setItem('gap/'+opt.file, JSON.stringify(gap)); + try{store.setItem('gap/'+opt.prefix, JSON.stringify(gap)); }catch(e){ Gun.log(err = e || "localStorage failure") } } }); @@ -1852,9 +1849,9 @@ var opt = root.opt; if(root.once){ return } if(false === opt.localStorage){ return } - opt.file = opt.file || opt.prefix || 'gun/'; // support old option name. + opt.prefix = opt.file || 'gun/'; var graph = root.graph, acks = {}, count = 0, to; - var disk = Gun.obj.ify(store.getItem(opt.file)) || {}; + var disk = Gun.obj.ify(store.getItem(opt.prefix)) || {}; var lS = function(){}, u; root.on('localStorage', disk); // NON-STANDARD EVENT! @@ -1902,10 +1899,10 @@ var ack = acks; acks = {}; if(data){ disk = data } - try{store.setItem(opt.file, JSON.stringify(disk)); + try{store.setItem(opt.prefix, JSON.stringify(disk)); }catch(e){ Gun.log(err = e || "localStorage failure"); - root.on('localStorage:error', {err: err, file: opt.file, flush: disk, retry: flush}); + root.on('localStorage:error', {err: err, file: opt.prefix, flush: disk, retry: flush}); } if(!err && !Gun.obj.empty(opt.peers)){ return } // only ack if there are no peers. Gun.obj.map(ack, function(yes, id){ diff --git a/lib/rindexed.js b/lib/rindexed.js index 5bd340db..671dccb8 100644 --- a/lib/rindexed.js +++ b/lib/rindexed.js @@ -1,87 +1,103 @@ -function Store(opt){ - opt = opt || {}; - opt.file = String(opt.file || 'radata'); - var db = null; +;(function(){ + var Gun = (typeof window !== "undefined")? window.Gun : require('../gun'); - // Initialize indexedDB. Version 1. - const request = window.indexedDB.open(opt.file, 1) + Gun.on('create', function(root){ + this.to.next(root); + root.opt.store = root.opt.store || Store(root.opt); + }); - // Create schema. onupgradeneeded is called only when DB is first created or when the DB version increases. - request.onupgradeneeded = function(event){ - const db = event.target.result; - db.createObjectStore(opt.file); + function Store(opt){ + opt = opt || {}; + opt.file = String(opt.file || 'radata'); + var db = null; + + opt.indexedDB = opt.indexedDB || window.indexedDB; + // Initialize indexedDB. Version 1. + var request = opt.indexedDB.open(opt.file, 1) + + // Create schema. onupgradeneeded is called only when DB is first created or when the DB version increases. + request.onupgradeneeded = function(event){ + var db = event.target.result; + db.createObjectStore(opt.file); + } + + // onsuccess is called when the DB is ready. + request.onsuccess = function(){ + db = request.result; + } + + request.onerror = function(event){ + console.log('ERROR: RAD IndexedDB generic error:', event); + }; + + var store = function Store(){}, u; + + store.put = function(file, data, cb){ + cb = cb || function(){}; + if(!db){ + var es = 'ERROR: RAD IndexedDB not yet ready.' + console.log(es); + cb(es, undefined); + } else { + // Start a transaction. The transaction will be automaticallt closed when the last success/error handler took no new action. + var transaction = db.transaction([opt.file], 'readwrite'); + + // Add or update data. + var radStore = transaction.objectStore(opt.file); + var putRequest = radStore.put(data, file); + putRequest.onsuccess = radStore.onsuccess = transaction.onsuccess = function(){ + //console.log('RAD IndexedDB put transaction was succesful.'); + cb(null, 1); + }; + putRequest.onabort = radStore.onabort = transaction.onabort = function(){ + var es = 'ERROR: RAD IndexedDB put transaction was aborted.'; + console.log(es); + cb(es, undefined); + }; + putRequest.onerror = radStore.onerror = transaction.onerror = function(event){ + var es = 'ERROR: RAD IndexedDB put transaction was in error: ' + JSON.stringify(event) + console.log(es); + cb(es, undefined); + }; + } + }; + + store.get = function(file, cb){ + cb = cb || function(){}; + if(!db){ + var es = 'ERROR: RAD IndexedDB not yet ready.'; + console.log(es); + cb(es, undefined); + } else { + // Start a transaction. The transaction will be automaticallt closed when the last success/error handler took no new action. + var transaction = db.transaction([opt.file], 'readwrite'); + + // Read data. + var radStore = transaction.objectStore(opt.file); + var getRequest = radStore.get(file); + getRequest.onsuccess = function(){ + //console.log('RAD IndexedDB get transaction was succesful.'); + cb(null, getRequest.result); + }; + getRequest.onabort = function(){ + var es = 'ERROR: RAD IndexedDB get transaction was aborted.'; + console.log(es); + cb(es, undefined); + }; + getRequest.onerror = function(event){ + var es = 'ERROR: RAD IndexedDB get transaction was in error: ' + JSON.stringify(event) + console.log(es); + cb(es, undefined); + }; + } + }; + + return store; } - // onsuccess is called when the DB is ready. - request.onsuccess = function(){ - db = request.result; + if(Gun.window){ + Gun.window.RindexedDB = Store; + } else { + module.exports = Store; } - - request.onerror = function(event){ - console.log('ERROR: RAD IndexedDB generic error:', event); - }; - - var store = function Store(){}, u; - - store.put = function(file, data, cb){ - cb = cb || function(){}; - if(!db){ - const es = 'ERROR: RAD IndexedDB not yet ready.' - console.log(es); - cb(es, undefined); - } else { - // Start a transaction. The transaction will be automaticallt closed when the last success/error handler took no new action. - const transaction = db.transaction([opt.file], 'readwrite'); - - // Add or update data. - const radStore = transaction.objectStore(opt.file); - const putRequest = radStore.put(data, file); - putRequest.onsuccess = radStore.onsuccess = transaction.onsuccess = function(){ - console.log('RAD IndexedDB put transaction was succesful.'); - cb(null, 1); - }; - putRequest.onabort = radStore.onabort = transaction.onabort = function(){ - const es = 'ERROR: RAD IndexedDB put transaction was aborted.'; - console.log(es); - cb(es, undefined); - }; - putRequest.onerror = radStore.onerror = transaction.onerror = function(event){ - const es = 'ERROR: RAD IndexedDB put transaction was in error: ' + JSON.stringify(event) - console.log(es); - cb(es, undefined); - }; - } - }; - - store.get = function(file, cb){ - cb = cb || function(){}; - if(!db){ - const es = 'ERROR: RAD IndexedDB not yet ready.'; - console.log(es); - cb(es, undefined); - } else { - // Start a transaction. The transaction will be automaticallt closed when the last success/error handler took no new action. - const transaction = db.transaction([opt.file], 'readwrite'); - - // Read data. - const radStore = transaction.objectStore(opt.file); - const getRequest = radStore.get(file); - getRequest.onsuccess = function(){ - console.log('RAD IndexedDB get transaction was succesful.'); - cb(null, getRequest.result); - }; - getRequest.onabort = function(){ - const es = 'ERROR: RAD IndexedDB get transaction was aborted.'; - console.log(es); - cb(es, undefined); - }; - getRequest.onerror = function(event){ - const es = 'ERROR: RAD IndexedDB get transaction was in error: ' + JSON.stringify(event) - console.log(es); - cb(es, undefined); - }; - } - }; - - return store; -} +}()); \ No newline at end of file diff --git a/test/tmp/indexedDB.html b/test/tmp/indexedDB.html new file mode 100644 index 00000000..53d9afd2 --- /dev/null +++ b/test/tmp/indexedDB.html @@ -0,0 +1,25 @@ +

          RindexedDB

          + + + + + + + + + + +

          + + + + \ No newline at end of file From 80a9a67d0b344c093d887f5093c8885e4642b432 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Fri, 24 Aug 2018 03:07:56 -0700 Subject: [PATCH 101/221] unbuild --- gun.min.js | 2 +- sea/authenticate.js | 6 +++--- sea/create.js | 16 ++++++++++++++-- sea/pair.js | 3 ++- sea/root.js | 2 +- sea/sha256.js | 6 ++---- sea/shim.js | 2 +- sea/sign.js | 3 ++- sea/user.js | 5 ++--- sea/verify.js | 3 ++- src/adapters/localStorage.js | 33 +++++++++++++++------------------ src/adapters/mesh.js | 4 ---- src/chain.js | 4 +--- src/graph.js | 7 +++++-- src/map.js | 6 ++---- src/root.js | 20 ++++++++++++++++++-- 16 files changed, 71 insertions(+), 51 deletions(-) diff --git a/gun.min.js b/gun.min.js index ba252adf..d80b0399 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 b=(t=t||{}).console||{log:function(){}};function _(o){return 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 f=module;_(function(t){var p={fn:{is:function(t){return!!t&&"function"==typeof t}}};p.bi={is:function(t){return t instanceof Boolean||"boolean"==typeof t}},p.num={is:function(t){return!d(t)&&(0<=t-parseFloat(t)+1||1/0===t||-1/0===t)}},p.text={is:function(t){return"string"==typeof t}},p.text.ify=function(t){return p.text.is(t)?t:"undefined"!=typeof JSON?JSON.stringify(t):t&&t.toString?t.toString():t},p.text.random=function(t,n){var o="";for(t=t||24,n=n||"0123456789ABCDEFGHIJKLMNOPQRSTUVWXZabcdefghijklmnopqrstuvwxyz";0")){if(!(n>t[">"]))return!1;o=!0}if(p.obj.has(t,"<")){if(!(n",s.drift=0,s.is=function(t,n,o){var e=n&&t&&t[m]&&t[m][s._]||o;if(e)return g(e=e[n])?e:-1/0},s.lex=function(){return s().toString(36).replace(".","")},s.ify=function(t,n,o,e,i){if(!t||!t[m]){if(!i)return;t=a.soul.ify(t,i)}var r=c(t[m],s._);return void 0!==n&&n!==m&&(g(o)&&(r[n]=o),void 0!==e&&(t[n]=e)),t},s.to=function(t,n,o){var e=t[n];return p(e)&&(e=d(e)),s.ify(o,n,s.is(t,n),e,a.soul(t))},function(){function u(t,n){m!==n&&s.ify(this.o,n,this.s)}s.map=function(i,r,a){var t=p(t=i||r)?t:null;return i=v(i=i||r)?i:null,t&&!i?(r=g(r)?r:s(),t[m]=t[m]||{},h(t,u,{o:t,s:r}),t):(a=a||p(r)?r:void 0,r=g(r)?r:s(),function(t,n,o,e){if(!i)return u.call({o:o,s:r},t,n),t;i.call(a||this||{},t,n,o,e),l(o,n)&&void 0===o[n]||u.call({o:o,s:r},t,n)})}}();var f=n.obj,c=f.as,l=f.has,p=f.is,h=f.map,d=f.copy,g=n.num.is,v=n.fn.is,m=a._;t.exports=s})(_,"./state"),_(function(t){var a=_("./type"),f=_("./val"),c=_("./node"),r={};!function(){function i(t,n){if(!t||n!==c.soul(t)||!c.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&&c.is(o.n,t,o.as)}r.is=function(t,n,o,e){return!(!t||!l(t)||u(t))&&!s(t,i,{cb:n,fn:o,as:e})}}(),function(){function u(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=i,c.ify(n.obj,e,n)&&(t.graph[f.rel.is(n.rel)]=n.node),n)}function e(t,n,o){var e,i,r=this,a=r.env;if(c._===n&&h(t,f.rel._))return o._;if(e=s(t,n,o,r,a)){if(n||(r.node=r.node||o||{},h(t,c._)&&c.soul(t)&&(r.node._=d(t._)),r.node=c.soul.ify(r.node,f.rel.is(r.rel)),r.rel=r.rel||f.rel.ify(c.soul(r.node))),(i=a.map)&&(i.call(a.as||{},t,n,o,r),h(o,n))){if(void 0===(t=o[n]))return void p(o,n);if(!(e=s(t,n,o,r,a)))return}if(!n)return r.node;if(!0===e)return t;if((i=u(a,{obj:t,path:r.path.concat(n)})).node)return i.rel}}function i(t){var n=this,o=f.link.is(n.rel),e=n.env.graph;n.rel=n.rel||f.rel.ify(t),n.rel[f.rel._]=t,n.node&&n.node[c._]&&(n.node[c._][f.rel._]=t),h(e,o)&&(e[t]=e[o],p(e,o))}function s(t,n,o,e,i){var r;return!!f.is(t)||(l(t)?1:(r=i.invalid)?s(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."))))}r.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.rel=f.rel.ify(n.soul)),n.graph=n.graph||{},n.seen=n.seen||[],n.as=n.as||o,u(n,e),n.root=e.node,n.graph}}(),r.node=function(t){var n=c.soul(t);if(n)return o({},n,t)},function(){function i(t,n){var o,e;if(c._!==n)(o=f.rel.is(t))?(e=this.opt.seen[o])?this.obj[n]=e:this.obj[n]=this.opt.seen[o]=r.to(this.graph,o,this.opt):this.obj[n]=t;else{if(u(t,f.rel._))return;this.obj[n]=d(t)}}r.to=function(t,n,o){if(t){var e={};return o=o||{seen:{}},s(t[n],i,{obj:e,graph:t,opt:o}),e}}}();a.fn.is;var n=a.obj,l=n.is,p=n.del,h=n.has,u=n.empty,o=n.put,s=n.map,d=n.copy;t.exports=r})(_,"./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){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");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"),function(){function a(t){var n,o,e=this.as,i=e.at||e,r=i.$;(o=t["#"])||(o=t["#"]=u(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)))}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}}(),function(){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]||v,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||v)[n];if(!i){if(!(e.opt||v).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),h(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,h(t.put,s,t),h(o.souls,function(t){if(t)return t})||o.c||(o.c=1,this.off(),h(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)}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)});h(e.put,r,e),e.async||h(e.map,f,e),void 0!==e.defer&&setTimeout(function(){c.on.put(t,n)},e.defer-e.machine),e.diff&&o.on("put",p(t,{put:e.diff}))},c.on.get=function(t,n){var o=n._,e=t.get[d],i=o.graph[e],r=t.get[g],a=(o.next||(o.next={}))[e];if(!i||!a)return o.on("get",t);if(r){if(!l(i,r))return o.on("get",t);i=c.state.to(i,r)}else i=c.obj.copy(i);i=c.graph.node(i),a.ack,o.on("in",{"@":t["#"],how:"mem",put:i,$:n}),o.on("get",t)}}(),c.chain.opt=function(t){t=t||{};var n=this._,o=t.peers||t;return a(t)||(t={}),a(n.opt)||(n.opt=t),i(o)&&(o=[o]),e(o)&&(o=h(o,function(t,n,o){o(t,{url:t})}),a(n.opt.peers)||(n.opt.peers={}),n.opt.peers=p(o,n.opt.peers)),n.opt.peers=n.opt.peers||{},p(t,n.opt),c.on("opt",n),n.opt.uuid=n.opt.uuid||function(){return s()+u(12)},this};var e=c.list.is,o=c.text,i=o.is,u=o.random,r=c.obj,a=r.is,l=r.has,p=r.to,h=r.map,s=(r.copy,c.state.lex),d=c.val.rel._,g=".",v=(c.node._,c.val.link.is,{});b.debug=function(t,n){return b.debug.i&&t===b.debug.i&&b.debug.i++&&(b.log.apply(b,arguments)||n)},(c.log=function(){return!c.log.off&&b.log.apply(b,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=c);try{void 0!==f&&(f.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 .once, apologies unexpected."),this.once(t,n)},a.chain.once=function(t,n){var o=this,e=o._,i=e.put;if(0=(a.batch||1e3))return f();e||(e=setTimeout(f,a.wait||1))}),r.on("get",function(n){this.to.next(n);var o,e,i=n.get;function t(){if(i&&(o=i["#"])){var t=i["."];(e=s[o]||void 0)&&t&&(e=Gun.state.to(e,t)),(e||Gun.obj.empty(a.peers))&&r.on("in",{"@":n["#"],put:Gun.graph.node(e),how:"lS",lS:n.I})}}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(e),e=!1;var n=i;i={},t&&(s=t);try{c.setItem(a.file,JSON.stringify(s))}catch(t){Gun.log(o=t||"localStorage failure"),r.on("localStorage:error",{err:o,file:a.file,flush:s,retry:f})}(o||Gun.obj.empty(a.peers))&&Gun.obj.map(n,function(t,n){r.on("in",{"@":n,err:o,ok:0})})}}})}})(_,"./adapters/localStorage"),_(function(t){var d=_("../type");function o(p){var h=function(){};return h.out=function(t){var n;if(this.to&&this.to.next(t),(n=t["@"])&&(n=p.dup.s[n])&&(n=n.it)&&n.mesh)return h.say(t,n.mesh.via),void(n["##"]=t["##"]);h.say(t)},h.hear=function(t,n){if(t){var o,e,i,r=p.dup,a=t[0];try{i=JSON.parse(t)}catch(t){}if("{"===a){if(!i)return;if(r.check(o=i["#"]))return;if((a=(r.track(o,!0).it=i)["@"])&&i.put&&(a+=e=i["##"]||(i["##"]=h.hash(i)))!=o){if(r.check(a))return;(a=r.s)[e]=a[o]}return(i.mesh=function(){}).via=n,(a=i["><"])&&(i.mesh.to=d.obj.map(a.split(","),function(t,n,o){o(t,!0)})),void p.on("in",i)}if("["!==a);else{if(!i)return;for(var u,s=0;u=i[s++];)h.hear(u,n)}}},function(){function r(n,o){var t=o.wire;try{t.send?t.readyState===t.OPEN?t.send(n):(o.queue=o.queue||[]).push(n):o.say&&o.say(n)}catch(t){(o.queue=o.queue||[]).push(n)}}h.say=function(n,o){var t,e,i;o?(o.wire||p.opt.wire&&p.opt.wire(o))&&(e=n.mesh||a,o!==e.via&&((i=e.raw)||(i=h.raw(n)),(t=n["@"])&&(t=p.dup.s[t])&&(t=t.it)&&t.get&&t["##"]&&t["##"]===n["##"]||(t=e.to)&&(t[o.url]||t[o.id])||(o.batch?o.batch.push(i):(o.batch=[],setTimeout(function(){var t=o.batch;t&&(o.batch=null,t.length&&r(JSON.stringify(t),o))},p.opt.gap||p.opt.wait||1),r(i,o))))):d.obj.map(p.opt.peers,function(t){h.say(n,t)})}}(),function(){function f(t,n){var o;return n instanceof Object?(d.obj.map(Object.keys(n).sort(),e,{to:o={},on:n}),o):n}function e(t){this.to[t]=this.on[t]}h.raw=function(t){if(!t)return"";var n,o,e,i=p.dup,r=t.mesh||{};if(e=r.raw)return e;if("string"==typeof t)return t;t["@"]&&(e=t.put)&&((o=t["##"])||(n=c(e,f)||"",o=h.hash(t,n),t["##"]=o),(e=i.s)[o=t["@"]+o]=e[t["#"]],t["#"]=o||t["#"],n&&((t=d.obj.to(t)).put=l));var a=0,u=[];d.obj.map(p.opt.peers,function(t){if(u.push(t.url||t.id),9<++a)return!0}),t["><"]=u.join();var s=c(t);return g!==n&&(s=s.replace('"'+l+'"',n)),r&&(r.raw=s),s},h.hash=function(t,n){return o.hash(n||c(t.put,f)||"")||t["#"]||d.text.random(9)};var c=JSON.stringify,l=":])([:"}(),h.hi=function(n){p.on("hi",n);var t=n.queue;n.queue=[],d.obj.map(t,function(t){h.say(t,n)})},h}o.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=0||1/0===t||-(1/0)===t)}},n.text={is:function(t){return"string"==typeof t}},n.text.ify=function(t){return n.text.is(t)?t:"undefined"!=typeof JSON?JSON.stringify(t):t&&t.toString?t.toString():t},n.text.random=function(t,n){var o="";for(t=t||24,n=n||"0123456789ABCDEFGHIJKLMNOPQRSTUVWXZabcdefghijklmnopqrstuvwxyz";t>0;)o+=n.charAt(Math.floor(Math.random()*n.length)),t--;return o},n.text.match=function(t,o){function e(t,n){for(var o,e=-1,i=0;o=n[i++];)if(!~(e=t.indexOf(o,e+1)))return!1;return!0}var i=!1;if(t=t||"",o=n.text.is(o)?{"=":o}:o||{},n.obj.has(o,"~")&&(t=t.toLowerCase(),o["="]=(o["="]||o["~"]).toLowerCase()),n.obj.has(o,"="))return t===o["="];if(n.obj.has(o,"*")){if(t.slice(0,o["*"].length)!==o["*"])return!1;i=!0,t=t.slice(o["*"].length)}if(n.obj.has(o,"!")){if(t.slice(-o["!"].length)!==o["!"])return!1;i=!0}if(n.obj.has(o,"+")&&n.list.map(n.list.is(o["+"])?o["+"]:[o["+"]],function(n){return t.indexOf(n)>=0?void(i=!0):!0}))return!1;if(n.obj.has(o,"-")&&n.list.map(n.list.is(o["-"])?o["-"]:[o["-"]],function(n){return t.indexOf(n)<0?void(i=!0):!0}))return!1;if(n.obj.has(o,">")){if(!(t>o[">"]))return!1;i=!0}if(n.obj.has(o,"<")){if(!(tn?-1:n>o?1:0):0}},n.list.map=function(t,n,o){return a(t,n,o)},n.list.index=1,n.obj={is:function(t){return t?t instanceof Object&&t.constructor===Object||"Object"===Object.prototype.toString.call(t).match(/^\[object (\w+)\]$/)[1]:!1}},n.obj.put=function(t,n,o){return(t||{})[n]=o,t},n.obj.has=function(t,n){return t&&Object.prototype.hasOwnProperty.call(t,n)},n.obj.del=function(t,n){return t?(t[n]=null,delete t[n],t):void 0},n.obj.as=function(t,n,o,e){return t[n]=t[n]||(e===o?{}:o)},n.obj.ify=function(t){if(r(t))return t;try{t=JSON.parse(t)}catch(n){t={}}return t},function(){function t(t,n){u(this,n)&&o!==this[n]||(this[n]=t)}var o;n.obj.to=function(n,o){return o=o||{},a(n,t,o),o}}(),n.obj.copy=function(t){return t?JSON.parse(JSON.stringify(t)):t},function(){function t(t,n){var o=this.n;if(!o||!(n===o||r(o)&&u(o,n)))return n?!0:void 0}n.obj.empty=function(n,o){return n&&a(n,t,{n:o})?!1:!0}}(),function(){function t(n,o){return 2===arguments.length?(t.r=t.r||{},void(t.r[n]=o)):(t.r=t.r||[],void t.r.push(n))}var i=Object.keys;n.obj.map=function(a,s,f){var c,l,p,h,d,v=0,g=o(s);if(t.r=null,i&&r(a)&&(h=i(a),d=!0),e(a)||h)for(l=(h||a).length;l>v;v++){var m=v+n.list.index;if(g){if(p=d?s.call(f||this,a[h[v]],h[v],t):s.call(f||this,a[v],m,t),p!==c)return p}else if(s===a[d?h[v]:v])return h?h[v]:m}else for(v in a)if(g){if(u(a,v)&&(p=f?s.call(f,a[v],v,t):s(a[v],v,t),p!==c))return p}else if(s===a[v])return v;return g?t.r:n.list.index?0:-1}}(),n.time={},n.time.is=function(t){return t?t instanceof Date:+(new Date).getTime()};var o=n.fn.is,e=n.list.is,i=n.obj,r=i.is,u=i.has,a=i.map;t.exports=n})(t,"./type"),t(function(t){t.exports=function n(t,o,e){if(!t)return{to:n};var i,t=(this.tag||(this.tag={}))[t]||(this.tag[t]={tag:t,to:n._={next:function(t){var n;(n=this.to)&&n.next(t)}}});if(o instanceof Function){var r={off:n.off||(n.off=function(){return this.next===n._.next?!0:(this===this.the.last&&(this.the.last=this.back),this.to.back=this.back,this.next=n._.next,this.back.to=this.to,void(this.the.last===this.the&&delete this.on.tag[this.the.tag]))}),to:n._,next:o,the:t,on:this,as:e};return(r.back=t.last||t).to=r,t.last=r}return(t=t.to)&&i!==o&&t.next(o),t}})(t,"./onto"),t(function(t){function n(t,n,e,i,r){if(n>t)return{defer:!0};if(e>n)return{historical:!0};if(n>e)return{converge:!0,incoming:!0};if(n===e){if(i=o(i)||"",r=o(r)||"",i===r)return{state:!0};if(r>i)return{converge:!0,current:!0};if(i>r)return{converge:!0,incoming:!0}}return{err:"Invalid CRDT Data: "+i+" to "+r+" at "+n+" to "+e+"!"}}if("undefined"==typeof JSON)throw new Error("JSON is not included in this browser. Please load it first: ajax.cdnjs.com/ajax/libs/json2/20110223/json2.js");var o=JSON.stringify;t.exports=n})(t,"./HAM"),t(function(n){var o=t("./type"),e={};e.is=function(t){return t===i?!1:null===t?!0:t===1/0?!1:s(t)||u(t)||a(t)?!0:e.rel.is(t)||!1},e.link=e.rel={_:"#"},function(){function t(t,n){var o=this;return o.id?o.id=!1:n==r&&s(t)?void(o.id=t):o.id=!1}e.rel.is=function(n){if(n&&n[r]&&!n._&&c(n)){var o={};if(p(n,t,o),o.id)return o.id}return!1}}(),e.rel.ify=function(t){return l({},r,t)},o.obj.has._=".";var i,r=e.link._,u=o.bi.is,a=o.num.is,s=o.text.is,f=o.obj,c=f.is,l=f.put,p=f.map;n.exports=e})(t,"./val"),t(function(n){var o=t("./type"),e=t("./val"),i={_:"_"};i.soul=function(t,n){return t&&t._&&t._[n||p]},i.soul.ify=function(t,n){return n="string"==typeof n?{soul:n}:n||{},t=t||{},t._=t._||{},t._[p]=n.soul||t._[p]||l(),t},i.soul._=e.link._,function(){function t(t,n){return n!==i._?e.is(t)?void(this.cb&&this.cb.call(this.as,t,n,this.n,this.s)):!0:void 0}i.is=function(n,o,e){var r;return a(n)&&(r=i.soul(n))?!f(n,t,{as:e,cb:o,s:r,n:n}):!1}}(),function(){function t(t,n){var o,i,r=this.o;return r.map?(o=r.map.call(this.as,t,""+n,r.node),void(i===o?s(r.node,n):r.node&&(r.node[n]=o))):void(e.is(t)&&(r.node[n]=t))}i.ify=function(n,o,e){return o?"string"==typeof o?o={soul:o}:o instanceof Function&&(o={map:o}):o={},o.map&&(o.node=o.map.call(e,n,r,o.node||{})),(o.node=i.soul.ify(o.node||{},o))&&f(n,t,{o:o,as:e}),o.node}}();var r,u=o.obj,a=u.is,s=u.del,f=u.map,c=o.text,l=c.random,p=i.soul._;n.exports=i})(t,"./node"),t(function(n){function o(){var t;return t=r(),t>u?(a=0,u=t+o.drift):u=t+(a+=1)/s+o.drift}{var e=t("./type"),i=t("./node"),r=e.time.is,u=-(1/0),a=0,s=1e3,f="undefined"!=typeof performance?performance.timing&&performance:!1;f&&f.timing&&f.timing.navigationStart||(f=!1)}o._=">",o.drift=0,o.is=function(t,n,e){var i=n&&t&&t[_]&&t[_][o._]||e;if(i)return b(i=i[n])?i:-(1/0)},o.lex=function(){return o().toString(36).replace(".","")},o.ify=function(t,n,e,r,u){if(!t||!t[_]){if(!u)return;t=i.soul.ify(t,u)}var a=p(t[_],o._);return c!==n&&n!==_&&(b(e)&&(a[n]=e),c!==r&&(t[n]=r)),t},o.to=function(t,n,e){var r=t[n];return d(r)&&(r=g(r)),o.ify(e,n,o.is(t,n),r,i.soul(t))},function(){function t(t,n){_!==n&&o.ify(this.o,n,this.s)}o.map=function(n,e,i){var r,u=d(u=n||e)?u:null;return n=y(n=n||e)?n:null,u&&!n?(e=b(e)?e:o(),u[_]=u[_]||{},v(u,t,{o:u,s:e}),u):(i=i||d(e)?e:r,e=b(e)?e:o(),function(o,u,a,s){return n?(n.call(i||this||{},o,u,a,s),void(h(a,u)&&r===a[u]||t.call({o:a,s:e},o,u))):(t.call({o:a,s:e},o,u),o)})}}();var c,l=e.obj,p=l.as,h=l.has,d=l.is,v=l.map,g=l.copy,m=e.num,b=m.is,k=e.fn,y=k.is,_=i._;n.exports=o})(t,"./state"),t(function(n){var o=t("./type"),e=t("./val"),i=t("./node"),r={};!function(){function t(t,o){return t&&o===i.soul(t)&&i.is(t,this.fn,this.as)?void(this.cb&&(n.n=t,n.as=this.as,this.cb.call(n.as,t,o,n))):!0}function n(t){t&&i.is(n.n,t,n.as)}r.is=function(n,o,e,i){return n&&s(n)&&!l(n)?!h(n,t,{cb:o,fn:e,as:i}):!1}}(),function(){function t(t,o){var r;return(r=p(t,o))?r:(o.env=t,o.soul=a,i.ify(o.obj,n,o)&&(o.rel=o.rel||e.rel.ify(i.soul(o.node)),o.obj!==t.shell&&(t.graph[e.rel.is(o.rel)]=o.node)),o)}function n(n,o,r){var a,s,p=this,h=p.env;if(i._===o&&c(n,e.rel._))return r._;if(a=l(n,o,r,p,h)){if(o||(p.node=p.node||r||{},c(n,i._)&&i.soul(n)&&(p.node._=d(n._)),p.node=i.soul.ify(p.node,e.rel.is(p.rel)),p.rel=p.rel||e.rel.ify(i.soul(p.node))),(s=h.map)&&(s.call(h.as||{},n,o,r,p),c(r,o))){if(n=r[o],u===n)return void f(r,o);if(!(a=l(n,o,r,p,h)))return}if(!o)return p.node;if(!0===a)return n;if(s=t(h,{obj:n,path:p.path.concat(o)}),s.node)return s.rel}}function a(t){var n=this,o=e.link.is(n.rel),r=n.env.graph;n.rel=n.rel||e.rel.ify(t),n.rel[e.rel._]=t,n.node&&n.node[i._]&&(n.node[i._][e.rel._]=t),c(r,o)&&(r[t]=r[o],f(r,o))}function l(t,n,i,r,u){var a;return e.is(t)?!0:s(t)?1:(a=u.invalid)?(t=a.call(u.as||{},t,n,i),l(t,n,i,r,u)):(u.err="Invalid value at '"+r.path.concat(n).join(".")+"'!",void(o.list.is(t)&&(u.err+=" Use `.set(item)` instead of an Array.")))}function p(t,n){for(var o,e=t.seen,i=e.length;i--;)if(o=e[i],n.obj===o.obj)return o;e.push(n)}r.ify=function(n,o,i){var r={path:[],obj:n};return o?"string"==typeof o?o={soul:o}:o instanceof Function&&(o.map=o):o={},o.soul&&(r.rel=e.rel.ify(o.soul)),o.shell=(i||{}).shell,o.graph=o.graph||{},o.seen=o.seen||[],o.as=o.as||i,t(o,r),o.root=r.node,o.graph}}(),r.node=function(t){var n=i.soul(t);if(n)return p({},n,t)},function(){function t(t,n){var o,u;if(i._===n){if(l(t,e.rel._))return;return void(this.obj[n]=d(t))}return(o=e.rel.is(t))?(u=this.opt.seen[o])?void(this.obj[n]=u):void(this.obj[n]=this.opt.seen[o]=r.to(this.graph,o,this.opt)):void(this.obj[n]=t)}r.to=function(n,o,e){if(n){var i={};return e=e||{seen:{}},h(n[o],t,{obj:i,graph:n,opt:e}),i}}}();var u,a=(o.fn.is,o.obj),s=a.is,f=a.del,c=a.has,l=a.empty,p=a.put,h=a.map,d=a.copy;n.exports=r})(t,"./graph"),t(function(n){t("./onto"),n.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}var 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}}})(t,"./ask"),t(function(n){function o(t){var n={s:{}};return t=t||{max:1e3,age:9e3},n.check=function(t){var o;return(o=n.s[t])?o.pass?o.pass=!1:n.track(t):!1},n.track=function(o,r){var u=n.s[o]||(n.s[o]={});return u.was=i(),r&&(u.pass=!0),n.to||(n.to=setTimeout(function(){var o=i();e.obj.map(n.s,function(i,r){t.age>o-i.was||e.obj.del(n.s,r)}),n.to=null},t.age+9)),u},n}var e=t("./type"),i=e.time.is;n.exports=o})(t,"./dup"),t(function(n){function i(t){return t instanceof i?(this._={gun:this,$:this}).$:this instanceof i?i.create(this._={gun:this,$:this,opt:t}):new i(t)}i.is=function(t){return t instanceof i||t&&t._&&t===t._.$||!1},i.version=.9,i.chain=i.prototype,i.chain.toJSON=function(){};var r=t("./type");r.obj.to(r,i),i.HAM=t("./HAM"),i.val=t("./val"),i.node=t("./node"),i.state=t("./state"),i.graph=t("./graph"),i.on=t("./onto"),i.ask=t("./ask"),i.dup=t("./dup"),function(){function t(n){var o,e,r=this,a=r.as,s=a.at||a,f=s.$;return(e=n["#"])||(e=n["#"]=c(9)),(o=s.dup).check(e)?void(a.out===n.out&&(n.out=u,r.to.next(n))):(o.track(e),s.ask(n["@"],n)||(n.get&&i.on.get(n,f),n.put&&i.on.put(n,f)),r.to.next(n),void(a.out||(n.out=t,s.on("out",n))))}i.create=function(n){n.root=n.root||n,n.graph=n.graph||{},n.on=n.on||i.on,n.ask=n.ask||i.ask,n.dup=n.dup||i.dup();var o=n.$.opt(n.opt);return n.once||(n.on("in",t,n),n.on("out",t,{at:n,out:t}),i.on("create",n),n.on("create",n)),n.once=1,o}}(),function(){function t(t,n,o,e){var r=this,u=i.state.is(o,n);if(!u)return r.err="Error: No state on '"+n+"' in node '"+e+"'!";var a=r.graph[e]||k,s=i.state.is(a,n,!0),f=a[n],c=i.HAM(r.machine,u,s,t,f);return c.incoming?(r.put[e]=i.state.to(o,n,r.put[e]),(r.diff||(r.diff={}))[e]=i.state.to(o,n,r.diff[e]),void(r.souls[e]=!0)):void(c.defer&&(r.defer=u<(r.defer||1/0)?u:r.defer))}function n(t,n){var i=this,u=i.$._,a=(u.next||k)[n];if(!a){if(!(u.opt||k)["super"])return void(i.souls[n]=!1);a=i.$.get(n)._}var s=i.map[n]={put:t,get:n,$:a.$},f={ctx:i,msg:s};i.async=!!u.tag.node,i.ack&&(s["@"]=i.ack),v(t,o,f),i.async&&(i.and||u.on("node",function(t){this.to.next(t),t===i.map[t.get]&&(i.souls[t.get]=!1,v(t.put,e,t),v(i.souls,function(t){return t?t:void 0})||i.c||(i.c=1,this.off(),v(i.map,r,i)))}),i.and=!0,u.on("node",s))}function o(t,n){var o=this.ctx,e=o.graph,r=this.msg,u=r.get,a=r.put,s=r.$._;e[u]=i.state.to(a,n,e[u]),o.async||(s.put=i.state.to(a,n,s.put))}function e(t,n){var o=this,e=o.put,r=o.$._;r.put=i.state.to(e,n,r.put)}function r(t){t.$&&(this.cat.stop=this.stop,t.$._.on("in",t),this.cat.stop=null)}i.on.put=function(o,e){var a=e._,s={$:e,graph:a.graph,put:{},map:{},souls:{},machine:i.state(),ack:o["@"],cat:a,stop:{}};return i.graph.is(o.put,null,t,s)||(s.err="Error: Invalid graph!"),s.err?a.on("in",{"@":o["#"],err:i.log(s.err)}):(v(s.put,n,s),s.async||v(s.map,r,s),u!==s.defer&&setTimeout(function(){i.on.put(o,e)},s.defer-s.machine),void(s.diff&&a.on("put",d(o,{put:s.diff}))))},i.on.get=function(t,n){var o,e=n._,r=t.get,u=r[m],a=e.graph[u],s=r[b],f=e.next||(e.next={}),c=f[u];if(r["*"]){var l={};i.obj.map(e.graph,function(t,n){i.text.match(n,r)&&(l[n]=i.obj.copy(t))}),i.obj.empty(l)||e.on("in",{"@":t["#"],how:"*",put:l,$:n})}if(!a||!c)return e.on("get",t);if(s){if(!h(a,s))return e.on("get",t);a=i.state.to(a,s)}else a=i.obj.copy(a);a=i.graph.node(a),o=c.ack,e.on("in",{"@":t["#"],how:"mem",put:a,$:n}),e.on("get",t)}}(),function(){i.chain.opt=function(t){t=t||{};var n=this,o=n._,e=t.peers||t;return p(t)||(t={}),p(o.opt)||(o.opt=t),f(e)&&(e=[e]),a(e)&&(e=v(e,function(t,n,o){o(t,{url:t})}),p(o.opt.peers)||(o.opt.peers={}),o.opt.peers=d(e,o.opt.peers)),o.opt.peers=o.opt.peers||{},d(t,o.opt),i.on("opt",o),o.opt.uuid=o.opt.uuid||function(){return g()+c(12)},n}}();var u,a=i.list.is,s=i.text,f=s.is,c=s.random,l=i.obj,p=l.is,h=l.has,d=l.to,v=l.map,g=(l.copy,i.state.lex),m=i.val.rel._,b=".",k=(i.node._,i.val.link.is,{});o.debug=function(t,n){return o.debug.i&&t===o.debug.i&&o.debug.i++&&(o.log.apply(o,arguments)||n)},i.log=function(){return!i.log.off&&o.log.apply(o,arguments),[].slice.call(arguments).join(" ")},i.log.once=function(t,n,o){return(o=i.log.once)[t]=o[t]||0,o[t]++||i.log(n)},i.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=i).window=window);try{"undefined"!=typeof e&&(e.exports=i)}catch(y){}n.exports=i})(t,"./root"),t(function(){var n=t("./root");n.chain.back=function(t,i){var r;if(t=t||1,-1===t||1/0===t)return this._.root.$;if(1===t)return(this._.back||this._).$;var u=this,a=u._;if("string"==typeof t&&(t=t.split(".")),!(t instanceof Array)){if(t instanceof Function){for(var s,r={back:a};(r=r.back)&&o===(s=t(r,i)););return s}return n.num.is(t)?(a.back||a).$.back(t-1):this}var f=0,c=t.length,r=a;for(f;c>f;f++)r=(r||e)[t[f]];return o!==r?i?u:r:(r=a.back)?r.$.back(t,i):void 0};var o,e={}})(t,"./back"),t(function(){function n(t){var n,o,e,i=this.as,r=i.back,u=i.root;if(t.I||(t.I=i.$),t.$||(t.$=i.$),this.to.next(t),o=t.get){if(o["#"]||i.soul){if(o["#"]=o["#"]||i.soul,t["#"]||(t["#"]=b(9)),r=u.$.get(o["#"])._,o=o["."]){if(d(r.put,o)&&(n=r.$.get(o)._,(e=n.ack)||(n.ack=-1),r.on("in",{$:r.$,put:c.state.to(r.put,o),get:r.get}),e))return}else{if(e=r.ack,e||(r.ack=-1),d(r,"put")&&r.on("in",r),e)return;t.$=r.$}return u.ask(f,t),u.on("in",t)}if(u.now&&(u.now[i.id]=u.now[i.id]||!0,i.pass={}),o["."])return i.get?(t={get:{".":i.get},$:i.$},r.ask||(r.ask={}),r.ask[i.get]=t.$._,r.on("out",t)):(t={get:{},$:i.$},r.on("out",t));if(i.ack=i.ack||-1,i.get)return t.$=i.$,o["."]=i.get,(r.ask||(r.ask={}))[i.get]=t.$._,r.on("out",t)}return r.on("out",t)}function o(t){var n,o,r=this,s=r.as,f=s.root,h=t.$,b=(h||p)._||p,k=t.put;if(s.get&&t.get!==s.get&&(t=g(t,{get:s.get})),s.has&&b!==s&&(t=g(t,{$:s.$}),b.ack&&(s.ack=b.ack)),l===k){if(o=b.put,r.to.next(t),s.soul)return;if(l===o&&l!==b.put)return;return i(s,t,r),s.has&&a(s,t),v(b.echo,s.id),void v(s.map,b.id)}if(s.soul)return r.to.next(t),i(s,t,r),void(s.next&&m(k,u,{msg:t,cat:s}));if(!(n=c.val.link.is(k)))return c.val.is(k)?(s.has||s.soul?a(s,t):(b.has||b.soul)&&((b.echo||(b.echo={}))[s.id]=b.echo[b.id]||s,(s.map||(s.map={}))[b.id]=s.map[b.id]||{at:b}),r.to.next(t),void i(s,t,r)):(s.has&&b!==s&&d(b,"put")&&(s.put=b.put),(n=c.node.soul(k))&&b.has&&(b.put=s.root.$.get(n)._.put),o=(f.stop||{})[b.id],r.to.next(t),e(s,t,b,n),i(s,t,r),void(s.next&&m(k,u,{msg:t,cat:s})));f.stop;o=f.stop||{},o=o[b.id]||(o[b.id]={}),o.is=o.is||b.put,o[s.id]=b.put||!0,r.to.next(t),e(s,t,b,n),i(s,t,r)}function e(t,n,o,i){if(i&&k!==t.get){var r=t.root.$.get(i)._;t.has?o=r:o.has&&e(o,n,o,i),o!==t&&(o.$||(o={}),(o.echo||(o.echo={}))[t.id]=o.echo[t.id]||t,t.has&&!(t.map||p)[o.id]&&a(t,n),r=o.id?(t.map||(t.map={}))[o.id]=t.map[o.id]||{at:o}:{},(i!==r.link||r.pass||t.pass)&&(t.pass&&(c.obj.map(t.map,function(t){t.pass=!0}),v(t,"pass")),r.pass&&v(r,"pass"),t.has&&(t.link=i),s(t,r.link=i)))}}function i(t,n){t.echo&&m(t.echo,r,n)}function r(t){t&&t.on&&t.on("in",this)}function u(t,n){var o,e,i,r=this.cat,u=r.next||p,a=this.msg;(k!==n||u[n])&&(e=u[n])&&(e.has?(l!==e.put&&c.val.link.is(t)||(e.put=t),o=e.$):(i=a.$)&&(i=(o=a.$.get(n))._,l!==i.put&&c.val.link.is(t)||(i.put=t)),e.on("in",{put:t,get:n,$:o,via:a}))}function a(t,n){if(t.has||t.soul){{var o=t.map;t.root}t.map=null,t.has&&(t.link=null),(t.pass||n["@"]||null!==o)&&(l===o&&c.val.link.is(t.put)||(m(o,function(n){(n=n.at)&&v(n.echo,t.id)}),o=t.put,m(t.next,function(n,e){return l===o&&l!==t.put?!0:(n.put=l,n.ack&&(n.ack=-1),void n.on("in",{get:e,$:n.$,put:l}))})))}}function s(t,n){var o=t.root.$.get(n)._;(!t.ack||(o.on("out",{get:{"#":n}}),t.ask))&&(o=t.ask,c.obj.del(t,"ask"),m(o||t.next,function(t,o){t.on("out",{get:{"#":n,".":o}})}),c.obj.del(t,"ask"))}function f(t){var n=this.as,o=n.get||p,e=n.$._,i=(t.put||p)[o["#"]];if(e.ack&&(e.ack=e.ack+1||1),!t.put||o["."]&&!d(i,e.get)){if(e.put!==l)return;return void e.on("in",{get:e.get,put:e.put=l,$:e.$,"@":t["@"]})}return k==o["."]?void e.on("in",{get:e.get,put:c.val.link.ify(o["#"]),$:e.$,"@":t["@"]}):(t.$=e.root.$,void c.on.put(t,e.root.$))}var c=t("./root");c.chain.chain=function(t){var e,i=this,r=i._,u=new(t||i).constructor(i),a=u._;return a.root=e=r.root,a.id=++e.once,a.back=i._,a.on=c.on,a.on("in",o,a),a.on("out",n,a),u};var l,p={},h=c.obj,d=h.has,v=(h.put,h.del),g=h.to,m=h.map,b=c.text.random,k=(c.val.rel._,c.node._)})(t,"./chain"),t(function(){function n(t,n){var o=n._,e=o.next,i=n.chain(),r=i._;return e||(e=o.next={}),e[r.get=t]=r,n===o.root.$?r.soul=t:(o.soul||o.has)&&(r.has=t),r}function o(t,n,o,e){var i,r=t._;return(i=r.soul)?(n(i,e,r),t):(i=r.link)?(n(i,e,r),t):(t.get(function(t,o){o.rid(t);var r=(r=t.$)&&r._||{};i=r.link||r.soul||c.is(t.put)||l(t.put),n(i,e,t,o)},{out:{get:{".":!0}}}),t)}function e(t){var n,o=this,e=o.as,i=e.at,r=i.root,a=t.$,f=(a||{})._||{},l=t.put||f.put;if((n=r.now)&&o!==n[e.now])return o.to.next(t);if(o.seen&&f.id&&o.seen[f.id])return o.to.next(t);if((n=l)&&n[c._]&&(n=c.is(n))&&(n=(t.$$=f.root.gun.get(n))._,u!==n.put&&(t=s(t,{put:l=n.put}))),(n=r.mum)&&f.id){if(n[f.id])return;u===l||c.is(l)||(n[f.id]=!0)}return e.use(t,o),o.stun?void(o.stun=null):void o.to.next(t)}function i(t){var n=this.on;if(!t||n.soul||n.has)return this.off();if(t=(t=(t=t.$||t)._||t).id){{var o,e;n.map}return(o=(e=this.seen||(this.seen={}))[t])?!0:void(e[t]=!0)}}var r=t("./root");r.chain.get=function(t,u,a){var s,l;if("string"!=typeof t){if(t instanceof Function){if(!0===u)return o(this,t,u,a);s=this;var h,d=s._,v=d.root,l=v.now;a=u||{},a.at=d,a.use=t,a.out=a.out||{},a.out.get=a.out.get||{},(h=d.on("in",e,a)).rid=i,(v.now={$:1})[a.now=d.id]=h;var g=v.mum;return v.mum={},d.on("out",a.out),v.mum=g,v.now=l,s}return f(t)?this.get(""+t,u,a):(l=c.is(t))?this.get(l,u,a):((a=this.chain())._.err={err:r.log("Invalid get request!",t)},u&&u.call(a,a._.err),a)}var m=this,b=m._,k=b.next||p;return(s=k[t])||(s=n(t,m)),s=s.$,(l=b.stun)&&(s._.stun=s._.stun||l),u&&u instanceof Function&&s.get(u,a),s};var u,a=r.obj,s=(a.has,r.obj.to),f=r.num.is,c=r.val.link,l=r.node.soul,p=(r.node._,{})})(t,"./get"),t(function(){function n(t){t.batch=i;var n=t.opt||{},o=t.env=c.state.map(u,n.state);return o.soul=t.soul,t.graph=c.graph.ify(t.data,o,t),o.err?((t.ack||m).call(t,t.out={err:c.log(o.err)}),void(t.res&&t.res())):void t.batch()}function e(t){return void(t&&t())}function i(){var t=this;t.graph&&!v(t.stun,r)&&(t.res=t.res||function(t){t&&t()},t.res(function(){var n=t.$.back(-1)._,o=n.ask(function(o){n.root.on("ack",o),o.err&&c.log(o),o.lack||this.off(),t.ack&&t.ack(o,this)},t.opt),e=n.root.now;p.del(n.root,"now");var i=n.root.mum;n.root.mum={},t.ref._.on("out",{$:t.ref,put:t.out=t.env.graph,opt:t.opt,"#":o}),n.root.mum=i?p.to(i,n.root.mum):i,n.root.now=e},t),t.res&&t.res())}function r(t){return t?!0:void 0}function u(t,n,o,e){var i=this,r=c.is(t);!n&&e.path.length&&(i.res||b)(function(){var n=e.path,o=i.ref,u=(i.opt,0),s=n.length;for(u;s>u;u++)o=o.get(n[u]);r&&(o=t);var f=o._.dub;return f||(f=c.node.soul(e.obj))?(o.back(-1).get(f),void e.soul(f)):((i.stun=i.stun||{})[n]=!0,void o.get(a,!0,{as:{at:e,as:i,p:n}}))},{as:i,at:e})}function a(t,n,o,e){var n=n.as,i=n.at;n=n.as;var r=((o||{}).$||{})._||{};return t=r.dub=r.dub||t||c.node.soul(i.obj)||c.node.soul(o.put||r.put)||c.val.rel.is(o.put||r.put)||(n.via.back("opt.uuid")||c.text.random)(),e&&(e.stun=!0),t?void s(r,r.dub=t,i,n):void r.via.back("opt.uuid")(function(t,o){return t?c.log(t):void s(r,r.dub=r.dub||o,i,n)})}function s(t,n,o,e){t.$.back(-1).get(n),o.soul(n),e.stun[o.path]=!1,e.batch()}function f(t,n,e,i){if(n=n.as,e.$&&e.$._){if(e.err)return void o.log("Please report this as an issue! Put.any.err");var r,u=e.$._,a=u.put,s=n.opt||{};if(!(r=n.ref)||!r._.now){if(i&&(i.stun=!0),n.ref!==n.$){if(r=n.$._.get||u.get,!r)return void o.log("Please report this as an issue! Put.no.get");n.data=d({},r,n.data),r=null}if(l===a){if(!u.get)return;t||(r=u.$.back(function(t){return t.link||t.soul?t.link||t.soul:void(n.data=d({},t.get,n.data))})),r=r||u.get,u=u.root.$.get(r)._,n.soul=r,a=n.data}return n.not||(n.soul=n.soul||t)||(n.path&&h(n.data)?n.soul=(s.uuid||n.via.back("opt.uuid")||c.text.random)():(k==u.get&&(n.soul=(u.put||g)["#"]||u.dub),n.soul=n.soul||u.soul||u.soul||(s.uuid||n.via.back("opt.uuid")||c.text.random)()),n.soul)?void n.ref.put(n.data,n.soul,n):void n.via.back("opt.uuid")(function(t,o){return t?c.log(t):void n.ref.put(n.data,n.soul=o,n)})}}}var c=t("./root");c.chain.put=function(t,o,i){var r,u=this,a=u._,s=a.root.$;return i=i||{},i.data=t,i.via=i.$=i.via||i.$||u,"string"==typeof o?i.soul=o:i.ack=i.ack||o,a.soul&&(i.soul=a.soul),i.soul||s===u?h(i.data)?(i.soul=i.soul||(i.not=c.node.soul(i.data)||(i.via.back("opt.uuid")||c.text.random)()),i.soul?(i.$=u=s.get(i.soul),i.ref=i.$,n(i),u):(i.via.back("opt.uuid")(function(t,n){return t?c.log(t):void(i.ref||i.$).put(i.data,i.soul=n,i)}),u)):((i.ack||m).call(i,i.out={err:c.log("Data saved to the root level of the graph must be a node (an object), not a",typeof i.data,'of "'+i.data+'"!')}),i.res&&i.res(),u):c.is(t)?(t.get(function(t,n,e){return!t&&c.val.is(e.put)?c.log("The reference you are saving is a",typeof e.put,'"'+e.put+'", not a node (object)!'):void u.put(c.val.rel.ify(t),o,i)},!0),u):(i.ref=i.ref||s._===(r=a.back)?u:r.$,i.ref._.soul&&c.val.is(i.data)&&a.get?(i.data=d({},a.get,i.data),i.ref.put(i.data,i.soul,i),u):(i.ref.get(f,!0,{as:i}),i.out||(i.res=i.res||e,i.$._.stun=i.ref._.stun),u))};var l,p=c.obj,h=p.is,d=p.put,v=p.map,g={},m=function(){},b=function(t,n){t.call(n||g)},k=c.node._})(t,"./put"),t(function(n){var o=t("./root");t("./chain"),t("./back"),t("./put"),t("./get"),n.exports=o})(t,"./index"),t(function(){function n(t,n){{var o,e=this,r=t.$,u=(r||{})._||{},a=u.put||t.put;e.at}if(i!==a){if(o=t.$$){if(o=t.$$._,i===o.put)return;a=o.put}e.change&&(a=t.put),e.as?e.ok.call(e.as,t,n):e.ok.call(r,a,t.get,t,n)}}function o(t,n,e){var r,u,a=this.as,s=(a.at,t.$),f=s._,c=f.put||t.put;if(u=t.$$){if(r=u=t.$$._,i===u.put)return;c=u.put}return(u=n.wait)&&(u=u[f.id])&&clearTimeout(u),e||i!==c&&!f.soul&&!f.link&&(!r||0 .once, apologies unexpected."),this.once(t,n)},e.chain.once=function(t,n){var r=this,u=r._,a=u.put;if(0=(n.batch||1e3)?s():void(e||(e=setTimeout(s,n.wait||1)))}),t.on("get",function(o){function e(){if(s&&(i=s["#"])){var e=s["."];r=u[i]||a,r&&e&&(r=Gun.state.to(r,e)),(r||Gun.obj.empty(n.peers))&&t.on("in",{"@":o["#"],put:Gun.graph.node(r),how:"lS",lS:o.I})}}this.to.next(o);var i,r,a,s=o.get;Gun.debug?setTimeout(e,1):e()});var a=function(t,n,o,e){u[e]=Gun.state.to(o,n,u[e])},s=function(a){var f;r=0,clearTimeout(e),e=!1;var c=i;i={},a&&(u=a);try{o.setItem(n.prefix,JSON.stringify(u))}catch(l){Gun.log(f=l||"localStorage failure"),t.on("localStorage:error",{err:f,file:n.prefix,flush:u,retry:s})}(f||Gun.obj.empty(n.peers))&&Gun.obj.map(c,function(n,o){t.on("in",{"@":o,err:f,ok:0})})}}})}})(t,"./adapters/localStorage"),t(function(n){function o(t){var n=function(){};return n.out=function(o){var e;return this.to&&this.to.next(o),(e=o["@"])&&(e=t.dup.s[e])&&(e=e.it)&&e.mesh?(n.say(o,e.mesh.via),void(e["##"]=o["##"])):void n.say(o)},n.hear=function(o,i){if(o){var r,u,a,s=t.dup,f=o[0];try{a=JSON.parse(o)}catch(c){}if("{"===f){if(!a)return;if(s.check(r=a["#"]))return;if(s.track(r,!0).it=a,(f=a["@"])&&a.put&&(u=a["##"]||(a["##"]=n.hash(a)),(f+=u)!=r)){if(s.check(f))return;(f=s.s)[u]=f[r]}return(a.mesh=function(){}).via=i,(f=a["><"])&&(a.mesh.to=e.obj.map(f.split(","),function(t,n,o){o(t,!0)})),void t.on("in",a)}if("["!==f);else{if(!a)return;for(var l,p=0;l=a[p++];)n.hear(l,i)}}},function(){function o(t,n){var o=n.wire;try{o.send?o.send(t):n.say&&n.say(t)}catch(e){(n.queue=n.queue||[]).push(t)}}n.say=function(i,u){if(!u)return void e.obj.map(t.opt.peers,function(t){n.say(i,t)});var a,s,f,c=u.wire||t.opt.wire&&t.opt.wire(u);if(c&&(s=i.mesh||r,u!==s.via&&((f=s.raw)||(f=n.raw(i)),!((a=i["@"])&&(a=t.dup.s[a])&&(a=a.it)&&a.get&&a["##"]&&a["##"]===i["##"]||(a=s.to)&&(a[u.url]||a[u.id]))))){if(u.batch)return void u.batch.push(f);u.batch=[],setTimeout(function(){var t=u.batch;t&&(u.batch=null,t.length&&o(JSON.stringify(t),u))},t.opt.gap||t.opt.wait||1),o(f,u)}}}(),function(){function r(t,n){var o;return n instanceof Object?(e.obj.map(Object.keys(n).sort(),u,{to:o={},on:n}),o):n}function u(t){this.to[t]=this.on[t]}n.raw=function(o){if(!o)return"";var u,f,c,l=t.dup,p=o.mesh||{};if(c=p.raw)return c;if("string"==typeof o)return o;o["@"]&&(c=o.put)&&((f=o["##"])||(u=a(c,r)||"",f=n.hash(o,u),o["##"]=f),(c=l.s)[f=o["@"]+f]=c[o["#"]],o["#"]=f||o["#"],u&&((o=e.obj.to(o)).put=s));var h=0,d=[];e.obj.map(t.opt.peers,function(t){return d.push(t.url||t.id),++h>9?!0:void 0}),o["><"]=d.join();var v=a(o);return i!==u&&(v=v.replace('"'+s+'"',u)),p&&(p.raw=v),v},n.hash=function(t,n){return o.hash(n||a(t.put,r)||"")||t["#"]||e.text.random(9)};var a=JSON.stringify,s=":])([:"}(),n.hi=function(o){t.on("hi",o);var i=o.queue;o.queue=[],e.obj.map(i,function(t){n.say(t,o)})},n}var e=t("../type");o.hash=function(t){if("string"!=typeof t)return{err:1};var n=0;if(!t.length)return n;for(var o,e=0,i=t.length;i>e;++e)o=t.charCodeAt(e),n=(n<<5)-n+o,n|=0;return n};var i,r={};Object.keys=Object.keys||function(t){return map(t,function(t,n,o){o(n)})};try{n.exports=o}catch(u){}})(t,"./adapters/mesh"),t(function(){var n=t("../index");n.Mesh=t("./mesh"),n.on("opt",function(t){function o(n){if(n&&n.url){var o=n.url.replace("http","ws"),u=n.wire=new i.WebSocket(o);return u.onclose=function(){t.on("bye",n),e(n)},u.onerror=function(t){e(n),t&&"ECONNREFUSED"===t.code},u.onopen=function(){a.hi(n)},u.onmessage=function(t){t&&(r.inLength=(r.inLength||0)+(t.data||t).length,a.hear(t.data||t,n))},u}}function e(t){clearTimeout(t.defer),t.defer=setTimeout(function(){o(t)},2e3)}this.to.next(t);var i=t.opt;if(!t.once&&!1!==i.WebSocket){var r;"undefined"!=typeof window&&(r=window),"undefined"!=typeof global&&(r=global),r=r||{};var u=i.WebSocket||r.WebSocket||r.webkitWebSocket||r.mozWebSocket;if(u){i.WebSocket=u;var a=i.mesh=i.mesh||n.Mesh(t);t.on("create",function(n){this.to.next(n),t.on("out",a.out)}),i.wire=i.wire||o}}})})(t,"./adapters/websocket")}(); \ No newline at end of file diff --git a/sea/authenticate.js b/sea/authenticate.js index 06c2eb26..a4ce10ff 100644 --- a/sea/authenticate.js +++ b/sea/authenticate.js @@ -15,7 +15,7 @@ let err // then attempt to log into each one until we find ours! // (if two users have the same username AND the same password... that would be bad) - const [ user ] = await Promise.all(aliases.map(async ({ at: at, pub: pub }) => { + const users = await Promise.all(aliases.map(async ({ at: at, pub: pub }, i) => { // attempt to PBKDF2 extend the password with the salt. (Verifying the signature gives us the plain text salt.) const auth = parseProps(at.put.auth) // NOTE: aliasquery uses `gun.get` which internally SEA.read verifies the data for us, so we do not need to re-verify it here. @@ -30,7 +30,7 @@ const salt = auth.salt const sea = await SEA.decrypt(auth.ek, proof) if (!sea) { - err = 'Failed to decrypt secret!' + err = 'Failed to decrypt secret! ' + i +'/'+aliases.length; return } // now we have AES decrypted the private key, from when we encrypted it with the proof at registration. @@ -53,7 +53,7 @@ throw { err } } })) - + var user = Gun.list.map(users, function(acc){ if(acc){ return acc } }) if (!user) { throw { err: err || 'Public key does not exist!' } } diff --git a/sea/create.js b/sea/create.js index ac14b49d..a3b6f64e 100644 --- a/sea/create.js +++ b/sea/create.js @@ -14,7 +14,7 @@ var u; // Well first we have to actually create a user. That is what this function does. - User.prototype.create = function(username, pass, cb){ + User.prototype.create = function(username, pass, cb, opt){ // TODO: Needs to be cleaned up!!! const gunRoot = this.back(-1) var gun = this, cat = (gun._); @@ -24,12 +24,13 @@ return gun; } cat.ing = true; + opt = opt || {}; var resolve = function(){}, reject = resolve; // Because more than 1 user might have the same username, we treat the alias as a list of those users. if(cb){ resolve = reject = cb } gunRoot.get('~@'+username).get(async (at, ev) => { ev.off() - if (at.put) { + if (at.put && !opt.already) { // If we can enforce that a user name is already taken, it might be nice to try, but this is not guaranteed. const err = 'User already created!' Gun.log(err) @@ -165,6 +166,17 @@ return user._.sea; } User.prototype.leave = async function(){ + var gun = this, user = (gun.back(-1)._).user; + if(user){ + delete user.is; + delete user._.is; + delete user._.sea; + } + if(typeof window !== 'undefined'){ + var tmp = window.sessionStorage; + delete tmp.alias; + delete tmp.tmp; + } return await authLeave(this.back(-1)) } // If authenticated user wants to delete his/her account, let's support it! diff --git a/sea/pair.js b/sea/pair.js index 793083eb..2946c9bd 100644 --- a/sea/pair.js +++ b/sea/pair.js @@ -51,7 +51,8 @@ const r = { pub: sa.pub, priv: sa.priv, /* pubId, */ epub: dh.epub, epriv: dh.epriv } if(cb){ try{ cb(r) }catch(e){console.log(e)} } return r; - } catch(e) { + } catch(e) { + console.log(e); SEA.err = e; if(cb){ cb() } return; diff --git a/sea/root.js b/sea/root.js index 23cd2bcc..00fbf22b 100644 --- a/sea/root.js +++ b/sea/root.js @@ -4,7 +4,7 @@ // THIS IS AN EARLY ALPHA! function SEA(){} - if(typeof window !== "undefined"){ SEA.window = window } + if(typeof window !== "undefined"){ (SEA.window = window).SEA = SEA } module.exports = SEA; \ No newline at end of file diff --git a/sea/sha256.js b/sea/sha256.js index 43f97dc9..a3ff728a 100644 --- a/sea/sha256.js +++ b/sea/sha256.js @@ -1,14 +1,12 @@ - const { - subtle, ossl = subtle, random: getRandomBytes, TextEncoder, TextDecoder - } = require('./shim') + const shim = require('./shim'); const Buffer = require('./buffer') const parse = require('./parse') const { pbkdf2 } = require('./settings') // This internal func returns SHA-256 hashed data for signing const sha256hash = async (mm) => { const m = parse(mm) - const hash = await ossl.digest({name: pbkdf2.hash}, new TextEncoder().encode(m)) + const hash = await shim.subtle.digest({name: pbkdf2.hash}, new shim.TextEncoder().encode(m)) return Buffer.from(hash) } module.exports = sha256hash diff --git a/sea/shim.js b/sea/shim.js index 83e52389..379d042f 100644 --- a/sea/shim.js +++ b/sea/shim.js @@ -28,7 +28,7 @@ }); try{ const WebCrypto = require('node-webcrypto-ossl') - api.ossl = new WebCrypto({directory: 'key_storage'}).subtle // ECDH + api.ossl = new WebCrypto({directory: 'ossl'}).subtle // ECDH }catch(e){ console.log("node-webcrypto-ossl is optionally needed for ECDH, please install if needed."); } diff --git a/sea/sign.js b/sea/sign.js index fe4ed994..fdb8dde0 100644 --- a/sea/sign.js +++ b/sea/sign.js @@ -25,7 +25,8 @@ if(cb){ try{ cb(r) }catch(e){console.log(e)} } return r; - } catch(e) { + } catch(e) { + console.log(e); SEA.err = e; if(cb){ cb() } return; diff --git a/sea/user.js b/sea/user.js index 05a91f1c..7c0fadcd 100644 --- a/sea/user.js +++ b/sea/user.js @@ -3,9 +3,8 @@ var Gun = SEA.Gun; var then = require('./then'); - function User(){ - this._ = {$: this} - Gun.call() + function User(root){ + this._ = {$: this}; } User.prototype = (function(){ function F(){}; F.prototype = Gun.chain; return new F() }()) // Object.create polyfill User.prototype.constructor = User; diff --git a/sea/verify.js b/sea/verify.js index 1ce4347a..adfa29e4 100644 --- a/sea/verify.js +++ b/sea/verify.js @@ -26,7 +26,8 @@ if(cb){ try{ cb(r) }catch(e){console.log(e)} } return r; - } catch(e) { + } catch(e) { + console.log(e); SEA.err = e; if(cb){ cb() } return; diff --git a/src/adapters/localStorage.js b/src/adapters/localStorage.js index c3672909..d81e71e4 100644 --- a/src/adapters/localStorage.js +++ b/src/adapters/localStorage.js @@ -15,24 +15,21 @@ Gun.on('create', function(root){ // See the next 'opt' code below for actual saving of data. var ev = this.to, opt = root.opt; if(root.once){ return ev.next(root) } - if(false === opt.localStorage){ return ev.next(root) } - opt.file = opt.file || 'gun/'; - var gap = Gun.obj.ify(store.getItem('gap/'+opt.file)) || {}; + //if(false === opt.localStorage){ return ev.next(root) } // we want offline resynce queue regardless! + opt.prefix = opt.file || 'gun/'; + var gap = Gun.obj.ify(store.getItem('gap/'+opt.prefix)) || {}; var empty = Gun.obj.empty, id, to, go; // add re-sync command. if(!empty(gap)){ - root.on('localStorage', function(disk){ - this.off(); - var send = {} - Gun.obj.map(gap, function(node, soul){ - Gun.obj.map(node, function(val, key){ - send[soul] = Gun.state.to(disk[soul], key, send[soul]); - }); + var disk = Gun.obj.ify(store.getItem(opt.prefix)) || {}, send = {}; + Gun.obj.map(gap, function(node, soul){ + Gun.obj.map(node, function(val, key){ + send[soul] = Gun.state.to(disk[soul], key, send[soul]); }); - setTimeout(function(){ - root.on('out', {put: send, '#': root.ask(ack), I: root.$}); - },10); }); + setTimeout(function(){ + root.on('out', {put: send, '#': root.ask(ack), I: root.$}); + },10); } root.on('out', function(msg){ @@ -70,7 +67,7 @@ Gun.on('create', function(root){ var flush = function(){ clearTimeout(to); to = false; - try{store.setItem('gap/'+opt.file, JSON.stringify(gap)); + try{store.setItem('gap/'+opt.prefix, JSON.stringify(gap)); }catch(e){ Gun.log(err = e || "localStorage failure") } } }); @@ -80,9 +77,9 @@ Gun.on('create', function(root){ var opt = root.opt; if(root.once){ return } if(false === opt.localStorage){ return } - opt.file = opt.file || opt.prefix || 'gun/'; // support old option name. + opt.prefix = opt.file || 'gun/'; var graph = root.graph, acks = {}, count = 0, to; - var disk = Gun.obj.ify(store.getItem(opt.file)) || {}; + var disk = Gun.obj.ify(store.getItem(opt.prefix)) || {}; var lS = function(){}, u; root.on('localStorage', disk); // NON-STANDARD EVENT! @@ -130,10 +127,10 @@ Gun.on('create', function(root){ var ack = acks; acks = {}; if(data){ disk = data } - try{store.setItem(opt.file, JSON.stringify(disk)); + try{store.setItem(opt.prefix, JSON.stringify(disk)); }catch(e){ Gun.log(err = e || "localStorage failure"); - root.on('localStorage:error', {err: err, file: opt.file, flush: disk, retry: flush}); + root.on('localStorage:error', {err: err, file: opt.prefix, flush: disk, retry: flush}); } if(!err && !Gun.obj.empty(opt.peers)){ return } // only ack if there are no peers. Gun.obj.map(ack, function(yes, id){ diff --git a/src/adapters/mesh.js b/src/adapters/mesh.js index 8c5d4fb8..96149ccb 100644 --- a/src/adapters/mesh.js +++ b/src/adapters/mesh.js @@ -99,11 +99,7 @@ function Mesh(ctx){ var wire = peer.wire; try{ if(wire.send){ - if(wire.readyState === wire.OPEN){ wire.send(raw); - } else { - (peer.queue = peer.queue || []).push(raw); - } } else if(peer.say){ peer.say(raw); diff --git a/src/chain.js b/src/chain.js index f2c5d8b0..c2a1d20d 100644 --- a/src/chain.js +++ b/src/chain.js @@ -24,7 +24,6 @@ function output(msg){ at.on('in', at); return; }*/ - //console.log("out!", at.get, get); if(get['#'] || at.soul){ get['#'] = get['#'] || at.soul; msg['#'] || (msg['#'] = text_rand(9)); @@ -164,13 +163,12 @@ function relate(at, msg, from, rel){ not(at, msg); } tmp = from.id? ((at.map || (at.map = {}))[from.id] = at.map[from.id] || {at: from}) : {}; - //console.log("REL?", at.id, at.get, rel === tmp.link, tmp.pass || at.pass); if(rel === tmp.link){ if(!(tmp.pass || at.pass)){ return; } } - if(at.pass){ + if(at.pass){ Gun.obj.map(at.map, function(tmp){ tmp.pass = true }) obj_del(at, 'pass'); } diff --git a/src/graph.js b/src/graph.js index 49b305ed..a7f6f682 100644 --- a/src/graph.js +++ b/src/graph.js @@ -33,6 +33,7 @@ var Graph = {}; if(env.soul){ at.rel = Val.rel.ify(env.soul); } + env.shell = (as||{}).shell; env.graph = env.graph || {}; env.seen = env.seen || []; env.as = env.as || as; @@ -45,8 +46,10 @@ var Graph = {}; at.env = env; at.soul = soul; if(Node.ify(at.obj, map, at)){ - //at.rel = at.rel || Val.rel.ify(Node.soul(at.node)); - env.graph[Val.rel.is(at.rel)] = at.node; + at.rel = at.rel || Val.rel.ify(Node.soul(at.node)); + if(at.obj !== env.shell){ + env.graph[Val.rel.is(at.rel)] = at.node; + } } return at; } diff --git a/src/map.js b/src/map.js index 04cc4518..b3072500 100644 --- a/src/map.js +++ b/src/map.js @@ -14,10 +14,8 @@ Gun.chain.map = function(cb, opt, t){ gun.map().on(function(data, key, at, ev){ var next = (cb||noop).call(this, data, key, at, ev); if(u === next){ return } - if(data === next || Gun.is(next)){ - chain._.on('in', next._); - return; - } + if(data === next){ return chain._.on('in', at) } + if(Gun.is(next)){ return chain._.on('in', next._) } chain._.on('in', {get: key, put: next}); }); return chain; diff --git a/src/root.js b/src/root.js index e362dd34..24022317 100644 --- a/src/root.js +++ b/src/root.js @@ -151,8 +151,24 @@ Gun.dup = require('./dup'); } Gun.on.get = function(msg, gun){ - var root = gun._, soul = msg.get[_soul], node = root.graph[soul], has = msg.get[_has], tmp; + var root = gun._, get = msg.get, soul = get[_soul], node = root.graph[soul], has = get[_has], tmp; var next = root.next || (root.next = {}), at = next[soul]; + if(get['*']){ // TEMPORARY HACK FOR MARTTI, TESTING + var graph = {}; + Gun.obj.map(root.graph, function(node, soul){ + if(Gun.text.match(soul, get)){ + graph[soul] = Gun.obj.copy(node); + } + }); + if(!Gun.obj.empty(graph)){ + root.on('in', { + '@': msg['#'], + how: '*', + put: graph, + $: gun + }); + } + } // TEMPORARY HACK FOR MARTTI, TESTING if(!node || !at){ return root.on('get', msg) } if(has){ if(!obj_has(node, has)){ return root.on('get', msg) } @@ -213,7 +229,7 @@ Gun.log.once = function(w,s,o){ return (o = Gun.log.once)[w] = o[w] || 0, o[w]++ Gun.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'!"); ;"Please do not remove these messages unless you are paying for a monthly sponsorship, thanks!"; -if(typeof window !== "undefined"){ window.Gun = Gun } +if(typeof window !== "undefined"){ (window.Gun = Gun).window = window } try{ if(typeof common !== "undefined"){ common.exports = Gun } }catch(e){} module.exports = Gun; From 5b624376b79cd0e90b77cf5e7b4dc12004882cff Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Fri, 24 Aug 2018 03:24:29 -0700 Subject: [PATCH 102/221] indexedDB!!! Thanks @robertheessels --- test/tmp/indexedDB.html | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/tmp/indexedDB.html b/test/tmp/indexedDB.html index 53d9afd2..6097fe09 100644 --- a/test/tmp/indexedDB.html +++ b/test/tmp/indexedDB.html @@ -15,11 +15,10 @@ \ No newline at end of file From 2630cc8223a9d857142638ff35f178d982e26313 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Fri, 24 Aug 2018 16:36:29 -0700 Subject: [PATCH 103/221] Not swearing: DAM @$$ Heisenbug fixed! https://github.com/amark/gun/wiki/@$$ --- gun.js | 15 +++++++++------ package.json | 2 +- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/gun.js b/gun.js index 67791109..168ef767 100644 --- a/gun.js +++ b/gun.js @@ -823,7 +823,7 @@ }); } } // TEMPORARY HACK FOR MARTTI, TESTING - if(!node || !at){ return root.on('get', msg) } + if(!node){ return root.on('get', msg) } if(has){ if(!obj_has(node, has)){ return root.on('get', msg) } node = Gun.state.to(node, has); @@ -834,7 +834,7 @@ node = Gun.obj.copy(node); } node = Gun.graph.node(node); - tmp = at.ack; + tmp = (at||empty).ack; root.on('in', { '@': msg['#'], how: 'mem', @@ -1941,7 +1941,8 @@ if(!raw){ return } var dup = ctx.dup, id, hash, msg, tmp = raw[0]; try{msg = JSON.parse(raw); - }catch(e){} + }catch(e){console.log('DAM JSON parse error', e)} + console.log("hear:", msg); if('{' === tmp){ if(!msg){ return } if(dup.check(id = msg['#'])){ return } @@ -2017,7 +2018,7 @@ var wire = peer.wire; try{ if(wire.send){ - wire.send(raw); + wire.send(raw); } else if(peer.say){ peer.say(raw); @@ -2028,7 +2029,7 @@ } }()); - + ;(function(){ mesh.raw = function(msg){ @@ -2051,7 +2052,9 @@ }); msg['><'] = to.join(); var raw = $(msg); if(u !== put){ - raw = raw.replace('"'+ _ +'"', put); + tmp = raw.indexOf(_, raw.indexOf('put')); + raw = raw.slice(0, tmp-1) + put + raw.slice(tmp + _.length + 1); + //raw = raw.replace('"'+ _ +'"', put); // https://github.com/amark/gun/wiki/@$$ Heisenbug } if(msh){ msh.raw = raw; diff --git a/package.json b/package.json index 30df1026..3c7b04eb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gun", - "version": "0.9.9999", + "version": "0.9.99991", "description": "A realtime, decentralized, offline-first, graph data synchronization engine.", "main": "index.js", "browser": "gun.min.js", From 001eb6f15d5bf24bc3a4d8e3266be5e2837ff017 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Fri, 24 Aug 2018 16:49:57 -0700 Subject: [PATCH 104/221] Not swearing: DAM @$$ Heisenbug fixed! --- gun.js | 1 - package-lock.json | 2 +- test/panic/holy-grail.js | 1 + 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gun.js b/gun.js index 168ef767..8188b3b7 100644 --- a/gun.js +++ b/gun.js @@ -1942,7 +1942,6 @@ var dup = ctx.dup, id, hash, msg, tmp = raw[0]; try{msg = JSON.parse(raw); }catch(e){console.log('DAM JSON parse error', e)} - console.log("hear:", msg); if('{' === tmp){ if(!msg){ return } if(dup.check(id = msg['#'])){ return } diff --git a/package-lock.json b/package-lock.json index 414e3295..635c6288 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "gun", - "version": "0.9.9998", + "version": "0.9.99991", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/test/panic/holy-grail.js b/test/panic/holy-grail.js index d96dfa2a..188d0499 100644 --- a/test/panic/holy-grail.js +++ b/test/panic/holy-grail.js @@ -45,6 +45,7 @@ describe("The Holy Grail Test!", function(){ }); it("GUN started!", function(){ + console.log("I must have screwed up my NPM installs, server won't start properly but Holy-Grail passes if I do it manually. Will fix later."); return server.run(function(test){ var env = test.props; test.async(); From 8fff5e9a1fe4af76151b913dad51f3847c902718 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Wed, 29 Aug 2018 15:03:27 -0700 Subject: [PATCH 105/221] SEA & DAM fix --- examples/game/space.html | 25 ++++++++++++- gun.js | 72 ++++++++++++++++++++++++------------ gun.min.js | 3 +- lib/webrtc.js | 27 +++++--------- lib/wire.js | 30 ++++++--------- nts.js | 7 ++-- package.json | 3 +- sea.js | 13 ++++--- sea/shim.js | 9 +++-- sea/verify.js | 4 +- src/adapters/localStorage.js | 2 +- src/adapters/mesh.js | 64 ++++++++++++++++++++++++-------- src/adapters/websocket.js | 16 +++----- src/root.js | 4 +- test/tmp/seanode.js | 13 +++++++ test/tmp/space.html | 50 +++++++++++++++++++++++++ 16 files changed, 236 insertions(+), 106 deletions(-) create mode 100644 test/tmp/seanode.js create mode 100644 test/tmp/space.html diff --git a/examples/game/space.html b/examples/game/space.html index edfdae50..f393be5b 100644 --- a/examples/game/space.html +++ b/examples/game/space.html @@ -7,9 +7,11 @@
          +

          +

          Hello world!

          - - + - - -

          - - - \ No newline at end of file + From 6126f4be65144dfee2775d2041a2422398eb09d5 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Fri, 21 Sep 2018 16:06:36 -0700 Subject: [PATCH 114/221] Update indexedDB.html --- test/tmp/indexedDB.html | 1 - 1 file changed, 1 deletion(-) diff --git a/test/tmp/indexedDB.html b/test/tmp/indexedDB.html index 284dcf7d..159fcd2e 100644 --- a/test/tmp/indexedDB.html +++ b/test/tmp/indexedDB.html @@ -1,6 +1,5 @@

          RindexedDB

          - From 5289126d1356c8f6f2d929f5491610103f6df251 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Sun, 23 Sep 2018 01:23:21 -0700 Subject: [PATCH 115/221] fix NodeJS SEA auth w/ PBKDF2 --- examples/basic/user.html | 8 +-- gun.js | 3 +- package-lock.json | 41 ++++++++-------- package.json | 4 +- sea.js | 102 ++++++++++++++++++--------------------- 5 files changed, 77 insertions(+), 81 deletions(-) diff --git a/examples/basic/user.html b/examples/basic/user.html index 62a782aa..c736c67b 100644 --- a/examples/basic/user.html +++ b/examples/basic/user.html @@ -11,7 +11,7 @@
          - +
          @@ -19,8 +19,8 @@ - - - - \ No newline at end of file diff --git a/test/tmp/bigsync.js b/test/tmp/bigsync.js index 5119d726..10f5cba7 100644 --- a/test/tmp/bigsync.js +++ b/test/tmp/bigsync.js @@ -1,17 +1,25 @@ var Gun = require('../../'); -var data = require('fs').readFileSync('/Users/mark/Downloads/raddataformat.txt'); +/*var data = ''; +var a = [], b = Gun.text.random(1000 * 1000 * 10), c; +for(var i = 0; i <= 7; i++){ + data += b; +} +*/ +data = 1; -data = data.toString(); -data += data + data; - -console.log(data.length); - -var gun = Gun('http://localhost:8080/gun'); +var gun = Gun('http://localhost:8765/gun'); +//var gun = Gun(); setTimeout(function(){ + + /*console.log("READ!"); + gun.get('bigsync').get('raw').on(function(a,b){ + console.log('yay!', b, (a && a.slice && a.slice(0,20)) || a, a.length); + }); + return;*/ console.log("SEND!"); - gun.get('bigsync').get('raw').put(data); + gun.get('bigsync').get('raw').put(data, function(ack){console.log(ack)}); /*var req = require('http').request({ host: 'localhost' diff --git a/test/tmp/nab.html b/test/tmp/nab.html deleted file mode 100644 index a5c4b368..00000000 --- a/test/tmp/nab.html +++ /dev/null @@ -1,101 +0,0 @@ -

          notabug

          - - - - - - - -

          homepage

          -
            -
          - - - - - - - - \ No newline at end of file From d269419c96e3bde38c06c8b119f44e658407629e Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Tue, 25 Sep 2018 15:46:50 -0700 Subject: [PATCH 119/221] unbuild Stabilized against V8 Fatalities. --- gun.min.js | 4 ++-- package-lock.json | 2 +- package.json | 2 +- src/adapters/localStorage.js | 2 +- src/adapters/mesh.js | 34 ++++++++++++++++++++++------------ src/dup.js | 2 +- 6 files changed, 28 insertions(+), 18 deletions(-) diff --git a/gun.min.js b/gun.min.js index adfd5edc..61285cd0 100644 --- a/gun.min.js +++ b/gun.min.js @@ -1,2 +1,2 @@ -!function(){function t(n,o){function e(t){return t.split("/").slice(-1).toString().replace(".js","")}return o?require(n):n.slice?t[e(n)]:function(o,i){n(o={exports:{}}),t[e(i)]=o.exports}}var n;"undefined"!=typeof window&&(n=window),"undefined"!=typeof global&&(n=global),n=n||{};var o=n.console||{log:function(){}};if("undefined"!=typeof module)var e=module;t(function(t){var n={};n.fn={is:function(t){return!!t&&"function"==typeof t}},n.bi={is:function(t){return t instanceof Boolean||"boolean"==typeof t}},n.num={is:function(t){return!e(t)&&(t-parseFloat(t)+1>=0||1/0===t||-(1/0)===t)}},n.text={is:function(t){return"string"==typeof t}},n.text.ify=function(t){return n.text.is(t)?t:"undefined"!=typeof JSON?JSON.stringify(t):t&&t.toString?t.toString():t},n.text.random=function(t,n){var o="";for(t=t||24,n=n||"0123456789ABCDEFGHIJKLMNOPQRSTUVWXZabcdefghijklmnopqrstuvwxyz";t>0;)o+=n.charAt(Math.floor(Math.random()*n.length)),t--;return o},n.text.match=function(t,o){function e(t,n){for(var o,e=-1,i=0;o=n[i++];)if(!~(e=t.indexOf(o,e+1)))return!1;return!0}var i=!1;if(t=t||"",o=n.text.is(o)?{"=":o}:o||{},n.obj.has(o,"~")&&(t=t.toLowerCase(),o["="]=(o["="]||o["~"]).toLowerCase()),n.obj.has(o,"="))return t===o["="];if(n.obj.has(o,"*")){if(t.slice(0,o["*"].length)!==o["*"])return!1;i=!0,t=t.slice(o["*"].length)}if(n.obj.has(o,"!")){if(t.slice(-o["!"].length)!==o["!"])return!1;i=!0}if(n.obj.has(o,"+")&&n.list.map(n.list.is(o["+"])?o["+"]:[o["+"]],function(n){return t.indexOf(n)>=0?void(i=!0):!0}))return!1;if(n.obj.has(o,"-")&&n.list.map(n.list.is(o["-"])?o["-"]:[o["-"]],function(n){return t.indexOf(n)<0?void(i=!0):!0}))return!1;if(n.obj.has(o,">")){if(!(t>o[">"]))return!1;i=!0}if(n.obj.has(o,"<")){if(!(tn?-1:n>o?1:0):0}},n.list.map=function(t,n,o){return a(t,n,o)},n.list.index=1,n.obj={is:function(t){return t?t instanceof Object&&t.constructor===Object||"Object"===Object.prototype.toString.call(t).match(/^\[object (\w+)\]$/)[1]:!1}},n.obj.put=function(t,n,o){return(t||{})[n]=o,t},n.obj.has=function(t,n){return t&&Object.prototype.hasOwnProperty.call(t,n)},n.obj.del=function(t,n){return t?(t[n]=null,delete t[n],t):void 0},n.obj.as=function(t,n,o,e){return t[n]=t[n]||(e===o?{}:o)},n.obj.ify=function(t){if(r(t))return t;try{t=JSON.parse(t)}catch(n){t={}}return t},function(){function t(t,n){u(this,n)&&o!==this[n]||(this[n]=t)}var o;n.obj.to=function(n,o){return o=o||{},a(n,t,o),o}}(),n.obj.copy=function(t){return t?JSON.parse(JSON.stringify(t)):t},function(){function t(t,n){var o=this.n;if(!o||!(n===o||r(o)&&u(o,n)))return n?!0:void 0}n.obj.empty=function(n,o){return n&&a(n,t,{n:o})?!1:!0}}(),function(){function t(n,o){return 2===arguments.length?(t.r=t.r||{},void(t.r[n]=o)):(t.r=t.r||[],void t.r.push(n))}var i=Object.keys;n.obj.map=function(a,s,f){var c,l,p,d,h,v=0,g=o(s);if(t.r=null,i&&r(a)&&(d=i(a),h=!0),e(a)||d)for(l=(d||a).length;l>v;v++){var m=v+n.list.index;if(g){if(p=h?s.call(f||this,a[d[v]],d[v],t):s.call(f||this,a[v],m,t),p!==c)return p}else if(s===a[h?d[v]:v])return d?d[v]:m}else for(v in a)if(g){if(u(a,v)&&(p=f?s.call(f,a[v],v,t):s(a[v],v,t),p!==c))return p}else if(s===a[v])return v;return g?t.r:n.list.index?0:-1}}(),n.time={},n.time.is=function(t){return t?t instanceof Date:+(new Date).getTime()};var o=n.fn.is,e=n.list.is,i=n.obj,r=i.is,u=i.has,a=i.map;t.exports=n})(t,"./type"),t(function(t){t.exports=function n(t,o,e){if(!t)return{to:n};var i,t=(this.tag||(this.tag={}))[t]||(this.tag[t]={tag:t,to:n._={next:function(t){var n;(n=this.to)&&n.next(t)}}});if(o instanceof Function){var r={off:n.off||(n.off=function(){return this.next===n._.next?!0:(this===this.the.last&&(this.the.last=this.back),this.to.back=this.back,this.next=n._.next,this.back.to=this.to,void(this.the.last===this.the&&delete this.on.tag[this.the.tag]))}),to:n._,next:o,the:t,on:this,as:e};return(r.back=t.last||t).to=r,t.last=r}return(t=t.to)&&i!==o&&t.next(o),t}})(t,"./onto"),t(function(t){function n(t,n,e,i,r){if(n>t)return{defer:!0};if(e>n)return{historical:!0};if(n>e)return{converge:!0,incoming:!0};if(n===e){if(i=o(i)||"",r=o(r)||"",i===r)return{state:!0};if(r>i)return{converge:!0,current:!0};if(i>r)return{converge:!0,incoming:!0}}return{err:"Invalid CRDT Data: "+i+" to "+r+" at "+n+" to "+e+"!"}}if("undefined"==typeof JSON)throw new Error("JSON is not included in this browser. Please load it first: ajax.cdnjs.com/ajax/libs/json2/20110223/json2.js");var o=JSON.stringify;t.exports=n})(t,"./HAM"),t(function(n){var o=t("./type"),e={};e.is=function(t){return t===i?!1:null===t?!0:t===1/0?!1:s(t)||u(t)||a(t)?!0:e.rel.is(t)||!1},e.link=e.rel={_:"#"},function(){function t(t,n){var o=this;return o.id?o.id=!1:n==r&&s(t)?void(o.id=t):o.id=!1}e.rel.is=function(n){if(n&&n[r]&&!n._&&c(n)){var o={};if(p(n,t,o),o.id)return o.id}return!1}}(),e.rel.ify=function(t){return l({},r,t)},o.obj.has._=".";var i,r=e.link._,u=o.bi.is,a=o.num.is,s=o.text.is,f=o.obj,c=f.is,l=f.put,p=f.map;n.exports=e})(t,"./val"),t(function(n){var o=t("./type"),e=t("./val"),i={_:"_"};i.soul=function(t,n){return t&&t._&&t._[n||p]},i.soul.ify=function(t,n){return n="string"==typeof n?{soul:n}:n||{},t=t||{},t._=t._||{},t._[p]=n.soul||t._[p]||l(),t},i.soul._=e.link._,function(){function t(t,n){return n!==i._?e.is(t)?void(this.cb&&this.cb.call(this.as,t,n,this.n,this.s)):!0:void 0}i.is=function(n,o,e){var r;return a(n)&&(r=i.soul(n))?!f(n,t,{as:e,cb:o,s:r,n:n}):!1}}(),function(){function t(t,n){var o,i,r=this.o;return r.map?(o=r.map.call(this.as,t,""+n,r.node),void(i===o?s(r.node,n):r.node&&(r.node[n]=o))):void(e.is(t)&&(r.node[n]=t))}i.ify=function(n,o,e){return o?"string"==typeof o?o={soul:o}:o instanceof Function&&(o={map:o}):o={},o.map&&(o.node=o.map.call(e,n,r,o.node||{})),(o.node=i.soul.ify(o.node||{},o))&&f(n,t,{o:o,as:e}),o.node}}();var r,u=o.obj,a=u.is,s=u.del,f=u.map,c=o.text,l=c.random,p=i.soul._;n.exports=i})(t,"./node"),t(function(n){function o(){var t;return t=r(),t>u?(a=0,u=t+o.drift):u=t+(a+=1)/s+o.drift}{var e=t("./type"),i=t("./node"),r=e.time.is,u=-(1/0),a=0,s=1e3,f="undefined"!=typeof performance?performance.timing&&performance:!1;f&&f.timing&&f.timing.navigationStart||(f=!1)}o._=">",o.drift=0,o.is=function(t,n,e){var i=n&&t&&t[_]&&t[_][o._]||e;if(i)return b(i=i[n])?i:-(1/0)},o.lex=function(){return o().toString(36).replace(".","")},o.ify=function(t,n,e,r,u){if(!t||!t[_]){if(!u)return;t=i.soul.ify(t,u)}var a=p(t[_],o._);return c!==n&&n!==_&&(b(e)&&(a[n]=e),c!==r&&(t[n]=r)),t},o.to=function(t,n,e){var r=t[n];return h(r)&&(r=g(r)),o.ify(e,n,o.is(t,n),r,i.soul(t))},function(){function t(t,n){_!==n&&o.ify(this.o,n,this.s)}o.map=function(n,e,i){var r,u=h(u=n||e)?u:null;return n=y(n=n||e)?n:null,u&&!n?(e=b(e)?e:o(),u[_]=u[_]||{},v(u,t,{o:u,s:e}),u):(i=i||h(e)?e:r,e=b(e)?e:o(),function(o,u,a,s){return n?(n.call(i||this||{},o,u,a,s),void(d(a,u)&&r===a[u]||t.call({o:a,s:e},o,u))):(t.call({o:a,s:e},o,u),o)})}}();var c,l=e.obj,p=l.as,d=l.has,h=l.is,v=l.map,g=l.copy,m=e.num,b=m.is,k=e.fn,y=k.is,_=i._;n.exports=o})(t,"./state"),t(function(n){var o=t("./type"),e=t("./val"),i=t("./node"),r={};!function(){function t(t,o){return t&&o===i.soul(t)&&i.is(t,this.fn,this.as)?void(this.cb&&(n.n=t,n.as=this.as,this.cb.call(n.as,t,o,n))):!0}function n(t){t&&i.is(n.n,t,n.as)}r.is=function(n,o,e,i){return n&&s(n)&&!l(n)?!d(n,t,{cb:o,fn:e,as:i}):!1}}(),function(){function t(t,o){var r;return(r=p(t,o))?r:(o.env=t,o.soul=a,i.ify(o.obj,n,o)&&(o.rel=o.rel||e.rel.ify(i.soul(o.node)),o.obj!==t.shell&&(t.graph[e.rel.is(o.rel)]=o.node)),o)}function n(n,o,r){var a,s,p=this,d=p.env;if(i._===o&&c(n,e.rel._))return r._;if(a=l(n,o,r,p,d)){if(o||(p.node=p.node||r||{},c(n,i._)&&i.soul(n)&&(p.node._=h(n._)),p.node=i.soul.ify(p.node,e.rel.is(p.rel)),p.rel=p.rel||e.rel.ify(i.soul(p.node))),(s=d.map)&&(s.call(d.as||{},n,o,r,p),c(r,o))){if(n=r[o],u===n)return void f(r,o);if(!(a=l(n,o,r,p,d)))return}if(!o)return p.node;if(!0===a)return n;if(s=t(d,{obj:n,path:p.path.concat(o)}),s.node)return s.rel}}function a(t){var n=this,o=e.link.is(n.rel),r=n.env.graph;n.rel=n.rel||e.rel.ify(t),n.rel[e.rel._]=t,n.node&&n.node[i._]&&(n.node[i._][e.rel._]=t),c(r,o)&&(r[t]=r[o],f(r,o))}function l(t,n,i,r,u){var a;return e.is(t)?!0:s(t)?1:(a=u.invalid)?(t=a.call(u.as||{},t,n,i),l(t,n,i,r,u)):(u.err="Invalid value at '"+r.path.concat(n).join(".")+"'!",void(o.list.is(t)&&(u.err+=" Use `.set(item)` instead of an Array.")))}function p(t,n){for(var o,e=t.seen,i=e.length;i--;)if(o=e[i],n.obj===o.obj)return o;e.push(n)}r.ify=function(n,o,i){var r={path:[],obj:n};return o?"string"==typeof o?o={soul:o}:o instanceof Function&&(o.map=o):o={},o.soul&&(r.rel=e.rel.ify(o.soul)),o.shell=(i||{}).shell,o.graph=o.graph||{},o.seen=o.seen||[],o.as=o.as||i,t(o,r),o.root=r.node,o.graph}}(),r.node=function(t){var n=i.soul(t);if(n)return p({},n,t)},function(){function t(t,n){var o,u;if(i._===n){if(l(t,e.rel._))return;return void(this.obj[n]=h(t))}return(o=e.rel.is(t))?(u=this.opt.seen[o])?void(this.obj[n]=u):void(this.obj[n]=this.opt.seen[o]=r.to(this.graph,o,this.opt)):void(this.obj[n]=t)}r.to=function(n,o,e){if(n){var i={};return e=e||{seen:{}},d(n[o],t,{obj:i,graph:n,opt:e}),i}}}();var u,a=(o.fn.is,o.obj),s=a.is,f=a.del,c=a.has,l=a.empty,p=a.put,d=a.map,h=a.copy;n.exports=r})(t,"./graph"),t(function(n){t("./onto"),n.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}var 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}}})(t,"./ask"),t(function(n){function o(t){var n={s:{}};return t=t||{max:1e3,age:9e3},n.check=function(t){var o;return(o=n.s[t])?o.pass?o.pass=!1:n.track(t):!1},n.track=function(o,r){var u=n.s[o]||(n.s[o]={});return u.was=i(),r&&(u.pass=!0),n.to||(n.to=setTimeout(function(){var o=i();e.obj.map(n.s,function(i,r){t.age>o-i.was||e.obj.del(n.s,r)}),n.to=null},t.age+9)),u},n}var e=t("./type"),i=e.time.is;n.exports=o})(t,"./dup"),t(function(n){function i(t){return t instanceof i?(this._={gun:this,$:this}).$:this instanceof i?i.create(this._={gun:this,$:this,opt:t}):new i(t)}i.is=function(t){return t instanceof i||t&&t._&&t===t._.$||!1},i.version=.9,i.chain=i.prototype,i.chain.toJSON=function(){};var r=t("./type");r.obj.to(r,i),i.HAM=t("./HAM"),i.val=t("./val"),i.node=t("./node"),i.state=t("./state"),i.graph=t("./graph"),i.on=t("./onto"),i.ask=t("./ask"),i.dup=t("./dup"),function(){function t(n){var o,e,r=this,a=r.as,s=a.at||a,f=s.$;return(e=n["#"])||(e=n["#"]=c(9)),(o=s.dup).check(e)?void(a.out===n.out&&(n.out=u,r.to.next(n))):(o.track(e),s.ask(n["@"],n)||(n.get&&i.on.get(n,f),n.put&&i.on.put(n,f)),r.to.next(n),void(a.out||(n.out=t,s.on("out",n))))}i.create=function(n){n.root=n.root||n,n.graph=n.graph||{},n.on=n.on||i.on,n.ask=n.ask||i.ask,n.dup=n.dup||i.dup();var o=n.$.opt(n.opt);return n.once||(n.on("in",t,n),n.on("out",t,{at:n,out:t}),i.on("create",n),n.on("create",n)),n.once=1,o}}(),function(){function t(t,n,o,e){var r=this,u=i.state.is(o,n);if(!u)return r.err="Error: No state on '"+n+"' in node '"+e+"'!";var a=r.graph[e]||k,s=i.state.is(a,n,!0),f=a[n],c=i.HAM(r.machine,u,s,t,f);return c.incoming?(r.put[e]=i.state.to(o,n,r.put[e]),(r.diff||(r.diff={}))[e]=i.state.to(o,n,r.diff[e]),void(r.souls[e]=!0)):void(c.defer&&(r.defer=u<(r.defer||1/0)?u:r.defer))}function n(t,n){var i=this,u=i.$._,a=(u.next||k)[n];if(!a){if(!(u.opt||k)["super"])return void(i.souls[n]=!1);a=i.$.get(n)._}var s=i.map[n]={put:t,get:n,$:a.$},f={ctx:i,msg:s};i.async=!!u.tag.node,i.ack&&(s["@"]=i.ack),v(t,o,f),i.async&&(i.and||u.on("node",function(t){this.to.next(t),t===i.map[t.get]&&(i.souls[t.get]=!1,v(t.put,e,t),v(i.souls,function(t){return t?t:void 0})||i.c||(i.c=1,this.off(),v(i.map,r,i)))}),i.and=!0,u.on("node",s))}function o(t,n){var o=this.ctx,e=o.graph,r=this.msg,u=r.get,a=r.put,s=r.$._;e[u]=i.state.to(a,n,e[u]),o.async||(s.put=i.state.to(a,n,s.put))}function e(t,n){var o=this,e=o.put,r=o.$._;r.put=i.state.to(e,n,r.put)}function r(t){t.$&&(this.cat.stop=this.stop,t.$._.on("in",t),this.cat.stop=null)}i.on.put=function(o,e){var a=e._,s={$:e,graph:a.graph,put:{},map:{},souls:{},machine:i.state(),ack:o["@"],cat:a,stop:{}};return i.graph.is(o.put,null,t,s)||(s.err="Error: Invalid graph!"),s.err?a.on("in",{"@":o["#"],err:i.log(s.err)}):(v(s.put,n,s),s.async||v(s.map,r,s),u!==s.defer&&setTimeout(function(){i.on.put(o,e)},s.defer-s.machine),void(s.diff&&a.on("put",h(o,{put:s.diff}))))},i.on.get=function(t,n){var o,e=n._,r=t.get,u=r[m],a=e.graph[u],s=r[b],f=e.next||(e.next={}),c=f[u];if(d(u,"*")){var l={};i.obj.map(e.graph,function(t,n){i.text.match(n,u)&&(l[n]=i.obj.copy(t))}),i.obj.empty(l)||e.on("in",{"@":t["#"],how:"*",put:l,$:n})}if(!a)return e.on("get",t);if(s){if(!d(a,s))return e.on("get",t);a=i.state.to(a,s)}else a=i.obj.copy(a);a=i.graph.node(a),o=(c||k).ack,e.on("in",{"@":t["#"],how:"mem",put:a,$:n}),e.on("get",t)}}(),function(){i.chain.opt=function(t){t=t||{};var n=this,o=n._,e=t.peers||t;return p(t)||(t={}),p(o.opt)||(o.opt=t),f(e)&&(e=[e]),a(e)&&(e=v(e,function(t,n,o){o(t,{url:t})}),p(o.opt.peers)||(o.opt.peers={}),o.opt.peers=h(e,o.opt.peers)),o.opt.peers=o.opt.peers||{},h(t,o.opt),i.on("opt",o),o.opt.uuid=o.opt.uuid||function(){return g()+c(12)},n}}();var u,a=i.list.is,s=i.text,f=s.is,c=s.random,l=i.obj,p=l.is,d=l.has,h=l.to,v=l.map,g=(l.copy,i.state.lex),m=i.val.rel._,b=".",k=(i.node._,i.val.link.is,{});o.debug=function(t,n){return o.debug.i&&t===o.debug.i&&o.debug.i++&&(o.log.apply(o,arguments)||n)},i.log=function(){return!i.log.off&&o.log.apply(o,arguments),[].slice.call(arguments).join(" ")},i.log.once=function(t,n,o){return(o=i.log.once)[t]=o[t]||0,o[t]++||i.log(n)},i.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=i).window=window);try{"undefined"!=typeof e&&(e.exports=i)}catch(y){}n.exports=i})(t,"./root"),t(function(){var n=t("./root");n.chain.back=function(t,i){var r;if(t=t||1,-1===t||1/0===t)return this._.root.$;if(1===t)return(this._.back||this._).$;var u=this,a=u._;if("string"==typeof t&&(t=t.split(".")),!(t instanceof Array)){if(t instanceof Function){for(var s,r={back:a};(r=r.back)&&o===(s=t(r,i)););return s}return n.num.is(t)?(a.back||a).$.back(t-1):this}var f=0,c=t.length,r=a;for(f;c>f;f++)r=(r||e)[t[f]];return o!==r?i?u:r:(r=a.back)?r.$.back(t,i):void 0};var o,e={}})(t,"./back"),t(function(){function n(t){var n,o,e,i=this.as,r=i.back,u=i.root;if(t.I||(t.I=i.$),t.$||(t.$=i.$),this.to.next(t),o=t.get){if(o["#"]||i.soul){if(o["#"]=o["#"]||i.soul,t["#"]||(t["#"]=b(9)),r=u.$.get(o["#"])._,o=o["."]){if(h(r.put,o)&&(n=r.$.get(o)._,(e=n.ack)||(n.ack=-1),r.on("in",{$:r.$,put:c.state.to(r.put,o),get:r.get}),e))return}else{if(e=r.ack,e||(r.ack=-1),h(r,"put")&&r.on("in",r),e)return;t.$=r.$}return u.ask(f,t),u.on("in",t)}if(u.now&&(u.now[i.id]=u.now[i.id]||!0,i.pass={}),o["."])return i.get?(t={get:{".":i.get},$:i.$},r.ask||(r.ask={}),r.ask[i.get]=t.$._,r.on("out",t)):(t={get:{},$:i.$},r.on("out",t));if(i.ack=i.ack||-1,i.get)return t.$=i.$,o["."]=i.get,(r.ask||(r.ask={}))[i.get]=t.$._,r.on("out",t)}return r.on("out",t)}function o(t){var n,o,r=this,s=r.as,f=s.root,d=t.$,b=(d||p)._||p,k=t.put;if(s.get&&t.get!==s.get&&(t=g(t,{get:s.get})),s.has&&b!==s&&(t=g(t,{$:s.$}),b.ack&&(s.ack=b.ack)),l===k){if(o=b.put,r.to.next(t),s.soul)return;if(l===o&&l!==b.put)return;return i(s,t,r),s.has&&a(s,t),v(b.echo,s.id),void v(s.map,b.id)}if(s.soul)return r.to.next(t),i(s,t,r),void(s.next&&m(k,u,{msg:t,cat:s}));if(!(n=c.val.link.is(k)))return c.val.is(k)?(s.has||s.soul?a(s,t):(b.has||b.soul)&&((b.echo||(b.echo={}))[s.id]=b.echo[b.id]||s,(s.map||(s.map={}))[b.id]=s.map[b.id]||{at:b}),r.to.next(t),void i(s,t,r)):(s.has&&b!==s&&h(b,"put")&&(s.put=b.put),(n=c.node.soul(k))&&b.has&&(b.put=s.root.$.get(n)._.put),o=(f.stop||{})[b.id],r.to.next(t),e(s,t,b,n),i(s,t,r),void(s.next&&m(k,u,{msg:t,cat:s})));f.stop;o=f.stop||{},o=o[b.id]||(o[b.id]={}),o.is=o.is||b.put,o[s.id]=b.put||!0,r.to.next(t),e(s,t,b,n),i(s,t,r)}function e(t,n,o,i){if(i&&k!==t.get){var r=t.root.$.get(i)._;t.has?o=r:o.has&&e(o,n,o,i),o!==t&&(o.$||(o={}),(o.echo||(o.echo={}))[t.id]=o.echo[t.id]||t,t.has&&!(t.map||p)[o.id]&&a(t,n),r=o.id?(t.map||(t.map={}))[o.id]=t.map[o.id]||{at:o}:{},(i!==r.link||r.pass||t.pass)&&(t.pass&&(c.obj.map(t.map,function(t){t.pass=!0}),v(t,"pass")),r.pass&&v(r,"pass"),t.has&&(t.link=i),s(t,r.link=i)))}}function i(t,n){t.echo&&m(t.echo,r,n)}function r(t){t&&t.on&&t.on("in",this)}function u(t,n){var o,e,i,r=this.cat,u=r.next||p,a=this.msg;(k!==n||u[n])&&(e=u[n])&&(e.has?(l!==e.put&&c.val.link.is(t)||(e.put=t),o=e.$):(i=a.$)&&(i=(o=a.$.get(n))._,l!==i.put&&c.val.link.is(t)||(i.put=t)),e.on("in",{put:t,get:n,$:o,via:a}))}function a(t,n){if(t.has||t.soul){{var o=t.map;t.root}t.map=null,t.has&&(t.link=null),(t.pass||n["@"]||null!==o)&&(l===o&&c.val.link.is(t.put)||(m(o,function(n){(n=n.at)&&v(n.echo,t.id)}),o=t.put,m(t.next,function(n,e){return l===o&&l!==t.put?!0:(n.put=l,n.ack&&(n.ack=-1),void n.on("in",{get:e,$:n.$,put:l}))})))}}function s(t,n){var o=t.root.$.get(n)._;(!t.ack||(o.on("out",{get:{"#":n}}),t.ask))&&(o=t.ask,c.obj.del(t,"ask"),m(o||t.next,function(t,o){t.on("out",{get:{"#":n,".":o}})}),c.obj.del(t,"ask"))}function f(t){var n=this.as,o=n.get||p,e=n.$._,i=(t.put||p)[o["#"]];if(e.ack&&(e.ack=e.ack+1||1),!t.put||o["."]&&!h(i,e.get)){if(e.put!==l)return;return void e.on("in",{get:e.get,put:e.put=l,$:e.$,"@":t["@"]})}return k==o["."]?void e.on("in",{get:e.get,put:c.val.link.ify(o["#"]),$:e.$,"@":t["@"]}):(t.$=e.root.$,void c.on.put(t,e.root.$))}var c=t("./root");c.chain.chain=function(t){var e,i=this,r=i._,u=new(t||i).constructor(i),a=u._;return a.root=e=r.root,a.id=++e.once,a.back=i._,a.on=c.on,a.on("in",o,a),a.on("out",n,a),u};var l,p={},d=c.obj,h=d.has,v=(d.put,d.del),g=d.to,m=d.map,b=c.text.random,k=(c.val.rel._,c.node._)})(t,"./chain"),t(function(){function n(t,n){var o=n._,e=o.next,i=n.chain(),r=i._;return e||(e=o.next={}),e[r.get=t]=r,n===o.root.$?r.soul=t:(o.soul||o.has)&&(r.has=t),r}function o(t,n,o,e){var i,r=t._;return(i=r.soul)?(n(i,e,r),t):(i=r.link)?(n(i,e,r),t):(t.get(function(t,o){o.rid(t);var r=(r=t.$)&&r._||{};i=r.link||r.soul||c.is(t.put)||l(t.put),n(i,e,t,o)},{out:{get:{".":!0}}}),t)}function e(t){var n,o=this,e=o.as,i=e.at,r=i.root,a=t.$,f=(a||{})._||{},l=t.put||f.put;if((n=r.now)&&o!==n[e.now])return o.to.next(t);if(o.seen&&f.id&&o.seen[f.id])return o.to.next(t);if((n=l)&&n[c._]&&(n=c.is(n))&&(n=(t.$$=f.root.gun.get(n))._,u!==n.put&&(t=s(t,{put:l=n.put}))),(n=r.mum)&&f.id){if(n[f.id])return;u===l||c.is(l)||(n[f.id]=!0)}return e.use(t,o),o.stun?void(o.stun=null):void o.to.next(t)}function i(t){var n=this.on;if(!t||n.soul||n.has)return this.off();if(t=(t=(t=t.$||t)._||t).id){{var o,e;n.map}return(o=(e=this.seen||(this.seen={}))[t])?!0:void(e[t]=!0)}}var r=t("./root");r.chain.get=function(t,u,a){var s,l;if("string"!=typeof t){if(t instanceof Function){if(!0===u)return o(this,t,u,a);s=this;var d,h=s._,v=h.root,l=v.now;a=u||{},a.at=h,a.use=t,a.out=a.out||{},a.out.get=a.out.get||{},(d=h.on("in",e,a)).rid=i,(v.now={$:1})[a.now=h.id]=d;var g=v.mum;return v.mum={},h.on("out",a.out),v.mum=g,v.now=l,s}return f(t)?this.get(""+t,u,a):(l=c.is(t))?this.get(l,u,a):((a=this.chain())._.err={err:r.log("Invalid get request!",t)},u&&u.call(a,a._.err),a)}var m=this,b=m._,k=b.next||p;return(s=k[t])||(s=n(t,m)),s=s.$,(l=b.stun)&&(s._.stun=s._.stun||l),u&&u instanceof Function&&s.get(u,a),s};var u,a=r.obj,s=(a.has,r.obj.to),f=r.num.is,c=r.val.link,l=r.node.soul,p=(r.node._,{})})(t,"./get"),t(function(){function n(t){t.batch=i;var n=t.opt||{},o=t.env=c.state.map(u,n.state);return o.soul=t.soul,t.graph=c.graph.ify(t.data,o,t),o.err?((t.ack||m).call(t,t.out={err:c.log(o.err)}),void(t.res&&t.res())):void t.batch()}function e(t){return void(t&&t())}function i(){var t=this;t.graph&&!v(t.stun,r)&&(t.res=t.res||function(t){t&&t()},t.res(function(){var n=t.$.back(-1)._,o=n.ask(function(o){n.root.on("ack",o),o.err&&c.log(o),o.lack||this.off(),t.ack&&t.ack(o,this)},t.opt),e=n.root.now;p.del(n.root,"now");var i=n.root.mum;n.root.mum={},t.ref._.on("out",{$:t.ref,put:t.out=t.env.graph,opt:t.opt,"#":o}),n.root.mum=i?p.to(i,n.root.mum):i,n.root.now=e},t),t.res&&t.res())}function r(t){return t?!0:void 0}function u(t,n,o,e){var i=this,r=c.is(t);!n&&e.path.length&&(i.res||b)(function(){var n=e.path,o=i.ref,u=(i.opt,0),s=n.length;for(u;s>u;u++)o=o.get(n[u]);r&&(o=t);var f=o._.dub;return f||(f=c.node.soul(e.obj))?(o.back(-1).get(f),void e.soul(f)):((i.stun=i.stun||{})[n]=!0,void o.get(a,!0,{as:{at:e,as:i,p:n}}))},{as:i,at:e})}function a(t,n,o,e){var n=n.as,i=n.at;n=n.as;var r=((o||{}).$||{})._||{};return t=r.dub=r.dub||t||c.node.soul(i.obj)||c.node.soul(o.put||r.put)||c.val.rel.is(o.put||r.put)||(n.via.back("opt.uuid")||c.text.random)(),e&&(e.stun=!0),t?void s(r,r.dub=t,i,n):void r.via.back("opt.uuid")(function(t,o){return t?c.log(t):void s(r,r.dub=r.dub||o,i,n)})}function s(t,n,o,e){t.$.back(-1).get(n),o.soul(n),e.stun[o.path]=!1,e.batch()}function f(t,n,e,i){if(n=n.as,e.$&&e.$._){if(e.err)return void o.log("Please report this as an issue! Put.any.err");var r,u=e.$._,a=u.put,s=n.opt||{};if(!(r=n.ref)||!r._.now){if(i&&(i.stun=!0),n.ref!==n.$){if(r=n.$._.get||u.get,!r)return void o.log("Please report this as an issue! Put.no.get");n.data=h({},r,n.data),r=null}if(l===a){if(!u.get)return;t||(r=u.$.back(function(t){return t.link||t.soul?t.link||t.soul:void(n.data=h({},t.get,n.data))})),r=r||u.get,u=u.root.$.get(r)._,n.soul=r,a=n.data}return n.not||(n.soul=n.soul||t)||(n.path&&d(n.data)?n.soul=(s.uuid||n.via.back("opt.uuid")||c.text.random)():(k==u.get&&(n.soul=(u.put||g)["#"]||u.dub),n.soul=n.soul||u.soul||u.soul||(s.uuid||n.via.back("opt.uuid")||c.text.random)()),n.soul)?void n.ref.put(n.data,n.soul,n):void n.via.back("opt.uuid")(function(t,o){return t?c.log(t):void n.ref.put(n.data,n.soul=o,n)})}}}var c=t("./root");c.chain.put=function(t,o,i){var r,u=this,a=u._,s=a.root.$;return i=i||{},i.data=t,i.via=i.$=i.via||i.$||u,"string"==typeof o?i.soul=o:i.ack=i.ack||o,a.soul&&(i.soul=a.soul),i.soul||s===u?d(i.data)?(i.soul=i.soul||(i.not=c.node.soul(i.data)||(i.via.back("opt.uuid")||c.text.random)()),i.soul?(i.$=u=s.get(i.soul),i.ref=i.$,n(i),u):(i.via.back("opt.uuid")(function(t,n){return t?c.log(t):void(i.ref||i.$).put(i.data,i.soul=n,i)}),u)):((i.ack||m).call(i,i.out={err:c.log("Data saved to the root level of the graph must be a node (an object), not a",typeof i.data,'of "'+i.data+'"!')}),i.res&&i.res(),u):c.is(t)?(t.get(function(t,n,e){return!t&&c.val.is(e.put)?c.log("The reference you are saving is a",typeof e.put,'"'+e.put+'", not a node (object)!'):void u.put(c.val.rel.ify(t),o,i)},!0),u):(i.ref=i.ref||s._===(r=a.back)?u:r.$,i.ref._.soul&&c.val.is(i.data)&&a.get?(i.data=h({},a.get,i.data),i.ref.put(i.data,i.soul,i),u):(i.ref.get(f,!0,{as:i}),i.out||(i.res=i.res||e,i.$._.stun=i.ref._.stun),u))};var l,p=c.obj,d=p.is,h=p.put,v=p.map,g={},m=function(){},b=function(t,n){t.call(n||g)},k=c.node._})(t,"./put"),t(function(n){var o=t("./root");t("./chain"),t("./back"),t("./put"),t("./get"),n.exports=o})(t,"./index"),t(function(){function n(t,n){{var o,e=this,r=t.$,u=(r||{})._||{},a=u.put||t.put;e.at}if(i!==a){if(o=t.$$){if(o=t.$$._,i===o.put)return;a=o.put}e.change&&(a=t.put),e.as?e.ok.call(e.as,t,n):e.ok.call(r,a,t.get,t,n)}}function o(t,n,e){var r,a,s=this.as,f=(s.at,t.$),c=f._,l=c.put||t.put;if(a=t.$$){if(r=a=t.$$._,i===a.put)return;l=a.put}return(a=n.wait)&&(a=a[c.id])&&clearTimeout(a),!e&&(i===l||c.soul||c.link||r&&!(0 .once, apologies unexpected."),this.once(t,n)},e.chain.once=function(t,n){var r=this,u=r._,a=u.put;if(0=(n.batch||1e3)?s():void(e||(e=setTimeout(s,n.wait||1)))}),t.on("get",function(o){function e(){if(s&&(i=s["#"])){var e=s["."];r=u[i]||a,r&&e&&(r=Gun.state.to(r,e)),(r||Gun.obj.empty(n.peers))&&t.on("in",{"@":o["#"],put:Gun.graph.node(r),how:"lS",lS:o.I})}}this.to.next(o);var i,r,a,s=o.get;Gun.debug?setTimeout(e,1):e()});var a=function(t,n,o,e){u[e]=Gun.state.to(o,n,u[e])},s=function(a){var f;r=0,clearTimeout(e),e=!1;var c=i;i={},a&&(u=a);try{o.setItem(n.prefix,JSON.stringify(u))}catch(l){Gun.log(f=l||"localStorage failure"),t.on("localStorage:error",{err:f,file:n.prefix,flush:u,retry:s})}(f||Gun.obj.empty(n.peers))&&Gun.obj.map(c,function(n,o){t.on("in",{"@":o,err:f,ok:0})})}}})}})(t,"./adapters/localStorage"),t(function(n){function e(t){var n=function(){},a=t.opt;return n.out=function(o){var e;return this.to&&this.to.next(o),(e=o["@"])&&(e=t.dup.s[e])&&(e=e.it)&&e.mesh?(n.say(o,e.mesh.via,1),void(e["##"]=o["##"])):void n.say(o)},t.on("create",function(o){o.opt.pid=o.opt.pid||i.text.random(9),this.to.next(o),t.on("out",n.out)}),n.hear=function(e,r){if(e){var u,a,s,f=t.dup,c=e[0];try{s=JSON.parse(e)}catch(l){o.log("DAM JSON parse error",l)}if("{"===c){if(!s)return;if(f.check(u=s["#"]))return;if(f.track(u,!0).it=s,(c=s["@"])&&s.put&&(a=s["##"]||(s["##"]=n.hash(s)),(c+=a)!=u)){if(f.check(c))return;(c=f.s)[a]=c[u]}return(s.mesh=function(){}).via=r,(c=s["><"])&&(s.mesh.to=i.obj.map(c.split(","),function(t,n,o){o(t,!0)})),s.dam?void((c=n.hear[s.dam])&&c(s,r,t)):void t.on("in",s)}if("["!==c);else{if(!s)return;for(var p,d=0;p=s[d++];)n.hear(p,r)}}},function(){function o(t,n){var o=n.wire;try{o.send?o.send(t):n.say&&n.say(t)}catch(e){(n.queue=n.queue||[]).push(t)}}n.say=function(e,r,s){if(!r)return void i.obj.map(a.peers,function(t){n.say(e,t)});var f,c,l,p=r.wire||a.wire&&a.wire(r);if(p&&(c=e.mesh||u,r!==c.via&&((l=c.raw)||(l=n.raw(e)),!((f=e["@"])&&(f=t.dup.s[f])&&(f=f.it)&&f.get&&f["##"]&&f["##"]===e["##"]||(f=c.to)&&(f[r.url]||f[r.id])&&!s)))){if(r.batch)return void r.batch.push(l);r.batch=[],setTimeout(function(){var t=r.batch;t&&(r.batch=null,t.length&&o(JSON.stringify(t),r))},a.gap||a.wait||1),o(l,r)}}}(),function(){function o(t,n){var o;return n instanceof Object?(i.obj.map(Object.keys(n).sort(),u,{to:o={},on:n}),o):n}function u(t){this.to[t]=this.on[t]}n.raw=function(e){if(!e)return"";var u,c,l,p=t.dup,d=e.mesh||{};if(l=d.raw)return l;if("string"==typeof e)return e;e["@"]&&(l=e.put)&&((c=e["##"])||(u=s(l,o)||"",c=n.hash(e,u),e["##"]=c),(l=p.s)[c=e["@"]+c]=l[e["#"]],e["#"]=c||e["#"],u&&((e=i.obj.to(e)).put=f));var h=0,v=[];i.obj.map(a.peers,function(t){return v.push(t.url||t.id),++h>9?!0:void 0}),e["><"]=v.join();var g=s(e);return r!==u&&(l=g.indexOf(f,g.indexOf("put")),g=g.slice(0,l-1)+u+g.slice(l+f.length+1)),d&&(d.raw=g),g},n.hash=function(t,n){return e.hash(n||s(t.put,o)||"")||t["#"]||i.text.random(9)};var s=JSON.stringify,f=":])([:"}(),n.hi=function(o){var e=o.wire||{};o.id||o.url?(a.peers[o.url||o.id]=o,i.obj.del(a.peers,e.id)):(e=e.id=e.id||i.text.random(9),n.say({dam:"?"},a.peers[e]=o)),e.hied||t.on(e.hied="hi",o),e=o.queue,o.queue=[],i.obj.map(e,function(t){n.say(t,o)})},n.bye=function(n){i.obj.del(a.peers,n.id),t.on("bye",n)},n.hear["?"]=function(t,o){return t.pid?(o.id=o.id||t.pid,void n.hi(o)):n.say({dam:"?",pid:a.pid,"@":t["#"]},o)},n}var i=t("../type");e.hash=function(t){if("string"!=typeof t)return{err:1};var n=0;if(!t.length)return n;for(var o,e=0,i=t.length;i>e;++e)o=t.charCodeAt(e),n=(n<<5)-n+o,n|=0;return n};var r,u={};Object.keys=Object.keys||function(t){return map(t,function(t,n,o){o(n)})};try{n.exports=e}catch(a){}})(t,"./adapters/mesh"),t(function(){var n=t("../index");n.Mesh=t("./mesh"),n.on("opt",function(t){function o(t){try{if(!t||!t.url)return o&&o(t);var n=t.url.replace("http","ws"),o=t.wire=new i.WebSocket(n);return o.onclose=function(){i.mesh.bye(t),e(t)},o.onerror=function(n){e(t),n&&"ECONNREFUSED"===n.code},o.onopen=function(){i.mesh.hi(t)},o.onmessage=function(n){ -n&&i.mesh.hear(n.data||n,t)},o}catch(r){}}function e(t){clearTimeout(t.defer),t.defer=setTimeout(function(){o(t)},2e3)}this.to.next(t);var i=t.opt;if(!t.once&&!1!==i.WebSocket){var r;"undefined"!=typeof window&&(r=window),"undefined"!=typeof global&&(r=global),r=r||{};var u=i.WebSocket||r.WebSocket||r.webkitWebSocket||r.mozWebSocket;if(u){i.WebSocket=u;{i.mesh=i.mesh||n.Mesh(t),i.wire}i.wire=o}}})})(t,"./adapters/websocket")}(); \ No newline at end of file +!function(){function t(n,o){function e(t){return t.split("/").slice(-1).toString().replace(".js","")}return o?require(n):n.slice?t[e(n)]:function(o,i){n(o={exports:{}}),t[e(i)]=o.exports}}var n;"undefined"!=typeof window&&(n=window),"undefined"!=typeof global&&(n=global),n=n||{};var o=n.console||{log:function(){}};if("undefined"!=typeof module)var e=module;t(function(t){var n={};n.fn={is:function(t){return!!t&&"function"==typeof t}},n.bi={is:function(t){return t instanceof Boolean||"boolean"==typeof t}},n.num={is:function(t){return!e(t)&&(t-parseFloat(t)+1>=0||1/0===t||-(1/0)===t)}},n.text={is:function(t){return"string"==typeof t}},n.text.ify=function(t){return n.text.is(t)?t:"undefined"!=typeof JSON?JSON.stringify(t):t&&t.toString?t.toString():t},n.text.random=function(t,n){var o="";for(t=t||24,n=n||"0123456789ABCDEFGHIJKLMNOPQRSTUVWXZabcdefghijklmnopqrstuvwxyz";t>0;)o+=n.charAt(Math.floor(Math.random()*n.length)),t--;return o},n.text.match=function(t,o){function e(t,n){for(var o,e=-1,i=0;o=n[i++];)if(!~(e=t.indexOf(o,e+1)))return!1;return!0}var i=!1;if(t=t||"",o=n.text.is(o)?{"=":o}:o||{},n.obj.has(o,"~")&&(t=t.toLowerCase(),o["="]=(o["="]||o["~"]).toLowerCase()),n.obj.has(o,"="))return t===o["="];if(n.obj.has(o,"*")){if(t.slice(0,o["*"].length)!==o["*"])return!1;i=!0,t=t.slice(o["*"].length)}if(n.obj.has(o,"!")){if(t.slice(-o["!"].length)!==o["!"])return!1;i=!0}if(n.obj.has(o,"+")&&n.list.map(n.list.is(o["+"])?o["+"]:[o["+"]],function(n){return t.indexOf(n)>=0?void(i=!0):!0}))return!1;if(n.obj.has(o,"-")&&n.list.map(n.list.is(o["-"])?o["-"]:[o["-"]],function(n){return t.indexOf(n)<0?void(i=!0):!0}))return!1;if(n.obj.has(o,">")){if(!(t>o[">"]))return!1;i=!0}if(n.obj.has(o,"<")){if(!(tn?-1:n>o?1:0):0}},n.list.map=function(t,n,o){return u(t,n,o)},n.list.index=1,n.obj={is:function(t){return t?t instanceof Object&&t.constructor===Object||"Object"===Object.prototype.toString.call(t).match(/^\[object (\w+)\]$/)[1]:!1}},n.obj.put=function(t,n,o){return(t||{})[n]=o,t},n.obj.has=function(t,n){return t&&Object.prototype.hasOwnProperty.call(t,n)},n.obj.del=function(t,n){return t?(t[n]=null,delete t[n],t):void 0},n.obj.as=function(t,n,o,e){return t[n]=t[n]||(e===o?{}:o)},n.obj.ify=function(t){if(r(t))return t;try{t=JSON.parse(t)}catch(n){t={}}return t},function(){function t(t,n){a(this,n)&&o!==this[n]||(this[n]=t)}var o;n.obj.to=function(n,o){return o=o||{},u(n,t,o),o}}(),n.obj.copy=function(t){return t?JSON.parse(JSON.stringify(t)):t},function(){function t(t,n){var o=this.n;if(!o||!(n===o||r(o)&&a(o,n)))return n?!0:void 0}n.obj.empty=function(n,o){return n&&u(n,t,{n:o})?!1:!0}}(),function(){function t(n,o){return 2===arguments.length?(t.r=t.r||{},void(t.r[n]=o)):(t.r=t.r||[],void t.r.push(n))}var i=Object.keys;n.obj.map=function(u,s,f){var c,l,p,d,h,v=0,g=o(s);if(t.r=null,i&&r(u)&&(d=i(u),h=!0),e(u)||d)for(l=(d||u).length;l>v;v++){var m=v+n.list.index;if(g){if(p=h?s.call(f||this,u[d[v]],d[v],t):s.call(f||this,u[v],m,t),p!==c)return p}else if(s===u[h?d[v]:v])return d?d[v]:m}else for(v in u)if(g){if(a(u,v)&&(p=f?s.call(f,u[v],v,t):s(u[v],v,t),p!==c))return p}else if(s===u[v])return v;return g?t.r:n.list.index?0:-1}}(),n.time={},n.time.is=function(t){return t?t instanceof Date:+(new Date).getTime()};var o=n.fn.is,e=n.list.is,i=n.obj,r=i.is,a=i.has,u=i.map;t.exports=n})(t,"./type"),t(function(t){t.exports=function n(t,o,e){if(!t)return{to:n};var i,t=(this.tag||(this.tag={}))[t]||(this.tag[t]={tag:t,to:n._={next:function(t){var n;(n=this.to)&&n.next(t)}}});if(o instanceof Function){var r={off:n.off||(n.off=function(){return this.next===n._.next?!0:(this===this.the.last&&(this.the.last=this.back),this.to.back=this.back,this.next=n._.next,this.back.to=this.to,void(this.the.last===this.the&&delete this.on.tag[this.the.tag]))}),to:n._,next:o,the:t,on:this,as:e};return(r.back=t.last||t).to=r,t.last=r}return(t=t.to)&&i!==o&&t.next(o),t}})(t,"./onto"),t(function(t){function n(t,n,e,i,r){if(n>t)return{defer:!0};if(e>n)return{historical:!0};if(n>e)return{converge:!0,incoming:!0};if(n===e){if(i=o(i)||"",r=o(r)||"",i===r)return{state:!0};if(r>i)return{converge:!0,current:!0};if(i>r)return{converge:!0,incoming:!0}}return{err:"Invalid CRDT Data: "+i+" to "+r+" at "+n+" to "+e+"!"}}if("undefined"==typeof JSON)throw new Error("JSON is not included in this browser. Please load it first: ajax.cdnjs.com/ajax/libs/json2/20110223/json2.js");var o=JSON.stringify;t.exports=n})(t,"./HAM"),t(function(n){var o=t("./type"),e={};e.is=function(t){return t===i?!1:null===t?!0:t===1/0?!1:s(t)||a(t)||u(t)?!0:e.rel.is(t)||!1},e.link=e.rel={_:"#"},function(){function t(t,n){var o=this;return o.id?o.id=!1:n==r&&s(t)?void(o.id=t):o.id=!1}e.rel.is=function(n){if(n&&n[r]&&!n._&&c(n)){var o={};if(p(n,t,o),o.id)return o.id}return!1}}(),e.rel.ify=function(t){return l({},r,t)},o.obj.has._=".";var i,r=e.link._,a=o.bi.is,u=o.num.is,s=o.text.is,f=o.obj,c=f.is,l=f.put,p=f.map;n.exports=e})(t,"./val"),t(function(n){var o=t("./type"),e=t("./val"),i={_:"_"};i.soul=function(t,n){return t&&t._&&t._[n||p]},i.soul.ify=function(t,n){return n="string"==typeof n?{soul:n}:n||{},t=t||{},t._=t._||{},t._[p]=n.soul||t._[p]||l(),t},i.soul._=e.link._,function(){function t(t,n){return n!==i._?e.is(t)?void(this.cb&&this.cb.call(this.as,t,n,this.n,this.s)):!0:void 0}i.is=function(n,o,e){var r;return u(n)&&(r=i.soul(n))?!f(n,t,{as:e,cb:o,s:r,n:n}):!1}}(),function(){function t(t,n){var o,i,r=this.o;return r.map?(o=r.map.call(this.as,t,""+n,r.node),void(i===o?s(r.node,n):r.node&&(r.node[n]=o))):void(e.is(t)&&(r.node[n]=t))}i.ify=function(n,o,e){return o?"string"==typeof o?o={soul:o}:o instanceof Function&&(o={map:o}):o={},o.map&&(o.node=o.map.call(e,n,r,o.node||{})),(o.node=i.soul.ify(o.node||{},o))&&f(n,t,{o:o,as:e}),o.node}}();var r,a=o.obj,u=a.is,s=a.del,f=a.map,c=o.text,l=c.random,p=i.soul._;n.exports=i})(t,"./node"),t(function(n){function o(){var t;return t=r(),t>a?(u=0,a=t+o.drift):a=t+(u+=1)/s+o.drift}{var e=t("./type"),i=t("./node"),r=e.time.is,a=-(1/0),u=0,s=1e3,f="undefined"!=typeof performance?performance.timing&&performance:!1;f&&f.timing&&f.timing.navigationStart||(f=!1)}o._=">",o.drift=0,o.is=function(t,n,e){var i=n&&t&&t[x]&&t[x][o._]||e;if(i)return b(i=i[n])?i:-(1/0)},o.lex=function(){return o().toString(36).replace(".","")},o.ify=function(t,n,e,r,a){if(!t||!t[x]){if(!a)return;t=i.soul.ify(t,a)}var u=p(t[x],o._);return c!==n&&n!==x&&(b(e)&&(u[n]=e),c!==r&&(t[n]=r)),t},o.to=function(t,n,e){var r=t[n];return h(r)&&(r=g(r)),o.ify(e,n,o.is(t,n),r,i.soul(t))},function(){function t(t,n){x!==n&&o.ify(this.o,n,this.s)}o.map=function(n,e,i){var r,a=h(a=n||e)?a:null;return n=y(n=n||e)?n:null,a&&!n?(e=b(e)?e:o(),a[x]=a[x]||{},v(a,t,{o:a,s:e}),a):(i=i||h(e)?e:r,e=b(e)?e:o(),function(o,a,u,s){return n?(n.call(i||this||{},o,a,u,s),void(d(u,a)&&r===u[a]||t.call({o:u,s:e},o,a))):(t.call({o:u,s:e},o,a),o)})}}();var c,l=e.obj,p=l.as,d=l.has,h=l.is,v=l.map,g=l.copy,m=e.num,b=m.is,k=e.fn,y=k.is,x=i._;n.exports=o})(t,"./state"),t(function(n){var o=t("./type"),e=t("./val"),i=t("./node"),r={};!function(){function t(t,o){return t&&o===i.soul(t)&&i.is(t,this.fn,this.as)?void(this.cb&&(n.n=t,n.as=this.as,this.cb.call(n.as,t,o,n))):!0}function n(t){t&&i.is(n.n,t,n.as)}r.is=function(n,o,e,i){return n&&s(n)&&!l(n)?!d(n,t,{cb:o,fn:e,as:i}):!1}}(),function(){function t(t,o){var r;return(r=p(t,o))?r:(o.env=t,o.soul=u,i.ify(o.obj,n,o)&&(o.rel=o.rel||e.rel.ify(i.soul(o.node)),o.obj!==t.shell&&(t.graph[e.rel.is(o.rel)]=o.node)),o)}function n(n,o,r){var u,s,p=this,d=p.env;if(i._===o&&c(n,e.rel._))return r._;if(u=l(n,o,r,p,d)){if(o||(p.node=p.node||r||{},c(n,i._)&&i.soul(n)&&(p.node._=h(n._)),p.node=i.soul.ify(p.node,e.rel.is(p.rel)),p.rel=p.rel||e.rel.ify(i.soul(p.node))),(s=d.map)&&(s.call(d.as||{},n,o,r,p),c(r,o))){if(n=r[o],a===n)return void f(r,o);if(!(u=l(n,o,r,p,d)))return}if(!o)return p.node;if(!0===u)return n;if(s=t(d,{obj:n,path:p.path.concat(o)}),s.node)return s.rel}}function u(t){var n=this,o=e.link.is(n.rel),r=n.env.graph;n.rel=n.rel||e.rel.ify(t),n.rel[e.rel._]=t,n.node&&n.node[i._]&&(n.node[i._][e.rel._]=t),c(r,o)&&(r[t]=r[o],f(r,o))}function l(t,n,i,r,a){var u;return e.is(t)?!0:s(t)?1:(u=a.invalid)?(t=u.call(a.as||{},t,n,i),l(t,n,i,r,a)):(a.err="Invalid value at '"+r.path.concat(n).join(".")+"'!",void(o.list.is(t)&&(a.err+=" Use `.set(item)` instead of an Array.")))}function p(t,n){for(var o,e=t.seen,i=e.length;i--;)if(o=e[i],n.obj===o.obj)return o;e.push(n)}r.ify=function(n,o,i){var r={path:[],obj:n};return o?"string"==typeof o?o={soul:o}:o instanceof Function&&(o.map=o):o={},o.soul&&(r.rel=e.rel.ify(o.soul)),o.shell=(i||{}).shell,o.graph=o.graph||{},o.seen=o.seen||[],o.as=o.as||i,t(o,r),o.root=r.node,o.graph}}(),r.node=function(t){var n=i.soul(t);if(n)return p({},n,t)},function(){function t(t,n){var o,a;if(i._===n){if(l(t,e.rel._))return;return void(this.obj[n]=h(t))}return(o=e.rel.is(t))?(a=this.opt.seen[o])?void(this.obj[n]=a):void(this.obj[n]=this.opt.seen[o]=r.to(this.graph,o,this.opt)):void(this.obj[n]=t)}r.to=function(n,o,e){if(n){var i={};return e=e||{seen:{}},d(n[o],t,{obj:i,graph:n,opt:e}),i}}}();var a,u=(o.fn.is,o.obj),s=u.is,f=u.del,c=u.has,l=u.empty,p=u.put,d=u.map,h=u.copy;n.exports=r})(t,"./graph"),t(function(n){t("./onto"),n.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}var 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}}})(t,"./ask"),t(function(n){function o(t){var n={s:{}};return t=t||{max:1e3,age:9e3},n.check=function(t){var o;return(o=n.s[t])?o.pass?o.pass=!1:n.track(t):!1},n.track=function(o,r){var a=n.s[o]||(n.s[o]={});return a.was=i(),r&&(a.pass=!0),n.to||(n.to=setTimeout(function(){var o=i();e.obj.map(n.s,function(i,r){i&&t.age>o-i.was||e.obj.del(n.s,r)}),n.to=null},t.age+9)),a},n}var e=t("./type"),i=e.time.is;n.exports=o})(t,"./dup"),t(function(n){function i(t){return t instanceof i?(this._={gun:this,$:this}).$:this instanceof i?i.create(this._={gun:this,$:this,opt:t}):new i(t)}i.is=function(t){return t instanceof i||t&&t._&&t===t._.$||!1},i.version=.9,i.chain=i.prototype,i.chain.toJSON=function(){};var r=t("./type");r.obj.to(r,i),i.HAM=t("./HAM"),i.val=t("./val"),i.node=t("./node"),i.state=t("./state"),i.graph=t("./graph"),i.on=t("./onto"),i.ask=t("./ask"),i.dup=t("./dup"),function(){function t(n){var o,e,r=this,u=r.as,s=u.at||u,f=s.$;return(e=n["#"])||(e=n["#"]=c(9)),(o=s.dup).check(e)?void(u.out===n.out&&(n.out=a,r.to.next(n))):(o.track(e),s.ask(n["@"],n)||(n.get&&i.on.get(n,f),n.put&&i.on.put(n,f)),r.to.next(n),void(u.out||(n.out=t,s.on("out",n))))}i.create=function(n){n.root=n.root||n,n.graph=n.graph||{},n.on=n.on||i.on,n.ask=n.ask||i.ask,n.dup=n.dup||i.dup();var o=n.$.opt(n.opt);return n.once||(n.on("in",t,n),n.on("out",t,{at:n,out:t}),i.on("create",n),n.on("create",n)),n.once=1,o}}(),function(){function t(t,n,o,e){var r=this,a=i.state.is(o,n);if(!a)return r.err="Error: No state on '"+n+"' in node '"+e+"'!";var u=r.graph[e]||k,s=i.state.is(u,n,!0),f=u[n],c=i.HAM(r.machine,a,s,t,f);return c.incoming?(r.put[e]=i.state.to(o,n,r.put[e]),(r.diff||(r.diff={}))[e]=i.state.to(o,n,r.diff[e]),void(r.souls[e]=!0)):void(c.defer&&(r.defer=a<(r.defer||1/0)?a:r.defer))}function n(t,n){var i=this,a=i.$._,u=(a.next||k)[n];if(!u){if(!(a.opt||k)["super"])return void(i.souls[n]=!1);u=i.$.get(n)._}var s=i.map[n]={put:t,get:n,$:u.$},f={ctx:i,msg:s};i.async=!!a.tag.node,i.ack&&(s["@"]=i.ack),v(t,o,f),i.async&&(i.and||a.on("node",function(t){this.to.next(t),t===i.map[t.get]&&(i.souls[t.get]=!1,v(t.put,e,t),v(i.souls,function(t){return t?t:void 0})||i.c||(i.c=1,this.off(),v(i.map,r,i)))}),i.and=!0,a.on("node",s))}function o(t,n){var o=this.ctx,e=o.graph,r=this.msg,a=r.get,u=r.put,s=r.$._;e[a]=i.state.to(u,n,e[a]),o.async||(s.put=i.state.to(u,n,s.put))}function e(t,n){var o=this,e=o.put,r=o.$._;r.put=i.state.to(e,n,r.put)}function r(t){t.$&&(this.cat.stop=this.stop,t.$._.on("in",t),this.cat.stop=null)}i.on.put=function(o,e){var u=e._,s={$:e,graph:u.graph,put:{},map:{},souls:{},machine:i.state(),ack:o["@"],cat:u,stop:{}};return i.graph.is(o.put,null,t,s)||(s.err="Error: Invalid graph!"),s.err?u.on("in",{"@":o["#"],err:i.log(s.err)}):(v(s.put,n,s),s.async||v(s.map,r,s),a!==s.defer&&setTimeout(function(){i.on.put(o,e)},s.defer-s.machine),void(s.diff&&u.on("put",h(o,{put:s.diff}))))},i.on.get=function(t,n){var o,e=n._,r=t.get,a=r[m],u=e.graph[a],s=r[b],f=e.next||(e.next={}),c=f[a];if(d(a,"*")){var l={};i.obj.map(e.graph,function(t,n){i.text.match(n,a)&&(l[n]=i.obj.copy(t))}),i.obj.empty(l)||e.on("in",{"@":t["#"],how:"*",put:l,$:n})}if(!u)return e.on("get",t);if(s){if(!d(u,s))return e.on("get",t);u=i.state.to(u,s)}else u=i.obj.copy(u);u=i.graph.node(u),o=(c||k).ack,e.on("in",{"@":t["#"],how:"mem",put:u,$:n}),e.on("get",t)}}(),function(){i.chain.opt=function(t){t=t||{};var n=this,o=n._,e=t.peers||t;return p(t)||(t={}),p(o.opt)||(o.opt=t),f(e)&&(e=[e]),u(e)&&(e=v(e,function(t,n,o){o(t,{url:t})}),p(o.opt.peers)||(o.opt.peers={}),o.opt.peers=h(e,o.opt.peers)),o.opt.peers=o.opt.peers||{},h(t,o.opt),i.on("opt",o),o.opt.uuid=o.opt.uuid||function(){return g()+c(12)},n}}();var a,u=i.list.is,s=i.text,f=s.is,c=s.random,l=i.obj,p=l.is,d=l.has,h=l.to,v=l.map,g=(l.copy,i.state.lex),m=i.val.rel._,b=".",k=(i.node._,i.val.link.is,{});o.debug=function(t,n){return o.debug.i&&t===o.debug.i&&o.debug.i++&&(o.log.apply(o,arguments)||n)},i.log=function(){return!i.log.off&&o.log.apply(o,arguments),[].slice.call(arguments).join(" ")},i.log.once=function(t,n,o){return(o=i.log.once)[t]=o[t]||0,o[t]++||i.log(n)},i.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=i).window=window);try{"undefined"!=typeof e&&(e.exports=i)}catch(y){}n.exports=i})(t,"./root"),t(function(){var n=t("./root");n.chain.back=function(t,i){var r;if(t=t||1,-1===t||1/0===t)return this._.root.$;if(1===t)return(this._.back||this._).$;var a=this,u=a._;if("string"==typeof t&&(t=t.split(".")),!(t instanceof Array)){if(t instanceof Function){for(var s,r={back:u};(r=r.back)&&o===(s=t(r,i)););return s}return n.num.is(t)?(u.back||u).$.back(t-1):this}var f=0,c=t.length,r=u;for(f;c>f;f++)r=(r||e)[t[f]];return o!==r?i?a:r:(r=u.back)?r.$.back(t,i):void 0};var o,e={}})(t,"./back"),t(function(){function n(t){var n,o,e,i=this.as,r=i.back,a=i.root;if(t.I||(t.I=i.$),t.$||(t.$=i.$),this.to.next(t),o=t.get){if(o["#"]||i.soul){if(o["#"]=o["#"]||i.soul,t["#"]||(t["#"]=b(9)),r=a.$.get(o["#"])._,o=o["."]){if(h(r.put,o)&&(n=r.$.get(o)._,(e=n.ack)||(n.ack=-1),r.on("in",{$:r.$,put:c.state.to(r.put,o),get:r.get}),e))return}else{if(e=r.ack,e||(r.ack=-1),h(r,"put")&&r.on("in",r),e)return;t.$=r.$}return a.ask(f,t),a.on("in",t)}if(a.now&&(a.now[i.id]=a.now[i.id]||!0,i.pass={}),o["."])return i.get?(t={get:{".":i.get},$:i.$},r.ask||(r.ask={}),r.ask[i.get]=t.$._,r.on("out",t)):(t={get:{},$:i.$},r.on("out",t));if(i.ack=i.ack||-1,i.get)return t.$=i.$,o["."]=i.get,(r.ask||(r.ask={}))[i.get]=t.$._,r.on("out",t)}return r.on("out",t)}function o(t){var n,o,r=this,s=r.as,f=s.root,d=t.$,b=(d||p)._||p,k=t.put;if(s.get&&t.get!==s.get&&(t=g(t,{get:s.get})),s.has&&b!==s&&(t=g(t,{$:s.$}),b.ack&&(s.ack=b.ack)),l===k){if(o=b.put,r.to.next(t),s.soul)return;if(l===o&&l!==b.put)return;return i(s,t,r),s.has&&u(s,t),v(b.echo,s.id),void v(s.map,b.id)}if(s.soul)return r.to.next(t),i(s,t,r),void(s.next&&m(k,a,{msg:t,cat:s}));if(!(n=c.val.link.is(k)))return c.val.is(k)?(s.has||s.soul?u(s,t):(b.has||b.soul)&&((b.echo||(b.echo={}))[s.id]=b.echo[b.id]||s,(s.map||(s.map={}))[b.id]=s.map[b.id]||{at:b}),r.to.next(t),void i(s,t,r)):(s.has&&b!==s&&h(b,"put")&&(s.put=b.put),(n=c.node.soul(k))&&b.has&&(b.put=s.root.$.get(n)._.put),o=(f.stop||{})[b.id],r.to.next(t),e(s,t,b,n),i(s,t,r),void(s.next&&m(k,a,{msg:t,cat:s})));f.stop;o=f.stop||{},o=o[b.id]||(o[b.id]={}),o.is=o.is||b.put,o[s.id]=b.put||!0,r.to.next(t),e(s,t,b,n),i(s,t,r)}function e(t,n,o,i){if(i&&k!==t.get){var r=t.root.$.get(i)._;t.has?o=r:o.has&&e(o,n,o,i),o!==t&&(o.$||(o={}),(o.echo||(o.echo={}))[t.id]=o.echo[t.id]||t,t.has&&!(t.map||p)[o.id]&&u(t,n),r=o.id?(t.map||(t.map={}))[o.id]=t.map[o.id]||{at:o}:{},(i!==r.link||r.pass||t.pass)&&(t.pass&&(c.obj.map(t.map,function(t){t.pass=!0}),v(t,"pass")),r.pass&&v(r,"pass"),t.has&&(t.link=i),s(t,r.link=i)))}}function i(t,n){t.echo&&m(t.echo,r,n)}function r(t){t&&t.on&&t.on("in",this)}function a(t,n){var o,e,i,r=this.cat,a=r.next||p,u=this.msg;(k!==n||a[n])&&(e=a[n])&&(e.has?(l!==e.put&&c.val.link.is(t)||(e.put=t),o=e.$):(i=u.$)&&(i=(o=u.$.get(n))._,l!==i.put&&c.val.link.is(t)||(i.put=t)),e.on("in",{put:t,get:n,$:o,via:u}))}function u(t,n){if(t.has||t.soul){{var o=t.map;t.root}t.map=null,t.has&&(t.link=null),(t.pass||n["@"]||null!==o)&&(l===o&&c.val.link.is(t.put)||(m(o,function(n){(n=n.at)&&v(n.echo,t.id)}),o=t.put,m(t.next,function(n,e){return l===o&&l!==t.put?!0:(n.put=l,n.ack&&(n.ack=-1),void n.on("in",{get:e,$:n.$,put:l}))})))}}function s(t,n){var o=t.root.$.get(n)._;(!t.ack||(o.on("out",{get:{"#":n}}),t.ask))&&(o=t.ask,c.obj.del(t,"ask"),m(o||t.next,function(t,o){t.on("out",{get:{"#":n,".":o}})}),c.obj.del(t,"ask"))}function f(t){var n=this.as,o=n.get||p,e=n.$._,i=(t.put||p)[o["#"]];if(e.ack&&(e.ack=e.ack+1||1),!t.put||o["."]&&!h(i,e.get)){if(e.put!==l)return;return void e.on("in",{get:e.get,put:e.put=l,$:e.$,"@":t["@"]})}return k==o["."]?void e.on("in",{get:e.get,put:c.val.link.ify(o["#"]),$:e.$,"@":t["@"]}):(t.$=e.root.$,void c.on.put(t,e.root.$))}var c=t("./root");c.chain.chain=function(t){var e,i=this,r=i._,a=new(t||i).constructor(i),u=a._;return u.root=e=r.root,u.id=++e.once,u.back=i._,u.on=c.on,u.on("in",o,u),u.on("out",n,u),a};var l,p={},d=c.obj,h=d.has,v=(d.put,d.del),g=d.to,m=d.map,b=c.text.random,k=(c.val.rel._,c.node._)})(t,"./chain"),t(function(){function n(t,n){var o=n._,e=o.next,i=n.chain(),r=i._;return e||(e=o.next={}),e[r.get=t]=r,n===o.root.$?r.soul=t:(o.soul||o.has)&&(r.has=t),r}function o(t,n,o,e){var i,r=t._;return(i=r.soul)?(n(i,e,r),t):(i=r.link)?(n(i,e,r),t):(t.get(function(t,o){o.rid(t);var r=(r=t.$)&&r._||{};i=r.link||r.soul||c.is(t.put)||l(t.put),n(i,e,t,o)},{out:{get:{".":!0}}}),t)}function e(t){var n,o=this,e=o.as,i=e.at,r=i.root,u=t.$,f=(u||{})._||{},l=t.put||f.put;if((n=r.now)&&o!==n[e.now])return o.to.next(t);if(o.seen&&f.id&&o.seen[f.id])return o.to.next(t);if((n=l)&&n[c._]&&(n=c.is(n))&&(n=(t.$$=f.root.gun.get(n))._,a!==n.put&&(t=s(t,{put:l=n.put}))),(n=r.mum)&&f.id){if(n[f.id])return;a===l||c.is(l)||(n[f.id]=!0)}return e.use(t,o),o.stun?void(o.stun=null):void o.to.next(t)}function i(t){var n=this.on;if(!t||n.soul||n.has)return this.off();if(t=(t=(t=t.$||t)._||t).id){{var o,e;n.map}return(o=(e=this.seen||(this.seen={}))[t])?!0:void(e[t]=!0)}}var r=t("./root");r.chain.get=function(t,a,u){var s,l;if("string"!=typeof t){if(t instanceof Function){if(!0===a)return o(this,t,a,u);s=this;var d,h=s._,v=h.root,l=v.now;u=a||{},u.at=h,u.use=t,u.out=u.out||{},u.out.get=u.out.get||{},(d=h.on("in",e,u)).rid=i,(v.now={$:1})[u.now=h.id]=d;var g=v.mum;return v.mum={},h.on("out",u.out),v.mum=g,v.now=l,s}return f(t)?this.get(""+t,a,u):(l=c.is(t))?this.get(l,a,u):((u=this.chain())._.err={err:r.log("Invalid get request!",t)},a&&a.call(u,u._.err),u)}var m=this,b=m._,k=b.next||p;return(s=k[t])||(s=n(t,m)),s=s.$,(l=b.stun)&&(s._.stun=s._.stun||l),a&&a instanceof Function&&s.get(a,u),s};var a,u=r.obj,s=(u.has,r.obj.to),f=r.num.is,c=r.val.link,l=r.node.soul,p=(r.node._,{})})(t,"./get"),t(function(){function n(t){t.batch=i;var n=t.opt||{},o=t.env=c.state.map(a,n.state);return o.soul=t.soul,t.graph=c.graph.ify(t.data,o,t),o.err?((t.ack||m).call(t,t.out={err:c.log(o.err)}),void(t.res&&t.res())):void t.batch()}function e(t){return void(t&&t())}function i(){var t=this;t.graph&&!v(t.stun,r)&&(t.res=t.res||function(t){t&&t()},t.res(function(){var n=t.$.back(-1)._,o=n.ask(function(o){n.root.on("ack",o),o.err&&c.log(o),o.lack||this.off(),t.ack&&t.ack(o,this)},t.opt),e=n.root.now;p.del(n.root,"now");var i=n.root.mum;n.root.mum={},t.ref._.on("out",{$:t.ref,put:t.out=t.env.graph,opt:t.opt,"#":o}),n.root.mum=i?p.to(i,n.root.mum):i,n.root.now=e},t),t.res&&t.res())}function r(t){return t?!0:void 0}function a(t,n,o,e){var i=this,r=c.is(t);!n&&e.path.length&&(i.res||b)(function(){var n=e.path,o=i.ref,a=(i.opt,0),s=n.length;for(a;s>a;a++)o=o.get(n[a]);r&&(o=t);var f=o._.dub;return f||(f=c.node.soul(e.obj))?(o.back(-1).get(f),void e.soul(f)):((i.stun=i.stun||{})[n]=!0,void o.get(u,!0,{as:{at:e,as:i,p:n}}))},{as:i,at:e})}function u(t,n,o,e){var n=n.as,i=n.at;n=n.as;var r=((o||{}).$||{})._||{};return t=r.dub=r.dub||t||c.node.soul(i.obj)||c.node.soul(o.put||r.put)||c.val.rel.is(o.put||r.put)||(n.via.back("opt.uuid")||c.text.random)(),e&&(e.stun=!0),t?void s(r,r.dub=t,i,n):void r.via.back("opt.uuid")(function(t,o){return t?c.log(t):void s(r,r.dub=r.dub||o,i,n)})}function s(t,n,o,e){t.$.back(-1).get(n),o.soul(n),e.stun[o.path]=!1,e.batch()}function f(t,n,e,i){if(n=n.as,e.$&&e.$._){if(e.err)return void o.log("Please report this as an issue! Put.any.err");var r,a=e.$._,u=a.put,s=n.opt||{};if(!(r=n.ref)||!r._.now){if(i&&(i.stun=!0),n.ref!==n.$){if(r=n.$._.get||a.get,!r)return void o.log("Please report this as an issue! Put.no.get");n.data=h({},r,n.data),r=null}if(l===u){if(!a.get)return;t||(r=a.$.back(function(t){return t.link||t.soul?t.link||t.soul:void(n.data=h({},t.get,n.data))})),r=r||a.get,a=a.root.$.get(r)._,n.soul=r,u=n.data}return n.not||(n.soul=n.soul||t)||(n.path&&d(n.data)?n.soul=(s.uuid||n.via.back("opt.uuid")||c.text.random)():(k==a.get&&(n.soul=(a.put||g)["#"]||a.dub),n.soul=n.soul||a.soul||a.soul||(s.uuid||n.via.back("opt.uuid")||c.text.random)()),n.soul)?void n.ref.put(n.data,n.soul,n):void n.via.back("opt.uuid")(function(t,o){return t?c.log(t):void n.ref.put(n.data,n.soul=o,n)})}}}var c=t("./root");c.chain.put=function(t,o,i){var r,a=this,u=a._,s=u.root.$;return i=i||{},i.data=t,i.via=i.$=i.via||i.$||a,"string"==typeof o?i.soul=o:i.ack=i.ack||o,u.soul&&(i.soul=u.soul),i.soul||s===a?d(i.data)?(i.soul=i.soul||(i.not=c.node.soul(i.data)||(i.via.back("opt.uuid")||c.text.random)()),i.soul?(i.$=a=s.get(i.soul),i.ref=i.$,n(i),a):(i.via.back("opt.uuid")(function(t,n){return t?c.log(t):void(i.ref||i.$).put(i.data,i.soul=n,i)}),a)):((i.ack||m).call(i,i.out={err:c.log("Data saved to the root level of the graph must be a node (an object), not a",typeof i.data,'of "'+i.data+'"!')}),i.res&&i.res(),a):c.is(t)?(t.get(function(t,n,e){return!t&&c.val.is(e.put)?c.log("The reference you are saving is a",typeof e.put,'"'+e.put+'", not a node (object)!'):void a.put(c.val.rel.ify(t),o,i)},!0),a):(i.ref=i.ref||s._===(r=u.back)?a:r.$,i.ref._.soul&&c.val.is(i.data)&&u.get?(i.data=h({},u.get,i.data),i.ref.put(i.data,i.soul,i),a):(i.ref.get(f,!0,{as:i}),i.out||(i.res=i.res||e,i.$._.stun=i.ref._.stun),a))};var l,p=c.obj,d=p.is,h=p.put,v=p.map,g={},m=function(){},b=function(t,n){t.call(n||g)},k=c.node._})(t,"./put"),t(function(n){var o=t("./root");t("./chain"),t("./back"),t("./put"),t("./get"),n.exports=o})(t,"./index"),t(function(){function n(t,n){{var o,e=this,r=t.$,a=(r||{})._||{},u=a.put||t.put;e.at}if(i!==u){if(o=t.$$){if(o=t.$$._,i===o.put)return;u=o.put}e.change&&(u=t.put),e.as?e.ok.call(e.as,t,n):e.ok.call(r,u,t.get,t,n)}}function o(t,n,e){var r,u,s=this.as,f=(s.at,t.$),c=f._,l=c.put||t.put;if(u=t.$$){if(r=u=t.$$._,i===u.put)return;l=u.put}return(u=n.wait)&&(u=u[c.id])&&clearTimeout(u),!e&&(i===l||c.soul||c.link||r&&!(0 .once, apologies unexpected."),this.once(t,n)},e.chain.once=function(t,n){var r=this,a=r._,u=a.put;if(0=(n.batch||1e3)?s():void(e||(e=setTimeout(s,n.wait||1)))}),t.on("get",function(o){function e(){if(s&&(i=s["#"])){var e=s["."];r=a[i]||u,r&&e&&(r=Gun.state.to(r,e)),(r||Gun.obj.empty(n.peers))&&t.on("in",{"@":o["#"],put:Gun.graph.node(r),how:"lS",lS:o.I})}}this.to.next(o);var i,r,u,s=o.get;Gun.debug?setTimeout(e,1):e()});var u=function(t,n,o,e){a[e]=Gun.state.to(o,n,a[e])},s=function(u){var f;r=0,clearTimeout(e),e=!1;var c=i;i={},u&&(a=u);try{o.setItem(n.prefix,JSON.stringify(a))}catch(l){Gun.log(f=(l||"localStorage failure")+" Consider using GUN's IndexedDB plugin for RAD for more storage space, temporary example at https://github.com/amark/gun/blob/master/test/tmp/indexedDB.html ."),t.on("localStorage:error",{err:f,file:n.prefix,flush:a,retry:s})}(f||Gun.obj.empty(n.peers))&&Gun.obj.map(c,function(n,o){t.on("in",{"@":o,err:f,ok:0})})}}})}})(t,"./adapters/localStorage"),t(function(n){function e(t){var n=function(){},u=t.opt||{};return u.log=u.log||o.log,u.gap=u.gap||u.wait||1,u.pack=u.pack||.3*(u.memory?1e3*u.memory*1e3:1399e6),n.out=function(o){var e;return this.to&&this.to.next(o),(e=o["@"])&&(e=t.dup.s[e])&&(e=e.it)&&e.mesh?(n.say(o,e.mesh.via,1),void(e["##"]=o["##"])):void n.say(o)},t.on("create",function(o){o.opt.pid=o.opt.pid||i.text.random(9),this.to.next(o),t.on("out",n.out)}),n.hear=function(o,e){if(o){var r,a,s,f=t.dup,c=o[0];if(u.pack<=o.length)return n.say({dam:"!",err:"Message too big!"},e);try{s=JSON.parse(o)}catch(l){u.log("DAM JSON parse error",l)}if("{"===c){if(!s)return;if(f.check(r=s["#"]))return;if(f.track(r,!0).it=s,(c=s["@"])&&s.put&&(a=s["##"]||(s["##"]=n.hash(s)),(c+=a)!=r)){if(f.check(c))return;(c=f.s)[a]=c[r]}return(s.mesh=function(){}).via=e,(c=s["><"])&&(s.mesh.to=i.obj.map(c.split(","),function(t,n,o){o(t,!0)})),s.dam?void((c=n.hear[s.dam])&&c(s,e,t)):void t.on("in",s)}if("["!==c);else{if(!s)return;for(var p,d=0;p=s[d++];)n.hear(p,e)}}},function(){function o(t){var n=t.batch;if(n&&(t.batch=t.tail=null,n.length))try{e(JSON.stringify(n),t)}catch(o){u.log("DAM JSON stringify error",o)}}function e(t,n){var o=n.wire;try{o.send?o.send(t):n.say&&n.say(t)}catch(e){(n.queue=n.queue||[]).push(t)}}n.say=function(r,s,f){if(!s)return void i.obj.map(u.peers,function(t){n.say(r,t)});var c,l,p,d=s.wire||u.wire&&u.wire(s);if(d&&(l=r.mesh||a,s!==l.via&&((p=l.raw)||(p=n.raw(r)),!((c=r["@"])&&(c=t.dup.s[c])&&(c=c.it)&&c.get&&c["##"]&&c["##"]===r["##"]||(c=l.to)&&(c[s.url]||c[s.id])&&!f)))){if(s.batch){if(s.tail=(s.tail||0)+p.length,s.tail<=u.pack)return void s.batch.push(p);o(s)}s.batch=[],setTimeout(function(){o(s)},u.gap),e(p,s)}}}(),function(){function o(t,n){var o;return n instanceof Object?(i.obj.map(Object.keys(n).sort(),a,{to:o={},on:n}),o):n}function a(t){this.to[t]=this.on[t]}n.raw=function(e){if(!e)return"";var a,c,l,p=t.dup,d=e.mesh||{};if(l=d.raw)return l;if("string"==typeof e)return e;e["@"]&&(l=e.put)&&((c=e["##"])||(a=s(l,o)||"",c=n.hash(e,a),e["##"]=c),(l=p.s)[c=e["@"]+c]=l[e["#"]],e["#"]=c||e["#"],a&&((e=i.obj.to(e)).put=f));var h=0,v=[];i.obj.map(u.peers,function(t){return v.push(t.url||t.id),++h>9?!0:void 0}),e["><"]=v.join();var g=s(e);return r!==a&&(l=g.indexOf(f,g.indexOf("put")),g=g.slice(0,l-1)+a+g.slice(l+f.length+1)),d&&(d.raw=g),g},n.hash=function(t,n){return e.hash(n||s(t.put,o)||"")||t["#"]||i.text.random(9)};var s=JSON.stringify,f=":])([:"}(),n.hi=function(o){var e=o.wire||{};o.id||o.url?(u.peers[o.url||o.id]=o,i.obj.del(u.peers,e.id)):(e=e.id=e.id||i.text.random(9),n.say({dam:"?"},u.peers[e]=o)),e.hied||t.on(e.hied="hi",o),e=o.queue,o.queue=[],i.obj.map(e,function(t){n.say(t,o)})},n.bye=function(n){i.obj.del(u.peers,n.id),t.on("bye",n)},n.hear["!"]=function(t){u.log("Error:",t.err)},n.hear["?"]=function(t,o){return t.pid?(o.id=o.id||t.pid,void n.hi(o)):n.say({dam:"?",pid:u.pid,"@":t["#"]},o)},n}var i=t("../type");e.hash=function(t){if("string"!=typeof t)return{err:1};var n=0;if(!t.length)return n;for(var o,e=0,i=t.length;i>e;++e)o=t.charCodeAt(e), +n=(n<<5)-n+o,n|=0;return n};var r,a={};Object.keys=Object.keys||function(t){return map(t,function(t,n,o){o(n)})};try{n.exports=e}catch(u){}})(t,"./adapters/mesh"),t(function(){var n=t("../index");n.Mesh=t("./mesh"),n.on("opt",function(t){function o(t){try{if(!t||!t.url)return o&&o(t);var n=t.url.replace("http","ws"),o=t.wire=new i.WebSocket(n);return o.onclose=function(){i.mesh.bye(t),e(t)},o.onerror=function(n){e(t),n&&"ECONNREFUSED"===n.code},o.onopen=function(){i.mesh.hi(t)},o.onmessage=function(n){n&&i.mesh.hear(n.data||n,t)},o}catch(r){}}function e(t){clearTimeout(t.defer),t.defer=setTimeout(function(){o(t)},2e3)}this.to.next(t);var i=t.opt;if(!t.once&&!1!==i.WebSocket){var r;"undefined"!=typeof window&&(r=window),"undefined"!=typeof global&&(r=global),r=r||{};var a=i.WebSocket||r.WebSocket||r.webkitWebSocket||r.mozWebSocket;if(a){i.WebSocket=a;{i.mesh=i.mesh||n.Mesh(t),i.wire}i.wire=o}}})})(t,"./adapters/websocket")}(); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index bbfbd78f..8f356c89 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "gun", - "version": "0.9.99994", + "version": "0.9.99995", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 3d9b4e28..0dcca8db 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gun", - "version": "0.9.99994", + "version": "0.9.99995", "description": "A realtime, decentralized, offline-first, graph data synchronization engine.", "main": "index.js", "browser": "gun.min.js", diff --git a/src/adapters/localStorage.js b/src/adapters/localStorage.js index 932d7164..33361ab5 100644 --- a/src/adapters/localStorage.js +++ b/src/adapters/localStorage.js @@ -129,7 +129,7 @@ Gun.on('create', function(root){ if(data){ disk = data } try{store.setItem(opt.prefix, JSON.stringify(disk)); }catch(e){ - Gun.log(err = e || "localStorage failure"); + Gun.log(err = (e || "localStorage failure") + " Consider using GUN's IndexedDB plugin for RAD for more storage space, temporary example at https://github.com/amark/gun/blob/master/test/tmp/indexedDB.html ."); root.on('localStorage:error', {err: err, file: opt.prefix, flush: disk, retry: flush}); } if(!err && !Gun.obj.empty(opt.peers)){ return } // only ack if there are no peers. diff --git a/src/adapters/mesh.js b/src/adapters/mesh.js index d3a77929..6c99a6e8 100644 --- a/src/adapters/mesh.js +++ b/src/adapters/mesh.js @@ -3,7 +3,10 @@ var Type = require('../type'); function Mesh(ctx){ var mesh = function(){}; - var opt = ctx.opt; + var opt = ctx.opt || {}; + opt.log = opt.log || console.log; + opt.gap = opt.gap || opt.wait || 1; + opt.pack = opt.pack || (opt.memory? (opt.memory * 1000 * 1000) : 1399000000) * 0.3; // max_old_space_size defaults to 1400 MB. mesh.out = function(msg){ var tmp; if(this.to){ this.to.next(msg) } @@ -29,8 +32,9 @@ function Mesh(ctx){ mesh.hear = function(raw, peer){ if(!raw){ return } var dup = ctx.dup, id, hash, msg, tmp = raw[0]; + if(opt.pack <= raw.length){ return mesh.say({dam: '!', err: "Message too big!"}, peer) } try{msg = JSON.parse(raw); - }catch(e){console.log('DAM JSON parse error', e)} + }catch(e){opt.log('DAM JSON parse error', e)} if('{' === tmp){ if(!msg){ return } if(dup.check(id = msg['#'])){ return } @@ -94,20 +98,25 @@ function Mesh(ctx){ } if((tmp = msh.to) && (tmp[peer.url] || tmp[peer.id]) && !o){ return } // TODO: still needs to be tested if(peer.batch){ - peer.batch.push(raw); - return; + peer.tail = (peer.tail || 0) + raw.length; + if(peer.tail <= opt.pack){ + peer.batch.push(raw); + return; + } + flush(peer); } peer.batch = []; - setTimeout(function(){ - var tmp = peer.batch; - if(!tmp){ return } - peer.batch = null; - if(!tmp.length){ return } - send(JSON.stringify(tmp), peer); - }, opt.gap || opt.wait || 1); + setTimeout(function(){flush(peer)}, opt.gap); send(raw, peer); } - + function flush(peer){ + var tmp = peer.batch; + if(!tmp){ return } + peer.batch = peer.tail = null; + if(!tmp.length){ return } + try{send(JSON.stringify(tmp), peer); + }catch(e){opt.log('DAM JSON stringify error', e)} + } function send(raw, peer){ var wire = peer.wire; try{ @@ -193,6 +202,7 @@ function Mesh(ctx){ ctx.on('bye', peer); } + mesh.hear['!'] = function(msg, peer){ opt.log('Error:', msg.err) } mesh.hear['?'] = function(msg, peer){ if(!msg.pid){ return mesh.say({dam: '?', pid: opt.pid, '@': msg['#']}, peer) } peer.id = peer.id || msg.pid; diff --git a/src/dup.js b/src/dup.js index 0d99434b..040089ac 100644 --- a/src/dup.js +++ b/src/dup.js @@ -16,7 +16,7 @@ function Dup(opt){ dup.to = setTimeout(function(){ var now = time_is(); Type.obj.map(dup.s, function(it, id){ - if(opt.age > (now - it.was)){ return } + if(it && opt.age > (now - it.was)){ return } Type.obj.del(dup.s, id); }); dup.to = null; From e59bece17ed06041db5d43e3ccac577051231eca Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Tue, 25 Sep 2018 16:00:57 -0700 Subject: [PATCH 120/221] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index f019fd71..502cd122 100644 --- a/README.md +++ b/README.md @@ -101,6 +101,7 @@ On that note, let's get some official shout outs covered first:

          Thanks to:
          Lorenzo Mangani, +NLnet Foundation, Sam Liu, Daniel Dombrowsky, Vincent Woo, From 5b442293a8fb86efd62da7a0fba538769145cbfb Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Tue, 25 Sep 2018 16:06:51 -0700 Subject: [PATCH 121/221] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 502cd122..febd3ffb 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,7 @@ On that note, let's get some official shout outs covered first:

          Thanks to:
          +Robert Heessels, Lorenzo Mangani, NLnet Foundation, Sam Liu, From 5cfa492d7dfead3b6425472e85cce50bc6976601 Mon Sep 17 00:00:00 2001 From: masterex1000 Date: Wed, 26 Sep 2018 17:32:22 -0600 Subject: [PATCH 122/221] Add les.js (Memory Evict) --- lib/les.js | 121 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 lib/les.js diff --git a/lib/les.js b/lib/les.js new file mode 100644 index 00000000..e6f3cb16 --- /dev/null +++ b/lib/les.js @@ -0,0 +1,121 @@ +; +(function() { + + // _ _____ ____ _ + // | | | ____/ ___| (_)___ + // | | | _| \___ \ | / __| + // | |___| |___ ___) | | \__ \ + // |_____|_____|____(_)/ |___/ + // ---------------------------- + // LES.js (Last rEcently uSed) + // ---------------------------- + // A Small, lightweight, queue-based + // Garbage Collector for Gun + // Originally By: Collin Conrad (@masterex1000) + + //NOTE: set to false is running from file in YOUR code + var USELOCALGUN = true; + + //NOTE: adds some debug messages + var DEBUG = false; + + + var Gun = (typeof window !== "undefined") ? window.Gun : (USELOCALGUN ? require('../gun') : require("gun")); + var ev = {}; + var empty = {}; + + Gun.on('opt', function(root) { + this.to.next(root); + if (root.once) + return; + if (typeof process == 'undefined') + return + var mem = process.memoryUsage; + + if (!mem) //exit because we are in the browser + return; + + //Figure out the most amount of memory we can use. TODO: make configurable? + ev.max = parseFloat(root.opt.memory || process.env.WEB_MEMORY || 512) * 0.8; + + var nodes = {}; //checks if the node already exists + var nodesArray = []; //used to easily sort everything and store info about the nodes + var memoryUpdate = 0; // last time we printed the current memory stats + + var check = function() { + ev.used = mem().rss / 1024 / 1024; //Contains the amt. of used ram in MB + setTimeout(function() { // So we can handle requests etc. before we start collecting + GC(ev.used / ev.max); // Calculate the memory ratio, and execute the garbage collector + }, 1); + } + + setInterval(check, 1000); // set the garbage collector to run every second, TODO: make configurable + + //Executed every time a node gets modifyed + root.on("put", function(e) { + var ctime = Date.now(); + var souls = Object.keys(e.put || empty); + for (var i = 0; i < souls.length; i++) { + enqueueNode(souls[i], ctime); + } + }); + + //Adds a soul the garbage collectors "freeing" queue + function enqueueNode(soul, ctime) { + if (nodes[soul] == true) { //The node already exists in the queue + var index = nodesArray.findIndex(function(e) { + return e[0] === soul; + }); + if (index == -1) { + console.err("Something happened and the node '" + soul + "' won't get garbage collection unless the value is updated agian"); + return; + } else { + nodesArray.splice(index, 1); // remove the existing ref. + nodesArray.push([soul, ctime]); // push the new instance + } + } else { + nodesArray.push([soul, ctime]); + nodes[soul] = true; + } + } + + //The main garbage collecting routine + function GC(memRatio) { + var curTime = Date.now(); // get the current time + + if (curTime - memoryUpdate >= 5000) { + console.log("|GC| %s | Current Memory Ratio: %d | Current Ram Usage %sMB | Nodes in Memory %s", new Date().toLocaleString(), round(memRatio, 2), round(ev.used, 2), Object.keys(root.graph || empty).length); + memoryUpdate = curTime; + } + + var freed = 0; + + while (nodesArray.length > 0) { + var soul = nodesArray[0][0]; + var nts = nodesArray[0][1]; + if (DEBUG) + console.log("Soul: " + soul + " | Remove Importance: " + calcRemoveImportance(nts, curTime, memRatio) + + " | Memory Ratio: " + memRatio + " | Time Existed: " + (curTime - nts) / 1000); + if (calcRemoveImportance(nodesArray[0][1], curTime, memRatio) >= 100) { + root.gun.get(nodesArray[0][0]).off(); //Remove the node + delete nodes[nodesArray[0][0]]; // remove the lookup value + nodesArray.splice(0, 1); + freed++; + } else + break; + } + if (freed > 0) + console.log("|GC| Removed %s nodes in %s seconds-----------------------------------------------------------------", freed, (Date.now() - curTime) * 0.001); + } + + //Generates a number that, after it hits a threshold, the node gets removed + function calcRemoveImportance(timestamp, ctime, memoryUsageRatio) { + var time = (ctime - timestamp) * 0.001; + return time * 10 * (memoryUsageRatio * memoryUsageRatio) + } + + function round(value, decimals) { //a basic rounding function + return Number(Math.round(value + 'e' + decimals) + 'e-' + decimals); + } + }); +}()); \ No newline at end of file From 4e5b98af4cf902627061f67c589bf7b105743828 Mon Sep 17 00:00:00 2001 From: masterex1000 Date: Wed, 26 Sep 2018 17:47:01 -0600 Subject: [PATCH 123/221] Add les.js (Memory Evict) --- lib/les.js | 121 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 lib/les.js diff --git a/lib/les.js b/lib/les.js new file mode 100644 index 00000000..e6f3cb16 --- /dev/null +++ b/lib/les.js @@ -0,0 +1,121 @@ +; +(function() { + + // _ _____ ____ _ + // | | | ____/ ___| (_)___ + // | | | _| \___ \ | / __| + // | |___| |___ ___) | | \__ \ + // |_____|_____|____(_)/ |___/ + // ---------------------------- + // LES.js (Last rEcently uSed) + // ---------------------------- + // A Small, lightweight, queue-based + // Garbage Collector for Gun + // Originally By: Collin Conrad (@masterex1000) + + //NOTE: set to false is running from file in YOUR code + var USELOCALGUN = true; + + //NOTE: adds some debug messages + var DEBUG = false; + + + var Gun = (typeof window !== "undefined") ? window.Gun : (USELOCALGUN ? require('../gun') : require("gun")); + var ev = {}; + var empty = {}; + + Gun.on('opt', function(root) { + this.to.next(root); + if (root.once) + return; + if (typeof process == 'undefined') + return + var mem = process.memoryUsage; + + if (!mem) //exit because we are in the browser + return; + + //Figure out the most amount of memory we can use. TODO: make configurable? + ev.max = parseFloat(root.opt.memory || process.env.WEB_MEMORY || 512) * 0.8; + + var nodes = {}; //checks if the node already exists + var nodesArray = []; //used to easily sort everything and store info about the nodes + var memoryUpdate = 0; // last time we printed the current memory stats + + var check = function() { + ev.used = mem().rss / 1024 / 1024; //Contains the amt. of used ram in MB + setTimeout(function() { // So we can handle requests etc. before we start collecting + GC(ev.used / ev.max); // Calculate the memory ratio, and execute the garbage collector + }, 1); + } + + setInterval(check, 1000); // set the garbage collector to run every second, TODO: make configurable + + //Executed every time a node gets modifyed + root.on("put", function(e) { + var ctime = Date.now(); + var souls = Object.keys(e.put || empty); + for (var i = 0; i < souls.length; i++) { + enqueueNode(souls[i], ctime); + } + }); + + //Adds a soul the garbage collectors "freeing" queue + function enqueueNode(soul, ctime) { + if (nodes[soul] == true) { //The node already exists in the queue + var index = nodesArray.findIndex(function(e) { + return e[0] === soul; + }); + if (index == -1) { + console.err("Something happened and the node '" + soul + "' won't get garbage collection unless the value is updated agian"); + return; + } else { + nodesArray.splice(index, 1); // remove the existing ref. + nodesArray.push([soul, ctime]); // push the new instance + } + } else { + nodesArray.push([soul, ctime]); + nodes[soul] = true; + } + } + + //The main garbage collecting routine + function GC(memRatio) { + var curTime = Date.now(); // get the current time + + if (curTime - memoryUpdate >= 5000) { + console.log("|GC| %s | Current Memory Ratio: %d | Current Ram Usage %sMB | Nodes in Memory %s", new Date().toLocaleString(), round(memRatio, 2), round(ev.used, 2), Object.keys(root.graph || empty).length); + memoryUpdate = curTime; + } + + var freed = 0; + + while (nodesArray.length > 0) { + var soul = nodesArray[0][0]; + var nts = nodesArray[0][1]; + if (DEBUG) + console.log("Soul: " + soul + " | Remove Importance: " + calcRemoveImportance(nts, curTime, memRatio) + + " | Memory Ratio: " + memRatio + " | Time Existed: " + (curTime - nts) / 1000); + if (calcRemoveImportance(nodesArray[0][1], curTime, memRatio) >= 100) { + root.gun.get(nodesArray[0][0]).off(); //Remove the node + delete nodes[nodesArray[0][0]]; // remove the lookup value + nodesArray.splice(0, 1); + freed++; + } else + break; + } + if (freed > 0) + console.log("|GC| Removed %s nodes in %s seconds-----------------------------------------------------------------", freed, (Date.now() - curTime) * 0.001); + } + + //Generates a number that, after it hits a threshold, the node gets removed + function calcRemoveImportance(timestamp, ctime, memoryUsageRatio) { + var time = (ctime - timestamp) * 0.001; + return time * 10 * (memoryUsageRatio * memoryUsageRatio) + } + + function round(value, decimals) { //a basic rounding function + return Number(Math.round(value + 'e' + decimals) + 'e-' + decimals); + } + }); +}()); \ No newline at end of file From f1ff3b005cf3348aefb51e9b243a45ec2c9c456c Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Thu, 27 Sep 2018 16:30:56 -0700 Subject: [PATCH 124/221] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index febd3ffb..336915e8 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ **GUN** is an _ecosystem_ of tools that let you build tomorrow's dApps, today. -Decentralized alternatives to [Reddit](https://notabug.io/), [YouTube](https://d.tube/), [Wikipedia](https://news.ycombinator.com/item?id=17685682), etc. are already pushing terabytes of daily P2P traffic on GUN. We are a [friendly community](https://gitter.im/amark/gun) creating a free fun future for freedom: +Decentralized alternatives to [Reddit](https://notabug.io/t/whatever/comments/36588a16b9008da4e3f15663c2225e949eca4a15/gpu-bot-test), [YouTube](https://d.tube/), [Wikipedia](https://news.ycombinator.com/item?id=17685682), etc. are already pushing terabytes of daily P2P traffic on GUN. We are a [friendly community](https://gitter.im/amark/gun) creating a free fun future for freedom: From 41482d25cc7f944e83b519cbc2e8848ade577bb7 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Mon, 1 Oct 2018 15:51:15 -0700 Subject: [PATCH 125/221] SEA User.auth(pair for @mmalmi --- examples/game/space.html | 8 ++++---- gun.js | 4 ++-- package.json | 2 +- sea.js | 31 ++++++++++++++++++++++--------- 4 files changed, 29 insertions(+), 16 deletions(-) diff --git a/examples/game/space.html b/examples/game/space.html index f393be5b..cd93483d 100644 --- a/examples/game/space.html +++ b/examples/game/space.html @@ -9,13 +9,13 @@

          - - - + + + - - + + + + + +
          +
          Share
          + + + + + + + + + \ No newline at end of file diff --git a/gun.min.js b/gun.min.js index d30b4be2..d701be45 100644 --- a/gun.min.js +++ b/gun.min.js @@ -1,2 +1,2 @@ -!function(){function t(n,o){function e(t){return t.split("/").slice(-1).toString().replace(".js","")}return o?require(n):n.slice?t[e(n)]:function(o,i){n(o={exports:{}}),t[e(i)]=o.exports}}var n;"undefined"!=typeof window&&(n=window),"undefined"!=typeof global&&(n=global),n=n||{};var o=n.console||{log:function(){}};if("undefined"!=typeof module)var e=module;t(function(t){var n={};n.fn={is:function(t){return!!t&&"function"==typeof t}},n.bi={is:function(t){return t instanceof Boolean||"boolean"==typeof t}},n.num={is:function(t){return!e(t)&&(t-parseFloat(t)+1>=0||1/0===t||-(1/0)===t)}},n.text={is:function(t){return"string"==typeof t}},n.text.ify=function(t){return n.text.is(t)?t:"undefined"!=typeof JSON?JSON.stringify(t):t&&t.toString?t.toString():t},n.text.random=function(t,n){var o="";for(t=t||24,n=n||"0123456789ABCDEFGHIJKLMNOPQRSTUVWXZabcdefghijklmnopqrstuvwxyz";t>0;)o+=n.charAt(Math.floor(Math.random()*n.length)),t--;return o},n.text.match=function(t,o){function e(t,n){for(var o,e=-1,i=0;o=n[i++];)if(!~(e=t.indexOf(o,e+1)))return!1;return!0}var i=!1;if(t=t||"",o=n.text.is(o)?{"=":o}:o||{},n.obj.has(o,"~")&&(t=t.toLowerCase(),o["="]=(o["="]||o["~"]).toLowerCase()),n.obj.has(o,"="))return t===o["="];if(n.obj.has(o,"*")){if(t.slice(0,o["*"].length)!==o["*"])return!1;i=!0,t=t.slice(o["*"].length)}if(n.obj.has(o,"!")){if(t.slice(-o["!"].length)!==o["!"])return!1;i=!0}if(n.obj.has(o,"+")&&n.list.map(n.list.is(o["+"])?o["+"]:[o["+"]],function(n){return t.indexOf(n)>=0?void(i=!0):!0}))return!1;if(n.obj.has(o,"-")&&n.list.map(n.list.is(o["-"])?o["-"]:[o["-"]],function(n){return t.indexOf(n)<0?void(i=!0):!0}))return!1;if(n.obj.has(o,">")){if(!(t>o[">"]))return!1;i=!0}if(n.obj.has(o,"<")){if(!(tn?-1:n>o?1:0):0}},n.list.map=function(t,n,o){return u(t,n,o)},n.list.index=1,n.obj={is:function(t){return t?t instanceof Object&&t.constructor===Object||"Object"===Object.prototype.toString.call(t).match(/^\[object (\w+)\]$/)[1]:!1}},n.obj.put=function(t,n,o){return(t||{})[n]=o,t},n.obj.has=function(t,n){return t&&Object.prototype.hasOwnProperty.call(t,n)},n.obj.del=function(t,n){return t?(t[n]=null,delete t[n],t):void 0},n.obj.as=function(t,n,o,e){return t[n]=t[n]||(e===o?{}:o)},n.obj.ify=function(t){if(r(t))return t;try{t=JSON.parse(t)}catch(n){t={}}return t},function(){function t(t,n){a(this,n)&&o!==this[n]||(this[n]=t)}var o;n.obj.to=function(n,o){return o=o||{},u(n,t,o),o}}(),n.obj.copy=function(t){return t?JSON.parse(JSON.stringify(t)):t},function(){function t(t,n){var o=this.n;if(!o||!(n===o||r(o)&&a(o,n)))return n?!0:void 0}n.obj.empty=function(n,o){return n&&u(n,t,{n:o})?!1:!0}}(),function(){function t(n,o){return 2===arguments.length?(t.r=t.r||{},void(t.r[n]=o)):(t.r=t.r||[],void t.r.push(n))}var i=Object.keys;n.obj.map=function(u,s,f){var c,l,p,d,h,v=0,g=o(s);if(t.r=null,i&&r(u)&&(d=i(u),h=!0),e(u)||d)for(l=(d||u).length;l>v;v++){var m=v+n.list.index;if(g){if(p=h?s.call(f||this,u[d[v]],d[v],t):s.call(f||this,u[v],m,t),p!==c)return p}else if(s===u[h?d[v]:v])return d?d[v]:m}else for(v in u)if(g){if(a(u,v)&&(p=f?s.call(f,u[v],v,t):s(u[v],v,t),p!==c))return p}else if(s===u[v])return v;return g?t.r:n.list.index?0:-1}}(),n.time={},n.time.is=function(t){return t?t instanceof Date:+(new Date).getTime()};var o=n.fn.is,e=n.list.is,i=n.obj,r=i.is,a=i.has,u=i.map;t.exports=n})(t,"./type"),t(function(t){t.exports=function n(t,o,e){if(!t)return{to:n};var i,t=(this.tag||(this.tag={}))[t]||(this.tag[t]={tag:t,to:n._={next:function(t){var n;(n=this.to)&&n.next(t)}}});if(o instanceof Function){var r={off:n.off||(n.off=function(){return this.next===n._.next?!0:(this===this.the.last&&(this.the.last=this.back),this.to.back=this.back,this.next=n._.next,this.back.to=this.to,void(this.the.last===this.the&&delete this.on.tag[this.the.tag]))}),to:n._,next:o,the:t,on:this,as:e};return(r.back=t.last||t).to=r,t.last=r}return(t=t.to)&&i!==o&&t.next(o),t}})(t,"./onto"),t(function(t){function n(t,n,e,i,r){if(n>t)return{defer:!0};if(e>n)return{historical:!0};if(n>e)return{converge:!0,incoming:!0};if(n===e){if(i=o(i)||"",r=o(r)||"",i===r)return{state:!0};if(r>i)return{converge:!0,current:!0};if(i>r)return{converge:!0,incoming:!0}}return{err:"Invalid CRDT Data: "+i+" to "+r+" at "+n+" to "+e+"!"}}if("undefined"==typeof JSON)throw new Error("JSON is not included in this browser. Please load it first: ajax.cdnjs.com/ajax/libs/json2/20110223/json2.js");var o=JSON.stringify;t.exports=n})(t,"./HAM"),t(function(n){var o=t("./type"),e={};e.is=function(t){return t===i?!1:null===t?!0:t===1/0?!1:s(t)||a(t)||u(t)?!0:e.rel.is(t)||!1},e.link=e.rel={_:"#"},function(){function t(t,n){var o=this;return o.id?o.id=!1:n==r&&s(t)?void(o.id=t):o.id=!1}e.rel.is=function(n){if(n&&n[r]&&!n._&&c(n)){var o={};if(p(n,t,o),o.id)return o.id}return!1}}(),e.rel.ify=function(t){return l({},r,t)},o.obj.has._=".";var i,r=e.link._,a=o.bi.is,u=o.num.is,s=o.text.is,f=o.obj,c=f.is,l=f.put,p=f.map;n.exports=e})(t,"./val"),t(function(n){var o=t("./type"),e=t("./val"),i={_:"_"};i.soul=function(t,n){return t&&t._&&t._[n||p]},i.soul.ify=function(t,n){return n="string"==typeof n?{soul:n}:n||{},t=t||{},t._=t._||{},t._[p]=n.soul||t._[p]||l(),t},i.soul._=e.link._,function(){function t(t,n){return n!==i._?e.is(t)?void(this.cb&&this.cb.call(this.as,t,n,this.n,this.s)):!0:void 0}i.is=function(n,o,e){var r;return u(n)&&(r=i.soul(n))?!f(n,t,{as:e,cb:o,s:r,n:n}):!1}}(),function(){function t(t,n){var o,i,r=this.o;return r.map?(o=r.map.call(this.as,t,""+n,r.node),void(i===o?s(r.node,n):r.node&&(r.node[n]=o))):void(e.is(t)&&(r.node[n]=t))}i.ify=function(n,o,e){return o?"string"==typeof o?o={soul:o}:o instanceof Function&&(o={map:o}):o={},o.map&&(o.node=o.map.call(e,n,r,o.node||{})),(o.node=i.soul.ify(o.node||{},o))&&f(n,t,{o:o,as:e}),o.node}}();var r,a=o.obj,u=a.is,s=a.del,f=a.map,c=o.text,l=c.random,p=i.soul._;n.exports=i})(t,"./node"),t(function(n){function o(){var t;return t=r(),t>a?(u=0,a=t+o.drift):a=t+(u+=1)/s+o.drift}{var e=t("./type"),i=t("./node"),r=e.time.is,a=-(1/0),u=0,s=1e3,f="undefined"!=typeof performance?performance.timing&&performance:!1;f&&f.timing&&f.timing.navigationStart||(f=!1)}o._=">",o.drift=0,o.is=function(t,n,e){var i=n&&t&&t[x]&&t[x][o._]||e;if(i)return b(i=i[n])?i:-(1/0)},o.lex=function(){return o().toString(36).replace(".","")},o.ify=function(t,n,e,r,a){if(!t||!t[x]){if(!a)return;t=i.soul.ify(t,a)}var u=p(t[x],o._);return c!==n&&n!==x&&(b(e)&&(u[n]=e),c!==r&&(t[n]=r)),t},o.to=function(t,n,e){var r=t[n];return h(r)&&(r=g(r)),o.ify(e,n,o.is(t,n),r,i.soul(t))},function(){function t(t,n){x!==n&&o.ify(this.o,n,this.s)}o.map=function(n,e,i){var r,a=h(a=n||e)?a:null;return n=y(n=n||e)?n:null,a&&!n?(e=b(e)?e:o(),a[x]=a[x]||{},v(a,t,{o:a,s:e}),a):(i=i||h(e)?e:r,e=b(e)?e:o(),function(o,a,u,s){return n?(n.call(i||this||{},o,a,u,s),void(d(u,a)&&r===u[a]||t.call({o:u,s:e},o,a))):(t.call({o:u,s:e},o,a),o)})}}();var c,l=e.obj,p=l.as,d=l.has,h=l.is,v=l.map,g=l.copy,m=e.num,b=m.is,k=e.fn,y=k.is,x=i._;n.exports=o})(t,"./state"),t(function(n){var o=t("./type"),e=t("./val"),i=t("./node"),r={};!function(){function t(t,o){return t&&o===i.soul(t)&&i.is(t,this.fn,this.as)?void(this.cb&&(n.n=t,n.as=this.as,this.cb.call(n.as,t,o,n))):!0}function n(t){t&&i.is(n.n,t,n.as)}r.is=function(n,o,e,i){return n&&s(n)&&!l(n)?!d(n,t,{cb:o,fn:e,as:i}):!1}}(),function(){function t(t,o){var r;return(r=p(t,o))?r:(o.env=t,o.soul=u,i.ify(o.obj,n,o)&&(o.rel=o.rel||e.rel.ify(i.soul(o.node)),o.obj!==t.shell&&(t.graph[e.rel.is(o.rel)]=o.node)),o)}function n(n,o,r){var u,s,p=this,d=p.env;if(i._===o&&c(n,e.rel._))return r._;if(u=l(n,o,r,p,d)){if(o||(p.node=p.node||r||{},c(n,i._)&&i.soul(n)&&(p.node._=h(n._)),p.node=i.soul.ify(p.node,e.rel.is(p.rel)),p.rel=p.rel||e.rel.ify(i.soul(p.node))),(s=d.map)&&(s.call(d.as||{},n,o,r,p),c(r,o))){if(n=r[o],a===n)return void f(r,o);if(!(u=l(n,o,r,p,d)))return}if(!o)return p.node;if(!0===u)return n;if(s=t(d,{obj:n,path:p.path.concat(o)}),s.node)return s.rel}}function u(t){var n=this,o=e.link.is(n.rel),r=n.env.graph;n.rel=n.rel||e.rel.ify(t),n.rel[e.rel._]=t,n.node&&n.node[i._]&&(n.node[i._][e.rel._]=t),c(r,o)&&(r[t]=r[o],f(r,o))}function l(t,n,i,r,a){var u;return e.is(t)?!0:s(t)?1:(u=a.invalid)?(t=u.call(a.as||{},t,n,i),l(t,n,i,r,a)):(a.err="Invalid value at '"+r.path.concat(n).join(".")+"'!",void(o.list.is(t)&&(a.err+=" Use `.set(item)` instead of an Array.")))}function p(t,n){for(var o,e=t.seen,i=e.length;i--;)if(o=e[i],n.obj===o.obj)return o;e.push(n)}r.ify=function(n,o,i){var r={path:[],obj:n};return o?"string"==typeof o?o={soul:o}:o instanceof Function&&(o.map=o):o={},o.soul&&(r.rel=e.rel.ify(o.soul)),o.shell=(i||{}).shell,o.graph=o.graph||{},o.seen=o.seen||[],o.as=o.as||i,t(o,r),o.root=r.node,o.graph}}(),r.node=function(t){var n=i.soul(t);if(n)return p({},n,t)},function(){function t(t,n){var o,a;if(i._===n){if(l(t,e.rel._))return;return void(this.obj[n]=h(t))}return(o=e.rel.is(t))?(a=this.opt.seen[o])?void(this.obj[n]=a):void(this.obj[n]=this.opt.seen[o]=r.to(this.graph,o,this.opt)):void(this.obj[n]=t)}r.to=function(n,o,e){if(n){var i={};return e=e||{seen:{}},d(n[o],t,{obj:i,graph:n,opt:e}),i}}}();var a,u=(o.fn.is,o.obj),s=u.is,f=u.del,c=u.has,l=u.empty,p=u.put,d=u.map,h=u.copy;n.exports=r})(t,"./graph"),t(function(n){t("./onto"),n.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}var 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}}})(t,"./ask"),t(function(n){function o(t){var n={s:{}};return t=t||{max:1e3,age:9e3},n.check=function(t){var o;return(o=n.s[t])?o.pass?o.pass=!1:n.track(t):!1},n.track=function(o,r){var a=n.s[o]||(n.s[o]={});return a.was=i(),r&&(a.pass=!0),n.to||(n.to=setTimeout(function(){var o=i();e.obj.map(n.s,function(i,r){i&&t.age>o-i.was||e.obj.del(n.s,r)}),n.to=null},t.age+9)),a},n}var e=t("./type"),i=e.time.is;n.exports=o})(t,"./dup"),t(function(n){function i(t){return t instanceof i?(this._={gun:this,$:this}).$:this instanceof i?i.create(this._={gun:this,$:this,opt:t}):new i(t)}i.is=function(t){return t instanceof i||t&&t._&&t===t._.$||!1},i.version=.9,i.chain=i.prototype,i.chain.toJSON=function(){};var r=t("./type");r.obj.to(r,i),i.HAM=t("./HAM"),i.val=t("./val"),i.node=t("./node"),i.state=t("./state"),i.graph=t("./graph"),i.on=t("./onto"),i.ask=t("./ask"),i.dup=t("./dup"),function(){function t(n){var o,e,r=this,u=r.as,s=u.at||u,f=s.$;return(e=n["#"])||(e=n["#"]=c(9)),(o=s.dup).check(e)?void(u.out===n.out&&(n.out=a,r.to.next(n))):(o.track(e),s.ask(n["@"],n)||(n.get&&i.on.get(n,f),n.put&&i.on.put(n,f)),r.to.next(n),void(u.out||(n.out=t,s.on("out",n))))}i.create=function(n){n.root=n.root||n,n.graph=n.graph||{},n.on=n.on||i.on,n.ask=n.ask||i.ask,n.dup=n.dup||i.dup();var o=n.$.opt(n.opt);return n.once||(n.on("in",t,n),n.on("out",t,{at:n,out:t}),i.on("create",n),n.on("create",n)),n.once=1,o}}(),function(){function t(t,n,o,e){var r=this,a=i.state.is(o,n);if(!a)return r.err="Error: No state on '"+n+"' in node '"+e+"'!";var u=r.graph[e]||k,s=i.state.is(u,n,!0),f=u[n],c=i.HAM(r.machine,a,s,t,f);return c.incoming?(r.put[e]=i.state.to(o,n,r.put[e]),(r.diff||(r.diff={}))[e]=i.state.to(o,n,r.diff[e]),void(r.souls[e]=!0)):void(c.defer&&(r.defer=a<(r.defer||1/0)?a:r.defer))}function n(t,n){var i=this,a=i.$._,u=(a.next||k)[n];if(!u){if(!(a.opt||k)["super"])return void(i.souls[n]=!1);u=i.$.get(n)._}var s=i.map[n]={put:t,get:n,$:u.$},f={ctx:i,msg:s};i.async=!!a.tag.node,i.ack&&(s["@"]=i.ack),v(t,o,f),i.async&&(i.and||a.on("node",function(t){this.to.next(t),t===i.map[t.get]&&(i.souls[t.get]=!1,v(t.put,e,t),v(i.souls,function(t){return t?t:void 0})||i.c||(i.c=1,this.off(),v(i.map,r,i)))}),i.and=!0,a.on("node",s))}function o(t,n){var o=this.ctx,e=o.graph,r=this.msg,a=r.get,u=r.put,s=r.$._;e[a]=i.state.to(u,n,e[a]),o.async||(s.put=i.state.to(u,n,s.put))}function e(t,n){var o=this,e=o.put,r=o.$._;r.put=i.state.to(e,n,r.put)}function r(t){t.$&&(this.cat.stop=this.stop,t.$._.on("in",t),this.cat.stop=null)}i.on.put=function(o,e){var u=e._,s={$:e,graph:u.graph,put:{},map:{},souls:{},machine:i.state(),ack:o["@"],cat:u,stop:{}};return i.graph.is(o.put,null,t,s)||(s.err="Error: Invalid graph!"),s.err?u.on("in",{"@":o["#"],err:i.log(s.err)}):(v(s.put,n,s),s.async||v(s.map,r,s),a!==s.defer&&setTimeout(function(){i.on.put(o,e)},s.defer-s.machine),void(s.diff&&u.on("put",h(o,{put:s.diff}))))},i.on.get=function(t,n){var o,e=n._,r=t.get,a=r[m],u=e.graph[a],s=r[b],f=e.next||(e.next={}),c=f[a];if(d(a,"*")){var l={};i.obj.map(e.graph,function(t,n){i.text.match(n,a)&&(l[n]=i.obj.copy(t))}),i.obj.empty(l)||e.on("in",{"@":t["#"],how:"*",put:l,$:n})}if(!u)return e.on("get",t);if(s){if(!d(u,s))return e.on("get",t);u=i.state.to(u,s)}else u=i.obj.copy(u);u=i.graph.node(u),o=(c||k).ack,e.on("in",{"@":t["#"],how:"mem",put:u,$:n}),e.on("get",t)}}(),function(){i.chain.opt=function(t){t=t||{};var n=this,o=n._,e=t.peers||t;return p(t)||(t={}),p(o.opt)||(o.opt=t),f(e)&&(e=[e]),u(e)&&(e=v(e,function(t,n,o){o(t,{url:t})}),p(o.opt.peers)||(o.opt.peers={}),o.opt.peers=h(e,o.opt.peers)),o.opt.peers=o.opt.peers||{},h(t,o.opt),i.on("opt",o),o.opt.uuid=o.opt.uuid||function(){return g()+c(12)},n}}();var a,u=i.list.is,s=i.text,f=s.is,c=s.random,l=i.obj,p=l.is,d=l.has,h=l.to,v=l.map,g=(l.copy,i.state.lex),m=i.val.rel._,b=".",k=(i.node._,i.val.link.is,{});o.debug=function(t,n){return o.debug.i&&t===o.debug.i&&o.debug.i++&&(o.log.apply(o,arguments)||n)},i.log=function(){return!i.log.off&&o.log.apply(o,arguments),[].slice.call(arguments).join(" ")},i.log.once=function(t,n,o){return(o=i.log.once)[t]=o[t]||0,o[t]++||i.log(n)},i.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=i).window=window);try{"undefined"!=typeof e&&(e.exports=i)}catch(y){}n.exports=i})(t,"./root"),t(function(){var n=t("./root");n.chain.back=function(t,i){var r;if(t=t||1,-1===t||1/0===t)return this._.root.$;if(1===t)return(this._.back||this._).$;var a=this,u=a._;if("string"==typeof t&&(t=t.split(".")),!(t instanceof Array)){if(t instanceof Function){for(var s,r={back:u};(r=r.back)&&o===(s=t(r,i)););return s}return n.num.is(t)?(u.back||u).$.back(t-1):this}var f=0,c=t.length,r=u;for(f;c>f;f++)r=(r||e)[t[f]];return o!==r?i?a:r:(r=u.back)?r.$.back(t,i):void 0};var o,e={}})(t,"./back"),t(function(){function n(t){var n,o,e,i=this.as,r=i.back,a=i.root;if(t.I||(t.I=i.$),t.$||(t.$=i.$),this.to.next(t),o=t.get){if(o["#"]||i.soul){if(o["#"]=o["#"]||i.soul,t["#"]||(t["#"]=b(9)),r=a.$.get(o["#"])._,o=o["."]){if(h(r.put,o)&&(n=r.$.get(o)._,(e=n.ack)||(n.ack=-1),r.on("in",{$:r.$,put:c.state.to(r.put,o),get:r.get}),e))return}else{if(e=r.ack,e||(r.ack=-1),h(r,"put")&&r.on("in",r),e)return;t.$=r.$}return a.ask(f,t),a.on("in",t)}if(a.now&&(a.now[i.id]=a.now[i.id]||!0,i.pass={}),o["."])return i.get?(t={get:{".":i.get},$:i.$},r.ask||(r.ask={}),r.ask[i.get]=t.$._,r.on("out",t)):(t={get:{},$:i.$},r.on("out",t));if(i.ack=i.ack||-1,i.get)return t.$=i.$,o["."]=i.get,(r.ask||(r.ask={}))[i.get]=t.$._,r.on("out",t)}return r.on("out",t)}function o(t){var n,o,r=this,s=r.as,f=s.root,d=t.$,b=(d||p)._||p,k=t.put;if(s.get&&t.get!==s.get&&(t=g(t,{get:s.get})),s.has&&b!==s&&(t=g(t,{$:s.$}),b.ack&&(s.ack=b.ack)),l===k){if(o=b.put,r.to.next(t),s.soul)return;if(l===o&&l!==b.put)return;return i(s,t,r),s.has&&u(s,t),v(b.echo,s.id),void v(s.map,b.id)}if(s.soul)return r.to.next(t),i(s,t,r),void(s.next&&m(k,a,{msg:t,cat:s}));if(!(n=c.val.link.is(k)))return c.val.is(k)?(s.has||s.soul?u(s,t):(b.has||b.soul)&&((b.echo||(b.echo={}))[s.id]=b.echo[b.id]||s,(s.map||(s.map={}))[b.id]=s.map[b.id]||{at:b}),r.to.next(t),void i(s,t,r)):(s.has&&b!==s&&h(b,"put")&&(s.put=b.put),(n=c.node.soul(k))&&b.has&&(b.put=s.root.$.get(n)._.put),o=(f.stop||{})[b.id],r.to.next(t),e(s,t,b,n),i(s,t,r),void(s.next&&m(k,a,{msg:t,cat:s})));f.stop;o=f.stop||{},o=o[b.id]||(o[b.id]={}),o.is=o.is||b.put,o[s.id]=b.put||!0,r.to.next(t),e(s,t,b,n),i(s,t,r)}function e(t,n,o,i){if(i&&k!==t.get){var r=t.root.$.get(i)._;t.has?o=r:o.has&&e(o,n,o,i),o!==t&&(o.$||(o={}),(o.echo||(o.echo={}))[t.id]=o.echo[t.id]||t,t.has&&!(t.map||p)[o.id]&&u(t,n),r=o.id?(t.map||(t.map={}))[o.id]=t.map[o.id]||{at:o}:{},(i!==r.link||r.pass||t.pass)&&(t.pass&&(c.obj.map(t.map,function(t){t.pass=!0}),v(t,"pass")),r.pass&&v(r,"pass"),t.has&&(t.link=i),s(t,r.link=i)))}}function i(t,n){t.echo&&m(t.echo,r,n)}function r(t){t&&t.on&&t.on("in",this)}function a(t,n){var o,e,i,r=this.cat,a=r.next||p,u=this.msg;(k!==n||a[n])&&(e=a[n])&&(e.has?(l!==e.put&&c.val.link.is(t)||(e.put=t),o=e.$):(i=u.$)&&(i=(o=u.$.get(n))._,l!==i.put&&c.val.link.is(t)||(i.put=t)),e.on("in",{put:t,get:n,$:o,via:u}))}function u(t,n){if(t.has||t.soul){{var o=t.map;t.root}t.map=null,t.has&&(t.link=null),(t.pass||n["@"]||null!==o)&&(l===o&&c.val.link.is(t.put)||(m(o,function(n){(n=n.at)&&v(n.echo,t.id)}),o=t.put,m(t.next,function(n,e){return l===o&&l!==t.put?!0:(n.put=l,n.ack&&(n.ack=-1),void n.on("in",{get:e,$:n.$,put:l}))})))}}function s(t,n){var o=t.root.$.get(n)._;(!t.ack||(o.on("out",{get:{"#":n}}),t.ask))&&(o=t.ask,c.obj.del(t,"ask"),m(o||t.next,function(t,o){t.on("out",{get:{"#":n,".":o}})}),c.obj.del(t,"ask"))}function f(t){var n=this.as,o=n.get||p,e=n.$._,i=(t.put||p)[o["#"]];if(e.ack&&(e.ack=e.ack+1||1),!t.put||o["."]&&!h(i,e.get)){if(e.put!==l)return;return void e.on("in",{get:e.get,put:e.put=l,$:e.$,"@":t["@"]})}return k==o["."]?void e.on("in",{get:e.get,put:c.val.link.ify(o["#"]),$:e.$,"@":t["@"]}):(t.$=e.root.$,void c.on.put(t,e.root.$))}var c=t("./root");c.chain.chain=function(t){var e,i=this,r=i._,a=new(t||i).constructor(i),u=a._;return u.root=e=r.root,u.id=++e.once,u.back=i._,u.on=c.on,u.on("in",o,u),u.on("out",n,u),a};var l,p={},d=c.obj,h=d.has,v=(d.put,d.del),g=d.to,m=d.map,b=c.text.random,k=(c.val.rel._,c.node._)})(t,"./chain"),t(function(){function n(t,n){var o=n._,e=o.next,i=n.chain(),r=i._;return e||(e=o.next={}),e[r.get=t]=r,n===o.root.$?r.soul=t:(o.soul||o.has)&&(r.has=t),r}function o(t,n,o,e){var i,r=t._;return(i=r.soul)?(n(i,e,r),t):(i=r.link)?(n(i,e,r),t):(t.get(function(t,o){o.rid(t);var r=(r=t.$)&&r._||{};i=r.link||r.soul||c.is(t.put)||l(t.put),n(i,e,t,o)},{out:{get:{".":!0}}}),t)}function e(t){var n,o=this,e=o.as,i=e.at,r=i.root,u=t.$,f=(u||{})._||{},l=t.put||f.put;if((n=r.now)&&o!==n[e.now])return o.to.next(t);if(o.seen&&f.id&&o.seen[f.id])return o.to.next(t);if((n=l)&&n[c._]&&(n=c.is(n))&&(n=(t.$$=f.root.gun.get(n))._,a!==n.put&&(t=s(t,{put:l=n.put}))),(n=r.mum)&&f.id){if(n[f.id])return;a===l||c.is(l)||(n[f.id]=!0)}return e.use(t,o),o.stun?void(o.stun=null):void o.to.next(t)}function i(t){var n=this.on;if(!t||n.soul||n.has)return this.off();if(t=(t=(t=t.$||t)._||t).id){{var o,e;n.map}return(o=(e=this.seen||(this.seen={}))[t])?!0:void(e[t]=!0)}}var r=t("./root");r.chain.get=function(t,a,u){var s,l;if("string"!=typeof t){if(t instanceof Function){if(!0===a)return o(this,t,a,u);s=this;var d,h=s._,v=h.root,l=v.now;u=a||{},u.at=h,u.use=t,u.out=u.out||{},u.out.get=u.out.get||{},(d=h.on("in",e,u)).rid=i,(v.now={$:1})[u.now=h.id]=d;var g=v.mum;return v.mum={},h.on("out",u.out),v.mum=g,v.now=l,s}return f(t)?this.get(""+t,a,u):(l=c.is(t))?this.get(l,a,u):((u=this.chain())._.err={err:r.log("Invalid get request!",t)},a&&a.call(u,u._.err),u)}var m=this,b=m._,k=b.next||p;return(s=k[t])||(s=n(t,m)),s=s.$,(l=b.stun)&&(s._.stun=s._.stun||l),a&&a instanceof Function&&s.get(a,u),s};var a,u=r.obj,s=(u.has,r.obj.to),f=r.num.is,c=r.val.link,l=r.node.soul,p=(r.node._,{})})(t,"./get"),t(function(){function n(t){t.batch=i;var n=t.opt||{},o=t.env=c.state.map(a,n.state);return o.soul=t.soul,t.graph=c.graph.ify(t.data,o,t),o.err?((t.ack||m).call(t,t.out={err:c.log(o.err)}),void(t.res&&t.res())):void t.batch()}function e(t){return void(t&&t())}function i(){var t=this;t.graph&&!v(t.stun,r)&&(t.res=t.res||function(t){t&&t()},t.res(function(){var n=t.$.back(-1)._,o=n.ask(function(o){n.root.on("ack",o),o.err&&c.log(o),o.lack||this.off(),t.ack&&t.ack(o,this)},t.opt),e=n.root.now;p.del(n.root,"now");var i=n.root.mum;n.root.mum={},t.ref._.on("out",{$:t.ref,put:t.out=t.env.graph,opt:t.opt,"#":o}),n.root.mum=i?p.to(i,n.root.mum):i,n.root.now=e},t),t.res&&t.res())}function r(t){return t?!0:void 0}function a(t,n,o,e){var i=this,r=c.is(t);!n&&e.path.length&&(i.res||b)(function(){var n=e.path,o=i.ref,a=(i.opt,0),s=n.length;for(a;s>a;a++)o=o.get(n[a]);r&&(o=t);var f=o._.dub;return f||(f=c.node.soul(e.obj))?(o.back(-1).get(f),void e.soul(f)):((i.stun=i.stun||{})[n]=!0,void o.get(u,!0,{as:{at:e,as:i,p:n}}))},{as:i,at:e})}function u(t,n,o,e){var n=n.as,i=n.at;n=n.as;var r=((o||{}).$||{})._||{};return t=r.dub=r.dub||t||c.node.soul(i.obj)||c.node.soul(o.put||r.put)||c.val.rel.is(o.put||r.put)||(n.via.back("opt.uuid")||c.text.random)(),e&&(e.stun=!0),t?void s(r,r.dub=t,i,n):void r.via.back("opt.uuid")(function(t,o){return t?c.log(t):void s(r,r.dub=r.dub||o,i,n)})}function s(t,n,o,e){t.$.back(-1).get(n),o.soul(n),e.stun[o.path]=!1,e.batch()}function f(t,n,e,i){if(n=n.as,e.$&&e.$._){if(e.err)return void o.log("Please report this as an issue! Put.any.err");var r,a=e.$._,u=a.put,s=n.opt||{};if(!(r=n.ref)||!r._.now){if(i&&(i.stun=!0),n.ref!==n.$){if(r=n.$._.get||a.get,!r)return void o.log("Please report this as an issue! Put.no.get");n.data=h({},r,n.data),r=null}if(l===u){if(!a.get)return;t||(r=a.$.back(function(t){return t.link||t.soul?t.link||t.soul:void(n.data=h({},t.get,n.data))})),r=r||a.get,a=a.root.$.get(r)._,n.soul=r,u=n.data}return n.not||(n.soul=n.soul||t)||(n.path&&d(n.data)?n.soul=(s.uuid||n.via.back("opt.uuid")||c.text.random)():(k==a.get&&(n.soul=(a.put||g)["#"]||a.dub),n.soul=n.soul||a.soul||a.soul||(s.uuid||n.via.back("opt.uuid")||c.text.random)()),n.soul)?void n.ref.put(n.data,n.soul,n):void n.via.back("opt.uuid")(function(t,o){return t?c.log(t):void n.ref.put(n.data,n.soul=o,n)})}}}var c=t("./root");c.chain.put=function(t,o,i){var r,a=this,u=a._,s=u.root.$;return i=i||{},i.data=t,i.via=i.$=i.via||i.$||a,"string"==typeof o?i.soul=o:i.ack=i.ack||o,u.soul&&(i.soul=u.soul),i.soul||s===a?d(i.data)?(i.soul=i.soul||(i.not=c.node.soul(i.data)||(i.via.back("opt.uuid")||c.text.random)()),i.soul?(i.$=a=s.get(i.soul),i.ref=i.$,n(i),a):(i.via.back("opt.uuid")(function(t,n){return t?c.log(t):void(i.ref||i.$).put(i.data,i.soul=n,i)}),a)):((i.ack||m).call(i,i.out={err:c.log("Data saved to the root level of the graph must be a node (an object), not a",typeof i.data,'of "'+i.data+'"!')}),i.res&&i.res(),a):c.is(t)?(t.get(function(t,n,e){return!t&&c.val.is(e.put)?c.log("The reference you are saving is a",typeof e.put,'"'+e.put+'", not a node (object)!'):void a.put(c.val.rel.ify(t),o,i)},!0),a):(i.ref=i.ref||s._===(r=u.back)?a:r.$,i.ref._.soul&&c.val.is(i.data)&&u.get?(i.data=h({},u.get,i.data),i.ref.put(i.data,i.soul,i),a):(i.ref.get(f,!0,{as:i}),i.out||(i.res=i.res||e,i.$._.stun=i.ref._.stun),a))};var l,p=c.obj,d=p.is,h=p.put,v=p.map,g={},m=function(){},b=function(t,n){t.call(n||g)},k=c.node._})(t,"./put"),t(function(n){var o=t("./root");t("./chain"),t("./back"),t("./put"),t("./get"),n.exports=o})(t,"./index"),t(function(){function n(t,n){{var o,e=this,r=t.$,a=(r||{})._||{},u=a.put||t.put;e.at}if(i!==u){if(o=t.$$){if(o=t.$$._,i===o.put)return;u=o.put}e.change&&(u=t.put),e.as?e.ok.call(e.as,t,n):e.ok.call(r,u,t.get,t,n)}}function o(t,n,e){var r,u,s=this.as,f=(s.at,t.$),c=f._,l=c.put||t.put;if(u=t.$$){if(r=u=t.$$._,i===u.put)return;l=u.put}return(u=n.wait)&&(u=u[c.id])&&clearTimeout(u),!e&&(i===l||c.soul||c.link||r&&!(0 .once, apologies unexpected."),this.once(t,n)},e.chain.once=function(t,n){var r=this,a=r._,u=a.put;if(0=(n.batch||1e3)?s():void(e||(e=setTimeout(s,n.wait||1)))}),t.on("get",function(o){function e(){if(s&&(i=s["#"])){var e=s["."];r=a[i]||u,r&&e&&(r=Gun.state.to(r,e)),(r||Gun.obj.empty(n.peers))&&t.on("in",{"@":o["#"],put:Gun.graph.node(r),how:"lS",lS:o.I})}}this.to.next(o);var i,r,u,s=o.get;Gun.debug?setTimeout(e,1):e()});var u=function(t,n,o,e){a[e]=Gun.state.to(o,n,a[e])},s=function(u){var f;r=0,clearTimeout(e),e=!1;var c=i;i={},u&&(a=u);try{o.setItem(n.prefix,JSON.stringify(a))}catch(l){Gun.log(f=(l||"localStorage failure")+" Consider using GUN's IndexedDB plugin for RAD for more storage space, temporary example at https://github.com/amark/gun/blob/master/test/tmp/indexedDB.html ."),t.on("localStorage:error",{err:f,file:n.prefix,flush:a,retry:s})}(f||Gun.obj.empty(n.peers))&&Gun.obj.map(c,function(n,o){t.on("in",{"@":o,err:f,ok:0})})}}})}})(t,"./adapters/localStorage"),t(function(n){function e(t){var n=function(){},u=t.opt||{};return u.log=u.log||o.log,u.gap=u.gap||u.wait||1,u.pack=u.pack||.3*(u.memory?1e3*u.memory*1e3:1399e6),n.out=function(o){var e;return this.to&&this.to.next(o),(e=o["@"])&&(e=t.dup.s[e])&&(e=e.it)&&e.mesh?(n.say(o,e.mesh.via,1),void(e["##"]=o["##"])):void n.say(o)},t.on("create",function(o){o.opt.pid=o.opt.pid||i.text.random(9),this.to.next(o),t.on("out",n.out)}),n.hear=function(o,e){if(o){var r,a,s,f=t.dup,c=o[0];if(u.pack<=o.length)return n.say({dam:"!",err:"Message too big!"},e);try{s=JSON.parse(o)}catch(l){u.log("DAM JSON parse error",l)}if("{"===c){if(!s)return;if(f.check(r=s["#"]))return;if(f.track(r,!0).it=s,(c=s["@"])&&s.put&&(a=s["##"]||(s["##"]=n.hash(s)),(c+=a)!=r)){if(f.check(c))return;(c=f.s)[a]=c[r]}return(s.mesh=function(){}).via=e,(c=s["><"])&&(s.mesh.to=i.obj.map(c.split(","),function(t,n,o){o(t,!0)})),s.dam?void((c=n.hear[s.dam])&&c(s,e,t)):void t.on("in",s)}if("["!==c);else{if(!s)return;for(var p,d=0;p=s[d++];)n.hear(p,e)}}},function(){function o(t){var n=t.batch;if(n&&(t.batch=t.tail=null,n.length))try{e(JSON.stringify(n),t)}catch(o){u.log("DAM JSON stringify error",o)}}function e(t,n){var o=n.wire;try{o.send?o.send(t):n.say&&n.say(t)}catch(e){(n.queue=n.queue||[]).push(t)}}n.say=function(r,s,f){if(!s)return void i.obj.map(u.peers,function(t){n.say(r,t)});var c,l,p,d=s.wire||u.wire&&u.wire(s);if(d&&(l=r.mesh||a,s!==l.via&&((p=l.raw)||(p=n.raw(r)),!((c=r["@"])&&(c=t.dup.s[c])&&(c=c.it)&&c.get&&c["##"]&&c["##"]===r["##"]||(c=l.to)&&(c[s.url]||c[s.id])&&!f)))){if(s.batch){if(s.tail=(s.tail||0)+p.length,s.tail<=u.pack)return void s.batch.push(p);o(s)}s.batch=[],setTimeout(function(){o(s)},u.gap),e(p,s)}}}(),function(){function o(t,n){var o;return n instanceof Object?(i.obj.map(Object.keys(n).sort(),a,{to:o={},on:n}),o):n}function a(t){this.to[t]=this.on[t]}n.raw=function(e){if(!e)return"";var a,c,l,p=t.dup,d=e.mesh||{};if(l=d.raw)return l;if("string"==typeof e)return e;e["@"]&&(l=e.put)&&((c=e["##"])||(a=s(l,o)||"",c=n.hash(e,a),e["##"]=c),(l=p.s)[c=e["@"]+c]=l[e["#"]],e["#"]=c||e["#"],a&&((e=i.obj.to(e)).put=f));var h=0,v=[];i.obj.map(u.peers,function(t){return v.push(t.url||t.id),++h>9?!0:void 0}),e["><"]=v.join();var g=s(e);return r!==a&&(l=g.indexOf(f,g.indexOf("put")),g=g.slice(0,l-1)+a+g.slice(l+f.length+1)),d&&(d.raw=g),g},n.hash=function(t,n){return e.hash(n||s(t.put,o)||"")||t["#"]||i.text.random(9)};var s=JSON.stringify,f=":])([:"}(),n.hi=function(o){var e=o.wire||{};o.id||o.url?(u.peers[o.url||o.id]=o,i.obj.del(u.peers,e.id)):(e=e.id=e.id||i.text.random(9),n.say({dam:"?"},u.peers[e]=o)),e.hied||t.on(e.hied="hi",o),e=o.queue,o.queue=[],i.obj.map(e,function(t){n.say(t,o)})},n.bye=function(n){i.obj.del(u.peers,n.id),t.on("bye",n)},n.hear["!"]=function(t){u.log("Error:",t.err)},n.hear["?"]=function(t,o){return t.pid?(o.id=o.id||t.pid,void n.hi(o)):n.say({dam:"?",pid:u.pid,"@":t["#"]},o)},n}var i=t("../type");e.hash=function(t){if("string"!=typeof t)return{err:1};var n=0;if(!t.length)return n;for(var o,e=0,i=t.length;i>e;++e)o=t.charCodeAt(e), -n=(n<<5)-n+o,n|=0;return n};var r,a={};Object.keys=Object.keys||function(t){return map(t,function(t,n,o){o(n)})};try{n.exports=e}catch(u){}})(t,"./adapters/mesh"),t(function(){var n=t("../index");n.Mesh=t("./mesh"),n.on("opt",function(t){function o(t){try{if(!t||!t.url)return o&&o(t);var n=t.url.replace("http","ws"),o=t.wire=new i.WebSocket(n);return o.onclose=function(){i.mesh.bye(t),e(t)},o.onerror=function(n){e(t),n&&"ECONNREFUSED"===n.code},o.onopen=function(){i.mesh.hi(t)},o.onmessage=function(n){n&&i.mesh.hear(n.data||n,t)},o}catch(r){}}function e(t){clearTimeout(t.defer),t.defer=setTimeout(function(){o(t)},2e3)}this.to.next(t);var i=t.opt;if(!t.once&&!1!==i.WebSocket){var r;"undefined"!=typeof window&&(r=window),"undefined"!=typeof global&&(r=global),r=r||{};var a=i.WebSocket||r.WebSocket||r.webkitWebSocket||r.mozWebSocket;if(a){i.WebSocket=a;{i.mesh=i.mesh||n.Mesh(t),i.wire}i.wire=o}}})})(t,"./adapters/websocket")}(); \ No newline at end of file +!function(){function t(n,o){function e(t){return t.split("/").slice(-1).toString().replace(".js","")}return o?require(n):n.slice?t[e(n)]:function(o,i){n(o={exports:{}}),t[e(i)]=o.exports}}var n;"undefined"!=typeof window&&(n=window),"undefined"!=typeof global&&(n=global),n=n||{};var o=n.console||{log:function(){}};if("undefined"!=typeof module)var e=module;t(function(t){var n={};n.fn={is:function(t){return!!t&&"function"==typeof t}},n.bi={is:function(t){return t instanceof Boolean||"boolean"==typeof t}},n.num={is:function(t){return!e(t)&&(t-parseFloat(t)+1>=0||1/0===t||-(1/0)===t)}},n.text={is:function(t){return"string"==typeof t}},n.text.ify=function(t){return n.text.is(t)?t:"undefined"!=typeof JSON?JSON.stringify(t):t&&t.toString?t.toString():t},n.text.random=function(t,n){var o="";for(t=t||24,n=n||"0123456789ABCDEFGHIJKLMNOPQRSTUVWXZabcdefghijklmnopqrstuvwxyz";t>0;)o+=n.charAt(Math.floor(Math.random()*n.length)),t--;return o},n.text.match=function(t,o){function e(t,n){for(var o,e=-1,i=0;o=n[i++];)if(!~(e=t.indexOf(o,e+1)))return!1;return!0}var i=!1;if(t=t||"",o=n.text.is(o)?{"=":o}:o||{},n.obj.has(o,"~")&&(t=t.toLowerCase(),o["="]=(o["="]||o["~"]).toLowerCase()),n.obj.has(o,"="))return t===o["="];if(n.obj.has(o,"*")){if(t.slice(0,o["*"].length)!==o["*"])return!1;i=!0,t=t.slice(o["*"].length)}if(n.obj.has(o,"!")){if(t.slice(-o["!"].length)!==o["!"])return!1;i=!0}if(n.obj.has(o,"+")&&n.list.map(n.list.is(o["+"])?o["+"]:[o["+"]],function(n){return t.indexOf(n)>=0?void(i=!0):!0}))return!1;if(n.obj.has(o,"-")&&n.list.map(n.list.is(o["-"])?o["-"]:[o["-"]],function(n){return t.indexOf(n)<0?void(i=!0):!0}))return!1;if(n.obj.has(o,">")){if(!(t>o[">"]))return!1;i=!0}if(n.obj.has(o,"<")){if(!(tn?-1:n>o?1:0):0}},n.list.map=function(t,n,o){return u(t,n,o)},n.list.index=1,n.obj={is:function(t){return t?t instanceof Object&&t.constructor===Object||"Object"===Object.prototype.toString.call(t).match(/^\[object (\w+)\]$/)[1]:!1}},n.obj.put=function(t,n,o){return(t||{})[n]=o,t},n.obj.has=function(t,n){return t&&Object.prototype.hasOwnProperty.call(t,n)},n.obj.del=function(t,n){return t?(t[n]=null,delete t[n],t):void 0},n.obj.as=function(t,n,o,e){return t[n]=t[n]||(e===o?{}:o)},n.obj.ify=function(t){if(r(t))return t;try{t=JSON.parse(t)}catch(n){t={}}return t},function(){function t(t,n){a(this,n)&&o!==this[n]||(this[n]=t)}var o;n.obj.to=function(n,o){return o=o||{},u(n,t,o),o}}(),n.obj.copy=function(t){return t?JSON.parse(JSON.stringify(t)):t},function(){function t(t,n){var o=this.n;if(!o||!(n===o||r(o)&&a(o,n)))return n?!0:void 0}n.obj.empty=function(n,o){return n&&u(n,t,{n:o})?!1:!0}}(),function(){function t(n,o){return 2===arguments.length?(t.r=t.r||{},void(t.r[n]=o)):(t.r=t.r||[],void t.r.push(n))}var i=Object.keys;n.obj.map=function(u,s,f){var c,l,p,d,h,v=0,g=o(s);if(t.r=null,i&&r(u)&&(d=i(u),h=!0),e(u)||d)for(l=(d||u).length;l>v;v++){var m=v+n.list.index;if(g){if(p=h?s.call(f||this,u[d[v]],d[v],t):s.call(f||this,u[v],m,t),p!==c)return p}else if(s===u[h?d[v]:v])return d?d[v]:m}else for(v in u)if(g){if(a(u,v)&&(p=f?s.call(f,u[v],v,t):s(u[v],v,t),p!==c))return p}else if(s===u[v])return v;return g?t.r:n.list.index?0:-1}}(),n.time={},n.time.is=function(t){return t?t instanceof Date:+(new Date).getTime()};var o=n.fn.is,e=n.list.is,i=n.obj,r=i.is,a=i.has,u=i.map;t.exports=n})(t,"./type"),t(function(t){t.exports=function n(t,o,e){if(!t)return{to:n};var i,t=(this.tag||(this.tag={}))[t]||(this.tag[t]={tag:t,to:n._={next:function(t){var n;(n=this.to)&&n.next(t)}}});if(o instanceof Function){var r={off:n.off||(n.off=function(){return this.next===n._.next?!0:(this===this.the.last&&(this.the.last=this.back),this.to.back=this.back,this.next=n._.next,this.back.to=this.to,void(this.the.last===this.the&&delete this.on.tag[this.the.tag]))}),to:n._,next:o,the:t,on:this,as:e};return(r.back=t.last||t).to=r,t.last=r}return(t=t.to)&&i!==o&&t.next(o),t}})(t,"./onto"),t(function(t){function n(t,n,e,i,r){if(n>t)return{defer:!0};if(e>n)return{historical:!0};if(n>e)return{converge:!0,incoming:!0};if(n===e){if(i=o(i)||"",r=o(r)||"",i===r)return{state:!0};if(r>i)return{converge:!0,current:!0};if(i>r)return{converge:!0,incoming:!0}}return{err:"Invalid CRDT Data: "+i+" to "+r+" at "+n+" to "+e+"!"}}if("undefined"==typeof JSON)throw new Error("JSON is not included in this browser. Please load it first: ajax.cdnjs.com/ajax/libs/json2/20110223/json2.js");var o=JSON.stringify;t.exports=n})(t,"./HAM"),t(function(n){var o=t("./type"),e={};e.is=function(t){return t===i?!1:null===t?!0:t===1/0?!1:s(t)||a(t)||u(t)?!0:e.rel.is(t)||!1},e.link=e.rel={_:"#"},function(){function t(t,n){var o=this;return o.id?o.id=!1:n==r&&s(t)?void(o.id=t):o.id=!1}e.rel.is=function(n){if(n&&n[r]&&!n._&&c(n)){var o={};if(p(n,t,o),o.id)return o.id}return!1}}(),e.rel.ify=function(t){return l({},r,t)},o.obj.has._=".";var i,r=e.link._,a=o.bi.is,u=o.num.is,s=o.text.is,f=o.obj,c=f.is,l=f.put,p=f.map;n.exports=e})(t,"./val"),t(function(n){var o=t("./type"),e=t("./val"),i={_:"_"};i.soul=function(t,n){return t&&t._&&t._[n||p]},i.soul.ify=function(t,n){return n="string"==typeof n?{soul:n}:n||{},t=t||{},t._=t._||{},t._[p]=n.soul||t._[p]||l(),t},i.soul._=e.link._,function(){function t(t,n){return n!==i._?e.is(t)?void(this.cb&&this.cb.call(this.as,t,n,this.n,this.s)):!0:void 0}i.is=function(n,o,e){var r;return u(n)&&(r=i.soul(n))?!f(n,t,{as:e,cb:o,s:r,n:n}):!1}}(),function(){function t(t,n){var o,i,r=this.o;return r.map?(o=r.map.call(this.as,t,""+n,r.node),void(i===o?s(r.node,n):r.node&&(r.node[n]=o))):void(e.is(t)&&(r.node[n]=t))}i.ify=function(n,o,e){return o?"string"==typeof o?o={soul:o}:o instanceof Function&&(o={map:o}):o={},o.map&&(o.node=o.map.call(e,n,r,o.node||{})),(o.node=i.soul.ify(o.node||{},o))&&f(n,t,{o:o,as:e}),o.node}}();var r,a=o.obj,u=a.is,s=a.del,f=a.map,c=o.text,l=c.random,p=i.soul._;n.exports=i})(t,"./node"),t(function(n){function o(){var t;return t=r(),t>a?(u=0,a=t+o.drift):a=t+(u+=1)/s+o.drift}{var e=t("./type"),i=t("./node"),r=e.time.is,a=-(1/0),u=0,s=1e3,f="undefined"!=typeof performance?performance.timing&&performance:!1;f&&f.timing&&f.timing.navigationStart||(f=!1)}o._=">",o.drift=0,o.is=function(t,n,e){var i=n&&t&&t[x]&&t[x][o._]||e;if(i)return b(i=i[n])?i:-(1/0)},o.lex=function(){return o().toString(36).replace(".","")},o.ify=function(t,n,e,r,a){if(!t||!t[x]){if(!a)return;t=i.soul.ify(t,a)}var u=p(t[x],o._);return c!==n&&n!==x&&(b(e)&&(u[n]=e),c!==r&&(t[n]=r)),t},o.to=function(t,n,e){var r=t[n];return h(r)&&(r=g(r)),o.ify(e,n,o.is(t,n),r,i.soul(t))},function(){function t(t,n){x!==n&&o.ify(this.o,n,this.s)}o.map=function(n,e,i){var r,a=h(a=n||e)?a:null;return n=y(n=n||e)?n:null,a&&!n?(e=b(e)?e:o(),a[x]=a[x]||{},v(a,t,{o:a,s:e}),a):(i=i||h(e)?e:r,e=b(e)?e:o(),function(o,a,u,s){return n?(n.call(i||this||{},o,a,u,s),void(d(u,a)&&r===u[a]||t.call({o:u,s:e},o,a))):(t.call({o:u,s:e},o,a),o)})}}();var c,l=e.obj,p=l.as,d=l.has,h=l.is,v=l.map,g=l.copy,m=e.num,b=m.is,k=e.fn,y=k.is,x=i._;n.exports=o})(t,"./state"),t(function(n){var o=t("./type"),e=t("./val"),i=t("./node"),r={};!function(){function t(t,o){return t&&o===i.soul(t)&&i.is(t,this.fn,this.as)?void(this.cb&&(n.n=t,n.as=this.as,this.cb.call(n.as,t,o,n))):!0}function n(t){t&&i.is(n.n,t,n.as)}r.is=function(n,o,e,i){return n&&s(n)&&!l(n)?!d(n,t,{cb:o,fn:e,as:i}):!1}}(),function(){function t(t,o){var r;return(r=p(t,o))?r:(o.env=t,o.soul=u,i.ify(o.obj,n,o)&&(o.rel=o.rel||e.rel.ify(i.soul(o.node)),o.obj!==t.shell&&(t.graph[e.rel.is(o.rel)]=o.node)),o)}function n(n,o,r){var u,s,p=this,d=p.env;if(i._===o&&c(n,e.rel._))return r._;if(u=l(n,o,r,p,d)){if(o||(p.node=p.node||r||{},c(n,i._)&&i.soul(n)&&(p.node._=h(n._)),p.node=i.soul.ify(p.node,e.rel.is(p.rel)),p.rel=p.rel||e.rel.ify(i.soul(p.node))),(s=d.map)&&(s.call(d.as||{},n,o,r,p),c(r,o))){if(n=r[o],a===n)return void f(r,o);if(!(u=l(n,o,r,p,d)))return}if(!o)return p.node;if(!0===u)return n;if(s=t(d,{obj:n,path:p.path.concat(o)}),s.node)return s.rel}}function u(t){var n=this,o=e.link.is(n.rel),r=n.env.graph;n.rel=n.rel||e.rel.ify(t),n.rel[e.rel._]=t,n.node&&n.node[i._]&&(n.node[i._][e.rel._]=t),c(r,o)&&(r[t]=r[o],f(r,o))}function l(t,n,i,r,a){var u;return e.is(t)?!0:s(t)?1:(u=a.invalid)?(t=u.call(a.as||{},t,n,i),l(t,n,i,r,a)):(a.err="Invalid value at '"+r.path.concat(n).join(".")+"'!",void(o.list.is(t)&&(a.err+=" Use `.set(item)` instead of an Array.")))}function p(t,n){for(var o,e=t.seen,i=e.length;i--;)if(o=e[i],n.obj===o.obj)return o;e.push(n)}r.ify=function(n,o,i){var r={path:[],obj:n};return o?"string"==typeof o?o={soul:o}:o instanceof Function&&(o.map=o):o={},o.soul&&(r.rel=e.rel.ify(o.soul)),o.shell=(i||{}).shell,o.graph=o.graph||{},o.seen=o.seen||[],o.as=o.as||i,t(o,r),o.root=r.node,o.graph}}(),r.node=function(t){var n=i.soul(t);if(n)return p({},n,t)},function(){function t(t,n){var o,a;if(i._===n){if(l(t,e.rel._))return;return void(this.obj[n]=h(t))}return(o=e.rel.is(t))?(a=this.opt.seen[o])?void(this.obj[n]=a):void(this.obj[n]=this.opt.seen[o]=r.to(this.graph,o,this.opt)):void(this.obj[n]=t)}r.to=function(n,o,e){if(n){var i={};return e=e||{seen:{}},d(n[o],t,{obj:i,graph:n,opt:e}),i}}}();var a,u=(o.fn.is,o.obj),s=u.is,f=u.del,c=u.has,l=u.empty,p=u.put,d=u.map,h=u.copy;n.exports=r})(t,"./graph"),t(function(n){t("./onto"),n.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}var 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}}})(t,"./ask"),t(function(n){function o(t){var n={s:{}};return t=t||{max:1e3,age:9e3},n.check=function(t){var o;return(o=n.s[t])?o.pass?o.pass=!1:n.track(t):!1},n.track=function(o,r){var a=n.s[o]||(n.s[o]={});return a.was=i(),r&&(a.pass=!0),n.to||(n.to=setTimeout(function(){var o=i();e.obj.map(n.s,function(i,r){i&&t.age>o-i.was||e.obj.del(n.s,r)}),n.to=null},t.age+9)),a},n}var e=t("./type"),i=e.time.is;n.exports=o})(t,"./dup"),t(function(n){function i(t){return t instanceof i?(this._={gun:this,$:this}).$:this instanceof i?i.create(this._={gun:this,$:this,opt:t}):new i(t)}i.is=function(t){return t instanceof i||t&&t._&&t===t._.$||!1},i.version=.9,i.chain=i.prototype,i.chain.toJSON=function(){};var r=t("./type");r.obj.to(r,i),i.HAM=t("./HAM"),i.val=t("./val"),i.node=t("./node"),i.state=t("./state"),i.graph=t("./graph"),i.on=t("./onto"),i.ask=t("./ask"),i.dup=t("./dup"),function(){function t(n){var o,e,r=this,u=r.as,s=u.at||u,f=s.$;return(e=n["#"])||(e=n["#"]=c(9)),(o=s.dup).check(e)?void(u.out===n.out&&(n.out=a,r.to.next(n))):(o.track(e),s.ask(n["@"],n)||(n.get&&i.on.get(n,f),n.put&&i.on.put(n,f)),r.to.next(n),void(u.out||(n.out=t,s.on("out",n))))}i.create=function(n){n.root=n.root||n,n.graph=n.graph||{},n.on=n.on||i.on,n.ask=n.ask||i.ask,n.dup=n.dup||i.dup();var o=n.$.opt(n.opt);return n.once||(n.on("in",t,n),n.on("out",t,{at:n,out:t}),i.on("create",n),n.on("create",n)),n.once=1,o}}(),function(){function t(t,n,o,e){var r=this,a=i.state.is(o,n);if(!a)return r.err="Error: No state on '"+n+"' in node '"+e+"'!";var u=r.graph[e]||k,s=i.state.is(u,n,!0),f=u[n],c=i.HAM(r.machine,a,s,t,f);return c.incoming?(r.put[e]=i.state.to(o,n,r.put[e]),(r.diff||(r.diff={}))[e]=i.state.to(o,n,r.diff[e]),void(r.souls[e]=!0)):void(c.defer&&(r.defer=a<(r.defer||1/0)?a:r.defer))}function n(t,n){var i=this,a=i.$._,u=(a.next||k)[n];if(!u){if(!(a.opt||k)["super"])return void(i.souls[n]=!1);u=i.$.get(n)._}var s=i.map[n]={put:t,get:n,$:u.$},f={ctx:i,msg:s};i.async=!!a.tag.node,i.ack&&(s["@"]=i.ack),v(t,o,f),i.async&&(i.and||a.on("node",function(t){this.to.next(t),t===i.map[t.get]&&(i.souls[t.get]=!1,v(t.put,e,t),v(i.souls,function(t){return t?t:void 0})||i.c||(i.c=1,this.off(),v(i.map,r,i)))}),i.and=!0,a.on("node",s))}function o(t,n){var o=this.ctx,e=o.graph,r=this.msg,a=r.get,u=r.put,s=r.$._;e[a]=i.state.to(u,n,e[a]),o.async||(s.put=i.state.to(u,n,s.put))}function e(t,n){var o=this,e=o.put,r=o.$._;r.put=i.state.to(e,n,r.put)}function r(t){t.$&&(this.cat.stop=this.stop,t.$._.on("in",t),this.cat.stop=null)}i.on.put=function(o,e){var u=e._,s={$:e,graph:u.graph,put:{},map:{},souls:{},machine:i.state(),ack:o["@"],cat:u,stop:{}};return i.graph.is(o.put,null,t,s)||(s.err="Error: Invalid graph!"),s.err?u.on("in",{"@":o["#"],err:i.log(s.err)}):(v(s.put,n,s),s.async||v(s.map,r,s),a!==s.defer&&setTimeout(function(){i.on.put(o,e)},s.defer-s.machine),void(s.diff&&u.on("put",h(o,{put:s.diff}))))},i.on.get=function(t,n){var o,e=n._,r=t.get,a=r[m],u=e.graph[a],s=r[b],f=e.next||(e.next={}),c=f[a];if(d(a,"*")){var l={};i.obj.map(e.graph,function(t,n){i.text.match(n,a)&&(l[n]=i.obj.copy(t))}),i.obj.empty(l)||e.on("in",{"@":t["#"],how:"*",put:l,$:n})}if(!u)return e.on("get",t);if(s){if(!d(u,s))return e.on("get",t);u=i.state.to(u,s)}else u=i.obj.copy(u);u=i.graph.node(u),o=(c||k).ack,e.on("in",{"@":t["#"],how:"mem",put:u,$:n}),e.on("get",t)}}(),function(){i.chain.opt=function(t){t=t||{};var n=this,o=n._,e=t.peers||t;return p(t)||(t={}),p(o.opt)||(o.opt=t),f(e)&&(e=[e]),u(e)&&(e=v(e,function(t,n,o){o(t,{url:t})}),p(o.opt.peers)||(o.opt.peers={}),o.opt.peers=h(e,o.opt.peers)),o.opt.peers=o.opt.peers||{},h(t,o.opt),i.on("opt",o),o.opt.uuid=o.opt.uuid||function(){return g()+c(12)},n}}();var a,u=i.list.is,s=i.text,f=s.is,c=s.random,l=i.obj,p=l.is,d=l.has,h=l.to,v=l.map,g=(l.copy,i.state.lex),m=i.val.rel._,b=".",k=(i.node._,i.val.link.is,{});o.debug=function(t,n){return o.debug.i&&t===o.debug.i&&o.debug.i++&&(o.log.apply(o,arguments)||n)},i.log=function(){return!i.log.off&&o.log.apply(o,arguments),[].slice.call(arguments).join(" ")},i.log.once=function(t,n,o){return(o=i.log.once)[t]=o[t]||0,o[t]++||i.log(n)},i.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=i).window=window);try{"undefined"!=typeof e&&(e.exports=i)}catch(y){}n.exports=i})(t,"./root"),t(function(){var n=t("./root");n.chain.back=function(t,i){var r;if(t=t||1,-1===t||1/0===t)return this._.root.$;if(1===t)return(this._.back||this._).$;var a=this,u=a._;if("string"==typeof t&&(t=t.split(".")),!(t instanceof Array)){if(t instanceof Function){for(var s,r={back:u};(r=r.back)&&o===(s=t(r,i)););return s}return n.num.is(t)?(u.back||u).$.back(t-1):this}var f=0,c=t.length,r=u;for(f;c>f;f++)r=(r||e)[t[f]];return o!==r?i?a:r:(r=u.back)?r.$.back(t,i):void 0};var o,e={}})(t,"./back"),t(function(){function n(t){var n,o,e,i=this.as,r=i.back,a=i.root;if(t.I||(t.I=i.$),t.$||(t.$=i.$),this.to.next(t),o=t.get){if(o["#"]||i.soul){if(o["#"]=o["#"]||i.soul,t["#"]||(t["#"]=b(9)),r=a.$.get(o["#"])._,o=o["."]){if(h(r.put,o)&&(n=r.$.get(o)._,(e=n.ack)||(n.ack=-1),r.on("in",{$:r.$,put:c.state.to(r.put,o),get:r.get}),e))return}else{if(e=r.ack,e||(r.ack=-1),h(r,"put")&&r.on("in",r),e)return;t.$=r.$}return a.ask(f,t),a.on("in",t)}if(a.now&&(a.now[i.id]=a.now[i.id]||!0,i.pass={}),o["."])return i.get?(t={get:{".":i.get},$:i.$},r.ask||(r.ask={}),r.ask[i.get]=t.$._,r.on("out",t)):(t={get:{},$:i.$},r.on("out",t));if(i.ack=i.ack||-1,i.get)return t.$=i.$,o["."]=i.get,(r.ask||(r.ask={}))[i.get]=t.$._,r.on("out",t)}return r.on("out",t)}function o(t){var n,o,r=this,s=r.as,f=s.root,d=t.$,b=(d||p)._||p,k=t.put;if(s.get&&t.get!==s.get&&(t=g(t,{get:s.get})),s.has&&b!==s&&(t=g(t,{$:s.$}),b.ack&&(s.ack=b.ack)),l===k){if(o=b.put,r.to.next(t),s.soul)return;if(l===o&&l!==b.put)return;return i(s,t,r),s.has&&u(s,t),v(b.echo,s.id),void v(s.map,b.id)}if(s.soul)return r.to.next(t),i(s,t,r),void(s.next&&m(k,a,{msg:t,cat:s}));if(!(n=c.val.link.is(k)))return c.val.is(k)?(s.has||s.soul?u(s,t):(b.has||b.soul)&&((b.echo||(b.echo={}))[s.id]=b.echo[b.id]||s,(s.map||(s.map={}))[b.id]=s.map[b.id]||{at:b}),r.to.next(t),void i(s,t,r)):(s.has&&b!==s&&h(b,"put")&&(s.put=b.put),(n=c.node.soul(k))&&b.has&&(b.put=s.root.$.get(n)._.put),o=(f.stop||{})[b.id],r.to.next(t),e(s,t,b,n),i(s,t,r),void(s.next&&m(k,a,{msg:t,cat:s})));f.stop;o=f.stop||{},o=o[b.id]||(o[b.id]={}),o.is=o.is||b.put,o[s.id]=b.put||!0,r.to.next(t),e(s,t,b,n),i(s,t,r)}function e(t,n,o,i){if(i&&k!==t.get){var r=t.root.$.get(i)._;t.has?o=r:o.has&&e(o,n,o,i),o!==t&&(o.$||(o={}),(o.echo||(o.echo={}))[t.id]=o.echo[t.id]||t,t.has&&!(t.map||p)[o.id]&&u(t,n),r=o.id?(t.map||(t.map={}))[o.id]=t.map[o.id]||{at:o}:{},(i!==r.link||r.pass||t.pass)&&(t.pass&&(c.obj.map(t.map,function(t){t.pass=!0}),v(t,"pass")),r.pass&&v(r,"pass"),t.has&&(t.link=i),s(t,r.link=i)))}}function i(t,n){t.echo&&m(t.echo,r,n)}function r(t){t&&t.on&&t.on("in",this)}function a(t,n){var o,e,i,r=this.cat,a=r.next||p,u=this.msg;(k!==n||a[n])&&(e=a[n])&&(e.has?(l!==e.put&&c.val.link.is(t)||(e.put=t),o=e.$):(i=u.$)&&(i=(o=u.$.get(n))._,l!==i.put&&c.val.link.is(t)||(i.put=t)),e.on("in",{put:t,get:n,$:o,via:u}))}function u(t,n){if(t.has||t.soul){{var o=t.map;t.root}t.map=null,t.has&&(t.link=null),(t.pass||n["@"]||null!==o)&&(l===o&&c.val.link.is(t.put)||(m(o,function(n){(n=n.at)&&v(n.echo,t.id)}),o=t.put,m(t.next,function(n,e){return l===o&&l!==t.put?!0:(n.put=l,n.ack&&(n.ack=-1),void n.on("in",{get:e,$:n.$,put:l}))})))}}function s(t,n){var o=t.root.$.get(n)._;(!t.ack||(o.on("out",{get:{"#":n}}),t.ask))&&(o=t.ask,c.obj.del(t,"ask"),m(o||t.next,function(t,o){t.on("out",{get:{"#":n,".":o}})}),c.obj.del(t,"ask"))}function f(t){var n=this.as,o=n.get||p,e=n.$._,i=(t.put||p)[o["#"]];if(e.ack&&(e.ack=e.ack+1||1),!t.put||o["."]&&!h(i,e.get)){if(e.put!==l)return;return void e.on("in",{get:e.get,put:e.put=l,$:e.$,"@":t["@"]})}return k==o["."]?void e.on("in",{get:e.get,put:c.val.link.ify(o["#"]),$:e.$,"@":t["@"]}):(t.$=e.root.$,void c.on.put(t,e.root.$))}var c=t("./root");c.chain.chain=function(t){var e,i=this,r=i._,a=new(t||i).constructor(i),u=a._;return u.root=e=r.root,u.id=++e.once,u.back=i._,u.on=c.on,u.on("in",o,u),u.on("out",n,u),a};var l,p={},d=c.obj,h=d.has,v=(d.put,d.del),g=d.to,m=d.map,b=c.text.random,k=(c.val.rel._,c.node._)})(t,"./chain"),t(function(){function n(t,n){var o=n._,e=o.next,i=n.chain(),r=i._;return e||(e=o.next={}),e[r.get=t]=r,n===o.root.$?r.soul=t:(o.soul||o.has)&&(r.has=t),r}function o(t,n,o,e){var i,r=t._;return(i=r.soul)?(n(i,e,r),t):(i=r.link)?(n(i,e,r),t):(t.get(function(t,o){o.rid(t);var r=(r=t.$)&&r._||{};i=r.link||r.soul||c.is(t.put)||l(t.put),n(i,e,t,o)},{out:{get:{".":!0}}}),t)}function e(t){var n,o=this,e=o.as,i=e.at,r=i.root,u=t.$,f=(u||{})._||{},l=t.put||f.put;if((n=r.now)&&o!==n[e.now])return o.to.next(t);if(o.seen&&f.id&&o.seen[f.id])return o.to.next(t);if((n=l)&&n[c._]&&(n=c.is(n))&&(n=(t.$$=f.root.gun.get(n))._,a!==n.put&&(t=s(t,{put:l=n.put}))),(n=r.mum)&&f.id){if(n[f.id])return;a===l||c.is(l)||(n[f.id]=!0)}return e.use(t,o),o.stun?void(o.stun=null):void o.to.next(t)}function i(t){var n=this.on;if(!t||n.soul||n.has)return this.off();if(t=(t=(t=t.$||t)._||t).id){{var o,e;n.map}return(o=(e=this.seen||(this.seen={}))[t])?!0:void(e[t]=!0)}}var r=t("./root");r.chain.get=function(t,a,u){var s,l;if("string"!=typeof t){if(t instanceof Function){if(!0===a)return o(this,t,a,u);s=this;var d,h=s._,v=h.root,l=v.now;u=a||{},u.at=h,u.use=t,u.out=u.out||{},u.out.get=u.out.get||{},(d=h.on("in",e,u)).rid=i,(v.now={$:1})[u.now=h.id]=d;var g=v.mum;return v.mum={},h.on("out",u.out),v.mum=g,v.now=l,s}return f(t)?this.get(""+t,a,u):(l=c.is(t))?this.get(l,a,u):((u=this.chain())._.err={err:r.log("Invalid get request!",t)},a&&a.call(u,u._.err),u)}var m=this,b=m._,k=b.next||p;return(s=k[t])||(s=n(t,m)),s=s.$,(l=b.stun)&&(s._.stun=s._.stun||l),a&&a instanceof Function&&s.get(a,u),s};var a,u=r.obj,s=(u.has,r.obj.to),f=r.num.is,c=r.val.link,l=r.node.soul,p=(r.node._,{})})(t,"./get"),t(function(){function n(t){t.batch=i;var n=t.opt||{},o=t.env=c.state.map(a,n.state);return o.soul=t.soul,t.graph=c.graph.ify(t.data,o,t),o.err?((t.ack||m).call(t,t.out={err:c.log(o.err)}),void(t.res&&t.res())):void t.batch()}function e(t){return void(t&&t())}function i(){var t=this;t.graph&&!v(t.stun,r)&&(t.res=t.res||function(t){t&&t()},t.res(function(){var n=t.$.back(-1)._,o=n.ask(function(o){n.root.on("ack",o),o.err&&c.log(o),o.lack||this.off(),t.ack&&t.ack(o,this)},t.opt),e=n.root.now;p.del(n.root,"now");var i=n.root.mum;n.root.mum={},t.ref._.on("out",{$:t.ref,put:t.out=t.env.graph,opt:t.opt,"#":o}),n.root.mum=i?p.to(i,n.root.mum):i,n.root.now=e},t),t.res&&t.res())}function r(t){return t?!0:void 0}function a(t,n,o,e){var i=this,r=c.is(t);!n&&e.path.length&&(i.res||b)(function(){var n=e.path,o=i.ref,a=(i.opt,0),s=n.length;for(a;s>a;a++)o=o.get(n[a]);r&&(o=t);var f=o._.dub;return f||(f=c.node.soul(e.obj))?(o.back(-1).get(f),void e.soul(f)):((i.stun=i.stun||{})[n]=!0,void o.get(u,!0,{as:{at:e,as:i,p:n}}))},{as:i,at:e})}function u(t,n,o,e){var n=n.as,i=n.at;n=n.as;var r=((o||{}).$||{})._||{};return t=r.dub=r.dub||t||c.node.soul(i.obj)||c.node.soul(o.put||r.put)||c.val.rel.is(o.put||r.put)||(n.via.back("opt.uuid")||c.text.random)(),e&&(e.stun=!0),t?void s(r,r.dub=t,i,n):void r.via.back("opt.uuid")(function(t,o){return t?c.log(t):void s(r,r.dub=r.dub||o,i,n)})}function s(t,n,o,e){t.$.back(-1).get(n),o.soul(n),e.stun[o.path]=!1,e.batch()}function f(t,n,e,i){if(n=n.as,e.$&&e.$._){if(e.err)return void o.log("Please report this as an issue! Put.any.err");var r,a=e.$._,u=a.put,s=n.opt||{};if(!(r=n.ref)||!r._.now){if(i&&(i.stun=!0),n.ref!==n.$){if(r=n.$._.get||a.get,!r)return void o.log("Please report this as an issue! Put.no.get");n.data=h({},r,n.data),r=null}if(l===u){if(!a.get)return;t||(r=a.$.back(function(t){return t.link||t.soul?t.link||t.soul:void(n.data=h({},t.get,n.data))})),r=r||a.get,a=a.root.$.get(r)._,n.soul=r,u=n.data}return n.not||(n.soul=n.soul||t)||(n.path&&d(n.data)?n.soul=(s.uuid||n.via.back("opt.uuid")||c.text.random)():(k==a.get&&(n.soul=(a.put||g)["#"]||a.dub),n.soul=n.soul||a.soul||a.soul||(s.uuid||n.via.back("opt.uuid")||c.text.random)()),n.soul)?void n.ref.put(n.data,n.soul,n):void n.via.back("opt.uuid")(function(t,o){return t?c.log(t):void n.ref.put(n.data,n.soul=o,n)})}}}var c=t("./root");c.chain.put=function(t,o,i){var r,a=this,u=a._,s=u.root.$;return i=i||{},i.data=t,i.via=i.$=i.via||i.$||a,"string"==typeof o?i.soul=o:i.ack=i.ack||o,u.soul&&(i.soul=u.soul),i.soul||s===a?d(i.data)?(i.soul=i.soul||(i.not=c.node.soul(i.data)||(i.via.back("opt.uuid")||c.text.random)()),i.soul?(i.$=a=s.get(i.soul),i.ref=i.$,n(i),a):(i.via.back("opt.uuid")(function(t,n){return t?c.log(t):void(i.ref||i.$).put(i.data,i.soul=n,i)}),a)):((i.ack||m).call(i,i.out={err:c.log("Data saved to the root level of the graph must be a node (an object), not a",typeof i.data,'of "'+i.data+'"!')}),i.res&&i.res(),a):c.is(t)?(t.get(function(t,n,e){return!t&&c.val.is(e.put)?c.log("The reference you are saving is a",typeof e.put,'"'+e.put+'", not a node (object)!'):void a.put(c.val.rel.ify(t),o,i)},!0),a):(i.ref=i.ref||s._===(r=u.back)?a:r.$,i.ref._.soul&&c.val.is(i.data)&&u.get?(i.data=h({},u.get,i.data),i.ref.put(i.data,i.soul,i),a):(i.ref.get(f,!0,{as:i}),i.out||(i.res=i.res||e,i.$._.stun=i.ref._.stun),a))};var l,p=c.obj,d=p.is,h=p.put,v=p.map,g={},m=function(){},b=function(t,n){t.call(n||g)},k=c.node._})(t,"./put"),t(function(n){var o=t("./root");t("./chain"),t("./back"),t("./put"),t("./get"),n.exports=o})(t,"./index"),t(function(){function n(t,n){{var o,e=this,r=t.$,a=(r||{})._||{},u=a.put||t.put;e.at}if(i!==u){if(o=t.$$){if(o=t.$$._,i===o.put)return;u=o.put}e.change&&(u=t.put),e.as?e.ok.call(e.as,t,n):e.ok.call(r,u,t.get,t,n)}}function o(t,n,r){var u,f,c=this.as,l=(c.at,t.$),p=l._,d=p.put||t.put;return(f=t.$$)&&(u=f=t.$$._,i!==u.put&&(d=u.put)),(f=n.wait)&&(f=f[p.id])&&clearTimeout(f),!r&&(i===d||p.soul||p.link||u&&!(0 .once, apologies unexpected."),this.once(t,n)},e.chain.once=function(t,n){var r=this,a=r._,u=a.put;if(0=(o.batch||1e3)?s():void(e||(e=setTimeout(s,o.wait||1)))}),n.on("get",function(t){function e(){if(s&&(i=s["#"])){var e=s["."];r=a[i]||u,r&&e&&(r=Gun.state.to(r,e)),(r||Gun.obj.empty(o.peers))&&n.on("in",{"@":t["#"],put:Gun.graph.node(r),how:"lS",lS:t.I})}}this.to.next(t);var i,r,u,s=t.get;Gun.debug?setTimeout(e,1):e()});var u=function(t,n,o,e){a[e]=Gun.state.to(o,n,a[e])},s=function(u){var f;r=0,clearTimeout(e),e=!1;var c=i;i={},u&&(a=u);try{t.setItem(o.prefix,JSON.stringify(a))}catch(l){Gun.log(f=(l||"localStorage failure")+" Consider using GUN's IndexedDB plugin for RAD for more storage space, temporary example at https://github.com/amark/gun/blob/master/test/tmp/indexedDB.html ."),n.on("localStorage:error",{err:f,file:o.prefix,flush:a,retry:s})}(f||Gun.obj.empty(o.peers))&&Gun.obj.map(c,function(t,o){n.on("in",{"@":o,err:f,ok:0})})}}})}})(t,"./adapters/localStorage"),t(function(n){function e(t){var n=function(){},u=t.opt||{};return u.log=u.log||o.log,u.gap=u.gap||u.wait||1,u.pack=u.pack||.3*(u.memory?1e3*u.memory*1e3:1399e6),n.out=function(o){var e;return this.to&&this.to.next(o),(e=o["@"])&&(e=t.dup.s[e])&&(e=e.it)&&e.mesh?(n.say(o,e.mesh.via,1),void(e["##"]=o["##"])):void n.say(o)},t.on("create",function(o){o.opt.pid=o.opt.pid||i.text.random(9),this.to.next(o),t.on("out",n.out)}),n.hear=function(o,e){if(o){var r,a,s,f=t.dup,c=o[0];if(u.pack<=o.length)return n.say({dam:"!",err:"Message too big!"},e);try{s=JSON.parse(o)}catch(l){u.log("DAM JSON parse error",l)}if("{"===c){if(!s)return;if(f.check(r=s["#"]))return;if(f.track(r,!0).it=s,(c=s["@"])&&s.put&&(a=s["##"]||(s["##"]=n.hash(s)),(c+=a)!=r)){if(f.check(c))return;(c=f.s)[a]=c[r]}return(s.mesh=function(){}).via=e,(c=s["><"])&&(s.mesh.to=i.obj.map(c.split(","),function(t,n,o){o(t,!0)})),s.dam?void((c=n.hear[s.dam])&&c(s,e,t)):void t.on("in",s)}if("["!==c);else{if(!s)return;for(var p,d=0;p=s[d++];)n.hear(p,e)}}},function(){function o(t){var n=t.batch;if(n&&(t.batch=t.tail=null,n.length))try{e(JSON.stringify(n),t)}catch(o){u.log("DAM JSON stringify error",o)}}function e(t,n){var o=n.wire;try{o.send?o.send(t):n.say&&n.say(t)}catch(e){(n.queue=n.queue||[]).push(t)}}n.say=function(r,s,f){if(!s)return void i.obj.map(u.peers,function(t){n.say(r,t)});var c,l,p,d=s.wire||u.wire&&u.wire(s);if(d&&(l=r.mesh||a,s!==l.via&&((p=l.raw)||(p=n.raw(r)),!((c=r["@"])&&(c=t.dup.s[c])&&(c=c.it)&&c.get&&c["##"]&&c["##"]===r["##"]||(c=l.to)&&(c[s.url]||c[s.id])&&!f)))){if(s.batch){if(s.tail=(s.tail||0)+p.length,s.tail<=u.pack)return void s.batch.push(p);o(s)}s.batch=[],setTimeout(function(){o(s)},u.gap),e(p,s)}}}(),function(){function o(t,n){var o;return n instanceof Object?(i.obj.map(Object.keys(n).sort(),a,{to:o={},on:n}),o):n}function a(t){this.to[t]=this.on[t]}n.raw=function(e){if(!e)return"";var a,c,l,p=t.dup,d=e.mesh||{};if(l=d.raw)return l;if("string"==typeof e)return e;e["@"]&&(l=e.put)&&((c=e["##"])||(a=s(l,o)||"",c=n.hash(e,a),e["##"]=c),(l=p.s)[c=e["@"]+c]=l[e["#"]],e["#"]=c||e["#"],a&&((e=i.obj.to(e)).put=f));var h=0,v=[];i.obj.map(u.peers,function(t){return v.push(t.url||t.id),++h>9?!0:void 0}),e["><"]=v.join();var g=s(e);return r!==a&&(l=g.indexOf(f,g.indexOf("put")),g=g.slice(0,l-1)+a+g.slice(l+f.length+1)),d&&(d.raw=g),g},n.hash=function(t,n){return e.hash(n||s(t.put,o)||"")||t["#"]||i.text.random(9)};var s=JSON.stringify,f=":])([:"}(),n.hi=function(o){var e=o.wire||{};o.id||o.url?(u.peers[o.url||o.id]=o,i.obj.del(u.peers,e.id)):(e=e.id=e.id||i.text.random(9),n.say({dam:"?"},u.peers[e]=o)),e.hied||t.on(e.hied="hi",o),e=o.queue,o.queue=[],i.obj.map(e,function(t){n.say(t,o)})},n.bye=function(n){i.obj.del(u.peers,n.id),t.on("bye",n)},n.hear["!"]=function(t){u.log("Error:",t.err)},n.hear["?"]=function(t,o){return t.pid?(o.id=o.id||t.pid,void n.hi(o)):n.say({dam:"?",pid:u.pid,"@":t["#"]},o)},n}var i=t("../type");e.hash=function(t){ +if("string"!=typeof t)return{err:1};var n=0;if(!t.length)return n;for(var o,e=0,i=t.length;i>e;++e)o=t.charCodeAt(e),n=(n<<5)-n+o,n|=0;return n};var r,a={};Object.keys=Object.keys||function(t){return map(t,function(t,n,o){o(n)})};try{n.exports=e}catch(u){}})(t,"./adapters/mesh"),t(function(){var n=t("../index");n.Mesh=t("./mesh"),n.on("opt",function(t){function o(t){try{if(!t||!t.url)return o&&o(t);var n=t.url.replace("http","ws"),o=t.wire=new i.WebSocket(n);return o.onclose=function(){i.mesh.bye(t),e(t)},o.onerror=function(n){e(t),n&&"ECONNREFUSED"===n.code},o.onopen=function(){i.mesh.hi(t)},o.onmessage=function(n){n&&i.mesh.hear(n.data||n,t)},o}catch(r){}}function e(t){clearTimeout(t.defer),t.defer=setTimeout(function(){o(t)},2e3)}this.to.next(t);var i=t.opt;if(!t.once&&!1!==i.WebSocket){var r;"undefined"!=typeof window&&(r=window),"undefined"!=typeof global&&(r=global),r=r||{};var a=i.WebSocket||r.WebSocket||r.webkitWebSocket||r.mozWebSocket;if(a){i.WebSocket=a;{i.mesh=i.mesh||n.Mesh(t),i.wire}i.wire=o}}})})(t,"./adapters/websocket")}(); \ No newline at end of file diff --git a/lib/normalize.js b/lib/normalize.js new file mode 100644 index 00000000..901f1671 --- /dev/null +++ b/lib/normalize.js @@ -0,0 +1,139 @@ +;(function(){ + function normalize(opt){ + var el = $(this); + opt = opt || $.extend(true, normalize.opt, opt||{}); + el.children().each(function(){ + var a = {$: $(this), opt: opt}; + a.tag = normalize.tag(a.$); + $(a.opt.mutate).each(function(i,fn){ + fn && fn(a); + }); + }) + }; + var n = normalize, u; + n.get = function(o, p){ + p = p.split('.'); + var i = 0, l = p.length, u; + while((o = o[p[i++]]) != null && i < l){}; + return i < l ? u : o; + } + n.has = function(o,p){ + return Object.prototype.hasOwnProperty.call(o, p); + } + n.tag = function(e){ + return (($(e)[0]||{}).nodeName||'').toLowerCase(); + } + n.attrs = function(e, cb){ + var attr = {}; + (e = $(e)) && e.length && $(e[0].attributes||[]).each(function(v,n){ + n = n.nodeName||n.name; + v = e.attr(n); + v = cb? cb(v,n,e) : v; + if(v !== u && v !== false){ attr[n] = v } + }); + return attr; + } + n.joint = function(e, d){ + d = (d? 'next' : 'previous') + 'Sibling' + return $(($(e)[0]||{})[d]); + } + var h = { + attr: function(a$, av, al){ + var l = function(i,v){ + var t = v; + i = al? v : i; + v = al? av[v.toLowerCase()] : t; + a$.attr(i, v); + } + al? $(al.sort()).each(l) : $.each(av,l); + } + } + n.opt = { // some reasonable defaults, limited to content alone. + tags: { + 'a': {attrs:{'src':1}, exclude:{'a':1}}, + 'b': {exclude:{'b':1}}, + //'blockquote':1, + 'br': {empty: 1}, + 'div': 1, + //'code':1, + 'i': {exclude:{'i':1}}, + 'img': {attrs:{'src':1}, empty: 1}, + 'li':1, 'ol':1, + 'p': {exclude:{'p':1,'div':1}}, + //'pre':1, + 's': {exclude:{'s':1}}, + 'sub':1, 'sup':1, + 'span': {exclude:{'p':1,'ul':1,'ol':1,'li':1,'br':1}}, + 'u': {exclude:{'u':1,'p':1}}, + 'ul':1 + } + // a, audio, b, br, div, i, img, li, ol, p, s, span, sub, sup, u, ul, video + // button, canvas, embed, form, iframe, input, style, svg, table, + // Text: bold, italics, underline, align, bullet, list, + ,convert: { + 'em': 'i', 'strong': 'b' + } + ,attrs: { + 'id':1 + ,'class':1 + ,'style':1 + } + ,mutate: [ + function(a){ // attr + a.attrs = []; + a.attr = $.extend(a.opt.attrs, n.get(a.opt,'tags.'+ a.tag +'attrs')); + a.attr = n.attrs(a.$, function(v,i){ + a.$.removeAttr(i); + if(a.attr[i.toLowerCase()]){ + a.attrs.push(i) + return v; + } + }); + // if this tag is gonna get converted, wait to add attr back till after the convert + if(a.attrs && !n.get(a.opt, 'convert.' + a.tag)){ + h.attr(a.$, a.attr, a.attrs); + } + } + ,function(a, tmp){ // convert + if(!(tmp = n.get(a.opt,'convert.' + a.tag))){ return } + a.attr = a.attr || n.attrs(a.$); + a.$.replaceWith(a.$ = $('<'+ (a.tag = t.toLowerCase()) +'>').append(a.$.contents())); + h.attr(a.$, a.attr, a.attrs); + } + ,function(a, tmp){ // lookahead + if((tmp = n.joint(a.$,1)) && (t = t.contents()).length === 1 && a.tag === n.tag(t = t.first())){ + a.$.append(t.parent()); // no need to unwrap the child, since the recursion will do it for us + } + } + ,function(a){ // recurse + // this needs to precede the exclusion and empty. + normalize(a); + } + ,function(a){ // exclude + var t; + if(!n.get(a.opt,'tags.' + a.tag) + || ((t = n.get(a.opt,'tags.'+ a.tag +'.exclude')) + && a.$.parents($.map(t,function(i,v){return v})+' ').length) + ){ + a.$.replaceWith(a.$.contents()); + } + } + ,function(a){ // prior + var t; + if((t = n.joint(a.$)).length && a.tag === n.tag(t)){ + t.append(a.$.contents()); + } + } + ,function(a){ // empty + // should always go last, since the element will be removed! + if(a.opt.empty || !n.has(a.opt,'empty')){ + if(!n.get(a.opt,'tags.'+ a.tag +'.empty') + && !a.$.contents().length){ + a.$.remove(); + } + } + } + ] + } + $.fn.normalize = normalize; +}()); \ No newline at end of file diff --git a/lib/reboot.js b/lib/reboot.js new file mode 100644 index 00000000..9a2ba612 --- /dev/null +++ b/lib/reboot.js @@ -0,0 +1,19 @@ +;(function(){ + var exec = require('child_process').execSync; + var dir = __dirname, tmp; + + try{exec("crontab -l"); + }catch(e){tmp = e} + if(0 > tmp.toString().indexOf('no')){ return } + + try{tmp = exec('which node').toString(); + }catch(e){console.log(e);return} + + try{tmp = exec('echo "@reboot '+tmp+' '+dir+'/../examples/http.js" > '+dir+'/reboot.cron'); + }catch(e){console.log(e);return} + + try{tmp = exec('crontab '+dir+'/reboot.cron'); + }catch(e){console.log(e);return} + console.log(tmp.toString()); + +}()); \ No newline at end of file diff --git a/lib/server.js b/lib/server.js index a893322e..0c698be1 100644 --- a/lib/server.js +++ b/lib/server.js @@ -3,15 +3,16 @@ Gun.serve = require('./serve'); //process.env.GUN_ENV = process.env.GUN_ENV || 'debug'; Gun.on('opt', function(root){ + if(u === root.opt.super){ + root.opt.super = true; + } this.to.next(root); - if(root.once){ return } - if(u !== root.opt.super){ return } - root.opt.super = true; }) require('../nts'); require('./store'); require('./rs3'); require('./wire'); + //try{require('../axe');}catch(e){} require('./file'); require('./evict'); if('debug' === process.env.GUN_ENV){ require('./debug') } diff --git a/package.json b/package.json index 47c7d85f..a8f8ebfa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gun", - "version": "0.9.99997", + "version": "0.9.99998", "description": "A realtime, decentralized, offline-first, graph data synchronization engine.", "main": "index.js", "browser": "gun.min.js", diff --git a/sea.js b/sea.js index 7c08fc81..ca47037a 100644 --- a/sea.js +++ b/sea.js @@ -27,15 +27,9 @@ if(typeof window !== "undefined"){ module.window = window } var tmp = module.window || module; - var SEA = tmp.SEA || function(){}; + var SEA = tmp.SEA || {}; - if(SEA.window = module.window){ try{ - SEA.window.SEA = SEA; - tmp = document.createEvent('CustomEvent'); - tmp.initCustomEvent('extension', false, false, {type: "SEA"}); - (window.dispatchEvent || window.fireEvent)(tmp); - window.postMessage({type: "SEA"}, '*'); - } catch(e){} } + if(SEA.window = module.window){ SEA.window.SEA = SEA } try{ if(typeof common !== "undefined"){ common.exports = SEA } }catch(e){} module.exports = SEA; @@ -320,8 +314,18 @@ var S = USE('./settings'); var Buff = (typeof Buffer !== 'undefined')? Buffer : shim.Buffer; + SEA.name = SEA.name || (async (cb, opt) => { try { + if(cb){ try{ cb() }catch(e){console.log(e)} } + return; + } catch(e) { + console.log(e); + SEA.err = e; + if(cb){ cb() } + return; + }}); + //SEA.pair = async (data, proof, cb) => { try { - SEA.pair = SEA.pair || (async (cb) => { try { + SEA.pair = SEA.pair || (async (cb, opt) => { try { const ecdhSubtle = shim.ossl || shim.subtle // First: ECDSA keys for signing/verifying... @@ -383,7 +387,7 @@ var S = USE('./settings'); var sha256hash = USE('./sha256'); - SEA.sign = SEA.sign || (async (data, pair, cb) => { try { + SEA.sign = SEA.sign || (async (data, pair, cb, opt) => { try { if(data && data.slice && 'SEA{' === data.slice(0,4) && '"m":' === data.slice(4,8)){ @@ -393,6 +397,10 @@ if(cb){ try{ cb(data) }catch(e){console.log(e)} } return data; } + opt = opt || {}; + if(!(pair||opt).priv){ + pair = await SEA.I(null, {what: data, how: 'sign', why: opt.why}); + } const pub = pair.pub const priv = pair.priv const jwk = S.jwk(pub, priv) @@ -422,7 +430,7 @@ var parse = USE('./parse'); var u; - SEA.verify = SEA.verify || (async (data, pair, cb) => { try { + SEA.verify = SEA.verify || (async (data, pair, cb, opt) => { try { const json = parse(data) if(false === pair){ // don't verify! const raw = (json !== data)? @@ -431,6 +439,8 @@ if(cb){ try{ cb(raw) }catch(e){console.log(e)} } return raw; } + opt = opt || {}; + // SEA.I // verify is free! Requires no user permission. if(json === data){ throw "No signature on data." } const pub = pair.pub || pair const jwk = S.jwk(pub) @@ -474,8 +484,12 @@ var aeskey = USE('./aeskey'); SEA.encrypt = SEA.encrypt || (async (data, pair, cb, opt) => { try { - var opt = opt || {}; - const key = pair.epriv || pair; + opt = opt || {}; + var key = (pair||opt).epriv || pair; + if(!key){ + pair = await SEA.I(null, {what: data, how: 'encrypt', why: opt.why}); + key = pair.epriv || pair; + } const msg = JSON.stringify(data) const rand = {s: shim.random(8), iv: shim.random(16)}; const ct = await aeskey(key, rand.s, opt) @@ -507,8 +521,12 @@ var parse = USE('./parse'); SEA.decrypt = SEA.decrypt || (async (data, pair, cb, opt) => { try { - var opt = opt || {}; - const key = pair.epriv || pair; + opt = opt || {}; + var key = (pair||opt).epriv || pair; + if(!key){ + pair = await SEA.I(null, {what: data, how: 'decrypt', why: opt.why}); + key = pair.epriv || pair; + } const json = parse(data) const ct = await aeskey(key, shim.Buffer.from(json.s, 'utf8'), opt) .then((aes) => (/*shim.ossl ||*/ shim.subtle).decrypt({ // Keeping aesKey scope as private as possible... @@ -530,8 +548,12 @@ var SEA = USE('./root'); var shim = USE('./shim'); var S = USE('./settings'); - // Derive shared secret from other's pub and my epub/epriv - SEA.secret = SEA.secret || (async (key, pair, cb) => { try { + // Derive shared secret from other's pub and my epub/epriv + SEA.secret = SEA.secret || (async (key, pair, cb, opt) => { try { + opt = opt || {}; + if(!pair || !pair.epriv || !pair.epub){ + pair = await SEA.I(null, {what: key, how: 'secret', why: opt.why}); + } const pub = key.epub || key const epub = pair.epub const epriv = pair.epriv @@ -576,6 +598,7 @@ ;USE(function(module){ // Old Code... + try{ const __gky10 = USE('./shim') const crypto = __gky10.crypto const subtle = __gky10.subtle @@ -594,8 +617,8 @@ const keysToEcdsaJwk = __gky11.jwk const sha1hash = USE('./sha1') const sha256hash = USE('./sha256') - const recallCryptoKey = USE('./remember') const parseProps = USE('./parse') + }catch(e){} // Practical examples about usage found from ./test/common.js const SEA = USE('./root'); @@ -609,7 +632,7 @@ // This is easy way to use IndexedDB, all methods are Promises // Note: Not all SEA interfaces have to support this. - SEA.EasyIndexedDB = EasyIndexedDB; + try{SEA.EasyIndexedDB = EasyIndexedDB;}catch(e){} // This is Buffer used in SEA and usable from Gun/SEA application also. // For documentation see https://nodejs.org/api/buffer.html @@ -656,419 +679,6 @@ module.exports = SEA })(USE, './sea'); - ;USE(function(module){ - var SEA = USE('./sea'); - var Gun = SEA.Gun; - // This is internal func queries public key(s) for alias. - const queryGunAliases = (alias, gunRoot) => new Promise((resolve, reject) => { - // load all public keys associated with the username alias we want to log in with. - gunRoot.get('~@'+alias).once((data, key) => { - //rev.off(); - if (!data) { - // if no user, don't do anything. - const err = 'No user!' - Gun.log(err) - return reject({ err }) - } - // then figuring out all possible candidates having matching username - const aliases = [] - let c = 0 - // TODO: how about having real chainable map without callback ? - Gun.obj.map(data, (at, pub) => { - if (!pub.slice || '~' !== pub.slice(0, 1)) { - // TODO: ... this would then be .filter((at, pub)) - return - } - ++c - // grab the account associated with this public key. - gunRoot.get(pub).once(data => { - pub = pub.slice(1) - --c - if (data){ - aliases.push({ pub, put: data }) - } - if (!c && (c = -1)) { - resolve(aliases) - } - }) - }) - if (!c) { - reject({ err: 'Public key does not exist!' }) - } - }) - }) - module.exports = queryGunAliases - })(USE, './query'); - - ;USE(function(module){ - var SEA = USE('./sea'); - var Gun = SEA.Gun; - const queryGunAliases = USE('./query') - const parseProps = USE('./parse') - // This is internal User authentication func. - const authenticate = async (alias, pass, gunRoot) => { - // load all public keys associated with the username alias we want to log in with. - const aliases = (await queryGunAliases(alias, gunRoot)) - .filter(a => !!a.pub && !!a.put) - // Got any? - if (!aliases.length) { - throw { err: 'Public key does not exist!' } - } - let err - // then attempt to log into each one until we find ours! - // (if two users have the same username AND the same password... that would be bad) - const users = await Promise.all(aliases.map(async (a, i) => { - // attempt to PBKDF2 extend the password with the salt. (Verifying the signature gives us the plain text salt.) - const auth = parseProps(a.put.auth) - // NOTE: aliasquery uses `gun.get` which internally SEA.read verifies the data for us, so we do not need to re-verify it here. - // SEA.verify(at.put.auth, pub).then(function(auth){ - try { - const proof = await SEA.work(pass, auth.s) - //const props = { pub: pub, proof: proof, at: at } - // the proof of work is evidence that we've spent some time/effort trying to log in, this slows brute force. - /* - MARK TO @mhelander : pub vs epub!??? - */ - const salt = auth.salt - const sea = await SEA.decrypt(auth.ek, proof) - if (!sea) { - err = 'Failed to decrypt secret! ' + (i+1) +'/'+aliases.length; - return - } - // now we have AES decrypted the private key, from when we encrypted it with the proof at registration. - // if we were successful, then that meanswe're logged in! - const priv = sea.priv - const epriv = sea.epriv - const epub = a.put.epub - // TODO: 'salt' needed? - err = null - if(SEA.window){ - var tmp; try{tmp = window.sessionStorage}catch(e){} - if(tmp && gunRoot._.opt.remember){ // TODO: Bug! This needs to be moved to finalize? - tmp.alias = alias; - tmp.tmp = pass; - } - } - return {priv: priv, pub: a.put.pub, salt: salt, epub: epub, epriv: epriv }; - } catch (e) { - err = 'Failed to decrypt secret!' - throw { err } - } - })) - var user = Gun.list.map(users, function(acc){ if(acc){ return acc } }) - if (!user) { - throw { err: err || 'Public key does not exist!' } - } - return user - } - module.exports = authenticate; - })(USE, './authenticate'); - - ;USE(function(module){ - const authsettings = USE('./settings') - const SEA = USE('./sea'); - const Gun = SEA.Gun; - //const { scope: seaIndexedDb } = USE('./indexed') - // This updates sessionStorage & IndexedDB to persist authenticated "session" - const updateStorage = (proof, key, pin) => async (props) => { - if (!Gun.obj.has(props, 'alias')) { - return // No 'alias' - we're done. - } - if (authsettings.validity && proof && Gun.obj.has(props, 'iat')) { - props.proof = proof - delete props.remember // Not stored if present - - const alias = props.alias - const id = props.alias - const remember = { alias: alias, pin: pin } - - try { - const signed = await SEA.sign(JSON.stringify(remember), key) - - sessionStorage.setItem('user', alias) - sessionStorage.setItem('remember', signed) - - const encrypted = await SEA.encrypt(props, pin) - - if (encrypted) { - const auth = await SEA.sign(encrypted, key) - await seaIndexedDb.wipe() // NO! Do not do this. It ruins other people's sessionStorage code. This is bad/wrong, commenting it out. - await seaIndexedDb.put(id, { auth: auth }) - } - - return props - } catch (err) { - throw { err: 'Session persisting failed!' } - } - } - - // Wiping IndexedDB completely when using random PIN - await seaIndexedDb.wipe() // NO! Do not do this. It ruins other people's sessionStorage code. This is bad/wrong, commenting it out. - // And remove sessionStorage data - sessionStorage.removeItem('user') - sessionStorage.removeItem('remember') - - return props - } - module.exports = updateStorage - })(USE, './update'); - - ;USE(function(module){ - const SEA = USE('./sea'); - const Gun = SEA.Gun; - const Buffer = USE('./buffer') - const authsettings = USE('./settings') - const updateStorage = USE('./update') - // This internal func persists User authentication if so configured - const authPersist = async (user, proof, opts) => { - // opts = { pin: 'string' } - // no opts.pin then uses random PIN - // How this works: - // called when app bootstraps, with wanted options - // IF authsettings.validity === 0 THEN no remember-me, ever - // IF PIN then signed 'remember' to window.sessionStorage and 'auth' to IndexedDB - const pin = Buffer.from( - (Gun.obj.has(opts, 'pin') && opts.pin) || Gun.text.random(10), - 'utf8' - ).toString('base64') - - const alias = user.alias - const exp = authsettings.validity // seconds // @mhelander what is `exp`??? - - if (proof && alias && exp) { - const iat = Math.ceil(Date.now() / 1000) // seconds - const remember = Gun.obj.has(opts, 'pin') || undefined // for hook - not stored - const props = authsettings.hook({ alias: alias, iat: iat, exp: exp, remember: remember }) - const pub = user.pub - const epub = user.epub - const priv = user.sea.priv - const epriv = user.sea.epriv - const key = { pub: pub, priv: priv, epub: epub, epriv: epriv } - if (props instanceof Promise) { - const asyncProps = await props.then() - return await updateStorage(proof, key, pin)(asyncProps) - } - return await updateStorage(proof, key, pin)(props) - } - return await updateStorage()({ alias: 'delete' }) - } - module.exports = authPersist - })(USE, './persist'); - - ;USE(function(module){ - const authPersist = USE('./persist') - // This internal func finalizes User authentication - const finalizeLogin = async (alias, key, gunRoot, opts) => { - const user = gunRoot._.user - // add our credentials in-memory only to our root gun instance - var tmp = user._.tag; - var opt = user._.opt; - user._ = gunRoot.get('~'+key.pub)._; - user._.opt = opt; - var tags = user._.tag; - /*Object.values && Object.values(tmp).forEach(function(tag){ - // TODO: This is ugly & buggy code, it needs to be refactored & tested into a event "merge" utility. - var t = tags[tag.tag]; - console.log("hm??", tag, t); - if(!t){ - tags[tag.tag] = tag; - return; - } - if(tag.last){ - tag.last.to = t.to; - t.last = tag.last = t.last || tag.last; - } - t.to = tag.to; - })*/ - //user._.tag = tmp || user._.tag; - // so that way we can use the credentials to encrypt/decrypt data - // that is input/output through gun (see below) - const pub = key.pub - const priv = key.priv - const epub = key.epub - const epriv = key.epriv - user._.is = user.is = {alias: alias, pub: pub}; - Object.assign(user._, { alias: alias, pub: pub, epub: epub, sea: { pub: pub, priv: priv, epub: epub, epriv: epriv } }) - //console.log("authorized", user._); - // persist authentication - //await authPersist(user._, key.proof, opts) // temporarily disabled - // emit an auth event, useful for page redirects and stuff. - try { - gunRoot._.on('auth', user._) // TODO: Deprecate this, emit on user instead! Update docs when you do. - //user._.on('auth', user._) // Arrgh, this doesn't work without event "merge" code, but "merge" code causes stack overflow and crashes after logging in & trying to write data. - } catch (e) { - console.log('Your \'auth\' callback crashed with:', e) - } - // returns success with the user data credentials. - return user._ - } - module.exports = finalizeLogin - })(USE, './login'); - - ;USE(function(module){ - const Buffer = USE('./buffer') - const authsettings = USE('./settings') - //const { scope: seaIndexedDb } = USE('./indexed') - const queryGunAliases = USE('./query') - const parseProps = USE('./parse') - const updateStorage = USE('./update') - const SEA = USE('./sea') - const Gun = SEA.Gun; - const finalizeLogin = USE('./login') - - // This internal func recalls persisted User authentication if so configured - const authRecall = async (gunRoot, authprops) => { - // window.sessionStorage only holds signed { alias, pin } !!! - const remember = authprops || sessionStorage.getItem('remember') - const { alias = sessionStorage.getItem('user'), pin: pIn } = authprops || {} // @mhelander what is pIn? - const pin = pIn && Buffer.from(pIn, 'utf8').toString('base64') - // Checks for existing proof, matching alias and expiration: - const checkRememberData = async ({ proof, alias: aLias, iat, exp, remember }) => { - if (!!proof && alias === aLias) { - const checkNotExpired = (args) => { - if (Math.floor(Date.now() / 1000) < (iat + args.exp)) { - // No way hook to update 'iat' - return Object.assign(args, { iat: iat, proof: proof }) - } else { - Gun.log('Authentication expired!') - } - } - // We're not gonna give proof to hook! - const hooked = authsettings.hook({ alias: alias, iat: iat, exp: exp, remember: remember }) - return ((hooked instanceof Promise) - && await hooked.then(checkNotExpired)) || checkNotExpired(hooked) - } - } - const readAndDecrypt = async (data, pub, key) => - parseProps(await SEA.decrypt(await SEA.verify(data, pub), key)) - - // Already authenticated? - if (gunRoot._.user - && Gun.obj.has(gunRoot._.user._, 'pub') - && Gun.obj.has(gunRoot._.user._, 'sea')) { - return gunRoot._.user._ // Yes, we're done here. - } - // No, got persisted 'alias'? - if (!alias) { - throw { err: 'No authentication session found!' } - } - // Yes, got persisted 'remember'? - if (!remember) { - throw { // And return proof if for matching alias - err: (await seaIndexedDb.get(alias, 'auth') && authsettings.validity - && 'Missing PIN and alias!') || 'No authentication session found!' - } - } - // Yes, let's get (all?) matching aliases - const aliases = (await queryGunAliases(alias, gunRoot)) - .filter(({ pub } = {}) => !!pub) - // Got any? - if (!aliases.length) { - throw { err: 'Public key does not exist!' } - } - let err - // Yes, then attempt to log into each one until we find ours! - // (if two users have the same username AND the same password... that would be bad) - const [ { key, at, proof, pin: newPin } = {} ] = await Promise - .all(aliases.filter(({ at: { put } = {} }) => !!put) - .map(async ({ at: at, pub: pub }) => { - const readStorageData = async (args) => { - const props = args || parseProps(await SEA.verify(remember, pub, true)) - let pin = props.pin - let aLias = props.alias - - const data = (!pin && alias === aLias) - // No PIN, let's try short-term proof if for matching alias - ? await checkRememberData(props) - // Got PIN so get IndexedDB secret if signature is ok - : await checkRememberData(await readAndDecrypt(await seaIndexedDb.get(alias, 'auth'), pub, pin)) - pin = pin || data.pin - delete data.pin - return { pin: pin, data: data } - } - // got pub, try auth with pin & alias :: or unwrap Storage data... - const __gky20 = await readStorageData(pin && { pin, alias }) - const data = __gky20.data - const newPin = __gky20.pin - const proof = data.proof - - if (!proof) { - if (!data) { - err = 'No valid authentication session found!' - return - } - try { // Wipes IndexedDB silently - await updateStorage()(data) - } catch (e) {} //eslint-disable-line no-empty - err = 'Expired session!' - return - } - - try { // auth parsing or decryption fails or returns empty - silently done - const auth= at.put.auth.auth - const sea = await SEA.decrypt(auth, proof) - if (!sea) { - err = 'Failed to decrypt private key!' - return - } - const priv = sea.priv - const epriv = sea.epriv - const epub = at.put.epub - // Success! we've found our private data! - err = null - return { proof: proof, at: at, pin: newPin, key: { pub: pub, priv: priv, epriv: epriv, epub: epub } } - } catch (e) { - err = 'Failed to decrypt private key!' - return - } - }).filter((props) => !!props)) - - if (!key) { - throw { err: err || 'Public key does not exist!' } - } - - // now we have AES decrypted the private key, - // if we were successful, then that means we're logged in! - try { - await updateStorage(proof, key, newPin || pin)(key) - - const user = Object.assign(key, { at: at, proof: proof }) - const pIN = newPin || pin - - const pinProp = pIN && { pin: Buffer.from(pIN, 'base64').toString('utf8') } - - return await finalizeLogin(alias, user, gunRoot, pinProp) - } catch (e) { // TODO: right log message ? - Gun.log('Failed to finalize login with new password!') - const { err = '' } = e || {} - throw { err: 'Finalizing new password login failed! Reason: '+err } - } - } - module.exports = authRecall - })(USE, './recall'); - - ;USE(function(module){ - const authPersist = USE('./persist') - const authsettings = USE('./settings') - //const { scope: seaIndexedDb } = USE('./indexed') - // This internal func executes logout actions - const authLeave = async (gunRoot, alias = gunRoot._.user._.alias) => { - var user = gunRoot._.user._ || {}; - [ 'get', 'soul', 'ack', 'put', 'is', 'alias', 'pub', 'epub', 'sea' ].map((key) => delete user[key]) - if(user.$){ - delete user.$.is; - } - // Let's use default - gunRoot.user(); - // Removes persisted authentication & CryptoKeys - try { - await authPersist({ alias: alias }) - } catch (e) {} //eslint-disable-line no-empty - return { ok: 0 } - } - module.exports = authLeave - })(USE, './leave'); - ;USE(function(module){ var Gun = USE('./sea').Gun; Gun.chain.then = function(cb){ @@ -1100,7 +710,7 @@ (at = (user = at.user = gun.chain(new User))._).opt = {}; at.opt.uuid = function(cb){ var id = uuid(), pub = root.user; - if(!pub || !(pub = (pub._).sea) || !(pub = pub.pub)){ return id } + if(!pub || !(pub = pub.is) || !(pub = pub.pub)){ return id } id = id + '~' + pub + '.'; if(cb && cb.call){ cb(null, id) } return id; @@ -1115,22 +725,75 @@ // TODO: This needs to be split into all separate functions. // Not just everything thrown into 'create'. - const SEA = USE('./sea') - const User = USE('./user') - const authRecall = USE('./recall') - const authsettings = USE('./settings') - const authenticate = USE('./authenticate') - const finalizeLogin = USE('./login') - const authLeave = USE('./leave') - const _initial_authsettings = USE('./settings').recall - const Gun = SEA.Gun; + var SEA = USE('./sea'); + var User = USE('./user'); + var authsettings = USE('./settings'); + var Gun = SEA.Gun; + + var noop = function(){}; - var u; // Well first we have to actually create a user. That is what this function does. - User.prototype.create = function(username, pass, cb, opt){ - // TODO: Needs to be cleaned up!!! - const gunRoot = this.back(-1) - var gun = this, cat = (gun._); + User.prototype.create = function(alias, pass, cb, opt){ + var gun = this, cat = (gun._), root = gun.back(-1); + cb = cb || noop; + if(cat.ing){ + cb({err: Gun.log("User is already being created or authenticated!"), wait: true}); + return gun; + } + cat.ing = true; + opt = opt || {}; + var act = {}, u; + act.a = function(pubs){ + act.pubs = pubs; + if(pubs && !opt.already){ + // If we can enforce that a user name is already taken, it might be nice to try, but this is not guaranteed. + var ack = {err: Gun.log('User already created!')}; + cat.ing = false; + cb(ack); + gun.leave(); + return; + } + act.salt = Gun.text.random(64); // pseudo-randomly create a salt, then use PBKDF2 function to extend the password with it. + SEA.work(pass, act.salt, act.b); // this will take some short amount of time to produce a proof, which slows brute force attacks. + } + act.b = function(proof){ + act.proof = proof; + SEA.pair(act.c); // now we have generated a brand new ECDSA key pair for the user account. + } + act.c = function(pair){ + act.pair = pair || {}; + // the user's public key doesn't need to be signed. But everything else needs to be signed with it! + act.data = {pub: pair.pub}; + SEA.sign(alias, pair, act.d); + } + act.d = function(alias){ + act.data.alias = alias; + SEA.sign(act.pair.epub, act.pair, act.e); + } + act.e = function(epub){ + act.data.epub = epub; + SEA.encrypt({priv: act.pair.priv, epriv: act.pair.epriv}, act.proof, act.f); // to keep the private key safe, we AES encrypt it with the proof of work! + } + act.f = function(auth){ + act.data.auth = auth; + SEA.sign({ek: auth, s: act.salt}, act.pair, act.g); + } + act.g = function(auth){ var tmp; + act.data.auth = auth; + root.get(tmp = '~'+act.pair.pub).put(act.data); // awesome, now we can actually save the user with their public key as their ID. + root.get('~@'+alias).put(Gun.obj.put({}, tmp, Gun.val.link.ify(tmp))); // next up, we want to associate the alias with the public key. So we add it to the alias list. + setTimeout(function(){ // we should be able to delete this now, right? + cat.ing = false; + cb({ok: 0, pub: act.pair.pub}); // callback that the user has been created. (Note: ok = 0 because we didn't wait for disk to ack) + if(noop === cb){ gun.auth(alias, pass) } // if no callback is passed, auto-login after signing up. + },10); + } + root.get('~@'+alias).once(act.a); + return gun; + } + // now that we have created a user, we want to authenticate them! + User.prototype.auth = function(alias, pass, cb, opt){ + var gun = this, cat = (gun._), root = gun.back(-1); cb = cb || function(){}; if(cat.ing){ cb({err: Gun.log("User is already being created or authenticated!"), wait: true}); @@ -1138,160 +801,116 @@ } cat.ing = true; opt = opt || {}; - var resolve = function(){}, reject = resolve; - // Because more than 1 user might have the same username, we treat the alias as a list of those users. - if(cb){ resolve = reject = cb } - gunRoot.get('~@'+username).get(async (at, ev) => { - ev.off() - if (at.put && !opt.already) { - // If we can enforce that a user name is already taken, it might be nice to try, but this is not guaranteed. - const err = 'User already created!' - Gun.log(err) - cat.ing = false; - gun.leave(); - return reject({ err: err }) + var pair = (alias.pub || alias.epub)? alias : (pass.pub || pass.epub)? pass : null; + var act = {}, u; + act.a = function(data){ + if(!data){ return act.b() } + if(!data.pub){ + var tmp = []; + Gun.node.is(data, function(v){ tmp.push(v) }) + return act.b(tmp); } - const salt = Gun.text.random(64) - // pseudo-randomly create a salt, then use CryptoJS's PBKDF2 function to extend the password with it. - try { - const proof = await SEA.work(pass, salt) - // this will take some short amount of time to produce a proof, which slows brute force attacks. - const pairs = await SEA.pair() - // now we have generated a brand new ECDSA key pair for the user account. - const pub = pairs.pub - const priv = pairs.priv - const epriv = pairs.epriv - // the user's public key doesn't need to be signed. But everything else needs to be signed with it! - const alias = await SEA.sign(username, pairs) - if(u === alias){ throw SEA.err } - const epub = await SEA.sign(pairs.epub, pairs) - if(u === epub){ throw SEA.err } - // to keep the private key safe, we AES encrypt it with the proof of work! - const auth = await SEA.encrypt({ priv: priv, epriv: epriv }, proof) - .then((auth) => // TODO: So signedsalt isn't needed? - // SEA.sign(salt, pairs).then((signedsalt) => - SEA.sign({ek: auth, s: salt}, pairs) - // ) - ).catch((e) => { Gun.log('SEA.en or SEA.write calls failed!'); cat.ing = false; gun.leave(); reject(e) }) - const user = { alias: alias, pub: pub, epub: epub, auth: auth } - const tmp = '~'+pairs.pub; - // awesome, now we can actually save the user with their public key as their ID. - try{ - - gunRoot.get(tmp).put(user) - }catch(e){console.log(e)} - // next up, we want to associate the alias with the public key. So we add it to the alias list. - gunRoot.get('~@'+username).put(Gun.obj.put({}, tmp, Gun.val.link.ify(tmp))) - // callback that the user has been created. (Note: ok = 0 because we didn't wait for disk to ack) - setTimeout(() => { cat.ing = false; resolve({ ok: 0, pub: pairs.pub}) }, 10) // TODO: BUG! If `.auth` happens synchronously after `create` finishes, auth won't work. This setTimeout is a temporary hack until we can properly fix it. - } catch (e) { - Gun.log('SEA.create failed!') - cat.ing = false; - gun.leave(); - reject(e) + if(act.name){ return act.f(data) } + act.c((act.data = data).auth); + } + act.b = function(list){ + var get = (act.list = (act.list||[]).concat(list||[])).shift(); + if(u === get){ + if(act.name){ return act.err('Your user account is not published for dApps to access, please consider syncing it online, or allowing local access by adding your device as a peer.') } + return act.err('Wrong user or password.') } - }) - return gun; // gun chain commands must return gun chains! - } - // now that we have created a user, we want to authenticate them! - User.prototype.auth = function(alias, pass, cb, opt){ - // TODO: Needs to be cleaned up!!!! - const opts = opt || (typeof cb !== 'function' && cb) - let pin = opts && opts.pin - let newpass = opts && opts.newpass - const gunRoot = this.back(-1) - cb = typeof cb === 'function' ? cb : () => {} - newpass = newpass || (opts||{}).change; - var gun = this, cat = (gun._); - if(cat.ing){ - cb({err: "User is already being created or authenticated!", wait: true}); - return gun; + root.get(get).once(act.a); } - cat.ing = true; - - const putErr = (msg) => (e) => { - const { message, err = message || '' } = e - Gun.log(msg) - var error = { err: msg+' Reason: '+err } - return cat.ing = false, gun.leave(), cb(error), gun; + act.c = function(auth){ + if(u === auth){ return act.b() } + SEA.work(pass, (act.auth = auth).s, act.d); // the proof of work is evidence that we've spent some time/effort trying to log in, this slows brute force. } - - var key = (alias.pub || alias.epub)? alias : (pass.pub || pass.epub)? pass : null; - if(key){ - (async function(){ try { - alias = (typeof alias === 'string')? alias : null; - const login = finalizeLogin(alias, key, gunRoot, { pin: pin }) - login.catch(putErr('Finalizing login failed!')) - return cat.ing = false, cb(await login), gun; - } catch(e){ - return cat.ing = false, gun.leave(), cb(e), gun; - }}()) - return gun; + act.d = function(proof){ + if(u === proof){ return act.b() } + SEA.decrypt(act.auth.ek, proof, act.e); } - - if (!pass && pin) { (async function(){ - try { - var r = await authRecall(gunRoot, { alias: alias, pin: pin }) - return cat.ing = false, cb(r), gun; - } catch (e) { - var err = { err: 'Auth attempt failed! Reason: No session data for alias & PIN' } - return cat.ing = false, gun.leave(), cb(err), gun; - }}()) - return gun; + act.e = function(half){ + if(u === half){ return act.b() } + act.half = half; + act.f(act.data); } - - (async function(){ try { - const keys = await authenticate(alias, pass, gunRoot) - if (!keys) { - return putErr('Auth attempt failed!')({ message: 'No keys' }) + act.f = function(data){ + if(!data || !data.pub){ return act.b() } + var tmp = act.half || {}; + act.g({pub: data.pub, epub: data.epub, priv: tmp.priv, epriv: tmp.epriv}); + } + act.g = function(pair){ + act.pair = pair; + var user = (root._).user, at = (user._); + var tmp = at.tag; + var upt = at.opt; + at = user._ = root.get('~'+pair.pub)._; + at.opt = upt; + // add our credentials in-memory only to our root user instance + user.is = {pub: pair.pub, epub: pair.epub, alias: alias}; + at.sea = act.pair; + cat.ing = false; + opt.change? act.z() : cb(at); + if(SEA.window && ((gun.back('user')._).opt||opt).remember){ + // TODO: this needs to be modular. + var sS = {}; try{sS = window.sessionStorage}catch(e){} + sS.recall = true; + sS.alias = alias; + sS.tmp = pass; } - const pub = keys.pub - const priv = keys.priv - const epub = keys.epub - const epriv = keys.epriv - // we're logged in! - if (newpass) { - // password update so encrypt private key using new pwd + salt - try { - const salt = Gun.text.random(64); - const encSigAuth = await SEA.work(newpass, salt) - .then((key) => - SEA.encrypt({ priv: priv, epriv: epriv }, key) - .then((auth) => SEA.sign({ek: auth, s: salt}, keys)) - ) - const signedEpub = await SEA.sign(epub, keys) - const signedAlias = await SEA.sign(alias, keys) - const user = { - pub: pub, - alias: signedAlias, - auth: encSigAuth, - epub: signedEpub - } - // awesome, now we can update the user using public key ID. - gunRoot.get('~'+user.pub).put(user) - // then we're done - const login = finalizeLogin(alias, keys, gunRoot, { pin }) - login.catch(putErr('Failed to finalize login with new password!')) - return cat.ing = false, cb(await login), gun - } catch (e) { - return putErr('Password set attempt failed!')(e) - } - } else { - const login = finalizeLogin(alias, keys, gunRoot, { pin: pin }) - login.catch(putErr('Finalizing login failed!')) - return cat.ing = false, cb(await login), gun; + try{ + (root._).on('auth', at) // TODO: Deprecate this, emit on user instead! Update docs when you do. + //at.on('auth', at) // Arrgh, this doesn't work without event "merge" code, but "merge" code causes stack overflow and crashes after logging in & trying to write data. + }catch(e){ + Gun.log("Your 'auth' callback crashed with:", e); } - } catch (e) { - return putErr('Auth attempt failed!')(e) - } }()); + } + act.z = function(){ + // password update so encrypt private key using new pwd + salt + act.salt = Gun.text.random(64); // pseudo-random + SEA.work(opt.change, act.salt, act.y); + } + act.y = function(proof){ + SEA.encrypt({priv: act.pair.priv, epriv: act.pair.epriv}, proof, act.x); + } + act.x = function(auth){ + SEA.sign({ek: auth, s: act.salt}, act.pair, act.w); + } + act.w = function(auth){ + root.get('~'+act.pair.pub).get('auth').put(auth, cb); + } + act.err = function(e){ + var ack = {err: Gun.log(e || 'User cannot be found!')}; + cat.ing = false; + cb(ack); + } + act.plugin = function(name){ + if(!(act.name = name)){ return act.err() } + var tmp = [name]; + if('~' !== name[0]){ + tmp[1] = '~'+name; + tmp[2] = '~@'+name; + } + act.b(tmp); + } + if(pair){ + act.g(pair); + } else + if(alias){ + root.get('~@'+alias).once(act.a); + } else + if(!alias && !pass){ + SEA.name(act.plugin); + } return gun; } User.prototype.pair = function(){ + console.log("user.pair() IS DEPRECATED AND WILL BE DELETED!!!"); var user = this; if(!user.is){ return false } return user._.sea; } - User.prototype.leave = async function(){ + User.prototype.leave = function(opt, cb){ var gun = this, user = (gun.back(-1)._).user; if(user){ delete user.is; @@ -1299,86 +918,52 @@ delete user._.sea; } if(SEA.window){ - var tmp; try{tmp = window.sessionStorage}catch(e){}; tmp = tmp || {}; - delete tmp.alias; - delete tmp.tmp; + var sS = {}; try{sS = window.sessionStorage}catch(e){}; + delete sS.alias; + delete sS.tmp; + delete sS.recall; } - return await authLeave(this.back(-1)) + return gun; } // If authenticated user wants to delete his/her account, let's support it! - User.prototype.delete = async function(alias, pass){ - const gunRoot = this.back(-1) + User.prototype.delete = async function(alias, pass, cb){ + var gun = this, root = gun.back(-1), user = gun.back('user'); try { - const __gky40 = await authenticate(alias, pass, gunRoot) - const pub = __gky40.pub - await authLeave(gunRoot, alias) - // Delete user data - gunRoot.get('~'+pub).put(null) - // Wipe user data from memory - const { user = { _: {} } } = gunRoot._; - // TODO: is this correct way to 'logout' user from Gun.User ? - [ 'alias', 'sea', 'pub' ].map((key) => delete user._[key]) - user._.is = user.is = {} - gunRoot.user() - return { ok: 0 } // TODO: proper return codes??? + user.auth(alias, pass, function(ack){ + var pub = (user.is||{}).pub; + // Delete user data + user.map().once(function(){ this.put(null) }); + // Wipe user data from memory + user.leave(); + (cb || noop)({ok: 0}); + }); } catch (e) { - Gun.log('User.delete failed! Error:', e) - throw e // TODO: proper error codes??? + Gun.log('User.delete failed! Error:', e); } + return gun; } - // If authentication is to be remembered over reloads or browser closing, - // set validity time in minutes. - User.prototype.recall = function(setvalidity, options){ - var gun = this; - const gunRoot = this.back(-1) - - let validity - let opts - - var o = setvalidity, tmp; - if(o && o.sessionStorage){ + User.prototype.recall = function(opt, cb){ + var gun = this, root = gun.back(-1), tmp; + opt = opt || {}; + if(opt && opt.sessionStorage){ if(SEA.window){ - try{tmp = window.sessionStorage}catch(e){} - if(tmp){ - gunRoot._.opt.remember = true; - if(tmp.alias && tmp.tmp){ - gunRoot.user().auth(tmp.alias, tmp.tmp); + var sS = {}; try{sS = window.sessionStorage}catch(e){} + if(sS){ + (root._).opt.remember = true; + ((gun.back('user')._).opt||opt).remember = true; + if(sS.recall || (sS.alias && sS.tmp)){ + root.user().auth(sS.alias, sS.tmp, cb); } } } return gun; } - - if (!Gun.val.is(setvalidity)) { - opts = setvalidity - validity = _initial_authsettings.validity - } else { - opts = options - validity = setvalidity * 60 // minutes to seconds - } - - try { - // opts = { hook: function({ iat, exp, alias, proof }) } - // iat == Date.now() when issued, exp == seconds to expire from iat - // How this works: - // called when app bootstraps, with wanted options - // IF authsettings.validity === 0 THEN no remember-me, ever - // IF PIN then signed 'remember' to window.sessionStorage and 'auth' to IndexedDB - authsettings.validity = typeof validity !== 'undefined' - ? validity : _initial_authsettings.validity - authsettings.hook = (Gun.obj.has(opts, 'hook') && typeof opts.hook === 'function') - ? opts.hook : _initial_authsettings.hook - // All is good. Should we do something more with actual recalled data? - (async function(){ await authRecall(gunRoot) }()); - return gun; - } catch (e) { - const err = 'No session!' - Gun.log(err) - // NOTE! It's fine to resolve recall with reason why not successful - // instead of rejecting... - //return { err: (e && e.err) || err } - return gun; - } + /* + TODO: copy mhelander's expiry code back in. + Although, we should check with community, + should expiry be core or a plugin? + */ + return gun; } User.prototype.alive = async function(){ const gunRoot = this.back(-1) @@ -1404,7 +989,7 @@ User.prototype.grant = function(to, cb){ console.log("`.grant` API MAY BE DELETED OR CHANGED OR RENAMED, DO NOT USE!"); var gun = this, user = gun.back(-1).user(), pair = user.pair(), path = ''; - gun.back(function(at){ if(at.pub){ return } path += (at.get||'') }); + gun.back(function(at){ if(at.is){ return } path += (at.get||'') }); (async function(){ var enc, sec = await user.get('trust').get(pair.pub).get(path).then(); sec = await SEA.decrypt(sec, pair); @@ -1425,7 +1010,7 @@ User.prototype.secret = function(data, cb){ console.log("`.secret` API MAY BE DELETED OR CHANGED OR RENAMED, DO NOT USE!"); var gun = this, user = gun.back(-1).user(), pair = user.pair(), path = ''; - gun.back(function(at){ if(at.pub){ return } path += (at.get||'') }); + gun.back(function(at){ if(at.is){ return } path += (at.get||'') }); (async function(){ var enc, sec = await user.get('trust').get(pair.pub).get(path).then(); sec = await SEA.decrypt(sec, pair); @@ -1555,9 +1140,9 @@ return each.end({err: "Account must match!"}); } check['user'+soul+key] = 1; - if(user && (user = user._) && user.sea && pub === user.pub){ + if(user && user.is && pub === user.is.pub){ //var id = Gun.text.random(3); - SEA.sign(val, user.sea, function(data){ var rel; + SEA.sign(val, (user._).sea, function(data){ var rel; if(u === data){ return each.end({err: SEA.err || 'Pub signature fail.'}) } if(rel = Gun.val.link.is(val)){ (at.sea.own[rel] = at.sea.own[rel] || {})[pub] = true; @@ -1590,7 +1175,7 @@ return s; } each.any = function(val, key, node, soul, user){ var tmp, pub; - if(!user || !(user = user._) || !(user = user.sea)){ + if(!user || !user.is){ if(tmp = relpub(soul)){ check['any'+soul+key] = 1; SEA.verify(val, pub = tmp, function(data){ var rel; @@ -1631,20 +1216,19 @@ //}); return; } - var pub = tmp; - if(pub !== user.pub){ + if((pub = tmp) !== (user.is||noop).pub){ each.any(val, key, node, soul); return; } /*var other = Gun.obj.map(at.sea.own[soul], function(v, p){ - if(user.pub !== p){ return p } + if((user.is||{}).pub !== p){ return p } }); if(other){ each.any(val, key, node, soul); return; }*/ check['any'+soul+key] = 1; - SEA.sign(val, user, function(data){ + SEA.sign(val, (user._).sea, function(data){ if(u === data){ return each.end({err: 'My signature fail.'}) } node[key] = data; check['any'+soul+key] = 0; @@ -1669,6 +1253,7 @@ } to.next(msg); // pass forward any data we do not know how to handle or process (this allows custom security protocols). } + var noop = {}; })(USE, './index'); }()); \ No newline at end of file diff --git a/sea/authenticate.js b/sea/authenticate.js deleted file mode 100644 index 91bc0d8e..00000000 --- a/sea/authenticate.js +++ /dev/null @@ -1,63 +0,0 @@ - - var SEA = require('./sea'); - var Gun = SEA.Gun; - const queryGunAliases = require('./query') - const parseProps = require('./parse') - // This is internal User authentication func. - const authenticate = async (alias, pass, gunRoot) => { - // load all public keys associated with the username alias we want to log in with. - const aliases = (await queryGunAliases(alias, gunRoot)) - .filter(a => !!a.pub && !!a.put) - // Got any? - if (!aliases.length) { - throw { err: 'Public key does not exist!' } - } - let err - // then attempt to log into each one until we find ours! - // (if two users have the same username AND the same password... that would be bad) - const users = await Promise.all(aliases.map(async (a, i) => { - // attempt to PBKDF2 extend the password with the salt. (Verifying the signature gives us the plain text salt.) - const auth = parseProps(a.put.auth) - // NOTE: aliasquery uses `gun.get` which internally SEA.read verifies the data for us, so we do not need to re-verify it here. - // SEA.verify(at.put.auth, pub).then(function(auth){ - try { - const proof = await SEA.work(pass, auth.s) - //const props = { pub: pub, proof: proof, at: at } - // the proof of work is evidence that we've spent some time/effort trying to log in, this slows brute force. - /* - MARK TO @mhelander : pub vs epub!??? - */ - const salt = auth.salt - const sea = await SEA.decrypt(auth.ek, proof) - if (!sea) { - err = 'Failed to decrypt secret! ' + (i+1) +'/'+aliases.length; - return - } - // now we have AES decrypted the private key, from when we encrypted it with the proof at registration. - // if we were successful, then that meanswe're logged in! - const priv = sea.priv - const epriv = sea.epriv - const epub = a.put.epub - // TODO: 'salt' needed? - err = null - if(SEA.window){ - var tmp = SEA.window.sessionStorage; - if(tmp && gunRoot._.opt.remember){ - SEA.window.sessionStorage.alias = alias; - SEA.window.sessionStorage.tmp = pass; - } - } - return {priv: priv, pub: a.put.pub, salt: salt, epub: epub, epriv: epriv }; - } catch (e) { - err = 'Failed to decrypt secret!' - throw { err } - } - })) - var user = Gun.list.map(users, function(acc){ if(acc){ return acc } }) - if (!user) { - throw { err: err || 'Public key does not exist!' } - } - return user - } - module.exports = authenticate; - \ No newline at end of file diff --git a/sea/buffer.js b/sea/buffer.js index c17702b7..1854bd1c 100644 --- a/sea/buffer.js +++ b/sea/buffer.js @@ -45,7 +45,7 @@ } return buf } - const byteLength = input.byteLength + const byteLength = input.byteLength // what is going on here? FOR MARTTI const length = input.byteLength ? input.byteLength : input.length if (length) { let buf diff --git a/sea/create.js b/sea/create.js index a6c00cfd..96048918 100644 --- a/sea/create.js +++ b/sea/create.js @@ -2,22 +2,75 @@ // TODO: This needs to be split into all separate functions. // Not just everything thrown into 'create'. - const SEA = require('./sea') - const User = require('./user') - const authRecall = require('./recall') - const authsettings = require('./settings') - const authenticate = require('./authenticate') - const finalizeLogin = require('./login') - const authLeave = require('./leave') - const _initial_authsettings = require('./settings').recall - const Gun = SEA.Gun; + var SEA = require('./sea'); + var User = require('./user'); + var authsettings = require('./settings'); + var Gun = SEA.Gun; + + var noop = function(){}; - var u; // Well first we have to actually create a user. That is what this function does. - User.prototype.create = function(username, pass, cb, opt){ - // TODO: Needs to be cleaned up!!! - const gunRoot = this.back(-1) - var gun = this, cat = (gun._); + User.prototype.create = function(alias, pass, cb, opt){ + var gun = this, cat = (gun._), root = gun.back(-1); + cb = cb || noop; + if(cat.ing){ + cb({err: Gun.log("User is already being created or authenticated!"), wait: true}); + return gun; + } + cat.ing = true; + opt = opt || {}; + var act = {}, u; + act.a = function(pubs){ + act.pubs = pubs; + if(pubs && !opt.already){ + // If we can enforce that a user name is already taken, it might be nice to try, but this is not guaranteed. + var ack = {err: Gun.log('User already created!')}; + cat.ing = false; + cb(ack); + gun.leave(); + return; + } + act.salt = Gun.text.random(64); // pseudo-randomly create a salt, then use PBKDF2 function to extend the password with it. + SEA.work(pass, act.salt, act.b); // this will take some short amount of time to produce a proof, which slows brute force attacks. + } + act.b = function(proof){ + act.proof = proof; + SEA.pair(act.c); // now we have generated a brand new ECDSA key pair for the user account. + } + act.c = function(pair){ + act.pair = pair || {}; + // the user's public key doesn't need to be signed. But everything else needs to be signed with it! + act.data = {pub: pair.pub}; + SEA.sign(alias, pair, act.d); + } + act.d = function(alias){ + act.data.alias = alias; + SEA.sign(act.pair.epub, act.pair, act.e); + } + act.e = function(epub){ + act.data.epub = epub; + SEA.encrypt({priv: act.pair.priv, epriv: act.pair.epriv}, act.proof, act.f); // to keep the private key safe, we AES encrypt it with the proof of work! + } + act.f = function(auth){ + act.data.auth = auth; + SEA.sign({ek: auth, s: act.salt}, act.pair, act.g); + } + act.g = function(auth){ var tmp; + act.data.auth = auth; + root.get(tmp = '~'+act.pair.pub).put(act.data); // awesome, now we can actually save the user with their public key as their ID. + root.get('~@'+alias).put(Gun.obj.put({}, tmp, Gun.val.link.ify(tmp))); // next up, we want to associate the alias with the public key. So we add it to the alias list. + setTimeout(function(){ // we should be able to delete this now, right? + cat.ing = false; + cb({ok: 0, pub: act.pair.pub}); // callback that the user has been created. (Note: ok = 0 because we didn't wait for disk to ack) + if(noop === cb){ gun.auth(alias, pass) } // if no callback is passed, auto-login after signing up. + },10); + } + root.get('~@'+alias).once(act.a); + return gun; + } + // now that we have created a user, we want to authenticate them! + User.prototype.auth = function(alias, pass, cb, opt){ + var gun = this, cat = (gun._), root = gun.back(-1); cb = cb || function(){}; if(cat.ing){ cb({err: Gun.log("User is already being created or authenticated!"), wait: true}); @@ -25,234 +78,169 @@ } cat.ing = true; opt = opt || {}; - var resolve = function(){}, reject = resolve; - // Because more than 1 user might have the same username, we treat the alias as a list of those users. - if(cb){ resolve = reject = cb } - gunRoot.get('~@'+username).get(async (at, ev) => { - ev.off() - if (at.put && !opt.already) { - // If we can enforce that a user name is already taken, it might be nice to try, but this is not guaranteed. - const err = 'User already created!' - Gun.log(err) - cat.ing = false; - gun.leave(); - return reject({ err: err }) + var pair = (alias.pub || alias.epub)? alias : (pass.pub || pass.epub)? pass : null; + var act = {}, u; + act.a = function(data){ + if(!data){ return act.b() } + if(!data.pub){ + var tmp = []; + Gun.node.is(data, function(v){ tmp.push(v) }) + return act.b(tmp); } - const salt = Gun.text.random(64) - // pseudo-randomly create a salt, then use CryptoJS's PBKDF2 function to extend the password with it. - try { - const proof = await SEA.work(pass, salt) - // this will take some short amount of time to produce a proof, which slows brute force attacks. - const pairs = await SEA.pair() - // now we have generated a brand new ECDSA key pair for the user account. - const pub = pairs.pub - const priv = pairs.priv - const epriv = pairs.epriv - // the user's public key doesn't need to be signed. But everything else needs to be signed with it! - const alias = await SEA.sign(username, pairs) - if(u === alias){ throw SEA.err } - const epub = await SEA.sign(pairs.epub, pairs) - if(u === epub){ throw SEA.err } - // to keep the private key safe, we AES encrypt it with the proof of work! - const auth = await SEA.encrypt({ priv: priv, epriv: epriv }, proof) - .then((auth) => // TODO: So signedsalt isn't needed? - // SEA.sign(salt, pairs).then((signedsalt) => - SEA.sign({ek: auth, s: salt}, pairs) - // ) - ).catch((e) => { Gun.log('SEA.en or SEA.write calls failed!'); cat.ing = false; gun.leave(); reject(e) }) - const user = { alias: alias, pub: pub, epub: epub, auth: auth } - const tmp = '~'+pairs.pub; - // awesome, now we can actually save the user with their public key as their ID. - try{ - - gunRoot.get(tmp).put(user) - }catch(e){console.log(e)} - // next up, we want to associate the alias with the public key. So we add it to the alias list. - gunRoot.get('~@'+username).put(Gun.obj.put({}, tmp, Gun.val.link.ify(tmp))) - // callback that the user has been created. (Note: ok = 0 because we didn't wait for disk to ack) - setTimeout(() => { cat.ing = false; resolve({ ok: 0, pub: pairs.pub}) }, 10) // TODO: BUG! If `.auth` happens synchronously after `create` finishes, auth won't work. This setTimeout is a temporary hack until we can properly fix it. - } catch (e) { - Gun.log('SEA.create failed!') - cat.ing = false; - gun.leave(); - reject(e) - } - }) - return gun; // gun chain commands must return gun chains! - } - // now that we have created a user, we want to authenticate them! - User.prototype.auth = function(alias, pass, cb, opt){ - // TODO: Needs to be cleaned up!!!! - const opts = opt || (typeof cb !== 'function' && cb) - let pin = opts && opts.pin - let newpass = opts && opts.newpass - const gunRoot = this.back(-1) - cb = typeof cb === 'function' ? cb : () => {} - newpass = newpass || (opts||{}).change; - var gun = this, cat = (gun._); - if(cat.ing){ - cb({err: "User is already being created or authenticated!", wait: true}); - return gun; + if(act.name){ return act.f(data) } + act.c((act.data = data).auth); } - cat.ing = true; - - if (!pass && pin) { (async function(){ - try { - var r = await authRecall(gunRoot, { alias: alias, pin: pin }) - return cat.ing = false, cb(r), gun; - } catch (e) { - var err = { err: 'Auth attempt failed! Reason: No session data for alias & PIN' } - return cat.ing = false, gun.leave(), cb(err), gun; - }}()) - return gun; - } - - const putErr = (msg) => (e) => { - const { message, err = message || '' } = e - Gun.log(msg) - var error = { err: msg+' Reason: '+err } - return cat.ing = false, gun.leave(), cb(error), gun; - } - - (async function(){ try { - const keys = await authenticate(alias, pass, gunRoot) - if (!keys) { - return putErr('Auth attempt failed!')({ message: 'No keys' }) + act.b = function(list){ + var get = (act.list = (act.list||[]).concat(list||[])).shift(); + if(u === get){ + if(act.name){ return act.err('Your user account is not published for dApps to access, please consider syncing it online, or allowing local access by adding your device as a peer.') } + return act.err('Wrong user or password.') } - const pub = keys.pub - const priv = keys.priv - const epub = keys.epub - const epriv = keys.epriv - // we're logged in! - if (newpass) { - // password update so encrypt private key using new pwd + salt - try { - const salt = Gun.text.random(64); - const encSigAuth = await SEA.work(newpass, salt) - .then((key) => - SEA.encrypt({ priv: priv, epriv: epriv }, key) - .then((auth) => SEA.sign({ek: auth, s: salt}, keys)) - ) - const signedEpub = await SEA.sign(epub, keys) - const signedAlias = await SEA.sign(alias, keys) - const user = { - pub: pub, - alias: signedAlias, - auth: encSigAuth, - epub: signedEpub - } - // awesome, now we can update the user using public key ID. - gunRoot.get('~'+user.pub).put(user) - // then we're done - const login = finalizeLogin(alias, keys, gunRoot, { pin }) - login.catch(putErr('Failed to finalize login with new password!')) - return cat.ing = false, cb(await login), gun - } catch (e) { - return putErr('Password set attempt failed!')(e) - } - } else { - const login = finalizeLogin(alias, keys, gunRoot, { pin: pin }) - login.catch(putErr('Finalizing login failed!')) - return cat.ing = false, cb(await login), gun; + root.get(get).once(act.a); + } + act.c = function(auth){ + if(u === auth){ return act.b() } + SEA.work(pass, (act.auth = auth).s, act.d); // the proof of work is evidence that we've spent some time/effort trying to log in, this slows brute force. + } + act.d = function(proof){ + if(u === proof){ return act.b() } + SEA.decrypt(act.auth.ek, proof, act.e); + } + act.e = function(half){ + if(u === half){ return act.b() } + act.half = half; + act.f(act.data); + } + act.f = function(data){ + if(!data || !data.pub){ return act.b() } + var tmp = act.half || {}; + act.g({pub: data.pub, epub: data.epub, priv: tmp.priv, epriv: tmp.epriv}); + } + act.g = function(pair){ + act.pair = pair; + var user = (root._).user, at = (user._); + var tmp = at.tag; + var upt = at.opt; + at = user._ = root.get('~'+pair.pub)._; + at.opt = upt; + // add our credentials in-memory only to our root user instance + user.is = {pub: pair.pub, epub: pair.epub, alias: alias}; + at.sea = act.pair; + cat.ing = false; + opt.change? act.z() : cb(at); + if(SEA.window && ((gun.back('user')._).opt||opt).remember){ + // TODO: this needs to be modular. + var sS = {}; try{sS = window.sessionStorage}catch(e){} + sS.recall = true; + sS.alias = alias; + sS.tmp = pass; } - } catch (e) { - return putErr('Auth attempt failed!')(e) - } }()); + try{ + (root._).on('auth', at) // TODO: Deprecate this, emit on user instead! Update docs when you do. + //at.on('auth', at) // Arrgh, this doesn't work without event "merge" code, but "merge" code causes stack overflow and crashes after logging in & trying to write data. + }catch(e){ + Gun.log("Your 'auth' callback crashed with:", e); + } + } + act.z = function(){ + // password update so encrypt private key using new pwd + salt + act.salt = Gun.text.random(64); // pseudo-random + SEA.work(opt.change, act.salt, act.y); + } + act.y = function(proof){ + SEA.encrypt({priv: act.pair.priv, epriv: act.pair.epriv}, proof, act.x); + } + act.x = function(auth){ + SEA.sign({ek: auth, s: act.salt}, act.pair, act.w); + } + act.w = function(auth){ + root.get('~'+act.pair.pub).get('auth').put(auth, cb); + } + act.err = function(e){ + var ack = {err: Gun.log(e || 'User cannot be found!')}; + cat.ing = false; + cb(ack); + } + act.plugin = function(name){ + if(!(act.name = name)){ return act.err() } + var tmp = [name]; + if('~' !== name[0]){ + tmp[1] = '~'+name; + tmp[2] = '~@'+name; + } + act.b(tmp); + } + if(pair){ + act.g(pair); + } else + if(alias){ + root.get('~@'+alias).once(act.a); + } else + if(!alias && !pass){ + SEA.name(act.plugin); + } return gun; } User.prototype.pair = function(){ + console.log("user.pair() IS DEPRECATED AND WILL BE DELETED!!!"); var user = this; if(!user.is){ return false } return user._.sea; } - User.prototype.leave = async function(){ + User.prototype.leave = function(opt, cb){ var gun = this, user = (gun.back(-1)._).user; if(user){ delete user.is; delete user._.is; delete user._.sea; } - if(typeof window !== 'undefined'){ - var tmp = window.sessionStorage; - delete tmp.alias; - delete tmp.tmp; + if(SEA.window){ + var sS = {}; try{sS = window.sessionStorage}catch(e){}; + delete sS.alias; + delete sS.tmp; + delete sS.recall; } - return await authLeave(this.back(-1)) + return gun; } // If authenticated user wants to delete his/her account, let's support it! - User.prototype.delete = async function(alias, pass){ - const gunRoot = this.back(-1) + User.prototype.delete = async function(alias, pass, cb){ + var gun = this, root = gun.back(-1), user = gun.back('user'); try { - const __gky40 = await authenticate(alias, pass, gunRoot) - const pub = __gky40.pub - await authLeave(gunRoot, alias) - // Delete user data - gunRoot.get('~'+pub).put(null) - // Wipe user data from memory - const { user = { _: {} } } = gunRoot._; - // TODO: is this correct way to 'logout' user from Gun.User ? - [ 'alias', 'sea', 'pub' ].map((key) => delete user._[key]) - user._.is = user.is = {} - gunRoot.user() - return { ok: 0 } // TODO: proper return codes??? + user.auth(alias, pass, function(ack){ + var pub = (user.is||{}).pub; + // Delete user data + user.map().once(function(){ this.put(null) }); + // Wipe user data from memory + user.leave(); + (cb || noop)({ok: 0}); + }); } catch (e) { - Gun.log('User.delete failed! Error:', e) - throw e // TODO: proper error codes??? + Gun.log('User.delete failed! Error:', e); } + return gun; } - // If authentication is to be remembered over reloads or browser closing, - // set validity time in minutes. - User.prototype.recall = function(setvalidity, options){ - var gun = this; - const gunRoot = this.back(-1) - - let validity - let opts - - var o = setvalidity; - if(o && o.sessionStorage){ - if(typeof window !== 'undefined'){ - var tmp = window.sessionStorage; - if(tmp){ - gunRoot._.opt.remember = true; - if(tmp.alias && tmp.tmp){ - gunRoot.user().auth(tmp.alias, tmp.tmp); + User.prototype.recall = function(opt, cb){ + var gun = this, root = gun.back(-1), tmp; + opt = opt || {}; + if(opt && opt.sessionStorage){ + if(SEA.window){ + var sS = {}; try{sS = window.sessionStorage}catch(e){} + if(sS){ + (root._).opt.remember = true; + ((gun.back('user')._).opt||opt).remember = true; + if(sS.recall || (sS.alias && sS.tmp)){ + root.user().auth(sS.alias, sS.tmp, cb); } } } return gun; } - - if (!Gun.val.is(setvalidity)) { - opts = setvalidity - validity = _initial_authsettings.validity - } else { - opts = options - validity = setvalidity * 60 // minutes to seconds - } - - try { - // opts = { hook: function({ iat, exp, alias, proof }) } - // iat == Date.now() when issued, exp == seconds to expire from iat - // How this works: - // called when app bootstraps, with wanted options - // IF authsettings.validity === 0 THEN no remember-me, ever - // IF PIN then signed 'remember' to window.sessionStorage and 'auth' to IndexedDB - authsettings.validity = typeof validity !== 'undefined' - ? validity : _initial_authsettings.validity - authsettings.hook = (Gun.obj.has(opts, 'hook') && typeof opts.hook === 'function') - ? opts.hook : _initial_authsettings.hook - // All is good. Should we do something more with actual recalled data? - (async function(){ await authRecall(gunRoot) }()); - return gun; - } catch (e) { - const err = 'No session!' - Gun.log(err) - // NOTE! It's fine to resolve recall with reason why not successful - // instead of rejecting... - //return { err: (e && e.err) || err } - return gun; - } + /* + TODO: copy mhelander's expiry code back in. + Although, we should check with community, + should expiry be core or a plugin? + */ + return gun; } User.prototype.alive = async function(){ const gunRoot = this.back(-1) @@ -278,7 +266,7 @@ User.prototype.grant = function(to, cb){ console.log("`.grant` API MAY BE DELETED OR CHANGED OR RENAMED, DO NOT USE!"); var gun = this, user = gun.back(-1).user(), pair = user.pair(), path = ''; - gun.back(function(at){ if(at.pub){ return } path += (at.get||'') }); + gun.back(function(at){ if(at.is){ return } path += (at.get||'') }); (async function(){ var enc, sec = await user.get('trust').get(pair.pub).get(path).then(); sec = await SEA.decrypt(sec, pair); @@ -299,7 +287,7 @@ User.prototype.secret = function(data, cb){ console.log("`.secret` API MAY BE DELETED OR CHANGED OR RENAMED, DO NOT USE!"); var gun = this, user = gun.back(-1).user(), pair = user.pair(), path = ''; - gun.back(function(at){ if(at.pub){ return } path += (at.get||'') }); + gun.back(function(at){ if(at.is){ return } path += (at.get||'') }); (async function(){ var enc, sec = await user.get('trust').get(pair.pub).get(path).then(); sec = await SEA.decrypt(sec, pair); diff --git a/sea/decrypt.js b/sea/decrypt.js index d82a7f9f..94b5cdf5 100644 --- a/sea/decrypt.js +++ b/sea/decrypt.js @@ -6,8 +6,12 @@ var parse = require('./parse'); SEA.decrypt = SEA.decrypt || (async (data, pair, cb, opt) => { try { - var opt = opt || {}; - const key = pair.epriv || pair; + opt = opt || {}; + var key = (pair||opt).epriv || pair; + if(!key){ + pair = await SEA.I(null, {what: data, how: 'decrypt', why: opt.why}); + key = pair.epriv || pair; + } const json = parse(data) const ct = await aeskey(key, shim.Buffer.from(json.s, 'utf8'), opt) .then((aes) => (/*shim.ossl ||*/ shim.subtle).decrypt({ // Keeping aesKey scope as private as possible... diff --git a/sea/encrypt.js b/sea/encrypt.js index 6816efb3..c03a037b 100644 --- a/sea/encrypt.js +++ b/sea/encrypt.js @@ -5,8 +5,12 @@ var aeskey = require('./aeskey'); SEA.encrypt = SEA.encrypt || (async (data, pair, cb, opt) => { try { - var opt = opt || {}; - const key = pair.epriv || pair; + opt = opt || {}; + var key = (pair||opt).epriv || pair; + if(!key){ + pair = await SEA.I(null, {what: data, how: 'encrypt', why: opt.why}); + key = pair.epriv || pair; + } const msg = JSON.stringify(data) const rand = {s: shim.random(8), iv: shim.random(16)}; const ct = await aeskey(key, rand.s, opt) diff --git a/sea/index.js b/sea/index.js index 80a5d26f..a70f45e5 100644 --- a/sea/index.js +++ b/sea/index.js @@ -62,7 +62,7 @@ // if there is a request to read data from us, then... var soul = msg.get['#']; if(soul){ // for now, only allow direct IDs to be read. - if(typeof soul !== 'string'){ return to.next(msg) } // do not handle lexical cursors. + if(soul !== 'string'){ return to.next(msg) } // do not handle lexical cursors. if('alias' === soul){ // Allow reading the list of usernames/aliases in the system? return to.next(msg); // yes. } else @@ -111,9 +111,9 @@ return each.end({err: "Account must match!"}); } check['user'+soul+key] = 1; - if(user && (user = user._) && user.sea && pub === user.pub){ + if(user && user.is && pub === user.is.pub){ //var id = Gun.text.random(3); - SEA.sign(val, user.sea, function(data){ var rel; + SEA.sign(val, (user._).sea, function(data){ var rel; if(u === data){ return each.end({err: SEA.err || 'Pub signature fail.'}) } if(rel = Gun.val.link.is(val)){ (at.sea.own[rel] = at.sea.own[rel] || {})[pub] = true; @@ -146,7 +146,7 @@ return s; } each.any = function(val, key, node, soul, user){ var tmp, pub; - if(!user || !(user = user._) || !(user = user.sea)){ + if(!user || !user.is){ if(tmp = relpub(soul)){ check['any'+soul+key] = 1; SEA.verify(val, pub = tmp, function(data){ var rel; @@ -187,20 +187,19 @@ //}); return; } - var pub = tmp; - if(pub !== user.pub){ + if((pub = tmp) !== (user.is||noop).pub){ each.any(val, key, node, soul); return; } /*var other = Gun.obj.map(at.sea.own[soul], function(v, p){ - if(user.pub !== p){ return p } + if((user.is||{}).pub !== p){ return p } }); if(other){ each.any(val, key, node, soul); return; }*/ check['any'+soul+key] = 1; - SEA.sign(val, user, function(data){ + SEA.sign(val, (user._).sea, function(data){ if(u === data){ return each.end({err: 'My signature fail.'}) } node[key] = data; check['any'+soul+key] = 0; @@ -210,7 +209,7 @@ each.end = function(ctx){ // TODO: Can't you just switch this to each.end = cb? if(each.err){ return } if((each.err = ctx.err) || ctx.no){ - console.log('NO!', each.err, msg.put); + console.log('NO!', each.err, msg.put); // 451 mistmached data FOR MARTTI return; } if(!each.end.ed){ return } @@ -225,5 +224,6 @@ } to.next(msg); // pass forward any data we do not know how to handle or process (this allows custom security protocols). } + var noop = {}; - + \ No newline at end of file diff --git a/sea/leave.js b/sea/leave.js deleted file mode 100644 index df497b8f..00000000 --- a/sea/leave.js +++ /dev/null @@ -1,21 +0,0 @@ - - const authPersist = require('./persist') - const authsettings = require('./settings') - //const { scope: seaIndexedDb } = require('./indexed') - // This internal func executes logout actions - const authLeave = async (gunRoot, alias = gunRoot._.user._.alias) => { - var user = gunRoot._.user._ || {}; - [ 'get', 'soul', 'ack', 'put', 'is', 'alias', 'pub', 'epub', 'sea' ].map((key) => delete user[key]) - if(user.$){ - delete user.$.is; - } - // Let's use default - gunRoot.user(); - // Removes persisted authentication & CryptoKeys - try { - await authPersist({ alias: alias }) - } catch (e) {} //eslint-disable-line no-empty - return { ok: 0 } - } - module.exports = authLeave - \ No newline at end of file diff --git a/sea/login.js b/sea/login.js deleted file mode 100644 index 1288aebf..00000000 --- a/sea/login.js +++ /dev/null @@ -1,49 +0,0 @@ - - const authPersist = require('./persist') - // This internal func finalizes User authentication - const finalizeLogin = async (alias, key, gunRoot, opts) => { - const user = gunRoot._.user - // add our credentials in-memory only to our root gun instance - var tmp = user._.tag; - var opt = user._.opt; - user._ = gunRoot.get('~'+key.pub)._; - user._.opt = opt; - var tags = user._.tag; - /*Object.values && Object.values(tmp).forEach(function(tag){ - // TODO: This is ugly & buggy code, it needs to be refactored & tested into a event "merge" utility. - var t = tags[tag.tag]; - console.log("hm??", tag, t); - if(!t){ - tags[tag.tag] = tag; - return; - } - if(tag.last){ - tag.last.to = t.to; - t.last = tag.last = t.last || tag.last; - } - t.to = tag.to; - })*/ - //user._.tag = tmp || user._.tag; - // so that way we can use the credentials to encrypt/decrypt data - // that is input/output through gun (see below) - const pub = key.pub - const priv = key.priv - const epub = key.epub - const epriv = key.epriv - user._.is = user.is = {alias: alias, pub: pub}; - Object.assign(user._, { alias: alias, pub: pub, epub: epub, sea: { pub: pub, priv: priv, epub: epub, epriv: epriv } }) - //console.log("authorized", user._); - // persist authentication - //await authPersist(user._, key.proof, opts) // temporarily disabled - // emit an auth event, useful for page redirects and stuff. - try { - gunRoot._.on('auth', user._) // TODO: Deprecate this, emit on user instead! Update docs when you do. - //user._.on('auth', user._) // Arrgh, this doesn't work without event "merge" code, but "merge" code causes stack overflow and crashes after logging in & trying to write data. - } catch (e) { - console.log('Your \'auth\' callback crashed with:', e) - } - // returns success with the user data credentials. - return user._ - } - module.exports = finalizeLogin - \ No newline at end of file diff --git a/sea/pair.js b/sea/pair.js index 9ff4651e..dd02e9d6 100644 --- a/sea/pair.js +++ b/sea/pair.js @@ -4,8 +4,18 @@ var S = require('./settings'); var Buff = (typeof Buffer !== 'undefined')? Buffer : shim.Buffer; + SEA.name = SEA.name || (async (cb, opt) => { try { + if(cb){ try{ cb() }catch(e){console.log(e)} } + return; + } catch(e) { + console.log(e); + SEA.err = e; + if(cb){ cb() } + return; + }}); + //SEA.pair = async (data, proof, cb) => { try { - SEA.pair = SEA.pair || (async (cb) => { try { + SEA.pair = SEA.pair || (async (cb, opt) => { try { const ecdhSubtle = shim.ossl || shim.subtle // First: ECDSA keys for signing/verifying... diff --git a/sea/persist.js b/sea/persist.js deleted file mode 100644 index 511decc8..00000000 --- a/sea/persist.js +++ /dev/null @@ -1,41 +0,0 @@ - - const SEA = require('./sea'); - const Gun = SEA.Gun; - const Buffer = require('./buffer') - const authsettings = require('./settings') - const updateStorage = require('./update') - // This internal func persists User authentication if so configured - const authPersist = async (user, proof, opts) => { - // opts = { pin: 'string' } - // no opts.pin then uses random PIN - // How this works: - // called when app bootstraps, with wanted options - // IF authsettings.validity === 0 THEN no remember-me, ever - // IF PIN then signed 'remember' to window.sessionStorage and 'auth' to IndexedDB - const pin = Buffer.from( - (Gun.obj.has(opts, 'pin') && opts.pin) || Gun.text.random(10), - 'utf8' - ).toString('base64') - - const alias = user.alias - const exp = authsettings.validity // seconds // @mhelander what is `exp`??? - - if (proof && alias && exp) { - const iat = Math.ceil(Date.now() / 1000) // seconds - const remember = Gun.obj.has(opts, 'pin') || undefined // for hook - not stored - const props = authsettings.hook({ alias: alias, iat: iat, exp: exp, remember: remember }) - const pub = user.pub - const epub = user.epub - const priv = user.sea.priv - const epriv = user.sea.epriv - const key = { pub: pub, priv: priv, epub: epub, epriv: epriv } - if (props instanceof Promise) { - const asyncProps = await props.then() - return await updateStorage(proof, key, pin)(asyncProps) - } - return await updateStorage(proof, key, pin)(props) - } - return await updateStorage()({ alias: 'delete' }) - } - module.exports = authPersist - \ No newline at end of file diff --git a/sea/query.js b/sea/query.js deleted file mode 100644 index f256c8e0..00000000 --- a/sea/query.js +++ /dev/null @@ -1,43 +0,0 @@ - - var SEA = require('./sea'); - var Gun = SEA.Gun; - // This is internal func queries public key(s) for alias. - const queryGunAliases = (alias, gunRoot) => new Promise((resolve, reject) => { - // load all public keys associated with the username alias we want to log in with. - gunRoot.get('~@'+alias).once((data, key) => { - //rev.off(); - if (!data) { - // if no user, don't do anything. - const err = 'No user!' - Gun.log(err) - return reject({ err }) - } - // then figuring out all possible candidates having matching username - const aliases = [] - let c = 0 - // TODO: how about having real chainable map without callback ? - Gun.obj.map(data, (at, pub) => { - if (!pub.slice || '~' !== pub.slice(0, 1)) { - // TODO: ... this would then be .filter((at, pub)) - return - } - ++c - // grab the account associated with this public key. - gunRoot.get(pub).once(data => { - pub = pub.slice(1) - --c - if (data){ - aliases.push({ pub, put: data }) - } - if (!c && (c = -1)) { - resolve(aliases) - } - }) - }) - if (!c) { - reject({ err: 'Public key does not exist!' }) - } - }) - }) - module.exports = queryGunAliases - \ No newline at end of file diff --git a/sea/recall.js b/sea/recall.js deleted file mode 100644 index 998f39de..00000000 --- a/sea/recall.js +++ /dev/null @@ -1,141 +0,0 @@ - - const Buffer = require('./buffer') - const authsettings = require('./settings') - //const { scope: seaIndexedDb } = require('./indexed') - const queryGunAliases = require('./query') - const parseProps = require('./parse') - const updateStorage = require('./update') - const SEA = require('./sea') - const Gun = SEA.Gun; - const finalizeLogin = require('./login') - - // This internal func recalls persisted User authentication if so configured - const authRecall = async (gunRoot, authprops) => { - // window.sessionStorage only holds signed { alias, pin } !!! - const remember = authprops || sessionStorage.getItem('remember') - const { alias = sessionStorage.getItem('user'), pin: pIn } = authprops || {} // @mhelander what is pIn? - const pin = pIn && Buffer.from(pIn, 'utf8').toString('base64') - // Checks for existing proof, matching alias and expiration: - const checkRememberData = async ({ proof, alias: aLias, iat, exp, remember }) => { - if (!!proof && alias === aLias) { - const checkNotExpired = (args) => { - if (Math.floor(Date.now() / 1000) < (iat + args.exp)) { - // No way hook to update 'iat' - return Object.assign(args, { iat: iat, proof: proof }) - } else { - Gun.log('Authentication expired!') - } - } - // We're not gonna give proof to hook! - const hooked = authsettings.hook({ alias: alias, iat: iat, exp: exp, remember: remember }) - return ((hooked instanceof Promise) - && await hooked.then(checkNotExpired)) || checkNotExpired(hooked) - } - } - const readAndDecrypt = async (data, pub, key) => - parseProps(await SEA.decrypt(await SEA.verify(data, pub), key)) - - // Already authenticated? - if (gunRoot._.user - && Gun.obj.has(gunRoot._.user._, 'pub') - && Gun.obj.has(gunRoot._.user._, 'sea')) { - return gunRoot._.user._ // Yes, we're done here. - } - // No, got persisted 'alias'? - if (!alias) { - throw { err: 'No authentication session found!' } - } - // Yes, got persisted 'remember'? - if (!remember) { - throw { // And return proof if for matching alias - err: (await seaIndexedDb.get(alias, 'auth') && authsettings.validity - && 'Missing PIN and alias!') || 'No authentication session found!' - } - } - // Yes, let's get (all?) matching aliases - const aliases = (await queryGunAliases(alias, gunRoot)) - .filter(({ pub } = {}) => !!pub) - // Got any? - if (!aliases.length) { - throw { err: 'Public key does not exist!' } - } - let err - // Yes, then attempt to log into each one until we find ours! - // (if two users have the same username AND the same password... that would be bad) - const [ { key, at, proof, pin: newPin } = {} ] = await Promise - .all(aliases.filter(({ at: { put } = {} }) => !!put) - .map(async ({ at: at, pub: pub }) => { - const readStorageData = async (args) => { - const props = args || parseProps(await SEA.verify(remember, pub, true)) - let pin = props.pin - let aLias = props.alias - - const data = (!pin && alias === aLias) - // No PIN, let's try short-term proof if for matching alias - ? await checkRememberData(props) - // Got PIN so get IndexedDB secret if signature is ok - : await checkRememberData(await readAndDecrypt(await seaIndexedDb.get(alias, 'auth'), pub, pin)) - pin = pin || data.pin - delete data.pin - return { pin: pin, data: data } - } - // got pub, try auth with pin & alias :: or unwrap Storage data... - const __gky20 = await readStorageData(pin && { pin, alias }) - const data = __gky20.data - const newPin = __gky20.pin - const proof = data.proof - - if (!proof) { - if (!data) { - err = 'No valid authentication session found!' - return - } - try { // Wipes IndexedDB silently - await updateStorage()(data) - } catch (e) {} //eslint-disable-line no-empty - err = 'Expired session!' - return - } - - try { // auth parsing or decryption fails or returns empty - silently done - const auth= at.put.auth.auth - const sea = await SEA.decrypt(auth, proof) - if (!sea) { - err = 'Failed to decrypt private key!' - return - } - const priv = sea.priv - const epriv = sea.epriv - const epub = at.put.epub - // Success! we've found our private data! - err = null - return { proof: proof, at: at, pin: newPin, key: { pub: pub, priv: priv, epriv: epriv, epub: epub } } - } catch (e) { - err = 'Failed to decrypt private key!' - return - } - }).filter((props) => !!props)) - - if (!key) { - throw { err: err || 'Public key does not exist!' } - } - - // now we have AES decrypted the private key, - // if we were successful, then that means we're logged in! - try { - await updateStorage(proof, key, newPin || pin)(key) - - const user = Object.assign(key, { at: at, proof: proof }) - const pIN = newPin || pin - - const pinProp = pIN && { pin: Buffer.from(pIN, 'base64').toString('utf8') } - - return await finalizeLogin(alias, user, gunRoot, pinProp) - } catch (e) { // TODO: right log message ? - Gun.log('Failed to finalize login with new password!') - const { err = '' } = e || {} - throw { err: 'Finalizing new password login failed! Reason: '+err } - } - } - module.exports = authRecall - \ No newline at end of file diff --git a/sea/root.js b/sea/root.js index 7095ad34..7b99eb97 100644 --- a/sea/root.js +++ b/sea/root.js @@ -7,15 +7,9 @@ if(typeof window !== "undefined"){ module.window = window } var tmp = module.window || module; - var SEA = tmp.SEA || function(){}; + var SEA = tmp.SEA || {}; - if(SEA.window = module.window){ try{ - SEA.window.SEA = SEA; - tmp = document.createEvent('CustomEvent'); - tmp.initCustomEvent('extension', false, false, {type: "SEA"}); - (window.dispatchEvent || window.fireEvent)(tmp); - window.postMessage({type: "SEA"}, '*'); - } catch(e){} } + if(SEA.window = module.window){ SEA.window.SEA = SEA } try{ if(typeof common !== "undefined"){ common.exports = SEA } }catch(e){} module.exports = SEA; diff --git a/sea/sea.js b/sea/sea.js index 77032638..7eab76a2 100644 --- a/sea/sea.js +++ b/sea/sea.js @@ -1,5 +1,6 @@ // Old Code... + try{ const __gky10 = require('./shim') const crypto = __gky10.crypto const subtle = __gky10.subtle @@ -18,8 +19,8 @@ const keysToEcdsaJwk = __gky11.jwk const sha1hash = require('./sha1') const sha256hash = require('./sha256') - const recallCryptoKey = require('./remember') const parseProps = require('./parse') + }catch(e){} // Practical examples about usage found from ./test/common.js const SEA = require('./root'); @@ -75,7 +76,7 @@ // Cheers! Tell me what you think. var Gun = (SEA.window||{}).Gun || require('./gun', 1); Gun.SEA = SEA; - SEA.Gun = Gun; + SEA.GUN = SEA.Gun = Gun; module.exports = SEA \ No newline at end of file diff --git a/sea/secret.js b/sea/secret.js index 3d38ba18..cf832004 100644 --- a/sea/secret.js +++ b/sea/secret.js @@ -2,8 +2,12 @@ var SEA = require('./root'); var shim = require('./shim'); var S = require('./settings'); - // Derive shared secret from other's pub and my epub/epriv - SEA.secret = SEA.secret || (async (key, pair, cb) => { try { + // Derive shared secret from other's pub and my epub/epriv + SEA.secret = SEA.secret || (async (key, pair, cb, opt) => { try { + opt = opt || {}; + if(!pair || !pair.epriv || !pair.epub){ + pair = await SEA.I(null, {what: key, how: 'secret', why: opt.why}); + } const pub = key.epub || key const epub = pair.epub const epriv = pair.epriv diff --git a/sea/shim.js b/sea/shim.js index 82dccd8a..28594a8b 100644 --- a/sea/shim.js +++ b/sea/shim.js @@ -1,43 +1,38 @@ + const SEA = require('./root') const Buffer = require('./buffer') const api = {Buffer: Buffer} + var o = {}; - if (typeof window !== 'undefined') { - var crypto = window.crypto || window.msCrypto; - var subtle = crypto.subtle || crypto.webkitSubtle; - const TextEncoder = window.TextEncoder - const TextDecoder = window.TextDecoder + if(SEA.window){ + api.crypto = window.crypto || window.msCrypto; + api.subtle = (api.crypto||o).subtle || (api.crypto||o).webkitSubtle; + api.TextEncoder = window.TextEncoder; + api.TextDecoder = window.TextDecoder; + api.random = (len) => Buffer.from(api.crypto.getRandomValues(new Uint8Array(Buffer.alloc(len)))) + } + if(!api.crypto){try{ + var crypto = require('crypto', 1); + const { subtle } = require('@trust/webcrypto', 1) // All but ECDH + const { TextEncoder, TextDecoder } = require('text-encoding', 1) Object.assign(api, { crypto, subtle, TextEncoder, TextDecoder, - random: (len) => Buffer.from(crypto.getRandomValues(new Uint8Array(Buffer.alloc(len)))) - }) - } else { - try{ - var crypto = require('crypto', 1); - const { subtle } = require('@trust/webcrypto', 1) // All but ECDH - const { TextEncoder, TextDecoder } = require('text-encoding', 1) - Object.assign(api, { - crypto, - subtle, - TextEncoder, - TextDecoder, - random: (len) => Buffer.from(crypto.randomBytes(len)) - }); - //try{ - const WebCrypto = require('node-webcrypto-ossl', 1) - api.ossl = new WebCrypto({directory: 'ossl'}).subtle // ECDH - //}catch(e){ - //console.log("node-webcrypto-ossl is optionally needed for ECDH, please install if needed."); - //} - }catch(e){ - console.log("@trust/webcrypto and text-encoding are not included by default, you must add it to your package.json!"); - console.log("node-webcrypto-ossl is temporarily needed for ECDSA signature verification, and optionally needed for ECDH, please install if needed (currently necessary so add them to your package.json for now)."); - TRUST_WEBCRYPTO_OR_TEXT_ENCODING_NOT_INSTALLED; - } - } + random: (len) => Buffer.from(crypto.randomBytes(len)) + }); + //try{ + const WebCrypto = require('node-webcrypto-ossl', 1) + api.ossl = new WebCrypto({directory: 'ossl'}).subtle // ECDH + //}catch(e){ + //console.log("node-webcrypto-ossl is optionally needed for ECDH, please install if needed."); + //} + }catch(e){ + console.log("@trust/webcrypto and text-encoding are not included by default, you must add it to your package.json!"); + console.log("node-webcrypto-ossl is temporarily needed for ECDSA signature verification, and optionally needed for ECDH, please install if needed (currently necessary so add them to your package.json for now)."); + TRUST_WEBCRYPTO_OR_TEXT_ENCODING_NOT_INSTALLED; + }} module.exports = api \ No newline at end of file diff --git a/sea/sign.js b/sea/sign.js index 399df922..05688cce 100644 --- a/sea/sign.js +++ b/sea/sign.js @@ -4,7 +4,7 @@ var S = require('./settings'); var sha256hash = require('./sha256'); - SEA.sign = SEA.sign || (async (data, pair, cb) => { try { + SEA.sign = SEA.sign || (async (data, pair, cb, opt) => { try { if(data && data.slice && 'SEA{' === data.slice(0,4) && '"m":' === data.slice(4,8)){ @@ -14,6 +14,10 @@ if(cb){ try{ cb(data) }catch(e){console.log(e)} } return data; } + opt = opt || {}; + if(!(pair||opt).priv){ + pair = await SEA.I(null, {what: data, how: 'sign', why: opt.why}); + } const pub = pair.pub const priv = pair.priv const jwk = S.jwk(pub, priv) diff --git a/sea/update.js b/sea/update.js deleted file mode 100644 index a312d63f..00000000 --- a/sea/update.js +++ /dev/null @@ -1,48 +0,0 @@ - - const authsettings = require('./settings') - const SEA = require('./sea'); - const Gun = SEA.Gun; - //const { scope: seaIndexedDb } = require('./indexed') - // This updates sessionStorage & IndexedDB to persist authenticated "session" - const updateStorage = (proof, key, pin) => async (props) => { - if (!Gun.obj.has(props, 'alias')) { - return // No 'alias' - we're done. - } - if (authsettings.validity && proof && Gun.obj.has(props, 'iat')) { - props.proof = proof - delete props.remember // Not stored if present - - const alias = props.alias - const id = props.alias - const remember = { alias: alias, pin: pin } - - try { - const signed = await SEA.sign(JSON.stringify(remember), key) - - sessionStorage.setItem('user', alias) - sessionStorage.setItem('remember', signed) - - const encrypted = await SEA.encrypt(props, pin) - - if (encrypted) { - const auth = await SEA.sign(encrypted, key) - await seaIndexedDb.wipe() // NO! Do not do this. It ruins other people's sessionStorage code. This is bad/wrong, commenting it out. - await seaIndexedDb.put(id, { auth: auth }) - } - - return props - } catch (err) { - throw { err: 'Session persisting failed!' } - } - } - - // Wiping IndexedDB completely when using random PIN - await seaIndexedDb.wipe() // NO! Do not do this. It ruins other people's sessionStorage code. This is bad/wrong, commenting it out. - // And remove sessionStorage data - sessionStorage.removeItem('user') - sessionStorage.removeItem('remember') - - return props - } - module.exports = updateStorage - \ No newline at end of file diff --git a/sea/user.js b/sea/user.js index 7c0fadcd..daab6da3 100644 --- a/sea/user.js +++ b/sea/user.js @@ -19,7 +19,7 @@ (at = (user = at.user = gun.chain(new User))._).opt = {}; at.opt.uuid = function(cb){ var id = uuid(), pub = root.user; - if(!pub || !(pub = (pub._).sea) || !(pub = pub.pub)){ return id } + if(!pub || !(pub = pub.is) || !(pub = pub.pub)){ return id } id = id + '~' + pub + '.'; if(cb && cb.call){ cb(null, id) } return id; diff --git a/sea/verify.js b/sea/verify.js index 128aa928..1946f6b5 100644 --- a/sea/verify.js +++ b/sea/verify.js @@ -6,7 +6,7 @@ var parse = require('./parse'); var u; - SEA.verify = SEA.verify || (async (data, pair, cb) => { try { + SEA.verify = SEA.verify || (async (data, pair, cb, opt) => { try { const json = parse(data) if(false === pair){ // don't verify! const raw = (json !== data)? @@ -15,6 +15,9 @@ if(cb){ try{ cb(raw) }catch(e){console.log(e)} } return raw; } + opt = opt || {}; + // SEA.I // verify is free! Requires no user permission. + if(json === data){ throw "No signature on data." } const pub = pair.pub || pair const jwk = S.jwk(pub) const key = await (shim.ossl || shim.subtle).importKey('jwk', jwk, S.ecdsa.pair, false, ['verify']) @@ -27,7 +30,7 @@ if(cb){ try{ cb(r) }catch(e){console.log(e)} } return r; } catch(e) { - console.log(e); + console.log(e); // mismatched owner FOR MARTTI SEA.err = e; if(cb){ cb() } return; diff --git a/src/adapters/localStorage.js b/src/adapters/localStorage.js index 33361ab5..38aac62b 100644 --- a/src/adapters/localStorage.js +++ b/src/adapters/localStorage.js @@ -1,10 +1,12 @@ if(typeof Gun === 'undefined'){ return } // TODO: localStorage is Browser only. But it would be nice if it could somehow plugin into NodeJS compatible localStorage APIs? -var root, noop = function(){}, u; -if(typeof window !== 'undefined'){ root = window } -var store = root.localStorage || {setItem: noop, removeItem: noop, getItem: noop}; - +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!"); + store = {setItem: noop, removeItem: noop, getItem: noop}; +} /* NOTE: Both `lib/file.js` and `lib/memdisk.js` are based on this design! If you update anything here, consider updating the other adapters as well. diff --git a/src/on.js b/src/on.js index 4121852e..f9b3998a 100644 --- a/src/on.js +++ b/src/on.js @@ -78,19 +78,19 @@ function val(msg, eve, to){ var opt = this.as, cat = opt.at, gun = msg.$, at = gun._, data = at.put || msg.put, link, tmp; if(tmp = msg.$$){ link = tmp = (msg.$$._); - if(u === tmp.put){ - return; + if(u !== link.put){ + data = link.put; } - data = tmp.put; } if((tmp = eve.wait) && (tmp = tmp[at.id])){ clearTimeout(tmp) } if((!to && (u === data || at.soul || at.link || (link && !(0 < link.ack)))) - || (u === data && (tmp = (obj_map(at.root.opt.peers, function(v,k,t){t(k)})||[]).length) && (link||at).ack <= tmp)){ + || (u === data && (tmp = (obj_map(at.root.opt.peers, function(v,k,t){t(k)})||[]).length) && (!to && (link||at).ack <= tmp))){ tmp = (eve.wait = {})[at.id] = setTimeout(function(){ val.call({as:opt}, msg, eve, tmp || 1); }, opt.wait || 99); return; } + if(link && u === link.put && (tmp = rel.is(data))){ data = Gun.node.ify({}, tmp) } eve.rid(msg); opt.ok.call(gun || opt.$, data, msg.get); } From 4896085d3a880e9186880bf90361f0bb45b28162 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Sat, 17 Nov 2018 17:12:39 -0800 Subject: [PATCH 133/221] quick fix, republish ...999... --- package.json | 2 +- sea.js | 34 ++++------------------------------ 2 files changed, 5 insertions(+), 31 deletions(-) diff --git a/package.json b/package.json index a8f8ebfa..e89ff43a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gun", - "version": "0.9.99998", + "version": "0.9.99999", "description": "A realtime, decentralized, offline-first, graph data synchronization engine.", "main": "index.js", "browser": "gun.min.js", diff --git a/sea.js b/sea.js index ca47037a..40957b4f 100644 --- a/sea.js +++ b/sea.js @@ -597,46 +597,20 @@ })(USE, './secret'); ;USE(function(module){ - // Old Code... - try{ - const __gky10 = USE('./shim') - const crypto = __gky10.crypto - const subtle = __gky10.subtle - const ossl = __gky10.ossl - const TextEncoder = __gky10.TextEncoder - const TextDecoder = __gky10.TextDecoder - const getRandomBytes = __gky10.random - const EasyIndexedDB = USE('./indexed') - const Buffer = USE('./buffer') - var settings = USE('./settings'); - const __gky11 = USE('./settings') - const pbKdf2 = __gky11.pbkdf2 - const ecdsaKeyProps = __gky11.ecdsa.pair - const ecdsaSignProps = __gky11.ecdsa.sign - const ecdhKeyProps = __gky11.ecdh - const keysToEcdsaJwk = __gky11.jwk - const sha1hash = USE('./sha1') - const sha256hash = USE('./sha256') - const parseProps = USE('./parse') - }catch(e){} - + var shim = USE('./shim'); // Practical examples about usage found from ./test/common.js - const SEA = USE('./root'); + var SEA = USE('./root'); SEA.work = USE('./work'); SEA.sign = USE('./sign'); SEA.verify = USE('./verify'); SEA.encrypt = USE('./encrypt'); SEA.decrypt = USE('./decrypt'); - SEA.random = SEA.random || getRandomBytes; - - // This is easy way to use IndexedDB, all methods are Promises - // Note: Not all SEA interfaces have to support this. - try{SEA.EasyIndexedDB = EasyIndexedDB;}catch(e){} + SEA.random = SEA.random || shim.random; // This is Buffer used in SEA and usable from Gun/SEA application also. // For documentation see https://nodejs.org/api/buffer.html - SEA.Buffer = SEA.Buffer || Buffer; + SEA.Buffer = SEA.Buffer || USE('./buffer'); // These SEA functions support now ony Promises or // async/await (compatible) code, use those like Promises. From 0ad2c74b794ef33a7adf3177f91effd0c7f55841 Mon Sep 17 00:00:00 2001 From: Jake Date: Wed, 21 Nov 2018 05:27:11 +0200 Subject: [PATCH 134/221] added react-native demo --- examples/react-native/.babelrc | 3 + examples/react-native/.buckconfig | 6 + examples/react-native/.flowconfig | 70 + examples/react-native/.gitattributes | 1 + examples/react-native/.gitignore | 56 + examples/react-native/.watchmanconfig | 1 + examples/react-native/README.md | 0 examples/react-native/android/app/BUCK | 65 + .../react-native/android/app/build.gradle | 151 ++ .../android/app/proguard-rules.pro | 17 + .../android/app/src/main/AndroidManifest.xml | 26 + .../app/src/main/assets/html/blank.html | 0 .../main/java/com/gundemo/MainActivity.java | 15 + .../java/com/gundemo/MainApplication.java | 47 + .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 3056 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 5024 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2096 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 2858 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 4569 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 7098 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 6464 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 10676 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 9250 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 15523 bytes .../app/src/main/res/values/strings.xml | 3 + .../app/src/main/res/values/styles.xml | 8 + examples/react-native/android/build.gradle | 39 + .../react-native/android/gradle.properties | 18 + .../android/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 54329 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 + examples/react-native/android/gradlew | 172 ++ examples/react-native/android/gradlew.bat | 84 + examples/react-native/android/keystores/BUCK | 8 + .../keystores/debug.keystore.properties | 4 + examples/react-native/android/settings.gradle | 5 + examples/react-native/app.json | 4 + examples/react-native/index.js | 8 + .../react-native/ios/GunDemo-tvOS/Info.plist | 54 + .../ios/GunDemo-tvOSTests/Info.plist | 24 + .../ios/GunDemo.xcodeproj/project.pbxproj | 1590 ++++++++++++ .../react-native/ios/GunDemo/AppDelegate.h | 14 + .../react-native/ios/GunDemo/AppDelegate.m | 35 + .../ios/GunDemo/Base.lproj/LaunchScreen.xib | 42 + .../AppIcon.appiconset/Contents.json | 38 + .../ios/GunDemo/Images.xcassets/Contents.json | 6 + examples/react-native/ios/GunDemo/Info.plist | 60 + examples/react-native/ios/GunDemo/main.m | 16 + .../ios/GunDemoTests/GunDemoTests.m | 68 + .../react-native/ios/GunDemoTests/Info.plist | 24 + examples/react-native/package.json | 30 + examples/react-native/shim.js | 20 + examples/react-native/src/App/Demo.js | 152 ++ .../react-native/src/App/PolyFillCrypto.js | 92 + examples/react-native/src/App/app.js | 26 + examples/react-native/src/App/index.js | 1 + .../src/extensions/asyncStorageAdapter.js | 75 + examples/react-native/src/extensions/sea.js | 1215 ++++++++++ .../src/webview-crypto/MainWorker.d.ts | 14 + .../src/webview-crypto/MainWorker.js | 170 ++ .../src/webview-crypto/MainWorker.js.map | 1 + .../src/webview-crypto/WebViewWorker.d.ts | 6 + .../src/webview-crypto/WebViewWorker.js | 75 + .../src/webview-crypto/WebViewWorker.js.map | 1 + .../src/webview-crypto/asyncSerialize.d.ts | 8 + .../src/webview-crypto/asyncSerialize.js | 56 + .../src/webview-crypto/asyncSerialize.js.map | 1 + .../src/webview-crypto/compat.d.ts | 1 + .../react-native/src/webview-crypto/compat.js | 4 + .../src/webview-crypto/compat.js.map | 1 + .../src/webview-crypto/index.d.ts | 3 + .../react-native/src/webview-crypto/index.js | 4 + .../src/webview-crypto/index.js.map | 1 + .../src/webview-crypto/serializeBinary.d.ts | 5 + .../src/webview-crypto/serializeBinary.js | 160 ++ .../src/webview-crypto/serializeBinary.js.map | 1 + .../webview-crypto/webViewWorkerString.d.ts | 3 + .../src/webview-crypto/webViewWorkerString.js | 2135 +++++++++++++++++ .../webview-crypto/webViewWorkerString.js.map | 1 + 78 files changed, 7049 insertions(+) create mode 100644 examples/react-native/.babelrc create mode 100644 examples/react-native/.buckconfig create mode 100644 examples/react-native/.flowconfig create mode 100644 examples/react-native/.gitattributes create mode 100644 examples/react-native/.gitignore create mode 100644 examples/react-native/.watchmanconfig create mode 100644 examples/react-native/README.md create mode 100644 examples/react-native/android/app/BUCK create mode 100644 examples/react-native/android/app/build.gradle create mode 100644 examples/react-native/android/app/proguard-rules.pro create mode 100644 examples/react-native/android/app/src/main/AndroidManifest.xml create mode 100644 examples/react-native/android/app/src/main/assets/html/blank.html create mode 100644 examples/react-native/android/app/src/main/java/com/gundemo/MainActivity.java create mode 100644 examples/react-native/android/app/src/main/java/com/gundemo/MainApplication.java create mode 100644 examples/react-native/android/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 examples/react-native/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png create mode 100644 examples/react-native/android/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 examples/react-native/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png create mode 100644 examples/react-native/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 examples/react-native/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png create mode 100644 examples/react-native/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 examples/react-native/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png create mode 100644 examples/react-native/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 examples/react-native/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png create mode 100644 examples/react-native/android/app/src/main/res/values/strings.xml create mode 100644 examples/react-native/android/app/src/main/res/values/styles.xml create mode 100644 examples/react-native/android/build.gradle create mode 100644 examples/react-native/android/gradle.properties create mode 100644 examples/react-native/android/gradle/wrapper/gradle-wrapper.jar create mode 100644 examples/react-native/android/gradle/wrapper/gradle-wrapper.properties create mode 100755 examples/react-native/android/gradlew create mode 100644 examples/react-native/android/gradlew.bat create mode 100644 examples/react-native/android/keystores/BUCK create mode 100644 examples/react-native/android/keystores/debug.keystore.properties create mode 100644 examples/react-native/android/settings.gradle create mode 100644 examples/react-native/app.json create mode 100644 examples/react-native/index.js create mode 100644 examples/react-native/ios/GunDemo-tvOS/Info.plist create mode 100644 examples/react-native/ios/GunDemo-tvOSTests/Info.plist create mode 100644 examples/react-native/ios/GunDemo.xcodeproj/project.pbxproj create mode 100644 examples/react-native/ios/GunDemo/AppDelegate.h create mode 100644 examples/react-native/ios/GunDemo/AppDelegate.m create mode 100644 examples/react-native/ios/GunDemo/Base.lproj/LaunchScreen.xib create mode 100644 examples/react-native/ios/GunDemo/Images.xcassets/AppIcon.appiconset/Contents.json create mode 100644 examples/react-native/ios/GunDemo/Images.xcassets/Contents.json create mode 100644 examples/react-native/ios/GunDemo/Info.plist create mode 100644 examples/react-native/ios/GunDemo/main.m create mode 100644 examples/react-native/ios/GunDemoTests/GunDemoTests.m create mode 100644 examples/react-native/ios/GunDemoTests/Info.plist create mode 100644 examples/react-native/package.json create mode 100644 examples/react-native/shim.js create mode 100644 examples/react-native/src/App/Demo.js create mode 100644 examples/react-native/src/App/PolyFillCrypto.js create mode 100644 examples/react-native/src/App/app.js create mode 100644 examples/react-native/src/App/index.js create mode 100644 examples/react-native/src/extensions/asyncStorageAdapter.js create mode 100644 examples/react-native/src/extensions/sea.js create mode 100644 examples/react-native/src/webview-crypto/MainWorker.d.ts create mode 100644 examples/react-native/src/webview-crypto/MainWorker.js create mode 100644 examples/react-native/src/webview-crypto/MainWorker.js.map create mode 100644 examples/react-native/src/webview-crypto/WebViewWorker.d.ts create mode 100644 examples/react-native/src/webview-crypto/WebViewWorker.js create mode 100644 examples/react-native/src/webview-crypto/WebViewWorker.js.map create mode 100644 examples/react-native/src/webview-crypto/asyncSerialize.d.ts create mode 100644 examples/react-native/src/webview-crypto/asyncSerialize.js create mode 100644 examples/react-native/src/webview-crypto/asyncSerialize.js.map create mode 100644 examples/react-native/src/webview-crypto/compat.d.ts create mode 100644 examples/react-native/src/webview-crypto/compat.js create mode 100644 examples/react-native/src/webview-crypto/compat.js.map create mode 100644 examples/react-native/src/webview-crypto/index.d.ts create mode 100644 examples/react-native/src/webview-crypto/index.js create mode 100644 examples/react-native/src/webview-crypto/index.js.map create mode 100644 examples/react-native/src/webview-crypto/serializeBinary.d.ts create mode 100644 examples/react-native/src/webview-crypto/serializeBinary.js create mode 100644 examples/react-native/src/webview-crypto/serializeBinary.js.map create mode 100644 examples/react-native/src/webview-crypto/webViewWorkerString.d.ts create mode 100644 examples/react-native/src/webview-crypto/webViewWorkerString.js create mode 100644 examples/react-native/src/webview-crypto/webViewWorkerString.js.map diff --git a/examples/react-native/.babelrc b/examples/react-native/.babelrc new file mode 100644 index 00000000..d4b74b5b --- /dev/null +++ b/examples/react-native/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["module:metro-react-native-babel-preset"] +} diff --git a/examples/react-native/.buckconfig b/examples/react-native/.buckconfig new file mode 100644 index 00000000..934256cb --- /dev/null +++ b/examples/react-native/.buckconfig @@ -0,0 +1,6 @@ + +[android] + target = Google Inc.:Google APIs:23 + +[maven_repositories] + central = https://repo1.maven.org/maven2 diff --git a/examples/react-native/.flowconfig b/examples/react-native/.flowconfig new file mode 100644 index 00000000..1043c82d --- /dev/null +++ b/examples/react-native/.flowconfig @@ -0,0 +1,70 @@ +[ignore] +; We fork some components by platform +.*/*[.]android.js + +; Ignore "BUCK" generated dirs +/\.buckd/ + +; Ignore unexpected extra "@providesModule" +.*/node_modules/.*/node_modules/fbjs/.* + +; Ignore duplicate module providers +; For RN Apps installed via npm, "Libraries" folder is inside +; "node_modules/react-native" but in the source repo it is in the root +.*/Libraries/react-native/React.js + +; Ignore polyfills +.*/Libraries/polyfills/.* + +; Ignore metro +.*/node_modules/metro/.* + +[include] + +[libs] +node_modules/react-native/Libraries/react-native/react-native-interface.js +node_modules/react-native/flow/ +node_modules/react-native/flow-github/ + +[options] +emoji=true + +esproposal.optional_chaining=enable +esproposal.nullish_coalescing=enable + +module.system=haste +module.system.haste.use_name_reducers=true +# get basename +module.system.haste.name_reducers='^.*/\([a-zA-Z0-9$_.-]+\.js\(\.flow\)?\)$' -> '\1' +# strip .js or .js.flow suffix +module.system.haste.name_reducers='^\(.*\)\.js\(\.flow\)?$' -> '\1' +# strip .ios suffix +module.system.haste.name_reducers='^\(.*\)\.ios$' -> '\1' +module.system.haste.name_reducers='^\(.*\)\.android$' -> '\1' +module.system.haste.name_reducers='^\(.*\)\.native$' -> '\1' +module.system.haste.paths.blacklist=.*/__tests__/.* +module.system.haste.paths.blacklist=.*/__mocks__/.* +module.system.haste.paths.blacklist=/node_modules/react-native/Libraries/Animated/src/polyfills/.* +module.system.haste.paths.whitelist=/node_modules/react-native/Libraries/.* + +munge_underscores=true + +module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub' + +module.file_ext=.js +module.file_ext=.jsx +module.file_ext=.json +module.file_ext=.native.js + +suppress_type=$FlowIssue +suppress_type=$FlowFixMe +suppress_type=$FlowFixMeProps +suppress_type=$FlowFixMeState + +suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) +suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ +suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy +suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError + +[version] +^0.78.0 diff --git a/examples/react-native/.gitattributes b/examples/react-native/.gitattributes new file mode 100644 index 00000000..d42ff183 --- /dev/null +++ b/examples/react-native/.gitattributes @@ -0,0 +1 @@ +*.pbxproj -text diff --git a/examples/react-native/.gitignore b/examples/react-native/.gitignore new file mode 100644 index 00000000..5d647565 --- /dev/null +++ b/examples/react-native/.gitignore @@ -0,0 +1,56 @@ +# OSX +# +.DS_Store + +# Xcode +# +build/ +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata +*.xccheckout +*.moved-aside +DerivedData +*.hmap +*.ipa +*.xcuserstate +project.xcworkspace + +# Android/IntelliJ +# +build/ +.idea +.gradle +local.properties +*.iml + +# node.js +# +node_modules/ +npm-debug.log +yarn-error.log + +# BUCK +buck-out/ +\.buckd/ +*.keystore + +# fastlane +# +# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the +# screenshots whenever they are needed. +# For more information about the recommended setup visit: +# https://docs.fastlane.tools/best-practices/source-control/ + +*/fastlane/report.xml +*/fastlane/Preview.html +*/fastlane/screenshots + +# Bundle artifact +*.jsbundle diff --git a/examples/react-native/.watchmanconfig b/examples/react-native/.watchmanconfig new file mode 100644 index 00000000..9e26dfee --- /dev/null +++ b/examples/react-native/.watchmanconfig @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/examples/react-native/README.md b/examples/react-native/README.md new file mode 100644 index 00000000..e69de29b diff --git a/examples/react-native/android/app/BUCK b/examples/react-native/android/app/BUCK new file mode 100644 index 00000000..5d9a8b3f --- /dev/null +++ b/examples/react-native/android/app/BUCK @@ -0,0 +1,65 @@ +# To learn about Buck see [Docs](https://buckbuild.com/). +# To run your application with Buck: +# - install Buck +# - `npm start` - to start the packager +# - `cd android` +# - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"` +# - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck +# - `buck install -r android/app` - compile, install and run application +# + +lib_deps = [] + +for jarfile in glob(['libs/*.jar']): + name = 'jars__' + jarfile[jarfile.rindex('/') + 1: jarfile.rindex('.jar')] + lib_deps.append(':' + name) + prebuilt_jar( + name = name, + binary_jar = jarfile, + ) + +for aarfile in glob(['libs/*.aar']): + name = 'aars__' + aarfile[aarfile.rindex('/') + 1: aarfile.rindex('.aar')] + lib_deps.append(':' + name) + android_prebuilt_aar( + name = name, + aar = aarfile, + ) + +android_library( + name = "all-libs", + exported_deps = lib_deps, +) + +android_library( + name = "app-code", + srcs = glob([ + "src/main/java/**/*.java", + ]), + deps = [ + ":all-libs", + ":build_config", + ":res", + ], +) + +android_build_config( + name = "build_config", + package = "com.gundemo", +) + +android_resource( + name = "res", + package = "com.gundemo", + res = "src/main/res", +) + +android_binary( + name = "app", + keystore = "//android/keystores:debug", + manifest = "src/main/AndroidManifest.xml", + package_type = "debug", + deps = [ + ":app-code", + ], +) diff --git a/examples/react-native/android/app/build.gradle b/examples/react-native/android/app/build.gradle new file mode 100644 index 00000000..134d4fd1 --- /dev/null +++ b/examples/react-native/android/app/build.gradle @@ -0,0 +1,151 @@ +apply plugin: "com.android.application" + +import com.android.build.OutputFile + +/** + * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets + * and bundleReleaseJsAndAssets). + * These basically call `react-native bundle` with the correct arguments during the Android build + * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the + * bundle directly from the development server. Below you can see all the possible configurations + * and their defaults. If you decide to add a configuration block, make sure to add it before the + * `apply from: "../../node_modules/react-native/react.gradle"` line. + * + * project.ext.react = [ + * // the name of the generated asset file containing your JS bundle + * bundleAssetName: "index.android.bundle", + * + * // the entry file for bundle generation + * entryFile: "index.android.js", + * + * // whether to bundle JS and assets in debug mode + * bundleInDebug: false, + * + * // whether to bundle JS and assets in release mode + * bundleInRelease: true, + * + * // whether to bundle JS and assets in another build variant (if configured). + * // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants + * // The configuration property can be in the following formats + * // 'bundleIn${productFlavor}${buildType}' + * // 'bundleIn${buildType}' + * // bundleInFreeDebug: true, + * // bundleInPaidRelease: true, + * // bundleInBeta: true, + * + * // whether to disable dev mode in custom build variants (by default only disabled in release) + * // for example: to disable dev mode in the staging build type (if configured) + * devDisabledInStaging: true, + * // The configuration property can be in the following formats + * // 'devDisabledIn${productFlavor}${buildType}' + * // 'devDisabledIn${buildType}' + * + * // the root of your project, i.e. where "package.json" lives + * root: "../../", + * + * // where to put the JS bundle asset in debug mode + * jsBundleDirDebug: "$buildDir/intermediates/assets/debug", + * + * // where to put the JS bundle asset in release mode + * jsBundleDirRelease: "$buildDir/intermediates/assets/release", + * + * // where to put drawable resources / React Native assets, e.g. the ones you use via + * // require('./image.png')), in debug mode + * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug", + * + * // where to put drawable resources / React Native assets, e.g. the ones you use via + * // require('./image.png')), in release mode + * resourcesDirRelease: "$buildDir/intermediates/res/merged/release", + * + * // by default the gradle tasks are skipped if none of the JS files or assets change; this means + * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to + * // date; if you have any other folders that you want to ignore for performance reasons (gradle + * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/ + * // for example, you might want to remove it from here. + * inputExcludes: ["android/**", "ios/**"], + * + * // override which node gets called and with what additional arguments + * nodeExecutableAndArgs: ["node"], + * + * // supply additional arguments to the packager + * extraPackagerArgs: [] + * ] + */ + +project.ext.react = [ + entryFile: "index.js" +] + +apply from: "../../node_modules/react-native/react.gradle" + +/** + * Set this to true to create two separate APKs instead of one: + * - An APK that only works on ARM devices + * - An APK that only works on x86 devices + * The advantage is the size of the APK is reduced by about 4MB. + * Upload all the APKs to the Play Store and people will download + * the correct one based on the CPU architecture of their device. + */ +def enableSeparateBuildPerCPUArchitecture = false + +/** + * Run Proguard to shrink the Java bytecode in release builds. + */ +def enableProguardInReleaseBuilds = false + +android { + compileSdkVersion rootProject.ext.compileSdkVersion + buildToolsVersion rootProject.ext.buildToolsVersion + + defaultConfig { + applicationId "com.gundemo" + minSdkVersion rootProject.ext.minSdkVersion + targetSdkVersion rootProject.ext.targetSdkVersion + versionCode 1 + versionName "1.0" + ndk { + abiFilters "armeabi-v7a", "x86" + } + } + splits { + abi { + reset() + enable enableSeparateBuildPerCPUArchitecture + universalApk false // If true, also generate a universal APK + include "armeabi-v7a", "x86" + } + } + buildTypes { + release { + minifyEnabled enableProguardInReleaseBuilds + proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" + } + } + // applicationVariants are e.g. debug, release + applicationVariants.all { variant -> + variant.outputs.each { output -> + // For each separate APK per architecture, set a unique version code as described here: + // http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits + def versionCodes = ["armeabi-v7a":1, "x86":2] + def abi = output.getFilter(OutputFile.ABI) + if (abi != null) { // null for the universal-debug, universal-release variants + output.versionCodeOverride = + versionCodes.get(abi) * 1048576 + defaultConfig.versionCode + } + } + } +} + +dependencies { + compile project(':react-native-webview-bridge') + implementation fileTree(dir: "libs", include: ["*.jar"]) + implementation "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}" + implementation "com.facebook.react:react-native:+" // From node_modules +} + +// Run this once to be able to run the application with BUCK +// puts all compile dependencies into folder libs for BUCK to use +task copyDownloadableDepsToLibs(type: Copy) { + from configurations.compile + into 'libs' +} diff --git a/examples/react-native/android/app/proguard-rules.pro b/examples/react-native/android/app/proguard-rules.pro new file mode 100644 index 00000000..a92fa177 --- /dev/null +++ b/examples/react-native/android/app/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/examples/react-native/android/app/src/main/AndroidManifest.xml b/examples/react-native/android/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000..5fde7ad3 --- /dev/null +++ b/examples/react-native/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + diff --git a/examples/react-native/android/app/src/main/assets/html/blank.html b/examples/react-native/android/app/src/main/assets/html/blank.html new file mode 100644 index 00000000..e69de29b diff --git a/examples/react-native/android/app/src/main/java/com/gundemo/MainActivity.java b/examples/react-native/android/app/src/main/java/com/gundemo/MainActivity.java new file mode 100644 index 00000000..de2d8c2f --- /dev/null +++ b/examples/react-native/android/app/src/main/java/com/gundemo/MainActivity.java @@ -0,0 +1,15 @@ +package com.gundemo; + +import com.facebook.react.ReactActivity; + +public class MainActivity extends ReactActivity { + + /** + * Returns the name of the main component registered from JavaScript. + * This is used to schedule rendering of the component. + */ + @Override + protected String getMainComponentName() { + return "GunDemo"; + } +} diff --git a/examples/react-native/android/app/src/main/java/com/gundemo/MainApplication.java b/examples/react-native/android/app/src/main/java/com/gundemo/MainApplication.java new file mode 100644 index 00000000..cd09d780 --- /dev/null +++ b/examples/react-native/android/app/src/main/java/com/gundemo/MainApplication.java @@ -0,0 +1,47 @@ +package com.gundemo; + +import android.app.Application; + +import com.facebook.react.ReactApplication; +import com.github.alinz.reactnativewebviewbridge.WebViewBridgePackage; +import com.facebook.react.ReactNativeHost; +import com.facebook.react.ReactPackage; +import com.facebook.react.shell.MainReactPackage; +import com.facebook.soloader.SoLoader; + +import java.util.Arrays; +import java.util.List; + +public class MainApplication extends Application implements ReactApplication { + + private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { + @Override + public boolean getUseDeveloperSupport() { + return BuildConfig.DEBUG; + } + + @Override + protected List getPackages() { + return Arrays.asList( + new MainReactPackage(), + new WebViewBridgePackage() + ); + } + + @Override + protected String getJSMainModuleName() { + return "index"; + } + }; + + @Override + public ReactNativeHost getReactNativeHost() { + return mReactNativeHost; + } + + @Override + public void onCreate() { + super.onCreate(); + SoLoader.init(this, /* native exopackage */ false); + } +} diff --git a/examples/react-native/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/examples/react-native/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..a2f5908281d070150700378b64a84c7db1f97aa1 GIT binary patch literal 3056 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 axPAxe%7rDusX+w*00006jj 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⁣ zwiG+x#%j}{0gU~J8;<|!B1@-XaB@{KORFwrYg_8rOv({b0EO#DbeQRm;B6_9=mXGf z-x|VL{zd`)#@yN}HkCSJbjbNlE|zL3Wm9Q8HY`sV)}3%pgN>cL^67{Z;PPL(*wT8N zUjXU{@|*hvm}({wsAC=x0^ok0%UAz0;sogW{B!nDqk|JJ5x~4NfTDgP49^zeu`csl?5mY@JdQdISc zFs!E{^grmkLnUk9 zny~m)1vws@5BFI<-0Tuo2JWX(0v`W|t(wg;s--L47WTvTMz-8l#TL^=OJNRS2?_Qj z3AKT+gvbyBi#H*-tJ%tWD|>EV3wy|8qxfzS!5RW;Jpl5*zo&^UBU=fG#2}UvRyNkK zA06Dy9;K1ca@r2T>yThYgI!ont$(G{6q#2QT+00r_x0(b)gsE`lBB?2gr55gq^D3Fi&p%E(p9>U%bv zkg1Jco(RbyTX7FDHOnl7-O@ zI$AaIl?9NJKPm(WiBP`1-#CB1QzU>&hKm)fpa5DKE{2$X0hGz-0uZ?cyTk(YC!Y&| zL=1VrNERSA5NA2jq7FACfX4JfPyj5XXl1yv0>~s;eF7L2$>&oMqeTFT2m$y7FlkON z_yurD1yIOvA;5C6016pyxBznGUt0kJ&k5r#;&>Jow`r)sp9R~PmK~lz$3xH%LT*1U zJdOyABZ3!FvNoR*vN$5ykHS8f`jA4zV+|L}i1C4`B2c{R0;UdYxaU|H)2avz@ z=mEYc|2S<+(B2Tj+FkX+2D+yFI!k9lWMA61DJ{)e;lum$(;O87?vGJJe!KtK04+N_ zI*P~t@dUb>9Xh{dbyl{-ZQ(UMgz7$|QfL5XSPkskt^NgctYC#;4WcZB1@%@wy@2t3 z2z0DI7&%b$*Aw~abe?GxE`ez@+6hOh-6*8fHRV{1os$EL@}uUZeG4h1&Be`98q*7j z=3-v+lhIjfWVo12!<>%V^a6lTgW3+_#W6n|p*~==zOH7z$0{LSZk(Tpd7EaD04hnA zL;#fxS0aD{`5^&D`}>0Uq?byDD-l2=!wm_bLcUl4gc(% za1p|itVANvFF>hghAS07Im1;IK;|b*W)}VDyI;BIp2=K*yu2a)j?B|f<44NI$NbmJ z#dE0>jI$fMr&@>4kN8MLFb4&2O9fEKaQg%(QO$4_1rVQywG^CmBLh#}_7gKW3vd?| z2?1^&KWq8}8I^_S0|)MowU_pw$q@nl@Nkn$z>BQq_KA^9yaR`(R3u{{Ig;cwt z@AJ^{ODQCm^neroM9nKNUAXi9RCK`OsP_LuR0PUR(YZCCX5dNF6VzcoK&=b^r`W?ltt|*F zpkoae%ZT{C1h~EcFui~b7fF`vb<<~j_VquuUA$}QqIKYELPp#;{u?q8Dz}WAG-(3; zjrm$i%7UbyZMM(Y{>!uJ#vNB?R~B{6Htp=>e*<{fQQ5W7V(1coCWlOON!MzZxhum| ztZBQpGR z;~#ur^&PockKdV{Q6R>o`Pl{0x!DEbpZ7y9Y;*ZvE!*gU`V1W3znva{f=?WO5I&>B z&hw6}tjECtaghm5z|C#%M;Yf_*pI^};h}Vl=^r9EN=tVDj86D;C$jIJ?K7VP+00000NkvXXu0mjf D5i!M* literal 0 HcmV?d00001 diff --git a/examples/react-native/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/examples/react-native/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..459ca609d3ae0d3943ab44cdc27feef9256dc6d7 GIT binary patch literal 7098 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 literal 0 HcmV?d00001 diff --git a/examples/react-native/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/examples/react-native/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..8ca12fe024be86e868d14e91120a6902f8e88ac6 GIT binary patch literal 6464 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 B0*L?s literal 0 HcmV?d00001 diff --git a/examples/react-native/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/examples/react-native/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..8e19b410a1b15ff180f3dacac19395fe3046cdec GIT binary patch literal 10676 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 literal 0 HcmV?d00001 diff --git a/examples/react-native/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/examples/react-native/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..4c19a13c239cb67b8a2134ddd5f325db1d2d5bee GIT binary patch literal 15523 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 BIP(Ai literal 0 HcmV?d00001 diff --git a/examples/react-native/android/app/src/main/res/values/strings.xml b/examples/react-native/android/app/src/main/res/values/strings.xml new file mode 100644 index 00000000..532e430a --- /dev/null +++ b/examples/react-native/android/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + GunDemo + diff --git a/examples/react-native/android/app/src/main/res/values/styles.xml b/examples/react-native/android/app/src/main/res/values/styles.xml new file mode 100644 index 00000000..319eb0ca --- /dev/null +++ b/examples/react-native/android/app/src/main/res/values/styles.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/examples/react-native/android/build.gradle b/examples/react-native/android/build.gradle new file mode 100644 index 00000000..a1e80854 --- /dev/null +++ b/examples/react-native/android/build.gradle @@ -0,0 +1,39 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + ext { + buildToolsVersion = "27.0.3" + minSdkVersion = 16 + compileSdkVersion = 27 + targetSdkVersion = 26 + supportLibVersion = "27.1.1" + } + repositories { + google() + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:3.1.4' + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + mavenLocal() + google() + jcenter() + maven { + // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm + url "$rootDir/../node_modules/react-native/android" + } + } +} + + +task wrapper(type: Wrapper) { + gradleVersion = '4.4' + distributionUrl = distributionUrl.replace("bin", "all") +} diff --git a/examples/react-native/android/gradle.properties b/examples/react-native/android/gradle.properties new file mode 100644 index 00000000..89e0d99e --- /dev/null +++ b/examples/react-native/android/gradle.properties @@ -0,0 +1,18 @@ +# Project-wide Gradle settings. + +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. + +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html + +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +# Default value: -Xmx10248m -XX:MaxPermSize=256m +# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 + +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true diff --git a/examples/react-native/android/gradle/wrapper/gradle-wrapper.jar b/examples/react-native/android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..01b8bf6b1f99cad9213fc495b33ad5bbab8efd20 GIT binary patch literal 54329 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

          <5G2M1WZP5 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

          + +
          A social network you own & control.
          +
          +
          + + + +
          +
          + +
          +

          Express your thoughts & connect with the world around you!

          +

          - Discover new relationships.

          +

          - Keep up with friends and news in realtime.

          +

          - Watch fun videos and photos from people who share.

          +

          - But this time, you own it: fully decentralized.

          +
          +
          +
          +
          +

          Welcome, you are currently connected to 2 peers. Why not try to sign up or log in?

          +

          - Your identity is created here, by you. Not on a server.

          +

          - It uses secure cryptographic methods to protect you.

          +

          - Only you have access to it, meaning even we cannot reset your password!

          +

          - For added security, you can freely download and run it on your own computer.

          +
          +
          +
          +
          Crafted with ♥ by era.
          +
          +
          +