packages feed

language-ecmascript 0.9 → 0.9.1

raw patch · 11 files changed

+2590/−6 lines, 11 filesdep ~data-defaultPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: data-default

API changes (from Hackage documentation)

Files

+ CHANGELOG view
@@ -0,0 +1,5 @@+Version change log.++=0.9.1= +Increased the upper bound on data-default in dependencies. See+https://github.com/jswebtools/language-ecmascript/pull/5
language-ecmascript.cabal view
@@ -1,5 +1,5 @@ Name:           language-ecmascript-Version:        0.9+Version:        0.9.1 Cabal-Version:	>= 1.10 Copyright:      (c) 2007-2012 Brown University, (c) 2008-2010 Claudiu Saftoiu,                 (c) 2012 Stevens Institute of Technology@@ -10,8 +10,9 @@ Maintainer:     Andrey Chudnov <oss@chudnov.com> Homepage:       http://github.com/jswebtools/language-ecmascript Bug-reports:    http://github.com/jswebtools/language-ecmascript/issues-Stability:      provisional-Tested-with:    GHC==7.0.4, GHC==7.4.1+Stability:      experimental+Tested-with:    GHC==7.4.1+Extra-Source-Files: tests/parse-pretty/*.js, CHANGELOG Category:       Language Build-Type:     Simple Synopsis:       JavaScript analysis tools@@ -20,7 +21,7 @@   Includes a parser, pretty-printer, and basic building blocks for more   sophisticated tools. -  This package supercedes package WebBits.+  This package used to be called WebBits.  Source-repository head    type: git@@ -42,7 +43,7 @@     containers >= 0.1,     syb >= 0.1,     uniplate >= 1.6 && <1.7,-    data-default >= 0.4 && <0.5+    data-default >= 0.4 && <0.6   ghc-options:     -fwarn-incomplete-patterns   Exposed-Modules:@@ -72,7 +73,7 @@     directory,     filepath,     HUnit,-    data-default >=0.4 && <0.5+    data-default >=0.4 && <0.6   Default-Extensions: DeriveDataTypeable, ScopedTypeVariables, DeriveFunctor, DeriveFoldable, DeriveTraversable, FlexibleContexts   Default-Language: Haskell2010   ghc-options:
+ tests/parse-pretty/add.js view
@@ -0,0 +1,1 @@+1+2;;;;
+ tests/parse-pretty/do-while.js view
@@ -0,0 +1,3 @@+do {+  x = y;+} while (element);
+ tests/parse-pretty/flapjax-fxinternal-22dec2008.js view
@@ -0,0 +1,2552 @@+function flapjaxInit(options) {+  // compress via http://alex.dojotoolkit.org/shrinksafe/+  // make sure to change final eval call to use exported library renamed +  // name+  +  var defaultOptions = {+    includeSynonyms: true,+    exportMisc: true,+    exportCore: true,+    exportDOM: true,+    exportDOMMisc: true,+    exportWS: true,+    hide: [ ],+    show: [ ],+    redefine: false,+  };+  +  if (options === false) {+    options = { hide: [ ], show: [ ] };+  }+  else if (options === true || !options) {+    options = { };+  }++  // Fill in any missing options using the defaults.+  for (var option in defaultOptions) {+    if (options[option] === undefined) {+      options[option] = defaultOptions[option];+    }+  };+  +  // Transform hide and show lists into tables+  var hideArray = options.hide;+  options.hide = { };+  for (var i = 0; i < hideArray.length; i++) {+    options.hide[hideArray[i]] = true;+  }+  var showArray = options.show;+  options.show = { };+  for (var i = 0; i < showArray.length; i++) {+    options.show[showArray[i]] = true;+  }+  +  var warn = function(s) {+    /*if (console && console.warn) {+      console.warn(s);+    }*/+  };+   +  +  var flapjax = {     +    version: 4, +    base: {}, //pulses+    combinators: {}, // combinators yielding nodes+	  behaviours: {},+    dom: {} // dom convenience methods and combinators+  };+  +  var d = flapjax.dom;+  +	flapjax.pub = {util:flapjax};+  +	var annotate = function(fn,names,protoArg,protoObjs,protoNames) {+		for(var i=0; i<names.length;i++) {+			flapjax.pub[names[i]] = fn;+		}+		if(protoArg != undefined) {+			var pf = function() {+				var args = slice(arguments,0);+				args.splice(protoArg,0,this);+				return fn.apply(this,args);+			}+			for(var i=0; i<protoObjs.length; i++) {+				for(var j=0; j<protoNames.length;j++) {+					protoObjs[i][protoNames[j]] = pf;+				}+			}+		}+	}+  +  var exports = { };+  var synonyms = { };++  var misc = { }; /* Used as a symbol */+  var core = { }; /* Used as a symbol */+  var dom = { }; /* Used as a symbol */+  var domMisc = { }; /* Used as a symbol */+  var ws = { }; /* Used as a symbol */+  +  var fxExport = function(exportCategory,exportVal,+                          exportName /* , synonyms */) {+    if (!(exportCategory instanceof Object)) {+      throw 'fxExport: category is ' + exportCategory;+    };++    if (typeof(exportName) != 'string') {+      console.log(exportVal);+      throw 'fxExport: name is ' + exportName;   +    };++    exportVal.__flapjaxCategory = exportCategory;+    exports[exportName] = exportVal;+    for (var i = 3; i < arguments.length; i++) {+      exports[arguments[i]] = exportVal;+      synonyms[arguments[i]] = true;+    }+  }+  +  var fxMethodSynonyms = function(obj,method) {+    if (options.includeSynonyms === true) {+      for (var i = 2; i < arguments.length; i++) {+        obj.prototype[arguments[i]] = obj.prototype[method];+      };+    };+  };+  +  //////////////////////////////////////////////////////////////////////////////+  // Miscellaneous functions+  +	//credit 4umi+	//slice: Array a * Integer * Integer -> Array a+	var slice = function (arr, start, stop) {+		var i, len = arr.length, r = [];+		if( !stop ) { stop = len; }+		if( stop < 0 ) { stop = len + stop; }+		if( start < 0 ) { start = len - start; }+		if( stop < start ) { i = start; start = stop; stop = i; }+		for( i = 0; i < stop - start; i++ ) { r[i] = arr[start+i]; }+		return r;+	}+  +	var isEqual = function (a,b) {+		return (a == b) ||+			( (((typeof(a) == 'number') && isNaN(a)) || a == 'NaN') &&+			  (((typeof(b) == 'number') && isNaN(b)) || b == 'NaN') );+	};++	//member: a * Array b -> Boolean+	var member = function(elt, lst) {+		for (var i = 0; i < lst.length; i++) { +			if (isEqual(lst[i], elt)) {return true;} +		}+		return false;+	};+  +	var zip = function(arrays) {+		if (arrays.length == 0) return [];+		var ret = [];+		for(var i=0; i<arrays[0].length;i++) {+			ret.push([]);+			for(var j=0; j<arrays.length;j++) +				ret[i].push(arrays[j][i]);+		}+		return ret;+	}++	//map: (a * ... -> z) * [a] * ... -> [z]+	var map = function (fn) {+		var arrays = slice(arguments, 1);+		if (arrays.length === 0) { return []; }+		else if (arrays.length === 1) {+			var ret = [];+			for(var i=0; i<arrays[0].length; i++) {ret.push(fn(arrays[0][i]));}+			return ret;+		}+		else {+			var ret = zip(arrays);+			var o = new Object();+			for(var i=0; i<ret.length; i++) {ret[i] = fn.apply(o,ret[i]);}+			return ret;+		}+	};+	  +	//filter: (a -> Boolean) * Array a -> Array a+	var filter = function (predFn, arr) {+		var res = [];+		for (var i = 0; i < arr.length; i++) { +			if (predFn(arr[i])) { res.push(arr[i]); }+		}+		return res;+	};+	  +  //fold: (a * .... * accum -> accum) * accum * [a] * ... -> accum+  //fold over list(s), left to right+  var fold = function(fn, init /* arrays */) {+		var lists = slice(arguments, 2);+		if (lists.length === 0) { return init; }+		else if(lists.length === 1) {+			var acc = init;+			for(var i = 0; i < lists[0].length; i++) {+				acc = fn(lists[0][i],acc);+			}+			return acc;+		}+		else {+			var acc = init;+			for (var i = 0; i < lists[0].length; i++) {+				var args = map( function (lst) { return lst[i];}, +		          lists);+				args.push(acc);+				acc = fn.apply({}, args);+			}+			return acc;+		}+  };+	  +  //foldR: (a * .... * accum -> accum) * accum * [a] * ... -> accum+	//fold over list(s), right to left, fold more memory efficient (left to right)+	var foldR = function (fn, init /* arrays */) {+    var lists = slice(arguments, 2);+		if (lists.length === 0) { return init; }+		else if(lists.length === 1) {+			var acc = init;+			for(var i=lists[0].length - 1; i > -1; i--)+				acc = fn(lists[0][i],acc);+			return acc;+		}+		else {+			var acc = init;+			for (var i = lists[0].length - 1; i > -1; i--) {+				var args = map( function (lst) { return lst[i];}, +		          lists);+				args.push(acc);+				acc = fn.apply({}, args);+			}+			return acc;     +		}+	};+  +  var pushAll = function(destArray,srcArray) {+    for (var i = 0; i < srcArray.length; i++) {+      destArray.push(srcArray[i]);+    }+    return destArray;+  };+	  +  fxExport(misc,slice,'slice');+  fxExport(misc,member,'member');+  fxExport(misc,map,'map');+  fxExport(misc,map,'forEach');+  fxExport(misc,filter,'filter');+  fxExport(misc,fold,'fold');+  fxExport(misc,foldR,'foldR');+  +  //////////////////////////////////////////////////////////////////////////////+  // Flapjax core+  +  //Pulse: Stamp * Path * Obj+  var Pulse = function (stamp, value) {+    this.stamp = stamp;+    this.value = value;+  };+++  //Probably can optimize as we expect increasing insert runs etc+  var PQ = function () {+    var ctx = this;+    ctx.val = [];+    this.insert = function (kv) {+			ctx.val.push(kv);+			var kvpos = ctx.val.length-1;+			while(kvpos > 0 && kv.k < ctx.val[Math.floor((kvpos-1)/2)].k) {+				var oldpos = kvpos;+				kvpos = Math.floor((kvpos-1)/2);+				ctx.val[oldpos] = ctx.val[kvpos];+				ctx.val[kvpos] = kv;+			}+    };+    this.isEmpty = function () { +      return ctx.val.length === 0; +    };+    this.pop = function () {+			if(ctx.val.length == 1) {+				return ctx.val.pop();+			}+			var ret = ctx.val.shift();+			ctx.val.unshift(ctx.val.pop());+			var kvpos = 0;+			var kv = ctx.val[0];+			while(1) {+				var leftChild = (kvpos*2+1 < ctx.val.length ? ctx.val[kvpos*2+1].k : kv.k+1);+				var rightChild = (kvpos*2+2 < ctx.val.length ? ctx.val[kvpos*2+2].k : kv.k+1);+				if(leftChild > kv.k && rightChild > kv.k)+					break;+				else if(leftChild < rightChild) {+					ctx.val[kvpos] = ctx.val[kvpos*2+1];+					ctx.val[kvpos*2+1] = kv;+					kvpos = kvpos*2+1;+				}+				else {+					ctx.val[kvpos] = ctx.val[kvpos*2+2];+					ctx.val[kvpos*2+2] = kv;+					kvpos = kvpos*2+2;+				}+			}+			return ret;+		};+  };+  +  var lastRank = 0;+  var stamp = 1;+  var nextStamp = function () { return ++stamp; };+  +  //propagatePulse: Pulse * Array Node -> +  //Send the pulse to each node +  var propagatePulse = function (pulse, node) {+    var queue = new PQ(); //topological queue for current timestep+	queue.insert({k:node.rank,n:node,v:pulse});+	while(!(queue.isEmpty())) {+		var qv = queue.pop();+		qv.n.updater(function(nextPulse) {+			for(var i=0; i<qv.n.sendsTo.length;i++)+				queue.insert({k:qv.n.sendsTo[i].rank,n:qv.n.sendsTo[i],v:nextPulse});+		},new Pulse(qv.v.stamp,qv.v.value));+	}+  };+  +  //Event: Array Node b * ( (Pulse a -> Void) * Pulse b -> Void)+  var EventStream = function (nodes,updater) {+    this.updater = updater;+    +    this.sendsTo = []; //forward link+    +    for (var i = 0; i < nodes.length; i++) {+      nodes[i].sendsTo.push(this);+    }+    +    this.rank = ++lastRank;+  };+	EventStream.prototype = new Object();+  +  fxExport(core,EventStream,'EventStream');+  +  +  //createNode: Array Node a * ( (Pulse b ->) * (Pulse a) -> Void) -> Node b+  var createNode = function (nodes, updater) {+		return new EventStream(nodes,updater);+	};+  +  //attachListenerNode: Node * Node -> Voids+  //flow from node to dependent+  //note: does not add flow as counting for rank nor updates parent ranks+  var attachListener = function (node, dependent) {+    if (!(node instanceof EventStream)) { throw 'attachListenenerNode: expects event as first arg';} //SAFETY+    if (!(dependent instanceof EventStream)) { throw 'attachListenenerNode: expects event as second arg';} //SAFETY+    +    node.sendsTo.push(dependent);+		if(node.rank > dependent.rank) {+			var lowest = lastRank+1;+			var q = [dependent];+			while(q.length) {+				var cur = q.splice(0,1)[0];+				cur.rank = ++lastRank;+				q = q.concat(cur.sendsTo);+			}+		}+  };+  +  //removeListenerNode: Node * Node -> Boolean+  //remove flow from node to dependent+  //note: does not remove flow as counting for rank nor updates parent ranks+  var removeListener = function (node, dependent)+  {+    if (!(node instanceof EventStream)) { throw 'removeListenerNode: expects event as first arg';} //SAFETY+    if (!(dependent instanceof EventStream)) { throw 'removeListenenerNode: expects event as second arg';} //SAFETY+    +    var foundSending = false;+    for (var i = 0; i < node.sendsTo.length && !foundSending; i++) {+      if (node.sendsTo[i] == dependent) {+        node.sendsTo.splice(i, 1);+        foundSending = true;+      }+    }+    +    return foundSending;+  };+  +  // An internal_e is a node that simply propagates all pulses it receives.  It's used internally by various +  // combinators.+  var internal_e = function(dependsOn) {+    return createNode(dependsOn || [ ],function(send,pulse) { send(pulse); });+  }+  +  var zero_e = function() {+    return createNode([],function(send,pulse) {+        throw ('zero_e : received a value; zero_e should not receive a value; the value was ' + pulse.value);+    });+  };+  fxExport(core,zero_e,'zero_e');+  +  var one_e = function(val) {+    var sent = false;+    var evt = createNode([],function(send,pulse) {+      if (sent) {+        throw ('one_e : received an extra value');+      }+      sent = true;+      send(pulse);+    });+    window.setTimeout(function() { sendEvent(evt,val); },0);+    return evt;+  };+  fxExport(core,one_e,'one_e');+  +  // a.k.a. mplus; merge_e(e1,e2) == merge_e(e2,e1)+  var merge_e = function() {+    if (arguments.length == 0) {+      return zero_e();+    }+    else {+      var deps = slice(arguments,0);+      return internal_e(deps);+    }+  };+  fxExport(core,merge_e,'merge_e');++  EventStream.prototype.merge_e = function() {+    var deps = slice(arguments,0);+    deps.push(this);+    return internal_e(deps);+  };+  fxMethodSynonyms(EventStream,'merge_e','merge');++  EventStream.prototype.constant_e = function(constantValue) {+    return createNode([this],function(send,pulse) {+      pulse.value = constantValue;+      send(pulse);+    });+  };+  fxMethodSynonyms(EventStream,'constant_e','constant','replaceValue_e','replaceValue');+  +  var constant_e = function(e) { return e.constant_e(); };+  fxExport(core,constant_e,'constant_e','replaceValue_e');+  +	var createTimeSyncNode = function(nodes) {+		var nqs = map(function(n) {+				var qpulse = [];+				return {q:qpulse,v:createNode([n],function(s,p) {qpulse.push(p.value); s(p);},nodes)};+    },nodes);+		return createNode(+      map(function(n) {return n.v;},nqs), function(s,p) {+        var allfull = fold(function(n,acc) {return n.q.length && acc;},true,nqs);+        if(allfull) {+          p.value = map(function(n) {return n.q.shift();},nqs);+          s(p);+      }});+	};+  +	//This is up here so we can add things to its prototype that are in flapjax.combinators+  var Behaviour = function (event, init, updater) {+    if (!(event instanceof EventStream)) { +      throw 'Behaviour: expected event as second arg'; +    }+    +    var behave = this;+    this.last = init;+    +    //sendEvent to this might impact other nodes that depend on this event+    //sendBehaviour defaults to this one+    this.underlyingRaw = event;+    +    //unexposed, sendEvent to this will only impact dependents of this behaviour+    this.underlying =+    createNode(+      [event], +	  (updater ? +	   function (s, p) {behave.last = updater(p.value); p.value = behave.last; s(p);} : +	   function (s, p) {behave.last = p.value;  s(p);}));+  };+	Behaviour.prototype = new Object();+  fxExport(core,Behaviour,'Behaviour');+  fxExport(core,Behaviour,'Behavior');+  +  var receiver_e = function() {+    var evt = internal_e();+    evt.sendEvent = function(value) {+      propagatePulse(new Pulse(nextStamp(), value),evt);+    };+    return evt;+  };+  fxExport(core,receiver_e,'receiver_e');+  +  //note that this creates a new timestamp and new event queue+  var sendEvent = function (node, value) {+    if (!(node instanceof EventStream)) { throw 'sendEvent: expected Event as first arg'; } //SAFETY+    +    propagatePulse(new Pulse(nextStamp(), value),node);+  };+  fxExport(core,sendEvent,'sendEvent');+  synonyms['sendEvent'] = true; // Hack: sendEvent simply should not be exported; calling it a synonym deprecates it.+  +  // bind_e :: EventStream a * (a -> EventStream b) -> EventStream b+  EventStream.prototype.bind_e = function(k) {+    /* m.sendsTo result_e+     * result_e.sendsTo prev_e+     * prev_e.sendsTo return_e+     */+    var m = this;+    var prev_e = false;+    +    var out_e = createNode([],function(send,pulse) { send(pulse); });+    out_e.name = "bind out_e";+    +    var in_e = createNode([m], function (send,pulse) {+      if (prev_e) { +        removeListener(prev_e,out_e);+      }+      prev_e = k(pulse.value);+      if (prev_e instanceof EventStream) {+        attachListener(prev_e,out_e);+      }+      else {+        throw "bind_e : expected EventStream";+      }+    });+    in_e.name = "bind in_e";+    +    return out_e;+  };++  /* Could be written as:+   *+   * e.bind_e(function(v) { return one_e(f(v)); })+   */+  EventStream.prototype.lift_e = function(f) {+    if (!(f instanceof Function)) {+      throw ('lift_e : expected a function as the first argument; received ' + f);+    };+    +    return createNode([this],function(send,pulse) {+      pulse.value = f(pulse.value);+      send(pulse);+    });+  };+  fxMethodSynonyms(EventStream,'lift_e',+    'transform_e','map_e','apply_e','lift','transform','map','apply');+  +  EventStream.prototype.not_e = function() { return this.lift_e(function(v) { return !v; }); };+  fxMethodSynonyms(EventStream,'not_e','not');+  +  var not_e = function(e) { return e.not_e(); };+  fxExport(core,not_e,'not_e','not');+  +  EventStream.prototype.filter_e = function(pred) {+    if (!(pred instanceof Function)) {+      throw ('filter_e : expected predicate; received ' + pred);+    };+    +    // Can be a bind_e+    return createNode([this],+      function(send,pulse) {+        if (pred(pulse.value)) { send(pulse); }+    });+  };+  fxMethodSynonyms(EventStream,'filter_e','filter');+  +  var filter_e = function(e,p) { return e.filter_e(p); };+  fxExport(core,filter_e,'filter_e');+  +  // Fires just once.+  EventStream.prototype.once_e = function() {+    var done = false;+    // Alternately: this.collect_e(0,\n v -> (n+1,v)).filter_e(\(n,v) -> n == 1).lift_e(fst)+    return createNode([this],function(send,pulse) {+      if (!done) { done = true; send(pulse); }+    });+  };+  fxMethodSynonyms(EventStream,'once_e','once')+  +  var once_e = function(e) { return e.once_e(); };+  fxExport(core,once_e,'once_e');+  +  EventStream.prototype.skipFirst_e = function() {+    var skipped = false;+    return createNode([this],function(send,pulse) {+      if (skipped)+        { send(pulse); }+      else+        { skipped = true; }+    });+  };+  fxMethodSynonyms(EventStream,'skipFirst_e','skipFirst');+  +  var skipFirst_e = function(e) { return e.skipFirst_e(); };+  fxExport(core,skipFirst_e,'skipFirst_e');+  +  EventStream.prototype.collect_e = function(init,fold) {+    var acc = init;+    return this.lift_e(+      function (n) {+        var next = fold(n, acc);+        acc = next;+        return next;+      });+  };+  fxMethodSynonyms(EventStream,'collect_e','collect','transformWithMemory');+  +  var collect_e = function(e,i,f) { return e.collect_e(i,f); };+  fxExport(core,collect_e,'collect_e');+  +  // a.k.a. join+  EventStream.prototype.switch_e = function() {+    return this.bind_e(function(v) { return v; });+  };+  fxMethodSynonyms(EventStream,'switch_e','forwardLatest');+  +  var switch_e = function(e) { return e.switch_e(); };+  fxExport(core,switch_e,'switch_e');+  +  EventStream.prototype.if_e = function(thenE,elseE) {+    var testStamp = -1;+    var testValue = false;+    +    createNode([this],function(_,pulse) { testStamp = pulse.stamp; testValue = pulse.value; });+    +    return merge_e(+      createNode([thenE],function(send,pulse) { if (testValue && (testStamp == pulse.stamp)) { send(pulse); } }),+      createNode([elseE],function(send,pulse) { if (!testValue && (testStamp == pulse.stamp)) { send(pulse); } }));+  };+  fxMethodSynonyms(EventStream,'if_e','choose_e','choose');+  +  var if_e = function(test,thenE,elseE) {+    if (test instanceof EventStream)+      { return test.if_e(thenE,elseE); }+    else+      { return test ? thenE : elseE; }+  };+  fxExport(core,if_e,'if_e','choose_e');+      +  var cond_e = function (/*. predValArrays */) {+    var predValArrays = slice(arguments, 0);+    var acc = zero_e();+    for (var i = predValArrays.length - 1; i > -1; i--) {+      acc = if_e(predValArrays[i][0],predValArrays[i][1], acc);+    }+    return acc; +  };+  fxExport(core,cond_e,'cond_e');+  +  var and_e = function (/* . nodes */) {+    var nodes = slice(arguments, 0);+    +    var acc = (nodes.length > 0)? +    nodes[nodes.length - 1] : one_e(true);+    +    for (var i = nodes.length - 2; i > -1; i--) {+      acc = if_e(+        nodes[i], +        acc, +        nodes[i].constant_e(false));+    }+    return acc;+  };+  fxExport(core,and_e,'and_e');+  +  EventStream.prototype.and_e = function( /* others */ ) {+    var deps = [this].concat(slice(arguments,0));+    return and_e.apply(this,deps);+  };+  fxMethodSynonyms(EventStream,'and_e','and');+  +  var or_e = function () {+    var nodes = slice(arguments, 0);+    var acc = (nodes.length > 2)? +    nodes[nodes.length - 1] : one_e(false); +    for (var i = nodes.length - 2; i > -1; i--) {+      acc = if_e(+        nodes[i],+        nodes[i],+        acc);+    }+    return acc;+  };+  fxExport(core,or_e,'or_e');+  +  EventStream.prototype.or_e = function(/*others*/) {+    var deps = [this].concat(slice(arguments,0));+    return or_e.apply(this,deps);+  };+  fxMethodSynonyms(EventStream,'or_e','or');+  +  var delayStatic_e = function (event, time) {+    +    var resE = internal_e();+    +    createNode(+      [event],+      function (s, p) { +        setTimeout( +          function () { sendEvent(resE, p.value);}, +      time ); });+    +    return resE;+  };+  +  //delay_e: Event a * [Behaviour] Number ->  Event a+  EventStream.prototype.delay_e = function (time) {+    var event = this;+    +    if (time instanceof Behaviour) {+      +      var receiverEE = internal_e();+      var link = +      {+        from: event, +        towards: delayStatic_e(event, valueNow(time))+      };+      +			//TODO: Change semantics such that we are always guaranteed to get an event going out?+      var switcherE = +      createNode(+        [changes(time)],+        function (s, p) {+          removeListener(link.from, link.towards); +          link =+          {+            from: event, +            towards: delayStatic_e(event, p.value)+          };+          sendEvent(receiverEE, link.towards);+        });+      +      var resE = receiverEE.switch_e();+      +      sendEvent(switcherE, valueNow(time));+      return resE;+      +        } else { return delayStatic_e(event, time); }+  };+  fxMethodSynonyms(EventStream,'delay_e','delay');+  +  var delay_e = function(sourceE,interval) {+    return sourceE.delay_e(interval);+  };+  fxExport(core,delay_e,'delay_e');+  +  //lift_e: ([Event] (. Array a -> b)) . Array [Event] a -> [Event] b+  var lift_e = function (fn /*, [node0 | val0], ...*/) {+    //      if (!(fn instanceof Function)) { throw 'lift_e: expected fn as second arg'; } //SAFETY+    +    var valsOrNodes = slice(arguments, 0);+    //selectors[i]() returns either the node or real val, optimize real vals+    var selectors = [];+    var selectI = 0;+    var nodes = [];+    for (var i = 0; i < valsOrNodes.length; i++) {+      if (valsOrNodes[i] instanceof EventStream) {+        nodes.push(valsOrNodes[i]);+        selectors.push( +          (function(ii) {+              return function(realArgs) { +                return realArgs[ii];+              };+          })(selectI));+        selectI++;+      } else {+        selectors.push( +          (function(aa) { +              return function () {+                return aa;+              }; +          })(valsOrNodes[i]));+      } +    }+    +    var context = this;+		var nofnodes = slice(selectors,1);+    +    if (nodes.length === 0) {+      return one_e(fn.apply(context, valsOrNodes));+    } else if ((nodes.length === 1) && (fn instanceof Function)) {+      return nodes[0].lift_e(+        function () {+          var args = arguments;+          return fn.apply(+            context, +            map(function (s) {return s(args);}, nofnodes));+        });+    } else if (nodes.length === 1) {+      return fn.lift_e(+        function (v) {+          var args = arguments;+          return v.apply(+            context, +            map(function (s) {return s(args);}, nofnodes));+        });                +    } else if (fn instanceof Function) {+      return createTimeSyncNode(nodes).lift_e(+        function (arr) {+          return fn.apply(+            this,+            map(function (s) { return s(arr); }, nofnodes));+        });+    } else if (fn instanceof EventStream) {+      return createTimeSyncNode(nodes).lift_e(+        function (arr) {+          return arr[0].apply(+            this, +            map(function (s) {return s(arr); }, nofnodes));+        });+        } else {throw 'unknown lift_e case';}+  };+  fxExport(core,lift_e,'lift_e','transform_e','map_e','apply_e');+  +  EventStream.prototype.snapshot_e = function (valueB) {+    return createNode(+      [this],+      function (s, p) {+        p.value = valueNow(valueB);+        s(p);+      }+      ); +  };+  fxMethodSynonyms(EventStream,'snapshot_e','snapshot','takeSnapshot');++  var snapshot_e = function(triggerE,valueB) {+    return triggerE.snapshot_e(valueB);+  };+  fxExport(core,snapshot_e,'snapshot_e');++  EventStream.prototype.filterRepeats_e = function(optStart) {+    var hadFirst = optStart === undefined ? false : true;+    var prev = optStart;+  +    return this.filter_e(function (v) {+      if (!hadFirst || !(isEqual(prev,v))) {+        hadFirst = true;+        prev = v;+        return true;+      }+      else {+        return false;+      }+    });+  };+  fxMethodSynonyms(EventStream,'filterRepeats_e','filterRepeats');++  var filterRepeats_e = function(sourceE,optStart) {+    return sourceE.filterRepeats_e(optStart);+  };+  fxExport(core,filterRepeats_e,'filterRepeats_e','filterRepeats');++  //credit Pete Hopkins+  var calmStatic_e = function (triggerE, time) {+		var out = internal_e();+    createNode(+      [triggerE],+      function() {+        var towards = null;+        return function (s, p) {+          if (towards !== null) { clearTimeout(towards); }+          towards = setTimeout( function () { towards = null; sendEvent(out,p.value) }, time );+        };+      }());+		return out;+  };+  +  //calm_e: Event a * [Behaviour] Number -> Event a+  EventStream.prototype.calm_e = function(time) {+    if (time instanceof Behaviour) {+			var out = internal_e();+      createNode(+        [this],+        function() {+          var towards = null;+          return function (s, p) {+            if (towards !== null) { clearTimeout(towards); }+            towards = setTimeout( function () { towards = null; sendEvent(out,p.value) }, valueNow(time));+          };+        }());+			return out;+    } else {+      return calmStatic_e(this,time);       +    }+  };+  fxMethodSynonyms(EventStream,'calm_e','calm');+  +  var calm_e = function(sourceE,interval) {+    return sourceE.calm_e(interval);+  };+  fxExport(core,calm_e,'calm_e');+  +  EventStream.prototype.blind_e = function (time) {+    return createNode(+      [this],+      function () {+        var intervalFn = +        time instanceof Behaviour?+        function () { return valueNow(time); }+        : function () { return time; };+        var lastSent = (new Date()).getTime() - intervalFn() - 1;+        return function (s, p) {+          var curTime = (new Date()).getTime();+          if (curTime - lastSent > intervalFn()) {+            lastSent = curTime;+            s(p);+          }+        };+      }());+  };+  fxMethodSynonyms(EventStream,'blind_e','blind');+  +  var blind_e = function(sourceE,interval) {+    return sourceE.blind_e(interval);+  };+  fxExport(core,blind_e,'blind_e');+ +  EventStream.prototype.hold = function(init) {+    return new Behaviour(this,init);+  };+  fxMethodSynonyms(EventStream,'hold','startsWith','toBehavior');++  var hold = function(e,init) {+    if (!(e instanceof EventStream)) {+      throw 'hold: expected EventStream; received ' + e;+    }+    return e.hold(init); +  };+  fxExport(core,hold,'hold');+  +  Behaviour.prototype.valueNow = function() {+    return this.last;+  };+  var valueNow = function(behavior) { return behavior.valueNow(); };+  fxExport(core,valueNow,'valueNow');++  Behaviour.prototype.changes = function() {+    return this.underlying;+  };+  fxMethodSynonyms(Behaviour,'changes','toEvent');+  +  var changes = function (behave) { return behave.changes(); }+  fxExport(core,changes,'changes');+  +  Behaviour.prototype.switch_b = function() {+    var behaviourCreatorsB = this;+    var init = valueNow(behaviourCreatorsB);+    +    var prevSourceE = null;+    +    var receiverE = new internal_e();+    +		//XXX could result in out-of-order propagation! Fix!+    var makerE = +    createNode(+      [changes(behaviourCreatorsB)],+      function (_, p) {+        if (!(p.value instanceof Behaviour)) { throw 'switch_b: expected Behaviour as value of Behaviour of first argument'; } //SAFETY+        if (prevSourceE != null) {+          removeListener(prevSourceE, receiverE);+        }+        +        prevSourceE = changes(p.value);+        attachListener(prevSourceE, receiverE);+        +        sendEvent(receiverE, valueNow(p.value));+      });+    +    if (init instanceof Behaviour) {+      sendEvent(makerE, init);+    }+    +    return hold(+      receiverE,+      init instanceof Behaviour? valueNow(init) : init);+  };+  fxMethodSynonyms(Behaviour,'switch_b','forwardLatest');+  +  var switch_b = function (b) { return b.switch_b(); };+  fxExport(core,switch_b,'switch_b');+  +  //TODO test, signature+  var timer_b = function(interval) {+    return hold(timer_e(interval), (new Date()).getTime());+  };+  fxExport(dom,timer_b,'timer_b','asTimer_b');+  +  //TODO test, signature+  var delayStatic_b = function (triggerB, time, init) {+    return hold(delayStatic_e(changes(triggerB), time), init);+  };+  +  //TODO test, signature+  Behaviour.prototype.delay_b = function (time, init) {+    var triggerB = this;+    if (time instanceof Behaviour) {+      return hold(+        delay_e(+          changes(triggerB), +          time),+        arguments.length > 3 ? init : valueNow(triggerB));+    } else {+      return delayStatic_b(+        triggerB, +        time,+        arguments.length > 3 ? init : valueNow(triggerB));+    }+  };+  fxMethodSynonyms(Behaviour,'delay_b','delay');+  +  var delay_b = function(srcB, timeB, init) { +    return srcB.delay_b(timeB,init); +  };+  fxExport(core,delay_b,'delay_b');+  +  //artificially send a pulse to underlying event node of a behaviour+  //note: in use, might want to use a receiver node as a proxy or an identity map+  Behaviour.prototype.sendBehaviour = function(val) {+    sendEvent(this.underlyingRaw,val);+  };+  Behaviour.prototype.sendBehavior = Behaviour.prototype.sendBehaviour;+  +  var sendBehaviour = function (b,v) { b.sendBehaviour(v); };+  fxExport(core,sendBehaviour,'sendBehaviour');+  fxExport(core,sendBehaviour,'sendBehavior');++  Behaviour.prototype.if_b = function(trueB,falseB) {+    var testB = this;+    //TODO auto conversion for behaviour funcs+    if (!(trueB instanceof Behaviour)) { trueB = constant_b(trueB); }+    if (!(falseB instanceof Behaviour)) { falseB = constant_b(falseB); }+    return lift_b(function(te,t,f) { return te ? t : f; },testB,trueB,falseB);+  };+  fxMethodSynonyms(Behaviour,'if_b','choose_b','choose');+  +  var if_b = function(test,cons,altr) {+    if (!(test instanceof Behaviour)) { test = constant_b(test); };+    +    return test.if_b(cons,altr);+  };+  fxExport(core,if_b,'if_b','choose_b');+  ++  //cond_b: . [Behaviour boolean, Behaviour a] -> Behaviour a+  var cond_b = function (/* . pairs */ ) {+    var pairs = slice(arguments, 0);+	return lift_b.apply({},[function() {+			for(var i=0;i<pairs.length;i++) {+				if(arguments[i]) return arguments[pairs.length+i];+			}+			return undefined;+		}].concat(map(function(pair) {return pair[0];},pairs).concat(map(function(pair) {return pair[1];},pairs))));+  };+  fxExport(core,cond_b,'cond_b');+  +  //TODO optionally append to objects+  //createConstantB: a -> Behaviour a+  var constant_b = function (val) {+    return new Behaviour(internal_e(), val);+  };+  fxExport(core,constant_b,'constant_b','receiver_b');+  +	var lift_b = function (fn /* . behaves */) {+    var args = slice(arguments, 1);++    //dependencies+    var constituentsE =+      map(changes,+      filter(function (v) { return v instanceof Behaviour; },+        arguments));+    +    //calculate new vals+    var getCur = function (v) {+      return v instanceof Behaviour ? v.last : v;+    };+    +    var ctx = this;+    var getRes = function () {+      return getCur(fn).apply(ctx, map(getCur, args));+    };+	+    if(constituentsE.length == 1) {+      return new Behaviour(constituentsE[0],getRes(),getRes);+    }+      +    //gen/send vals @ appropriate time+    var prevStamp = -1;+    var mid = createNode(constituentsE, function (s, p) {+        if (p.stamp != prevStamp) {+          prevStamp = p.stamp;+          s(p);+    }});+    return new Behaviour(mid,getRes(),getRes);+  };+  fxExport(core,lift_b,'lift_b','transform_b','apply_b');+  +  Behaviour.prototype.lift_b = function(/* args */) {+    var args= slice(arguments,0).concat([this]);+    return lift_b.apply(this,args);+  };+  fxMethodSynonyms(Behaviour,'lift_b','transform_b','apply_b','transform',+    'lift');+  +  var and_b = function (/* . behaves */) {+	return lift_b.apply({},[function() {+			for(var i=0; i<arguments.length; i++) {if(!arguments[i]) return false;}+			return true;+	}].concat(slice(arguments,0)));+  };+  fxExport(core, and_b, 'and_b');+  +  Behaviour.prototype.and_b = function() {+    return and_b([this].concat(arguments));+  };+  fxMethodSynonyms(Behaviour,'and_b','and');+  +  var or_b = function (/* . behaves */ ) {+	return lift_b.apply({},[function() {+			for(var i=0; i<arguments.length; i++) {if(arguments[i]) return true;}+			return false;+	}].concat(slice(arguments,0)));+  };+  fxExport(core,or_b,'or_b');+  +  Behaviour.prototype.or_b = function () {+    return or_b([this].concat(arguments));+  };+  fxMethodSynonyms(Behaviour, 'or_b', 'or');+  +  Behaviour.prototype.not_b = function() {+    return this.lift_b(function(v) { return !v; });+  };+  fxMethodSynonyms(Behaviour,'not_b','not');+  +  var not_b = function(b) { return b.not_b(); };+  fxExport(core,not_b,'not_b');+  +  Behaviour.prototype.blind_b = function (intervalB) {+    return changes(this).blind_e(intervalB).hold(this.valueNow());+  };+  fxMethodSynonyms(Behaviour,'blind_b','blind');+  +  var blind_b = function(srcB,intervalB) {+    return srcB.blind_b(intervalB);+  };+  fxExport(core,blind_b,'blind_b');+  +  Behaviour.prototype.calm_b = function (intervalB) {+    return this.changes().calm_e(intervalB).hold(this.valueNow());+  };+  fxMethodSynonyms(Behaviour,'calm_b','calm');+  +  var calm_b = function (srcB,intervalB) { +    return srcB.calm_b(intervalB);+  };+  fxExport(core,calm_b,'calm_b');+    +  //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////+  // DOM Utilities+  +	//credit Scott Andrew+	//usage: addEvent(myDomObj, "mouseover", event->void )+	//warning: do not use 'this' as meaning depends on browser (myDomObj vs window)+	//addEvent: Dom * String DomEventEnum * (DomEvent -> a) -> Void+	var addEvent = function (obj, evType, fn) {+		//TODO encode mouseleave evt, formalize new evt interface+    +		if (obj.addEventListener) {+      obj.addEventListener(evType, fn, false); //TODO true fails on Opera+      return true;+		} else if (obj.attachEvent) {+      //some reason original had code bloat here+      return obj.attachEvent("on"+evType, fn); +		} else {+      return false; +		}+	};+  fxExport(domMisc,addEvent,'addEvent');++  // The Flapjax library does not use this function  +	//credit Dustin Diaz +	//note: node/tag optional+	//getElementsByClass: Regexp CSSSelector * Dom * String DomNodeEnum -> Array Dom+	var getElementsByClass = function (searchClass, node, tag) {+		var classElements = [];+		if ( (node === null) || (node === undefined) ) { node = document; }+		if ( (tag === null) || (tag === undefined) ) { tag = '*'; }+		var els = node.getElementsByTagName(tag);+		var elsLen = els.length;+		var pattern = new RegExp("(^|\\s)"+searchClass+"(\\s|$)");+		for (var i = 0, j = 0; i < elsLen; i++) {+      if ( pattern.test(els[i].className) ) {+        classElements.push(els[i]);+      }+		}+		return classElements;+	};+  fxExport(domMisc,getElementsByClass,'getElementsByClass','$$');+  +	//assumes IDs already preserved+	//swapDom: (Dom a U String) [* (Dom b U String)] -> Dom a+	var swapDom = function(replaceMe, withMe) {+		if ((replaceMe === null) || (replaceMe === undefined)) { throw ('swapDom: expected dom node or id, received: ' + replaceMe); } //SAFETY+    +		var replaceMeD = getObj(replaceMe);+		if (!(replaceMeD.nodeType > 0)) { throw ('swapDom expected a Dom node as first arg, received ' + replaceMeD); } //SAFETY+    +		if (withMe) {+      var withMeD = getObj(withMe);+      if (!(withMeD.nodeType > 0)) { throw 'swapDom: can only swap with a DOM object'; } //SAFETY+      try {+        if(withMeD != replaceMeD) replaceMeD.parentNode.replaceChild(withMeD, replaceMeD);+      } catch (e) {+        throw('swapDom error in replace call: withMeD: ' + withMeD + ', replaceMe Parent: ' + replaceMeD + ', ' + e + ', parent: ' + replaceMeD.parentNode);                    +      }+		} else {+      replaceMeD.parentNode.removeChild(replaceMeD); //TODO isolate child and set innerHTML to "" to avoid psuedo-leaks?+		}+		return replaceMeD;+	};+  fxExport(domMisc,swapDom,'swapDom');+  +	//getObj: String U Dom -> Dom+	//throws +	//  'getObj: expects a Dom obj or Dom id as first arg'+	//  'getObj: flapjax: cannot access object'+	//  'getObj: no obj to get+	//also known as '$'+	//TODO Maybe alternative?+	var getObj = function (name) {+		if (typeof(name) == 'object') { return name; }+		else if ((typeof(name) == 'null') || (typeof(name) == 'undefined')) {+      throw 'getObj: expects a Dom obj or Dom id as first arg';+		} else {+      +      var res = +			document.getElementById ? document.getElementById(name) :+			document.all ? document.all[name] :+			document.layers ? document.layers[name] :+			(function(){ throw 'getObj: flapjax: cannot access object';})();+      if ((res === null) || (res === undefined)) { +        throw ('getObj: no obj to get: ' + name); +      }+      return res;+		}+	};+  fxExport(domMisc,getObj,'getObj');+  fxExport(domMisc,getObj,'$');+  +  //helper to reduce obj look ups+  //getDynObj: domNode . Array (id) -> domObj+  //obj * [] ->  obj+  //obj * ['position'] ->  obj+  //obj * ['style', 'color'] ->  obj.style+  var getMostDom = function (domObj, indices) {+    var acc = getObj(domObj);+    if ( (indices === null) || (indices === undefined) || (indices.length < 1)) {+      return acc;+    } else {+      for (var i = 0; i < indices.length - 1; i++) {+        acc = acc[indices[i]];+      }+      return acc;+    }       +  };+  +  var getDomVal = function (domObj, indices) {+    var val = getMostDom(domObj, indices);+    if (indices && indices.length > 0) {+      val = val[indices[indices.length - 1]];+    }+    return val;+  };+  +  //TODO: manual timer management stinks.+  // TODO: Name turn off or somethin+  var ___timerID = 0;+  var __getTimerId = function () { return ++___timerID; };    +  var timerDisablers = [];+  +  var disableTimerNode = function (node) { timerDisablers[node.__timerId](); };+  +  var disableTimer = function (v) {+    if (v instanceof Behaviour) { +      disableTimerNode(v.underlyingRaw); +    } else if (v instanceof EventStream) {+      disableTimerNode(v);+    }+  };+  fxExport(dom,disableTimer,'disableTimer');+  +  var createTimerNodeStatic = function (interval) {+    var node = internal_e();+    node.__timerId = __getTimerId();+    var fn = function () { sendEvent(node, (new Date()).getTime());};+    var timer = setInterval(fn, interval);+    timerDisablers[node.__timerId] = function () {clearInterval(timer); };+    return node;+  };+  +  var timer_e = function (interval) {+    if (interval instanceof Behaviour) {+      var receiverE = internal_e();+      +      //the return+      var res = receiverE.switch_e();+      +      //keep track of previous timer to disable it+      var prevE = createTimerNodeStatic(valueNow(interval));+      +      //init+      sendEvent(receiverE, prevE);+      +      //interval changes: collect old timer+      createNode(+        [changes(interval)],+        function (_, p) {+          disableTimerNode(prevE); +          prevE = createTimerNodeStatic(p.value);+          sendEvent(receiverE, prevE);+        });+      +      res.__timerId = __getTimerId();+      timerDisablers[res.__timerId] = function () {+        disableTimerNode[prevE]();+        return;+      };+      +      return res;+    } else {+      return createTimerNodeStatic(interval);+    }+  };+  fxExport(dom,timer_e,'timer_e','asTimer_e');++	d.TagB = function(tagName,args) {+		this.resE = internal_e();+		this.currentTag = document.createElement(tagName);+		this.extractParameters(args);+		this.insertChildrenNodes();+		this.styleHooks = [];+		this.styleChangedE = internal_e();+		var ctx = this;+    this.styleChangedE.lift_e(function(_) {+				var oldTag = ctx.currentTag;+				ctx.currentTag = document.createElement(tagName);+        while (oldTag.firstChild) {+          ctx.currentTag.appendChild(oldTag.removeChild(oldTag.firstChild));+				}+				while(ctx.styleHooks.length) removeListener(ctx.styleHooks.pop(),ctx.styleChangedE);+        ctx.enstyle(ctx.currentTag,ctx.attribs);+        sendEvent(ctx.resE, ctx.currentTag);+		});+		this.enstyle(this.currentTag,this.attribs);+    this.resB = hold(this.resE, this.currentTag);+	};+	d.TagB.prototype = {+    // Array [[Behaviour] Object *] [[Behaviour] Array] [Behaviour] Dom U String U undefined+    //   --> {attribs: Array [Behaviour] Object, arrs: Array [Behaviour] Array [Behaviour] Dom }+    // split an arguments array into:+    //   1. arrs: (coalesced, and possibly time varying) arrays of dom objects +    //   2. attribs: attribute objects+		extractParameters: function(args) {+			this.arrs = [];+			var attribs = [];+      +			var curarr = [];+			this.arrs.push(curarr);+			for (var i = 0; i < args.length; i++) {+				if (args[i] instanceof Behaviour) {+					var vn = valueNow(args[i]);+					if (vn instanceof Array) {	        +						this.arrs.push(args[i]);+						curarr = [];+						this.arrs.push(curarr);+					} else {+						if ( ((typeof(vn) == 'object') && (vn.nodeType == 1)) ||+              (typeof(vn) == 'string') || (vn == undefined)) {+            curarr.push(args[i]);+              } else if (typeof(vn) == 'object') {+                attribs.push(args[i]);+              }+              else { throw ('createParameterizedTagB: unknown behaviour argument argument ' + i); } //SAFETY+					}+				} else {+					if (args[i] instanceof Array) {+						var arr = args[i];+						for (var j = 0; j < arr.length; j++) { curarr.push(arr[j]); }+					} else {+						var vn = args[i];+						if ( ((typeof(vn) == 'object') && (vn.nodeType == 1)) ||+              (typeof(vn) == 'string') || (vn == undefined)) {+						curarr.push(args[i]);+              } else if (typeof(vn) == 'object') {+                attribs.push(args[i]);+              }+					}+				}+			};+			if(attribs.length > 1) throw ('createParameterizedTagB ' + tagName + ': more than one attribute (' + attribs.length + ')');+			this.attribs = attribs.length > 0 ? attribs[0] : {};+		},+		insertChildrenNodes: function() {+			var ctx = this;+      +			function quickNode(e) { +        if ((typeof(e) == 'object') && (e.nodeType))+					return e; +        else if ( e == undefined )+					return document.createTextNode(''); +        else +          return document.createTextNode(e); +      }+      +			function unBehaviourize(arr) {+				return map(function(n) {return (n instanceof Behaviour) ? valueNow(n) : n;},arr)+			}+      +			var lnodes = map(function() {return [];},this.arrs);+			var arrLastVals = map(unBehaviourize,unBehaviourize(this.arrs));+      +			var arrChangesE = internal_e();+			var nodeChangesE = internal_e();+			+			function attachNodes(i,arr) {+				for(var j=0;j<arr.length;j++) {+					var cnode = arr[j];+					if(cnode instanceof Behaviour) {+						var newnode = (function(jj) {+                return changes(cnode).lift_e(function(n) {return {index:i,jdex:jj,val:n};});+						})(j);+						lnodes[i].push(newnode);+						attachListener(newnode,nodeChangesE);+						cnode = valueNow(cnode);+					}+				}+			}+      +			var childChangesE = merge_e(+				// Behaviour arrays change+				arrChangesE.lift_e(function(ai) {+            var i = ai.index;+            var newarr = ai.val;+            while(lnodes[i].length) {+              var ln = lnodes[i].pop();+              removeListener(ln,nodeChangesE);+            }+            var newvals = map(function(n) {return quickNode(n);},unBehaviourize(newarr));+            for(var j=0;j<arrLastVals[i].length;j++)+				try {+					ctx.currentTag.removeChild(arrLastVals[i][j]);+				}+				catch(e) {}+            if(newvals.length) {+              var nextNode = null;+              for(ii = i+1; ii < arrLastVals.length && !(arrLastVals[ii].length) ; ii++);+              if(ii < arrLastVals.length) nextNode = arrLastVals[ii][0];+              for(var j=0; j<newvals.length; j++) ctx.currentTag.insertBefore(newvals[j],nextNode);+            }+            arrLastVals[i] = newvals;+            attachNodes(i,newarr);+            return ctx.currentTag;+				}),+				// Behaviour nodes change+				nodeChangesE.lift_e(function(ni) {+            var i = ni.index;+            var j = ni.jdex;+            var newnode = quickNode(ni.val);+            swapDom(arrLastVals[i][j],newnode);+            arrLastVals[i][j] = newnode;+            return ctx.currentTag;+				}));+			childChangesE.lift_e(function(cc) {sendEvent(ctx.resE,cc);});+      +			for(var i=0; i<this.arrs.length;i++) {+				for(var j=0; j<arrLastVals[i].length; j++) {+					arrLastVals[i][j] = quickNode(arrLastVals[i][j]);+					this.currentTag.appendChild(arrLastVals[i][j]);+				}+				if(this.arrs[i] instanceof Behaviour) {+					attachNodes(i,valueNow(this.arrs[i]));+					var newnode = (function(ii) {return changes(ctx.arrs[ii]).lift_e(function(na) {return {index:ii,val:na};});})(i);+					attachListener(newnode,arrChangesE);+				}+				else {+					attachNodes(i,this.arrs[i]);+				}+			}+		},+		enstyle: function(obj,vals) {+			//build & record hook if dynamic collection+			if (vals instanceof Behaviour) {+				if (!(typeof(valueNow(vals)) == 'object')) { throw 'enstyle: expected object literal as behaviour value'; } //SAFETY+				this.styleHooks.push(changes(vals));+				attachListener(changes(vals),this.styleChangedE);+			}+			var valsV = vals instanceof Behaviour ? valueNow(vals) : vals;+			if (typeof(valsV) == 'object') {+				for (var i in valsV) {+					if (!(Object.prototype) || !(Object.prototype[i])) {+						this.enstyleProperty(obj,valsV, i);+					}+				}+			} +			else { throw 'enstyle: expected object literals'; } //SAFETY+		},+    enstyleProperty: function (obj, vals, i) {+      if (vals[i] instanceof Behaviour) {+        if (typeof(valueNow(vals[i])) == 'object') {+          this.enstyle(obj[i], vals[i]);+        }+				else {+          obj[i] = valueNow(vals[i]);+					changes(vals[i]).lift_e(function(v) {obj[i] = v;});+				}+			}+			else {+        if (typeof(vals[i]) == 'object') {+          this.enstyle(obj[i], vals[i]);+        } else {+          obj[i] = vals[i];+        }+      }+    }+	};+  +	d.createParameterizedTagB = function(tagName) {+		return new d.TagB(tagName,slice(arguments,1)).resB;+	}+  +  d.enstyleStaticProperty = function (obj, props, index) {+    if (typeof(props[index]) == 'object') {+      for (var i in props[index]) {+        if (!(Object.prototype) || !(Object.prototype[i])) {+          d.enstyleStaticProperty(obj[index], props[index], i);+        }+      }+    } else {+      obj[index] = props[index];+			if (index == 'checked')	obj['defaultChecked'] = props[index]; /* TODO: this should maybe be elsewhere? */+			if (index == 'selected') obj['defaultSelected'] = props[index]; /* TODO: this should maybe be elsewhere? */+    }+  };+  +  d.staticTagMaker = function (tagName) {+    +    return function () {+      +      var tagD = document.createElement(tagName);+      if (!(tagD.nodeType > 0)) { throw (tagName + ': invalid tag name'); } //SAFETY+      +      //partition input+      +      //          if (arguments[1] === null || arguments[1] === undefined) { arguments[1] = {}; }+      var attribs = [];+      for (var i = 0; i < arguments.length; i++) {+        if (arguments[i] instanceof Array) {+          for (var j = 0; j < arguments[i].length; j++) {+            if (arguments[i][j]) {+              tagD.appendChild(+                (typeof(arguments[i][j]) == 'object' &&+                  arguments[i][j].nodeType > 0)?+                arguments[i][j] :+                document.createTextNode(arguments[i][j]));+            }+          }+        } else if (!arguments[i]) {+          //ignore+        } else if ((typeof(arguments[i]) == 'object') && +          (arguments[i].nodeType > 0)) {+        tagD.appendChild(arguments[i]);+          } else if (typeof(arguments[i]) == 'object') {+            attribs.push(arguments[i]);+          } else {+            tagD.appendChild(document.createTextNode(arguments[i]));                    +          }+      }+      +      if (attribs.length == 1) { +        for (var k in attribs[0]) {+          if (!(Object.prototype) || !(Object.prototype[k])) {+            d.enstyleStaticProperty(tagD, attribs[0], k);   +          }+        }+      } else if (attribs.length >  0) { +        throw 'static enstyle: expected object literals'; //SAFETY+      } /* else {+      alert('no attribs on: ' + tagName);+      } */+      +      +      return tagD;+    };+  };+  +  +  +  var generatedTags = +  [ "a", "b", "blockquote", "br", "button", "canvas", "div", "fieldset", +  "form", "font", "h1", "h2", "h3", "h4", "hr", "img", "iframe", "input", +  "label", "legend", "li", "ol", "optgroup", "option", +  "p", "pre", "select", "span", "strong", "table", "tbody", +  "td", "textarea", "tfoot", "th", "thead", "tr", "tt", "ul" ];+  +  map(+    function (tagName) { +      +      var upper = tagName.toUpperCase();+      +      //d.<TAG>B+      d[upper + 'B'] = function () { +        return d.createParameterizedTagB.apply(this, [tagName].concat(slice(arguments,0)));+      };          +			annotate(d[upper+'B'],[upper+'B']);+      +      //d.<TAG>+      d[upper] = d.staticTagMaker(tagName);  //faster, simple+      /*              function () {+      // 8/16/06 - leo - arguments bug+      // more forgiving: allows reactive children (just doesn't propagate them)+      var args = [b.maybeEmpty].concat(slice(arguments, 0)); +      return valueNow(d[upper + 'B'].apply(this, args));+      }; */+			annotate(d[upper],[upper]);+    },+    generatedTags);+  +  //TEXTB: Behaviour a -> Behaviour Dom TextNode    +  d.TEXTB = function (strB) {+    //      if (!(strB instanceof Behaviour || typeof(strB) == 'string')) { throw 'TEXTB: expected Behaviour as second arg'; } //SAFETY+    if (!(strB instanceof Behaviour)) { strB = constant_b(strB); }+    +    return hold(+      changes(strB).lift_e(+        function (txt) { return document.createTextNode(txt); }),+      document.createTextNode(valueNow(strB)));+  };+	annotate(d.TEXTB,['TEXTB']);+  +  var TEXT = function (str) {+    return document.createTextNode(str);+  };+  fxExport(dom,TEXT,'TEXT');+  +  //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////+  // Reactive DOM+  +  //tagRec: Array (EventName a) * +  //      ( .Array (Event a) * Array (Event a) -> Behaviour Dom) -> Behaviour Dom+  var tagRec = function (eventNames, maker) {+    if (!(eventNames instanceof Array)) { throw 'tagRec: expected array of event names as first arg'; } //SAFETY+    if (!(maker instanceof Function)) { throw 'tagRec: expected function as second arg'; } //SAFETY+    +    var numEvents = eventNames.length;+    var internals = [ ];+    var switches = [ ];+    for (var i = 0; i < numEvents; i++) {+      internals[i] = internal_e();+      switches[i] = internals[i].switch_e();+    };+    +    var domB = maker.apply(this,switches);+    +    var prevValue;+    +    var interceptE = createNode([domB.changes()],function (_,p) {+      if (isEqual(p.value,prevValue)) { return; }+      +      prevValue = p.value;+      for (var i = 0; i < numEvents; i++) {+        sendEvent(internals[i],extractEvent_e(prevValue,eventNames[i]));+      };+    });+    +    sendEvent(interceptE,domB.valueNow());+    +    return domB;+  };+  fxExport(dom,tagRec,'tagRec','nodeWithOwnEvents');+  +  //extractEventStatic_e: Dom * String -> Event+  var extractEventStatic_e = function (domObj, eventName) {+    if (!eventName) { throw 'extractEvent_e : no event name specified'; }+    if (!domObj) { throw 'extractEvent_e : no DOM element specified'; }+    +    domObj = getObj(domObj);+    +    var primEventE = internal_e();+    addEvent(domObj,eventName,function(evt) {+       sendEvent(primEventE, evt || window.event);+       // Important for IE; false would prevent things like a checkbox actually+       // checking.+       return true;+    });+    +    return primEventE;+  };++  //extractEvent_e: [Behaviour] Dom * String -> Event+  var extractEvent_e = function (domB, eventName) {+    if (!(domB instanceof Behaviour)) {+      return extractEventStatic_e(domB,eventName);+    }+    else {+      var domE = domB.changes();+      +      var eventEE = domE.lift_e(function(dom) {+        return extractEventStatic_e(dom,eventName);+      });+      +      var resultE = eventEE.switch_e();+      +      sendEvent(domE,domB.valueNow());+      +      return resultE;+    };+  };+  fxExport(dom,extractEvent_e,'extractEvent_e','$EVT');+  +  //extractEvents_e: +  //      [Behaviour] Dom  +  //      . Array String+  //      -> Event+  // ex: extractEvents_e(m, 'body', 'mouseover', 'mouseout')+  d.extractEvents_e = function (domObj /* . eventNames */) {+    var eventNames = slice(arguments, 1);+    +    var events = map(+      function (eventName) {+        return extractEvent_e(domObj, eventName); +      },+      eventNames.length === 0 ? [] : eventNames);+    +    return merge_e.apply(this, events);+  };+  annotate(d.extractEvents_e,['extractEvents_e'],0,[Behaviour.prototype],['extractEvents_e']);+  +  //value of dom form object during trigger+  d.extractValueOnEvent_e = function (triggerE, domObj) {+    if (!(triggerE instanceof EventStream)) { throw 'extractValueOnEvent_e: expected Event as first arg'; } //SAFETY+    +    return changes(d.extractValueOnEvent_b.apply(this, arguments));+    +  };+  annotate(d.extractValueOnEvent_e,['extractValueOnEvent_e']);+  +  //extractDomFieldOnEvent_e: Event * Dom U String . Array String -> Event a+  d.extractDomFieldOnEvent_e = function (triggerE, domObj /* . indices */) {+    if (!(triggerE instanceof EventStream)) { throw 'extractDomFieldOnEvent_e: expected Event as first arg'; } //SAFETY+    var indices = slice(arguments, 2);+    var res =+    triggerE.lift_e(+      function () { return getDomVal(domObj, indices); });+    return res;+  };+  +  d.extractValue_e = function (domObj) {+    return changes(d.extractValue_b.apply(this, arguments));+  };+  annotate(d.extractValue_e,['extractValue_e','$E']);+  +  //extractValueOnEvent_b: Event * DOM -> Behaviour+  // value of a dom form object, polled during trigger+  d.extractValueOnEvent_b = function (triggerE, domObj) {+    return d.extractValueStatic_b(domObj, triggerE);+  };+  annotate(d.extractValueOnEvent_b,['extractValueOnEvent_b']);+  +  //extractValueStatic_b: DOM [ * Event ] -> Behaviour a+  //If no trigger for extraction is specified, guess one+  d.extractValueStatic_b = function (domObj, triggerE) {+    +    var objD;+    try {+      objD = getObj(domObj);+	    //This is for IE+	    if(typeof(domObj) == 'string' && objD.id != domObj) {+	    	throw 'Make a radio group';+	    }+    } catch (e) {+      objD = {type: 'radio-group', name: domObj};+    }+    +    var getter; // get value at any current point in time+    +    +    switch (objD.type)  {+      +      //TODO: checkbox.value instead of status?+    case 'checkbox': +      +      return hold(+        filterRepeats_e(+          d.extractDomFieldOnEvent_e(+            triggerE ? triggerE : +            d.extractEvents_e(+              objD, +              'click', 'keyup', 'change'),+            objD,+            'checked'),objD.checked),+        objD.checked);+      +      case 'select-one':+        +        getter = function (_) {                         +          return objD.selectedIndex > -1 ? +          (objD.options[objD.selectedIndex].value ?+            objD.options[objD.selectedIndex].value :+            objD.options[objD.selectedIndex].innerText)+			    : undefined;+        };+        +        return hold(+          filterRepeats_e(+              (triggerE ? triggerE :+              d.extractEvents_e(+                objD,+                'click', 'keyup', 'change')).lift_e(getter)),getter(),+          getter());+        +        case 'select-multiple':+          //TODO ryan's cfilter adapted for equality check+          +          getter = function (_) {+            var res = [];+            for (var i = 0; i < objD.options.length; i++) {+              if (objD.options[i].selected) {+                res.push(objD.options[i].value ? objD.options[i].value : objD.options[i].innerText);+              }+            }+            return res;+          };+          +          +          return hold(+              (triggerE ? triggerE : +              d.extractEvents_e(+                objD,+                'click', 'keyup', 'change')).lift_e(getter),+            getter());+          +          case 'text':+          case 'textarea':+          case 'hidden':+          case 'password':+            +            return hold(+              filterRepeats_e(+                d.extractDomFieldOnEvent_e(+                  triggerE ? triggerE :+                  d.extractEvents_e(+                    objD, +                    'click', 'keyup', 'change'),+                  objD,+                  'value'),objD.value),+              objD.value);+            +            case 'button': //same as above, but don't filter repeats+              +              return hold(+                d.extractDomFieldOnEvent_e(+                  triggerE ? triggerE :+                  d.extractEvents_e(+                    objD, +                    'click', 'keyup', 'change'),+                  objD,+                  'value'),+                objD.value);+              +              +              case 'radio': +              case 'radio-group':+                +                //TODO returns value of selected button, but if none specified,+                //      returns 'on', which is ambiguous. could return index,+                //      but that is probably more annoying+                +                var radiosAD = filter(+                  function (elt) { +                    return (elt.type == 'radio') &&+                    (elt.getAttribute('name') == objD.name); +                  },+                  document.getElementsByTagName('input'));+                +                getter = +                objD.type == 'radio' ?+                +                function (_) {+                  return objD.checked;+                } :+                +                function (_) {+                  for (var i = 0; i < radiosAD.length; i++) {+                    if (radiosAD[i].checked) {+                      return radiosAD[i].value; +                    }+                  }+                  return undefined; //TODO throw exn? +                };+                +                var actualTriggerE = triggerE ? triggerE :+                merge_e.apply(+                  this,+                  map(+                    function (radio) { +                      return d.extractEvents_e(+                        radio, +                    'click', 'keyup', 'change'); },+                      radiosAD));+                +                return hold(+                  filterRepeats_e(+                      actualTriggerE.lift_e(getter),getter()),+                  getter());+                +                default:+                  +                  throw ('extractValueStatic_b: unknown value type "' + objD.type + '"');+    }+  };+  +  d.extractValue_b = function (domObj) {+    if (domObj instanceof Behaviour) {+      return lift_b(function (dom) { return d.extractValueStatic_b(dom); },+                    domObj)+             .switch_b();+    } else {+      return d.extractValueStatic_b(domObj);+    }+  };+	annotate(d.extractValue_b,['extractValue_b','$B'],0,[Behaviour.prototype],['extractValue_b','$B']);+  +  //into[index] = deepValueNow(from) via descending from object and mutating each field+  d.deepStaticUpdate = function (into, from, index) {+    var fV = (from instanceof Behaviour)? valueNow(from) : from;+    if (typeof(fV) == 'object') {+      for (var i in fV) {+        if (!(Object.prototype) || !(Object.prototype[i])) {+          d.deepStaticUpdate(index? into[index] : into, fV[i], i);+        }+      }+    } else {+      var old = into[index];+      into[index] = fV;+    }+  };+  +  //note: no object may be time varying, just the fields+  //into[index] = from+  //only updates on changes+  d.deepDynamicUpdate = function (into, from, index) {+    var fV = (from instanceof Behaviour)? valueNow(from) : from;+    if (typeof(fV) == 'object') {+      if (from instanceof Behaviour) {+        throw 'deepDynamicUpdate: dynamic collections not supported';+      }+      for (var i in fV) {+        if (!(Object.prototype) || !(Object.prototype[i])) {+          d.deepDynamicUpdate(index? into[index] : into, fV[i], i);+        }+      }+    } else {+      if (from instanceof Behaviour) {+        createNode(+          [changes(from)],+          function (s, p) {+            if (index) { +              var old = into[index];+              into[index] = p.value;+            }+            else { into = p.value; } //TODO notify topE?+          });+      }+    }+  };+  +	+  d.insertValue = function (val, domObj /* . indices */) {+    var indices = slice(arguments, 2);+    var parent = getMostDom(domObj, indices);+    d.deepStaticUpdate(parent, val, indices ? indices[indices.length - 1] : undefined);    	+  };+  annotate(d.insertValue,['insertValue']);+  +  //TODO convenience method (default to firstChild nodeValue) +  d.insertValueE = function (triggerE, domObj /* . indices */) {+    if (!(triggerE instanceof EventStream)) { throw 'insertValueE: expected Event as first arg'; } //SAFETY+    +    var indices = slice(arguments, 2);+    var parent = getMostDom(domObj, indices);+    +      triggerE.lift_e(function (v) {+        d.deepStaticUpdate(parent, v, indices? indices[indices.length - 1] : undefined);+      });+  };+  annotate(d.insertValueE,['insertValueE'],0,[EventStream.prototype],['insertValueE']);+  +  //insertValueB: Behaviour * domeNode . Array (id) -> void+  //TODO notify adapter of initial state change?+  d.insertValueB = function (triggerB, domObj /* . indices */) { +    +    var indices = slice(arguments, 2);+    var parent = getMostDom(domObj, indices);+    +    +    //NOW+    d.deepStaticUpdate(parent, triggerB, indices ? indices[indices.length - 1] : undefined);+    +    //LATER+    d.deepDynamicUpdate(parent, triggerB, indices? indices[indices.length -1] : undefined);+    +  };+  annotate(d.insertValueB,['insertValueB'],0,[Behaviour.prototype],['insertValueB']);+  +  //TODO copy dom event call backs of original to new? i don't thinks so+  //  complication though: registration of call backs should be scoped+  d.insertDomE = function (triggerE, domObj) {+    +    if (!(triggerE instanceof EventStream)) { throw 'insertDomE: expected Event as first arg'; } //SAFETY+    +    var objD = getObj(domObj);+    +    var res = triggerE.lift_e(+      function (newObj) {+        //TODO safer check+        if (!((typeof(newObj) == 'object') && (newObj.nodeType == 1))) { +          newObj = d.SPAN({}, newObj);+        }+        swapDom(objD, newObj);+        objD = newObj;+        return newObj; // newObj;+      });+    +    return res;+  };+  annotate(d.insertDomE,['insertDomE'],0,[EventStream.prototype],['insertDomE']);+  +  //insertDom: dom +  //          * dom +  //          [* (null | undefined | 'over' | 'before' | 'after' | 'leftMost' | 'rightMost' | 'beginning' | 'end']+  //          -> void+  // TODO: for consistency, switch replaceWithD, hookD argument order+  d.insertDom = function (hookD, replaceWithD, optPosition) {+    switch (optPosition)+    {+    case undefined:+    case null:+    case 'over':+      swapDom(hookD,replaceWithD);+      break;+    case 'before':  +      hookD.parentNode.insertBefore(replaceWithD, hookD);+      break;+    case 'after':+      if (hookD.nextSibling) {+        hookD.parentNode.insertBefore(replaceWithD, hookD.nextSibling);+      } else {+        hookD.parentNode.appendChild(replaceWithD);+      }+      break;+    case 'leftMost':+      if (hookD.parentNode.firstChild) { +        hookD.parentNode.insertBefore(+          replaceWithD, +          hookD.parentNode.firstChild);+                } else { hookD.parentNode.appendChild(replaceWithD); }+                break;+              case 'rightMost':+                hookD.parentNode.appendChild(replaceWithD);+                break;+              case 'beginning':+                if (hookD.firstChild) { +                  hookD.insertBefore(+                    replaceWithD, +                    hookD.firstChild);+                } else { hookD.appendChild(replaceWithD); }+                break;+              case 'end':+                hookD.appendChild(replaceWithD);+                break;+              default:+                throw ('domInsert: unknown position: ' + optPosition);+    }+  };+  +  //insertDom: dom +  //          * dom U String domID +  //          [* (null | undefined | 'over' | 'before' | 'after' | 'leftMost' | 'rightMost' | 'beginning' | 'end']+  //          -> void+  d.insertDomClean = function (replaceWithD, hook, optPosition) {+    //TODO span of textnode instead of textnode?+    d.insertDom(+	    getObj(hook), +	    ((typeof(replaceWithD) == 'object') && (replaceWithD.nodeType > 0)) ? replaceWithD :+      document.createTextNode(replaceWithD),	    +	    optPosition);     	    +  };+  annotate(d.insertDomClean,['insertDom']);+  +  //TODO test+  //insertDomB: +  //      [Behaviour] String U Dom +  //      [* ( id U null U undefined ) +  //          [* ('before' U 'after' U 'leftMost' U 'rightMost' U 'over' U 'beginning' U 'end')]]+  //      -> Behaviour a+  //if optID not specified, id must be set in init val of trigger+  //if position is not specified, default to 'over'+  //performs initial swap onload    +  d.insertDomB = function (initTriggerB, optID, optPosition) {+    +    if (!(initTriggerB instanceof Behaviour)) { +      initTriggerB = constant_b(initTriggerB);+    }+    +    var triggerB = +    lift_b(+      function (d) { +        if ((typeof(d) == 'object') && (d.nodeType >  0)) {+          return d;+        } else {+          var res = document.createElement('span'); //TODO createText instead+          res.appendChild(document.createTextNode(d));+          return res;+        }+      },+      initTriggerB);+    +    var initD = valueNow(triggerB);+    if (!((typeof(initD) == 'object') && (initD.nodeType == 1))) { throw ('insertDomB: initial value conversion failed: ' + initD); } //SAFETY	+    +    d.insertDom(+      optID === null || optID === undefined ? getObj(initD.getAttribute('id')) : getObj(optID), +      initD, +      optPosition);+    +    var resB = hold(+      d.insertDomE(+        changes(triggerB),+        initD), +      initD);+    +    return resB;+  };+  annotate(d.insertDomB,['insertDomB'],0,[Behaviour.prototype],['insertDomB']);+  +  +  d.extractId_b = function (id, start)+  {+    return hold(+      createNode( start instanceof Behaviour? [changes(start)] :+        [],+        function (s, p) {+          p.value = getObj(id);+          s(p);+        }),+      getObj(id));+  };+  annotate(d.insertDomB,['extractId_b'],1,[Behaviour.prototype],['extractId_b']);+  +  var mouse_e = function(elem) {+    return extractEvent_e(elem,'mousemove')+    .lift_e(function(evt) {+        if (evt.pageX | evt.pageY) {+          return { left: evt.pageX, top: evt.pageY };+        }+        else if (evt.clientX || evt.clientY) {+          return { left : evt.clientX + document.body.scrollLeft,+                   top: evt.clientY + document.body.scrollTop };+        }+        else {+          return { left: 0, top: 0 };+        }+    });+  };+  +  var mouse_b = function(elem) {+    return mouse_e(elem).hold({ left: 0, top: 0 });+  }+  fxExport(dom,mouse_b,'mouse_b');+  +  var mouseLeft_b = function(elem) {+    return lift_b(function(v) { return v.left; },mouse_b(elem));+  };+  fxExport(dom,mouseLeft_b,'mouseLeft_b');+  +  var mouseTop_b = function(elem) {+    return mouse_b(elem).lift_b(function(v) { return v.top; });+  };+  +  fxExport(dom,mouseTop_b,'mouseTop_b');+  +  var clicks_e = function(elem) {+    return extractEvent_e(elem,'click');+  };+  fxExport(dom,clicks_e,'clicks_e');+  +  //////////////////////////////////////////////////////////////////////////////+  // Combinators for web services+  +  +	//credit Matt White+	var getURLParam = function (param) {+    var lparam = param.toLowerCase();+    var aReturn = [];+    var strHref = window.location.href;+    var endstr = (strHref.indexOf('#') > -1) ? strHref.indexOf('#') : strHref.length;+    if ( strHref.indexOf("?") > -1 ) {+      var strQueryString = strHref.substring(strHref.indexOf("?")+1,endstr);+      map(function(qp) {+          var eq = qp.indexOf('=');+          var qname = qp.substr(0,eq+1).toLowerCase();+          if(qname == lparam+"=") aReturn.push(decodeURIComponent(qp.substr(eq+1)));+      },strQueryString.split("&"));+    }+    if (aReturn.length == 0) return undefined;+    else if(aReturn.length == 1) return aReturn[0];+    else return aReturn;+	};+  fxExport(domMisc,getURLParam,'getURLParam','$URL');+  +	//credit Quirksmode+	//readCookie: String -> String U Undefined+	var readCookie = function (name) {+    var nameEQ = name + "=";+    var ca = document.cookie.split(';');+    for (var i=0; i < ca.length; i++) {+      var co = ca[i];+      while (co.charAt(0) == ' ') { co = co.substring(1, co.length); }+      if (co.indexOf(nameEQ) === 0) { +        return co.substring(nameEQ.length, co.length);+      }+    }+    return undefined;       +	};+  fxExport(domMisc,readCookie,'readCookie');+  +  //========== dynamic scripts ==========+  var scriptCounter = 0;+  var deleteScript = function (scriptID) {+    var scriptD = getObj(scriptID);+    scriptD.parentNode.removeChild(scriptD); //TODO isolate child and set innerHTML to "" to avoid psuedo-leaks?+  };+  +  // optional fn/param that gets polled until parm is defined+  var runScript = function (url, fn, param) {+    var script = document.createElement("script");+    script.src = url;+    var scriptID = 'scriptFnRPC' + scriptCounter++;+    script.setAttribute('id', scriptID);+    document.getElementsByTagName("head").item(0).appendChild(script);+    var timer = {};+    var check = +    function () {+      eval("try { if (" + param + "!== undefined) {var stat = " + param + ";}} catch (e) {}");+      if (stat !== undefined) {+        eval(param + " = undefined;");+        clearInterval(timer.timer);+        clearInterval(timer.timeout);+        if (fn instanceof Function) {+          fn(stat); +        }+        deleteScript(scriptID);+      }+    };+    timer.timer = setInterval(check, 3500);+    timer.timeout = +    setTimeout( +      function () { +        try { clearInterval(timer.timer); }+        catch (e) {}+      },+      5000); //TODO make parameter?+  };+  +  // Node {url, globalArg} -> Node a+  //load script @ url and poll until param is set, then pass it along+  var evalForeignScriptVal_e = function(urlArg_e) {+    var result = receiver_e();+    urlArg_e.lift_e(function(urlArg) {+        runScript(urlArg.url,+          function(val) { result.sendEvent(val); }, +          urlArg.globalArg);+    });+    +    return result;+  };+  fxExport(ws,evalForeignScriptVal_e,'evalForeignScriptVal_e');+  +  var ajaxRequest = function(method,url,body,async,useFlash,callback) {+    var xhr;+    if (useFlash) {+      xhr = new FlashXMLHttpRequest();+      xhr.onload = function() { callback(xhr); };+    }+    else if (window.XMLHttpRequest && !(window.ActiveXObject)) {+      xhr = new window.XMLHttpRequest();+      xhr.onload = function() { callback(xhr); };+    }+    else if (window.ActiveXObject) {+      try { xhr = new ActiveXObject("Msxml2.XMLHTTP"); }+      catch(e) { xhr = new ActiveXObject("Microsoft.XMLHTTP"); }+      +      xhr.onreadystatechange = function() {+        if (xhr.readyState == 4) { callback(xhr); }+      };+    };+    +    xhr.open(method,url,async);+    +    if (method == 'POST') {+      xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');+    }+    +    xhr.send(body);+    return xhr;+  };++  var encodeREST = function(obj) {+    var str = "";+    for (var field in obj) {+      if (typeof(obj[field]) !== 'function') { // skips functions in the object+        if (str != '') { str += '&'; }+        str += field + '=' + encodeURIComponent(obj[field]);+      }+    }+    return str;+  };++  // From json.org+  var parseJSON = function(str) {+    try {+        return !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(+                str.replace(/"(\\.|[^"\\])*"/g, ''))) &&+            eval('(' + str + ')');+    } catch (e) {+        throw 'cannot parse JSON string: ' + e;+    }+  };++  var toJSONString = (function() {+    var m = {+            '\b': '\\b',+            '\t': '\\t',+            '\n': '\\n',+            '\f': '\\f',+            '\r': '\\r',+            '"' : '\\"',+            '\\': '\\\\'+        };+    var s = {+      array: function (x) {+        var a = ['['], b, f, i, l = x.length, v;+        for (i = 0; i < l; i += 1) {+          v = x[i];+          f = s[typeof v];+          if (f) {+            v = f(v);+            if (typeof v == 'string') {+              if (b) {+                a[a.length] = ',';+              }+              a[a.length] = v;+              b = true;+            }+          }+        }+        a[a.length] = ']';+        return a.join('');+      },+      'boolean': function (x) {+        return String(x);+      },+      'null': function (x) {+        return "null";+      },+      number: function (x) {+        return isFinite(x) ? String(x) : 'null';+      },+      object: function (x) {+        if (x) {+          if (x instanceof Array) {+            return s.array(x);+          }+          var a = ['{'], b, f, i, v;+          for (i in x) {+            v = x[i];+            f = s[typeof v];+            if (f) {+              v = f(v);+              if (typeof v == 'string') {+                if (b) {+                  a[a.length] = ',';+                }+                a.push(s.string(i), ':', v);+                b = true;+              }+            }+          }+          a[a.length] = '}';+          return a.join('');+        }+        return 'null';+      },+      string: function (x) {+        if (/["\\\x00-\x1f]/.test(x)) {+          x = x.replace(/([\x00-\x1f\\"])/g, function(a, b) {+              var c = m[b];+              if (c) {+                return c;+              }+              c = b.charCodeAt();+              return '\\u00' ++              Math.floor(c / 16).toString(16) ++              (c % 16).toString(16);+          });+        }+        return '"' + x + '"';+      }+    };+    return function(val) {+      var f = s[typeof val];+      if (f) { return f(val); }+      else { throw 'parseJSON: unknown object type: ' + (typeof val); }+    };+  })();+   +  var serverRequest_e = function(useFlash,requestE) {+    var response_e = receiver_e();+    +    requestE.lift_e(function (obj) {+        var body = '';+        var method = 'GET';+        var url = obj.url;+        +        var reqType = obj.request ? obj.request : (obj.fields ? 'post' : 'get');+        if (obj.request == 'get') {+          url += "?" + encodeREST(obj.fields);+          body = '';+          method = 'GET';+        } else if (obj.request == 'post') {+          body = toJSONString(obj.fields); +          method = 'POST';+        } else if (obj.request == 'rawPost') {+          body = obj.body;+          method = 'POST';+        }+        else if (obj.request == 'rest') {+          body = encodeREST(obj.fields);+          method = 'POST';+        }+        else {+          raise ("Invalid request type: " + obj.request);+        }+        +        var async = obj.async;+        +        var xhr;+        +        // Branch on the response type to determine how to parse it+        if (obj.response == 'json') {+          xhr = ajaxRequest(method,url,body,async,useFlash,+            function(xhr) {+              response_e.sendEvent(parseJSON(xhr.responseText)); +            });+        }+        else if (obj.response == 'xml') {+          ajaxRequest(method,url,body,async,useFlash,+            function(xhr) {+              response_e.sendEvent(xhr.responseXML);+            });+        }+        else if (obj.response == 'plain' || !obj.response) {+          ajaxRequest(method,url,body,async,useFlash,+            function(xhr) {+              response_e.sendEvent(xhr.responseText);+          });+        }+        else {+          raise('Unknown response format: ' + obj.response);+        }+    });+    +    return response_e;+  };+  +  var getWebServiceObject_e = function(requestE) {+    return serverRequest_e(false,requestE);+  };+  fxExport(ws,getWebServiceObject_e,'getWebServiceObject_e');+  +  var getForeignWebServiceObject_e = function(requestE) {+    return serverRequest_e(true,requestE);+  };+  fxExport(ws,getForeignWebServiceObject_e,'getForeignWebServiceObject_e');++  var cumulativeOffset = function(element) {+    var valueT = 0, valueL = 0;+    do {+      valueT += element.offsetTop  || 0;+      valueL += element.offsetLeft || 0;+      element = element.offsetParent;+    } while (element);+    return { left: valueL, top: valueT };+ };+fxExport(domMisc,cumulativeOffset,'cumulativeOffset');++  ///////// OPTIONALLY EXPORT PUBLIC FUNCTIONS TO GLOBAL NAMESPACE+  if (!options.hideAll) {+    for (var zz in flapjax.pub) {+      if (!options[zz]) {+        window[zz] = flapjax.pub[zz]; // use eval instead so as to achieve Flash compatibility+      }+    }+  }+  +  for (var id in exports) {+    if (window[id]) {+      if (options.redefine === false) {+        warn('window.' + id + ' is already defined; Flapjax will not ' ++             'redefine it.');+      }+      else {+        warn('Flapjax is redefining window.' + id + '.');+      }+    }++    if (window[id] && options.redefine === false) {+      // Don't redefine id+    }+    else if (options.show && options.hide && options.show[id] === true && +        options.hide[id] === true) {+      throw('flapjaxInit: invalid options: ' + id + " specified as 'show' and 'hide'"); +    }+    else if (options.show && options.show[id]) {+      window[id] = exports[id];+    }+    else if (options.hide && options.hide[id]) {+      // do nothing -- don't export+    }+    // Default behavior--check if it is a synonym first ...+    else if (!synonyms[id] || options.includeSynonyms) {+      // ... then export if its of the right category+      if (options.exportMisc && exports[id].__flapjaxCategory === misc) {+        window[id] = exports[id];+      }+      else if (options.exportDOMMisc && exports[id].__flapjaxCategory === domMisc) {+        window[id] = exports[id];+      }+      else if (options.exportDOM && exports[id].__flapjaxCategory === dom) {+        window[id] = exports[id];+      }+      else if (options.exportCore && exports[id].__flapjaxCategory === core) {+        window[id] = exports[id];+      }+      else if (options.exportWS && exports[id].__flapjaxCategory === ws) {+        window[id] = exports[id];+      }+    }+  }+  +  return exports;+}
+ tests/parse-pretty/neg.js view
@@ -0,0 +1,2 @@+var foo = -x;+var bar = +y;
+ tests/parse-pretty/numbers.js view
@@ -0,0 +1,2 @@+var x = 23;+var y = 23.0;
+ tests/parse-pretty/object-lit-1.js view
@@ -0,0 +1,4 @@+var x = {  // avoid ambiguity with BlockStmt+  foo : 23, +  bar : 50 +}
+ tests/parse-pretty/object-lit-2.js view
@@ -0,0 +1,4 @@+var x = {  // avoid ambiguity with BlockStmt+  foo : 23, +  bar : 50, +} 
+ tests/parse-pretty/prefix-chain.js view
@@ -0,0 +1,4 @@+var w = typeof typeof 34;+var x = ! -- x; // derived from jQuery+var y = ! !x; // derived from Prototype+var z = !! -- x;
+ tests/parse-pretty/strings.js view
@@ -0,0 +1,6 @@+var x = '\b';+var z = {+  '\b': '\\b' // lhs is a PropString, not a StringLit, but must be printed+              //  as a StringLit+};+var w = "\\s";