commit f4285a7328304f0e7bdcab56a36264e8b41cb9cc Author: theory Date: Mon Mar 17 03:04:59 2014 -0600 hmm diff --git a/Procfile b/Procfile new file mode 100644 index 00000000..0a818360 --- /dev/null +++ b/Procfile @@ -0,0 +1 @@ +web: node init.js \ No newline at end of file diff --git a/deps/theory.js b/deps/theory.js new file mode 100644 index 00000000..52001b2d --- /dev/null +++ b/deps/theory.js @@ -0,0 +1,928 @@ +/** 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){ + m = a.obj.ify(m.data||m); + if(theory.com.asked[m.when]){ + a(theory.com.asked,m.when+"->")(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= 'x'; + 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;i1?this._listeners[a]=d.slice(0,e).concat(d.slice(e+1)):delete this._listeners[a];return}return},d.prototype.dispatchEvent=function(a){var b=a.type,c=Array.prototype.slice.call(arguments,0);this["on"+b]&&this["on"+b].apply(this,c);if(this._listeners&&b in this._listeners)for(var d=0;d=3e3&&a<=4999},c.countRTO=function(a){var b;return a>100?b=3*a:b=a+200,b},c.log=function(){b.console&&console.log&&console.log.apply&&console.log.apply(console,arguments)},c.bind=function(a,b){return a.bind?a.bind(b):function(){return a.apply(b,arguments)}},c.flatUrl=function(a){return a.indexOf("?")===-1&&a.indexOf("#")===-1},c.amendUrl=function(b){var d=a.location;if(!b)throw new Error("Wrong url for SockJS");if(!c.flatUrl(b))throw new Error("Only basic urls are supported in SockJS");return b.indexOf("//")===0&&(b=d.protocol+b),b.indexOf("/")===0&&(b=d.protocol+"//"+d.host+b),b=b.replace(/[/]+$/,""),b},c.arrIndexOf=function(a,b){for(var c=0;c=0},c.delay=function(a,b){return typeof a=="function"&&(b=a,a=0),setTimeout(b,a)};var i=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,j={"\0":"\\u0000","\x01":"\\u0001","\x02":"\\u0002","\x03":"\\u0003","\x04":"\\u0004","\x05":"\\u0005","\x06":"\\u0006","\x07":"\\u0007","\b":"\\b","\t":"\\t","\n":"\\n","\x0b":"\\u000b","\f":"\\f","\r":"\\r","\x0e":"\\u000e","\x0f":"\\u000f","\x10":"\\u0010","\x11":"\\u0011","\x12":"\\u0012","\x13":"\\u0013","\x14":"\\u0014","\x15":"\\u0015","\x16":"\\u0016","\x17":"\\u0017","\x18":"\\u0018","\x19":"\\u0019","\x1a":"\\u001a","\x1b":"\\u001b","\x1c":"\\u001c","\x1d":"\\u001d","\x1e":"\\u001e","\x1f":"\\u001f",'"':'\\"',"\\":"\\\\","\x7f":"\\u007f","\x80":"\\u0080","\x81":"\\u0081","\x82":"\\u0082","\x83":"\\u0083","\x84":"\\u0084","\x85":"\\u0085","\x86":"\\u0086","\x87":"\\u0087","\x88":"\\u0088","\x89":"\\u0089","\x8a":"\\u008a","\x8b":"\\u008b","\x8c":"\\u008c","\x8d":"\\u008d","\x8e":"\\u008e","\x8f":"\\u008f","\x90":"\\u0090","\x91":"\\u0091","\x92":"\\u0092","\x93":"\\u0093","\x94":"\\u0094","\x95":"\\u0095","\x96":"\\u0096","\x97":"\\u0097","\x98":"\\u0098","\x99":"\\u0099","\x9a":"\\u009a","\x9b":"\\u009b","\x9c":"\\u009c","\x9d":"\\u009d","\x9e":"\\u009e","\x9f":"\\u009f","\xad":"\\u00ad","\u0600":"\\u0600","\u0601":"\\u0601","\u0602":"\\u0602","\u0603":"\\u0603","\u0604":"\\u0604","\u070f":"\\u070f","\u17b4":"\\u17b4","\u17b5":"\\u17b5","\u200c":"\\u200c","\u200d":"\\u200d","\u200e":"\\u200e","\u200f":"\\u200f","\u2028":"\\u2028","\u2029":"\\u2029","\u202a":"\\u202a","\u202b":"\\u202b","\u202c":"\\u202c","\u202d":"\\u202d","\u202e":"\\u202e","\u202f":"\\u202f","\u2060":"\\u2060","\u2061":"\\u2061","\u2062":"\\u2062","\u2063":"\\u2063","\u2064":"\\u2064","\u2065":"\\u2065","\u2066":"\\u2066","\u2067":"\\u2067","\u2068":"\\u2068","\u2069":"\\u2069","\u206a":"\\u206a","\u206b":"\\u206b","\u206c":"\\u206c","\u206d":"\\u206d","\u206e":"\\u206e","\u206f":"\\u206f","\ufeff":"\\ufeff","\ufff0":"\\ufff0","\ufff1":"\\ufff1","\ufff2":"\\ufff2","\ufff3":"\\ufff3","\ufff4":"\\ufff4","\ufff5":"\\ufff5","\ufff6":"\\ufff6","\ufff7":"\\ufff7","\ufff8":"\\ufff8","\ufff9":"\\ufff9","\ufffa":"\\ufffa","\ufffb":"\\ufffb","\ufffc":"\\ufffc","\ufffd":"\\ufffd","\ufffe":"\\ufffe","\uffff":"\\uffff"},k=/[\x00-\x1f\ud800-\udfff\ufffe\uffff\u0300-\u0333\u033d-\u0346\u034a-\u034c\u0350-\u0352\u0357-\u0358\u035c-\u0362\u0374\u037e\u0387\u0591-\u05af\u05c4\u0610-\u0617\u0653-\u0654\u0657-\u065b\u065d-\u065e\u06df-\u06e2\u06eb-\u06ec\u0730\u0732-\u0733\u0735-\u0736\u073a\u073d\u073f-\u0741\u0743\u0745\u0747\u07eb-\u07f1\u0951\u0958-\u095f\u09dc-\u09dd\u09df\u0a33\u0a36\u0a59-\u0a5b\u0a5e\u0b5c-\u0b5d\u0e38-\u0e39\u0f43\u0f4d\u0f52\u0f57\u0f5c\u0f69\u0f72-\u0f76\u0f78\u0f80-\u0f83\u0f93\u0f9d\u0fa2\u0fa7\u0fac\u0fb9\u1939-\u193a\u1a17\u1b6b\u1cda-\u1cdb\u1dc0-\u1dcf\u1dfc\u1dfe\u1f71\u1f73\u1f75\u1f77\u1f79\u1f7b\u1f7d\u1fbb\u1fbe\u1fc9\u1fcb\u1fd3\u1fdb\u1fe3\u1feb\u1fee-\u1fef\u1ff9\u1ffb\u1ffd\u2000-\u2001\u20d0-\u20d1\u20d4-\u20d7\u20e7-\u20e9\u2126\u212a-\u212b\u2329-\u232a\u2adc\u302b-\u302c\uaab2-\uaab3\uf900-\ufa0d\ufa10\ufa12\ufa15-\ufa1e\ufa20\ufa22\ufa25-\ufa26\ufa2a-\ufa2d\ufa30-\ufa6d\ufa70-\ufad9\ufb1d\ufb1f\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40-\ufb41\ufb43-\ufb44\ufb46-\ufb4e\ufff0-\uffff]/g,l,m=JSON&&JSON.stringify||function(a){return i.lastIndex=0,i.test(a)&&(a=a.replace(i,function(a){return j[a]})),'"'+a+'"'},n=function(a){var b,c={},d=[];for(b=0;b<65536;b++)d.push(String.fromCharCode(b));return a.lastIndex=0,d.join("").replace(a,function(a){return c[a]="\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4),""}),a.lastIndex=0,c};c.quote=function(a){var b=m(a);return k.lastIndex=0,k.test(b)?(l||(l=n(k)),b.replace(k,function(a){return l[a]})):b};var o=["websocket","xdr-streaming","xhr-streaming","iframe-eventsource","iframe-htmlfile","xdr-polling","xhr-polling","iframe-xhr-polling","jsonp-polling"];c.probeProtocols=function(){var a={};for(var b=0;b0&&h(a)};return c.websocket!==!1&&h(["websocket"]),d["xhr-streaming"]&&!c.null_origin?e.push("xhr-streaming"):d["xdr-streaming"]&&!c.cookie_needed&&!c.null_origin?e.push("xdr-streaming"):h(["iframe-eventsource","iframe-htmlfile"]),d["xhr-polling"]&&!c.null_origin?e.push("xhr-polling"):d["xdr-polling"]&&!c.cookie_needed&&!c.null_origin?e.push("xdr-polling"):h(["iframe-xhr-polling","jsonp-polling"]),e};var p="_sockjs_global";c.createHook=function(){var a="a"+c.random_string(8);if(!(p in b)){var d={};b[p]=function(a){return a in d||(d[a]={id:a,del:function(){delete d[a]}}),d[a]}}return b[p](a)},c.attachMessage=function(a){c.attachEvent("message",a)},c.attachEvent=function(c,d){typeof b.addEventListener!="undefined"?b.addEventListener(c,d,!1):(a.attachEvent("on"+c,d),b.attachEvent("on"+c,d))},c.detachMessage=function(a){c.detachEvent("message",a)},c.detachEvent=function(c,d){typeof b.addEventListener!="undefined"?b.removeEventListener(c,d,!1):(a.detachEvent("on"+c,d),b.detachEvent("on"+c,d))};var q={},r=!1,s=function(){for(var a in q)q[a](),delete q[a]},t=function(){if(r)return;r=!0,s()};c.attachEvent("unload",t),c.unload_add=function(a){var b=c.random_string(8);return q[b]=a,r&&c.delay(s),b},c.unload_del=function(a){a in q&&delete q[a]},c.createIframe=function(b,d){var e=a.createElement("iframe"),f,g,h=function(){clearTimeout(f);try{e.onload=null}catch(a){}e.onerror=null},i=function(){e&&(h(),setTimeout(function(){e&&e.parentNode.removeChild(e),e=null},0),c.unload_del(g))},j=function(a){e&&(i(),d(a))},k=function(a,b){try{e&&e.contentWindow&&e.contentWindow.postMessage(a,b)}catch(c){}};return e.src=b,e.style.display="none",e.style.position="absolute",e.onerror=function(){j("onerror")},e.onload=function(){clearTimeout(f),f=setTimeout(function(){j("onload timeout")},2e3)},a.body.appendChild(e),f=setTimeout(function(){j("timeout")},15e3),g=c.unload_add(i),{post:k,cleanup:i,loaded:h}},c.createHtmlfile=function(a,d){var e=new ActiveXObject("htmlfile"),f,g,i,j=function(){clearTimeout(f)},k=function(){e&&(j(),c.unload_del(g),i.parentNode.removeChild(i),i=e=null,CollectGarbage())},l=function(a){e&&(k(),d(a))},m=function(a,b){try{i&&i.contentWindow&&i.contentWindow.postMessage(a,b)}catch(c){}};e.open(),e.write(' + + + + + + + + + + + + + + Gun Tests +
+
+ + \ No newline at end of file diff --git a/test/mocha.js b/test/mocha.js new file mode 100644 index 00000000..7abc6488 --- /dev/null +++ b/test/mocha.js @@ -0,0 +1,4228 @@ +;(function(){ +if ('undefined' == typeof window) { + return; +} + +// CommonJS require() + +function require(p){ + var path = require.resolve(p) + , mod = require.modules[path]; + if (!mod) throw new Error('failed to require "' + p + '"'); + if (!mod.exports) { + mod.exports = {}; + mod.call(mod.exports, mod, mod.exports, require.relative(path)); + } + return mod.exports; + } + +require.modules = {}; + +require.resolve = function (path){ + var orig = path + , reg = path + '.js' + , index = path + '/index.js'; + return require.modules[reg] && reg + || require.modules[index] && index + || orig; + }; + +require.register = function (path, fn){ + require.modules[path] = fn; + }; + +require.relative = function (parent) { + return function(p){ + if ('.' != p.charAt(0)) return require(p); + + var path = parent.split('/') + , segs = p.split('/'); + 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 require(path.join('/')); + }; + }; + + +require.register("browser/debug.js", function(module, exports, require){ + +module.exports = function(type){ + return function(){ + + } +}; +}); // module: browser/debug.js + +require.register("browser/diff.js", function(module, exports, require){ + +}); // module: browser/diff.js + +require.register("browser/events.js", function(module, exports, require){ + +/** + * Module exports. + */ + +exports.EventEmitter = EventEmitter; + +/** + * Check if `obj` is an array. + */ + +function isArray(obj) { + return '[object Array]' == {}.toString.call(obj); +} + +/** + * Event emitter constructor. + * + * @api public + */ + +function EventEmitter(){}; + +/** + * Adds a listener. + * + * @api public + */ + +EventEmitter.prototype.on = function (name, fn) { + if (!this.$events) { + this.$events = {}; + } + + if (!this.$events[name]) { + this.$events[name] = fn; + } else if (isArray(this.$events[name])) { + this.$events[name].push(fn); + } else { + this.$events[name] = [this.$events[name], fn]; + } + + return this; +}; + +EventEmitter.prototype.addListener = EventEmitter.prototype.on; + +/** + * Adds a volatile listener. + * + * @api public + */ + +EventEmitter.prototype.once = function (name, fn) { + var self = this; + + function on () { + self.removeListener(name, on); + fn.apply(this, arguments); + }; + + on.listener = fn; + this.on(name, on); + + return this; +}; + +/** + * Removes a listener. + * + * @api public + */ + +EventEmitter.prototype.removeListener = function (name, fn) { + if (this.$events && this.$events[name]) { + var list = this.$events[name]; + + if (isArray(list)) { + var pos = -1; + + for (var i = 0, l = list.length; i < l; i++) { + if (list[i] === fn || (list[i].listener && list[i].listener === fn)) { + pos = i; + break; + } + } + + if (pos < 0) { + return this; + } + + list.splice(pos, 1); + + if (!list.length) { + delete this.$events[name]; + } + } else if (list === fn || (list.listener && list.listener === fn)) { + delete this.$events[name]; + } + } + + return this; +}; + +/** + * Removes all listeners for an event. + * + * @api public + */ + +EventEmitter.prototype.removeAllListeners = function (name) { + if (name === undefined) { + this.$events = {}; + return this; + } + + if (this.$events && this.$events[name]) { + this.$events[name] = null; + } + + return this; +}; + +/** + * Gets all listeners for a certain event. + * + * @api public + */ + +EventEmitter.prototype.listeners = function (name) { + if (!this.$events) { + this.$events = {}; + } + + if (!this.$events[name]) { + this.$events[name] = []; + } + + if (!isArray(this.$events[name])) { + this.$events[name] = [this.$events[name]]; + } + + return this.$events[name]; +}; + +/** + * Emits an event. + * + * @api public + */ + +EventEmitter.prototype.emit = function (name) { + if (!this.$events) { + return false; + } + + var handler = this.$events[name]; + + if (!handler) { + return false; + } + + var args = [].slice.call(arguments, 1); + + if ('function' == typeof handler) { + handler.apply(this, args); + } else if (isArray(handler)) { + var listeners = handler.slice(); + + for (var i = 0, l = listeners.length; i < l; i++) { + listeners[i].apply(this, args); + } + } else { + return false; + } + + return true; +}; +}); // module: browser/events.js + +require.register("browser/fs.js", function(module, exports, require){ + +}); // module: browser/fs.js + +require.register("browser/path.js", function(module, exports, require){ + +}); // module: browser/path.js + +require.register("browser/progress.js", function(module, exports, require){ + +/** + * Expose `Progress`. + */ + +module.exports = Progress; + +/** + * Initialize a new `Progress` indicator. + */ + +function Progress() { + this.percent = 0; + this.size(0); + this.fontSize(11); + this.font('helvetica, arial, sans-serif'); +} + +/** + * Set progress size to `n`. + * + * @param {Number} n + * @return {Progress} for chaining + * @api public + */ + +Progress.prototype.size = function(n){ + this._size = n; + return this; +}; + +/** + * Set text to `str`. + * + * @param {String} str + * @return {Progress} for chaining + * @api public + */ + +Progress.prototype.text = function(str){ + this._text = str; + return this; +}; + +/** + * Set font size to `n`. + * + * @param {Number} n + * @return {Progress} for chaining + * @api public + */ + +Progress.prototype.fontSize = function(n){ + this._fontSize = n; + return this; +}; + +/** + * Set font `family`. + * + * @param {String} family + * @return {Progress} for chaining + */ + +Progress.prototype.font = function(family){ + this._font = family; + return this; +}; + +/** + * Update percentage to `n`. + * + * @param {Number} n + * @return {Progress} for chaining + */ + +Progress.prototype.update = function(n){ + this.percent = n; + return this; +}; + +/** + * Draw on `ctx`. + * + * @param {CanvasRenderingContext2d} ctx + * @return {Progress} for chaining + */ + +Progress.prototype.draw = function(ctx){ + var percent = Math.min(this.percent, 100) + , size = this._size + , half = size / 2 + , x = half + , y = half + , rad = half - 1 + , fontSize = this._fontSize; + + ctx.font = fontSize + 'px ' + this._font; + + var angle = Math.PI * 2 * (percent / 100); + ctx.clearRect(0, 0, size, size); + + // outer circle + ctx.strokeStyle = '#9f9f9f'; + ctx.beginPath(); + ctx.arc(x, y, rad, 0, angle, false); + ctx.stroke(); + + // inner circle + ctx.strokeStyle = '#eee'; + ctx.beginPath(); + ctx.arc(x, y, rad - 1, 0, angle, true); + ctx.stroke(); + + // text + var text = this._text || (percent | 0) + '%' + , w = ctx.measureText(text).width; + + ctx.fillText( + text + , x - w / 2 + 1 + , y + fontSize / 2 - 1); + + return this; +}; + +}); // module: browser/progress.js + +require.register("browser/tty.js", function(module, exports, require){ + +exports.isatty = function(){ + return true; +}; + +exports.getWindowSize = function(){ + return [window.innerHeight, window.innerWidth]; +}; +}); // module: browser/tty.js + +require.register("context.js", function(module, exports, require){ + +/** + * Expose `Context`. + */ + +module.exports = Context; + +/** + * Initialize a new `Context`. + * + * @api private + */ + +function Context(){} + +/** + * Set the context `Runnable` to `runnable`. + * + * @param {Runnable} runnable + * @return {Context} + * @api private + */ + +Context.prototype.runnable = function(runnable){ + this._runnable = runnable; + return this; +}; + +/** + * Set test timeout `ms`. + * + * @param {Number} ms + * @return {Context} self + * @api private + */ + +Context.prototype.timeout = function(ms){ + this._runnable.timeout(ms); + return this; +}; + +/** + * Inspect the context void of `._runnable`. + * + * @return {String} + * @api private + */ + +Context.prototype.inspect = function(){ + return JSON.stringify(this, function(key, val){ + return '_runnable' == key + ? undefined + : val; + }, 2); +}; + +}); // module: context.js + +require.register("hook.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Runnable = require('./runnable'); + +/** + * Expose `Hook`. + */ + +module.exports = Hook; + +/** + * Initialize a new `Hook` with the given `title` and callback `fn`. + * + * @param {String} title + * @param {Function} fn + * @api private + */ + +function Hook(title, fn) { + Runnable.call(this, title, fn); + this.type = 'hook'; +} + +/** + * Inherit from `Runnable.prototype`. + */ + +Hook.prototype = new Runnable; +Hook.prototype.constructor = Hook; + + +}); // module: hook.js + +require.register("interfaces/bdd.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Suite = require('../suite') + , Test = require('../test'); + +/** + * BDD-style interface: + * + * describe('Array', function(){ + * describe('#indexOf()', function(){ + * it('should return -1 when not present', function(){ + * + * }); + * + * it('should return the index when present', function(){ + * + * }); + * }); + * }); + * + */ + +module.exports = function(suite){ + var suites = [suite]; + + suite.on('pre-require', function(context){ + + // noop variants + + context.xdescribe = function(){}; + context.xit = function(){}; + + /** + * Execute before running tests. + */ + + context.before = function(fn){ + suites[0].beforeAll(fn); + }; + + /** + * Execute after running tests. + */ + + context.after = function(fn){ + suites[0].afterAll(fn); + }; + + /** + * Execute before each test case. + */ + + context.beforeEach = function(fn){ + suites[0].beforeEach(fn); + }; + + /** + * Execute after each test case. + */ + + context.afterEach = function(fn){ + suites[0].afterEach(fn); + }; + + /** + * Describe a "suite" with the given `title` + * and callback `fn` containing nested suites + * and/or tests. + */ + + context.describe = context.context = function(title, fn){ + var suite = Suite.create(suites[0], title); + suites.unshift(suite); + fn(); + suites.shift(); + }; + + /** + * Describe a specification or test-case + * with the given `title` and callback `fn` + * acting as a thunk. + */ + + context.it = function(title, fn){ + suites[0].addTest(new Test(title, fn)); + }; + }); +}; + +}); // module: interfaces/bdd.js + +require.register("interfaces/exports.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Suite = require('../suite') + , Test = require('../test'); + +/** + * TDD-style interface: + * + * exports.Array = { + * '#indexOf()': { + * 'should return -1 when the value is not present': function(){ + * + * }, + * + * 'should return the correct index when the value is present': function(){ + * + * } + * } + * }; + * + */ + +module.exports = function(suite){ + var suites = [suite]; + + suite.on('require', visit); + + function visit(obj) { + var suite; + for (var key in obj) { + if ('function' == typeof obj[key]) { + var fn = obj[key]; + switch (key) { + case 'before': + suites[0].beforeAll(fn); + break; + case 'after': + suites[0].afterAll(fn); + break; + case 'beforeEach': + suites[0].beforeEach(fn); + break; + case 'afterEach': + suites[0].afterEach(fn); + break; + default: + suites[0].addTest(new Test(key, fn)); + } + } else { + var suite = Suite.create(suites[0], key); + suites.unshift(suite); + visit(obj[key]); + suites.shift(); + } + } + } +}; +}); // module: interfaces/exports.js + +require.register("interfaces/index.js", function(module, exports, require){ + +exports.bdd = require('./bdd'); +exports.tdd = require('./tdd'); +exports.qunit = require('./qunit'); +exports.exports = require('./exports'); + +}); // module: interfaces/index.js + +require.register("interfaces/qunit.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Suite = require('../suite') + , Test = require('../test'); + +/** + * QUnit-style interface: + * + * suite('Array'); + * + * test('#length', function(){ + * var arr = [1,2,3]; + * ok(arr.length == 3); + * }); + * + * test('#indexOf()', function(){ + * var arr = [1,2,3]; + * ok(arr.indexOf(1) == 0); + * ok(arr.indexOf(2) == 1); + * ok(arr.indexOf(3) == 2); + * }); + * + * suite('String'); + * + * test('#length', function(){ + * ok('foo'.length == 3); + * }); + * + */ + +module.exports = function(suite){ + var suites = [suite]; + + suite.on('pre-require', function(context){ + + /** + * Execute before running tests. + */ + + context.before = function(fn){ + suites[0].beforeAll(fn); + }; + + /** + * Execute after running tests. + */ + + context.after = function(fn){ + suites[0].afterAll(fn); + }; + + /** + * Execute before each test case. + */ + + context.beforeEach = function(fn){ + suites[0].beforeEach(fn); + }; + + /** + * Execute after each test case. + */ + + context.afterEach = function(fn){ + suites[0].afterEach(fn); + }; + + /** + * Describe a "suite" with the given `title`. + */ + + context.suite = function(title){ + if (suites.length > 1) suites.shift(); + var suite = Suite.create(suites[0], title); + suites.unshift(suite); + }; + + /** + * Describe a specification or test-case + * with the given `title` and callback `fn` + * acting as a thunk. + */ + + context.test = function(title, fn){ + suites[0].addTest(new Test(title, fn)); + }; + }); +}; + +}); // module: interfaces/qunit.js + +require.register("interfaces/tdd.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Suite = require('../suite') + , Test = require('../test'); + +/** + * TDD-style interface: + * + * suite('Array', function(){ + * suite('#indexOf()', function(){ + * suiteSetup(function(){ + * + * }); + * + * test('should return -1 when not present', function(){ + * + * }); + * + * test('should return the index when present', function(){ + * + * }); + * + * suiteTeardown(function(){ + * + * }); + * }); + * }); + * + */ + +module.exports = function(suite){ + var suites = [suite]; + + suite.on('pre-require', function(context){ + + /** + * Execute before each test case. + */ + + context.setup = function(fn){ + suites[0].beforeEach(fn); + }; + + /** + * Execute after each test case. + */ + + context.teardown = function(fn){ + suites[0].afterEach(fn); + }; + + /** + * Execute before the suite. + */ + + context.suiteSetup = function(fn){ + suites[0].beforeAll(fn); + }; + + /** + * Execute after the suite. + */ + + context.suiteTeardown = function(fn){ + suites[0].afterAll(fn); + }; + + /** + * Describe a "suite" with the given `title` + * and callback `fn` containing nested suites + * and/or tests. + */ + + context.suite = function(title, fn){ + var suite = Suite.create(suites[0], title); + suites.unshift(suite); + fn(); + suites.shift(); + }; + + /** + * Describe a specification or test-case + * with the given `title` and callback `fn` + * acting as a thunk. + */ + + context.test = function(title, fn){ + suites[0].addTest(new Test(title, fn)); + }; + }); +}; + +}); // module: interfaces/tdd.js + +require.register("mocha.js", function(module, exports, require){ + +/*! + * mocha + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var path = require('browser/path'); + +/** + * Expose `Mocha`. + */ + +exports = module.exports = Mocha; + +/** + * Library version. + */ + +exports.version = '1.1.0'; + +/** + * Expose internals. + */ + +exports.utils = require('./utils'); +exports.interfaces = require('./interfaces'); +exports.reporters = require('./reporters'); +exports.Runnable = require('./runnable'); +exports.Context = require('./context'); +exports.Runner = require('./runner'); +exports.Suite = require('./suite'); +exports.Hook = require('./hook'); +exports.Test = require('./test'); + +/** + * Return image `name` path. + * + * @param {String} name + * @return {String} + * @api private + */ + +function image(name) { + return __dirname + '/../images/' + name + '.png'; +} + +/** + * Setup mocha with `options`. + * + * Options: + * + * - `ui` name "bdd", "tdd", "exports" etc + * - `reporter` reporter instance, defaults to `mocha.reporters.Dot` + * - `globals` array of accepted globals + * - `timeout` timeout in milliseconds + * - `ignoreLeaks` ignore global leaks + * - `grep` string or regexp to filter tests with + * + * @param {Object} options + * @api public + */ + +function Mocha(options) { + options = options || {}; + this.files = []; + this.options = options; + this.grep(options.grep); + this.suite = new exports.Suite('', new exports.Context); + this.ui(options.ui); + this.reporter(options.reporter); + if (options.timeout) this.suite.timeout(options.timeout); +} + +/** + * Add test `file`. + * + * @param {String} file + * @api public + */ + +Mocha.prototype.addFile = function(file){ + this.files.push(file); + return this; +}; + +/** + * Set reporter to `name`, defaults to "dot". + * + * @param {String} name + * @api public + */ + +Mocha.prototype.reporter = function(name){ + name = name || 'dot'; + this._reporter = require('./reporters/' + name); + if (!this._reporter) throw new Error('invalid reporter "' + name + '"'); + return this; +}; + +/** + * Set test UI `name`, defaults to "bdd". + * + * @param {String} bdd + * @api public + */ + +Mocha.prototype.ui = function(name){ + name = name || 'bdd'; + this._ui = exports.interfaces[name]; + if (!this._ui) throw new Error('invalid interface "' + name + '"'); + this._ui = this._ui(this.suite); + return this; +}; + +/** + * Load registered files. + * + * @api private + */ + +Mocha.prototype.loadFiles = function(){ + var suite = this.suite; + this.files.forEach(function(file){ + file = path.resolve(file); + suite.emit('pre-require', global, file); + suite.emit('require', require(file), file); + suite.emit('post-require', global, file); + }); +}; + +/** + * Enable growl support. + * + * @api private + */ + +Mocha.prototype.growl = function(runner, reporter) { + var notify = require('growl'); + + runner.on('end', function(){ + var stats = reporter.stats; + if (stats.failures) { + var msg = stats.failures + ' of ' + runner.total + ' tests failed'; + notify(msg, { title: 'Failed', image: image('fail') }); + } else { + notify(stats.passes + ' tests passed in ' + stats.duration + 'ms', { + title: 'Passed' + , image: image('pass') + }); + } + }); +}; + +/** + * Add regexp to grep for to the options object + * + * @param {RegExp} or {String} re + * @return {Mocha} + * @api public + */ + +Mocha.prototype.grep = function(re){ + this.options.grep = 'string' == typeof re + ? new RegExp(re) + : re; + return this; +}; + +/** + * Run tests and invoke `fn()` when complete. + * + * @param {Function} fn + * @return {Runner} + * @api public + */ + +Mocha.prototype.run = function(fn){ + this.loadFiles(); + var suite = this.suite; + var options = this.options; + var runner = new exports.Runner(suite); + var reporter = new this._reporter(runner); + runner.ignoreLeaks = options.ignoreLeaks; + if (options.grep) runner.grep(options.grep); + if (options.globals) runner.globals(options.globals); + if (options.growl) this.growl(runner, reporter); + return runner.run(fn); +}; +}); // module: mocha.js + +require.register("reporters/base.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var tty = require('browser/tty') + , diff = require('browser/diff'); + +/** + * Save timer references to avoid Sinon interfering (see GH-237). + */ + +var Date = global.Date + , setTimeout = global.setTimeout + , setInterval = global.setInterval + , clearTimeout = global.clearTimeout + , clearInterval = global.clearInterval; + +/** + * Check if both stdio streams are associated with a tty. + */ + +var isatty = tty.isatty(1) && tty.isatty(2); + +/** + * Expose `Base`. + */ + +exports = module.exports = Base; + +/** + * Enable coloring by default. + */ + +exports.useColors = isatty; + +/** + * Default color map. + */ + +exports.colors = { + 'pass': 90 + , 'fail': 31 + , 'bright pass': 92 + , 'bright fail': 91 + , 'bright yellow': 93 + , 'pending': 36 + , 'suite': 0 + , 'error title': 0 + , 'error message': 31 + , 'error stack': 90 + , 'checkmark': 32 + , 'fast': 90 + , 'medium': 33 + , 'slow': 31 + , 'green': 32 + , 'light': 90 + , 'diff gutter': 90 + , 'diff added': 42 + , 'diff removed': 41 +}; + +/** + * Color `str` with the given `type`, + * allowing colors to be disabled, + * as well as user-defined color + * schemes. + * + * @param {String} type + * @param {String} str + * @return {String} + * @api private + */ + +var color = exports.color = function(type, str) { + if (!exports.useColors) return str; + return '\033[' + exports.colors[type] + 'm' + str + '\033[0m'; +}; + +/** + * Expose term window size, with some + * defaults for when stderr is not a tty. + */ + +exports.window = { + width: isatty + ? process.stdout.getWindowSize + ? process.stdout.getWindowSize(1)[0] + : tty.getWindowSize()[1] + : 75 +}; + +/** + * Expose some basic cursor interactions + * that are common among reporters. + */ + +exports.cursor = { + hide: function(){ + process.stdout.write('\033[?25l'); + }, + + show: function(){ + process.stdout.write('\033[?25h'); + }, + + deleteLine: function(){ + process.stdout.write('\033[2K'); + }, + + beginningOfLine: function(){ + process.stdout.write('\033[0G'); + }, + + CR: function(){ + exports.cursor.deleteLine(); + exports.cursor.beginningOfLine(); + } +}; + +/** + * A test is considered slow if it + * exceeds the following value in milliseconds. + */ + +exports.slow = 75; + +/** + * Outut the given `failures` as a list. + * + * @param {Array} failures + * @api public + */ + +exports.list = function(failures){ + console.error(); + failures.forEach(function(test, i){ + // format + var fmt = color('error title', ' %s) %s:\n') + + color('error message', ' %s') + + color('error stack', '\n%s\n'); + + // msg + var err = test.err + , message = err.message || '' + , stack = err.stack || message + , index = stack.indexOf(message) + message.length + , msg = stack.slice(0, index) + , actual = err.actual + , expected = err.expected; + + // actual / expected diff + if ('string' == typeof actual && 'string' == typeof expected) { + var len = Math.max(actual.length, expected.length); + + if (len < 20) msg = errorDiff(err, 'Chars'); + else msg = errorDiff(err, 'Words'); + + // linenos + var lines = msg.split('\n'); + if (lines.length > 4) { + var width = String(lines.length).length; + msg = lines.map(function(str, i){ + return pad(++i, width) + ' |' + ' ' + str; + }).join('\n'); + } + + // legend + msg = '\n' + + color('diff removed', 'actual') + + ' ' + + color('diff added', 'expected') + + '\n\n' + + msg + + '\n'; + + // indent + msg = msg.replace(/^/gm, ' '); + + fmt = color('error title', ' %s) %s:\n%s') + + color('error stack', '\n%s\n'); + } + + // indent stack trace without msg + stack = stack.slice(index ? index + 1 : index) + .replace(/^/gm, ' '); + + console.error(fmt, (i + 1), test.fullTitle(), msg, stack); + }); +}; + +/** + * Initialize a new `Base` reporter. + * + * All other reporters generally + * inherit from this reporter, providing + * stats such as test duration, number + * of tests passed / failed etc. + * + * @param {Runner} runner + * @api public + */ + +function Base(runner) { + var self = this + , stats = this.stats = { suites: 0, tests: 0, passes: 0, pending: 0, failures: 0 } + , failures = this.failures = []; + + if (!runner) return; + this.runner = runner; + + runner.on('start', function(){ + stats.start = new Date; + }); + + runner.on('suite', function(suite){ + stats.suites = stats.suites || 0; + suite.root || stats.suites++; + }); + + runner.on('test end', function(test){ + stats.tests = stats.tests || 0; + stats.tests++; + }); + + runner.on('pass', function(test){ + stats.passes = stats.passes || 0; + + var medium = exports.slow / 2; + test.speed = test.duration > exports.slow + ? 'slow' + : test.duration > medium + ? 'medium' + : 'fast'; + + stats.passes++; + }); + + runner.on('fail', function(test, err){ + stats.failures = stats.failures || 0; + stats.failures++; + test.err = err; + failures.push(test); + }); + + runner.on('end', function(){ + stats.end = new Date; + stats.duration = new Date - stats.start; + }); + + runner.on('pending', function(){ + stats.pending++; + }); +} + +/** + * Output common epilogue used by many of + * the bundled reporters. + * + * @api public + */ + +Base.prototype.epilogue = function(){ + var stats = this.stats + , fmt + , tests; + + console.log(); + + function pluralize(n) { + return 1 == n ? 'test' : 'tests'; + } + + // failure + if (stats.failures) { + fmt = color('bright fail', ' ?') + + color('fail', ' %d of %d %s failed') + + color('light', ':') + + console.error(fmt, + stats.failures, + this.runner.total, + pluralize(this.runner.total)); + + Base.list(this.failures); + console.error(); + return; + } + + // pass + fmt = color('bright pass', ' ?') + + color('green', ' %d %s complete') + + color('light', ' (%dms)'); + + console.log(fmt, + stats.tests || 0, + pluralize(stats.tests), + stats.duration); + + // pending + if (stats.pending) { + fmt = color('pending', ' •') + + color('pending', ' %d %s pending'); + + console.log(fmt, stats.pending, pluralize(stats.pending)); + } + + console.log(); +}; + +/** + * Pad the given `str` to `len`. + * + * @param {String} str + * @param {String} len + * @return {String} + * @api private + */ + +function pad(str, len) { + str = String(str); + return Array(len - str.length + 1).join(' ') + str; +} + +/** + * Return a character diff for `err`. + * + * @param {Error} err + * @return {String} + * @api private + */ + +function errorDiff(err, type) { + return diff['diff' + type](err.actual, err.expected).map(function(str){ + if (/^(\n+)$/.test(str.value)) str.value = Array(++RegExp.$1.length).join(''); + if (str.added) return colorLines('diff added', str.value); + if (str.removed) return colorLines('diff removed', str.value); + return str.value; + }).join(''); +} + +/** + * Color lines for `str`, using the color `name`. + * + * @param {String} name + * @param {String} str + * @return {String} + * @api private + */ + +function colorLines(name, str) { + return str.split('\n').map(function(str){ + return color(name, str); + }).join('\n'); +} + +}); // module: reporters/base.js + +require.register("reporters/doc.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , utils = require('../utils'); + +/** + * Expose `Doc`. + */ + +exports = module.exports = Doc; + +/** + * Initialize a new `Doc` reporter. + * + * @param {Runner} runner + * @api public + */ + +function Doc(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , total = runner.total + , indents = 2; + + function indent() { + return Array(indents).join(' '); + } + + runner.on('suite', function(suite){ + if (suite.root) return; + ++indents; + console.log('%s
', indent()); + ++indents; + console.log('%s

