Browse Source

update gundb

Nikolay Suslov 6 years ago
parent
commit
602bb2dcbb

+ 31 - 28
public/lib/gundb/gun.js

@@ -264,11 +264,11 @@
 			|| num_is(v)){ // by "number" we mean integers or decimals.
 				return true; // simple values are valid.
 			}
-			return Val.rel.is(v) || false; // is the value a soul relation? Then it is valid and return it. If not, everything else remaining is an invalid data type. Custom extensions can be built on top of these primitives to support other types.
+			return Val.link.is(v) || false; // is the value a soul relation? Then it is valid and return it. If not, everything else remaining is an invalid data type. Custom extensions can be built on top of these primitives to support other types.
 		}
 		Val.link = Val.rel = {_: '#'};
 		;(function(){
-			Val.rel.is = function(v){ // this defines whether an object is a soul relation or not, they look like this: {'#': 'UUID'}
+			Val.link.is = function(v){ // this defines whether an object is a soul relation or not, they look like this: {'#': 'UUID'}
 				if(v && v[rel_] && !v._ && obj_is(v)){ // must be an object.
 					var o = {};
 					obj_map(v, map, o);
@@ -287,7 +287,7 @@
 				}
 			}
 		}());
-		Val.rel.ify = function(t){ return obj_put({}, rel_, t) } // convert a soul into a relation and return it.
+		Val.link.ify = function(t){ return obj_put({}, rel_, t) } // convert a soul into a relation and return it.
 		Type.obj.has._ = '.';
 		var rel_ = Val.link._, u;
 		var bi_is = Type.bi.is;
@@ -473,7 +473,7 @@
 					env.map = env;
 				}
 				if(env.soul){
-					at.rel = Val.rel.ify(env.soul);
+					at.link = Val.link.ify(env.soul);
 				}
 				env.shell = (as||{}).shell;
 				env.graph = env.graph || {};
