Massive directory cleanup, more reliable transport

This commit is contained in:
Mark Nadal 2014-12-06 15:26:00 -08:00
parent f27f330131
commit 221b9385d7
68 changed files with 3015 additions and 1554550 deletions

View File

@ -1,3 +0,0 @@
For information about action hooks supported by OpenShift, consult the documentation:
http://openshift.github.io/documentation/oo_user_guide.html#the-openshift-directory

View File

@ -1,23 +0,0 @@
Run scripts or jobs on a periodic basis
=======================================
Any scripts or jobs added to the minutely, hourly, daily, weekly or monthly
directories will be run on a scheduled basis (frequency is as indicated by the
name of the directory) using run-parts.
run-parts ignores any files that are hidden or dotfiles (.*) or backup
files (*~ or *,) or named *.{rpmsave,rpmorig,rpmnew,swp,cfsaved}
The presence of two specially named files jobs.deny and jobs.allow controls
how run-parts executes your scripts/jobs.
jobs.deny ===> Prevents specific scripts or jobs from being executed.
jobs.allow ===> Only execute the named scripts or jobs (all other/non-named
scripts that exist in this directory are ignored).
The principles of jobs.deny and jobs.allow are the same as those of cron.deny
and cron.allow and are described in detail at:
http://docs.redhat.com/docs/en-US/Red_Hat_Enterprise_Linux/6/html/Deployment_Guide/ch-Automating_System_Tasks.html#s2-autotasks-cron-access
See: man crontab or above link for more details and see the the weekly/
directory for an example.
PLEASE NOTE: The Cron cartridge must be installed in order to run the configured jobs.

View File

View File

View File

View File

View File

@ -1,16 +0,0 @@
Run scripts or jobs on a weekly basis
=====================================
Any scripts or jobs added to this directory will be run on a scheduled basis
(weekly) using run-parts.
run-parts ignores any files that are hidden or dotfiles (.*) or backup
files (*~ or *,) or named *.{rpmsave,rpmorig,rpmnew,swp,cfsaved} and handles
the files named jobs.deny and jobs.allow specially.
In this specific example, the chronograph script is the only script or job file
executed on a weekly basis (due to white-listing it in jobs.allow). And the
README and chrono.dat file are ignored either as a result of being black-listed
in jobs.deny or because they are NOT white-listed in the jobs.allow file.
For more details, please see ../README.cron file.

View File

@ -1 +0,0 @@
Time And Relative D...n In Execution (Open)Shift!

View File

@ -1,3 +0,0 @@
#!/bin/bash
echo "`date`: `cat $(dirname \"$0\")/chrono.dat`"

View File

@ -1,12 +0,0 @@
#
# Script or job files listed in here (one entry per line) will be
# executed on a weekly-basis.
#
# Example: The chronograph script will be executed weekly but the README
# and chrono.dat files in this directory will be ignored.
#
# The README file is actually ignored due to the entry in the
# jobs.deny which is checked before jobs.allow (this file).
#
chronograph

View File

@ -1,7 +0,0 @@
#
# Any script or job files listed in here (one entry per line) will NOT be
# executed (read as ignored by run-parts).
#
README

View File

@ -1 +0,0 @@
web: node init.js

741
deps/discrete.js vendored
View File

@ -1,741 +0,0 @@
module.exports=require('theory')((function(){
var discrete = {};
discrete.name = 'discrete';
discrete.author = 'Mark';
discrete.version = 1.2;
root.opts.discrete = root.opts.discrete||{};
discrete.dep = [];
window.jQuery? '': root.opts.discrete.jquery?
discrete.dep.push(root.opts.discrete.jquery) : console.log('Error: Needs jQuery! Include it or assign a path to `root.opts.discrete.jquery`');
discrete.init = (function(a){
console.log('discrete.init');
function the(){ return the };
the.os = (function(){
function os(){ return os };
var ua = navigator.userAgent, lua = a.text.low(ua);
os.is = (function(){
function is(q){
return (q)?(is.win||is.lin||is.mac||is.and||is.ios||"unknown"):is;
} if(root.page){
is.win = (ua.search("Win") >= 0)? "Windows":false;
is.lin = (ua.search("Linux") >= 0)? "Linux":false;
is.mac = (ua.search("Mac") >= 0)? "Macintosh":false
is.and = (lua.search("android") >= 0)? "Android":false
is.ios = (lua.search('ipod') >= 0
|| lua.search('iphone') >= 0
|| lua.search('ipad') >= 0)? "iOS":false
} else {
is.node = true;
} return is;
})();
os.wkv = a.num.dec(a.list(ua.match(/AppleWebKit\/([\d\.]+)/)).at(-1));
if(os.is.and){
var s = '', v = a.list(ua.match(/Android\s+([\d\.]+)/)).at(-1);
a.list(a.num(v).ify([])).each(function(v,i){
s += (v*100+'').slice(0,3);
});
os.version = os.V = a.num.ify(s);
} return os;
})();
the.device = (function(){
function device(){ return device };
device.is = (function(){
function is(){ return is };
is.touch = (('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch); // via Modernizer
is.oriented = ('onorientationchange' in window) || ('orientation' in window);
return is;
})();
device.size = (function(){
function size(){ return size };
size.x = size.width = screen.width;
size.y = size.height = screen.height;
return size;
})();
device.rotate = (function(fn){
if(a.fns.is(fn)){
return a.on('discrete-rotate').event(fn);
}
device.vertical = ($(window).height() > $(document).width())? true : false;
device.horizontal = !device.vertical;
a.on('discrete-rotate').emit();
});
return device;
})();
the.event = (function(){ // TODO: MARK: RE-EXAMINE NOW THAT THEORY SUPPORTS EVENTS.
var event = {}, events = [];
event.arg = (function(args,w,h){
var m = {way:w,how:h};
var jq = a.list(args.o).at(1);
if(jq){
m.where = jq.jquery? jq : $(jq);
m.what = a.text.caps(a.list(args.t).at(1));
}else{
if(args.t.length == 2){
m.what = a.text.caps(a.list(args.t).at(1));
m.where = $(a.list(args.t).at(2));
}else{
m.where = $(a.list(args.t).at(1));
}
}
m.cb = a.list(args.f).at(1);
events.push(m);
return m;
});
event.emit = (function(e){
//console.log("--");
a.list(events).each(function(v,i){
if(v.way && e.way != v.way){
return;
}
if(v.how && e.how != v.how){
return;
}
if(v.what && a.text.caps(e.what) != v.what){
return;
}
//console.log(e.way +" == "+ v.way +" :: "+ e.how +" == "+ v.how +" :: "+ e.what +" == "+ v.what);
if(
v.where[0] == window || v.where.is(document) ||
$(e.where).closest(v.where.selector||v.where).length
){
v.cb(e);
}
});
});
return event;
})();
the.mouse = (function(){
function mouse(){ return mouse; }
mouse.x = 0;
mouse.y = 0;
mouse.left = false;
mouse.right = false;
mouse.move = (function(e){
var m = the.event.arg(a.fns.sort(a.list.slit.call(arguments, 0)),mouse.name,'move');
});
mouse.down = (function(e){
var m = the.event.arg(a.fns.sort(a.list.slit.call(arguments, 0)),mouse.name,'down');
});
mouse.up = (function(h,fn,e){
var m = the.event.arg(a.fns.sort(a.list.slit.call(arguments, 0)),mouse.name,'up');
});
mouse.click = (function(e){
var m = the.event.arg(a.fns.sort(a.list.slit.call(arguments, 0)),mouse.name,'click');
});
mouse.dbl = (function(e){
var m = the.event.arg(a.fns.sort(a.list.slit.call(arguments, 0)),mouse.name,'dbl');
});
mouse.point = (function(s,h,v){ // WARNING! This uses some potentially dangerous tricks which might not work for your page.
var stack = [], d = [], c = 0, e, e_, b = $('body'), scroll = b.scrollTop(), x = true;
if(document.elementFromPoint){
while(x
&& (e=the.mouse.at(h||the.mouse.horizontal,v||the.mouse.vertical))
&& e.style && e.nodeName != 'HTML'
){
if(s && $ && $(e).is(s)){
x = false;
} if(e == e_){
e.style.display = 'none';
} else {
w = e.style.cssText;
e.style.width = e.style.maxWidth = e.style.minWidth =
e.style.paddingLeft = e.style.paddingRight =
e.style.marginLeft = e.style.marginRight =
e.style.mouseStacker = 0;
stack.push(e_=e);
d.push(w)
}
}
} else if(window.event) {
stack.push(window.event.target);
}
a.list(stack).each(function(e,i){
e.style.cssText = d[--i];
});
b.scrollTop(scroll);
return stack;
});
mouse.poke = (function(e,t,c){
if(!e.time && !t){ return 0 }
if(e.time && e.time.scroll != $(document).scrollTop()){ return 0 } // TODO: BUG: Potential? HACK: if scroll pos changed since down, then no go.
c = c || [];
c[0] = c[0] || c[0] === 0? c[0] : the.mouse._x;
c[1] = c[1] || c[1] === 0? c[1] : the.mouse._y;
if(a.time.is() - (t||e.time.up) < the.touch.opt.dbl && (
Math.abs(the.mouse.x - c[0]) <= the.touch.opt.radius
&& Math.abs(the.mouse.y - c[1]) <= the.touch.opt.radius
)){ return 2 }
if(a.time.is() - (t||e.time.down) < the.touch.opt.click && (
Math.abs(the.mouse.x - c[0]) <= the.touch.opt.radius
&& Math.abs(the.mouse.y - c[1]) <= the.touch.opt.radius
)){ return 1 }
return 0;
});
mouse.hold = (function(e,r){
if(!e.time){ return 0 }
if(e.time.scroll != $(document).scrollTop()){ return 0 } // TODO: BUG: Potential? HACK: if scroll pos changed since down, then no go.
if(Math.abs(the.mouse.x - the.mouse._x) <= (r||the.touch.opt.radius)
&& Math.abs(the.mouse.y - the.mouse._y) <= (r||the.touch.opt.radius)
){
return a.time.is() - e.time.down;
} return 0;
});
mouse.which = (function(e){
if(e.way != 'mouse'){ return 'left' }
function left(e){
if (e.which) {
if(e.which == 3) return false;
else if(e.which == 1) return true;
} else if (e.button) {
if(e.button == 2) return false;
else if(e.button == 1) return true;
}
}
function right(e){
return !left(e);
}
if(left(e)) {
mouse.left = true;
return "left";
} else if(right(e)) {
mouse.right = true;
return "right";
}
});
mouse.on = (function(){
var on = {};
on.time = {down:0,up:0};
on.down = (function(e){
if(!e) return false;
e.way = mouse.name;
e.how = 'down';
e.where = e.target;
e.what = mouse.which(e);
e[e.what] = true;
mouse._x = mouse.x;
mouse._y = mouse.y;
mouse.horizontal = e.clientX;
mouse.vertical = e.clientY;
on.time.down = a.time.is();
on.time.scroll = $(document).scrollTop();
the.event.emit(e);
return true; // DETERMINE EXCEPTIONS
});
on.up = (function(e){
if(!e) return false;
e.way = mouse.name;
e.where = e.target;
e.what = mouse.which(e);
e[e.what] = true;
on.poke(e,on.time);
e.how = 'up';
e.time = on.time;
the.event.emit(e,on.time);
on.time.up = a.time.is();
mouse[e.what] = false;
return true;
});
on.move = (function(e){
if(!e) return false;
e.way = mouse.name;
e.how = 'move';
e.where = e.target;
mouse.x_ = mouse.x;
mouse.y_ = mouse.y;
mouse.horizontal = e.clientX;
mouse.vertical = e.clientY;
if(e.pageX || e.pageY){
mouse.x = e.pageX;
mouse.y = e.pageY;
mouse.target = e.target;
} else if(e.clientX || e.clientY){
mouse.x = e.clientX + document.body.scrollLeft
+ document.documentElement.scrollLeft;
mouse.y = e.clientY + document.body.scrollTop
+ document.documentElement.scrollTop;
mouse.target = e.srcElement;
}
the.event.emit(e);
});
on.poke = (function(e,t){ return });
on.click = (function(e,p){
if(!e) return false;
e.how = 'click';
e.where = e.where||e.target;
e.what = mouse.which(e);
e[e.what] = true;
e.way = p? mouse.name : e.way||mouse.name;
the.event.emit(e);
mouse[e.what] = false;
return true;
});
on.dbl = (function(e){
if(!e) return false;
e.way = e.way||mouse.name;
e.how = 'dbl';
e.where = e.where||e.target;
e.what = mouse.which(e);
e[e.what] = true;
the.event.emit(e);
mouse[e.what] = false;
return true;
});
return on;
})();
return mouse;
})();
the.key = (function(){
function key($){
key.$ = $ !== undefined? $ : undefined;
return key;
}
key.e = window.event;
key.is = '';
key._is = '';
key.combo = [];
key.trail = [];
key.opt = {forget:1000};
key.down = (function(h,fn,e){
var m = key.on.arg(key.$, a.fns.sort(a.list.slit.call(arguments, 0)));
m.down = m.cb;
key.on.arch(m,key.on.down_,'-'); // this makes '-' unusuable if we're splitting on it, need to add option for this and handle runs, combos, etc.
});
key.hold = (function(h,fn,e){
var m = key.on.arg(key.$, a.fns.sort(a.list.slit.call(arguments, 0)));
m.hold = m.cb;
key.on.arch(m,key.on.hold_,'-'); // same as above
});
key.up = (function(h,fn,e){
var m = key.on.arg(key.$, a.fns.sort(a.list.slit.call(arguments, 0)));
m.up = m.cb;
key.on.arch(m,key.on.up_,'-'); // same as above
});
key.on = (function(m){
var on = {}, level = [], arch;
on.arg = (function(k, args){
var m = {};
m.key = k || a.text.caps(a.list(args.t).at(1));
m.key = (m.key === '')? 'all' : m.key;
m.cb = a.list(args.f).at(1);
var jq = a.text.caps(a.list(args.o).at(1));
if(jq){
m.jq = jq.jquery? jq : $(jq);
}else{
jq = a.text.caps(a.list(args.t).at(2));
jq = (jq === 'DOCUMENT')? window.document : (jq === 'WINDOW')? window : '';
m.jq = $(jq);
}
return m;
});
on.down = (function(e){
if(!e) return false;
e.way = key.name;
e.where = e.target;
e.code = e.keyCode;
e.tag = e.key = key._is = a.text.caps(key.tag(e));
key.e = e;
e.how = 'hold';
key.on.emit(e,key.on.hold_);
if(key.on[key._is]) return a("key.tame->")();
key.e.how = e.how = 'down';
key.on[key.is = key._is] = true;
key.on.emit(e,key.on.down_);
key.combo.push(key.is);
key.trail.push(key.is);
key.trail = key.trail.slice(-12);
return a(the,"key.tame->")(e);
});
on.up = (function(e){
if(!e) return false;
e.way = key.name;
e.how = 'up';
e.where = e.target;
e.code = e.keyCode;
e.tag = e.key = key.is_ = a.text.caps(key.tag(e));
key.e = e;
key.on[key.is_] = false;
key.combo = a.list(key.combo).each(function(v,i,t){
if(v === key.is_){ return }
t(v);
})||[];
key.on.emit(e,key.on.up_);
key.is = '';
return true; // DETERMINE EXCEPTIONS
});
on.arch = (function(m,w,s){
var arch = w, al;
m.key = a.text.caps(m.key);
al = m.key.split(s);
a.list(al).each(function(u,h){
if(!a.obj.get(arch,u)){
if(al.length == h){
arch[u] = {map:m};
}else{
arch[u] = {};
}
}
arch = arch[u];
});
});
on.emit = (function(e,w){
var r;
a(w,'ALL.map.'+e.how+'->')(e);
arch = a.list(level).at(-1)||w;
if(r = arch[e.tag]){
a.time.stop(on.forget);
a(r,'map.'+e.how+'->')(e);
if(a.obj(r).each(function(v,i){
if(a.obj.is(v) && i != 'map') return true;
})){
level.push(r);
}
on.forget = a.time.wait(function(){
level = [];
},key.opt.forget);
return;
}
});
on.forget;
on.down_ = {};
on.hold_ = {};
on.up_ = {};
return on;
})();
key.tag = (function(code){
if(!code) return false;
code = (code.keyCode)?code.keyCode:code;
code = (typeof code == 'number')? 'kc'+code:code;
return key.special[code] || String.fromCharCode(a.num.ify(code.substring(2)));
});
key.code = (function(tag){
if(!tag) return false;
return (key.special[tag.toLowerCase()])? key.special[tag.toLowerCase()] : a.text.caps(tag).charCodeAt(0);
});
key.tame = function(){return !(key._is in key.strange)};
key.strange = {' ':1,ERASE:1};
key.reserved = {Z:1,X:1,C:1,V:1,R:1,T:1,N:1,F12:1,F11:1,PU:1,PD:1,pu:1,pd:1}; // reserved keys
key.special = {
'esc':27
,'kc27': 'esc'
,'tab':9
,'kc9':'tab'
,' ':32
,'kc32':' '
,'enter':13
,'kc13':'enter'
,'erase':8
,'kc8': 'erase'
,'kc92':'\\'
,'\\':92
,'scroll':145
,'kc145':'scroll'
,'caps':20
,'kc20':'caps'
,'num':144
,'kc144':'num'
,'pause':19
,'kc19':'pause'
,'insert':45
,'kc45':'insert'
,'home':36
,'kc36':'home'
,'delete':46
,'kc46':'del'
,'end':35
,'kc35':'end'
,'pu':33
,'kc33':'pu'
,'pd':34
,'kc34':'pd'
,'left':37
,'kc37':'left'
,'up':38
,'kc38':'up'
,'right':39
,'kc39':'right'
,'down':40
,'kc40':'down'
,'shift':16
,'kc16':'shift'
,'ctrl':17
,'kc17':'ctrl'
,'alt':18
,'kc18':'alt'
,'¤':91
,'cmd':91
,'kc91':((the.os.is.win||the.os.is.lin||the.os.is.and)?'¤':'cmd')
,'kc91':'['
,'[':91
,'kc93':']'
,']':93
,'kc126':'`'
,'`':126
,'kc95':'-'
,'-':95
,'kc61':'='
,'=':61
,'kc59':';'
,';':59
,'kc222':"'"
,"'":222
,'kc47':'/'
,'/':47
,'kc62':'.'
,'.':62
,'kc44':','
,',':44
,'f1':112
,'kc112':'F1'
,'f2':113
,'kc113':'F2'
,'f3':114
,'kc114':'F3'
,'f4':115
,'kc115':'F4'
,'f5':116
,'kc116':'F5'
,'f6':117
,'kc117':'F6'
,'f7':118
,'kc118':'F7'
,'f8':119
,'kc119':'F8'
,'f9':120
,'kc120':'F9'
,'f10':121
,'kc121':'F10'
,'f11':122
,'kc122':'F11'
,'f12':123
,'kc123':'F12'
};
return key;
})();
the.touch = (function(){
var touch = {};
a.log(touch.name = 'touch');
touch.opt = {
click: 250
,dbl: 500
,radius: 50
,mouse: true
,react: true
}
touch.count = 0;
touch.point = [{},{},{},{},{},{},{},{},{},{},{}];
touch.move = (function(e){
var m = the.event.arg(a.fns.sort(a.list.slit.call(arguments, 0)),touch.name,'move');
});
touch.down = (function(e){
var m = the.event.arg(a.fns.sort(a.list.slit.call(arguments, 0)),touch.name,'down');
});
touch.up = (function(e){
var m = the.event.arg(a.fns.sort(a.list.slit.call(arguments, 0)),touch.name,'up');
});
touch.gest = (function(b,c,fn){
var gest = {};
a.log(gest.name = 'gest');
gest.angle = 0;
gest.scale = 1.0;
gest.start = (function(e){
});
gest.morph = (function(e){
gest.angle = e.rotation;
gest.scale = e.scale;
$(document).trigger('touch/gest/morph');
});
gest.end = (function(e){
});
return gest;
})();
touch.time = {down:0,up:0};
touch.on = (function(){
var on = {};
on.down = (function(e){
the.mouse.target = false;
var multi = e.touches || [{}], on = e.changedTouches;
the.mouse._x = the.mouse.x_ = the.mouse.x = multi[0].pageX;
the.mouse._y = the.mouse.y_ = the.mouse.y = multi[0].pageY;
the.mouse.horizontal = multi[0].clientX;
the.mouse.vertical = multi[0].clientY;
touch.count = multi.length;
a.list(multi).each(function(v,i){
v._x = v.x_ = v.x = v.pageX;
v._y = v.y_ = v.y = v.pageY;
touch.point[v.id = i] = v||{};
});
e.way = touch.name;
e.what = touch.count;
e.where = multi[0].target;
e.stun = jQuery.Event.stun;
e.stop = jQuery.Event.stop;
e.how = 'down';
touch.time.down = a.time.is();
touch.time.scroll = $(document).scrollTop();
the.event.emit(e);
});
on.move = (function(e){
var multi = e.touches || [{}];
the.mouse.x = the.mouse.x_ = multi[0].pageX;
the.mouse.y = the.mouse.y_ = multi[0].pageY;
the.mouse.horizontal = multi[0].clientX;
the.mouse.vertical = multi[0].clientY;
a.list(multi).each(function(v,i){
v.x = v.x_ = v.pageX;
v.y = v.y_ = v.pageY;
if(!v.id) touch.point[v.id = i] = v||{}; // Android does not update without this.
});
e.way = touch.name;
e.how = 'move';
e.where = multi[0].target;
e.what = touch.count;
e.stun = jQuery.Event.stun;
e.stop = jQuery.Event.stop;
the.event.emit(e);
});
on.up = (function(e){
var t = a.time.is(), multi = e.changedTouches;
e.what = touch.count;
if((touch.count = multi.length) == 0){
touch.point = [{},{},{},{},{},{},{},{},{},{},{}];
}
e.way = touch.name;
e.where = multi[0].target;
e.stun = jQuery.Event.stun;
e.stop = jQuery.Event.stop;
if(touch.count === 1){ the.mouse.on.poke(e,touch.time) }
e.how = 'up';
e.time = touch.time;
the.event.emit(e);
touch.time.up = a.time.is();
});
return on;
})();
touch.feel = (function(e){
touch.opt.react = e = a.bi.is(e)?e:!touch.opt.react;
if(e){
try{
document.addEventListener("touchmove", touch.on.move, true);
document.addEventListener('touchstart', touch.on.down, true);
document.addEventListener('touchend', touch.on.up, true);
document.addEventListener("gesturechange", touch.gest.morph, true);
document.addEventListener('gesturestart', touch.gest.start, true);
document.addEventListener('gestureend', touch.gest.end, true);
}catch(e){
}
} else {
console.log('touchless ?');
try{
document.removeEventListener("touchmove", touch.on.move, true);
document.removeEventListener('touchstart', touch.on.down, true);
document.removeEventListener('touchend', touch.on.up, true);
document.removeEventListener("gesturechange", touch.gest.morph, true);
document.removeEventListener('gesturestart', touch.gest.start, true);
document.removeEventListener('gestureend', touch.gest.end, true);
}catch(e){
}
}
});
return touch;
})();
the.drag = (function(){
var drag = {};
a.log(drag.name = 'drag');
drag.enter = (function(e){
$(document).trigger('dragenter',[e]);
});
drag.over = (function(e){
$(document).trigger('dragover',[e]);
});
drag.drop = (function(e){
$(document).trigger('mousemove',[e]);
$(document).trigger('dragdrop',[e]);
e.preventDefault();
return false;
});
drag.change = (function(e){
$(document).trigger('dragchange',[e]);
});
return drag;
})();
the.doc = doc = {}
/** -------- INITIATE JQUERY BINDINGS -------- **/
if(root.page){
$(document).ready(function(){
jQuery.Event.stun = (function(e){(e||this).preventDefault();return (e||this)});
jQuery.Event.stop = (function(e){(e||this).stopPropagation();return (e||this)});
jQuery.Event.prototype.stun = jQuery.Event.stun;
jQuery.Event.prototype.stop = jQuery.Event.stop;
$(document).scroll(function(e){
//the.touch.scroll = a.time.is(); iOS calls scroll after touch/mouse events.
}).mousemove(function(e,el){
if(el) e = el;
if(!e) var e = window.event;
e.stopPropagation();e.preventDefault();
the.mouse.on.move(e);
}).mousedown(function(e){
if(!e) var e = window.event;
if(the.mouse.on.down(e)){
return true;
}
e.stopPropagation();e.preventDefault();
}).mouseup(function(e){
if(!e) var e = window.event;
if(the.mouse.on.up(e)){
return true;
}
e.stopPropagation();e.preventDefault();
}).click(function(e){ // iOS only emits on clickable elements
the.mouse.on.click(e);
}).dblclick(function(e){
the.mouse.on.dbl(e);
}).keydown(function(e){
if(the.key.on.down(e)){ return true }
}).keyup(function(e){
if(the.key.on.up(e)){ return true }
});
/** -- DEFAULT SETTINGS -- **/
$(document).on('focus',"textarea, input, [contenteditable=true]",function(){
the.key.combo = []; // iOS not trigger 'keyup' sometimes on input exits, so clear combo manually.
the.key.tame = function(){return true};
}).on('blur',"textarea, input, [contenteditable=true]",function(){
the.key.combo = []; // iOS not trigger 'keyup' sometimes on input exits, so clear combo manually.
the.key.tame = function(){return false}; // PREVENT UNLOAD & SCROLL BOTTOM
});
(document.body||{}).onorientationchange = the.device.rotate;
});
(function(window){
the.touch.feel(the.touch.opt.react);
try{
document.addEventListener('dragenter', the.drag.enter, false);
document.addEventListener("change", the.drag.change, false);
document.addEventListener('drop', the.drag.drop, false);
document.addEventListener('dragover', the.drag.over, false);
}catch(e){console.log("drag fail", e);};
function afocus(e){
if(e) if(e.target != window) return true;
the.key.combo = [];
};
document.onfocusin = afocus;
window.onfocus = afocus;
})(window);
}
return the;
});
return discrete;
})());

2
deps/jquery.js vendored

File diff suppressed because one or more lines are too long

30
deps/key/LTIE9.css vendored
View File

@ -1,30 +0,0 @@
/* IE6 POSITON: FIXED; FLICKER: NONE; */
*html body,*html html{background-image:url(about:blank);background-attachment:fixed;}
*html #keys-top{
position: absolute;
top:expression(eval(document.compatMode&&document.compatMode=='CSS1Compat')?
documentElement.scrollTop+((0))
:document.body.scrollTop+((0)));
}
*html #keys-main{
position: absolute;
top:expression(eval(document.compatMode&&document.compatMode=='CSS1Compat')?
documentElement.scrollTop+((documentElement.clientHeight-this.clientHeight))
:document.body.scrollTop+((document.body.clientHeight-this.clientHeight)));
}
*html #keyboard {
position: fixed;
padding: 0;
margin: 0;
width: auto;
height: auto;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
.keyboard li {
background: black;
background: white;
}