%s

', indent(), suite.title); + console.log('%s
', indent()); + }); + + runner.on('suite end', function(suite){ + if (suite.root) return; + console.log('%s
', indent()); + --indents; + console.log('%s
', indent()); + --indents; + }); + + runner.on('pass', function(test){ + console.log('%s
%s
', indent(), test.title); + var code = utils.escape(clean(test.fn.toString())); + console.log('%s
%s
', indent(), code); + }); +} + +/** + * Strip the function definition from `str`, + * and re-indent for pre whitespace. + */ + +function clean(str) { + str = str + .replace(/^function *\(.*\) *{/, '') + .replace(/\s+\}$/, ''); + + var spaces = str.match(/^\n?( *)/)[1].length + , re = new RegExp('^ {' + spaces + '}', 'gm'); + + str = str.replace(re, ''); + + return str; +} +}); // module: reporters/doc.js + +require.register("reporters/dot.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , color = Base.color; + +/** + * Expose `Dot`. + */ + +exports = module.exports = Dot; + +/** + * Initialize a new `Dot` matrix test reporter. + * + * @param {Runner} runner + * @api public + */ + +function Dot(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , width = Base.window.width * .75 | 0 + , n = 0; + + runner.on('start', function(){ + process.stdout.write('\n '); + }); + + runner.on('pending', function(test){ + process.stdout.write(color('pending', '.')); + }); + + runner.on('pass', function(test){ + if (++n % width == 0) process.stdout.write('\n '); + if ('slow' == test.speed) { + process.stdout.write(color('bright yellow', '.')); + } else { + process.stdout.write(color(test.speed, '.')); + } + }); + + runner.on('fail', function(test, err){ + if (++n % width == 0) process.stdout.write('\n '); + process.stdout.write(color('fail', '.')); + }); + + runner.on('end', function(){ + console.log(); + self.epilogue(); + }); +} + +/** + * Inherit from `Base.prototype`. + */ + +Dot.prototype = new Base; +Dot.prototype.constructor = Dot; + +}); // module: reporters/dot.js + +require.register("reporters/html-cov.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var JSONCov = require('./json-cov') + , fs = require('browser/fs'); + +/** + * Expose `HTMLCov`. + */ + +exports = module.exports = HTMLCov; + +/** + * Initialize a new `JsCoverage` reporter. + * + * @param {Runner} runner + * @api public + */ + +function HTMLCov(runner) { + var jade = require('jade') + , file = __dirname + '/templates/coverage.jade' + , str = fs.readFileSync(file, 'utf8') + , fn = jade.compile(str, { filename: file }) + , self = this; + + JSONCov.call(this, runner, false); + + runner.on('end', function(){ + process.stdout.write(fn({ + cov: self.cov + , coverageClass: coverageClass + })); + }); +} + +function coverageClass(n) { + if (n >= 75) return 'high'; + if (n >= 50) return 'medium'; + if (n >= 25) return 'low'; + return 'terrible'; +} +}); // module: reporters/html-cov.js + +require.register("reporters/html.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , utils = require('../utils') + , Progress = require('../browser/progress') + , escape = utils.escape; + +/** + * Save timer references to avoid Sinon interfering (see GH-237). + */ + +var Date = global.Date + , setTimeout = global.setTimeout + , setInterval = global.setInterval + , clearTimeout = global.clearTimeout + , clearInterval = global.clearInterval; + +/** + * Expose `Doc`. + */ + +exports = module.exports = HTML; + +/** + * Stats template. + */ + +var statsTemplate = '
    ' + + '
  • ' + + '
  • passes: 0
  • ' + + '
  • failures: 0
  • ' + + '
  • duration: 0s
  • ' + + '
