flow.js
function define() {	
		var thisFlow = function() {
			applyArgs(thisFlow.exec, thisFlow, arguments);
		}
		
		thisFlow.blocks = arguments;
		
		thisFlow.exec = function() {
			// The flowState is the actual object each step in the flow is applied to. It acts as a
			// callback to the next function. It also maintains the internal state of each execution
			// and acts as a place for users to save values between steps of the flow.
			var flowState = function() {
				if (flowState.__frozen) return;
				
				if (flowState.__timeoutId) {
					clearTimeout(flowState.__timeoutId);
					delete flowState.__timeoutId;
				}
				
				var blockIdx = flowState.__nextBlockIdx ++;
				var block = thisFlow.blocks[blockIdx];
				
				if (block === undefined) {
					return;
				}
				else {
					applyArgs(block, flowState, arguments);
				}
			}
			
			// __nextBlockIdx specifies which function is the next step in the flow.
			flowState.__nextBlockIdx = 0;
			
			// __multiCount is incremented every time MULTI is used to createa a multiplexed callback
			flowState.__multiCount = 0;
			
			// __multiOutputs accumulates the arguments of each call to callbacks generated by MULTI
			flowState.__multiOutputs = [];
			
			// REWIND signals that the next call to thisFlow should repeat this step. It allows you
			// to create serial loops.
			flowState.REWIND = function() {
				flowState.__nextBlockIdx -= 1;
			}
			
			// MULTI can be used to generate callbacks that must ALL be called before the next step
			// in the flow is executed. Arguments to those callbacks are accumulated, and an array of
			// of those arguments objects is sent as the one argument to the next step in the flow.
			// @param {String} resultId An identifier to get the result of a multi call.
			flowState.MULTI = function(resultId) {
				flowState.__multiCount += 1;
				return function() {
					flowState.__multiCount -= 1;
					flowState.__multiOutputs.push(arguments);

          if (resultId) {
            var result = arguments.length <= 1 ? arguments[0] : arguments
            flowState.__multiOutputs[resultId] = result;
          }
					
					if (flowState.__multiCount === 0) {
						var multiOutputs = flowState.__multiOutputs;
						flowState.__multiOutputs = [];
						flowState(multiOutputs);
					}
				}
			}
						
			// TIMEOUT sets a timeout that freezes a flow and calls the provided callback. This
			// timeout is cleared if the next flow step happens first.
			flowState.TIMEOUT = function(milliseconds, timeoutCallback) {
				if (flowState.__timeoutId !== undefined) {
					throw new Error("timeout already set for this flow step");
				}
				
				flowState.__timeoutId = setTimeout(function() {
					flowState.__frozen = true;
					timeoutCallback();
				}, milliseconds);
			}
			
			applyArgs(flowState, this, arguments);
		}
		
		return thisFlow;
	}
function define() {	
		var thisFlow = function() {
			applyArgs(thisFlow.exec, thisFlow, arguments);
		}
		
		thisFlow.blocks = arguments;
		
		thisFlow.exec = function() {
			// The flowState is the actual object each step in the flow is applied to. It acts as a
			// callback to the next function. It also maintains the internal state of each execution
			// and acts as a place for users to save values between steps of the flow.
			var flowState = function() {
				if (flowState.__frozen) return;
				
				if (flowState.__timeoutId) {
					clearTimeout(flowState.__timeoutId);
					delete flowState.__timeoutId;
				}
				
				var blockIdx = flowState.__nextBlockIdx ++;
				var block = thisFlow.blocks[blockIdx];
				
				if (block === undefined) {
					return;
				}
				else {
					applyArgs(block, flowState, arguments);
				}
			}
			
			// __nextBlockIdx specifies which function is the next step in the flow.
			flowState.__nextBlockIdx = 0;
			
			// __multiCount is incremented every time MULTI is used to createa a multiplexed callback
			flowState.__multiCount = 0;
			
			// __multiOutputs accumulates the arguments of each call to callbacks generated by MULTI
			flowState.__multiOutputs = [];
			
			// REWIND signals that the next call to thisFlow should repeat this step. It allows you
			// to create serial loops.
			flowState.REWIND = function() {
				flowState.__nextBlockIdx -= 1;
			}
			
			// MULTI can be used to generate callbacks that must ALL be called before the next step
			// in the flow is executed. Arguments to those callbacks are accumulated, and an array of
			// of those arguments objects is sent as the one argument to the next step in the flow.
			// @param {String} resultId An identifier to get the result of a multi call.
			flowState.MULTI = function(resultId) {
				flowState.__multiCount += 1;
				return function() {
					flowState.__multiCount -= 1;
					flowState.__multiOutputs.push(arguments);

          if (resultId) {
            var result = arguments.length <= 1 ? arguments[0] : arguments
            flowState.__multiOutputs[resultId] = result;
          }
					
					if (flowState.__multiCount === 0) {
						var multiOutputs = flowState.__multiOutputs;
						flowState.__multiOutputs = [];
						flowState(multiOutputs);
					}
				}
			}
						
			// TIMEOUT sets a timeout that freezes a flow and calls the provided callback. This
			// timeout is cleared if the next flow step happens first.
			flowState.TIMEOUT = function(milliseconds, timeoutCallback) {
				if (flowState.__timeoutId !== undefined) {
					throw new Error("timeout already set for this flow step");
				}
				
				flowState.__timeoutId = setTimeout(function() {
					flowState.__frozen = true;
					timeoutCallback();
				}, milliseconds);
			}
			
			applyArgs(flowState, this, arguments);
		}
		
		return thisFlow;
	}
defines a flow given any number of functions as arguments