151
deps/key/key.css vendored
View File

@ -1,151 +0,0 @@
#keyface{
z-index: 99999999;
}
#keyput {
display: none;
text-align: center;
width: 240px;
margin-left: -120px;
padding: .5em 0;
border: none;
z-index: 9999;
background-color: rgba(100%,100%,100%,.65);
border-radius: 7px;
-moz-border-radius: 7px;
-webkit-border-radius: 7px;
-moz-box-shadow: #6FA1D9 0px 0px 10px -2px inset;
-webkit-box-shadow: #6FA1D9 0px 0px 10px -2px inset;
box-shadow: #6FA1D9 0px 0px 10px -2px inset;
}#keyput:focus {
outline: none;
}
#keyboard, .keyboard {
position: fixed;
height: 100%;
width: 0px;
bottom: 0px;
left: 50%;
right: 50%;
z-index: 99999999;
font-family: 'Trebuchet MS', sans-serif;
text-rendering: optimizeLegibility;
}
.key-a {
cursor: pointer;
}
.punc {
display: none;
}
.key-offset {
visibility: hidden;
}
.keyboard ul {
position:relative;
list-style-type: none;
clear: both;
margin: 0;
padding: 0;
d-isplay: none;
}
.keyboard li, .keyboard .key {
display: none;
float:left;
min-width: 2em;
padding: .4em .4em;
margin: .2em;
text-align: center;
text-shadow: none;
border-radius: 7px;
-moz-border-radius: 7px;
-webkit-border-radius: 7px;
-moz-box-shadow: #6FA1D9 0px 0px 10px -2px;
-webkit-box-shadow: #6FA1D9 0px 0px 10px -2px;
box-shadow: #6FA1D9 0px 0px 10px -2px;
color: white;
background-color: rgba(0,0,0,.75);
color: #999;
background-color: rgba(100%,100%,100%,.65);
}
#keys-top {
position: fixed;
top: 0;
overflow: visible;
b-ackground: rgba(0,0,0,.5);
}
#keys-main {
position: fixed;
width: 100%;
padding: 0;
right: 0;
bottom: 0;
left: 0;
overflow: visible;
b-ackground: rgba(0,0,0,.5);
max-height: 150px; /* Bug? Prevent Jumpyness */
}
#keys-left {
position: absolute;
left: 0;
bottom: 0;
z-index: 0;
b-ackground: green;
}
#keys {
text-align: center;
z-index: 1;
b-ackground: blue;
}
#keys-right {
position: absolute;
right: 0;
bottom: 0;
z-index: 0;
b-ackground: red;
}
.key-rowR {
float: right;
}
.key-bumpL {
margin-left: -35px;
}
.key-mtextc {
margin: 0px;
text-align: center;
}
#instr {
text-align: center;
font-family: 'Trebuchet MS', sans-serif;
text-rendering: optimizeLegibility;
text-shadow: 10px 10px 25px rgba(100%,100%,100%,.9)
,-5px -5px 25px rgba(100%,100%,100%,.9)
,-5px 10px 25px rgba(100%,100%,100%,.9)
,10px -5px 25px rgba(100%,100%,100%,.9);
box-shadow: none;
color: white;
color: black;
background: rgba(0,0,0,.25);
background: transparent;
font-size: 12pt;
padding: 2px 0px;
}
.hide {
display: none;
}
.show {
display: block;
}

131
deps/key/key.html vendored
View File