'; + +/** + * Initialize a new `Doc` reporter. + * + * @param {Runner} runner + * @api public + */ + +function HTML(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , total = runner.total + , root = document.getElementById('mocha') + , stat = fragment(statsTemplate) + , items = stat.getElementsByTagName('li') + , passes = items[1].getElementsByTagName('em')[0] + , failures = items[2].getElementsByTagName('em')[0] + , duration = items[3].getElementsByTagName('em')[0] + , canvas = stat.getElementsByTagName('canvas')[0] + , report = fragment('
    ') + , stack = [report] + , progress + , ctx + + if (canvas.getContext) { + ctx = canvas.getContext('2d'); + progress = new Progress; + } + + if (!root) return error('#mocha div missing, add it to your document'); + + root.appendChild(stat); + root.appendChild(report); + + if (progress) progress.size(40); + + runner.on('suite', function(suite){ + if (suite.root) return; + + // suite + var url = location.protocol + '//' + location.host + location.pathname + '?grep=^' + utils.escapeRegexp(suite.fullTitle()); + var el = fragment('
  • %s

  • ', url, suite.title); + + // container + stack[0].appendChild(el); + stack.unshift(document.createElement('ul')); + el.appendChild(stack[0]); + }); + + runner.on('suite end', function(suite){ + if (suite.root) return; + stack.shift(); + }); + + runner.on('fail', function(test, err){ + if ('hook' == test.type || err.uncaught) runner.emit('test end', test); + }); + + runner.on('test end', function(test){ + // TODO: add to stats + var percent = stats.tests / total * 100 | 0; + if (progress) progress.update(percent).draw(ctx); + + // update stats + var ms = new Date - stats.start; + text(passes, stats.passes); + text(failures, stats.failures); + text(duration, (ms / 1000).toFixed(2)); + + // test + if ('passed' == test.state) { + var el = fragment('
  • %e%ems

  • ', test.speed, test.title, test.duration); + } else if (test.pending) { + var el = fragment('
  • %e

  • ', test.title); + } else { + var el = fragment('
  • %e

  • ', test.title); + var str = test.err.stack || test.err.toString(); + + // FF / Opera do not add the message + if (!~str.indexOf(test.err.message)) { + str = test.err.message + '\n' + str; + } + + // <=IE7 stringifies to [Object Error]. Since it can be overloaded, we + // check for the result of the stringifying. + if ('[object Error]' == str) str = test.err.message; + + // Safari doesn't give you a stack. Let's at least provide a source line. + if (!test.err.stack && test.err.sourceURL && test.err.line !== undefined) { + str += "\n(" + test.err.sourceURL + ":" + test.err.line + ")"; + } + + el.appendChild(fragment('
    %e
    ', str)); + } + + // toggle code + var h2 = el.getElementsByTagName('h2')[0]; + + on(h2, 'click', function(){ + pre.style.display = 'none' == pre.style.display + ? 'block' + : 'none'; + }); + + // code + // TODO: defer + if (!test.pending) { + var pre = fragment('
    %e
    ', clean(test.fn.toString())); + el.appendChild(pre); + pre.style.display = 'none'; + } + + stack[0].appendChild(el); + }); +} + +/** + * Display error `msg`. + */ + +function error(msg) { + document.body.appendChild(fragment('
    %s
    ', msg)); +} + +/** + * Return a DOM fragment from `html`. + */ + +function fragment(html) { + var args = arguments + , div = document.createElement('div') + , i = 1; + + div.innerHTML = html.replace(/%([se])/g, function(_, type){ + switch (type) { + case 's': return String(args[i++]); + case 'e': return escape(args[i++]); + } + }); + + return div.firstChild; +} + +/** + * Set `el` text to `str`. + */ + +function text(el, str) { + if (el.textContent) { + el.textContent = str; + } else { + el.innerText = str; + } +} + +/** + * Listen on `event` with callback `fn`. + */ + +function on(el, event, fn) { + if (el.addEventListener) { + el.addEventListener(event, fn, false); + } else { + el.attachEvent('on' + event, fn); + } +} + +/** + * Strip the function definition from `str`, + * and re-indent for pre whitespace. + */ + +function clean(str) { + str = str + .replace(/^function *\(.*\) *{/, '') + .replace(/\s+\}$/, ''); + + var spaces = str.match(/^\n?( *)/)[1].length + , re = new RegExp('^ {' + spaces + '}', 'gm'); + + str = str + .replace(re, '') + .replace(/^\s+/, ''); + + return str; +} + +}); // module: reporters/html.js + +require.register("reporters/index.js", function(module, exports, require){ + +exports.Base = require('./base'); +exports.Dot = require('./dot'); +exports.Doc = require('./doc'); +exports.TAP = require('./tap'); +exports.JSON = require('./json'); +exports.HTML = require('./html'); +exports.List = require('./list'); +exports.Min = require('./min'); +exports.Spec = require('./spec'); +exports.Progress = require('./progress'); +exports.Landing = require('./landing'); +exports.JSONCov = require('./json-cov'); +exports.HTMLCov = require('./html-cov'); +exports.JSONStream = require('./json-stream'); +exports.XUnit = require('./xunit') +exports.Teamcity = require('./teamcity') + +}); // module: reporters/index.js + +require.register("reporters/json-cov.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base'); + +/** + * Expose `JSONCov`. + */ + +exports = module.exports = JSONCov; + +/** + * Initialize a new `JsCoverage` reporter. + * + * @param {Runner} runner + * @param {Boolean} output + * @api public + */ + +function JSONCov(runner, output) { + var self = this + , output = 1 == arguments.length ? true : output; + + Base.call(this, runner); + + var tests = [] + , failures = [] + , passes = []; + + runner.on('test end', function(test){ + tests.push(test); + }); + + runner.on('pass', function(test){ + passes.push(test); + }); + + runner.on('fail', function(test){ + failures.push(test); + }); + + runner.on('end', function(){ + var cov = global._$jscoverage || {}; + var result = self.cov = map(cov); + result.stats = self.stats; + result.tests = tests.map(clean); + result.failures = failures.map(clean); + result.passes = passes.map(clean); + if (!output) return; + process.stdout.write(JSON.stringify(result, null, 2 )); + }); +} + +/** + * Map jscoverage data to a JSON structure + * suitable for reporting. + * + * @param {Object} cov + * @return {Object} + * @api private + */ + +function map(cov) { + var ret = { + instrumentation: 'node-jscoverage' + , sloc: 0 + , hits: 0 + , misses: 0 + , coverage: 0 + , files: [] + }; + + for (var filename in cov) { + var data = coverage(filename, cov[filename]); + ret.files.push(data); + ret.hits += data.hits; + ret.misses += data.misses; + ret.sloc += data.sloc; + } + + if (ret.sloc > 0) { + ret.coverage = (ret.hits / ret.sloc) * 100; + } + + return ret; +}; + +/** + * Map jscoverage data for a single source file + * to a JSON structure suitable for reporting. + * + * @param {String} filename name of the source file + * @param {Object} data jscoverage coverage data + * @return {Object} + * @api private + */ + +function coverage(filename, data) { + var ret = { + filename: filename, + coverage: 0, + hits: 0, + misses: 0, + sloc: 0, + source: {} + }; + + data.source.forEach(function(line, num){ + num++; + + if (data[num] === 0) { + ret.misses++; + ret.sloc++; + } else if (data[num] !== undefined) { + ret.hits++; + ret.sloc++; + } + + ret.source[num] = { + source: line + , coverage: data[num] === undefined + ? '' + : data[num] + }; + }); + + ret.coverage = ret.hits / ret.sloc * 100; + + return ret; +} + +/** + * Return a plain-object representation of `test` + * free of cyclic properties etc. + * + * @param {Object} test + * @return {Object} + * @api private + */ + +function clean(test) { + return { + title: test.title + , fullTitle: test.fullTitle() + , duration: test.duration + } +} + +}); // module: reporters/json-cov.js + +require.register("reporters/json-stream.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , color = Base.color; + +/** + * Expose `List`. + */ + +exports = module.exports = List; + +/** + * Initialize a new `List` test reporter. + * + * @param {Runner} runner + * @api public + */ + +function List(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , total = runner.total; + + runner.on('start', function(){ + console.log(JSON.stringify(['start', { total: total }])); + }); + + runner.on('pass', function(test){ + console.log(JSON.stringify(['pass', clean(test)])); + }); + + runner.on('fail', function(test, err){ + console.log(JSON.stringify(['fail', clean(test)])); + }); + + runner.on('end', function(){ + process.stdout.write(JSON.stringify(['end', self.stats])); + }); +} + +/** + * Return a plain-object representation of `test` + * free of cyclic properties etc. + * + * @param {Object} test + * @return {Object} + * @api private + */ + +function clean(test) { + return { + title: test.title + , fullTitle: test.fullTitle() + , duration: test.duration + } +} +}); // module: reporters/json-stream.js + +require.register("reporters/json.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , cursor = Base.cursor + , color = Base.color; + +/** + * Expose `JSON`. + */ + +exports = module.exports = JSONReporter; + +/** + * Initialize a new `JSON` reporter. + * + * @param {Runner} runner + * @api public + */ + +function JSONReporter(runner) { + var self = this; + Base.call(this, runner); + + var tests = [] + , failures = [] + , passes = []; + + runner.on('test end', function(test){ + tests.push(test); + }); + + runner.on('pass', function(test){ + passes.push(test); + }); + + runner.on('fail', function(test){ + failures.push(test); + }); + + runner.on('end', function(){ + var obj = { + stats: self.stats + , tests: tests.map(clean) + , failures: failures.map(clean) + , passes: passes.map(clean) + }; + + process.stdout.write(JSON.stringify(obj, null, 2)); + }); +} + +/** + * Return a plain-object representation of `test` + * free of cyclic properties etc. + * + * @param {Object} test + * @return {Object} + * @api private + */ + +function clean(test) { + return { + title: test.title + , fullTitle: test.fullTitle() + , duration: test.duration + } +} +}); // module: reporters/json.js + +require.register("reporters/landing.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , cursor = Base.cursor + , color = Base.color; + +/** + * Expose `Landing`. + */ + +exports = module.exports = Landing; + +/** + * Airplane color. + */ + +Base.colors.plane = 0; + +/** + * Airplane crash color. + */ + +Base.colors['plane crash'] = 31; + +/** + * Runway color. + */ + +Base.colors.runway = 90; + +/** + * Initialize a new `Landing` reporter. + * + * @param {Runner} runner + * @api public + */ + +function Landing(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , width = Base.window.width * .75 | 0 + , total = runner.total + , stream = process.stdout + , plane = color('plane', '?') + , crashed = -1 + , n = 0; + + function runway() { + var buf = Array(width).join('-'); + return ' ' + color('runway', buf); + } + + runner.on('start', function(){ + stream.write('\n '); + cursor.hide(); + }); + + runner.on('test end', function(test){ + // check if the plane crashed + var col = -1 == crashed + ? width * ++n / total | 0 + : crashed; + + // show the crash + if ('failed' == test.state) { + plane = color('plane crash', '?'); + crashed = col; + } + + // render landing strip + stream.write('\033[4F\n\n'); + stream.write(runway()); + stream.write('\n '); + stream.write(color('runway', Array(col).join('·'))); + stream.write(plane) + stream.write(color('runway', Array(width - col).join('·') + '\n')); + stream.write(runway()); + stream.write('\033[0m'); + }); + + runner.on('end', function(){ + cursor.show(); + console.log(); + self.epilogue(); + }); +} + +/** + * Inherit from `Base.prototype`. + */ + +Landing.prototype = new Base; +Landing.prototype.constructor = Landing; + +}); // module: reporters/landing.js + +require.register("reporters/list.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , cursor = Base.cursor + , color = Base.color; + +/** + * Expose `List`. + */ + +exports = module.exports = List; + +/** + * Initialize a new `List` test reporter. + * + * @param {Runner} runner + * @api public + */ + +function List(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , n = 0; + + runner.on('start', function(){ + console.log(); + }); + + runner.on('test', function(test){ + process.stdout.write(color('pass', ' ' + test.fullTitle() + ': ')); + }); + + runner.on('pending', function(test){ + var fmt = color('checkmark', ' -') + + color('pending', ' %s'); + console.log(fmt, test.fullTitle()); + }); + + runner.on('pass', function(test){ + var fmt = color('checkmark', ' ?') + + color('pass', ' %s: ') + + color(test.speed, '%dms'); + cursor.CR(); + console.log(fmt, test.fullTitle(), test.duration); + }); + + runner.on('fail', function(test, err){ + cursor.CR(); + console.log(color('fail', ' %d) %s'), ++n, test.fullTitle()); + }); + + runner.on('end', self.epilogue.bind(self)); +} + +/** + * Inherit from `Base.prototype`. + */ + +List.prototype = new Base; +List.prototype.constructor = List; + + +}); // module: reporters/list.js + +require.register("reporters/markdown.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , utils = require('../utils'); + +/** + * Expose `Markdown`. + */ + +exports = module.exports = Markdown; + +/** + * Initialize a new `Markdown` reporter. + * + * @param {Runner} runner + * @api public + */ + +function Markdown(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , total = runner.total + , level = 0 + , buf = ''; + + function title(str) { + return Array(level).join('#') + ' ' + str; + } + + function indent() { + return Array(level).join(' '); + } + + function mapTOC(suite, obj) { + var ret = obj; + obj = obj[suite.title] = obj[suite.title] || { suite: suite }; + suite.suites.forEach(function(suite){ + mapTOC(suite, obj); + }); + return ret; + } + + function stringifyTOC(obj, level) { + ++level; + var buf = ''; + var link; + for (var key in obj) { + if ('suite' == key) continue; + if (key) link = ' - [' + key + '](#' + utils.slug(obj[key].suite.fullTitle()) + ')\n'; + if (key) buf += Array(level).join(' ') + link; + buf += stringifyTOC(obj[key], level); + } + --level; + return buf; + } + + function generateTOC(suite) { + var obj = mapTOC(suite, {}); + return stringifyTOC(obj, 0); + } + + generateTOC(runner.suite); + + runner.on('suite', function(suite){ + ++level; + var slug = utils.slug(suite.fullTitle()); + buf += '' + '\n'; + buf += title(suite.title) + '\n'; + }); + + runner.on('suite end', function(suite){ + --level; + }); + + runner.on('pass', function(test){ + var code = clean(test.fn.toString()); + buf += test.title + '.\n'; + buf += '\n```js'; + buf += code + '\n'; + buf += '```\n\n'; + }); + + runner.on('end', function(){ + process.stdout.write('# TOC\n'); + process.stdout.write(generateTOC(runner.suite)); + process.stdout.write(buf); + }); +} + +/** + * Strip the function definition from `str`, + * and re-indent for pre whitespace. + */ + +function clean(str) { + str = str + .replace(/^function *\(.*\) *{/, '') + .replace(/\s+\}$/, ''); + + var spaces = str.match(/^\n?( *)/)[1].length + , re = new RegExp('^ {' + spaces + '}', 'gm'); + + str = str.replace(re, ''); + + return str; +} +}); // module: reporters/markdown.js + +require.register("reporters/min.js", function(module, exports, require){ +/** + * Module dependencies. + */ + +var Base = require('./base'); + +/** + * Expose `Min`. + */ + +exports = module.exports = Min; + +/** + * Initialize a new `Min` minimal test reporter (best used with --watch). + * + * @param {Runner} runner + * @api public + */ + +function Min(runner) { + Base.call(this, runner); + + runner.on('start', function(){ + // clear screen + process.stdout.write('\033[2J'); + // set cursor position + process.stdout.write('\033[1;3H'); + }); + + runner.on('end', this.epilogue.bind(this)); +} + +/** + * Inherit from `Base.prototype`. + */ + +Min.prototype = new Base; +Min.prototype.constructor = Min; + +}); // module: reporters/min.js + +require.register("reporters/progress.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , cursor = Base.cursor + , color = Base.color; + +/** + * Expose `Progress`. + */ + +exports = module.exports = Progress; + +/** + * General progress bar color. + */ + +Base.colors.progress = 90; + +/** + * Initialize a new `Progress` bar test reporter. + * + * @param {Runner} runner + * @param {Object} options + * @api public + */ + +function Progress(runner, options) { + Base.call(this, runner); + + var self = this + , options = options || {} + , stats = this.stats + , width = Base.window.width * .50 | 0 + , total = runner.total + , complete = 0 + , max = Math.max; + + // default chars + options.open = options.open || '['; + options.complete = options.complete || '?'; + options.incomplete = options.incomplete || '·'; + options.close = options.close || ']'; + options.verbose = false; + + // tests started + runner.on('start', function(){ + console.log(); + cursor.hide(); + }); + + // tests complete + runner.on('test end', function(){ + complete++; + var incomplete = total - complete + , percent = complete / total + , n = width * percent | 0 + , i = width - n; + + cursor.CR(); + process.stdout.write('\033[J'); + process.stdout.write(color('progress', ' ' + options.open)); + process.stdout.write(Array(n).join(options.complete)); + process.stdout.write(Array(i).join(options.incomplete)); + process.stdout.write(color('progress', options.close)); + if (options.verbose) { + process.stdout.write(color('progress', ' ' + complete + ' of ' + total)); + } + }); + + // tests are complete, output some stats + // and the failures if any + runner.on('end', function(){ + cursor.show(); + console.log(); + self.epilogue(); + }); +} + +/** + * Inherit from `Base.prototype`. + */ + +Progress.prototype = new Base; +Progress.prototype.constructor = Progress; + + +}); // module: reporters/progress.js + +require.register("reporters/spec.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , cursor = Base.cursor + , color = Base.color; + +/** + * Expose `Spec`. + */ + +exports = module.exports = Spec; + +/** + * Initialize a new `Spec` test reporter. + * + * @param {Runner} runner + * @api public + */ + +function Spec(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , indents = 0 + , n = 0; + + function indent() { + return Array(indents).join(' ') + } + + runner.on('start', function(){ + console.log(); + }); + + runner.on('suite', function(suite){ + ++indents; + console.log(color('suite', '%s%s'), indent(), suite.title); + }); + + runner.on('suite end', function(suite){ + --indents; + if (1 == indents) console.log(); + }); + + runner.on('test', function(test){ + process.stdout.write(indent() + color('pass', ' ? ' + test.title + ': ')); + }); + + runner.on('pending', function(test){ + var fmt = indent() + color('pending', ' - %s'); + console.log(fmt, test.title); + }); + + runner.on('pass', function(test){ + if ('fast' == test.speed) { + var fmt = indent() + + color('checkmark', ' ?') + + color('pass', ' %s '); + cursor.CR(); + console.log(fmt, test.title); + } else { + var fmt = indent() + + color('checkmark', ' ?') + + color('pass', ' %s ') + + color(test.speed, '(%dms)'); + cursor.CR(); + console.log(fmt, test.title, test.duration); + } + }); + + runner.on('fail', function(test, err){ + cursor.CR(); + console.log(indent() + color('fail', ' %d) %s'), ++n, test.title); + }); + + runner.on('end', self.epilogue.bind(self)); +} + +/** + * Inherit from `Base.prototype`. + */ + +Spec.prototype = new Base; +Spec.prototype.constructor = Spec; + + +}); // module: reporters/spec.js + +require.register("reporters/tap.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , cursor = Base.cursor + , color = Base.color; + +/** + * Expose `TAP`. + */ + +exports = module.exports = TAP; + +/** + * Initialize a new `TAP` reporter. + * + * @param {Runner} runner + * @api public + */ + +function TAP(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , total = runner.total + , n = 1; + + runner.on('start', function(){ + console.log('%d..%d', 1, total); + }); + + runner.on('test end', function(){ + ++n; + }); + + runner.on('pending', function(test){ + console.log('ok %d %s # SKIP -', n, title(test)); + }); + + runner.on('pass', function(test){ + console.log('ok %d %s', n, title(test)); + }); + + runner.on('fail', function(test, err){ + console.log('not ok %d %s', n, title(test)); + console.log(err.stack.replace(/^/gm, ' ')); + }); +} + +/** + * Return a TAP-safe title of `test` + * + * @param {Object} test + * @return {String} + * @api private + */ + +function title(test) { + return test.fullTitle().replace(/#/g, ''); +} + +}); // module: reporters/tap.js + +require.register("reporters/teamcity.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base'); + +/** + * Expose `Teamcity`. + */ + +exports = module.exports = Teamcity; + +/** + * Initialize a new `Teamcity` reporter. + * + * @param {Runner} runner + * @api public + */ + +function Teamcity(runner) { + Base.call(this, runner); + var stats = this.stats; + + runner.on('start', function() { + console.log("##teamcity[testSuiteStarted name='mocha.suite']"); + }); + + runner.on('test', function(test) { + console.log("##teamcity[testStarted name='" + escape(test.fullTitle()) + "']"); + }); + + runner.on('fail', function(test, err) { + console.log("##teamcity[testFailed name='" + escape(test.fullTitle()) + "' message='" + escape(err.message) + "']"); + }); + + runner.on('pending', function(test) { + console.log("##teamcity[testIgnored name='" + escape(test.fullTitle()) + "' message='pending']"); + }); + + runner.on('test end', function(test) { + console.log("##teamcity[testFinished name='" + escape(test.fullTitle()) + "' duration='" + test.duration + "']"); + }); + + runner.on('end', function() { + console.log("##teamcity[testSuiteFinished name='mocha.suite' duration='" + stats.duration + "']"); + }); +} + +/** + * Escape the given `str`. + */ + +function escape(str) { + return str + .replace(/\|/g, "||") + .replace(/\n/g, "|n") + .replace(/\r/g, "|r") + .replace(/\[/g, "|[") + .replace(/\]/g, "|]") + .replace(/\u0085/g, "|x") + .replace(/\u2028/g, "|l") + .replace(/\u2029/g, "|p") + .replace(/'/g, "|'"); +} + +}); // module: reporters/teamcity.js + +require.register("reporters/xunit.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , utils = require('../utils') + , escape = utils.escape; + +/** + * Save timer references to avoid Sinon interfering (see GH-237). + */ + +var Date = global.Date + , setTimeout = global.setTimeout + , setInterval = global.setInterval + , clearTimeout = global.clearTimeout + , clearInterval = global.clearInterval; + +/** + * Expose `XUnit`. + */ + +exports = module.exports = XUnit; + +/** + * Initialize a new `XUnit` reporter. + * + * @param {Runner} runner + * @api public + */ + +function XUnit(runner) { + Base.call(this, runner); + var stats = this.stats + , tests = [] + , self = this; + + runner.on('test end', function(test){ + tests.push(test); + }); + + runner.on('end', function(){ + console.log(tag('testsuite', { + name: 'Mocha Tests' + , tests: stats.tests + , failures: stats.failures + , errors: stats.failures + , skip: stats.tests - stats.failures - stats.passes + , timestamp: (new Date).toUTCString() + , time: stats.duration / 1000 + }, false)); + + tests.forEach(test); + console.log(''); + }); +} + +/** + * Inherit from `Base.prototype`. + */ + +XUnit.prototype = new Base; +XUnit.prototype.constructor = XUnit; + + +/** + * Output tag for the given `test.` + */ + +function test(test) { + var attrs = { + classname: test.parent.fullTitle() + , name: test.title + , time: test.duration / 1000 + }; + + if ('failed' == test.state) { + var err = test.err; + attrs.message = escape(err.message); + console.log(tag('testcase', attrs, false, tag('failure', attrs, false, cdata(err.stack)))); + } else if (test.pending) { + console.log(tag('testcase', attrs, false, tag('skipped', {}, true))); + } else { + console.log(tag('testcase', attrs, true) ); + } +} + +/** + * HTML tag helper. + */ + +function tag(name, attrs, close, content) { + var end = close ? '/>' : '>' + , pairs = [] + , tag; + + for (var key in attrs) { + pairs.push(key + '="' + escape(attrs[key]) + '"'); + } + + tag = '<' + name + (pairs.length ? ' ' + pairs.join(' ') : '') + end; + if (content) tag += content + ''; +} + +}); // module: reporters/xunit.js + +require.register("runnable.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var EventEmitter = require('browser/events').EventEmitter + , debug = require('browser/debug')('runnable'); + +/** + * Save timer references to avoid Sinon interfering (see GH-237). + */ + +var Date = global.Date + , setTimeout = global.setTimeout + , setInterval = global.setInterval + , clearTimeout = global.clearTimeout + , clearInterval = global.clearInterval; + +/** + * Expose `Runnable`. + */ + +module.exports = Runnable; + +/** + * Initialize a new `Runnable` with the given `title` and callback `fn`. + * + * @param {String} title + * @param {Function} fn + * @api private + */ + +function Runnable(title, fn) { + this.title = title; + this.fn = fn; + this.async = fn && fn.length; + this.sync = ! this.async; + this._timeout = 2000; + this.timedOut = false; +} + +/** + * Inherit from `EventEmitter.prototype`. + */ + +Runnable.prototype = new EventEmitter; +Runnable.prototype.constructor = Runnable; + + +/** + * Set & get timeout `ms`. + * + * @param {Number} ms + * @return {Runnable|Number} ms or self + * @api private + */ + +Runnable.prototype.timeout = function(ms){ + if (0 == arguments.length) return this._timeout; + debug('timeout %d', ms); + this._timeout = ms; + if (this.timer) this.resetTimeout(); + return this; +}; + +/** + * Return the full title generated by recursively + * concatenating the parent's full title. + * + * @return {String} + * @api public + */ + +Runnable.prototype.fullTitle = function(){ + return this.parent.fullTitle() + ' ' + this.title; +}; + +/** + * Clear the timeout. + * + * @api private + */ + +Runnable.prototype.clearTimeout = function(){ + clearTimeout(this.timer); +}; + +/** + * Reset the timeout. + * + * @api private + */ + +Runnable.prototype.resetTimeout = function(){ + var self = this + , ms = this.timeout(); + + this.clearTimeout(); + if (ms) { + this.timer = setTimeout(function(){ + self.callback(new Error('timeout of ' + ms + 'ms exceeded')); + self.timedOut = true; + }, ms); + } +}; + +/** + * Run the test and invoke `fn(err)`. + * + * @param {Function} fn + * @api private + */ + +Runnable.prototype.run = function(fn){ + var self = this + , ms = this.timeout() + , start = new Date + , ctx = this.ctx + , finished + , emitted; + + if (ctx) ctx.runnable(this); + + // timeout + if (this.async) { + if (ms) { + this.timer = setTimeout(function(){ + done(new Error('timeout of ' + ms + 'ms exceeded')); + self.timedOut = true; + }, ms); + } + } + + // called multiple times + function multiple() { + if (emitted) return; + emitted = true; + self.emit('error', new Error('done() called multiple times')); + } + + // finished + function done(err) { + if (self.timedOut) return; + if (finished) return multiple(); + self.clearTimeout(); + self.duration = new Date - start; + finished = true; + fn(err); + } + + // for .resetTimeout() + this.callback = done; + + // async + if (this.async) { + try { + this.fn.call(ctx, function(err){ + if (err instanceof Error) return done(err); + if (null != err) return done(new Error('done() invoked with non-Error: ' + err)); + done(); + }); + } catch (err) { + done(err); + } + return; + } + + // sync + try { + if (!this.pending) this.fn.call(ctx); + this.duration = new Date - start; + fn(); + } catch (err) { + fn(err); + } +}; + +}); // module: runnable.js + +require.register("runner.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var EventEmitter = require('browser/events').EventEmitter + , debug = require('browser/debug')('runner') + , Test = require('./test') + , utils = require('./utils') + , noop = function(){}; + +/** + * Expose `Runner`. + */ + +module.exports = Runner; + +/** + * Initialize a `Runner` for the given `suite`. + * + * Events: + * + * - `start` execution started + * - `end` execution complete + * - `suite` (suite) test suite execution started + * - `suite end` (suite) all tests (and sub-suites) have finished + * - `test` (test) test execution started + * - `test end` (test) test completed + * - `hook` (hook) hook execution started + * - `hook end` (hook) hook complete + * - `pass` (test) test passed + * - `fail` (test, err) test failed + * + * @api public + */ + +function Runner(suite) { + var self = this; + this._globals = []; + this.suite = suite; + this.total = suite.total(); + this.failures = 0; + this.on('test end', function(test){ self.checkGlobals(test); }); + this.on('hook end', function(hook){ self.checkGlobals(hook); }); + this.grep(/.*/); + this.globals(utils.keys(global).concat(['errno'])); +} + +/** + * Inherit from `EventEmitter.prototype`. + */ + +Runner.prototype = new EventEmitter; +Runner.prototype.constructor = Runner; + + +/** + * Run tests with full titles matching `re`. Updates runner.total + * with number of tests matched. + * + * @param {RegExp} re + * @return {Runner} for chaining + * @api public + */ + +Runner.prototype.grep = function(re){ + debug('grep %s', re); + this._grep = re; + this.total = this.grepTotal(this.suite); + return this; +}; + +/** + * Returns the number of tests matching the grep search for the + * given suite. + * + * @param {Suite} suite + * @return {Number} + * @api public + */ + +Runner.prototype.grepTotal = function(suite) { + var self = this; + var total = 0; + + suite.eachTest(function(test){ + if (self._grep.test(test.fullTitle())) total++; + }); + + return total; +}; + +/** + * Allow the given `arr` of globals. + * + * @param {Array} arr + * @return {Runner} for chaining + * @api public + */ + +Runner.prototype.globals = function(arr){ + if (0 == arguments.length) return this._globals; + debug('globals %j', arr); + utils.forEach(arr, function(arr){ + this._globals.push(arr); + }, this); + return this; +}; + +/** + * Check for global variable leaks. + * + * @api private + */ + +Runner.prototype.checkGlobals = function(test){ + if (this.ignoreLeaks) return; + var leaks = utils.filter(utils.keys(global), function(key){ + var matched = utils.filter(this._globals, function(allowed){ + return allowed == key || key.lastIndexOf(allowed.split('*')[0], 0) == 0; + }); + return matched.length == 0 && (!global.navigator || 'onerror' !== key); + }, this); + + this._globals = this._globals.concat(leaks); + + if (leaks.length > 1) { + this.fail(test, new Error('global leaks detected: ' + leaks.join(', ') + '')); + } else if (leaks.length) { + this.fail(test, new Error('global leak detected: ' + leaks[0])); + } +}; + +/** + * Fail the given `test`. + * + * @param {Test} test + * @param {Error} err + * @api private + */ + +Runner.prototype.fail = function(test, err){ + ++this.failures; + test.state = 'failed'; + if ('string' == typeof err) { + err = new Error('the string "' + err + '" was thrown, throw an Error :)'); + } + this.emit('fail', test, err); +}; + +/** + * Fail the given `hook` with `err`. + * + * Hook failures (currently) hard-end due + * to that fact that a failing hook will + * surely cause subsequent tests to fail, + * causing jumbled reporting. + * + * @param {Hook} hook + * @param {Error} err + * @api private + */ + +Runner.prototype.failHook = function(hook, err){ + this.fail(hook, err); + this.emit('end'); +}; + +/** + * Run hook `name` callbacks and then invoke `fn()`. + * + * @param {String} name + * @param {Function} function + * @api private + */ + +Runner.prototype.hook = function(name, fn){ + var suite = this.suite + , hooks = suite['_' + name] + , ms = suite._timeout + , self = this + , timer; + + function next(i) { + var hook = hooks[i]; + if (!hook) return fn(); + self.currentRunnable = hook; + + self.emit('hook', hook); + + hook.on('error', function(err){ + self.failHook(hook, err); + }); + + hook.run(function(err){ + hook.removeAllListeners('error'); + if (err) return self.failHook(hook, err); + self.emit('hook end', hook); + next(++i); + }); + } + + process.nextTick(function(){ + next(0); + }); +}; + +/** + * Run hook `name` for the given array of `suites` + * in order, and callback `fn(err)`. + * + * @param {String} name + * @param {Array} suites + * @param {Function} fn + * @api private + */ + +Runner.prototype.hooks = function(name, suites, fn){ + var self = this + , orig = this.suite; + + function next(suite) { + self.suite = suite; + + if (!suite) { + self.suite = orig; + return fn(); + } + + self.hook(name, function(err){ + if (err) { + self.suite = orig; + return fn(err); + } + + next(suites.pop()); + }); + } + + next(suites.pop()); +}; + +/** + * Run hooks from the top level down. + * + * @param {String} name + * @param {Function} fn + * @api private + */ + +Runner.prototype.hookUp = function(name, fn){ + var suites = [this.suite].concat(this.parents()).reverse(); + this.hooks(name, suites, fn); +}; + +/** + * Run hooks from the bottom up. + * + * @param {String} name + * @param {Function} fn + * @api private + */ + +Runner.prototype.hookDown = function(name, fn){ + var suites = [this.suite].concat(this.parents()); + this.hooks(name, suites, fn); +}; + +/** + * Return an array of parent Suites from + * closest to furthest. + * + * @return {Array} + * @api private + */ + +Runner.prototype.parents = function(){ + var suite = this.suite + , suites = []; + while (suite = suite.parent) suites.push(suite); + return suites; +}; + +/** + * Run the current test and callback `fn(err)`. + * + * @param {Function} fn + * @api private + */ + +Runner.prototype.runTest = function(fn){ + var test = this.test + , self = this; + + try { + test.on('error', function(err){ + self.fail(test, err); + }); + test.run(fn); + } catch (err) { + fn(err); + } +}; + +/** + * Run tests in the given `suite` and invoke + * the callback `fn()` when complete. + * + * @param {Suite} suite + * @param {Function} fn + * @api private + */ + +Runner.prototype.runTests = function(suite, fn){ + var self = this + , tests = suite.tests + , test; + + function next(err) { + // if we bail after first err + if (self.failures && suite._bail) return fn(); + + // next test + test = tests.shift(); + + // all done + if (!test) return fn(); + + // grep + if (!self._grep.test(test.fullTitle())) return next(); + + // pending + if (test.pending) { + self.emit('pending', test); + self.emit('test end', test); + return next(); + } + + // execute test and hook(s) + self.emit('test', self.test = test); + self.hookDown('beforeEach', function(){ + self.currentRunnable = self.test; + self.runTest(function(err){ + test = self.test; + + if (err) { + self.fail(test, err); + self.emit('test end', test); + return self.hookUp('afterEach', next); + } + + test.state = 'passed'; + self.emit('pass', test); + self.emit('test end', test); + self.hookUp('afterEach', next); + }); + }); + } + + this.next = next; + next(); +}; + +/** + * Run the given `suite` and invoke the + * callback `fn()` when complete. + * + * @param {Suite} suite + * @param {Function} fn + * @api private + */ + +Runner.prototype.runSuite = function(suite, fn){ + var total = this.grepTotal(suite) + , self = this + , i = 0; + + debug('run suite %s', suite.fullTitle()); + + if (!total) return fn(); + + this.emit('suite', this.suite = suite); + + function next() { + var curr = suite.suites[i++]; + if (!curr) return done(); + self.runSuite(curr, next); + } + + function done() { + self.suite = suite; + self.hook('afterAll', function(){ + self.emit('suite end', suite); + fn(); + }); + } + + this.hook('beforeAll', function(){ + self.runTests(suite, next); + }); +}; + +/** + * Handle uncaught exceptions. + * + * @param {Error} err + * @api private + */ + +Runner.prototype.uncaught = function(err){ + debug('uncaught exception'); + var runnable = this.currentRunnable; + if ('failed' == runnable.state) return; + runnable.clearTimeout(); + err.uncaught = true; + this.fail(runnable, err); + + // recover from test + if ('test' == runnable.type) { + this.emit('test end', runnable); + this.hookUp('afterEach', this.next); + return; + } + + // bail on hooks + this.emit('end'); +}; + +/** + * Run the root suite and invoke `fn(failures)` + * on completion. + * + * @param {Function} fn + * @return {Runner} for chaining + * @api public + */ + +Runner.prototype.run = function(fn){ + var self = this + , fn = fn || function(){}; + + debug('start'); + + // callback + this.on('end', function(){ + debug('end'); + process.removeListener('uncaughtException', this.uncaught); + fn(self.failures); + }); + + // run suites + this.emit('start'); + this.runSuite(this.suite, function(){ + debug('finished running'); + self.emit('end'); + }); + + // uncaught exception + process.on('uncaughtException', function(err){ + self.uncaught(err); + }); + + return this; +}; + +}); // module: runner.js + +require.register("suite.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var EventEmitter = require('browser/events').EventEmitter + , debug = require('browser/debug')('suite') + , utils = require('./utils') + , Hook = require('./hook'); + +/** + * Expose `Suite`. + */ + +exports = module.exports = Suite; + +/** + * Create a new `Suite` with the given `title` + * and parent `Suite`. When a suite with the + * same title is already present, that suite + * is returned to provide nicer reporter + * and more flexible meta-testing. + * + * @param {Suite} parent + * @param {String} title + * @return {Suite} + * @api public + */ + +exports.create = function(parent, title){ + var suite = new Suite(title, parent.ctx); + suite.parent = parent; + title = suite.fullTitle(); + parent.addSuite(suite); + return suite; +}; + +/** + * Initialize a new `Suite` with the given + * `title` and `ctx`. + * + * @param {String} title + * @param {Context} ctx + * @api private + */ + +function Suite(title, ctx) { + this.title = title; + this.ctx = ctx; + this.suites = []; + this.tests = []; + this._beforeEach = []; + this._beforeAll = []; + this._afterEach = []; + this._afterAll = []; + this.root = !title; + this._timeout = 2000; + this._bail = false; +} + +/** + * Inherit from `EventEmitter.prototype`. + */ + +Suite.prototype = new EventEmitter; +Suite.prototype.constructor = Suite; + + +/** + * Return a clone of this `Suite`. + * + * @return {Suite} + * @api private + */ + +Suite.prototype.clone = function(){ + var suite = new Suite(this.title); + debug('clone'); + suite.ctx = this.ctx; + suite.timeout(this.timeout()); + suite.bail(this.bail()); + return suite; +}; + +/** + * Set timeout `ms` or short-hand such as "2s". + * + * @param {Number|String} ms + * @return {Suite|Number} for chaining + * @api private + */ + +Suite.prototype.timeout = function(ms){ + if (0 == arguments.length) return this._timeout; + if (String(ms).match(/s$/)) ms = parseFloat(ms) * 1000; + debug('timeout %d', ms); + this._timeout = parseInt(ms, 10); + return this; +}; + +/** + * Sets whether to bail after first error. + * + * @parma {Boolean} bail + * @return {Suite|Number} for chaining + * @api private + */ + +Suite.prototype.bail = function(bail){ + if (0 == arguments.length) return this._bail; + debug('bail %s', bail); + this._bail = bail; + return this; +}; + +/** + * Run `fn(test[, done])` before running tests. + * + * @param {Function} fn + * @return {Suite} for chaining + * @api private + */ + +Suite.prototype.beforeAll = function(fn){ + var hook = new Hook('"before all" hook', fn); + hook.parent = this; + hook.timeout(this.timeout()); + hook.ctx = this.ctx; + this._beforeAll.push(hook); + this.emit('beforeAll', hook); + return this; +}; + +/** + * Run `fn(test[, done])` after running tests. + * + * @param {Function} fn + * @return {Suite} for chaining + * @api private + */ + +Suite.prototype.afterAll = function(fn){ + var hook = new Hook('"after all" hook', fn); + hook.parent = this; + hook.timeout(this.timeout()); + hook.ctx = this.ctx; + this._afterAll.push(hook); + this.emit('afterAll', hook); + return this; +}; + +/** + * Run `fn(test[, done])` before each test case. + * + * @param {Function} fn + * @return {Suite} for chaining + * @api private + */ + +Suite.prototype.beforeEach = function(fn){ + var hook = new Hook('"before each" hook', fn); + hook.parent = this; + hook.timeout(this.timeout()); + hook.ctx = this.ctx; + this._beforeEach.push(hook); + this.emit('beforeEach', hook); + return this; +}; + +/** + * Run `fn(test[, done])` after each test case. + * + * @param {Function} fn + * @return {Suite} for chaining + * @api private + */ + +Suite.prototype.afterEach = function(fn){ + var hook = new Hook('"after each" hook', fn); + hook.parent = this; + hook.timeout(this.timeout()); + hook.ctx = this.ctx; + this._afterEach.push(hook); + this.emit('afterEach', hook); + return this; +}; + +/** + * Add a test `suite`. + * + * @param {Suite} suite + * @return {Suite} for chaining + * @api private + */ + +Suite.prototype.addSuite = function(suite){ + suite.parent = this; + suite.timeout(this.timeout()); + suite.bail(this.bail()); + this.suites.push(suite); + this.emit('suite', suite); + return this; +}; + +/** + * Add a `test` to this suite. + * + * @param {Test} test + * @return {Suite} for chaining + * @api private + */ + +Suite.prototype.addTest = function(test){ + test.parent = this; + test.timeout(this.timeout()); + test.ctx = this.ctx; + this.tests.push(test); + this.emit('test', test); + return this; +}; + +/** + * Return the full title generated by recursively + * concatenating the parent's full title. + * + * @return {String} + * @api public + */ + +Suite.prototype.fullTitle = function(){ + if (this.parent) { + var full = this.parent.fullTitle(); + if (full) return full + ' ' + this.title; + } + return this.title; +}; + +/** + * Return the total number of tests. + * + * @return {Number} + * @api public + */ + +Suite.prototype.total = function(){ + return utils.reduce(this.suites, function(sum, suite){ + return sum + suite.total(); + }, 0) + this.tests.length; +}; + +/** + * Iterates through each suite recursively to find + * all tests. Applies a function in the format + * `fn(test)`. + * + * @param {Function} fn + * @return {Suite} + * @api private + */ + +Suite.prototype.eachTest = function(fn){ + utils.forEach(this.tests, fn); + utils.forEach(this.suites, function(suite){ + suite.eachTest(fn); + }); + return this; +}; + +}); // module: suite.js + +require.register("test.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Runnable = require('./runnable'); + +/** + * Expose `Test`. + */ + +module.exports = Test; + +/** + * Initialize a new `Test` with the given `title` and callback `fn`. + * + * @param {String} title + * @param {Function} fn + * @api private + */ + +function Test(title, fn) { + Runnable.call(this, title, fn); + this.pending = !fn; + this.type = 'test'; +} + +/** + * Inherit from `Runnable.prototype`. + */ + +Test.prototype = new Runnable; +Test.prototype.constructor = Test; + + +/** + * Inspect the context void of private properties. + * + * @return {String} + * @api private + */ + +Test.prototype.inspect = function(){ + return JSON.stringify(this, function(key, val){ + return '_' == key[0] + ? undefined + : 'parent' == key + ? '#' + : val; + }, 2); +}; +}); // module: test.js + +require.register("utils.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var fs = require('browser/fs') + , path = require('browser/path') + , join = path.join + , debug = require('browser/debug')('watch'); + +/** + * Ignored directories. + */ + +var ignore = ['node_modules', '.git']; + +/** + * Escape special characters in the given string of html. + * + * @param {String} html + * @return {String} + * @api private + */ + +exports.escape = function(html) { + return String(html) + .replace(/&/g, '&') + .replace(/"/g, '"') + .replace(//g, '>'); +}; + +/** + * Array#forEach (<=IE8) + * + * @param {Array} array + * @param {Function} fn + * @param {Object} scope + * @api private + */ + +exports.forEach = function(arr, fn, scope) { + for (var i = 0, l = arr.length; i < l; i++) + fn.call(scope, arr[i], i); +}; + +/** + * Array#indexOf (<=IE8) + * + * @parma {Array} arr + * @param {Object} obj to find index of + * @param {Number} start + * @api private + */ + +exports.indexOf = function (arr, obj, start) { + for (var i = start || 0, l = arr.length; i < l; i++) { + if (arr[i] === obj) + return i; + } + return -1; +}; + +/** + * Array#reduce (<=IE8) + * + * @param {Array} array + * @param {Function} fn + * @param {Object} initial value + * @param {Object} scope + * @api private + */ + +exports.reduce = function(arr, fn, val, scope) { + var rval = val; + + for (var i = 0, l = arr.length; i < l; i++) { + rval = fn.call(scope, rval, arr[i], i, arr); + } + + return rval; +}; + +/** + * Array#filter (<=IE8) + * + * @param {Array} array + * @param {Function} fn + * @param {Object} scope + * @api private + */ + +exports.filter = function(arr, fn, scope) { + var ret = []; + + for (var i = 0, l = arr.length; i < l; i++) { + var val = arr[i]; + if (fn.call(scope, val, i, arr)) + ret.push(val); + } + + return ret; +}; + +/** + * Object.keys (<=IE8) + * + * @param {Object} obj + * @return {Array} keys + * @api private + */ + +exports.keys = Object.keys || function(obj) { + var keys = [] + , has = Object.prototype.hasOwnProperty // for `window` on <=IE8 + + for (var key in obj) { + if (has.call(obj, key)) { + keys.push(key); + } + } + + return keys; +}; + +/** + * Watch the given `files` for changes + * and invoke `fn(file)` on modification. + * + * @param {Array} files + * @param {Function} fn + * @api private + */ + +exports.watch = function(files, fn){ + var options = { interval: 100 }; + files.forEach(function(file){ + debug('file %s', file); + fs.watchFile(file, options, function(curr, prev){ + if (prev.mtime < curr.mtime) fn(file); + }); + }); +}; + +/** + * Ignored files. + */ + +function ignored(path){ + return !~ignore.indexOf(path); +} + +/** + * Lookup files in the given `dir`. + * + * @return {Array} + * @api private + */ + +exports.files = function(dir, ret){ + ret = ret || []; + + fs.readdirSync(dir) + .filter(ignored) + .forEach(function(path){ + path = join(dir, path); + if (fs.statSync(path).isDirectory()) { + exports.files(path, ret); + } else if (path.match(/\.(js|coffee)$/)) { + ret.push(path); + } + }); + + return ret; +}; + +/** + * Compute a slug from the given `str`. + * + * @param {String} str + * @return {String} + * @api private + */ + +exports.slug = function(str){ + return str + .toLowerCase() + .replace(/ +/g, '-') + .replace(/[^-\w]/g, ''); +}; + +/** + * Escape regular expression characters in `str`. + * + * @param {String} str + * @return {String} + * @api private + */ + +exports.escapeRegexp = function(str){ + return str.replace(/[-\\^$*+?.()|[\]{}]/g, "\\$&"); +}; +}); // module: utils.js +/** + * Node shims. + * + * These are meant only to allow + * mocha.js to run untouched, not + * to allow running node code in + * the browser. + */ + +process = {}; +process.exit = function(status){}; +process.stdout = {}; +global = window; + +/** + * next tick implementation. + */ + +process.nextTick = (function(){ + // postMessage behaves badly on IE8 + if (window.ActiveXObject || !window.postMessage) { + return function(fn){ fn() }; + } + + // based on setZeroTimeout by David Baron + // - http://dbaron.org/log/20100309-faster-timeouts + var timeouts = [] + , name = 'mocha-zero-timeout' + + window.addEventListener('message', function(e){ + if (e.source == window && e.data == name) { + if (e.stopPropagation) e.stopPropagation(); + if (timeouts.length) timeouts.shift()(); + } + }, true); + + return function(fn){ + timeouts.push(fn); + window.postMessage(name, '*'); + } +})(); + +/** + * Remove uncaughtException listener. + */ + +process.removeListener = function(e){ + if ('uncaughtException' == e) { + window.onerror = null; + } +}; + +/** + * Implements uncaughtException listener. + */ + +process.on = function(e, fn){ + if ('uncaughtException' == e) { + window.onerror = fn; + } +}; + +/** + * Expose mocha. + */ + +window.mocha = require('mocha'); + +// boot +;(function(){ + var suite = new mocha.Suite('', new mocha.Context) + , utils = mocha.utils + , options = {} + + /** + * Highlight the given string of `js`. + */ + + function highlight(js) { + return js + .replace(//g, '>') + .replace(/\/\/(.*)/gm, '//$1') + .replace(/('.*?')/gm, '$1') + .replace(/(\d+\.\d+)/gm, '$1') + .replace(/(\d+)/gm, '$1') + .replace(/\bnew *(\w+)/gm, 'new $1') + .replace(/\b(function|new|throw|return|var|if|else)\b/gm, '$1') + } + + /** + * Highlight code contents. + */ + + function highlightCode() { + var code = document.getElementsByTagName('code'); + for (var i = 0, len = code.length; i < len; ++i) { + code[i].innerHTML = highlight(code[i].innerHTML); + } + } + + /** + * Parse the given `qs`. + */ + + function parse(qs) { + return utils.reduce(qs.replace('?', '').split('&'), function(obj, pair){ + var i = pair.indexOf('=') + , key = pair.slice(0, i) + , val = pair.slice(++i); + + obj[key] = decodeURIComponent(val); + return obj; + }, {}); + } + + /** + * Setup mocha with the given setting options. + */ + + mocha.setup = function(opts){ + if ('string' === typeof opts) options.ui = opts; + else options = opts; + + ui = mocha.interfaces[options.ui]; + if (!ui) throw new Error('invalid mocha interface "' + ui + '"'); + if (options.timeout) suite.timeout(options.timeout); + ui(suite); + suite.emit('pre-require', window); + }; + + /** + * Run mocha, returning the Runner. + */ + + mocha.run = function(fn){ + suite.emit('run'); + var runner = new mocha.Runner(suite); + var Reporter = options.reporter || mocha.reporters.HTML; + var reporter = new Reporter(runner); + var query = parse(window.location.search || ""); + if (query.grep) runner.grep(new RegExp(query.grep)); + if (options.ignoreLeaks) runner.ignoreLeaks = true; + if (options.globals) runner.globals(options.globals); + runner.globals(['location']); + runner.on('end', highlightCode); + return runner.run(fn); + }; +})(); +})(); \ No newline at end of file diff --git a/test/server.js b/test/server.js new file mode 100644 index 00000000..79bb292d --- /dev/null +++ b/test/server.js @@ -0,0 +1,25 @@ +module.exports=require('theory') +({name: 'echo' +, state: {way:'state', flow:-1} +, invincible: true +//, dep: ['../gun'] +, init: function(a){ + var echo = {}; + echo.put = function(m){ + console.log('stream', m); + } + echo.state = function(m){ + var w = echo.get(m); + console.log('state', w); + if(w){ + m.what.body = 1; + } + a.com.reply(m); + }; + echo.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 ; + }; + return echo; +}}); \ No newline at end of file diff --git a/test/test.js b/test/test.js new file mode 100644 index 00000000..75b42247 --- /dev/null +++ b/test/test.js @@ -0,0 +1,27 @@ +$(function(){ + /* + Tests not finished! + How does one automate testing of human input? + */ + describe('Start',function(){ + it('tests',function(){ + //return; + var s = theory.shot({src: '/test/server.js'}) + , g = s.gun('gunjs.herokuapp.com/state.json'); + s.wait(); + var b = g({}); + var c = g({}); + b('name','Bob'); + c('name','Calvin'); + c('brother',b); + s.go(); + console.log('first test done'); + }); + }); + (function run(){ + if(theory && theory.shot){ + return mocha.run(); + } + theory.time.wait(run,10); + })(); +}); \ No newline at end of file