@@ -488,16 +488,16 @@
 				at.env = env;
 				at.soul = soul;
 				if(Node.ify(at.obj, map, at)){
-					at.rel = at.rel || Val.rel.ify(Node.soul(at.node));
+					at.link = at.link || Val.link.ify(Node.soul(at.node));
 					if(at.obj !== env.shell){
-						env.graph[Val.rel.is(at.rel)] = at.node;
+						env.graph[Val.link.is(at.link)] = at.node;
 					}
 				}
 				return at;
 			}
 			function map(v,k,n){
 				var at = this, env = at.env, is, tmp;
-				if(Node._ === k && obj_has(v,Val.rel._)){
+				if(Node._ === k && obj_has(v,Val.link._)){
 					return n._; // TODO: Bug?
 				}
 				if(!(is = valid(v,k,n, at,env))){ return }
@@ -506,8 +506,8 @@
 					if(obj_has(v, Node._) && Node.soul(v)){ // ? for safety ?
 						at.node._ = obj_copy(v._);
 					}
-					at.node = Node.soul.ify(at.node, Val.rel.is(at.rel));
-					at.rel = at.rel || Val.rel.ify(Node.soul(at.node));
+					at.node = Node.soul.ify(at.node, Val.link.is(at.link));
+					at.link = at.link || Val.link.ify(Node.soul(at.node));
 				}
 				if(tmp = env.map){
 					tmp.call(env.as || {}, v,k,n, at);
@@ -526,14 +526,14 @@
 				}
 				tmp = node(env, {obj: v, path: at.path.concat(k)});
 				if(!tmp.node){ return }
-				return tmp.rel; //{'#': Node.soul(tmp.node)};
+				return tmp.link; //{'#': Node.soul(tmp.node)};
 			}
 			function soul(id){ var at = this;
-				var prev = Val.link.is(at.rel), graph = at.env.graph;
-				at.rel = at.rel || Val.rel.ify(id);
-				at.rel[Val.rel._] = id;
+				var prev = Val.link.is(at.link), graph = at.env.graph;
+				at.link = at.link || Val.link.ify(id);
+				at.link[Val.link._] = id;
 				if(at.node && at.node[Node._]){
-					at.node[Node._][Val.rel._] = id;
+					at.node[Node._][Val.link._] = id;
 				}
 				if(obj_has(graph, prev)){
 					graph[id] = graph[prev];
@@ -573,13 +573,13 @@
 			}
 			function map(v,k){ var tmp, obj;
 				if(Node._ === k){
-					if(obj_empty(v, Val.rel._)){
+					if(obj_empty(v, Val.link._)){
 						return;
 					}
 					this.obj[k] = obj_copy(v);
 					return;
 				}
-				if(!(tmp = Val.rel.is(v))){
+				if(!(tmp = Val.link.is(v))){
 					this.obj[k] = v;
 					return;
 				}
@@ -871,7 +871,7 @@
 		var list_is = Gun.list.is;
 		var text = Gun.text, text_is = text.is, text_rand = text.random;
 		var obj = Gun.obj, obj_is = obj.is, obj_has = obj.has, obj_to = obj.to, obj_map = obj.map, obj_copy = obj.copy;
-		var state_lex = Gun.state.lex, _soul = Gun.val.rel._, _has = '.', node_ = Gun.node._, rel_is = Gun.val.link.is;
+		var state_lex = Gun.state.lex, _soul = Gun.val.link._, _has = '.', node_ = Gun.node._, rel_is = Gun.val.link.is;
 		var empty = {}, u;
 
 		console.debug = function(i, s){ return (console.debug.i && i === console.debug.i && console.debug.i++) && (console.log.apply(console, arguments) || s) };
@@ -1133,11 +1133,11 @@
 			if(!(at = next[key])){
 				return;
 			}
-			//if(data && data[_soul] && (tmp = Gun.val.rel.is(data)) && (tmp = (cat.root.$.get(tmp)._)) && obj_has(tmp, 'put')){
+			//if(data && data[_soul] && (tmp = Gun.val.link.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))){
+				//if(!(data && data[_soul] && Gun.val.link.is(data) === Gun.node.soul(at.put))){
 				if(u === at.put || !Gun.val.link.is(data)){
 					at.put = data;
 				}
@@ -1160,7 +1160,10 @@
 			if(!(at.has || at.soul)){ return }
 			var tmp = at.map, root = at.root;
 			at.map = null;
-			if(at.has){ at.link = null }
+			if(at.has){
+				if(at.dub && at.root.stop){ at.dub = null }
+				at.link = null;
+			}
 			//if(!root.now || !root.now[at.id]){
 			if(!at.pass){
 				if((!msg['@']) && null === tmp){ return }
@@ -1219,7 +1222,7 @@
 		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;
 		var text_rand = Gun.text.random;
-		var _soul = Gun.val.rel._, node_ = Gun.node._;
+		var _soul = Gun.val.link._, node_ = Gun.node._;
 	})(USE, './chain');
 
 	;USE(function(module){
@@ -1286,10 +1289,9 @@
 		}
 		function soul(gun, cb, opt, as){
 			var cat = gun._, acks = 0, tmp;
-			if(tmp = cat.soul){ return cb(tmp, as, cat), gun }
-			if(tmp = cat.link){ return cb(tmp, as, cat), gun }
+			if(tmp = cat.soul || cat.link || cat.dub){ return cb(tmp, as, cat), gun }
 			gun.get(function(msg, ev){
-				if(u === msg.put && (tmp = (obj_map(cat.root.opt.peers, function(v,k,t){t(k)})||[]).length) && acks++ <= tmp){
+				if(u === msg.put && (tmp = (obj_map(cat.root.opt.peers, function(v,k,t){t(k)})||[]).length) && ++acks < tmp){
 					return;
 				}
 				ev.rid(msg);
@@ -1393,10 +1395,11 @@
 					if(!soul && Gun.val.is(msg.put)){
 						return Gun.log("The reference you are saving is a", typeof msg.put, '"'+ msg.put +'", not a node (object)!');
 					}
-					gun.put(Gun.val.rel.ify(soul), cb, as);
+					gun.put(Gun.val.link.ify(soul), cb, as);
 				}, true);
 				return gun;
 			}
+			if(at.has && (tmp = Gun.val.link.is(data))){ at.dub = tmp }
 			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);
@@ -1492,7 +1495,7 @@
 		function soul(id, as, msg, eve){
 			var as = as.as, cat = as.at; as = as.as;
 			var at = ((msg || {}).$ || {})._ || {};
-			id = at.dub = at.dub || id || Gun.node.soul(cat.obj) || Gun.node.soul(msg.put || at.put) || Gun.val.rel.is(msg.put || at.put) || (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?
+			id = at.dub = at.dub || id || Gun.node.soul(cat.obj) || Gun.node.soul(msg.put || at.put) || Gun.val.link.is(msg.put || at.put) || (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(eve){ eve.stun = true }
 			if(!id){ // polyfill async uuid for SEA
 				at.via.back('opt.uuid')(function(err, id){ // TODO: improve perf without anonymous callback
@@ -1551,7 +1554,7 @@
 					if(node_ == at.get){
 						as.soul = (at.put||empty)['#'] || at.dub;
 					}
-					as.soul = as.soul || at.soul || at.soul || (opt.uuid || as.via.back('opt.uuid') || Gun.text.random)();
+					as.soul = as.soul || at.soul || at.link || (opt.uuid || as.via.back('opt.uuid') || Gun.text.random)();
 				}
 				if(!as.soul){ // polyfill async uuid for SEA
 					as.via.back('opt.uuid')(function(err, soul){ // TODO: improve perf without anonymous callback
@@ -1804,7 +1807,7 @@
 					});
 				});
 				setTimeout(function(){
-					root.on('out', {put: send, '#': root.ask(ack), I: root.$});
+					root.on('out', {put: send, '#': root.ask(ack)});
 				},1);
 			}
 

File diff suppressed because it is too large
+ 0 - 0
public/lib/gundb/gun.min.js


+ 360 - 0
public/lib/gundb/lib/meta.js

@@ -0,0 +1,360 @@
+$(function(){
+	var m = window.meta = {edit:[], os:{}}, ua = '', u;
+	try{ua = navigator.userAgent.toLowerCase()}catch(e){}
+	m.os.is = {
+		win: (ua.search("win") >= 0)? "windows":false,
+		lin: (ua.search("linux") >= 0)? "linux":false,
+		mac: (ua.search("mac") >= 0)? "macintosh":false,
+		and: (ua.search("android") >= 0)? "android":false,
+		ios: (ua.search('ipod') >= 0 
+			|| ua.search('iphone') >= 0 
+			|| ua.search('ipad') >= 0)? "ios":false
+	}
+	var k = m.key = {ctrl: 17, cmd: 91};
+	k.meta = (m.os.is.win||m.os.is.lin||m.os.is.and)? k.ctrl : k.cmd;
+	k.down = function(eve){
+		if($(eve.target).is('input') || eve.repeat){ return }
+		(k.eve = m.eve = eve).which = eve.which || eve.fake || eve.keyCode;
+		if(!eve.fake && eve.which === k.last){ return }
+		if(k.meta === (k.last = eve.which)){ k.down.meta = m.flip(k.wipe()) || true }
+		if(m.flip.is()){
+			(k.combo || (k.combo = [])).push(eve.which);
+			m.check('on', eve.which, k.at || (k.at = m.edit));
+		}
+		if(eve.metaKey && (k.meta !== eve.which)){ k.up(eve) } // on some systems, meta hijacks keyup
+	}
+	k.up = function(eve){ var tmp;
+		if($(eve.target).is('input')){ return }
+		k.eve = m.eve = eve;
+		k.last = null;
+		eve.which = eve.which || eve.fake || eve.keyCode;
+		if(m.flip.is()){ m.check('up', eve.which) }
+		if(tmp = (k.meta === eve.which)){ k.down.meta = false }
+		if(tmp && k.at === m.edit){ k.wipe() }
+		if(27 === eve.which){ return m.flip(false) }
+	}
+	m.flip = function(tmp, aid){
+		if(aid){
+			m.flip.aid = true;
+			setTimeout(function(){$(document).one('click',function(eve){m.flip(m.flip.aid = false)})},250); // ugly but important for visual aid.
+		}
+		var board = $('#meta .meta-menu');
+		((tmp === false) || (!tmp && board.is(':visible')))? 
+			board.addClass('meta-none')
+		: board.removeClass('meta-none');
+	}
+	m.flip.is = function(){
+		if(m.flip.aid && ((m.eve||{}).fake || k.at !== m.edit)){ m.flip.aid = false }
+		return !m.flip.aid && $('#meta .meta-menu').is(':visible');
+	}
+	m.flip.wait = 500;
+	m.check = function(how, key, at){
+		at = k.at || m.edit;
+		//m.list(at);
+		var edit = at[key], tmp;
+		if(!edit){ return }
+		if(k.eve && k.eve.preventDefault){ k.eve.preventDefault() }
+		if(edit[how]){
+			edit[how](m.eve);
+			if(k.at !== m.edit && 'up' === how){
+				if(k.down.meta){ m.list(k.at = m.edit) }
+				else { k.wipe() }
+			}
+		}
+		if('up' != how){ return }
+		edit.back = at;
+		m.list(edit, at);
+	}
+	m.list = function(at){
+		var l = [];
+		$.each(at, function(i,k){ 'back' != i && k.combo && l.push(k) });
+		if(!l.length){ return }
+		k.at = at;
+		l = l.sort(function(a,b){
+			a = a.combo.slice(-1)[0] || 0;
+			if(a.length){ a = a.toUpperCase().charCodeAt(0) }
+			b = b.combo.slice(-1)[0] || 0;
+			if(b.length){ b = b.toUpperCase().charCodeAt(0) }
+			return (a < b)? -1 : 1;
+		});
+		var $ul = $('#meta .meta-menu ul')
+		$ul.children('li').addClass('meta-none').hide(); setTimeout(function(){ $ul.children('.meta-none').remove() },250); // necessary fix for weird bug glitch
+		$.each(l, function(i, k){
+			$ul.append($('<li>').text(k.name));
+		});
+		if(!at.back){ return }
+		$ul.append($('<li>').html('&larr;').one('click', function(){ m.list(k.at = at.back) }));
+	}
+	m.ask = function(help, cb){
+		var $ul = $('#meta .meta-menu ul').empty();
+		var $put = $('<input>').attr('id', 'meta-ask').attr('placeholder', help);
+		var $form = $('<form>').append($put).on('submit', function(eve){ 
+			eve.preventDefault();
+			cb($put.val());
+			$li.remove();
+			k.wipe();
+		});
+		var $li = $('<li>').append($form);
+		$ul.append($li);
+		$put.focus();
+	}
+	k.wipe = function(){
+		k.combo = [];
+		m.flip(false);
+		m.flip.aid = false;
+		m.list(k.at = m.edit);
+	};
+	$(document).on('keydown', k.down).on('keyup', k.up);
+	m.tap = {};
+	m.tap.select = function(eve){
+		m.tap.range = null;
+		if(!(m.tap.text()||'').trim()){
+			if(m.tap.was){
+				m.tap.was = null;
+				m.flip(false);
+			}
+			return;
+		}
+		m.flip(m.tap.range = monotype((eve||{}).target), m.tap.was = true);
+	}
+	m.tap.text = function(tmp){
+		return ((tmp = window.getSelection) && tmp().toString()) ||
+			((tmp = document.selection) && tmp.createRange().text) || '';
+	}
+	$(window).on('blur', k.wipe).on('focus', k.wipe);
+	$(document).on('select contextmenu keyup mouseup', '[contenteditable=true]', m.tap.select);
+	//.on('keydown', '[contenteditable=true]', function(e){});
+	$(document).on('touchstart', '#meta .meta-start', function(eve){ m.tap.stun = true });
+	$(document).on('click', '#meta .meta-menu li', function(eve){
+		if(m.tap.stun){ return m.tap.stun = false }
+		if(!(eve.fake = eve.which = (($(this).text().match(/[A-Z]/)||{})[0]||'').toUpperCase().charCodeAt(0))){ return }
+		eve.tap = true;
+		k.down(eve);
+		k.up(eve);
+	});
+	meta.edit = function(edit){
+		var tmp = edit.combow = [];
+		$.each(edit.combo || (edit.combo = []), function(i,k){
+			if(!k || !k.length){ return }
+			tmp.push(k.toUpperCase().charCodeAt(0));
+		});
+		var at = meta.edit, l = edit.combo.length;
+		$.each(tmp, function(i,k){ at = at[k] = (++i >= l)? edit : at[k] || {} });
+		edit.combow = edit.combow.join(',');
+		m.list(meta.edit);
+	}
+	meta.text = {zws: '&#8203;'};
+	meta.text.editor = function(opt, as){ var tmp;
+		if(!opt){ return }
+		opt = (typeof opt == 'string')? {edit: opt} : opt.tag? opt : {tag: opt};
+		var r = opt.range = opt.range || m.tap.range || monotype(), cmd = opt.edit;
+		as = opt.as = opt.as || as;
+		if(cmd && document.execCommand){
+			r.restore();
+			if(document.execCommand(cmd, null, as||null)){ return }
+		}
+		if(!opt.tag){ return }
+		opt.tag = $(opt.tag);
+		opt.name = opt.name || opt.tag.prop('tagName');
+		if((tmp = $(r.get()).closest(opt.name)).length){
+			if(r.s === r.e){
+				tmp.after(meta.text.zws);
+				r = r.select(monotype.next(tmp[0]),1);
+			} else {
+				tmp.contents().unwrap(opt.name);
+			}
+		} else
+		if(r.s === r.e){
+			r.insert(opt.tag);
+			r = r.select(opt.tag);
+		} else {
+			r.wrap(opt.tag);
+		}
+		r.restore();
+		opt.range = null;
+		if(m.tap.range){ m.tap.range = monotype() }
+	}
+	;(function(){try{
+		/* UI */
+		if(meta.css){ return }
+		var $m = $('<div>').attr('id', 'meta');
+		$m.append($('<span>').text('+').addClass('meta-start'));
+		$m.append($('<div>').addClass('meta-menu meta-none').append('<ul>'));
+		$(document.body).append($m);
+		css({
+			'#meta': {
+				display: 'block',
+				position: 'fixed',
+				bottom: '2em',
+				right: '2em',
+				background: 'white',
+				'font-size': '18pt',
+				'font-family': 'Tahoma, arial',
+				'box-shadow': '0px 0px 1px #000044',
+				'border-radius': '1em',
+				'text-align': 'center',
+				'z-index': 999999,
+				margin: 0,
+				padding: 0,
+				width: '2em',
+				height: '2em',
+				opacity: 0.7,
+				color: '#000044',
+				overflow: 'visible',
+				transition: 'all 0.2s ease-in'
+			},
+			'#meta .meta-none': {display: 'none'},
+			'#meta span': {'line-height': '2em'},
+			'#meta .meta-menu': {
+				background: 'rgba(0,0,0,0.1)',
+				width: '12em',
+				right: '-2em',
+				bottom: '-2em',
+				overflow: 'visible',
+				position: 'absolute',
+				'overflow-y': 'scroll',
+				'text-align': 'right',
+				'min-height': '20em',
+				height: '100vh'
+			},
+			'#meta .meta-menu ul': {
+				padding: 0,
+				margin: '1em 1em 2em 0',
+				'list-style-type': 'none'
+			},
+			'#meta .meta-menu ul li': {
+				display: 'block',
+				background: 'white',
+				padding: '0.5em 1em',
+				'border-radius': '1em',
+				'margin-left': '0.25em',
+				'margin-top': '0.25em',
+				'float': 'right'
+			},
+			'#meta a': {color: 'black'},
+			'#meta:hover': {opacity: 1},
+			'#meta .meta-menu ul:before': {
+				content: "' '",
+				display: 'block',
+				'min-height': '15em',
+				height: '50vh'
+			},
+			'#meta li': {
+				background: 'white',
+				padding: '0.5em 1em',
+				'border-radius': '1em',
+				'margin-left': '0.25em',
+				'margin-top': '0.25em',
+				'float': 'right'
+			},
+			'#meta:hover .meta-menu': {display: 'block'}
+		});
+		function css(css){
+			var tmp = '';
+			$.each(css, function(c,r){
+				tmp += c + ' {\n';
+				$.each(r, function(k,v){
+					tmp += '\t'+ k +': '+ v +';\n';
+				});
+				tmp += '}\n';
+			});
+			(node = document.createElement('style')).innerHTML = tmp;
+			document.body.appendChild(node);
+		}
+	}catch(e){}}());
+	;(function(){
+	// on fires when shortcut keydowns or on touch after command selected and then touchdown
+	meta.edit({
+		name: "Bold",
+		combo: ['B'],
+		on: function(e){
+			meta.text.editor('bold');
+		},
+		up: function(){}
+	});
+	meta.edit({
+		name: "Italic",
+		combo: ['I'],
+		on: function(e){
+			meta.text.editor('italic');
+		},
+		up: function(){}
+	});
+	meta.edit({
+		name: "Underline",
+		combo: ['U'],
+		on: function(e){
+			meta.text.editor('underline');
+		},
+		up: function(){}
+	});
+	meta.edit({
+		name: "linK",
+		combo: ['K'],
+		up: function(e){
+			var range = meta.tap.range || monotype();
+			meta.ask('Paste or type link...', function(url){
+				meta.text.editor({tag: $('<a href="'+url+'">link</a>'), edit: url? 'createLink' : 'unlink', as: url, range: range});
+			})
+		},
+		on: function(){}
+	});
+	meta.edit({name: "aliGn", combo: ['G']});
+	meta.edit({
+		name: "Left",
+		combo: ['G','L'],
+		on: function(e){ meta.text.editor('justifyLeft') },
+		up: function(){}
+	});
+	meta.edit({
+		name: "Right",
+		combo: ['G','R'],
+		on: function(e){ meta.text.editor('justifyRight') },
+		up: function(){ }
+	});
+	meta.edit({
+		name: "Middle",
+		combo: ['G','M'],
+		on: function(e){ meta.text.editor('justifyCenter') },
+		up: function(){ }
+	});
+	meta.edit({
+		name: "Justify",
+		combo: ['G','J'],
+		on: function(e){ meta.text.editor('justifyFull') },
+		up: function(){}
+	});
+	// Align Number
+	// Align Points
+	// Align Strike
+	meta.edit({name: "Size", combo: ['S']});
+	meta.edit({
+		name: "Small",
+		combo: ['S','S'],
+		on: function(e){ meta.text.editor('fontSize', 2) },
+		up: function(){ }
+	});
+	meta.edit({
+		name: "Normal",
+		combo: ['S','N'],
+		on: function(e){ meta.text.editor('fontSize', 5) },
+		up: function(){}
+	});
+	meta.edit({
+		name: "Header",
+		combo: ['S','H'],
+		on: function(e){ meta.text.editor('fontSize', 6) },
+		up: function(){}
+	});
+	meta.edit({
+		name: "Title",
+		combo: ['S','T'],
+		on: function(e){ meta.text.editor('fontSize', 7) },
+		up: function(){}
+	});
+	// Size Spacing
+	// Size Super
+	// Size Sub
+	meta.edit({name: "Edit", combo: ['E']});
+	}());
+});

+ 0 - 38
public/lib/gundb/lib/metae.js

@@ -1,38 +0,0 @@
-$(function(){
-	var m = window.meta = {edit:[], os:{}}, ua = '';
-	try{ua = navigator.userAgent.toLowerCase()}catch(e){}
-	m.os.is = {
-		win: (ua.search("win") >= 0)? "windows":false,
-		lin: (ua.search("linux") >= 0)? "linux":false,
-		mac: (ua.search("mac") >= 0)? "macintosh":false,
-		and: (ua.search("android") >= 0)? "android":false,
-		ios: (ua.search('ipod') >= 0 
-			|| ua.search('iphone') >= 0 
-			|| ua.search('ipad') >= 0)? "ios":false
-	}
-	m.key = {ctrl: 17, cmd: 91};
-	m.key.meta = (m.os.is.win||m.os.is.lin||m.os.is.and)? m.key.ctrl : m.key.cmd;
-	m.key.on = {};
-	$(document).on('keydown', function(e){
-		m.e = e;
-		console.log('keydown', e.keyCode);
-		m.key.on[e.code = e.keyCode] = !0;
-	}).on('keyup', function(e){
-		m.e = e;
-		delete m.key.on[e.code = e.keyCode];
-	}).on('keydown', '[contenteditable=true]', function(e){
-		return;
-		var r = monotype();
-		console.log("keys down", Gun.obj.copy(m.key.on));
-		$.each(m.edit, function(i,edit){ var tmp = true;
-			$.each(edit.keys||[''], function(i,k){
-				if(!m.key.on[k.length? k.charCodeAt(0) : k]){ tmp = false }
-			});
-			console.log(tmp, edit);
-		})
-		r.restore();
-	});
-	m.edit.push({keys: ['B'], on: function(){
-		console.log('hi!');
-	}})
-});

+ 88 - 8
public/lib/gundb/lib/monotype.js

@@ -121,13 +121,12 @@
 		return o;
 	}
 	return monotype;
-})(function(r,opt){
-	r = r || {};
+})(function(e,opt){
+	var r = {}, t, m = monotype;
 	opt = opt || {};
-	monotype.win = opt.win || window;
-	r = r.jquery || monotype.text(r)? {root: $(r)} : r;
-	r.root = $(r.root || monotype.win.document.body);
-	var t, m = monotype;
+	m.win = opt.win || window;
+	r = (e||r).jquery || m.text(e)? {root: $(e||m.win.document.body)} : r;
+	r.root = $(r.root || m.win.document.body);
 	//console.log('_______________________');
 	r.R = m.range(0);
 	r.H = {};
@@ -226,5 +225,86 @@
 		m.restore(R);
 		return r;
 	}
-	return r;
-});
+	return monotype.late(r,opt);
+	//return r;
+});
+monotype.late = function(r,opt){
+	var u, m = r //monotype(r,opt)
+	, strhml = function(t){
+		return (t[0] === '<' && $(t).length)
+	}, jqtxt = function(n){
+		return n.jquery?n:(strhml(n))?$('<div>'+n+'</div>').contents():$(document.createTextNode(n));
+	}
+	m.get = function(d){
+		if(u === d){ return $([m.R.startContainer, m.R.endContainer]) }
+		return monotype.deep((d = (d && d > 0))? m.R.endContainer : m.R.startContainer
+			, d? m.R.endOffset : m.R.startOffset).container;
+	}
+	m.remove = function(n,R){
+		R = m.R || m.range();
+		R.deleteContents();
+		monotype.restore(R);
+		m = monotype(m,opt);
+		return m;
+	}
+	m.insert = function(n,R){
+		n = jqtxt(n);
+		R = m.R || m.range();
+		R.deleteContents();
+		$(n.get().reverse()).each(function(){
+			R.insertNode(this);
+		});
+		R.selectNodeContents(n.last()[0]);
+		monotype.restore(R);
+		m = monotype(m,opt);
+		return m;
+	}
+	m.wrap = function(n,R){
+		var jq;
+		n = jqtxt(n);
+		n = n[0];
+		R = m.R || m.range();
+		if(monotype.text(R.startContainer) || monotype.text(R.endContainer)){
+			var b = R.cloneContents();
+			R.deleteContents();
+			jq = $(n);
+			jq.html(b);
+			jq = jq[0];
+			R.insertNode(jq);
+		}else{
+			R.surroundContents(n);
+		}
+		R.selectNodeContents(jq||n);
+		monotype.restore(R);
+		m = monotype(m,opt);
+		return m;
+	}
+	m.select = function(n,i,e,j){
+		var R = m.R || m.range(), t = e;
+		n = $(n);
+		if($.isNumeric(e)){
+			e = j || n;
+			j = t;
+		} else {
+			e = e || n;
+		}
+		j = $.isNumeric(j)? j : $.isNumeric(i)? i : Infinity;
+		i = i || 0;
+		if(i < 0){
+			t = n.contents().length || n.text().length;
+			i = t + i;
+		} if(j < 0){
+			t = n.contents().length || n.text().length;
+			j = t + j;
+		} if(j === Infinity){
+			R.selectNodeContents(n[0]);
+		} else {
+			R.setStart(n[0],i);
+			R.setEnd(e[0],j);
+		}
+		monotype.restore(R);
+		m = monotype(m,opt);
+		return m;
+	}
+	return m;
+}

+ 284 - 138
public/lib/gundb/lib/normalize.js

@@ -1,138 +1,284 @@
-;(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);
-			});
-		})
-		return el;
-	};
-	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 = tmp.toLowerCase()) +'>').append(a.$.contents()));
-				h.attr(a.$, a.attr, a.attrs);
-			}
-			,function(a, tmp){ // lookahead
-				if((tmp = n.joint(a.$,1)) && (tmp = tmp.contents()).length === 1 && a.tag === n.tag(tmp = tmp.first())){
-					a.$.append(tmp.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, tmp){ // exclude
-				if(!n.get(a.opt,'tags.' + a.tag) 
-				|| ((tmp = n.get(a.opt,'tags.'+ a.tag +'.exclude')) 
-				&& a.$.parents($.map(tmp,function(i,v){return v})+' ').length)
-				){ 
-					a.$.replaceWith(a.$.contents());
-				}
-			}
-			,function(a, tmp){ // prior
-				if((tmp = n.joint(a.$)).length && a.tag === n.tag(tmp)){
-					tmp.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;
-}());
+(function(){
+
+  $.normalize = function(html, customOpt){
+    var html, root$, wrapped, opt;
+    opt = html.opt || (customOpt ? prepareOptTags($.extend(true, baseOpt, customOpt))
+                                 : defaultOpt);
+    if(!html.opt){
+      // first call
+      unstableList.length = 0; // drop state from previous run (in case there has been error)
+      root$ = $('<div>'+html+'</div>');
+    }
+    // initial recursion
+    (html.$ || root$).contents().each(function(){
+      if(this.nodeType === this.TEXT_NODE) {
+      this.textContent = this.textContent.replace(/^[ \n]+|[ \n]+$/g, ' ');
+        return;
+      }
+      var a = {$: $(this), opt: opt};
+      initTag(a);
+      $.normalize(a);
+    });
+    if(root$){
+      stateMachine();
+      return root$.html();
+    }
+  }
+
+  var baseOpt = {
+    hierarchy: ['div', 'pre', 'ol', 'ul', 'li',
+                'h1', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'a', // block
+                'b', 'code', 'i', 'span', 's', 'sub', 'sup', 'u',   // inline
+                'br']                                               // empty
+    ,tags: {
+      'a': {attrs:{'href':1}, exclude:{'a':1}},
+      'b': {exclude:{'b':1,'p':1}},
+      'br': {empty: 1},
+      'i': {exclude:{'i':1,'p':1}},
+      'span': {exclude:{'p':1,'ul':1,'ol':1,'li':1,'br':1}},
+      's': {space:1},
+      'u': {exclude:{'u':1,'p':1},space:1},
+    }
+    ,convert: {
+      'em': 'i', 'strong': 'b', 'strike': 's',
+    }
+    ,attrs: {
+      'id':1
+      ,'class':1
+      ,'style':1
+    }
+    ,blockTag: function(a){
+      return a.opt.tags[a.tag].order < a.opt.tags.a.order;
+    }
+    ,mutate: [exclude, moveSpaceUp, next, parentOrderWrap]
+  }
+
+  var defaultOpt = prepareOptTags($.extend(true, {}, baseOpt));
+
+  var unstableList = [];
+
+  function addUnstable(a) { // NOT ES5
+    if(!a.tag) { throw Error("not tag in ", a) }
+    if(a.unstable) return;
+    unstableList.push(a);
+    a.unstable = true;
+  }
+
+  function initTag(a) {
+    // initial handling (container, convert, attributes):
+    a.tag = tag(a.$);
+      if(empty(a)) {
+      return;
+    }
+    parseAndRemoveAttrs(a);
+    convert(a);
+    setAttrs(a);
+    a.$[0].a = a; // link from dom element back to a
+    // state machine init
+    unstableList.push(a);
+    a.unstable = true;
+    return a;
+  }
+
+  function stateMachine() {
+    if(unstableList.length===0)
+      return;
+    var a, i = -1;
+    while (a = unstableList.pop()) { // PERF: running index is probably faster than shift (mutates array)
+      a.unstable = false;
+      $(a.opt.mutate).each(function(i,fn){
+        return fn && fn(a, addUnstable);
+      });
+    }
+  }
+
+  function prepareOptTags(opt) {
+    var name, tag, tags = opt.tags;
+    for(name in tags) {
+      if(opt.hierarchy.indexOf(name)===-1)
+        throw Error('tag "'+name+'" is missing hierachy definition');
+    }
+    opt.hierarchy.forEach(function(name){
+      if(!tags[name]){
+        tags[name] = {attrs: opt.attrs};
+      }
+      (tag=tags[name]).attrs = $.extend(tag.attrs||{}, opt.attrs);
+      tag.name = name; // not used, debug help (REMOVE later?)
+      // order
+      tag.order = opt.hierarchy.indexOf(name)
+      if(tag.order === -1) {
+      throw Error("Order of '"+name+"' not defined in hierarchy");
+    }
+    });
+    return opt;
+  }
+
+  // GENERAL UTILS
+
+  function get(o, args){ // path argments as separate string parameters
+    if(typeof args === 'string')
+      return o[args[0]];
+    var i = 0, l = args.length, u;
+    while((o = o[args[i++]]) != null && i < l){};
+    return i < l ? u : o;
+  }
+
+  function has(obj,prop){
+    return Object.prototype.hasOwnProperty.call(obj, prop);
+  }
+
+  // ELEMENT UTILS
+
+  function tag(e){
+    return (($(e)[0]||{}).nodeName||'').toLowerCase();
+  }
+
+  function joint(e, d){
+    d = (d? 'next' : 'previous') + 'Sibling';
+    return $(($(e)[0]||{})[d]);
+  }
+
+  // create key val attributes object from elements attributes
+  function attrsAsObj(e, filterCb){
+    var attrObj = {};
+    (e = $(e)) && e.length && $(e[0].attributes||[]).each(function(value,name){
+      name = name.nodeName||name.name;
+      value = e.attr(name);
+      value = filterCb? filterCb(value,name,e) : value;
+      if(value !== undefined && value !== false)
+        attrObj[name] = value;
+    });
+    return attrObj;
+  }
+
+  // TODO: PERF testing - for loop to compare through?
+  function sameAttrs(a, b) {
+    return JSON.stringify(a.attr) === JSON.stringify(b.attr);
+  }
+
+  // INITIAL MUTATORS
+
+  function parseAndRemoveAttrs(a) {
+    a.attrs = [];
+    var tag = a.opt.convert[a.tag] || a.tag,
+    tOpt = a.opt.tags[tag];
+    a.attr = tOpt && attrsAsObj(a.$, function(value,name){
+    a.$.removeAttr(name);
+    if(tOpt.attrs[name.toLowerCase()]){
+      a.attrs.push(name)
+      return value;
+    }
+    });
+  }
+
+  function setAttrs(a){
+    var l  = function(ind,name){
+      var t = name;
+      name = a.attrs? name : ind;
+      var value = a.attrs? a.attr[name.toLowerCase()] : t;
+      a.$.attr(name, value);
+    }
+    a.attrs? $(a.attrs.sort()).each(l) : $.each(a.attr,l);
+  }
+
+  function convert(a){
+    var t;
+    if(t = a.opt.convert[a.tag]){
+      a.$.replaceWith(a.$ = $('<'+ (a.tag = t.toLowerCase()) +'>').append(a.$.contents()));
+    }
+  }
+
+  // LOOPING (STATE MACHINE) MUTATORS
+
+  function exclude(a, addUnstable){
+    var t = get(a.opt, ['tags', a.tag]),
+    pt = get(a.opt, ['tags', tag(a.$.parent())]);
+    if(!t || (pt && get(pt, ['exclude', a.tag]))){
+      var c = a.$.contents();
+      a.$.replaceWith(c);
+      c.length===1 && c[0].a && addUnstable(c[0].a);
+      return false;
+    }
+  }
+
+  function moveSpaceUp(a, addUnstable){
+    var n = a.$[0];
+    if(moveSpace(n, true) + moveSpace(n, false)) {
+      // either front, back or both spaces moved
+      var c;
+      if(n.textContent==='') {
+        empty(a);
+      } else if((c = a.$.contents()[0]) && c.a) {
+        parentOrderWrap(c.a, addUnstable)
+      }
+    }
+  }
+
+  function moveSpace(n, bef) {
+    var childRe  = bef? /^ / : / $/,
+        parentRe = bef? / $/ : /^ /,
+        c = bef? 'firstChild' : 'lastChild',
+        s = bef? 'previousSibling' : 'nextSibling';
+        sAdd = bef? 'after' : 'before';
+        pAdd = bef? 'prepend' : 'append';
+    if(!n || !n[c] || n[c].nodeType !== n.TEXT_NODE || !n[c].wholeText.match(childRe)) {
+      return 0;
+    }
+    if((n2 = n[s]) && !n.a.opt.blockTag(n.a)) {
+      if(n2.nodeType === 3 && !n2.textContent.match(parentRe)) {
+        n2.textContent = (bef?'':' ') + n2.textContent + (bef?' ':'');
+      } else if(n2.nodeType === 1) {
+        $(n2)[sAdd](' ');
+      }
+    } else if((n2 = n.parentNode) && !n.a.opt.blockTag(n.a)) {
+      $(n2)[pAdd](' ');
+    } else {
+      return 0;
+    }
+    n[c].textContent = n[c].wholeText.replace(childRe, '');
+    if(!n[c].wholeText.length)
+      $(n[c]).remove();
+    return 1;
+  }
+
+  function next(a, addUnstable, t){
+    var t = t || joint(a.$, true), sm;
+    if(!t.length || a.opt.blockTag(a))
+      return;
+    if(a.opt.spaceMerge && t.length===1 && t[0].nodeType === 3 && t[0].wholeText===' '){
+      if(!(t2 = joint(t, true)).length || a.opt.blockTag(t2[0].a))
+        return;
+      t.remove();
+      t2.prepend(' ');
+      return next(a, addUnstable, t2);
+    }
+    if(!t[0].a || a.tag !== t[0].a.tag || !sameAttrs(a, t[0].a))
+      return;
+    t.prepend(a.$.contents());
+    empty(a);
+    addUnstable(t[0].a);
+    (t = t.children(":first")).length && addUnstable(t[0].a);
+  }
+
+  function empty(a){
+    var t = a.opt.tags[a.tag];
+    if((!t || !t.empty) && !a.$.contents().length && !a.$[0].attributes.length){
+      a.$.remove();
+      return true; // NOTE true/false - different API than in exclude
+    }
+  }
+
+  function parentOrderWrap(a, addUnstable){
+    var parent = a.$.parent(), children = parent.contents(),
+    tags = a.opt.tags, ptag;
+
+    if(children.length===1 && children[0] === a.$[0]
+    && (ptag=tags[tag(parent)]) && ptag.order > tags[a.tag].order){
+      parent.after(a.$);
+      parent.append(a.$.contents());
+      a.$.append(parent);
+      addUnstable(parent[0].a);
+      addUnstable(a);
+    }
+  }
+})();

+ 2 - 1
public/lib/gundb/lib/upload.js

@@ -25,9 +25,10 @@
 		if(!e){ return cb && cb({err: "No file!"}) }
 		if(e.err){ return }
 		var file = (((e.event || e).target || e).result || e), img = new Image();
+    img.crossOrigin = "Anonymous";
     img.src = file;
     img.onload = function(){
-    	if(img.width < w && img.height < (h||Infinity)){
+    	if(img.width < (w = w || 1000) && img.height < (h||Infinity) && "data:" == file.slice(0,5)){
     		e.base64 = file;
     		return cb(e || file);
     	}

+ 32 - 45
public/lib/gundb/sea/index.js

@@ -50,11 +50,11 @@
 
     // signature handles data output, it is a proxy to the security function.
     function signature(msg){
-      if(msg.user){
+      if((msg._||noop).user){
         return this.to.next(msg);
       }
       var ctx = this.as;
-      msg.user = ctx.user;
+      (msg._||(msg._=function(){})).user = ctx.user;
       security.call(this, msg);
     }
 
@@ -95,9 +95,9 @@
             each.pubs(val, key, node, soul); return;
           }
           if('~' === soul.slice(0,1) && 2 === (tmp = soul.slice(1)).split('.').length){ // special case, account data for a public key.
-            each.pub(val, key, node, soul, tmp, msg.user); return;
+            each.pub(val, key, node, soul, tmp, (msg._||noop).user); return;
           }
-          each.any(val, key, node, soul, msg.user); return;
+          each.any(val, key, node, soul, (msg._||noop).user); return;
           return each.end({err: "No other data allowed!"});
         };
         each.alias = function(val, key, node, soul){ // Example: {_:#~@, ~@alice: {#~@alice}}
@@ -116,7 +116,7 @@
             return each.end({err: "Account must match!"});
           }
           check['user'+soul+key] = 1;
-          if(msg.I && user && user.is && pub === user.is.pub){
+          if(Gun.is(msg.$) && user && user.is && pub === user.is.pub){
             SEA.sign(SEA.opt.prep(tmp = SEA.opt.parse(val), key, node, soul), (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)){
@@ -141,20 +141,12 @@
           });
         };
         each.any = function(val, key, node, soul, user){ var tmp, pub;
-          if(!user || !user.is){
-            if(tmp = SEA.opt.pub(soul)){
-              check['any'+soul+key] = 1;
-              SEA.verify(SEA.opt.pack(val,key,node,soul), pub = tmp, function(data){ var rel;
-                data = SEA.opt.unpack(data, key, node);
-                if(u === data){ return each.end({err: "Mismatched owner on '" + key + "'."}) } // thanks @rogowski !
-                if((rel = Gun.val.link.is(data)) && pub === SEA.opt.pub(rel)){
-                  (at.sea.own[rel] = at.sea.own[rel] || {})[pub] = true;
-                }
-                check['any'+soul+key] = 0;
-                each.end({ok: 1});
-              });
+          if(!(pub = SEA.opt.pub(soul))){
+            if(at.opt.secure){
+              each.end({err: "Soul is missing public key at '" + key + "'."});
               return;
             }
+            // TODO: Ask community if should auto-sign non user-graph data.
             check['any'+soul+key] = 1;
             at.on('secure', function(msg){ this.off();
               check['any'+soul+key] = 0;
@@ -164,38 +156,33 @@
             //each.end({err: "Data cannot be modified."});
             return;
           }
-          if(!(tmp = SEA.opt.pub(soul))){
-            if(at.opt.secure){
-              each.end({err: "Soul is missing public key at '" + key + "'."});
+          if(Gun.is(msg.$) && user && user.is && pub === user.is.pub){
+            /*var other = Gun.obj.map(at.sea.own[soul], function(v, p){
+              if((user.is||{}).pub !== p){ return p }
+            });
+            if(other){
+              each.any(val, key, node, soul);
               return;
-            }
-            // TODO: Ask community if should auto-sign non user-graph data.
-            check['any'+soul+key] = 0;
-            each.end({ok: 1});
-            return;
-          }
-          if(!msg.I){ // only sign data put out from this instance.
-            each.any(val, key, node, soul);
-            return;
-          }
-          if((pub = tmp) !== (user.is||noop).pub){
-            each.any(val, key, node, soul);
+            }*/
+            check['any'+soul+key] = 1;
+            SEA.sign(SEA.opt.prep(tmp = SEA.opt.parse(val), key, node, soul), (user._).sea, function(data){
+              if(u === data){ return each.end({err: 'My signature fail.'}) }
+              node[key] = JSON.stringify({':': SEA.opt.unpack(data.m), '~': data.s});
+              check['any'+soul+key] = 0;
+              each.end({ok: 1});
+            }, {check: SEA.opt.pack(tmp, key, node, soul), raw: 1});
             return;
           }
-          /*var other = Gun.obj.map(at.sea.own[soul], function(v, p){
-            if((user.is||{}).pub !== p){ return p }
-          });
-          if(other){
-            each.any(val, key, node, soul);
-            return;
-          }*/
           check['any'+soul+key] = 1;
-          SEA.sign(SEA.opt.prep(tmp = SEA.opt.parse(val), key, node, soul), (user._).sea, function(data){
-            if(u === data){ return each.end({err: 'My signature fail.'}) }
-            node[key] = JSON.stringify({':': SEA.opt.unpack(data.m), '~': data.s});
+          SEA.verify(SEA.opt.pack(val,key,node,soul), pub, function(data){ var rel;
+            data = SEA.opt.unpack(data, key, node);
+            if(u === data){ return each.end({err: "Mismatched owner on '" + key + "'."}) } // thanks @rogowski !
+            if((rel = Gun.val.link.is(data)) && pub === SEA.opt.pub(rel)){
+              (at.sea.own[rel] = at.sea.own[rel] || {})[pub] = true;
+            }
             check['any'+soul+key] = 0;
             each.end({ok: 1});
-          }, {check: SEA.opt.pack(tmp, key, node, soul), raw: 1});
+          });
         }
         each.end = function(ctx){ // TODO: Can't you just switch this to each.end = cb?
           if(each.err){ return }
@@ -207,7 +194,7 @@
           if(Gun.obj.map(check, function(no){
             if(no){ return true }
           })){ return }
-          msg.user = at.user; // already been through firewall, does not need to again on out.
+          (msg._||{}).user = at.user || security; // already been through firewall, does not need to again on out.
           to.next(msg);
         };
         Gun.obj.map(msg.put, each.node);
@@ -248,7 +235,7 @@
       }
     }
     SEA.opt.shuffle_attack = 1546329600000; // Jan 1, 2019
-    var noop = {}, u;
+    var noop = function(){}, u;
     var fl = Math.floor; // TODO: Still need to fix inconsistent state issue.
     var rel_is = Gun.val.rel.is;
     // TODO: Potential bug? If pub/priv key starts with `-`? IDK how possible.

Some files were not shown because too many files changed in this diff