@ -1,131 +0,0 @@
<!DOCTYPE html>
<html>
<body>
<div id="keyboard" class="keyboard" style="display: none;">
<!--[if lt IE 9]>
<link rel="stylesheet" href="/+/key/LTIE9.css">
<![endif]-->
<div id="keys-top">
<ul id="kt1">
<li id="kc27" class="alphanum lhand">esc</li>
<li id="kc112" class="alphanum lhand">F1</li>
<li id="kc113" class="alphanum lhand">F2</li>
<li id="kc114" class="alphanum lhand">F3</li>
<li id="kc115" class="alphanum lhand">F4</li>
<li id="kc116" class="alphanum lhand">F5</li>
<li id="kc117" class="alphanum lhand">F6</li>
<li id="kc118" class="alphanum rhand">F7</li>
<li id="kc119" class="alphanum rhand">F8</li>
<li id="kc120" class="alphanum rhand">F9</li>
<li id="kc121" class="alphanum rhand">F10</li>
<li id="kc122" class="alphanum rhand">F11</li>
<li id="kc123" class="alphanum rhand">F12</li>
</ul>
<ul id="kt2" class="key-bumpL">
<li style="min-width: 1.9em;" id="kc126">`</li>
<li id="kc49" class="alphanum lhand">1</li>
<li id="kc50" class="alphanum lhand">2</li>
<li id="kc51" class="alphanum lhand">3</li>
<li id="kc52" class="alphanum lhand">4</li>
<li id="kc53" class="alphanum lhand">5</li>
<li id="kc54" class="alphanum lhand">6</li>
<li id="kc55" class="alphanum rhand">7</li>
<li id="kc56" class="alphanum rhand">8</li>
<li id="kc57" class="alphanum rhand">9</li>
<li id="kc48" class="alphanum rhand">0</li>
<li id="kc95" class="alphanum rhand">-</li>
<li id="kc61" class="alphanum rhand">=</li>
<li class="mod" style="text-align: right; min-width: 3.5em;" id="kc8">erase</li>
</ul>
</div>
<div id="keys-main">
<div id="keys-left">
<ul id="kl1">
<li class="mod" style="text-align: left; min-width: 3.2em;" id="kc9">tab</li>
</ul>
<ul id="kl2">
<li class="mod" style="text-align: left; min-width: 3.75em;" id="kc20">caps</li>
</ul>
<ul id="kl3">
<li class="mod" style="text-align: left; min-width: 5.3em;" id="kc16">shift</li>
</ul>
<ul id="kl4">
<li class="mod" style="text-align: left; min-width:50px" id="kc17">ctrl</li>
<li class="mod" style="min-width: 3.2em;" id="kc91">&curren;</li>
<li class="mod" style="min-width: 3.2em;" id="kc18">alt</li>
</ul>
</div>
<div id="instr" class="key-mtextc">
<span class="instr"></span>
</div>
<div id="keys">
<ul id="kp1">
<li id="kc81" class="alphanum lhand">Q</li>
<li id="kc87" class="alphanum lhand">W</li>
<li id="kc69" class="alphanum lhand">E</li>
<li id="kc82" class="alphanum lhand">R</li>
<li id="kc84" class="alphanum lhand">T</li>
<li id="kc89" class="alphanum rhand">Y</li>
<li id="kc85" class="alphanum rhand">U</li>
<li id="kc73" class="alphanum rhand">I</li>
<li id="kc79" class="alphanum rhand">O</li>
<li id="kc80" class="alphanum rhand">P</li>
<li id="kc91" class="alphanum rhand punc">[</li>
<li id="kc93" class="alphanum rhand punc">]</li>
<li id="kc92" class="alphanum rhand punc">\</li>
</ul>
<ul id="kp2">
<li class="key-offset" style="min-width:8px;padding:1px;margin:0px;"></li>
<li id="kc65" class="alphanum lhand">A</li>
<li id="kc83" class="alphanum lhand">S</li>
<li id="kc68" class="alphanum lhand">D</li>
<li id="kc70" class="alphanum lhand">F</li>
<li id="kc71" class="alphanum lhand">G</li>
<li id="kc72" class="alphanum rhand">H</li>
<li id="kc74" class="alphanum rhand">J</li>
<li id="kc75" class="alphanum rhand">K</li>
<li id="kc76" class="alphanum rhand">L</li>
<li id="kc59" class="alphanum rhand punc">;</li>
<li id="kc222" class="alphanum rhand punc">'</li>
</ul>
<ul id="kp3">
<li class="key-offset" style="min-width:33px;padding:1px;margin:0px;"></li>
<li id="kc90" class="alphanum lhand">Z</li>
<li id="kc88" class="alphanum lhand">X</li>
<li id="kc67" class="alphanum lhand">C</li>
<li id="kc86" class="alphanum lhand">V</li>
<li id="kc66" class="alphanum lhand">B</li>
<li id="kc78" class="alphanum rhand">N</li>
<li id="kc77" class="alphanum rhand">M</li>
<li id="kc44" class="alphanum rhand punc">,</li>
<li id="kc62" class="alphanum rhand punc">.</li>
<li id="kc47" class="alphanum rhand punc">/</li>
</ul>
<input id="keyput"/>
</div>
<div id="keys-right">
<ul id="kr1" class="key-rowR">
<li class="mod rhand" style="text-align: right; min-width: 4.5em;" id="kc13">enter</li>
</ul>
<ul id="kr2" class="key-rowR">
<li class="mod rhand" style="text-align: right; min-width: 5.9em; float: none;" id="kc16">shift</li>
<li id="kc38" class="arrow">&uarr;</li>
<!--
-->
</ul>
<ul id="kr3" class="key-rowR">
<li class="mod" style="min-width: 3.2em;" id="kc18">alt</li>
<li class="mod" style="min-width: 3.2em;" id="kc91">&curren;</li>
<li class="mod" style="min-width: 3.2em;" id="kc17">ctrl</li>
<li id="kc37" class="arrow">&larr;</li>
<li id="kc40" class="arrow">&darr;</li>
<li id="kc39" class="arrow">&rarr;</li>
<!--
-->
</ul>
</div>
</div>
</div>
</body>
</html>

185
deps/key/key.js vendored
View File

@ -1,185 +0,0 @@
module.exports=require('theory')((function(){
var key = {};
key.name = 'key';
key.author = 'Mark';
key.version = 4;
root.opts.kiwi = root.opts.kiwi||{};
key.deps = ['../discrete'];
key.init = (function(a){
var the = a.discrete || theory.discrete;
$(document).ready(function(){
root.opts.key = root.opts.key || {};
var kf = $("#keyface"), h = root.opts.key.host||'';
if(!kf.length){
$("body").append("<div id='keyface'></div>");
$('head').append('<link rel="stylesheet" href="'+h+'/key/key.css">');
kf = $('#keyface').load(h+"/key/key.html",function(){
r.init();
});
} else {
r.init();
}
});
var doc = {
skin: {
a: {color:'#000'}
,on: {}
,dull: {color:'#999'}
,scale: {
touch: {'font-size':'1.25em'}
,key: {'font-size':'1em'}
}
,slide: {
up: 175
,down: 200
}
}
}, realboard = (function(){ return !the.device.is.oriented })
layout = (function(doc){
var lo = {};
lo.doc = doc||{};
lo.size = {};
lo.kb = $("#keyboard");
lo.kt = $("#keys-top");
lo.km = $("#keys-main");
lo.kl = $("#keys-left");
lo.kr = $("#keys-right");
lo.k = $("#keys");
lo.widths = (function(){
var r = {};
r.lx = lo.width(lo.kl,{max:true,out:true})||0;
r.kx = lo.width(lo.k,{max:true,out:true})||0;
r.rx = lo.width(lo.kr,{max:true,out:true})||0;
r.tx = lo.width(lo.kt,{max:true,out:true})||0;
return r;
});
lo.set = function(e,c){
lo.size.x = $(document).width();
lo.size.o = lo.size.x/2;
lo.size.max = lo.widths();
lo.k.css({ width: lo.size.max.kx, 'margin-left': 'auto', 'margin-right':'auto' });
lo.kt.css({ width: lo.size.max.tx, left: lo.size.o - lo.size.max.tx/2 });
//console.log(lo.size.max.kx);
var bk = lo.k.find("ul.key-row-a").last().find("li:visible").not(".key-offset")
,bkflp = (bk.first().position()||{left:0}).left
,bkfl = (lo.k.offset()||{left:0}).left + bkflp;
//console.log(bkfl +" < "+ lo.size.max.lx);
if(bkfl < lo.size.max.lx){
if(!c && realboard()){
if(lo.size.x <= (lo.size.max.lx - bkflp) + lo.size.max.kx || lo.size.x <= lo.size.max.tx
|| lo.size.x - lo.size.max.rx <= ((bk.last().offset()||{left:0}).left + bk.last().outerWidth(true))
){
lo.kb.find("li:not(.key-a)").hide();
return lo.set(e,true);
}
}
lo.k.css({'margin-left': lo.size.max.lx - bkflp });
}
};
lo.width = function(a,b){
var x = 1, aa = a.children("ul.key-row-a").first(), b = b||{};
b.out = b.out||false;
b.max = b.max||false;
b.filter = b.filter||':visible';
a.children("ul.key-row-a").each(function(){
aa = (aa.children('li'+b.filter).length < $(this).children('li'+b.filter).length)?
((b.max)? $(this) : aa) : ((b.max)? aa : $(this));
});
aa.children('li'+b.filter).each(function(){
x += Math.ceil($(this).outerWidth(b.out)||1);
});
return ++x;
}
lo.track = function(i){
lo.set();
lo.doc.initset = true;
$(window).resize(lo.set);
}
return lo;
}),
r = (function(m){
var k = {};
k.map = (function(o){
var tag, code, s, j, x = 1, d, row, rowi, ul = {}, punc = {}, uls = {}
,npunc = ":not(.punc)", w = $(document).width();
k.go = true;
k.wipe(function(){
k.go = false;
a.obj(o).each(function(v,i){
if(!v || v.key || i === 'tag'){ return }
tag = a.text.caps(i);
code = the.key.code(tag);
tag = $.isFunction(v.tag)? v.tag() : (v.tag||v||undefined);
j = $("#kc"+code).show().addClass('key-a').css(doc.skin.a).html(tag);
//console.log(" - "+j.outerWidth(true));
row = j.closest('ul').addClass('key-row-a');
d = d || row;
rowi = row.attr('id');
ul[rowi] = row;
if(j.is('.punc')){
npunc = "";
}
});
if(realboard()){
//x = layout.width(,{out:true,filter: npunc});
a.obj(ul).each(function(v,i){
d = (d.children('li'+npunc).length < v.children('li'+npunc).length)?
v : d;
});
(d||$()).children("li"+npunc).each(function(){ // + npunc possibly wrong! actually most def is.
x += Math.ceil($(this).outerWidth(true)||1);
});
}
a.obj(ul).each(function(v,i){
if(realboard() && x < w){
v.children('li'+npunc).show();
}
v.slideDown(doc.skin.slide.down);
});
k.layout();
});
return true;
});
k.wipe = (function(fn){
if(!k || !k.b){ return }
if(!k.on){ k.on = k.b.show() }
k.$put.blur().hide().val('');
var c = 0, l;
l = k.$rows.stop(true,true).removeClass('key-row-a').removeAttr('style').length;
k.$rows.slideUp(doc.skin.slide.up,function(){
$(this).empty().append(k.row[$(this).attr('id')].clone());
}).promise().done(fn);
});
k.instr = (function(s){
if(!s) return false;
k.$instr.stop(true,true).slideUp(function(){
k.$instr.slideDown().children('.instr').html(s).show();
});
return;
});
k.row = {};
k.clone = (function(){
k.$rows.each(function(){
k.row[$(this).attr('id')] = $(this).contents().clone();
});
});
k.init = (function(){
k.on = false;
k.b = $("#keyboard");
k.$rows = $("#keyboard ul");
k.$instr = $("#instr");
k.$put = $("#keyput");
$(document).trigger('keyboard');
k.clone();
k.lo = layout(doc);
k.lo.track();
});
k.layout = (function(){
k.lo && k.lo.set && k.lo.set();
});
return k;
});r=r();
return r;
});
return key;
})());

928
deps/theory.js vendored
View File

@ -1,928 +0,0 @@
/** THEORY **/
;var theory=theory||null;if(theory){root.init()}else{
theory=(function(b,c,fn){
function theory(b,c){
var a = (function(b,c){
var a = a||theory, l = arguments.length;
if(l == 1){
if(a.text.is(b)){
return a.obj.get(a,b);
}
} if(l == 2){
if(a.text.is(c)){
return a.obj.get(b,c);
}
}
});
if(this && theory.bi.is(this)){ return theorize(a) }
return a(b,c);
} var $, _;
function theorize(a){
var $=undefined,_=undefined;
a.log = (function(s){
//console.log(s);
return a.log;
});
a.fns = (function(){
function fns($){
fns.$_ = $ !== undefined? $ : _;
return fns;
} var $;
fns.is = (function(fn){
$ = fns.$_;fns.$_=_;fn = $||fn;
return (fn instanceof Function)? true : false;
});
fns.flow = (function(s,f){ // TODO: BUG: Seriously reconsider then().done() because they fail on .end() after a synchronous callback, provide no doc or support for it until you do.
var t = (function(){
var args = a.list.slit.call(arguments,0), n;
args.push(t);
n = (function(){
(t.list[t.i++] || t.end).apply(t,args);
})();
return t;
}), list = a.list.is(s)? s : a.list.is(f)? f : 0;
f = a.fns.is(f)? f : a.fns.is(s)? s : function(){};
t.end = list? f : function(){}; // TODO: Receives `next` as param, is this desirable?
t.then = (function(fn){
if(a.fns.is(fn)){ t.list.push(fn) }
return t;
});
t.done = (function(fn){
t.end = a.fns.is(fn)? fn : t.end;
return t;
});
t.list = list || [];
t.i = 0;
if(list){ t() }
else{ f(t) }
return t;
});
fns.sort = (function(args){
if(!args){ return {e:"Empty"} }
var args = a.list.slit.call(args, 0), r = {b:[],n:[],t:[],l:[],o:[],f:[]};
for(var i = 0; i < args.length; i++){
if (fns.is(args[i])){
r.f.push(args[i]);
} else if(a.list.is(args[i])){
r.l.push(args[i]);
} else if(a.obj.is(args[i])){
r.o.push(args[i]);
} else if(a.num.is(args[i])){
r.n.push(args[i]);
} else if(a.text.is(args[i])){
r.t.push(args[i]);
} else if(a.bi.is(args[i])){
r.b.push(args[i]);
}
}
return r;
});
fns.$ = (function(t,v){
v = t.$;
t.$=_;
return v;
});
fns.pass = (function(fn,o){
$ = fns.$_;fns.$_=_;if($){ o=fn;fn=$ }
if(a.text.is(o)){ var tmp = a(fn,o); o = fn; fn = tmp }
if(!fns.is(fn)){ return _ }
return (function(){
return fn.apply(o, a.list.slit.call(arguments));
});
});
return fns;
})();
a.list = (function(){
function list($){
list.$ = $ !== undefined? $ : _;
return list;
} var $;
list.is = (function(l){
l = a.fns.$(list)||l;
return (l instanceof Array)? true : false;
});
list.slit = Array.prototype.slice;
list.at = (function(l,i,opt){
var r;
if($=a.fns.$(list)){ opt=i;i=l;l=$ }
if(!l||!i){ return undefined }
if(a.text.is(l)){ l = l.split('') }
if(i < 0){
r = l.slice().reverse();
i = Math.abs(i);
} opt = opt || {};
if(opt.ebb){
for(--i; 0 <= i; i--){ // upgrade to functionalize
if(r && r[i] !== undefined){ return r[i] }
else if(l[i] !== undefined){ return l[i] }
} return undefined;
}
return (r||l)[--i];
});
list.ify = (function(l,opt){
if($=a.fns.$(list)){ opt=l;l=$ }
opt=opt||{};
opt.wedge = opt.wedge||':';
opt.split = opt.split||',';
var r = [];
if(a.list.is(l)){
return l;
} else
if(a.text.is(l)){
var r = new RegExp("\\s*\\"+opt.split+"\\s*",'ig');
return l.split(r);
} else
if(a.obj.is(l)){
a.obj(l).each(function(v,i){
r.push(i+opt.wedge+(a.obj.is(v)? a.text.ify(v) : v));
});
}
return r;
});
list.fuse = (function(l){
var args = a.list.slit.call(arguments, 0), ll;
l = ($=a.fns.$(list))||l;
ll = $? a.fns.sort(args).l : a.fns.sort(args).l.slice(1);
return Array.prototype.concat.apply(l,ll);
});
list.union = list.u = (function(l,ll){ //[1,2,3,4,5] u [3,5,6,7,8] = [1,2,3,4,5,6,7,8]
return not_implemented_yet;
if($=a.fns.$(list)){ ll=l;l=$ }
// yeaaah, try again.
return r;
});
list.intersect = list.n = (function(l,ll){ //[1,2,3,4,5] n [3,5,6,7,8] = [3,5]
return not_implemented_yet;
if($=a.fns.$(list)){ ll=l;l=$ }
// yeaah, try again.
});
list.less = (function(l,s){ // ToDo: Add ability to use a function to determine what is removed.
var args = a.list.slit.call(arguments, 0), sl = s, ls = l;
l = ($=a.fns.$(list))||l;
s = $? args : args.slice(1);
if($ === args.length){ l=ls;s=sl }
sl = s.length;
return a.list(l).each(function(v,i,t){
if(1 == sl && a.test.is(v,s[0])){ return } else
if(a.list(s).each(function(w,j){
if(a.test.is(v,w)){ return true }
})){ return }
t(v);
})||[];
});
list.each = list.find = (function(l,c,t){
if($=a.fns.$(list)){ t=c;c=l;l=$ }
return a.obj.each(l,c,t);
});
list.copy = (function(l){
return a.obj.copy( ($=a.fns.$(list))||l );
});
list.index = 1;
return list;
})();
a.obj = (function(){
function obj($){
obj.$ = $ !== undefined? $ : _;
return obj;
} var $;
obj.is = (function(o){
o = a.fns.$(obj)||o;
return (o instanceof Object && !a.list.is(o) && !a.fns.is(o))? true : false;
});
obj.ify = (function(o){
o = a.fns.$(obj)||o;
if(a.obj.is(o)){ return o }
try{
o = JSON.parse(o);
}catch(e){o={}};
return o;
});
obj.empty = (function(o){
if(!(o = a.fns.$(obj)||o)){ return true }
return obj.each(o,function(v,i){
if(i){ return true }
})? false : true;
});
obj.copy = (function(o,r,l){
if(!r){
o = a.fns.$(obj) || o;
} l = a.list.is(o);
if(r && !a.obj.is(o) && !l){ return o }
r = {}; o = a.obj.each(o,function(v,i,t){
l? t(obj.copy(v,true)) : (r[i] = obj.copy(v,true));
})||[];
return l? o : r;
});
obj.union = obj.u = (function(x,y){
var args = a.list.slit.call(arguments, 0), r = {};
if($=a.fns.$(obj)){ y=x;x=$ }
if(a.list.is(x)){ y = x } else
if(a.list.is(y)){ } else {
y = $? args : args.slice(1);
y.splice(0,0,x);
}
a.list(y).each(function(v,i){
a.obj(v).each(function(w,j){
if(a.obj(r).has(j)){ return }
r[j] = w;
});
});
return r;
});
obj.has = (function(o,k){
if($=a.fns.$(obj)){ k=o;o=$ }
return Object.prototype.hasOwnProperty.call(o, k);
});
obj.each = (function(l,c,_){
if($=a.fns.$(obj)){ _=c;c=l;l=$ }
var i = 0, ii = 0, x, r, rr, f = a.fns.is(c),
t = (function(k,v){
if(v !== undefined){
rr = rr || {};
rr[k] = v;
return;
} rr = rr || [];
rr.push(k);
});
if(a.list.is(l)){
x = l.length;
for(;i < x; i++){
ii = (i + a.list.index);
if(f){
r = _? c.call(_, l[i], ii, t) : c(l[i], ii, t);
if(r !== undefined){ return r }
} else {
if(a.test.is(c,l[i])){ return ii }
}
}
} else if(a.obj.is(l)){
for(i in l){
if(f){
if(a.obj(l).has(i)){
r = _? c.call(_, l[i], i, t) : c(l[i], i, t);
if(r !== undefined){ return r }
}
} else {
if(a.test.is(c,l[i])){ return i }
}
}
}
return f? rr : a.list.index? 0 : -1;
});
obj.get = (function(o,l,opt,f){
if($=a.fns.$(obj)){ l=o;o=$ }
if(a.num.is(l)){ l = a.text.ify(l) }
if(a.list.is(l)){ l = l.join('.') }
if(a.text.is(l)){
f = (l.length == (l = l.replace(a.text.find.__.fn,'')).length)?
undefined : function(){}; l = l.split(a.text.find.__.dot);
} if(!l){ return }
var x = (l||[]).length, r,
deep = (function(o,v){
return a.list(o).each(function(w,j){
if(a.obj(w||{}).has(v)){ return w }
if(a.list.is(w)){ return deep(w,v) }
});
}), get = (function(v,i,t,n){
if(a.list.is(o)){
if(/^\-?\d+$/.test(v)){
n = a.list.index;
v = a.num.ify(v);
} else {
o = deep(o,v);
}
}
if(n || a.obj(o||{}).has(v)){
o = n? a.list(o).at(v) : o[v];
if(i === x - (a.list.index? 0 : 1)){
return f? a.fns.is(o)? o : f : o;
} return;
}
return f || a.test.nil;
}); r = a.list(l).each(get);
return r === a.test.nil? undefined : r;
});
return obj;
})();
a.text = (function(){
function text($){
text.$ = $ !== undefined? $ : _;
return text;
} var $;
text.is = (function(t){
t = (($=a.fns.$(text))!==_)?$:t;
return typeof t == 'string'?true:false;
});
text.get = (function(q){ return });
text.ify = (function(t){
t = (($=a.fns.$(text))!==_)?$:t;
if(JSON){ return JSON.stringify(t) }
return t.toString? t.toString():t;
});
text.random = text.r = (function(l,c){
if($=a.fns.$(text)){ c=l;l=$ } var $ = $||l, s = '';
l = a.num.is($)? $ : a.num.is(c)? c : 16;
c = a.text.is($)? $ : a.text.is(c)? c : '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz';
while(l>0){ s += c.charAt(Math.floor(Math.random()*c.length)); l-- }
return s;
});
text.clip = (function(t,r,s,e){
if($=a.fns.$(text)){ e=s;s=r;r=t;t=$ } // IE6 fails if e === undefined with Mocha
return t = (t||'').split(r), t=a.num.is(e)?t.slice(s,e):t.slice(s), t.join(r);
});
text.find = (function(t){
var regex = {};
a.log(regex.name = t.name+'.find');
regex.is = /[\.\\\?\*\[\]\{\}\(\)\^\$\+\|\,]/ig
regex.special = {'.':1,'\\':1,'?':1,'*':1,'[':1,']':1,'{':1,'}':1,'(':1,')':1,'^':1,'$':1,'+':1,'|':1,',':1}
regex.mail = /^(("[\w-\s]+")|([\w-]+(?:[\.\+][\w-]+)*)|("[\w-\s]+")([\w-]+(?:[\.\+][\w-]+)*))(@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$)|(@\[?((25[0-5]\.|2[0-4][0-9]\.|1[0-9]{2}\.|[0-9]{1,2}\.))((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[0-9]{1,2})\.){2}(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[0-9]{1,2})\]?$)/i;
regex.base64 = new RegExp("^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{4})$");
regex.list = /(,\s|;\s|,|;|\s)/ig;
regex.css = /(.+?):(.+?);/ig;
regex.url = /[-a-zA-Z0-9@:%_\+.~#?&//=]{2,256}\.[a-z]{2,4}\b(\/[-a-zA-Z0-9@:%_\+.~#?&//=]*)?/gi;
regex.ext = /\.([^\.]+)$/i;
regex.ws_ = /\-/ig;
regex.space = /\s/ig;
regex.num = /(\-\d+\.\d+|\d+\.\d+|\-\d+|\d+)/g;
regex['int'] = /(\-\d+|\d+)/g;
regex.__ = { fn: /\-\>$/, dot: /\./ };
return regex;
})(text);
text.caps = (function(t){
t = a.fns.$(text)||t;
t = (text.is(t))?t:"";
return t.toUpperCase();
});
text.low = (function(t){
t = a.fns.$(text)||t;
t = (text.is(t))?t:"";
return t.toLowerCase();
});
return text;
})();
a.num = (function(){
function num($){
num.$ = ($ !== undefined? $ : _);
return num;
} var $;
num.is = (function(n){
n = (($=a.fns.$(num))!==_)?$:n;
return ( (n===0)? true : (!isNaN(n) && !a.bi.is(n) && !a.list.is(n) && !a.text.is(n))? true : false);
});
num.i = (function(n){return parseInt(a.fns.$(num)||n,10)});
num.dec = (function(n){return parseFloat(a.fns.$(num)||n)});
num.ify = (function(n,o){
if(($=a.fns.$(num))!==_){ o=n;n=$ }
var r, l = a.list.is(o);
if(a.list.is(o)){
if(a.num.is(n)){
return [n];
} if(a.text.is(n)){
r = n.match(a.text.find.num) || [];
return a.list(r).each(function(v,i,t){
t(a.num.ify(v));
});
}
}
r = num.dec(n);
if(a.num.is(r)){ return r }
if(!n){ return }
if(a.text.is(n)){
return a.num.ify( (n.match(a.text.find.num)||[])[0] );
}
});
num.random = num.r = (function(l){
l = ((($=a.fns.$(num))!==_)?$:l)||6;
if(a.list.is(l)){ return (Math.floor(Math.random() * (l[1] - l[0] + 1)) + l[0]) }
l = (l<=14)? l : 14;
var n = '9';
for(var i = 0; i < l-1; i++){ n += '0' }
n = a.num.ify(n);
var r = function(){return Math.floor(Math.random()*10)||(l==1?0:r())};
n = Math.floor(r() + Math.pow(Math.random(),Math.random()) * (n));
if(n.toString().length != l){ return num.r(l) }
return n;
});
return num;
})();
a.bi = (function(){
function bi($){
bi.$ = $ !== undefined? $ : _;
return bi;
} var $;
bi.is = (function(b){
b = (($=a.fns.$(bi))!==_)?$:b;
return (b instanceof Boolean || typeof b == 'boolean')?true:false;
});
return bi;
})();
a.on = (function(){
function on($){
on.$ = $ !== undefined? $ : _;
return on;
} var $, events = {}, sort = (function(A,B){
if(!A || !B){ return 0 } A = A.i; B = B.i;
if(A < B){ return -1 }else if(A > B){ return 1 }
else { return 0 }
});
on.emit = (function(){
if(!a.text.is($ = a.fns.$(on))) return;
var e = events[$] = events[$] || (events[$] = []), args = arguments;
if(!(events[$] = a.list(e).each(function(hear, i, t){
if(!hear.fn) return; t(hear);
hear.fn.apply(hear, args);
}))){ delete events[$]; }
});
on.event = (function(fn, i){
if(!a.text.is($ = a.fns.$(on))) return;
var $ = events[$] = events[$] || (events[$] = [])
, e = {fn: fn, i: i || 0, off: function(){ return !(e.fn = false); }};
return $.push(e), $.sort(sort), e;
});
return on;
})();
a.time = (function(){
function time($){
time.$ = $ !== undefined? $ : _;
return time;
}
time.is = (function(t){
t = ($=a.fns.$(time))||t;
return t? t instanceof Date : (+new Date().getTime());
});
time.now = (function(){
var n = a.num.ify((a.time.is().toString())+'.'+a.num.r(4));
return (theory.time.now.last||0) < n? (theory.time.now.last = n) : time.now();
});
time.loop = (function(fn,d){
var args = a.fns.sort(a.list.slit.call(arguments, 0));
return (args.f.length)?setInterval(a.list(args.f).at(1),a.list(args.n).at(1)):_;
});
time.wait = (function(fn,d){
var args = a.fns.sort(a.list.slit.call(arguments, 0));
return (args.f.length)?setTimeout(a.list(args.f).at(1),a.list(args.n).at(1)):_;
});
time.stop = (function(i){
i = ($=a.fns.$(time))||i;
return (clearTimeout(i)&&clearInterval(i))||true;
});
return time;
})();
a.com = (function($){
var com = a.com;
com.$ = $ !== undefined? $ : _;
com.way = com.way||$;$=_;
com.queue = [];
theory.com.queue = theory.com.queue||[];
com.dc = [theory.time.now()];
com.node = (function(opt){
if(!process._events){ process._events = {} }
if(process.send && !process._events.theory){
process._events.theory = (function(m){
com.msg(a.obj.ify(m));
}); process.on('message',process._events.theory);
process.send({onOpen:{readyState:(process.readyState = 1)},mod:module.theory[opt.way]});
com.wire = process;
return;
}
});
com.page = (function(){
com.src = com.src||(window.location.protocol +'//'+ window.location.hostname)
+ ((window.location.port)?':'+window.location.port:'')
+ (com.path||'/com');
var municate = (function(){
if(!window.SockJS){ return }
theory.com.wire = new window.SockJS(com.src);
theory.com.wire.onopen = function(){
theory.com.open&&theory.com.open();
console.log("Communication initiated at "+com.src+" with "+com.wire.protocol+".");
com.drain();
};
theory.com.wire.onmessage = theory.com.municate||function(m){
var fn, m = a.obj.ify(m.data||m);
if(fn = theory.com.asked[m.when]){
if(a.fns.is(fn)){ fn(m) }
delete theory.com.asked[m.when];
return;
}
com.msg(m);
};
theory.com.wire.onclose = function(m){
console.log('close');
theory.com.close&&theory.com.close(m);
};
});
if(theory.com.off || root.opts.com === false){ return }
if(window.SockJS){
municate();
} else {
module.ajax.load(com.url||(location.local+'//cdn.sockjs.org/sockjs-0.3.min.js')
,function(d){municate()});
}
});
com.drain = (function(){
while(theory.com.queue.length > 0){
com.write(theory.com.queue.shift());
}
});
com.write = (function(m,c){
c = c||theory.com.wire;
if(!c || c.readyState !== 1){
theory.com.queue.push(m);
return;
}
if(a.obj.is(m)){
m = a.text(m).ify();
}
//console.log("send --> "+m);
c.send(m);
});
com.init = (function(c){
if(root.node){ com.node({way:c}) }
if(c){ return }
if(root.page){ com.page() }
return com;
});
/** Helpers **/
com.msg = (function(m,c){
theory.obj.get(theory,theory.obj.get(m,'how.way')+'->')(m,c);
});
com.ways = (function(m,w){
var way = w||a.obj.get(m,'how.way')||com.way;
if($=a.fns.$(com)){
way = ($.charAt(0)=='.')?com.way+$:$;
} return m = com.meta(m,way);
});
com.ask = (function(m,f){
if(!a.fns.is(f)){ return }
m = com.ways(m);
delete m.where;
theory.com.asked[m.when] = f;
com.write(m);
});theory.com.asked = theory.com.asked||{};
com.reply = (function(m){
m = com.ways(m);
if(m.how.web){
m.how.way = 'web.reply';
} m.who = m.who||{};
m.who.to = m.who.to||m.who.tid;
com.write(m);
});
com.send = (function(m){
m = com.ways(m);
com.write(m);
});
com.meta = (function(m,opt){
if(!a.obj.is(m)){ m = {what:m} }
var n = {what: (m.what = m.what||{}) };
opt = opt||{c:{}};
if(a.text.is(opt)){ opt = {w:opt,c:{}} }
if(opt.protocol){ opt.c = opt }
a.obj(m).each(function(v,i){
if( i == 'how' || i == 'who' || i == 'what' ||
i == 'when'|| i == 'where'){ return }
n.what[i] = m.what[i] = v; delete m[i];
});
if(!m.how){ n.how={way: opt.w||com.way} }else{
n.how = m.how;
n.how.way = opt.w||m.how.way||com.way;
delete m.how;
} m.how = n.how;
if(!m.when){ n.when=a.time.now() }else{
n.when = m.when;
delete m.when;
} m.when = n.when;
if(!m.who){
if(root.page && !com.who){
n.who = { tid: (com.who=root.who) }
} if(root.node){ n.who = {} }
}else{
if(a.obj.is(m.who)){ n.who=m.who }else{
n.who = {to: m.who}
} if(root.node){
} if(root.page && !com.who){
n.who.tid = com.who = root.who;
} delete m.who;
} m.who = n.who;
if(!m.where){
if(root.page){ if(a.text.is(m.where)){}else{};
} if(root.node){ n.where={pid: process.pid} }
}else{
if(a.obj.is(m.where)){ n.where = m.where }else{
n.where = {at: m.where};
} if(root.node){
if(!a.obj(m.where).has('pid')){ n.where.pid=process.pid }
} delete m.where;
} m.where = n.where;
return n;
}); /** END HELPERS **/
return com;
});
a.test = (function(){
function test($){
if($===undefined && a.fns.is(test.$)){ try{return test.$()}catch(e){return e} }
test.$ = arguments.length? $ : test.nil;
return test;
} test.nil = test.$ = 'ThEoRy.TeSt.NiL-VaLuE';
test._ = (function(r){ r = a.fns.$(test); test.$ = test.nil; return r; });
test.of = (function(t,f){
if(($=test._()) !== test.nil){ f=t;t=$ }
return t instanceof f;
});
test.is = (function(a, b, aStack, bStack){ // modified Underscore's to fix flaws
if(($=test._()) !== test.nil){ b=a;a=$ }
var _ = {isFunction:theory.fns.is
,has:theory.obj.has}, eq = test.is;
aStack = aStack||[]; bStack = bStack||[];
// Identical objects are equal. `0 === -0`, but they aren't identical.
if(a === b){ return a !== 0 || 1 / a == 1 / b }
if(a == null || b == null){ return a === b }
var className = Object.prototype.toString.apply(a);
if(className != Object.prototype.toString.apply(b)){ return false }
switch(className){
case '[object String]': return a == String(b);
case '[object Number]': return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b);
case '[object Function]': return a.name === b.name && a.toString() === b.toString();
case '[object Date]':
case '[object Boolean]': return +a == +b;
case '[object RegExp]': return a.source == b.source && a.global == b.global &&
a.multiline == b.multiline && a.ignoreCase == b.ignoreCase;
}
if(typeof a != 'object' || typeof b != 'object'){ return false }
var length = aStack.length;
while(length--){ if(aStack[length] == a){ return bStack[length] == b} }
aStack.push(a); bStack.push(b);
var size = 0, result = true;
if(className == '[object Array]'){
size = a.length; result = size == b.length;
if(result){
while(size--){
if(!(result = eq(a[size], b[size], aStack, bStack))){ break }
}
}
}else{
var aCtor = a.constructor, bCtor = b.constructor;
if(aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) &&
_.isFunction(bCtor) && (bCtor instanceof bCtor))){ return false }
for(var key in a){
if(_.has(a, key)){
size++;
if(!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))){ break }
}
} if(result){
for(key in b){
if(_.has(b, key) && !(size--)){ break }
} result = !size;
}
}
aStack.pop(); bStack.pop();
return result;
});
return test;
})();
return a;
}
theory.Name = 'theory';
theory.version = 2.5;
theorize(theory);
return theory;
})(true);
/**
BASE
**/
(function(r){
var root = root||{}, a = theory;
root.opts = root.opts || {};
root.deps = {loaded:{},alias:{},all:{},wait:{}};
root.pollute = ((typeof GLOBAL !== 'undefined' && GLOBAL.global && GLOBAL.process &&
GLOBAL.process.env && GLOBAL.process.pid && GLOBAL.process.execPath)?
(function(){
global.node = root.node = true;
global.opts = root.opts;
global.theory = theory;
module.theory = module.theory||{}
process.env.totheory = __filename;
if(process.env.NODE_ENV==='production'){process.env.LIVE = true};
module.path = require('path');
require.sep = module.path.sep;
module.exports=(function(cb,deps,name){
if(!arguments.length) return theory;
var args = a.fns.sort(a.list.slit.call(arguments, 0)), r
,m = util.require.apply({},arguments);
args.file = root.submodule||(module.parent||{}).filename;
global.aname = global.aname||m.name;
a.obj(util.deps(m.dependencies,{flat:{},src:args.file})).each(function(name,path){
var p = require(root.submodule=path=util.resolve(path,path));
m.theory[name] = (theory.obj.is(p) && theory.obj.empty(p))? undefined : p;
});
module.theory[m.name] = a.obj.ify(a.text.ify(m));
var mod = (theory[m.name] = m.init(m.theory));
if(global.aname === m.name && theory.com) theory.com(theory.Name).init(m.name);
return mod;
});
return;
}) : (function(){
root = window.root = window.root||root;
root.page = true;
root.who = root.who||a.list((document.cookie+';').match(/tid=(.+?);/)||[]).at(-1)||'';
window.console = window.console||{log:function(s){return s}};
console.saw = (function(s){console.log(a.text(s).ify())});
location.local=(location.protocol==='file:'?'http:':'');
var noConflict={__dirname: window.__dirname,module:window.module,exports:window.exports,require:window.require};
window.__dirname = '';
window.module = {exports: (window.exports = {})};
window.module.ajax = {load:(function(b,c){
var d=document,j="script",s=d.createElement(j); module.sync=(s.onload===null||!s.readyState)?0:1; // IE6+
var e=2166136261,g=b.length,h=c,i=/=\?/,w=window.setTimeout,x,y,a=function(z){
document.body&&(z=z||x)&&s&&document.body[z]?document.body[y=z](s):w(a,0);
};if(i.test(b)){for(;g--;)e=e*16777619^b.charCodeAt(g);
window[j+=e<0?-e:e]=function(){h.apply(h,arguments);delete window[j]};b=b.replace(i,"="+j);c=0
};s.onload=s.onreadystatechange=function(){if(y&&/de|m/.test(s.readyState||"m")){
c&&c();a(x='removeChild');try{for(c in s)delete s[c]}catch(b){}
}};s.src=b;c&&a(x='appendChild');
})};module.ajax.load('#');
window.module.ajax.code = util.load;
window.onerror = (function(e,w,l){
console.log(e + " at line "+ l +" on "+ w);
//if(theory.com){ theory.com.send({e:e,url:w,line:l}) }
});
window.require = module.require = function require(p){
if(!p){ return require }
if(util.stripify(p) == util.stripify(theory.Name)){
return util.require;
} var fn, c = 0, cb = function(f){ fn = f; };
theory.list((p = theory.list.is(p)? p : [p])).each(function(v){
window.module.ajax.code(v,function(d){++c && (p.length <= c) && fn && fn(d)});
}); return cb;
}; window.require.sep = '/'; require.resolve = util.resolve; require.cache = {};
util.init();
if(root.opts.amd === false){theory.obj(noConflict).each(function(v,i){window[i]=v});}
if(theory.com){ theory.com(theory.Name).init() }
})
);
var util = {};
util.theorize = (function(mod){
mod.theory = theory.call(true);
if(mod.theory.com){ mod.theory.com(mod.name) }
return mod.theory;
});
util.require = (function(){
var mod, args = a.fns.sort(a.list.slit.call(arguments,0))
, fail = {name:'fail',init:(function(){console.log('module failed to load')})};
if(args.o.length === 1 && !args.t.length && !args.l.length){
mod = a.list(args.o).at(1);
} else {
if(args.f.length){
mod = {
name: a.list(args.t).at(1)
,init: a.list(args.f).at(1)
,dependencies: a.list(args.l).at(1) || a.list(args.o).at(1)
}
}
} mod.name = mod.name||fail.name;
mod.init = mod.init||mod.main||mod.start||mod.boot||mod.cb||mod.fn||fail.init;
mod.dependencies = mod.dependencies||mod.require||mod.deps||mod.dep;
mod.dependencies = a.list.is(mod.dependencies)?
a.list(mod.dependencies).each(function(v,i,t){t(v,1)}) : mod.dependencies;
mod.theory = util.theorize(mod);
if(root.node){ return mod }
args = {cb:function(p, opt){
if(args.launched
|| a.list(util.deps(mod.dependencies,{flat:{}})).each(function(v,j){
if(!(i = root.deps.loaded[j])){ return true }
if(i === 2){ return true }
if(i && i.launch && a.text.is(v) && mod.theory[v] === undefined){ mod.theory[v] = i.launch; }
})){ return }
args.on.off();
args.launched = {launch: (theory[mod.name] = mod.init(mod.theory||theory)), n:mod.name};
module.exports = exports = args.launched.launch;
if(mod.src){
root.deps.loaded[mod.src] = args.launched;
theory.on('ThEoRy_DePs').emit();
} return args.launched.launch;
}}; args.on = theory.on('ThEoRy_DePs').event(args.cb);
args.start = function(){util.deps(mod.dependencies,args); return args.cb()}
args.name = function(src){
module.on = args.name = false;
root.deps.alias[args.src = mod.src = src] = mod.name;
if((root.deps.all[src] = mod.dependencies)){
root.deps.loaded[src] = 2;
} if(!window.JSON){module.ajax.load(root.opts.JSON||location.local // JSON shim when needed
+"//ajax.cdnjs.com/ajax/libs/json2/20110223/json2.js",args.start)
} else { return args.start() };
}; module.on = (!(require||{}).ing)? args.name(util.src(1))||false : args.name;
});
util.deps = (function(deps, opt){
opt = opt || {};
a.obj(deps).each(function(v,i){
var path = i, dopt = {p:i};
if(opt.src){
delete deps[i];
deps[path = util.resolve(opt.src, util.pathify(path))] = v;
} if(a.list.is(v)){
delete deps[i];
v = deps[path] = a.list(v).each(function(w,i,t){t(util.resolve(opt.src,util.pathify(w)),1)})
} if(a.obj.is(v)){
dopt.defer = v;
opt.flat && util.deps(v,{flat: opt.flat});
} if(v && a.text.is(v)){
dopt.name = v;
} if(opt.flat){
var url = util.urlify(util.pathify(path));
if((i = opt.flat[url]) && i !== 1){ return }
opt.flat[url] = (opt.sub? 1 : dopt.name) || util.stripify(path);
if(i !== 1 && url && a.text.is(url) && (v = root.deps.all[url])){
(a.obj.is(v) || a.list.is(v)) && util.deps(v,{flat: opt.flat, sub:1});
} return;
} return util.load(path, dopt);
});
return opt.flat;
});
util.urlify = (function(url){ // via SO, IE6+ safe
if(!root.page){ return url; }
var el= document.createElement('div');
el.innerHTML= '<a href="'+url+'">x</a>';
return el.firstChild.href;
});
util.pathify = (function(p){
if(!root.page){ return p; }
return p = (/\.js$/i.test(p))? p : p+'.js';
});
util.stripify = (function(p){
if(!a.text.is(p)){ return ''; } p=p.replace(/^\./,'');
return (p.split(require.sep).reverse()[0]).replace(/\.js$/i,'');
});
util.resolve = (function(p1, p2){ // via browserify
if('.' != p2.charAt(0)){ return p2.replace('/',require.sep) }
var path = p1.replace('/',require.sep).split(require.sep)
, segs = p2.replace('/',require.sep).split(require.sep)
path.pop();
for(var i=0;i<segs.length;i++){
var seg = segs[i];
if('..' == seg){ path.pop() }
else if('.' != seg){ path.push(seg) }
} return path.join(require.sep);
});
util.load = (function(p, opt ,z){
if(util.stripify(p) == util.stripify(theory.Name)){
return util.require;
} opt = opt || {};
{var w=root.deps.wait;if(module.sync){if(!z && !a.obj.empty(w)){
w[p] = opt;if(opt.defer){w=root.deps.wait = a.obj(w).u(opt.defer)}return;
}w[p] = opt;if(opt.defer){w=root.deps.wait = a.obj(w).u(opt.defer)}}}
var path = util.pathify(p), url = util.urlify(path)
, cb = (function(d){
if(false !== d){
console.log(opt.p||p, ' loaded');
root.deps.loaded[url] = 1;
module.on && module.on(url);
theory.fns.is(opt) && opt(d);
} theory.on('ThEoRy_DePs').emit();
!module.sync && opt.defer && util.deps(opt.defer, opt);
{if(module.sync){delete w[p];if(!a.obj(w).each(function(v,i,t){
delete w[i];util.load(i,v,1);return 1;})){w=root.deps.wait = false}}}
}); if(root.deps.loaded[url]
|| root.deps.loaded[url] === 0){
return cb(false);
} root.deps.loaded[url] = 0;
(require||{}).ing=true;
try{window.module.ajax.load(path,cb);}
catch(e){console.log("Network error.")};
console.log('loading', opt.p||p);
});
util.sandbox = (function(s,n){
try{ // via jQuery
(window.execScript || function(s){
window["eval"].call(window, s);
})(s);
}catch(e){
console.log("sandbox fail: "+n);
console.log(e, s);
}
});
util.theorycount = 0;
util.src = (function(){
var s = document.getElementsByTagName('script');
s = (s[s.length-1]||{}).src;
return util.stripify(s) === theory.Name? location : s||location;
});
util.init = (function(r){
if(!root.page){ return }
var z='', s = document.getElementsByTagName('script'), t;
for(var i in s){var v = s[i]; // IE6 fails on each, use for instead
r = v.src||r;
if(v.id || !v.innerHTML || util.stripify(v.src)
!== util.stripify(theory.Name)){ false;
} else { t = v }
} if(t){
util.sandbox(t.innerHTML,'Theory Configuration');
t.id = "theory"+util.theorycount++;
}
return r;
});
root.init = (function(){
root.pollute();
return util.init;
})();
})()};

1
examples/Procfile Normal file
View File

@ -0,0 +1 @@
web: node all.js

View File

@ -59,7 +59,7 @@
</li>
</ul>
<script>
var gun = Gun([location + 'gun']);
var gun = Gun([location.origin + '/gun']);
angular.module('admin', []).controller('editor', function($scope){
$scope.data = {};
$scope.$data = gun.load('blob/data').get(function(data){

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://ajax.cdnjs.com/ajax/libs/json2/20110223/json2.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="../../gun.js"></script>
<script src="old_gun_for_slinger.js"></script>
</head>
<body><center>
<style>

15
examples/all.js Normal file
View File

@ -0,0 +1,15 @@
console.log("If modules not found, run `npm install` in /example folder!"); // git subtree push -P examples heroku master
var port = process.env.OPENSHIFT_NODEJS_PORT || process.env.VCAP_APP_PORT || process.env.PORT || 8888;
var express = require('express');
var app = express();
var Gun = require('gun');
var gun = Gun({
s3: (process.env.NODE_ENV === 'production')? null : require('../test/shotgun') // replace this with your own keys!
});
gun.attach(app);
app.use(express.static(__dirname)).listen(port);
console.log('Server started on port ' + port + ' with /gun');

View File

@ -0,0 +1,76 @@
<!DOCTYPE html>
<html ng-app="admin">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://ajax.cdnjs.com/ajax/libs/json2/20110223/json2.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.js"></script>
<script src="../../gun.js"></script>
</head>
<body ng-controller="editor">
<style>
html, body {
font-family: Verdana, Geneva, sans-serif;
}
a {
color: skyblue;
text-decoration: none;
cursor: poiner;
}
ul, li {
list-style-type: none;
}
ul:hover, li:hover {
list-style-type: inherit;
}
input {
border: none;
border-bottom: dashed 1px gainsboro;
}
.none {
display: none;
}
</style>
<h3>Admin JSON Editor</h3>
This is a live view of your data, you can edit it in realtime or add new key/values.
<ul name="list">
<li ng-repeat="(key, val) in data">
<div ng-if="key != '_'">
<b>{{key}}</b>:
<span contenteditable="true" gun>{{val}}</span>
</div>
</li>
<li>
<form ng-submit="add()">
<label>
<input ng-model="field" placeholder="key" ng-submit="add()">
<a ng-click="add()">add</a>
<input type="submit" class="none"/>
</label>
</form>
</li>
</ul>
<script>
var gun = Gun(location.origin + '/gun');
angular.module('admin', []).controller('editor', function($scope){
$scope.data = {};
$scope.$data = gun.load('blob/data').on(function(data){
Gun.obj.map(data, function(val, field){
if(val === $scope.data[field]){ return }
$scope.data[field] = val;
});
$scope.$apply();
});
$scope.add = function(a,b,c){
$scope.$data.path($scope.field).set( $scope.data[$scope.field] = 'value' );
$scope.field = '';
};
}).directive('gun', function(){
return function(scope, elem){
elem.on('keyup', function(){
scope.$data.path(scope.key).set( scope.data[scope.key] = elem.text() );
});
};
});
</script>
</body>
</html>

View File

@ -2,7 +2,7 @@ var gun = require('gun')({
s3: (process.env.NODE_ENV === 'production')? null : require('../../test/shotgun') // replace this with your own keys!
});
gun.load('email/mark@gundb.io', function(Mark){
gun.load('email/mark@gundb.io').get(function(Mark){
console.log("Hello ", Mark);
this.path('username').set('amark'); // because we hadn't saved it yet!
this.path('cat').get(function(Hobbes){ // `this` is context of the nodes you explore via path

18
examples/hello-world.js Normal file
View File

@ -0,0 +1,18 @@
var Gun = require('gun');
var gun = Gun({
s3: {
key: '', // AWS Access Key
secret: '', // AWS Secret Token
bucket: '' // The bucket you want to save into
}
});
gun.set({ hello: 'world' }).key('my/first/data');
var http = require('http');
http.createServer(function (req, res) {
gun.load('my/first/data', function(err, data){
res.writeHead(200, {'Content-Type': 'application/json'});
res.end(JSON.stringify(data));
});
}).listen(1337, '127.0.0.1');
console.log('Server running at http://127.0.0.1:1337/');

2
examples/node_modules/gun/index.js generated vendored
View File

@ -1 +1 @@
module.exports = require(__dirname + '/../../../shots');
module.exports = require(__dirname + '/../../../index');

17
examples/package.json Normal file
View File

@ -0,0 +1,17 @@
{
"name": "examples",
"main": "all.js",
"description": "Example gun apps"
, "version": "0.0.1"
, "engines": {
"node": "~>0.6.6"
}
, "dependencies": {
"express": "~>4.9.0",
"gun": "~>0.0.8"
}
, "scripts": {
"start": "node all.js",
"test": "mocha"
}
}

15
examples/todo/index.html Normal file
View File

@ -0,0 +1,15 @@
<html>
<head>
<title>ToDo</title>
</head>
<body>
<h1>
Todo List
</h1>
<form name="sign" action="http://localhost:8888/gun">
<input name="email" placeholder="email">
<input name="password" type="password" placeholder="password">
<input type="submit" name="it" value="sign in or up">
</form>
</body>
</html>

View File

@ -1,4 +0,0 @@
```
curl http://randomuser.coolaj86.com/api?seed=rohkevus&results=50000 \
-o users.json
```

View File

@ -1,43 +0,0 @@
'use strict';
var users = require('./users.json').results
, Chance = require('chance')
, chance = new Chance(1234)
, b
, d = Date.now()
, num = 50
;
users = users.map(function(user){
user = user.user;
user._ = user._ || {};
user._['#'] = user.sha1;
user.first = user.name.first;
user.last = user.name.last;
user.title = user.name.title;
delete user.name;
user.zip = user.location.zip;
user.street = user.location.street;
user.city = user.location.city;
user.state = user.location.state;
delete user.location;
return user;
})
users = chance.shuffle(users).slice(0, num);
b = chance.shuffle(users.slice(0));
b.forEach(function (user, i) {
if (0 === (i % 100)) {
console.log((Date.now() - d) / 1000, i);
d = Date.now();
}
user.friends = chance.shuffle(users).slice(chance.integer({ min: 20, max: (num < 120)? num : 120 }));
});
var gun = require('gun')({
s3: require('../test/shotgun') // replace this with your own keys!
});
gun.set(b[0]);
console.log(b[1], b[1].friends.length);
console.log((Date.now() - d) / 1000, num);

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +0,0 @@
/*!
* Amplify Store - Persistent Client-Side Storage 1.1.0
*
* Copyright 2011 appendTo LLC. (http://appendto.com/team)
* Dual licensed under the MIT or GPL licenses.
* http://appendto.com/open-source-licenses
*
* http://amplifyjs.com
*/
(function(a,b){function e(a,e){c.addType(a,function(f,g,h){var i,j,k,l,m=g,n=(new Date).getTime();if(!f){m={},l=[],k=0;try{f=e.length;while(f=e.key(k++))d.test(f)&&(j=JSON.parse(e.getItem(f)),j.expires&&j.expires<=n?l.push(f):m[f.replace(d,"")]=j.data);while(f=l.pop())e.removeItem(f)}catch(o){}return m}f="__amplify__"+f;if(g===b){i=e.getItem(f),j=i?JSON.parse(i):{expires:-1};if(j.expires&&j.expires<=n)e.removeItem(f);else return j.data}else if(g===null)e.removeItem(f);else{j=JSON.stringify({data:g,expires:h.expires?n+h.expires:null});try{e.setItem(f,j)}catch(o){c[a]();try{e.setItem(f,j)}catch(o){throw c.error()}}}return m})}var c=a.store=function(a,b,d,e){var e=c.type;d&&d.type&&d.type in c.types&&(e=d.type);return c.types[e](a,b,d||{})};c.types={},c.type=null,c.addType=function(a,b){c.type||(c.type=a),c.types[a]=b,c[a]=function(b,d,e){e=e||{},e.type=a;return c(b,d,e)}},c.error=function(){return"amplify.store quota exceeded"};var d=/^__amplify__/;for(var f in{localStorage:1,sessionStorage:1})try{window[f].getItem&&e(f,window[f])}catch(g){}if(window.globalStorage)try{e("globalStorage",window.globalStorage[window.location.hostname]),c.type==="sessionStorage"&&(c.type="globalStorage")}catch(g){}(function(){if(!c.types.localStorage){var a=document.createElement("div"),d="amplify";a.style.display="none",document.getElementsByTagName("head")[0].appendChild(a);try{a.addBehavior("#default#userdata"),a.load(d)}catch(e){a.parentNode.removeChild(a);return}c.addType("userData",function(e,f,g){a.load(d);var h,i,j,k,l,m=f,n=(new Date).getTime();if(!e){m={},l=[],k=0;while(h=a.XMLDocument.documentElement.attributes[k++])i=JSON.parse(h.value),i.expires&&i.expires<=n?l.push(h.name):m[h.name]=i.data;while(e=l.pop())a.removeAttribute(e);a.save(d);return m}e=e.replace(/[^-._0-9A-Za-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u37f-\u1fff\u200c-\u200d\u203f\u2040\u2070-\u218f]/g,"-");if(f===b){h=a.getAttribute(e),i=h?JSON.parse(h):{expires:-1};if(i.expires&&i.expires<=n)a.removeAttribute(e);else return i.data}else f===null?a.removeAttribute(e):(j=a.getAttribute(e),i=JSON.stringify({data:f,expires:g.expires?n+g.expires:null}),a.setAttribute(e,i));try{a.save(d)}catch(o){j===null?a.removeAttribute(e):a.setAttribute(e,j),c.userData();try{a.setAttribute(e,i),a.save(d)}catch(o){j===null?a.removeAttribute(e):a.setAttribute(e,j);throw c.error()}}return m})}})(),function(){function e(a){return a===b?b:JSON.parse(JSON.stringify(a))}var a={},d={};c.addType("memory",function(c,f,g){if(!c)return e(a);if(f===b)return e(a[c]);d[c]&&(clearTimeout(d[c]),delete d[c]);if(f===null){delete a[c];return null}a[c]=f,g.expires&&(d[c]=setTimeout(function(){delete a[c],delete d[c]},g.expires));return f})}()})(this.amplify=this.amplify||{})

742
gun.js

File diff suppressed because it is too large Load Diff

577
gun0.js
View File

@ -1,577 +0,0 @@
/**** The Abstact Structure
A JSON graph structure that is lightweight and flexible to describe anything.
The current goal, however, is limited to encompassing HTML and CSS for starters.
Immediately after that is describing code as a state.
A node is something which has relationships and or value.
Relationships and values aren't any different, other than that
a relationship is a reference and a value is embedded.
*****/
module.exports = require('theory')
('gun',function(a){
a.gun = (function(){
function gun(p,v,w){
var args = arguments.length
, cb = a.fns.is(v)? v : null
, g, n, b, w = w || a.time.now();
if(gun.is(this)){
n = this;
g = n._.clip || function(){ return {} };
if(a.text.is(p)){
if(args >= 2){ // set
var u, ref = {}
, val = gun.at(n,p,ref);
if(!ref.cartridge || !ref.cartridge._ || !ref.cartridge._[gun._.id]){
return;
} ref.id = ref.cartridge._[gun._.id] +'.'+ ref.path;
v = gun.ify.be(v);
b = gun.bullet(ref.path,v,w);
console.log("after:", v, b);
if(a.gun.ham){
v = a.gun.ham(ref.cartridge,b,v,w); // TODO: BUG! Need to update when also!
if(v === u){
console.log("HAM REJECTION", p, v, val);
return;
}
}
console.log("HAM set", p, v);
if(ref.at){
if(v === null){
if(a.list.is(ref.at)){
t = o.val || t;
var j = ref.at.indexOf(ref.prop);
if(0 <= j){
ref.at.splice(j,1);
} else {
j = a.list(ref.at).find(gun.id(ref.prop));
if(j){
ref.at.splice(--j,1);
}
}
} else {
delete ref.at[ref.prop];
}
var del = {}; del[ref.id] = null;
gun.fire(del, g[gun._.id], w);
v = ref.at;
} else {
if(a.fns.is(v) && v[gun._.id]){ // then it is a clip!
v = {};
}
v = gun.at(v);
if(gun.is(v)){
v = gun.id(v._[gun._.id]); // update this to handle clip#cart
} else {
v = gun.ify.be(v);
}
if(a.obj.is(v)){
ref.at[ref.prop] = v;
//ref.tmp = ref.at[ref.prop] = gun.ify.obj(v, val);
} else
if(a.list.is(v)){
ref.tmp = ref.at[ref.prop] = gun.ify.list(v, val);
} else {
ref.at[ref.prop] = v;
}
var diff = {}; diff[ref.id] = v;
gun.fire(diff, g[gun._.id], w);
v = ref.tmp || v;
}
return v;
}
return;
}
if(args >= 1){ // get
v = gun.at(n,p);
return v;
}
}
return;
}
n = a.obj.is(v)? v : a.obj.is(p)? p : null;
p = a.text.is(p)? p : gun.id();
if(a.obj.is(n)){ // create a clip from this object
var c;
g = gun.ify(n);
if((c = gun.magazine[p]) && a.fns.is(c)){
console.log("clip already exists in magazine,", p);
a.obj(g).each(function(n,id){
if(!gun.is(n)){ return }
c(id,n);
});
return gun.magazine[p];
}
var clip = gun.magazine[p] = function(p,v,w){
var args, id, path, n, w = w || a.time.now();
if(a.text.is(p)){
id = a.text(p).clip('.',0,1);
path = a.text(p).clip('.',1);
if(a.obj(g).has(id) && gun.is(g[id])){
n = g[id];
p = path;
}
}
args = a.list.slit.call(arguments);
if(!args.length){
return g;
}
if(path){
if(n){
n._.clip = n._.clip || clip;
return gun.apply(n, args);
}
return;
}
var fn = function(p,v,w){
if(!n){ return }
var args = a.list.slit.call(arguments);
return !args.length? n : gun.apply(n,args);
}
if(n){
if(args.length === 1){
n._.clip = n._.clip || clip;
return fn;
}
if(gun.is(v) && gun.ham){
var h = v._[gun._.ham] || {};
a.obj(v).each(function(v,p){
if(p === '_'){ return }
console.log('-------------->', p, h[p], h, 1); // Wait! This isn't correct because it should be '>' not '.'!
fn(p, v, h[p] || (a.num.is(h)? h : 1)); // Wait! This isn't correct because it should be '>' not '.'!
});
return fn;
}
if(v === null){
delete g[n._[gun._.id]];
var del = {}; del[n._[gun._.id]] = n = null;
gun.fire(del, g[gun._.id], w); // TODO: BUG! HAM UPDATES!
return null;
}
return;
}
if(a.text.is(p) && a.obj.is(v)){
v = v;
v._ = gun.id(p);
} else
if(a.obj.is(p)){
v = p;
}
if(a.obj.is(v)){
n = gun.ify(v,u,{}); // a clip cannot be created from this, only a single cartridge
n._ = n._ || gun.id({});
n._.clip = clip; // JSONifying excludes functions.
var add = {}; add[n._[gun._.id]] = g[n._[gun._.id]] = n;
gun.fire(add, clip[gun._.id], w); // TODO: BUG! HAM UPDATES!
return fn;
}
}
clip[gun._.id] = p;
return clip;
}
} var u;
gun._ = {
id: '#' // do not change this!
}
gun.is = function(o){
return (o && o._ && o._[gun._.id])? true : false;
}
gun.id = function(t){
if(t){
var _ = {};_[gun._.id] = a.text.is(t)? t : gun.id();
return _;
}
return a.text.r(9);
}
gun.at = function(n,p,ref){
if(a.fns.is(n)){
n = n();
}
if(!p){
return n;
}
ref = ref || {};
var pp = a.list.is(p)? p : (p||'').split('.')
, g = a.fns.is(n._.clip)? n._.clip() : this
, i = 0, l = pp.length, v = n
, x, y, z;
ref.cartridge = n;
ref.prop = pp[l-1];
ref.path = pp.slice(i).join('.');
while(i < l && v !== u){
x = pp[i++];
if(a.obj.is(v) && a.obj(v).has(x)){
ref.at = v;
v = v[x];
if(v && v[gun._.id]){
v = a.obj(g).has(v[gun._.id])? g[v[gun._.id]] : u;
if(v){
return gun.at.call(g,v,pp.slice(i),ref);
}
}
} else
if(a.list.is(v)){
ref.at = v;
return a.list(v).each(function(w,j){
if(!w) return;
if(!p) return;
w = a.obj(g).has(w[gun._.id]||w)? g[w[gun._.id]||w] : u;
if(!w) return;
if(w._ && x === w._[gun._.id]){
i += 1;
p = false;
}
return gun.at.call(g,w,pp.slice(i-1),ref);
});
} else {
ref.at = v;
v = u;
}
}
if(a.list.is(v)){
ref.at = v;
v = a.list(v).each(function(w,j,t){
if(w){
if(a.obj(g).has(w[gun._.id]||w)) t(g[w[gun._.id]||w]);
}
}) || [];
}
return i < l? u : v;
}
gun.ify = function(o, opt, n){
var g = {};
opt = opt || {};
opt.seen = opt.seen || [];
if(!a.obj.is(o)){ return g }
function ify(o,i,f,n,p){
if(gun.ify.is(o)){
f[i] = o;
return
}
if(a.obj.is(o)){
var seen;
if(seen = ify.seen(o)){
ify.be(seen);
return;
}
if(gun.is(o)){
f[i] = gun.id(o._[gun._.id]);
g[o._[gun._.id]] = n;
} else {
f[i] = n;
}
opt.seen.push({cartridge: n, prop: i, from: f, src: o});
a.obj(o).each(function(v,j){
ify(v,j,n,{},f);
});
if(gun.is(n)){
g[n._[gun._.id]] = n;
f[i] = gun.id(n._[gun._.id]);
}
return;
}
if(a.list.is(o)){
f[i] = a.list(o).each(function(v,j,t){
var seen;
if(a.fns.is(v)){
v = gun.at(v);
}
if(a.obj.is(v)){
if(seen = ify.seen(v)){
ify.be(seen);
if(gun.is(seen.cartridge)){ t(seen.cartridge._[gun._.id]) }
} else {
gun.ify(v, opt, n);
if(gun.is(n)){
t(n._[gun._.id]);
}
}
} else
if(a.text.is(v)){
if(a.obj(g).has(v)){
t(v);
} else {
t(v); // same as above :/ because it could be that this ID just hasn't been indexed yet.
}
}
}) || [];
return;
}
}
ify.be = function(seen){
var n = seen.cartridge;
n._ = n._||{};
n._[gun._.id] = n._[gun._.id]||gun.id();
g[n._[gun._.id]] = n;
if(seen.from){
seen.from[seen.prop] = gun.id(n._[gun._.id]);
}
}
ify.seen = function(o){
return a.list(opt.seen).each(function(v){
if(v && v.src === o){ return v }
}) || false;
}
var is = true, cartridge = n || {};
a.obj(o).each(function(v,i){
if(!gun.is(v)){ is = false }
ify(v, i, cartridge, {});
});
if(!is){
ify.be({cartridge: cartridge});
g[cartridge._[gun._.id]] = cartridge;
}
if(n){
return n;
}
return g;
}
gun.ify.be = function(v,g){ // update this to handle externals!
var r;
g = g || {};
if(gun.ify.is(v)){
r = v;
} else
if(a.obj.is(v)){
r = {};
a.obj(v).each(function(w,i){
w = gun.ify.be(w);
if(w === u){ return }
r[i] = w;
});
} else
if(a.list.is(v)){ // references only
r = a.list(v).each(function(w,i,t){
if(!w){ return }
w = gun.at(w);
if(gun.is(w)){
t(w._[gun._.id]);
} else
if(w[gun._.id]){
t(w[gun._.id]);
} else
if(a.obj(g).has(w)){
t(w);
}
}) || [];
}
return r;
}
gun.ify.is = function(v){ // null, binary, number (!Infinity), text, or a ref.
if(v === null){ return true } // deletes
if(v === Infinity){ return false }
if(a.bi.is(v)
|| a.num.is(v)
|| a.text.is(v)){
return true; // simple values
}
if(a.obj.is(v) && a.text.is(v[gun._.id])){ // ref
return true;
}
return false;
}
gun.ify.obj = function(v, val){
if(a.obj.is(val) && a.obj.is(v)){
a.obj(v).each(function(d, i){
if(a.gun.ham && a.gun.ham.call(g,n,p,v,w,val)){
}
});
}
return v;
}
gun.ify.list = function(v, val){
var r;
r = a.list.is(val)? val.concat(v) : v;
r = a.list(r).each(function(r,i,t){t(r,1)})||{};
r = a.obj(r).each(function(w,r,t){t(r)})||[]; // idempotency of this over latency? TODO! INVESTIGATE!!
return r;
}
gun.duel = function(old,now){
a.obj(now).each(function(g,id){
if(!gun.is(g)){ return }
var c;
if(a.obj(old).has(id) && gun.is(c = old[id])){
a.obj(g).each(function(v,i){
});
} else {
old[id] = g;
}
});
}
gun.bullet = function(p,v,w){
var b = {};
b[p] = v;
if(gun.ham && gun._.ham){
b._ = {};
b._[gun._.ham] = w || a.time.now();
}
return b;
}
gun.fire = function(bullet,c,w,op){
bullet = bullet.what? bullet : {what: bullet};
bullet.where = c || bullet.where;
bullet.when = w || bullet.when;
if(!a.obj.is(bullet.what)){ return gun.fire.jam("No ammo.", bullet) }
if(!a.num.is(bullet.when)){ return gun.fire.jam("No time.", bullet) }
if(!a.text.is(bullet.where)){ return gun.fire.jam("No location.", bullet) }
bullet.how = bullet.how || {};
bullet.how.gun = op || 1;
theory.on(gun.event).emit(bullet);
}
gun.fire.jam = function(s,b){ if(b){ return console.log("Gun jam:",s,b) } console.log("Gun jam:",s) }
gun.shots = function(hear,s){ return theory.on(gun.event+(s?'.'+s:'')).event(hear) }
gun.event = 'gun';
gun.magazine = {};
return gun;
})();
/* Hypothetical Amnesia Machine
A thought experiment in efficient cause, linear time, and knowledge.
Suppose everything you will ever know in your life was already be stored
in your brain. Now suppose we have some machine, which delicately traverses
your mind and gives you amnesia about all these facts. You now no longer can
recall any of this knowledge because that information is disconnected from
all other pieces of knowledge - making it impossible for your mind to then
associate and thus remember things. But the curious fact is that all this
knowledge is still stored within your mind, it is just inaccessible.
Now suppose, this amnesia machine is designed to unlock various bits of
that knowledge, making it connected again to other related tidbits and thus
making it accessible to you. This unlocking process is activated at some pre-
determined value, such as a timestamp. Can it really be said that this is
indistinguishable from the supposed flow of past, present, and future?
Such that future information is not just unknown, but fundamentally does
not exist, and then by actions taken in the present is caused to be. As a
result of your senses, you then experience this effect, and thus 'learning'
that knowledge. Could we truly build a proof that reality is one way or the
other? But if we did, wouldn't that scurrying little machine just race across
our minds and assure it induces amnesia into our remembrance of its existence?
Nay, we cannot. We can only hypothesize about the existence of this crafty
device. For the blindness that it does shed upon us captivates our perception
of how the world really is, us forever duped into thinking time is linear.
And here, in write and code, is this machine used and exploited. Holding
in its power the ability to quarantine and keep secret, until upon some
value, some condition, some scheme or rendition, does it raise its mighty
clutch of deception and expose the truth, shining in its radiance and glory,
all at the ease of making a single connection. Whereupon we do assure that
all conscious actors are agreed upon in a unified spot, synchronized in the
capacity to realize such beautiful information.
*/
a.gun._.ham = '>';
a.gun.ham = function(n,p,v,w){
if(!n){ return }
console.log("HAM:", n, p, v, w);
if(!a.text.is(p)){
if(a.obj.is(p) && p._){
a.obj(p).each(function(sv,i){
if(i === '_'){ return }
v = sv = a.gun.ham(n,i,sv, a.gun.ham.when(p._, i) || w); // works for now, but may not on other non-bullet objects
if(sv === u){
delete p[i];
} else {
p[i] = sv;
}
});
return v;
}
return;
}
var val = a.gun.at(n,p)
, when, age, now, u, q;
q = p.replace('.',a.gun._.ham);
n._ = n._ || {};
n._[a.gun._.ham] = n._[a.gun._.ham] || {};
age = function(q){
if(!q){ return 0 }
var when = n._[a.gun._.ham][q];
if(when || when === 0){
return when;
}
return age(a.text(q).clip(a.gun._.ham,0,-1));
}
when = age(q);
v = (function(){
if(a.gun.ify.is(v)){ // simple values are directly resolved
return v;
} else
if(a.obj.is(v)){
if(a.obj.is(val)){ // resolve sub-values
var change = false;
a.obj(v).each(function(sv,i){
sv = a.gun.ham(n, (p+'.'+i), sv, w, val[i]); // TODO: BUG! Still need to deal with sub-value bullets resolving to container's age.
if(sv === u){ return }
change = true;
val[i] = sv;
});
if(change){
return v = val;
} else {
return;; // nothing new
}
}
a.obj(v).each(function(sv,i){
sv = a.gun.ham(n, (p+'.'+i), sv, w, (val||{})[i]);
if(sv === u){ delete v[i] }
});
return v;
} else
if(a.list.is(v)){
if(!a.list.is(val)){ // TODO: deal with this later.
return v;
}
return v;
} else { // unknown matches are directly resolved
return;
}
})();
if(v === u){ return }
if(w < when){
console.log("new < old");
return;
} else
if(w === when){ // this needs to be updated also!
if(val === v || a.test.is(val,v) || a.text.ify(val) < a.text.ify(v)){
console.log("new === old");
return;
}
} else
if((now = a.time.now() + 1) < w){ // tolerate a threshold of 1ms.
console.log("amnesia", Math.ceil(w - now));
/* Amnesia Quarantine */
a.time.wait(function(){
console.log("run again");
a.gun.call(n,p,v,w);
}, Math.ceil(w - now)); // crude implementation for now.
return;
}
v = (function(){
if(a.obj.is(v)){
w = when; // objects are resolved relative to their previous values.
}
return v;
})();
n._[a.gun._.ham][q] = w; // if properties get deleted it may be nice to eventually delete the HAM, but that could cause problems so we don't for now.
// ps. It may be possible to delete simple values if they are not proceeded by an object?
return v;
}
a.gun.ham.when = function(w, i){
var h;
if(w && w._){
w = w._;
}
if(w && (h = w[a.gun._.ham])){
if(a.obj(h).has(i)){
return h[i];
}
if(a.num.is(h)){
return h;
}
}
}
return a.gun;
});

View File

@ -1,17 +0,0 @@
var Gun = require('gun');
var gun = Gun({
s3: {
key: '', // AWS Access Key
secret: '', // AWS Secret Token
bucket: '' // The bucket you want to save into
}});
gun.set({ hello: 'world' }).key('my/first/data')
var http = require('http');
http.createServer(function (req, res) {
gun.load('my/first/data', function(data){
res.writeHead(200, {'Content-Type': 'application/json'});
res.end(JSON.stringify(data));
});
}).listen(1337, '127.0.0.1');
console.log('Server running at http://127.0.0.1:1337/');

View File

@ -4,7 +4,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=0">
<style>
body {
background-image: url(./img/kimber.jpg);
background-image: url(./web/img/kimber.jpg);
background-repeat: no-repeat;
background-position: left top;
font-family: Arial;

View File

@ -1 +1 @@
module.exports = require('./shots');
module.exports = require('./lib/server');

31
init.js
View File

@ -1,31 +0,0 @@
(function(){
process.env.rootdir = __dirname;
var LIVE = process.env.LIVE || (process.env.NODE_ENV === 'production'), web, opt = {};
opt.port = process.env.OPENSHIFT_NODEJS_PORT || process.env.VCAP_APP_PORT || process.env.PORT;
opt.host = process.env.OPENSHIFT_NODEJS_IP;
if(opt.port || opt.host){ LIVE = true }
opt.port = opt.port || 8888;
opt.host = opt.host || '0.0.0.0';
if(LIVE){
//process.env['redis-install'] = '/tmp';
} else {
// Keys are hosted outside this folder, you must provide your own with environment variables.
var keys = '../../linux/.ssh/keys-gun.js';
if((require('fs').existsSync||require('path').existsSync)(keys)){
require(keys);
}
if((require('fs').existsSync||require('path').existsSync)('../coalesce')){
web = require('../coalesce');
}
}
opt.run = ['./test/server', './test/tests', './test/shoot'];
opt.node = {key: "temp gun key", src:["http://gunjs.herokuapp.com/com","http://gunjs-amark.rhcloud.com/com","http://gunjs.aws.af.cm/com"]};
web = web || require('coalesce');
web(opt);
console.log("Gun @ "+ opt.port);
})();

View File

@ -1,155 +1,155 @@
;module.exports = (function(a, own){
function s3(opt){
if(!(a.fns.is(this) || this instanceof s3)){
return new s3(opt);
}
var s = this;
s.on = a.on.create();
s.mime = require('mime');
s.AWS = require('aws-sdk');
s.config = {};
opt = opt || {};
s.AWS.config.bucket = s.config.bucket = opt.bucket || opt.Bucket || s.config.bucket || process.env.AWS_S3_BUCKET;
s.AWS.config.region = s.config.region = opt.region || s.config.region || process.env.AWS_REGION || "us-east-1";
s.AWS.config.accessKeyId = s.config.accessKeyId = opt.key || opt.accessKeyId || s.config.accessKeyId || process.env.AWS_ACCESS_KEY_ID;
s.AWS.config.secretAccessKey = s.config.secretAccessKey = opt.secret || opt.secretAccessKey || s.config.secretAccessKey || process.env.AWS_SECRET_ACCESS_KEY;
if(s.config.fakes3 = s.config.fakes3 || opt.fakes3 || process.env.fakes3){
s.AWS.config.endpoint = s.config.endpoint = opt.fakes3 || s.config.fakes3 || process.env.fakes3;
s.AWS.config.sslEnabled = s.config.sslEnabled = false;
s.AWS.config.bucket = s.config.bucket = s.config.bucket.replace('.','p');
}
s.AWS.config.update(s.config);
s.S3 = function(){
var s = new this.AWS.S3();
if(this.config.fakes3){
s.endpoint = config.endpoint;
}
return s;
}
return s;
};
s3.id = function(m){ return m.Bucket +'/'+ m.Key }
s3.chain = s3.prototype;
s3.chain.put = function(key, o, cb, m){
if(!key){ return }
m = m || {}
m.Bucket = m.Bucket || this.config.bucket;
m.Key = m.Key || key;
if(a.obj.is(o) || a.list.is(o)){
m.Body = a.text.ify(o);
m.ContentType = this.mime.lookup('json')
} else {
m.Body = a.text.is(o)? o : a.text.ify(o);
}
this.S3().putObject(m, function(e,r){
//console.log('saved', e,r);
if(!cb){ return }
cb(e,r);
});
return this;
}
s3.chain.get = function(key, cb, o){
if(!key){ return }
var s = this
, m = {
Bucket: s.config.bucket
,Key: key
}, id = s3.id(m);
s.on(id).once(function(e,d,t,m,r){
delete s.batch[id];
if(!a.fns.is(cb)){ return }
try{ cb(e,d,t,m,r);
}catch(e){
console.log(e);
}
});
s.batch = s.batch || {};
if(s.batch[id]){ return s }
s.batch[id] = (s.batch[id] || 0) + 1;
console.log("no batch!");
s.S3().getObject(m, function(e,r){
var d, t, m;
r = r || (this && this.httpResponse);
if(e || !r){ return s.on(id).emit(e) }
r.Text = r.text = t = (r.Body||r.body||'').toString('utf8');
r.Type = r.type = r.ContentType || (r.headers||{})['content-type'];
if(r.type && 'json' === s.mime.extension(r.type)){
d = a.obj.ify(t);
}
m = r.Metadata;
s.on(id).emit(e, d, t, m, r); // Warning about the r parameter, is is the raw response and may result in stupid SAX errors.
});
return s;
}
s3.chain.del = function(key, cb){
if(!key){ return }
var m = {
Bucket: this.config.bucket
,Key: key
}
this.S3().deleteObject(m, function(e,r){
if(!cb){ return }
cb(e, r);
});
return this;
}
s3.chain.dbs = function(o, cb){
cb = cb || o;
var m = {}
this.S3().listBuckets(m, function(e,r){
//console.log('dbs',e);
a.list.map((r||{}).Contents, function(v){console.log(v);});
//console.log('---end list---');
if(!a.fns.is(cb)) return;
cb(e,r);
});
return this;
}
s3.chain.keys = function(from, upto, cb){
cb = cb || upto || from;
var m = {
Bucket: this.config.bucket
}
if(a.text.is(from)){
m.Prefix = from;
}
if(a.text.is(upto)){
m.Delimiter = upto;
}
this.S3().listObjects(m, function(e,r){
//console.log('list',e);
a.list.each((r||{}).Contents, function(v){console.log(v)});
//console.log('---end list---');
if(!a.fns.is(cb)) return;
cb(e,r);
});
return this;
}
return s3;
})(require('../gun'), {});
/**
Knox S3 Config is:
knox.createClient({
key: ''
, secret: ''
, bucket: ''
, endpoint: 'us-standard'
, port: 0
, secure: true
, token: ''
, style: ''
, agent: ''
});
aws-sdk for s3 is:
{ "accessKeyId": "akid", "secretAccessKey": "secret", "region": "us-west-2" }
AWS.config.loadFromPath('./config.json');
{
accessKeyId: process.env.AWS_ACCESS_KEY_ID = ''
,secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY = ''
,Bucket: process.env.s3Bucket = ''
,region: process.env.AWS_REGION = "us-east-1"
,sslEnabled: ''
}
;module.exports = (function(a, own){
function s3(opt){
if(!(a.fns.is(this) || this instanceof s3)){
return new s3(opt);
}
var s = this;
s.on = a.on.create();
s.mime = require('mime');
s.AWS = require('aws-sdk');
s.config = {};
opt = opt || {};
s.AWS.config.bucket = s.config.bucket = opt.bucket || opt.Bucket || s.config.bucket || process.env.AWS_S3_BUCKET;
s.AWS.config.region = s.config.region = opt.region || s.config.region || process.env.AWS_REGION || "us-east-1";
s.AWS.config.accessKeyId = s.config.accessKeyId = opt.key || opt.accessKeyId || s.config.accessKeyId || process.env.AWS_ACCESS_KEY_ID;
s.AWS.config.secretAccessKey = s.config.secretAccessKey = opt.secret || opt.secretAccessKey || s.config.secretAccessKey || process.env.AWS_SECRET_ACCESS_KEY;
if(s.config.fakes3 = s.config.fakes3 || opt.fakes3 || process.env.fakes3){
s.AWS.config.endpoint = s.config.endpoint = opt.fakes3 || s.config.fakes3 || process.env.fakes3;
s.AWS.config.sslEnabled = s.config.sslEnabled = false;
s.AWS.config.bucket = s.config.bucket = s.config.bucket.replace('.','p');
}
s.AWS.config.update(s.config);
s.S3 = function(){
var s = new this.AWS.S3();
if(this.config.fakes3){
s.endpoint = config.endpoint;
}
return s;
}
return s;
};
s3.id = function(m){ return m.Bucket +'/'+ m.Key }
s3.chain = s3.prototype;
s3.chain.put = function(key, o, cb, m){
if(!key){ return }
m = m || {}
m.Bucket = m.Bucket || this.config.bucket;
m.Key = m.Key || key;
if(a.obj.is(o) || a.list.is(o)){
m.Body = a.text.ify(o);
m.ContentType = this.mime.lookup('json')
} else {
m.Body = a.text.is(o)? o : a.text.ify(o);
}
this.S3().putObject(m, function(e,r){
//console.log('saved', e,r);
if(!cb){ return }
cb(e,r);
});
return this;
}
s3.chain.get = function(key, cb, o){
if(!key){ return }
var s = this
, m = {
Bucket: s.config.bucket
,Key: key
}, id = s3.id(m);
s.on(id).once(function(e,d,t,m,r){
delete s.batch[id];
if(!a.fns.is(cb)){ return }
try{ cb(e,d,t,m,r);
}catch(e){
console.log(e);
}
});
s.batch = s.batch || {};
if(s.batch[id]){ return s }
s.batch[id] = (s.batch[id] || 0) + 1;
console.log("no batch!");
s.S3().getObject(m, function(e,r){
var d, t, m;
r = r || (this && this.httpResponse);
if(e || !r){ return s.on(id).emit(e) }
r.Text = r.text = t = (r.Body||r.body||'').toString('utf8');
r.Type = r.type = r.ContentType || (r.headers||{})['content-type'];
if(r.type && 'json' === s.mime.extension(r.type)){
d = a.obj.ify(t);
}
m = r.Metadata;
s.on(id).emit(e, d, t, m, r); // Warning about the r parameter, is is the raw response and may result in stupid SAX errors.
});
return s;
}
s3.chain.del = function(key, cb){
if(!key){ return }
var m = {
Bucket: this.config.bucket
,Key: key
}
this.S3().deleteObject(m, function(e,r){
if(!cb){ return }
cb(e, r);
});
return this;
}
s3.chain.dbs = function(o, cb){
cb = cb || o;
var m = {}
this.S3().listBuckets(m, function(e,r){
//console.log('dbs',e);
a.list.map((r||{}).Contents, function(v){console.log(v);});
//console.log('---end list---');
if(!a.fns.is(cb)) return;
cb(e,r);
});
return this;
}
s3.chain.keys = function(from, upto, cb){
cb = cb || upto || from;
var m = {
Bucket: this.config.bucket
}
if(a.text.is(from)){
m.Prefix = from;
}
if(a.text.is(upto)){
m.Delimiter = upto;
}
this.S3().listObjects(m, function(e,r){
//console.log('list',e);
a.list.each((r||{}).Contents, function(v){console.log(v)});
//console.log('---end list---');
if(!a.fns.is(cb)) return;
cb(e,r);
});
return this;
}
return s3;
})(require('gun/gun'), {});
/**
Knox S3 Config is:
knox.createClient({
key: ''
, secret: ''
, bucket: ''
, endpoint: 'us-standard'
, port: 0
, secure: true
, token: ''
, style: ''
, agent: ''
});
aws-sdk for s3 is:
{ "accessKeyId": "akid", "secretAccessKey": "secret", "region": "us-west-2" }
AWS.config.loadFromPath('./config.json');
{
accessKeyId: process.env.AWS_ACCESS_KEY_ID = ''
,secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY = ''
,Bucket: process.env.s3Bucket = ''
,region: process.env.AWS_REGION = "us-east-1"
,sslEnabled: ''
}
**/

50
lib/http.js Normal file
View File

@ -0,0 +1,50 @@
var Gun = require('gun/gun')
, formidable = require('formidable')
, url = require('url');
module.exports = function(req, res, next){
next = next || function(){};
if(!req || !res){ return next() }
if(!req.url){ return next() }
if(!req.method){ return next() }
var msg = {};
msg.url = url.parse(req.url, true);
msg.method = (req.method||'').toLowerCase();
msg.headers = req.headers;
var u, body
, form = new formidable.IncomingForm()
, post = function(err, body){
if(u !== body){ msg.body = body }
next(msg, function(reply){
if(!res){ return }
if(!reply){ return res.end() }
if(Gun.obj.has(reply, 'statusCode') || Gun.obj.has(reply, 'status')){
res.statusCode = reply.statusCode || reply.status;
}
if(reply.headers){
if(!res._headerSent){
Gun.obj.map(reply.headers, function(val, field){
res.setHeader(field, val);
});
}
}
if(Gun.obj.has(reply,'chunk') || Gun.obj.has(reply,'write')){
res.write(Gun.text.ify(reply.chunk || reply.write) || '');
}
if(Gun.obj.has(reply,'body') || Gun.obj.has(reply,'end')){
res.end(Gun.text.ify(reply.body || reply.end) || '');
}
});
}
form.on('field',function(k,v){
(body = body || {})[k] = v;
}).on('file',function(k,v){
return; // files not supported in gun yet
}).on('error',function(e){
if(form.done){ return }
post(e);
}).on('end', function(){
if(form.done){ return }
post(null, body);
});
form.parse(req);
}

37
lib/jsonp.js Normal file
View File

@ -0,0 +1,37 @@
var Gun = require('gun/gun');
module.exports = function(req, cb){
if(!req.url || !req.url.query || !req.url.query.jsonp){ return cb }
cb.jsonp = req.url.query.jsonp;
delete req.url.query.jsonp;
Gun.obj.map(Gun.obj.ify(req.url.query['`']), function(val, i){
req.headers[i] = val;
});
delete req.url.query['`'];
if(req.url.query.$){
req.body = req.url.query.$;
if(!Gun.obj.has(req.url.query, '^') || 'json' == req.url.query['^']){
req.body = Gun.obj.ify(req.body); // TODO: BUG! THIS IS WRONG! This doesn't handle multipart chunking, and will fail!
}
}
delete req.url.query.$;
delete req.url.query['^'];
delete req.url.query['%'];
var reply = {headers:{}};
return function(res){
if(!res){ return }
if(res.headers){
Gun.obj.map(res.headers, function(val, field){
reply.headers[field] = val;
});
}
reply.headers['Content-Type'] = "text/javascript";
if(Gun.obj.has(res,'chunk') && (!reply.body || Gun.list.is(reply.chunks))){
(reply.chunks = reply.chunks || []).push(res.chunk);
}
if(Gun.obj.has(res,'body')){
reply.body = res.body; // self-reference yourself so on the client we can get the headers and body.
reply.body = ';'+ cb.jsonp + '(' + Gun.text.ify(reply) + ');'; // javascriptify it! can't believe the client trusts us.
cb(reply);
}
}
}

113
lib/s3.js Normal file
View File

@ -0,0 +1,113 @@
;(function(){
var Gun = require('gun/gun');
var S3 = require('./aws');
Gun.on('opt').event(function(gun, opt){
opt.s3 = opt.s3 || {};
var s3 = gun.__.opt.s3 = gun.__.opt.s3 || S3(opt && opt.s3);
s3.prefix = s3.prefix || opt.s3.prefix || '';
s3.prekey = s3.prekey || opt.s3.prekey || '';
s3.prenode = s3.prenode || opt.s3.prenode || '_/nodes/';
gun.__.opt.batch = opt.batch || gun.__.opt.batch || 10;
gun.__.opt.throttle = opt.throttle || gun.__.opt.throttle || 15;
gun.__.opt.disconnect = opt.disconnect || gun.__.opt.disconnect || 5;
s3.load = s3.load || function(key, cb, opt){
if(!key){ return }
cb = cb || function(){};
opt = opt || {};
if(key[Gun._.soul]){
key = s3.prefix + s3.prenode + key[Gun._.soul];
} else {
key = s3.prefix + s3.prekey + key;
}
s3.get(key, function(err, data, text, meta){
console.log('via s3', key, err);
if(meta && meta[Gun._.soul]){
return s3.load(meta, cb);
}
if(err && err.statusCode == 404){
err = null; // we want a difference between 'unfound' (data is null) and 'error' (auth is wrong).
}
cb(err, data);
});
}
s3.set = s3.set || function(nodes, cb){
s3.batching += 1;
cb = cb || function(){};
cb.count = 0;
var next = s3.next
, ack = Gun.text.random(8)
, batch = s3.batch[next] = s3.batch[next] || {};
s3.on(ack).once(cb);
Gun.obj.map(nodes, function(node, soul){
cb.count += 1;
batch[soul] = (batch[soul] || 0) + 1;
//console.log("set listener for", next + ':' + soul, batch[soul], cb.count);
s3.on(next + ':' + soul).event(function(){
cb.count -= 1;
//console.log("transaction", cb.count);
if(!cb.count){
s3.on(ack).emit();
this.off(); // MEMORY LEAKS EVERYWHERE!!!!!!!!!!!!!!!! FIX THIS!!!!!!!!!
}
});
});
if(gun.__.opt.batch < s3.batching){
return s3.set.now();
}
if(!gun.__.opt.throttle){
return s3.set.now();
}
s3.wait = s3.wait || setTimeout(s3.set.now, gun.__.opt.throttle * 1000); // in seconds
}
s3.set.now = s3.set.now || function(){
clearTimeout(s3.wait);
s3.batching = 0;
s3.wait = null;
var now = s3.next
, batch = s3.batch[s3.next];
s3.next = Gun.time.is();
Gun.obj.map(batch, function put(exists, soul){
var node = gun.__.graph[soul]; // the batch does not actually have the nodes, but what happens when we do cold data? Could this be gone?
s3.put(s3.prefix + s3.prenode + soul, node, function(err, reply){
console.log("s3 put reply", soul, err, reply);
if(err || !reply){
put(exists, soul); // naive implementation of retry TODO: BUG: need backoff and anti-infinite-loop!
return;
}
s3.on(now + ':' + soul).emit(200);
});
});
}
s3.next = s3.next || Gun.time.is();
s3.on = s3.on || Gun.on.create();
s3.batching = s3.batching || 0;
s3.batched = s3.batched || {};
s3.batch = s3.batch || {};
s3.persisted = s3.persisted || {};
s3.wait = s3.wait || null;
s3.key = s3.key || function(key, soul, cb){
var meta = {};
meta[Gun._.soul] = soul = Gun.text.is(soul)? soul : (soul||{})[Gun._.soul];
if(!soul){
return cb({err: "No soul!"});
}
s3.put(s3.prefix + s3.prekey + key, '', function(err, reply){ // key is 2 bytes??? Should be smaller. Wait HUH? What did I mean by this?
console.log("s3 put reply", soul, err, reply);
if(err || !reply){
s3.key(key, soul, cb); // naive implementation of retry TODO: BUG: need backoff and anti-infinite-loop!
return;
}
cb();
}, {Metadata: meta});
}
opt.hooks = opt.hooks || {};
gun.opt({hooks: {
load: opt.hooks.load || s3.load
,set: opt.hooks.set || s3.set
,key: opt.hooks.key || s3.key
}}, true);
});
}());

7
lib/server.js Normal file
View File

@ -0,0 +1,7 @@
;(function(){
console.log("Hello wonderful person! :) I'm mark@gunDB.io, message me for help or with hatemail. I want to hear from you! <3");
var Gun = require('../gun');
require('./s3');
require('./wsp');
module.exports = Gun;
}());

37
lib/ws.js Normal file
View File

@ -0,0 +1,37 @@
var Gun = require('gun/gun')
, url = require('url');
module.exports = function(wss, server){
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 || {};
//console.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 || req.method;
msg.headers = msg.headers || {};
Gun.obj.map(req.headers, function(val, i){
msg.headers[i] = msg.headers[i] || val; // reattach headers
});
server.call(ws, msg, function(reply){
if(!ws || !ws.send){ return }
reply = reply || {};
reply.wsrid = msg.wsrid;
ws.send(Gun.text.ify(reply));
});
});
ws.off = function(m){
console.log("ws.off", m);
ws.send = null;
}
ws.on('close', ws.off);
ws.on('error', ws.off);
});
}

153
lib/wsp.js Normal file
View File

@ -0,0 +1,153 @@
;(function(wsp){
var Gun = require('gun/gun')
, formidable = require('formidable')
, ws = require('ws').Server
, http = require('./http')
, url = require('url');
Gun.on('opt').event(function(gun, opt){
gun.__.opt.ws = opt.ws = gun.__.opt.ws || opt.ws || {};
gun.attach = gun.attach || function(app){
if(app.use){
app.use(gun.server);
}
var listen = app.listen;
app.listen = function(port){
var server = listen.apply(app, arguments);
gun.__.opt.ws.server = gun.__.opt.ws.server || opt.ws.server || server;
gun.__.opt.ws.path = gun.__.opt.ws.path || opt.ws.path || '/gun';
require('./ws')(gun.server.websocket = gun.server.websocket || new ws(gun.__.opt.ws), function(req, res){
var ws = this;
req.headers['gun-tid'] = ws.tid = ws.tid? ws.tid : req.headers['gun-tid'];
ws.sub = ws.sub || gun.server.on('network').event(function(msg){
if(!ws || !ws.send){ return this.off() }
if(!msg || (msg.headers && msg.headers['gun-tid'] === ws.tid)){ return }
delete msg.wsrid; // depreciate this!
ws.send(Gun.text.ify(msg));
});
gun.__.opt.hooks.transport(req, res);
});
gun.__.opt.ws.port = port || opt.ws.port || gun.__.opt.ws.port || 80;
return server;
}
return gun;
}
gun.server = gun.server || function(req, res, next){
//console.log("\n\n GUN SERVER!", req);
next = next || function(){};
if(!req || !res){ return next() }
if(!req.url){ return next() }
if(!req.method){ return next() }
var msg = {};
msg.url = url.parse(req.url, true);
if(!gun.server.regex.test(msg.url.pathname)){ return next() }
if(msg.url.pathname.replace(gun.server.regex,'').slice(0,3).toLowerCase() === '.js'){
res.writeHead(200, {'Content-Type': 'text/javascript'});
res.end(gun.server.js = gun.server.js || require('fs').readFileSync(__dirname + '/../gun.js')); // gun server is caching the gun library for the client
return;
}
http(req, res, function(req, res){
if(!req){ return next() }
var tab, cb = res = require('./jsonp')(req, res);
if(req.headers && (tab = req.headers['gun-tid'])){
tab = (gun.server.peers = gun.server.peers || {})[tab] = gun.server.peers[tab] || {tid: tab};
tab.sub = tab.sub || gun.server.on('network').event(function(req){
if(!tab){ return this.off() } // self cleans up after itself!
if(!req || (req.headers && req.headers['gun-tid'] === tab.tid)){ return }
(tab.queue = tab.queue || []).push(req);
tab.drain(tab.reply);
});
cb = function(r){ (r.headers||{}).poll = gun.__.opt.poll; res(r) }
tab.drain = tab.drain || function(res){
if(!res || !tab || !tab.queue || !tab.queue.length){ return }
res({headers: {'gun-tid': tab.tid}, body: tab.queue });
tab.off = setTimeout(function(){ tab = null }, gun.__.opt.pull);
tab.reply = tab.queue = null;
return true;
}
clearTimeout(tab.off);
if(req.headers.pull){
if(tab.drain(cb)){ return }
return tab.reply = cb;
}
}
gun.__.opt.hooks.transport(req, cb);
});
}
gun.server.on = gun.server.on || Gun.on.create();
gun.__.opt.poll = gun.__.opt.poll || opt.poll || 1;
gun.__.opt.pull = gun.__.opt.pull || opt.pull || gun.__.opt.poll * 1000;
gun.server.regex = gun.__.opt.route = gun.__.opt.route || opt.route || /^\/gun/i;
if((gun.__.opt.maxSockets = opt.maxSockets || gun.__.opt.maxSockets) !== false){
require('https').globalAgent.maxSockets = require('http').globalAgent.maxSockets = gun.__.opt.maxSockets || Infinity; // WARNING: Document this!
}
/* gun.server.xff = function(r){
if(!r){ return '' }
var req = {headers: r.headers || {}, connection: r.connection || {}, socket: r.socket || {}};
return req.headers['x-forwarded-for'] || req.connection.remoteAddress || req.socket.remoteAddress || (req.connection.socket || {}).remoteAddress || '';
} */
gun.server.transport = gun.server.transport || (function(){
// all streams, technically PATCH but implemented as POST, are forwarded to other trusted peers
// except for the ones that are listed in the message as having already been sending to.
// all states, implemented with GET, are replied to the source that asked for it.
function tran(req, cb){
//console.log("gun.server", req);
req.method = req.body? 'post' : 'get'; // post or get is based on whether there is a body or not
req.url.key = req.url.pathname.replace(gun.server.regex,'').replace(/^\//i,'') || '';
if('get' == req.method){ return tran.load(req, cb) }
if('post' == req.method){ return tran.post(req, cb) }
cb({body: {hello: 'world'}});
}
tran.load = function(req, cb){
var key = req.url.key
, reply = {headers: {'Content-Type': tran.json}};
if(!key){
if(!Gun.obj.has(req.url.query, Gun._.soul)){
return cb({headers: reply.headers, body: {err: "No key or soul to load."}});
}
key = {};
key[Gun._.soul] = req.url.query[Gun._.soul];
}
gun.load(key, function(err, node){
//tran.sub.scribe(req.tab, node._[Gun._.soul]);
cb({headers: reply.headers, body: (err? (err.err? err : {err: err || "Unknown error."}) : node || null)});
});
}
tran.post = function(req, cb){
// NOTE: It is highly recommended you do your own 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 reply = {headers: {'Content-Type': tran.json}};
if(!req.body){ return cb({headers: reply.headers, body: {err: "No body"}}) }
if(req.url.key && Gun.obj.has(req.body, Gun._.soul)){ // key hook!
console.log("TODO: BUG! IMPLEMENT KEY TRANSPORT HOOK!");
return;
}
// saving
Gun.obj.map(req.body, function(node, soul){
if(soul != Gun.is.soul.on(node)){ return this.end("No soul!") }
gun.load(node._, this.add(soul));
}, Gun.fns.sum(function(err){
if(err){ return cb({headers: reply.headers, body: {err: err}}) }
gun.union(req.body, function(err, context){
if(err || context.err || !context.nodes){ return cb({headers: reply.headers, body: {err: err || context.err || "Union failed." }}) }
if(!Gun.fns.is(gun.__.opt.hooks.set)){ return cb({headers: reply.headers, body: {err: "Persistence not supported." }}) }
gun.__.opt.hooks.set(context.nodes, function(err, data){ // since we've already manually done the union, we can now directly call the persistence layer.
if(err){ return cb({headers: reply.headers, body: {err: err || "Persistence failed." }}) }
cb({headers: reply.headers, body: {ok: "Persisted."}});
});
});
}));
gun.server.on('network').emit(req);
}
gun.server.on('network').event(function(req){
// TODO: MARK! You should move the networking events to here, not in WSS only.
});
tran.json = 'application/json';
return tran;
}());
opt.hooks = opt.hooks || {};
gun.opt({hooks: {
transport: opt.hooks.transport || gun.server.transport
}}, true);
});
}({}));

View File

@ -1,442 +1,354 @@
;(function(){
console.log("Hello wonderful person! :) I'm mark@gunDB.io, message me for help or with hatemail. I want to hear from you! <3");
var Gun = require(__dirname+'/gun')
, S3 = require(__dirname+'/gate/s3') // redis has been removed, can be replaced with a disk system
, formidable = require('formidable')
, url = require('url')
, meta = {};
Gun.on('opt').event(function(gun, opt){
gun.server = gun.server || function(req, res, next){ // this whole function needs refactoring and modularization
//console.log("\n\n GUN SERVER!");
next = next || function(){};
if(!req || !res){ return next() }
if(!req.url){ return next() }
if(!req.method){ return next() }
var msg = {};
msg.url = url.parse(req.url, true);
if(!gun.server.regex.test(msg.url.pathname)){ return next() }
msg.url.key = msg.url.pathname.replace(gun.server.regex,'') || '';
if(msg.url.key.toLowerCase() === '.js'){
res.writeHead(200, {'Content-Type': 'text/javascript'});
res.end(gun.server.js = gun.server.js || require('fs').readFileSync(__dirname + '/gun.js')); // gun server is caching the gun library for the client
return;
}
msg.url.key = msg.url.key.replace(/^\//i,'') || ''; // strip the base slash
msg.method = (req.method||'').toLowerCase();
msg.headers = req.headers;
var body
, form = new formidable.IncomingForm()
, post = function(err, body){
msg.body = body;
gun.__.opt.hooks.transport(msg, function(reply){
if(!res){ return }
if(!reply){ return res.end() }
if(reply.headers){
if(!res._headerSent){
Gun.obj.map(reply.headers, function(val, field){
res.setHeader(field, val);
});
}
}
meta.CORS(req, res); // add option to disable this
if(Gun.obj.has(reply,'chunk')){
res.write(Gun.text.ify(reply.chunk) || '');
}
if(Gun.obj.has(reply,'body')){
res.end(Gun.text.ify(reply.body) || '');
}
});
}
form.on('field',function(k,v){
(body = body || {})[k] = v;
}).on('file',function(k,v){
return; // files not supported in gun yet
}).on('error',function(e){
if(form.done){ return }
post(e);
}).on('end', function(){
if(form.done){ return }
post(null, body);
});
form.parse(req);
}
gun.server.regex = /^\/gun/i;
opt.s3 = opt.s3 || {};
var s3 = gun.__.opt.s3 = gun.__.opt.s3 || S3(opt && opt.s3);
s3.prefix = s3.prefix || opt.s3.prefix || '';
s3.prekey = s3.prekey || opt.s3.prekey || '';
s3.prenode = s3.prenode || opt.s3.prenode || '_/nodes/';
gun.__.opt.batch = opt.batch || gun.__.opt.batch || 10;
gun.__.opt.throttle = opt.throttle || gun.__.opt.throttle || 15;
gun.__.opt.disconnect = opt.disconnect || gun.__.opt.disconnect || 5;
if(!gun.__.opt.keepMaxSockets){ require('https').globalAgent.maxSockets = require('http').globalAgent.maxSockets = Infinity } // WARNING: Document this!
s3.load = s3.load || function(key, cb, opt){
if(!key){ return }
cb = cb || function(){};
opt = opt || {};
if(key[Gun._.soul]){
key = s3.prefix + s3.prenode + key[Gun._.soul];
} else {
key = s3.prefix + s3.prekey + key;
}
s3.get(key, function(err, data, text, meta){
console.log('via s3', key, err);
if(meta && meta[Gun._.soul]){
return s3.load(meta, cb);
}
if(err && err.statusCode == 404){
err = null; // we want a difference between 'unfound' (data is null) and 'error' (auth is wrong).
}
cb(err, data);
});
}
s3.set = s3.set || function(nodes, cb){
s3.batching += 1;
cb = cb || function(){};
cb.count = 0;
var next = s3.next
, ack = Gun.text.random(8)
, batch = s3.batch[next] = s3.batch[next] || {};
s3.on(ack).once(cb);
Gun.obj.map(nodes, function(node, soul){
cb.count += 1;
batch[soul] = (batch[soul] || 0) + 1;
//console.log("set listener for", next + ':' + soul, batch[soul], cb.count);
s3.on(next + ':' + soul).event(function(){
cb.count -= 1;
//console.log("transaction", cb.count);
if(!cb.count){
s3.on(ack).emit();
this.off(); // MEMORY LEAKS EVERYWHERE!!!!!!!!!!!!!!!! FIX THIS!!!!!!!!!
}
});
});
if(gun.__.opt.batch < s3.batching){
return s3.set.now();
}
if(!gun.__.opt.throttle){
return s3.set.now();
}
s3.wait = s3.wait || setTimeout(s3.set.now, gun.__.opt.throttle * 1000); // in seconds
}
s3.set.now = s3.set.now || function(){
clearTimeout(s3.wait);
s3.batching = 0;
s3.wait = null;
var now = s3.next
, batch = s3.batch[s3.next];
s3.next = Gun.time.is();
Gun.obj.map(batch, function put(exists, soul){
var node = gun.__.graph[soul]; // the batch does not actually have the nodes, but what happens when we do cold data? Could this be gone?
s3.put(s3.prefix + s3.prenode + soul, node, function(err, reply){
console.log("s3 put reply", soul, err, reply);
if(err || !reply){
put(exists, soul); // naive implementation of retry TODO: BUG: need backoff and anti-infinite-loop!
return;
}
s3.on(now + ':' + soul).emit(200);
});
});
}
s3.next = s3.next || Gun.time.is();
s3.on = s3.on || Gun.on.create();
s3.batching = s3.batching || 0;
s3.batched = s3.batched || {};
s3.batch = s3.batch || {};
s3.persisted = s3.persisted || {};
s3.wait = s3.wait || null;
s3.key = s3.key || function(key, soul, cb){
var meta = {};
meta[Gun._.soul] = soul = Gun.text.is(soul)? soul : (soul||{})[Gun._.soul];
if(!soul){
return cb({err: "No soul!"});
}
s3.put(s3.prefix + s3.prekey + key, '', function(err, reply){ // key is 2 bytes??? Should be smaller
console.log("s3 put reply", soul, err, reply);
if(err || !reply){
s3.key(key, soul, cb); // naive implementation of retry TODO: BUG: need backoff and anti-infinite-loop!
return;
}
cb();
}, {Metadata: meta});
}
gun.server.transport = (function(){
function tran(req, cb){
//console.log(req);
req.sub = req.headers['gun-sub']; // grab the sub
req.tab = tran.sub.s[req.sub] || {}; // check to see if there already is a tab associated with it, or create one
req.tab.sub = req.sub = req.sub || Gun.text.random(); // Generate a session id if we don't already have one
req.tran = tran.xhr(req, cb) || tran.jsonp(req, cb); // polyfill transport layer
clearTimeout(req.tab.timeout);
// raw test for now, no auth:
if(!req.tran){ return cb({headers: {"Content-Type": tran.json}, body: {err: "No transport layer!"}}) }
if('post' === req.method || 'patch' === req.method){ return tran.post(req, req.tran) } // TODO: Handle JSONP emulated POST via GET
if('get' !== req.method){ return req.tran({body: {err: "Invalid method"}}) }
if(!req.url.key){ return tran.sub(req, req.tran) } // get acts as sub, too.
return tran.load(req, req.tran); // else load the state for the tab!
}
tran.load = function(req, cb){
var reply = {}, key;
reply.headers = {'Content-Type': tran.json};
reply.headers['Gun-Sub'] = req.tab.sub = req.sub;
key = (Gun._.meta == req.url.key)? req.url.query : req.url.key;
console.log("Loading", req.url.key, 'for', req.tab);
gun.load(key, function(node){
tran.sub.scribe(req.tab, node._[Gun._.soul]);
cb({
headers: reply.headers
,body: node
});
}).blank(function(){
cb({
headers: reply.headers
,body: null
});
}).dud(function(err){
cb({
headers: reply.headers
,body: {err: err || "Unknown error."}
});
});
}
tran.post = function(req, cb){ // post is used as patch, sad that patch has such poor support
if(!req.body){ return cb({body: {err: "No body"}}) }
// raw test for now, no auth:
// should probably load all the nodes first? YES.
var context = gun.union(req.body, function(err, context){ // data safely transformed
cb = cb || function(){};
if(err || context.err){ return cb({body: {err: context.err}}) }
if(Gun.fns.is(gun.__.opt.hooks.set)){
gun.__.opt.hooks.set(context.nodes, function saved(err, data){ // now iterate through those nodes to S3 and get a callback once all are saved
var body = {};
if(err){
body.err = err ;
}
if(!req.sub){
if(!err){
body = defer.map({}, context.nodes, 1);
}
return cb({body: body});
}
var now = tran.post.s[req.sub]; // begin our stupid Chrome fix, we should abstract this out into defer (where it belogns) to keep things clean.
if(!now){ return } // utoh we've lost our reply to the tab!
clearTimeout(now.timeout);
now.body = now.body || {}; // make sure we have a body for our multi-response in a single response.
if(req.wait){ // did this request get deferred?
(now.body.refed = now.body.refed || {})[req.wait] = err? {err: err} : defer.map({}, context.nodes, 1); // then reply to it "here".
} else {
now.body.reply = err? {err: err} : defer.map({}, context.nodes, 1); // else this is the original POST that had to be upgraded.
}
if(0 < (now.count = ((now.count || 0) - 1))){
// Don't reply till all deferred POSTs have successfully heard back from S3. (Sarcasm: Like counting guarantees that)
return now.timeout = setTimeout(saved, gun.__.opt.throttle * 2 * 1000); // reply not guaranteed, so time it out, in seconds.
}
if(Gun.fns.is(now)){
now({body: now.body}); // FINALLY reply for ALL the POSTs for that session that accumulated.
} else {
// console.log("Error! We deleted our response!");
}
Gun.obj.del(tran.post.s, req.sub); // clean up our memory.
// need to rewrite that if Stream is enabled that both Stream + State save are guaranteed before replying.
});
// stuff past this point is just stupid implementation optimizations.
function defer(nodes, req){ // because Chrome can only handle 4 requests at a time, sad face.
if(!req.sub){
return;
}
var next = tran.post.s[req.sub];
if(!next){ // was there a previous POST? If not, we become the previous POST.
//cb({chunk: ''}); // because on some services (heroku) you need to reply starting a stream to keep the connection open.
return tran.post.s[req.sub] = cb;
}
next.count = (next.count || 1) + 1; // start counting how many we accumulate
next.body = next.body || {}; // this becomes the polyfill for all the posts
next.body.refed = next.body.refed || {}; // where we refeed the responses for the deferred POSTs.
req.wait = Gun.text.random(); // generate an random id for this deferred POST.
next.body.refed[req.wait] = false; // establish that we are incomplete.
cb({body: {defer: req.wait}}); // end this POST immediately so Chrome only ever uses a couple connections.
cb = null; // null it out so we don't accidentally reply to it once we hear back from S3.
}
defer.map = function(now, nodes, val){ // shortcut for maping which nodes were saved successfully
if(!now){ return }
Gun.obj.map(nodes, function(node, soul, map){
now[soul] = val;
});
return now;
}
defer(context.nodes, req); // actually do the weird stuff to make Chrome not be slow
} else {
context.err = "Warning! You have no persistence layer to save to!";
Gun.log(context.err);
cb({body: {err: "Server has no persistence layer!"}});
}
});
if(context.err){
cb({body: {err: context.err}});
return cb = null;
}
Gun.obj.map(context.nodes, function(node, soul){ // live push the stream out in realtime to every tab subscribed
var msg = {};
msg.headers = req.headers; // polyfill the delta as its own message.
msg.body = node;
console.log("emit delta", soul);
tran.push(soul).emit(msg);
});
}
tran.post.s = {};
tran.sub = function(req, cb){
//console.log("<-- ", req.sub, req.tran ," -->");
req.tab = tran.sub.s[req.sub];
if(!req.tab){
cb({
headers: {'Gun-Sub': ''}
,body: {err: "Please re-initialize sub."}
});
return;
}
//console.log("\n\n\n THE CURRENT STATUS IS");console.log(req.tab);
if(req.tab.queue && req.tab.queue.length){
tran.clean(req.tab); // We flush their data now, if they don't come back for more within timeout, we remove their session
console.log("_____ NOW PUSHING YOUR DATA ______", req.sub);
cb({ headers: {'Gun-Sub': req.sub} });
while(1 < req.tab.queue.length){
cb({ chunk: req.tab.queue.shift() });
}
cb({ body: req.tab.queue.shift() });
} else {
cb({chunk: ''}); // same thing as the defer code, initialize a stream to support some services (heroku).
req.tab.reply = cb;
console.log("_____ STANDING BY, WAITING FOR DATA ______", req.sub);
}
}
tran.sub.s = {};
tran.clean = function(tab, mult){
if(!tab){ return }
mult = mult || 1;
clearTimeout(tab.timeout);
tab.timeout = setTimeout(function(){
if(!tab){ return }
if(tab.reply){ tab.reply({body: {err: "Connection timed out"}}) }
console.log("!!!! DISCONNECTING CLIENT !!!!!", tab.sub);
Gun.obj.del(tran.sub.s, tab.sub)
}, gun.__.opt.disconnect * mult * 1000); // in seconds
}
tran.sub.scribe = function(tab, soul){
tran.sub.s[tab.sub] = tab;
tab.subs = tab.subs || {};
tab.subs[soul] = tab.subs[soul] || tran.push(soul).event(function(req){
if(!req){ return }
if(!tab){ return this.off() } // resolve any dangling callbacks
req.sub = req.sub || req.headers['gun-sub'];
if(req.sub === tab.sub){ return } // do not send back to the tab that sent it
console.log('FROM:', req.sub, "TO:", tab.sub);
tran.clean(tab);
if(tab.reply){
tab.reply({
headers: {'Gun-Sub': tab.sub}
,body: req.body
});
tab.reply = null;
return;
}
(tab.queue = tab.queue || []).push(req.body);
});
tran.clean(tab, 2);
}
tran.xhr = function(req, cb){ // Streaming Long Polling
return req.tran || (req.headers['x-requested-with'] === 'XMLHttpRequest'? transport : null);
function transport(res){
if(!res){ return }
var reply = {headers: {}};
if(res.headers){
Gun.obj.map(res.headers, function(val, field){
reply.headers[field] = val;
});
}
reply.headers["Content-Type"] = tran.json;
if(Gun.obj.has(res,'chunk')){
cb({
headers: reply.headers
,chunk: Gun.text.ify(res.chunk) + '\n'
})
}
if(Gun.obj.has(res,'body')){
cb({
headers: reply.headers
,body: Gun.text.ify(res.body)
})
}
}
}
tran.jsonp = function(req, cb){
var reply = {headers: {}};
if(req.tran || req.headers['x-requested-with']){ return }
if((req.url.query||{}).jsonp){
cb.jsonp = req.url.query.jsonp;
Gun.obj.del(req.url.query, 'jsonp');
req.headers['x-requested-with'] = 'jsonp'; // polyfill
req.sub = req.headers['gun-sub'] = req.headers['gun-sub'] || req.url.query['Gun-Sub'] || req.url.query['gun-sub'];
Gun.obj.del(req.url.query, 'Gun-Sub');
Gun.obj.del(req.url.query, 'gun-sub');
return transport;
}
function transport(res){
if(!res){ return }
if(res.headers){
Gun.obj.map(res.headers, function(val, field){
reply.headers[field] = val;
});
}
if(Gun.obj.has(res,'chunk') && (!reply.body || Gun.list.is(reply.chunks))){
(reply.chunks = reply.chunks || []).push(res.chunk);
}
if(Gun.obj.has(res,'body')){
reply.body = res.body; // self-reference yourself so on the client we can get the headers and body.
reply.body = ';'+ cb.jsonp + '(' + Gun.text.ify(reply) + ');'; // javascriptify it! can't believe the client trusts us.
cb(reply);
}
}
}
tran.json = 'application/json';
tran.push = Gun.on.create();
return tran;
}());
opt.hooks = opt.hooks || {};
gun.opt({hooks: {
load: opt.hooks.load || s3.load
,set: opt.hooks.set || s3.set
,key: opt.hooks.key || s3.key
,transport: opt.hooks.transport || gun.server.transport
}}, true);
});
meta.json = 'application/json';
meta.JSON = function(res, data, multi){
if(res && !res._headerSent){
res.setHeader('Content-Type', meta.json);
}
if(!data && multi){
res.write(Gun.text.ify(multi||'') + '\n');
return;
}
return res.end(Gun.text.ify(data||''));
};
meta.CORS = function(req, res){
if(!res || res.CORSHeader || res._headerSent){ return }
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Methods", ["POST", "GET", "PUT", "DELETE", "OPTIONS"]);
res.setHeader("Access-Control-Allow-Credentials", false);
res.setHeader("Access-Control-Max-Age", 1000 * 60 * 60 * 24);
res.setHeader("Access-Control-Allow-Headers", ["X-Requested-With", "X-HTTP-Method-Override", "Content-Type", "Accept", "Gun-Sub"]);
res.setHeader("Access-Control-Expose-Headers", ["Content-Type", "Gun-Sub"]);
res.CORSHeader = true;
if(req && req.method === 'OPTIONS'){
res.end();
return true;
}
};
module.exports = Gun;
;(function(){
var Gun = require('gun/gun')
, formidable = require('formidable')
, url = require('url')
, meta = {};
Gun.on('opt').event(function(gun, opt){
gun.server = gun.server || function(req, res, next){ // this whole function needs refactoring and modularization
//console.log("\n\n GUN SERVER!");
next = next || function(){};
if(!req || !res){ return next() }
if(!req.url){ return next() }
if(!req.method){ return next() }
var msg = {};
msg.url = url.parse(req.url, true);
if(!gun.server.regex.test(msg.url.pathname)){ return next() }
msg.url.key = msg.url.pathname.replace(gun.server.regex,'') || '';
if(msg.url.key.toLowerCase() === '.js'){
res.writeHead(200, {'Content-Type': 'text/javascript'});
res.end(gun.server.js = gun.server.js || require('fs').readFileSync(__dirname + '/gun.js')); // gun server is caching the gun library for the client
return;
}
msg.url.key = msg.url.key.replace(/^\//i,'') || ''; // strip the base slash
msg.method = (req.method||'').toLowerCase();
msg.headers = req.headers;
var body
, form = new formidable.IncomingForm()
, post = function(err, body){
msg.body = body;
gun.__.opt.hooks.transport(msg, function(reply){
if(!res){ return }
if(!reply){ return res.end() }
if(reply.headers){
if(!res._headerSent){
Gun.obj.map(reply.headers, function(val, field){
res.setHeader(field, val);
});
}
}
meta.CORS(req, res); // add option to disable this
if(Gun.obj.has(reply,'chunk')){
res.write(Gun.text.ify(reply.chunk) || '');
}
if(Gun.obj.has(reply,'body')){
res.end(Gun.text.ify(reply.body) || '');
}
});
}
form.on('field',function(k,v){
(body = body || {})[k] = v;
}).on('file',function(k,v){
return; // files not supported in gun yet
}).on('error',function(e){
if(form.done){ return }
post(e);
}).on('end', function(){
if(form.done){ return }
post(null, body);
});
form.parse(req);
}
gun.server.regex = /^\/gun/i;
if(!gun.__.opt.keepMaxSockets){ require('https').globalAgent.maxSockets = require('http').globalAgent.maxSockets = Infinity } // WARNING: Document this!
gun.server.transport = (function(){
function tran(req, cb){
//console.log(req);
req.sub = req.headers['gun-sub']; // grab the sub
req.tab = tran.sub.s[req.sub] || {}; // check to see if there already is a tab associated with it, or create one
req.tab.sub = req.sub = req.sub || Gun.text.random(); // Generate a session id if we don't already have one
req.tran = tran.xhr(req, cb) || tran.jsonp(req, cb); // polyfill transport layer
clearTimeout(req.tab.timeout);
// raw test for now, no auth:
if(!req.tran){ return cb({headers: {"Content-Type": tran.json}, body: {err: "No transport layer!"}}) }
if('post' === req.method || 'patch' === req.method){ return tran.post(req, req.tran) } // TODO: Handle JSONP emulated POST via GET
if('get' !== req.method){ return req.tran({body: {err: "Invalid method"}}) }
if(!req.url.key){ return tran.sub(req, req.tran) } // get acts as sub, too.
return tran.load(req, req.tran); // else load the state for the tab!
}
tran.load = function(req, cb){
var reply = {}, key;
reply.headers = {'Content-Type': tran.json};
reply.headers['Gun-Sub'] = req.tab.sub = req.sub;
key = (Gun._.meta == req.url.key)? req.url.query : req.url.key;
console.log("Loading", req.url.key, 'for', req.tab);
gun.load(key, function(node){
tran.sub.scribe(req.tab, node._[Gun._.soul]);
cb({
headers: reply.headers
,body: node
});
}).blank(function(){
cb({
headers: reply.headers
,body: null
});
}).dud(function(err){
cb({
headers: reply.headers
,body: {err: err || "Unknown error."}
});
});
}
tran.post = function(req, cb){ // post is used as patch, sad that patch has such poor support
if(!req.body){ return cb({body: {err: "No body"}}) }
if(req.url.key && Gun.obj.has(req.body, Gun._.soul)){ // key hook!
req.tab = tran.sub.s[req.sub] || {};
req.tab.sub = req.sub;
console.log("key.hook", req.tab);
tran.sub.scribe(req.tab, req.body[Gun._.soul]);
return gun.load(req.body).get(function(frozen){
// NEED to allow a security callback so server can tamper with this!
this.key(req.url.key, function(err, reply){
reply = reply || {};
if(err){ reply.err = err }
reply = {body: reply};
reply.headers = {'Content-Type': tran.json};
reply.headers['Gun-Sub'] = req.tab.sub;
cb(reply);
});
}); // do I need to handle the blank case? :/ Not sure.
}
// raw test for now, no auth:
// should probably load all the nodes first? YES.
var context = gun.union(req.body, function(err, context){ // data safely transformed
cb = cb || function(){};
if(err || context.err){ return cb({body: {err: context.err}}) }
if(Gun.fns.is(gun.__.opt.hooks.set)){
gun.__.opt.hooks.set(context.nodes, function saved(err, data){ // now iterate through those nodes to S3 and get a callback once all are saved
var body = {};
if(err){
body.err = err ;
}
if(!req.sub){
if(!err){
body = defer.map({}, context.nodes, 1);
}
return cb({body: body});
}
var now = tran.post.s[req.sub]; // begin our stupid Chrome fix, we should abstract this out into defer (where it belogns) to keep things clean.
if(!now){ return } // utoh we've lost our reply to the tab!
clearTimeout(now.timeout);
now.body = now.body || {}; // make sure we have a body for our multi-response in a single response.
if(req.wait){ // did this request get deferred?
(now.body.refed = now.body.refed || {})[req.wait] = err? {err: err} : defer.map({}, context.nodes, 1); // then reply to it "here".
} else {
now.body.reply = err? {err: err} : defer.map({}, context.nodes, 1); // else this is the original POST that had to be upgraded.
}
if(0 < (now.count = ((now.count || 0) - 1))){
// Don't reply till all deferred POSTs have successfully heard back from S3. (Sarcasm: Like counting guarantees that)
return now.timeout = setTimeout(saved, gun.__.opt.throttle * 2 * 1000); // reply not guaranteed, so time it out, in seconds.
}
if(Gun.fns.is(now)){
now({body: now.body}); // FINALLY reply for ALL the POSTs for that session that accumulated.
} else {
// console.log("Error! We deleted our response!");
}
Gun.obj.del(tran.post.s, req.sub); // clean up our memory.
// need to rewrite that if Stream is enabled that both Stream + State save are guaranteed before replying.
});
// stuff past this point is just stupid implementation optimizations.
function defer(nodes, req){ // because Chrome can only handle 4 requests at a time, sad face.
if(!req.sub){
return;
}
var next = tran.post.s[req.sub];
if(!next){ // was there a previous POST? If not, we become the previous POST.
//cb({chunk: ''}); // because on some services (heroku) you need to reply starting a stream to keep the connection open.
return tran.post.s[req.sub] = cb;
}
next.count = (next.count || 1) + 1; // start counting how many we accumulate
next.body = next.body || {}; // this becomes the polyfill for all the posts
next.body.refed = next.body.refed || {}; // where we refeed the responses for the deferred POSTs.
req.wait = Gun.text.random(); // generate an random id for this deferred POST.
next.body.refed[req.wait] = false; // establish that we are incomplete.
cb({body: {defer: req.wait}}); // end this POST immediately so Chrome only ever uses a couple connections.
cb = null; // null it out so we don't accidentally reply to it once we hear back from S3.
}
defer.map = function(now, nodes, val){ // shortcut for maping which nodes were saved successfully
if(!now){ return }
Gun.obj.map(nodes, function(node, soul, map){
now[soul] = val;
});
return now;
}
defer(context.nodes, req); // actually do the weird stuff to make Chrome not be slow
} else {
context.err = "Warning! You have no persistence layer to save to!";
Gun.log(context.err);
cb({body: {err: "Server has no persistence layer!"}});
}
});
if(context.err){
cb({body: {err: context.err}});
return cb = null;
}
Gun.obj.map(context.nodes, function(node, soul){ // live push the stream out in realtime to every tab subscribed
var msg = {};
msg.headers = req.headers; // polyfill the delta as its own message.
msg.body = node;
console.log("emit delta", soul);
tran.push(soul).emit(msg);
});
}
tran.post.s = {};
tran.sub = function(req, cb){
//console.log("<-- ", req.sub, req.tran ," -->");
req.tab = tran.sub.s[req.sub];
if(!req.tab){
cb({
headers: {'Gun-Sub': ''}
,body: {err: "Please re-initialize sub."}
});
return;
}
//console.log("\n\n\n THE CURRENT STATUS IS");console.log(req.tab);
if(req.tab.queue && req.tab.queue.length){
tran.clean(req.tab); // We flush their data now, if they don't come back for more within timeout, we remove their session
console.log("_____ NOW PUSHING YOUR DATA ______", req.sub);
cb({ headers: {'Gun-Sub': req.sub} });
while(1 < req.tab.queue.length){
cb({ chunk: req.tab.queue.shift() });
}
cb({ body: req.tab.queue.shift() });
} else {
cb({chunk: ''}); // same thing as the defer code, initialize a stream to support some services (heroku).
req.tab.reply = cb;
console.log("_____ STANDING BY, WAITING FOR DATA ______", req.sub);
}
}
tran.sub.s = {};
tran.clean = function(tab, mult){
if(!tab){ return }
mult = mult || 1;
clearTimeout(tab.timeout);
tab.timeout = setTimeout(function(){
if(!tab){ return }
if(tab.reply){ tab.reply({body: {err: "Connection timed out"}}) }
console.log("!!!! DISCONNECTING CLIENT !!!!!", tab.sub);
Gun.obj.del(tran.sub.s, tab.sub)
}, gun.__.opt.disconnect * mult * 1000); // in seconds
}
tran.sub.scribe = function(tab, soul){
tran.sub.s[tab.sub] = tab;
tab.subs = tab.subs || {};
console.log("meow subscribes", soul);
tab.subs[soul] = tab.subs[soul] || tran.push(soul).event(function(req){
if(!req){ return }
if(!tab){ return this.off() } // resolve any dangling callbacks
req.sub = req.sub || req.headers['gun-sub'];
if(req.sub === tab.sub){ return } // do not send back to the tab that sent it
console.log('FROM:', req.sub, "TO:", tab.sub);
tran.clean(tab);
if(tab.reply){
tab.reply({
headers: {'Gun-Sub': tab.sub}
,body: req.body
});
tab.reply = null;
return;
}
(tab.queue = tab.queue || []).push(req.body);
});
tran.clean(tab, 2);
}
tran.xhr = function(req, cb){ // Streaming Long Polling
return req.tran || (req.headers['x-requested-with'] === 'XMLHttpRequest'? transport : null);
function transport(res){
if(!res){ return }
var reply = {headers: {}};
if(res.headers){
Gun.obj.map(res.headers, function(val, field){
reply.headers[field] = val;
});
}
reply.headers["Content-Type"] = tran.json;
if(Gun.obj.has(res,'chunk')){
cb({
headers: reply.headers
,chunk: Gun.text.ify(res.chunk) + '\n'
})
}
if(Gun.obj.has(res,'body')){
cb({
headers: reply.headers
,body: Gun.text.ify(res.body)
})
}
}
}
tran.jsonp = function(req, cb){
var reply = {headers: {}};
if(req.tran || req.headers['x-requested-with']){ return }
if((req.url.query||{}).jsonp){
cb.jsonp = req.url.query.jsonp;
Gun.obj.del(req.url.query, 'jsonp');
req.headers['x-requested-with'] = 'jsonp'; // polyfill
req.sub = req.headers['gun-sub'] = req.headers['gun-sub'] || req.url.query['Gun-Sub'] || req.url.query['gun-sub'];
Gun.obj.del(req.url.query, 'Gun-Sub');
Gun.obj.del(req.url.query, 'gun-sub');
return transport;
}
function transport(res){
if(!res){ return }
if(res.headers){
Gun.obj.map(res.headers, function(val, field){
reply.headers[field] = val;
});
}
if(Gun.obj.has(res,'chunk') && (!reply.body || Gun.list.is(reply.chunks))){
(reply.chunks = reply.chunks || []).push(res.chunk);
}
if(Gun.obj.has(res,'body')){
reply.body = res.body; // self-reference yourself so on the client we can get the headers and body.
reply.body = ';'+ cb.jsonp + '(' + Gun.text.ify(reply) + ');'; // javascriptify it! can't believe the client trusts us.
cb(reply);
}
}
}
tran.json = 'application/json';
tran.push = Gun.on.create();
return tran;
}());
opt.hooks = opt.hooks || {};
gun.opt({hooks: {
transport: opt.hooks.transport || gun.server.transport
}}, true);
});
meta.json = 'application/json';
meta.JSON = function(res, data, multi){
if(res && !res._headerSent){
res.setHeader('Content-Type', meta.json);
}
if(!data && multi){
res.write(Gun.text.ify(multi||'') + '\n');
return;
}
return res.end(Gun.text.ify(data||''));
};
meta.CORS = function(req, res){
if(!res || res.CORSHeader || res._headerSent){ return }
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Methods", ["POST", "GET", "PUT", "DELETE", "OPTIONS"]);
res.setHeader("Access-Control-Allow-Credentials", false);
res.setHeader("Access-Control-Max-Age", 1000 * 60 * 60 * 24);
res.setHeader("Access-Control-Allow-Headers", ["X-Requested-With", "X-HTTP-Method-Override", "Content-Type", "Accept", "Gun-Sub"]);
res.setHeader("Access-Control-Expose-Headers", ["Content-Type", "Gun-Sub"]);
res.CORSHeader = true;
if(req && req.method === 'OPTIONS'){
res.end();
return true;
}
};
}());

View File

@ -1,16 +0,0 @@
---
applications:
".":
name: gunjs
framework:
name: standalone
info:
mem: 64M
description: Standalone Application
exec:
runtime: node10
command: node init.js
infra: aws
url: http://gunjs.aws.af.cm
mem: 64M
instances: 1

46
on.js
View File

@ -1,46 +0,0 @@
;(function(){
var setImmediate = setImmediate || function(cb){setTimeout(cb,0)}
function On(){
var chain = new Chain();
return chain.$ = function(where){
chain.$[where] = function(fn){
chain.$[where] = fn;
}
chain.where = where;
return chain;
}
}
On.is = function(On){ return (On instanceof On)? true : false }
function Chain(){
if(!(this instanceof Chain)){
return new Chain();
}
}
Chain.chain = Chain.prototype;
Chain.chain.emit = function(a,s,d,f){
var me = this
, where = me.where
, args = Array.prototype.slice.call(arguments);
setImmediate(function(){
if(!me || !me.$ || !me.$[where]){ return }
me.$[where].apply(me, args);
});
return me;
}
if(typeof window !== "undefined"){
window.On = On;
} else {
module.exports = On;
}
;(function(){ // test
var doSomething = function(){
var cb = On();
cb('now').emit(1,2,3);
return cb;
}
doSomething('foo', 'bar').now(function(a,b,c){
console.log("Oh yeah baby", a,b,c);
})
}());
}());

View File

@ -1,5 +1,5 @@
{ "name": "gun"
, "version": "0.0.8"
, "version": "0.0.9"
, "author": "Mark Nadal"
, "description": "Graph engine."
, "engines": {
@ -9,6 +9,7 @@
"mime": "~>1.2.11",
"aws-sdk": "~>2.0.0",
"formidable": "~>1.0.15",
"ws": "~>0.4.32",
"request": "~>2.39.0"
}
, "devDependencies": {

View File

@ -1,2 +0,0 @@
console.log("!!! OPENSHIFT ONLY !!!");
require('./init');

148
shot0.js
View File

@ -1,148 +0,0 @@
module.exports = require('theory')
('shot',function(a){
return function(opt){
opt = opt || {};
opt.path = opt.path || '.'
opt.batch = opt.batch || 0;
opt.throttle = opt.throttle || 0;
opt.src = opt.src || (this && this.com) || '';
opt.cache = a.num.is(opt.cache)? opt.cache : opt.cache || 1;
if(root.node){ return require(opt.path+'/shots0')(opt); }
var u, shot = {},
store = window.amplify && window.amplify.store? amplify.store
: function(src, data){
if(data === u){ return store[src] }
return store[src] = data;
}
store.batch = [];
store.last = a.time.now();
store.list = function(){
var g = store(a.gun.event) || {}
, z = function(l,g,i){
if(i !== 0 && !i){ return }
if(!l || !l[i]){ return }
shot.fire(l[i], 1);
console.log("re-sent", l[i]);
a.time.wait(function(){ z(l,g,i+1) },1);
}
a.obj(g).each(function(l,g){
z(l,g,0);
});
}
store.sort = function(A,B){
if(!A || !B){ return 0 }
A = ((A||{})._||{})[a.gun._.ham]; B = ((B||{})._||{})[a.gun._.ham];
if(A < B){ return -1 }
else if(A > B){ return 1 }
else { return 0 }
}
store.add = function(m, g, b){
if(!m){ return }
g = '_' + (a(g,'at') || g || a(m,'where.at') || m.where);
var gs = store(a.gun.event) || {}
, when = shot.when(m);
gs[g] = gs[g] || [];
if(a.list(gs[g]).each(function(v){
var w = shot.when(v);
if(w === when){
return true;
}
})){ return 2; } // already
if(opt.batch && a.list.is(b)){ b.push(m) }
gs[g].push(m);
store(a.gun.event, gs);
return gs[g];
}
store.del = function(m, g){
if(!m){ return }
var gs = store(a.gun.event) || {}
, when = shot.when(m);
g = '_'+(m.where.at || m.where || g);
console.log("clear queue", g, m);
gs[g] = gs[g] || [];
gs[g] = a.list(gs[g]).each(function(v,i,t){
var w = shot.when(v);
if(w === when){
return;
}
t(v);
});
store(a.gun.event, gs);
}
store.set = function(key, val){
var s = store(a.gun.event) || {};
s[key] = val;
store(a.gun.event, s);
}
store.get = function(key, cb){
var s = store(a.gun.event) || {};
s = s[key];
if(cb){
return cb(null, s);
}
return s;
};
a.gun.shots(shot.fire = function(m, r){
if(!m || !m.where){ return }
if(!r){
if(store.add(m, m.where, store.batch) === 2){
return;
}
}
if(opt.src && opt.src.send){
m = opt.src.meta(m);
if(!m.what || !m.where || !m.when){ return }
console.log("to server!", m);
return opt.src.send(m);
}
return; // below should be a fallback. TODO: Unfinished!
});
shot.when = function(m){ return a(m,'what._.'+a.gun._.ham) || a(m,'_.'+a.gun._.ham) || m.when }
shot.load = function(where,cb,o){
if(!where){ return }
o = o || {};
var m = {what: where, how: {gun:3}}
, g = a.gun.magazine[where] || store.get(where);
g = a.fns.is(g)? g : a.obj.is(g)? a.gun(where, g) : null;
if(g){
//cb(g);
}
//console.log("!!! ASK !!!");
if(opt.src && opt.src.ask){
opt.src.ask(m,function(m){
if(g){
//console.log("!!! double load !!!");
//return; // prevent load from calling twice! Add sync comparison.
}
if(!m || !m.what){ cb(null) }
if(o.cache !== 0){
if(o.cache || opt.cache){ // make options more configurable.
store.set(where, m.what);
}
}
m = a.gun(where, m.what);
cb(m);
});
}
}
shot.spray = function(filter){
if(filter && filter.how){
shot.spray.action(filter);
return shot;
}
if(a.fns.is(filter)){
shot.spray.action = filter;
return shot;
}
return shot.spray.action;
}
shot.spray.action = function(m){
if(!m || !m.how || !m.how.gun){ return }
if(m.how.gun === -1){
store.del(m);
}
}
store.list();
return shot;
}
},['./gun0'])

305
shots0.js
View File

@ -1,305 +0,0 @@
module.exports = require('theory')
('shot',function(a){
var s3 = require(__dirname+'/gate/s3')
, store = require(__dirname+'/gate/redis');
function shot(opt){
opt = opt || {};
var u, shot = {};
opt.path = opt.path || '.'
opt.batch = opt.batch || 10;
opt.throttle = opt.throttle || 15;
opt.src = opt.src || (this && this.com) || '';
opt.redis = opt.redis || {};
opt.redis.max = a.num.is(opt.redis.max)? opt.redis.max : .8;
opt.redis.Max = Math.floor(require('os').totalmem() * opt.redis.max);
opt.redis.append = a.obj(opt.redis).has('append')? opt.redis.append : true;
opt.redis.expire = opt.redis.expire || 60*15;
opt.redis.config = function(){
if(opt.redis.config.done === 0){ return }
opt.redis.config.done = 3;
var reply = function(e,r){
if(e){ return }
opt.redis.config.done -= 1;
};
if(opt.redis.max){
store.client.config('set','maxmemory',opt.redis.Max, reply);
store.client.config('set','maxmemory-policy','allkeys-lru', reply);
}
if(opt.redis.append){
store.client.config('set','appendonly','yes', reply);
}
}
opt.s3 = opt.s3 || {};
opt.s3.Bucket = a.text.is(opt.s3.bucket)? opt.s3.bucket : (process.env.s3Bucket || '');
opt.s3.bucket = a.fns.is(opt.s3.bucket)? opt.s3.bucket : function(key){
return opt.s3.Bucket || a.text(key).clip('/',0,1);
}
opt.s3.key = a.fns.is(opt.s3.key)? opt.s3.key : function(key){
if(key.slice(0, opt.s3.Bucket.length) === opt.s3.Bucket){
key = key.slice(opt.s3.Bucket.length)||'';
if(key.charAt(0) === '/'){
key = key.slice(1);
}
}
return key;
}
store.batch = [];
store.last = a.time.now();
store.push = function(key, score, val, cb){
if(!val){ return }
store.client.zadd(key, score, val, function(e,r){
if(e){
store.clienf.zadd(key, score, val, cb);
return;
}
if(cb){ cb(e,r) }
});
}
store.when = function(m){ return a(m,'what._.'+a.gun._.ham) || a(m,'_.'+a.gun._.ham) || m.when }
store.where = function(m){ return a.text.is(m)? m : a.text.is(m.where)? m.where : m.where.at }
store.add = function(m, g){
if(!m){ return }
g = '_' + (g || a(m,'where.at') || m.where);
store.push(g, store.when(m) || 0, a.text.ify(m));
}
store.del = function(m, g){
}
store.sort = function(A,B){
if(!A || !B){ return 0 }
A = A.w; B = B.w;
if(A < B){ return -1 }
else if(A > B){ return 1 }
else { return 0 }
}
store.batching = 0;
store.batched = {};
store.batch = {};
store.persisted = {};
store.wait = null;
store.stay = function(key, val, cb){
store.batching += 1;
store.batch[key] = val;
(store.batched[key] = store.batched[key]||[]).push(cb);
if(opt.batch < store.batching){
return store.stay.now();
}
if(!opt.throttle){
return store.stay.now();
}
store.wait = store.wait || a.time.wait(store.stay.now, opt.throttle * 1000); // to seconds
}
store.stay.now = function(){
store.batching = 0;
a.time.stop(store.wait);
store.wait = null;
a.obj(store.batch).each(function(g,where){
if(!g || !where){ return }
//console.log('*************** save', where, '*******************');
store.stay.put(where,g,function(e,r){
a.list(store.batched[where]).each(function(cb){
if(a.fns.is(cb)){ cb(e,r) }
console.log('*** saved ***');
});
console.log(store.batched[where]);
delete store.batched[where];
});
});
}
store.stay.put = function(where,obj,cb){
s3(opt.s3.bucket(where)).put(opt.s3.key(where),obj,function(e,r){
if(!e){ store.persisted[where] = 's3' }
if(a.fns.is(cb)){ cb(e,r) }
});
}
store.set = function(key, value, cb, fn){
opt.redis.config();
var val = a.text.is(value)? value : a.text.ify(value);
if(a.fns.is(fn)){ store.stay(key, value, fn) }
//console.log("potential setex:", key, opt.redis.expire, val);
if(opt.redis.max){
store.client.set(key, val, function(e,r){
if(e){
store.clienf.setex(key, opt.redis.expire, val, cb);
return;
}
if(cb){ cb(e,r) }
});
} else {
store.client.setex(key, opt.redis.expire, val, function(e,r){
if(e){
store.clienf.setex(key, opt.redis.expire, val, cb);
return;
}
if(cb){ cb(e,r) }
});
}
}
store.get = function(key, cb){
store.clienf.get(key, function(e,r){
if(e || !r){ return store.client.get(key, cb) }
if(cb){ cb(e,r) }
});
}
shot.load = function(where,cb,o){
//console.log("shot.load >", where);
if(!where){ return }
where = store.where(where);
if(!a.text.is(where)){ return }
if(a.fns.is(a.gun.magazine[where])){
console.log('via memory', where);
cb(a.gun.magazine[where], null); // TODO: Need to clear queue these at some point, too!
return;
}
if(opt.src && opt.src.send){
//console.log("Getting and subscribe");
opt.src.send({where:{on: where}, how: {gun: 2}});
}
store.get(where, function(e,r){
if(e || !r){
return s3(opt.s3.bucket(where)).get(opt.s3.key(where),function(e,r,t){
console.log('via s3', where); if(e){ console.log(e) }
if(e || !r){ return cb(null, e) }
store.persisted[where] = 's3';
store.set(where, (t || a.text.ify(r)));
r = shot.load.action(where,r); //a.gun(where,r);
cb(r, e);
},o);
}
console.log('via redis', where);
r = a.obj.ify(r);
r = shot.load.action(where,r); //a.gun(where,r);
cb(r,e);
});
}
shot.load.action = function(w,o){
if(!w || !o){ return }
return a.gun(w,o);
}
shot.spray = function(m){
if(m && m.how){
shot.spray.action(m);
return shot;
}
if(a.fns.is(m)){
shot.spray.transform = m;
return shot.spray.action;
}
return shot.spray.action;
}
shot.spray.transform = function(g,m,d){if(d){d()}}
shot.spray.action = function(m){
console.log("gun spray ---->", m, (opt.src && opt.src.way? opt.src.way : null));
if(!m || !m.how){ return }
var where = store.where(m);
if(m.how.gun === -2){
console.log("gun data from others", m);
if(m && m.what && m.what.session){ console.log(m.what.session) }
return;
}
if(m.how.gun === 2){
if(!a.fns.is(a.gun.magazine[where])){
return;
}
if(opt.src && opt.src.send){
console.log("gun subscribe sync", m);
opt.src.send({what: a.gun.magazine[where](), where: where, how: {gun: -(m.how.gun||2)}});
}
return;
}
if(m.how.gun === 3){
shot.load(m.what, function(g,e){
shot.pump.action(g, m, function(){ // receive custom edited copy here and send it down instead.
if(!opt.src || !opt.src.reply){ return }
m.what = a.fns.is(g)? g() : {};
m.how.gun = -(m.how.gun||3);
opt.src.reply(m);
}, e);
});
return;
}
if(!where){ return }
store.add(m);
var n = a.obj.copy(m);
shot.load(where, function(g,e){
var done = function(){
var u, s, w = store.when(m) || 0, r = {}, cb;
m.how.gun = -(m.how.gun||1);
g = a.fns.is(g)? g : (a.gun.magazine[where] || function(){});
a.obj(m.what).each(function(v,p){
if(g(p,v,w) === u){
r[p] = 0; // Error code
return;
} s = true;
});
m.what = r;
cb = function(){
if(!opt.src || !opt.src.reply || m.where.mid){ return }
opt.src.reply(m);
console.log('reply', m);
}
if(!s){ return cb() }
store.set(where, g(), null, cb);
};
done.end = function(){};
shot.spray.transform(g, m, done, e);
});
if(n.where && !n.where.mid && opt.src.send){
n.who = {};
opt.src.send(n);
}
}
if(opt.src && opt.src.on){
opt.src.on(shot.spray.action);
}
shot.pump = function(fn){
shot.pump.action = fn || shot.pump.action;
return shot;
}
shot.pump.action = function(g,m,d){if(d){d()}}
shot.server = function(req,res){
console.log('shot server', req);
if(!req || !res){ return }
var b = shot.server.get(req);
if(!b || !b.b){ return }
b = a.obj.ify((b||{}).b);
if(a.obj.is(b)){ b = [b] }
if(!a.list.is(b)){ return }
//console.log('gun >>>>>>');
a.list(b).each(function(v,i){
//console.log(v);
});
//console.log('<<<<<< gun');
if(req.how && req.when && req.who && a.fns.is(res)){
req.what.body = {ok:1};
res(req);
}
return true;
}
shot.server.get = function(m){
return !a.obj.empty(a(m,'what.form'))? a(m,'what.form')
: !a.obj.empty(a(m,'what.url.query'))? a(m,'what.url.query')
: false ;
};
a.gun.shots(function(m){
var w;
if(!store.persisted[w = store.where(m)]){
if(opt.src && opt.src.send){
//console.log("made and subscribed", m);
opt.src.send({where:{on: w}, how: {gun: 2}})
}
store.stay.put(w, m.what, function(e,r){
//console.log("---> gun shots", m, "new graph saved!");
});
return;
}
if(opt.src && opt.src.send){
opt.src.send(m);
}
});
shot.gun = a.gun;
return shot;
}
shot.gun = a.gun;
return shot;
},[__dirname+'/gun0'])

View File

@ -147,6 +147,114 @@ describe('Gun', function(){
expect(Gun.obj.map({a:'z',b:3,c:'x'},function(v,i,t){ if(v===3){ return 0 }})).to.be(0);
});
});
describe('Functions', function(){
it('sum',function(done){
var obj = {a:2, b:2, c:3, d: 9};
Gun.obj.map(obj, function(num, key){
setTimeout(this.add(function(){
this.sum(null, num * num);
}, key), parseInt((""+Math.random()).substring(2,5)));
}, Gun.fns.sum(function(err, val){
expect(val.a).to.eql(4);
expect(val.b).to.eql(4);
expect(val.c).to.eql(9);
expect(val.d).to.eql(81);
done();
}));
});
});
describe('Gun Safety', function(){
var gun = Gun();
it('is',function(){
expect(Gun.is(gun)).to.be(true);
expect(Gun.is(true)).to.be(false);
expect(Gun.is(false)).to.be(false);
expect(Gun.is(0)).to.be(false);
expect(Gun.is(1)).to.be(false);
expect(Gun.is('')).to.be(false);
expect(Gun.is('a')).to.be(false);
expect(Gun.is(Infinity)).to.be(false);
expect(Gun.is(NaN)).to.be(false);
expect(Gun.is([])).to.be(false);
expect(Gun.is([1])).to.be(false);
expect(Gun.is({})).to.be(false);
expect(Gun.is({a:1})).to.be(false);
expect(Gun.is(function(){})).to.be(false);
});
it('is value',function(){
expect(Gun.is.value(false)).to.be(true);
expect(Gun.is.value(true)).to.be(true);
expect(Gun.is.value(0)).to.be(true);
expect(Gun.is.value(1)).to.be(true);
expect(Gun.is.value('')).to.be(true);
expect(Gun.is.value('a')).to.be(true);
expect(Gun.is.value({'#':'somesoulidhere'})).to.be('somesoulidhere');
expect(Gun.is.value({'#':'somesoulidhere', and: 'nope'})).to.be(false);
expect(Gun.is.value(Infinity)).to.be(false); // boohoo :(
expect(Gun.is.value(NaN)).to.be(false);
expect(Gun.is.value([])).to.be(false);
expect(Gun.is.value([1])).to.be(false);
expect(Gun.is.value({})).to.be(false);
expect(Gun.is.value({a:1})).to.be(false);
expect(Gun.is.value(function(){})).to.be(false);
});
it('is soul',function(){
expect(Gun.is.soul({'#':'somesoulidhere'})).to.be('somesoulidhere');
expect(Gun.is.soul({'#':'somethingelsehere'})).to.be('somethingelsehere');
expect(Gun.is.soul({'#':'somesoulidhere', and: 'nope'})).to.be(false);
expect(Gun.is.soul({or: 'nope', '#':'somesoulidhere'})).to.be(false);
expect(Gun.is.soul(false)).to.be(false);
expect(Gun.is.soul(true)).to.be(false);
expect(Gun.is.soul('')).to.be(false);
expect(Gun.is.soul('a')).to.be(false);
expect(Gun.is.soul(0)).to.be(false);
expect(Gun.is.soul(1)).to.be(false);
expect(Gun.is.soul(Infinity)).to.be(false); // boohoo :(
expect(Gun.is.soul(NaN)).to.be(false);
expect(Gun.is.soul([])).to.be(false);
expect(Gun.is.soul([1])).to.be(false);
expect(Gun.is.soul({})).to.be(false);
expect(Gun.is.soul({a:1})).to.be(false);
expect(Gun.is.soul(function(){})).to.be(false);
});
it('is node',function(){
expect(Gun.is.node({_:{'#':'somesoulidhere'}})).to.be(true);
expect(Gun.is.node({_:{'#':'somesoulidhere'}, a:0, b: 1, c: '', d: 'e', f: {'#':'somethingelsehere'}})).to.be(true);
expect(Gun.is.node({_:{'#':'somesoulidhere'}, a:0, b: 1, c: '', d: 'e', f: {'#':'somethingelsehere'}, g: Infinity})).to.be(false);
expect(Gun.is.node({_:{'#':'somesoulidhere'}, a:0, b: 1, z: NaN, c: '', d: 'e'})).to.be(false);
expect(Gun.is.node({_:{'#':'somesoulidhere'}, a:0, b: 1, y: {_: 'cool'}, c: '', d: 'e'})).to.be(false);
expect(Gun.is.node({_:{'#':'somesoulidhere'}, a:0, b: 1, x: [], c: '', d: 'e'})).to.be(false);
expect(Gun.is.node({})).to.be(false);
expect(Gun.is.node({a:1})).to.be(false);
expect(Gun.is.node({_:{}})).to.be(false);
expect(Gun.is.node({_:{}, a:1})).to.be(false);
expect(Gun.is.node({'#':'somesoulidhere'})).to.be(false);
});
it('is graph',function(){
expect(Gun.is.graph({'somesoulidhere': {_:{'#':'somesoulidhere'}}})).to.be(true);
expect(Gun.is.graph({'somesoulidhere': {_:{'#':'somesoulidhere'}}, 'somethingelsehere': {_:{'#':'somethingelsehere'}}})).to.be(true);
expect(Gun.is.graph({'somesoulidhere': {_:{'#':'somesoulidhere'}, a:0, b: 1, c: '', d: 'e', f: {'#':'somethingelsehere'}}, 'somethingelsehere': {_:{'#':'somethingelsehere'}}})).to.be(true);
expect(Gun.is.graph({'somesoulidhere': {_:{'#':'somesoulidhere'}, a:0, b: 1, c: '', d: 'e', f: {'#':'somethingelsehere'}}})).to.be(true);
expect(Gun.is.graph({'somesoulidhere': {_:{'#':'somesoulidhere'}, a:0, b: 1, c: '', d: 'e', f: {'#':'somethingelsehere'}}, foo: 1, 'somethingelsehere': {_:{'#':'somethingelsehere'}}})).to.be(false);
expect(Gun.is.graph({'somesoulidhere': {_:{'#':'somesoulidhere'}, a:0, b: 1, c: '', d: 'e', f: {'#':'somethingelsehere'}}, foo: {}, 'somethingelsehere': {_:{'#':'somethingelsehere'}}})).to.be(false);
expect(Gun.is.graph({'somesoulidhere': {_:{'#':'somesoulidhere'}, a:0, b: 1, c: '', d: 'e', f: {'#':'somethingelsehere'}}, foo: {_:{'#':'FOO'}}, 'somethingelsehere': {_:{'#':'somethingelsehere'}}})).to.be(false);
expect(Gun.is.graph({'somesoulidhere': {_:{'#':'somesoulidhere'}, a:0, b: 1, c: '', d: 'e', f: {'#':'somethingelsehere'}}, foo: {_:{}}, 'somethingelsehere': {_:{'#':'somethingelsehere'}}})).to.be(false);
expect(Gun.is.graph({'somesoulidhere': {_:{'#':'somesoulidhere'}, a:0, b: Infinity, c: '', d: 'e', f: {'#':'somethingelsehere'}}})).to.be(false);
expect(Gun.is.graph({'somesoulidhere': {_:{'#':'somesoulidhere'}, a:0, b: Infinity, c: '', d: 'e', f: {'#':'somethingelsehere'}}, 'somethingelsehere': {_:{'#':'somethingelsehere'}}})).to.be(false);
expect(Gun.is.graph({_:{'#':'somesoulidhere'}})).to.be(false);
expect(Gun.is.graph({_:{'#':'somesoulidhere'}, a:0, b: 1, c: '', d: 'e', f: {'#':'somethingelsehere'}})).to.be(false);
expect(Gun.is.graph({_:{'#':'somesoulidhere'}, a:0, b: 1, c: '', d: 'e', f: {'#':'somethingelsehere'}, g: Infinity})).to.be(false);
expect(Gun.is.graph({_:{'#':'somesoulidhere'}, a:0, b: 1, z: NaN, c: '', d: 'e'})).to.be(false);
expect(Gun.is.graph({_:{'#':'somesoulidhere'}, a:0, b: 1, y: {_: 'cool'}, c: '', d: 'e'})).to.be(false);
expect(Gun.is.graph({_:{'#':'somesoulidhere'}, a:0, b: 1, x: [], c: '', d: 'e'})).to.be(false);
expect(Gun.is.graph({})).to.be(false); // Empty graph is not a graph :(
expect(Gun.is.graph({a:1})).to.be(false);
expect(Gun.is.graph({_:{}})).to.be(false);
expect(Gun.is.graph({_:{}, a:1})).to.be(false);
expect(Gun.is.graph({'#':'somesoulidhere'})).to.be(false);
});
});
});
it('ify', function(){

View File

@ -1,64 +1,64 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
</head>
<body>
<style>
.table li {
float: left;
min-width: 200px;
max-width: 400px;
}
ul, li {
list-style: none;
}
.clear {
clear: both;
}
.none {
display: none;
}
</style>
<ul>
<li><ul class="table none">
<li>Seconds in month:</li>
<li><input type="number" value="2629743.83" id="sim"></li>
</ul></li>
<li class="clear"></li>
<li><ul class="table">
<li>Persist every seconds:</li>
<li><input type="number" value="15" id="se"></li>
</ul></li>
<li class="clear"></li>
<li><ul class="table">
<li>Over how many objects:</li>
<li><input type="number" value="100" id="o"></li>
</ul></li>
<li class="clear"></li>
<li><ul class="table">
<li>Cost $:</li>
<li><input type="number" value="" readonly id="r"></li>
</ul></li>
</ul>
<br>
<p>
This page is for throughput calculation, it assumes continuous load non-stop.
</p>
<script>
$(function(){
var sim = $('#sim')
, se = $('#se')
, o = $('#o')
, r = $('#r')
, n = function(n){ return parseFloat(n) }
$(document).on('keyup', function(){
r.val(
(( n(sim.val()) / n(se.val()) ) * n(o.val()) / 1000 * 0.005 ).toFixed(2)
);
})
})
</script>
</body>
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
</head>
<body>
<style>
.table li {
float: left;
min-width: 200px;
max-width: 400px;
}
ul, li {
list-style: none;
}
.clear {
clear: both;
}
.none {
display: none;
}
</style>
<ul>
<li><ul class="table none">
<li>Seconds in month:</li>
<li><input type="number" value="2629743.83" id="sim"></li>
</ul></li>
<li class="clear"></li>
<li><ul class="table">
<li>Persist every seconds:</li>
<li><input type="number" value="15" id="se"></li>
</ul></li>
<li class="clear"></li>
<li><ul class="table">
<li>Over how many objects:</li>
<li><input type="number" value="100" id="o"></li>
</ul></li>
<li class="clear"></li>
<li><ul class="table">
<li>Cost $:</li>
<li><input type="number" value="" readonly id="r"></li>
</ul></li>
</ul>
<br>
<p>
This page is for throughput calculation, it assumes continuous load non-stop.
</p>
<script>
$(function(){
var sim = $('#sim')
, se = $('#se')
, o = $('#o')
, r = $('#r')
, n = function(n){ return parseFloat(n) }
$(document).on('keyup', function(){
r.val(
(( n(sim.val()) / n(se.val()) ) * n(o.val()) / 1000 * 0.005 ).toFixed(2)
);
})
})
</script>
</body>
</html>

46
web/deck/deck.html Normal file
View File

@ -0,0 +1,46 @@
<style>
html, body {
margin: 0;
padding: 0;
text-align: center;
font-size: 36pt;
font-family: Verdana, Geneva, sans-serif;
}
</style>
<div style="height: 100%; min-height: 500px; background-color: rgb(241, 90, 34); color: white;">
<div id="e1413969480658t7942" class="" style="position: relative; display: block; overflow: hidden; padding: 10px; margin: 0px auto; min-height: 413px;
background-image: url('wave.png'); background-color: rgb(108, 197, 195); background-position: 43.1875% 100%; background-repeat: repeat-x;">
<div id="e1414010158000t6484" class="" style="position: relative; display: block; overflow: hidden; padding: 10px; margin: 0px auto; min-height: 9px;" contenteditable="false">Problem</div>
<div id="e1414009476621t898" class="" style="position: relative; display: block; overflow: hidden; padding: 10px; margin: 0px auto; min-height: 481px; width: 370px;
background-image: url('whale.png'); background-position: 50% 50%; background-repeat: no-repeat;"></div>
</div>
<div id="e1414009076551t8032" class="" style="position: relative; display: block; overflow: hidden; padding: 10px; margin: 0px auto 51px; min-height: 100px;">
<br>Hassle to deploy slow databases that are costly to scale</div>
</div>
<div id="e1414009851463t501" class="" style="position: relative; display: block; overflow: hidden; padding: 10px; margin: 0px auto; height: 100%; min-height: 500px;">
<div id="e1414009879758t838" class="" style="position: relative; display: block; overflow: hidden; padding: 10px; margin: 0px auto; min-height: 100px; background-color: rgba(0, 0, 0, 0);" contenteditable="false">Solution</div>
<div id="e1414009950683t8894" class="" style="position: relative; display: block; overflow: hidden; padding: 10px; margin: 0px auto; width: 50%; min-width: 200px; max-width: 500px; height: 400px;
background-image: url('../../img/gun-logo.png'); background-position: 50% 50%; background-repeat: no-repeat; background-size: 100%;"></div>
<div id="e1414009972993t897" class="" style="position: relative; display: block; overflow: hidden; padding: 10px; margin: 0px auto; min-height: 100px; background-color: rgba(0, 0, 0, 0);" contenteditable="false">the NoDB database</div>
</div>
<div id="e1414010217854t5686" class="" style="position: relative; display: block; overflow: hidden; padding: 10px; margin: 0px auto; height: 100%; min-height: 500px; background-color: black; color: white;
background-image: url('polygen.png'); background-position: 50% 50%; background-repeat: no-repeat; background-size: 100%;">
<div id="e1414010395848t489" class="" style="position: relative; display: block; overflow: hidden; padding: 10px; margin: 0px auto; min-height: 100px;" contenteditable="false">How</div>
<div id="e1414010397417t8943" class="" style="position: relative; display: block; overflow: hidden; padding: 10px; margin: 0px auto; height: 500px;"></div>
<div id="e1414010398484t2942" class="" style="position: relative; display: block; overflow: hidden; padding: 10px; margin: 0px auto; min-height: 100px;" contenteditable="false">peer to peer algorithms that mimic reality</div>
</div>
<div id="e1414010478794t8943" class="" style="position: relative; display: block; overflow: hidden; padding: 10px; margin: 0px auto; height: 100%; min-height: 500px;">
<div id="e1414010488753t8274" class="" style="position: relative; display: block; overflow: hidden; padding: 10px; margin: 0px auto; min-height: 100px;" contenteditable="false">Now</div>
<div id="e1414010489729t8174" class="" style="position: relative; display: block; overflow: hidden; padding: 10px; margin: 0px auto; height: 400px;
background-image: url('stats.png'); background-position: 50% 50%; background-repeat: no-repeat; background-size: 100%;"></div>
<div id="e1414010490585t2896" class="" style="position: relative; display: block; overflow: hidden; padding: 10px; margin: 0px auto; min-height: 100px;" contenteditable="false">fastest growing trends ever in software history</div>
</div>
<div id="e1414010542879t6487" class="" style="position: relative; display: block; overflow: hidden; padding: 10px; margin: 0px auto; min-height: 500px; height: 100%; background-color: black; color: white;
background-image: url('team2.jpg'); background-position: 39.8610229492188% 17.7705977382876%; background-repeat: no-repeat; background-size: 100%;">
<div id="e1414010614360t886" class="" style="position: relative; display: block; overflow: hidden; padding: 10px; margin: 0px auto; min-height: 100px;" contenteditable="false">Team</div>
<div id="e1414010615329t6812" class="" style="position: relative; display: block; overflow: hidden; padding: 10px; margin: 0px auto; height: 400px;"></div>
<div id="e1414010616147t6367" class="" style="position: relative; display: block; overflow: hidden; padding: 10px; margin: 0px auto; min-height: 100px;" contenteditable="false"></div>
</div>
<div id="e1414010638042t831" class="" style="position: relative; display: block; overflow: hidden; padding: 10px; margin: 0px auto; min-height: 500px; height: 100%;" contenteditable="false">
<div id="e1414010679930t7366" class="create-evyt" style="position: relative; display: block; overflow: hidden; padding: 10px; margin: 0px auto; min-height: 100px;" contenteditable="false">we@gunDB.io are raising $500k</div>
</div>

BIN
web/deck/team2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 522 KiB

BIN
web/deck/wave.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
web/deck/whale.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

Before

Width:  |  Height:  |  Size: 113 KiB

After

Width:  |  Height:  |  Size: 113 KiB

View File

Before

Width:  |  Height:  |  Size: 81 KiB

After

Width:  |  Height:  |  Size: 81 KiB

View File

@ -1,87 +1,93 @@
Notes:
Messaging
Every message has who/what/when/where/why/how metadata.
Who is information that identifies the potential keys or locations a reply should be made to, such that a user can receive it no matter where they are
What is the message/delta itself
When is when the message was sent, this may have no relation to a timestamp on a delta transmission
Where is the destination that the message is trying to get to, and the paths it has taken to get there
Why is any arbitrary comment
How is the transformation that caused the message, and potentially the expected transformation to happen
Data
Because data can be in more than one place at a time, its identifier should not be mixed with any whereabouts even if you are planning on only using it within your walled garden.
Instead, the data itself should express its particular locality - information about a statue in Rome should not be identified a being Roman, but express it is Roman.
Therefore, preferrably the identifier for a thing should be globally unique, in case it is ever shared by multiple services - that way conflict won't happen.
This is important because that way any service is forced to do a scan on its own dataset to match with this service's own identifier and link them together - or start fresh if no match exists.
Information is not deleted, mostly just dereferenced - which may eventually cause cold storage, and loss of data as every system has physical limitations.
Arrays cannot be supported because cardinality is actually an expression of the data, not an identifier - for if it were, it would cause concurrency problems resulting in divergence.
Identifiers
Reality seems to be lacking any true identifiers because we perceive things in incredibly mutable states.
Often times attributes that may appear to be static are in fact not - take for instance the color of a car.
One generally assumes that the color will not change, since it is not observed much - however the lifetime of a program may outlive the developer. Even the sun will go dark one day.
This is the power of graphs, particularly in a functional setting - they are searchable, potentially timelessly.
As such identifiers should only be created in response to an attempt to match incoming unfound data with data stored.
If successful, the service is free and should make as many extra identifiers to reference and link that data again as to avoid doing slow scans again.
The most likely candidate for that identifier is the identifier that was given to the service, as there is high probability that the requester will make such requests again.
Throught his means, an identifier can spread like a virus through multiple services, where if it exists it can be retrieved immediately.
Thus, no one identifier should potentially conflict with any other identifier, as that would produce an erroneous lookup and a faulty response.
Do identifiers point to subsets or nodes, or both? Where do identifiers live? Ever in the graph itself? A developer of course would want an identifier to point to both.
However this is a little tricky, because a single node by itself is fairly useless (hermeneutics) because it has no context, especially if it is composed of many parts.
So an identifier referencing a "single node" should technically pull in its relations as well, into the subset. But what then do we return to the developer? The subset or the node?
If you assume the node, then identifiers "point" to different types of data - unless we allow the node the same methods as the subset, where map returns itself.
If we return the subset, it is inconvenient that you then have to scan for the thing you were already identifying, unless the map method also accepts traversal strings.
Identifiers are suppose to intentionally allow humans to think in a document based perspective, however there is no guarantee that the pieces in their system will remain that way.
Take for example a car, you'd assume that the wheel is part of the car and should be referenced as such. But what happens when the tire pops? It is removed and then used as a swing.
Now tell me, the "belongingness" of the tire is now in the hierarchy of the tree that it was hung on. Hierarchy is imposed by directional relations, not as static structures.
So there must be a way to evolve the system, for if we assume the identifier now references the subset, giving context to the original node, we need all of them to be uniquely referenced.
The unique references are the system's internal IDs, not the human friendly identifiers, these must be system-wide guaranteed to be unique.
But if everything has one, no matter how small, then that increases the odds quite substantially of conflicts. Meaning larger IDs need to be generated, which is never pretty.
This also then causes scanning issues, cause now countless tiny nodes are floating around in the system that will get mapped over, that is unpleasant for the developer.
Unless of course there are really good tools that allow them to map with string traversals (known paths) and value traversal (matching structures), in addition to the callback.
Meaning everything should be its own object, but really good search tools should be available to make this easy.
If this is the case, enforce the many-solution, that you alway have a subset and never a single node - a single node is just a subset of one.
Or is it? Or is it the subset of the things that compose the node? Do you hide these from the developer? Expose them?
It seems like subset of one works fine when you already have the larger subset, but not when you are using the initial identifier.
So can we mitigate that by providing really good priority loading tools?
Special Characters
These are reserved for gun, to include meta-data on the data itself.
/ is used as a delimiter in service specific identifiers
# is used to define the transition from a graph identifier, into the nodes themselves
. represents walking the path through a node's scope
_ represents non-human data in the graph that the amnesia machine uses to process stuff
> and < are dedicated to comparing timestamp states, timelessly to avoid malicious abuse (this should always come last, because requests will be rejected without it)
{
who: {}
,what: {'#": 'email/hi@example.com'}
,when: {'>': 1406184438192 }
,where: {}
,how: '*'
}
{
_: {
#: 'email/hi@example.com'
>: 1406184438192
}
}
Stream
If we receive a message with data at a symbolic scope that doesn't exist we should still save it.
However if we attempt to read it, we should be unable to access it because the symbols haven't been connected.
That way idempotently, when the symbols are connected, it'll then be readable if they haven't already been overwritten.
Grouping of symbols always inherit and merge, if all of them need to be dereferenced you must explicitly dereference it.
How do we do memory management / clean up then of old dead bad data?
Init
You initialize with a node(s) you want to connect to.
Evolution
var node = gun.create('person/joe', {}); // this creates a 'new' node with an identifier to this node
node('name', 'joe'); // changes properties
node('age', 24);
node('eyes', {}); // this internally creates a new node within the same subset as joe,
HOOKS:
- TRANSPORT:
Has to basically re-implement set/load/key over some transport.
REMEMBER that you have to subscribe on all set/load/key (especially key).
Notes:
Messaging
Every message has who/what/when/where/why/how metadata.
Who is information that identifies the potential keys or locations a reply should be made to, such that a user can receive it no matter where they are
What is the message/delta itself
When is when the message was sent, this may have no relation to a timestamp on a delta transmission
Where is the destination that the message is trying to get to, and the paths it has taken to get there
Why is any arbitrary comment
How is the transformation that caused the message, and potentially the expected transformation to happen
Data
Because data can be in more than one place at a time, its identifier should not be mixed with any whereabouts even if you are planning on only using it within your walled garden.
Instead, the data itself should express its particular locality - information about a statue in Rome should not be identified a being Roman, but express it is Roman.
Therefore, preferrably the identifier for a thing should be globally unique, in case it is ever shared by multiple services - that way conflict won't happen.
This is important because that way any service is forced to do a scan on its own dataset to match with this service's own identifier and link them together - or start fresh if no match exists.
Information is not deleted, mostly just dereferenced - which may eventually cause cold storage, and loss of data as every system has physical limitations.
Arrays cannot be supported because cardinality is actually an expression of the data, not an identifier - for if it were, it would cause concurrency problems resulting in divergence.
Identifiers
Reality seems to be lacking any true identifiers because we perceive things in incredibly mutable states.
Often times attributes that may appear to be static are in fact not - take for instance the color of a car.
One generally assumes that the color will not change, since it is not observed much - however the lifetime of a program may outlive the developer. Even the sun will go dark one day.
This is the power of graphs, particularly in a functional setting - they are searchable, potentially timelessly.
As such identifiers should only be created in response to an attempt to match incoming unfound data with data stored.
If successful, the service is free and should make as many extra identifiers to reference and link that data again as to avoid doing slow scans again.
The most likely candidate for that identifier is the identifier that was given to the service, as there is high probability that the requester will make such requests again.
Throught his means, an identifier can spread like a virus through multiple services, where if it exists it can be retrieved immediately.
Thus, no one identifier should potentially conflict with any other identifier, as that would produce an erroneous lookup and a faulty response.
Do identifiers point to subsets or nodes, or both? Where do identifiers live? Ever in the graph itself? A developer of course would want an identifier to point to both.
However this is a little tricky, because a single node by itself is fairly useless (hermeneutics) because it has no context, especially if it is composed of many parts.
So an identifier referencing a "single node" should technically pull in its relations as well, into the subset. But what then do we return to the developer? The subset or the node?
If you assume the node, then identifiers "point" to different types of data - unless we allow the node the same methods as the subset, where map returns itself.
If we return the subset, it is inconvenient that you then have to scan for the thing you were already identifying, unless the map method also accepts traversal strings.
Identifiers are suppose to intentionally allow humans to think in a document based perspective, however there is no guarantee that the pieces in their system will remain that way.
Take for example a car, you'd assume that the wheel is part of the car and should be referenced as such. But what happens when the tire pops? It is removed and then used as a swing.
Now tell me, the "belongingness" of the tire is now in the hierarchy of the tree that it was hung on. Hierarchy is imposed by directional relations, not as static structures.
So there must be a way to evolve the system, for if we assume the identifier now references the subset, giving context to the original node, we need all of them to be uniquely referenced.
The unique references are the system's internal IDs, not the human friendly identifiers, these must be system-wide guaranteed to be unique.
But if everything has one, no matter how small, then that increases the odds quite substantially of conflicts. Meaning larger IDs need to be generated, which is never pretty.
This also then causes scanning issues, cause now countless tiny nodes are floating around in the system that will get mapped over, that is unpleasant for the developer.
Unless of course there are really good tools that allow them to map with string traversals (known paths) and value traversal (matching structures), in addition to the callback.
Meaning everything should be its own object, but really good search tools should be available to make this easy.
If this is the case, enforce the many-solution, that you alway have a subset and never a single node - a single node is just a subset of one.
Or is it? Or is it the subset of the things that compose the node? Do you hide these from the developer? Expose them?
It seems like subset of one works fine when you already have the larger subset, but not when you are using the initial identifier.
So can we mitigate that by providing really good priority loading tools?
Special Characters
These are reserved for gun, to include meta-data on the data itself.
/ is used as a delimiter in service specific identifiers
# is used to define the transition from a graph identifier, into the nodes themselves
. represents walking the path through a node's scope
_ represents non-human data in the graph that the amnesia machine uses to process stuff
> and < are dedicated to comparing timestamp states, timelessly to avoid malicious abuse (this should always come last, because requests will be rejected without it)
{
who: {}
,what: {'#": 'email/hi@example.com'}
,when: {'>': 1406184438192 }
,where: {}
,how: '*'
}
{
_: {
#: 'email/hi@example.com'
>: 1406184438192
}
}
Stream
If we receive a message with data at a symbolic scope that doesn't exist we should still save it.
However if we attempt to read it, we should be unable to access it because the symbols haven't been connected.
That way idempotently, when the symbols are connected, it'll then be readable if they haven't already been overwritten.
Grouping of symbols always inherit and merge, if all of them need to be dereferenced you must explicitly dereference it.
How do we do memory management / clean up then of old dead bad data?
Init
You initialize with a node(s) you want to connect to.
Evolution
var node = gun.create('person/joe', {}); // this creates a 'new' node with an identifier to this node
node('name', 'joe'); // changes properties
node('age', 24);
node('eyes', {}); // this internally creates a new node within the same subset as joe,
node('eyes.color', 'blue');

210
web/time.html Normal file
View File

@ -0,0 +1,210 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="../gun.js"></script>
<link id="style" rel="stylesheet" href="https://yandex.st/highlightjs/8.0/styles/sunburst.min.css">
<script src="https://yandex.st/highlightjs/8.0/highlight.min.js"></script>
<script src="https://dl.dropboxusercontent.com/u/4374976/random/phrase.js"></script>
</head>
<body>
<style>
@import url(http://fonts.googleapis.com/css?family=Dosis|Poiret+One|Oxygen);
html, body {
font-family: 'Oxygen', Candara, Calibri, Segoe, "Segoe UI", Optima, Arial, sans-serif;
}
.center {
text-align: center;
}
.lean {
font-family: 'Poiret One', Candara, Calibri, Segoe, "Segoe UI", Optima, Arial, sans-serif;
}
.clean {
font-family: 'Dosis', Candara, Calibri, Segoe, "Segoe UI", Optima, Arial, sans-serif;
}
.crisp {
font-family: 'Oxygen', Candara, Calibri, Segoe, "Segoe UI", Optima, Arial, sans-serif;
}
pre {
background-color: black;
border: 1px dashed white;
color: white;
line-height: 1.5em;
padding: 1em;
overflow: hidden;
}
button {
border: none;
color: white;
background: skyblue;
padding: 1em;
cursor: pointer;
}
input {
background: transparent;
border: 2px dashed grey;
padding: 1em;
}
.step {
display: none;
}
.step:target {
display: block;
}
.grid {
text-align: center;
}
.unit {
display: inline-block;
}
.learn {
min-width: 250px;
max-width: 400px;
width: 30%;
padding: 2em;
}
</style>
<div class="center">
<h1 class="lean">Easiest . Database . Ever</h1>
<h2 class="lean">Scale without pain, because it is decentralized.</h2>
</div>
<div id="steps">
<div id="step1">
As easy as 1, 2, 3!
<ol>
<li>Connect to a gun server.</li>
<li>Save some data.</li>
<li>Create a key to open it up later.</li>
</ol>
<pre>var gun = Gun('http://localhost:8888/gun');
gun.set({hello: 'world'}).key('<span class="random">my/first/data</span>');</pre>
<a href="#step2" class="run"><button>
Try it Now!
</button></a>
<small>Disclaimer: This is a demo only! Data is deleted every 24 hours.</small>
<!--
<div>
Already have a key? Then
<input placeholder="copy and paste it into here!">
</div>
-->
</div>
<div id="step2" class="step">
Let's test to see if the data got saved.
<ol>
<li><a id="parallel" href="?key=" target="_blank">Open this page</a> in another browser tab.</li>
<li>Now you'll see <b class="random" style="color: crimson;">my/first/data</b> load over there.
<li>Meanwhile, this textarea will wait for realtime updates from the other tab:</li>
</ol>
<textarea style="width: 100%; height: 100px;">// Your data will log here!</textarea>
The next level will be unlocked when you complete the realtime sync between tabs.
</div>
<div id="step3" class="step">
<pre>var gun = Gun('http://localhost:8888/gun');
gun.load('<span class="random">my/first/data</span>', function(data){
$('textarea').text(demo.print(data));
});</pre>
<a href="#step4" class="run"><button>
Run the Code!
</button></a> Does the key match from the previous tab?
<textarea style="width: 100%; height: 100px;">// Your data will log here!</textarea>
</div>
<div id="step4" class="step">
Now let's listen to realtime updates, and change the value on the 'hello' field.
<pre>gun.load('<span class="random">my/first/data</span>')
.on(function(updates){
$('textarea').text(demo.print(updates));
}).path('hello').set('You!');</pre>
<a class="run"><button>
Let's do This!
</button></a>
<textarea style="width: 100%; height: 100px;">// Your data will log here!</textarea>
</div>
</div>
<div class="grid">
<div class="learn unit center">
<h1 class="lean">Did you know?</h1>
<h2 class="lean">GUN is lightning fast, cause it runs in memory.</h2>
Click to <a href="#step2" class="run"><button>
See How
</button></a> persistence works.
</div>
<div class="learn unit center">
<h1 class="lean">Guess what!</h1>
<h2 class="lean">GUN is the only database with realtime push notifications.</h2>
Learn <a href="#step2" class="run"><button>
How it Works
</button></a>.
</div>
<div class="learn unit center">
<h1 class="lean">Have Big Data?</h1>
<h2 class="lean">GUN tranforms it into <i>meaningful data</i>, with regular JS.</h2>
Discover <a href="#step2" class="run"><button>
How To
</button></a> do a graph search.
</div>
</div>
<script>
$(function(){
var demo = {}, gun;
window.demo = demo;
demo.key = location.search.split('=')[1];
demo.random = demo.key || random_phrase.noun() +'/'+ random_phrase.verb() +'/'+ random_phrase.adjective() +'/'+ random_phrase.noun() +'/'+ random_phrase.adverb();
$(".random").text(demo.random);
$('pre').each(function(){
$(this).html(hljs.highlight('javascript', $(this).text()).value);
});
$('#step1').addClass((demo.key || location.hash)? 'step' : '').find('a').first().click(function(){
$('#step1').addClass('step');
});
$('#parallel').attr('href', '?key=' + demo.random + '#step3');
$(".run").click(function(){
var code = $(this).closest('.step').attr('id');
if(!code || !demo[code]){ return } // something went wrong!
demo[code]();
});
demo.step0 = function(){
gun = window.gun = window.gun || Gun('http://localhost:8888/gun');
}
demo.step1 = function(){
demo.step0();
gun.set({hello: 'world'}).key(demo.random);
// and also do this, so we can unlock!
gun.load(demo.random)
.on(function(updates){
$('textarea').text(demo.print(updates));
// unlock level 5!
});
}
demo.step2 = function(){} // no step 2
demo.step3 = function(){
demo.step0();
gun.load(demo.random, function(data){
$('textarea').text(demo.print(data));
});
}
demo.step4 = function(){
demo.step0();
gun.load(demo.random)
.on(function(updates){
$('textarea').text(demo.print(updates));
}).path('hello').set('You!');
}
demo.print = function(data){
if(!data){ return }
delete data._; // this is gun specific metadata that we don't want to print.
return JSON.stringify(data, null, 2);
}
});
</script>
<a href="https://github.com/amark/gun"><img style="position: absolute; top: 0; right: 0; border: 0;" src="https://camo.githubusercontent.com/38ef81f8aca64bb9a64448d0d70f1308ef5341ab/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f72696768745f6461726b626c75655f3132313632312e706e67" alt="Fork me on GitHub" data-canonical-src="https://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png"></a>
</body>
</html>